diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 000000000..04a24c3b0 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,14 @@ +// For format details, see https://aka.ms/devcontainer.json. For config options, see the +// README at: https://github.com/devcontainers/templates/tree/main/src/alpine +{ + // ref: https://docs.github.com/en/codespaces/setting-up-your-project-for-codespaces/adding-a-dev-container-configuration/introduction-to-dev-containers#dockerfile + "image": "docker.io/kcllang/kcl-builder:latest", + "customizations": { + "vscode": { + "extensions": [ + "rust-lang.rust-analyzer", + "ms-vscode.makefile-tools" + ] + } + } +} \ No newline at end of file diff --git a/.flake8 b/.flake8 deleted file mode 100644 index 106f6eee4..000000000 --- a/.flake8 +++ /dev/null @@ -1,5 +0,0 @@ -[antflake8] -max-line-length = 120 -select = C,E,F,W,B,B950 -extend-ignore = F403, F405, E203, E501, W503 -exclude = *_pb2.py, lark_token.py diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md deleted file mode 100644 index 360c0032a..000000000 --- a/.github/ISSUE_TEMPLATE.md +++ /dev/null @@ -1,31 +0,0 @@ -- With issues: - - Use the search tool before opening a new issue. - - Please provide source code and commit sha if you found a bug. - - Review existing issues and provide feedback or react to them. - -## Description - - - -## How to reproduce - - - -TODO - -## Expectations - - - -TODO - -## Actual result - - - -TODO - -## Environment - -- KCLVM version: -- Operating system: diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md deleted file mode 100644 index 8717809e0..000000000 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ /dev/null @@ -1,6 +0,0 @@ -- With pull requests: - - Open your pull request against `main` - - Your pull request should have no more than two commits, if not you should squash them. - - It should pass all tests in the available continuous integration systems such as GitHub Actions. - - You should add/modify tests to cover your proposed code changes. - - If your pull request contains a new feature, please document it on the README. diff --git a/.github/workflows/backport.yaml b/.github/workflows/backport.yaml new file mode 100644 index 000000000..57336cfef --- /dev/null +++ b/.github/workflows/backport.yaml @@ -0,0 +1,17 @@ +name: Backport merged pull request +on: + pull_request_target: + types: [closed] +permissions: + contents: write # so it can comment + pull-requests: write # so it can create pull requests +jobs: + backport: + name: Backport pull request + runs-on: ubuntu-latest + # Don't run on closed unmerged pull requests + if: github.event.pull_request.merged + steps: + - uses: actions/checkout@v3 + - name: Create backport pull requests + uses: korthout/backport-action@v1 diff --git a/.github/workflows/build-test-alpine-linux-musl-arm64.yml b/.github/workflows/build-test-alpine-linux-musl-arm64.yml new file mode 100644 index 000000000..18410bf25 --- /dev/null +++ b/.github/workflows/build-test-alpine-linux-musl-arm64.yml @@ -0,0 +1,58 @@ +name: Build and Test Musl +on: + pull_request: + branches: + - main + push: + branches: + - main +jobs: + build-and-test-musl: + name: Build and Test on Alpine Linux (musl) + runs-on: ubuntu-latest + steps: + - name: Check out code + uses: actions/checkout@v3 + with: + submodules: "true" + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v2 + - name: Pull Alpine Linux Docker image + run: | + docker pull alpine:latest + - name: Build in Docker + run: | + docker run --rm \ + -v ${{ github.workspace }}:/workspace -w /workspace \ + alpine:latest \ + /bin/sh -c " + apk add --no-cache \ + bash \ + git \ + make \ + gcc \ + musl-dev \ + python3 \ + python3-dev \ + py3-pip \ + rust \ + cargo \ + && \ + export KCL_BUILD_GIT_SHA=$(git rev-parse HEAD) && \ + git config --global --add safe.directory /workspace && \ + git config --global user.name 'GitHub Action' && \ + git config --global user.email 'action@github.com' && \ + make && \ + make release && \ + _build/dist/linux/kclvm/bin/kclvm_cli version" + - name: Read VERSION file + id: read_version + run: | + VERSION=$(cat VERSION) + echo "VERSION=v${VERSION}" >> $GITHUB_ENV + - name: Upload Artifact + uses: actions/upload-artifact@v4 + with: + name: kcl-${{ env.VERSION }}-linux-musl + if-no-files-found: error + path: _build/kclvm-${{ env.VERSION }}-linux-amd64.tar.gz \ No newline at end of file diff --git a/.github/workflows/build-test-centos7-amd64.yaml b/.github/workflows/build-test-centos7-amd64.yaml new file mode 100644 index 000000000..d5eaadbad --- /dev/null +++ b/.github/workflows/build-test-centos7-amd64.yaml @@ -0,0 +1,53 @@ +name: Build and Test on centos7 amd64 +on: + pull_request: + branches: + - main + push: + branches: + - main +jobs: + build-and-test-centos7: + name: Build and Test on centos7 amd64 + runs-on: ubuntu-latest + steps: + - name: Check out code + uses: actions/checkout@v3 + with: + submodules: "true" + + - name: Set up QEMU + uses: docker/setup-qemu-action@v2 + with: + platforms: linux/amd64 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v2 + + - name: Pull custom centos7 Docker image + run: | + docker pull kcllang/kcl-builder:centos7 + + # Use llvm7 to build kcl in centos7 + - name: Release + run: | + docker run --rm \ + -v ${{ github.workspace }}:/workspace -w /workspace \ + kcllang/kcl-builder:centos7 \ + /bin/bash -c "export KCL_BUILD_GIT_SHA=$(git rev-parse HEAD) && source ~/.bash_profile && export PATH=$PATH:/opt/build/bin/ && sed -i 's/llvm12/llvm7/g' kclvm/compiler/Cargo.toml && git config --global --add safe.directory /workspace && git config --global user.name 'GitHub Action' && git config --global user.email 'action@github.com' && git add . && git commit -m 'chore: bump llvm version to 7.0' && make && make release" + + - name: Show Artifact Version + run: _build/dist/linux/kclvm/bin/kclvm_cli version + + - name: Read VERSION file + id: read_version + run: | + VERSION=$(cat VERSION) + echo "VERSION=v${VERSION}" >> $GITHUB_ENV + + - name: Upload Artifact + uses: actions/upload-artifact@v4 + with: + name: kcl-${{ env.VERSION }}-linux-amd64 + if-no-files-found: error + path: _build/kclvm-${{ env.VERSION }}-linux-amd64.tar.gz diff --git a/.github/workflows/build-test-macos-arm64.yml b/.github/workflows/build-test-macos-arm64.yml new file mode 100644 index 000000000..fc5b770ee --- /dev/null +++ b/.github/workflows/build-test-macos-arm64.yml @@ -0,0 +1,66 @@ +name: Build and Test on MacOS ARCH64 +on: + pull_request: + branches: + - main + push: + branches: + - main +env: + MACOSX_DEPLOYMENT_TARGET: '11.0' +jobs: + build-and-test: + # Ref: https://github.com/actions/runner-images/tree/main/images/macos + # Note: The arch of macos-13-xlarge and macos-14 is arm64 + strategy: + matrix: + os: [macos-13-xlarge, macos-14] + runs-on: ${{ matrix.os }} + steps: + - name: Git checkout + uses: actions/checkout@v2 + with: + submodules: "true" + + - run: clang --version + - run: cargo --version + - run: rustc --print sysroot + + - name: Delete rust cargo + run: rm -rf /root/.cargo/bin + shell: bash + - name: Install rust nightly toolchain + uses: actions-rs/toolchain@v1 + with: + toolchain: 1.79 + override: true + components: clippy, rustfmt + - name: Set up python + uses: actions/setup-python@v4 + with: + python-version: '3.11' + - name: Grammar test + working-directory: ./kclvm + run: export PATH=$PATH:$PWD/../_build/dist/darwin/kclvm/bin && make && make test-grammar + shell: bash + - name: Evaluator Grammar test + working-directory: ./kclvm + run: export PATH=$PATH:$PWD/../_build/dist/darwin/kclvm/bin && make test-grammar-evaluator + shell: bash + + - name: Release + run: export PATH=$PATH:$PWD/../_build/dist/darwin/kclvm/bin && make release + shell: bash + + - name: Read VERSION file + id: read_version + run: | + VERSION=$(cat VERSION) + echo "VERSION=v${VERSION}" >> $GITHUB_ENV + + - uses: actions/upload-artifact@v4 + if: "contains(matrix.os, 'macos-13-xlarge')" + with: + name: kcl-${{ env.VERSION }}-darwin-arm64 + if-no-files-found: error + path: _build/kclvm-${{ env.VERSION }}-darwin-arm64.tar.gz diff --git a/.github/workflows/build-test-ubuntu-arm64.yml b/.github/workflows/build-test-ubuntu-arm64.yml new file mode 100644 index 000000000..b084c711a --- /dev/null +++ b/.github/workflows/build-test-ubuntu-arm64.yml @@ -0,0 +1,49 @@ +name: Build and Test on Linux ARCH64 +on: + pull_request: + branches: + - main + push: + branches: + - main +jobs: + build-and-test-arm64: + name: Build and Test on Linux ARM64 + runs-on: ubuntu-latest + steps: + - name: Check out code + uses: actions/checkout@v3 + with: + submodules: "true" + + - name: Set up QEMU + uses: docker/setup-qemu-action@v2 + with: + platforms: linux/amd64,linux/arm64 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v2 + + - name: Pull custom ARM64 Docker image + run: | + docker pull --platform linux/arm64 kcllang/kcl-builder-arm64 + + - name: Build in Docker + run: | + docker run --rm --platform linux/arm64 \ + -v ${{ github.workspace }}:/workspace -w /workspace \ + kcllang/kcl-builder-arm64 \ + /bin/bash -c "export KCL_BUILD_GIT_SHA=$(git rev-parse HEAD) && git config --global --add safe.directory /workspace && git config --global user.name 'GitHub Action' && git config --global user.email 'action@github.com' && make && make release && _build/dist/linux/kclvm/bin/kclvm_cli version" + + - name: Read VERSION file + id: read_version + run: | + VERSION=$(cat VERSION) + echo "VERSION=v${VERSION}" >> $GITHUB_ENV + + - name: Upload Artifact + uses: actions/upload-artifact@v4 + with: + name: kcl-${{ env.VERSION }}-linux-arm64 + if-no-files-found: error + path: _build/kclvm-${{ env.VERSION }}-linux-arm64.tar.gz diff --git a/.github/workflows/github-actions.yaml b/.github/workflows/github-actions.yaml deleted file mode 100644 index 663b7416d..000000000 --- a/.github/workflows/github-actions.yaml +++ /dev/null @@ -1,39 +0,0 @@ -name: KCLVM-actions -on: [push] -jobs: - test-unit: - name: Test - runs-on: ubuntu-latest - container: - image: kusionstack/kclvm-builder - steps: - - name: Check out code - uses: actions/checkout@v3 - with: - submodules: 'true' - - name: Build KCLVM - run: make build - shell: bash - - name: Grammar test - run: | - chmod +x ./internal/kclvm_py/scripts/test_grammar.sh - topdir=$(realpath $(dirname $0)) ./internal/kclvm_py/scripts/test_grammar.sh - shell: bash - - name: Internal python unit test - run: | - chmod +x ./internal/kclvm_py/scripts/test_unit.sh - ./internal/kclvm_py/scripts/test_unit.sh - shell: bash - - name: Delete rust cargo - run: rm -rf /root/.cargo/bin - shell: bash - - name: Install rust nightly toolchain - uses: actions-rs/toolchain@v1 - with: - toolchain: nightly - override: true - components: clippy, rustfmt - - name: Rust unit test - working-directory: ./kclvm - run: make test - shell: bash diff --git a/.github/workflows/macos_test.yaml b/.github/workflows/macos_test.yaml new file mode 100644 index 000000000..96502779c --- /dev/null +++ b/.github/workflows/macos_test.yaml @@ -0,0 +1,95 @@ +name: build-and-test-macos +on: + pull_request: + branches: + - main + push: + branches: + - main +env: + MACOSX_DEPLOYMENT_TARGET: '10.13' +jobs: + build-and-test: + # Ref: https://github.com/actions/runner-images/tree/main/images/macos + strategy: + matrix: + os: [macos-13] + runs-on: ${{ matrix.os }} + steps: + - name: Git checkout + uses: actions/checkout@v2 + with: + submodules: "true" + + - name: Set up python + uses: actions/setup-python@v4 + with: + python-version: '3.11' + + - name: Set up Go + uses: actions/setup-go@v2 + with: + go-version: 1.23 + + - name: Install KCL CLI + run: | + go install kcl-lang.io/cli/cmd/kcl@main + echo "$(go env GOPATH)/bin" >> $GITHUB_PATH + echo "${{ github.workspace }}/go/bin" >> $GITHUB_PATH + + - run: clang --version + - run: cargo --version + - run: rustc --print sysroot + + - name: Delete rust cargo + run: rm -rf /root/.cargo/bin + shell: bash + - name: Install rust nightly toolchain + uses: actions-rs/toolchain@v1 + with: + toolchain: 1.79 + override: true + components: clippy, rustfmt + - name: Code format check + working-directory: ./kclvm + run: cargo fmt --check + shell: bash + - name: Grammar test + working-directory: ./kclvm + run: export PATH=$PATH:$PWD/../_build/dist/darwin/kclvm/bin && make && make test-grammar + shell: bash + - name: Evaluator Grammar test + working-directory: ./kclvm + run: export PATH=$PATH:$PWD/../_build/dist/darwin/kclvm/bin && make test-grammar-evaluator + shell: bash + - name: Runtime test + working-directory: ./kclvm + run: export PATH=$PATH:$PWD/../_build/dist/darwin/kclvm/bin && make test-runtime + shell: bash + + - name: Unit test + working-directory: ./kclvm + run: export PATH=$PATH:$PWD/../_build/dist/darwin/kclvm/bin && make codecov-lcov + shell: bash + + - name: Coveralls upload + uses: coverallsapp/github-action@master + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + path-to-lcov: ./kclvm/.kclvm_cov/lcov.info + + - name: Release + run: export PATH=$PATH:$PWD/../_build/dist/darwin/kclvm/bin && make release + shell: bash + + - name: Read VERSION file + id: read_version + run: | + VERSION=$(cat VERSION) + echo "VERSION=v${VERSION}" >> $GITHUB_ENV + + - uses: actions/upload-artifact@v4 + with: + name: kcl-${{ env.VERSION }}-darwin-amd64 + if-no-files-found: error + path: _build/kclvm-${{ env.VERSION }}-darwin-amd64.tar.gz diff --git a/.github/workflows/main_windows.yml b/.github/workflows/main_windows.yml deleted file mode 100644 index 857b46c79..000000000 --- a/.github/workflows/main_windows.yml +++ /dev/null @@ -1,38 +0,0 @@ -name: build-and-test-windows -on: push -jobs: - build-and-test: - runs-on: windows-2019 - env: - LLVM_SYS_120_PREFIX: "C:/LLVM" - KCLVM_CLANG: "C:/LLVM/bin/clang.exe" - steps: - - name: Git checkout - uses: actions/checkout@v2 - with: - submodules: 'true' - - - run: clang --version - - run: cargo --version - - - run: rustc --print sysroot - - - run: Rename-Item "C:/Program Files/LLVM" "C:/Program Files/LLVM-old" - - # Install LLVM-12 - - run: Invoke-WebRequest -Uri https://github.com/KusionStack/llvm-package-windows/releases/download/v12.0.1/LLVM-12.0.1-win64.7z -OutFile C:/LLVM-12.0.1-win64.7z - - run: Get-FileHash -Algorithm MD5 C:/LLVM-12.0.1-win64.7z # md5: 3fcf77f82c6c3ee650711439b20aebe5 - - run: 7z x -y C:/LLVM-12.0.1-win64.7z -o"C:/LLVM" - - run: Remove-Item C:/LLVM-12.0.1-win64.7z - - - run: echo "C:/LLVM/bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append - - - name: Run make - working-directory: scripts/build-windows - run: mingw32-make - - - run: scripts/build-windows/_output/kclvm-windows/kclvm_cli.exe -h - - run: scripts/build-windows/_output/kclvm-windows/kcl.exe ./samples/hello.k - - - run: Compress-Archive -Path scripts/build-windows/_output/kclvm-windows -DestinationPath C:/kclvm-windows.zip - - run: Get-FileHash -Algorithm MD5 C:/kclvm-windows.zip diff --git a/.github/workflows/mingw_test.yaml b/.github/workflows/mingw_test.yaml new file mode 100644 index 000000000..c9c70c844 --- /dev/null +++ b/.github/workflows/mingw_test.yaml @@ -0,0 +1,48 @@ +name: build-and-test-windows-mingw +on: + pull_request: + branches: + - main + push: + branches: + - main +jobs: + build-and-test: + name: build and test on windows mingw + runs-on: windows-latest + steps: + - name: Git checkout + uses: actions/checkout@v2 + with: + submodules: "true" + + - name: Install rust nightly toolchain + uses: actions-rs/toolchain@v1 + with: + toolchain: 1.79 + override: true + components: clippy, rustfmt + + - run: C:\msys64\usr\bin\pacman.exe -S --needed mingw-w64-x86_64-gcc --noconfirm + - shell: pwsh + run: echo "C:\msys64\mingw64\bin" >> $Env:GITHUB_PATH + + - working-directory: ./kclvm + run: | + rustup target add x86_64-pc-windows-gnu + cargo build -r --target x86_64-pc-windows-gnu + + - name: Read VERSION file + id: read_version + run: | + $version = Get-Content VERSION + echo "VERSION=v$version" >> $env:GITHUB_ENV + + - uses: actions/upload-artifact@v4 + with: + name: kclvm-${{ env.VERSION }}-windows-mingw + if-no-files-found: error + path: | + kclvm/target/x86_64-pc-windows-gnu/release/libkclvm_cli_cdylib.a + kclvm/target/x86_64-pc-windows-gnu/release/libkclvm_cli_cdylib.dll.a + kclvm/target/x86_64-pc-windows-gnu/release/kclvm_cli_cdylib.dll diff --git a/.github/workflows/test_compiler_base.yaml b/.github/workflows/test_compiler_base.yaml new file mode 100644 index 000000000..e573c5281 --- /dev/null +++ b/.github/workflows/test_compiler_base.yaml @@ -0,0 +1,57 @@ +name: build-and-test-compiler-base +on: + push: + paths: + - 'compiler_base/**' + pull_request: + paths: + - 'compiler_base/**' + +jobs: + check-fmt: + name: Test + strategy: + matrix: + os: [ubuntu-latest, windows-latest, macos-latest] + runs-on: ${{ matrix.os }} + steps: + - name: Check out code + uses: actions/checkout@v3 + with: + submodules: "true" + - name: Install rust nightly toolchain + uses: actions-rs/toolchain@v1 + with: + toolchain: 1.79 + override: true + components: clippy, rustfmt + - name: Rust code format check + working-directory: ./compiler_base + run: cargo fmt --check + shell: bash + test-codecov-lcov: + name: Test + strategy: + matrix: + os: [ubuntu-latest, macos-latest] + runs-on: ${{ matrix.os }} + steps: + - name: Check out code + uses: actions/checkout@v3 + with: + submodules: "true" + - name: Install rust nightly toolchain + uses: actions-rs/toolchain@v1 + with: + toolchain: 1.79 + override: true + components: clippy, rustfmt + - name: Compiler_base rust unit test + working-directory: ./compiler_base + run: make codecov-lcov + shell: bash + - name: Coveralls upload + uses: coverallsapp/github-action@master + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + path-to-lcov: ./compiler_base/.compiler_base/lcov.info diff --git a/.github/workflows/ubuntu_test.yaml b/.github/workflows/ubuntu_test.yaml new file mode 100644 index 000000000..de8fbc61d --- /dev/null +++ b/.github/workflows/ubuntu_test.yaml @@ -0,0 +1,67 @@ +name: build-and-test-ubuntu +on: + pull_request: + branches: + - main + push: + branches: + - main +jobs: + build-and-test: + # Ref: https://github.com/actions/runner-images/tree/main/images/linux + name: Test + runs-on: ubuntu-latest + steps: + - name: Check out code + uses: actions/checkout@v3 + with: + submodules: "true" + - name: Set up Go + uses: actions/setup-go@v2 + with: + go-version: 1.23 + + # Prerequisite + + - name: Install Python3 (for Grammar test) + shell: bash + run: | + sudo apt-get update + sudo apt-get install -y git wget curl make + sudo apt-get install python3 python3-pip -y + - name: Install rust nightly toolchain + uses: actions-rs/toolchain@v1 + with: + toolchain: 1.79 + override: true + components: clippy, rustfmt + - name: Code format check + working-directory: ./kclvm + run: cargo fmt --check + shell: bash + - name: Code clippy check + working-directory: ./kclvm + run: cargo clippy --no-deps -r + shell: bash + - name: Grammar test + working-directory: ./kclvm + run: export PATH=$PATH:$PWD/../_build/dist/linux/kclvm/bin && make && make test-grammar + shell: bash + - name: Evaluator Grammar test + working-directory: ./kclvm + run: export PATH=$PATH:$PWD/../_build/dist/linux/kclvm/bin && make test-grammar-evaluator + shell: bash + - name: Runtime test + working-directory: ./kclvm + run: export PATH=$PATH:$PWD/../_build/dist/linux/kclvm/bin && make test-runtime + shell: bash + - name: Install KCL CLI + run: | + go install kcl-lang.io/cli/cmd/kcl@main + echo "$(go env GOPATH)/bin" >> $GITHUB_PATH + echo "${{ github.workspace }}/go/bin" >> $GITHUB_PATH + - name: Unit test + working-directory: ./kclvm + run: export PATH=$PATH:$PWD/../_build/dist/linux/kclvm/bin && make test + shell: bash + diff --git a/.github/workflows/wasm_test.yaml b/.github/workflows/wasm_test.yaml new file mode 100644 index 000000000..497f66fb4 --- /dev/null +++ b/.github/workflows/wasm_test.yaml @@ -0,0 +1,38 @@ +name: build-and-test-wasm +on: + pull_request: + branches: + - main + push: + branches: + - main +jobs: + build-and-test: + # Ref: https://github.com/actions/runner-images/tree/main/images/linux + name: Test + runs-on: ubuntu-latest + steps: + - name: Check out code + uses: actions/checkout@v3 + with: + submodules: "true" + + - name: Install rust nightly toolchain + uses: actions-rs/toolchain@v1 + with: + toolchain: 1.79 + override: true + components: clippy, rustfmt + + - name: Unit test + working-directory: ./kclvm + run: | + rustup target add wasm32-wasi && make build-wasm + mv target/wasm32-wasi/release/kclvm_cli_cdylib.wasm target/wasm32-wasi/release/kcl.wasm + shell: bash + + - uses: actions/upload-artifact@v4 + with: + name: kcl-wasm + if-no-files-found: error + path: kclvm/target/wasm32-wasi/release/kcl.wasm diff --git a/.github/workflows/windows_test.yaml b/.github/workflows/windows_test.yaml new file mode 100644 index 000000000..b55178641 --- /dev/null +++ b/.github/workflows/windows_test.yaml @@ -0,0 +1,82 @@ +name: build-and-test-windows +on: + pull_request: + branches: + - main + push: + branches: + - main +jobs: + build-and-test: + name: build and test on windows + runs-on: windows-latest + env: + LLVM_SYS_120_PREFIX: "C:/LLVM" + KCLVM_CLANG: "C:/LLVM/bin/clang.exe" + steps: + - name: Git checkout + uses: actions/checkout@v2 + with: + submodules: "true" + + - name: Install rust nightly toolchain + uses: actions-rs/toolchain@v1 + with: + toolchain: 1.79 + override: true + components: clippy, rustfmt + + - name: Set up Go + uses: actions/setup-go@v2 + with: + go-version: 1.23 + + - name: Install KCL + shell: powershell + run: | + go install kcl-lang.io/cli/cmd/kcl@main + $GoPath = go env GOPATH + $GoInstallBin = Join-Path $GoPath "bin" + $Env:PATH += ";$GoInstallBin" + $Env:PATH += ";${{ github.workspace }}\go\bin" + + - uses: ilammy/msvc-dev-cmd@v1 + + - run: clang --version + - run: cargo --version + + # Install LLVM-12 + - run: Invoke-WebRequest -Uri https://github.com/kcl-lang/llvm-package-windows/releases/download/v12.0.1/LLVM-12.0.1-win64.7z -OutFile C:/LLVM-12.0.1-win64.7z + - run: Get-FileHash -Algorithm MD5 C:/LLVM-12.0.1-win64.7z # md5: 3fcf77f82c6c3ee650711439b20aebe5 + - run: 7z x -y C:/LLVM-12.0.1-win64.7z -o"C:/LLVM" + - run: Remove-Item C:/LLVM-12.0.1-win64.7z + + - run: echo "C:/LLVM/bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append + + # Build kclvm CLI + - run: .\scripts\build-windows\build.ps1 + + # Set kclvm CLI into PATH + - run: echo ";$(pwd)\scripts\build-windows\_output\kclvm-windows\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append + working-directory: . + + # Rust unit test + - run: cargo test --workspace -r -- --nocapture + working-directory: ./kclvm + + - name: Read VERSION file + id: read_version + run: | + $version = Get-Content VERSION + echo "VERSION=v$version" >> $env:GITHUB_ENV + + - name: Rename kclvm-windows folder + run: | + $version = "${{ env.VERSION }}" + Rename-Item -Path ".\scripts\build-windows\_output\kclvm-windows" -NewName "kclvm-$version-windows" + + - uses: actions/upload-artifact@v4 + with: + name: kclvm-${{ env.VERSION }}-windows + if-no-files-found: error + path: scripts/build-windows/_output/kclvm-${{ env.VERSION }}-windows diff --git a/.gitignore b/.gitignore index da7c25fb7..5af2a7fca 100644 --- a/.gitignore +++ b/.gitignore @@ -25,6 +25,7 @@ __kcl_test_main.k /kcl-go* /_build_dist .kusion +._target /venv/ @@ -74,13 +75,21 @@ lark_parser.pickle /scripts/docker/kclvm-builder-centos7/crates.io-index /scripts/docker/kclvm-builder-ubuntu/crates.io-index *.tar.gz + +# KCL cache and temp output +.kclvm +.kclvm_cov +*.dylib +*.so +*.dll +*.lock +*.ll +*.ll.lock _a.out.* _a.out_*.* -# KCLVM cache -.kclvm -__main__.dylib -__main__.so -__main__.dll -__main__.lock -__main__.ll -__main__.ll.lock + +# Compiler_base +.compiler_base + +# KCL mod lock file +!.mod.lock diff --git a/.gitmodules b/.gitmodules index 56f9403ef..431e3bb6d 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,3 @@ -[submodule "plugins"] - path = plugins - url = https://github.com/KusionStack/kcl-plugin +[submodule "test/integration/konfig"] + path = test/integration/konfig + url = https://github.com/KusionStack/konfig.git diff --git a/ADOPTERS.md b/ADOPTERS.md new file mode 100644 index 000000000..0ca3f3cf9 --- /dev/null +++ b/ADOPTERS.md @@ -0,0 +1,11 @@ +# Adopters + +This list shows non-exhaustive adopters of KCL. If you are using to KCL, then please add your team and use-case to this file. + +## Adopters list + +### Organizations + ++ *[Ant Group](https://www.antgroup.com/)* - Large scale Kubernetes configuration abstraction and management with GitOps. ++ *[Youzan](https://www.youzan.com/)* - Large scale Kubernetes configuration abstraction and management with GitOps. ++ *[Huawei](https://www.huawei.com/)* - Terraform resource model abstraction and management. diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 000000000..b4cb411b7 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,128 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +We as members, contributors, and leaders pledge to make participation in our +community a harassment-free experience for everyone, regardless of age, body +size, visible or invisible disability, ethnicity, sex characteristics, gender +identity and expression, level of experience, education, socio-economic status, +nationality, personal appearance, race, religion, or sexual identity +and orientation. + +We pledge to act and interact in ways that contribute to an open, welcoming, +diverse, inclusive, and healthy community. + +## Our Standards + +Examples of behavior that contributes to a positive environment for our +community include: + +* Demonstrating empathy and kindness toward other people +* Being respectful of differing opinions, viewpoints, and experiences +* Giving and gracefully accepting constructive feedback +* Accepting responsibility and apologizing to those affected by our mistakes, + and learning from the experience +* Focusing on what is best not just for us as individuals, but for the + overall community + +Examples of unacceptable behavior include: + +* The use of sexualized language or imagery, and sexual attention or + advances of any kind +* Trolling, insulting or derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or email + address, without their explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Enforcement Responsibilities + +Community leaders are responsible for clarifying and enforcing our standards of +acceptable behavior and will take appropriate and fair corrective action in +response to any behavior that they deem inappropriate, threatening, offensive, +or harmful. + +Community leaders have the right and responsibility to remove, edit, or reject +comments, commits, code, wiki edits, issues, and other contributions that are +not aligned to this Code of Conduct, and will communicate reasons for moderation +decisions when appropriate. + +## Scope + +This Code of Conduct applies within all community spaces, and also applies when +an individual is officially representing the community in public spaces. +Examples of representing our community include using an official e-mail address, +posting via an official social media account, or acting as an appointed +representative at an online or offline event. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported to the community leaders responsible for enforcement at +xpf6677@gmail.com. +All complaints will be reviewed and investigated promptly and fairly. + +All community leaders are obligated to respect the privacy and security of the +reporter of any incident. + +## Enforcement Guidelines + +Community leaders will follow these Community Impact Guidelines in determining +the consequences for any action they deem in violation of this Code of Conduct: + +### 1. Correction + +**Community Impact**: Use of inappropriate language or other behavior deemed +unprofessional or unwelcome in the community. + +**Consequence**: A private, written warning from community leaders, providing +clarity around the nature of the violation and an explanation of why the +behavior was inappropriate. A public apology may be requested. + +### 2. Warning + +**Community Impact**: A violation through a single incident or series +of actions. + +**Consequence**: A warning with consequences for continued behavior. No +interaction with the people involved, including unsolicited interaction with +those enforcing the Code of Conduct, for a specified period of time. This +includes avoiding interactions in community spaces as well as external channels +like social media. Violating these terms may lead to a temporary or +permanent ban. + +### 3. Temporary Ban + +**Community Impact**: A serious violation of community standards, including +sustained inappropriate behavior. + +**Consequence**: A temporary ban from any sort of interaction or public +communication with the community for a specified period of time. No public or +private interaction with the people involved, including unsolicited interaction +with those enforcing the Code of Conduct, is allowed during this period. +Violating these terms may lead to a permanent ban. + +### 4. Permanent Ban + +**Community Impact**: Demonstrating a pattern of violation of community +standards, including sustained inappropriate behavior, harassment of an +individual, or aggression toward or disparagement of classes of individuals. + +**Consequence**: A permanent ban from any sort of public interaction within +the community. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], +version 2.0, available at +https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. + +Community Impact Guidelines were inspired by [Mozilla's code of conduct +enforcement ladder](https://github.com/mozilla/diversity). + +[homepage]: https://www.contributor-covenant.org + +For answers to common questions about this code of conduct, see the FAQ at +https://www.contributor-covenant.org/faq. Translations are available at +https://www.contributor-covenant.org/translations. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md deleted file mode 100644 index c0de0584f..000000000 --- a/CONTRIBUTING.md +++ /dev/null @@ -1,134 +0,0 @@ -# KCLVM Developing Guide - -KCLVM follows a very standard Github development process, using Github tracker for issues and merging pull requests into master. If you would like to contribute something, or simply want to hack on the code this document should help you get started. - -Before we accept a non-trivial patch or pull request we will need you to sign the Contributor License Agreement. Signing the contributor’s agreement does not grant anyone commits rights to the main repository, but it does mean that we can accept your contributions, and you will get an author credit if we do. Active contributors might be asked to join the core team and given the ability to merge pull requests. - -## Install Dependencies - -### macOS and OS X - -+ `Python3.7+` -+ `Go 1.16+` -+ `Rust 2021 edition` -+ `openssl@1.1` - -``` -brew install openssl@1.1 -``` - -### Linux - -+ `Go 1.16+` -+ `Rust 2021 edition` -+ `Python3 Building Dependencies` - -For UNIX based systems, you can run: - -``` -yum groupinstall -y "Development Tools" -yum install -y gcc patch libffi-devel python-devel zlib-devel bzip2-devel ncurses-devel sqlite-devel -yum install -y libpcap-devel xz-devel readline-devel tk-devel gdbm-devel db4-deve -yum -y install yum-utils -yum-builddep -y python3 -yum install -y zlib* -yum install -y openssl-devel -yum install -y glibc-static -``` - -On Debian, Ubuntu, and other apt based systems, you can run: - -``` -apt-get update - -apt-get install -y git wget curl -apt-get install -y make gcc patch -apt-get install -y python-dev libffi-dev -apt-get install -y zlib1g-dev ncurses-dev build-essential libncurses5-dev libgdbm-dev libnss3-dev libssl-dev libreadline-dev libffi-dev -``` - -### Docker - -Use the image `kusionstack/kclvm-builder`, run: - -``` -make sh-in-docker -``` - -## Building and Testing - -### Scripting - -We provide a simple `run.sh` script to build and package with. - -To build everything, run: - -``` -./run.sh -a build -``` - -Building includes two steps, which are `build-cpython` and `build-kclvm`. Alternatively, these steps can be invoked separately: - -``` -./run.sh -a build-cpython -./run.sh -a build-kclvm -``` - -Building KCL requires local ssl module. Use -s $yourLocalSSL to specify custom ssl path: - -``` -./run.sh -a build -s $your-local-ssl -./run.sh -a build-cpython -s $your-local-ssl -``` - -If -s option unset, default ssl path will be used: -Darwin: `$(brew --prefix openssl@1.1)` -Linux: `/usr/lib64` - -To use KCL, add the path `_build/dist/{os}/kclvm/bin` to the `PATH` environment variable. Here, `{os}` stands for the operating system, which can be `Darwin`, `centos`, `ubuntu` or other types. - -Then, you can run: - -``` -kcl hello.k -``` - -To perform testing, run: - -``` -./run.sh -a test -``` - -Next, we can refer to [KCLVM README](./kclvm/README.md) for the next step of environment configuration and build the KCLVM rust code. - -If we have changed any codes in the program, we can update kclvm binaries, run: - -``` -./run.sh -a update-kclvm -``` - -To build a tar file, run: - -``` -./run.sh -a release -``` - -## Using KCL - -The specific user manual is as follows: [KCLVM User Manual](docs/cmd/README_KCLVM_USE.md) - -## Code Structure - -KCL has added the following files and directories: - -+ `kclvm` - The KCL compiler code. -+ `test` - All KCL test cases include regression tests and unit tests. -+ `scripts` - The directory where additional scripts to build and test KCL resist. -+ `run.sh` - The script to perform operations such as building and testing. -+ `internal/kclvm_py` - KCLVM Python implementation, will be abandoned soon, please do not submit any code to it, it will be reorganized in the way of KCLVM Python SDK in the future. -+ `docs` - KCL command line Documentation. -+ `spec` - KCL model and API Specification. - -During building and testing, the following directories can be generated: - -+ `_build` - The directory to save building results including distributions. diff --git a/GOVERNANCE.md b/GOVERNANCE.md new file mode 100644 index 000000000..79eff78c1 --- /dev/null +++ b/GOVERNANCE.md @@ -0,0 +1,65 @@ +# KCL Project Governance + +As a CNCF sandbox project, the KCL project adheres to the [CNCF Code of Conduct](https://github.com/cncf/foundation/blob/master/code-of-conduct.md). + +## Overview + +- [KCL Project Governance](#kcl-project-governance) + - [Overview](#overview) + - [Maintainer Ship](#maintainer-ship) + - [Adding Maintainers](#adding-maintainers) + - [Removal of Inactive Maintainers](#removal-of-inactive-maintainers) + - [Decision-Making Process](#decision-making-process) + - [Updating Governance](#updating-governance) + +## Maintainer Ship + +Maintainers of the KCL project share the responsibility of its success. They have three main responsibilities: + ++ Share responsibility for the project's success. ++ Make a long-term investment to improve the project. ++ Spend time on tasks that may not be the most interesting, but are essential for the project's success. + +Maintainers often work tirelessly, but their contributions may not always be fully appreciated. While it may be easy to focus on the more exciting and technically advanced features, it is equally important to work on minor bug fixes, small improvements, long-term stability optimizations, and other essential aspects of the project. + +## Adding Maintainers + +Maintainers are individuals who have shown dedication to the long-term success of the project. Contributors wishing to become maintainers should have actively participated in tackling issues, contributing code, and reviewing proposals and code for a period of at least two months. + +Maintainer ship is built on trust, which extends beyond code contributions. It is important for potential maintainers to earn the trust of current maintainers by demonstrating their commitment to the best interests of the project. + +Current maintainers hold regular maintainer meetings to identify active contributors who have consistently invested time in the project over the prior months. From this list, if one or more individuals are deemed qualified candidates, a proposal to add them as maintainers can be submitted on GitHub via a pull request. If at least 50% of the maintainers agree with the proposal, the newly added maintainer(s) will be considered valid. + +## Removal of Inactive Maintainers + +Similar to adding maintainers, existing maintainers can be removed from the active maintainer list. If an existing maintainer meets one of the following conditions, any other maintainer can propose their removal via a pull request: + ++ The maintainer has not participated in community activities for more than three months. ++ The maintainer has violated the governance rules more than twice. + +Once the above conditions are confirmed, the maintainer can be removed from the list, unless the original maintainer requests to remain and receives at least 50% of the votes from other maintainers. + +If a maintainer is removed from the maintaining list, the other maintainers should acknowledge their contribution by adding their name to an alumni section. + +## Decision-Making Process + +The KCL project is an open-source project that values openness. This means that the KCL repository is the source of truth for every aspect of the project, including values, design, documentation, roadmap, interfaces, etc. If it is part of the project, it should be in the repository. + +All decisions, regardless of their size, should follow the following three steps to be considered an update to the project: + +1. Open a pull request. +2. Discuss the changes under the pull request. +3. Merge or reject the pull request. + +When the KCL project has less than seven maintainers, a pull request (except for adding maintainers) may be merged if it meets the following conditions: + ++ At least one maintainer comments "LGTM" (Looks Good To Me) on the pull request. ++ No other maintainers have opposing opinions. + +When the KCL project has more than seven maintainers, a pull request (except for adding maintainers) may be merged if it meets the following conditions: + ++ At least two maintainers comment "LGTM" (Looks Good To Me) on the pull request. + +## Updating Governance + +Any substantive updates to the Governance require a supermajority vote from the maintainers. diff --git a/MAINTAINERS b/MAINTAINERS new file mode 100644 index 000000000..6443f3449 --- /dev/null +++ b/MAINTAINERS @@ -0,0 +1,10 @@ +Pengfei Xu Ant Group Peefy +Xiaodong Duo Ant Group ldxdl +Chaoqun Huang TuSimple ekkoful +Shushan Chai Ant Group chai2010 +Rui Xia Ant Group amyXia1994 +Zhe Zong Ant Group zong-zhe +Xiangfei Chen <897013703@qq.com> Ant Group NeverRaR +Zheng Zhang <18012015693@163.com> Ant Group He1pa +Yi Zhen Ant Group i-zhen +Junxing Zhu Southeast University jakezhu9 diff --git a/Makefile b/Makefile index 6962930d7..32541693d 100644 --- a/Makefile +++ b/Makefile @@ -1,11 +1,11 @@ -# Copyright 2021 The KCL Authors. All rights reserved. +# Copyright The KCL Authors. All rights reserved. -PROJECT_NAME = KCLVM +PROJECT_NAME = kcl PWD:=$(shell pwd) -KCLVM_VERSION := $(shell cat VERSION) -BUILD_IMAGE:=kusionstack/kclvm-builder +VERSION := $(shell cat VERSION) +BUILD_IMAGE:=kcllang/kcl-builder # export DOCKER_DEFAULT_PLATFORM=linux/amd64 # or @@ -14,17 +14,45 @@ BUILD_IMAGE:=kusionstack/kclvm-builder RUN_IN_DOCKER:=docker run -it --rm RUN_IN_DOCKER+=-v ~/.ssh:/root/.ssh RUN_IN_DOCKER+=-v ~/.gitconfig:/root/.gitconfig -RUN_IN_DOCKER+=-v ~/go/pkg/mod:/go/pkg/mod RUN_IN_DOCKER+=-v ${PWD}:/root/kclvm RUN_IN_DOCKER+=-w /root/kclvm ${BUILD_IMAGE} # ---------------- -# KCLVM build +# Build # ---------------- +.PHONY: build build: ${PWD}/run.sh -a build +.PHONY: build-lsp +build-lsp: + make -C ./kclvm build-lsp + +.PHONY: release +release: + ${PWD}/run.sh -a release + +.PHONY: check +check: + make -C ./kclvm check + +.PHONY: test +test: + make -C ./kclvm test + +.PHONY: test-grammar +test-grammar: + make -C ./kclvm test-grammar + +.PHONY: fmt +fmt: + make -C ./kclvm fmt + +.PHONY: tag +tag: + scripts/tag.sh v$(VERSION) + # ---------------- # Docker # ---------------- diff --git a/README-zh.md b/README-zh.md new file mode 100644 index 000000000..e4076a7b3 --- /dev/null +++ b/README-zh.md @@ -0,0 +1,87 @@ +

KCL: 基于约束的记录及函数语言

+ +

+English | 简体中文 +

+

+介绍 | 特性 | 场景 | 安装 | 文档 | 贡献 | 路线规划 +

+ +

+ + + + + + + + +

+ +## 介绍 + +KCL 是一个开源的基于约束的记录及函数语言并通过成熟的编程语言技术和实践来改进对大量繁杂配置比如云原生 Kubernetes 配置场景的编写,致力于构建围绕配置的更好的模块化、扩展性和稳定性,更简单的逻辑编写,以及更简单的自动化和生态工具集成。 + +

+ +

+ +## 场景 + +您可以将 KCL 用于 + ++ [生成静态配置数据](https://kcl-lang.io/docs/user_docs/guides/configuration)如 JSON, YAML 等,或者[与已有的数据进行集成](https://kcl-lang.io/docs/user_docs/guides/data-integration) ++ [使用 Schema 对配置数据进行抽象建模](https://kcl-lang.io/docs/user_docs/guides/schema-definition)并减少配置数据中的样板文件 ++ [为配置数据定义带有规则约束](https://kcl-lang.io/docs/user_docs/guides/validation)的 Schema 并对数据进行自动验证 ++ [通过梯度自动化方案和 GitOps](https://kcl-lang.io/docs/user_docs/guides/automation)无副作用地组织、简化、统一和管理庞大的配置 ++ 通过[分块编写配置数据](https://kcl-lang.io/docs/reference/lang/tour#config-operations)为不同的环境可扩展地管理庞大的配置 ++ 通过与[云原生配置工具](https://www.kcl-lang.io/docs/user_docs/guides/working-with-k8s/mutate-manifests/kubectl-kcl-plugin)集成直接编辑或校验存量 Kubernetes 资源 ++ 与 [KusionStack](https://kusionstack.io) 一起,用作平台工程语言来交付现代应用程序 + +## 特性 + ++ **简单易用**:源于 Python、Golang 等高级语言,采纳函数式编程语言特性,低副作用 ++ **设计良好**:独立的规范驱动的语法、语义、运行时和系统库设计 ++ **快速建模**:[开箱即用的模型库](https://artifacthub.io/packages/search?org=kcl&sort=relevance&page=1)和以 [Schema](https://kcl-lang.io/docs/reference/lang/tour#schema) 为中心的配置类型及模块化抽象 ++ **功能完备**:基于 [Config](https://kcl-lang.io/docs/reference/lang/tour#config-operations)、[Schema](https://kcl-lang.io/docs/reference/lang/tour#schema)、[Lambda](https://kcl-lang.io/docs/reference/lang/tour#function)、[Rule](https://kcl-lang.io/docs/reference/lang/tour#rule) 的配置及其模型、逻辑和策略编写 ++ **可靠稳定**:依赖[静态类型系统](https://kcl-lang.io/docs/reference/lang/tour/#type-system)、[约束](https://kcl-lang.io/docs/reference/lang/tour/#validation)和[自定义规则](https://kcl-lang.io/docs/reference/lang/tour#rule)的配置稳定性 ++ **强可扩展**:通过独立配置块[自动合并机制](https://kcl-lang.io/docs/reference/lang/tour/#-operators-1)保证配置编写的高可扩展性 ++ **易自动化**:[CRUD APIs](https://kcl-lang.io/docs/reference/lang/tour/#kcl-cli-variable-override),[多语言 SDK](https://kcl-lang.io/docs/reference/xlang-api/overview),[语言插件](https://github.com/kcl-lang/kcl-plugin) 构成的梯度自动化方案 ++ **极致性能**:使用 Rust & C,[LLVM](https://llvm.org/) 实现,支持编译到本地代码和 [WASM](https://webassembly.org/) 的高性能编译时和运行时 ++ **API 亲和**:原生支持 [OpenAPI](https://github.com/kcl-lang/kcl-openapi)、 Kubernetes CRD, Kubernetes Resource Model (KRM) 等 API 生态规范 ++ **开发友好**:[语言工具](https://kcl-lang.io/docs/tools/cli/kcl/) (Format,Lint,Test,Vet,Doc, 包管理工具等) 和 [IDE 插件](https://kcl-lang.io/docs/tools/Ide/) 构建良好的研发体验 ++ **安全可控**:面向领域,不原生提供线程、IO 等系统级功能,低噪音,低安全风险,易维护,易治理 ++ **多语言 SDK**:Rust, Go, Python, .NET, Java 和 Node.js 等 SDK 满足不同场景和应用使用需求 ++ **生态集成**:通过 [Kubectl KCL 插件](https://github.com/kcl-lang/kubectl-kcl)、[Kustomize KCL 插件](https://github.com/kcl-lang/kustomize-kcl)、[Helm KCL 插件](https://github.com/kcl-lang/helm-kcl) 、[KPT KCL SDK](https://github.com/kcl-lang/kpt-kcl) 或者 [Crossplane KCL 函数](https://github.com/kcl-lang/crossplane-kcl) 直接编辑、校验或者抽象资源 + ++ **生产可用**:广泛应用在蚂蚁集团平台工程及自动化的生产环境实践中 + +## 如何选择 + +详细的功能和场景对比参考[这里](https://kcl-lang.io/docs/user_docs/getting-started/intro)。 + +## 安装 + +有关安装的更多信息,请查看 KCL 官网的[安装指南](https://kcl-lang.io/docs/user_docs/getting-started/install/) + +## 文档 + +更多文档请访问[KCL 网站](https://kcl-lang.io/) + +## 贡献 + +参考[开发手册](./docs/dev_guide/1.about_this_guide.md)。您也可以直接在 GitHub Codespaces 中打开该项目开始贡献。 + +[![用 GitHub Codespaces 打开](https://github.com/codespaces/badge.svg)](https://codespaces.new/kcl-lang/kcl) + +## 路线规划 + +参考[KCL 路线规划](https://github.com/kcl-lang/kcl/issues/882) + +## 社区 + +欢迎访问 [社区](https://github.com/kcl-lang/community) 加入我们。 + +## License + +[![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fkcl-lang%2Fkcl.svg?type=large)](https://app.fossa.com/projects/git%2Bgithub.com%2Fkcl-lang%2Fkcl?ref=badge_large) diff --git a/README.md b/README.md index bccca797e..fa47b974e 100644 --- a/README.md +++ b/README.md @@ -1,91 +1,86 @@ -# KCL +

KCL: Constraint-based Record & Functional Language

-![license](https://img.shields.io/badge/license-Apache--2.0-green.svg) -[![Continuous Integration](https://github.com/KusionStack/KCLVM/actions/workflows/github-actions.yaml/badge.svg)](https://github.com/KusionStack/KCLVM/actions?query=branch%3Amain) +

+English | 简体中文 +

+

+Introduction | Features | What is it for | Installation | Documentation | Contributing | Roadmap +

-[中文](./README_ZH.md) +

+ + + + + + + + +

-Kusion Configuration Language (KCL) is an open source configuration language mainly used in [Kusion Stack](https://kusionstack.io). KCL is a statically typed language for configuration and policy scenarios, based on concepts such as declarative and Object-Oriented Programming (OOP) paradigms. +## Introduction -## Core Features +KCL is an open-source, constraint-based record and functional language that enhances the writing of complex configurations, including those for cloud-native scenarios. With its advanced programming language technology and practices, KCL is dedicated to promoting better modularity, scalability, and stability for configurations. It enables simpler logic writing and offers ease of automation APIs and integration with homegrown systems. -+ **Simple** - + Originated from Python and Golang, incorporating functional language features. - + Absorbs integrated language elements such as statements, expressions, conditions, loops, etc. - + Type and data separation, schema declaration configuration definition. -+ **Stable** - + Strong immutable constraint. - + Compile-time type deduction, type checking. - + Rule policy definition: attribute-centric constraint expressions, query results based on constraints. - + Testable: assert, print, and test tools. -+ **Scalable** - + Configuration unification: compile-time configuration dependency graph substitution. - + Configuration attribute operators: meet the needs of configuration override, merge, add and delete, etc. - + Configuration reuse: rich built-in data structures and syntax semantics, easily to expand one configuration of different scenarios. -+ **Engineering** - + Schema single inheritance and declarative model reuse and assembly. - + Tool & API granular configuration automation. - + Rich built-in functions and system libraries. - + Top-level dynamic data input. - + Code organization: modules and packages. - + [Plug-in system](https://github.com/KusionStack/kcl-plugin): reuse common programming language ecology. - + [OpenAPI model support](https://github.com/KusionStack/kcl-openapi): Swagger and KCL schema bidirectional conversion, Kubernetes CRD conversion to KCL schema. -+ **High Performance** - + Works with the LLVM optimizer, supports compilation to native code and formats like WASM and executes efficiently. +

+ +

-## Installing & Documentation +## What is it for? -### How to install +You can use KCL to -[Download](https://github.com/KusionStack/KCLVM/releases) the latest release from GitHub and add `{install-location}/kclvm/bin` to environment PATH. ++ [Generate low-level static configuration data](https://kcl-lang.io/docs/user_docs/guides/configuration) such as JSON, YAML, etc., or [integrate with existing data](https://kcl-lang.io/docs/user_docs/guides/data-integration). ++ Reduce boilerplate in configuration data with the [schema modeling](https://kcl-lang.io/docs/user_docs/guides/schema-definition). ++ Define schemas with [rule constraints for configuration data and validate](https://kcl-lang.io/docs/user_docs/guides/validation) them automatically. ++ Organize, simplify, unify and manage large configurations without side effects through [gradient automation schemes and GitOps](https://kcl-lang.io/docs/user_docs/guides/automation). ++ Manage large configurations in a scalable way for different environments with [isolated configuration blocks](https://kcl-lang.io/docs/reference/lang/tour#config-operations). ++ Mutating or validating Kubernetes resources with [cloud-native configuration tool plugins](https://www.kcl-lang.io/docs/user_docs/guides/working-with-k8s/mutate-manifests/kubectl-kcl-plugin). ++ Used as a platform engineering programming language to deliver modern applications with [KusionStack](https://kusionstack.io). -### Quick Showcase +## Features -`./samples/fib.k` is an example of calculating the Fibonacci sequence. ++ **Easy-to-use**: Originated from high-level languages ​​such as Python and Golang, incorporating functional language features with low side effects. ++ **Well-designed**: Independent spec-driven syntax, semantics, runtime and system modules design. ++ **Quick modeling**: [Out-of-the-box modules](https://artifacthub.io/packages/search?org=kcl&sort=relevance&page=1) and [Schema](https://kcl-lang.io/docs/reference/lang/tour#schema)-centric configuration types and modular abstraction. ++ **Rich capabilities**: Configuration with type, logic and policy based on [Config](https://kcl-lang.io/docs/reference/lang/tour#config-operations), [Schema](https://kcl-lang.io/docs/reference/lang/tour#schema), [Lambda](https://kcl-lang.io/docs/reference/lang/tour#function), [Rule](https://kcl-lang.io/docs/reference/lang/tour#rule). ++ **Stability**: Configuration stability is achieved through a [static type system](https://kcl-lang.io/docs/reference/lang/tour/#type-system), [constraints](https://kcl-lang.io/docs/reference/lang/tour/#validation), and [rules](https://kcl-lang.io/docs/reference/lang/tour#rule). ++ **Scalability**: High scalability is assured with an [automatic merge mechanism](https://kcl-lang.io/docs/reference/lang/tour/#-operators-1) of isolated config blocks. ++ **Fast automation**: Gradient automation scheme of [CRUD APIs](https://kcl-lang.io/docs/reference/lang/tour/#kcl-cli-variable-override), [multilingual SDKs](https://kcl-lang.io/docs/reference/xlang-api/overview), and [language plugin](https://github.com/kcl-lang/kcl-plugin) ++ **High performance**: High compile-time and runtime performance using Rust & C and [LLVM](https://llvm.org/), and support compilation to native code and [WASM](https://webassembly.org/). ++ **API affinity**: Native support for ecological API specifications such as [OpenAPI](https://github.com/kcl-lang/kcl-openapi), Kubernetes CRD, Kubernetes Resource Model (KRM) spec. ++ **Developer-friendly**: Friendly development experiences with rich [language tools](https://kcl-lang.io/docs/tools/cli/kcl/) (Format, Lint, Test, Vet, Doc, package management tools etc.), and multiple [IDE extensions](https://kcl-lang.io/docs/tools/Ide/). ++ **Safety & maintainable**: Domain-oriented, no system-level functions such as native threads and IO, low noise and security risk, easy maintenance and governance. ++ **Rich multi-language SDK**: Rust, Go, Python, .NET, Java and Node.js SDKs meet different scenarios and application use prelude. ++ **Integrations**: Abstract, mutate and validate manifests through [Kubectl KCL Plugin](https://github.com/kcl-lang/kubectl-kcl), [Kustomize KCL Plugin](https://github.com/kcl-lang/kustomize-kcl), [Helm KCL Plugin](https://github.com/kcl-lang/helm-kcl), [KPT KCL SDK](https://github.com/kcl-lang/kpt-kcl) or [Crossplane KCL Function](https://github.com/kcl-lang/crossplane-kcl). ++ **Production-ready**: Widely used in production practices of platform engineering and automation at Ant Group. -```kcl -schema Fib: - n1: int = n - 1 - n2: int = n1 - 1 - n: int - value: int +## How to choose? - if n <= 1: - value = 1 - elif n == 2: - value = 1 - else: - value = Fib {n: n1}.value + Fib {n: n2}.value +A detailed feature and scenario comparison is [here](https://kcl-lang.io/docs/user_docs/getting-started/intro). -fib8 = Fib {n: 8}.value -``` +## Installation -We can execute the following command to get a YAML output. +For more information about installation, please check the [Installation Guide](https://kcl-lang.io/docs/user_docs/getting-started/install/) on the KCL official website. -``` -kcl ./samples/fib.k -``` +## Documentation -YAML output +Detailed documentation is available at [KCL Website](https://kcl-lang.io/) -```yaml -fib8: 21 -``` +## Contributing -### Documentation +See [Developing Guide](./docs/dev_guide/1.about_this_guide.md). You can also get started by opening the project in GitHub Codespaces. -Detailed documentation is available at https://kusionstack.io +[![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/kcl-lang/kcl) -## Developing & Contributing +## Roadmap -### Developing +See [KCL Roadmap](https://github.com/kcl-lang/kcl/issues/882). -See [Developing Guide](./CONTRIBUTING.md). +## Community -### Roadmap - -See [KCLVM Roadmap](https://kusionstack.io/docs/governance/intro/roadmap#kclvm-%E8%B7%AF%E7%BA%BF%E8%A7%84%E5%88%92) +See the [community](https://github.com/kcl-lang/community) for ways to join us. ## License -Apache License Version 2.0 +[![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fkcl-lang%2Fkcl.svg?type=large)](https://app.fossa.com/projects/git%2Bgithub.com%2Fkcl-lang%2Fkcl?ref=badge_large) diff --git a/README_ZH.md b/README_ZH.md deleted file mode 100644 index 92f929b24..000000000 --- a/README_ZH.md +++ /dev/null @@ -1,91 +0,0 @@ -# KCL - -![license](https://img.shields.io/badge/license-Apache--2.0-green.svg) -[![Continuous Integration](https://github.com/KusionStack/KCLVM/actions/workflows/github-actions.yaml/badge.svg)](https://github.com/KusionStack/KCLVM/actions?query=branch%3Amain) - -[English](./README.md) - -Kusion 配置语言(KCL)是一种开源配置语言,主要用于 [Kusion Stack](https://kusionstack.io) 开放协同技术栈。并且 KCL 是一种基于声明性和面向对象编程 (OOP) 范式等概念,用于配置和策略场景的静态类型语言。 - -## 核心特性 - -+ **简单** - + 源于 Python、Golang,融入函数语言特性 - + 吸收语句、表达式、条件、循环等语言元素 - + 类型和数据分离,Schema 声明配置定义 -+ **稳定** - + 强不可变约束 - + 编译时类型推导、类型检查 - + Rule 策略定义:以属性为中心的约束表达式、根据约束查询结果 - + 可测试:语言内置 assert 断言、print 打印和测试工具 -+ **可扩展** - + 配置合并:编译时配置依赖图代换 - + 配置属性运算符:满足配置覆盖、合并、添加和删除等需求 - + 配置复用:丰富的内置数据结构和语法语义,轻松扩展同一份配置到不同场景 -+ **工程化** - + Schema 单一继承和声明性模型复用和组装 - + 工具和API 粒度的配置自动化“增删改查” - + 丰富的内置函数和系统库 - + 顶层数据动态导入 - + 代码组织:模块和包 - + [插件系统](https://github.com/KusionStack/kcl-plugin):复用通用编程语言生态。 - + [OpenAPI 模型支持](https://github.com/KusionStack/kcl-openapi):Swagger 与 Schema 双向转换,Kubernetes CRD 转换为 Schema -+ **高性能** - + 配合 LLVM 优化器、支持编译到本地代码和 WASM 等格式并高效执行 - -## 安装 & 文档 - -### 如何安装 - -从 Github releases 页面[下载](https://github.com/KusionStack/KCLVM/releases),并且将 `{install-location}/kclvm/bin` 添加到您的环境变量中 - -### 快速开始 - -`./samples/fib.k` 是一个计算斐波那契数列的例子 - -```kcl -schema Fib: - n1: int = n - 1 - n2: int = n1 - 1 - n: int - value: int - - if n <= 1: - value = 1 - elif n == 2: - value = 1 - else: - value = Fib {n: n1}.value + Fib {n: n2}.value - -fib8 = Fib {n: 8}.value -``` - -我们可以通过执行如下命令得到 YAML 输出 - -``` -kcl ./samples/fib.k -``` - -YAML 输出 - -```yaml -fib8: 21 -``` - -### 文档 - -更多文档请访问 https://kusionstack.io - -## 开发 & 贡献 - -### 开发 - -参考[开发手册](./CONTRIBUTING.md). - -### 路线规划 - -参考[KCLVM 路线规划](https://kusionstack.io/docs/governance/intro/roadmap#kclvm-%E8%B7%AF%E7%BA%BF%E8%A7%84%E5%88%92) - -## 许可 - -Apache License Version 2.0 diff --git a/VERSION b/VERSION index f7abe273d..142464bf2 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.4.2 \ No newline at end of file +0.11.0 \ No newline at end of file diff --git a/build.ps1 b/build.ps1 new file mode 100644 index 000000000..a3e5a058b --- /dev/null +++ b/build.ps1 @@ -0,0 +1,14 @@ +Set-Location $PSScriptRoot +. '.\scripts\build-windows\build.ps1' +$bin_path = Join-Path $PSScriptRoot 'scripts\build-windows\_output\kclvm-windows\bin' +$env:Path += ";$bin_path" +# rust unit test +Set-Location .\kclvm +cargo test --workspace -r -- --nocapture +Set-Location $PSScriptRoot +# rust runtime test +Set-Location .\kclvm\tests\test_units +python3 -m pytest -vv +Set-Location $PSScriptRoot +# konfig test +Invoke-Expression -Command '.\test\integration\test_konfig.bat' diff --git a/cli/Cargo.toml b/cli/Cargo.toml new file mode 100644 index 000000000..30ea22483 --- /dev/null +++ b/cli/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "kclvm_cli" +version = "0.11.0" +edition = "2021" + +[[bin]] +path = "src/main.rs" +name = "kclvm_cli" + +[profile.release] +rpath = true +panic = "unwind" +opt-level = "z" # Optimize for size. +lto = true diff --git a/cli/build.rs b/cli/build.rs new file mode 100644 index 000000000..bb7623caf --- /dev/null +++ b/cli/build.rs @@ -0,0 +1,13 @@ +fn main() { + if cfg!(target_os = "windows") { + println!("cargo:rustc-link-search=..\\kclvm\\target\\release"); + } else { + println!("cargo:rustc-link-search=../kclvm/target/release"); + } + println!("cargo:rustc-link-lib=dylib=kclvm_cli_cdylib"); + if cfg!(target_os = "macos") { + println!("cargo:rustc-link-arg=-Wl,-rpath,@loader_path"); + } else if cfg!(target_os = "linux") { + println!("cargo:rustc-link-arg=-Wl,-rpath,$ORIGIN"); + } +} diff --git a/cli/src/main.rs b/cli/src/main.rs new file mode 100644 index 000000000..8ec47d258 --- /dev/null +++ b/cli/src/main.rs @@ -0,0 +1,30 @@ +//! The `kclvm` command-line interface. + +use std::{ + ffi::{c_char, c_int, CString}, + process::ExitCode, +}; + +#[link(name = "kclvm_cli_cdylib")] +#[allow(improper_ctypes)] +extern "C" { + fn kclvm_cli_main(argc: c_int, argv: *const *const c_char) -> *mut ExitCode; +} + +fn main() -> ExitCode { + // create a vector of zero terminated strings + let args = std::env::args() + .map(|arg| CString::new(arg).unwrap()) + .collect::>(); + // convert the strings to raw pointers + let c_args = args + .iter() + .map(|arg| arg.as_ptr()) + .collect::>(); + unsafe { + // pass the pointer of the vector's internal buffer to a C function + let result = kclvm_cli_main(c_args.len() as c_int, c_args.as_ptr()); + let result = Box::from_raw(result); + *result + } +} diff --git a/compiler_base/3rdparty/rustc_data_structures/Cargo.toml b/compiler_base/3rdparty/rustc_data_structures/Cargo.toml new file mode 100644 index 000000000..486bd842b --- /dev/null +++ b/compiler_base/3rdparty/rustc_data_structures/Cargo.toml @@ -0,0 +1,40 @@ +[package] +name = "rustc_data_structures" +version = "0.1.2" +edition = "2021" +authors = ["zongzhe1024@163.com"] +license = "Apache-2.0 OR MIT" +description = "Reuse rustc_data_structures for compiler_base" +readme = "README.md" +homepage = "https://github.com/kcl-lang/kcl" +repository = "https://github.com/kcl-lang/kcl" +keywords = ["rustc", "data_structures"] +categories = ["command-line-utilities"] + +[lib] +doctest = false + +[dependencies] +arrayvec = { version = "0.7", default-features = false } +ena = "0.14" +indexmap = { version = "1.8.0", features = ["rustc-rayon"] } +tracing = "0.1" +jobserver_crate = { version = "0.1.13", package = "jobserver" } + +cfg-if = "0.1.2" +stable_deref_trait = "1.0.0" +rayon = { version = "0.3.2", package = "rustc-rayon" } +rayon-core = { version = "0.3.2", package = "rustc-rayon-core" } +rustc-hash = "1.1.0" +bitflags = "1.2.1" +libc = "0.2" +tempfile = "3.5.0" + +[dependencies.parking_lot] +version = "0.12" + +[target.'cfg(windows)'.dependencies] +winapi = { version = "0.3", features = ["std", "fileapi", "psapi", "winerror"] } + +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +memmap2 = "0.2.1" diff --git a/compiler_base/3rdparty/rustc_data_structures/README.md b/compiler_base/3rdparty/rustc_data_structures/README.md new file mode 100644 index 000000000..f0e02cbc4 --- /dev/null +++ b/compiler_base/3rdparty/rustc_data_structures/README.md @@ -0,0 +1,3 @@ +reuse rustc_data_structures for compiler_base. + +note: [WIP] Do not use it. \ No newline at end of file diff --git a/kclvm/3rdparty/rustc_data_structures/src/LICENSE b/compiler_base/3rdparty/rustc_data_structures/src/LICENSE similarity index 100% rename from kclvm/3rdparty/rustc_data_structures/src/LICENSE rename to compiler_base/3rdparty/rustc_data_structures/src/LICENSE diff --git a/kclvm/3rdparty/rustc_data_structures/src/atomic_ref.rs b/compiler_base/3rdparty/rustc_data_structures/src/atomic_ref.rs similarity index 100% rename from kclvm/3rdparty/rustc_data_structures/src/atomic_ref.rs rename to compiler_base/3rdparty/rustc_data_structures/src/atomic_ref.rs diff --git a/kclvm/3rdparty/rustc_data_structures/src/base_n.rs b/compiler_base/3rdparty/rustc_data_structures/src/base_n.rs similarity index 97% rename from kclvm/3rdparty/rustc_data_structures/src/base_n.rs rename to compiler_base/3rdparty/rustc_data_structures/src/base_n.rs index 3c7bea271..0438159e6 100644 --- a/kclvm/3rdparty/rustc_data_structures/src/base_n.rs +++ b/compiler_base/3rdparty/rustc_data_structures/src/base_n.rs @@ -2,9 +2,6 @@ /// Bases up to and including 36 can be used for case-insensitive things. use std::str; -#[cfg(test)] -mod tests; - pub const MAX_BASE: usize = 64; pub const ALPHANUMERIC_ONLY: usize = 62; pub const CASE_INSENSITIVE: usize = 36; diff --git a/kclvm/3rdparty/rustc_data_structures/src/captures.rs b/compiler_base/3rdparty/rustc_data_structures/src/captures.rs similarity index 100% rename from kclvm/3rdparty/rustc_data_structures/src/captures.rs rename to compiler_base/3rdparty/rustc_data_structures/src/captures.rs diff --git a/kclvm/3rdparty/rustc_data_structures/src/flock.rs b/compiler_base/3rdparty/rustc_data_structures/src/flock.rs similarity index 100% rename from kclvm/3rdparty/rustc_data_structures/src/flock.rs rename to compiler_base/3rdparty/rustc_data_structures/src/flock.rs diff --git a/kclvm/3rdparty/rustc_data_structures/src/frozen.rs b/compiler_base/3rdparty/rustc_data_structures/src/frozen.rs similarity index 100% rename from kclvm/3rdparty/rustc_data_structures/src/frozen.rs rename to compiler_base/3rdparty/rustc_data_structures/src/frozen.rs diff --git a/kclvm/3rdparty/rustc_data_structures/src/fx.rs b/compiler_base/3rdparty/rustc_data_structures/src/fx.rs similarity index 100% rename from kclvm/3rdparty/rustc_data_structures/src/fx.rs rename to compiler_base/3rdparty/rustc_data_structures/src/fx.rs diff --git a/compiler_base/3rdparty/rustc_data_structures/src/lib.rs b/compiler_base/3rdparty/rustc_data_structures/src/lib.rs new file mode 100644 index 000000000..1377b0430 --- /dev/null +++ b/compiler_base/3rdparty/rustc_data_structures/src/lib.rs @@ -0,0 +1,76 @@ +//! Various data structures used by the Rust compiler. The intention +//! is that code in here should be not be *specific* to rustc, so that +//! it can be easily unit tested and so forth. +//! +//! # Note +//! +//! This API is completely unstable and subject to change. + +#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] +#![allow(rustc::default_hash_types)] +#![allow(rustc::potential_query_instability)] + +extern crate tracing; +#[macro_use] +extern crate cfg_if; + +#[inline(never)] +#[cold] +pub fn cold_path R, R>(f: F) -> R { + f() +} + +#[macro_export] +macro_rules! likely { + ($e:expr) => { + match $e { + #[allow(unused_unsafe)] + e => unsafe { std::intrinsics::likely(e) }, + } + }; +} + +pub mod base_n; + +pub mod captures; +pub mod flock; +pub mod fx; + +pub mod macros; +pub mod stable_map; +pub use ena::snapshot_vec; +pub mod stable_set; +#[macro_use] + +mod atomic_ref; +pub mod sync; +pub use atomic_ref::AtomicRef; +pub mod frozen; + +pub mod temp_dir; +pub mod unhash; + +pub use ena::undo_log; +pub use ena::unify; + +pub struct OnDrop(pub F); + +impl OnDrop { + /// Forgets the function which prevents it from running. + /// Ensure that the function owns no memory, otherwise it will be leaked. + #[inline] + pub fn disable(self) { + std::mem::forget(self); + } +} + +impl Drop for OnDrop { + #[inline] + fn drop(&mut self) { + (self.0)(); + } +} + +// See comments in src/librustc_middle/lib.rs +#[doc(hidden)] +pub fn __noop_fix_for_27438() {} diff --git a/kclvm/3rdparty/rustc_data_structures/src/macros.rs b/compiler_base/3rdparty/rustc_data_structures/src/macros.rs similarity index 100% rename from kclvm/3rdparty/rustc_data_structures/src/macros.rs rename to compiler_base/3rdparty/rustc_data_structures/src/macros.rs diff --git a/kclvm/3rdparty/rustc_data_structures/src/stable_map.rs b/compiler_base/3rdparty/rustc_data_structures/src/stable_map.rs similarity index 96% rename from kclvm/3rdparty/rustc_data_structures/src/stable_map.rs rename to compiler_base/3rdparty/rustc_data_structures/src/stable_map.rs index 670452d0d..5401cd7f0 100644 --- a/kclvm/3rdparty/rustc_data_structures/src/stable_map.rs +++ b/compiler_base/3rdparty/rustc_data_structures/src/stable_map.rs @@ -54,7 +54,9 @@ where K: Eq + Hash, { pub fn new() -> StableMap { - StableMap { base: FxHashMap::default() } + StableMap { + base: FxHashMap::default(), + } } pub fn into_sorted_vector(self) -> Vec<(K, V)> diff --git a/kclvm/3rdparty/rustc_data_structures/src/stable_set.rs b/compiler_base/3rdparty/rustc_data_structures/src/stable_set.rs similarity index 95% rename from kclvm/3rdparty/rustc_data_structures/src/stable_set.rs rename to compiler_base/3rdparty/rustc_data_structures/src/stable_set.rs index c7ca74f5f..66ce0d1a1 100644 --- a/kclvm/3rdparty/rustc_data_structures/src/stable_set.rs +++ b/compiler_base/3rdparty/rustc_data_structures/src/stable_set.rs @@ -43,7 +43,9 @@ impl Eq for StableSet where T: Eq + Hash {} impl StableSet { pub fn new() -> StableSet { - StableSet { base: FxHashSet::default() } + StableSet { + base: FxHashSet::default(), + } } pub fn into_sorted_vector(self) -> Vec diff --git a/compiler_base/3rdparty/rustc_data_structures/src/sync.rs b/compiler_base/3rdparty/rustc_data_structures/src/sync.rs new file mode 100644 index 000000000..c143e3d75 --- /dev/null +++ b/compiler_base/3rdparty/rustc_data_structures/src/sync.rs @@ -0,0 +1,108 @@ +//! This module defines types which are thread safe if cfg!(parallel_compiler) is true. +//! +//! `Lrc` is an alias of `Arc` if cfg!(parallel_compiler) is true, `Rc` otherwise. +//! +//! `Lock` is a mutex. +//! It internally uses `parking_lot::Mutex` if cfg!(parallel_compiler) is true, +//! `RefCell` otherwise. +//! +//! `RwLock` is a read-write lock. +//! It internally uses `parking_lot::RwLock` if cfg!(parallel_compiler) is true, +//! `RefCell` otherwise. +//! +//! `MTLock` is a mutex which disappears if cfg!(parallel_compiler) is false. +//! +//! `MTRef` is an immutable reference if cfg!(parallel_compiler), and a mutable reference otherwise. +//! +//! `rustc_erase_owner!` erases an OwningRef owner into Erased or Erased + Send + Sync +//! depending on the value of cfg!(parallel_compiler). + +use std::collections::HashMap; +use std::hash::{BuildHasher, Hash}; + +pub use std::sync::atomic::Ordering; +pub use std::sync::atomic::Ordering::SeqCst; + +pub use std::marker::Send; +pub use std::marker::Sync; + +pub use parking_lot::MappedRwLockReadGuard as MappedReadGuard; +pub use parking_lot::MappedRwLockWriteGuard as MappedWriteGuard; +pub use parking_lot::RwLockReadGuard as ReadGuard; +pub use parking_lot::RwLockWriteGuard as WriteGuard; + +pub use parking_lot::MappedMutexGuard as MappedLockGuard; +pub use parking_lot::MutexGuard as LockGuard; + +pub use std::sync::atomic::{AtomicBool, AtomicU32, AtomicU64, AtomicUsize}; + +pub use std::sync::Arc as Lrc; +pub use std::sync::Weak; + +pub type MTRef<'a, T> = &'a T; + +pub use rayon::{join, scope}; + +/// Runs a list of blocks in parallel. The first block is executed immediately on +/// the current thread. Use that for the longest running block. +#[macro_export] +macro_rules! parallel { + (impl $fblock:tt [$($c:tt,)*] [$block:tt $(, $rest:tt)*]) => { + parallel!(impl $fblock [$block, $($c,)*] [$($rest),*]) + }; + (impl $fblock:tt [$($blocks:tt,)*] []) => { + ::rustc_data_structures::sync::scope(|s| { + $( + s.spawn(|_| $blocks); + )* + $fblock; + }) + }; + ($fblock:tt, $($blocks:tt),*) => { + // Reverse the order of the later blocks since Rayon executes them in reverse order + // when using a single thread. This ensures the execution order matches that + // of a single threaded rustc + parallel!(impl $fblock [] [$($blocks),*]); + }; + } + +pub use rayon_core::WorkerLocal; + +use rayon::iter::IntoParallelIterator; +pub use rayon::iter::ParallelIterator; + +pub fn par_iter(t: T) -> T::Iter { + t.into_par_iter() +} + +pub fn par_for_each_in(t: T, for_each: impl Fn(T::Item) + Sync + Send) { + t.into_par_iter().for_each(for_each) +} + +#[macro_export] +macro_rules! rustc_erase_owner { + ($v:expr) => {{ + let v = $v; + ::rustc_data_structures::sync::assert_send_val(&v); + v.erase_send_sync_owner() + }}; +} + +pub fn assert_sync() {} +pub fn assert_send() {} +pub fn assert_send_val(_t: &T) {} +pub fn assert_send_sync_val(_t: &T) {} + +pub trait HashMapExt { + /// Same as HashMap::insert, but it may panic if there's already an + /// entry for `key` with a value not equal to `value` + fn insert_same(&mut self, key: K, value: V); +} + +impl HashMapExt for HashMap { + fn insert_same(&mut self, key: K, value: V) { + self.entry(key) + .and_modify(|old| assert!(*old == value)) + .or_insert(value); + } +} diff --git a/kclvm/3rdparty/rustc_data_structures/src/temp_dir.rs b/compiler_base/3rdparty/rustc_data_structures/src/temp_dir.rs similarity index 83% rename from kclvm/3rdparty/rustc_data_structures/src/temp_dir.rs rename to compiler_base/3rdparty/rustc_data_structures/src/temp_dir.rs index a780d2386..81a17cfa6 100644 --- a/kclvm/3rdparty/rustc_data_structures/src/temp_dir.rs +++ b/compiler_base/3rdparty/rustc_data_structures/src/temp_dir.rs @@ -16,7 +16,7 @@ impl Drop for MaybeTempDir { // occur. let dir = unsafe { ManuallyDrop::take(&mut self.dir) }; if self.keep { - dir.into_path(); + let _ = dir.into_path(); } } } @@ -29,6 +29,9 @@ impl AsRef for MaybeTempDir { impl MaybeTempDir { pub fn new(dir: TempDir, keep_on_drop: bool) -> MaybeTempDir { - MaybeTempDir { dir: ManuallyDrop::new(dir), keep: keep_on_drop } + MaybeTempDir { + dir: ManuallyDrop::new(dir), + keep: keep_on_drop, + } } } diff --git a/kclvm/3rdparty/rustc_data_structures/src/unhash.rs b/compiler_base/3rdparty/rustc_data_structures/src/unhash.rs similarity index 100% rename from kclvm/3rdparty/rustc_data_structures/src/unhash.rs rename to compiler_base/3rdparty/rustc_data_structures/src/unhash.rs diff --git a/compiler_base/3rdparty/rustc_errors/Cargo.toml b/compiler_base/3rdparty/rustc_errors/Cargo.toml new file mode 100644 index 000000000..c2028c9eb --- /dev/null +++ b/compiler_base/3rdparty/rustc_errors/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "rustc_errors" +version = "0.1.2" +edition = "2021" +authors = ["zongzhe1024@163.com"] +license = "Apache-2.0 OR MIT" +description = "Reuse rustc_errors for compiler_base" +readme = "README.md" +homepage = "https://github.com/kcl-lang/kcl" +repository = "https://github.com/kcl-lang/kcl" +keywords = ["rustc", "rustc_errors"] +categories = ["command-line-utilities"] + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +termcolor = "1.0" + +[target.'cfg(windows)'.dependencies] +winapi = { version = "0.3", features = ["handleapi", "synchapi", "winbase"] } \ No newline at end of file diff --git a/compiler_base/3rdparty/rustc_errors/README.md b/compiler_base/3rdparty/rustc_errors/README.md new file mode 100644 index 000000000..84f89a6c4 --- /dev/null +++ b/compiler_base/3rdparty/rustc_errors/README.md @@ -0,0 +1,3 @@ +reuse rustc_errors for compiler_base. + +note: [WIP] Do not use it. \ No newline at end of file diff --git a/kclvm/3rdparty/rustc_span/src/LICENSE b/compiler_base/3rdparty/rustc_errors/src/LICENSE similarity index 100% rename from kclvm/3rdparty/rustc_span/src/LICENSE rename to compiler_base/3rdparty/rustc_errors/src/LICENSE diff --git a/compiler_base/3rdparty/rustc_errors/src/README.md b/compiler_base/3rdparty/rustc_errors/src/README.md new file mode 100644 index 000000000..5bc39dd86 --- /dev/null +++ b/compiler_base/3rdparty/rustc_errors/src/README.md @@ -0,0 +1,14 @@ +Porting ['rustc_errors/styled_buffer.rs'] and ['rustc_errors/lock.rs'] code here to enable code reuse due to the unstable and unreusable of the ['rustc_errors'] crate now. +We mainly reuse helper structs and functions like `StyledBuffer`, `StyledString` to render text in Compiler-Base, and reuse helper function `acquire_global_lock` to emit the diagnostic messages. + +Note: the structs and functions here exist as implementations and will not be exposed to other crates directly. + +Reuse 'styled_buffer.rs' and 'lock.rs' in 'rustc_errors', +and 'styled_buffer.rs' has been modified to fit the feature of 'Compiler-Base'. + +We modified some features on porting code: +- add method `appendl()` and `pushs()` to 'StyledBuffer'. +- replaced the `enum Style` with generics `T: Clone + PartialEq + Eq + Style` to support extending more styles, because we need that `StyledBuffer` is still valid when facing the user-defined style, rather than just supporting a built-in `enum Style`. +- added some test cases for 'StyledBuffer' with 'trait Style'. + +If anyone feels uncomfortable, please feel free to contact us. \ No newline at end of file diff --git a/compiler_base/3rdparty/rustc_errors/src/lib.rs b/compiler_base/3rdparty/rustc_errors/src/lib.rs new file mode 100644 index 000000000..47112e4b9 --- /dev/null +++ b/compiler_base/3rdparty/rustc_errors/src/lib.rs @@ -0,0 +1,305 @@ +//! Text rendering and related helper functions. +//! +//! Reuse 'styled_buffer.rs' in 'rustc_errors', +//! and 'styled_buffer.rs' has been modified to fit the feature of 'Compiler-Base'. +//! +//! - add method `appendl()` and `pushs()` to `StyledBuffer`. +//! +//! - replaced the `enum Style` with generics `T: Clone + PartialEq + Eq + Style` to support extending more styles. +//! `StyledBuffer` still should be valid when facing the user-defined style, rather than just supporting a built-in `enum Style`. +//! +//! - add some test cases for 'StyledBuffer'. +use termcolor::ColorSpec; +pub mod lock; +pub mod styled_buffer; + +/// 'Style' is a trait used to specify the user customize 'XXXStyle' can be accepted by 'StyleBuffer'. +/// +/// It provides the following method `render_style_to_color_spec()`. +/// render_style_to_color_spec(&self) : render style to terminal color/font configuration. +pub trait Style { + /// render style to terminal color/font configuration. + /// + /// # Example + /// + /// ```rust + /// use termcolor::Color; + /// use termcolor::ColorSpec; + /// use rustc_errors::Style; + /// #[derive(Copy, Clone, Debug, PartialEq, Eq)] + /// pub enum DummyStyle { + /// Dummy, + /// NoStyle, + /// } + /// + /// impl Style for DummyStyle { + /// fn render_style_to_color_spec(&self) -> ColorSpec { + /// let mut spec = ColorSpec::new(); + /// match self{ + /// // For `DummyStyle::Dummy`, the font is intense and the font color is red. + /// DummyStyle::Dummy => { + /// spec.set_fg(Some(Color::Red)).set_intense(true); + /// } + /// DummyStyle::NoStyle => todo!() + /// } + /// spec + /// } + /// } + /// ``` + fn render_style_to_color_spec(&self) -> ColorSpec; +} + +#[cfg(test)] +mod test_styled_buffer { + use crate::{ + styled_buffer::{StyledBuffer, StyledString}, + Style, + }; + use termcolor::{Color, ColorSpec}; + + // DummyStyle for testing 'StyledBuffer'. + #[derive(Copy, Clone, Debug, PartialEq, Eq)] + pub enum DummyStyle { + Dummy, + NoStyle, + } + + impl Style for DummyStyle { + fn render_style_to_color_spec(&self) -> ColorSpec { + let mut spec = ColorSpec::new(); + match self { + DummyStyle::Dummy => { + spec.set_fg(Some(Color::Red)).set_intense(true); + } + DummyStyle::NoStyle => { + spec.set_fg(Some(Color::Green)).set_intense(false); + } + } + spec + } + } + + fn construct_new_styledbuffer() -> StyledBuffer { + StyledBuffer::new() + } + + fn putc_hello_world(sb: &mut StyledBuffer) { + sb.putc(0, 0, 'H', Some(DummyStyle::NoStyle)); + sb.putc(0, 1, 'e', Some(DummyStyle::NoStyle)); + sb.putc(0, 2, 'l', Some(DummyStyle::NoStyle)); + sb.putc(0, 3, 'l', Some(DummyStyle::NoStyle)); + sb.putc(0, 4, 'o', Some(DummyStyle::NoStyle)); + sb.putc(0, 5, 'W', Some(DummyStyle::Dummy)); + sb.putc(0, 6, 'o', Some(DummyStyle::Dummy)); + sb.putc(0, 7, 'r', Some(DummyStyle::Dummy)); + sb.putc(0, 8, 'l', Some(DummyStyle::Dummy)); + sb.putc(0, 9, 'd', Some(DummyStyle::Dummy)); + } + + fn puts_hello_world(sb: &mut StyledBuffer) { + sb.puts(0, 0, "Hello", Some(DummyStyle::NoStyle)); + sb.puts(0, 5, "World", Some(DummyStyle::Dummy)); + } + + fn pushs_hello_world(sb: &mut StyledBuffer) { + sb.pushs("Hello", Some(DummyStyle::NoStyle)); + sb.pushs("World", Some(DummyStyle::Dummy)); + } + + fn appendl_hello_world(sb: &mut StyledBuffer) { + sb.appendl("Hello", Some(DummyStyle::NoStyle)); + sb.appendl("World", Some(DummyStyle::Dummy)); + } + + fn require_hello_world(styled_strings: Vec>>) { + assert_eq!(styled_strings.len(), 1); + assert_eq!(styled_strings.get(0).unwrap().len(), 2); + + assert_eq!(styled_strings.get(0).unwrap().get(0).unwrap().text, "Hello"); + assert!( + DummyStyle::NoStyle + == *styled_strings + .get(0) + .unwrap() + .get(0) + .unwrap() + .style + .as_ref() + .unwrap() + ); + assert_eq!(styled_strings.get(0).unwrap().get(1).unwrap().text, "World"); + assert!( + DummyStyle::Dummy + == *styled_strings + .get(0) + .unwrap() + .get(1) + .unwrap() + .style + .as_ref() + .unwrap() + ); + } + + #[test] + fn test_putc() { + let mut sb = construct_new_styledbuffer(); + putc_hello_world(&mut sb); + + let styled_strings = sb.render(); + + require_hello_world(styled_strings); + + sb.putc(0, 0, 'H', Some(DummyStyle::NoStyle)); + sb.putc(0, 1, 'E', Some(DummyStyle::NoStyle)); + sb.putc(0, 2, 'L', Some(DummyStyle::NoStyle)); + sb.putc(0, 3, 'L', Some(DummyStyle::NoStyle)); + sb.putc(0, 4, 'O', Some(DummyStyle::NoStyle)); + let styled_strings = sb.render(); + assert_eq!(styled_strings.get(0).unwrap().get(0).unwrap().text, "HELLO"); + assert!( + DummyStyle::NoStyle + == *styled_strings + .get(0) + .unwrap() + .get(0) + .unwrap() + .style + .as_ref() + .unwrap(), + "style error: expected style : {:?}", + DummyStyle::NoStyle + ); + } + + #[test] + fn test_putc_new_line() { + let mut sb = construct_new_styledbuffer(); + putc_hello_world(&mut sb); + + sb.putc(2, 0, 'A', Some(DummyStyle::Dummy)); + let styled_strings = sb.render(); + assert_eq!(styled_strings.len(), 3); + assert_eq!(styled_strings.get(0).unwrap().len(), 2); + assert_eq!(styled_strings.get(1).unwrap().len(), 0); + assert_eq!(styled_strings.get(2).unwrap().len(), 1); + assert_eq!(styled_strings.get(2).unwrap().get(0).unwrap().text, "A"); + assert!( + DummyStyle::Dummy + == *styled_strings + .get(2) + .unwrap() + .get(0) + .unwrap() + .style + .as_ref() + .unwrap(), + "style error: expected style : {:?}", + DummyStyle::Dummy + ); + } + + #[test] + fn test_puts() { + let mut sb = construct_new_styledbuffer(); + puts_hello_world(&mut sb); + let styled_strings = sb.render(); + require_hello_world(styled_strings); + } + + #[test] + fn test_puts_new_line() { + let mut sb = construct_new_styledbuffer(); + puts_hello_world(&mut sb); + + sb.puts(2, 0, "A", Some(DummyStyle::Dummy)); + let styled_strings = sb.render(); + assert_eq!(styled_strings.len(), 3); + assert_eq!(styled_strings.get(0).unwrap().len(), 2); + assert_eq!(styled_strings.get(1).unwrap().len(), 0); + assert_eq!(styled_strings.get(2).unwrap().len(), 1); + assert_eq!(styled_strings.get(2).unwrap().get(0).unwrap().text, "A"); + assert!( + DummyStyle::Dummy + == *styled_strings + .get(2) + .unwrap() + .get(0) + .unwrap() + .style + .as_ref() + .unwrap(), + "style error: expected style : {:?}", + DummyStyle::Dummy + ); + } + + #[test] + fn test_pushs() { + let mut sb = construct_new_styledbuffer(); + pushs_hello_world(&mut sb); + let styled_strings = sb.render(); + assert_eq!(styled_strings.len(), 2); + assert_eq!(styled_strings.get(0).unwrap().len(), 1); + + assert_eq!(styled_strings.get(0).unwrap().get(0).unwrap().text, "Hello"); + assert!( + DummyStyle::NoStyle + == *styled_strings + .get(0) + .unwrap() + .get(0) + .unwrap() + .style + .as_ref() + .unwrap(), + "style error: expected style : {:?}", + DummyStyle::NoStyle + ); + + assert_eq!(styled_strings.get(1).unwrap().get(0).unwrap().text, "World"); + assert!( + DummyStyle::Dummy + == *styled_strings + .get(1) + .unwrap() + .get(0) + .unwrap() + .style + .as_ref() + .unwrap(), + "style error: expected style : {:?}", + DummyStyle::Dummy + ); + } + + #[test] + fn test_appendl() { + let mut sb = construct_new_styledbuffer(); + appendl_hello_world(&mut sb); + let styled_strings = sb.render(); + require_hello_world(styled_strings); + } + + #[test] + fn test_prepend() { + let mut sb = construct_new_styledbuffer(); + sb.appendl("World", Some(DummyStyle::Dummy)); + sb.prepend(0, "Hello", Some(DummyStyle::NoStyle)); + let styled_strings = sb.render(); + require_hello_world(styled_strings); + } + + #[test] + fn test_num_lines() { + let mut sb = construct_new_styledbuffer(); + putc_hello_world(&mut sb); + assert_eq!(sb.num_lines(), 1); + sb.appendl("World", Some(DummyStyle::Dummy)); + assert_eq!(sb.num_lines(), 1); + pushs_hello_world(&mut sb); + assert_eq!(sb.num_lines(), 3); + puts_hello_world(&mut sb); + assert_eq!(sb.num_lines(), 3); + } +} diff --git a/compiler_base/3rdparty/rustc_errors/src/lock.rs b/compiler_base/3rdparty/rustc_errors/src/lock.rs new file mode 100644 index 000000000..a73472021 --- /dev/null +++ b/compiler_base/3rdparty/rustc_errors/src/lock.rs @@ -0,0 +1,93 @@ +//! Bindings to acquire a global named lock. +//! +//! This is intended to be used to synchronize multiple compiler processes to +//! ensure that we can output complete errors without interleaving on Windows. +//! Note that this is currently only needed for allowing only one 32-bit MSVC +//! linker to execute at once on MSVC hosts, so this is only implemented for +//! `cfg(windows)`. Also note that this may not always be used on Windows, +//! only when targeting 32-bit MSVC. +//! +//! For more information about why this is necessary, see where this is called. + +use std::any::Any; + +#[cfg(windows)] +pub fn acquire_global_lock(name: &str) -> Box { + use std::ffi::CString; + use std::io; + + use winapi::shared::ntdef::HANDLE; + use winapi::um::handleapi::CloseHandle; + use winapi::um::synchapi::{CreateMutexA, ReleaseMutex, WaitForSingleObject}; + use winapi::um::winbase::{INFINITE, WAIT_ABANDONED, WAIT_OBJECT_0}; + + struct Handle(HANDLE); + + impl Drop for Handle { + fn drop(&mut self) { + unsafe { + CloseHandle(self.0); + } + } + } + + struct Guard(Handle); + + impl Drop for Guard { + fn drop(&mut self) { + unsafe { + ReleaseMutex((self.0).0); + } + } + } + + let cname = CString::new(name).unwrap(); + unsafe { + // Create a named mutex, with no security attributes and also not + // acquired when we create it. + // + // This will silently create one if it doesn't already exist, or it'll + // open up a handle to one if it already exists. + let mutex = CreateMutexA(std::ptr::null_mut(), 0, cname.as_ptr()); + if mutex.is_null() { + panic!( + "failed to create global mutex named `{}`: {}", + name, + io::Error::last_os_error() + ); + } + let mutex = Handle(mutex); + + // Acquire the lock through `WaitForSingleObject`. + // + // A return value of `WAIT_OBJECT_0` means we successfully acquired it. + // + // A return value of `WAIT_ABANDONED` means that the previous holder of + // the thread exited without calling `ReleaseMutex`. This can happen, + // for example, when the compiler crashes or is interrupted via ctrl-c + // or the like. In this case, however, we are still transferred + // ownership of the lock so we continue. + // + // If an error happens.. well... that's surprising! + match WaitForSingleObject(mutex.0, INFINITE) { + WAIT_OBJECT_0 | WAIT_ABANDONED => {} + code => { + panic!( + "WaitForSingleObject failed on global mutex named \ + `{}`: {} (ret={:x})", + name, + io::Error::last_os_error(), + code + ); + } + } + + // Return a guard which will call `ReleaseMutex` when dropped. + Box::new(Guard(mutex)) + } +} + +#[cfg(not(windows))] +pub fn acquire_global_lock(_name: &str) -> Box { + Box::new(()) +} diff --git a/compiler_base/3rdparty/rustc_errors/src/styled_buffer.rs b/compiler_base/3rdparty/rustc_errors/src/styled_buffer.rs new file mode 100644 index 000000000..e9e8c8702 --- /dev/null +++ b/compiler_base/3rdparty/rustc_errors/src/styled_buffer.rs @@ -0,0 +1,197 @@ +//! 'StyledBuffer', a generic, is responsible for text rendering. +//! +//! An acceptable custom `XXXStyle` for `StyledBuffer` must implement trait `Clone`, `PartialEq`, `Eq` and `Style`. +use crate::Style; + +/// An acceptable custom `XXXStyle` for `StyledBuffer` must implement trait `Clone`, `PartialEq`, `Eq` and `Style`. +#[derive(Debug, PartialEq, Eq)] +pub struct StyledBuffer +where + T: Clone + PartialEq + Eq + Style, +{ + lines: Vec>>, +} + +#[derive(Clone, Debug, PartialEq, Eq)] +struct StyledChar +where + T: Clone + PartialEq + Eq + Style, +{ + chr: char, + style: Option, +} + +/// An acceptable custom `XXXStyle` for `StyledString` must implement trait `Clone`, `PartialEq`, `Eq` and `Style`. +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct StyledString +where + T: Clone + PartialEq + Eq + Style, +{ + pub text: String, + pub style: Option, +} + +impl StyledString +where + T: Clone + PartialEq + Eq + Style, +{ + /// Constructs a new `StyledString` by string and style. + /// + /// # Examples + /// + /// ```ignore + /// // You need to choose a style for the generic parameter `T` of `StyledString`. + /// #[derive(Clone, PartialEq, Eq)] + /// enum MyStyle{ + /// Style_1 + /// } + /// impl Style for MyStyle { + /// ... + /// } + /// + /// let styled_string = StyledString::::new("Hello Styled String".to_string(), Some); + /// ``` + #[inline] + pub fn new(text: String, style: Option) -> Self { + StyledString { text, style } + } +} + +impl StyledChar +where + T: Clone + PartialEq + Eq + Style, +{ + const SPACE: StyledChar = StyledChar::new(' ', None); + + const fn new(chr: char, style: Option) -> Self { + StyledChar { chr, style } + } +} + +impl StyledBuffer +where + T: Clone + PartialEq + Eq + Style, +{ + pub fn new() -> StyledBuffer { + StyledBuffer { lines: vec![] } + } + + /// Returns content of `StyledBuffer` split by lines and line styles + pub fn render(&self) -> Vec>> { + let mut output: Vec>> = vec![]; + let mut styled_vec: Vec> = vec![]; + + for styled_line in &self.lines { + let mut current_style = None; + let mut current_text = String::new(); + + for sc in styled_line { + if sc.style != current_style { + if !current_text.is_empty() { + styled_vec.push(StyledString { + text: current_text, + style: current_style, + }); + } + current_style = sc.style.clone(); + current_text = String::new(); + } + current_text.push(sc.chr); + } + if !current_text.is_empty() { + styled_vec.push(StyledString { + text: current_text, + style: current_style, + }); + } + + // done with the row, push and keep going + output.push(styled_vec); + + styled_vec = vec![]; + } + + output + } + + fn ensure_lines(&mut self, line: usize) { + if line >= self.lines.len() { + self.lines.resize(line + 1, Vec::new()); + } + } + + /// Sets `chr` with `style` for given `line`, `col`. + /// If `line` does not exist in our buffer, adds empty lines up to the given + /// and fills the last line with unstyled whitespace. + pub fn putc(&mut self, line: usize, col: usize, chr: char, style: Option) { + self.ensure_lines(line); + if col >= self.lines[line].len() { + self.lines[line].resize(col + 1, StyledChar::SPACE); + } + self.lines[line][col] = StyledChar::new(chr, style); + } + + /// Sets `string` with `style` for given `line`, starting from `col`. + /// If `line` does not exist in our buffer, adds empty lines up to the given + /// and fills the last line with unstyled whitespace. + pub fn puts(&mut self, line: usize, col: usize, string: &str, style: Option) { + let mut n = col; + for c in string.chars() { + self.putc(line, n, c, style.clone()); + n += 1; + } + } + + /// Sets `string` with `style` for a new line, starting from col 0. + /// It will add an new empty line after all the buffer lines for the `string`. + pub fn pushs(&mut self, string: &str, style: Option) { + let line = self.num_lines(); + let mut col = 0; + for c in string.chars() { + self.putc(line, col, c, style.clone()); + col += 1; + } + } + + /// For the last line inserts `string` with `style` after old content of that line, + /// adding a new line if the `StyledBuffer` has no line. + pub fn appendl(&mut self, string: &str, style: Option) { + let line = if self.num_lines() > 0 { + self.num_lines() - 1 + } else { + self.num_lines() + }; + self.append(line, string, style); + } + + /// For given `line` inserts `string` with `style` before old content of that line, + /// adding lines if needed + pub fn prepend(&mut self, line: usize, string: &str, style: Option) { + self.ensure_lines(line); + let string_len = string.chars().count(); + + if !self.lines[line].is_empty() { + // Push the old content over to make room for new content + for _ in 0..string_len { + self.lines[line].insert(0, StyledChar::SPACE); + } + } + + self.puts(line, 0, string, style); + } + + /// For given `line` inserts `string` with `style` after old content of that line, + /// adding lines if needed + pub fn append(&mut self, line: usize, string: &str, style: Option) { + if line >= self.lines.len() { + self.puts(line, 0, string, style); + } else { + let col = self.lines[line].len(); + self.puts(line, col, string, style); + } + } + + pub fn num_lines(&self) -> usize { + self.lines.len() + } +} diff --git a/compiler_base/3rdparty/rustc_span/Cargo.toml b/compiler_base/3rdparty/rustc_span/Cargo.toml new file mode 100644 index 000000000..d2188fcb8 --- /dev/null +++ b/compiler_base/3rdparty/rustc_span/Cargo.toml @@ -0,0 +1,26 @@ +[package] +name = "rustc_span" +version = "0.1.2" +edition = "2021" +authors = ["zongzhe1024@163.com"] +license = "Apache-2.0 OR MIT" +description = "Reuse rustc_span for compiler_base" +readme = "README.md" +homepage = "https://github.com/kcl-lang/kcl" +repository = "https://github.com/kcl-lang/kcl" +keywords = ["rustc", "rustc_span"] +categories = ["command-line-utilities"] + +[lib] +doctest = false + +[dependencies] +rustc_data_structures = "0.1.2" +scoped-tls = "1.0" +unicode-width = "0.1.4" +cfg-if = "0.1.2" +tracing = "0.1" +sha1 = { package = "sha-1", version = "0.10.0" } +sha2 = "0.10.1" +md5 = { package = "md-5", version = "0.10.0" } +blake3 = "1.5.4" diff --git a/compiler_base/3rdparty/rustc_span/README.md b/compiler_base/3rdparty/rustc_span/README.md new file mode 100644 index 000000000..1d68c9408 --- /dev/null +++ b/compiler_base/3rdparty/rustc_span/README.md @@ -0,0 +1,3 @@ +reuse rustc_span for compiler_base. + +note: [WIP] Do not use it. \ No newline at end of file diff --git a/compiler_base/3rdparty/rustc_span/src/LICENSE b/compiler_base/3rdparty/rustc_span/src/LICENSE new file mode 100644 index 000000000..8467a0168 --- /dev/null +++ b/compiler_base/3rdparty/rustc_span/src/LICENSE @@ -0,0 +1,231 @@ +Short version for non-lawyers: + +The Rust Project is dual-licensed under Apache 2.0 and MIT +terms. + + +Longer version: + +Copyrights in the Rust project are retained by their contributors. No +copyright assignment is required to contribute to the Rust project. + +Some files include explicit copyright notices and/or license notices. +For full authorship information, see the version control history or +https://thanks.rust-lang.org + +Except as otherwise noted (below and/or in individual files), Rust is +licensed under the Apache License, Version 2.0 or + or the MIT license + or , at your option. + + +The Rust Project includes packages written by third parties. +The following third party packages are included, and carry +their own copyright notices and license terms: + +* LLVM. Code for this package is found in src/llvm-project. + + Copyright (c) 2003-2013 University of Illinois at + Urbana-Champaign. All rights reserved. + + Developed by: + + LLVM Team + + University of Illinois at Urbana-Champaign + + http://llvm.org + + Permission is hereby granted, free of charge, to any + person obtaining a copy of this software and associated + documentation files (the "Software"), to deal with the + Software without restriction, including without + limitation the rights to use, copy, modify, merge, + publish, distribute, sublicense, and/or sell copies of + the Software, and to permit persons to whom the Software + is furnished to do so, subject to the following + conditions: + + * Redistributions of source code must retain the + above copyright notice, this list of conditions + and the following disclaimers. + + * Redistributions in binary form must reproduce the + above copyright notice, this list of conditions + and the following disclaimers in the documentation + and/or other materials provided with the + distribution. + + * Neither the names of the LLVM Team, University of + Illinois at Urbana-Champaign, nor the names of its + contributors may be used to endorse or promote + products derived from this Software without + specific prior written permission. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF + ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED + TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A + PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT + SHALL THE CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE + FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT + OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS WITH THE SOFTWARE. + +* Additional libraries included in LLVM carry separate + BSD-compatible licenses. See src/llvm-project/llvm/LICENSE.TXT + for details. + +* compiler-rt, in src/compiler-rt is dual licensed under + LLVM's license and MIT: + + Copyright (c) 2009-2014 by the contributors listed in + CREDITS.TXT + + All rights reserved. + + Developed by: + + LLVM Team + + University of Illinois at Urbana-Champaign + + http://llvm.org + + Permission is hereby granted, free of charge, to any + person obtaining a copy of this software and associated + documentation files (the "Software"), to deal with the + Software without restriction, including without + limitation the rights to use, copy, modify, merge, + publish, distribute, sublicense, and/or sell copies of + the Software, and to permit persons to whom the Software + is furnished to do so, subject to the following + conditions: + + * Redistributions of source code must retain the + above copyright notice, this list of conditions + and the following disclaimers. + + * Redistributions in binary form must reproduce the + above copyright notice, this list of conditions + and the following disclaimers in the documentation + and/or other materials provided with the + distribution. + + * Neither the names of the LLVM Team, University of + Illinois at Urbana-Champaign, nor the names of its + contributors may be used to endorse or promote + products derived from this Software without + specific prior written permission. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF + ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED + TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A + PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT + SHALL THE CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE + FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT + OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS WITH THE SOFTWARE. + + ======================================================== + + Copyright (c) 2009-2014 by the contributors listed in + CREDITS.TXT + + Permission is hereby granted, free of charge, to any + person obtaining a copy of this software and associated + documentation files (the "Software"), to deal in the + Software without restriction, including without + limitation the rights to use, copy, modify, merge, + publish, distribute, sublicense, and/or sell copies of + the Software, and to permit persons to whom the Software + is furnished to do so, subject to the following + conditions: + + The above copyright notice and this permission notice + shall be included in all copies or substantial portions + of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF + ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED + TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A + PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT + SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR + IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + +* Portions of the FFI code for interacting with the native ABI + is derived from the Clay programming language, which carries + the following license. + + Copyright (C) 2008-2010 Tachyon Technologies. + All rights reserved. + + Redistribution and use in source and binary forms, with + or without modification, are permitted provided that the + following conditions are met: + + 1. Redistributions of source code must retain the above + copyright notice, this list of conditions and the + following disclaimer. + + 2. Redistributions in binary form must reproduce the + above copyright notice, this list of conditions and + the following disclaimer in the documentation and/or + other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + DEVELOPERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + OF SUCH DAMAGE. + +* libbacktrace, under src/libbacktrace: + + Copyright (C) 2012-2014 Free Software Foundation, Inc. + Written by Ian Lance Taylor, Google. + + Redistribution and use in source and binary forms, with + or without modification, are permitted provided that the + following conditions are met: + + (1) Redistributions of source code must retain the + above copyright notice, this list of conditions and + the following disclaimer. + + (2) Redistributions in binary form must reproduce + the above copyright notice, this list of conditions + and the following disclaimer in the documentation + and/or other materials provided with the + distribution. + + (3) The name of the author may not be used to + endorse or promote products derived from this + software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + OF SUCH DAMAGE. */ \ No newline at end of file diff --git a/kclvm/3rdparty/rustc_span/src/README.md b/compiler_base/3rdparty/rustc_span/src/README.md similarity index 100% rename from kclvm/3rdparty/rustc_span/src/README.md rename to compiler_base/3rdparty/rustc_span/src/README.md diff --git a/kclvm/3rdparty/rustc_span/src/analyze_source_file.rs b/compiler_base/3rdparty/rustc_span/src/analyze_source_file.rs similarity index 100% rename from kclvm/3rdparty/rustc_span/src/analyze_source_file.rs rename to compiler_base/3rdparty/rustc_span/src/analyze_source_file.rs diff --git a/kclvm/3rdparty/rustc_span/src/caching_source_map_view.rs b/compiler_base/3rdparty/rustc_span/src/caching_source_map_view.rs similarity index 100% rename from kclvm/3rdparty/rustc_span/src/caching_source_map_view.rs rename to compiler_base/3rdparty/rustc_span/src/caching_source_map_view.rs diff --git a/kclvm/3rdparty/rustc_span/src/fatal_error.rs b/compiler_base/3rdparty/rustc_span/src/fatal_error.rs similarity index 100% rename from kclvm/3rdparty/rustc_span/src/fatal_error.rs rename to compiler_base/3rdparty/rustc_span/src/fatal_error.rs diff --git a/compiler_base/3rdparty/rustc_span/src/lib.rs b/compiler_base/3rdparty/rustc_span/src/lib.rs new file mode 100644 index 000000000..f4fcb4040 --- /dev/null +++ b/compiler_base/3rdparty/rustc_span/src/lib.rs @@ -0,0 +1,1203 @@ +//! Source positions and related helper functions. +//! +//! Important concepts in this module include: +//! +//! - the *span*, represented by [`SpanData`] and related types; +//! - source code as represented by a [`SourceMap`]; and +//! - interned strings, represented by [`Symbol`]s, with some common symbols available statically in the [`sym`] module. +//! +//! Unlike most compilers, the span contains not only the position in the source code, but also various other metadata, +//! such as the edition and macro hygiene. This metadata is stored in [`SyntaxContext`] and [`ExpnData`]. +//! +//! ## Note +//! +//! This API is completely unstable and subject to change. + +mod caching_source_map_view; +pub mod fatal_error; +pub mod source_map; +pub use self::caching_source_map_view::CachingSourceMapView; +use rustc_data_structures::sync::Lrc; +pub use source_map::SourceMap; + +mod span_encoding; +pub use span_encoding::{Span, DUMMY_SP}; + +mod analyze_source_file; + +use std::borrow::Cow; +use std::cmp::{self, Ordering}; +use std::collections::hash_map::DefaultHasher; +use std::fmt; +use std::hash::{Hash, Hasher}; +use std::ops::{Add, Range, Sub}; +use std::path::{Path, PathBuf}; +use std::rc::Rc; +use std::str::FromStr; + +use blake3; +use blake3::Hash as Blake3; +use md5::Digest; +use md5::Md5; +use sha1::Sha1; +use sha2::Sha256; + +use tracing::debug; + +// FIXME: We should use this enum or something like it to get rid of the +// use of magic `/rust/1.x/...` paths across the board. +#[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd)] +pub enum RealFileName { + LocalPath(PathBuf), + /// For remapped paths (namely paths into libstd that have been mapped + /// to the appropriate spot on the local host's file system, and local file + /// system paths that have been remapped with `FilePathMapping`), + Remapped { + /// `local_path` is the (host-dependent) local path to the file. This is + /// None if the file was imported from another crate + local_path: Option, + /// `virtual_name` is the stable path rustc will store internally within + /// build artifacts. + virtual_name: PathBuf, + }, +} + +impl Hash for RealFileName { + fn hash(&self, state: &mut H) { + // To prevent #70924 from happening again we should only hash the + // remapped (virtualized) path if that exists. This is because + // virtualized paths to sysroot crates (/rust/$hash or /rust/$version) + // remain stable even if the corresponding local_path changes + self.remapped_path_if_available().hash(state) + } +} + +impl RealFileName { + /// Returns the path suitable for reading from the file system on the local host, + /// if this information exists. + /// Avoid embedding this in build artifacts; see `remapped_path_if_available()` for that. + pub fn local_path(&self) -> Option<&Path> { + match self { + RealFileName::LocalPath(p) => Some(p), + RealFileName::Remapped { + local_path: p, + virtual_name: _, + } => p.as_ref().map(PathBuf::as_path), + } + } + + /// Returns the path suitable for reading from the file system on the local host, + /// if this information exists. + /// Avoid embedding this in build artifacts; see `remapped_path_if_available()` for that. + pub fn into_local_path(self) -> Option { + match self { + RealFileName::LocalPath(p) => Some(p), + RealFileName::Remapped { + local_path: p, + virtual_name: _, + } => p, + } + } + + /// Returns the path suitable for embedding into build artifacts. This would still + /// be a local path if it has not been remapped. A remapped path will not correspond + /// to a valid file system path: see `local_path_if_available()` for something that + /// is more likely to return paths into the local host file system. + pub fn remapped_path_if_available(&self) -> &Path { + match self { + RealFileName::LocalPath(p) + | RealFileName::Remapped { + local_path: _, + virtual_name: p, + } => &p, + } + } + + /// Returns the path suitable for reading from the file system on the local host, + /// if this information exists. Otherwise returns the remapped name. + /// Avoid embedding this in build artifacts; see `remapped_path_if_available()` for that. + pub fn local_path_if_available(&self) -> &Path { + match self { + RealFileName::LocalPath(path) + | RealFileName::Remapped { + local_path: None, + virtual_name: path, + } + | RealFileName::Remapped { + local_path: Some(path), + virtual_name: _, + } => path, + } + } + + pub fn to_string_lossy(&self, display_pref: FileNameDisplayPreference) -> Cow<'_, str> { + match display_pref { + FileNameDisplayPreference::Local => self.local_path_if_available().to_string_lossy(), + FileNameDisplayPreference::Remapped => { + self.remapped_path_if_available().to_string_lossy() + } + } + } +} + +/// Differentiates between real files and common virtual files. +#[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd, Hash)] +pub enum FileName { + Real(RealFileName), + /// Call to `quote!`. + QuoteExpansion(u64), + /// Command line. + Anon(u64), + /// Hack in `src/librustc_ast/parse.rs`. + // FIXME(jseyfried) + MacroExpansion(u64), + ProcMacroSourceCode(u64), + /// Strings provided as `--cfg [cfgspec]` stored in a `crate_cfg`. + CfgSpec(u64), + /// Strings provided as crate attributes in the CLI. + CliCrateAttr(u64), + /// Custom sources for explicit parser calls from plugins and drivers. + Custom(String), + DocTest(PathBuf, isize), + /// Post-substitution inline assembly from LLVM. + InlineAsm(u64), +} + +impl From for FileName { + fn from(p: PathBuf) -> Self { + assert!(!p.to_string_lossy().ends_with('>')); + FileName::Real(RealFileName::LocalPath(p)) + } +} + +#[derive(Clone, Copy, Eq, PartialEq, Hash, Debug)] +pub enum FileNameDisplayPreference { + Remapped, + Local, +} + +pub struct FileNameDisplay<'a> { + inner: &'a FileName, + display_pref: FileNameDisplayPreference, +} + +impl fmt::Display for FileNameDisplay<'_> { + fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + use FileName::*; + match *self.inner { + Real(ref name) => { + write!(fmt, "{}", name.to_string_lossy(self.display_pref)) + } + QuoteExpansion(_) => write!(fmt, ""), + MacroExpansion(_) => write!(fmt, ""), + Anon(_) => write!(fmt, ""), + ProcMacroSourceCode(_) => write!(fmt, ""), + CfgSpec(_) => write!(fmt, ""), + CliCrateAttr(_) => write!(fmt, ""), + Custom(ref s) => write!(fmt, "<{}>", s), + DocTest(ref path, _) => write!(fmt, "{}", path.display()), + InlineAsm(_) => write!(fmt, ""), + } + } +} + +impl FileNameDisplay<'_> { + pub fn to_string_lossy(&self) -> Cow<'_, str> { + match self.inner { + FileName::Real(ref inner) => inner.to_string_lossy(self.display_pref), + _ => Cow::from(format!("{}", self)), + } + } +} + +impl FileName { + pub fn is_real(&self) -> bool { + use FileName::*; + match *self { + Real(_) => true, + Anon(_) + | MacroExpansion(_) + | ProcMacroSourceCode(_) + | CfgSpec(_) + | CliCrateAttr(_) + | Custom(_) + | QuoteExpansion(_) + | DocTest(_, _) + | InlineAsm(_) => false, + } + } + + pub fn prefer_remapped(&self) -> FileNameDisplay<'_> { + FileNameDisplay { + inner: self, + display_pref: FileNameDisplayPreference::Remapped, + } + } + + // This may include transient local filesystem information. + // Must not be embedded in build outputs. + pub fn prefer_local(&self) -> FileNameDisplay<'_> { + FileNameDisplay { + inner: self, + display_pref: FileNameDisplayPreference::Local, + } + } + + pub fn display(&self, display_pref: FileNameDisplayPreference) -> FileNameDisplay<'_> { + FileNameDisplay { + inner: self, + display_pref, + } + } +} + +/// Represents a span. +/// +/// Spans represent a region of code, used for error reporting. Positions in spans +/// are *absolute* positions from the beginning of the [`SourceMap`], not positions +/// relative to [`SourceFile`]s. Methods on the `SourceMap` can be used to relate spans back +/// to the original source. +/// +/// You must be careful if the span crosses more than one file, since you will not be +/// able to use many of the functions on spans in source_map and you cannot assume +/// that the length of the span is equal to `span.hi - span.lo`; there may be space in the +/// [`BytePos`] range between files. +/// +/// `SpanData` is public because `Span` uses a thread-local interner and can't be +/// sent to other threads, but some pieces of performance infra run in a separate thread. +/// Using `Span` is generally preferred. +#[derive(Clone, Copy, Hash, PartialEq, Eq)] +pub struct SpanData { + pub lo: BytePos, + pub hi: BytePos, +} + +// Order spans by position in the file. +impl Ord for SpanData { + fn cmp(&self, other: &Self) -> Ordering { + let SpanData { lo: s_lo, hi: s_hi } = self; + let SpanData { lo: o_lo, hi: o_hi } = other; + + (s_lo, s_hi).cmp(&(o_lo, o_hi)) + } +} + +impl PartialOrd for SpanData { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +impl SpanData { + #[inline] + pub fn span(&self) -> Span { + Span::new(self.lo, self.hi) + } + #[inline] + pub fn with_lo(&self, lo: BytePos) -> Span { + Span::new(lo, self.hi) + } + #[inline] + pub fn with_hi(&self, hi: BytePos) -> Span { + Span::new(self.lo, hi) + } + /// Returns `true` if this is a dummy span with any hygienic context. + #[inline] + pub fn is_dummy(self) -> bool { + self.lo.0 == 0 && self.hi.0 == 0 + } + /// Returns `true` if `self` fully encloses `other`. + pub fn contains(self, other: Self) -> bool { + self.lo <= other.lo && other.hi <= self.hi + } +} + +impl PartialOrd for Span { + fn partial_cmp(&self, rhs: &Self) -> Option { + PartialOrd::partial_cmp(&self.data(), &rhs.data()) + } +} +impl Ord for Span { + fn cmp(&self, rhs: &Self) -> Ordering { + Ord::cmp(&self.data(), &rhs.data()) + } +} + +impl Span { + #[inline] + pub fn lo(self) -> BytePos { + self.data().lo + } + #[inline] + pub fn with_lo(self, lo: BytePos) -> Span { + self.data().with_lo(lo) + } + #[inline] + pub fn hi(self) -> BytePos { + self.data().hi + } + #[inline] + pub fn with_hi(self, hi: BytePos) -> Span { + self.data().with_hi(hi) + } + + /// Returns `true` if this is a dummy span with any hygienic context. + #[inline] + pub fn is_dummy(self) -> bool { + self.data_untracked().is_dummy() + } + + /// Returns a new span representing an empty span at the beginning of this span. + #[inline] + pub fn shrink_to_lo(self) -> Span { + let span = self.data_untracked(); + span.with_hi(span.lo) + } + /// Returns a new span representing an empty span at the end of this span. + #[inline] + pub fn shrink_to_hi(self) -> Span { + let span = self.data_untracked(); + span.with_lo(span.hi) + } + + #[inline] + /// Returns `true` if `hi == lo`. + pub fn is_empty(self) -> bool { + let span = self.data_untracked(); + span.hi == span.lo + } + + /// Returns `self` if `self` is not the dummy span, and `other` otherwise. + pub fn substitute_dummy(self, other: Span) -> Span { + if self.is_dummy() { + other + } else { + self + } + } + + /// Returns `true` if `self` fully encloses `other`. + pub fn contains(self, other: Span) -> bool { + let span = self.data(); + let other = other.data(); + span.contains(other) + } + + /// Returns `true` if `self` touches `other`. + pub fn overlaps(self, other: Span) -> bool { + let span = self.data(); + let other = other.data(); + span.lo < other.hi && other.lo < span.hi + } + + /// Returns `true` if the spans are equal with regards to the source text. + /// + /// Use this instead of `==` when either span could be generated code, + /// and you only care that they point to the same bytes of source text. + pub fn source_equal(self, other: Span) -> bool { + let span = self.data(); + let other = other.data(); + span.lo == other.lo && span.hi == other.hi + } + + /// Returns `Some(span)`, where the start is trimmed by the end of `other`. + pub fn trim_start(self, other: Span) -> Option { + let span = self.data(); + let other = other.data(); + if span.hi > other.hi { + Some(span.with_lo(cmp::max(span.lo, other.hi))) + } else { + None + } + } + + /// Returns a `Span` that would enclose both `self` and `end`. + /// + /// ```text + /// ____ ___ + /// self lorem ipsum end + /// ^^^^^^^^^^^^^^^^^^^^ + /// ``` + pub fn to(self, end: Span) -> Span { + let span_data = self.data(); + let end_data = end.data(); + Span::new( + cmp::min(span_data.lo, end_data.lo), + cmp::max(span_data.hi, end_data.hi), + ) + } + + /// Returns a `Span` between the end of `self` to the beginning of `end`. + /// + /// ```text + /// ____ ___ + /// self lorem ipsum end + /// ^^^^^^^^^^^^^ + /// ``` + pub fn between(self, end: Span) -> Span { + let span = self.data(); + let end = end.data(); + Span::new(span.hi, end.lo) + } + + /// Returns a `Span` from the beginning of `self` until the beginning of `end`. + /// + /// ```text + /// ____ ___ + /// self lorem ipsum end + /// ^^^^^^^^^^^^^^^^^ + /// ``` + pub fn until(self, end: Span) -> Span { + // Most of this function's body is copied from `to`. + // We can't just do `self.to(end.shrink_to_lo())`, + // because to also does some magic where it uses min/max so + // it can handle overlapping spans. Some advanced mis-use of + // `until` with different ctxts makes this visible. + let span_data = self.data(); + let end_data = end.data(); + Span::new(span_data.lo, end_data.lo) + } + + pub fn from_inner(self, inner: InnerSpan) -> Span { + let span = self.data(); + Span::new( + span.lo + BytePos::from_usize(inner.start), + span.lo + BytePos::from_usize(inner.end), + ) + } +} + +impl Default for Span { + fn default() -> Self { + DUMMY_SP + } +} + +impl fmt::Debug for SpanData { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(&Span::new(self.lo, self.hi), f) + } +} + +/// Identifies an offset of a multi-byte character in a `SourceFile`. +#[derive(Copy, Clone, Eq, PartialEq, Debug)] +pub struct MultiByteChar { + /// The absolute offset of the character in the `SourceMap`. + pub pos: BytePos, + /// The number of bytes, `>= 2`. + pub bytes: u8, +} + +/// Identifies an offset of a non-narrow character in a `SourceFile`. +#[derive(Copy, Clone, Eq, PartialEq, Debug)] +pub enum NonNarrowChar { + /// Represents a zero-width character. + ZeroWidth(BytePos), + /// Represents a wide (full-width) character. + Wide(BytePos), + /// Represents a tab character, represented visually with a width of 4 characters. + Tab(BytePos), +} + +impl NonNarrowChar { + fn new(pos: BytePos, width: usize) -> Self { + match width { + 0 => NonNarrowChar::ZeroWidth(pos), + 2 => NonNarrowChar::Wide(pos), + 4 => NonNarrowChar::Tab(pos), + _ => panic!("width {} given for non-narrow character", width), + } + } + + /// Returns the absolute offset of the character in the `SourceMap`. + pub fn pos(&self) -> BytePos { + match *self { + NonNarrowChar::ZeroWidth(p) | NonNarrowChar::Wide(p) | NonNarrowChar::Tab(p) => p, + } + } + + /// Returns the width of the character, 0 (zero-width) or 2 (wide). + pub fn width(&self) -> usize { + match *self { + NonNarrowChar::ZeroWidth(_) => 0, + NonNarrowChar::Wide(_) => 2, + NonNarrowChar::Tab(_) => 4, + } + } +} + +impl Add for NonNarrowChar { + type Output = Self; + + fn add(self, rhs: BytePos) -> Self { + match self { + NonNarrowChar::ZeroWidth(pos) => NonNarrowChar::ZeroWidth(pos + rhs), + NonNarrowChar::Wide(pos) => NonNarrowChar::Wide(pos + rhs), + NonNarrowChar::Tab(pos) => NonNarrowChar::Tab(pos + rhs), + } + } +} + +impl Sub for NonNarrowChar { + type Output = Self; + + fn sub(self, rhs: BytePos) -> Self { + match self { + NonNarrowChar::ZeroWidth(pos) => NonNarrowChar::ZeroWidth(pos - rhs), + NonNarrowChar::Wide(pos) => NonNarrowChar::Wide(pos - rhs), + NonNarrowChar::Tab(pos) => NonNarrowChar::Tab(pos - rhs), + } + } +} + +/// Identifies an offset of a character that was normalized away from `SourceFile`. +#[derive(Copy, Clone, Eq, PartialEq, Debug)] +pub struct NormalizedPos { + /// The absolute offset of the character in the `SourceMap`. + pub pos: BytePos, + /// The difference between original and normalized string at position. + pub diff: u32, +} + +#[derive(PartialEq, Eq, Clone, Debug)] +pub enum ExternalSource { + /// No external source has to be loaded, since the `SourceFile` represents a local crate. + Unneeded, + Foreign { + kind: ExternalSourceKind, + /// This SourceFile's byte-offset within the source_map of its original crate. + original_start_pos: BytePos, + /// The end of this SourceFile within the source_map of its original crate. + original_end_pos: BytePos, + }, +} + +/// The state of the lazy external source loading mechanism of a `SourceFile`. +#[derive(PartialEq, Eq, Clone, Debug)] +pub enum ExternalSourceKind { + /// The external source has been loaded already. + Present(Rc), + /// No attempt has been made to load the external source. + AbsentOk, + /// A failed attempt has been made to load the external source. + AbsentErr, + Unneeded, +} + +impl ExternalSource { + pub fn get_source(&self) -> Option<&Rc> { + match self { + ExternalSource::Foreign { + kind: ExternalSourceKind::Present(ref src), + .. + } => Some(src), + _ => None, + } + } +} + +#[derive(Debug)] +pub struct OffsetOverflowError; + +#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub enum SourceFileHashAlgorithm { + Md5, + Sha1, + Sha256, + Blake3, +} + +impl FromStr for SourceFileHashAlgorithm { + type Err = (); + + fn from_str(s: &str) -> Result { + match s { + "md5" => Ok(SourceFileHashAlgorithm::Md5), + "sha1" => Ok(SourceFileHashAlgorithm::Sha1), + "sha256" => Ok(SourceFileHashAlgorithm::Sha256), + "blake3" => Ok(SourceFileHashAlgorithm::Blake3), + _ => Err(()), + } + } +} + +/// The hash of the on-disk source file used for debug info. +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +pub struct SourceFileHash { + pub kind: SourceFileHashAlgorithm, + value: [u8; 32], +} + +impl SourceFileHash { + pub fn new(kind: SourceFileHashAlgorithm, src: &str) -> SourceFileHash { + let mut hash = SourceFileHash { + kind, + value: Default::default(), + }; + let len = hash.hash_len(); + let value = &mut hash.value[..len]; + let data = src.as_bytes(); + match kind { + SourceFileHashAlgorithm::Md5 => { + value.copy_from_slice(&Md5::digest(data)); + } + SourceFileHashAlgorithm::Sha1 => { + value.copy_from_slice(&Sha1::digest(data)); + } + SourceFileHashAlgorithm::Sha256 => { + value.copy_from_slice(&Sha256::digest(data)); + } + SourceFileHashAlgorithm::Blake3 => { + value.copy_from_slice(blake3::hash(data).as_bytes()); + } + } + hash + } + + /// Check if the stored hash matches the hash of the string. + pub fn matches(&self, src: &str) -> bool { + Self::new(self.kind, src) == *self + } + + /// The bytes of the hash. + pub fn hash_bytes(&self) -> &[u8] { + let len = self.hash_len(); + &self.value[..len] + } + + fn hash_len(&self) -> usize { + match self.kind { + SourceFileHashAlgorithm::Md5 => 16, + SourceFileHashAlgorithm::Sha1 => 20, + SourceFileHashAlgorithm::Sha256 => 32, + SourceFileHashAlgorithm::Blake3 => 32, + } + } +} + +/// A single source in the [`SourceMap`]. +#[derive(Clone)] +pub struct SourceFile { + /// The name of the file that the source came from. Source that doesn't + /// originate from files has names between angle brackets by convention + /// (e.g., ``). + pub name: FileName, + /// The complete source code. + pub src: Option>, + /// The source code's hash. + pub src_hash: SourceFileHash, + /// The start position of this source in the `SourceMap`. + pub start_pos: BytePos, + /// The end position of this source in the `SourceMap`. + pub end_pos: BytePos, + /// Locations of lines beginnings in the source code. + pub lines: Vec, + /// Locations of multi-byte characters in the source code. + pub multibyte_chars: Vec, + /// Width of characters that are not narrow in the source code. + pub non_narrow_chars: Vec, + /// Locations of characters removed during normalization. + pub normalized_pos: Vec, + /// A hash of the filename, used for speeding up hashing in incremental compilation. + pub name_hash: u64, +} + +impl fmt::Debug for SourceFile { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(fmt, "SourceFile({:?})", self.name) + } +} + +impl SourceFile { + pub fn new( + name: FileName, + mut src: String, + start_pos: BytePos, + hash_kind: SourceFileHashAlgorithm, + ) -> Self { + // Compute the file hash before any normalization. + let src_hash = SourceFileHash::new(hash_kind, &src); + let normalized_pos = normalize_src(&mut src, start_pos); + + let name_hash = { + let mut hasher = DefaultHasher::new(); + name.hash(&mut hasher); + hasher.finish() + }; + let end_pos = start_pos.to_usize() + src.len(); + assert!(end_pos <= u32::MAX as usize); + + let (lines, multibyte_chars, non_narrow_chars) = + analyze_source_file::analyze_source_file(&src, start_pos); + + SourceFile { + name, + src: Some(Rc::new(src)), + src_hash, + start_pos, + end_pos: Pos::from_usize(end_pos), + lines, + multibyte_chars, + non_narrow_chars, + normalized_pos, + name_hash, + } + } + + /// Returns the `BytePos` of the beginning of the current line. + pub fn line_begin_pos(&self, pos: BytePos) -> BytePos { + let line_index = self.lookup_line(pos).unwrap(); + self.lines[line_index] + } + + /// Gets a line from the list of pre-computed line-beginnings. + /// The line number here is 0-based. + pub fn get_line(&self, line_number: usize) -> Option> { + fn get_until_newline(src: &str, begin: usize) -> &str { + // We can't use `lines.get(line_number+1)` because we might + // be parsing when we call this function and thus the current + // line is the last one we have line info for. + let slice = &src[begin..]; + match slice.find('\n') { + Some(e) => &slice[..e], + None => slice, + } + } + + let begin = { + let line = self.lines.get(line_number)?; + let begin: BytePos = *line - self.start_pos; + begin.to_usize() + }; + + if let Some(ref src) = self.src { + Some(Cow::from(get_until_newline(src, begin))) + } else { + None + } + } + + pub fn is_real_file(&self) -> bool { + self.name.is_real() + } + + pub fn is_imported(&self) -> bool { + self.src.is_none() + } + + pub fn count_lines(&self) -> usize { + self.lines.len() + } + + /// Finds the line containing the given position. The return value is the + /// index into the `lines` array of this `SourceFile`, not the 1-based line + /// number. If the source_file is empty or the position is located before the + /// first line, `None` is returned. + pub fn lookup_line(&self, pos: BytePos) -> Option { + match self.lines.binary_search(&pos) { + Ok(idx) => Some(idx), + Err(0) => None, + Err(idx) => Some(idx - 1), + } + } + + pub fn line_bounds(&self, line_index: usize) -> Range { + if self.is_empty() { + return self.start_pos..self.end_pos; + } + + assert!(line_index < self.lines.len()); + if line_index == (self.lines.len() - 1) { + self.lines[line_index]..self.end_pos + } else { + self.lines[line_index]..self.lines[line_index + 1] + } + } + + /// Returns whether or not the file contains the given `SourceMap` byte + /// position. The position one past the end of the file is considered to be + /// contained by the file. This implies that files for which `is_empty` + /// returns true still contain one byte position according to this function. + #[inline] + pub fn contains(&self, byte_pos: BytePos) -> bool { + byte_pos >= self.start_pos && byte_pos <= self.end_pos + } + + #[inline] + pub fn is_empty(&self) -> bool { + self.start_pos == self.end_pos + } + + /// Calculates the original byte position relative to the start of the file + /// based on the given byte position. + pub fn original_relative_byte_pos(&self, pos: BytePos) -> BytePos { + // Diff before any records is 0. Otherwise use the previously recorded + // diff as that applies to the following characters until a new diff + // is recorded. + let diff = match self.normalized_pos.binary_search_by(|np| np.pos.cmp(&pos)) { + Ok(i) => self.normalized_pos[i].diff, + Err(i) if i == 0 => 0, + Err(i) => self.normalized_pos[i - 1].diff, + }; + + BytePos::from_u32(pos.0 - self.start_pos.0 + diff) + } + + /// Converts an absolute `BytePos` to a `CharPos` relative to the `SourceFile`. + pub fn bytepos_to_file_charpos(&self, bpos: BytePos) -> CharPos { + // The number of extra bytes due to multibyte chars in the `SourceFile`. + let mut total_extra_bytes = 0; + + for mbc in self.multibyte_chars.iter() { + debug!("{}-byte char at {:?}", mbc.bytes, mbc.pos); + if mbc.pos < bpos { + // Every character is at least one byte, so we only + // count the actual extra bytes. + total_extra_bytes += mbc.bytes as u32 - 1; + // We should never see a byte position in the middle of a + // character. + assert!(bpos.to_u32() >= mbc.pos.to_u32() + mbc.bytes as u32); + } else { + break; + } + } + + assert!(self.start_pos.to_u32() + total_extra_bytes <= bpos.to_u32()); + CharPos(bpos.to_usize() - self.start_pos.to_usize() - total_extra_bytes as usize) + } + + /// Looks up the file's (1-based) line number and (0-based `CharPos`) column offset, for a + /// given `BytePos`. + pub fn lookup_file_pos(&self, pos: BytePos) -> (usize, CharPos) { + let chpos = self.bytepos_to_file_charpos(pos); + match self.lookup_line(pos) { + Some(a) => { + let line = a + 1; // Line numbers start at 1 + let linebpos = self.lines[a]; + let linechpos = self.bytepos_to_file_charpos(linebpos); + let col = chpos - linechpos; + debug!( + "byte pos {:?} is on the line at byte pos {:?}", + pos, linebpos + ); + debug!( + "char pos {:?} is on the line at char pos {:?}", + chpos, linechpos + ); + debug!("byte is on line: {}", line); + assert!(chpos >= linechpos); + (line, col) + } + None => (0, chpos), + } + } + + /// Looks up the file's (1-based) line number, (0-based `CharPos`) column offset, and (0-based) + /// column offset when displayed, for a given `BytePos`. + pub fn lookup_file_pos_with_col_display(&self, pos: BytePos) -> (usize, CharPos, usize) { + let (line, col_or_chpos) = self.lookup_file_pos(pos); + if line > 0 { + let col = col_or_chpos; + let linebpos = self.lines[line - 1]; + let col_display = { + let start_width_idx = self + .non_narrow_chars + .binary_search_by_key(&linebpos, |x| x.pos()) + .unwrap_or_else(|x| x); + let end_width_idx = self + .non_narrow_chars + .binary_search_by_key(&pos, |x| x.pos()) + .unwrap_or_else(|x| x); + let special_chars = end_width_idx - start_width_idx; + let non_narrow: usize = self.non_narrow_chars[start_width_idx..end_width_idx] + .iter() + .map(|x| x.width()) + .sum(); + col.0 - special_chars + non_narrow + }; + (line, col, col_display) + } else { + let chpos = col_or_chpos; + let col_display = { + let end_width_idx = self + .non_narrow_chars + .binary_search_by_key(&pos, |x| x.pos()) + .unwrap_or_else(|x| x); + let non_narrow: usize = self.non_narrow_chars[0..end_width_idx] + .iter() + .map(|x| x.width()) + .sum(); + chpos.0 - end_width_idx + non_narrow + }; + (0, chpos, col_display) + } + } +} + +/// Normalizes the source code and records the normalizations. +fn normalize_src(src: &mut String, start_pos: BytePos) -> Vec { + let mut normalized_pos = vec![]; + remove_bom(src, &mut normalized_pos); + normalize_newlines(src, &mut normalized_pos); + + // Offset all the positions by start_pos to match the final file positions. + for np in &mut normalized_pos { + np.pos.0 += start_pos.0; + } + + normalized_pos +} + +/// Removes UTF-8 BOM, if any. +fn remove_bom(src: &mut String, normalized_pos: &mut Vec) { + if src.starts_with('\u{feff}') { + src.drain(..3); + normalized_pos.push(NormalizedPos { + pos: BytePos(0), + diff: 3, + }); + } +} + +/// Replaces `\r\n` with `\n` in-place in `src`. +/// +/// Returns error if there's a lone `\r` in the string. +fn normalize_newlines(src: &mut String, normalized_pos: &mut Vec) { + if !src.as_bytes().contains(&b'\r') { + return; + } + + // We replace `\r\n` with `\n` in-place, which doesn't break utf-8 encoding. + // While we *can* call `as_mut_vec` and do surgery on the live string + // directly, let's rather steal the contents of `src`. This makes the code + // safe even if a panic occurs. + + let mut buf = std::mem::replace(src, String::new()).into_bytes(); + let mut gap_len = 0; + let mut tail = buf.as_mut_slice(); + let mut cursor = 0; + let original_gap = normalized_pos.last().map_or(0, |l| l.diff); + loop { + let idx = match find_crlf(&tail[gap_len..]) { + None => tail.len(), + Some(idx) => idx + gap_len, + }; + tail.copy_within(gap_len..idx, 0); + tail = &mut tail[idx - gap_len..]; + if tail.len() == gap_len { + break; + } + cursor += idx - gap_len; + gap_len += 1; + normalized_pos.push(NormalizedPos { + pos: BytePos::from_usize(cursor + 1), + diff: original_gap + gap_len as u32, + }); + } + + // Account for removed `\r`. + // After `set_len`, `buf` is guaranteed to contain utf-8 again. + let new_len = buf.len() - gap_len; + unsafe { + buf.set_len(new_len); + *src = String::from_utf8_unchecked(buf); + } + + fn find_crlf(src: &[u8]) -> Option { + let mut search_idx = 0; + while let Some(idx) = find_cr(&src[search_idx..]) { + if src[search_idx..].get(idx + 1) != Some(&b'\n') { + search_idx += idx + 1; + continue; + } + return Some(search_idx + idx); + } + None + } + + fn find_cr(src: &[u8]) -> Option { + src.iter().position(|&b| b == b'\r') + } +} + +// _____________________________________________________________________________ +// Pos, BytePos, CharPos +// + +pub trait Pos { + fn from_usize(n: usize) -> Self; + fn to_usize(&self) -> usize; + fn from_u32(n: u32) -> Self; + fn to_u32(&self) -> u32; +} + +macro_rules! impl_pos { + ( + $( + $(#[$attr:meta])* + $vis:vis struct $ident:ident($inner_vis:vis $inner_ty:ty); + )* + ) => { + $( + $(#[$attr])* + $vis struct $ident($inner_vis $inner_ty); + + impl Pos for $ident { + #[inline(always)] + fn from_usize(n: usize) -> $ident { + $ident(n as $inner_ty) + } + + #[inline(always)] + fn to_usize(&self) -> usize { + self.0 as usize + } + + #[inline(always)] + fn from_u32(n: u32) -> $ident { + $ident(n as $inner_ty) + } + + #[inline(always)] + fn to_u32(&self) -> u32 { + self.0 as u32 + } + } + + impl Add for $ident { + type Output = $ident; + + #[inline(always)] + fn add(self, rhs: $ident) -> $ident { + $ident(self.0 + rhs.0) + } + } + + impl Sub for $ident { + type Output = $ident; + + #[inline(always)] + fn sub(self, rhs: $ident) -> $ident { + $ident(self.0 - rhs.0) + } + } + + impl fmt::Display for $ident { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.0) + } + } + )* + }; +} + +impl_pos! { + /// A byte offset. + /// + /// Keep this small (currently 32-bits), as AST contains a lot of them. + #[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)] + pub struct BytePos(pub u32); + + /// A character offset. + /// + /// Because of multibyte UTF-8 characters, a byte offset + /// is not equivalent to a character offset. The [`SourceMap`] will convert [`BytePos`] + /// values to `CharPos` values as necessary. + #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)] + pub struct CharPos(pub usize); +} + +impl BytePos {} + +// _____________________________________________________________________________ +// Loc, SourceFileAndLine, SourceFileAndBytePos +// + +/// A source code location used for error reporting. +#[derive(Debug, Clone)] +pub struct Loc { + /// Information about the original source. + pub file: Lrc, + /// The (1-based) line number. + pub line: usize, + /// The (0-based) column offset. + pub col: CharPos, + /// The (0-based) column offset when displayed. + pub col_display: usize, +} + +// Used to be structural records. +#[derive(Debug)] +pub struct SourceFileAndLine { + pub sf: Lrc, + /// Index of line, starting from 0. + pub line: usize, +} +#[derive(Debug)] +pub struct SourceFileAndBytePos { + pub sf: Lrc, + pub pos: BytePos, +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub struct LineInfo { + /// Index of line, starting from 0. + pub line_index: usize, + + /// Column in line where span begins, starting from 0. + pub start_col: CharPos, + + /// Column in line where span ends, starting from 0, exclusive. + pub end_col: CharPos, +} + +pub struct FileLines { + pub file: Lrc, + pub lines: Vec, +} + +// _____________________________________________________________________________ +// SpanLinesError, SpanSnippetError, DistinctSources, MalformedSourceMapPositions +// + +pub type FileLinesResult = Result; + +#[derive(Clone, PartialEq, Eq, Debug)] +pub enum SpanLinesError { + DistinctSources(DistinctSources), +} + +#[derive(Clone, PartialEq, Eq, Debug)] +pub enum SpanSnippetError { + IllFormedSpan(Span), + DistinctSources(DistinctSources), + MalformedForSourcemap(MalformedSourceMapPositions), + SourceNotAvailable { filename: FileName }, +} + +#[derive(Clone, PartialEq, Eq, Debug)] +pub struct DistinctSources { + pub begin: (FileName, BytePos), + pub end: (FileName, BytePos), +} + +#[derive(Clone, PartialEq, Eq, Debug)] +pub struct MalformedSourceMapPositions { + pub name: FileName, + pub source_len: usize, + pub begin_pos: BytePos, + pub end_pos: BytePos, +} + +/// Range inside of a `Span` used for diagnostics when we only have access to relative positions. +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +pub struct InnerSpan { + pub start: usize, + pub end: usize, +} + +impl InnerSpan { + pub fn new(start: usize, end: usize) -> InnerSpan { + InnerSpan { start, end } + } +} diff --git a/kclvm/3rdparty/rustc_span/src/source_map.rs b/compiler_base/3rdparty/rustc_span/src/source_map.rs similarity index 100% rename from kclvm/3rdparty/rustc_span/src/source_map.rs rename to compiler_base/3rdparty/rustc_span/src/source_map.rs diff --git a/kclvm/3rdparty/rustc_span/src/span_encoding.rs b/compiler_base/3rdparty/rustc_span/src/span_encoding.rs similarity index 100% rename from kclvm/3rdparty/rustc_span/src/span_encoding.rs rename to compiler_base/3rdparty/rustc_span/src/span_encoding.rs diff --git a/compiler_base/Cargo.toml b/compiler_base/Cargo.toml new file mode 100644 index 000000000..e0aeca2e1 --- /dev/null +++ b/compiler_base/Cargo.toml @@ -0,0 +1,28 @@ +[package] +name = "compiler_base" +version = "0.1.4" +edition = "2021" +authors = ["zongzhe1024@163.com"] +license = "Apache-2.0 OR MIT" +description = "A common domain programming language framework." +readme = "README.md" +homepage = "https://github.com/kcl-lang/kcl" +repository = "https://github.com/kcl-lang/kcl" +keywords = ["compiler"] +categories = ["command-line-utilities"] + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] + +[workspace] +members = [ + "session", + "macros", + "span", + "error", + "parallel", + "3rdparty/rustc_errors", + "3rdparty/rustc_data_structures", + "3rdparty/rustc_span", +] \ No newline at end of file diff --git a/compiler_base/README.md b/compiler_base/README.md new file mode 100644 index 000000000..3fc0e905f --- /dev/null +++ b/compiler_base/README.md @@ -0,0 +1,2 @@ +Compiler_Base +note: [WIP] Do not use it. \ No newline at end of file diff --git a/compiler_base/error/Cargo.toml b/compiler_base/error/Cargo.toml new file mode 100644 index 000000000..b5d6ab966 --- /dev/null +++ b/compiler_base/error/Cargo.toml @@ -0,0 +1,27 @@ +[package] +name = "compiler_base_error" +version = "0.1.6" +edition = "2021" +authors = ["zongzhe1024@163.com"] +license = "Apache-2.0 OR MIT" +description = "compiler_base_error" +readme = "README.md" +homepage = "https://github.com/kcl-lang/kcl" +repository = "https://github.com/kcl-lang/kcl" +keywords = ["compiler", "error"] +categories = ["command-line-utilities"] + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +compiler_base_span = "0.1.3" +compiler_base_macros = "0.1.1" +pretty_assertions = "1.3.0" +rustc_span = "0.1.2" +rustc_errors = "0.1.2" +unic-langid = {version="0.9.0", features = ["macros"]} + +fluent = "0.16.0" +termcolor = "1.0" +walkdir = "2" +anyhow = "1.0" \ No newline at end of file diff --git a/compiler_base/error/README.md b/compiler_base/error/README.md new file mode 100644 index 000000000..e12e8547c --- /dev/null +++ b/compiler_base/error/README.md @@ -0,0 +1,3 @@ +compiler_base_error + +note: [WIP] Do not use it. \ No newline at end of file diff --git a/compiler_base/error/src/diagnostic/components.rs b/compiler_base/error/src/diagnostic/components.rs new file mode 100644 index 000000000..a97c6bc2e --- /dev/null +++ b/compiler_base/error/src/diagnostic/components.rs @@ -0,0 +1,377 @@ +//! 'components.rs' defines all components with style `DiagnosticStyle` that builtin in compiler_base_error. +use std::{cmp::Ordering, sync::Arc}; + +use super::{style::DiagnosticStyle, Component}; +use crate::errors::ComponentFormatError; +use compiler_base_span::{span_to_filename_string, SourceFile, SourceMap, Span}; +use rustc_errors::styled_buffer::{StyledBuffer, StyledString}; +use rustc_span::LineInfo; + +const CODE_LINE_PREFIX: &str = " | "; +const FILE_PATH_PREFIX: &str = "-->"; + +/// `Label` can be considered as a component of diagnostic to display a short label message in `Diagnositc`. +/// `Label` provides "error", "warning", "note" and "Help" four kinds of labels. +/// +/// # Examples +/// +/// ```rust +/// # use compiler_base_error::Component; +/// # use compiler_base_error::components::Label; +/// # use compiler_base_error::DiagnosticStyle; +/// # use rustc_errors::styled_buffer::StyledBuffer; +/// +/// let mut sb = StyledBuffer::::new(); +/// let mut errs = vec![]; +/// +/// // rendering text: "error[E3131]" +/// Label::Error("E3131".to_string()).format(&mut sb, &mut errs); +/// +/// // rendering text: "warning[W3131]" +/// Label::Warning("W3131".to_string()).format(&mut sb, &mut errs); +/// +/// // rendering text: "note" +/// Label::Note.format(&mut sb, &mut errs); +/// +/// // rendering text: "help" +/// Label::Help.format(&mut sb, &mut errs); +/// ``` +pub enum Label { + Error(String), + Warning(String), + Note, + Help, +} + +impl Component for Label { + fn format(&self, sb: &mut StyledBuffer, _: &mut Vec) { + let (text, style, code) = match self { + Label::Error(ecode) => ("error", DiagnosticStyle::NeedFix, Some(ecode)), + Label::Warning(wcode) => ("warning", DiagnosticStyle::NeedAttention, Some(wcode)), + Label::Note => ("note", DiagnosticStyle::Important, None), + Label::Help => ("help", DiagnosticStyle::Helpful, None), + }; + sb.appendl(text, Some(style)); + + // e.g. "error[E1010]" + if let Some(c) = code { + sb.appendl("[", Some(DiagnosticStyle::Helpful)); + sb.appendl(c.as_str(), Some(DiagnosticStyle::Helpful)); + sb.appendl("]", Some(DiagnosticStyle::Helpful)); + } + } +} + +// Make `StyledString` into a component of diagnostic to display a string with style. +// For more information about `StyledString`, see doc in `/compiler_base/3rdparty/rustc_errors/src/styled_buffer.rs`. +impl Component for StyledString { + #[inline] + fn format(&self, sb: &mut StyledBuffer, _: &mut Vec) { + sb.appendl(&self.text, self.style); + } +} + +/// `UnderLine` is a component of diagnostic to display an underline. +/// +/// ```ignore +/// int test = 0; +/// ^^^^ This is an underline under variable `test` +/// ``` +pub struct UnderLine { + start: usize, + end: usize, + symbol: StyledString, +} + +const DEFAULT_UNDERLINE_LABEL: &str = "^"; +impl UnderLine { + /// Constructs a new `UnderLine` with a default label. + /// + /// # Examples + /// + /// ```rust + /// # use compiler_base_error::Component; + /// # use compiler_base_error::components::UnderLine; + /// # use compiler_base_error::DiagnosticStyle; + /// # use rustc_errors::styled_buffer::StyledBuffer; + /// + /// let mut sb = StyledBuffer::::new(); + /// let mut errs = vec![]; + /// + /// // rendering text: "^^^^^^^^^^" + /// let ul = UnderLine::new_with_default_label(0, 10, None); + /// ul.format(&mut sb, &mut errs); + /// + /// // rendering text: "^^^^^^^^^^" in `DiagnosticStyle::NeedFix`. + /// let ul_need_fix = UnderLine::new_with_default_label(0, 10, Some(DiagnosticStyle::NeedFix)); + /// ul_need_fix.format(&mut sb, &mut errs); + /// ``` + #[inline] + pub fn new_with_default_label( + start: usize, + end: usize, + style: Option, + ) -> Self { + Self { + start, + end, + symbol: StyledString::::new( + DEFAULT_UNDERLINE_LABEL.to_string(), + style, + ), + } + } + + /// Constructs a new `UnderLine` with a custom label. + /// + /// # Examples + /// + /// ```rust + /// # use compiler_base_error::Component; + /// # use compiler_base_error::components::UnderLine; + /// # use compiler_base_error::DiagnosticStyle; + /// # use rustc_errors::styled_buffer::StyledBuffer; + /// + /// let mut sb = StyledBuffer::::new(); + /// let mut errs = vec![]; + /// + /// // rendering text: "__________" + /// let ul = UnderLine::new(0, 10, "_".to_string(), None); + /// ul.format(&mut sb, &mut errs); + /// + /// // rendering text: "~~" in `DiagnosticStyle::NeedFix`. + /// let ul_need_fix = UnderLine::new(0, 2, "~".to_string(), Some(DiagnosticStyle::NeedFix)); + /// ul_need_fix.format(&mut sb, &mut errs); + /// ``` + #[inline] + pub fn new(start: usize, end: usize, label: String, style: Option) -> Self { + Self { + start, + end, + symbol: StyledString::::new(label, style), + } + } +} + +impl Component for UnderLine { + fn format(&self, sb: &mut StyledBuffer, errs: &mut Vec) { + match self.start.cmp(&self.end) { + Ordering::Greater => errs.push(ComponentFormatError::new( + "UnderLine", + "Failed to Format UnderLine in One Line.", + )), + Ordering::Less => { + let indent = self.start; + format!("{: {} + } + } +} + +/// `CodeSnippet` is a component of diagnostic to display code snippets. +/// +/// Note: +/// If the span spans multiple lines of code, only the first line of the code will be selected. +/// +/// In the text rendered by [`CodeSnippet`], the specific position of the span will be highlighted by an underline. +/// +/// Therefore, we recommend that do not use a span with a large scope, +/// the scope of the span should be as small as possible and point to the problem location in the code snippet. +pub struct CodeSnippet { + code_span: Span, + source_map: Arc, +} + +impl CodeSnippet { + /// # Examples + /// + /// If you want to get one line code snippet from 'compiler_base/error/src/diagnostic/test_datas/code_snippet' file + /// ```ignore + /// Line 1 Code Snippet. + /// Line 2 Code Snippet. + /// ``` + /// + /// ```rust + /// # use compiler_base_error::{ + /// # Component, + /// # DiagnosticStyle, + /// # }; + /// # use compiler_base_span::{ + /// # SourceMap, + /// # FilePathMapping, + /// # span_to_filename_string + /// # }; + /// # use rustc_errors::styled_buffer::StyledBuffer; + /// # use compiler_base_span::{span::new_byte_pos, SpanData}; + /// # use compiler_base_error::components::CodeSnippet; + /// # use std::{path::PathBuf, sync::Arc, fs}; + /// + /// let mut sb = StyledBuffer::::new(); + /// let mut errs = vec![]; + /// + /// // 1. You shouled load the file and create the `SourceFile` + /// let filename = fs::canonicalize(&PathBuf::from("./src/diagnostic/test_datas/code_snippet")) + /// .unwrap() + /// .display() + /// .to_string(); + /// + /// let src = std::fs::read_to_string(filename.clone()).unwrap(); + /// let sm = SourceMap::new(FilePathMapping::empty()); + /// sm.new_source_file(PathBuf::from(filename.clone()).into(), src.to_string()); + /// + /// // 2. You should create a code span for the code snippet. + /// let code_span = SpanData { + /// lo: new_byte_pos(22), + /// hi: new_byte_pos(42), + /// }.span(); + /// + /// // 3. You can create the `CodeSnippet` by the `SourceFile`, + /// // and render text "Line 2 Code Snippet.". + /// let code_snippet = CodeSnippet::new(code_span, Arc::new(sm)); + /// code_snippet.format(&mut sb, &mut errs); + /// ``` + #[inline] + pub fn new(code_span: Span, source_map: Arc) -> Self { + Self { + code_span, + source_map, + } + } +} + +impl Component for CodeSnippet { + fn format(&self, sb: &mut StyledBuffer, errs: &mut Vec) { + match self.source_map.span_to_lines(self.code_span) { + Ok(affected_lines) => { + match self + .source_map + .source_file_by_filename(&span_to_filename_string( + &self.code_span, + &self.source_map, + )) { + Some(sf) => { + // If the span cross multiple lines of code, + // only the first line of the code will be selected. + if let Some(line) = affected_lines.lines.first() { + let indent = (line.line_index + 1).to_string().len(); + self.format_file_info(sb, errs, &affected_lines.lines, indent); + StyledString::new( + format!("{: errs.push(ComponentFormatError::new( + "CodeSnippet", + "Failed to Load Source File", + )), + }; + } + Err(_) => errs.push(ComponentFormatError::new( + "CodeSnippet", + "Failed to Display Code Snippet Lines", + )), + }; + } +} + +impl CodeSnippet { + /// Format a code line in [`CodeSnippet`] into ' | ' + /// + /// : The line number of the first line of code in the code snippet. + /// : The src code. + /// + /// e.g. "12 | int a = 10;" + fn format_code_line( + &self, + sb: &mut StyledBuffer, + errs: &mut Vec, + line: &LineInfo, + indent: usize, + sf: &SourceFile, + ) { + // The line number shown in diagnostic should begin from 1. + // The `line.line_index` get from `SourceMap` begin from 0. + // So, the line number shown in diagnostic should be equal to line.line_index + 1. + let line_index = (line.line_index + 1).to_string(); + StyledString::new( + format!("{: ::'. + /// + /// : The full path of the span. + /// : The line number of the first line of code in the code snippet. + /// : The column number of the first line of code in the code snippet. + /// + /// e.g. "--> /User/test/file_name.file_extension:1:10" + fn format_file_info( + &self, + sb: &mut StyledBuffer, + errs: &mut Vec, + lines: &[LineInfo], + indent: usize, + ) { + let (first_line, first_col) = match lines.first() { + Some(line) => (line.line_index + 1, line.start_col.0 + 1), + None => { + errs.push(ComponentFormatError::new( + "CodeSnippet", + "Failed to Display Code Snippet.", + )); + (0, 0) + } + }; + StyledString::new( + format!("{:>indent$}{}", "", FILE_PATH_PREFIX), + Some(DiagnosticStyle::Url), + ) + .format(sb, errs); + + StyledString::new( + format!( + " {}:{}:{}\n", + span_to_filename_string(&self.code_span, &self.source_map), + first_line, + first_col + ), + Some(DiagnosticStyle::Url), + ) + .format(sb, errs); + } +} diff --git a/compiler_base/error/src/diagnostic/diagnostic_handler.rs b/compiler_base/error/src/diagnostic/diagnostic_handler.rs new file mode 100644 index 000000000..281f13e50 --- /dev/null +++ b/compiler_base/error/src/diagnostic/diagnostic_handler.rs @@ -0,0 +1,720 @@ +//! This crate provides `DiagnosticHandler` supports diagnostic messages to terminal stderr. +//! +//! `DiagnosticHandler` mainly consists of 4 parts: +//! - Emitter: Emit the styled string to terminal stderr. +//! - Template Loader: Load template files locally and find messages from file contents. +//! - A set for Diagnostics: All the diagnostic messages. +//! +//! For more information about diagnostic, see doc in "compiler_base/error/diagnostic/mod.rs". +//! For more information about emitter, see doc in "compiler_base/error/src/emitter.rs". +//! For more information about template loader, see doc in "compiler_base/error/src/diagnostic/diagnostic_message.rs". + +use crate::{ + diagnostic::diagnostic_message::TemplateLoader, emit_diagnostic_to_uncolored_text, Diagnostic, + DiagnosticStyle, Emitter, EmitterWriter, +}; +use anyhow::{bail, Context, Result}; +use compiler_base_span::fatal_error::FatalError; +use fluent::FluentArgs; +use std::{ + fmt::Debug, + path::PathBuf, + sync::{Arc, Mutex}, +}; + +// Default template resource file path. +const DEFAULT_TEMPLATE_RESOURCE: &str = "src/diagnostic/locales/en-US/"; +const DIAGNOSTIC_MESSAGES_ROOT: &str = env!("CARGO_MANIFEST_DIR"); + +/// `DiagnosticHandler` supports diagnostic messages to terminal stderr. +/// +/// `DiagnosticHandler` will load template file(*ftl) directory when instantiating through the constructor `new_with_template_dir()`. +/// "*.ftl" file looks like, e.g. './src/diagnostic/locales/en-US/default.ftl' : +/// ``` ignore +/// invalid-syntax = Invalid syntax +/// .expected = Expected one of `{$expected_items}` +/// ``` +/// There are two lines in './src/diagnostic/locales/en-US/default.ftl'. +/// - In line 1, `invalid-syntax` is a `index`, `Invalid syntax` is the `Message String` to this `index`. +/// - In line 2, `.expected` is another `index`, it is a `sub_index` of `invalid-syntax`. +/// - In line 2, `sub_index` must start with a point `.` and it is optional and can be more than one. +/// - In line 2, `Expected one of `{$expected_items}`` is the `Message String` to `.expected`. It is an interpolated string. +/// - In line 2, `{$expected_items}` is a `MessageArgs` of the `Expected one of `{$expected_items}`` +/// and `MessageArgs` can be recognized as a Key-Value entry, it is optional. +/// +/// The pattern of above '*.ftl' file looks like: +/// ``` ignore +/// <'index'> = <'message_string' with optional 'MessageArgs'> +/// = <'message_string' with optional 'MessageArgs'>* +/// ``` +/// +/// Note: `DiagnosticHandler` uses `Mutex` internally to ensure thread safety, +/// so you don't need to use references like `Arc` or `Mutex` to make `DiagnosticHandler` thread safe. +/// +/// When your compiler needs to use `Compiler-Base-Error` to displaying diagnostics, you need to create a `DiagnosticHandler` at first. +/// For more information about how to create a `DiagnosticHandler`, see the doc above method `new_with_template_dir()`. +/// Since creating `DiagnosticHandler` needs to load the locally template (*.ftl) file, it may cause I/O performance loss, +/// so we recommend you create `DiagnosticHandler` eagerly and globally in the compiler and pass references to other modules that use `DiagnosticHandler`. +/// +/// And since `DiagnosticHandler` provides methods that do not supports mutable references "&mut self", so passing immutable references (&) is enough. +/// +/// For Example: +/// +/// 1. You can put `DiagnosticHandler` on the same level as `Lexer`, `Parser` and `CodeGenerator` in your compiler. +/// ```ignore +/// struct Compiler { +/// diag_handler: DiagnosticHandler, +/// lang_lexer: Lexer, +/// lang_parser: Parser, +/// code_generator: CodeGenerator +/// } +/// ``` +/// +/// 2. And send the immutable references to `Lexer`, `Parser` and `CodeGenerator` to displaying the diagnostic during compiling. +/// ```ignore +/// impl Compiler { +/// fn compile(&self) { +/// self.lang_lexer.lex(&self.diag_handler); +/// self.lang_parser.parse(&self.diag_handler); +/// self.code_generator.gen(&self.diag_handler); +/// } +/// } +/// ``` +/// +/// ```ignore +/// impl Lexer { +/// fn lex(&self, diag_handler: &DiagnosticHandler){ +/// handler.XXXX(); // do something to diaplay diagnostic. +/// } +/// } +/// ``` +/// +pub struct DiagnosticHandler { + handler_inner: Mutex, +} + +impl Debug for DiagnosticHandler { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self.handler_inner.lock() { + Ok(inner) => { + write!(f, "{:?}", inner) + } + Err(_) => { + write!(f, "") + } + } + } +} + +impl DiagnosticHandler { + /// Create a `DiagnosticHandler` with no (*.ftl) template files. + /// Use this method if the diagnostic message does not need to be loaded from the template file (*.ftl). + pub fn default() -> Self { + Self { + handler_inner: Mutex::new(DiagnosticHandlerInner::default()), + } + } + + /// Load all (*.ftl) template files under default directory. + /// + /// Default directory "./src/diagnostic/locales/en-US/" + /// Call the constructor 'new_with_template_dir()' to load the file. + /// For more information about the constructor 'new_with_template_dir()', see the doc above 'new_with_template_dir()'. + /// + /// Note: This method has not been completed, and it may throw an error that the file path does not exist. + pub fn new_with_default_template_dir() -> Result { + let mut cargo_file_path = PathBuf::from(DIAGNOSTIC_MESSAGES_ROOT); + cargo_file_path.push(DEFAULT_TEMPLATE_RESOURCE); + let abs_path = cargo_file_path.to_str().with_context(|| { + format!("No such file or directory '{}'", DEFAULT_TEMPLATE_RESOURCE) + })?; + + DiagnosticHandler::new_with_template_dir(abs_path).with_context(|| { + format!( + "Failed to init `TemplateLoader` from '{}'", + DEFAULT_TEMPLATE_RESOURCE + ) + }) + } + + /// Load all (*.ftl) template files under directory `template_dir`. + /// `DiagnosticHandler` will load all the files end with "*.ftl" under the directory recursively. + /// If directory `template_dir` does not exist, this method will return an error. + /// + /// template_files + /// | + /// |---- template.ftl + /// |---- sub_template_files + /// | + /// |---- sub_template.ftl + /// + /// 'template.ftl' and 'sub_template.ftl' can both loaded by the `new_with_template_dir()`. + /// + /// # Examples + /// + /// ```rust + /// # use compiler_base_error::diagnostic_handler::DiagnosticHandler; + /// let diag_handler = DiagnosticHandler::new_with_template_dir("./src/diagnostic/locales/en-US/"); + /// match diag_handler { + /// Ok(_) => {} + /// Err(_) => {panic!("`diag_handler` should be Ok(...)")} + /// } + /// + /// // './src_invalid/diagnostic/locales/en-US/' does not exist. + /// let diag_handler_invalid = DiagnosticHandler::new_with_template_dir("./src_invalid/diagnostic/locales/en-US/"); + /// match diag_handler_invalid { + /// Ok(_) => {panic!("`diag_handler_invalid` should be Err(...)")} + /// Err(_) => {} + /// } + /// ``` + pub fn new_with_template_dir(template_dir: &str) -> Result { + let handler_inner = DiagnosticHandlerInner::new_with_template_dir(template_dir) + .with_context(|| format!("Failed to init `TemplateLoader` from '{}'", template_dir))?; + Ok(Self { + handler_inner: Mutex::new(handler_inner), + }) + } + + /// Add a diagnostic generated from error to `DiagnosticHandler`. + /// `DiagnosticHandler` contains a set of `Diagnostic` + /// + /// Note: `DiagnosticHandler` does not deduplicate diagnostics. + /// If you add two same diagnostics, you will see two same messages in the terminal. + /// + /// # Examples + /// + /// ```rust + /// # use compiler_base_error::DiagnosticStyle; + /// # use compiler_base_error::diagnostic_handler::DiagnosticHandler; + /// # use compiler_base_error::Diagnostic; + /// let diag_1 = Diagnostic::::new(); + /// let mut diag_handler = DiagnosticHandler::new_with_template_dir("./src/diagnostic/locales/en-US/").unwrap(); + /// assert_eq!(diag_handler.diagnostics_count().unwrap(), 0); + /// + /// diag_handler.add_err_diagnostic(diag_1); + /// assert_eq!(diag_handler.diagnostics_count().unwrap(), 1); + /// ``` + pub fn add_err_diagnostic(&self, diag: Diagnostic) -> Result<&Self> { + match self.handler_inner.lock() { + Ok(mut inner) => { + inner.add_err_diagnostic(diag); + Ok(self) + } + Err(_) => bail!("Add Error Diagnostic Failed."), + } + } + + /// Add a diagnostic generated from warning to `DiagnosticHandler`. + /// `DiagnosticHandler` contains a set of `Diagnostic` + /// + /// Note: `DiagnosticHandler` does not deduplicate diagnostics. + /// If you add two same diagnostics, you will see two same messages in the terminal. + /// + /// # Examples + /// + /// ```rust + /// # use compiler_base_error::DiagnosticStyle; + /// # use compiler_base_error::diagnostic_handler::DiagnosticHandler; + /// # use compiler_base_error::Diagnostic; + /// let diag_1 = Diagnostic::::new(); + /// let mut diag_handler = DiagnosticHandler::new_with_template_dir("./src/diagnostic/locales/en-US/").unwrap(); + /// assert_eq!(diag_handler.diagnostics_count().unwrap(), 0); + /// + /// diag_handler.add_warn_diagnostic(diag_1); + /// assert_eq!(diag_handler.diagnostics_count().unwrap(), 1); + /// ``` + pub fn add_warn_diagnostic(&self, diag: Diagnostic) -> Result<&Self> { + match self.handler_inner.lock() { + Ok(mut inner) => { + inner.add_warn_diagnostic(diag); + Ok(self) + } + Err(_) => bail!("Add Warn Diagnostic Failed."), + } + } + + /// Get count of diagnostics in `DiagnosticHandler`. + /// `DiagnosticHandler` contains a set of `Diagnostic` + /// + /// # Examples + /// + /// ```rust + /// # use compiler_base_error::DiagnosticStyle; + /// # use compiler_base_error::diagnostic_handler::DiagnosticHandler; + /// # use compiler_base_error::Diagnostic; + /// let diag_1 = Diagnostic::::new(); + /// let mut diag_handler = DiagnosticHandler::new_with_template_dir("./src/diagnostic/locales/en-US/").unwrap(); + /// assert_eq!(diag_handler.diagnostics_count().unwrap(), 0); + /// + /// diag_handler.add_warn_diagnostic(diag_1); + /// assert_eq!(diag_handler.diagnostics_count().unwrap(), 1); + /// ``` + pub fn diagnostics_count(&self) -> Result { + match self.handler_inner.lock() { + Ok(inner) => Ok(inner.diagnostics_count()), + Err(_) => bail!("Diagnostics Counts Failed."), + } + } + + /// Emit all the diagnostics into strings and return. + /// + /// # Examples + /// + /// ```rust + /// use compiler_base_error::DiagnosticStyle; + /// use compiler_base_error::diagnostic_handler::DiagnosticHandler; + /// use compiler_base_error::Diagnostic; + /// use compiler_base_error::components::Label; + /// + /// let mut diag_1 = Diagnostic::::new(); + /// diag_1.append_component(Box::new(Label::Note)); + /// + /// let mut diag_handler = DiagnosticHandler::default(); + /// + /// assert_eq!(diag_handler.diagnostics_count().unwrap(), 0); + /// + /// diag_handler.add_err_diagnostic(diag_1); + /// assert_eq!(diag_handler.diagnostics_count().unwrap(), 1); + /// assert_eq!(diag_handler.emit_all_diags_into_string().unwrap().get(0).unwrap().as_ref().unwrap(), "note"); + /// ``` + pub fn emit_all_diags_into_string(&self) -> Result>> { + match self.handler_inner.lock() { + Ok(inner) => Ok(inner.emit_all_diags_into_string()), + Err(_) => bail!("Emit Diagnostics Failed."), + } + } + + /// Emit the [`index`]th diagnostics into strings and return. + /// + /// # Examples + /// + /// ```rust + /// use compiler_base_error::DiagnosticStyle; + /// use compiler_base_error::diagnostic_handler::DiagnosticHandler; + /// use compiler_base_error::Diagnostic; + /// use compiler_base_error::components::Label; + /// + /// let mut diag_1 = Diagnostic::::new(); + /// diag_1.append_component(Box::new(Label::Note)); + /// + /// let mut diag_handler = DiagnosticHandler::default(); + /// + /// assert_eq!(diag_handler.diagnostics_count().unwrap(), 0); + /// + /// diag_handler.add_err_diagnostic(diag_1); + /// assert_eq!(diag_handler.diagnostics_count().unwrap(), 1); + /// assert_eq!(diag_handler.emit_nth_diag_into_string(0).unwrap().unwrap().unwrap(), "note"); + /// ``` + pub fn emit_nth_diag_into_string(&self, index: usize) -> Result>> { + match self.handler_inner.lock() { + Ok(inner) => Ok(inner.emit_nth_diag_into_string(index)), + Err(_) => bail!("Emit Diagnostics Failed."), + } + } + + /// Emit the diagnostic messages generated from error to to terminal stderr. + /// + /// # Examples + /// + /// ```rust + /// # use compiler_base_error::DiagnosticStyle; + /// # use compiler_base_error::diagnostic_handler::DiagnosticHandler; + /// # use compiler_base_error::Diagnostic; + /// let diag_1 = Diagnostic::::new(); + /// let mut diag_handler = DiagnosticHandler::new_with_template_dir("./src/diagnostic/locales/en-US/").unwrap(); + /// + /// assert_eq!(diag_handler.has_errors().unwrap(), false); + /// diag_handler.emit_error_diagnostic(diag_1); + /// assert_eq!(diag_handler.has_errors().unwrap(), true); + /// ``` + pub fn emit_error_diagnostic(&self, diag: Diagnostic) -> Result<&Self> { + match self.handler_inner.lock() { + Ok(mut inner) => { + inner + .emit_error_diagnostic(diag) + .with_context(|| ("Emit Error Diagnostics Failed."))?; + Ok(self) + } + Err(_) => bail!("Emit Error Diagnostics Failed."), + } + } + + /// Emit the diagnostic messages generated from warning to to terminal stderr. + /// + /// # Examples + /// + /// ```rust + /// # use compiler_base_error::DiagnosticStyle; + /// # use compiler_base_error::diagnostic_handler::DiagnosticHandler; + /// # use compiler_base_error::Diagnostic; + /// let diag_1 = Diagnostic::::new(); + /// let mut diag_handler = DiagnosticHandler::new_with_template_dir("./src/diagnostic/locales/en-US/").unwrap(); + /// + /// assert_eq!(diag_handler.has_warns().unwrap(), false); + /// diag_handler.emit_warn_diagnostic(diag_1); + /// assert_eq!(diag_handler.has_warns().unwrap(), true); + /// ``` + pub fn emit_warn_diagnostic(&self, diag: Diagnostic) -> Result<&Self> { + match self.handler_inner.lock() { + Ok(mut inner) => { + inner + .emit_warn_diagnostic(diag) + .with_context(|| ("Emit Warn Diagnostics Failed."))?; + Ok(self) + } + Err(_) => bail!("Emit Warn Diagnostics Failed."), + } + } + + /// Emit all the diagnostics messages to to terminal stderr. + /// `DiagnosticHandler` contains a set of `Diagnostic` + /// + /// # Examples + /// + /// ```rust + /// # use compiler_base_error::DiagnosticStyle; + /// # use compiler_base_error::diagnostic_handler::DiagnosticHandler; + /// # use compiler_base_error::Diagnostic; + /// let diag_1 = Diagnostic::::new(); + /// let diag_2 = Diagnostic::::new(); + /// let mut diag_handler = DiagnosticHandler::new_with_template_dir("./src/diagnostic/locales/en-US/").unwrap(); + /// + /// diag_handler.add_err_diagnostic(diag_1); + /// diag_handler.add_err_diagnostic(diag_2); + /// diag_handler.emit_stashed_diagnostics(); + /// ``` + pub fn emit_stashed_diagnostics(&self) -> Result<&Self> { + match self.handler_inner.lock() { + Ok(mut inner) => { + inner + .emit_stashed_diagnostics() + .with_context(|| ("Emit Stashed Diagnostics Failed."))?; + Ok(self) + } + Err(_) => bail!("Emit Stashed Diagnostics Failed."), + } + } + + /// If some diagnotsics generated by errors, `has_errors` returns `True`. + /// + /// # Examples + /// + /// ```rust + /// # use compiler_base_error::DiagnosticStyle; + /// # use compiler_base_error::diagnostic_handler::DiagnosticHandler; + /// # use compiler_base_error::Diagnostic; + /// let diag_1 = Diagnostic::::new(); + /// let mut diag_handler = DiagnosticHandler::new_with_template_dir("./src/diagnostic/locales/en-US/").unwrap(); + /// + /// assert_eq!(diag_handler.has_errors().unwrap(), false); + /// diag_handler.emit_error_diagnostic(diag_1); + /// assert_eq!(diag_handler.has_errors().unwrap(), true); + /// ``` + pub fn has_errors(&self) -> Result { + match self.handler_inner.lock() { + Ok(inner) => Ok(inner.has_errors()), + Err(_) => bail!("Check Has Errors Failed."), + } + } + + /// If some diagnotsics generated by warnings, `has_errors` returns `True`. + /// + /// # Examples + /// + /// ```rust + /// # use compiler_base_error::DiagnosticStyle; + /// # use compiler_base_error::diagnostic_handler::DiagnosticHandler; + /// # use compiler_base_error::Diagnostic; + /// let diag_1 = Diagnostic::::new(); + /// let mut diag_handler = DiagnosticHandler::new_with_template_dir("./src/diagnostic/locales/en-US/").unwrap(); + /// + /// assert_eq!(diag_handler.has_warns().unwrap(), false); + /// diag_handler.emit_warn_diagnostic(diag_1); + /// assert_eq!(diag_handler.has_warns().unwrap(), true); + /// ``` + pub fn has_warns(&self) -> Result { + match self.handler_inner.lock() { + Ok(inner) => Ok(inner.has_warns()), + Err(_) => bail!("Check Has Warns Failed."), + } + } + + /// After emitting all the diagnostics, it will panic. + /// + /// # Examples + /// + /// ```rust + /// # use compiler_base_error::DiagnosticStyle; + /// # use compiler_base_error::Diagnostic; + /// # use compiler_base_error::diagnostic_handler::DiagnosticHandler; + /// # use std::panic; + /// let diag_handler = DiagnosticHandler::new_with_template_dir("./src/diagnostic/locales/en-US/").unwrap(); + /// + /// diag_handler.abort_if_errors().unwrap(); + /// diag_handler.add_warn_diagnostic(Diagnostic::::new()).unwrap(); + /// + /// diag_handler.abort_if_errors().unwrap(); + /// diag_handler.add_err_diagnostic(Diagnostic::::new()).unwrap(); + /// + /// let result = panic::catch_unwind(|| { + /// diag_handler.abort_if_errors().unwrap(); + /// }); + /// assert!(result.is_err()); + /// ``` + pub fn abort_if_errors(&self) -> Result<&Self> { + match self.handler_inner.lock() { + Ok(mut inner) => { + inner + .abort_if_errors() + .with_context(|| ("Abort If Errors Failed."))?; + Ok(self) + } + Err(_) => bail!("Abort If Errors Failed."), + } + } + + /// Get the message string from "*.ftl" file by `index`, `sub_index` and `MessageArgs`. + /// And for the 'default.ftl' shown above, you can get messages as follow: + /// + /// ```ignore + /// invalid-syntax = Invalid syntax + /// .expected = Expected one of `{$expected_items}` + /// ``` + /// + /// 1. If you want the message 'Invalid syntax' in line 1. + /// + /// ``` rust + /// # use compiler_base_error::diagnostic_handler::MessageArgs; + /// # use compiler_base_error::diagnostic_handler::DiagnosticHandler; + /// + /// // 1. Prepare an empty `MessageArgs`, Message in line 1 is not an interpolated string. + /// let no_args = MessageArgs::new(); + /// + /// // 2. `index` is 'invalid-syntax' and has no `sub_index`. + /// let index = "invalid-syntax"; + /// let sub_index = None; + /// + /// // 3. Create the `DiagnosticHandler` with template (*.ftl) files directory. + /// let diag_handler = DiagnosticHandler::new_with_template_dir("./src/diagnostic/locales/en-US/").unwrap(); + /// + /// // 4. Get the message. + /// let msg_in_line_1 = diag_handler.get_diagnostic_msg(index, sub_index, &no_args).unwrap(); + /// + /// assert_eq!(msg_in_line_1, "Invalid syntax"); + /// ``` + /// + /// 2. If you want the message 'Expected one of `{$expected_items}`' in line 2. + /// + /// ``` rust + /// # use compiler_base_error::diagnostic_handler::MessageArgs; + /// # use compiler_base_error::diagnostic_handler::DiagnosticHandler; + /// + /// // 1. Prepare the `MessageArgs` for `{$expected_items}`. + /// let mut args = MessageArgs::new(); + /// args.set("expected_items", "I am an expected item"); + /// + /// // 2. `index` is 'invalid-syntax'. + /// let index = "invalid-syntax"; + /// + /// // 3. `sub_index` is 'expected'. + /// let sub_index = "expected"; + /// + /// // 4. Create the `DiagnosticHandler` with template (*.ftl) files directory. + /// let diag_handler = DiagnosticHandler::new_with_template_dir("./src/diagnostic/locales/en-US/").unwrap(); + /// + /// // 5. Get the message. + /// let msg_in_line_2 = diag_handler.get_diagnostic_msg(index, Some(sub_index), &args).unwrap(); + /// + /// assert_eq!(msg_in_line_2, "Expected one of `\u{2068}I am an expected item\u{2069}`"); + /// ``` + pub fn get_diagnostic_msg( + &self, + index: &str, + sub_index: Option<&str>, + args: &MessageArgs, + ) -> Result { + match self.handler_inner.lock() { + Ok(inner) => inner.get_diagnostic_msg(index, sub_index, args), + Err(_) => bail!("Find Diagnostic Message Failed."), + } + } +} + +/// `MessageArgs` is the arguments of the interpolated string. +/// +/// `MessageArgs` is a Key-Value entry which only supports "set" and without "get". +/// You need getting nothing from `MessageArgs`. Only setting it and senting it to `DiagnosticHandler` is enough. +/// +/// Note: Currently both `Key` and `Value` of `MessageArgs` types only support string (&str). +/// +/// # Examples +/// +/// ``` rust +/// # use compiler_base_error::diagnostic_handler::DiagnosticHandler; +/// # use compiler_base_error::diagnostic_handler::MessageArgs; +/// +/// let index = "invalid-syntax"; +/// let sub_index = Some("expected"); +/// let mut msg_args = MessageArgs::new(); +/// // You only need "set()". +/// msg_args.set("This is Key", "This is Value"); +/// +/// // Create the `DiagnosticHandler` with template (*.ftl) files directory. +/// let diag_handler = DiagnosticHandler::new_with_template_dir("./src/diagnostic/locales/en-US/").unwrap(); +/// +/// // When you use it, just sent it to `DiagnosticHandler`. +/// let msg_in_line_1 = diag_handler.get_diagnostic_msg(index, sub_index, &msg_args); +/// ``` +/// +/// For more information about the `DiagnosticHandler` see the doc above struct `DiagnosticHandler`. +#[derive(Default)] +pub struct MessageArgs<'a>(pub(crate) FluentArgs<'a>); +impl<'a> MessageArgs<'a> { + pub fn new() -> Self { + Self(FluentArgs::new()) + } + + pub fn set(&mut self, k: &'a str, v: &'a str) { + self.0.set(k, v); + } +} + +pub(crate) struct DiagnosticHandlerInner { + emitter: Box>, + diagnostics: Vec>, + err_count: usize, + warn_count: usize, + template_loader: Arc, +} + +impl Debug for DiagnosticHandlerInner { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let mut diag_fmt = String::new(); + for diag in &self.diagnostics { + diag_fmt.push_str(&format!("{:?}", diag)); + } + write!(f, "{}", diag_fmt) + } +} + +impl DiagnosticHandlerInner { + pub(crate) fn default() -> Self { + Self { + err_count: 0, + warn_count: 0, + emitter: Box::new(EmitterWriter::default()), + diagnostics: vec![], + template_loader: Arc::new(TemplateLoader::default()), + } + } + + /// Load all (*.ftl) template files under directory `template_dir`. + pub(crate) fn new_with_template_dir(template_dir: &str) -> Result { + let template_loader = TemplateLoader::new_with_template_dir(template_dir) + .with_context(|| format!("Failed to init `TemplateLoader` from '{}'", template_dir))?; + + Ok(Self { + err_count: 0, + warn_count: 0, + emitter: Box::new(EmitterWriter::default()), + diagnostics: vec![], + template_loader: Arc::new(template_loader), + }) + } + + /// Add a diagnostic generated from error to `DiagnosticHandler`. + /// `DiagnosticHandler` contains a set of `Diagnostic` + pub(crate) fn add_err_diagnostic(&mut self, diag: Diagnostic) { + self.diagnostics.push(diag); + self.err_count += 1; + } + + /// Add a diagnostic generated from warning to `DiagnosticHandler`. + /// `DiagnosticHandler` contains a set of `Diagnostic` + pub(crate) fn add_warn_diagnostic(&mut self, diag: Diagnostic) { + self.diagnostics.push(diag); + self.warn_count += 1; + } + + /// Get count of diagnostics in `DiagnosticHandler`. + /// `DiagnosticHandler` contains a set of `Diagnostic` + #[inline] + pub(crate) fn diagnostics_count(&self) -> usize { + self.diagnostics.len() + } + + /// Emit all the diagnostics into strings and return. + pub(crate) fn emit_all_diags_into_string(&self) -> Vec> { + self.diagnostics + .iter() + .map(|d| Ok(emit_diagnostic_to_uncolored_text(d)?)) + .collect() + } + + /// Emit the [`index`]th diagnostic into string and return. + pub(crate) fn emit_nth_diag_into_string(&self, index: usize) -> Option> { + self.diagnostics + .get(index) + .map(|d| emit_diagnostic_to_uncolored_text(d)) + } + + /// Emit the diagnostic messages generated from error to to terminal stderr. + pub(crate) fn emit_error_diagnostic( + &mut self, + diag: Diagnostic, + ) -> Result<()> { + self.emitter.emit_diagnostic(&diag)?; + self.err_count += 1; + Ok(()) + } + + /// Emit the diagnostic messages generated from warning to to terminal stderr. + pub(crate) fn emit_warn_diagnostic(&mut self, diag: Diagnostic) -> Result<()> { + self.emitter.emit_diagnostic(&diag)?; + self.warn_count += 1; + Ok(()) + } + + /// Emit all the diagnostics messages to to terminal stderr. + /// `DiagnosticHandler` contains a set of `Diagnostic` + pub(crate) fn emit_stashed_diagnostics(&mut self) -> Result<()> { + for diag in &self.diagnostics { + self.emitter.emit_diagnostic(diag)? + } + Ok(()) + } + + /// If some diagnotsics generated by errors, `has_errors` returns `True`. + #[inline] + pub(crate) fn has_errors(&self) -> bool { + self.err_count > 0 + } + + /// If some diagnotsics generated by warnings, `has_errors` returns `True`. + #[inline] + pub(crate) fn has_warns(&self) -> bool { + self.warn_count > 0 + } + + /// After emitting all the diagnostics, it will panic. + pub(crate) fn abort_if_errors(&mut self) -> Result<()> { + self.emit_stashed_diagnostics()?; + + if self.has_errors() { + FatalError.raise(); + } + + Ok(()) + } + + /// Get the message string from "*.ftl" file by `index`, `sub_index` and `MessageArgs`. + /// "*.ftl" file looks like, e.g. './src/diagnostic/locales/en-US/default.ftl' : + pub(crate) fn get_diagnostic_msg( + &self, + index: &str, + sub_index: Option<&str>, + args: &MessageArgs, + ) -> Result { + self.template_loader.get_msg_to_str(index, sub_index, args) + } +} diff --git a/compiler_base/error/src/diagnostic/diagnostic_message.rs b/compiler_base/error/src/diagnostic/diagnostic_message.rs new file mode 100644 index 000000000..2bdd917f3 --- /dev/null +++ b/compiler_base/error/src/diagnostic/diagnostic_message.rs @@ -0,0 +1,138 @@ +//! The crate provides `TemplateLoader` to load the diagnositc message displayed in diagnostics from "*.ftl" files, +//! `TemplateLoader` relies on 'fluent0.16.0' to support loading diagnositc message from "*.ftl" files. +//! +//! 'fluent0.16.0' is used to support diagnostic text template. +//! For more information about 'fluent0.16.0', see https://projectfluent.org/. + +use anyhow::{bail, Context, Result}; +use fluent::{FluentBundle, FluentResource}; +use std::{fs, sync::Arc}; +use unic_langid::langid; +use walkdir::{DirEntry, WalkDir}; + +use crate::diagnostic_handler::MessageArgs; +/// Struct `TemplateLoader` load template contents from "*.ftl" file. +/// `TemplateLoader` will operate on files locally. +pub(crate) struct TemplateLoader { + template_inner: Arc, +} + +impl TemplateLoader { + /// Create an empty TemplateLoader that does not load any template files(*.ftl). + pub(crate) fn default() -> Self { + Self { + template_inner: Arc::new(TemplateLoaderInner::default()), + } + } + + /// Create the `TemplateLoader` with template (*.ftl) files directory. + /// `TemplateLoader` will load all the files end with "*.ftl" under the directory recursively. + /// template_files + /// | + /// |---- template.ftl + /// |---- sub_template_files + /// | + /// |---- sub_template.ftl + /// + /// 'template.ftl' and 'sub_template.ftl' can both loaded by the `new_with_template_dir()`. + pub(crate) fn new_with_template_dir(template_dir: &str) -> Result { + let template_inner = TemplateLoaderInner::new_with_template_dir(template_dir) + .with_context(|| format!("Failed to load '*.ftl' from '{}'", template_dir))?; + Ok(Self { + template_inner: Arc::new(template_inner), + }) + } + + /// Get the message string from "*.ftl" file by `index`, `sub_index` and `MessageArgs`. + /// For more information about "*.ftl" file, see the doc above `DiagnosticHandler`. + /// "*.ftl" file looks like, e.g. './src/diagnostic/locales/en-US/default.ftl' : + pub(crate) fn get_msg_to_str( + &self, + index: &str, + sub_index: Option<&str>, + args: &MessageArgs, + ) -> Result { + let msg = match self.template_inner.get_template_bunder().get_message(index) { + Some(m) => m, + None => bail!("Message doesn't exist."), + }; + + let pattern = match sub_index { + Some(s_id) => { + let attr = msg.get_attribute(s_id).unwrap(); + attr.value() + } + None => match msg.value() { + Some(v) => v, + None => bail!("Message has no value."), + }, + }; + + let MessageArgs(args) = args; + let value = self.template_inner.get_template_bunder().format_pattern( + pattern, + Some(args), + &mut vec![], + ); + Ok(value.to_string()) + } +} + +/// `TemplateLoaderInner` is used to privatize the default constructor of `TemplateLoader`. +struct TemplateLoaderInner { + template_bunder: FluentBundle, +} + +impl TemplateLoaderInner { + fn default() -> Self { + Self { + template_bunder: FluentBundle::default(), + } + } + + fn new_with_template_dir(template_dir: &str) -> Result { + let mut template_bunder = FluentBundle::new(vec![langid!("en-US")]); + load_all_templates_in_dir_to_resources(template_dir, &mut template_bunder) + .with_context(|| format!("Failed to load '*.ftl' from '{}'", template_dir))?; + Ok(Self { template_bunder }) + } + + fn get_template_bunder(&self) -> &FluentBundle { + &self.template_bunder + } +} + +fn is_ftl_file(entry: &DirEntry) -> bool { + entry + .file_name() + .to_str() + .map(|s| s.ends_with(".ftl")) + .unwrap_or(false) +} + +fn load_all_templates_in_dir_to_resources( + dir: &str, + fluent_bundle: &mut FluentBundle, +) -> Result<()> { + if !std::path::Path::new(&dir).exists() { + bail!("Failed to load '*.ftl' dir"); + } + + for entry in WalkDir::new(dir) { + let entry = entry?; + + if is_ftl_file(&entry) { + let resource = fs::read_to_string(entry.path())?; + + match FluentResource::try_new(resource) { + Ok(s) => { + if fluent_bundle.add_resource(s).is_err() { + bail!("Failed to parse an FTL string.") + } + } + Err(_) => bail!("Failed to add FTL resources to the bundle."), + }; + } + } + Ok(()) +} diff --git a/compiler_base/error/src/diagnostic/locales/en-US/default.ftl b/compiler_base/error/src/diagnostic/locales/en-US/default.ftl new file mode 100644 index 000000000..67e493db8 --- /dev/null +++ b/compiler_base/error/src/diagnostic/locales/en-US/default.ftl @@ -0,0 +1,3 @@ +invalid-syntax = + Invalid syntax + .expected = Expected one of `{$expected_items}` diff --git a/compiler_base/error/src/diagnostic/locales/en-US/test/default1.ftl b/compiler_base/error/src/diagnostic/locales/en-US/test/default1.ftl new file mode 100644 index 000000000..4290d805b --- /dev/null +++ b/compiler_base/error/src/diagnostic/locales/en-US/test/default1.ftl @@ -0,0 +1,3 @@ +invalid-syntax-1 = + Invalid syntax 1 + .expected_1 = Expected one of `{$expected_items}` 1 diff --git a/compiler_base/error/src/diagnostic/mod.rs b/compiler_base/error/src/diagnostic/mod.rs new file mode 100644 index 000000000..5191e133d --- /dev/null +++ b/compiler_base/error/src/diagnostic/mod.rs @@ -0,0 +1,176 @@ +use crate::errors::ComponentFormatError; +pub use rustc_errors::styled_buffer::{StyledBuffer, StyledString}; +use rustc_errors::Style; +use std::fmt::Debug; + +pub mod components; +pub mod diagnostic_handler; +pub mod diagnostic_message; +pub mod style; + +#[cfg(test)] +mod tests; + +/// 'Component' specifies the method `format()` that all diagnostic components should implement. +/// +/// 'Component' decouples 'structure' and 'theme' during formatting diagnostic components. +/// `T: Clone + PartialEq + Eq + Style` is responsible for 'theme' such as colors/fonts in the component formatting. +/// `format()` organizes the 'structure' of diagnostic components. +pub trait Component +where + T: Clone + PartialEq + Eq + Style, +{ + /// `format()` formats components into `StyledString` and saves them in `StyledBuffer`. + /// + /// # Examples + /// + /// ```rust + /// # use compiler_base_error::errors::ComponentFormatError; + /// # use compiler_base_error::Component; + /// # use compiler_base_error::DiagnosticStyle; + /// # use rustc_errors::styled_buffer::StyledBuffer; + /// + /// struct ComponentWithStyleLogo { + /// text: String + /// } + /// + /// impl Component for ComponentWithStyleLogo { + /// fn format(&self, sb: &mut StyledBuffer, errs: &mut Vec) { + /// // set style + /// sb.pushs(&self.text, Some(DiagnosticStyle::Logo)); + /// } + /// } + /// + /// ``` + fn format(&self, sb: &mut StyledBuffer, errs: &mut Vec); +} + +/// `Diagnostic` is a collection of various components, +/// and any data structure that implements `Component` can be a part of `Diagnostic`. +/// +/// # Examples +/// +/// ```rust +/// # use rustc_errors::styled_buffer::StyledBuffer; +/// # use compiler_base_error::components::Label; +/// # use compiler_base_error::DiagnosticStyle; +/// # use compiler_base_error::Diagnostic; +/// # use compiler_base_error::Component; +/// +/// // If you want a diagnostic message “error[E3033]: this is an error!”. +/// let mut diagnostic = Diagnostic::new(); +/// +/// // First, create a label component wrapped by `Box<>` +/// let err_label = Box::new(Label::Error("E3033".to_string())); +/// +/// // Second, add the label component to `Diagnostic`. +/// diagnostic.append_component(err_label); +/// +/// // Then, create a string component wrapped by `Box<>`. +/// let msg = Box::new(": this is an error!".to_string()); +/// +/// // And add it to `Diagnostic`. +/// diagnostic.append_component(msg); +/// +/// // Create a `Styledbuffer` to get the result. +/// let mut sb = StyledBuffer::::new(); +/// +/// // Create an error set for collecting errors. +/// let mut errs = vec![]; +/// +/// // Rendering ! +/// diagnostic.format(&mut sb, &mut errs); +/// let result = sb.render(); +/// +/// // “error[E3033]: this is an error!” is only one line. +/// assert_eq!(result.len(), 1); +/// +/// // “error[E3033]: this is an error!” has three different style snippets. +/// +/// // "error" - DiagnosticStyle::NeedFix +/// // "[E3033]" - DiagnosticStyle::Helpful +/// // ": this is an error!" - None +/// +/// // `DiagnosticStyle` can be rendered into different text colors and formats when diaplaying. +/// +/// assert_eq!(result.get(0).unwrap().len(), 3); +/// assert_eq!(result.get(0).unwrap().get(0).unwrap().text, "error"); +/// assert_eq!(result.get(0).unwrap().get(1).unwrap().text, "[E3033]"); +/// assert_eq!(result.get(0).unwrap().get(2).unwrap().text, ": this is an error!"); +/// +/// assert_eq!(result.get(0).unwrap().get(0).unwrap().style, Some(DiagnosticStyle::NeedFix)); +/// assert_eq!(result.get(0).unwrap().get(1).unwrap().style, Some(DiagnosticStyle::Helpful)); +/// assert_eq!(result.get(0).unwrap().get(2).unwrap().style, None); +/// ``` +#[derive(Default)] +pub struct Diagnostic +where + T: Clone + PartialEq + Eq + Style + Debug, +{ + components: Vec>>, +} + +impl Debug for Diagnostic +where + T: Clone + PartialEq + Eq + Style + Debug, +{ + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let mut diag_fmt = String::new(); + for component in &self.components { + let mut s_sb = StyledBuffer::::new(); + let mut s_errs = vec![]; + component.format(&mut s_sb, &mut s_errs); + diag_fmt.push_str(&format!("{:?}\n", s_sb.render())); + } + write!(f, "{}", diag_fmt) + } +} + +impl PartialEq for Diagnostic +where + T: Clone + PartialEq + Eq + Style + Debug, +{ + fn eq(&self, other: &Self) -> bool { + format!("{:?}", self) == format!("{:?}", other) + } +} + +impl Diagnostic +where + T: Clone + PartialEq + Eq + Style + Debug, +{ + pub fn new() -> Self { + Diagnostic { components: vec![] } + } + + pub fn append_component(&mut self, component: Box>) { + self.components.push(component); + } + + pub fn prepend_component(&mut self, component: Box>) { + self.components.insert(0, component); + } +} + +impl Component for Diagnostic +where + T: Clone + PartialEq + Eq + Style + Debug, +{ + fn format(&self, sb: &mut StyledBuffer, errs: &mut Vec) { + for component in &self.components { + component.format(sb, errs); + } + } +} + +/// `String` can be considered as a component of diagnostic with no style. +/// +/// The result of component `String` rendering is a `String` who has no style. +impl Component for String +where + T: Clone + PartialEq + Eq + Style + Debug, +{ + fn format(&self, sb: &mut StyledBuffer, _: &mut Vec) { + sb.appendl(self, None); + } +} diff --git a/compiler_base/error/src/diagnostic/style.rs b/compiler_base/error/src/diagnostic/style.rs new file mode 100644 index 000000000..5ed58af43 --- /dev/null +++ b/compiler_base/error/src/diagnostic/style.rs @@ -0,0 +1,118 @@ +//! 'style.rs' defines all styles that needed in compiler_base_error. +use rustc_errors::Style; +use termcolor::{Color, ColorSpec}; + +/// 'DiagnosticStyle' defines all the styles that needed when displaying diagnostic message. +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum DiagnosticStyle { + Logo, + NeedFix, + NeedAttention, + Helpful, + Important, + Url, +} + +impl Style for DiagnosticStyle { + fn render_style_to_color_spec(&self) -> ColorSpec { + let mut spec = ColorSpec::new(); + match self { + DiagnosticStyle::Logo => {} + DiagnosticStyle::NeedFix => { + spec.set_fg(Some(Color::Red)) + .set_intense(true) + .set_bold(true); + } + DiagnosticStyle::NeedAttention => { + spec.set_fg(Some(Color::Yellow)) + .set_intense(true) + .set_bold(true); + } + DiagnosticStyle::Helpful => { + spec.set_fg(Some(Color::Green)) + .set_intense(true) + .set_bold(true); + } + DiagnosticStyle::Important => { + spec.set_fg(Some(Color::Cyan)) + .set_intense(true) + .set_bold(true); + } + DiagnosticStyle::Url => { + spec.set_fg(Some(Color::Blue)) + .set_intense(true) + .set_bold(true); + } + } + spec + } +} + +impl DiagnosticStyle { + /// Check if a `ColorSpec` is corresponding to the `DiagnosticStyle`. + /// + /// # Examples + /// + /// ```rust + /// # use rustc_errors::Style; + /// # use compiler_base_error::DiagnosticStyle; + /// + /// let mut color_spec = DiagnosticStyle::NeedFix.render_style_to_color_spec(); + /// assert!(DiagnosticStyle::NeedFix.check_is_expected_colorspec(&color_spec)); + /// + /// color_spec.set_bold(false); + /// assert!(!DiagnosticStyle::NeedFix.check_is_expected_colorspec(&color_spec)); + /// ``` + pub fn check_is_expected_colorspec(&self, spec: &ColorSpec) -> bool { + match self { + DiagnosticStyle::Logo => true, + DiagnosticStyle::NeedFix => { + spec.fg() == Some(&Color::Red) && spec.intense() && spec.bold() + } + DiagnosticStyle::NeedAttention => { + spec.fg() == Some(&Color::Yellow) && spec.intense() && spec.bold() + } + DiagnosticStyle::Helpful => { + spec.fg() == Some(&Color::Green) && spec.intense() && spec.bold() + } + DiagnosticStyle::Important => { + spec.fg() == Some(&Color::Cyan) && spec.intense() && spec.bold() + } + DiagnosticStyle::Url => { + spec.fg() == Some(&Color::Blue) && spec.intense() && spec.bold() + } + } + } +} + +#[cfg(test)] +mod tests { + mod test_style { + use crate::diagnostic::style::DiagnosticStyle; + use rustc_errors::Style; + + #[test] + fn test_render_style_to_color_spec() { + let color_spec = DiagnosticStyle::NeedFix.render_style_to_color_spec(); + assert!(DiagnosticStyle::NeedFix.check_is_expected_colorspec(&color_spec)); + + let color_spec = DiagnosticStyle::NeedAttention.render_style_to_color_spec(); + assert!(DiagnosticStyle::NeedAttention.check_is_expected_colorspec(&color_spec)); + + let color_spec = DiagnosticStyle::Helpful.render_style_to_color_spec(); + assert!(DiagnosticStyle::Helpful.check_is_expected_colorspec(&color_spec)); + + let color_spec = DiagnosticStyle::Important.render_style_to_color_spec(); + assert!(DiagnosticStyle::Important.check_is_expected_colorspec(&color_spec)); + + let color_spec = DiagnosticStyle::Logo.render_style_to_color_spec(); + assert!(DiagnosticStyle::Logo.check_is_expected_colorspec(&color_spec)); + + let mut color_spec = DiagnosticStyle::Url.render_style_to_color_spec(); + assert!(DiagnosticStyle::Url.check_is_expected_colorspec(&color_spec)); + + color_spec.set_bold(false); + assert!(!DiagnosticStyle::Url.check_is_expected_colorspec(&color_spec)); + } + } +} diff --git a/compiler_base/error/src/diagnostic/test_datas/code_snippet b/compiler_base/error/src/diagnostic/test_datas/code_snippet new file mode 100644 index 000000000..af4753b0b --- /dev/null +++ b/compiler_base/error/src/diagnostic/test_datas/code_snippet @@ -0,0 +1,16 @@ +Line 1 Code Snippet. +Line 2 Code Snippet. +Line 3 Code Snippet. +Line 4 Code Snippet. +Line 5 Code Snippet. +Line 6 Code Snippet. +Line 7 Code Snippet. +Line 8 Code Snippet. +Line 9 Code Snippet. +Line 10 Code Snippet. +Line 11 Code Snippet. +Line 12 Code Snippet. +Line 13 Code Snippet. +Line 14 Code Snippet. +Line 15 Code Snippet. +Line 16 Code Snippet. diff --git a/compiler_base/error/src/diagnostic/tests.rs b/compiler_base/error/src/diagnostic/tests.rs new file mode 100644 index 000000000..ce721a38e --- /dev/null +++ b/compiler_base/error/src/diagnostic/tests.rs @@ -0,0 +1,415 @@ +mod test_diagnostic { + use crate::diagnostic::{components::Label, style::DiagnosticStyle, Component, Diagnostic}; + use rustc_errors::styled_buffer::StyledBuffer; + + #[test] + fn test_diagnostic_with_label() { + let mut diagnostic = Diagnostic::new(); + + let err_label = Box::new(Label::Error("E3033".to_string())); + diagnostic.append_component(err_label); + + let msg = Box::new(": this is an error!".to_string()); + diagnostic.append_component(msg); + + let mut sb = StyledBuffer::::new(); + + let mut errs = vec![]; + diagnostic.format(&mut sb, &mut errs); + let result = sb.render(); + + assert_eq!(result.len(), 1); + assert_eq!(result.get(0).unwrap().len(), 3); + assert_eq!(result.get(0).unwrap().get(0).unwrap().text, "error"); + assert_eq!(result.get(0).unwrap().get(1).unwrap().text, "[E3033]"); + assert_eq!( + result.get(0).unwrap().get(2).unwrap().text, + ": this is an error!" + ); + + assert_eq!( + result.get(0).unwrap().get(0).unwrap().style, + Some(DiagnosticStyle::NeedFix) + ); + assert_eq!( + result.get(0).unwrap().get(1).unwrap().style, + Some(DiagnosticStyle::Helpful) + ); + assert_eq!(result.get(0).unwrap().get(2).unwrap().style, None); + } + + #[test] + fn test_diagnsotic_fmt() { + let mut diag_1 = Diagnostic::::new(); + let err_label_1 = Box::new(Label::Error("E3033".to_string())); + diag_1.append_component(err_label_1); + + assert_eq!(format!("{:?}", diag_1), "[[StyledString { text: \"error\", style: Some(NeedFix) }, StyledString { text: \"[E3033]\", style: Some(Helpful) }]]\n"); + } + + #[test] + fn test_diagnostic_equal() { + let mut diag_1 = Diagnostic::::new(); + let err_label_1 = Box::new(Label::Error("E3033".to_string())); + diag_1.append_component(err_label_1); + + let msg_1 = Box::new(": this is an error!".to_string()); + diag_1.append_component(msg_1); + + let mut diag_2 = Diagnostic::::new(); + let err_label_2 = Box::new(Label::Error("E3033".to_string())); + diag_2.append_component(err_label_2); + + let msg_2 = Box::new(": this is another error!".to_string()); + diag_2.append_component(msg_2); + + assert_ne!(diag_1, diag_2); + + let mut diag_3 = Diagnostic::::new(); + let err_label_3 = Box::new(Label::Error("E3033".to_string())); + diag_3.append_component(err_label_3); + let msg_3 = Box::new(": this is another error!".to_string()); + diag_3.append_component(msg_3); + + assert_eq!(diag_2, diag_3); + } +} + +mod test_components { + + use std::{fs, path::PathBuf, sync::Arc}; + + use crate::{ + components::CodeSnippet, + diagnostic::{components::Label, style::DiagnosticStyle, Component}, + emit_diagnostic_to_uncolored_text, Diagnostic, + }; + use compiler_base_span::{span::new_byte_pos, FilePathMapping, SourceMap, Span, SpanData}; + use pretty_assertions::assert_eq; + use rustc_errors::styled_buffer::{StyledBuffer, StyledString}; + + #[test] + fn test_label() { + let mut sb = StyledBuffer::::new(); + let mut errs = vec![]; + Label::Error("E3030".to_string()).format(&mut sb, &mut errs); + Label::Warning("W3030".to_string()).format(&mut sb, &mut errs); + Label::Note.format(&mut sb, &mut errs); + Label::Help.format(&mut sb, &mut errs); + let result = sb.render(); + assert_eq!(errs.len(), 0); + assert_eq!(result.len(), 1); + assert_eq!(result.get(0).unwrap().len(), 6); + assert_eq!(result.get(0).unwrap().get(0).unwrap().text, "error"); + assert_eq!(result.get(0).unwrap().get(1).unwrap().text, "[E3030]"); + assert_eq!(result.get(0).unwrap().get(2).unwrap().text, "warning"); + assert_eq!(result.get(0).unwrap().get(3).unwrap().text, "[W3030]"); + assert_eq!(result.get(0).unwrap().get(4).unwrap().text, "note"); + assert_eq!(result.get(0).unwrap().get(5).unwrap().text, "help"); + } + + #[test] + fn test_string() { + let mut sb = StyledBuffer::::new(); + let mut errs = vec![]; + "this is a component string" + .to_string() + .format(&mut sb, &mut errs); + let result = sb.render(); + assert_eq!(errs.len(), 0); + assert_eq!(result.len(), 1); + assert_eq!(result.get(0).unwrap().len(), 1); + assert_eq!( + result.get(0).unwrap().get(0).unwrap().text, + "this is a component string" + ); + assert_eq!(result.get(0).unwrap().get(0).unwrap().style, None); + } + + #[test] + fn test_string_with_style() { + let mut sb = StyledBuffer::::new(); + let mut errs = vec![]; + StyledString::::new( + "This is a string with NeedFix style".to_string(), + Some(DiagnosticStyle::NeedFix), + ) + .format(&mut sb, &mut errs); + let result = sb.render(); + assert_eq!(errs.len(), 0); + assert_eq!(result.len(), 1); + assert_eq!(result.get(0).unwrap().len(), 1); + assert_eq!( + result.get(0).unwrap().get(0).unwrap().text, + "This is a string with NeedFix style" + ); + assert_eq!( + result.get(0).unwrap().get(0).unwrap().style.unwrap(), + DiagnosticStyle::NeedFix + ); + + StyledString::::new("This is a string with no style".to_string(), None) + .format(&mut sb, &mut errs); + let result = sb.render(); + assert_eq!(errs.len(), 0); + assert_eq!(result.len(), 1); + assert_eq!(result.get(0).unwrap().len(), 2); + assert_eq!( + result.get(0).unwrap().get(1).unwrap().text, + "This is a string with no style" + ); + assert_eq!(result.get(0).unwrap().get(1).unwrap().style, None); + } + + fn gen_diag_with_code_snippet(filename: String, sp: Span) -> Diagnostic { + let filename = fs::canonicalize(&PathBuf::from(filename)) + .unwrap() + .display() + .to_string(); + + let src = std::fs::read_to_string(filename.clone()).unwrap(); + let sm = SourceMap::new(FilePathMapping::empty()); + sm.new_source_file(PathBuf::from(filename.clone()).into(), src); + + let code_snippet = CodeSnippet::new(sp, Arc::new(sm)); + let mut diag = Diagnostic::new(); + diag.append_component(Box::new(code_snippet)); + diag + } + + #[test] + fn test_code_snippet() { + let code_span = SpanData { + lo: new_byte_pos(0), + hi: new_byte_pos(5), + } + .span(); + let filename = "./src/diagnostic/test_datas/code_snippet".to_string(); + let diag = gen_diag_with_code_snippet(filename.clone(), code_span); + + let expected = format!( + r#" + --> {}:1:1 + | +1 | Line 1 Code Snippet. + | ^^^^^ +"#, + PathBuf::from(filename) + .canonicalize() + .unwrap() + .display() + .to_string() + ); + assert_eq!( + format!("\n{}\n", emit_diagnostic_to_uncolored_text(&diag).unwrap()), + expected + ); + } + + #[test] + fn test_code_snippet_with_larger_line_index() { + let code_span = SpanData { + lo: new_byte_pos(216), + hi: new_byte_pos(220), + } + .span(); + let filename = "./src/diagnostic/test_datas/code_snippet".to_string(); + let diag = gen_diag_with_code_snippet(filename.clone(), code_span); + + let expected = format!( + r#" + --> {}:11:6 + | +11 | Line 11 Code Snippet. + | ^^^^ +"#, + PathBuf::from(filename) + .canonicalize() + .unwrap() + .display() + .to_string() + ); + + assert_eq!( + format!("\n{}\n", emit_diagnostic_to_uncolored_text(&diag).unwrap()), + expected + ); + } + + #[test] + fn test_code_snippet_with_style() { + let code_span = SpanData { + lo: new_byte_pos(0), + hi: new_byte_pos(5), + } + .span(); + let filename = "./src/diagnostic/test_datas/code_snippet".to_string(); + let diag = gen_diag_with_code_snippet(filename.clone(), code_span); + + let mut sb = StyledBuffer::::new(); + let mut errs = vec![]; + diag.format(&mut sb, &mut errs); + + let result = sb.render(); + assert_eq!(errs.len(), 0); + + assert_eq!(errs.len(), 0); + assert_eq!(result.len(), 1); + assert_eq!(result.get(0).unwrap().len(), 4); + let expected_path = format!( + " --> {}:1:1\n | \n1 | ", + PathBuf::from(filename) + .canonicalize() + .unwrap() + .display() + .to_string() + ); + assert_eq!( + result.get(0).unwrap().get(0).unwrap().style.unwrap(), + DiagnosticStyle::Url + ); + assert_eq!(result.get(0).unwrap().get(0).unwrap().text, expected_path); + assert_eq!(result.get(0).unwrap().get(1).unwrap().style, None); + assert_eq!( + result.get(0).unwrap().get(1).unwrap().text, + "Line 1 Code Snippet.\n" + ); + assert_eq!( + result.get(0).unwrap().get(2).unwrap().style.unwrap(), + DiagnosticStyle::Url + ); + assert_eq!(result.get(0).unwrap().get(2).unwrap().text, " | "); + assert_eq!( + result.get(0).unwrap().get(3).unwrap().style.unwrap(), + DiagnosticStyle::NeedFix + ); + assert_eq!(result.get(0).unwrap().get(3).unwrap().text, "^^^^^"); + } + + #[test] + fn test_code_span_with_cross_lines_span() { + let filename = "./src/diagnostic/test_datas/code_snippet".to_string(); + let code_diag = emit_diagnostic_to_uncolored_text(&gen_diag_with_code_snippet( + filename.clone(), + SpanData { + lo: new_byte_pos(0), + hi: new_byte_pos(20), + } + .span(), + )) + .unwrap(); + + let cross_line_diag = emit_diagnostic_to_uncolored_text(&gen_diag_with_code_snippet( + filename.clone(), + SpanData { + lo: new_byte_pos(0), + hi: new_byte_pos(200), + } + .span(), + )) + .unwrap(); + assert_eq!(code_diag, cross_line_diag); + } +} + +mod test_error_message { + use crate::{diagnostic::diagnostic_message::TemplateLoader, diagnostic_handler::MessageArgs}; + + #[test] + fn test_template_message() { + let template_dir = "./src/diagnostic/locales/en-US"; + let template_loader = TemplateLoader::new_with_template_dir(template_dir).unwrap(); + + let mut args = MessageArgs::new(); + check_template_msg( + "invalid-syntax", + None, + &args, + "Invalid syntax", + &template_loader, + ); + + args.set("expected_items", "I am an expected item"); + check_template_msg( + "invalid-syntax", + Some("expected"), + &args, + "Expected one of `\u{2068}I am an expected item\u{2069}`", + &template_loader, + ); + + args.set("expected_items", "I am an expected item"); + check_template_msg( + "invalid-syntax-1", + Some("expected_1"), + &args, + "Expected one of `\u{2068}I am an expected item\u{2069}` 1", + &template_loader, + ); + } + + fn check_template_msg( + index: &str, + sub_index: Option<&str>, + args: &MessageArgs, + expected_msg: &str, + template_loader: &TemplateLoader, + ) { + let msg_in_line = template_loader.get_msg_to_str(index, sub_index, args); + assert_eq!(msg_in_line.unwrap(), expected_msg); + } +} + +mod test_diag_handler { + use crate::{ + components::Label, + diagnostic_handler::{DiagnosticHandler, MessageArgs}, + Diagnostic, DiagnosticStyle, + }; + use anyhow::{Context, Result}; + #[test] + fn test_return_self() { + let prev_hook = std::panic::take_hook(); + std::panic::set_hook(Box::new(|_| {})); + let result = std::panic::catch_unwind(|| { + return_self_for_test().unwrap(); + }); + assert!(result.is_err()); + std::panic::set_hook(prev_hook); + } + + fn return_self_for_test() -> Result<()> { + DiagnosticHandler::new_with_default_template_dir()? + .add_err_diagnostic(Diagnostic::::new())? + .add_warn_diagnostic(Diagnostic::::new())? + .emit_error_diagnostic(Diagnostic::::new())? + .emit_warn_diagnostic(Diagnostic::::new())? + .emit_stashed_diagnostics()? + .abort_if_errors() + .with_context(|| "One of the five methods above failed")?; + Ok(()) + } + + #[test] + fn test_diag_handler_fmt() { + let diag_handler = DiagnosticHandler::new_with_default_template_dir().unwrap(); + let mut diag = Diagnostic::::new(); + let err_label_1 = Box::new(Label::Error("E3033".to_string())); + diag.append_component(err_label_1); + diag_handler.add_err_diagnostic(diag).unwrap(); + assert_eq!(format!("{:?}", diag_handler), "[[StyledString { text: \"error\", style: Some(NeedFix) }, StyledString { text: \"[E3033]\", style: Some(Helpful) }]]\n"); + } + + #[test] + fn test_diag_handler_default() { + let diag_handler = DiagnosticHandler::default(); + match diag_handler.get_diagnostic_msg("index", Some("sub_index"), &MessageArgs::default()) { + Ok(_) => { + panic!("Unreachable") + } + Err(err) => { + assert_eq!(format!("{:?}", err), "Message doesn't exist.") + } + }; + } +} diff --git a/compiler_base/error/src/emitter.rs b/compiler_base/error/src/emitter.rs new file mode 100644 index 000000000..bcf336942 --- /dev/null +++ b/compiler_base/error/src/emitter.rs @@ -0,0 +1,478 @@ +//! 'emitter.rs' defines the diagnostic emitter, +//! which is responsible for displaying the rendered diagnostic. +//! +//! The crate provides `Emitter` trait to define the interface that diagnostic emitter should implement. +//! and also provides a built-in emitters: +//! +//! + `EmitterWriter` is responsible for emitting diagnostic to the writer who implements trait [`Write`] and [`Send`]. +//! + TODO(zongz): `EmitterAPI` is responsible for serializing diagnostics and emitting them to the API. +//! +//!Besides, it's easy to define your customized `Emitter` by implementing `Emitter` trait. +//! For more information about how to define your customized `Emitter`, see the doc above `Emitter` trait. + +use crate::{ + diagnostic::{Component, Diagnostic}, + errors::ComponentError, + DiagnosticStyle, +}; +use anyhow::Result; +use rustc_errors::{ + styled_buffer::{StyledBuffer, StyledString}, + Style, +}; +use std::fmt::Debug; +use std::io::{self, Write}; +use termcolor::{Ansi, Buffer, BufferWriter, ColorChoice, ColorSpec, StandardStream, WriteColor}; + +/// trait `Emitter` for emitting diagnostic. +/// +/// `T: Clone + PartialEq + Eq + Style` is responsible for the theme style when diaplaying diagnostic. +/// Builtin `DiagnosticStyle` provided in 'compiler_base/error/diagnostic/style.rs'. +/// +/// To customize your own `Emitter`, you could do the following steps: +/// +/// # Examples +/// +/// 1. Define your Emitter: +/// +/// ```ignore rust +/// +/// // create a new `Emitter` +/// struct DummyEmitter { +/// support_color: bool +/// } +/// +/// // `Dummy_Emitter` can use `DiagnosticStyle` or other style user-defined. +/// impl Emitter for DummyEmitter { +/// fn supports_color(&self) -> bool { +/// // Does `Dummy_Emitter` support color ? +/// self.support_color +/// } +/// +/// fn emit_diagnostic(&mut self, diag: &Diagnostic) { +/// // Format `Diagnostic` into `String`. +/// let styled_string = self.format_diagnostic(diag); +/// todo!("displaying the 'styled_string'"); +/// } +/// +/// fn format_diagnostic(&mut self, diag: &Diagnostic) -> StyledBuffer { +/// // Format `Diagnostic` into `String`. +/// // This part can format `Diagnostic` into a `String`, but it does not automatically diaplay, +/// // and the `String` can be sent to an external port such as RPC. +/// let mut sb = StyledBuffer::::new(); +/// diag.format(&mut sb); +/// sb +/// } +/// } +/// +/// ``` +/// +/// 2. Use your Emitter with diagnostic: +/// +/// ```ignore rust +/// +/// // Create a diagnostic for emitting. +/// let mut diagnostic = Diagnostic::::new(); +/// +/// // Create a string component wrapped by `Box<>`. +/// let msg = Box::new(": this is an error!".to_string()); +/// +/// // Add it to `Diagnostic`. +/// diagnostic.append_component(msg); +/// +/// // Create the emitter and emit it. +/// let mut emitter = DummyEmitter {}; +/// emitter.emit_diagnostic(&diagnostic); +/// ``` +pub trait Emitter +where + T: Clone + PartialEq + Eq + Style + Debug, +{ + /// Format struct `Diagnostic` into `String` and render `String` into `StyledString`, + /// and save `StyledString` in `StyledBuffer`. + fn format_diagnostic( + &mut self, + diag: &Diagnostic, + ) -> Result, ComponentError>; + + /// Emit a structured diagnostic. + fn emit_diagnostic(&mut self, diag: &Diagnostic) -> Result<()>; + + /// Checks if we can use colors in the current output stream. + /// `false` by default. + fn supports_color(&self) -> bool { + false + } +} + +/// `EmitterWriter` implements trait `Emitter` based on `termcolor1.0` +/// for rendering diagnostic as strings and displaying them to the terminal. +/// +/// `termcolor1.0` supports displaying colorful string to terminal. +/// +/// # Examples +/// +/// ```rust +/// # use crate::compiler_base_error::Emitter; +/// # use compiler_base_error::EmitterWriter; +/// # use compiler_base_error::{components::Label, Diagnostic}; +/// # use compiler_base_error::DiagnosticStyle; +/// +/// // 1. Create a EmitterWriter +/// let mut term_emitter = EmitterWriter::default(); +/// +/// // 2. Create a diagnostic for emitting. +/// let mut diagnostic = Diagnostic::::new(); +/// +/// // 3. Create components wrapped by `Box<>`. +/// let err_label = Box::new(Label::Error("E3033".to_string())); +/// let msg = Box::new(": this is an error!".to_string()); +/// +/// // 4. Add components to `Diagnostic`. +/// diagnostic.append_component(err_label); +/// diagnostic.append_component(msg); +/// +/// // 5. Emit the diagnostic. +/// term_emitter.emit_diagnostic(&diagnostic); +/// ``` +pub struct EmitterWriter<'a> { + dst: Destination<'a>, +} + +impl<'a> EmitterWriter<'a> { + /// Return a [`Destination`] with custom writer. + /// + /// # Examples + /// + /// ```rust + /// use compiler_base_error::Destination; + /// use compiler_base_error::EmitterWriter; + /// use termcolor::ColorChoice; + /// // 1. Create a `Destination` and close the color. + /// let dest = Destination::from_stderr(ColorChoice::Never); + /// + /// // 2. Create the EmiterWriter by `Destination` with writer stderr. + /// let emitter_writer = EmitterWriter::new_with_writer(dest); + /// ``` + pub fn new_with_writer(dst: Destination<'a>) -> Self { + Self { dst } + } +} + +impl<'a> Default for EmitterWriter<'a> { + /// Return a [`Destination`] with writer stderr. + fn default() -> Self { + Self { + dst: Destination::from_stderr(ColorChoice::Auto), + } + } +} + +/// Emit destinations provide four ways to emit. +/// +/// - [`Destination::Terminal`]: Emit by [`StandardStream`] +/// - [`Destination::Buffered`]: Emit by [`BufferWriter`], you can save content in [`Buffer`] first, and then emit the [`Buffer`] to [`BufferWriter`] on flush. +/// - [`Destination::UnColoredRaw`]: Emit by a custom writer that does not support colors. +/// - [`Destination::ColoredRaw`]: Emit by a custom writer that supports colors. +/// +/// Note: All custom writers must implement two traits [`Write`] and [`Send`]. +/// +/// # Examples +/// 1. If you want to use writer stdout or stderr, you can use the method `from_stderr` and `from_stdout`. +/// +/// ```rust +/// use compiler_base_error::Destination; +/// use termcolor::ColorChoice; +/// // stdout +/// let dest_stdout = Destination::from_stdout(ColorChoice::Never); +/// // stderr +/// let dest_stderr = Destination::from_stderr(ColorChoice::Never); +/// ``` +/// +/// 2. If you want to use custom writer +/// ```rust +/// use compiler_base_error::Destination; +/// use termcolor::Ansi; +/// use std::io::Write; +/// use std::io; +/// +/// // 1. Define a custom writer. +/// struct MyWriter { +/// content: String, +/// } +/// +/// // 2. Implement trait `Write`. +/// impl Write for MyWriter { +/// fn write(&mut self, buf: &[u8]) -> io::Result { +/// if let Ok(s) = std::str::from_utf8(buf) { +/// self.content.push_str(s) +/// } else { +/// self.content = "Nothing".to_string(); +/// } +/// Ok(buf.len()) +/// } +/// +/// fn flush(&mut self) -> io::Result<()> { +/// Ok(()) +/// } +/// } +/// // 3. Implement trait `Send`. +/// unsafe impl Send for MyWriter {} +/// +/// // 4. Define a destiation. +/// let mut my_writer = MyWriter{ content: String::new() }; +/// Destination::UnColoredRaw(&mut my_writer); +/// +/// // 5. If your custom writer supports color. +/// Destination::ColoredRaw(Ansi::new(&mut my_writer)); +/// ``` +pub enum Destination<'a> { + /// Emit to stderr/stdout by stream. + Terminal(StandardStream), + + /// Save by the 'Buffer', and then Emit to stderr/stdout by the 'Buffer' through the 'BufferWriter'. + Buffered(BufferWriter, Buffer), + + /// Emit to a destiation without color. + UnColoredRaw(&'a mut (dyn Write + Send)), + + /// Emit to a customize destiation with color. + ColoredRaw(Ansi<&'a mut (dyn Write + Send)>), +} + +impl<'a> Destination<'a> { + /// New a stderr destination. + /// [`ColorChoice`] is used to determine whether the output content has been colored. + pub fn from_stderr(choice: ColorChoice) -> Self { + // On Windows we'll be performing global synchronization on the entire + // system for emitting errors, so there's no need to buffer + // anything. + // + // On non-Windows we rely on the atomicity of `write` to ensure errors + // don't get all jumbled up. + if cfg!(windows) { + Self::Terminal(StandardStream::stderr(choice)) + } else { + let buffer_writer = BufferWriter::stderr(choice); + let buffer = buffer_writer.buffer(); + Destination::Buffered(buffer_writer, buffer) + } + } + + /// New a stdout destination. + /// [`ColorChoice`] is used to determine whether the output content has been colored. + pub fn from_stdout(choice: ColorChoice) -> Self { + // On Windows we'll be performing global synchronization on the entire + // system for emitting errors, so there's no need to buffer + // anything. + // + // On non-Windows we rely on the atomicity of `write` to ensure errors + // don't get all jumbled up. + if cfg!(windows) { + Self::Terminal(StandardStream::stdout(choice)) + } else { + let buffer_writer = BufferWriter::stdout(ColorChoice::Auto); + let buffer = buffer_writer.buffer(); + Destination::Buffered(buffer_writer, buffer) + } + } + + /// Returns true if and only if the underlying [`Destination`] supports colors. + pub fn supports_color(&self) -> bool { + match *self { + Self::Terminal(ref stream) => stream.supports_color(), + Self::Buffered(ref buffer, _) => buffer.buffer().supports_color(), + Self::UnColoredRaw(_) => false, + Self::ColoredRaw(_) => true, + } + } + + /// Set color for the [`Destination`] by [`ColorSpec`]. + /// Subsequent writes to this writer will use these settings until either `reset()` is called or new color settings are set. + /// If there was a problem resetting the color settings, then an error is returned. + pub fn set_color(&mut self, color: &ColorSpec) -> io::Result<()> { + match *self { + Self::Terminal(ref mut t) => t.set_color(color), + Self::Buffered(_, ref mut t) => t.set_color(color), + Self::ColoredRaw(ref mut t) => t.set_color(color), + Self::UnColoredRaw(_) => Ok(()), + } + } + + /// Reset the current color settings for [`Destination`] to their original settings. + /// If there was a problem resetting the color settings, then an error is returned. + pub fn reset(&mut self) -> io::Result<()> { + match *self { + Self::Terminal(ref mut t) => t.reset(), + Self::Buffered(_, ref mut t) => t.reset(), + Self::ColoredRaw(ref mut t) => t.reset(), + Self::UnColoredRaw(_) => Ok(()), + } + } +} + +impl<'a> Write for Destination<'a> { + fn write(&mut self, bytes: &[u8]) -> io::Result { + match *self { + Self::Terminal(ref mut t) => t.write(bytes), + Self::Buffered(_, ref mut buf) => buf.write(bytes), + Self::UnColoredRaw(ref mut w) => w.write(bytes), + Self::ColoredRaw(ref mut t) => t.write(bytes), + } + } + + fn flush(&mut self) -> io::Result<()> { + match *self { + Self::Terminal(ref mut t) => t.flush(), + Self::Buffered(_, ref mut buf) => buf.flush(), + Self::UnColoredRaw(ref mut w) => w.flush(), + Self::ColoredRaw(ref mut w) => w.flush(), + } + } +} + +impl<'a> Drop for Destination<'a> { + fn drop(&mut self) { + if let Destination::Buffered(ref mut dst, ref mut buf) = self { + drop(dst.print(buf)); + } + } +} + +impl<'a, T> Emitter for EmitterWriter<'a> +where + T: Clone + PartialEq + Eq + Style + Debug, +{ + /// Checks if we can use colors in the current output stream. + /// Depends on `termcolor1.0` which supports color. + fn supports_color(&self) -> bool { + self.dst.supports_color() + } + + /// Emit a structured diagnostic. + /// It will call `format_diagnostic` first to format the `Diagnostic` into `StyledString`. + /// + /// It will `panic` if something wrong during emitting. + fn emit_diagnostic(&mut self, diag: &Diagnostic) -> Result<()> { + let buffer = self.format_diagnostic(diag)?; + emit_to_destination(&buffer.render(), &mut self.dst)?; + Ok(()) + } + + /// Format struct `Diagnostic` into `String` and render `String` into `StyledString`, + /// and save `StyledString` in `StyledBuffer`. + fn format_diagnostic( + &mut self, + diag: &Diagnostic, + ) -> Result, ComponentError> { + let mut sb = StyledBuffer::::new(); + let mut errs = vec![]; + diag.format(&mut sb, &mut errs); + if !errs.is_empty() { + return Err(ComponentError::ComponentFormatErrors(errs)); + } + Ok(sb) + } +} + +fn emit_to_destination( + rendered_buffer: &[Vec>], + dst: &mut Destination, +) -> io::Result<()> +where + T: Clone + PartialEq + Eq + Style + Debug, +{ + use rustc_errors::lock; + + // In order to prevent error message interleaving, where multiple error lines get intermixed + // when multiple compiler processes error simultaneously, we emit errors with additional + // steps. + // + // On Unix systems, we write into a buffered terminal rather than directly to a terminal. When + // the .flush() is called we take the buffer created from the buffered writes and write it at + // one shot. Because the Unix systems use ANSI for the colors, which is a text-based styling + // scheme, this buffered approach works and maintains the styling. + // + // On Windows, styling happens through calls to a terminal API. This prevents us from using the + // same buffering approach. Instead, we use a global Windows mutex, which we acquire long + // enough to output the full error message, then we release. + // + // This part of the code refers to the implementation of [`rustc_error`]. + let _buffer_lock = lock::acquire_global_lock("compiler_base_errors"); + for (pos, line) in rendered_buffer.iter().enumerate() { + for part in line { + let color_spec = match &part.style { + Some(style) => style.render_style_to_color_spec(), + None => ColorSpec::new(), + }; + dst.set_color(&color_spec)?; + write!(dst, "{}", part.text)?; + dst.reset()?; + } + if pos != rendered_buffer.len() - 1 { + writeln!(dst)?; + } + } + dst.flush()?; + Ok(()) +} + +/// Emit the [`Diagnostic`] with [`DiagnosticStyle`] to uncolored text strng. +/// +/// Examples +/// +/// ```rust +/// use compiler_base_error::{Diagnostic, components::Label}; +/// use compiler_base_error::emit_diagnostic_to_uncolored_text; +/// use compiler_base_error::DiagnosticStyle; +/// // 1. Define your diagnostic. +/// let mut diag = Diagnostic::::new(); +/// +/// // 2. Add a component for the diagnostic, otherwise it will emit an empty string. +/// diag.append_component(Box::new(Label::Note)); +/// +/// // 3. Emit it. +/// let text = emit_diagnostic_to_uncolored_text(&diag).unwrap(); +/// assert_eq!(text, "note"); +/// ``` +pub fn emit_diagnostic_to_uncolored_text(diag: &Diagnostic) -> Result { + let mut emit_tes = EmitResultText::new(); + { + let mut emit_writter = + EmitterWriter::new_with_writer(Destination::UnColoredRaw(&mut emit_tes)); + emit_writter.emit_diagnostic(diag)?; + } + Ok(emit_tes.test_res) +} + +/// Used to save the result of emit into a [`String`], +/// because trait [`Write`] and [`Send`] cannot be directly implemented by [`String`]. +pub(crate) struct EmitResultText { + test_res: String, +} + +impl Write for EmitResultText { + fn write(&mut self, buf: &[u8]) -> io::Result { + if let Ok(s) = std::str::from_utf8(buf) { + self.test_res.push_str(s) + } else { + self.test_res = String::new(); + } + Ok(buf.len()) + } + + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } +} + +unsafe impl Send for EmitResultText {} + +impl EmitResultText { + /// New a [`EmitResultText`] with an empty [`String`]。 + pub(crate) fn new() -> Self { + Self { + test_res: String::new(), + } + } +} diff --git a/compiler_base/error/src/errors.rs b/compiler_base/error/src/errors.rs new file mode 100644 index 000000000..25c9a816c --- /dev/null +++ b/compiler_base/error/src/errors.rs @@ -0,0 +1,93 @@ +//! This crate provides all error types used in compiler-base-error. + +use std::{error::Error, fmt}; + +impl Error for ComponentFormatError {} +impl Error for ComponentError {} + +/// `ComponentFormatError` will be return when `Component` formatting exception occurs. +/// For more information about `Component`, see doc in 'compiler_base/error/src/diagnostic/mod.rs' +/// and 'compiler_base/error/src/diagnostic/components.rs'. +#[derive(Debug)] +pub struct ComponentFormatError { + name: String, + message: String, +} + +impl ComponentFormatError { + /// The constructor of `ComponentFormatError`. + /// # Examples + /// + /// ```rust + /// # use compiler_base_error::errors::ComponentFormatError; + /// + /// // If you want to new a `ComponentFormatError`, + /// // the first arg is the component name, and the second arg is the help info for this error. + /// let component_format_error = ComponentFormatError::new("name", "The component format failed."); + /// + /// let err_fmt = format!("{:?}", component_format_error); + /// assert_eq!("ComponentFormatError { name: \"name\", message: \"The component format failed.\" }", err_fmt); + /// ``` + pub fn new(name: &str, msg: &str) -> Self { + Self { + name: name.to_string(), + message: msg.to_string(), + } + } + + pub(crate) fn format(&self) -> String { + format!( + "Failed to display '{}' on terminal, {}.\n", + self.name, self.message + ) + } +} + +impl fmt::Display for ComponentFormatError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.format()) + } +} + +/// `ComponentError` is a collection of errors in `Component`. +/// For more information about `Component`, see doc in 'compiler_base/error/src/diagnostic/mod.rs' +/// and 'compiler_base/error/src/diagnostic/components.rs'. +/// +/// Currently `ComponentError` only supports type `ComponentFormatErrors`, and more types can be added later if needed. +/// +/// # Examples +/// +/// ```rust +/// # use compiler_base_error::errors::ComponentFormatError; +/// # use compiler_base_error::errors::ComponentError; +/// +/// // If you want to new a `ComponentFormatError`, +/// let component_format_error_1 = ComponentFormatError::new("name_1", "The component_1 format failed."); +/// let component_format_error_2 = ComponentFormatError::new("name_2", "The component_1 format failed."); +/// let errs = vec![component_format_error_1, component_format_error_2]; +/// let component_format_errors = ComponentError::ComponentFormatErrors(errs); +/// +/// let errs_fmt = format!("{:?}", component_format_errors); +/// assert_eq!( +/// "ComponentFormatErrors([ComponentFormatError { name: \"name_1\", message: \"The component_1 format failed.\" }, ComponentFormatError { name: \"name_2\", message: \"The component_1 format failed.\" }])" +/// , errs_fmt) +/// ``` +#[derive(Debug)] +pub enum ComponentError { + ComponentFormatErrors(Vec), +} + +impl fmt::Display for ComponentError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + ComponentError::ComponentFormatErrors(errs) => { + let mut result = String::new(); + for e in errs { + result += &e.format(); + } + result += "/n"; + write!(f, "{}", result) + } + } + } +} diff --git a/compiler_base/error/src/lib.rs b/compiler_base/error/src/lib.rs new file mode 100644 index 000000000..baca04ed1 --- /dev/null +++ b/compiler_base/error/src/lib.rs @@ -0,0 +1,25 @@ +//! Compiler-Base-Error +//! +//! The idea with `Compiler-Base-Error` is to make a reusable library, +//! by separating out error thorwing and diagnostic diaplaying or other error handling procedures. +//! +//! - Compiler-Base-Error provides `DiagnosticHandler` to diaplay diagnostic. +//! For more information about `DiagnosticHandler`, see doc in 'compiler_base/error/diagnostic/diagnostic_handler.rs'. +//! +//! - TODO(zongz): Compiler-Base-Error provides `ErrorRecover` to recover from errors. + +mod diagnostic; +mod emitter; +#[cfg(test)] +mod tests; + +pub mod errors; +pub mod unit_type; + +pub use diagnostic::{ + components, diagnostic_handler, style::DiagnosticStyle, Component, Diagnostic, StyledBuffer, + StyledString, +}; + +pub use emitter::{emit_diagnostic_to_uncolored_text, Destination, Emitter, EmitterWriter}; +pub use termcolor::{Ansi, Buffer, BufferWriter, ColorChoice, ColorSpec, StandardStream}; diff --git a/compiler_base/error/src/tests.rs b/compiler_base/error/src/tests.rs new file mode 100644 index 000000000..dfa1cd3cc --- /dev/null +++ b/compiler_base/error/src/tests.rs @@ -0,0 +1,250 @@ +mod test_diagnostic_handler { + use std::panic; + + use crate::{ + diagnostic_handler::{DiagnosticHandler, MessageArgs}, + Diagnostic, DiagnosticStyle, + }; + + #[test] + fn test_diagnostic_handler_new_with_template_dir() { + let diag_handler = + DiagnosticHandler::new_with_template_dir("./src/diagnostic/locales/en-US/"); + match diag_handler { + Ok(_) => {} + Err(_) => { + panic!("`diag_handler` should be Ok(...)") + } + } + + let diag_handler_invalid = DiagnosticHandler::new_with_template_dir("./invalid_path"); + if diag_handler_invalid.is_ok() { + panic!("`diag_handler_invalid` should be Err(...)") + } + } + + #[test] + fn test_diagnostic_handler_add_diagnostic() { + let diag_1 = Diagnostic::::new(); + let diag_handler = + DiagnosticHandler::new_with_template_dir("./src/diagnostic/locales/en-US/").unwrap(); + assert_eq!(diag_handler.diagnostics_count().unwrap(), 0); + + diag_handler.add_err_diagnostic(diag_1).unwrap(); + assert_eq!(diag_handler.diagnostics_count().unwrap(), 1); + } + + #[test] + fn test_diagnostic_handler_get_diagnostic_msg() { + let no_args = MessageArgs::new(); + let index = "invalid-syntax"; + let sub_index = None; + let diag_handler = + DiagnosticHandler::new_with_template_dir("./src/diagnostic/locales/en-US/").unwrap(); + let msg_in_line_1 = diag_handler + .get_diagnostic_msg(index, sub_index, &no_args) + .unwrap(); + assert_eq!(msg_in_line_1, "Invalid syntax"); + + let mut args = MessageArgs::new(); + args.set("expected_items", "I am an expected item"); + let sub_index = "expected"; + let msg_in_line_2 = diag_handler + .get_diagnostic_msg(index, Some(sub_index), &args) + .unwrap(); + assert_eq!( + msg_in_line_2, + "Expected one of `\u{2068}I am an expected item\u{2069}`" + ); + } + + #[test] + fn test_diagnostic_handler_has() { + let diag_handler = + DiagnosticHandler::new_with_template_dir("./src/diagnostic/locales/en-US/").unwrap(); + // test has_errors() + assert!(!diag_handler.has_errors().unwrap()); + diag_handler + .add_err_diagnostic(Diagnostic::::new()) + .unwrap(); + assert!(diag_handler.has_errors().unwrap()); + + // test has_warns() + assert!(!diag_handler.has_warns().unwrap()); + diag_handler + .add_warn_diagnostic(Diagnostic::::new()) + .unwrap(); + assert!(diag_handler.has_warns().unwrap()); + } + + #[test] + fn test_abort_if_errors() { + let diag_handler = + DiagnosticHandler::new_with_template_dir("./src/diagnostic/locales/en-US/").unwrap(); + diag_handler.abort_if_errors().unwrap(); + diag_handler + .add_warn_diagnostic(Diagnostic::::new()) + .unwrap(); + diag_handler.abort_if_errors().unwrap(); + diag_handler + .add_err_diagnostic(Diagnostic::::new()) + .unwrap(); + + let result = panic::catch_unwind(|| { + diag_handler.abort_if_errors().unwrap(); + }); + assert!(result.is_err()); + } +} + +mod test_errors { + use rustc_errors::styled_buffer::StyledBuffer; + + use crate::errors::{ComponentError, ComponentFormatError}; + use crate::{Component, Diagnostic, DiagnosticStyle, Emitter, EmitterWriter}; + + // Component to generate errors. + struct ComponentGenError; + impl Component for ComponentGenError { + fn format( + &self, + _: &mut StyledBuffer, + errs: &mut Vec, + ) { + errs.push(ComponentFormatError::new( + "ComponentGenError", + "This is an error for testing", + )); + } + } + + #[test] + fn test_component_format_error() { + let cge = ComponentGenError {}; + let mut diagnostic = Diagnostic::::new(); + diagnostic.append_component(Box::new(cge)); + + let mut emitter = EmitterWriter::default(); + match emitter.emit_diagnostic(&diagnostic) { + Ok(_) => { + panic!("`emit_diagnostic` shoule be failed.") + } + Err(err) => { + match err.downcast_ref::() { + Some(ce) => { + let err_msg = format!("{:?}", ce); + assert_eq!(err_msg, "ComponentFormatErrors([ComponentFormatError { name: \"ComponentGenError\", message: \"This is an error for testing\" }])") + } + None => { + panic!("Error Type Error") + } + }; + } + }; + } +} + +mod test_emitter { + use crate::{ + components::Label, diagnostic_handler::DiagnosticHandler, + emit_diagnostic_to_uncolored_text, emitter::Destination, Diagnostic, Emitter, + EmitterWriter, + }; + use std::io::{self, Write}; + use termcolor::Ansi; + + struct MyWriter { + content: String, + } + + impl Write for MyWriter { + fn write(&mut self, buf: &[u8]) -> io::Result { + if let Ok(s) = std::str::from_utf8(buf) { + self.content.push_str(s) + } else { + self.content = "Nothing".to_string(); + } + Ok(buf.len()) + } + + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } + } + + unsafe impl Send for MyWriter {} + + #[test] + fn test_emit_to_raw() { + let mut writer = MyWriter { + content: String::new(), + }; + { + let mut emitter = + EmitterWriter::new_with_writer(Destination::ColoredRaw(Ansi::new(&mut writer))); + let mut diag = Diagnostic::new(); + diag.append_component(Box::new(Label::Note)); + emitter.emit_diagnostic(&diag).unwrap(); + } + + assert_eq!( + writer.content, + "\u{1b}[0m\u{1b}[1m\u{1b}[38;5;14mnote\u{1b}[0m" + ); + writer.content = String::new(); + { + let mut emitter = + EmitterWriter::new_with_writer(Destination::UnColoredRaw(&mut writer)); + let mut diag = Diagnostic::new(); + diag.append_component(Box::new(Label::Note)); + emitter.emit_diagnostic(&diag).unwrap(); + } + + assert_eq!(writer.content, "note"); + } + + #[test] + fn test_emit_diag_to_uncolored_text() { + let mut diag = Diagnostic::new(); + diag.append_component(Box::new(Label::Note)); + assert_eq!(emit_diagnostic_to_uncolored_text(&diag).unwrap(), "note"); + } + + struct EmitResultText { + pub text_res: String, + } + + impl Write for EmitResultText { + fn write(&mut self, buf: &[u8]) -> io::Result { + if let Ok(s) = std::str::from_utf8(buf) { + self.text_res.push_str(s) + } else { + self.text_res = String::new(); + } + Ok(buf.len()) + } + + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } + } + + unsafe impl Send for EmitResultText {} + + #[test] + fn test_emit_diag_to_uncolored_text_many_times() { + let mut emit_res = EmitResultText { + text_res: String::new(), + }; + { + let mut emit_writter = + EmitterWriter::new_with_writer(Destination::UnColoredRaw(&mut emit_res)); + let mut diag = Diagnostic::new(); + diag.append_component(Box::new(Label::Note)); + emit_writter.emit_diagnostic(&diag).unwrap(); + emit_writter.emit_diagnostic(&diag).unwrap(); + emit_writter.emit_diagnostic(&diag).unwrap(); + } + assert_eq!(emit_res.text_res, "notenotenote"); + } +} diff --git a/compiler_base/error/src/unit_type.rs b/compiler_base/error/src/unit_type.rs new file mode 100644 index 000000000..02c0195c3 --- /dev/null +++ b/compiler_base/error/src/unit_type.rs @@ -0,0 +1,31 @@ +//! This file provides some of the self-encapsulated types used in handling error messages. + +/// [`TyeWithUnit`] is a trait for types that can be converted into a string with a unit. +pub trait TypeWithUnit { + fn into_string_with_unit(self) -> String; +} + +/// [`UnitUsize`] is a [`usize`] type that can be converted into a string with a unit. +pub struct UnitUsize(pub usize, pub String); + +impl TypeWithUnit for UnitUsize { + /// [`into_string_with_unit`] converts [`UnitUsize`] into a string with a unit. + /// + /// # Examples + /// + /// ``` + /// use compiler_base_error::unit_type::{TypeWithUnit, UnitUsize}; + /// + /// let unit_usize = UnitUsize(1, "byte".to_string()); + /// assert_eq!(unit_usize.into_string_with_unit(), "1 byte"); + /// let unit_usize = UnitUsize(2, "byte".to_string()); + /// assert_eq!(unit_usize.into_string_with_unit(), "2 bytes"); + /// ``` + fn into_string_with_unit(self) -> String { + if self.0 > 1 { + format!("{} {}s", self.0, self.1) + } else { + format!("{} {}", self.0, self.1) + } + } +} diff --git a/compiler_base/macros/Cargo.toml b/compiler_base/macros/Cargo.toml new file mode 100644 index 000000000..78269a343 --- /dev/null +++ b/compiler_base/macros/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "compiler_base_macros" +version = "0.1.1" +edition = "2021" +authors = ["zongzhe1024@163.com"] +license = "Apache-2.0 OR MIT" +description = "compiler_base_macros" +readme = "README.md" +homepage = "https://github.com/kcl-lang/kcl" +repository = "https://github.com/kcl-lang/kcl" +keywords = ["compiler", "macro"] +categories = ["command-line-utilities"] + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/compiler_base/macros/README.md b/compiler_base/macros/README.md new file mode 100644 index 000000000..13db101fb --- /dev/null +++ b/compiler_base/macros/README.md @@ -0,0 +1,3 @@ +compiler_base_macros + +note: [WIP] Do not use it. \ No newline at end of file diff --git a/kclvm/error/src/bug.rs b/compiler_base/macros/src/bug.rs similarity index 100% rename from kclvm/error/src/bug.rs rename to compiler_base/macros/src/bug.rs diff --git a/compiler_base/macros/src/lib.rs b/compiler_base/macros/src/lib.rs new file mode 100644 index 000000000..be7f63958 --- /dev/null +++ b/compiler_base/macros/src/lib.rs @@ -0,0 +1,5 @@ +#[macro_use] +pub mod bug; + +#[cfg(test)] +mod tests; diff --git a/compiler_base/macros/src/tests.rs b/compiler_base/macros/src/tests.rs new file mode 100644 index 000000000..61ed1fb84 --- /dev/null +++ b/compiler_base/macros/src/tests.rs @@ -0,0 +1,46 @@ +mod test_bug { + use crate::bug; + + #[test] + fn test_bug_macro() { + std::panic::set_hook(Box::new(|_| {})); + let result = std::panic::catch_unwind(|| { + bug!(); + }); + assert!(result.is_err()); + let result = std::panic::catch_unwind(|| { + bug!("an error msg"); + }); + assert!(result.is_err()); + match result { + Ok(_) => panic!("test bug!() failed"), + Err(panic_err) => { + let err_message = if let Some(s) = panic_err.downcast_ref::() { + (*s).clone() + } else { + panic!("test bug!() failed") + }; + assert_eq!( + err_message, + "Internal error, please report a bug to us. The error message is: an error msg" + ); + } + } + + let result = std::panic::catch_unwind(|| { + bug!("an error msg with string format {}", "msg"); + }); + assert!(result.is_err()); + match result { + Ok(_) => panic!("test bug!() failed"), + Err(panic_err) => { + let err_message = if let Some(s) = panic_err.downcast_ref::() { + (*s).clone() + } else { + panic!("test bug!() failed") + }; + assert_eq!(err_message, "Internal error, please report a bug to us. The error message is: an error msg with string format msg"); + } + } + } +} diff --git a/compiler_base/makefile b/compiler_base/makefile new file mode 100644 index 000000000..1bb5b642c --- /dev/null +++ b/compiler_base/makefile @@ -0,0 +1,39 @@ +PWD:=$(shell pwd) +COVER_REPORT_FILE_PATH:=$(PWD)/target/llvm-cov/html/index.html + +# ------------------------ +# Compile and run +# ------------------------ + +# Cargo check all packages +check: + cargo check --release + +# Cargo fmt all packages +fmt: + cargo fmt --all + +# Cargo clippy all packages +lint: + cargo clippy + +# ------------------------ +# Tests +# ------------------------ + +# Unit tests without code cov +test: + cargo test -p compiler_base_* + +# Unit tests with code cov (Requires rust 1.60+) +codecov: + rustup component add llvm-tools-preview + cargo install cargo-llvm-cov + cargo llvm-cov --workspace --ignore-filename-regex gpyrpc.rs --html --open + +# Unit tests with code cov and output the lcov file (Requires rust 1.60+) +codecov-lcov: + rustup component add llvm-tools-preview + cargo install cargo-llvm-cov + mkdir $(PWD)/.compiler_base + cargo llvm-cov --lcov --output-path $(PWD)/.compiler_base/lcov.info --workspace --ignore-filename-regex gpyrpc.rs diff --git a/compiler_base/parallel/Cargo.toml b/compiler_base/parallel/Cargo.toml new file mode 100644 index 000000000..1c6d71525 --- /dev/null +++ b/compiler_base/parallel/Cargo.toml @@ -0,0 +1,24 @@ +[package] +name = "compiler_base_parallel" +version = "0.1.0" +edition = "2021" +authors = ["zongzhe1024@163.com"] +license = "Apache-2.0 OR MIT" +description = "A common domain programming language framework." +readme = "README.md" +homepage = "https://github.com/kcl-lang/kcl" +repository = "https://github.com/kcl-lang/kcl" +keywords = ["compiler", "parallel"] +categories = ["command-line-utilities"] + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +log = "0.4" +rand = "0.8.4" +anyhow = "1.0.69" +fern = { version = "0.6", features = ["colored"] } +chrono = "0.4.0" +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" +pretty_assertions = "1.3.0" diff --git a/compiler_base/parallel/README.md b/compiler_base/parallel/README.md new file mode 100644 index 000000000..6c0db24fc --- /dev/null +++ b/compiler_base/parallel/README.md @@ -0,0 +1,60 @@ +# [WIP] compiler_base_parallel + +## Summary + +`compiler_base_parallel` defines the core logic for multitasking execution engine. It aims to provide reusable components and accumulate some general concurrency models for compiler developments. + +The `compiler_base_parallel` crate consists of three main components: Task, Executor, and Reporter. + +## Task +[`Task`](./src/task/mod.rs) is the smallest executable unit, anything can be considered as a [`Task`](./src/task/mod.rs) can be executed by [`Executor`](./src/executor/mod.rs). Therefore, we provide a trait to define a [`Task`](./src/task/mod.rs). + +```rust +pub trait Task { + /// [`run`] will be executed of the [[`Task`](./src/task/mod.rs)], + /// and the result of the execution is communicated with other threads through the [`ch`] which is a [`Sender`], + /// so [`run`] method does not need to return a value. + fn run(&self, ch: Sender); + + /// Return the [`TaskInfo`] + fn info(&self) -> TaskInfo; +} +``` + +To develop a concurrency mechanism for a compiler in a `compiler_base_parallel`-way, the first step is to create a [`Task`](./src/task/mod.rs). + +For more information about [`Task`](./src/task/mod.rs), see the docs in source code in `./src/task/mod.rs`. + +## Executor + +[`Executor`](./src/executor/mod.rs) is responsible for executing the [`Task`](./src/task/mod.rs). + +We also provide a trait to define a [`Executor`](./src/executor/mod.rs). + +```rust +pub trait Executor { + /// [`run_all_tasks`] will execute all tasks concurrently. + /// [`notify_what_happened`] is a notifier that receives [`TaskEvent`] to output the [[`Task`](./src/task/mod.rs)] execution status in to the log. + fn run_all_tasks(self, tasks: Vec, notify_what_happened: F) -> Result<()> + where + T: Task + Sync + Send + 'static, + F: Fn(TaskEvent) -> Result<()>; + + /// The count for threads. + fn concurrency_capacity(&self) -> usize; +} +``` + +For more information about [`Executor`](./src/executor/mod.rs), see docs in source code in `./src/executor/mod.rs`. + +### TimeoutExecutor + +[`TimeoutExecutor`](./src/executor/timeout.rs) refers to the concurrency mechanism adopted by rustc in the rust unit testing and mainly contains the following features: + +- Tasks are executed concurrently based on the number of threads. + +- A timeout queue is used to monitor the execution of the [`Task`](./src/task/mod.rs) has timed out. If it does, a warning will be reported, but the [`Task`](./src/task/mod.rs) will not stop and will run until it is manually interrupted. + +If you want to implement unit testing, fuzz, bench or other you want to do in parallel in your compiler using the same workflow as rustc testing, you can use the [`TimeoutExecutor`](./src/executor/timeout.rs). If this workflow is not suitable for your compiler, you can choose to implement your own [`Executor`](./src/executor/mod.rs). + +## [WIP] Reporter diff --git a/compiler_base/parallel/src/executor/LICENSE b/compiler_base/parallel/src/executor/LICENSE new file mode 100644 index 000000000..8467a0168 --- /dev/null +++ b/compiler_base/parallel/src/executor/LICENSE @@ -0,0 +1,231 @@ +Short version for non-lawyers: + +The Rust Project is dual-licensed under Apache 2.0 and MIT +terms. + + +Longer version: + +Copyrights in the Rust project are retained by their contributors. No +copyright assignment is required to contribute to the Rust project. + +Some files include explicit copyright notices and/or license notices. +For full authorship information, see the version control history or +https://thanks.rust-lang.org + +Except as otherwise noted (below and/or in individual files), Rust is +licensed under the Apache License, Version 2.0 or + or the MIT license + or , at your option. + + +The Rust Project includes packages written by third parties. +The following third party packages are included, and carry +their own copyright notices and license terms: + +* LLVM. Code for this package is found in src/llvm-project. + + Copyright (c) 2003-2013 University of Illinois at + Urbana-Champaign. All rights reserved. + + Developed by: + + LLVM Team + + University of Illinois at Urbana-Champaign + + http://llvm.org + + Permission is hereby granted, free of charge, to any + person obtaining a copy of this software and associated + documentation files (the "Software"), to deal with the + Software without restriction, including without + limitation the rights to use, copy, modify, merge, + publish, distribute, sublicense, and/or sell copies of + the Software, and to permit persons to whom the Software + is furnished to do so, subject to the following + conditions: + + * Redistributions of source code must retain the + above copyright notice, this list of conditions + and the following disclaimers. + + * Redistributions in binary form must reproduce the + above copyright notice, this list of conditions + and the following disclaimers in the documentation + and/or other materials provided with the + distribution. + + * Neither the names of the LLVM Team, University of + Illinois at Urbana-Champaign, nor the names of its + contributors may be used to endorse or promote + products derived from this Software without + specific prior written permission. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF + ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED + TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A + PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT + SHALL THE CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE + FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT + OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS WITH THE SOFTWARE. + +* Additional libraries included in LLVM carry separate + BSD-compatible licenses. See src/llvm-project/llvm/LICENSE.TXT + for details. + +* compiler-rt, in src/compiler-rt is dual licensed under + LLVM's license and MIT: + + Copyright (c) 2009-2014 by the contributors listed in + CREDITS.TXT + + All rights reserved. + + Developed by: + + LLVM Team + + University of Illinois at Urbana-Champaign + + http://llvm.org + + Permission is hereby granted, free of charge, to any + person obtaining a copy of this software and associated + documentation files (the "Software"), to deal with the + Software without restriction, including without + limitation the rights to use, copy, modify, merge, + publish, distribute, sublicense, and/or sell copies of + the Software, and to permit persons to whom the Software + is furnished to do so, subject to the following + conditions: + + * Redistributions of source code must retain the + above copyright notice, this list of conditions + and the following disclaimers. + + * Redistributions in binary form must reproduce the + above copyright notice, this list of conditions + and the following disclaimers in the documentation + and/or other materials provided with the + distribution. + + * Neither the names of the LLVM Team, University of + Illinois at Urbana-Champaign, nor the names of its + contributors may be used to endorse or promote + products derived from this Software without + specific prior written permission. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF + ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED + TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A + PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT + SHALL THE CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE + FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT + OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS WITH THE SOFTWARE. + + ======================================================== + + Copyright (c) 2009-2014 by the contributors listed in + CREDITS.TXT + + Permission is hereby granted, free of charge, to any + person obtaining a copy of this software and associated + documentation files (the "Software"), to deal in the + Software without restriction, including without + limitation the rights to use, copy, modify, merge, + publish, distribute, sublicense, and/or sell copies of + the Software, and to permit persons to whom the Software + is furnished to do so, subject to the following + conditions: + + The above copyright notice and this permission notice + shall be included in all copies or substantial portions + of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF + ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED + TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A + PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT + SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR + IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + +* Portions of the FFI code for interacting with the native ABI + is derived from the Clay programming language, which carries + the following license. + + Copyright (C) 2008-2010 Tachyon Technologies. + All rights reserved. + + Redistribution and use in source and binary forms, with + or without modification, are permitted provided that the + following conditions are met: + + 1. Redistributions of source code must retain the above + copyright notice, this list of conditions and the + following disclaimer. + + 2. Redistributions in binary form must reproduce the + above copyright notice, this list of conditions and + the following disclaimer in the documentation and/or + other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + DEVELOPERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + OF SUCH DAMAGE. + +* libbacktrace, under src/libbacktrace: + + Copyright (C) 2012-2014 Free Software Foundation, Inc. + Written by Ian Lance Taylor, Google. + + Redistribution and use in source and binary forms, with + or without modification, are permitted provided that the + following conditions are met: + + (1) Redistributions of source code must retain the + above copyright notice, this list of conditions and + the following disclaimer. + + (2) Redistributions in binary form must reproduce + the above copyright notice, this list of conditions + and the following disclaimer in the documentation + and/or other materials provided with the + distribution. + + (3) The name of the author may not be used to + endorse or promote products derived from this + software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + OF SUCH DAMAGE. */ \ No newline at end of file diff --git a/compiler_base/parallel/src/executor/README.md b/compiler_base/parallel/src/executor/README.md new file mode 100644 index 000000000..1e6cefa5d --- /dev/null +++ b/compiler_base/parallel/src/executor/README.md @@ -0,0 +1,3 @@ +[`TimeoutExecutor`] in [`timeout.rs`] is implemented with the same concurrency mechanism of method [`run_tests`] in [https://github.com/rust-lang/rust/blob/master/library/test/src/lib.rs]. + +If anyone feels uncomfortable, please feel free to contact us. \ No newline at end of file diff --git a/compiler_base/parallel/src/executor/mod.rs b/compiler_base/parallel/src/executor/mod.rs new file mode 100644 index 000000000..5cb0c108a --- /dev/null +++ b/compiler_base/parallel/src/executor/mod.rs @@ -0,0 +1,171 @@ +//! This file provides everything to define a [`Executor`] that can execute [`crate::task::Task`]. +use std::{ + sync::{mpsc::Sender, Arc, Mutex}, + thread::{self, JoinHandle}, +}; + +use super::task::{event::TaskEvent, FinishedTask, Task}; +use anyhow::Result; + +pub mod timeout; + +#[cfg(test)] +mod tests; + +/// [`Executor`] can execute [`Task`] concurrently. +/// +/// The following example is just to show how [`Task`] and [`Executor`] work. +/// It's not a guarantee that the following code is bug-free. +/// +/// # Examples +/// +/// ```rust +/// use compiler_base_parallel::task::TaskInfo; +/// use compiler_base_parallel::task::event::TaskEvent; +/// use compiler_base_parallel::task::Task; +/// use compiler_base_parallel::task::TaskStatus; +/// use std::sync::mpsc::Sender; +/// use std::sync::mpsc::channel; +/// use compiler_base_parallel::task::FinishedTask; +/// use compiler_base_parallel::executor::Executor; +/// use compiler_base_parallel::task::event::TaskEventType; +/// use std::thread; +/// use std::io; +/// use anyhow::Result; +/// +/// // 1. First, we need to prepare a method to display to the log. +/// // Print the information. +/// fn print_log(event: TaskEvent) -> Result<()> { +/// match event.ty() { +/// TaskEventType::Start => { +/// println!("Task {} start.", event.tinfo()) +/// } +/// TaskEventType::Wait => { +/// println!("Task {} waiting.", event.tinfo()) +/// } +/// TaskEventType::Timeout(_) => { +/// println!("Task {} timeout.", event.tinfo()) +/// } +/// TaskEventType::Finished(ft) => { +/// println!("Task {} finished {}", event.tinfo(), ft) +/// } +/// } +/// Ok(()) +/// } +/// +/// // 2. Define a custom executor [`MyExec`] for test. +/// pub(crate) struct MyExec { +/// pub(crate) num: usize, +/// } +/// +/// // 3. Implement trait [`Executor`] for [`MyExec`]. +/// impl Executor for MyExec { +/// fn run_all_tasks(self, tasks: &[T], _notify_what_happened: F) -> Result<()> +/// where +/// T: Task + Clone + Sync + Send + 'static, +/// F: Fn(TaskEvent) -> Result<()>, +/// { +/// // The channel for communication. +/// let (tx, rx) = channel::(); +/// +/// // Load all tasks into the thread and execute. +/// let tasks = tasks.to_vec(); +/// let mut threads = vec![]; +/// let mut t_infos = vec![]; +/// for t in tasks { +/// t_infos.push(t.info()); +/// let ch = tx.clone(); +/// threads.push(thread::spawn(move || t.run(ch))); +/// } +/// +/// // Get all the task results and display to the log. +/// for ti in t_infos { +/// let _res = rx.recv().unwrap(); +/// _notify_what_happened(TaskEvent::finished(ti, _res))?; +/// } +/// Ok(()) +/// } +/// +/// fn concurrency_capacity(&self) -> usize { +/// self.num +/// } +/// } +/// +/// // 4. Define a custom task [`MyTask`] for test. +/// #[derive(Clone)] +/// struct MyTask { +/// id: usize, +/// name: String, +/// } +/// +/// impl MyTask { +/// pub fn new(id: usize, name: String) -> Self { +/// Self { id, name } +/// } +/// } +/// // 5. Implement trait [`Task`] for [`MyTask`]. +/// impl Task for MyTask { +/// fn run(&self, ch: Sender) { +/// // [`FinishedTask`] is constructed here passed to other threads via [`ch`]. +/// ch.send(FinishedTask::new( +/// TaskInfo::new(self.id.into(), self.name.clone().into()), +/// vec![], +/// vec![], +/// TaskStatus::Finished, +/// )) +/// .unwrap(); +/// } +/// +/// fn info(&self) -> TaskInfo { +/// TaskInfo::new(self.id.into(), self.name.clone().into()) +/// } +/// } +/// +/// // Create an [`Executor`] with thread count 10. +/// let my_exec = MyExec { num: 10 }; +/// +/// // Create [`Task`]s +/// let my_tasks = vec![ +/// MyTask { id: 0, name:"MyTask0".to_string() }, +/// MyTask { id: 1, name:"MyTask1".to_string() }, +/// MyTask { id: 2, name:"MyTask2".to_string() }, +/// ]; +/// my_exec.run_all_tasks(&my_tasks, |x| print_log(x)).unwrap(); +/// ``` +pub trait Executor { + /// [`run_all_tasks`] will execute all tasks concurrently. + /// [`notify_what_happened`] is a notifier that receives [`TaskEvent`] to output the [`Task`] execution status in to the log. + fn run_all_tasks(self, tasks: &[T], notify_what_happened: F) -> Result<()> + where + T: Task + Clone + Sync + Send + 'static, + F: Fn(TaskEvent) -> Result<()>; + + /// The count for threads. + fn concurrency_capacity(&self) -> usize; +} + +/// [`start_task`] is mainly used to load the method of [`Task`] into the thread and start the execution, +/// and return the [`JoinHandle<()>`] of the corresponding thread. +/// If the current platform does not support multi-threading, +/// it directly executes the method and returns [`None`]. +/// +/// [`ch`] is used to communicate with the method loaded into the thread. +pub(crate) fn start_task(task: T, ch: Sender) -> Option> +where + T: Task + Sync + Send + 'static, +{ + let tname = task.info(); + let run_task = move || task.run(ch); + let supports_threads = !cfg!(target_os = "emscripten") && !cfg!(target_family = "wasm"); + if supports_threads { + let tb = thread::Builder::new().name(tname.into()); + let run_task = Arc::new(Mutex::new(Some(run_task))); + match tb.spawn(move || run_task.lock().unwrap().take().unwrap()()) { + Ok(handle) => Some(handle), + Err(e) => panic!("failed to spawn thread to run test: {e}"), + } + } else { + run_task(); + None + } +} diff --git a/compiler_base/parallel/src/executor/test_reporter/output b/compiler_base/parallel/src/executor/test_reporter/output new file mode 100644 index 000000000..eb9803839 --- /dev/null +++ b/compiler_base/parallel/src/executor/test_reporter/output @@ -0,0 +1,20 @@ +[2023-03-14][10:49:48][Task][INFO] waiting +[2023-03-14][10:49:48][Task][INFO] waiting +[2023-03-14][10:49:48][Task][INFO] waiting +[2023-03-14][10:49:48][Task][INFO] waiting +[2023-03-14][10:49:48][Task][INFO] waiting +[2023-03-14][10:49:48][Task][INFO] waiting +[2023-03-14][10:49:48][Task][INFO] waiting +[2023-03-14][10:49:48][Task][INFO] waiting +[2023-03-14][10:49:48][Task][INFO] waiting +[2023-03-14][10:49:48][Task][INFO] waiting +[2023-03-14][10:49:48][Task][INFO] finished +[2023-03-14][10:49:48][Task][INFO] finished +[2023-03-14][10:49:48][Task][INFO] finished +[2023-03-14][10:49:48][Task][INFO] finished +[2023-03-14][10:49:48][Task][INFO] finished +[2023-03-14][10:49:48][Task][INFO] finished +[2023-03-14][10:49:48][Task][INFO] finished +[2023-03-14][10:49:48][Task][INFO] finished +[2023-03-14][10:49:48][Task][INFO] finished +[2023-03-14][10:49:48][Task][INFO] finished diff --git a/compiler_base/parallel/src/executor/tests.rs b/compiler_base/parallel/src/executor/tests.rs new file mode 100644 index 000000000..ae0fa9b6d --- /dev/null +++ b/compiler_base/parallel/src/executor/tests.rs @@ -0,0 +1,350 @@ +#[allow(unused)] +mod test_timeout_executor { + use std::{ + collections::{HashMap, HashSet}, + io, + io::Write, + panic, + sync::{mpsc::channel, Arc, Mutex}, + thread, + time::{Duration, Instant}, + }; + + use anyhow::Result; + use rand::Rng; + + use crate::{ + executor::{timeout::TimeoutExecutor, Executor}, + task::{ + event::TaskEvent, + reporter::{ + file_reporter_init, report_event, report_event_details, report_event_short_message, + std_reporter_init, + }, + FinishedTask, Task, TaskInfo, TaskStatus, + }, + }; + + /// Prepare the expected events with stdout in the unit tests. + fn generate_task_events_with_finished_stdout(tasks: Vec, stdout: String) -> Vec + where + T: Task + Clone, + { + let wait_tasks = tasks.clone(); + let mut res = vec![]; + let mut wait_events: Vec = wait_tasks + .into_iter() + .map(|t| TaskEvent::wait(t.info())) + .collect(); + + let finished_tasks = tasks; + let mut finished_events: Vec = finished_tasks + .into_iter() + .map(|t| { + TaskEvent::finished( + t.info(), + FinishedTask::new( + t.info(), + stdout.as_bytes().to_vec(), + vec![], + TaskStatus::Finished, + ), + ) + }) + .collect(); + + res.append(&mut wait_events); + res.append(&mut finished_events); + res + } + + /// Collect events triggered during task execution. + fn capture_events(event: TaskEvent, out: &mut Arc>) -> Result<()> { + writeln!(out.lock().unwrap(), "{}", event); + Ok(()) + } + + #[derive(Clone)] + /// Custom [`Task`] for testing + struct MyTask { + id: usize, + } + + impl Task for MyTask { + fn run(&self, ch: std::sync::mpsc::Sender) { + ch.send(FinishedTask::new( + TaskInfo::new(self.id.into(), "Task".to_string().into()), + "Hello World".to_string().as_bytes().to_vec(), + vec![], + TaskStatus::Finished, + )) + .unwrap(); + } + + fn info(&self) -> TaskInfo { + TaskInfo::new(self.id.into(), "Task".to_string().into()) + } + } + + #[derive(Default)] + /// [`EventsCollector`] used to collected [`TaskEvent`]s for testing. + struct EventsCollector { + pub(crate) events_str: String, + } + + impl EventsCollector { + pub fn clean(&mut self) -> &mut Self { + self.events_str = String::new(); + self + } + } + + impl Write for EventsCollector { + fn write(&mut self, buf: &[u8]) -> io::Result { + if let Ok(s) = std::str::from_utf8(buf) { + self.events_str.push_str(s) + } + Ok(buf.len()) + } + + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } + } + + #[cfg(not(target_os = "windows"))] + const NEW_LINE: &str = "\n"; + #[cfg(target_os = "windows")] + const NEW_LINE: &'static str = "\r\n"; + + fn run_my_task_with_thread_num(task_count: usize, thread_count: usize) { + let mut tasks = vec![]; + + for i in 0..task_count { + tasks.push(MyTask { id: i }) + } + + let executor = TimeoutExecutor::new_with_thread_count_and_timeout( + thread_count, + Instant::now() + Duration::from_secs(120), + ); + + let mut events_collector = Arc::new(Mutex::new(EventsCollector::default())); + + let expected_events = + generate_task_events_with_finished_stdout(tasks.clone(), "Hello World".to_string()); + + expected_events.into_iter().for_each(|e| { + capture_events(e, &mut Arc::clone(&events_collector)); + }); + + let mut expected_events_strs: Vec = events_collector + .lock() + .unwrap() + .events_str + .clone() + .split(NEW_LINE) + .map(|s| s.to_string()) + .collect(); + + events_collector.lock().unwrap().clean(); + + executor + .run_all_tasks(&tasks, |e| { + capture_events(e, &mut Arc::clone(&events_collector)) + }) + .unwrap(); + + let mut got_events_strs: Vec = events_collector + .lock() + .unwrap() + .events_str + .clone() + .split(NEW_LINE) + .map(|s| s.to_string()) + .collect(); + + got_events_strs.sort(); + expected_events_strs.sort(); + assert_eq!(got_events_strs, expected_events_strs); + } + + #[test] + /// Run for 1 minute with a random number (0 to 100000) of threads and tasks + fn test_tasks_executor() { + let start_time = Instant::now(); + + loop { + let random_thread_number = rand::thread_rng().gen_range(1..=100000); + let random_task_number = rand::thread_rng().gen_range(1..=100000); + + run_my_task_with_thread_num(random_task_number, random_thread_number); + + if Instant::now().duration_since(start_time) > Duration::from_secs(60) { + break; + } + } + } + + #[test] + fn test_tasks_executor_with_zero_thread() { + let result: Result<(), Box> = std::panic::catch_unwind(|| { + run_my_task_with_thread_num(1, 0); + }); + assert!(result.is_err()); + } + + #[test] + fn test_tasks_executor_with_zero_task() { + run_my_task_with_thread_num(0, 1); + } + + #[derive(Clone)] + /// Custom [`Task`] for testing, + /// [`OnlyPanicTask`] will do nothing in addition to panic. + struct OnlyPanicTask { + id: usize, + } + + impl Task for OnlyPanicTask { + /// Only panic. + fn run(&self, ch: std::sync::mpsc::Sender) { + panic!("This Task Panic.") + } + + fn info(&self) -> TaskInfo { + TaskInfo::new(self.id.into(), "PanicTask".to_string().into()) + } + } + + #[test] + /// If the task fails and returns nothing, + /// it will wait for the task to complete, + /// and a timeout message will be printed if the wait times out. + fn test_panic_tasks_executor() { + let mut tasks = vec![OnlyPanicTask { id: 0 }]; + + let executor = TimeoutExecutor::new_with_thread_count(2); + let mut events_collector = Arc::new(Mutex::new(EventsCollector::default())); + + events_collector.lock().unwrap().clean(); + + let (tx, rx) = channel::(); + let events_collector_tmp = Arc::clone(&events_collector); + let handle = thread::spawn(move || { + executor + .run_all_tasks(&tasks, |e| { + capture_events(e, &mut Arc::clone(&events_collector_tmp)) + }) + .unwrap(); + tx.send("Unreachable Code".to_string()); + }); + + let timeout = Duration::from_secs(70); + match rx.recv_timeout(timeout) { + Ok(_) => { + panic!("unreachable code"); + } + Err(_) => { + assert_eq!(events_collector + .lock() + .unwrap() + .events_str, + "tname:PanicTask tid:0 event:waiting\ntname:PanicTask tid:0 event:timeout 59s\n"); + handle.thread().unpark(); + } + } + } + + #[derive(Clone)] + /// Custom [`Task`] for testing, + /// [`PanicAfterReturnTask`] will panic after return result. + struct PanicAfterReturnTask { + id: usize, + } + + impl Task for PanicAfterReturnTask { + /// panic and return. + fn run(&self, ch: std::sync::mpsc::Sender) { + ch.send(FinishedTask::new( + TaskInfo::new(self.id.into(), "PanicAfterReturnTask".to_string().into()), + "Hello World".to_string().as_bytes().to_vec(), + vec![], + TaskStatus::Finished, + )) + .unwrap(); + panic!("This task panic after return result.") + } + + fn info(&self) -> TaskInfo { + TaskInfo::new(self.id.into(), "PanicAfterReturnTask".to_string().into()) + } + } + + #[test] + /// If the task is done, but the thread panics after getting the task done, + /// the [`run_all_tasks`] will return an [`io::Error`]. + fn test_panic_after_return_tasks_executor() { + let mut tasks = vec![PanicAfterReturnTask { id: 0 }]; + let executor = TimeoutExecutor::new_with_thread_count(2); + let mut events_collector = Arc::new(Mutex::new(EventsCollector::default())); + tasks + .clone() + .into_iter() + .map(|t| TaskEvent::wait(t.info())) + .for_each(|e| { + capture_events(e, &mut Arc::clone(&events_collector)); + }); + + let mut expected_events_strs: Vec = events_collector + .lock() + .unwrap() + .events_str + .clone() + .split(NEW_LINE) + .map(|s| s.to_string()) + .collect(); + + events_collector.lock().unwrap().clean(); + + let result: Result, Box> = + std::panic::catch_unwind(|| { + executor.run_all_tasks(&tasks, |e| { + capture_events(e, &mut Arc::clone(&events_collector)) + }) + }); + + let mut got_events_strs: Vec = events_collector + .lock() + .unwrap() + .events_str + .clone() + .split(NEW_LINE) + .map(|s| s.to_string()) + .collect(); + + got_events_strs.sort(); + expected_events_strs.sort(); + assert_eq!(got_events_strs, expected_events_strs); + + match result { + Ok(res) => match res { + Ok(_) => { + panic!("unreachable code"); + } + Err(err) => { + assert_eq!( + format!("{}", err), + format!( + "The task {} has completed, but the thread has failed", + PanicAfterReturnTask { id: 0 }.info() + ) + ); + } + }, + Err(_) => { + panic!("unreachable code"); + } + } + } +} diff --git a/compiler_base/parallel/src/executor/timeout.rs b/compiler_base/parallel/src/executor/timeout.rs new file mode 100644 index 000000000..8d9bf0682 --- /dev/null +++ b/compiler_base/parallel/src/executor/timeout.rs @@ -0,0 +1,214 @@ +//!This file provides a concrete implementation [`TimeoutExecutor`] of [`Executor`]. +//! [`TimeoutExecutor`] is a [`Executor`] with a timeout queue that can monitor the timeout situation of [`Task`]s. +use std::{ + collections::{HashMap, VecDeque}, + sync::mpsc::{channel, RecvTimeoutError}, + time::{Duration, Instant}, +}; + +use crate::task::{ + event::TaskEvent, FinishedTask, RunningTask, Task, TaskId, TaskInfo, TaskStatus, +}; + +use super::{start_task, Executor}; +use anyhow::{bail, Result}; + +/// [`TimeoutSituation`] is an internal structure for the timeout situation of a [`Task`]. +pub(crate) struct TimeoutSituation { + tinfo: TaskInfo, + deadline: Instant, +} + +/// [`TimeoutExecutor`] is a [`Executor`] with a timeout queue. +/// [`TimeoutExecutor`] is used in the same way as [`Executor`], +/// for more information, see doc [`Executor`]. +pub struct TimeoutExecutor { + timeout_queue: VecDeque, + capacity: usize, + timeout: Option, +} + +impl TimeoutExecutor { + /// New a [`TimeoutExecutor`] with [`thread_count`]. + pub fn new_with_thread_count(thread_count: usize) -> Self { + debug_assert!( + thread_count > 0, + "At least one thread is required to execute the task." + ); + TimeoutExecutor { + timeout_queue: VecDeque::default(), + capacity: thread_count, + timeout: Some(default_deadline_60_seconds()), + } + } + + /// New a [`TimeoutExecutor`] with [`thread_count`] and [`timeout`]. + pub fn new_with_thread_count_and_timeout(thread_count: usize, timeout: Instant) -> Self { + debug_assert!( + thread_count > 0, + "At least one thread is required to execute the task." + ); + TimeoutExecutor { + timeout_queue: VecDeque::default(), + capacity: thread_count, + timeout: Some(timeout), + } + } + + /// Find all the timeout [`Task`] from the running tasks and return their [`TaskId`]. + fn all_timed_out_tasks_info( + &mut self, + running_tasks: &HashMap, + ) -> Vec { + let now = Instant::now(); + let mut timed_out = Vec::new(); + while let Some(timeout_entry) = self.timeout_queue.front() { + if now < timeout_entry.deadline { + break; + } + // Note: [`TimeoutSituation`]s of [`Task`]s that have timed out are removed from the queue. + let timeout_entry = self.timeout_queue.pop_front().unwrap(); + if running_tasks.contains_key(&timeout_entry.tinfo.tid()) { + timed_out.push(timeout_entry.tinfo); + } + } + timed_out + } + + /// [`deadline`] will return how long until the front of the queue has timed out, + /// [`Duration::new(0, 0)`] if it has already timed out, and [`None`] if the queue is empty. + fn deadline(&self) -> Option { + self.timeout_queue + .front() + .map(|&TimeoutSituation { deadline, .. }| { + let now = Instant::now(); + if deadline >= now { + deadline - now + } else { + Duration::new(0, 0) + } + }) + } +} + +impl Executor for TimeoutExecutor { + fn run_all_tasks(mut self, tasks: &[T], notify_what_happened: F) -> Result<()> + where + T: Task + Clone + Sync + Send + 'static, + F: Fn(TaskEvent) -> Result<()>, + { + // The channel for communication. + let (tx, rx) = channel::(); + // All the [`Task`]s are waiting to be loaded into the thread. + let mut waiting_tasks = VecDeque::from(tasks.to_vec()); + let mut running_tasks = HashMap::::default(); + let mut running_count = 0; + + // Load tasks into threads + while running_count > 0 || !waiting_tasks.is_empty() { + while running_count < self.concurrency_capacity() && !waiting_tasks.is_empty() { + // Pop a [`Task`]. + let task = waiting_tasks.pop_front().unwrap(); + let tid = task.info().tid(); + let tinfo = task.info(); + + // Calculate the deadline. + let deadline = if let Some(timeout) = self.timeout { + timeout + } else { + default_deadline_60_seconds() + }; + + // Notify the log that the [`Task`] is waiting to be executed. + let event = TaskEvent::wait(task.info()); + notify_what_happened(event)?; + + // Load the [`Task`] into the thread for execution, + // and return the [`JoinHandler`] corresponding to the thread. + let join_handle = start_task(task, tx.clone()); + + // Create [`RunningTask`] to manage thread after startup + + running_tasks.insert(tid, RunningTask { join_handle }); + + // The [`TimeoutSituation`] of the current task is added to the queue. + self.timeout_queue + .push_back(TimeoutSituation { tinfo, deadline }); + running_count += 1; + } + + // Wait for the result of the [`Task`] execution + let mut res; + loop { + if let Some(timeout) = self.deadline() { + // Waiting. + res = rx.recv_timeout(timeout); + // Notify the log that the [`Task`] is timeout. + for tid in self.all_timed_out_tasks_info(&running_tasks) { + notify_what_happened(TaskEvent::time_out(tid, timeout))?; + } + // Note: If the result of [`Task`] is not ready, it will wait for the result. + if res.is_ok() { + break; + }; + } else { + res = rx.recv().map_err(|_| RecvTimeoutError::Disconnected); + break; + } + } + + // Get the result of [`Task`] execution from channel. + let mut finished_task = res.unwrap(); + + // Get the thread [`JoinHandler<()>`] corresponding to the [`Task`]. + let running_task = match running_tasks.remove(&finished_task.tinfo().tid()) { + Some(rs) => rs, + None => { + panic!( + "size id {}, {}", + running_tasks.len(), + finished_task.tinfo() + ) + } + }; + + // And wait for the end of thread execution through [`join`]. + running_task.join(&mut finished_task); + + let fail = match finished_task.status() { + // Only a bug will stop the testing process immediately, + TaskStatus::Bug(_) => { + std::mem::forget(rx); + bail!( + "The task {} has completed, but the thread has failed", + finished_task.tinfo() + ); + } + _ => false, + }; + + // Notify the log that the [`Task`] finished. + let event = TaskEvent::finished(finished_task.tinfo(), finished_task); + + notify_what_happened(event)?; + running_count -= 1; + + if fail { + // Prevent remaining threads from panicking + std::mem::forget(rx); + return Ok(()); + } + } + Ok(()) + } + + fn concurrency_capacity(&self) -> usize { + self.capacity + } +} + +/// Calculate the result of current time add the default timeout 60 seconds. +pub(crate) fn default_deadline_60_seconds() -> Instant { + pub(crate) const _TIMEOUT_S: u64 = 60; + Instant::now() + Duration::from_secs(_TIMEOUT_S) +} diff --git a/compiler_base/parallel/src/lib.rs b/compiler_base/parallel/src/lib.rs new file mode 100644 index 000000000..c0d1bcbcd --- /dev/null +++ b/compiler_base/parallel/src/lib.rs @@ -0,0 +1,2 @@ +pub mod executor; +pub mod task; diff --git a/compiler_base/parallel/src/task/event.rs b/compiler_base/parallel/src/task/event.rs new file mode 100644 index 000000000..4f27dac1d --- /dev/null +++ b/compiler_base/parallel/src/task/event.rs @@ -0,0 +1,102 @@ +//! This file provides [`TaskEvent`], +//! which tells the logging system to display information. +use std::time::Duration; + +use serde::{Deserialize, Serialize}; + +use super::{FinishedTask, TaskInfo}; + +#[derive(Clone, Serialize, Deserialize)] +/// [`TaskEvent`] is an event that triggers the log displaying. +pub struct TaskEvent { + tinfo: TaskInfo, + ty: TaskEventType, +} + +impl std::fmt::Display for TaskEvent { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{} event:{}", self.tinfo(), self.ty) + } +} + +impl PartialEq for TaskEvent { + fn eq(&self, other: &Self) -> bool { + self.tinfo == other.tinfo && self.ty == other.ty + } +} + +impl TaskEvent { + /// Get [`super::TaskInfo`] about the [`super::Task`] that emitted this event. + pub fn tinfo(&self) -> TaskInfo { + self.tinfo.clone() + } + + /// Get [`TaskEventType`] + pub fn ty(&self) -> TaskEventType { + self.ty.clone() + } + + /// New a [`TaskEvent`] with [TaskEventType::Start]. + pub fn start(tinfo: TaskInfo) -> Self { + Self { + tinfo, + ty: TaskEventType::Start, + } + } + + /// New a [`TaskEvent`] with [TaskEventType::Wait]. + pub fn wait(tinfo: TaskInfo) -> Self { + Self { + tinfo, + ty: TaskEventType::Wait, + } + } + + /// New a [`TaskEvent`] with [TaskEventType::Timeout]. + pub fn time_out(tinfo: TaskInfo, deadline: Duration) -> Self { + Self { + tinfo, + ty: TaskEventType::Timeout(deadline), + } + } + + /// New a [`TaskEvent`] with [TaskEventType::Finished]. + pub fn finished(tinfo: TaskInfo, finished_task: FinishedTask) -> Self { + Self { + tinfo, + ty: TaskEventType::Finished(finished_task), + } + } +} + +#[derive(Clone, Serialize, Deserialize)] +/// [`TaskEventType`] is the event type of [`TaskEvent`]. +pub enum TaskEventType { + Start, + Wait, + Timeout(Duration), + Finished(FinishedTask), +} + +impl std::fmt::Display for TaskEventType { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + match self { + TaskEventType::Start => write!(f, "start"), + TaskEventType::Wait => write!(f, "waiting"), + TaskEventType::Timeout(t) => write!(f, "timeout {}s", t.as_secs()), + TaskEventType::Finished(ft) => write!(f, "finished {}", ft), + } + } +} + +impl PartialEq for TaskEventType { + fn eq(&self, other: &Self) -> bool { + match (self, other) { + (TaskEventType::Start, TaskEventType::Start) + | (TaskEventType::Wait, TaskEventType::Wait) => true, + (TaskEventType::Timeout(t1), TaskEventType::Timeout(t2)) => t1 == t2, + (TaskEventType::Finished(f1), TaskEventType::Finished(f2)) => f1 == f2, + _ => false, + } + } +} diff --git a/compiler_base/parallel/src/task/mod.rs b/compiler_base/parallel/src/task/mod.rs new file mode 100644 index 000000000..64d204c36 --- /dev/null +++ b/compiler_base/parallel/src/task/mod.rs @@ -0,0 +1,382 @@ +//! This file provides everything to define a [`Task`] that an [`crate::executor::Executor`] can execute. +use std::{fmt, sync::mpsc::Sender, thread}; + +use serde::{Deserialize, Serialize}; +pub mod event; +pub mod reporter; + +/// [`Task`] is the unit that [`crate::executor::Executor`] can execute concurrently. +/// +/// # Example +/// +/// ```rust +/// use compiler_base_parallel::task::Task; +/// use compiler_base_parallel::task::FinishedTask; +/// use std::sync::mpsc::channel; +/// use std::sync::mpsc::Sender; +/// use compiler_base_parallel::task::TaskName; +/// use compiler_base_parallel::task::TaskId; +/// use compiler_base_parallel::task::TaskInfo; +/// use compiler_base_parallel::task::TaskStatus; +/// +/// // 1. Define a custom task [`MyTask`]. +/// struct MyTask { +/// id: usize, +/// name: String, +/// } +/// +/// // 2. Implement trait [`Task`] for [`MyTask`]. +/// impl Task for MyTask { +/// fn run(&self, ch: Sender) { +/// // [`FinishedTask`] is constructed here passed to other threads via [`ch`]. +/// let res = FinishedTask::new(self.info(), vec![], vec![], TaskStatus::Finished); +/// ch.send(res).unwrap(); +/// } +/// +/// fn info(&self) -> TaskInfo { +/// TaskInfo::new(self.id.into(), self.name.to_string().into()) +/// } +/// } +/// +/// impl MyTask { +/// pub fn new(id: usize, name: String) -> Self { +/// Self { id, name } +/// } +/// } +/// +/// // 3. Create [`channel`] to pass [`FinishedTask`]. +/// let (tx, rx) = channel::(); +/// let my_task = MyTask::new(0, "MyTask 0".to_string()); +/// my_task.run(tx); +/// +/// // 4. [`FinishedTask`] created in [`Task`] will be got from channel. +/// match rx.recv() { +/// Ok(res) => { +/// assert_eq!(res.tinfo().tid(), 0.into()); +/// assert_eq!(res.tinfo().tname(), "MyTask 0".to_string().into()); +/// assert_eq!(res.status(), TaskStatus::Finished); +/// }, +/// Err(_) => panic!("unreachable code") +/// } +/// ``` +pub trait Task { + /// [`run`] will be executed of the [`Task`], + /// and the result of the execution is communicated with other threads through the [`ch`] which is a [`Sender`], + /// so [`run`] method does not need to return a value. + /// + /// Note: If the [`run`] method panics before returning the result through the [`ch`], + /// nothing will be output, and the outside world will not be able to get the running status of the task. + /// Therefore, when implementing the [`run`] method, + /// please try to handle the failure case as much as possible to ensure that all result can be sent to [`ch`]. + /// + /// If you can not get the results properly and you are confident that all the possible results are returned through [`ch`], + /// please contact us, this maybe a bug. + fn run(&self, ch: Sender); + + /// Return the [`TaskInfo`] + fn info(&self) -> TaskInfo; +} + +#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)] +pub struct TaskInfo { + tid: TaskId, + tname: TaskName, +} + +impl TaskInfo { + pub fn new(tid: TaskId, tname: TaskName) -> Self { + Self { tid, tname } + } + + pub fn tid(&self) -> TaskId { + self.tid + } + + pub fn tname(&self) -> TaskName { + self.tname.clone() + } +} + +impl From for String { + fn from(info: TaskInfo) -> Self { + format!("{}", info) + } +} + +impl std::fmt::Display for TaskInfo { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "tname:{} tid:{}", self.tname(), self.tid()) + } +} + +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)] +/// The ID for the [`Task`]. +/// [`TaskId`] will be used as the key of the [`HashMap`], [`TaskId`] is a type alias of [`usize`]. +/// so [`TaskID`] should be unique to each [`Task`]. +pub struct TaskId(usize); + +impl From for TaskId { + fn from(u: usize) -> Self { + TaskId(u) + } +} + +impl TaskId { + /// New a [`TaskId`] + pub fn new(id: usize) -> Self { + TaskId(id) + } +} + +impl std::fmt::Display for TaskId { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.0) + } +} + +#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)] +/// The name for the [`Task`]. +/// [`TaskName`] will be used to log displaying, [`TaskName`] is a type alias of [`String`]. +pub struct TaskName(String); + +impl From for TaskName { + fn from(s: String) -> Self { + TaskName(s) + } +} + +impl std::fmt::Display for TaskName { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.0) + } +} + +impl From for String { + fn from(task_name: TaskName) -> Self { + task_name.0 + } +} + +#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)] +/// [`TaskStatus`] is the execution status of [`Task`] and is part of the result returned. +/// At present, it mainly includes three parts: +/// - [`TaskStatus::Finished`]: The [`Task`] has been finished. +/// - [`TaskStatus::Waiting`]: The [`Task`] is running or waiting and can not get the results. +/// - [`TaskStatus::Failed(String)`]: The failure status contains a String argument that holds some information about the exception. +/// - [`TaskStatus::Bug(String)`]: Bug means that the failure of the [`Task`] is caused by a bug. +pub enum TaskStatus { + /// The [`Task`] has been finished. + Finished, + /// The [`Task`] is running or waiting and can not get the results. + Waiting, + /// The [`Task`] is failed, and this status contains a [`String`] argument that holds some information about the exception. + Failed(String), + /// Bug means that the failure of the [`Task`] is caused by a bug. + Bug(String), +} + +impl std::fmt::Display for TaskStatus { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + TaskStatus::Finished => { + write!(f, "{}", "finished") + } + TaskStatus::Waiting => { + write!(f, "{}", "waiting") + } + TaskStatus::Failed(reason) => { + write!(f, "{}:{}", "failed", reason) + } + TaskStatus::Bug(reason) => { + write!(f, "{}:{}", "bug", reason) + } + } + } +} + +#[derive(Clone, Serialize, Deserialize)] +/// [`FinishedTask`] represents the execution result of the [`Task`]. +pub struct FinishedTask { + tinfo: TaskInfo, + stdout: Vec, + stderr: Vec, + status: TaskStatus, +} + +impl PartialEq for FinishedTask { + fn eq(&self, other: &Self) -> bool { + self.tinfo == other.tinfo + && self.stdout == other.stdout + && self.stderr == other.stderr + && self.status == other.status + } +} + +impl std::fmt::Display for FinishedTask { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!( + f, + "{} finished\nstdout:\n{}\nstderr:\n{}\nstatus:{}", + self.tinfo(), + String::from_utf8_lossy(&self.stdout()), + String::from_utf8_lossy(&self.stderr()), + self.status + ) + } +} + +impl FinishedTask { + /// New a [`FinishedTask`] + pub fn new(tinfo: TaskInfo, stdout: Vec, stderr: Vec, status: TaskStatus) -> Self { + Self { + tinfo, + stdout, + stderr, + status, + } + } + + /// Get [`TaskInfo`] + pub fn tinfo(&self) -> TaskInfo { + self.tinfo.clone() + } + + /// Get [`TaskStatus`] + pub fn status(&self) -> TaskStatus { + self.status.clone() + } + + /// Get the stdout for the [`Task`] in [`Vec`]. + pub fn stdout(&self) -> Vec { + self.stdout.clone() + } + + /// Get the stderr for the [`Task`] in [`Vec`]. + pub fn stderr(&self) -> Vec { + self.stderr.clone() + } + + /// Find a bug and set status. + pub fn find_bug(&mut self, info: String) { + self.status = TaskStatus::Bug(info) + } + + /// Display the short message for [`FinishedTask`]. + pub fn short_msg(&self) -> String { + format!("{} finished, status:{}\n", self.tinfo(), self.status) + } + + /// Display the detailed message for [`FinishedTask`]. + pub fn details(&self) -> String { + format!( + "\n{} finished\nstdout:{}\nstderr:{}\nstatus:{}\n", + self.tinfo(), + String::from_utf8_lossy(&self.stdout()), + String::from_utf8_lossy(&self.stderr()), + self.status + ) + } +} + +/// [`RunningTask`] is an internal structure to manage threads after startup. +/// It contains only one member, whose type is the [`std::thread::JoinHandle`] returned by [`std::thread::spawn`]. +/// Once [`Task`] has been loaded into the thread and started, +/// [`crate::executor::Executor`] controls the running threads by [`RunningTask`]. +pub(crate) struct RunningTask { + pub(crate) join_handle: Option>, +} + +impl RunningTask { + /// Call the [`join`] and wait for the associated thread to finish. + pub(crate) fn join(self, task: &mut FinishedTask) { + if let Some(join_handle) = self.join_handle { + // If [`Task`] returns [`TaskStatus::Finished`], that means [`Task`] is running correctly, + // but the thread executing the [`Task`] returns an error, that means there's a bug. + if join_handle.join().is_err() { + if let TaskStatus::Finished = task.status() { + task.find_bug(format!( + "Exception occurs after task '{}' reporting success", + task.tinfo() + )); + } + } + } + } +} + +#[allow(unused)] +mod test { + use std::{ + sync::mpsc::{channel, Sender}, + thread, + }; + + use crate::task::RunningTask; + + use super::{FinishedTask, Task, TaskInfo, TaskStatus}; + + // 1. Define a custom task [`MyTask`] for test. + struct MyTask { + id: usize, + name: String, + } + + impl MyTask { + pub fn new(id: usize, name: String) -> Self { + Self { id, name } + } + } + // 2. Implement trait [`Task`] for [`MyTask`]. + impl Task for MyTask { + fn run(&self, ch: Sender) { + // [`FinishedTask`] is constructed here passed to other threads via [`ch`]. + ch.send(FinishedTask::new( + TaskInfo::new(self.id.into(), self.name.clone().into()), + vec![], + vec![], + TaskStatus::Finished, + )) + .unwrap(); + } + + fn info(&self) -> TaskInfo { + TaskInfo::new(self.id.into(), self.name.clone().into()) + } + } + + #[test] + fn test_get_finish_task_from_mytask() { + // Create [`channel`] to pass [`FinishedTask`]. + let (tx, rx) = channel::(); + let my_task = MyTask::new(0, "MyTask 0".to_string()); + my_task.run(tx); + + // [`FinishedTask`] created in [`Task`] will be got from channel. + match rx.recv() { + Ok(res) => { + assert_eq!(res.tinfo().tid(), 0.into()); + assert_eq!(res.tinfo().tname(), "MyTask 0".to_string().into()); + assert_eq!(res.status, TaskStatus::Finished); + } + Err(_) => panic!("unreachable code"), + } + } + + #[test] + fn test_running_task_join() { + // Create [`channel`] to pass [`FinishedTask`]. + let (tx, rx) = channel::(); + let my_task = MyTask::new(0, "MyTask 0".to_string()); + let running_task = RunningTask { + join_handle: Some(thread::spawn(move || { + my_task.run(tx); + })), + }; + + let mut res = rx.recv().unwrap(); + + running_task.join(&mut res); + + assert_eq!(res.status(), TaskStatus::Finished); + } +} diff --git a/compiler_base/parallel/src/task/reporter.rs b/compiler_base/parallel/src/task/reporter.rs new file mode 100644 index 000000000..4952b2e28 --- /dev/null +++ b/compiler_base/parallel/src/task/reporter.rs @@ -0,0 +1,406 @@ +//! This file provides method to report the task execution logs. +use std::sync::Once; + +use crate::task::{ + event::{TaskEvent, TaskEventType}, + TaskStatus, +}; +use anyhow::Result; +use fern::{ + colors::{Color, ColoredLevelConfig}, + Dispatch, +}; +use log::{error, info, warn}; + +/// [`ReporterConfig`] is mainly responsible for the configuration of log display. +pub struct ReporterConfig { + level_filter: log::LevelFilter, + stdout: bool, + stderr: bool, + file_path: Option, +} + +impl ReporterConfig { + /// New a default [`ReporterConfig`]. + /// + /// Note: Since the default [`ReporterConfig`] does not define the level and destination of the log, + /// it will display nothing if you only use the default configuration. + pub fn default() -> Self { + ReporterConfig { + level_filter: log::LevelFilter::Off, + stdout: false, + stderr: false, + file_path: None, + } + } + + /// Set the [`log::LevelFilter`] for the log. + pub fn filter(mut self, level_filter: log::LevelFilter) -> Self { + self.level_filter = level_filter; + self + } + + /// Set the destination flag [std::io::Stdout]. + /// If [`true`], the log will display to [std::io::Stdout]. + pub fn stdout(mut self, is_stdout: bool) -> Self { + self.stdout = is_stdout; + self + } + + /// Set the destination flag [std::io::Stderr]. + /// If [`true`], the log will display to [std::io::Stderr]. + pub fn stderr(mut self, is_stderr: bool) -> Self { + self.stdout = is_stderr; + self + } + + /// Set the destination flag to a file. + /// The log will be displaied to a file in path [`file_path`]. + /// If [`file_path`] doesn't exist, + /// the [`init_reporter_once`] method will throw an error. + pub fn file(mut self, file_path: &str) -> Self { + self.file_path = Some(file_path.to_string()); + self + } +} + +static TIME_PATTERN: &'static str = "[%Y-%m-%d][%H:%M:%S]"; + +/// Set the color config for the log in stdout/stderr. +fn set_reporter_color() -> ColoredLevelConfig { + ColoredLevelConfig::new() + .error(Color::Red) + .warn(Color::Yellow) + .debug(Color::Blue) + .info(Color::Green) + .trace(Color::Black) +} + +/// Return the [`Dispatch`] logger, based on the [`ReporterConfig`]. +fn set_reporter_conf(conf: &ReporterConfig) -> Result { + let mut dispatch = fern::Dispatch::new() + .format(move |out, message, record| { + out.finish(format_args!( + "{}[{}][{}] {}", + chrono::Local::now().format(TIME_PATTERN), + record.target(), + set_reporter_color().color(record.level()), + message + )) + }) + .level(conf.level_filter); + + if conf.stdout { + dispatch = dispatch.chain(std::io::stdout()); + } + + if conf.stderr { + dispatch = dispatch.chain(std::io::stderr()); + } + + if let Some(file) = &conf.file_path { + dispatch = dispatch + .format(move |out, message, record| { + out.finish(format_args!( + "{}[{}][{}] {}", + chrono::Local::now().format(TIME_PATTERN), + record.target(), + record.level(), + message + )) + }) + .chain(fern::log_file(file)?); + } + Ok(dispatch) +} + +/// Generate the [`Dispatch`] logger and apply it. +/// +/// Note: The [`init_reporter`] method can be called only once, +/// so it should be run as early in the program as possible. +/// +/// # Errors: +/// +/// 1. This function will return an error if a global logger has already been +/// set to a previous logger. +/// +/// 2. This function will return an error if the path to the file in [`ReporterConfig`] +/// used for logging does not exist. +fn init_reporter(conf: &ReporterConfig) -> Result<()> { + set_reporter_conf(conf)?.apply()?; + Ok(()) +} + +/// Generate the [`Dispatch`] logger and apply it. +/// +/// Note: The [`init_reporter_once`] method can be called only once, +/// so it should be run as early in the program as possible. +/// +/// # Errors: +/// +/// This function will return an error if the path to the file in [`ReporterConfig`] +/// used for logging does not exist. +/// +/// # Note: +/// +/// Only the [`ReporterConfig`] used in the first call to the [`init_reporter_once`] is taken. +pub fn init_reporter_once(conf: &ReporterConfig) -> Result<()> { + static INIT: Once = Once::new(); + let mut result = Ok(()); + INIT.call_once(|| result = init_reporter(conf)); + result +} + +/// Initialize a file reporter with the default configuration, +/// the log will be output to a [`log_file`]. +pub fn file_reporter_init(log_file: &str) -> Result<()> { + let conf = ReporterConfig::default() + .filter(log::LevelFilter::Debug) + .stdout(true) + .stderr(true) + .file(&log_file); + init_reporter_once(&conf) +} + +/// Initialize a stdout/stderr reporter with the default configuration, +/// the log will be output to stdout/stderr. +pub fn std_reporter_init(stdout: bool, stderr: bool) -> Result<()> { + let conf = ReporterConfig::default() + .filter(log::LevelFilter::Debug) + .stdout(stdout) + .stderr(stderr); + init_reporter_once(&conf) +} + +/// Display short logs based on the received [`TaskEvent`]. +/// Based on the fecade implementation provided by [`log`]. +/// If you want to change the logging engine, you just need to implement a new [`init_reporter_once`]. +/// +/// # Note: +/// +/// Before you use this method to log, make sure that [`init_reporter_once`] is called once to initialize the logging engine. +pub fn report_event_short_message(event: TaskEvent) -> Result<()> { + match event.ty() { + TaskEventType::Start => { + info!(target: &format!("{}", event.tinfo().tname()), "start") + } + TaskEventType::Wait => { + info!(target: &format!("{}", event.tinfo().tname()), "waiting") + } + TaskEventType::Timeout(t) => { + warn!( + target: &format!("{}", event.tinfo().tname()), + "It's been running for over {} seconds", + t.as_secs() + ) + } + TaskEventType::Finished(fin_res) => match fin_res.status() { + TaskStatus::Finished | TaskStatus::Waiting => { + info!( + target: &format!("{}", event.tinfo().tname()), + "{}", + fin_res.status() + ) + } + TaskStatus::Failed(_) | TaskStatus::Bug(_) => { + error!( + target: &format!("{}", event.tinfo().tname()), + "{}", + fin_res.status() + ) + } + }, + } + Ok(()) +} + +/// Display detailed logs based on the received [`TaskEvent`]. +/// Based on the fecade implementation provided by [`log`]. +/// If you want to change the logging engine, you just need to implement a new [`init_reporter_once`]. +/// +/// # Note: +/// +/// Before you use this method to log, make sure that [`init_reporter_once`] is called once to initialize the logging engine. +pub fn report_event_details(event: TaskEvent) -> Result<()> { + match event.ty() { + TaskEventType::Start => { + info!( + target: &format!("{}", event.tinfo().tname()), + "\n{} start", + event.tinfo() + ) + } + TaskEventType::Wait => { + info!( + target: &format!("{}", event.tinfo().tname()), + "\n{} waiting", + event.tinfo() + ) + } + TaskEventType::Timeout(t) => { + warn!( + target: &format!("{}", event.tinfo().tname()), + "It's been running for over {} seconds", + t.as_secs() + ) + } + TaskEventType::Finished(fin_res) => match fin_res.status() { + TaskStatus::Finished | TaskStatus::Waiting => { + info!( + target: &format!("{}", event.tinfo().tname()), + "\n{}", fin_res + ) + } + TaskStatus::Failed(_) | TaskStatus::Bug(_) => { + error!( + target: &format!("{}", event.tinfo().tname()), + "\n{}", fin_res + ) + } + }, + } + Ok(()) +} + +/// Display logs based on the received [`TaskEvent`]. +/// Short messages will be output if the task executed normally, +/// and detailed messages will be output if the task failed. +pub fn report_event(event: TaskEvent) -> Result<()> { + match event.ty() { + TaskEventType::Start | TaskEventType::Wait | TaskEventType::Timeout(_) => { + report_event_short_message(event)?; + } + TaskEventType::Finished(fin_res) => match fin_res.status() { + TaskStatus::Finished | TaskStatus::Waiting => { + report_event_short_message(event)?; + } + TaskStatus::Failed(_) | TaskStatus::Bug(_) => { + report_event_details(event)?; + } + }, + } + Ok(()) +} + +#[cfg(test)] +mod test { + use std::{ + fs::{self, File}, + io::BufReader, + path::Path, + }; + + use crate::task::{ + event::TaskEvent, + reporter::{report_event_short_message, ReporterConfig}, + }; + + use super::{init_reporter_once, report_event_details, set_reporter_conf}; + use anyhow::Result; + use pretty_assertions::assert_eq; + + pub fn report_event_file(name: &str, report_func: &F) + where + F: Fn(TaskEvent) -> Result<()>, + { + let event_path = Path::new(EVENT_PATH).join(name); + let event_json = event_path.join(format!("{}.json", name)); + + let event: TaskEvent = + serde_json::from_reader(BufReader::new(File::open(event_json).unwrap())).unwrap(); + + report_func(event).unwrap(); + } + + pub fn expect_event_report(name: &str, expect_file_name: &str) -> String { + let event_path = Path::new(EVENT_PATH).join(name); + let expect_path = event_path.join(expect_file_name); + format!( + "{}{}", + chrono::Local::now().format("[%Y-%m-%d][%H:%M:%S]"), + fs::read_to_string(&expect_path.display().to_string()) + .expect("Something went wrong reading the file") + ) + } + + const EVENT_PATH: &str = "./src/task/test_datas/test_event_reporter"; + const EVENTS: [&'static str; 7] = [ + "start_event", + "wait_event", + "timeout_event", + "finished_event", + "finished_event_waiting", + "finished_event_failed", + "finished_event_bug", + ]; + + fn test_event_reporter(got: String, expect_short_msg: String, report_func: F) + where + F: Fn(TaskEvent) -> Result<()>, + { + let event_path = Path::new(EVENT_PATH); + let output_path = event_path.join(got.to_string()); + let file = File::create(output_path.clone()).expect("Failed to create file"); + file.set_len(0).expect("Failed to clear file"); + + let conf = ReporterConfig::default() + .filter(log::LevelFilter::Debug) + .file(&output_path.display().to_string()); + init_reporter_once(&conf).unwrap(); + + let mut expected_result = String::new(); + for event in EVENTS { + report_event_file(event, &report_func); + expected_result.push_str(&format!( + "{}", + expect_event_report(event, &expect_short_msg) + )); + } + expected_result.push_str("\n"); + let got_result = fs::read_to_string(&output_path.display().to_string()) + .expect("Something went wrong reading the file"); + + assert_eq!(got_result, expected_result); + } + + fn test_file_not_exist() { + let conf = ReporterConfig::default() + .filter(log::LevelFilter::Debug) + .file("./not_exist_dir/not_exist"); + match set_reporter_conf(&conf) { + Ok(_) => { + panic!("Unreachable Code") + } + Err(err) => { + assert_eq!("No such file or directory (os error 2)", format!("{}", err)) + } + }; + } + + #[test] + /// Since [`init_reporter_once`] can only be called once, + /// the test cases must be executed in a certain order. + fn test_in_order() { + let event_path = Path::new(EVENT_PATH); + let output_path = event_path.join("output"); + let file = File::create(output_path.clone()).expect("Failed to create file"); + file.set_len(0).expect("Failed to clear file"); + let conf = ReporterConfig::default() + .filter(log::LevelFilter::Debug) + .file(&output_path.display().to_string()); + + init_reporter_once(&conf).unwrap(); + + test_file_not_exist(); + test_event_reporter( + "output".to_string(), + "output_short".to_string(), + report_event_short_message, + ); + test_event_reporter( + "output".to_string(), + "output_detail".to_string(), + report_event_details, + ); + } +} diff --git a/compiler_base/parallel/src/task/test_datas/test_event_reporter/finished_event/finished_event.json b/compiler_base/parallel/src/task/test_datas/test_event_reporter/finished_event/finished_event.json new file mode 100644 index 000000000..249b8ae04 --- /dev/null +++ b/compiler_base/parallel/src/task/test_datas/test_event_reporter/finished_event/finished_event.json @@ -0,0 +1,31 @@ +{ + "tinfo": { + "tid": 0, + "tname": "finished_event_task" + }, + "ty": { + "Finished": { + "tinfo": { + "tid": 0, + "tname": "finished_event_task" + }, + "stdout": [ + 115, + 116, + 100, + 111, + 117, + 116 + ], + "stderr": [ + 115, + 116, + 100, + 101, + 114, + 114 + ], + "status": "Finished" + } + } +} \ No newline at end of file diff --git a/compiler_base/parallel/src/task/test_datas/test_event_reporter/finished_event/output_detail b/compiler_base/parallel/src/task/test_datas/test_event_reporter/finished_event/output_detail new file mode 100644 index 000000000..a1bf94f44 --- /dev/null +++ b/compiler_base/parallel/src/task/test_datas/test_event_reporter/finished_event/output_detail @@ -0,0 +1,7 @@ +[finished_event_task][INFO] +tname:finished_event_task tid:0 finished +stdout: +stdout +stderr: +stderr +status:finished diff --git a/compiler_base/parallel/src/task/test_datas/test_event_reporter/finished_event/output_short b/compiler_base/parallel/src/task/test_datas/test_event_reporter/finished_event/output_short new file mode 100644 index 000000000..d8f0b142c --- /dev/null +++ b/compiler_base/parallel/src/task/test_datas/test_event_reporter/finished_event/output_short @@ -0,0 +1 @@ +[finished_event_task][INFO] finished diff --git a/compiler_base/parallel/src/task/test_datas/test_event_reporter/finished_event_bug/finished_event_bug.json b/compiler_base/parallel/src/task/test_datas/test_event_reporter/finished_event_bug/finished_event_bug.json new file mode 100644 index 000000000..57b8423af --- /dev/null +++ b/compiler_base/parallel/src/task/test_datas/test_event_reporter/finished_event_bug/finished_event_bug.json @@ -0,0 +1,33 @@ +{ + "tinfo": { + "tid": 0, + "tname": "finished_event_task" + }, + "ty": { + "Finished": { + "tinfo": { + "tid": 0, + "tname": "finished_event_task" + }, + "stdout": [ + 115, + 116, + 100, + 111, + 117, + 116 + ], + "stderr": [ + 115, + 116, + 100, + 101, + 114, + 114 + ], + "status": { + "Bug": "The message output when bugs." + } + } + } +} \ No newline at end of file diff --git a/compiler_base/parallel/src/task/test_datas/test_event_reporter/finished_event_bug/output_detail b/compiler_base/parallel/src/task/test_datas/test_event_reporter/finished_event_bug/output_detail new file mode 100644 index 000000000..db59a6936 --- /dev/null +++ b/compiler_base/parallel/src/task/test_datas/test_event_reporter/finished_event_bug/output_detail @@ -0,0 +1,7 @@ +[finished_event_task][ERROR] +tname:finished_event_task tid:0 finished +stdout: +stdout +stderr: +stderr +status:bug:The message output when bugs. \ No newline at end of file diff --git a/compiler_base/parallel/src/task/test_datas/test_event_reporter/finished_event_bug/output_short b/compiler_base/parallel/src/task/test_datas/test_event_reporter/finished_event_bug/output_short new file mode 100644 index 000000000..e58c1e20f --- /dev/null +++ b/compiler_base/parallel/src/task/test_datas/test_event_reporter/finished_event_bug/output_short @@ -0,0 +1 @@ +[finished_event_task][ERROR] bug:The message output when bugs. \ No newline at end of file diff --git a/compiler_base/parallel/src/task/test_datas/test_event_reporter/finished_event_failed/finished_event_failed.json b/compiler_base/parallel/src/task/test_datas/test_event_reporter/finished_event_failed/finished_event_failed.json new file mode 100644 index 000000000..5e611ad1d --- /dev/null +++ b/compiler_base/parallel/src/task/test_datas/test_event_reporter/finished_event_failed/finished_event_failed.json @@ -0,0 +1,33 @@ +{ + "tinfo": { + "tid": 0, + "tname": "finished_event_task" + }, + "ty": { + "Finished": { + "tinfo": { + "tid": 0, + "tname": "finished_event_task" + }, + "stdout": [ + 115, + 116, + 100, + 111, + 117, + 116 + ], + "stderr": [ + 115, + 116, + 100, + 101, + 114, + 114 + ], + "status": { + "Failed": "The task failed." + } + } + } +} \ No newline at end of file diff --git a/compiler_base/parallel/src/task/test_datas/test_event_reporter/finished_event_failed/output_detail b/compiler_base/parallel/src/task/test_datas/test_event_reporter/finished_event_failed/output_detail new file mode 100644 index 000000000..f701b67f9 --- /dev/null +++ b/compiler_base/parallel/src/task/test_datas/test_event_reporter/finished_event_failed/output_detail @@ -0,0 +1,7 @@ +[finished_event_task][ERROR] +tname:finished_event_task tid:0 finished +stdout: +stdout +stderr: +stderr +status:failed:The task failed. diff --git a/compiler_base/parallel/src/task/test_datas/test_event_reporter/finished_event_failed/output_short b/compiler_base/parallel/src/task/test_datas/test_event_reporter/finished_event_failed/output_short new file mode 100644 index 000000000..6f07c2d4c --- /dev/null +++ b/compiler_base/parallel/src/task/test_datas/test_event_reporter/finished_event_failed/output_short @@ -0,0 +1 @@ +[finished_event_task][ERROR] failed:The task failed. diff --git a/compiler_base/parallel/src/task/test_datas/test_event_reporter/finished_event_waiting/finished_event_waiting.json b/compiler_base/parallel/src/task/test_datas/test_event_reporter/finished_event_waiting/finished_event_waiting.json new file mode 100644 index 000000000..505eef625 --- /dev/null +++ b/compiler_base/parallel/src/task/test_datas/test_event_reporter/finished_event_waiting/finished_event_waiting.json @@ -0,0 +1,31 @@ +{ + "tinfo": { + "tid": 0, + "tname": "finished_event_task" + }, + "ty": { + "Finished": { + "tinfo": { + "tid": 0, + "tname": "finished_event_task" + }, + "stdout": [ + 115, + 116, + 100, + 111, + 117, + 116 + ], + "stderr": [ + 115, + 116, + 100, + 101, + 114, + 114 + ], + "status": "Waiting" + } + } +} \ No newline at end of file diff --git a/compiler_base/parallel/src/task/test_datas/test_event_reporter/finished_event_waiting/output_detail b/compiler_base/parallel/src/task/test_datas/test_event_reporter/finished_event_waiting/output_detail new file mode 100644 index 000000000..aa45deacb --- /dev/null +++ b/compiler_base/parallel/src/task/test_datas/test_event_reporter/finished_event_waiting/output_detail @@ -0,0 +1,7 @@ +[finished_event_task][INFO] +tname:finished_event_task tid:0 finished +stdout: +stdout +stderr: +stderr +status:waiting diff --git a/compiler_base/parallel/src/task/test_datas/test_event_reporter/finished_event_waiting/output_short b/compiler_base/parallel/src/task/test_datas/test_event_reporter/finished_event_waiting/output_short new file mode 100644 index 000000000..dd9fe4e73 --- /dev/null +++ b/compiler_base/parallel/src/task/test_datas/test_event_reporter/finished_event_waiting/output_short @@ -0,0 +1 @@ +[finished_event_task][INFO] waiting diff --git a/compiler_base/parallel/src/task/test_datas/test_event_reporter/output b/compiler_base/parallel/src/task/test_datas/test_event_reporter/output new file mode 100644 index 000000000..2edf83436 --- /dev/null +++ b/compiler_base/parallel/src/task/test_datas/test_event_reporter/output @@ -0,0 +1,33 @@ +[2023-03-28][13:54:46][start_event_task][INFO] +tname:start_event_task tid:0 start +[2023-03-28][13:54:46][wait_event_task][INFO] +tname:wait_event_task tid:0 waiting +[2023-03-28][13:54:46][timeout_event_task][WARN] It's been running for over 10 seconds +[2023-03-28][13:54:46][finished_event_task][INFO] +tname:finished_event_task tid:0 finished +stdout: +stdout +stderr: +stderr +status:finished +[2023-03-28][13:54:46][finished_event_task][INFO] +tname:finished_event_task tid:0 finished +stdout: +stdout +stderr: +stderr +status:waiting +[2023-03-28][13:54:46][finished_event_task][ERROR] +tname:finished_event_task tid:0 finished +stdout: +stdout +stderr: +stderr +status:failed:The task failed. +[2023-03-28][13:54:46][finished_event_task][ERROR] +tname:finished_event_task tid:0 finished +stdout: +stdout +stderr: +stderr +status:bug:The message output when bugs. diff --git a/compiler_base/parallel/src/task/test_datas/test_event_reporter/start_event/output_detail b/compiler_base/parallel/src/task/test_datas/test_event_reporter/start_event/output_detail new file mode 100644 index 000000000..a0a809d0a --- /dev/null +++ b/compiler_base/parallel/src/task/test_datas/test_event_reporter/start_event/output_detail @@ -0,0 +1,2 @@ +[start_event_task][INFO] +tname:start_event_task tid:0 start diff --git a/compiler_base/parallel/src/task/test_datas/test_event_reporter/start_event/output_short b/compiler_base/parallel/src/task/test_datas/test_event_reporter/start_event/output_short new file mode 100644 index 000000000..a1ee63c55 --- /dev/null +++ b/compiler_base/parallel/src/task/test_datas/test_event_reporter/start_event/output_short @@ -0,0 +1 @@ +[start_event_task][INFO] start diff --git a/compiler_base/parallel/src/task/test_datas/test_event_reporter/start_event/start_event.json b/compiler_base/parallel/src/task/test_datas/test_event_reporter/start_event/start_event.json new file mode 100644 index 000000000..2856d888d --- /dev/null +++ b/compiler_base/parallel/src/task/test_datas/test_event_reporter/start_event/start_event.json @@ -0,0 +1,7 @@ +{ + "tinfo": { + "tid": 0, + "tname": "start_event_task" + }, + "ty": "Start" +} \ No newline at end of file diff --git a/compiler_base/parallel/src/task/test_datas/test_event_reporter/timeout_event/output_detail b/compiler_base/parallel/src/task/test_datas/test_event_reporter/timeout_event/output_detail new file mode 100644 index 000000000..8a3ba0baa --- /dev/null +++ b/compiler_base/parallel/src/task/test_datas/test_event_reporter/timeout_event/output_detail @@ -0,0 +1 @@ +[timeout_event_task][WARN] It's been running for over 10 seconds diff --git a/compiler_base/parallel/src/task/test_datas/test_event_reporter/timeout_event/output_short b/compiler_base/parallel/src/task/test_datas/test_event_reporter/timeout_event/output_short new file mode 100644 index 000000000..8a3ba0baa --- /dev/null +++ b/compiler_base/parallel/src/task/test_datas/test_event_reporter/timeout_event/output_short @@ -0,0 +1 @@ +[timeout_event_task][WARN] It's been running for over 10 seconds diff --git a/compiler_base/parallel/src/task/test_datas/test_event_reporter/timeout_event/timeout_event.json b/compiler_base/parallel/src/task/test_datas/test_event_reporter/timeout_event/timeout_event.json new file mode 100644 index 000000000..943818aab --- /dev/null +++ b/compiler_base/parallel/src/task/test_datas/test_event_reporter/timeout_event/timeout_event.json @@ -0,0 +1,12 @@ +{ + "tinfo": { + "tid": 0, + "tname": "timeout_event_task" + }, + "ty": { + "Timeout": { + "secs": 10, + "nanos": 0 + } + } +} \ No newline at end of file diff --git a/compiler_base/parallel/src/task/test_datas/test_event_reporter/wait_event/output_detail b/compiler_base/parallel/src/task/test_datas/test_event_reporter/wait_event/output_detail new file mode 100644 index 000000000..c4b29c249 --- /dev/null +++ b/compiler_base/parallel/src/task/test_datas/test_event_reporter/wait_event/output_detail @@ -0,0 +1,2 @@ +[wait_event_task][INFO] +tname:wait_event_task tid:0 waiting diff --git a/compiler_base/parallel/src/task/test_datas/test_event_reporter/wait_event/output_short b/compiler_base/parallel/src/task/test_datas/test_event_reporter/wait_event/output_short new file mode 100644 index 000000000..03f18eec2 --- /dev/null +++ b/compiler_base/parallel/src/task/test_datas/test_event_reporter/wait_event/output_short @@ -0,0 +1 @@ +[wait_event_task][INFO] waiting diff --git a/compiler_base/parallel/src/task/test_datas/test_event_reporter/wait_event/wait_event.json b/compiler_base/parallel/src/task/test_datas/test_event_reporter/wait_event/wait_event.json new file mode 100644 index 000000000..d4a4cad90 --- /dev/null +++ b/compiler_base/parallel/src/task/test_datas/test_event_reporter/wait_event/wait_event.json @@ -0,0 +1,7 @@ +{ + "tinfo": { + "tid": 0, + "tname": "wait_event_task" + }, + "ty": "Wait" +} \ No newline at end of file diff --git a/compiler_base/session/Cargo.toml b/compiler_base/session/Cargo.toml new file mode 100644 index 000000000..5d74754ee --- /dev/null +++ b/compiler_base/session/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "compiler_base_session" +version = "0.1.3" +edition = "2021" +authors = ["zongzhe1024@163.com"] +license = "Apache-2.0 OR MIT" +description = "compiler_base_session" +readme = "README.md" +homepage = "https://github.com/kcl-lang/kcl" +repository = "https://github.com/kcl-lang/kcl" +keywords = ["compiler", "session"] +categories = ["command-line-utilities"] + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +compiler_base_span = "0.1.2" +compiler_base_error = "0.1.6" +anyhow = "1.0" diff --git a/compiler_base/session/README.md b/compiler_base/session/README.md new file mode 100644 index 000000000..4f0066489 --- /dev/null +++ b/compiler_base/session/README.md @@ -0,0 +1,3 @@ +compiler_base_session + +note: [WIP] Do not use it. \ No newline at end of file diff --git a/compiler_base/session/src/lib.rs b/compiler_base/session/src/lib.rs new file mode 100644 index 000000000..5f134dc75 --- /dev/null +++ b/compiler_base/session/src/lib.rs @@ -0,0 +1,471 @@ +use anyhow::{Context, Result}; +use compiler_base_error::{diagnostic_handler::DiagnosticHandler, Diagnostic, DiagnosticStyle}; +use compiler_base_span::{FilePathMapping, SourceMap}; +use std::{ + path::{Path, PathBuf}, + sync::Arc, +}; + +#[cfg(test)] +mod tests; + +/// Represents the data associated with a compilation +/// session for a single crate. +/// +/// Note: TODO(zongz): This is a WIP structure. +/// Currently only contains the part related to error diagnostic displaying. +pub struct Session { + pub sm: Arc, + pub diag_handler: Arc, +} + +impl Session { + /// Construct a `Session` + /// + /// # Examples + /// + /// ```rust + /// # use compiler_base_session::Session; + /// # use compiler_base_error::diagnostic_handler::DiagnosticHandler; + /// # use std::path::PathBuf; + /// # use compiler_base_span::FilePathMapping; + /// # use compiler_base_span::SourceMap; + /// # use std::sync::Arc; + /// # use std::fs; + /// + /// // 1. You should create a new `SourceMap` wrapped with `Arc`. + /// let filename = fs::canonicalize(&PathBuf::from("./src/test_datas/code_snippet")).unwrap().display().to_string(); + /// let src = std::fs::read_to_string(filename.clone()).unwrap(); + /// let sm = Arc::new(SourceMap::new(FilePathMapping::empty())); + /// sm.new_source_file(PathBuf::from(filename.clone()).into(), src.to_string()); + /// + /// // 2. You should create a new `DiagnosticHandler` wrapped with `Arc`. + /// let diag_handler = Arc::new(DiagnosticHandler::new_with_template_dir("./src/test_datas/locales/en-US").unwrap()); + /// + /// // 3. Create `Session` + /// let sess = Session::new(sm, diag_handler); + /// + /// ``` + #[inline] + pub fn new(sm: Arc, diag_handler: Arc) -> Self { + Self { sm, diag_handler } + } + + /// Construct a `Session` with file name and optional source code. + /// + /// In the method, a `SourceMap` with a `SourceFile` will be created from `filename` and the optional source code `code`. + /// + /// Note: `code` has higher priority than `filename`, + /// If `code` is not None and the content in file `filename` is not the same as `code`, + /// then the content in `code` will be used as the source code. + /// + /// If `code` is None, the session will use the content of file `filename` as source code. + /// + /// # Examples + /// + /// ```rust + /// # use compiler_base_session::Session; + /// # use std::path::PathBuf; + /// const CARGO_ROOT: &str = env!("CARGO_MANIFEST_DIR"); + /// let mut cargo_file_path = PathBuf::from(CARGO_ROOT); + /// cargo_file_path.push("src/test_datas/code_snippet"); + /// let abs_path = cargo_file_path.to_str().unwrap(); + /// + /// let sess = Session::new_with_file_and_code(abs_path, None); + /// ``` + /// The `sess` will take the content of file `abs_path` as source code. + /// + /// ```rust + /// # use compiler_base_session::Session; + /// # use std::path::PathBuf; + /// const CARGO_ROOT: &str = env!("CARGO_MANIFEST_DIR"); + /// let mut cargo_file_path = PathBuf::from(CARGO_ROOT); + /// cargo_file_path.push("src/test_datas/code_snippet"); + /// let abs_path = cargo_file_path.to_str().unwrap(); + /// + /// let sess = Session::new_with_file_and_code(abs_path, Some("This is tmp source code")); + /// ``` + /// The `sess` will take "This is tmp source code" as source code. + pub fn new_with_file_and_code(filename: &str, code: Option<&str>) -> Result { + let sm = SourceMap::new(FilePathMapping::empty()); + match code { + Some(c) => { + sm.new_source_file(PathBuf::from(filename).into(), c.to_string()); + } + None => { + sm.load_file(&Path::new(&filename)) + .with_context(|| "Failed to load source file")?; + } + } + let diag = DiagnosticHandler::default(); + Ok(Self { + sm: Arc::new(sm), + diag_handler: Arc::new(diag), + }) + } + + /// Construct a `Session` with source code. + /// + /// In the method, a `SourceMap` with a `SourceFile` will be created from an empty path. + /// + /// # Examples + /// + /// ```rust + /// # use compiler_base_session::Session; + /// let sess = Session::new_with_src_code("This is the source code"); + /// ``` + #[inline] + pub fn new_with_src_code(code: &str) -> Result { + let sm = SourceMap::new(FilePathMapping::empty()); + sm.new_source_file(PathBuf::from("").into(), code.to_string()); + let diag = DiagnosticHandler::default(); + + Ok(Self { + sm: Arc::new(sm), + diag_handler: Arc::new(diag), + }) + } + + /// Emit all diagnostics to terminal and abort. + /// + /// # Panics + /// + /// After emitting the diagnositcs, the program will panic. + /// + /// # Examples + /// + /// If you want to emit an error diagnostic. + /// ```rust + /// # use compiler_base_session::Session; + /// # use compiler_base_error::components::Label; + /// # use compiler_base_error::DiagnosticStyle; + /// # use compiler_base_error::Diagnostic; + /// # use compiler_base_session::SessionDiagnostic; + /// # use anyhow::Result; + /// + /// // 1. Create your own error type. + /// struct MyError; + /// + /// // 2. Implement trait `SessionDiagnostic` manually. + /// impl SessionDiagnostic for MyError { + /// fn into_diagnostic(self, sess: &Session) -> Result> { + /// let mut diag = Diagnostic::::new(); + /// // 1. Label Component + /// let label_component = Box::new(Label::Error("error".to_string())); + /// diag.append_component(label_component); + /// Ok(diag) + /// } + /// } + /// + /// let result = std::panic::catch_unwind(|| { + /// // 3. Create a Session. + /// let sess = Session::new_with_src_code("test code").unwrap(); + /// // 4. Add the error diagnostic. + /// sess.add_err(MyError {}).unwrap(); + /// // 5. Emit the error diagnostic. + /// sess.emit_stashed_diagnostics_and_abort().unwrap(); + /// }); + /// assert!(result.is_err()); + /// ``` + #[inline] + pub fn emit_stashed_diagnostics_and_abort(&self) -> Result<&Self> { + self.diag_handler + .abort_if_errors() + .with_context(|| "Internal Bug: Fail to display error diagnostic")?; + Ok(self) + } + + /// Emit all diagnostics to strings. + /// + /// # Examples + /// + /// If you want to emit an diagnostic. + /// ```rust + /// # use compiler_base_session::Session; + /// # use compiler_base_error::components::Label; + /// # use compiler_base_error::DiagnosticStyle; + /// # use compiler_base_error::Diagnostic; + /// # use compiler_base_session::SessionDiagnostic; + /// # use anyhow::Result; + /// + /// // 1. Create your own error type. + /// struct MyError; + /// + /// // 2. Implement trait `SessionDiagnostic` manually. + /// impl SessionDiagnostic for MyError { + /// fn into_diagnostic(self, sess: &Session) -> Result> { + /// let mut diag = Diagnostic::::new(); + /// // 1. Label Component + /// let label_component = Box::new(Label::Error("error".to_string())); + /// diag.append_component(label_component); + /// Ok(diag) + /// } + /// } + /// // 3. Create a Session. + /// let sess = Session::new_with_src_code("test code").unwrap(); + /// + /// // 4. Add the error + /// sess.add_err(MyError {}).unwrap(); + /// + /// // 5. Emit the error diagnostic. + /// assert_eq!(sess.emit_all_diags_into_string().unwrap().get(0).unwrap().as_ref().unwrap(), "error[error]"); + /// ``` + #[inline] + pub fn emit_all_diags_into_string(&self) -> Result>> { + self.diag_handler.emit_all_diags_into_string() + } + + /// Emit [`index`]th diagnostic to string. + /// + /// # Examples + /// + /// If you want to emit an diagnostic. + /// ```rust + /// # use compiler_base_session::Session; + /// # use compiler_base_error::components::Label; + /// # use compiler_base_error::DiagnosticStyle; + /// # use compiler_base_error::Diagnostic; + /// # use compiler_base_session::SessionDiagnostic; + /// # use anyhow::Result; + /// + /// // 1. Create your own error type. + /// struct MyError; + /// + /// // 2. Implement trait `SessionDiagnostic` manually. + /// impl SessionDiagnostic for MyError { + /// fn into_diagnostic(self, sess: &Session) -> Result> { + /// let mut diag = Diagnostic::::new(); + /// // 1. Label Component + /// let label_component = Box::new(Label::Error("error".to_string())); + /// diag.append_component(label_component); + /// Ok(diag) + /// } + /// } + /// // 3. Create a Session. + /// let sess = Session::new_with_src_code("test code").unwrap(); + /// + /// // 4. Add the error + /// sess.add_err(MyError {}).unwrap(); + /// + /// // 5. Emit the error diagnostic. + /// assert_eq!(sess.emit_nth_diag_into_string(0).unwrap().unwrap().unwrap(), "error[error]"); + /// ``` + #[inline] + pub fn emit_nth_diag_into_string(&self, index: usize) -> Result>> { + self.diag_handler.emit_nth_diag_into_string(index) + } + + /// Emit all diagnostics to terminal. + /// + /// # Examples + /// + /// If you want to emit an diagnostic. + /// ```rust + /// # use compiler_base_session::Session; + /// # use compiler_base_error::components::Label; + /// # use compiler_base_error::DiagnosticStyle; + /// # use compiler_base_error::Diagnostic; + /// # use compiler_base_session::SessionDiagnostic; + /// # use anyhow::Result; + /// + /// // 1. Create your own error type. + /// struct MyError; + /// + /// // 2. Implement trait `SessionDiagnostic` manually. + /// impl SessionDiagnostic for MyError { + /// fn into_diagnostic(self, sess: &Session) -> Result> { + /// let mut diag = Diagnostic::::new(); + /// // 1. Label Component + /// let label_component = Box::new(Label::Error("error".to_string())); + /// diag.append_component(label_component); + /// Ok(diag) + /// } + /// } + /// // 3. Create a Session. + /// let sess = Session::new_with_src_code("test code").unwrap(); + /// + /// // 4. Add the error + /// sess.add_err(MyError {}).unwrap(); + /// + /// // 5. Emit the error diagnostic. + /// sess.emit_stashed_diagnostics().unwrap(); + /// ``` + pub fn emit_stashed_diagnostics(&self) -> Result<&Self> { + self.diag_handler + .emit_stashed_diagnostics() + .with_context(|| "Internal Bug: Fail to display error diagnostic")?; + Ok(self) + } + + /// Add an error diagnostic generated from error to `Session`. + /// + /// # Examples + /// + /// ```rust + /// # use compiler_base_error::DiagnosticStyle; + /// # use compiler_base_error::diagnostic_handler::DiagnosticHandler; + /// # use compiler_base_error::Diagnostic; + /// # use compiler_base_error::components::Label; + /// # use compiler_base_session::Session; + /// # use compiler_base_session::SessionDiagnostic; + /// # use anyhow::Result; + /// + /// // 1. Create your own error type. + /// struct MyError; + /// + /// // 2. Implement trait `SessionDiagnostic` manually. + /// impl SessionDiagnostic for MyError { + /// fn into_diagnostic(self, sess: &Session) -> Result> { + /// let mut diag = Diagnostic::::new(); + /// // 1. Label Component + /// let label_component = Box::new(Label::Error("error".to_string())); + /// diag.append_component(label_component); + /// Ok(diag) + /// } + /// } + /// + /// let sess = Session::new_with_src_code("test code").unwrap(); + /// assert_eq!(sess.diagnostics_count().unwrap(), 0); + /// + /// sess.add_err(MyError{}); + /// assert_eq!(sess.diagnostics_count().unwrap(), 1); + /// ``` + pub fn add_err(&self, err: impl SessionDiagnostic) -> Result<&Self> { + self.diag_handler + .add_err_diagnostic(err.into_diagnostic(self)?)?; + Ok(self) + } + + /// Add an warn diagnostic generated from warning to `Session`. + /// + /// # Examples + /// + /// ```rust + /// # use compiler_base_error::DiagnosticStyle; + /// # use compiler_base_error::diagnostic_handler::DiagnosticHandler; + /// # use compiler_base_error::Diagnostic; + /// # use compiler_base_error::components::Label; + /// # use compiler_base_session::Session; + /// # use compiler_base_session::SessionDiagnostic; + /// # use anyhow::Result; + /// + /// // 1. Create your own error type. + /// struct MyWarning; + /// + /// // 2. Implement trait `SessionDiagnostic` manually. + /// impl SessionDiagnostic for MyWarning { + /// fn into_diagnostic(self, sess: &Session) -> Result> { + /// let mut diag = Diagnostic::::new(); + /// // 1. Label Component + /// let label_component = Box::new(Label::Warning("warning".to_string())); + /// diag.append_component(label_component); + /// Ok(diag) + /// } + /// } + /// + /// let sess = Session::new_with_src_code("test code").unwrap(); + /// assert_eq!(sess.diagnostics_count().unwrap(), 0); + /// + /// sess.add_err(MyWarning{}); + /// assert_eq!(sess.diagnostics_count().unwrap(), 1); + /// ``` + pub fn add_warn(&self, warn: impl SessionDiagnostic) -> Result<&Self> { + self.diag_handler + .add_warn_diagnostic(warn.into_diagnostic(self)?)?; + Ok(self) + } + + /// Get count of diagnostics in `DiagnosticHandler`. + /// + /// # Examples + /// + /// ```rust + /// # use compiler_base_error::DiagnosticStyle; + /// # use compiler_base_error::diagnostic_handler::DiagnosticHandler; + /// # use compiler_base_error::Diagnostic; + /// # use compiler_base_error::components::Label; + /// # use compiler_base_session::Session; + /// # use compiler_base_session::SessionDiagnostic; + /// # use anyhow::Result; + /// + /// // 1. Create your own error type. + /// struct MyWarning; + /// + /// // 2. Implement trait `SessionDiagnostic` manually. + /// impl SessionDiagnostic for MyWarning { + /// fn into_diagnostic(self, sess: &Session) -> Result> { + /// let mut diag = Diagnostic::::new(); + /// // 1. Label Component + /// let label_component = Box::new(Label::Warning("warning".to_string())); + /// diag.append_component(label_component); + /// Ok(diag) + /// } + /// } + /// + /// let sess = Session::new_with_src_code("test code").unwrap(); + /// assert_eq!(sess.diagnostics_count().unwrap(), 0); + /// + /// sess.add_err(MyWarning{}); + /// assert_eq!(sess.diagnostics_count().unwrap(), 1); + #[inline] + pub fn diagnostics_count(&self) -> Result { + self.diag_handler.diagnostics_count() + } +} + +impl Default for Session { + /// New a default session with a empty source map. + /// + /// # Examples + /// + /// ``` + /// use compiler_base_session::Session; + /// + /// assert_eq!(Session::default().diagnostics_count().unwrap(), 0); + /// ``` + fn default() -> Self { + Self { + sm: Arc::new(SourceMap::new(FilePathMapping::empty())), + diag_handler: Arc::new(DiagnosticHandler::default()), + } + } +} + +/// Trait implemented by error types. +/// +/// You can implement manually for error types as below. +/// +/// # Example +/// +/// ```rust +/// use anyhow::Result; +/// use compiler_base_error::components::Label; +/// use compiler_base_error::DiagnosticStyle; +/// use compiler_base_error::Diagnostic; +/// use compiler_base_session::Session; +/// use compiler_base_session::SessionDiagnostic; +/// +/// // 1. Create your own error type. +/// struct MyError; +/// +/// // 2. Implement trait `SessionDiagnostic` manually. +/// impl SessionDiagnostic for MyError { +/// fn into_diagnostic(self, sess: &Session) -> Result> { +/// let mut diag = Diagnostic::::new(); +/// // 1. Label Component +/// let label_component = Box::new(Label::Error("error".to_string())); +/// diag.append_component(label_component); +/// Ok(diag) +/// } +/// } +/// +/// // 3. The diagnostic of MyError will display "error" on terminal. +/// // For more information about diagnositc displaying, see doc in `compiler_base_error`. +/// ``` +/// +/// Note: +/// TODO(zongz): `#[derive(SessionDiagnostic)]` is WIP, before that you need to manually implement this trait. +/// This should not be implemented manually. Instead, use `#[derive(SessionDiagnostic)]` in the future. +pub trait SessionDiagnostic { + fn into_diagnostic(self, sess: &Session) -> Result>; +} diff --git a/compiler_base/session/src/test_datas/code_snippet b/compiler_base/session/src/test_datas/code_snippet new file mode 100644 index 000000000..47d492e14 --- /dev/null +++ b/compiler_base/session/src/test_datas/code_snippet @@ -0,0 +1,2 @@ +Line 1 Code Snippet. +Line 2 Code Snippet. diff --git a/compiler_base/session/src/test_datas/locales/en-US/default.ftl b/compiler_base/session/src/test_datas/locales/en-US/default.ftl new file mode 100644 index 000000000..67e493db8 --- /dev/null +++ b/compiler_base/session/src/test_datas/locales/en-US/default.ftl @@ -0,0 +1,3 @@ +invalid-syntax = + Invalid syntax + .expected = Expected one of `{$expected_items}` diff --git a/compiler_base/session/src/test_datas/locales/en-US/test/default1.ftl b/compiler_base/session/src/test_datas/locales/en-US/test/default1.ftl new file mode 100644 index 000000000..4290d805b --- /dev/null +++ b/compiler_base/session/src/test_datas/locales/en-US/test/default1.ftl @@ -0,0 +1,3 @@ +invalid-syntax-1 = + Invalid syntax 1 + .expected_1 = Expected one of `{$expected_items}` 1 diff --git a/compiler_base/session/src/tests.rs b/compiler_base/session/src/tests.rs new file mode 100644 index 000000000..6defaf673 --- /dev/null +++ b/compiler_base/session/src/tests.rs @@ -0,0 +1,186 @@ +mod test_session { + use std::{path::PathBuf, sync::Arc}; + + use crate::{Session, SessionDiagnostic}; + use anyhow::Result; + use compiler_base_error::{ + components::{CodeSnippet, Label}, + Diagnostic, DiagnosticStyle, + }; + use compiler_base_span::{span::new_byte_pos, Span}; + + const CARGO_ROOT: &str = env!("CARGO_MANIFEST_DIR"); + #[test] + fn test_new_session_with_filename() { + let mut cargo_file_path = PathBuf::from(CARGO_ROOT); + cargo_file_path.push("src/test_datas/code_snippet"); + let abs_path = cargo_file_path.to_str().unwrap(); + match Session::new_with_file_and_code(abs_path, None) { + Ok(_) => {} + Err(_) => { + panic!("Unreachable") + } + } + } + + #[test] + fn test_new_session_with_filename_and_src() { + let mut cargo_file_path = PathBuf::from(CARGO_ROOT); + cargo_file_path.push("src/test_datas/code_snippet"); + let abs_path = cargo_file_path.to_str().unwrap(); + match Session::new_with_file_and_code(abs_path, Some("Hello World")) { + Ok(_) => {} + Err(_) => { + panic!("Unreachable") + } + } + } + + #[test] + fn test_new_session_with_filename_invalid() { + let mut cargo_file_path = PathBuf::from(CARGO_ROOT); + cargo_file_path.push("src/test_datas/no_exists"); + let abs_path = cargo_file_path.to_str().unwrap(); + match Session::new_with_file_and_code(abs_path, None) { + Ok(_) => { + panic!("Unreachable") + } + Err(err) => { + assert_eq!(err.to_string(), "Failed to load source file") + } + } + } + + // 1. Create your own error type. + struct MyError; + + // 2. Implement trait `SessionDiagnostic` manually. + impl SessionDiagnostic for MyError { + fn into_diagnostic(self, _: &Session) -> Result> { + let mut diag = Diagnostic::::new(); + // Label Component + let label_component = Box::new(Label::Error("error".to_string())); + diag.append_component(label_component); + Ok(diag) + } + } + + #[test] + fn test_session_emit_err() { + let prev_hook = std::panic::take_hook(); + std::panic::set_hook(Box::new(|_| {})); + let result = std::panic::catch_unwind(|| { + // 3. Create a Session. + let sess = Session::new_with_src_code("test code").unwrap(); + // 4. Add the error diagnostic. + sess.add_err(MyError {}).unwrap(); + // 5. Emit the error diagnostic. + sess.emit_stashed_diagnostics_and_abort().unwrap(); + }); + assert!(result.is_err()); + std::panic::set_hook(prev_hook); + } + + // 1. Create your own error type. + struct CodeSnippetError { + span: Span, + } + + // 2. Implement trait `SessionDiagnostic` manually. + impl SessionDiagnostic for CodeSnippetError { + fn into_diagnostic(self, sess: &Session) -> Result> { + let mut diag = Diagnostic::::new(); + // Label Component + let label_component = Box::new(Label::Error("error".to_string())); + diag.append_component(label_component); + + let msg_component = Box::new(": This is a code snippet error.".to_string()); + diag.append_component(msg_component); + + let code_snippet_component = + Box::new(CodeSnippet::new(self.span, Arc::clone(&sess.sm))); + diag.append_component(code_snippet_component); + + let msg_component_1 = Box::new("This is the bad code snippet.".to_string()); + diag.append_component(msg_component_1); + + Ok(diag) + } + } + + #[test] + fn test_session_emit_code_snippet_err() { + let prev_hook = std::panic::take_hook(); + std::panic::set_hook(Box::new(|_| {})); + + let mut cargo_file_path = PathBuf::from(CARGO_ROOT); + cargo_file_path.push("src/test_datas/code_snippet"); + let abs_path = cargo_file_path.to_str().unwrap(); + + let result = std::panic::catch_unwind(|| { + // Create a Session with no src code. + let sess = Session::new_with_file_and_code(abs_path, None).unwrap(); + // Add the error diagnostic. + sess.add_err(CodeSnippetError { + span: Span::new(new_byte_pos(0), new_byte_pos(8)), + }) + .unwrap(); + // Emit the error diagnostic. + sess.emit_stashed_diagnostics_and_abort().unwrap(); + }); + assert!(result.is_err()); + + let result_with_src = std::panic::catch_unwind(|| { + // Create a Session with src code. + let sess_with_src = + Session::new_with_file_and_code(abs_path, Some("This is session with src code .")) + .unwrap(); + // Add the error diagnostic. + sess_with_src + .add_err(CodeSnippetError { + span: Span::new(new_byte_pos(0), new_byte_pos(8)), + }) + .unwrap(); + // Emit the error diagnostic. + sess_with_src.emit_stashed_diagnostics_and_abort().unwrap(); + }); + assert!(result_with_src.is_err()); + + std::panic::set_hook(prev_hook); + } + + #[test] + fn test_emit_stashed_diagnostics() { + let sess = Session::new_with_src_code("test code").unwrap(); + sess.add_err(MyError {}).unwrap(); + sess.emit_stashed_diagnostics().unwrap(); + } + + #[test] + fn test_add_err() { + let sess = Session::new_with_src_code("test code").unwrap(); + assert_eq!(sess.diagnostics_count().unwrap(), 0); + sess.add_err(MyError {}).unwrap(); + assert_eq!(sess.diagnostics_count().unwrap(), 1); + } + + struct MyWarning; + + impl SessionDiagnostic for MyWarning { + fn into_diagnostic(self, _: &Session) -> Result> { + let mut diag = Diagnostic::::new(); + // Label Component + let label_component = Box::new(Label::Warning("warning".to_string())); + diag.append_component(label_component); + Ok(diag) + } + } + + #[test] + fn test_add_warn() { + let sess = Session::new_with_src_code("test code").unwrap(); + assert_eq!(sess.diagnostics_count().unwrap(), 0); + sess.add_warn(MyWarning {}).unwrap(); + assert_eq!(sess.diagnostics_count().unwrap(), 1); + } +} diff --git a/compiler_base/span/Cargo.toml b/compiler_base/span/Cargo.toml new file mode 100644 index 000000000..d4bff210c --- /dev/null +++ b/compiler_base/span/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "compiler_base_span" +version = "0.1.3" +edition = "2021" +authors = ["zongzhe1024@163.com"] +license = "Apache-2.0 OR MIT" +description = "compiler_base_span" +readme = "README.md" +homepage = "https://github.com/kcl-lang/kcl" +repository = "https://github.com/kcl-lang/kcl" +keywords = ["compiler", "span"] +categories = ["command-line-utilities"] + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +rustc_span = "0.1.2" diff --git a/compiler_base/span/README.md b/compiler_base/span/README.md new file mode 100644 index 000000000..3624a23b3 --- /dev/null +++ b/compiler_base/span/README.md @@ -0,0 +1,3 @@ +compiler_base_span + +note: [WIP] Do not use it. \ No newline at end of file diff --git a/compiler_base/span/src/lib.rs b/compiler_base/span/src/lib.rs new file mode 100644 index 000000000..dd750aad9 --- /dev/null +++ b/compiler_base/span/src/lib.rs @@ -0,0 +1,47 @@ +//! Source positions and related helper functions. +//! +//! Important concepts in this module include: +//! +//! - the *span*, represented by [`Span`] and related types; +//! - interned strings, represented by [`Symbol`]s, with some common symbols available statically in the [`sym`] module. +//! +//! Reference: https://github.com/rust-lang/rust/blob/master/compiler/rustc_span/src/lib.rs + +pub mod span; +pub use rustc_span::fatal_error; +pub use span::{BytePos, Span, SpanData, DUMMY_SP}; + +pub type SourceMap = rustc_span::SourceMap; +pub type SourceFile = rustc_span::SourceFile; +pub type FilePathMapping = rustc_span::source_map::FilePathMapping; +pub type Loc = rustc_span::Loc; + +/// Get the filename from `SourceMap` by `Span`. +/// +/// # Examples +/// +/// ```rust +/// # use compiler_base_span::{span_to_filename_string, span::new_byte_pos, FilePathMapping, SourceMap}; +/// # use rustc_span::SpanData; +/// # use std::path::PathBuf; +/// # use std::fs; +/// +/// // 1. You need to hold a `SourceMap` at first. +/// let filename = fs::canonicalize(&PathBuf::from("./src/test_datas/code_snippet")).unwrap().display().to_string(); +/// let src = std::fs::read_to_string(filename.clone()).unwrap(); +/// let sm = SourceMap::new(FilePathMapping::empty()); +/// sm.new_source_file(PathBuf::from(filename.clone()).into(), src.to_string()); +/// +/// // 2. You got the span in `SourceMap`. +/// let code_span = SpanData { +/// lo: new_byte_pos(21), +/// hi: new_byte_pos(22), +/// }.span(); +/// +/// // 3. You can got the filename by `span_to_filename_string()`. +/// assert_eq!(filename, span_to_filename_string(&code_span, &sm)); +/// ``` +#[inline] +pub fn span_to_filename_string(span: &Span, sm: &SourceMap) -> String { + format!("{}", sm.span_to_filename(*span).prefer_remapped()) +} diff --git a/compiler_base/span/src/span.rs b/compiler_base/span/src/span.rs new file mode 100644 index 000000000..886d10237 --- /dev/null +++ b/compiler_base/span/src/span.rs @@ -0,0 +1,19 @@ +use rustc_span; + +pub type BytePos = rustc_span::BytePos; +pub type Span = rustc_span::Span; +pub type SpanData = rustc_span::SpanData; +pub const DUMMY_SP: Span = rustc_span::DUMMY_SP; + +/// New a `BytePos` +/// +/// # Examples +/// +/// ```rust +/// # use compiler_base_span::span::new_byte_pos; +/// let byte_pos = new_byte_pos(10); +/// ``` +#[inline] +pub fn new_byte_pos(arg: u32) -> rustc_span::BytePos { + rustc_span::BytePos(arg) +} diff --git a/compiler_base/span/src/test_datas/code_snippet b/compiler_base/span/src/test_datas/code_snippet new file mode 100644 index 000000000..47d492e14 --- /dev/null +++ b/compiler_base/span/src/test_datas/code_snippet @@ -0,0 +1,2 @@ +Line 1 Code Snippet. +Line 2 Code Snippet. diff --git a/compiler_base/src/lib.rs b/compiler_base/src/lib.rs new file mode 100644 index 000000000..a02d74547 --- /dev/null +++ b/compiler_base/src/lib.rs @@ -0,0 +1 @@ +// TODO(zong-zhe): add more external interfaces of CompilerBase. diff --git a/docs/cmd/README_KCLVM_USE.md b/docs/cmd/README_KCLVM_USE.md deleted file mode 100644 index 652f595c2..000000000 --- a/docs/cmd/README_KCLVM_USE.md +++ /dev/null @@ -1,129 +0,0 @@ -# Kusion Configuration Language Virtual Machine (KCLVM) Command-Line Interface (CLI) Tool - -KCLVM mainly uses a CLI tool to help us to build our cloud native configuration application, and the CLI tool is a cross-platform tool chain for compiling the KCL file. We can easily use it to generate our wanted configuration YAML file. - -## Abstract - -```cli -kcl [-h] [-D ARGUMENT] [-S PATH_SELECTOR] [-O OVERRIDES] - [-Y [SETTING [SETTING ...]]] [-o OUTPUT] [-n] [-r] [-c] [-s] [-v] - [-d] [-p] [-L] [-l] [-V] [--target {native,wasm}] - [file [file ...]] -``` - -## Parameters - -* `ARGUMENT`: The top-level argument. -* `OUTPUT`: The output file. -* `SETTING`: The top-level YAML setting file. -* `PATH_SELECTOR`: The configuration selector path. -* `OVERRIDES`: The configuration override path and value. - -## Arguments - -### Positional Arguments - -* `file`: The input KCL files to be compiled. - -### Optional Arguments - -* `-h|--help`: Show the help message and exit. -* `-D|--argument`: Specify the top-level argument. -* `-Y|--setting`: Specify the top-level setting file. -* `-o|--output`: Specify the output file. -* `-n|--disable-none`: Disable dumping None values. -* `-r|--strict-range-check`: Do perform strict numeric range check. -* `-c|--compile-only`: Compile only and do not generate the YAML file. -* `-s|--save-temps`: Save intermediate files. -* `-v|--verbose`: Run in verbose mode. -* `-d|--debug`: Run in debug mode (for developers only). -* `-p|--profile`: Perform profiling. -* `-L|--list-attributes`: Show schema attributes list. -* `-l|--list-options`: Show kcl options list. -* `-V|--version`: Show the kcl version. -* `-S|--path-selector`: Specify the path selector. -* `-O|--overrides`: Specify the configuration override path and value. -* `--target {native,wasm}`: Specify the target type - -## Examples - -* If we have written our KCL files, KCL can be invoked as: - -``` -kcl your_config.k -``` - -* In addition, we can specify the location of the output: - -``` -kcl your_config.k -o your_yaml.yaml -``` - -* We can use `-D ARGUMENT` or `--argument ARGUMENT` to specify the top-level arguments: - -``` -kcl your_config.k -D your_arguments - -Examples: -kcl your_config.k -D argsName=argsValue -``` - -* We can use `-Y SETTING` or `--setting SETTING` to specify the top-level arguments through the YAML file: - -``` -kcl your_config.k -Y your_setting_file.yaml -``` - -* If we don’t want to display `none` values in the generated file, we can use the parameter `-n`: - -``` -kcl your_config.k -n -``` - -* If we want to perform the strict numeric range check, we can use the parameter `-r`: - -``` -kcl your_config.k -r -``` - -* If we want to save intermediate files, we can use the parameter `-s`: - -``` -kcl your_config.k -s -``` - -* If we want to show schema attributes list and kcl options list, we can use the parameter `-L` and `-l`: - -``` -kcl your_config.k -L -l -``` - -* If we want to get part of KCL configuration, we can use `-S` or `--path-selector` to specify the configuration override path and value: - -``` -kcl your_config.k -S pkg:variable_path -``` - -* If we want to override part of the KCL configuration content, we can use `-O` or `--overrides` to specify the configuration override path and value: - -``` -kcl your_config.k -O pkg:variable_path=value -``` - -* If we want to compile KCL code into a native dynamic link library, we can use `--target` to specify the `native` target. - -``` -kcl your_config.k --target native -``` - -* If we want to compile KCL code into a WASM module, we can use `--target` to specify the `wasm` target. - -``` -kcl your_config.k --target wasm -``` - -* For more information, we can use the following command to show the help message: - -``` -kcl --help -``` diff --git a/docs/design/ide_kpm_watcher.md b/docs/design/ide_kpm_watcher.md new file mode 100644 index 000000000..3d95df4bd --- /dev/null +++ b/docs/design/ide_kpm_watcher.md @@ -0,0 +1,101 @@ +## KCL Watch System + +### 1. Introduction +The KCL Watch System aims to monitor changes to files and directories within the KCL package directory. It dynamically detects file types based on their extensions and invokes corresponding handlers to perform actions upon changes. This system enhances the development experience by providing real-time feedback and enabling rapid iteration during development and continuous integration. + +### 2. Design Research + +I researched various file watching systems such as Pyright, TypeScript, and Rust Analyzer to understand their architecture and functionality. I found that these systems share a similar core architecture and interface functionalities: + +**Typescript:** +- Offers a file watching API through libraries like `fs.watch` or `chokidar`. +- Core interface functionalities include initializing a watcher, registering watch paths, defining event handlers, and error handling. +- Configuration can be done via `tsconfig.json` to customize watch behavior. + +**Pyright:** +- Utilizes the `watchdog` library for file system monitoring. +- Core interface functionalities align with those of other languages: initializing a watcher, registering watch paths, handling events, and error handling. +- Reference: [Watchdog](https://github.com/gorakhargosh/watchdog) + +**Rust Analyzer:** +- Uses the `notify` crate for file system monitoring. +- Core interface includes initializing a watcher, registering watch paths, defining event handlers, and handling errors. +- Configuration is done via `watch.toml` to customize watch tasks, file patterns to watch, ignore patterns, and commands to execute upon file changes. +- Reference: [Cargo Watch](https://crates.io/crates/cargo-watch) + +### 3. Architecture Overview + +#### 3.1 Watcher +- Utilizes a file system notification library (e.g., `notify`) to monitor changes to files and directories. +- Maintains a list of registered watch paths and corresponding event handlers. +- Runs asynchronously to minimize latency and improve responsiveness. + +#### 3.2 File Type Detector +- A file detector analyzes files to determine their types based on their extensions like `.k, .mod, .JSON, .YAML`, etc. +- Provides a mapping of file types to corresponding handlers. + +#### 3.3 Handler Registry +- Registers and manages operations for different file types defined above. +- Handlers define actions to be executed upon file system events (e.g., file creation, modification, deletion). + +#### 3.4 Configuration Manager +- Manages configuration settings for the KCL Watch System. +- Allows developers to specify watch paths, file types, and handler configurations. +- Supports configuration via configuration files (e.g., `kcl.toml`). + +### 4. Core API of Watch System (Rough design, actual implementation might differ during development) + +#### 4.1 Watcher API +- `initialize()`: Initializes the watcher component. +- `registerPath(path: string)`: Registers a path to monitor for file system events. +- `unregisterPath(path: string)`: Unregisters a path from monitoring. +- `on(event: string, handler: Function)`: Registers an event handler for a specific file system event. +- `start()`: Starts the watcher to begin monitoring registered paths. +- `stop()`: Stops the watcher and clears all registered paths and handlers. + +#### 4.2 File Type Detector API +- `detectFileType(filePath: string): string`: Determines the file type based on its extension. + +#### 4.3 Handler Registry API +- `registerHandler(fileType: string, handler: Function)`: Registers a handler for a specific file type. +- `unregisterHandler(fileType: string)`: Unregisters a handler for a specific file type. + +#### 4.4 Configuration Manager API +- `loadConfig(configPath: string)`: Loads configuration settings from a specified configuration file. +- `setWatchPaths(paths: string[])`: Sets the watch paths based on the configuration. +- `setHandlerConfigurations(config: Object)`: Sets handler configurations based on the configuration file. + +### 5. Architecture Diagram (Mermaid.js) + +```mermaid +graph LR + A[KCL] --> B[Watcher] + B --> C[File Type Detector] + C --> D[Handler Registry] + D --> E[Configuration Manager] + E --> B + + B -->|File System Events| F[Event Handling] + C -->|File Type| F + D -->|Handler Actions| F + E -->|Configuration Settings| F +``` + +### 6. Integration with KCL Language Server(to be implemented) + +To integrate the KCL Watch System with the KCL language server, I am going follow these steps: + +#### 6.1 Import Necessary Modules +- In `main.rs`, import the required modules from the KCL Watch System(to be implemented). + +#### 6.2 Initialize KCL Watch System +- Then I will modify the `run_server` function in `main.rs` to initialize the KCL Watch System. + +#### 6.3 Integrate File Watching with Language Server +- Then I will modify the `main_loop` function in `main_loop.rs` to handle file watching events. + +#### 6.4 Implement Watch Handlers +- Also need to create a new module `kcl_watch_system.rs` to implement the watch system integration. + +#### 6.5 Update File Watching Event Handling +- Then In `notification.rs`, add the necessary event handlers for file watching events. diff --git a/docs/design/ide_kpm_workflow.md b/docs/design/ide_kpm_workflow.md new file mode 100644 index 000000000..186811d12 --- /dev/null +++ b/docs/design/ide_kpm_workflow.md @@ -0,0 +1,70 @@ +### Research Report: + +#### Introduction: +The research report explores the workflows of popular IDEs for languages like Python, Go, and Rust, focusing on package installation, virtual environments, automatic updates, and package project management. The report also proposes integrating similar functionalities into the KCL (Configuration Language) development environment. + +#### Python (PyCharm): +1. **Package Installation**: + - Users can install packages easily through PyCharm's built-in package manager. + - Proposal: Implement a search command to fetch packages from a global repository like ArtifactHub. + +2. **Virtual Environments**: + - PyCharm supports effortless creation and activation of virtual environments. + - Proposal: Integrate virtual environment creation for KCL development to mitigate version mismatch errors. + +3. **Automatic Updates**: + - PyCharm prompts users to update installed packages. + - Proposal: Implement automatic updates for the KCL package using a similar mechanism. + +4. **Package Project Management**: + - Project-specific dependencies can be managed via a `requirements.txt` file. + - Proposal: Introduce a `kcl.mod` file to specify dependencies and provide a command (`kpm install kcl.mod`) to download them. + +#### Go Language (Golang): +1. **Package Installation**: + - IDEs like GoLand or VSCode with the Go extension seamlessly integrate with Go modules. + - Proposal: Allow fetching dependencies of KCL packages directly within the IDE. + +2. **Virtual Environments**: + - Go relies on Go modules for dependency management. + - Proposal: Although Go doesn't have traditional virtual environments, creating an isolated environment for KCL development could enhance user experience. + +3. **Automatic Updates**: + - Go modules automatically check for updates to dependencies specified in `go.mod`. + - Proposal: Enable automatic updates for KCL packages. + +4. **Package Project Management**: + - Go projects typically use a `go.mod` file to specify dependencies. + - Proposal: Introduce tools for managing dependencies in KCL projects, similar to `go mod tidy`. + +#### Rust Language: + +1. **Package Installation**: + - IDEs such as IntelliJ IDEA with the Rust plugin or Visual Studio Code with the Rust extension support Cargo, Rust's package manager. + - Developers can use Cargo commands (`cargo build`, `cargo run`, `cargo test`, etc.) directly within the IDE to manage dependencies and build their projects. + +2. **Virtual Environments**: + - Rust projects utilize `Cargo.toml` files to specify dependencies and project configurations. + - IDEs provide tools to create and manage virtual environments using Cargo, enabling developers to isolate project dependencies effectively. + +3. **Automatic Updates**: + - Cargo also automatically checks for updates to dependencies specified in the `Cargo.toml` file. + +4. **Package Project Management**: + - Rust projects include a `Cargo.toml` file at the project root to declare dependencies and their versions. + + - Features like dependency resolution, semantic versioning support, and conflict resolution are commonly integrated into IDEs to streamline package management in Rust projects. + + + +### User Stories: + +1. **As a developer, I want to be able to search for and install packages easily from a global repository to simplify the process of adding dependencies to my KCL projects.** + +2. **As a developer, I want to create and manage virtual environments for KCL development to isolate project dependencies and avoid version mismatch errors.** + +3. **As a developer, I want the KCL package to be automatically updated when a new version is available to ensure that I'm using the latest version with bug fixes and improvements.** + +4. **As a developer, I want to fetch dependencies of KCL packages directly within my IDE, similar to GoLand's integration with Go modules, to simplify the process of adding dependencies and improve productivity.** + +5. **As a developer, I want tools for managing dependencies in KCL projects, similar to Go's `go mod tidy`, to ensure consistency and correctness of dependencies.** diff --git a/docs/dev_guide/1.about_this_guide.md b/docs/dev_guide/1.about_this_guide.md new file mode 100644 index 000000000..0e5cfc375 --- /dev/null +++ b/docs/dev_guide/1.about_this_guide.md @@ -0,0 +1,20 @@ +# About this Guide + +This guide is intended to help document how `KCL` (the KCL compiler) works, and to help new contributors get involved in KCL development. + +This guide consists of **4** parts: + +1. **Building and Testing `KCL`**: Contains information that should be useful no matter how you are contributing, about building, testing, debugging, profiling, etc. +2. **Contributing to `KCL`**: Contains information that should be useful no matter how you are contributing, about procedures for contribution, using git and Github, etc. +3. **`KCL` Architecture**: Contains an introduction to the architecture of the compiler and a detailed introduction to each compilation process. +4. **Appendices**: There are a few of these with different information, including a glossary. + +The Guide itself is of course open-source as well, and the sources can be found at the [GitHub repository](https://github.com/kcl-lang/kcl/tree/main/docs/dev_guide). If you find any mistakes in the guide, please file an issue about it. Even better, open a Github Pull Request (PR) with a correction! + +If you do contribute to the guide, please see the corresponding subsection on writing documentation in this guide. + +Read [Quick Start](2.quick_start.md) to start. + +## Other Documentations + +* [KCL Documents](https://kcl-lang.io/) diff --git a/docs/dev_guide/2.quick_start.md b/docs/dev_guide/2.quick_start.md new file mode 100644 index 000000000..9d30a2da7 --- /dev/null +++ b/docs/dev_guide/2.quick_start.md @@ -0,0 +1,216 @@ +# Quick Start + +This documentation is *NOT* intended to be comprehensive; it is meant to be a quick guide for the most useful things. For more information, see the develop guide in its entirety. + +## Asking Questions + +Before asking a question, make sure you have: + +- Searched open and closed: + - [KCL GitHub Issues](https://github.com/kcl-lang/kcl/issues?utf8=%E2%9C%93&q=is%3Aissue) + +- Read the documentations: + - [KCL Documents](https://kcl-lang.io/docs/reference/lang/tour) + - [KCL Readme](https://github.com/kcl-lang/kcl) + +If you have any questions about `KCL`, you are welcome to ask your questions in [KCL Github Issues](https://github.com/kcl-lang/kcl/issues). When you ask a question, please describe the details as clearly as possible so that others in the KCL community can understand, and you *MUST* be polite and avoid personal attack and avoid not objective comparison with other projects. + +## Cloning and Building `KCL` + +### System Requirements + +The following hardware is recommended. + +- 10GB+ of free disk space. +- 4GB+ RAM +- 2+ cores + +### Dependencies + +#### Docker + +- `docker` + +In the top level of the `kcl-lang/kcl` repo and run: + +```sh +make sh-in-docker +``` + +Using a docker image is our recommended way, of course, you can also configure your local development environment according to the following content. + +#### macOS and OS X + +- `git` +- `Rust 1.79+` +- `LLVM 12` (Optional, only for the LLVM backend and release) +- `Python 3.7+` (Optional, only for integration tests) + +You'll need LLVM installed and `llvm-config` in your `PATH`. Just download from [LLVM 12](https://releases.llvm.org/download.html) or install `llvm@12` using `brew`. + +```sh +# llvm@12 (Optional, only for the LLVM backend and release) +brew install llvm@12 +``` + +Add the LLVM installation location to `LLVM_SYS_120_PREFIX` and the `$PATH`. + +```sh +export LLVM_SYS_120_PREFIX= +export PATH=/bin:$PATH +``` + +#### Linux + +- `git` +- `Rust 1.79+` +- `LLVM 12` (Optional, only for the LLVM backend and release) +- `Python3 Building Dependencies` (Optional, only for integration tests) + +For UNIX based systems, you can run: + +```sh +yum groupinstall -y "Development Tools" +yum install -y gcc patch libffi-devel python-devel zlib-devel bzip2-devel ncurses-devel sqlite-devel +yum install -y libpcap-devel xz-devel readline-devel tk-devel gdbm-devel db4-deve +yum -y install yum-utils +yum-builddep -y python3 +yum install -y zlib* +yum install -y openssl-devel +yum install -y glibc-static + +# clang-12 & llvm-12 (Optional, only for the LLVM backend and release), if llvm is not found, you can use ./scripts/build-llvm/build.sh to build llvm-12 locally. +yum -y install clang +clang --version +yum -y install llvm-devel +yum -y install libffi-devel +ln -s /usr/lib64/libtinfo.so.6 /usr/lib64/libtinfo.so +``` + +On Debian, Ubuntu, and other apt based systems, you can run: + +```sh +apt-get update + +apt-get install -y git wget curl +apt-get install -y make gcc patch +apt-get install -y python-dev libffi-dev +apt-get install -y zlib1g-dev ncurses-dev build-essential libncurses5-dev libgdbm-dev libnss3-dev libssl-dev libreadline-dev libffi-dev + +# clang-12 & llvm-12 (Optional, only for the LLVM backend and release), if llvm is not found, you can use ./scripts/build-llvm/build.sh to build llvm-12 locally. +apt-get install -y clang-12 lld-12 +ln -sf /usr/bin/clang-12 /usr/bin/clang +ln -sf /usr/bin/wasm-ld-12 /usr/bin/wasm-ld +``` + +#### Windows + +- `git` +- `Rust 1.79+` +- `LLVM 12` (Optional, only for the LLVM backend and release) +- `Python 3.7+` (Only for integration tests) + +Please add the LLVM installation location to `LLVM_SYS_120_PREFIX` and the `$PATH`. + +### Cloning + +You can just do a normal git clone: + +```sh +git clone https://github.com/kcl-lang/kcl.git +cd kcl +``` + +### Checking + +In the top level of the `kcl-lang/kcl` repo and run: + +```sh +make check +``` + +### Building + +#### macOS, OS X and Linux + +In the top level of the `kcl-lang/kcl` repo and run: + +```sh +make build +``` + +#### Windows + +In the top level of the `kcl-lang/kcl` repo and run: + +```sh +.\build.ps1 +``` + +### Building for Different Targets + +#### wasm32-wasi + +In the folder `kclvm` of the `kcl-lang/kcl` repo and run: + +```shell +make build-wasm +``` + +### Testing + +#### Unit Testing + +In the top level of the `kcl-lang/kcl` repo and run: + +```sh +make test +``` + +See the chapters on building and testing for more details. + +#### Grammar Integration Testing + +In the top level of the `kcl-lang/kcl` repo and run: + +```sh +make test-grammar +``` + +See the chapters on building and testing for more details. Note that the testing requires the Python environment. + +### Formatting + +In the top level of the `kcl-lang/kcl` repo and run: + +```sh +make fmt +``` + +## Contributor Procedures + +### Create an Issue + +Every change should be accompanied by a dedicated tracking issue for that change. The main text of this issue should describe the change being made, with a focus on what users must do to fix their code. The issue should be approachable and practical; it may make sense to direct users to some other issue for the full details. The issue also serves as a place where users can comment with questions or other concerns. + +When you open an issue on the `kcl-lang/kcl` repo, you need to to choose an issue template on this [page](https://github.com/kcl-lang/kcl/issues/new/choose), you can choose a template according to different situations and fill in the corresponding content, and you also need to select appropriate labels for your issue to help classify and identify. + +### Create a PR + +When you open a PR on the `kcl-lang/kcl` repo, you need to assign reviewers in the KCL Dev Team list, and reviewers are the persons that will approve the PR to be tested and merged. + +Please note that all code changes in the KCL project require corresponding comments and tests. For more code and test writing details, please see the chapters on code of conduct and testing. + +Besides, all PRs need to have corresponding issues tracking, and need to add appropriate labels and milestone information. + +#### Bug Fixes or "Normal" Code Changes + +For most PRs, no special procedures are needed. You can just open an issue and a PR, and it will be reviewed, approved, and merged. This includes most bug fixes, refactoring, and other user-invisible changes. + +Also, note that it is perfectly acceptable to open WIP PRs or GitHub Draft PRs. Some people prefer to do this so they can get feedback along the way or share their code with a collaborator. Others do this so they can utilize the CI to build and test their PR (e.g. if you are developing on a laptop). + +#### New Features + +In order to implement a new feature, usually you will need to go through [the KEP process](https://github.com/kcl-lang/KEP) to propose a design, have discussions, etc. + +After a feature is approved to be added, a tracking issue is created on the `kcl-lang/kcl` repo, which tracks the progress towards the implementation of the feature, any bugs reported, and eventually stabilization. The feature then can be implemented. diff --git a/docs/dev_guide/3.coding_conventions.md b/docs/dev_guide/3.coding_conventions.md new file mode 100644 index 000000000..581717e2d --- /dev/null +++ b/docs/dev_guide/3.coding_conventions.md @@ -0,0 +1,11 @@ +# Coding Conventions + +The core code of KCL is fully built by Rust, so we recommend that you follow the [Rust standard coding style](https://github.com/rust-lang/style-team). Thanks to Rust's rich and powerful language toolchains, we recommend that you use tools such as `cargo fmt`, `cargo clippy`, and `cargo fix` to check or refactor every commit of code change before submission. + +## Line Length + +Lines should be at most 100 characters. It's even better if you can keep things to 80. + +## Tabs v.s. Spaces + +Prefer 4-space indent. diff --git a/docs/dev_guide/4.architecture.md b/docs/dev_guide/4.architecture.md new file mode 100644 index 000000000..16fdfef13 --- /dev/null +++ b/docs/dev_guide/4.architecture.md @@ -0,0 +1,68 @@ +# Architecture + +## What Compiler does to KCL Code + +Although KCL is a **Domain Specific Language (DSL)**, it is not much different from compilers for general-purpose languages. The main difference is that KCL provides more relevant syntax semantics for the problems it solves. + +### Invocation + +Compilation begins when a user writes a KCL source program in text and invokes the `kcl` command on it. + +### Bootstrap + +The bootstrap phase initializes the compiler environment by setting up the required contexts, loading the configuration files, and preparing the necessary resources to process the input KCL files. + +### Lexing and Parsing + +Lexing, or lexical analysis, is the process of converting a sequence of characters into a sequence of tokens. A lexer, also known as a tokenizer, scans the source code to produce these tokens. + +Parsing takes the tokens produced by the lexer and attempts to construct an Abstract Syntax Tree (AST) that represents the hierarchical syntactic structure of the source code. + +### Resolving + +Resolving involves analyzing the AST to understand the relationships between different parts of the code. This includes identifying the scope of variables, resolving semantic names, and ensuring that references are correctly linked. + +### Compiling + +The compiling phase translates the resolved AST into an intermediate representation (IR) that is optimized for the subsequent phases. The IR is a lower-level representation of the program that is closer to machine code. + +### Evaluating + +After compilation, the evaluating phase executes the program using the IR including AST and LLVM IR. During this phase, the compiler can evaluate expressions, compute values, and perform optimizations that are runtime-specific. + +### Runtime + +At runtime, the KCL environment executes the compiled IR. This involves various runtime behaviors such as value calculations, error handling, and invoking system libraries. + +#### Values + +Values are the runtime representations of the entities defined in the KCL code. They can include primitives like integers and strings, as well as complex data structures. + +#### System Standard Libraries + +The standard libraries provide pre-defined functions and resources that the user can invoke in KCL programs. These libraries provide a wide array of functionality to interact with the system and perform complex tasks. + +## Language Tools + +Language tools are additional utilities that support language features, such as syntax highlighting, linting, formatting, and refactoring. + +## The IDE Extension and Language Server + +The IDE extension provides developers with tools to write KCL code efficiently within an Integrated Development Environment (IDE). The Language Server Protocol (LSP) is used to offer capabilities like code completion, error detection, and hover information. + +## API and Multiple Language SDKs + +KCL provides APIs and SDKs for multiple programming languages, allowing developers to interact with KCL programs from different technology stacks. + +## Appendix A: Glossary + +| Term | Meaning | +| -------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- | +| AST | The abstract syntax tree produced by the `kclvm_ast` crate; reflects user syntax very closely. | +| Lexer | A tool that converts the input code into a stream of tokens for parsing. | +| Parser | A tool that constructs an AST from a stream of tokens. | +| Namer | The compiler component responsible for assigning unique names to language entities and ensuring they are used consistently throughout the program. | +| Resolver | Part of the compiler that resolves ambiguities and links references to their corresponding declarations. | +| Intermediate Representation (IR) | An intermediate code representation generated during the compilation process, designed to optimize subsequent code generation steps or direct execution. | +| Value | In KCL, this usually refers to the result of a computation or any entity that can be expressed in code. | +| Type System | A set of rules and checking processes used by the compiler to determine the types of various expressions and variables. | diff --git a/docs/dev_guide/5.source_code.md b/docs/dev_guide/5.source_code.md new file mode 100644 index 000000000..3bbe4c989 --- /dev/null +++ b/docs/dev_guide/5.source_code.md @@ -0,0 +1,37 @@ +# High-level Overview of Source Code + +## Workspace Structure + +The `kcl-lang/kcl` repository consists of a single large cargo workspace. + +The repository consists of three main directories: + ++ `kclvm` contains the source code for the KCL core. It consists of many crates that together make up the compiler. ++ `compiler_base` contains a set of basic libraries for compilers, which are dependent on `kcl` ++ `scripts` contains the source code and image build scripts. ++ `test` contains the compiler grammar integration tests. + +## Core Code (kclvm) + +`kclvm` contains the source code for the KCL core. It consists of many crates that together make up the compiler. + ++ `api` contains over ten important APIs of KCL, including parsing code, running code, toolchain APIs, etc. It is the interface layer of KCL Rust core and other multi language SDKs of KCL, such as kcl-go, kcl-py, and kcl-java. ++ `ast` contains the core Abstract Syntax Tree (AST), tree walker and token definitions. ++ `ast_pretty` contains the tools and utilities to format and print the AST in a human-readable way. ++ `cmd` houses the command-line interface tools, enabling the users to interact with the compiler via the command-line such as `kclvm_cli` binary. ++ `compiler` contains the main compilation logic, responsible for converting the high-level KCL code into an intermediate representation before it is executed further. ++ `config` holds configuration-related code, including parsing command-line arguments, handling configuration files, and managing compiler settings. ++ `error` includes definitions and handlers for error messages, diagnostics, and compiler warnings to assist with debugging and user feedback. ++ `evaluator` is where the logic for evaluating expressions and executing KCL code resides. This often involves the runtime environment and can include the computation of values and handling of user-defined functions. ++ `lexer` is responsible for breaking down the raw KCL source into a stream of tokens (lexical analysis), which are then fed to the parser. ++ `loader` handles the loading and management of KCL modules, including discovering, parsing, and assembling modules from different sources into the compiler workflow. ++ `macros` contains macro definitions and utilities for code generation and automating repetitive coding patterns within the compiler source code itself. ++ `parser` takes the stream of tokens from the lexer and constructs the AST, which represents the syntactic structure of the KCL code. ++ `query` manages code queries and information retrieval, such as finding or replacing the definition of a variable, within the KCL programs. ++ `runner` provides the functionality to execute compiled KCL programs directly, managing the setup and invocation of the KCL runtime environment. ++ `runtime` includes the runtime support necessary for executing KCL, such as memory management, value representation, and built-in functions. ++ `sema` or `semantic analysis` contains the code for type checking, validation, and other analyses to ensure that the KCL programs follow predefined semantic rules. ++ `spec` houses the code related to the specification of the KCL language, which may include language versioning, feature definitions, syntax rules and API definitions. ++ `tools` contains additional utilities supporting the compiler, such as code formatters, linters, language server and development scripts for assisting in compiler maintenance and enhancement. ++ `utils` includes a collection of helper functions and common routines that are used across various parts of the project. ++ `version` holds the code responsible for managing the versioning of the KCL compiler, including setting, updating, and displaying version information. diff --git a/docs/dev_guide/6.languager_server.md b/docs/dev_guide/6.languager_server.md new file mode 100644 index 000000000..4b5527a06 --- /dev/null +++ b/docs/dev_guide/6.languager_server.md @@ -0,0 +1,158 @@ +# KCL Language Server Dev Guide + +## About the guide + +This guide describes the design and implementation of KCL Language Server and can help you better understand KCL Language Server. + +## What is Language Server Protocol + +[Language Server Extension Guide](https://code.visualstudio.com/api/language-extensions/language-server-extension-guide) + +Language Server is a special kind of Visual Studio Code extension that powers the editing experience for many programming languages. With Language Servers, you can implement autocomplete, error-checking (diagnostics), jump-to-definition, and many other language features supported in VS Code. + +Microsoft specified Language Server Protocol, which standardizes the communication between language tooling and code editor. This way, Language Servers can be implemented in any language and run in their own process to avoid performance cost, as they communicate with the code editor through the Language Server Protocol. Furthermore, any LSP-compliant language toolings can integrate with multiple LSP-compliant code editors, and any LSP-compliant code editors can easily pick up multiple LSP-compliant language toolings. LSP is a win for both language tooling providers and code editor vendors! + +![lsp](../image/lsp.png) + +## KCL Language Server Overview + +![overview](../image/overview.png) + +### Workflow + +When a user opens a kcl file in an IDE (taking VSCode as an example), the IDE plugin will be started, and the plugin will execute `kcl-language-server` in the PATH to run the server binary. +The server side mainly has the following steps: + ++ Setup stdio connections ++ Parse initialize params from client ++ Construct and send server-side capabilities to the client. These capabilities indicate which features the server implements, such as highlighting, completion, hover. For features that are not implemented, the client will not send those requests in subsequent communications. ++ execute `main_loop()`,it will new a `LanguageServerState` and execute the method `run()`. ++ `LanguageServerState` receive Events and distributes them to the thread pool for processing. ++ Process changes, The function process_vfs_changes() retrieves the changed (including create, deleted and modify) files from vfs. Compile new files based on cache, and write new compilation results (AST, and semantic information GlobalState) to db. If some compilation errors occurred, the server will actively send diagnostics to the client without require from the Client. + +### Key Concepts and Structures + +#### LanguageServerState + +LanguageServerState is an important structure on the server side. It mainly consists of the following parts: + ++ Sender: Channel to send language server messages to the client. ++ Task sender and receiver: Channel to send and receive tasks to from background operations. ++ analysis: Holds the state (compile result and semantic information) of the analysis process. ++ vfs: The virtual filesystem that holds all the file contents, mainly to solve the situation where changes in the IDE are not saved to the file system. ++ Various caches: Caching of multiple compilation stages to improve performance. + +#### LanguageServerSnapshot + +LanguageServerSnapshot is snapshot of the state of the language server. It copies the current state of LanguageServerState and handles various tasks in threads. + +#### Event + +Currently, Events are mainly divided into two categories: + ++ Task: Internal task scheduling on the server side. mainly include + + Notification: Send notification to the Client, mainly used to send some Log information + + Response: Send response to the Client. When each sub-thread processes the LSP request, it does not communicate directly with the client. Instead, first send `Task(Response(r))` on the server side, and then `LanguageServerState.sender.send(r)` + + Retry: Retry some requests ++ LSP Message: + + LSP Notification: LSP notification does not need to be returned by the server. For example, open files, close files, change file, etc. + + LSP Request: LSP request needs to be returned by the server. For example, goto definition, hover. + +For different Events, `handle_event()` mainly does two things: + +1. Dispatch different events, process events synchronously in the main thread or asynchronously in the thread pool. + +2. Process changes: For LSP Notification, although there is no need to return any information to the client, it has some changes and needs to update the status of LanguageServerState. Specifically, when opening or changing files, we need to compile these files for subsequent processing of other requests. When closing files, we can clear the cache of these files. + +#### Compile uint + +Before each compilation, the `lookup_compile_unit()` function is executed. This is because kcl, unlike other languages, does not have a clear definition of "project" (such as Cargo.toml in rust). We are unable to determine which project or projects the current file belongs to. So `lookup_compile_unit()` does some tradeoff to find "files" need to be compiled. Mainly follow the following rules: + ++ Entry files always need to be compiled ++ If there is a compiled configuration file (kcl.yaml) in the directory where the current file is located, compile it according to the definition of the compiled configuration. ++ If not, compile the current directory as a package. + +This is still not a good practice and we are considering how to solve it better. + +### Example + +#### Goto Definition + +Goto definition is a common function in IDEs. We use this case to illustrate how kcl lsp server works. + +1. Start VSCode and setup connection between client and server. +2. Open kcl file in VSCode. +3. Client Send a `DidOpenTextDocument` notification to server. +4. Server receive this notification and execute `handle_event()`: + 1. Dispatch this notification to `on_did_open_text_document()`, it will update vfs + 2. Process vfs changes: Compile it and save the compile result into db. +5. User execute `Goto Definition`(e.t., `command` + click) +6. Client Send a `GotoDefinition` request to server. +7. Server receive this request and execute `handle_event()`: + 1. Dispatch this request to `handle_goto_definition()`. + 1. Get the compile result from db, which insert in step 4.2 + 2. Use the API provided by `GlobalState` to query the definition position of the symbol corresponding to the requested Position. + 3. Send a `Task(Response(res))` + 2. No change, nothing todo. +8. Server receive this task and execute `handle_event()`: + 1. Dispatch this task to `send()`. This will actually send a `Response(res)` to the client. + 2. No change, nothing todo. +9. Client receive the response and jump to definition position. + +## KCL Language Client + +LSP Client is implemented based on the API provided by IDEs. Currently, KCL supports the following IDEs: + ++ VSCode: ++ IntelliJ: ++ NeoVim: + +## Build && Test + +1. build kcl-language-server +If you have prepared a kcl development environment, you can use the script we provide to build hole kcl project, it contains kcl-language-server: + +For MacOS and Linux + +```bash +./run.sh +``` + +For Windows + +```bash +./build.ps1 +``` + +Alternatively, you can use cargo to build kcl-language-server: + +```bash +make build-lsp +``` + +The built language server will be at `kclvm/target/release/kcl-language-server` + +1. Add kcl-language-server to PATH + +Add the `kcl-language-server` to PATH verify that: +`kcl-language-server version` + +Expected output: + +```bash +~: kcl-language-server version +Version: x.x.x-xxx +Platform: xxxxxx +GitCommit: xxxxxx +``` + +1. Test with client + +Download the KCL extension in the VSCode extension marketplace and open any kcl project or file to start testing. We can check the log from here. + +![test](../image/test.png) + +### Tips + +1. Don't use any `print!` or `println!` in your code. LSP will use stdio for client-server communication. The print information will be regarded as the message sent by the server to the client. If necessary, you can use `eprintln!` or `log_message()` +2. If you execute `kcl-language-server` in the CMD, there will be nothing output. It just wait for the client to send initialization message. diff --git a/docs/image/lsp.png b/docs/image/lsp.png new file mode 100644 index 000000000..4ec7b85a8 Binary files /dev/null and b/docs/image/lsp.png differ diff --git a/docs/image/overview.png b/docs/image/overview.png new file mode 100644 index 000000000..d72a56732 Binary files /dev/null and b/docs/image/overview.png differ diff --git a/docs/image/test.png b/docs/image/test.png new file mode 100644 index 000000000..11036dc11 Binary files /dev/null and b/docs/image/test.png differ diff --git a/docs/tools/docgen/docgen.md b/docs/tools/docgen/docgen.md deleted file mode 100644 index 3ba4e2645..000000000 --- a/docs/tools/docgen/docgen.md +++ /dev/null @@ -1,317 +0,0 @@ -# KCL 文档生成工具 - -Kusion 命令行工具支持从 KCL 源码中一键提取模型文档,并支持丰富的输出格式:JSON,YAML 和 Markdown 等。本文介绍 KCL 语言的文档规范,举例说明如何使用 KCL 文档生成工具提取文档,并展示新增本地化语言文档的流程。 - -## KCL 语言的文档规范 - -KCL文件的文档主要包含如下两个部分: - -* 当前 KCL Moudle 的文档:对当前 KCL 文件的说明 -* KCL 文件内包含的所有 Schema 的文档:对当前 Schema 的说明,其中包含 Schema 描述、Schema 各属性的描述、Examples 三部分,具体格式如下: - -1. Schema 描述 - -```python -"""这是Schema一个简短的描述信息 -""" -``` - -2. Schema 各属性的描述:包含属性描述、属性类型、默认值、是否可选 - -```python -""" -Attributes ----------- -x : type, default is a, optional. - Description of parameter `x`. -y : type, default is b, required. - Description of parameter `y`. -""" -``` - -其中,使用 `----------` 表示 `Attributes` 为一个标题(`-` 符号长度与标题长度保持一致),属性名称与属性类型用冒号 `:` 分隔,属性的说明另起一行并增加缩进进行书写。属性的默认值说明跟在属性类型之后使用逗号 `,` 分隔,书写为 `default is {默认值}` 形式,此外需要说明属性是否为可选/必选,对于可选属性在默认值之后书写 `optional`,对于必选属性在默认值之后书写 `required`。 - - -3. Examples - -```python -""" -Examples --------- -val = Schema { - name = "Alice" - age = 18 -} -""" -``` - -此外,KCL 文档字符串语法应采用 [re-structured text (reST)](https://docutils.sourceforge.io/rst.html) 语法子集,并使用 [Sphinx](https://www.sphinx-doc.org/en/master/) 渲染呈现。 - -## 从 KCL 源码生成文档 - -使用 kcl-doc generate 命令,从用户指定的文件或目录中提取文档,并输出到指定目录。 - -* 参数说明 -``` -usage: kcl-doc generate [-h] [--format YAML] [-o OUTPUT] [--r] - [--i18n-locale LOCALE] [--repo-url REPO_URL] - [files [files ...]] - -positional arguments: - files KCL file paths. If there's more than one files to - generate, separate them by space - -optional arguments: - -h, --help show this help message and exit - --format YAML Doc file format, support YAML, JSON and MARKDOWN. - Defaults to MARKDOWN - -o OUTPUT, --output-path OUTPUT - Specify the output directory. Defaults to ./kcl_doc - --r, -R, --recursive Search directory recursively - --i18n-locale LOCALE I18n locale, e.g.: zh, zh_cn, en, en_AS. Defaults to - en - --repo-url REPO_URL The source code repository url. It will displayed in - the generated doc to link to the source code. - --i18n-path I18N_PATH - The i18n input file path. It can be a path to an i18n - file when generating doc for a single kcl file, or a - path to a directory that contains i18n files when - generating docs for multipule kcl files. The program - will search for the i18n input file according to the - locale when generating docs. If i18n file exists, use - it instead of source file to generate the doc -``` - -* 从指定的一个或多个文件中提取文档,并输出到指定目录 - -```text -kcl-doc generate your_config.k your_another_config.k -o your_docs_output_dir -``` - -* 从指定目录内,递归地查找 KCL 源码文件,并提取文档 - -```text -kcl-doc generate your_config_dir -r -o your_docs_output_dir -``` - -* 在生成文档时,指定源码仓库地址。一经指定,生成的文档中将包含指向源码文件的链接 - -```text -kcl-doc generate your_config.k -o your_docs_output_dir --repo-url https://url/to/source_code -``` - -## 新增本地化语言的文档 - -如前所示,默认情况下,文档生成工具提取的文档以源码 docstring 的内容为准,因而文档的语言随 docstring 编写语言而定。如果需要为源文件新增本地化语言的文档,则可以遵循按如下步骤: - -1. 初始化 i18n 配置文件。该步骤基于指定的 KCL 源码文件,生成相应的 i18n 配置文件,文件格式可选 JSON/YAML,默认为 YAML. 输出的配置文件名称将以指定的目标本地化方言结尾 - -```text -kcl-doc init-i18n your_config.k --format JSON --i18n-locale your_target_locale -``` - -2. 手动修改上述生成的 i18n 配置文件,使用目标语言修改配置中的 doc 字段 - -3. 基于修改后的 i18n 配置,生成本地化语言的文档。工具将查找指定目标语言的 i18n 配置文件,并转化为最终的文档 - -```text -kcl-doc generate your_config_dir --i18n-locale your_target_locale --format Markdown -``` - -接下来,通过一个小例子演示新增本地化语言文档的过程。 - -1. 准备 KCL 源码文件,例如 server.k: - -```python -schema Server: - """Server is the common user interface for long-running - services adopting the best practice of Kubernetes. - - Attributes - ---------- - workloadType : str, default is "Deployment", required - Use this attribute to specify which kind of long-running service you want. - Valid values: Deployment, CafeDeployment. - See also: kusion_models/core/v1/workload_metadata.k. - name : str, required - A Server-level attribute. - The name of the long-running service. - See also: kusion_models/core/v1/metadata.k. - labels : {str:str}, optional - A Server-level attribute. - The labels of the long-running service. - See also: kusion_models/core/v1/metadata.k. - - Examples - ---------------------- - myCustomApp = AppConfiguration { - name = "componentName" - } - """ - - workloadType: str = "Deployment" - name: str - labels?: {str: str} -``` - -2. 从 server.k 得到初始化的 i18n 配置文件,例如希望为其增加中文文档,指定生成的配置文件格式为 YAML - -```text -kcl init-i18n server.k --format YAML --i18n-locale zh_cn -``` - -该命令将在当前目录下创建 kcl_doc 目录,并生成 i18n 配置文件 kcl_doc/i18n_server_zh_cn.yaml,其内容如下: - -```yaml -name: server -relative_path: ./server.k -schemas: -- name: Server - doc: | - Server is the common user interface for long-running - services adopting the best practice of Kubernetes. - attributes: - - name: workloadType - doc: | - Use this attribute to specify which kind of long-running service you want. - Valid values: Deployment, CafeDeployment. - See also: kusion_models/core/v1/workload_metadata.k. - type: - type_str: str - type_category: BUILTIN - builtin_type: STRING - default_value: '"Deployment"' - is_optional: false - - name: name - doc: | - A Server-level attribute. - The name of the long-running service. - See also: kusion_models/core/v1/metadata.k. - type: - type_str: str - type_category: BUILTIN - builtin_type: STRING - is_optional: false - default_value: '' - - name: labels - doc: | - A Server-level attribute. - The labels of the long-running service. - See also: kusion_models/core/v1/metadata.k. - type: - type_str: '{str: str}' - type_category: DICT - dict_type: - key_type: - type_str: str - type_category: BUILTIN - builtin_type: STRING - value_type: - type_str: str - type_category: BUILTIN - builtin_type: STRING - is_optional: true - default_value: '' - examples: | - myCustomApp = AppConfiguration { - name = "componentName" - } -doc: '' -source_code_url: '' -``` - -3. 修改初始化得到的 i18n 配置,将其中的 doc 字段修改为中文的描述,修改后的配置如下: - -```yaml -name: server -relative_path: ./server.k -schemas: -- name: Server - doc: | - Server 模型定义了采用 Kubernetes 最佳实践的持续运行的服务的通用配置接口 - attributes: - - name: workloadType - doc: | - workloadType 属性定义了服务的类型,是服务级别的属性。合法的取值有:Deployment, CafeDeployment. - 另请查看:kusion_models/core/v1/workload_metadata.k. - type: - type_str: str - type_category: BUILTIN - builtin_type: STRING - default_value: '"Deployment"' - is_optional: false - - name: name - doc: | - name 为服务的名称,是服务级别的属性。 - 另请查看:kusion_models/core/v1/metadata.k. - type: - type_str: str - type_category: BUILTIN - builtin_type: STRING - is_optional: false - default_value: '' - - name: labels - doc: | - labels 为服务的标签,是服务级别的属性。 - 另请查看:kusion_models/core/v1/metadata.k. - type: - type_str: '{str: str}' - type_category: DICT - dict_type: - key_type: - type_str: str - type_category: BUILTIN - builtin_type: STRING - value_type: - type_str: str - type_category: BUILTIN - builtin_type: STRING - is_optional: true - default_value: '' - examples: | - myCustomApp = AppConfiguration { - name = "componentName" - } -doc: '' -source_code_url: '' -``` - -4. 基于修改后的 i18n 配置,生成本地化语言的文档,执行如下命令,将输出中文的文档 kcl_doc/doc_server_zh_cn.md,命令及生成的文档内容如下: - -```text -kcl-doc generate server.k --i18n-locale zh_cn --format Markdown -``` - -~~~markdown -# server -## Schema Server -Server 模型定义了采用 Kubernetes 最佳实践的持续运行的服务的通用配置接口 - -### Attributes -|Name and Description|Type|Default Value|Required| -|--------------------|----|-------------|--------| -|**workloadType**
workloadType 属性定义了服务的类型,是服务级别的属性。合法的取值有:Deployment, CafeDeployment.
另请查看:kusion_models/core/v1/workload_metadata.k.|str|"Deployment"|**required**| -|**name**
name 为服务的名称,是服务级别的属性。
另请查看:kusion_models/core/v1/metadata.k.|str|Undefined|**required**| -|**labels**
labels 为服务的标签,是服务级别的属性。
另请查看:kusion_models/core/v1/metadata.k.|{str: str}|Undefined|optional| -### Examples -``` -myCustomApp = AppConfiguration { - name = "componentName" -} -``` - - - -~~~ - -## 附录 - -### 常见的 reST 概念 - -对于 reST 格式的文档,段落和缩进很重要,新段落用空白行标记,缩进即为表示输出中的缩进。可以使用如下方式表示字体样式: - -* \*斜体\* -* \*\*粗体\*\* -* \`\`等宽字体\`\` - -参考 [reST 文档](https://docutils.sourceforge.io/rst.html)获得更多帮助。 diff --git a/docs/tools/format/format.md b/docs/tools/format/format.md deleted file mode 100644 index da4c4224f..000000000 --- a/docs/tools/format/format.md +++ /dev/null @@ -1,64 +0,0 @@ -# KCL 格式化工具 - -## 简介 - -KCL 支持通过内置的命令行工具一键格式化多个 KCL 文件文档。本文展示 KCL 编码风格和 KCL 格式化工具的使用方式。 - -## 使用方式 - -* 单文件格式化 - -```text -kcl-fmt your_config.k -``` - -* 文件夹内多文件格式化 - -```text -kcl-fmt your_config_path -R -``` - -* 命令行参数 - * `-R|--recursive` 设置是否递归遍历子文件夹 - * `-w|--fmt-output` 设置是否输出到标准输出流,不加 `-w` 表示原地格式化 KCL 文件 - -## 格式化文件效果展示 - -* 格式化前 - -```py -import math -mixin DeploymentMixin: - service:str ="my-service" -schema DeploymentBase: - name: str - image : str -schema Deployment[replicas] ( DeploymentBase ) : - mixin[DeploymentMixin] - replicas : int = replicas - command: [str ] - labels: {str: str} -deploy = Deployment(replicas = 3){} -``` - -* 格式化后 - -```py -import math - -mixin DeploymentMixin: - service: str = "my-service" - -schema DeploymentBase: - name: str - image: str - -schema Deployment[replicas](DeploymentBase): - mixin [DeploymentMixin] - replicas: int = replicas - command: [str] - labels: {str:str} - -deploy = Deployment(replicas=3) {} - -``` diff --git a/docs/tools/kcl-lint/lint.md b/docs/tools/kcl-lint/lint.md deleted file mode 100644 index 3899dd99e..000000000 --- a/docs/tools/kcl-lint/lint.md +++ /dev/null @@ -1,155 +0,0 @@ -# KCL Lint 工具 - -## 简介 - -KCL 支持通过内置的命令行工具对 KCL 代码进行检查,并支持多种输出格式。本文档展示 KCL Lint 工具的使用方式。 - -## 示例 - -### 工程结构 - -``` -. -└── Test - └── kcl.mod - └── .kcllint - └── a.k - └── b.k - └── dir - └── c.k - └── test.k -``` - -其中,`.kcllint` 文件为配置参数文件,非必需项,`a.k`,`b.k`,`c.k`,`test.k` 为测试的 kcl 文件。 - -命令: - -```bash -kcl-lint your_config.k -``` - -或 - -``` -kcl-lint your_config_path -``` - -lint 配置文件 - -``` -kcl-lint --config abspath/.kcllint your_config.k -``` - -输出结果示例: - -``` -/Users/../test.k:12:1: E0501 line too long (122 > 120 characters) -# line too long, line too long, line too long, line too long, line too long, line too long, line too long, line too long, -^ - -/Users/../test.k:14:1: E0413 Import b should be placed at the top of the module -import b -^ - - -Check total 1 files: -1 E0413: ImportStmt is not at the top of the file -1 E0501: Line too long -KCL Lint: 2 problems - -``` - -## KCL Lint 工具使用方式 - -### CLI 参数 - -``` -usage: kcl-lint [-h] [--config file] [file] - -positional arguments: - file KCL file path - -optional arguments: - -h, --help show this help message and exit - --config file KCL lint config path - -``` - -+ --config : lint 配置文件 `.kcllint` 的路径 -+ file : 需要检查的单个 `.k` 文件路径或路径目录下的所有 `.k` 文件,支持绝对路径或当前目录的相对路径 - -### Lint 配置参数 - -#### 优先级 - -Lint 的配置参数的优先级如下: - -1. CLI 参数中的 `--config file` 路径的 `.kcllint` 文件 -2. 被检查 `.k` 文件所在目录或被检查目录下的 `.kcllint` 文件 -3. 默认配置 - -#### .kcllint - -`.kcllint` 文件以 yaml 格式书写。其内容包括: - -- check_list 用于选择检查的 checker,可选项为 `"import"`、`"misc"`、`"basic"` -- ignore 用于选择忽略的检查项,可选项见错误代码 -- max_line_length 为检查的参数,即单行代码最大长度 -- output 用于选择输出流和输出格式,可选项为 `"stdout"`、`"file"`、`"sarif"` -- output_path 为可选项,当 output 选择了"file"或"sarif",则必须设置输出文件的路径 -- [schema|mixin|argument|variable|schema_attribute]_naming_style 使用内置命名规范检查 -- [schema|mixin|argument|variable|schema_attribute]_RGX 使用自定义正则表达式进行命名规范检查 -- bad_names 禁用的命名 - -示例: - -```yaml -check_list: ["import","misc"] -ignore: ["E0501"] -max_line_length: 120 -output: ["stdout"] -``` - -#### 默认配置 - -```yaml -check_list: [import, misc, basic] -ignore: [] -max_line_length: 200 -output: [stdout] -output_path: null -module_naming_style: ANY -package_naming_style: ANY -schema_naming_style: PascalCase -mixin_naming_style: PascalCase -argument_naming_style: camelCase -variable_naming_style: ANY -schema_attribute_naming_style: ANY -module_rgx: null -package_rgx: null -schema_rgx: null -mixin_rgx: null -argument_rgx: null -variable_rgx: null -schema_attribute_rgx: null -bad_names: [foo, bar, baz, toto, tata, tutu, I, l, O] -``` - -### 检查项及错误代码 - -目前提供 import,misc,和 basic - -- import_checker - - - E0401: Unable to import. - - W0401: Reimport. - - E0406: Module import itself. - - W0411: Import but unused. - - E0413: ImportStmt is not at the top of the file. -- misc_checker - - - E0501: Line too long. -- basic_checker - - - C0103: Invalid-name - - C0104: Disallowed-name. diff --git a/docs/tools/kcl-test/kcl-test.md b/docs/tools/kcl-test/kcl-test.md deleted file mode 100644 index 55e0f87f4..000000000 --- a/docs/tools/kcl-test/kcl-test.md +++ /dev/null @@ -1,173 +0,0 @@ -# KCL 单元测试工具 - -## 简介 - -KCL 支持通过内置的 `kcl-test` 命令行工具和 `testing` 包提供了简易的测试框架。每个目录下的全部 KCL 文件是一个测试整体,每个 `_test.k` 中 `Test` 开头的 schema 是一个测试案例。 - -## 使用方式 - -假设有 hello.k 文件,代码如下: - -```python -schema Person: - name: str = "kcl" - age: int = 1 - -hello = Person { - name = "hello kcl" - age = 102 -} -``` - -构造 hello_test.k 测试文件,内容如下: - -```python -schema TestPerson: - a = Person{} - assert a.name == 'kcl' - -schema TestPerson_age: - a = Person{} - assert a.age == 1 - -schema TestPerson_ok: - a = Person{} - assert a.name == "kcl" - assert a.age == 1 -``` - -然后再目录下执行 `kcl-test` 命令: - -``` -$ kcl-test -ok /pkg/to/app [365.154142ms] -$ -``` - -## 失败的测试 - -将 hello_test.k 测试代码修改如下,构造失败的测试: - -```python -# Copyright 2021 The KCL Authors. All rights reserved. - -import testing - -schema TestPerson: - a = Person{} - assert a.name == 'kcl2' - -schema TestPerson_age: - a = Person{} - assert a.age == 123 - -schema TestPerson_ok: - a = Person{} - assert a.name == "kcl2" - assert a.age == 1 -``` - -测试输出的错误如下: - -``` -$ kcl-test -FAIL /pkg/to/app [354.153775ms] ----- failed [48.817552ms] - KCL Runtime Error: File /pkg/to/app/hello_test.k:7: - assert a.name == 'kcl2' - Assertion failure ----- failed [47.515009ms] - KCL Runtime Error: File /pkg/to/app/hello_test.k:11: - assert a.age == 123 - Assertion failure ----- failed [47.26677ms] - KCL Runtime Error: File /pkg/to/app/hello_test.k:15: - assert a.name == "kcl2" - Assertion failure -$ -``` - -## 配置 option 参数 - -可以通过 testing 包指定面值类型的命令行参数: - -```python -schema TestOptions: - testing.arguments("name", "ktest") - testing.arguments("age", "123") - testing.arguments("int0", 0) - testing.arguments("float0", 0.0) - testing.arguments("bool-true", True) - testing.arguments("bool-false", False) - - name = option("name") - assert name == "ktest" - - age = option("age") - assert age == 123 - - assert option("int0") == 0 - assert option("float0") == 0.0 - assert option("bool-true") == True - assert option("bool-false") == False -``` - -其中 `testing.arguments` 定义一组 key-value 参数,只有在当前的测试中有效。 - -option 参数也可以从 settings.yaml 文件读取。假设有 `./settings.yaml` 文件如下: - -```yaml - - key: app-name - value: app - - key: env-type - value: prod - - key: image - value: reg.docker.inc.com/test-image -``` - -然后可以通过 `testing.setting_file("./settings.yaml")` 方式配置参数。同时依然支持 `testing.arguments()` 覆盖配置文件中的参数: - -```py -schema TestOptions_setting: - testing.setting_file("./settings.yaml") - testing.arguments("file", "settings.yaml") - - assert option("app-name") == "app" - assert option("file") == "settings.yaml" -``` - -testing.setting_file("settings.yaml") 则是从 yaml 文件加载对应的 key-value 参数。 - -## 测试插件 - -如果要测试的目录含有 `plugin.py` 和测试文件,自动切换到插件模式。那么将测试前设置 `KCL_PLUGINS_ROOT` 环境变量(不能再访问其他目录的插件)用于测试当前插件,测试完成之后恢复之前的 `KCL_PLUGINS_ROOT` 环境变量。 - -## 集成测试 - -目录含有 `*.k` 时自动执行集成测试,如果有 `stdout.golden` 则验证输出的结果,如果有 `stderr.golden` 则验证错误。支持 `settings.yaml` 文件定义命令行参数。 - -如果有 k 文件含有 `# kcl-test: ignore` 标注注释将忽略测试。 - -## 批量测试 - -- `kcl-test path` 执行指定目录的测试, 当前目录可以省略该参数 -- `kcl-test -run=regexp` 可以执行匹配模式的测试 -- `kcl-test ./...` 递归执行子目录的单元测试 - -## 命令行参数 - -``` -$ kcl-test -h -NAME: - kcl-go test - test packages - -USAGE: - kcl-go test [command options] [packages] - -OPTIONS: - --run value Run only those tests matching the regular expression. - --quiet, -q Set quiet mode (default: false) - --verbose, -v Log all tests as they are run (default: false) - --debug, -d Run in debug mode (for developers only) (default: false) - --help, -h show help (default: false) -``` diff --git a/docs/tools/kcl-vet/kcl-vet.md b/docs/tools/kcl-vet/kcl-vet.md deleted file mode 100644 index d10e2ace5..000000000 --- a/docs/tools/kcl-vet/kcl-vet.md +++ /dev/null @@ -1,77 +0,0 @@ -# KCL Validation 工具 - -## 简介 - -KCL 支持通过内置的 `kcl-vet` 命令行工具提供了基本的配置数据校验能力,可以编写 KCL schema 对输入的 JSON/YAML 格式文件进行类型以及数值的校验。 - -## 使用方式 - -假设有 data.json 文件,代码如下: - -```json -{ - "name": "Alice", - "age": "18", - "message": "This is Alice", - "data": { - "id": "1", - "value": "value1" - }, - "labels": { - "key": "value" - }, - "hc": [1, 2, 3] -} -``` - -构造 schema.k 校验文件,内容如下: - -```py -schema User: - name: str - age: int - message?: str - data: Data - labels: {str:} - hc: [int] - - check: - age > 10 - -schema Data: - id: int - value: str -``` - -在目录下执行如下命令 - -``` -$ kcl-vet data.json schema.k -Validate succuss! -``` - -## 指定校验的 schema - -当教研的 KCL 文件中存在多个 schema 定义时,kcl-vet 工具会默认取第一个 schema 定义进行校验,如果需要指定校验的 schema,可以使用 `-d|--schema` 参数 - -``` -$kcl-vet data.json schema.k -d User -``` - -## 命令行参数 - -``` -$ kcl-vet -h -usage: kcl-vet [-h] [-d schema] [--format format] [-n attribute_name] - data_file kcl_file - -positional arguments: - data_file Validation data file - kcl_file KCL file - -optional arguments: - -h, --help show this help message and exit - -d schema, --schema schema - --format format Validation data file format, support YAML and JSON - -n attribute_name, --attribute-name attribute_name -``` diff --git a/icons/KCL128x128.png b/icons/KCL128x128.png deleted file mode 100644 index 2e1660d7f..000000000 Binary files a/icons/KCL128x128.png and /dev/null differ diff --git a/icons/KCL128x128.svg b/icons/KCL128x128.svg deleted file mode 100644 index ded49cd57..000000000 --- a/icons/KCL128x128.svg +++ /dev/null @@ -1,12 +0,0 @@ - - - - - background - - - - Layer 1 - K - - \ No newline at end of file diff --git a/icons/KCL16x16.png b/icons/KCL16x16.png deleted file mode 100644 index e84bab49d..000000000 Binary files a/icons/KCL16x16.png and /dev/null differ diff --git a/icons/KCL16x16.svg b/icons/KCL16x16.svg deleted file mode 100644 index 761f6496f..000000000 --- a/icons/KCL16x16.svg +++ /dev/null @@ -1,15 +0,0 @@ - - - - background - - - - - - - Layer 1 - K - - \ No newline at end of file diff --git a/icons/KCL40x40.png b/icons/KCL40x40.png deleted file mode 100644 index 7fa6866c3..000000000 Binary files a/icons/KCL40x40.png and /dev/null differ diff --git a/icons/KCL40x40.svg b/icons/KCL40x40.svg deleted file mode 100644 index 390bb86ae..000000000 --- a/icons/KCL40x40.svg +++ /dev/null @@ -1,12 +0,0 @@ - - - - - background - - - - Layer 1 - K - - \ No newline at end of file diff --git a/internal/kclvm_py/Makefile b/internal/kclvm_py/Makefile deleted file mode 100644 index 5a19ae925..000000000 --- a/internal/kclvm_py/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -default: - -gen: - go run 0_gen.go > z_embed.go - -go fmt - go test - -clean: diff --git a/internal/kclvm_py/README.md b/internal/kclvm_py/README.md deleted file mode 100644 index f0ee47045..000000000 --- a/internal/kclvm_py/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# KCLVM-Python - -KCLVM Python implementation, will be abandoned soon, please do not submit any code to it, it will be reorganized in the way of KCLVM Python SDK in the future. diff --git a/internal/kclvm_py/__init__.py b/internal/kclvm_py/__init__.py deleted file mode 100644 index d74aaf8ad..000000000 --- a/internal/kclvm_py/__init__.py +++ /dev/null @@ -1 +0,0 @@ -# Copyright 2021 The KCL Authors. All rights reserved. diff --git a/internal/kclvm_py/__main__.py b/internal/kclvm_py/__main__.py deleted file mode 100644 index e93e22095..000000000 --- a/internal/kclvm_py/__main__.py +++ /dev/null @@ -1,5 +0,0 @@ -# Copyright 2021 The KCL Authors. All rights reserved. - -import kclvm.internal.kclvm_internal.main as main - -main.Main() diff --git a/internal/kclvm_py/api/object/__init__.py b/internal/kclvm_py/api/object/__init__.py deleted file mode 100644 index b6d5b552a..000000000 --- a/internal/kclvm_py/api/object/__init__.py +++ /dev/null @@ -1,53 +0,0 @@ -# Copyright 2021 The KCL Authors. All rights reserved. - -from .object import * -from .function import * -from .schema import * -from .decorator import * -from .bytecode import * - -__all__ = [ - "KCLObject", - "KCLBaseTypeObject", - "KCLLiteralObject", - "KCLIntObject", - "KCLFloatObject", - "KCLStringObject", - "KCLNameConstantObject", - "KCLTrueObject", - "KCLFalseObject", - "KCLNoneObject", - "KCLBuiltinTypeObject", - "KCLListTypeObject", - "KCLDictTypeObject", - "KCLUnionTypeObject", - "KCLSchemaTypeObject", - "KCLNumberMultiplierTypeObject", - "KCLSchemaObject", - "KCLSchemaIndexSignatureObject", - "KCLDictObject", - "KCLListObject", - "KCLClosureObject", - "KCLFunctionObject", - "KCLBuiltinFunctionObject", - "KCLMemberFunctionObject", - "KCLCompiledFunctionObject", - "KCLUnpackObject", - "KCLSliceObject", - "KCLObjectType", - "KCLIterObject", - "KCLModuleObject", - "KCLDecoratorObject", - "KWArg", - "SCHEMA_SELF_VALUE_KEY", - "SCHEMA_CONFIG_VALUE_KEY", - "Parameter", - "KCLFunctionTypeObject", - "to_kcl_obj", - "to_python_obj", - "KCLBytecode", - "KCLProgram", - "KCLResult", - "KCLTypeKind", - "SchemaTypeRefGraph", -] diff --git a/internal/kclvm_py/api/object/bytecode.py b/internal/kclvm_py/api/object/bytecode.py deleted file mode 100644 index 77d174c92..000000000 --- a/internal/kclvm_py/api/object/bytecode.py +++ /dev/null @@ -1,63 +0,0 @@ -# Copyright 2021 The KCL Authors. All rights reserved. - -import typing - -from .object import ( - KCLObject, - to_python_obj, - to_kcl_obj, -) -import kclvm.api.object.internal as internal - - -class KCLResult: - def __init__( - self, m: typing.Dict[str, KCLObject], filename: typing.Optional[str] = None - ): - self.m: typing.Dict[str, KCLObject] = m - self.filename: str = filename - - def __str__(self) -> str: - return f"{self.m}" - - def filter_by_path_selector( - self, to_kcl: bool = True - ) -> typing.Dict[str, KCLObject]: - if not internal.is_selector_mode(): - return self.m - selector_index = internal.build_selector_index() - filtered_result = {} - for k, v in self.m.items(): - if k in selector_index: - select_data = internal.select_instance_attributes( - to_python_obj(self.m[k]), selector_index[k] - ) - filtered_result[k] = to_kcl_obj(select_data) if to_kcl else select_data - self.m = filtered_result or self.m - return self.m - - -class KCLBytecode: - def __init__( - self, - *, - names: typing.List[str] = None, - constants: typing.List[KCLObject] = None, - instructions: typing.List[int] = None, - ): - self.names: typing.List[str] = names if names else [] - self.constants: typing.List[KCLObject] = constants if constants else [] - self.instructions: typing.List[int] = instructions if instructions else [] - - -class KCLProgram: - def __init__( - self, - *, - root: str = "", - main: str = "", - pkgs: typing.Dict[str, KCLBytecode] = None, - ): - self.root: str = root if root else "" - self.main: str = main if main else "" - self.pkgs: typing.Dict[str, KCLBytecode] = pkgs if pkgs else {} diff --git a/internal/kclvm_py/api/object/decorator.py b/internal/kclvm_py/api/object/decorator.py deleted file mode 100644 index 43202e476..000000000 --- a/internal/kclvm_py/api/object/decorator.py +++ /dev/null @@ -1,58 +0,0 @@ -# Copyright 2021 The KCL Authors. All rights reserved. - -from typing import List, Any -from dataclasses import dataclass - -from kclvm.api.object.internal import decorator_factory, Decorator, DecoratorTargetType - -from .object import ( - KCLObject, - KCLObjectType, - to_python_obj, - to_kcl_obj, -) -from .function import ( - KCLFunctionObject, - KWArg, -) - - -@dataclass -class KCLDecoratorObject(KCLFunctionObject): - target: DecoratorTargetType - name: str - key: str = "" - value: Any = None - decorator: Decorator = None - - def resolve(self, args: List[KCLObject], kwargs: List[KWArg]): - """Build a internal decorator object""" - args = to_python_obj(args) - kwargs = to_python_obj({kw.name.value: kw.value for kw in kwargs}) - self.decorator = decorator_factory.get(self.name, self.target, *args, **kwargs) - return self - - def call( - self, args: List[KCLObject], kwargs: List[KWArg], vm=None, key=None, value=None - ) -> KCLObject: - """Decorator run""" - self.key = to_python_obj(key) - self.value = to_python_obj(value) - return to_kcl_obj( - self.decorator.run( - self.key, - self.value if self.target == DecoratorTargetType.ATTRIBUTE else None, - ) - ) - - def type(self) -> KCLObjectType: - """ - Get the object type - """ - return KCLObjectType.DECORATOR - - def type_str(self) -> str: - """ - Get the object type - """ - return "decorator" diff --git a/internal/kclvm_py/api/object/function.py b/internal/kclvm_py/api/object/function.py deleted file mode 100644 index 62d45cb6b..000000000 --- a/internal/kclvm_py/api/object/function.py +++ /dev/null @@ -1,181 +0,0 @@ -# Copyright 2021 The KCL Authors. All rights reserved. - -from abc import abstractmethod -from typing import Callable, List, Optional -from dataclasses import dataclass - -from .object import ( - ANT_TYPE_STR, - KCLObject, - KCLListObject, - KCLObjectType, - KCLBaseTypeObject, - KCLTypeKind, - to_python_obj, - to_kcl_obj, -) - -BUILTIN_KCL_OBJ_FUNCTIONS = [ - "typeof", -] - - -@dataclass -class KWArg: - """KCL function call arguments - - Parameters - ---------- - - name: str - - value: KCLObject - """ - - name: KCLObject - value: KCLObject - - -@dataclass -class Parameter: - """KCL function definition parameter - - Parameters - ---------- - - name: str - The argument name - - value: KCLObject - Value is the default value to use if the argument is not provided. - If no default is specified then value is None. - - type_annotation: str - The argument type annotation. - """ - - name: str = None - value: Optional[KCLObject] = None - type_annotation: Optional[str] = None - type: Optional[KCLBaseTypeObject] = None - - def param_doc(self) -> str: - _type_str = self.type.type_str() if self.type else "any" - _value_doc = "" - if self.value: - _value_str = ( - f'"{self.value.value}"' - if isinstance(self.value.value, str) - else f"{self.value.value}" - ) - _value_doc = f"={_value_str}" - return f"{self.name}: {_type_str}{_value_doc}" - - -@dataclass -class KCLFunctionObject(KCLObject): - name: str - - def type(self) -> KCLObjectType: - """ - Get the object type - """ - return KCLObjectType.FUNCTION - - def type_str(self) -> str: - """ - Get the object type - """ - return "function" - - @abstractmethod - def call(self, args: List[KCLObject], kwargs: List[KWArg], vm=None) -> KCLObject: - pass - - -@dataclass -class KCLBuiltinFunctionObject(KCLFunctionObject): - function: Callable - - def call(self, args: List[KCLObject], kwargs: List[KWArg], vm=None) -> KCLObject: - if not self.function: - raise Exception("invalid kcl function object") - - if self._is_kcl_obj_builtin(): - return to_kcl_obj( - self.function(*args, **{kw.name.value: kw.value for kw in kwargs}) - ) - - return to_kcl_obj( - self.function( - *to_python_obj(args), - **to_python_obj({kw.name.value: kw.value for kw in kwargs}), - ) - ) - - def _is_kcl_obj_builtin(self) -> bool: - return self.name in BUILTIN_KCL_OBJ_FUNCTIONS - - -@dataclass -class KCLMemberFunctionObject(KCLFunctionObject): - obj: KCLObject - - def call(self, args: List[KCLObject], kwargs: List[KWArg], vm=None) -> KCLObject: - return to_kcl_obj( - self.obj.call_member_method( - self.name, - *to_python_obj(args), - **to_python_obj({kw.name.value: kw.value for kw in kwargs}), - ) - ) - - -@dataclass -class KCLCompiledFunctionObject(KCLFunctionObject): - instructions: list = None - names: list = None - constants: list = None - num_parameters: int = 0 - num_locals: int = 0 - params: List[Parameter] = None - pkgpath: str = None - closure: KCLListObject = None - - -@dataclass -class KCLClosureObject(KCLObject): - name: str = None - parameters: List[str] = None - - def type(self) -> KCLObjectType: - """ - Get the object type - """ - return KCLObjectType.CLOSURE - - def type_str(self) -> str: - """ - Get the object type - """ - return "closure" - - -@dataclass -class KCLFunctionTypeObject(KCLBaseTypeObject): - name: str - params: List[Parameter] - self_type: Optional[KCLBaseTypeObject] - return_type: KCLBaseTypeObject - doc: Optional[str] = None - kwonlyargs_index: int = None - is_variadic: bool = False - - def type_str(self) -> str: - return "function(({}) -> {})".format( - ", ".join( - [ - p.type.type_str() if p.type else ANT_TYPE_STR - for p in self.params or [] - ] - ), - self.return_type.type_str() if self.return_type else ANT_TYPE_STR, - ) - - def type_kind(self) -> str: - return KCLTypeKind.FuncKind diff --git a/internal/kclvm_py/api/object/internal/__init__.py b/internal/kclvm_py/api/object/internal/__init__.py deleted file mode 100644 index 3c83e9176..000000000 --- a/internal/kclvm_py/api/object/internal/__init__.py +++ /dev/null @@ -1,44 +0,0 @@ -# Copyright 2021 The KCL Authors. All rights reserved. - -from .option import ( - kcl_option, - kcl_option_exec, - kcl_option_init_all, - kcl_option_init, - kcl_option_reset, - kcl_option_check, -) -from .decorators import ( - decorator_factory, - Decorator, - DecoratorTargetType, - Deprecated, - Info, -) -from .selector import select -from .undefined import Undefined, UndefinedType -from .path_selector import ( - is_selector_mode, - build_selector_index, - select_instance_attributes, -) - -__all__ = [ - "kcl_option", - "kcl_option_exec", - "kcl_option_init_all", - "kcl_option_init", - "kcl_option_reset", - "kcl_option_check", - "select", - "is_selector_mode", - "build_selector_index", - "select_instance_attributes", - "decorator_factory", - "Decorator", - "DecoratorTargetType", - "Deprecated", - "Info", - "Undefined", - "UndefinedType", -] diff --git a/internal/kclvm_py/api/object/internal/common.py b/internal/kclvm_py/api/object/internal/common.py deleted file mode 100644 index 78c2216c7..000000000 --- a/internal/kclvm_py/api/object/internal/common.py +++ /dev/null @@ -1,228 +0,0 @@ -# Copyright 2021 The KCL Authors. All rights reserved. - -import re - -import kclvm.kcl.error as kcl_error - -DICT_TYPE_NAME = "dict" -LIST_TYPE_NAME = "list" -SCHEMA_TYPE_NAME = "Schema" -CLASS_TYPE_TMPL = "" -builtin_types = ["str", "int", "float", "bool"] - - -def isdicttype(expectedtype): - if isinstance(expectedtype, str) and len(expectedtype) >= 2: - return expectedtype[0] == "{" and expectedtype[-1] == "}" - else: - return False - - -def islisttype(expectedtype): - if isinstance(expectedtype, str) and len(expectedtype) >= 2: - return expectedtype[0] == "[" and expectedtype[-1] == "]" - else: - return False - - -def separate_kv(expectedtype): - stack = "" - n = 0 - try: - for c in expectedtype: - if c == "[" or c == "{": - stack += c - elif c == "]": - if stack[-1] != "[": - raise - stack = stack[:-1] - elif c == "}": - if stack[-1] != "{": - raise - stack = stack[:-1] - elif c == ":": - if len(stack) != 0: - raise - return expectedtype[:n], expectedtype[n + 1 :] - n += 1 - except Exception: - return None, None - return "", "" - - -def dereferencetype(expectedtype): - if ( - len(expectedtype) > 1 - and (expectedtype[0] == "[" and expectedtype[-1] == "]") - or (expectedtype[0] == "{" and expectedtype[-1] == "}") - ): - return expectedtype[1:-1] - return expectedtype - - -def split_type_union(type_union: str): - """ - Split the union type e.g. 'A|B|C' -> ['A', 'B', 'C'], do not split '|' in dict and list - """ - i = 0 - s_index = 0 - stack = [] - types = [] - while i < len(type_union): - c = type_union[i] - if c == "|" and len(stack) == 0: - types.append(type_union[s_index:i]) - s_index = i + 1 - # List/Dict type - if c == "[" or c == "{": - stack.append(c) - # List/Dict type - if c == "]" or c == "}": - stack.pop() - # String literal type - if c == '"': - matched = re.match(r'"(?!"").*?(? bool: - """Whether a type string is a union type string, e.g. A|B|C, - and detect '|' in type string except '|' in dict or list. - """ - stack = [] - i = 0 - while i < len(tpe or ""): - c = tpe[i] - if c == "|" and not stack: - return True - if c in "[{": - stack.append(c) - if c in "]}": - stack.pop() - if c == '"': - matched = re.match(r'"(?!"").*?(?", tpe_str).group(1) - else: - return tpe_str - - -def get_builtin_type(tpe_str): - if "kclvm_runtime.builtins" in tpe_str: - return re.match(r"kclvm_runtime.builtins.(.*)", tpe_str).group(1) - else: - return tpe_str - - -def demangle_type(tpe: str, var=None): - if not tpe: - return tpe - if isdicttype(tpe): - key_tpe, value_tpe = separate_kv(dereferencetype(tpe)) - return "{{{}:{}}}".format(demangle_type(key_tpe), demangle_type(value_tpe)) - elif islisttype(tpe): - return "[{}]".format(demangle_type(dereferencetype(tpe))) - else: - return get_builtin_type(tpe) - - -def do_union(obj, delta): - """ - Union delta to obj recursively - """ - obj_tpe = get_class_name(str(type(obj))) - delta_tpe = get_class_name(str(type(delta))) - if isinstance(obj, list): - if not isinstance(delta, list): - kcl_error.report_exception( - err_type=kcl_error.ErrType.TypeError_Runtime_TYPE, - arg_msg="union failure, expect list, got {}".format( - demangle_type(delta_tpe, delta) - ), - ) - length = len(obj) if len(obj) > len(delta) else len(delta) - result_list = obj - for idx in range(length): - if idx >= len(obj): - result_list.append(delta[idx]) - elif idx < len(delta): - result_list[idx] = union(result_list[idx], delta[idx]) - return result_list - if isinstance(obj, dict): - if not isinstance(delta, dict): - kcl_error.report_exception( - err_type=kcl_error.ErrType.TypeError_Runtime_TYPE, - arg_msg="union failure, expect dict, got {}".format( - demangle_type(delta_tpe, delta) - ), - ) - result_dict = obj - for k in delta: - if k not in obj: - result_dict[k] = delta[k] - else: - result_dict[k] = union(obj[k], delta[k]) - return result_dict - if type(obj) != type(delta): - kcl_error.report_exception( - err_type=kcl_error.ErrType.TypeError_Runtime_TYPE, - arg_msg="union failure, expect {}, got {}".format( - demangle_type(obj_tpe), demangle_type(delta_tpe, delta) - ), - ) - return delta - - -def union(obj, delta, or_mode=False): - if obj is None: - return delta - if delta is None: - return obj - if isinstance(obj, (list, dict)) or isinstance(delta, (list, dict)): - return do_union(obj, delta) - if or_mode: - return obj | delta - else: - return obj if delta is None else delta diff --git a/internal/kclvm_py/api/object/internal/decorators.py b/internal/kclvm_py/api/object/internal/decorators.py deleted file mode 100644 index a48811aeb..000000000 --- a/internal/kclvm_py/api/object/internal/decorators.py +++ /dev/null @@ -1,255 +0,0 @@ -# Copyright 2021 The KCL Authors. All rights reserved. - -import sys -import enum -from abc import ABCMeta, abstractmethod -from typing import Dict, Type - -import kclvm.kcl.error as kcl_error - -DECORATOR_TARGET_ERR_NAME_MSG = ": Decorator target name cannot be empty" - - -class DecoratorTargetType(enum.Enum): - """ - Marked annotated position by the decorator - """ - - SCHEMA_TYPE = 0 - ATTRIBUTE = 1 - - -class Decorator(metaclass=ABCMeta): - """ - An abstract decorator. - - This abc is used to run actions as a wrapper of key-value pair in kcl schema. - - A concrete decorator should inherit this class and impel the run method to handle key-value. - - :class:`~Deprecated` class is a sample of decorator which is used to check deprecation of key on config. - - you can use your ``Deprecated`` class like this in your source code as follows: - - .. code-block:: python - - schema Person: - @deprecated(version="1.16", reason="use firstName and lastName instead", strict=True) - name : str - - .. code-block:: python - - @deprecated(version="1.16", reason="use firstName and lastName instead", strict=True) - schema Person: - name : str - - """ - - def __init__(self, name: str, target: DecoratorTargetType, *args, **kwargs): - self.name = name - try: - self.target = ( - target - if isinstance(target, DecoratorTargetType) - else DecoratorTargetType(target) - ) - except ValueError: - msg = ( - kcl_error.INVALID_DECORATOR_TARGET_MSG.format(target) - if target - else kcl_error.INVALID_DECORATOR_TARGET_MSG.format("") - ) - kcl_error.report_exception( - err_type=kcl_error.ErrType.InvalidDecoratorTarget_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=kwargs.get("filename"), - line_no=kwargs.get("lineno"), - col_no=kwargs.get("columnno"), - ) - ], - arg_msg=msg, - ) - self.filename = kwargs.get("filename") - self.lineno = kwargs.get("lineno") - self.columnno = kwargs.get("columnno") - - @abstractmethod - def run(self, key: str, value, *args, **kwargs): - """ - Decorate on a key-value pair in runtime. - - :param key: Key to Decorated - :param value: Value to Decorated - :param args: Decorator run positional args - :param kwargs: Decorator run keyword args - :return: - """ - pass - - -class DecoratorFactory: - """ - A decorator factory used to get decorator object. - """ - - def __init__(self): - self._decorators: Dict[str, Type[Decorator]] = {} - - def register(self, name: str, decorator: Type[Decorator]): - """ - Register a decorator with a unique name. - - :param name: Name of the decorator - :param decorator: The decorator to be registered - :return: None - """ - self._decorators[name] = decorator - - def get(self, name: str, target: DecoratorTargetType, *args, **kwargs): - """ - Get and return a decorator object. - An UnKnownDecorator will be thrown if no decorator found. - - :param name: Name of the decorator - :param target: Target of the decorator e.g., schema and attribute - :param args: Decorator meta info positional args - :param kwargs: Decorator meta info keyword args - :return: A decorator object - """ - decorator = self._decorators.get(name) - if not decorator: - filename = kwargs.get("filename") - lineno = kwargs.get("lineno") - columnno = kwargs.get("columnno") - kcl_error.report_exception( - err_type=kcl_error.ErrType.UnKnownDecorator_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=filename, line_no=lineno, col_no=columnno - ) - ], - arg_msg=kcl_error.UNKNOWN_DECORATOR_MSG.format(name) - if name - else kcl_error.UNKNOWN_DECORATOR_MSG.format(""), - ) - return decorator(name, target, *args, **kwargs) - - -class Deprecated(Decorator): - """This decorator is used to get the deprecation message according to the wrapped key-value pair. - - Examples - -------- - @deprecated(version="v1.16", reason="The age attribute was deprecated", strict=True) - schema Person: - name: str - age: int - """ - - NAME = "deprecated" - - def __init__(self, name, target, *args, **kwargs): - """ - Construct a deprecated decorator - - :param args: Deprecated decorator build positional args - :param kwargs: Deprecated decorator build keyword args - """ - super().__init__(self.NAME, target, *args, **kwargs) - self.version = kwargs.get("version", "") - self.reason = kwargs.get("reason", "") - self.strict = kwargs.get("strict", True) - - def run(self, key: str, value, *args, **kwargs): - """ - Build and report deprecation message. - - A KCL runtime error will be thrown if self.strict is True, otherwise it just print warning message. - - :param key: Key to Deprecated decorated - :param value: Value to Deprecated decorated - :param args: Deprecated decorator run positional args - :param kwargs: Deprecated decorator run positional args - :return should_change_value: Mark the value of the deprecated schema attribute should be modified - """ - filename = self.filename - lineno = self.lineno - columnno = self.columnno - if not key: - kcl_error.report_exception( - err_type=kcl_error.ErrType.NameError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=filename, line_no=lineno, col_no=columnno - ) - ], - arg_msg=kcl_error.NAME_ERROR_MSG.format(DECORATOR_TARGET_ERR_NAME_MSG), - ) - # Mark the value of the deprecated schema attribute should be modified - should_change_value = False - # Error or warning message - msg = "" - # Append a version info into message - if self.version: - msg += "since version {}".format(self.version) - # Append a reason info into message - if self.reason: - msg += ", " + self.reason - if self.strict: - if self.target == DecoratorTargetType.SCHEMA_TYPE or ( - self.target == DecoratorTargetType.ATTRIBUTE and value - ): - kcl_error.report_exception( - err_type=kcl_error.ErrType.Deprecated_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=filename, line_no=lineno, col_no=columnno - ) - ], - arg_msg=kcl_error.DEPRECATED_WARNING_MSG.format(key, msg), - ) - should_change_value = True - else: - # If it is a modified schema attribute, ignore the assignment without reporting an error. - kcl_error.print_kcl_warning_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.Deprecated_Warning_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=filename, line_no=lineno, col_no=columnno - ) - ], - arg_msg=kcl_error.DEPRECATED_WARNING_MSG.format(key, msg), - ), - file=sys.stderr, - ) - should_change_value = False - return should_change_value - - -class Info(Decorator): - """Info decorator is used to mark some compile-time information for external API queries - - Examples - -------- - @info(message="User message") - schema Person: - name: str - age: int - """ - - NAME = "info" - - def __init__(self, name, target, *args, **kwargs): - """Construct a Info decorator""" - super().__init__(self.NAME, target, *args, **kwargs) - - def run(self, key: str, value, *args, **kwargs): - """Nothing to do on Info decorator""" - pass - - -decorator_factory = DecoratorFactory() -decorator_factory.register(Deprecated.NAME, Deprecated) -decorator_factory.register(Info.NAME, Info) diff --git a/internal/kclvm_py/api/object/internal/option.py b/internal/kclvm_py/api/object/internal/option.py deleted file mode 100644 index 561db4a56..000000000 --- a/internal/kclvm_py/api/object/internal/option.py +++ /dev/null @@ -1,292 +0,0 @@ -# Copyright 2021 The KCL Authors. All rights reserved. - -import typing -import ast -import os - -import kclvm.kcl.error as kcl_error -import kclvm.internal.util as util -import kclvm.config - - -class KclOptionElem: - def __init__(self, name: str): - self.name = name - self.defined = False - self.value_type = "" # bool/int/float/str/list/dict - self.required = False - self.default = None - self.help = "" - self.file = "" - self.line = 0 - - self.inited = False - self.value = None - - def get_help(self, verbose_mode=0) -> str: - name = self.name - default = self.default if self.default else "?" - - type_and_required = "" - if self.value_type != "" and self.required: - type_and_required = f" ({self.value_type},required)" - elif self.value_type != "": - type_and_required = f" ({self.value_type})" - elif self.required: - type_and_required = " (required)" - - if verbose_mode > 1 and self.file and self.line > 0: - filename = os.path.relpath(self.file, os.getcwd()) - return f"{name}={default}{type_and_required} {self.help} ({filename}:{self.line})".strip() - else: - return f"{name}={default}{type_and_required} {self.help}".strip() - - def __str__(self) -> str: - return self.get_help() - - -class _KclOptionDict: - def __init__(self): - self.m: typing.Dict[str, KclOptionElem] = {} # map[name]KclOptionElem - self.reset() - - def reset(self): - self.m = {} # map[name]KclOptionElem - - def len(self) -> int: - return len(self.m) - - def get_dict(self): - return self.m # map[name]KclOptionElem - - def keys(self) -> list: - return list(self.m.keys()) - - def has_key(self, name: str) -> bool: - return name in self.m - - @classmethod - def _check_value_type(cls, value_type: str, value: typing.Any) -> bool: - if not value_type or value is None: - return True - return cls._get_typed_value(value_type, value) is not None - - # noinspection PyBroadException - @classmethod - def _get_typed_value(cls, value_type: str, value) -> typing.Any: - if not value_type: - return value - if value is None: - return None - - if value_type == "bool": - return True if str(value).lower() in ("yes", "true", "1") else bool(value) - if value_type == "int": - try: - return int(value) - except Exception: - return None - if value_type == "float": - try: - return float(value) - except Exception: - return None - if value_type == "str": - return str(value) - if value_type == "list": - if isinstance(value, list): - return value - try: - result = ast.literal_eval(value) - return result if type(result) is list else None - except Exception: - return None - if value_type == "dict": - if isinstance(value, dict): - return value - try: - result = ast.literal_eval(value) - return result if type(result) is dict else None - except Exception: - return None - - # unknown type - kcl_error.report_exception( - err_type=kcl_error.ErrType.EvaluationError_TYPE, - arg_msg=f"unknown type: {value_type}", - ) - - def option( - self, - name: str, - *, - value_type="", - required=False, - default=None, - help="", - file="", - line=0, - ) -> typing.Any: - - if value_type and value_type not in [ - "bool", - "int", - "float", - "str", - "list", - "dict", - ]: - kcl_error.report_exception( - err_type=kcl_error.ErrType.EvaluationError_TYPE, - arg_msg=f"'{value_type}' must one of bool/int/float/str/list/dict or empty string", - ) - - opt = self.get(name) - opt.defined = True - - if value_type: - opt.value_type = value_type - if required: - opt.required = required - if default is not None: - opt.default = default - if help: - opt.help = help - if file: - opt.file = file - if line > 0: - opt.line = line - - if opt.value is None: - opt.value = opt.default - - if value_type and opt.value is not None: - raw_value = opt.value - opt.value = self._get_typed_value(value_type, opt.value) - if opt.value is None: - kcl_error.report_exception( - err_type=kcl_error.ErrType.EvaluationError_TYPE, - arg_msg=f"cannot use '{raw_value}' as type '{value_type}'", - ) - - self.m[name] = opt - kcl_option_exec() # FIXME: filename, lineno, colno info - return opt.value # Do type conversion? - - def init_value(self, *d_list, name: str = "", value=None, **attrs): - def _init_kv(name_: str, value_: str): - opt = self.get(name_) - opt.value = value_ - opt.inited = True - self.m[name_] = opt - - for d in d_list: - kv = d.split("=") - if len(kv) != 2 or not kv[0]: - kcl_error.report_exception( - err_type=kcl_error.ErrType.EvaluationError_TYPE, - arg_msg=f"invalid args: {d}", - ) - _init_kv(kv[0], kv[1]) - - for name, value in attrs.items(): - _init_kv(name, value) - - if name: - _init_kv(name, value) - - def get(self, name: str) -> KclOptionElem: - if name in self.m: - return self.m[name] - else: - return KclOptionElem(name) - - def check(self, *, check_required=True, check_none=False, verbose_mode=0): - for name, v in self.m.items(): - if verbose_mode > 1 and not v.defined: - kcl_error.report_exception( - err_type=kcl_error.ErrType.EvaluationError_TYPE, - file_msgs=[kcl_error.ErrFileMsg(line_no=1)], - arg_msg=f"invalid '-D {name}={v.value}', option('{name}') undefined", - ) - if check_required and v.required and (not v.inited): - kcl_error.report_exception( - err_type=kcl_error.ErrType.EvaluationError_TYPE, - file_msgs=[kcl_error.ErrFileMsg(filename=v.file, line_no=v.line)], - arg_msg=f"option('{name}') must be initialized, try '-D {name}=?' argument", - ) - if check_none and not v.value: - kcl_error.report_exception( - err_type=kcl_error.ErrType.EvaluationError_TYPE, - file_msgs=[kcl_error.ErrFileMsg(filename=v.file, line_no=v.line)], - arg_msg=f"option('{name}') is None", - ) - if not self._check_value_type(v.value_type, v.value): - kcl_error.report_exception( - err_type=kcl_error.ErrType.EvaluationError_TYPE, - file_msgs=[kcl_error.ErrFileMsg(line_no=1)], - arg_msg=f"cannot use '-D {name}={v.value}' as type {v.value_type}", - ) - - return None - - def help(self, *, prefix: str = "", verbose_mode=0) -> str: - if len(self.m) == 0: - return "" - - msg = "option list:\n" - for name in self.keys(): - msg += f"{prefix}{self.get(name).get_help(verbose_mode)}\n" - return msg[:-1] # remove \n - - -_kcl_option_dict = _KclOptionDict() - - -def kcl_option_dict(): - return _kcl_option_dict.get_dict() - - -def kcl_option_help(verbose_mode=0) -> str: - return _kcl_option_dict.help(prefix=" -D ", verbose_mode=verbose_mode) - - -def kcl_option_check(verbose_mode=0): - _kcl_option_dict.check(verbose_mode=verbose_mode) - - -def kcl_option_init(*args, name: str = "", value=None, **attrs): - _kcl_option_dict.init_value(*args, name=name, value=value, **attrs) - - -def kcl_option( - name: str, *, type="", required=False, default=None, help="", file="", line=0 -) -> typing.Any: - return _kcl_option_dict.option( - name, - value_type=type, - required=required, - default=default, - help=help, - file=file, - line=line, - ) - - -def kcl_option_reset(): - _kcl_option_dict.reset() - - -def kcl_option_exec(): - if kclvm.config.list_option_mode > 0: - kclvm.config.options_help_message = kcl_option_help( - verbose_mode=kclvm.config.list_option_mode - ) - else: - kcl_option_check() - - -def kcl_option_init_all(): - if kclvm.config.arguments: - for _k, _v in util.merge_option_same_keys(kclvm.config.arguments).items(): - kcl_option_init(name=_k, value=_v) diff --git a/internal/kclvm_py/api/object/internal/path_selector.py b/internal/kclvm_py/api/object/internal/path_selector.py deleted file mode 100644 index 2defaccbf..000000000 --- a/internal/kclvm_py/api/object/internal/path_selector.py +++ /dev/null @@ -1,164 +0,0 @@ -# Copyright 2021 The KCL Authors. All rights reserved. - -from typing import Union, Tuple, Optional, List - -import kclvm.kcl.error as kcl_error -import kclvm.config -from kclvm.internal.util import dotdict - -from .common import union -from .selector import select - -SELECT_ALL_SYMBOL = "*" -SELECT_INDEX_LEFT_SYMBOL = "[" -SELECT_INDEX_RIGHT_SYMBOL = "]" -SELECT_KEYS_LEFT_SYMBOL = "{" -SELECT_KEYS_RIGHT_SYMBOL = "}" -SELECT_KEYS_SPLIT_SYMBOL = "," - - -def build_selector_index() -> dict: - """Build path selector index map""" - - return _build_selector_index(kclvm.config.path_selector) - - -def _build_selector_index(path_selector: List[List[str]]): - """ - Build selector index with given path selector: [pkg, name.attr1.attr2] - - - single element: name.name1.name2 - - elements: name.{name1,name2}.name, notice that there is no space between name1 and Name2 - - all elements: name.*.name - - list indices: name.[0].name - - :param filename: - :param path_selector: - :return: index with format: {name: {attr1: {attr2: ... attrn: {}}}} - """ - identifiers = list( - map( - lambda select_item: list(map(eval_py_data, select_item[1].split("."))), - path_selector, - ) - ) - select_index = dotdict() - for identifier in identifiers: - index = select_index - for name in identifier: - if not index.get(name): - index[name] = dotdict() - index = index[name] - return select_index - - -def eval_py_data(s): - if isinstance(s, str) and s.isnumeric(): - import ast - - return ast.literal_eval(s) - return s - - -def is_selector_mode() -> bool: - """Mark whether is path selector mode""" - return len(kclvm.config.path_selector) > 0 - - -def parse_selector( - select_value: Union[str, int, float] -) -> Tuple[bool, Optional[int], list]: - """Parse input selector string to selector conditions - - Returns: - is_all: bool - index: Optional[int] - keys: List[str] - """ - # If the selector is numeric, it is a key - if isinstance(select_value, (int, float)): - return False, None, [select_value] - # Case 1: all element selector a.* - is_all = len(select_value) == 1 and select_value[0] == SELECT_ALL_SYMBOL - index = None - keys = [] - # Case 2: index selector a.[0] - is_may_index = ( - len(select_value) > 2 - and select_value[0] == SELECT_INDEX_LEFT_SYMBOL - and select_value[-1] == SELECT_INDEX_RIGHT_SYMBOL - ) - if is_may_index: - try: - index = int(select_value[1:-1]) - except Exception: - kcl_error.report_exception( - err_type=kcl_error.ErrType.CompileError_TYPE, - arg_msg="invalid path selector value {}".format(select_value), - ) - is_may_keys = ( - len(select_value) > 2 - and select_value[0] == SELECT_KEYS_LEFT_SYMBOL - and select_value[-1] == SELECT_KEYS_RIGHT_SYMBOL - ) - # Case 3: keys selector a.{key1, key2} - if is_may_keys: - keys += select_value[1:-1].split(SELECT_KEYS_SPLIT_SYMBOL) - # Case 4: single selector a.b.c - if not is_all and index is None and not keys: - keys.append(select_value) - return is_all, index, keys - - -def select_instance_attributes(instance, attrs): - """ - Select attributes from instance with dot selector, like a.b.c - - - single element: name.name1.name2 - - elements: name.{name1, name2}.name - - all elements: name.*.name - - list indices: name.[0].name - - :param instance: instance to select attributes - :param attrs: attributes used to select, format: {attr1: {attr2: ... attrn: {}}} - :return: - """ - - def select_instance_attribute(instance, attrs): - selected = {} - for attr in attrs: - attr_name = attr - # 1. Parse path selector including [0], *, {key1, key2, ...} and key - is_all, index, keys = parse_selector(attr_name) - # 2. Select value according path selector value - select_result = select(instance, is_all, index, keys) - if not select_result: - return None - select_result = select_result[keys[0]] if len(keys) == 1 else select_result - # 3. Sub select result if more attr to select - sub_select_result = {} - # 4. Get the sub path select result - if attrs.get(attr): - sub_select_result = select_instance_attribute( - select_result, - attrs[attr], - ) - # Dict/Schema selector - final_result = sub_select_result if sub_select_result else select_result - if not isinstance(instance, list): - if len(keys) == 1: - selected[keys[0]] = final_result - else: - selected = union(selected, final_result) - # List selector - else: - selected = final_result - return selected - - # Select self - if not attrs: - return instance - - result = select_instance_attribute(instance, attrs) - # No select result, return None - return result or None diff --git a/internal/kclvm_py/api/object/internal/selector.py b/internal/kclvm_py/api/object/internal/selector.py deleted file mode 100644 index 8c126ba3d..000000000 --- a/internal/kclvm_py/api/object/internal/selector.py +++ /dev/null @@ -1,309 +0,0 @@ -# Copyright 2021 The KCL Authors. All rights reserved. - -from typing import Optional, Union, List, Callable -from abc import ABCMeta, abstractmethod - -import kclvm.kcl.info as kcl_info -import kclvm.kcl.error as kcl_error - -from .common import ( - LIST_TYPE_NAME, - DICT_TYPE_NAME, - SCHEMA_TYPE_NAME, -) - -SCHEMA_SETTINGS_ATTR_NAME = "__settings__" -SELECTOR_ERROR = "SelectorError" -SELECTOR_EMPTY_VAR_ERROR_MSG = "selector expression variable can't be empty" -SELECTOR_INVALID_VAR_TYPE_ERROR_MSG = ( - "invalid selector expression variable type, expected list, dict and Schema" -) -SELECTOR_INVALID_EXPR_ERROR_MSG = "invalid selector expression" -SELECTOR_INVALID_USE_ERROR_MSG = "{} variable can't be used with {} selector expression" -SELECTOR_INVALID_CONDITION_ERROR_MSG = "invalid selector expression lambda condition" - - -SelectorVar = Union[list, dict] - - -class Selector(metaclass=ABCMeta): - """ - Selector expression interface - """ - - def __init__(self, data: SelectorVar) -> None: - self.data: SelectorVar = data - - @abstractmethod - def get_all(self) -> Optional[SelectorVar]: - """ - Get all child items form self.data - """ - pass - - @abstractmethod - def get_by_index(self, index: int) -> Optional[SelectorVar]: - """ - Get all child items by index - """ - pass - - @abstractmethod - def get_by_keys(self, keys: List[str]) -> Optional[SelectorVar]: - """ - Get all child items form self.data when child key is in keys - """ - pass - - @abstractmethod - def get_item_by_condition(self, condition: Callable) -> Optional[SelectorVar]: - """ - Get all child items form self.data when child meets the condition - """ - pass - - def get_var(self) -> SelectorVar: - """ - Get data variable - """ - return self.data - - def select( - self, - is_all: bool = False, - index: Optional[int] = None, - keys: List[str] = None, - condition: Callable = None, - ) -> Optional[SelectorVar]: - if is_all: - return self.get_all() - if index is not None: - return self.get_by_index(index) - if keys: - return self.get_by_keys(keys) - if condition and callable(condition): - return self.get_item_by_condition(condition) - kcl_error.report_exception( - err_type=kcl_error.ErrType.SelectorError_TYPE, - arg_msg=SELECTOR_INVALID_EXPR_ERROR_MSG, - ) - - @staticmethod - def _handle_collection( - result: Optional[Union[list, dict]] - ) -> Optional[Union[list, dict]]: - """ - If the result len is zero, return None, else return itself - """ - return result if result else None - - -class ListSelector(Selector): - """ - List selector expression inherited from Selector - """ - - def __init__(self, data: SelectorVar) -> None: - super().__init__(data) - - def get_all(self) -> SelectorVar: - """ - Get all child items form self.data - """ - return self.get_var() - - def get_by_index(self, index: int) -> Optional[SelectorVar]: - """ - Get all child items by index - """ - var = self.get_var() - return var[index] if -len(var) <= index < len(var) else None - - def get_by_keys(self, keys: List[str]) -> SelectorVar: - """ - Get all child items form self.data when child key is in keys - """ - kcl_error.report_exception( - err_type=kcl_error.ErrType.SelectorError_TYPE, - arg_msg=SELECTOR_INVALID_USE_ERROR_MSG.format( - LIST_TYPE_NAME, DICT_TYPE_NAME - ), - ) - - def get_item_by_condition(self, condition: Callable) -> Optional[SelectorVar]: - """ - Get all child items form self.data when child meets the condition - """ - var = self.get_var() - if condition.__code__.co_argcount == 1: - return self._handle_collection([v for v in var if condition(v)]) - elif condition.__code__.co_argcount == 2: - return self._handle_collection( - [v for i, v in enumerate(var) if condition(i, v)] - ) - kcl_error.report_exception( - err_type=kcl_error.ErrType.SelectorError_TYPE, - arg_msg=SELECTOR_INVALID_CONDITION_ERROR_MSG, - ) - - -class DictSelector(Selector): - """ - List selector expression inherited from Selector - """ - - def __init__(self, data: SelectorVar) -> None: - super().__init__(data) - - def get_all(self) -> SelectorVar: - """ - Get all child items form self.data - """ - return self.get_var() - - def get_by_index(self, index: int) -> SelectorVar: - """ - Get all child items by index - """ - kcl_error.report_exception( - err_type=kcl_error.ErrType.SelectorError_TYPE, - arg_msg=SELECTOR_INVALID_USE_ERROR_MSG.format( - DICT_TYPE_NAME, LIST_TYPE_NAME - ), - ) - - def get_by_keys(self, keys: List[str]) -> Optional[SelectorVar]: - """ - Get all child items form self.data when child key is in keys - """ - var = self.get_var() - return self._handle_collection({k: var[k] for k in var if k in keys}) - - def get_item_by_condition(self, condition: Callable) -> Optional[SelectorVar]: - """ - Get all child items form self.data when child meets the condition - """ - var = self.get_var() - if condition.__code__.co_argcount == 1: - return self._handle_collection({k: var[k] for k in var if condition(k)}) - elif condition.__code__.co_argcount == 2: - return self._handle_collection( - {k: v for k, v in var.items() if condition(k, v)} - ) - kcl_error.report_exception( - err_type=kcl_error.ErrType.SelectorError_TYPE, - arg_msg=SELECTOR_INVALID_CONDITION_ERROR_MSG, - ) - - -class SchemaSelector(Selector): - """ - Schema selector expression inherited from Selector - """ - - def __init__(self, data: SelectorVar) -> None: - super().__init__(data) - - def get_all(self) -> Optional[SelectorVar]: - """ - Get all child items form self.data - """ - var = self.get_var() - return self._handle_collection( - { - kcl_info.demangle(k): var[k] - for k in var - if kcl_info.ismangled(k) and SCHEMA_SETTINGS_ATTR_NAME not in k - } - ) - - def get_by_index(self, index: int) -> SelectorVar: - """ - Get all child items by index - """ - kcl_error.report_exception( - err_type=kcl_error.ErrType.SelectorError_TYPE, - arg_msg=SELECTOR_INVALID_USE_ERROR_MSG.format( - SCHEMA_TYPE_NAME, LIST_TYPE_NAME - ), - ) - - def get_by_keys(self, keys: List[str]) -> Optional[SelectorVar]: - """ - Get all child items form self.data when child key is in keys - """ - data = self.get_all() - return self._handle_collection({k: data[k] for k in data if k in keys}) - - def get_item_by_condition(self, condition: Callable) -> Optional[SelectorVar]: - """ - Get all child items form self.data when child meets the condition - """ - var = self.get_var() - if condition.__code__.co_argcount == 1: - return self._handle_collection( - { - kcl_info.demangle(k): var[k] - for k in var - if kcl_info.ismangled(k) and condition(kcl_info.demangle(k)) - } - ) - elif condition.__code__.co_argcount == 2: - return self._handle_collection( - { - kcl_info.demangle(k): v - for k, v in var.items() - if kcl_info.ismangled(k) and condition(kcl_info.demangle(k), v) - } - ) - kcl_error.report_exception( - err_type=kcl_error.ErrType.SelectorError_TYPE, - arg_msg=SELECTOR_INVALID_CONDITION_ERROR_MSG, - ) - - -class SelectorFactory: - """ - Factory class to build selector - """ - - @staticmethod - def get(var: SelectorVar) -> Selector: - """ - Get selector class using 'var' - """ - - def is_kcl_schema(obj): - from kclvm.api.object import KCLSchemaObject - - return isinstance(obj, KCLSchemaObject) - - if isinstance(var, list): - return ListSelector(var) - if isinstance(var, dict): - return DictSelector(var) - if is_kcl_schema(var): - return SchemaSelector(var) - kcl_error.report_exception( - err_type=kcl_error.ErrType.SelectorError_TYPE, - arg_msg=SELECTOR_INVALID_VAR_TYPE_ERROR_MSG, - ) - - -def select( - var: SelectorVar, - is_all: bool = False, - index: Optional[int] = None, - keys: List[str] = None, - condition: Callable = None, -): - """ - Use the selector expression to filter out the child elements of 'var' - and return their references - """ - if var is None: - kcl_error.report_exception( - err_type=kcl_error.ErrType.SelectorError_TYPE, - arg_msg=SELECTOR_EMPTY_VAR_ERROR_MSG, - ) - return SelectorFactory.get(var).select(is_all, index, keys or [], condition) diff --git a/internal/kclvm_py/api/object/internal/undefined.py b/internal/kclvm_py/api/object/internal/undefined.py deleted file mode 100644 index 496f2fb1c..000000000 --- a/internal/kclvm_py/api/object/internal/undefined.py +++ /dev/null @@ -1,29 +0,0 @@ -# Copyright 2021 The KCL Authors. All rights reserved. - - -class UndefinedType: - def __repr__(self): - return self.__str__() - - def __str__(self): - """Built-in str(Undefined) like str(None)""" - return "Undefined" - - def __bool__(self): - """Built-in bool(Undefined) like bool(None)""" - return False - - @staticmethod - def type_str(): - """Error message show type""" - return "UndefinedType" - - @property - def value(self): - return self._value - - def __init__(self): - self._value = None - - -Undefined = UndefinedType() diff --git a/internal/kclvm_py/api/object/object.py b/internal/kclvm_py/api/object/object.py deleted file mode 100644 index 906b2fab7..000000000 --- a/internal/kclvm_py/api/object/object.py +++ /dev/null @@ -1,1475 +0,0 @@ -# Copyright 2021 The KCL Authors. All rights reserved. - -from typing import Optional, Union, List, Dict, Any, Iterator, cast -from abc import abstractmethod -from copy import deepcopy -from dataclasses import dataclass, field -from enum import Enum, IntEnum - -import kclvm.kcl.error as kcl_error -import kclvm.kcl.info as kcl_info -import kclvm.kcl.ast as ast - -from kclvm.api.object.internal import Deprecated, Undefined, UndefinedType - -# -------------------------------- -# KCL Object definitions -# -------------------------------- - -AttrType = str - - -class KCLObjectType(Enum): - LITERAL = "LITERAL" - INTEGER = "INTEGER" - FLOAT = "FLOAT" - BOOLEAN = "BOOLEAN" - NONE = "NONE" - UNDEFINED = "UNDEFINED" - RETURN_VALUE = "RETURN_VALUE" - ERROR = "ERROR" - FUNCTION = "FUNCTION" - STRING = "STRING" - BUILTIN = "BUILTIN" - LIST = "LIST" - DICT = "DICT" - NUMBER_MULTIPLIER = "NUMBER_MULTIPLIER" - TUPLE = "TUPLE" - ITER = "ITER" - COMPILED_FUNCTION = "COMPILED_FUNCTION" - CLOSURE = "CLOSURE" - DECORATOR = "DECORATOR" - SLICE = "SLICE" - TYPE = "TYPE" - SCHEMA_TYPE = "SCHEMA_TYPE" - SCHEMA = "SCHEMA" - SCHEMA_INDEX_SIGNATURE = "SCHEMA_INDEX_SIGNATURE" - NAME_CONSTANT = "NAME_CONSTANT" - MODULE = "MODULE" - PACKAGE = "PACKAGE" - UNPACK = "UNPACK" - SCHEMA_CONFIG = "SCHEMA_CONFIG" - RUNTIME_CODE = "RUNTIME_CODE" - - -class KCLSchemaReverseFields: - SETTINGS = "__settings__" - NAME = "__schema_name__" - TYPE = "__schema_type__" - PKG_PATH = "__pkg_path__" - - -NUMBER_MULTIPLIER_TYPE_STR = "number_multiplier" -ANT_TYPE_STR = "any" - - -@dataclass -class KCLObject: - @abstractmethod - def type(self) -> KCLObjectType: - """ - Get the object type - """ - pass - - @abstractmethod - def type_str(self) -> str: - """ - Get the object type - """ - pass - - def is_truthy(self) -> bool: - tpe = self.type() - if tpe in [KCLObjectType.BOOLEAN, KCLObjectType.NONE]: - return self.value - elif tpe == KCLObjectType.UNDEFINED: - return False - elif tpe in [ - KCLObjectType.LIST, - KCLObjectType.DICT, - KCLObjectType.SCHEMA_TYPE, - KCLObjectType.STRING, - ]: - return bool(self.value) - elif tpe == KCLObjectType.INTEGER: - return self.value != 0 - elif tpe == KCLObjectType.FLOAT: - return self.value != 0.0 - return True - - -@dataclass -class KCLLiteralObject(KCLObject): - value: Any - - def type(self) -> KCLObjectType: - """ - Get the object type - """ - return KCLObjectType.LITERAL - - def type_str(self) -> str: - """ - Get the object type - """ - return "literal" - - -@dataclass -class KCLIntObject(KCLLiteralObject): - def type(self) -> KCLObjectType: - """ - Get the object type - """ - return KCLObjectType.INTEGER - - def type_str(self) -> str: - """ - Get the object type - """ - return "int" - - -@dataclass -class KCLFloatObject(KCLLiteralObject): - def type(self) -> KCLObjectType: - """ - Get the object type - """ - return KCLObjectType.FLOAT - - def type_str(self) -> str: - """ - Get the object type - """ - return "float" - - -@dataclass -class KCLNumberMultiplierObject(KCLFloatObject): - raw_value: int - binary_suffix: str - - def type(self) -> KCLObjectType: - """ - Get the object type - """ - return KCLObjectType.NUMBER_MULTIPLIER - - def type_str(self) -> str: - """ - Get the object type - """ - return ( - f"{NUMBER_MULTIPLIER_TYPE_STR}({self.raw_value}{self.binary_suffix})" - if self.raw_value and self.binary_suffix - else NUMBER_MULTIPLIER_TYPE_STR - ) - - def __str__(self) -> str: - return f"{self.raw_value}{self.binary_suffix}" - - def __repr__(self) -> str: - return self.__str__() - - def __int__(self) -> int: - return int(self.value) - - def __float__(self) -> float: - return float(self.value) - - def __bool__(self) -> bool: - return bool(self.value) - - -@dataclass -class KCLStringObject(KCLLiteralObject): - - MEMBER_FUNCTIONS = [ - "capitalize", - "count", - "endswith", - "find", - "format", - "index", - "isalnum", - "isalpha", - "isdigit", - "islower", - "isspace", - "istitle", - "isupper", - "join", - "lower", - "upper", - "lstrip", - "rstrip", - "replace", - "rfind", - "rindex", - "rsplit", - "split", - "splitlines", - "startswith", - "strip", - "title", - ] - - def type(self) -> KCLObjectType: - """ - Get the object type - """ - return KCLObjectType.STRING - - def type_str(self) -> str: - """ - Get the object type - """ - return "str" - - def check_attr(self, name: str): - if not name: - kcl_error.report_exception( - err_type=kcl_error.ErrType.EvaluationError_TYPE, - arg_msg="kcl string object member name can't be empty or None", - ) - if not hasattr(self.value, name) and name not in self.MEMBER_FUNCTIONS: - kcl_error.report_exception( - err_type=kcl_error.ErrType.EvaluationError_TYPE, - arg_msg=f"attribute {name} not found", - ) - - def get_member_method(self, name: str): - from .function import KCLMemberFunctionObject - - self.check_attr(name) - return KCLMemberFunctionObject(obj=self, name=name) - - def call_member_method(self, name: str, *args, **kwargs): - - return getattr(self.value, name).__call__(*args, **kwargs) - - -@dataclass -class KCLNameConstantObject(KCLObject): - value: Any - - def type(self) -> KCLObjectType: - """ - Get the object type - """ - return KCLObjectType.NAME_CONSTANT - - def type_str(self) -> str: - """ - Get the object type - """ - return "name_constant" - - -@dataclass -class KCLTrueObject(KCLNameConstantObject): - def type(self) -> KCLObjectType: - """ - Get the object type - """ - return KCLObjectType.BOOLEAN - - def type_str(self) -> str: - """ - Get the object type - """ - return "bool" - - @staticmethod - def instance() -> KCLNameConstantObject: - return TRUE_INSTANCE - - -@dataclass -class KCLFalseObject(KCLNameConstantObject): - def type(self) -> KCLObjectType: - """ - Get the object type - """ - return KCLObjectType.BOOLEAN - - def type_str(self) -> str: - """ - Get the object type - """ - return "bool" - - @staticmethod - def instance() -> KCLNameConstantObject: - return FALSE_INSTANCE - - -@dataclass -class KCLNoneObject(KCLNameConstantObject): - def type(self) -> KCLObjectType: - """ - Get the object type - """ - return KCLObjectType.NONE - - def type_str(self) -> str: - """ - Get the object type - """ - return "NoneType" - - @staticmethod - def instance() -> "KCLNoneObject": - return NONE_INSTANCE - - -@dataclass -class KCLUndefinedObject(KCLNameConstantObject): - def type(self) -> KCLObjectType: - """ - Get the object type - """ - return KCLObjectType.UNDEFINED - - def type_str(self) -> str: - """ - Get the object type - """ - return Undefined.type_str() - - @staticmethod - def instance() -> "KCLUndefinedObject": - return UNDEFINED_INSTANCE - - -@dataclass -class KCLListObject(KCLObject): - items: List[KCLObject] = field(default_factory=list) - - def type(self) -> KCLObjectType: - """ - Get the object type - """ - return KCLObjectType.LIST - - def type_str(self) -> str: - """ - Get the object type - """ - return "list" - - def append(self, item: KCLObject): - self.items.append(item) - - def append_unpack(self, items: KCLObject): - if not isinstance( - items, - ( - KCLListObject, - KCLSchemaObject, - KCLDictObject, - KCLNoneObject, - KCLUndefinedObject, - ), - ): - kcl_error.report_exception( - err_type=kcl_error.ErrType.EvaluationError_TYPE, - arg_msg=f"'{items.type_str()}' object is not iterable", - ) - if not isinstance(items, (KCLNoneObject, KCLUndefinedObject)): - self.items = [*self.items, *items.value] - - @property - def value(self): - return self.items - - def remove_at(self, index: KCLIntObject): - del self.items[to_python_obj(index)] - - def remove(self, val: KCLObject): - self.items.remove(val) - - -@dataclass -class KCLDictObject(KCLObject): - value: dict = field(default_factory=dict) - - def type(self) -> KCLObjectType: - """ - Get the object type - """ - return KCLObjectType.DICT - - def type_str(self) -> str: - """ - Get the object type - """ - return "dict" - - @property - def config_keys(self) -> set: - return set(self.value.keys()) - - def update_key_value(self, k: AttrType, v: KCLObject): - assert k is not None - self.value[to_python_obj(k)] = to_kcl_obj(v) - - def has_key(self, k: AttrType): - return to_python_obj(k) in self.value - - def __contains__(self, k: AttrType): - return to_python_obj(k) in self.value - - def get(self, k: AttrType) -> KCLObject: - if k is None or isinstance(k, UndefinedType): - return KCLUndefinedObject.instance() - if isinstance(k, (KCLNoneObject, KCLUndefinedObject)): - return KCLUndefinedObject.instance() - return self.value.get(to_python_obj(k), KCLUndefinedObject.instance()) - - def get_keys(self) -> KCLListObject: - return KCLListObject([to_kcl_obj(v) for v in self.value.keys()]) - - def get_values(self) -> KCLListObject: - return KCLListObject([to_kcl_obj(v) for v in self.value.values()]) - - def append_unpack(self, items: KCLObject): - if not isinstance( - items, - ( - KCLListObject, - KCLSchemaObject, - KCLDictObject, - KCLNoneObject, - KCLUndefinedObject, - ), - ): - kcl_error.report_exception( - err_type=kcl_error.ErrType.EvaluationError_TYPE, - arg_msg=f"'{items.type_str()}' object is not iterable", - ) - value = ( - KCLDictObject(value={}) - if isinstance(items, (KCLNoneObject, KCLUndefinedObject)) - else items - ) - if isinstance(value, KCLSchemaObject): - config = KCLSchemaConfigObject(value=value.value) - config.update_attr_op_using_obj(value) - self.union_with(deepcopy(config)) - else: - self.union_with(deepcopy(value)) - - def update(self, data: Union[dict, "KCLDictObject"]): - if isinstance(data, KCLDictObject): - for k, v in data.value.items(): - self.value[k] = to_kcl_obj(v) - if isinstance(data, dict): - for k, v in data.items(): - self.value[k] = to_kcl_obj(v) - - def union_with(self, obj: KCLObject, should_idempotent_check: bool = True): - from kclvm.vm.runtime.evaluator import union - - union(self, to_kcl_obj(obj), should_idempotent_check=should_idempotent_check) - if isinstance(self, KCLConfigObjectMixin): - self.update_attr_op_using_obj(obj) - - def merge_with(self, obj: KCLObject): - from kclvm.vm.runtime.evaluator import merge - - union_obj = cast( - KCLDictObject, - merge([self, obj]), - ) - self.update(union_obj) - - def insert_with_key( - self, attr: Union[str, KCLStringObject], obj: KCLObject, index=-1 - ): - value = self.get(attr) - if ( - value is None - or value is Undefined - or isinstance(value, UndefinedType) - or isinstance(value, (KCLNoneObject, KCLUndefinedObject)) - ): - value = KCLListObject() - self.value[attr] = value - if not isinstance(value, KCLListObject) or not isinstance(obj, KCLListObject): - kcl_error.report_exception( - err_type=kcl_error.ErrType.EvaluationError_TYPE, - arg_msg="only list attribute can be inserted value", - ) - if index is None or index == -1: - value = self.value[attr].value + obj.value - self.update({attr: value}) - elif index >= 0: - value = ( - self.value[attr].value[:index] - + obj.value - + self.value[attr].value[index:] - ) - self.update({attr: value}) - - def insert_with( - self, data: Union[dict, "KCLDictObject"], index: Optional[int] = None - ): - obj = data.value if isinstance(data, KCLDictObject) else data - if not isinstance(obj, dict): - return - for k, v in obj.items(): - self.insert_with_key(k, v, index) - - def list_key_override(self, attr: str, v: KCLObject, index: int): - value = self.get(attr) - if not isinstance(value, KCLListObject): - kcl_error.report_exception( - err_type=kcl_error.ErrType.EvaluationError_TYPE, - arg_msg="only list attribute can be inserted value", - ) - if v is None or isinstance(v, (KCLNoneObject, KCLUndefinedObject)): - self.value[attr].value.pop(index) - else: - self.value[attr].value[index] = v - - def unique_merge_with(self, obj: KCLObject): - from kclvm.vm.runtime.evaluator import union - - union(self, to_kcl_obj(obj), should_idempotent_check=True) - - def delete(self, key: Union[str, KCLStringObject]): - del self.value[to_python_obj(key)] - - -@dataclass -class KCLConfigObjectMixin: - operation_map: Dict[str, int] = field(default_factory=dict) - insert_index_map: Dict[str, Union[str, int]] = field(default_factory=dict) - - def add_operation(self, key: str, operation: int, insert_index=-1): - if not self.operation_map: - self.operation_map = {} - if not self.insert_index_map: - self.insert_index_map = {} - if not key: - return - self.operation_map[key] = operation - self.insert_index_map[key] = insert_index - - def get_operation(self, key: str) -> int: - if not self.operation_map: - self.operation_map = {} - return self.operation_map.get(key, ast.ConfigEntryOperation.UNION) - - def get_insert_index(self, key: str) -> Optional[Union[str, int]]: - if not self.insert_index_map: - return None - return self.insert_index_map.get(key) - - def update_attr_op_using_obj(self, obj: KCLObject): - if isinstance(obj, (KCLSchemaConfigObject, KCLSchemaObject)): - self.operation_map = {**self.operation_map, **obj.operation_map} - self.insert_index_map = {**self.insert_index_map, **obj.insert_index_map} - - -@dataclass -class KCLSchemaConfigObject(KCLDictObject, KCLConfigObjectMixin): - def type(self) -> KCLObjectType: - """ - Get the object type - """ - return KCLObjectType.DICT - - def type_str(self) -> str: - return "dict" # Please note it is actually a dict - - -@dataclass -class KCLSchemaObject(KCLObject, KCLConfigObjectMixin): - name: str = None - pkgpath: str = None - instance_pkgpath: str = None - attrs: dict = None - runtime_type: str = None - is_relaxed: bool = False - config_keys: set = field(default_factory=set) - __tags__: dict = field(default_factory=dict) - __decorators__: dict = field(default_factory=dict) - __stmt_buffer__: list = field(default_factory=dict) - - def type(self) -> KCLObjectType: - """ - Get the object type - """ - return KCLObjectType.SCHEMA - - def type_str(self) -> str: - """ - Get the object type - """ - return self.name - - def full_type_str(self) -> str: - """ - Get the object type - """ - return ( - f"{self.pkgpath}.{self.name}" - if self.pkgpath and self.pkgpath != ast.Program.MAIN_PKGPATH - else self.name - ) - - @property - def value(self): - return self.attrs - - def update_info(self, name: str, runtime_type: str, is_relaxed: bool): - self.name = name - self.runtime_type = runtime_type - self.is_relaxed = is_relaxed - - def construct( - self, config: Optional[KCLDictObject] = None, _args=None, _builder=None - ): - if config and isinstance(config, KCLDictObject): - self.attrs = config.value - return self - - def update(self, data: Union[dict, KCLObject]): - if isinstance(data, KCLDictObject): - for k, v in data.value.items(): - self.attrs[to_python_obj(k)] = to_kcl_obj(v) - if isinstance(data, dict): - for k, v in data.items(): - self.attrs[to_python_obj(k)] = to_kcl_obj(v) - - def get(self, k: Union[str, KCLStringObject], do_check: bool = True): - if not self.attrs or k not in self.attrs and do_check: - kcl_error.report_exception( - err_type=kcl_error.ErrType.AttributeError_TYPE, - arg_msg=f"schema '{self.full_type_str()}' attribute '{k}' not found", - ) - return self.attrs.get(to_python_obj(k)) - - def update_key_value(self, k: str, v: KCLObject): - assert k is not None - self.attrs[to_python_obj(k)] = to_kcl_obj(v) - - def append_unpack(self, items: KCLObject): - if not isinstance( - items, - ( - KCLListObject, - KCLSchemaObject, - KCLDictObject, - KCLNoneObject, - KCLUndefinedObject, - ), - ): - kcl_error.report_exception( - err_type=kcl_error.ErrType.EvaluationError_TYPE, - arg_msg=f"'{items.type_str()}' object is not iterable", - ) - value = ( - KCLDictObject(value={}) - if isinstance(items, (KCLNoneObject, KCLUndefinedObject)) - else items - ) - if isinstance(value, KCLSchemaObject): - config = KCLSchemaConfigObject(value=value.value) - config.update_attr_op_using_obj(value) - self.union_with(config) - else: - self.union_with(value) - - def insert_with_key( - self, attr: Union[str, KCLStringObject], obj: KCLObject, index=-1 - ): - self.insert_with(attr, obj, index) - - def insert_with(self, attr: Union[str, KCLStringObject], obj: KCLObject, index=-1): - value = self.get(attr, do_check=False) - if ( - value is None - or value is Undefined - or isinstance(value, UndefinedType) - or isinstance(value, (KCLNoneObject, KCLUndefinedObject)) - ): - value = KCLListObject() - self.attrs[attr] = value - if not isinstance(value, KCLListObject) or not isinstance(obj, KCLListObject): - kcl_error.report_exception( - err_type=kcl_error.ErrType.EvaluationError_TYPE, - arg_msg="only list attribute can be inserted value", - ) - if index is None or index == -1: - value = self.attrs[attr].value + obj.value - self.update({attr: value}) - elif index >= 0: - value = ( - self.attrs[attr].value[:index] - + obj.value - + self.attrs[attr].value[index:] - ) - self.update({attr: value}) - - def list_key_override(self, attr: str, v: KCLObject, index: int): - value = self.get(attr) - if not isinstance(value, KCLListObject): - kcl_error.report_exception( - err_type=kcl_error.ErrType.EvaluationError_TYPE, - arg_msg="only list attribute can be inserted value", - ) - if v is None or isinstance(v, (KCLNoneObject, KCLUndefinedObject)): - self.attrs[attr].value.pop(index) - else: - self.attrs[attr].value[index] = v - - def union_with( - self, obj: Union[KCLObject, dict], should_idempotent_check: bool = True - ): - from kclvm.vm.runtime.evaluator import union - - union(self, to_kcl_obj(obj), should_idempotent_check=should_idempotent_check) - if isinstance(self, KCLConfigObjectMixin): - self.update_attr_op_using_obj(obj) - - def delete(self, key: Union[str, KCLStringObject]): - del self.value[to_python_obj(key)] - - def has_key(self, attr: Union[str, KCLStringObject]): - return to_python_obj(attr) in self.attrs - - def __contains__(self, attr: Union[str, KCLStringObject]): - return to_python_obj(attr) in self.attrs - - def should_add_attr(self, name: str) -> bool: - """Determine whether an attribute can be added to schema attributes, - such as non-exported variables that start with `_` or relaxed attributes. - - Three situations that should be added: - 1. The attribute was originally an attribute of this schema - 2. Variables starting with an underscore `_` - 3. The schema is relaxed - """ - return ( - name in self - and self.get_attr_type(name) - or (isinstance(name, str) and name.startswith("_")) - or self.is_relaxed - ) - - # Attribute type - - def set_attr_type(self, attr: str, types: List[str]): - if not attr: - return - tagged = kcl_info.tagging("attr_type", attr) - if not self.__tags__: - self.__tags__ = {} - self.__tags__[tagged] = types - - def get_attr_type(self, attr: str) -> List[str]: - - if not attr or not self.__tags__: - return [] - tagged = kcl_info.tagging("attr_type", attr) - if tagged in self.__tags__: - return self.__tags__[tagged] - else: - return [] - - def set_attr_runtime_type(self, attr: str, types: List[str]): - if not attr: - return - tagged = kcl_info.tagging("runtime_attr_type", attr) - if not self.__tags__: - self.__tags__ = {} - if tagged in self.__tags__ and self.__tags__[tagged] != types: - kcl_error.report_exception( - err_type=kcl_error.ErrType.TypeError_Runtime_TYPE, - arg_msg=f"can't change schema field type of '{attr}'", - ) - self.__tags__[tagged] = types - - # Optional - - def set_attr_optional(self, attr: str, is_optional: bool): - if not attr: - return - tagged = kcl_info.tagging("is_optional", attr) - if not self.__tags__: - self.__tags__ = {} - if tagged in self.__tags__: - if self.__tags__[tagged] is False and is_optional is True: - kcl_error.report_exception( - err_type=kcl_error.ErrType.EvaluationError_TYPE, - arg_msg=f"can't change the required schema attribute of '{attr}' to optional", - ) - self.__tags__[tagged] = is_optional - - def get_attr_optional(self, attr: str) -> bool: - if not attr: - return False - tagged = kcl_info.tagging("is_optional", attr) - if not self.__tags__: - self.__tags__ = {} - return self.__tags__.get(tagged, False) - - def check_optional_attrs(self): - """Check all schema attributes are optional. - If the schema attribute is not optional and its value is None, an error is reported - """ - if not self.__tags__: - return - for k, v in self.attrs.items(): - # Note k is a string, v is a KCLObject - is_optional = self.get_attr_optional(str(k)) - # Relaxed schema attribute has no types and do not check the None value - types = self.get_attr_type(k) - # Whether v is not a optional attribute - if ( - types - and not is_optional - and (v is None or isinstance(v, (KCLNoneObject, KCLUndefinedObject))) - ): - kcl_error.report_exception( - err_type=kcl_error.ErrType.EvaluationError_TYPE, - arg_msg=f"attribute '{k}' of {self.name} is required and can't be None or Undefined", - ) - - # Attribute mutable - - def set_immutable_flag(self, attr: str, is_final: bool): - if not attr: - return - tagged = kcl_info.tagging("immutable", attr) - if not self.__tags__: - self.__tags__ = {} - self.__tags__[tagged] = is_final - - def get_immutable_flag(self, attr: str) -> bool: - if not attr: - return False - tagged = kcl_info.tagging("immutable", attr) - if not self.__tags__: - self.__tags__ = {} - return self.__tags__.get(tagged, False) - - # Decorators - - def add_decorator(self, field: str, decorator) -> None: - """ - Add a decorator to the schema - - Parameters - ---------- - - field: The schema attribute name or schema name - - decorator: A decorator class - - Return - ------ - None - """ - if not field: - return - if not self.__decorators__: - self.__decorators__ = {} - tagged = kcl_info.tagging("decorator", field) - if tagged not in self.__decorators__: - self.__decorators__[tagged] = [] - self.__decorators__[tagged].append(decorator) - - def run_all_decorators(self) -> None: - """ - Run schema all decorators and - parameters of per decorator is its key and value. - """ - if not self.__decorators__: - return - for k in self.__decorators__: - for decorator in self.__decorators__[k]: - name_member = kcl_info.detagging("decorator", k) - value = decorator.call( - None, - None, - key=name_member, - value=self.attrs.get(name_member), - ) - # If a schema attribute is deprecated, RESET it to be None - if ( - not value - or isinstance(value, (KCLNoneObject, KCLUndefinedObject)) - and decorator.name == Deprecated.NAME - ): - self.attrs[name_member] = None - - # Statement buffer - - def stmt_buffer_enqueue(self, content): - if not self.__stmt_buffer__: - self.__stmt_buffer__ = [] - if content and hasattr(self, "__stmt_buffer__"): - self.__stmt_buffer__.append(content) - - def stmt_buffer(self): - if hasattr(self, "__stmt_buffer__"): - return self.__stmt_buffer__ - return None - - -@dataclass -class KCLUnpackObject(KCLObject): - value: Union[ - KCLListObject, KCLDictObject, KCLSchemaObject, KCLNoneObject, KCLUndefinedObject - ] = None - is_double_star: bool = False - - def type(self) -> KCLObjectType: - """ - Get the object type - """ - return KCLObjectType.UNPACK - - def type_str(self) -> str: - """ - Get the object type - """ - return "unpack" - - def unpack(self): - if not isinstance( - self.value, - ( - KCLListObject, - KCLDictObject, - KCLSchemaObject, - KCLNoneObject, - KCLUndefinedObject, - ), - ): - kcl_error.report_exception( - err_type=kcl_error.ErrType.EvaluationError_TYPE, - arg_msg=f"only list, dict and schema object can be used with unpack operators * and **, got {self.value}", - ) - return self.value - - -@dataclass -class KCLSliceObject(KCLObject): - start: KCLObject = None - stop: KCLObject = None - step: KCLObject = None - - def type(self) -> KCLObjectType: - """ - Get the object type - """ - return KCLObjectType.SLICE - - def type_str(self) -> str: - """ - Get the object type - """ - return "slice" - - @property - def value(self): - return slice(self.start.value, self.stop.value, self.step.value) - - -@dataclass -class KCLModuleObject(KCLObject): - name: str - asname: str = None - value: Dict[str, KCLObject] = None - - def type(self) -> KCLObjectType: - """ - Get the object type - """ - return KCLObjectType.MODULE - - def type_str(self) -> str: - """ - Get the object type - """ - return "module" - - def get(self, name: str): - name = to_python_obj(name) - if self.value and name and name in self.value: - return self.value[name] - kcl_error.report_exception( - err_type=kcl_error.ErrType.AttributeError_Runtime_TYPE, - arg_msg=f"module '{self.name}' has no attribute '{name}'", - ) - - -@dataclass -class KCLIterObject(KCLObject): - iter: Iterator - - def type(self) -> KCLObjectType: - """ - Get the object type - """ - return KCLObjectType.ITER - - def type_str(self) -> str: - """ - Get the object type - """ - return "iter" - - def next(self) -> KCLObject: - next_obj = next(self.iter) - return to_kcl_obj(next_obj if isinstance(next_obj, tuple) else (next_obj,)) - - @staticmethod - def build_iter(obj: KCLObject, iter_variable_count: int = 1): - if obj.type() not in [ - KCLObjectType.DICT, - KCLObjectType.LIST, - KCLObjectType.STRING, - KCLObjectType.SCHEMA, - ]: - kcl_error.report_exception( - err_type=kcl_error.ErrType.EvaluationError_TYPE, - arg_msg=f"{obj.type_str()} object is not iterable", - ) - assert 0 < iter_variable_count <= 2 - if iter_variable_count == 1: - return KCLIterObject(iter=iter(obj.value)) - if obj.type() in [KCLObjectType.LIST, KCLObjectType.STRING]: - return KCLIterObject(iter=iter(enumerate(obj.value))) - if obj.type() in [KCLObjectType.DICT, KCLObjectType.SCHEMA]: - return KCLIterObject(iter=iter(obj.value.items())) - raise Exception(f"invalid iter object type {type(obj)}") - - @property - def value(self): - return self.iter - - -@dataclass -class KCLTupleObject(KCLObject): - value: List[KCLObject] - - def type(self) -> KCLObjectType: - """ - Get the object type - """ - return KCLObjectType.TUPLE - - def type_str(self) -> str: - """ - Get the object type - """ - return "tuple" - - -@dataclass -class KCLErrorObject(KCLObject, Exception): - file: Optional[str] = None - lineno: Optional[int] = None - colno: Optional[int] = None - msg: str = None - - def type(self) -> KCLObjectType: - """ - Get the object type - """ - return KCLObjectType.ERROR - - def type_str(self) -> str: - """ - Get the object type - """ - return "error" - - @property - def value(self): - return self.msg - - -# ---------------------- -# KCL type objects -# ---------------------- - - -class KCLTypeKind(IntEnum): - NoneKind = 0 - AnyKind = 1 - UnionKind = 2 - BoolKind = 3 - BoolLitKind = 4 - IntKind = 5 - IntLitKind = 6 - FloatKind = 7 - FloatLitKind = 8 - StrKind = 9 - StrLitKind = 10 - ListKind = 11 - DictKind = 12 - SchemaKind = 13 - SchemaDefKind = 14 - NumberMultiplierKind = 15 - FuncKind = 16 - VoidKind = 17 - ModuleKind = 18 - NamedKind = 19 - - -class TypeAliasMixin: - # Mark the type is a value or a type alias - is_type_alias: bool = False - - -@dataclass -class KCLBaseTypeObject(KCLObject, TypeAliasMixin): - def type(self) -> KCLObjectType: - """ - Get the object type - """ - return KCLObjectType.TYPE - - def type_str(self) -> str: - """ - Get the object type - """ - return "base_type" - - def type_kind(self) -> int: - return -1 - - -@dataclass -class KCLAnyTypeObject(KCLBaseTypeObject): - value: str = None # Can only be any - - def type_str(self) -> str: - """ - Get the object type - """ - return "any" - - def type_kind(self) -> int: - return KCLTypeKind.AnyKind - - -@dataclass -class KCLBuiltinTypeObject(KCLBaseTypeObject): - def type_str(self) -> str: - """ - Get the object type - """ - return "builtin" - - -@dataclass -class KCLIntTypeObject(KCLBuiltinTypeObject): - def type_str(self): - return "int" - - def type_kind(self) -> int: - return KCLTypeKind.IntKind - - -@dataclass -class KCLFloatTypeObject(KCLBuiltinTypeObject): - def type_str(self): - return "float" - - def type_kind(self) -> int: - return KCLTypeKind.FloatKind - - -@dataclass -class KCLStringTypeObject(KCLBuiltinTypeObject): - def type_str(self): - return "str" - - def type_kind(self) -> int: - return KCLTypeKind.StrKind - - -@dataclass -class KCLBoolTypeObject(KCLBuiltinTypeObject): - def type_str(self) -> str: - """ - Get the object type - """ - return "bool" - - def type_kind(self) -> int: - return KCLTypeKind.BoolKind - - -@dataclass -class KCLNameConstantTypeObject(KCLBaseTypeObject): - value: Optional[bool] = None - - def type_str(self) -> str: - """ - Get the object type - """ - return "NoneType" if self.value is None else "bool" - - -@dataclass -class KCLStringLitTypeObject(KCLBaseTypeObject): - value: str = None - - def type_str(self) -> str: - """ - Get the object type - """ - return f"str({self.value})" - - def type_kind(self) -> int: - return KCLTypeKind.StrLitKind - - -@dataclass -class KCLNumberLitTypeObject(KCLBaseTypeObject): - value: Union[int, float] = None - - def type_str(self) -> str: - """ - Get the object type - """ - return ( - f"int({self.value})" - if isinstance(self.value, int) - else f"float({self.value})" - ) - - def type_kind(self) -> int: - return ( - KCLTypeKind.IntLitKind - if self.is_int_lit_type() - else KCLTypeKind.FloatLitKind - ) - - def is_int_lit_type(self) -> bool: - return isinstance(self.value, int) - - def is_float_lit_type(self) -> bool: - return isinstance(self.value, float) - - -@dataclass -class KCLIntLitTypeObject(KCLNumberLitTypeObject): - def type_kind(self) -> int: - return KCLTypeKind.IntLitKind - - -@dataclass -class KCLFloatLitTypeObject(KCLNumberLitTypeObject): - def type_kind(self) -> int: - return KCLTypeKind.FloatLitKind - - -@dataclass -class KCLBoolLitTypeObject(KCLBaseTypeObject): - value: bool = None - - def type_str(self) -> str: - return f"bool({self.value})" - - def type_kind(self) -> int: - return KCLTypeKind.BoolLitKind - - -@dataclass -class KCLListTypeObject(KCLBaseTypeObject): - item_type: KCLBaseTypeObject = None - - def type_str(self) -> str: - """ - Get the object type - """ - return "[{}]".format(self.item_type.type_str()) - - def type_kind(self) -> int: - return KCLTypeKind.ListKind - - -@dataclass -class KCLDictTypeObject(KCLBaseTypeObject): - key_type: KCLBaseTypeObject = None - value_type: KCLBaseTypeObject = None - - def type_str(self) -> str: - """ - Get the object type - """ - return "{{{}:{}}}".format(self.key_type.type_str(), self.value_type.type_str()) - - def type_kind(self) -> int: - return KCLTypeKind.DictKind - - -@dataclass -class KCLUnionTypeObject(KCLBaseTypeObject): - types: List[KCLBaseTypeObject] = None - - def type_str(self) -> str: - """ - Get the object type - """ - return "{}".format("|".join([t.type_str() for t in self.types])) - - def type_kind(self) -> int: - return KCLTypeKind.UnionKind - - -@dataclass -class KCLModuleTypeObject(KCLBaseTypeObject): - pkgpath: str = "" - imported_filenames: List[str] = field(default_factory=list) - is_user_module: bool = False - is_system_module: bool = False - is_plugin_module: bool = False - - def type_str(self) -> str: - return "module" - - def type_kind(self) -> int: - return KCLTypeKind.ModuleKind - - -@dataclass -class KCLNumberMultiplierTypeObject(KCLBaseTypeObject): - value: int = None - raw_value: int = None - binary_suffix: str = None - - def type_str(self) -> str: - return ( - f"{NUMBER_MULTIPLIER_TYPE_STR}({self.raw_value}{self.binary_suffix})" - if self.raw_value and self.binary_suffix - else NUMBER_MULTIPLIER_TYPE_STR - ) - - def type_kind(self) -> int: - return KCLTypeKind.NumberMultiplierKind - - def is_literal(self) -> bool: - return bool(self.binary_suffix) - - -@dataclass -class KCLNamedTypeObject(KCLBaseTypeObject): - name: str - - def type_str(self) -> str: - return "named" - - def type_kind(self) -> int: - return KCLTypeKind.NamedKind - - -@dataclass -class KCLNoneTypeObject(KCLNameConstantTypeObject): - def type_str(self) -> str: - """ - Get the object type - """ - return "NoneType" - - def type_kind(self) -> int: - return KCLTypeKind.NoneKind - - -@dataclass -class KCLVoidTypeObject(KCLBaseTypeObject): - def type_str(self) -> str: - """ - Get the object type - """ - return "void" - - def type_kind(self) -> int: - return KCLTypeKind.VoidKind - - -# -------------------- -# KCL Object instances -# -------------------- - - -TRUE_INSTANCE = KCLTrueObject(value=True) -FALSE_INSTANCE = KCLFalseObject(value=False) -NONE_INSTANCE = KCLNoneObject(value=None) -UNDEFINED_INSTANCE = KCLUndefinedObject(value=Undefined.value) - - -def to_python_obj(v: Union[KCLObject, int, float, str, bool, list, dict]) -> Any: - if isinstance(v, KCLObject): - if isinstance(v, KCLUndefinedObject): - return Undefined - elif isinstance(v, KCLNumberMultiplierObject): - return v - elif isinstance(v, (KCLLiteralObject, KCLNameConstantObject, KCLSliceObject)): - return v.value - elif isinstance(v, (KCLDictObject, KCLSchemaObject)): - return {_k: to_python_obj(_v) for _k, _v in v.value.items()} - elif isinstance(v, (KCLListObject, KCLTupleObject)): - return [to_python_obj(_v) for _v in v.value] - elif v is None or v is Undefined or isinstance(v, UndefinedType): - return v - elif isinstance(v, list): - return [to_python_obj(_v) for _v in v] - elif isinstance(v, dict): - return {_k: to_python_obj(_v) for _k, _v in v.items()} - elif isinstance(v, (int, float, str, bool, dict, list)): - return v - else: - raise Exception(f"invalid KCL object type {type(v)} to native object") - - -def to_kcl_obj( - value: Union[KCLObject, int, float, str, bool, list, dict, tuple] -) -> KCLObject: - if isinstance(value, KCLObject): - return value - if value is None: - return KCLNoneObject.instance() - if value is Undefined or isinstance(value, UndefinedType): - return KCLUndefinedObject.instance() - if isinstance(value, bool): - return KCLTrueObject.instance() if value else KCLFalseObject.instance() - elif isinstance(value, int): - return KCLIntObject(value=value) - elif isinstance(value, float): - return KCLFloatObject(value=value) - elif isinstance(value, str): - return KCLStringObject(value=value) - elif isinstance(value, tuple): - return KCLTupleObject(value=[to_kcl_obj(v) for v in value]) - elif isinstance(value, (list, set)): - return KCLListObject([to_kcl_obj(v) for v in value]) - elif isinstance(value, dict): - if KCLSchemaReverseFields.SETTINGS in value and isinstance( - value[KCLSchemaReverseFields.SETTINGS], (dict, KCLDictObject) - ): - return KCLSchemaObject( - attrs={k: to_kcl_obj(v) for k, v in value.items()}, - name=value[KCLSchemaReverseFields.SETTINGS].get( - KCLSchemaReverseFields.NAME - ), - runtime_type=value[KCLSchemaReverseFields.SETTINGS].get( - KCLSchemaReverseFields.TYPE - ), - pkgpath=value[KCLSchemaReverseFields.SETTINGS].get( - KCLSchemaReverseFields.PKG_PATH - ), - ) - return KCLDictObject({k: to_kcl_obj(v) for k, v in value.items()}) - else: - raise Exception(f"invalid native object type {type(value)} to KCL object") diff --git a/internal/kclvm_py/api/object/schema.py b/internal/kclvm_py/api/object/schema.py deleted file mode 100644 index d7f179d0a..000000000 --- a/internal/kclvm_py/api/object/schema.py +++ /dev/null @@ -1,859 +0,0 @@ -# Copyright 2021 The KCL Authors. All rights reserved. -from copy import deepcopy -from dataclasses import dataclass, field -from typing import Optional, Union, List, Dict -from .decorator import KCLDecoratorObject -from .object import ( - KCLObject, - KCLObjectType, - KCLTrueObject, - KCLFalseObject, - KCLIntObject, - KCLFloatObject, - KCLStringObject, - KCLBaseTypeObject, - KCLDictObject, - KCLSchemaObject, - KCLNoneObject, - KCLUndefinedObject, - KCLTypeKind, - KCLAnyTypeObject, - KCLStringTypeObject, - KCLSchemaReverseFields, - to_kcl_obj, -) -from .function import KWArg, KCLCompiledFunctionObject - -import kclvm.kcl.error as kcl_error -import kclvm.kcl.info as kcl_info -import kclvm.api.object.internal.common as common - -from kclvm.internal.util import hash -from kclvm.compiler.check.check_type import ( - type_pack_and_check, - check_type, - has_literal_type, -) -from kclvm.kcl.ast import ast - -SETTINGS_OUTPUT_KEY = "output_type" -SETTINGS_OUTPUT_STANDALONE = "STANDALONE" -SETTINGS_OUTPUT_INLINE = "INLINE" -SETTINGS_OUTPUT_IGNORE = "IGNORE" - -SCHEMA_SETTINGS_ATTR_NAME = "__settings__" -SCHEMA_TYPE_ATTR_NAME = "__schema_type__" -SCHEMA_RUNTIME_TYPE_ATTR_NAME = "__runtime_schema_type__" -MAIN_MODULE_NAME = "__main__" - -SCHEMA_SELF_VALUE_KEY = "$schema_self" -SCHEMA_CONFIG_VALUE_KEY = "$schema_config" -SCHEMA_CONFIG_META_KEY = "$schema_config_meta" - - -class RefGraph: - """ - Reference graph - """ - - def __init__(self): - self.adjs = {} - - def _find_node_index(self, node): - return self.nodeset.index(node) - - def add_node_judge_cycle(self, node, another_node): - """ - add edge into the schema inheritance graph and check if cyclic inheritance occurs in schema - """ - if node not in self.adjs: - self.adjs[node] = [] - if another_node not in self.adjs: - self.adjs[another_node] = [] - self.adjs[another_node].append(node) - return self._has_cycle() - - def _has_cycle(self): - """ - Determine whether the schema inheritance graph is a Directed Acyclic Graph (DAG). - The detection uses Depth First Search (DFS) algorithm for each node - in the ergodic graph, and the time complexity is O (V + E), - V: the total number of detected nodes, - E: the total number of edges connected by nodes - """ - visited = {name: 0 for name in self.adjs.keys()} - - def _dfs(name): - visited[name] = 1 - for adj in self.adjs[name]: - if visited[adj] == 1: - return True - if visited[adj] == 0: - if _dfs(adj): - return True - else: - continue - visited[name] = 2 - return False - - for name in visited.keys(): - if visited[name] == 0 and _dfs(name): - return True - return False - - -class SchemaTypeRefGraph(RefGraph): - def get_sub_schemas(self, name: str) -> list: - """Get all sub schemas by name using BFS""" - result = [] - if not name: - return result - sub_schemas = self.adjs.get(name, []) - result += sub_schemas - for sub_schema in sub_schemas: - result += self.get_sub_schemas(sub_schema) - return result - - -class SchemaTypeFactory: - """ - A schema_type factory used to get schema_type object. - """ - - def __init__(self): - self._schema_types = {} - - def register(self, name: str, schema_type: "KCLSchemaTypeObject"): - """ - Register a schema_type with a unique name. - - :param name: Name of the schema_type - :param schema_type: The schema_type to be registered - :return: None - """ - self._schema_types[name] = schema_type - - def get(self, name: str): - """ - Get and return a schema_type object. - - :param name: Name of the schema_type - :return: A schema_type object - """ - schema_type = self._schema_types.get(name) - if not schema_type: - raise Exception(f"unknown schema type '{name}'") - return schema_type - - -@dataclass -class KCLSchemaIndexSignatureObject(KCLObject): - key_name: Optional[str] = None - key_type: str = None - value_type: str = None - value: KCLObject = None - any_other: bool = None - key_kcl_type: KCLBaseTypeObject = None - value_kcl_type: KCLBaseTypeObject = None - node: ast.SchemaIndexSignature = None - - def type(self) -> KCLObjectType: - """ - Get the object type - """ - return KCLObjectType.SCHEMA_INDEX_SIGNATURE - - def type_str(self) -> str: - """ - Get the object type string - """ - return "IndexSignatureType" - - def def_str(self) -> str: - return ( - # key_name - f"[{self.key_name + ': ' if self.key_name else ''}" - # ... - + ("..." if self.any_other else "") - # key_type - + f"{self.key_type}]: " - # value_type - + f"{self.value_type}" - ) - - -@dataclass -class KCLSchemaAttrObject(KCLObject): - is_optional: bool = True - is_final: bool = False - has_default: bool = False - attr_type: KCLBaseTypeObject = None - attr_node: Optional[ast.AST] = None - - -@dataclass -class KCLSchemaTypeObject(KCLBaseTypeObject): - name: str = None - MEMBER_FUNCTIONS = ["instances"] # Member function list - name: Optional[str] = None # Schema name - __refs__: Optional[list] = field(default_factory=list) # Instance reference list - func: Optional[KCLCompiledFunctionObject] = None # Body functions - check_fn: Optional[KCLCompiledFunctionObject] = None # Check function - is_mixin: bool = False # Mark is a schema mixin - is_protocol: bool = False # Mark is a schema protocol - is_rule: bool = False # Mark is a rule block - is_relaxed: bool = False # Mark is a relaxed schema - pkgpath: str = "" # Schema definition package path - filename: str = "" # Definition path location - doc: str = "" # Schema definition document string - runtime_type: Optional[str] = None # Schema runtime type file_hash + schema_name - base: Optional["KCLSchemaTypeObject"] = None # Base schema - protocol: Optional["KCLSchemaTypeObject"] = None # Protocol schema - mixins_names: Optional[List[str]] = field(default_factory=list) - mixins: List["KCLSchemaTypeObject"] = field( - default_factory=list - ) # Schema mixin list - attrs: Optional[dict] = field(default_factory=dict) # Schema attributes - attr_list: Optional[list] = field(default_factory=list) # Schema attribute order - attr_obj_map: Dict[Union[str, int, float], Optional[KCLSchemaAttrObject]] = field( - default_factory=dict - ) # Schema attribute type map - settings: Optional[dict] = field(default_factory=dict) # Schema settings - decorators: Optional[List[KCLDecoratorObject]] = field( - default_factory=list - ) # Schema decorator list - index_signature: Optional[ - KCLSchemaIndexSignatureObject - ] = None # Schema Index signature - node_ref: Optional[ast.SchemaStmt] = None - - # ----------------- - # Schema eval cache - # ----------------- - - _eval_cache = {} - - def can_add_members(self) -> bool: - return ( - self.name.endswith("Mixin") - or self.index_signature is not None - or self.is_relaxed - ) - - def type(self) -> KCLObjectType: - """ - Get the object type - """ - return KCLObjectType.SCHEMA_TYPE - - def type_str(self) -> str: - """ - Get the object type string - """ - return ( - self.name - if (self.pkgpath == "__main__" or not self.pkgpath) - else f"{self.pkgpath}.{self.name}" - ) - - def type_str_with_pkgpath(self) -> str: - """ - Get the object type string with pkgpath - """ - return ( - self.name - if (self.pkgpath == "__main__" or not self.pkgpath) - else f"@{self.pkgpath}.{self.name}" - ) - - def type_kind(self): - return KCLTypeKind.SchemaKind - - @property - def value(self) -> str: - """Return the runtime type string""" - return self.runtime_type - - @property - def key_type(self) -> str: - if self.index_signature: - return self.index_signature.key_kcl_type - return KCLStringTypeObject() - - @property - def value_type(self) -> str: - if self.index_signature: - return self.index_signature.value_kcl_type - return KCLAnyTypeObject() - - @property - def should_add_additional_key(self) -> bool: - return self.is_relaxed or self.index_signature is not None - - @property - def file_and_type(self) -> str: - return self.filename + self.runtime_type - - @property - def file_and_name(self) -> str: - return self.filename + self.name - - def is_sub_schema_of(self, base: Union["KCLSchemaTypeObject", str]) -> bool: - base_type_obj = base - if not isinstance(base_type_obj, KCLSchemaTypeObject): - return False - if ( - self.runtime_type == base.runtime_type - or self.file_and_name == base.file_and_name - ): - return True - base_ref = self.base - while base_ref and base_ref.runtime_type != base_type_obj.runtime_type: - base_ref = base_ref.base - return True if base_ref else False - - def get_obj_of_attr(self, attr: Union[int, str]) -> Optional[KCLSchemaAttrObject]: - if attr in self.attr_obj_map: - return self.attr_obj_map[attr] - base_ref = self.base - while base_ref and attr not in base_ref.attr_obj_map: - base_ref = base_ref.base - if base_ref: - return base_ref.attr_obj_map[attr] - return ( - self.protocol.attr_obj_map[attr] - if self.protocol and attr in self.protocol.attr_obj_map - else None - ) - - def get_type_of_attr(self, attr: Union[int, str]) -> Optional[KCLBaseTypeObject]: - attr_obj = self.get_obj_of_attr(attr) - return attr_obj.attr_type if attr_obj else None - - def get_node_of_attr(self, attr: Union[int, str]) -> Optional[ast.AST]: - attr_obj = self.get_obj_of_attr(attr) - return attr_obj.attr_node if attr_obj else None - - def set_type_of_attr(self, attr: Union[int, str], tpe: KCLBaseTypeObject): - if attr in self.attr_obj_map: - self.attr_obj_map[attr].attr_type = tpe - else: - self.attr_obj_map[attr] = KCLSchemaAttrObject(attr_type=tpe) - - def set_node_of_attr(self, attr: Union[int, str], ast_node: ast.AST): - if attr in self.attr_obj_map: - self.attr_obj_map[attr].attr_node = ast_node - else: - self.attr_obj_map[attr] = KCLSchemaAttrObject(attr_node=ast_node) - - def add_decorators(self, decorators: List[KCLDecoratorObject]): - if not self.decorators: - self.decorators = [] - self.decorators += decorators - - def set_func(self, func: KCLCompiledFunctionObject): - assert isinstance(func, KCLCompiledFunctionObject) - self.func = func - - def set_check_func(self, check_fn: Optional[KCLCompiledFunctionObject]): - if check_fn: - assert isinstance(check_fn, KCLCompiledFunctionObject) - self.check_fn = check_fn - else: - self.check_fn = None - - @staticmethod - def schema_runtime_type(tpe: str, filename=""): - return f"runtime_type_{hash(filename)}_{tpe}" - - @staticmethod - def new( - name: str, - base: Optional["KCLSchemaTypeObject"] = None, - protocol: Optional["KCLSchemaTypeObject"] = None, - filename: str = "", - is_relaxed: bool = False, - is_mixin: bool = False, - pkgpath: str = "", - attr_list: list = None, - index_signature: Optional[KCLSchemaIndexSignatureObject] = None, - vm=None, - ): - if not name: - kcl_error.report_exception( - err_type=kcl_error.ErrType.EvaluationError_TYPE, - arg_msg="schema name can't be None", - ) - runtime_type = KCLSchemaTypeObject.schema_runtime_type(name, pkgpath) - settings = { - SETTINGS_OUTPUT_KEY: SETTINGS_OUTPUT_INLINE - if not kcl_info.isprivate_field(name) - else SETTINGS_OUTPUT_IGNORE, - KCLSchemaReverseFields.NAME: name, - KCLSchemaReverseFields.TYPE: f"{pkgpath}.{name}", - KCLSchemaReverseFields.PKG_PATH: pkgpath, - } - obj = KCLSchemaTypeObject( - pkgpath=pkgpath, - name=name, - base=base, - protocol=protocol, - settings=settings, - filename=filename, - is_relaxed=is_relaxed, - is_mixin=is_mixin, - runtime_type=runtime_type, - attrs={attr: KCLUndefinedObject.instance() for attr in attr_list}, - attr_list=attr_list, - index_signature=index_signature, - ) - return obj - - def update_mixins(self, vm=None): - """Get mixins by name""" - if not self.mixins and self.mixins_names: - self.mixins = [] - for mixin_name in self.mixins_names: - if "." in mixin_name: # pkg.Schema - schema_type_obj = vm.find_schema_type(mixin_name) - if schema_type_obj and isinstance( - schema_type_obj, KCLSchemaTypeObject - ): - self.mixins.append(schema_type_obj) - else: - kcl_error.report_exception( - err_type=kcl_error.ErrType.EvaluationError_TYPE, - arg_msg="name '{}' is not defined".format(mixin_name), - ) - else: - if mixin_name not in vm.frames[0].globals: - kcl_error.report_exception( - err_type=kcl_error.ErrType.EvaluationError_TYPE, - arg_msg="name '{}' is not defined".format(mixin_name), - ) - schema_type_obj = vm.frames[0].globals[mixin_name] - self.mixins.append(schema_type_obj) - - def has_base(self): - return self.base and isinstance(self.base, KCLSchemaTypeObject) - - def new_empty_instance(self) -> KCLSchemaObject: - return KCLSchemaObject( - attrs={SCHEMA_SETTINGS_ATTR_NAME: to_kcl_obj(self.settings)}, - pkgpath=self.pkgpath, - name=self.name, - runtime_type=self.runtime_type, - ) - - def new_instance( - self, - config: Union[dict, KCLDictObject], - config_meta: dict, - args: List[KCLObject], - kwargs: List[KWArg], - vm, - ): - from kclvm.vm.runtime.evaluator import SchemaEvalContext - - context = SchemaEvalContext.build_from_vm( - vm=vm, - type_obj=self, - schema_obj=self.new_empty_instance(), - config=config, - config_meta=config_meta, - args=args, - kwargs=kwargs, - ) - # Save origin eval context - org_eval_ctx = vm.lazy_eval_ctx - vm.lazy_eval_ctx = context - # Reset the eval status before the evaluation - context.eval_reset() - # Get all schema attribute value place holders using the schema type object and the cache - if self.file_and_type in self._eval_cache: - context.place_holder_map = self._eval_cache[self.file_and_type] - else: - context.get_all_place_holders() - self._eval_cache[self.file_and_type] = context.place_holder_map - # New a schema instance using the type object - context.schema_obj = self._new_instance( - config, - config_meta, - args, - kwargs, - vm, - # Put the schema instance reference - inst=context.schema_obj, - ) - # Reset the eval status after the evaluation - context.eval_reset() - # Reload origin eval context - vm.lazy_eval_ctx = org_eval_ctx - # Return the schema instance - context.schema_obj.config_keys = ( - set(config.value.keys()) - if isinstance(config, KCLDictObject) - else set(config.keys()) - ) - return context.schema_obj - - def _new_instance( - self, - config: Union[dict, KCLDictObject], - config_meta: dict, - args: List[KCLObject], - kwargs: List[KWArg], - vm, - inst: KCLSchemaObject = None, - is_sub_schema: bool = False, - ) -> KCLSchemaObject: - self.do_args_type_check(args, kwargs, config_meta, vm) - inst = inst or self.new_empty_instance() - inst.instance_pkgpath = vm.ctx.pkgpath - for decorator in self.decorators: - inst.add_decorator(self.name, decorator=decorator) - if self.base and isinstance(self.base, KCLSchemaTypeObject): - inst = self.base._new_instance( - config, config_meta, [], [], vm, inst, is_sub_schema=True - ) - # Record all schema attributes - inst.union_with(self.attrs, should_idempotent_check=False) - for mixin in self.mixins: - inst.union_with(mixin.attrs, should_idempotent_check=False) - # Record the schema name, runtime_type and relaxed - inst.update_info(self.name, self.runtime_type, self.is_relaxed) - vm.push_frame_using_callable( - self.pkgpath, - self.func, - (args if args else []) + [config_meta, config, inst], - kwargs, - args_len=len(args), - ) - # Run the schema compiled function body - vm.run(run_current=True, ignore_nop=True) - - if SCHEMA_SETTINGS_ATTR_NAME not in inst: - inst.update({SCHEMA_SETTINGS_ATTR_NAME: self.settings}) - if SCHEMA_SETTINGS_ATTR_NAME in config: - inst.update( - {SCHEMA_SETTINGS_ATTR_NAME: config.get(SCHEMA_SETTINGS_ATTR_NAME)} - ) - - # Add settings attr - if not self.attrs: - self.attrs = {} - self.attrs[SCHEMA_SETTINGS_ATTR_NAME] = ( - inst.get(SCHEMA_SETTINGS_ATTR_NAME) or self.settings - ) - - # Do relaxed schema check and config patch - relaxed_keys = self.do_relaxed_check( - inst, config_meta, config, is_sub_schema, vm - ) - - # Record the schema name, runtime_type and relaxed - inst.update_info(self.name, self.runtime_type, self.is_relaxed) - - self.update_mixins(vm=vm) - - # Do all mixins expand execution after schema context - if self.mixins: - for mixin in self.mixins: - inst = mixin._new_instance( - config, config_meta, [], [], vm, inst, is_sub_schema=True - ) - - # Record the schema name, runtime_type and relaxed - inst.update_info(self.name, self.runtime_type, self.is_relaxed) - - # Record schema instance - if not self.__refs__: - self.__refs__ = [] - self.__refs__.append(inst) - - # Deal schema stmt queue - if not is_sub_schema and inst.stmt_buffer(): - buffers = inst.stmt_buffer() - func = KCLCompiledFunctionObject( - name=self.func.name, - params=self.func.params, - names=self.func.names, - constants=self.func.constants, - ) - relaxed = inst.is_relaxed - for buffer in buffers: - is_relaxed, pkg_path, codes = buffer - func.instructions = codes - inst.is_relaxed = is_relaxed - vm.push_frame_using_callable( - pkg_path, - func, - (args if args else []) + [config_meta, config, inst], - kwargs, - args_len=len(args), - ) - # Run the schema compiled function body - vm.run(run_current=True, ignore_nop=True) - inst.is_relaxed = relaxed - # Run all decorators - inst.run_all_decorators() - # Do all checks - if not is_sub_schema: - inst.operation_map = { - KCLSchemaReverseFields.SETTINGS: ast.ConfigEntryOperation.OVERRIDE - } - inst.update_attr_op_using_obj(config) - inst.check_optional_attrs() - self.do_check(inst, config_meta, config, relaxed_keys, vm) - # Return the schema object - return inst - - def do_args_type_check( - self, - args: List[KCLObject], - kwargs: List[KWArg], - config_meta: dict, - vm=None, - ): - """Check args type""" - - def check_arg_type(arg_name: str, value: KCLObject, expected_type: str): - checked, value_tpe = check_type(value, expected_type, vm) - if not checked: - if has_literal_type([expected_type]): - if isinstance( - value, - ( - KCLNoneObject, - KCLTrueObject, - KCLFalseObject, - KCLIntObject, - KCLFloatObject, - ), - ): - value_tpe = f"{value_tpe}({value.value})" - elif isinstance(value, KCLStringObject): - value_tpe = f'{value_tpe}("{value.value}")' - - conf_filename, conf_line, conf_column = ( - config_meta.get("$filename"), - config_meta.get("$lineno"), - config_meta.get("$columnno"), - ) - kcl_error.report_exception( - err_type=kcl_error.ErrType.TypeError_Runtime_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=conf_filename, - line_no=conf_line, - col_no=conf_column, - ) - ], - arg_msg='argument "{}" expect {}, got {}'.format( - arg_name, - common.get_tpes_str([expected_type]).replace("@", ""), - common.get_class_name(value_tpe), - ), - ) - - if self.func.params: - for i, value in enumerate(args or []): - arg_name = self.func.params[i].name - expected_type = self.func.params[i].type_annotation - check_arg_type(arg_name, value, expected_type) - - for kwarg in kwargs or []: - arg_name = kwarg.name.value - value = kwarg.value - if arg_name not in [p.name for p in self.func.params]: - kcl_error.report_exception( - err_type=kcl_error.ErrType.EvaluationError_TYPE, - arg_msg=f"schema arguments got an unexpected keyword argument '{arg_name}'", - ) - expected_types = [ - p.type_annotation for p in self.func.params if arg_name == p.name - ] - expected_type = expected_types[0] if expected_types else None - check_arg_type(arg_name, value, expected_type) - - def do_relaxed_check( - self, - inst: KCLSchemaObject, - config_meta: dict, - config: Union[dict, KCLDictObject], - is_sub_schema: bool, - vm, - ) -> List[str]: - """Do relaxed schema check and config patch""" - relaxed_keys = [] - if not is_sub_schema: - config_native = ( - config.value if isinstance(config, KCLDictObject) else config - ) - config_meta_native = config_meta - relaxed_keys = [ - key for key in config_native if key not in inst.value.keys() - ] - if self.protocol: - relaxed_keys = [ - key for key in relaxed_keys if key not in self.protocol.attr_list - ] - if self.is_relaxed or self.index_signature: - filename = vm.get_filename() - if self.index_signature and not self.index_signature.any_other: - for key in inst.value.keys(): - if key != SCHEMA_SETTINGS_ATTR_NAME: - value = inst.get(key) - checked, _ = check_type( - value, - self.index_signature.value_type, - vm=vm, - ) - if not checked: - kcl_error.report_exception( - err_type=kcl_error.ErrType.EvaluationError_TYPE, - file_msgs=[kcl_error.ErrFileMsg(filename=filename)], - arg_msg=f"the type '{value.type_str()}' of schema attribute '{key}' " - f"does not meet the index signature definition {self.index_signature.def_str()}", - ) - for key in relaxed_keys: - lineno, columnno = None, None - if key in config_meta_native: - lineno, columnno = ( - config_meta_native[key].get("lineno"), - config_meta_native[key].get("columnno"), - ) - value = config.get(key) - if self.index_signature and self.index_signature.value_type: - types = [self.index_signature.value_type] - from kclvm.vm.runtime.evaluator import union - - value = type_pack_and_check( - union( - deepcopy(self.index_signature.value), - value, - should_idempotent_check=True, - vm=vm, - ), - types, - filename, - lineno, - columnno, - vm=vm, - config_meta=config_meta, - ) - inst.update({key: value}) - - elif relaxed_keys: - lineno, columnno = None, None - if relaxed_keys[0] in config_meta_native: - lineno, columnno = ( - config_meta_native[relaxed_keys[0]].get("lineno"), - config_meta_native[relaxed_keys[0]].get("columnno"), - ) - kcl_error.report_exception( - err_type=kcl_error.ErrType.CannotAddMembers_Runtime_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=vm.get_filename(), line_no=lineno, col_no=columnno - ) - ], - arg_msg=kcl_error.CANNOT_ADD_MEMBERS_MSG.format( - ",".join([str(k) for k in relaxed_keys]), self.name - ), - ) - return relaxed_keys - - def do_check( - self, - inst: KCLSchemaObject, - config_meta: dict, - config: Union[dict, KCLDictObject], - relaxed_keys: List[str], - vm, - ): - assert inst, f"{inst}" - assert vm - - def call_check_fn(local_name: str = None, local_value: KCLObject = None): - if self.check_fn: - vm.push_frame_using_callable( - self.pkgpath, self.check_fn, [config_meta, config, inst], [] - ) - if local_name and local_value: - vm.update_local(local_name, local_value) - vm.run(run_current=True, ignore_nop=True) - - # check base - if self.base and isinstance(self.base, KCLSchemaTypeObject): - self.base.do_check(inst, config_meta, config, relaxed_keys, vm) - - # check mixin - for mixin in self.mixins or []: - mixin.do_check(inst, config_meta, config, relaxed_keys, vm) - - # check self - if self.index_signature and self.index_signature.key_name and relaxed_keys: - # For loop index signature attributes - for key in relaxed_keys: - call_check_fn(self.index_signature.key_name, to_kcl_obj(key)) - else: - call_check_fn() - - # Member Functions - - def instances(self, main_pkg: bool = True): - """Get all schema instances of self type and sub types""" - if not self.__refs__: - self.__refs__ = [] - return deepcopy( - [ - inst - for inst in self.__refs__ - if inst.instance_pkgpath == MAIN_MODULE_NAME - ] - if main_pkg - else self.__refs__ - ) - - def get_member_method(self, name: str): - from .function import KCLMemberFunctionObject - - if not name: - kcl_error.report_exception( - err_type=kcl_error.ErrType.EvaluationError_TYPE, - arg_msg="kcl string object member name can't be empty or None", - ) - if name not in self.MEMBER_FUNCTIONS: - kcl_error.report_exception( - err_type=kcl_error.ErrType.AttributeError_TYPE, - arg_msg=f"attribute '{name}' not found", - ) - return KCLMemberFunctionObject(obj=self, name=name) - - def call_member_method(self, name: str, *args, **kwargs): - if not hasattr(self, name) and name not in self.MEMBER_FUNCTIONS: - kcl_error.report_exception( - err_type=kcl_error.ErrType.AttributeError_TYPE, - arg_msg=f"attribute '{name}' not found", - ) - return getattr(self, name).__call__(*args, **kwargs) - - -@dataclass -class KCLSchemaDefTypeObject(KCLBaseTypeObject): - """Schema definition type denotes the schema definition type used in normal expressions. - - - `Person` of `data = Person.instances()` is a schema def type. - - `person` of `person = Person {}` is a schema type. - """ - - schema_type: KCLSchemaTypeObject - - def type_str(self) -> str: - """Get the object type""" - return self.schema_type.type_str() if self.schema_type else super().type_str() - - def type_kind(self) -> int: - """Get the""" - return KCLTypeKind.SchemaDefKind diff --git a/internal/kclvm_py/api/readme.md b/internal/kclvm_py/api/readme.md deleted file mode 100644 index 1333ed77b..000000000 --- a/internal/kclvm_py/api/readme.md +++ /dev/null @@ -1 +0,0 @@ -TODO diff --git a/internal/kclvm_py/api/version/__init__.py b/internal/kclvm_py/api/version/__init__.py deleted file mode 100644 index 30175578d..000000000 --- a/internal/kclvm_py/api/version/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -# Copyright 2021 The KCL Authors. All rights reserved. - -from .version import VERSION, CHECKSUM - -__all__ = ["VERSION", "CHECKSUM"] diff --git a/internal/kclvm_py/api/version/__main__.py b/internal/kclvm_py/api/version/__main__.py deleted file mode 100644 index 9e6891354..000000000 --- a/internal/kclvm_py/api/version/__main__.py +++ /dev/null @@ -1,27 +0,0 @@ -# Copyright 2021 The KCL Authors. All rights reserved. - -import sys - -import kclvm.api.version as version - -USAGE = """\ -usage: kclvm -m kclvm.api.version - kclvm -m kclvm.api.version -checksum - kclvm -m kclvm.api.version -h -""" - -if __name__ == "__main__": - if len(sys.argv) == 2 and (sys.argv[1] == "-h" or sys.argv[1] == "-help"): - print(USAGE) - sys.exit(0) - - if len(sys.argv) == 2 and sys.argv[1] == "-checksum": - print(version.CHECKSUM) - sys.exit(0) - - if len(sys.argv) > 1: - print(USAGE) - sys.exit(1) - - print(version.VERSION) - sys.exit(0) diff --git a/internal/kclvm_py/api/version/checksum.txt b/internal/kclvm_py/api/version/checksum.txt deleted file mode 100644 index 2046c0aee..000000000 --- a/internal/kclvm_py/api/version/checksum.txt +++ /dev/null @@ -1 +0,0 @@ -e07ed7af0d9bd1e86a3131714e4bd20c \ No newline at end of file diff --git a/internal/kclvm_py/api/version/version.py b/internal/kclvm_py/api/version/version.py deleted file mode 100644 index ff2b650a2..000000000 --- a/internal/kclvm_py/api/version/version.py +++ /dev/null @@ -1,7 +0,0 @@ -# Copyright 2021 The KCL Authors. All rights reserved. - -import os -from pathlib import Path - -VERSION = "0.4.2" -CHECKSUM = Path(f"{os.path.dirname(__file__)}/checksum.txt").read_text().strip() diff --git a/internal/kclvm_py/compiler/__init__.py b/internal/kclvm_py/compiler/__init__.py deleted file mode 100644 index d74aaf8ad..000000000 --- a/internal/kclvm_py/compiler/__init__.py +++ /dev/null @@ -1 +0,0 @@ -# Copyright 2021 The KCL Authors. All rights reserved. diff --git a/internal/kclvm_py/compiler/astutil/__init__.py b/internal/kclvm_py/compiler/astutil/__init__.py deleted file mode 100644 index dc57c7e76..000000000 --- a/internal/kclvm_py/compiler/astutil/__init__.py +++ /dev/null @@ -1,23 +0,0 @@ -# Copyright 2021 The KCL Authors. All rights reserved. - -from .builder import BuildLitNodeFromString, BuildLitNodeFromValue, BuildNodeFromString -from .filter import Declaration, filter_declarations, filter_stmt -from .fix import ( - fix_set_parent_info, - fix_qualified_identifier, - fix_and_get_module_import_list, - fix_test_schema_auto_relaxed, -) - -__all__ = [ - "BuildLitNodeFromString", - "BuildLitNodeFromValue", - "BuildNodeFromString", - "Declaration", - "filter_declarations", - "filter_stmt", - "fix_set_parent_info", - "fix_qualified_identifier", - "fix_and_get_module_import_list", - "fix_test_schema_auto_relaxed", -] diff --git a/internal/kclvm_py/compiler/astutil/builder.py b/internal/kclvm_py/compiler/astutil/builder.py deleted file mode 100644 index 20c46a7e0..000000000 --- a/internal/kclvm_py/compiler/astutil/builder.py +++ /dev/null @@ -1,90 +0,0 @@ -# Copyright 2021 The KCL Authors. All rights reserved. - -import re -from ast import literal_eval -from typing import Union - -import kclvm.kcl.ast as ast -import kclvm.compiler.parser as parser -import kclvm.api.object.internal as internal - - -def BuildNodeFromString(value: str, line: int = None, column: int = None) -> ast.Expr: - lit_node = BuildLitNodeFromString(value, line, column) - if isinstance(lit_node, ast.StringLit): - try: - val = parser.ParseExpr(code=value) - # If `val` is a identifier, convert it to a string literal - return lit_node if isinstance(val, ast.Identifier) else val - except Exception: - return lit_node - return lit_node - - -def BuildLitNodeFromValue( - value: Union[int, float, str, bool], line: int = None, column: int = None -) -> ast.Literal: - if value is None: - val = ast.NameConstantLit() - val.value = None - elif value is internal.Undefined: - val = ast.NameConstantLit() - val.value = internal.Undefined - elif value is True: - val = ast.NameConstantLit() - val.value = True - elif value is False: - val = ast.NameConstantLit() - val.value = False - elif isinstance(value, (int, float)): - val = ast.NumberLit(value=value) - else: - val = ast.StringLit() - val.value = value if isinstance(value, str) else str(value) - val.line = line - val.column = column - return val - - -def BuildLitNodeFromString( - value: str, line: int = None, column: int = None -) -> ast.Literal: - if value in ["True", "true"]: - val = ast.NameConstantLit() - val.value = True - elif value in ["False", "false"]: - val = ast.NameConstantLit() - val.value = False - elif value in ["None", "null"]: - val = ast.NameConstantLit() - val.value = None - elif value in ["Undefined"]: - val = ast.NameConstantLit() - val.value = internal.Undefined - elif is_number(value): - val = ast.NumberLit(value=literal_eval(value)) - else: - val = ast.StringLit() - val.value = str(value) - val.raw_value = value - - if val.value and val.value[0] == "'" and val.value[-1] == "'": - val.value = val.value[1:-1] - elif val.value and val.value[0] == '"' and val.value[-1] == '"': - val.value = val.value[1:-1] - - if ( - val.raw_value - and val.raw_value[0] not in ["'", '"'] - and val.raw_value[-1] not in ["'", '"'] - ): - val.raw_value = '"' + val.raw_value.replace('"', '\\"') + '"' - val.line = line - val.column = column - return val - - -def is_number(value: str): - """Whether a string is a number string""" - pattern = re.compile(r"^[-+]?[-0-9]\d*\.\d*|[-+]?\.?[0-9]\d*$") - return bool(pattern.match(value)) diff --git a/internal/kclvm_py/compiler/astutil/filter.py b/internal/kclvm_py/compiler/astutil/filter.py deleted file mode 100644 index d9c24730d..000000000 --- a/internal/kclvm_py/compiler/astutil/filter.py +++ /dev/null @@ -1,76 +0,0 @@ -# Copyright 2021 The KCL Authors. All rights reserved. - -from typing import cast, List, Union, Optional, Type -from dataclasses import dataclass - -import kclvm.kcl.ast as ast - - -@dataclass -class Declaration: - filename: str - name: str - value: ast.Expr - is_union: bool - - -def filter_declarations( - module: ast.Module, - ast_type: Optional[Union[Type[ast.AST], str, tuple, list]] = None, -) -> List[Declaration]: - """Get all global AssignStmt key-value pair config according to the `ast_type`. - When the `ast_type` is None, select all declarations - """ - if not module or not isinstance(module, ast.Module): - return [] - declaration_list = [] - for stmt in module.body or []: - declaration = None - if isinstance(stmt, ast.AssignStmt): - stmt = cast(ast.AssignStmt, stmt) - for target in stmt.targets: - name = target.get_name() - if target.ctx == ast.ExprContext.STORE: - value = cast(ast.Expr, stmt.value) - declaration = Declaration( - filename=stmt.filename, - name=name, - value=value, - is_union=False, - ) - elif isinstance(stmt, ast.UnificationStmt): - stmt = cast(ast.UnificationStmt, stmt) - name = stmt.target.get_name() - value = cast(ast.Expr, stmt.value) - declaration = Declaration( - filename=stmt.filename, name=name, value=stmt.value, is_union=True - ) - if declaration: - if ast_type is None: - declaration_list.append(declaration) - elif isinstance(ast_type, (list, tuple)) and isinstance( - stmt.value, tuple(ast_type) - ): - declaration_list.append(declaration) - elif isinstance(ast_type, str) and value.type == ast_type: - declaration_list.append(declaration) - elif isinstance(ast_type, type(ast.AST)) and isinstance( - stmt.value, ast_type - ): - declaration_list.append(declaration) - return declaration_list - - -def filter_stmt( - module: ast.Module, stmt_type: Union[str, Type[ast.Stmt]] -) -> List[ast.Stmt]: - """Get all AugAssignStmt at the top level of the module""" - if not module or not isinstance(module, ast.Module): - return [] - if not stmt_type: - return [] - result = [] - for stmt in module.body or []: - if stmt.type == stmt_type or isinstance(stmt, stmt_type): - result.append(stmt) - return result diff --git a/internal/kclvm_py/compiler/astutil/fix.py b/internal/kclvm_py/compiler/astutil/fix.py deleted file mode 100644 index a38ac7ce1..000000000 --- a/internal/kclvm_py/compiler/astutil/fix.py +++ /dev/null @@ -1,486 +0,0 @@ -# Copyright 2021 The KCL Authors. All rights reserved. - -import re -import typing -import copy -from collections import OrderedDict - -import kclvm.kcl.error as kcl_error -import kclvm.kcl.info as kcl_info -import kclvm.kcl.ast as ast -import kclvm.compiler.parser.lark_parser as lark_parser -import kclvm.compiler.vfs as vfs - -PKGPATH_IDENTIFIER_DOT_REGEX = r"[\d\w_]+\." -PKGPATH_DOT_REGEX = r"@[\d\w_\.]+\." - - -def _get_global_names(m: ast.Module) -> typing.List[str]: - assert m - assert isinstance(m, ast.Module) - - global_name_dict: typing.Dict[str, ast.AST] = OrderedDict() - - def walkFn_global(t: ast.AST) -> typing.Optional[typing.Callable]: - nonlocal global_name_dict - - if isinstance(t, (ast.SchemaStmt, ast.RuleStmt)): - node = t - if kcl_info.isprivate_field(node.name) or node.name not in global_name_dict: - global_name_dict[node.name] = node - else: - kcl_error.report_exception( - err_type=kcl_error.ErrType.UniqueKeyError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=lark_parser.filename, - line_no=node.line, - col_no=node.column, - ) - ], - arg_msg=kcl_error.UNIQUE_KEY_MSG.format(node.name), - ) - return None - - if isinstance(t, (ast.SchemaExpr, ast.LambdaExpr)): - return None - - if isinstance(t, ast.ImportStmt): - return None - - if isinstance(t, (ast.ListComp, ast.DictComp)): - return None - - if isinstance(t, ast.AssignStmt): - node = typing.cast(ast.AssignStmt, t) - for expr in node.targets: - if not isinstance(expr, ast.Identifier) or isinstance( - node.value, ast.LambdaExpr - ): - continue - - ident = typing.cast(ast.Identifier, expr) - is_config = isinstance(node.value, ast.SchemaExpr) - if ( - kcl_info.isprivate_field(ident.names[0]) - or (ident.names[0] not in global_name_dict) - or is_config - ): - global_name_dict[ident.names[0]] = node - else: - kcl_error.report_exception( - err_type=kcl_error.ErrType.ImmutableCompileError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=lark_parser.filename, - line_no=ident.line, - col_no=ident.column, - end_col_no=ident.end_column, - ) - ], - ) - - # continue walk - return walkFn_global - - # walk tree - ast.WalkTree(m, walkFn_global) - - # dict to list - return list(global_name_dict.keys()) - - -def _get_schema_local_names( - schema: typing.Union[ast.SchemaStmt, ast.RuleStmt] -) -> typing.List[str]: - assert schema - assert isinstance(schema, (ast.SchemaStmt, ast.RuleStmt)) - - local_name_dict: typing.Dict[str, ast.AST] = OrderedDict() - - # walk args - if schema.args: - for x in schema.args.args: - assert len(x.names) == 1, f"schema.args={schema.args}" - local_name_dict[x.names[0]] = x - - def walkFn_schema_local(t: ast.AST) -> typing.Optional[typing.Callable]: - if isinstance(t, ast.SchemaAttr): - node = typing.cast(ast.SchemaAttr, t) - local_name_dict[node.name] = node - return None - - if isinstance(t, ast.AssignStmt): - node = typing.cast(ast.AssignStmt, t) - - # a = b = c.d = value - for expr in node.targets: - if not isinstance(expr, ast.Identifier): - continue - - ident = typing.cast(ast.Identifier, expr) - - # skip: c.d = value - if len(ident.names) == 1: - local_name_dict[ident.names[0]] = ident - - # continue walk - return walkFn_schema_local - - # walk tree - ast.WalkTree(schema, walkFn_schema_local) - - return list(local_name_dict.keys()) - - -def fix_set_parent_info(m: ast.Module): - """ - set parent info on ast - :param m: target module ast - """ - - def _walk(t: ast.AST): - def _set_parent( - parent: ast.AST, inner: typing.Union[typing.List, typing.Dict, ast.AST] - ): - if isinstance(inner, list): - [_set_parent(parent, item) for item in inner] - return - if isinstance(inner, dict): - [_set_parent(parent, v) for _, v in inner] - return - if isinstance(inner, ast.AST): - inner.parent = parent - _walk(inner) - - for _, value in ast.iter_fields(t): - _set_parent(t, value) - - assert m and isinstance(m, ast.Module) - return _walk(m) - - -def fix_qualified_identifier( - m: ast.Module, *, import_names: typing.Optional[typing.Dict[str, str]] = None -): - """ - import path.to.pkg as pkgname - - x = pkgname.Name - """ - # 0. init import names - if import_names is None or not isinstance(import_names, dict): - import_names = {} - for import_spec in m.GetImportList(): - import_names[import_spec.name] = import_spec.path - - # 1. init global names - _global_names = _get_global_names(m) - for name in _global_names: - if name not in m.global_names: - m.global_names.append(name) - - # 2. init schema local name - _schema_local_names: typing.Dict[str, typing.List[str]] = {} - for schema in m.GetSchemaAndRuleList(): - _schema_local_names[schema.name] = _get_schema_local_names(schema) - if schema.name not in m.local_names: - m.local_names = _schema_local_names - - current_schema_name = "" - generator_local_vars = [] - - def walkFn_fix_global_ident(t: ast.AST) -> typing.Optional[typing.Callable]: - if isinstance(t, (ast.DictComp, ast.ListComp)): - for gen in t.generators or []: - for ident in gen.targets: - generator_local_vars.append(ident.get_first_name()) - ast.WalkTree(gen, walkFn_fix_global_ident) - if isinstance(t, ast.ListComp): - ast.WalkTree(t.elt, walkFn_fix_global_ident) - if isinstance(t, ast.DictComp): - ast.WalkTree(t.key, walkFn_fix_global_ident) - ast.WalkTree(t.value, walkFn_fix_global_ident) - generator_local_vars.clear() - return None - elif isinstance(t, ast.QuantExpr): - for ident in t.variables: - generator_local_vars.append(ident.get_first_name()) - ast.WalkTree(t.target, walkFn_fix_global_ident) - ast.WalkTree(t.test, walkFn_fix_global_ident) - ast.WalkTree(t.if_cond, walkFn_fix_global_ident) - generator_local_vars.clear() - if not isinstance(t, ast.Identifier): - return walkFn_fix_global_ident - - ident = typing.cast(ast.Identifier, t) - if len(ident.names) < 2: - return None - - # skip global name and generator local variables in list/dict comp and quant expression - if ident.names[0] in _global_names or ident.names[0] in generator_local_vars: - return None - - # fix qualified identifier - if ident.names[0] in import_names: - ident.pkgpath = import_names[ident.names[0]] - - return None - - def walkFn_fix_schema_ident(t: ast.AST) -> typing.Optional[typing.Callable]: - nonlocal current_schema_name - assert current_schema_name, f"current_schema_name={current_schema_name}" - - if not isinstance(t, ast.Identifier): - return walkFn_fix_global_ident - - ident = typing.cast(ast.Identifier, t) - if len(ident.names) < 2: - return None - - # skip local name - _local_names = _schema_local_names[current_schema_name] - if ident.names[0] in _local_names: - return None - - # skip global name - if ident.names[0] in _global_names: - return None - - # fix qualified identifier - if ident.names[0] in import_names: - ident.pkgpath = import_names[ident.names[0]] - - return None - - # ----------------------------------------------------- - - # 3. fix all ident - for stmt in m.body or []: - if isinstance(stmt, (ast.SchemaStmt, ast.RuleStmt)): - node = stmt - current_schema_name = node.name - ast.WalkTree(node, walkFn_fix_schema_ident) - current_schema_name = "" - continue - - ast.WalkTree(stmt, walkFn_fix_global_ident) - - # OK - return - - -def fix_and_get_module_import_list( - root: str, m: ast.Module, is_fix: bool = True, reversed: bool = False -) -> typing.List[ast.ImportStmt]: - assert m - assert isinstance(m, ast.Module) - assert m.pkg - - import_spec_list: typing.List[ast.ImportStmt] = [] - pkgpath_table = {} - - for stmt in m.body or []: - if not isinstance(stmt, ast.ImportStmt): - continue - - if is_fix: - assert stmt.path - assert stmt.pkg_name - - stmt.rawpath = stmt.path - - stmt.path = vfs.FixImportPath(root, m.filename, stmt.path) - stmt.name = stmt.pkg_name - if reversed: - pkgpath_table[stmt.path] = stmt.name - else: - pkgpath_table[stmt.name] = stmt.path - - import_spec = copy.deepcopy(stmt) - import_spec_list.append(import_spec) - - if not is_fix: - return import_spec_list - - # fix types name - # asname.Name => @abs.pkg.Name - # [asname.Name] => [@abs.pkg.Name] - # {str:asname.Name} => {str:@abs.pkg.Name} - # {str:[asname.Name]} => {str:[@abs.pkg.Name]} - # asname1.Name1 | asname2.Name2 => @abs.pkg1.Name1 | @abs.pkg2.Name2 - for stmt in m.body or []: - if isinstance(stmt, ast.AssignStmt): - assign_stmt = typing.cast(ast.AssignStmt, stmt) - if assign_stmt.type_annotation: - if reversed: - assign_stmt.type_annotation = re.sub( - PKGPATH_DOT_REGEX, - lambda x: f"{pkgpath_table[x.group()[1:-1]]}." - if x.group()[1:-1] in pkgpath_table - else x.group(), - assign_stmt.type_annotation, - ) - else: - assign_stmt.type_annotation = re.sub( - PKGPATH_IDENTIFIER_DOT_REGEX, - lambda x: f"@{pkgpath_table[x.group()[:-1]]}." - if x.group()[:-1] in pkgpath_table - else x.group(), - assign_stmt.type_annotation, - ) - elif isinstance(stmt, ast.SchemaStmt): - schema_stmt = typing.cast(ast.SchemaStmt, stmt) - # Fix schema arguments type - if schema_stmt.args and schema_stmt.args.type_annotation_list: - for i, _type in enumerate(schema_stmt.args.type_annotation_list): - # if the `_type` is None, the schema argument has no any type annotation - if not _type: - continue - if reversed: - schema_stmt.args.type_annotation_list[i] = re.sub( - PKGPATH_DOT_REGEX, - lambda x: f"{pkgpath_table[x.group()[1:-1]]}." - if x.group()[1:-1] in pkgpath_table - else x.group(), - _type, - ) - else: - schema_stmt.args.type_annotation_list[i] = re.sub( - PKGPATH_IDENTIFIER_DOT_REGEX, - lambda x: f"@{pkgpath_table[x.group()[:-1]]}." - if x.group()[:-1] in pkgpath_table - else x.group(), - _type, - ) - # Fix schame attr type - for attr in schema_stmt.body or []: - if not isinstance(attr, ast.SchemaAttr): - continue - schema_attr = typing.cast(ast.SchemaAttr, attr) - _type = schema_attr.type_str - if reversed: - schema_attr.type_str = re.sub( - PKGPATH_DOT_REGEX, - lambda x: f"{pkgpath_table[x.group()[1:-1]]}." - if x.group()[1:-1] in pkgpath_table - else x.group(), - _type, - ) - else: - schema_attr.type_str = re.sub( - PKGPATH_IDENTIFIER_DOT_REGEX, - lambda x: f"@{pkgpath_table[x.group()[:-1]]}." - if x.group()[:-1] in pkgpath_table - else x.group(), - _type, - ) - elif isinstance(stmt, ast.RuleStmt): - rule_stmt = typing.cast(ast.RuleStmt, stmt) - if rule_stmt.args and rule_stmt.args.type_annotation_list: - for i, _type in enumerate(rule_stmt.args.type_annotation_list): - # if the `_type` is None, the rule argument has no any type annotation - if not _type: - continue - if reversed: - rule_stmt.args.type_annotation_list[i] = re.sub( - PKGPATH_DOT_REGEX, - lambda x: f"{pkgpath_table[x.group()[1:-1]]}." - if x.group()[1:-1] in pkgpath_table - else x.group(), - _type, - ) - else: - rule_stmt.args.type_annotation_list[i] = re.sub( - PKGPATH_IDENTIFIER_DOT_REGEX, - lambda x: f"@{pkgpath_table[x.group()[:-1]]}." - if x.group()[:-1] in pkgpath_table - else x.group(), - _type, - ) - elif isinstance(stmt, ast.TypeAliasStmt): - # Fix rule arguments type - type_alias_stmt = typing.cast(ast.TypeAliasStmt, stmt) - if type_alias_stmt.type_value.plain_type_str: - if reversed: - type_alias_stmt.type_value.plain_type_str = re.sub( - PKGPATH_DOT_REGEX, - lambda x: f"{pkgpath_table[x.group()[1:-1]]}." - if x.group()[1:-1] in pkgpath_table - else x.group(), - type_alias_stmt.type_value.plain_type_str, - ) - else: - type_alias_stmt.type_value.plain_type_str = re.sub( - PKGPATH_IDENTIFIER_DOT_REGEX, - lambda x: f"@{pkgpath_table[x.group()[:-1]]}." - if x.group()[:-1] in pkgpath_table - else x.group(), - type_alias_stmt.type_value.plain_type_str, - ) - - class TypeNameTransformer(ast.TreeTransformer): - def walk_LambdaExpr(self, node: ast.LambdaExpr): - if node.args and node.args.type_annotation_list: - for i, _type in enumerate(node.args.type_annotation_list): - # if the `_type` is None, the schema argument has no any type annotation - if not _type: - continue - if reversed: - node.args.type_annotation_list[i] = re.sub( - PKGPATH_DOT_REGEX, - lambda x: f"{pkgpath_table[x.group()[1:-1]]}." - if x.group()[1:-1] in pkgpath_table - else x.group(), - _type, - ) - else: - node.args.type_annotation_list[i] = re.sub( - PKGPATH_IDENTIFIER_DOT_REGEX, - lambda x: f"@{pkgpath_table[x.group()[:-1]]}." - if x.group()[:-1] in pkgpath_table - else x.group(), - _type, - ) - if node.return_type_str: - if reversed: - node.return_type_str = re.sub( - PKGPATH_DOT_REGEX, - lambda x: f"{pkgpath_table[x.group()[1:-1]]}." - if x.group()[1:-1] in pkgpath_table - else x.group(), - node.return_type_str, - ) - else: - node.return_type_str = re.sub( - PKGPATH_IDENTIFIER_DOT_REGEX, - lambda x: f"@{pkgpath_table[x.group()[:-1]]}." - if x.group()[:-1] in pkgpath_table - else x.group(), - node.return_type_str, - ) - return node - - TypeNameTransformer().walk(m) - - return import_spec_list - - -def fix_test_schema_auto_relaxed(m: ast.Module): - if not m.filename.endswith("_test.k"): - return - - for stmt in m.body or []: - if not isinstance(stmt, ast.SchemaStmt): - continue - - schema = typing.cast(ast.SchemaStmt, stmt) - if schema.name.startswith("Test"): - for x in schema.body or []: - if not isinstance(x, ast.SchemaAttr): - continue - attr = typing.cast(ast.SchemaAttr, x) - attr.type_str = "" - attr.is_optional = True - - return diff --git a/internal/kclvm_py/compiler/build/__init__.py b/internal/kclvm_py/compiler/build/__init__.py deleted file mode 100644 index d74aaf8ad..000000000 --- a/internal/kclvm_py/compiler/build/__init__.py +++ /dev/null @@ -1 +0,0 @@ -# Copyright 2021 The KCL Authors. All rights reserved. diff --git a/internal/kclvm_py/compiler/build/compiler.py b/internal/kclvm_py/compiler/build/compiler.py deleted file mode 100644 index cbbd67774..000000000 --- a/internal/kclvm_py/compiler/build/compiler.py +++ /dev/null @@ -1,2219 +0,0 @@ -"""The `compiler` file mainly contains the function `CompileProgram` -which is used to compile the AST obtained by the parser module into -KCL bytecode. - -The KCL compiler is mainly based on `ast.TreeWalker` to implement -traversal of all AST nodes, perform semantic checks and generate -corresponding bytecodes, and implement scope checks based on the -symbol table. - -The main compilation process is to use `ast.TreeTransformer` to -preprocess the AST, such as eliminating syntactic sugar, checking -import, VFS path mapping, and configuration merging, etc. Then -generate the corresponding KCL bytecode, which mainly includes opcode, -operand, name memory, object memory, etc. The KCL bytecode is input -into the KCL virtual machine for execution and the result is obtained. - -:note: When the definition of any AST node is modified or the AST node -is added/deleted, it is necessary to modify the corresponding processing -in the compiler walk_{AST Name} methods. -:copyright: Copyright 2020 The KCL Authors. All rights reserved. -""" - -import typing - -from dataclasses import dataclass -from typing import Callable, Any, List, Dict, Optional, Union - -import kclvm.kcl.ast as ast -import kclvm.kcl.error as kcl_error -import kclvm.api.object as objpkg -import kclvm.api.object.internal as obj_internal -import kclvm.compiler.vfs as vfs -import kclvm.compiler.extension.builtin as builtin -import kclvm.compiler.astutil.fix as fix -import kclvm.vm.code as vm -import kclvm.unification as unification -import kclvm.tools.query as query - -from kclvm.api.object.internal import Undefined -from kclvm.kcl.types import ResolveProgram, ProgramScope, ANY_TYPE, parse_type_str -from kclvm.compiler.build.symtable import SymbolTable, SymbolScope -from kclvm.compiler.build.utils import units -from kclvm.internal.util import CheckRules - -from kclvm.compiler.build.data import ( - CMP_OP_MAPPING, - BIN_OP_MAPPING, - UNARY_OP_MAPPING, - ARG_OP_MAPPING, - EXPR_OP_MAPPING, - SUBSCR_OP_MAPPING, - SYMBOL_SCOPE_LOAD_OP_MAPPING, - SYMBOL_SCOPE_STORE_OP_MAPPING, - CompilerInternalErrorMeta, - SchemaConfigMeta, -) - - -_COMPILE_ERROR = kcl_error.ErrType.CompileError_TYPE -_BODY_ATTR = "body" -_EXPRS_ATTR = "exprs" - -LAMBDA_FUNC_NAME = "" -RESERVED_IDENTIFIERS = [ - "True", - "False", - "None", - "Undefined", -] -LITERAL_EXPRS = ( - ast.NumberLit, - ast.StringLit, - ast.NameConstantLit, - ast.QuantExpr, - ast.ListExpr, - ast.ListComp, - ast.DictComp, -) - - -@dataclass -class RuntimeCode(objpkg.KCLObject): - """ - Runtime code is a temporary structure for storing compilation results. - """ - - names: List[str] - constants: List[objpkg.KCLObject] - codes: List[int] - - def type(self) -> objpkg.KCLObjectType: - """ - Get the object type - """ - return objpkg.KCLObjectType.RUNTIME_CODE - - def type_str(self) -> str: - """ - Get the object type - """ - return "runtime_code" - - -# ----------------------------------------------------------------------------- -# _CompilerBase -# ----------------------------------------------------------------------------- - - -class _CompilerBase(ast.TreeWalker): - """_ComplierBase function""" - - def __init__(self, filename=""): - super().__init__() - - self.pkgpath: str = "" - - # File information - self.filename: str = filename - self.lineno: int = 0 - self.colno: int = 0 - # Compiler parameters - self.names: List[str] = [] - self.constants: List[objpkg.KCLObject] = builtin.get_builtin_func_objects() - # Symbol table - self.symtable: SymbolTable = SymbolTable.new_with_built_in() - # Compile scope level - self.scopes: list = [vm.CompilationScope(instructions=[])] - # In schema expression level - self._is_in_schema_exprs: List[bool] = [False] - # In schema statement level - self._is_in_schema_stmt: List[bool] = [False] - # In lambda expression level - self._is_in_lambda_expr: List[bool] = [False] - # In if statement - self._is_in_if_stmt: List[bool] = [False] - # Local vars - self._local_vars: List[str] = [] - # Schema func body and check cache - self._schema_build_cache: Dict[str, objpkg.RuntimeCode] = {} - # Lambda temp var index - self._lambda_temp_var_index = 0 - - # Base walker functions - - def generic_walk(self, t: ast.AST): - """Called if no explicit walker function exists for a node.""" - if not isinstance(t, ast.AST): - kcl_error.report_exception( - err_type=_COMPILE_ERROR, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=self.filename, - line_no=self.lineno, - col_no=self.colno, - ) - ], - arg_msg=CompilerInternalErrorMeta.INVALID_KCL_AST_MSG, - ) - if hasattr(t, _BODY_ATTR): - for n in t.body: - self.walk(n) - elif hasattr(t, _EXPRS_ATTR): - for n in t.exprs: - self.walk(n) - else: - self.walk(t) - - def update_line_column(self, t: ast.AST): - self.filename = t.filename or self.filename - self.lineno = t.get_line() if t.get_line() else self.lineno - self.colno = t.get_column() if t.get_column() else self.colno - - def expr_or_load_none(self, t: ast.Expr): - if t: - self.expr(t) - else: - self.load_constant(None) - - def stmt_or_load_none(self, t: ast.Stmt): - if t: - self.stmt(t) - else: - self.load_constant(None) - - def expr(self, t: ast.Expr): - if not t: - return - self.update_line_column(t) - self.walk(t) - - def stmt(self, t: ast.Stmt): - if not t: - return - self.update_line_column(t) - self.walk(t) - - def exprs(self, exprs: List[ast.Expr]): - if not exprs: - return - assert isinstance(exprs, list) - for expr in exprs: - self.expr(expr) - - def stmts(self, stmts: List[ast.Stmt]): - if not stmts: - return - assert isinstance(stmts, list) - for stmt in stmts: - self.stmt(stmt) - - # Util functions - - def get_node_name(self, t: ast.AST): - """Get the ast.AST node name""" - assert isinstance(t, ast.AST) - return t.type - - def raise_err(self, msg: str = ""): - """Raise a KCL compile error""" - msg = msg if msg else CompilerInternalErrorMeta.INVALID_KCL_AST_MSG - kcl_error.report_exception( - err_type=_COMPILE_ERROR, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=self.filename, - line_no=self.lineno, - col_no=self.colno, - ) - ], - arg_msg=msg, - ) - - # Emit functions - - def enter_scope(self): - """ - Enter scope such as internal of function and schema - """ - scope = vm.CompilationScope(instructions=[]) - self.scopes.append(scope) - self.symtable = SymbolTable.new(self.symtable, self.symtable.num_definitions) - - def leave_scope(self) -> List[int]: - """ - Leave scope - """ - if not self.scopes: - self.raise_err(CompilerInternalErrorMeta.INVALID_GLOBAL_IMPLICIT_SCOPE) - instructions = self.current_instruction() - self.scopes.pop() - self.symtable.outer.num_definitions = self.symtable.num_definitions - self.symtable = self.symtable.outer - return instructions # Return internal scope instructions - - def current_instruction(self) -> List[int]: - """Get the current instruction""" - return self.scopes[-1].instructions if self.scopes else [] - - def add_instruction(self, ins: List[int]) -> int: - """ - Add instructions into the current compile scope - """ - if not self.scopes: - self.raise_err(CompilerInternalErrorMeta.INVALID_GLOBAL_IMPLICIT_SCOPE) - pos = len(self.current_instruction()) - if not ins: - return pos - self.scopes[-1].instructions.extend( - ins + [(self.filename, self.lineno, self.colno)] - ) - return pos - - def add_constant(self, cst: objpkg.KCLObject) -> int: - """ - Add a KCLObject constant into the constant list - """ - self.constants.append(cst) - return len(self.constants) - - def add_name(self, name: str) -> int: - """ - Add a identifier string into the name list - """ - self.names.append(name) - return len(self.names) - - def change_operand(self, op: int, op_pos: int, operand: int): - """ - Change the operand in index 'op_pos' - """ - current_instruction = self.current_instruction() - if op_pos > len(current_instruction) + vm.InstructionWithArg.size() - 1: - self.raise_err(CompilerInternalErrorMeta.INVALID_OP_POS.format(op_pos)) - assert op == current_instruction[op_pos] - inst = vm.InstructionWithArg(op=vm.Opcode(op), lineno=self.lineno, arg=operand) - current_instruction[ - op_pos : op_pos + vm.InstructionWithArg.size() - ] = inst.output() - - def operand(self, operand1: int = 0, operand2: int = 0, operand3: int = 0): - """ - Build a total operand using operands - """ - assert 0 <= operand1 <= 255 and 0 <= operand2 <= 255 and 0 <= operand3 <= 255 - return operand1 + (operand2 << 8) + (operand3 << 16) - - def emit(self, op: vm.Opcode, operand: Optional[int] = None) -> int: - """ - Generate byte code and operand - - Parameters - --------- - op: operation code - operand: operand - """ - ins = ( - [op, (self.filename, self.lineno, self.colno)] - if operand is None - else [ - op, - (operand & 0xFF), - ((operand >> 8) & 0xFF), - ((operand >> 16) & 0xFF), - (self.filename, self.lineno, self.colno), - ] - ) - pos = len(self.scopes[-1].instructions) - self.scopes[-1].instructions.extend(ins) - return pos - - # Emit function object and call - - def make_func_with_content( - self, - content_func: Callable, - name: str, - args: ast.Arguments = None, - cached_name: str = None, - ): - if not content_func or not isinstance(content_func, Callable): - raise Exception(f"invalid function body {content_func}") - free_symbols = [] - argc = 0 - if args: - - def _check_defaults_legal(): - mark = False - for j, default in enumerate(reversed(args.defaults)): - if default is None: - mark = True - if default is not None and mark is True: - kcl_error.report_exception( - err_type=kcl_error.ErrType.IllegalArgumentError_Syntax_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=args.filename, - line_no=default.line, - col_no=args.args[len(args.defaults) - j - 1].column, - end_col_no=default.end_column, - arg_msg="A default argument", - ) - ], - arg_msg="non-default argument follows default argument", - ) - - CheckRules.check_list_len_equal( - [args.args, args.defaults, args.type_annotation_list] - ) - _check_defaults_legal() - arg_defaults = len([default for default in args.defaults if default]) - argc = self.operand(len(args.args), arg_defaults, 0) - for i, _ in enumerate(args.args): - self.load_constant(args.GetArgName(i)) - self.load_constant(args.GetArgType(i)) - self.load_constant(args.GetArgDefault(i)) - if cached_name and cached_name in self._schema_build_cache: - num_locals = 0 - count = self.add_constant(self._schema_build_cache[cached_name]) - else: - self.enter_scope() - if args: - for arg in args.args: - self.symtable.define(arg.get_name(), scope=SymbolScope.LOCAL) - self.add_name(arg.get_name()) - # self.expr(arg) - content_func(args) - free_symbols = self.symtable.free_symbols - instructions = self.leave_scope() - runtime_code = RuntimeCode( - codes=instructions, - names=self.names, - constants=self.constants, - ) - count = self.add_constant(runtime_code) - if cached_name and cached_name not in self._schema_build_cache: - self._schema_build_cache[cached_name] = runtime_code - num_locals = len(free_symbols) - if num_locals > 0: - for symbol in free_symbols: - self.emit(vm.Opcode.LOAD_CLOSURE, symbol.index) - self.emit(vm.Opcode.BUILD_LIST, num_locals) - # Load code - self.emit(vm.Opcode.LOAD_CONST, count - 1) - # Load function/closure name - self.load_constant(name) - self.emit( - vm.Opcode.MAKE_FUNCTION if num_locals == 0 else vm.Opcode.MAKE_CLOSURE, argc - ) - - def emit_call( - self, - args: List[ast.Expr], - keywords: List[ast.Keyword], - ): - self.exprs(args) - check_table = set() - for kw in keywords: - if kw in check_table: - self.raise_err(CompilerInternalErrorMeta.DUPLICATED_KW.format(kw.arg)) - check_table.add(kw) - self.load_constant(kw.arg.names[0]) - self.expr(kw.value) - op = vm.Opcode.CALL_FUNCTION - self.emit(op, len(args) + (len(keywords) << 8)) - - # Jump and label Instructions - - def set_jmp(self, op: vm.Opcode, label: vm.Label) -> int: - inst = None - if op in [ - vm.Opcode.JUMP_IF_FALSE_OR_POP, - vm.Opcode.JUMP_IF_TRUE_OR_POP, - vm.Opcode.JUMP_ABSOLUTE, - vm.Opcode.POP_JUMP_IF_FALSE, - vm.Opcode.POP_JUMP_IF_TRUE, - ]: - inst = vm.JumpAbs( - op=op, - dest=label, - filename=self.filename, - lineno=self.lineno, - colno=self.colno, - ) - elif op in [ - vm.Opcode.JUMP_FORWARD, - vm.Opcode.FOR_ITER, - ]: - inst = vm.JumpRel( - op=op, - dest=label, - filename=self.filename, - lineno=self.lineno, - colno=self.colno, - ) - else: - self.raise_err(CompilerInternalErrorMeta.INVALID_ARGED_OP_CODE.format(op)) - pos = self.add_instruction(inst.output()) - return pos - - def op_jmp(self, op: vm.Opcode, label: vm.Label): - pos = self.set_jmp(op, label) - label.number = op - label.pos = pos - - def op_label(self, label: vm.Label) -> int: - assert isinstance(label, vm.Label) - if label.number is not None: - self.change_operand( - label.number, label.pos, len(self.current_instruction()) - ) - return self.add_instruction(label.output()) - - def set_label(self, label: vm.Label): - assert isinstance(label, vm.Label) - label.pos = len(self.current_instruction()) - label.number = None - return self.add_instruction(label.output()) - - # Decorator - - def op_decorator( - self, - name: str, - key: str, - args: ast.CallExpr, - target: obj_internal.DecoratorTargetType, - ): - if not name: - kcl_error.report_exception( - err_type=_COMPILE_ERROR, - arg_msg="decorator name can't be None", - ) - decorator = objpkg.KCLDecoratorObject(name=name, target=target, key=key) - if args: - self.exprs(args.args) - check_table = set() - for kw in args.keywords: - if kw in check_table: - self.raise_err( - CompilerInternalErrorMeta.DUPLICATED_KW.format(kw.arg) - ) - check_table.add(kw) - self.load_constant(kw.arg.names[0]) - self.expr(kw.value) - n = self.operand(len(args.args), len(args.keywords)) - self.load_constant(decorator) - self.emit(vm.Opcode.MAKE_DECORATOR, n) - else: - self.load_constant(decorator) - self.emit(vm.Opcode.MAKE_DECORATOR, 0) - - # Symbol operations - - def store_symbol( - self, - name: str, - *, - scope: SymbolScope = None, - do_check: bool = True, - init_global_name: bool = False, - ) -> int: - symbol, exist = self.symtable.define(name, scope) - symbol.define_count = 0 if init_global_name else (symbol.define_count + 1) - if exist and do_check: - if symbol.define_count > 1: - # Variable name 'a' must be unique in package context - kcl_error.report_exception( - err_type=kcl_error.ErrType.ImmutableCompileError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=self.filename, - line_no=self.lineno, - col_no=self.colno, - ) - ], - ) - index = self.add_name(name) - 1 - if symbol.scope == SymbolScope.INTERNAL: - return index - op = SYMBOL_SCOPE_STORE_OP_MAPPING.get(symbol.scope) - if not op: - self.raise_err(CompilerInternalErrorMeta.INVALID_GLOBAL_IMPLICIT_SCOPE) - self.emit(op, index) - return index - - def load_symbol(self, name: str, emit: bool = True): - """ - Identifier symbol e.g., a, b, and c - """ - if not name: - self.raise_err(CompilerInternalErrorMeta.INVALID_NAME) - symbol = self.symtable.resolve(name) - if not symbol: - self.raise_err(CompilerInternalErrorMeta.SYMBOL_NOT_DEFINED.format(name)) - code = SYMBOL_SCOPE_LOAD_OP_MAPPING.get(symbol.scope) - if not code: - self.raise_err( - CompilerInternalErrorMeta.INVALID_SYMBOL_SCOPE.format(symbol.scope) - ) - if emit: - self.emit(code, symbol.index) - return symbol - - def op_name(self, op: vm.Opcode, name: str): - self.symtable.define(name, SymbolScope.INTERNAL) - index = self.add_name(name) - 1 - self.emit(op, index) - # Leave the inner attr scope, delete the variable from the symbol table. - self.symtable.delete(name, SymbolScope.INTERNAL) - - # Object constant operations - - def load_constant(self, value: Any): - """ - Runtime Literal constant e.g., 1, 1.1 and None - """ - obj = objpkg.to_kcl_obj(value) - count = self.add_constant(obj) - self.emit(vm.Opcode.LOAD_CONST, count - 1) - - def compile_program(self, prog: ast.Program) -> Optional[objpkg.KCLProgram]: - p = objpkg.KCLProgram( - root=prog.root, - main=prog.main, - ) - for pkgpath in prog.pkgs: - # Symbol table - self.symtable: SymbolTable = SymbolTable.new_with_built_in() - self.symtable.num_definitions = len(self.names) - # Compile scope level - self.scopes: list = [vm.CompilationScope(instructions=[])] - self.pkg_scope = self.program_scope.scope_map[pkgpath] - self.compile(pkgpath, prog.pkgs[pkgpath]) - p.pkgs[pkgpath] = objpkg.KCLBytecode( - names=self.names, - constants=self.constants, - instructions=self.current_instruction(), - ) - return p - - def compile(self, pkgpath: str, m_list: List[ast.Module]) -> Optional[RuntimeCode]: - assert pkgpath - assert m_list - self.pkgpath = pkgpath - - # Define global names - for m in m_list: - self.filename = m.filename - # Global schema and rule names - schema_rule_names = {n.name for n in m.GetSchemaAndRuleList()} - for name in m.global_names: - self.load_constant(Undefined) - self.store_symbol(name, init_global_name=True) - if name not in schema_rule_names: - self.symtable.delete(name, SymbolScope.GLOBAL) - - # Do import - for m in m_list: - self.filename = m.filename - for stmt in m.body: - if isinstance(stmt, ast.ImportStmt): - self.update_line_column(stmt) - import_spec = typing.cast(ast.ImportStmt, stmt) - self.load_constant(0) - self.load_constant(None) - - self.emit( - vm.Opcode.IMPORT_NAME, - self.store_symbol( - import_spec.path, - scope=SymbolScope.LOCAL, - init_global_name=True, - ), - ) - self.store_symbol( - f"@{import_spec.path}", - scope=SymbolScope.GLOBAL, - init_global_name=True, - ) - - # Define schema type - for m in m_list: - self.filename = m.filename - for stmt in m.body: - if isinstance(stmt, ast.SchemaStmt): - self.stmt(stmt) - elif isinstance(stmt, ast.RuleStmt): - self.stmt(stmt) - - # Define schema type twice - for m in m_list: - self.filename = m.filename - for stmt in m.body: - if isinstance(stmt, ast.SchemaStmt): - self.stmt(stmt) - elif isinstance(stmt, ast.RuleStmt): - self.stmt(stmt) - - # Exec stmt - for m in m_list: - self.filename = m.filename - for stmt in m.body: - self.stmt(stmt) - - -# ----------------------------------------------------------------------------- -# Compiler -# ----------------------------------------------------------------------------- - - -@dataclass -class Compiler(_CompilerBase): - """The Compiler class used to build code object, which will be - consumed by the virtual machine. - - It is mainly composed of code that traverses the tree, and - bytecode-related functions are defined in _ComplierBase. - """ - - def __init__(self, program_scope: ProgramScope, filename=""): - super().__init__(filename) - self.program_scope: ProgramScope = program_scope - self.pkg_scope = program_scope.scope_map[ast.Program.MAIN_PKGPATH] - - def get_type_from_identifier(self, t: ast.Identifier): - if not t or not isinstance(t, ast.Identifier): - return ANY_TYPE - tpe = parse_type_str(t.get_name()) - if not isinstance(tpe, objpkg.KCLNamedTypeObject): - return tpe - if len(t.names) == 1: - name = t.names[0] - if name in self.pkg_scope.elems: - return self.pkg_scope.elems[name].type - return ANY_TYPE - elif len(t.names) == 2: - pkgpath = t.pkgpath - name = t.names[1] - if pkgpath in self.pkg_scope.elems: - tpe = self.pkg_scope.elems[pkgpath].type - if ( - not tpe - or not isinstance(tpe, objpkg.KCLModuleTypeObject) - or tpe.pkgpath not in self.program_scope.scope_map - or name not in self.program_scope.scope_map[tpe.pkgpath].elems - ): - return ANY_TYPE - return self.program_scope.scope_map[tpe.pkgpath].elems[name].type - return ANY_TYPE - self.raise_err(msg="Invalid as keyword right identifier") - - # Walker functions - def walk_Module(self, t: ast.Module): - assert isinstance(t, ast.Module) - self.filename = t.filename - self.stmts(t.body) - - def walk_ExprStmt(self, t: ast.ExprStmt): - """ast.AST: ExprStmt""" - assert isinstance(t, ast.ExprStmt) - exprs = t.exprs - for expr in exprs: - # Ignore the doc string - if isinstance(expr, ast.StringLit): - continue - # Insert nop op before the expr statement - if self._is_in_schema_stmt[-1] and not self._is_in_if_stmt[-1]: - self.emit(vm.Opcode.SCHEMA_NOP) - self.expr(expr) - # Lambda expression temp variable - if self._is_in_lambda_expr[-1]: - self.store_symbol(f"@{self._lambda_temp_var_index}") - self._lambda_temp_var_index += 1 - # Store lambda expr variable and pop the stored value - self.emit(vm.Opcode.POP_TOP) - # If it is a literal and pop it from the stack except in the lambda expression - elif isinstance(expr, LITERAL_EXPRS) or isinstance(expr, ast.CallExpr): - self.emit(vm.Opcode.POP_TOP) - elif isinstance(expr, ast.SchemaExpr): - self.emit(vm.Opcode.EMIT_EXPR) - # Insert nop op after the expr statement - if self._is_in_schema_stmt[-1] and not self._is_in_if_stmt[-1]: - self.emit(vm.Opcode.SCHEMA_NOP) - - def walk_AssertStmt(self, t: ast.AssertStmt): - """ast.AST: AssertStmt - - Parameters - ---------- - test: Optional[Expr] - if_cond: Optional[Expr] - msg: Optional[Expr] - """ - assert isinstance(t, ast.AssertStmt) and t.test - - label_if_cond = vm.Label() - - if t.if_cond: - self.expr(t.if_cond) - self.op_jmp(vm.Opcode.POP_JUMP_IF_FALSE, label_if_cond) - - self.expr(t.test) - label = vm.Label() - self.op_jmp(vm.Opcode.POP_JUMP_IF_TRUE, label) - self.expr_or_load_none(t.msg) - self.emit(vm.Opcode.RAISE_VARARGS, 1) - self.op_label(label) - - if t.if_cond: - self.op_label(label_if_cond) - - def walk_IfStmt(self, t: ast.IfStmt): - """ast.AST: IfStmt - - Parameters - ---------- - - cond: Expr - - body: List[Stmt] - - elif_cond: List[Expr] - - elif_body: List[List[Stmt]] - - else_body: List[Stmt] - - Instructions: - ------------ - - vm.Opcode.POP_JUMP_IF_FALSE {body} - - """ - assert isinstance(t, ast.IfStmt) - assert t.cond - assert t.body - self.expr(t.cond) - self._is_in_if_stmt.append(True) - jump_if_false_label = vm.Label() - jump_last_labels = [vm.Label()] - # If condition - self.op_jmp(vm.Opcode.POP_JUMP_IF_FALSE, jump_if_false_label) - self.stmts(t.body) - self.op_jmp(vm.Opcode.JUMP_FORWARD, jump_last_labels[0]) - self.op_label(jump_if_false_label) - # Elif list - for elif_cond, elif_body in zip(t.elif_cond, t.elif_body): - self.expr(elif_cond) - jump_elif_false_label = vm.Label() - self.op_jmp(vm.Opcode.POP_JUMP_IF_FALSE, jump_elif_false_label) - self.stmts(elif_body) - jump_last_label = vm.Label() - self.op_jmp(vm.Opcode.JUMP_FORWARD, jump_last_label) - jump_last_labels.append(jump_last_label) - self.op_label(jump_elif_false_label) - self.stmts(t.else_body) - # After else - for label in jump_last_labels: - self.op_label(label) - self._is_in_if_stmt.pop() - if self._is_in_schema_stmt[-1]: - self.emit(vm.Opcode.SCHEMA_NOP) - - def walk_ImportStmt(self, t: ast.ImportStmt): - """ast.AST: ImportStmt - - Parameters - --------- - - path: str - - name: str - - asname: str - - Instructions - ------ - - vm.Opcode.IMPORT_NAME {symbol_index} 0 0 - - StackLayout - ----------- - TOS - - asname - - name - """ - assert isinstance(t, ast.ImportStmt) - assert t.pkg_name - - import_spec = typing.cast(ast.ImportStmt, t) - self.load_constant(0) - self.load_constant(None) - if self.pkgpath == "__main__": - self.emit( - vm.Opcode.IMPORT_NAME, - self.store_symbol( - import_spec.path, - scope=SymbolScope.LOCAL, - init_global_name=True, - ), - ) - self.store_symbol( - import_spec.pkg_name, - scope=SymbolScope.LOCAL, - init_global_name=True, - ) - else: - self.emit( - vm.Opcode.IMPORT_NAME, - self.store_symbol( - import_spec.path, - scope=SymbolScope.GLOBAL, - init_global_name=True, - ), - ) - self.store_symbol( - import_spec.pkg_name, - scope=SymbolScope.GLOBAL, - init_global_name=True, - ) - - def walk_RuleStmt(self, t: ast.RuleStmt): - """ast.AST: RuleStmt - - Parameters - ---------- - - doc: str = "" - - name: str = "" - - parent_rules: List[Identifier] = [] - - decorators: List[Decorator] = [] - - checks: List[CheckExpr] = [] - - name_node: Optional[Name] = None - - args: Optional[Arguments] = None - - for_host_name: Optional[Identifier] = None - - Stack Layout - ------------ - TOS - - 6. index signature - - 5. decorator list - - 4. check func - - 3. schema_body_func - - 2. mixin type object list - - 1. parent_type_obj - - 0. self type object - BOS - """ - assert isinstance(t, ast.RuleStmt) - assert self.pkgpath - # The schema type object - schema_type_obj = self.pkg_scope.elems.get(t.name).type.schema_type - - def schema_body_func(args: ast.Arguments): - # Store magic variables including config, config_meta and schema self pointer - magic_argument_list = [ - objpkg.SCHEMA_SELF_VALUE_KEY, - objpkg.SCHEMA_CONFIG_VALUE_KEY, - objpkg.SCHEMA_CONFIG_META_KEY, - ] - for key in magic_argument_list: - self.store_symbol(key) - self.emit(vm.Opcode.POP_TOP) - self.emit(vm.Opcode.SCHEMA_NOP) - # Pop frame and return the schema object - self.emit(vm.Opcode.RETURN_VALUE) - - def schema_check_func(_args: ast.Arguments): - # Store magic variables including config, config_meta and schema self pointer - magic_argument_list = [ - objpkg.SCHEMA_SELF_VALUE_KEY, - objpkg.SCHEMA_CONFIG_VALUE_KEY, - objpkg.SCHEMA_CONFIG_META_KEY, - ] - - for key in magic_argument_list: - self.store_symbol(key) - self.emit(vm.Opcode.POP_TOP) - - for check in t.checks or []: - self.expr(check) - - self.emit(vm.Opcode.RETURN_VALUE) - - schema_type_obj.attr_obj_map = {} - schema_type_obj.node_ref = None - self.load_constant(schema_type_obj) - # Rule statement has no schema parent name - self.load_constant(None) - # Parent rules - for rule in t.parent_rules or []: - rule_names = rule.names - if rule.pkgpath: - rule_names[0] = f"@{rule.pkgpath}" - self.load_constant(".".join(rule_names)) - rule_count = len(t.parent_rules) if t.parent_rules else 0 - # In schema level push - self._is_in_schema_stmt.append(True) - # Rule statement has not body func - # Schema body function including schema args, attribute context - self.make_func_with_content( - schema_body_func, - t.name, - t.args, - cached_name=schema_type_obj.runtime_type + "body", - ) - # Rule check expressions - if t.checks: - self.make_func_with_content( - schema_check_func, - t.name, - cached_name=schema_type_obj.runtime_type + "check", - ) - else: - self.load_constant(None) - - # Decorators - for decorator in t.decorators or []: - self.op_decorator( - decorator.name.get_name(), - t.name, - decorator.args, - obj_internal.DecoratorTargetType.SCHEMA_TYPE, - ) - decorator_count = len(t.decorators) if t.decorators else 0 - # Rule statement has no index signature - self.load_constant(None) - self.emit( - vm.Opcode.MAKE_SCHEMA, - self.operand(decorator_count, rule_count, 0), - ) - # Store the schema type object to the schema name symbol - self.store_symbol(t.name, init_global_name=True) - # In schema level pop - self._is_in_schema_stmt.pop() - - def walk_SchemaStmt(self, t: ast.SchemaStmt): - """ast.AST: SchemaStmt - - Parameters - ---------- - - doc: str - - name: str - - parent_name: Identifier - - is_mixin: bool - - args: Arguments - - settings: dict - - mixins: List[str] - - body: List[Union[SchemaAttr, Stmt]] - - decorators: List[Decorator] - - checks: List[CheckExpr] - - Stack Layout - ------------ - TOS - - 6. index signature - - 5. decorator list - - 4. check func - - 3. schema_body_func - - 2. mixin type object list - - 1. parent_type_obj - - 0. self type object - BOS - - vm.Opcode - ------ - {vm.Opcode.MAKE_SCHEMA} {decorator count} {mixin count} {attr count} -> SchemaTypeObject - """ - assert isinstance(t, ast.SchemaStmt) - assert self.pkgpath - # The schema type object - schema_type_obj = self.pkg_scope.elems.get(t.name).type.schema_type - - def schema_body_func(args: ast.Arguments): - # Store magic variables including config, config_meta and schema self pointer - magic_argument_list = [ - objpkg.SCHEMA_SELF_VALUE_KEY, - objpkg.SCHEMA_CONFIG_VALUE_KEY, - objpkg.SCHEMA_CONFIG_META_KEY, - ] - - for key in magic_argument_list: - self.store_symbol(key) - self.emit(vm.Opcode.POP_TOP) - - self.emit(vm.Opcode.SCHEMA_NOP) - # Emit schema context body including schema attribute declaration and expression - self.stmts(t.body) - self.emit(vm.Opcode.SCHEMA_NOP) - # Pop frame and return the schema object - self.emit(vm.Opcode.RETURN_VALUE) - - def schema_check_func(_args: ast.Arguments): - # Store magic variables including config, config_meta and schema self pointer - magic_argument_list = [ - objpkg.SCHEMA_SELF_VALUE_KEY, - objpkg.SCHEMA_CONFIG_VALUE_KEY, - objpkg.SCHEMA_CONFIG_META_KEY, - ] - - for key in magic_argument_list: - self.store_symbol(key) - self.emit(vm.Opcode.POP_TOP) - - for check in t.checks or []: - self.expr(check) - - self.emit(vm.Opcode.RETURN_VALUE) - - schema_type_obj.attr_obj_map = {} - schema_type_obj.node_ref = None - # Get the parent type obj of the schema if exist - self.load_constant(schema_type_obj) - self.expr_or_load_none(t.parent_name) - parent_name_str = t.parent_name.get_name() if t.parent_name else "" - if parent_name_str.endswith("Mixin"): - kcl_error.report_exception( - err_type=kcl_error.ErrType.IllegalInheritError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=self.filename, - line_no=t.line, - col_no=t.column, - end_col_no=t.end_column, - ) - ], - arg_msg=f"mixin inheritance {parent_name_str} is prohibited", - ) - - # Mixins - for mixin in t.mixins or []: - mixin_names = mixin.names - if mixin.pkgpath: - mixin_names[0] = f"@{mixin.pkgpath}" - - if not mixin_names[-1].endswith("Mixin"): - kcl_error.report_exception( - err_type=kcl_error.ErrType.MixinNamingError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=self.filename, - line_no=mixin.line, - col_no=mixin.column, - end_col_no=mixin.end_column, - ) - ], - arg_msg=f"a valid mixin name should end with 'Mixin', got '{mixin_names[-1]}'", - ) - - self.load_constant(".".join(mixin_names)) - mixin_count = len(t.mixins) if t.mixins else 0 - - # In schema level push - self._is_in_schema_stmt.append(True) - - # Schema body function including schema args, attribute context - self.make_func_with_content( - schema_body_func, - t.name, - t.args, - cached_name=schema_type_obj.runtime_type + "body", - ) - - # Schema check function - if t.checks: - self.make_func_with_content( - schema_check_func, - t.name, - cached_name=schema_type_obj.runtime_type + "check", - ) - else: - self.load_constant(None) - - # Decorators - for decorator in t.decorators or []: - self.op_decorator( - decorator.name.get_name(), - t.name, - decorator.args, - obj_internal.DecoratorTargetType.SCHEMA_TYPE, - ) - decorator_count = len(t.decorators) if t.decorators else 0 - # Index signature - self.stmt_or_load_none(t.index_signature) - self.emit( - vm.Opcode.MAKE_SCHEMA, - self.operand(decorator_count, mixin_count, 0), - ) - # Store the schema type object to the schema name symbol - self.store_symbol(t.name, init_global_name=True) - # In schema level pop - self._is_in_schema_stmt.pop() - - def walk_SchemaAttr(self, t: ast.SchemaAttr): - """ast.AST: SchemaAttr - - Parameters - ---------- - - doc: str - - name: str - - type_str: str - - is_optional: bool - - value: Expr - - decorators: List[Decorator] - - op: Union[AugOp, Assign] - - StackLayout - ----------- - TOS - - decorators - - types - - attr_name - - default - - is_optional - - op: vm.Opcode. - """ - self._local_vars = [] - self.load_constant(ARG_OP_MAPPING.get(t.op)) - # Optional - self.load_constant(bool(t.is_optional)) - # Final - self.load_constant(False) - # Has default - self.load_constant(bool(t.value)) - # Default value - self.expr_or_load_none(t.value) - # Attr name - self.load_constant(t.name) - # Attr type - self.load_constant(t.type_str) - # Decorators - for decorator in t.decorators or []: - self.op_decorator( - decorator.name.get_name(), - t.name, - decorator.args, - obj_internal.DecoratorTargetType.ATTRIBUTE, - ) - self.emit(vm.Opcode.SCHEMA_ATTR, len(t.decorators)) - self.emit(vm.Opcode.SCHEMA_NOP) - - def walk_SchemaIndexSignature(self, t: ast.SchemaIndexSignature): - """ast.AST: SchemaIndexSignature - - Parameters - ---------- - - key_name: Optional[str] = None - - key_type: Optional[str] = "str" - - value_type: Optional[str] = "" - - value: Optional[Expr] = None - - any_other: bool = False - """ - assert isinstance(t, ast.SchemaIndexSignature) - if not t.key_type or t.key_type not in ["str", "float", "int"]: - kcl_error.report_exception( - err_type=kcl_error.ErrType.IndexSignatureError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=self.filename, - line_no=t.get_line(), - col_no=t.get_column(), - end_col_no=t.get_end_column(), - ) - ], - arg_msg='the index signature parameter type must be "str", "int" or "float"', - ) - self.expr_or_load_none(t.value) - self.load_constant(t.any_other) - self.load_constant(t.key_name) - self.load_constant(t.value_type) - self.load_constant(t.key_type) - - def walk_IfExpr(self, t: ast.IfExpr): - """ast.AST: IfExpr - - Parameters - ---------- - - cond: Expr - - body: Expr - - orelse: Expr - """ - assert isinstance(t, ast.IfExpr) - self.expr(t.cond) - jump_if_false_label = vm.Label() - self.op_jmp(vm.Opcode.POP_JUMP_IF_FALSE, jump_if_false_label) - self.expr(t.body) - jump_last_label = vm.Label() - self.op_jmp(vm.Opcode.JUMP_FORWARD, jump_last_label) - self.op_label(jump_if_false_label) - self.expr(t.orelse) - self.op_label(jump_last_label) - - def walk_UnaryExpr(self, t: ast.UnaryExpr): - """ast.AST: UnaryExpr(Expr) - - Parameters - ---------- - - op: UnaryOp - - operand: Expr - """ - assert isinstance(t, ast.UnaryExpr) - opcode = UNARY_OP_MAPPING.get(t.op) - if not opcode: - self.raise_err(CompilerInternalErrorMeta.UNKNOWN_UNARYOP.format(t.op)) - self.expr(t.operand) - self.emit(opcode) - - def walk_BinaryExpr(self, t: ast.BinaryExpr): - """ast.AST: BinaryExpr - - Parameters - ---------- - - left: Expr - - right: Expr - - op: BinaryOperator - - StackLayout - ----------- - TOS - - right - - left - """ - assert isinstance(t, ast.BinaryExpr) and t.left and t.right and t.op - op = BIN_OP_MAPPING.get(t.op) - if not op: - self.raise_err(CompilerInternalErrorMeta.UNKNOWN_BINOP.format(t.op)) - if op == vm.Opcode.BINARY_LOGIC_AND or op == vm.Opcode.BINARY_LOGIC_OR: - # LogicExpr - op = ( - vm.Opcode.JUMP_IF_FALSE_OR_POP - if op == vm.Opcode.BINARY_LOGIC_AND - else vm.Opcode.JUMP_IF_TRUE_OR_POP - ) - values = [t.left, t.right] - label = vm.Label() - for i, e in enumerate(values): - self.expr(e) - if i != len(values) - 1: - self.op_jmp(op, label) - self.op_label(label) - else: - # BinaryExpr - self.expr(t.left) - if op == vm.Opcode.MEMBER_SHIP_AS: - type_object = self.get_type_from_identifier(t.right) - self.load_constant(type_object) - else: - self.expr(t.right) - # Update the op filename/line/column meta - self.update_line_column(t) - self.emit(op) - - def walk_SelectorExpr(self, t: ast.SelectorExpr): - """ast.AST: SelectorExpr - - Parameters - ---------- - - value: Expr - - attr: Identifier - - ctx: ExprContext - - has_question: bool - """ - assert isinstance(t, ast.SelectorExpr) - jump_if_false_label = vm.Label() - if t.has_question: - self.expr(t.value) # value is the condition - self.op_jmp(vm.Opcode.POP_JUMP_IF_FALSE, jump_if_false_label) - - if t.ctx != ast.ExprContext.AUGSTORE: - self.expr(t.value) - op = EXPR_OP_MAPPING.get(t.ctx) - if not op: - self.raise_err( - CompilerInternalErrorMeta.INVALID_PARAM_IN_ATTR.format(t.ctx) - ) - if t.ctx == ast.ExprContext.AUGLOAD: - self.emit(vm.Opcode.DUP_TOP) - elif t.ctx == ast.ExprContext.AUGSTORE: - self.emit(vm.Opcode.ROT_TWO) - - self.op_name(op, t.attr.get_name()) - - if t.has_question: - jump_last_label = vm.Label() - self.op_jmp(vm.Opcode.JUMP_FORWARD, jump_last_label) - self.op_label(jump_if_false_label) - self.load_constant(None) - self.op_label(jump_last_label) - - def walk_CallExpr(self, t: ast.CallExpr): - """ast.AST: CallExpr - - Parameters - ---------- - - func: Expr - - args: List[Expr] - - keywords: List[Keyword] - """ - assert isinstance(t, ast.CallExpr) - self.expr(t.func) - self.emit_call(t.args, t.keywords) - - def walk_Subscript(self, t: ast.Subscript): - """ast.AST: Subscript - - Parameters - ---------- - - value: Expr - - index: Expr - - lower: Expr - - upper: Expr - - step: Expr - - has_question: bool - """ - assert isinstance(t, ast.Subscript) - jump_if_false_label = vm.Label() - if t.has_question: - self.expr(t.value) # value is the condition - self.op_jmp(vm.Opcode.POP_JUMP_IF_FALSE, jump_if_false_label) - - if t.ctx != ast.ExprContext.AUGSTORE: - self.expr(t.value) - if t.index: - self.expr(t.index) - else: - n = 2 - for expr in [t.lower, t.upper]: - self.expr_or_load_none(expr) - if t.step: - n += 1 - self.expr(t.step) - self.emit(vm.Opcode.BUILD_SLICE, n) - opcodes = SUBSCR_OP_MAPPING.get(t.ctx) - if not opcodes: - self.raise_err( - CompilerInternalErrorMeta.INVALID_PARAM_IN_SUBSCR.format(t.ctx) - ) - for op in opcodes: - self.emit(op) - - if t.has_question: - jump_last_label = vm.Label() - self.op_jmp(vm.Opcode.JUMP_FORWARD, jump_last_label) - self.op_label(jump_if_false_label) - self.load_constant(None) - self.op_label(jump_last_label) - - def walk_ParenExpr(self, t: ast.ParenExpr): - """ast.AST: ParenExpr - - Parameters - ---------- - - expr: Expr - """ - assert isinstance(t, ast.ParenExpr) - self.expr(t.expr) - - def walk_QuantExpr(self, t: ast.QuantExpr): - """ast.AST: QuantExpr - - Parameters - ---------- - - target: Expr - - variables: List[Identifier] - - op: QuantOperation - - test: Optional[Expr] - - if_cond: Optional[Expr] - - ctx: ExprContext - - Notes - ----- - For different quantifier operations, results are different - any/all: bool - map: list - filter: list/dict/schema - """ - assert isinstance(t, ast.QuantExpr) - - # Quantifier expression initial result - if t.op in [ast.QuantOperation.ALL, ast.QuantOperation.ANY]: - self.load_constant(t.op == ast.QuantOperation.ALL) - elif t.op == ast.QuantOperation.MAP: - self.emit(vm.Opcode.BUILD_LIST, 0) - elif t.op == ast.QuantOperation.FILTER: - self.expr(t.target) - else: - self.raise_err(CompilerInternalErrorMeta.INVALID_QUANTIFIER_OP.format(t.op)) - - # Jump labels - start = vm.Label() - end_for = vm.Label() - all_any_end = vm.Label() - - # Copy collection value to be filtered - if t.op == ast.QuantOperation.FILTER: - self.emit(vm.Opcode.COPY_TOP) - self.emit(vm.Opcode.ROT_TWO) - self.emit(vm.Opcode.POP_TOP) - - # Iter the loop target - self.expr(t.target) - self.emit(vm.Opcode.GET_ITER, len(t.variables)) - - # Mark the beginning of for-loop - self.set_label(start) - # Declare iter and the mapping end of iter - self.op_jmp(vm.Opcode.FOR_ITER, end_for) - - # Push loop variables, such as filter k, v in data:' - key_name = None - val_name = None - for i, v in enumerate(t.variables): - name = v.get_name(False) - key_name = name if i == 0 else key_name - val_name = name if i == 1 else val_name - self.update_line_column(v) - self.store_symbol(name, scope=SymbolScope.LOCAL) - self._local_vars.append(name) - # POP the temp var_key variable - self.emit(vm.Opcode.POP_TOP) - - # QuantExpr inner or_test [IF or_test] - label_if_cond = vm.Label() - # Expression filter jump condition - if t.if_cond: - self.expr(t.if_cond) - self.op_jmp(vm.Opcode.POP_JUMP_IF_FALSE, label_if_cond) - - # Loop body if exist - if t.test: - self.expr(t.test) - if t.op in [ast.QuantOperation.ALL, ast.QuantOperation.ANY]: - self.op_jmp( - vm.Opcode.POP_JUMP_IF_FALSE - if t.op == ast.QuantOperation.ALL - else vm.Opcode.POP_JUMP_IF_TRUE, - all_any_end, - ) - elif t.op == ast.QuantOperation.MAP: - # Operand 2 denote the distance of the list to be mapped and TOS - self.emit(vm.Opcode.LIST_APPEND, 2) - elif t.op == ast.QuantOperation.FILTER: - filter_label = vm.Label() - self.op_jmp(vm.Opcode.POP_JUMP_IF_TRUE, filter_label) - # Copy the list/dict/schema loop variable - self.load_symbol(key_name) - if val_name: - self.load_symbol(val_name) - self.load_constant(True) - else: - self.load_constant(None) - self.load_constant(False) - # Operand 3 denote the distance of the list to be filtered and TOS - self.emit(vm.Opcode.DELETE_ITEM, 5) - self.op_label(filter_label) - - # Expression filter jump label - if t.if_cond: - self.op_label(label_if_cond) - # To next cycle - self.set_jmp(vm.Opcode.JUMP_ABSOLUTE, start) # Mark start - # Mark for-loop else constant - if t.op in [ast.QuantOperation.ALL, ast.QuantOperation.ANY]: - self.op_label(all_any_end) - self.emit(vm.Opcode.POP_TOP) - # Pop the initial value of the empty all/any value - self.emit(vm.Opcode.POP_TOP) - self.load_constant(t.op == ast.QuantOperation.ANY) - # Mark the end of for-loop - self.op_label(end_for) - - # Delete temp loop variables - for v in t.variables: - name = v.get_name(False) - self.symtable.delete(name, SymbolScope.LOCAL) - self._local_vars = [] - - def walk_ListExpr(self, t: ast.ListExpr): - """ast.AST: ListExpr - - Parameters - ---------- - - elts: List[Expr] - """ - assert isinstance(t, ast.ListExpr) - self.exprs(t.elts) - self.emit(vm.Opcode.BUILD_LIST, len(t.elts)) - - def walk_ListIfItemExpr(self, t: ast.ListIfItemExpr): - """ast.AST: ListIfItemExpr - - Parameters - ---------- - if_cond: Optional[Expr] = None - exprs: List[Expr] = [] - orelse: Optional[Expr] = None - - if condition item1 elif item2 else item3 - """ - assert isinstance(t, ast.ListIfItemExpr) - self.expr(t.if_cond) - jump_if_false_label = vm.Label() - jump_last_label = vm.Label() - self.op_jmp(vm.Opcode.POP_JUMP_IF_FALSE, jump_if_false_label) - self.exprs(t.exprs) - self.emit(vm.Opcode.BUILD_LIST, len(t.exprs)) - self.emit(vm.Opcode.UNPACK_SEQUENCE, 1) - self.op_jmp(vm.Opcode.JUMP_FORWARD, jump_last_label) - self.op_label(jump_if_false_label) - if t.orelse: - # Add the orelse item into the list - self.expr(t.orelse) - else: - # *None denotes do not add None into the list - self.load_constant(None) - self.emit(vm.Opcode.UNPACK_SEQUENCE, 1) - if t.orelse and not isinstance(t.orelse, ast.ListIfItemExpr): - self.emit(vm.Opcode.UNPACK_SEQUENCE, 1) - self.op_label(jump_last_label) - - def walk_ConfigExpr(self, t: ast.ConfigExpr): - """ast.AST: ConfigExpr - - Parameters - ---------- - - items: List[ConfigEntry] - """ - assert isinstance(t, ast.ConfigExpr) - self.op_config_data(t) - - def walk_ConfigIfEntryExpr(self, t: ast.ConfigIfEntryExpr): - """ast.AST: ConfigIfEntryExpr - - Parameters - ---------- - if_cond: Optional[Expr] = None - keys: List[Expr] = [] - values: List[Expr] = [] - operations: List[Expr] = [] - orelse: Optional[Expr] - - if condition: key: value -> **({key: value} if condition else self.expr(orelse)) - """ - assert isinstance(t, ast.ConfigIfEntryExpr) - self.expr(t.if_cond) - jump_if_false_label = vm.Label() - self.op_jmp(vm.Opcode.POP_JUMP_IF_FALSE, jump_if_false_label) - self.op_config_data_entries(t.keys, t.values, t.operations) - jump_last_label = vm.Label() - self.op_jmp(vm.Opcode.JUMP_FORWARD, jump_last_label) - self.op_label(jump_if_false_label) - self.expr_or_load_none(t.orelse) - self.op_label(jump_last_label) - - def walk_StarredExpr(self, t: ast.StarredExpr): - assert isinstance(t, ast.StarredExpr) and t.value - self.expr(t.value) - self.emit(vm.Opcode.UNPACK_SEQUENCE, 1) - - def comp_generator( - self, - generators: List[ast.CompClause], - gen_index: int, - elt: ast.Expr, - val: Optional[ast.Expr], - op: ast.ConfigEntryOperation, - node: Union[ast.ListComp, ast.DictComp], - ): - start = vm.Label() - end_for = vm.Label() - gen = generators[gen_index] - - variable_count = len(gen.targets) - assert 0 < variable_count <= 2 - - self.expr(gen.iter) - self.emit(vm.Opcode.GET_ITER, variable_count) - - self.set_label(start) - # Declare iter and the mapping end of iter - self.op_jmp(vm.Opcode.FOR_ITER, end_for) - # Push target, such as i in 'for i in [1,2]' - for target in gen.targets: - target_name = target.get_name(False) - self.update_line_column(target) - self.store_symbol( - target_name, scope=SymbolScope.LOCAL - ) # Target in for_comp is a local variable - self._local_vars.append(target_name) - self.emit(vm.Opcode.POP_TOP) # POP the temp target variable - - for e in gen.ifs: - self.expr(e) - self.set_jmp(vm.Opcode.POP_JUMP_IF_FALSE, start) - - gen_index += 1 - if gen_index >= len(generators): - if isinstance(node, ast.ListComp): - self.expr(elt) - self.emit(vm.Opcode.LIST_APPEND, int(gen_index + 1)) - elif isinstance(node, ast.DictComp): - self.expr(val) - self.expr(elt) - self.load_constant(op) - self.emit(vm.Opcode.MAP_ADD, int(gen_index + 1)) - else: - self.raise_err(CompilerInternalErrorMeta.UNKNOWN_COMP.format(node)) - else: - self.comp_generator(generators, gen_index, elt, val, op, node) - # To next cycle - self.set_jmp(vm.Opcode.JUMP_ABSOLUTE, start) # Mark start - # Mark the end of for-loop - self.op_label(end_for) - for target in gen.targets: - target_name = target.get_name(False) - self.symtable.delete(target_name, SymbolScope.LOCAL) - self._local_vars = [] - - def walk_ListComp(self, t: ast.ListComp): - """ast.AST: ListComp - - Parameters - ---------- - - elt: Expr - - generators: List[CompClause] - - targets: List[Expr] - - iter: Expr - - ifs: List[Expr] - """ - assert isinstance(t, ast.ListComp) - self.emit(vm.Opcode.BUILD_LIST, 0) - self.comp_generator(t.generators, 0, t.elt, None, None, t) - - def walk_DictComp(self, t: ast.DictComp): - """ast.AST: DictComp - - Parameters - ---------- - - key: Expr - - value: Expr - - generators: List[CompClause] - """ - assert isinstance(t, ast.DictComp) - self.emit(vm.Opcode.BUILD_MAP, 0) - self.comp_generator(t.generators, 0, t.key, t.value, t.operation, t) - - def get_schema_conf_meta( - self, - n: typing.Optional[ast.Identifier], - t: ast.ConfigExpr, - ): - """Print the schema conf meta""" - conf_meta = {} - if n: - conf_meta[SchemaConfigMeta.FILENAME] = self.filename - conf_meta[SchemaConfigMeta.LINE] = n.line - conf_meta[SchemaConfigMeta.COLUMN] = n.column - if isinstance(t, ast.ConfigExpr): - for k, v in zip(t.keys, t.values): - if not k: - # Double star unpack expression - continue - if isinstance(k, ast.Identifier): - name = k.get_first_name() - elif isinstance(k, ast.Literal): - name = str(k.value) - else: - name = str(k) - conf_meta[name] = { - "lineno": k.get_line(), - "columnno": k.get_column(), - "filename": k.filename or self.filename, - "$conf_meta": self.get_schema_conf_meta(None, v), - } - return conf_meta - - def op_config_data_entries( - self, keys: List[ast.Expr], values: List[ast.Expr], operations: List[int] - ): - self.emit(vm.Opcode.BUILD_SCHEMA_CONFIG) - for key, value, operation in zip(keys, values, operations): - insert_index_node = None - is_nest_key = False - if key is None: - self.load_constant(None) - self.expr(value) - self.emit(vm.Opcode.UNPACK_SEQUENCE, 2) - else: - if isinstance(key, ast.Subscript): - if isinstance(key.value, ast.Identifier) and isinstance( - key.index, ast.NumberLit - ): - insert_index_node = key.index - key = key.value - if isinstance(key, ast.Identifier): - if len(key.names) == 1: - name = key.get_name(False) - if name in self._local_vars: - self.expr(key) - else: - self.load_constant(name) - else: - is_nest_key = True - self.load_constant(key.get_name()) - else: - self.expr(key) - self.expr(value) - self.load_constant(is_nest_key) - self.load_constant(operation) - self.expr_or_load_none(insert_index_node) - self.emit(vm.Opcode.STORE_SCHEMA_CONFIG) - - def op_config_data(self, t: ast.ConfigExpr): - assert isinstance(t, ast.ConfigExpr) - self.op_config_data_entries(t.keys, t.values, t.operations) - - def walk_SchemaExpr(self, t: ast.SchemaExpr): - """ast.AST: SchemaExpr - - Parameters - ---------- - - name: Identifier - - config: ConfigExpr - - schema_args: Arguments - """ - assert isinstance(t, ast.SchemaExpr) - # Schema Config data features: 1. Omitted quotes; 2. Nest_key - config_meta = self.get_schema_conf_meta(t.name, t.config) - self.exprs(t.args) - check_table = set() - for kw in t.kwargs: - if kw in check_table: - self.raise_err(CompilerInternalErrorMeta.DUPLICATED_KW.format(kw.arg)) - check_table.add(kw) - self.load_constant(kw.arg.names[0]) - self.expr(kw.value) - self.load_constant(config_meta) - self._is_in_schema_exprs.append(True) - self.expr(t.config) - self.expr(t.name) - n = len(t.args) + (len(t.kwargs) << 8) - self.emit(vm.Opcode.BUILD_SCHEMA, n) - self._is_in_schema_exprs.pop() - - def walk_CheckExpr(self, t: ast.CheckExpr): - """ast.AST: CheckExpr - - Parameters - ---------- - - test: Expr - - if_cond: Expr - - msg: Expr - """ - assert isinstance(t, ast.CheckExpr) and t.test - - label_if_cond = vm.Label() - - if t.if_cond: - self.expr(t.if_cond) - self.op_jmp(vm.Opcode.POP_JUMP_IF_FALSE, label_if_cond) - - self.expr(t.test) - label = vm.Label() - self.op_jmp(vm.Opcode.POP_JUMP_IF_TRUE, label) - self.expr_or_load_none(t.msg) - self.emit(vm.Opcode.RAISE_CHECK, 1) - self.op_label(label) - - if t.if_cond: - self.op_label(label_if_cond) - - def walk_LambdaExpr(self, t: ast.LambdaExpr): - """ast.AST: LambdaExpr - - Parameters - ---------- - - args: Optional[Arguments] - - return_type_str: Optional[str] - - return_type_node: Optional[Type] - - body: List[Stmt] - """ - - def lambda_body_func(args: ast.Arguments): - # Emit lambda function body - self.stmts(t.body) - # Pop frame and return the schema object - self.emit(vm.Opcode.RETURN_LAST_VALUE) - - self._is_in_lambda_expr.append(True) - self.make_func_with_content( - lambda_body_func, - LAMBDA_FUNC_NAME, - t.args, - ) - self._is_in_lambda_expr.pop() - - def walk_Compare(self, t: ast.Compare): - assert isinstance(t, ast.Compare) - if len(t.ops) == 0: - self.raise_err(CompilerInternalErrorMeta.NO_OPS_OR_CMPS) - if len(t.ops) != len(t.comparators): - self.raise_err(CompilerInternalErrorMeta.UNEQUAL_OPS_AND_CMPS) - self.expr(t.left) - labels = [] - for i in range(len(t.ops)): - has_next = i < (len(t.ops) - 1) - self.expr(t.comparators[i]) - if has_next: - # Duplicates the reference on top of the stack. - self.emit(vm.Opcode.DUP_TOP) - # Lifts second and third stack item one position up, moves top down to position three. - self.emit(vm.Opcode.ROT_THREE) - else: - self.emit(vm.Opcode.ROT_TWO) - if CMP_OP_MAPPING.get(t.ops[i]): - # Performs a Boolean operation. The operation name can be found in cmp_op[opname]. - self.emit(vm.Opcode.COMPARE_OP, CMP_OP_MAPPING.get(t.ops[i])) - else: - self.raise_err(CompilerInternalErrorMeta.UNKNOWN_CMPOP.format(t.ops[i])) - if has_next: - # If TOS is false, sets the bytecode counter to target and leaves TOS on the stack. - # Otherwise (TOS is true), TOS is popped. - label = vm.Label() - labels.append(label) - self.op_jmp(vm.Opcode.JUMP_IF_FALSE_OR_POP, label) - if len(t.ops) > 1: - end_label = vm.Label() - # Increments bytecode counter by end label - self.op_jmp(vm.Opcode.JUMP_FORWARD, end_label) - for label in labels: - self.op_label(label) - # Swaps the two top-most stack items. - self.emit(vm.Opcode.ROT_TWO) - # Removes the TOS item. - self.emit(vm.Opcode.POP_TOP) - self.op_label(end_label) - - def walk_Identifier(self, t: ast.Identifier): - """ast.AST: Identifier - - Parameters - ---------- - - names: List[Name] - """ - assert isinstance(t, ast.Identifier) and t.ctx - names = t.names - if t.pkgpath: - names[0] = f"@{t.pkgpath}" - - if len(names) == 1: - name = names[0] - if name in RESERVED_IDENTIFIERS: - self.raise_err(CompilerInternalErrorMeta.INVALID_NAME) - - if t.ctx in [ast.ExprContext.LOAD, ast.ExprContext.AUGLOAD]: - # must be right value - if self._is_in_schema_stmt[-1] and name not in self._local_vars: - self.symtable.define(name, SymbolScope.INTERNAL) - index = self.add_name(name) - 1 - self.load_constant(name) - self.emit(vm.Opcode.SCHEMA_LOAD_ATTR, index) - # Leave the inner attr scope, delete the variable from the symbol table. - self.symtable.delete(name, SymbolScope.INTERNAL) - else: - self.load_symbol(name) - elif t.ctx in [ast.ast.ExprContext.AUGSTORE, ast.ast.ExprContext.STORE]: - if self._is_in_lambda_expr[-1]: - # Store lambda expr variable and pop the stored value - self.store_symbol(name) - self.emit(vm.Opcode.POP_TOP) - elif self._is_in_schema_stmt[-1]: - self.load_constant(name) - self.emit(vm.Opcode.SCHEMA_UPDATE_ATTR, 0) - if not self._is_in_if_stmt[-1]: - self.emit(vm.Opcode.SCHEMA_NOP) - else: - self.store_symbol(name) - elif t.ctx in [ast.ast.ExprContext.DEL]: - pass - else: - assert False - - elif len(names) > 1: - - if t.ctx != ast.ExprContext.AUGSTORE: - self.expr( - ast.Identifier( - names=[names[0]], line=self.lineno, column=self.colno - ) - ) - name_pairs = list(zip(names, names[1:])) - - for i, data in enumerate(name_pairs): - name, attr = data[0], data[1] - - ctx = t.ctx # TODO: Fix single name context in AST - if i == 0 and ( - ctx == ast.ExprContext.STORE or ctx == ast.ExprContext.AUGSTORE - ): - self.store_symbol(name) - if ( - t.ctx == ast.ExprContext.STORE - and i != (len(name_pairs) - 1) - and len(name_pairs) > 1 - ): - ctx = ast.ExprContext.LOAD - - op = EXPR_OP_MAPPING.get(ctx) - - if not op: - self.raise_err( - CompilerInternalErrorMeta.INVALID_PARAM_IN_ATTR.format(ctx) - ) - if ctx == ast.ExprContext.AUGLOAD: - self.emit(vm.Opcode.DUP_TOP) - elif ctx == ast.ExprContext.AUGSTORE: - self.emit(vm.Opcode.ROT_TWO) - - self.op_name(op, attr) - else: - self.raise_err(CompilerInternalErrorMeta.INVALID_NAME) - - def walk_NumberLit(self, t: ast.AST): - """ast.AST: NumberLit - - Parameters - ---------- - - value - """ - assert isinstance(t, ast.NumberLit) - - if t.binary_suffix: - value = units.cal_num(t.value, t.binary_suffix) - self.load_constant( - objpkg.KCLNumberMultiplierObject( - value=value, - raw_value=t.value, - binary_suffix=t.binary_suffix, - ) - ) - else: - self.load_constant(t.value) - - def walk_StringLit(self, t: ast.StringLit): - """ast.AST: StringLit - - Parameters - ---------- - - value - """ - assert isinstance(t, ast.StringLit) - self.load_constant(t.value) - - def walk_NameConstantLit(self, t: ast.NameConstantLit): - """ast.AST: NameConstantLit - - Parameters - ---------- - - value - """ - assert isinstance(t, ast.NameConstantLit) - self.load_constant(t.value) - - def walk_JoinedString(self, t: ast.JoinedString): - """ast.AST: JoinedString - Parameters - ---------- - - values: List[Union[Expr, StringLit]] - TOS - --- - - format_spec - - formatted expr list - Operand - ------- - Formatted expr list count - """ - assert isinstance(t, ast.JoinedString) - assert t.values - for value in t.values: - if isinstance(value, ast.FormattedValue): - self.expr(value.value) - self.load_constant(value.format_spec) - self.emit(vm.Opcode.FORMAT_VALUES, 1) - elif isinstance(value, ast.StringLit): - self.expr(value) - elif isinstance(value, ast.Expr): - self.expr(value) - self.load_constant(None) - self.emit(vm.Opcode.FORMAT_VALUES, 1) - else: - self.raise_err( - CompilerInternalErrorMeta.INVALID_STRING_INTERPOLATION_ITEM - ) - for i in range(len(t.values) - 1): - self.emit(vm.Opcode.BINARY_ADD) - - def walk_TypeAliasStmt(self, t: ast.TypeAliasStmt): - """ast.AST: TypeAliasStmt - - Parameters - ---------- - - type_name: Identifier - - type_value: Type - """ - # TypeAliasStmt has been replaced in the ResolveProgram function, - # there is no need to do any processing here - pass - - def walk_UnificationStmt(self, t: ast.UnificationStmt): - """ast.AST: UnificationStmt - - Parameters - ---------- - - target: Identifier - - value: Expr - """ - self._local_vars = [] - name = t.target.get_name() - if self._is_in_schema_stmt[-1]: - # Assign operator - self.load_constant(None) - # Optional - self.load_constant(False) - # Final - self.load_constant(False) - # Has default - self.load_constant(bool(t.value)) - # Default value - t.target.set_ctx(ast.ExprContext.LOAD) - self.expr(t.target) - self.expr_or_load_none(t.value) - self.emit(vm.Opcode.INPLACE_OR) - # Attr name - self.load_constant(name) - # Attr type - self.load_constant(t.value.name.get_name()) - # 0 denotes the decorator count - self.emit(vm.Opcode.SCHEMA_ATTR, 0) - self.emit(vm.Opcode.SCHEMA_NOP) - else: - if not self.symtable.resolve(name): - self.expr(t.value) - self.expr(t.target) - else: - t.target.set_ctx(ast.ExprContext.LOAD) - self.expr(t.target) - self.expr(t.value) - self.emit(vm.Opcode.INPLACE_OR) - t.target.set_ctx(ast.ExprContext.STORE) - self.expr(t.target) - - def walk_AssignStmt(self, t: ast.AssignStmt): - """ast.AST: AssignStmt - - Parameters - ---------- - - targets: List[Identifier] - - value: Expr - """ - self._local_vars = [] - # Infer to schema - if t.type_annotation and isinstance( - self.get_type_from_identifier(t.targets[0]), objpkg.KCLSchemaTypeObject - ): - # Config meta - self.load_constant({}) - # Config - self.expr(t.value) - # Load the schema type - names = t.type_annotation.split(".") - self.load_symbol(names[0]) - for name in names[1:]: - self.op_name(vm.Opcode.LOAD_ATTR, name) - # Build schema - self.emit(vm.Opcode.BUILD_SCHEMA, 0) - else: - self.expr(t.value) - for i, target in enumerate(t.targets): - self.update_line_column(target) - self.expr(target) - - def walk_AugAssignStmt(self, t: ast.AugAssignStmt): - """ast.AST: AugAssignStmt - - Parameters - ---------- - - target: Identifier - - value: Expr - - op: AugOp - """ - assert isinstance(t, ast.AugAssignStmt) and t.target and t.value and t.op - t.target.set_ctx(ast.ExprContext.LOAD) - self.expr(t.target) - self.expr(t.value) - opcode = ARG_OP_MAPPING.get(t.op) - if not opcode: - self.raise_err(CompilerInternalErrorMeta.UNKNOWN_AUG_BINOP.format(t.op)) - self.emit(opcode) - if t.target.pkgpath: - kcl_error.report_exception( - err_type=kcl_error.ErrType.CompileError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=self.filename, - line_no=t.target.get_line(), - col_no=t.target.get_column(), - end_col_no=t.target.get_end_column(), - ) - ], - arg_msg="module '{}' can't be assigned".format( - t.target.pkgpath.replace("@", "") - ), - ) - t.target.set_ctx(ast.ExprContext.STORE) - self.expr(t.target) - - -# ----------------------------------------------------------------------------- -# CompileProgram/ResolveProgram -# ----------------------------------------------------------------------------- - - -def FixAndResolveProgram(prog: ast.Program) -> ProgramScope: - """Fix AST program and resolve it.""" - # Preprocess - for pkgpath in prog.pkgs: - # Configuration merge with the same name - if pkgpath == ast.Program.MAIN_PKGPATH: - prog.pkgs[pkgpath] = unification.MergeASTList(prog.pkgs[pkgpath]) - - # Resolve program including the import check and the type check - return ResolveProgram(prog) - - -def CompileProgram( - prog: ast.Program, enable_cache: bool = True -) -> Optional[objpkg.KCLProgram]: - """Compile function""" - if not prog or not isinstance(prog, ast.Program): - return - modfile = vfs.LoadModFile(prog.root) - enable_cache = modfile.build.enable_pkg_cache and enable_cache - kcl_program = vfs.LoadBytecodeCache(prog.root, prog) if enable_cache else None - # Preprocess - for pkgpath in prog.pkgs: - # Configuration merge with the same name - if pkgpath == ast.Program.MAIN_PKGPATH: - # Config merge - prog.pkgs[pkgpath] = unification.MergeASTList(prog.pkgs[pkgpath]) - # Fix identifier pkgpath - import_names = {} - for m in prog.pkgs[pkgpath]: - fix.fix_qualified_identifier(m, import_names=import_names) - - # Apply command line arguments - query.ApplyOverrides(prog, prog.cmd_overrides) - - if not kcl_program: - # Resolve program and get the scope - scope = ResolveProgram(prog) - # Compile program using the scope - kcl_program = Compiler(scope).compile_program(prog) - if enable_cache: - vfs.SaveBytecodeCache(prog.root, prog, kcl_program) - return kcl_program - - -# ----------------------------------------------------------------------------- -# END -# ----------------------------------------------------------------------------- diff --git a/internal/kclvm_py/compiler/build/data.py b/internal/kclvm_py/compiler/build/data.py deleted file mode 100644 index 631e1c068..000000000 --- a/internal/kclvm_py/compiler/build/data.py +++ /dev/null @@ -1,151 +0,0 @@ -from kclvm.kcl.ast import BinOp, CmpOp, UnaryOp, AugOp, ExprContext - -from kclvm.vm.code import Opcode -from kclvm.compiler.build.symtable import SymbolScope - - -CMP_OP_MAPPING = { - CmpOp.Eq: Opcode.COMPARE_EQUAL_TO, - CmpOp.NotEq: Opcode.COMPARE_NOT_EQUAL_TO, - CmpOp.Lt: Opcode.COMPARE_LESS_THAN, - CmpOp.LtE: Opcode.COMPARE_LESS_THAN_OR_EQUAL_TO, - CmpOp.Gt: Opcode.COMPARE_GREATER_THAN, - CmpOp.GtE: Opcode.COMPARE_GREATER_THAN_OR_EQUAL_TO, - CmpOp.Is: Opcode.COMPARE_IS, - CmpOp.IsNot: Opcode.COMPARE_IS_NOT, - CmpOp.In: Opcode.COMPARE_IN, - CmpOp.NotIn: Opcode.COMPARE_NOT_IN, - CmpOp.Not: Opcode.COMPARE_IS_NOT, # 'not' => 'is not' -} - - -BIN_OP_MAPPING = { - **CMP_OP_MAPPING, - BinOp.Add: Opcode.BINARY_ADD, - BinOp.Sub: Opcode.BINARY_SUBTRACT, - BinOp.Mul: Opcode.BINARY_MULTIPLY, - BinOp.Div: Opcode.BINARY_TRUE_DIVIDE, - BinOp.Mod: Opcode.BINARY_MODULO, - BinOp.Pow: Opcode.BINARY_POWER, - BinOp.LShift: Opcode.BINARY_LSHIFT, - BinOp.RShift: Opcode.BINARY_RSHIFT, - BinOp.BitOr: Opcode.BINARY_OR, - BinOp.BitXor: Opcode.BINARY_XOR, - BinOp.BitAnd: Opcode.BINARY_AND, - BinOp.FloorDiv: Opcode.BINARY_FLOOR_DIVIDE, - BinOp.And: Opcode.BINARY_LOGIC_AND, - BinOp.Or: Opcode.BINARY_LOGIC_OR, - BinOp.As: Opcode.MEMBER_SHIP_AS, -} - -UNARY_OP_MAPPING = { - UnaryOp.Invert: Opcode.UNARY_INVERT, - UnaryOp.Not: Opcode.UNARY_NOT, - UnaryOp.UAdd: Opcode.UNARY_POSITIVE, - UnaryOp.USub: Opcode.UNARY_NEGATIVE, -} - -ARG_OP_MAPPING = { - AugOp.Add: Opcode.INPLACE_ADD, - AugOp.Sub: Opcode.INPLACE_SUBTRACT, - AugOp.Mul: Opcode.INPLACE_MULTIPLY, - AugOp.Div: Opcode.INPLACE_TRUE_DIVIDE, - AugOp.Mod: Opcode.INPLACE_MODULO, - AugOp.Pow: Opcode.INPLACE_POWER, - AugOp.LShift: Opcode.INPLACE_LSHIFT, - AugOp.RShift: Opcode.INPLACE_RSHIFT, - AugOp.BitOr: Opcode.INPLACE_OR, - AugOp.BitXor: Opcode.INPLACE_XOR, - AugOp.BitAnd: Opcode.INPLACE_AND, - AugOp.FloorDiv: Opcode.INPLACE_FLOOR_DIVIDE, -} - -EXPR_OP_MAPPING = { - ExprContext.AUGLOAD: Opcode.LOAD_ATTR, - ExprContext.LOAD: Opcode.LOAD_ATTR, - ExprContext.AUGSTORE: Opcode.STORE_ATTR, - ExprContext.STORE: Opcode.STORE_ATTR, - ExprContext.DEL: Opcode.DELETE_ATTR, -} - - -SUBSCR_OP_MAPPING = { - ExprContext.AUGLOAD: [Opcode.DUP_TOP_TWO, Opcode.BINARY_SUBSCR], - ExprContext.LOAD: [Opcode.BINARY_SUBSCR], - ExprContext.AUGSTORE: [Opcode.ROT_THREE, Opcode.STORE_SUBSCR], - ExprContext.STORE: [Opcode.STORE_SUBSCR], - ExprContext.DEL: [Opcode.DELETE_SUBSCR], -} - -SYMBOL_SCOPE_LOAD_OP_MAPPING = { - SymbolScope.BUILT_IN: Opcode.LOAD_BUILT_IN, - SymbolScope.LOCAL: Opcode.LOAD_LOCAL, - SymbolScope.GLOBAL: Opcode.LOAD_NAME, - SymbolScope.FREE: Opcode.LOAD_FREE, - SymbolScope.INTERNAL: Opcode.LOAD_NAME, -} - -SYMBOL_SCOPE_STORE_OP_MAPPING = { - SymbolScope.GLOBAL: Opcode.STORE_GLOBAL, - SymbolScope.LOCAL: Opcode.STORE_LOCAL, - SymbolScope.FREE: Opcode.STORE_FREE, -} - - -class CompilerInternalErrorMeta: - COMPILE_ERR = "compile error {}" - UNKNOWN_MOD = "unknown Module {}" - UNKNOWN_STMT = "unknown Stmt {}" - UNKNOWN_EXPR = "unknown Expr {}" - UNKNOWN_NUM = "unknown num {}" - UNKNOWN_NAME_CONST = "unknown NameContext const {}" - UNKNOWN_BINOP = "unknown BinOp {}" - UNKNOWN_AUG_BINOP = "unknown Aug BinOp {}" - UNKNOWN_UNARYOP = "unknown UnaryOp {}" - UNKNOWN_LOOPTYPE = "unknown loop type {}" - UNKNOWN_CMPOP = "unknown CompareOp {}" - UNKNOWN_COMP = "unknown comprehension {}" - INVALID_KCL_AST_MSG = "invalid KCL AST type" - INVALID_PARAM_IN_ATTR = "invalid param {} in attribute expression" - INVALID_PARAM_IN_SUBSCR = "invalid param {} in attribute subscript" - INVALID_SUBSCRIPT_KIND = "invalid subscript kind {}" - INVALID_TARGET_IN_LIST_TUPLE = ( - "invalid starred assignment target outside a list or tuple" - ) - INVALID_STARRED_EXPR = "invalid starred expression outside assignment target " - INVALID_TWO_STARRED_EXPR = "two starred expressions in assignment" - INVALID_JMP_CALL = "opJmp called with non jump instruction" - INVALID_NAME = "NameContext can't be None, True or False" - INVALID_SYMBOL = "symbol can't be None, True or False" - INVALID_SYMBOL_SCOPE = "invalid symbol scope {}" - INVALID_NONE_OP = "opcode can't be none" - INVALID_ARGED_OP_CODE = "opcode {} can't takes an argument" - INVALID_OP_CODE = "opcode {} can't be emitted without an argument" - INVALID_EXPR_CONTEXT = "invalid AST AssignStmt ExprContext value {}" - INVALID_OP_POS = "invalid opcode pos {}" - INVALID_MISSING_ARG = "missing arg in Arged opcode" - INVALID_GLOBAL_IMPLICIT_SCOPE = "not expecting scopeGlobalImplicit in set qualname" - INVALID_CLOSURE_FREE_SCOPE = ( - "invalid closure scope {} for free var {} in symbol table {}" - ) - INVALID_GENERATORS = "invalid generators" - INVALID_STRING_INTERPOLATION_ITEM = "invalid string interpolation item" - INVALID_QUANTIFIER_OP = "invalid quantifier expression operation {}" - SYMBOL_NOT_DEFINED = "name '{}' is not defined" - UNEQUAL_OPS_AND_CMPS = "unequal ops and comparators in compare" - UNEQUAL_DICT_KV_SIZE = "unequal dict keys len {} and values len {}" - TOO_MANY_EXPRS_IN_STAR_UNPACK = "too many expressions in star-unpacking assignment" - FAILED_SET_AUG_ASSIGN_CTX = "can't set context in AugAssign" - NO_OPS_OR_CMPS = "no ops or comparators in compare" - NO_SYMBOL_TABLE_FOR_AST = "no symbol table found for ast {}" - DUPLICATED_KW = "duplicated keyword argument" - - -class SchemaConfigMeta: - """ - SchemaConfigMeta defines the names of meta information - """ - - LINE = "$lineno" - COLUMN = "$columnno" - FILENAME = "$filename" diff --git a/internal/kclvm_py/compiler/build/preprocess.py b/internal/kclvm_py/compiler/build/preprocess.py deleted file mode 100644 index 5104e30d5..000000000 --- a/internal/kclvm_py/compiler/build/preprocess.py +++ /dev/null @@ -1,139 +0,0 @@ -# Copyright 2021 The KCL Authors. All rights reserved. - -from typing import Optional - -import kclvm.kcl.ast as ast - -_IDENTIFIER_PREFIX = "$" - - -class ASTIdentifierPrefixTransformer(ast.TreeTransformer): - @staticmethod - def _remove_prefix(name: str): - if not name: - return name - return name.replace(_IDENTIFIER_PREFIX, "") - - def walk_Name(self, node: ast.Name) -> None: - node.value = self._remove_prefix(node.value) - return node - - def walk_Identifier(self, node: ast.Identifier): - node.names = [self._remove_prefix(name) for name in node.names] - for name_node in node.name_nodes or []: - self.walk(name_node) - return node - - def walk_SchemaStmt(self, node: ast.SchemaStmt): - node.name = self._remove_prefix(node.name) - if node.parent_name: - node.parent_name = self.walk(node.parent_name) - for mixin in node.mixins or []: - self.walk(mixin) - for stmt in node.body or []: - self.walk(stmt) - for check in node.checks or []: - self.walk(check) - return node - - def walk_RuleStmt(self, node: ast.RuleStmt): - node.name = self._remove_prefix(node.name) - for rule in node.parent_rules or []: - self.walk(rule) - for check in node.checks or []: - self.walk(check) - return node - - def walk_SchemaAttr(self, node: ast.SchemaAttr): - node.name = self._remove_prefix(node.name) - node.type_str = self._remove_prefix(node.type_str) - return node - - def walk_ImportStmt(self, node: ast.ImportStmt): - if node.asname: - node.asname = self._remove_prefix(node.asname) - if node.as_name_node: - self.walk(node.as_name_node) - node.name = self._remove_prefix(node.name) - node.path = self._remove_prefix(node.path) - for path_node in node.path_nodes or []: - self.walk(path_node) - return node - - -class ConfigNestVarTransformer(ast.TreeTransformer): - def walk_ConfigEntry(self, t: ast.ConfigEntry): - # Unpack the nest var form `a.b.c = 1` to `a: {b: {c = 1}}` - is_nest_key = isinstance(t.key, ast.Identifier) and len(t.key.names) > 1 - if is_nest_key: - names = t.key.names - value = t.value - t.key.names = [t.key.names[0]] - for i, name in enumerate(names[1:][::-1]): - is_last_item = i == 0 - name_node = ast.Identifier( - names=[name], line=t.key.line, column=t.key.column - ) - name_node.filename = t.filename - entry_value = ast.ASTFactory.get_ast_configentry( - name_node, - value, - t.operation if is_last_item else ast.ConfigEntryOperation.UNION, - t.filename, - ) - value = ast.ConfigExpr(line=t.key.line, column=t.key.column) - value.filename = t.filename - value.items.append(entry_value) - t.value = value - t.operation = ast.ConfigEntryOperation.UNION - self.walk(t.value) - return t - - def walk_ConfigIfEntryExpr(self, t: ast.ConfigIfEntryExpr): - keys = [] - values = [] - operations = [] - for key, value, operation in zip(t.keys, t.values, t.operations): - is_nest_key = isinstance(key, ast.Identifier) and len(key.names) > 1 - if is_nest_key: - names = key.names - key.names = [key.names[0]] - for i, name in enumerate(names[1:][::-1]): - is_last_item = i == 0 - name_node = ast.Identifier( - names=[name], line=key.line, column=key.column - ) - name_node.filename = t.filename - entry_value = ast.ASTFactory.get_ast_configentry( - name_node, - value, - operation if is_last_item else ast.ConfigEntryOperation.UNION, - t.filename, - ) - value = ast.ConfigExpr(line=key.line, column=key.column) - value.filename = t.filename - value.items.append(entry_value) - operations.append(ast.ConfigEntryOperation.UNION) - else: - operations.append(operation) - keys.append(key) - values.append(value) - t.keys = keys - t.values = [self.walk(v) for v in values] - t.operations = operations - if t.orelse: - self.walk(t.orelse) - return t - - -def fix_identifier_prefix(node: Optional[ast.AST]) -> Optional[ast.AST]: - """Fix AST Identifier prefix and unpack the nest var form `a.b.c = 1` to `a: {b: {c = 1}}` - - Examples - -------- - $filter -> filter - """ - if not node or not isinstance(node, ast.AST): - return node - ConfigNestVarTransformer().walk(node) - return ASTIdentifierPrefixTransformer().walk(node) diff --git a/internal/kclvm_py/compiler/build/symtable.py b/internal/kclvm_py/compiler/build/symtable.py deleted file mode 100644 index 6f8773b90..000000000 --- a/internal/kclvm_py/compiler/build/symtable.py +++ /dev/null @@ -1,190 +0,0 @@ -from dataclasses import dataclass -from enum import Enum -from typing import Optional, List, Dict, Tuple - -import kclvm.kcl.info as kcl_info - -from kclvm.compiler.extension.builtin import BUILTIN_FUNCTIONS - - -class SymbolScope(Enum): - """Symbol Scope - - Parameters - ---------- - GLOBAL: str - Top level variables including variables in IfStmt - - LOCAL: str - Variables in schema context or in for comprehension - - BUILTIN: str - Built-in variables e.g., `print`, `sum`, - - FREE: str - Variables that need to be captured by closures - - INTERNAL: str - Internal variables used only for record names e.g., `b` and `c` in `a.b.c` - """ - - GLOBAL = "GLOBAL" - LOCAL = "LOCAL" - BUILT_IN = "BUILT_IN" - FREE = "FREE" - INTERNAL = "INTERNAL" - - -@dataclass -class Symbol: - """Symbol - - Parameters - ---------- - name: str - The symbol name - - index: int - The symbol index in the symbol table - - scope: - The symbol scope - - define_count: - The number of times the symbol is defined or declared - """ - - name: str - index: int - scope: SymbolScope = None - define_count: int = 0 - - -@dataclass -class SymbolTable: - """Symbol table - - Parameters - ---------- - outer: SymbolTable - The symbol table in the outer symbol scope - e.g., The schema context symbol table outer is the top level scope symbol table. - - store: Dict[str, Symbol] - The current scope symbol map to store all symbols - - free_symbols: List[Symbol] - The free symbol list in the current scope - - num_definitions: int - The total number of symbols - """ - - outer: "SymbolTable" = None - store: Dict[str, Symbol] = None - free_symbols: List[Symbol] = None - num_definitions: int = 0 - - def define(self, name: str, scope: SymbolScope = None) -> Tuple[Symbol, bool]: - """ - Define a symbol named 'name' with 'scope' and put it into symbol table - """ - assert isinstance(name, str) - - def default_scope(): - """The inner default symbol scope - - If outer is exist, return LOCAL scope, else return GLOBAL scope - """ - return SymbolScope.GLOBAL if self.outer is None else SymbolScope.LOCAL - - symbol = Symbol( - name=name, index=self.num_definitions, scope=scope or default_scope() - ) - is_exist = False - if ( - name in self.store - and not kcl_info.isprivate_field(name) - and self.store[name].scope == SymbolScope.GLOBAL - ): - is_exist = True - self.num_definitions += 1 - return self.store[name], is_exist - # Internal scope variable skip exist symbol - if symbol.scope == SymbolScope.INTERNAL and name in self.store: - pass - else: - self.store[name] = symbol - self.num_definitions += 1 - return symbol, is_exist - - def define_builtin(self, name: str, index: int) -> Symbol: - """Define a builtin function object""" - if self.store is None or not isinstance(self.store, dict): - raise Exception("Invalid symbol table store") - symbol = Symbol(name=name, index=index) - symbol.scope = SymbolScope.BUILT_IN - self.store[name] = symbol - return symbol - - def define_free(self, original: Symbol) -> Symbol: - """ - Define a symbol named 'name' with free scope and put it into symbol table - """ - self.free_symbols.append(original) - self.store[original.name] = Symbol( - name=original.name, index=original.index, scope=SymbolScope.FREE - ) - return self.store[original.name] - - def register_builtins(self): - """Register builtin functions into symbol table""" - builtins = BUILTIN_FUNCTIONS - for i, builtin in enumerate(builtins): - self.define_builtin(builtin, i) - return self - - def resolve(self, name: str) -> Optional[Symbol]: - """Resolve a symbol named 'name' - - Search from the current scope, if not found, search from the symbol table of its outer - """ - obj = self.store.get(name) - if not obj and self.outer: - obj = self.outer.resolve(name) - if not obj: - return obj - if obj.scope == SymbolScope.GLOBAL or obj.scope == SymbolScope.BUILT_IN: - return obj - elif obj.scope == SymbolScope.INTERNAL: - return None - return self.define_free(obj) - return obj - - def delete(self, name: str, scope: SymbolScope): - """Delete name from the symbol table""" - if ( - not name - or not scope - or name not in self.store - or self.store[name].scope != scope - ): - return - del self.store[name] - - # Static methods - - @staticmethod - def new(outer=None, num=0): - """New an empty symbol table""" - return SymbolTable( - outer=outer, - store={}, - free_symbols=[], - num_definitions=num, - ) - - @staticmethod - def new_with_built_in(outer=None, num=0): - """New a symbol table with all builtin functions""" - return SymbolTable.new(outer, num).register_builtins() diff --git a/internal/kclvm_py/compiler/build/utils/units.py b/internal/kclvm_py/compiler/build/utils/units.py deleted file mode 100644 index a1c155609..000000000 --- a/internal/kclvm_py/compiler/build/utils/units.py +++ /dev/null @@ -1,112 +0,0 @@ -# Units based on SI and ECI -# Ref: https://en.wikipedia.org/wiki/Binary_prefix -# Kubernetes use case: https://pkg.go.dev/k8s.io/apimachinery/pkg/api/resource#Quantity - -from typing import Union - - -IEC_SUFFIX = "i" -EXPONENTS = {"n": -3, "u": -2, "m": -1, "K": 1, "k": 1, "M": 2, "G": 3, "T": 4, "P": 5} -NUMBER_MULTIPLIER_REGEX = r"^([1-9][0-9]{0,63})(E|P|T|G|M|K|k|m|u|n|Ei|Pi|Ti|Gi|Mi|Ki)$" - - -def cal_num(value: int, suffix: str) -> int: - """ - Calculate number based on value and binary suffix. - - Supported suffixes: - SI: n | u | m | k | K | M | G | T | P - IEC: Ki | Mi | Gi | Ti | Pi - - Input: - value: int. - suffix: str. - - Returns: - int - - Raises: - ValueError on invalid or unknown suffix - """ - - if not isinstance(value, int): - raise ValueError("Unsupported value type: {}".format(type(value))) - - if not suffix: - return value - - base = 1000 - unit = suffix - - validate_unit(unit) - - if unit[-1] == "i": - base = 1024 - unit = unit[:-1] - - exponent = EXPONENTS[unit] - return value * (base ** exponent) - - -def to_quantity(quantity: Union[str, int]) -> int: - """ - Parse and return number based on input quantity. - - Supported suffixes: - SI: n | u | m | k | K | M | G | T | P - IEC: Ki | Mi | Gi | Ti | Pi - - Input: - quantity: str. - - Returns: - int - - Raises: - ValueError on invalid or unknown input - """ - if not isinstance(quantity, (int, str)): - raise ValueError("Unsupported quantity type: {}".format(type(quantity))) - - if isinstance(quantity, int): - return quantity - - number = quantity - suffix = None - if len(quantity) >= 2 and quantity[-1] == IEC_SUFFIX: - if quantity[-2] in EXPONENTS: - number = quantity[:-2] - suffix = quantity[-2:] - elif len(quantity) >= 1 and quantity[-1] in EXPONENTS: - number = quantity[:-1] - suffix = quantity[-1:] - - if not number: - raise ValueError("Number can't be empty") - - number = int(number) - - if suffix is None: - return number - - validate_unit(suffix[0]) - - if suffix.endswith(IEC_SUFFIX): - base = 1024 - else: - base = 1000 - - exponent = EXPONENTS[suffix[0]] - return number * (base ** exponent) - - -def validate_unit(unit: str) -> None: - # IEC validate - if not unit or not isinstance(unit, str) or len(unit) > 2: - raise ValueError("Invalid suffix {}".format(unit)) - - if unit in ["ni", "ui", "mi", "ki"]: - raise ValueError("Invalid suffix {}".format(unit)) - - if unit[0] not in EXPONENTS: - raise ValueError("Invalid suffix {}".format(unit)) diff --git a/internal/kclvm_py/compiler/check/check_type/__init__.py b/internal/kclvm_py/compiler/check/check_type/__init__.py deleted file mode 100644 index 2857db22d..000000000 --- a/internal/kclvm_py/compiler/check/check_type/__init__.py +++ /dev/null @@ -1,21 +0,0 @@ -from .check_type import ( - check, - check_type, - check_type_dict, - runtime_type, - runtime_types, - type_pack_and_check, - check_type_builtin, - has_literal_type, -) - -__all__ = [ - "check", - "check_type", - "check_type_dict", - "runtime_type", - "runtime_types", - "type_pack_and_check", - "check_type_builtin", - "has_literal_type", -] diff --git a/internal/kclvm_py/compiler/check/check_type/check_type.py b/internal/kclvm_py/compiler/check/check_type/check_type.py deleted file mode 100644 index 1876147a3..000000000 --- a/internal/kclvm_py/compiler/check/check_type/check_type.py +++ /dev/null @@ -1,585 +0,0 @@ -#! /usr/bin/env python3 - -from ast import literal_eval -from typing import Optional, List - -import kclvm.kcl.error as kcl_error -import kclvm.kcl.info as kcl_info -import kclvm.config -import kclvm.api.object as objpkg -import kclvm.api.object.internal.common as common -from kclvm.api.object.internal import Undefined, UndefinedType - -STR_TYPE = "str" -BOOL_TYPE = "bool" -INT_TYPE = "int" -FLOAT_TYPE = "float" -BUILTIN_TYPES = [STR_TYPE, BOOL_TYPE, INT_TYPE, FLOAT_TYPE] - -_KCL_TYPE_any = "any" -_KCL_TYPE_True = "True" -_KCL_TYPE_False = "False" -_KCL_TYPE_None = "None" - - -# ------------------------------ -# Numeric range check -# ------------------------------ - - -def check( - kcl_obj, - filename: Optional[str] = None, - lineno: Optional[int] = None, - columnno: Optional[int] = None, -): - """Check whether the KCL object meets the scope requirements""" - if not kclvm.config.debug: - return kcl_obj - strict_range_check = kclvm.config.strict_range_check - check_bit = 32 if strict_range_check else 64 - int_min = kcl_info.INT32_MIN if strict_range_check else kcl_info.INT64_MIN - int_max = kcl_info.INT32_MAX if strict_range_check else kcl_info.INT64_MAX - float_min = kcl_info.FLOAT32_MIN if strict_range_check else kcl_info.FLOAT64_MIN - float_max = kcl_info.FLOAT32_MAX if strict_range_check else kcl_info.FLOAT64_MAX - - def check_object(obj: objpkg.KCLObject): - if isinstance(obj, objpkg.KCLIntObject): - value = obj.value - if not (int_min <= value <= int_max): - kcl_error.report_exception( - err_type=kcl_error.ErrType.IntOverflow_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=filename, line_no=lineno, col_no=columnno - ) - ], - arg_msg=kcl_error.INT_OVER_FLOW_MSG.format( - str(obj.value), check_bit - ), - ) - elif isinstance(obj, objpkg.KCLFloatObject): - abs_var = abs(obj.value) - if 0 < abs_var < float_min: - kcl_error.report_warning( - err_type=kcl_error.ErrType.FloatUnderflow_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=filename, line_no=lineno, col_no=columnno - ) - ], - arg_msg=kcl_error.FLOAT_UNDER_FLOW_MSG.format( - str(obj.value), check_bit - ), - ) - obj.value = 0.0 - elif abs_var > float_max: - kcl_error.report_exception( - err_type=kcl_error.ErrType.FloatOverflow_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=filename, line_no=lineno, col_no=columnno - ) - ], - arg_msg=kcl_error.FLOAT_OVER_FLOW_MSG.format( - str(obj.value), check_bit - ), - ) - elif isinstance(obj, objpkg.KCLListObject): - for i in obj.value: - check_object(i) - elif isinstance(obj, (objpkg.KCLDictObject, objpkg.KCLSchemaObject)): - for k, v in obj.value.items(): - check_object(k) - check_object(v) - return obj - - obj = check_object(kcl_obj) - return obj - - -# ------------------------------ -# Type pack and check functions -# ------------------------------ - - -def runtime_types( - tpes: List[str], - vm=None, - filename: Optional[str] = None, - lineno: Optional[int] = None, - columnno: Optional[int] = None, -): - if not tpes: - return tpes - runtime_tpes = [] - for tpe in tpes: - runtime_tpe = runtime_type(tpe, vm, filename, lineno, columnno) - if runtime_tpe: - runtime_tpes.append(runtime_tpe) - return runtime_tpes - - -def runtime_type( - tpe: str, - vm=None, - filename: Optional[str] = None, - lineno: Optional[int] = None, - columnno: Optional[int] = None, -): - if not tpe: - return tpe - if common.isdicttype(tpe): - tpe = common.dereferencetype(tpe) - key_type, value_type = common.separate_kv(tpe) - if key_type is None or value_type is None: - kcl_error.report_exception( - err_type=kcl_error.ErrType.TypeError_Runtime_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=filename, line_no=lineno, col_no=columnno - ) - ], - arg_msg="error in dict type, key-value type can't be None", - ) - key_type = runtime_type( - key_type, - vm, - filename, - lineno, - columnno, - ) - value_type = runtime_type( - value_type, - vm, - filename, - lineno, - columnno, - ) - return "{{{}:{}}}".format(key_type, value_type) - elif common.islisttype(tpe): - tpe = common.dereferencetype(tpe) - ele_type = runtime_type(tpe, vm, filename, lineno, columnno) - return "[{}]".format(ele_type) - elif tpe in BUILTIN_TYPES: - return tpe - else: - if "." in tpe: - schema_tpe_obj = vm.find_schema_type(tpe) - if isinstance(schema_tpe_obj, objpkg.KCLSchemaTypeObject): - return schema_tpe_obj.runtime_type - else: - schema_name = tpe - if schema_name in vm.ctx.globals and isinstance( - vm.ctx.globals[schema_name], objpkg.KCLSchemaTypeObject - ): - return vm.ctx.globals[schema_name].runtime_type - return None - - -def convert_collection_value( - value, - expected_type: Optional[str], - filename: Optional[str] = None, - lineno: Optional[int] = None, - columnno: Optional[int] = None, - vm=None, - config_meta=None, -): - assert isinstance(value, objpkg.KCLObject) - - if expected_type == _KCL_TYPE_any: - return value - - is_collection = isinstance(value, (objpkg.KCLDictObject, objpkg.KCLListObject)) - invalid_match_dict = common.isdicttype(expected_type) and not isinstance( - value, objpkg.KCLDictObject - ) - invalid_match_list = common.islisttype(expected_type) and not isinstance( - value, objpkg.KCLListObject - ) - invalid_match = invalid_match_dict or invalid_match_list - if ( - not expected_type - or not is_collection - or invalid_match - or common.is_type_union(expected_type) - ): - return value - if common.isdicttype(expected_type): - # convert dict - key_tpe, value_tpe = common.separate_kv(common.dereferencetype(expected_type)) - expected_dict = {} - for k, v in value.value.items(): - expected_value = convert_collection_value( - v, value_tpe, filename, lineno, columnno, vm - ) - expected_dict[k] = expected_value - obj = objpkg.KCLSchemaConfigObject(value=expected_dict) - obj.update_attr_op_using_obj(value) - return obj - elif common.islisttype(expected_type): - # convert list - expected_type = common.dereferencetype(expected_type) - expected_list = [] - for i in value.value: - expected_schema = convert_collection_value( - i, - expected_type, - filename, - lineno, - columnno, - vm, - ) - expected_list.append(expected_schema) - return objpkg.KCLListObject(expected_list) - elif expected_type in BUILTIN_TYPES: - # Do nothing on built-in types - return value - elif isinstance(value, objpkg.KCLListObject): - # List value not match the schema type - return value - elif "." in expected_type: - # use cross pkg schema like 'pkg.schema' - # kcl support use cross pkg schema without import - schema_type = vm.find_schema_type(expected_type) - if schema_type and isinstance(schema_type, objpkg.KCLSchemaTypeObject): - config_meta_new = config_meta or vm.ctx.locals.get( - objpkg.SCHEMA_CONFIG_META_KEY - ) - return schema_type.new_instance(value, config_meta_new, [], [], vm) - elif ( - expected_type in vm.ctx.globals - and vm.ctx.globals[expected_type].type() == objpkg.KCLObjectType.SCHEMA_TYPE - ): - # Schema in current module context without import - config_meta_new = config_meta or vm.ctx.locals.get( - objpkg.SCHEMA_CONFIG_META_KEY - ) - schema_type = vm.ctx.globals[expected_type] - return schema_type.new_instance(value, config_meta_new, [], [], vm) - kcl_error.report_exception( - err_type=kcl_error.ErrType.EvaluationError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg(filename=filename, line_no=lineno, col_no=columnno) - ], - arg_msg="name '{}' is not defined".format(expected_type), - ) - - -def type_pack_and_check( - value, - expected_types: List[str], - filename=None, - lineno=None, - columno=None, - vm=None, - config_meta=None, -): - """ - Type pack and check - """ - if value is None or value is Undefined or isinstance(value, UndefinedType): - return value - value = objpkg.to_kcl_obj(value) - if ( - isinstance(value, (objpkg.KCLNoneObject, objpkg.KCLUndefinedObject)) - or not expected_types - ): - return value - is_schema = isinstance(value, objpkg.KCLSchemaObject) - value_tpe = value.type_str() - checked = False - convertted_value = None - for expected_type in expected_types: - convertted_value = ( - convert_collection_value( - value, - expected_type, - filename, - lineno, - columno, - vm=vm, - config_meta=config_meta, - ) - if not is_schema - else value - ) - checked, value_tpe = check_type(convertted_value, expected_type, vm=vm) - if checked: - break - if not checked: - if has_literal_type(expected_types): - if isinstance( - value, - ( - objpkg.KCLNoneObject, - objpkg.KCLTrueObject, - objpkg.KCLFalseObject, - objpkg.KCLIntObject, - objpkg.KCLFloatObject, - ), - ): - value_tpe = f"{value_tpe}({value.value})" - elif isinstance(value, objpkg.KCLStringObject): - value_tpe = f'{value_tpe}("{value.value}")' - kcl_error.report_exception( - err_type=kcl_error.ErrType.TypeError_Runtime_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg(filename=filename, line_no=lineno, col_no=columno) - ], - arg_msg="expect {}, got {}".format( - common.get_tpes_str(expected_types).replace("@", ""), - common.get_class_name(value_tpe), - ), - ) - return convertted_value - - -def has_literal_type(expected_types: List[str]) -> bool: - for expected_type in expected_types: - if is_literal_expected_type(expected_type): - return True - elif common.is_type_union(expected_type): - for typ in common.split_type_union(expected_type): - if is_literal_expected_type(typ): - return True - return False - - -def is_none_or_undefined(value) -> bool: - """Wether the value is None or Undefined""" - return value is None or isinstance( - value, (objpkg.UndefinedType, objpkg.KCLNoneObject, objpkg.KCLUndefinedObject) - ) - - -def check_type(value, expected_type: Optional[str], vm=None): - value_tpe = value.type_str() - # if expected type is a union type e.g. A|B|C int|str|[int] - if not expected_type or expected_type == _KCL_TYPE_any: - return True, value_tpe - if is_none_or_undefined(value): - return True, value_tpe - if common.is_type_union(expected_type): - return check_type_union( - value, - value_tpe, - expected_type, - vm=vm, - ) - elif check_literal_type(value, expected_type): - return True, expected_type - elif check_number_multiplier_type(value, expected_type): - return True, expected_type - # if value type is a dict type e.g. {"k": "v"} - elif isinstance(value, objpkg.KCLDictObject): - return check_type_dict( - value, - expected_type, - vm=vm, - ) - # if value type is a list type e.g. [1, 2, 3] - elif isinstance(value, objpkg.KCLListObject): - return check_type_list(value, expected_type, vm=vm) - elif value is not None and not isinstance( - value, (objpkg.KCLNoneObject, objpkg.KCLUndefinedObject) - ): - # if value type is a built-in type e.g. str, int, float, bool - if match_builtin_type(value_tpe, expected_type): - return True, value_tpe - # not list/dict, not built-in type, treat as user defined schema - if isinstance(value, objpkg.KCLSchemaObject): - return is_schema_expected_type(expected_type), value_tpe - return False, value_tpe - # Type Error - return False, value_tpe - - -def is_schema_expected_type(expected_type: Optional[str]) -> bool: - """Is scheam expected type""" - if not expected_type: - return True - return ( - not common.islisttype(expected_type) - and not common.isdicttype(expected_type) - and not common.is_builtin_type(expected_type) - and not is_literal_expected_type(expected_type) - ) - - -def is_literal_expected_type(expected_type: Optional[str]) -> bool: - if expected_type in [_KCL_TYPE_None, _KCL_TYPE_True, _KCL_TYPE_False]: - return True - - # str - if expected_type.startswith('"'): - return expected_type.endswith('"') - if expected_type.startswith("'"): - return expected_type.endswith("'") - - # int or float - if expected_type.isdigit(): - return True - if expected_type.replace(".", "", 1).isdigit() and expected_type.count(".") < 2: - return True - - # non literal type - return False - - -def check_literal_type(value, expected_type: Optional[str]): - if not is_literal_expected_type(expected_type): - return False - # none - if isinstance(value, objpkg.KCLNoneObject): - return expected_type == _KCL_TYPE_None - - # bool - if isinstance(value, objpkg.KCLFalseObject): - return expected_type == _KCL_TYPE_False - if isinstance(value, objpkg.KCLTrueObject): - return expected_type == _KCL_TYPE_True - - # number - if isinstance(value, (objpkg.KCLIntObject, objpkg.KCLFloatObject)): - return f"{value.value}" == expected_type - - # str - if isinstance(value, objpkg.KCLStringObject): - return f"{value.value}" == literal_eval(expected_type) - - return False - - -def check_number_multiplier_type(value, expected_type: Optional[str]): - """Check number multiplier""" - if isinstance(value, objpkg.KCLNumberMultiplierObject): - import kclvm.kcl.types.type_parser as type_parser - - if type_parser.is_number_multiplier_literal_type(expected_type): - return str(value) == expected_type - return expected_type == "units.NumberMultiplier" - return False - - -def check_type_dict( - value, - expected_type, - filename=None, - lineno=None, - columnno=None, - vm=None, -): - # Empty any type in [] or {:} - if expected_type == "": - return True, common.DICT_TYPE_NAME - if not common.isdicttype(expected_type): - return False, common.DICT_TYPE_NAME - - # validation None type on dict key and value - expected_type = common.dereferencetype(expected_type) - expected_key_type, expected_value_type = common.separate_kv(expected_type) - if expected_key_type is None or expected_value_type is None: - # either expected key type or value type can't be None - kcl_error.report_exception( - err_type=kcl_error.ErrType.TypeError_Runtime_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg(filename=filename, line_no=lineno, col_no=columnno) - ], - arg_msg="error in dict type, key-value type can't be None", - ) - expected_type = common.dereferencetype(expected_type) - runtime_key_type, runtime_value_type = common.separate_kv(expected_type) - if runtime_key_type is None or runtime_value_type is None: - # either runtime key type or value type can't be None - kcl_error.report_exception( - err_type=kcl_error.ErrType.TypeError_Runtime_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg(filename=filename, line_no=lineno, col_no=columnno) - ], - arg_msg="error in dict type, key-value type can't be None", - ) - # foreach k,v in dict, check expected and runtime type of key and value - for k, v in value.value.items(): - key_checked, value_checked = True, True - key_value_tpe, value_value_tpe = "", "" - # if no type is specified in dict, ignore drill-down type check - if expected_value_type: - value_checked, value_value_tpe = check_type(v, expected_value_type, vm=vm) - if not key_checked or not value_checked: - # shortcut on check failure - return False, "{{{}:{}}}".format(key_value_tpe, value_value_tpe) - return True, common.DICT_TYPE_NAME - - -def check_type_list( - value, - expected_type, - vm=None, -): - # Empty any type in [] or {:} - if expected_type == "": - return True, common.LIST_TYPE_NAME - if not common.islisttype(expected_type): - return False, common.LIST_TYPE_NAME - expected_type = common.dereferencetype(expected_type) - # foreach element in list, check expected and runtime type - for i in value.value: - checked, value_tpe = check_type(i, expected_type, vm=vm) - if not checked: - # shortcut on check failure - return False, "[{}]".format(value_tpe) - return True, common.LIST_TYPE_NAME - - -def check_type_builtin( - value, - expected_types, - should_raise_err=True, -): - if not expected_types: - return True - if any([tpe not in BUILTIN_TYPES for tpe in expected_types]): - return True - if any([match_builtin_type(value.type_str(), tpe) for tpe in expected_types]): - return True - if should_raise_err: - kcl_error.report_exception( - err_type=kcl_error.ErrType.TypeError_Runtime_TYPE, - arg_msg="expect {}, got {}".format( - common.get_tpes_str(expected_types).replace("@", ""), - common.get_class_name(value.type_str()), - ), - ) - return False - - -def match_builtin_type(value_tpe, expected_type): - return ( - value_tpe == expected_type - or value_tpe == common.CLASS_TYPE_TMPL.format(expected_type) - or (value_tpe == INT_TYPE and expected_type == FLOAT_TYPE) - ) - - -def check_type_union(value, value_tpe, expected_type, vm=None): - """ - Match built-in union type or single built-in type - """ - expected_types = common.split_type_union(expected_type) - if len(expected_types) == 1: - return False - return ( - any( - [ - check_type( - value, - tpe, - vm=vm, - )[0] - for tpe in expected_types - ] - ), - value_tpe, - ) diff --git a/internal/kclvm_py/compiler/extension/builtin/__init__.py b/internal/kclvm_py/compiler/extension/builtin/__init__.py deleted file mode 100644 index 4bc55a25a..000000000 --- a/internal/kclvm_py/compiler/extension/builtin/__init__.py +++ /dev/null @@ -1,17 +0,0 @@ -from .builtin import ( - kcl_builtin, - BUILTIN_FUNCTIONS, - STANDARD_SYSTEM_MODULES, - get_builtin_func_objects, - get_system_module_func_objects, - get_system_module_members, -) - -__all__ = [ - "kcl_builtin", - "BUILTIN_FUNCTIONS", - "STANDARD_SYSTEM_MODULES", - "get_builtin_func_objects", - "get_system_module_func_objects", - "get_system_module_members", -] diff --git a/internal/kclvm_py/compiler/extension/builtin/builtin.py b/internal/kclvm_py/compiler/extension/builtin/builtin.py deleted file mode 100644 index 26045214a..000000000 --- a/internal/kclvm_py/compiler/extension/builtin/builtin.py +++ /dev/null @@ -1,427 +0,0 @@ -from typing import Callable, Optional, Dict, Set -from functools import wraps -import inspect - -from kclvm.api.object import ( - KCLObject, - KCLNoneObject, - KCLTrueObject, - KCLSchemaObject, - KCLBuiltinFunctionObject, - to_kcl_obj, -) -from kclvm.api.object.internal import kcl_option -from kclvm.compiler.build.utils import units - -import kclvm.kcl.info as kcl_info - -STANDARD_SYSTEM_MODULES = [ - "collection", - "net", - "math", - "datetime", - "regex", - "yaml", - "json", - "crypto", - "base64", - "testing", - "units", -] -STANDARD_SYSTEM_MODULE_LOCATION = "kclvm.compiler.extension.builtin.system_module" - - -def kcl_builtin(func): - """KCL builtin decorator""" - - @wraps(func) - def decorated(*args, **kwargs): - return func(*args, **kwargs) - - return decorated - - -def kcl_obj_builtin(func): - """KCL builtin decorator""" - - @wraps(func) - def decorated(*args, **kwargs): - return func(*args, **kwargs) - - return decorated - - -@kcl_builtin -def KMANGLED_option( - key: str, *, type="", required=False, default=None, help="", file="", line=0 -): - """Return the top level argument by the key""" - - return kcl_option( - key, - type=type, - required=required, - default=default, - help=help, - file=file, - line=line, - ) - - -@kcl_builtin -def KMANGLED_print(*args, **kwargs): - """Prints the values to stdout""" - import builtins - - builtins.print(*args, **kwargs) - - -@kcl_builtin -def KMANGLED_multiplyof(a, b): - """Check if the modular result of a and b is 0""" - if isinstance(a, int) and isinstance(b, int): - return (a % b) == 0 - return False - - -@kcl_builtin -def KMANGLED_isunique(inval): - """Check if a list has duplicated elements""" - if isinstance(inval, list): - if len(inval) == len(set(inval)): - return True - return False - - -@kcl_builtin -def KMANGLED_len(inval): - """Return the length of a value""" - import builtins - - return builtins.len(inval) - - -@kcl_builtin -def KMANGLED_abs(*args, **kwargs): - """Return the absolute value of the argument.""" - import builtins - - return builtins.abs(*args, **kwargs) - - -@kcl_builtin -def KMANGLED_all_true(*args, **kwargs): - """Return True if bool(x) is True for all values x in the iterable. - - If the iterable is empty, return True. - """ - import builtins - - return builtins.all(*args, **kwargs) - - -@kcl_builtin -def KMANGLED_any_true(*args, **kwargs): - """Return True if bool(x) is True for any x in the iterable. - - If the iterable is empty, return False. - """ - import builtins - - return builtins.any(*args, **kwargs) - - -@kcl_builtin -def KMANGLED_hex(*args, **kwargs): - """Return the hexadecimal representation of an integer.""" - import builtins - - return builtins.hex(*args, **kwargs) - - -@kcl_builtin -def KMANGLED_sorted(*args, **kwargs): - """Return a new list containing all items from the iterable in ascending order. - - A custom key function can be supplied to customize the sort order, and the reverse - flag can be set to request the result in descending order. - """ - import builtins - - return [x for x in builtins.sorted(*args, **kwargs)] - - -@kcl_builtin -def KMANGLED_bin(*args, **kwargs): - """Return the binary representation of an integer.""" - import builtins - - return builtins.bin(*args, **kwargs) - - -@kcl_builtin -def KMANGLED_oct(*args, **kwargs): - """Return the octal representation of an integer.""" - import builtins - - return builtins.oct(*args, **kwargs) - - -@kcl_builtin -def KMANGLED_ord(*args, **kwargs): - """Return the Unicode code point for a one-character string.""" - import builtins - - return builtins.ord(*args, **kwargs) - - -@kcl_builtin -def KMANGLED_range(*args, **kwargs): - """Return the range of a value""" - import builtins - - return [x for x in builtins.range(*args, **kwargs)] - - -@kcl_builtin -def KMANGLED_max(*args, **kwargs): - """With a single iterable argument, return its biggest item. - The default keyword-only argument specifies an object to return - if the provided iterable is empty. With two or more arguments, - return the largest argument. - """ - import builtins - - return builtins.max(*args, **kwargs) - - -@kcl_builtin -def KMANGLED_min(*args, **kwargs): - """With a single iterable argument, return its smallest item. - The default keyword-only argument specifies an object to return - if the provided iterable is empty. With two or more arguments, - return the smallest argument. - """ - import builtins - - return builtins.min(*args, **kwargs) - - -@kcl_builtin -def KMANGLED_sum(*args, **kwargs): - """When the iterable is empty, return the start value. This function is - intended specifically for use with numeric values and may reject - non-numeric types. - """ - import builtins - - return builtins.sum(*args, **kwargs) - - -@kcl_builtin -def KMANGLED_pow(*args, **kwargs): - """Equivalent to x**y (with two arguments) or x**y % z (with three arguments) - - Some types, such as ints, are able to use a more efficient algorithm when - invoked using the three argument form. - """ - import builtins - - return builtins.pow(*args, **kwargs) - - -@kcl_builtin -def KMANGLED_round(*args, **kwargs): - """Round a number to a given precision in decimal digits. - - The return value is an integer if ndigits is omitted or None. - Otherwise the return value has the same type as the number. - ndigits may be negative. - """ - import builtins - - return builtins.round(*args, **kwargs) - - -@kcl_builtin -def KMANGLED_zip(*args, **kwargs): - """Return a zip object whose .__next__() method returns - a tuple where the i-th element comes from the i-th iterable - argument. The .__next__() method continues until the shortest - iterable in the argument sequence is exhausted and then - it raises StopIteration. - """ - import builtins - - return [list(r) for r in builtins.zip(*args, **kwargs)] - - -@kcl_builtin -def KMANGLED_int(*args, **kwargs) -> int: - """Convert a number or string to an integer, or return 0 if no arguments - are given. If x is a number, return x.__int__(). For floating point numbers, - this truncates towards zero. - """ - args = list(args) - if len(args) >= 1 and isinstance(args[0], str): - args[0] = str(units.to_quantity(args[0])) - return int(*tuple(args), **kwargs) - - -@kcl_builtin -def KMANGLED_float(x) -> float: - """Convert a string or number to a floating point number, if possible.""" - return float(x) - - -@kcl_builtin -def KMANGLED_str(x) -> str: - """Create a new string object from the given object. - If encoding or errors is specified, then the object must - expose a data buffer that will be decoded using the - given encoding and error handler. - """ - return str(x) - - -@kcl_builtin -def KMANGLED_list(*args, **kwargs) -> list: - """Built-in mutable sequence. - - If no argument is given, the constructor creates a new empty list. - The argument must be an iterable if specified. - """ - return list(*args, **kwargs) - - -@kcl_builtin -def KMANGLED_dict(x) -> dict: - """dict() -> new empty dictionary dict(mapping) -> new dictionary initialized from a - mapping object's (key, value) pairs dict(iterable) -> new dictionary initialized - as if via: d = {} for k, v in iterable: d[k] = v dict(**kwargs) -> new dictionary - initialized with the name=value pairs in the keyword argument list. - For example: dict(one=1, two=2) - """ - return dict(x) - - -@kcl_builtin -def KMANGLED_bool(x) -> bool: - """Returns True when the argument x is true, False otherwise. - The builtins True and False are the only two instances of the class bool. - The class bool is a subclass of the class int, and cannot be subclassed. - """ - return bool(x) - - -@kcl_obj_builtin -def KMANGLED_typeof(x: any, *, full_name: bool = False) -> str: - """Return the type of the kcl object""" - if isinstance(full_name, KCLTrueObject): - full_name = True - - if x is None or isinstance(x, KCLNoneObject): - return "None" - - if isinstance(x, KCLSchemaObject): - if full_name: - return x.full_type_str() - else: - return x.type_str() - - if isinstance(x, KCLObject): - return x.type_str() - else: - return type(x).__name__ - - -BUILTIN_FUNCTIONS_MAP = { - "option": KMANGLED_option, - "print": KMANGLED_print, - "multiplyof": KMANGLED_multiplyof, - "isunique": KMANGLED_isunique, - "len": KMANGLED_len, - "abs": KMANGLED_abs, - "all_true": KMANGLED_all_true, - "any_true": KMANGLED_any_true, - "hex": KMANGLED_hex, - "sorted": KMANGLED_sorted, - "bin": KMANGLED_bin, - "oct": KMANGLED_oct, - "ord": KMANGLED_ord, - "range": KMANGLED_range, - "max": KMANGLED_max, - "min": KMANGLED_min, - "sum": KMANGLED_sum, - "pow": KMANGLED_pow, - "round": KMANGLED_round, - "zip": KMANGLED_zip, - "bool": KMANGLED_bool, - "int": KMANGLED_int, - "str": KMANGLED_str, - "float": KMANGLED_float, - "list": KMANGLED_list, - "dict": KMANGLED_dict, - "typeof": KMANGLED_typeof, -} - -BUILTIN_FUNCTIONS = list(BUILTIN_FUNCTIONS_MAP.keys()) - - -def get_builtin_func_objects(): - """Get all builtin function objects""" - return [ - KCLBuiltinFunctionObject(name=builtin, function=BUILTIN_FUNCTIONS_MAP[builtin]) - for builtin in BUILTIN_FUNCTIONS - ] - - -def new_builtin_function( - name: str, func: Callable -) -> Optional[KCLBuiltinFunctionObject]: - """New a KCL builtin function object using native python function""" - if not func or not name: - return None - return KCLBuiltinFunctionObject(name=name, function=func) - - -def get_system_module_func_objects( - module_name: str, -) -> Dict[str, KCLBuiltinFunctionObject]: - """Get all KCL builtin functions from the standard system module named 'module_name'""" - if not module_name or module_name not in STANDARD_SYSTEM_MODULES: - return {} - module = __import__( - f"{STANDARD_SYSTEM_MODULE_LOCATION}.{module_name}", - fromlist=STANDARD_SYSTEM_MODULE_LOCATION, - ) - members = inspect.getmembers(module) - result = { - kcl_info.demangle(member_name): new_builtin_function( - kcl_info.demangle(member_name), member - ) - if inspect.isfunction(member) - else to_kcl_obj(member) - for member_name, member in members - if kcl_info.ismangled(member_name) - } - return result - - -def get_system_module_members( - module_name: str, -) -> Dict[str, Set[str]]: - """Get all members from the standard system module named 'module_name'""" - if not module_name or module_name not in STANDARD_SYSTEM_MODULES: - return {} - module = __import__( - f"{STANDARD_SYSTEM_MODULE_LOCATION}.{module_name}", - fromlist=STANDARD_SYSTEM_MODULE_LOCATION, - ) - members = inspect.getmembers(module) - result = { - kcl_info.demangle(member_name) - for member_name, _ in members - if kcl_info.ismangled(member_name) - } - return result diff --git a/internal/kclvm_py/compiler/extension/builtin/system_module/base64.py b/internal/kclvm_py/compiler/extension/builtin/system_module/base64.py deleted file mode 100644 index 1bc516130..000000000 --- a/internal/kclvm_py/compiler/extension/builtin/system_module/base64.py +++ /dev/null @@ -1,9 +0,0 @@ -import base64 as _base64 - - -def KMANGLED_encode(value: str, encoding: str = "utf-8") -> str: - return _base64.b64encode(value.encode(encoding)).decode(encoding) - - -def KMANGLED_decode(value: str, encoding: str = "utf-8") -> str: - return _base64.b64decode(value).decode(encoding) diff --git a/internal/kclvm_py/compiler/extension/builtin/system_module/collection.py b/internal/kclvm_py/compiler/extension/builtin/system_module/collection.py deleted file mode 100644 index 32a7aa66c..000000000 --- a/internal/kclvm_py/compiler/extension/builtin/system_module/collection.py +++ /dev/null @@ -1,13 +0,0 @@ -from copy import deepcopy - -import kclvm.api.object.internal.common as common - - -def KMANGLED_union_all(data: list) -> dict: - if not data: - return {} - data_copy = deepcopy(data) - value = data[0] - for d in data_copy[1:]: - common.union(value, d) - return value diff --git a/internal/kclvm_py/compiler/extension/builtin/system_module/crypto.py b/internal/kclvm_py/compiler/extension/builtin/system_module/crypto.py deleted file mode 100644 index f60d85a6e..000000000 --- a/internal/kclvm_py/compiler/extension/builtin/system_module/crypto.py +++ /dev/null @@ -1,25 +0,0 @@ -import hashlib as _hashlib - - -def KMANGLED_md5(value: str, encoding: str = "utf-8") -> str: - return _hashlib.md5(value.encode(encoding)).hexdigest() - - -def KMANGLED_sha1(value: str, encoding: str = "utf-8") -> str: - return _hashlib.sha1(value.encode(encoding)).hexdigest() - - -def KMANGLED_sha224(value: str, encoding: str = "utf-8") -> str: - return _hashlib.sha224(value.encode(encoding)).hexdigest() - - -def KMANGLED_sha256(value: str, encoding: str = "utf-8") -> str: - return _hashlib.sha256(value.encode(encoding)).hexdigest() - - -def KMANGLED_sha384(value: str, encoding: str = "utf-8") -> str: - return _hashlib.sha384(value.encode(encoding)).hexdigest() - - -def KMANGLED_sha512(value: str, encoding: str = "utf-8") -> str: - return _hashlib.sha512(value.encode(encoding)).hexdigest() diff --git a/internal/kclvm_py/compiler/extension/builtin/system_module/datetime.py b/internal/kclvm_py/compiler/extension/builtin/system_module/datetime.py deleted file mode 100644 index b9b0c191b..000000000 --- a/internal/kclvm_py/compiler/extension/builtin/system_module/datetime.py +++ /dev/null @@ -1,32 +0,0 @@ -#! /usr/bin/env python3 - -from datetime import datetime as dt -import time as _time - - -def KMANGLED_today(): - """ - Return the datetime today - """ - return str(dt.today()) - - -def KMANGLED_now(): - """ - Return the time at now - """ - return _time.asctime(_time.localtime(_time.time())) - - -def KMANGLED_ticks() -> float: - """ - Return the current time in seconds since the Epoch. - """ - return _time.time() - - -def KMANGLED_date() -> str: - """ - Return the datetime string - """ - return _time.strftime("%Y-%m-%d %H:%M:%S", _time.localtime()) diff --git a/internal/kclvm_py/compiler/extension/builtin/system_module/json.py b/internal/kclvm_py/compiler/extension/builtin/system_module/json.py deleted file mode 100644 index c2364ae71..000000000 --- a/internal/kclvm_py/compiler/extension/builtin/system_module/json.py +++ /dev/null @@ -1,30 +0,0 @@ -from pathlib import Path -import json - -from .util import filter_fields - - -def KMANGLED_encode( - data, sort_keys=False, indent=None, ignore_private=False, ignore_none=False -): - return json.dumps( - filter_fields(data, ignore_private, ignore_none), - sort_keys=sort_keys, - indent=indent, - ) - - -def KMANGLED_decode(value: str): - return json.loads(value) - - -def KMANGLED_dump_to_file( - data, - filename: str, - sort_keys=False, - indent=None, - ignore_private=False, - ignore_none=False, -): - json_str = KMANGLED_encode(data, sort_keys, indent, ignore_private, ignore_none) - Path(filename).write_text(json_str) diff --git a/internal/kclvm_py/compiler/extension/builtin/system_module/math.py b/internal/kclvm_py/compiler/extension/builtin/system_module/math.py deleted file mode 100644 index beea98f88..000000000 --- a/internal/kclvm_py/compiler/extension/builtin/system_module/math.py +++ /dev/null @@ -1,67 +0,0 @@ -#! /usr/bin/env python3 - -import math - - -def KMANGLED_ceil(*args, **kwargs): - return math.ceil(*args, **kwargs) - - -def KMANGLED_factorial(*args, **kwargs): - return math.factorial(*args, **kwargs) - - -def KMANGLED_floor(*args, **kwargs): - return math.floor(*args, **kwargs) - - -def KMANGLED_gcd(*args, **kwargs): - return math.gcd(*args, **kwargs) - - -def KMANGLED_isfinite(*args, **kwargs): - return math.isfinite(*args, **kwargs) - - -def KMANGLED_isinf(*args, **kwargs): - return math.isinf(*args, **kwargs) - - -def KMANGLED_isnan(*args, **kwargs): - return math.isnan(*args, **kwargs) - - -def KMANGLED_modf(x): - return list(math.modf(x)) - - -def KMANGLED_exp(*args, **kwargs): - return math.exp(*args, **kwargs) - - -def KMANGLED_expm1(*args, **kwargs): - return math.expm1(*args, **kwargs) - - -def KMANGLED_log(*args, **kwargs): - return math.log(*args, **kwargs) - - -def KMANGLED_log1p(*args, **kwargs): - return math.log1p(*args, **kwargs) - - -def KMANGLED_log2(*args, **kwargs): - return math.log2(*args, **kwargs) - - -def KMANGLED_log10(n): - return math.log10(n) - - -def KMANGLED_pow(*args, **kwargs): - return math.pow(*args, **kwargs) - - -def KMANGLED_sqrt(*args, **kwargs): - return math.sqrt(*args, **kwargs) diff --git a/internal/kclvm_py/compiler/extension/builtin/system_module/net.py b/internal/kclvm_py/compiler/extension/builtin/system_module/net.py deleted file mode 100644 index 32eb49e8c..000000000 --- a/internal/kclvm_py/compiler/extension/builtin/system_module/net.py +++ /dev/null @@ -1,153 +0,0 @@ -#! /usr/bin/env python3 -import ipaddress as _ip -import socket as _socket - -import kclvm.kcl.error as kcl_error - - -def check_empty_str(ip): - if not isinstance(ip, str) or ip.strip() == "": - kcl_error.report_exception( - err_type=kcl_error.ErrType.EvaluationError_TYPE, - arg_msg="ip must be non-empty string", - ) - - -def _get_ip(ip): - try: - return _ip.ip_address(ip) - except ValueError: - return None - - -def KMANGLED_split_host_port(ip_end_point: str): - """ - split the 'host' and 'port' from the ip end point - """ - check_empty_str(ip_end_point) - return ip_end_point.split(":") - - -def KMANGLED_join_host_port(host, port): - """ - merge the 'host' and 'port' - """ - return "{}:{}".format(host, port) - - -def KMANGLED_fqdn(name=""): - """ - get Fully Qualified Domain Name (FQDN) - """ - return _socket.getfqdn(str(name)) - - -def KMANGLED_parse_IP(ip): - """ - parse 'ip' to a real IP address - """ - return _get_ip(ip) - - -def KMANGLED_to_IP4(ip): - """ - get the IP4 form of 'ip' - """ - return str(_get_ip(ip)) - - -def KMANGLED_to_IP16(ip): - """ - get the IP16 form of 'ip' - """ - return int(_get_ip(ip)) - - -def KMANGLED_IP_string(ip: str): - """ - get the IP string - """ - return _get_ip(ip) - - -def KMANGLED_is_IPv4(ip: str): - """ - whether 'ip' is a IPv4 one - """ - ip = _get_ip(ip) - return isinstance(ip, _ip.IPv4Address) - - -def KMANGLED_is_IP(ip: str) -> bool: - """ - whether ip is a valid ip address - - Parameters - ---------- - - ip: input ip address - - Returns - ------- - - is_ip: a bool type return value - """ - ip = _get_ip(ip) - return ip is not None - - -def KMANGLED_is_loopback_IP(ip: str): - """ - whether 'ip' is a loopback one - """ - ip = _get_ip(ip) - return ip.is_loopback if ip else False - - -def KMANGLED_is_multicast_IP(ip: str): - """ - whether 'ip' is a multicast one - """ - ip = _get_ip(ip) - return ip.is_multicast if ip else False - - -def KMANGLED_is_interface_local_multicast_IP(ip: str): - """ - whether 'ip' is a interface, local and multicast one - """ - try: - ip = _ip.ip_interface(ip) - return (ip.is_site_local and ip.is_multicast) if ip else False - except ValueError: - return False - - -def KMANGLED_is_link_local_multicast_IP(ip: str): - """ - whether 'ip' is a link local and multicast one - """ - ip = _get_ip(ip) - return (ip.is_link_local and ip.is_multicast) if ip else False - - -def KMANGLED_is_link_local_unicast_IP(ip: str): - """ - whether 'ip' is a link local and unicast one - """ - ip = _get_ip(ip) - return (ip.is_link_local and not ip.is_multicast) if ip else False - - -def KMANGLED_is_global_unicast_IP(ip: str): - """ - whether 'ip' is a global and unicast one - """ - ip = _get_ip(ip) - return (ip.is_global and not ip.is_multicast) if ip else False - - -def KMANGLED_is_unspecified_IP(ip: str): - """ - whether 'ip' is a unspecified one - """ - ip = _get_ip(ip) - return ip.is_unspecified if ip else False diff --git a/internal/kclvm_py/compiler/extension/builtin/system_module/regex.py b/internal/kclvm_py/compiler/extension/builtin/system_module/regex.py deleted file mode 100644 index ed20b1306..000000000 --- a/internal/kclvm_py/compiler/extension/builtin/system_module/regex.py +++ /dev/null @@ -1,47 +0,0 @@ -#! /usr/bin/env python3 -import re as _re - - -def KMANGLED_replace(string: str, pattern: str, replace: str, count: int = 0): - """ - Return the string obtained by replacing the leftmost non-overlapping occurrences - of the pattern in string by the replacement. - """ - return _re.sub(pattern, replace, string, count) - - -def KMANGLED_match(string: str, pattern: str): - """ - Try to apply the pattern at the start of the string, returning a Match object, or None if no match was found. - """ - return bool(_re.match(pattern, string)) - - -def KMANGLED_compile(pattern: str): - """ - Compile a regular expression pattern, returning a bool value denoting whether the pattern is valid - """ - return bool(_re.compile(pattern)) - - -def KMANGLED_findall(string: str, pattern: str): - """ - Return a list of all non-overlapping matches in the string. - """ - return _re.findall(pattern, string) - - -def KMANGLED_search(string: str, pattern: str): - """ - Scan through string looking for a match to the pattern, - returning a Match object, or None if no match was found. - """ - return bool(_re.search(pattern, string)) - - -def KMANGLED_split(string: str, pattern: str, maxsplit: int = 0): - """ - Scan through string looking for a match to the pattern, - returning a Match object, or None if no match was found. - """ - return _re.split(pattern, string, maxsplit) diff --git a/internal/kclvm_py/compiler/extension/builtin/system_module/testing.py b/internal/kclvm_py/compiler/extension/builtin/system_module/testing.py deleted file mode 100644 index 7fa5227f0..000000000 --- a/internal/kclvm_py/compiler/extension/builtin/system_module/testing.py +++ /dev/null @@ -1,25 +0,0 @@ -# Copyright 2020 The KCL Authors. All rights reserved. - -import os -import typing - - -def KMANGLED_arguments(name: str, value: typing.Union[bool, int, float, str]) -> None: - """Set arguments for option function in test.""" - - assert isinstance(name, str) - assert isinstance(value, (bool, int, float, str)) - - # TODO: KMANGLED_arguments Support complex parameter types - - assert name, f"testing.arguments: '{name}' is invalid name" - return - - -def KMANGLED_setting_file(filename: str) -> None: - """Set setting file for option function in test.""" - assert isinstance(filename, str) - - assert os.path.exists(filename), f"testing.setting_file: '{filename}' not exists" - assert os.path.isfile(filename), f"testing.setting_file: '{filename}' is not file" - return diff --git a/internal/kclvm_py/compiler/extension/builtin/system_module/units.py b/internal/kclvm_py/compiler/extension/builtin/system_module/units.py deleted file mode 100644 index d4c400c86..000000000 --- a/internal/kclvm_py/compiler/extension/builtin/system_module/units.py +++ /dev/null @@ -1,140 +0,0 @@ -# Copyright 2020 The KCL Authors. All rights reserved. - -from typing import Union - -import kclvm.api.object as objpkg - -# -------------------------------------- -# Numerical Constants -# Usage: -# import units -# memory = 1024 * units.Mi # 1024Mi -# -------------------------------------- - -KMANGLED_n = 1e-09 -KMANGLED_u = 1e-06 -KMANGLED_m = 0.001 -KMANGLED_k = 1_000 -KMANGLED_K = 1_000 -KMANGLED_M = 1_000_000 -KMANGLED_G = 1_000_000_000 -KMANGLED_T = 1_000_000_000_000 -KMANGLED_P = 1_000_000_000_000_000 -KMANGLED_Ki = 1024 -KMANGLED_Mi = 1024 ** 2 -KMANGLED_Gi = 1024 ** 3 -KMANGLED_Ti = 1024 ** 4 -KMANGLED_Pi = 1024 ** 5 - -UNIT_MAPPING = { - "n": KMANGLED_n, - "u": KMANGLED_u, - "m": KMANGLED_m, - "k": KMANGLED_k, - "K": KMANGLED_K, - "M": KMANGLED_M, - "G": KMANGLED_G, - "T": KMANGLED_T, - "P": KMANGLED_P, - "Ki": KMANGLED_Ki, - "Mi": KMANGLED_Mi, - "Gi": KMANGLED_Gi, - "Ti": KMANGLED_Ti, - "Pi": KMANGLED_Pi, -} - -# -------------------------------------- -# Numerical Multiplier Type -# Usage: -# import units -# memory: units.NumberMultiplier = 1M -# -------------------------------------- - -KMANGLED_NumberMultiplier = objpkg.KCLNumberMultiplierTypeObject() - -# ------------------------------------------ -# Unit ToString Methods -# Usage: -# import units -# disk = units.to_Ki(1024) # "1Ki" -# Input: -# num: int -# Returns: -# int -# Raises: -# ValueError on invalid or unknown input -# ------------------------------------------ - - -def KMANGLED_to_n(num: int) -> str: - """Int literal to string with `n` suffix""" - return to_unit(num, "n") - - -def KMANGLED_to_u(num: int) -> str: - """Int literal to string with `u` suffix""" - return to_unit(num, "u") - - -def KMANGLED_to_m(num: int) -> str: - """Int literal to string with `m` suffix""" - return to_unit(num, "m") - - -def KMANGLED_to_K(num: int) -> str: - """Int literal to string with `K` suffix""" - return to_unit(num, "K") - - -def KMANGLED_to_M(num: int) -> str: - """Int literal to string with `M` suffix""" - return to_unit(num, "M") - - -def KMANGLED_to_G(num: int) -> str: - """Int literal to string with `G` suffix""" - return to_unit(num, "G") - - -def KMANGLED_to_T(num: int) -> str: - """Int literal to string with `T` suffix""" - return to_unit(num, "T") - - -def KMANGLED_to_P(num: int) -> str: - """Int literal to string with `P` suffix""" - return to_unit(num, "P") - - -def KMANGLED_to_Ki(num: int) -> str: - """Int literal to string with `Ki` suffix""" - return to_unit(num, "Ki") - - -def KMANGLED_to_Mi(num: int) -> str: - """Int literal to string with `Mi` suffix""" - return to_unit(num, "Mi") - - -def KMANGLED_to_Gi(num: int) -> str: - """Int literal to string with `Gi` suffix""" - return to_unit(num, "Gi") - - -def KMANGLED_to_Ti(num: int) -> str: - """Int literal to string with `Ti` suffix""" - return to_unit(num, "Ti") - - -def KMANGLED_to_Pi(num: int) -> str: - """Int literal to string with `Pi` suffix""" - return to_unit(num, "Pi") - - -def to_unit(num: Union[int, float], suffix: str) -> str: - """Connect numbers and suffixes""" - if not isinstance(num, (int, float)): - raise ValueError("Unsupported number type: {}".format(type(num))) - if not suffix or not isinstance(suffix, str) or suffix not in list(UNIT_MAPPING): - raise ValueError("Unsupported unit suffix: {}".format(suffix)) - return str(int(num // UNIT_MAPPING[suffix])) + suffix diff --git a/internal/kclvm_py/compiler/extension/builtin/system_module/util.py b/internal/kclvm_py/compiler/extension/builtin/system_module/util.py deleted file mode 100644 index 57a269fd7..000000000 --- a/internal/kclvm_py/compiler/extension/builtin/system_module/util.py +++ /dev/null @@ -1,39 +0,0 @@ -from typing import Any - -from kclvm.api.object import KCLNumberMultiplierObject -from kclvm.api.object.internal import Undefined, UndefinedType - -import kclvm.kcl.info as kcl_info - - -def filter_fields( - value: Any, ignore_private: bool = False, ignore_none: bool = False -) -> Any: - """Remove private attributes start with '_' and None value in data""" - if not value: - return value - if value is Undefined or isinstance(value, UndefinedType): - return value - if isinstance(value, KCLNumberMultiplierObject): - return str(value) - if isinstance(value, list): - return [ - filter_fields(_v, ignore_private, ignore_none) - for _v in value - if ignore_none and _v is not None or not ignore_none - if not isinstance(_v, UndefinedType) - ] - elif isinstance(value, dict): - return { - filter_fields(_k, ignore_private, ignore_none): filter_fields( - _v, ignore_private, ignore_none - ) - for _k, _v in value.items() - if not kcl_info.isprivate_field(_k) and ignore_private or not ignore_private - if ignore_none and _v is not None or not ignore_none - if not isinstance(_v, UndefinedType) - } - elif isinstance(value, (int, float, str, bool)): - return value - else: - raise Exception("Invalid KCL Object") diff --git a/internal/kclvm_py/compiler/extension/builtin/system_module/yaml.py b/internal/kclvm_py/compiler/extension/builtin/system_module/yaml.py deleted file mode 100644 index f6c043b09..000000000 --- a/internal/kclvm_py/compiler/extension/builtin/system_module/yaml.py +++ /dev/null @@ -1,46 +0,0 @@ -from io import StringIO -from pathlib import Path -import ruamel.yaml as yaml - -from .util import filter_fields - -_yaml = yaml.YAML() -_yaml.representer.add_representer( - str, - lambda dumper, data: dumper.represent_scalar( - u"tag:yaml.org,2002:str", data, style="|" - ) - if "\n" in data - else dumper.represent_str(data), -) -# Convert None to null -_yaml.representer.add_representer( - type(None), - lambda dumper, data: dumper.represent_scalar(u"tag:yaml.org,2002:null", u"null"), -) - - -def KMANGLED_encode(data, sort_keys=False, ignore_private=False, ignore_none=False): - buffer = StringIO() - data_filtered = filter_fields(data, ignore_private, ignore_none) - if sort_keys: - sorted_dict = yaml.comments.CommentedMap() - for k in sorted(data_filtered): - sorted_dict[k] = data_filtered[k] - _yaml.dump(sorted_dict, buffer) - else: - _yaml.dump(data_filtered, buffer) - return buffer.getvalue() - - -def KMANGLED_decode(value: str): - buffer = StringIO(value) - data = yaml.safe_load(buffer) - return data - - -def KMANGLED_dump_to_file( - data, filename: str, sort_keys=False, ignore_private=False, ignore_none=False -): - yaml_str = KMANGLED_encode(data, sort_keys, ignore_private, ignore_none) - Path(filename).write_text(yaml_str) diff --git a/internal/kclvm_py/compiler/extension/plugin/Makefile b/internal/kclvm_py/compiler/extension/plugin/Makefile deleted file mode 100644 index 93a02bd3c..000000000 --- a/internal/kclvm_py/compiler/extension/plugin/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -# Copyright 2020 The KCL Authors. All rights reserved. - -default: - python3 ./__main__.py - -test: - python3 -m pytest - -clean: diff --git a/internal/kclvm_py/compiler/extension/plugin/__init__.py b/internal/kclvm_py/compiler/extension/plugin/__init__.py deleted file mode 100644 index 6c5abc72f..000000000 --- a/internal/kclvm_py/compiler/extension/plugin/__init__.py +++ /dev/null @@ -1,25 +0,0 @@ -# Copyright 2020 The KCL Authors. All rights reserved. - -from .plugin import ( - reset_plugin, - get_plugin_root, - get_info, - get_source_code, - get_plugin, - init_plugin, - gendoc, -) -from .plugin_model import PLUGIN_MODULE_NAME, get_plugin_func_objects, get_plugin_names - -__all__ = [ - "reset_plugin", - "get_plugin_root", - "get_info", - "get_source_code", - "get_plugin", - "init_plugin", - "gendoc", - "PLUGIN_MODULE_NAME", - "get_plugin_func_objects", - "get_plugin_names", -] diff --git a/internal/kclvm_py/compiler/extension/plugin/main.py b/internal/kclvm_py/compiler/extension/plugin/main.py deleted file mode 100644 index 433e57e77..000000000 --- a/internal/kclvm_py/compiler/extension/plugin/main.py +++ /dev/null @@ -1,125 +0,0 @@ -# Copyright 2020 The KCL Authors. All rights reserved. - -import argparse -import sys -import json - -import kclvm.compiler.extension.plugin.plugin as plugin - - -def Main(): - parser = argparse.ArgumentParser(prog="kcl-plugin") - - subparsers = parser.add_subparsers( - dest="kcl_plugin_subcmd_name", help="kcl plugin sub commands" - ) - - parser_list = subparsers.add_parser("list", help="list all plugins") - - parser_init = subparsers.add_parser("init", help="init a new plugin") - - parser_info = subparsers.add_parser("info", help="show plugin document") - subparsers.add_parser("gendoc", help="gen all plugins document") - subparsers.add_parser("version", help="show plugin version") - parser_test = subparsers.add_parser("test", help="test plugin") - - parser_list.add_argument(dest="plugin_keyword", metavar="keyword", nargs="?") - - parser_init.add_argument(dest="plugin_name", metavar="name") - parser_info.add_argument(dest="plugin_name", metavar="name", nargs="?") - - parser_test.add_argument(dest="plugin_name", metavar="name") - - args = parser.parse_args() - - if args.kcl_plugin_subcmd_name == "list": - plugin_root = plugin.get_plugin_root() - if not plugin_root: - print("# plugin_root: ") - sys.exit(0) - - print(f"# plugin_root: {plugin.get_plugin_root()}") - names = plugin.get_plugin_names() - - count = 0 - for name in names: - if args.plugin_keyword and args.plugin_keyword not in name: - continue - info = plugin.get_info(name) - print(f"{info['name']}: {info['describe']} - {info['version']}") - count = count + 1 - - if count == 0: - print("no plugin") - sys.exit(0) - - sys.exit(0) - - if args.kcl_plugin_subcmd_name == "init": - plugin_root = plugin.get_plugin_root() - if not plugin_root: - print("# plugin_root: ") - sys.exit(0) - - names = plugin.get_plugin_names() - if args.plugin_name in names: - print(f"{args.plugin_name} exists") - sys.exit(1) - - plugin.init_plugin(args.plugin_name) - sys.exit(0) - - if args.kcl_plugin_subcmd_name == "info": - plugin_root = plugin.get_plugin_root() - if not plugin_root: - print("# plugin_root: ") - sys.exit(0) - - if not args.plugin_name: - print(f"plugin_root: {plugin.get_plugin_root()}") - sys.exit(0) - - names = plugin.get_plugin_names() - if args.plugin_name not in names: - print(f"{args.plugin_name} not found") - sys.exit(1) - - info = plugin.get_info(args.plugin_name) - - print(json.dumps(info, indent=4)) - sys.exit(0) - - if args.kcl_plugin_subcmd_name == "gendoc": - plugin_root = plugin.get_plugin_root() - if not plugin_root: - print("# plugin_root: ") - sys.exit(0) - - for name in plugin.get_plugin_names(): - plugin.gendoc(name) - - sys.exit(0) - - if args.kcl_plugin_subcmd_name == "version": - print(plugin.get_plugin_version()) - sys.exit(0) - - # TODO: Using kcl-test - if args.kcl_plugin_subcmd_name == "test": - names = plugin.get_plugin_names() - if args.plugin_name not in names: - print(f"{args.plugin_name} not found") - sys.exit(1) - - import pytest - - pytest.main(["-x", plugin.get_plugin_root(args.plugin_name)]) - sys.exit(0) - - parser.print_help() - plugin_root = plugin.get_plugin_root() - sys.exit(0) - - -if __name__ == "__main__": - Main() diff --git a/internal/kclvm_py/compiler/extension/plugin/plugin.py b/internal/kclvm_py/compiler/extension/plugin/plugin.py deleted file mode 100644 index 0698c9f9f..000000000 --- a/internal/kclvm_py/compiler/extension/plugin/plugin.py +++ /dev/null @@ -1,328 +0,0 @@ -# Copyright 2020 The KCL Authors. All rights reserved. - -import os -import glob -import re -import copy -import pathlib -import typing -import sys -import traceback -import inspect -import platform - -import kclvm.kcl.info as kcl_info -import kclvm.compiler.extension.plugin.template as plugin_template - - -UNKNOWN_VERSION = "unknown" - - -class Init: - def __init__(self, root: str = "", info_map=None): - if info_map is None: - info_map = {} - self.plugins_root = root or "" - self.plugins_info_map = info_map or {} - - -_re_plugin_name = re.compile("^[a-z][a-z0-9_-]*$") - - -def _is_valid_plugin_name(plugin_name: str) -> bool: - return _re_plugin_name.match(plugin_name) is not None - - -def _normalize_plugin_name(plugin_name: str) -> str: - if plugin_name.startswith("kcl_plugin.") or plugin_name.startswith("kcl_plugin/"): - plugin_name = plugin_name[len("kcl_plugin.") :] - return plugin_name - - -def _get_plugin(root: str, plugin_name: str) -> typing.Optional[any]: - if not os.path.exists(f"{root}/{plugin_name}/plugin.py"): - return None - - import importlib.util - - spec = importlib.util.spec_from_file_location( - f"kcl_plugin.{plugin_name}", f"{root}/{plugin_name}/plugin.py" - ) - pkg = importlib.util.module_from_spec(spec) - - try: - spec.loader.exec_module(pkg) - except Exception: - ex_type, ex_val, ex_stack = sys.exc_info() - print( - f"WARN: {root}/{plugin_name}/plugin.py:{traceback.extract_tb(ex_stack)[-1].lineno}: init_plugin failed: {ex_val}" - ) - return None - - func_map = {} - for func_name, func_body in inspect.getmembers(pkg, inspect.isfunction): - if func_name.startswith(kcl_info.MANGLE_PREFIX): - func_map[func_name[len(kcl_info.MANGLE_PREFIX) :]] = func_body - - for func_name, func_body in inspect.getmembers(pkg, inspect.isfunction): - if not func_name.startswith(kcl_info.MANGLE_PREFIX) and func_name[0] != "_": - if func_name not in func_map: - func_map[kcl_info.MANGLE_PREFIX + func_name] = func_body - - for func_name in func_map: - setattr(pkg, func_name, func_map[func_name]) - - return pkg - - -def _get_info(pkg) -> dict: - info = copy.deepcopy(getattr(pkg, "INFO")) - - info["method"] = {} - for s in dir(pkg): - if s.startswith(kcl_info.MANGLE_PREFIX): - func_name = s[len(kcl_info.MANGLE_PREFIX) :] - func_doc = getattr(pkg, s).__doc__ - info["method"][func_name] = func_doc if func_doc else "no doc" - - return info - - -def find_plugin_root() -> typing.Optional[str]: - return _find_plugin_root() - - -def _find_plugin_root() -> typing.Optional[str]: - # 1. try $KCL_PLUGINS_ROOT env - env_plugin_root = os.getenv("KCL_PLUGINS_ROOT", "") - if env_plugin_root != "": - return env_plugin_root - - # 2. try ${pwd}/.../plugins/hello/plugin.py - cwd_plugin_path = pathlib.Path(os.getcwd()).absolute() - root = cwd_plugin_path.root - while cwd_plugin_path: - if cwd_plugin_path == cwd_plugin_path.parent or str(cwd_plugin_path) == root: - break - plugin_list_file_path = cwd_plugin_path.joinpath("plugins/hello/plugin.py") - if plugin_list_file_path.exists() and plugin_list_file_path.is_file(): - return str(cwd_plugin_path.joinpath("plugins")) - if cwd_plugin_path.joinpath("kcl.mod").exists(): - break - cwd_plugin_path = cwd_plugin_path.parent - - # 3. try ${__file__}/.../plugins/hello/plugin.py - cwd_plugin_path = pathlib.Path(__file__).parent.absolute() - root = cwd_plugin_path.root - while cwd_plugin_path: - if cwd_plugin_path == cwd_plugin_path.parent or str(cwd_plugin_path) == root: - break - plugin_list_file_path = cwd_plugin_path.joinpath("plugins/hello/plugin.py") - if plugin_list_file_path.exists() and plugin_list_file_path.is_file(): - return str(cwd_plugin_path.joinpath("plugins")) - cwd_plugin_path = cwd_plugin_path.parent - - # 4. try $HOME/.kusion/kclvm/plugins - home_dir = os.getenv("HOME") if platform.system() != "Windows" else os.getenv("UserProfile") - home_plugin_root = os.path.join(home_dir, ".kusion/kclvm/plugins") - if os.path.exists(f"{home_plugin_root}/hello/plugin.py"): - return home_plugin_root - - # 5. not found - return None - - -def _init_plugin_root() -> typing.Tuple[typing.Optional[str], dict]: - plugins_root = _find_plugin_root() - if plugins_root is None: - return None, {} - - plugins_info = {} - - # 'hello' is builtin plugin, and used in test code - if not os.path.exists(f"{plugins_root}/hello/plugin.py"): - os.makedirs(f"{plugins_root}/hello") - - with open(f"{plugins_root}/hello/plugin.py", "w") as file: - file.write(plugin_template.get_plugin_template_code("hello")) - with open(f"{plugins_root}/hello/plugin_test.py", "w") as file: - file.write(plugin_template.get_plugin_test_template_code("hello")) - - # scan all plugins - k_files = glob.glob(f"{plugins_root}/*/plugin.py", recursive=False) - for i in range(len(k_files)): - plugin_name = os.path.basename(k_files[i][: -len("/plugin.py")]) - if _is_valid_plugin_name(plugin_name): - pkg = _get_plugin(plugins_root, plugin_name) - if not pkg: - continue - info = _get_info(pkg) - - plugins_info[plugin_name] = info - return plugins_root, plugins_info - - -# init plugins -_plugin_root, _plugin_info_map = _init_plugin_root() -init_ = Init(_plugin_root, _plugin_info_map) - - -# ----------------------------------------------------------------------------- -# API -# ----------------------------------------------------------------------------- - - -def reset_plugin(plugin_root: str = ""): - global _plugin_root - global _plugin_info_map - global init_ - - os.environ["KCL_PLUGINS_ROOT"] = f"{plugin_root}" - _plugin_root, _plugin_info_map = _init_plugin_root() - init_ = Init(_plugin_root, _plugin_info_map) - - -def get_plugin_version() -> str: - if not init_.plugins_root: - return UNKNOWN_VERSION - version_path = pathlib.Path(f"{init_.plugins_root}/VERSION") - if version_path.exists(): - return version_path.read_text() - return UNKNOWN_VERSION - - -def get_plugin_root(plugin_name: str = "") -> typing.Optional[str]: - if init_.plugins_root is None: - return None - if plugin_name != "": - plugin_name = _normalize_plugin_name(plugin_name) - return f"{init_.plugins_root}/{plugin_name}" - - return init_.plugins_root - - -def get_plugin_names() -> typing.List[str]: - if init_.plugins_root is None: - return [] - plugin_names = [] - for s in init_.plugins_info_map: - plugin_names.append(s) - - plugin_names.sort() - return plugin_names - - -def get_info(plugin_name: str) -> typing.Optional[dict]: - if init_.plugins_root is None: - return None - - plugin_name = _normalize_plugin_name(plugin_name) - - if plugin_name not in init_.plugins_info_map: - return None - return init_.plugins_info_map[plugin_name] - - -def get_source_code(plugin_name: str) -> typing.Optional[str]: - if init_.plugins_root is None: - return None - - plugin_name = _normalize_plugin_name(plugin_name) - - if plugin_name not in init_.plugins_info_map: - return None - - code = "" - with open(f"{init_.plugins_root}/{plugin_name}/plugin.py") as f: - code += f.read() - return code - - -def get_plugin(plugin_name: str) -> typing.Optional[any]: - if init_.plugins_root is None: - return None - - plugin_name = _normalize_plugin_name(plugin_name) - return _get_plugin(init_.plugins_root, plugin_name) - - -# ----------------------------------------------------------------------------- -# UTILS -# ----------------------------------------------------------------------------- - - -def init_plugin(plugin_name: str): - if init_.plugins_root is None: - return None - - plugin_name = _normalize_plugin_name(plugin_name) - - if not _is_valid_plugin_name(plugin_name): - print(f'WARN: init_plugin("{plugin_name}") failed, invalid name') - return - - if os.path.exists(f"{init_.plugins_root}/{plugin_name}/plugin.py"): - print(f'WARN: init_plugin("{plugin_name}") failed, plugin exists') - return - - golden_plugin_skectch_code = plugin_template.get_plugin_template_code(plugin_name) - golden_plugin_skectch_code_test = plugin_template.get_plugin_test_template_code( - plugin_name - ) - - if not os.path.exists(f"{init_.plugins_root}/{plugin_name}"): - os.makedirs(f"{init_.plugins_root}/{plugin_name}") - - with open(f"{init_.plugins_root}/{plugin_name}/plugin.py", "w") as file: - file.write(golden_plugin_skectch_code) - - with open(f"{init_.plugins_root}/{plugin_name}/plugin_test.py", "w") as file: - file.write(golden_plugin_skectch_code_test) - - gendoc(plugin_name) - - -def gendoc(plugin_name: str): - if init_.plugins_root is None: - print("WARN: plugin root not found") - return - - if not _is_valid_plugin_name(plugin_name): - print(f'WARN: gendoc("{plugin_name}") failed, invalid name') - return - - pkg = _get_plugin(init_.plugins_root, plugin_name) - if not pkg: - print("WARN: plugin init failed") - return - info = _get_info(pkg) - if info is None: - print(f'WARN: gendoc("{plugin_name}") failed, not found plugin') - return - - with open(f"{init_.plugins_root}/{plugin_name}/api.md", "w") as file: - file.write(f"# plugin: `{info['name']}` - {info['describe']}\n\n") - file.write(f"{info['long_describe']}\n\n") - file.write(f"*version: {info['version']}*\n\n") - - for func_name in info["method"]: - func_doc = info["method"][func_name] - - func_doc_line = [] - for line in func_doc.splitlines(): - if line.startswith(" "): - line = line[4:] - func_doc_line.append(line) - - file.write(f"## `{func_name}`\n\n") - for line in func_doc_line: - file.write(f"{line}\n") - - file.write("\n") - - return - - -# ----------------------------------------------------------------------------- -# END -# ----------------------------------------------------------------------------- diff --git a/internal/kclvm_py/compiler/extension/plugin/plugin_model.py b/internal/kclvm_py/compiler/extension/plugin/plugin_model.py deleted file mode 100644 index 901d22db2..000000000 --- a/internal/kclvm_py/compiler/extension/plugin/plugin_model.py +++ /dev/null @@ -1,48 +0,0 @@ -from typing import Callable, Optional, Dict -from functools import wraps -import inspect - -import kclvm.kcl.info as kcl_info - -from .plugin import get_plugin_names, get_plugin -from kclvm.api.object import KCLBuiltinFunctionObject - - -PLUGIN_MODULE_NAME = "kcl_plugin." -STANDARD_SYSTEM_MODULE_LOCATION = "kclvm_plugin" - - -def kcl_plugin(func): - @wraps(func) - def decorated(*args, **kwargs): - return func(*args, **kwargs) - - return decorated - - -def new_plugin_function( - name: str, func: Callable -) -> Optional[KCLBuiltinFunctionObject]: - """New a plugin function object using a native plugin function""" - if not func or not name: - return None - return KCLBuiltinFunctionObject(name=name, function=func) - - -def get_plugin_func_objects(plugin_name: str) -> Dict[str, KCLBuiltinFunctionObject]: - """Get all plugin function objects from a plugin named 'plugin_name'""" - if ( - not plugin_name - or plugin_name.replace(PLUGIN_MODULE_NAME, "") not in get_plugin_names() - ): - return {} - module = get_plugin(plugin_name) - members = inspect.getmembers(module) - result = { - kcl_info.demangle(func_name): new_plugin_function( - kcl_info.demangle(func_name), func - ) - for func_name, func in members - if kcl_info.ismangled(func_name) - } - return result diff --git a/internal/kclvm_py/compiler/extension/plugin/template.py b/internal/kclvm_py/compiler/extension/plugin/template.py deleted file mode 100644 index bb1653f5e..000000000 --- a/internal/kclvm_py/compiler/extension/plugin/template.py +++ /dev/null @@ -1,100 +0,0 @@ -# Copyright 2020 The KCL Authors. All rights reserved. - - -def get_plugin_template_code(plugin_name: str) -> str: - return f'''# Copyright 2020 The KCL Authors. All rights reserved. - -INFO = {{ - 'name': '{plugin_name}', - 'describe': '{plugin_name} doc', - 'long_describe': 'long describe', - 'version': '0.0.1', -}} - - -global_int: int = 0 - - -def set_global_int(v: int): - global global_int - global_int = v - - -def get_global_int() -> int: - return global_int - - -def say_hello(msg: str): - print('{plugin_name}.say_hello:', msg) - return None - - -def add(a: int, b: int) -> int: - """add two numbers, and return result""" - return a + b - - -def tolower(s: str) -> str: - return s.lower() - - -def update_dict(d: dict, key: str, value: str) -> dict: - d[key] = value - return d - - -def list_append(l: list, *values) -> list: - for v in values: - l.append(v) - return l - - -def foo(a, b, *, x, **values): - print(a, b, x, values) - return {{'a': a, 'b': b, 'x': x, **values}} -''' - - -def get_plugin_test_template_code(plugin_name: str) -> str: - return """# Copyright 2020 The KCL Authors. All rights reserved. - -# python3 -m pytest - -import plugin - - -def test_add(): - assert plugin.add(1, 2) == 3 - - -def test_tolower(): - assert plugin.tolower('KCL') == 'kcl' - - -def test_update_dict(): - assert plugin.update_dict({{'name': 123}}, 'name', 'kcl')['name'] == 'kcl' - - -def test_list_append(): - l = plugin.list_append(['abc'], 'name', 123) - assert len(l) == 3 - assert l[0] == 'abc' - assert l[1] == 'name' - assert l[2] == 123 - - -def test_foo(): - v = plugin.foo('aaa', 'bbb', x=123, y=234, abcd=1234) - assert len(v) == 5 - assert v['a'] == 'aaa' - assert v['b'] == 'bbb' - assert v['x'] == 123 - assert v['y'] == 234 - assert v['abcd'] == 1234 - - v = plugin.foo('aaa', 'bbb', x=123) - assert len(v) == 3 - assert v['a'] == 'aaa' - assert v['b'] == 'bbb' - assert v['x'] == 123 -""" diff --git a/internal/kclvm_py/compiler/parser/__init__.py b/internal/kclvm_py/compiler/parser/__init__.py deleted file mode 100644 index a64023e0a..000000000 --- a/internal/kclvm_py/compiler/parser/__init__.py +++ /dev/null @@ -1,11 +0,0 @@ -# Copyright 2020 The KCL Authors. All rights reserved. - -from .parser import ParseMode, ParseFile, ParseExpr, LoadProgram - - -__all__ = [ - "ParseMode", - "ParseFile", - "ParseExpr", - "LoadProgram", -] diff --git a/internal/kclvm_py/compiler/parser/lark.proto b/internal/kclvm_py/compiler/parser/lark.proto deleted file mode 100644 index 060a04ea3..000000000 --- a/internal/kclvm_py/compiler/parser/lark.proto +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2020 The KCL Authors. All rights reserved. - -syntax = "proto3"; - -package kclvm.compiler.parser.lark; - -// https://github.com/lark-parser/lark/blob/master/docs/_static/lark_cheatsheet.pdf - -message Tree { - string type = 1; - string token_value = 2; - repeated Tree children = 3; - - int32 line = 101; - int32 column = 102; - int32 end_line = 103; - int32 end_column = 104; -} diff --git a/internal/kclvm_py/compiler/parser/lark_parser.py b/internal/kclvm_py/compiler/parser/lark_parser.py deleted file mode 100644 index 02a09f908..000000000 --- a/internal/kclvm_py/compiler/parser/lark_parser.py +++ /dev/null @@ -1,240 +0,0 @@ -# Copyright 2020 The KCL Authors. All rights reserved. - -import typing -import pathlib - -from lark import Lark -from lark.indenter import Indenter -from lark.tree import Tree as LarkTree -from lark.lexer import Token as LarkToken - -import kclvm.kcl.error as kcl_error -import kclvm.compiler.parser.lark_pb2 as lark_pb - -_CACHE_FILE = pathlib.Path(__file__).parent.joinpath("lark_parser.pickle") -START_RULE = "start" - -filename = "" - - -class KCLIndenter(Indenter): - NL_type = "NEWLINE" - OPEN_PAREN_types = ["LPAR", "LSQB", "LBRACE"] - CLOSE_PAREN_types = ["RPAR", "RSQB", "RBRACE"] - INDENT_type = "_INDENT" - DEDENT_type = "_DEDENT" - tab_len = 4 - _indent_has_space = False # Mark whether there are spaces in an indent_level - _indent_has_tab = False # Mark whether there are tabs in an indent_level - - def __init__(self): - super().__init__() - self.reset_indent_space_tab() - - def reset_indent_space_tab(self): - self._indent_has_space = False - self._indent_has_tab = False - - def process(self, stream): - self.paren_level = 0 - self.indent_level = [0] - self.reset_indent_space_tab() - return self._process(stream) - - def check_tab_error(self, space_count, tab_count, line=None, column=None): - """Check TabError: Inconsistent use of tabs and spaces in indentation""" - self._indent_has_space = True if space_count else self._indent_has_space - self._indent_has_tab = True if tab_count else self._indent_has_tab - if self._indent_has_space and self._indent_has_tab: - import kclvm.compiler.parser.lark_parser as lark_parser - - kcl_error.report_exception( - err_type=kcl_error.ErrType.TabError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=lark_parser.filename, line_no=line, col_no=column - ) - ], - ) - - def handle_NL(self, token): - """Do not edit it, inherit from base class 'Indenter'""" - if self.paren_level > 0: - return - - yield token - - indent_str = token.rsplit("\n", 1)[1] # Tabs and spaces - space_count, tab_count = indent_str.count(" "), indent_str.count("\t") - indent = space_count + tab_count * self.tab_len - self.check_tab_error(space_count, tab_count, token.end_line, token.end_column) - - if indent > self.indent_level[-1]: - self.indent_level.append(indent) - yield LarkToken.new_borrow_pos(self.INDENT_type, indent_str, token) - else: - while indent < self.indent_level[-1]: - self.indent_level.pop() - self.reset_indent_space_tab() - lark_token = LarkToken.new_borrow_pos( - self.DEDENT_type, indent_str, token - ) - yield lark_token - - if indent != self.indent_level[-1]: - import kclvm.compiler.parser.lark_parser as lark_parser - - kcl_error.report_exception( - err_type=kcl_error.ErrType.IndentationError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=lark_parser.filename, - line_no=lark_token.end_line, - col_no=lark_token.end_column, - ) - ], - arg_msg=kcl_error.INDENTATION_ERROR_MSG.format(str(indent)), - ) - - -_kcl_lark_parser: typing.Optional[Lark] = None - - -def GetKclLarkParser() -> Lark: - global _kcl_lark_parser - - if _kcl_lark_parser is None: - _kcl_lark_parser = Lark.open( - "../../kcl/grammar/kcl.lark", - parser="lalr", - propagate_positions=True, - postlex=KCLIndenter(), - rel_to=__file__, - cache=str(_CACHE_FILE), - ) - - return _kcl_lark_parser - - -def IsRuleType(node_type: str) -> bool: - return node_type.islower() - - -def IsTokenType(node_type: str) -> bool: - return node_type.isupper() - - -def GetNode( - node: lark_pb.Tree, node_type: str, *more_node_type: str -) -> typing.Optional[lark_pb.Tree]: - node_list = GetNodeList(node, node_type, *more_node_type, max_size=1) - return node_list[0] if node_list else None - - -def GetNodeList( - node: lark_pb.Tree, - target_node_type: str, - *more_target_node_type: str, - max_size=0, - recursively: bool = True -) -> typing.List[lark_pb.Tree]: - node_type_list = [target_node_type, *more_target_node_type] - - if not node: - return [] - - if node.type in node_type_list: - return [node] # OK - - # try sub node - node_list = [] - for n in node.children or []: - if n.type in node_type_list: - node_list.append(n) - if 0 < max_size <= len(node_list): - return node_list - continue - if recursively: - node_list.extend( - GetNodeList( - n, target_node_type, *more_target_node_type, max_size=max_size - ) - ) - if 0 < max_size <= len(node_list): - return node_list - - return node_list - - -def WalkTree(t: lark_pb.Tree, walk_fn): - walk_fn(t) - for n in t.children: - WalkTree(n, walk_fn) - - -def ParseFile(filename: str, code: str, ignore_file_line: bool = False) -> lark_pb.Tree: - if not code: - with open(filename) as f: - code = str(f.read()) - return ParseCode(code, ignore_file_line=ignore_file_line) - - -def ParseCode(src: str, ignore_file_line: bool = False) -> lark_pb.Tree: - def _pb_build_Tree(_t: LarkTree) -> lark_pb.Tree: - if isinstance(_t, LarkTree): - rule_type = _t.data - - assert rule_type.islower() - assert len(_t.children) >= 0 - - # Empty file and return a empty lark tree node - if rule_type == START_RULE and not _t.children: - t = lark_pb.Tree( - type=rule_type, - token_value="", - children=[], - ) - elif not ignore_file_line: - t = lark_pb.Tree( - type=rule_type, - token_value="", # rule, not token - children=[], - line=_t.meta.line, - column=_t.meta.column, - end_line=_t.meta.end_line, - end_column=_t.meta.end_column, - ) - else: - t = lark_pb.Tree( - type=rule_type, token_value="", children=[] # rule, not token - ) - - for v in _t.children: - t.children.append(_pb_build_Tree(v)) - - return t - - if isinstance(_t, LarkToken): - token_type = _t.type - - assert token_type.isupper() - - if not ignore_file_line: - return lark_pb.Tree( - type=token_type, - token_value=_t.value, - children=[], - line=_t.line, - column=_t.column, - end_line=_t.end_line, - end_column=_t.end_column, - ) - else: - return lark_pb.Tree(type=token_type, token_value=_t.value, children=[]) - - return lark_pb.Tree() - - # To prevent empty files and files that only contain line continuation symbols - src += "\n" - tree = GetKclLarkParser().parse(src) - return _pb_build_Tree(tree) diff --git a/internal/kclvm_py/compiler/parser/lark_pb2.py b/internal/kclvm_py/compiler/parser/lark_pb2.py deleted file mode 100644 index 5a9a1df8b..000000000 --- a/internal/kclvm_py/compiler/parser/lark_pb2.py +++ /dev/null @@ -1,31 +0,0 @@ -# Copyright 2021 The KCL Authors. All rights reserved. - -from __future__ import annotations # for python 3.7 - -from typing import List -from dataclasses import dataclass, field - -# protobuf: -# -# message Tree { -# string type = 1; -# string token_value = 2; -# repeated Tree children = 3; -# -# int32 line = 101; -# int32 column = 102; -# int32 end_line = 103; -# int32 end_column = 104; -# } - - -@dataclass -class Tree: - type: str = "" - token_value: str = "" - children: List[Tree] = field(default_factory=lambda: []) - - line: int = 0 - column: int = 0 - end_line: int = 0 - end_column: int = 0 diff --git a/internal/kclvm_py/compiler/parser/lark_tree.py b/internal/kclvm_py/compiler/parser/lark_tree.py deleted file mode 100644 index 0560ebb66..000000000 --- a/internal/kclvm_py/compiler/parser/lark_tree.py +++ /dev/null @@ -1,413 +0,0 @@ -#! /usr/bin/env python3 - -import os -import json -from typing import Union, List, Dict, Optional -from copy import deepcopy - -from lark.exceptions import UnexpectedCharacters, UnexpectedToken -from lark.tree import Tree as LarkTree -from lark.lexer import Token as LarkToken - -import kclvm.kcl.error as kcl_error -from kclvm.compiler.parser.lark_parser import GetKclLarkParser - -TREE_TYPE = "tree" -TOKEN_TYPE = "token" - - -class Token: - ASSIGN = "ASSIGN" # "=" - COLON = "COLON" # ":" - SEMI_COLON = "SEMI_COLON" # ";" - COMMA = "COMMA" # "," - LEFT_PARENTHESES = "LEFT_PARENTHESES" # "(" - RIGHT_PARENTHESES = "RIGHT_PARENTHESES" # ")" - LEFT_BRACKETS = "LEFT_BRACKETS" # "[" - RIGHT_BRACKETS = "RIGHT_BRACKETS" # "]" - LEFT_BRACE = "LEFT_BRACE" # "{" - RIGHT_BRACE = "RIGHT_BRACE" # "}" - PLUS = "PLUS" # "+" - MINUS = "MINUS" # "-" - MULTIPLY = "MULTIPLY" # "*" - DIVIDE = "DIVIDE" # "/" - MOD = "MOD" # "%" - DOT = "DOT" # "." - AND = "AND" # "&" - OR = "OR" # "|" - XOR = "XOR" # "^" - NOT = "NOT" # "~" - LESS_THAN = "LESS_THAN" # "<" - GREATER_THAN = "GREATER_THAN" # ">" - EQUAL_TO = "EQUAL_TO" # "==" - NOT_EQUAL_TO = "NOT_EQUAL_TO" # "!=" - GREATER_THAN_OR_EQUAL_TO = "GREATER_THAN_OR_EQUAL_TO" # ">=" - LESS_THAN_OR_EQUAL_TO = "LESS_THAN_OR_EQUAL_TO" # "<=" - DOUBLE_STAR = "DOUBLE_STAR" # "**" - DOUBLE_DIVIDE = "DOUBLE_DIVIDE" # "//" - SHIFT_LEFT = "SHIFT_LEFT" # "<<" - SHIFT_RIGHT = "SHIFT_RIGHT" # ">>" - - COMP_PLUS = "COMP_PLUS" # "+=" - COMP_MINUS = "COMP_MINUS" # "-=" - COMP_MULTIPLY = "COMP_MULTIPLY" # "*=" - COMP_DIVIDE = "COMP_DIVIDE" # "/=" - COMP_MOD = "COMP_MOD" # "%=" - COMP_AND = "COMP_AND" # "&=" - COMP_OR = "COMP_OR" # "|=" - COMP_XOR = "COMP_XOR" # "^=" - COMP_NOT = "COMP_NOT" # "~=" - COMP_DOUBLE_STAR = "COMP_DOUBLE_STAR" # "**=" - COMP_DOUBLE_DIVIDE = "COMP_DOUBLE_DIVIDE" # "//=" - COMP_SHIFT_LEFT = "COMP_SHIFT_LEFT" # "<<=" - COMP_SHIFT_RIGHT = "COMP_SHIFT_RIGHT" # ">>=" - - IMPORT = "IMPORT" # "import" - AS = "AS" # "as" - DEF = "DEF" # "def" - LAMBDA = "LAMBDA" # "lambda" - SCHEMA = "SCHEMA" # "schema" - MIXIN = "MIXIN" # "mixin" - PROTOCOL = "PROTOCOL" # "protocol" - RELAXED = "RELAXED" # "relaxed" - CHECK = "CHECK" # "check" - INIT = "INIT" # "init" - TYPE = "TYPE" # "type" - FOR = "FOR" # "for" - ASSERT = "ASSERT" # "assert" - IF = "IF" # "if" - ELIF = "ELIF" # "elif" - ELSE = "ELSE" # "else" - L_OR = "L_OR" # "or" - L_AND = "L_AND" # "and" - L_NOT = "NOT" # "not" - L_L_NOT = "L_NOT" - - IN = "IN" # "in" - IS = "IS" # "is" - FINAL = "FINAL" # "final" - - ALL = "ALL" - ANY = "ANY" - MAP = "MAP" - FILTER = "FILTER" - - TRUE = "TRUE" - FALSE = "FALSE" - NONE = "NONE" - - NAME = "NAME" - COMMENT = "COMMENT" - NEWLINE = "NEWLINE" - - STRING = "STRING" - LONG_STRING = "LONG_STRING" - - DEC_NUMBER = "DEC_NUMBER" - HEX_NUMBER = "HEX_NUMBER" - OCT_NUMBER = "OCT_NUMBER" - BIN_NUMBER = "BIN_NUMBER" - FLOAT_NUMBER = "FLOAT_NUMBER" - IMAG_NUMBER = "IMAG_NUMBER" - - RIGHT_ARROW = "RIGHT_ARROW" - - @staticmethod - def is_string(token: str): - return token in [Token.STRING, Token.LONG_STRING] - - -class Tree: - DICT_KEY = "dict_key" - DICT_COMP = "dict_comp" - LIST_COMP = "list_comp" - DICT_EXPR = "dict_expr" - LIST_EXPR = "list_expr" - MULTI_EXPR = "multi_expr" - DOUBLE_STAR_EXPR = "double_star_expr" - CONFIG_EXPR = "config_expr" - SUB_SCRIPT = "subscript" - IDENTIFIER = "identifier" - STR_CALL_EXPR = "str_call_expr" - CALL_EXPR = "call_expr" - CALL_SUFFIX = "call_suffix" - SLICE_SUFFIX = "slice_suffix" - COMP_ITER = "comp_iter" - COMP_FOR = "comp_for" - COMP_IF = "comp_if" - COMP_CLAUSE = "comp_clause" - TEST = "test" - OR_TEST = "or_test" - SIMPLE_EXPR = "simple_expr" - EXPR = "expr" - PRIMARY_EXPR = "primary_expr" - STMT = "stmt" - IF_STMT = "if_stmt" - SCHEMA_MEMBER_STMT = ("schema_member_stmt",) - SCHEMA_BODY = "schema_body" - SCHEMA_ARGUMENTS = "schema_arguments" - MIXINS = ("mixins",) - TYPE_ALIAS_STMT = "type_alias_stmt" - SCHEMA_STMT = "schema_stmt" - SIMPLE_STMT = "simple_stmt" - DOC_STMT = "doc_stmt" - COMPOUND_STMT = "compound_stmt" - SMALL_STMT = "small_stmt" - IMPORT_STMT = "import_stmt" - ASSIGN_STMT = "assign_stmt" - ASSERT_STMT = "assert_stmt" - EXPR_STMT = "expr_stmt" - MEMBER_STMT = "member_stmt" - TYPE = "type" - EXECUTION_BLOCK = "execution_block" - STRING_DOT_NAME = "string_dot_name" - - SELECTOR_EXPR = "selector_expr" - SELECTOR_SUFFIX = "selector_suffix" - LIST_SELECTOR_SUFFIX = "list_selector_suffix" - DICT_SELECTOR_SUFFIX = "dict_selector_suffix" - - -BRACKETS_TOKENS = [ - Token.LEFT_PARENTHESES, # "(" - Token.RIGHT_PARENTHESES, # ")" - Token.LEFT_BRACKETS, # "[" - Token.RIGHT_BRACKETS, # "]" - Token.LEFT_BRACE, # "{" - Token.RIGHT_BRACE, # "}" -] -OPERATOR_TOKENS = { - Token.ASSIGN, # "=" - Token.PLUS, # "+" - Token.MINUS, # "-" - Token.MULTIPLY, # "*" - Token.DIVIDE, # "/" - Token.MOD, # "%" - Token.AND, # "&" - Token.OR, # "|" - Token.XOR, # "^" - Token.NOT, # "~" - Token.LESS_THAN, # "<" - Token.GREATER_THAN, # ">" - Token.EQUAL_TO, # "==" - Token.NOT_EQUAL_TO, # "!=" - Token.GREATER_THAN_OR_EQUAL_TO, # ">=" - Token.LESS_THAN_OR_EQUAL_TO, # "<=" - Token.DOUBLE_STAR, # "**" - Token.DOUBLE_DIVIDE, # "//" - Token.SHIFT_LEFT, # "<<" - Token.SHIFT_RIGHT, # ">>" - Token.COMP_PLUS, # "+=" - Token.COMP_MINUS, # "-=" - Token.COMP_MULTIPLY, # "*=" - Token.COMP_DIVIDE, # "/=" - Token.COMP_MOD, # "%=" - Token.COMP_AND, # "&=" - Token.COMP_OR, # "|=" - Token.COMP_XOR, # "^=" - Token.COMP_NOT, # "~=" - Token.COMP_DOUBLE_STAR, # "**=" - Token.COMP_DOUBLE_DIVIDE, # "//=" - Token.COMP_SHIFT_LEFT, # "<<=" - Token.COMP_SHIFT_RIGHT, # ">>=" -} -SEPERATOR_TOKENS = { - Token.COLON, # ":" - Token.SEMI_COLON, # ";" - Token.COMMA, # "," -} -FUNCTION_EXPRS = { - Tree.CALL_EXPR, - Tree.STR_CALL_EXPR, -} -_WALK_FUNCTION_PREFIX = "walk_" - -AstType = Dict[str, Union[str, List]] - - -class TreeWalker: - """ - The TreeWalk class can be used as a superclass in order - to walk an AST or similar tree. - - This class is meant to be subclassed, with the subclass adding walker - methods. - - Per default the walker functions for the nodes are ``'walk_'`` + - class name of the node. So a `expr_stmt` node visit function would - be `walk_expr_stmt`. This behavior can be changed by overriding - the `walk` method. If no walker function exists for a node - (return value `None`) the `generic_walker` walker is used instead. - """ - - def __init__(self) -> None: - pass - - def walk(self, node: AstType) -> None: - """Visit a node.""" - name = node["name"] - method = _WALK_FUNCTION_PREFIX + name - walker = getattr(self, method, self.generic_walk) - walker(node) - - def generic_walk(self, node: AstType): - """Called if no explicit walker function exists for a node.""" - children_key = "children" - if children_key in node: - for n in node[children_key]: - self.walk(n) - else: - self.walk(node) - - def walk_nodes(self, *nodes: Union[AstType, str]) -> None: - """Write nodes""" - if not nodes: - return - for node in nodes: - self.walk_node(node) - - def walk_node(self, node: Union[AstType, str]) -> None: - """Write node""" - self.walk(node) - - def get(self, node: AstType, name: str) -> Optional[AstType]: - """ - Get children from 'node' named 'name' - """ - if not node or "children" not in node: - return None - for i, n in enumerate(node["children"]): - if n["name"] == name: - node["children"] = node["children"][i + 1 :] - return n - return None - - def has(self, node: AstType, name: str) -> bool: - """ - Whether 'node' has the children named 'name' - """ - return name in [n["name"] for n in node["children"]] - - def get_value(self, node: AstType, default: Optional[str] = None) -> Optional[str]: - """ - Get tree node value recursively - """ - if not node: - return default - if node["type"] == TOKEN_TYPE: - return node.get("value", default) - elif node["type"] == TREE_TYPE: - return "".join(self.get_value(n) for n in node["children"]) - return default - - def get_children_value( - self, node: AstType, name: Optional[str] = None, default: Optional[str] = None - ) -> Optional[str]: - """ - Get children value recursively from 'node' named 'name' - """ - return self.get_value(self.get(node, name), default) if name else default - - def get_internal( - self, node: AstType, begin_name: str, end_name: str - ) -> Optional[List[AstType]]: - """ - Get children from 'begin_name' to 'end_name' - """ - begin_index = -1 - end_index = -1 - for i, n in enumerate(node["children"]): - if n["name"] == begin_name and begin_index == -1: - begin_index = i - if n["name"] == end_name: - end_index = i - if end_index >= begin_index: - result = deepcopy(node["children"][begin_index : end_index + 1]) - node["children"] = node["children"][end_index + 1 :] - return result - return None - - -def build_children(t: LarkTree) -> List[AstType]: - """ - Build json ast children of tree node, children type can be token or tree - """ - return list(map(lambda c: walk_lark_tree(c), t.children)) - - -def build_token_content(t: LarkToken) -> AstType: - """ - Build json ast token node - """ - return { - "type": TOKEN_TYPE, - "name": t.type, - "value": t.value, - "line": t.line, - "column": t.column, - } - - -def build_tree_content(t: LarkTree) -> AstType: - """ - Build json ast tree node - """ - return { - "type": TREE_TYPE, - "name": t.data, - "children": build_children(t), - } - - -def walk_lark_tree(t: Union[LarkTree, LarkToken]) -> AstType: - """ - Traverse the lark tree and return python dict - """ - if isinstance(t, LarkTree): - return build_tree_content(t) - elif isinstance(t, LarkToken): - return build_token_content(t) - else: - kcl_error.report_exception( - err_type=kcl_error.ErrType.CompileError_TYPE, - arg_msg="Unknown node type: {}".format(type(t)), - ) - - -def get_lark_tree_from_expr( - source: str, to_json_str: bool = True -) -> Union[str, AstType]: - try: - # Get lark parse tree - parse_tree = GetKclLarkParser().parse(source + "\n") - # Convert python dict to standard json - ast = walk_lark_tree(parse_tree) - return (json.dumps(ast) + "\n") if to_json_str else ast - except ( - UnexpectedCharacters, - UnexpectedToken, - ) as err: - kcl_error.report_exception( - err_type=kcl_error.ErrType.InvalidSyntax_TYPE, - file_msgs=[kcl_error.ErrFileMsg(line_no=err.line, col_no=err.column)], - ) - except Exception as err: - kcl_error.report_exception( - err_type=kcl_error.ErrType.CompileError_TYPE, arg_msg=str(err) - ) - - -def get_lark_tree_from_file(filename: str, to_json_str: bool = True) -> str: - """ - Get kcl json ast from .k file - """ - with open(filename, "r", encoding="utf-8") as pyfile: - source = pyfile.read() - return get_lark_tree_from_expr(source, to_json_str) - - -def get_lark_tree_from_path(path: str) -> List[str]: - """ - Get kcl json ast from kmodule package - """ - return [get_lark_tree_from_file(file) for file in sorted(os.listdir(path))] diff --git a/internal/kclvm_py/compiler/parser/parser.py b/internal/kclvm_py/compiler/parser/parser.py deleted file mode 100644 index ac002776a..000000000 --- a/internal/kclvm_py/compiler/parser/parser.py +++ /dev/null @@ -1,3036 +0,0 @@ -"""The `parser` file mainly contains the `walker` which is used to -traversal the lark tree generated by lark-parser and generate the kcl -ast. -The KCL parser is mainly based on `ast.TreeWalker` to implement -traversal of all lark tree nodes, generate corresponding ast nodes. - -The `walk` method will automatically call the walk_{node name} method -corresponding lark tree nodes. - -The work flow of walk_{node name} method looks like: - -`lark tree node -> walk -> walk_{node name} -> ast tree node` - -The `generic_walk` method is the default implementation of `walk` method -If one lark tree node does not need the walk_{node name} method. - -The work flow of `generic_walk` method looks like: - -`lark tree node -> walk -> # no walk_{node name} # -> generic_walk -> ast tree node` - -There are also some util methods to simplify each walk_{node name} -method in class `ASTBuilderWalker`. - -:note: Some util methods are for special scenarios. When using these methods, -please carefully read the comments of the method -:copyright: Copyright 2020 The KCL Authors. All rights reserved. -""" -import typing -import os -import re -import glob - -from ast import literal_eval -from pathlib import Path -from enum import IntEnum - -import lark - -import kclvm.kcl.error as kcl_error -import kclvm.config -import kclvm.api.object.internal as internal -import kclvm.compiler.vfs as vfs -import kclvm.compiler.parser.lark_pb2 as lark_pb -import kclvm.compiler.parser.lark_parser as lark_parser -import kclvm.compiler.parser.lark_tree as lark_tree -import kclvm.compiler.extension.builtin.builtin as builtin -import kclvm.compiler.astutil.fix as fix -import kclvm.compiler.build.preprocess as preprocess -import kclvm.kcl.ast as ast -import kclvm.internal.util.check_utils as check_utils - -from kclvm.internal.util.check_utils import PreCheck, PostCheck, CheckRules -from kclvm.kcl.ast.precedence import OpPrecedence, OP_PREC_MAP - -_INVALID_NEWLINE_STRING_MSG = "invalid NEWLINE token string value {}" - -ENDLINE_TOKEN = "\n" -COMMENT_START_TOKEN = "#" -STRING_INTERPOLATION_REGEX = re.compile(r"\$\{(.*?(:.*?)?)\}") -INLINE_COMMENT_WITH_MULTILINE_REGEX = re.compile("#[^\n]*[\n\t ]*") -KCL_MOD_PATH_ENV = "${KCL_MOD}" -DEFAULT_CACHE_OPTION = vfs.CacheOption() -AST_WITH_PARENT_CACHE_OPTION = vfs.CacheOption(cache_dir=vfs.FST_CACHE_DIR) - - -class ParseMode(IntEnum): - Null = 0 - ParseComments = 1 - - -class StrWithLocation(str): - def __init__(self) -> None: - super().__init__() - self.line: int = 0 - self.column: int = 0 - self.end_line: int = 0 - self.end_column: int = 0 - - def copy_line_column_from(self, node): - self.line = node.line - self.column = node.column - self.end_line = node.end_line - self.end_column = node.end_column - - return self - - -class Token(StrWithLocation): - def __init__(self, value: typing.Optional[str] = None) -> None: - super().__init__() - self.value = value - - -class Mixins(ast.AST): - def __init__(self) -> None: - super().__init__() - self.values: typing.List[ast.Identifier] = [] - - @PreCheck((lambda v: CheckRules.check_type_not_none(v, ast.Identifier)), "value") - def append(self, value: ast.Identifier): - self.values.append(value) - - -def report_complier_err( - arg=None, - err_type=kcl_error.ErrType.CompileError_TYPE, - filename=None, - line_no=None, - col_no=None, - end_col_no=None, -): - kcl_error.report_exception( - err_type=err_type, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=filename, line_no=line_no, col_no=col_no, end_col_no=end_col_no - ) - ], - arg_msg=arg, - ) - - -def report_syntax_err( - arg=None, - err_type=kcl_error.ErrType.IllegalArgumentError_Syntax_TYPE, - filename=None, - line_no=None, - col_no=None, - end_col_no=None, - source=None, -): - kcl_error.report_exception( - err_type=err_type, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=filename, - line_no=line_no, - col_no=col_no, - end_col_no=end_col_no, - src_code=source, - ) - ], - arg_msg=arg, - ) - - -def get_ast_cache_option(set_ast_parent: bool = False) -> vfs.CacheOption: - """Get AST cache option with the `set_ast_parent` parameter""" - return AST_WITH_PARENT_CACHE_OPTION if set_ast_parent else DEFAULT_CACHE_OPTION - - -class ASTBuilderWalker(ast.TreeWalker): - def __init__(self): - self.tokens_with_pos = [ - ast.LarkToken.L_COLON, - ast.LarkToken.L_RIGHT_BRACKETS, - ast.LarkToken.L_LEFT_BRACKETS, - ] - - def walk_non_token_children( - self, node: lark_pb.Tree - ) -> typing.List[typing.Union[None, ast.AST, list, str, tuple]]: - """ - Traverse all non-terminal child nodes of the current lark tree node, - and call the corresponding walk method. - Return the list of the walk method returns. - - Args: - node: The lark tree node - - Returns: the list of AST node generated from child nodes of the current lark tree node - - """ - return [ - self.walk(n) for n in node.children if not lark_parser.IsTokenType(n.type) - ] - - def walk_filtered_elements_ordered_by_types( - self, - node: lark_pb.Tree, - filter_types: typing.List[str], - with_token: bool = False, - ) -> typing.List[typing.Union[None, ast.AST, list, str, tuple]]: - """ - Traverse child nodes, not be selected by node types, of the current lark tree node, - and call the corresponding walk method. - Return the list of the walk method returns. - - Args: - node: The lark tree node - filter_types: The list of nodes that do not need to be traversed - with_token: A bool for traverses the terminal node or not - - Returns: the list of AST node generated from child nodes selected of the current lark tree node - - """ - if with_token: - return [self.walk(n) for n in node.children if n.type not in filter_types] - else: - return [ - self.walk(n) - for n in node.children - if n.type not in filter_types and not lark_parser.IsTokenType(n.type) - ] - - def walk_elements_ordered_by_types( - self, node: lark_pb.Tree, node_types: typing.List[str] - ) -> typing.Tuple: - """ - Traverse child nodes, selected by node types, of the current lark tree node, - and call the corresponding walk method. - Return the tuple of the walk method returns. - - Args: - node: The lark tree node - node_types: The list of nodes that need to be traversed - - Returns: the tuple of the walk method returns - - Notes: The order of the elements in node_types must be the same as the order of the lark tree node children. - The order of the elements in return tuple will be the same as the order of the node_types. - - """ - p: typing.List[typing.Union[None, ast.AST, list, str, tuple]] = [] - for n in node.children: - for i, nt in enumerate(node_types): - if n.type == nt: - if i < len(p): - continue - p.extend([None] * (i - len(p))) - p.append(self.walk(n)) - break - - p.extend([None] * (len(node_types) - len(p))) - - assert len(p) == len(node_types) - return tuple(p) - - def walk_all_by_type( - self, node: lark_pb.Tree, node_type: str - ) -> typing.List[typing.Union[None, ast.AST, list, str, tuple]]: - """ - Find all children nodes, selected by node type, of the current lark tree node, - and call the corresponding walk methods. - Return the list of the walk method returns. - - Args: - node: the lark tree node - node_type: type of selected node - - Returns: the list of the walk method returns. - - """ - return [self.walk(n) for n in node.children if n.type == node_type] - - def walk_one_by_type( - self, node: lark_pb.Tree, node_type: str - ) -> typing.Union[None, ast.AST, list, str, tuple]: - """ - Find the first child node, selected by node type, of the current lark tree node, - and call the corresponding walk method. - Return the walk method return. - - Args: - node: the lark tree node - node_type: type of selected node - - Returns: the walk method return. - - """ - for n in node.children: - if n.type == node_type: - return self.walk(n) - return None - - @PreCheck((lambda v: CheckRules.check_type_not_none(v, lark_pb.Tree)), "node") - @PostCheck(lambda v: CheckRules.check_type_allow_none(v, Token)) - def get_token_with_pos(self, node: lark_pb.Tree) -> typing.Optional[Token]: - return ( - Token(node.token_value).copy_line_column_from(node) - if node.type in self.tokens_with_pos - else None - ) - - def walk(self, node: lark_pb.Tree) -> typing.Union[None, ast.AST, list, str, tuple]: - """ - The walk method will automatically call the walk_{node name} method - corresponding lark tree nodes. - Return the ast node, the list/tuple of ast nodes and the str of token value generated by lark tree nodes - - Args: - node: the lark tree node - - Returns: the ast node, the list/tuple of ast nodes and the str of token value generated by lark tree nodes - - """ - assert node - method = self._WALK_FUNCTION_PREFIX + self.get_node_name(node) - walker = getattr(self, method, self.generic_walk) - return walker(node) - - def generic_walk( - self, node: lark_pb.Tree - ) -> typing.Union[None, ast.AST, list, str, tuple]: - """ - The generic_walk method is the default implementation of `walk` method - If one lark tree node does not need the walk_{node name} method. - Up to now, only the node with one child, the node with one non-terminal - child and one "NEWLINE" child, the node with one terminal node is allowed - - Args: - node: the lark tree node in Allowed Cases, Allowed Cases : A -> B, A->B NEWLINE, A -> TOKEN - - Returns: For each case in allowed cases, return walk(B), walk(B), TOKEN.token_value - - """ - assert node - assert len(node.children) <= 2 - if len(node.children) == 1: - return self.walk(node.children[0]) - elif ( - len(node.children) == 2 and node.children[1].type == ast.LarkToken.L_NEWLINE - ): - return self.walk(node.children[0]) - elif len(node.children) == 0 and lark_parser.IsTokenType(node.type): - return ( - node.token_value - if node.type not in self.tokens_with_pos - else self.get_token_with_pos(node) - ) - - raise AttributeError(f"Some 'walk_{node.type}()' methods are missing") - - def get_node_name(self, node: lark_pb.Tree) -> str: - return node.type - - -class ASTBuilder(ASTBuilderWalker): - def __init__( - self, - root: lark_pb.Tree, - *, - pkg: str = "", - name: str = "", - filename: str = "", - mode: ParseMode = ParseMode.Null, - ): - super().__init__() - self.root: lark_pb.Tree = root - self.pkg: str = pkg - self.filename: str = filename - self.name = name - self.mode = mode - self.ast_prece_table: dict = {} - - def BuildAST(self) -> ast.Module: - return check_utils.check_allow_none(self.walk(self.root), ast.Module) - - def register_precedence( - self, - op: typing.Union[ast.BinOp, ast.AugOp, ast.UnaryOp, ast.CmpOp], - node: typing.Union[ast.BinOp, ast.AugOp, ast.UnaryOp, ast.CmpOp, ast.AST], - ): - if not op or not node: - raise ValueError("A operation symbol is needed for precedence registration") - if not isinstance(op, (ast.BinOp, ast.AugOp, ast.UnaryOp, ast.CmpOp)): - raise ValueError( - "{} can not be used to register precedence".format(type(op).__name__) - ) - if not isinstance( - node, (ast.BinOp, ast.AugOp, ast.UnaryOp, ast.CmpOp, ast.AST) - ): - raise ValueError("{} do not need precedence".format(type(node).__name__)) - - prece = OP_PREC_MAP[op] - self.ast_prece_table[hash(node)] = prece - - def get_precedence( - self, node: typing.Union[ast.BinOp, ast.AugOp, ast.UnaryOp, ast.CmpOp, ast.AST] - ) -> int: - return self.ast_prece_table.get(hash(node), OpPrecedence.HIGHEST) - - @property - def is_parse_comments(self) -> bool: - return bool(self.mode & ParseMode.ParseComments) - - def split_newline_value(self, value: str) -> typing.List[str]: - """Split a NEWLINE token value into newline parts and inline comment parts - Input: "\n \n # comment \n # comment \n\n # comment \n" - Output: ["\n \n ", "# comment ", "\n ", "# comment ", "\n\n ", "# comment ", "\n"] - """ - if not value: - return [] - value = value.replace("\r", ENDLINE_TOKEN).replace("\t", " ") - parts: typing.List[str] = [] - # Mark containing COMMENT token - index = value.find(COMMENT_START_TOKEN) - if index == -1: - return [value] # Single NEWLINE without COMMENT - elif index > 0: - parts.append(value[:index]) # Add first NEWLINE token - inline_comments = INLINE_COMMENT_WITH_MULTILINE_REGEX.findall(value) - for comment in inline_comments: - index = comment.find(ENDLINE_TOKEN) - if index == -1: - report_complier_err( - _INVALID_NEWLINE_STRING_MSG.format(comment), filename=self.filename - ) - parts.append(comment[:index]) # Add COMMENT token - parts.append(comment[index:]) # Add NEWLINE token - if len(parts) > 1 and ENDLINE_TOKEN not in parts[-1]: - # Last part is not NEWLINE, raise an error - report_complier_err( - _INVALID_NEWLINE_STRING_MSG.format(value), filename=self.filename - ) - return parts - - def lark_name_to_ast_name(self, lark_name: lark_pb.Tree) -> ast.Name: - assert lark_name.type == lark_tree.Token.NAME - return ast.Name(value=lark_name.token_value).set_ast_position( - lark_name, filename=self.filename - ) - - def walk_NEWLINE(self, node: lark_pb.Tree) -> typing.List[ast.Comment]: - """Syntax - COMMENT: /#[^\n]*/ - NEWLINE: ( /\r?\n[\t ]*/ | COMMENT )+ - """ - if not node or node.type != ast.LarkToken.L_NEWLINE: - return [] - if not self.is_parse_comments: - return [] - parts = self.split_newline_value(node.token_value) - newline_count = 0 - blank_count = 0 - comments: typing.List[ast.Comment] = [] - col_no = node.column - for part in parts: - if part and part.startswith(COMMENT_START_TOKEN): - comments.append( - ast.Comment( - filename=self.filename, - line=node.line + newline_count, - end_line=node.line + newline_count, - column=col_no + blank_count, - end_column=col_no + blank_count + len(part), - text=part, - ) - ) - else: - newline_count += part.count("\n") - blank_count += part[part.rfind("\n") :].count(" ") - col_no = 1 if newline_count > 0 else node.column - return comments - - def walk_start(self, node: lark_pb.Tree) -> ast.Module: - """Syntax - start: (NEWLINE | statement)* - statement: simple_stmt | compound_stmt - simple_stmt: (assign_stmt | expr_stmt | assert_stmt | import_stmt | type_alias_stmt) NEWLINE - compound_stmt: if_stmt | schema_stmt - """ - - def __build_doc() -> str: - if not p.doc and len(p.body) >= 1: - for i, stmt in enumerate(p.body): - p.body[i].filename = p.filename - if isinstance(stmt, ast.ExprStmt): - expr_stmt = typing.cast(ast.ExprStmt, stmt) - if len(expr_stmt.exprs) == 1 and isinstance( - expr_stmt.exprs[0], ast.StringLit - ): - str_lit = check_utils.check_not_none( - expr_stmt.exprs[0], ast.StringLit - ) - if str_lit.is_long_string: - return self.simplify_StringLitValue(str_lit) - break - return "" - - def __build_comments(): - if not self.is_parse_comments: - return [] - comments: typing.List[ast.Comment] = [] - newline_token_list = lark_parser.GetNodeList(node, ast.LarkToken.L_NEWLINE) - for newline in newline_token_list: - comments.extend(self.walk(newline)) - return comments - - p = check_utils.check_not_none( - ast.ASTFactory.get_ast_module(node, self.pkg, self.filename, self.name), - ast.Module, - ) - - p.body = check_utils.check_all_allow_none( - list, self.walk_non_token_children(node), ast.Stmt - ) - p.doc = check_utils.check_allow_none(__build_doc(), str) - p.comments = check_utils.check_all_allow_none( - list, __build_comments(), ast.Comment - ) - - if not self.is_parse_comments: - if p.body: - p.set_end_line_column(p.body[-1]) - else: - p.offset_end_line(-1) - else: - if p.body and p.comments: - if p.body[-1].end_line > p.comments[-1].end_line: - p.set_end_line_column(p.body[-1]) - else: - p.set_end_line_column(p.comments[-1]) - elif p.comments: - p.set_end_line_column(p.comments[-1]) - elif p.body: - p.set_end_line_column(p.body[-1]) - else: - p.offset_end_line(-1) - - return p - - def walk_unification_stmt(self, node: lark_pb.Tree) -> ast.UnificationStmt: - """Syntax - unification_stmt: NAME COLON schema_expr - """ - stmt = ast.ASTFactory.get_ast(ast.UnificationStmt, node, self.filename) - stmt.target, stmt.value = self.walk(node.children[0]), self.walk( - node.children[2] - ) - stmt.target.ctx = ast.ExprContext.STORE - return stmt - - # ----------------------------------------------------- - # type_alias_stmt - # ----------------------------------------------------- - - def walk_type_alias_stmt(self, node: lark_pb.Tree) -> ast.TypeAliasStmt: - """Syntax - type_alias_stmt: "type" NAME ASSIGN type - """ - stmt = ast.ASTFactory.get_ast(ast.TypeAliasStmt, node, self.filename) - types = [ast.LarkToken.L_NAME, ast.LarkToken.L_type] - name, type_node = self.walk_elements_ordered_by_types(node, types) - stmt.type_value = check_utils.check_allow_none(type_node, ast.Type) - stmt.type_name = check_utils.check_not_none(name, ast.Identifier) - return stmt - - # ----------------------------------------------------- - # assign_stmt - # ----------------------------------------------------- - - def walk_assign_stmt( - self, node: lark_pb.Tree - ) -> typing.Union[ast.AssignStmt, ast.AugAssignStmt]: - """Syntax - assign_stmt: identifier [COLON type] (ASSIGN identifier)* ASSIGN test - | identifier (COMP_PLUS | COMP_MINUS | COMP_MULTIPLY | COMP_DOUBLE_STAR | COMP_DIVIDE - | COMP_DOUBLE_DIVIDE | COMP_MOD | COMP_AND | COMP_OR | COMP_XOR | COMP_SHIFT_LEFT - | COMP_SHIFT_RIGHT | L_OR | L_AND) - test - """ - - def __build_assign_stmt() -> ast.AssignStmt: - assign_stmt: ast.AssignStmt = check_utils.check_not_none( - ast.ASTFactory.get_ast(ast.AssignStmt, node, self.filename), - ast.AssignStmt, - ) - - assign_stmt.targets = targets - assign_stmt.type_annotation = ( - type_annotation_node.plain_type_str if type_annotation_node else None - ) - assign_stmt.type_annotation_node = type_annotation_node - for target in assign_stmt.targets: - target.ctx = ast.ExprContext.STORE - assign_stmt.value = test - return assign_stmt - - def __build_aug_assign_stmt() -> ast.AugAssignStmt: - aug_assign_stmt = check_utils.check_not_none( - ast.ASTFactory.get_ast(ast.AugAssignStmt, node, self.filename), - ast.AugAssignStmt, - ) - - op_node = node.children[1] if len(node.children) == 3 else None - aug_assign_stmt.op = ast.AugOp(op_node.type) - aug_assign_stmt.target = targets[0] - aug_assign_stmt.target.ctx = ast.ExprContext.AUGSTORE - aug_assign_stmt.value = test - return aug_assign_stmt - - targets = check_utils.check_all_not_none( - list, - self.walk_all_by_type(node, ast.LarkToken.L_identifier), - ast.Identifier, - ) - - test = ( - check_utils.check_not_none(self.walk(node.children[-1]), ast.Expr) - if len(node.children) > 0 - else None - ) - - types = [ast.LarkToken.L_type, ast.LarkToken.L_ASSIGN] - type_annotation_node, has_assign = self.walk_elements_ordered_by_types( - node, types - ) - type_annotation_node: ast.Type = check_utils.check_allow_none( - type_annotation_node, ast.Type - ) - has_assign = check_utils.check_allow_none(has_assign, str) - - if has_assign: - return __build_assign_stmt() - elif len(targets) == 1: - return __build_aug_assign_stmt() - - def walk_simple_assign_stmt( - self, node: lark_pb.Tree - ) -> typing.Union[ast.AssignStmt, ast.AugAssignStmt]: - return self.walk_assign_stmt(node) - - # ----------------------------------------------------- - # assert_stmt - # ----------------------------------------------------- - - def walk_assert_stmt(self, node: lark_pb.Tree) -> ast.AssertStmt: - """Syntax - assert_stmt: ASSERT simple_expr (IF simple_expr)? (COMMA test)? - """ - p = check_utils.check_not_none( - ast.ASTFactory.get_ast(ast.AssertStmt, node, self.filename), ast.AssertStmt - ) - - p.test, p.if_cond, p.msg = self.walk_elements_ordered_by_types( - node, - [ - ast.LarkToken.L_simple_expr, - ast.LarkToken.L_simple_expr, - ast.LarkToken.L_test, - ], - ) - p.test = check_utils.check_not_none(p.test, ast.Expr) - p.if_cond = check_utils.check_allow_none(p.if_cond, ast.Expr) - p.msg = check_utils.check_allow_none(p.msg, ast.Expr) - return p - - # ----------------------------------------------------- - # import_stmt - # ----------------------------------------------------- - - def walk_import_stmt(self, node: lark_pb.Tree) -> ast.ImportStmt: - """Syntax - import_stmt: IMPORT dot_name (AS NAME)? - """ - p: ast.ImportStmt = check_utils.check_not_none( - ast.ASTFactory.get_ast(ast.ImportStmt, node, self.filename), ast.ImportStmt - ) - - path, ident = self.walk_elements_ordered_by_types( - node, [ast.LarkToken.L_dot_name, ast.LarkToken.L_NAME] - ) - p.path = path[0] - p.path = check_utils.check_not_none(p.path, str) - ident = check_utils.check_allow_none(ident, ast.Identifier) - - p.name = p.path[p.path.rfind(".") + 1 :] - p.asname = "".join(ident.names) if ident else None - - p.path_nodes = path[1] - if ident: - assert ( - len(ident.name_nodes) == 1 - ), "as name in the import stmt must be a single NAME" - p.as_name_node = ident.name_nodes[0] - - return p - - def walk_dot_name(self, node: lark_pb.Tree) -> (str, typing.List[ast.Name]): - """Syntax - dot_name: (leading_dots identifier) | identifier - """ - types = [ast.LarkToken.L_leading_dots, ast.LarkToken.L_identifier] - dots, ident = self.walk_elements_ordered_by_types(node, types) - - dots = check_utils.check_allow_none(dots, str) - ident: ast.Identifier = check_utils.check_not_none(ident, ast.Identifier) - - dot_name = dots or "" - dot_name += ".".join([name for name in ident.names]) - - return dot_name, ident.name_nodes - - def walk_leading_dots(self, node: lark_pb.Tree) -> str: - """Syntax - leading_dots: DOT+ - """ - return "".join([child.token_value for child in node.children]) - - # ----------------------------------------------------- - # if_stmt - # ----------------------------------------------------- - - def walk_if_stmt(self, node: lark_pb.Tree) -> ast.IfStmt: - """Syntax - if_stmt: IF test COLON execution_block (ELIF test COLON execution_block)* (ELSE COLON execution_block)? - execution_block: if_simple_stmt | NEWLINE _INDENT schema_init_stmt+ _DEDENT - schema_init_stmt: if_simple_stmt | if_stmt - """ - p = check_utils.check_not_none( - ast.ASTFactory.get_ast(ast.IfStmt, node, self.filename), ast.IfStmt - ) - test_list = check_utils.check_all_not_none( - list, self.walk_all_by_type(node, ast.LarkToken.L_test), ast.Expr - ) - execution_block_list = check_utils.check_all_not_none( - list, self.walk_all_by_type(node, ast.LarkToken.L_execution_block), list - ) - - for execution_block in execution_block_list: - check_utils.check_all_not_none(list, execution_block, ast.Stmt) - - has_else = check_utils.check_allow_none( - self.walk_one_by_type(node, ast.LarkToken.L_ELSE), str - ) - - p.cond = test_list.pop(0) - if not p.body: - p.body = execution_block_list.pop(0) - p.set_end_line_column(p.body[-1]) - if has_else and p.body: - p.else_body = execution_block_list.pop(-1) - p.set_end_line_column(p.else_body[-1]) - if p.body and len(execution_block_list) > 0: - p.elif_body = execution_block_list - assert len(p.elif_body[-1]) > 0 - p.set_end_line_column(p.elif_body[-1][-1]) - if len(test_list) > 0: - p.elif_cond = test_list - - if p.else_body: - p.set_end_line_column(p.else_body[-1]) - - return p - - def walk_execution_block(self, node: lark_pb.Tree) -> typing.List[ast.Stmt]: - """Syntax - execution_block: if_simple_stmt | NEWLINE _INDENT schema_init_stmt+ _DEDENT - schema_init_stmt: if_simple_stmt | if_stmt - """ - if len(node.children) == 1: - return [check_utils.check_allow_none(self.walk(node.children[0]), ast.Stmt)] - else: - stmt_list = self.walk_all_by_type(node, ast.LarkToken.L_schema_init_stmt) - return check_utils.check_all_not_none( - list, - stmt_list, - ast.IfStmt, - ast.ExprStmt, - ast.AssertStmt, - ast.AssignStmt, - ast.AugAssignStmt, - ) - - # ----------------------------------------------------- - # schema_stmt - # ----------------------------------------------------- - - def walk_schema_stmt(self, node: lark_pb.Tree) -> ast.SchemaStmt: - """Syntax - schema_stmt: [decorators] (SCHEMA|MIXIN|PROTOCOL) [RELAXED] NAME - [LEFT_BRACKETS [schema_arguments] RIGHT_BRACKETS] - [LEFT_PARENTHESES identifier (COMMA identifier)* RIGHT_PARENTHESES] - [for_host] COLON NEWLINE [schema_body] - schema_arguments: schema_argument (COMMA schema_argument)* - schema_body: _INDENT (string NEWLINE)* [mixin_stmt] - (schema_attribute_stmt|schema_init_stmt|schema_index_signature)* - [check_block] _DEDENT - schema_attribute_stmt: attribute_stmt NEWLINE - attribute_stmt: [decorators] (FINAL)? NAME COLON type [(ASSIGN|COMP_OR) test] - schema_init_stmt: if_simple_stmt | if_stmt - """ - - def __build_schema_stmt_parent_name() -> typing.Optional[ast.Identifier]: - """Syntax - schema_stmt:[LEFT_PARENTHESES identifier (COMMA identifier)* RIGHT_PARENTHESES] - """ - idents = self.walk_all_by_type(node, ast.LarkToken.L_identifier) - if len(idents) > 1: - report_complier_err( - arg=kcl_error.MULTI_INHERIT_MSG.format(f"{p.name}"), - err_type=kcl_error.ErrType.MultiInheritError_TYPE, - filename=self.filename, - line_no=idents[0].line, - col_no=idents[0].column, - end_col_no=idents[-1].end_column, - ) - return ( - idents[0] if idents and isinstance(idents[0], ast.Identifier) else None - ) - - def __build_schema_stmt_doc(sch_body: lark_pb.Tree) -> str: - """Syntax - schema_body: (string NEWLINE)* - ?string: STRING | LONG_STRING - """ - for child in sch_body.children: - if child.type == ast.LarkToken.L_string: - if ( - len(child.children) > 0 - and child.children[0].type == ast.LarkToken.L_LONG_STRING - ): - return literal_eval(child.children[0].token_value) - return "" - - return "" - - def __build_schema_stmt_index_signature( - sch_body: lark_pb.Tree, - ) -> typing.Optional[ast.SchemaIndexSignature]: - """Syntax - schema_body: (schema_index_signature)* - schema_index_signature: LEFT_BRACKETS [NAME COLON] [ELLIPSIS] basic_type RIGHT_BRACKETS - COLON type [ASSIGN test] NEWLINE - """ - index_sig = check_utils.check_all_allow_none( - list, - self.walk_all_by_type(sch_body, ast.LarkToken.L_schema_index_signature), - ast.SchemaIndexSignature, - ) - if len(index_sig) > 1: - report_complier_err( - err_type=kcl_error.ErrType.IndexSignatureError_TYPE, - filename=self.filename, - line_no=index_sig[1].line, - col_no=index_sig[1].column, - end_col_no=index_sig[1].end_column, - arg="only one index signature is allowed in the schema", - ) - return index_sig[0] if index_sig else None - - p: ast.SchemaStmt = check_utils.check_not_none( - ast.ASTFactory.get_ast(ast.SchemaStmt, node, self.filename), ast.SchemaStmt - ) - - types = [ - ast.LarkToken.L_decorators, - ast.LarkToken.L_MIXIN, - ast.LarkToken.L_PROTOCOL, - ast.LarkToken.L_NAME, - ast.LarkToken.L_COLON, - ast.LarkToken.L_schema_body, - ] - ( - decorators, - is_mixin, - is_protocol, - ident, - colon, - body, - ) = self.walk_elements_ordered_by_types(node, types) - colon = check_utils.check_not_none(colon, Token) - ident = check_utils.check_not_none(ident, ast.Identifier) - p.decorators = ( - check_utils.check_all_allow_none(list, decorators, ast.Decorator) or [] - ) - p.body = check_utils.check_all_allow_none(list, body or [], ast.Stmt) - p.name = "".join(ident.names) - p.is_mixin = bool(is_mixin) or p.name.endswith("Mixin") - p.is_protocol = bool(is_protocol) or p.name.endswith("Protocol") - assert len(ident.name_nodes) == 1, "schema name must be a single NAME" - p.name_node = ident.name_nodes[0] - - mixins = None - for n in node.children: - if n.type == ast.LarkToken.L_schema_body: - p.doc = check_utils.check_allow_none(__build_schema_stmt_doc(n), str) - p.index_signature = check_utils.check_allow_none( - __build_schema_stmt_index_signature(n), ast.SchemaIndexSignature - ) - types = [ast.LarkToken.L_mixin_stmt, ast.LarkToken.L_check_block] - mixins, checks = self.walk_elements_ordered_by_types(n, types) - p.mixins = ( - check_utils.check_all_allow_none( - list, mixins.values, ast.Identifier - ) - if mixins - else [] - ) - p.checks = ( - check_utils.check_all_allow_none(list, checks, ast.CheckExpr) or [] - ) - elif n.type == ast.LarkToken.L_schema_arguments: - p.args = check_utils.check_allow_none(self.walk(n), ast.Arguments) - elif n.type == ast.LarkToken.L_for_host: - p.for_host_name = self.walk(n) - - p.parent_name = check_utils.check_allow_none( - __build_schema_stmt_parent_name(), ast.Identifier - ) - - if p.checks: - p.set_end_line_column(p.checks[-1]) - elif p.body: - p.set_end_line_column(p.body[-1]) - if ( - p.index_signature - and p.index_signature.get_end_line() > p.body[-1].get_end_line() - ): - p.set_end_line_column(p.index_signature) - elif p.index_signature: - p.set_end_line_column(p.index_signature) - elif p.mixins and mixins and isinstance(mixins, Mixins): - p.set_end_line_column(mixins) - else: - p.set_end_line(colon.end_line) - p.set_end_column(colon.end_column) - - return p - - def walk_for_host(self, node: lark_pb.Tree) -> typing.Optional[ast.Identifier]: - """Syntax - for_host: FOR identifier - """ - - for n in node.children or []: - if n.type == ast.LarkToken.L_identifier: - return typing.cast(ast.Identifier, self.walk(n)) - return None - - def walk_schema_arguments( - self, node: lark_pb.Tree - ) -> typing.Optional[ast.Arguments]: - """Syntax - schema_stmt: [decorators] SCHEMA [RELAXED] NAME [LEFT_BRACKETS [schema_arguments] RIGHT_BRACKETS] - [LEFT_PARENTHESES identifier (COMMA identifier)* RIGHT_PARENTHESES] COLON NEWLINE [schema_body] - schema_arguments: schema_argument (COMMA schema_argument)* - schema_argument: NAME [COLON type] [ASSIGN test] - """ - - p: ast.Arguments = check_utils.check_not_none( - ast.ASTFactory.get_ast(ast.Arguments, node, self.filename), ast.Arguments - ) - - arguments: typing.List[ - (ast.Identifier, typing.Optional[ast.Type], typing.Optional[ast.Expr]) - ] = self.walk_non_token_children(node) - assert all(len(argument) == 3 for argument in arguments) - - p.args = [argument[0] for argument in arguments] - for arg in p.args: - arg.ctx = ast.ExprContext.STORE - p.type_annotation_node_list = [argument[1] for argument in arguments] - p.type_annotation_list = [ - t.plain_type_str if t else None for t in p.type_annotation_node_list - ] - p.defaults = [argument[2] for argument in arguments] - - return p - - def walk_schema_argument( - self, node: lark_pb.Tree - ) -> (ast.Identifier, typing.Optional[ast.Type], typing.Optional[ast.Expr]): - """Syntax - schema_argument: NAME [COLON type] [ASSIGN test] - """ - types = [ast.LarkToken.L_NAME, ast.LarkToken.L_type, ast.LarkToken.L_test] - arg_name, arg_type_node, arg_value = self.walk_elements_ordered_by_types( - node, types - ) - arg_type_node: ast.Type = check_utils.check_allow_none(arg_type_node, ast.Type) - arg_name = check_utils.check_not_none(arg_name, ast.Identifier) - return arg_name, arg_type_node, arg_value - - def walk_schema_body( - self, node: lark_pb.Tree - ) -> typing.List[typing.Union[ast.SchemaAttr, ast.Stmt]]: - """ - schema_body: _INDENT (string NEWLINE)* [mixin_stmt] - (schema_attribute_stmt|schema_init_stmt|schema_index_signature)* - [check_block] _DEDENT - schema_init_stmt: if_simple_stmt | if_stmt - """ - filters = [ - ast.LarkToken.L_string, - ast.LarkToken.L_mixin_stmt, - ast.LarkToken.L_schema_index_signature, - ast.LarkToken.L_check_block, - ] - return check_utils.check_all_allow_none( - list, - self.walk_filtered_elements_ordered_by_types(node, filters), - ast.SchemaAttr, - ast.Stmt, - ) - - def walk_attribute_stmt(self, node: lark_pb.Tree) -> ast.SchemaAttr(): - """Syntax - schema_attribute_stmt: attribute_stmt NEWLINE - attribute_stmt: [decorators] (FINAL)? NAME [QUESTION] COLON type [(ASSIGN|COMP_OR) test] - """ - p: ast.SchemaAttr = check_utils.check_not_none( - ast.ASTFactory.get_ast(ast.SchemaAttr, node, self.filename), ast.SchemaAttr - ) - - types = [ - ast.LarkToken.L_decorators, - ast.LarkToken.L_identifier, - ast.LarkToken.L_QUESTION, - ast.LarkToken.L_type, - ast.LarkToken.L_test, - ] - ( - decorators, - name, - is_optional, - type_annotation, - p.value, - ) = self.walk_elements_ordered_by_types(node, types) - name: ast.Identifier = check_utils.check_not_none(name, ast.Identifier) - type_annotation = check_utils.check_not_none(type_annotation, ast.Type) - - p.name = ".".join(name.names) - p.type_str = type_annotation.plain_type_str - p.decorators = decorators or [] - p.is_optional = bool(is_optional) - p.name_node = name.name_nodes[0] - p.type_node = type_annotation - - for n in node.children: - if n.type in [ast.LarkToken.L_ASSIGN, ast.LarkToken.L_COMP_OR]: - p.op = ast.AugOp(n.type) - continue - - return p - - def walk_schema_index_signature( - self, node: lark_pb.Tree - ) -> ast.SchemaIndexSignature: - """Syntax - schema_index_signature: LEFT_BRACKETS [NAME COLON] [ELLIPSIS] basic_type RIGHT_BRACKETS - COLON type [ASSIGN test] NEWLINE - """ - p: ast.SchemaIndexSignature = check_utils.check_not_none( - ast.ASTFactory.get_ast(ast.SchemaIndexSignature, node, self.filename), - ast.SchemaIndexSignature, - ) - - types = [ - ast.LarkToken.L_NAME, - ast.LarkToken.L_ELLIPSIS, - ast.LarkToken.L_basic_type, - ast.LarkToken.L_type, - ast.LarkToken.L_test, - ] - ( - ident, - any_other, - key_type_node, - p.value_type_node, - p.value, - ) = self.walk_elements_ordered_by_types(node, types) - - p.key_type = check_utils.check_not_none(key_type_node.type_name, str) - p.value_type = check_utils.check_not_none(p.value_type_node.plain_type_str, str) - p.value_type_node = check_utils.check_not_none(p.value_type_node, ast.Type) - ident = check_utils.check_allow_none(ident, ast.Identifier) - - p.any_other = bool(any_other) - p.key_name = "".join(ident.names) if ident else None - if ident: - assert ( - len(ident.name_nodes) == 1 - ), "name of the schema index signature must be a single NAME" - p.name_node = ident.name_nodes[0] - - p.set_end_line(p.value_type_node.end_line) - p.set_end_column(p.value_type_node.end_column) - - if p.value: - p.set_end_line_column(p.value) - - return p - - # ----------------------------------------------------- - # decorators - # ----------------------------------------------------- - - def walk_decorators(self, node: lark_pb.Tree) -> typing.List[ast.Decorator]: - """Syntax - decorators: (AT decorator_expr NEWLINE)+ - decorator_expr: identifier [call_suffix] - """ - return check_utils.check_all_not_none( - list, - self.walk_all_by_type(node, ast.LarkToken.L_decorator_expr), - ast.Decorator, - ) - - def walk_decorator_expr(self, node: lark_pb.Tree) -> ast.Decorator: - """Syntax - decorator_expr: identifier [call_suffix] - """ - p = check_utils.check_not_none( - ast.ASTFactory.get_ast(ast.Decorator, node, self.filename), ast.Decorator - ) - - types = [ast.LarkToken.L_identifier, ast.LarkToken.L_call_suffix] - p.name, p.args = self.walk_elements_ordered_by_types(node, types) - p.name = check_utils.check_not_none(p.name, ast.Identifier) - p.args = check_utils.check_allow_none(p.args, ast.CallExpr) - return p - - # ----------------------------------------------------- - # rule_stmt - # ----------------------------------------------------- - - def walk_rule_stmt(self, node: lark_pb.Tree) -> ast.RuleStmt: - """Syntax - rule_stmt: [decorators] RULE NAME [LEFT_BRACKETS [schema_arguments] RIGHT_BRACKETS] [LEFT_PARENTHESES identifier (COMMA identifier)* RIGHT_PARENTHESES] [for_host] COLON NEWLINE [rule_body] - rule_body: _INDENT (string NEWLINE)* check_expr+ _DEDENT - """ - - def __build_rule_stmt_parent_names() -> typing.List[ast.Identifier]: - """Syntax - rule_stmt: [LEFT_PARENTHESES identifier (COMMA identifier)* RIGHT_PARENTHESES] - """ - idents = self.walk_all_by_type(node, ast.LarkToken.L_identifier) - return idents or [] - - def __build_rule_stmt_doc(rule_body: lark_pb.Tree) -> str: - """Syntax - rule_body: (string NEWLINE)* - ?string: STRING | LONG_STRING - """ - for child in rule_body.children: - if child.type == ast.LarkToken.L_string: - if ( - len(child.children) > 0 - and child.children[0].type == ast.LarkToken.L_LONG_STRING - ): - return literal_eval(child.children[0].token_value) - return "" - - return "" - - p: ast.RuleStmt = check_utils.check_not_none( - ast.ASTFactory.get_ast(ast.RuleStmt, node, self.filename), ast.RuleStmt - ) - - types = [ - ast.LarkToken.L_decorators, - ast.LarkToken.L_NAME, - ast.LarkToken.L_COLON, - ] - ( - decorators, - ident, - colon, - ) = self.walk_elements_ordered_by_types(node, types) - colon = check_utils.check_not_none(colon, Token) - ident = check_utils.check_not_none(ident, ast.Identifier) - p.decorators = ( - check_utils.check_all_allow_none(list, decorators, ast.Decorator) or [] - ) - p.name = "".join(ident.names) - assert len(ident.name_nodes) == 1, "rule name must be a single NAME" - p.name_node = ident.name_nodes[0] - - checks = None - for n in node.children: - if n.type == ast.LarkToken.L_rule_body: - p.doc = check_utils.check_allow_none(__build_rule_stmt_doc(n), str) - checks = self.walk_all_by_type(n, ast.LarkToken.L_check_expr) - p.checks = ( - check_utils.check_all_allow_none(list, checks, ast.CheckExpr) or [] - ) - elif n.type == ast.LarkToken.L_schema_arguments: - p.args = check_utils.check_allow_none(self.walk(n), ast.Arguments) - elif n.type == ast.LarkToken.L_for_host: - p.for_host_name = self.walk(n) - - p.parent_rules = check_utils.check_allow_none( - __build_rule_stmt_parent_names(), list - ) - - if p.checks: - p.set_end_line_column(p.checks[-1]) - else: - p.set_end_line(colon.end_line) - p.set_end_column(colon.end_column) - - return p - - # ----------------------------------------------------- - # type - # ----------------------------------------------------- - - def walk_type(self, node: lark_pb.Tree) -> ast.Type: - """Syntax - type: type_element (OR type_element)* - type_element: schema_type | basic_type | compound_type | literal_type - schema_type: identifier - basic_type: basic_type: STRING_TYPE | INT_TYPE | FLOAT_TYPE | BOOL_TYPE | ANY_TYPE - compound_type: list_type | dict_type - literal_type: string | number | TRUE | FALSE | NONE - list_type: LEFT_BRACKETS (type)? RIGHT_BRACKETS - dict_type: LEFT_BRACE (type)? COLON (type)? RIGHT_BRACE - """ - p: ast.Type = check_utils.check_not_none( - ast.ASTFactory.get_ast(ast.Type, node, filename=self.filename), ast.Type - ) - type_elements = check_utils.check_all_not_none( - list, - self.walk_non_token_children(node), - ast.Identifier, - ast.BasicType, - ast.ListType, - ast.DictType, - ast.LiteralType, - ) - p.type_elements = type_elements - - plain_types: typing.List[str] = [] - for type_element in type_elements: - if isinstance(type_element, ast.Identifier): - plain_types.append(".".join(type_element.names)) - continue - if isinstance(type_element, ast.BasicType): - plain_types.append(type_element.type_name) - continue - if isinstance(type_element, (ast.ListType, ast.DictType)): - plain_types.append(type_element.plain_type_str) - continue - if isinstance(type_element, ast.LiteralType): - plain_types.append(type_element.plain_value) - continue - - report_complier_err( - "Invalid type annotation. Valid type annotations: SchemaType, BasicType, ListType, LiteralType", - filename=self.filename, - line_no=type_element.line, - col_no=type_element.column, - end_col_no=type_element.end_column, - ) - p.plain_type_str = "|".join(plain_types) - return p - - def walk_basic_type(self, node: lark_pb.Tree) -> ast.BasicType: - assert len(node.children) == 1 - p: ast.BasicType = check_utils.check_not_none( - ast.ASTFactory.get_ast(ast.BasicType, node, self.filename), ast.BasicType - ) - p.type_name = node.children[0].token_value - return p - - def walk_literal_type(self, node: lark_pb.Tree) -> ast.LiteralType: - assert len(node.children) == 1 - p: ast.LiteralType = ast.LiteralType().set_ast_position( - node, filename=self.filename - ) - value_type = node.children[0].type - if value_type in ["string", "number"]: - lit = self.walk(node.children[0]) - if isinstance(lit, ast.StringLit): - p.value_type = lit.type - p.string_value = lit - p.plain_value = lit.raw_value - return p - if isinstance(lit, ast.NumberLit): - p.value_type = lit.type - p.number_value = lit - p.plain_value = ( - f"{str(lit.value)}{lit.binary_suffix}" - if lit.binary_suffix - else str(lit.value) - ) - return p - report_complier_err( - f"Invalid Literal Type {lit}. Valid Literal Types: StringLiteral, NumberLiteral", - filename=self.filename, - line_no=node.children[0].line, - col_no=node.children[0].column, - end_col_no=node.children[0].end_column, - ) - else: - assert lark_parser.IsTokenType(value_type) - value = node.children[0].token_value - assert value in ["True", "False", "None"] - p.plain_value = value - p.value_type = "bool" if value in ["True", "False"] else "None" - return p - - def walk_list_type(self, node: lark_pb.Tree) -> ast.ListType: - """ - list_type: LEFT_BRACKETS (type)? RIGHT_BRACKETS - """ - p: ast.ListType = check_utils.check_not_none( - ast.ASTFactory.get_ast(ast.ListType, node, filename=self.filename), - ast.ListType, - ) - inner_type: ast.Type = check_utils.check_allow_none( - self.walk_one_by_type(node, ast.LarkToken.L_type), ast.Type - ) - p.inner_type = inner_type - p.plain_type_str = f"[{inner_type.plain_type_str}]" if inner_type else "[]" - return p - - def walk_dict_type(self, node: lark_pb.Tree) -> ast.DictType: - """ - dict_type: LEFT_BRACE (type)? COLON (type)? RIGHT_BRACE - """ - p: ast.DictType = check_utils.check_not_none( - ast.ASTFactory.get_ast(ast.DictType, node, filename=self.filename), - ast.DictType, - ) - types = [ast.LarkToken.L_type, ast.LarkToken.L_COLON, ast.LarkToken.L_type] - key, colon, val = self.walk_elements_ordered_by_types(node, types) - - key: ast.Type = check_utils.check_allow_none(key, ast.Type) - val: ast.Type = check_utils.check_allow_none(val, ast.Type) - assert colon and colon == ":" - - p.key_type = key - p.value_type = val - - plain_key = key.plain_type_str if key else "" - plain_value = val.plain_type_str if val else "" - p.plain_type_str = "{" + f"{plain_key}:{plain_value}" + "}" - return p - - # ----------------------------------------------------- - # check_stmt - # ----------------------------------------------------- - - def walk_check_block(self, node: lark_pb.Tree) -> typing.List[ast.CheckExpr]: - """Syntax - check_block: CHECK COLON NEWLINE _INDENT check_expr+ _DEDENT - check_expr: simple_expr [IF simple_expr] [COMMA primary_expr] NEWLINE - """ - return check_utils.check_all_allow_none( - list, self.walk_non_token_children(node), ast.CheckExpr - ) - - def walk_check_expr(self, node: lark_pb.Tree) -> ast.CheckExpr: - """Syntax - check_expr: simple_expr [IF simple_expr] [COMMA primary_expr] NEWLINE - """ - p = check_utils.check_not_none( - ast.ASTFactory.get_ast(ast.CheckExpr, node, self.filename), ast.CheckExpr - ) - - types = [ - ast.LarkToken.L_simple_expr, - ast.LarkToken.L_simple_expr, - ast.LarkToken.L_primary_expr, - ] - p.test, p.if_cond, p.msg = self.walk_elements_ordered_by_types(node, types) - - p.msg = check_utils.check_allow_none(p.msg, ast.Expr) - p.test = check_utils.check_not_none(p.test, ast.Expr) - - if p.msg: - p.set_end_line_column(p.msg) - elif p.if_cond: - p.set_end_line_column(p.if_cond) - else: - p.set_end_line_column(p.test) - - return p - - # ----------------------------------------------------- - # mixin_stmt - # ----------------------------------------------------- - - def walk_mixin_stmt(self, node: lark_pb.Tree) -> Mixins: - """Syntax - mixin_stmt: MIXIN LEFT_BRACKETS [mixins | multiline_mixins] RIGHT_BRACKETS NEWLINE - multiline_mixins: NEWLINE _INDENT mixins NEWLINE _DEDENT - mixins: identifier (COMMA (NEWLINE mixins | identifier))* - """ - mixins = Mixins() - left_bracket = check_utils.check_not_none( - self.walk_one_by_type(node, ast.LarkToken.L_LEFT_BRACKETS), Token - ) - right_bracket = check_utils.check_not_none( - self.walk_one_by_type(node, ast.LarkToken.L_RIGHT_BRACKETS), Token - ) - - mixins.set_line(left_bracket.line) - mixins.set_column(left_bracket.column) - mixins.set_end_line(right_bracket.end_line) - mixins.set_end_column(right_bracket.end_column) - - def walk_fn(n: lark_pb.Tree): - if n.type == ast.LarkToken.L_identifier: - mixins.append( - check_utils.check_allow_none(self.walk(n), ast.Identifier) - ) - - lark_parser.WalkTree(node, walk_fn) - return mixins - - # ----------------------------------------------------- - # expression_stmt - # ----------------------------------------------------- - - def walk_testlist_expr(self, node: lark_pb.Tree) -> ast.ExprStmt: - """ - expr_stmt: testlist_expr - testlist_expr: test (COMMA test)* - """ - p = check_utils.check_not_none( - ast.ASTFactory.get_ast(ast.ExprStmt, node, self.filename), ast.ExprStmt - ) - p.exprs = check_utils.check_all_not_none( - list, self.walk_non_token_children(node), ast.Expr - ) - return p - - def walk_if_expr(self, node: lark_pb.Tree) -> ast.IfExpr: - """ - if_expr: simple_expr IF simple_expr ELSE test - """ - assert len(node.children) == 5 - p = check_utils.check_not_none( - ast.ASTFactory.get_ast(ast.IfExpr, node, self.filename), ast.IfExpr - ) - - types = [ - ast.LarkToken.L_simple_expr, - ast.LarkToken.L_simple_expr, - ast.LarkToken.L_test, - ] - p.body, p.cond, p.orelse = self.walk_elements_ordered_by_types(node, types) - - p.body = check_utils.check_not_none(p.body, ast.Expr) - p.cond = check_utils.check_not_none(p.cond, ast.Expr) - p.orelse = check_utils.check_not_none(p.orelse, ast.Expr) - return p - - def walk_simple_expr(self, node: lark_pb.Tree) -> ast.Expr: - """This function is equivalent to a filter, only the child nodes of the - current node need to adjust the priority, and all expressions passing - through this node will adjust the priority. - """ - assert len(node.children) == 1 - simple_expr = check_utils.check_not_none(self.walk(node.children[0]), ast.Expr) - return self.add_precedence(simple_expr) - - def add_precedence( - self, expr: ast.Expr - ) -> typing.Union[ast.UnaryExpr, ast.BinaryExpr, ast.Compare, ast.Expr]: - if not isinstance(expr, (ast.BinaryExpr, ast.UnaryExpr, ast.Compare)): - return expr - p = ( - self.add_compare_precedence(expr) - if isinstance(expr, ast.Compare) - else self.add_cal_expr_precedence(expr) - ) - p = check_utils.check_not_none(p, ast.UnaryExpr, ast.BinaryExpr, ast.Compare) - return p - - def add_cal_expr_precedence( - self, expr: typing.Union[ast.BinaryExpr, ast.UnaryExpr] - ) -> typing.Union[ast.UnaryExpr, ast.BinaryExpr, ast.Compare, ast.Expr]: - - if isinstance(expr, ast.UnaryExpr): - right_expr = expr.operand - elif isinstance(expr, ast.BinaryExpr): - right_expr = expr.right - else: - return expr - - start_local = right_expr - prece_op = self.get_precedence(expr.op) - prece_operand = self.get_precedence(right_expr) - - col_no_stack = ( - [] - ) # The stack is used to pass up the line and column number changes - if prece_op >= prece_operand and isinstance( - right_expr, (ast.BinaryExpr, ast.Compare) - ): - tmp = right_expr - while prece_op >= self.get_precedence(tmp.left) and isinstance( - tmp.left, (ast.BinaryExpr, ast.Compare) - ): - col_no_stack.append(tmp) - tmp = tmp.left - if isinstance(expr, ast.UnaryExpr): - expr.operand = tmp.left - elif isinstance(expr, ast.BinaryExpr): - expr.right = tmp.left - expr.set_end_column(tmp.left.get_end_column()) - tmp.left = expr - tmp.set_column(expr.get_column()) - # Calculate the change of the line and column number and pass it up - while col_no_stack: - tmp_col = col_no_stack.pop() - tmp_col.set_column(expr.get_column()) - expr = start_local - - expr = check_utils.check_not_none( - expr, ast.UnaryExpr, ast.BinaryExpr, ast.Compare - ) - return expr - - def add_compare_precedence( - self, expr: ast.Compare - ) -> typing.Union[ast.BinaryExpr, ast.Compare, ast.Expr]: - prece_op = self.get_precedence(expr) - comparators = expr.comparators - for i in range(len(comparators)): - prece_child = self.get_precedence(comparators[i]) - col_no_stack = [] - if isinstance(comparators[i], ast.BinaryExpr) and prece_op > prece_child: - tmp = comparators.pop(i) - start_local = tmp - while prece_op >= self.get_precedence(tmp.left) and isinstance( - tmp.left, ast.BinaryExpr - ): - col_no_stack.append(tmp) - tmp = tmp.left - comparators.insert(i, tmp.left) - expr.set_end_column(comparators[-1].get_end_column()) - tmp.left = expr - tmp.set_column(expr.get_column()) - # Calculate the change of the line and column number and pass it up - while col_no_stack: - tmp_col = col_no_stack.pop() - tmp_col.set_column(expr.get_column()) - expr = start_local - - expr = check_utils.check_not_none(expr, ast.BinaryExpr, ast.Compare) - return expr - - def walk_unary_expr(self, node: lark_pb.Tree) -> ast.UnaryExpr: - """Syntax - simple_expr : primary_expr | unary_expr | binary_expr - unary_expr: un_op simple_expr - """ - p = check_utils.check_not_none( - ast.ASTFactory.get_ast(ast.UnaryExpr, node, self.filename), ast.UnaryExpr - ) - - types = [ast.LarkToken.L_un_op, ast.LarkToken.L_simple_expr] - p.op, p.operand = self.walk_elements_ordered_by_types(node, types) - - p.op = check_utils.check_not_none(p.op, ast.UnaryOp) - p.operand = check_utils.check_not_none(p.operand, ast.Expr) - - self.register_precedence(p.op, p) - return p - - def walk_binary_expr( - self, node: lark_pb.Tree - ) -> typing.Union[ast.BinaryExpr, ast.Compare]: - """Syntax - binary_expr: simple_expr bin_op simple_expr - simple_expr : primary_expr | unary_expr | binary_expr - """ - - def __build_compare() -> typing.Union[ast.BinaryExpr, ast.Compare]: - assert len(node.children) == 3 - cmp_expr = check_utils.check_not_none( - ast.ASTFactory.get_ast(ast.Compare, node, self.filename), ast.Compare - ) - cmp_expr.left = check_utils.check_not_none( - self.walk(node.children[0]), ast.Expr - ) - - for i in range(1, len(node.children)): - n = node.children[i] - if ( - n.type == ast.LarkToken.L_bin_op - and len(n.children) > 0 - and ast.judge_compare_op(n.children[0].type) - ): - cmp_op = check_utils.check_not_none(self.walk(n), ast.CmpOp) - cmp_expr.ops.append(cmp_op) - continue - elif n.type == ast.LarkToken.L_simple_expr: - comparator = check_utils.check_not_none(self.walk(n), ast.Expr) - if isinstance(comparator, ast.Compare): - cmp_expr.ops.extend(comparator.ops) - cmp_expr.comparators.append(comparator.left) - cmp_expr.comparators.extend(comparator.comparators) - elif isinstance(comparator, ast.Expr): - cmp_expr.comparators.append(comparator) - else: - report_complier_err( - f"Unsupported comparator type: {type(comparator)}", - filename=self.filename, - line_no=node.line, - col_no=node.column, - end_col_no=node.end_column, - ) - continue - else: - report_complier_err( - f"Unsupported compare operation type: {n.type}", - filename=self.filename, - line_no=node.line, - col_no=node.column, - end_col_no=node.end_column, - ) - - if len(cmp_expr.ops) > 0: - self.register_precedence(cmp_expr.ops[0], cmp_expr) - return cmp_expr - - assert len(node.children) > 2 - assert len(node.children[1].children) > 0 - if ast.judge_compare_op(node.children[1].children[0].type): - return __build_compare() - - p = check_utils.check_not_none( - ast.ASTFactory.get_ast(ast.BinaryExpr, node, self.filename), ast.BinaryExpr - ) - - types = [ - ast.LarkToken.L_simple_expr, - ast.LarkToken.L_bin_op, - ast.LarkToken.L_simple_expr, - ] - p.left, p.op, p.right = self.walk_elements_ordered_by_types(node, types) - - p.left = check_utils.check_not_none(p.left, ast.Expr) - p.op = check_utils.check_not_none(p.op, ast.BinOp) - p.right = check_utils.check_not_none(p.right, ast.Expr) - - self.register_precedence(p.op, p) - return p - - def walk_un_op(self, node: lark_pb.Tree) -> ast.UnaryOp: - """Syntax - un_op: L_NOT | PLUS | MINUS | NOT - """ - assert len(node.children) > 0 - p = check_utils.check_not_none( - ast.ASTFactory.get_op(ast.UnaryOp, node.children[0].type), ast.UnaryOp - ) - self.register_precedence(p, p) - return p - - def walk_bin_op(self, node: lark_pb.Tree) -> typing.Union[ast.BinOp, ast.CmpOp]: - """Syntax - bin_op: L_OR | L_AND - | OR | XOR | AND - | SHIFT_LEFT | SHIFT_RIGHT - | PLUS | MINUS | MULTIPLY | DIVIDE | MOD | DOUBLE_DIVIDE - | DOUBLE_STAR | EQUAL_TO | NOT_EQUAL_TO - | LESS_THAN | GREATER_THAN | LESS_THAN_OR_EQUAL_TO | GREATER_THAN_OR_EQUAL_TO - | IN | L_NOT IN | IS | IS L_NOT | L_NOT | AS - """ - - def __build_cmp_op() -> ast.CmpOp: - real_type: str = "" - for index in range(len(node.children)): - if index != len(node.children) - 1: - real_type += node.children[index].type + " " - else: - real_type += node.children[index].type - - cmp_op = check_utils.check_not_none( - ast.ASTFactory.get_op(ast.CmpOp, real_type), ast.CmpOp - ) - return cmp_op - - assert len(node.children) > 0 - if ast.judge_compare_op(node.children[0].type): - p = __build_cmp_op() - else: - p = check_utils.check_not_none( - ast.ASTFactory.get_op(ast.BinOp, node.children[0].type), ast.BinOp - ) - self.register_precedence(p, p) - return p - - def walk_primary_expr( - self, node: lark_pb.Tree - ) -> typing.Union[ast.Literal, ast.Expr]: - """Syntax - primary_expr: identifier call_suffix | operand | primary_expr select_suffix | primary_expr call_suffix - | primary_expr slice_suffix - select_suffix:[question] DOT NAME - call_suffix: LEFT_PARENTHESES [arguments [COMMA]] RIGHT_PARENTHESES - slice_suffix: LEFT_BRACKETS (test | [test] COLON [test] [COLON [test]]) RIGHT_BRACKETS - arguments: argument (COMMA argument)* - argument: test | NAME ASSIGN test | MULTIPLY test | DOUBLE_STAR test - number: DEC_NUMBER | HEX_NUMBER | BIN_NUMBER | OCT_NUMBER | FLOAT_NUMBER | IMAG_NUMBER - string: STRING | LONG_STRING - """ - assert len(node.children) > 0 - if len(node.children) == 1: - expr = check_utils.check_not_none( - self.walk(node.children[0]), ast.Literal, ast.Expr - ) - return expr - elif len(node.children) == 2: - n0 = node.children[0] - if n0.type == ast.LarkToken.L_identifier: - func_expr: ast.Identifier = check_utils.check_not_none( - self.walk(n0), ast.Identifier - ) - call_suffix: ast.CallExpr = check_utils.check_not_none( - self.walk(node.children[1]), ast.CallExpr - ) - call_suffix.func = func_expr - call_suffix.set_ast_position(node, self.filename) - return call_suffix - elif n0.type == ast.LarkToken.L_primary_expr: - func_expr = check_utils.check_not_none( - self.walk(n0), ast.Literal, ast.Expr - ) - p = check_utils.check_not_none( - self.walk(node.children[1]), - ast.SelectorExpr, - ast.Subscript, - ast.CallExpr, - ) - - if node.children[1].type in [ - ast.LarkToken.L_select_suffix, - ast.LarkToken.L_slice_suffix, - ]: - p.value = func_expr - elif node.children[1].type == ast.LarkToken.L_call_suffix: - p.func = func_expr - p.set_ast_position(node, self.filename) - return p - - report_complier_err( - "Unsupported expression", - filename=self.filename, - line_no=node.line, - col_no=node.column, - end_col_no=node.end_column, - ) - - def walk_operand( - self, node: lark_pb.Tree - ) -> typing.Union[str, ast.Expr, ast.ParenExpr, ast.Identifier]: - """Syntax - operand: identifier | number | string | TRUE | FALSE | NONE | list_expr | list_comp | dict_expr | dict_comp - | schema_expr | LEFT_PARENTHESES expression RIGHT_PARENTHESES - """ - if len(node.children) == 1: - return self.walk(node.children[0]) - elif len(node.children) == 3: - p = check_utils.check_not_none( - ast.ASTFactory.get_ast(ast.ParenExpr, node, self.filename), - ast.ParenExpr, - ) - p.expr = self.walk(node.children[1]) - return p - else: - report_complier_err( - "Unsupported expression", - filename=self.filename, - line_no=node.line, - col_no=node.column, - end_col_no=node.end_column, - ) - - def walk_call_suffix(self, node: lark_pb.Tree) -> ast.CallExpr: - """Syntax - call_suffix: LEFT_PARENTHESES [arguments [COMMA]] RIGHT_PARENTHESES - arguments: argument (COMMA argument)* - argument: test | NAME ASSIGN test | MULTIPLY test | DOUBLE_STAR test - """ - p = check_utils.check_not_none( - ast.ASTFactory.get_ast(ast.CallExpr, node, self.filename), ast.CallExpr - ) - - args = self.walk_one_by_type(node, ast.LarkToken.L_arguments) - if args and isinstance(args, ast.CallExpr): - args.set_end_line_column(p) - args.set_ast_position(node, self.filename) - return args - return p - - def walk_select_suffix(self, node: lark_pb.Tree) -> ast.SelectorExpr: - """Syntax - select_suffix: [QUESTION] DOT NAME - """ - p: ast.SelectorExpr = check_utils.check_not_none( - ast.ASTFactory.get_ast(ast.SelectorExpr, node, self.filename), - ast.SelectorExpr, - ) - p.attr = check_utils.check_not_none( - self.walk_one_by_type(node, ast.LarkToken.L_NAME), ast.Identifier - ) - p.has_question = len(node.children) == 3 - return p - - def walk_slice_suffix(self, node: lark_pb.Tree) -> ast.Subscript: - """Syntax - slice_suffix: [QUESTION] LEFT_BRACKETS (test | [test] COLON [test] [COLON [test]]) RIGHT_BRACKETS - test: if_expr | primary_expr | unary_expr | binary_expr - """ - p = check_utils.check_not_none( - ast.ASTFactory.get_ast(ast.Subscript, node, self.filename), ast.Subscript - ) - - types = [ - ast.LarkToken.L_QUESTION, - ast.LarkToken.L_test, - ast.LarkToken.L_COLON, - ast.LarkToken.L_test, - ast.LarkToken.L_COLON, - ast.LarkToken.L_test, - ] - ( - has_question, - p.lower, - colon1, - p.upper, - colon2, - p.step, - ) = self.walk_elements_ordered_by_types(node, types) - - has_question = check_utils.check_allow_none(has_question, str) - p.lower = check_utils.check_allow_none(p.lower, ast.Expr) - colon1 = check_utils.check_allow_none(colon1, str) - p.upper = check_utils.check_allow_none(p.upper, ast.Expr) - colon2 = check_utils.check_allow_none(colon2, str) - p.step = check_utils.check_allow_none(p.step, ast.Expr) - - p.has_question = bool(has_question) - if not colon1 and not colon2: - p.index = p.lower - p.lower = None - - return p - - def walk_arguments(self, node: lark_pb.Tree) -> ast.CallExpr: - """Syntax - arguments: argument (COMMA argument)* - argument: test | NAME ASSIGN test | MULTIPLY test | DOUBLE_STAR test - """ - p: ast.CallExpr = check_utils.check_not_none( - ast.ASTFactory.get_ast(ast.CallExpr, node, self.filename), ast.CallExpr - ) - has_keyword = False - - for arg in node.children: - if arg.type == ast.LarkToken.L_argument: - assert len(arg.children) > 0 - n0 = arg.children[0] - if n0.type == ast.LarkToken.L_test: - if has_keyword: - report_syntax_err( - arg="positional argument follows keyword argument", - filename=self.filename, - line_no=n0.line, - col_no=n0.column, - end_col_no=n0.end_column, - ) - p.args.append( - check_utils.check_allow_none(self.walk(arg), ast.Expr) - ) - continue - elif n0.type == ast.LarkToken.L_NAME: - p.keywords.append( - check_utils.check_allow_none(self.walk(arg), ast.Keyword) - ) - has_keyword = True - continue - else: - report_complier_err( - "Unsupported argument", - filename=self.filename, - line_no=node.line, - col_no=node.column, - end_col_no=node.end_column, - ) - return p - - def walk_argument(self, node: lark_pb.Tree) -> ast.Expr: - """Syntax - argument: test | NAME ASSIGN test | MULTIPLY test | DOUBLE_STAR test - """ - assert len(node.children) > 0 - name, test = self.walk_elements_ordered_by_types( - node, [ast.LarkToken.L_NAME, ast.LarkToken.L_test] - ) - name = check_utils.check_allow_none(name, ast.Identifier) - test = check_utils.check_not_none(test, ast.Expr) - if name: - keyword: ast.Keyword = check_utils.check_not_none( - ast.ASTFactory.get_ast(ast.Keyword, node.children[0], self.filename), - ast.Keyword, - ) - keyword.arg = name - keyword.value = test - assert ( - len(name.name_nodes) == 1 - ), "name of the keyword argument must be a single NAME" - return keyword - else: - return test - - # ----------------------------------------------------- - # operand - # ----------------------------------------------------- - - def walk_identifier( - self, node: lark_pb.Tree, *, _ctx: ast.ExprContext = ast.ExprContext.LOAD - ) -> ast.Identifier: - """Syntax - identifier: NAME (DOT NAME)* - """ - p: ast.Identifier = check_utils.check_not_none( - ast.ASTFactory.get_ast(ast.Identifier, node, self.filename), ast.Identifier - ) - p.names = [ - n.token_value for n in node.children if n.type == ast.LarkToken.L_NAME - ] - p.name_nodes = [ - self.lark_name_to_ast_name(n) - for n in node.children - if n.type == ast.LarkToken.L_NAME - ] - return p - - def walk_quant_expr(self, node: lark_pb.Tree) -> ast.QuantExpr: - """Syntax - quant_expr: quant_op [ identifier COMMA ] identifier IN quant_target LEFT_BRACE (simple_expr [IF simple_expr] - | NEWLINE _INDENT simple_expr [IF simple_expr] NEWLINE _DEDENT)? RIGHT_BRACE - quant_target: string | identifier | list_expr | list_comp | dict_expr | dict_comp - quant_op: ALL | ANY | FILTER | MAP - """ - p = check_utils.check_not_none( - ast.ASTFactory.get_ast(ast.QuantExpr, node, self.filename), ast.QuantExpr - ) - types = [ - ast.LarkToken.L_quant_op, - ast.LarkToken.L_quant_target, - ast.LarkToken.L_simple_expr, - ast.LarkToken.L_simple_expr, - ] - op, p.target, p.test, p.if_cond = self.walk_elements_ordered_by_types( - node, types - ) - op = check_utils.check_not_none(op, str) - p.target = check_utils.check_not_none(p.target, ast.Expr) - p.test = check_utils.check_not_none(p.test, ast.Expr) - p.if_cond = check_utils.check_allow_none(p.if_cond, ast.Expr) - p.variables = check_utils.check_all_not_none( - list, - self.walk_all_by_type(node, ast.LarkToken.L_identifier), - ast.Identifier, - ) - p.op = ast.QuantOperation.MAPPING[op] - - return p - - def walk_list_expr(self, node: lark_pb.Tree) -> ast.ListExpr: - """Syntax - list_expr: LEFT_BRACKETS [list_items | NEWLINE _INDENT list_items _DEDENT] RIGHT_BRACKETS - list_items: list_item ((COMMA [NEWLINE] | NEWLINE) list_item)* [COMMA] [NEWLINE] - """ - p = check_utils.check_not_none( - ast.ASTFactory.get_ast(ast.ListExpr, node, self.filename), ast.ListExpr - ) - p.elts = ( - check_utils.check_all_allow_none( - list, self.walk_one_by_type(node, ast.LarkToken.L_list_items), ast.Expr - ) - or [] - ) - - return p - - def walk_list_items(self, node: lark_pb.Tree) -> typing.List[ast.Expr]: - """Syntax - list_items: list_item ((COMMA [NEWLINE] | NEWLINE) list_item)* [COMMA] [NEWLINE] - list_item: test | star_expr | if_item - """ - return check_utils.check_all_allow_none( - list, self.walk_all_by_type(node, ast.LarkToken.L_list_item), ast.Expr - ) - - def walk_list_comp(self, node: lark_pb.Tree) -> ast.ListComp: - """Syntax - list_comp: LEFT_BRACKETS (list_item comp_clause+ - | NEWLINE _INDENT list_item comp_clause+ _DEDENT) RIGHT_BRACKETS - list_item: test | star_expr - comp_clause: FOR loop_variables [COMMA] IN test [NEWLINE] [IF test [NEWLINE]] - """ - p = check_utils.check_not_none( - ast.ASTFactory.get_ast(ast.ListComp, node, self.filename), ast.ListComp - ) - p.elt = check_utils.check_not_none( - self.walk_one_by_type(node, ast.LarkToken.L_list_item), ast.Expr - ) - p.generators = check_utils.check_all_not_none( - list, - self.walk_all_by_type(node, ast.LarkToken.L_comp_clause), - ast.CompClause, - ) - return p - - def walk_dict_comp(self, node: lark_pb.Tree) -> ast.DictComp: - """Syntax - dict_comp: LEFT_BRACE (entry comp_clause+ | NEWLINE _INDENT entry comp_clause+ _DEDENT) RIGHT_BRACE - entry: test (COLON | ASSIGN | COMP_PLUS) test | double_star_expr - comp_clause: FOR loop_variables [COMMA] IN test [NEWLINE] [IF test [NEWLINE]] - """ - p = check_utils.check_not_none( - ast.ASTFactory.get_ast(ast.DictComp, node, self.filename), ast.DictComp - ) - - key_value = self.walk_one_by_type(node, ast.LarkToken.L_entry) - assert len(key_value) == 3 - assert key_value[0] is None or isinstance(key_value[0], ast.Expr) - p.key = key_value[0] - p.operation = key_value[1] - p.value = check_utils.check_not_none(key_value[2], ast.Expr) - p.generators = check_utils.check_all_not_none( - list, - self.walk_all_by_type(node, ast.LarkToken.L_comp_clause), - ast.CompClause, - ) - return p - - def walk_entries( - self, node: lark_pb.Tree - ) -> typing.List[typing.Tuple[typing.Optional[ast.Expr], ast.Expr]]: - """Syntax - entries: entry ((COMMA [NEWLINE] | NEWLINE) entry)* [COMMA] [NEWLINE] - entry: test COLON test | double_star_expr - """ - return self.walk_non_token_children(node) - - def walk_entry( - self, node: lark_pb.Tree - ) -> typing.Tuple[typing.Optional[ast.Expr], ast.Expr]: - """Syntax - entry: test (COLON | ASSIGN | COMP_PLUS) test | double_star_expr | if_entry - double_star_expr: DOUBLE_STAR primary_expr - """ - if len(node.children) == 3: - key = check_utils.check_not_none(self.walk(node.children[0]), ast.Expr) - val = check_utils.check_not_none(self.walk(node.children[2]), ast.Expr) - op = ast.ConfigEntryOperation.MAPPING[node.children[1].type] - return key, op, val - elif len(node.children) == 1: - return self.walk(node.children[0]) - else: - report_complier_err( - "Unsupported entry", - filename=self.filename, - line_no=node.line, - col_no=node.column, - end_col_no=node.end_column, - ) - - def walk_comp_clause(self, node: lark_pb.Tree) -> ast.CompClause: - """Syntax - comp_clause: FOR loop_variables [COMMA] IN simple_expr [NEWLINE] [IF test [NEWLINE]] - """ - p = check_utils.check_not_none( - ast.ASTFactory.get_ast(ast.CompClause, node, self.filename), ast.CompClause - ) - - types = [ - ast.LarkToken.L_loop_variables, - ast.LarkToken.L_simple_expr, - ast.LarkToken.L_test, - ] - p.targets, p.iter, test = self.walk_elements_ordered_by_types(node, types) - p.targets = check_utils.check_all_not_none(list, p.targets, ast.Identifier) - for i, target in enumerate(p.targets): - p.targets[i].ctx = ast.ExprContext.STORE - p.iter = check_utils.check_not_none(p.iter, ast.Expr) - test = check_utils.check_allow_none(test, ast.Expr) - - p.ifs = [test] if test else [] - return p - - def walk_if_entry( - self, node: lark_pb.Tree - ) -> typing.Tuple[None, ast.ConfigIfEntryExpr]: - """Syntax - if_entry: IF test COLON if_entry_exec_block (ELIF test COLON if_entry_exec_block)* (ELSE COLON if_entry_exec_block)? - if_entry_exec_block: (test (COLON | ASSIGN | COMP_PLUS) test | double_star_expr | if_entry) [NEWLINE] | NEWLINE _INDENT (test (COLON | ASSIGN | COMP_PLUS) test | double_star_expr | if_entry) ((COMMA [NEWLINE] | [NEWLINE]) (test (COLON | ASSIGN | COMP_PLUS) test | double_star_expr | if_entry))* [COMMA] [NEWLINE] _DEDENT - """ - if_entry_node = node - tests = lark_parser.GetNodeList( - if_entry_node, ast.LarkToken.L_test, recursively=False - ) - exec_blocks = lark_parser.GetNodeList( - if_entry_node, ast.LarkToken.L_if_entry_exec_block, recursively=False - ) - assert tests and exec_blocks - if_exec_blocks = exec_blocks[0] - key_value_tests = lark_parser.GetNodeList( - if_exec_blocks, - ast.LarkToken.L_test, - ast.LarkToken.L_double_star_expr, - ast.LarkToken.L_if_entry, - recursively=False, - ) - operation_nodes = lark_parser.GetNodeList( - if_exec_blocks, - ast.LarkToken.L_COLON, - ast.LarkToken.L_ASSIGN, - ast.LarkToken.L_COMP_PLUS, - recursively=False, - ) - val = check_utils.check_not_none( - ast.ASTFactory.get_ast(ast.ConfigIfEntryExpr, node, self.filename), - ast.ConfigIfEntryExpr, - ) - val.if_cond = self.walk(tests[0]) - i = 0 - j = 0 - while i < len(key_value_tests): - if ( - key_value_tests[i].type == ast.LarkToken.L_double_star_expr - or key_value_tests[i].type == ast.LarkToken.L_if_entry - ): - key, value = self.walk(key_value_tests[i]) - val.keys.append(key) - val.values.append(value) - val.operations.append(ast.ConfigEntryOperation.OVERRIDE) - i += 1 - else: - val.keys.append(self.walk(key_value_tests[i])) - val.values.append(self.walk(key_value_tests[i + 1])) - val.operations.append( - ast.ConfigEntryOperation.MAPPING.get(operation_nodes[j].type) - ) - j += 1 - i += 2 - if len(exec_blocks) > 1: - if len(tests) >= 1: - has_else = len(exec_blocks) > len(tests) - next_node = None - if has_else: - block = exec_blocks[-1] - config_expr = ast.ConfigExpr() - config_expr.set_ast_position(block, self.filename) - key_value_tests = lark_parser.GetNodeList( - block, - ast.LarkToken.L_test, - ast.LarkToken.L_double_star_expr, - ast.LarkToken.L_if_entry, - recursively=False, - ) - operation_nodes = lark_parser.GetNodeList( - block, - ast.LarkToken.L_COLON, - ast.LarkToken.L_ASSIGN, - ast.LarkToken.L_COMP_PLUS, - recursively=False, - ) - i = 0 - j = 0 - while i < len(key_value_tests): - if ( - key_value_tests[i].type == ast.LarkToken.L_double_star_expr - or key_value_tests[i].type == ast.LarkToken.L_if_entry - ): - key, value = self.walk(key_value_tests[i]) - operation = ast.ConfigEntryOperation.OVERRIDE - i += 1 - else: - key = self.walk(key_value_tests[i]) - value = self.walk(key_value_tests[i + 1]) - operation = ast.ConfigEntryOperation.MAPPING.get( - operation_nodes[j].type - ) - j += 1 - i += 2 - config_expr.items.append( - check_utils.check_not_none( - ast.ASTFactory.get_ast_configentry( - key, value, operation, self.filename - ), - ast.ConfigEntry, - ) - ) - next_node = config_expr - exec_blocks = exec_blocks[:-1] - for test, block in zip(tests[1:][::-1], exec_blocks[1:][::-1]): - config_if_expr = ast.ConfigIfEntryExpr() - config_if_expr.set_ast_position(test, self.filename) - key_value_tests = lark_parser.GetNodeList( - block, - ast.LarkToken.L_test, - ast.LarkToken.L_double_star_expr, - ast.LarkToken.L_if_entry, - recursively=False, - ) - operation_nodes = lark_parser.GetNodeList( - block, - ast.LarkToken.L_COLON, - ast.LarkToken.L_ASSIGN, - ast.LarkToken.L_COMP_PLUS, - recursively=False, - ) - config_if_expr.if_cond = self.walk(test) - i = 0 - j = 0 - while i < len(key_value_tests): - if ( - key_value_tests[i].type == ast.LarkToken.L_double_star_expr - or key_value_tests[i].type == ast.LarkToken.L_if_entry - ): - key, value = self.walk(key_value_tests[i]) - config_if_expr.keys.append(key) - config_if_expr.values.append(value) - config_if_expr.operations.append( - ast.ConfigEntryOperation.OVERRIDE - ) - i += 1 - else: - config_if_expr.keys.append(self.walk(key_value_tests[i])) - config_if_expr.values.append( - self.walk(key_value_tests[i + 1]) - ) - config_if_expr.operations.append( - ast.ConfigEntryOperation.MAPPING.get( - operation_nodes[j].type - ) - ) - j += 1 - i += 2 - config_if_expr.orelse = next_node - next_node = config_if_expr - val.orelse = next_node - return None, val - - def walk_if_item(self, node: lark_pb.Tree) -> ast.ListIfItemExpr: - """Syntax - if_item: IF test COLON if_item_exec_block (ELIF test COLON if_item_exec_block)* (ELSE COLON if_item_exec_block)? - if_item_exec_block: list_item [NEWLINE] | NEWLINE _INDENT list_item ((COMMA [NEWLINE] | NEWLINE) list_item)* [COMMA] [NEWLINE] _DEDENT - """ - x = check_utils.check_not_none( - ast.ASTFactory.get_ast(ast.ListIfItemExpr, node, self.filename), - ast.ListIfItemExpr, - ) - if_item_node = node - tests = lark_parser.GetNodeList( - if_item_node, ast.LarkToken.L_test, recursively=False - ) - exec_blocks = lark_parser.GetNodeList( - if_item_node, ast.LarkToken.L_if_item_exec_block, recursively=False - ) - x.if_cond = self.walk(tests[0]) - item_tests = lark_parser.GetNodeList( - exec_blocks[0], - ast.LarkToken.L_list_item, - recursively=False, - ) - x.exprs = [self.walk(test) for test in item_tests] - next_node = None - if len(exec_blocks) > 1: - if len(tests) >= 1: - has_else = len(exec_blocks) > len(tests) - if has_else: - block = exec_blocks[-1] - item_tests = lark_parser.GetNodeList( - block, - ast.LarkToken.L_list_item, - recursively=False, - ) - list_expr = ast.ListExpr() - list_expr.set_ast_position(block, self.filename) - list_expr.elts = [self.walk(test) for test in item_tests] - next_node = list_expr - exec_blocks = exec_blocks[:-1] - for test, block in zip(tests[1:][::-1], exec_blocks[1:][::-1]): - list_if_expr = ast.ListIfItemExpr() - list_if_expr.set_ast_position(test, self.filename) - item_tests = lark_parser.GetNodeList( - block, - ast.LarkToken.L_list_item, - recursively=False, - ) - list_if_expr.if_cond = self.walk(test) - list_if_expr.exprs = [self.walk(test) for test in item_tests] - list_if_expr.orelse = next_node - next_node = list_if_expr - x.orelse = next_node - return x - - def walk_star_expr(self, node: lark_pb.Tree) -> ast.StarredExpr: - """Syntax - star_expr: MULTIPLY primary_expr - """ - p = check_utils.check_not_none( - ast.ASTFactory.get_ast(ast.StarredExpr, node, self.filename), - ast.StarredExpr, - ) - assert len(node.children) == 2 - p.value = check_utils.check_not_none(self.walk(node.children[1]), ast.Expr) - return p - - def walk_double_star_expr(self, node: lark_pb.Tree) -> typing.Tuple: - """Syntax - double_star_expr: DOUBLE_STAR primary_expr - """ - val = check_utils.check_not_none( - self.walk_one_by_type(node, ast.LarkToken.L_primary_expr), - ast.Literal, - ast.Expr, - ) - return None, val - - def walk_loop_variables(self, node: lark_pb.Tree) -> typing.List: - """Syntax - loop_variables: primary_expr (COMMA primary_expr)* - """ - loop_variables = self.walk_all_by_type(node, ast.LarkToken.L_primary_expr) - if len(loop_variables) == 0 or len(loop_variables) > 2: - report_complier_err( - arg=f"the number of loop variables is {len(loop_variables)}, which can only be 1 or 2", - filename=self.filename, - line_no=node.line, - col_no=node.column, - end_col_no=node.end_column, - ) - - for n in loop_variables: - is_identifier = isinstance(n, ast.Identifier) - identifier = typing.cast(ast.Identifier, n) - if not is_identifier or (is_identifier and len(identifier.names) != 1): - report_complier_err( - "loop variables can only be ordinary identifiers", - filename=self.filename, - line_no=node.line, - col_no=node.column, - end_col_no=node.end_column, - ) - return loop_variables - - def walk_schema_expr(self, node: lark_pb.Tree) -> ast.SchemaExpr: - """Syntax - schema_expr: identifier (LEFT_PARENTHESES [arguments] RIGHT_PARENTHESES)? config_expr - arguments: argument (COMMA argument)* - """ - p = check_utils.check_not_none( - ast.ASTFactory.get_ast(ast.SchemaExpr, node, self.filename), ast.SchemaExpr - ) - - types = [ - ast.LarkToken.L_identifier, - ast.LarkToken.L_arguments, - ast.LarkToken.L_config_expr, - ] - p.name, call_expr, p.config = self.walk_elements_ordered_by_types(node, types) - - p.name = check_utils.check_not_none(p.name, ast.Identifier) - p.config = check_utils.check_not_none(p.config, ast.ConfigExpr) - call_expr = check_utils.check_allow_none(call_expr, ast.CallExpr) - - p.args = call_expr.args if call_expr else [] - p.kwargs = call_expr.keywords if call_expr else [] - return p - - def walk_config_expr(self, node: lark_pb.Tree) -> ast.ConfigExpr: - """Syntax - config_expr: LEFT_BRACE [config_entries | NEWLINE _INDENT config_entries _DEDENT] RIGHT_BRACE - config_entries: config_entry ((COMMA [NEWLINE] | NEWLINE) config_entry)* [COMMA] [NEWLINE] - """ - p = check_utils.check_not_none( - ast.ASTFactory.get_ast(ast.ConfigExpr, node, self.filename), ast.ConfigExpr - ) - p.items = ( - check_utils.check_all_allow_none( - list, - self.walk_one_by_type(node, ast.LarkToken.L_config_entries), - ast.ConfigEntry, - ) - or [] - ) - return p - - def walk_config_entries(self, node: lark_pb.Tree) -> typing.List[ast.ConfigEntry]: - """Syntax - config_entries: config_entry ((COMMA [NEWLINE] | NEWLINE) config_entry)* [COMMA] [NEWLINE] - config_entry: (test config_op test) | DOUBLE_STAR primary_expr - config_op: COLON | ASSIGN | COMP_PLUS - """ - return check_utils.check_all_allow_none( - list, - self.walk_all_by_type(node, ast.LarkToken.L_config_entry), - ast.ConfigEntry, - ) - - def walk_config_entry(self, node: lark_pb.Tree) -> ast.ConfigEntry: - """Syntax - config_entry: test (COLON | ASSIGN | COMP_PLUS) test | double_star_expr - double_star_expr: DOUBLE_STAR primary_expr - """ - p = check_utils.check_not_none( - ast.ASTFactory.get_ast(ast.ConfigEntry, node, self.filename), - ast.ConfigEntry, - ) - - if len(node.children) == 3: - config_op = node.children[1] - p.key = check_utils.check_not_none(self.walk(node.children[0]), ast.Expr) - p.value = check_utils.check_not_none(self.walk(node.children[2]), ast.Expr) - p.operation = ast.ConfigEntryOperation.MAPPING.get(config_op.type) - assert p.operation in range( - ast.ConfigEntryOperation.get_min(), - ast.ConfigEntryOperation.get_max() + 1, - ) - elif len(node.children) == 1: - key_value = self.walk(node.children[0]) - assert len(key_value) == 2 - assert key_value[0] is None - p.value = check_utils.check_not_none(key_value[1], ast.Literal, ast.Expr) - p.key = key_value[0] - else: - report_complier_err( - "Unsupported schema config entry", - filename=self.filename, - line_no=node.line, - col_no=node.column, - end_col_no=node.end_column, - ) - return p - - def walk_lambda_expr(self, node: lark_pb.Tree) -> ast.LambdaExpr: - """Syntax - lambda_expr: LAMBDA [schema_arguments] [RIGHT_ARROW type] LEFT_BRACE [expr_stmt | NEWLINE _INDENT schema_init_stmt+] _DEDENT RIGHT_BRACE - """ - p = check_utils.check_not_none( - ast.ASTFactory.get_ast(ast.LambdaExpr, node, self.filename), ast.LambdaExpr - ) - types = [ - ast.LarkToken.L_schema_arguments, - ast.LarkToken.L_type, - ] - p.args, p.return_type_node = self.walk_elements_ordered_by_types(node, types) - p.return_type_str = ( - p.return_type_node.plain_type_str if p.return_type_node else "" - ) - expr_stmt_list = lark_parser.GetNodeList( - node, ast.LarkToken.L_expr_stmt, recursively=False - ) - p.body = ( - [self.walk(expr_stmt_list[0])] - if expr_stmt_list - else self.walk_all_by_type(node, ast.LarkToken.L_schema_init_stmt) - ) - return p - - def walk_NAME(self, node: lark_pb) -> ast.Identifier: - def __build_identifier_by_name() -> ast.Identifier: - p: ast.Identifier = check_utils.check_not_none( - ast.ASTFactory.get_ast(ast.Identifier, node, self.filename), - ast.Identifier, - ) - p.names.append(node.token_value) - p.name_nodes.append(self.lark_name_to_ast_name(node)) - return p - - assert node - return __build_identifier_by_name() - - def walk_constant(self, node: lark_pb.Tree) -> ast.NameConstantLit: - """ - Grammar: - NONE | TRUE | FALSE - - Input: - constant node token. - - Output: - constant ast. - """ - - if len(node.children) == 1 and ast.LarkToken.is_name_constant( - node.children[0].type - ): - token_type = node.children[0].type - p = check_utils.check_not_none( - ast.ASTFactory.get_ast( - ast.NameConstantLit, node.children[0], self.filename - ), - ast.NameConstantLit, - ) - p.value = ( - literal_eval(node.children[0].token_value) - if token_type != ast.LarkToken.L_UNDEFINED - else internal.Undefined - ) - return p - else: - report_complier_err( - "Unsupported Constant", - filename=self.filename, - line_no=node.line, - col_no=node.column, - end_col_no=node.end_column, - ) - - def walk_number(self, node: lark_pb.Tree) -> ast.NumberLit: - """ - Grammar: - number: DEC_NUMBER [multiplier] | HEX_NUMBER | BIN_NUMBER | OCT_NUMBER | FLOAT_NUMBER - Input: - number lit tree node. - Output: - number lit ast. - """ - p: ast.NumberLit = check_utils.check_not_none( - ast.ASTFactory.get_ast(ast.NumberLit, node, self.filename), ast.NumberLit - ) - - if len(node.children) >= 1 and ast.LarkToken.is_int_number( - node.children[0].type - ): - p.value = ( - literal_eval(node.children[0].token_value) - if node.children[0].type != ast.LarkToken.L_OCT_NUMBER - else int(node.children[0].token_value, base=8) - ) - if len(node.children) == 2: - p.binary_suffix = self.walk(node.children[1]) - return p - elif len(node.children) >= 1 and ast.LarkToken.is_float_number( - node.children[0].type - ): - p.value = literal_eval(node.children[0].token_value) - return p - else: - report_complier_err( - "Unsupported Number", - filename=self.filename, - line_no=node.line, - col_no=node.column, - end_col_no=node.end_column, - ) - - def walk_multiplier(self, node: lark_pb.Tree) -> str: - """ - Grammar: - multiplier: ( SI_N_L | SI_U_L | SI_M_L | SI_K_L | SI_K | SI_M | SI_G | SI_T | SI_P ) [ IEC ] - Input: - multiplier tree node. - Output: - multiplier ast. - """ - assert len(node.children) >= 1 - bp = node.children[0].token_value - if len(node.children) == 2: - bp += "i" - - if not hasattr(ast.NumberBinarySuffix, bp): - report_complier_err( - f"unsupported quantity type: {bp}", - filename=self.filename, - line_no=node.children[0].line, - col_no=node.children[0].column, - end_col_no=node.children[0].end_column, - ) - - return getattr(ast.NumberBinarySuffix, bp) - - def walk_string( - self, node: lark_pb.Tree - ) -> typing.Union[ast.StringLit, ast.JoinedString]: - """ - According to pypy JoinedString - """ - assert len(node.children) >= 1 - node = node.children[0] - token_value = literal_eval(node.token_value) - string_value = ( - bytes.decode(token_value) - if isinstance(token_value, bytes) - else str(token_value) - ) - quotation = '"' if node.token_value.endswith('"') else "'" - quotation_index = node.token_value.find(quotation) - has_raw_prefix = ( - "r" in node.token_value[:quotation_index] - or "R" in node.token_value[:quotation_index] - ) - has_interpolation = bool(STRING_INTERPOLATION_REGEX.search(string_value)) - if has_raw_prefix or not has_interpolation: - p = check_utils.check_not_none( - ast.ASTFactory.get_ast(ast.StringLit, node, self.filename), - ast.StringLit, - ) - p.value = string_value - else: - p = check_utils.check_not_none( - ast.ASTFactory.get_ast(ast.JoinedString, node, self.filename), - ast.JoinedString, - ) - end = 0 - str_len = len(string_value) - if "$" in string_value.replace("${", "").replace("$$", ""): - # Check invalid single `$` - report_complier_err( - arg="invalid single '$', expecting '$' or '{'", - err_type=kcl_error.ErrType.InvalidFormatSpec_TYPE, - filename=self.filename, - line_no=node.line, - col_no=node.column, - end_col_no=node.end_column, - ) - while string_value and STRING_INTERPOLATION_REGEX.search(string_value): - match = STRING_INTERPOLATION_REGEX.search(string_value) - expr_string = match.group(1) - format_spec = None - if ":" in expr_string: - parts = expr_string.split(":") - expr_string, format_spec = parts[0], parts[1].strip() - start, end = match.span() - string_lit = string_value[:start] - if string_lit is not None: - p.values.append( - ast.ASTFactory.get_ast_literal( - ast.StringLit, - line=node.line, - column=node.column + start, - value=string_lit.replace("$$", "$"), - filename=self.filename, - ) - ) - string_value = string_value[end:] - expr = ParseExpr( - expr_string, - filename=self.filename, - line_offset=node.line - 1, - column_offset=node.column + 2 + start, - ) - if expr: - expr.filename = self.filename - if not expr: - report_complier_err( - arg=f"invalid string interpolation expression '{expr_string}'", - err_type=kcl_error.ErrType.InvalidFormatSpec_TYPE, - filename=self.filename, - line_no=node.line, - col_no=node.column, - end_col_no=node.end_column, - ) - formatted_value = check_utils.check_not_none( - ast.ASTFactory.get_ast_formatted_value( - expr, format_spec, self.filename - ), - ast.FormattedValue, - ) - p.values.append(formatted_value) - if end < str_len and string_value is not None: - p.values.append( - check_utils.check_not_none( - ast.ASTFactory.get_ast_literal( - ast.StringLit, - line=node.line, - column=node.column + end, - value=string_value.replace("$$", "$"), - filename=self.filename, - ), - ast.StringLit, - ) - ) - p.raw_value = node.token_value - p.is_long_string = node.type == ast.LarkToken.L_LONG_STRING - return p - - # ------------------------------------------------------------------------- - # simplify_StringLitValue - # ------------------------------------------------------------------------- - - def simplify_StringLitValue(self, str_lit: ast.StringLit) -> str: - if not str_lit or not str_lit.value: - return "" - - s: str = str_lit.value - # """str_value""" -> str_value - if s.startswith('"""'): - return s[3:-3] - - # '''str_value''' -> str_value - if s.startswith("'''"): - return s[3:-3] - - # "str_value" -> str_value - if s.startswith('"'): - return s[1:-1] - - # 'str_value' -> str_value - if s.startswith("'"): - return s[1:-1] - - # str_value -> str_value - return s - - -# ----------------------------------------------------------------------------- -# ParseFile -# ----------------------------------------------------------------------------- - - -def ParseFile( - filename: typing.Optional[str], - code: typing.Optional[str] = None, - *, - pkg: str = "", - mode: ParseMode = ParseMode.Null, -) -> ast.Module: - try: - if code is None: - code = Path(filename).read_text(encoding="utf-8") - # Store the KCL error file cache map - kcl_error.FileCache.put(filename, code) - lark_parser.filename = filename - larktree = lark_parser.ParseCode(code) - return ASTBuilder(larktree, pkg=pkg, filename=filename, mode=mode).BuildAST() - except ( - lark.exceptions.UnexpectedCharacters, - lark.exceptions.UnexpectedToken, - ) as err: - if kclvm.config.debug > 0: - raise - token_msgs = None - allowed_tokens = ( - list(err.accepts) - if isinstance(err, lark.exceptions.UnexpectedToken) - else list(err.allowed) - ) - if allowed_tokens: - allowed_tokens.sort() - token_msgs = [ - ParseAcceptToken(allowed_token) for allowed_token in allowed_tokens - ] - arg_msg = f"Expected one of {token_msgs}" if token_msgs else None - syntax_err = kcl_error.get_exception( - err_type=kcl_error.ErrType.InvalidSyntax_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=filename, - line_no=err.line, - col_no=err.column, - src_code=code, - arg_msg=arg_msg, - ) - ], - ) - syntax_err.accepts_lark = allowed_tokens - syntax_err.accepts_msg = token_msgs - raise syntax_err - - -@PreCheck((lambda v: CheckRules.check_type_not_none(v, str)), "key") -@PostCheck(lambda v: CheckRules.check_type_not_none(v, str)) -def ParseAcceptToken(key: str) -> str: - if key in ast.lark_token.LarkToken.LL_token_str_value_map.keys(): - token_value = ast.lark_token.LarkToken.LL_token_str_value_map[key] - elif key in ast.lark_token.LarkToken.LL_token_list: - token_value = key.lower() - else: - token_value = key - return token_value - - -# ----------------------------------------------------------------------------- -# ParseExpr -# ----------------------------------------------------------------------------- - - -def ParseExpr( - code: str, - filename: str = None, - line_offset: int = 0, - column_offset: int = 0, - *, - pkg: str = "", - mode: ParseMode = ParseMode.Null, -) -> ast.Expr: - ast.AST.set_offset(line_offset, column_offset) - module = ParseFile(filename, code, pkg=pkg, mode=mode) - ast.AST.reset_offset() - return module.GetFirstExprInExprStmt() - - -# ----------------------------------------------------------------------------- -# LoadProgram -# ----------------------------------------------------------------------------- - - -def _loadPackages( - modfile: kclvm.config.KclModFile, - import_spec: ast.ImportStmt, - pkgs: typing.Dict[str, typing.List[ast.Module]], - missing_pkgs: typing.List[str], - main_files: typing.List[str], - mode: ParseMode = ParseMode.Null, - set_ast_parent: bool = False, -): - root: str = modfile.root - pkgpath: str = import_spec.path - - assert root, f"root={root}" - assert pkgs - - if not pkgpath: - return - - # plugin pkgs - if pkgpath.startswith("kcl_plugin."): - return # ignore import error - - # builtin pkgs - if pkgpath in builtin.STANDARD_SYSTEM_MODULES: - return - - if pkgpath in pkgs: - return - if pkgpath in missing_pkgs: - return - - # try cache - if modfile.build.enable_pkg_cache: - if modfile.build.cached_pkg_prefix and pkgpath.startswith( - modfile.build.cached_pkg_prefix - ): - m_list = vfs.LoadPkgCache( - root, pkgpath, option=get_ast_cache_option(set_ast_parent) - ) - if m_list and isinstance(m_list, list): - pkgs[pkgpath] = m_list - for m in pkgs[pkgpath]: - import_spec_list = fix.fix_and_get_module_import_list( - root, m, False - ) - for import_spec in import_spec_list: - _loadPackages( - modfile, - import_spec, - pkgs, - missing_pkgs, - main_files, - mode=mode, - set_ast_parent=set_ast_parent, - ) - return - - # scan all kcl files - all_k_files = glob.glob(f"{root}/{pkgpath.replace('.', '/')}/*.k", recursive=False) - - # skip `_*.k` and `*_test.k` kcl files - k_files: typing.List[str] = [] - for s in all_k_files: - if os.path.basename(s).startswith("_"): - continue - if s.endswith("_test.k"): - continue - - k_files.append(s) - - if len(k_files) == 0 and os.path.isfile(f"{root}/{pkgpath.replace('.', '/')}.k"): - file = f"{root}/{pkgpath.replace('.', '/')}.k" - k_files.append(file) - - if len(k_files) == 0: - missing_pkgs.append(pkgpath) - return - - pkgs[pkgpath]: typing.List[ast.Module] = [] - - k_files.sort() - for filename in k_files: - with open(filename, "r", encoding="utf-8") as f: - code = str(f.read()) - - m = ParseFile(filename, code, pkg=pkgpath, mode=mode) - m.relative_filename = m.filename.replace(root, ".", 1) - preprocess.fix_identifier_prefix(m) - fix.fix_and_get_module_import_list(root, m) - fix.fix_qualified_identifier(m) - if set_ast_parent: - fix.fix_set_parent_info(m) - pkgs[pkgpath].append(m) - - # save cache - if modfile.build.enable_pkg_cache: - if modfile.build.cached_pkg_prefix and pkgpath.startswith( - modfile.build.cached_pkg_prefix - ): - vfs.SavePkgCache( - root, - pkgpath, - pkgs[pkgpath], - option=get_ast_cache_option(set_ast_parent), - ) - - for m in pkgs[pkgpath]: - import_spec_list = fix.fix_and_get_module_import_list(root, m, False) - for import_spec in import_spec_list: - _loadPackages( - modfile, - import_spec, - pkgs, - missing_pkgs, - main_files, - mode=mode, - set_ast_parent=set_ast_parent, - ) - - return - - -def LoadProgram( - *path: str, - work_dir: str = "", - k_code_list: typing.List[str] = None, - mode: ParseMode = ParseMode.Null, - set_ast_parent: bool = False, - load_packages: bool = True, -) -> ast.Program: - assert len(path) > 0 - # Clear the KCL error file cache map - kcl_error.FileCache.clear() - k_code_list = k_code_list or [] - if work_dir or kclvm.config.current_path: - path_list = [ - str(x).replace( - KCL_MOD_PATH_ENV, - vfs.GetPkgRoot(work_dir or kclvm.config.current_path) or "", - ) - for x in path - ] - else: - path_list = [str(x) for x in path] - k_files: typing.List[str] = [] - kclvm.config.input_file = path_list - for i, s in enumerate(path_list): - s = os.path.abspath(s) - if os.path.isdir(s): - for filename in glob.glob(f"{s}/*.k", recursive=False): - if os.path.basename(filename).startswith("_"): - continue - k_files.append(os.path.abspath(filename)) - elif i < len(k_code_list) or os.path.isfile(s): - k_files.append(os.path.abspath(s)) - else: - arg_msg = ( - f"Cannot find the kcl file, please check whether the file path {s}" - if s - else f"The file path {s} is None" - ) - kcl_error.report_exception( - err_type=kcl_error.ErrType.CannotFindModule_TYPE, arg_msg=arg_msg - ) - - if not k_files: - report_complier_err("No input KCL files") - - if not work_dir: - work_dir = os.path.dirname(k_files[0]) - - root: str = vfs.MustGetPkgRoot(k_files) - if not root: - root = work_dir - - modfile: kclvm.config.KclModFile = vfs.LoadModFile(root) - - pkgs: typing.Dict[str, typing.List[ast.Module]] = {} - missing_pkgs: typing.List[str] = [] - - main_pkg_modules: typing.List[ast.Module] = [] - __kcl_main__: str = "__main__" - import_names = {} - - for i, filename in enumerate(k_files): - code: typing.Optional[str] = None - if i < len(k_code_list): - code = k_code_list[i] - # Save main package cache - m = None - if modfile.build.enable_pkg_cache: - m = vfs.LoadMainPkgCache( - root, filename, option=get_ast_cache_option(set_ast_parent) - ) - if not m: - m = ParseFile( - filename, pkg=__kcl_main__, code=code, mode=ParseMode.ParseComments - ) - m.relative_filename = m.filename.replace(root, ".", 1) - preprocess.fix_identifier_prefix(m) - fix.fix_test_schema_auto_relaxed(m) - import_list = fix.fix_and_get_module_import_list(root, m) - for import_stmt in import_list: - import_names[import_stmt.name] = import_stmt.path - fix.fix_qualified_identifier(m, import_names=import_names) - if set_ast_parent: - fix.fix_set_parent_info(m) - else: - import_list = m.GetImportList() - for import_stmt in import_list: - import_names[import_stmt.name] = import_stmt.path - # Save main package cache - if modfile.build.enable_pkg_cache: - vfs.SaveMainPkgCache( - root, filename, m, option=get_ast_cache_option(set_ast_parent) - ) - m.name = __kcl_main__ - main_pkg_modules.append(m) - - pkgs[__kcl_main__] = main_pkg_modules - - for m in main_pkg_modules: - import_spec_list = fix.fix_and_get_module_import_list(root, m, False) - if load_packages: - for import_spec in import_spec_list: - _loadPackages( - modfile, - import_spec, - pkgs, - missing_pkgs, - k_files, - mode=mode, - set_ast_parent=set_ast_parent, - ) - - return ast.Program(root=root, main=__kcl_main__, pkgs=pkgs) - - -# ----------------------------------------------------------------------------- -# END -# ----------------------------------------------------------------------------- diff --git a/internal/kclvm_py/compiler/vfs/__init__.py b/internal/kclvm_py/compiler/vfs/__init__.py deleted file mode 100644 index 4bb8b268e..000000000 --- a/internal/kclvm_py/compiler/vfs/__init__.py +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2021 The KCL Authors. All rights reserved. - -from .vfs import ( - LoadPkgCache, - SavePkgCache, - LoadMainPkgCache, - SaveMainPkgCache, - LoadBytecodeCache, - SaveBytecodeCache, - IsAbsPkgPath, - IsRelPkgPath, - FixImportPath, - CacheOption, - DEFAULT_CACHE_DIR, - FST_CACHE_DIR, -) -from .kcl_mod import GetPkgRoot, MustGetPkgRoot, LoadModFile - -__all__ = [ - "LoadPkgCache", - "SavePkgCache", - "LoadMainPkgCache", - "SaveMainPkgCache", - "LoadBytecodeCache", - "SaveBytecodeCache", - "IsAbsPkgPath", - "IsRelPkgPath", - "FixImportPath", - "GetPkgRoot", - "MustGetPkgRoot", - "LoadModFile", - "CacheOption", - "DEFAULT_CACHE_DIR", - "FST_CACHE_DIR", -] diff --git a/internal/kclvm_py/compiler/vfs/kcl_mod.py b/internal/kclvm_py/compiler/vfs/kcl_mod.py deleted file mode 100644 index 3e7c99d56..000000000 --- a/internal/kclvm_py/compiler/vfs/kcl_mod.py +++ /dev/null @@ -1,88 +0,0 @@ -# Copyright 2021 The KCL Authors. All rights reserved. - -import typing -import pathlib -import os -import sys - -import toml -import google.protobuf.json_format as json_format - -import kclvm.config -import kclvm.kcl.error as kcl_error - - -def GetPkgRoot( - k_file_path: str, should_current_file_work_dir: bool = True -) -> typing.Optional[str]: - """Search kcl.mod filepath with the KCL file path""" - if not k_file_path: - return None - - # search by kcl.mod file - module_path = pathlib.Path(os.path.abspath(k_file_path)) - root = module_path.root - while module_path: - if module_path == module_path.parent or str(module_path) == root: - break - - kcl_mod_path = module_path.joinpath("kcl.mod") - if kcl_mod_path.exists() and kcl_mod_path.is_file(): - return str(module_path) - - module_path = module_path.parent - - if should_current_file_work_dir and k_file_path.endswith(".k"): - return os.path.dirname(k_file_path) - - return None - - -def MustGetPkgRoot(file_paths: typing.List[str]) -> typing.Optional[str]: - """Search kcl.mod filepath with the KCL file paths, - when found multiple kcl.mod paths, raise a compile error. - """ - # Get kcl.mod paths from input file paths and remove empty path using the filter function. - paths = set( - filter( - None, - [ - GetPkgRoot(file_path, should_current_file_work_dir=False) - for file_path in file_paths or [] - ], - ) - ) - # Not found kcl.mod. - if not paths: - return None - # Find one kcl.mod. - if len(paths) == 1: - return list(paths)[0] - # Find multiple kcl.mod, raise an error. - kcl_error.report_exception( - err_type=kcl_error.ErrType.CompileError_TYPE, - arg_msg=f"conflict kcl.mod file paths: {paths}", - ) - - -def LoadModFile(root: str) -> kclvm.config.KclModFile: - k_mod_file_path = f"{root}/kcl.mod" - - if not os.path.exists(k_mod_file_path): - mod_file = kclvm.config.KclModFile(root=root) - return mod_file - - d = toml.load(k_mod_file_path) - mod_file = kclvm.config.KclModFile(root=root) - json_format.ParseDict(d, mod_file, ignore_unknown_fields=True) - mod_file.root = root - return mod_file - - -if __name__ == "__main__": - if len(sys.argv) < 2 or (sys.argv[1] == "-h" or sys.argv[1] == "-help"): - print("usage: python3 ./this_py_file ") - sys.exit(0) - - f = LoadModFile(sys.argv[1]) - print(f) diff --git a/internal/kclvm_py/compiler/vfs/vfs.py b/internal/kclvm_py/compiler/vfs/vfs.py deleted file mode 100644 index 54f93f273..000000000 --- a/internal/kclvm_py/compiler/vfs/vfs.py +++ /dev/null @@ -1,373 +0,0 @@ -# Copyright 2021 The KCL Authors. All rights reserved. - -import re -import pathlib -import pickle -import os -import hashlib -import time - -from dataclasses import dataclass -from typing import Dict - -import kclvm.api.version as ver_pkg -import kclvm.api.object as objpkg -import kclvm.kcl.ast as ast - -from filelock import FileLock - -# ------------- -# Type alias -# ------------- - -CacheInfo = str -Cache = Dict[str, CacheInfo] - -LOCK_SUFFIX = ".lock" -NORMAL_CACHE_SUFFIX = ".data" -BYTECODE_CACHE_PREFIX = "bytecode" -BYTECODE_CACHE_SUFFIX = ".kclc" -DEFAULT_CACHE_DIR = ".kclvm/cache" -FST_CACHE_DIR = ".kclvm/fst_cache" -CACHE_INFO_FILENAME = "info.pickle" - - -@dataclass -class CacheOption: - cache_dir: str = DEFAULT_CACHE_DIR - - -def _get_cache_dir(root: str, cache_dir: str = DEFAULT_CACHE_DIR) -> str: - return os.path.join(root, cache_dir, f"{ver_pkg.VERSION}-{ver_pkg.CHECKSUM}") - - -def _get_cache_filename( - root: str, pkgpath: str, cache_dir: str = DEFAULT_CACHE_DIR -) -> str: - return os.path.join( - root, - cache_dir, - f"{ver_pkg.VERSION}-{ver_pkg.CHECKSUM}", - f"{pkgpath}{NORMAL_CACHE_SUFFIX}", - ) - - -def _get_cache_info_filename(root: str, cache_dir: str = DEFAULT_CACHE_DIR): - return os.path.join( - root, cache_dir, f"{ver_pkg.VERSION}-{ver_pkg.CHECKSUM}", CACHE_INFO_FILENAME - ) - - -def _get_cache_bytecode_filename( - root: str, check_sum: str, cache_dir: str = DEFAULT_CACHE_DIR -): - return os.path.join( - root, - cache_dir, - f"{ver_pkg.VERSION}-{ver_pkg.CHECKSUM}", - f"{BYTECODE_CACHE_PREFIX}_{check_sum}{BYTECODE_CACHE_SUFFIX}", - ) - - -def read_info_cache(root: str, cache_dir: str = DEFAULT_CACHE_DIR) -> Cache: - """Read the cache if it exists and is well formed. - If it is not well formed, the call to write_info_cache later should resolve the issue. - """ - cache_file = pathlib.Path(_get_cache_info_filename(root, cache_dir=cache_dir)) - if not cache_file.exists(): - return {} - - with cache_file.open("rb") as fobj: - try: - cache: Cache = pickle.load(fobj) - except (pickle.UnpicklingError, ValueError): - return {} - - return cache - - -def write_info_cache( - cache: Cache, root: str, filepath: str, cache_dir: str = DEFAULT_CACHE_DIR -) -> None: - """Update the cache info file.""" - dst_filename = _get_cache_info_filename(root, cache_dir=cache_dir) - try: - cache_dir = _get_cache_dir(root, cache_dir=cache_dir) - pathlib.Path(cache_dir).mkdir(parents=True, exist_ok=True) - relative_path = filepath.replace(root, ".", 1) - new_cache = { - **cache, - **{relative_path: get_cache_info(filepath)}, - } - tmp_filename = f"{cache_dir}/.{os.getpid()}{time.time_ns()}.tmp" - # Write cache atomic - with FileLock(dst_filename + LOCK_SUFFIX): - f = open(tmp_filename, "wb") - pickle.dump(new_cache, f) - f.flush() - os.fsync(f.fileno()) - f.close() - os.rename(tmp_filename, dst_filename) - except (pickle.UnpicklingError, ValueError): - f.close() - os.remove(tmp_filename) - - -def get_cache_info(path: str) -> CacheInfo: - """Return the information used to check if a file or path is already changed or not.""" - path = pathlib.Path(path) - check_sum = hashlib.md5() - if os.path.isfile(path): - with open(path, "rb") as f: - check_sum.update(f.read()) - else: - for file in list(sorted(path.glob("*.k"))): - with open(file, "rb") as f: - check_sum.update(f.read()) - return check_sum.hexdigest() - - -def get_pkg_realpath_from_pkgpath(root: str, pkgpath: str) -> str: - """Get the pkgpath real path in the file system according to the root and pkgpath""" - filepath = f"{root}/{pkgpath.replace('.', '/')}" - if os.path.isfile(f"{filepath}.k"): - filepath = f"{filepath}.k" - return filepath - - -def load_data_from_file(filename) -> any: - f = open(filename, "rb") - # PyCharm - # noinspection PyBroadException - try: - x = pickle.load(f) - f.close() - return x - except Exception: - f.close() - os.remove(filename) - return None - - -def save_data_to_file(dst_filename: str, tmp_filename: str, x: any): - try: - with FileLock(dst_filename + LOCK_SUFFIX): - # write cache atomic - f = open(tmp_filename, "wb") - # PyCharm - # noinspection PyBroadException - pickle.dump(x, f) - f.flush() - os.fsync(f.fileno()) - f.close() - os.rename(tmp_filename, dst_filename) - return - except Exception: - f.close() - os.remove(tmp_filename) - return - - -def LoadPkgCache(root: str, pkgpath: str, option: CacheOption = CacheOption()) -> any: - if not root or not pkgpath: - return None - - filename = _get_cache_filename(root, pkgpath, cache_dir=option.cache_dir) - if not os.path.exists(filename): - return None - - # Compare the md5 using cache - realpath = get_pkg_realpath_from_pkgpath(root, pkgpath) - if os.path.exists(realpath): - cache_info = read_info_cache(root, cache_dir=option.cache_dir) - relative_path = realpath.replace(root, ".", 1) - path_info_in_cache = cache_info.get(relative_path) - path_info = get_cache_info(realpath) - if path_info_in_cache != path_info: - return None - - return load_data_from_file(filename) - - -def SavePkgCache(root: str, pkgpath: str, x: any, option: CacheOption = CacheOption()): - if not root or not pkgpath or not x: - return - - dst_filename = _get_cache_filename(root, pkgpath, cache_dir=option.cache_dir) - - # Save the pkgpath timesample and filesize into the cache - realpath = get_pkg_realpath_from_pkgpath(root, pkgpath) - if os.path.exists(realpath): - cache_info = read_info_cache(root, cache_dir=option.cache_dir) - write_info_cache(cache_info, root, realpath, cache_dir=option.cache_dir) - - cache_dir = _get_cache_dir(root, cache_dir=option.cache_dir) - pathlib.Path(cache_dir).mkdir(parents=True, exist_ok=True) - - tmp_filename = f"{cache_dir}/{pkgpath}.{os.getpid()}{time.time_ns()}.tmp" - - save_data_to_file(dst_filename, tmp_filename, x) - - -def LoadMainPkgCache( - root: str, filename: str, option: CacheOption = CacheOption() -) -> any: - if not root or not filename: - return None - - cache_name = filename.replace(root, "").replace("/", "_") - cache_filename = _get_cache_filename(root, cache_name, cache_dir=option.cache_dir) - - if not os.path.exists(cache_filename): - return None - - # Compare the md5 using cache - if os.path.exists(filename): - cache_info = read_info_cache(root, cache_dir=option.cache_dir) - relative_path = filename.replace(root, ".", 1) - path_info_in_cache = cache_info.get(relative_path) - path_info = get_cache_info(filename) - if path_info_in_cache != path_info: - return None - - return load_data_from_file(cache_filename) - - -def SaveMainPkgCache( - root: str, filename: str, x: any, option: CacheOption = CacheOption() -): - if not root or not filename: - return - - cache_name = filename.replace(root, "").replace("/", "_") - dst_filename = _get_cache_filename(root, cache_name, cache_dir=option.cache_dir) - - if os.path.exists(filename): - cache_info = read_info_cache(root, cache_dir=option.cache_dir) - write_info_cache(cache_info, root, filename, cache_dir=option.cache_dir) - - cache_dir = _get_cache_dir(root, cache_dir=option.cache_dir) - pathlib.Path(cache_dir).mkdir(parents=True, exist_ok=True) - - tmp_filename = f"{cache_dir}/{cache_name}.{os.getpid()}{time.time_ns()}.tmp" - - save_data_to_file(dst_filename, tmp_filename, x) - - -def LoadBytecodeCache( - root: str, ast_program: ast.Program, option: CacheOption = CacheOption() -) -> objpkg.KCLProgram: - if not root: - return None - if not ast_program or not isinstance(ast_program, ast.Program): - return None - if not ast_program.pkgs: - return None - check_sum = ast_program.get_check_sum(root) - cache_filename = _get_cache_bytecode_filename( - root, check_sum, cache_dir=option.cache_dir - ) - if not os.path.exists(cache_filename): - return None - return load_data_from_file(cache_filename) - - -def SaveBytecodeCache( - root: str, - ast_program: ast.Program, - program: objpkg.KCLProgram, - option: CacheOption = CacheOption(), -): - if not root: - return - if not ast_program or not isinstance(ast_program, ast.Program): - return - if not program or not isinstance(program, objpkg.KCLProgram): - return - pkgs = list(program.pkgs.keys()) if program.pkgs else None - if not pkgs: - return - check_sum = ast_program.get_check_sum(root) - dst_filename = _get_cache_bytecode_filename( - root, check_sum, cache_dir=option.cache_dir - ) - if os.path.exists(dst_filename): - return - cache_dir = _get_cache_dir(root, cache_dir=option.cache_dir) - pathlib.Path(cache_dir).mkdir(parents=True, exist_ok=True) - - tmp_filename = f"{cache_dir}/{os.getpid()}{time.time_ns()}.kclc.tmp" - - save_data_to_file(dst_filename, tmp_filename, program) - - -def IsAbsPkgPath(s: str) -> bool: - if not s or not isinstance(s, str): - return False - if s.startswith("."): - return False - if os.path.isabs(s): - return False - if ".." in s: - return False - if re.search(r"\s", s): - return False - - return True - - -def IsRelPkgPath(s: str) -> bool: - return s.strip().startswith(".") if s and isinstance(s, str) else False - - -def FixImportPath(root: str, filepath: str, import_path: str) -> str: - """ - relpath: import .sub - FixImportPath(root, "path/to/app/file.k", ".sub") => path.to.app.sub - FixImportPath(root, "path/to/app/file.k", "..sub") => path.to.sub - FixImportPath(root, "path/to/app/file.k", "...sub") => path.sub - FixImportPath(root, "path/to/app/file.k", "....sub") => sub - FixImportPath(root, "path/to/app/file.k", ".....sub") => "" - - abspath: import path.to.sub - FixImportPath(root, "path/to/app/file.k", "path.to.sub") => path.to.sub - """ - assert root - assert filepath - assert import_path - - if not import_path.startswith("."): - return import_path - - # Filepath to pkgpath - pkgpath: str = ( - os.path.relpath(os.path.dirname(filepath), root).replace("/", ".").rstrip(".") - ) - pkgpath = pkgpath.replace("\\", ".").rstrip(".") - - leading_dot_count = len(import_path) - for i in range(len(import_path)): - if import_path[i] != ".": - leading_dot_count = i - break - - # The pkgpath is the current root path - if not pkgpath: - return import_path.lstrip(".") if leading_dot_count <= 1 else "" - - if leading_dot_count == 1: - return pkgpath + import_path - - ss = pkgpath.split(".") - - if (leading_dot_count - 1) < len(ss): - return ( - ".".join(ss[: -(leading_dot_count - 1)]) - + "." - + import_path[leading_dot_count:] - ) - - if (leading_dot_count - 1) == len(ss): - return import_path[leading_dot_count:] - - return "" diff --git a/internal/kclvm_py/config/__init__.py b/internal/kclvm_py/config/__init__.py deleted file mode 100644 index eee38774f..000000000 --- a/internal/kclvm_py/config/__init__.py +++ /dev/null @@ -1,53 +0,0 @@ -# Copyright 2021 The KCL Authors. All rights reserved. - -from .config import ( - verbose, - debug, - save_temps, - output, - input_file, - current_path, - disable_none, - strict_range_check, - arguments, - list_option_mode, - disable_schema_check, - options_help_message, - path_selector, - overrides, - dump, - parse_config, - is_target_native, - KCLTopLevelArgumentAction, - KCLPathSelectorAction, - KCLOverrideAction, - KCLCLISettingAction, -) -from .modfile_pb2 import KclModFile -from .settings import load_settings_files - -__all__ = [ - "verbose", - "debug", - "save_temps", - "output", - "input_file", - "current_path", - "disable_none", - "strict_range_check", - "arguments", - "list_option_mode", - "disable_schema_check", - "options_help_message", - "path_selector", - "overrides", - "dump", - "parse_config", - "is_target_native", - "KCLTopLevelArgumentAction", - "KCLPathSelectorAction", - "KCLOverrideAction", - "KCLCLISettingAction", - "KclModFile", - "load_settings_files", -] diff --git a/internal/kclvm_py/config/config.py b/internal/kclvm_py/config/config.py deleted file mode 100644 index bf9680aa5..000000000 --- a/internal/kclvm_py/config/config.py +++ /dev/null @@ -1,371 +0,0 @@ -from ast import literal_eval -from copy import deepcopy -from pathlib import Path -from typing import List -import argparse as _argparse -import ruamel.yaml as _yaml -from io import StringIO - -import kclvm.kcl.ast as ast -import kclvm.kcl.error as kcl -import kclvm.config - -verbose = 0 -""" -Print more information and intermediate representation. -""" - -debug = 0 -""" -Print debug information for developers. -""" - -save_temps = False -""" -Save the intermediate representation files. -""" - -output = None -""" -The name of the output file. -""" - -input_file = None -""" -The name of the input file. -""" - -current_path = None -""" -The current path where KCL is executed. -""" - -disable_none = False -""" -Disable dumping values that are None. -""" - -strict_range_check = False -""" -Whether perform strict numberic range check -""" - -arguments = [] -""" -Top level arguments. -""" - -list_option_mode = 0 -""" -List option mode (>= 0). -""" - -disable_schema_check = False -""" -Disabel schema check -""" - -options_help_message = "" -""" -Optopns help message -""" - -path_selector = [] -""" -The path selector -""" - -overrides = [] -""" -The configuration override path and value -""" - -is_target_native = False -"""Whether the target is 'native'""" - - -def dump(): - if verbose: - print("=== Configurations ===") - print("verbose = {}".format(verbose)) - print("save_temps = {}".format(save_temps)) - print("output = {}".format(output)) - print("disable_none = {}".format(disable_none)) - print("input_file = {}".format(input_file)) - print("current_path = {}".format(current_path)) - print("arguments = {}".format(arguments)) - print("strict_range_check = {}".format(strict_range_check)) - - print("list_option_mode = {}".format(list_option_mode)) - print("disable_schema_check = {}".format(disable_schema_check)) - - -def parse_config(argsdict: dict): - """ - Parse kclvm config with cli argument dict - """ - if not argsdict: - return - kclvm.config.verbose = ( - int(argsdict.get(KCLCLIFlag.VERBOSE, 0)) or kclvm.config.verbose - ) - kclvm.config.debug = int(argsdict.get(KCLCLIFlag.DEBUG, 0)) or kclvm.config.debug - kclvm.config.list_option_mode = ( - int(argsdict.get(KCLCLIFlag.LIST_OPTION_MODE, 0)) - or kclvm.config.list_option_mode - ) - kclvm.config.save_temps = ( - argsdict.get(KCLCLIFlag.SAVE_TEMPS, False) or kclvm.config.save_temps - ) - kclvm.config.strict_range_check = ( - argsdict.get(KCLCLIFlag.STRICT_RANGE_CHECK) or kclvm.config.strict_range_check - ) - kclvm.config.disable_none = ( - argsdict.get(KCLCLIFlag.DISABLE_NONE, False) or kclvm.config.disable_none - ) - kclvm.config.path_selector = argsdict.get( - KCLCLIFlag.PATH_SELECTOR, kclvm.config.path_selector - ) - kclvm.config.overrides = argsdict.get(KCLCLIFlag.OVERRIDES, kclvm.config.overrides) - kclvm.config.input_file = ( - argsdict.get(KCLCLIFlag.FILES) - or argsdict.get(KCLCLIFlag.FILE) - or kclvm.config.input_file - ) - kclvm.config.output = ( - argsdict.get(KCLCLIFlag.OUTPUT) - if argsdict.get(KCLCLIFlag.OUTPUT) - else kclvm.config.output - ) - kclvm.config.arguments += argsdict.get(KCLCLIFlag.ARGUMENT, []) - - -def _deal_key_value(values, keys, vals): - is_valid_value = False - _k, _v = None, None - try: - _k, _v = values - _v = literal_eval(_v) - except Exception: - pass - # _v is a string type, and avoid quotation ' and " mark escape error - _v = _v.replace("'", "\\'").replace('"', '\\"') if isinstance(_v, str) else _v - # the _v can only be KCL internal type - if _v is None or isinstance(_v, (bool, int, float, str, list, dict)): - is_valid_value = True - if _k is None or not isinstance(_k, str) or _k.strip() == "": - kcl.report_exception( - err_type=kcl.ErrType.IllegalArgumentError_TYPE, - arg_msg=f"Invalid option name: '{_k}'. should be a non-empty string", - ) - if not is_valid_value: - kcl.report_exception( - err_type=kcl.ErrType.IllegalArgumentError_TYPE, - arg_msg=f"Invalid option value: '{_object_to_yaml_str(_v)}' for option(\"{_k}\").", - ) - keys.append(_k) - vals.append(_v) - - -class KCLCLIFlag: - FILE = "file" - FILES = "files" - DISABLE_NONE = "disable_none" - DEBUG = "debug" - STRICT_RANGE_CHECK = "strict_range_check" - OUTPUT = "output" - VERBOSE = "verbose" - SAVE_TEMPS = "save_temps" - ARGUMENT = "argument" - PATH_SELECTOR = "path_selector" - OVERRIDES = "overrides" - LIST_OPTION_MODE = "list_option_mode" - - -class KCLTopLevelArgumentAction(_argparse.Action): - """KCL CLI top level argument argparse action""" - - def __call__(self, parser, namespace, values, option_string=None): - invalid_arg_msg = 'Invalid value for option "--argument(-D)"' - split_values = values.split("=") - _keys, _vals = [], [] - if len(split_values) == 2 and str(split_values[1]).strip() != "": - try: - _deal_key_value(split_values, _keys, _vals) - except Exception as err: - err_msg = err.arg_msg if isinstance(err, kcl.KCLException) else err - kcl.report_exception( - err_type=kcl.ErrType.IllegalArgumentError_TYPE, - arg_msg=f"{invalid_arg_msg}: {err_msg}", - ) - else: - kcl.report_exception( - err_type=kcl.ErrType.IllegalArgumentError_TYPE, - arg_msg=f"{invalid_arg_msg}: should be in = pattern, got: {values}", - ) - args = getattr(namespace, self.dest) - args = [] if args is None else deepcopy(args) - args += [(_k, _v) for _k, _v in zip(_keys, _vals)] - setattr(namespace, self.dest, args) - - -class KCLPathSelectorAction(_argparse.Action): - """KCL path selector action""" - - def __call__(self, parser, namespace, values, option_string=None): - def report_exception(): - kcl.report_exception( - err_type=kcl.ErrType.IllegalArgumentError_TYPE, - arg_msg=f"Invalid value for option \"--path-selector(-S)\": '{values}'. path selector should be in : pattern", - ) - - split_values = values.split(":", 1) - if len(split_values) > 2: - report_exception() - split_values = split_values if len(split_values) == 2 else ["", *split_values] - args = getattr(namespace, self.dest) - args = [] if args is None else deepcopy(args) - args += [split_values] - setattr(namespace, self.dest, args) - - -class KCLOverrideAction(_argparse.Action): - """KCL path override action""" - - def __call__(self, parser, namespace, values, option_string=None): - def report_exception(): - kcl.report_exception( - err_type=kcl.ErrType.IllegalArgumentError_TYPE, - arg_msg=f"Invalid value for option \"--override(-O)\": '{values}'. the override expr should be in = pattern", - ) - - args = getattr(namespace, self.dest) - if "=" in values: - split_values = values.split("=", 1) - paths = split_values[0].split(":", 1) - if len(split_values) < 2 or len(paths) > 2: - report_exception() - paths.append(split_values[1]) - args = [] if args is None else deepcopy(args) - paths = paths if len(paths) == 3 else ["", *paths] - paths += [ast.OverrideAction.CREATE_OR_UPDATE] - args += [paths] - elif values.endswith("-"): - paths = values[:-1].split(":", 1) - if len(paths) > 2: - report_exception() - paths = paths if len(paths) == 2 else ["", *paths] - paths += ["", ast.OverrideAction.DELETE] - args += [paths] - setattr(namespace, self.dest, args) - - -class KCLCLISettingAction: - """KCL CLI top level setting argparse action""" - - DEFAULT_SETTING_PATH = "kcl.yaml" - OPTION_FILE_TYPES = [".yaml", ".yml"] - KCL_OPTION_KEY = "kcl_options" - KCL_CLI_CONFIG_KEY = "kcl_cli_configs" - - ARGUMENTS_ITEM_KEY = "key" - ARGUMENTS_ITEM_VALUE = "value" - - KCL_OPTION_EXAMPLE = """ -kcl_options: - - key: myArg # the option key must be a string value - value: myArgValue""" - INVALID_OPTION_MSG = f"invalid kcl_options value, should be list of key/value mapping. \n=== A good example will be:==={KCL_OPTION_EXAMPLE}" - - def deal_config_obj(self, data: dict, keys: list, vals: list) -> bool: - if data is None or not isinstance(data, dict): - kcl.report_exception( - err_type=kcl.ErrType.IllegalArgumentError_TYPE, - arg_msg=f"setting file content should be a mapping, got: {_object_to_yaml_str(data)}", - ) - # Deal Arguments - kcl_options_mapping_list = data.get(self.KCL_OPTION_KEY) or [] - if not isinstance(kcl_options_mapping_list, list): - kcl.report_exception( - err_type=kcl.ErrType.IllegalArgumentError_TYPE, - arg_msg=f"{self.INVALID_OPTION_MSG}\n=== got: ===\n{_object_to_yaml_str({self.KCL_OPTION_KEY: kcl_options_mapping_list})}", - ) - for key_value in kcl_options_mapping_list: - if key_value is None or not isinstance(key_value, dict): - kcl.report_exception( - err_type=kcl.ErrType.IllegalArgumentError_TYPE, - arg_msg=f"{self.INVALID_OPTION_MSG}\n=== got: ===\n{_object_to_yaml_str({self.KCL_OPTION_KEY: [key_value]})}", - ) - _deal_key_value( - ( - key_value.get(self.ARGUMENTS_ITEM_KEY), - key_value.get(self.ARGUMENTS_ITEM_VALUE), - ), - keys, - vals, - ) - # Deal KCL CLI parameters - data = data.get(self.KCL_CLI_CONFIG_KEY, {}) - parse_config(data) - return True - - def deal_setting_file(self, filename, keys, vals): - data = None - if any(filename.endswith(t) for t in self.OPTION_FILE_TYPES): - try: - data = _yaml.safe_load(Path(filename).read_text(encoding="utf-8")) - except Exception as err: - err_msg = err.arg_msg if isinstance(err, kcl.KCLException) else err - kcl.report_exception( - err_type=kcl.ErrType.IllegalArgumentError_TYPE, - file_msgs=[kcl.ErrFileMsg(filename=filename)], - arg_msg=f"Invalid yaml content of setting file:\n{err_msg}", - ) - try: - self.deal_config_obj(data or {}, keys, vals) - except Exception as err: - err_msg = err.arg_msg if isinstance(err, kcl.KCLException) else err - kcl.report_exception( - err_type=kcl.ErrType.IllegalArgumentError_TYPE, - file_msgs=[kcl.ErrFileMsg(filename=filename)], - arg_msg=f"Invalid configuration in setting file:\n{err_msg}", - ) - else: - kcl.report_exception( - err_type=kcl.ErrType.IllegalArgumentError_TYPE, - file_msgs=[kcl.ErrFileMsg(filename=filename)], - arg_msg='Invalid value for option "--setting(-Y)": the setting file should be in yaml format', - ) - - def deal(self, filenames: List[str]) -> list: - if not filenames and not Path(self.DEFAULT_SETTING_PATH).exists(): - return [] - args = [] - for filename in filenames or [self.DEFAULT_SETTING_PATH]: - _keys, _vals = [], [] - self.deal_setting_file(filename, _keys, _vals) - args += [(_k, _v) for _k, _v in zip(_keys, _vals)] - return args - - -def _object_to_yaml_str(obj, options=None): - if not isinstance(obj, (list, dict)): - return obj - yaml_config = _yaml.YAML() - yaml_config.indent(mapping=3, sequence=2, offset=0) - yaml_config.allow_duplicate_keys = True - - # show null - def my_represent_none(self, data): - return self.represent_scalar("tag:yaml.org,2002:null", "null") - - yaml_config.representer.add_representer(type(None), my_represent_none) - - # yaml to string - if options is None: - options = {} - string_stream = StringIO() - yaml_config.dump(obj, string_stream, **options) - output_str = string_stream.getvalue() - string_stream.close() - return output_str diff --git a/internal/kclvm_py/config/modfile_pb2.py b/internal/kclvm_py/config/modfile_pb2.py deleted file mode 100644 index 8a04f775e..000000000 --- a/internal/kclvm_py/config/modfile_pb2.py +++ /dev/null @@ -1,54 +0,0 @@ -# -*- coding: utf-8 -*- -# Generated by the protocol buffer compiler. DO NOT EDIT! -# source: modfile/modfile.proto -"""Generated protocol buffer code.""" -from google.protobuf import descriptor as _descriptor -from google.protobuf import descriptor_pool as _descriptor_pool -from google.protobuf import message as _message -from google.protobuf import reflection as _reflection -from google.protobuf import symbol_database as _symbol_database -# @@protoc_insertion_point(imports) - -_sym_db = _symbol_database.Default() - - - - -DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x15modfile/modfile.proto\x12\rkclvm.modfile\"\xa2\x01\n\nKclModFile\x12\x0c\n\x04root\x18\x01 \x01(\t\x12\x10\n\x08root_pkg\x18\x02 \x01(\t\x12\x36\n\x05\x62uild\x18\x03 \x01(\x0b\x32\'.kclvm.modfile.KclModFile_build_section\x12<\n\x08\x65xpected\x18\x04 \x01(\x0b\x32*.kclvm.modfile.KclModFile_expected_section\"_\n\x18KclModFile_build_section\x12\x18\n\x10\x65nable_pkg_cache\x18\x01 \x01(\x08\x12\x19\n\x11\x63\x61\x63hed_pkg_prefix\x18\x02 \x01(\t\x12\x0e\n\x06target\x18\x03 \x01(\t\"\x98\x01\n\x1bKclModFile_expected_section\x12\x16\n\x0emin_build_time\x18\x01 \x01(\t\x12\x16\n\x0emax_build_time\x18\x02 \x01(\t\x12\x15\n\rkclvm_version\x18\x03 \x01(\t\x12\x1a\n\x12kcl_plugin_version\x18\x04 \x01(\t\x12\x16\n\x0eglobal_version\x18\x05 \x01(\tb\x06proto3') - - - -_KCLMODFILE = DESCRIPTOR.message_types_by_name['KclModFile'] -_KCLMODFILE_BUILD_SECTION = DESCRIPTOR.message_types_by_name['KclModFile_build_section'] -_KCLMODFILE_EXPECTED_SECTION = DESCRIPTOR.message_types_by_name['KclModFile_expected_section'] -KclModFile = _reflection.GeneratedProtocolMessageType('KclModFile', (_message.Message,), { - 'DESCRIPTOR' : _KCLMODFILE, - '__module__' : 'modfile.modfile_pb2' - # @@protoc_insertion_point(class_scope:kclvm.modfile.KclModFile) - }) -_sym_db.RegisterMessage(KclModFile) - -KclModFile_build_section = _reflection.GeneratedProtocolMessageType('KclModFile_build_section', (_message.Message,), { - 'DESCRIPTOR' : _KCLMODFILE_BUILD_SECTION, - '__module__' : 'modfile.modfile_pb2' - # @@protoc_insertion_point(class_scope:kclvm.modfile.KclModFile_build_section) - }) -_sym_db.RegisterMessage(KclModFile_build_section) - -KclModFile_expected_section = _reflection.GeneratedProtocolMessageType('KclModFile_expected_section', (_message.Message,), { - 'DESCRIPTOR' : _KCLMODFILE_EXPECTED_SECTION, - '__module__' : 'modfile.modfile_pb2' - # @@protoc_insertion_point(class_scope:kclvm.modfile.KclModFile_expected_section) - }) -_sym_db.RegisterMessage(KclModFile_expected_section) - -if _descriptor._USE_C_DESCRIPTORS == False: - - DESCRIPTOR._options = None - _KCLMODFILE._serialized_start=41 - _KCLMODFILE._serialized_end=203 - _KCLMODFILE_BUILD_SECTION._serialized_start=205 - _KCLMODFILE_BUILD_SECTION._serialized_end=300 - _KCLMODFILE_EXPECTED_SECTION._serialized_start=303 - _KCLMODFILE_EXPECTED_SECTION._serialized_end=455 -# @@protoc_insertion_point(module_scope) diff --git a/internal/kclvm_py/config/settings.py b/internal/kclvm_py/config/settings.py deleted file mode 100644 index 904e2e342..000000000 --- a/internal/kclvm_py/config/settings.py +++ /dev/null @@ -1,70 +0,0 @@ -# Copyright 2021 The KCL Authors. All rights reserved. - -import pathlib -from typing import List - -import kclvm.config -import kclvm.internal.util as util -import kclvm.internal.gpyrpc.gpyrpc_pb2 as pb2 - - -KCL_MOD_PATH_ENV = "${KCL_MOD}" - - -def load_settings_files( - work_dir: str, files: List[str] -) -> pb2.LoadSettingsFiles_Result: - """Load KCL CLI config from the setting files. - - Parameter - --------- - work_dir : str - The kcl run work directory. - files: - The setting YAML files. - - Returns - ------- - result: LoadSettingsFiles_Result - The merged kcl singleton config. - """ - from kclvm.compiler.vfs import GetPkgRoot - - if not files: - return pb2.LoadSettingsFiles_Result( - kcl_cli_configs=pb2.CliConfig(), kcl_options=[] - ) - key_value_pairs = [ - pb2.KeyValuePair(key=k, value=v) - for k, v in util.merge_option_same_keys( - kclvm.config.KCLCLISettingAction().deal(files) - ).items() - ] - if work_dir or kclvm.config.current_path: - files = [ - str( - pathlib.Path(work_dir) - .joinpath( - str(x).replace( - KCL_MOD_PATH_ENV, - GetPkgRoot(work_dir or kclvm.config.current_path or files[0]) - or "", - ) - ) - .resolve() - ) - for x in kclvm.config.input_file - ] - return pb2.LoadSettingsFiles_Result( - kcl_cli_configs=pb2.CliConfig( - files=files, - output=kclvm.config.output, - overrides=kclvm.config.overrides, - path_selector=kclvm.config.path_selector, - strict_range_check=kclvm.config.strict_range_check, - disable_none=kclvm.config.disable_none, - verbose=kclvm.config.verbose, - debug=kclvm.config.debug, - ), - kcl_options=key_value_pairs, - ) diff --git a/internal/kclvm_py/encoding/__init__.py b/internal/kclvm_py/encoding/__init__.py deleted file mode 100644 index d74aaf8ad..000000000 --- a/internal/kclvm_py/encoding/__init__.py +++ /dev/null @@ -1 +0,0 @@ -# Copyright 2021 The KCL Authors. All rights reserved. diff --git a/internal/kclvm_py/encoding/protobuf/__init__.py b/internal/kclvm_py/encoding/protobuf/__init__.py deleted file mode 100644 index ead1b79e0..000000000 --- a/internal/kclvm_py/encoding/protobuf/__init__.py +++ /dev/null @@ -1,96 +0,0 @@ -"""The `protobuf` module defines functionality for parsing protocol buffer -definitions and instances. - -Proto definition mapping follows the guidelines of mapping Proto to JSON as -discussed in https://developers.google.com/protocol-buffers/docs/proto3, and -carries some of the mapping further when possible with KCL. - -The following type mappings of definitions apply: - - Proto type KCL type/def Comments - message schema Message fields become KCL attribute, whereby - names are mapped to lowerCamelCase. - enum e1 | e2 | ... Where ex are strings. A separate mapping is - generated to obtain the numeric values. - oneof e1 | e2 | ... KCL union type. - map {K:V} - repeated V [V] - bool bool - string str - bytes str A base64-encoded string when converted to JSON. - int32, fixed32 int An integer with bounds as defined by int. - uint32 int An integer with bounds as defined by int. - int64, fixed64 int An integer with bounds as defined by int. - uint64 int An integer with bounds as defined by int. - float float A number with bounds as defined by float. - double float A number with bounds as defined by float. - Struct schema - Value any - google.proto.Any any - ListValue [...] - NullValue any - BoolValue bool - StringValue str - NumberValue float - StringValue str - Empty any - Timestamp float - Duration int - -Protobuf definitions can be annotated with KCL constraints that are included -in the generated KCL: - (kcl.opt) FieldOptions - val str KCL attribute default value. - optional bool Whether the KCL attribute is optional - final bool Whether the KCL attribute is final - -:copyright: Copyright 2020 The KCL Authors. All rights reserved. -""" - -from .parser import ( - Import, - Package, - Option, - Field, - OneOfField, - OneOf, - Map, - Reserved, - Range, - EnumField, - Enum, - Message, - Service, - Rpc, - Proto, - ImportOption, - Type, - KeyType, - parse_code, -) -from .protobuf import ( - protobuf_to_kcl, -) - -__all__ = [ - "Import", - "Package", - "Option", - "Field", - "OneOfField", - "OneOf", - "Map", - "Reserved", - "Range", - "EnumField", - "Enum", - "Message", - "Service", - "Rpc", - "Proto", - "ImportOption", - "Type", - "KeyType", - "parse_code", - "protobuf_to_kcl", -] diff --git a/internal/kclvm_py/encoding/protobuf/kcl.proto b/internal/kclvm_py/encoding/protobuf/kcl.proto deleted file mode 100644 index 10b4ece1a..000000000 --- a/internal/kclvm_py/encoding/protobuf/kcl.proto +++ /dev/null @@ -1,15 +0,0 @@ -syntax = "proto3"; - -package kcl; - -import "google/protobuf/descriptor.proto"; - -message FieldOptions { - string val = 1; - bool optional = 2; - bool final = 3; -} - -extend google.protobuf.FieldOptions { - FieldOptions opt = 1; -} diff --git a/internal/kclvm_py/encoding/protobuf/parser.py b/internal/kclvm_py/encoding/protobuf/parser.py deleted file mode 100644 index afc340687..000000000 --- a/internal/kclvm_py/encoding/protobuf/parser.py +++ /dev/null @@ -1,477 +0,0 @@ -# -*- coding: utf-8 -*- - -# Parser for protocol buffer .proto files -# Thanks to https://github.com/python-parsy/parsy/blob/master/examples/proto3.py -import enum as stdlib_enum -from string import ascii_letters, digits, hexdigits, octdigits - -import attr - -from parsy import char_from, from_enum, generate, regex, seq, string - -# This file follows the spec at -# https://developers.google.com/protocol-buffers/docs/reference/proto3-spec -# very closely. - -# However, because we are parsing into useful objects, we do transformations -# along the way e.g. turning into integers, strings etc. and custom objects. -# Some of the lowest level items have been implemented using 'regex' and converting -# the descriptions to regular expressions. Higher level constructs have been -# implemented using other parsy primitives and combinators. - -# Notes: - -# 1. Whitespace is very badly defined in the 'spec', so we guess what is meant. -# 2. The spec doesn't allow for comments, and neither does this parser. -# Other places mention that C++ style comments are allowed. To support that, -# this parser would need to be changed into split lexing/parsing stages -# (otherwise you hit issues with comments start markers within string literals). -# 3. Other notes inline. - - -# Our utilities -def optional_string(s): - return string(s).times(0, 1).concat() - - -def convert_octal(s): - return int(s, 8) - - -def convert_hex(s): - return int(s, 16) - - -def exclude_none(data): - return [i for i in data if i is not None] - - -convert_decimal = int - - -def lexeme(p): - """ - From a parser (or string), make a parser that consumes - whitespace on either side. - """ - if isinstance(p, str): - p = string(p) - return regex(r"\s*") >> p << regex(r"\s*") - - -def is_present(p): - """ - Given a parser or string, make a parser that returns - True if the parser matches, False otherwise - """ - return lexeme(p).optional().map(lambda v: False if v is None else True) - - -# Our data structures -@attr.s -class Import: - identifier = attr.ib() - option = attr.ib() - - -@attr.s -class Package: - identifier = attr.ib() - - -@attr.s -class Option: - name = attr.ib() - value = attr.ib() - - -@attr.s -class Field: - repeated = attr.ib() - type = attr.ib() - name = attr.ib() - number = attr.ib() - options = attr.ib() - - -@attr.s -class OneOfField: - type = attr.ib() - name = attr.ib() - number = attr.ib() - options = attr.ib() - - -@attr.s -class OneOf: - name = attr.ib() - fields = attr.ib() - - -@attr.s -class Map: - key_type = attr.ib() - type = attr.ib() - name = attr.ib() - number = attr.ib() - options = attr.ib() - - -@attr.s -class Reserved: - items = attr.ib() - - -@attr.s -class Range: - from_ = attr.ib() - to = attr.ib() - - -@attr.s -class EnumField: - name = attr.ib() - value = attr.ib() - options = attr.ib() - - -@attr.s -class Enum: - name = attr.ib() - body = attr.ib() - - -@attr.s -class Message: - name = attr.ib() - body = attr.ib() - - -@attr.s -class Service: - name = attr.ib() - body = attr.ib() - - -@attr.s -class Rpc: - name = attr.ib() - request_stream = attr.ib() - request_message_type = attr.ib() - response_stream = attr.ib() - response_message_type = attr.ib() - options = attr.ib() - - -@attr.s -class Proto: - syntax = attr.ib() - statements = attr.ib() - - -# Enums: -class ImportOption(stdlib_enum.Enum): - WEAK = "weak" - PUBLIC = "public" - - -class Type(stdlib_enum.Enum): - DOUBLE = "double" - FLOAT = "float" - INT32 = "int32" - INT64 = "int64" - UINT32 = "uint32" - UINT64 = "uint64" - SINT32 = "sint32" - SINT64 = "sint64" - FIXED32 = "fixed32" - FIXED64 = "fixed64" - SFIXED32 = "sfixed32" - SFIXED64 = "sfixed64" - BOOL = "bool" - STRING = "string" - BYTES = "bytes" - - -class KeyType(stdlib_enum.Enum): - INT32 = "int32" - INT64 = "int64" - UINT32 = "uint32" - UINT64 = "uint64" - SINT32 = "sint32" - SINT64 = "sint64" - FIXED32 = "fixed32" - FIXED64 = "fixed64" - SFIXED32 = "sfixed32" - SFIXED64 = "sfixed64" - BOOL = "bool" - STRING = "string" - - -# Some extra constants to avoid typing -SEMI = lexeme(";") -EQ = lexeme("=") -LPAREN = lexeme("(") -RPAREN = lexeme(")") -LBRACE = lexeme("{") -RBRACE = lexeme("}") - -# -- Beginning of following spec -- -# Letters and digits -letter = char_from(ascii_letters) -decimalDigit = char_from(digits) -octalDigit = char_from(octdigits) -hexDigit = char_from(hexdigits) - -# Identifiers - -# Compared to spec, we add some '_' prefixed items which are not wrapped in `lexeme`, -# on the assumption that spaces in the middle of identifiers are not accepted. -_ident = (letter + (letter | decimalDigit | string("_")).many().concat()).desc("ident") -ident = lexeme(_ident) -fullIdent = lexeme(ident + (string(".") + ident).many().concat()).desc("fullIdent") -_messageName = _ident -messageName = lexeme(ident).desc("messageName") -_enumName = ident -enumName = lexeme(_enumName).desc("enumName") -fieldName = ident.desc("fieldName") -oneofName = ident.desc("oneofName") -mapName = ident.desc("mapName") -serviceName = ident.desc("serviceName") -rpcName = ident.desc("rpcName") -messageType = ( - optional_string(".") + (_ident + string(".")).many().concat() + _messageName -) -enumType = optional_string(".") + (_ident + string(".")).many().concat() + _enumName - -# Integer literals -decimalLit = regex("[1-9][0-9]*").desc("decimalLit").map(convert_decimal) -octalLit = regex("0[0-7]*").desc("octalLit").map(convert_octal) -hexLit = regex("0[x|X][0-9a-fA-F]+").desc("octalLit").map(convert_hex) -intLit = decimalLit | octalLit | hexLit - - -# Floating-point literals -decimals = r"[0-9]+" -exponent = r"[e|E][+|-]?" + decimals -floatLit = ( - regex( - r"({decimals}\.({decimals})?({exponent})?)|{decimals}{exponent}|\.{decimals}({exponent})?".format( - decimals=decimals, exponent=exponent - ) - ) - .desc("floatLit") - .map(float) -) - - -# Boolean -boolLit = (string("true").result(True) | string("false").result(False)).desc("boolLit") - - -# String literals -hexEscape = regex(r"\\[x|X]") >> regex("[0-9a-fA-F]{2}").map(convert_hex).map(chr) -octEscape = regex(r"\\") >> regex("[0-7]{2}").map(convert_octal).map(chr) -charEscape = regex(r"\\") >> ( - string("a").result("\a") - | string("b").result("\b") - | string("f").result("\f") - | string("n").result("\n") - | string("r").result("\r") - | string("t").result("\t") - | string("v").result("\v") - | string("\\").result("\\") - | string("'").result("'") - | string('"').result('"') -) -escapes = hexEscape | octEscape | charEscape -# Correction to spec regarding " and ' inside quoted strings -strLit = ( - string("'") >> (escapes | regex(r"[^\0\n\'\\]")).many().concat() << string("'") - | string('"') >> (escapes | regex(r"[^\0\n\"\\]")).many().concat() << string('"') -).desc("strLit") -quote = string("'") | string('"') - -# EmptyStatement -emptyStatement = string(";").result(None) - - -# Signed numbers: -def signedNumberChange(s, num): - """(Extra compared to spec, to cope with need to produce signed numeric values)""" - return (-1) if s == "-" else (+1) - - -sign = regex("[-+]?") -signedIntLit = seq(sign, intLit).combine(signedNumberChange) -signedFloatLit = seq(sign, floatLit).combine(signedNumberChange) - - -# Constant -# put fullIdent at end to disabmiguate from boolLit -constant = signedIntLit | signedFloatLit | strLit | boolLit | fullIdent - -# Syntax -syntax = lexeme("syntax") >> EQ >> quote >> string("proto3") << quote + SEMI - -# Import Statement -import_option = from_enum(ImportOption) - -import_ = seq( - lexeme("import") >> import_option.optional().tag("option"), - lexeme(strLit).tag("identifier") << SEMI, -).combine_dict(Import) - -# Package -package = seq(lexeme("package") >> fullIdent << SEMI).map(Package) - -# Option -optionName = (ident | (LPAREN >> fullIdent << RPAREN)) + ( - string(".") + ident -).many().concat() -option = seq( - lexeme("option") >> optionName.tag("name"), - EQ >> constant.tag("value") << SEMI, -).combine_dict(Option) - -# Normal field -type_ = lexeme(from_enum(Type) | messageType | enumType) -fieldNumber = lexeme(intLit) - -fieldOption = seq(optionName.tag("name"), EQ >> constant.tag("value")).combine_dict( - Option -) -fieldOptions = fieldOption.sep_by(lexeme(","), min=1) -fieldOptionList = ( - (lexeme("[") >> fieldOptions << lexeme("]")) - .optional() - .map(lambda o: [] if o is None else o) -) - -field = seq( - is_present("repeated").tag("repeated"), - type_.tag("type"), - fieldName.tag("name") << EQ, - fieldNumber.tag("number"), - fieldOptionList.tag("options") << SEMI, -).combine_dict(Field) - - -# Oneof and oneof field -oneofField = seq( - type_.tag("type"), - fieldName.tag("name") << EQ, - fieldNumber.tag("number"), - fieldOptionList.tag("options") << SEMI, -).combine_dict(OneOfField) -oneof = seq( - lexeme("oneof") >> oneofName.tag("name"), - LBRACE - >> (oneofField | emptyStatement).many().map(exclude_none).tag("fields") - << RBRACE, -).combine_dict(OneOf) - -# Map field -keyType = lexeme(from_enum(KeyType)) -mapField = seq( - lexeme("map") >> lexeme("<") >> keyType.tag("key_type"), - lexeme(",") >> type_.tag("type"), - lexeme(">") >> mapName.tag("name"), - EQ >> fieldNumber.tag("number"), - fieldOptionList.tag("options") << SEMI, -).combine_dict(Map) - -# Reserved -range_ = seq( - lexeme(intLit).tag("from_"), - (lexeme("to") >> (intLit | lexeme("max"))).optional().tag("to"), -).combine_dict(Range) -ranges = range_.sep_by(lexeme(","), min=1) -# The spec for 'reserved' indicates 'fieldName' here, which is never a quoted string. -# But the example has a quoted string. We have changed it to 'strLit' -fieldNames = strLit.sep_by(lexeme(","), min=1) -reserved = seq(lexeme("reserved") >> (ranges | fieldNames) << SEMI).combine(Reserved) - -# Enum definition -enumValueOption = seq(optionName.tag("name") << EQ, constant.tag("value")).combine_dict( - Option -) -enumField = seq( - ident.tag("name") << EQ, - lexeme(intLit).tag("value"), - (lexeme("[") >> enumValueOption.sep_by(lexeme(","), min=1) << lexeme("]")) - .optional() - .map(lambda o: [] if o is None else o) - .tag("options") - << SEMI, -).combine_dict(EnumField) -enumBody = ( - LBRACE >> (option | enumField | emptyStatement).many().map(exclude_none) << RBRACE -) -enum = seq(lexeme("enum") >> enumName.tag("name"), enumBody.tag("body")).combine_dict( - Enum -) - - -# Message definition -@generate -def message(): - yield lexeme("message") - name = yield messageName - body = yield messageBody - return Message(name=name, body=body) - - -messageBody = ( - LBRACE - >> ( - field | enum | message | option | oneof | mapField | reserved | emptyStatement - ).many() - << RBRACE -) - - -# Service definition -rpc = seq( - lexeme("rpc") >> rpcName.tag("name"), - LPAREN >> (is_present("stream").tag("request_stream")), - messageType.tag("request_message_type") << RPAREN, - lexeme("returns") >> LPAREN >> (is_present("stream").tag("response_stream")), - messageType.tag("response_message_type") << RPAREN, - ((LBRACE >> (option | emptyStatement).many() << RBRACE) | SEMI.result([])) - .optional() - .map(exclude_none) - .tag("options"), -).combine_dict(Rpc) - -service = seq( - lexeme("service") >> serviceName.tag("name"), - LBRACE - >> (option | rpc | emptyStatement).many().map(exclude_none).tag("body") - << RBRACE, -).combine_dict(Service) - - -# Proto file -topLevelDef = message | enum | service -proto = seq( - syntax.tag("syntax"), - (import_ | package | option | topLevelDef | emptyStatement) - .many() - .map(exclude_none) - .tag("statements"), -).combine_dict(Proto) - - -def parse_code(code: str) -> Proto: - """Parse a proto code string - - Parameters - ---------- - code : str. The proto code string. - - Returns - ------- - result : Proto. The proto node structure. - """ - return proto.parse(code) diff --git a/internal/kclvm_py/encoding/protobuf/printer.py b/internal/kclvm_py/encoding/protobuf/printer.py deleted file mode 100644 index ca911d22d..000000000 --- a/internal/kclvm_py/encoding/protobuf/printer.py +++ /dev/null @@ -1,393 +0,0 @@ -# Copyright 2021 The KCL Authors. All rights reserved. - -import io -from typing import List -from dataclasses import dataclass - -import kclvm.kcl.ast as ast - -from .token import TokenValue -from .parser import ( - Import, - Package, - Option, - Field, - OneOfField, - OneOf, - Map, - Reserved, - Range, - EnumField, - Enum, - Message, - Service, - Rpc, - Proto, - ImportOption, - Type, - KeyType, -) - - -PROTO_NODE_TUPLE = ( - Import, - Package, - Option, - Field, - OneOfField, - OneOf, - Map, - Reserved, - Range, - EnumField, - Enum, - Message, - Service, - Rpc, - Proto, - ImportOption, - Type, - KeyType, -) - -_INVALID_NODE_MSG = "Invalid proto node" -WHITESPACE = " " -TAB = "\t" -NEWLINE = "\n" - - -# --------------------------------------------------- -# Printer config -# --------------------------------------------------- - - -@dataclass -class Config: - tab_len: int = 4 - indent_len: int = 4 - use_spaces: bool = True - - -class BasePrinter(ast.TreeWalker): - def __init__(self, config: Config, out: io.TextIOBase): - self.output: str = "" - self.config: Config = config - self.out: io.TextIOBase = out - self.indent: int = 0 - - # Base walker functions - - def get_node_name(self, t): - """Get the ast.AST node name""" - return type(t).__name__ - - def enter(self): - self.indent += 1 - - def leave(self): - self.indent -= 1 - - # --------------- - # Write functions - # --------------- - - @staticmethod - def interleave(inter, f, seq): - """Call f on each item in seq, calling inter() in between.""" - if not seq: - return - seq = iter(seq) - f(next(seq)) - for x in seq: - inter() - f(x) - - def write(self, text: str = ""): - self.out.write(text) - - def fill(self): - self.write( - (self.indent * self.config.indent_len * WHITESPACE) - if self.config.use_spaces - else (TAB * self.indent) - ) - - def print(self, *values): - for value in values or []: - if isinstance(value, PROTO_NODE_TUPLE): - self.walk(value) - elif value is True: - self.write("true") - elif value is False: - self.write("false") - else: - self.write(str(value)) - - -class Printer(BasePrinter): - def __init__(self, config: Config, out: io.TextIOBase): - super().__init__(config, out) - - def walk_Proto(self, t: Proto): - self.print( - TokenValue.SYNTAX, - WHITESPACE, - TokenValue.EQ, - WHITESPACE, - f'"{t.syntax}"', - TokenValue.SEMI, - NEWLINE, - ) - for node in t.statements or []: - self.walk(node) - - def walk_Import(self, t: Import): - self.print( - TokenValue.IMPORT, - WHITESPACE, - t.option.value, - WHITESPACE, - f'"{t.identifier}"', - TokenValue.SEMI, - NEWLINE, - ) - - def walk_Package(self, t: Package): - self.print( - TokenValue.PACKAGE, - WHITESPACE, - ) - self.interleave( - lambda: self.print(TokenValue.COMMA), lambda n: self.print(n), t.identifier - ) - self.print( - TokenValue.SEMI, - NEWLINE, - ) - - def walk_Option(self, t: Option): - self.fill() - self.print( - TokenValue.OPTION, - WHITESPACE, - t.name, - WHITESPACE, - TokenValue.EQ, - WHITESPACE, - f'"{t.value}"' if isinstance(t.value, str) else t.value, - TokenValue.SEMI, - NEWLINE, - ) - - def walk_Enum(self, t: Enum): - self.write(NEWLINE) - self.fill() - self.print( - TokenValue.ENUM, - WHITESPACE, - t.name, - WHITESPACE, - TokenValue.LBRACE, - NEWLINE, - ) - self.enter() - for node in t.body: - self.walk(node) - self.leave() - self.fill() - self.print(TokenValue.RBRACE) - self.write(NEWLINE) - - def walk_EnumField(self, t: EnumField): - self.fill() - self.print( - t.name, - WHITESPACE, - TokenValue.EQ, - WHITESPACE, - t.value, - ) - self.write_field_options(t.options) - self.write(TokenValue.SEMI) - self.write(NEWLINE) - - def walk_Message(self, t: Message): - self.write(NEWLINE) - self.fill() - self.print( - TokenValue.MESSAGE, - WHITESPACE, - t.name, - WHITESPACE, - TokenValue.LBRACE, - NEWLINE, - ) - self.enter() - for node in t.body: - self.walk(node) - self.leave() - self.fill() - self.print(TokenValue.RBRACE) - self.write(NEWLINE) - - def walk_Map(self, t: Map): - self.fill() - self.print( - TokenValue.MAP, - TokenValue.LANGLE_BRACK, - t.key_type, - TokenValue.COMMA, - WHITESPACE, - t.type, - TokenValue.RANGLE_BRACK, - WHITESPACE, - t.name, - WHITESPACE, - TokenValue.EQ, - WHITESPACE, - t.number, - ) - self.write_field_options(t.options) - self.write(TokenValue.SEMI) - self.write(NEWLINE) - - def walk_Field(self, t: Field): - self.fill() - if t.repeated: - self.print( - TokenValue.REPEATED, - WHITESPACE, - ) - self.print( - t.type, WHITESPACE, t.name, WHITESPACE, TokenValue.EQ, WHITESPACE, t.number - ) - self.write_field_options(t.options) - self.write(TokenValue.SEMI) - self.write(NEWLINE) - - def walk_OneOf(self, t: OneOf): - self.fill() - self.print( - TokenValue.ONEOF, - WHITESPACE, - t.name, - WHITESPACE, - TokenValue.LBRACE, - NEWLINE, - ) - self.enter() - for node in t.fields: - self.walk(node) - self.leave() - self.fill() - self.print(TokenValue.RBRACE) - self.write(NEWLINE) - - def walk_OneOfField(self, t: OneOfField): - self.fill() - self.print( - t.type, WHITESPACE, t.name, WHITESPACE, TokenValue.EQ, WHITESPACE, t.number - ) - self.write_field_options(t.options) - self.write(TokenValue.SEMI) - self.write(NEWLINE) - - def walk_Service(self, t: Service): - self.write(NEWLINE) - self.fill() - self.print( - TokenValue.SERVICE, - WHITESPACE, - t.name, - WHITESPACE, - TokenValue.LBRACE, - NEWLINE, - ) - self.enter() - for node in t.body: - self.walk(node) - self.leave() - self.fill() - self.print(TokenValue.RBRACE) - self.write(NEWLINE) - - def walk_Rpc(self, t: Rpc): - self.fill() - self.print( - TokenValue.RPC, - WHITESPACE, - t.name, - TokenValue.LPAREN, - t.request_message_type, - TokenValue.RPAREN, - WHITESPACE, - TokenValue.RETURNS, - WHITESPACE, - TokenValue.LPAREN, - t.response_message_type, - TokenValue.RPAREN, - ) - self.write_field_options(t.options) - self.write(TokenValue.SEMI) - self.write(NEWLINE) - - def walk_Reserved(self, t: Reserved): - self.fill() - self.print( - TokenValue().RESERVED, - WHITESPACE, - ) - self.interleave( - lambda: self.write(TokenValue.COMMA + WHITESPACE), - lambda n: self.print(f'"{n}"' if isinstance(n, str) else n), - t.items, - ) - self.write(TokenValue.SEMI) - self.write(NEWLINE) - - def walk_Range(self, t: Range): - self.print(f'"{t.from_}"' if isinstance(t.from_, str) else t.from_) - if t.to: - self.print( - WHITESPACE, - TokenValue.TO, - WHITESPACE, - f'"{t.to}"' if isinstance(t.to, str) else t.to, - ) - - def walk_Type(self, t: Type): - self.print(t.value) - - def walk_KeyType(self, t: KeyType): - self.print(t.value) - - def write_field_options(self, options: List[Option]): - def write_option(option: Option): - self.print( - TokenValue.LPAREN, - option.name, - TokenValue.RPAREN, - WHITESPACE, - TokenValue.EQ, - WHITESPACE, - f'"{option.value}"' if isinstance(option.value, str) else option.value, - ) - - if not options: - return - self.write(WHITESPACE) - self.write(TokenValue.LBRACK) - self.interleave( - lambda: self.write(TokenValue.COMMA + WHITESPACE), write_option, options - ) - self.write(TokenValue.RBRACK) - - -def print_node_to_string( - node, - config: Config = Config(), -) -> str: - """Print a proto node to string io with `config`""" - out = io.StringIO() - Printer(config, out).walk(node) - return out.getvalue() diff --git a/internal/kclvm_py/encoding/protobuf/protobuf.py b/internal/kclvm_py/encoding/protobuf/protobuf.py deleted file mode 100644 index fe48fb303..000000000 --- a/internal/kclvm_py/encoding/protobuf/protobuf.py +++ /dev/null @@ -1,249 +0,0 @@ -# Copyright 2021 The KCL Authors. All rights reserved. - -from typing import cast, List, Union -from io import StringIO - -import kclvm.kcl.ast as ast -import kclvm.kcl.types as types -import kclvm.api.object as objpkg -import kclvm.tools.printer as printer -import kclvm.compiler.parser.parser as parser - -from .parser import ( - parse_code, - Proto, - Message, - Field, - Map, - Enum, - EnumField, - Type, - KeyType, - OneOf, - OneOfField, -) -from .types import ( - PROTOBUF_SCALAR_TYPE_TO_KCL_MAPPING, - KCL_SCALAR_TYPE_TO_PROTOBUF_TYPE_MAPPING, - KCL_SCALAR_TYPE_TO_PROTOBUF_KEY_TYPE_MAPPING, -) -from .printer import print_node_to_string - - -CODE_INPUT = "" -PROTO3_SYNTAX = "proto3" - - -def protobuf_to_kcl(proto_code: str) -> str: - """Covert a protobuf code string to a KCL code string. - - Parameters - ---------- - proto_code : str. The protobuf code string. - - Returns - ------- - kcl_code : str. The KCL code string. - """ - kcl_module = protobuf_to_kcl_ast(proto_code) - buf = StringIO() - printer.PrintAST(kcl_module, buf) - return buf.getvalue() - - -def kcl_to_protobuf(kcl_code: str) -> str: - """Covert a a KCL code string to a protobuf code string. - - Parameters - ---------- - kcl_code : str. The KCL code string. - - Returns - ------- - proto_code : str. The protobuf code string. - """ - ast_program = parser.LoadProgram(CODE_INPUT, k_code_list=[kcl_code]) - types.ResolveProgram(ast_program) - main_ast = ast_program.pkgs[ast.Program.MAIN_PKGPATH][0] - proto = Proto( - syntax=PROTO3_SYNTAX, - statements=[ - convert_schema_to_message(schema) for schema in main_ast.GetSchemaList() - ], - ) - return print_node_to_string(proto) - - -def protobuf_to_kcl_ast(proto_code: str) -> ast.Module: - """Covert a protobuf code string to a KCL code string. - - Parameters - ---------- - proto_code : str. The protobuf code string. - - Returns - ------- - kcl_ast : ast.Module. The KCL Module AST node. - """ - proto = parse_code(proto_code) - kcl_module = ast.Module(line=1, column=1) - for statement in proto.statements: - if isinstance(statement, Message): - message = cast(Message, statement) - kcl_module.body.extend(convert_message_to_schema_list(message)) - elif isinstance(statement, Enum): - enum = cast(Enum, statement) - kcl_module.body.append(convert_enum_to_type_alias(enum)) - # TODO: Import node on multi proto files - return kcl_module - - -def convert_proto_type_to_kcl_type(tpe: Union[Type, str]) -> str: - """Convert a proto type to a KCL type""" - return ( - PROTOBUF_SCALAR_TYPE_TO_KCL_MAPPING.get(tpe.value) - if isinstance(tpe, (Type, KeyType)) - else (tpe or "any") - ) - - -def convert_kcl_type_to_proto_type( - tpe: types.Type, is_proto_key_type: bool = False -) -> Union[str, KeyType, Type]: - """Convert a kcl type to a proto type""" - if isinstance(tpe, objpkg.KCLNamedTypeObject): - return tpe.name - elif isinstance( - tpe, - ( - objpkg.KCLIntTypeObject, - objpkg.KCLFloatTypeObject, - objpkg.KCLStringTypeObject, - objpkg.KCLBoolTypeObject, - ), - ): - return ( - KCL_SCALAR_TYPE_TO_PROTOBUF_KEY_TYPE_MAPPING.get(tpe.type_str()) - if is_proto_key_type - else KCL_SCALAR_TYPE_TO_PROTOBUF_TYPE_MAPPING.get(tpe.type_str()) - ) - raise ValueError(f"Unsupported KCL type {tpe} to proto type") - - -def convert_message_to_schema_list(message: Message) -> List[ast.Stmt]: - """Convert proto Message to KCL schema list because a - proto Message can be nested definition. - """ - if not message or not isinstance(message, Message): - raise ValueError(f"Invalid parameter message {message}, expected Message") - schema = ast.SchemaStmt() - # Mapping the message name to the schema name - schema.name = message.name - results = [] - results.append(schema) - for node in message.body: - schema_attr = ast.SchemaAttr() - if isinstance(node, Field): - field = cast(Field, node) - schema_attr.name = field.name - kcl_type_str = convert_proto_type_to_kcl_type(field.type) - schema_attr.type_str = ( - f"[{kcl_type_str}]" if field.repeated else kcl_type_str - ) - schema.body.append(schema_attr) - elif isinstance(node, Map): - field = cast(Map, node) - schema_attr.name = field.name - kcl_key_type_str = convert_proto_type_to_kcl_type(field.key_type) - kcl_value_type_str = convert_proto_type_to_kcl_type(field.type) - schema_attr.type_str = ( - "{" + kcl_key_type_str + ":" + kcl_value_type_str + "}" - ) - schema.body.append(schema_attr) - elif isinstance(node, OneOf): - field = cast(OneOf, node) - schema_attr.name = field.name - # OneOfField - schema_attr.type_str = " | ".join( - [convert_proto_type_to_kcl_type(field.type) for field in field.fields] - ) - schema.body.append(schema_attr) - elif isinstance(node, Message): - results.extend(convert_message_to_schema_list(node)) - return results - - -def convert_enum_to_type_alias(enum: Enum) -> ast.TypeAliasStmt: - """Convert a proto Enum to a KCL TypeAliasStmt""" - if not enum or not isinstance(enum, Enum): - raise ValueError(f"Invalid parameter Enum {enum}, expected Enum") - type_alias = ast.TypeAliasStmt() - type_alias.type_name = ast.ASTFactory.get_ast_identifier(enum.name) - values = [str(node.value) for node in enum.body if isinstance(node, EnumField)] - type_alias.type_value = ast.Type() - type_alias.type_value.plain_type_str = " | ".join(values) - return type_alias - - -def convert_schema_to_message(schema: ast.SchemaStmt) -> Message: - """Convert KCL schema to a proto Message""" - if not schema or not isinstance(schema, ast.SchemaStmt): - raise ValueError(f"Invalid parameter schema {schema}, expected ast.SchemaStmt") - return Message( - name=schema.name, - body=[ - convert_schema_attr_to_message_body(schema_attr, i + 1) - for i, schema_attr in enumerate(schema.body) - if isinstance(schema_attr, ast.SchemaAttr) - ], - ) - - -def convert_schema_attr_to_message_body( - schema_attr: ast.SchemaAttr, - number: int = 1, -) -> Union[Field, Map, OneOf]: - """Convert KCL schema attr to a proto Message body item""" - if not schema_attr or not isinstance(schema_attr, ast.SchemaAttr): - raise ValueError( - f"Invalid parameter schema {schema_attr}, expected ast.SchemaAttr" - ) - type_node = types.parse_type_str(schema_attr.type_str) - if isinstance(type_node, objpkg.KCLDictTypeObject): - field = Map( - name=schema_attr.name, - key_type=convert_kcl_type_to_proto_type(type_node.key_type, True), - type=convert_kcl_type_to_proto_type(type_node.value_type), - number=number, - options=[], - ) - elif isinstance(type_node, objpkg.KCLUnionTypeObject): - # Convert union type to one of - field = OneOf( - name=schema_attr.name, - fields=[], - ) - filed_name_prefix = schema_attr.name - for i, tpe in enumerate(type_node.types): - field.fields.append( - OneOfField( - name=filed_name_prefix + f"{i + 1}", - number=i + 1, - type=types.type_to_kcl_type_annotation_str(tpe), - options=[], - ) - ) - else: - field = Field( - name=schema_attr.name, - type="", - repeated=False, - options=[], - number=number, - ) - if isinstance(type_node, objpkg.KCLListTypeObject): - field.repeated = True - field.type = convert_kcl_type_to_proto_type(type_node.item_type) - else: - field.type = convert_kcl_type_to_proto_type(type_node) - return field diff --git a/internal/kclvm_py/encoding/protobuf/token.py b/internal/kclvm_py/encoding/protobuf/token.py deleted file mode 100644 index 5bcdb61a5..000000000 --- a/internal/kclvm_py/encoding/protobuf/token.py +++ /dev/null @@ -1,29 +0,0 @@ -# Copyright 2021 The KCL Authors. All rights reserved. - - -class TokenValue: - SEMI = ";" - COMMA = "," - EQ = "=" - LPAREN = "(" - RPAREN = ")" - LBRACK = "[" - RBRACK = "]" - LBRACE = "{" - RBRACE = "}" - LANGLE_BRACK = "<" - RANGLE_BRACK = ">" - SYNTAX = "syntax" - IMPORT = "import" - MESSAGE = "message" - ENUM = "enum" - PACKAGE = "package" - OPTION = "option" - ONEOF = "oneof" - MAP = "map" - REPEATED = "repeated" - SERVICE = "service" - RPC = "rpc" - RETURNS = "returns" - TO = "to" - RESERVED = "reserved" diff --git a/internal/kclvm_py/encoding/protobuf/types.py b/internal/kclvm_py/encoding/protobuf/types.py deleted file mode 100644 index 9c4b2579d..000000000 --- a/internal/kclvm_py/encoding/protobuf/types.py +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2021 The KCL Authors. All rights reserved. - -from typing import Dict - -from .parser import Type, KeyType - -PROTOBUF_SCALAR_TYPE_TO_KCL_MAPPING: Dict[str, str] = { - "int32": "int", - "int64": "int", - "uint32": "int", - "uint64": "int", - "double": "float", - "float": "float", - "fixed32": "int", - "fixed64": "int", - "sfixed32": "int", - "sfixed64": "int", - "bool": "bool", - "string": "str", - "bytes": "str", -} - -KCL_SCALAR_TYPE_TO_PROTOBUF_TYPE_MAPPING: Dict[str, Type] = { - "int": Type.INT64, - "float": Type.DOUBLE, - "bool": Type.BOOL, - "str": Type.STRING, -} - -KCL_SCALAR_TYPE_TO_PROTOBUF_KEY_TYPE_MAPPING: Dict[str, Type] = { - "int": KeyType.INT64, - "float": KeyType.INT64, - "bool": KeyType.BOOL, - "str": KeyType.STRING, -} diff --git a/internal/kclvm_py/internal/__init__.py b/internal/kclvm_py/internal/__init__.py deleted file mode 100644 index d74aaf8ad..000000000 --- a/internal/kclvm_py/internal/__init__.py +++ /dev/null @@ -1 +0,0 @@ -# Copyright 2021 The KCL Authors. All rights reserved. diff --git a/internal/kclvm_py/internal/gpyrpc/__init__.py b/internal/kclvm_py/internal/gpyrpc/__init__.py deleted file mode 100644 index d74aaf8ad..000000000 --- a/internal/kclvm_py/internal/gpyrpc/__init__.py +++ /dev/null @@ -1 +0,0 @@ -# Copyright 2021 The KCL Authors. All rights reserved. diff --git a/internal/kclvm_py/internal/gpyrpc/gpyrpc.py b/internal/kclvm_py/internal/gpyrpc/gpyrpc.py deleted file mode 100644 index 35ebcb146..000000000 --- a/internal/kclvm_py/internal/gpyrpc/gpyrpc.py +++ /dev/null @@ -1,132 +0,0 @@ -# Copyright 2021 The KCL Authors. All rights reserved. - -import json -import sys -import traceback - -from typing import List, Dict, Callable - -import google.protobuf.json_format as json_format - -import kclvm.kcl.error as kcl_error - -from .gpyrpc_pb2 import ( - Error, - Request, - Response, - ListMethod_Result, - Ping_Args, - Ping_Result, -) - -# https://developers.google.com/protocol-buffers/docs/reference/google.protobuf -# https://developers.google.com/protocol-buffers/docs/reference/python-generated -# https://github.com/protocolbuffers/protobuf/tree/master/src/google/protobuf - -_rpc_method_table: Dict[str, Callable[[Request], Response]] = {} - - -def _gpyrpcCallProxy(method: str, jsonpb_Request: str) -> str: - assert method - assert jsonpb_Request - - try: - fn = _rpc_method_table[method] - assert fn - - req = Request() - json_format.Parse(jsonpb_Request, req) - - resp = Response() - fn_result = fn(req) - resp.CopyFrom(fn_result) - - jsonpb_Response: str = json_format.MessageToJson( - resp, including_default_value_fields=True, preserving_proto_field_name=True - ) - return jsonpb_Response - - except kcl_error.KCLException as err: - errMessage = f"{err}" - resp = Response(err=Error(message=errMessage)) - return json_format.MessageToJson( - resp, including_default_value_fields=True, preserving_proto_field_name=True - ) - except OSError as err: - errMessage = f"OSError: {err}" - resp = Response(err=Error(message=errMessage)) - return json_format.MessageToJson( - resp, including_default_value_fields=True, preserving_proto_field_name=True - ) - except AssertionError as err: - ex_type, ex_val, ex_stack = sys.exc_info() - tb_info = traceback.extract_tb(ex_stack)[-1] - - filename = tb_info.filename - line = tb_info.lineno - - errMessage = f"AssertionError: {err}" - resp = Response(err=Error(message=errMessage, filename=filename, line=line)) - return json_format.MessageToJson( - resp, including_default_value_fields=True, preserving_proto_field_name=True - ) - except Exception as err: - errMessage = f"Exception: Internal Error! Please report a bug to us: method={method}, err={err}, stack trace={traceback.format_exc()}" - resp = Response(err=Error(message=errMessage)) - return json_format.MessageToJson( - resp, including_default_value_fields=True, preserving_proto_field_name=True - ) - - -def gpyrpcCallProxy(method: str, jsonRequest: str) -> str: - if not method: - errMessage = "method is empty" - resp = Response(err=Error(message=errMessage)) - return json_format.MessageToJson( - resp, including_default_value_fields=True, preserving_proto_field_name=True - ) - - if method not in _rpc_method_table: - errMessage = f"method '{method}' not found" - resp = Response(err=Error(message=errMessage)) - return json_format.MessageToJson( - resp, including_default_value_fields=True, preserving_proto_field_name=True - ) - resp: Response = {"error": f"method '{method}' not found"} - return str(json.dumps(resp)) - - return _gpyrpcCallProxy(method, jsonRequest) - - -def RegisterMethod(method: str, fn: Callable[[Request], Response]): - assert method - assert fn - - assert method not in _rpc_method_table - _rpc_method_table[method] = fn - - -# args: gpyrpc.Ping_Args -# result: gpyrpc.Ping_Result -def _gpyrpcPing(req: Request) -> Response: - args = Ping_Args() - req.args.Unpack(args) - - resp = Response() - resp.result.Pack(Ping_Result(value=args.value)) - return resp - - -# args: gpyrpc.ListMethod_Args -# result: gpyrpc.ListMethod_Result -def _gpyrpcListMethod(req: Request) -> Response: - keys: List[str] = list(sorted(_rpc_method_table)) - - resp = Response() - resp.result.Pack(ListMethod_Result(method_name_list=keys)) - - return resp - - -RegisterMethod("gpyrpc.BuiltinService.Ping", _gpyrpcPing) -RegisterMethod("gpyrpc.BuiltinService.ListMethod", _gpyrpcListMethod) diff --git a/internal/kclvm_py/internal/gpyrpc/gpyrpc_pb2.py b/internal/kclvm_py/internal/gpyrpc/gpyrpc_pb2.py deleted file mode 100644 index 1e9ec3278..000000000 --- a/internal/kclvm_py/internal/gpyrpc/gpyrpc_pb2.py +++ /dev/null @@ -1,609 +0,0 @@ -# -*- coding: utf-8 -*- -# Generated by the protocol buffer compiler. DO NOT EDIT! -# source: gpyrpc/gpyrpc.proto -"""Generated protocol buffer code.""" -from google.protobuf import descriptor as _descriptor -from google.protobuf import descriptor_pool as _descriptor_pool -from google.protobuf import message as _message -from google.protobuf import reflection as _reflection -from google.protobuf import symbol_database as _symbol_database -# @@protoc_insertion_point(imports) - -_sym_db = _symbol_database.Default() - - -from google.protobuf import any_pb2 as google_dot_protobuf_dot_any__pb2 -from google.protobuf import descriptor_pb2 as google_dot_protobuf_dot_descriptor__pb2 - - -DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x13gpyrpc/gpyrpc.proto\x12\x06gpyrpc\x1a\x19google/protobuf/any.proto\x1a google/protobuf/descriptor.proto\")\n\nCmdArgSpec\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t\"[\n\x0f\x43mdOverrideSpec\x12\x0f\n\x07pkgpath\x18\x01 \x01(\t\x12\x12\n\nfield_path\x18\x02 \x01(\t\x12\x13\n\x0b\x66ield_value\x18\x03 \x01(\t\x12\x0e\n\x06\x61\x63tion\x18\x04 \x01(\t\"f\n\x0cRestResponse\x12$\n\x06result\x18\x01 \x01(\x0b\x32\x14.google.protobuf.Any\x12\r\n\x05\x65rror\x18\x02 \x01(\t\x12!\n\x07kcl_err\x18\x03 \x01(\x0b\x32\x10.gpyrpc.KclError\"`\n\x08KclError\x12\x0e\n\x06\x65wcode\x18\x01 \x01(\t\x12\x0c\n\x04name\x18\x02 \x01(\t\x12\x0b\n\x03msg\x18\x03 \x01(\t\x12)\n\x0b\x65rror_infos\x18\x04 \x03(\x0b\x32\x14.gpyrpc.KclErrorInfo\"w\n\x0cKclErrorInfo\x12\x11\n\terr_level\x18\x01 \x01(\t\x12\x0f\n\x07\x61rg_msg\x18\x02 \x01(\t\x12\x10\n\x08\x66ilename\x18\x03 \x01(\t\x12\x10\n\x08src_code\x18\x04 \x01(\t\x12\x0f\n\x07line_no\x18\x05 \x01(\t\x12\x0e\n\x06\x63ol_no\x18\x06 \x01(\t\"\x1a\n\tPing_Args\x12\r\n\x05value\x18\x01 \x01(\t\"\x1c\n\x0bPing_Result\x12\r\n\x05value\x18\x01 \x01(\t\"\x11\n\x0fListMethod_Args\"-\n\x11ListMethod_Result\x12\x18\n\x10method_name_list\x18\x01 \x03(\t\"Z\n\x17ParseFile_LarkTree_Args\x12\x10\n\x08\x66ilename\x18\x01 \x01(\t\x12\x13\n\x0bsource_code\x18\x02 \x01(\t\x12\x18\n\x10ignore_file_line\x18\x03 \x01(\x08\"3\n\x19ParseFile_LarkTree_Result\x12\x16\n\x0elark_tree_json\x18\x01 \x01(\t\";\n\x12ParseFile_AST_Args\x12\x10\n\x08\x66ilename\x18\x01 \x01(\t\x12\x13\n\x0bsource_code\x18\x02 \x01(\t\"(\n\x14ParseFile_AST_Result\x12\x10\n\x08\x61st_json\x18\x01 \x01(\t\"0\n\x15ParseProgram_AST_Args\x12\x17\n\x0fk_filename_list\x18\x01 \x03(\t\"+\n\x17ParseProgram_AST_Result\x12\x10\n\x08\x61st_json\x18\x01 \x01(\t\"\xe0\x02\n\x10\x45xecProgram_Args\x12\x10\n\x08work_dir\x18\x01 \x01(\t\x12\x17\n\x0fk_filename_list\x18\x02 \x03(\t\x12\x13\n\x0bk_code_list\x18\x03 \x03(\t\x12 \n\x04\x61rgs\x18\x04 \x03(\x0b\x32\x12.gpyrpc.CmdArgSpec\x12*\n\toverrides\x18\x05 \x03(\x0b\x32\x17.gpyrpc.CmdOverrideSpec\x12\x1b\n\x13\x64isable_yaml_result\x18\x06 \x01(\x08\x12\x1a\n\x12print_override_ast\x18\x07 \x01(\x08\x12\x1a\n\x12strict_range_check\x18\x08 \x01(\x08\x12\x14\n\x0c\x64isable_none\x18\t \x01(\x08\x12\x0f\n\x07verbose\x18\n \x01(\x05\x12\r\n\x05\x64\x65\x62ug\x18\x0b \x01(\x05\x12\x11\n\tsort_keys\x18\x0c \x01(\x08\x12 \n\x18include_schema_type_path\x18\r \x01(\x08\"T\n\x12\x45xecProgram_Result\x12\x13\n\x0bjson_result\x18\x01 \x01(\t\x12\x13\n\x0byaml_result\x18\x02 \x01(\t\x12\x14\n\x0c\x65scaped_time\x18\x65 \x01(\t\"\'\n\x10ResetPlugin_Args\x12\x13\n\x0bplugin_root\x18\x01 \x01(\t\"\x14\n\x12ResetPlugin_Result\"!\n\x0f\x46ormatCode_Args\x12\x0e\n\x06source\x18\x01 \x01(\t\"&\n\x11\x46ormatCode_Result\x12\x11\n\tformatted\x18\x01 \x01(\x0c\"\x1f\n\x0f\x46ormatPath_Args\x12\x0c\n\x04path\x18\x01 \x01(\t\")\n\x11\x46ormatPath_Result\x12\x14\n\x0c\x63hangedPaths\x18\x01 \x03(\t\"\x1d\n\rLintPath_Args\x12\x0c\n\x04path\x18\x01 \x01(\t\"\"\n\x0fLintPath_Result\x12\x0f\n\x07results\x18\x01 \x03(\t\"F\n\x11OverrideFile_Args\x12\x0c\n\x04\x66ile\x18\x01 \x01(\t\x12\r\n\x05specs\x18\x02 \x03(\t\x12\x14\n\x0cimport_paths\x18\x03 \x03(\t\"%\n\x13OverrideFile_Result\x12\x0e\n\x06result\x18\x01 \x01(\x08\"\x1d\n\rEvalCode_Args\x12\x0c\n\x04\x63ode\x18\x01 \x01(\t\"&\n\x0f\x45valCode_Result\x12\x13\n\x0bjson_result\x18\x02 \x01(\t\" \n\x10ResolveCode_Args\x12\x0c\n\x04\x63ode\x18\x01 \x01(\t\"%\n\x12ResolveCode_Result\x12\x0f\n\x07success\x18\x01 \x01(\x08\"E\n\x12GetSchemaType_Args\x12\x0c\n\x04\x66ile\x18\x01 \x01(\t\x12\x0c\n\x04\x63ode\x18\x02 \x01(\t\x12\x13\n\x0bschema_name\x18\x03 \x01(\t\"A\n\x14GetSchemaType_Result\x12)\n\x10schema_type_list\x18\x01 \x03(\x0b\x32\x0f.gpyrpc.KclType\"g\n\x11ValidateCode_Args\x12\x0c\n\x04\x64\x61ta\x18\x01 \x01(\t\x12\x0c\n\x04\x63ode\x18\x02 \x01(\t\x12\x0e\n\x06schema\x18\x03 \x01(\t\x12\x16\n\x0e\x61ttribute_name\x18\x04 \x01(\t\x12\x0e\n\x06\x66ormat\x18\x05 \x01(\t\";\n\x13ValidateCode_Result\x12\x0f\n\x07success\x18\x01 \x01(\x08\x12\x13\n\x0b\x65rr_message\x18\x02 \x01(\t\"+\n\x0b\x43odeSnippet\x12\x0e\n\x06schema\x18\x01 \x01(\t\x12\x0c\n\x04rule\x18\x02 \x01(\t\"<\n\x0fSpliceCode_Args\x12)\n\x0c\x63odeSnippets\x18\x01 \x03(\x0b\x32\x13.gpyrpc.CodeSnippet\"\'\n\x11SpliceCode_Result\x12\x12\n\nspliceCode\x18\x01 \x01(\t\":\n\x08Position\x12\x0c\n\x04line\x18\x01 \x01(\x03\x12\x0e\n\x06\x63olumn\x18\x02 \x01(\x03\x12\x10\n\x08\x66ilename\x18\x03 \x01(\t\"J\n\rComplete_Args\x12\x1d\n\x03pos\x18\x01 \x01(\x0b\x32\x10.gpyrpc.Position\x12\x0c\n\x04name\x18\x02 \x01(\t\x12\x0c\n\x04\x63ode\x18\x03 \x01(\t\"(\n\x0f\x43omplete_Result\x12\x15\n\rcompleteItems\x18\x01 \x01(\t\";\n\x0cGoToDef_Args\x12\x1d\n\x03pos\x18\x01 \x01(\x0b\x32\x10.gpyrpc.Position\x12\x0c\n\x04\x63ode\x18\x02 \x01(\t\"#\n\x0eGoToDef_Result\x12\x11\n\tlocations\x18\x01 \x01(\t\"1\n\x13\x44ocumentSymbol_Args\x12\x0c\n\x04\x66ile\x18\x01 \x01(\t\x12\x0c\n\x04\x63ode\x18\x02 \x01(\t\"\'\n\x15\x44ocumentSymbol_Result\x12\x0e\n\x06symbol\x18\x01 \x01(\t\"9\n\nHover_Args\x12\x1d\n\x03pos\x18\x01 \x01(\x0b\x32\x10.gpyrpc.Position\x12\x0c\n\x04\x63ode\x18\x02 \x01(\t\"#\n\x0cHover_Result\x12\x13\n\x0bhoverResult\x18\x01 \x01(\t\"i\n\x11ListDepFiles_Args\x12\x10\n\x08work_dir\x18\x01 \x01(\t\x12\x14\n\x0cuse_abs_path\x18\x02 \x01(\x08\x12\x13\n\x0binclude_all\x18\x03 \x01(\x08\x12\x17\n\x0fuse_fast_parser\x18\x04 \x01(\x08\"F\n\x13ListDepFiles_Result\x12\x0f\n\x07pkgroot\x18\x01 \x01(\t\x12\x0f\n\x07pkgpath\x18\x02 \x01(\t\x12\r\n\x05\x66iles\x18\x03 \x03(\t\"9\n\x16LoadSettingsFiles_Args\x12\x10\n\x08work_dir\x18\x01 \x01(\t\x12\r\n\x05\x66iles\x18\x02 \x03(\t\"q\n\x18LoadSettingsFiles_Result\x12*\n\x0fkcl_cli_configs\x18\x01 \x01(\x0b\x32\x11.gpyrpc.CliConfig\x12)\n\x0bkcl_options\x18\x02 \x03(\x0b\x32\x14.gpyrpc.KeyValuePair\"\xa6\x01\n\tCliConfig\x12\r\n\x05\x66iles\x18\x01 \x03(\t\x12\x0e\n\x06output\x18\x02 \x01(\t\x12\x11\n\toverrides\x18\x03 \x03(\t\x12\x15\n\rpath_selector\x18\x04 \x03(\t\x12\x1a\n\x12strict_range_check\x18\x05 \x01(\x08\x12\x14\n\x0c\x64isable_none\x18\x06 \x01(\x08\x12\x0f\n\x07verbose\x18\x07 \x01(\x03\x12\r\n\x05\x64\x65\x62ug\x18\x08 \x01(\x08\"*\n\x0cKeyValuePair\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t\"\xf4\x02\n\x07KclType\x12\x0c\n\x04type\x18\x01 \x01(\t\x12$\n\x0bunion_types\x18\x02 \x03(\x0b\x32\x0f.gpyrpc.KclType\x12\x0f\n\x07\x64\x65\x66\x61ult\x18\x03 \x01(\t\x12\x13\n\x0bschema_name\x18\x04 \x01(\t\x12\x12\n\nschema_doc\x18\x05 \x01(\t\x12\x33\n\nproperties\x18\x06 \x03(\x0b\x32\x1f.gpyrpc.KclType.PropertiesEntry\x12\x10\n\x08required\x18\x07 \x03(\t\x12\x1c\n\x03key\x18\x08 \x01(\x0b\x32\x0f.gpyrpc.KclType\x12\x1d\n\x04item\x18\t \x01(\x0b\x32\x0f.gpyrpc.KclType\x12\x0c\n\x04line\x18\n \x01(\x05\x12%\n\ndecorators\x18\x0b \x03(\x0b\x32\x11.gpyrpc.Decorator\x1a\x42\n\x0fPropertiesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x1e\n\x05value\x18\x02 \x01(\x0b\x32\x0f.gpyrpc.KclType:\x02\x38\x01\"\x90\x01\n\tDecorator\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x11\n\targuments\x18\x02 \x03(\t\x12\x31\n\x08keywords\x18\x03 \x03(\x0b\x32\x1f.gpyrpc.Decorator.KeywordsEntry\x1a/\n\rKeywordsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\x32\x82\x01\n\x0e\x42uiltinService\x12.\n\x04Ping\x12\x11.gpyrpc.Ping_Args\x1a\x13.gpyrpc.Ping_Result\x12@\n\nListMethod\x12\x17.gpyrpc.ListMethod_Args\x1a\x19.gpyrpc.ListMethod_Result2\xb4\x0b\n\x0cKclvmService\x12.\n\x04Ping\x12\x11.gpyrpc.Ping_Args\x1a\x13.gpyrpc.Ping_Result\x12X\n\x12ParseFile_LarkTree\x12\x1f.gpyrpc.ParseFile_LarkTree_Args\x1a!.gpyrpc.ParseFile_LarkTree_Result\x12I\n\rParseFile_AST\x12\x1a.gpyrpc.ParseFile_AST_Args\x1a\x1c.gpyrpc.ParseFile_AST_Result\x12R\n\x10ParseProgram_AST\x12\x1d.gpyrpc.ParseProgram_AST_Args\x1a\x1f.gpyrpc.ParseProgram_AST_Result\x12\x43\n\x0b\x45xecProgram\x12\x18.gpyrpc.ExecProgram_Args\x1a\x1a.gpyrpc.ExecProgram_Result\x12\x43\n\x0bResetPlugin\x12\x18.gpyrpc.ResetPlugin_Args\x1a\x1a.gpyrpc.ResetPlugin_Result\x12@\n\nFormatCode\x12\x17.gpyrpc.FormatCode_Args\x1a\x19.gpyrpc.FormatCode_Result\x12@\n\nFormatPath\x12\x17.gpyrpc.FormatPath_Args\x1a\x19.gpyrpc.FormatPath_Result\x12:\n\x08LintPath\x12\x15.gpyrpc.LintPath_Args\x1a\x17.gpyrpc.LintPath_Result\x12\x46\n\x0cOverrideFile\x12\x19.gpyrpc.OverrideFile_Args\x1a\x1b.gpyrpc.OverrideFile_Result\x12:\n\x08\x45valCode\x12\x15.gpyrpc.EvalCode_Args\x1a\x17.gpyrpc.EvalCode_Result\x12\x43\n\x0bResolveCode\x12\x18.gpyrpc.ResolveCode_Args\x1a\x1a.gpyrpc.ResolveCode_Result\x12I\n\rGetSchemaType\x12\x1a.gpyrpc.GetSchemaType_Args\x1a\x1c.gpyrpc.GetSchemaType_Result\x12\x46\n\x0cValidateCode\x12\x19.gpyrpc.ValidateCode_Args\x1a\x1b.gpyrpc.ValidateCode_Result\x12@\n\nSpliceCode\x12\x17.gpyrpc.SpliceCode_Args\x1a\x19.gpyrpc.SpliceCode_Result\x12:\n\x08\x43omplete\x12\x15.gpyrpc.Complete_Args\x1a\x17.gpyrpc.Complete_Result\x12\x37\n\x07GoToDef\x12\x14.gpyrpc.GoToDef_Args\x1a\x16.gpyrpc.GoToDef_Result\x12L\n\x0e\x44ocumentSymbol\x12\x1b.gpyrpc.DocumentSymbol_Args\x1a\x1d.gpyrpc.DocumentSymbol_Result\x12\x31\n\x05Hover\x12\x12.gpyrpc.Hover_Args\x1a\x14.gpyrpc.Hover_Result\x12\x46\n\x0cListDepFiles\x12\x19.gpyrpc.ListDepFiles_Args\x1a\x1b.gpyrpc.ListDepFiles_Result\x12U\n\x11LoadSettingsFiles\x12\x1e.gpyrpc.LoadSettingsFiles_Args\x1a .gpyrpc.LoadSettingsFiles_ResultB0Z.kusionstack.io/kclvm-go/pkg/spec/gpyrpc;gpyrpcb\x06proto3') - - - -_CMDARGSPEC = DESCRIPTOR.message_types_by_name['CmdArgSpec'] -_CMDOVERRIDESPEC = DESCRIPTOR.message_types_by_name['CmdOverrideSpec'] -_RESTRESPONSE = DESCRIPTOR.message_types_by_name['RestResponse'] -_KCLERROR = DESCRIPTOR.message_types_by_name['KclError'] -_KCLERRORINFO = DESCRIPTOR.message_types_by_name['KclErrorInfo'] -_PING_ARGS = DESCRIPTOR.message_types_by_name['Ping_Args'] -_PING_RESULT = DESCRIPTOR.message_types_by_name['Ping_Result'] -_LISTMETHOD_ARGS = DESCRIPTOR.message_types_by_name['ListMethod_Args'] -_LISTMETHOD_RESULT = DESCRIPTOR.message_types_by_name['ListMethod_Result'] -_PARSEFILE_LARKTREE_ARGS = DESCRIPTOR.message_types_by_name['ParseFile_LarkTree_Args'] -_PARSEFILE_LARKTREE_RESULT = DESCRIPTOR.message_types_by_name['ParseFile_LarkTree_Result'] -_PARSEFILE_AST_ARGS = DESCRIPTOR.message_types_by_name['ParseFile_AST_Args'] -_PARSEFILE_AST_RESULT = DESCRIPTOR.message_types_by_name['ParseFile_AST_Result'] -_PARSEPROGRAM_AST_ARGS = DESCRIPTOR.message_types_by_name['ParseProgram_AST_Args'] -_PARSEPROGRAM_AST_RESULT = DESCRIPTOR.message_types_by_name['ParseProgram_AST_Result'] -_EXECPROGRAM_ARGS = DESCRIPTOR.message_types_by_name['ExecProgram_Args'] -_EXECPROGRAM_RESULT = DESCRIPTOR.message_types_by_name['ExecProgram_Result'] -_RESETPLUGIN_ARGS = DESCRIPTOR.message_types_by_name['ResetPlugin_Args'] -_RESETPLUGIN_RESULT = DESCRIPTOR.message_types_by_name['ResetPlugin_Result'] -_FORMATCODE_ARGS = DESCRIPTOR.message_types_by_name['FormatCode_Args'] -_FORMATCODE_RESULT = DESCRIPTOR.message_types_by_name['FormatCode_Result'] -_FORMATPATH_ARGS = DESCRIPTOR.message_types_by_name['FormatPath_Args'] -_FORMATPATH_RESULT = DESCRIPTOR.message_types_by_name['FormatPath_Result'] -_LINTPATH_ARGS = DESCRIPTOR.message_types_by_name['LintPath_Args'] -_LINTPATH_RESULT = DESCRIPTOR.message_types_by_name['LintPath_Result'] -_OVERRIDEFILE_ARGS = DESCRIPTOR.message_types_by_name['OverrideFile_Args'] -_OVERRIDEFILE_RESULT = DESCRIPTOR.message_types_by_name['OverrideFile_Result'] -_EVALCODE_ARGS = DESCRIPTOR.message_types_by_name['EvalCode_Args'] -_EVALCODE_RESULT = DESCRIPTOR.message_types_by_name['EvalCode_Result'] -_RESOLVECODE_ARGS = DESCRIPTOR.message_types_by_name['ResolveCode_Args'] -_RESOLVECODE_RESULT = DESCRIPTOR.message_types_by_name['ResolveCode_Result'] -_GETSCHEMATYPE_ARGS = DESCRIPTOR.message_types_by_name['GetSchemaType_Args'] -_GETSCHEMATYPE_RESULT = DESCRIPTOR.message_types_by_name['GetSchemaType_Result'] -_VALIDATECODE_ARGS = DESCRIPTOR.message_types_by_name['ValidateCode_Args'] -_VALIDATECODE_RESULT = DESCRIPTOR.message_types_by_name['ValidateCode_Result'] -_CODESNIPPET = DESCRIPTOR.message_types_by_name['CodeSnippet'] -_SPLICECODE_ARGS = DESCRIPTOR.message_types_by_name['SpliceCode_Args'] -_SPLICECODE_RESULT = DESCRIPTOR.message_types_by_name['SpliceCode_Result'] -_POSITION = DESCRIPTOR.message_types_by_name['Position'] -_COMPLETE_ARGS = DESCRIPTOR.message_types_by_name['Complete_Args'] -_COMPLETE_RESULT = DESCRIPTOR.message_types_by_name['Complete_Result'] -_GOTODEF_ARGS = DESCRIPTOR.message_types_by_name['GoToDef_Args'] -_GOTODEF_RESULT = DESCRIPTOR.message_types_by_name['GoToDef_Result'] -_DOCUMENTSYMBOL_ARGS = DESCRIPTOR.message_types_by_name['DocumentSymbol_Args'] -_DOCUMENTSYMBOL_RESULT = DESCRIPTOR.message_types_by_name['DocumentSymbol_Result'] -_HOVER_ARGS = DESCRIPTOR.message_types_by_name['Hover_Args'] -_HOVER_RESULT = DESCRIPTOR.message_types_by_name['Hover_Result'] -_LISTDEPFILES_ARGS = DESCRIPTOR.message_types_by_name['ListDepFiles_Args'] -_LISTDEPFILES_RESULT = DESCRIPTOR.message_types_by_name['ListDepFiles_Result'] -_LOADSETTINGSFILES_ARGS = DESCRIPTOR.message_types_by_name['LoadSettingsFiles_Args'] -_LOADSETTINGSFILES_RESULT = DESCRIPTOR.message_types_by_name['LoadSettingsFiles_Result'] -_CLICONFIG = DESCRIPTOR.message_types_by_name['CliConfig'] -_KEYVALUEPAIR = DESCRIPTOR.message_types_by_name['KeyValuePair'] -_KCLTYPE = DESCRIPTOR.message_types_by_name['KclType'] -_KCLTYPE_PROPERTIESENTRY = _KCLTYPE.nested_types_by_name['PropertiesEntry'] -_DECORATOR = DESCRIPTOR.message_types_by_name['Decorator'] -_DECORATOR_KEYWORDSENTRY = _DECORATOR.nested_types_by_name['KeywordsEntry'] -CmdArgSpec = _reflection.GeneratedProtocolMessageType('CmdArgSpec', (_message.Message,), { - 'DESCRIPTOR' : _CMDARGSPEC, - '__module__' : 'gpyrpc.gpyrpc_pb2' - # @@protoc_insertion_point(class_scope:gpyrpc.CmdArgSpec) - }) -_sym_db.RegisterMessage(CmdArgSpec) - -CmdOverrideSpec = _reflection.GeneratedProtocolMessageType('CmdOverrideSpec', (_message.Message,), { - 'DESCRIPTOR' : _CMDOVERRIDESPEC, - '__module__' : 'gpyrpc.gpyrpc_pb2' - # @@protoc_insertion_point(class_scope:gpyrpc.CmdOverrideSpec) - }) -_sym_db.RegisterMessage(CmdOverrideSpec) - -RestResponse = _reflection.GeneratedProtocolMessageType('RestResponse', (_message.Message,), { - 'DESCRIPTOR' : _RESTRESPONSE, - '__module__' : 'gpyrpc.gpyrpc_pb2' - # @@protoc_insertion_point(class_scope:gpyrpc.RestResponse) - }) -_sym_db.RegisterMessage(RestResponse) - -KclError = _reflection.GeneratedProtocolMessageType('KclError', (_message.Message,), { - 'DESCRIPTOR' : _KCLERROR, - '__module__' : 'gpyrpc.gpyrpc_pb2' - # @@protoc_insertion_point(class_scope:gpyrpc.KclError) - }) -_sym_db.RegisterMessage(KclError) - -KclErrorInfo = _reflection.GeneratedProtocolMessageType('KclErrorInfo', (_message.Message,), { - 'DESCRIPTOR' : _KCLERRORINFO, - '__module__' : 'gpyrpc.gpyrpc_pb2' - # @@protoc_insertion_point(class_scope:gpyrpc.KclErrorInfo) - }) -_sym_db.RegisterMessage(KclErrorInfo) - -Ping_Args = _reflection.GeneratedProtocolMessageType('Ping_Args', (_message.Message,), { - 'DESCRIPTOR' : _PING_ARGS, - '__module__' : 'gpyrpc.gpyrpc_pb2' - # @@protoc_insertion_point(class_scope:gpyrpc.Ping_Args) - }) -_sym_db.RegisterMessage(Ping_Args) - -Ping_Result = _reflection.GeneratedProtocolMessageType('Ping_Result', (_message.Message,), { - 'DESCRIPTOR' : _PING_RESULT, - '__module__' : 'gpyrpc.gpyrpc_pb2' - # @@protoc_insertion_point(class_scope:gpyrpc.Ping_Result) - }) -_sym_db.RegisterMessage(Ping_Result) - -ListMethod_Args = _reflection.GeneratedProtocolMessageType('ListMethod_Args', (_message.Message,), { - 'DESCRIPTOR' : _LISTMETHOD_ARGS, - '__module__' : 'gpyrpc.gpyrpc_pb2' - # @@protoc_insertion_point(class_scope:gpyrpc.ListMethod_Args) - }) -_sym_db.RegisterMessage(ListMethod_Args) - -ListMethod_Result = _reflection.GeneratedProtocolMessageType('ListMethod_Result', (_message.Message,), { - 'DESCRIPTOR' : _LISTMETHOD_RESULT, - '__module__' : 'gpyrpc.gpyrpc_pb2' - # @@protoc_insertion_point(class_scope:gpyrpc.ListMethod_Result) - }) -_sym_db.RegisterMessage(ListMethod_Result) - -ParseFile_LarkTree_Args = _reflection.GeneratedProtocolMessageType('ParseFile_LarkTree_Args', (_message.Message,), { - 'DESCRIPTOR' : _PARSEFILE_LARKTREE_ARGS, - '__module__' : 'gpyrpc.gpyrpc_pb2' - # @@protoc_insertion_point(class_scope:gpyrpc.ParseFile_LarkTree_Args) - }) -_sym_db.RegisterMessage(ParseFile_LarkTree_Args) - -ParseFile_LarkTree_Result = _reflection.GeneratedProtocolMessageType('ParseFile_LarkTree_Result', (_message.Message,), { - 'DESCRIPTOR' : _PARSEFILE_LARKTREE_RESULT, - '__module__' : 'gpyrpc.gpyrpc_pb2' - # @@protoc_insertion_point(class_scope:gpyrpc.ParseFile_LarkTree_Result) - }) -_sym_db.RegisterMessage(ParseFile_LarkTree_Result) - -ParseFile_AST_Args = _reflection.GeneratedProtocolMessageType('ParseFile_AST_Args', (_message.Message,), { - 'DESCRIPTOR' : _PARSEFILE_AST_ARGS, - '__module__' : 'gpyrpc.gpyrpc_pb2' - # @@protoc_insertion_point(class_scope:gpyrpc.ParseFile_AST_Args) - }) -_sym_db.RegisterMessage(ParseFile_AST_Args) - -ParseFile_AST_Result = _reflection.GeneratedProtocolMessageType('ParseFile_AST_Result', (_message.Message,), { - 'DESCRIPTOR' : _PARSEFILE_AST_RESULT, - '__module__' : 'gpyrpc.gpyrpc_pb2' - # @@protoc_insertion_point(class_scope:gpyrpc.ParseFile_AST_Result) - }) -_sym_db.RegisterMessage(ParseFile_AST_Result) - -ParseProgram_AST_Args = _reflection.GeneratedProtocolMessageType('ParseProgram_AST_Args', (_message.Message,), { - 'DESCRIPTOR' : _PARSEPROGRAM_AST_ARGS, - '__module__' : 'gpyrpc.gpyrpc_pb2' - # @@protoc_insertion_point(class_scope:gpyrpc.ParseProgram_AST_Args) - }) -_sym_db.RegisterMessage(ParseProgram_AST_Args) - -ParseProgram_AST_Result = _reflection.GeneratedProtocolMessageType('ParseProgram_AST_Result', (_message.Message,), { - 'DESCRIPTOR' : _PARSEPROGRAM_AST_RESULT, - '__module__' : 'gpyrpc.gpyrpc_pb2' - # @@protoc_insertion_point(class_scope:gpyrpc.ParseProgram_AST_Result) - }) -_sym_db.RegisterMessage(ParseProgram_AST_Result) - -ExecProgram_Args = _reflection.GeneratedProtocolMessageType('ExecProgram_Args', (_message.Message,), { - 'DESCRIPTOR' : _EXECPROGRAM_ARGS, - '__module__' : 'gpyrpc.gpyrpc_pb2' - # @@protoc_insertion_point(class_scope:gpyrpc.ExecProgram_Args) - }) -_sym_db.RegisterMessage(ExecProgram_Args) - -ExecProgram_Result = _reflection.GeneratedProtocolMessageType('ExecProgram_Result', (_message.Message,), { - 'DESCRIPTOR' : _EXECPROGRAM_RESULT, - '__module__' : 'gpyrpc.gpyrpc_pb2' - # @@protoc_insertion_point(class_scope:gpyrpc.ExecProgram_Result) - }) -_sym_db.RegisterMessage(ExecProgram_Result) - -ResetPlugin_Args = _reflection.GeneratedProtocolMessageType('ResetPlugin_Args', (_message.Message,), { - 'DESCRIPTOR' : _RESETPLUGIN_ARGS, - '__module__' : 'gpyrpc.gpyrpc_pb2' - # @@protoc_insertion_point(class_scope:gpyrpc.ResetPlugin_Args) - }) -_sym_db.RegisterMessage(ResetPlugin_Args) - -ResetPlugin_Result = _reflection.GeneratedProtocolMessageType('ResetPlugin_Result', (_message.Message,), { - 'DESCRIPTOR' : _RESETPLUGIN_RESULT, - '__module__' : 'gpyrpc.gpyrpc_pb2' - # @@protoc_insertion_point(class_scope:gpyrpc.ResetPlugin_Result) - }) -_sym_db.RegisterMessage(ResetPlugin_Result) - -FormatCode_Args = _reflection.GeneratedProtocolMessageType('FormatCode_Args', (_message.Message,), { - 'DESCRIPTOR' : _FORMATCODE_ARGS, - '__module__' : 'gpyrpc.gpyrpc_pb2' - # @@protoc_insertion_point(class_scope:gpyrpc.FormatCode_Args) - }) -_sym_db.RegisterMessage(FormatCode_Args) - -FormatCode_Result = _reflection.GeneratedProtocolMessageType('FormatCode_Result', (_message.Message,), { - 'DESCRIPTOR' : _FORMATCODE_RESULT, - '__module__' : 'gpyrpc.gpyrpc_pb2' - # @@protoc_insertion_point(class_scope:gpyrpc.FormatCode_Result) - }) -_sym_db.RegisterMessage(FormatCode_Result) - -FormatPath_Args = _reflection.GeneratedProtocolMessageType('FormatPath_Args', (_message.Message,), { - 'DESCRIPTOR' : _FORMATPATH_ARGS, - '__module__' : 'gpyrpc.gpyrpc_pb2' - # @@protoc_insertion_point(class_scope:gpyrpc.FormatPath_Args) - }) -_sym_db.RegisterMessage(FormatPath_Args) - -FormatPath_Result = _reflection.GeneratedProtocolMessageType('FormatPath_Result', (_message.Message,), { - 'DESCRIPTOR' : _FORMATPATH_RESULT, - '__module__' : 'gpyrpc.gpyrpc_pb2' - # @@protoc_insertion_point(class_scope:gpyrpc.FormatPath_Result) - }) -_sym_db.RegisterMessage(FormatPath_Result) - -LintPath_Args = _reflection.GeneratedProtocolMessageType('LintPath_Args', (_message.Message,), { - 'DESCRIPTOR' : _LINTPATH_ARGS, - '__module__' : 'gpyrpc.gpyrpc_pb2' - # @@protoc_insertion_point(class_scope:gpyrpc.LintPath_Args) - }) -_sym_db.RegisterMessage(LintPath_Args) - -LintPath_Result = _reflection.GeneratedProtocolMessageType('LintPath_Result', (_message.Message,), { - 'DESCRIPTOR' : _LINTPATH_RESULT, - '__module__' : 'gpyrpc.gpyrpc_pb2' - # @@protoc_insertion_point(class_scope:gpyrpc.LintPath_Result) - }) -_sym_db.RegisterMessage(LintPath_Result) - -OverrideFile_Args = _reflection.GeneratedProtocolMessageType('OverrideFile_Args', (_message.Message,), { - 'DESCRIPTOR' : _OVERRIDEFILE_ARGS, - '__module__' : 'gpyrpc.gpyrpc_pb2' - # @@protoc_insertion_point(class_scope:gpyrpc.OverrideFile_Args) - }) -_sym_db.RegisterMessage(OverrideFile_Args) - -OverrideFile_Result = _reflection.GeneratedProtocolMessageType('OverrideFile_Result', (_message.Message,), { - 'DESCRIPTOR' : _OVERRIDEFILE_RESULT, - '__module__' : 'gpyrpc.gpyrpc_pb2' - # @@protoc_insertion_point(class_scope:gpyrpc.OverrideFile_Result) - }) -_sym_db.RegisterMessage(OverrideFile_Result) - -EvalCode_Args = _reflection.GeneratedProtocolMessageType('EvalCode_Args', (_message.Message,), { - 'DESCRIPTOR' : _EVALCODE_ARGS, - '__module__' : 'gpyrpc.gpyrpc_pb2' - # @@protoc_insertion_point(class_scope:gpyrpc.EvalCode_Args) - }) -_sym_db.RegisterMessage(EvalCode_Args) - -EvalCode_Result = _reflection.GeneratedProtocolMessageType('EvalCode_Result', (_message.Message,), { - 'DESCRIPTOR' : _EVALCODE_RESULT, - '__module__' : 'gpyrpc.gpyrpc_pb2' - # @@protoc_insertion_point(class_scope:gpyrpc.EvalCode_Result) - }) -_sym_db.RegisterMessage(EvalCode_Result) - -ResolveCode_Args = _reflection.GeneratedProtocolMessageType('ResolveCode_Args', (_message.Message,), { - 'DESCRIPTOR' : _RESOLVECODE_ARGS, - '__module__' : 'gpyrpc.gpyrpc_pb2' - # @@protoc_insertion_point(class_scope:gpyrpc.ResolveCode_Args) - }) -_sym_db.RegisterMessage(ResolveCode_Args) - -ResolveCode_Result = _reflection.GeneratedProtocolMessageType('ResolveCode_Result', (_message.Message,), { - 'DESCRIPTOR' : _RESOLVECODE_RESULT, - '__module__' : 'gpyrpc.gpyrpc_pb2' - # @@protoc_insertion_point(class_scope:gpyrpc.ResolveCode_Result) - }) -_sym_db.RegisterMessage(ResolveCode_Result) - -GetSchemaType_Args = _reflection.GeneratedProtocolMessageType('GetSchemaType_Args', (_message.Message,), { - 'DESCRIPTOR' : _GETSCHEMATYPE_ARGS, - '__module__' : 'gpyrpc.gpyrpc_pb2' - # @@protoc_insertion_point(class_scope:gpyrpc.GetSchemaType_Args) - }) -_sym_db.RegisterMessage(GetSchemaType_Args) - -GetSchemaType_Result = _reflection.GeneratedProtocolMessageType('GetSchemaType_Result', (_message.Message,), { - 'DESCRIPTOR' : _GETSCHEMATYPE_RESULT, - '__module__' : 'gpyrpc.gpyrpc_pb2' - # @@protoc_insertion_point(class_scope:gpyrpc.GetSchemaType_Result) - }) -_sym_db.RegisterMessage(GetSchemaType_Result) - -ValidateCode_Args = _reflection.GeneratedProtocolMessageType('ValidateCode_Args', (_message.Message,), { - 'DESCRIPTOR' : _VALIDATECODE_ARGS, - '__module__' : 'gpyrpc.gpyrpc_pb2' - # @@protoc_insertion_point(class_scope:gpyrpc.ValidateCode_Args) - }) -_sym_db.RegisterMessage(ValidateCode_Args) - -ValidateCode_Result = _reflection.GeneratedProtocolMessageType('ValidateCode_Result', (_message.Message,), { - 'DESCRIPTOR' : _VALIDATECODE_RESULT, - '__module__' : 'gpyrpc.gpyrpc_pb2' - # @@protoc_insertion_point(class_scope:gpyrpc.ValidateCode_Result) - }) -_sym_db.RegisterMessage(ValidateCode_Result) - -CodeSnippet = _reflection.GeneratedProtocolMessageType('CodeSnippet', (_message.Message,), { - 'DESCRIPTOR' : _CODESNIPPET, - '__module__' : 'gpyrpc.gpyrpc_pb2' - # @@protoc_insertion_point(class_scope:gpyrpc.CodeSnippet) - }) -_sym_db.RegisterMessage(CodeSnippet) - -SpliceCode_Args = _reflection.GeneratedProtocolMessageType('SpliceCode_Args', (_message.Message,), { - 'DESCRIPTOR' : _SPLICECODE_ARGS, - '__module__' : 'gpyrpc.gpyrpc_pb2' - # @@protoc_insertion_point(class_scope:gpyrpc.SpliceCode_Args) - }) -_sym_db.RegisterMessage(SpliceCode_Args) - -SpliceCode_Result = _reflection.GeneratedProtocolMessageType('SpliceCode_Result', (_message.Message,), { - 'DESCRIPTOR' : _SPLICECODE_RESULT, - '__module__' : 'gpyrpc.gpyrpc_pb2' - # @@protoc_insertion_point(class_scope:gpyrpc.SpliceCode_Result) - }) -_sym_db.RegisterMessage(SpliceCode_Result) - -Position = _reflection.GeneratedProtocolMessageType('Position', (_message.Message,), { - 'DESCRIPTOR' : _POSITION, - '__module__' : 'gpyrpc.gpyrpc_pb2' - # @@protoc_insertion_point(class_scope:gpyrpc.Position) - }) -_sym_db.RegisterMessage(Position) - -Complete_Args = _reflection.GeneratedProtocolMessageType('Complete_Args', (_message.Message,), { - 'DESCRIPTOR' : _COMPLETE_ARGS, - '__module__' : 'gpyrpc.gpyrpc_pb2' - # @@protoc_insertion_point(class_scope:gpyrpc.Complete_Args) - }) -_sym_db.RegisterMessage(Complete_Args) - -Complete_Result = _reflection.GeneratedProtocolMessageType('Complete_Result', (_message.Message,), { - 'DESCRIPTOR' : _COMPLETE_RESULT, - '__module__' : 'gpyrpc.gpyrpc_pb2' - # @@protoc_insertion_point(class_scope:gpyrpc.Complete_Result) - }) -_sym_db.RegisterMessage(Complete_Result) - -GoToDef_Args = _reflection.GeneratedProtocolMessageType('GoToDef_Args', (_message.Message,), { - 'DESCRIPTOR' : _GOTODEF_ARGS, - '__module__' : 'gpyrpc.gpyrpc_pb2' - # @@protoc_insertion_point(class_scope:gpyrpc.GoToDef_Args) - }) -_sym_db.RegisterMessage(GoToDef_Args) - -GoToDef_Result = _reflection.GeneratedProtocolMessageType('GoToDef_Result', (_message.Message,), { - 'DESCRIPTOR' : _GOTODEF_RESULT, - '__module__' : 'gpyrpc.gpyrpc_pb2' - # @@protoc_insertion_point(class_scope:gpyrpc.GoToDef_Result) - }) -_sym_db.RegisterMessage(GoToDef_Result) - -DocumentSymbol_Args = _reflection.GeneratedProtocolMessageType('DocumentSymbol_Args', (_message.Message,), { - 'DESCRIPTOR' : _DOCUMENTSYMBOL_ARGS, - '__module__' : 'gpyrpc.gpyrpc_pb2' - # @@protoc_insertion_point(class_scope:gpyrpc.DocumentSymbol_Args) - }) -_sym_db.RegisterMessage(DocumentSymbol_Args) - -DocumentSymbol_Result = _reflection.GeneratedProtocolMessageType('DocumentSymbol_Result', (_message.Message,), { - 'DESCRIPTOR' : _DOCUMENTSYMBOL_RESULT, - '__module__' : 'gpyrpc.gpyrpc_pb2' - # @@protoc_insertion_point(class_scope:gpyrpc.DocumentSymbol_Result) - }) -_sym_db.RegisterMessage(DocumentSymbol_Result) - -Hover_Args = _reflection.GeneratedProtocolMessageType('Hover_Args', (_message.Message,), { - 'DESCRIPTOR' : _HOVER_ARGS, - '__module__' : 'gpyrpc.gpyrpc_pb2' - # @@protoc_insertion_point(class_scope:gpyrpc.Hover_Args) - }) -_sym_db.RegisterMessage(Hover_Args) - -Hover_Result = _reflection.GeneratedProtocolMessageType('Hover_Result', (_message.Message,), { - 'DESCRIPTOR' : _HOVER_RESULT, - '__module__' : 'gpyrpc.gpyrpc_pb2' - # @@protoc_insertion_point(class_scope:gpyrpc.Hover_Result) - }) -_sym_db.RegisterMessage(Hover_Result) - -ListDepFiles_Args = _reflection.GeneratedProtocolMessageType('ListDepFiles_Args', (_message.Message,), { - 'DESCRIPTOR' : _LISTDEPFILES_ARGS, - '__module__' : 'gpyrpc.gpyrpc_pb2' - # @@protoc_insertion_point(class_scope:gpyrpc.ListDepFiles_Args) - }) -_sym_db.RegisterMessage(ListDepFiles_Args) - -ListDepFiles_Result = _reflection.GeneratedProtocolMessageType('ListDepFiles_Result', (_message.Message,), { - 'DESCRIPTOR' : _LISTDEPFILES_RESULT, - '__module__' : 'gpyrpc.gpyrpc_pb2' - # @@protoc_insertion_point(class_scope:gpyrpc.ListDepFiles_Result) - }) -_sym_db.RegisterMessage(ListDepFiles_Result) - -LoadSettingsFiles_Args = _reflection.GeneratedProtocolMessageType('LoadSettingsFiles_Args', (_message.Message,), { - 'DESCRIPTOR' : _LOADSETTINGSFILES_ARGS, - '__module__' : 'gpyrpc.gpyrpc_pb2' - # @@protoc_insertion_point(class_scope:gpyrpc.LoadSettingsFiles_Args) - }) -_sym_db.RegisterMessage(LoadSettingsFiles_Args) - -LoadSettingsFiles_Result = _reflection.GeneratedProtocolMessageType('LoadSettingsFiles_Result', (_message.Message,), { - 'DESCRIPTOR' : _LOADSETTINGSFILES_RESULT, - '__module__' : 'gpyrpc.gpyrpc_pb2' - # @@protoc_insertion_point(class_scope:gpyrpc.LoadSettingsFiles_Result) - }) -_sym_db.RegisterMessage(LoadSettingsFiles_Result) - -CliConfig = _reflection.GeneratedProtocolMessageType('CliConfig', (_message.Message,), { - 'DESCRIPTOR' : _CLICONFIG, - '__module__' : 'gpyrpc.gpyrpc_pb2' - # @@protoc_insertion_point(class_scope:gpyrpc.CliConfig) - }) -_sym_db.RegisterMessage(CliConfig) - -KeyValuePair = _reflection.GeneratedProtocolMessageType('KeyValuePair', (_message.Message,), { - 'DESCRIPTOR' : _KEYVALUEPAIR, - '__module__' : 'gpyrpc.gpyrpc_pb2' - # @@protoc_insertion_point(class_scope:gpyrpc.KeyValuePair) - }) -_sym_db.RegisterMessage(KeyValuePair) - -KclType = _reflection.GeneratedProtocolMessageType('KclType', (_message.Message,), { - - 'PropertiesEntry' : _reflection.GeneratedProtocolMessageType('PropertiesEntry', (_message.Message,), { - 'DESCRIPTOR' : _KCLTYPE_PROPERTIESENTRY, - '__module__' : 'gpyrpc.gpyrpc_pb2' - # @@protoc_insertion_point(class_scope:gpyrpc.KclType.PropertiesEntry) - }) - , - 'DESCRIPTOR' : _KCLTYPE, - '__module__' : 'gpyrpc.gpyrpc_pb2' - # @@protoc_insertion_point(class_scope:gpyrpc.KclType) - }) -_sym_db.RegisterMessage(KclType) -_sym_db.RegisterMessage(KclType.PropertiesEntry) - -Decorator = _reflection.GeneratedProtocolMessageType('Decorator', (_message.Message,), { - - 'KeywordsEntry' : _reflection.GeneratedProtocolMessageType('KeywordsEntry', (_message.Message,), { - 'DESCRIPTOR' : _DECORATOR_KEYWORDSENTRY, - '__module__' : 'gpyrpc.gpyrpc_pb2' - # @@protoc_insertion_point(class_scope:gpyrpc.Decorator.KeywordsEntry) - }) - , - 'DESCRIPTOR' : _DECORATOR, - '__module__' : 'gpyrpc.gpyrpc_pb2' - # @@protoc_insertion_point(class_scope:gpyrpc.Decorator) - }) -_sym_db.RegisterMessage(Decorator) -_sym_db.RegisterMessage(Decorator.KeywordsEntry) - -_BUILTINSERVICE = DESCRIPTOR.services_by_name['BuiltinService'] -_KCLVMSERVICE = DESCRIPTOR.services_by_name['KclvmService'] -if _descriptor._USE_C_DESCRIPTORS == False: - - DESCRIPTOR._options = None - DESCRIPTOR._serialized_options = b'Z.kusionstack.io/kclvm-go/pkg/spec/gpyrpc;gpyrpc' - _KCLTYPE_PROPERTIESENTRY._options = None - _KCLTYPE_PROPERTIESENTRY._serialized_options = b'8\001' - _DECORATOR_KEYWORDSENTRY._options = None - _DECORATOR_KEYWORDSENTRY._serialized_options = b'8\001' - _CMDARGSPEC._serialized_start=92 - _CMDARGSPEC._serialized_end=133 - _CMDOVERRIDESPEC._serialized_start=135 - _CMDOVERRIDESPEC._serialized_end=226 - _RESTRESPONSE._serialized_start=228 - _RESTRESPONSE._serialized_end=330 - _KCLERROR._serialized_start=332 - _KCLERROR._serialized_end=428 - _KCLERRORINFO._serialized_start=430 - _KCLERRORINFO._serialized_end=549 - _PING_ARGS._serialized_start=551 - _PING_ARGS._serialized_end=577 - _PING_RESULT._serialized_start=579 - _PING_RESULT._serialized_end=607 - _LISTMETHOD_ARGS._serialized_start=609 - _LISTMETHOD_ARGS._serialized_end=626 - _LISTMETHOD_RESULT._serialized_start=628 - _LISTMETHOD_RESULT._serialized_end=673 - _PARSEFILE_LARKTREE_ARGS._serialized_start=675 - _PARSEFILE_LARKTREE_ARGS._serialized_end=765 - _PARSEFILE_LARKTREE_RESULT._serialized_start=767 - _PARSEFILE_LARKTREE_RESULT._serialized_end=818 - _PARSEFILE_AST_ARGS._serialized_start=820 - _PARSEFILE_AST_ARGS._serialized_end=879 - _PARSEFILE_AST_RESULT._serialized_start=881 - _PARSEFILE_AST_RESULT._serialized_end=921 - _PARSEPROGRAM_AST_ARGS._serialized_start=923 - _PARSEPROGRAM_AST_ARGS._serialized_end=971 - _PARSEPROGRAM_AST_RESULT._serialized_start=973 - _PARSEPROGRAM_AST_RESULT._serialized_end=1016 - _EXECPROGRAM_ARGS._serialized_start=1019 - _EXECPROGRAM_ARGS._serialized_end=1371 - _EXECPROGRAM_RESULT._serialized_start=1373 - _EXECPROGRAM_RESULT._serialized_end=1457 - _RESETPLUGIN_ARGS._serialized_start=1459 - _RESETPLUGIN_ARGS._serialized_end=1498 - _RESETPLUGIN_RESULT._serialized_start=1500 - _RESETPLUGIN_RESULT._serialized_end=1520 - _FORMATCODE_ARGS._serialized_start=1522 - _FORMATCODE_ARGS._serialized_end=1555 - _FORMATCODE_RESULT._serialized_start=1557 - _FORMATCODE_RESULT._serialized_end=1595 - _FORMATPATH_ARGS._serialized_start=1597 - _FORMATPATH_ARGS._serialized_end=1628 - _FORMATPATH_RESULT._serialized_start=1630 - _FORMATPATH_RESULT._serialized_end=1671 - _LINTPATH_ARGS._serialized_start=1673 - _LINTPATH_ARGS._serialized_end=1702 - _LINTPATH_RESULT._serialized_start=1704 - _LINTPATH_RESULT._serialized_end=1738 - _OVERRIDEFILE_ARGS._serialized_start=1740 - _OVERRIDEFILE_ARGS._serialized_end=1810 - _OVERRIDEFILE_RESULT._serialized_start=1812 - _OVERRIDEFILE_RESULT._serialized_end=1849 - _EVALCODE_ARGS._serialized_start=1851 - _EVALCODE_ARGS._serialized_end=1880 - _EVALCODE_RESULT._serialized_start=1882 - _EVALCODE_RESULT._serialized_end=1920 - _RESOLVECODE_ARGS._serialized_start=1922 - _RESOLVECODE_ARGS._serialized_end=1954 - _RESOLVECODE_RESULT._serialized_start=1956 - _RESOLVECODE_RESULT._serialized_end=1993 - _GETSCHEMATYPE_ARGS._serialized_start=1995 - _GETSCHEMATYPE_ARGS._serialized_end=2064 - _GETSCHEMATYPE_RESULT._serialized_start=2066 - _GETSCHEMATYPE_RESULT._serialized_end=2131 - _VALIDATECODE_ARGS._serialized_start=2133 - _VALIDATECODE_ARGS._serialized_end=2236 - _VALIDATECODE_RESULT._serialized_start=2238 - _VALIDATECODE_RESULT._serialized_end=2297 - _CODESNIPPET._serialized_start=2299 - _CODESNIPPET._serialized_end=2342 - _SPLICECODE_ARGS._serialized_start=2344 - _SPLICECODE_ARGS._serialized_end=2404 - _SPLICECODE_RESULT._serialized_start=2406 - _SPLICECODE_RESULT._serialized_end=2445 - _POSITION._serialized_start=2447 - _POSITION._serialized_end=2505 - _COMPLETE_ARGS._serialized_start=2507 - _COMPLETE_ARGS._serialized_end=2581 - _COMPLETE_RESULT._serialized_start=2583 - _COMPLETE_RESULT._serialized_end=2623 - _GOTODEF_ARGS._serialized_start=2625 - _GOTODEF_ARGS._serialized_end=2684 - _GOTODEF_RESULT._serialized_start=2686 - _GOTODEF_RESULT._serialized_end=2721 - _DOCUMENTSYMBOL_ARGS._serialized_start=2723 - _DOCUMENTSYMBOL_ARGS._serialized_end=2772 - _DOCUMENTSYMBOL_RESULT._serialized_start=2774 - _DOCUMENTSYMBOL_RESULT._serialized_end=2813 - _HOVER_ARGS._serialized_start=2815 - _HOVER_ARGS._serialized_end=2872 - _HOVER_RESULT._serialized_start=2874 - _HOVER_RESULT._serialized_end=2909 - _LISTDEPFILES_ARGS._serialized_start=2911 - _LISTDEPFILES_ARGS._serialized_end=3016 - _LISTDEPFILES_RESULT._serialized_start=3018 - _LISTDEPFILES_RESULT._serialized_end=3088 - _LOADSETTINGSFILES_ARGS._serialized_start=3090 - _LOADSETTINGSFILES_ARGS._serialized_end=3147 - _LOADSETTINGSFILES_RESULT._serialized_start=3149 - _LOADSETTINGSFILES_RESULT._serialized_end=3262 - _CLICONFIG._serialized_start=3265 - _CLICONFIG._serialized_end=3431 - _KEYVALUEPAIR._serialized_start=3433 - _KEYVALUEPAIR._serialized_end=3475 - _KCLTYPE._serialized_start=3478 - _KCLTYPE._serialized_end=3850 - _KCLTYPE_PROPERTIESENTRY._serialized_start=3784 - _KCLTYPE_PROPERTIESENTRY._serialized_end=3850 - _DECORATOR._serialized_start=3853 - _DECORATOR._serialized_end=3997 - _DECORATOR_KEYWORDSENTRY._serialized_start=3950 - _DECORATOR_KEYWORDSENTRY._serialized_end=3997 - _BUILTINSERVICE._serialized_start=4000 - _BUILTINSERVICE._serialized_end=4130 - _KCLVMSERVICE._serialized_start=4133 - _KCLVMSERVICE._serialized_end=5593 -# @@protoc_insertion_point(module_scope) diff --git a/internal/kclvm_py/internal/gpyrpc/gpyrpc_pb_protorpc.py b/internal/kclvm_py/internal/gpyrpc/gpyrpc_pb_protorpc.py deleted file mode 100644 index 26da1ede4..000000000 --- a/internal/kclvm_py/internal/gpyrpc/gpyrpc_pb_protorpc.py +++ /dev/null @@ -1,393 +0,0 @@ -# Code generated by protoc-gen-protorpc-py. DO NOT EDIT. -# -# plugin: https://github.com/chai2010/protorpc/protoc-gen-plugin -# plugin: https://github.com/chai2010/protorpc-py/protoc-gen-protorpc-py -# -# source: gpyrpc.proto - -import abc -import sys -import typing - -from google.protobuf import message as _message - -from .protorpc import ServiceMeta as _ServiceMeta -from .protorpc import Server as _Server - -from .gpyrpc_pb2 import ( - Complete_Args, - Complete_Result, - DocumentSymbol_Args, - DocumentSymbol_Result, - EvalCode_Args, - EvalCode_Result, - ExecProgram_Args, - ExecProgram_Result, - FormatCode_Args, - FormatCode_Result, - FormatPath_Args, - FormatPath_Result, - GetSchemaType_Args, - GetSchemaType_Result, - GoToDef_Args, - GoToDef_Result, - Hover_Args, - Hover_Result, - LintPath_Args, - LintPath_Result, - ListDepFiles_Args, - ListDepFiles_Result, - ListMethod_Args, - ListMethod_Result, - LoadSettingsFiles_Args, - LoadSettingsFiles_Result, - OverrideFile_Args, - OverrideFile_Result, - ParseFile_AST_Args, - ParseFile_AST_Result, - ParseFile_LarkTree_Args, - ParseFile_LarkTree_Result, - ParseProgram_AST_Args, - ParseProgram_AST_Result, - Ping_Args, - Ping_Result, - ResetPlugin_Args, - ResetPlugin_Result, - ResolveCode_Args, - ResolveCode_Result, - SpliceCode_Args, - SpliceCode_Result, - ValidateCode_Args, - ValidateCode_Result, -) - - -class BuiltinService(metaclass=abc.ABCMeta): - @abc.abstractmethod - def Ping(self, args: Ping_Args) -> Ping_Result: - pass - - @abc.abstractmethod - def ListMethod(self, args: ListMethod_Args) -> ListMethod_Result: - pass - - -class KclvmService(metaclass=abc.ABCMeta): - @abc.abstractmethod - def Ping(self, args: Ping_Args) -> Ping_Result: - pass - - @abc.abstractmethod - def ParseFile_LarkTree( - self, args: ParseFile_LarkTree_Args - ) -> ParseFile_LarkTree_Result: - pass - - @abc.abstractmethod - def ParseFile_AST(self, args: ParseFile_AST_Args) -> ParseFile_AST_Result: - pass - - @abc.abstractmethod - def ParseProgram_AST(self, args: ParseProgram_AST_Args) -> ParseProgram_AST_Result: - pass - - @abc.abstractmethod - def ExecProgram(self, args: ExecProgram_Args) -> ExecProgram_Result: - pass - - @abc.abstractmethod - def ResetPlugin(self, args: ResetPlugin_Args) -> ResetPlugin_Result: - pass - - @abc.abstractmethod - def FormatCode(self, args: FormatCode_Args) -> FormatCode_Result: - pass - - @abc.abstractmethod - def FormatPath(self, args: FormatPath_Args) -> FormatPath_Result: - pass - - @abc.abstractmethod - def LintPath(self, args: LintPath_Args) -> LintPath_Result: - pass - - @abc.abstractmethod - def OverrideFile(self, args: OverrideFile_Args) -> OverrideFile_Result: - pass - - @abc.abstractmethod - def EvalCode(self, args: EvalCode_Args) -> EvalCode_Result: - pass - - @abc.abstractmethod - def ResolveCode(self, args: ResolveCode_Args) -> ResolveCode_Result: - pass - - @abc.abstractmethod - def GetSchemaType(self, args: GetSchemaType_Args) -> GetSchemaType_Result: - pass - - @abc.abstractmethod - def ValidateCode(self, args: ValidateCode_Args) -> ValidateCode_Result: - pass - - @abc.abstractmethod - def SpliceCode(self, args: SpliceCode_Args) -> SpliceCode_Result: - pass - - @abc.abstractmethod - def Complete(self, args: Complete_Args) -> Complete_Result: - pass - - @abc.abstractmethod - def GoToDef(self, args: GoToDef_Args) -> GoToDef_Result: - pass - - @abc.abstractmethod - def DocumentSymbol(self, args: DocumentSymbol_Args) -> DocumentSymbol_Result: - pass - - @abc.abstractmethod - def Hover(self, args: Hover_Args) -> Hover_Result: - pass - - @abc.abstractmethod - def ListDepFiles(self, args: ListDepFiles_Args) -> ListDepFiles_Result: - pass - - @abc.abstractmethod - def LoadSettingsFiles( - self, args: LoadSettingsFiles_Args - ) -> LoadSettingsFiles_Result: - pass - - -class BuiltinService_Meta(_ServiceMeta): - def __init__(self, instance: BuiltinService): - super().__init__() - self._instance = instance - - def get_service_name(self) -> str: - return "BuiltinService" - - def get_method_list(self) -> typing.List[str]: - return [ - "Ping", - "ListMethod", - ] - - def create_method_req_message(self, method: str) -> _message.Message: - if method in ["Ping", "BuiltinService.Ping"]: - return Ping_Args() - if method in ["ListMethod", "BuiltinService.ListMethod"]: - return ListMethod_Args() - raise Exception(f"unknown method: {method}") - - def create_method_resp_message(self, method: str) -> _message.Message: - if method in ["Ping", "BuiltinService.Ping"]: - return Ping_Result() - if method in ["ListMethod", "BuiltinService.ListMethod"]: - return ListMethod_Result() - raise Exception(f"unknown method: {method}") - - def get_service_instance(self) -> _message.Message: - return typing.cast(_message.Message, self._instance) - - def call_method(self, method: str, req: _message.Message) -> _message.Message: - if method in ["Ping", "BuiltinService.Ping"]: - return self._instance.Ping(req) - if method in ["ListMethod", "BuiltinService.ListMethod"]: - return self._instance.ListMethod(req) - raise Exception(f"unknown method: {method}") - - -class KclvmService_Meta(_ServiceMeta): - def __init__(self, instance: KclvmService): - super().__init__() - self._instance = instance - - def get_service_name(self) -> str: - return "KclvmService" - - def get_method_list(self) -> typing.List[str]: - return [ - "Ping", - "ParseFile_LarkTree", - "ParseFile_AST", - "ParseProgram_AST", - "ExecProgram", - "ResetPlugin", - "FormatCode", - "FormatPath", - "LintPath", - "OverrideFile", - "EvalCode", - "ResolveCode", - "GetSchemaType", - "ValidateCode", - "SpliceCode", - "Complete", - "GoToDef", - "DocumentSymbol", - "Hover", - "ListDepFiles", - "LoadSettingsFiles", - ] - - def create_method_req_message(self, method: str) -> _message.Message: - if method in ["Ping", "KclvmService.Ping"]: - return Ping_Args() - if method in ["ParseFile_LarkTree", "KclvmService.ParseFile_LarkTree"]: - return ParseFile_LarkTree_Args() - if method in ["ParseFile_AST", "KclvmService.ParseFile_AST"]: - return ParseFile_AST_Args() - if method in ["ParseProgram_AST", "KclvmService.ParseProgram_AST"]: - return ParseProgram_AST_Args() - if method in ["ExecProgram", "KclvmService.ExecProgram"]: - return ExecProgram_Args() - if method in ["ResetPlugin", "KclvmService.ResetPlugin"]: - return ResetPlugin_Args() - if method in ["FormatCode", "KclvmService.FormatCode"]: - return FormatCode_Args() - if method in ["FormatPath", "KclvmService.FormatPath"]: - return FormatPath_Args() - if method in ["LintPath", "KclvmService.LintPath"]: - return LintPath_Args() - if method in ["OverrideFile", "KclvmService.OverrideFile"]: - return OverrideFile_Args() - if method in ["EvalCode", "KclvmService.EvalCode"]: - return EvalCode_Args() - if method in ["ResolveCode", "KclvmService.ResolveCode"]: - return ResolveCode_Args() - if method in ["GetSchemaType", "KclvmService.GetSchemaType"]: - return GetSchemaType_Args() - if method in ["ValidateCode", "KclvmService.ValidateCode"]: - return ValidateCode_Args() - if method in ["SpliceCode", "KclvmService.SpliceCode"]: - return SpliceCode_Args() - if method in ["Complete", "KclvmService.Complete"]: - return Complete_Args() - if method in ["GoToDef", "KclvmService.GoToDef"]: - return GoToDef_Args() - if method in ["DocumentSymbol", "KclvmService.DocumentSymbol"]: - return DocumentSymbol_Args() - if method in ["Hover", "KclvmService.Hover"]: - return Hover_Args() - if method in ["ListDepFiles", "KclvmService.ListDepFiles"]: - return ListDepFiles_Args() - if method in ["LoadSettingsFiles", "KclvmService.LoadSettingsFiles"]: - return LoadSettingsFiles_Args() - raise Exception(f"unknown method: {method}") - - def create_method_resp_message(self, method: str) -> _message.Message: - if method in ["Ping", "KclvmService.Ping"]: - return Ping_Result() - if method in ["ParseFile_LarkTree", "KclvmService.ParseFile_LarkTree"]: - return ParseFile_LarkTree_Result() - if method in ["ParseFile_AST", "KclvmService.ParseFile_AST"]: - return ParseFile_AST_Result() - if method in ["ParseProgram_AST", "KclvmService.ParseProgram_AST"]: - return ParseProgram_AST_Result() - if method in ["ExecProgram", "KclvmService.ExecProgram"]: - return ExecProgram_Result() - if method in ["ResetPlugin", "KclvmService.ResetPlugin"]: - return ResetPlugin_Result() - if method in ["FormatCode", "KclvmService.FormatCode"]: - return FormatCode_Result() - if method in ["FormatPath", "KclvmService.FormatPath"]: - return FormatPath_Result() - if method in ["LintPath", "KclvmService.LintPath"]: - return LintPath_Result() - if method in ["OverrideFile", "KclvmService.OverrideFile"]: - return OverrideFile_Result() - if method in ["EvalCode", "KclvmService.EvalCode"]: - return EvalCode_Result() - if method in ["ResolveCode", "KclvmService.ResolveCode"]: - return ResolveCode_Result() - if method in ["GetSchemaType", "KclvmService.GetSchemaType"]: - return GetSchemaType_Result() - if method in ["ValidateCode", "KclvmService.ValidateCode"]: - return ValidateCode_Result() - if method in ["SpliceCode", "KclvmService.SpliceCode"]: - return SpliceCode_Result() - if method in ["Complete", "KclvmService.Complete"]: - return Complete_Result() - if method in ["GoToDef", "KclvmService.GoToDef"]: - return GoToDef_Result() - if method in ["DocumentSymbol", "KclvmService.DocumentSymbol"]: - return DocumentSymbol_Result() - if method in ["Hover", "KclvmService.Hover"]: - return Hover_Result() - if method in ["ListDepFiles", "KclvmService.ListDepFiles"]: - return ListDepFiles_Result() - if method in ["LoadSettingsFiles", "KclvmService.LoadSettingsFiles"]: - return LoadSettingsFiles_Result() - raise Exception(f"unknown method: {method}") - - def get_service_instance(self) -> _message.Message: - return typing.cast(_message.Message, self._instance) - - def call_method(self, method: str, req: _message.Message) -> _message.Message: - if method in ["Ping", "KclvmService.Ping"]: - return self._instance.Ping(req) - if method in ["ParseFile_LarkTree", "KclvmService.ParseFile_LarkTree"]: - return self._instance.ParseFile_LarkTree(req) - if method in ["ParseFile_AST", "KclvmService.ParseFile_AST"]: - return self._instance.ParseFile_AST(req) - if method in ["ParseProgram_AST", "KclvmService.ParseProgram_AST"]: - return self._instance.ParseProgram_AST(req) - if method in ["ExecProgram", "KclvmService.ExecProgram"]: - return self._instance.ExecProgram(req) - if method in ["ResetPlugin", "KclvmService.ResetPlugin"]: - return self._instance.ResetPlugin(req) - if method in ["FormatCode", "KclvmService.FormatCode"]: - return self._instance.FormatCode(req) - if method in ["FormatPath", "KclvmService.FormatPath"]: - return self._instance.FormatPath(req) - if method in ["LintPath", "KclvmService.LintPath"]: - return self._instance.LintPath(req) - if method in ["OverrideFile", "KclvmService.OverrideFile"]: - return self._instance.OverrideFile(req) - if method in ["EvalCode", "KclvmService.EvalCode"]: - return self._instance.EvalCode(req) - if method in ["ResolveCode", "KclvmService.ResolveCode"]: - return self._instance.ResolveCode(req) - if method in ["GetSchemaType", "KclvmService.GetSchemaType"]: - return self._instance.GetSchemaType(req) - if method in ["ValidateCode", "KclvmService.ValidateCode"]: - return self._instance.ValidateCode(req) - if method in ["SpliceCode", "KclvmService.SpliceCode"]: - return self._instance.SpliceCode(req) - if method in ["Complete", "KclvmService.Complete"]: - return self._instance.Complete(req) - if method in ["GoToDef", "KclvmService.GoToDef"]: - return self._instance.GoToDef(req) - if method in ["DocumentSymbol", "KclvmService.DocumentSymbol"]: - return self._instance.DocumentSymbol(req) - if method in ["Hover", "KclvmService.Hover"]: - return self._instance.Hover(req) - if method in ["ListDepFiles", "KclvmService.ListDepFiles"]: - return self._instance.ListDepFiles(req) - if method in ["LoadSettingsFiles", "KclvmService.LoadSettingsFiles"]: - return self._instance.LoadSettingsFiles(req) - raise Exception(f"unknown method: {method}") - - -class BuiltinService_Server: - def __init__(self, instance: BuiltinService): - self.instance = instance - - def run(self, *, stdin=sys.stdin, stdout=sys.stdout): - rpc_server = _Server() - rpc_server.register_service(BuiltinService_Meta(self.instance)) - rpc_server.run(stdin=stdin, stdout=stdout) - - -class KclvmService_Server: - def __init__(self, instance: KclvmService): - self.instance = instance - - def run(self, *, stdin=sys.stdin, stdout=sys.stdout): - rpc_server = _Server() - rpc_server.register_service(KclvmService_Meta(self.instance)) - rpc_server.run(stdin=stdin, stdout=stdout) diff --git a/internal/kclvm_py/internal/gpyrpc/protorpc.py b/internal/kclvm_py/internal/gpyrpc/protorpc.py deleted file mode 100644 index 1a8bd0916..000000000 --- a/internal/kclvm_py/internal/gpyrpc/protorpc.py +++ /dev/null @@ -1,284 +0,0 @@ -# Copyright 2021 The KCL Authors. All rights reserved. - -import abc -import sys -import traceback -import typing - -from dataclasses import dataclass - -import kclvm.kcl.error as kcl_error -import kclvm.internal.gpyrpc.varint as varint - -from google.protobuf import message as _message -import google.protobuf.json_format as _json_format - -from .protorpc_wire_pb2 import ( - MAX_REQUEST_HEADER_LEN, - RequestHeader, - ResponseHeader, -) - - -@dataclass -class Status: - error: str = "" - - -class Channel(object): - def __init__(self, *, stdin=sys.stdin, stdout=sys.stdout): - self.stdin = stdin - self.stdout = stdout - self.next_id = 1 - - def get_next_id(self) -> int: - next_id = self.next_id - self.next_id = self.next_id + 1 - return next_id - - def send_frame(self, data: bytes): - self.stdout.buffer.write(varint.encode(len(data))) - self.stdout.buffer.write(data) - self.stdout.flush() - - def recv_frame(self, _max_size: int = 0) -> bytes: - size = varint.decode_stream(self.stdin.buffer) - - if size > _max_size > 0: - raise Exception(f"protorpc: varint overflows maxSize({_max_size})") - - data = self.stdin.buffer.read(size) - return data - - def write_request(self, method: str, req: _message.Message): - body = req.SerializeToString() - - hdr = RequestHeader( - id=self.get_next_id(), method=method, raw_request_len=len(body) - ) - self.send_frame(hdr.SerializeToString()) - self.send_frame(body) - - def read_request_header(self) -> RequestHeader: - data = self.recv_frame(MAX_REQUEST_HEADER_LEN) - hdr = RequestHeader() - hdr.ParseFromString(data) - - if hdr.snappy_compressed_request_len != 0: - raise Exception("py: unsupport snappy compressed request") - if hdr.checksum != 0: - raise Exception("py: unsupport checksum request") - - return hdr - - def read_request_body(self, header: RequestHeader, body: _message.Message): - data = self.recv_frame( - max(header.raw_request_len, header.snappy_compressed_request_len) - ) - body.ParseFromString(data) - - def write_response(self, id_: int, error: str, response: _message.Message): - body = response.SerializeToString() - hdr = ResponseHeader(id=id_, error=error, raw_response_len=len(body)) - self.send_frame(hdr.SerializeToString()) - self.send_frame(body) - - def read_response_header(self) -> ResponseHeader: - data = self.recv_frame(0) - hdr = ResponseHeader() - hdr.ParseFromString(data) - - if hdr.snappy_compressed_response_len != 0: - raise Exception("py: unsupport snappy compressed response") - if hdr.checksum != 0: - raise Exception("py: unsupport checksum response") - - return hdr - - def read_response_body(self, header: ResponseHeader, body: _message.Message): - data = self.recv_frame( - max(header.raw_response_len, header.snappy_compressed_response_len) - ) - body.ParseFromString(data) - - def call_method( - self, method: str, req: _message.Message, resp: _message.Message - ) -> Status: - self.write_request(method, req) - resp_hdr = self.read_response_header() - self.read_response_body(resp_hdr, resp) - return Status(error=resp_hdr.error) - - -class ServiceMeta(metaclass=abc.ABCMeta): - @abc.abstractmethod - def get_service_name(self) -> str: - pass - - @abc.abstractmethod - def get_method_list(self) -> typing.List[str]: - pass - - @abc.abstractmethod - def create_method_req_message(self, method: str) -> _message.Message: - pass - - @abc.abstractmethod - def create_method_resp_message(self, method: str) -> _message.Message: - pass - - @abc.abstractmethod - def get_service_instance(self) -> _message.Message: - pass - - @abc.abstractmethod - def call_method(self, method: str, req: _message.Message) -> _message.Message: - pass - - -class Server: - def __init__(self): - self.srv_table: typing.Dict[str, ServiceMeta] = {} - self.chan: typing.Optional[Channel] = None - - def register_service(self, srv: ServiceMeta): - self.srv_table[srv.get_service_name()] = srv - - def get_service_name_list(self) -> typing.List[str]: - name_list: typing.List[str] = [] - for s in self.srv_table.keys(): - name_list.append(s) - name_list.sort() - return name_list - - def get_method_name_list(self) -> typing.List[str]: - name_list: typing.List[str] = [] - for srv in self.srv_table.values(): - srv_name = srv.get_service_name() - for method_name in srv.get_method_list(): - name_list.append(f"{srv_name}.{method_name}") - name_list.sort() - return name_list - - def run(self, *, stdin=sys.stdin, stdout=sys.stdout): - self.chan = Channel(stdin=stdin, stdout=stdout) - while True: - self._accept_one_call() - - def run_once(self, *, stdin=sys.stdin, stdout=sys.stdout): - self.chan = Channel(stdin=stdin, stdout=stdout) - self._accept_one_call() - - def call_method( - self, method_path: str, req_body: bytes, *, encoding: str = "json" - ) -> dict: - if encoding not in ["json", "protobuf"]: - raise Exception(f"encoding '{encoding}' not support") - - service_name = method_path[: method_path.rfind(".")] - method_name = method_path[method_path.rfind(".") + 1 :] - - if service_name not in self.srv_table: - raise Exception(f"service '{service_name}' not found") - - service = self.srv_table[service_name] - - req = service.create_method_req_message(method_name) - - if encoding == "json": - _json_format.Parse(req_body, req) - else: - req.ParseFromString(req_body) - - try: - resp = service.call_method(method_name, req) - - except kcl_error.KCLException as err: - raise err - - except OSError as err: - err_message = f"OSError: {err}" - raise Exception(err_message) - - except AssertionError as err: - err_message = f"AssertionError: {err}" - raise Exception(err_message) - - except Exception as err: - err_message = f"Exception: Internal Error! Please report a bug to us: method={method_name}, err={err}, stack trace={traceback.format_exc()}" - raise Exception(err_message) - - # return response - # https://googleapis.dev/python/protobuf/latest/google/protobuf/json_format.html - return _json_format.MessageToDict( - resp, - including_default_value_fields=True, - preserving_proto_field_name=True, - ) - - def _accept_one_call(self): - hdr = self._read_req_header() - - service_name = hdr.method[: hdr.method.rfind(".")] - method_name = hdr.method[hdr.method.rfind(".") + 1 :] - - if service_name not in self.srv_table: - raise Exception(f"service '{service_name}' not found") - - service = self.srv_table[service_name] - - req = self._read_req(service, hdr) - - try: - resp = service.call_method(method_name, req) - self._write_resp(hdr.id, "", resp) - return - - except kcl_error.KCLException as err: - resp = service.create_method_resp_message(method_name) - - err_message = f"{err}" - self._write_resp(hdr.id, err_message, resp) - return - - except OSError as err: - resp = service.create_method_resp_message(method_name) - - err_message = f"OSError: {err}" - self._write_resp(hdr.id, err_message, resp) - return - - except AssertionError as err: - resp = service.create_method_resp_message(method_name) - - err_message = f"AssertionError: {err}" - self._write_resp(hdr.id, err_message, resp) - return - - except Exception as err: - resp = service.create_method_resp_message(method_name) - - err_message = f"Exception: Internal Error! Please report a bug to us: method={method_name}, err={err}, stack trace={traceback.format_exc()}" - self._write_resp(hdr.id, err_message, resp) - return - - def _read_req_header(self) -> RequestHeader: - return self.chan.read_request_header() - - def _read_req(self, service: ServiceMeta, hdr: RequestHeader) -> _message.Message: - req = service.create_method_req_message(hdr.method) - self.chan.read_request_body(hdr, req) - return req - - def _write_resp(self, id_: int, error: str, resp: _message.Message): - self.chan.write_response(id_, error, resp) - - -class Client: - def __init__(self, chan: Channel = None): - self.chan: Channel = chan - - def call_method( - self, method: str, req: _message.Message, resp: _message.Message - ) -> Status: - return self.chan.call_method(method, req, resp) diff --git a/internal/kclvm_py/internal/gpyrpc/protorpc_wire_pb2.py b/internal/kclvm_py/internal/gpyrpc/protorpc_wire_pb2.py deleted file mode 100644 index 5e14f945f..000000000 --- a/internal/kclvm_py/internal/gpyrpc/protorpc_wire_pb2.py +++ /dev/null @@ -1,51 +0,0 @@ -# -*- coding: utf-8 -*- -# Generated by the protocol buffer compiler. DO NOT EDIT! -# source: gpyrpc/protorpc_wire.proto -"""Generated protocol buffer code.""" -from google.protobuf.internal import enum_type_wrapper -from google.protobuf import descriptor as _descriptor -from google.protobuf import descriptor_pool as _descriptor_pool -from google.protobuf import message as _message -from google.protobuf import reflection as _reflection -from google.protobuf import symbol_database as _symbol_database -# @@protoc_insertion_point(imports) - -_sym_db = _symbol_database.Default() - - - - -DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1agpyrpc/protorpc_wire.proto\x12\rprotorpc_wire\"}\n\rRequestHeader\x12\n\n\x02id\x18\x01 \x01(\x04\x12\x0e\n\x06method\x18\x02 \x01(\t\x12\x17\n\x0fraw_request_len\x18\x03 \x01(\r\x12%\n\x1dsnappy_compressed_request_len\x18\x04 \x01(\r\x12\x10\n\x08\x63hecksum\x18\x05 \x01(\r\"\x7f\n\x0eResponseHeader\x12\n\n\x02id\x18\x01 \x01(\x04\x12\r\n\x05\x65rror\x18\x02 \x01(\t\x12\x18\n\x10raw_response_len\x18\x03 \x01(\r\x12&\n\x1esnappy_compressed_response_len\x18\x04 \x01(\r\x12\x10\n\x08\x63hecksum\x18\x05 \x01(\r*.\n\x05\x43onst\x12\x08\n\x04ZERO\x10\x00\x12\x1b\n\x16MAX_REQUEST_HEADER_LEN\x10\x80\x08\x62\x06proto3') - -_CONST = DESCRIPTOR.enum_types_by_name['Const'] -Const = enum_type_wrapper.EnumTypeWrapper(_CONST) -ZERO = 0 -MAX_REQUEST_HEADER_LEN = 1024 - - -_REQUESTHEADER = DESCRIPTOR.message_types_by_name['RequestHeader'] -_RESPONSEHEADER = DESCRIPTOR.message_types_by_name['ResponseHeader'] -RequestHeader = _reflection.GeneratedProtocolMessageType('RequestHeader', (_message.Message,), { - 'DESCRIPTOR' : _REQUESTHEADER, - '__module__' : 'gpyrpc.protorpc_wire_pb2' - # @@protoc_insertion_point(class_scope:protorpc_wire.RequestHeader) - }) -_sym_db.RegisterMessage(RequestHeader) - -ResponseHeader = _reflection.GeneratedProtocolMessageType('ResponseHeader', (_message.Message,), { - 'DESCRIPTOR' : _RESPONSEHEADER, - '__module__' : 'gpyrpc.protorpc_wire_pb2' - # @@protoc_insertion_point(class_scope:protorpc_wire.ResponseHeader) - }) -_sym_db.RegisterMessage(ResponseHeader) - -if _descriptor._USE_C_DESCRIPTORS == False: - - DESCRIPTOR._options = None - _CONST._serialized_start=301 - _CONST._serialized_end=347 - _REQUESTHEADER._serialized_start=45 - _REQUESTHEADER._serialized_end=170 - _RESPONSEHEADER._serialized_start=172 - _RESPONSEHEADER._serialized_end=299 -# @@protoc_insertion_point(module_scope) diff --git a/internal/kclvm_py/internal/gpyrpc/varint.py b/internal/kclvm_py/internal/gpyrpc/varint.py deleted file mode 100644 index c06f3466f..000000000 --- a/internal/kclvm_py/internal/gpyrpc/varint.py +++ /dev/null @@ -1,71 +0,0 @@ -"""Varint encoder/decoder - -varints are a common encoding for variable length integer data, used in -libraries such as sqlite, protobuf, v8, and more. - -Here's a quick and dirty module to help avoid reimplementing the same thing -over and over again. -""" - -# byte-oriented StringIO was moved to io.BytesIO in py3k -try: - from io import BytesIO -except ImportError: - from StringIO import StringIO as BytesIO - -import sys - -if sys.version > "3": - - def _byte(b): - return bytes((b,)) - - -else: - - def _byte(b): - return chr(b) - - -def encode(number): - """Pack `number` into varint bytes""" - buf = b"" - while True: - towrite = number & 0x7F - number >>= 7 - if number: - buf += _byte(towrite | 0x80) - else: - buf += _byte(towrite) - break - return buf - - -def decode_stream(stream): - """Read a varint from `stream`""" - shift = 0 - result = 0 - while True: - i = _read_one(stream) - result |= (i & 0x7F) << shift - shift += 7 - if not (i & 0x80): - break - - return result - - -def decode_bytes(buf): - """Read a varint from from `buf` bytes""" - return decode_stream(BytesIO(buf)) - - -def _read_one(stream): - """Read a byte from the file (as an integer) - - raises EOFError if the stream ends while reading bytes. - """ - c = stream.read(1) - if c == b"": - raise EOFError("Unexpected EOF while reading bytes") - return ord(c) diff --git a/internal/kclvm_py/internal/kclvm_internal/__init__.py b/internal/kclvm_py/internal/kclvm_internal/__init__.py deleted file mode 100644 index d936bb260..000000000 --- a/internal/kclvm_py/internal/kclvm_internal/__init__.py +++ /dev/null @@ -1,9 +0,0 @@ -import kclvm.config as config -import kclvm.api.version - -from .main import Main - -__all__ = ["Main"] - -__version__ = kclvm.api.version.VERSION -config.version = __version__ diff --git a/internal/kclvm_py/internal/kclvm_internal/main.py b/internal/kclvm_py/internal/kclvm_internal/main.py deleted file mode 100644 index c43f58051..000000000 --- a/internal/kclvm_py/internal/kclvm_internal/main.py +++ /dev/null @@ -1,245 +0,0 @@ -"""Expose KCLVM command via ``python -m kclvm``, or ``kcl`` for short.""" -import sys -import os -import argparse -import cProfile -import typing - -import kclvm.config -import kclvm.kcl.ast as kcl_ast -import kclvm.program.exec as kclvm_exec -import kclvm.compiler.parser -import kclvm.kcl.error as kcl_error -import kclvm.internal.log as klog -import kclvm.tools.format -import kclvm.tools.docs -import kclvm.api.version -import kclvm.vm.planner as planner - -from kclvm.api.object.internal import kcl_option_init_all -from kclvm.tools.list_attribute.utils import ListAttributePrinter - - -def Main(): - try: - parser = argparse.ArgumentParser( - prog="kcl", description="K Configuration Language Virtual Machine" - ) - parser.add_argument( - "-D", - "--argument", - default=[], - action=kclvm.config.KCLTopLevelArgumentAction, - help="Specify the top-level argument", - required=False, - ) - parser.add_argument( - "-S", - "--path-selector", - default=[], - action=kclvm.config.KCLPathSelectorAction, - help="Specify the path selector", - required=False, - ) - parser.add_argument( - "-O", - "--overrides", - default=[], - action=kclvm.config.KCLOverrideAction, - help="Specify the configuration override path and value", - required=False, - ) - parser.add_argument( - "-Y", - "--setting", - help="Specify the command line setting file", - nargs="*", - required=False, - ) - parser.add_argument( - "-o", "--output", help="Specify the output file", required=False - ) - parser.add_argument( - "-n", - "--disable-none", - help="Disable dumping None values", - action="store_true", - required=False, - ) - parser.add_argument( - "--sort", - help="Sort result keys", - dest="sort_keys", - action="store_true", - required=False, - ) - parser.add_argument( - "-r", - "--strict-range-check", - help="Do perform strict numeric range check", - action="store_true", - required=False, - ) - parser.add_argument( - "-c", - "--compile-only", - help="Compile only", - action="store_true", - required=False, - ) - parser.add_argument( - "-s", - "--save-temps", - help="Save intermediate files", - action="store_true", - required=False, - ) - parser.add_argument( - "-v", - "--verbose", - help="Run in verbose mode", - action="count", - default=0, - required=False, - ) - parser.add_argument( - "-d", - "--debug", - help="Run in debug mode (for developers only)", - action="count", - default=0, - required=False, - ) - parser.add_argument( - "-p", - "--profile", - help="Perform profiling", - action="store_true", - required=False, - ) - parser.add_argument( - "-L", - "--list-attributes", - dest="show_attribute_list", - help="Show schema attributes list", - action="store_true", - ) - parser.add_argument( - "-l", - "--list-options", - dest="list_option_mode", - default=0, - action="count", - help="Show kcl options list", - ) - parser.add_argument( - "-V", - "--version", - help="Show the kclvm version", - action="version", - version=f"kclvm version is {kclvm.api.version.VERSION}; " - f"checksum: {kclvm.api.version.CHECKSUM}", - ) - parser.add_argument("file", help="Input compile file", nargs="*") - parser.add_argument( - "--target", - help="Specify the target type", - type=str, - default="", - choices=["native", "wasm"], - required=False, - ) - - args = parser.parse_args() - if len(sys.argv) == 1: - parser.print_help(sys.stdout) - sys.exit(0) - - argsdict = vars(args) - kclvm.config.current_path = os.getcwd() - # 1. Deal KCL CLI using settings file - kclvm.config.arguments = kclvm.config.KCLCLISettingAction().deal( - argsdict["setting"] - ) - # 2. Deal KCL CLI config using CLI arguments - kclvm.config.parse_config(argsdict) - - compile_only = argsdict["compile_only"] - target = argsdict["target"] - - if args.list_option_mode > 0: - kclvm.config.list_option_mode = args.list_option_mode - kclvm.config.disable_schema_check = True - - kclvm.config.dump() - - def kcl_main(): - kcl_option_init_all() - if kclvm.config.input_file: - files = kclvm.config.input_file - if args.show_attribute_list: - for file in files: - ListAttributePrinter(file).print() - exit(0) - - overrides: typing.List[kcl_ast.CmdOverrideSpec] = [] - for x in kclvm.config.overrides: - if len(x) == 4: - overrides.append( - kcl_ast.CmdOverrideSpec( - pkgpath=x[0], - field_path=x[1], - field_value=x[2], - action=x[3], - ) - ) - - output = kclvm_exec.Run( - files, - cmd_overrides=overrides, - print_override_ast=len(overrides) > 0 and kclvm.config.debug, - target=f"{target}", - ) - - if kclvm.config.list_option_mode > 0: - print(kclvm.config.options_help_message) - exit(0) - if not compile_only: - output = planner.YAMLPlanner(sort_keys=args.sort_keys).plan( - output.filter_by_path_selector( - to_kcl=not ( - kclvm.config.is_target_native - or kclvm.config.is_target_wasm - ) - ), - to_py=not ( - kclvm.config.is_target_native or kclvm.config.is_target_wasm - ), - ) - klog.write_out(output) - return - - if argsdict["profile"]: - cProfile.runctx("kcl_main()", None, locals()) - else: - kcl_main() - except kcl_error.KCLException as err: - if kclvm.config.debug and kclvm.config.verbose > 2: - raise err - kcl_error.print_kcl_error_message(err, file=sys.stderr) - sys.exit(1) - except OSError as err: - if kclvm.config.debug and kclvm.config.verbose > 2: - raise err - kcl_error.print_common_error_message(err, file=sys.stderr) - sys.exit(1) - except AssertionError as err: - kcl_error.print_internal_error_message(err, file=sys.stderr) - raise - except Exception: - kcl_error.print_internal_error_message(file=sys.stderr) - raise - - -if __name__ == "__main__": - Main() diff --git a/internal/kclvm_py/internal/kclx/__main__.py b/internal/kclvm_py/internal/kclx/__main__.py deleted file mode 100644 index b2236f3b7..000000000 --- a/internal/kclvm_py/internal/kclx/__main__.py +++ /dev/null @@ -1,52 +0,0 @@ -# Copyright 2021 The KCL Authors. All rights reserved. - -import sys -from dataclasses import dataclass - -import kclvm.compiler.parser as parser -import kclvm.compiler.build.compiler as compiler - -from .transformer import transform_ast_to_kclx_ast_json_str - -USAGE = """\ -usage: kclvm -m kclvm.internal.kclx -f= -usage: kclvm -m kclvm.internal.kclx -h -""" - - -@dataclass -class CmdFlags: - help: bool = False - file: str = "" - - -def parse_flags(args: list) -> CmdFlags: - m = CmdFlags() - for s in args: - if s == "-h" or s == "-help": - m.help = True - continue - - if s.startswith("-f="): - value = s[len("-f=") :] - m.file = value - continue - - return m - - -def main(): - flags = parse_flags(sys.argv[1:]) - - if flags.help: - print(USAGE) - sys.exit(0) - - if flags.file: - ast_prog = parser.LoadProgram(*flags.file.split(",")) - compiler.FixAndResolveProgram(ast_prog) - print(transform_ast_to_kclx_ast_json_str(ast_prog)) - - -if __name__ == "__main__": - main() diff --git a/internal/kclvm_py/internal/kclx/transformer.py b/internal/kclvm_py/internal/kclx/transformer.py deleted file mode 100644 index 3d5322d77..000000000 --- a/internal/kclvm_py/internal/kclx/transformer.py +++ /dev/null @@ -1,973 +0,0 @@ -# Copyright 2021 The KCL Authors. All rights reserved. - -import typing -from dataclasses import dataclass - -import kclvm.config -import kclvm.kcl.error as kcl_error -import kclvm.kcl.info as kcl_info -import kclvm.kcl.ast as ast - - -KCLX_NODE_FIELD = "node" -BIN_OP_MAPPING = { - ast.BinOp.Add: "Add", - ast.BinOp.Sub: "Sub", - ast.BinOp.Mul: "Mul", - ast.BinOp.Div: "Div", - ast.BinOp.Mod: "Mod", - ast.BinOp.Pow: "Pow", - ast.BinOp.LShift: "LShift", - ast.BinOp.RShift: "RShift", - ast.BinOp.BitOr: "BitOr", - ast.BinOp.BitAnd: "BitAnd", - ast.BinOp.BitXor: "BitXor", - ast.BinOp.FloorDiv: "FloorDiv", - ast.BinOp.As: "As", - ast.BinOp.And: "And", - ast.BinOp.Or: "Or", -} -AUG_OP_MAPPING = { - ast.AugOp.Assign: "Assign", - ast.AugOp.Add: "Add", - ast.AugOp.Sub: "Sub", - ast.AugOp.Mul: "Mul", - ast.AugOp.Div: "Div", - ast.AugOp.Mod: "Mod", - ast.AugOp.Pow: "Pow", - ast.AugOp.LShift: "LShift", - ast.AugOp.RShift: "RShift", - ast.AugOp.BitOr: "BitOr", - ast.AugOp.BitXor: "BitXor", - ast.AugOp.BitAnd: "BitAnd", - ast.AugOp.FloorDiv: "FloorDiv", -} -UNARY_OP_MAPPING = { - ast.UnaryOp.UAdd: "UAdd", - ast.UnaryOp.USub: "USub", - ast.UnaryOp.Invert: "Invert", - ast.UnaryOp.Not: "Not", -} -CMP_OP_MAPPING = { - ast.CmpOp.Eq: "Eq", - ast.CmpOp.NotEq: "NotEq", - ast.CmpOp.Lt: "Lt", - ast.CmpOp.LtE: "LtE", - ast.CmpOp.Gt: "Gt", - ast.CmpOp.GtE: "GtE", - ast.CmpOp.Is: "Is", - ast.CmpOp.In: "In", - ast.CmpOp.Not: "Not", - ast.CmpOp.IsNot: "IsNot", - ast.CmpOp.NotIn: "NotIn", -} -QUANT_OP_MAPPING = { - ast.QuantOperation.ALL: "All", - ast.QuantOperation.ANY: "Any", - ast.QuantOperation.FILTER: "Filter", - ast.QuantOperation.MAP: "Map", -} -CONFIG_ENTRY_OP_MAPPING = { - ast.ConfigEntryOperation.UNION: "Union", - ast.ConfigEntryOperation.OVERRIDE: "Override", - ast.ConfigEntryOperation.INSERT: "Insert", -} -EXPR_CTX_MAPPING = { - ast.ExprContext.LOAD: "Load", - ast.ExprContext.STORE: "Store", - ast.ExprContext.AUGLOAD: "Load", - ast.ExprContext.AUGSTORE: "Store", - ast.ExprContext.DEL: "Del", -} -OVERRIDE_ACTION_MAPPING = { - ast.OverrideAction.CREATE_OR_UPDATE: "CreateOrUpdate", - ast.OverrideAction.DELETE: "Delete", -} -TYPE_KCLX_ENUM_MAPPING = { - # Stmt - "TypeAliasStmt": "TypeAlias", - "UnificationStmt": "Unification", - "AssignStmt": "Assign", - "AugAssignStmt": "AugAssign", - "AssertStmt": "Assert", - "IfStmt": "If", - "ImportStmt": "Import", - "SchemaIndexSignature": "SchemaIndexSignature", - "SchemaAttr": "SchemaAttr", - "SchemaStmt": "Schema", - "RuleStmt": "Rule", - # Expr - "Identifier": "Identifier", - "UnaryExpr": "Unary", - "BinaryExpr": "Binary", - "IfExpr": "If", - "SelectorExpr": "Selector", - "CallExpr": "Call", - "ParenExpr": "Paren", - "QuantExpr": "Quant", - "ListExpr": "List", - "ListIfItemExpr": "ListIfItem", - "ListComp": "ListComp", - "StarredExpr": "Starred", - "DictComp": "DictComp", - "ConfigIfEntryExpr": "ConfigIfEntry", - "CompClause": "CompClause", - "SchemaExpr": "Schema", - "ConfigExpr": "Config", - "ConfigEntry": "ConfigEntry", - "CheckExpr": "Check", - "LambdaExpr": "Lambda", - "Decorator": "Decorator", - "Subscript": "Subscript", - "Keyword": "Keyword", - "Arguments": "Arguments", - "Compare": "Compare", - "NumberLit": "NumberLit", - "StringLit": "StringLit", - "NameConstantLit": "NameConstantLit", - "JoinedString": "JoinedString", - "FormattedValue": "FormattedValue", -} -INIT_FILENAME = "" -INIT_POS = 1 - - -@dataclass -class KCLxNode: - filename: str - line: int - column: int - end_line: int - end_column: int - - -class BaseKCLxASTTransformer(ast.TreeWalker): - @staticmethod - def ast_meta_to_dict(t: ast.AST) -> dict: - return KCLxNode( - filename=t.filename or INIT_FILENAME, - line=t.line or INIT_POS, - column=t.column or INIT_POS, - end_line=t.end_line or t.line or INIT_POS, - end_column=t.end_column or t.end_column or INIT_POS, - ).__dict__ - - def get_node_name(self, t: ast.AST): - return t.type - - def stmts(self, stmts: typing.List[ast.Stmt]): - return [self.stmt(stmt) for stmt in stmts or []] - - def exprs(self, exprs: typing.List[ast.Expr], with_enum_name: bool = False): - return [self.expr(expr, with_enum_name) for expr in exprs or []] - - def expr(self, expr: ast.Expr, with_enum_name: bool = False): - expr_value = self.walk(expr) if expr else None - if with_enum_name and expr_value and KCLX_NODE_FIELD in expr_value: - expr_value[KCLX_NODE_FIELD] = { - TYPE_KCLX_ENUM_MAPPING[expr._ast_type]: expr_value[KCLX_NODE_FIELD] - } - return expr_value - - def stmt(self, stmt: ast.Expr): - return self.walk(stmt) if stmt else None - - -class KCLxASTTransformer(BaseKCLxASTTransformer): - """TODO: Transform the Python KCL AST to the KCLx AST""" - - def walk_Module(self, t: ast.Module): - data = self.ast_meta_to_dict(t) - data.update( - { - "filename": t.filename, - "pkg": t.pkg, - "doc": t.doc, - "name": t.name, - "body": self.stmts(t.body), - "comments": self.exprs(t.comments), - } - ) - return data - - def walk_TypeAliasStmt(self, t: ast.TypeAliasStmt): - data = self.ast_meta_to_dict(t) - data.update( - { - KCLX_NODE_FIELD: { - TYPE_KCLX_ENUM_MAPPING[t._ast_type]: { - "type_name": self.expr(t.type_name), - "type_value": { - KCLX_NODE_FIELD: t.type_value.plain_type_str, - **self.ast_meta_to_dict(t), - }, - } - } - } - ) - return data - - def walk_ExprStmt(self, t: ast.ExprStmt): - data = self.ast_meta_to_dict(t) - data.update({KCLX_NODE_FIELD: {"Expr": {"exprs": self.exprs(t.exprs, True)}}}) - return data - - def walk_UnificationStmt(self, t: ast.UnificationStmt): - data = self.ast_meta_to_dict(t) - data.update( - { - KCLX_NODE_FIELD: { - TYPE_KCLX_ENUM_MAPPING[t._ast_type]: { - "target": self.expr(t.target), - "value": self.expr(t.value), - } - } - } - ) - return data - - def walk_AssignStmt(self, t: ast.AssignStmt): - data = self.ast_meta_to_dict(t) - data.update( - { - KCLX_NODE_FIELD: { - TYPE_KCLX_ENUM_MAPPING[t._ast_type]: { - "targets": self.exprs(t.targets), - "value": self.expr(t.value, True), - "type_annotation": { - KCLX_NODE_FIELD: t.type_annotation, - **self.ast_meta_to_dict(t), - } - if t.type_annotation - else None, - } - } - } - ) - return data - - def walk_AugAssignStmt(self, t: ast.AugAssignStmt): - data = self.ast_meta_to_dict(t) - data.update( - { - KCLX_NODE_FIELD: { - TYPE_KCLX_ENUM_MAPPING[t._ast_type]: { - "target": self.expr(t.target), - "value": self.expr(t.value, True), - "op": AUG_OP_MAPPING[t.op], - } - } - } - ) - return data - - def walk_AssertStmt(self, t: ast.AssertStmt): - data = self.ast_meta_to_dict(t) - data.update( - { - KCLX_NODE_FIELD: { - TYPE_KCLX_ENUM_MAPPING[t._ast_type]: { - "test": self.expr(t.test, True), - "if_cond": self.expr(t.if_cond, True), - "msg": self.expr(t.msg, True), - } - } - } - ) - return data - - def walk_IfStmt(self, t: ast.IfStmt): - data = self.ast_meta_to_dict(t) - elif_stmt = None - if t.elif_cond and t.elif_body: - elif_stmt = ast.IfStmt() - elif_stmt.set_ast_position(t) - elif_stmt.cond = t.elif_cond[0] - elif_stmt.body = t.elif_body[0] - elif_stmt.elif_cond = t.elif_cond[1:] - elif_stmt.elif_body = t.elif_body[1:] - elif_stmt.else_body = t.else_body - data.update( - { - KCLX_NODE_FIELD: { - TYPE_KCLX_ENUM_MAPPING[t._ast_type]: { - "cond": self.expr(t.cond, True), - "body": self.stmts(t.body), - "orelse": self.stmts([elif_stmt]) - if elif_stmt - else self.stmts(t.else_body), - } - } - } - ) - return data - - def walk_ImportStmt(self, t: ast.ImportStmt): - data = self.ast_meta_to_dict(t) - data.update( - { - KCLX_NODE_FIELD: { - TYPE_KCLX_ENUM_MAPPING[t._ast_type]: { - "path": t.path, - "rawpath": t.rawpath, - "name": t.name, - "asname": t.asname, - } - } - } - ) - return data - - def walk_SchemaIndexSignature(self, t: ast.SchemaIndexSignature): - data = self.ast_meta_to_dict(t) - data.update( - { - KCLX_NODE_FIELD: { - "key_name": t.key_name, - "value": self.expr(t.value, True), - "key_type": { - KCLX_NODE_FIELD: t.key_type, - **self.ast_meta_to_dict(t), - }, - "value_type": { - KCLX_NODE_FIELD: t.value_type, - **self.ast_meta_to_dict(t.value_type_node), - }, - "any_other": t.any_other, - } - } - ) - return data - - def walk_SchemaAttr(self, t: ast.SchemaAttr): - data = self.ast_meta_to_dict(t) - data.update( - { - KCLX_NODE_FIELD: { - TYPE_KCLX_ENUM_MAPPING[t._ast_type]: { - "doc": t.doc, - "name": { - KCLX_NODE_FIELD: t.name, - **self.ast_meta_to_dict(t), - }, - "type_str": { - KCLX_NODE_FIELD: t.type_str, - **self.ast_meta_to_dict(t), - }, - "value": self.expr(t.value, True), - "op": {"Bin": BIN_OP_MAPPING[t.op]} - if isinstance(t.op, ast.BinOp) - else ( - {"Aug": AUG_OP_MAPPING[t.op]} - if isinstance(t.op, ast.AugOp) - else None - ), - "is_optional": t.is_optional, - "decorators": self.exprs(t.decorators), - } - } - } - ) - return data - - def walk_SchemaStmt(self, t: ast.SchemaStmt): - data = self.ast_meta_to_dict(t) - data.update( - { - KCLX_NODE_FIELD: { - TYPE_KCLX_ENUM_MAPPING[t._ast_type]: { - "doc": t.doc, - "name": { - KCLX_NODE_FIELD: t.name, - **self.ast_meta_to_dict(t.name_node), - }, - "parent_name": self.expr(t.parent_name), - "for_host_name": self.expr(t.for_host_name), - "is_mixin": t.is_mixin, - "is_protocol": t.is_protocol, - "args": self.expr(t.args), - "mixins": self.exprs(t.mixins), - "body": self.stmts(t.body), - "decorators": self.exprs(t.decorators), - "checks": self.exprs(t.checks), - "index_signature": self.stmt(t.index_signature), - } - } - } - ) - return data - - def walk_RuleStmt(self, t: ast.RuleStmt): - data = self.ast_meta_to_dict(t) - data.update( - { - KCLX_NODE_FIELD: { - TYPE_KCLX_ENUM_MAPPING[t._ast_type]: { - "doc": t.doc, - "name": { - KCLX_NODE_FIELD: t.name, - **self.ast_meta_to_dict(t.name_node), - }, - "parent_rules": self.exprs(t.parent_rules), - "for_host_name": self.expr(t.for_host_name), - "args": self.expr(t.args), - "decorators": self.exprs(t.decorators), - "checks": self.exprs(t.checks), - } - } - } - ) - return data - - def walk_Identifier(self, t: ast.Identifier): - data = self.ast_meta_to_dict(t) - data.update( - { - KCLX_NODE_FIELD: { - "names": t.names, - "pkgpath": t.names[0] - if t.names[0].startswith("@") - else (t.pkgpath or ""), - "ctx": EXPR_CTX_MAPPING.get(t.ctx, "Load"), - } - } - ) - return data - - def walk_UnaryExpr(self, t: ast.UnaryExpr): - data = self.ast_meta_to_dict(t) - data.update( - { - KCLX_NODE_FIELD: { - "op": UNARY_OP_MAPPING[t.op], - "operand": self.expr(t.operand, True), - } - } - ) - return data - - def walk_BinaryExpr(self, t: ast.BinaryExpr): - data = self.ast_meta_to_dict(t) - data.update( - { - KCLX_NODE_FIELD: { - "left": self.expr(t.left, True), - "op": {"Bin": BIN_OP_MAPPING[t.op]} - if isinstance(t.op, ast.BinOp) - else {"Cmp": CMP_OP_MAPPING[t.op]}, - "right": self.expr(t.right, True), - } - } - ) - return data - - def walk_IfExpr(self, t: ast.IfExpr): - data = self.ast_meta_to_dict(t) - data.update( - { - KCLX_NODE_FIELD: { - "body": self.expr(t.body, True), - "cond": self.expr(t.cond, True), - "orelse": self.expr(t.orelse, True), - } - } - ) - return data - - def walk_SelectorExpr(self, t: ast.SelectorExpr): - data = self.ast_meta_to_dict(t) - data.update( - { - KCLX_NODE_FIELD: { - "value": self.expr(t.value, True), - "attr": self.expr(t.attr), - "ctx": EXPR_CTX_MAPPING[t.ctx], - "has_question": t.has_question, - } - } - ) - return data - - def walk_CallExpr(self, t: ast.CallExpr): - data = self.ast_meta_to_dict(t) - data.update( - { - KCLX_NODE_FIELD: { - "func": self.expr(t.func, True), - "args": self.exprs(t.args, True), - "keywords": self.exprs(t.keywords), - } - } - ) - return data - - def walk_ParenExpr(self, t: ast.ParenExpr): - data = self.ast_meta_to_dict(t) - data.update( - { - KCLX_NODE_FIELD: { - "expr": self.expr(t.expr, True), - } - } - ) - return data - - def walk_QuantExpr(self, t: ast.QuantExpr): - data = self.ast_meta_to_dict(t) - data.update( - { - KCLX_NODE_FIELD: { - "target": self.expr(t.target, True), - "variables": self.exprs(t.variables), - "op": QUANT_OP_MAPPING[t.op], - "test": self.expr(t.test, True), - "if_cond": self.expr(t.if_cond, True), - "ctx": EXPR_CTX_MAPPING[t.ctx], - } - } - ) - return data - - def walk_ListExpr(self, t: ast.ListExpr): - data = self.ast_meta_to_dict(t) - data.update( - { - KCLX_NODE_FIELD: { - "elts": self.exprs(t.elts, True), - "ctx": EXPR_CTX_MAPPING[t.ctx], - } - } - ) - return data - - def walk_ListIfItemExpr(self, t: ast.ListIfItemExpr): - data = self.ast_meta_to_dict(t) - data.update( - { - KCLX_NODE_FIELD: { - "if_cond": self.expr(t.if_cond, True), - "exprs": self.exprs(t.exprs, True), - "orelse": self.expr(t.orelse, True), - } - } - ) - return data - - def walk_ListComp(self, t: ast.ListComp): - data = self.ast_meta_to_dict(t) - data.update( - { - KCLX_NODE_FIELD: { - "elt": self.expr(t.elt, True), - "generators": self.exprs(t.generators), - } - } - ) - return data - - def walk_StarredExpr(self, t: ast.StarredExpr): - data = self.ast_meta_to_dict(t) - data.update( - { - KCLX_NODE_FIELD: { - "value": self.expr(t.value, True), - "ctx": EXPR_CTX_MAPPING[t.ctx], - } - } - ) - return data - - def walk_DictComp(self, t: ast.DictComp): - data = self.ast_meta_to_dict(t) - data.update( - { - KCLX_NODE_FIELD: { - "entry": { - "key": self.expr(t.key, True), - "value": self.expr(t.value, True), - "operation": CONFIG_ENTRY_OP_MAPPING[t.operation], - "insert_index": -1, - }, - "generators": self.exprs(t.generators), - } - } - ) - return data - - def walk_ConfigIfEntryExpr(self, t: ast.ConfigIfEntryExpr): - data = self.ast_meta_to_dict(t) - keys = [] - values = [] - for key, value, operation in zip(t.keys, t.values, t.operations): - is_nest_key = isinstance(key, ast.Identifier) and len(key.names) > 1 - if is_nest_key: - names = key.names - key.names = [key.names[0]] - for i, name in enumerate(names[1:][::-1]): - is_last_item = i == 0 - name_node = ast.Identifier( - names=[name], line=key.line, column=key.column - ) - name_node.filename = t.filename - entry_value = ast.ASTFactory.get_ast_configentry( - name_node, - value, - operation if is_last_item else ast.ConfigEntryOperation.UNION, - t.filename, - ) - value = ast.ConfigExpr(line=key.line, column=key.column) - value.filename = t.filename - value.items.append(entry_value) - keys.append(key) - values.append(value) - t.keys = keys - t.values = values - items = [] - for key, value, op in zip(t.keys, t.values, t.operations): - items.append( - ast.ConfigEntry( - line=key.line if key else value.line, - column=key.column if key else value.column, - key=key, - value=value, - operation=op, - ) - ) - data.update( - { - KCLX_NODE_FIELD: { - "if_cond": self.expr(t.if_cond, True), - "items": self.exprs(items), - "orelse": self.expr(t.orelse, True), - } - } - ) - return data - - def walk_CompClause(self, t: ast.CompClause): - data = self.ast_meta_to_dict(t) - data.update( - { - KCLX_NODE_FIELD: { - "targets": self.exprs(t.targets), - "iter": self.expr(t.iter, True), - "ifs": self.exprs(t.ifs, True), - } - } - ) - return data - - def walk_SchemaExpr(self, t: ast.SchemaExpr): - data = self.ast_meta_to_dict(t) - data.update( - { - KCLX_NODE_FIELD: { - "name": self.expr(t.name), - "args": self.exprs(t.args, True), - "kwargs": self.exprs(t.kwargs), - "config": self.expr(t.config, True), - } - } - ) - return data - - def walk_ConfigExpr(self, t: ast.ConfigExpr): - data = self.ast_meta_to_dict(t) - data.update( - { - KCLX_NODE_FIELD: { - "items": self.exprs(t.items), - } - } - ) - return data - - def walk_ConfigEntry(self, t: ast.ConfigEntry): - # Unpack the nest var form `a.b.c = 1` to `a: {b: {c = 1}}` - is_nest_key = isinstance(t.key, ast.Identifier) and len(t.key.names) > 1 - if is_nest_key: - names = t.key.names - value = t.value - t.key.names = [t.key.names[0]] - for i, name in enumerate(names[1:][::-1]): - is_last_item = i == 0 - name_node = ast.Identifier( - names=[name], line=t.key.line, column=t.key.column - ) - name_node.filename = t.filename - entry_value = ast.ASTFactory.get_ast_configentry( - name_node, - value, - t.operation if is_last_item else ast.ConfigEntryOperation.UNION, - t.filename, - ) - value = ast.ConfigExpr(line=t.key.line, column=t.key.column) - value.filename = t.filename - value.items.append(entry_value) - t.value = value - t.operation = ast.ConfigEntryOperation.UNION - data = self.ast_meta_to_dict(t) - data.update( - { - KCLX_NODE_FIELD: { - "key": self.expr(t.key, True), - "value": self.expr(t.value, True), - "operation": CONFIG_ENTRY_OP_MAPPING[ - ast.ConfigEntryOperation.UNION if is_nest_key else t.operation - ], - "insert_index": t.insert_index, - } - } - ) - return data - - def walk_CheckExpr(self, t: ast.CheckExpr): - data = self.ast_meta_to_dict(t) - data.update( - { - KCLX_NODE_FIELD: { - "test": self.expr(t.test, True), - "if_cond": self.expr(t.if_cond, True), - "msg": self.expr(t.msg, True), - } - } - ) - return data - - def walk_LambdaExpr(self, t: ast.LambdaExpr): - """ast.AST: LambdaExpr - - Parameters - ---------- - - args: Optional[Arguments] - - return_type_str: Optional[str] - - return_type_node: Optional[Type] - - body: List[Stmt] - """ - data = self.ast_meta_to_dict(t) - data.update( - { - KCLX_NODE_FIELD: { - "args": self.expr(t.args), - "return_type_str": t.return_type_str, - "body": self.stmts(t.body), - } - } - ) - return data - - def walk_Decorator(self, t: ast.Decorator): - name = self.expr(t.name, True) - call_expr = self.expr(t.args) - if call_expr: - call_expr[KCLX_NODE_FIELD]["func"] = name - return call_expr - else: - data = self.ast_meta_to_dict(t) - data.update( - { - KCLX_NODE_FIELD: { - "func": name, - "args": [], - "keywords": [], - } - } - ) - return data - - def walk_Subscript(self, t: ast.Subscript): - data = self.ast_meta_to_dict(t) - data.update( - { - KCLX_NODE_FIELD: { - "value": self.expr(t.value, True), - "index": self.expr(t.index, True), - "lower": self.expr(t.lower, True), - "upper": self.expr(t.upper, True), - "step": self.expr(t.step, True), - "ctx": EXPR_CTX_MAPPING[t.ctx], - "has_question": t.has_question, - } - } - ) - return data - - def walk_Keyword(self, t: ast.Keyword): - data = self.ast_meta_to_dict(t) - data.update( - { - KCLX_NODE_FIELD: { - "arg": self.expr(t.arg), - "value": self.expr(t.value, True), - } - } - ) - return data - - def walk_Arguments(self, t: ast.Arguments): - data = self.ast_meta_to_dict(t) - data.update( - { - KCLX_NODE_FIELD: { - "args": self.exprs(t.args), - "defaults": self.exprs(t.defaults, True), - "type_annotation_list": [ - {KCLX_NODE_FIELD: tpe_str, **self.ast_meta_to_dict(t)} - if tpe_str - else None - for tpe_str, tpe_node in zip( - t.type_annotation_list, t.type_annotation_node_list - ) - ], - } - } - ) - return data - - def walk_Compare(self, t: ast.Compare): - data = self.ast_meta_to_dict(t) - data.update( - { - KCLX_NODE_FIELD: { - "left": self.expr(t.left, True), - "ops": [CMP_OP_MAPPING[op] for op in t.ops], - "comparators": self.exprs(t.comparators, True), - } - } - ) - return data - - def walk_JoinedString(self, t: ast.JoinedString): - data = self.ast_meta_to_dict(t) - data.update( - { - KCLX_NODE_FIELD: { - "is_long_string": t.is_long_string, - "values": self.exprs(t.values, True), - "raw_value": t.raw_value, - } - } - ) - return data - - def walk_FormattedValue(self, t: ast.FormattedValue): - data = self.ast_meta_to_dict(t) - data.update( - { - KCLX_NODE_FIELD: { - "is_long_string": t.is_long_string, - "value": self.expr(t.value, True), - "format_spec": t.format_spec, - } - } - ) - return data - - def walk_NumberLit(self, t: ast.NumberLit): - data = self.ast_meta_to_dict(t) - data.update( - { - KCLX_NODE_FIELD: { - "binary_suffix": t.binary_suffix, - "value": {"Int": t.value} - if isinstance(t.value, int) - else {"Float": t.value}, - } - } - ) - return data - - def walk_StringLit(self, t: ast.StringLit): - data = self.ast_meta_to_dict(t) - data.update( - { - KCLX_NODE_FIELD: { - "is_long_string": t.is_long_string, - "raw_value": t.raw_value or t.value, - "value": t.value, - } - } - ) - return data - - def walk_NameConstantLit(self, t: ast.NameConstantLit): - data = self.ast_meta_to_dict(t) - value = "Undefined" - value = "None" if t.value is None else value - value = "True" if t.value is True else value - value = "False" if t.value is False else value - data.update({KCLX_NODE_FIELD: {"value": value}}) - return data - - def walk_Comment(self, t: ast.Comment): - data = self.ast_meta_to_dict(t) - data.update({KCLX_NODE_FIELD: {"text": t.text}}) - return data - - -def transform_ast_to_kclx_ast_json_str(program: ast.Program) -> str: - check_number_lit_range(program) - for pkgpath in program.pkgs: - for i, module in enumerate(program.pkgs[pkgpath]): - program.pkgs[pkgpath][i] = KCLxASTTransformer().walk_Module(module) - return program.to_json(indent=None) - - -def check_number_lit_range(program: ast.Program): - strict_range_check = kclvm.config.strict_range_check - check_bit = 32 if strict_range_check else 64 - int_min = kcl_info.INT32_MIN if strict_range_check else kcl_info.INT64_MIN - int_max = kcl_info.INT32_MAX if strict_range_check else kcl_info.INT64_MAX - float_min = kcl_info.FLOAT32_MIN if strict_range_check else kcl_info.FLOAT64_MIN - float_max = kcl_info.FLOAT32_MAX if strict_range_check else kcl_info.FLOAT64_MAX - - def walk_lit(t: ast.AST) -> typing.Optional[typing.Callable]: - if isinstance(t, (ast.NumberLit)): - numberLit = typing.cast(ast.NumberLit, t) - value = numberLit.value - - if isinstance(value, int): - if not (int_min <= value <= int_max): - kcl_error.report_exception( - err_type=kcl_error.ErrType.IntOverflow_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=numberLit.filename, line_no=numberLit.line - ) - ], - arg_msg=kcl_error.INT_OVER_FLOW_MSG.format( - str(value), check_bit - ), - ) - elif isinstance(value, float): - abs_var = abs(value) - if 0 < abs_var < float_min: - kcl_error.report_exception( - err_type=kcl_error.ErrType.FloatUnderflow_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=numberLit.filename, line_no=numberLit.line - ) - ], - arg_msg=kcl_error.FLOAT_UNDER_FLOW_MSG.format( - str(value), check_bit - ), - ) - elif abs_var > float_max: - kcl_error.report_exception( - err_type=kcl_error.ErrType.FloatOverflow_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=numberLit.filename, line_no=numberLit.line - ) - ], - arg_msg=kcl_error.FLOAT_OVER_FLOW_MSG.format( - str(value), check_bit - ), - ) - - return walk_lit - - for pkgpath in program.pkgs: - for i, module in enumerate(program.pkgs[pkgpath]): - ast.WalkTree(module, walk_lit) diff --git a/internal/kclvm_py/internal/log/__init__.py b/internal/kclvm_py/internal/log/__init__.py deleted file mode 100644 index dccdd4668..000000000 --- a/internal/kclvm_py/internal/log/__init__.py +++ /dev/null @@ -1,9 +0,0 @@ -# Copyright 2021 The KCL Authors. All rights reserved. - -from .write_out import write_out, write_log, indent_log - -__all__ = [ - "write_out", - "write_log", - "indent_log", -] diff --git a/internal/kclvm_py/internal/log/write_out.py b/internal/kclvm_py/internal/log/write_out.py deleted file mode 100644 index 62a050c93..000000000 --- a/internal/kclvm_py/internal/log/write_out.py +++ /dev/null @@ -1,30 +0,0 @@ -#! /usr/bin/env python3 - -import kclvm.config - - -def write_out(inputs): - outputs = inputs - if kclvm.config.output: - with open(kclvm.config.output, "w") as f: - f.write(outputs) - else: - print(outputs, end="") - - -LOG_INDENT_STRING = " " -log_indent = 0 - - -def write_log(message, level=1): - """Write log message whose level is no less than the verbosity level""" - if kclvm.config.verbose >= level: - for _ in range(log_indent): - print(LOG_INDENT_STRING, end="") - print(message) - - -def indent_log(step=1): - """Adjust the indentation level of log messages""" - global log_indent - log_indent += step diff --git a/internal/kclvm_py/internal/util/__init__.py b/internal/kclvm_py/internal/util/__init__.py deleted file mode 100644 index f6bd5207a..000000000 --- a/internal/kclvm_py/internal/util/__init__.py +++ /dev/null @@ -1,34 +0,0 @@ -# Copyright 2021 The KCL Authors. All rights reserved. - -from .util import dotdict, hash, merge_option_same_keys, safe_call -from .check_utils import ( - check_allow_none, - check_all_allow_none, - check_not_none, - check_all_not_none, - PreCheck, - PostCheck, - CheckRules, - CHECK_MODE, - alert_internal_bug, - check_type_not_none, - check_type_allow_none, -) - -__all__ = [ - "dotdict", - "hash", - "merge_option_same_keys", - "check_allow_none", - "check_all_allow_none", - "check_not_none", - "check_all_not_none", - "PreCheck", - "PostCheck", - "CheckRules", - "CHECK_MODE", - "alert_internal_bug", - "check_type_not_none", - "check_type_allow_none", - "safe_call", -] diff --git a/internal/kclvm_py/internal/util/check_utils.py b/internal/kclvm_py/internal/util/check_utils.py deleted file mode 100644 index 421008b30..000000000 --- a/internal/kclvm_py/internal/util/check_utils.py +++ /dev/null @@ -1,302 +0,0 @@ -""" -The `check_utils` file mainly contains some methods for defensive programming. - -Method `PreCheck` can be used for pre-checking the method, -mainly to verify whether the incoming parameters of the method meet conditions. - -Method `PostCheck` can be used for post-checking the method, -mainly to verify whether the return of the method meets conditions. - -Method `PostSimpleExprCheck` can be used for post-checking the method, -Compared with `PostCheck`, `PostSimpleExprCheck` supports verifying -some simple relationship between the return value and the input parameters - -For example: - -# Check whether the type of incoming parameter "a" is int -@PreCheck((lambda v: isinstance(v, int)), "a") -# Check whether the type of incoming parameter "b" is int -@PreCheck((lambda v: isinstance(v, int)), "b") -# Check whether the type of return value is int -@PostCheck((lambda v: isinstance(v, int))) -# Check whether the return value is equal to the sum of input parameters -@PostSimpleExprCheck((lambda inputs, result: result == inputs["a"] + inputs["b"]), ["a", "b"]) -def add(a, b): - return a + b - -Class `CheckRules` and some other global methods are built-in check rules -that can be used in `PreCheck` and `PostCheck`. - -:copyright: Copyright 2020 The KCL Authors. All rights reserved. -""" -import locale -import typing -import functools -from inspect import Signature -from typing import Callable, Any, List - -# CHECK_MODE is a switch, -# you can return the parameters directly by turning the CHECK_MODE = False - -CHECK_MODE = False - - -class CheckRules: - @staticmethod - def check_list_len_equal(all_lists: list): - if not CHECK_MODE: - return - assert all_lists - assert isinstance(all_lists, list) - assert all( - result is True - for result in [isinstance(list_inner, list) for list_inner in all_lists] - ) - assert all( - result == len(all_lists[0]) - for result in [len(list_inner) for list_inner in all_lists] - ) - - @staticmethod - def check_locale(lang: str): - if not CHECK_MODE: - return True - LOCALE_LIST = list(locale.locale_alias.keys()) - if not lang or not isinstance(lang, str) or lang not in LOCALE_LIST: - return False - return True - - @staticmethod - def check_type_not_none(item, *tpes) -> bool: - if CHECK_MODE: - return item is not None and isinstance(item, tpes) - return True - - @staticmethod - def check_type_allow_none(item, *tpes) -> bool: - if CHECK_MODE: - return item is None or isinstance(item, tpes) - return True - - @staticmethod - def check_list_item_type_allow_none(item, *tpes) -> bool: - if CHECK_MODE: - check_all_allow_none(list, item, *tpes) - return True - - @staticmethod - def check_int_range_allow_none(target: int, low: int, high: int) -> bool: - if CHECK_MODE: - if target is None: - return True - check_type_not_none(target, int) - check_type_not_none(low, int) - check_type_not_none(high, int) - return target in range(low, high) - else: - return True - - @staticmethod - def check_str_len_not_none(target: str, length: int) -> bool: - if CHECK_MODE: - check_type_not_none(target, str) - check_type_not_none(length, int) - return len(target) == length - else: - return True - - @staticmethod - def check_str_len_allow_none(target: str, length: int) -> bool: - if CHECK_MODE: - if target is None: - return True - check_type_not_none(target, str) - check_type_not_none(length, int) - return len(target) == length - else: - return True - - -def check_allow_none(node, tpe): - if node and CHECK_MODE: - assert isinstance(node, tpe) - return typing.cast(tpe, node) - - -def check_all_allow_none(set_tpe: typing.Type, nodes, *item_tpes): - if nodes and CHECK_MODE: - assert isinstance(nodes, set_tpe) - assert isinstance(nodes, (list, tuple)) and all( - isinstance(item, item_tpes) for item in nodes - ) - return typing.cast(set_tpe, nodes) - - -def check_not_none(node, *tpes): - if CHECK_MODE: - assert node and isinstance(node, tpes) - return typing.cast(tpes, node) - - -def check_all_not_none(set_tpe: typing.Type, nodes, *item_tpes): - if CHECK_MODE: - assert nodes and isinstance(nodes, set_tpe) - assert isinstance(nodes, (list, tuple)) and all( - isinstance(item, item_tpes) for item in nodes - ) - return typing.cast(set_tpe, nodes) - - -def check_type_allow_none(node, *tpes): - if node and CHECK_MODE: - assert isinstance(node, tpes) - return node - - -def check_type_not_none(node, *tpes): - if CHECK_MODE: - assert node is not None and isinstance(node, tpes) - return node - - -def alert_internal_bug(): - if CHECK_MODE: - assert False, "Here is unreachable unless a bug occurs" - - -def PreCheck(condition: Callable[[Any], bool], param_name: str, param_pos: int = None): - def conditioner(func): - @functools.wraps(func) - def check_condition(*args, **kwargs): - if not CHECK_MODE: - return func(*args, **kwargs) - check_type_not_none(condition, Callable) - check_type_not_none(func, Callable) - check_type_not_none(CHECK_MODE, bool) - check_type_not_none(param_name, str) - check_type_allow_none(param_pos, int) - param_names_list = [ - i[0] - for i in Signature.from_callable(func).parameters.items() - if len(i) > 0 - ] - if param_name not in param_names_list: - raise AssertionError( - f"Pre-Condition failed: " - f"There is no parameter named {param_name} in function {func.__name__}. " - f"The function parameters list: {param_names_list}." - ) - try: - param_value = kwargs[ - param_name - ] # if the param in kwargs for the function - except KeyError: - if not CheckRules.check_int_range_allow_none( - param_pos, 0, len(param_names_list) - ): - raise AssertionError( - f"Pre-Condition failed: param_pos: {param_pos} is out of range. " - f"There are only {len(param_names_list)} parameters in {func.__name__}" - ) - if param_names_list.index(param_name) < len( - args - ): # if the param in args for the function - param_value = ( - args[param_pos] - if param_pos - else args[param_names_list.index(param_name)] - ) - else: - param_value = None - - if condition(param_value): - return func(*args, **kwargs) - else: - raise AssertionError( - f"Pre-Condition failed: {func.__name__}({param_name} = {param_value}), " - f"Check Condition: {condition.__name__}" - ) - - return check_condition - - return conditioner - - -def PostCheck(condition: Callable[[Any], bool]): - def conditioner(func): - @functools.wraps(func) - def check_condition(*args, **kwargs): - if not CHECK_MODE: - return func(*args, **kwargs) - check_type_not_none(condition, Callable) - check_type_not_none(func, Callable) - check_type_not_none(CHECK_MODE, bool) - result = func(*args, **kwargs) - if condition(result): - return result - else: - raise AssertionError( - f"Post-Condition failed: {func.__name__} with returned {result}," - f"Check Condition: {condition.__name__}" - ) - - return check_condition - - return conditioner - - -def PostSimpleExprCheck( - condition: Callable[[Any, Any], bool], dependent_params: List[str] -): - def conditioner(func): - @functools.wraps(func) - def check_condition(*args, **kwargs): - if not CHECK_MODE: - return func(*args, **kwargs) - check_type_not_none(condition, Callable) - check_type_not_none(func, Callable) - check_type_not_none(CHECK_MODE, bool) - check_all_not_none(list, dependent_params, str) - sig_params = {} - param_names_list = [ - i[0] - for i in Signature.from_callable(func).parameters.items() - if len(i) > 0 - ] - for (k, v) in Signature.from_callable(func).parameters.items(): - sig_params[k] = (k, v) - inputs = {} - - for param in dependent_params: - try: - inputs[param] = kwargs[ - param - ] # if the param in kwargs for the function - except KeyError: - try: - inputs[param] = args[ # if the param in args for the function - param_names_list.index(sig_params[param][0]) - ] - except IndexError: - assert ( - len(sig_params[param]) > 0 - ) # if the param in the function has default value - inputs[param] = sig_params[param][1].default - except KeyError: - raise AssertionError( - f"Post-Condition failed: " - f"There is no parameter named {param} in function {func.__name__}. " - f"The function parameters list: {param_names_list}." - ) - - result = func(*args, **kwargs) - if condition(inputs, result): - return result - else: - raise AssertionError( - f"Post-condition failed: {func.__name__} with inputs: {inputs}, returned {result}" - ) - - return check_condition - - return conditioner diff --git a/internal/kclvm_py/internal/util/util.py b/internal/kclvm_py/internal/util/util.py deleted file mode 100644 index 15ce423d7..000000000 --- a/internal/kclvm_py/internal/util/util.py +++ /dev/null @@ -1,32 +0,0 @@ -import hashlib -import typing - - -class dotdict(dict): - """dot.notation access to dictionary attributes""" - - __getattr__ = dict.get - __setattr__ = dict.__setitem__ - __delattr__ = dict.__delitem__ - - -def hash(input_str): - return hashlib.md5(input_str.encode("utf-8")).hexdigest() - - -def merge_option_same_keys(args): - """ - merge kcl -D and -Y argument with the same keys - """ - if not args: - return {} - return {k: v for k, v in args} - - -def safe_call(fn: typing.Callable, *args, **kwargs) -> (typing.Any, Exception): - result = None - try: - result = fn(*args, **kwargs) - return result, None - except Exception as err: - return result, err diff --git a/internal/kclvm_py/kcl/README.md b/internal/kclvm_py/kcl/README.md deleted file mode 100644 index caa7ca22b..000000000 --- a/internal/kclvm_py/kcl/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# KCL - -This module provides the K Configuration Language definitions. diff --git a/internal/kclvm_py/kcl/__init__.py b/internal/kclvm_py/kcl/__init__.py deleted file mode 100644 index d74aaf8ad..000000000 --- a/internal/kclvm_py/kcl/__init__.py +++ /dev/null @@ -1 +0,0 @@ -# Copyright 2021 The KCL Authors. All rights reserved. diff --git a/internal/kclvm_py/kcl/ast/0_gen.go b/internal/kclvm_py/kcl/ast/0_gen.go deleted file mode 100644 index 1e0899ddc..000000000 --- a/internal/kclvm_py/kcl/ast/0_gen.go +++ /dev/null @@ -1,5 +0,0 @@ -// Copyright 2020 The KCL Authors. All rights reserved. - -//go:generate go run aa_gen_lark_token.go - -package ast diff --git a/internal/kclvm_py/kcl/ast/Makefile b/internal/kclvm_py/kcl/ast/Makefile deleted file mode 100644 index 4c3f56a72..000000000 --- a/internal/kclvm_py/kcl/ast/Makefile +++ /dev/null @@ -1,6 +0,0 @@ -# Copyright 2020 The KCL Authors. All rights reserved. - -gen: - go run aa_gen_lark_token.go - -clean: diff --git a/internal/kclvm_py/kcl/ast/__init__.py b/internal/kclvm_py/kcl/ast/__init__.py deleted file mode 100644 index 52c2067b8..000000000 --- a/internal/kclvm_py/kcl/ast/__init__.py +++ /dev/null @@ -1,40 +0,0 @@ -"""The `ast` module mainly defines the abstract nodes of all -KCL syntax and the corresponding supporting tools that make -working with the trees simpler. - -The syntax tree can be generated through functions such as -ParseFile/LoadProgram, and the result will be a tree of -objects whose classes all inherit from `ast.AST`. - -In addition to the grammar model itself, the `ast` module -also defines the priority of all KCL operators, as well as -the walker and transformer modules that help process the AST. -The former is used to better traverse the AST, and the latter -is used to modify the existing AST more quickly. - -:copyright: Copyright 2020 The KCL Authors. All rights reserved. -""" - -from .ast import * -from .precedence import OP_PREC_MAP, precedence -from .lark_token import TokenValue -from .walker import TreeWalker, WalkTree -from .transformer import TreeTransformer -from .fields_map import iter_fields - -__all__ = [ - "ast", - "BinOp", - "CmpOp", - "UnaryOp", - "AugOp", - "ExprContext", - "OP_PREC_MAP", - "precedence", - "TokenValue", - "TreeWalker", - "WalkTree", - "TreeTransformer", - "iter_fields", - "ASTFactory", -] diff --git a/internal/kclvm_py/kcl/ast/aa_gen_lark_token.go b/internal/kclvm_py/kcl/ast/aa_gen_lark_token.go deleted file mode 100644 index 6405244aa..000000000 --- a/internal/kclvm_py/kcl/ast/aa_gen_lark_token.go +++ /dev/null @@ -1,152 +0,0 @@ -// Copyright 2020 The KCL Authors. All rights reserved. - -//go:build ignore -// +build ignore - -package main - -import ( - "bytes" - "flag" - "fmt" - "io/ioutil" - "log" - "regexp" - "strings" - "unicode" -) - -var ( - flagFilename = flag.String("file", "../grammar/kcl.lark", "set lark file") - flagOutput = flag.String("output", "lark_token.py", "set output file") -) - -func main() { - flag.Parse() - - larkData, err := ioutil.ReadFile(*flagFilename) - if err != nil { - log.Fatal(err) - } - - var buf = new(bytes.Buffer) - - fmt.Fprintln(buf, "# Copyright 2020 The KCL Authors. All rights reserved.") - fmt.Fprintln(buf) - - fmt.Fprintln(buf, "# Auto generated by {gen_lark_token.go & kcl.lark}; DO NOT EDIT!!!") - fmt.Fprintln(buf) - fmt.Fprintln(buf) - - fmt.Fprintln(buf, "class LarkToken:") - fmt.Fprintln(buf) - - var names, comments = getLarkNames(string(larkData)) - - var rule_list []string - var tok_list []string - - for _, s := range names { - if unicode.IsLower(rune(s[0])) { - rule_list = append(rule_list, s) - } else { - tok_list = append(tok_list, s) - } - } - - fmt.Fprintf(buf, " # kcl.lark rules and tokens (len=%d)\n", len(names)) - for i, s := range names { - if strings.HasPrefix(comments[i], "type: ") { - comments[i] = strings.Replace(comments[i], "type: ", "@type: ", 1) - } - fmt.Fprintf(buf, " L_%s = \"%s\" # %s ...\n", s, s, comments[i]) - } - fmt.Fprintln(buf) - - //fmt.Fprintf(buf, " # Lark rule alias name (=> f'LL_{rule_name.upper()}'\n") - //for _, s := range rule_list { - // fmt.Fprintf(buf, " LL_%s = L_%s\n", strings.ToUpper(s), s) - //} - //fmt.Fprintln(buf) - - fmt.Fprintf(buf, " # kcl.lark tokens list (len=%d)\n", len(tok_list)) - - fmt.Fprintln(buf, " LL_token_list = [") - for _, s := range tok_list { - fmt.Fprintf(buf, " L_%s,\n", s) - } - fmt.Fprintln(buf, " ]") - - fmt.Fprintln(buf) - fmt.Fprintf(buf, " # kcl.lark rules list (len=%d)\n", len(rule_list)) - - fmt.Fprintln(buf, " LL_rule_list = [") - for _, s := range rule_list { - fmt.Fprintf(buf, " L_%s,\n", s) - } - fmt.Fprintln(buf, " ]") - - fmt.Fprintln(buf) - fmt.Fprintf(buf, " # kcl.lark tokens string value map\n") - fmt.Fprintln(buf, " LL_token_str_value_map = {") - for i, s := range names { - if unicode.IsUpper(rune(s[0])) { - if val := getTokenStrValue(comments[i]); val != "" { - fmt.Fprintf(buf, " L_%s: \"%s\",\n", s, val) - } - } - } - fmt.Fprintln(buf, " }") - - fmt.Fprintln(buf) - fmt.Fprintln(buf) - fmt.Fprintln(buf, "class TokenValue:") - for i, s := range names { - if unicode.IsUpper(rune(s[0])) { - if val := getTokenStrValue(comments[i]); val != "" { - fmt.Fprintf(buf, " %s = \"%s\"\n", s, val) - } - } - } - - err = ioutil.WriteFile(*flagOutput, buf.Bytes(), 0666) - if err != nil { - log.Fatal(err) - } -} - -func getLarkNames(larkData string) (names []string, comments []string) { - lines := strings.Split(larkData, "\n") - for i, line := range lines { - line := strings.Trim(line, "? \t") - if matched, _ := regexp.MatchString(`^\w+(\.|:)`, line); matched { - if idx := strings.Index(line, ":"); idx > 0 { - line = line[:idx] - } - if idx := strings.Index(line, "."); idx > 0 { - line = line[:idx] - } - if line != "" { - names = append(names, line) - comments = append(comments, lines[i]) - } - } - } - return -} - -func getTokenStrValue(tok_comment string) string { - // FALSE: "False" ... - if idx := strings.Index(tok_comment, ":"); idx >= 0 { - tok_comment = tok_comment[idx+1:] - } - - // IMAG_NUMBER.2: /\d+j/i | FLOAT_NUMBER "j"i ... - tok_comment = strings.TrimSpace(tok_comment) - if s := tok_comment; s == "" || s[0] != '"' { - return "" - } - - tok_comment = strings.Trim(tok_comment, `'"`) - return tok_comment -} diff --git a/internal/kclvm_py/kcl/ast/ast.py b/internal/kclvm_py/kcl/ast/ast.py deleted file mode 100644 index 6edaa7cc6..000000000 --- a/internal/kclvm_py/kcl/ast/ast.py +++ /dev/null @@ -1,1639 +0,0 @@ -"""The `ast` file contains the definitions of all KCL AST nodes -and operators and all AST nodes are derived from the `AST` class. -The main structure of a KCL program is as follows: - -┌─────────────────────────────────────────────────────────────────┐ -│ Program │ -│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ -│ │ Main Package │ │ Package1 │ │ Package2 │ │ -│ │ ┌───────────┐ │ │ ┌───────────┐ │ │ ┌───────────┐ │ │ -│ │ │ Module1 │ │ │ │ Module1 │ │ │ │ Module1 │ │ │ -│ │ └───────────┘ │ │ └───────────┘ │ │ └───────────┘ │ │ -│ │ ┌───────────┐ │ │ ┌───────────┐ │ │ ┌───────────┐ │ │ -│ │ │ Module2 │ │ │ │ Module2 │ │ │ │ Module2 │ │ │ -│ │ └───────────┘ │ │ └───────────┘ │ │ └───────────┘ │ │ -│ │ ┌───────────┐ │ │ ┌───────────┐ │ │ ┌───────────┐ │ │ -│ │ │ ... │ │ │ │ ... │ │ │ │ ... │ │ │ -│ │ └───────────┘ │ │ └───────────┘ │ │ └───────────┘ │ │ -│ └─────────────────┘ └─────────────────┘ └─────────────────┘ │ -└─────────────────────────────────────────────────────────────────┘ - -A single KCL file represents a module, which records file information, -package path information, and module document information, which is -mainly composed of all the statements in the KCL file. - -The combination of multiple KCL files is regarded as a complete KCL -Program. For example, a single KCL file can be imported into KCL -files in other packages through statements such as import. Therefore, -the Program is composed of multiple modules, and each module is -associated with it. Corresponding to the package path. - -:note: When the definition of any AST node is modified or the AST node -is added/deleted, it is necessary to modify the corresponding processing -in the compiler and regenerate the walker code. -:copyright: Copyright 2020 The KCL Authors. All rights reserved. -""" - -import os -import json -import hashlib -import typing - -from enum import Enum -from abc import ABC -from typing import List, Optional, Union, Dict -from pathlib import PosixPath - -import kclvm.kcl.ast.lark_token as lark_token -import kclvm.kcl.ast as ast -import kclvm.internal.util.check_utils as check_utils - -from .lark_token import TokenValue - - -class CmdArgSpec: - """KCL command line argument spec, e.g. `kcl main.k -D name=value`""" - - def __init__(self, *, name: str = "", value: any = None): - self.name: str = name - self.value: any = value - - -class OverrideAction(Enum): - CREATE_OR_UPDATE = "CreateOrUpdate" - DELETE = "Delete" - - -class CmdOverrideSpec: - """KCL command line override spec, e.g. `kcl main.k -O pkgpath:path.to.field=field_value`""" - - def __init__( - self, - *, - pkgpath: str = "", - field_path: str = "", - field_value: str = "", - action: OverrideAction = OverrideAction.CREATE_OR_UPDATE, - ): - self.pkgpath: str = pkgpath - self.field_path: str = field_path - self.field_value: str = field_value - self.action: OverrideAction = action - - -class LarkToken(lark_token.LarkToken): - @staticmethod - def is_string(token: str): - return token in [ - LarkToken.L_STRING, - LarkToken.L_LONG_STRING, - ] - - @staticmethod - def is_int_number(token: str): - return token in [ - LarkToken.L_DEC_NUMBER, - LarkToken.L_HEX_NUMBER, - LarkToken.L_BIN_NUMBER, - LarkToken.L_OCT_NUMBER, - ] - - @staticmethod - def is_float_number(token: str): - return token == LarkToken.L_FLOAT_NUMBER - - @staticmethod - def is_name_constant(token: str): - return token in [ - LarkToken.L_TRUE, - LarkToken.L_FALSE, - LarkToken.L_NONE, - LarkToken.L_UNDEFINED, - ] - - @staticmethod - def get_token_value(token: str) -> str: - return LarkToken.LL_token_str_value_map[token] - - -class BinOp(Enum): - """BinOp is the set of all binary operators in KCL.""" - - Add = LarkToken.L_PLUS - Sub = LarkToken.L_MINUS - Mul = LarkToken.L_MULTIPLY - Div = LarkToken.L_DIVIDE - Mod = LarkToken.L_MOD - Pow = LarkToken.L_DOUBLE_STAR - LShift = LarkToken.L_SHIFT_LEFT - RShift = LarkToken.L_SHIFT_RIGHT - BitOr = LarkToken.L_OR - BitXor = LarkToken.L_XOR - BitAnd = LarkToken.L_AND - FloorDiv = LarkToken.L_DOUBLE_DIVIDE - As = LarkToken.L_AS - - And = LarkToken.L_L_AND # True and False - Or = LarkToken.L_L_OR # True or False - - @classmethod - def enum_value_list(cls) -> [str]: - return list(map(lambda c: c.value, cls)) - - @classmethod - def enum_key_list(cls) -> [str]: - return list(map(lambda c: c, cls)) - - -class AugOp(Enum): - Assign = LarkToken.L_ASSIGN - Add = LarkToken.L_COMP_PLUS - Sub = LarkToken.L_COMP_MINUS - Mul = LarkToken.L_COMP_MULTIPLY - Div = LarkToken.L_COMP_DIVIDE - Mod = LarkToken.L_COMP_MOD - Pow = LarkToken.L_COMP_DOUBLE_STAR - LShift = LarkToken.L_COMP_SHIFT_LEFT - RShift = LarkToken.L_COMP_SHIFT_RIGHT - BitOr = LarkToken.L_COMP_OR - BitXor = LarkToken.L_COMP_XOR - BitAnd = LarkToken.L_COMP_AND - FloorDiv = LarkToken.L_COMP_DOUBLE_DIVIDE - - @classmethod - def enum_value_list(cls) -> [str]: - return list(map(lambda c: c.value, cls)) - - @classmethod - def enum_key_list(cls) -> [str]: - return list(map(lambda c: c, cls)) - - -class UnaryOp(Enum): - UAdd = LarkToken.L_PLUS - USub = LarkToken.L_MINUS - Invert = LarkToken.L_NOT - Not = LarkToken.L_L_NOT - - @classmethod - def enum_value_list(cls) -> [str]: - return list(map(lambda c: c.value, cls)) - - @classmethod - def enum_key_list(cls) -> [str]: - return list(map(lambda c: c, cls)) - - -def judge_compare_op(optype: str) -> bool: - return optype in CmpOp.enum_value_list() - - -CMP_OP_VALUE_LIST = [ - LarkToken.L_EQUAL_TO, - LarkToken.L_NOT_EQUAL_TO, - LarkToken.L_LESS_THAN, - LarkToken.L_LESS_THAN_OR_EQUAL_TO, - LarkToken.L_GREATER_THAN, - LarkToken.L_GREATER_THAN_OR_EQUAL_TO, - LarkToken.L_IS, - LarkToken.L_IN, - LarkToken.L_L_NOT, -] - - -class CmpOp(Enum): - Eq = LarkToken.L_EQUAL_TO - NotEq = LarkToken.L_NOT_EQUAL_TO - Lt = LarkToken.L_LESS_THAN - LtE = LarkToken.L_LESS_THAN_OR_EQUAL_TO - Gt = LarkToken.L_GREATER_THAN - GtE = LarkToken.L_GREATER_THAN_OR_EQUAL_TO - Is = LarkToken.L_IS - In = LarkToken.L_IN - - Not = LarkToken.L_L_NOT - - IsNot = f"{LarkToken.L_IS} {LarkToken.L_L_NOT}" # "IS NOT" - NotIn = f"{LarkToken.L_L_NOT} {LarkToken.L_IN}" # "NOT IN" - - @classmethod - def enum_value_list(cls) -> [str]: - return CMP_OP_VALUE_LIST - - @classmethod - def enum_key_list(cls) -> [str]: - return list(map(lambda c: c, cls)) - - -class ExprContext(Enum): - LOAD = "LOAD" - STORE = "STORE" - DEL = "DEL" - AUGLOAD = "AUGLOAD" - AUGSTORE = "AUGSTORE" - PARAM = "PARAM" - - @classmethod - def enum_value_list(cls) -> [str]: - return list(map(lambda c: c.value, cls)) - - -AST_ENUM_LIST = { - "BinOp": BinOp, - "AugOp": AugOp, - "UnaryOp": UnaryOp, - "CmpOp": CmpOp, - "ExprContext": ExprContext, - "OverrideAction": OverrideAction, -} - -OPERATOR_VALUE_MAP = { - AugOp.Assign: TokenValue.ASSIGN, - AugOp.Add: TokenValue.COMP_PLUS, - AugOp.Sub: TokenValue.COMP_MINUS, - AugOp.Mul: TokenValue.COMP_MULTIPLY, - AugOp.Div: TokenValue.COMP_DIVIDE, - AugOp.Mod: TokenValue.COMP_MOD, - AugOp.Pow: TokenValue.COMP_DOUBLE_STAR, - AugOp.LShift: TokenValue.COMP_SHIFT_LEFT, - AugOp.RShift: TokenValue.COMP_SHIFT_RIGHT, - AugOp.BitOr: TokenValue.COMP_OR, - AugOp.BitXor: TokenValue.COMP_XOR, - AugOp.BitAnd: TokenValue.COMP_AND, - AugOp.FloorDiv: TokenValue.COMP_DOUBLE_DIVIDE, - BinOp.Add: TokenValue.PLUS, - BinOp.Sub: TokenValue.MINUS, - BinOp.Mul: TokenValue.MULTIPLY, - BinOp.Div: TokenValue.DIVIDE, - BinOp.Mod: TokenValue.MOD, - BinOp.Pow: TokenValue.DOUBLE_STAR, - BinOp.LShift: TokenValue.SHIFT_LEFT, - BinOp.RShift: TokenValue.SHIFT_RIGHT, - BinOp.BitOr: TokenValue.OR, - BinOp.BitXor: TokenValue.XOR, - BinOp.BitAnd: TokenValue.AND, - BinOp.FloorDiv: TokenValue.DOUBLE_DIVIDE, - BinOp.And: TokenValue.L_AND, - BinOp.Or: TokenValue.L_OR, - BinOp.As: TokenValue.AS, - CmpOp.Eq: TokenValue.EQUAL_TO, - CmpOp.NotEq: TokenValue.NOT_EQUAL_TO, - CmpOp.Lt: TokenValue.LESS_THAN, - CmpOp.LtE: TokenValue.LESS_THAN_OR_EQUAL_TO, - CmpOp.Gt: TokenValue.GREATER_THAN, - CmpOp.GtE: TokenValue.GREATER_THAN_OR_EQUAL_TO, - CmpOp.Is: TokenValue.IS, - CmpOp.In: TokenValue.IN, - CmpOp.Not: TokenValue.NOT, - CmpOp.IsNot: " ".join([TokenValue.IS, TokenValue.L_NOT]), - CmpOp.NotIn: " ".join([TokenValue.L_NOT, TokenValue.IN]), - UnaryOp.UAdd: TokenValue.PLUS, - UnaryOp.USub: TokenValue.MINUS, - UnaryOp.Invert: TokenValue.NOT, - UnaryOp.Not: TokenValue.L_NOT, -} - - -class Position: - """Position describes an arbitrary source position including the filename, - line, and column location. - - A Position is valid if the line number is > 0. - The line and column are both 1 based. - """ - - def __init__(self, filename: str = None, line: int = None, column: int = None): - self.filename: str = filename - self.line: int = line - self.column: int = column - - def is_valid(self) -> bool: - return self.filename is not None and self.line is not None and self.line > 0 - - def less(self, pos: "Position") -> bool: - if not self.is_valid() or not pos or not pos.is_valid(): - return False - if self.filename != pos.filename: - return False - if self.line < pos.line: - return True - if self.line == pos.line: - return self.column < pos.column - return False - - def less_equal(self, pos: "Position") -> bool: - if not self.is_valid() or not pos or not pos.is_valid(): - return False - if self.less(pos): - return True - return self == pos - - def __eq__(self, other: "Position") -> bool: - return ( - self.filename == other.filename - and self.line == other.line - and self.column == other.column - ) - - def __str__(self) -> str: - return f"<{self.filename}, ({self.line}, {self.column})>" - - -class AST: - """ - All KCL node types implement the KCL AST interface - """ - - _line_offset: int = 0 - _column_offset: int = 0 - - def __init__( - self, - line: Optional[int] = 0, - column: Optional[int] = 0, - end_line: Optional[int] = 0, - end_column: Optional[int] = 0, - ) -> None: - self.filename: str = None - self.relative_filename: str = None - self.line: int = line - self.column: int = column - self.end_line: int = end_line - self.end_column: int = end_column - self.parent: Optional[AST] = None - - def __str__(self) -> str: - return f"<{self.type}, ({self.line}, {self.column})>" - - def __repr__(self) -> str: - return self.__str__() - - def get_line(self) -> int: - """ - Get the node line, which is 1 based - """ - return self.line - - def get_column(self) -> int: - """ - Get the node column, which is 1 based - """ - return self.column - - def get_end_line(self) -> int: - """ - Get the node end_line - """ - return self.end_line - - def get_end_column(self) -> int: - """ - Get the node end_column - """ - return self.end_column - - def set_ast_position(self, node, filename=None): - import kclvm.compiler.parser.lark_pb2 as lark_pb - - check_utils.check_type_not_none(node, AST, lark_pb.Tree) - check_utils.check_type_allow_none(filename, str, PosixPath) - self.filename = filename if isinstance(node, lark_pb.Tree) else node.filename - self.line = node.line + self._line_offset - self.column = node.column + self._column_offset - self.end_line = node.end_line + self._line_offset - self.end_column = node.end_column + self._column_offset - - return self - - def set_column(self, column: int): - assert isinstance(column, int) and column >= 0 - self.column = column - - def set_line(self, line: int): - assert isinstance(line, int) and line >= 0 - self.line = line - - def set_end_line_column(self, ast_node): - assert ast_node and isinstance(ast_node, AST) - self.end_line = ast_node.end_line - self.end_column = ast_node.end_column - - def set_end_line(self, end_line: int): - assert isinstance(end_line, int) and end_line >= 0 - self.end_line = end_line - - def set_end_column(self, end_column: int): - assert isinstance(end_column, int) and end_column >= 0 - self.end_column = end_column - - def offset_column(self, offset_column: int): - assert isinstance(offset_column, int) - self.column += offset_column - - def offset_line(self, offset_line: int): - assert isinstance(offset_line, int) - self.line += offset_line - - def offset_end_line(self, offset_end_line: int): - assert isinstance(offset_end_line, int) - self.end_line += offset_end_line - - def offset_end_column(self, offset_end_column: int): - assert isinstance(offset_end_column, int) - self.end_column += offset_end_column - - @classmethod - def set_offset(cls, line_offset: int = 0, column_offset=0): - cls._line_offset = line_offset - cls._column_offset = column_offset - - @classmethod - def reset_offset(cls): - cls._line_offset = 0 - cls._column_offset = 0 - - @property - def type(self) -> str: - return self.__class__.__name__ - - @property - def pos(self) -> Position: - return Position(filename=self.filename, line=self.line, column=self.column) - - @property - def end_pos(self) -> Position: - return Position( - filename=self.filename, line=self.end_line, column=self.end_column - ) - - def to_json(self, indent=4, sort_keys=False): - return json.dumps( - self, - default=lambda o: o.value - if type(o) in AST_ENUM_LIST.values() - else {k: v for k, v in o.__dict__.items() if k != "parent"}, - indent=indent, - sort_keys=sort_keys, - ) - - def contains_pos(self, pos: Position) -> bool: - """ - check if current node contains a position - :param pos: the given position - :return: if current node contains the given position - """ - start_pos = Position( - filename=self.filename, - line=self.line, - column=self.column, - ) - end_pos = Position( - filename=self.filename, - line=self.end_line, - column=self.end_column, - ) - return start_pos.less_equal(pos) and pos.less_equal(end_pos) - - def get_children(self) -> List["AST"]: - def walk_field(inner: typing.Union[typing.List, typing.Dict, AST]): - if isinstance(inner, list): - [walk_field(item) for item in inner] - return - if isinstance(inner, dict): - [walk_field(v) for _, v in inner] - return - if isinstance(inner, AST): - children.append(inner) - - children = [] - [walk_field(field) for _, field in ast.iter_fields(self)] - return children - - def find_leaf_by_pos(self, pos: Position) -> Optional["AST"]: - if pos and pos.is_valid() and self.contains_pos(pos): - children = self.get_children() - if len(children) == 0: - return self - else: - for child in children: - leaf = child.find_leaf_by_pos(pos) - if leaf: - return leaf - return None - - def find_nearest_parent_by_type(self, tpe: typing.Type["AST"]) -> Optional["AST"]: - parent = self.parent - while parent: - if parent.type == tpe.__name__: - return typing.cast(tpe, parent) - parent = parent.parent - return None - - -class Stmt(AST): - def __init__( - self, line: Optional[int] = None, column: Optional[int] = None - ) -> None: - super().__init__(line, column) - self._ast_type = "Stmt" - - -class Expr(AST): - def __init__( - self, line: Optional[int] = None, column: Optional[int] = None - ) -> None: - super().__init__(line, column) - self._ast_type = "Expr" - - -class Name(Expr, ABC): - def __init__( - self, - line: Optional[int] = None, - column: Optional[int] = None, - value: Optional[str] = None, - ) -> None: - super().__init__(line, column) - self._ast_type = "Name" - self.value: str = value - - -class TypeAliasStmt(Stmt): - def __init__( - self, line: Optional[int] = None, column: Optional[int] = None - ) -> None: - super().__init__(line, column) - self._ast_type = "TypeAliasStmt" - self.type_name: Optional[Identifier] = None - self.type_value: Optional[Type] = None - - -class ExprStmt(Stmt): - def __init__( - self, line: Optional[int] = None, column: Optional[int] = None - ) -> None: - super().__init__(line, column) - self._ast_type = "ExprStmt" - self.exprs: List[Expr] = [] - - -class UnificationStmt(Stmt): - def __init__( - self, line: Optional[int] = None, column: Optional[int] = None - ) -> None: - super().__init__(line, column) - self._ast_type = "UnificationStmt" - self.target: Identifier = None - self.value: SchemaExpr = None - - -class AssignStmt(Stmt): - def __init__( - self, line: Optional[int] = None, column: Optional[int] = None - ) -> None: - super().__init__(line, column) - self._ast_type = "AssignStmt" - self.targets: List[Identifier] = [] - self.value: Optional[Expr] = None - self.type_annotation: str = "" - self.type_annotation_node: Optional[Type] = None - - def __str__(self): - return super().__str__()[:-1] + f" targets: {self.targets} value: {self.value}>" - - -class AugAssignStmt(Stmt): - def __init__( - self, line: Optional[int] = None, column: Optional[int] = None - ) -> None: - super().__init__(line, column) - self._ast_type = "AugAssignStmt" - self.op: Optional[AugOp] = None - self.target: Optional[Identifier] = None - self.value: Optional[Expr] = None - - def __str__(self): - return ( - super().__str__()[:-1] - + f" target: {self.target} augop: {self.op} value: {self.value}>" - ) - - -class AssertStmt(Stmt): - def __init__( - self, line: Optional[int] = None, column: Optional[int] = None - ) -> None: - super().__init__(line, column) - self._ast_type = "AssertStmt" - self.test: Optional[Expr] = None - self.if_cond: Optional[Expr] = None - self.msg: Optional[Expr] = None - - -class IfStmt(Stmt): - def __init__( - self, line: Optional[int] = None, column: Optional[int] = None - ) -> None: - super().__init__(line, column) - self._ast_type = "IfStmt" - self.cond: Optional[Expr] = None - self.body: List[Stmt] = [] - self.elif_cond: List[Expr] = [] - self.elif_body: List[List[Stmt]] = [] - self.else_body: List[Stmt] = [] - - def __str__(self): - return ( - super().__str__()[:-1] - + f" cond: {self.cond} body: {self.body} elif_cond: {self.elif_cond} elifbody: {self.elif_body} elsebody: {self.else_body}>" - ) - - -class ImportStmt(Stmt): - def __init__( - self, line: Optional[int] = None, column: Optional[int] = None - ) -> None: - super().__init__(line, column) - self._ast_type = "ImportStmt" - self.path: Optional[str] = None - self.name: Optional[str] = None - self.asname: Optional[str] = None - self.path_nodes: [Name] = [] - self.as_name_node: Optional[Name] = None - - self.rawpath: Optional[str] = None # only for error message - - def __str__(self): - return super().__str__()[:-1] + f" name: {self.name}>" - - @property - def pkg_name(self) -> str: - return self.asname or self.name - - -class SchemaIndexSignature(Stmt): - def __init__( - self, line: Optional[int] = None, column: Optional[int] = None - ) -> None: - super().__init__(line, column) - self._ast_type = "SchemaIndexSignature" - self.key_name: Optional[str] = None - self.key_type: Optional[str] = "str" - self.value_type: Optional[str] = "" - self.value: Optional[Expr] = None - self.any_other: bool = False - self.name_node: Optional[Name] = None - self.value_type_node: Optional[Type] = None - - -class SchemaAttr(Stmt): - def __init__( - self, line: Optional[int] = None, column: Optional[int] = None - ) -> None: - super().__init__(line, column) - self._ast_type = "SchemaAttr" - self.doc: str = "" - self.name: str = "" - self.type_str: str = "" - self.op: Optional[Union[BinOp, AugOp]] = None - self.value: Optional[Expr] = None - self.is_optional: bool = False - self.decorators: List[Decorator] = [] - self.name_node: Optional[Name] = None - self.type_node: Optional[Type] = None - - def __str__(self): - return ( - super().__str__()[:-1] - + f" name: {self.name} type: {self.type_str} value: {self.value}>" - ) - - -class SchemaStmt(Stmt): - def __init__( - self, line: Optional[int] = None, column: Optional[int] = None - ) -> None: - super().__init__(line, column) - self._ast_type = "SchemaStmt" - self.doc: str = "" - self.name: str = "" - self.parent_name: Optional[Identifier] = None - self.for_host_name: Optional[Identifier] = None - self.is_mixin: bool = False - self.is_protocol: bool = False - self.args: Optional[Arguments] = None - self.mixins: List[Identifier] = [] - self.body: List[Union[SchemaAttr, Stmt]] = [] - self.decorators: List[Decorator] = [] - self.checks: List[CheckExpr] = [] - self.index_signature: Optional[SchemaIndexSignature] = None - self.name_node: Optional[Name] = None - - def __str__(self): - return super().__str__()[:-1] + f" name: {self.name} body: {self.body}>" - - def has_only_attribute_definitions(self) -> bool: - return not bool( - self.args - or self.mixins - or self.checks - or self.index_signature - or any( - [not isinstance(p, (SchemaAttr, UnificationStmt)) for p in self.body] - ) - ) - - def GetAttrList(self) -> List[SchemaAttr]: - attr_list = [] - - for attr in self.body or []: - if isinstance(attr, (SchemaAttr, UnificationStmt)): - attr_list.append(attr) - - return attr_list - - def GetAttrNameList(self) -> List[str]: - attr_list = self.GetAttrList() - return [attr.name for attr in attr_list] - - def GetIndexSignatureAttrName(self) -> Optional[str]: - return self.index_signature.key_name if self.index_signature else None - - def GetStmtList(self) -> List[Stmt]: - stmt_list = [] - - for attr in self.body: - if not isinstance(attr, SchemaAttr): - stmt_list.append(attr) - - return stmt_list - - def GetLeftIdentifierList(self): - """Get schema full attribute list including - un-exported attributes and relaxed attributes - """ - attr_list = [] - - def loop_body(body: List[Stmt]): - """Get the l-values recursively and add them into schema attr list""" - if not body: - return - for stmt in body: - if isinstance(stmt, AssignStmt): - for target in stmt.targets: - add_name(target.get_first_name()) - elif isinstance(stmt, (AugAssignStmt, UnificationStmt)): - add_name(stmt.target.get_first_name()) - elif isinstance(stmt, IfStmt): - loop_body(stmt.body) - for body in stmt.elif_body: - loop_body(body) - loop_body(stmt.else_body) - elif isinstance(stmt, SchemaAttr): - add_name(stmt.name) - - def add_name(name: str): - """Add the `name` into schema attr list""" - if not name or not isinstance(name, str): - return - attr_list.append(name) - - loop_body(self.body) - return attr_list - - -class RuleStmt(Stmt): - def __init__( - self, line: Optional[int] = None, column: Optional[int] = None - ) -> None: - super().__init__(line, column) - self._ast_type = "RuleStmt" - self.doc: str = "" - self.name: str = "" - self.parent_rules: List[Identifier] = [] - self.decorators: List[Decorator] = [] - self.checks: List[CheckExpr] = [] - self.name_node: Optional[Name] = None - self.args: Optional[Arguments] = None - self.for_host_name: Optional[Identifier] = None - - -class IfExpr(Expr): - def __init__( - self, line: Optional[int] = None, column: Optional[int] = None - ) -> None: - super().__init__(line, column) - self._ast_type = "IfExpr" - - # body if cond else orelse - self.body: Optional[Expr] = None # self.body - self.cond: Optional[Expr] = None # self.cond - self.orelse: Optional[Expr] = None # self.orelse - - -class UnaryExpr(Expr): - def __init__( - self, line: Optional[int] = None, column: Optional[int] = None - ) -> None: - super().__init__(line, column) - self._ast_type = "UnaryExpr" - self.op: Optional[UnaryOp] = None - self.operand: Optional[Expr] = None - - -class BinaryExpr(Expr): - def __init__( - self, line: Optional[int] = None, column: Optional[int] = None - ) -> None: - super().__init__(line, column) - self._ast_type = "BinaryExpr" - self.left: Optional[Expr] = None - self.op: Optional[Union[BinOp, CmpOp]] = None - self.right: Optional[Expr] = None - - def __str__(self): - return ( - super().__str__()[:-1] - + f" left: {self.left} op: {self.op} right: {self.right}>" - ) - - -class SelectorExpr(Expr): - def __init__( - self, - line: Optional[int] = None, - column: Optional[int] = None, - ctx: ExprContext = ExprContext.LOAD, - ) -> None: - super().__init__(line, column) - self._ast_type = "SelectorExpr" - self.value: Optional[Expr] = None - self.attr: Optional[Identifier] = None - self.ctx: Optional[ExprContext] = ctx - self.has_question: bool = False - - -class CallExpr(Expr): - def __init__( - self, line: Optional[int] = None, column: Optional[int] = None - ) -> None: - super().__init__(line, column) - self._ast_type = "CallExpr" - self.func: Optional[Expr] = None - self.args: List[Expr] = [] - self.keywords: List[Keyword] = [] - - def __str__(self): - return super().__str__()[:-1] + f" func: {self.func} args: {self.args}>" - - -class ParenExpr(Expr): - def __init__( - self, line: Optional[int] = None, column: Optional[int] = None - ) -> None: - super().__init__(line, column) - self._ast_type = "ParenExpr" - self.expr: Optional[Expr] = None - - -class QuantExpr(Expr): - def __init__( - self, - line: Optional[int] = None, - column: Optional[int] = None, - ctx: ExprContext = ExprContext.LOAD, - ) -> None: - super().__init__(line, column) - self._ast_type = "QuantExpr" - self.target: Optional[Expr] = None - self.variables: List[Identifier] = [] - self.op: Optional[int] = None - self.test: Optional[Expr] = None - self.if_cond: Optional[Expr] = None - self.ctx: ExprContext = ctx - - -class QuantOperation: - ALL = 1 - ANY = 2 - FILTER = 3 - MAP = 4 - - MAPPING = { - "any": ANY, - "all": ALL, - "map": MAP, - "filter": FILTER, - } - - -class ListExpr(Expr): - def __init__( - self, - line: Optional[int] = None, - column: Optional[int] = None, - ctx: ExprContext = ExprContext.LOAD, - ) -> None: - super().__init__(line, column) - self._ast_type = "ListExpr" - self.elts: List[Expr] = [] - self.ctx: ExprContext = ctx - - def __str__(self): - return super().__str__()[:-1] + f" values: {self.elts}>" - - -class ListIfItemExpr(Expr): - def __init__( - self, line: Optional[int] = None, column: Optional[int] = None - ) -> None: - super().__init__(line, column) - self._ast_type = "ListIfItemExpr" - self.if_cond: Optional[Expr] = None - self.exprs: List[Expr] = [] - self.orelse: Optional[Expr] = None - - -class ListComp(Expr): - def __init__( - self, line: Optional[int] = None, column: Optional[int] = None - ) -> None: - super().__init__(line, column) - self._ast_type = "ListComp" - self.elt: Optional[Expr] = None - self.generators: List[CompClause] = [] - - -class StarredExpr(Expr): - def __init__( - self, - line: Optional[int] = None, - column: Optional[int] = None, - ctx: ExprContext = ExprContext.LOAD, - ) -> None: - super().__init__(line, column) - self._ast_type = "StarredExpr" - self.value: Optional[Expr] = None - self.ctx: ExprContext = ctx - - -class DictComp(Expr): - def __init__( - self, line: Optional[int] = None, column: Optional[int] = None - ) -> None: - super().__init__(line, column) - self._ast_type = "DictComp" - self.key: Optional[Expr] = None - self.value: Optional[Expr] = None - self.operation: Optional[ConfigEntryOperation] = None - self.generators: List[CompClause] = [] - - -class ConfigIfEntryExpr(Expr): - def __init__( - self, line: Optional[int] = None, column: Optional[int] = None - ) -> None: - super().__init__(line, column) - self._ast_type = "ConfigIfEntryExpr" - self.if_cond: Optional[Expr] = None - self.keys: List[Expr] = [] - self.values: List[Expr] = [] - self.operations: List[int] = [] - self.orelse: Optional[Expr] = None - - -class CompClause(Expr): - def __init__( - self, line: Optional[int] = None, column: Optional[int] = None - ) -> None: - super().__init__(line, column) - self._ast_type = "CompClause" - self.targets: List[Identifier] = [] - self.iter: Optional[Expr] = None - self.ifs: List[Expr] = [] - - -class SchemaExpr(Expr): - def __init__( - self, line: Optional[int] = None, column: Optional[int] = None - ) -> None: - super().__init__(line, column) - self._ast_type = "SchemaExpr" - self.name: Optional[Identifier] = None - self.args: List[Expr] = [] - self.kwargs: List[Keyword] = [] - self.config: Optional[ConfigExpr] = None - - def __str__(self): - return super().__str__()[:-1] + f" name: {self.name} config: {self.config}>" - - -class ConfigExpr(Expr): - def __init__( - self, line: Optional[int] = None, column: Optional[int] = None - ) -> None: - super().__init__(line, column) - self._ast_type = "ConfigExpr" - self.items: List[ConfigEntry] = [] - - @property - def keys(self) -> List[Expr]: - return [item.key for item in self.items] - - @property - def values(self) -> List[Expr]: - return [item.value for item in self.items] - - @property - def operations(self) -> List[int]: - return [item.operation for item in self.items] - - def __str__(self): - return super().__str__()[:-1] + f" keys: {self.keys} values: {self.values}>" - - -class ConfigEntryOperation: - UNION = 0 - OVERRIDE = 1 - INSERT = 2 - UNIQUE = 3 - UNIFICATION = 4 - MAPPING = { - LarkToken.L_COLON: UNION, - LarkToken.L_ASSIGN: OVERRIDE, - LarkToken.L_COMP_PLUS: INSERT, - } - - @staticmethod - def get_min(): - return ConfigEntryOperation.UNION - - @staticmethod - def get_max(): - return ConfigEntryOperation.UNIFICATION - - -class ConfigEntry(AST): - def __init__( - self, - line: Optional[int] = None, - column: Optional[int] = None, - key: Expr = None, - value: Expr = None, - operation: int = ConfigEntryOperation.UNION, - ) -> None: - super().__init__(line, column) - self._ast_type = "ConfigEntry" - self.key: Expr = key - self.value: Expr = value - self.operation: int = operation - self.insert_index: int = -1 - - def __str__(self): - return super().__str__()[:-1] + f" key: {self.key} value: {self.value}>" - - -class CheckExpr(Expr): - def __init__( - self, line: Optional[int] = None, column: Optional[int] = None - ) -> None: - super().__init__(line, column) - self._ast_type = "CheckExpr" - self.test: Optional[Expr] = None - self.if_cond: Optional[Expr] = None - self.msg: Optional[Expr] = None - - -class LambdaExpr(Expr): - def __init__( - self, line: Optional[int] = None, column: Optional[int] = None - ) -> None: - super().__init__(line, column) - self._ast_type = "LambdaExpr" - self.args: Optional[Arguments] = None - self.return_type_str: Optional[str] = None - self.return_type_node: Optional[Type] = None - self.body: List[Stmt] = [] - - -class Decorator(Expr): - def __init__( - self, line: Optional[int] = None, column: Optional[int] = None - ) -> None: - super().__init__(line, column) - self._ast_type = "Decorator" - self.name: Optional[Identifier] = None - self.args: Optional[CallExpr] = None - - -class Subscript(Expr): - def __init__( - self, line: Optional[int] = None, column: Optional[int] = None - ) -> None: - super().__init__(line, column) - self._ast_type = "Subscript" - self.value: Optional[Expr] = None - self.index: Optional[Expr] = None - self.lower: Optional[Expr] = None - self.upper: Optional[Expr] = None - self.step: Optional[Expr] = None - self.ctx: ExprContext = ExprContext.LOAD - self.has_question: bool = False - - -class Keyword(Expr): - def __init__( - self, line: Optional[int] = None, column: Optional[int] = None - ) -> None: - super().__init__(line, column) - self._ast_type = "Keyword" - self.arg: Optional[Identifier] = None - self.value: Optional[Expr] = None - - -class Arguments(Expr): - def __init__( - self, line: Optional[int] = None, column: Optional[int] = None - ) -> None: - super().__init__(line, column) - self._ast_type = "Arguments" - self.args: List[Identifier] = [] # arg0, arg1, ... - self.defaults: List[Expr] = [] - self.type_annotation_list: List[str] = [] - self.type_annotation_node_list: List[Type] = [] - - def __str__(self): - return super().__str__()[:-1] + f" args: {self.args}>" - - def GetArgName(self, i: int) -> str: - if 0 <= i < len(self.args): - return self.args[i].get_name() - return "" - - def GetArgType(self, i: int) -> str: - if 0 <= i < len(self.type_annotation_list): - return self.type_annotation_list[i] - return "" - - def SetArgType(self, i: int, tpe: str): - if 0 <= i < len(self.type_annotation_list): - self.type_annotation_list[i] = tpe - - def GetArgDefault(self, i: int) -> Optional[str]: - if 0 <= i < len(self.defaults): - return ( - typing.cast(StringLit, self.defaults[i]).value - if self.defaults[i] - else None - ) - return None - - -class Compare(Expr): - def __init__( - self, - line: Optional[int] = None, - column: Optional[int] = None, - ) -> None: - super().__init__(line, column) - self._ast_type = "Compare" - self.left: Optional[Expr] = None - self.ops: List[CmpOp] = [] - self.comparators: List[Expr] = [] - - -class Identifier(Expr): - def __init__( - self, - line: Optional[int] = None, - column: Optional[int] = None, - names: List[str] = None, - ctx: ExprContext = ExprContext.LOAD, - ) -> None: - super().__init__(line, column) - self._ast_type = "Identifier" - self.names: List[str] = names if names else [] - self.pkgpath: str = "" - self.ctx: ExprContext = ctx - self.name_nodes: List[Name] = [] - - def set_filename(self, filename: str) -> Expr: - self.filename = filename - return self - - def get_name(self, wrapper=True): - return ".".join(self.names) if wrapper else self.names[-1] - - def get_first_name(self): - return self.names[0] - - def set_ctx(self, ctx: ExprContext): - self.ctx = ctx - - def __str__(self): - return super().__str__()[:-1] + f" name: {self.get_name()}>" - - -class Literal(Expr): - def __init__( - self, - line: Optional[int] = None, - column: Optional[int] = None, - value=None, - ) -> None: - super().__init__(line, column) - self._ast_type = "Literal" - self.value = value - - def __str__(self): - return super().__str__()[:-1] + f" value: {self.value}>" - - -class NumberLit(Literal): - def __init__( - self, - line: Optional[int] = None, - column: Optional[int] = None, - value: Optional[int] = None, - ) -> None: - super().__init__(line, column, value) - self._ast_type = "NumberLit" - self.binary_suffix: Optional[str] = None - - -class NumberBinarySuffix: - n = "n" - u = "u" - m = "m" - k = "k" - K = "K" - M = "M" - G = "G" - T = "T" - P = "P" - Ki = "Ki" - Mi = "Mi" - Gi = "Gi" - Ti = "Ti" - Pi = "Pi" - - -class StringLit(Literal): - def __init__( - self, - line: Optional[int] = None, - column: Optional[int] = None, - value: Optional[str] = None, - ) -> None: - super().__init__(line, column, value) - self._ast_type = "StringLit" - self.is_long_string: bool = False - self.raw_value: Optional[str] = None - - -class NameConstantLit(Literal): - """ - Name constant: True, False, None - """ - - def __init__( - self, - line: Optional[int] = None, - column: Optional[int] = None, - value: Optional[bool] = None, - ) -> None: - super().__init__(line, column, value) - self._ast_type = "NameConstantLit" - - -class JoinedString(Expr): - def __init__( - self, - line: Optional[int] = None, - column: Optional[int] = None, - ) -> None: - super().__init__(line, column) - self._ast_type = "JoinedString" - self.is_long_string: bool = False - self.values: List[Union[StringLit, FormattedValue]] = [] - self.raw_value: Optional[str] = None - - -class FormattedValue(Expr): - def __init__( - self, - line: Optional[int] = None, - column: Optional[int] = None, - value: Optional[Expr] = None, - format_spec: str = None, - ) -> None: - super().__init__(line, column) - self._ast_type = "FormattedValue" - self.is_long_string: bool = False - self.value: Optional[Expr] = value - self.format_spec: str = format_spec - - -class Comment(AST): - def __init__( - self, - filename: Optional[str] = None, - line: Optional[int] = None, - column: Optional[int] = None, - end_line: Optional[int] = None, - end_column: Optional[int] = None, - text: Optional[str] = None, - ) -> None: - super().__init__(line, column, end_line=end_line, end_column=end_column) - self.filename = filename - self._ast_type = "Comment" - self.text: Optional[str] = text - - def __str__(self): - return super().__str__()[:-1] + f" text: {self.text}>" - - -class CommentGroup(AST): - def __init__( - self, - line: Optional[int] = None, - column: Optional[int] = None, - ) -> None: - super().__init__(line, column) - self._ast_type = "CommentGroup" - self.comments: List[Comment] = [] - - -class Type(AST): - def __init__( - self, - line: Optional[int] = None, - column: Optional[int] = None, - ) -> None: - super().__init__(line, column) - self._ast_type = "Type" - # type_element: schema_type | basic_type | compound_type | literal_type - self.type_elements: List[ - Union[Identifier, BasicType, ListType, DictType, LiteralType] - ] = [] - self.plain_type_str: str = "" - - -class BasicType(AST): - def __init__( - self, - line: Optional[int] = None, - column: Optional[int] = None, - ) -> None: - super().__init__(line, column) - self._ast_type = "BasicType" - self.type_name: str = "" - - -class ListType(AST): - def __init__( - self, - line: Optional[int] = None, - column: Optional[int] = None, - ) -> None: - super().__init__(line, column) - self._ast_type = "ListType" - self.inner_type: Optional[Type] = None - self.plain_type_str: str = "" - - -class DictType(AST): - def __init__( - self, - line: Optional[int] = None, - column: Optional[int] = None, - ) -> None: - super().__init__(line, column) - self._ast_type = "DictType" - self.key_type: Optional[Type] = None - self.value_type: Optional[Type] = None - self.plain_type_str: str = "" - - -class LiteralType(AST): - def __init__( - self, - line: Optional[int] = None, - column: Optional[int] = None, - ) -> None: - super().__init__(line, column) - self._ast_type = "LiteralType" - self.plain_value: str = "" - self.value_type: str = "" - self.string_value: Optional[StringLit] = None - self.number_value: Optional[NumberLit] = None - - -class Module(AST): - """Module is an abstract syntax tree for a single KCL file.""" - - def __init__( - self, - line: Optional[int] = None, - column: Optional[int] = None, - pkg: str = "", - filename: str = "", - ) -> None: - super().__init__(line, column) - self._ast_type = "Module" - self.pkg: str = pkg - self.filename: str = filename - self.body: List[Stmt] = [] - - self.doc: str = "" - self.name = self.pkg # {__main__} or same as {self.pkg} - - self.global_names: List[str] = [] - self.local_names: Dict[str, List[str]] = {} - - self.comments: List[ - Comment - ] = [] # List of all comments in the source KCL module - - def __str__(self): - return ( - super().__str__()[:-1] - + f" pkg: {self.pkg} filename: {self.filename} body: {self.body}>" - ) - - def GetPkgpath(self, asname: str) -> str: - for stmt in self.body or []: - if isinstance(stmt, ImportStmt): - import_spec = typing.cast(ImportStmt, stmt) - if import_spec.asname == asname: - return import_spec.path - return "" - - def GetImportList(self) -> List[ImportStmt]: - import_list: List[ImportStmt] = [] - - for stmt in self.body or []: - if isinstance(stmt, ImportStmt): - import_list.append(stmt) - - return import_list - - def GetSchemaList(self) -> List[SchemaStmt]: - schema_list: List[SchemaStmt] = [] - - for stmt in self.body or []: - if isinstance(stmt, SchemaStmt): - schema_list.append(stmt) - - return schema_list - - def GetSchemaAndRuleList(self) -> List[Union[SchemaStmt, RuleStmt]]: - schema_rule_list: List[Union[SchemaStmt, RuleStmt]] = [] - - for stmt in self.body or []: - if isinstance(stmt, (SchemaStmt, RuleStmt)): - schema_rule_list.append(stmt) - - return schema_rule_list - - def GetFileName(self, root: str = "") -> str: - """# Construct the filename from the root path and relative file.""" - if root and self.relative_filename and self.relative_filename[0] == ".": - filename = root + self.relative_filename[1:] - else: - filename = self.filename - return filename - - def GetFirstExprInExprStmt(self) -> Expr: - if self.body and len(self.body) > 0: - if isinstance(self.body[0], ExprStmt) and len(self.body[0].exprs) > 0: - return self.body[0].exprs[0] - return None - - -class ASTFactory: - @staticmethod - def get_ast_module(node, pkg, filename, name) -> Module: - check_utils.check_type_allow_none(filename, str, PosixPath) - check_utils.check_allow_none(pkg, str) - - p = Module() - p.line = 1 - p.column = 1 - p.pkg = pkg - p.set_ast_position(node, filename) - p.name = name - return p - - @staticmethod - def get_ast_configentry(key, value, operation, filename) -> ConfigEntry: - check_utils.check_type_allow_none(key, Identifier, StringLit) - check_utils.check_allow_none(value, Expr) - check_utils.check_type_allow_none(filename, str, PosixPath) - p = ConfigEntry( - line=key.line if key else value.line, - column=key.column if key else value.column, - key=key, - value=value, - operation=operation, - ) - p.filename = filename - return p - - @staticmethod - def get_ast_identifier(value: str) -> Identifier: - check_utils.check_not_none(value, str) - p = Identifier() - p.names = value.split(".") - return p - - @staticmethod - def get_ast_literal(tpe: typing.Type[AST], line, column, value, filename): - assert tpe - check_utils.check_allow_none(line, int) - check_utils.check_allow_none(column, int) - check_utils.check_type_allow_none(filename, str, PosixPath) - p = tpe(line, column, value) - p.filename = filename - return typing.cast(tpe, p) - - @staticmethod - def get_ast(tpe: typing.Type[AST], node, filename): - assert tpe - check_utils.check_type_allow_none(filename, str, PosixPath) - p = tpe().set_ast_position(node, filename) - return typing.cast(tpe, p) - - @staticmethod - def get_op(tpe: typing.Type[Enum], op_type: str): - assert tpe - check_utils.check_allow_none(op_type, str) - p = tpe(op_type) if op_type else None - return typing.cast(tpe, p) - - @staticmethod - def get_ast_formatted_value(value, format_spec, filename): - check_utils.check_type_allow_none(filename, str, PosixPath) - check_utils.check_allow_none(value, Expr) - check_utils.check_allow_none(format_spec, str) - p = FormattedValue(value=value, format_spec=format_spec) - p.set_ast_position(value, filename) - return p - - -class Program: - """Program is the AST collection of all files of the running KCL program.""" - - MAIN_PKGPATH = "__main__" - - def __init__( - self, - *, - root: str = "", - main: str = "", - pkgs: Dict[str, List[Module]] = None, - cmd_args: List[CmdArgSpec] = None, - cmd_overrides: List[CmdOverrideSpec] = None, - ): - self.root: str = root if root else "" - self.main: str = main if main else "" - self.pkgs: Dict[str, List[Module]] = pkgs if pkgs else {} - - self.cmd_args: List[CmdArgSpec] = cmd_args if cmd_args else [] - self.cmd_overrides: List[CmdOverrideSpec] = ( - cmd_overrides if cmd_overrides else [] - ) - - def get_check_sum(self, root: str = "") -> str: - """Get the AST program all file md5 sum""" - check_sum = hashlib.md5() - for modules in self.pkgs.values(): - for module in modules: - if ( - root - and module.relative_filename - and module.relative_filename[0] == "." - ): - filename = root + module.relative_filename[1:] - else: - filename = module.filename - if os.path.isfile(filename): - # Encoding the filename into the checksum - check_sum.update( - (filename.replace(root, ".", 1) if root else filename).encode( - encoding="utf-8" - ) - ) - with open(filename, "rb") as f: - check_sum.update(f.read()) - return check_sum.hexdigest() - - def to_json(self, indent=4, sort_keys=False): - return json.dumps( - self, - default=lambda o: o.value - if type(o) in AST_ENUM_LIST.values() - else o.__dict__, - indent=indent, - sort_keys=sort_keys, - ) diff --git a/internal/kclvm_py/kcl/ast/fields_map.py b/internal/kclvm_py/kcl/ast/fields_map.py deleted file mode 100644 index 57210e13f..000000000 --- a/internal/kclvm_py/kcl/ast/fields_map.py +++ /dev/null @@ -1,104 +0,0 @@ -# Copyright 2020 The KCL Authors. All rights reserved. - -from typing import Tuple, Union, List - -import kclvm.kcl.ast as ast - -# Auto Generated -AST_FIELDS_MAP = { - # Stmt - "ExprStmt": ["exprs"], - "UnificationStmt": ["target", "value"], - "TypeAliasStmt": ["type_name"], - "AssignStmt": ["targets", "value", "type_annotation_node"], - "AugAssignStmt": ["target", "op", "value"], - "AssertStmt": ["test", "if_cond", "msg"], - "IfStmt": ["cond", "body", "elif_cond", "elif_body", "else_body"], - "ImportStmt": ["path", "name", "asname", "rawpath", "path_nodes", "as_name_node"], - "SchemaAttr": [ - "doc", - "name", - "type_str", - "op", - "value", - "is_optional", - "decorators", - "name_node", - "type_node", - ], - "SchemaStmt": [ - "doc", - "name", - "parent_name", - "is_mixin", - "args", - "mixins", - "body", - "decorators", - "checks", - "index_signature", - "name_node", - "for_host_name", - ], - "RuleStmt": [ - "doc", - "name", - "parent_rules", - "decorators", - "args", - "checks", - "name_node", - "for_host_name", - ], - # Expr - "QuantExpr": ["target", "variables", "test", "if_cond"], - "SchemaIndexSignature": ["value", "name_node", "value_type_node"], - "IfExpr": ["body", "cond", "orelse"], - "UnaryExpr": ["op", "operand"], - "BinaryExpr": ["left", "op", "right"], - "SelectorExpr": ["value", "attr", "has_question"], - "CallExpr": ["func", "args", "keywords"], - "Subscript": ["value", "index", "lower", "upper", "step", "has_question"], - "ParenExpr": ["expr"], - "Operand": ["value"], - "ListExpr": ["elts"], - "ListComp": ["elt", "generators"], - "ListIfItemExpr": ["if_cond", "exprs", "orelse"], - "StarredExpr": ["value"], - "DictComp": ["key", "value", "generators"], - "ConfigIfEntryExpr": ["if_cond", "keys", "values", "orelse"], - "CompClause": ["targets", "iter", "ifs"], - "SchemaExpr": ["name", "args", "kwargs", "config"], - "ConfigExpr": ["items"], - "ConfigEntry": ["key", "value", "operation", "insert_index"], - "CheckExpr": ["test", "if_cond", "msg"], - "LambdaExpr": ["args", "body"], - "Decorator": ["name", "args"], - "Keyword": ["arg", "value"], - "Arguments": ["args", "defaults", "type_annotation_node_list"], - "Compare": ["left", "ops", "comparators"], - "Identifier": ["names", "name_nodes"], - "Name": ["value"], - "Literal": ["value"], - "NumberLit": ["value"], - "StringLit": ["value", "is_long_string"], - "NameConstantLit": ["value"], - "JoinedString": ["values", "is_long_string"], - "FormattedValue": ["value", "is_long_string", "format_spec"], - "Comment": ["text"], - "CommentGroup": ["comments"], - "Module": ["body", "comments"], - # Type - "Type": ["type_elements"], - "BasicType": ["type_name"], - "ListType": ["inner_type"], - "DictType": ["key_type", "value_type"], - "LiteralType": ["string_value", "number_value"], -} - - -def iter_fields(t: ast.AST) -> List[Tuple[str, Union[ast.AST, List[ast.AST]]]]: - """Return ast node attribute-value AST pair""" - if not t or not isinstance(t, ast.AST): - return [] - return [(field, getattr(t, field)) for field in AST_FIELDS_MAP[t.type]] diff --git a/internal/kclvm_py/kcl/ast/lark_token.py b/internal/kclvm_py/kcl/ast/lark_token.py deleted file mode 100644 index f2f4a208b..000000000 --- a/internal/kclvm_py/kcl/ast/lark_token.py +++ /dev/null @@ -1,581 +0,0 @@ -# Copyright 2020 The KCL Authors. All rights reserved. - -# Auto generated by {gen_lark_token.go & kcl.lark}; DO NOT EDIT!!! - - -class LarkToken: - - # kcl.lark rules and tokens (len=186) - L_start = "start" # start: (NEWLINE | statement)* ... - L_statement = "statement" # statement: simple_stmt | compound_stmt ... - L_simple_stmt = "simple_stmt" # simple_stmt: (assign_stmt | unification_stmt | expr_stmt | assert_stmt | import_stmt | type_alias_stmt) NEWLINE ... - L_compound_stmt = "compound_stmt" # compound_stmt: if_stmt | schema_stmt | rule_stmt ... - L_import_stmt = "import_stmt" # import_stmt: IMPORT dot_name (AS NAME)? ... - L_dot_name = "dot_name" # dot_name: (leading_dots identifier) | identifier ... - L_leading_dots = "leading_dots" # leading_dots: DOT+ ... - L_assert_stmt = "assert_stmt" # assert_stmt: ASSERT simple_expr (IF simple_expr)? (COMMA test)? ... - L_if_stmt = "if_stmt" # if_stmt: IF test COLON execution_block (ELIF test COLON execution_block)* (ELSE COLON execution_block)? ... - L_execution_block = "execution_block" # execution_block: if_simple_stmt | NEWLINE _INDENT schema_init_stmt+ _DEDENT ... - L_if_simple_stmt = "if_simple_stmt" # if_simple_stmt: (simple_assign_stmt | unification_stmt | expr_stmt | assert_stmt) NEWLINE ... - L_assign_stmt = "assign_stmt" # assign_stmt: identifier [COLON type] (ASSIGN identifier)* ASSIGN test ... - L_simple_assign_stmt = "simple_assign_stmt" # simple_assign_stmt: identifier ASSIGN test ... - L_unification_stmt = "unification_stmt" # unification_stmt: identifier COLON schema_expr ... - L_schema_stmt = "schema_stmt" # schema_stmt: [decorators] (SCHEMA|MIXIN|PROTOCOL) NAME [LEFT_BRACKETS [schema_arguments] RIGHT_BRACKETS] [LEFT_PARENTHESES identifier (COMMA identifier)* RIGHT_PARENTHESES] [for_host] COLON NEWLINE [schema_body] ... - L_schema_arguments = "schema_arguments" # schema_arguments: schema_argument (COMMA schema_argument)* ... - L_schema_argument = "schema_argument" # schema_argument: NAME [COLON type] [ASSIGN test] ... - L_schema_body = "schema_body" # schema_body: _INDENT (string NEWLINE)* [mixin_stmt] (schema_attribute_stmt|schema_init_stmt|schema_index_signature)* [check_block] _DEDENT ... - L_schema_attribute_stmt = "schema_attribute_stmt" # schema_attribute_stmt: attribute_stmt NEWLINE ... - L_attribute_stmt = "attribute_stmt" # attribute_stmt: [decorators] identifier [QUESTION] COLON type [(ASSIGN|COMP_OR) test] ... - L_schema_init_stmt = "schema_init_stmt" # schema_init_stmt: if_simple_stmt | if_stmt ... - L_schema_index_signature = "schema_index_signature" # schema_index_signature: LEFT_BRACKETS [NAME COLON] [ELLIPSIS] basic_type RIGHT_BRACKETS COLON type [ASSIGN test] NEWLINE ... - L_rule_stmt = "rule_stmt" # rule_stmt: [decorators] RULE NAME [LEFT_BRACKETS [schema_arguments] RIGHT_BRACKETS] [LEFT_PARENTHESES identifier (COMMA identifier)* RIGHT_PARENTHESES] [for_host] COLON NEWLINE [rule_body] ... - L_rule_body = "rule_body" # rule_body: _INDENT (string NEWLINE)* check_expr+ _DEDENT ... - L_for_host = "for_host" # for_host: FOR identifier ... - L_decorators = "decorators" # decorators: (AT decorator_expr NEWLINE)+ ... - L_decorator_expr = "decorator_expr" # decorator_expr: identifier [call_suffix] ... - L_type = "type" # @type: type_element (OR type_element)* ... - L_type_element = "type_element" # type_element: schema_type | basic_type | compound_type | literal_type ... - L_schema_type = "schema_type" # schema_type: identifier ... - L_basic_type = "basic_type" # basic_type: STRING_TYPE | INT_TYPE | FLOAT_TYPE | BOOL_TYPE | ANY_TYPE ... - L_compound_type = "compound_type" # compound_type: list_type | dict_type ... - L_list_type = "list_type" # list_type: LEFT_BRACKETS (type)? RIGHT_BRACKETS ... - L_dict_type = "dict_type" # dict_type: LEFT_BRACE (type)? COLON (type)? RIGHT_BRACE ... - L_literal_type = "literal_type" # literal_type: string | number | TRUE | FALSE | NONE ... - L_type_alias_stmt = "type_alias_stmt" # type_alias_stmt: TYPE NAME ASSIGN type ... - L_check_block = "check_block" # check_block: CHECK COLON NEWLINE _INDENT check_expr+ _DEDENT ... - L_check_expr = "check_expr" # check_expr: simple_expr [IF simple_expr] [COMMA primary_expr] NEWLINE ... - L_mixin_stmt = "mixin_stmt" # mixin_stmt: MIXIN LEFT_BRACKETS [mixins | multiline_mixins] RIGHT_BRACKETS NEWLINE ... - L_multiline_mixins = "multiline_mixins" # multiline_mixins: NEWLINE _INDENT mixins NEWLINE _DEDENT ... - L_mixins = "mixins" # mixins: identifier (COMMA (NEWLINE mixins | identifier))* ... - L_expr_stmt = "expr_stmt" # expr_stmt: testlist_expr ... - L_testlist_expr = "testlist_expr" # testlist_expr: test (COMMA test)* ... - L_test = "test" # test: if_expr | simple_expr ... - L_if_expr = "if_expr" # if_expr: simple_expr IF simple_expr ELSE test ... - L_simple_expr = "simple_expr" # simple_expr: unary_expr | binary_expr | primary_expr ... - L_unary_expr = "unary_expr" # unary_expr: un_op simple_expr ... - L_binary_expr = "binary_expr" # binary_expr: simple_expr bin_op simple_expr ... - L_bin_op = "bin_op" # bin_op: L_OR | L_AND ... - L_un_op = "un_op" # un_op: L_NOT | PLUS | MINUS | NOT ... - L_primary_expr = "primary_expr" # primary_expr: identifier call_suffix | operand | primary_expr select_suffix | primary_expr call_suffix | primary_expr slice_suffix ... - L_operand = "operand" # operand: identifier | number | string | constant | quant_expr | list_expr | list_comp | config_expr | dict_comp | schema_expr | lambda_expr | LEFT_PARENTHESES test RIGHT_PARENTHESES ... - L_select_suffix = "select_suffix" # select_suffix: [QUESTION] DOT NAME ... - L_call_suffix = "call_suffix" # call_suffix: LEFT_PARENTHESES [arguments [COMMA]] RIGHT_PARENTHESES ... - L_slice_suffix = "slice_suffix" # slice_suffix: [QUESTION] LEFT_BRACKETS (test | [test] COLON [test] [COLON [test]]) RIGHT_BRACKETS ... - L_arguments = "arguments" # arguments: argument (COMMA argument)* ... - L_argument = "argument" # argument: test | NAME ASSIGN test | MULTIPLY test | DOUBLE_STAR test ... - L_identifier = "identifier" # identifier: NAME (DOT NAME)* ... - L_quant_expr = "quant_expr" # quant_expr: quant_op [ identifier COMMA ] identifier IN quant_target LEFT_BRACE (simple_expr [IF simple_expr] | NEWLINE _INDENT simple_expr [IF simple_expr] NEWLINE _DEDENT)? RIGHT_BRACE ... - L_quant_target = "quant_target" # quant_target: string | identifier | list_expr | list_comp | config_expr | dict_comp ... - L_quant_op = "quant_op" # quant_op: ALL | ANY | FILTER | MAP ... - L_list_expr = "list_expr" # list_expr: LEFT_BRACKETS [list_items | NEWLINE [_INDENT list_items _DEDENT]] RIGHT_BRACKETS ... - L_list_items = "list_items" # list_items: list_item ((COMMA [NEWLINE] | [NEWLINE]) list_item)* [COMMA] [NEWLINE] ... - L_list_item = "list_item" # list_item: test | star_expr | if_item ... - L_list_comp = "list_comp" # list_comp: LEFT_BRACKETS (list_item comp_clause+ | NEWLINE _INDENT list_item comp_clause+ _DEDENT) RIGHT_BRACKETS ... - L_dict_comp = "dict_comp" # dict_comp: LEFT_BRACE (entry comp_clause+ | NEWLINE _INDENT entry comp_clause+ _DEDENT) RIGHT_BRACE ... - L_entry = "entry" # entry: test (COLON | ASSIGN | COMP_PLUS) test ... - L_comp_clause = "comp_clause" # comp_clause: FOR loop_variables [COMMA] IN simple_expr [NEWLINE] [IF test [NEWLINE]] ... - L_if_entry = "if_entry" # if_entry: IF test COLON if_entry_exec_block (ELIF test COLON if_entry_exec_block)* (ELSE COLON if_entry_exec_block)? ... - L_if_entry_exec_block = "if_entry_exec_block" # if_entry_exec_block: (test (COLON | ASSIGN | COMP_PLUS) test | double_star_expr | if_entry) [NEWLINE] | NEWLINE _INDENT (test (COLON | ASSIGN | COMP_PLUS) test | double_star_expr | if_entry) ((COMMA [NEWLINE] | [NEWLINE]) (test (COLON | ASSIGN | COMP_PLUS) test | double_star_expr | if_entry))* [COMMA] [NEWLINE] _DEDENT ... - L_if_item = "if_item" # if_item: IF test COLON if_item_exec_block (ELIF test COLON if_item_exec_block)* (ELSE COLON if_item_exec_block)? ... - L_if_item_exec_block = "if_item_exec_block" # if_item_exec_block: list_item [NEWLINE] | NEWLINE _INDENT list_item ((COMMA [NEWLINE] | NEWLINE) list_item)* [COMMA] [NEWLINE] _DEDENT ... - L_star_expr = "star_expr" # star_expr: MULTIPLY primary_expr ... - L_double_star_expr = "double_star_expr" # double_star_expr: DOUBLE_STAR primary_expr ... - L_loop_variables = "loop_variables" # loop_variables: primary_expr (COMMA primary_expr)* ... - L_schema_expr = "schema_expr" # schema_expr: identifier (LEFT_PARENTHESES [arguments] RIGHT_PARENTHESES)? config_expr ... - L_config_expr = "config_expr" # config_expr: LEFT_BRACE [config_entries | NEWLINE [_INDENT config_entries _DEDENT]] RIGHT_BRACE ... - L_config_entries = "config_entries" # config_entries: config_entry ((COMMA [NEWLINE] | [NEWLINE]) config_entry)* [COMMA] [NEWLINE] ... - L_config_entry = "config_entry" # config_entry: test (COLON | ASSIGN | COMP_PLUS) test | double_star_expr | if_entry ... - L_lambda_expr = "lambda_expr" # lambda_expr: LAMBDA [schema_arguments] [RIGHT_ARROW type] LEFT_BRACE [expr_stmt | NEWLINE _INDENT schema_init_stmt+ _DEDENT] RIGHT_BRACE ... - L_number = "number" # number: DEC_NUMBER [multiplier] | HEX_NUMBER | BIN_NUMBER | OCT_NUMBER | FLOAT_NUMBER ... - L_multiplier = "multiplier" # multiplier: SI_N_L | SI_U_L | SI_M_L | SI_K_L | SI_K | SI_M | SI_G | SI_T | SI_P ... - L_string = "string" # string: STRING | LONG_STRING ... - L_ASSIGN = "ASSIGN" # ASSIGN: "=" ... - L_COLON = "COLON" # COLON: ":" ... - L_SEMI_COLON = "SEMI_COLON" # SEMI_COLON: ";" ... - L_COMMA = "COMMA" # COMMA: "," ... - L_QUESTION = "QUESTION" # QUESTION: "?" ... - L_ELLIPSIS = "ELLIPSIS" # ELLIPSIS: "..." ... - L_RIGHT_ARROW = "RIGHT_ARROW" # RIGHT_ARROW: "->" ... - L_LEFT_PARENTHESES = "LEFT_PARENTHESES" # LEFT_PARENTHESES: "(" ... - L_RIGHT_PARENTHESES = "RIGHT_PARENTHESES" # RIGHT_PARENTHESES: ")" ... - L_LEFT_BRACKETS = "LEFT_BRACKETS" # LEFT_BRACKETS: "[" ... - L_RIGHT_BRACKETS = "RIGHT_BRACKETS" # RIGHT_BRACKETS: "]" ... - L_LEFT_BRACE = "LEFT_BRACE" # LEFT_BRACE: "{" ... - L_RIGHT_BRACE = "RIGHT_BRACE" # RIGHT_BRACE: "}" ... - L_PLUS = "PLUS" # PLUS: "+" ... - L_MINUS = "MINUS" # MINUS: "-" ... - L_MULTIPLY = "MULTIPLY" # MULTIPLY: "*" ... - L_DIVIDE = "DIVIDE" # DIVIDE: "/" ... - L_MOD = "MOD" # MOD: "%" ... - L_DOT = "DOT" # DOT: "." ... - L_AND = "AND" # AND: "&" ... - L_OR = "OR" # OR: "|" ... - L_XOR = "XOR" # XOR: "^" ... - L_NOT = "NOT" # NOT: "~" ... - L_LESS_THAN = "LESS_THAN" # LESS_THAN: "<" ... - L_GREATER_THAN = "GREATER_THAN" # GREATER_THAN: ">" ... - L_EQUAL_TO = "EQUAL_TO" # EQUAL_TO: "==" ... - L_NOT_EQUAL_TO = "NOT_EQUAL_TO" # NOT_EQUAL_TO: "!=" ... - L_GREATER_THAN_OR_EQUAL_TO = "GREATER_THAN_OR_EQUAL_TO" # GREATER_THAN_OR_EQUAL_TO: ">=" ... - L_LESS_THAN_OR_EQUAL_TO = "LESS_THAN_OR_EQUAL_TO" # LESS_THAN_OR_EQUAL_TO: "<=" ... - L_DOUBLE_STAR = "DOUBLE_STAR" # DOUBLE_STAR: "**" ... - L_DOUBLE_DIVIDE = "DOUBLE_DIVIDE" # DOUBLE_DIVIDE: "//" ... - L_SHIFT_LEFT = "SHIFT_LEFT" # SHIFT_LEFT: "<<" ... - L_SHIFT_RIGHT = "SHIFT_RIGHT" # SHIFT_RIGHT: ">>" ... - L_AT = "AT" # AT: "@" ... - L_COMP_PLUS = "COMP_PLUS" # COMP_PLUS: "+=" ... - L_COMP_MINUS = "COMP_MINUS" # COMP_MINUS: "-=" ... - L_COMP_MULTIPLY = "COMP_MULTIPLY" # COMP_MULTIPLY: "*=" ... - L_COMP_DIVIDE = "COMP_DIVIDE" # COMP_DIVIDE: "/=" ... - L_COMP_MOD = "COMP_MOD" # COMP_MOD: "%=" ... - L_COMP_AND = "COMP_AND" # COMP_AND: "&=" ... - L_COMP_OR = "COMP_OR" # COMP_OR: "|=" ... - L_COMP_XOR = "COMP_XOR" # COMP_XOR: "^=" ... - L_COMP_DOUBLE_STAR = "COMP_DOUBLE_STAR" # COMP_DOUBLE_STAR: "**=" ... - L_COMP_DOUBLE_DIVIDE = "COMP_DOUBLE_DIVIDE" # COMP_DOUBLE_DIVIDE: "//=" ... - L_COMP_SHIFT_LEFT = "COMP_SHIFT_LEFT" # COMP_SHIFT_LEFT: "<<=" ... - L_COMP_SHIFT_RIGHT = "COMP_SHIFT_RIGHT" # COMP_SHIFT_RIGHT: ">>=" ... - L_IMPORT = "IMPORT" # IMPORT: "import" ... - L_AS = "AS" # AS: "as" ... - L_RULE = "RULE" # RULE: "rule" ... - L_SCHEMA = "SCHEMA" # SCHEMA: "schema" ... - L_MIXIN = "MIXIN" # MIXIN: "mixin" ... - L_PROTOCOL = "PROTOCOL" # PROTOCOL: "protocol" ... - L_CHECK = "CHECK" # CHECK: "check" ... - L_FOR = "FOR" # FOR: "for" ... - L_ASSERT = "ASSERT" # ASSERT: "assert" ... - L_IF = "IF" # IF: "if" ... - L_ELIF = "ELIF" # ELIF: "elif" ... - L_ELSE = "ELSE" # ELSE: "else" ... - L_L_OR = "L_OR" # L_OR: "or" ... - L_L_AND = "L_AND" # L_AND: "and" ... - L_L_NOT = "L_NOT" # L_NOT: "not" ... - L_IN = "IN" # IN: "in" ... - L_IS = "IS" # IS: "is" ... - L_LAMBDA = "LAMBDA" # LAMBDA: "lambda" ... - L_ALL = "ALL" # ALL: "all" ... - L_ANY = "ANY" # ANY: "any" ... - L_FILTER = "FILTER" # FILTER: "filter" ... - L_MAP = "MAP" # MAP: "map" ... - L_TYPE = "TYPE" # TYPE: "type" ... - L_ANY_TYPE = "ANY_TYPE" # ANY_TYPE: "any" ... - L_STRING_TYPE = "STRING_TYPE" # STRING_TYPE: "str" ... - L_INT_TYPE = "INT_TYPE" # INT_TYPE: "int" ... - L_FLOAT_TYPE = "FLOAT_TYPE" # FLOAT_TYPE: "float" ... - L_BOOL_TYPE = "BOOL_TYPE" # BOOL_TYPE: "bool" ... - L_TRUE = "TRUE" # TRUE: "True" ... - L_FALSE = "FALSE" # FALSE: "False" ... - L_NONE = "NONE" # NONE: "None" ... - L_UNDEFINED = "UNDEFINED" # UNDEFINED: "Undefined" ... - L_SI_N_L = "SI_N_L" # SI_N_L: "n" ... - L_SI_U_L = "SI_U_L" # SI_U_L: "u" ... - L_SI_M_L = "SI_M_L" # SI_M_L: "m" ... - L_SI_K_L = "SI_K_L" # SI_K_L: "k" ... - L_SI_K = "SI_K" # SI_K: "K" ... - L_SI_M = "SI_M" # SI_M: "M" ... - L_SI_G = "SI_G" # SI_G: "G" ... - L_SI_T = "SI_T" # SI_T: "T" ... - L_SI_P = "SI_P" # SI_P: "P" ... - L_SI_K_IEC = "SI_K_IEC" # SI_K_IEC: "Ki" ... - L_SI_M_IEC = "SI_M_IEC" # SI_M_IEC: "Mi" ... - L_SI_G_IEC = "SI_G_IEC" # SI_G_IEC: "Gi" ... - L_SI_T_IEC = "SI_T_IEC" # SI_T_IEC: "Ti" ... - L_SI_P_IEC = "SI_P_IEC" # SI_P_IEC: "Pi" ... - L_IEC = "IEC" # IEC: "i" ... - L_NAME = "NAME" # NAME: /\$?[a-zA-Z_]\w*/ ... - L_COMMENT = "COMMENT" # COMMENT: /#[^\n]*/ ... - L_NEWLINE = "NEWLINE" # NEWLINE: ( /\r?\n[\t ]*/ | COMMENT )+ ... - L_STRING = "STRING" # STRING: /r?("(?!"").*?(?", - L_LEFT_PARENTHESES: "(", - L_RIGHT_PARENTHESES: ")", - L_LEFT_BRACKETS: "[", - L_RIGHT_BRACKETS: "]", - L_LEFT_BRACE: "{", - L_RIGHT_BRACE: "}", - L_PLUS: "+", - L_MINUS: "-", - L_MULTIPLY: "*", - L_DIVIDE: "/", - L_MOD: "%", - L_DOT: ".", - L_AND: "&", - L_OR: "|", - L_XOR: "^", - L_NOT: "~", - L_LESS_THAN: "<", - L_GREATER_THAN: ">", - L_EQUAL_TO: "==", - L_NOT_EQUAL_TO: "!=", - L_GREATER_THAN_OR_EQUAL_TO: ">=", - L_LESS_THAN_OR_EQUAL_TO: "<=", - L_DOUBLE_STAR: "**", - L_DOUBLE_DIVIDE: "//", - L_SHIFT_LEFT: "<<", - L_SHIFT_RIGHT: ">>", - L_AT: "@", - L_COMP_PLUS: "+=", - L_COMP_MINUS: "-=", - L_COMP_MULTIPLY: "*=", - L_COMP_DIVIDE: "/=", - L_COMP_MOD: "%=", - L_COMP_AND: "&=", - L_COMP_OR: "|=", - L_COMP_XOR: "^=", - L_COMP_DOUBLE_STAR: "**=", - L_COMP_DOUBLE_DIVIDE: "//=", - L_COMP_SHIFT_LEFT: "<<=", - L_COMP_SHIFT_RIGHT: ">>=", - L_IMPORT: "import", - L_AS: "as", - L_RULE: "rule", - L_SCHEMA: "schema", - L_MIXIN: "mixin", - L_PROTOCOL: "protocol", - L_CHECK: "check", - L_FOR: "for", - L_ASSERT: "assert", - L_IF: "if", - L_ELIF: "elif", - L_ELSE: "else", - L_L_OR: "or", - L_L_AND: "and", - L_L_NOT: "not", - L_IN: "in", - L_IS: "is", - L_LAMBDA: "lambda", - L_ALL: "all", - L_ANY: "any", - L_FILTER: "filter", - L_MAP: "map", - L_TYPE: "type", - L_ANY_TYPE: "any", - L_STRING_TYPE: "str", - L_INT_TYPE: "int", - L_FLOAT_TYPE: "float", - L_BOOL_TYPE: "bool", - L_TRUE: "True", - L_FALSE: "False", - L_NONE: "None", - L_UNDEFINED: "Undefined", - L_SI_N_L: "n", - L_SI_U_L: "u", - L_SI_M_L: "m", - L_SI_K_L: "k", - L_SI_K: "K", - L_SI_M: "M", - L_SI_G: "G", - L_SI_T: "T", - L_SI_P: "P", - L_SI_K_IEC: "Ki", - L_SI_M_IEC: "Mi", - L_SI_G_IEC: "Gi", - L_SI_T_IEC: "Ti", - L_SI_P_IEC: "Pi", - L_IEC: "i", - } - - -class TokenValue: - ASSIGN = "=" - COLON = ":" - SEMI_COLON = ";" - COMMA = "," - QUESTION = "?" - ELLIPSIS = "..." - RIGHT_ARROW = "->" - LEFT_PARENTHESES = "(" - RIGHT_PARENTHESES = ")" - LEFT_BRACKETS = "[" - RIGHT_BRACKETS = "]" - LEFT_BRACE = "{" - RIGHT_BRACE = "}" - PLUS = "+" - MINUS = "-" - MULTIPLY = "*" - DIVIDE = "/" - MOD = "%" - DOT = "." - AND = "&" - OR = "|" - XOR = "^" - NOT = "~" - LESS_THAN = "<" - GREATER_THAN = ">" - EQUAL_TO = "==" - NOT_EQUAL_TO = "!=" - GREATER_THAN_OR_EQUAL_TO = ">=" - LESS_THAN_OR_EQUAL_TO = "<=" - DOUBLE_STAR = "**" - DOUBLE_DIVIDE = "//" - SHIFT_LEFT = "<<" - SHIFT_RIGHT = ">>" - AT = "@" - COMP_PLUS = "+=" - COMP_MINUS = "-=" - COMP_MULTIPLY = "*=" - COMP_DIVIDE = "/=" - COMP_MOD = "%=" - COMP_AND = "&=" - COMP_OR = "|=" - COMP_XOR = "^=" - COMP_DOUBLE_STAR = "**=" - COMP_DOUBLE_DIVIDE = "//=" - COMP_SHIFT_LEFT = "<<=" - COMP_SHIFT_RIGHT = ">>=" - IMPORT = "import" - AS = "as" - RULE = "rule" - SCHEMA = "schema" - MIXIN = "mixin" - PROTOCOL = "protocol" - CHECK = "check" - FOR = "for" - ASSERT = "assert" - IF = "if" - ELIF = "elif" - ELSE = "else" - L_OR = "or" - L_AND = "and" - L_NOT = "not" - IN = "in" - IS = "is" - LAMBDA = "lambda" - ALL = "all" - ANY = "any" - FILTER = "filter" - MAP = "map" - TYPE = "type" - ANY_TYPE = "any" - STRING_TYPE = "str" - INT_TYPE = "int" - FLOAT_TYPE = "float" - BOOL_TYPE = "bool" - TRUE = "True" - FALSE = "False" - NONE = "None" - UNDEFINED = "Undefined" - SI_N_L = "n" - SI_U_L = "u" - SI_M_L = "m" - SI_K_L = "k" - SI_K = "K" - SI_M = "M" - SI_G = "G" - SI_T = "T" - SI_P = "P" - SI_K_IEC = "Ki" - SI_M_IEC = "Mi" - SI_G_IEC = "Gi" - SI_T_IEC = "Ti" - SI_P_IEC = "Pi" - IEC = "i" diff --git a/internal/kclvm_py/kcl/ast/precedence.py b/internal/kclvm_py/kcl/ast/precedence.py deleted file mode 100644 index 7a2a4662a..000000000 --- a/internal/kclvm_py/kcl/ast/precedence.py +++ /dev/null @@ -1,139 +0,0 @@ -from enum import IntEnum -from typing import Union - -import kclvm.kcl.ast.ast as ast - - -class OpPrecedence(IntEnum): - """Operator precedence in grammar - - assign_stmt: // precedence 0 - or_test: and_test (L_OR and_test)* // precedence 1 - and_test: not_test (L_AND not_test)* // precedence 2 - not_test: L_NOT not_test | comparison // precedence 3 - comparison: expr (comp_op expr)* // precedence 4 - expr: xor_expr (OR xor_expr)* // precedence 5 - xor_expr: and_expr (XOR and_expr)* // precedence 6 - and_expr: shift_expr (AND shift_expr)* // precedence 7 - shift_expr: arith_expr ((SHIFT_LEFT|SHIFT_RIGHT) arith_expr)* // precedence 8 - arith_expr: term ((PLUS|MINUS) term)* // precedence 9 - term: factor ((MULTIPLY|DIVIDE|MOD|DOUBLE_DIVIDE) factor)* // precedence 10 - factor: (PLUS|MINUS|NOT) factor | power // precedence 11 - power: primary_expr (DOUBLE_STAR factor)? // precedence 12 - """ - - LOWEST = 0 - HIGHEST = 12 - - -OP_PREC_MAP = { - ast.AugOp.Assign: 0, - ast.AugOp.Add: 0, - ast.AugOp.Sub: 0, - ast.AugOp.Mul: 0, - ast.AugOp.Div: 0, - ast.AugOp.Mod: 0, - ast.AugOp.Pow: 0, - ast.AugOp.LShift: 0, - ast.AugOp.RShift: 0, - ast.AugOp.BitOr: 0, - ast.AugOp.BitXor: 0, - ast.AugOp.BitAnd: 0, - ast.AugOp.FloorDiv: 0, - ast.BinOp.Add: 9, - ast.BinOp.Sub: 9, - ast.BinOp.Mul: 10, - ast.BinOp.Div: 10, - ast.BinOp.Mod: 10, - ast.BinOp.Pow: 12, - ast.BinOp.LShift: 8, - ast.BinOp.RShift: 8, - ast.BinOp.BitOr: 6, - ast.BinOp.BitXor: 5, - ast.BinOp.BitAnd: 7, - ast.BinOp.FloorDiv: 10, - ast.BinOp.As: 4, - ast.BinOp.And: 2, - ast.BinOp.Or: 1, - ast.CmpOp.Eq: 4, - ast.CmpOp.NotEq: 4, - ast.CmpOp.Lt: 4, - ast.CmpOp.LtE: 4, - ast.CmpOp.Gt: 4, - ast.CmpOp.GtE: 4, - ast.CmpOp.Is: 4, - ast.CmpOp.In: 4, - ast.CmpOp.Not: 4, - ast.CmpOp.IsNot: 4, - ast.CmpOp.NotIn: 4, - ast.UnaryOp.UAdd: 11, - ast.UnaryOp.USub: 11, - ast.UnaryOp.Invert: 11, - ast.UnaryOp.Not: 3, -} - - -def precedence(op: Union[ast.BinOp, ast.AugOp, ast.UnaryOp, ast.CmpOp]) -> int: - """Return KCL operator precedence""" - if not op: - return int(OpPrecedence.LOWEST) - - # x ** y -> 12 - if op == ast.BinOp.Pow: - return int(OpPrecedence.HIGHEST) - - # +x, -x, ~x -> 11 - if op == ast.UnaryOp.UAdd or op == ast.UnaryOp.USub or op == ast.UnaryOp.Invert: - return OpPrecedence.HIGHEST - 1 - - # x * y, x / y, x // y, x % y -> 10 - if ( - op == ast.BinOp.Mul - or op == ast.BinOp.Div - or op == ast.BinOp.FloorDiv - or op == ast.BinOp.Mod - ): - return OpPrecedence.HIGHEST - 2 - - # x + y, x - y -> 9 - if op == ast.BinOp.Add or op == ast.BinOp.Sub: - return OpPrecedence.HIGHEST - 3 - - # x >> y, x << y -> 8 - if op == ast.BinOp.LShift or op == ast.BinOp.RShift: - return OpPrecedence.HIGHEST - 4 - - # x & y -> 7 - if op == ast.BinOp.BitAnd: - return OpPrecedence.HIGHEST - 5 - - # x | y -> 6 - if op == ast.BinOp.BitOr: - return OpPrecedence.HIGHEST - 6 - - # x ^ y -> 5 - if op == ast.BinOp.BitXor: - return OpPrecedence.HIGHEST - 7 - - # x > y, x < y, etc. -> 4 - if isinstance(op, ast.CmpOp): - return OpPrecedence.HIGHEST - 8 - - # not x -> 3 - if op == ast.UnaryOp.Not: - return OpPrecedence.HIGHEST - 9 - - # x and y -> 2 - if op == ast.BinOp.And: - return OpPrecedence.HIGHEST - 10 - - # x or y -> 1 - if op == ast.BinOp.Or: - return OpPrecedence.HIGHEST - 11 - - # x = y, x += y, x -= y -> 0 - if isinstance(op, ast.AugOp): - assert OpPrecedence.HIGHEST - 12 == OpPrecedence.LOWEST - return OpPrecedence.HIGHEST - 12 - - return int(OpPrecedence.LOWEST) diff --git a/internal/kclvm_py/kcl/ast/transformer.py b/internal/kclvm_py/kcl/ast/transformer.py deleted file mode 100644 index ac2ba217e..000000000 --- a/internal/kclvm_py/kcl/ast/transformer.py +++ /dev/null @@ -1,69 +0,0 @@ -# Copyright 2020 The KCL Authors. All rights reserved. - -import kclvm.kcl.ast as ast - - -class TreeTransformer(ast.TreeWalker): - """The TreeTransformer subclass that walks the abstract syntax tree and - allows modification of nodes. - - The `TreeTransformer` will walk the AST and use the return value of the - walker methods to replace or remove the old node. If the return value of - the walker method is ``None``, the node will be removed from its location, - otherwise it is replaced with the return value. The return value may be the - original node in which case no replacement takes place. - - Keep in mind that if the node you're operating on has child nodes you must - either transform the child nodes yourself or call the :meth:`generic_walk` - method for the node first. - - For nodes that were part of a collection of statements (that applies to all - statement nodes), the walker may also return a list of nodes rather than - just a single node, e.g., `module` AST contains the `body` attribute, which - is a list of statement - - Example: - - class ChangeSchemaExprNameTransformer(TreeTransformer): - def walk_SchemaExpr(self, t: ast.SchemaExpr): - if t.name.get_name() == 'Person': - t.name.set_name('PersonNew') - return t - - Usually we can use the transformer like this:: - - node = YourTransformer().walk(node) - - """ - - # Base transformer functions - - def get_node_name(self, t: ast.AST): - """Get the ast.AST node name""" - assert isinstance(t, ast.AST) - return t.type - - def generic_walk(self, t: ast.AST): - """Called if no explicit walker function exists for a node.""" - for field, old_value in ast.iter_fields(t): - if isinstance(old_value, list): - new_values = [] - for value in old_value: - if isinstance(value, ast.AST): - value = self.walk(value) - if value is None: - continue - elif not isinstance(value, ast.AST): - new_values.extend(value) - continue - elif isinstance(value, list): - value = [self.walk(v) for v in value] - new_values.append(value) - old_value[:] = new_values - elif isinstance(old_value, ast.AST): - new_node = self.walk(old_value) - if new_node is None: - delattr(t, field) - else: - setattr(t, field, new_node) - return t diff --git a/internal/kclvm_py/kcl/ast/walker.py b/internal/kclvm_py/kcl/ast/walker.py deleted file mode 100644 index 5ba542ee6..000000000 --- a/internal/kclvm_py/kcl/ast/walker.py +++ /dev/null @@ -1,397 +0,0 @@ -# Copyright 2020 The KCL Authors. All rights reserved. - -import typing -from abc import abstractmethod - -import kclvm.kcl.ast as ast - - -class TreeWalker: - """The TreeWalk class can be used as a superclass in order - to walk an AST or similar tree. - - This class is meant to be subclassed, with the subclass adding walker - methods. - - Per default the walker functions for the nodes are ``'walk_'`` + - class name of the node. So a `expr_stmt` node visit function would - be `walk_expr_stmt`. This behavior can be changed by overriding - the `walk` method. If no walker function exists for a node - (return value `None`) the `generic_walker` walker is used instead. - """ - - _WALK_FUNCTION_PREFIX = "walk_" - - def walk(self, node) -> None: - """Visit a node.""" - method = self._WALK_FUNCTION_PREFIX + self.get_node_name(node) - walker = getattr(self, method, self.generic_walk) - return walker(node) - - @abstractmethod - def generic_walk(self, node): - """Called if no explicit walker function exists for a node.""" - pass - - @abstractmethod - def get_node_name(self, node): - """Called if no explicit walker function exists for a node.""" - pass - - -# ----------------------------------------------------------------------------- -# WalkTree -# ----------------------------------------------------------------------------- - - -def _WalkTree( - t: ast.AST, walk_fn: typing.Callable[[ast.AST], typing.Optional[typing.Callable]] -): - if t and callable(walk_fn): - walk_fn = walk_fn(t) - if (not t) or (not callable(walk_fn)): - return - - if isinstance(t, ast.TypeAliasStmt): - return - - if isinstance(t, ast.ExprStmt): - node = typing.cast(ast.ExprStmt, t) - for x in node.exprs or []: - _WalkTree(x, walk_fn) - return - - if isinstance(t, ast.UnificationStmt): - node = typing.cast(ast.UnificationStmt, t) - if node.target: - _WalkTree(node.target, walk_fn) - if node.value: - _WalkTree(node.value, walk_fn) - return - - if isinstance(t, ast.AssignStmt): - node = typing.cast(ast.AssignStmt, t) - for x in node.targets or []: - _WalkTree(x, walk_fn) - if node.value: - _WalkTree(node.value, walk_fn) - return - - if isinstance(t, ast.AugAssignStmt): - node = typing.cast(ast.AugAssignStmt, t) - if node.target: - _WalkTree(node.target, walk_fn) - if node.value: - _WalkTree(node.value, walk_fn) - return - - if isinstance(t, ast.AssertStmt): - node = typing.cast(ast.AssertStmt, t) - if node.test: - _WalkTree(node.test, walk_fn) - if node.if_cond: - _WalkTree(node.if_cond, walk_fn) - if node.msg: - _WalkTree(node.msg, walk_fn) - return - - if isinstance(t, ast.IfStmt): - node = typing.cast(ast.IfStmt, t) - if node.cond: - _WalkTree(node.cond, walk_fn) - for x in node.body or []: - _WalkTree(x, walk_fn) - for x in node.elif_cond or []: - _WalkTree(x, walk_fn) - for if_body in node.elif_body or []: - for x in if_body: - _WalkTree(x, walk_fn) - for x in node.else_body or []: - _WalkTree(x, walk_fn) - return - - if isinstance(t, ast.ImportStmt): - return - - if isinstance(t, ast.SchemaIndexSignature): - node = typing.cast(ast.SchemaIndexSignature, t) - if node.value: - _WalkTree(node.value, walk_fn) - return - - if isinstance(t, ast.SchemaAttr): - node = typing.cast(ast.SchemaAttr, t) - if node.value: - _WalkTree(node.value, walk_fn) - for x in node.decorators or []: - _WalkTree(x, walk_fn) - return - - if isinstance(t, ast.SchemaStmt): - node = typing.cast(ast.SchemaStmt, t) - if node.parent_name: - _WalkTree(node.parent_name, walk_fn) - if node.args: - _WalkTree(node.args, walk_fn) - if node.for_host_name: - _WalkTree(node.for_host_name, walk_fn) - if node.index_signature: - _WalkTree(node.index_signature, walk_fn) - for x in node.mixins or []: - _WalkTree(x, walk_fn) - for x in node.body or []: - _WalkTree(x, walk_fn) - for x in node.decorators or []: - _WalkTree(x, walk_fn) - for x in node.checks or []: - _WalkTree(x, walk_fn) - return - - if isinstance(t, ast.RuleStmt): - node = typing.cast(ast.RuleStmt, t) - for x in node.parent_rules or []: - _WalkTree(x, walk_fn) - for x in node.decorators or []: - _WalkTree(x, walk_fn) - if node.args: - _WalkTree(node.args, walk_fn) - if node.for_host_name: - _WalkTree(node.for_host_name, walk_fn) - for x in node.checks or []: - _WalkTree(x, walk_fn) - return - - if isinstance(t, ast.IfExpr): - node = typing.cast(ast.IfExpr, t) - if node.body: - _WalkTree(node.body, walk_fn) - if node.cond: - _WalkTree(node.cond, walk_fn) - if node.orelse: - _WalkTree(node.orelse, walk_fn) - return - - if isinstance(t, ast.UnaryExpr): - node = typing.cast(ast.UnaryExpr, t) - if node.operand: - _WalkTree(node.operand, walk_fn) - return - - if isinstance(t, ast.BinaryExpr): - node = typing.cast(ast.BinaryExpr, t) - if node.left: - _WalkTree(node.left, walk_fn) - if node.right: - _WalkTree(node.right, walk_fn) - return - - if isinstance(t, ast.SelectorExpr): - node = typing.cast(ast.SelectorExpr, t) - if node.value: - _WalkTree(node.value, walk_fn) - if node.attr: - _WalkTree(node.attr, walk_fn) - return - - if isinstance(t, ast.CallExpr): - node = typing.cast(ast.CallExpr, t) - if node.func: - _WalkTree(node.func, walk_fn) - for x in node.args or []: - _WalkTree(x, walk_fn) - for x in node.keywords or []: - _WalkTree(x, walk_fn) - return - - if isinstance(t, ast.ParenExpr): - node = typing.cast(ast.ParenExpr, t) - _WalkTree(node.expr, walk_fn) - return - - if isinstance(t, ast.QuantExpr): - node = typing.cast(ast.QuantExpr, t) - for var in node.variables: - _WalkTree(var, walk_fn) - if node.target: - _WalkTree(node.target, walk_fn) - if node.test: - _WalkTree(node.test, walk_fn) - if node.if_cond: - _WalkTree(node.if_cond, walk_fn) - return - - if isinstance(t, ast.ListExpr): - node = typing.cast(ast.ListExpr, t) - for x in node.elts or []: - _WalkTree(x, walk_fn) - return - - if isinstance(t, ast.ListComp): - node = typing.cast(ast.ListComp, t) - if node.elt: - _WalkTree(node.elt, walk_fn) - for x in node.generators or []: - _WalkTree(x, walk_fn) - return - - if isinstance(t, ast.ListIfItemExpr): - node = typing.cast(ast.ListIfItemExpr, t) - if node.if_cond: - _WalkTree(node.if_cond, walk_fn) - for expr in node.exprs or []: - _WalkTree(expr, walk_fn) - if node.orelse: - _WalkTree(node.orelse, walk_fn) - return - - if isinstance(t, ast.StarredExpr): - node = typing.cast(ast.StarredExpr, t) - if node.value: - _WalkTree(node.value, walk_fn) - return - - if isinstance(t, ast.ConfigIfEntryExpr): - node = typing.cast(ast.ConfigIfEntryExpr, t) - if node.if_cond: - _WalkTree(node.if_cond, walk_fn) - for key in node.keys or []: - _WalkTree(key, walk_fn) - for value in node.values or []: - _WalkTree(value, walk_fn) - if node.orelse: - _WalkTree(node.orelse, walk_fn) - return - - if isinstance(t, ast.ConfigExpr): - node = typing.cast(ast.ConfigExpr, t) - for x in node.keys or []: - _WalkTree(x, walk_fn) - for x in node.values or []: - _WalkTree(x, walk_fn) - return - - if isinstance(t, ast.DictComp): - node = typing.cast(ast.DictComp, t) - if node.key: - _WalkTree(node.key, walk_fn) - if node.value: - _WalkTree(node.value, walk_fn) - for x in node.generators or []: - _WalkTree(x, walk_fn) - return - - if isinstance(t, ast.CompClause): - node = typing.cast(ast.CompClause, t) - for x in node.targets or []: - _WalkTree(x, walk_fn) - if node.iter: - _WalkTree(node.iter, walk_fn) - for x in node.ifs or []: - _WalkTree(x, walk_fn) - return - - if isinstance(t, ast.SchemaExpr): - node = typing.cast(ast.SchemaExpr, t) - if node.name: - _WalkTree(node.name, walk_fn) - for x in node.args or []: - _WalkTree(x, walk_fn) - for x in node.kwargs or []: - _WalkTree(x, walk_fn) - if node.config: - _WalkTree(node.config, walk_fn) - return - - if isinstance(t, ast.CheckExpr): - node = typing.cast(ast.CheckExpr, t) - if node.test: - _WalkTree(node.test, walk_fn) - if node.if_cond: - _WalkTree(node.if_cond, walk_fn) - if node.msg: - _WalkTree(node.msg, walk_fn) - return - - if isinstance(t, ast.LambdaExpr): - node = typing.cast(ast.LambdaExpr, t) - if node.args: - _WalkTree(node.args, walk_fn) - for x in node.body or []: - _WalkTree(x, walk_fn) - return - - if isinstance(t, ast.Decorator): - node = typing.cast(ast.Decorator, t) - if node.name: - _WalkTree(node.name, walk_fn) - if node.args: - _WalkTree(node.args, walk_fn) - return - - if isinstance(t, ast.Subscript): - node = typing.cast(ast.Subscript, t) - if node.value: - _WalkTree(node.value, walk_fn) - if node.index: - _WalkTree(node.index, walk_fn) - if node.lower: - _WalkTree(node.lower, walk_fn) - if node.upper: - _WalkTree(node.upper, walk_fn) - if node.step: - _WalkTree(node.step, walk_fn) - return - - if isinstance(t, ast.Keyword): - node = typing.cast(ast.Keyword, t) - if node.arg: - _WalkTree(node.arg, walk_fn) - if node.value: - _WalkTree(node.value, walk_fn) - return - - if isinstance(t, ast.Arguments): - node = typing.cast(ast.Arguments, t) - for x in node.args or []: - _WalkTree(x, walk_fn) - for x in node.defaults or []: - _WalkTree(x, walk_fn) - return - - if isinstance(t, ast.Compare): - node = typing.cast(ast.Compare, t) - if node.left: - _WalkTree(node.left, walk_fn) - for x in node.comparators or []: - _WalkTree(x, walk_fn) - return - - if isinstance(t, ast.Identifier): - _ = typing.cast(ast.Identifier, t) - return - - if isinstance(t, ast.Literal): - _ = typing.cast(ast.Literal, t) - return - if isinstance(t, ast.JoinedString): - node = typing.cast(ast.JoinedString, t) - for x in node.values or []: - _WalkTree(x, walk_fn) - return - if isinstance(t, ast.FormattedValue): - node = typing.cast(ast.FormattedValue, t) - if node.value: - _WalkTree(node.value, walk_fn) - return - - if isinstance(t, ast.Module): - node = typing.cast(ast.Module, t) - for x in node.body or []: - _WalkTree(x, walk_fn) - return - - assert False, f"_WalkTree: t = {t}" - - -def WalkTree(m: ast.AST, walk_fn: typing.Callable[[ast.AST], None]): - _WalkTree(m, walk_fn) diff --git a/internal/kclvm_py/kcl/error/__init__.py b/internal/kclvm_py/kcl/error/__init__.py deleted file mode 100644 index c53bc2c48..000000000 --- a/internal/kclvm_py/kcl/error/__init__.py +++ /dev/null @@ -1,107 +0,0 @@ -# Copyright 2021 The KCL Authors. All rights reserved. - -from .kcl_error import ( - KCLError, - KCLException, - KCLSyntaxException, - KCLRuntimeException, - KCLCompileException, - KCLTypeException, - UnKnownDecoratorError, - DeprecatedError, - InvalidDecoratorTargetError, - KCLNameError, - TypeRuntimeError, - EvaluationError, - KCLTabError, - InvalidSyntaxError, - CompileError, - CannotFindModule, - print_kcl_error_message, - print_kcl_warning_message, - print_common_error_message, - print_internal_error_message, - report_exception, - report_warning, - get_exception, - ErrType, -) - -from .kcl_err_theme import KCLErrMsgTheme, KCLErrMsgThemeDefault - -from .kcl_err_template import ( - ErrLevel, - ErrFileMsg, - FileCache, -) - -from .kcl_err_msg import ( - ErrEwcode, - KCL_ERR_MSG, - INT_OVER_FLOW_MSG, - FLOAT_OVER_FLOW_MSG, - FLOAT_UNDER_FLOW_MSG, - DEPRECATED_WARNING_MSG, - SCHEMA_CHECK_FILE_MSG_ERR, - SCHEMA_CHECK_FILE_MSG_COND, - RECURSIVE_LOADING_MODULE_MSG, - CANNOT_FIND_MODULE_MSG, - UNIQUE_KEY_MSG, - CANNOT_ADD_MEMBERS_MSG, - MULTI_INHERIT_MSG, - INDENTATION_ERROR_MSG, - UNKNOWN_DECORATOR_MSG, - INVALID_DECORATOR_TARGET_MSG, - NAME_ERROR_MSG, - INVALID_FORMAT_SPEC_MSG, -) - -__all__ = [ - "ErrLevel", - "report_exception", - "report_warning", - "ErrType", - "get_exception", - "INT_OVER_FLOW_MSG", - "FLOAT_OVER_FLOW_MSG", - "FLOAT_UNDER_FLOW_MSG", - "DEPRECATED_WARNING_MSG", - "SCHEMA_CHECK_FILE_MSG_ERR", - "SCHEMA_CHECK_FILE_MSG_COND", - "UNIQUE_KEY_MSG", - "CANNOT_ADD_MEMBERS_MSG", - "RECURSIVE_LOADING_MODULE_MSG", - "CANNOT_FIND_MODULE_MSG", - "MULTI_INHERIT_MSG", - "INDENTATION_ERROR_MSG", - "UNKNOWN_DECORATOR_MSG", - "INVALID_DECORATOR_TARGET_MSG", - "NAME_ERROR_MSG", - "INVALID_FORMAT_SPEC_MSG", - "ErrFileMsg", - "ErrEwcode", - "print_kcl_error_message", - "print_kcl_warning_message", - "print_common_error_message", - "print_internal_error_message", - "KCLException", - "KCLSyntaxException", - "KCLCompileException", - "KCLRuntimeException", - "KCLTypeException", - "UnKnownDecoratorError", - "InvalidDecoratorTargetError", - "KCLNameError", - "TypeRuntimeError", - "EvaluationError", - "KCLError", - "DeprecatedError", - "KCLTabError", - "InvalidSyntaxError", - "CompileError", - "CannotFindModule", - "KCLErrMsgTheme", - "KCLErrMsgThemeDefault", - "KCL_ERR_MSG", - "FileCache", -] diff --git a/internal/kclvm_py/kcl/error/kcl_err_msg.py b/internal/kclvm_py/kcl/error/kcl_err_msg.py deleted file mode 100644 index c5c71627f..000000000 --- a/internal/kclvm_py/kcl/error/kcl_err_msg.py +++ /dev/null @@ -1,613 +0,0 @@ -""" -The `kcl_err_msg` file mainly contains constants used in KCL error messages. - -INT_OVER_FLOW_MSG: String constants ending with "_MSG" are the recommended string template when raising KCL exceptions. - -ErrEwcode: All ewcodes for KCL exception. - -ErrMsgContent_EN: A dict for kcl exception message, - = - -ErrArgMsgDefault_EN: A dict for default arguments provided when a kcl exception is raised, - = - -ErrName_EN: A dict for kcl exception names, - = - -KCLErrMsgManager: A singleton class that encapsulates some methods of obtaining KCL exception information - -:copyright: Copyright 2020 The KCL Authors. All rights reserved. -""" -import sys -from abc import ABCMeta, abstractmethod -from kclvm.internal.util import PreCheck, CheckRules, PostCheck -from kclvm.internal.util.check_utils import PostSimpleExprCheck - -ERROR = "E" -WARNING = "W" - -SYNTAX = "1" -COMPLIER = "2" -RUNTIME = "3" - -ATTRIBUTE = "A" -SCHEMA = "B" -MIXIN = "C" -INHERIT = "D" -IMPORT = "F" -TYPE = "G" -DECORATOR = "H" -ARGUMENT = "I" -OVERFLOW = "K" -COMPLING = "L" -RUNNING = "M" -DEPRECATED = "N" -DOC = "P" -IMMUTABLE = "Q" - -INT_OVER_FLOW_MSG = "{}: A {} bit integer overflow" -FLOAT_OVER_FLOW_MSG = "{}: A {}-bit floating point number overflow" -FLOAT_UNDER_FLOW_MSG = "{}: A {}-bit floating point number underflow" -DEPRECATED_WARNING_MSG = "{} was deprecated {}" - -SCHEMA_CHECK_FILE_MSG_ERR = "Instance check failed" -SCHEMA_CHECK_FILE_MSG_COND = "Check failed on the condition" - -UNIQUE_KEY_MSG = "Variable name '{}' must be unique in package context" -CANNOT_ADD_MEMBERS_MSG = "{}: No such member in the schema '{}'" -RECURSIVE_LOADING_MODULE_MSG = "In module {}, recursively loading modules: {}" -CANNOT_FIND_MODULE_MSG = "Cannot find the module {} from {}" -MULTI_INHERIT_MSG = "Multiple inheritance of {} is prohibited" -INDENTATION_ERROR_MSG = "Unindent {} does not match any outer indentation level" -UNKNOWN_DECORATOR_MSG = "UnKnown decorator {}" -INVALID_DECORATOR_TARGET_MSG = "Invalid decorator target {}" -NAME_ERROR_MSG = "Name error {}" -INVALID_FORMAT_SPEC_MSG = "{} is invalid format spec" - - -class ErrEwcode: - KCLException_Ew = "00000" # 00000 - KCLError_Ew = ERROR + "0000" # E0000 - KCLWarning_Ew = WARNING + "0000" # W0000 - - KCLSyntaxException_Ew = "0" + SYNTAX + "000" # 01000 - KCLCompileException_Ew = "0" + COMPLIER + "000" # 02000 - KCLRuntimeException_Ew = "0" + RUNTIME + "000" # 03000 - - KCLAttributeException_Ew = "00" + ATTRIBUTE + "00" # 00A00 - KCLSchemaException_Ew = "00" + SCHEMA + "00" # 00B00 - KCLMixinException_Ew = "00" + MIXIN + "00" # 00C00 - KCLInheritException_Ew = "00" + INHERIT + "00" # 00D00 - KCLImportException_Ew = "00" + IMPORT + "00" # 00F00 - KCLTypeException_Ew = "00" + TYPE + "00" # 00G00 - KCLDecoratorException_Ew = "00" + DECORATOR + "00" # 00H00 - KCLArgumentException_Ew = "00" + ARGUMENT + "00" # 00I00 - KCLOverflowException_Ew = "00" + OVERFLOW + "00" # 00K00 - KCLComplingException_Ew = "00" + COMPLING + "00" # 00L00 - KCLRunningException_Ew = "00" + RUNNING + "00" # 00M00 - KCLDeprecatedException_Ew = "00" + DEPRECATED + "00" # 00N00 - KCLDocException_Ew = "00" + DOC + "00" # 00P00 - KCLImmutableException_Ew = "00" + IMMUTABLE + "00" # 00Q00 - - InvalidSyntax_Ew = ERROR + SYNTAX + "001" # E1001 - KCLTabError_Ew = ERROR + SYNTAX + "002" # E1002 - KCLIndentationError_Ew = ERROR + SYNTAX + "003" # E1003 - - CannotFindModule_Ew = ERROR + COMPLIER + IMPORT + "04" # E2F04 - FailedLoadModule_Ew = ERROR + COMPLIER + IMPORT + "05" # E2F05 - RecursiveLoad_Ew = ERROR + COMPLIER + IMPORT + "06" # E3F06 - - FloatOverflow_Ew = ERROR + RUNTIME + OVERFLOW + "07" # E3K04 - FloatUnderflow_Ew = WARNING + COMPLIER + OVERFLOW + "08" # W2K08 - IntOverflow_Ew = ERROR + RUNTIME + OVERFLOW + "09" # E3K09 - - InvalidDocstring_Ew = WARNING + COMPLIER + DOC + "10" # W2P10 - - Deprecated_Ew = ERROR + RUNTIME + DEPRECATED + "11" # E3N11 - DeprecatedWarning_Ew = WARNING + COMPLIER + DEPRECATED + "12" # W2N12 - - UnKnownDecorator_Ew = ERROR + COMPLIER + DECORATOR + "13" # E2H13 - InvalidDecoratorTarget_Ew = ERROR + COMPLIER + DECORATOR + "14" # E2H14 - - MixinNamingError_Ew = ERROR + COMPLIER + MIXIN + "15" # E2C15 - MixinStructureIllegal_Ew = ERROR + COMPLIER + MIXIN + "16" # E2C16 - - SchemaCheckFailure_Ew = ERROR + RUNTIME + SCHEMA + "17" # E3B17 - CannotAddMembersComplieError_Ew = ERROR + COMPLIER + SCHEMA + "18" # E2B17 - CannotAddMembersRuntimeError_Ew = ERROR + RUNTIME + SCHEMA + "19" # E3B19 - IndexSignatureError_Ew = ERROR + COMPLIER + SCHEMA + "20" # E2B20 - - TypeRuntimeError_Ew = ERROR + RUNTIME + TYPE + "21" # E3G21 - TypeComplieError_Ew = ERROR + COMPLIER + TYPE + "22" # E2G22 - - CompileError_Ew = ERROR + COMPLIER + COMPLING + "23" # E2L23 - SelectorError_Ew = ERROR + COMPLIER + COMPLING + "24" # E2L24 - KCLNameError_Ew = ERROR + COMPLIER + COMPLING + "25" # E2L25 - KCLValueError_Ew = ERROR + COMPLIER + COMPLING + "26" # E2L26 - KCLKeyError_Ew = ERROR + COMPLIER + COMPLING + "27" # E2L27 - UniqueKeyError_Ew = ERROR + COMPLIER + COMPLING + "28" # E2L28 - - KCLAttributeComplieError_Ew = ERROR + COMPLIER + ATTRIBUTE + "29" # E2A29 - KCLAttributeRuntimeError_Ew = ERROR + RUNTIME + ATTRIBUTE + "30" # E3A30 - IllegalAttributeError_Ew = ERROR + COMPLIER + ATTRIBUTE + "31" # E2A31 - - MultiInheritError_Ew = ERROR + COMPLIER + INHERIT + "32" # E2D32 - CycleInheritError_Ew = ERROR + COMPLIER + INHERIT + "33" # E2D33 - IllegalInheritError_Ew = ERROR + COMPLIER + INHERIT + "34" # E2D34 - - IllegalArgumentRuntimeError_Ew = ERROR + RUNTIME + ARGUMENT + "35" # E3I35 - IllegalArgumentComplieError_Ew = ERROR + COMPLIER + ARGUMENT + "36" # E2I36 - IllegalArgumentSyntaxError_Ew = ERROR + SYNTAX + ARGUMENT + "37" # E1I37 - - EvaluationError_Ew = ERROR + RUNTIME + RUNNING + "38" # E3M38 - InvalidFormatSpec_Ew = ERROR + RUNTIME + RUNNING + "39" # E3M39 - KCLAssertionError_Ew = ERROR + RUNTIME + RUNNING + "40" # E3M40 - - ImmutableCompileError_Ew = ERROR + COMPLIER + COMPLING + "41" # E3L41 - KCLRecursionError_Ew = ERROR + RUNTIME + RUNNING + "42" # E3M42 - PlanError_Ew = ERROR + RUNTIME + RUNNING + "43" # E3M43 - ImmutableRuntimeError_Ew = ERROR + RUNTIME + RUNNING + "44" # E3M44 - - @staticmethod - def contains(ewcode: str): - return ewcode in ErrEwcode.__dict__.values() - - -ErrMsgContent_EN: dict = { - ErrEwcode.KCLException_Ew: "Exception", - ErrEwcode.KCLError_Ew: "Error", - ErrEwcode.KCLWarning_Ew: "Warning", - ErrEwcode.KCLSyntaxException_Ew: "Syntax", - ErrEwcode.KCLCompileException_Ew: "Compile", - ErrEwcode.KCLRuntimeException_Ew: "Runtime", - ErrEwcode.KCLAttributeException_Ew: "An attribute exception occurs", - ErrEwcode.KCLSchemaException_Ew: "A schema exception occurs", - ErrEwcode.KCLMixinException_Ew: "A mixin exception occurs", - ErrEwcode.KCLInheritException_Ew: "An inherit exception occurs", - ErrEwcode.KCLImportException_Ew: "An import exception occurs", - ErrEwcode.KCLTypeException_Ew: "A type exception occurs", - ErrEwcode.KCLDecoratorException_Ew: "A decorator exception occurs", - ErrEwcode.KCLArgumentException_Ew: "An argument exception occurs", - ErrEwcode.KCLOverflowException_Ew: "An overflow exception occurs", - ErrEwcode.KCLComplingException_Ew: "An compling exception occurs", - ErrEwcode.KCLRunningException_Ew: "An running exception occurs", - ErrEwcode.KCLDeprecatedException_Ew: "A deprecated exception occurs", - ErrEwcode.KCLDocException_Ew: "A doc exception occurs", - ErrEwcode.KCLImmutableException_Ew: "A Immutable exception occurs", - ErrEwcode.InvalidSyntax_Ew: "Invalid syntax", - ErrEwcode.KCLTabError_Ew: "Tab Error", - ErrEwcode.KCLIndentationError_Ew: "Indentation Error", - ErrEwcode.CannotFindModule_Ew: "Cannot find the module", - ErrEwcode.FailedLoadModule_Ew: "Failed to load module", - ErrEwcode.RecursiveLoad_Ew: "Recursively loading module", - ErrEwcode.FloatOverflow_Ew: "Float overflow", - ErrEwcode.FloatUnderflow_Ew: "Float underflow", - ErrEwcode.IntOverflow_Ew: "Integer overflow", - ErrEwcode.InvalidDocstring_Ew: "Invalid docstring", - ErrEwcode.Deprecated_Ew: "Deprecated error", - ErrEwcode.DeprecatedWarning_Ew: "Deprecated warning", - ErrEwcode.UnKnownDecorator_Ew: "UnKnown decorator", - ErrEwcode.InvalidDecoratorTarget_Ew: "Invalid Decorator Target", - ErrEwcode.MixinNamingError_Ew: "Illegal mixin naming", - ErrEwcode.MixinStructureIllegal_Ew: "Illegal mixin structure", - ErrEwcode.SchemaCheckFailure_Ew: "Schema check is failed to check condition", - ErrEwcode.CannotAddMembersComplieError_Ew: "Cannot add members to a schema", - ErrEwcode.CannotAddMembersRuntimeError_Ew: "Cannot add members to a schema", - ErrEwcode.IndexSignatureError_Ew: "Invalid index signature", - ErrEwcode.TypeRuntimeError_Ew: "The type got is inconsistent with the type expected", - ErrEwcode.TypeComplieError_Ew: "The type got is inconsistent with the type expected", - ErrEwcode.CompileError_Ew: "A complie error occurs during compiling", - ErrEwcode.SelectorError_Ew: "Selector Error", - ErrEwcode.KCLNameError_Ew: "Name Error", - ErrEwcode.KCLValueError_Ew: "Value Error", - ErrEwcode.KCLKeyError_Ew: "Key Error", - ErrEwcode.UniqueKeyError_Ew: "Unique key error", - ErrEwcode.KCLAttributeComplieError_Ew: "Attribute error occurs during compiling", - ErrEwcode.KCLAttributeRuntimeError_Ew: "Attribute error occurs at runtime", - ErrEwcode.IllegalAttributeError_Ew: "Illegal attribute", - ErrEwcode.MultiInheritError_Ew: "Multiple inheritance is illegal", - ErrEwcode.CycleInheritError_Ew: "Cycle Inheritance is illegal", - ErrEwcode.IllegalInheritError_Ew: "Illegal inheritance", - ErrEwcode.IllegalArgumentRuntimeError_Ew: "Illegal command line argument at runtime", - ErrEwcode.IllegalArgumentComplieError_Ew: "Illegal argument during compiling", - ErrEwcode.IllegalArgumentSyntaxError_Ew: "Illegal argument syntax", - ErrEwcode.EvaluationError_Ew: "Evaluation failure", - ErrEwcode.InvalidFormatSpec_Ew: "Invalid format specification", - ErrEwcode.KCLAssertionError_Ew: "Assertion failure", - ErrEwcode.ImmutableCompileError_Ew: "Immutable variable is modified during compiling", - ErrEwcode.ImmutableRuntimeError_Ew: "Immutable variable is modified at runtime", - ErrEwcode.KCLRecursionError_Ew: "Recursively reference", - ErrEwcode.PlanError_Ew: "Plan Error", -} - -ErrArgMsgDefault_EN: dict = { - ErrEwcode.KCLException_Ew: "Exception", - ErrEwcode.KCLError_Ew: "Error", - ErrEwcode.KCLWarning_Ew: "Warning", - ErrEwcode.KCLSyntaxException_Ew: "Syntax", - ErrEwcode.KCLCompileException_Ew: "Complie", - ErrEwcode.KCLRuntimeException_Ew: "Runtime", - ErrEwcode.KCLAttributeException_Ew: "An attribute exception occurs", - ErrEwcode.KCLSchemaException_Ew: "A schema exception occurs", - ErrEwcode.KCLMixinException_Ew: "A mixin exception occurs", - ErrEwcode.KCLInheritException_Ew: "An inherit exception occurs", - ErrEwcode.KCLImportException_Ew: "An import exception occurs", - ErrEwcode.KCLTypeException_Ew: "A type exception occurs", - ErrEwcode.KCLDecoratorException_Ew: "A decorator exception occurs", - ErrEwcode.KCLArgumentException_Ew: "An argument exception occurs", - ErrEwcode.KCLOverflowException_Ew: "An overflow exception occurs", - ErrEwcode.KCLComplingException_Ew: "An compling exception occurs", - ErrEwcode.KCLRunningException_Ew: "An running exception occurs", - ErrEwcode.KCLDeprecatedException_Ew: "A deprecated exception occurs", - ErrEwcode.KCLDocException_Ew: "A doc exception occurs", - ErrEwcode.KCLImmutableException_Ew: "A Immutable exception occurs", - ErrEwcode.InvalidSyntax_Ew: "Invalid syntax", - ErrEwcode.KCLTabError_Ew: "Inconsistent use of tabs and spaces in indentation", - ErrEwcode.KCLIndentationError_Ew: "Indentation Error", - ErrEwcode.CannotFindModule_Ew: "Cannot find the module", - ErrEwcode.FailedLoadModule_Ew: "Failed to load module", - ErrEwcode.RecursiveLoad_Ew: "Recursively loading module", - ErrEwcode.FloatOverflow_Ew: "Float overflow", - ErrEwcode.FloatUnderflow_Ew: "Float underflow", - ErrEwcode.IntOverflow_Ew: "Integer overflow", - ErrEwcode.InvalidDocstring_Ew: "Invalid docstring", - ErrEwcode.Deprecated_Ew: "Deprecated error", - ErrEwcode.DeprecatedWarning_Ew: "Deprecated warning", - ErrEwcode.UnKnownDecorator_Ew: "UnKnown decorator", - ErrEwcode.InvalidDecoratorTarget_Ew: "Invalid Decorator Target", - ErrEwcode.MixinNamingError_Ew: "Illegal mixin naming", - ErrEwcode.MixinStructureIllegal_Ew: "Illegal mixin structure", - ErrEwcode.SchemaCheckFailure_Ew: "Check failed on check conditions", - ErrEwcode.CannotAddMembersComplieError_Ew: "Cannot add members to a schema", - ErrEwcode.CannotAddMembersRuntimeError_Ew: "Cannot add members to a schema", - ErrEwcode.IndexSignatureError_Ew: "Invalid index signature", - ErrEwcode.TypeRuntimeError_Ew: "The type got is inconsistent with the type expected", - ErrEwcode.TypeComplieError_Ew: "The type got is inconsistent with the type expected", - ErrEwcode.CompileError_Ew: "A complie error occurs during compiling", - ErrEwcode.SelectorError_Ew: "Selector Error", - ErrEwcode.KCLNameError_Ew: "Name Error", - ErrEwcode.KCLValueError_Ew: "Value Error", - ErrEwcode.KCLKeyError_Ew: "Key Error", - ErrEwcode.UniqueKeyError_Ew: "Unique key error", - ErrEwcode.KCLAttributeComplieError_Ew: "Attribute error occurs during compiling", - ErrEwcode.KCLAttributeRuntimeError_Ew: "Attribute error occurs at runtime", - ErrEwcode.IllegalAttributeError_Ew: "Illegal attribute", - ErrEwcode.MultiInheritError_Ew: "Multiple inheritance is illegal", - ErrEwcode.CycleInheritError_Ew: "Cycle Inheritance is illegal", - ErrEwcode.IllegalInheritError_Ew: "Illegal inheritance", - ErrEwcode.IllegalArgumentRuntimeError_Ew: "Illegal command line argument at runtime", - ErrEwcode.IllegalArgumentComplieError_Ew: "Illegal argument during compiling", - ErrEwcode.IllegalArgumentSyntaxError_Ew: "Illegal argument syntax", - ErrEwcode.EvaluationError_Ew: "Evaluation failure", - ErrEwcode.InvalidFormatSpec_Ew: "Invalid format specification", - ErrEwcode.KCLAssertionError_Ew: "Assertion failure", - ErrEwcode.ImmutableCompileError_Ew: "Immutable variable is modified during compiling", - ErrEwcode.ImmutableRuntimeError_Ew: "Immutable variable is modified at runtime", - ErrEwcode.KCLRecursionError_Ew: "maximum recursion depth exceeded", - ErrEwcode.PlanError_Ew: "Plan Error", -} - -ErrName_EN: dict = { - ErrEwcode.KCLException_Ew: "KCLException", - ErrEwcode.KCLError_Ew: "KCLError", - ErrEwcode.KCLWarning_Ew: "KCLWarning", - ErrEwcode.KCLSyntaxException_Ew: "KCLSyntaxException", - ErrEwcode.KCLCompileException_Ew: "KCLCompileException", - ErrEwcode.KCLRuntimeException_Ew: "KCLRuntimeException", - ErrEwcode.KCLAttributeException_Ew: "KCLAttributeException", - ErrEwcode.KCLSchemaException_Ew: "KCLSchemaException", - ErrEwcode.KCLMixinException_Ew: "KCLMixinException", - ErrEwcode.KCLInheritException_Ew: "KCLInheritException", - ErrEwcode.KCLImportException_Ew: "KCLImportException", - ErrEwcode.KCLTypeException_Ew: "KCLTypeException", - ErrEwcode.KCLDecoratorException_Ew: "KCLDecoratorException", - ErrEwcode.KCLArgumentException_Ew: "KCLArgumentException", - ErrEwcode.KCLOverflowException_Ew: "KCLOverflowException", - ErrEwcode.KCLComplingException_Ew: "KCLComplingException", - ErrEwcode.KCLRunningException_Ew: "KCLRunningException", - ErrEwcode.KCLDeprecatedException_Ew: "KCLDeprecatedException", - ErrEwcode.KCLDocException_Ew: "KCLDocException", - ErrEwcode.KCLImmutableException_Ew: "KCLImmutableException", - ErrEwcode.InvalidSyntax_Ew: "InvalidSyntax", - ErrEwcode.KCLTabError_Ew: "KCLTabError", - ErrEwcode.KCLIndentationError_Ew: "KCLIndentationError", - ErrEwcode.CannotFindModule_Ew: "CannotFindModule", - ErrEwcode.FailedLoadModule_Ew: "FailedLoadModule", - ErrEwcode.RecursiveLoad_Ew: "RecursiveLoad", - ErrEwcode.FloatOverflow_Ew: "FloatOverflow", - ErrEwcode.FloatUnderflow_Ew: "FloatUnderflow", - ErrEwcode.IntOverflow_Ew: "IntOverflow", - ErrEwcode.InvalidDocstring_Ew: "InvalidDocstring", - ErrEwcode.Deprecated_Ew: "Deprecated", - ErrEwcode.DeprecatedWarning_Ew: "DeprecatedWarning", - ErrEwcode.UnKnownDecorator_Ew: "UnKnownDecorator", - ErrEwcode.InvalidDecoratorTarget_Ew: "InvalidDecoratorTarget", - ErrEwcode.MixinNamingError_Ew: "MixinNamingError", - ErrEwcode.MixinStructureIllegal_Ew: "MixinStructureIllegal", - ErrEwcode.SchemaCheckFailure_Ew: "SchemaCheckFailure", - ErrEwcode.CannotAddMembersComplieError_Ew: "CannotAddMembersComplieError", - ErrEwcode.CannotAddMembersRuntimeError_Ew: "CannotAddMembersRuntimeError", - ErrEwcode.IndexSignatureError_Ew: "IndexSignatureError", - ErrEwcode.TypeRuntimeError_Ew: "TypeRuntimeError", - ErrEwcode.TypeComplieError_Ew: "TypeComplieError", - ErrEwcode.CompileError_Ew: "CompileError", - ErrEwcode.SelectorError_Ew: "SelectorError", - ErrEwcode.KCLNameError_Ew: "KCLNameError", - ErrEwcode.KCLValueError_Ew: "KCLValueError", - ErrEwcode.KCLKeyError_Ew: "KCLKeyError", - ErrEwcode.UniqueKeyError_Ew: "UniqueKeyError", - ErrEwcode.KCLAttributeComplieError_Ew: "KCLAttributeComplieError", - ErrEwcode.KCLAttributeRuntimeError_Ew: "KCLAttributeRuntimeError", - ErrEwcode.IllegalAttributeError_Ew: "IllegalAttributeError", - ErrEwcode.MultiInheritError_Ew: "MultiInheritError", - ErrEwcode.CycleInheritError_Ew: "CycleInheritError", - ErrEwcode.IllegalInheritError_Ew: "IllegalInheritError", - ErrEwcode.IllegalArgumentRuntimeError_Ew: "IllegalArgumentRuntimeError", - ErrEwcode.IllegalArgumentComplieError_Ew: "IllegalArgumentComplieError", - ErrEwcode.IllegalArgumentSyntaxError_Ew: "IllegalArgumentSyntaxError", - ErrEwcode.EvaluationError_Ew: "EvaluationError", - ErrEwcode.InvalidFormatSpec_Ew: "InvalidFormatSpec", - ErrEwcode.KCLAssertionError_Ew: "KCLAssertionError", - ErrEwcode.ImmutableCompileError_Ew: "ImmutableCompileError", - ErrEwcode.ImmutableRuntimeError_Ew: "ImmutableRuntimeError", - ErrEwcode.KCLRecursionError_Ew: "KCLRecursionError", - ErrEwcode.PlanError_Ew: "PlanError", -} - - -class ErrMsgLang: - EN_US_UTF_8 = "c.utf8" - - -class ErrMsg(metaclass=ABCMeta): - @abstractmethod - def get_defaule_ewcode(self) -> str: - pass - - @abstractmethod - def get_err_cate_ewcode(self, err_id: str) -> str: - pass - - @abstractmethod - def get_err_type_ewcode(self, err_id: str) -> str: - pass - - @abstractmethod - def get_err_cate_msg_by_errid(self, err_id: str) -> str: - pass - - @abstractmethod - def get_err_type_msg_by_errid(self, err_id: str) -> str: - pass - - @abstractmethod - def get_err_msg_by_errid(self, err_id: str) -> str: - pass - - @abstractmethod - def get_defaule_arg_msg_by_errid(self, err_id: str) -> str: - pass - - @abstractmethod - def get_err_code_by_errid(self, err_id: str) -> str: - pass - - @abstractmethod - def is_warning(self, err_id: str) -> bool: - pass - - @abstractmethod - def is_syntax_error(self, err_id: str) -> bool: - pass - - @abstractmethod - def is_compiler_error(self, err_id: str) -> bool: - pass - - @abstractmethod - def is_runtime_error(self, err_id: str) -> bool: - pass - - @abstractmethod - def get_err_name_by_ewcode(self, err_id: str): - pass - - -class KCLErrMsg_EN(ErrMsg): - @PostCheck(lambda result: ErrEwcode.contains(result)) - def get_defaule_ewcode(self) -> str: - return ErrEwcode.KCLException_Ew - - @PreCheck((lambda v: ErrEwcode.contains(v)), "err_id") - @PostCheck(lambda result: ErrEwcode.contains(result)) - @PostSimpleExprCheck( - (lambda inputs, result: result == inputs["err_id"][:1] + "0000"), ["err_id"] - ) - def get_err_cate_ewcode(self, err_id: str) -> str: - return err_id[:1] + "0000" - - @PreCheck((lambda v: ErrEwcode.contains(v)), "err_id") - @PostCheck(lambda result: ErrEwcode.contains(result)) - @PostSimpleExprCheck( - (lambda inputs, result: result == "0" + inputs["err_id"][1:2] + "000"), - ["err_id"], - ) - def get_err_type_ewcode(self, err_id: str) -> str: - return "0" + err_id[1:2] + "000" - - @PreCheck((lambda v: ErrEwcode.contains(v)), "err_id") - @PostCheck(lambda result: result in ErrMsgContent_EN.values()) - def get_err_cate_msg_by_errid(self, err_id: str) -> str: - return ErrMsgContent_EN[self.get_err_cate_ewcode(err_id)] - - @PreCheck((lambda v: ErrEwcode.contains(v)), "err_id") - @PostCheck(lambda result: result in ErrMsgContent_EN.values()) - def get_err_type_msg_by_errid(self, err_id: str) -> str: - return ErrMsgContent_EN[self.get_err_type_ewcode(err_id)] - - @PreCheck((lambda v: ErrEwcode.contains(v)), "err_id") - @PostCheck(lambda result: result in ErrMsgContent_EN.values()) - def get_err_msg_by_errid(self, err_id: str) -> str: - return ErrMsgContent_EN[err_id] - - @PreCheck((lambda v: ErrEwcode.contains(v)), "err_id") - @PostCheck(lambda result: result in ErrArgMsgDefault_EN.values()) - def get_defaule_arg_msg_by_errid(self, err_id: str) -> str: - return ErrArgMsgDefault_EN[err_id] - - @PreCheck((lambda v: ErrEwcode.contains(v)), "err_id") - @PostCheck(lambda result: CheckRules.check_type_not_none(result, str)) - @PostSimpleExprCheck( - (lambda inputs, result: result == "[" + inputs["err_id"] + "]"), ["err_id"] - ) - def get_err_code_by_errid(self, err_id: str) -> str: - return "[" + err_id + "]" - - @PreCheck((lambda v: ErrEwcode.contains(v)), "err_id") - @PostCheck(lambda result: CheckRules.check_type_not_none(result, bool)) - def is_warning(self, err_id: str) -> bool: - return err_id[:1] == WARNING - - @PreCheck((lambda v: ErrEwcode.contains(v)), "err_id") - @PostCheck(lambda result: CheckRules.check_type_not_none(result, bool)) - def is_syntax_error(self, err_id: str) -> bool: - return err_id[1:2] == SYNTAX - - @PreCheck((lambda v: ErrEwcode.contains(v)), "err_id") - @PostCheck(lambda result: CheckRules.check_type_not_none(result, bool)) - def is_compiler_error(self, err_id: str) -> bool: - return err_id[1:2] == COMPLIER - - @PreCheck((lambda v: ErrEwcode.contains(v)), "err_id") - @PostCheck(lambda result: CheckRules.check_type_not_none(result, bool)) - def is_runtime_error(self, err_id: str) -> bool: - return err_id[1:2] == RUNTIME - - @PreCheck((lambda v: ErrEwcode.contains(v)), "err_id") - @PostCheck(lambda result: result in ErrName_EN.values()) - def get_err_name_by_ewcode(self, err_id: str) -> str: - return ErrName_EN[err_id] - - -class KCLErrMsgManager(ErrMsg): - _instance = None - - def __new__(cls): - if cls._instance is None: - cls._instance = object.__new__(cls) - return cls._instance - - def __init__(self, lang: ErrMsgLang = ErrMsgLang.EN_US_UTF_8): - self.ALL_KCL_ERROR_MSGS: dict = {ErrMsgLang.EN_US_UTF_8: KCLErrMsg_EN()} - self.lang = lang - self.KCL_ERROR_MSG = self.ALL_KCL_ERROR_MSGS[self.lang] - - @PreCheck((lambda v: CheckRules.check_locale(v)), "lang") - def switch_lang(self, lang: str): - try: - self.KCL_ERROR_MSG = self.ALL_KCL_ERROR_MSGS[lang] - except KeyError: - print( - f"KCLVM does not support '{lang}', " - f"KCLVM have automatically switched to {ErrMsgLang.EN_US_UTF_8}", - file=sys.stderr, - ) - self.lang = ErrMsgLang.EN_US_UTF_8 - self.KCL_ERROR_MSG = self.ALL_KCL_ERROR_MSGS[self.lang] - - @PreCheck((lambda v: CheckRules.check_type_not_none(v, ErrMsg)), "err_msg") - @PreCheck((lambda v: CheckRules.check_locale(v)), "lang") - def append_lang(self, lang: str, err_msg: ErrMsg): - if lang in self.ALL_KCL_ERROR_MSGS.keys(): - print( - f"KCLVM currently supports {lang}, " - f"If you want to change the language pack, " - f"please use the method update_lang", - file=sys.stderr, - ) - return - else: - self.ALL_KCL_ERROR_MSGS[lang] = err_msg - - @PreCheck((lambda v: CheckRules.check_type_not_none(v, ErrMsg)), "err_msg") - @PreCheck((lambda v: CheckRules.check_locale(v)), "lang") - def update_lang(self, lang: str, err_msg: ErrMsg): - self.ALL_KCL_ERROR_MSGS[lang] = err_msg - - @PostCheck(lambda result: CheckRules.check_type_not_none(result, str)) - @PostCheck(lambda result: result == ErrEwcode.KCLException_Ew) - def get_defaule_ewcode(self) -> str: - return self.KCL_ERROR_MSG.get_defaule_ewcode() - - @PreCheck((lambda v: ErrEwcode.contains(v)), "err_id") - @PostCheck(lambda result: CheckRules.check_type_not_none(result, str)) - @PostSimpleExprCheck( - (lambda inputs, result: result == inputs["err_id"][:1] + "0000"), ["err_id"] - ) - def get_err_cate_ewcode(self, err_id: str) -> str: - return self.KCL_ERROR_MSG.get_err_cate_ewcode(err_id) - - @PreCheck((lambda v: ErrEwcode.contains(v)), "err_id") - @PostCheck(lambda result: CheckRules.check_type_not_none(result, str)) - @PostSimpleExprCheck( - (lambda inputs, result: result == "0" + inputs["err_id"][1:2] + "000"), - ["err_id"], - ) - def get_err_type_ewcode(self, err_id: str) -> str: - return self.KCL_ERROR_MSG.get_err_type_ewcode(err_id) - - @PreCheck((lambda v: ErrEwcode.contains(v)), "err_id") - @PostCheck(lambda result: CheckRules.check_type_not_none(result, str)) - def get_err_cate_msg_by_errid(self, err_id: str) -> str: - return self.KCL_ERROR_MSG.get_err_cate_msg_by_errid(err_id) - - @PreCheck((lambda v: ErrEwcode.contains(v)), "err_id") - @PostCheck(lambda result: CheckRules.check_type_not_none(result, str)) - def get_err_type_msg_by_errid(self, err_id: str) -> str: - return self.KCL_ERROR_MSG.get_err_type_msg_by_errid(err_id) - - @PreCheck((lambda v: ErrEwcode.contains(v)), "err_id") - @PostCheck(lambda result: CheckRules.check_type_not_none(result, str)) - def get_err_msg_by_errid(self, err_id: str) -> str: - return self.KCL_ERROR_MSG.get_err_msg_by_errid(err_id) - - @PreCheck((lambda v: ErrEwcode.contains(v)), "err_id") - @PostCheck(lambda result: CheckRules.check_type_not_none(result, str)) - def get_defaule_arg_msg_by_errid(self, err_id: str) -> str: - return self.KCL_ERROR_MSG.get_defaule_arg_msg_by_errid(err_id) - - @PreCheck((lambda v: ErrEwcode.contains(v)), "err_id") - @PostCheck(lambda result: CheckRules.check_type_not_none(result, str)) - @PostSimpleExprCheck( - (lambda inputs, result: result == "[" + inputs["err_id"] + "]"), ["err_id"] - ) - def get_err_code_by_errid(self, err_id: str) -> str: - return self.KCL_ERROR_MSG.get_err_code_by_errid(err_id) - - @PreCheck((lambda v: ErrEwcode.contains(v)), "err_id") - @PostCheck(lambda result: CheckRules.check_type_not_none(result, bool)) - def is_warning(self, err_id: str) -> bool: - return self.KCL_ERROR_MSG.is_warning(err_id) - - @PreCheck((lambda v: ErrEwcode.contains(v)), "err_id") - @PostCheck(lambda result: CheckRules.check_type_not_none(result, bool)) - def is_syntax_error(self, err_id: str) -> bool: - return self.KCL_ERROR_MSG.is_syntax_error(err_id) - - @PreCheck((lambda v: ErrEwcode.contains(v)), "err_id") - @PostCheck(lambda result: CheckRules.check_type_not_none(result, bool)) - def is_compiler_error(self, err_id: str) -> bool: - return self.KCL_ERROR_MSG.is_compiler_error(err_id) - - @PreCheck((lambda v: ErrEwcode.contains(v)), "err_id") - @PostCheck(lambda result: CheckRules.check_type_not_none(result, bool)) - def is_runtime_error(self, err_id: str) -> bool: - return self.KCL_ERROR_MSG.is_runtime_error(err_id) - - @PreCheck((lambda v: ErrEwcode.contains(v)), "err_id") - @PostCheck(lambda result: CheckRules.check_type_not_none(result, str)) - def get_err_name_by_ewcode(self, err_id: str): - return self.KCL_ERROR_MSG.get_err_name_by_ewcode(err_id) - - -KCL_ERR_MSG = KCLErrMsgManager() diff --git a/internal/kclvm_py/kcl/error/kcl_err_template.py b/internal/kclvm_py/kcl/error/kcl_err_template.py deleted file mode 100644 index c2c2d0f78..000000000 --- a/internal/kclvm_py/kcl/error/kcl_err_template.py +++ /dev/null @@ -1,590 +0,0 @@ -""" -The `kcl_err_template` file mainly contains some string templates to organize the structure of the KCL error message. - -The KCL error message comes from kcl_err_msg.py - -KCLErrMsgTemplate: An abstract class, which specifies the methods required by KCL error message template classes. - -KCLErrMsgTemplateDefault: The default KCL template class implementation. - -Provide four file message templates in KCLErrMsgTemplateDefault: - - get_hint_msg_common: ----------------------------------------------------------------------------- - KCL Compile Error[E2L23] : A complie error occurs during compiling - ---> File /main.k:2:14 - 2 | name: str - 14 ^ -> Failure - An error occurs ----------------------------------------------------------------------------- - - get_hint_msg_tiny: ----------------------------------------------------------------------------- - KCL Compile Error[E2L23] : A compile error occurs during compiling - An error occurs ----------------------------------------------------------------------------- - - get_hint_msg_summary: ----------------------------------------------------------------------------- - KCL Compile Error[E2L23] : A complie error occurs during compiling - ---> File /main.k:2 - 2 | name: str -> Failure - An error occurs ----------------------------------------------------------------------------- - - get_hint_msg_detail: ----------------------------------------------------------------------------- - KCL Compile Error[E2L23] : A complie error occurs during compiling - ---> File /main.k:2:5 - 2 | name: str - 5 ^^^^^^^^^ -> Failure - An error occurs ----------------------------------------------------------------------------- - -Provide one error message templates in KCLErrMsgTemplateDefault: - - err_msg_template: ----------------------------------------------------------------------------- - KCL Compile Error[E2L23] : A compile error occurs during compiling ----------------------------------------------------------------------------- - -color_txt_err_msg(), color_txt_err_file_msg() in KCLErrMsgTemplateDefault -will call methods provided in kcl_err_template.py to highlight some fields -in the kcl error message - -:copyright: Copyright 2020 The KCL Authors. All rights reserved. -""" -import os -import typing -import threading - -from enum import unique, Enum -from pathlib import PosixPath -from string import Template -from abc import ABCMeta, abstractmethod -from kclvm.kcl.error.kcl_err_theme import ( - ColorOption, - KCLErrMsgTheme, - KCLErrMsgThemeDefault, -) -from kclvm.kcl.error.kcl_err_msg import KCL_ERR_MSG, ErrEwcode -from kclvm.internal.util import PreCheck, CheckRules, PostCheck, check_utils - -DEFAULT_MSG_2 = "Failure" - - -@unique -class ErrLevel(Enum): - SERIOUS = 1 - ORDINARY = 2 - - -@unique -class MsgId(Enum): - ERR_TYPE = 1 - ERR_CATE = 2 - EWCODE = 3 - MSG_1 = 4 - MSG_2 = 5 - - FILENAME = 8 - SRC_CODE_LINE = 9 - LINE_NO = 10 - COL_NO = 11 - ERR_ARG = 12 - MARK = 13 - - -@unique -class ErrMsgFmt(Enum): - COLOR_TXT = 1 - NO_COLOR_TXT = 2 - - -class FileCache: - """File cache to store the filename and code mapping""" - - _file_cache: typing.Dict[str, str] = {} - _lock = threading.RLock() - - @staticmethod - def clear(): - FileCache._file_cache.clear() - - @staticmethod - def put(file: str, code: str): - FileCache._lock.acquire() - FileCache._file_cache[file] = code - FileCache._lock.release() - - @staticmethod - def get(file: str) -> str: - return FileCache._file_cache.get(file, "") - - -UP_ARROW = "^" -WAVY = "~" - -MARK_SYMBOL = {ErrLevel.SERIOUS: UP_ARROW, ErrLevel.ORDINARY: WAVY} - -TAB = " " -COLON = ":" -COMMA = ", " -WHITE_SPACE = " " -SPARATOER = " |" -NEW_LINE = "\n" -HINT_MSG = "{}" -FILE_PREFIX = "---> File " -MSG_PREFIX = "KCL " - - -class KCLErrMsgTemplate(metaclass=ABCMeta): - @PreCheck((lambda v: CheckRules.check_type_allow_none(v, ErrMsgFmt)), "fmt") - @PreCheck((lambda v: CheckRules.check_type_allow_none(v, KCLErrMsgTheme)), "theme") - def __init__( - self, - fmt: ErrMsgFmt = ErrMsgFmt.NO_COLOR_TXT, - theme: KCLErrMsgTheme = KCLErrMsgThemeDefault(), - ): - self.fmt = fmt - self.theme = theme - - @abstractmethod - def get_hint_msg_common( - self, - filename: str, - line_no: int, - col_no: int, - src_code_line: str, - indent_count: int = 0, - mark: str = MARK_SYMBOL[ErrLevel.SERIOUS], - ) -> str: - pass - - @abstractmethod - def get_hint_msg_tiny(self, filename: str, indent_count: int = 0) -> str: - pass - - @abstractmethod - def get_hint_msg_summary( - self, filename: str, line_no: int, src_code_line: str, indent_count: int = 0 - ) -> str: - pass - - @abstractmethod - def get_hint_msg_detail( - self, - filename: str, - line_no: int, - col_no: int, - end_col_no: int, - src_code_line: str, - indent_count: int = 0, - mark: str = MARK_SYMBOL[ErrLevel.SERIOUS], - ) -> str: - pass - - @abstractmethod - def err_msg_template( - self, err_type: str, err_cate: str, ewcode_fmt: str, msg_1: str - ): - pass - - @abstractmethod - def color_txt_err_file_msg(self, mark_level: ErrLevel): - pass - - @abstractmethod - def color_txt_err_msg(self, err_type: str, err_cate: str): - pass - - -class KCLErrMsgTemplateDefault(KCLErrMsgTemplate): - @PreCheck((lambda v: CheckRules.check_type_allow_none(v, ErrMsgFmt)), "fmt") - @PreCheck((lambda v: CheckRules.check_type_allow_none(v, KCLErrMsgTheme)), "theme") - def __init__( - self, - fmt: ErrMsgFmt = ErrMsgFmt.NO_COLOR_TXT, - theme: KCLErrMsgTheme = KCLErrMsgThemeDefault(), - ): - super().__init__(fmt, theme) - self.fmt = fmt - self.theme = theme - - self.ErrMsgLables = { - MsgId.ERR_TYPE: "${err_type}", - MsgId.ERR_CATE: "${err_cate}", - MsgId.EWCODE: "${ewcode}", - MsgId.MSG_1: "${msg_1}", - MsgId.MSG_2: "${msg_2}", - MsgId.FILENAME: "${filename}", - MsgId.SRC_CODE_LINE: "${src_code_line}", - MsgId.LINE_NO: "${line_no}", - MsgId.COL_NO: "${col_no}", - MsgId.ERR_ARG: "${err_arg}", - MsgId.MARK: "${mark}", - } - self.FILENAME = self.ErrMsgLables[MsgId.FILENAME] - self.LINE_NO = self.ErrMsgLables[MsgId.LINE_NO] - self.COL_NO = self.ErrMsgLables[MsgId.COL_NO] - self.MARK = self.ErrMsgLables[MsgId.MARK] - - self.EWCODE = self.ErrMsgLables[MsgId.EWCODE] - self.ERR_TYPE = self.ErrMsgLables[MsgId.ERR_TYPE] - self.ERR_CATE = self.ErrMsgLables[MsgId.ERR_CATE] - self.MSG_1 = self.ErrMsgLables[MsgId.MSG_1] - self.MSG_2 = self.ErrMsgLables[MsgId.MSG_2] - - self.SRC_CODE_LINE = self.ErrMsgLables[MsgId.SRC_CODE_LINE] - self.ERR_ARG = self.ErrMsgLables[MsgId.ERR_ARG] - - def clean_color(self): - self.FILENAME = self.ErrMsgLables[MsgId.FILENAME] - self.LINE_NO = self.ErrMsgLables[MsgId.LINE_NO] - self.COL_NO = self.ErrMsgLables[MsgId.COL_NO] - self.MARK = self.ErrMsgLables[MsgId.MARK] - - self.EWCODE = self.ErrMsgLables[MsgId.EWCODE] - self.ERR_TYPE = self.ErrMsgLables[MsgId.ERR_TYPE] - self.ERR_CATE = self.ErrMsgLables[MsgId.ERR_CATE] - - @PreCheck((lambda v: CheckRules.check_type_not_none(v, str)), "filename") - @PreCheck((lambda v: CheckRules.check_type_not_none(v, int)), "line_no") - @PreCheck((lambda v: CheckRules.check_type_not_none(v, int)), "col_no") - @PreCheck((lambda v: CheckRules.check_type_not_none(v, str)), "src_code_line") - @PreCheck((lambda v: CheckRules.check_type_allow_none(v, int)), "indent_count") - @PreCheck((lambda v: CheckRules.check_type_allow_none(v, str)), "mark") - @PostCheck(lambda v: CheckRules.check_type_not_none(v, str)) - def get_hint_msg_common( - self, - filename: str, - line_no: int, - col_no: int, - src_code_line: str, - indent_count: int = 0, - mark: str = MARK_SYMBOL[ErrLevel.SERIOUS], - ) -> str: - HINT_MSG_COMMON = ( - NEW_LINE - + TAB * indent_count - + FILE_PREFIX - + self.FILENAME - + COLON - + self.LINE_NO - + COLON - + self.COL_NO - + NEW_LINE - + TAB * indent_count - + self.LINE_NO - + SPARATOER - + self.SRC_CODE_LINE - + NEW_LINE - + TAB * indent_count - + (self.COL_NO + WHITE_SPACE).rjust( - len(str(line_no)) + 1 + col_no + len(self.COL_NO) - len(str(col_no)), - WHITE_SPACE, - ) - + self.MARK - + WHITE_SPACE - ) - hint_msg_args = { - "filename": filename, - "line_no": line_no, - "col_no": col_no, - "src_code_line": src_code_line, - "mark": mark, - } - return Template(HINT_MSG_COMMON).substitute(hint_msg_args) - - @PreCheck((lambda v: CheckRules.check_type_not_none(v, str)), "filename") - @PreCheck((lambda v: CheckRules.check_type_allow_none(v, int)), "indent_count") - @PostCheck(lambda v: CheckRules.check_type_not_none(v, str)) - def get_hint_msg_tiny(self, filename: str, indent_count: int = 0) -> str: - HINT_MSG_TINY = NEW_LINE + TAB * indent_count + FILE_PREFIX + self.FILENAME - hint_msg_args = {"filename": filename} - return Template(HINT_MSG_TINY).substitute(hint_msg_args) - - @PreCheck((lambda v: CheckRules.check_type_not_none(v, str)), "filename") - @PreCheck((lambda v: CheckRules.check_type_not_none(v, int)), "line_no") - @PreCheck((lambda v: CheckRules.check_type_not_none(v, str)), "src_code_line") - @PreCheck((lambda v: CheckRules.check_type_allow_none(v, int)), "indent_count") - @PostCheck(lambda v: CheckRules.check_type_not_none(v, str)) - def get_hint_msg_summary( - self, filename: str, line_no: int, src_code_line: str, indent_count: int = 0 - ) -> str: - HINT_MSG_SUMMARY = ( - NEW_LINE - + TAB * indent_count - + FILE_PREFIX - + self.FILENAME - + COLON - + self.LINE_NO - + NEW_LINE - + TAB * indent_count - + self.LINE_NO - + SPARATOER - + self.SRC_CODE_LINE - ) - hint_msg_args = { - "filename": filename, - "line_no": line_no, - "src_code_line": src_code_line, - } - return Template(HINT_MSG_SUMMARY).substitute(hint_msg_args) - - @PreCheck((lambda v: CheckRules.check_type_not_none(v, str)), "filename") - @PreCheck((lambda v: CheckRules.check_type_not_none(v, int)), "line_no") - @PreCheck((lambda v: CheckRules.check_type_not_none(v, int)), "col_no") - @PreCheck((lambda v: CheckRules.check_type_not_none(v, int)), "end_col_no") - @PreCheck((lambda v: CheckRules.check_type_not_none(v, str)), "src_code_line") - @PreCheck((lambda v: CheckRules.check_type_allow_none(v, int)), "indent_count") - @PreCheck((lambda v: CheckRules.check_type_allow_none(v, str)), "mark") - @PostCheck(lambda v: CheckRules.check_type_not_none(v, str)) - def get_hint_msg_detail( - self, - filename: str, - line_no: int, - col_no: int, - end_col_no: int, - src_code_line: str, - indent_count: int = 0, - mark: str = MARK_SYMBOL[ErrLevel.SERIOUS], - ) -> str: - HINT_MSG_DETAIL = ( - NEW_LINE - + TAB * indent_count - + FILE_PREFIX - + self.FILENAME - + COLON - + self.LINE_NO - + COLON - + self.COL_NO - + NEW_LINE - + TAB * indent_count - + self.LINE_NO - + SPARATOER - + self.SRC_CODE_LINE - + NEW_LINE - + TAB * indent_count - + (self.COL_NO + WHITE_SPACE).rjust( - len(str(line_no)) + 1 + col_no + len(self.COL_NO) - len(str(col_no)), - WHITE_SPACE, - ) - + self.MARK * (end_col_no - col_no) - + WHITE_SPACE - ) - hint_msg_args = { - "filename": filename, - "line_no": line_no, - "col_no": col_no, - "src_code_line": src_code_line, - "mark": mark, - } - return Template(HINT_MSG_DETAIL).substitute(hint_msg_args) - - @PreCheck((lambda v: CheckRules.check_type_not_none(v, str)), "err_type") - @PreCheck((lambda v: CheckRules.check_type_not_none(v, str)), "err_cate") - @PreCheck((lambda v: CheckRules.check_type_not_none(v, str)), "ewcode_fmt") - @PreCheck((lambda v: CheckRules.check_type_not_none(v, str)), "msg_1") - @PostCheck(lambda v: CheckRules.check_type_not_none(v, str)) - def err_msg_template( - self, err_type: str, err_cate: str, ewcode_fmt: str, msg_1: str - ): - SIMPLE_TEMPLATE_DOC = ( - MSG_PREFIX - + self.ERR_TYPE - + WHITE_SPACE - + self.ERR_CATE - + self.EWCODE - + WHITE_SPACE - + COLON - + WHITE_SPACE - + self.MSG_1 - ) - simple_args = { - "err_type": err_type, - "err_cate": err_cate, - "ewcode": ewcode_fmt, - "msg_1": msg_1, - } - return Template(SIMPLE_TEMPLATE_DOC).substitute(simple_args) - - @PreCheck((lambda v: CheckRules.check_type_not_none(v, ErrLevel)), "mark_level") - def color_txt_err_file_msg(self, mark_level: ErrLevel): - self.MARK = self.theme.color_mark(self.MARK, mark_level.value) - self.FILENAME = self.theme.color(self.FILENAME, ColorOption.FILE_NAME) - self.LINE_NO = self.theme.color(self.LINE_NO, ColorOption.LINE_COLUMN) - self.COL_NO = self.theme.color(self.COL_NO, ColorOption.LINE_COLUMN) - - @PreCheck((lambda v: CheckRules.check_type_not_none(v, str)), "err_type") - @PreCheck((lambda v: CheckRules.check_type_not_none(v, str)), "err_cate") - def color_txt_err_msg(self, err_type: str, err_cate: str): - self.EWCODE = self.theme.color(self.EWCODE, ColorOption.EWCODE) - self.ERR_TYPE = self.color_err_msg(slot=self.ERR_TYPE, msg=err_type) - self.ERR_CATE = self.color_err_msg(slot=self.ERR_CATE, msg=err_cate) - - @PreCheck((lambda v: CheckRules.check_type_not_none(v, str)), "msg") - @PreCheck((lambda v: CheckRules.check_type_not_none(v, str)), "slot") - @PostCheck(lambda v: CheckRules.check_type_not_none(v, str)) - def color_err_msg(self, slot: str, msg: str): - msg_theme_map: dict = { - KCL_ERR_MSG.get_err_msg_by_errid(ErrEwcode.KCLError_Ew): ColorOption.ERROR, - KCL_ERR_MSG.get_err_msg_by_errid( - ErrEwcode.KCLWarning_Ew - ): ColorOption.WARNING, - KCL_ERR_MSG.get_err_msg_by_errid( - ErrEwcode.KCLSyntaxException_Ew - ): ColorOption.SYNTAX, - KCL_ERR_MSG.get_err_msg_by_errid( - ErrEwcode.KCLCompileException_Ew - ): ColorOption.COMPLIE, - KCL_ERR_MSG.get_err_msg_by_errid( - ErrEwcode.KCLRuntimeException_Ew - ): ColorOption.RUNTIME, - KCL_ERR_MSG.get_err_msg_by_errid( - ErrEwcode.KCLException_Ew - ): ColorOption.ERROR, - } - try: - return self.theme.color(slot, msg_theme_map[msg]) - except KeyError: - check_utils.alert_internal_bug() - - -class ErrFileMsg: - @PreCheck( - (lambda v: CheckRules.check_type_allow_none(v, str, PosixPath)), "filename" - ) - @PreCheck((lambda v: CheckRules.check_type_allow_none(v, int)), "line_no") - @PreCheck((lambda v: CheckRules.check_type_allow_none(v, int)), "col_no") - @PreCheck((lambda v: CheckRules.check_type_allow_none(v, int)), "end_col_no") - @PreCheck((lambda v: CheckRules.check_type_allow_none(v, str)), "src_code") - @PreCheck((lambda v: CheckRules.check_type_allow_none(v, str)), "arg_msg") - @PreCheck((lambda v: CheckRules.check_type_allow_none(v, int)), "indent_count") - def __init__( - self, - filename: typing.Union[str, PosixPath] = None, - line_no: int = None, - col_no: int = None, - end_col_no: int = None, - src_code: str = None, - arg_msg: str = DEFAULT_MSG_2, - indent_count: int = 0, - err_level: ErrLevel = ErrLevel.SERIOUS, - ): - self.filename = filename - self.line_no = line_no - self.col_no = col_no - self.end_col_no = end_col_no - self.src_code = src_code - self.err_level = err_level if err_level else ErrLevel.SERIOUS - self.arg_msg = arg_msg if arg_msg else DEFAULT_MSG_2 - self.indent_count = indent_count - - -@PreCheck((lambda v: CheckRules.check_type_not_none(v, ErrFileMsg)), "file_msg") -@PostCheck(lambda v: CheckRules.check_type_not_none(v, str)) -def get_src_code(file_msg: ErrFileMsg) -> str: - """Produce formatted error hint messages""" - src_line = "" - if file_msg.filename: - source_line: str = "" - if file_msg.line_no: - if file_msg.src_code: - lines = file_msg.src_code.split("\n") - else: - lines = ( - open(file_msg.filename, "r", encoding="utf8").read().split("\n") - if os.path.exists(file_msg.filename) - else FileCache.get(file_msg.filename).split("\n") - ) - - if 0 < file_msg.line_no <= len(lines): - source_line = lines[file_msg.line_no - 1] - return source_line - elif file_msg.src_code and file_msg.line_no: - lines = file_msg.src_code.split("\n") - if 0 < file_msg.line_no <= len(lines): - src_line = lines[file_msg.line_no - 1] - return src_line - return "" - - -@PreCheck((lambda v: CheckRules.check_type_not_none(v, ErrFileMsg)), "file_msg") -@PostCheck(lambda v: CheckRules.check_type_not_none(v, str)) -def get_hint_msg( - file_msg: ErrFileMsg, msg_tem: KCLErrMsgTemplate = KCLErrMsgTemplateDefault() -) -> str: - if msg_tem is None: - msg_tem = KCLErrMsgTemplateDefault() - msg_tem.clean_color() - if msg_tem.fmt == ErrMsgFmt.COLOR_TXT: - msg_tem.color_txt_err_file_msg(file_msg.err_level) - result = "" - arg = " -> " + file_msg.arg_msg if file_msg.arg_msg else "" - mark = MARK_SYMBOL[file_msg.err_level] - if file_msg.filename: - if file_msg.line_no: - src_code = get_src_code(file_msg) - if file_msg.col_no and file_msg.end_col_no: - result = ( - msg_tem.get_hint_msg_detail( - file_msg.filename, - file_msg.line_no, - file_msg.col_no, - file_msg.end_col_no, - src_code, - indent_count=file_msg.indent_count, - mark=mark, - ) - + arg - ) - elif file_msg.col_no and not file_msg.end_col_no: - result = ( - msg_tem.get_hint_msg_common( - file_msg.filename, - file_msg.line_no, - file_msg.col_no, - src_code, - indent_count=file_msg.indent_count, - mark=mark, - ) - + arg - ) - elif not file_msg.col_no and not file_msg.end_col_no: - result = ( - msg_tem.get_hint_msg_summary( - file_msg.filename, - file_msg.line_no, - src_code, - indent_count=file_msg.indent_count, - ) - + arg - ) - else: - result = ( - msg_tem.get_hint_msg_tiny( - file_msg.filename, indent_count=file_msg.indent_count - ) - + arg - ) - - return result - - -@PreCheck((lambda v: CheckRules.check_type_not_none(v, str)), "ewcode") -@PostCheck(lambda v: CheckRules.check_type_not_none(v, str)) -def get_err_msg( - ewcode: str, msg_tem: KCLErrMsgTemplate = KCLErrMsgTemplateDefault() -) -> str: - if msg_tem is None: - msg_tem = KCLErrMsgTemplateDefault() - msg_tem.clean_color() - err_type = KCL_ERR_MSG.get_err_type_msg_by_errid(ewcode) - err_cate = KCL_ERR_MSG.get_err_cate_msg_by_errid(ewcode) - ewcode_fmt = KCL_ERR_MSG.get_err_code_by_errid(ewcode) - err_msg = KCL_ERR_MSG.get_err_msg_by_errid(ewcode) - - if msg_tem.fmt == ErrMsgFmt.COLOR_TXT: - msg_tem.color_txt_err_msg(err_type, err_cate) - return msg_tem.err_msg_template(err_type, err_cate, ewcode_fmt, err_msg) diff --git a/internal/kclvm_py/kcl/error/kcl_err_theme.py b/internal/kclvm_py/kcl/error/kcl_err_theme.py deleted file mode 100644 index 741ffdfff..000000000 --- a/internal/kclvm_py/kcl/error/kcl_err_theme.py +++ /dev/null @@ -1,91 +0,0 @@ -""" -The `kcl_err_theme` file mainly contains the color constants needed to highlight the KCL error message. - -ThemeId (Enum): The color theme of highlight KCL error message, currently there is only one `DEFAULT`. - -ColorOption (Enum): Fields that can be highlighted in the KCL error message. - -KCLErrMsgTheme: An abstract class, which specifies the methods required by KCL error message theme classes. - -KCLErrMsgThemeDefault: It is the default implementation class of KCLErrMsgTheme. - -Default highlight: - - EWCODE: green - ERROR: red - WARNING: yellow - FILE_NAME: blue - LINE_COLUMN: cyan - SYNTAX: dark yellow - COMPLIE: dark green - RUNTIME: dark blue - MARK: { - 1: red - 2: purple - }, - -:copyright: Copyright 2020 The KCL Authors. All rights reserved. -""" -from enum import Enum, unique -from kclvm.internal.util import PreCheck, CheckRules -from abc import ABCMeta, abstractmethod - - -@unique -class ThemeId(Enum): - DEFAULT = 0 - OTHER = 1 - - -@unique -class ColorOption(Enum): - EWCODE = 0 - ERROR = 1 - WARNING = 2 - FILE_NAME = 3 - LINE_COLUMN = 4 - MARK = 5 - SYNTAX = 6 - COMPLIE = 7 - RUNTIME = 8 - - -class KCLErrMsgTheme(metaclass=ABCMeta): - @abstractmethod - def color_mark(self, mark: str, mark_level: int = 1): - pass - - @abstractmethod - def color(self, content: str, color_option: ColorOption): - pass - - -class KCLErrMsgThemeDefault(KCLErrMsgTheme): - def __init__(self): - self.KCL_THEME: dict = { - ColorOption.EWCODE: "\033[0;92m{}\033[0m", # green - ColorOption.ERROR: "\033[0;91m{}\033[0m", # red - ColorOption.WARNING: "\033[0;93m{}\033[0m", # yellow - ColorOption.FILE_NAME: "\033[0;94m{}\033[0m", # blue - ColorOption.LINE_COLUMN: "\033[0;96m{}\033[0m", # cyan - ColorOption.SYNTAX: "\033[0;33m{}\033[0m", # dark yellow - ColorOption.COMPLIE: "\033[0;32m{}\033[0m", # dark green - ColorOption.RUNTIME: "\033[0;34m{}\033[0m", # dark blue - ColorOption.MARK: { - 1: "\033[0;31m{}\033[0m", # red - 2: "\033[0;35m{}\033[0m", # purple - }, - } - - @PreCheck((lambda v: CheckRules.check_type_not_none(v, str)), "mark") - @PreCheck((lambda v: CheckRules.check_type_not_none(v, int)), "mark_level") - @PreCheck((lambda v: CheckRules.check_int_range_allow_none(v, 1, 3)), "mark_level") - def color_mark(self, mark: str, mark_level: int = 1): - return self.KCL_THEME[ColorOption.MARK][mark_level].format(mark) - - @PreCheck((lambda v: CheckRules.check_type_not_none(v, str)), "content") - @PreCheck( - (lambda v: CheckRules.check_type_not_none(v, ColorOption)), "color_option" - ) - def color(self, content: str, color_option: ColorOption): - return self.KCL_THEME[color_option].format(content) diff --git a/internal/kclvm_py/kcl/error/kcl_error.py b/internal/kclvm_py/kcl/error/kcl_error.py deleted file mode 100644 index 921937e29..000000000 --- a/internal/kclvm_py/kcl/error/kcl_error.py +++ /dev/null @@ -1,1611 +0,0 @@ -""" -The `kcl_error` file mainly contains all KCL exceptions. - -KCLException is the top-level exception class, all KCL exceptions inherit from KCLException. - -KCLException.err_info_stack : -A file information stack is built in KCLException to save file information when an exception occurs. - -KCLException.gen_err_msg : -Method `gen_err_msg` generates KCL error message without highlighting -by calling the method provided in kcl_err_template.py - -KCLException.show_msg_with_theme : -Method `show_msg_with_theme` generates KCL error message with highlighting -by calling the method provided in kcl_err_template.py - -:note: At present, the KCL error message templates of the two methods `gen_err_msg` and `show_msg_with_theme` -are created by default arguments, and they are not synchronized. -If the template of one method is changed, -the template of the other method also needs to be replaced manually, -otherwise the message output by the two methods will be different. - -:copyright: Copyright 2020 The KCL Authors. All rights reserved. -""" -import sys -import typing -from enum import Enum, unique - -import kclvm.kcl.error.kcl_err_template as err_template - -from kclvm.kcl.error.kcl_err_msg import KCL_ERR_MSG, ErrEwcode -from kclvm.internal.util import PreCheck, CheckRules, PostCheck - - -class KCLException(Exception): - @PreCheck( - ( - lambda v: CheckRules.check_list_item_type_allow_none( - v, err_template.ErrFileMsg - ) - ), - "file_msgs", - ) - @PreCheck((lambda v: CheckRules.check_type_allow_none(v, str)), "arg_msg") - @PreCheck((lambda v: CheckRules.check_type_allow_none(v, str)), "ewcode") - @PreCheck( - ( - lambda v: CheckRules.check_str_len_allow_none( - v, len(KCL_ERR_MSG.get_defaule_ewcode()) - ) - ), - "ewcode", - ) - def __init__( - self, - file_msgs: typing.List[err_template.ErrFileMsg] = None, - ewcode: str = None, - arg_msg: str = None, - ): - self.ewcode = ErrEwcode.KCLException_Ew if not ewcode else ewcode - self.name = KCL_ERR_MSG.get_err_name_by_ewcode(self.ewcode) - self.err_info_stack: typing.List[err_template.ErrFileMsg] = [] - if file_msgs: - self.err_info_stack.extend(file_msgs) - self.arg_msg = ( - arg_msg - if arg_msg - else KCL_ERR_MSG.get_defaule_arg_msg_by_errid(self.ewcode) - ) - - def __str__(self): - return self.gen_err_msg() - - def show_msg_with_theme( - self, - color_template=err_template.KCLErrMsgTemplateDefault( - fmt=err_template.ErrMsgFmt.COLOR_TXT - ), - ) -> str: - if not color_template: - color_template = err_template.KCLErrMsgTemplateDefault( - fmt=err_template.ErrMsgFmt.COLOR_TXT - ) - return self.gen_err_msg(msg_tem=color_template) - - def gen_err_msg(self, msg_tem=err_template.KCLErrMsgTemplateDefault()) -> str: - result = "" - result += err_template.get_err_msg(self.ewcode, msg_tem) - count = 0 - for file in reversed(self.err_info_stack): - if file and file.filename: - file.indent_count = count - result += err_template.get_hint_msg(file, msg_tem) - count += 1 - return result + "\n" + self.arg_msg if self.arg_msg else result - - def no_err_msg(self) -> bool: - return self.err_info_stack is None or len(self.err_info_stack) == 0 - - def append_err_info(self, einfo: err_template.ErrFileMsg): - self.err_info_stack.append(einfo) - - def pop_err_info(self) -> err_template.ErrFileMsg: - return ( - self.err_info_stack.pop(-1) - if len(self.err_info_stack) > 0 - else err_template.ErrFileMsg() - ) - - @property - def filename(self): - return self.err_info_stack[-1].filename if len(self.err_info_stack) > 0 else "" - - @property - def lineno(self): - return self.err_info_stack[-1].line_no if len(self.err_info_stack) > 0 else "" - - @property - def colno(self): - return self.err_info_stack[-1].col_no if len(self.err_info_stack) > 0 else "" - - -class KCLError(KCLException): - @PreCheck( - ( - lambda v: CheckRules.check_list_item_type_allow_none( - v, err_template.ErrFileMsg - ) - ), - "file_msgs", - ) - @PreCheck((lambda v: CheckRules.check_type_allow_none(v, str)), "arg_msg") - def __init__( - self, - file_msgs: typing.List[err_template.ErrFileMsg] = None, - arg_msg: str = None, - ): - self.ewcode = ErrEwcode.KCLError_Ew - KCLException.__init__( - self, file_msgs=file_msgs, ewcode=self.ewcode, arg_msg=arg_msg - ) - - -class KCLWarning(KCLException): - @PreCheck( - ( - lambda v: CheckRules.check_list_item_type_allow_none( - v, err_template.ErrFileMsg - ) - ), - "file_msgs", - ) - @PreCheck((lambda v: CheckRules.check_type_allow_none(v, str)), "arg_msg") - def __init__( - self, - file_msgs: typing.List[err_template.ErrFileMsg] = None, - arg_msg: str = None, - ): - self.ewcode = ErrEwcode.KCLWarning_Ew - KCLException.__init__( - self, file_msgs=file_msgs, ewcode=self.ewcode, arg_msg=arg_msg - ) - - -class KCLSyntaxException(KCLException): - @PreCheck( - ( - lambda v: CheckRules.check_list_item_type_allow_none( - v, err_template.ErrFileMsg - ) - ), - "file_msgs", - ) - @PreCheck((lambda v: CheckRules.check_type_allow_none(v, str)), "arg_msg") - def __init__( - self, - file_msgs: typing.List[err_template.ErrFileMsg] = None, - arg_msg: str = None, - ): - self.ewcode = ErrEwcode.KCLSyntaxException_Ew - KCLException.__init__( - self, file_msgs=file_msgs, ewcode=self.ewcode, arg_msg=arg_msg - ) - - -class KCLCompileException(KCLException): - @PreCheck( - ( - lambda v: CheckRules.check_list_item_type_allow_none( - v, err_template.ErrFileMsg - ) - ), - "file_msgs", - ) - @PreCheck((lambda v: CheckRules.check_type_allow_none(v, str)), "arg_msg") - def __init__( - self, - file_msgs: typing.List[err_template.ErrFileMsg] = None, - arg_msg: str = None, - ): - self.ewcode = ErrEwcode.KCLCompileException_Ew - KCLException.__init__( - self, file_msgs=file_msgs, ewcode=self.ewcode, arg_msg=arg_msg - ) - - -class KCLRuntimeException(KCLException): - @PreCheck( - ( - lambda v: CheckRules.check_list_item_type_allow_none( - v, err_template.ErrFileMsg - ) - ), - "file_msgs", - ) - @PreCheck((lambda v: CheckRules.check_type_allow_none(v, str)), "arg_msg") - def __init__( - self, - file_msgs: typing.List[err_template.ErrFileMsg] = None, - arg_msg: str = None, - ): - self.ewcode = ErrEwcode.KCLRuntimeException_Ew - KCLException.__init__( - self, file_msgs=file_msgs, ewcode=self.ewcode, arg_msg=arg_msg - ) - - -class KCLAttributeException(KCLException): - @PreCheck( - ( - lambda v: CheckRules.check_list_item_type_allow_none( - v, err_template.ErrFileMsg - ) - ), - "file_msgs", - ) - @PreCheck((lambda v: CheckRules.check_type_allow_none(v, str)), "arg_msg") - def __init__( - self, - file_msgs: typing.List[err_template.ErrFileMsg] = None, - arg_msg: str = None, - ): - self.ewcode = ErrEwcode.KCLAttributeException_Ew - KCLException.__init__( - self, file_msgs=file_msgs, ewcode=self.ewcode, arg_msg=arg_msg - ) - - -class KCLSchemaException(KCLException): - @PreCheck( - ( - lambda v: CheckRules.check_list_item_type_allow_none( - v, err_template.ErrFileMsg - ) - ), - "file_msgs", - ) - @PreCheck((lambda v: CheckRules.check_type_allow_none(v, str)), "arg_msg") - def __init__( - self, - file_msgs: typing.List[err_template.ErrFileMsg] = None, - arg_msg: str = None, - ): - self.ewcode = ErrEwcode.KCLSchemaException_Ew - KCLException.__init__( - self, file_msgs=file_msgs, ewcode=self.ewcode, arg_msg=arg_msg - ) - - -class KCLMixinException(KCLException): - @PreCheck( - ( - lambda v: CheckRules.check_list_item_type_allow_none( - v, err_template.ErrFileMsg - ) - ), - "file_msgs", - ) - @PreCheck((lambda v: CheckRules.check_type_allow_none(v, str)), "arg_msg") - def __init__( - self, - file_msgs: typing.List[err_template.ErrFileMsg] = None, - arg_msg: str = None, - ): - self.ewcode = ErrEwcode.KCLMixinException_Ew - KCLException.__init__( - self, file_msgs=file_msgs, ewcode=self.ewcode, arg_msg=arg_msg - ) - - -class KCLInheritException(KCLException): - @PreCheck( - ( - lambda v: CheckRules.check_list_item_type_allow_none( - v, err_template.ErrFileMsg - ) - ), - "file_msgs", - ) - @PreCheck((lambda v: CheckRules.check_type_allow_none(v, str)), "arg_msg") - def __init__( - self, - file_msgs: typing.List[err_template.ErrFileMsg] = None, - arg_msg: str = None, - ): - self.ewcode = ErrEwcode.KCLInheritException_Ew - KCLException.__init__( - self, file_msgs=file_msgs, ewcode=self.ewcode, arg_msg=arg_msg - ) - - -class KCLImportException(KCLException): - @PreCheck( - ( - lambda v: CheckRules.check_list_item_type_allow_none( - v, err_template.ErrFileMsg - ) - ), - "file_msgs", - ) - @PreCheck((lambda v: CheckRules.check_type_allow_none(v, str)), "arg_msg") - def __init__( - self, - file_msgs: typing.List[err_template.ErrFileMsg] = None, - arg_msg: str = None, - ): - self.ewcode = ErrEwcode.KCLImportException_Ew - KCLException.__init__( - self, file_msgs=file_msgs, ewcode=self.ewcode, arg_msg=arg_msg - ) - - -class KCLTypeException(KCLException): - @PreCheck( - ( - lambda v: CheckRules.check_list_item_type_allow_none( - v, err_template.ErrFileMsg - ) - ), - "file_msgs", - ) - @PreCheck((lambda v: CheckRules.check_type_allow_none(v, str)), "arg_msg") - def __init__( - self, - file_msgs: typing.List[err_template.ErrFileMsg] = None, - arg_msg: str = None, - ): - self.ewcode = ErrEwcode.KCLTypeException_Ew - KCLException.__init__( - self, file_msgs=file_msgs, ewcode=self.ewcode, arg_msg=arg_msg - ) - - -class KCLDecoratorException(KCLException): - @PreCheck( - ( - lambda v: CheckRules.check_list_item_type_allow_none( - v, err_template.ErrFileMsg - ) - ), - "file_msgs", - ) - @PreCheck((lambda v: CheckRules.check_type_allow_none(v, str)), "arg_msg") - def __init__( - self, - file_msgs: typing.List[err_template.ErrFileMsg] = None, - arg_msg: str = None, - ): - self.ewcode = ErrEwcode.KCLDecoratorException_Ew - KCLException.__init__( - self, file_msgs=file_msgs, ewcode=self.ewcode, arg_msg=arg_msg - ) - - -class KCLArgumentException(KCLException): - @PreCheck( - ( - lambda v: CheckRules.check_list_item_type_allow_none( - v, err_template.ErrFileMsg - ) - ), - "file_msgs", - ) - @PreCheck((lambda v: CheckRules.check_type_allow_none(v, str)), "arg_msg") - def __init__( - self, - file_msgs: typing.List[err_template.ErrFileMsg] = None, - arg_msg: str = None, - ): - self.ewcode = ErrEwcode.KCLArgumentException_Ew - KCLException.__init__( - self, file_msgs=file_msgs, ewcode=self.ewcode, arg_msg=arg_msg - ) - - -class KCLOverflowException(KCLException): - @PreCheck( - ( - lambda v: CheckRules.check_list_item_type_allow_none( - v, err_template.ErrFileMsg - ) - ), - "file_msgs", - ) - @PreCheck((lambda v: CheckRules.check_type_allow_none(v, str)), "arg_msg") - def __init__( - self, - file_msgs: typing.List[err_template.ErrFileMsg] = None, - arg_msg: str = None, - ): - self.ewcode = ErrEwcode.KCLOverflowException_Ew - KCLException.__init__( - self, file_msgs=file_msgs, ewcode=self.ewcode, arg_msg=arg_msg - ) - - -class KCLComplingException(KCLException): - @PreCheck( - ( - lambda v: CheckRules.check_list_item_type_allow_none( - v, err_template.ErrFileMsg - ) - ), - "file_msgs", - ) - @PreCheck((lambda v: CheckRules.check_type_allow_none(v, str)), "arg_msg") - def __init__( - self, - file_msgs: typing.List[err_template.ErrFileMsg] = None, - arg_msg: str = None, - ): - self.ewcode = ErrEwcode.KCLComplingException_Ew - KCLException.__init__( - self, file_msgs=file_msgs, ewcode=self.ewcode, arg_msg=arg_msg - ) - - -class KCLRunningException(KCLException): - @PreCheck( - ( - lambda v: CheckRules.check_list_item_type_allow_none( - v, err_template.ErrFileMsg - ) - ), - "file_msgs", - ) - @PreCheck((lambda v: CheckRules.check_type_allow_none(v, str)), "arg_msg") - def __init__( - self, - file_msgs: typing.List[err_template.ErrFileMsg] = None, - arg_msg: str = None, - ): - self.ewcode = ErrEwcode.KCLRunningException_Ew - KCLException.__init__( - self, file_msgs=file_msgs, ewcode=self.ewcode, arg_msg=arg_msg - ) - - -class KCLDeprecatedException(KCLException): - @PreCheck( - ( - lambda v: CheckRules.check_list_item_type_allow_none( - v, err_template.ErrFileMsg - ) - ), - "file_msgs", - ) - @PreCheck((lambda v: CheckRules.check_type_allow_none(v, str)), "arg_msg") - def __init__( - self, - file_msgs: typing.List[err_template.ErrFileMsg] = None, - arg_msg: str = None, - ): - self.ewcode = ErrEwcode.KCLDeprecatedException_Ew - KCLException.__init__( - self, file_msgs=file_msgs, ewcode=self.ewcode, arg_msg=arg_msg - ) - - -class KCLDocException(KCLException): - @PreCheck( - ( - lambda v: CheckRules.check_list_item_type_allow_none( - v, err_template.ErrFileMsg - ) - ), - "file_msgs", - ) - @PreCheck((lambda v: CheckRules.check_type_allow_none(v, str)), "arg_msg") - def __init__( - self, - file_msgs: typing.List[err_template.ErrFileMsg] = None, - arg_msg: str = None, - ): - self.ewcode = ErrEwcode.KCLDocException_Ew - KCLException.__init__( - self, file_msgs=file_msgs, ewcode=self.ewcode, arg_msg=arg_msg - ) - - -class KCLImmutableException(KCLException): - @PreCheck( - ( - lambda v: CheckRules.check_list_item_type_allow_none( - v, err_template.ErrFileMsg - ) - ), - "file_msgs", - ) - @PreCheck((lambda v: CheckRules.check_type_allow_none(v, str)), "arg_msg") - def __init__( - self, - file_msgs: typing.List[err_template.ErrFileMsg] = None, - arg_msg: str = None, - ): - self.ewcode = ErrEwcode.KCLImmutableException_Ew - KCLException.__init__( - self, file_msgs=file_msgs, ewcode=self.ewcode, arg_msg=arg_msg - ) - - -class InvalidSyntaxError(KCLError, KCLSyntaxException): - @PreCheck( - ( - lambda v: CheckRules.check_list_item_type_allow_none( - v, err_template.ErrFileMsg - ) - ), - "file_msgs", - ) - @PreCheck((lambda v: CheckRules.check_type_allow_none(v, str)), "arg_msg") - def __init__( - self, - file_msgs: typing.List[err_template.ErrFileMsg] = None, - arg_msg: str = None, - ): - self.ewcode = ErrEwcode.InvalidSyntax_Ew - self.accepts_lark = [] - self.accepts_msg = [] - KCLException.__init__( - self, file_msgs=file_msgs, ewcode=self.ewcode, arg_msg=arg_msg - ) - - -class KCLTabError(KCLError, KCLSyntaxException): - @PreCheck( - ( - lambda v: CheckRules.check_list_item_type_allow_none( - v, err_template.ErrFileMsg - ) - ), - "file_msgs", - ) - @PreCheck((lambda v: CheckRules.check_type_allow_none(v, str)), "arg_msg") - def __init__( - self, - file_msgs: typing.List[err_template.ErrFileMsg] = None, - arg_msg: str = None, - ): - self.ewcode = ErrEwcode.KCLTabError_Ew - KCLException.__init__( - self, file_msgs=file_msgs, ewcode=self.ewcode, arg_msg=arg_msg - ) - - -class KCLIndentationError(KCLError, KCLSyntaxException): - @PreCheck( - ( - lambda v: CheckRules.check_list_item_type_allow_none( - v, err_template.ErrFileMsg - ) - ), - "file_msgs", - ) - @PreCheck((lambda v: CheckRules.check_type_allow_none(v, str)), "arg_msg") - def __init__( - self, - file_msgs: typing.List[err_template.ErrFileMsg] = None, - arg_msg: str = None, - ): - self.ewcode = ErrEwcode.KCLIndentationError_Ew - KCLException.__init__( - self, file_msgs=file_msgs, ewcode=self.ewcode, arg_msg=arg_msg - ) - - -class CannotFindModule(KCLError, KCLCompileException, KCLImportException): - @PreCheck( - ( - lambda v: CheckRules.check_list_item_type_allow_none( - v, err_template.ErrFileMsg - ) - ), - "file_msgs", - ) - @PreCheck((lambda v: CheckRules.check_type_allow_none(v, str)), "arg_msg") - def __init__( - self, - file_msgs: typing.List[err_template.ErrFileMsg] = None, - arg_msg: str = None, - ): - self.ewcode = ErrEwcode.CannotFindModule_Ew - KCLException.__init__( - self, file_msgs=file_msgs, ewcode=self.ewcode, arg_msg=arg_msg - ) - - -class FailedLoadModule(KCLError, KCLCompileException, KCLImportException): - @PreCheck( - ( - lambda v: CheckRules.check_list_item_type_allow_none( - v, err_template.ErrFileMsg - ) - ), - "file_msgs", - ) - @PreCheck((lambda v: CheckRules.check_type_allow_none(v, str)), "arg_msg") - def __init__( - self, - file_msgs: typing.List[err_template.ErrFileMsg] = None, - arg_msg: str = None, - ): - self.ewcode = ErrEwcode.FailedLoadModule_Ew - KCLException.__init__( - self, file_msgs=file_msgs, ewcode=self.ewcode, arg_msg=arg_msg - ) - - -class RecursiveLoad(KCLError, KCLCompileException, KCLImportException): - @PreCheck( - ( - lambda v: CheckRules.check_list_item_type_allow_none( - v, err_template.ErrFileMsg - ) - ), - "file_msgs", - ) - @PreCheck((lambda v: CheckRules.check_type_allow_none(v, str)), "arg_msg") - def __init__( - self, - file_msgs: typing.List[err_template.ErrFileMsg] = None, - arg_msg: str = None, - ): - self.ewcode = ErrEwcode.RecursiveLoad_Ew - KCLException.__init__( - self, file_msgs=file_msgs, ewcode=self.ewcode, arg_msg=arg_msg - ) - - -class FloatOverflow(KCLError, KCLRuntimeException, KCLOverflowException): - @PreCheck( - ( - lambda v: CheckRules.check_list_item_type_allow_none( - v, err_template.ErrFileMsg - ) - ), - "file_msgs", - ) - @PreCheck((lambda v: CheckRules.check_type_allow_none(v, str)), "arg_msg") - def __init__( - self, - file_msgs: typing.List[err_template.ErrFileMsg] = None, - arg_msg: str = None, - ): - self.ewcode = ErrEwcode.FloatOverflow_Ew - KCLException.__init__( - self, file_msgs=file_msgs, ewcode=self.ewcode, arg_msg=arg_msg - ) - - -class FloatUnderflow(KCLWarning, KCLCompileException, KCLOverflowException): - @PreCheck( - ( - lambda v: CheckRules.check_list_item_type_allow_none( - v, err_template.ErrFileMsg - ) - ), - "file_msgs", - ) - @PreCheck((lambda v: CheckRules.check_type_allow_none(v, str)), "arg_msg") - def __init__( - self, - file_msgs: typing.List[err_template.ErrFileMsg] = None, - arg_msg: str = None, - ): - self.ewcode = ErrEwcode.FloatUnderflow_Ew - KCLException.__init__( - self, file_msgs=file_msgs, ewcode=self.ewcode, arg_msg=arg_msg - ) - - -class IntOverflow(KCLError, KCLRuntimeException, KCLOverflowException): - @PreCheck( - ( - lambda v: CheckRules.check_list_item_type_allow_none( - v, err_template.ErrFileMsg - ) - ), - "file_msgs", - ) - @PreCheck((lambda v: CheckRules.check_type_allow_none(v, str)), "arg_msg") - def __init__( - self, - file_msgs: typing.List[err_template.ErrFileMsg] = None, - arg_msg: str = None, - ): - self.ewcode = ErrEwcode.IntOverflow_Ew - KCLException.__init__( - self, file_msgs=file_msgs, ewcode=self.ewcode, arg_msg=arg_msg - ) - - -class InvalidDocstring(KCLWarning, KCLCompileException, KCLDocException): - @PreCheck( - ( - lambda v: CheckRules.check_list_item_type_allow_none( - v, err_template.ErrFileMsg - ) - ), - "file_msgs", - ) - @PreCheck((lambda v: CheckRules.check_type_allow_none(v, str)), "arg_msg") - def __init__( - self, - file_msgs: typing.List[err_template.ErrFileMsg] = None, - arg_msg: str = None, - ): - self.ewcode = ErrEwcode.InvalidDocstring_Ew - KCLException.__init__( - self, file_msgs=file_msgs, ewcode=self.ewcode, arg_msg=arg_msg - ) - - -class DeprecatedError(KCLError, KCLRuntimeException, KCLDeprecatedException): - @PreCheck( - ( - lambda v: CheckRules.check_list_item_type_allow_none( - v, err_template.ErrFileMsg - ) - ), - "file_msgs", - ) - @PreCheck((lambda v: CheckRules.check_type_allow_none(v, str)), "arg_msg") - def __init__( - self, - file_msgs: typing.List[err_template.ErrFileMsg] = None, - arg_msg: str = None, - ): - self.ewcode = ErrEwcode.Deprecated_Ew - KCLException.__init__( - self, file_msgs=file_msgs, ewcode=self.ewcode, arg_msg=arg_msg - ) - - -class DeprecatedWarning(KCLWarning, KCLDeprecatedException): - @PreCheck( - ( - lambda v: CheckRules.check_list_item_type_allow_none( - v, err_template.ErrFileMsg - ) - ), - "file_msgs", - ) - @PreCheck((lambda v: CheckRules.check_type_allow_none(v, str)), "arg_msg") - def __init__( - self, - file_msgs: typing.List[err_template.ErrFileMsg] = None, - arg_msg: str = None, - ): - self.ewcode = ErrEwcode.DeprecatedWarning_Ew - KCLException.__init__( - self, file_msgs=file_msgs, ewcode=self.ewcode, arg_msg=arg_msg - ) - - -class UnKnownDecoratorError(KCLError, KCLCompileException, KCLDecoratorException): - @PreCheck( - ( - lambda v: CheckRules.check_list_item_type_allow_none( - v, err_template.ErrFileMsg - ) - ), - "file_msgs", - ) - @PreCheck((lambda v: CheckRules.check_type_allow_none(v, str)), "arg_msg") - def __init__( - self, - file_msgs: typing.List[err_template.ErrFileMsg] = None, - arg_msg: str = None, - ): - self.ewcode = ErrEwcode.UnKnownDecorator_Ew - KCLException.__init__( - self, file_msgs=file_msgs, ewcode=self.ewcode, arg_msg=arg_msg - ) - - -class InvalidDecoratorTargetError(KCLError, KCLCompileException, KCLDecoratorException): - @PreCheck( - ( - lambda v: CheckRules.check_list_item_type_allow_none( - v, err_template.ErrFileMsg - ) - ), - "file_msgs", - ) - @PreCheck((lambda v: CheckRules.check_type_allow_none(v, str)), "arg_msg") - def __init__( - self, - file_msgs: typing.List[err_template.ErrFileMsg] = None, - arg_msg: str = None, - ): - self.ewcode = ErrEwcode.InvalidDecoratorTarget_Ew - KCLException.__init__( - self, file_msgs=file_msgs, ewcode=self.ewcode, arg_msg=arg_msg - ) - - -class MixinNamingError(KCLError, KCLCompileException, KCLMixinException): - @PreCheck( - ( - lambda v: CheckRules.check_list_item_type_allow_none( - v, err_template.ErrFileMsg - ) - ), - "file_msgs", - ) - @PreCheck((lambda v: CheckRules.check_type_allow_none(v, str)), "arg_msg") - def __init__( - self, - file_msgs: typing.List[err_template.ErrFileMsg] = None, - arg_msg: str = None, - ): - self.ewcode = ErrEwcode.MixinNamingError_Ew - KCLException.__init__( - self, file_msgs=file_msgs, ewcode=self.ewcode, arg_msg=arg_msg - ) - - -class MixinStructureIllegal(KCLError, KCLCompileException, KCLMixinException): - @PreCheck( - ( - lambda v: CheckRules.check_list_item_type_allow_none( - v, err_template.ErrFileMsg - ) - ), - "file_msgs", - ) - @PreCheck((lambda v: CheckRules.check_type_allow_none(v, str)), "arg_msg") - def __init__( - self, - file_msgs: typing.List[err_template.ErrFileMsg] = None, - arg_msg: str = None, - ): - self.ewcode = ErrEwcode.MixinStructureIllegal_Ew - KCLException.__init__( - self, file_msgs=file_msgs, ewcode=self.ewcode, arg_msg=arg_msg - ) - - -class SchemaCheckFailure(KCLError, KCLRuntimeException, KCLSchemaException): - @PreCheck( - ( - lambda v: CheckRules.check_list_item_type_allow_none( - v, err_template.ErrFileMsg - ) - ), - "file_msgs", - ) - @PreCheck((lambda v: CheckRules.check_type_allow_none(v, str)), "arg_msg") - def __init__( - self, - file_msgs: typing.List[err_template.ErrFileMsg] = None, - arg_msg: str = None, - ): - self.ewcode = ErrEwcode.SchemaCheckFailure_Ew - KCLException.__init__( - self, file_msgs=file_msgs, ewcode=self.ewcode, arg_msg=arg_msg - ) - - -class CannotAddMembersComplieError(KCLError, KCLCompileException, KCLSchemaException): - @PreCheck( - ( - lambda v: CheckRules.check_list_item_type_allow_none( - v, err_template.ErrFileMsg - ) - ), - "file_msgs", - ) - @PreCheck((lambda v: CheckRules.check_type_allow_none(v, str)), "arg_msg") - def __init__( - self, - file_msgs: typing.List[err_template.ErrFileMsg] = None, - arg_msg: str = None, - ): - self.ewcode = ErrEwcode.CannotAddMembersComplieError_Ew - KCLException.__init__( - self, file_msgs=file_msgs, ewcode=self.ewcode, arg_msg=arg_msg - ) - - -class CannotAddMembersRuntimeError(KCLError, KCLRuntimeException, KCLSchemaException): - @PreCheck( - ( - lambda v: CheckRules.check_list_item_type_allow_none( - v, err_template.ErrFileMsg - ) - ), - "file_msgs", - ) - @PreCheck((lambda v: CheckRules.check_type_allow_none(v, str)), "arg_msg") - def __init__( - self, - file_msgs: typing.List[err_template.ErrFileMsg] = None, - arg_msg: str = None, - ): - self.ewcode = ErrEwcode.CannotAddMembersRuntimeError_Ew - KCLException.__init__( - self, file_msgs=file_msgs, ewcode=self.ewcode, arg_msg=arg_msg - ) - - -class IndexSignatureError(KCLError, KCLCompileException, KCLSchemaException): - @PreCheck( - ( - lambda v: CheckRules.check_list_item_type_allow_none( - v, err_template.ErrFileMsg - ) - ), - "file_msgs", - ) - @PreCheck((lambda v: CheckRules.check_type_allow_none(v, str)), "arg_msg") - def __init__( - self, - file_msgs: typing.List[err_template.ErrFileMsg] = None, - arg_msg: str = None, - ): - self.ewcode = ErrEwcode.IndexSignatureError_Ew - KCLException.__init__( - self, file_msgs=file_msgs, ewcode=self.ewcode, arg_msg=arg_msg - ) - - -class TypeRuntimeError(KCLError, KCLRuntimeException, KCLTypeException): - @PreCheck( - ( - lambda v: CheckRules.check_list_item_type_allow_none( - v, err_template.ErrFileMsg - ) - ), - "file_msgs", - ) - @PreCheck((lambda v: CheckRules.check_type_allow_none(v, str)), "arg_msg") - def __init__( - self, - file_msgs: typing.List[err_template.ErrFileMsg] = None, - arg_msg: str = None, - ): - self.ewcode = ErrEwcode.TypeRuntimeError_Ew - KCLException.__init__( - self, file_msgs=file_msgs, ewcode=self.ewcode, arg_msg=arg_msg - ) - - -class TypeComplieError(KCLError, KCLCompileException, KCLTypeException): - @PreCheck( - ( - lambda v: CheckRules.check_list_item_type_allow_none( - v, err_template.ErrFileMsg - ) - ), - "file_msgs", - ) - @PreCheck((lambda v: CheckRules.check_type_allow_none(v, str)), "arg_msg") - def __init__( - self, - file_msgs: typing.List[err_template.ErrFileMsg] = None, - arg_msg: str = None, - ): - self.ewcode = ErrEwcode.TypeComplieError_Ew - KCLException.__init__( - self, file_msgs=file_msgs, ewcode=self.ewcode, arg_msg=arg_msg - ) - - -class CompileError(KCLError, KCLCompileException, KCLComplingException): - @PreCheck( - ( - lambda v: CheckRules.check_list_item_type_allow_none( - v, err_template.ErrFileMsg - ) - ), - "file_msgs", - ) - @PreCheck((lambda v: CheckRules.check_type_allow_none(v, str)), "arg_msg") - def __init__( - self, - file_msgs: typing.List[err_template.ErrFileMsg] = None, - arg_msg: str = None, - ): - self.ewcode = ErrEwcode.CompileError_Ew - KCLException.__init__( - self, file_msgs=file_msgs, ewcode=self.ewcode, arg_msg=arg_msg - ) - - -class SelectorError(KCLError, KCLCompileException, KCLComplingException): - @PreCheck( - ( - lambda v: CheckRules.check_list_item_type_allow_none( - v, err_template.ErrFileMsg - ) - ), - "file_msgs", - ) - @PreCheck((lambda v: CheckRules.check_type_allow_none(v, str)), "arg_msg") - def __init__( - self, - file_msgs: typing.List[err_template.ErrFileMsg] = None, - arg_msg: str = None, - ): - self.ewcode = ErrEwcode.SelectorError_Ew - KCLException.__init__( - self, file_msgs=file_msgs, ewcode=self.ewcode, arg_msg=arg_msg - ) - - -class KCLNameError(KCLError, KCLCompileException, KCLComplingException): - @PreCheck( - ( - lambda v: CheckRules.check_list_item_type_allow_none( - v, err_template.ErrFileMsg - ) - ), - "file_msgs", - ) - @PreCheck((lambda v: CheckRules.check_type_allow_none(v, str)), "arg_msg") - def __init__( - self, - file_msgs: typing.List[err_template.ErrFileMsg] = None, - arg_msg: str = None, - ): - self.ewcode = ErrEwcode.KCLNameError_Ew - KCLException.__init__( - self, file_msgs=file_msgs, ewcode=self.ewcode, arg_msg=arg_msg - ) - - -class KCLValueError(KCLError, KCLCompileException, KCLComplingException): - @PreCheck( - ( - lambda v: CheckRules.check_list_item_type_allow_none( - v, err_template.ErrFileMsg - ) - ), - "file_msgs", - ) - @PreCheck((lambda v: CheckRules.check_type_allow_none(v, str)), "arg_msg") - def __init__( - self, - file_msgs: typing.List[err_template.ErrFileMsg] = None, - arg_msg: str = None, - ): - self.ewcode = ErrEwcode.KCLValueError_Ew - KCLException.__init__( - self, file_msgs=file_msgs, ewcode=self.ewcode, arg_msg=arg_msg - ) - - -class KCLKeyError(KCLError, KCLCompileException, KCLComplingException): - @PreCheck( - ( - lambda v: CheckRules.check_list_item_type_allow_none( - v, err_template.ErrFileMsg - ) - ), - "file_msgs", - ) - @PreCheck((lambda v: CheckRules.check_type_allow_none(v, str)), "arg_msg") - def __init__( - self, - file_msgs: typing.List[err_template.ErrFileMsg] = None, - arg_msg: str = None, - ): - self.ewcode = ErrEwcode.KCLKeyError_Ew - KCLException.__init__( - self, file_msgs=file_msgs, ewcode=self.ewcode, arg_msg=arg_msg - ) - - -class UniqueKeyError(KCLError, KCLCompileException, KCLComplingException): - @PreCheck( - ( - lambda v: CheckRules.check_list_item_type_allow_none( - v, err_template.ErrFileMsg - ) - ), - "file_msgs", - ) - @PreCheck((lambda v: CheckRules.check_type_allow_none(v, str)), "arg_msg") - def __init__( - self, - file_msgs: typing.List[err_template.ErrFileMsg] = None, - arg_msg: str = None, - ): - self.ewcode = ErrEwcode.UniqueKeyError_Ew - KCLException.__init__( - self, file_msgs=file_msgs, ewcode=self.ewcode, arg_msg=arg_msg - ) - - -class KCLAttributeComplieError(KCLError, KCLCompileException, KCLAttributeException): - @PreCheck( - ( - lambda v: CheckRules.check_list_item_type_allow_none( - v, err_template.ErrFileMsg - ) - ), - "file_msgs", - ) - @PreCheck((lambda v: CheckRules.check_type_allow_none(v, str)), "arg_msg") - def __init__( - self, - file_msgs: typing.List[err_template.ErrFileMsg] = None, - arg_msg: str = None, - ): - self.ewcode = ErrEwcode.KCLAttributeComplieError_Ew - KCLException.__init__( - self, file_msgs=file_msgs, ewcode=self.ewcode, arg_msg=arg_msg - ) - - -class KCLAttributeRuntimeError(KCLError, KCLRuntimeException, KCLAttributeException): - @PreCheck( - ( - lambda v: CheckRules.check_list_item_type_allow_none( - v, err_template.ErrFileMsg - ) - ), - "file_msgs", - ) - @PreCheck((lambda v: CheckRules.check_type_allow_none(v, str)), "arg_msg") - def __init__( - self, - file_msgs: typing.List[err_template.ErrFileMsg] = None, - arg_msg: str = None, - ): - self.ewcode = ErrEwcode.KCLAttributeRuntimeError_Ew - KCLException.__init__( - self, file_msgs=file_msgs, ewcode=self.ewcode, arg_msg=arg_msg - ) - - -class IllegalAttributeError(KCLError, KCLCompileException, KCLAttributeException): - @PreCheck( - ( - lambda v: CheckRules.check_list_item_type_allow_none( - v, err_template.ErrFileMsg - ) - ), - "file_msgs", - ) - @PreCheck((lambda v: CheckRules.check_type_allow_none(v, str)), "arg_msg") - def __init__( - self, - file_msgs: typing.List[err_template.ErrFileMsg] = None, - arg_msg: str = None, - ): - self.ewcode = ErrEwcode.IllegalAttributeError_Ew - KCLException.__init__( - self, file_msgs=file_msgs, ewcode=self.ewcode, arg_msg=arg_msg - ) - - -class MultiInheritError(KCLError, KCLCompileException, KCLInheritException): - @PreCheck( - ( - lambda v: CheckRules.check_list_item_type_allow_none( - v, err_template.ErrFileMsg - ) - ), - "file_msgs", - ) - @PreCheck((lambda v: CheckRules.check_type_allow_none(v, str)), "arg_msg") - def __init__( - self, - file_msgs: typing.List[err_template.ErrFileMsg] = None, - arg_msg: str = None, - ): - self.ewcode = ErrEwcode.MultiInheritError_Ew - KCLException.__init__( - self, file_msgs=file_msgs, ewcode=self.ewcode, arg_msg=arg_msg - ) - - -class CycleInheritError(KCLError, KCLCompileException, KCLInheritException): - @PreCheck( - ( - lambda v: CheckRules.check_list_item_type_allow_none( - v, err_template.ErrFileMsg - ) - ), - "file_msgs", - ) - @PreCheck((lambda v: CheckRules.check_type_allow_none(v, str)), "arg_msg") - def __init__( - self, - file_msgs: typing.List[err_template.ErrFileMsg] = None, - arg_msg: str = None, - ): - self.ewcode = ErrEwcode.CycleInheritError_Ew - KCLException.__init__( - self, file_msgs=file_msgs, ewcode=self.ewcode, arg_msg=arg_msg - ) - - -class IllegalInheritError(KCLError, KCLCompileException, KCLInheritException): - @PreCheck( - ( - lambda v: CheckRules.check_list_item_type_allow_none( - v, err_template.ErrFileMsg - ) - ), - "file_msgs", - ) - @PreCheck((lambda v: CheckRules.check_type_allow_none(v, str)), "arg_msg") - def __init__( - self, - file_msgs: typing.List[err_template.ErrFileMsg] = None, - arg_msg: str = None, - ): - self.ewcode = ErrEwcode.IllegalInheritError_Ew - KCLException.__init__( - self, file_msgs=file_msgs, ewcode=self.ewcode, arg_msg=arg_msg - ) - - -class IllegalArgumentRuntimeError(KCLError, KCLRuntimeException, KCLArgumentException): - @PreCheck( - ( - lambda v: CheckRules.check_list_item_type_allow_none( - v, err_template.ErrFileMsg - ) - ), - "file_msgs", - ) - @PreCheck((lambda v: CheckRules.check_type_allow_none(v, str)), "arg_msg") - def __init__( - self, - file_msgs: typing.List[err_template.ErrFileMsg] = None, - arg_msg: str = None, - ): - self.ewcode = ErrEwcode.IllegalArgumentRuntimeError_Ew - KCLException.__init__( - self, file_msgs=file_msgs, ewcode=self.ewcode, arg_msg=arg_msg - ) - - -class IllegalArgumentComplieError(KCLError, KCLCompileException, KCLArgumentException): - @PreCheck( - ( - lambda v: CheckRules.check_list_item_type_allow_none( - v, err_template.ErrFileMsg - ) - ), - "file_msgs", - ) - @PreCheck((lambda v: CheckRules.check_type_allow_none(v, str)), "arg_msg") - def __init__( - self, - file_msgs: typing.List[err_template.ErrFileMsg] = None, - arg_msg: str = None, - ): - self.ewcode = ErrEwcode.IllegalArgumentComplieError_Ew - KCLException.__init__( - self, file_msgs=file_msgs, ewcode=self.ewcode, arg_msg=arg_msg - ) - - -class IllegalArgumentSyntaxError(KCLError, KCLSyntaxException, KCLArgumentException): - @PreCheck( - ( - lambda v: CheckRules.check_list_item_type_allow_none( - v, err_template.ErrFileMsg - ) - ), - "file_msgs", - ) - @PreCheck((lambda v: CheckRules.check_type_allow_none(v, str)), "arg_msg") - def __init__( - self, - file_msgs: typing.List[err_template.ErrFileMsg] = None, - arg_msg: str = None, - ): - self.ewcode = ErrEwcode.IllegalArgumentSyntaxError_Ew - KCLException.__init__( - self, file_msgs=file_msgs, ewcode=self.ewcode, arg_msg=arg_msg - ) - - -class EvaluationError(KCLError, KCLRuntimeException, KCLRunningException): - @PreCheck( - ( - lambda v: CheckRules.check_list_item_type_allow_none( - v, err_template.ErrFileMsg - ) - ), - "file_msgs", - ) - @PreCheck((lambda v: CheckRules.check_type_allow_none(v, str)), "arg_msg") - def __init__( - self, - file_msgs: typing.List[err_template.ErrFileMsg] = None, - arg_msg: str = None, - ): - self.ewcode = ErrEwcode.EvaluationError_Ew - KCLException.__init__( - self, file_msgs=file_msgs, ewcode=self.ewcode, arg_msg=arg_msg - ) - - -class InvalidFormatSpec(KCLError, KCLRuntimeException, KCLRunningException): - @PreCheck( - ( - lambda v: CheckRules.check_list_item_type_allow_none( - v, err_template.ErrFileMsg - ) - ), - "file_msgs", - ) - @PreCheck((lambda v: CheckRules.check_type_allow_none(v, str)), "arg_msg") - def __init__( - self, - file_msgs: typing.List[err_template.ErrFileMsg] = None, - arg_msg: str = None, - ): - self.ewcode = ErrEwcode.InvalidFormatSpec_Ew - KCLException.__init__( - self, file_msgs=file_msgs, ewcode=self.ewcode, arg_msg=arg_msg - ) - - -class KCLAssertionError(KCLError, KCLRuntimeException, KCLRunningException): - @PreCheck( - ( - lambda v: CheckRules.check_list_item_type_allow_none( - v, err_template.ErrFileMsg - ) - ), - "file_msgs", - ) - @PreCheck((lambda v: CheckRules.check_type_allow_none(v, str)), "arg_msg") - def __init__( - self, - file_msgs: typing.List[err_template.ErrFileMsg] = None, - arg_msg: str = None, - ): - self.ewcode = ErrEwcode.KCLAssertionError_Ew - KCLException.__init__( - self, file_msgs=file_msgs, ewcode=self.ewcode, arg_msg=arg_msg - ) - - -class ImmutableRuntimeError(KCLError, KCLCompileException, KCLImmutableException): - @PreCheck( - ( - lambda v: CheckRules.check_list_item_type_allow_none( - v, err_template.ErrFileMsg - ) - ), - "file_msgs", - ) - @PreCheck((lambda v: CheckRules.check_type_allow_none(v, str)), "arg_msg") - def __init__( - self, - file_msgs: typing.List[err_template.ErrFileMsg] = None, - arg_msg: str = None, - ): - self.ewcode = ErrEwcode.ImmutableRuntimeError_Ew - KCLException.__init__( - self, file_msgs=file_msgs, ewcode=self.ewcode, arg_msg=arg_msg - ) - - -class ImmutableCompileError(KCLError, KCLCompileException, KCLImmutableException): - @PreCheck( - ( - lambda v: CheckRules.check_list_item_type_allow_none( - v, err_template.ErrFileMsg - ) - ), - "file_msgs", - ) - @PreCheck((lambda v: CheckRules.check_type_allow_none(v, str)), "arg_msg") - def __init__( - self, - file_msgs: typing.List[err_template.ErrFileMsg] = None, - arg_msg: str = None, - ): - self.ewcode = ErrEwcode.ImmutableCompileError_Ew - KCLException.__init__( - self, file_msgs=file_msgs, ewcode=self.ewcode, arg_msg=arg_msg - ) - - -class KCLRecursionError(KCLError, KCLRuntimeException, KCLRunningException): - @PreCheck( - ( - lambda v: CheckRules.check_list_item_type_allow_none( - v, err_template.ErrFileMsg - ) - ), - "file_msgs", - ) - @PreCheck((lambda v: CheckRules.check_type_allow_none(v, str)), "arg_msg") - def __init__( - self, - file_msgs: typing.List[err_template.ErrFileMsg] = None, - arg_msg: str = None, - ): - self.ewcode = ErrEwcode.KCLRecursionError_Ew - KCLException.__init__( - self, file_msgs=file_msgs, ewcode=self.ewcode, arg_msg=arg_msg - ) - - -class PlanError(KCLError, KCLRuntimeException, KCLRunningException): - @PreCheck( - ( - lambda v: CheckRules.check_list_item_type_allow_none( - v, err_template.ErrFileMsg - ) - ), - "file_msgs", - ) - @PreCheck((lambda v: CheckRules.check_type_allow_none(v, str)), "arg_msg") - def __init__( - self, - file_msgs: typing.List[err_template.ErrFileMsg] = None, - arg_msg: str = None, - ): - self.ewcode = ErrEwcode.PlanError_Ew - KCLException.__init__( - self, file_msgs=file_msgs, ewcode=self.ewcode, arg_msg=arg_msg - ) - - -@unique -class ErrType(Enum): - InvalidSyntax_TYPE = (0,) - TabError_TYPE = (1,) - IndentationError_TYPE = (2,) - CannotFindModule_TYPE = (3,) - FailedLoadModule_TYPE = (4,) - CompileError_TYPE = (5,) - EvaluationError_TYPE = (6,) - RecursiveLoad_TYPE = (7,) - FloatOverflow_TYPE = (8,) - FloatUnderflow_TYPE = (9,) - IntOverflow_TYPE = (10,) - InvalidDocstring_TYPE = (11,) - Deprecated_TYPE = (12,) - UnKnownDecorator_TYPE = (13,) - InvalidDecoratorTarget_TYPE = (14,) - InvalidFormatSpec_TYPE = (15,) - SelectorError_TYPE = (16,) - SchemaCheckFailure_TYPE = (17,) - MixinNamingError_TYPE = (18,) - MixinStructureIllegal_TYPE = (19,) - - IndexSignatureError_TYPE = (20,) - TypeError_Runtime_TYPE = (21,) - TypeError_Compile_TYPE = (22,) - NameError_TYPE = (23,) - ValueError_TYPE = (24,) - KeyError_TYPE = (25,) - UniqueKeyError_TYPE = (26,) - AttributeError_TYPE = (27,) - AttributeError_Runtime_TYPE = (28,) - AssertionError_TYPE = (29,) - ImmutableCompileError_TYPE = (30,) - ImmutableRuntimeError_TYPE = (31,) - MultiInheritError_TYPE = (32,) - CycleInheritError_TYPE = (33,) - IllegalInheritError_TYPE = (34,) - IllegalAttributeError_TYPE = (35,) - IllegalArgumentError_TYPE = (36,) - IllegalArgumentError_Complie_TYPE = (37,) - IllegalArgumentError_Syntax_TYPE = (38,) - RecursionError_TYPE = (39,) - PlanError_TYPE = (40,) - Deprecated_Warning_TYPE = (41,) - CannotAddMembers_TYPE = (42,) - CannotAddMembers_Runtime_TYPE = (43,) - - -ERR_TYPE_EWCODE_MAP = { - ErrType.InvalidSyntax_TYPE: InvalidSyntaxError, - ErrType.TabError_TYPE: KCLTabError, - ErrType.IndentationError_TYPE: KCLIndentationError, - ErrType.CannotFindModule_TYPE: CannotFindModule, - ErrType.FailedLoadModule_TYPE: FailedLoadModule, - ErrType.CompileError_TYPE: CompileError, - ErrType.EvaluationError_TYPE: EvaluationError, - ErrType.RecursiveLoad_TYPE: RecursiveLoad, - ErrType.FloatOverflow_TYPE: FloatOverflow, - ErrType.FloatUnderflow_TYPE: FloatUnderflow, - ErrType.IntOverflow_TYPE: IntOverflow, - ErrType.InvalidDocstring_TYPE: InvalidDocstring, - ErrType.Deprecated_TYPE: DeprecatedError, - ErrType.Deprecated_Warning_TYPE: DeprecatedWarning, - ErrType.UnKnownDecorator_TYPE: UnKnownDecoratorError, - ErrType.InvalidDecoratorTarget_TYPE: InvalidDecoratorTargetError, - ErrType.InvalidFormatSpec_TYPE: InvalidFormatSpec, - ErrType.SelectorError_TYPE: SelectorError, - ErrType.SchemaCheckFailure_TYPE: SchemaCheckFailure, - ErrType.MixinNamingError_TYPE: MixinNamingError, - ErrType.MixinStructureIllegal_TYPE: MixinStructureIllegal, - ErrType.CannotAddMembers_TYPE: CannotAddMembersComplieError, - ErrType.CannotAddMembers_Runtime_TYPE: CannotAddMembersRuntimeError, - ErrType.IndexSignatureError_TYPE: IndexSignatureError, - ErrType.TypeError_Runtime_TYPE: TypeRuntimeError, - ErrType.TypeError_Compile_TYPE: TypeComplieError, - ErrType.NameError_TYPE: KCLNameError, - ErrType.ValueError_TYPE: KCLValueError, - ErrType.KeyError_TYPE: KCLKeyError, - ErrType.UniqueKeyError_TYPE: UniqueKeyError, - ErrType.AttributeError_TYPE: KCLAttributeComplieError, - ErrType.AttributeError_Runtime_TYPE: KCLAttributeRuntimeError, - ErrType.AssertionError_TYPE: KCLAssertionError, - ErrType.ImmutableCompileError_TYPE: ImmutableCompileError, - ErrType.ImmutableRuntimeError_TYPE: ImmutableRuntimeError, - ErrType.MultiInheritError_TYPE: MultiInheritError, - ErrType.CycleInheritError_TYPE: CycleInheritError, - ErrType.IllegalInheritError_TYPE: IllegalInheritError, - ErrType.IllegalAttributeError_TYPE: IllegalAttributeError, - ErrType.IllegalArgumentError_TYPE: IllegalArgumentRuntimeError, - ErrType.IllegalArgumentError_Complie_TYPE: IllegalArgumentComplieError, - ErrType.IllegalArgumentError_Syntax_TYPE: IllegalArgumentSyntaxError, - ErrType.RecursionError_TYPE: KCLRecursionError, - ErrType.PlanError_TYPE: PlanError, -} - - -@PreCheck( - (lambda v: CheckRules.check_list_item_type_allow_none(v, err_template.ErrFileMsg)), - "file_msgs", -) -@PreCheck((lambda v: CheckRules.check_type_not_none(v, ErrType)), "err_type") -@PreCheck((lambda v: CheckRules.check_type_allow_none(v, str)), "arg_msg") -@PostCheck(lambda result: CheckRules.check_type_not_none(result, KCLException)) -def get_exception( - err_type: ErrType = None, - file_msgs: typing.List[err_template.ErrFileMsg] = None, - arg_msg: str = None, -): - return ERR_TYPE_EWCODE_MAP[err_type](file_msgs=file_msgs, arg_msg=arg_msg) - - -@PreCheck( - (lambda v: CheckRules.check_list_item_type_allow_none(v, err_template.ErrFileMsg)), - "file_msgs", -) -@PreCheck((lambda v: CheckRules.check_type_allow_none(v, str)), "arg_msg") -@PreCheck((lambda v: CheckRules.check_type_not_none(v, ErrType)), "err_type") -def report_exception( - err_type: ErrType, - file_msgs: typing.List[err_template.ErrFileMsg] = None, - arg_msg: str = None, -): - raise get_exception(err_type, file_msgs, arg_msg) - - -@PreCheck( - (lambda v: CheckRules.check_list_item_type_allow_none(v, err_template.ErrFileMsg)), - "file_msgs", -) -@PreCheck((lambda v: CheckRules.check_type_allow_none(v, str)), "arg_msg") -@PreCheck((lambda v: CheckRules.check_type_not_none(v, ErrType)), "err_type") -def report_warning( - err_type: ErrType, - file_msgs: typing.List[err_template.ErrFileMsg] = None, - arg_msg: str = None, -): - print_kcl_warning_message( - get_exception(err_type, file_msgs, arg_msg), file=sys.stderr - ) - - -@PreCheck((lambda v: CheckRules.check_type_not_none(v, KCLException)), "err") -def print_kcl_error_message(err: KCLException, file=sys.stderr): - err_msg = err.show_msg_with_theme() if file.isatty() else (str(err)) - print(err_msg, file=file) - - -@PreCheck((lambda v: CheckRules.check_type_not_none(v, KCLWarning)), "err") -def print_kcl_warning_message(err: KCLWarning, file=sys.stderr): - err_msg = err.show_msg_with_theme() if file.isatty() else (str(err)) - print(err_msg, file=file) - - -@PreCheck((lambda v: CheckRules.check_type_not_none(v, Exception)), "err") -def print_common_error_message(err: Exception, file=sys.stderr): - print("Error: {0}".format(err), file=file) - - -@PreCheck((lambda v: CheckRules.check_type_allow_none(v, Exception)), "err") -def print_internal_error_message(err: Exception = None, file=sys.stderr): - if err: - print(err, file=file) - print("Internal Error! Please report a bug to us.", file=file) diff --git a/internal/kclvm_py/kcl/error/readme.md b/internal/kclvm_py/kcl/error/readme.md deleted file mode 100644 index 00c4300f3..000000000 --- a/internal/kclvm_py/kcl/error/readme.md +++ /dev/null @@ -1,139 +0,0 @@ -# KCL excpetion -This readme mainly introduces the KCL exceptions and KCL exception message work flow. - -## 1. Work Flow -``` - ---------------- ---------------- ----------------------- ------------------ - | | | | | | | | - | kcl_error.py | --> | kcl_error.py | ---> | kcl_err_template.py | ---> | kcl_err_msg.py | - no color | | | | | | | | - KCLXXXError.gen_err_msg() <-------- | | | | | no color | | | - color | KCLXXXError | <-- | KCLException | <--- | <---------------- | <--- | | - KCLXXXError.show_msg_with_theme() <-------- | | | | | | | | - ---------------- ---------------- ----------------------- ------------------ - ^ | color - | v - ----------------------- - | kcl_err_theme.py | - | | - ----------------------- - - -``` -- KCLXXXError.gen_err_msg() - 1. `KCLXXXError` will call method `gen_err_msg()` of the parent class `KCLException` - and get KCL error message without highlighting. - - 2. The `gen_err_msg()` of `KCLException` will call methods provided in `kcl_err_template.py` - to obtain the structured KCL error message. - - 3. `kcl_err_template.py` will obtain KCL error message constants through methods provided by `kcl_err_msg.py` - and return the structured error messages to `KCLException`. - - 4. Because `gen_err_msg()` sets the highlight flag to False, - so `kcl_err_template.py` will return KCL error messages without highlight. - - -- KCLXXXError.show_msg_with_theme() - 1. `KCLXXXError` will call method `show_msg_with_theme()` of the parent class `KCLException` - and get KCL error message with highlighting. - - 2. The `gen_err_msg()` of `KCLException` will call methods provided in `kcl_err_template.py` - to obtain the structured KCL error message. - - 3. `kcl_err_template.py` will obtain KCL error message constants through methods provided by `kcl_err_msg.py` - and return the structured and highlight error messages to `KCLException`. - - 4. Because `show_msg_with_theme()` sets the highlight flag to True, - so before returning KCL error messages to `KCLException`, - `kcl_err_template.py` will call the method provided in `kcl_err_theme.py` to highlight KCL error messages. - Then `kcl_err_template.py` will return KCL error messages with highlight. - -## 2. KCL exceptions - -This section lists all the exceptions in KCLVM. -They can be divided into a three-level inheritance structure. -The top-level KCLException inherits Python Exception, -the second level contains 12 categories of KCL exceptions, -and the last level contains 44 exceptions inherits the second level exceptions。 - -Each exception in KCL contains a unique identifier `ewcode`. -Each bit in ewcode shows different information in this exception. - -For example: the ewcode of exception `FailedLoadModuleError` in kclvm is `E2F05`. -``` -E: Error : This exception is an error. -2: Compile : This exception occured during compiling -F: Import : This exception occurred when importing the package -05: FailedLoadModule : This exception occurred because the module failed to load -``` - -All exceptions, the inheritance relationship between exceptions, -and ewcode are shown in the following table. - -| ewcode | KCL exception | parent exception | -| ---- | ---- | ---- | -| 00000 | KCLException | Exception | -| E0000 | KCLError | KCLException | -| W0000 | KCLWarning | KCLException | -| 01000 | KCLSyntaxException | KCLException | -| 02000 | KCLCompileException | KCLException | -| 03000 | KCLRuntimeException | KCLException | -| 00A00 | KCLAttributeException | KCLException | -| 00B00 | KCLSchemaException | KCLException | -| 00C00 | KCLMixinException | KCLException | -| 00D00 | KCLInheritException | KCLException | -| 00F00 | KCLImportException | KCLException | -| 00G00 | KCLTypeException | KCLException | -| 00H00 | KCLDecoratorException | KCLException | -| 00I00 | KCLArgumentException | KCLException | -| 00K00 | KCLOverflowException | KCLException | -| 00L00 | KCLComplingException | KCLException | -| 00M00 | KCLRunningException| KCLException | -| 00N00 | KCLDeprecatedException | KCLException | -| 00P00 | KCLDocException | KCLException | -| 00Q00 | KCLImmutableException | KCLException | -| E1001 | InvalidSyntaxError | KCLError, KCLSyntaxException | -| E1002 | KCLTabError | KCLError, KCLSyntaxException | -| E1003 | KCLIndentationError | KCLError, KCLSyntaxException | -| E2F04 | CannotFindModule | KCLError, KCLCompileException, KCLImportException | -| E2F05 | FailedLoadModule | KCLError, KCLCompileException, KCLImportException | -| E3F06 | RecursiveLoad | KCLError, KCLRuntimeException, KCLImportException | -| E3K04 | FloatOverflow | KCLError, KCLRuntimeException, KCLOverflowException | -| W2K04 | FloatUnderflow | KCLWarning, KCLCompileException, KCLOverflowException | -| E3K09 | IntOverflow | KCLError, KCLRuntimeException, KCLOverflowException | -| W2P10 | InvalidDocstring | KCLWarning, KCLCompileException, KCLDocException | -| E3N11 | DeprecatedError | KCLError, KCLRuntimeException, KCLDeprecatedException | -| W2N12 | DeprecatedWarning | KCLWarning, KCLDeprecatedException | -| E2H13 | UnKnownDecoratorError | KCLError, KCLCompileException, KCLDecoratorException | -| E2H14 | InvalidDecoratorTargetError | KCLError, KCLCompileException, KCLDecoratorException | -| E2C15 | MixinNamingError | KCLError, KCLCompileException, KCLMixinException | -| E2C16 | MixinStructureIllegal | KCLError, KCLCompileException, KCLMixinException | -| E3B17 | SchemaCheckFailure | KCLError, KCLRuntimeException, KCLSchemaException | -| E2B17 | CannotAddMembersComplieError | KCLError, KCLCompileException, KCLSchemaException | -| E3B19 | CannotAddMembersRuntimeError | KCLError, KCLRuntimeException, KCLSchemaException | -| E2B20 | IndexSignatureError | KCLError, KCLCompileException, KCLSchemaException | -| E3G21 | TypeRuntimeError | KCLError, KCLRuntimeException, KCLTypeException | -| E2G22 | TypeComplieError | KCLError, KCLCompileException, KCLTypeException | -| E2L23 | CompileError | KCLError, KCLCompileException, KCLComplingException | -| E2L24 | SelectorError | KCLError, KCLCompileException, KCLComplingException | -| E2L25 | KCLNameError | KCLError, KCLCompileException, KCLComplingException | -| E2L26 | KCLValueError | KCLError, KCLCompileException, KCLComplingException | -| E2L27 | KCLKeyError | KCLError, KCLCompileException, KCLComplingException | -| E2L28 | UniqueKeyError | KCLError, KCLCompileException, KCLComplingException | -| E2A29 | KCLAttributeComplieError | KCLError, KCLCompileException, KCLAttributeException | -| E3A30 | KCLAttributeRuntimeError | KCLError, KCLRuntimeException, KCLAttributeException | -| E2A31 | IllegalAttributeError | KCLError, KCLCompileException, KCLAttributeException | -| E2D32 | MultiInheritError | KCLError, KCLCompileException, KCLInheritException | -| E2D33 | CycleInheritError | KCLError, KCLRuntimeException, KCLInheritException | -| E2D34 | IllegalInheritError | KCLError, KCLCompileException, KCLInheritException | -| E3I35 | IllegalArgumentRuntimeError | KCLError, KCLRuntimeException, KCLArgumentException | -| E2I36 | IllegalArgumentComplieError | KCLError, KCLCompileException, KCLArgumentException | -| E1I37 | IllegalArgumentSyntaxError | KCLError, KCLSyntaxException, KCLArgumentException | -| E3M38 | EvaluationError | KCLError, KCLRuntimeException, KCLRunningException | -| E3M39 | InvalidFormatSpec | KCLError, KCLRuntimeException, KCLRunningException | -| E3M40 | KCLAssertionError | KCLError, KCLRuntimeException, KCLRunningException | -| E3M41 | ImmutableCompileError | KCLError, KCLCompileException, KCLImmutableException | -| E3M44 | ImmutableRuntimeError | KCLError, KCLRuntimeException, KCLImmutableException | -| E3M42 | KCLRecursionError | KCLError, KCLRuntimeException, KCLRunningException | -| E3M43 | PlanError | KCLError, KCLRuntimeException, KCLRunningException | diff --git a/internal/kclvm_py/kcl/grammar/kcl.lark b/internal/kclvm_py/kcl/grammar/kcl.lark deleted file mode 100644 index 398fed0e1..000000000 --- a/internal/kclvm_py/kcl/grammar/kcl.lark +++ /dev/null @@ -1,263 +0,0 @@ -// Copyright 2021 The KCL Authors. All rights reserved. - -//////////// KCL grammar //////////// -start: (NEWLINE | statement)* - -statement: simple_stmt | compound_stmt -simple_stmt: (assign_stmt | unification_stmt | expr_stmt | assert_stmt | import_stmt | type_alias_stmt) NEWLINE -compound_stmt: if_stmt | schema_stmt | rule_stmt - -//////////// import_stmt //////////// -import_stmt: IMPORT dot_name (AS NAME)? -dot_name: (leading_dots identifier) | identifier -leading_dots: DOT+ - -/////////// assert_stmt //////////// -assert_stmt: ASSERT simple_expr (IF simple_expr)? (COMMA test)? - -//////////// if_stmt //////////// -if_stmt: IF test COLON execution_block (ELIF test COLON execution_block)* (ELSE COLON execution_block)? -execution_block: if_simple_stmt | NEWLINE _INDENT schema_init_stmt+ _DEDENT -if_simple_stmt: (simple_assign_stmt | unification_stmt | expr_stmt | assert_stmt) NEWLINE - -//////////// assign_stmt //////////// -assign_stmt: identifier [COLON type] (ASSIGN identifier)* ASSIGN test - | identifier (COMP_PLUS | COMP_MINUS | COMP_MULTIPLY | COMP_DOUBLE_STAR | COMP_DIVIDE - | COMP_DOUBLE_DIVIDE | COMP_MOD | COMP_AND | COMP_OR | COMP_XOR | COMP_SHIFT_LEFT - | COMP_SHIFT_RIGHT) test - -simple_assign_stmt: identifier ASSIGN test - | identifier (COMP_PLUS | COMP_MINUS | COMP_MULTIPLY | COMP_DOUBLE_STAR | COMP_DIVIDE - | COMP_DOUBLE_DIVIDE | COMP_MOD | COMP_AND | COMP_OR | COMP_XOR | COMP_SHIFT_LEFT - | COMP_SHIFT_RIGHT) test - -//////////// unification_stmt //////////// -unification_stmt: identifier COLON schema_expr - -//////////// schema_stmt //////////// -schema_stmt: [decorators] (SCHEMA|MIXIN|PROTOCOL) NAME [LEFT_BRACKETS [schema_arguments] RIGHT_BRACKETS] [LEFT_PARENTHESES identifier (COMMA identifier)* RIGHT_PARENTHESES] [for_host] COLON NEWLINE [schema_body] -schema_arguments: schema_argument (COMMA schema_argument)* -schema_argument: NAME [COLON type] [ASSIGN test] -schema_body: _INDENT (string NEWLINE)* [mixin_stmt] (schema_attribute_stmt|schema_init_stmt|schema_index_signature)* [check_block] _DEDENT -schema_attribute_stmt: attribute_stmt NEWLINE -attribute_stmt: [decorators] identifier [QUESTION] COLON type [(ASSIGN|COMP_OR) test] -schema_init_stmt: if_simple_stmt | if_stmt -schema_index_signature: LEFT_BRACKETS [NAME COLON] [ELLIPSIS] basic_type RIGHT_BRACKETS COLON type [ASSIGN test] NEWLINE - -//////////// rule_stmt //////////// -rule_stmt: [decorators] RULE NAME [LEFT_BRACKETS [schema_arguments] RIGHT_BRACKETS] [LEFT_PARENTHESES identifier (COMMA identifier)* RIGHT_PARENTHESES] [for_host] COLON NEWLINE [rule_body] -rule_body: _INDENT (string NEWLINE)* check_expr+ _DEDENT - -for_host: FOR identifier - -/////////// decorators //////////// -decorators: (AT decorator_expr NEWLINE)+ -decorator_expr: identifier [call_suffix] - -//////////// type //////////// -type: type_element (OR type_element)* -type_element: schema_type | basic_type | compound_type | literal_type -schema_type: identifier -basic_type: STRING_TYPE | INT_TYPE | FLOAT_TYPE | BOOL_TYPE | ANY_TYPE -compound_type: list_type | dict_type -list_type: LEFT_BRACKETS (type)? RIGHT_BRACKETS -dict_type: LEFT_BRACE (type)? COLON (type)? RIGHT_BRACE -literal_type: string | number | TRUE | FALSE | NONE - -//////////// type alias //////////// -type_alias_stmt: TYPE NAME ASSIGN type - -//////////// check_stmt //////////// -check_block: CHECK COLON NEWLINE _INDENT check_expr+ _DEDENT -check_expr: simple_expr [IF simple_expr] [COMMA primary_expr] NEWLINE - -//////////// mixin_stmt //////////// -mixin_stmt: MIXIN LEFT_BRACKETS [mixins | multiline_mixins] RIGHT_BRACKETS NEWLINE -multiline_mixins: NEWLINE _INDENT mixins NEWLINE _DEDENT -mixins: identifier (COMMA (NEWLINE mixins | identifier))* - - -//////////// expression_stmt //////////// -expr_stmt: testlist_expr -testlist_expr: test (COMMA test)* -test: if_expr | simple_expr -if_expr: simple_expr IF simple_expr ELSE test - -simple_expr: unary_expr | binary_expr | primary_expr - -unary_expr: un_op simple_expr -binary_expr: simple_expr bin_op simple_expr - -bin_op: L_OR | L_AND - | OR | XOR | AND - | SHIFT_LEFT | SHIFT_RIGHT - | PLUS | MINUS | MULTIPLY | DIVIDE | MOD | DOUBLE_DIVIDE - | DOUBLE_STAR - | EQUAL_TO | NOT_EQUAL_TO - | LESS_THAN | GREATER_THAN | LESS_THAN_OR_EQUAL_TO | GREATER_THAN_OR_EQUAL_TO - | IN | L_NOT IN | IS | IS L_NOT | L_NOT | AS -un_op: L_NOT | PLUS | MINUS | NOT - -primary_expr: identifier call_suffix | operand | primary_expr select_suffix | primary_expr call_suffix | primary_expr slice_suffix -operand: identifier | number | string | constant | quant_expr | list_expr | list_comp | config_expr | dict_comp | schema_expr | lambda_expr | LEFT_PARENTHESES test RIGHT_PARENTHESES -select_suffix: [QUESTION] DOT NAME -call_suffix: LEFT_PARENTHESES [arguments [COMMA]] RIGHT_PARENTHESES -slice_suffix: [QUESTION] LEFT_BRACKETS (test | [test] COLON [test] [COLON [test]]) RIGHT_BRACKETS -arguments: argument (COMMA argument)* -argument: test | NAME ASSIGN test | MULTIPLY test | DOUBLE_STAR test - - -//////////// operand //////////// -identifier: NAME (DOT NAME)* -quant_expr: quant_op [ identifier COMMA ] identifier IN quant_target LEFT_BRACE (simple_expr [IF simple_expr] | NEWLINE _INDENT simple_expr [IF simple_expr] NEWLINE _DEDENT)? RIGHT_BRACE -quant_target: string | identifier | list_expr | list_comp | config_expr | dict_comp -quant_op: ALL | ANY | FILTER | MAP -list_expr: LEFT_BRACKETS [list_items | NEWLINE [_INDENT list_items _DEDENT]] RIGHT_BRACKETS -list_items: list_item ((COMMA [NEWLINE] | [NEWLINE]) list_item)* [COMMA] [NEWLINE] -list_item: test | star_expr | if_item -list_comp: LEFT_BRACKETS (list_item comp_clause+ | NEWLINE _INDENT list_item comp_clause+ _DEDENT) RIGHT_BRACKETS -dict_comp: LEFT_BRACE (entry comp_clause+ | NEWLINE _INDENT entry comp_clause+ _DEDENT) RIGHT_BRACE -entry: test (COLON | ASSIGN | COMP_PLUS) test -comp_clause: FOR loop_variables [COMMA] IN simple_expr [NEWLINE] [IF test [NEWLINE]] -if_entry: IF test COLON if_entry_exec_block (ELIF test COLON if_entry_exec_block)* (ELSE COLON if_entry_exec_block)? -if_entry_exec_block: (test (COLON | ASSIGN | COMP_PLUS) test | double_star_expr | if_entry) [NEWLINE] | NEWLINE _INDENT (test (COLON | ASSIGN | COMP_PLUS) test | double_star_expr | if_entry) ((COMMA [NEWLINE] | [NEWLINE]) (test (COLON | ASSIGN | COMP_PLUS) test | double_star_expr | if_entry))* [COMMA] [NEWLINE] _DEDENT -if_item: IF test COLON if_item_exec_block (ELIF test COLON if_item_exec_block)* (ELSE COLON if_item_exec_block)? -if_item_exec_block: list_item [NEWLINE] | NEWLINE _INDENT list_item ((COMMA [NEWLINE] | NEWLINE) list_item)* [COMMA] [NEWLINE] _DEDENT - -star_expr: MULTIPLY primary_expr -double_star_expr: DOUBLE_STAR primary_expr -loop_variables: primary_expr (COMMA primary_expr)* -schema_expr: identifier (LEFT_PARENTHESES [arguments] RIGHT_PARENTHESES)? config_expr -config_expr: LEFT_BRACE [config_entries | NEWLINE [_INDENT config_entries _DEDENT]] RIGHT_BRACE -config_entries: config_entry ((COMMA [NEWLINE] | [NEWLINE]) config_entry)* [COMMA] [NEWLINE] -config_entry: test (COLON | ASSIGN | COMP_PLUS) test | double_star_expr | if_entry - -//////////// lambda_expr //////////// -lambda_expr: LAMBDA [schema_arguments] [RIGHT_ARROW type] LEFT_BRACE [expr_stmt | NEWLINE _INDENT schema_init_stmt+ _DEDENT] RIGHT_BRACE - -//////////// misc //////////// -number: DEC_NUMBER [multiplier] | HEX_NUMBER | BIN_NUMBER | OCT_NUMBER | FLOAT_NUMBER -multiplier: SI_N_L | SI_U_L | SI_M_L | SI_K_L | SI_K | SI_M | SI_G | SI_T | SI_P - | SI_K_IEC | SI_M_IEC | SI_G_IEC | SI_T_IEC | SI_P_IEC -string: STRING | LONG_STRING -constant : TRUE | FALSE | NONE | UNDEFINED -// Tokens - -ASSIGN: "=" -COLON: ":" -SEMI_COLON: ";" -COMMA: "," -QUESTION: "?" -ELLIPSIS: "..." -RIGHT_ARROW: "->" -LEFT_PARENTHESES: "(" -RIGHT_PARENTHESES: ")" -LEFT_BRACKETS: "[" -RIGHT_BRACKETS: "]" -LEFT_BRACE: "{" -RIGHT_BRACE: "}" -PLUS: "+" -MINUS: "-" -MULTIPLY: "*" -DIVIDE: "/" -MOD: "%" -DOT: "." -AND: "&" -OR: "|" -XOR: "^" -NOT: "~" -LESS_THAN: "<" -GREATER_THAN: ">" -EQUAL_TO: "==" -NOT_EQUAL_TO: "!=" -GREATER_THAN_OR_EQUAL_TO: ">=" -LESS_THAN_OR_EQUAL_TO: "<=" -DOUBLE_STAR: "**" -DOUBLE_DIVIDE: "//" -SHIFT_LEFT: "<<" -SHIFT_RIGHT: ">>" -AT: "@" - -COMP_PLUS: "+=" -COMP_MINUS: "-=" -COMP_MULTIPLY: "*=" -COMP_DIVIDE: "/=" -COMP_MOD: "%=" -COMP_AND: "&=" -COMP_OR: "|=" -COMP_XOR: "^=" -COMP_DOUBLE_STAR: "**=" -COMP_DOUBLE_DIVIDE: "//=" -COMP_SHIFT_LEFT: "<<=" -COMP_SHIFT_RIGHT: ">>=" - -// Special tokens -IMPORT: "import" -AS: "as" -RULE: "rule" -SCHEMA: "schema" -MIXIN: "mixin" -PROTOCOL: "protocol" -CHECK: "check" -FOR: "for" -ASSERT: "assert" -IF: "if" -ELIF: "elif" -ELSE: "else" -L_OR: "or" -L_AND: "and" -L_NOT: "not" -IN: "in" -IS: "is" -LAMBDA: "lambda" -ALL: "all" -ANY: "any" -FILTER: "filter" -MAP: "map" -TYPE: "type" - -ANY_TYPE: "any" -STRING_TYPE: "str" -INT_TYPE: "int" -FLOAT_TYPE: "float" -BOOL_TYPE: "bool" - -// Constant tokens -TRUE: "True" -FALSE: "False" -NONE: "None" -UNDEFINED: "Undefined" - -// Binary prefix -SI_N_L: "n" -SI_U_L: "u" -SI_M_L: "m" -SI_K_L: "k" -SI_K: "K" -SI_M: "M" -SI_G: "G" -SI_T: "T" -SI_P: "P" -SI_K_IEC: "Ki" -SI_M_IEC: "Mi" -SI_G_IEC: "Gi" -SI_T_IEC: "Ti" -SI_P_IEC: "Pi" -IEC: "i" - -NAME: /\$?[a-zA-Z_]\w*/ -COMMENT: /#[^\n]*/ -NEWLINE: ( /\r?\n[\t ]*/ | COMMENT )+ - -STRING: /r?("(?!"").*?(? len( - MANGLE_PREFIX - ), "Internal Error: Demangling failure. Please report a bug to us." - demangled_name += name[len(MANGLE_PREFIX) :] - else: - demangled_name = demangle(name[:dot]) + "." + demangle(name[dot + 1 :]) - else: - demangled_name = name - return demangled_name - - -def ismangled(name): - """Check if a name is mangled""" - if name.startswith(MANGLE_PREFIX): - return True - return False - - -def tagging(tag, name=None): - """tagging a name""" - return TAGGING_PREFIX + tag + "_" + name - - -def detagging(tag, name=None): - """Detagging a name if it is tagged""" - if istagged(name): - return name[len(TAGGING_PREFIX) + len(tag) + 1 :] - return name - - -def istagged(name): - """Check if a name is tagged""" - if name.startswith(TAGGING_PREFIX): - return True - return False - - -def isprivate_field(name): - return name.startswith("_") diff --git a/internal/kclvm_py/kcl/types/__init__.py b/internal/kclvm_py/kcl/types/__init__.py deleted file mode 100644 index 162ee042f..000000000 --- a/internal/kclvm_py/kcl/types/__init__.py +++ /dev/null @@ -1,62 +0,0 @@ -# Copyright 2021 The KCL Authors. All rights reserved. - -from .scope import ( - Scope, - ProgramScope, - PackageScope, - BUILTIN_SCOPE, - PLUGIN_SCOPE_MAPPING, -) -from .checker import ResolveProgram, CheckConfig -from .type import ( - Type, - VOID_TYPE, - NONE_TYPE, - INT_TYPE, - FLOAT_TYPE, - STR_TYPE, - BOOL_TYPE, - ANY_TYPE, - TRUE_LIT_TYPE, - FALSE_LIT_TYPE, - DICT_STR_ANY_TYPE, - DICT_STR_STR_TYPE, - DICT_ANY_ANY_TYPE, - INT_OR_STR_TYPE, - sup, - assignable_to, - is_upper_bound, - type_to_kcl_type_annotation_str, -) -from .type_parser import parse_type_str -from .type_convension import type_convert - -__all__ = [ - "Scope", - "ProgramScope", - "PackageScope", - "BUILTIN_SCOPE", - "PLUGIN_SCOPE_MAPPING", - "ResolveProgram", - "CheckConfig", - "Type", - "VOID_TYPE", - "NONE_TYPE", - "INT_TYPE", - "FLOAT_TYPE", - "STR_TYPE", - "BOOL_TYPE", - "ANY_TYPE", - "TRUE_LIT_TYPE", - "FALSE_LIT_TYPE", - "DICT_STR_ANY_TYPE", - "DICT_STR_STR_TYPE", - "DICT_ANY_ANY_TYPE", - "INT_OR_STR_TYPE", - "sup", - "assignable_to", - "is_upper_bound", - "type_to_kcl_type_annotation_str", - "parse_type_str", - "type_convert", -] diff --git a/internal/kclvm_py/kcl/types/calculation.py b/internal/kclvm_py/kcl/types/calculation.py deleted file mode 100644 index 3330c1ffb..000000000 --- a/internal/kclvm_py/kcl/types/calculation.py +++ /dev/null @@ -1,344 +0,0 @@ -# Copyright 2020 The KCL Authors. All rights reserved. - -from typing import Union, List, Optional - -import kclvm.kcl.error as kcl_error -import kclvm.kcl.ast as ast -import kclvm.api.object as objpkg - -from .type import ( - Type, - ANY_TYPE, - INT_TYPE, - FLOAT_TYPE, - STR_TYPE, - BOOL_TYPE, - FALSE_LIT_TYPE, - NONE_TYPE, - NUMBER_TYPE_KINDS, - ITERABLE_KINDS, - STR_KINDS, - INT_KINDS, - BOOL_KINDS, - BUILTIN_KINDS, - sup, - has_any_type, - is_upper_bound, - infer_to_variable_type, - literal_union_type_to_variable_type, - is_kind_type_or_kind_union_type, -) - - -ZERO_LIT_TYPES: List[Type] = [ - objpkg.KCLIntLitTypeObject(0), - objpkg.KCLFloatLitTypeObject(0.0), - FALSE_LIT_TYPE, -] - - -def binary( - t1: Type, - t2: Type, - op: Union[ast.BinOp, ast.AugOp], - filename: Optional[str] = None, - line: Optional[int] = None, - column: Optional[int] = None, -) -> Type: - """Binary operator calculation table. - - Arithmetic (int or float; result has type float unless both operands have type int) - number + number # addition - number - number # subtraction - number * number # multiplication - number / number # real division (result is always a float) - number // number # floored division - number % number # remainder of floored division - number ^ number # bitwise XOR - number << number # bitwise left shift - number >> number # bitwise right shift - - Concatenation - string + string - list + list - - Repetition (string/list) - int * sequence - sequence * int - - Union - int | int - list | list - dict | dict - schema | schema - schema | dict - - Add: number + number, str + str, list + list - Sub: number - number - Mul: number * number, number * list, list * number - Div: number / number - FloorDiv: number // number - Mod: number % number - Pow: number ** number - LShift: int >> int - RShift: int << int - BitOr: int | int, list | list, dict | dict, schema | schema, schema | dict - BitXOr: int ^ int - BitAdd int & int - - And: any_type and any_type -> bool - Or: any_type1 or any_type1 -> sup([any_type1, any_type2]) - """ - - def number_binary() -> Type: - return ( - FLOAT_TYPE - if ( - t1.type_kind() - in [objpkg.KCLTypeKind.FloatKind, objpkg.KCLTypeKind.FloatLitKind] - or t2.type_kind() - in [objpkg.KCLTypeKind.FloatKind, objpkg.KCLTypeKind.FloatLitKind] - ) - else INT_TYPE - ) - - if has_any_type([t1, t2]): - return ANY_TYPE - - t1 = literal_union_type_to_variable_type(t1) - t2 = literal_union_type_to_variable_type(t2) - - if op == ast.BinOp.Add or op == ast.AugOp.Add: - if t1.type_kind() in NUMBER_TYPE_KINDS and t2.type_kind() in NUMBER_TYPE_KINDS: - return number_binary() - if t1.type_kind() in STR_KINDS and t2.type_kind() in STR_KINDS: - return STR_TYPE - if isinstance(t1, objpkg.KCLListTypeObject) and isinstance( - t2, objpkg.KCLListTypeObject - ): - return objpkg.KCLListTypeObject(item_type=sup([t1.item_type, t2.item_type])) - elif op == ast.BinOp.Mul or op == ast.AugOp.Mul: - if t1.type_kind() in NUMBER_TYPE_KINDS and t2.type_kind() in NUMBER_TYPE_KINDS: - return number_binary() - if t1.type_kind() in INT_KINDS and ( - is_kind_type_or_kind_union_type( - t2, STR_KINDS + NUMBER_TYPE_KINDS + [objpkg.KCLTypeKind.ListKind] - ) - ): - return t2 - if ( - is_kind_type_or_kind_union_type( - t1, STR_KINDS + NUMBER_TYPE_KINDS + [objpkg.KCLTypeKind.ListKind] - ) - ) and t2.type_kind() in INT_KINDS: - return t1 - elif op == ast.BinOp.Sub or op == ast.AugOp.Sub: - if t1.type_kind() in NUMBER_TYPE_KINDS and t2.type_kind() in NUMBER_TYPE_KINDS: - return number_binary() - elif op == ast.BinOp.Div or op == ast.AugOp.Div: - if t1.type_kind() in NUMBER_TYPE_KINDS and t2.type_kind() in NUMBER_TYPE_KINDS: - if t2 in ZERO_LIT_TYPES: - kcl_error.report_exception( - err_type=kcl_error.ErrType.CompileError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=filename, line_no=line, col_no=column - ) - ], - arg_msg="integer division or modulo by zero", - ) - return number_binary() - elif op == ast.BinOp.Mod or op == ast.AugOp.Mod: - if t1.type_kind() in NUMBER_TYPE_KINDS and t2.type_kind() in NUMBER_TYPE_KINDS: - if t2 in ZERO_LIT_TYPES: - kcl_error.report_exception( - err_type=kcl_error.ErrType.CompileError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=filename, line_no=line, col_no=column - ) - ], - arg_msg="integer division or modulo by zero", - ) - return INT_TYPE - elif op == ast.BinOp.FloorDiv or op == ast.AugOp.FloorDiv: - if t1.type_kind() in NUMBER_TYPE_KINDS and t2.type_kind() in NUMBER_TYPE_KINDS: - if t2 in ZERO_LIT_TYPES: - kcl_error.report_exception( - err_type=kcl_error.ErrType.CompileError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=filename, line_no=line, col_no=column - ) - ], - arg_msg="integer division or modulo by zero", - ) - return number_binary() - elif op == ast.BinOp.Pow or op == ast.AugOp.Pow: - if t1.type_kind() in NUMBER_TYPE_KINDS and t2.type_kind() in NUMBER_TYPE_KINDS: - return number_binary() - elif op == ast.BinOp.BitOr or op == ast.AugOp.BitOr: - if t1.type_kind() in INT_KINDS and t2.type_kind() in INT_KINDS: - return INT_TYPE - if t2 == NONE_TYPE: - return t1 - if t1 == NONE_TYPE: - return t2 - if isinstance(t1, objpkg.KCLListTypeObject) and isinstance( - t2, objpkg.KCLListTypeObject - ): - return objpkg.KCLListTypeObject(item_type=sup([t1.item_type, t2.item_type])) - if isinstance(t1, objpkg.KCLDictTypeObject) and isinstance( - t2, objpkg.KCLDictTypeObject - ): - return objpkg.KCLDictTypeObject( - key_type=sup([t1.key_type, t2.key_type]), - value_type=sup([t1.value_type, t2.value_type]), - ) - if isinstance(t1, objpkg.KCLSchemaTypeObject) and isinstance( - t2, (objpkg.KCLSchemaTypeObject, objpkg.KCLDictTypeObject) - ): - return t1 - elif op == ast.BinOp.LShift or op == ast.AugOp.LShift: - if t1.type_kind() in INT_KINDS and t2.type_kind() in INT_KINDS: - return INT_TYPE - elif op == ast.BinOp.RShift or op == ast.AugOp.RShift: - if t1.type_kind() in INT_KINDS and t2.type_kind() in INT_KINDS: - return INT_TYPE - elif op == ast.BinOp.BitXor or op == ast.AugOp.BitXor: - if t1.type_kind() in INT_KINDS and t2.type_kind() in INT_KINDS: - return INT_TYPE - elif op == ast.BinOp.BitAnd or op == ast.AugOp.BitAnd: - if t1.type_kind() in INT_KINDS and t2.type_kind() in INT_KINDS: - return INT_TYPE - elif op == ast.BinOp.And: - return BOOL_TYPE - elif op == ast.BinOp.Or: - return sup([t1, t2]) - elif op == ast.BinOp.As: - if not is_upper_bound(infer_to_variable_type(t1), t2): - kcl_error.report_exception( - err_type=kcl_error.ErrType.CompileError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg(filename=filename, line_no=line, col_no=column) - ], - arg_msg=f"Conversion of type '{t1.type_str()}' to type '{t2.type_str()}' " - "may be a mistake because neither type sufficiently overlaps with the other", - ) - return t2.schema_type if isinstance(t2, objpkg.KCLSchemaDefTypeObject) else t2 - kcl_error.report_exception( - err_type=kcl_error.ErrType.CompileError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg(filename=filename, line_no=line, col_no=column) - ], - arg_msg=f"unsupported operand type(s) for {ast.OPERATOR_VALUE_MAP.get(op)}: '{t1.type_str()}' and '{t2.type_str()}'", - ) - - -def compare( - t1: Type, - t2: Type, - op: ast.CmpOp, - filename: Optional[str] = None, - line: Optional[int] = None, - column: Optional[int] = None, -) -> Type: - """Compare operator calculation table - - bool # False < True False < True - int # mathematical 1 < 2 - float # as defined by IEEE 754 1.0 < 2.0 - string # lexicographical "1" < 2 - list # lexicographical [1] == [2] - iterable # 1 in [1, 2, 3], "s" in "ss", "key" in Schema - """ - - t1 = literal_union_type_to_variable_type(t1) - t2 = literal_union_type_to_variable_type(t2) - - if has_any_type([t1, t2]): - return ANY_TYPE - if ( - is_kind_type_or_kind_union_type(t1, NUMBER_TYPE_KINDS) - and is_kind_type_or_kind_union_type(t2, NUMBER_TYPE_KINDS) - and op not in [ast.CmpOp.In, ast.CmpOp.NotIn] - ): - return BOOL_TYPE - if ( - is_kind_type_or_kind_union_type(t1, STR_KINDS) - and is_kind_type_or_kind_union_type(t2, STR_KINDS) - and op not in [ast.CmpOp.Eq, ast.CmpOp.NotEq] - ): - return BOOL_TYPE - if ( - is_kind_type_or_kind_union_type(t1, BUILTIN_KINDS) - and is_kind_type_or_kind_union_type(t2, BUILTIN_KINDS) - and op in [ast.CmpOp.Eq, ast.CmpOp.NotEq] - ): - return BOOL_TYPE - if isinstance(t1, objpkg.KCLListTypeObject) and isinstance( - t2, objpkg.KCLListTypeObject - ): - return BOOL_TYPE - if ( - isinstance(t1, (objpkg.KCLDictTypeObject, objpkg.KCLSchemaTypeObject)) - and isinstance(t2, (objpkg.KCLDictTypeObject, objpkg.KCLSchemaTypeObject)) - and op in [ast.CmpOp.Eq, ast.CmpOp.NotEq] - ): - return BOOL_TYPE - if op in [ast.CmpOp.In, ast.CmpOp.NotIn] and t2.type_kind() in ITERABLE_KINDS: - return BOOL_TYPE - if (t1 == NONE_TYPE or t2 == NONE_TYPE) and op in [ - ast.CmpOp.Eq, - ast.CmpOp.NotEq, - ast.CmpOp.Is, - ast.CmpOp.IsNot, - ast.CmpOp.Not, - ]: - return BOOL_TYPE - kcl_error.report_exception( - err_type=kcl_error.ErrType.CompileError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg(filename=filename, line_no=line, col_no=column) - ], - arg_msg=f"unsupported operand type(s) for {ast.OPERATOR_VALUE_MAP.get(op)}: '{t1.type_str()}' and '{t2.type_str()}'", - ) - - -def unary( - t: Type, - op: ast.UnaryOp, - filename: Optional[str] = None, - line: Optional[int] = None, - column: Optional[int] = None, -) -> Type: - """Unary operator calculation table - - + number unary positive (int, float) - - number unary negation (int, float) - ~ number unary bitwise inversion (int) - not x logical negation (any type) - """ - if has_any_type([t]): - return ANY_TYPE - - t = literal_union_type_to_variable_type(t) - - if op == ast.UnaryOp.UAdd: - if t.type_kind() in NUMBER_TYPE_KINDS: - return t - if op == ast.UnaryOp.USub: - if t.type_kind() in NUMBER_TYPE_KINDS: - return t - if op == ast.UnaryOp.Invert: - if t.type_kind() in (INT_KINDS + BOOL_KINDS): - return INT_TYPE - if op == ast.UnaryOp.Not: - return BOOL_TYPE - kcl_error.report_exception( - err_type=kcl_error.ErrType.CompileError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg(filename=filename, line_no=line, col_no=column) - ], - arg_msg=f"bad operand type for unary {ast.OPERATOR_VALUE_MAP.get(op)}: '{t.type_str()}'", - ) diff --git a/internal/kclvm_py/kcl/types/checker.py b/internal/kclvm_py/kcl/types/checker.py deleted file mode 100644 index 357ee5738..000000000 --- a/internal/kclvm_py/kcl/types/checker.py +++ /dev/null @@ -1,2618 +0,0 @@ -"""The `checker` file mainly contains the function `ResolveProgram` -based on the AST walker, which is used to run semantic checking and -type checking of KCL. - -:copyright: Copyright 2020 The KCL Authors. All rights reserved. -""" - -import os -import pathlib -import typing -from enum import IntEnum -from typing import cast, Union, List, Dict, Tuple, Optional -from dataclasses import dataclass - -import kclvm.api.object as objpkg -import kclvm.api.object.internal as internal -import kclvm.kcl.error as kcl_error -import kclvm.kcl.info as kcl_info -import kclvm.kcl.ast as ast -import kclvm.compiler.astutil as astutil -import kclvm.compiler.extension.builtin as builtin -import kclvm.compiler.extension.plugin as plugin - -from kclvm.compiler.build.utils import units -from kclvm.kcl.types.scope import ( - Scope, - PackageScope, - ScopeObject, - ProgramScope, - BUILTIN_SCOPE, - DECORATOR_SCOPE, - PLUGIN_SCOPE_MAPPING, - MODULE_SCOPE_MAPPING, - SCHEMA_TYPE_MEMBER_SCOPE, - STR_TYPE_MEMBER_SCOPE, -) -from kclvm.kcl.types.type import ( - Type, - ANY_TYPE, - VOID_TYPE, - NONE_TYPE, - STR_TYPE, - BOOL_TYPE, - INT_TYPE, - TRUE_LIT_TYPE, - FALSE_LIT_TYPE, - DICT_STR_ANY_TYPE, - RESERVED_TYPE_IDENTIFIERS, - KEY_KINDS, - sup, - assignable_to, - is_upper_bound, - infer_to_variable_type, - is_kind_type_or_kind_union_type, - type_to_kcl_type_annotation_str, -) -from kclvm.kcl.types.type_parser import parse_type_str -from kclvm.kcl.types.calculation import binary, compare, unary -from kclvm.kcl.types.walker import WalkType -from kclvm.internal.util import check_utils - -ITER_TYPES = ( - objpkg.KCLAnyTypeObject, - objpkg.KCLListTypeObject, - objpkg.KCLStringTypeObject, - objpkg.KCLStringLitTypeObject, - objpkg.KCLDictTypeObject, - objpkg.KCLSchemaTypeObject, -) -MAX_SCOPE_SCAN_COUNT = 3 -VALID_FORMAT_SPEC_SET = {"#json", "#yaml"} -TYPE_KIND_BUILTIN_FUNCTION_MAPPING = { - objpkg.KCLTypeKind.BoolKind: "bool", - objpkg.KCLTypeKind.IntKind: "int", - objpkg.KCLTypeKind.FloatKind: "float", - objpkg.KCLTypeKind.StrKind: "str", - objpkg.KCLTypeKind.ListKind: "list", - objpkg.KCLTypeKind.DictKind: "dict", -} - - -class SwitchConfigExprContextState(IntEnum): - SWITCH_CONFIG_EXPR_ONCE = 1 - KEEP_CONFIG_EXPR_UNCHANGED = 0 - - -@dataclass -class CheckConfig: - raise_err: bool = True - config_attr_auto_fix: bool = False - - -class BaseTypeChecker(ast.TreeWalker): - def __init__(self, program: ast.Program, config: CheckConfig = CheckConfig()): - # The type checker config - self.config: CheckConfig = config - # The AST program reference - self.program: ast.Program = program - # Current package path, default is the main package path - self.pkgpath = ast.Program.MAIN_PKGPATH - # Current filename - self.filename = "" - # The scope mapping between `pkgpath` and `scope` - self.scope_map: Dict[str, Scope] = {} - # Current scope - self.scope: Optional[Scope] = None - # Current schema type - self.in_schema_type: Optional[Type] = None - # Current schema expr type stack - self.config_expr_context: List[Optional[ScopeObject]] = [] - # Check error list - self.errs: List[kcl_error.KCLException] = [] - # Local vars - self._local_vars: List[str] = [] - # Schema type reference graph - self.schema_reference: objpkg.SchemaTypeRefGraph = objpkg.SchemaTypeRefGraph() - # Schema types mapping - self.schema_mapping: Dict[str, Type] = {} - # Package path import reference graph - self.import_reference: objpkg.RefGraph = objpkg.RefGraph() - # In lambda expression level - self._is_in_lambda_expr: List[bool] = [False] - # Reset scope status - self.reset_scopes() - # Set __main_ package context - self.change_package_context(self.pkgpath, self.filename) - - @staticmethod - def reset_scopes(): - BUILTIN_SCOPE.children = [] - - def new_config_expr_context_item( - self, - name: str = None, - type_obj: Optional[Type] = None, - node: Optional[ast.AST] = None, - ) -> ScopeObject: - return ScopeObject( - name=name, - node=node, - type=type_obj, - pos=ast.Position(filename=node.filename, line=node.line, column=node.column) - if node - else None, - end=ast.Position( - filename=node.filename, line=node.end_line, column=node.end_column - ) - if node - else None, - ) - - def find_schema_attr_obj_from_schema_expr_stack( - self, key_name: str - ) -> Optional[ScopeObject]: - """Finds the items needed to switch the context by name 'key_name' - - At present, only when the top item of the stack is 'KCLSchemaTypeObject' or 'KCLDictTypeObject', - it will return the next item (the attribute named 'key_name' in 'KCLSchemaTypeObject' - or the value of 'key_name' in 'KCLDictTypeObject') needed to be pushed. - If the top item of the stack is not 'KCLSchemaTypeObject' or 'KCLDictTypeObject', - it will return 'None'. - - Args: - key_name: The name of the item needed to be pushed onto the 'config_expr_context' stack - - Returns: - The item needed to be pushed onto the 'config_expr_context' stack - - """ - if ( - not key_name - or not self.config_expr_context - or not self.config_expr_context[-1] - ): - return None - if not isinstance(self.config_expr_context[-1], ScopeObject): - check_utils.alert_internal_bug() - - if isinstance(self.config_expr_context[-1].type, objpkg.KCLSchemaTypeObject): - schema_type = typing.cast( - objpkg.KCLSchemaTypeObject, self.config_expr_context[-1].type - ) - attr_type_obj = schema_type.get_obj_of_attr(key_name) - if not attr_type_obj and schema_type.index_signature: - ctx_obj = self.new_config_expr_context_item( - name=key_name, - type_obj=schema_type.index_signature.value_kcl_type, - node=schema_type.index_signature.node, - ) - elif attr_type_obj: - ctx_obj = self.new_config_expr_context_item( - name=key_name, - type_obj=attr_type_obj.attr_type, - node=attr_type_obj.attr_node, - ) - else: - return None - return ctx_obj - if isinstance(self.config_expr_context[-1].type, objpkg.KCLDictTypeObject): - dict_type = typing.cast( - objpkg.KCLDictTypeObject, self.config_expr_context[-1].type - ) - ctx_obj = self.new_config_expr_context_item( - name=key_name, - type_obj=dict_type.value_type, - node=self.config_expr_context[-1].node, - ) - return ctx_obj - return None - - def switch_config_expr_context_by_key(self, key: ast.Expr) -> int: - """Switch the context in 'config_expr_context' stack by AST nodes 'Identifier', 'Subscript' or 'Literal' - - Args: - key: AST nodes 'Identifier', 'Subscript' or 'Literal' - - Returns: - push stack times - - """ - names = [] - if not key: - return SwitchConfigExprContextState.KEEP_CONFIG_EXPR_UNCHANGED - if isinstance(key, ast.Identifier): - names = key.names - elif isinstance(key, ast.Subscript): - if isinstance(key.value, ast.Identifier) and isinstance( - key.index, ast.NumberLit - ): - names = key.value.names - elif isinstance(key, ast.Literal): - names = [key.value] - else: - return SwitchConfigExprContextState.KEEP_CONFIG_EXPR_UNCHANGED - return self.switch_config_expr_context_by_names(names) - - def switch_config_expr_context_by_names( - self, names: List[Union[str, float, int]] - ) -> int: - """Switch the context in 'config_expr_context' stack by names - - Traverse all name in 'names', find the next item that needs to be pushed into the stack, - according to name and the top context of the stack, and push the item into the stack. - - Args: - names: A list of string containing the names of items to be pushed - - Returns: - push stack times - - """ - stack_depth = 0 - for name in names: - stack_depth += self.switch_config_expr_context_by_name(name) - return stack_depth - - def switch_config_expr_context_by_name(self, name: str) -> int: - """Switch the context in 'config_expr_context' stack by name - - find the next item that needs to be pushed into the stack, - according to name and the top context of the stack, and push the item into the stack. - - Args: - name: the name of item to be pushed - - Returns: - push stack times - - """ - ctx_obj = self.find_schema_attr_obj_from_schema_expr_stack(name) - return self.switch_config_expr_context(ctx_obj) - - def switch_config_expr_context( - self, config_ctx_obj: ScopeObject - ) -> SwitchConfigExprContextState: - """Push method for the 'config_expr_context' stack - - Args: - config_ctx_obj: the item needed to be pushed - - Returns: - push stack times - - """ - self.config_expr_context.append(config_ctx_obj) - return SwitchConfigExprContextState.SWITCH_CONFIG_EXPR_ONCE - - def restore_config_expr_context(self) -> Optional[objpkg.KCLSchemaTypeObject]: - """Pop method for the 'config_expr_context' stack - - Returns: - the item poped from stack - - """ - return self.config_expr_context.pop(-1) if self.config_expr_context else None - - def clear_config_expr_context(self, stack_depth: int = 0, clear_all: bool = False): - """Pop_All method for the 'config_expr_context' stack - - Args: - stack_depth: 'stack_depth' is the number of stacks that need to be popped - clear_all: 'clear_all' is True to clear all the items of the stack - - """ - if clear_all: - self.config_expr_context.clear() - else: - while stack_depth > 0: - stack_depth -= 1 - self.restore_config_expr_context() - - def check_config_expr_by_key_name( - self, name: str, key: ast.AST, check_rules: List[typing.Callable] - ): - """Check whether the key of config expr meets the constraints of schema attributes such as final, defined. - - Args: - name: the name of key - key: the ast node of key - check_rules: the constraints, such as 'check_defined' - - """ - if name and self.config_expr_context and self.config_expr_context[-1]: - self.check_attr( - attr=name, - node=key, - obj=self.config_expr_context[-1].type, - check_rules=check_rules, - ) - - def check_config_entry( - self, key: ast.Expr, value: ast.Expr, check_rules: List[typing.Callable] - ) -> typing.Optional[ast.Expr]: - """Check the key-value in 'ConfigExpr', such as check_defined and check_type - - Notes: - If the top item of the 'config_expr_context' stack is 'None', the check will be skipped. - - Args: - key: the key of 'ConfigExpr'. - value: the value of 'ConfigExpr'. - check_rules: Some checks on the key individually,such as check_defined. - - """ - if not (key and self.config_expr_context and self.config_expr_context[-1]): - return - names: List[Union[str, float, int]] = [] - has_index = False - - def _check() -> typing.Optional[ast.Expr]: - stack_depth = 0 - fix_call_expr = None - for name in names: - self.check_config_expr_by_key_name(name, key, check_rules) - stack_depth += self.switch_config_expr_context_by_name(name) - value_tpe = self.expr(value) - if len(names) > 1: - for _ in range(len(names) - 1): - value_tpe = objpkg.KCLDictTypeObject( - key_type=STR_TYPE, value_type=value_tpe - ) - if has_index: - value_tpe = ( - objpkg.KCLListTypeObject(value_tpe) - if value_tpe and isinstance(value_tpe, objpkg.KCLBaseTypeObject) - else None - ) - if self.config.config_attr_auto_fix: - try: - _check_type(value_tpe) - # Type check error and fix the attr type with the builtin functions - except Exception: - expected_attr_type = self.config_expr_context[-1].type.type_kind() - if expected_attr_type in TYPE_KIND_BUILTIN_FUNCTION_MAPPING: - func_name = TYPE_KIND_BUILTIN_FUNCTION_MAPPING[ - expected_attr_type - ] - fix_call_expr = ast.CallExpr(line=key.line, column=key.column) - fix_call_expr.func = ast.ASTFactory.get_ast_identifier( - func_name - ) - fix_call_expr.args = [value] - else: - _check_type(value_tpe) - self.clear_config_expr_context(stack_depth=stack_depth) - return fix_call_expr - - def _check_type(value_tpe: Type): - if value_tpe and self.config_expr_context and self.config_expr_context[-1]: - self.must_assignable_to( - node=key, - tpe=value_tpe or ANY_TYPE, - expected_type=self.config_expr_context[-1].type, - expected_node=self.config_expr_context[-1].node, - ) - - if isinstance(key, ast.Identifier): - names = key.names - elif isinstance(key, ast.Subscript): - if isinstance(key.value, ast.Identifier) and isinstance( - key.index, ast.NumberLit - ): - names = key.value.names - has_index = True - else: - return - elif isinstance(key, ast.Literal): - names = [key.value] - else: - return - return _check() - - def get_node_name(self, t: ast.AST): - """Get the ast.AST node name""" - assert isinstance(t, ast.AST), str(type(t)) - return t.type - - def generic_walk(self, t: ast.AST): - """Called if no explicit walker function exists for a node.""" - raise Exception( - f"The function walk_{t.type} is not defined in the type checker." - ) - - def raise_err( - self, - nodes: [ast.AST], - category: kcl_error.ErrType = kcl_error.ErrType.CompileError_TYPE, - msg: str = "", - file_msgs=None, - file_levels=None, - ): - """Raise a KCL compile error""" - err = kcl_error.get_exception( - err_type=category, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=node.filename, - line_no=node.line, - col_no=node.column, - arg_msg=(file_msgs[i] if i < len(file_msgs) else file_msgs[-1]) - if file_msgs - else None, - err_level=( - file_levels[i] if i < len(file_levels) else file_levels[-1] - ) - if file_levels - else None, - ) - for i, node in enumerate(nodes) - if node - ], - arg_msg=msg, - ) - if self.config.raise_err: - raise err - self.errs.append(err) - - def change_package_context(self, pkgpath: str, filename: str): - """Change the package scope context with pkgpath and filename""" - if not pkgpath: - return - if pkgpath not in self.scope_map: - self.scope_map[pkgpath] = PackageScope( - parent=BUILTIN_SCOPE, - file_begin_position_map={ - module.filename: ast.Position( - filename=module.filename, - line=module.line, - column=module.column, - ) - for module in self.program.pkgs[pkgpath] - }, - file_end_position_map={ - module.filename: ast.Position( - filename=module.filename, - line=module.end_line, - column=module.end_column, - ) - for module in self.program.pkgs[pkgpath] - }, - ) - BUILTIN_SCOPE.children.append(self.scope_map[pkgpath]) - self.pkgpath = pkgpath - self.filename = filename - self.scope = self.scope_map[pkgpath] - - def check(self, pkgpath: str = ast.Program.MAIN_PKGPATH) -> ProgramScope: - """The check main function""" - self.check_import(pkgpath) - self.init_global_types() - for module in self.program.pkgs[pkgpath]: - self.filename = module.filename - self.walk(module) - self.scope_map[pkgpath] = self.scope - return ProgramScope( - scope_map=self.scope_map, - schema_reference=self.schema_reference, - ) - - def check_import(self, pkgpath: str = ast.Program.MAIN_PKGPATH): - """The import check function""" - self.pkgpath = pkgpath - self.change_package_context(pkgpath, self.filename) - self.init_import_list() - - def build_rule_protocol_type( - self, t: ast.RuleStmt - ) -> Optional[objpkg.KCLSchemaDefTypeObject]: - if t.for_host_name and isinstance(t.for_host_name, ast.Identifier): - if len(t.for_host_name.names) > 2: - self.raise_err( - category=kcl_error.ErrType.MultiInheritError_TYPE, - nodes=[t.for_host_name], - msg=kcl_error.MULTI_INHERIT_MSG.format(t.name), - ) - return None - tpe = self.expr(t.for_host_name) - if not isinstance(tpe, objpkg.KCLSchemaDefTypeObject): - self.raise_err( - category=kcl_error.ErrType.IllegalInheritError_TYPE, - nodes=[t], - msg=f"invalid schema inherit object type '{tpe.type_str()}'", - ) - return None - return cast(objpkg.KCLSchemaDefTypeObject, tpe) - return None - - def build_schema_protocol_type( - self, t: ast.SchemaStmt - ) -> Optional[objpkg.KCLSchemaDefTypeObject]: - # Mixin type check with protocol - if not t.is_mixin and t.for_host_name: - self.raise_err( - category=kcl_error.ErrType.IllegalInheritError_TYPE, - nodes=[t.for_host_name], - msg="only schema mixin can inherit from protocol", - ) - return None - if t.is_mixin and t.for_host_name: - if len(t.for_host_name.names) > 2: - self.raise_err( - category=kcl_error.ErrType.MultiInheritError_TYPE, - nodes=[t.for_host_name], - msg=kcl_error.MULTI_INHERIT_MSG.format(t.name), - ) - return None - tpe = self.expr(t.for_host_name) - if not isinstance(tpe, objpkg.KCLSchemaDefTypeObject): - self.raise_err( - category=kcl_error.ErrType.IllegalInheritError_TYPE, - nodes=[t], - msg=f"invalid schema inherit object type '{tpe.type_str()}'", - ) - return None - return cast(objpkg.KCLSchemaDefTypeObject, tpe) - return None - - def build_schema_parent_type( - self, t: ast.SchemaStmt - ) -> Optional[objpkg.KCLSchemaDefTypeObject]: - if t.parent_name: - if len(t.parent_name.names) > 2: - self.raise_err( - category=kcl_error.ErrType.MultiInheritError_TYPE, - nodes=[t.parent_name], - msg=kcl_error.MULTI_INHERIT_MSG.format(t.name), - ) - return None - schema_parent_type = self.expr(t.parent_name) - if not isinstance(schema_parent_type, objpkg.KCLSchemaDefTypeObject): - self.raise_err( - category=kcl_error.ErrType.IllegalInheritError_TYPE, - nodes=[t], - msg=f"illegal schema inherit object type '{schema_parent_type.type_str()}'", - ) - return None - return schema_parent_type - return None - - def build_schema_type( - self, - t: ast.SchemaStmt, - base_def: objpkg.KCLSchemaDefTypeObject = None, - protocol_def: objpkg.KCLSchemaDefTypeObject = None, - should_add_schema_ref: bool = False, - ) -> objpkg.KCLSchemaDefTypeObject: - """Build a schema type and check""" - # Base schema: get the parent type obj of the schema if exist - if t.name in RESERVED_TYPE_IDENTIFIERS: - self.raise_err( - [t], - kcl_error.ErrType.IllegalInheritError_TYPE, - "schema name '{}' cannot be the same as the built-in types ({})".format( - t.name, ", ".join(RESERVED_TYPE_IDENTIFIERS) - ), - ) - if t.is_protocol and not t.has_only_attribute_definitions(): - self.raise_err( - [t], - kcl_error.ErrType.CompileError_TYPE, - msg="a protocol is only allowed to define attributes in it", - ) - base = base_def.schema_type if base_def else None - protocol = protocol_def.schema_type if protocol_def else None - parent_name_str = t.parent_name.get_name() if t.parent_name else "" - if parent_name_str.endswith("Mixin"): - self.raise_err( - [t], - kcl_error.ErrType.IllegalInheritError_TYPE, - f"mixin inheritance {parent_name_str} is prohibited", - ) - schema_attr_names = t.GetLeftIdentifierList() - # Index signature - index_sign_name = t.GetIndexSignatureAttrName() - index_sign_obj = None - if index_sign_name and index_sign_name in schema_attr_names: - self.raise_err( - nodes=[t.index_signature], - category=kcl_error.ErrType.IndexSignatureError_TYPE, - msg=f"index signature attribute name '{index_sign_name}' " - "cannot have the same name as schema attributes", - ) - if t.index_signature: - key_kcl_type = self.parse_type_str_with_scope( - t.index_signature.key_type, t.index_signature - ) - if not is_kind_type_or_kind_union_type(key_kcl_type, KEY_KINDS): - self.raise_err( - nodes=[t.index_signature], - category=kcl_error.ErrType.IndexSignatureError_TYPE, - msg=f"invalid index signature key type: '{key_kcl_type.type_str()}'", - ) - value_kcl_type = self.parse_type_str_with_scope( - t.index_signature.value_type, t.index_signature - ) - index_sign_obj = objpkg.KCLSchemaIndexSignatureObject( - key_name=t.index_signature.key_name, - key_type=t.index_signature.key_type, - value_type=t.index_signature.value_type, - any_other=t.index_signature.any_other, - key_kcl_type=key_kcl_type, - value_kcl_type=value_kcl_type, - node=t.index_signature, - ) - t.index_signature.key_type = type_to_kcl_type_annotation_str(key_kcl_type) - t.index_signature.value_type = type_to_kcl_type_annotation_str( - value_kcl_type - ) - - # Schema attr type map - attr_obj_map = { - objpkg.SCHEMA_SETTINGS_ATTR_NAME: objpkg.KCLSchemaAttrObject( - attr_type=DICT_STR_ANY_TYPE - ) - } - for attr in t.GetAttrList(): - name = ( - attr.name - if isinstance(attr, ast.SchemaAttr) - else attr.target.get_first_name() - ) - if isinstance(attr, ast.SchemaAttr): - tpe = self.parse_type_str_with_scope(attr.type_str, attr) - attr.type_str = type_to_kcl_type_annotation_str(tpe) - else: - tpe = self.parse_type_str_with_scope( - attr.value.name.get_first_name(), attr - ) - attr.value.name.names = [type_to_kcl_type_annotation_str(tpe)] - base_tpe = (base.get_type_of_attr(name) if base else None) or ANY_TYPE - if name not in attr_obj_map: - existed_attr = base.get_obj_of_attr(name) if base else None - attr_obj_map[name] = objpkg.KCLSchemaAttrObject( - is_optional=existed_attr.is_optional - if existed_attr - else isinstance(attr, ast.SchemaAttr) and attr.is_optional, - is_final=False, - has_default=( - (isinstance(attr, ast.SchemaAttr) and attr.value is not None) - or (existed_attr and existed_attr.has_default) - ), - attr_type=tpe, - attr_node=attr, - ) - if not is_upper_bound( - attr_obj_map[name].attr_type, tpe - ) or not is_upper_bound(base_tpe, tpe): - self.raise_err( - [attr], - kcl_error.ErrType.TypeError_Compile_TYPE, - f"can't change schema field type of '{name}'", - ) - if ( - isinstance(attr, ast.SchemaAttr) - and attr.is_optional - and not attr_obj_map[name].is_optional - ): - self.raise_err( - [attr], - msg=f"can't change the required schema attribute of '{name}' to optional", - ) - if ( - index_sign_obj - and not index_sign_obj.any_other - and not is_upper_bound(index_sign_obj.value_kcl_type, tpe) - ): - self.raise_err( - nodes=[attr], - category=kcl_error.ErrType.IndexSignatureError_TYPE, - msg=f"the type '{tpe.type_str()}' of schema attribute '{name}' " - f"does not meet the index signature definition {index_sign_obj.def_str()}", - ) - - mixin_name_list = [] - for mixin in t.mixins or []: - mixin_names = mixin.names - if mixin.pkgpath: - mixin_names[0] = f"@{mixin.pkgpath}" - if not mixin_names[-1].endswith("Mixin"): - self.raise_err( - [mixin], - kcl_error.ErrType.MixinNamingError_TYPE, - f"a valid mixin name should end with 'Mixin', got '{mixin_names[-1]}'", - ) - mixin_name_list.append(mixin.get_name()) - mixin_type = self.expr(mixin) - if mixin_type == ANY_TYPE: - continue - if not isinstance(mixin_type, objpkg.KCLSchemaDefTypeObject): - self.raise_err( - [mixin], - kcl_error.ErrType.CompileError_TYPE, - msg=f"illegal schema mixin object type '{mixin_type.type_str()}'", - ) - else: - for name, attr_obj in mixin_type.schema_type.attr_obj_map.items(): - if name not in attr_obj_map: - attr_obj_map[name] = attr_obj - - params: List[objpkg.Parameter] = [] - # Schema arguments - if t.args: - for i, arg in enumerate(t.args.args): - name = arg.get_name() - if name in schema_attr_names: - self.raise_err( - [arg], - msg=f"Unexpected parameter name '{name}' " - "with the same name as the schema attribute", - ) - type_annotation = t.args.GetArgType(i) - type_node = self.parse_type_str_with_scope( - type_annotation, t.args.args[i] - ) - default = t.args.GetArgDefault(i) - params.append( - objpkg.Parameter( - name=name, - value=objpkg.to_kcl_obj(default), - type_annotation=type_annotation, - type=type_node, - ) - ) - t.args.SetArgType(i, type_to_kcl_type_annotation_str(type_node)) - runtime_type = objpkg.KCLSchemaTypeObject.schema_runtime_type( - t.name, self.pkgpath - ) - if should_add_schema_ref and self.schema_reference.add_node_judge_cycle( - runtime_type, base.runtime_type if base else "" - ): - base_name = base.name if base else "" - self.raise_err( - [t], - kcl_error.ErrType.CycleInheritError_TYPE, - f"{t.name} and {base_name}", - ) - schema_type = objpkg.KCLSchemaTypeObject( - name=t.name, - is_mixin=t.is_mixin, - is_protocol=t.is_protocol, - pkgpath=self.pkgpath, - filename=self.filename, - doc=t.doc, - base=base, - protocol=protocol, - runtime_type=runtime_type, - mixins_names=mixin_name_list, - attr_list=schema_attr_names, - attr_obj_map=attr_obj_map, - node_ref=t, - settings={ - objpkg.SETTINGS_OUTPUT_KEY: objpkg.SETTINGS_OUTPUT_INLINE - if not kcl_info.isprivate_field(t.name) - else objpkg.SETTINGS_OUTPUT_IGNORE - }, - index_signature=index_sign_obj, - func=objpkg.KCLCompiledFunctionObject( - name=t.name, - params=params, - ), - ) - self.schema_mapping[runtime_type] = schema_type - return objpkg.KCLSchemaDefTypeObject(schema_type=schema_type) - - def build_rule_type( - self, - t: ast.RuleStmt, - protocol_def: objpkg.KCLSchemaDefTypeObject = None, - should_add_schema_ref: bool = False, - ) -> objpkg.KCLSchemaDefTypeObject: - """Build a schema type using the rule statement""" - if t.name in RESERVED_TYPE_IDENTIFIERS: - self.raise_err( - [t], - kcl_error.ErrType.IllegalInheritError_TYPE, - "rule name '{}' cannot be the same as the built-in types ({})".format( - t.name, ", ".join(RESERVED_TYPE_IDENTIFIERS) - ), - ) - protocol = protocol_def.schema_type if protocol_def else None - mixin_name_list = [] - for mixin in t.parent_rules or []: - mixin_names = mixin.names - if mixin.pkgpath: - mixin_names[0] = f"@{mixin.pkgpath}" - mixin_name_list.append(mixin.get_name()) - - params: List[objpkg.Parameter] = [] - # Schema arguments - if t.args: - for i, arg in enumerate(t.args.args): - type_annotation = t.args.GetArgType(i) - type_node = self.parse_type_str_with_scope( - type_annotation, t.args.args[i] - ) - default = t.args.GetArgDefault(i) - params.append( - objpkg.Parameter( - name=arg.names[0], - value=objpkg.to_kcl_obj(default), - type_annotation=type_annotation, - type=type_node, - ) - ) - t.args.SetArgType(i, type_to_kcl_type_annotation_str(type_node)) - runtime_type = objpkg.KCLSchemaTypeObject.schema_runtime_type( - t.name, self.pkgpath - ) - - return objpkg.KCLSchemaDefTypeObject( - schema_type=objpkg.KCLSchemaTypeObject( - name=t.name, - is_rule=True, - pkgpath=self.pkgpath, - filename=self.filename, - protocol=protocol, - runtime_type=runtime_type, - mixins_names=mixin_name_list, - attr_list=[], - attr_obj_map={}, - settings={ - objpkg.SETTINGS_OUTPUT_KEY: objpkg.SETTINGS_OUTPUT_INLINE - if not kcl_info.isprivate_field(t.name) - else objpkg.SETTINGS_OUTPUT_IGNORE - }, - func=objpkg.KCLCompiledFunctionObject( - name=t.name, - params=params, - ), - ) - ) - - @staticmethod - def is_builtin_or_plugin_module(path: str) -> bool: - """Whether is a builtin system module or a plugin module""" - if not path or not isinstance(path, str): - return False - return path in builtin.STANDARD_SYSTEM_MODULES or path.startswith( - plugin.PLUGIN_MODULE_NAME - ) - - def init_global_types(self): - """Init global types including top-level global variable types and schema types - TODO: optimize the function with twice scan - """ - # 1. Scan all schema type symbol - for module in self.program.pkgs[self.pkgpath]: - self.change_package_context(self.pkgpath, module.filename) - for stmt in module.GetSchemaAndRuleList(): - if stmt.name in self.scope.elems: - self.raise_err( - [stmt], - kcl_error.ErrType.UniqueKeyError_TYPE, - kcl_error.UNIQUE_KEY_MSG.format(stmt.name), - ) - continue - schema_type_obj = objpkg.KCLSchemaTypeObject( - name=stmt.name, - runtime_type=objpkg.KCLSchemaTypeObject.schema_runtime_type( - stmt.name, self.pkgpath - ), - filename=self.filename, - pkgpath=self.pkgpath, - ) - self.scope.elems[stmt.name] = ScopeObject( - name=stmt.name, - node=stmt, - type=objpkg.KCLSchemaDefTypeObject( - schema_type=schema_type_obj, - ), - pos=ast.Position( - filename=self.filename, - line=stmt.line, - column=stmt.column, - ), - end=ast.Position( - filename=self.filename, - line=stmt.end_line, - column=stmt.end_column, - ), - ) - # 2. Scan all variable type symbol - self.init_global_var_types() - # 3. Build all schema types - for i in range(MAX_SCOPE_SCAN_COUNT): - for k, o in self.scope.elems.items(): - if isinstance(o.node, ast.SchemaStmt): - self.filename = o.type.schema_type.filename - schema_parent_type = self.build_schema_parent_type( - self.scope.elems[k].node - ) - schema_protocol_type = self.build_schema_protocol_type( - self.scope.elems[k].node - ) - self.scope.elems[k].type = self.build_schema_type( - self.scope.elems[k].node, - schema_parent_type, - schema_protocol_type, - i == MAX_SCOPE_SCAN_COUNT - 1, - ) - self.scope.elems[k].type = cast( - objpkg.KCLSchemaDefTypeObject, self.scope.elems[k].type - ) - elif isinstance(o.node, ast.RuleStmt): - self.filename = o.type.schema_type.filename - schema_protocol_type = self.build_rule_protocol_type( - self.scope.elems[k].node - ) - self.scope.elems[k].type = self.build_rule_type( - self.scope.elems[k].node, - schema_protocol_type, - i == MAX_SCOPE_SCAN_COUNT - 1, - ) - self.scope.elems[k].type = cast( - objpkg.KCLSchemaDefTypeObject, self.scope.elems[k].type - ) - # 4. Build all variable types - self.init_global_var_types(False) - - def do_import_stmt_check(self, t: ast.ImportStmt): - """Do import check and store the module object into the map""" - pkgpath = f"@{t.path}" - for name in [pkgpath, t.pkg_name]: - if name in self.scope.elems: - self.scope.elems[name].type.imported_filenames.append(self.filename) - else: - module_object = objpkg.KCLModuleTypeObject( - pkgpath=t.path, - imported_filenames=[self.filename], - is_user_module=not self.is_builtin_or_plugin_module(t.path), - is_system_module=t.path in builtin.STANDARD_SYSTEM_MODULES, - is_plugin_module=t.path.startswith(plugin.PLUGIN_MODULE_NAME), - ) - self.scope.elems[name] = ScopeObject( - name=t.path, - node=t, - type=module_object, - pos=ast.Position( - filename=self.filename, - line=t.line, - column=t.column, - ), - end=ast.Position( - filename=self.filename, - line=t.end_line, - column=t.end_column, - ), - ) - if not self.scope.elems[pkgpath].type.is_user_module: - return - # Save current pkgpath and filename - current_pkg_path = self.pkgpath - current_filename = self.filename - # Recursive import check - if self.import_reference.add_node_judge_cycle(self.pkgpath, t.path): - kcl_error.report_exception( - err_type=kcl_error.ErrType.RecursiveLoad_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=self.filename, - line_no=t.line, - ), - ], - arg_msg=kcl_error.RECURSIVE_LOADING_MODULE_MSG.format( - current_pkg_path, - ", ".join([self.pkgpath, t.path]), - ), - ) - # Switch pkgpath context - if t.path not in self.scope_map: - self.check(t.path) - # Restore the current context - self.change_package_context(current_pkg_path, current_filename) - - def parse_type_str_with_scope(self, type_str: str, node: ast.AST) -> Type: - # Type str to Type - tpe = parse_type_str(type_str) - - # If a named type, find it from scope to get the specific type - def walk_fn(t: Type): - if isinstance(t, objpkg.KCLNamedTypeObject): - if "." in t.name and t.name.rsplit(".", 1)[0] == f"@{self.pkgpath}": - t.name = t.name.replace(f"@{self.pkgpath}.", "", 1) - tpe = self.expr( - ast.Identifier( - names=t.name.rsplit(".", 1) - if t.name.startswith("@") - else t.name.split("."), - line=node.line, - ).set_filename(node.filename) - ) - if isinstance(tpe, objpkg.KCLSchemaDefTypeObject): - return tpe.schema_type - elif isinstance(tpe, objpkg.KCLNumberMultiplierTypeObject): - return tpe - elif hasattr(tpe, "is_type_alias") and tpe.is_type_alias: - return tpe - else: - self.raise_err( - [node], - msg=f"'{t.name}' refers to a value, but is being used as a type here", - ) - return t - - return WalkType(tpe, walk_fn) - - def init_import_list(self): - """Init import list and store the module scope object into the scope map""" - for module in self.program.pkgs[self.pkgpath]: - self.filename = module.filename - import_stmt_list = module.GetImportList() - for t in import_stmt_list: - self.do_import_stmt_check(t) - - def init_global_var_types(self, unique_check: bool = True): - """Init all global variable types""" - - def get_top_level_assign_list(module: ast.Module) -> List[ast.AssignStmt]: - - attr_list = [] - - def loop_body(body: List[ast.Stmt]): - """Get the l-values recursively and add them into schema attr list""" - if not body: - return - for stmt in body: - if isinstance(stmt, ast.AssignStmt): - attr_list.append(stmt) - elif isinstance(stmt, ast.IfStmt): - loop_body(stmt.body) - for body in stmt.elif_body: - loop_body(body) - loop_body(stmt.else_body) - - loop_body(module.body) - return attr_list - - def init_scope_with_assign_stmt(assign_stmt: ast.AssignStmt): - for target in assign_stmt.targets: - name = target.names[0] - if ( - name in self.scope.elems - and not kcl_info.isprivate_field(name) - and unique_check - ): - self.raise_err( - [target], - kcl_error.ErrType.ImmutableCompileError_TYPE, - ) - continue - if assign_stmt.type_annotation: - annotation_type = self.parse_type_str_with_scope( - assign_stmt.type_annotation, assign_stmt - ) - assign_stmt.type_annotation = type_to_kcl_type_annotation_str( - annotation_type - ) - if name in self.scope.elems: - origin_type = self.scope.elems[name].type - if not is_upper_bound(origin_type, annotation_type): - self.raise_err( - nodes=[self.scope.elems[name].node, target], - category=kcl_error.ErrType.TypeError_Compile_TYPE, - msg=f"can not change type of {name}", - file_msgs=[ - f"expect {origin_type.type_str()}", - f"got {annotation_type.type_str()}", - ], - file_levels=[ - kcl_error.ErrLevel.ORDINARY, - kcl_error.ErrLevel.SERIOUS, - ], - ) - continue - elif name in self.scope.elems: - annotation_type = self.scope.elems[name].type or ANY_TYPE - else: - annotation_type = ANY_TYPE - self.scope.elems[name] = ScopeObject( - name=name, - node=target, - type=annotation_type, - pos=ast.Position( - filename=self.filename, - line=target.line, - column=target.column, - ), - end=ast.Position( - filename=self.filename, - line=target.end_line, - column=target.end_column, - ), - ) - - for module in self.program.pkgs[self.pkgpath]: - self.change_package_context(self.pkgpath, module.filename) - for stmt in astutil.filter_stmt(module, ast.TypeAliasStmt): - self.walk(stmt) - for stmt in get_top_level_assign_list(module): - init_scope_with_assign_stmt(stmt) - - def dict_assignable_to_schema( - self, - node: ast.AST, - dict_type: Union[objpkg.KCLDictTypeObject, objpkg.KCLAnyTypeObject], - schema_type: objpkg.KCLSchemaTypeObject, - relaxed_key_type_mapping: Optional[Dict[str, Type]] = None, - ) -> bool: - """Judge a dict can be converted to schema in compile time""" - # Do relaxed schema check key and value type check - if relaxed_key_type_mapping and not False and not schema_type.index_signature: - self.raise_err( - nodes=[node], - category=kcl_error.ErrType.CannotAddMembers_TYPE, - msg=kcl_error.CANNOT_ADD_MEMBERS_MSG.format( - ",".join(relaxed_key_type_mapping.keys()), schema_type.name - ), - ) - return False - if dict_type == ANY_TYPE: - return True - if schema_type.index_signature: - schema_key_type = schema_type.index_signature.key_kcl_type - schema_value_type = schema_type.index_signature.value_kcl_type - for k in relaxed_key_type_mapping or {}: - tpe = relaxed_key_type_mapping[k] - if not assignable_to(tpe, schema_value_type): - self.raise_err( - [node], - msg=f"expected schema index signature value type {schema_value_type.type_str()}, " - f"got {tpe.type_str()} of the key '{k}'", - ) - if not schema_type.index_signature.any_other: - return assignable_to( - dict_type.key_type, schema_key_type - ) and assignable_to(dict_type.value_type, schema_value_type) - return True - - def load_attr_type( - self, - node: ast.AST, - obj: Type, - attr: str, - ) -> Type: - if obj == ANY_TYPE: - return ANY_TYPE - if isinstance(obj, objpkg.KCLDictTypeObject): - return obj.value_type - if isinstance(obj, objpkg.KCLSchemaDefTypeObject): - # Schema type member functions - if attr in objpkg.KCLSchemaTypeObject.MEMBER_FUNCTIONS: - return SCHEMA_TYPE_MEMBER_SCOPE.elems[attr].type - self.raise_err( - [node], - kcl_error.ErrType.AttributeError_TYPE, - f"schema '{obj.type_str()}' attribute '{attr}' not found", - ) - return ANY_TYPE - if isinstance(obj, objpkg.KCLSchemaTypeObject): - # Schema attribute - if obj.get_type_of_attr(attr) is None: - if not obj.should_add_additional_key: - self.raise_err( - [node], - kcl_error.ErrType.AttributeError_TYPE, - f"schema '{obj.type_str()}' attribute '{attr}' not found", - ) - return ANY_TYPE - return obj.get_type_of_attr(attr) - if isinstance(obj, (objpkg.KCLStringTypeObject, objpkg.KCLStringLitTypeObject)): - if attr not in objpkg.KCLStringObject.MEMBER_FUNCTIONS: - self.raise_err( - [node], - kcl_error.ErrType.AttributeError_TYPE, - f"str object has no attribute '{attr}'", - ) - return ANY_TYPE - return STR_TYPE_MEMBER_SCOPE.elems[attr].type - if isinstance(obj, objpkg.KCLUnionTypeObject): - return ANY_TYPE - # TODO: union type load attr based the type guard. e.g, a: str|int; if a is str: xxx; if a is int: xxx; - # return sup([self.load_attr_type(t, attr, filename, line, column) for t in obj.types]) - self.raise_err( - [node], - kcl_error.ErrType.AttributeError_TYPE, - f"{obj.type_str() if obj else None} has no attribute '{attr}'", - ) - return ANY_TYPE - - def check_attr( - self, node: ast.AST, obj: Type, attr: str, check_rules: List[typing.Callable] - ): - if obj and isinstance(obj, objpkg.KCLSchemaTypeObject): - for check_rule in check_rules: - check_rule(name=attr, node=node, schema_type=obj) - - def check_defined( - self, - name: Optional[str], - node: ast.AST, - schema_type: objpkg.KCLSchemaTypeObject, - ): - schema_type = self.schema_mapping.get(schema_type.runtime_type) or schema_type - if ( - isinstance(schema_type, objpkg.KCLSchemaTypeObject) - and not schema_type.get_obj_of_attr(name) - and not schema_type.can_add_members() - and not self._is_in_lambda_expr[-1] - ): - self.raise_err( - nodes=[node], - category=kcl_error.ErrType.CannotAddMembers_TYPE, - msg=f"Cannot add member '{name}' to schema '{schema_type.name}'", - file_msgs=[f"'{name}' is not defined in schema '{schema_type.name}'"], - ) - - def check_type(self, node: ast.AST, tpe: Type, expected_type: Type) -> bool: - if type is None: - return False - if ( - tpe.type_kind() == objpkg.KCLTypeKind.ListKind - and expected_type.type_kind() == objpkg.KCLTypeKind.ListKind - ): - return self.check_type(node, tpe.item_type, expected_type.item_type) - elif ( - tpe.type_kind() == objpkg.KCLTypeKind.DictKind - and expected_type.type_kind() == objpkg.KCLTypeKind.DictKind - ): - return self.check_type( - node, tpe.key_type, expected_type.key_type - ) and self.check_type(node, tpe.value_type, expected_type.value_type) - elif tpe.type_kind() == objpkg.KCLTypeKind.UnionKind: - return all([self.check_type(node, t, expected_type) for t in tpe.types]) - if ( - tpe.type_kind() == objpkg.KCLTypeKind.DictKind - and expected_type.type_kind() == objpkg.KCLTypeKind.SchemaKind - ): - return self.dict_assignable_to_schema(node, tpe, expected_type) - if expected_type.type_kind() == objpkg.KCLTypeKind.UnionKind: - return any([self.check_type(node, tpe, t) for t in expected_type.types]) - else: - return assignable_to(tpe, expected_type) - - def must_assignable_to( - self, - node: ast.AST, - tpe: Type, - expected_type: Type, - err_category=kcl_error.ErrType.TypeError_Compile_TYPE, - expected_node: ast.AST = None, - ): - expect_type_str = ( - expected_type.type_str() if expected_type is not None else None - ) - tpe_str = tpe.type_str() if tpe is not None else None - if tpe is None or not self.check_type(node, tpe, expected_type): - self.raise_err( - nodes=[expected_node, node] if expected_node else [node], - category=err_category, - msg=f"expect {expect_type_str}, got {tpe_str}", - file_msgs=[f"expect {expect_type_str}", f"got {tpe_str}"] - if expected_node - else [f"got {tpe_str}"], - file_levels=[kcl_error.ErrLevel.ORDINARY, kcl_error.ErrLevel.SERIOUS] - if expected_node - else [kcl_error.ErrLevel.SERIOUS], - ) - - def must_be_type(self, node: ast.AST, expected_type: Type): - if node and isinstance(node, ast.AST): - tpe = self.walk(node) - self.must_assignable_to(node, tpe, expected_type) - - def enter_scope(self, node: ast.AST): - if node and isinstance(node, ast.AST): - scope = Scope( - parent=self.scope, - node=node, - pos=ast.Position( - filename=self.filename, - line=node.line, - column=node.column, - ), - end=ast.Position( - filename=self.filename, - line=node.end_line, - column=node.end_column, - ), - ) - else: - scope = Scope(self.scope, node) - self.scope.children.append(scope) - self.scope = scope - - def leave_scope(self): - self.scope = self.scope.parent - self._local_vars = [] - - def stmts(self, stmts: List[ast.Stmt]): - stmt_types = [self.stmt(stmt) for stmt in stmts or []] - return stmt_types[-1] if stmt_types else ANY_TYPE - - def exprs(self, exprs: List[ast.Expr]): - return [self.expr(expr) for expr in exprs or []] - - def expr(self, node: ast.Expr): - return self.walk(node) - - def expr_or_any_type(self, node: ast.Expr): - return self.walk(node) if node else ANY_TYPE - - def stmt(self, node: ast.Stmt): - return self.walk(node) - - def lookup_type_from_scope(self, name: str, node: ast.AST) -> Optional[Type]: - tpe = self.find_type_in_scope(name) - if tpe: - return tpe - self.raise_err( - [node], msg="name '{}' is not defined".format(name.replace("@", "")) - ) - return ANY_TYPE - - def find_type_in_scope(self, name: str) -> Optional[Type]: - scope = self.find_scope(name) - return scope.type or ANY_TYPE if scope else None - - def find_scope(self, name: str) -> Optional[Scope]: - scope = self.scope - while scope and name not in scope.elems: - scope = scope.parent - if scope: - return scope.elems[name] or None - return None - - def set_type_to_scope(self, name: str, tpe: Type, node: ast.AST): - if not name: - return - scope = self.scope - while scope and name not in scope.elems: - scope = scope.parent - if scope: - scope.elems[name].type = infer_to_variable_type(tpe) - return - self.raise_err([node], msg=f"name '{name}' is not defined") - - def do_arguments_type_check( - self, - args: List[ast.Expr], - kwargs: List[ast.Keyword], - params: List[objpkg.Parameter], - ): - """Do schema argument type check""" - arg_types: List[Type] = self.exprs(args) - kwarg_types: List[Tuple[str, Type]] = [] - check_table = set() - for kw in kwargs or []: - arg_name = kw.arg.names[0] - if arg_name in check_table: - self.raise_err( - [kw], msg=f"duplicated keyword argument {kw.arg.get_name()}" - ) - check_table.add(arg_name) - arg_value_type = self.expr(kw.value) - kwarg_types.append((arg_name, arg_value_type)) - - if params: - for i, value in enumerate(arg_types): - arg_name = params[i].name - expected_type = params[i].type - self.must_assignable_to( - args[i], - value, - expected_type, - kcl_error.ErrType.TypeError_Compile_TYPE, - ) - for i, kwarg in enumerate(kwarg_types): - arg_name, value = kwarg - if arg_name not in [p.name for p in params]: - self.raise_err( - [kwargs[i]], - msg=f"arguments got an unexpected keyword argument '{arg_name}'", - ) - expected_types = [p.type for p in params if arg_name == p.name] - expected_type = expected_types[0] if expected_types else ANY_TYPE - self.must_assignable_to( - kwargs[i], - value, - expected_type, - kcl_error.ErrType.TypeError_Compile_TYPE, - ) - - def do_loop_type_check( - self, - t: ast.AST, - target_node: ast.AST, - key_name: str, - val_name: str, - iter_type: Type, - ): - """Do loop type check including quant and comp for expression""" - if isinstance(iter_type, objpkg.KCLUnionTypeObject): - types = iter_type.types - else: - types = [iter_type] - key_type, value_type = ANY_TYPE, ANY_TYPE - last_key_type, last_value_type = VOID_TYPE, VOID_TYPE - for iter_type in types: - if not isinstance(iter_type, ITER_TYPES): - self.raise_err( - [t], msg=f"'{iter_type.type_str()}' object is not iterable" - ) - if isinstance(iter_type, objpkg.KCLListTypeObject): - # Two variables - if val_name: - key_type, value_type = sup([INT_TYPE, last_key_type]), sup( - [iter_type.item_type, last_value_type] - ) - self.set_type_to_scope(key_name, key_type, target_node) - self.set_type_to_scope(val_name, value_type, target_node) - else: - key_type = sup([iter_type.item_type, last_key_type]) - self.set_type_to_scope(key_name, key_type, target_node) - elif isinstance( - iter_type, (objpkg.KCLDictTypeObject, objpkg.KCLSchemaTypeObject) - ): - key_type, value_type = sup([iter_type.key_type, last_key_type]), sup( - [iter_type.value_type, last_value_type] - ) - self.set_type_to_scope(key_name, key_type, target_node) - self.set_type_to_scope(val_name, value_type, target_node) - elif isinstance( - iter_type, (objpkg.KCLStringTypeObject, objpkg.KCLStringLitTypeObject) - ): - if val_name: - key_type, value_type = sup([INT_TYPE, last_key_type]), sup( - [STR_TYPE, last_value_type] - ) - self.set_type_to_scope(key_name, key_type, target_node) - self.set_type_to_scope(val_name, value_type, target_node) - else: - key_type = sup([STR_TYPE, last_key_type]) - self.set_type_to_scope(key_name, key_type, target_node) - last_key_type, last_value_type = key_type, value_type - - -class TypeChecker(BaseTypeChecker): - def walk_Module(self, t: ast.Module): - return self.stmts(t.body) - - def walk_ExprStmt(self, t: ast.ExprStmt): - expr_types = self.exprs(t.exprs) - return expr_types[-1] if expr_types else ANY_TYPE - - def walk_AssertStmt(self, t: ast.AssertStmt): - self.expr(t.test) - # Check type in if_cond expression - self.expr_or_any_type(t.if_cond) - self.must_be_type(t.msg, STR_TYPE) - return ANY_TYPE - - def walk_IfStmt(self, t: ast.IfStmt): - self.expr(t.cond) - self.stmts(t.body) - for elif_cond, elif_body in zip(t.elif_cond, t.elif_body): - self.expr(elif_cond) - self.stmts(elif_body) - self.stmts(t.else_body) - return ANY_TYPE - - def walk_ImportStmt(self, t: ast.ImportStmt): - """import as """ - # Add package name into the scope - if t.path not in self.scope_map: - self.do_import_stmt_check(t) - return ANY_TYPE - - def walk_RuleStmt(self, t: ast.RuleStmt): - self.in_schema_type = cast( - objpkg.KCLSchemaDefTypeObject, self.lookup_type_from_scope(t.name, t) - ).schema_type - # Rule Decorators - self.exprs(t.decorators) - self.enter_scope(t) - # Rule args - for param in self.in_schema_type.func.params or []: - self.scope.elems[param.name] = ScopeObject( - name=param.name, - node=t.args, - type=param.type, - pos=ast.Position( - filename=self.filename, - line=t.line, - column=t.column, - ), - end=ast.Position( - filename=self.filename, - line=t.end_line, - column=t.end_column, - ), - ) - # Rule check expressions - self.exprs(t.checks) - self.leave_scope() - self.in_schema_type = None - return ANY_TYPE - - def walk_SchemaStmt(self, t: ast.SchemaStmt): - self.in_schema_type = cast( - objpkg.KCLSchemaDefTypeObject, self.lookup_type_from_scope(t.name, t) - ).schema_type - # Schema Decorators - self.exprs(t.decorators) - self.enter_scope(t) - # Schema args - for param in self.in_schema_type.func.params or []: - self.scope.elems[param.name] = ScopeObject( - name=param.name, - node=t.args, - type=param.type, - pos=ast.Position( - filename=self.filename, - line=t.line, - column=t.column, - ), - end=ast.Position( - filename=self.filename, - line=t.end_line, - column=t.end_column, - ), - ) - # Schema index signature - if ( - self.in_schema_type.index_signature - and self.in_schema_type.index_signature.key_name - ): - self.scope.elems[ - self.in_schema_type.index_signature.key_name - ] = ScopeObject( - name=self.in_schema_type.index_signature.key_name, - node=t.index_signature, - type=self.in_schema_type.index_signature.key_kcl_type, - pos=ast.Position( - filename=self.filename, - line=t.index_signature.line, - column=t.index_signature.column, - ), - end=ast.Position( - filename=self.filename, - line=t.index_signature.end_line, - column=t.index_signature.end_column, - ), - ) - schema_attr_names = t.GetLeftIdentifierList() - for name in schema_attr_names: - if name not in self.scope.elems: - self.scope.elems[name] = ScopeObject( - name=name, - node=None, - type=ANY_TYPE, - ) - # Schema body - self.stmts(t.body) - # Schema check block - self.exprs(t.checks) - self.leave_scope() - self.in_schema_type = None - return ANY_TYPE - - def walk_SchemaAttr(self, t: ast.SchemaAttr): - self._local_vars = [] - if "." in t.name: - self.raise_err([t], msg="schema attribute can not be selected") - expected_type = self.in_schema_type.get_type_of_attr(t.name) or ANY_TYPE - # Schema attribute decorators - self.exprs(t.decorators) - self.scope.elems[t.name] = ScopeObject( - name=t.name, - node=t, - type=expected_type, - pos=ast.Position( - filename=self.filename, - line=t.line, - column=t.column, - ), - end=ast.Position( - filename=self.filename, - line=t.end_line, - column=t.end_column, - ), - ) - # Do not check type if no default value - if t.value: - if isinstance(expected_type, objpkg.KCLSchemaTypeObject): - init_stack_depth = self.switch_config_expr_context( - self.new_config_expr_context_item( - name=expected_type.name, type_obj=expected_type, node=t - ) - ) - value_type = self.expr(t.value) - self.clear_config_expr_context(stack_depth=init_stack_depth) - else: - value_type = self.expr(t.value) - # Assign - if not t.op or t.op == ast.AugOp.Assign: - self.must_assignable_to( - t, - value_type, - expected_type, - kcl_error.ErrType.TypeError_Compile_TYPE, - ) - else: - self.must_assignable_to( - t, - binary(expected_type, value_type, t.op), - expected_type, - kcl_error.ErrType.TypeError_Compile_TYPE, - ) - return ANY_TYPE - - def walk_Decorator(self, t: ast.Decorator): - decorator_name = t.name.get_name() - # Judge invalid decorator - internal.decorator_factory.get( - decorator_name, - internal.DecoratorTargetType.SCHEMA_TYPE, - filename=self.filename, - lineno=t.line, - columnno=t.column, - ) - # Decorator args type check according to decorator lookup table - decorator_func_type = DECORATOR_SCOPE.elems.get(decorator_name, ANY_TYPE).type - if isinstance(decorator_func_type, objpkg.KCLFunctionTypeObject) and t.args: - self.do_arguments_type_check( - t.args.args, t.args.keywords, decorator_func_type.params - ) - return ANY_TYPE - - def walk_IfExpr(self, t: ast.IfExpr): - """ if else -> sup([body, orelse])""" - self.expr(t.cond) - types = self.exprs([t.body, t.orelse]) - return sup(types) - - def walk_UnaryExpr(self, t: ast.UnaryExpr): - return unary(self.expr(t.operand), t.op, self.filename, t.line) - - def walk_BinaryExpr(self, t: ast.BinaryExpr): - left_type, right_type = self.expr(t.left), self.expr(t.right) - if t.op == ast.BinOp.As: - if not isinstance(t.right, ast.Identifier): - self.raise_err( - [t.right], msg="Keyword 'as' right operand must be a type" - ) - return self.expr(t.left) - # Replace with type alias - right_type = self.parse_type_str_with_scope(t.right.get_name(), t.right) - type_annotation_str = type_to_kcl_type_annotation_str(right_type) - if ( - "." in type_annotation_str - and type_annotation_str.rsplit(".", 1)[0] == f"@{self.pkgpath}" - ): - type_annotation_str = type_annotation_str.replace( - f"@{self.pkgpath}.", "", 1 - ) - t.right.names = type_annotation_str.rsplit(".", 1) - return binary(left_type, right_type, t.op, self.filename, t.line) - - def walk_Compare(self, t: ast.Compare): - for t1, t2, op in zip([t.left] + t.comparators, t.comparators, t.ops): - compare(self.expr(t1), self.expr(t2), op, self.filename, t.line) - return BOOL_TYPE - - def walk_SelectorExpr(self, t: ast.SelectorExpr): - value_type = self.expr(t.value) - for name in t.attr.names: - value_type = self.load_attr_type(t, value_type, name) - return value_type - - def walk_CallExpr(self, t: ast.CallExpr): - func_type = self.expr(t.func) - if ( - func_type != ANY_TYPE - and func_type.type_kind() != objpkg.KCLTypeKind.FuncKind - and not isinstance(func_type, objpkg.KCLSchemaDefTypeObject) - ): - self.raise_err([t], msg=f"'{func_type.type_str()}' object is not callable") - return ANY_TYPE - if func_type == ANY_TYPE: - self.do_arguments_type_check( - t.args, - t.keywords, - [], - ) - return ANY_TYPE - self.do_arguments_type_check( - t.args, - t.keywords, - func_type.schema_type.func.params - if isinstance(func_type, objpkg.KCLSchemaDefTypeObject) - else func_type.params, - ) - return ( - func_type.schema_type - if isinstance(func_type, objpkg.KCLSchemaDefTypeObject) - else func_type.return_type - ) - - def walk_ParenExpr(self, t: ast.ParenExpr): - return self.expr(t.expr) - - def walk_QuantExpr(self, t: ast.QuantExpr): - """ - self.target: Optional[Expr] = None - self.variables: List[Identifier] = [] - self.op: Optional[int] = None - self.test: Optional[Expr] = None - self.if_cond: Optional[Expr] = None - """ - iter_type = self.expr(t.target) - if iter_type == ANY_TYPE: - return ANY_TYPE - self.enter_scope(t) - key_name = None - val_name = None - target_node = None - for i, target in enumerate(t.variables): - target_node = target - name = target.names[0] - key_name = name if i == 0 else key_name - val_name = name if i == 1 else val_name - self._local_vars.append(name) - self.scope.elems[name] = ScopeObject( - name=name, - node=target, - type=ANY_TYPE, - ) - self.do_loop_type_check(t, target_node, key_name, val_name, iter_type) - self.expr_or_any_type(t.if_cond) - item_type = self.expr(t.test) - return_type = ANY_TYPE - if t.op in [ast.QuantOperation.ALL, ast.QuantOperation.ANY]: - return_type = BOOL_TYPE - elif t.op == ast.QuantOperation.MAP: - return_type = objpkg.KCLListTypeObject(item_type=item_type) - elif t.op == ast.QuantOperation.FILTER: - return_type = iter_type - else: - self.raise_err([t], msg=f"Invalid quantifier expression op {t.op}") - self.leave_scope() - return return_type - - def walk_ListExpr(self, t: ast.ListExpr): - item_type = sup(self.exprs(t.elts)) - return objpkg.KCLListTypeObject(item_type=item_type) - - def walk_StarredExpr(self, t: ast.StarredExpr): - """Single star unpack expression *t.value""" - value_type = self.expr(t.value) - if value_type == ANY_TYPE: - return ANY_TYPE - if isinstance(value_type, objpkg.KCLNoneTypeObject): - return NONE_TYPE - if isinstance(value_type, objpkg.KCLListTypeObject): - return value_type.item_type - if isinstance( - value_type, (objpkg.KCLDictTypeObject, objpkg.KCLSchemaTypeObject) - ): - return value_type.key_type - if is_kind_type_or_kind_union_type( - value_type, - [objpkg.KCLTypeKind.DictKind, objpkg.KCLTypeKind.SchemaKind], - ): - return sup([tpe.key_type for tpe in value_type.types]) - self.raise_err( - [t.value], - msg=f"only list, dict, schema object can be used * unpacked, got {value_type.type_str()}", - ) - return ANY_TYPE - - def walk_ListComp(self, t: ast.ListComp): - self.enter_scope(t) - self.exprs(t.generators) - if isinstance(t.elt, ast.StarredExpr): - self.raise_err( - [t.elt], - msg="list unpacking cannot be used in list comprehension", - ) - item_type = self.expr(t.elt) - self.leave_scope() - return objpkg.KCLListTypeObject(item_type=item_type) - - def walk_DictComp(self, t: ast.DictComp): - self.enter_scope(t) - self.exprs(t.generators) - if not t.key: - self.raise_err( - [t.value], - msg="dict unpacking cannot be used in dict comprehension", - ) - key_type, value_type = self.expr(t.key), self.expr(t.value) - self.leave_scope() - return objpkg.KCLDictTypeObject(key_type=key_type, value_type=value_type) - - def walk_CompClause(self, t: ast.CompClause): - iter_type = self.expr(t.iter) - key_name = None - val_name = None - target_node = None - for i, target in enumerate(t.targets): - target_node = target - name = target.names[0] - key_name = name if i == 0 else key_name - val_name = name if i == 1 else val_name - self._local_vars.append(name) - self.scope.elems[name] = ScopeObject( - name=name, - node=target, - type=ANY_TYPE, - pos=ast.Position( - filename=self.filename, - line=target.line, - column=target.column, - ), - end=ast.Position( - filename=self.filename, - line=target.end_line, - column=target.end_column, - ), - ) - if iter_type == ANY_TYPE: - return ANY_TYPE - self.do_loop_type_check(t, target_node, key_name, val_name, iter_type) - self.exprs(t.ifs) - return ANY_TYPE - - def walk_Subscript(self, t: ast.Subscript): - value_type = self.expr(t.value) - if value_type == ANY_TYPE: - return ANY_TYPE - if isinstance( - value_type, (objpkg.KCLSchemaTypeObject, objpkg.KCLDictTypeObject) - ): - if not t.index: - self.raise_err([t], msg="unhashable type: 'slice'") - return ANY_TYPE - key_type = self.expr(t.index) - if key_type == ANY_TYPE or key_type == NONE_TYPE: - return value_type.value_type - if not is_kind_type_or_kind_union_type(key_type, KEY_KINDS): - self.raise_err( - [t.index], - msg=f"invalid dict/schema key type: '{key_type.type_str()}'", - ) - return ANY_TYPE - return ( - self.load_attr_type(t, value_type, t.index.value) - if isinstance(t.index, ast.StringLit) - else value_type.value_type - ) - elif isinstance( - value_type, - ( - objpkg.KCLListTypeObject, - objpkg.KCLStringTypeObject, - objpkg.KCLStringLitTypeObject, - ), - ): - if t.index: - self.must_be_type(t.index, INT_TYPE) - return ( - value_type.item_type - if isinstance(value_type, objpkg.KCLListTypeObject) - else STR_TYPE - ) - else: - self.must_be_type(t.lower, INT_TYPE) - self.must_be_type(t.upper, INT_TYPE) - self.must_be_type(t.step, INT_TYPE) - return ( - value_type - if isinstance(value_type, objpkg.KCLListTypeObject) - else STR_TYPE - ) - self.raise_err( - [t.value], msg=f"'{value_type.type_str()}' object is not subscriptable" - ) - return ANY_TYPE - - def walk_SchemaExpr(self, t: ast.SchemaExpr): - # Auto append schema import statements. - if self.config.config_attr_auto_fix: - try: - schema_def_type = self.walk(t.name) - except Exception: - # Match the schema package path. - pkgpaths = [ - schema.pkgpath - for schema in self.schema_mapping.values() - if t.name.get_name() == schema.name - ] - if pkgpaths: - # Select the first matched path. - pkgpath = pkgpaths[0] - import_list = self.program.pkgs[self.pkgpath][0].GetImportList() - imported_pkgpath = [stmt.path for stmt in import_list] - # Exists import - try: - index = imported_pkgpath.index(pkgpath) - t.name.names = [import_list[index].pkg_name] + t.name.names - # Not exists import, append the import stmt. - except ValueError: - if pkgpath and pkgpath != ast.Program.MAIN_PKGPATH: - name = pkgpath.rsplit(".")[-1] - import_stmt = ast.ImportStmt(1, 1) - import_stmt.path = pkgpath - import_stmt.name = name - self.program.pkgs[self.pkgpath][0].body.insert( - 0, import_stmt - ) - t.name.names = [name] + t.name.names - return ANY_TYPE - else: - schema_def_type = self.walk(t.name) - if isinstance(schema_def_type, objpkg.KCLSchemaDefTypeObject): - schema_type_annotation_str = type_to_kcl_type_annotation_str( - schema_def_type - ) - if ( - "." in schema_type_annotation_str - and schema_type_annotation_str.rsplit(".", 1)[0] == f"@{self.pkgpath}" - ): - schema_type_annotation_str = schema_type_annotation_str.replace( - f"@{self.pkgpath}.", "", 1 - ) - t.name.names = schema_type_annotation_str.rsplit(".", 1) - schema_type = cast(objpkg.KCLSchemaTypeObject, schema_def_type.schema_type) - init_stack_depth = self.switch_config_expr_context( - self.new_config_expr_context_item( - name=schema_type.name, type_obj=schema_type, node=t - ) - ) - self.expr(t.config) - self.clear_config_expr_context(stack_depth=init_stack_depth) - # Do schema argument type check - self.do_arguments_type_check(t.args, t.kwargs, schema_type.func.params) - return schema_type - elif isinstance(schema_def_type, objpkg.KCLSchemaTypeObject): - schema_type = schema_def_type - init_stack_depth = self.switch_config_expr_context( - self.new_config_expr_context_item( - name=schema_type.name, type_obj=schema_type, node=t - ) - ) - self.expr(t.config) - self.clear_config_expr_context(stack_depth=init_stack_depth) - if t.args or t.kwargs: - self.raise_err( - [t.name], - msg="Arguments cannot be used in the schema modification expression", - ) - return schema_type - elif isinstance(schema_def_type, objpkg.KCLDictTypeObject): - dict_type = schema_def_type - init_stack_depth = self.switch_config_expr_context( - self.new_config_expr_context_item(type_obj=dict_type, node=t) - ) - config_type = self.expr(t.config) - self.clear_config_expr_context(stack_depth=init_stack_depth) - return binary( - dict_type, config_type, ast.BinOp.BitOr, self.filename, t.line - ) - self.raise_err( - [t.name], - msg=f"Invalid schema type '{schema_def_type.type_str() if schema_def_type else None}'", - ) - return ANY_TYPE - - def walk_ConfigExpr(self, t: ast.ConfigExpr): - value_types = [] - key_types = [] - fix_values = [] - for i, key, value, op in zip( - range(len(t.keys)), t.keys, t.values, t.operations - ): - stack_depth = 0 - fix_value = self.check_config_entry(key, value, [self.check_defined]) - fix_values.append((i, fix_value)) - stack_depth += self.switch_config_expr_context_by_key(key) - value_type = ANY_TYPE - has_insert_index = False - # Double_star expr and dict_if_entry expr - if not key: - value_type = self.expr(value) - if value_type == ANY_TYPE or value_type == NONE_TYPE: - value_types.append(value_type) - elif isinstance( - value_type, (objpkg.KCLDictTypeObject, objpkg.KCLSchemaTypeObject) - ): - key_types.append(value_type.key_type) - value_types.append(value_type.value_type) - elif is_kind_type_or_kind_union_type( - value_type, - [objpkg.KCLTypeKind.DictKind, objpkg.KCLTypeKind.SchemaKind], - ): - key_types.append(sup([tpe.key_type for tpe in value_type.types])) - value_types.append( - sup([tpe.value_type for tpe in value_type.types]) - ) - else: - self.raise_err( - nodes=[value], - msg=f"only dict and schema can be used ** unpack, got '{value_type.type_str()}'", - ) - elif isinstance(key, ast.Identifier): - # Nest identifier key -> str key - if len(key.names) == 1: - name = key.get_name(False) - key_type = self.expr(key) if name in self._local_vars else STR_TYPE - if key_type != ANY_TYPE and key_type.type_kind() not in KEY_KINDS: - self.raise_err( - nodes=[key], - category=kcl_error.ErrType.IllegalAttributeError_TYPE, - msg=f"type '{key_type.type_str()}'", - ) - else: - key_type = STR_TYPE - key_types.append(key_type) - value_type = self.expr(value) - nest_value_type = value_type - for _ in range(len(key.names) - 1): - nest_value_type = objpkg.KCLDictTypeObject( - key_type=STR_TYPE, value_type=nest_value_type - ) - value_types.append(nest_value_type) - elif isinstance(key, ast.Subscript): - if isinstance(key.value, ast.Identifier) and isinstance( - key.index, ast.NumberLit - ): - has_insert_index = True - value_type = self.expr(value) - key_types.append(STR_TYPE) - value_types.append(objpkg.KCLListTypeObject(value_type)) - else: - key_type, value_type = self.expr(key), self.expr(value) - if key_type != ANY_TYPE and key_type.type_kind() not in KEY_KINDS: - self.raise_err( - [key], - kcl_error.ErrType.IllegalAttributeError_TYPE, - f"type '{key_type.type_str()}'", - ) - key_types.append(key_type) - value_types.append(value_type) - if ( - op == ast.ConfigEntryOperation.INSERT - and not has_insert_index - and value_type != ANY_TYPE - and not isinstance(value_type, objpkg.KCLListTypeObject) - ): - self.raise_err( - [value], - kcl_error.ErrType.IllegalAttributeError_TYPE, - f"only list type can in inserted, got '{value_type.type_str()}'", - ) - self.clear_config_expr_context(stack_depth=stack_depth) - key_type = sup(key_types) - value_type = sup(value_types) - for i, fix_value in fix_values: - if fix_value: - t.items[i].value = fix_value - # self.clear_config_expr_context(stack_depth=init_stack_depth) - return objpkg.KCLDictTypeObject(key_type=key_type, value_type=value_type) - - def walk_CheckExpr(self, t: ast.CheckExpr): - self.must_be_type(t.msg, STR_TYPE) - # Check type in if_cond expression - self.expr_or_any_type(t.if_cond) - return self.expr(t.test) - - def walk_LambdaExpr(self, t: ast.LambdaExpr): - """ast.AST: LambdaExpr - - Parameters - ---------- - - args: Optional[Arguments] - - return_type_str: Optional[str] - - return_type_node: Optional[Type] - - body: List[Stmt] - """ - params = [] - return_type = ANY_TYPE - if t.args: - for i, arg in enumerate(t.args.args): - name = arg.get_name() - type_annotation = t.args.GetArgType(i) - type_node = self.parse_type_str_with_scope( - type_annotation, t.args.args[i] - ) - default = t.args.GetArgDefault(i) - params.append( - objpkg.Parameter( - name=name, - value=objpkg.to_kcl_obj(default), - type_annotation=type_annotation, - type=type_node, - ) - ) - t.args.SetArgType(i, type_to_kcl_type_annotation_str(type_node)) - if t.return_type_str: - return_type = self.parse_type_str_with_scope(t.return_type_str, t) - t.return_type_str = type_to_kcl_type_annotation_str(return_type) - self.enter_scope(t) - self._is_in_lambda_expr.append(True) - # Lambda args - for param in params or []: - self.scope.elems[param.name] = ScopeObject( - name=param.name, - node=t.args, - type=param.type, - pos=ast.Position( - filename=self.filename, - line=t.line, - column=t.column, - ), - end=ast.Position( - filename=self.filename, - line=t.end_line, - column=t.end_column, - ), - ) - real_return_type = self.stmts(t.body) - self.leave_scope() - self._is_in_lambda_expr.pop() - self.must_assignable_to( - t.body[-1] if t.body else t, real_return_type, return_type - ) - if ( - real_return_type != ANY_TYPE - and return_type == ANY_TYPE - and not t.return_type_str - ): - return_type = real_return_type - return objpkg.KCLFunctionTypeObject( - name="", - params=params, - self_type=ANY_TYPE, - return_type=return_type, - doc="", - ) - - def walk_Identifier(self, t: ast.Identifier): - assert len(t.names) >= 1 - if t.pkgpath: - t.names[0] = f"@{t.pkgpath}" - if t.ctx == ast.ExprContext.STORE or t.ctx == ast.ExprContext.AUGSTORE: - self.raise_err( - [t], msg="only schema and dict object can be updated attribute" - ) - name = t.names[0] - if os.getenv("KCL_FEATURE_GATEWAY_STRONG_MUTABLE"): - if t.ctx == ast.ExprContext.STORE or t.ctx == ast.ExprContext.AUGSTORE: - if self.in_schema_type: - if not kcl_info.isprivate_field(name) and ( - name in self.scope.elems - and self.scope.elems[name].pos - and ( - t.line != self.scope.elems[name].pos.line - or t.column != self.scope.elems[name].pos.column - ) - ): - self.raise_err( - [t], - kcl_error.ErrType.ImmutableCompileError_TYPE, - ) - if len(t.names) == 1: - if self.in_schema_type: - # Load from schema if in schema - tpe = self.in_schema_type.get_type_of_attr(name) - if t.ctx == ast.ExprContext.LOAD or t.ctx == ast.ExprContext.AUGLOAD: - scope_type = self.find_type_in_scope(name) - if name in self._local_vars: - return scope_type or ANY_TYPE - if tpe and tpe != ANY_TYPE: - return tpe - return scope_type or ANY_TYPE - # TODO: Enhanced Mixin with protocol - # return tpe or self.lookup_type_from_scope(name, t) - elif ( - t.ctx == ast.ExprContext.STORE or t.ctx == ast.ExprContext.AUGSTORE - ): - if name not in self.scope.elems or not tpe: - self.scope.elems[name] = ScopeObject( - name=name, - node=t, - type=ANY_TYPE, - pos=ast.Position( - filename=self.filename, - line=t.line, - column=t.column, - ), - end=ast.Position( - filename=self.filename, - line=t.end_line, - column=t.end_column, - ), - ) - if not tpe: - self.in_schema_type.set_type_of_attr(name, ANY_TYPE) - return ANY_TYPE - self.check_attr( - t, - self.in_schema_type, - name, - [self.check_defined], - ) - return tpe if tpe else self.lookup_type_from_scope(name, t) - else: - if t.ctx == ast.ExprContext.LOAD or t.ctx == ast.ExprContext.AUGLOAD: - return self.lookup_type_from_scope(name, t) - elif ( - t.ctx == ast.ExprContext.STORE or t.ctx == ast.ExprContext.AUGSTORE - ): - if name not in self.scope.elems and not self.in_schema_type: - self.scope.elems[name] = ScopeObject( - name=name, - node=t, - type=ANY_TYPE, - pos=ast.Position( - filename=self.filename, - line=t.line, - column=t.column, - ), - end=ast.Position( - filename=self.filename, - line=t.end_line, - column=t.end_column, - ), - ) - return ANY_TYPE - return self.lookup_type_from_scope(name, t) - return ANY_TYPE - else: - names = t.names - if t.ctx != ast.ExprContext.AUGSTORE: - tpe = self.expr( - ast.Identifier( - names=[names[0]], line=t.line, column=t.column - ).set_filename(t.filename) - ) - else: - tpe = self.lookup_type_from_scope(t.names[0], t) - - for name in names[1:]: - if isinstance(tpe, objpkg.KCLModuleTypeObject): - if tpe.is_user_module: - if tpe.pkgpath not in self.scope_map: - self.raise_err( - [t], msg=f"name '{tpe.pkgpath}' is not defined" - ) - return ANY_TYPE - elif name not in self.scope_map[tpe.pkgpath].elems: - self.raise_err( - [t], - kcl_error.ErrType.AttributeError_TYPE, - f"module '{tpe.pkgpath}' has no attribute '{name}'", - ) - tpe = ANY_TYPE - elif ( - self.filename not in tpe.imported_filenames - and self.pkgpath != ast.Program.MAIN_PKGPATH - ): - self.raise_err( - [t], msg=f"name '{tpe.pkgpath}' is not defined" - ) - tpe = ANY_TYPE - else: - tpe = self.scope_map[tpe.pkgpath].elems[name].type - if isinstance(tpe, objpkg.KCLModuleTypeObject): - self.raise_err( - [t], - kcl_error.ErrType.CompileError_TYPE, - f"can not import the attribute '{name}' from the module '{t.names[0]}'", - file_msgs=[f"'{name}' is a module attribute"], - ) - elif tpe.is_plugin_module: - tpe = ( - PLUGIN_SCOPE_MAPPING[tpe.pkgpath].elems[name].type - if ( - tpe.pkgpath in PLUGIN_SCOPE_MAPPING - and name in PLUGIN_SCOPE_MAPPING[tpe.pkgpath].elems - ) - else ANY_TYPE - ) - elif tpe.is_system_module: - members = builtin.get_system_module_members(tpe.pkgpath) - if name not in members: - self.raise_err( - [t], - kcl_error.ErrType.AttributeError_TYPE, - f"module '{tpe.pkgpath}' has no attribute '{name}'", - ) - tpe = ( - MODULE_SCOPE_MAPPING[tpe.pkgpath].elems[name].type - if ( - tpe.pkgpath in MODULE_SCOPE_MAPPING - and name in MODULE_SCOPE_MAPPING[tpe.pkgpath].elems - ) - else ANY_TYPE - ) - else: - tpe = ANY_TYPE - elif ( - t.ctx == ast.ExprContext.STORE or t.ctx == ast.ExprContext.AUGSTORE - ): - self.check_attr( - t, - tpe, - name, - [self.check_defined], - ) - tpe = self.load_attr_type(t, tpe, name) - else: - tpe = self.load_attr_type(t, tpe, name) - - return tpe - - def walk_NumberLit(self, t: ast.AST): - if t.binary_suffix: - value = units.cal_num(t.value, t.binary_suffix) - return objpkg.KCLNumberMultiplierTypeObject( - value=value, - raw_value=t.value, - binary_suffix=t.binary_suffix, - ) - return ( - objpkg.KCLIntLitTypeObject(t.value) - if isinstance(t.value, int) - else objpkg.KCLFloatLitTypeObject(t.value) - ) - - def walk_StringLit(self, t: ast.StringLit): - return objpkg.KCLStringLitTypeObject(t.value) - - def walk_NameConstantLit(self, t: ast.NameConstantLit): - if t.value is None or isinstance(t.value, internal.UndefinedType): - return NONE_TYPE - return TRUE_LIT_TYPE if t.value is True else FALSE_LIT_TYPE - - def walk_FormattedValue(self, t: ast.FormattedValue): - if ( - t.format_spec - and isinstance(t.format_spec, str) - and t.format_spec.lower() not in VALID_FORMAT_SPEC_SET - ): - self.raise_err([t], msg=f"{t.format_spec} is a invalid format spec") - return self.expr(t.value) - - def walk_JoinedString(self, t: ast.JoinedString): - self.exprs(t.values) - return STR_TYPE - - def walk_TypeAliasStmt(self, t: ast.TypeAliasStmt): - """ast.AST: TypeAliasStmt - - Parameters - ---------- - - type_name: Identifier - - type_value: Type - """ - tpe = self.parse_type_str_with_scope(t.type_value.plain_type_str, t.type_value) - if isinstance(tpe, objpkg.KCLSchemaTypeObject): - tpe = objpkg.KCLSchemaDefTypeObject(schema_type=tpe) - tpe.is_type_alias = True - name = t.type_name.get_name() - if name in RESERVED_TYPE_IDENTIFIERS: - self.raise_err( - [t], - kcl_error.ErrType.IllegalInheritError_TYPE, - "type alias '{}' cannot be the same as the built-in types ({})".format( - name, ", ".join(RESERVED_TYPE_IDENTIFIERS) - ), - ) - self.scope.elems[name] = ScopeObject( - name=name, - node=t, - type=tpe, - pos=ast.Position( - filename=self.filename, - line=t.line, - column=t.column, - ), - end=ast.Position( - filename=self.filename, - line=t.end_line, - column=t.end_column, - ), - ) - return tpe - - def walk_UnificationStmt(self, t: ast.UnificationStmt): - if len(t.target.names) > 1: - self.raise_err([t.target], msg="unification identifier can not be selected") - name = t.target.names[0] - tpe = self.expr(t.target) - value_tpe = self.expr(t.value) - self.must_assignable_to(t.target, value_tpe, tpe) - if value_tpe != ANY_TYPE and tpe == ANY_TYPE: - self.set_type_to_scope(name, value_tpe, t.target) - return value_tpe - - def walk_AssignStmt(self, t: ast.AssignStmt): - """id: T = E""" - self._local_vars = [] - for target in t.targets: - name = target.names[0] - if len(target.names) == 1: - tpe = self.expr(target) - if isinstance(tpe, objpkg.KCLSchemaTypeObject): - init_stack_depth = self.switch_config_expr_context( - self.new_config_expr_context_item( - name=tpe.name, type_obj=tpe, node=t - ) - ) - value_tpe = self.expr(t.value) - self.clear_config_expr_context(stack_depth=init_stack_depth) - else: - value_tpe = self.expr(t.value) - self.must_assignable_to(target, value_tpe, tpe) - if value_tpe != ANY_TYPE and tpe == ANY_TYPE and not t.type_annotation: - self.set_type_to_scope(name, value_tpe, target) - if self.in_schema_type: - # Set attr type if in schema - tpe = self.in_schema_type.set_type_of_attr( - name, infer_to_variable_type(value_tpe) - ) - else: - self.lookup_type_from_scope(name, target) - tpe = self.expr(target) - value_tpe = self.expr(t.value) - self.must_assignable_to(target, value_tpe, tpe) - return value_tpe - - def walk_AugAssignStmt(self, t: ast.AugAssignStmt): - t.target.ctx = ast.ExprContext.LOAD - new_target_type = binary( - self.expr(t.target), self.expr(t.value), t.op, self.filename, t.line - ) - t.target.ctx = ast.ExprContext.STORE - expected_type = self.expr(t.target) - self.must_assignable_to(t.target, new_target_type, expected_type) - return new_target_type - - def walk_ListIfItemExpr(self, t: ast.ListIfItemExpr): - self.expr_or_any_type(t.if_cond) - or_else_type = self.expr_or_any_type(t.orelse) - exprs_type = sup(self.exprs(t.exprs)) - return sup([or_else_type, exprs_type]) - - def walk_ConfigIfEntryExpr(self, t: ast.ConfigIfEntryExpr): - self.expr_or_any_type(t.if_cond) - key_types, value_types = [], [] - for key, value in zip(t.keys, t.values): - stack_depth = 0 - self.check_config_entry(key, value, [self.check_defined]) - stack_depth += self.switch_config_expr_context_by_key(key) - if not key: - key_type = ANY_TYPE - value_type = self.expr(value) - if value_type == ANY_TYPE or value_type == NONE_TYPE: - value_types.append(value_type) - elif isinstance( - value_type, (objpkg.KCLDictTypeObject, objpkg.KCLSchemaTypeObject) - ): - key_type = value_type.key_type - value_type = value_type.value_type - elif is_kind_type_or_kind_union_type( - value_type, - [objpkg.KCLTypeKind.DictKind, objpkg.KCLTypeKind.SchemaKind], - ): - key_type = sup([tpe.key_type for tpe in value_type.types]) - value_type = sup([tpe.value_type for tpe in value_type.types]) - else: - self.raise_err( - nodes=[value], - msg=f"only dict and schema can be used ** unpack, got '{value_type.type_str()}'", - ) - elif isinstance(key, ast.Identifier): - key_type = STR_TYPE - value_type = self.expr(value) - for _ in range(len(key.names) - 1): - value_type = objpkg.KCLDictTypeObject( - key_type=STR_TYPE, value_type=value_type - ) - else: - key_type = self.expr(key) - value_type = self.expr(value) - key_types.append(key_type) - value_types.append(value_type) - self.clear_config_expr_context(stack_depth=stack_depth) - dict_type = objpkg.KCLDictTypeObject( - key_type=sup(key_types), - value_type=sup(value_types), - ) - or_else_type = self.expr_or_any_type(t.orelse) - return sup([dict_type, or_else_type]) - - -def ResolveProgramImport(prog: ast.Program): - """Check import error""" - if not prog or not isinstance(prog, ast.Program): - return - root = prog.root - main_files = [module.filename for module in prog.pkgs[ast.Program.MAIN_PKGPATH]] - for pkgpath in prog.pkgs or []: - for m in prog.pkgs[pkgpath]: - for import_spec in m.GetImportList(): - pkgpath = import_spec.path - if pkgpath in builtin.STANDARD_SYSTEM_MODULES: - continue - - if pkgpath.startswith(plugin.PLUGIN_MODULE_NAME): - plugin_name = pkgpath.replace(plugin.PLUGIN_MODULE_NAME, "") - if plugin_name not in plugin.get_plugin_names(): - kcl_error.report_exception( - err_type=kcl_error.ErrType.CannotFindModule_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=import_spec.filename or m.filename, - line_no=import_spec.line, - col_no=import_spec.column, - end_col_no=import_spec.end_column, - ) - ], - arg_msg=kcl_error.CANNOT_FIND_MODULE_MSG.format( - import_spec.rawpath, plugin.get_plugin_root(plugin_name) - ), - ) - continue - - if pkgpath not in prog.pkgs: - kcl_error.report_exception( - err_type=kcl_error.ErrType.CannotFindModule_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=import_spec.filename or m.filename, - line_no=import_spec.line, - col_no=import_spec.column, - end_col_no=import_spec.end_column, - ) - ], - arg_msg=kcl_error.CANNOT_FIND_MODULE_MSG.format( - import_spec.rawpath, - str(pathlib.Path(prog.root) / (pkgpath.replace(".", "/"))), - ), - ) - - if os.path.isfile(f"{root}/{pkgpath.replace('.', '/')}.k"): - file = f"{root}/{pkgpath.replace('.', '/')}.k" - if file in main_files or []: - kcl_error.report_exception( - file_msgs=[ - kcl_error.ErrFileMsg( - filename=import_spec.filename, - line_no=import_spec.line, - col_no=import_spec.column, - ) - ], - err_type=kcl_error.ErrType.CompileError_TYPE, - arg_msg=f"Cannot import {file} in the main package", - ) - - -def ResolveProgram( - program: ast.Program, config: CheckConfig = CheckConfig() -) -> ProgramScope: - """Resolve program including the import check and the type check""" - ResolveProgramImport(program) - return TypeChecker(program, config).check() diff --git a/internal/kclvm_py/kcl/types/scope.py b/internal/kclvm_py/kcl/types/scope.py deleted file mode 100644 index 1d3ab97ae..000000000 --- a/internal/kclvm_py/kcl/types/scope.py +++ /dev/null @@ -1,1203 +0,0 @@ -# Copyright 2020 The KCL Authors. All rights reserved. - -from typing import List, Dict, Optional, cast -from dataclasses import dataclass, field - -import kclvm.kcl.ast as ast -import kclvm.api.object as objpkg -import kclvm.api.object.internal as internal -import kclvm.compiler.extension.builtin.builtin as builtin -import kclvm.compiler.extension.plugin as plugin - -from .type import ( - Type, - ANY_TYPE, - STR_TYPE, - BOOL_TYPE, - INT_TYPE, - FLOAT_TYPE, - LIST_ANY_TYPE, - LIST_STR_TYPE, - DICT_ANY_ANY_TYPE, - ITERABLE_TYPE_STR, - ITERABLE_TYPE, - NUMBER_TYPE_STR, - NUMBER_TYPE, -) - - -@dataclass -class ScopeObject: - """The object stored in the scope - - Parameters - ---------- - name: str - The scope object name. - node: ast.AST - The scope object AST node reference. - type: Type - The type of the scope object. - pos: ast.Position - The scope object start position. - end: ast.Position - The scope object end position. - """ - - name: str - node: Optional[ast.AST] - type: Type - pos: ast.Position = None - end: ast.Position = None - - def check_pos_valid(self): - return ( - self.node - and self.node.pos - and self.node.pos.is_valid() - and self.node.end_pos - and self.node.end_pos.is_valid() - ) - - -@dataclass -class Scope: - """A Scope maintains a set of objects and links to its containing - (parent) and contained (children) scopes. Objects may be inserted - and looked up by name. The zero value for Scope is a ready-to-use - empty scope. - - Parameters - ---------- - parent: Scope - The parent scope. - node: ast.AST - The scope AST node reference. - children: Type: - The child scope list. - elems: Dict[str, ScopeObject] - The scope object mapping with its name. - pos: ast.Position - The scope start position. - end: ast.Position - The scope end position. - """ - - parent: "Scope" = None - node: ast.AST = None - children: List["Scope"] = field(default_factory=list) - elems: Dict[str, ScopeObject] = field(default_factory=dict) - pos: ast.Position = None - end: ast.Position = None - - def contains_pos(self, pos: ast.Position) -> bool: - """ - check if current scope contains a position - :param pos: the given position - :return: if current scope contains the given position - """ - if isinstance(self.node, ast.SchemaStmt): - for item in [ - *(self.node.body if self.node.body else []), - *(self.node.checks if self.node.checks else []), - self.node.index_signature, - ]: - if item and item.contains_pos(pos): - return True - return False - elif isinstance(self.node, ast.RuleStmt): - for item in self.node.checks or []: - if item and item.contains_pos(pos): - return True - return False - return self.pos and self.pos.less_equal(pos) and pos.less_equal(self.end) - - def inner_most(self, pos: ast.Position) -> Optional["Scope"]: - # self is BUILTIN_SCOPE - if self.parent is None: - for child in self.children or []: - if child.contains_pos(pos): - return child.inner_most(pos) - return None - # self is not BUILTIN_SCOPE - if self.contains_pos(pos): - for child in self.children or []: - if child.contains_pos(pos): - return child.inner_most(pos) - return self - return None - - def get_enclosing_scope(self) -> Optional["Scope"]: - return self.parent - - def get_parent_schema_scope( - self, program_scope: "ProgramScope" - ) -> Optional["Scope"]: - if ( - self.node - and isinstance(self.node, ast.SchemaStmt) - and self.node.parent_name - ): - schema = self.parent.elems[self.node.name] - if not isinstance(schema.type, objpkg.KCLSchemaDefTypeObject): - return None - schema_type_def_obj = cast(objpkg.KCLSchemaDefTypeObject, schema.type) - if ( - not schema_type_def_obj.schema_type - or not schema_type_def_obj.schema_type.base - ): - return None - base_type_obj = schema_type_def_obj.schema_type.base - # the schema and its base schema are in the same scope - if schema_type_def_obj.schema_type.pkgpath == base_type_obj.pkgpath: - return self.parent.search_child_scope_by_name(base_type_obj.name) - # the schema and its base schema are in the different scopes - base_pkg_scope = program_scope.scope_map.get(base_type_obj.pkgpath) - if not base_pkg_scope: - return None - return base_pkg_scope.search_child_scope_by_name(base_type_obj.name) - return None - - def search_child_scope_by_name(self, name: str) -> Optional["Scope"]: - assert name - if name not in self.elems: - return None - elem: ScopeObject = self.elems[name] - for child in self.children: - if child.node == elem.node: - return child - return None - - -@dataclass -class PackageScope(Scope): - file_begin_position_map: Dict[str, ast.Position] = field(default_factory=dict) - file_end_position_map: Dict[str, ast.Position] = field(default_factory=dict) - - def contains_pos(self, pos: ast.Position) -> bool: - """ - check if current package scope contains a position - :param pos: the given position - :return: if current package scope contains the given position - """ - assert pos.filename - file_begin_pos = self.file_begin_position_map.get(pos.filename) - file_end_pos = self.file_end_position_map.get(pos.filename) - return ( - file_begin_pos - and file_end_pos - and pos - and file_begin_pos.less_equal(pos) - and pos.less_equal(file_end_pos) - ) - - -# Decorator scope including decorator function type such as `deprecated`. -DECORATOR_SCOPE: Scope = Scope( - elems={ - internal.Deprecated.NAME: ScopeObject( - name=internal.Deprecated.NAME, - node=None, - type=objpkg.KCLFunctionTypeObject( - name=internal.Deprecated.NAME, - params=[ - objpkg.Parameter( - name="version", - type_annotation="str", - type=STR_TYPE, - ), - objpkg.Parameter( - name="reason", - type_annotation="str", - type=STR_TYPE, - ), - objpkg.Parameter( - name="strict", - type_annotation="bool", - type=BOOL_TYPE, - ), - ], - self_type=ANY_TYPE, - return_type=ANY_TYPE, - doc=internal.Deprecated.__doc__, - ), - ), - internal.Info.NAME: ScopeObject( - name=internal.Info.NAME, - node=None, - type=objpkg.KCLFunctionTypeObject( - name=internal.Info.NAME, - params=[], - self_type=ANY_TYPE, - return_type=ANY_TYPE, - doc=internal.Info.__doc__, - ), - ), - } -) - - -# Builtin-function types table -BUILTIN_SCOPE: Scope = Scope( - elems={ - # option(key: str, *, type: str = "", required: bool = False, default: any = None, help: str = "", file: str = "", line: int = 0) -> any - "option": ScopeObject( - name="option", - node=None, - type=objpkg.KCLFunctionTypeObject( - name="option", - params=[ - objpkg.Parameter( - name="key", - value=None, - type_annotation="str", - type=STR_TYPE, - ), - objpkg.Parameter( - name="type", - value=objpkg.KCLStringObject(""), - type_annotation="str", - type=STR_TYPE, - ), - objpkg.Parameter( - name="required", - value=objpkg.KCLFalseObject.instance(), - type_annotation="bool", - type=BOOL_TYPE, - ), - objpkg.Parameter( - name="default", - value=objpkg.KCLNoneObject.instance(), - type_annotation="any", - type=ANY_TYPE, - ), - objpkg.Parameter( - name="help", - value=objpkg.KCLStringObject(""), - type_annotation="str", - type=STR_TYPE, - ), - objpkg.Parameter( - name="help", - value=objpkg.KCLStringObject(""), - type_annotation="str", - type=STR_TYPE, - ), - objpkg.Parameter( - name="file", - value=objpkg.KCLStringObject(""), - type_annotation="str", - type=STR_TYPE, - ), - objpkg.Parameter( - name="line", - value=objpkg.KCLIntObject(0), - type_annotation="int", - type=INT_TYPE, - ), - ], - self_type=ANY_TYPE, - return_type=ANY_TYPE, - doc=builtin.KMANGLED_option.__doc__, - ), - ), - # print(value, ..., sep=' ', end='\n') -> NONE_TYPE - "print": ScopeObject( - name="print", - node=None, - type=objpkg.KCLFunctionTypeObject( - name="print", - params=[], - self_type=ANY_TYPE, - return_type=ANY_TYPE, - doc=builtin.KMANGLED_print.__doc__, - is_variadic=True, - ), - ), - # multiplyof(a: int, b: int) -> bool - "multiplyof": ScopeObject( - name="multiplyof", - node=None, - type=objpkg.KCLFunctionTypeObject( - name="multiplyof", - params=[ - objpkg.Parameter( - name="a", - value=None, - type_annotation="int", - type=INT_TYPE, - ), - objpkg.Parameter( - name="b", - value=None, - type_annotation="int", - type=INT_TYPE, - ), - ], - self_type=ANY_TYPE, - return_type=INT_TYPE, - doc=builtin.KMANGLED_multiplyof.__doc__, - ), - ), - # isunique(inval: List[Any]) -> bool - "isunique": ScopeObject( - name="isunique", - node=None, - type=objpkg.KCLFunctionTypeObject( - name="isunique", - params=[ - objpkg.Parameter( - name="inval", - value=None, - type_annotation="[]", - type=LIST_ANY_TYPE, - ), - ], - self_type=ANY_TYPE, - return_type=BOOL_TYPE, - doc=builtin.KMANGLED_isunique.__doc__, - ), - ), - # len(inval: Union[dict, list, schema, str]) -> int - "len": ScopeObject( - name="len", - node=None, - type=objpkg.KCLFunctionTypeObject( - name="len", - params=[ - objpkg.Parameter( - name="inval", - value=None, - type_annotation=ITERABLE_TYPE_STR, - type=ITERABLE_TYPE, - ), - ], - self_type=ANY_TYPE, - return_type=INT_TYPE, - doc=builtin.KMANGLED_len.__doc__, - ), - ), - # abs(inval: Union[int, float, bool]) -> Union[int, float, bool] - "abs": ScopeObject( - name="abs", - node=None, - type=objpkg.KCLFunctionTypeObject( - name="abs", - params=[ - objpkg.Parameter( - name="inval", - value=None, - type_annotation="any", - type=ANY_TYPE, - ), - ], - self_type=ANY_TYPE, - return_type=ANY_TYPE, - doc=builtin.KMANGLED_abs.__doc__, - ), - ), - # all_true(inval: Union[dict, list, schema, str]) -> bool - "all_true": ScopeObject( - name="all_true", - node=None, - type=objpkg.KCLFunctionTypeObject( - name="all_true", - params=[ - objpkg.Parameter( - name="inval", - value=None, - type_annotation="[]", - type=LIST_ANY_TYPE, - ), - ], - self_type=ANY_TYPE, - return_type=BOOL_TYPE, - doc=builtin.KMANGLED_all_true.__doc__, - ), - ), - # any_true(inval: Union[dict, list, schema, str]) -> bool - "any_true": ScopeObject( - name="any_true", - node=None, - type=objpkg.KCLFunctionTypeObject( - name="any_true", - params=[ - objpkg.Parameter( - name="inval", - value=None, - type_annotation="[]", - type=LIST_ANY_TYPE, - ), - ], - self_type=ANY_TYPE, - return_type=BOOL_TYPE, - doc=builtin.KMANGLED_any_true.__doc__, - ), - ), - # hex(number: int) -> str - "hex": ScopeObject( - name="hex", - node=None, - type=objpkg.KCLFunctionTypeObject( - name="hex", - params=[ - objpkg.Parameter( - name="number", - value=None, - type_annotation="int", - type=INT_TYPE, - ), - ], - self_type=ANY_TYPE, - return_type=STR_TYPE, - doc=builtin.KMANGLED_hex.__doc__, - ), - ), - # bin(number: int) -> str - "bin": ScopeObject( - name="bin", - node=None, - type=objpkg.KCLFunctionTypeObject( - name="bin", - params=[ - objpkg.Parameter( - name="number", - value=None, - type_annotation="int", - type=INT_TYPE, - ), - ], - self_type=ANY_TYPE, - return_type=STR_TYPE, - doc=builtin.KMANGLED_bin.__doc__, - ), - ), - # oct(number: int) -> str - "oct": ScopeObject( - name="oct", - node=None, - type=objpkg.KCLFunctionTypeObject( - name="oct", - params=[ - objpkg.Parameter( - name="number", - value=None, - type_annotation="int", - type=INT_TYPE, - ), - ], - self_type=ANY_TYPE, - return_type=STR_TYPE, - doc=builtin.KMANGLED_oct.__doc__, - ), - ), - # ord(c: str) -> int - "ord": ScopeObject( - name="ord", - node=None, - type=objpkg.KCLFunctionTypeObject( - name="ord", - params=[ - objpkg.Parameter( - name="number", - value=None, - type_annotation="int", - type=STR_TYPE, - ), - ], - self_type=ANY_TYPE, - return_type=INT_TYPE, - doc=builtin.KMANGLED_ord.__doc__, - ), - ), - # sorted(inval: Union[dict, list, schema, str]) -> List[Any] - "sorted": ScopeObject( - name="sorted", - node=None, - type=objpkg.KCLFunctionTypeObject( - name="sorted", - params=[ - objpkg.Parameter( - name="inval", - value=None, - type_annotation=ITERABLE_TYPE_STR, - type=ITERABLE_TYPE, - ), - objpkg.Parameter( - name="reverse", - value=objpkg.KCLFalseObject.instance(), - type_annotation="bool", - type=BOOL_TYPE, - ), - ], - self_type=ANY_TYPE, - return_type=LIST_ANY_TYPE, - doc=builtin.KMANGLED_sorted.__doc__, - ), - ), - # range(start: int, stop: int, step: int = None) -> list - "range": ScopeObject( - name="range", - node=None, - type=objpkg.KCLFunctionTypeObject( - name="range", - params=[ - objpkg.Parameter( - name="start", - value=None, - type_annotation="int", - type=INT_TYPE, - ), - objpkg.Parameter( - name="stop", - value=None, - type_annotation="int", - type=INT_TYPE, - ), - objpkg.Parameter( - name="step", - value=objpkg.KCLNoneObject.instance(), - type_annotation="int", - type=INT_TYPE, - ), - ], - self_type=ANY_TYPE, - return_type=objpkg.KCLListTypeObject(item_type=INT_TYPE), - doc=builtin.KMANGLED_range.__doc__, - ), - ), - # max(iterable: List[Any]) -> Any - "max": ScopeObject( - name="max", - node=None, - type=objpkg.KCLFunctionTypeObject( - name="max", - params=[], - self_type=ANY_TYPE, - return_type=ANY_TYPE, - doc=builtin.KMANGLED_max.__doc__, - ), - ), - # min(iterable: List[Any]) -> Any - "min": ScopeObject( - name="min", - node=None, - type=objpkg.KCLFunctionTypeObject( - name="min", - params=[], - self_type=ANY_TYPE, - return_type=ANY_TYPE, - doc=builtin.KMANGLED_min.__doc__, - ), - ), - # sum(iterable: List[Any], start: Any = 0) -> Any - "sum": ScopeObject( - name="sum", - node=None, - type=objpkg.KCLFunctionTypeObject( - name="sum", - params=[ - objpkg.Parameter( - name="iterable", - value=None, - type_annotation="[]", - type=LIST_ANY_TYPE, - ), - objpkg.Parameter( - name="start", - value=objpkg.KCLIntObject(0), - type_annotation="any", - type=ANY_TYPE, - ), - ], - self_type=ANY_TYPE, - return_type=ANY_TYPE, - doc=builtin.KMANGLED_sum.__doc__, - ), - ), - # pow(x: number, y: number, z: number) -> number - "pow": ScopeObject( - name="pow", - node=None, - type=objpkg.KCLFunctionTypeObject( - name="pow", - params=[ - objpkg.Parameter( - name="x", - value=None, - type_annotation=NUMBER_TYPE_STR, - type=NUMBER_TYPE, - ), - objpkg.Parameter( - name="y", - value=None, - type_annotation=NUMBER_TYPE_STR, - type=NUMBER_TYPE, - ), - objpkg.Parameter( - name="z", - value=None, - type_annotation=NUMBER_TYPE_STR, - type=NUMBER_TYPE, - ), - ], - self_type=ANY_TYPE, - return_type=NUMBER_TYPE, - doc=builtin.KMANGLED_pow.__doc__, - ), - ), - # round(number: number, ndigits: int) -> number - "round": ScopeObject( - name="round", - node=None, - type=objpkg.KCLFunctionTypeObject( - name="round", - params=[ - objpkg.Parameter( - name="number", - value=None, - type_annotation=NUMBER_TYPE_STR, - type=NUMBER_TYPE, - ), - objpkg.Parameter( - name="ndigits", - value=objpkg.KCLNoneObject.instance(), - type_annotation="int", - type=INT_TYPE, - ), - ], - self_type=ANY_TYPE, - return_type=NUMBER_TYPE, - doc=builtin.KMANGLED_round.__doc__, - ), - ), - # zip(*args) -> List[Any] - "zip": ScopeObject( - name="zip", - node=None, - type=objpkg.KCLFunctionTypeObject( - name="zip", - params=[], - self_type=ANY_TYPE, - return_type=LIST_ANY_TYPE, - doc=builtin.KMANGLED_zip.__doc__, - is_variadic=True, - ), - ), - # int(number: number|str) -> int - "int": ScopeObject( - name="int", - node=None, - type=objpkg.KCLFunctionTypeObject( - name="int", - params=[ - objpkg.Parameter( - name="number", - value=None, - type_annotation="any", - type=ANY_TYPE, - ), - objpkg.Parameter( - name="base", - value=objpkg.KCLIntObject(10), - type_annotation="int", - type=ANY_TYPE, - ), - ], - self_type=ANY_TYPE, - return_type=INT_TYPE, - doc=builtin.KMANGLED_int.__doc__, - ), - ), - # float(number: number|str) -> float - "float": ScopeObject( - name="float", - node=None, - type=objpkg.KCLFunctionTypeObject( - name="float", - params=[ - objpkg.Parameter( - name="number", - value=None, - type_annotation="any", - type=ANY_TYPE, - ) - ], - self_type=ANY_TYPE, - return_type=FLOAT_TYPE, - doc=builtin.KMANGLED_float.__doc__, - ), - ), - # list(x: any) -> [] - "list": ScopeObject( - name="list", - node=None, - type=objpkg.KCLFunctionTypeObject( - name="list", - params=[ - objpkg.Parameter( - name="x", - value=None, - type_annotation="any", - type=ANY_TYPE, - ) - ], - self_type=ANY_TYPE, - return_type=LIST_ANY_TYPE, - doc=builtin.KMANGLED_list.__doc__, - ), - ), - # dict(x: any) -> {:} - "dict": ScopeObject( - name="dict", - node=None, - type=objpkg.KCLFunctionTypeObject( - name="dict", - params=[ - objpkg.Parameter( - name="x", - value=None, - type_annotation="any", - type=ANY_TYPE, - ) - ], - self_type=ANY_TYPE, - return_type=DICT_ANY_ANY_TYPE, - doc=builtin.KMANGLED_dict.__doc__, - ), - ), - # bool(x: any) -> bool - "bool": ScopeObject( - name="bool", - node=None, - type=objpkg.KCLFunctionTypeObject( - name="bool", - params=[ - objpkg.Parameter( - name="x", - value=None, - type_annotation="any", - type=ANY_TYPE, - ) - ], - self_type=ANY_TYPE, - return_type=BOOL_TYPE, - doc=builtin.KMANGLED_bool.__doc__, - ), - ), - # str(obj: any) -> str - "str": ScopeObject( - name="str", - node=None, - type=objpkg.KCLFunctionTypeObject( - name="str", - params=[ - objpkg.Parameter( - name="x", - value=None, - type_annotation="any", - type=ANY_TYPE, - ) - ], - self_type=ANY_TYPE, - return_type=STR_TYPE, - doc=builtin.KMANGLED_str.__doc__, - ), - ), - # typeof(x: any, *, full_name: bool = False) -> str: - "typeof": ScopeObject( - name="typeof", - node=None, - type=objpkg.KCLFunctionTypeObject( - name="typeof", - params=[ - objpkg.Parameter( - name="x", - value=None, - type_annotation="any", - type=ANY_TYPE, - ), - objpkg.Parameter( - name="full_name", - value=objpkg.KCLFalseObject.instance(), - type_annotation="bool", - type=BOOL_TYPE, - ), - ], - self_type=ANY_TYPE, - return_type=STR_TYPE, - doc=builtin.KMANGLED_typeof.__doc__, - ), - ), - } -) - -# System module types table -MODULE_SCOPE_MAPPING: Dict[str, Scope] = { - **{name: Scope(elems={}) for name in builtin.STANDARD_SYSTEM_MODULES}, - **{ - "units": Scope( - elems={ - "NumberMultiplier": ScopeObject( - name="NumberMultiplier", - node=None, - type=objpkg.KCLNumberMultiplierTypeObject(), - ), - } - ), - }, -} - -try: - # Plugin module types table - PLUGIN_SCOPE_MAPPING: Dict[str, Scope] = { - "{}".format(plugin.PLUGIN_MODULE_NAME + name): Scope(elems={}) - for name in plugin.get_plugin_names() - } -except Exception: - PLUGIN_SCOPE_MAPPING: Dict[str, Scope] = {} - - -# Member function or property types table e.g., str.replace and schema.instances -SCHEMA_TYPE_MEMBER_SCOPE: Scope = Scope( - elems={ - "instances": ScopeObject( - name=objpkg.KCLSchemaTypeObject.instances.__name__, - node=None, - type=objpkg.KCLFunctionTypeObject( - name=objpkg.KCLSchemaTypeObject.instances.__name__, - params=[], - self_type=DICT_ANY_ANY_TYPE, - return_type=LIST_ANY_TYPE, - doc=objpkg.KCLSchemaTypeObject.instances.__doc__, - ), - ) - } -) - -STR_TYPE_MEMBER_SCOPE: Scope = Scope( - elems={ - "capitalize": ScopeObject( - name="".capitalize.__name__, - node=None, - type=objpkg.KCLFunctionTypeObject( - name="".capitalize.__name__, - params=[], - self_type=STR_TYPE, - return_type=STR_TYPE, - doc="".capitalize.__doc__, - ), - ), - "count": ScopeObject( - name="".count.__name__, - node=None, - type=objpkg.KCLFunctionTypeObject( - name="".count.__name__, - params=[], - self_type=STR_TYPE, - return_type=INT_TYPE, - doc="".count.__doc__, - ), - ), - "endswith": ScopeObject( - name="".endswith.__name__, - node=None, - type=objpkg.KCLFunctionTypeObject( - name="".endswith.__name__, - params=[], - self_type=STR_TYPE, - return_type=BOOL_TYPE, - doc="".endswith.__doc__, - ), - ), - "find": ScopeObject( - name="".find.__name__, - node=None, - type=objpkg.KCLFunctionTypeObject( - name="".find.__name__, - params=[], - self_type=STR_TYPE, - return_type=INT_TYPE, - doc="".find.__doc__, - ), - ), - "format": ScopeObject( - name="".format.__name__, - node=None, - type=objpkg.KCLFunctionTypeObject( - name="".format.__name__, - params=[], - self_type=STR_TYPE, - return_type=STR_TYPE, - doc="".format.__doc__, - ), - ), - "index": ScopeObject( - name="".index.__name__, - node=None, - type=objpkg.KCLFunctionTypeObject( - name="".index.__name__, - params=[], - self_type=STR_TYPE, - return_type=INT_TYPE, - doc="".index.__doc__, - ), - ), - "isalnum": ScopeObject( - name="".isalnum.__name__, - node=None, - type=objpkg.KCLFunctionTypeObject( - name="".isalnum.__name__, - params=[], - self_type=STR_TYPE, - return_type=BOOL_TYPE, - doc="".isalnum.__doc__, - ), - ), - "isalpha": ScopeObject( - name="".isalpha.__name__, - node=None, - type=objpkg.KCLFunctionTypeObject( - name="".isalpha.__name__, - params=[], - self_type=STR_TYPE, - return_type=BOOL_TYPE, - doc="".isalpha.__doc__, - ), - ), - "isdigit": ScopeObject( - name="".isdigit.__name__, - node=None, - type=objpkg.KCLFunctionTypeObject( - name="".isdigit.__name__, - params=[], - self_type=STR_TYPE, - return_type=BOOL_TYPE, - doc="".isdigit.__doc__, - ), - ), - "islower": ScopeObject( - name="".islower.__name__, - node=None, - type=objpkg.KCLFunctionTypeObject( - name="".islower.__name__, - params=[], - self_type=STR_TYPE, - return_type=BOOL_TYPE, - doc="".islower.__doc__, - ), - ), - "isspace": ScopeObject( - name="".isspace.__name__, - node=None, - type=objpkg.KCLFunctionTypeObject( - name="".isspace.__name__, - params=[], - self_type=STR_TYPE, - return_type=BOOL_TYPE, - doc="".isspace.__doc__, - ), - ), - "istitle": ScopeObject( - name="".istitle.__name__, - node=None, - type=objpkg.KCLFunctionTypeObject( - name="".istitle.__name__, - params=[], - self_type=STR_TYPE, - return_type=BOOL_TYPE, - doc="".istitle.__doc__, - ), - ), - "isupper": ScopeObject( - name="".isupper.__name__, - node=None, - type=objpkg.KCLFunctionTypeObject( - name="".isupper.__name__, - params=[], - self_type=STR_TYPE, - return_type=BOOL_TYPE, - doc="".isupper.__doc__, - ), - ), - "join": ScopeObject( - name="".join.__name__, - node=None, - type=objpkg.KCLFunctionTypeObject( - name="".join.__name__, - params=[], - self_type=STR_TYPE, - return_type=STR_TYPE, - doc="".join.__doc__, - ), - ), - "lower": ScopeObject( - name="".lower.__name__, - node=None, - type=objpkg.KCLFunctionTypeObject( - name="".lower.__name__, - params=[], - self_type=STR_TYPE, - return_type=STR_TYPE, - doc="".lower.__doc__, - ), - ), - "upper": ScopeObject( - name="".upper.__name__, - node=None, - type=objpkg.KCLFunctionTypeObject( - name="".upper.__name__, - params=[], - self_type=STR_TYPE, - return_type=STR_TYPE, - doc="".upper.__doc__, - ), - ), - "lstrip": ScopeObject( - name="".lstrip.__name__, - node=None, - type=objpkg.KCLFunctionTypeObject( - name="".lstrip.__name__, - params=[], - self_type=STR_TYPE, - return_type=STR_TYPE, - doc="".lstrip.__doc__, - ), - ), - "rstrip": ScopeObject( - name="".rstrip.__name__, - node=None, - type=objpkg.KCLFunctionTypeObject( - name="".rstrip.__name__, - params=[], - self_type=STR_TYPE, - return_type=STR_TYPE, - doc="".rstrip.__doc__, - ), - ), - "replace": ScopeObject( - name="".replace.__name__, - node=None, - type=objpkg.KCLFunctionTypeObject( - name="".replace.__name__, - params=[], - self_type=STR_TYPE, - return_type=STR_TYPE, - doc="".replace.__doc__, - ), - ), - "rfind": ScopeObject( - name="".rfind.__name__, - node=None, - type=objpkg.KCLFunctionTypeObject( - name="".rfind.__name__, - params=[], - self_type=STR_TYPE, - return_type=INT_TYPE, - doc="".rfind.__doc__, - ), - ), - "rindex": ScopeObject( - name="".rindex.__name__, - node=None, - type=objpkg.KCLFunctionTypeObject( - name="".rindex.__name__, - params=[], - self_type=STR_TYPE, - return_type=INT_TYPE, - doc="".rindex.__doc__, - ), - ), - "rsplit": ScopeObject( - name="".rsplit.__name__, - node=None, - type=objpkg.KCLFunctionTypeObject( - name="".rsplit.__name__, - params=[], - self_type=STR_TYPE, - return_type=LIST_STR_TYPE, - doc="".rsplit.__doc__, - ), - ), - "split": ScopeObject( - name="".split.__name__, - node=None, - type=objpkg.KCLFunctionTypeObject( - name="".split.__name__, - params=[], - self_type=STR_TYPE, - return_type=LIST_STR_TYPE, - doc="".split.__doc__, - ), - ), - "splitlines": ScopeObject( - name="".splitlines.__name__, - node=None, - type=objpkg.KCLFunctionTypeObject( - name="".splitlines.__name__, - params=[], - self_type=STR_TYPE, - return_type=LIST_STR_TYPE, - doc="".splitlines.__doc__, - ), - ), - "startswith": ScopeObject( - name="".startswith.__name__, - node=None, - type=objpkg.KCLFunctionTypeObject( - name="".startswith.__name__, - params=[], - self_type=STR_TYPE, - return_type=BOOL_TYPE, - doc="".startswith.__doc__, - ), - ), - "strip": ScopeObject( - name="".strip.__name__, - node=None, - type=objpkg.KCLFunctionTypeObject( - name="".strip.__name__, - params=[], - self_type=STR_TYPE, - return_type=STR_TYPE, - doc="".strip.__doc__, - ), - ), - "title": ScopeObject( - name="".title.__name__, - node=None, - type=objpkg.KCLFunctionTypeObject( - name="".title.__name__, - params=[], - self_type=STR_TYPE, - return_type=STR_TYPE, - doc="".title.__doc__, - ), - ), - } -) - - -@dataclass -class ProgramScope: - scope_map: Dict[str, Scope] - builtin_scope: Scope = BUILTIN_SCOPE - plugin_scope_map: Scope = field(default_factory=lambda: PLUGIN_SCOPE_MAPPING) - system_module_scope_map: Dict[str, Scope] = field( - default_factory=lambda: MODULE_SCOPE_MAPPING - ) - member_scope_map: Dict[str, Scope] = field( - default_factory=lambda: { - objpkg.KCLTypeKind.StrKind: SCHEMA_TYPE_MEMBER_SCOPE, - objpkg.KCLTypeKind.SchemaKind: STR_TYPE_MEMBER_SCOPE, - } - ) - schema_reference: objpkg.SchemaTypeRefGraph = None - - @property - def main_scope(self) -> Scope: - return self.scope_map[ast.Program.MAIN_PKGPATH] - - @property - def pkgpaths(self) -> List[str]: - return list(self.scope_map.keys()) diff --git a/internal/kclvm_py/kcl/types/type.py b/internal/kclvm_py/kcl/types/type.py deleted file mode 100644 index 3eab448ac..000000000 --- a/internal/kclvm_py/kcl/types/type.py +++ /dev/null @@ -1,286 +0,0 @@ -# Copyright 2020 The KCL Authors. All rights reserved. - -from typing import cast, List - -import kclvm.api.object as objpkg -import kclvm.unification.subsume as subsume - -# ------------------------------------ -# Type alias -# ------------------------------------ - -Type = objpkg.KCLBaseTypeObject - -# ------------------------------------ -# Type annotation str constants -# ------------------------------------ - -ANY_TYPE_STR = "any" -INT_TYPE_STR = "int" -FLOAT_TYPE_STR = "float" -STR_TYPE_STR = "str" -BOOL_TYPE_STR = "bool" -ITERABLE_TYPE_STR = "str|{:}|[]" -NUMBER_TYPE_STR = "int|float|bool" -NUM_OR_STR_TYPE_STR = "int|float|bool|str" -RESERVED_TYPE_IDENTIFIERS = [ - ANY_TYPE_STR, - INT_TYPE_STR, - FLOAT_TYPE_STR, - STR_TYPE_STR, - BOOL_TYPE_STR, -] - -# ------------------------------------ -# Type constants -# ------------------------------------ - -VOID_TYPE: Type = objpkg.KCLVoidTypeObject() -NONE_TYPE: Type = objpkg.KCLNoneTypeObject() -INT_TYPE: Type = objpkg.KCLIntTypeObject() -FLOAT_TYPE: Type = objpkg.KCLFloatTypeObject() -STR_TYPE: Type = objpkg.KCLStringTypeObject() -BOOL_TYPE: Type = objpkg.KCLBoolTypeObject() -ANY_TYPE: Type = objpkg.KCLAnyTypeObject() -TRUE_LIT_TYPE: Type = objpkg.KCLBoolLitTypeObject(value=True) -FALSE_LIT_TYPE: Type = objpkg.KCLBoolLitTypeObject(value=False) -NUMBER_TYPE: Type = objpkg.KCLUnionTypeObject(types=[INT_TYPE, FLOAT_TYPE, BOOL_TYPE]) -NUM_OR_STR_TYPE: Type = objpkg.KCLUnionTypeObject( - types=[INT_TYPE, FLOAT_TYPE, BOOL_TYPE, STR_TYPE] -) -LIST_ANY_TYPE: Type = objpkg.KCLListTypeObject(item_type=ANY_TYPE) -LIST_STR_TYPE: Type = objpkg.KCLListTypeObject(item_type=STR_TYPE) -DICT_ANY_ANY_TYPE: Type = objpkg.KCLDictTypeObject( - key_type=ANY_TYPE, value_type=ANY_TYPE -) -DICT_STR_ANY_TYPE: Type = objpkg.KCLDictTypeObject( - key_type=STR_TYPE, value_type=ANY_TYPE -) -DICT_STR_STR_TYPE: Type = objpkg.KCLDictTypeObject( - key_type=STR_TYPE, value_type=STR_TYPE -) -INT_OR_STR_TYPE: Type = objpkg.KCLUnionTypeObject(types=[INT_TYPE, STR_TYPE]) -ITERABLE_TYPE: Type = objpkg.KCLUnionTypeObject( - types=[LIST_ANY_TYPE, DICT_ANY_ANY_TYPE, STR_TYPE] -) -LIT_TYPE_KIND_MAPPING = { - objpkg.KCLTypeKind.StrLitKind: STR_TYPE, - objpkg.KCLTypeKind.IntLitKind: INT_TYPE, - objpkg.KCLTypeKind.FloatLitKind: FLOAT_TYPE, - objpkg.KCLTypeKind.BoolLitKind: BOOL_TYPE, -} - -# ------------------------------------ -# Type kind constants -# ------------------------------------ - -NUMBER_TYPE_KINDS = [ - objpkg.KCLTypeKind.IntKind, - objpkg.KCLTypeKind.FloatKind, - objpkg.KCLTypeKind.IntLitKind, - objpkg.KCLTypeKind.FloatLitKind, - # Please note that the True/False name constant can be used to 1 + True - objpkg.KCLTypeKind.BoolKind, - objpkg.KCLTypeKind.BoolLitKind, -] -STR_KINDS = [ - objpkg.KCLTypeKind.StrKind, - objpkg.KCLTypeKind.StrLitKind, -] -INT_KINDS = [ - objpkg.KCLTypeKind.IntKind, - objpkg.KCLTypeKind.IntLitKind, -] -FLOAT_KINDS = [ - objpkg.KCLTypeKind.FloatKind, - objpkg.KCLTypeKind.FloatLitKind, -] -BOOL_KINDS = [ - objpkg.KCLTypeKind.BoolKind, - objpkg.KCLTypeKind.BoolLitKind, -] -ITERABLE_KINDS = [ - objpkg.KCLTypeKind.ListKind, - objpkg.KCLTypeKind.DictKind, - objpkg.KCLTypeKind.SchemaKind, - objpkg.KCLTypeKind.StrKind, - objpkg.KCLTypeKind.StrLitKind, -] -KEY_KINDS = STR_KINDS -BUILTIN_KINDS = NUMBER_TYPE_KINDS + STR_KINDS - -# ----------------------- -# Type functions -# ----------------------- - - -def sup(types: List[Type]) -> Type: - """The sup function returns the minimum supremum of all types in an array of types""" - return typeof(types, should_remove_sub_types=True) - - -def typeof(types: List[Type], should_remove_sub_types: bool = False) -> Type: - """Build a sup type from types [T1, T2, ... , Tn]""" - assert isinstance(types, list) - # 1. Initialize an ordered set to store the type array - type_set = [] - # 2. Add the type array to the ordered set for sorting by the type id and de-duplication - add_types_to_type_set(type_set, types) - # 3. Remove sub types according to partial order relation rules e.g. sub schema types - if should_remove_sub_types: - type_set = remove_sub_types(type_set) - if len(type_set) == 0: - return ANY_TYPE - if len(type_set) == 1: - return type_set[0] - type_set.sort(key=lambda t: t.type_kind()) - return objpkg.KCLUnionTypeObject(types=type_set) - - -def add_types_to_type_set(type_set: List[Type], types: List[Type]): - """Add types into the type set""" - for tpe in types or []: - add_type_to_type_set(type_set, tpe) - - -def add_type_to_type_set(type_set: List[Type], tpe: Type): - """Add a type into the type set""" - if isinstance(tpe, objpkg.KCLUnionTypeObject): - tpe = cast(objpkg.KCLUnionTypeObject, tpe) - add_types_to_type_set(type_set, tpe.types) - # Ignore 'void' types in unions - elif not isinstance(tpe, objpkg.KCLVoidTypeObject): - if tpe not in type_set: - type_set.append(tpe) - - -def remove_sub_types(type_set: List[Type]) -> List[Type]: - """Remove sub types from the type set""" - remove_index_list = set() - for i, source in enumerate(type_set): - for j, target in enumerate(type_set): - if i != j: - is_subsume = subsume.type_subsume(source, target) - if is_subsume: - remove_index_list.add(i) - return [tpe for i, tpe in enumerate(type_set) if i not in remove_index_list] - - -def assignable_to(tpe: Type, expected_type: Type) -> bool: - """Judge type `tpe` can be assigned the expected type""" - if tpe.type_kind() >= objpkg.KCLTypeKind.VoidKind: - return False - if ( - tpe.type_kind() - == expected_type.type_kind() - == objpkg.KCLTypeKind.NumberMultiplierKind - ): - if expected_type.is_literal(): - return expected_type.type_str() == tpe.type_str() - else: - return True - return subsume.type_subsume(tpe, expected_type, check_left_any=True) - - -def is_upper_bound(type1: Type, type2: Type) -> bool: - """Whether `type1` is the upper bound of the `type2`""" - return subsume.type_subsume(type2, type1) - - -def has_any_type(types: List[Type]): - """Whether a type array contains any type""" - return any([t == ANY_TYPE for t in types]) - - -def infer_to_variable_type(tpe: Type): - """Infer the value type to the variable type""" - if tpe is None: - return tpe - # Literal type to its named type e.g., 1 -> int, "s" -> str - if tpe.type_kind() in LIT_TYPE_KIND_MAPPING: - return LIT_TYPE_KIND_MAPPING[tpe.type_kind()] - # Union type e.g., 1|2|"s" -> int|str - if tpe.type_kind() == objpkg.KCLTypeKind.UnionKind: - return sup([infer_to_variable_type(t) for t in tpe.types]) - # List type e.g., [1|2] -> [int] - if tpe.type_kind() == objpkg.KCLTypeKind.ListKind: - tpe.item_type = infer_to_variable_type(tpe.item_type) - # Dict type e.g., {str:1|2} -> {str:int} - if tpe.type_kind() == objpkg.KCLTypeKind.DictKind: - tpe.key_type = infer_to_variable_type(tpe.key_type) - tpe.value_type = infer_to_variable_type(tpe.value_type) - # None/Undefined type to any type e.g., None -> any - if tpe == NONE_TYPE: - return ANY_TYPE - return tpe - - -def literal_union_type_to_variable_type(tpe: Type): - """Convert the literal union type to its variable type - e.g., 1|2 -> int, 's'|'ss' -> str. - """ - if tpe.type_kind() == objpkg.KCLTypeKind.UnionKind: - return infer_to_variable_type(tpe) - return tpe - - -def is_kind_type_or_kind_union_type(tpe: Type, kind_list: List[int]): - """Judge a type kind in the type kind list or the union - type kinds are all in the type kind. - """ - result = False - if tpe.type_kind() == objpkg.KCLTypeKind.UnionKind: - result = all([t.type_kind() in kind_list for t in tpe.types]) - elif tpe.type_kind() in kind_list: - result = True - return result - - -def type_to_kcl_type_annotation_str(tpe: Type) -> str: - """Convert type to a kcl type annotation string""" - if not tpe or not isinstance(tpe, Type): - raise ValueError(f"Parameter type must be a valid type, got {tpe}") - if isinstance(tpe, objpkg.KCLUnionTypeObject): - return "|".join([type_to_kcl_type_annotation_str(t) for t in tpe.types]) - elif isinstance(tpe, objpkg.KCLIntTypeObject): - return "int" - elif isinstance(tpe, objpkg.KCLFloatTypeObject): - return "float" - elif isinstance(tpe, objpkg.KCLStringTypeObject): - return "str" - elif isinstance(tpe, objpkg.KCLBoolTypeObject): - return "bool" - elif isinstance(tpe, objpkg.KCLAnyTypeObject): - return "any" - elif isinstance(tpe, objpkg.KCLStringLitTypeObject): - return '"{}"'.format(tpe.value.replace('"', '\\"')) - elif isinstance( - tpe, - ( - objpkg.KCLIntLitTypeObject, - objpkg.KCLFloatLitTypeObject, - objpkg.KCLBoolLitTypeObject, - ), - ): - return str(tpe.value) - elif isinstance(tpe, objpkg.KCLListTypeObject): - return "[" + type_to_kcl_type_annotation_str(tpe.item_type) + "]" - elif isinstance(tpe, objpkg.KCLDictTypeObject): - return ( - "{" - + type_to_kcl_type_annotation_str(tpe.key_type) - + ":" - + type_to_kcl_type_annotation_str(tpe.value_type) - + "}" - ) - elif isinstance(tpe, objpkg.KCLSchemaDefTypeObject): - return tpe.schema_type.type_str_with_pkgpath() - elif isinstance(tpe, objpkg.KCLSchemaTypeObject): - return tpe.type_str_with_pkgpath() - elif isinstance(tpe, objpkg.KCLNumberMultiplierTypeObject): - return ( - f"{tpe.raw_value}{tpe.binary_suffix}" - if tpe.is_literal() - else "units.NumberMultiplier" - ) - return "" diff --git a/internal/kclvm_py/kcl/types/type_convension.py b/internal/kclvm_py/kcl/types/type_convension.py deleted file mode 100644 index 20f5fd21f..000000000 --- a/internal/kclvm_py/kcl/types/type_convension.py +++ /dev/null @@ -1,71 +0,0 @@ -# Copyright 2020 The KCL Authors. All rights reserved. - -import kclvm.kcl.error as kcl_error -import kclvm.api.object as objpkg - -from .type import Type - - -def type_convert(obj: objpkg.KCLObject, tpe: Type) -> objpkg.KCLObject: - """The type of `obj` is converted to another type. - - Raise an runtime error occurs in the type conversion. - """ - if not obj or not isinstance(obj, objpkg.KCLObject): - raise ValueError("Invalid parameter obj, expected KCL object") - if not tpe or not isinstance(tpe, Type): - raise ValueError("Invalid parameter tpe, expected KCL type object") - if isinstance(obj, (objpkg.KCLNoneObject, objpkg.KCLUndefinedObject)): - return obj - if isinstance(tpe, objpkg.KCLAnyTypeObject): - return obj - if isinstance(tpe, objpkg.KCLIntTypeObject) and isinstance( - obj, (objpkg.KCLIntObject, objpkg.KCLFloatObject) - ): - return objpkg.KCLIntObject(int(obj.value)) - if isinstance(tpe, objpkg.KCLFloatTypeObject) and isinstance( - obj, (objpkg.KCLIntObject, objpkg.KCLFloatObject) - ): - return objpkg.KCLFloatObject(float(obj.value)) - if isinstance(tpe, objpkg.KCLStringTypeObject) and isinstance( - obj, objpkg.KCLStringObject - ): - return obj - if isinstance(tpe, objpkg.KCLBoolTypeObject) and isinstance( - obj, objpkg.KCLNameConstantObject - ): - return obj - if isinstance(tpe, objpkg.KCLListTypeObject) and isinstance( - obj, objpkg.KCLListObject - ): - return objpkg.KCLListObject( - items=[type_convert(item, tpe.item_type) for item in obj.items] - ) - if isinstance(tpe, objpkg.KCLDictTypeObject) and isinstance( - obj, objpkg.KCLDictObject - ): - if isinstance(obj, objpkg.KCLSchemaConfigObject): - return objpkg.KCLSchemaConfigObject( - operation_map=obj.operation_map, - insert_index_map=obj.insert_index_map, - value={ - k: type_convert(obj.value[k], tpe.value_type) for k in obj.value - }, - ) - else: - return objpkg.KCLDictObject( - value={k: type_convert(obj.value[k], tpe.value_type) for k in obj.value} - ) - if ( - isinstance(tpe, objpkg.KCLSchemaTypeObject) - and isinstance(obj, objpkg.KCLSchemaObject) - and obj.runtime_type == tpe.runtime_type - ): - return obj - if isinstance(tpe, objpkg.KCLSchemaDefTypeObject): - return type_convert(obj, tpe.schema_type) - kcl_error.report_exception( - err_type=kcl_error.ErrType.EvaluationError_TYPE, - file_msgs=[kcl_error.ErrFileMsg(filename=None, line_no=None, col_no=None)], - arg_msg=f"Cannot convert type '{obj.type_str()}' to '{tpe.type_str()}'", - ) diff --git a/internal/kclvm_py/kcl/types/type_parser.py b/internal/kclvm_py/kcl/types/type_parser.py deleted file mode 100644 index e1c05c7d6..000000000 --- a/internal/kclvm_py/kcl/types/type_parser.py +++ /dev/null @@ -1,182 +0,0 @@ -"""The `type_parser` file mainly contains the function `parse_type_str` -which is used to parser a type string to a KCL type object - -:copyright: Copyright 2020 The KCL Authors. All rights reserved. -""" - -import re as _re - -from typing import Dict -from ast import literal_eval - -import kclvm.api.object as objpkg -import kclvm.api.object.internal.common as common -import kclvm.compiler.build.utils.units as units - -from .type import ( - Type, - INT_TYPE, - FLOAT_TYPE, - STR_TYPE, - BOOL_TYPE, - ANY_TYPE, - TRUE_LIT_TYPE, - FALSE_LIT_TYPE, - DICT_STR_ANY_TYPE, - DICT_STR_STR_TYPE, - sup, -) - -BUILTIN_TYPES = ["str", "bool", "int", "float"] -_KCL_TYPE_any = "any" -_KCL_TYPE_True = "True" -_KCL_TYPE_False = "False" - - -TYPES_MAPPING: Dict[str, Type] = { - "int": INT_TYPE, - "float": FLOAT_TYPE, - "str": STR_TYPE, - "bool": BOOL_TYPE, - "any": ANY_TYPE, - "[]": objpkg.KCLListTypeObject(item_type=ANY_TYPE), - "[any]": objpkg.KCLListTypeObject(item_type=ANY_TYPE), - "[str]": objpkg.KCLListTypeObject(item_type=STR_TYPE), - "{:}": objpkg.KCLDictTypeObject(key_type=ANY_TYPE, value_type=ANY_TYPE), - "{str:}": DICT_STR_ANY_TYPE, - "{str:any}": DICT_STR_ANY_TYPE, - "{str:str}": DICT_STR_STR_TYPE, -} - - -def parse_type_str(tpe_str: str) -> Type: - """Parser a type string to a type object""" - if tpe_str is None or tpe_str == "": - return ANY_TYPE - if not isinstance(tpe_str, str): - raise ValueError(f"Argument tpe_str must be str, not {type(tpe_str)}") - # Remove the space in the type string - tpe_str = tpe_str.strip(" \t\f\v\r\n") - if tpe_str in TYPES_MAPPING: - return TYPES_MAPPING[tpe_str] - # Union type - if is_union_type_str(tpe_str): - return parse_union_type_str(tpe_str) - # Bultin literal type - elif is_lit_type_str(tpe_str): - return parse_lit_type_str(tpe_str) - # Number multiplier literal type - elif is_number_multiplier_literal_type(tpe_str): - return parse_number_multiplier_literal_type(tpe_str) - # Dict type - elif is_dict_type_str(tpe_str): - k_type_str, v_type_str = common.separate_kv(common.dereferencetype(tpe_str)) - return objpkg.KCLDictTypeObject( - key_type=parse_type_str(k_type_str), - value_type=parse_type_str(v_type_str), - ) - # List type - elif is_list_type_str(tpe_str): - return objpkg.KCLListTypeObject( - item_type=parse_type_str(common.dereferencetype(tpe_str)) - ) - # Schema type or pkg.Schema type or named type - return parse_named_type(tpe_str) - - -# ----------------------- -# Judge type string -# ----------------------- - - -def is_union_type_str(tpe: str) -> bool: - """Whether a type string is a union type string, e.g. A|B|C, - and detect '|' in type string except '|' in dict or list. - """ - return common.is_type_union(tpe) - - -def is_list_type_str(tpe: str) -> bool: - """Whether a type string is a list type string""" - return common.islisttype(tpe) - - -def is_dict_type_str(tpe: str) -> bool: - """Whether a type string is a dict type string""" - return common.isdicttype(tpe) - - -def is_lit_type_str(tpe: str) -> bool: - """Whether a type string is a literal type string""" - if tpe in [_KCL_TYPE_True, _KCL_TYPE_False]: - return True - - # str - if tpe.startswith('"'): - return tpe.endswith('"') - if tpe.startswith("'"): - return tpe.endswith("'") - - # int or float - try: - float(tpe) - return True - except ValueError: - pass - - # non literal type - return False - - -def is_number_multiplier_literal_type(tpe: str) -> bool: - """Whether a type string is a number multiplier literal type string""" - return bool(_re.match(units.NUMBER_MULTIPLIER_REGEX, tpe)) - - -# ----------------------- -# Parse type string -# ----------------------- - - -def parse_union_type_str(tpe_str: str) -> Type: - """Parse union type string""" - type_str_list = common.split_type_union(tpe_str) - types = [parse_type_str(tpe) for tpe in type_str_list] - return sup(types) - - -def parse_lit_type_str(tpe_str: str) -> Type: - """Parse literal type string""" - type_val = literal_eval(tpe_str) - if isinstance(type_val, bool): - return TRUE_LIT_TYPE if type_val else FALSE_LIT_TYPE - if isinstance(type_val, str): - return objpkg.KCLStringLitTypeObject(value=type_val) - if isinstance(type_val, int): - return objpkg.KCLIntLitTypeObject(value=type_val) - if isinstance(type_val, float): - return objpkg.KCLFloatLitTypeObject(value=type_val) - raise ValueError(f"Invalid argument tpe_str {tpe_str}") - - -def parse_number_multiplier_literal_type(tpe_str: str) -> Type: - """Parse number multiplier literal type""" - if tpe_str[-1] == units.IEC_SUFFIX: - value, suffix = int(tpe_str[:-2]), tpe_str[-2:] - else: - value, suffix = int(tpe_str[:-1]), tpe_str[-1] - return objpkg.KCLNumberMultiplierTypeObject( - value=units.cal_num(value, suffix), - raw_value=value, - binary_suffix=suffix, - ) - - -def parse_named_type(tpe_str: str) -> Type: - # Please note Named type to find it in the scope (e.g. schema type, type alias) - return objpkg.KCLNamedTypeObject(name=tpe_str) - - -# ----------------------- -# END -# ----------------------- diff --git a/internal/kclvm_py/kcl/types/walker.py b/internal/kclvm_py/kcl/types/walker.py deleted file mode 100644 index c7cdaa968..000000000 --- a/internal/kclvm_py/kcl/types/walker.py +++ /dev/null @@ -1,30 +0,0 @@ -# Copyright 2020 The KCL Authors. All rights reserved. - -from typing import Callable, cast - -import kclvm.api.object as objpkg - -from .type import Type - - -def WalkType(tpe: Type, walk_fn: Callable): - """Walk one type recursively and deal the type using the `walk_fn`""" - if not tpe or not isinstance(tpe, Type): - return tpe - tpe = walk_fn(tpe) - if tpe.type_kind() == objpkg.KCLTypeKind.UnionKind: - tpe = cast(objpkg.KCLUnionTypeObject, tpe) - types = [] - for t in tpe.types: - t = WalkType(t, walk_fn) - if t: - types.append(t) - tpe.types = types - elif tpe.type_kind() == objpkg.KCLTypeKind.ListKind: - tpe = cast(objpkg.KCLListTypeObject, tpe) - tpe.item_type = WalkType(tpe.item_type, walk_fn) - elif tpe.type_kind() == objpkg.KCLTypeKind.DictKind: - tpe = cast(objpkg.KCLDictTypeObject, tpe) - tpe.key_type = WalkType(tpe.key_type, walk_fn) - tpe.value_type = WalkType(tpe.value_type, walk_fn) - return tpe diff --git a/internal/kclvm_py/program/eval/__init__.py b/internal/kclvm_py/program/eval/__init__.py deleted file mode 100644 index 528fe3d27..000000000 --- a/internal/kclvm_py/program/eval/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -from .eval import EvalCode, EvalAST - -__all__ = ["EvalCode", "EvalAST"] diff --git a/internal/kclvm_py/program/eval/eval.py b/internal/kclvm_py/program/eval/eval.py deleted file mode 100644 index e084113ce..000000000 --- a/internal/kclvm_py/program/eval/eval.py +++ /dev/null @@ -1,31 +0,0 @@ -# Copyright 2021 The KCL Authors. All rights reserved. - -from typing import Optional - -import kclvm.kcl.ast as ast -import kclvm.compiler.parser.parser as parser -import kclvm.vm as vm -import kclvm.vm.planner as planner -import kclvm.compiler.build.compiler as compiler - -MAIN_PKG_NAME = "__main__" - - -def EvalCode(filename: str, code: Optional[str] = None) -> str: - # Parser - module = parser.ParseFile(filename, code) - return EvalAST(module) - - -def EvalAST(module: ast.Module) -> str: - module.pkg = MAIN_PKG_NAME - # Compiler - bytecode = compiler.CompileProgram( - ast.Program( - root=MAIN_PKG_NAME, main=MAIN_PKG_NAME, pkgs={MAIN_PKG_NAME: [module]} - ) - ) - # VM run - result = vm.Run(bytecode) - # YAML plan - return planner.YAMLPlanner().plan(result.filter_by_path_selector()) diff --git a/internal/kclvm_py/program/eval/readme.md b/internal/kclvm_py/program/eval/readme.md deleted file mode 100644 index 1333ed77b..000000000 --- a/internal/kclvm_py/program/eval/readme.md +++ /dev/null @@ -1 +0,0 @@ -TODO diff --git a/internal/kclvm_py/program/exec/__init__.py b/internal/kclvm_py/program/exec/__init__.py deleted file mode 100644 index dd31f19f5..000000000 --- a/internal/kclvm_py/program/exec/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -# Copyright 2021 The KCL Authors. All rights reserved. - -from .runner import Run - -__all__ = [ - "Run", -] diff --git a/internal/kclvm_py/program/exec/kclvm_cli.py b/internal/kclvm_py/program/exec/kclvm_cli.py deleted file mode 100644 index 6cfdefe56..000000000 --- a/internal/kclvm_py/program/exec/kclvm_cli.py +++ /dev/null @@ -1,205 +0,0 @@ -# Copyright 2022 The KCL Authors. All rights reserved. - -import os -import sys -import platform -import typing -import json -import inspect - -from ctypes import * - -import google.protobuf.json_format as json_format - -import kclvm.compiler.extension.plugin.plugin as kcl_plugin -import kclvm.kcl.info as kcl_info -import kclvm.internal.gpyrpc.gpyrpc_pb2 as pb2 -import kclvm.api.object as objpkg -import kclvm.kcl.error as kcl_error -import kclvm.config - - -kclvm_PANIC_INFO_KEY = "__kcl_PanicInfo__" - - -_cli_dll = None - - -def init_cli_dll(): - global _cli_dll - - if _cli_dll: - return - - if platform.system() == "Darwin": - _exe_root = os.path.dirname(os.path.dirname(sys.executable)) - _cli_dll_path = f"{_exe_root}/bin/libkclvm_cli_cdylib.dylib" - _cli_dll = CDLL(_cli_dll_path) - elif platform.system() == "Linux": - _exe_root = os.path.dirname(os.path.dirname(sys.executable)) - _cli_dll_path = f"{_exe_root}/bin/libkclvm_cli_cdylib.so" - _cli_dll = CDLL(_cli_dll_path) - elif platform.system() == "Windows": - _exe_root = os.path.dirname(sys.executable) - _cli_dll_path = f"{_exe_root}/kclvm_cli_cdylib.dll" - _cli_dll = CDLL(_cli_dll_path) - else: - raise f"unknown os: {platform.system()}" - - -class PluginContex: - def __init__(self): - self._plugin_dict: typing.Dict[str, any] = {} - - def call_method(self, name: str, args_json: str, kwargs_json: str) -> str: - return self._call_py_method(name, args_json, kwargs_json) - - def _call_py_method(self, name: str, args_json: str, kwargs_json: str) -> str: - try: - return self._call_py_method_unsafe(name, args_json, kwargs_json) - except Exception as e: - return json.dumps({"__kcl_PanicInfo__": f"{e}"}) - - def _get_plugin(self, plugin_name: str) -> typing.Optional[any]: - if plugin_name in self._plugin_dict: - return self._plugin_dict[plugin_name] - - module = kcl_plugin.get_plugin(plugin_name) - self._plugin_dict[plugin_name] = module - return module - - def _call_py_method_unsafe( - self, name: str, args_json: str, kwargs_json: str - ) -> str: - dotIdx = name.rfind(".") - if dotIdx < 0: - return "" - - modulePath = name[:dotIdx] - mathodName = name[dotIdx + 1 :] - - plugin_name = modulePath[modulePath.rfind(".") + 1 :] - - module = self._get_plugin(plugin_name) - mathodFunc = None - - for func_name, func in inspect.getmembers(module): - if func_name == kcl_info.demangle(mathodName): - mathodFunc = func - break - - args = [] - kwargs = {} - - if args_json: - args = json.loads(args_json) - if not isinstance(args, list): - return "" - if kwargs_json: - kwargs = json.loads(kwargs_json) - if not isinstance(kwargs, dict): - return "" - - result = mathodFunc(*args, **kwargs) - return json.dumps(result) - - -__plugin_context__ = PluginContex() -__plugin_method_agent_buffer__ = create_string_buffer(1024) - - -@CFUNCTYPE(c_char_p, c_char_p, c_char_p, c_char_p) -def plugin_method_agent(method: str, args_json: str, kwargs_json: str) -> c_char_p: - method = str(method, encoding="utf-8") - args_json = str(args_json, encoding="utf-8") - kwargs_json = str(kwargs_json, encoding="utf-8") - - json_result = __plugin_context__.call_method(method, args_json, kwargs_json) - - global __plugin_method_agent_buffer__ - __plugin_method_agent_buffer__ = create_string_buffer(json_result.encode("utf-8")) - return addressof(__plugin_method_agent_buffer__) - - -def kclvm_cli_run(args: pb2.ExecProgram_Args) -> str: - init_cli_dll() - - _cli_dll.kclvm_cli_run.restype = c_char_p - _cli_dll.kclvm_cli_run.argtypes = [c_char_p, c_void_p] - - args_json = json_format.MessageToJson( - args, including_default_value_fields=True, preserving_proto_field_name=True - ) - - result_json = _cli_dll.kclvm_cli_run(args_json.encode("utf-8"), plugin_method_agent) - return result_json.decode(encoding="utf-8") - - -def kclvm_cli_native_run_dylib(args: pb2.ExecProgram_Args) -> objpkg.KCLResult: - json_result = kclvm_cli_run(args) - warn_json_result = "" - - if json_result.startswith("ERROR:"): - warn_json_result = json_result[len("ERROR:") :] - json_result = "{}" - - try: - data = json.loads(json_result) - except Exception as e: - raise Exception(f"Exception={e}, json_result={json_result}") - - panic_info = {} - if kclvm_PANIC_INFO_KEY in data: - panic_info = data - else: - if warn_json_result: - try: - panic_info = json.loads(warn_json_result) - except Exception as e: - raise Exception(f"Exception={e}, warn_json_result={warn_json_result}") - else: - panic_info = {} - - # check panic_info - if panic_info.get(kclvm_PANIC_INFO_KEY): - err_type_code = panic_info["err_type_code"] - if err_type_code: - err_type = kcl_error.ErrType((err_type_code,)) - else: - err_type = kcl_error.ErrType.EvaluationError_TYPE - - file_msg = [ - kcl_error.ErrFileMsg( - filename=panic_info.get("kcl_file"), - line_no=panic_info.get("kcl_line"), - col_no=panic_info.get("kcl_col"), - arg_msg=panic_info.get("kcl_arg_msg"), - ) - ] - if kclvm.config.debug and kclvm.config.verbose >= 2: - rust_filename = panic_info.get("rust_file") - rust_line = panic_info.get("rust_line") - rust_col = panic_info.get("rust_col") - print(f"Rust error info: {rust_filename}:{rust_line}:{rust_col}") - - config_meta_file_msg = kcl_error.ErrFileMsg( - filename=panic_info.get("kcl_config_meta_file"), - line_no=panic_info.get("kcl_config_meta_line"), - col_no=panic_info.get("kcl_config_meta_col"), - arg_msg=panic_info.get("kcl_config_meta_arg_msg"), - ) - if config_meta_file_msg.arg_msg: - file_msg.append(config_meta_file_msg) - - if panic_info.get("is_warning") or panic_info.get("is_warnning"): - kcl_error.report_warning( - err_type=err_type, file_msgs=[], arg_msg=panic_info.get("message") - ) - else: - kcl_error.report_exception( - err_type=err_type, - file_msgs=file_msg, - arg_msg=panic_info.get("message"), - ) - - return objpkg.KCLResult(data, os.path.abspath(args.k_filename_list[-1])) diff --git a/internal/kclvm_py/program/exec/native_runner.py b/internal/kclvm_py/program/exec/native_runner.py deleted file mode 100644 index bf79701cf..000000000 --- a/internal/kclvm_py/program/exec/native_runner.py +++ /dev/null @@ -1,463 +0,0 @@ -# Copyright 2021 The KCL Authors. All rights reserved. - -import os -import typing -import sys -import subprocess -import pathlib -import json -import glob -import hashlib -import platform -import shutil -import filelock - -import kclvm.config -import kclvm.kcl.ast as ast -import kclvm.api.object as objpkg -import kclvm.compiler.build.compiler as compiler -import kclvm.compiler.vfs as vfs -import kclvm.kcl.error as kcl_error -import kclvm.api.version as ver_pkg - - -CLANG = "clang" -LL_FILE_PATTERN = "*.ll" -BC_FILE_PATTERN = "*.bc" -LL_FILE_SUFFIX = ".ll" -BC_FILE_SUFFIX = ".bc" -LOCK_FILE_SUFFIX = ".lock" -KCLVM_PANIC_INFO_KEY = "__kcl_PanicInfo__" -NATIVE_CACHE_DIR = ".kclvm/native_cache" -KCLVM_CLI_SUB_CMD = "build" -CACHE_OPTION = vfs.CacheOption(cache_dir=NATIVE_CACHE_DIR) - - -def native_run( - path_list: typing.List[str], *, ast_prog: ast.Program -) -> objpkg.KCLResult: - - from kclvm.internal.kclx.transformer import transform_ast_to_kclx_ast_json_str - - # Config - - _no_link = True - _exe = ".exe" if os.name == "nt" else "" - _executable_root = os.path.dirname(os.path.dirname(sys.executable)) - _kclvm_cli = f"{_executable_root}/bin/kclvm-cli{_exe}" - _clang = f"{_executable_root}/tools/clang/bin/{CLANG}{_exe}" - _clang = _clang if os.path.exists(_clang) else f"{CLANG}{_exe}" - _rust_libstd_name = ( - pathlib.Path(f"{_executable_root}/lib/rust-libstd-name.txt").read_text().strip() - ) - _rust_libstd_dylib = f"{_executable_root}/lib/{_rust_libstd_name}" - _kclvm_bc = f"{_executable_root}/include/_kclvm.bc" - _a_out_ast_json = "_a.out.ast.json" - _a_out_bc = "_a.out.ll" - _lib_suffix = get_dylib_suffix() - _a_out_dylib = f"_a.out.{_lib_suffix}" - _out_bc_files = [] - - # Resolve Program - compiler.CompileProgram(ast_prog) - # Build Program with kclvm-cli, clang with cache - root = ast_prog.root - modfile = vfs.LoadModFile(root) - enable_cache = modfile.build.enable_pkg_cache - if enable_cache: - build_paths = [] - check_sum = ast_prog.get_check_sum(root) - cache_dir = f"{root}/{NATIVE_CACHE_DIR}/{ver_pkg.VERSION}-{ver_pkg.CHECKSUM}" - pathlib.Path(cache_dir).mkdir(parents=True, exist_ok=True) - for pkgpath in ast_prog.pkgs: - is_main_pkg = pkgpath == ast.Program.MAIN_PKGPATH - compile_prog = ast.Program( - root=root, main=ast_prog.main, pkgs={pkgpath: ast_prog.pkgs[pkgpath]} - ) - if is_main_pkg: - check_sum = compile_prog.get_check_sum(root) - main_virtual_filename = f"{check_sum}.k" - else: - main_virtual_filename = "" - bc_path = ( - f"{cache_dir}/{pkgpath}" - if not is_main_pkg - else f"{cache_dir}/{check_sum}" - ) - with filelock.FileLock(bc_path + LOCK_FILE_SUFFIX): - dylib_relative_path = ( - vfs.LoadMainPkgCache( - root, main_virtual_filename, option=CACHE_OPTION - ) - if is_main_pkg - else vfs.LoadPkgCache(root, pkgpath, option=CACHE_OPTION) - ) - # If AST module has been modified, ignore the dylib cache - if ast_prog.cmd_overrides and is_main_pkg: - dylib_relative_path = None - if dylib_relative_path is None: - # Build dylib - ast_json = transform_ast_to_kclx_ast_json_str(compile_prog) - with open(_a_out_ast_json, "w") as file: - file.write(ast_json) - dylib_path = ( - f"{cache_dir}/{pkgpath}.{_lib_suffix}" - if not is_main_pkg - else f"{cache_dir}/{check_sum}.{_lib_suffix}" - ) - if kclvm.config.verbose > 3: - print(f"Compiling {pkgpath}") - if os.path.exists(bc_path): - os.remove(bc_path) - process = subprocess.run( - [ - _kclvm_cli, - KCLVM_CLI_SUB_CMD, - _a_out_ast_json, - "--bc", - _kclvm_bc, - "-o", - bc_path, - "--linkmode", - "no_link", - ] - ) - if process.returncode != 0: - raise Exception( - f"stdout: {process.stdout}, stderr: {process.stderr}" - ) - process = subprocess.run( - [ - _clang, - "-Wno-override-module", - "-Wno-error=unused-command-line-argument", - "-Wno-unused-command-line-argument", - "-shared", - "-undefined", - "dynamic_lookup", - f"-Wl,-rpath,{_executable_root}/lib", - f"-L{_executable_root}/lib", - "-lkclvm_native_shared", - f"-I{_executable_root}/include", - bc_path + LL_FILE_SUFFIX, - _rust_libstd_dylib, - "-fPIC", - "-o", - dylib_path, - ] - ) - if process.returncode != 0: - raise Exception( - f"stdout: {process.stdout}, stderr: {process.stderr}" - ) - dylib_relative_path = dylib_path.replace(root, ".", 1) - if not is_main_pkg: - vfs.SavePkgCache( - root, pkgpath, dylib_relative_path, option=CACHE_OPTION - ) - else: - vfs.SaveMainPkgCache( - root, - main_virtual_filename, - dylib_relative_path, - option=CACHE_OPTION, - ) - _out_bc_files.append(bc_path + LL_FILE_SUFFIX) - else: - if dylib_relative_path.startswith("."): - dylib_path = dylib_relative_path.replace(".", root, 1) - build_paths.append(dylib_path) - _a_out_dylib = f"{cache_dir}/{check_sum}.out.{_lib_suffix}" - - process = subprocess.run( - [ - _clang, - "-Wno-override-module", - "-Wno-error=unused-command-line-argument", - "-Wno-unused-command-line-argument", - "-shared", - "-undefined", - "dynamic_lookup", - f"-Wl,-rpath,{_executable_root}/lib", - f"-L{_executable_root}/lib", - "-lkclvm_native_shared", - f"-I{_executable_root}/include", - *build_paths, - _rust_libstd_dylib, - "-fPIC", - "-o", - _a_out_dylib, - ] - ) - if process.returncode != 0: - raise Exception(f"stdout: {process.stdout}, stderr: {process.stderr}") - else: - # Transfrom Program - ast_json = transform_ast_to_kclx_ast_json_str(ast_prog) - with open(_a_out_ast_json, "w") as file: - file.write(ast_json) - if _no_link and os.path.exists(_a_out_bc): - os.remove(_a_out_bc) - if _no_link: - _out_bc_files = glob.glob(_a_out_bc + LL_FILE_PATTERN) - for file in _out_bc_files: - if os.path.exists(file): - os.remove(file) - # kclvm compile - process = subprocess.run( - [ - _kclvm_cli, - KCLVM_CLI_SUB_CMD, - _a_out_ast_json, - "--bc", - _kclvm_bc, - "-o", - _a_out_bc, - *(["--linkmode", "no_link"] if _no_link else []), - ] - ) - if process.returncode != 0: - raise Exception(f"stdout: {process.stdout}, stderr: {process.stderr}") - _out_bc_files = glob.glob(_a_out_bc + LL_FILE_PATTERN) - # clang - if _no_link: - process = subprocess.run( - [ - _clang, - "-Wno-override-module", - "-Wno-error=unused-command-line-argument", - "-Wno-unused-command-line-argument", - "-shared", - "-undefined", - "dynamic_lookup", - f"-Wl,-rpath,{_executable_root}/lib", - f"-L{_executable_root}/lib", - "-lkclvm_native", - f"-I{_executable_root}/include", - *_out_bc_files, - _rust_libstd_dylib, - f"{_executable_root}/lib/libkclvm.{_lib_suffix}", - "-fno-lto", - "-fPIC", - "-o", - _a_out_dylib, - ] - ) - else: - process = subprocess.run( - [ - _clang, - "-Wno-override-module", - "-Wno-error=unused-command-line-argument", - "-Wno-unused-command-line-argument", - "-shared", - "-undefined", - "dynamic_lookup", - f"-Wl,-rpath,{_executable_root}/lib", - f"-L{_executable_root}/lib", - "-lkclvm_native", - f"-I{_executable_root}/include", - _a_out_bc, - _rust_libstd_dylib, - f"{_executable_root}/lib/libkclvm.{_lib_suffix}", - "-fno-lto", - "-fPIC", - "-o", - _a_out_dylib, - ] - ) - if process.returncode != 0: - raise Exception(f"stdout: {process.stdout}, stderr: {process.stderr}") - - # run app - result = native_run_dylib(path_list, _a_out_dylib) - - if not kclvm.config.debug: - if os.path.exists(_a_out_ast_json): - os.remove(_a_out_ast_json) - if not enable_cache: - if _no_link: - for file in _out_bc_files: - if os.path.exists(file): - os.remove(file) - else: - if os.path.exists(_a_out_bc): - os.remove(_a_out_bc) - if os.path.exists(_a_out_dylib): - os.remove(_a_out_dylib) - - return result - - -def native_run_dylib( - path_list: typing.List[str], dylib_path: str, should_exit: bool = False -) -> objpkg.KCLResult: - """Native run with dylib""" - import kclvm_plugin as kclvm_plugin - - # run app - ctx = kclvm_plugin.AppContext(os.path.abspath(dylib_path)) - - # init options - ctx.InitOptions(kclvm.config.arguments) - - # run app - json_result = ctx.RunApp( - strict_range_check=kclvm.config.strict_range_check, - disable_none=kclvm.config.disable_none, - disable_schema_check=kclvm.config.disable_schema_check, - list_option_mode=kclvm.config.list_option_mode, - debug_mode=kclvm.config.debug, - ) - warn_json_result = ctx.GetWarn() - - if kclvm.config.list_option_mode: - print(json_result, end="") - return objpkg.KCLResult({}) - - try: - data = json.loads(json_result) - except Exception as e: - raise Exception(f"Exception={e}, json_result={json_result}") - - panic_info = {} - if KCLVM_PANIC_INFO_KEY in data: - panic_info = data - else: - if warn_json_result: - try: - panic_info = json.loads(warn_json_result) - except Exception as e: - raise Exception(f"Exception={e}, warn_json_result={warn_json_result}") - else: - panic_info = {} - - # check panic_info - if panic_info.get(KCLVM_PANIC_INFO_KEY): - err_type_code = panic_info["err_type_code"] - if err_type_code: - err_type = kcl_error.ErrType((err_type_code,)) - else: - err_type = kcl_error.ErrType.EvaluationError_TYPE - - file_msg = [ - kcl_error.ErrFileMsg( - filename=panic_info.get("kcl_file"), - line_no=panic_info.get("kcl_line"), - col_no=panic_info.get("kcl_col"), - arg_msg=panic_info.get("kcl_arg_msg"), - ) - ] - if kclvm.config.debug and kclvm.config.verbose >= 2: - rust_filename = panic_info.get("rust_file") - rust_line = panic_info.get("rust_line") - rust_col = panic_info.get("rust_col") - print(f"Rust error info: {rust_filename}:{rust_line}:{rust_col}") - - config_meta_file_msg = kcl_error.ErrFileMsg( - filename=panic_info.get("kcl_config_meta_file"), - line_no=panic_info.get("kcl_config_meta_line"), - col_no=panic_info.get("kcl_config_meta_col"), - arg_msg=panic_info.get("kcl_config_meta_arg_msg"), - ) - if config_meta_file_msg.arg_msg: - file_msg.append(config_meta_file_msg) - - if panic_info.get("is_warning") or panic_info.get("is_warnning"): - kcl_error.report_warning( - err_type=err_type, file_msgs=[], arg_msg=panic_info.get("message") - ) - else: - kcl_error.report_exception( - err_type=err_type, - file_msgs=file_msg, - arg_msg=panic_info.get("message"), - ) - - return objpkg.KCLResult(data, os.path.abspath(path_list[-1])) - - -def native_try_run_dylib( - root, path_list: typing.List[str], dylib_path: str -) -> typing.Optional[objpkg.KCLResult]: - if os.path.exists(dylib_path): - if is_linux_platform(): - # Run ldd - _ldd = "ldd" - _so_not_found_flag = " => not found" - try: - process = subprocess.run( - [ - _ldd, - dylib_path, - ], - capture_output=True, - ) - if process.returncode != 0: - return None - linked_so_path_list = [ - p.strip("\t ") - for p in str(process.stdout, encoding="utf-8").split("\n") - if p - ] - not_found_so_path_list = [ - p.replace(_so_not_found_flag, "").strip() - for p in linked_so_path_list - if _so_not_found_flag in p - ] - target_path = not_found_so_path_list[-1].rsplit("/", 1)[0] - source_path = ( - f"{root}/{NATIVE_CACHE_DIR}/{ver_pkg.VERSION}-{ver_pkg.CHECKSUM}" - ) - - if os.path.exists(target_path): - shutil.rmtree(target_path) - os.makedirs(target_path) - if os.path.exists(source_path): - for root, dirs, files in os.walk(source_path): - for file in files: - src_file = os.path.join(root, file) - shutil.copy(src_file, target_path) - - return native_run_dylib(path_list, dylib_path, should_exit=True) - except Exception: - return None - return None - - -def get_path_list_dylib_path(root: str, path_list: typing.List[str]) -> str: - check_sum = hashlib.md5() - if not path_list or not root: - return "" - for filename in path_list: - if os.path.isfile(filename): - filename = os.path.abspath(filename) - check_sum.update( - (filename.replace(root, ".", 1) if root else filename).encode( - encoding="utf-8" - ) - ) - with open(filename, "rb") as f: - check_sum.update(f.read()) - cache_dir = f"{root}/{NATIVE_CACHE_DIR}/{ver_pkg.VERSION}-{ver_pkg.CHECKSUM}" - dylib_path = "{}/{}.out.{}".format( - cache_dir, check_sum.hexdigest(), get_dylib_suffix() - ) - return dylib_path - - -def get_dylib_suffix() -> str: - """Get dylib suffix on diffrent platform""" - sysstr = platform.system() - if sysstr == "Windows": - lib_suffix = "dll" - elif sysstr == "Linux": - lib_suffix = "so" - else: - lib_suffix = "dylib" - return lib_suffix - - -def is_linux_platform() -> bool: - """Platform is linux""" - return platform.system() == "Linux" diff --git a/internal/kclvm_py/program/exec/native_runner_wasm32.py b/internal/kclvm_py/program/exec/native_runner_wasm32.py deleted file mode 100644 index 45ba99c53..000000000 --- a/internal/kclvm_py/program/exec/native_runner_wasm32.py +++ /dev/null @@ -1,342 +0,0 @@ -# Copyright 2021 The KCL Authors. All rights reserved. - -import os -import typing -import sys -import subprocess -import glob -import platform -import json -import inspect - -import kclvm.config -import kclvm.kcl.ast as ast -import kclvm.kcl.info as kcl_info -import kclvm.api.object as objpkg -import kclvm.compiler.build.compiler as compiler -import kclvm.compiler.extension.plugin.plugin as kcl_plugin -import kclvm.kcl.error as kcl_error - -from .native_runner import ( - LL_FILE_PATTERN, - KCLVM_PANIC_INFO_KEY, -) - - -def native_run_wasm32( - path_list: typing.List[str], *, ast_prog: ast.Program -) -> objpkg.KCLResult: - from kclvm.internal.kclx.transformer import transform_ast_to_kclx_ast_json_str - - # Config - - if platform.system() == "Windows": - _no_link = True - _executable_root = os.path.dirname(sys.executable) - _kclvm_cli = f"{_executable_root}\\kclvm_cli.exe" - _clang = f"{_executable_root}\\tools\\clang\\bin\\clang.exe" - _clang = _clang if os.path.exists(_clang) else "clang.exe" - - _kclvm_bc = f"{_executable_root}\\include\\_kclvm.bc" - _kclvm_lib_path = f"{_executable_root}\\libs" - _kclvm_lib_name = "kclvm_wasm32" - _kclvm_undefined_file = f"{_executable_root}\\libs\\_kclvm_undefined_wasm.txt" - - else: - _no_link = True - _executable_root = os.path.dirname(os.path.dirname(sys.executable)) - _kclvm_cli = f"{_executable_root}/bin/kclvm_cli" - _clang = f"{_executable_root}/tools/clang/bin/clang" - _clang = _clang if os.path.exists(_clang) else "clang" - - _kclvm_bc = f"{_executable_root}/include/_kclvm.bc" - _kclvm_lib_path = f"{_executable_root}/lib" - _kclvm_lib_name = "kclvm_wasm32" - _kclvm_undefined_file = f"{_executable_root}/lib/_kclvm_undefined_wasm.txt" - - _a_out_ast_json = "_a.out.ast.json" - _a_out_ll = "_a.out.ll" - _a_out_wasm = "_a.out.wasm" - _out_bc_files = [] - - # Resolve Program - compiler.CompileProgram(ast_prog) - - # Build Program with kclvm_cli, windows donot support cache - - if True: - # Transfrom Program - ast_json = transform_ast_to_kclx_ast_json_str(ast_prog) - with open(_a_out_ast_json, "w") as file: - file.write(ast_json) - if _no_link and os.path.exists(_a_out_ll): - os.remove(_a_out_ll) - if _no_link: - _out_bc_files = glob.glob(_a_out_ll + LL_FILE_PATTERN) - for file in _out_bc_files: - if os.path.exists(file): - os.remove(file) - - # kclvm compile - try: - args = [ - _kclvm_cli, - "build", - _a_out_ast_json, - "--bc", - _kclvm_bc, - "-o", - _a_out_ll + ".tmp.ll", - ] - subprocess.check_call(args) - - fix_ll_local_name(_a_out_ll, _a_out_ll + ".tmp.ll") - os.remove(_a_out_ll + ".tmp.ll") - - except subprocess.CalledProcessError as e: - raise e - _out_bc_files = glob.glob(_a_out_ll + LL_FILE_PATTERN) - - # clang - try: - args = [ - _clang, - "--target=wasm32-unknown-unknown-wasm", - "-Wno-override-module", - "-nostdlib", - "-Wl,--no-entry", - "-Wl,--export-all", - f"-Wl,--allow-undefined-file={_kclvm_undefined_file}", - "-O3", - f"-L{_kclvm_lib_path}", - f"-l{_kclvm_lib_name}", - _a_out_ll, - "-o", - _a_out_wasm, - ] - - if platform.system() == "Windows": - subprocess.check_call(args, stdout=open(os.devnull, "wb")) - else: - subprocess.check_call(args) - - except subprocess.CalledProcessError as e: - raise e - - # run wasm - result = WasmApp(path_list, _a_out_wasm).run() - if not kclvm.config.debug: - if os.path.exists(_a_out_ast_json): - os.remove(_a_out_ast_json) - if os.path.exists(_a_out_ll): - os.remove(_a_out_ll) - if _no_link: - for file in _out_bc_files: - if os.path.exists(file): - os.remove(file) - if os.path.exists(_a_out_wasm): - os.remove(_a_out_wasm) - - return result - - -class WasmApp: - def __init__( - self, path_list: typing.List[str], wasm_path: str, should_exit: bool = False - ): - import wasmer - import wasmer_compiler_cranelift - - self.path_list = path_list - self.wasm_path = wasm_path - self.should_exit = should_exit - - self.store = wasmer.Store(wasmer.engine.JIT(wasmer_compiler_cranelift.Compiler)) - self.module = wasmer.Module(self.store, open(wasm_path, "rb").read()) - - def kclvm_plugin_invoke_json_wasm(method: int, args: int, kwargs: int) -> int: - return self._invoke_json_wasm(method, args, kwargs) - - self.import_object = wasmer.ImportObject() - self.import_object.register( - "env", - { - "kclvm_plugin_invoke_json_wasm": wasmer.Function( - self.store, kclvm_plugin_invoke_json_wasm - ), - }, - ) - - self.instance = wasmer.Instance(self.module, self.import_object) - self.memory = self.instance.exports.memory - - self._invoke_json_buffer = self.instance.exports.kclvm_value_Str(0) - self.instance.exports.kclvm_value_Str_resize( - self._invoke_json_buffer, 1024 * 1024 * 1024 - ) - - def _invoke_json_wasm(self, method_ptr: int, args_ptr: int, kwargs_ptr: int) -> int: - method_len = self.instance.exports.kclvm_strlen(method_ptr) - args_len = self.instance.exports.kclvm_strlen(args_ptr) - kwargs_len = self.instance.exports.kclvm_strlen(kwargs_ptr) - - reader = bytearray(self.memory.buffer) - - method = reader[method_ptr : method_ptr + method_len].decode() - args = reader[args_ptr : args_ptr + args_len].decode() - kwargs = reader[kwargs_ptr : kwargs_ptr + kwargs_len].decode() - - json_result = self._call_py_method(method, args, kwargs) - - bytes_result = json_result.encode(encoding="utf8") - self.instance.exports.kclvm_value_Str_resize( - self._invoke_json_buffer, len(bytes_result) + 1 - ) - - buf_ptr = self.instance.exports.kclvm_value_Str_ptr(self._invoke_json_buffer) - buf_len = self.instance.exports.kclvm_value_Str_len(self._invoke_json_buffer) - assert buf_len == len(bytes_result) + 1 - - mem = self.memory.uint8_view() - for i in range(len(bytes_result)): - mem[buf_ptr + i] = bytes_result[i] - mem[buf_ptr + len(bytes_result)] = 0 - - return buf_ptr - - def run(self) -> objpkg.KCLResult: - ctx = self.instance.exports.kclvm_context_new() - result = self.instance.exports.kclvm_main(ctx) - - c_str_ptr = self.instance.exports.kclvm_value_Str_ptr(result) - c_str_len = self.instance.exports.kclvm_value_len(result) - - reader = bytearray(self.memory.buffer) - result = reader[c_str_ptr : c_str_ptr + c_str_len].decode() - - return self.json_to_object(result, None) - - def json_to_object( - self, json_result: str, warn_json_result: str = None - ) -> objpkg.KCLResult: - if kclvm.config.list_option_mode: - print(json_result, end="") - return objpkg.KCLResult({}) - - data = json.loads(json_result) - - panic_info = {} - if KCLVM_PANIC_INFO_KEY in data: - panic_info = data - else: - if warn_json_result: - panic_info = json.loads(warn_json_result) - else: - panic_info = {} - - # check panic_info - if panic_info.get(KCLVM_PANIC_INFO_KEY): - err_type_code = panic_info["err_type_code"] - if err_type_code: - err_type = kcl_error.ErrType((err_type_code,)) - else: - err_type = kcl_error.ErrType.EvaluationError_TYPE - - file_msg = [ - kcl_error.ErrFileMsg( - filename=panic_info.get("kcl_file"), - line_no=panic_info.get("kcl_line"), - col_no=panic_info.get("kcl_col"), - arg_msg=panic_info.get("kcl_arg_msg"), - ) - ] - if kclvm.config.debug and kclvm.config.verbose >= 2: - rust_filename = panic_info.get("rust_file") - rust_line = panic_info.get("rust_line") - rust_col = panic_info.get("rust_col") - print(f"Rust error info: {rust_filename}:{rust_line}:{rust_col}") - - config_meta_file_msg = kcl_error.ErrFileMsg( - filename=panic_info.get("kcl_config_meta_file"), - line_no=panic_info.get("kcl_config_meta_line"), - col_no=panic_info.get("kcl_config_meta_col"), - arg_msg=panic_info.get("kcl_config_meta_arg_msg"), - ) - if config_meta_file_msg.arg_msg: - file_msg.append(config_meta_file_msg) - - if panic_info.get("is_warning") or panic_info.get("is_warnning"): - kcl_error.report_warning( - err_type=err_type, file_msgs=[], arg_msg=panic_info.get("message") - ) - else: - kcl_error.report_exception( - err_type=err_type, - file_msgs=file_msg, - arg_msg=panic_info.get("message"), - ) - - return objpkg.KCLResult(data, os.path.abspath(self.path_list[-1])) - - def _call_py_method(self, name: str, args_json: str, kwargs_json: str) -> str: - try: - return self._call_py_method_unsafe(name, args_json, kwargs_json) - except Exception as e: - return json.dumps({"__kcl_PanicInfo__": f"{e}"}) - - def _call_py_method_unsafe( - self, name: str, args_json: str, kwargs_json: str - ) -> str: - dotIdx = name.rfind(".") - if dotIdx < 0: - return "" - - modulePath = name[:dotIdx] - mathodName = name[dotIdx + 1 :] - - plugin_name = modulePath[modulePath.rfind(".") + 1 :] - - module = kcl_plugin.get_plugin(plugin_name) - mathodFunc = None - - for func_name, func in inspect.getmembers(module): - if func_name == kcl_info.demangle(mathodName): - mathodFunc = func - break - - args = [] - kwargs = {} - - if args_json: - args = json.loads(args_json) - if not isinstance(args, list): - return "" - if kwargs_json: - kwargs = json.loads(kwargs_json) - if not isinstance(kwargs, dict): - return "" - - result = mathodFunc(*args, **kwargs) - return json.dumps(result) - - -def fix_ll_local_name(dst_path, src_path: str): - replaceArgs_old = [] - replaceArgs_new = [] - - for i in range(0, 10): - replaceArgs_old.append(f"%{i}") - replaceArgs_new.append(f"%local_{i}") - - replaceArgs_old.append(f"\n{i}") - replaceArgs_new.append(f"\nlocal_{i}") - - with open(src_path, "r") as file: - code = file.read() - - if platform.system() == "Windows": - for i in range(0, len(replaceArgs_old)): - code = code.replace(replaceArgs_old[i], replaceArgs_new[i], -1) - - with open(dst_path, "w") as f: - f.write(code) diff --git a/internal/kclvm_py/program/exec/native_runner_windows_amd64.py b/internal/kclvm_py/program/exec/native_runner_windows_amd64.py deleted file mode 100644 index 338562617..000000000 --- a/internal/kclvm_py/program/exec/native_runner_windows_amd64.py +++ /dev/null @@ -1,140 +0,0 @@ -# Copyright 2021 The KCL Authors. All rights reserved. - -import os -import typing -import sys -import subprocess -import glob -import platform - -import kclvm.config -import kclvm.kcl.ast as ast -import kclvm.api.object as objpkg -import kclvm.compiler.build.compiler as compiler - -from .native_runner import ( - LL_FILE_PATTERN, - native_run_dylib, -) - - -def native_run_windows( - path_list: typing.List[str], *, ast_prog: ast.Program -) -> objpkg.KCLResult: - if platform.system() != "Windows": - raise "native_run_windows only for windows" - - from kclvm.internal.kclx.transformer import transform_ast_to_kclx_ast_json_str - - # Config - - _no_link = True - _executable_root = os.path.dirname(sys.executable) - _kclvm_cli = f"{_executable_root}\\kclvm-cli.exe" - _clang = f"{_executable_root}\\tools\\clang\\bin\\clang.exe" - _clang = _clang if os.path.exists(_clang) else "clang.exe" - - _kclvm_main_win_c = f"{_executable_root}\\libs\\_kclvm_main_win.c" - _kclvm_dll_lib = f"{_executable_root}\\libs\\kclvm.dll.lib" - _kclvm_bc = f"{_executable_root}\\libs\\_kclvm.bc" - _a_out_ast_json = "_a.out.ast.json" - _a_out_ll = "_a.out.ll" - _a_out_dylib = "_a.out.dll" - _out_bc_files = [] - - # Resolve Program - compiler.CompileProgram(ast_prog) - - # Build Program with kclvm-cli, windows donot support cache - - if True: - # Transfrom Program - ast_json = transform_ast_to_kclx_ast_json_str(ast_prog) - with open(_a_out_ast_json, "w") as file: - file.write(ast_json) - if _no_link and os.path.exists(_a_out_ll): - os.remove(_a_out_ll) - if _no_link: - _out_bc_files = glob.glob(_a_out_ll + LL_FILE_PATTERN) - for file in _out_bc_files: - if os.path.exists(file): - os.remove(file) - - # kclvm compile - try: - args = [ - _kclvm_cli, - "build", - _a_out_ast_json, - "--bc", - _kclvm_bc, - "-o", - _a_out_ll + ".tmp.ll", - ] - subprocess.check_call(args) - - fix_ll_local_name(_a_out_ll, _a_out_ll + ".tmp.ll") - os.remove(_a_out_ll + ".tmp.ll") - - except subprocess.CalledProcessError as e: - raise e - _out_bc_files = glob.glob(_a_out_ll + LL_FILE_PATTERN) - - # clang - try: - args = [ - _clang, - "-Wno-override-module", - "-shared", - _a_out_ll, - _kclvm_main_win_c, - _kclvm_dll_lib, - "-lws2_32", - "-lbcrypt", - "-lAdvapi32", - "-lUserenv", - "-o", - _a_out_dylib, - ] - subprocess.check_call(args, stdout=open(os.devnull, "wb")) - - except subprocess.CalledProcessError as e: - raise e - - # run app - result = native_run_dylib(path_list, _a_out_dylib) - if not kclvm.config.debug: - if os.path.exists(_a_out_ast_json): - os.remove(_a_out_ast_json) - if _no_link: - for file in _out_bc_files: - if os.path.exists(file): - os.remove(file) - else: - if os.path.exists(_a_out_ll): - os.remove(_a_out_ll) - if os.path.exists(_a_out_dylib): - os.remove(_a_out_dylib) - - return result - - -def fix_ll_local_name(dst_path, src_path: str): - replaceArgs_old = [] - replaceArgs_new = [] - - for i in range(0, 10): - replaceArgs_old.append(f"%{i}") - replaceArgs_new.append(f"%local_{i}") - - replaceArgs_old.append(f"\n{i}") - replaceArgs_new.append(f"\nlocal_{i}") - - with open(src_path, "r") as file: - code = file.read() - - for i in range(0, len(replaceArgs_old)): - code = code.replace(replaceArgs_old[i], replaceArgs_new[i], -1) - - with open(dst_path, "w") as f: - f.write(code) diff --git a/internal/kclvm_py/program/exec/runner.py b/internal/kclvm_py/program/exec/runner.py deleted file mode 100644 index ccd2f9bb1..000000000 --- a/internal/kclvm_py/program/exec/runner.py +++ /dev/null @@ -1,190 +0,0 @@ -# Copyright 2021 The KCL Authors. All rights reserved. - -import os -import platform -import typing -import json - -from ast import literal_eval - -import kclvm.config -import kclvm.kcl.ast as ast -import kclvm.api.object as objpkg -import kclvm.tools.query as query -import kclvm.compiler.parser.parser as parser -import kclvm.compiler.build.compiler as compiler -import kclvm.compiler.vfs as vfs -import kclvm.vm as vm -import kclvm.internal.gpyrpc.gpyrpc_pb2 as pb2 - -from kclvm.api.object.internal import ( - kcl_option_reset, - kcl_option_init_all, -) -from .native_runner import native_run, is_linux_platform -from .kclvm_cli import kclvm_cli_native_run_dylib - - -KCLVM_PANIC_INFO_KEY = "__kcl_PanicInfo__" -KCLVM_RUN_MODE_WITHIN_CACHE_ENV = "KCLVM_RUN_MODE_WITHIN_CACHE" -KCLVM_TARGET_ENV_KEY = "KCLVM_TARGET" - - -def Run( - path_list: typing.List[str], - *, - work_dir: str = "", - k_code_list: typing.List[str] = None, - cmd_args: typing.List[ast.CmdArgSpec] = None, - cmd_overrides: typing.List[ast.CmdOverrideSpec] = None, - # -r --strict-range-check - strict_range_check: bool = None, - # -n --disable-none - disable_none: bool = None, - # -v --verbose - verbose: int = None, - # -d --debug - debug: int = None, - print_override_ast: bool = False, - # --target - target: str = "", -) -> objpkg.KCLResult: - assert len(path_list) > 0 - - if not work_dir and not k_code_list: - for s in path_list: - if os.path.isdir(s): - work_dir = s - if not work_dir and not k_code_list: - work_dir = kclvm.config.current_path or os.path.dirname(path_list[0]) - - root = vfs.MustGetPkgRoot(path_list) - modfile = vfs.LoadModFile(root) - target = (target or modfile.build.target or os.getenv(KCLVM_TARGET_ENV_KEY) or "").lower() - - kclvm.config.input_file = path_list - kclvm.config.current_path = work_dir - kclvm.config.is_target_native = target == "native" - kclvm.config.is_target_wasm = target == "wasm" - - if strict_range_check is not None: - kclvm.config.strict_range_check = strict_range_check - if disable_none is not None: - kclvm.config.disable_none = disable_none - if verbose is not None: - kclvm.config.verbose = verbose - if debug is not None: - kclvm.config.debug = debug - - if cmd_args: - kclvm.config.arguments = [] - for x in cmd_args or []: - try: - better_value = literal_eval(x.value) - kclvm.config.arguments.append((x.name, better_value)) - except Exception: - kclvm.config.arguments.append((x.name, x.value)) - - # rust: build/link/run - if target == "native" or target == "wasm": - kclvm.config.is_target_native = True - - args = pb2.ExecProgram_Args() - args.work_dir = work_dir - args.k_filename_list.extend(path_list) - args.k_code_list.extend(k_code_list) - - for kv in kclvm.config.arguments or []: - key, value = kv - if isinstance(value, (bool, list, dict)): - value = json.dumps(value) - elif isinstance(value, str): - value = '"{}"'.format(value.replace('"', '\\"')) - else: - value = str(value) - args.args.append( - pb2.CmdArgSpec( - name=key, - value=value, - ) - ) - - for x in cmd_overrides or []: - args.overrides.append( - pb2.CmdOverrideSpec( - pkgpath=x.pkgpath, - field_path=x.field_path, - field_value=x.field_value, - action=x.action.value, - ) - ) - - args.print_override_ast = print_override_ast or False - args.strict_range_check = strict_range_check or False - args.disable_none = disable_none or False - args.verbose = verbose or 0 - args.debug = debug or 0 - - return kclvm_cli_native_run_dylib(args) - - # Only for linux debug directly run - from .native_runner import ( - get_path_list_dylib_path, - native_run_dylib, - native_try_run_dylib, - ) - - if ( - target == "native" - and is_linux_platform() - and not cmd_overrides - and os.environ.get(KCLVM_RUN_MODE_WITHIN_CACHE_ENV) - ): - dylib_path = get_path_list_dylib_path(root, path_list) - if os.path.exists(dylib_path): - try: - return native_run_dylib(path_list, dylib_path, should_exit=True) - except Exception: - result = native_try_run_dylib(root, path_list, dylib_path) - if result: - return result - - ast_prog = parser.LoadProgram( - *path_list, - work_dir=work_dir, - k_code_list=k_code_list, - mode=parser.ParseMode.ParseComments if cmd_overrides else parser.ParseMode.Null, - ) - ast_prog.cmd_args = cmd_args if cmd_args else [] - ast_prog.cmd_overrides = cmd_overrides if cmd_overrides else [] - - # Apply argument - kcl_option_reset() - kcl_option_init_all() - - if target == "native": - if platform.system() == "Windows": - from .native_runner_windows_amd64 import native_run_windows - - result = native_run_windows(path_list, ast_prog=ast_prog) - else: - result = native_run(path_list, ast_prog=ast_prog) - - elif target == "wasm": - from .native_runner_wasm32 import native_run_wasm32 - - result = native_run_wasm32(path_list, ast_prog=ast_prog) - - else: - # AST to bytecode list - bin_prog = compiler.CompileProgram( - ast_prog, enable_cache=not bool(ast_prog.cmd_overrides) - ) - - # Run bytecode list - result = vm.Run(bin_prog) - - # If cmd overrides are used and config.debug is True, write back KCL files - if print_override_ast: - query.PrintOverridesAST() - return result diff --git a/internal/kclvm_py/program/repl/readme.md b/internal/kclvm_py/program/repl/readme.md deleted file mode 100644 index 1333ed77b..000000000 --- a/internal/kclvm_py/program/repl/readme.md +++ /dev/null @@ -1 +0,0 @@ -TODO diff --git a/internal/kclvm_py/program/rpc-server/__init__.py b/internal/kclvm_py/program/rpc-server/__init__.py deleted file mode 100644 index d74aaf8ad..000000000 --- a/internal/kclvm_py/program/rpc-server/__init__.py +++ /dev/null @@ -1 +0,0 @@ -# Copyright 2021 The KCL Authors. All rights reserved. diff --git a/internal/kclvm_py/program/rpc-server/__main__.py b/internal/kclvm_py/program/rpc-server/__main__.py deleted file mode 100644 index c314ebd8d..000000000 --- a/internal/kclvm_py/program/rpc-server/__main__.py +++ /dev/null @@ -1,633 +0,0 @@ -# Copyright 2021 The KCL Authors. All rights reserved. - -import json -import sys -import socket -import subprocess -import typing -import time -import pathlib - -from dataclasses import dataclass -from http.server import BaseHTTPRequestHandler, HTTPServer - -import kclvm.kcl.ast as ast -import kclvm.kcl.error as kcl_error -import kclvm.kcl.types as types -import kclvm.config -import kclvm.compiler.extension.plugin as plugin -import kclvm.compiler.parser.lark_parser as lark_parser -import kclvm.compiler.parser.parser as parser -import kclvm.program.exec as kclvm_exec -import kclvm.vm.planner as planner -import kclvm.internal.gpyrpc.gpyrpc_pb2 as pb2 -import kclvm.internal.gpyrpc.gpyrpc_pb_protorpc as pbrpc -import kclvm.internal.gpyrpc.protorpc as protorpc -from kclvm.tools.format import kcl_fmt_source, kcl_fmt -from kclvm.tools.lint.lint import kcl_lint -from kclvm.tools.query import override_file -from kclvm.tools.validation import validate_code_with_attr_data -from kclvm.tools.langserver import grpc_wrapper -from kclvm.tools.printer import SchemaRuleCodeSnippet, splice_schema_with_rule -from kclvm.tools.list_attribute.schema import get_schema_type_from_code - -import kclvm.kcl.error.kcl_err_template as kcl_err_template - -import google.protobuf.json_format as _json_format - -USAGE = """\ -usage: kclvm -m kclvm.program.rpc-server # run server on stdin/stdout - kclvm -m kclvm.program.rpc-server -http=:2021 # run fast http server on port - kclvm -m kclvm.program.rpc-server -h -""" - - -@dataclass -class CmdFlags: - help: bool = False - - http_addr: str = "" - http_port: int = 0 - - use_http_server: bool = False - - -def parse_flags(args: typing.List[str]) -> CmdFlags: - m = CmdFlags() - for s in args: - if s == "-h" or s == "-help": - m.help = True - continue - - if s.startswith("-http="): - value = s[len("-http=") :] - m.http_addr = str(value[: value.find(":")]) - m.http_port = int(value[value.find(":") + 1 :]) - continue - - if s.startswith("-http.server="): - value = s[len("-http.server=") :] - m.http_addr = str(value[: value.find(":")]) - m.http_port = int(value[value.find(":") + 1 :]) - m.use_http_server = True - continue - - if m.http_port and not m.http_addr: - m.http_addr = "localhost" - - return m - - -class ASTTransformer(ast.TreeTransformer): - def walk_NameConstantLit(self, t: ast.NameConstantLit): - t.value = str(t.value) - return t - - -# KclvmService implementation -class KclvmServiceImpl(pbrpc.KclvmService): - def Ping(self, args: pb2.Ping_Args) -> pb2.Ping_Result: - return pb2.Ping_Result(value=args.value) - - def ParseFile_LarkTree( - self, args: pb2.ParseFile_LarkTree_Args - ) -> pb2.ParseFile_LarkTree_Result: - result = pb2.ParseFile_LarkTree_Result() - - if args.source_code: - t = lark_parser.ParseFile( - args.filename, args.source_code, ignore_file_line=args.ignore_file_line - ) - result.lark_tree_json = json.dumps(t, default=lambda obj: obj.__dict__) - - return result - - def ParseFile_AST(self, args: pb2.ParseFile_AST_Args) -> pb2.ParseFile_AST_Result: - t = parser.ParseFile(args.filename, args.source_code) - ASTTransformer().walk(t) - result = pb2.ParseFile_AST_Result() - result.ast_json = t.to_json() - return result - - def ParseProgram_AST( - self, args: pb2.ParseProgram_AST_Args - ) -> pb2.ParseProgram_AST_Result: - program = parser.LoadProgram(*list(args.k_filename_list)) - for pkgpath in program.pkgs: - for i, module in enumerate(program.pkgs[pkgpath]): - program.pkgs[pkgpath][i] = ASTTransformer().walk(module) - result = pb2.ParseProgram_AST_Result() - result.ast_json = program.to_json() - return result - - def ExecProgram(self, args: pb2.ExecProgram_Args) -> pb2.ExecProgram_Result: - cmd_args: typing.List[ast.CmdArgSpec] = [] - cmd_overrides: typing.List[ast.CmdOverrideSpec] = [] - - # kcl -D name=value main.k - for x in args.args: - cmd_args.append(ast.CmdArgSpec(name=x.name, value=x.value)) - - # kcl main.k -O pkgpath:path.to.field=field_value - for x in args.overrides: - cmd_overrides.append( - ast.CmdOverrideSpec( - pkgpath=x.pkgpath or "__main__", - field_path=x.field_path, - field_value=x.field_value, - action=ast.OverrideAction(x.action) - if x.action - else ast.OverrideAction.CREATE_OR_UPDATE, - ) - ) - - work_dir: str = args.work_dir - k_filename_list: typing.List[str] = list(args.k_filename_list) - k_filename_list = [ - str( - pathlib.Path(work_dir or kclvm.config.current_path or "").joinpath(file) - ) - if file.startswith(".") - else file - for file in k_filename_list or [] - ] - k_code_list: typing.List[str] = list(args.k_code_list) - disable_yaml_result: bool = args.disable_yaml_result - print_override_ast: bool = args.print_override_ast - - # -r --strict-range-check - strict_range_check: bool = args.strict_range_check - # -n --disable-none - disable_none: bool = args.disable_none - # -v --verbose - verbose: int = args.verbose - # -d --debug - debug: int = args.debug - - sort_keys: bool = args.sort_keys - include_schema_type_path: bool = args.include_schema_type_path - - start_time = time.time() - kcl_result = kclvm_exec.Run( - k_filename_list, - work_dir=work_dir, - k_code_list=k_code_list, - cmd_args=cmd_args, - cmd_overrides=cmd_overrides, - print_override_ast=print_override_ast, - strict_range_check=strict_range_check, - disable_none=disable_none, - verbose=verbose, - debug=debug, - ) - end_time = time.time() - - result = pb2.ExecProgram_Result() - - result.escaped_time = f"{end_time-start_time}" - - # json - output_json = planner.JSONPlanner( - sort_keys=sort_keys, include_schema_type_path=include_schema_type_path - ).plan( - kcl_result.filter_by_path_selector( - to_kcl=not kclvm.config.is_target_native - ), - to_py=not kclvm.config.is_target_native, - ) - result.json_result = output_json - - # yaml - if not disable_yaml_result: - output_yaml = planner.YAMLPlanner( - sort_keys=sort_keys, include_schema_type_path=include_schema_type_path - ).plan( - kcl_result.filter_by_path_selector( - to_kcl=not kclvm.config.is_target_native - ), - to_py=not kclvm.config.is_target_native, - ) - result.yaml_result = output_yaml - - return result - - def ResetPlugin(self, args: pb2.ResetPlugin_Args) -> pb2.ResetPlugin_Result: - plugin.reset_plugin(args.plugin_root) - result = pb2.ResetPlugin_Result() - return result - - def FormatCode(self, args: pb2.FormatCode_Args) -> pb2.FormatCode_Result: - formatted, _ = kcl_fmt_source(args.source) - return pb2.FormatCode_Result(formatted=formatted.encode("utf-8")) - - def FormatPath(self, args: pb2.FormatPath_Args) -> pb2.FormatPath_Result: - path = args.path - recursively = False - if path.endswith("..."): - recursively = True - path = path[: len(path) - 3] - if path == "" or path is None: - path = "." - changed_paths = kcl_fmt(path, recursively=recursively) - return pb2.FormatPath_Result(changedPaths=changed_paths) - - def LintPath(self, args: pb2.LintPath_Args) -> pb2.LintPath_Result: - path = args.path - - results: typing.List[str] = [] - for lintMessage in kcl_lint(path): - results.append(f"{lintMessage.msg}") - - return pb2.LintPath_Result(results=results) - - def OverrideFile(self, args: pb2.OverrideFile_Args) -> pb2.OverrideFile_Result: - result = override_file(args.file, args.specs, args.import_paths) - return pb2.OverrideFile_Result(result=result) - - def EvalCode(self, args: pb2.EvalCode_Args) -> pb2.EvalCode_Result: - import tempfile - import os - - work_dir = tempfile.mkdtemp() - - with open(f"{work_dir}/kcl.mod", "w") as f: - pass - with open(f"{work_dir}/main.k", "w") as f: - f.write(args.code) - - kcl_result = kclvm_exec.Run( - ["main.k"], work_dir=work_dir, k_code_list=[args.code] - ) - output_json = planner.JSONPlanner().plan( - kcl_result.filter_by_path_selector(), only_first=True - ) - - os.remove(f"{work_dir}/kcl.mod") - os.remove(f"{work_dir}/main.k") - - result = pb2.EvalCode_Result(json_result=output_json) - return result - - def ResolveCode(self, args: pb2.ResolveCode_Args) -> pb2.ResolveCode_Result: - import tempfile - import os - - work_dir = tempfile.mkdtemp() - - with open(f"{work_dir}/kcl.mod", "w") as f: - pass - with open(f"{work_dir}/main.k", "w") as f: - f.write(args.code) - - ast_prog = parser.LoadProgram( - *["main.k"], - work_dir=work_dir, - k_code_list=[args.code], - ) - types.ResolveProgram(ast_prog) - - os.remove(f"{work_dir}/kcl.mod") - os.remove(f"{work_dir}/main.k") - - result = pb2.ResolveCode_Result(success=True) - return result - - def GetSchemaType(self, args: pb2.GetSchemaType_Args) -> pb2.GetSchemaType_Result: - schema_type_list = get_schema_type_from_code( - args.file, args.code, args.schema_name - ) - return pb2.GetSchemaType_Result(schema_type_list=schema_type_list) - - def ValidateCode(self, args: pb2.ValidateCode_Args) -> pb2.ValidateCode_Result: - data: str = args.data - code: str = args.code - schema: typing.Optional[str] = args.schema or None - format_: str = args.format or "JSON" - - success = validate_code_with_attr_data(data, code, schema, format_) - return pb2.ValidateCode_Result(success=success) - - def SpliceCode(self, args: pb2.SpliceCode_Args): - code_snippets_pb = args.codeSnippets - code_snippets = [ - SchemaRuleCodeSnippet( - schema=code_snippet.schema, - rule=code_snippet.rule, - ) - for code_snippet in code_snippets_pb - ] - splice_code = splice_schema_with_rule(code_snippets) - return pb2.SpliceCode_Result(spliceCode=splice_code) - - def Complete(self, args: pb2.Complete_Args) -> pb2.Complete_Result: - pos: pb2.Position = args.pos - name: str = args.name - code: str = args.code - - complete_items = grpc_wrapper.complete_wrapper(pos=pos, name=name, code=code) - return pb2.Complete_Result(completeItems=complete_items) - - def GoToDef(self, args: pb2.GoToDef_Args) -> pb2.GoToDef_Result: - pos: pb2.Position = args.pos - code: str = args.code - - locations = grpc_wrapper.go_to_def_wrapper(pos=pos, code=code) - return pb2.GoToDef_Result(locations=locations) - - def DocumentSymbol( - self, args: pb2.DocumentSymbol_Args - ) -> pb2.DocumentSymbol_Result: - file: str = args.file - code: str = args.code - symbol = grpc_wrapper.document_symbol_wrapper(file=file, code=code) - return pb2.DocumentSymbol_Result(symbol=symbol) - - def Hover(self, args: pb2.Hover_Args) -> pb2.Hover_Result: - pos: pb2.Position = args.pos - code: str = args.code - hover_result = grpc_wrapper.hover_wrapper(pos=pos, code=code) - return pb2.Hover_Result(hoverResult=hover_result) - - _kcl_go_exe: str = "" - - def ListDepFiles(self, args: pb2.ListDepFiles_Args) -> pb2.ListDepFiles_Result: - if not self._kcl_go_exe: - import os - - if os.name == "nt": - _executable_root = os.path.dirname(sys.executable) - self._kcl_go_exe = f"{_executable_root}/kcl-go.exe" - else: - _executable_root = os.path.dirname(os.path.dirname(sys.executable)) - self._kcl_go_exe = f"{_executable_root}/bin/kcl-go" - - # kcl-go list-app -use-fast-parser= -show-abs= -show-index=false - args = [ - self._kcl_go_exe, - "list-app", - f"-use-fast-parser={args.use_fast_parser}", - f"-include-all={args.include_all}", - f"-show-abs={args.use_abs_path}", - "-show-index=false", - args.work_dir, - ] - - proc = subprocess.run(args, capture_output=True, text=True) - stdout = str(proc.stdout or "").strip() - stderr = str(proc.stderr or "").strip() - - if proc.returncode != 0: - if stdout and stderr: - raise Exception(f"stdout: {stdout}, stderr: {stderr}") - else: - raise Exception(stdout if stdout else stderr) - - pkgroot: str = "" - pkgpath: str = "" - files: typing.List[str] = [] - - for s in stdout.splitlines(): - if s.startswith("pkgroot:"): - pkgroot = s[len("pkgroot:") :] - pkgroot = s.strip() - elif s.startswith("pkgpath:"): - pkgpath = s[len("pkgpath:") :] - pkgpath = s.strip() - else: - s = s.strip() - if s: - files.append(s) - - return pb2.ListDepFiles_Result(pkgroot=pkgroot, pkgpath=pkgpath, files=files) - - def LoadSettingsFiles( - self, args: pb2.LoadSettingsFiles_Args - ) -> pb2.LoadSettingsFiles_Result: - return kclvm.config.load_settings_files(args.work_dir, args.files) - - -def _makeRpcServer(): - rpc_server = protorpc.Server() - - # BuiltinService implementation (depends on rpc_server) - class BuiltinServiceImpl(pbrpc.BuiltinService): - def Ping(self, args: pb2.Ping_Args) -> pb2.Ping_Result: - return pb2.Ping_Result(value=args.value) - - def ListMethod(self, args: pb2.ListMethod_Args) -> pb2.ListMethod_Result: - return pb2.ListMethod_Result( - method_name_list=rpc_server.get_method_name_list() - ) - - # Metaclass for packaging services - builtin_service = pbrpc.BuiltinService_Meta( - typing.cast(pbrpc.BuiltinService, BuiltinServiceImpl()) - ) - kclvm_service = pbrpc.KclvmService_Meta( - typing.cast(pbrpc.KclvmService, KclvmServiceImpl()) - ) - - # Register service metaclass - rpc_server.register_service(builtin_service) - rpc_server.register_service(kclvm_service) - - return rpc_server - - -def runStdioProtorpcServer(): - """Start protorpc service based on stdin/stdout""" - - # Redirect stdout: raw_stdout raw_stdout will be used for protorpc communication - raw_stdout = sys.stdout - sys.stdout = sys.stderr - - # Start the service based on raw_stdout (blocking) - rpc_server = _makeRpcServer() - rpc_server.run(stdout=raw_stdout) - - -def runHttpServer(*, addr: str = "", port: int = 2021): - - rpc_server = _makeRpcServer() - - class MyHTTPServer(HTTPServer): - def server_bind(self): - self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1) - self.socket.bind(self.server_address) - - class httpHandler(BaseHTTPRequestHandler): - def do_GET(self): - - # http://localhost:2021/api:protorpc/BuiltinService.Ping - # http://localhost:2021/api:protorpc/BuiltinService.ListMethod - - # Build protorpc call - if self.path.startswith("/api:protorpc/"): - self.send_response(200) - self.send_header("Content-type", "application/json") - self.end_headers() - - from urllib.parse import urlparse - - u = urlparse(self.path) - method = u.path[len("/api:protorpc/") :] - - resp = {} - try: - result = rpc_server.call_method(method, b"{}", encoding="json") - resp["result"] = result - resp["error"] = "" - except kcl_error.KCLException as err: - resp["result"] = None - resp["error"] = f"{err}" - resp["kcl_err"] = kcl_err_to_response_dict(err) - except Exception as err: - resp["result"] = None - resp["error"] = f"{err}" - self.wfile.write(bytes(json.dumps(resp), "utf8")) - else: - self.send_response(200) - self.send_header("Content-type", "text/html") - self.end_headers() - - message = f"Hello, World! Here is a GET response: path={self.path}" - self.wfile.write(bytes(message, "utf8")) - - def do_POST(self): - self.send_response(200) - self.send_header("Content-type", "application/octet-stream") - self.end_headers() - - content_len = int(self.headers.get("Content-Length")) - req_body = self.rfile.read(content_len) - - # Build protorpc call - if self.path.startswith("/api:protorpc/"): - method = self.path[len("/api:protorpc/") :] - resp = {} - try: - result = rpc_server.call_method(method, req_body, encoding="json") - resp["result"] = result - resp["error"] = "" - except kcl_error.KCLException as err: - resp["result"] = None - resp["error"] = f"{err}" - resp["kcl_err"] = kcl_err_to_response_dict(err) - except Exception as err: - resp["result"] = None - resp["error"] = f"{err}" - self.wfile.write(bytes(json.dumps(resp), "utf8")) - else: - message = f"Hello, World! Here is a POST response: path={self.path}" - self.wfile.write(bytes(message, "utf8")) - - print(f"run http server on http://{addr}:{port} ...") - - with MyHTTPServer(("", port), httpHandler) as server: - server.serve_forever() - - -def runFastApiServer(*, addr: str = "", port: int = 2021): - import uvicorn - - app = create_app() - uvicorn.run(app, host=addr, port=port) - - -def kcl_err_to_response_dict(err: kcl_error.KCLException) -> pb2.KclError: - return _json_format.MessageToDict( - pb2.KclError( - ewcode=f"{err.ewcode}", - name=f"{err.name}", - msg=f"{err.arg_msg}", - error_infos=[ - pb2.KclErrorInfo( - err_level=f"{err_info.err_level}", - arg_msg=f"{err_info.arg_msg}", - filename=f"{err_info.filename}", - src_code=f"{kcl_err_template.get_src_code(err_info)}", - line_no=f"{err_info.line_no}", - col_no=f"{err_info.col_no}", - ) - for err_info in err.err_info_stack - ], - ), - including_default_value_fields=True, - preserving_proto_field_name=True, - ) - - -# ./gunicorn "kclvm.program.rpc-server:create_app()" -w 4 -k uvicorn.workers.UvicornWorker -b :2021 -def create_app(): - import fastapi - - app = fastapi.FastAPI() - rpc_server = _makeRpcServer() - - @app.get("/") - async def index(): - return "KCL Rest Server" - - @app.get("/api:protorpc/{method}") - async def on_rest_api_get(method: str, request: fastapi.Request): - resp = {} - try: - result = rpc_server.call_method(method, b"{}", encoding="json") - resp["result"] = result - resp["error"] = "" - except kcl_error.KCLException as err: - resp["result"] = None - resp["error"] = f"{err}" - resp["kcl_err"] = kcl_err_to_response_dict(err) - except Exception as err: - resp["result"] = None - resp["error"] = f"{err}" - - return resp - - @app.post("/api:protorpc/{method}") - async def on_rest_api_post(method: str, request: bytes = fastapi.Body(...)): - resp = {} - try: - result = rpc_server.call_method(method, request, encoding="json") - resp["result"] = result - resp["error"] = "" - except kcl_error.KCLException as err: - resp["result"] = None - resp["error"] = f"{err}" - resp["kcl_err"] = kcl_err_to_response_dict(err) - except Exception as err: - resp["result"] = None - resp["error"] = f"{err}" - - return resp - - return app - - -def main(): - flags = parse_flags(sys.argv[1:]) - - if flags.help: - print(USAGE) - sys.exit(0) - - from kclvm.compiler.parser.lark_parser import GetKclLarkParser - - GetKclLarkParser() - - if flags.http_addr or flags.http_port: - print(f"flags: {flags}") - if not flags.use_http_server: - runFastApiServer(addr=flags.http_addr, port=flags.http_port) - else: - runHttpServer(addr=flags.http_addr, port=flags.http_port) - sys.exit(0) - else: - runStdioProtorpcServer() - sys.exit(0) - - -if __name__ == "__main__": - main() diff --git a/internal/kclvm_py/scripts/build-cpython.sh b/internal/kclvm_py/scripts/build-cpython.sh deleted file mode 100755 index c83f26f31..000000000 --- a/internal/kclvm_py/scripts/build-cpython.sh +++ /dev/null @@ -1,86 +0,0 @@ -#!/usr/bin/env bash - -# Stop on error. -set -e - -prepare_dirs () { - cpython_build_dir="$topdir/_build/build/$os/cpython" - mkdir -p "$cpython_build_dir" - cpython_install_dir="$topdir/_build/dist/$os/cpython" - mkdir -p "$cpython_install_dir" -} - -# Switch configuration options. -config_option="Default" -if [ "$os" != "" ]; then - config_option=$os -fi - -# python version -py_ver_major="3" -py_ver_minor="7" -py_ver_micro="6" - -for config in "$config_option" -do - case $config in - "Default" | "centos") - config_envs="LANG=C.UTF-8" - config_options="--enable-optimizations --with-ssl" - echo "$REPLY: The configuration is $config: config_envs=$config_envs config_options=$config_options" - break - ;; - "Darwin") - if [ "$sslpath" == "" ]; then - sslpath=$(brew --prefix openssl@1.1) - fi - - if [ x"$(uname -m)" == x"arm64" ]; then - py_ver_major="3" - py_ver_minor="9" - py_ver_micro="12" - fi - - config_envs="LANG=C.UTF-8" - config_options="--enable-optimizations --with-openssl=$sslpath --with-ssl-default-suites=python" - echo "$REPLY: The configuration is $config: config_envs=$config_envs config_options=$config_options" - break - ;; - "ubuntu" | "debian" | "Ubuntu" |"Debian" | "Static-Debian" | "Cood1-Debian" | "Cood1Shared-Debian") - config_envs="CFLAGS=-Wno-coverage-mismatch" - config_options="--enable-optimizations --with-ssl" - echo "$REPLY: The configuration is $config: config_envs=$config_envs config_options=$config_options" - break - ;; - *) echo "Invalid config option $REPLY:$config" - exit 1 - break - ;; - esac -done - -# py_ver_str="$(python3 -c 'import os; print(os.path.basename(os.path.dirname(os.__file__)))')" -py_ver_str="${py_ver_major}.${py_ver_minor}.${py_ver_micro}" - -# wget python -mkdir -p $topdir/_build/3rdparty -wget -P $topdir/_build/3rdparty "https://www.python.org/ftp/python/${py_ver_str}/Python-${py_ver_str}.tgz" -tar zxvf $topdir/_build/3rdparty/Python-${py_ver_str}.tgz -C $topdir/_build/3rdparty - -prepare_dirs -prefix_option="--prefix=$cpython_install_dir" -cpython_source_dir="$topdir/_build/3rdparty/Python-${py_ver_str}" - -# Perform the configuration/make/make install process. -set -x -cd $cpython_build_dir -eval $config_envs $cpython_source_dir/configure $prefix_option $config_options -# The make -j command may fail on some OS. -# make -j "$(nproc)" -make -j8 build_all -make -j8 altinstall -set +x - -# Print the summary. -echo "================ Summary ================" -echo " CPython is built into $cpython_build_dir" \ No newline at end of file diff --git a/internal/kclvm_py/scripts/build-kclvm.sh b/internal/kclvm_py/scripts/build-kclvm.sh deleted file mode 100755 index 71ef4ff76..000000000 --- a/internal/kclvm_py/scripts/build-kclvm.sh +++ /dev/null @@ -1,73 +0,0 @@ -#!/usr/bin/env bash - -# Stop on error. -set -e - -prepare_dirs () { - cpython_build_dir="$topdir/_build/dist/$os/cpython" - kclvm_packages_dir="$topdir/_build/packages" - kclvm_install_dir="$topdir/_build/dist/$os/kclvm" - mkdir -p "$kclvm_install_dir" - mkdir -p "$kclvm_packages_dir" -} - -prepare_dirs -kclvm_source_dir="$topdir/internal/kclvm_py" - -# python exe name -py_exe_name="python3.7" -if [ -d "${cpython_build_dir}/lib/python3.9" ]; then - py_exe_name="python3.9" -fi - -# py_lib_basename: python3.x -py_lib_basename="python3.7" -if [ -d "${cpython_build_dir}/lib/python3.9" ]; then - py_lib_basename="python3.9" -fi - -# Perform the build process. -set -x - -# Copy files from CPython. -cd $kclvm_install_dir -mkdir -p bin -mkdir -p lib -cp $cpython_build_dir/bin/${py_exe_name} $kclvm_install_dir/bin/kclvm -cp -r $cpython_build_dir/lib/${py_lib_basename} $kclvm_install_dir/lib/ -cp -r $cpython_build_dir/include $kclvm_install_dir/ - -# Copy KCLVM. -cp "$topdir/internal/kclvm_py/scripts/cli/kcl" $kclvm_install_dir/bin/ -cp "$topdir/internal/kclvm_py/scripts/cli/kcl-plugin" $kclvm_install_dir/bin/ -cp "$topdir/internal/kclvm_py/scripts/cli/kcl-doc" $kclvm_install_dir/bin/ -cp "$topdir/internal/kclvm_py/scripts/cli/kcl-test" $kclvm_install_dir/bin/ -cp "$topdir/internal/kclvm_py/scripts/cli/kcl-lint" $kclvm_install_dir/bin/ -cp "$topdir/internal/kclvm_py/scripts/cli/kcl-fmt" $kclvm_install_dir/bin/ -cp "$topdir/internal/kclvm_py/scripts/cli/kcl-vet" $kclvm_install_dir/bin/ -chmod +x $kclvm_install_dir/bin/kcl -chmod +x $kclvm_install_dir/bin/kcl-plugin -chmod +x $kclvm_install_dir/bin/kcl-doc -chmod +x $kclvm_install_dir/bin/kcl-test -chmod +x $kclvm_install_dir/bin/kcl-lint -chmod +x $kclvm_install_dir/bin/kcl-fmt -chmod +x $kclvm_install_dir/bin/kcl-vet - -if [ -d $kclvm_install_dir/lib/${py_lib_basename}/kclvm ]; then - rm -rf $kclvm_install_dir/lib/${py_lib_basename}/kclvm -fi -cp -r $kclvm_source_dir $kclvm_install_dir/lib/${py_lib_basename} -mv $kclvm_install_dir/lib/${py_lib_basename}/kclvm_py $kclvm_install_dir/lib/${py_lib_basename}/kclvm - -# Get site-packages. -chmod +x $topdir/internal/kclvm_py/scripts/kcllib-install.sh -$topdir/internal/kclvm_py/scripts/kcllib-install.sh - -# Install plugins -cp -rf $topdir/plugins $kclvm_install_dir/ - -set +x - -# Print the summary. -echo "================ Summary ================" -echo " KCLVM is installed into $kclvm_install_dir" diff --git a/internal/kclvm_py/scripts/build.sh b/internal/kclvm_py/scripts/build.sh deleted file mode 100755 index a7f223c53..000000000 --- a/internal/kclvm_py/scripts/build.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/usr/bin/env bash - -os=$os topdir=$topdir sslpath=$sslpath $topdir/internal/kclvm_py/scripts/build-cpython.sh -os=$os topdir=$topdir $topdir/internal/kclvm_py/scripts/build-kclvm.sh diff --git a/internal/kclvm_py/scripts/cli/kcl b/internal/kclvm_py/scripts/cli/kcl deleted file mode 100755 index 63cd3eaea..000000000 --- a/internal/kclvm_py/scripts/cli/kcl +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/sh - -kclvm_path=$(cd `dirname $0`; pwd)/kclvm -export PATHONPATH='' -$kclvm_path -m kclvm "$@" diff --git a/internal/kclvm_py/scripts/cli/kcl-doc b/internal/kclvm_py/scripts/cli/kcl-doc deleted file mode 100755 index e49fd8e15..000000000 --- a/internal/kclvm_py/scripts/cli/kcl-doc +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/sh - -kclvm_path=$(cd `dirname $0`; pwd)/kclvm -export PATHONPATH='' -$kclvm_path -m kclvm.tools.docs "$@" diff --git a/internal/kclvm_py/scripts/cli/kcl-fmt b/internal/kclvm_py/scripts/cli/kcl-fmt deleted file mode 100755 index db13541a8..000000000 --- a/internal/kclvm_py/scripts/cli/kcl-fmt +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/sh - -kclvm_path=$(cd `dirname $0`; pwd)/kclvm -export PATHONPATH='' -$kclvm_path -m kclvm.tools.format "$@" diff --git a/internal/kclvm_py/scripts/cli/kcl-lint b/internal/kclvm_py/scripts/cli/kcl-lint deleted file mode 100755 index cdde2eb1f..000000000 --- a/internal/kclvm_py/scripts/cli/kcl-lint +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/sh - -kclvm_path=$(cd `dirname $0`; pwd)/kclvm -export PATHONPATH='' -$kclvm_path -m kclvm.tools.lint.lint "$@" diff --git a/internal/kclvm_py/scripts/cli/kcl-plugin b/internal/kclvm_py/scripts/cli/kcl-plugin deleted file mode 100755 index a6b35c267..000000000 --- a/internal/kclvm_py/scripts/cli/kcl-plugin +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/sh - -kclvm_path=$(cd `dirname $0`; pwd)/kclvm -export PATHONPATH='' -$kclvm_path -m kclvm.tools.plugin "$@" diff --git a/internal/kclvm_py/scripts/cli/kcl-test b/internal/kclvm_py/scripts/cli/kcl-test deleted file mode 100755 index 05327dbff..000000000 --- a/internal/kclvm_py/scripts/cli/kcl-test +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/sh - -kcl_go_path=$(cd `dirname $0`; pwd)/kcl-go -if [[ ! -f $kcl_go_path ]]; then - echo "kcl-go not found, please check the installation" - exit 1 -fi -export PATHONPATH='' -$kcl_go_path test "$@" diff --git a/internal/kclvm_py/scripts/cli/kcl-vet b/internal/kclvm_py/scripts/cli/kcl-vet deleted file mode 100755 index 723a923f5..000000000 --- a/internal/kclvm_py/scripts/cli/kcl-vet +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/sh - -kclvm_path=$(cd `dirname $0`; pwd)/kclvm -export PATHONPATH='' -$kclvm_path -m kclvm.tools.validation "$@" diff --git a/internal/kclvm_py/scripts/format.sh b/internal/kclvm_py/scripts/format.sh deleted file mode 100755 index 8e83370f8..000000000 --- a/internal/kclvm_py/scripts/format.sh +++ /dev/null @@ -1,23 +0,0 @@ -#!/usr/bin/env bash - -# Stop on error. -set -e - -root="$topdir" -kclvm_src="$topdir/internal/kclvm_py" - -# 使用中文环境 -#export LANGUAGE=zh_CN.utf-8 - -# or English Env -export LANGUAGE=en_US.utf-8 - -# Install black format tools -python3 -m pip install black==21.5b1 - -# Run the black format -python3 -m black $kclvm_src --extend-exclude .*?_pb2.py\|lark_token.py - -# Print the summary. -echo "================ Format Summary ================" -echo "black format done successfully in $root" diff --git a/internal/kclvm_py/scripts/kcllib-install.sh b/internal/kclvm_py/scripts/kcllib-install.sh deleted file mode 100755 index 1b5e74ad5..000000000 --- a/internal/kclvm_py/scripts/kcllib-install.sh +++ /dev/null @@ -1,7 +0,0 @@ - -# kclvm path -kclvm=$topdir/_build/dist/$os/kclvm/bin/kclvm -install_list=$topdir/internal/kclvm_py/scripts/requirements.txt - -# kclvm pip install all libs -$kclvm -m pip install -r $install_list diff --git a/internal/kclvm_py/scripts/lint-check.sh b/internal/kclvm_py/scripts/lint-check.sh deleted file mode 100755 index 131c286ea..000000000 --- a/internal/kclvm_py/scripts/lint-check.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/usr/bin/env bash - -# Stop on error. -set -e - -root="$topdir" -kclvm_install_dir="$topdir/_build/dist/$os/kclvm" - -# or English Env -export LANGUAGE=en_US.utf-8 - -# Install flake8 lint tools and run linting. -$kclvm_install_dir/bin/kclvm -m pip install flake8==4.0.0 -$kclvm_install_dir/bin/kclvm -m flake8 --config ./.flake8 ./internal/kclvm_py - -# Print the summary. -echo "================ Lint Summary ================" -echo " Lint done successfully in $root" diff --git a/internal/kclvm_py/scripts/release.sh b/internal/kclvm_py/scripts/release.sh deleted file mode 100755 index 658e3370c..000000000 --- a/internal/kclvm_py/scripts/release.sh +++ /dev/null @@ -1,17 +0,0 @@ -#!/usr/bin/env bash - -kclvm_release_file="kclvm-$os-latest.tar.gz" -kclvm_release_path="$topdir/_build" -kclvm_package_dir="$topdir/_build/dist/$os" -kclvm_install_dir="kclvm" - -rm $kclvm_release_file - -cd $kclvm_package_dir -tar -czvf $kclvm_release_file $kclvm_install_dir - -mv $kclvm_package_dir/$kclvm_release_file $kclvm_release_path/$kclvm_release_file - -# Print the summary. -echo "================ Summary ================" -echo " $kclvm_release_path/$kclvm_release_file has been created" diff --git a/internal/kclvm_py/scripts/requirements.txt b/internal/kclvm_py/scripts/requirements.txt deleted file mode 100644 index 0bb05437b..000000000 --- a/internal/kclvm_py/scripts/requirements.txt +++ /dev/null @@ -1,25 +0,0 @@ -wheel==0.34.2 -twine==3.2.0 -pyyaml==5.4 -pytest-xdist==2.2.1 -lark-parser==0.11.3 -filelock==3.6.0 -yapf==0.29.0 -pytest==6.2.2 -pypeg2==2.15.2 -protobuf==3.19.4 -gevent==20.9 -grequests -schema -coverage -ruamel.yaml -toml -numpydoc -pygls==0.10.3 -fastapi -uvicorn -gunicorn==20.1.0 -parsy==1.3.0 -wasmer==1.0.0 -wasmer_compiler_cranelift==1.0.0 -pyopenssl diff --git a/internal/kclvm_py/scripts/test.sh b/internal/kclvm_py/scripts/test.sh deleted file mode 100755 index 08de06049..000000000 --- a/internal/kclvm_py/scripts/test.sh +++ /dev/null @@ -1,69 +0,0 @@ -#!/usr/bin/env bash -RED='\033[0;31m' -function red() { - printf "${RED}$@${NC}\n" -} - -if [ "$?" -ne 0 ]; then - echo $(red update gitsubmodule failed! exit...) - exit 1 -fi - -# Options -help_message=$(cat <<-END - Usage: - test.sh -h - Print this help message - test.sh -a [action] - Perform a test - test.sh - Perform a test interactively - Available actions: - test_unit - trigger unit test - test_grammar - trigger grammar test - all - trigger all tests -END -) -action= -while getopts "a:h:s:" opt; do - case $opt in - a) - action="$OPTARG" - ;; - h) - echo "$help_message" - exit 1 - ;; - \?) echo "Invalid option -$OPTARG" - ;; - esac -done - -if [ "$action" == "" ]; then - PS3='Please select the test scope: ' - options=("test_unit" "test_grammar" "all") - select action in "${options[@]}" - do - case $action in - "test_unit") - $topdir/internal/kclvm_py/scripts/test_unit.sh - break - ;; - "test_grammar") - $topdir/internal/kclvm_py/scripts/test_grammar.sh - break - ;; - "all") - $topdir/internal/kclvm_py/scripts/test_unit.sh && $topdir/internal/kclvm_py/scripts/test_grammar.sh - break - ;; - *) echo "Invalid action $REPLY:$action" - exit 1 - break - ;; - esac - done -fi diff --git a/internal/kclvm_py/scripts/test_grammar.sh b/internal/kclvm_py/scripts/test_grammar.sh deleted file mode 100755 index 168d8e3a2..000000000 --- a/internal/kclvm_py/scripts/test_grammar.sh +++ /dev/null @@ -1,12 +0,0 @@ -#!/usr/bin/env bash - -topdir=$(realpath $(dirname $0)/../../../) -kclvm_install_dir="$topdir/_build/dist/$os/kclvm" -kclvm_source_dir="$topdir" - -echo PATH=$PATH:$kclvm_source_dir/_build/dist/ubuntu/kclvm/bin >> ~/.bash_profile -source ~/.bash_profile - -# Grammar test -cd $kclvm_source_dir/test/grammar -kclvm -m pytest -v -n 10 diff --git a/internal/kclvm_py/scripts/test_unit.sh b/internal/kclvm_py/scripts/test_unit.sh deleted file mode 100755 index 245927847..000000000 --- a/internal/kclvm_py/scripts/test_unit.sh +++ /dev/null @@ -1,15 +0,0 @@ -#!/usr/bin/env bash - -topdir=$(realpath $(dirname $0)/../../../) -kclvm_install_dir="$topdir/_build/dist/$os/kclvm" -kclvm_source_dir="$topdir" - -echo PATH=$PATH:$kclvm_source_dir/_build/dist/ubuntu/kclvm/bin >> ~/.bash_profile -source ~/.bash_profile - -# Install the dependency -kclvm -m pip install nose==1.3.7 - -# Unit test -cd $kclvm_source_dir/test/test_units/ -kclvm -m nose diff --git a/internal/kclvm_py/scripts/unittest_coverage.sh b/internal/kclvm_py/scripts/unittest_coverage.sh deleted file mode 100755 index f1ad80de1..000000000 --- a/internal/kclvm_py/scripts/unittest_coverage.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/sh - -# --------------------------------------------------------------------------------- -# Show the unit test coverage report -# For more info, see the -# [Python Coverage Documents](https://coverage.readthedocs.io/en/latest/) -# TODO: Using more mature tools and practices. e.g. -# https://github.com/CleanCut/green -# https://github.com/oldani/HtmlTestRunner -# --------------------------------------------------------------------------------- - -src="$(realpath $(dirname $0))/../" -unittest_path=$src/test/test_units/ -package_name=kclvm -xunit_file=TEST-kclvm.xml - -# Install the dependency -kclvm -m pip install nose==1.3.7 -# Run test with coverage output -kclvm -m nose --cover-package $package_name --with-coverage --cover-xml --cover-html --cover-erase --with-xunit --xunit-file=$xunit_file --tests=$unittest_path diff --git a/internal/kclvm_py/scripts/update-kclvm.sh b/internal/kclvm_py/scripts/update-kclvm.sh deleted file mode 100755 index 6d1b9e113..000000000 --- a/internal/kclvm_py/scripts/update-kclvm.sh +++ /dev/null @@ -1,137 +0,0 @@ -#!/usr/bin/env bash - -# Stop on error. -set -e - -prepare_dirs () { - cpython_build_dir="$topdir/_build/dist/$os/cpython" - kclvm_packages_dir="$topdir/_build/packages" - kclvm_install_dir="$topdir/_build/dist/$os/kclvm" - mkdir -p "$kclvm_install_dir" - mkdir -p "$kclvm_packages_dir" -} - -prepare_dirs -kclvm_source_dir="$topdir/internal" - -# Perform the build process. -set -x - -# Copy KCLVM. -cp "$topdir/internal/kclvm_py/scripts/cli/kcl" $kclvm_install_dir/bin/ -cp "$topdir/internal/kclvm_py/scripts/cli/kcl-plugin" $kclvm_install_dir/bin/ -cp "$topdir/internal/kclvm_py/scripts/cli/kcl-doc" $kclvm_install_dir/bin/ -cp "$topdir/internal/kclvm_py/scripts/cli/kcl-test" $kclvm_install_dir/bin/ -cp "$topdir/internal/kclvm_py/scripts/cli/kcl-lint" $kclvm_install_dir/bin/ -cp "$topdir/internal/kclvm_py/scripts/cli/kcl-fmt" $kclvm_install_dir/bin/ -cp "$topdir/internal/kclvm_py/scripts/cli/kcl-vet" $kclvm_install_dir/bin/ -chmod +x $kclvm_install_dir/bin/kcl -chmod +x $kclvm_install_dir/bin/kcl-plugin -chmod +x $kclvm_install_dir/bin/kcl-doc -chmod +x $kclvm_install_dir/bin/kcl-test -chmod +x $kclvm_install_dir/bin/kcl-lint -chmod +x $kclvm_install_dir/bin/kcl-fmt -chmod +x $kclvm_install_dir/bin/kcl-vet - -kclvm_lib_dir=$kclvm_install_dir/lib/python3.7/ -if [ -d $kclvm_install_dir/lib/python3.9/ ]; then - kclvm_lib_dir=$kclvm_install_dir/lib/python3.9/ -fi - -if [ -d $kclvm_lib_dir/kclvm ]; then - rm -rf $kclvm_lib_dir/kclvm -fi -cp -r $kclvm_source_dir/kclvm_py $kclvm_lib_dir/kclvm - -set +x - -# build kclvm-cli - -cd $topdir/kclvm -cargo build --release - -touch $kclvm_install_dir/bin/kclvm_cli -rm $kclvm_install_dir/bin/kclvm_cli -cp ./target/release/kclvm_cli $kclvm_install_dir/bin/kclvm_cli - -# libkclvm_cli - -# Darwin dylib -if [ -e target/release/libkclvm_cli_cdylib.dylib ]; then - touch $kclvm_install_dir/bin/libkclvm_cli_cdylib.dylib - rm $kclvm_install_dir/bin/libkclvm_cli_cdylib.dylib - cp target/release/libkclvm_cli_cdylib.dylib $kclvm_install_dir/bin/libkclvm_cli_cdylib.dylib -fi -# Linux so -if [ -e target/release/libkclvm_cli_cdylib.so ]; then - touch $kclvm_install_dir/bin/libkclvm_cli_cdylib.so - rm $kclvm_install_dir/bin/libkclvm_cli_cdylib.so - cp target/release/libkclvm_cli_cdylib.so $kclvm_install_dir/bin/libkclvm_cli_cdylib.so -fi -# Windows dll -if [ -e target/release/libkclvm_cli_cdylib.dll ]; then - touch $kclvm_install_dir/bin/libkclvm_cli_cdylib.dll - rm $kclvm_install_dir/bin/libkclvm_cli_cdylib.dll - cp target/release/libkclvm_cli_cdylib.dll $kclvm_install_dir/bin/libkclvm_cli_cdylib.dll -fi - - -# build rust std lib - -RUST_SYS_ROOT=`rustc --print sysroot` - -# libstd-*.dylib or libstd-*.so -cd $RUST_SYS_ROOT/lib -RUST_LIBSTD=`find libstd-*.*` - -mkdir -p $kclvm_install_dir/lib -cp "$RUST_SYS_ROOT/lib/$RUST_LIBSTD" $kclvm_install_dir/lib/$RUST_LIBSTD -echo "$RUST_LIBSTD" > $kclvm_install_dir/lib/rust-libstd-name.txt - -# Build kclvm runtime - -cd $topdir/kclvm/runtime -## Native -cargo build --release -cp target/release/libkclvm.a $kclvm_install_dir/lib/libkclvm_native.a - -# Darwin dylib -if [ -e target/release/libkclvm.dylib ]; then - touch $kclvm_install_dir/lib/libkclvm.dylib - rm $kclvm_install_dir/lib/libkclvm.dylib - cp target/release/libkclvm.dylib $kclvm_install_dir/lib/ - cp target/release/libkclvm.dylib $kclvm_install_dir/lib/libkclvm_native_shared.dylib -fi -# Linux so -if [ -e target/release/libkclvm.so ]; then - touch $kclvm_install_dir/lib/libkclvm.so - rm $kclvm_install_dir/lib/libkclvm.so - cp target/release/libkclvm.so $kclvm_install_dir/lib/ - cp target/release/libkclvm.so $kclvm_install_dir/lib/libkclvm_native_shared.so -fi -# Windows dll -if [ -e target/release/libkclvm.dll ]; then - touch $kclvm_install_dir/lib/libkclvm.dll - rm $kclvm_install_dir/lib/libkclvm.dll - cp target/release/libkclvm.dll $kclvm_install_dir/lib/ - cp target/release/libkclvm.dll $kclvm_install_dir/lib/libkclvm_native_shared.dll -fi - -# WASM -cargo build --release --target wasm32-unknown-unknown -cp target/wasm32-unknown-unknown/release/libkclvm.a $kclvm_install_dir/lib/libkclvm_wasm32.a -cp src/_kclvm_undefined_wasm.txt $kclvm_install_dir/lib/_kclvm_undefined_wasm.txt - -cp src/_kclvm.bc $kclvm_install_dir/include/_kclvm.bc -cp src/_kclvm.h $kclvm_install_dir/include/_kclvm.h - -cd $kclvm_install_dir/include - -# build kclvm_plugin python module - -cd $topdir/kclvm/plugin -kclvm setup.py install_lib - -# Print the summary. -echo "================ Summary ================" -echo " KCLVM is updated into $kclvm_install_dir" diff --git a/internal/kclvm_py/spec/Makefile b/internal/kclvm_py/spec/Makefile deleted file mode 100644 index 6f98429a4..000000000 --- a/internal/kclvm_py/spec/Makefile +++ /dev/null @@ -1,43 +0,0 @@ -# Copyright 2021 The KCL Authors. All rights reserved. - -default: - go install github.com/golang/protobuf/protoc-gen-go@latest - - mkdir -p ./_output - - # modfile - protoc -I. --python_out=./_output ./modfile/modfile.proto - - cp ./_output/modfile/modfile_pb2.py \ - ../config/modfile_pb2.py - - # gpyrpc - protoc -I. --python_out=./_output ./gpyrpc/gpyrpc.proto ./gpyrpc/protorpc_wire.proto - - mkdir -p ../internal/gpyrpc - cp ./_output/gpyrpc/gpyrpc_pb2.py \ - ../internal/gpyrpc/gpyrpc_pb2.py - cp ./_output/gpyrpc/protorpc_wire_pb2.py \ - ../internal/gpyrpc/protorpc_wire_pb2.py - - # protorpc - protoc -I. --python_out=./_output ./gpyrpc/protorpc_wire.proto - make protorpc-stub - - -rm -rf ./_output - -protorpc-stub: - cd ./gpyrpc/protoc-gen-protorpc-py && go fmt \ - && go install github.com/golang/protobuf/protoc-gen-go@latest \ - && go install . - - cd gpyrpc && protoc --protorpc-py_out=. gpyrpc.proto - cp ./gpyrpc/kusionstack.io/kclvm-go/pkg/spec/gpyrpc/gpyrpc.pb.protorpc.py \ - ../internal/gpyrpc/gpyrpc_pb_protorpc.py - - -rm -rf ./gpyrpc/kusionstack.io - - cd .. && make format - -clean: - -rm -rf ./_output diff --git a/internal/kclvm_py/spec/gpyrpc/gpyrpc.proto b/internal/kclvm_py/spec/gpyrpc/gpyrpc.proto deleted file mode 100644 index d9a6dfecf..000000000 --- a/internal/kclvm_py/spec/gpyrpc/gpyrpc.proto +++ /dev/null @@ -1,395 +0,0 @@ -// Copyright 2021 The KCL Authors. All rights reserved. -// -// This file defines the request parameters and return structure of the KCLVM RPC server. -// We can use the following command to start a KCLVM RPC server. -// -// ``` -// kclvm -m kclvm.program.rpc-server -http=:2021 -// ``` -// -// The service can then be requested via the POST protocol: -// -// ``` -// $ curl -X POST http://127.0.0.1:2021/api:protorpc/BuiltinService.Ping --data '{}' -// { -// "error": "", -// "result": {} -// } -// ``` - -syntax = "proto3"; - -package gpyrpc; - -option go_package = "kusionstack.io/kclvm-go/pkg/spec/gpyrpc;gpyrpc"; - -import "google/protobuf/any.proto"; -import "google/protobuf/descriptor.proto"; - -// ---------------------------------------------------------------------------- - -// kcl main.k -D name=value -message CmdArgSpec { - string name = 1; - string value = 2; // TODO: any? -} - -// kcl main.k -O pkgpath:path.to.field=field_value -message CmdOverrideSpec { - string pkgpath = 1; - string field_path = 2; - string field_value = 3; - string action = 4; -} - -// ---------------------------------------------------------------------------- -// gpyrpc request/response/error types -// ---------------------------------------------------------------------------- - -message RestResponse { - google.protobuf.Any result = 1; - string error = 2; - KclError kcl_err = 3; -} - -message KclError { - string ewcode = 1; // See kclvm/kcl/error/kcl_err_msg.py - string name = 2; - string msg = 3; - repeated KclErrorInfo error_infos = 4; -} - -message KclErrorInfo { - string err_level = 1; - string arg_msg = 2; - string filename = 3; - string src_code = 4; - string line_no = 5; - string col_no = 6; -} - -// ---------------------------------------------------------------------------- -// service requset/response -// ---------------------------------------------------------------------------- - -// gpyrpc.BuiltinService -service BuiltinService { - rpc Ping(Ping_Args) returns(Ping_Result); - rpc ListMethod(ListMethod_Args) returns(ListMethod_Result); -} - -// gpyrpc.KclvmService -service KclvmService { - rpc Ping(Ping_Args) returns(Ping_Result); - - rpc ParseFile_LarkTree(ParseFile_LarkTree_Args) returns(ParseFile_LarkTree_Result); - rpc ParseFile_AST(ParseFile_AST_Args) returns(ParseFile_AST_Result); - rpc ParseProgram_AST(ParseProgram_AST_Args) returns(ParseProgram_AST_Result); - - rpc ExecProgram(ExecProgram_Args) returns(ExecProgram_Result); - - rpc ResetPlugin(ResetPlugin_Args) returns(ResetPlugin_Result); - - rpc FormatCode(FormatCode_Args) returns(FormatCode_Result); - rpc FormatPath(FormatPath_Args) returns(FormatPath_Result); - rpc LintPath(LintPath_Args) returns(LintPath_Result); - rpc OverrideFile(OverrideFile_Args) returns (OverrideFile_Result); - - rpc EvalCode(EvalCode_Args) returns(EvalCode_Result); - rpc ResolveCode(ResolveCode_Args) returns(ResolveCode_Result); - rpc GetSchemaType(GetSchemaType_Args) returns(GetSchemaType_Result); - rpc ValidateCode(ValidateCode_Args) returns(ValidateCode_Result); - rpc SpliceCode(SpliceCode_Args) returns(SpliceCode_Result); - - rpc Complete(Complete_Args) returns(Complete_Result); - rpc GoToDef(GoToDef_Args) returns(GoToDef_Result); - rpc DocumentSymbol(DocumentSymbol_Args) returns(DocumentSymbol_Result); - rpc Hover(Hover_Args) returns(Hover_Result); - - rpc ListDepFiles(ListDepFiles_Args) returns(ListDepFiles_Result); - rpc LoadSettingsFiles(LoadSettingsFiles_Args) returns(LoadSettingsFiles_Result); -} - -message Ping_Args { - string value = 1; -} -message Ping_Result { - string value = 1; -} - -message ListMethod_Args { - // empty -} -message ListMethod_Result { - repeated string method_name_list = 1; -} - -message ParseFile_LarkTree_Args { - string filename = 1; - string source_code = 2; - bool ignore_file_line = 3; -} -message ParseFile_LarkTree_Result { - string lark_tree_json = 1; -} - -message ParseFile_AST_Args { - string filename = 1; - string source_code = 2; -} -message ParseFile_AST_Result { - string ast_json = 1; // json value -} - -message ParseProgram_AST_Args { - repeated string k_filename_list = 1; -} -message ParseProgram_AST_Result { - string ast_json = 1; // json value -} - -message ExecProgram_Args { - string work_dir = 1; - - repeated string k_filename_list = 2; - repeated string k_code_list = 3; - - repeated CmdArgSpec args = 4; - repeated CmdOverrideSpec overrides = 5; - - bool disable_yaml_result = 6; - - bool print_override_ast = 7; - - // -r --strict-range-check - bool strict_range_check = 8; - - // -n --disable-none - bool disable_none = 9; - // -v --verbose - int32 verbose = 10; - - // -d --debug - int32 debug = 11; - - // yaml/json: sort keys - bool sort_keys = 12; - // include schema type path in JSON/YAML result - bool include_schema_type_path = 13; -} -message ExecProgram_Result { - string json_result = 1; - string yaml_result = 2; - - string escaped_time = 101; -} - -message ResetPlugin_Args { - string plugin_root = 1; -} -message ResetPlugin_Result { - // empty -} - -message FormatCode_Args { - string source = 1; -} - -message FormatCode_Result { - bytes formatted = 1; -} - -message FormatPath_Args { - string path = 1; -} - -message FormatPath_Result { - repeated string changedPaths = 1; -} - -message LintPath_Args { - string path = 1; -} - -message LintPath_Result { - repeated string results = 1; -} - -message OverrideFile_Args { - string file = 1; - repeated string specs = 2; - repeated string import_paths = 3; -} - -message OverrideFile_Result { - bool result = 1; -} - -message EvalCode_Args { - string code = 1; -} -message EvalCode_Result { - string json_result = 2; -} - -message ResolveCode_Args { - string code = 1; -} - -message ResolveCode_Result { - bool success = 1; -} - -message GetSchemaType_Args { - string file = 1; - string code = 2; - string schema_name = 3; // emtry is all -} -message GetSchemaType_Result { - repeated KclType schema_type_list = 1; -} - -message ValidateCode_Args { - string data = 1; - string code = 2; - string schema = 3; - string attribute_name = 4; - string format = 5; -} - -message ValidateCode_Result { - bool success = 1; - string err_message = 2; -} - -message CodeSnippet { - string schema = 1; - string rule = 2; -} - -message SpliceCode_Args { - repeated CodeSnippet codeSnippets = 1; -} - -message SpliceCode_Result { - string spliceCode = 1; -} - -message Position { - int64 line = 1; - int64 column = 2; - string filename = 3; -} - -message Complete_Args { - Position pos = 1; - string name = 2; - string code = 3; -} - -message Complete_Result { - string completeItems = 1; -} - -message GoToDef_Args { - Position pos = 1; - string code = 2; -} - -message GoToDef_Result { - string locations = 1; -} - -message DocumentSymbol_Args { - string file = 1; - string code = 2; -} - -message DocumentSymbol_Result { - string symbol = 1; -} - -message Hover_Args { - Position pos = 1; - string code = 2; -} - -message Hover_Result { - string hoverResult = 1; -} - -message ListDepFiles_Args { - string work_dir = 1; - bool use_abs_path = 2; - bool include_all = 3; - bool use_fast_parser = 4; -} - -message ListDepFiles_Result { - string pkgroot = 1; - string pkgpath = 2; - repeated string files = 3; -} - -// --------------------------------------------------------------------------------- -// LoadSettingsFiles API -// Input work dir and setting files and return the merged kcl singleton config. -// --------------------------------------------------------------------------------- - -message LoadSettingsFiles_Args { - string work_dir = 1; - repeated string files = 2; -} - -message LoadSettingsFiles_Result { - CliConfig kcl_cli_configs = 1; - repeated KeyValuePair kcl_options = 2; -} - -message CliConfig { - repeated string files = 1; - string output = 2; - repeated string overrides = 3; - repeated string path_selector = 4; - bool strict_range_check = 5; - bool disable_none = 6; - int64 verbose = 7; - bool debug = 8; -} - -message KeyValuePair { - string key = 1; - string value = 2; -} - -// ---------------------------------------------------------------------------- -// JSON Schema Lit -// ---------------------------------------------------------------------------- - -message KclType { - string type = 1; // schema, dict, list, str, int, float, bool, null, type_string - repeated KclType union_types = 2 ; // union types - string default = 3; // default value - - string schema_name = 4; // schema name - string schema_doc = 5; // schema doc - map properties = 6; // schema properties - repeated string required = 7; // required schema properties, [property_name1, property_name2] - - KclType key = 8; // dict key type - KclType item = 9; // dict/list item type - - int32 line = 10; - - repeated Decorator decorators = 11; // schema decorators -} - -message Decorator { - string name = 1; - repeated string arguments = 2; - map keywords = 3; -} - -// ---------------------------------------------------------------------------- -// END -// ---------------------------------------------------------------------------- diff --git a/internal/kclvm_py/spec/gpyrpc/protoc-gen-protorpc-py/go.mod b/internal/kclvm_py/spec/gpyrpc/protoc-gen-protorpc-py/go.mod deleted file mode 100644 index a177520de..000000000 --- a/internal/kclvm_py/spec/gpyrpc/protoc-gen-protorpc-py/go.mod +++ /dev/null @@ -1,8 +0,0 @@ -module github.com/chai2010/protorpc-py/protoc-gen-protorpc-py - -go 1.16 - -require ( - github.com/chai2010/protorpc v1.1.1 - github.com/golang/protobuf v1.0.0 // indirect -) diff --git a/internal/kclvm_py/spec/gpyrpc/protoc-gen-protorpc-py/go.sum b/internal/kclvm_py/spec/gpyrpc/protoc-gen-protorpc-py/go.sum deleted file mode 100644 index 357b14bc7..000000000 --- a/internal/kclvm_py/spec/gpyrpc/protoc-gen-protorpc-py/go.sum +++ /dev/null @@ -1,5 +0,0 @@ -github.com/chai2010/protorpc v1.1.1 h1:UQIj4l0At5C9zDbQJFlvIcZeREexylWvc3rH9ZSlfso= -github.com/chai2010/protorpc v1.1.1/go.mod h1:/wO0kiyVdu7ug8dCMrA2yDr2vLfyhsLEuzLa9J2HJ+I= -github.com/golang/protobuf v1.0.0 h1:lsek0oXi8iFE9L+EXARyHIjU5rlWIhhTkjDz3vHhWWQ= -github.com/golang/protobuf v1.0.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= diff --git a/internal/kclvm_py/spec/gpyrpc/protoc-gen-protorpc-py/main.go b/internal/kclvm_py/spec/gpyrpc/protoc-gen-protorpc-py/main.go deleted file mode 100644 index c393b1c52..000000000 --- a/internal/kclvm_py/spec/gpyrpc/protoc-gen-protorpc-py/main.go +++ /dev/null @@ -1,225 +0,0 @@ -package main - -import ( - "bytes" - "fmt" - "log" - "os" - "path/filepath" - "sort" - "strings" - "text/template" - - plugin "github.com/chai2010/protorpc/protoc-gen-plugin" - "github.com/golang/protobuf/protoc-gen-go/descriptor" - "github.com/golang/protobuf/protoc-gen-go/generator" -) - -func init() { - plugin.RegisterCodeGenerator(new(protorpcPlugin)) -} - -func main() { - if len(os.Args) > 1 && (os.Args[1] == "-h" || os.Args[1] == "-help") { - fmt.Println("usage: protoc-gen-protorpc-py") - fmt.Println(" # install protoc") - fmt.Println(" go install github.com/golang/protobuf/protoc-gen-go") - fmt.Println(" go install github.com/chai2010/protorpc/protoc-gen-protorpc") - fmt.Println(" # install protoc-gen-protorpc-py") - fmt.Println(" protoc --protorpc-py_out=. gpyrpc.proto") - fmt.Println(" protoc-gen-protorpc-py -h") - return - } - plugin.Main() -} - -type protorpcPlugin struct{} - -func (p *protorpcPlugin) Name() string { return "protorpc-py" } -func (p *protorpcPlugin) FileNameExt() string { return ".pb.protorpc.py" } - -func (p *protorpcPlugin) HeaderCode(g *generator.Generator, file *generator.FileDescriptor) string { - moduleName := strings.TrimSuffix(filepath.Base(file.GetName()), ".proto") + "_pb2" - - var serviceList []*ServiceSpec - for _, svc := range file.Service { - serviceList = append(serviceList, p.buildServiceSpec(g, svc)) - } - - var messageMap = make(map[string]bool) - for _, svc := range serviceList { - for _, method := range svc.MethodList { - messageMap[method.InputTypeName] = true - messageMap[method.OutputTypeName] = true - } - } - - var messageList []string - for k := range messageMap { - messageList = append(messageList, k) - } - sort.Strings(messageList) - - var fnMap = template.FuncMap{ - "hello": func() string { return "hello" }, - } - - var buf bytes.Buffer - t := template.Must(template.New("").Funcs(fnMap).Parse(tmpl)) - err := t.Execute(&buf, - struct { - G *generator.Generator - File *generator.FileDescriptor - ModuleName string - ServiceList []*ServiceSpec - MessageList []string - }{ - G: g, - File: file, - ModuleName: moduleName, - ServiceList: serviceList, - MessageList: messageList, - }, - ) - if err != nil { - log.Fatal(err) - } - - return buf.String() -} - -func (p *protorpcPlugin) ServiceCode(g *generator.Generator, file *generator.FileDescriptor, svc *descriptor.ServiceDescriptorProto) string { - return "" -} - -func (p *protorpcPlugin) MessageCode(g *generator.Generator, file *generator.FileDescriptor, msg *descriptor.DescriptorProto) string { - return "" -} - -type ServiceSpec struct { - ServiceName string - ServiceRawName string - - MethodList []ServiceMethodSpec -} - -type ServiceMethodSpec struct { - MethodName string - MethodRawName string - - InputTypeName string - OutputTypeName string -} - -func (p *protorpcPlugin) buildServiceSpec(g *generator.Generator, svc *descriptor.ServiceDescriptorProto) *ServiceSpec { - spec := &ServiceSpec{ - ServiceName: generator.CamelCase(svc.GetName()), - ServiceRawName: svc.GetName(), - } - - for _, m := range svc.Method { - if m.GetClientStreaming() || m.GetServerStreaming() { - continue - } - spec.MethodList = append(spec.MethodList, ServiceMethodSpec{ - MethodName: generator.CamelCase(m.GetName()), - MethodRawName: m.GetName(), - - InputTypeName: g.TypeName(g.ObjectNamed(m.GetInputType())), - OutputTypeName: g.TypeName(g.ObjectNamed(m.GetOutputType())), - }) - } - - return spec -} - -const tmpl = ` -{{- $G := .G -}} -{{- $File := .File -}} -{{- $ModuleName := .ModuleName -}} -{{- $ServiceList := .ServiceList -}} -{{- $MessageList := .MessageList -}} - -# Code generated by protoc-gen-protorpc-py. DO NOT EDIT. -# -# plugin: https://github.com/chai2010/protorpc/protoc-gen-plugin -# plugin: https://github.com/chai2010/protorpc-py/protoc-gen-protorpc-py -# -# source: {{$File.GetName}} - -import abc -import sys -import typing - -from google.protobuf import message as _message - -from .protorpc import ServiceMeta as _ServiceMeta -from .protorpc import Server as _Server - -from .{{$ModuleName}} import ({{range $k, $v := $MessageList}} - {{$v}}, -{{- end}}) - -{{range $k, $svc := $ServiceList}} -class {{$svc.ServiceName}}(metaclass=abc.ABCMeta): - {{- range $sss, $method := $svc.MethodList}} - - @abc.abstractmethod - def {{$method.MethodName}}(self, args: {{$method.InputTypeName}}) -> {{$method.OutputTypeName}}: - pass - {{- end}} -{{end}} - -{{range $k, $svc := $ServiceList}} -class {{$svc.ServiceName}}_Meta(_ServiceMeta): - - def __init__(self, instance: {{$svc.ServiceName}}): - super().__init__() - self._instance = instance - - def get_service_name(self) -> str: - return "{{$svc.ServiceName}}" - - def get_method_list(self) -> typing.List[str]: - return [ - {{- range $_, $method := $svc.MethodList}} - "{{$method.MethodRawName}}", - {{- end}} - ] - - def create_method_req_message(self, method: str) -> _message.Message: - {{- range $_, $method := $svc.MethodList}} - if method in ["{{$method.MethodRawName}}", "{{$svc.ServiceName}}.{{$method.MethodRawName}}"]: - return {{$method.InputTypeName}}() - {{- end}} - raise Exception(f"unknown method: {method}") - - def create_method_resp_message(self, method: str) -> _message.Message: - {{- range $_, $method := $svc.MethodList}} - if method in ["{{$method.MethodRawName}}", "{{$svc.ServiceName}}.{{$method.MethodRawName}}"]: - return {{$method.OutputTypeName}}() - {{- end}} - raise Exception(f"unknown method: {method}") - - def get_service_instance(self) -> _message.Message: - return typing.cast(_message.Message, self._instance) - - def call_method(self, method: str, req: _message.Message) -> _message.Message: - {{- range $_, $method := $svc.MethodList}} - if method in ["{{$method.MethodRawName}}", "{{$svc.ServiceName}}.{{$method.MethodRawName}}"]: - return self._instance.{{$method.MethodName}}(req) - {{- end}} - raise Exception(f"unknown method: {method}") -{{end}} - -{{range $k, $svc := $ServiceList}} -class {{$svc.ServiceName}}_Server: - def __init__(self, instance: {{$svc.ServiceName}}): - self.instance = instance - - def run(self, *, stdin=sys.stdin, stdout=sys.stdout): - rpc_server = _Server() - rpc_server.register_service({{$svc.ServiceName}}_Meta(self.instance)) - rpc_server.run(stdin=stdin, stdout=stdout) -{{end}} -` diff --git a/internal/kclvm_py/spec/gpyrpc/protorpc.py b/internal/kclvm_py/spec/gpyrpc/protorpc.py deleted file mode 100644 index 66ae46ace..000000000 --- a/internal/kclvm_py/spec/gpyrpc/protorpc.py +++ /dev/null @@ -1,170 +0,0 @@ -import abc -import sys -import typing - -import varint - -from google.protobuf import message as _message - -from .protorpc_wire_pb2 import ( - RequestHeader, - ResponseHeader, -) - - -class Channel(object): - def __init__(self, *, stdin=sys.stdin, stdout=sys.stdout): - self.stdin = stdin - self.stdout = stdout - self.next_id = 1 - - def get_next_id(self) -> int: - next_id = self.next_id - self.next_id = self.next_id + 1 - return next_id - - def send_frame(self, data: bytes): - self.stdout.buffer.write(varint.encode(len(data))) - self.stdout.buffer.write(data) - self.stdout.flush() - - def recv_frame(self, _max_size: int = 0) -> bytes: - size = varint.decode_stream(self.stdin.buffer) - data = self.stdin.buffer.read(size) - return data - - def write_request(self, method: str, req: _message.Message): - body = req.SerializeToString() - - hdr = RequestHeader( - id=self.get_next_id(), method=method, raw_request_len=len(body) - ) - self.send_frame(hdr.SerializeToString()) - self.send_frame(body) - - def read_request_header(self) -> RequestHeader: - data = self.recv_frame() - hdr = RequestHeader() - hdr.ParseFromString(data) - return hdr - - def read_request_body(self, _header: RequestHeader, body: _message.Message): - data = self.recv_frame() - body.ParseFromString(data) - - def write_response(self, id_: int, error: str, response: _message.Message): - if not error: - body = response.SerializeToString() - else: - body = "" - - hdr = ResponseHeader(id=id_, error=error, raw_response_len=len(body)) - self.send_frame(hdr.SerializeToString()) - - if not error: - self.send_frame(body) - - def read_response_header(self) -> ResponseHeader: - data = self.recv_frame() - hdr = ResponseHeader() - hdr.ParseFromString(data) - return hdr - - def read_response_body(self, header: ResponseHeader, body: _message.Message): - if header.error: - raise header.error - data = self.recv_frame() - body.ParseFromString(data) - - def call_method(self, method: str, req: _message.Message, resp: _message.Message): - self.write_request(method, req) - resp_hdr = self.read_response_header() - self.read_response_body(resp_hdr, resp) - - -class ServiceMeta(metaclass=abc.ABCMeta): - def __init__(self, instance: _message.Message): - self._instance = instance - - def get_service_instance(self) -> _message.Message: - return self._instance - - def call_method(self, method: str, req: _message.Message) -> _message.Message: - return getattr(self.get_service_instance(), method[method.rfind(".") + 1:])( - req - ) - - @abc.abstractmethod - def get_service_name(self) -> str: - pass - - @abc.abstractmethod - def get_method_list(self) -> typing.List[str]: - pass - - @abc.abstractmethod - def create_method_req_message(self, method: str) -> _message.Message: - pass - - @abc.abstractmethod - def create_method_resp_message(self, method: str) -> _message.Message: - pass - - -class Server: - def __init__(self): - self.srv_table: typing.Dict[str, ServiceMeta] = {} - self.chan: typing.Optional[Channel] = None - - def register_service(self, srv: ServiceMeta): - self.srv_table[srv.get_service_name()] = srv - - def get_service_name_list(self) -> typing.List[str]: - name_list: typing.List[str] = [] - for s in self.srv_table.keys(): - name_list.append(s) - name_list.sort() - return name_list - - def get_method_name_list(self) -> typing.List[str]: - name_list: typing.List[str] = [] - for s in self.srv_table.values(): - name_list.extend(s.get_method_list()) - name_list.sort() - return name_list - - def run(self, *, stdin=sys.stdin, stdout=sys.stdout): - self.chan = Channel(stdin=stdin, stdout=stdout) - while True: - self._accept_one_call() - - def _accept_one_call(self): - hdr = self._read_req_header() - - service_name = hdr.method[: hdr.method.rfind(".")] - method_name = hdr.method[hdr.method.rfind(".") + 1:] - service = self.srv_table[service_name] - - req = self._read_req(service, hdr) - resp = service.call_method(method_name, req) - - self._write_resp(hdr.id, "", resp) - - def _read_req_header(self) -> RequestHeader: - return self.chan.read_request_header() - - def _read_req(self, service: ServiceMeta, hdr: RequestHeader) -> _message.Message: - req = service.create_method_req_message(hdr.method) - self.chan.read_request_body(hdr, req) - return req - - def _write_resp(self, id_: int, error: str, resp: _message.Message): - self.chan.write_response(id_, error, resp) - - -class Client: - def __init__(self, chan: Channel = None): - self.chan: Channel = chan - - def call_method(self, method: str, req: _message.Message, resp: _message.Message): - self.chan.call_method(method, req, resp) diff --git a/internal/kclvm_py/spec/gpyrpc/protorpc_wire.proto b/internal/kclvm_py/spec/gpyrpc/protorpc_wire.proto deleted file mode 100644 index 75a5078db..000000000 --- a/internal/kclvm_py/spec/gpyrpc/protorpc_wire.proto +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright 2013 . All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -syntax = "proto3"; - -// -// protorpc wire format wrapper -// -// 0. Frame Format -// len : uvarint64 -// data: byte[len] -// -// 1. Client Send Request -// Send RequestHeader: sendFrame(zsock, hdr, len(hdr)) -// Send Request: sendFrame(zsock, body, hdr.snappy_compressed_request_len) -// -// 2. Server Recv Request -// Recv RequestHeader: recvFrame(zsock, hdr, max_hdr_len, 0) -// Recv Request: recvFrame(zsock, body, hdr.snappy_compressed_request_len, 0) -// -// 3. Server Send Response -// Send ResponseHeader: sendFrame(zsock, hdr, len(hdr)) -// Send Response: sendFrame(zsock, body, hdr.snappy_compressed_response_len) -// -// 4. Client Recv Response -// Recv ResponseHeader: recvFrame(zsock, hdr, max_hdr_len, 0) -// Recv Response: recvFrame(zsock, body, hdr.snappy_compressed_response_len, 0) -// -package protorpc_wire; - -enum Const { - ZERO = 0; - MAX_REQUEST_HEADER_LEN = 1024; -} - -message RequestHeader { - uint64 id = 1; - string method = 2; - - uint32 raw_request_len = 3; - uint32 snappy_compressed_request_len = 4; - uint32 checksum = 5; -} - -message ResponseHeader { - uint64 id = 1; - string error = 2; - - uint32 raw_response_len = 3; - uint32 snappy_compressed_response_len = 4; - uint32 checksum = 5; -} diff --git a/internal/kclvm_py/spec/modfile/modfile.proto b/internal/kclvm_py/spec/modfile/modfile.proto deleted file mode 100644 index e90dfd738..000000000 --- a/internal/kclvm_py/spec/modfile/modfile.proto +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright 2021 The KCL Authors. All rights reserved. - -syntax = "proto3"; - -package kclvm.modfile; - -// kcl.mod 文件对应的内存格式 -// kcl.mod 文件为TOML格式, 字段名字和类型保持一致 -message KclModFile { - string root = 1; // 根目录路径, 由程序填充(TODO) - string root_pkg = 2; // 根包import路径, 对应所有子包的前缀, 可以忽略(TODO) - - KclModFile_build_section build = 3; // build 配置 - KclModFile_expected_section expected = 4; // expected 配置 -} - -message KclModFile_build_section { - bool enable_pkg_cache = 1; // 启动pkg缓存 - string cached_pkg_prefix = 2; // 缓存的前缀路径 - string target = 3; // 编译的目标,可选 native, wasm -} - -message KclModFile_expected_section { - string min_build_time = 1; // 期望构建时间下界 2021-08-14 20:30:08 - string max_build_time = 2; // 期望构建时间上界 2021-08-16 20:30:08 - string kclvm_version = 3; // KCLVM 版本依赖 - string kcl_plugin_version = 4; // KCLVM Plugin 版本依赖 - string global_version = 5; // 全局版本 -} diff --git a/internal/kclvm_py/tools/docs/__init__.py b/internal/kclvm_py/tools/docs/__init__.py deleted file mode 100644 index cea1fe5cc..000000000 --- a/internal/kclvm_py/tools/docs/__init__.py +++ /dev/null @@ -1,11 +0,0 @@ -from .doc import ( - kcl_doc_generate, - kcl_i18n_init, - kcl_i18n_info, -) - -__all__ = [ - "kcl_doc_generate", - "kcl_i18n_init", - "kcl_i18n_info", -] diff --git a/internal/kclvm_py/tools/docs/__main__.py b/internal/kclvm_py/tools/docs/__main__.py deleted file mode 100644 index 7676837c5..000000000 --- a/internal/kclvm_py/tools/docs/__main__.py +++ /dev/null @@ -1,198 +0,0 @@ -# Copyright 2020 The KCL Authors. All rights reserved. -""" -kcl-doc parses KCL source code - including comments - and produces documentation as HTML or plain text. -""" -import argparse -import sys - -import kclvm.kcl.error as kcl_error -import kclvm.tools.docs.doc as doc -import kclvm.tools.docs.formats as doc_formats - - -class DocGenMeta: - DEFAULT_SOURCE_FORMAT = "YAML" - DEFAULT_OUTPUT_DIR = "kcl_doc" - I18N_FORMAT_DESC = "i18n file format, support YAML, JSON" - DEFAULT_DOC_FILE_FORMAT = doc_formats.KCLDocFormat.MARKDOWN - DEFAULT_LOCALE = "en" - KCL_FILE_DESC = "KCL file paths. If there's more than one files to generate, separate them by space" - DOC_FORMAT_DESC = ( - "Doc file format, support YAML, JSON and MARKDOWN. Defaults to MARKDOWN" - ) - LOCALE_DESC = "I18n locale, e.g.: zh, zh_CN, en, en_AS. Defaults to en" - OUTPUT_DIR_DESC = ( - f"Specify the output directory. Defaults to ./{DEFAULT_OUTPUT_DIR}" - ) - REPO_URL_DESC = "The source code repository url. It will displayed in the generated doc to link to the source code." - I18N_INPUT_PATH_DESC = ( - "The i18n input file path. It can be a path to an i18n file when generating doc for a single kcl file, " - "or a path to a directory that contains i18n files when generating docs for multipule kcl files. " - "The program will search for the i18n input file according to the locale when generating docs. " - "If i18n file exists, use it instead of source file to generate the doc" - ) - - -if __name__ == "__main__": - parser = argparse.ArgumentParser(prog="kcl-doc") - subparsers = parser.add_subparsers( - dest="kcl_doc_subcmd_name", help="kcl doc sub commands" - ) - - parser_init = subparsers.add_parser( - "init-i18n", help="init the i18n source doc files of the given KCL files" - ) - parser_init.add_argument( - dest="kcl_files", metavar="files", help=DocGenMeta.KCL_FILE_DESC, nargs="*" - ) - parser_init.add_argument( - "--format", - dest="format", - metavar=DocGenMeta.DEFAULT_SOURCE_FORMAT, - default=DocGenMeta.DEFAULT_SOURCE_FORMAT, - type=str, - help=DocGenMeta.I18N_FORMAT_DESC, - ) - parser_init.add_argument( - "-o", - "-od" "--output-dir", - dest="output", - default=DocGenMeta.DEFAULT_OUTPUT_DIR, - type=str, - help=DocGenMeta.OUTPUT_DIR_DESC, - required=False, - ) - parser_init.add_argument( - "--i18n-locale", - dest="locale", - default=DocGenMeta.DEFAULT_LOCALE, - help=DocGenMeta.LOCALE_DESC, - ) - - parser_info = subparsers.add_parser( - "info-i18n", help="show an i18n source doc of a kcl file" - ) - parser_info.add_argument( - dest="kcl_files", metavar="files", help=DocGenMeta.KCL_FILE_DESC, nargs="*" - ) - parser_info.add_argument( - "--format", - dest="format", - metavar=DocGenMeta.DEFAULT_SOURCE_FORMAT, - default=DocGenMeta.DEFAULT_SOURCE_FORMAT, - type=str, - help=DocGenMeta.I18N_FORMAT_DESC, - ) - parser_info.add_argument( - "--i18n-locale", - dest="locale", - default=DocGenMeta.DEFAULT_LOCALE, - help=DocGenMeta.LOCALE_DESC, - ) - - # TODO: kcl-doc update-i18n cmd - - parser_generate = subparsers.add_parser( - "generate", help="generate a displayable doc file of a kcl file" - ) - parser_generate.add_argument( - dest="kcl_files", metavar="files", help=DocGenMeta.KCL_FILE_DESC, nargs="*" - ) - parser_generate.add_argument( - "--format", - dest="format", - metavar=DocGenMeta.DEFAULT_SOURCE_FORMAT, - default=DocGenMeta.DEFAULT_DOC_FILE_FORMAT, - type=str, - help=DocGenMeta.DOC_FORMAT_DESC, - ) - parser_generate.add_argument( - "-o", - "--output-path", - dest="output", - default=DocGenMeta.DEFAULT_OUTPUT_DIR, - type=str, - help=DocGenMeta.OUTPUT_DIR_DESC, - required=False, - ) - parser_generate.add_argument( - "--r", - "-R", - "--recursive", - dest="recursive", - action="store_true", - required=False, - help="Search directory recursively", - ) - parser_generate.add_argument( - "--i18n-locale", - dest="locale", - default=DocGenMeta.DEFAULT_LOCALE, - help=DocGenMeta.LOCALE_DESC, - ) - - parser_generate.add_argument( - "--repo-url", - dest="repo_url", - help=DocGenMeta.REPO_URL_DESC, - ) - - parser_generate.add_argument( - "--i18n-path", - dest="i18n_path", - help=DocGenMeta.I18N_INPUT_PATH_DESC, - ) - - parser_generate.add_argument( - "--with-locale-suffix", - dest="with_locale_suffix", - action="store_true", - default=False, - help="if the generated doc files have the locale suffix in their filenames", - ) - - args = parser.parse_args() - - def kcl_doc_main(): - if args.kcl_doc_subcmd_name == "init-i18n": - doc.kcl_i18n_init(args.kcl_files, args.output, args.format, args.locale) - print("KCL i18n meta file inited.") - sys.exit(0) - - if args.kcl_doc_subcmd_name == "info-i18n": - doc.kcl_i18n_info(args.kcl_files, args.format, args.locale) - sys.exit(0) - - if args.kcl_doc_subcmd_name == "generate": - doc.kcl_doc_generate( - args.kcl_files, - args.output, - args.format, - args.locale, - args.recursive, - args.repo_url, - args.i18n_path, - args.with_locale_suffix, - ) - print("KCL doc generated.") - sys.exit(0) - - print("nothing to do.\n") - help_msg = parser.format_help() - print(f"{help_msg}") - sys.exit(0) - - try: - kcl_doc_main() - except kcl_error.KCLException as err: - kcl_error.print_kcl_error_message(err, file=sys.stderr) - sys.exit(1) - except OSError as err: - kcl_error.print_common_error_message(err, file=sys.stderr) - sys.exit(1) - except AssertionError as err: - kcl_error.print_internal_error_message(err, file=sys.stderr) - raise - except Exception: - kcl_error.print_internal_error_message(file=sys.stderr) - raise diff --git a/internal/kclvm_py/tools/docs/checker.py b/internal/kclvm_py/tools/docs/checker.py deleted file mode 100644 index 1e62bdea0..000000000 --- a/internal/kclvm_py/tools/docs/checker.py +++ /dev/null @@ -1,128 +0,0 @@ -from typing import List, Dict - -import kclvm.kcl.error as kcl_error -import kclvm.tools.docs.model_pb2 as model - - -class SchemaDocStringChecker: - """KCL schema docstring verification - - Verify that the schema docstring is consistent with - the schema definition - - Parameters - ---------- - schema: model.SchemaDoc - The schema AST node - - model: model.SchemaDoc - The schema document model - """ - - ATTR_NOT_FOUND_IN_DOC = ( - "Missing schema attribute description in schema: '{}', attribute: '{}'" - ) - ATTR_NOT_FOUND_IN_SCHEMA = ( - "Redundant schema attribute description in schema: '{}', attribute: '{}'" - ) - ATTR_INFO_INCONSISTENT_TYPE = "Inconsistent schema attribute info: schema: '{}', attribute: '{}', type in docstring: '{}', actual type : '{}'" - - ATTR_INFO_INCONSISTENT_OPTIONAL = "Inconsistent schema attribute info: schema: '{}', attribute: '{}', is_optional in docstring: '{}', actual is_optional : '{}'" - - def __init__(self, source_code: model.SchemaDoc, doc_string: model.SchemaDoc): - self._source_code = source_code - self._doc_string = doc_string - - def _check_attribute_diff( - self, - attr_map: Dict[str, model.SchemaAttributeDoc], - attr_doc_map: Dict[str, model.SchemaAttributeDoc], - ): - """Verify that the schema docstring Attributes section describes exactly the same attributes as the schema body defines: - 1. all the attributes defined in the schema body must have the corresponding description in the docstring Attributes section - 2. all the attributes described in the docstring Attributes section must have the corresponding definition in the schema body - """ - - attr_not_in_doc = set(attr_map) - set(attr_doc_map) - attr_not_in_schema = set(attr_doc_map) - set(attr_map) - if attr_not_in_schema: - kcl_error.report_warning( - err_type=kcl_error.ErrType.InvalidDocstring_TYPE, - arg_msg=self.ATTR_NOT_FOUND_IN_SCHEMA.format( - self._source_code.name, - ",".join(attr_not_in_schema), - ), - ) - if attr_not_in_doc: - kcl_error.report_warning( - err_type=kcl_error.ErrType.InvalidDocstring_TYPE, - arg_msg=self.ATTR_NOT_FOUND_IN_DOC.format( - self._source_code.name, - ",".join(attr_not_in_doc), - ), - ) - - def _check_attribute_def( - self, - attr_map: Dict[str, model.SchemaAttributeDoc], - attr_doc_map: Dict[str, model.SchemaAttributeDoc], - ): - """Verify that each attribute in the schema docstring Attributes section is consistent with the corresponding attribute in schema body. - Following features of the attribute will be verified: - 1. the attribute's type - 2. the attribute's optional info - todo: the default value is not checked, since the code representation can be various, it can only be checked semantically. - """ - common_attr_list = set(attr_map) & set(attr_doc_map) - for attr in common_attr_list: - schema_attr = attr_map[attr] - schema_attr_doc = attr_doc_map[attr] - if schema_attr.type.type_str.replace( - " ", "" - ) != schema_attr_doc.type.type_str.replace(" ", ""): - kcl_error.report_warning( - err_type=kcl_error.ErrType.InvalidDocstring_TYPE, - arg_msg=self.ATTR_INFO_INCONSISTENT_TYPE.format( - self._source_code.name, - attr, - schema_attr_doc.type.type_str, - schema_attr.type.type_str, - ), - ) - if schema_attr.is_optional != schema_attr_doc.is_optional: - kcl_error.report_warning( - err_type=kcl_error.ErrType.InvalidDocstring_TYPE, - arg_msg=self.ATTR_INFO_INCONSISTENT_OPTIONAL.format( - self._source_code.name, - attr, - schema_attr_doc.is_optional, - schema_attr.is_optional, - ), - ) - - def _check( - self, - schema_attr_list: List[model.SchemaAttributeDoc], - attr_doc_list: List[model.SchemaAttributeDoc], - ): - if not schema_attr_list or not attr_doc_list: - return - # Grouped by the schema attribute name - attr_map = {attr.name: attr for attr in schema_attr_list} - attr_doc_map = {attr.name: attr for attr in attr_doc_list} - # Check attribute diff between schema docstring and schema AST - self._check_attribute_diff(attr_map, attr_doc_map) - # Check attribute definition between schema docstring and schema AST - self._check_attribute_def(attr_map, attr_doc_map) - - def check(self): - if ( - self._source_code is None - or self._doc_string is None - or not isinstance(self._source_code, model.SchemaDoc) - or not isinstance(self._doc_string, model.SchemaDoc) - ): - return - schema_attr_list = self._source_code.attributes - attr_doc_list = self._doc_string.attributes - self._check(schema_attr_list, attr_doc_list) diff --git a/internal/kclvm_py/tools/docs/doc.py b/internal/kclvm_py/tools/docs/doc.py deleted file mode 100644 index 616cebcb9..000000000 --- a/internal/kclvm_py/tools/docs/doc.py +++ /dev/null @@ -1,393 +0,0 @@ -"""Module doc extracts source code documentation from a KCL AST -""" -import io -import os - -from typing import Union, List, Dict, Optional -from pathlib import Path - -import kclvm.kcl.error as kcl_error -import kclvm.compiler.vfs as vfs -import kclvm.compiler.parser.parser as parser -import kclvm.tools.docs.formats as doc_formats -import kclvm.kcl.types.checker as type_checker -import kclvm.api.object as obj_pkg -import kclvm.kcl.ast as ast -import kclvm.tools.docs.model_pb2 as model -import kclvm.tools.docs.writer as writer -import kclvm.tools.docs.reader as reader -import kclvm.tools.docs.link_resolver as link_resolver -import kclvm.tools.docs.doc_escaper as doc_escaper -import kclvm.tools.docs.doc_parser as doc_parser -import kclvm.tools.docs.i18n as i18n -import kclvm.tools.docs.utils as utils - -# --------------------------------------------------- -# Constants -# --------------------------------------------------- - -KCL_SUFFIX = "*.k" -INVALID_OUTPUT_FORMAT_MSG = "invalid output format, expected: yaml, json or markdown" -INVALID_I18N_FORMAT_MSG = "invalid i18n metadata format, expected: yaml, json" - -# --------------------------------------------------- -# User interface functions used by kcl-doc cli -# --------------------------------------------------- - - -def kcl_doc_generate( - kcl_files: List[str], - output: str, - format: str = doc_formats.KCLDocFormat.MARKDOWN, - locale: str = "en", - recursively=False, - repo_url: str = None, - i18n_path: str = None, - with_locale_suffix: bool = False, -) -> None: - """ - generate a displayable doc file of a kcl file - :param kcl_files: the kcl file paths to generate doc on - :param output: the dir path to output the generated doc file - :param format: the document format to generate - :param locale: the document locale to generate - :param recursively: if search for the kcl files to generate doc on recursively - :param repo_url: the url to the source code repo - :param i18n_path: the i18n input path - """ - # check if the format and locale is valid - locale = locale.lower() - format_upper = format.upper() - if format_upper not in doc_formats.KCLDocFormat.MAPPING: - kcl_error.report_exception( - err_type=kcl_error.ErrType.CompileError_TYPE, - arg_msg=INVALID_OUTPUT_FORMAT_MSG, - ) - i18n.check_locale(locale) - # check if all the files exist - if len(kcl_files) == 0: - kcl_error.report_exception( - err_type=kcl_error.ErrType.CannotFindModule_TYPE, - arg_msg="Empty list of input KCL files", - ) - for kcl_file in kcl_files: - if not Path(kcl_file).exists(): - kcl_error.report_exception( - err_type=kcl_error.ErrType.CannotFindModule_TYPE, - arg_msg=f"Cannot find the kcl file, please check whether the file path {kcl_file} exists" - if kcl_file - else f"The file path {kcl_file} is None", - ) - # parse module docs - module_docs = _parse_file_docs( - kcl_files, format_upper, locale, recursively, repo_url, with_locale_suffix - ) - # write to output - path = Path(output).resolve() - for _, doc in module_docs.items(): - # if the i18n file exists, use the doc content decoded from the existing file - i18n_file_path, i18n_format = _existed_i18n_file_path( - i18n_path, path, doc.name, locale - ) - if i18n_file_path and i18n_format: - doc = _read_from_file(i18n_format, i18n_file_path) - _escape_text({doc.name: doc}, format_upper) - doc_file_path = _doc_file_path( - path / Path(doc.relative_path).parent, - doc.name, - locale, - format_upper, - with_locale_suffix, - ) - _write_to_file(doc, format_upper, doc_file_path) - - -def kcl_i18n_init( - kcl_files: List[str], - output: str, - format: str, - locale: str = "en", - recursively=False, - with_locale_suffix: bool = False, -) -> None: - """ - init an i18n source doc file of a KCL file. Users can then modify the document part of it and generate docs in other formats based on it - :param kcl_files: the kcl file paths to generate doc on - :param output: the dir path to output the inited i18n file - :param format: the document format to init - :param locale: the document locale to init - :param recursively: if search for the kcl files to generate doc on recursively - """ - # check if the format and locale is valid - locale = locale.lower() - format_upper = format.upper() - if format_upper not in doc_formats.KCLI18NFormat.MAPPING: - kcl_error.report_exception( - err_type=kcl_error.ErrType.CompileError_TYPE, - arg_msg=INVALID_I18N_FORMAT_MSG, - ) - i18n.check_locale(locale) - # check if all the files exist - if len(kcl_files) == 0: - kcl_error.report_exception( - err_type=kcl_error.ErrType.CannotFindModule_TYPE, - arg_msg="Empty list of input KCL files", - ) - for kcl_file in kcl_files: - if not Path(kcl_file).exists(): - kcl_error.report_exception( - err_type=kcl_error.ErrType.CannotFindModule_TYPE, - arg_msg=f"Cannot find the kcl file, please check whether the file path {kcl_file} exists" - if kcl_file - else f"The file path {kcl_file} is None", - ) - # parse module docs - module_docs = _parse_file_docs( - kcl_files, - format_upper, - locale, - recursively, - with_locale_suffix=with_locale_suffix, - ) - # write to output - path = Path(output).resolve() - path.mkdir(parents=True, exist_ok=True) - for _, doc in module_docs.items(): - i18n_path = _i18n_file_path(path, doc.name, locale, format_upper) - # reset doc content before gen i18n file - _write_to_file(doc, format_upper, i18n_path) - - -def kcl_i18n_info(kcl_files: List[str], format: str, locale: str) -> None: - """ - show an i18n source doc of a kcl file - :param kcl_files: the kcl files to show i18n info - :param format: the i18n file format to display - :param locale: the i18n file locale to display - """ - # check if the format and locale is valid - locale = locale.lower() - format_upper = format.upper() - if format_upper not in doc_formats.KCLI18NFormat.MAPPING: - kcl_error.report_exception( - err_type=kcl_error.ErrType.CompileError_TYPE, - arg_msg=INVALID_I18N_FORMAT_MSG, - ) - i18n.check_locale(locale) - - for kcl_file in kcl_files: - # calculate the i18n file path - path = _i18n_file_path( - Path(kcl_file).parent, utils.module_name(kcl_file), locale, format_upper - ) - # display the doc content read from i18n file to console - print(f"i18n file: {path} \ncontent:") - path = Path(path) - if path.exists(): - module_doc = _read_from_file(format_upper, path) - if module_doc: - output = io.StringIO() - _write_to_io(module_doc, format_upper, output) - print(output.getvalue()) - else: - print("Failed to parse i18n locale file, get nothing.") - else: - print( - f"I18n local file not exist. \n KCL file path: {kcl_file}, format: {format}, locale: {locale}" - ) - - -# --------------------------------------------------- -# Internal functions -# --------------------------------------------------- - - -def _read_from_file(format: str, in_file: Union[str, Path]) -> model.ModuleDoc: - with Path(in_file).open(mode="r", encoding="utf-8") as in_io: - module_doc = _read_from_io(format, in_io) - return module_doc - - -def _read_from_io(format: str, in_io: io.TextIOBase) -> model.ModuleDoc: - doc_reader = reader.factory.get(format, in_io) - return doc_reader.read_doc() - - -def _write_to_file( - doc: model.ModuleDoc, format: str, out_file: Union[str, Path] -) -> None: - Path(out_file).parent.mkdir(parents=True, exist_ok=True) - with Path(out_file).open(mode="w", encoding="utf-8") as out: - _write_to_io(doc, format, out) - - -def _write_to_io(doc: model.ModuleDoc, format: str, out: io.TextIOBase) -> None: - doc_writer = writer.factory.get(format, out) - doc_writer.write_doc(doc) - - -def _doc_file_name( - module_name: str, locale: str, format: str, with_locale_suffix: bool = False -) -> str: - return ( - f"doc_{module_name}_{locale}" + doc_formats.KCLDocSuffix.TO_SUFFIX[format] - if with_locale_suffix - else f"doc_{module_name}{doc_formats.KCLDocSuffix.TO_SUFFIX[format]}" - ) - - -def _doc_file_path( - path: Path, name: str, locale: str, format: str, with_locale_suffix: bool = False -) -> Path: - return path / _doc_file_name( - module_name=name, - locale=locale, - format=format, - with_locale_suffix=with_locale_suffix, - ) - - -def _i18n_file_path(path: Path, name: str, locale: str, format: str) -> Path: - return path / (f"i18n_{name}_{locale}" + doc_formats.KCLDocSuffix.TO_SUFFIX[format]) - - -def _existed_i18n_file_path( - i18n_path: str, path: Path, name: str, locale: str -) -> (Optional[Path], Optional[str]): - """ - check if there are existed i18n files for current source file path. - When there exists more than one possible i18n files, the priority to return is: KCL -> YAML -> JSON - - :param i18n_path: the i18n input file path - :param path: the dir path that contains KCL source file - :param name: the KCL module name to generate doc on - :param locale: the target locale - :return: the i18n file path if existed, else return None. - """ - if i18n_path: - i18n_path = Path(i18n_path) - if not i18n_path.exists(): - return None, None - if ( - i18n_path.is_file() - and i18n_path.suffix in doc_formats.KCLI18NFormat.FROM_SUFFIX - ): - return i18n_path, doc_formats.KCLI18NFormat.FROM_SUFFIX[i18n_path.suffix] - elif i18n_path.is_dir(): - path = i18n_path - else: - return None, None - yaml_i18n_path = _i18n_file_path(path, name, locale, doc_formats.KCLI18NFormat.YAML) - if yaml_i18n_path.exists(): - return yaml_i18n_path, doc_formats.KCLI18NFormat.YAML - - json_i18n_path = _i18n_file_path(path, name, locale, doc_formats.KCLI18NFormat.JSON) - if json_i18n_path.exists(): - return json_i18n_path, doc_formats.KCLI18NFormat.JSON - - return None, None - - -def _escape_text(module_docs: Dict[str, model.ModuleDoc], format: str): - escaper = doc_escaper.factory.get(format) - for path, module in module_docs.items(): - module_docs[path] = escaper.escape(module) - - -def _resolve_link( - root: str, - module_docs: Dict[str, model.ModuleDoc], - format: str, - locale: str, - with_locale_suffix: bool = False, -): - resolver = link_resolver.factory.get(format, _doc_file_name) - for path, module in module_docs.items(): - module_docs[path] = resolver.resolve(module, root, locale, with_locale_suffix) - - -def _parse_file_docs( - kcl_files: List[str], - format: str, - locale: str, - recursively: bool, - repo_url: str = None, - with_locale_suffix: bool = False, -) -> Dict[str, model.ModuleDoc]: - pkgs: List[str] = [] - if recursively: - for kcl_file in kcl_files: - pkgs.extend(_find_kcl_pkgs_recursively(Path(kcl_file))) - pkgs = list(set(pkgs)) - else: - pkgs = kcl_files - if len(pkgs) == 0: - return {} - root: str = vfs.GetPkgRoot(pkgs[0]) or os.path.dirname(pkgs[0]) - module_docs: Dict[str, model.ModuleDoc] = {} - trigger_lines = [ - f"import .{str(Path(pkg).relative_to(root)).replace('/', '.').rstrip('.k')}\n" - for pkg in pkgs - ] - trigger_file = Path(root) / "trigger_doc_gen.k" - with open(trigger_file, "w") as f: - f.writelines(trigger_lines) - try: - prog = parser.LoadProgram( - str(trigger_file), - work_dir=root, - ) - type_checker.ResolveProgramImport(prog) - checker = type_checker.TypeChecker(prog, type_checker.CheckConfig()) - checker.check_import(prog.MAIN_PKGPATH) - checker.init_global_types() - del prog.pkgs[prog.MAIN_PKGPATH] - finally: - os.remove(trigger_file) - pkg_docs = _parse_program_docs(prog, checker, repo_url) - _escape_text(pkg_docs, format) - _resolve_link(prog.root, pkg_docs, format, locale, with_locale_suffix) - - module_docs.update(pkg_docs) - return module_docs - - -def _parse_program_docs( - program: ast.Program, checker: type_checker.TypeChecker, repo_url: str = None -) -> Dict[str, model.ModuleDoc]: - - pkgs: Dict[str, List[ast.Module]] = program.pkgs - module_docs: Dict[str, model.ModuleDoc] = {} - for pkgpath, modules in pkgs.items(): - for m in modules: - schema_docs: list = [] - schema_list = m.GetSchemaList() - # only generate module doc if the module contains schemas - if schema_list: - for schema in schema_list: - current_scope = checker.scope_map[pkgpath] - schema_obj_type = current_scope.elems[schema.name].type - if isinstance(schema_obj_type, obj_pkg.KCLSchemaDefTypeObject): - schema_doc = doc_parser.SchemaDocParser( - schema=schema, - schema_type=schema_obj_type.schema_type, - root=program.root, - ).doc - schema_docs.append(schema_doc) - module_doc = model.ModuleDoc( - name=utils.module_name(m.filename), - relative_path=m.relative_filename, - doc=m.doc, - schemas=schema_docs, - source_code_url=repo_url, - ) - module_docs[m.relative_filename] = module_doc - return module_docs - - -def _find_kcl_pkgs_recursively(file: Path) -> List[str]: - if file.is_file(): - return [str(file)] - all_files = file.rglob("*.k") - pkgs: List[str] = [str(f.parent) for f in all_files] - return list(set(pkgs)) diff --git a/internal/kclvm_py/tools/docs/doc_escaper.py b/internal/kclvm_py/tools/docs/doc_escaper.py deleted file mode 100644 index 3742c2f59..000000000 --- a/internal/kclvm_py/tools/docs/doc_escaper.py +++ /dev/null @@ -1,60 +0,0 @@ -from abc import ABC, abstractmethod - -import kclvm.tools.docs.factory as factory -import kclvm.tools.docs.formats as doc_formats -import kclvm.tools.docs.model_pb2 as model - - -class DocEscaper(ABC): - """ - doc escaper checks the special character in the doc and escape it - """ - - @abstractmethod - def escape(self, doc: model.ModuleDoc) -> model.ModuleDoc: - pass - - -class MarkdownDocEscaper(DocEscaper): - def escape(self, module: model.ModuleDoc) -> model.ModuleDoc: - # remove line breaks at the beginning and the end - module.doc = self.escape_special_symbol(module.doc.strip("\n")) - for schema in module.schemas: - schema.name = self.escape_special_symbol(schema.name) - schema.doc = self.escape_special_symbol(schema.doc.strip("\n")) - if schema.attributes: - for attr in schema.attributes: - attr.name = self.escape_special_symbol(attr.name) - attr.doc = self.escape_special_symbol(attr.doc.strip("\n")) - attr.type.type_str = self.escape_special_symbol(attr.type.type_str) - if schema.examples: - schema.examples = schema.examples.strip("\n") - return module - - @staticmethod - def escape_special_symbol(name: str) -> str: - return ( - name.replace("_", "\\_") - .replace("*", "\\*") - .replace("#", "\\#") - .replace("|", "|") - .replace("<", "\\<") - .replace(">", "\\>") - .replace("\n", "
") - ) - - -class YamlDocEscaper(DocEscaper): - def escape(self, module: model.ModuleDoc) -> None: - return module - - -class JsonDocEscaper(DocEscaper): - def escape(self, module: model.ModuleDoc) -> None: - return module - - -factory = factory.DocEscaperFactory() -factory.register_format(doc_formats.KCLDocFormat.MARKDOWN, MarkdownDocEscaper) -factory.register_format(doc_formats.KCLDocFormat.YAML, YamlDocEscaper) -factory.register_format(doc_formats.KCLDocFormat.JSON, JsonDocEscaper) diff --git a/internal/kclvm_py/tools/docs/doc_parser.py b/internal/kclvm_py/tools/docs/doc_parser.py deleted file mode 100644 index a2a71df78..000000000 --- a/internal/kclvm_py/tools/docs/doc_parser.py +++ /dev/null @@ -1,314 +0,0 @@ -""" -Docstring parser for KCL models. - -Basically, we follow the docstring standard of numpy doc, use the related tools as underlying libs -and extend the part which it does not cover, such as default value. - -Reference: -+ https://numpydoc.readthedocs.io/ -""" - -import re -import typing -from numpydoc.docscrape import NumpyDocString - -import kclvm.kcl.ast as ast -import kclvm.api.object as objpkg -import kclvm.tools.docs.checker as checker -import kclvm.tools.docs.model_pb2 as model - -# Try to match type, optional, and default value. -# Note: there is no standard way to define default value in numpydoc, we define it as below. -TYPE_OPTIONAL_DEFAULT_REGEX = re.compile( - r"(?P.*?)(,?\s*[Dd]efault(?: is | = |: |s to |)\s*(?P.*?))?(,?\s*(?Poptional|\(optional\)|required|\(required\)).?)?$" -) - - -class SchemaDocParser: - """Schema doc parser. - - The schema doc is defined in model.SchemaDoc - - :param schema. The schema ast. - :param doc. The schema docstring - """ - - def __init__( - self, - schema: ast.SchemaStmt, - schema_type: objpkg.KCLSchemaTypeObject, - doc=None, - root: str = None, - checker=checker.SchemaDocStringChecker, - ): - self._schema = schema - self.root = root - self.schema_type = schema_type - - if doc is None: - if schema is None: - raise ValueError("No schema or documentation string given") - - import inspect - - doc = inspect.cleandoc(schema.doc) - schema_doc = NumpyDocString(doc) - - # Base Schema relation - base_schema: model.Type = None - if self._schema.parent_name: - assert self.schema_type.base - base_schema = model.Type( - type_str=self._schema.parent_name.get_name(), - type_category=model.Type.TypeCategory.SCHEMA, - schema_type=model.SchemaType( - name=self.schema_type.base.name, - relative_path=self.schema_type.base.filename.replace( - self.root, ".", 1 - ), - ), - ) - - doc = model.SchemaDoc(name=schema.name, base_schema=base_schema) - - # Summary - summary = "" - for sum_line in schema_doc["Summary"]: - summary += sum_line + "\n" - doc.doc = summary - - # Attributes - # From docstring: collect the attribute map from the Attributes docstring - doc_attr_map: typing.Dict[str, model.SchemaAttributeDoc] = {} - for attr in schema_doc["Attributes"]: - doc_attr_name = attr[0] - doc_attr_type = attr[1] - doc_attr_desc = "" - doc_attr_default = None - doc_attr_optional = False - - if attr[2]: - for desc in attr[2]: - doc_attr_desc += desc + "\n" - - # To prevent the doc pattern e.g., `name: type`, and modify it with kcl format tool - if ":" in doc_attr_name: - name_type_parts = doc_attr_name.split(":", 1) - if name_type_parts and len(name_type_parts) >= 2: - doc_attr_name = name_type_parts[0].strip() - doc_attr_type = name_type_parts[1].strip() + doc_attr_type - doc_attr_name = doc_attr_name.lstrip("$") - if doc_attr_type: - match = TYPE_OPTIONAL_DEFAULT_REGEX.match(doc_attr_type) - if ( - match is None - or match.group(0) == match.group(2) - or match.group(0) == match.group(3) - ): - # if there is no type defined, optional(group2) or default(group3) - # may be treated as type(group0) - # fixme: hacky, find a better way to check type - doc_attr_type = "" - else: - doc_attr_type = match.group("type") - # reset on all false cases - doc_attr_type = "" if not doc_attr_type else doc_attr_type - if match is not None: - doc_attr_default = match.group("value") - optional = match.group("optional") - if optional is not None: - doc_attr_optional = "optional" in optional - doc_attr_map[doc_attr_name] = model.SchemaAttributeDoc( - name=doc_attr_name, - type=model.Type(type_str=doc_attr_type), - is_optional=doc_attr_optional, - default_value=doc_attr_default, - doc=doc_attr_desc, - ) - - # From source code: collect the attribute map from the schema stmt: get each attribute's type, default value, optional info - code_attr_map: typing.Dict[str, model.SchemaAttributeDoc] = {} - for attr_name, attr_obj in self.schema_type.attr_obj_map.items(): - if attr_name == objpkg.SCHEMA_SETTINGS_ATTR_NAME: - # ignore __settings__ attribute - # todo: show __settings__ config in schema summary info - continue - code_attr_type: model.Type = self.type_doc(attr_obj.attr_type) - # fixme: hacky. the schema type str should be calculated recursively - if ( - code_attr_type.type_category == model.Type.TypeCategory.SCHEMA - and attr_obj.attr_node is not None - and attr_obj.attr_node.type_node is not None - ): - attr_node = typing.cast(ast.SchemaAttr, attr_obj.attr_node) - code_attr_type.type_str = attr_node.type_node.plain_type_str - code_attr_optional: bool = attr_obj.is_optional - # todo: get default value from ast - code_default_value: str = "" - code_attr_map[attr_name] = model.SchemaAttributeDoc( - name=attr_name, - type=code_attr_type, - is_optional=code_attr_optional, - default_value=code_default_value, - doc="", - ) - - # Merge attributes from docstring and source code - # According to source code: - # the attribute list, the type and the optional info of each attribute - # According to docstring: - # the default value and the description of each attribute - for attr_name, code_attr in code_attr_map.items(): - code_attr.doc = ( - doc_attr_map[attr_name].doc if attr_name in doc_attr_map else "" - ) - code_attr.default_value = ( - doc_attr_map[attr_name].default_value - if attr_name in doc_attr_map - else "" - ) - doc.attributes.append(code_attr) - - # Examples - examples = "" - for example in schema_doc["Examples"]: - examples += example + "\n" - doc.examples = examples - self.doc = doc - # Validate schema attr - if checker: - checker( - model.SchemaDoc( - name=schema.name, - attributes=[code_attr_map[attr] for attr in code_attr_map], - ), - model.SchemaDoc( - name=schema.name, - attributes=[doc_attr_map[attr] for attr in doc_attr_map], - ), - ).check() - - def type_doc(self, tpe: objpkg.KCLBaseTypeObject) -> model.Type: - def _short_schema_tpe(tpe: objpkg.KCLBaseTypeObject) -> str: - fullname = tpe.type_str() - parts = fullname.rsplit(".", 2) - return f"{parts[1]}.{parts[2]}" if len(parts) > 2 else fullname - - def _get_type_str(tpe: objpkg.KCLBaseTypeObject) -> str: - if not tpe: - return "" - if tpe.type_kind() in type_str_mapping: - return type_str_mapping[tpe.type_kind()](tpe) - else: - return tpe.type_str() - - type_str_mapping = { - objpkg.KCLTypeKind.StrLitKind: lambda t: f'"{t.value}"', - objpkg.KCLTypeKind.IntLitKind: lambda t: f"{t.value}", - objpkg.KCLTypeKind.BoolLitKind: lambda t: f"{t.value}", - objpkg.KCLTypeKind.FloatLitKind: lambda t: f"{t.value}", - objpkg.KCLTypeKind.NoneKind: lambda t: "None", - objpkg.KCLTypeKind.SchemaKind: _short_schema_tpe, - objpkg.KCLTypeKind.ListKind: lambda t: f"[{_get_type_str(t.item_type)}]", - objpkg.KCLTypeKind.DictKind: lambda t: f"{{{_get_type_str(t.key_type)}: {_get_type_str(t.value_type)}}}" - if t.value_type - else f"{{{_get_type_str(t.key_type)}:}}", - objpkg.KCLTypeKind.UnionKind: lambda t: " | ".join( - [_get_type_str(inner_type) for inner_type in t.types] - ), - } - - type_mapping = { - # ant type - objpkg.KCLTypeKind.AnyKind: lambda t: model.Type( - type_str=t.type_str(), type_category=model.Type.TypeCategory.ANY - ), - # builtin type - objpkg.KCLTypeKind.StrKind: lambda t: model.Type( - type_str=t.type_str(), - type_category=model.Type.TypeCategory.BUILTIN, - builtin_type=model.Type.BuiltinType.STRING, - ), - objpkg.KCLTypeKind.IntKind: lambda t: model.Type( - type_str=t.type_str(), - type_category=model.Type.TypeCategory.BUILTIN, - builtin_type=model.Type.BuiltinType.INT, - ), - objpkg.KCLTypeKind.BoolKind: lambda t: model.Type( - type_str=t.type_str(), - type_category=model.Type.TypeCategory.BUILTIN, - builtin_type=model.Type.BuiltinType.BOOL, - ), - objpkg.KCLTypeKind.FloatKind: lambda t: model.Type( - type_str=t.type_str(), - type_category=model.Type.TypeCategory.BUILTIN, - builtin_type=model.Type.BuiltinType.FLOAT, - ), - # lit type - objpkg.KCLTypeKind.StrLitKind: lambda t: model.Type( - type_str=_get_type_str(t), - type_category=model.Type.TypeCategory.LIT, - lit_type=model.LitType(string_lit=t.value), - ), - objpkg.KCLTypeKind.IntLitKind: lambda t: model.Type( - type_str=_get_type_str(t), - type_category=model.Type.TypeCategory.LIT, - lit_type=model.LitType(int_lit=t.value), - ), - objpkg.KCLTypeKind.BoolLitKind: lambda t: model.Type( - type_str=_get_type_str(t), - type_category=model.Type.TypeCategory.LIT, - lit_type=model.LitType(bool_lit=t.value), - ), - objpkg.KCLTypeKind.FloatLitKind: lambda t: model.Type( - type_str=_get_type_str(t), - type_category=model.Type.TypeCategory.LIT, - lit_type=model.LitType(float_lit=t.value), - ), - # name constant type - objpkg.KCLTypeKind.NoneKind: lambda t: model.Type( - type_str=_get_type_str(t), - type_category=model.Type.TypeCategory.NAMED_CONSTANT, - named_constant=model.Type.NamedConstant.NONE, - ), - # number multiplier type - objpkg.KCLTypeKind.NumberMultiplierKind: lambda t: model.Type( - type_str=_get_type_str(t), - type_category=model.Type.TypeCategory.NUMBER_MULTIPLIER, - ), - # schema type - objpkg.KCLTypeKind.SchemaKind: lambda t: model.Type( - type_str=_get_type_str(t), - type_category=model.Type.TypeCategory.SCHEMA, - schema_type=model.SchemaType( - name=t.name, - relative_path=t.filename.replace(self.root, ".", 1), - ), - ), - # list type - objpkg.KCLTypeKind.ListKind: lambda t: model.Type( - type_str=_get_type_str(t), - type_category=model.Type.TypeCategory.LIST, - list_type=model.ListType(item_type=self.type_doc(t.item_type)), - ), - # dict type - objpkg.KCLTypeKind.DictKind: lambda t: model.Type( - type_str=_get_type_str(t), - type_category=model.Type.TypeCategory.DICT, - dict_type=model.DictType( - key_type=self.type_doc(t.key_type), - value_type=self.type_doc(t.value_type), - ), - ), - # union type - objpkg.KCLTypeKind.UnionKind: lambda t: model.Type( - type_str=_get_type_str(t), - type_category=model.Type.TypeCategory.UNION, - union_type=model.UnionType( - types=[self.type_doc(inner_type) for inner_type in t.types] - ), - ), - } - if tpe.type_kind() in type_mapping: - return type_mapping[tpe.type_kind()](tpe) - raise TypeError diff --git a/internal/kclvm_py/tools/docs/factory.py b/internal/kclvm_py/tools/docs/factory.py deleted file mode 100644 index 0c651f3dd..000000000 --- a/internal/kclvm_py/tools/docs/factory.py +++ /dev/null @@ -1,70 +0,0 @@ -import io -import kclvm.kcl.error as kcl_error -import kclvm.tools.docs.templater as templater - -# --------------------------------------------------- -# Constants -# --------------------------------------------------- - - -INVALID_FORMAT_MSG = "an unsupported format, expected {}" - - -# --------------------------------------------------- -# Factory -# --------------------------------------------------- - - -class IOFactory: - def __init__(self): - self._creators = {} - - def register_format(self, format: str, creator): - self._creators[format] = creator - - def get(self, format: str, io: io.TextIOBase): - creator = self._creators.get(format) - if not creator: - formats = ",".join(self._creators.keys()) - kcl_error.report_exception( - err_type=kcl_error.ErrType.CompileError_TYPE, - arg_msg=INVALID_FORMAT_MSG.format(formats), - ) - return creator(io) - - -class PathResolverFactory: - def __init__(self): - self._resolvers = {} - - def register_format(self, format: str, resolver): - self._resolvers[format] = resolver - - def get(self, format: str, doc_name_formatter): - resolver = self._resolvers.get(format) - if not resolver: - kcl_error.report_exception( - err_type=kcl_error.ErrType.CompileError_TYPE, - arg_msg=INVALID_FORMAT_MSG.format(",".join(self._resolvers.keys())), - ) - return resolver( - doc_name_formatter=doc_name_formatter, - schema_section_render=templater.md_schema_section_render, - ) # todo, get templater from factory - - -class DocEscaperFactory: - def __init__(self): - self._escapers = {} - - def register_format(self, format: str, escaper): - self._escapers[format] = escaper - - def get(self, format: str): - escaper = self._escapers.get(format) - if not escaper: - kcl_error.report_exception( - err_type=kcl_error.ErrType.CompileError_TYPE, - arg_msg=INVALID_FORMAT_MSG.format(",".join(self._escapers.keys())), - ) - return escaper() diff --git a/internal/kclvm_py/tools/docs/formats.py b/internal/kclvm_py/tools/docs/formats.py deleted file mode 100644 index 142eb8730..000000000 --- a/internal/kclvm_py/tools/docs/formats.py +++ /dev/null @@ -1,45 +0,0 @@ -class KCLDocFormat: - """ - KCL document formats including yaml, json, markdown, reST, HTML5, etc. - TODO: RST, HTML5 style document generation. - """ - - YAML: str = "YAML" - JSON: str = "JSON" - MARKDOWN: str = "MARKDOWN" - - MAPPING = { - YAML: YAML, - JSON: JSON, - MARKDOWN: MARKDOWN, - } - - -class KCLDocSuffix: - """ - KCL document suffix including .yaml, .json, .md, .rst, .html, etc. - TODO: RST, HTML5 style document generation. - """ - - YAML: str = ".yaml" - JSON: str = ".json" - MARKDOWN: str = ".md" - TO_SUFFIX = { - KCLDocFormat.YAML: YAML, - KCLDocFormat.JSON: JSON, - KCLDocFormat.MARKDOWN: MARKDOWN, - } - - -class KCLI18NFormat: - """ - KCL i18n meta file formats including yaml, json. - """ - - YAML: str = KCLDocFormat.YAML - JSON: str = KCLDocFormat.JSON - MAPPING = { - YAML: YAML, - JSON: JSON, - } - FROM_SUFFIX = {KCLDocSuffix.YAML: YAML, KCLDocSuffix.JSON: JSON} diff --git a/internal/kclvm_py/tools/docs/i18n.py b/internal/kclvm_py/tools/docs/i18n.py deleted file mode 100644 index cfa055be7..000000000 --- a/internal/kclvm_py/tools/docs/i18n.py +++ /dev/null @@ -1,25 +0,0 @@ -import locale as _locale - -import kclvm.kcl.error as kcl_error - -LOCALE_LIST = list(_locale.locale_alias.keys()) -INVALID_I18N_LOCALE_MSG = "invalid i18n locale, expected {}" - - -def check_locale(locale: str): - """Check a locale string is a valid locale - - Parameters - ---------- - locale: locale string - """ - if ( - not locale - or not isinstance(locale, str) - or locale not in LOCALE_LIST - or locale.replace("-", "_") not in LOCALE_LIST - ): - kcl_error.report_exception( - err_type=kcl_error.ErrType.CompileError_TYPE, - arg_msg=INVALID_I18N_LOCALE_MSG.format(", ".join(LOCALE_LIST)), - ) diff --git a/internal/kclvm_py/tools/docs/link_resolver.py b/internal/kclvm_py/tools/docs/link_resolver.py deleted file mode 100644 index ba360d23c..000000000 --- a/internal/kclvm_py/tools/docs/link_resolver.py +++ /dev/null @@ -1,143 +0,0 @@ -import os -import pathlib -from abc import ABC, abstractmethod - -import kclvm.tools.docs.factory as factory -import kclvm.tools.docs.formats as doc_formats -import kclvm.tools.docs.model_pb2 as model -import kclvm.tools.docs.utils as utils - - -class LinkResolver(ABC): - """ - path resolver refills the path links in Type.type_str - """ - - def __init__(self, doc_name_formatter, schema_section_render): - self.doc_name_formatter = doc_name_formatter - self.schema_section_render = schema_section_render - - @abstractmethod - def resolve( - self, - doc: model.ModuleDoc, - root: str, - locale: str, - with_locale_suffix: bool = False, - ) -> model.ModuleDoc: - pass - - -class MarkdownLinkResolver(LinkResolver): - def resolve( - self, - module: model.ModuleDoc, - root: str, - locale: str, - with_locale_suffix: bool = False, - ) -> model.ModuleDoc: - def add_link( - tpe: model.Type, current_module: model.ModuleDoc, root: str - ) -> str: - def to_md_anchor(original: str) -> str: - return "-".join(original.lower().split()) - - def resolve_relative_path(to_dir: str, from_dir: str) -> str: - if to_dir == from_dir: - return "" - common_path = os.path.commonpath([from_dir, to_dir]) - upper_count = len(from_dir.strip("/").split("/")) - len( - common_path.strip("/").split("/") - ) - - return ( - "../" * upper_count - + to_dir.replace(common_path, "", 1).lstrip("/") - + ("" if to_dir == common_path else "/") - ) - - if tpe.type_category in [ - model.Type.TypeCategory.ANY, - model.Type.TypeCategory.BUILTIN, - model.Type.TypeCategory.LIT, - model.Type.TypeCategory.NAMED_CONSTANT, - ]: - return tpe.type_str - if tpe.type_category == model.Type.TypeCategory.SCHEMA: - assert tpe.schema_type - section_link = to_md_anchor( - self.schema_section_render(tpe.schema_type.name) - ) - from_path = pathlib.Path(current_module.relative_path) - to_path = pathlib.Path(tpe.schema_type.relative_path) - - file_link = "" - if str(from_path) != str(to_path): - # defines in different file - relative_dir = resolve_relative_path( - to_dir=str(to_path.parent), from_dir=str(from_path.parent) - ) - file_link = f"{relative_dir}{self.doc_name_formatter(utils.module_name(tpe.schema_type.relative_path), locale, doc_formats.KCLDocFormat.MARKDOWN, with_locale_suffix)}" - # remove .md file extension suffix - file_link = file_link[:-3] - return f"[{tpe.type_str}]({file_link}#{section_link})" - if tpe.type_category == model.Type.TypeCategory.UNION: - assert tpe.union_type - return " \\| ".join( - [ - add_link(t, current_module=current_module, root=root) - for t in tpe.union_type.types - ] - ) - if tpe.type_category == model.Type.TypeCategory.DICT: - assert tpe.dict_type - key_type_str = add_link( - tpe.dict_type.key_type, current_module=current_module, root=root - ) - value_type_str = add_link( - tpe.dict_type.value_type, current_module=current_module, root=root - ) - return ( - f"{{{key_type_str}: {value_type_str}}}" - if value_type_str - else f"{{{key_type_str}:}}" - ) - if tpe.type_category == model.Type.TypeCategory.LIST: - assert tpe.list_type - return f"[{add_link(tpe.list_type.item_type, current_module=current_module, root=root)}]" - return tpe.type_str - - for schema in module.schemas: - for attr in schema.attributes: - attr.type.type_str = add_link(attr.type, module, root) - if schema.base_schema: - schema.base_schema.type_str = add_link(schema.base_schema, module, root) - return module - - -class YamlLinkResolver(LinkResolver): - def resolve( - self, - module: model.ModuleDoc, - root: str, - locale: str, - with_locale_suffix: bool = False, - ) -> model.ModuleDoc: - return module - - -class JsonLinkResolver(LinkResolver): - def resolve( - self, - module: model.ModuleDoc, - root: str, - locale: str, - with_locale_suffix: bool = False, - ) -> model.ModuleDoc: - return module - - -factory = factory.PathResolverFactory() -factory.register_format(doc_formats.KCLDocFormat.MARKDOWN, MarkdownLinkResolver) -factory.register_format(doc_formats.KCLDocFormat.YAML, YamlLinkResolver) -factory.register_format(doc_formats.KCLDocFormat.JSON, JsonLinkResolver) diff --git a/internal/kclvm_py/tools/docs/makefile b/internal/kclvm_py/tools/docs/makefile deleted file mode 100644 index c4198e47d..000000000 --- a/internal/kclvm_py/tools/docs/makefile +++ /dev/null @@ -1,4 +0,0 @@ -# Copyright 2020 The KCL Authors. All rights reserved. - -default: - protoc --proto_path=. --python_out=. model.proto diff --git a/internal/kclvm_py/tools/docs/model.proto b/internal/kclvm_py/tools/docs/model.proto deleted file mode 100644 index 9002693c6..000000000 --- a/internal/kclvm_py/tools/docs/model.proto +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright 2020 The KCL Authors. All rights reserved. - -syntax = "proto3"; - -package kclvm.doc.model; - -message ModuleDoc { - string name = 1; // KCL module name - string relative_path = 2; // KCL module relative path - string doc = 3; // KCL module top-level document string - repeated SchemaDoc schemas = 4; // Schema doc list in the module - string source_code_url = 5; // The url of the KCL module source code -} - -message SchemaDoc { - string name = 1; // Schema name - string doc = 2; // Doc string of schema itself - repeated SchemaAttributeDoc attributes = 3; // Schema attribute doc list in the schema - string examples = 4; // Example string - Type base_schema = 5; // Base Schema -} - -message SchemaAttributeDoc { - string name = 1; // Schema attribute - string doc = 2; // Schema attribute document desc string - Type type = 4; // Schema attribute type - bool is_optional = 5; // If the attribute must have a value - string default_value = 6; // Default value of the attribute -} - -message Type { - string type_str = 1; - enum TypeCategory { - UNION = 0; - LIST = 1; - DICT = 2; - SCHEMA = 3; - BUILTIN = 4; - LIT = 5; - NAMED_CONSTANT = 6; - ANY = 7; - NUMBER_MULTIPLIER = 8; - } - TypeCategory type_category = 2; // the category of the type - optional UnionType union_type = 3; // optional, if the type is a union type - optional ListType list_type = 4; // optional, if the type is a list type - optional DictType dict_type = 5; // optional, if the type is a dict type - optional SchemaType schema_type = 6; // optional, if the type is a schema type - enum BuiltinType { - INT = 0; - FLOAT = 1; - STRING = 2; - BOOL = 3; - } - optional BuiltinType builtin_type = 7; // optional, if the type is a builtin type - optional LitType lit_type = 8; // optional, if the type is a literal type - enum NamedConstant { - NONE = 0; - } - optional NamedConstant named_constant = 9; // optional, if the type is a named constant -} - -message UnionType { - repeated Type types = 1; // the union types -} - -message ListType { - Type item_type = 1; // the item type -} - -message DictType { - Type key_type = 1; // the key type - Type value_type = 2; // the value type -} - -message SchemaType { - string name = 1; // the schema name - string relative_path = 2; // the relative path of the module that defines the schema -} - -message LitType { - optional string string_lit = 1; // optional, if the type is a string literal - optional int64 int_lit = 2; // optional, if the type is a int literal - optional float float_lit = 3; // optional, if the type is a float literal - optional bool bool_lit = 4; // optional, if the type is a float literal -} diff --git a/internal/kclvm_py/tools/docs/model_pb2.py b/internal/kclvm_py/tools/docs/model_pb2.py deleted file mode 100644 index 3ba02c924..000000000 --- a/internal/kclvm_py/tools/docs/model_pb2.py +++ /dev/null @@ -1,790 +0,0 @@ -# -*- coding: utf-8 -*- -# Generated by the protocol buffer compiler. DO NOT EDIT! -# source: model.proto -"""Generated protocol buffer code.""" -from google.protobuf import descriptor as _descriptor -from google.protobuf import message as _message -from google.protobuf import reflection as _reflection -from google.protobuf import symbol_database as _symbol_database -# @@protoc_insertion_point(imports) - -_sym_db = _symbol_database.Default() - - - - -DESCRIPTOR = _descriptor.FileDescriptor( - name='model.proto', - package='kclvm.doc.model', - syntax='proto3', - serialized_options=None, - create_key=_descriptor._internal_create_key, - serialized_pb=b'\n\x0bmodel.proto\x12\x0fkclvm.doc.model\"\x83\x01\n\tModuleDoc\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x15\n\rrelative_path\x18\x02 \x01(\t\x12\x0b\n\x03\x64oc\x18\x03 \x01(\t\x12+\n\x07schemas\x18\x04 \x03(\x0b\x32\x1a.kclvm.doc.model.SchemaDoc\x12\x17\n\x0fsource_code_url\x18\x05 \x01(\t\"\x9d\x01\n\tSchemaDoc\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0b\n\x03\x64oc\x18\x02 \x01(\t\x12\x37\n\nattributes\x18\x03 \x03(\x0b\x32#.kclvm.doc.model.SchemaAttributeDoc\x12\x10\n\x08\x65xamples\x18\x04 \x01(\t\x12*\n\x0b\x62\x61se_schema\x18\x05 \x01(\x0b\x32\x15.kclvm.doc.model.Type\"\x80\x01\n\x12SchemaAttributeDoc\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0b\n\x03\x64oc\x18\x02 \x01(\t\x12#\n\x04type\x18\x04 \x01(\x0b\x32\x15.kclvm.doc.model.Type\x12\x13\n\x0bis_optional\x18\x05 \x01(\x08\x12\x15\n\rdefault_value\x18\x06 \x01(\t\"\x9c\x06\n\x04Type\x12\x10\n\x08type_str\x18\x01 \x01(\t\x12\x39\n\rtype_category\x18\x02 \x01(\x0e\x32\".kclvm.doc.model.Type.TypeCategory\x12\x33\n\nunion_type\x18\x03 \x01(\x0b\x32\x1a.kclvm.doc.model.UnionTypeH\x00\x88\x01\x01\x12\x31\n\tlist_type\x18\x04 \x01(\x0b\x32\x19.kclvm.doc.model.ListTypeH\x01\x88\x01\x01\x12\x31\n\tdict_type\x18\x05 \x01(\x0b\x32\x19.kclvm.doc.model.DictTypeH\x02\x88\x01\x01\x12\x35\n\x0bschema_type\x18\x06 \x01(\x0b\x32\x1b.kclvm.doc.model.SchemaTypeH\x03\x88\x01\x01\x12<\n\x0c\x62uiltin_type\x18\x07 \x01(\x0e\x32!.kclvm.doc.model.Type.BuiltinTypeH\x04\x88\x01\x01\x12/\n\x08lit_type\x18\x08 \x01(\x0b\x32\x18.kclvm.doc.model.LitTypeH\x05\x88\x01\x01\x12@\n\x0enamed_constant\x18\t \x01(\x0e\x32#.kclvm.doc.model.Type.NamedConstantH\x06\x88\x01\x01\"\x83\x01\n\x0cTypeCategory\x12\t\n\x05UNION\x10\x00\x12\x08\n\x04LIST\x10\x01\x12\x08\n\x04\x44ICT\x10\x02\x12\n\n\x06SCHEMA\x10\x03\x12\x0b\n\x07\x42UILTIN\x10\x04\x12\x07\n\x03LIT\x10\x05\x12\x12\n\x0eNAMED_CONSTANT\x10\x06\x12\x07\n\x03\x41NY\x10\x07\x12\x15\n\x11NUMBER_MULTIPLIER\x10\x08\"7\n\x0b\x42uiltinType\x12\x07\n\x03INT\x10\x00\x12\t\n\x05\x46LOAT\x10\x01\x12\n\n\x06STRING\x10\x02\x12\x08\n\x04\x42OOL\x10\x03\"\x19\n\rNamedConstant\x12\x08\n\x04NONE\x10\x00\x42\r\n\x0b_union_typeB\x0c\n\n_list_typeB\x0c\n\n_dict_typeB\x0e\n\x0c_schema_typeB\x0f\n\r_builtin_typeB\x0b\n\t_lit_typeB\x11\n\x0f_named_constant\"1\n\tUnionType\x12$\n\x05types\x18\x01 \x03(\x0b\x32\x15.kclvm.doc.model.Type\"4\n\x08ListType\x12(\n\titem_type\x18\x01 \x01(\x0b\x32\x15.kclvm.doc.model.Type\"^\n\x08\x44ictType\x12\'\n\x08key_type\x18\x01 \x01(\x0b\x32\x15.kclvm.doc.model.Type\x12)\n\nvalue_type\x18\x02 \x01(\x0b\x32\x15.kclvm.doc.model.Type\"1\n\nSchemaType\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x15\n\rrelative_path\x18\x02 \x01(\t\"\x9d\x01\n\x07LitType\x12\x17\n\nstring_lit\x18\x01 \x01(\tH\x00\x88\x01\x01\x12\x14\n\x07int_lit\x18\x02 \x01(\x03H\x01\x88\x01\x01\x12\x16\n\tfloat_lit\x18\x03 \x01(\x02H\x02\x88\x01\x01\x12\x15\n\x08\x62ool_lit\x18\x04 \x01(\x08H\x03\x88\x01\x01\x42\r\n\x0b_string_litB\n\n\x08_int_litB\x0c\n\n_float_litB\x0b\n\t_bool_litb\x06proto3' -) - - - -_TYPE_TYPECATEGORY = _descriptor.EnumDescriptor( - name='TypeCategory', - full_name='kclvm.doc.model.Type.TypeCategory', - filename=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - values=[ - _descriptor.EnumValueDescriptor( - name='UNION', index=0, number=0, - serialized_options=None, - type=None, - create_key=_descriptor._internal_create_key), - _descriptor.EnumValueDescriptor( - name='LIST', index=1, number=1, - serialized_options=None, - type=None, - create_key=_descriptor._internal_create_key), - _descriptor.EnumValueDescriptor( - name='DICT', index=2, number=2, - serialized_options=None, - type=None, - create_key=_descriptor._internal_create_key), - _descriptor.EnumValueDescriptor( - name='SCHEMA', index=3, number=3, - serialized_options=None, - type=None, - create_key=_descriptor._internal_create_key), - _descriptor.EnumValueDescriptor( - name='BUILTIN', index=4, number=4, - serialized_options=None, - type=None, - create_key=_descriptor._internal_create_key), - _descriptor.EnumValueDescriptor( - name='LIT', index=5, number=5, - serialized_options=None, - type=None, - create_key=_descriptor._internal_create_key), - _descriptor.EnumValueDescriptor( - name='NAMED_CONSTANT', index=6, number=6, - serialized_options=None, - type=None, - create_key=_descriptor._internal_create_key), - _descriptor.EnumValueDescriptor( - name='ANY', index=7, number=7, - serialized_options=None, - type=None, - create_key=_descriptor._internal_create_key), - _descriptor.EnumValueDescriptor( - name='NUMBER_MULTIPLIER', index=8, number=8, - serialized_options=None, - type=None, - create_key=_descriptor._internal_create_key), - ], - containing_type=None, - serialized_options=None, - serialized_start=931, - serialized_end=1062, -) -_sym_db.RegisterEnumDescriptor(_TYPE_TYPECATEGORY) - -_TYPE_BUILTINTYPE = _descriptor.EnumDescriptor( - name='BuiltinType', - full_name='kclvm.doc.model.Type.BuiltinType', - filename=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - values=[ - _descriptor.EnumValueDescriptor( - name='INT', index=0, number=0, - serialized_options=None, - type=None, - create_key=_descriptor._internal_create_key), - _descriptor.EnumValueDescriptor( - name='FLOAT', index=1, number=1, - serialized_options=None, - type=None, - create_key=_descriptor._internal_create_key), - _descriptor.EnumValueDescriptor( - name='STRING', index=2, number=2, - serialized_options=None, - type=None, - create_key=_descriptor._internal_create_key), - _descriptor.EnumValueDescriptor( - name='BOOL', index=3, number=3, - serialized_options=None, - type=None, - create_key=_descriptor._internal_create_key), - ], - containing_type=None, - serialized_options=None, - serialized_start=1064, - serialized_end=1119, -) -_sym_db.RegisterEnumDescriptor(_TYPE_BUILTINTYPE) - -_TYPE_NAMEDCONSTANT = _descriptor.EnumDescriptor( - name='NamedConstant', - full_name='kclvm.doc.model.Type.NamedConstant', - filename=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - values=[ - _descriptor.EnumValueDescriptor( - name='NONE', index=0, number=0, - serialized_options=None, - type=None, - create_key=_descriptor._internal_create_key), - ], - containing_type=None, - serialized_options=None, - serialized_start=1121, - serialized_end=1146, -) -_sym_db.RegisterEnumDescriptor(_TYPE_NAMEDCONSTANT) - - -_MODULEDOC = _descriptor.Descriptor( - name='ModuleDoc', - full_name='kclvm.doc.model.ModuleDoc', - filename=None, - file=DESCRIPTOR, - containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[ - _descriptor.FieldDescriptor( - name='name', full_name='kclvm.doc.model.ModuleDoc.name', index=0, - number=1, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='relative_path', full_name='kclvm.doc.model.ModuleDoc.relative_path', index=1, - number=2, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='doc', full_name='kclvm.doc.model.ModuleDoc.doc', index=2, - number=3, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='schemas', full_name='kclvm.doc.model.ModuleDoc.schemas', index=3, - number=4, type=11, cpp_type=10, label=3, - has_default_value=False, default_value=[], - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='source_code_url', full_name='kclvm.doc.model.ModuleDoc.source_code_url', index=4, - number=5, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - ], - extensions=[ - ], - nested_types=[], - enum_types=[ - ], - serialized_options=None, - is_extendable=False, - syntax='proto3', - extension_ranges=[], - oneofs=[ - ], - serialized_start=33, - serialized_end=164, -) - - -_SCHEMADOC = _descriptor.Descriptor( - name='SchemaDoc', - full_name='kclvm.doc.model.SchemaDoc', - filename=None, - file=DESCRIPTOR, - containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[ - _descriptor.FieldDescriptor( - name='name', full_name='kclvm.doc.model.SchemaDoc.name', index=0, - number=1, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='doc', full_name='kclvm.doc.model.SchemaDoc.doc', index=1, - number=2, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='attributes', full_name='kclvm.doc.model.SchemaDoc.attributes', index=2, - number=3, type=11, cpp_type=10, label=3, - has_default_value=False, default_value=[], - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='examples', full_name='kclvm.doc.model.SchemaDoc.examples', index=3, - number=4, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='base_schema', full_name='kclvm.doc.model.SchemaDoc.base_schema', index=4, - number=5, type=11, cpp_type=10, label=1, - has_default_value=False, default_value=None, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - ], - extensions=[ - ], - nested_types=[], - enum_types=[ - ], - serialized_options=None, - is_extendable=False, - syntax='proto3', - extension_ranges=[], - oneofs=[ - ], - serialized_start=167, - serialized_end=324, -) - - -_SCHEMAATTRIBUTEDOC = _descriptor.Descriptor( - name='SchemaAttributeDoc', - full_name='kclvm.doc.model.SchemaAttributeDoc', - filename=None, - file=DESCRIPTOR, - containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[ - _descriptor.FieldDescriptor( - name='name', full_name='kclvm.doc.model.SchemaAttributeDoc.name', index=0, - number=1, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='doc', full_name='kclvm.doc.model.SchemaAttributeDoc.doc', index=1, - number=2, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='type', full_name='kclvm.doc.model.SchemaAttributeDoc.type', index=2, - number=4, type=11, cpp_type=10, label=1, - has_default_value=False, default_value=None, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='is_optional', full_name='kclvm.doc.model.SchemaAttributeDoc.is_optional', index=3, - number=5, type=8, cpp_type=7, label=1, - has_default_value=False, default_value=False, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='default_value', full_name='kclvm.doc.model.SchemaAttributeDoc.default_value', index=4, - number=6, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - ], - extensions=[ - ], - nested_types=[], - enum_types=[ - ], - serialized_options=None, - is_extendable=False, - syntax='proto3', - extension_ranges=[], - oneofs=[ - ], - serialized_start=327, - serialized_end=455, -) - - -_TYPE = _descriptor.Descriptor( - name='Type', - full_name='kclvm.doc.model.Type', - filename=None, - file=DESCRIPTOR, - containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[ - _descriptor.FieldDescriptor( - name='type_str', full_name='kclvm.doc.model.Type.type_str', index=0, - number=1, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='type_category', full_name='kclvm.doc.model.Type.type_category', index=1, - number=2, type=14, cpp_type=8, label=1, - has_default_value=False, default_value=0, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='union_type', full_name='kclvm.doc.model.Type.union_type', index=2, - number=3, type=11, cpp_type=10, label=1, - has_default_value=False, default_value=None, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='list_type', full_name='kclvm.doc.model.Type.list_type', index=3, - number=4, type=11, cpp_type=10, label=1, - has_default_value=False, default_value=None, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='dict_type', full_name='kclvm.doc.model.Type.dict_type', index=4, - number=5, type=11, cpp_type=10, label=1, - has_default_value=False, default_value=None, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='schema_type', full_name='kclvm.doc.model.Type.schema_type', index=5, - number=6, type=11, cpp_type=10, label=1, - has_default_value=False, default_value=None, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='builtin_type', full_name='kclvm.doc.model.Type.builtin_type', index=6, - number=7, type=14, cpp_type=8, label=1, - has_default_value=False, default_value=0, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='lit_type', full_name='kclvm.doc.model.Type.lit_type', index=7, - number=8, type=11, cpp_type=10, label=1, - has_default_value=False, default_value=None, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='named_constant', full_name='kclvm.doc.model.Type.named_constant', index=8, - number=9, type=14, cpp_type=8, label=1, - has_default_value=False, default_value=0, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - ], - extensions=[ - ], - nested_types=[], - enum_types=[ - _TYPE_TYPECATEGORY, - _TYPE_BUILTINTYPE, - _TYPE_NAMEDCONSTANT, - ], - serialized_options=None, - is_extendable=False, - syntax='proto3', - extension_ranges=[], - oneofs=[ - _descriptor.OneofDescriptor( - name='_union_type', full_name='kclvm.doc.model.Type._union_type', - index=0, containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[]), - _descriptor.OneofDescriptor( - name='_list_type', full_name='kclvm.doc.model.Type._list_type', - index=1, containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[]), - _descriptor.OneofDescriptor( - name='_dict_type', full_name='kclvm.doc.model.Type._dict_type', - index=2, containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[]), - _descriptor.OneofDescriptor( - name='_schema_type', full_name='kclvm.doc.model.Type._schema_type', - index=3, containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[]), - _descriptor.OneofDescriptor( - name='_builtin_type', full_name='kclvm.doc.model.Type._builtin_type', - index=4, containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[]), - _descriptor.OneofDescriptor( - name='_lit_type', full_name='kclvm.doc.model.Type._lit_type', - index=5, containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[]), - _descriptor.OneofDescriptor( - name='_named_constant', full_name='kclvm.doc.model.Type._named_constant', - index=6, containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[]), - ], - serialized_start=458, - serialized_end=1254, -) - - -_UNIONTYPE = _descriptor.Descriptor( - name='UnionType', - full_name='kclvm.doc.model.UnionType', - filename=None, - file=DESCRIPTOR, - containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[ - _descriptor.FieldDescriptor( - name='types', full_name='kclvm.doc.model.UnionType.types', index=0, - number=1, type=11, cpp_type=10, label=3, - has_default_value=False, default_value=[], - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - ], - extensions=[ - ], - nested_types=[], - enum_types=[ - ], - serialized_options=None, - is_extendable=False, - syntax='proto3', - extension_ranges=[], - oneofs=[ - ], - serialized_start=1256, - serialized_end=1305, -) - - -_LISTTYPE = _descriptor.Descriptor( - name='ListType', - full_name='kclvm.doc.model.ListType', - filename=None, - file=DESCRIPTOR, - containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[ - _descriptor.FieldDescriptor( - name='item_type', full_name='kclvm.doc.model.ListType.item_type', index=0, - number=1, type=11, cpp_type=10, label=1, - has_default_value=False, default_value=None, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - ], - extensions=[ - ], - nested_types=[], - enum_types=[ - ], - serialized_options=None, - is_extendable=False, - syntax='proto3', - extension_ranges=[], - oneofs=[ - ], - serialized_start=1307, - serialized_end=1359, -) - - -_DICTTYPE = _descriptor.Descriptor( - name='DictType', - full_name='kclvm.doc.model.DictType', - filename=None, - file=DESCRIPTOR, - containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[ - _descriptor.FieldDescriptor( - name='key_type', full_name='kclvm.doc.model.DictType.key_type', index=0, - number=1, type=11, cpp_type=10, label=1, - has_default_value=False, default_value=None, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='value_type', full_name='kclvm.doc.model.DictType.value_type', index=1, - number=2, type=11, cpp_type=10, label=1, - has_default_value=False, default_value=None, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - ], - extensions=[ - ], - nested_types=[], - enum_types=[ - ], - serialized_options=None, - is_extendable=False, - syntax='proto3', - extension_ranges=[], - oneofs=[ - ], - serialized_start=1361, - serialized_end=1455, -) - - -_SCHEMATYPE = _descriptor.Descriptor( - name='SchemaType', - full_name='kclvm.doc.model.SchemaType', - filename=None, - file=DESCRIPTOR, - containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[ - _descriptor.FieldDescriptor( - name='name', full_name='kclvm.doc.model.SchemaType.name', index=0, - number=1, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='relative_path', full_name='kclvm.doc.model.SchemaType.relative_path', index=1, - number=2, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - ], - extensions=[ - ], - nested_types=[], - enum_types=[ - ], - serialized_options=None, - is_extendable=False, - syntax='proto3', - extension_ranges=[], - oneofs=[ - ], - serialized_start=1457, - serialized_end=1506, -) - - -_LITTYPE = _descriptor.Descriptor( - name='LitType', - full_name='kclvm.doc.model.LitType', - filename=None, - file=DESCRIPTOR, - containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[ - _descriptor.FieldDescriptor( - name='string_lit', full_name='kclvm.doc.model.LitType.string_lit', index=0, - number=1, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='int_lit', full_name='kclvm.doc.model.LitType.int_lit', index=1, - number=2, type=3, cpp_type=2, label=1, - has_default_value=False, default_value=0, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='float_lit', full_name='kclvm.doc.model.LitType.float_lit', index=2, - number=3, type=2, cpp_type=6, label=1, - has_default_value=False, default_value=float(0), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='bool_lit', full_name='kclvm.doc.model.LitType.bool_lit', index=3, - number=4, type=8, cpp_type=7, label=1, - has_default_value=False, default_value=False, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - ], - extensions=[ - ], - nested_types=[], - enum_types=[ - ], - serialized_options=None, - is_extendable=False, - syntax='proto3', - extension_ranges=[], - oneofs=[ - _descriptor.OneofDescriptor( - name='_string_lit', full_name='kclvm.doc.model.LitType._string_lit', - index=0, containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[]), - _descriptor.OneofDescriptor( - name='_int_lit', full_name='kclvm.doc.model.LitType._int_lit', - index=1, containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[]), - _descriptor.OneofDescriptor( - name='_float_lit', full_name='kclvm.doc.model.LitType._float_lit', - index=2, containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[]), - _descriptor.OneofDescriptor( - name='_bool_lit', full_name='kclvm.doc.model.LitType._bool_lit', - index=3, containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[]), - ], - serialized_start=1509, - serialized_end=1666, -) - -_MODULEDOC.fields_by_name['schemas'].message_type = _SCHEMADOC -_SCHEMADOC.fields_by_name['attributes'].message_type = _SCHEMAATTRIBUTEDOC -_SCHEMADOC.fields_by_name['base_schema'].message_type = _TYPE -_SCHEMAATTRIBUTEDOC.fields_by_name['type'].message_type = _TYPE -_TYPE.fields_by_name['type_category'].enum_type = _TYPE_TYPECATEGORY -_TYPE.fields_by_name['union_type'].message_type = _UNIONTYPE -_TYPE.fields_by_name['list_type'].message_type = _LISTTYPE -_TYPE.fields_by_name['dict_type'].message_type = _DICTTYPE -_TYPE.fields_by_name['schema_type'].message_type = _SCHEMATYPE -_TYPE.fields_by_name['builtin_type'].enum_type = _TYPE_BUILTINTYPE -_TYPE.fields_by_name['lit_type'].message_type = _LITTYPE -_TYPE.fields_by_name['named_constant'].enum_type = _TYPE_NAMEDCONSTANT -_TYPE_TYPECATEGORY.containing_type = _TYPE -_TYPE_BUILTINTYPE.containing_type = _TYPE -_TYPE_NAMEDCONSTANT.containing_type = _TYPE -_TYPE.oneofs_by_name['_union_type'].fields.append( - _TYPE.fields_by_name['union_type']) -_TYPE.fields_by_name['union_type'].containing_oneof = _TYPE.oneofs_by_name['_union_type'] -_TYPE.oneofs_by_name['_list_type'].fields.append( - _TYPE.fields_by_name['list_type']) -_TYPE.fields_by_name['list_type'].containing_oneof = _TYPE.oneofs_by_name['_list_type'] -_TYPE.oneofs_by_name['_dict_type'].fields.append( - _TYPE.fields_by_name['dict_type']) -_TYPE.fields_by_name['dict_type'].containing_oneof = _TYPE.oneofs_by_name['_dict_type'] -_TYPE.oneofs_by_name['_schema_type'].fields.append( - _TYPE.fields_by_name['schema_type']) -_TYPE.fields_by_name['schema_type'].containing_oneof = _TYPE.oneofs_by_name['_schema_type'] -_TYPE.oneofs_by_name['_builtin_type'].fields.append( - _TYPE.fields_by_name['builtin_type']) -_TYPE.fields_by_name['builtin_type'].containing_oneof = _TYPE.oneofs_by_name['_builtin_type'] -_TYPE.oneofs_by_name['_lit_type'].fields.append( - _TYPE.fields_by_name['lit_type']) -_TYPE.fields_by_name['lit_type'].containing_oneof = _TYPE.oneofs_by_name['_lit_type'] -_TYPE.oneofs_by_name['_named_constant'].fields.append( - _TYPE.fields_by_name['named_constant']) -_TYPE.fields_by_name['named_constant'].containing_oneof = _TYPE.oneofs_by_name['_named_constant'] -_UNIONTYPE.fields_by_name['types'].message_type = _TYPE -_LISTTYPE.fields_by_name['item_type'].message_type = _TYPE -_DICTTYPE.fields_by_name['key_type'].message_type = _TYPE -_DICTTYPE.fields_by_name['value_type'].message_type = _TYPE -_LITTYPE.oneofs_by_name['_string_lit'].fields.append( - _LITTYPE.fields_by_name['string_lit']) -_LITTYPE.fields_by_name['string_lit'].containing_oneof = _LITTYPE.oneofs_by_name['_string_lit'] -_LITTYPE.oneofs_by_name['_int_lit'].fields.append( - _LITTYPE.fields_by_name['int_lit']) -_LITTYPE.fields_by_name['int_lit'].containing_oneof = _LITTYPE.oneofs_by_name['_int_lit'] -_LITTYPE.oneofs_by_name['_float_lit'].fields.append( - _LITTYPE.fields_by_name['float_lit']) -_LITTYPE.fields_by_name['float_lit'].containing_oneof = _LITTYPE.oneofs_by_name['_float_lit'] -_LITTYPE.oneofs_by_name['_bool_lit'].fields.append( - _LITTYPE.fields_by_name['bool_lit']) -_LITTYPE.fields_by_name['bool_lit'].containing_oneof = _LITTYPE.oneofs_by_name['_bool_lit'] -DESCRIPTOR.message_types_by_name['ModuleDoc'] = _MODULEDOC -DESCRIPTOR.message_types_by_name['SchemaDoc'] = _SCHEMADOC -DESCRIPTOR.message_types_by_name['SchemaAttributeDoc'] = _SCHEMAATTRIBUTEDOC -DESCRIPTOR.message_types_by_name['Type'] = _TYPE -DESCRIPTOR.message_types_by_name['UnionType'] = _UNIONTYPE -DESCRIPTOR.message_types_by_name['ListType'] = _LISTTYPE -DESCRIPTOR.message_types_by_name['DictType'] = _DICTTYPE -DESCRIPTOR.message_types_by_name['SchemaType'] = _SCHEMATYPE -DESCRIPTOR.message_types_by_name['LitType'] = _LITTYPE -_sym_db.RegisterFileDescriptor(DESCRIPTOR) - -ModuleDoc = _reflection.GeneratedProtocolMessageType('ModuleDoc', (_message.Message,), { - 'DESCRIPTOR' : _MODULEDOC, - '__module__' : 'model_pb2' - # @@protoc_insertion_point(class_scope:kclvm.doc.model.ModuleDoc) - }) -_sym_db.RegisterMessage(ModuleDoc) - -SchemaDoc = _reflection.GeneratedProtocolMessageType('SchemaDoc', (_message.Message,), { - 'DESCRIPTOR' : _SCHEMADOC, - '__module__' : 'model_pb2' - # @@protoc_insertion_point(class_scope:kclvm.doc.model.SchemaDoc) - }) -_sym_db.RegisterMessage(SchemaDoc) - -SchemaAttributeDoc = _reflection.GeneratedProtocolMessageType('SchemaAttributeDoc', (_message.Message,), { - 'DESCRIPTOR' : _SCHEMAATTRIBUTEDOC, - '__module__' : 'model_pb2' - # @@protoc_insertion_point(class_scope:kclvm.doc.model.SchemaAttributeDoc) - }) -_sym_db.RegisterMessage(SchemaAttributeDoc) - -Type = _reflection.GeneratedProtocolMessageType('Type', (_message.Message,), { - 'DESCRIPTOR' : _TYPE, - '__module__' : 'model_pb2' - # @@protoc_insertion_point(class_scope:kclvm.doc.model.Type) - }) -_sym_db.RegisterMessage(Type) - -UnionType = _reflection.GeneratedProtocolMessageType('UnionType', (_message.Message,), { - 'DESCRIPTOR' : _UNIONTYPE, - '__module__' : 'model_pb2' - # @@protoc_insertion_point(class_scope:kclvm.doc.model.UnionType) - }) -_sym_db.RegisterMessage(UnionType) - -ListType = _reflection.GeneratedProtocolMessageType('ListType', (_message.Message,), { - 'DESCRIPTOR' : _LISTTYPE, - '__module__' : 'model_pb2' - # @@protoc_insertion_point(class_scope:kclvm.doc.model.ListType) - }) -_sym_db.RegisterMessage(ListType) - -DictType = _reflection.GeneratedProtocolMessageType('DictType', (_message.Message,), { - 'DESCRIPTOR' : _DICTTYPE, - '__module__' : 'model_pb2' - # @@protoc_insertion_point(class_scope:kclvm.doc.model.DictType) - }) -_sym_db.RegisterMessage(DictType) - -SchemaType = _reflection.GeneratedProtocolMessageType('SchemaType', (_message.Message,), { - 'DESCRIPTOR' : _SCHEMATYPE, - '__module__' : 'model_pb2' - # @@protoc_insertion_point(class_scope:kclvm.doc.model.SchemaType) - }) -_sym_db.RegisterMessage(SchemaType) - -LitType = _reflection.GeneratedProtocolMessageType('LitType', (_message.Message,), { - 'DESCRIPTOR' : _LITTYPE, - '__module__' : 'model_pb2' - # @@protoc_insertion_point(class_scope:kclvm.doc.model.LitType) - }) -_sym_db.RegisterMessage(LitType) - - -# @@protoc_insertion_point(module_scope) diff --git a/internal/kclvm_py/tools/docs/pb.py b/internal/kclvm_py/tools/docs/pb.py deleted file mode 100644 index ac1347a14..000000000 --- a/internal/kclvm_py/tools/docs/pb.py +++ /dev/null @@ -1,13 +0,0 @@ -# Copyright 2020 The KCL Authors. All rights reserved. - -import google.protobuf.json_format as json_format - - -def FromJson(text: str, message): - return json_format.Parse(text, message) - - -def ToJson(message) -> str: - return json_format.MessageToJson( - message, including_default_value_fields=True, preserving_proto_field_name=True - ) diff --git a/internal/kclvm_py/tools/docs/reader.py b/internal/kclvm_py/tools/docs/reader.py deleted file mode 100644 index 42f439aae..000000000 --- a/internal/kclvm_py/tools/docs/reader.py +++ /dev/null @@ -1,82 +0,0 @@ -import ruamel.yaml as yaml -import json -import io - -from abc import ABC, abstractmethod - -import kclvm.tools.docs.pb as pb -import kclvm.tools.docs.model_pb2 as model -import kclvm.tools.docs.factory as factory -import kclvm.tools.docs.formats as doc_formats - -# --------------------------------------------------- -# Constants -# --------------------------------------------------- - - -ENDLINE = "\n" - - -# ------------------------------------------------------- -# Document reader from KCL ModuleDoc type ot markdown type -# ------------------------------------------------------- - - -class ModuleDocReader(ABC): - """Module document reader class. - - This class provides basic functions for reader KCL Module from the IO. - """ - - def __init__(self, io_in: io.TextIOBase): - self.io_in: io.TextIOBase = io_in - - @abstractmethod - def read_doc(self) -> model.ModuleDoc: - pass - - def read(self) -> str: - return self.io_in.read() - - -class JsonDocReader(ModuleDocReader): - """JSON document reader based on ModuleDocReader. - - The class is used to read KCL module document from JSON file. - """ - - def _load_module_from_json(self, data) -> model.ModuleDoc: - return pb.FromJson(data, model.ModuleDoc()) - - def read_doc(self) -> model.ModuleDoc: - json_data = self.read() - return self._load_module_from_json(json_data) - - -class YamlDocReader(JsonDocReader): - """YAML document reader based on JsonDocReader. - - The class is used to read KCL module document from YAML file - """ - - def read_doc(self) -> model.ModuleDoc: - dict_data = yaml.safe_load(self.io_in) - json_data = json.dumps(dict_data) - return self._load_module_from_json(json_data) - - -class MarkDownDocReader(YamlDocReader): - """Markdown document reader based on KCLModuleDocReader. - - The class is used to read KCL module document from markdown file. - """ - - def read_doc(self) -> model.ModuleDoc: - """TODO: Parse a Markdown string to KCL module document model.""" - raise NotImplementedError() - - -factory = factory.IOFactory() -factory.register_format(doc_formats.KCLDocFormat.JSON, JsonDocReader) -factory.register_format(doc_formats.KCLDocFormat.YAML, YamlDocReader) -factory.register_format(doc_formats.KCLDocFormat.MARKDOWN, MarkDownDocReader) diff --git a/internal/kclvm_py/tools/docs/templater.py b/internal/kclvm_py/tools/docs/templater.py deleted file mode 100644 index c73b53078..000000000 --- a/internal/kclvm_py/tools/docs/templater.py +++ /dev/null @@ -1,78 +0,0 @@ -# class DocTemplater -import kclvm.tools.docs.model_pb2 as model - - -def md_schema_section_render(schema_name: str): - return f"Schema {schema_name}" - - -def md_module_doc_templater(module: model.ModuleDoc) -> str: - def table(records, headings) -> str: - """ - Generate a Markdown table from records. - records -- Iterable. Rows will be generated from this. - headings -- List of column headings. - """ - table_heading = ( - f"|{'|'.join(headings)}|\n|{'|'.join(['-' * len(h) for h in headings])}|\n" - ) - table_rows = "\n".join( - [f"|{record[0]}|{record[1]}|{record[2]}|{record[3]}|" for record in records] - ) - return f"{table_heading}{table_rows}\n" - - # module header - header = f"# {module.name}\n\n" - # source code link - file_name = module.relative_path.replace("./", "") - source_code = ( - f"Source: [{file_name}]({module.source_code_url}/{file_name})\n\n" - if module.source_code_url - else "" - ) - # module doc string - module_doc = f"{module.doc}\n\n" if module.doc else "" - # schemas header - schemas_section = "" - if module.schemas: - for schema in module.schemas: - _schema_header = f"## Schema {schema.name}\n\n" - _schema_docstring = f"{schema.doc}\n\n" if schema.doc else "" - - _base_schema_section = "" - if schema.base_schema and schema.base_schema.type_str: - _base_schema_section = ( - f"### Base Schema\n{schema.base_schema.type_str}\n\n" - ) - - attributes_section = "" - if schema.attributes: - attributes_header = "### Attributes\n\n" - attributes_table = table( - [ - [ - f"**{a.name}**
{a.doc}" if a.doc else f"**{a.name}**", - a.type.type_str, - a.default_value if a.default_value else "Undefined", - "optional" if a.is_optional else "**required**", - ] - for a in schema.attributes - ], - [ - "Name and Description", - "Type", - "Default Value", - "Required", - ], - ) - attributes_section = f"{attributes_header}{attributes_table}" - # Examples - _examples = ( - f"### Examples\n```python\n{schema.examples}\n```\n\n" - if schema.examples - else "" - ) - schemas_section = f"{schemas_section}{_schema_header}{_schema_docstring}{_base_schema_section}{attributes_section}{_examples}" - # not editable footer - not_editable = "" - return f"{header}{source_code}{module_doc}{schemas_section}{not_editable}" diff --git a/internal/kclvm_py/tools/docs/utils.py b/internal/kclvm_py/tools/docs/utils.py deleted file mode 100644 index e09306f79..000000000 --- a/internal/kclvm_py/tools/docs/utils.py +++ /dev/null @@ -1,5 +0,0 @@ -from pathlib import Path - - -def module_name(file_path: str) -> str: - return Path(file_path).with_suffix("").name diff --git a/internal/kclvm_py/tools/docs/writer.py b/internal/kclvm_py/tools/docs/writer.py deleted file mode 100644 index cd5380935..000000000 --- a/internal/kclvm_py/tools/docs/writer.py +++ /dev/null @@ -1,108 +0,0 @@ -from ruamel.yaml import YAML -import io - -from abc import ABC, abstractmethod - -import kclvm.tools.docs.pb as pb -import kclvm.tools.docs.model_pb2 as model -import kclvm.tools.docs.factory as factory -import kclvm.tools.docs.formats as doc_formats -import kclvm.tools.docs.templater as templater - - -# --------------------------------------------------- -# Constants -# --------------------------------------------------- - - -ENDLINE = "\n" - - -# ------------------------------------------------------- -# Document writer from KCL ModuleDoc type ot markdown type -# ------------------------------------------------------- - - -class ModuleDocWriter(ABC): - """Module document writer class. - - This class provides basic functions for write KCL Module to the IO. - """ - - def __init__(self, out: io.TextIOBase): - self.out: io.TextIOBase = out - - @abstractmethod - def write_doc(self, module: model.ModuleDoc) -> None: - pass - - def write(self, content: str = ""): - """Write the content to the string io""" - self.out.write(content) - - def writeln(self, content: str = ""): - """Write the content with an endline to the string io""" - self.write(content + ENDLINE) - - -class JsonDocWriter(ModuleDocWriter): - """JSON document writer based on ModuleDocWriter. - - The class is used to generate JSON file from KCL module document string. - """ - - def _dump_json_str(self, module: model.ModuleDoc) -> str: - return pb.ToJson(module) - - def write_doc(self, module: model.ModuleDoc) -> None: - json_str = self._dump_json_str(module) - self.write(json_str) - - -class YamlDocWriter(JsonDocWriter): - """YAML document writer based on JsonDocWriter. - - The class is used to generate YAML file from KCL module document string. - """ - - def write_doc(self, module: model.ModuleDoc) -> None: - def set_style(d, flow): - if isinstance(d, dict): - if flow: - d.fa.set_flow_style() - else: - d.fa.set_block_style() - for k in d: - set_style(d[k], flow) - elif isinstance(d, list): - if flow: - d.fa.set_flow_style() - else: - d.fa.set_block_style() - for item in d: - set_style(item, flow) - - json_str = self._dump_json_str(module) - yaml = YAML() - data = yaml.load(json_str) - set_style(data, flow=False) - yaml.dump(data, self.out) - - -class MarkDownDocWriter(ModuleDocWriter): - """Markdown document writer based on KCLModuleDocWriter. - - The class is used to generate markdown file from KCL module document string. - """ - - def write_doc(self, module: model.ModuleDoc) -> None: - """ - Write document - """ - self.writeln(templater.md_module_doc_templater(module)) - - -factory = factory.IOFactory() -factory.register_format(doc_formats.KCLDocFormat.JSON, JsonDocWriter) -factory.register_format(doc_formats.KCLDocFormat.YAML, YamlDocWriter) -factory.register_format(doc_formats.KCLDocFormat.MARKDOWN, MarkDownDocWriter) diff --git a/internal/kclvm_py/tools/format/__init__.py b/internal/kclvm_py/tools/format/__init__.py deleted file mode 100644 index 1eb89b48f..000000000 --- a/internal/kclvm_py/tools/format/__init__.py +++ /dev/null @@ -1,21 +0,0 @@ -# Copyright 2021 The KCL Authors. All rights reserved. - -from .format import ( - TextAdapterWalker, - Formatter, - kcl_ast_to_fmt_file, - kcl_fmt_source, - kcl_fmt_dir, - kcl_fmt_file, - kcl_fmt, -) - -__all__ = [ - "TextAdapterWalker", - "Formatter", - "kcl_ast_to_fmt_file", - "kcl_fmt_source", - "kcl_fmt_dir", - "kcl_fmt_file", - "kcl_fmt", -] diff --git a/internal/kclvm_py/tools/format/__main__.py b/internal/kclvm_py/tools/format/__main__.py deleted file mode 100644 index 30e42a97d..000000000 --- a/internal/kclvm_py/tools/format/__main__.py +++ /dev/null @@ -1,55 +0,0 @@ -import sys -import argparse -import traceback - -from kclvm.tools.format.format import kcl_fmt - - -def kcl_format_main(): - """KCL format tool CLI entry point""" - parser = argparse.ArgumentParser(prog="kcl-fmt") - parser.add_argument( - dest="file", - type=str, - help="Input file or path name for formatting", - ) - parser.add_argument( - "-R", - "--recursive", - dest="recursive", - help="Iterate through subdirectories recursively", - action="store_true", - required=False, - ) - parser.add_argument( - "-w", - "--std-output", - dest="std_output", - help="Whether to output format to stdout", - action="store_true", - required=False, - ) - parser.add_argument( - "-d", - "--debug", - dest="debug_mode", - help="Run in debug mode (for developers only)", - action="store_true", - required=False, - ) - args = parser.parse_args() - if len(sys.argv) == 1: - parser.print_help(sys.stdout) - sys.exit(0) - - try: - kcl_fmt(args.file, is_stdout=args.std_output, recursively=args.recursive) - except Exception as err: - if args.debug_mode: - print(traceback.format_exc()) - else: - print(f"{err}") - - -if __name__ == "__main__": - kcl_format_main() diff --git a/internal/kclvm_py/tools/format/format.py b/internal/kclvm_py/tools/format/format.py deleted file mode 100644 index 0389d02ba..000000000 --- a/internal/kclvm_py/tools/format/format.py +++ /dev/null @@ -1,812 +0,0 @@ -# Copyright 2021 The KCL Authors. All rights reserved. - -import re -import pathlib - -from io import StringIO -from typing import List, Union - -import kclvm.kcl.error as kcl_error -import kclvm.internal.log as klog - -from kclvm.compiler.parser.lark_tree import get_lark_tree_from_expr -from kclvm.compiler.parser.lark_tree import ( - Token, - Tree, - AstType, - TreeWalker, - TOKEN_TYPE, - TREE_TYPE, - OPERATOR_TOKENS, -) - -_INVALID_NEWLINE_STRING_MSG = "invalid NEWLINE token string value {}" -_INLINE_COMMENT_REGEX = "#[^\n]*\n" -_INLINE_COMMENT_WITH_MULTILINE_REGEX = "#[^\n]*[\n\t ]*" -_NODE_WITH_NEWLINE_EXPRS = [ - Tree.CONFIG_EXPR, - Tree.DICT_COMP, - Tree.DICT_EXPR, - Tree.LIST_COMP, - Tree.LIST_EXPR, - Tree.COMP_CLAUSE, - Tree.SIMPLE_STMT, - Tree.SCHEMA_MEMBER_STMT, - Tree.MIXINS, -] -SEPARATOR_TOKEN = " " -EMPTY_TOKEN = "" -ENDLINE_TOKEN = "\n" -COMMENT_START_TOKEN = "#" - - -class TextAdapterWalker(TreeWalker): - """ - Walker adapted for text processing, can be used as a semantic-independent - walker super class such as formatter and linter - """ - - def __init__(self): - super().__init__() - self.printer = StringIO() # Printer used to write expressions and tokens - self.indent_level: int = 0 # Now indent level - self.indent_queue = [0] # Indent queue - self.indent_space_count: int = 4 # Default indent space count - - def write(self, text: str) -> None: - """Append a piece of text to the current line.""" - self.printer.write(text) - - def write_token_separator(self) -> None: - """Print the separator between tokens.""" - self.write(SEPARATOR_TOKEN) - - def walk_node(self, node: Union[AstType, str]) -> None: - """Write node""" - if isinstance(node, str): - self.write(node) - else: - self.walk(node) - - def fill(self, text: str = "") -> None: - """Append a piece of text to the current line.""" - self.printer.write(ENDLINE_TOKEN) - self.write_indent() - self.printer.write(text) - - def write_indent(self) -> None: - """Append indent white space according indent level""" - self.printer.write( - self.indent_space_count * self.indent_level * SEPARATOR_TOKEN - ) - - def count_blank_line(self, text: str) -> int: - """Blank line count in a NEWLINE token""" - return re.sub(_INLINE_COMMENT_REGEX, EMPTY_TOKEN, text).count(ENDLINE_TOKEN) - 1 - - def count_indent(self, text: str) -> int: - """ - Count the indent by number of white spaces for a leading text - e.g. NEWLINE "\n " its indent count is 4 - e.g. NEWLINE "\n # inline comment\n " its indent count is 3 - """ - if ENDLINE_TOKEN not in text: - return 0 - line = text.split(ENDLINE_TOKEN)[-1] - temptext = line.replace(SEPARATOR_TOKEN, EMPTY_TOKEN) - count = len(line) if len(temptext) == 0 else 0 - if count not in self.indent_queue: - # Indent increase - self.indent_queue.append(count) - else: - # Indent decrease - idx = self.indent_queue.index(count) - del self.indent_queue[idx + 1 :] - idx = self.indent_queue.index(count) - self.indent_level = idx - return count - - def generic_walk(self, node: AstType) -> None: - """Called if no explicit walker function exists for a node.""" - if node["type"] == TOKEN_TYPE: - self.walk_pre_token(node) - self.walk_token(node) - self.walk_post_token(node) - elif node["type"] == TREE_TYPE: - for n in node["children"]: - self.walk(n) - else: - kcl_error.report_exception( - err_type=kcl_error.ErrType.CompileError_TYPE, - arg_msg="Unknown format node type", - ) - - def walk_pre_token(self, node: AstType) -> None: - """Deal after token""" - pass - - def walk_post_token(self, node: AstType) -> None: - """Deal after token""" - pass - - def walk_token(self, node: AstType) -> None: - """AST: token""" - pass - - -class Formatter(TextAdapterWalker): - def __init__(self) -> None: - super().__init__() - self.last_token: str = EMPTY_TOKEN # Last token name - self.last_token_value: str = EMPTY_TOKEN # Last token value - self.single_comment_spaces: int = 2 # Inline comment after its expressions - self.max_blank_line: int = 1 # Maximum number of blank lines - self._is_in_arguments = False # Mark is in arguments - self._is_in_collection_if = False # Mark is in collection if - self._is_colon_without_space = False # Mark is in expr with colon except space - - # Base - - def generic_walk(self, node: AstType) -> None: - """Formatter special walk""" - if node["name"] in _NODE_WITH_NEWLINE_EXPRS: - self.write_node_with_newline(node) - else: - super().generic_walk(node) - - # Tokens - - def add_blank_line(self) -> None: - """Blank line before and after schema_stmt""" - if ( - self.last_token == Token.NEWLINE - and self.count_blank_line(self.last_token_value) < self.max_blank_line - ): - self.write_token(ENDLINE_TOKEN) - self.last_token = Token.NEWLINE - self.last_token_value = ENDLINE_TOKEN * 2 - - def split_newline_value(self, value: str) -> List[str]: - """Split a NEWLINE token value into newline parts and inline comment parts - - Input: "\n \n # comment \n # comment \n\n # comment \n" - Output: ["\n \n ", "# comment ", "\n ", "# comment ", "\n\n ", "# comment ", "\n"] - """ - if not value: - return [] - parts = [] - # Mark containing COMMENT token - index = value.find(COMMENT_START_TOKEN) - if index == -1: - return [value] # Single NEWLINE without COMMENT - elif index > 0: - parts.append(value[:index]) # Add first NEWLINE token - inline_comments = re.findall(_INLINE_COMMENT_WITH_MULTILINE_REGEX, value) - for comment in inline_comments: - index = comment.find(ENDLINE_TOKEN) - if index == -1: - kcl_error.report_exception( - err_type=kcl_error.ErrType.CompileError_TYPE, - arg_msg=_INVALID_NEWLINE_STRING_MSG.format(comment), - ) - parts.append(comment[:index]) # Add COMMENT token - parts.append(comment[index:]) # Add NEWLINE token - if len(parts) > 1 and ENDLINE_TOKEN not in parts[-1]: - # Last part is not NEWLINE, raise an error - kcl_error.report_exception( - err_type=kcl_error.ErrType.CompileError_TYPE, - arg_msg=_INVALID_NEWLINE_STRING_MSG.format(value), - ) - return parts - - def write_newline(self, value: str) -> None: - """ - Write newline except inline comment - """ - blank_line_count = self.count_blank_line(value) - value = value.replace(SEPARATOR_TOKEN, "") - newline_count = 0 - for i, c in enumerate(value): - if c == ENDLINE_TOKEN: - newline_count += 1 - # Consecutive blank lines - if newline_count < blank_line_count: - pass - # If there is a blank line, keep it - elif self.count_blank_line(value[i + 1 :]): - self.fill() - # First NEWLINE in last expr - else: - self.write(ENDLINE_TOKEN) - - def walk_newline(self, token: AstType) -> None: - """ - Format NEWLINE token contains '#', '\n' and ' ' - """ - # Record indent level and Windows line break handling and 1 tab <-> 4 spaces - value = token["value"].replace("\r", ENDLINE_TOKEN).replace("\t", " ") - # Remove start blank lines except comments and first token is NEWLINE - if self.last_token == "": - # Get all inline comments - self.write("".join(re.findall(_INLINE_COMMENT_REGEX, value))) - return - # Record indent - self.count_indent(value) - parts = self.split_newline_value(value) - for part in parts: - if part.startswith(COMMENT_START_TOKEN): - self.write(part) - else: - self.write_newline(part) - - def write_string(self, value: str) -> None: - """Print KCL string with prefix""" - quota = False - for c in value: - # The string prefix is uniformly lowercase - if not quota: - c = c.lower() - # String start quotation marks - if c == '"' or c == "'": - quota = True - self.write(c) - - def write_token(self, node: Union[str, AstType]) -> None: - """Write token node or token string""" - if not node: - return - if isinstance(node, str): - self.write(node) - else: - self.walk_token(node) - - def walk_post_token(self, token: AstType) -> None: - """Deal after token""" - name, value = token["name"], token["value"] - if name == Token.ASSIGN and self._is_in_arguments: - # Do not write space between '=' in kwargs - pass - elif ( - name == Token.COLON - and self._is_colon_without_space - and not self._is_in_arguments - ): - # Do not write space after colon ':' e.g. check: and schema Name: - pass - elif ( - name in [Token.PLUS, Token.MINUS, Token.NOT] - and self.last_token in OPERATOR_TOKENS - ): - # Do not write space between unary operator - pass - elif name in OPERATOR_TOKENS: - self.write_token_separator() - elif name == Token.FOR and self.last_token != Token.NEWLINE: - self.write_token_separator() - elif name in [Token.IF, Token.ELIF] and self._is_in_collection_if: - self.write_token_separator() - # Write space after , and : except NEWLINE behind it and write space behind keyword - elif name in [ - Token.IMPORT, - Token.LAMBDA, - Token.SCHEMA, - Token.RELAXED, - Token.ASSERT, - Token.FINAL, - Token.IN, - Token.AS, - Token.IS, - Token.MIXIN, - Token.PROTOCOL, - Token.TYPE, - Token.COMMA, - Token.COLON, - Token.L_AND, - Token.L_OR, - Token.L_L_NOT, - Token.SEMI_COLON, - Token.ALL, - Token.ANY, - Token.MAP, - Token.FILTER, - ]: - self.write_token_separator() - self.last_token, self.last_token_value = name, value - - def walk_pre_token(self, token: AstType) -> None: - """Deal before token""" - name = token["name"] - value = token["value"] - if name == Token.ASSIGN and self._is_in_arguments: - # Do not write space between '=' in kwargs - pass - elif ( - name in [Token.PLUS, Token.MINUS, Token.NOT] - and self.last_token in OPERATOR_TOKENS - ): - # Do not write space between unary operator - pass - elif name in OPERATOR_TOKENS: - self.write_token_separator() - elif name == Token.FOR and self.last_token != Token.NEWLINE: - self.write_token_separator() - elif name in [Token.IN, Token.AS, Token.IS, Token.L_AND, Token.L_OR]: - self.write_token_separator() - elif ( - name == Token.NEWLINE - and value.startswith(COMMENT_START_TOKEN) - and self.last_token != "" - ): - # Two spaces between expr and inline comment # - self.write(SEPARATOR_TOKEN * self.single_comment_spaces) - - def walk_token(self, token: AstType) -> None: - """AST: token node""" - name = token["name"] - value = token["value"] - if name == Token.NEWLINE: - self.walk_newline(token) - elif Token.is_string(name): - self.write_string(value) - else: - self.write_token(value) - - # Exprs - - def write_expr(self, node: AstType) -> None: - """Write expr""" - if node: - self.walk_nodes(*node["children"]) - - def write_arguments(self, nodes: List[AstType]) -> None: - """Arguments in call_expr, str_expr and schema_expr""" - self._is_in_arguments = True - self.walk_nodes(*nodes) - self._is_in_arguments = False - - def walk_call_suffix(self, node: AstType) -> None: - """AST: call_suffix - - call_suffix: LEFT_PARENTHESES [arguments [COMMA]] RIGHT_PARENTHESES - """ - self.write_arguments(node["children"]) - - def walk_schema_expr(self, node: AstType) -> None: - """AST: schema_expr - - schema_expr: identifier (LEFT_PARENTHESES [arguments] RIGHT_PARENTHESES)? dict_expr - """ - self.write_expr(self.get(node, Tree.IDENTIFIER)) - self.write_arguments( - self.get_internal(node, Token.LEFT_PARENTHESES, Token.RIGHT_PARENTHESES) - ) - # Write space between 'SchemaName' and '{}' in schema_expr - self.write_token_separator() - self.write_expr(self.get(node, Tree.CONFIG_EXPR)) - - def walk_star_expr(self, node: AstType) -> None: - """AST: star_expr - - star_expr: MULTIPLY primary_expr - """ - # Do not write space between * in list iter and var - if self.get(node, Token.MULTIPLY): - self.write("*") - self.write_expr(self.get(node, Tree.PRIMARY_EXPR)) - - def walk_double_star_expr(self, node: AstType) -> None: - """AST: double_star_expr - - double_star_expr: DOUBLE_STAR primary_expr - """ - # Do not write space between ** in dict iter and var - if self.get(node, Token.DOUBLE_STAR): - self.write("**") - self.write_expr(self.get(node, Tree.PRIMARY_EXPR)) - - def walk_lambda_expr(self, node: AstType) -> None: - """AST: if_expr - - lambda_expr: LAMBDA [schema_arguments] [RIGHT_ARROW type] LEFT_BRACE [expr_stmt | NEWLINE _INDENT schema_init_stmt+ _DEDENT] RIGHT_BRACE - """ - for n in node["children"]: - self.walk_node(n) - if n["name"] in [Tree.SCHEMA_ARGUMENTS, Token.RIGHT_ARROW, Tree.TYPE]: - self.write_token_separator() - - def walk_if_expr(self, node: AstType) -> None: - """AST: if_expr - - if_expr: or_test IF or_test ELSE test - """ - self.write_expr(self.get(node, Tree.SIMPLE_EXPR)) - while self.get(node, Token.IF): - self.write_token_separator() - self.write_token("if") - self.write_token_separator() - self.write_expr(self.get(node, Tree.SIMPLE_EXPR)) - self.write_token_separator() - self.write_token("else") - self.write_token_separator() - self.write_expr(self.get(node, Tree.TEST)) - - def walk_comp_clause(self, node: AstType) -> None: - """AST: comp_clause - - comp_clause: FOR loop_variables [COMMA] IN or_test [NEWLINE] [IF test [NEWLINE]] - """ - for n in node["children"]: - if n["name"] == Token.IF and self.last_token != Token.NEWLINE: - self.write_token_separator() - self.walk_node(n) - if n["name"] == Token.IF: - self.write_token_separator() - - def walk_quant_expr(self, node: AstType) -> None: - """AST: quant_expr - - quant_expr: quant_op [ identifier COMMA ] identifier IN quant_target LEFT_BRACE (simple_expr [IF simple_expr] | NEWLINE _INDENT simple_expr [IF simple_expr] NEWLINE _DEDENT)? RIGHT_BRACE - """ - for n in node["children"]: - if n["name"] == Token.IF and self.last_token != Token.NEWLINE: - self.write_token_separator() - if n["name"] == Token.LEFT_BRACE: - self.write_token_separator() - self.walk_node(n) - if n["name"] == Token.IF: - self.write_token_separator() - - def write_node_with_newline(self, node: AstType) -> None: - """ - Write node with , ; and NEWLINE - such as list_comp and dict_comp. - """ - children = node["children"] - for i, n in enumerate(children): - if ( - n["name"] in [Token.COMMA, Token.SEMI_COLON] - and i < len(children) - 1 - and children[i + 1]["name"] == Token.NEWLINE - ): - self.write(n["value"]) - else: - self.walk(n) - - def write_colon_without_space(self, node: AstType) -> None: - """ - Write expr with colon : without space - """ - self._is_colon_without_space = True - self.write_expr(node) - self._is_colon_without_space = False - - def walk_mixins(self, node: AstType) -> None: - """AST: mixins - - mixins: identifier (COMMA (NEWLINE mixins | identifier))* - """ - self.write_node_with_newline(node) - - def walk_list_items(self, node: AstType) -> None: - """AST: list_items - - list_items: list_item ((COMMA [NEWLINE] | NEWLINE) list_item)* [COMMA] [NEWLINE] - """ - self.write_node_with_newline(node) - - def walk_entries(self, node: AstType) -> None: - """AST: entries - - entries: entry ((COMMA [NEWLINE] | NEWLINE) entry)* [COMMA] [NEWLINE] - """ - self.write_node_with_newline(node) - - def walk_config_entries(self, node: AstType) -> None: - """AST: config_entries - - entries: entry ((COMMA [NEWLINE] | NEWLINE) entry)* [COMMA] [NEWLINE] - """ - self.write_node_with_newline(node) - - def walk_subscript_suffix(self, node: AstType) -> None: - """AST: subscript_suffix - - subscript_suffix: LEFT_BRACKETS (test | [test] COLON [test] [COLON [test]]) RIGHT_BRACKETS - """ - self.write_colon_without_space(node) - - def walk_slice_suffix(self, node: AstType) -> None: - """AST: slice_suffix - - slice_suffix: LEFT_BRACKETS (test | [test] COLON [test] [COLON [test]]) RIGHT_BRACKETS - """ - self.write_colon_without_space(node) - - def walk_bin_op(self, node: AstType) -> None: - """AST: comp_op""" - children = node["children"] - for i, n in enumerate(children): - # IN | L_NOT IN | IS | IS L_NOT | L_NOT - if n["name"] == Token.IS: - self.write_token_separator() - self.write(n["value"]) - if i + 1 < len(children) and children[i + 1]["name"] != Token.L_L_NOT: - self.write_token_separator() - elif n["name"] == Token.L_L_NOT: - self.write_token_separator() - if i == 0: - self.write(n["value"]) - if i + 1 < len(children) and children[i + 1]["name"] != Token.IN: - self.write_token_separator() - if i == 1: - self.write("not") - self.write_token_separator() - else: - self.walk(n) - - def walk_not_test(self, node: AstType) -> None: - """AST: not_test""" - if self.get(node, Token.L_NOT): - self.write_token("not") - self.write_token_separator() - self.write_expr(node) - - def walk_check_block(self, node: AstType) -> None: - """AST: check_block - - check_block: CHECK COLON NEWLINE _INDENT check_expr+ _DEDENT - """ - self.write_token(self.get(node, Token.CHECK)) - self.write_token(self.get(node, Token.COLON)) - self.write_expr(node) - - def walk_check_expr(self, node: AstType) -> None: - """AST: check_expr - - check_expr: simple_expr [IF simple_expr] [COMMA primary_expr] NEWLINE - """ - self.write_expr(self.get(node, Tree.SIMPLE_EXPR)) - if self.get(node, Token.IF): - self.write_token_separator() - self.write_token("if") - self.write_token_separator() - self.write_expr(self.get(node, Tree.SIMPLE_EXPR)) - for n in node["children"]: - self.walk(n) - - def walk_dict_type(self, node: AstType) -> None: - """AST: dict_type""" - self.write_colon_without_space(node) - - # Statements - - def write_stmt(self, node: AstType) -> None: - """Write stmt""" - self.write_token(self.get(node, Token.NEWLINE)) - self.walk_nodes(*node["children"]) - - def write_condition_and_body(self, node: AstType) -> None: - """Write if and elif condition and body""" - self.write_token_separator() - self.write_expr(self.get(node, Tree.TEST)) - self.write_token(":") - self.write_stmt(self.get(node, Tree.EXECUTION_BLOCK)) - - def walk_start(self, node: AstType) -> None: - """node: start - start: (NEWLINE | statement)* - statement: simple_stmt | compound_stmt - simple_stmt: (assign_stmt | unification_stmt | expr_stmt | assert_stmt | import_stmt | type_alias_stmt) NEWLINE - """ - last_stmt_is_import = False - for n in node["children"]: - if n["name"] != Token.NEWLINE: - stmt_name = n["children"][0]["children"][0]["name"] - # Add a blank line after consecutive import statements - if last_stmt_is_import and stmt_name != Tree.IMPORT_STMT: - self.add_blank_line() - last_stmt_is_import = stmt_name == Tree.IMPORT_STMT - self.walk_node(n) - - def walk_if_stmt(self, node: AstType) -> None: - """AST: if_stmt""" - self.write_token("if") - self.write_condition_and_body(node) - while self.get(node, Token.ELIF): - self.write_token("elif") - self.write_condition_and_body(node) - if self.get(node, Token.ELSE): - self.write_token("else:") - self.write_stmt(self.get(node, Tree.EXECUTION_BLOCK)) - - def walk_assert_stmt(self, node: AstType) -> None: - """Syntax - assert_stmt: ASSERT simple_expr (IF simple_expr)? (COMMA test)? - """ - self.write_token("assert") - self.write_token_separator() - self.write_expr(self.get(node, Tree.SIMPLE_EXPR)) - if self.get(node, Token.IF): - self.write_token_separator() - self.write_token("if") - self.write_token_separator() - self.write_expr(self.get(node, Tree.SIMPLE_EXPR)) - test_node = self.get(node, Tree.TEST) - if test_node: - self.write_token(", ") - self.write_expr(test_node) - - def walk_schema_stmt(self, node: AstType) -> None: - """AST: schema_stmt - - schema_stmt: [decorators] (SCHEMA|MIXIN|PROTOCOL) [RELAXED] NAME [LEFT_BRACKETS [schema_arguments] RIGHT_BRACKETS] [LEFT_PARENTHESES identifier (COMMA identifier)* RIGHT_PARENTHESES] COLON NEWLINE [schema_body] - schema_body: _INDENT (string NEWLINE)* [mixin_stmt] (schema_attribute_stmt|schema_init_stmt)* [check_block] _DEDENT - schema_attribute_stmt: attribute_stmt NEWLINE - attribute_stmt: [decorators] (FINAL)? NAME COLON type [(ASSIGN|COMP_OR) test] - schema_init_stmt: if_simple_stmt | if_stmt - """ - - self.add_blank_line() - self._is_colon_without_space = True - keywords = [Token.SCHEMA, Token.MIXIN, Token.PROTOCOL] - for keyword in keywords: - if self.has(node, keyword): - self.walk_nodes(*self.get_internal(node, keyword, Token.COLON)) - break - self._is_colon_without_space = False - self.write_expr(node) - self.add_blank_line() - - def walk_schema_argument(self, node: AstType): - """AST: schema_argument - - schema_argument: NAME [COLON type] [ASSIGN test] - """ - nodes = node["children"] - if self.has(node, Token.COLON): - self.walk_nodes(*nodes) - else: - self.write_arguments(nodes) - - def walk_if_item(self, node: AstType): - """Syntax - if_item: IF test COLON if_item_exec_block (ELIF test COLON if_item_exec_block)* (ELSE COLON if_item_exec_block)? - """ - self._is_in_collection_if = True - self.write_colon_without_space(node) - self._is_in_collection_if = False - - def walk_if_entry(self, node: AstType): - """Syntax - if_entry: IF test COLON if_entry_exec_block (ELIF test COLON if_entry_exec_block)* (ELSE COLON if_entry_exec_block)? - """ - self._is_in_collection_if = True - for n in node["children"]: - if n["name"] == Token.COLON: - self.write(":") - else: - self.walk_node(n) - self._is_in_collection_if = False - - # User interfaces - - def fmt_ast(self, ast: AstType) -> str: - """Format main function and return the format string buffer""" - if not isinstance(ast, dict): - kcl_error.report_exception( - err_type=kcl_error.ErrType.CompileError_TYPE, arg_msg="Invalid ast type" - ) - self.walk_node(ast) - # Append file last blank line - if self.last_token_value == ENDLINE_TOKEN: - self.write(ENDLINE_TOKEN) - self.printer.seek(0) - return self.printer.read()[:-1] - - -def _get_kcl_files(file_or_dir: pathlib.Path, recursively=False): - """ - Get files in dir - """ - kcl_file_selector = "*.k" - return ( - file_or_dir.rglob(kcl_file_selector) - if recursively - else file_or_dir.glob(kcl_file_selector) - ) - - -def kcl_ast_to_fmt_file(json_ast: AstType) -> str: - """ - Update a kcl ast to a fmt file - """ - return Formatter().fmt_ast(json_ast) - - -def kcl_fmt_source(source: str) -> (str, bool): - """ - Format kcl code string and return formatted string - """ - formatted_code = Formatter().fmt_ast(get_lark_tree_from_expr(source, False)) - return formatted_code, source != formatted_code - - -def kcl_fmt_dir(file_or_dir: pathlib.Path, _recursively=False) -> int: - """ - Format all kcl files in the input directory. - If 'recursive' is 'True', recursively search kcl files from all its - sub directories. - - Return - ------ - Number of formatted files - """ - return len([kcl_fmt_file(file) for file in _get_kcl_files(file_or_dir)]) - - -def kcl_fmt_file(filepath: pathlib.Path, is_stdout=False) -> bool: - """ - Format single kcl file - """ - source, is_formatted = kcl_fmt_source(filepath.read_text(encoding="utf-8")) - if is_stdout: - print(source, end="") - else: - filepath.write_text(source) - return is_formatted - - -def kcl_fmt(input_file_or_path: str, is_stdout=False, recursively=False) -> List[str]: - """ - Format kcl file or path contains kcl files - - Parameters - ---------- - - input_file_or_path: Input filename or pathname string - """ - try: - changed_paths: List[str] = [] - formatting_filename = None - path = pathlib.Path(input_file_or_path).resolve() - if path.is_dir(): - for i, file in enumerate(_get_kcl_files(path, recursively)): - formatting_filename = file - if kcl_fmt_file(file, is_stdout): - changed_paths.append(str(file.name)) - elif path.is_file(): - formatting_filename = path - if kcl_fmt_file(path, is_stdout): - changed_paths.append(str(path.name)) - if not is_stdout: - format_count = len(changed_paths) - klog.write_out( - "KCL format done and {} formatted:\n".format( - str(format_count) + " file was" - if format_count <= 1 - else str(format_count) + " files were" - ) - ) - [klog.write_out(f"{p}\n") for p in changed_paths] - return changed_paths - except kcl_error.KCLSyntaxException as err: - # TODO: Support _Formatter filename context and remove this except. - # Add filename, line, column and raise - kcl_error.report_exception( - err_type=kcl_error.ErrType.InvalidSyntax_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=formatting_filename, line_no=err.lineno, col_no=err.colno - ) - ], - ) - - except Exception as err: - kcl_error.report_exception( - err_type=kcl_error.ErrType.CompileError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=formatting_filename, - ) - ], - arg_msg=str(err), - ) diff --git a/internal/kclvm_py/tools/langserver/common.py b/internal/kclvm_py/tools/langserver/common.py deleted file mode 100644 index 75437146e..000000000 --- a/internal/kclvm_py/tools/langserver/common.py +++ /dev/null @@ -1,181 +0,0 @@ -import typing -import pathlib - -import kclvm.compiler.parser.parser as parser -import kclvm.kcl.ast as ast -import kclvm.kcl.types.scope as scope -import kclvm.kcl.error as kcl_error - -from kclvm.kcl.types import ResolveProgram, ProgramScope, CheckConfig -from pygls.lsp.types.basic_structures import Location, Range, Position -from pygls.lsp.types.language_features.completion import ( - CompletionItemKind, - CompletionItem, -) -from kclvm.api.object import KCLTypeKind -from kclvm.compiler.vfs.vfs import get_pkg_realpath_from_pkgpath as get_realpath - -INNER_TYPE_2_COMPLETION_ITEM_KIND = { - # any type - KCLTypeKind.AnyKind: CompletionItemKind.Text, - # base types - KCLTypeKind.BoolKind: CompletionItemKind.Value, - KCLTypeKind.IntKind: CompletionItemKind.Value, - KCLTypeKind.FloatKind: CompletionItemKind.Value, - KCLTypeKind.StrKind: CompletionItemKind.Value, - # constants - KCLTypeKind.NoneKind: CompletionItemKind.Constant, - KCLTypeKind.BoolLitKind: CompletionItemKind.Constant, - KCLTypeKind.FloatLitKind: CompletionItemKind.Constant, - KCLTypeKind.IntLitKind: CompletionItemKind.Constant, - KCLTypeKind.StrLitKind: CompletionItemKind.Constant, - # schema - KCLTypeKind.SchemaKind: CompletionItemKind.Struct, - KCLTypeKind.SchemaDefKind: CompletionItemKind.Struct, - # built in function - KCLTypeKind.FuncKind: CompletionItemKind.Function, -} - - -def pos_to_node( - pos: ast.Position, code: str = None -) -> (typing.Optional[ast.Program], typing.Optional[ast.AST]): - if not pos or not pos.is_valid(): - return None, None - prog = file_to_prog(pos.filename, code) - if not prog: - return None, None - for module in prog.pkgs[ast.Program.MAIN_PKGPATH]: - leaf_node = module.find_leaf_by_pos(pos) - if leaf_node: - return prog, leaf_node - return prog, None - - -def pos_to_scope( - pos: ast.Position, code: str = None -) -> ( - typing.Optional[ast.Program], - typing.Optional[scope.Scope], - typing.Optional[scope.Scope], -): - if not pos or not pos.is_valid(): - return None, None, None - prog, prog_scope = file_or_prog_to_scope(None, pos.filename, code) - if not prog_scope or not prog_scope.main_scope: - return None, None, None - return prog, prog_scope.main_scope.inner_most(pos), prog_scope - - -def file_or_prog_to_scope( - prog: typing.Optional[ast.Program] = None, file_path: str = None, code: str = None -) -> (typing.Optional[ast.Program], typing.Optional[ProgramScope]): - prog = prog or file_to_prog(file_path, code) - if not prog: - return None, None - no_raise = CheckConfig() - no_raise.raise_err = False - try: - return prog, ResolveProgram(prog, config=no_raise) - except Exception: - return None, None - - -def file_to_prog(file_path: str, code: str = None) -> typing.Optional[ast.Program]: - code_list = [code] if code is not None else [] - try: - prog = parser.LoadProgram( - file_path, - mode=parser.ParseMode.Null, - k_code_list=code_list, - set_ast_parent=True, - ) - return prog - except kcl_error.KCLError: - return None - except Exception: - return None - - -def file_to_ast(file_path: str, code: str = None) -> typing.Optional[ast.Module]: - try: - module = parser.ParseFile(file_path, code) - return module - except Exception: - return None - - -def scope_obj_to_location(obj: scope.ScopeObject) -> typing.Optional[Location]: - if obj and obj.check_pos_valid(): - if obj.node.type in [ - "SchemaStmt", - "RuleStmt", - "SchemaAttr", - "SchemaIndexSignature", - ]: - return node_to_location(obj.node.name_node) - if obj.node.type == "Identifier": - return node_to_location(obj.node.name_nodes[0]) - if obj.node.type == "ImportStmt": - return node_to_location( - obj.node.as_name_node - if obj.node.as_name_node - else obj.node.path_nodes[-1] - ) - return None - - -def node_to_location(node: ast.AST) -> typing.Optional[Location]: - return ( - Location( - uri=str(pathlib.Path(node.filename)), - range=Range( - start=kcl_pos_to_lsp_pos(node.pos), - end=kcl_pos_to_lsp_pos(node.end_pos), - ), - ) - if node - and node.pos - and node.pos.is_valid() - and node.end_pos - and node.end_pos.is_valid() - else None - ) - - -def kcl_pos_to_lsp_pos(pos: ast.Position) -> Position: - return Position(line=pos.line - 1, character=pos.column - 1) - - -def scope_obj_to_completion_item(obj: scope.ScopeObject) -> CompletionItem: - assert obj and obj.name and obj.type - return CompletionItem( - label=obj.name, - kind=INNER_TYPE_2_COMPLETION_ITEM_KIND.get(obj.type.type_kind()), - ) - - -def pkgpath_to_location(root: str, pkgpath: str) -> typing.Optional[Location]: - filepath = get_realpath_from_pkgpath(root, pkgpath) - return file_to_location(filepath) - - -def file_to_location(filepath: str) -> typing.Optional[Location]: - if not filepath or not is_kcl_file(filepath): - return None - return Location(uri=filepath, range=emptyRange()) - - -def is_kcl_file(filepath: str) -> bool: - return filepath.endswith(".k") - - -def emptyRange() -> Range: - return Range( - start=Position(line=0, character=0), - end=Position(line=0, character=0), - ) - - -def get_realpath_from_pkgpath(root: str, pkgpath: str) -> str: - return str(pathlib.Path(get_realpath(root, pkgpath)).absolute()) diff --git a/internal/kclvm_py/tools/langserver/complete.py b/internal/kclvm_py/tools/langserver/complete.py deleted file mode 100644 index d693f6a32..000000000 --- a/internal/kclvm_py/tools/langserver/complete.py +++ /dev/null @@ -1,20 +0,0 @@ -import pygls.lsp.types.language_features.completion as completion -import typing -import kclvm.kcl.ast as ast -from kclvm.tools.langserver.common import pos_to_scope, scope_obj_to_completion_item - - -def complete( - pos: ast.Position, name: str, code: str = None -) -> typing.List[completion.CompletionItem]: - _, inner_most, _ = pos_to_scope(pos, code) - _scope = inner_most - completion_list: completion.CompletionList = completion.CompletionList( - isIncomplete=False - ) - while _scope is not None: - for key, obj in _scope.elems.items(): - if key.startswith(name): - completion_list.add_item(scope_obj_to_completion_item(obj)) - _scope = _scope.parent - return completion_list.items diff --git a/internal/kclvm_py/tools/langserver/document_symbol.py b/internal/kclvm_py/tools/langserver/document_symbol.py deleted file mode 100644 index 4fc24b92b..000000000 --- a/internal/kclvm_py/tools/langserver/document_symbol.py +++ /dev/null @@ -1,153 +0,0 @@ -""" -https://microsoft.github.io/language-server-protocol/specification#textDocument_documentSymbol -DocumentSymbol[] which is a hierarchy of symbols found in a given text document. -class DocumentSymbol(Model): - name: str # The name of this symbol. Will be displayed in the user interface - and therefore must not be an empty string or a string only - consisting of white spaces. - kind: SymbolKind # The kind of this symbol. - range: Range # The range enclosing this symbol not including leading/trailing - whitespace but everything else like comments. This information - is typically used to determine if the clients cursor is inside - the symbol to reveal in the symbol in the UI. - selection_range: Range # The range that should be selected and revealed when this symbol - is being picked, e.g. the name of a function. Must be contained - by the `range`. - detail: Optional[str] = None # More detail for this symbol, e.g the signature of a function. - children: Optional[List['DocumentSymbol']] = None # Children of this symbol, e.g. properties of a class. - deprecated: Optional[bool] = False # Indicates if this symbol is deprecated. - -In KCl, we select variables and schema definitions as symbols,, and the schema attributes and mixins in the schema will -be the child nodes of the schema, e.g: - -a = b = 1 a -schema Person: b - mixin [ Person - nameMixin mixin - ] -> nameMixin - age: int = 1 age - person -person = Person{ - ... -} -""" -from typing import List -from pygls.lsp.types.language_features.document_symbol import DocumentSymbol, SymbolKind -from pygls.lsp.types.basic_structures import Range, Position - -import kclvm.kcl.ast as ast -from kclvm.tools.langserver.common import file_to_ast - - -def range_check(s: DocumentSymbol): - """ - DocumentSymbol.selection_range must be contained by the DocumentSymbol.range - a = { ... } - ^^ ^ - ││ └-range_end - │└---selection_range_end - │ - range_start, selection_range_start - - """ - assert isinstance(s, DocumentSymbol) - range = s.range - selection_range = s.selection_range - assert ( - (range.start.line <= selection_range.start.line) - & (selection_range.start.line <= selection_range.end.line) - & (selection_range.end.line <= range.end.line) - ) - if range.start.line == selection_range.start.line: - assert selection_range.start.character >= range.start.character - if selection_range.end.line == range.end.line: - assert selection_range.start.character >= range.start.character - if s.children: - for child in s.children: - range_check(child) - - -def ast_position_to_range(node: ast.AST) -> Range: - assert isinstance(node, ast.AST) - return Range( - start=Position(line=node.line - 1, character=node.column - 1), - end=Position(line=node.end_line - 1, character=node.end_column - 1), - ) - - -def identifier_to_document_symbol(node: ast.Identifier) -> DocumentSymbol: - assert isinstance(node, ast.Identifier) - range = Range( - start=Position(line=node.line - 1, character=node.column - 1), - end=Position(line=node.end_line - 1, character=node.end_column - 1), - ) - return DocumentSymbol( - name=".".join(node.names), - range=range, - selection_range=range, - kind=SymbolKind.Variable, - ) - - -def schema_attr_to_document_symbol(node: ast.SchemaAttr) -> DocumentSymbol: - assert isinstance(node, ast.SchemaAttr) - return DocumentSymbol( - name=node.name, - range=ast_position_to_range(node), - kind=SymbolKind.Property, - selection_range=ast_position_to_range(node.name_node), - ) - - -def schema_stmt_to_document_symbol(node: ast.SchemaStmt) -> DocumentSymbol: - assert isinstance(node, ast.SchemaStmt) - symbol = DocumentSymbol( - name=node.name, - kind=SymbolKind.Struct, - range=ast_position_to_range(node), - selection_range=ast_position_to_range(node.name_node), - children=[], - ) - if len(node.mixins): - range = Range( - start=Position(line=node.line, character=4), - end=Position(line=node.line, character=9), - ) - symbol.children.append( - DocumentSymbol( - name="mixin", - kind=SymbolKind.Property, - range=range, - selection_range=range, - children=[identifier_to_document_symbol(id) for id in node.mixins], - ) - ) - symbol.children += [ - schema_attr_to_document_symbol(attr) for attr in node.GetAttrList() - ] - return symbol - - -def assign_stmt_to_document_symbol(node: ast.AssignStmt) -> DocumentSymbol: - assert isinstance(node, ast.AssignStmt) - id_symbols = [] - for identifier in node.targets: - symbol = identifier_to_document_symbol(identifier) - symbol.range = ast_position_to_range(node) - id_symbols.append(symbol) - return id_symbols - - -def document_symbol(file: str, code: str = None) -> List[DocumentSymbol]: - symbols = [] - module = file_to_ast(file, code) - if not module or not isinstance(module, ast.Module): - return [] - for stmt in module.body or []: - if isinstance(stmt, ast.SchemaStmt): - symbols.append(schema_stmt_to_document_symbol(stmt)) - if isinstance(stmt, ast.AssignStmt): - symbols.extend(assign_stmt_to_document_symbol(stmt)) - for s in symbols: - range_check(s) - return symbols diff --git a/internal/kclvm_py/tools/langserver/go_to_def.py b/internal/kclvm_py/tools/langserver/go_to_def.py deleted file mode 100644 index 9ecf5da76..000000000 --- a/internal/kclvm_py/tools/langserver/go_to_def.py +++ /dev/null @@ -1,201 +0,0 @@ -from typing import List, cast, Optional -from pygls.lsp.types.basic_structures import Location - -import kclvm.kcl.ast as ast -import kclvm.kcl.types.scope as scope -import kclvm.tools.langserver.common as common -from kclvm.api.object.object import KCLTypeKind, KCLModuleTypeObject -from kclvm.api.object.schema import KCLSchemaTypeObject, KCLSchemaDefTypeObject - - -def definition( - pos: ast.Position, code: str = None -) -> (Optional[ast.AST], Optional[scope.ScopeObject]): - prog: ast.Program - prog, leaf_node = common.pos_to_node(pos, code) - if not leaf_node: - # no name node at the position - return None, None - parent: ast.AST = leaf_node.parent - if isinstance(leaf_node, ast.Name): - if ( - parent.type == "Identifier" - and parent.parent.type == "ConfigEntry" - and parent is parent.parent.key - ): - identifier: ast.Identifier = cast(ast.Identifier, parent) - _, prog_scope = common.file_or_prog_to_scope(prog) - schema_expr: ast.SchemaExpr = leaf_node.find_nearest_parent_by_type( - ast.SchemaExpr - ) - if schema_expr: - schema_name: ast.Identifier = schema_expr.name - schema_scope_obj = find_declaration( - schema_name, schema_name.name_nodes[-1], prog_scope - ) - top_attr = find_inner_name( - schema_scope_obj, identifier.name_nodes[0], prog_scope - ) - result_obj = find_declaration_by_scope_obj( - identifier=identifier, - name_node=leaf_node, - top_name_obj=top_attr, - prog_scope=prog_scope, - ) - return leaf_node, result_obj - if parent.type == "Identifier" and ( - parent.parent.type != "ConfigEntry" or parent is parent.parent.value - ): - identifier: ast.Identifier = cast(ast.Identifier, parent) - _, prog_scope = common.file_or_prog_to_scope(prog) - declaration = find_declaration(identifier, leaf_node, prog_scope) - return leaf_node, declaration - return leaf_node, None - - -def go_to_def(pos: ast.Position, code: str = None) -> List[Location]: - prog: ast.Program - prog, leaf_node = common.pos_to_node(pos, code) - if not leaf_node: - # no name node at the position - return [] - parent: ast.AST = leaf_node.parent - if isinstance(leaf_node, ast.Name): - if parent.type == "ImportStmt": - import_stmt: ast.ImportStmt = cast(ast.ImportStmt, parent) - if leaf_node in import_stmt.path_nodes: - index = import_stmt.path_nodes.index(leaf_node) - if index == len(import_stmt.path_nodes) - 1: - # this might be a module name, return the target module file path - loc = common.pkgpath_to_location( - root=prog.root, pkgpath=import_stmt.path - ) - return [loc] if loc else [] - return [common.node_to_location(leaf_node)] - if ( - parent.type == "Identifier" - and parent.parent.type == "ConfigEntry" - and parent is parent.parent.key - ): - identifier: ast.Identifier = cast(ast.Identifier, parent) - _, prog_scope = common.file_or_prog_to_scope(prog) - schema_expr: ast.SchemaExpr = leaf_node.find_nearest_parent_by_type( - ast.SchemaExpr - ) - if schema_expr: - schema_name: ast.Identifier = schema_expr.name - schema_scope_obj = find_declaration( - schema_name, schema_name.name_nodes[-1], prog_scope - ) - top_attr = find_inner_name( - schema_scope_obj, identifier.name_nodes[0], prog_scope - ) - result_obj = find_declaration_by_scope_obj( - identifier=identifier, - name_node=leaf_node, - top_name_obj=top_attr, - prog_scope=prog_scope, - ) - loc = common.scope_obj_to_location(result_obj) - return [loc] if loc else [] - if parent.type == "Identifier" and ( - parent.parent.type != "ConfigEntry" or parent is parent.parent.value - ): - identifier: ast.Identifier = cast(ast.Identifier, parent) - _, prog_scope = common.file_or_prog_to_scope(prog) - declaration = find_declaration(identifier, leaf_node, prog_scope) - loc = common.scope_obj_to_location(declaration) - return [loc] if loc else [] - return [common.node_to_location(leaf_node)] - - -def find_declaration( - identifier: ast.Identifier, name_node: ast.Name, prog_scope: scope.ProgramScope -) -> Optional[scope.ScopeObject]: - if not identifier or not name_node or not prog_scope: - return None - top_name = identifier.name_nodes[0] - top_name_obj = find_declaration_obj_by_pos_and_name( - top_name.pos, top_name.value, prog_scope - ) - return find_declaration_by_scope_obj( - identifier, name_node, top_name_obj, prog_scope - ) - - -def find_declaration_by_scope_obj( - identifier: ast.Identifier, - name_node: ast.Name, - top_name_obj: scope.ScopeObject, - prog_scope: scope.ProgramScope, -) -> Optional[scope.ScopeObject]: - if not identifier or not name_node or not top_name_obj or not prog_scope: - return None - index = identifier.name_nodes.index(name_node) - i = 0 - obj = top_name_obj - while i < index: - i = i + 1 - obj = find_inner_name(obj, identifier.name_nodes[i], prog_scope) - if not obj: - return None - return obj - - -def find_declaration_obj_by_pos_and_name( - pos: ast.Position, name: str, prog_scope: scope.ProgramScope -) -> Optional[scope.ScopeObject]: - if not pos or not pos.is_valid() or not name or not prog_scope: - return None - inner_most = prog_scope.main_scope.inner_most(pos) - if not inner_most or not inner_most.elems: - return None - scope_obj = inner_most.elems.get(name) - if scope_obj is not None: - return scope_obj - # 1. search through the parent schema scope tree - parent_scope = inner_most.get_parent_schema_scope(prog_scope) - while parent_scope is not None: - scope_obj = parent_scope.elems.get(name) - if scope_obj is not None: - return scope_obj - parent_scope = parent_scope.get_parent_schema_scope(prog_scope) - # 2. search through the enclosing scope tree - while inner_most is not None: - scope_obj = inner_most.elems.get(name) - if scope_obj is not None: - return scope_obj - inner_most = inner_most.get_enclosing_scope() - return None - - -def find_inner_name( - out_name_obj: scope.ScopeObject, - inner_name: ast.Name, - prog_scope: scope.ProgramScope, -) -> Optional[scope.ScopeObject]: - if not out_name_obj or not inner_name or not prog_scope: - return None - if out_name_obj.type.type_kind() == KCLTypeKind.SchemaKind: - return find_attr_by_name(inner_name.value, out_name_obj.type, prog_scope) - if out_name_obj.type.type_kind() == KCLTypeKind.ModuleKind: - out_type = cast(KCLModuleTypeObject, out_name_obj.type) - if out_type.is_user_module: - pkg_scope = prog_scope.scope_map.get(out_type.pkgpath) - return pkg_scope.elems.get(inner_name.value) if pkg_scope else None - if out_name_obj.type.type_kind() == KCLTypeKind.SchemaDefKind: - out_type = cast(KCLSchemaDefTypeObject, out_name_obj.type) - return find_attr_by_name(inner_name.value, out_type.schema_type, prog_scope) - - -def find_attr_by_name( - attr_name: str, schema_type: KCLSchemaTypeObject, prog_scope: scope.ProgramScope -) -> Optional[scope.ScopeObject]: - while schema_type: - if attr_name in schema_type.attr_list: - # todo: support jump to schema index signature - pkg_scope = prog_scope.scope_map.get(schema_type.pkgpath) - schema_scope = pkg_scope.search_child_scope_by_name(schema_type.name) - return schema_scope.elems.get(attr_name) if schema_scope else None - schema_type = schema_type.base - return None diff --git a/internal/kclvm_py/tools/langserver/grpc_wrapper.py b/internal/kclvm_py/tools/langserver/grpc_wrapper.py deleted file mode 100644 index ad21f22d3..000000000 --- a/internal/kclvm_py/tools/langserver/grpc_wrapper.py +++ /dev/null @@ -1,63 +0,0 @@ -import json -from typing import Union, Optional - -from kclvm.internal.gpyrpc.gpyrpc_pb2 import Position -import kclvm.kcl.ast as ast -from .complete import complete -from .go_to_def import go_to_def -from .document_symbol import document_symbol -from .hover import hover - - -def go_to_def_wrapper(pos: Position, code: str = None) -> str: - pos_wrapper = proto_pos_to_ast_pos(pos) - result = go_to_def(pos=pos_wrapper, code=code) - return json.dumps(obj=result, default=lambda x: x.__dict__) - - -def complete_wrapper(pos: Position, name: str, code: str = None) -> str: - pos_wrapper = proto_pos_to_ast_pos(pos) - result = complete(pos=pos_wrapper, name=name, code=code) - return json.dumps(obj=result, default=lambda x: x.__dict__) - - -def proto_pos_to_ast_pos(pos: Position) -> ast.Position: - return ast.Position(filename=pos.filename, line=pos.line + 1, column=pos.column + 1) - - -class SnakeToCamel(json.JSONEncoder): - """Class attributes need to be converted to camel-case notation because client is expecting that.""" - - def to_camel(self, s: str): - return "".join( - word.capitalize() if idx > 0 else word - for idx, word in enumerate(s.split("_")) - ) - - def convert_key( - self, instance: Union[int, float, str, bool, list, dict, tuple] - ) -> Optional[Union[int, float, str, bool, list, dict, tuple]]: - if instance is None: - return None - if isinstance(instance, (bool, int, float, str)): - return instance - elif isinstance(instance, (list, set, tuple)): - return [self.convert_key(v) for v in instance] - elif isinstance(instance, dict): - return {self.to_camel(k): self.convert_key(v) for k, v in instance.items()} - else: - return self.convert_key(instance.__dict__) - - def default(self, obj): - return self.convert_key(obj.__dict__) - - -def document_symbol_wrapper(file: str, code: str = None) -> str: - result = document_symbol(file=file, code=code) - return json.dumps(obj=result, cls=SnakeToCamel) - - -def hover_wrapper(pos: Position, code: str) -> str: - pos_wrapper = proto_pos_to_ast_pos(pos) - result = hover(pos=pos_wrapper, code=code) - return json.dumps(obj=result, default=lambda x: x.__dict__) diff --git a/internal/kclvm_py/tools/langserver/hover.py b/internal/kclvm_py/tools/langserver/hover.py deleted file mode 100644 index 559fd0e1e..000000000 --- a/internal/kclvm_py/tools/langserver/hover.py +++ /dev/null @@ -1,67 +0,0 @@ -import typing -import pygls.lsp.types.language_features.hover as pygls_hover -from pygls.lsp.types.basic_structures import MarkupContent, MarkupKind, Range -import kclvm.kcl.ast as ast -import kclvm.api.object as objpkg -from kclvm.kcl.types.scope import ScopeObject -import kclvm.tools.langserver.common as common -from . import go_to_def - - -def hover(pos: ast.Position, code: str = None) -> typing.Optional[pygls_hover.Hover]: - def_node, def_obj = go_to_def.definition(pos, code) - if not def_node: - return None - if def_obj: - return scope_obj_desc(def_node, def_obj) - else: - return ast_node_desc(def_node) - - -def ast_node_desc(node: ast.AST) -> typing.Optional[pygls_hover.Hover]: - if isinstance(node, ast.Name): - return pygls_hover.Hover( - contents=MarkupContent( - kind=MarkupKind.PlainText, - value=node.value, - ), - range=Range( - start=common.kcl_pos_to_lsp_pos(node.pos), - end=common.kcl_pos_to_lsp_pos(node.end_pos), - ), - ) - return None - - -def scope_obj_desc( - node: ast.AST, obj: ScopeObject -) -> typing.Optional[pygls_hover.Hover]: - if isinstance(node, ast.AST) and isinstance(obj, ScopeObject): - # 针对每种类型的 scope object,进行不同的显示 - if not obj.node and isinstance(obj.type, objpkg.KCLFunctionTypeObject): - # the target scope object is a built-in function name - msg = ( - f"(built-in) {obj.name}(" - + ", ".join([param.param_doc() for param in obj.type.params]) - + f"): {obj.type.return_type.type_str() if obj.type.return_type else 'any'}" - + f"\n{obj.type.doc}" - if obj.type.doc - else "" - ) - else: - msg = ( - f"{obj.name}\ntype: {obj.type.type_str()}\ndefined in:{obj.node.filename}" - if obj.node - else obj.name - ) - return pygls_hover.Hover( - contents=MarkupContent( - kind=MarkupKind.PlainText, - value=msg, - ), - range=Range( - start=common.kcl_pos_to_lsp_pos(node.pos), - end=common.kcl_pos_to_lsp_pos(node.end_pos), - ), - ) - return None diff --git a/internal/kclvm_py/tools/lint/checkers/__init__.py b/internal/kclvm_py/tools/lint/checkers/__init__.py deleted file mode 100644 index 7625e276c..000000000 --- a/internal/kclvm_py/tools/lint/checkers/__init__.py +++ /dev/null @@ -1,16 +0,0 @@ -""" -Base id of standard checkers (used in msg and report ids): -01: basic -02: Schema -03: format -04: import -05: misc -06: variables -07: -08: -09: syntax -10-50: not yet used: reserved for future internal checkers. -51-99: perhaps used: reserved for external checkers -""" - -__all__ = ["base_checker", "imports", "misc", "basic"] diff --git a/internal/kclvm_py/tools/lint/checkers/base_checker.py b/internal/kclvm_py/tools/lint/checkers/base_checker.py deleted file mode 100644 index 681b5d4de..000000000 --- a/internal/kclvm_py/tools/lint/checkers/base_checker.py +++ /dev/null @@ -1,57 +0,0 @@ -from typing import Any -from abc import abstractmethod - -import kclvm.kcl.ast as ast - - -class BaseChecker(ast.TreeWalker): - # checker name (you may reuse an existing one) - name: str = "" - # options level (0 will be displaying in --help, 1 in --long-help) - level = 1 - # ordered list of options to control the checker behaviour - options: Any = {} - # messages constant to display - MSGS: Any = {} - # messages issued by this checker - msgs: Any = [] - # mark this checker as enabled or not. - enabled: bool = True - - def __init__(self, linter=None) -> None: - """ - checker instances should have the linter as argument - - :param linter: is an object implementing KCLLinter. - """ - if self.name is not None: - self.name = self.name.lower() - self.linter = linter - self.options = linter.config if linter else None - - def __eq__(self, other) -> bool: - return self.name == other.name and self.linter == other.linter - - def generic_walk(self, t: ast.AST) -> None: - """Called if no explicit walker function exists for a node.""" - for _, value in ast.iter_fields(t): - if isinstance(value, list): - for v in value: - # IfStmt.elif_body: List[List[Stmt]] - if isinstance(v, list): - for v1 in v: - self.walk(v1) - if isinstance(v, ast.AST): - self.walk(v) - elif isinstance(value, ast.AST): - self.walk(value) - - def get_node_name(self, t: ast.AST) -> str: - """Get the ast.AST node name""" - assert isinstance(t, ast.AST) - return t.type - - @abstractmethod - def check(self, prog: ast.Program, code: str): - """Should be overridden by subclass""" - raise NotImplementedError() diff --git a/internal/kclvm_py/tools/lint/checkers/basic.py b/internal/kclvm_py/tools/lint/checkers/basic.py deleted file mode 100644 index 111cf9220..000000000 --- a/internal/kclvm_py/tools/lint/checkers/basic.py +++ /dev/null @@ -1,336 +0,0 @@ -"""basic checker for Python code""" -import re -from typing import Pattern - -import kclvm.tools.lint.message.message as message -import kclvm.kcl.ast as ast -import kclvm.tools.lint.lint.utils as utils -from kclvm.tools.lint.checkers.base_checker import BaseChecker - - -MSGS = { - "C0103": ( - '%s name "%s" doesn\'t conform to %s.', - "Invalid-name.", - "{0} name {1} doesn't conform to {2}.", - ), - "C0104": ( - 'Disallowed name "%s".', - "Disallowed-name.", - 'Disallowed name "{0}."', - ), -} - - -class NamingStyle: - ANY: Pattern[str] = re.compile(".*") - MOD_NAME_RGX: Pattern[str] = ANY - PKG_NAME_RGX: Pattern[str] = ANY - SCHEMA_NAME_RGX: Pattern[str] = ANY - MIXIN_NAME_RGX: Pattern[str] = ANY - PROTOCOL_NAME_RGX: Pattern[str] = ANY - SCHEMA_ATTRIBUTE_RGX: Pattern[str] = ANY - VARIABLE_RGX: Pattern[str] = ANY - ARGUMENT_RGX: Pattern[str] = ANY - DEFAULT_NAME_RGX: Pattern[str] = ANY - - @classmethod - def get_regex(cls, name_type): - return { - "module": cls.MOD_NAME_RGX, - "package": cls.PKG_NAME_RGX, - "schema": cls.SCHEMA_NAME_RGX, - "mixin": cls.MIXIN_NAME_RGX, - "protocol": cls.PROTOCOL_NAME_RGX, - "argument": cls.ARGUMENT_RGX, - "variable": cls.VARIABLE_RGX, - "schema_attribute": cls.SCHEMA_ATTRIBUTE_RGX, - }[name_type] - - -class SnakeCaseStyle(NamingStyle): - ANY: Pattern[str] = re.compile(".*") - MOD_NAME_RGX: Pattern[str] = re.compile(r"^\$?[a-z][a-z_]*$") - PKG_NAME_RGX: Pattern[str] = re.compile(r"^\$?[a-z][a-z_]*$") - SCHEMA_NAME_RGX: Pattern[str] = ANY - MIXIN_NAME_RGX: Pattern[str] = ANY - PROTOCOL_NAME_RGX: Pattern[str] = ANY - VARIABLE_RGX: Pattern[str] = ANY - SCHEMA_ATTRIBUTE_RGX: Pattern[str] = ANY - ARGUMENT_RGX: Pattern[str] = ANY - DEFAULT_NAME_RGX: Pattern[str] = ANY - - -class CamelCaseStyle(NamingStyle): - """Regex rules for camelCase naming style.""" - - ANY: Pattern[str] = re.compile(".*") - MOD_NAME_RGX: Pattern[str] = ANY - PKG_NAME_RGX: Pattern[str] = ANY - SCHEMA_NAME_RGX: Pattern[str] = ANY - MIXIN_NAME_RGX: Pattern[str] = ANY - PROTOCOL_NAME_RGX: Pattern[str] = ANY - VARIABLE_RGX: Pattern[str] = ANY - SCHEMA_ATTRIBUTE_RGX: Pattern[str] = re.compile(r"^\$?[a-z][a-zA-Z]*$") - ARGUMENT_RGX: Pattern[str] = re.compile(r"^\$?[a-z][a-zA-Z]*$") - DEFAULT_NAME_RGX: Pattern[str] = re.compile(r"^\$?[a-z][a-zA-Z]*$") - - -class PascalCaseStyle(NamingStyle): - """Regex rules for PascalCase naming style.""" - - ANY: Pattern[str] = re.compile(".*") - MOD_NAME_RGX: Pattern[str] = ANY - PKG_NAME_RGX: Pattern[str] = ANY - SCHEMA_NAME_RGX: Pattern[str] = re.compile(r"^\$?[A-Z][a-zA-Z\d]*$") - MIXIN_NAME_RGX: Pattern[str] = re.compile(r"^\$?[A-Z][a-zA-Z\d]*Mixin$") - PROTOCOL_NAME_RGX: Pattern[str] = re.compile(r"^\$?[A-Z][a-zA-Z\d]*Protocol$") - VARIABLE_RGX: Pattern[str] = ANY - SCHEMA_ATTRIBUTE_RGX: Pattern[str] = ANY - ARGUMENT_RGX: Pattern[str] = ANY - DEFAULT_NAME_RGX: Pattern[str] = ANY - - -class UpperCaseStyle(NamingStyle): - """Regex rules for UPPER_CASE naming style.""" - - ANY: Pattern[str] = re.compile(".*") - MOD_NAME_RGX: Pattern[str] = ANY - PKG_NAME_RGX: Pattern[str] = ANY - SCHEMA_NAME_RGX: Pattern[str] = ANY - MIXIN_NAME_RGX: Pattern[str] = ANY - PROTOCOL_NAME_RGX: Pattern[str] = ANY - VARIABLE_RGX: Pattern[str] = ANY - SCHEMA_ATTRIBUTE_RGX: Pattern[str] = ANY - ARGUMENT_RGX: Pattern[str] = ANY - DEFAULT_NAME_RGX: Pattern[str] = re.compile(r"^\$?[^\W\da-z_][^\Wa-z]*$") - - -class AnyStyle(NamingStyle): - pass - - -NAMING_STYLES = { - "snake_case": SnakeCaseStyle, - "camelCase": CamelCaseStyle, - "PascalCase": PascalCaseStyle, - "UPPER_CASE": UpperCaseStyle, - "ANY": AnyStyle, -} - - -KNOWN_NAME_TYPES = { - "module", - "package", - "schema", - "mixin", - "protocol", - "argument", - "variable", - "schema_attribute", -} - - -class BasicChecker(BaseChecker): - def __init__(self, linter) -> None: - super().__init__(linter) - self.name = "BaseCheck" - self.code = None - self.MSGS = MSGS - self.module = None - self.naming_rules = None - self.bad_names = None - self.prog = None - - def reset(self) -> None: - self.msgs.clear() - self.code = None - self.module = None - self.naming_rules = None - self.bad_names = None - - def get_module(self, prog: ast.Program, code: str) -> None: - assert isinstance(prog, ast.Program) - assert code is not None - self.prog = prog - self.module = prog.pkgs["__main__"][0] - self.code = code - self.naming_rules = self._create_naming_rules() - self.bad_names = self.options.bad_names - - def check(self, prog: ast.Program, code: str) -> None: - assert isinstance(prog, ast.Program) - assert code is not None - self.reset() - self.get_module(prog, code) - self.walk(self.module) - - def _create_naming_rules(self): - regexps = {} - for name_type in KNOWN_NAME_TYPES: - # naming rgx in config, .e.g module-rgx : [^\W\dA-Z][^\WA-Z]+$ - custom_regex_setting_name = f"{name_type}_rgx" - if getattr(self.options, custom_regex_setting_name): - regexps[name_type] = re.compile( - getattr(self.options, custom_regex_setting_name) - ) - else: - # naming rgx in config, .e.g module-rgx : [^\W\dA-Z][^\WA-Z]+$ - naming_style_name = f"{name_type}_naming_style" - regexps[name_type] = NAMING_STYLES[ - getattr(self.options, naming_style_name) - ].get_regex(name_type) - return regexps - - def _check_name(self, name: str, name_type: str): - return self.naming_rules[name_type].search(name) - - def _disallowed_name(self, name: str): - return name in self.bad_names - - def _get_name_style_or_rgx(self, name_type): - name_rgx = f"{name_type}_rgx" - name_style = f"{name_type}_naming_style" - if getattr(self.options, name_rgx): - return getattr(self.options, name_rgx) - else: - return getattr(self.options, name_style) + " naming style" - - def walk_RuleStmt(self, t: ast.RuleStmt) -> None: - assert isinstance(t, ast.RuleStmt) - if not self._check_name(t.name, "schema"): - name_style_or_rgx = self._get_name_style_or_rgx("schema") - self.msgs.append( - message.Message( - "C0103", - self.module.filename, - MSGS["C0103"][0] % ("Schema", t.name, name_style_or_rgx), - utils.get_source_code( - self.module.filename, t.name_node.line, self.code - ), - (t.name_node.line, t.name_node.column), - ["Schema", t.name, name_style_or_rgx], - ) - ) - self.generic_walk(t) - - def walk_SchemaStmt(self, t: ast.SchemaStmt) -> None: - assert isinstance(t, ast.SchemaStmt) - if t.is_mixin: - if not self._check_name(t.name, "mixin"): - name_style_or_rgx = self._get_name_style_or_rgx("mixin") - self.msgs.append( - message.Message( - "C0103", - self.module.filename, - MSGS["C0103"][0] % ("Mixin", t.name, name_style_or_rgx), - utils.get_source_code( - self.module.filename, t.name_node.line, self.code - ), - (t.name_node.line, t.name_node.column), - ["Mixin", t.name, name_style_or_rgx], - ) - ) - elif t.is_protocol: - if not self._check_name(t.name, "protocol"): - name_style_or_rgx = self._get_name_style_or_rgx("schema") - self.msgs.append( - message.Message( - "C0103", - self.module.filename, - MSGS["C0103"][0] % ("Protocol", t.name, name_style_or_rgx), - utils.get_source_code( - self.module.filename, t.name_node.line, self.code - ), - (t.name_node.line, t.name_node.column), - ["Protocol", t.name, name_style_or_rgx], - ) - ) - else: - if not self._check_name(t.name, "schema"): - name_style_or_rgx = self._get_name_style_or_rgx("schema") - self.msgs.append( - message.Message( - "C0103", - self.module.filename, - MSGS["C0103"][0] % ("Schema", t.name, name_style_or_rgx), - utils.get_source_code( - self.module.filename, t.name_node.line, self.code - ), - (t.name_node.line, t.name_node.column), - ["Schema", t.name, name_style_or_rgx], - ) - ) - self.generic_walk(t) - - def walk_Arguments(self, t: ast.Arguments) -> None: - assert isinstance(t, ast.Arguments) - for arg in t.args: - for name in arg.name_nodes: - if not self._check_name(name.value, "argument"): - name_style_or_rgx = self._get_name_style_or_rgx("argument") - self.msgs.append( - message.Message( - "C0103", - self.module.filename, - MSGS["C0103"][0] - % ("Argument", name.value, name_style_or_rgx), - utils.get_source_code( - self.module.filename, t.line, self.code - ), - (t.line, t.column), - ["Argument", name.value, name_style_or_rgx], - ) - ) - self.generic_walk(t) - - def walk_SchemaAttr(self, t: ast.SchemaAttr) -> None: - assert isinstance(t, ast.SchemaAttr) - if not self._check_name(t.name, "schema_attribute"): - name_style_or_rgx = self._get_name_style_or_rgx("schema_attribute") - self.msgs.append( - message.Message( - "C0103", - self.module.filename, - MSGS["C0103"][0] % ("Schema attribute", t.name, name_style_or_rgx), - utils.get_source_code(self.module.filename, t.line, self.code), - (t.line, t.column), - ["Schema attribute", t.name, name_style_or_rgx], - ) - ) - self.generic_walk(t) - - def walk_AssignStmt(self, t: ast.AssignStmt) -> None: - assert isinstance(t, ast.AssignStmt) - for target in t.targets: - for name in target.name_nodes: - if not self._check_name(name.value, "variable"): - name_style_or_rgx = self._get_name_style_or_rgx("variable") - self.msgs.append( - message.Message( - "C0103", - self.module.filename, - MSGS["C0103"][0] - % ("Variable", name.value, name_style_or_rgx), - utils.get_source_code( - self.module.filename, t.line, self.code - ), - (name.line, name.column), - ["Variable", name.value, name_style_or_rgx], - ) - ) - self.generic_walk(t) - - def walk_Name(self, t: ast.Name) -> None: - assert isinstance(t, ast.Name) - if self._disallowed_name(t.value): - self.msgs.append( - message.Message( - "C0104", - self.module.filename, - MSGS["C0104"][0] % t.value, - utils.get_source_code(self.module.filename, t.line, self.code), - (t.line, t.column), - [t.value], - ) - ) diff --git a/internal/kclvm_py/tools/lint/checkers/imports.py b/internal/kclvm_py/tools/lint/checkers/imports.py deleted file mode 100644 index e3dce0220..000000000 --- a/internal/kclvm_py/tools/lint/checkers/imports.py +++ /dev/null @@ -1,228 +0,0 @@ -import os -from typing import Union - -import kclvm.kcl.info as kcl_info -import kclvm.tools.lint.message.message as message -import kclvm.compiler.vfs as vfs -import kclvm.kcl.ast as ast -import kclvm.compiler.extension.plugin.plugin_model as plugin -import kclvm.compiler.extension.builtin.builtin as builtin -import kclvm.tools.lint.lint.utils as utils -from kclvm.tools.lint.checkers.base_checker import BaseChecker -import re - -MSGS = { - "E0401": ("Unable to import %s.", "Unable to import.", "Unable to import '{0}'."), - "W0404": ( - "%s is reimported multiple times.", - "Module reimported.", - "'{0}' is reimported multiple times.", - ), - "E0406": ( - "Module import itself.", - "Module import itself.", - "Module import itself.", - ), - "W0411": ( - "%s imported but unused.", - "Module imported but unused.", - "'{0}' imported but unused.", - ), - "E0413": ( - "Import %s should be placed at the top of the module.", - "ImportStmt is not at the top of the file.", - "Import '{0}' should be placed at the top of the module.", - ), -} - -IMPORT_POSITION_CHECK_LIST = [ - "AssignStmt", - "AugAssignStmt", - "AssertStmt", - "IfStmt", - "TypeAliasStmt", - "SchemaStmt", - "RuleStmt", -] - - -class ImportsChecker(BaseChecker): - def __init__(self, linter=None) -> None: - super().__init__(linter) - self.name = "ImportCheck" - self.MSGS = MSGS - self.prog = None - self.module = None - self.code = None - self.root: str = None - # for reimport check - self.has_imported_modules = None - # for unused import check - self.import_names_map = None - # for import position check - self.import_position_check = True - - def reset(self) -> None: - self.msgs.clear() - self.module = None - self.code = None - self.root = None - if self.import_names_map: - self.import_names_map.clear() - if self.has_imported_modules: - self.has_imported_modules.clear() - self.import_position_check = True - - def get_module(self, prog: ast.Program, code: str) -> None: - assert isinstance(prog, ast.Program) - assert code is not None - self.prog = prog - self.module = prog.pkgs["__main__"][0] - self.code = code - self.root = prog.root - self.has_imported_modules = [] - self.import_names_map = {} - - def check(self, prog: ast.Program, code: str) -> None: - assert isinstance(prog, ast.Program) - assert code is not None - self.reset() - self.get_module(prog, code) - self.walk(self.module) - for k, v in self.import_names_map.items(): - self.msgs.append( - message.Message( - "W0411", - self.module.filename, - MSGS["W0411"][0] % k, - utils.get_source_code(self.module.filename, v.line, self.code), - (v.line, v.column), - [k], - ) - ) - - def check_import_file_exist(self, t: ast.ImportStmt, abs_path: str) -> bool: - assert isinstance(t, ast.ImportStmt) - if os.path.isdir(abs_path) or os.path.isfile( - abs_path + kcl_info.KCL_FILE_SUFFIX - ): - return True - else: - self.msgs.append( - message.Message( - "E0401", - self.module.filename, - MSGS["E0401"][0] % t.path, - utils.get_source_code(self.module.filename, t.line, self.code), - (t.line, t.column), - [t.path], - ) - ) - return False - - def check_import_position(self, t: ast.AST) -> None: - assert isinstance(t, ast.AST) - if self.import_position_check: - if t._ast_type in IMPORT_POSITION_CHECK_LIST: - self.import_position_check = False - else: - if isinstance(t, ast.ImportStmt): - self.msgs.append( - message.Message( - "E0413", - self.module.filename, - MSGS["E0413"][0] % t.pkg_name, - utils.get_source_code(self.module.filename, t.line, self.code), - (t.line, t.column), - [t.pkg_name], - ) - ) - - def check_unused_import(self, t: Union[ast.Identifier, str]) -> None: - if isinstance(t, ast.Identifier): - if t.get_first_name() in self.import_names_map.keys(): - self.import_names_map.pop(t.get_first_name()) - else: - # SchemaAttr.types, A|B, [A|B], {A|B:C} - type_list = re.split(r"[|:\[\]\{\}]", t) - for type in type_list: - names = type.split(".") - first_name = names[0] - if first_name in self.import_names_map.keys(): - self.import_names_map.pop(first_name) - - def check_import_itself(self, t: ast.ImportStmt, abs_path: str) -> None: - assert isinstance(t, ast.ImportStmt) - if os.path.isdir(abs_path): - return - abs_path += kcl_info.KCL_FILE_SUFFIX - # normpath: a/./b -> a/b - if abs_path == str(os.path.normpath(self.module.filename)): - self.msgs.append( - message.Message( - "E0406", - self.module.filename, - MSGS["E0406"][0], - utils.get_source_code(self.module.filename, t.line, self.code), - (t.line, t.column), - [], - ) - ) - - def check_reimport(self, t: ast.ImportStmt, abs_path: str) -> None: - assert isinstance(t, ast.ImportStmt) - if abs_path in self.has_imported_modules: - self.msgs.append( - message.Message( - "W0404", - self.module.filename, - MSGS["W0404"][0] % t.pkg_name, - utils.get_source_code(self.module.filename, t.line, self.code), - (t.line, t.column), - [t.pkg_name], - ) - ) - else: - self.import_names_map[t.pkg_name] = t - self.has_imported_modules.append(abs_path) - - def generic_walk(self, t: ast.AST) -> None: - """Called if no explicit walker function exists for a node.""" - self.check_import_position(t) - for field, value in ast.iter_fields(t): - if isinstance(value, list): - for v in value: - # IfStmt.elif_body: List[List[Stmt]] - if isinstance(v, list): - for v1 in v: - self.walk(v1) - if isinstance(v, ast.AST): - self.walk(v) - elif isinstance(value, ast.AST): - self.walk(value) - - def walk_Identifier(self, t: ast.Identifier) -> None: - assert isinstance(t, ast.Identifier) - self.check_unused_import(t) - - def walk_SchemaAttr(self, t: ast.SchemaAttr) -> None: - assert isinstance(t, ast.SchemaAttr) - self.check_unused_import(t.type_str) - self.generic_walk(t) - - def walk_ImportStmt(self, t: ast.ImportStmt) -> None: - assert isinstance(t, ast.ImportStmt) - self.check_import_position(t) - if ( - t.path.startswith(plugin.PLUGIN_MODULE_NAME) - or t.name in builtin.STANDARD_SYSTEM_MODULES - ): - self.check_reimport(t, t.path) - return - fix_path = vfs.FixImportPath(self.root, self.module.filename, t.path).replace( - ".", "/" - ) - abs_path = os.path.join(self.root, fix_path) - if self.check_import_file_exist(t, abs_path): - self.check_import_itself(t, abs_path) - self.check_reimport(t, abs_path) diff --git a/internal/kclvm_py/tools/lint/checkers/misc.py b/internal/kclvm_py/tools/lint/checkers/misc.py deleted file mode 100644 index 709a86bfc..000000000 --- a/internal/kclvm_py/tools/lint/checkers/misc.py +++ /dev/null @@ -1,66 +0,0 @@ -from typing import List - -import kclvm.kcl.ast.ast as ast -import kclvm.tools.lint.message.message as message -from kclvm.tools.lint.checkers.base_checker import BaseChecker - -MSGS = { - "E0501": ( - "line too long (%d > %d characters).", - "Line too long.", - "line too long ('{0}' > '{1}' characters).", - ) -} - - -class MiscChecker(BaseChecker): - def __init__(self, linter) -> None: - super().__init__(linter) - self.name = "MiscCheck" - self.code = None - self.MSGS = MSGS - self.module = None - self.prog = None - self.work_dir = None - self.root: str = None - - def reset(self) -> None: - self.msgs.clear() - self.code = None - self.module = None - self.root = None - - def get_module(self, prog: ast.Program, code: str) -> None: - assert isinstance(prog, ast.Program) - assert code is not None - self.prog = prog - self.module = prog.pkgs["__main__"][0] - self.code = code - self.root: str = prog.root - - def check(self, prog: ast.Program, code: str) -> None: - assert isinstance(prog, ast.Program) - assert code is not None - self.reset() - self.get_module(prog, code) - code_lines = self.code.split("\n") - self.check_line_too_long(code_lines) - - # todo: check in ast instead of code or file - def check_line_too_long(self, code_lines: List[str]) -> None: - for i, v in enumerate(code_lines): - if len(v) > self.options.max_line_length: - self.msgs.append( - message.Message( - "E0501", - self.module.filename, - MSGS["E0501"][0] - % ( - len(v), - self.options.max_line_length, - ), - v.strip(), - (i + 1, 1), - [len(v), self.options.max_line_length], - ) - ) diff --git a/internal/kclvm_py/tools/lint/lint/KCLLint.py b/internal/kclvm_py/tools/lint/lint/KCLLint.py deleted file mode 100644 index f1820d2b5..000000000 --- a/internal/kclvm_py/tools/lint/lint/KCLLint.py +++ /dev/null @@ -1,334 +0,0 @@ -""" -KCLLinter class controls all inspection processes of lint: loading config, checking and generating reports. - -The workflow of KCLLinter is as follows: -1. Load config. -2. Find all KCL files under the 'path' from CLI arguments, and parse them to ast.Program. -3. Register checker and reporter according to config -4. Distribute ast to each checker for checking, and generate Message,which represents the result of check. -5. Linter collects Messages from all checkers. -6. Distribute Message to each reporter as output -┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ -│ KCLLinter │ -│ │ -│ ┌───────────┐ ┌─────────────────────────────────────────────────────────────────┐ │ -│ │ KCL file │ │ Checker │ │ -│ └───────────┘ │ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ │ -│ ↓ │ │ importChecker │ │ schemaChecker │ │ ... │ │ │ -│ ┌───────────┐ │ │ ┌───────────┐ │ │ ┌───────────┐ │ │ ┌───────────┐ │ │ │ -│ │ ast.Prog │ → │ │ │ Message │ │ │ │ Message │ │ │ │ Message │ │ │ │ -│ └───────────┘ │ │ └───────────┘ │ │ └───────────┘ │ │ └───────────┘ │ │ │ -│ │ │ ┌───────────┐ │ │ ┌───────────┐ │ │ ┌───────────┐ │ │ │ -│ │ │ │ Message │ │ │ │ Message │ │ │ │ Message │ │ │ │ -│ │ │ └───────────┘ │ │ └───────────┘ │ │ └───────────┘ │ │ │ -│ ┌──────────────────────┐ │ │ ┌───────────┐ │ │ ┌───────────┐ │ │ ┌───────────┐ │ │ │ -│ │ Config │ │ │ │ ... │ │ │ │ ... │ │ │ │ ... │ │ │ │ -│ │ │ │ │ └───────────┘ │ │ └───────────┘ │ │ └───────────┘ │ │ │ -│ │ 1 config │ │ └─────────────────┘ └─────────────────┘ └─────────────────┘ │ │ -│ │ 2 .kcllint │ └─────────────────────────────────────────────────────────────────┘ │ -│ │ 3 default_config │ │ -│ │ │ ↓ │ -│ │ │ msgs_map -> MessageID: count │ -│ └──────────────────────┘ msgs -> ┌────────────────────────────────────────────────────┐ │ -│ │ ┌───────────┐ ┌───────────┐ ┌───────────┐ │ │ -│ │ │ Message │ │ Message │ │ Message │ │ │ -│ │ └───────────┘ └───────────┘ └───────────┘ │ │ -│ └────────────────────────────────────────────────────┘ │ -│ │ -│ ↓ │ -│ ┌─────────────────────────────────────────────────────────────────┐ │ -│ │ Reporter │ │ -│ │ ┌───────────┐ ┌───────────┐ ┌───────────┐ ┌───────────┐ │ │ -│ │ │ stdout │ │ sarif │ │ file │ │ ... │ │ │ -│ │ └───────────┘ └───────────┘ └───────────┘ └───────────┘ │ │ -│ └─────────────────────────────────────────────────────────────────┘ │ -│ │ -│ │ -│ │ -└─────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ -""" -import os -import glob -import ruamel.yaml as yaml -from typing import Dict, Any, Optional, List - -import kclvm.compiler.parser.parser as parser -from kclvm.tools.lint.checkers import * -import kclvm.tools.lint.reporters.base_reporter as base_reporter -import kclvm.tools.lint.reporters.stdout_reporter as stdout_reporter -import kclvm.tools.lint.reporters.file_reporter as file_reporter -import kclvm.tools.lint.reporters.sarif_reporter as sarif_reporter -import kclvm.kcl.error.kcl_error as error -import kclvm.tools.lint.message.message as message -import kclvm.tools.lint.lint.exceptions as exceptions -import kclvm.kcl.info as kcl_info -import kclvm.kcl.ast as ast - -LINT_CONFIG_SUFFIX = ".kcllint" -DEFAULT_CONFIG = { - "check_list": ["import", "misc", "basic"], - "ignore": [], - "max_line_length": 200, - "output": ["stdout"], - "output_path": None, - "module_naming_style": "ANY", - "package_naming_style": "ANY", - "schema_naming_style": "PascalCase", - "mixin_naming_style": "PascalCase", - "protocol_naming_style": "PascalCase", - "argument_naming_style": "camelCase", - "variable_naming_style": "ANY", - "schema_attribute_naming_style": "ANY", - "module_rgx": None, - "package_rgx": None, - "schema_rgx": None, - "mixin_rgx": None, - "protocol_rgx": None, - "argument_rgx": None, - "variable_rgx": None, - "schema_attribute_rgx": None, - "bad_names": ["foo", "bar", "baz", "toto", "tata", "tutu", "I", "l", "O"], -} - -MSGS = {"E0999": ("Parse failed:%s.", "Parse failed.", "Parse failed:'{0}'.")} -PARSE_FAILED_MSG_ID = "E0999" - - -class CheckerFactory: - @staticmethod - def get_checker(checker: str, linter=None) -> Optional[base_checker.BaseChecker]: - if checker == "import": - return imports.ImportsChecker(linter) - elif checker == "misc": - return misc.MiscChecker(linter) - elif checker == "basic": - return basic.BasicChecker(linter) - else: - raise exceptions.InvalidCheckerError(checker) - - -class ReporterFactory: - @staticmethod - def get_reporter( - reporter: str, linter=None - ) -> Optional[base_reporter.BaseReporter]: - if reporter == "stdout": - return stdout_reporter.STDOUTReporter(linter) - elif reporter == "file": - return file_reporter.FileReporter(linter) - elif reporter == "sarif": - return sarif_reporter.SARIFReporter(linter) - else: - raise exceptions.InvalidReporterError(reporter) - - -class LinterConfig: - def __init__(self): - self.check_list = ["import", "misc", "basic"] - self.ignore = [] - self.max_line_length = 200 - self.output = ["stdout"] - self.output_path = None - self.module_naming_style = "ANY" - self.package_naming_style = "ANY" - self.schema_naming_style = "PascalCase" - self.mixin_naming_style = "PascalCase" - self.protocol_naming_style = "PascalCase" - self.argument_naming_style = "camelCase" - self.variable_naming_style = "ANY" - self.schema_attribute_naming_style = "ANY" - self.module_rgx = None - self.package_rgx = None - self.schema_rgx = None - self.mixin_rgx = None - self.protocol_rgx = None - self.argument_rgx = None - self.variable_rgx = None - self.schema_attribute_rgx = None - self.bad_names = ["foo", "bar", "baz", "toto", "tata", "tutu", "I", "l", "O"] - - def update(self, config: {}): - for k, v in config.items(): - if hasattr(self, k): - self.__setattr__(k, v) - - -class KCLLinter: - def __init__( - self, - *path: str, - config: Dict[str, Any] = None, - k_code_list: List[str] = None, - ) -> None: - self.path = path or [] - self.k_code_list = k_code_list or [] - self.file_list = [] - self.programs_list = [] - self.checkers = [] - self.reporters = [] - self.config = LinterConfig() - self.msgs = [] - self.MSGS = MSGS - self.msgs_map = {} - - path_list = [x for x in path] - for i, s in enumerate(path_list): - s = os.path.abspath(s) - if os.path.isfile(s): - self.file_list.append(s) - elif os.path.isdir(s): - self.file_list += glob.glob( - os.path.join(s, "**", kcl_info.KCL_FILE_PATTERN), - recursive=True, - ) - else: - raise FileNotFoundError(s) - - self._load_config(config) - - def reset(self): - self.reporters.clear() - self.checkers.clear() - self.MSGS = MSGS - self.msgs.clear() - self.msgs_map = {} - - def run(self) -> None: - self.reset() - self._register_checkers(self.config.check_list) - self._register_reporters(self.config.output) - self._get_programs(self.file_list, self.k_code_list) - self._check(self.programs_list, self.checkers, self.k_code_list) - self._display() - - def check(self) -> None: - self.reset() - self._register_checkers(self.config.check_list) - self._register_reporters(self.config.output) - self._get_programs(self.file_list, self.k_code_list) - self._check(self.programs_list, self.checkers, self.k_code_list) - - def _load_config(self, config) -> None: - for s in self.path: - if os.path.isfile(s): - kcllint_path = os.path.join( - os.path.abspath(os.path.dirname(s)), LINT_CONFIG_SUFFIX - ) - elif os.path.isdir(s): - kcllint_path = os.path.join(os.path.abspath(s), LINT_CONFIG_SUFFIX) - if os.path.isfile(kcllint_path): - with open(kcllint_path, "r", encoding="utf-8") as f: - kcllint_config = f.read() - self.config.update(yaml.safe_load(kcllint_config)) - break - if config: - self.config.update(config) - - def _register_checker(self, checker: base_checker.BaseChecker) -> None: - self.checkers.append(checker) - if hasattr(checker, "MSGS"): - self.MSGS.update(checker.MSGS) - - def _register_checkers(self, checkers: List[str]) -> None: - factory = CheckerFactory() - for s in checkers: - self._register_checker(factory.get_checker(s, self)) - - def _register_reporters(self, reporters: List[str]) -> None: - if not reporters or len(reporters) == 0: - raise exceptions.EmptyReporterError - if "file" in reporters or "sarif" in reporters: - assert self.config.output_path, "Without ouput file path" - factory = ReporterFactory() - self.reporters = [factory.get_reporter(s, self) for s in reporters] - - def _get_programs( - self, file_list: List[str], k_code_list: List[str] - ) -> List[ast.Program]: - for i, file in enumerate(file_list): - _code = k_code_list[i] if (i < len(k_code_list)) else None - _k_code_list = [_code] if _code else None - try: - prog = parser.LoadProgram(file, k_code_list=_k_code_list) - self.programs_list.append(prog) - except error.KCLException as err: - if not _code: - with open(err.filename) as f: - _code = f.read() - source_line = _code.split("\n")[err.lineno - 1] - msg = message.Message( - PARSE_FAILED_MSG_ID, - err.filename, - MSGS[PARSE_FAILED_MSG_ID][0] % err.name, - source_line, - (err.lineno, err.colno), - [err.name], - ) - if (msg not in self.msgs) and ( - PARSE_FAILED_MSG_ID not in self.config.ignore - ): - self.msgs.append(msg) - self.msgs_map[PARSE_FAILED_MSG_ID] = ( - self.msgs_map.setdefault(PARSE_FAILED_MSG_ID, 0) + 1 - ) - - def _check( - self, - progs: List[ast.Program], - checkers: List[base_checker.BaseChecker], - k_code_list: List[str], - ): - for i, prog in enumerate(progs): - if i < len(k_code_list): - _code = k_code_list[i] - else: - module = prog.pkgs["__main__"][0] - with open(module.filename) as f: - _code = f.read() - for checker in checkers: - checker.check(prog, _code) - # collect msgs to linter - for msg in checker.msgs: - if msg.msg_id in self.config.ignore: - continue - if msg not in self.msgs: - self.msgs.append(msg) - self.msgs_map[msg.msg_id] = ( - self.msgs_map.setdefault(msg.msg_id, 0) + 1 - ) - - def _display(self) -> None: - for reporter in self.reporters: - reporter.display() - - -def kcl_lint(*path: str, config: Dict[str, Any] = None) -> List[message.Message]: - """ - Check kcl files or all kcl files in dirs - :param path: str, path of a kcl file or dir - :param config: Dict[str, Any], config of lint - :return: List[Message] result of lint check - """ - lint = KCLLinter(*path, config=config) - lint.check() - return lint.msgs - - -def kcl_lint_code( - *path: str, - k_code_list: List[str], - config: Dict[str, Any] = None, -) -> List[message.Message]: - """ - Check individual code of string type or some code in kcl file - if pararm:file not None, file must be a path of kcl file and code should be part of the file, - .e.g select some code for checking in ide - :param k_code_list: code of string type or some code in kcl file - :param config: Dict[str, Any], config of lint - :param path: path of kcl file - :return: List[Message] result of lint check - """ - assert len(k_code_list) > 0 - lint = KCLLinter(*path, config=config, k_code_list=k_code_list) - lint.check() - return lint.msgs diff --git a/internal/kclvm_py/tools/lint/lint/__init__.py b/internal/kclvm_py/tools/lint/lint/__init__.py deleted file mode 100644 index ecac76d94..000000000 --- a/internal/kclvm_py/tools/lint/lint/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -from .KCLLint import KCLLinter, kcl_lint, kcl_lint_code - -__all__ = ["KCLLinter", "kcl_lint", "kcl_lint_code"] diff --git a/internal/kclvm_py/tools/lint/lint/__main__.py b/internal/kclvm_py/tools/lint/lint/__main__.py deleted file mode 100644 index 2062c70ba..000000000 --- a/internal/kclvm_py/tools/lint/lint/__main__.py +++ /dev/null @@ -1,68 +0,0 @@ -import argparse -import sys -import traceback -import os -import ruamel.yaml as yaml - -from kclvm.tools.lint.lint.KCLLint import KCLLinter - -LINT_CONFIG_SUFFIX = ".kcllint" - - -class LintMeta: - KCL_FILE_DESC = "KCL file path" - AUTO_FIX = "Auto fix" - KCL_CONFIG_PATH = "KCL lint config path" - - -def kcl_lint_main() -> None: - parser = argparse.ArgumentParser(prog="kcl-lint") - """ - parser.add_argument( - "--fix", - dest="auto_fix", - action="store_true", - help=LintMeta.AUTO_FIX, - required=False, - ) - """ - parser.add_argument( - "--config", - dest="kcl_lint_config", - metavar="file", - type=str, - help=LintMeta.KCL_CONFIG_PATH, - ) - parser.add_argument( - dest="kcl_files", - metavar="file", - type=str, - help=LintMeta.KCL_FILE_DESC, - nargs="+", - ) - # Todo:add check_list, ignore, max_line_length, output to cli args - args = parser.parse_args() - if len(sys.argv) == 1: - parser.print_help(sys.stdout) - sys.exit(0) - if args.kcl_lint_config: - assert os.path.isfile(args.kcl_lint_config) and args.kcl_lint_config.endswith( - LINT_CONFIG_SUFFIX - ), "Path error, can't find '.kcllint'" - config_path = args.kcl_lint_config - with open(config_path, "r", encoding="utf-8") as f: - config = yaml.safe_load(f) - KCLLinter(*args.kcl_files, config=config).run() - else: - KCLLinter(*args.kcl_files).run() - """ - if args.auto_fix: - print("Auto fix: todo") - """ - - -if __name__ == "__main__": - try: - kcl_lint_main() - except Exception: - print(traceback.format_exc()) diff --git a/internal/kclvm_py/tools/lint/lint/exceptions.py b/internal/kclvm_py/tools/lint/lint/exceptions.py deleted file mode 100644 index 89a717dfa..000000000 --- a/internal/kclvm_py/tools/lint/lint/exceptions.py +++ /dev/null @@ -1,25 +0,0 @@ -class InvalidCheckerError(Exception): - """raised when selected reporter is invalid (e.g. not found)""" - - def __init__(self, checker: str): - self.checker_name = checker - - def __str__(self): - return f"Args wrong, checker {self.checker_name} not found" - - -class EmptyReporterError(Exception): - """raised when reporter list is empty and so should not be displayed""" - - def __str__(self): - return "Without output reporter" - - -class InvalidReporterError(Exception): - """raised when selected reporter is invalid (e.g. not found)""" - - def __init__(self, reporter: str): - self.reporter_name = reporter - - def __str__(self): - return f"Args wrong, reporter {self.reporter_name} not found" diff --git a/internal/kclvm_py/tools/lint/lint/utils.py b/internal/kclvm_py/tools/lint/lint/utils.py deleted file mode 100644 index e9a854ba3..000000000 --- a/internal/kclvm_py/tools/lint/lint/utils.py +++ /dev/null @@ -1,39 +0,0 @@ -import os -from io import StringIO -from typing import Union, Optional -import pathlib - -import kclvm.kcl.ast.ast as ast -import kclvm.tools.printer.printer as printer -import kclvm.kcl.info as kcl_info - - -def get_source_code( - file: Optional[Union[str, pathlib.PosixPath]], line: int, code: Optional[str] = None -) -> str: - if code: - lines = code.split("\n") - assert line <= len(lines) - source_line = lines[line - 1] - else: - _file = str(file) - assert is_kcl_file(_file) - assert line > 0 - with open(_file, "r", encoding="utf8") as source_file: - lines = source_file.read().split("\n") - assert line <= len(lines) - source_line = lines[line - 1] - return source_line - - -def is_kcl_file(file: str) -> bool: - assert isinstance(file, str) - return os.path.isfile(file) and file.endswith(kcl_info.KCL_FILE_SUFFIX) - - -def get_code_from_module(module: ast.Module) -> str: - assert isinstance(module, ast.Module) - with StringIO() as IO: - printer.PrintAST(module, IO) - code = IO.getvalue() - return code diff --git a/internal/kclvm_py/tools/lint/message/message.py b/internal/kclvm_py/tools/lint/message/message.py deleted file mode 100644 index 2b1a8ee0a..000000000 --- a/internal/kclvm_py/tools/lint/message/message.py +++ /dev/null @@ -1,49 +0,0 @@ -import pathlib -from typing import Tuple, Union, Optional, List, Any - - -class Message: - """This class represent a message to be issued by the reporters""" - - def __init__( - self, - msg_id: str, - file: Optional[Union[str, pathlib.PosixPath]], - msg: str, - source_code: str, - pos: Tuple[int, int], - arguments: List[Any], - ): - self.msg_id = msg_id - self.level = msg_id[0] - self.file = str(file) if file else None - self.msg = msg - self.source_code = source_code - self.pos = pos - self.arguments = [str(arg) for arg in arguments] - - def __str__(self): - return ( - f"{self.file}:{self.pos[0]}:{self.pos[1]}: {self.msg_id} {self.msg}\n" - + self.source_code - + "\n" - + (self.pos[1] - 1) * " " - + "^" - ) - - def __eq__(self, other): - return ( - self.msg_id, - self.file, - self.msg, - self.source_code, - self.pos, - self.arguments, - ) == ( - other.msg_id, - other.file, - other.msg, - other.source_code, - other.pos, - other.arguments, - ) diff --git a/internal/kclvm_py/tools/lint/reporters/base_reporter.py b/internal/kclvm_py/tools/lint/reporters/base_reporter.py deleted file mode 100644 index 5ae374f98..000000000 --- a/internal/kclvm_py/tools/lint/reporters/base_reporter.py +++ /dev/null @@ -1,35 +0,0 @@ -from typing import List - -from kclvm.tools.lint.message.message import Message - - -class BaseReporter: - name: str = "" - """base class for reporters""" - - def __init__(self, linter, output=None, encoding=None): - self.linter = linter - self.out = None - self.out_encoding = None - self.set_output(output, encoding) - - def __eq__(self, other): - return self.name == other.name and self.linter == other.linter - - def set_output(self, output=None, encoding="utf-8"): - """ - set output stream - todo: - The output property is not used yet, and replaced by open_output_stream. - When reporter display the result, the 'open_output_stream' function is - called to open the output stream. - """ - self.out = output - self.out_encoding = encoding - - def display(self): - self.print_msg(self.linter.msgs) - - def print_msg(self, msgs: List[Message] = None): - """Should be overridden by subclass""" - raise NotImplementedError() diff --git a/internal/kclvm_py/tools/lint/reporters/file_reporter.py b/internal/kclvm_py/tools/lint/reporters/file_reporter.py deleted file mode 100644 index 5f7e279d4..000000000 --- a/internal/kclvm_py/tools/lint/reporters/file_reporter.py +++ /dev/null @@ -1,26 +0,0 @@ -import sys -from typing import List - -from kclvm.tools.lint.reporters.base_reporter import BaseReporter -from kclvm.tools.lint.message.message import Message - - -class FileReporter(BaseReporter): - def __init__(self, linter, output=None, encoding=None): - self.name = "file_reporter" - self.output_file = linter.config.output_path - super().__init__(linter, output, encoding) - - def print_msg(self, msgs: List[Message] = None): - assert self.output_file - with open(self.output_file, "w") as f: - current = sys.stdout - sys.stdout = f - for msg in msgs: - print(msg) - print() - print("Check total {} files:".format(len(self.linter.file_list))) - for k, v in self.linter.msgs_map.items(): - print("{:<8}{}: {}".format(v, k, self.linter.MSGS[k][1])) - print(f"KCL Lint: {len(self.linter.msgs)} problems") - sys.stdout = current diff --git a/internal/kclvm_py/tools/lint/reporters/sarif_reporter.py b/internal/kclvm_py/tools/lint/reporters/sarif_reporter.py deleted file mode 100644 index 02f624bb2..000000000 --- a/internal/kclvm_py/tools/lint/reporters/sarif_reporter.py +++ /dev/null @@ -1,81 +0,0 @@ -import sys -from typing import List, Dict, Tuple -import json -from kclvm.tools.lint.reporters.base_reporter import BaseReporter -from kclvm.tools.lint.message.message import Message - - -LEVEL_MAP = {"E": "error", "W": "waring", "C": "note"} - - -class SARIFMeta: - VERSION = "2.1.0" - SCHEMA = "https://docs.oasis-open.org/sarif/sarif/v2.1.0/cs01/schemas/sarif-schema-2.1.0.json" - NAME = "kcl-lint" - KCLLINT_VERSION = "0.0.1" - INFORMATION_URI = "https://kusion-docs.com/docs/reference/cli/kcl/lint" - - -class Rule: - def __init__(self, id: str, default: str, short: str): - self.id = id - self.messageStrings = { - "default": {"text": default}, - "shortStrings": {"text": short}, - } - - -class Result: - def __init__(self, m: Message): - self.ruleId = m.msg_id - self.level = LEVEL_MAP[m.msg_id[0]] if (m.msg_id[0] in LEVEL_MAP) else "note" - self.message = {"id": "default", "arguments": m.arguments} - self.locations = [ - { - "physicalLocation": { - "artifactLocation": {"uri": m.file}, - "region": {"startLine": m.pos[0], "startColumn": m.pos[1]}, - } - } - ] - - -class Tool: - def __init__(self, ids: List[str], MSGS: Dict[str, Tuple[str, str]]): - self.driver = { - "name": SARIFMeta.NAME, - "version": SARIFMeta.KCLLINT_VERSION, - "informationUri": SARIFMeta.INFORMATION_URI, - "rules": [Rule(id, MSGS[id][2], MSGS[id][1]) for id in ids], - } - - -class SarifLog(object): - """Static Analysis Results Format (SARIF) Version 2.1.0 JSON Schema: a standard format for the output of static analysis tools.""" - - def __init__(self, msgs: List[Message], MSGS: Dict[str, Tuple[str, str]]): - self.version = SARIFMeta.VERSION - # self.$schema = SARIFMeta.SCHEMA - msg_ids = list(set([m.msg_id for m in msgs])) - self.runs = [ - {"tool": Tool(msg_ids, MSGS), "results": [Result(m) for m in msgs]} - ] - - -class SARIFReporter(BaseReporter): - def __init__(self, linter, output=None, encoding=None): - self.name = "sarif_reporter" - self.output_file = linter.config.output_path - super().__init__(linter, output, encoding) - - def print_msg(self, msgs: List[Message] = None): - assert self.output_file - sarif_log = SarifLog(msgs, self.linter.MSGS) - json_str = json.dumps( - sarif_log, default=lambda o: o.__dict__, sort_keys=True, indent=2 - ) - with open(self.output_file, "w") as f: - current = sys.stdout - sys.stdout = f - print(json_str) - sys.stdout = current diff --git a/internal/kclvm_py/tools/lint/reporters/stdout_reporter.py b/internal/kclvm_py/tools/lint/reporters/stdout_reporter.py deleted file mode 100644 index 302001fff..000000000 --- a/internal/kclvm_py/tools/lint/reporters/stdout_reporter.py +++ /dev/null @@ -1,78 +0,0 @@ -import sys -from typing import List - -from kclvm.tools.lint.reporters.base_reporter import BaseReporter -from kclvm.tools.lint.message.message import Message - -LINT_THEME: dict = { - "ID": "\033[0;92m{}\033[0m", # green - "ERROR": "\033[0;91m{}\033[0m", # red - "WARNING": "\033[0;93m{}\033[0m", # yellow - "FILE_NAME": "\033[0;94m{}\033[0m", # blue - "LINE_COLUMN": "\033[0;96m{}\033[0m", # cyan - "MARK": "\033[0;31m{}\033[0m", # red - "NUMBER": "\033[0;31m{}\033[0m", # red -} - - -def color(content: str, content_type: str): - return LINT_THEME[content_type].format(content) - - -def msg_with_color(msg: Message): - return ( - color(msg.file, "FILE_NAME") - + ":" - + color(msg.pos[0], "LINE_COLUMN") - + ":" - + color(msg.pos[1], "LINE_COLUMN") - + ": " - + color(msg.msg_id, "ID") - + " " - + msg.msg - + "\n" - + msg.source_code - + "\n" - + (msg.pos[1] - 1) * " " - + color("^", "MARK") - ) - - -class STDOUTReporter(BaseReporter): - def __init__(self, linter, output=None, encoding=None): - self.name = "stdout_reporter" - super().__init__(linter, output, encoding) - - def print_msg(self, msgs: List[Message], file=sys.stdout): - """ - Print msgs with color.Because CI cannot parse color information, e.g. [0;31m{, - it is not enabled temporarily - - for msg in msgs: - print((msg_with_color(msg) if file.isatty() else str(msg)) + "\n") - print( - "Check total " - + ( - color(len(self.linter.file_list), "NUMBER") - if file.isatty() - else str(len(self.linter.file_list)) - ) - + " files:" - ) - for k, v in self.linter.msgs_map.items(): - print(("{:<19}".format(color(v, "NUMBER")) - + color(k, "ID") - + ": " - + self.linter.MSGS[k][1] - ) if file.isatty() else ("{:<8}{}: {}".format(v, k, self.linter.MSGS[k][1]))) - print("KCL Lint: " - + (color(len(self.linter.msgs), "NUMBER") if file.isatty() else str(len(self.linter.msgs))) - + " problems") - """ - for msg in msgs: - print(msg) - print() - print(f"Check total {len(self.linter.file_list)} files:") - for k, v in self.linter.msgs_map.items(): - print("{:<8}{}: {}".format(v, k, self.linter.MSGS[k][1])) - print(f"KCL Lint: {len(self.linter.msgs)} problems") diff --git a/internal/kclvm_py/tools/list_attribute/schema.py b/internal/kclvm_py/tools/list_attribute/schema.py deleted file mode 100644 index 034dc3f1b..000000000 --- a/internal/kclvm_py/tools/list_attribute/schema.py +++ /dev/null @@ -1,205 +0,0 @@ -# Copyright 2021 The KCL Authors. All rights reserved. - -import io - -from typing import List, Dict, Set - -import kclvm.compiler.parser as parser -import kclvm.api.object as objpkg -import kclvm.kcl.ast as ast -import kclvm.kcl.types as types -import kclvm.internal.gpyrpc.gpyrpc_pb2 as pb2 -import kclvm.tools.printer as printer - - -def get_schema_type_from_code( - file: str, code: str, schema_name: str = None -) -> List[pb2.KclType]: - """Get schema types from a kcl file or code. - - Parameters - ---------- - file: str - The kcl filename - code: str - The kcl code string - schema_name: str - The schema name got, when the schema name is empty, all schemas are returned. - - Returns - ------- - schema_types: List[pb2.KclType] - - KclType: - string type = 1; // schema, dict, list, str, int, float, bool, int(), float() str(), bool() - repeated KclType union_types = 2 ; // union types - string default = 3; // default value - - string schema_name = 4; // schema name - string schema_doc = 5; // schema doc - map properties = 6; // schema properties - repeated string required = 7; // required schema properties, [property_name1, property_name2] - - KclType key = 8; // dict key type - KclType item = 9; // dict/list item type - - int32 line = 10; - """ - result = [] - program = parser.LoadProgram( - file or "", k_code_list=[code] if code else None - ) - for name, o in types.ResolveProgram(program).main_scope.elems.items(): - if isinstance(o.type, objpkg.KCLSchemaDefTypeObject): - if not schema_name or name == schema_name: - result.append(kcl_type_obj_to_pb_kcl_type(o.type)) - return result - - -def kcl_type_obj_to_pb_kcl_type(tpe: types.Type) -> pb2.KclType: - """any, schema, dict, list, str, int, float, bool, int(), float() str(), bool(), union""" - if isinstance(tpe, objpkg.KCLSchemaDefTypeObject): - return kcl_type_obj_to_pb_kcl_type(tpe.schema_type) - elif isinstance(tpe, objpkg.KCLSchemaTypeObject): - return schema_type_obj_to_pb_kcl_type(tpe) - elif isinstance(tpe, objpkg.KCLAnyTypeObject): - return pb2.KclType( - type="any", - ) - elif isinstance(tpe, objpkg.KCLDictTypeObject): - return pb2.KclType( - type="dict", - key=kcl_type_obj_to_pb_kcl_type(tpe.key_type), - item=kcl_type_obj_to_pb_kcl_type(tpe.value_type), - ) - elif isinstance(tpe, objpkg.KCLListTypeObject): - return pb2.KclType( - type="list", - item=kcl_type_obj_to_pb_kcl_type(tpe.item_type), - ) - elif isinstance( - tpe, - ( - objpkg.KCLIntTypeObject, - objpkg.KCLFloatTypeObject, - objpkg.KCLStringTypeObject, - objpkg.KCLBoolTypeObject, - objpkg.KCLIntLitTypeObject, - objpkg.KCLFloatLitTypeObject, - objpkg.KCLStringLitTypeObject, - objpkg.KCLBoolLitTypeObject, - ), - ): - return pb2.KclType( - type=tpe.type_str(), - ) - elif isinstance(tpe, objpkg.KCLUnionTypeObject): - return pb2.KclType( - type="union", - union_types=[kcl_type_obj_to_pb_kcl_type(t) for t in tpe.types], - ) - return ( - pb2.KclType( - type=tpe.type_str(), - ) - if isinstance(tpe, types.Type) - else None - ) - - -def schema_type_obj_to_pb_kcl_type( - schema_type_obj: objpkg.KCLSchemaTypeObject, -) -> pb2.KclType: - """Convert the schema type object to the protobuf kcl type.""" - return pb2.KclType( - type="schema", - schema_name=schema_type_obj.name, - schema_doc=schema_type_obj.doc, - properties=get_schema_type_obj_properties(schema_type_obj), - decorators=[ - kcl_decorator_to_pb_decorator(decorator) - for decorator in schema_type_obj.node_ref.decorators or [] - ], - required=list(sorted(get_schema_type_obj_required_attributes(schema_type_obj))), - ) - - -def get_schema_type_obj_properties( - schema_type_obj: objpkg.KCLSchemaTypeObject, -) -> Dict[str, pb2.KclType]: - """Get schema properties from a schema type object""" - result_map = {} - base_result_map = ( - get_schema_type_obj_properties(schema_type_obj.base) - if schema_type_obj.base - else {} - ) - for attr, attr_obj in schema_type_obj.attr_obj_map.items(): - if attr != objpkg.SCHEMA_SETTINGS_ATTR_NAME: - type_node = attr_obj.attr_type - result_map[attr] = kcl_type_obj_to_pb_kcl_type(type_node) - result_map[attr].default = ( - value_to_string(attr_obj.attr_node.value) - if attr_obj.attr_node.value - else "" - ) - result_map[attr].decorators.extend( - [ - kcl_decorator_to_pb_decorator(decorator) - for decorator in attr_obj.attr_node.decorators - ] - if isinstance(attr_obj.attr_node, ast.SchemaAttr) - else [] - ) - base_result_map.update(result_map) - line = 1 - for k in base_result_map: - base_result_map[k].line = line - line += 1 - return base_result_map - - -def get_schema_type_obj_required_attributes( - schema_type_obj: objpkg.KCLSchemaTypeObject, -) -> Set[str]: - """Get the required attributes from the schema type object""" - base_attribute_set = ( - get_schema_type_obj_required_attributes(schema_type_obj.base) - if schema_type_obj.base - else set() - ) - required_attribute_set = { - attr - for attr, attr_obj in schema_type_obj.attr_obj_map.items() - if attr != objpkg.SCHEMA_SETTINGS_ATTR_NAME and not attr_obj.is_optional - } - required_attribute_set.update(base_attribute_set) - return required_attribute_set - - -def kcl_decorator_to_pb_decorator(node: ast.Decorator) -> pb2.Decorator: - """Convert the decorator node to the protobuf decorator type.""" - - return pb2.Decorator( - name=node.name.get_name(), - arguments=[value_to_string(arg) for arg in node.args.args or [] if arg] - if node.args - else [], - keywords={ - keyword.arg.get_name(): value_to_string(keyword.value) - for keyword in node.args.keywords or [] - if keyword - } - if node.args - else {}, - ) - - -def value_to_string(node: ast.AST) -> str: - """AST value to string""" - if isinstance(node, ast.StringLit): - return node.value - else: - buffer = io.StringIO() - printer.PrintAST(node, out=buffer) - return buffer.getvalue() diff --git a/internal/kclvm_py/tools/list_attribute/utils.py b/internal/kclvm_py/tools/list_attribute/utils.py deleted file mode 100644 index 14ba360f8..000000000 --- a/internal/kclvm_py/tools/list_attribute/utils.py +++ /dev/null @@ -1,285 +0,0 @@ -import os -import glob -import pathlib -from io import StringIO -from typing import List, Dict, Optional -from dataclasses import dataclass - -import kclvm.compiler.parser.parser as parser -import kclvm.compiler.vfs as vfs -import kclvm.compiler.extension.plugin.plugin_model as plugin -import kclvm.compiler.extension.builtin.builtin as builtin -import kclvm.kcl.ast.ast as ast -import kclvm.kcl.info as kcl_info -import kclvm.tools.printer.printer as printer - - -@dataclass -class Config: - name_len: int = 30 - type_len: int = 30 - default_len: int = 30 - final_len: int = 10 - optional_len: int = 10 - - -def get_import_module( - module: ast.Module, result: Dict[str, ast.Module] = None -) -> Optional[Dict[str, ast.Module]]: - """Get all import module in a module.""" - if not module: - return None - assert isinstance(module, ast.Module) - if not result: - result = {} - import_file_list = [] - import_stmt_list = module.GetImportList() - work_dir = os.path.dirname(module.filename) - root: str = vfs.GetPkgRoot(work_dir) - if not root: - root = work_dir - for stmt in import_stmt_list or []: - if ( - stmt.path.startswith(plugin.PLUGIN_MODULE_NAME) - or stmt.name in builtin.STANDARD_SYSTEM_MODULES - ): - continue - # import_path to abs_path - fix_path = vfs.FixImportPath(root, module.filename, stmt.path).replace(".", "/") - abs_path = os.path.join(root, fix_path) - # Get all .k file if path is a folder - if os.path.isdir(abs_path): - file_glob = os.path.join(abs_path, "**", kcl_info.KCL_FILE_PATTERN) - import_file_list += glob.glob(file_glob, recursive=True) - else: - abs_path += kcl_info.KCL_FILE_SUFFIX - import_file_list.append(abs_path) - for file in import_file_list: - # Skip `_*.k` and `*_test.k` kcl files - if os.path.basename(file).startswith("_"): - continue - if file.endswith("_test.k"): - continue - if file not in result: - import_module = parser.ParseFile(file) - result[file] = import_module - if import_module.GetImportList(): - get_import_module(import_module, result) - return result - - -def get_import_schema( - module: ast.Module, -) -> Optional[Dict[ast.Module, List[ast.SchemaStmt]]]: - """Get all import schema in a module.""" - if not module: - return None - assert isinstance(module, ast.Module) - import_module_list = get_import_module(module).values() - import_schema_map = {m: m.GetSchemaList() for m in import_module_list} - return import_schema_map - - -class FullSchema(ast.SchemaStmt): - """ - Schema with base schema's attr. - todo: mixin attr - """ - - def __init__(self, schema: ast.SchemaStmt, module: ast.Module) -> None: - super().__init__(schema.line, schema.column) - self.self_schema = schema - self.parent_attr: Dict[str, List[ast.SchemaAttr]] = get_parent_attr_map( - schema, module, {} - ) - - def __str__(self): - s = self.self_schema.name + ", attr:[" - for name in self.self_schema.GetAttrNameList(): - s += f"{name}, " - s = s[:-2] + "]," - for p in self.parent_attr: - s += f" parent:{p}, attr:[" - for attr in self.parent_attr[p]: - s += f"{attr.name}, " - s = s[:-2] + "]," - - return s - - -def get_parent_attr_map( - ori_schema: ast.SchemaStmt, - module: ast.Module, - result: Dict[str, List[ast.SchemaAttr]] = None, -) -> Optional[Dict[str, List[ast.SchemaAttr]]]: - if not ori_schema or not module: - return None - assert isinstance(ori_schema, ast.SchemaStmt) - assert isinstance(module, ast.Module) - if not result: - result = {} - if not ori_schema.parent_name: - return result - else: - # Current module and schema. - full_schema_map: Dict[ast.Module, List[ast.SchemaStmt]] = { - module: module.GetSchemaList() - } - # Import module and schemas. - full_schema_map.update(get_import_schema(module)) - # key : module , value: List[ast.SchemaStmt] - for key, value in full_schema_map.items(): - for schema in value: - if schema.name == ori_schema.parent_name.get_name(): - result[schema.name] = schema.GetAttrList() - if schema.parent_name: - get_parent_attr_map(schema, key, result) - break - else: - continue - break - return result - - -def get_full_schema_list(module: ast.Module) -> List[FullSchema]: - """Get all FullSchema in a module""" - schema_list = module.GetSchemaList() - full_schema_list = [FullSchema(schema, module) for schema in schema_list] - return full_schema_list - - -class ListAttributePrinter: - def __init__(self, file: str = None, config: Config = Config()) -> None: - self.file = file - self.name_len = config.name_len - self.type_len = config.type_len - self.default_len = config.default_len - self.final_len = config.final_len - self.optional_len = config.optional_len - self.module = None - self.schema_list = None - self.import_schema_list = None - self.full_schema_list = None - - def build_full_schema_list(self): - self.module = parser.ParseFile(self.file) - self.schema_list = self.module.GetSchemaList() - self.import_schema_list = get_import_schema(self.module) - self.full_schema_list = get_full_schema_list(self.module) - - def print(self): - self.build_full_schema_list() - if self.module: - self.print_schema_list() - self.print_schema_structures() - - def print_schema_list(self): - print("------------ schema list ------------") - file_path = self.module.filename - file_name = pathlib.Path(file_path).name - print("Here are schemas defined in {}:".format(file_name)) - for schema in self.schema_list: - print("- " + schema.name) - print("Here are schemas imported to {}:".format(file_name)) - for key, value in self.import_schema_list.items(): - import_file_path = key.filename - import_file_name = pathlib.Path(import_file_path).name - if len(value) > 0: - print("imported from {}".format(import_file_name)) - for schema in value: - print("- " + schema.name) - - def print_schema_structures(self): - print("------------ schema structures ------------") - for full_schema in self.full_schema_list: - print("schema {}:".format(full_schema.self_schema.name)) - self.print_header() - for attr in full_schema.self_schema.GetAttrList(): - self.print_schema_attr(attr) - - for key, value in full_schema.parent_attr.items(): - print("attrs inherited from {}".format(key)) - for attr in value: - self.print_schema_attr(attr) - print() - - def _print_schema_attr(self, attr: ast.SchemaAttr, default: str): - print( - "{:<{}}{:<{}}{:<{}}{:<{}}{:<{}}".format( - # name - attr.name - if len(attr.name) <= self.name_len - else attr.name[: self.name_len - 3] + "...", - self.name_len, - # type - attr.type_str - if len(attr.type_str) <= self.type_len - else attr.type_str[: self.type_len - 3] + "...", - self.type_len, - # default - default, - self.default_len, - "", - self.final_len, - # is_optional - "" if attr.is_optional else "Required", - self.optional_len, - ) - ) - - def print_schema_attr(self, attr: ast.SchemaAttr): - if not attr: - return - assert isinstance(attr, ast.SchemaAttr) - if attr.value and isinstance(attr.value, ast.SchemaExpr): - """ - Because ast node SchemaExpr is too long to print, - when the default value of attr.value is a SchemaExpr,just print schema name,e.g.: - schema Name: - firstName : str - lastName : str - - schema Person: - name: Name = Name { - firstName = "hello" - lastName = "world" - } - ------------------------------------- - schema Person: - name type default ... - name Name -> Name{...} - """ - default = ( - attr.type_str - if len(attr.type_str) <= (self.default_len - 5) - else attr.type_str[: self.default_len - 5] - ) + "{...}" - self._print_schema_attr(attr, default) - return - with StringIO() as expr: - printer.PrintAST(attr.value, expr) - default_str = expr.getvalue() - if len(default_str) > self.default_len or ("\n" in default_str): - default_str = "..." - self._print_schema_attr(attr, default_str) - - def print_header(self): - print( - "{:<{}}{:<{}}{:<{}}{:<{}}{:<{}}".format( - # name - "name", - self.name_len, - # type - "type", - self.type_len, - # default - "default", - self.default_len, - # is_final - "is_final", - self.final_len, - # is_optional - "is_optional", - self.optional_len, - ) - ) diff --git a/internal/kclvm_py/tools/plugin/__init__.py b/internal/kclvm_py/tools/plugin/__init__.py deleted file mode 100644 index d74aaf8ad..000000000 --- a/internal/kclvm_py/tools/plugin/__init__.py +++ /dev/null @@ -1 +0,0 @@ -# Copyright 2021 The KCL Authors. All rights reserved. diff --git a/internal/kclvm_py/tools/plugin/__main__.py b/internal/kclvm_py/tools/plugin/__main__.py deleted file mode 100644 index 062472d78..000000000 --- a/internal/kclvm_py/tools/plugin/__main__.py +++ /dev/null @@ -1,5 +0,0 @@ -# Copyright 2021 The KCL Authors. All rights reserved. - -import kclvm.compiler.extension.plugin.main as main - -main.Main() diff --git a/internal/kclvm_py/tools/printer/__init__.py b/internal/kclvm_py/tools/printer/__init__.py deleted file mode 100644 index ffffacad3..000000000 --- a/internal/kclvm_py/tools/printer/__init__.py +++ /dev/null @@ -1,9 +0,0 @@ -from .printer import PrintAST, Config -from .splice import SchemaRuleCodeSnippet, splice_schema_with_rule - -__all__ = [ - "PrintAST", - "Config", - "SchemaRuleCodeSnippet", - "splice_schema_with_rule", -] diff --git a/internal/kclvm_py/tools/printer/printer.py b/internal/kclvm_py/tools/printer/printer.py deleted file mode 100644 index 3ee7b47e4..000000000 --- a/internal/kclvm_py/tools/printer/printer.py +++ /dev/null @@ -1,1290 +0,0 @@ -# Copyright 2021 The KCL Authors. All rights reserved. - -import io -import re -import sys -from enum import IntEnum -from dataclasses import dataclass -from typing import List, Dict, Union, Tuple, Optional - -import kclvm.kcl.ast as ast -import kclvm.compiler.astutil.fix as fix - -# --------------------------------------------------- -# Constants -# --------------------------------------------------- - - -class Indentation(IntEnum): - Indent = 0 - Dedent = 1 - Newline = 2 - IndentWithNewline = 3 - DedentWithNewline = 4 - Fill = 5 - - -_INVALID_AST_MSG = "Invalid AST Node" -_TEMP_ROOT = "" - -WHITESPACE = " " -TAB = "\t" -NEWLINE = "\n" -COMMA_WHITESPACE = ast.TokenValue.COMMA + WHITESPACE -IDENTIFIER_REGEX = r"^\$?[a-zA-Z_]\w*$" -QUANT_OP_TOKEN_VAL_MAPPING = { - ast.QuantOperation.ALL: ast.TokenValue.ALL, - ast.QuantOperation.ANY: ast.TokenValue.ANY, - ast.QuantOperation.MAP: ast.TokenValue.MAP, - ast.QuantOperation.FILTER: ast.TokenValue.FILTER, -} - -# --------------------------------------------------- -# Printer config -# --------------------------------------------------- - - -@dataclass -class Config: - tab_len: int = 4 - indent_len: int = 4 - use_spaces: bool = True - is_fix: bool = False - - -# --------------------------------------------------- -# Printer -# --------------------------------------------------- - - -class BasePrinter(ast.TreeWalker): - def __init__(self, config: Config, out: io.TextIOBase): - self.output: str = "" - self.indent = 0 - self.cfg: Config = config - self.out: io.TextIOBase = out - # Print comments - self.last_ast_line: int = 0 - self.comments: List[ast.Comment] = [] - self.import_spec: Dict[str, str] = {} - - # Base walker functions - - def get_node_name(self, t: ast.AST): - """Get the ast.AST node name""" - assert isinstance(t, ast.AST) - return t.type - - def generic_walk(self, t: ast.AST): - """Called if no explicit walker function exists for a node.""" - if not isinstance(t, ast.AST): - raise Exception(_INVALID_AST_MSG, t) - else: - self.walk(t) - - def write_ast_comments(self, t: ast.AST): - if not t or not isinstance(t, ast.AST): - return - if t.line and t.line > self.last_ast_line: - self.last_ast_line = t.line - if self.comments: - index = -1 - for i, comment in enumerate(self.comments): - if comment.line <= t.line: - index = i - self.write(comment.text + NEWLINE) - self.fill() - else: - break - if index >= 0: - del self.comments[: index + 1] - - # ----------------- - # Expr and Stmt walker functions - # ----------------- - - def expr(self, expr: ast.Expr): - if not expr: - return - self.write_ast_comments(expr) - self.generic_walk(expr) - - def stmt(self, stmt: ast.Stmt): - if not stmt: - return - self.fill() - self.write_ast_comments(stmt) - self.generic_walk(stmt) - - def stmts(self, stmts: List[ast.Stmt]): - for stmt in stmts or []: - self.stmt(stmt) - - def exprs(self, exprs: List[ast.Expr]): - for expr in exprs or []: - self.expr(expr) - - # -------------------------- - # Indent and scope functions - # -------------------------- - - def enter(self): - self.indent += 1 - - def leave(self): - self.indent -= 1 - - # -------------------------- - # Write functions - # -------------------------- - - @staticmethod - def interleave(inter, f, seq): - """Call f on each item in seq, calling inter() in between.""" - if not seq: - return - seq = iter(seq) - try: - f(next(seq)) - except StopIteration: - pass - else: - for x in seq: - inter() - f(x) - - def write(self, text: str = ""): - self.out.write(text) - - def writeln(self, text: str = ""): - self.write(text + NEWLINE) - self.fill() - - def write_with_spaces(self, text: str = ""): - self.write(" " + text + " ") - - def fill(self, text: str = ""): - """Indent a piece of text, according to the current indentation level""" - if self.cfg.use_spaces: - self.write(WHITESPACE * self.indent * self.cfg.indent_len + text) - else: - self.write(TAB * self.indent + text) - - def print(self, *values): - for value in values or []: - if isinstance(value, ast.Expr): - self.expr(value) - elif isinstance(value, ast.Stmt): - self.stmt(value) - elif isinstance(value, ast.AST): - self.generic_walk(value) - elif value == Indentation.Indent: - self.enter() - elif value == Indentation.Dedent: - self.leave() - elif value == Indentation.Newline: - self.writeln() - elif value == Indentation.IndentWithNewline: - self.enter() - self.writeln() - elif value == Indentation.DedentWithNewline: - self.leave() - self.writeln() - elif value == Indentation.Fill: - self.fill() - elif isinstance(value, str): - self.write(value) - elif isinstance(value, (int, float, bool)): - self.write(str(value)) - - def print_ast(self, t: ast.AST): - if not t: - return - if isinstance(t, ast.Module) and self.cfg.is_fix: - fix.fix_and_get_module_import_list( - _TEMP_ROOT, t, is_fix=True, reversed=True - ) - self.walk(t) - for comment in self.comments or []: - self.write(comment.text + NEWLINE) - self.fill() - - -class Printer(BasePrinter): - def __init__(self, config: Config, out: io.TextIOBase): - super().__init__(config, out) - - def walk_Module(self, t: ast.Module): - """ast.AST: Module - - Parameters - ---------- - - body: List[Stmt] - """ - assert isinstance(t, ast.Module) - self.comments = t.comments - self.stmts(t.body) - - def walk_ExprStmt(self, t: ast.ExprStmt): - """ast.AST: ExprStmt - - Parameters - ---------- - - exprs: List[Expr] - """ - assert isinstance(t, ast.ExprStmt) - self.interleave(lambda: self.write(COMMA_WHITESPACE), self.expr, t.exprs) - self.writeln() - - def walk_AssertStmt(self, t: ast.AssertStmt): - """ast.AST: AssertStmt - - Parameters - ---------- - - test: Expr - - if_cond: Expr - - msg: Expr - """ - assert isinstance(t, ast.AssertStmt) and t.test - self.print( - ast.TokenValue.ASSERT, - WHITESPACE, - t.test, - ) - if t.if_cond: - self.print(WHITESPACE, ast.TokenValue.IF, WHITESPACE, t.if_cond) - if t.msg: - self.print( - COMMA_WHITESPACE, - t.msg, - ) - self.print(NEWLINE) - - def walk_IfStmt(self, t: ast.IfStmt): - """ast.AST: IfStmt - - Parameters - ---------- - - cond: Expr - - body: List[Stmt] - - elif_cond: List[Expr] - - elif_body: List[List[Stmt]] - - else_body: List[Stmt] - """ - assert isinstance(t, ast.IfStmt) - assert t.cond - assert t.body - self.print( - ast.TokenValue.IF, - WHITESPACE, - t.cond, - ast.TokenValue.COLON, - NEWLINE, - Indentation.Indent, - ) - self.stmts(t.body) - self.print(Indentation.Dedent) - if t.elif_cond: - for cond, body in zip(t.elif_cond, t.elif_body): - self.print( - ast.TokenValue.ELIF, - WHITESPACE, - cond, - ast.TokenValue.COLON, - NEWLINE, - Indentation.Indent, - ) - self.stmts(body) - self.print(Indentation.Dedent) - if t.else_body: - self.print( - ast.TokenValue.ELSE, - ast.TokenValue.COLON, - NEWLINE, - Indentation.Indent, - ) - self.stmts(t.else_body) - self.print(Indentation.Dedent) - self.print(NEWLINE) - - def walk_ImportStmt(self, t: ast.ImportStmt): - """ast.AST: ImportStmt - - Parameters - --------- - - path: str - - name: str - - asname: str - """ - assert isinstance(t, ast.ImportStmt) - assert t.pkg_name - self.print( - ast.TokenValue.IMPORT, - WHITESPACE, - t.path, - ) - if t.asname: - self.print( - WHITESPACE, - ast.TokenValue.AS, - WHITESPACE, - t.asname, - ) - self.import_spec[t.path] = t.pkg_name - self.writeln() - - def walk_SchemaStmt(self, t: ast.SchemaStmt): - """ast.AST: SchemaStmt - - Parameters - ---------- - - doc: str - - name: str - - parent_name: Identifier - - is_mixin: bool - - is_protocol: bool - - args: Arguments - - settings: dict - - mixins: List[str] - - body: List[Union[SchemaAttr, Stmt]] - - decorators: List[Decorator] - - checks: List[CheckExpr] - - for_host_name: Optional[Identifier] = None - - index_signature: Optional[SchemaIndexSignature] = None - """ - assert isinstance(t, ast.SchemaStmt) - self.exprs(t.decorators) - tok = ast.TokenValue.SCHEMA - if t.is_mixin: - tok = ast.TokenValue.MIXIN - elif t.is_protocol: - tok = ast.TokenValue.PROTOCOL - self.print( - tok, - WHITESPACE, - ) - self.print(t.name) - if t.args: - self.print( - ast.TokenValue.LEFT_BRACKETS, - t.args, - ast.TokenValue.RIGHT_BRACKETS, - ) - if t.parent_name: - self.print( - ast.TokenValue.LEFT_PARENTHESES, - t.parent_name, - ast.TokenValue.RIGHT_PARENTHESES, - ) - if t.for_host_name: - self.print( - WHITESPACE, - ast.TokenValue.FOR, - WHITESPACE, - t.for_host_name, - ) - self.print( - ast.TokenValue.COLON, - NEWLINE, - Indentation.Indent, # Schema Stmt indent - ) - if t.doc: - self.print( - Indentation.Fill, - '"""', - t.doc.replace('"', '\\"'), - '"""', - NEWLINE, - ) - if t.mixins: - self.print( - Indentation.Fill, - ast.TokenValue.MIXIN, - WHITESPACE, - ast.TokenValue.LEFT_BRACKETS, - Indentation.IndentWithNewline, - ) - self.interleave( - lambda: self.print(ast.TokenValue.COMMA, Indentation.Newline), - self.print, - t.mixins, - ) - self.print( - Indentation.Dedent, - Indentation.Newline, - ast.TokenValue.RIGHT_BRACKETS, - NEWLINE, - ) - if t.index_signature: - self.print(t.index_signature) - self.print(NEWLINE) - self.stmts(t.body) - self.write(NEWLINE) - if t.checks: - self.print( - Indentation.Fill, - ast.TokenValue.CHECK, - ast.TokenValue.COLON, - Indentation.IndentWithNewline, # Schema check indent - ) - self.interleave( - lambda: self.print(Indentation.Newline), - self.print, - t.checks, - ) - self.write(NEWLINE) - # Schema check dedent - self.print(Indentation.Dedent) - self.write(NEWLINE) - # Schema Stmt dedent - self.print(Indentation.Dedent) - - def walk_SchemaIndexSignature(self, t: ast.SchemaIndexSignature): - """ast.AST: SchemaIndexSignature - - Parameters - ---------- - - key_name: Optional[str] - - key_type: Optional[str] - - value_type: Optional[str] - - value: Optional[Expr] - - any_other: bool - - name_node: Optional[Name] - - value_type_node: Optional[Type] - """ - self.write(ast.TokenValue.LEFT_BRACKETS) - if t.any_other: - self.write("...") - if t.key_name: - self.print( - t.key_name, - ast.TokenValue.COLON, - WHITESPACE, - ) - self.print( - t.key_type, - ast.TokenValue.RIGHT_BRACKETS, - ast.TokenValue.COLON, - WHITESPACE, - t.value_type, - ) - if t.value: - self.print(WHITESPACE, ast.TokenValue.ASSIGN, WHITESPACE, t.value) - - def walk_RuleStmt(self, t: ast.RuleStmt): - """ast.AST: RuleStmt - - Parameters - ---------- - self.doc: str = "" - self.name: str = "" - self.parent_rules: List[Identifier] = [] - self.decorators: List[Decorator] = [] - self.checks: List[CheckExpr] = [] - self.name_node: Optional[Name] = None - self.args: Optional[Arguments] = None - self.for_host_name: Optional[Identifier] = None - """ - assert isinstance(t, ast.RuleStmt) - self.exprs(t.decorators) - self.print( - ast.TokenValue.RULE, - WHITESPACE, - ) - self.print(t.name) - if t.args: - self.print( - ast.TokenValue.LEFT_BRACKETS, - t.args, - ast.TokenValue.RIGHT_BRACKETS, - ) - if t.parent_rules: - self.print(ast.TokenValue.LEFT_PARENTHESES) - self.interleave( - lambda: self.print(ast.TokenValue.COMMA, WHITESPACE), - self.print, - t.parent_rules, - ) - self.print(ast.TokenValue.RIGHT_PARENTHESES) - if t.for_host_name: - self.print( - WHITESPACE, - ast.TokenValue.FOR, - WHITESPACE, - t.for_host_name, - ) - self.print( - ast.TokenValue.COLON, - Indentation.IndentWithNewline, # Schema Stmt indent - ) - if t.doc: - self.print( - '"""', - t.doc.replace('"', '\\"'), - '"""', - Indentation.Newline, - ) - if t.checks: - self.interleave( - lambda: self.print(Indentation.Newline), - self.print, - t.checks, - ) - self.write(NEWLINE) - # Schema Stmt dedent - self.print(Indentation.Dedent) - - def walk_Decorator(self, t: ast.Decorator): - """ast.AST: Decorator - - Parameters - ---------- - - name: Optional[Identifier] - - args: Optional[CallExpr] - """ - assert isinstance(t, ast.Decorator) - self.print( - ast.TokenValue.AT, - t.name, - ) - if t.args: - self.print( - ast.TokenValue.LEFT_PARENTHESES, - t.args, - ast.TokenValue.RIGHT_PARENTHESES, - ) - self.writeln() - - def walk_Arguments(self, t: ast.Arguments): - """ast.AST: Arguments - - Parameters - ---------- - - args: List[Identifier] = [] - - type_annotation_list: List[str] = [] - - defaults: List[Expr] = [] - """ - assert isinstance(t, ast.Arguments) - - def write_argument( - para: Tuple[ast.Identifier, Optional[str], Optional[ast.Expr]] - ): - arg, type_str, default = para - self.print( - arg, - (": " + type_str) if type_str else "", - ) - if default: - self.print(WHITESPACE, ast.TokenValue.ASSIGN, WHITESPACE, default) - - self.interleave( - lambda: self.write(COMMA_WHITESPACE), - write_argument, - zip(t.args, t.type_annotation_list, t.defaults), - ) - - def walk_SchemaAttr(self, t: ast.SchemaAttr): - """ast.AST: SchemaAttr - - Parameters - ---------- - - doc: str - - name: str - - type_str: str - - is_optional: bool - - value: Expr - - decorators: List[Decorator] - - op: Union[AugOp, Assign] - """ - assert isinstance(t, ast.SchemaAttr) - self.exprs(t.decorators) - self.print( - t.name, - ast.TokenValue.QUESTION if t.is_optional else "", - ) - self.print(ast.TokenValue.COLON, WHITESPACE, t.type_str) - if t.op: - self.print( - WHITESPACE, - ast.OPERATOR_VALUE_MAP[t.op], - WHITESPACE, - t.value, - ) - self.write(NEWLINE) - - def walk_IfExpr(self, t: ast.IfExpr): - """ast.AST: IfExpr - - Parameters - ---------- - - cond: Expr - - body: Expr - - orelse: Expr - """ - assert isinstance(t, ast.IfExpr) - self.print( - t.body, - WHITESPACE, - ast.TokenValue.IF, - WHITESPACE, - t.cond, - WHITESPACE, - ast.TokenValue.ELSE, - WHITESPACE, - t.orelse, - ) - - def walk_UnaryExpr(self, t: ast.UnaryExpr): - """ast.AST: UnaryExpr(Expr) - - Parameters - ---------- - - op: UnaryOp - - operand: Expr - """ - assert isinstance(t, ast.UnaryExpr) - self.print( - ast.OPERATOR_VALUE_MAP[t.op], - t.operand, - ) - - def walk_BinaryExpr(self, t: ast.BinaryExpr): - """ast.AST: BinaryExpr - - Parameters - ---------- - - left: Expr - - right: Expr - - op: BinaryOperator - """ - assert isinstance(t, ast.BinaryExpr) and t.left and t.right and t.op - self.print( - t.left, - WHITESPACE, - ast.OPERATOR_VALUE_MAP[t.op], - WHITESPACE, - t.right, - ) - - def walk_SelectorExpr(self, t: ast.SelectorExpr): - """ast.AST: SelectorExpr - - Parameters - ---------- - - value: Expr - - attr: Identifier - - ctx: ExprContext - - has_question: bool - """ - assert isinstance(t, ast.SelectorExpr) - self.print( - t.value, - ast.TokenValue.QUESTION if t.has_question else "", - ast.TokenValue.DOT, - t.attr, - ) - - def walk_CallExpr(self, t: ast.CallExpr): - """ast.AST: CallExpr - - Parameters - ---------- - - func: Expr - - args: List[Expr] - - keywords: List[Keyword] - """ - assert isinstance(t, ast.CallExpr) - if t.func: - self.print( - t.func, - ast.TokenValue.LEFT_PARENTHESES, - ) - self.write_args_and_kwargs(t.args, t.keywords) - if t.func: - self.print( - ast.TokenValue.RIGHT_PARENTHESES, - ) - - def walk_ParenExpr(self, t: ast.ParenExpr): - """ast.AST: ParenExpr - - Parameters - ---------- - - expr: Expr - """ - assert isinstance(t, ast.ParenExpr) - self.print( - ast.TokenValue.LEFT_PARENTHESES, - t.expr, - ast.TokenValue.RIGHT_PARENTHESES, - ) - - def walk_ListExpr(self, t: ast.ListExpr): - """ast.AST: ListExpr - - Parameters - ---------- - - elts: List[Expr] - """ - assert isinstance(t, ast.ListExpr) - in_one_line = len(set(map(lambda e: e.line, t.elts)).union([t.line])) == 1 - self.write(ast.TokenValue.LEFT_BRACKETS) - if t.elts: - self.print(Indentation.IndentWithNewline if not in_one_line else "") - splits = COMMA_WHITESPACE if in_one_line else Indentation.Newline - self.interleave( - lambda: self.print(splits), - self.expr, - t.elts, - ) - self.print(Indentation.DedentWithNewline if not in_one_line else "") - self.write(ast.TokenValue.RIGHT_BRACKETS) - - def walk_StarredExpr(self, t: ast.StarredExpr): - assert isinstance(t, ast.StarredExpr) and t.value - self.print( - ast.TokenValue.MULTIPLY, - t.value, - ) - - def walk_ListComp(self, t: ast.ListComp): - """ast.AST: ListComp - - Parameters - ---------- - - elt: Expr - - generators: List[CompClause] - - targets: List[Expr] - - iter: Expr - - ifs: List[Expr] - """ - assert isinstance(t, ast.ListComp) - self.write(ast.TokenValue.LEFT_BRACKETS) - self.expr(t.elt) - for gen in t.generators: - self.expr(gen) - self.write(ast.TokenValue.RIGHT_BRACKETS) - - def walk_DictComp(self, t: ast.DictComp): - """ast.AST: DictComp - - Parameters - ---------- - - key: Expr - - value: Expr - - generators: List[CompClause] - """ - assert isinstance(t, ast.DictComp) - self.write(ast.TokenValue.LEFT_BRACE) - self.print( - t.key, - ast.TokenValue.COLON, - WHITESPACE, - t.value, - ) - for gen in t.generators: - self.expr(gen) - self.write(ast.TokenValue.RIGHT_BRACE) - - def walk_CompClause(self, t: ast.CompClause): - """ast.AST: CompClause - - Parameters - ---------- - - targets: List[Expr] - - iter: Expr - - ifs: List[Expr] - """ - assert isinstance(t, ast.CompClause) - self.write_with_spaces(ast.TokenValue.FOR) - self.interleave(lambda: self.write(COMMA_WHITESPACE), self.expr, t.targets) - self.write_with_spaces(ast.TokenValue.IN) - self.expr(t.iter) - for if_clause in t.ifs: - self.write_with_spaces(ast.TokenValue.IF) - self.expr(if_clause) - - def walk_QuantExpr(self, t: ast.QuantExpr): - """ast.AST: QuantExpr - - Parameters - ---------- - - target: Optional[Expr] = None - - variables: List[Identifier] = [] - - op: Optional[int] = None - - test: Optional[Expr] = None - - if_cond: Optional[Expr] = None - - ctx: ExprContext = ctx - """ - in_one_line = t.test.line == t.line - self.print( - QUANT_OP_TOKEN_VAL_MAPPING[t.op], - WHITESPACE, - ) - self.interleave(lambda: self.write(COMMA_WHITESPACE), self.expr, t.variables) - self.write_with_spaces(ast.TokenValue.IN) - self.expr(t.target) - self.write(WHITESPACE) - self.write(ast.TokenValue.LEFT_BRACE) - self.print(Indentation.IndentWithNewline if not in_one_line else "") - self.expr(t.test) - if t.if_cond: - self.print(WHITESPACE, ast.TokenValue.IF, WHITESPACE, t.if_cond) - self.print(Indentation.DedentWithNewline if not in_one_line else "") - self.write(ast.TokenValue.RIGHT_BRACE) - - def walk_Subscript(self, t: ast.Subscript): - """ast.AST: Subscript - - Parameters - ---------- - - value: Optional[Expr] = None - - index: Optional[Expr] = None - - lower: Optional[Expr] = None - - upper: Optional[Expr] = None - - step: Optional[Expr] = None - - ctx: ExprContext = ExprContext.LOAD - - has_question: bool = False - """ - assert isinstance(t, ast.Subscript) - self.print( - t.value, - ast.TokenValue.QUESTION if t.has_question else "", - ast.TokenValue.LEFT_BRACKETS, - ) - if t.index: - self.expr(t.index) - else: - self.print( - t.lower, - ast.TokenValue.COLON, - t.upper, - ast.TokenValue.COLON, - t.step, - ) - self.print(ast.TokenValue.RIGHT_BRACKETS) - - def walk_SchemaExpr(self, t: ast.SchemaExpr): - """ast.AST: SchemaExpr - - Parameters - ---------- - - name: Identifier - - config: ConfigExpr - - args: List[Expr] = [] - - kwargs: List[Keyword] = [] - """ - assert isinstance(t, ast.SchemaExpr) - self.print(t.name) - - if t.args or t.kwargs: - self.write(ast.TokenValue.LEFT_PARENTHESES) - self.write_args_and_kwargs(t.args, t.kwargs) - self.write(ast.TokenValue.RIGHT_PARENTHESES) - - self.print(WHITESPACE, t.config) - - def walk_ConfigExpr(self, t: ast.ConfigExpr): - """ast.AST: ConfigExpr - - Parameters - ---------- - - items: List[ConfigEntry] = [] - - key: Expr = key - - value: Expr = value - - operation: int = ConfigEntryOperation.UNION - - insert_index: Union[int, str] = -1 - """ - - def write_config_key(key: ast.AST) -> int: - """Write config key and return need right brace""" - if isinstance(key, ast.Identifier): - self.write_ast_comments(key) - names = key.names - # Judge contains string identifier, e.g., "x-y-z" - need_right_brace = not all( - [bool(re.match(IDENTIFIER_REGEX, n)) for n in names] - ) - if need_right_brace: - # a: {b: {c op value}} - self.print( - ": {".join( - ['"{}"'.format(n.replace('"', '\\"')) for n in names] - ) - ) - return len(names) - 1 - else: - # a.b.c op value - self.expr(key) - return 0 - else: - self.expr(key) - return 0 - - def write_item(item: ast.ConfigEntry): - if item.key is None: - # for dictionary unpacking operator in dicts {**{'y': 2}} - # see PEP 448 for details - if not isinstance(item.value, ast.ConfigIfEntryExpr): - self.print(ast.TokenValue.DOUBLE_STAR) - self.print(item.value) - else: - tok = ast.TokenValue.COLON - if item.operation == ast.ConfigEntryOperation.INSERT: - tok = ast.TokenValue.COMP_PLUS - elif item.operation == ast.ConfigEntryOperation.OVERRIDE: - tok = ast.TokenValue.ASSIGN - print_right_brace_count = write_config_key(item.key) - if item.insert_index is not None and item.insert_index >= 0: - self.print( - ast.TokenValue.LEFT_BRACKETS, - item.insert_index, - ast.TokenValue.RIGHT_BRACKETS, - ) - if tok != ast.TokenValue.COLON: - self.print(WHITESPACE) - self.print( - tok, - WHITESPACE, - item.value, - ) - self.print(ast.TokenValue.RIGHT_BRACE * (print_right_brace_count or 0)) - - in_one_line = len(set(map(lambda e: e.line, t.items)).union([t.line])) == 1 - self.write(ast.TokenValue.LEFT_BRACE) - if t.items: - self.print(Indentation.IndentWithNewline if not in_one_line else "") - self.interleave( - lambda: self.print(COMMA_WHITESPACE) if in_one_line else self.writeln(), - write_item, - t.items, - ) - self.print(Indentation.DedentWithNewline if not in_one_line else "") - self.write(ast.TokenValue.RIGHT_BRACE) - - def walk_CheckExpr(self, t: ast.CheckExpr): - """ast.AST: CheckExpr - - Parameters - ---------- - - test: Expr - - if_cond: Expr - - msg: Expr - """ - assert isinstance(t, ast.CheckExpr) and t.test - self.expr(t.test) - if t.if_cond: - self.print(WHITESPACE, ast.TokenValue.IF, WHITESPACE, t.if_cond) - if t.msg: - self.print( - COMMA_WHITESPACE, - t.msg, - ) - - def walk_LambdaExpr(self, t: ast.LambdaExpr): - """ast.AST: LambdaExpr - - Parameters - ---------- - - args: Optional[Arguments] - - return_type_str: Optional[str] - - return_type_node: Optional[Type] - - body: List[Stmt] - """ - self.print(ast.TokenValue.LAMBDA) - if t.args: - self.print( - WHITESPACE, - t.args, - ) - if t.return_type_str: - self.print( - WHITESPACE, - ast.TokenValue.RIGHT_ARROW, - WHITESPACE, - t.return_type_str, - ) - self.print( - WHITESPACE, - ast.TokenValue.LEFT_BRACE, - NEWLINE, - Indentation.Indent, - ) - self.stmts(t.body) - self.print( - Indentation.Dedent, - NEWLINE, - ast.TokenValue.RIGHT_BRACE, - ) - - def walk_Compare(self, t: ast.Compare): - """ast.AST: Compare - - Parameters - ---------- - - left: Optional[Expr] = None - - ops: List[CmpOp] = [] - - comparators: List[Expr] = [] - """ - assert isinstance(t, ast.Compare) - self.expr(t.left) - for op, expr in zip(t.ops, t.comparators): - self.print( - WHITESPACE, - ast.OPERATOR_VALUE_MAP[op], - WHITESPACE, - expr, - ) - - def walk_Identifier(self, t: ast.Identifier): - """ast.AST: Identifier - - Parameters - ---------- - - names: List[str] - """ - assert isinstance(t, ast.Identifier) and t.ctx - # Convert pkgpath qualified name to a normal identifier - if t.names[0].startswith("@"): - pkgpath = t.names[0][1:] - t.names[0] = self.import_spec.get(pkgpath) or pkgpath - self.write(t.get_name()) - - def walk_NumberLit(self, t: ast.AST): - """ast.AST: NumberLit - - Parameters - ---------- - - value: int - """ - assert isinstance(t, ast.NumberLit) - self.write(str(t.value)) - - def walk_StringLit(self, t: ast.StringLit): - """ast.AST: StringLit - - Parameters - ---------- - - value: str - - raw_value: str - - is_long_string = False - """ - assert isinstance(t, ast.StringLit) - self.write(t.raw_value or '"{}"'.format(t.value.replace('"', '\\"'))) - - def walk_NameConstantLit(self, t: ast.NameConstantLit): - """ast.AST: NameConstantLit - - Parameters - ---------- - - value - """ - assert isinstance(t, ast.NameConstantLit) - # None, Undefined, True, False - self.write(str(t.value)) - - def walk_JoinedString(self, t: ast.JoinedString): - """ast.AST: JoinedString - - Parameters - ---------- - - values: List[Union[Expr, StringLit]] - - TOS - --- - - format_spec - - formatted expr list - - Operand - ------- - Formatted expr list count - """ - assert isinstance(t, ast.JoinedString) - assert t.values - self.print('"') - for value in t.values: - if isinstance(value, ast.FormattedValue): - self.print( - "$", - ast.TokenValue.LEFT_BRACE, - value.value, - ) - if value.format_spec: - self.print( - ast.TokenValue.COLON, - WHITESPACE, - value.format_spec, - ) - self.print( - ast.TokenValue.RIGHT_BRACE, - ) - elif isinstance(value, ast.StringLit): - self.write(value.raw_value or '{}'.format(value.value.replace('"', '\\"'))) - elif isinstance(value, ast.Expr): - self.expr(value) - else: - raise Exception("Invalid AST JoinedString children") - self.print('"') - - def walk_TypeAliasStmt(self, t: ast.TypeAliasStmt): - """ast.AST: TypeAliasStmt - - Parameters - ---------- - - type_name: Identifier - - type_value: Type - """ - self.print( - ast.TokenValue.TYPE, - WHITESPACE, - t.type_name, - WHITESPACE, - ast.TokenValue.ASSIGN, - WHITESPACE, - t.type_value.plain_type_str, - NEWLINE, - ) - - def walk_UnificationStmt(self, t: ast.UnificationStmt): - """ast.AST: UnificationStmt - - Parameters - ---------- - - target: Identifier - - value: SchemaExpr - """ - self.print(t.target, ast.TokenValue.COLON, WHITESPACE, t.value, NEWLINE) - - def walk_AssignStmt(self, t: ast.AssignStmt): - """ast.AST: AssignStmt - - Parameters - ---------- - - targets: List[Identifier] - - value: Expr - """ - assert isinstance(t, ast.AssignStmt) and t.targets and t.value - for i, target in enumerate(t.targets): - self.print(target) - if i == 0 and t.type_annotation: - self.print(ast.TokenValue.COLON, WHITESPACE, t.type_annotation) - self.print(WHITESPACE, ast.TokenValue.ASSIGN, WHITESPACE) - self.print(t.value, NEWLINE) - if isinstance(t.value, ast.SchemaExpr): - self.print(NEWLINE) - - def walk_AugAssignStmt(self, t: ast.AugAssignStmt): - """ast.AST: AugAssignStmt - - Parameters - ---------- - - target: Identifier - - value: Expr - - op: AugOp - """ - assert isinstance(t, ast.AugAssignStmt) and t.target and t.value and t.op - self.print( - t.target, - WHITESPACE, - ast.OPERATOR_VALUE_MAP[t.op], - WHITESPACE, - t.value, - NEWLINE, - ) - - def write_args_and_kwargs(self, args: List[ast.Expr], keywords: List[ast.Keyword]): - def print_arg_assign_value(keyword: ast.Keyword): - self.print( - keyword.arg, - ast.TokenValue.ASSIGN, - keyword.value, - ) - - self.interleave(lambda: self.write(COMMA_WHITESPACE), self.expr, args) - if args and keywords: - self.print(COMMA_WHITESPACE) - self.interleave( - lambda: self.write(COMMA_WHITESPACE), print_arg_assign_value, keywords - ) - - def walk_ListIfItemExpr(self, t: ast.ListIfItemExpr): - assert isinstance(t, ast.ListIfItemExpr) - self.print( - ast.TokenValue.IF, - WHITESPACE, - t.if_cond, - ast.TokenValue.COLON, - Indentation.IndentWithNewline, - ) - self.interleave(lambda: self.print(NEWLINE), self.print, t.exprs) - self.print(Indentation.DedentWithNewline) - if t.orelse: - if isinstance(t.orelse, ast.ListIfItemExpr): - self.print("el") - self.expr(t.orelse) - elif isinstance(t.orelse, ast.ListExpr): - self.print( - ast.TokenValue.ELSE, - ast.TokenValue.COLON, - Indentation.IndentWithNewline, - ) - self.interleave(lambda: self.print(NEWLINE), self.print, t.orelse.elts) - self.print(Indentation.Dedent) - - def walk_ConfigIfEntryExpr(self, t: ast.ConfigIfEntryExpr): - assert isinstance(t, ast.ConfigIfEntryExpr) - self.print( - ast.TokenValue.IF, - WHITESPACE, - t.if_cond, - ast.TokenValue.COLON, - Indentation.IndentWithNewline, - ) - - def write_item(item): - key, value, operation = item - tok = ast.TokenValue.COLON - if operation == ast.ConfigEntryOperation.INSERT: - tok = ast.TokenValue.COMP_PLUS - elif operation == ast.ConfigEntryOperation.OVERRIDE: - tok = ast.TokenValue.ASSIGN - self.print(key) - if tok != ast.TokenValue.COLON: - self.print(WHITESPACE) - self.print( - tok, - WHITESPACE, - value, - ) - - self.interleave( - lambda: self.writeln(), - write_item, - zip(t.keys, t.values, t.operations), - ) - self.print(Indentation.DedentWithNewline) - if t.orelse: - if isinstance(t.orelse, ast.ConfigIfEntryExpr): - self.print("el") - self.expr(t.orelse) - elif isinstance(t.orelse, ast.ConfigExpr): - self.print( - ast.TokenValue.ELSE, - ast.TokenValue.COLON, - Indentation.IndentWithNewline, - ) - self.interleave( - lambda: self.print(Indentation.Newline), - write_item, - zip(t.orelse.keys, t.orelse.values, t.orelse.operations), - ) - self.print(Indentation.Dedent) - - -def PrintAST( - node: ast.AST, - out: Union[io.TextIOBase, io.StringIO] = sys.stdout, - config: Config = Config(), -): - """Print a KCL AST Module to `out` io with `config`""" - Printer(config, out).print_ast(node) diff --git a/internal/kclvm_py/tools/printer/splice.py b/internal/kclvm_py/tools/printer/splice.py deleted file mode 100644 index ba6669769..000000000 --- a/internal/kclvm_py/tools/printer/splice.py +++ /dev/null @@ -1,86 +0,0 @@ -# Copyright 2021 The KCL Authors. All rights reserved. - -import io -from dataclasses import dataclass -from typing import List - -import kclvm.kcl.ast as ast -import kclvm.compiler.parser as parser - -from .printer import PrintAST - - -NEWLINE = "\n" -MOCK_SCHEMA = "MockSchema" - - -@dataclass -class SchemaRuleCodeSnippet: - """Schema and rule code snippet structure""" - - schema: str = "" - rule: str = "" - - -def splice_schema_with_rule(code_snippets: List[SchemaRuleCodeSnippet]) -> str: - """Splice schema with rule code - - Returns a string result denoting the splicing code. - - Parameters - ---------- - code_snippets : List[SchemaRuleCodeSnippet] - A list of schema and rule code snippet structure - """ - if not isinstance(code_snippets, list): - raise ValueError(f"Invalid parameter {code_snippets}, expected list") - with io.StringIO() as buf: - for code in code_snippets: - if not code or not isinstance(code, SchemaRuleCodeSnippet): - raise ValueError( - f"Invalid parameter {code}, expected SchemaRuleCodeSnippet" - ) - module = parser.ParseFile( - ".k", code.schema, mode=parser.ParseMode.ParseComments - ) - module_schema_rule = parser.ParseFile( - ".k", - build_rule_check_block_str( - MOCK_SCHEMA, - code.rule, - ), - mode=parser.ParseMode.ParseComments, - ) - schema_rule_list = module_schema_rule.GetSchemaList() - if schema_rule_list: - for i, stmt in enumerate(module.body): - if isinstance(module.body[i], ast.SchemaStmt): - module.body[i].checks = schema_rule_list[0].checks - for comment in module_schema_rule.comments: - comment.line = module.body[i].end_line + 1 - module.comments.append(comment) - PrintAST(module, buf) - return buf.getvalue().rstrip(NEWLINE) + NEWLINE - - -def add_indent_to_code_string(code: str, indent: int = 4) -> str: - """Add indent to code string""" - if not code or not isinstance(code, str): - return "" - lines = code.split(NEWLINE) - return NEWLINE.join([" " * indent + line for line in lines]) - - -def build_rule_check_block_str(schema_name: str, rule_code: str) -> str: - """Build rule check block string using the rule code string""" - if not schema_name or not isinstance(rule_code, str): - return "" - if not rule_code or not isinstance(rule_code, str): - return "" - return ( - f"schema {schema_name}:" - + NEWLINE - + add_indent_to_code_string("check:", 4) - + NEWLINE - + add_indent_to_code_string(rule_code, 8) - ) diff --git a/internal/kclvm_py/tools/query/__init__.py b/internal/kclvm_py/tools/query/__init__.py deleted file mode 100644 index 45c094c9e..000000000 --- a/internal/kclvm_py/tools/query/__init__.py +++ /dev/null @@ -1,16 +0,0 @@ -from .override import ( - ApplyOverrides, - FixModuleOverride, - PrintOverridesAST, - OverrideInfo, - override_file, -) - - -__all__ = [ - "ApplyOverrides", - "FixModuleOverride", - "PrintOverridesAST", - "OverrideInfo", - "override_file", -] diff --git a/internal/kclvm_py/tools/query/override.py b/internal/kclvm_py/tools/query/override.py deleted file mode 100644 index 636381bc3..000000000 --- a/internal/kclvm_py/tools/query/override.py +++ /dev/null @@ -1,390 +0,0 @@ -# Copyright 2021 The KCL Authors. All rights reserved. - -import typing -import copy -import os -import pathlib -from dataclasses import dataclass - -import kclvm.kcl.ast as ast -import kclvm.kcl.types as types -import kclvm.kcl.error as kcl_error -import kclvm.unification as unification -import kclvm.compiler.astutil as astutil -import kclvm.compiler.parser as parser -from kclvm.tools.printer import PrintAST, Config -from kclvm.tools.format import kcl_fmt_file - - -KCL_FEATURE_GATE_OVERRIDE_AUTO_FIX_ENV = "KCL_FEATURE_GATE_OVERRIDE_AUTO_FIX" - - -@dataclass -class OverrideInfo: - pkgpath: str = None - filename: str = None - module: ast.Module = None - - # --------------- - # Static members - # --------------- - - MODIFIED = [] - - -class OverrideTransformer(ast.TreeTransformer): - def __init__( - self, - target_id: str, - field_path: str, - override_key: ast.Identifier, - override_value: ast.Literal, - override_action: ast.OverrideAction = ast.OverrideAction.CREATE_OR_UPDATE, - ): - super().__init__() - self.target_id: str = target_id - self.field_path: str = field_path - self.override_key: ast.Identifier = override_key - self.override_value: ast.Literal = override_value - self.override_target_count: int = 0 - self.has_override: bool = False - self.override_action: ast.OverrideAction = override_action - - def walk_UnificationStmt(self, t: ast.UnificationStmt): - """ast.AST: UnificationStmt - - Parameters - ---------- - - target: Identifier - - value: SchemaExpr - """ - name = t.target.names[0] - if name != self.target_id: - return t - self.override_target_count = 1 - self.has_override = True - self.walk(t.value) - return t - - def walk_AssignStmt(self, t: ast.AssignStmt): - if not isinstance(t.value, ast.SchemaExpr): - return t - self.override_target_count = 0 - for target in t.targets: - if not isinstance(target, ast.Identifier): - continue - assign_target = typing.cast(ast.Identifier, target) - if len(assign_target.names) != 1: - continue - if assign_target.names[0] != self.target_id: - continue - self.override_target_count = self.override_target_count + 1 - if self.override_target_count == 0: - return t - self.has_override = True - schema_expr_old: ast.SchemaExpr = copy.deepcopy(t.value) - schema_expr_new: ast.SchemaExpr = t.value - self.walk_SchemaExpr(schema_expr_new) - - if len(t.targets) == 1: - return t - - # Fix multiple assign - assign_stmt_list = [] - for target in t.targets: - x: ast.AssignStmt = copy.deepcopy(t) - x.targets = [target] - if len(target.names) == 1 and target.names[0] == self.target_id: - x.value = schema_expr_new - else: - x.value = schema_expr_old - assign_stmt_list.append(x) - return assign_stmt_list - - def walk_SchemaExpr(self, t: ast.SchemaExpr): - if self.override_target_count <= 0: - return t - if not self._find_schema_config_and_replace( - t, self.field_path, self.override_value - ): - # Not exist and append an override value when the action is CREATE_OR_UPDATE - if self.override_action == ast.OverrideAction.CREATE_OR_UPDATE: - t.config.items.append( - ast.ConfigEntry( - key=self.override_key, - value=self.override_value, - operation=ast.ConfigEntryOperation.OVERRIDE, - ) - ) - self.override_target_count = 0 - return t - - def walk_SchemaStmt(self, t: ast.SchemaStmt): - """Do not override AssignStmt in SchemaStmt""" - return t - - def _get_config_field_paths( - self, - config: typing.Union[ast.SchemaExpr, ast.ConfigExpr], - ) -> typing.Tuple[typing.List[str], typing.List[str]]: - def _get_key_value_paths( - key, value - ) -> typing.Tuple[typing.List[str], typing.List[str]]: - _paths, _paths_with_id = [], [] - if isinstance(key, ast.Identifier): - path = key.get_name() - elif isinstance(key, ast.StringLit): - path = key.value - else: - return _paths, _paths_with_id - _paths.append(f"{path}") - _paths_with_id.append(f"{path}") - value_paths, value_paths_with_id = self._get_config_field_paths(value) - if value_paths: - _paths.extend([f"{path}.{value_path}" for value_path in value_paths]) - _paths_with_id.extend( - [f"{path}|{value_path}" for value_path in value_paths_with_id] - ) - return _paths, _paths_with_id - - paths, paths_with_id = [], [] - if isinstance(config, ast.SchemaExpr): - for item in config.config.items: - _paths, _paths_with_id = _get_key_value_paths(item.key, item.value) - paths.extend(_paths) - paths_with_id.extend(_paths_with_id) - elif isinstance(config, ast.ConfigExpr): - for key, value in zip(config.keys, config.values): - _paths, _paths_with_id = _get_key_value_paths(key, value) - paths.extend(_paths) - paths_with_id.extend(_paths_with_id) - return paths, paths_with_id - - def _replace_with_id_path( - self, - schema_config: typing.Union[ast.SchemaExpr, ast.ConfigExpr], - path_with_id: str, - override_value: ast.Literal, - ) -> typing.Optional[ast.SchemaExpr]: - if not path_with_id or not schema_config: - return None - parts = path_with_id.split("|") - config = schema_config - - def _get_path_from_key(key: ast.AST) -> str: - path = "" - if isinstance(key, ast.Identifier): - path = key.get_name() - elif isinstance(key, ast.StringLit): - path = key.value - return path - - for i, part in enumerate(parts): - if isinstance(config, ast.SchemaExpr): - delete_index_list = [] - config_ref = config - for j, item in enumerate(config.config.items): - path = _get_path_from_key(item.key) - if path == part: - if self.override_action == ast.OverrideAction.CREATE_OR_UPDATE: - if i == len(parts) - 1: - override_value.set_ast_position(config) - item.value = override_value - config = item.value - elif self.override_action == ast.OverrideAction.DELETE: - delete_index_list.append(j) - continue - config_ref.config.items = [ - item - for j, item in enumerate(config_ref.config.items) - if j not in delete_index_list - ] - elif isinstance(config, ast.ConfigExpr): - key_value_pairs = zip(config.keys, config.values) - delete_index_list = [] - config_ref = config - for j, key_value in enumerate(key_value_pairs): - key, value = key_value - path = _get_path_from_key(key) - if path == part: - if self.override_action == ast.OverrideAction.CREATE_OR_UPDATE: - if i == len(parts) - 1: - override_value.set_ast_position(config) - config.items[j].value = override_value - config = value - elif self.override_action == ast.OverrideAction.DELETE: - delete_index_list.append(j) - continue - config_ref.items = [ - item - for j, item in enumerate(config_ref.items) - if j not in delete_index_list - ] - if override_value: - override_value.set_ast_position(config) - return schema_config - - def _find_schema_config_and_replace( - self, schema_config: ast.SchemaExpr, field_path: str, value: typing.Any - ) -> bool: - if not schema_config: - raise Exception("override schema config can't be None") - # Find field_path by nested identifier - paths, paths_with_id = self._get_config_field_paths(schema_config) - if field_path not in paths: - return False - path_with_id = paths_with_id[paths.index(field_path)] - self._replace_with_id_path(schema_config, path_with_id, value) - return True - - -def ApplyOverrides( - prog: ast.Program, - overrides: typing.List[ast.CmdOverrideSpec], - import_paths: typing.List[str] = None, -): - for override in overrides or []: - pkgpath = override.pkgpath if override.pkgpath else prog.main - if pkgpath in prog.pkgs: - for mx in prog.pkgs[pkgpath]: - if FixModuleOverride(mx, override): - OverrideInfo.MODIFIED.append( - OverrideInfo( - pkgpath=pkgpath, - filename=mx.GetFileName(root=prog.root), - module=mx, - ) - ) - ModuleAddImportPaths(mx, import_paths) - # Override type check and to auto fix - if os.getenv(KCL_FEATURE_GATE_OVERRIDE_AUTO_FIX_ENV): - types.ResolveProgram(prog, types.CheckConfig(config_attr_auto_fix=True)) - # Put AST module modified deepcopy - OverrideInfo.MODIFIED = [copy.deepcopy(m) for m in OverrideInfo.MODIFIED] - - -def PrintOverridesAST(): - """Print override AST program""" - if OverrideInfo.MODIFIED: - for value in OverrideInfo.MODIFIED: - with open(value.filename, "w") as f: - f.flush() - os.fsync(f.fileno()) - PrintAST(value.module, f, Config(is_fix=True)) - kcl_fmt_file(pathlib.Path(value.filename)) - - -def ModuleAddImportPaths( - m: ast.Module, import_paths: typing.List[str], ignore_exist: bool = False -) -> ast.Module: - """Add more import paths into the AST module.""" - if not import_paths: - return m - import_stmt_list = [] - exist_import_set = [stmt.path for stmt in m.GetImportList()] - line = 1 - for path in import_paths or []: - if not ignore_exist and path in exist_import_set: - continue - import_stmt = ast.ImportStmt(line, 1) - import_stmt.path = path - import_stmt.name = path.rsplit(".")[-1] - import_stmt_list.append(import_stmt) - line += 1 - m.body = import_stmt_list + m.body - - -def FixModuleOverride(m: ast.Module, override: ast.CmdOverrideSpec) -> bool: - assert m - assert override - - ss = override.field_path.split(".") - if len(ss) <= 1: - return False - - target_id: str = ss[0] - field: str = ".".join(ss[1:]) - value: str = override.field_value - - key = ast.Identifier(names=[s for s in field.split(".")], ctx=ast.ExprContext.STORE) - val = astutil.BuildNodeFromString(value) - - transformer = OverrideTransformer( - target_id, field, key, val, override_action=override.action - ) - transformer.walk(m) - return transformer.has_override - - -def override_file( - file: str, specs: typing.List[str], import_paths: typing.List[str] = None -) -> bool: - """Override and rewrite a file with override spec - - Parameters - ---------- - file: str - The File that need to be overridden - specs: List[str] - List of specs that need to be overridden. - Each spec string satisfies the form: := or :- - When the pkgpath is '__main__', it can be omitted. - - Return - ------ - result: bool - Whether override is successful - """ - overrides = [spec_str_to_override(spec) for spec in specs or []] - program = parser.LoadProgram( - file, - mode=parser.ParseMode.ParseComments, - load_packages=bool(os.getenv(KCL_FEATURE_GATE_OVERRIDE_AUTO_FIX_ENV)), - ) - # Config unification - program.pkgs[ast.Program.MAIN_PKGPATH] = unification.MergeASTList( - program.pkgs[ast.Program.MAIN_PKGPATH] - ) - OverrideInfo.MODIFIED = [] - ApplyOverrides(program, overrides, import_paths) - PrintOverridesAST() - return True - - -def spec_str_to_override(spec: str) -> ast.CmdOverrideSpec: - """Override spec string to override structure""" - - def report_exception(): - kcl_error.report_exception( - err_type=kcl_error.ErrType.IllegalArgumentError_TYPE, - arg_msg=f"Invalid spec format '{spec}', expected := or :-", - ) - - # Create or update the override value - if "=" in spec: - split_values = spec.split("=", 1) - paths = split_values[0].split(":", 1) - if len(split_values) < 2 or len(paths) > 2: - report_exception() - paths.append(split_values[1]) - paths = paths if len(paths) == 3 else ["", *paths] - return ast.CmdOverrideSpec( - pkgpath=paths[0], - field_path=paths[1], - field_value=paths[2], - action=ast.OverrideAction.CREATE_OR_UPDATE, - ) - # Delete the override value - elif spec.endswith("-"): - paths = spec[:-1].split(":", 1) - if len(paths) > 2: - report_exception() - paths = paths if len(paths) == 2 else ["", *paths] - return ast.CmdOverrideSpec( - pkgpath=paths[0], - field_path=paths[1], - field_value="", - action=ast.OverrideAction.DELETE, - ) - - report_exception() diff --git a/internal/kclvm_py/tools/validation/__init__.py b/internal/kclvm_py/tools/validation/__init__.py deleted file mode 100644 index 49f02dc27..000000000 --- a/internal/kclvm_py/tools/validation/__init__.py +++ /dev/null @@ -1,8 +0,0 @@ -# Copyright 2021 The KCL Authors. All rights reserved. - -from .validation import validate_code, validate_code_with_attr_data - -__all__ = [ - "validate_code", - "validate_code_with_attr_data", -] diff --git a/internal/kclvm_py/tools/validation/__main__.py b/internal/kclvm_py/tools/validation/__main__.py deleted file mode 100644 index 2a14735a7..000000000 --- a/internal/kclvm_py/tools/validation/__main__.py +++ /dev/null @@ -1,89 +0,0 @@ -# Copyright 2021 The KCL Authors. All rights reserved. - -import argparse -import sys -import pathlib - -import kclvm.kcl.error as kcl_error - -from .validation import validate_code - - -class ValidationMeta: - DATA_FILE_DESC = "Validation data file" - KCL_FILE_DESC = "KCL file" - FORMAT_DESC = "Validation data file format, support YAML and JSON" - - -def kcl_vet_main(): - """KCL validation CLI main function.""" - parser = argparse.ArgumentParser(prog="kcl-vet") - parser.add_argument( - "-d", - "--schema", - dest="schema", - metavar="schema", - type=str, - default=None, - required=False, - ) - parser.add_argument( - "--format", - dest="format", - metavar="format", - type=str, - default="json", - required=False, - help=ValidationMeta.FORMAT_DESC, - ) - parser.add_argument( - "-n", - "--attribute-name", - dest="attribute_name", - metavar="attribute_name", - type=str, - default="value", - required=False, - ) - parser.add_argument( - dest="data_file", - metavar="data_file", - type=str, - help=ValidationMeta.DATA_FILE_DESC, - ) - parser.add_argument( - dest="kcl_file", - metavar="kcl_file", - type=str, - help=ValidationMeta.KCL_FILE_DESC, - ) - args = parser.parse_args() - if len(sys.argv) == 1: - parser.print_help(sys.stdout) - sys.exit(0) - - data_str = pathlib.Path(args.data_file).read_text() - code_str = pathlib.Path(args.kcl_file).read_text() - - # Validate code - if validate_code( - data_str, code_str, args.schema, args.attribute_name, args.format, args.kcl_file - ): - print("Validate succuss!") - - -if __name__ == "__main__": - try: - kcl_vet_main() - except kcl_error.KCLException as err: - kcl_error.print_kcl_error_message(err, file=sys.stderr) - sys.exit(1) - except OSError as err: - kcl_error.print_common_error_message(err, file=sys.stderr) - sys.exit(1) - except AssertionError as err: - kcl_error.print_internal_error_message(err, file=sys.stderr) - raise - except Exception: - kcl_error.print_internal_error_message(file=sys.stderr) - raise diff --git a/internal/kclvm_py/tools/validation/validation.py b/internal/kclvm_py/tools/validation/validation.py deleted file mode 100644 index faef2d35e..000000000 --- a/internal/kclvm_py/tools/validation/validation.py +++ /dev/null @@ -1,214 +0,0 @@ -# Copyright 2021 The KCL Authors. All rights reserved. - -from typing import Optional, Any, List - -import kclvm.kcl.error as kcl_error -import kclvm.kcl.ast as ast -import kclvm.compiler.astutil as astutil -import kclvm.compiler.parser as parser -import kclvm.compiler.extension.builtin.system_module.json as json -import kclvm.compiler.extension.builtin.system_module.yaml as yaml -import kclvm.program.eval as eval - - -class ValidationMeta: - TEMP_FILE = "validationTempKCLCode.k" - - -class ValidationDataFormat: - """ - KCL validation data formats including yaml and json. - """ - - YAML: str = "yaml" - JSON: str = "json" - MAPPING = { - "YAML": yaml.KMANGLED_decode, - "JSON": json.KMANGLED_decode, - } - - -def validate_code( - data: str, - code: str, - schema: Optional[str] = None, - attribute_name: str = "value", - format: str = "json", - filename: str = None, -) -> bool: - """Validate the data string using the schema code string, when the parameter - `schema` is omitted, use the first scheam appeared in the code, when the schema - if not found, raise an schema not found error. - - Returns a bool result denoting whether validating success, raise an error - when validating failed because of the file not found error, schema not found - error, syntax error, check error, etc. - - Parameters - ---------- - data : str - A JSON or YAML data string. - code : str - A KCL code string. - schema : str - The schema name required for verification. - attribute_name : str - The validation attribute name, default is `value`. - format: str, default is "json" - The data format, suppored json, JSON, yaml and YAML. - filename: str, default is None - The filename of the KCL code. - - Examples - -------- - >>> data = '{"key": "value"}' # A JSON data string - >>> code = ''' - schema Person: - key: str - - check: - "value" in key # `key` is required and `key` must contain "value" - ''' - >>> validate_code(data, code) - True - - """ - check_validation_para(data, code, format) - # 1. Parse kcl code string to the AST module. - module = parser.ParseFile(filename=filename or ValidationMeta.TEMP_FILE, code=code) - schema_list = astutil.filter_stmt(module, ast.SchemaStmt) - # 2. Deserialize data str and covert it to a KCL AST node. - decoder = ValidationDataFormat.MAPPING.get(format.upper()) - value = decoder(data) - schema_name = schema or (schema_list[0].name if schema_list else None) - node_list = validate_value_to_ast_node_list(value, schema_name, attribute_name) - # 3. Insert the value AST node into the module and eval - module.body = node_list + module.body - eval.EvalAST(module) - return True - - -def validate_code_with_attr_data( - data: str, - code: str, - schema: Optional[str] = None, - format: str = "json", -) -> bool: - """Validate the data string using the schema code string, when the parameter - `schema` is omitted, use the first scheam appeared in the code, when the schema - if not found, raise an schema not found error. - - Returns a bool result denoting whether validating success, raise an error - when validating failed because of the file not found error, schema not found - error, syntax error, check error, etc. - - Parameters - ---------- - data : str - A JSON or YAML data string including the attribute key - code : str - A KCL code string. - schema : str - The schema name required for verification. - format: str, default is "json" - The data format, suppored json, JSON, yaml and YAML. - - Examples - -------- - >>> data = '{"attr": {"key": "value"}}' # A JSON data string including the attribute name - >>> code = ''' - schema Person: - key: str - - check: - "value" in key # `key` is required and `key` must contain "value" - ''' - >>> validate_code_with_attr_data(data, code) - True - """ - check_validation_para(data, code, format) - decoder = ValidationDataFormat.MAPPING.get(format.upper()) - value = decoder(data) - if not value or not isinstance(value, dict) or len(value) != 1: - raise ValueError( - f"Invalid parameter data: {data}, expected a dict with only one attribute" - ) - attribute_name = list(value.keys())[0] - data = json.KMANGLED_encode(value[attribute_name]) - return validate_code( - data=data, - code=code, - schema=schema, - attribute_name=attribute_name, - format=format, - ) - - -def check_validation_para(data: str, code: str, format: str): - if data is None or not isinstance(data, str): - raise ValueError(f"Invalid parameter data: {data}") - if code is None or not isinstance(code, str): - raise ValueError(f"Invalid parameter code: {code}") - if ( - format is None - or not isinstance(format, str) - or format.upper() not in ValidationDataFormat.MAPPING - ): - raise ValueError( - f"Invalid parameter format: {format}, expected one of {ValidationDataFormat.MAPPING.keys()}" - ) - - -def validate_value_to_ast_node_list( - value: Any, schema_name: str = None, attribute_name: str = "value" -) -> List[ast.AST]: - """Covert a validation value to a KCL AST node""" - - def build_assign_node(attribute_name: str, node: ast.AST) -> List[ast.AssignStmt]: - if not attribute_name: - raise ValueError(f"Invalid parameter attribute_name: {attribute_name}") - assign_stmt = ast.AssignStmt() - assign_stmt.value = node - assign_stmt.targets = [ - ast.Identifier( - names=[attribute_name], - ctx=ast.ExprContext.STORE, - ) - ] - return [assign_stmt] - - if isinstance(value, (int, float, bool, str, list, tuple, set, dict)): - node = value_to_ast(value, schema_name) - return build_assign_node(attribute_name, node) - else: - kcl_error.report_exception( - err_type=kcl_error.ErrType.CompileError_TYPE, - arg_msg=f"invalid validation data value {value}", - ) - - -def value_to_ast(value: Any, schema_name: Optional[str] = None) -> ast.AST: - node = None - if value is None: - node = ast.NameConstantLit(value=None) - elif isinstance(value, (list, tuple, set)): - node = ast.ListExpr() - node.elts = [value_to_ast(v, schema_name) for v in value] - elif isinstance(value, dict): - config = ast.ConfigExpr() - if schema_name: - node = ast.SchemaExpr() - node.name = ast.Identifier(names=[schema_name]) - node.config = config - else: - node = config - for k, v in value.items(): - config.items.append( - ast.ConfigEntry( - key=value_to_ast(k, schema_name), - value=value_to_ast(v), - ) - ) - elif isinstance(value, (bool, int, float, str)): - node = astutil.BuildLitNodeFromValue(value) - return node diff --git a/internal/kclvm_py/unification/__init__.py b/internal/kclvm_py/unification/__init__.py deleted file mode 100644 index fadee117b..000000000 --- a/internal/kclvm_py/unification/__init__.py +++ /dev/null @@ -1,15 +0,0 @@ -from .merge import MergeAST, MergeASTList, MergeASTToVertex, MergeStrategy -from .vertex import Vertex -from .unifier import Unifier -from .subsume import value_subsume, type_subsume - -__all__ = [ - "MergeASTList", - "MergeAST", - "MergeASTToVertex", - "MergeStrategy", - "Vertex", - "Unifier", - "value_subsume", - "type_subsume", -] diff --git a/internal/kclvm_py/unification/merge.py b/internal/kclvm_py/unification/merge.py deleted file mode 100644 index 4a930be5e..000000000 --- a/internal/kclvm_py/unification/merge.py +++ /dev/null @@ -1,342 +0,0 @@ -# Copyright 2021 The KCL Authors. All rights reserved. - -from dataclasses import dataclass -from abc import ABC, abstractmethod -from copy import deepcopy -from enum import IntEnum -from collections import defaultdict -from typing import Tuple, List, Optional, cast - -import kclvm.kcl.ast as ast -import kclvm.compiler.astutil as astutil - -from .vertex import Vertex -from .unifier import Unifier, UnifierConfig - - -INVALID_STRATEGY_MSG = "invalid strategy {}" - - -class BaseMerger(ABC): - def __init__(self, module: ast.Module): - self.module: ast.Module = module - - @abstractmethod - def merge(self) -> Tuple[Vertex, Vertex, ast.Module]: - raise NotImplementedError - - -@dataclass -class UnifyMerger(BaseMerger): - def __init__(self, module: ast.Module): - super().__init__(module) - - def unify_ast_module( - self, config: UnifierConfig = UnifierConfig() - ) -> Tuple[Optional[Vertex], Optional[Vertex], ast.Module]: - """Unify vertex according to the AST Module""" - if not self.module: - return None, None, self.module - vertex = Vertex.ast_to_vertex(self.module) - unify_vertex = Unifier(config).unify(vertex) - merged_module = cast(ast.Module, unify_vertex.vertex_to_ast()) - return vertex, unify_vertex, merged_module - - def merge(self) -> Tuple[Vertex, Vertex, ast.Module]: - """Merge the AST Module - - Input - ----- - None - - Output - ------ - vertex: Vertex formed by AST before merging - unify_vertex: Vertex formed by AST after merging - module: The merged AST - """ - vertex, unify_vertex, merged_module = self.unify_ast_module() - self.module = _deal_origin_ast_module(merged_module, self.module) - return vertex, unify_vertex, self.module - - -@dataclass -class UniqueUnifyMerger(UnifyMerger): - def __init__(self, module: ast.Module): - super().__init__(module) - - def merge(self) -> Tuple[Vertex, Vertex, ast.Module]: - """Merge the AST Module - - Input - ----- - None - - Output - ------ - vertex: Vertex formed by AST before merging - unify_vertex: Vertex formed by AST after merging - module: The merged AST - """ - vertex, unify_vertex, merged_module = self.unify_ast_module( - config=UnifierConfig(check_unique=True) - ) - self.module = _deal_origin_ast_module(merged_module, self.module) - return vertex, unify_vertex, self.module - - -@dataclass -class Overrider(UnifyMerger): - def __init__(self, module: ast.Module): - super().__init__(module) - - def merge(self) -> Tuple[Vertex, Vertex, ast.Module]: - vertex, unify_vertex, merged_module = self.unify_ast_module( - config=UnifierConfig(override=True) - ) - self.module = _deal_origin_ast_module(merged_module, self.module) - return vertex, unify_vertex, self.module - - -class MergeStrategy(IntEnum): - UNION = 1 # `:` - OVERRIDE = 2 # `=` - UNIQUE = 3 # `!` - - -class MergeStrategyFactory: - - MAPPING = { - MergeStrategy.UNION: UnifyMerger, - MergeStrategy.OVERRIDE: Overrider, - MergeStrategy.UNIQUE: UniqueUnifyMerger, - } - - @staticmethod - def get(strategy: MergeStrategy): - return MergeStrategyFactory.MAPPING.get(strategy, UnifyMerger) - - -def _deal_origin_ast_module( - merged_module: ast.Module, origin_module: ast.Module, all_visited: bool = False -) -> Optional[ast.Module]: - """Deal origin AST Module according to merged_module""" - if not merged_module or not isinstance(merged_module, ast.Module): - return None - merged_declaration_list = astutil.filter_declarations(merged_module, ast.SchemaExpr) - merged_declaration_map = defaultdict(list) - for d in merged_declaration_list: - d.value.filename = d.filename - merged_declaration_map[d.name].append(d.value) - merged_declaration_visited = {d.name: False for d in merged_declaration_list} - # Reverse traversal - origin_module.body = origin_module.body[::-1] - i = 0 - # TODO: Optimize the while loop using AST Transformer. - while i < len(origin_module.body): - stmt = origin_module.body[i] - if isinstance(stmt, ast.UnificationStmt): - target = stmt.target - name = target.get_first_name() - if name in merged_declaration_map: - del origin_module.body[i] - i -= 1 - values = merged_declaration_map[name] - if values and not merged_declaration_visited[name] and not all_visited: - identifier = ast.Identifier( - line=target.line, - column=target.column, - names=[name], - ctx=ast.ExprContext.STORE, - ) - identifier.pkgpath = target.pkgpath - identifier.filename = target.filename - identifier.end_line, identifier.end_column = ( - target.end_line, - target.end_column, - ) - insert_unification_stmt = ast.UnificationStmt( - line=stmt.line, column=stmt.column - ) - insert_unification_stmt.target = identifier - ( - insert_unification_stmt.end_line, - insert_unification_stmt.end_column, - ) = ( - stmt.end_line, - stmt.end_column, - ) - for value in values: - stmt_copy = deepcopy(insert_unification_stmt) - stmt_copy.value = value - stmt_copy.filename = value.filename - stmt_copy.line = value.line - stmt_copy.column = value.column - stmt_copy.end_line = value.end_line - stmt_copy.end_column = value.end_column - i += 1 - origin_module.body.insert(i, stmt_copy) - merged_declaration_visited[name] = True - elif isinstance(stmt, ast.AssignStmt) and isinstance( - stmt.value, ast.SchemaExpr - ): - if not stmt.targets: - del origin_module.body[i] - i -= 1 - j = 0 - while j < len(stmt.targets): - target = stmt.targets[j] - name = target.get_first_name() - if name in merged_declaration_map: - del stmt.targets[j] - j -= 1 - if len(stmt.targets) == 0: - del origin_module.body[i] - i -= 1 - values = merged_declaration_map[name] - if ( - values - and not merged_declaration_visited[name] - and not all_visited - ): - identifier = ast.Identifier( - line=target.line, - column=target.column, - names=[name], - ctx=ast.ExprContext.STORE, - ) - identifier.pkgpath = target.pkgpath - identifier.filename = target.filename - identifier.end_line, identifier.end_column = ( - target.end_line, - target.end_column, - ) - insert_assign_stmt = ast.AssignStmt( - line=stmt.line, column=stmt.column - ) - insert_assign_stmt.targets = [identifier] - insert_assign_stmt.end_line, insert_assign_stmt.end_column = ( - stmt.end_line, - stmt.end_column, - ) - for value in values: - stmt_copy = deepcopy(insert_assign_stmt) - stmt_copy.value = value - stmt_copy.filename = value.filename - stmt_copy.line = value.line - stmt_copy.column = value.column - stmt_copy.end_line = value.end_line - stmt_copy.end_column = value.end_column - i += 1 - origin_module.body.insert(i, stmt_copy) - merged_declaration_visited[name] = True - j += 1 - i += 1 - # Remove empty targets assignment - origin_module.body = [ - m - for m in reversed(origin_module.body) - if not isinstance(m, ast.AssignStmt) or m.targets - ] - return origin_module - - -def MergeASTList( - modules: List[ast.Module], strategy: MergeStrategy = MergeStrategy.UNION -) -> List[ast.Module]: - """Merge the configurations of the same name in the - AST Module list, and the ones that cannot be merged - will be handed over to the VM for calculation. - """ - if not modules or not isinstance(modules, list): - return [] - # AST module filename list - filenames = [m.filename for m in modules] - # Config need to be merged - file_configs = [ - stmt - for m in modules[1:] - for stmt in m.body - if (isinstance(stmt, ast.AssignStmt) and isinstance(stmt.value, ast.SchemaExpr)) - or isinstance(stmt, ast.UnificationStmt) - or isinstance(stmt, ast.ImportStmt) - ] - # Config filename meta - files_meta = [ - (m.filename, stmt.line, stmt.column, stmt.end_line, stmt.end_column) - for m in modules[1:] - for stmt in m.body - if (isinstance(stmt, ast.AssignStmt) and isinstance(stmt.value, ast.SchemaExpr)) - or isinstance(stmt, ast.UnificationStmt) - or isinstance(stmt, ast.ImportStmt) - ] - # Record the statement filename - for i, config in enumerate(file_configs): - ( - file_configs[i].filename, - file_configs[i].line, - file_configs[i].column, - file_configs[i].end_line, - file_configs[i].end_column, - ) = files_meta[i] - if not modules[0].body: - modules[0].body = [] - modules[0].body += file_configs - MergeAST(modules[0], strategy) - # Other file config list - file_configs = [ - stmt - for stmt in modules[0].body - if stmt.filename is not None - and stmt.filename != modules[0].filename - and not isinstance(stmt, ast.ImportStmt) - ] - # Origin module - modules[0].body = [stmt for stmt in modules[0].body if stmt not in file_configs] - # Filter all config except the first file - for i, _ in enumerate(modules[1:]): - modules[i + 1].body = [ - stmt - for stmt in modules[i + 1].body - if ( - not isinstance(stmt, ast.AssignStmt) - or not isinstance(stmt.value, ast.SchemaExpr) - ) - and not isinstance(stmt, ast.UnificationStmt) - ] - # Insert the merged configuration into different files - for config in file_configs: - index = filenames.index(config.filename) - line = config.line - insert_index = len(modules[index].body) - for i, stmt in enumerate(modules[index].body): - if stmt.line >= line: - insert_index = i - break - modules[index].body.insert(insert_index, config) - # Return the merged multi-file modules - return modules - - -def MergeAST( - module: ast.Module, strategy: MergeStrategy = MergeStrategy.UNION -) -> ast.Module: - """Merge the configurations of the same name in the single - AST module, and the ones that cannot be merged will be handed - over to the VM for calculation. - """ - _, _, merged_module = MergeASTToVertex(module, strategy) - return merged_module - - -def MergeASTToVertex( - module: ast.Module, strategy: MergeStrategy = MergeStrategy.UNION -) -> Tuple[Optional[Vertex], Optional[Vertex], ast.Module]: - """Merge the configurations of the same name in the AST and - return the merged vertices, and the ones that cannot be merged - will be handed over to the VM for calculation. - """ - if not module: - return None, None, module - merger = MergeStrategyFactory.get(strategy) - return merger(module).merge() diff --git a/internal/kclvm_py/unification/subsume.py b/internal/kclvm_py/unification/subsume.py deleted file mode 100644 index bf7cc6b68..000000000 --- a/internal/kclvm_py/unification/subsume.py +++ /dev/null @@ -1,161 +0,0 @@ -# Copyright 2021 The KCL Authors. All rights reserved. - -from typing import cast - -import kclvm.api.object as obj - - -def value_subsume( - value1: obj.KCLObject, value2: obj.KCLObject, should_recursive_check: bool = True -) -> bool: - """Calculate the partial order relationship between `KCL value objects` - and judge whether the value1 object ∈ the value2 object. - - Please note that The type and value of KCL are defined and used separately, - so the partial order relationship calculation is also divided into two types, - type and value, and there is no partial order relationship between type - objects and value objects. - """ - if not value1 or not value2: - return False - if not isinstance(value1, obj.KCLObject) or not isinstance(value2, obj.KCLObject): - return False - if value1 == value2 or value1 is value2: - return True - if isinstance(value1, (obj.KCLNoneObject, obj.KCLUndefinedObject)): - return True - if isinstance(value2, (obj.KCLNoneObject, obj.KCLUndefinedObject)): - return True - if isinstance(value1, obj.KCLIntObject): - return isinstance(value2, obj.KCLIntObject) and value1.value == value2.value - if isinstance(value1, obj.KCLFloatObject): - return isinstance(value2, obj.KCLFloatObject) and value1.value == value2.value - if isinstance(value1, obj.KCLNameConstantObject): - return ( - isinstance(value2, obj.KCLNameConstantObject) - and value1.value == value2.value - ) - if isinstance(value1, (obj.KCLListObject, obj.KCLTupleObject)): - return ( - isinstance(value2, (obj.KCLListObject, obj.KCLTupleObject)) - and len(value1.items) == len(value2.items) - and all( - [ - value_subsume(item1, item2, should_recursive_check) - for item1, item2 in zip(value1.items, value2.items) - ] - ) - ) - if isinstance(value1, (obj.KCLDictObject, obj.KCLSchemaObject)): - if isinstance(value2, (obj.KCLDictObject, obj.KCLSchemaObject)): - value1_dict = {k: value1.get(k) for k in sorted(list(value1.value.keys()))} - value2_dict = {k: value2.get(k) for k in sorted(list(value2.value.keys()))} - - if len(value1_dict) == 0: - return True - - if all([key not in value2_dict for key in value1_dict]): - return True - - if should_recursive_check: - for key1, value1 in value1_dict.items(): - if key1 not in value2_dict: - continue - value2 = value2_dict.get(key1) - if not value_subsume(value1, value2, should_recursive_check): - return False - return True - return False - - -def type_subsume( - value1: obj.KCLObject, value2: obj.KCLObject, check_left_any: bool = False -) -> bool: - """Calculate the partial order relationship between `KCL type objects` - and judge whether the value1 object ∈ the value2 object. - - Please note that The type and value of KCL are defined and used separately, - so the partial order relationship calculation is also divided into two types, - type and value, and there is no partial order relationship between type - objects and value objects. - """ - if not value1 or not value2: - return False - if not isinstance(value1, obj.KCLObject) or not isinstance(value2, obj.KCLObject): - return False - if value1 == value2 or value1 is value2: - return True - if check_left_any and isinstance(value1, obj.KCLAnyTypeObject): - return True - if isinstance(value2, obj.KCLAnyTypeObject): - return True - if isinstance(value1, obj.KCLNoneTypeObject): - return True - if isinstance(value1, obj.KCLUnionTypeObject): - return all([type_subsume(tpe, value2) for tpe in value1.types]) - if isinstance(value2, obj.KCLUnionTypeObject): - return any([type_subsume(value1, tpe) for tpe in value2.types]) - if isinstance(value1, obj.KCLSchemaTypeObject): - if not isinstance(value2, obj.KCLSchemaTypeObject): - return False - value1 = cast(obj.KCLSchemaTypeObject, value1) - value2 = cast(obj.KCLSchemaTypeObject, value2) - return value1.is_sub_schema_of(value2) - if isinstance(value1, obj.KCLIntTypeObject) and isinstance( - value2, obj.KCLFloatTypeObject - ): - return True - if isinstance(value1, obj.KCLBuiltinTypeObject): - return ( - isinstance(value2, obj.KCLBuiltinTypeObject) - and value1.type_kind() == value2.type_kind() - ) - if isinstance( - value1, - ( - obj.KCLStringLitTypeObject, - obj.KCLNumberLitTypeObject, - obj.KCLBoolLitTypeObject, - ), - ): - if isinstance( - value2, - ( - obj.KCLStringLitTypeObject, - obj.KCLNumberLitTypeObject, - obj.KCLBoolLitTypeObject, - ), - ): - return ( - value1.type_kind() == value2.type_kind() - and value1.value == value2.value - ) - elif isinstance(value2, obj.KCLBuiltinTypeObject): - # float_lit -> float - # int_lit -> int - # bool_lit -> bool - # str_lit -> str - # int_lit/bool_lit -> float - if isinstance(value2, obj.KCLFloatTypeObject) and not isinstance( - value1, obj.KCLStringLitTypeObject - ): - return True - return value2.type_str() in value1.type_str() - if isinstance(value1, obj.KCLListTypeObject): - return isinstance(value2, obj.KCLListTypeObject) and type_subsume( - value1.item_type, value2.item_type, check_left_any - ) - if isinstance(value1, obj.KCLDictTypeObject): - return ( - isinstance(value2, obj.KCLDictTypeObject) - and type_subsume(value1.key_type, value2.key_type, check_left_any) - and type_subsume(value1.value_type, value2.value_type, check_left_any) - ) - if isinstance(value1, obj.KCLNumberMultiplierTypeObject) and isinstance( - value2, obj.KCLNumberMultiplierTypeObject - ): - if value1.is_literal(): - return not value2.is_literal() and value1.type_str() == value2.type_str() - else: - return True - return False diff --git a/internal/kclvm_py/unification/unifier.py b/internal/kclvm_py/unification/unifier.py deleted file mode 100644 index 8e7fe0e48..000000000 --- a/internal/kclvm_py/unification/unifier.py +++ /dev/null @@ -1,118 +0,0 @@ -# Copyright 2021 The KCL Authors. All rights reserved. - -from typing import List -from dataclasses import dataclass -from collections import defaultdict - -import kclvm.kcl.error as kcl_error - -from .vertex import Vertex - - -NAME_NONE_BUCKET_KEY = "$name_none" - - -@dataclass -class UnifierConfig: - """The vertex unification config""" - - check_unique: bool = False - override: bool = False - - -class Unifier: - def __init__(self, config: UnifierConfig = UnifierConfig()): - self.config: UnifierConfig = config - - def unify(self, vertex: Vertex) -> Vertex: - """The vertex unification function""" - if not vertex or not isinstance(vertex, Vertex): - return vertex - # Using bucket map to check unique/merge option and store values - bucket = defaultdict(list) - for v in vertex.adjs or []: - self.append_vertex_into_bucket(bucket, v) - # Using the following configuration meta (filename/line/column) with the same name - # to override the previous configuration e.g., `stack config -> base config` - for k, v_list in bucket.items(): - if v_list: - for j in range(len(v_list)): - v_list[j].meta = v_list[-1].meta - # Merge vertices in the vertex list the with the same name - bucket[k] = self.merge_vertices(v_list) - # Merge the vertex adjs - vertex.adjs = sum(bucket.values(), []) - return vertex - - def merge_vertices(self, vertices: List[Vertex]) -> List[Vertex]: - """Merge a vertex list with same names""" - if not vertices or not isinstance(vertices, list): - return [] - vertex_list = [] - # Merge all adjs in vertex with the same name, - # if the adjs is None, append it into the vertex list - total_adjs = sum([v.adjs or [] for v in vertices], []) - is_unified = False - meta_names = [] - for v in vertices: - # If there are vertices in the list without adjs, they may have the - # conflict values and put them into the vertex list - # and deal the value conflict in VM - if v.adjs is None and v.node: - vertex_list.append(v) - elif not is_unified: - v.adjs = total_adjs - vertex_list.append(self.unify(v)) - is_unified = True - if v.config_meta.name and v.config_meta.name not in meta_names: - if v.option.is_override: - meta_names = [v.config_meta.name] - else: - meta_names.append(v.config_meta.name) - if len(meta_names) >= 2 and v.option.is_union: - kcl_error.report_exception( - err_type=kcl_error.ErrType.CompileError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=v.meta.filename, - line_no=v.meta.line, - col_no=v.meta.column, - ) - ], - arg_msg=f"conflict unification types between {meta_names[-1]} and {meta_names[0]}", - ) - # Return the merged the vertex list - return vertex_list - - def append_vertex_into_bucket(self, bucket: dict, v: Vertex): - """Append the vertex into the bucket map with unique and override option""" - if not isinstance(bucket, dict) or not isinstance(v, Vertex): - return - # Check unique key error - if self.config.check_unique and len(bucket[v.name]) > 1 and v.option.is_unique: - kcl_error.report_exception( - err_type=kcl_error.ErrType.CompileError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=v.meta.filename, - line_no=v.node.line, - col_no=v.node.column, - end_col_no=v.node.end_column, - ) - ], - arg_msg=f"config of '{v.name}' must be unique", - ) - # Put the different value into the bucket with the same `name`. - # Please note that then the vertex key is a runtime variable - # such as string interpolation, the name is None e.g., `{"${name}": "Alice"}` - # else the name is the key name such as `name` in `{"name": "Alice"}` - if v.name is not None: - # Override the value in the bucket - if self.config.override: - bucket[v.name] = [v] - # Append the multiple values into the bucket and calculate these values in VM - else: - bucket[v.name].append(v) - # Store the name none node including unpack expression and collection if expression - else: - bucket[NAME_NONE_BUCKET_KEY].append(v) diff --git a/internal/kclvm_py/unification/vertex.py b/internal/kclvm_py/unification/vertex.py deleted file mode 100644 index 87700686a..000000000 --- a/internal/kclvm_py/unification/vertex.py +++ /dev/null @@ -1,420 +0,0 @@ -# Copyright 2021 The KCL Authors. All rights reserved. - -from io import StringIO -from dataclasses import dataclass -from typing import cast, List, Optional, Union - -import kclvm.kcl.ast as ast -import kclvm.compiler.astutil as astutil - - -VERTEX_ROOT_NAME = "@root" - - -@dataclass -class Meta: - """The filename, line and column info""" - - filename: Optional[str] = None - line: Optional[int] = None - column: Optional[int] = None - end_line: Optional[int] = None - end_column: Optional[int] = None - - @staticmethod - def from_ast_node(node: ast.AST) -> "Meta": - return ( - Meta( - filename=node.filename, - line=node.line, - column=node.column, - end_line=node.end_line, - end_column=node.end_column, - ) - if node and isinstance(node, ast.AST) - else Meta() - ) - - -@dataclass -class ConfigMeta: - """The schema config name, args and kwargs AST node references""" - - name: str = None - pkgpath: str = None - args: List[ast.Expr] = None - kwargs: List[ast.Keyword] = None - - -@dataclass -class VertexOption: - """The vertex unification options""" - - is_union: bool = False # `:` - is_override: bool = False # `=` - is_append: bool = False # `+=` - is_unique: bool = False # `!` - is_strategy_merge: bool = False # `?` - - -@dataclass -class Vertex: - """ - Parameters - ---------- - name: Union[int, float, str, ast.AST] - Vertex node name. When the name is a variable needed to be calculated in VM, - it is a AST type - adjs: List["Vertex"] - The list of downstream nodes of the vertex - node: ast.AST - The AST node reference - meta: Mate - The filename, line and column info - config_meta: ConfigMeta: - The schema config name, args and kwargs AST node references - option: - The vertex unification options - - Methods - ------- - vertex_to_ast: - Vertex -> AST - ast_to_vertex: - AST -> Vertex - """ - - name: Union[int, float, str, ast.AST] - adjs: Optional[List["Vertex"]] - node: ast.AST = None - meta: Optional[Meta] = Meta() - config_meta: Optional[ConfigMeta] = ConfigMeta() - option: Optional[VertexOption] = VertexOption() - - # --------------- - # Member method - # --------------- - - def pretty(self, indent: int = 1) -> str: - """Pretty print to show the vertex structure""" - with StringIO() as buf: - buf.write("name: " + str(self.name) + "\n") - buf.write("is_unique: " + str(self.option.is_unique) + "\n") - if self.config_meta.name: - buf.write("config_name: " + self.config_meta.name + "\n") - if self.adjs: - buf.write("adjs: \n") - for v in self.adjs: - lines = v.pretty(indent).split("\n") - buf.write( - "\n".join([" " * indent * 4 + line for line in lines]) + "\n" - ) - else: - buf.write("value: " + str(self.node)) - return buf.getvalue().rstrip(" \n") + "\n" - - def vertex_to_ast(self) -> Optional[ast.AST]: - """Vertex to KCL AST""" - - def append_config_key_value( - t: Union[ast.SchemaExpr, ast.ConfigExpr], - key: Union[int, float, str, Optional[ast.AST]], - value: ast.AST, - op: int = ast.ConfigEntryOperation.UNION, - meta: Meta = Meta(), - ): - if isinstance(t, ast.SchemaExpr): - if not t.config: - t.config = ast.ConfigExpr(line=t.line, column=t.column) - t.config.filename = meta.filename - if not t.config.items: - t.config.items = [] - # If `key` is None, it may be a double star expr - key_node = None - if key and isinstance(key, ast.AST): - key_node = key - elif isinstance(key, str): - key_node = ast.Identifier( - line=meta.line, column=meta.column, names=[key] - ).set_filename(meta.filename) - key_node.end_line, key_node.end_column = ( - meta.end_line, - meta.end_column, - ) - elif isinstance(key, (int, float)): - key_node = ast.NumberLit( - line=meta.line, column=meta.column, value=key - ) - key_node.end_line, key_node.end_column = ( - meta.end_line, - meta.end_column, - ) - if isinstance(key_node, ast.AST): - key_node.filename = meta.filename - value = cast(ast.Expr, value) - t.config.items.append( - ast.ConfigEntry( - key=key_node, - value=value, - operation=op, - ) - ) - elif isinstance(t, ast.ConfigExpr): - if not t.items: - t.items = [] - # If `key` is None, it may be a double star expr - key_node = None - if key and isinstance(key, ast.AST): - key_node = key - elif isinstance(key, str): - key_node = ast.StringLit( - line=meta.line, column=meta.column, value=key - ) - key_node.end_line, key_node.end_column = ( - meta.end_line, - meta.end_column, - ) - elif isinstance(key, (int, float)): - key_node = ast.NumberLit( - line=meta.line, column=meta.column, value=key - ) - key_node.end_line, key_node.end_column = ( - meta.end_line, - meta.end_column, - ) - if isinstance(key_node, ast.AST): - key_node.filename = meta.filename - key_node = cast(ast.Expr, key_node) - t.items.append( - ast.ConfigEntry( - key=key_node, - value=value, - operation=op, - ) - ) - - # Get root vertex - if isinstance(self.name, str) and self.name == VERTEX_ROOT_NAME: - module = ast.Module(filename=self.meta.filename, line=1, column=1) - for v in self.adjs: - assign_stmt = ast.AssignStmt( - line=v.meta.line, - column=v.meta.column, - ) - assign_stmt.targets = [ - ast.Identifier( - line=v.node.line, - column=v.node.column, - names=[v.name], - ctx=ast.ExprContext.STORE, - ).set_filename(v.node.filename) - ] - assign_stmt.end_line = v.meta.end_line - assign_stmt.end_column = v.meta.end_column - assign_stmt.value = v.vertex_to_ast() - assign_stmt.filename = v.meta.filename - module.body.append(assign_stmt) - return module - # Get normal vertex such as in the right assignment - else: - # SchemaExpr config - if self.config_meta.name: - config_expr = ast.SchemaExpr( - line=self.meta.line, - column=self.meta.column, - ) - name = ast.Identifier( - line=self.meta.line, - column=self.meta.column, - names=self.config_meta.name.split("."), - ).set_filename(self.meta.filename) - name.end_line, name.end_column = ( - self.meta.end_line, - self.meta.end_column, - ) - config_expr.name = name - config_expr.name.pkgpath = self.config_meta.pkgpath - config_expr.args = self.config_meta.args - config_expr.kwargs = self.config_meta.kwargs - # ConfigExpr config - else: - config_expr = ast.ConfigExpr( - line=self.meta.line, - column=self.meta.column, - ) - config_expr.end_line, config_expr.end_column = ( - self.meta.end_line, - self.meta.end_column, - ) - if self.adjs: - for vv in self.adjs: - op = ast.ConfigEntryOperation.UNION - op = ( - ast.ConfigEntryOperation.OVERRIDE - if vv.option.is_override - else op - ) - op = ast.ConfigEntryOperation.INSERT if vv.option.is_append else op - if vv.adjs: - append_config_key_value( - config_expr, vv.name, vv.vertex_to_ast(), op, vv.meta - ) - elif vv.node: - append_config_key_value( - config_expr, vv.name, vv.node, op, vv.meta - ) - return config_expr - elif self.node: - return self.node - return None - - # --------------- - # Static method - # --------------- - - @staticmethod - def update_vertex_option(v: "Vertex", op: int): - """Update the vertex option using the schema config operation""" - if not isinstance(v, Vertex): - return - v.option = VertexOption( - is_override=op == ast.ConfigEntryOperation.OVERRIDE, - is_append=op == ast.ConfigEntryOperation.INSERT, - is_union=op == ast.ConfigEntryOperation.UNION, - ) - - @staticmethod - def ast_to_vertex( - t: ast.AST, - name: Optional[Union[int, float, str, ast.AST]] = None, - is_in_schema: bool = False, - ) -> Optional["Vertex"]: - """Build a vertex from AST""" - if not t or not isinstance(t, ast.AST): - return None - if isinstance(t, ast.Module): - t = cast(ast.Module, t) - root = Vertex.new_root( - node=t, - adjs=[], - ) - declarations = astutil.filter_declarations(t) - for d in declarations: - if "." not in d.name: - vertex = Vertex.ast_to_vertex(d.value, d.name) - vertex.meta.filename = d.filename - vertex.option.is_union = d.is_union - root.adjs.append(vertex) - return root - elif isinstance(t, ast.SchemaExpr): - vertex = Vertex.ast_to_vertex(t.config, name, True) - vertex.meta = Meta.from_ast_node(t) - vertex.name = name - vertex.config_meta = ConfigMeta( - name=t.name.get_name(), - pkgpath=t.name.pkgpath, - args=t.args, - kwargs=t.kwargs, - ) - if not vertex.adjs and isinstance(vertex.node, ast.ConfigExpr): - vertex.node = t - return vertex - elif isinstance(t, ast.ConfigExpr): - vertex = Vertex( - node=t, - name=name, - adjs=[], - meta=Meta.from_ast_node(t), - ) - for key, value, operation in zip( - t.keys, - t.values, - t.operations - if isinstance(t, ast.ConfigExpr) - else [ast.ConfigEntryOperation.UNION] * len(t.keys), - ): - # Double star expression - if not key: - value_vertex = Vertex.ast_to_vertex( - value, name=None, is_in_schema=is_in_schema - ) - value_vertex.node = value - value_vertex.meta = Meta.from_ast_node(value) - Vertex.update_vertex_option(value_vertex, operation) - vertex.adjs.append(value_vertex) - elif isinstance(key, ast.Identifier) and ( - isinstance(t, ast.ConfigExpr) or is_in_schema - ): - nest_key_len = len(key.names) - nest_vertex_list = [ - Vertex( - name=key.names[i], - node=key, - adjs=[], - meta=Meta.from_ast_node(key), - ) - for i in range(nest_key_len - 1) - ] - final_vertex = Vertex.ast_to_vertex( - value, name=key.names[-1], is_in_schema=is_in_schema - ) - final_vertex.meta = Meta.from_ast_node(key) - if nest_key_len > 1: - # Link all vertex in nest vertex list - for i in range(nest_key_len - 2): - nest_vertex_list[i].adjs = [nest_vertex_list[i + 1]] - nest_vertex_list[-1].adjs = [final_vertex] - value_vertex = ( - final_vertex if nest_key_len == 1 else nest_vertex_list[0] - ) - value_vertex.meta = Meta.from_ast_node(key) - if isinstance(value, ast.SchemaExpr): - value_vertex.config_meta = ConfigMeta( - name=value.name.get_name(), - args=value.args, - kwargs=value.kwargs, - ) - Vertex.update_vertex_option( - value_vertex, ast.ConfigEntryOperation.UNION - ) - Vertex.update_vertex_option(final_vertex, operation) - vertex.adjs.append(value_vertex) - else: - # Variable attributes that cannot be clearly expressed - # Such as string interpolation which denotes a runtime value - value_vertex = Vertex.ast_to_vertex( - value, - name=key.value - if isinstance(key, (ast.StringLit, ast.NumberLit)) - else key, - is_in_schema=is_in_schema, - ) - value_vertex.meta = Meta.from_ast_node(key) - Vertex.update_vertex_option(value_vertex, operation) - vertex.adjs.append(value_vertex) - return vertex - # Vertex end node and its adjs is None - return Vertex( - name=name, - node=t, - adjs=None, - meta=Meta.from_ast_node(t), - ) - - @staticmethod - def new_root( - node: ast.Module = None, adjs: Optional[List["Vertex"]] = None - ) -> "Vertex": - """New a empty vertex root node""" - return Vertex( - name=VERTEX_ROOT_NAME, - node=node, - adjs=adjs, - meta=Meta( - filename=node.filename, - line=1, - column=1, - end_line=1, - end_column=1, - ), - ) diff --git a/internal/kclvm_py/vm/__init__.py b/internal/kclvm_py/vm/__init__.py deleted file mode 100644 index 328a8f4a0..000000000 --- a/internal/kclvm_py/vm/__init__.py +++ /dev/null @@ -1,9 +0,0 @@ -# Copyright 2021 The KCL Authors. All rights reserved. - -from .vm import VirtualMachine, Run, Frame - -__all__ = [ - "VirtualMachine", - "Run", - "Frame", -] diff --git a/internal/kclvm_py/vm/code/__init__.py b/internal/kclvm_py/vm/code/__init__.py deleted file mode 100644 index 06cdb363a..000000000 --- a/internal/kclvm_py/vm/code/__init__.py +++ /dev/null @@ -1,41 +0,0 @@ -""" The `code` module mainly contains the definition of KCL -bytecode. The bytecode factory is used for display debugging -in the `code_factory` file and the corresponding bytecode -execution function is in the `code_actions` file. - -Each bytecode corresponds to an execution function. For example, -a binary addition operation corresponds to `Opcode.BINARY_ADD`. - -KCL Bytecodes are mainly divided into three categories: -* Stack operation bytecodes -* KCL semantic related bytecode -* Internal bytecodes for debugging - -:copyright: Copyright 2020 The KCL Authors. All rights reserved. -""" - -from .code import ( - Opcode, - Label, - JumpAbs, - JumpRel, - Instruction, - InstructionWithArg, - EmittedInstruction, - CompilationScope, -) -from .code_factory import SchemaBodyOpcodeFactory -from .code_actions import VM_OP_ACTIONS - -__all__ = [ - "Opcode", - "Label", - "Instruction", - "InstructionWithArg", - "JumpAbs", - "JumpRel", - "EmittedInstruction", - "CompilationScope", - "SchemaBodyOpcodeFactory", - "VM_OP_ACTIONS", -] diff --git a/internal/kclvm_py/vm/code/code.py b/internal/kclvm_py/vm/code/code.py deleted file mode 100644 index ba04d02aa..000000000 --- a/internal/kclvm_py/vm/code/code.py +++ /dev/null @@ -1,255 +0,0 @@ -# Copyright 2021 The KCL Authors. All rights reserved. - -from dataclasses import dataclass -from typing import List, Optional -from enum import IntEnum - - -class Opcode(IntEnum): - """Opcode class is used in KCL virtual machine. - - Virtual machine operator code can be divided into two categories - - Stack opcode - - Semantics opcode - """ - - INVALID = -1 # Invalid opcode - - POP_TOP = 1 # Stack pops 1 operand from the top of the stack - ROT_TWO = 2 # Stack rotates 2 operands - ROT_THREE = 3 # Stack rotates 3 operands - DUP_TOP = 4 # Copy the reference of the top element of the Stack to a copy and put it on the top of the stack - DUP_TOP_TWO = 5 # Copy the references of the first two elements on the top of the Stack to one copy and put it on the top of the stack. - COPY_TOP = 6 # Copy the value of the top element of the Stack to a copy and put it on the top of the stack - NOP = 9 # No operation - - UNARY_POSITIVE = 10 # +a - UNARY_NEGATIVE = 11 # -a - UNARY_NOT = 12 # not a - UNARY_INVERT = 13 # ~a - - MEMBER_SHIP_AS = 16 # a as b - - BINARY_POWER = 20 # a ** b - BINARY_MULTIPLY = 21 # a * b - BINARY_MODULO = 22 # a % b - BINARY_ADD = 23 # a + b - BINARY_SUBTRACT = 24 # a - b - BINARY_SUBSCR = 25 # b[a] - BINARY_FLOOR_DIVIDE = 26 # a // b - BINARY_TRUE_DIVIDE = 27 # a / b - BINARY_LSHIFT = 28 # `a << b` - BINARY_RSHIFT = 29 # `a >> b` - BINARY_AND = 30 # `a & b` - BINARY_XOR = 31 # `a ^ b` - BINARY_OR = 32 # `a | b` - BINARY_LOGIC_AND = 33 # `a and b` - BINARY_LOGIC_OR = 34 # `a or b` - - INPLACE_FLOOR_DIVIDE = 40 # a //= b - INPLACE_TRUE_DIVIDE = 41 # a /= b - INPLACE_ADD = 42 # a += b - INPLACE_SUBTRACT = 43 # `a -= b` - INPLACE_MULTIPLY = 44 # `a *= b` - INPLACE_MODULO = 45 # a %= b - INPLACE_POWER = 46 # a **= b - INPLACE_LSHIFT = 47 # a <<= b - INPLACE_RSHIFT = 48 # a >>= b - INPLACE_AND = 49 # a &= b - INPLACE_XOR = 50 # a ^= b - INPLACE_OR = 51 # a |= b - - COMPARE_EQUAL_TO = 60 # a == b - COMPARE_NOT_EQUAL_TO = 61 # a != b - COMPARE_LESS_THAN = 62 # a < b - COMPARE_LESS_THAN_OR_EQUAL_TO = 63 # a <= b - COMPARE_GREATER_THAN = 64 # a > b - COMPARE_GREATER_THAN_OR_EQUAL_TO = 65 # a >= b - COMPARE_IS = 66 # a is b - COMPARE_IS_NOT = 67 # a is not b - COMPARE_IN = 68 # a in b - COMPARE_NOT_IN = 69 # a not in b - - STORE_MAP = 70 # Put a dict entry into the dict object - STORE_SUBSCR = 71 # Put a subscript of collection - DELETE_SUBSCR = 72 # Delete a subscript of collection - BUILD_SCHEMA_CONFIG = 73 # Generate an empty schema config object - STORE_SCHEMA_CONFIG = 74 # Put a schema config entry into the schema config object - - PRINT_EXPR = 80 # Print expression to stdout - EMIT_EXPR = 81 # Emit a schema expression to the output - - SCHEMA_NOP = 90 # Expressions in the schema interval operation - RETURN_VALUE = 91 # Return value in the schema - RETURN_LAST_VALUE = 92 # Return the last value in the lambda expression - - HAVE_ARGUMENT = 99 # Opcodes from here have an argument - - STORE_NAME = 100 # Index in name list - UNPACK_SEQUENCE = 101 # Number of sequence items - GET_ITER = 102 # Get a element from a iterator - FOR_ITER = 103 # Get a iterator from str/list/dict/schema - STORE_ATTR = 105 # Index in name list - DELETE_ATTR = 106 # Delete a attribute - STORE_GLOBAL = 107 # Store a global variable - DELETE_GLOBAL = 108 # Delete a global variable - LOAD_GLOBAL = 109 # Index in name list - LOAD_CONST = 110 # Index in const list - LOAD_NAME = 111 # Index in name list - LOAD_LOCAL = 112 # Local variable number - STORE_LOCAL = 113 # Local variable number - DELETE_LOCAL = 114 # Local variable number - LOAD_FREE = 115 # Load from closure cell - STORE_FREE = 116 # Store into cell - DELETE_FREE = 117 # Delete closure cell - BUILD_TUPLE = 118 # Number of tuple items - BUILD_LIST = 119 # Number of list items - BUILD_SET = 120 # Number of set items - BUILD_MAP = 121 # Always zero for now - LOAD_ATTR = 123 # Index in name list - LOAD_BUILT_IN = 124 # Index in built-in list - IMPORT_NAME = 126 # Index in name list - COMPARE_OP = 127 # Comparison operator - - JUMP_FORWARD = 130 # Number of bytes to skip - JUMP_IF_FALSE_OR_POP = 131 # Target byte offset from beginning of code - JUMP_IF_TRUE_OR_POP = 132 # Target byte offset from beginning of code - JUMP_ABSOLUTE = 133 # Target byte offset from beginning of code - POP_JUMP_IF_FALSE = 134 # Target byte offset from beginning of code - POP_JUMP_IF_TRUE = 135 # Target byte offset from beginning of code - - CALL_FUNCTION = 140 # #args + (#kwargs<<8) CALL_FUNCTION_XXX opcodes defined below depend on this definition - MAKE_FUNCTION = 141 # #defaults + #kwdefaults<<8 + #annotations<<16 - BUILD_SLICE = 142 # Number of items - MAKE_CLOSURE = 143 # same as MAKE_FUNCTION - LOAD_CLOSURE = 144 # Load free variable from closure - RAISE_VARARGS = 145 # Number of raise arguments (1, 2 or 3) - RAISE_CHECK = 146 # Expressions in the check block - - LIST_APPEND = 150 # Append a item into the list used in the comprehension - SET_ADD = 151 # Append a item into the set used in the comprehension - MAP_ADD = 152 # Append a item into the dict used in the comprehension - DELETE_ITEM = 153 # Delete a item into the dict used in the filter expression - - MAKE_SCHEMA = 160 # Build schema construct function - BUILD_SCHEMA = 161 # Build a schema instance - LOAD_BUILD_SCHEMA = 162 # Load schema - SCHEMA_ATTR = 163 # Declare a schema attribute - SCHEMA_LOAD_ATTR = 164 # Load attribute in the schema - SCHEMA_UPDATE_ATTR = 165 # Update attribute in the schema - MAKE_DECORATOR = 166 # Build a decorator in the schema - - FORMAT_VALUES = 170 # Format value in the string interpolation - - DEBUG_STACK = 180 # Debug stack - DEBUG_LOCALS = 181 # Debug VM locals - DEBUG_GLOBALS = 182 # Debug VM globals - DEBUG_NAMES = 183 # Debug VM names - - @staticmethod - def has_arg(code: int) -> bool: - return code > Opcode.HAVE_ARGUMENT - - -@dataclass -class Pos: - number: int = 0 - pos: int = 0 - filename: str = None - lineno: int = None - colno: int = None - - def get_pos(self) -> int: - return self.pos - - def get_number(self) -> int: - return self.number - - def get_lineno(self) -> int: - return self.lineno - - def set_lineno(self, lineno: int): - self.lineno = lineno - - def set_pos(self, number: int, pos: int) -> bool: - self.number = number - old_pos = self.pos - self.pos = pos - return old_pos != pos - - -@dataclass -class Instruction(Pos): - op: Opcode = None - - @staticmethod - def size() -> int: - return 1 - - def output(self) -> List[int]: - return [self.op] - - -@dataclass -class Label(Pos): - @staticmethod - def size() -> int: - return 0 - - def output(self) -> List[int]: - return [] - - def stack_effect(self): - return 0 - - -@dataclass -class InstructionWithArg(Instruction): - arg: int = 0 - - def byte(self, arg) -> int: - return arg & 0xFF - - @staticmethod - def size() -> int: - return 4 - - def output(self) -> List[int]: - out = [ - self.byte(self.op), - self.byte(self.arg), - self.byte(self.arg >> 8), - self.byte(self.arg >> 16), - ] - return out - - -@dataclass -class JumpRel(InstructionWithArg): - dest: Label = Label() - - def output(self) -> List[int]: - self.arg = self.dest.get_pos() - return super().output() - - -@dataclass -class JumpAbs(InstructionWithArg): - dest: Label = Label() - - def output(self) -> List[int]: - self.arg = self.dest.get_pos() - return super().output() - - -@dataclass -class EmittedInstruction: - opcode: Opcode = Opcode.INVALID - position: int = 0 - - -@dataclass -class CompilationScope: - instructions: list - last_instruction: Optional[EmittedInstruction] = EmittedInstruction() - previous_instruction: Optional[EmittedInstruction] = EmittedInstruction() diff --git a/internal/kclvm_py/vm/code/code_actions.py b/internal/kclvm_py/vm/code/code_actions.py deleted file mode 100644 index 5bb3618a8..000000000 --- a/internal/kclvm_py/vm/code/code_actions.py +++ /dev/null @@ -1,1088 +0,0 @@ -# Copyright 2021 The KCL Authors. All rights reserved. - -import time -from typing import Optional -from copy import deepcopy - -import kclvm.api.object as obj -import kclvm.kcl.error as kcl -import kclvm.kcl.ast as ast -import kclvm.kcl.types as types -import kclvm.config -import kclvm.compiler.extension.builtin - -from kclvm.vm.runtime.evaluator.eval import Evaluator -from kclvm.vm.code import Opcode -from kclvm.compiler.check.check_type import ( - type_pack_and_check, - runtime_types, -) -from kclvm.unification import value_subsume - -_evaluator_inst = Evaluator() - - -def is_kcl_debug(): - return kclvm.config.debug and kclvm.config.verbose > 2 - - -def debug_stack(vm, _code: int, arg: int) -> Optional[obj.KCLObject]: - idx = int(arg & 0xFF) - at = int((arg >> 8) & 0xFF) - return vm.debug_stack(idx, at) - - -def debug_locals(vm, _code: int, arg: int) -> Optional[obj.KCLObject]: - idx = int(arg & 0xFF) - at = int((arg >> 8) & 0xFF) - return vm.debug_locals(idx, at) - - -def debug_globals(vm, _code: int, arg: int) -> Optional[obj.KCLObject]: - idx = int(arg & 0xFF) - at = int((arg >> 8) & 0xFF) - return vm.debug_globals(idx, at) - - -def debug_names(vm, _code: int, arg: int) -> Optional[obj.KCLObject]: - idx = int(arg & 0xFF) - at = int((arg >> 8) & 0xFF) - return vm.debug_names(idx, at) - - -def unpack_operand(arg: int): - return int(arg & 0xFF), int((arg >> 8) & 0xFF), int((arg >> 16) & 0xFF) - - -def bin_action(vm, code: int, _arg: int) -> Optional[obj.KCLObject]: - right, left = vm.pop(), vm.top() - result = _evaluator_inst.eval_binary_op(left, right, code, vm=vm) - vm.set_top(result) - return result - - -def unary_action(vm, code: int, _arg: int) -> Optional[obj.KCLObject]: - expr_obj = vm.top() - result = _evaluator_inst.eval_unary_op(expr_obj, code) - vm.set_top(result) - return result - - -def inplace_action(vm, code: int, _arg: int) -> Optional[obj.KCLObject]: - value, target = vm.pop(), vm.top() - result = _evaluator_inst.eval_inplace_op(target, value, code, vm=vm) - vm.set_top(result) - return result - - -def bin_add(vm, code: int, arg: int) -> Optional[obj.KCLObject]: - return bin_action(vm, code, arg) - - -def bin_substract(vm, code: int, arg: int) -> Optional[obj.KCLObject]: - return bin_action(vm, code, arg) - - -def bin_floor_divide(vm, code: int, arg: int) -> Optional[obj.KCLObject]: - return bin_action(vm, code, arg) - - -def bin_true_divide(vm, code: int, arg: int) -> Optional[obj.KCLObject]: - return bin_action(vm, code, arg) - - -def build_map(vm, _code: int, _arg: int) -> Optional[obj.KCLObject]: - dict_obj = obj.KCLDictObject(value={}) - vm.push(dict_obj) - return dict_obj - - -def load_free(vm, _code: int, arg: int) -> Optional[obj.KCLObject]: - free_obj = obj.NONE_INSTANCE - index = vm.frame_index - name = vm.names[arg] - # Search the local variables from the inside to the outside schema - while index >= 1: - index -= 1 - if name in vm.frames[index].locals: - free_obj = vm.frames[index].locals[name] - vm.push(free_obj) - return free_obj - - -def load_closure(vm, _code: int, arg: int) -> Optional[obj.KCLObject]: - # free_obj = vm.ctx.free_vars[arg] - closure_obj = ( - vm.ctx.free_vars[arg] if arg < len(vm.ctx.free_vars) else obj.UNDEFINED_INSTANCE - ) - vm.push(closure_obj) - return closure_obj - - -def make_function(vm, code: int, arg: int) -> Optional[obj.KCLObject]: - return make_compiled_function(vm, code, arg) - - -def make_closure(vm, code: int, arg: int) -> Optional[obj.KCLObject]: - return make_compiled_function(vm, code, arg, is_closure=True) - - -def make_compiled_function( - vm, _code: int, arg: int, is_closure: bool = False -) -> Optional[obj.KCLObject]: - """ - Pushes a new function object on the stack. From bottom to top, the consumed stack must consist of values if the argument carries a specified flag value - + 0x01 a tuple of default values for positional-only and positional-or-keyword parameters in positional order - + 0x02 a dictionary of keyword-only parameters’ default values - + 0x04 an annotation dictionary - + 0x08 a tuple containing cells for free variables, making a closure - + the code associated with the function (at TOS1) - + the qualified name of the function (at TOS) - """ - # Pop the function name - name = vm.pop().value - # Pop code placeholder - runtime_code = vm.pop() - closure = vm.pop() if is_closure else None - args, _, _ = unpack_operand(arg) - # var params []grumpy.Param - params: list = [0] * args - index = 0 - for index in range(args): - # positional args placeholders to fit grumpy arg validate - arg_value = vm.pop() - arg_type = vm.pop().value - arg_name = vm.pop().value - params[index] = obj.Parameter( - name=arg_name, type_annotation=arg_type, value=arg_value - ) - - func = obj.KCLCompiledFunctionObject( - name=name, - instructions=runtime_code.codes, - names=runtime_code.names, - constants=runtime_code.constants, - num_locals=0, - num_parameters=arg, - params=params[::-1], - pkgpath=vm.cur_run_pkg, - closure=closure, - ) - vm.push(func) - return func - - -def pop_top(vm, _code: int, _arg: int) -> Optional[obj.KCLObject]: - return vm.pop() - - -def rot_two(vm, _code: int, _arg: int) -> Optional[obj.KCLObject]: - v = vm.pop() - w = vm.pop() - vm.push(v) - vm.push(w) - return w - - -def rot_three(vm, _code: int, _arg: int) -> Optional[obj.KCLObject]: - v = vm.pop() - w = vm.pop() - u = vm.pop() - vm.push(v) - vm.push(w) - vm.push(u) - return u - - -def dup_top(vm, _code: int, _arg: int) -> Optional[obj.KCLObject]: - vm.push(vm.peek()) - return vm.peek() - - -def copy_top(vm, _code: int, _arg: int) -> Optional[obj.KCLObject]: - vm.push(deepcopy(vm.peek())) - return vm.peek() - - -def dup_top_two(vm, _code: int, _arg: int) -> Optional[obj.KCLObject]: - v = vm.pop() - w = vm.pop() - vm.push(w) - vm.push(v) - vm.push(w) - vm.push(v) - return v - - -def nop(_vm, _code: int, _arg: int) -> Optional[obj.KCLObject]: - """Empty opcode action""" - pass - - -def unary_pos(vm, code: int, arg: int) -> Optional[obj.KCLObject]: - return unary_action(vm, code, arg) - - -def unary_neg(vm, code: int, arg: int) -> Optional[obj.KCLObject]: - return unary_action(vm, code, arg) - - -def unary_not(vm, code: int, arg: int) -> Optional[obj.KCLObject]: - return unary_action(vm, code, arg) - - -def unary_invert(vm, code: int, arg: int) -> Optional[obj.KCLObject]: - return unary_action(vm, code, arg) - - -def bin_power(vm, code: int, arg: int) -> Optional[obj.KCLObject]: - return bin_action(vm, code, arg) - - -def bin_mul(vm, code: int, arg: int) -> Optional[obj.KCLObject]: - return bin_action(vm, code, arg) - - -def bin_mod(vm, code: int, arg: int) -> Optional[obj.KCLObject]: - return bin_action(vm, code, arg) - - -def bin_subscr(vm, code: int, arg: int) -> Optional[obj.KCLObject]: - return bin_action(vm, code, arg) - - -def inplace_floor_div(vm, code: int, arg: int) -> Optional[obj.KCLObject]: - return inplace_action(vm, code, arg) - - -def inplace_true_div(vm, code: int, arg: int) -> Optional[obj.KCLObject]: - return inplace_action(vm, code, arg) - - -def store_map(vm, _code: int, _arg: int) -> Optional[obj.KCLObject]: - v, k = vm.pop(), vm.pop() - config_ref = vm.peek() - if v.type() == obj.KCLObjectType.UNPACK and k.type() in [ - obj.KCLObjectType.NONE, - obj.KCLObjectType.UNDEFINED, - ]: - config_ref.append_unpack(v.unpack()) - else: - config_ref.update_key_value(k, v) - return config_ref - - -def inplace_add(vm, code: int, arg: int) -> Optional[obj.KCLObject]: - return inplace_action(vm, code, arg) - - -def inplace_sub(vm, code: int, arg: int) -> Optional[obj.KCLObject]: - return inplace_action(vm, code, arg) - - -def inplace_mul(vm, code: int, arg: int) -> Optional[obj.KCLObject]: - return inplace_action(vm, code, arg) - - -def inplace_mod(vm, code: int, arg: int) -> Optional[obj.KCLObject]: - return inplace_action(vm, code, arg) - - -def store_subscr(vm, _code: int, _arg: int) -> Optional[obj.KCLObject]: - """v[w] = u""" - w = vm.pop() - v = vm.pop() - u = vm.pop() - _evaluator_inst.set_item(v, w, u) - return v - - -def bin_lshift(vm, code: int, arg: int) -> Optional[obj.KCLObject]: - return bin_action(vm, code, arg) - - -def bin_rshift(vm, code: int, arg: int) -> Optional[obj.KCLObject]: - return bin_action(vm, code, arg) - - -def bin_and(vm, code: int, arg: int) -> Optional[obj.KCLObject]: - return bin_action(vm, code, arg) - - -def bin_xor(vm, code: int, arg: int) -> Optional[obj.KCLObject]: - return bin_action(vm, code, arg) - - -def bin_or(vm, code: int, arg: int) -> Optional[obj.KCLObject]: - return bin_action(vm, code, arg) - - -def bin_logic_and(vm, code: int, arg: int) -> Optional[obj.KCLObject]: - return bin_action(vm, code, arg) - - -def bin_logic_or(vm, code: int, arg: int) -> Optional[obj.KCLObject]: - return bin_action(vm, code, arg) - - -def inplace_pow(vm, code: int, arg: int) -> Optional[obj.KCLObject]: - return inplace_action(vm, code, arg) - - -def get_iter(vm, _code: int, _arg: int) -> Optional[obj.KCLObject]: - assert 0 < _arg <= 2 - iter_obj = obj.KCLIterObject.build_iter(vm.top(), _arg) - vm.set_top(iter_obj) - return None - - -def print_expr(vm, _code: int, _arg: int) -> Optional[obj.KCLObject]: - expr_obj = vm.pop() - print(expr_obj.value) - return expr_obj - - -def emit_expr(vm, _code: int, _arg: int) -> Optional[obj.KCLObject]: - emitted_obj = vm.pop() - if isinstance(emitted_obj, obj.KCLSchemaObject): - output_type = ( - emitted_obj.get(obj.SCHEMA_SETTINGS_ATTR_NAME) - .get(obj.SETTINGS_OUTPUT_KEY) - .value - ) - if ( - output_type == obj.SETTINGS_OUTPUT_STANDALONE - or output_type == obj.SETTINGS_OUTPUT_IGNORE - ): - # Internal magic variable - vm.update_global(f"$EMIT_VAR_{time.time()}", emitted_obj) - return emitted_obj - - -def inplace_lshift(vm, code: int, arg: int) -> Optional[obj.KCLObject]: - return inplace_action(vm, code, arg) - - -def inplace_rlshift(vm, code: int, arg: int) -> Optional[obj.KCLObject]: - return inplace_action(vm, code, arg) - - -def inplace_and(vm, code: int, arg: int) -> Optional[obj.KCLObject]: - return inplace_action(vm, code, arg) - - -def inplace_xor(vm, code: int, arg: int) -> Optional[obj.KCLObject]: - return inplace_action(vm, code, arg) - - -def inplace_or(vm, code: int, arg: int) -> Optional[obj.KCLObject]: - return inplace_action(vm, code, arg) - - -def return_value(vm, _code: int, _arg: int) -> Optional[obj.KCLObject]: - vm.pop_frame() - return vm.peek() - - -def return_last_value(vm, _code: int, _arg: int) -> Optional[obj.KCLObject]: - frame = vm.pop_frame() - variables = list(frame.locals.values()) - return_obj = variables[-1] if variables else obj.NONE_INSTANCE - vm.push(return_obj) - return return_obj - - -def store_name(vm, _code: int, arg: int) -> Optional[obj.KCLObject]: - return vm.store_name(arg) - - -def unpack_sequence(vm, _code: int, arg: int) -> Optional[obj.KCLObject]: - sequence_obj = vm.pop() - unpack_obj = obj.KCLUnpackObject(sequence_obj, arg != 1) - vm.push(unpack_obj) - return unpack_obj - - -def for_iter(vm, _code: int, arg: int) -> Optional[obj.KCLObject]: - """ - TOS is an iterator. Call its iter_next() method. If this yields a new value, - push it on the stack (leaving the iterator below it). - If the iterator indicates it is exhausted TOS is popped, - and the byte code counter is incremented by 'arg' argument. - """ - try: - iter_next_obj = _evaluator_inst.iter_next(vm.peek()) - assert isinstance(iter_next_obj, obj.KCLTupleObject) - # Push loop variables - for o in iter_next_obj.value[::-1]: - vm.push(obj.to_kcl_obj(o)) - except StopIteration: - it = vm.pop() - assert isinstance(it, obj.KCLIterObject) - vm.set_instruction_pointer(arg) - except Exception as err: - kcl.report_exception( - err_type=kcl.ErrType.EvaluationError_TYPE, arg_msg=str(err) - ) - - return None - - -def store_attr(vm, _code: int, arg: int) -> Optional[obj.KCLObject]: - """v.w = u""" - w = vm.names[arg] - v = vm.pop() - u = vm.pop() - - _evaluator_inst.set_attr(v, obj.KCLStringObject(w), u, vm=vm) - - return v - - -def store_global(vm, _code: int, arg: int) -> Optional[obj.KCLObject]: - return vm.store_name(arg) - - -def load_const(vm, _code: int, arg: int) -> Optional[obj.KCLObject]: - return vm.load_const(arg) - - -def load_name(vm, _code: int, arg: int) -> Optional[obj.KCLObject]: - return vm.load_name(arg) - - -def build_list(vm, _code: int, arg: int) -> Optional[obj.KCLObject]: - items = [vm.pop() for _i in range(arg)][::-1] - list_obj = obj.KCLListObject(items=[]) - for item in items: - if item.type() == obj.KCLObjectType.UNPACK: - list_obj.append_unpack(item.unpack()) - else: - list_obj.append(item) - vm.push(list_obj) - return list_obj - - -def schema_attr(vm, _code: int, arg: int) -> Optional[obj.KCLObject]: - """ - Define a schema attr into schema type object - """ - n_decorators = arg - decorators_obj = [vm.pop() for _i in range(n_decorators)][::-1] - expected_types = [vm.pop().value] - attr, value, has_default, is_final, is_optional, op_code = ( - vm.pop().value, - vm.pop(), - vm.pop().value, - vm.pop().value, - vm.pop().value, - vm.pop().value, - ) - config_meta = vm.lazy_eval_ctx.config_meta - config_obj = vm.ctx.locals[obj.SCHEMA_CONFIG_VALUE_KEY] - schema_obj = vm.ctx.locals[obj.SCHEMA_SELF_VALUE_KEY] - config_value = config_obj.get(attr) - schema_obj.set_attr_type(attr, expected_types) - schema_obj.set_attr_optional(attr, is_optional) - attr_runtime_types = runtime_types(expected_types, vm=vm) - if attr_runtime_types: - schema_obj.set_attr_runtime_type(attr, attr_runtime_types) - for decorator in decorators_obj: - schema_obj.add_decorator(attr, decorator) - - operation = ( - config_obj.get_operation(attr) - if isinstance(config_obj, obj.KCLSchemaConfigObject) - else ast.ConfigEntryOperation.UNION - ) - insert_index = ( - config_obj.get_insert_index(attr) - if isinstance(config_obj, obj.KCLSchemaConfigObject) - else None - ) - - # Update and union with config_value - if has_default: - target = ( - schema_obj.get(attr) if attr in schema_obj else obj.KCLNoneObject.instance() - ) - if op_code is None: - op_value = value - else: - op_value = _evaluator_inst.eval_inplace_op(target, value, op_code, vm=vm) - op_value = type_pack_and_check(op_value, expected_types, vm=vm) - if schema_obj.get_immutable_flag(attr) and target.value != op_value.value: - kcl.report_exception( - err_type=kcl.ErrType.ImmutableRuntimeError_TYPE, - arg_msg=f"final schema field '{attr}'", - ) - vm.lazy_eval_ctx.set_value(attr, op_value) - elif attr not in schema_obj: - schema_obj.update({attr: obj.KCLUndefinedObject.instance()}) - - if attr in config_obj: - conf_meta = config_meta.get(attr, {}) - filename = conf_meta.get("filename") - lineno = conf_meta.get("lineno") - columnno = conf_meta.get("columnno") - if is_final and obj.to_python_obj(config_value) != obj.to_python_obj( - schema_obj.attrs.get(attr) - ): - kcl.report_exception( - err_type=kcl.ErrType.ImmutableRuntimeError_TYPE, - file_msgs=[ - kcl.ErrFileMsg(filename=filename, line_no=lineno, col_no=columnno) - ], - arg_msg=f"final schema field '{attr}'", - ) - _evaluator_inst.update_schema_attr( - attr=attr, - schema_obj=schema_obj, - config_value=config_value, - conf_meta=conf_meta, - expected_types=expected_types, - operation=operation, - index=insert_index, - vm=vm, - filename=filename, - lineno=lineno, - columnno=columnno, - ) - vm.lazy_eval_ctx.set_value(attr, schema_obj.get(attr)) - - # Update mutable flag - schema_obj.set_immutable_flag(attr, is_final) - vm.update_local(attr, schema_obj.get(attr)) - return schema_obj - - -def schema_update_attr(vm, _code: int, arg: int) -> Optional[obj.KCLObject]: - name = vm.pop().value - value = vm.pop() - - schema_obj = vm.ctx.locals[obj.SCHEMA_SELF_VALUE_KEY] - config_obj = vm.ctx.locals[obj.SCHEMA_CONFIG_VALUE_KEY] - config_meta = vm.lazy_eval_ctx.config_meta - config_value = config_obj.get(name) - - # A private schema attribute can be added into schema object whether it's relaxed or not - if schema_obj.get_immutable_flag(name): - kcl.report_exception( - err_type=kcl.ErrType.ImmutableRuntimeError_TYPE, - arg_msg=f"final schema field '{name}'", - ) - - conf_meta = config_meta.get(name, {}) - filename = conf_meta.get("filename") - lineno = conf_meta.get("lineno") - columnno = conf_meta.get("columnno") - if name not in schema_obj or not schema_obj.get_attr_type(name): - schema_obj.set_attr_optional(name, True) - vm.lazy_eval_ctx.set_value( - name, type_pack_and_check(value, schema_obj.get_attr_type(name), vm=vm) - ) - - if name in config_obj: - config_value = type_pack_and_check( - config_value, - schema_obj.get_attr_type(name), - vm=vm, - filename=filename, - lineno=lineno, - columno=columnno, - config_meta=conf_meta.get("$conf_meta"), - ) - cfg_obj = obj.KCLSchemaConfigObject(value={name: config_value}) - cfg_obj.update_attr_op_using_obj(config_obj) - schema_obj.union_with(cfg_obj) - vm.lazy_eval_ctx.set_value(name, schema_obj.get(name)) - - -def make_decorator(vm, _code: int, arg: int) -> Optional[obj.KCLObject]: - decorator = vm.pop() - assert isinstance(decorator, obj.KCLDecoratorObject) - args, kwargs = _evaluator_inst.call_vars_and_keywords(arg, vm) - decorator.resolve(args, kwargs) - vm.push(decorator) - return decorator - - -def schema_load_attr(vm, _code: int, arg: int) -> Optional[obj.KCLObject]: - name_obj = vm.top() - vm.set_top(vm.lazy_eval_ctx.get_value(name_obj.value)) - return name_obj - - -def import_name(vm, _code: int, arg: int) -> Optional[obj.KCLObject]: - return vm.import_name(_code, arg) - - -def jump_forward(vm, _code: int, arg: int) -> Optional[obj.KCLObject]: - vm.set_instruction_pointer(arg) - return None - - -def jump_if_false_or_pop(vm, _code: int, arg: int) -> Optional[obj.KCLObject]: - condition_obj = vm.peek() - if not obj.KCLObject.is_truthy(condition_obj): - vm.set_instruction_pointer(arg) - else: - vm.pop() - return None - - -def jump_if_true_or_pop(vm, _code: int, arg: int) -> Optional[obj.KCLObject]: - if obj.KCLObject.is_truthy(vm.peek()): - vm.set_instruction_pointer(arg) - else: - vm.pop() - return None - - -def jump_absolute(vm, _code: int, arg: int) -> Optional[obj.KCLObject]: - vm.set_instruction_pointer(arg) - return None - - -def pop_jump_if_false(vm, _code: int, arg: int) -> Optional[obj.KCLObject]: - condition_obj = vm.pop() - if not obj.KCLObject.is_truthy(condition_obj): - vm.set_instruction_pointer(arg) - return None - - -def pop_jump_if_true(vm, _code: int, arg: int) -> Optional[obj.KCLObject]: - condition_obj = vm.pop() - if obj.KCLObject.is_truthy(condition_obj): - vm.set_instruction_pointer(arg) - return None - - -def load_global(vm, _code: int, arg: int) -> Optional[obj.KCLObject]: - vm.load_name(arg) - return None - - -def raise_varargs(vm, _code: int, arg: int) -> Optional[obj.KCLObject]: - if arg != 1: - raise Exception(f"invalid raise_varargs opcode arg {arg}") - msg_obj = vm.pop() - msg = msg_obj.value if msg_obj.type() == obj.KCLObjectType.STRING else "" - if arg == 1: - kcl.report_exception( - err_type=kcl.ErrType.AssertionError_TYPE, arg_msg=msg if msg else "" - ) - return None - - -def raise_check(vm, _code: int, arg: int) -> Optional[obj.KCLObject]: - if arg != 1: - raise Exception(f"invalid raise_check opcode arg {arg}") - msg_obj = vm.pop() - msg = msg_obj.value if msg_obj.type() == obj.KCLObjectType.STRING else "" - if arg == 1: - config_meta = obj.to_python_obj(vm.ctx.locals[obj.SCHEMA_CONFIG_META_KEY]) - conf_filename, conf_line, conf_column = ( - config_meta.get("$filename"), - config_meta.get("$lineno"), - config_meta.get("$columnno"), - ) - filename, line, _ = vm.get_info(True) - kcl.report_exception( - err_type=kcl.ErrType.SchemaCheckFailure_TYPE, - file_msgs=[ - kcl.ErrFileMsg( - filename=filename, - line_no=line, - arg_msg=kcl.SCHEMA_CHECK_FILE_MSG_COND, - ), - kcl.ErrFileMsg( - filename=conf_filename, - line_no=conf_line, - col_no=conf_column, - arg_msg=kcl.SCHEMA_CHECK_FILE_MSG_ERR, - ), - ], - arg_msg=msg if msg else "", - ) - return None - - -def load_local(vm, _code: int, arg: int) -> Optional[obj.KCLObject]: - vm.load_local(arg) - return None - - -def store_local(vm, _code: int, arg: int) -> Optional[obj.KCLObject]: - vm.store_local(arg) - return None - - -def call_function(vm, code: int, arg: int) -> Optional[obj.KCLObject]: - _evaluator_inst.eval_call(code, arg, vm) - return None - - -def build_slice(vm, _code: int, arg: int) -> Optional[obj.KCLObject]: - if arg != 2 and arg != 3: - raise Exception(f"invalid slice argc {arg}") - step = obj.KCLNoneObject.instance() - if arg == 3: - step = vm.pop() - stop = vm.pop() - start = vm.top() - vm.set_top(obj.KCLSliceObject(start=start, stop=stop, step=step)) - return None - - -def list_append(vm, _code: int, arg: int) -> Optional[obj.KCLObject]: - item = vm.pop() - list_obj = vm.peek_nth(arg) - _evaluator_inst.list_append(list_obj, item) - return list_obj - - -def map_add(vm, _code: int, arg: int) -> Optional[obj.KCLObject]: - operation = vm.pop().value - key = vm.pop() - value = vm.pop() - config_ref = vm.peek_nth(arg) - data_obj = obj.KCLSchemaConfigObject(value={key.value: value}) - if operation is None or operation == ast.ConfigEntryOperation.UNION: - config_ref.union_with(data_obj) - elif operation == ast.ConfigEntryOperation.OVERRIDE: - config_ref.update(data_obj) - elif operation == ast.ConfigEntryOperation.INSERT: - config_ref.insert_with(data_obj, -1) - else: - config_ref.update(data_obj) - return config_ref - - -def delete_item(vm, _code: int, arg: int) -> Optional[obj.KCLObject]: - collection_obj = vm.peek_nth(arg) - is_two_var = vm.pop().value - value = vm.pop() - item = vm.pop() - if isinstance(collection_obj, (obj.KCLSchemaObject, obj.KCLDictObject)): - collection_obj.delete(item) - elif isinstance(collection_obj, obj.KCLListObject): - if is_two_var: - collection_obj.remove(value) - else: - collection_obj.remove(item) - else: - kcl.report_exception( - err_type=kcl.ErrType.EvaluationError_TYPE, - arg_msg=f"illegal quantifier expression type '{collection_obj.type_str()}'", - ) - return collection_obj - - -def schema_nop(vm, _code: int, arg: int) -> Optional[obj.KCLObject]: - """Schema nop between scheam update attributes""" - schema_obj = vm.ctx.locals[obj.SCHEMA_SELF_VALUE_KEY] - return schema_obj - - -def make_schema(vm, _code: int, arg: int) -> Optional[obj.KCLObject]: - """ - Stack Layout - ------------ - TOS - - 6. index signature - - 5. decorator list - - 4. check func - - 3. schema_body_func - - 2. mixin type object list - - 1. parent_type_obj - - 0. schema_type_obj - """ - decorator_count, mixin_count, _ = unpack_operand(arg) - index_signature = None - index_signature_key_type = vm.pop().value - if index_signature_key_type: - index_signature = obj.KCLSchemaIndexSignatureObject( - key_type=index_signature_key_type, - value_type=vm.pop().value, - key_name=vm.pop().value, - any_other=vm.pop().value, - value=vm.pop(), - ) - decorators = [vm.pop() for _i in range(decorator_count)][::-1] - schema_check_func = vm.pop() - schema_body_func = vm.pop() - mixins = [vm.pop() for _i in range(mixin_count)][::-1] - parent_schema_type = vm.pop() - if parent_schema_type.type() not in [ - obj.KCLObjectType.SCHEMA_TYPE, - obj.KCLObjectType.NONE, - obj.KCLObjectType.UNDEFINED, - ]: - kcl.report_exception( - err_type=kcl.ErrType.EvaluationError_TYPE, - arg_msg="illegal schema inherit object type", - ) - self_schema_type = vm.pop() - - type_obj = obj.KCLSchemaTypeObject.new( - self_schema_type.name, - parent_schema_type - if isinstance(parent_schema_type, obj.KCLSchemaTypeObject) - else None, - self_schema_type.protocol, - filename=vm.get_info()[0], - is_mixin=self_schema_type.is_mixin, - pkgpath=self_schema_type.pkgpath, - attr_list=self_schema_type.attr_list, - index_signature=index_signature, - is_relaxed=bool(index_signature), - vm=vm, - ) - - vm.define_schema_type( - f"{self_schema_type.pkgpath}.{self_schema_type.name}", type_obj - ) - - if isinstance(schema_body_func, obj.KCLCompiledFunctionObject): - schema_body_func.name = self_schema_type.name - type_obj.set_func(schema_body_func) - else: - assert isinstance(schema_body_func, (obj.KCLNoneObject, obj.KCLUndefinedObject)) - - if isinstance(schema_check_func, obj.KCLCompiledFunctionObject): - schema_check_func.name = self_schema_type.name - type_obj.set_check_func(schema_check_func) - else: - assert isinstance( - schema_check_func, (obj.KCLNoneObject, obj.KCLUndefinedObject) - ) - - type_obj.add_decorators(decorators) - - if len(mixins) > 0: - if isinstance(mixins[0], obj.KCLStringObject): - type_obj.mixins_names = [x.value for x in mixins] - elif isinstance(mixins[0], obj.KCLSchemaTypeObject): - type_obj.mixins = mixins - else: - assert False, f"make_schema: mixins[0] type: {type(mixins[0])}" - type_obj.update_mixins(vm=vm) - vm.push(type_obj) - return type_obj - - -def build_schema(vm, _code: int, arg: int) -> Optional[obj.KCLObject]: - schema_obj = vm.pop() - config_obj = vm.pop() - config_meta = obj.to_python_obj(vm.pop()) - args, kwargs = _evaluator_inst.call_vars_and_keywords(arg, vm) - # Schema type object - if isinstance(schema_obj, obj.KCLSchemaTypeObject): - if isinstance(config_obj, obj.KCLDictObject): - inst = schema_obj.new_instance(config_obj, config_meta, args, kwargs, vm) - else: - inst = config_obj - # Schema value object - else: - inst = _evaluator_inst.eval_binary_op( - schema_obj, config_obj, Opcode.BINARY_OR, vm=vm - ) - vm.push(inst) - return inst - - -def build_schema_config(vm, _code: int, _arg: int) -> Optional[obj.KCLObject]: - config_obj = obj.KCLSchemaConfigObject( - value={}, operation_map={}, insert_index_map={} - ) - vm.push(config_obj) - return config_obj - - -def store_schema_config(vm, _code: int, _arg: int) -> Optional[obj.KCLObject]: - insert_index, operation, is_nest_key = ( - vm.pop().value, - vm.pop().value, - vm.pop().value, - ) - v, k = vm.pop(), vm.pop() - config_ref = vm.peek() - if v.type() == obj.KCLObjectType.UNPACK and k.type() in [ - obj.KCLObjectType.NONE, - obj.KCLObjectType.UNDEFINED, - ]: - config_ref.append_unpack(v.unpack()) - else: - # Deal the nest var config e.g., {a.b.c: "123"} -> {a: {b: {c: "123"}}} - if k.type() == obj.KCLObjectType.STRING and is_nest_key: - data_obj = obj.KCLSchemaConfigObject() - obj_ref = data_obj - nest_keys = k.value.split(".") - for i, key in enumerate(nest_keys): - obj_ref.value[key] = ( - v if i == len(nest_keys) - 1 else obj.KCLSchemaConfigObject() - ) - if i == len(nest_keys) - 1: - obj_ref.add_operation(key, operation, insert_index) - obj_ref = obj_ref.value[key] - operation = ast.ConfigEntryOperation.UNION - insert_index = None - else: - data_obj = obj.KCLSchemaConfigObject(value={k.value: v}) - config_ref.add_operation(k.value, operation, insert_index) - if operation is None or operation == ast.ConfigEntryOperation.UNION: - config_ref.union_with(data_obj) - elif operation == ast.ConfigEntryOperation.OVERRIDE: - config_ref.update(data_obj) - elif operation == ast.ConfigEntryOperation.INSERT: - config_ref.insert_with(data_obj, insert_index) - elif operation == ast.ConfigEntryOperation.UNIQUE: - config_ref.unique_merge_with(data_obj) - elif operation == ast.ConfigEntryOperation.UNIFICATION: - if value_subsume(data_obj, config_ref): - config_ref.union_with(data_obj) - else: - kcl.report_exception( - err_type=kcl.ErrType.EvaluationError_TYPE, - arg_msg="unification conflict", - ) - else: - config_ref.union_with(data_obj) - return config_ref - - -def load_attr(vm, _code: int, arg: int) -> Optional[obj.KCLObject]: - attr_obj = vm.top() - name = vm.names[arg] - value = _evaluator_inst.load_attr(attr_obj, name) - vm.set_top(value) - return value - - -def load_builtin(vm, _code: int, arg: int) -> Optional[obj.KCLObject]: - return vm.load_builtin(arg) - - -def format_values(vm, code: int, arg: int) -> Optional[obj.KCLObject]: - assert arg >= 0 - formatted_str_obj_list = [] - format_spec = vm.pop().value - for i in range(arg): - format_obj = vm.pop() - format_value = _evaluator_inst.format_value(format_obj, format_spec) - formatted_str_obj_list.append(format_value) - for str_obj in formatted_str_obj_list[::-1]: - vm.push(str_obj) - return vm.peek() - - -def member_ship_as(vm, code: int, arg: int) -> Optional[obj.KCLObject]: - # Pop the type object - type_object = vm.pop() - vm.set_top(types.type_convert(vm.top(), type_object)) - return vm.top() - - -def compare_op(vm, _code: int, arg: int) -> Optional[obj.KCLObject]: - left, right = vm.pop(), vm.top() - result = _evaluator_inst.eval_compare_op(left, right, arg, vm=vm) - vm.set_top(result) - return result - - -VM_OP_ACTIONS = { - Opcode.BINARY_ADD: bin_add, - Opcode.BINARY_SUBTRACT: bin_substract, - Opcode.BINARY_MULTIPLY: bin_mul, - Opcode.BINARY_FLOOR_DIVIDE: bin_floor_divide, - Opcode.BINARY_TRUE_DIVIDE: bin_true_divide, - Opcode.BUILD_SCHEMA_CONFIG: build_schema_config, - Opcode.STORE_SCHEMA_CONFIG: store_schema_config, - Opcode.POP_TOP: pop_top, - Opcode.ROT_TWO: rot_two, - Opcode.ROT_THREE: rot_three, - Opcode.DUP_TOP: dup_top, - Opcode.DUP_TOP_TWO: dup_top_two, - Opcode.COPY_TOP: copy_top, - Opcode.NOP: nop, - Opcode.UNARY_POSITIVE: unary_pos, - Opcode.UNARY_NEGATIVE: unary_neg, - Opcode.UNARY_NOT: unary_not, - Opcode.UNARY_INVERT: unary_invert, - Opcode.BINARY_POWER: bin_power, - Opcode.BINARY_MODULO: bin_mod, - Opcode.BINARY_SUBSCR: bin_subscr, - Opcode.INPLACE_FLOOR_DIVIDE: inplace_floor_div, - Opcode.INPLACE_TRUE_DIVIDE: inplace_true_div, - Opcode.STORE_MAP: store_map, - Opcode.INPLACE_ADD: inplace_add, - Opcode.INPLACE_SUBTRACT: inplace_sub, - Opcode.INPLACE_MULTIPLY: inplace_mul, - Opcode.INPLACE_MODULO: inplace_mod, - Opcode.STORE_SUBSCR: store_subscr, - Opcode.BINARY_LSHIFT: bin_lshift, - Opcode.BINARY_RSHIFT: bin_rshift, - Opcode.BINARY_AND: bin_and, - Opcode.BINARY_XOR: bin_xor, - Opcode.BINARY_OR: bin_or, - Opcode.BINARY_LOGIC_AND: bin_logic_and, - Opcode.BINARY_LOGIC_OR: bin_logic_or, - Opcode.INPLACE_POWER: inplace_pow, - Opcode.GET_ITER: get_iter, - Opcode.PRINT_EXPR: print_expr, - Opcode.EMIT_EXPR: emit_expr, - Opcode.INPLACE_LSHIFT: inplace_lshift, - Opcode.INPLACE_RSHIFT: inplace_rlshift, - Opcode.INPLACE_AND: inplace_and, - Opcode.INPLACE_XOR: inplace_xor, - Opcode.INPLACE_OR: inplace_or, - Opcode.RETURN_VALUE: return_value, - Opcode.RETURN_LAST_VALUE: return_last_value, - Opcode.STORE_NAME: store_name, - Opcode.UNPACK_SEQUENCE: unpack_sequence, - Opcode.FOR_ITER: for_iter, - Opcode.STORE_ATTR: store_attr, - Opcode.STORE_GLOBAL: store_global, - Opcode.LOAD_CONST: load_const, - Opcode.LOAD_NAME: load_name, - Opcode.BUILD_LIST: build_list, - Opcode.BUILD_MAP: build_map, - Opcode.LOAD_ATTR: load_attr, - Opcode.IMPORT_NAME: import_name, - Opcode.JUMP_FORWARD: jump_forward, - Opcode.JUMP_IF_FALSE_OR_POP: jump_if_false_or_pop, - Opcode.JUMP_IF_TRUE_OR_POP: jump_if_true_or_pop, - Opcode.JUMP_ABSOLUTE: jump_absolute, - Opcode.POP_JUMP_IF_FALSE: pop_jump_if_false, - Opcode.POP_JUMP_IF_TRUE: pop_jump_if_true, - Opcode.LOAD_GLOBAL: load_global, - Opcode.RAISE_VARARGS: raise_varargs, - Opcode.RAISE_CHECK: raise_check, - Opcode.LOAD_LOCAL: load_local, - Opcode.STORE_LOCAL: store_local, - Opcode.LOAD_FREE: load_free, - Opcode.CALL_FUNCTION: call_function, - Opcode.MAKE_FUNCTION: make_function, - Opcode.BUILD_SLICE: build_slice, - Opcode.LOAD_CLOSURE: load_closure, - Opcode.MAKE_CLOSURE: make_closure, - Opcode.LIST_APPEND: list_append, - Opcode.MAP_ADD: map_add, - Opcode.DELETE_ITEM: delete_item, - Opcode.MAKE_SCHEMA: make_schema, - Opcode.BUILD_SCHEMA: build_schema, - Opcode.SCHEMA_ATTR: schema_attr, - Opcode.LOAD_BUILT_IN: load_builtin, - Opcode.COMPARE_OP: compare_op, - Opcode.MAKE_DECORATOR: make_decorator, - Opcode.SCHEMA_LOAD_ATTR: schema_load_attr, - Opcode.SCHEMA_UPDATE_ATTR: schema_update_attr, - Opcode.SCHEMA_NOP: schema_nop, - Opcode.FORMAT_VALUES: format_values, - Opcode.MEMBER_SHIP_AS: member_ship_as, - Opcode.DEBUG_STACK: debug_stack, - Opcode.DEBUG_LOCALS: debug_locals, - Opcode.DEBUG_GLOBALS: debug_globals, - Opcode.DEBUG_NAMES: debug_names, -} diff --git a/internal/kclvm_py/vm/code/code_factory.py b/internal/kclvm_py/vm/code/code_factory.py deleted file mode 100644 index 8905b3199..000000000 --- a/internal/kclvm_py/vm/code/code_factory.py +++ /dev/null @@ -1,243 +0,0 @@ -# Copyright 2021 The KCL Authors. All rights reserved. - -from typing import Optional, List, Tuple -from dataclasses import dataclass, field - -from .code import Opcode - - -@dataclass -class OpcodeContent: - op: Opcode - arg: Optional[int] - arg_list: List[int] - index: int - meta: Tuple[str, int, int] - - @property - def begin_index(self): - return self.index - - @property - def end_index(self): - return self.index + len(self.arg_list) + 1 - - -@dataclass -class OpcodeFactory: - pkgpath: Optional[str] - values: List[OpcodeContent] = field(default_factory=list) - - @property - def begin_index(self): - return self.values[0].begin_index - - @property - def end_index(self): - return self.values[-1].end_index - - def pretty_print(self): - if not self.values: - return - for value in self.values: - print( - ">>> ", - value.op, - "arg:", - value.arg, - "index:", - value.index, - "line", - value.meta[1], - ) - - # --------------------- - # Static methods - # --------------------- - - @staticmethod - def build_from_codes(codes: list, pkgpath: str) -> "OpcodeFactory": - f = OpcodeFactory(pkgpath=pkgpath) - isp = 0 - while codes and isp < len(codes): - code = codes[isp] - opcode_index = isp - isp += 1 - # Skip the invalid opcode - if code == Opcode.INVALID: - continue - arg = None - arg_list = [] - if Opcode.has_arg(code): - arg = codes[isp] + (codes[isp + 1] << 8) + (codes[isp + 2] << 16) - arg_list = [codes[isp], codes[isp + 1], codes[isp + 2]] - isp += 3 - info = codes[isp] - isp += 1 - f.values.append( - OpcodeContent( - op=Opcode(code), - arg=arg, - arg_list=arg_list, - index=opcode_index, - meta=info, - ) - ) - return f - - @staticmethod - def to_codes(contents: List[OpcodeContent]) -> list: - return sum( - [ - [content.op] - + ( - ([content.op] * len(content.arg_list or [])) - if content.op == Opcode.INVALID - else (content.arg_list or []) - ) - + [content.op if content.op == Opcode.INVALID else content.meta] - for content in contents or [] - ], - [], - ) - - -@dataclass -class SchemaBodyOpcodeFactory(OpcodeFactory): - schema_name: str = None - begin_code: List[OpcodeContent] = None - end_code: List[OpcodeContent] = None - - def validate(self) -> bool: - return ( - self.values - and self.values[0].op == Opcode.STORE_LOCAL - and self.values[-1].op == Opcode.RETURN_VALUE - ) - - def update_start_end_code(self) -> "SchemaBodyOpcodeFactory": - if not self.validate(): - raise ValueError("Invalid schema opcode factory") - for i, value in enumerate(self.values): - if value.op == Opcode.SCHEMA_NOP and not self.begin_code: - self.begin_code = self.values[:i] - if value.op == Opcode.RETURN_VALUE: - self.end_code = [value] - return self - - def split_to_schema_attr_codes(self) -> List["SchemaBodyOpcodeFactory"]: - if not self.validate(): - raise ValueError("Invalid schema opcode factory") - results = [] - last_nop_index = 0 - next_nop_index = -1 - if_stack = [False] - if not self.end_code or not self.begin_code: - self.update_start_end_code() - for i, value in enumerate(self.values): - if value.op == Opcode.POP_JUMP_IF_FALSE: - if_stack.append(True) - if value.op == Opcode.JUMP_FORWARD: - if_stack.pop() - if value.op == Opcode.SCHEMA_NOP: - last_nop_index = i - if SchemaBodyOpcodeFactory.is_schema_line_op(value.op): - for j, v in enumerate(self.values[i + 1 :]): - if v.op == Opcode.SCHEMA_NOP: - next_nop_index = i + j + 1 - break - values_append = [] - if if_stack[-1]: - for v in self.values[last_nop_index : next_nop_index + 1]: - if value.index < v.index < self.values[next_nop_index].index: - values_append.append( - OpcodeContent( - op=Opcode.INVALID, - arg=v.arg, - arg_list=v.arg_list, - index=v.index, - meta=v.meta, - ) - ) - else: - values_append.append(v) - else: - values_append = self.values[last_nop_index : next_nop_index + 1] - results.append( - SchemaBodyOpcodeFactory( - pkgpath=self.pkgpath, - schema_name=self.schema_name, - values=values_append, - begin_code=self.begin_code, - end_code=self.end_code, - ) - ) - return results - - def to_run_code_list(self) -> list: - assert self.end_code and self.begin_code - # Single attribute code - begin_codes = OpcodeFactory.to_codes(self.begin_code) - end_codes = OpcodeFactory.to_codes(self.end_code) - codes = OpcodeFactory.to_codes(self.values) - start_to_code_count = self.values[0].index - self.begin_code[-1].end_index - 1 - code_to_end_count = self.end_code[0].index - self.values[-1].end_index - 1 - return ( - begin_codes - + [Opcode.INVALID] * start_to_code_count - + codes - + [Opcode.INVALID] * code_to_end_count - + end_codes - ) - - def pretty_print(self): - if not self.values: - return - RED = "\033[31m" - GREEN = "\033[32m" - BLUE = "\033[34m" - BOLD = "\033[1m" - RESET = "\033[m" - found_nop = False - for value in self.values: - if value.op == Opcode.SCHEMA_NOP: - found_nop = True - print(f"{BOLD}{GREEN}", end="") - elif value.op == Opcode.RETURN_VALUE or not found_nop: - print(f"{BOLD}{RED}", end="") - else: - print(f"{BOLD}{BLUE}", end="") - print( - ">>> ", - value.op, - "arg:", - value.arg, - "index:", - value.index, - "line", - value.meta[1], - ) - print(f"{RESET}") - - # --------------------- - # Static methods - # --------------------- - - @staticmethod - def is_schema_line_op(op: int): - return ( - op == Opcode.SCHEMA_ATTR - or op == Opcode.SCHEMA_UPDATE_ATTR - or op == Opcode.STORE_ATTR - ) - - @staticmethod - def build_from_codes( - codes: list, pkgpath: str, schema_name: str - ) -> "SchemaBodyOpcodeFactory": - ctx = OpcodeFactory.build_from_codes(codes, pkgpath) - return SchemaBodyOpcodeFactory( - pkgpath=ctx.pkgpath, - schema_name=schema_name, - values=ctx.values, - ) diff --git a/internal/kclvm_py/vm/planner/__init__.py b/internal/kclvm_py/vm/planner/__init__.py deleted file mode 100644 index f03b91f76..000000000 --- a/internal/kclvm_py/vm/planner/__init__.py +++ /dev/null @@ -1,8 +0,0 @@ -from .plan import ( - ObjectPlanner, - JSONPlanner, - YAMLPlanner, - plan, -) - -__all__ = ["ObjectPlanner", "JSONPlanner", "YAMLPlanner", "plan"] diff --git a/internal/kclvm_py/vm/planner/plan.py b/internal/kclvm_py/vm/planner/plan.py deleted file mode 100644 index db1fb3e83..000000000 --- a/internal/kclvm_py/vm/planner/plan.py +++ /dev/null @@ -1,309 +0,0 @@ -import io -import json -import inspect - -from dataclasses import dataclass -from collections import OrderedDict -from typing import Dict, List -from ruamel.yaml import YAML - -import kclvm -import kclvm.config -import kclvm.api.object as obj - -from kclvm.api.object.internal import Undefined, UndefinedType -from kclvm.api.object.schema import ( - SETTINGS_OUTPUT_KEY, - SCHEMA_SETTINGS_ATTR_NAME, -) - - -KCL_PLAN_TYPE = [ - obj.KCLObjectType.INTEGER, # int - obj.KCLObjectType.FLOAT, # float - obj.KCLObjectType.STRING, # string - obj.KCLObjectType.BOOLEAN, # True, False - obj.KCLObjectType.NUMBER_MULTIPLIER, # 1M, 1Ki - obj.KCLObjectType.NONE, # None - obj.KCLObjectType.UNDEFINED, # Undefined - obj.KCLObjectType.DICT, # dict - obj.KCLObjectType.LIST, # list - obj.KCLObjectType.SCHEMA, # dict with __settings__ -] -LIST_DICT_TEMP_KEY = "$" - - -def is_kcl_schema(value: dict): - return ( - value is not None - and isinstance(value, dict) - and SCHEMA_SETTINGS_ATTR_NAME in value - ) - - -def order_dict(d: any) -> dict: - result = {} - for k, v in sorted(d.items()): - if isinstance(v, dict): - result[k] = order_dict(v) - else: - result[k] = v - return result - - -def handle_schema(value: dict): - # on kcl schema - filtered = filter_results(value) - if filtered is None: - return filtered, False - settings = SCHEMA_SETTINGS_ATTR_NAME - output_type = SETTINGS_OUTPUT_KEY - if settings in value and value[settings][output_type] == obj.SETTINGS_OUTPUT_IGNORE: - if len(filtered) <= 1: - return None, False - else: - return filtered[1:], True - standalone = False - if ( - settings in value - and value[settings][output_type] == obj.SETTINGS_OUTPUT_STANDALONE - ): - standalone = True - return filtered, standalone - - -def filter_results(keyvalues: dict) -> List[dict]: - if keyvalues is None: - return None - - # index 0 for in-line keyvalues output, index 1: for standalone keyvalues outputs - results = [OrderedDict()] - - for key, value in keyvalues.items(): - if value is None and kclvm.config.disable_none: - continue - if isinstance(key, str) and key.startswith("_"): - pass - elif value is Undefined or isinstance(value, UndefinedType): - pass - elif inspect.isclass(value): - pass - elif inspect.isfunction(value): - pass - elif inspect.ismodule(value): - pass - elif inspect.isfunction(value): - pass - elif is_kcl_schema(value): - filtered, standalone = handle_schema(value) - if filtered is not None: - if standalone: - # if the instance is marked as 'STANDALONE', treat it as a separate one and - # extend it and derived STANDALONE instances to results. - results.extend(filtered) - else: - # else put it as the value of the key of results - if len(results) > 0 and len(filtered) > 0: - results[0][key] = filtered[0] - if len(filtered) > 1: - # if the value has derived 'STANDALONE' instances, extend them - results.extend(filtered[1:]) - elif isinstance(value, dict): - filtered = filter_results(value) - if len(results) > 0 and len(filtered) > 0: - results[0][key] = filtered[0] - if len(results) > 0 and len(filtered) > 1: - # if the value has derived 'STANDALONE' instances, extend them - results.extend(filtered[1:]) - elif isinstance(value, list): - filtered_list = [] - standalone_list = [] - ignore_schema_count = 0 - for i in value: - if is_kcl_schema(i): - filtered, standalone = handle_schema(i) - if filtered is None: - ignore_schema_count += 1 - continue - if filtered: - if standalone: - standalone_list.extend(filtered) - else: - filtered_list.extend(filtered) - elif isinstance(i, dict): - filtered = filter_results(i) - if filtered: - filtered_list.extend(filtered) - elif i is None and kclvm.config.disable_none: - continue - elif not isinstance(i, UndefinedType): - # Filter list elements - filtered = filter_results({LIST_DICT_TEMP_KEY: i}) - if ( - len(results) > 0 - and len(filtered) > 0 - and LIST_DICT_TEMP_KEY in filtered[0] - ): - filtered_list.append(filtered[0][LIST_DICT_TEMP_KEY]) - if len(results) > 0 and len(filtered) > 1: - # if the value has derived 'STANDALONE' instances, extend them - results.extend(filtered[1:]) - schema_in_list_count = ignore_schema_count + len(standalone_list) - if len(results) > 0 and 0 <= schema_in_list_count < len(value): - results[0][key] = filtered_list - if standalone_list: - results.extend(standalone_list) - else: - results[0][key] = value - return results - - -@dataclass -class ObjectPlanner: - """Planner is used to modify VM exec result to YAML""" - - def __init__( - self, *, sort_keys: bool = False, include_schema_type_path: bool = False - ) -> None: - self.sort_keys = sort_keys - self.include_schema_type_path = include_schema_type_path - - def to_python(self, v): - if isinstance(v, obj.KCLObject): - if isinstance(v, obj.KCLLiteralObject): - return v.value - elif isinstance(v, obj.KCLSchemaObject): - result = {_k: self.to_python(_v) for _k, _v in v.attrs.items()} - if self.include_schema_type_path: - result["@type"] = v.full_type_str() - return result - elif isinstance(v, (obj.KCLListObject, obj.KCLTupleObject)): - return [self.to_python(_v) for _v in v.value] - elif isinstance(v, obj.KCLDictObject): - return {_k: self.to_python(_v) for _k, _v in v.value.items()} - elif isinstance(v, (obj.KCLUndefinedObject, obj.KCLFunctionObject)): - return Undefined - elif isinstance(v, obj.KCLNameConstantObject): - return v.value - else: - return Undefined - elif isinstance(v, (list, tuple, set)): - return [self.to_python(_v) for _v in v] - elif isinstance(v, dict): - return {_k: self.to_python(_v) for _k, _v in v.items()} - elif isinstance(v, (int, float, str, bool)) or v is None: - return v - elif v is Undefined or isinstance(v, UndefinedType): - return v - else: - raise Exception("Invalid KCL Object") - - def plan(self, var_dict: Dict[str, obj.KCLObject]) -> Dict[str, any]: - assert isinstance(var_dict, dict) - data = { - k: self.to_python(v) - for k, v in var_dict.items() - if v and v.type() in KCL_PLAN_TYPE - } - return data - - -@dataclass -class YAMLPlanner(ObjectPlanner): - def __init__( - self, *, sort_keys: bool = False, include_schema_type_path: bool = False - ) -> None: - super().__init__( - sort_keys=sort_keys, include_schema_type_path=include_schema_type_path - ) - - def plan(self, var_dict: Dict[str, obj.KCLObject], to_py: bool = True) -> str: - assert isinstance(var_dict, dict) - plan_obj = super().plan(var_dict) if to_py else var_dict - # Represent OrderedDict as dict. - yaml = YAML() - yaml.representer.add_representer( - OrderedDict, - lambda dumper, data: dumper.represent_mapping( - "tag:yaml.org,2002:map", data - ), - ) - # Convert tuple to list. - yaml.representer.add_representer( - tuple, - lambda dumper, data: dumper.represent_sequence( - "tag:yaml.org,2002:seq", data - ), - ) - # Convert None to null - yaml.representer.add_representer( - type(None), - lambda dumper, data: dumper.represent_scalar( - u"tag:yaml.org,2002:null", u"null" - ), - ) - yaml.representer.add_representer( - str, - lambda dumper, data: dumper.represent_scalar( - u"tag:yaml.org,2002:str", data, style="|" - ) - if "\n" in data - else dumper.represent_str(data), - ) - results = filter_results(plan_obj) - if self.sort_keys: - results = [order_dict(r) for r in results] - outputs = "" - with io.StringIO() as buf: - if results: - for result in results[:-1]: - if result: - yaml.dump(result, buf) - buf.write("---\n") - if results[-1]: - yaml.dump(results[-1], buf) - outputs = buf.getvalue() - return outputs - - -class JSONPlanner(ObjectPlanner): - def __init__( - self, *, sort_keys: bool = False, include_schema_type_path: bool = False - ) -> None: - super().__init__( - sort_keys=sort_keys, include_schema_type_path=include_schema_type_path - ) - - def plan( - self, - var_dict: Dict[str, obj.KCLObject], - *, - only_first=False, - to_py: bool = True - ) -> str: - assert isinstance(var_dict, dict) - plan_obj = super().plan(var_dict) if to_py else var_dict - results = filter_results(plan_obj) - if self.sort_keys: - results = [order_dict(r) for r in results] - results = [r for r in results if r] - return ( - json.dumps( - results if not only_first else results[0], - default=lambda o: o.__dict__, - indent=4, - ) - if results - else "" - ) - - -def plan( - val_map: Dict[str, obj.KCLObject], - *, - sort_keys: bool = False, - include_schema_type_path: bool = False -) -> str: - return YAMLPlanner( - sort_keys=sort_keys, include_schema_type_path=include_schema_type_path - ).plan(val_map) diff --git a/internal/kclvm_py/vm/runtime/README.md b/internal/kclvm_py/vm/runtime/README.md deleted file mode 100644 index 312aa053b..000000000 --- a/internal/kclvm_py/vm/runtime/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# KCLVM Runtime - -This module provides the runtime for KCLVM. diff --git a/internal/kclvm_py/vm/runtime/__init__.py b/internal/kclvm_py/vm/runtime/__init__.py deleted file mode 100644 index d74aaf8ad..000000000 --- a/internal/kclvm_py/vm/runtime/__init__.py +++ /dev/null @@ -1 +0,0 @@ -# Copyright 2021 The KCL Authors. All rights reserved. diff --git a/internal/kclvm_py/vm/runtime/evaluator/__init__.py b/internal/kclvm_py/vm/runtime/evaluator/__init__.py deleted file mode 100644 index d72cbbed1..000000000 --- a/internal/kclvm_py/vm/runtime/evaluator/__init__.py +++ /dev/null @@ -1,12 +0,0 @@ -from .union import union, merge -from .common import handle_subscript -from .lazy import ValueCache, Backtracking, SchemaEvalContext - -__all__ = [ - "union", - "merge", - "handle_subscript", - "ValueCache", - "SchemaEvalContext", - "Backtracking", -] diff --git a/internal/kclvm_py/vm/runtime/evaluator/common.py b/internal/kclvm_py/vm/runtime/evaluator/common.py deleted file mode 100644 index 275866281..000000000 --- a/internal/kclvm_py/vm/runtime/evaluator/common.py +++ /dev/null @@ -1,25 +0,0 @@ -from kclvm.api.object import ( - KCLObject, - KCLStringObject, - KCLListObject, - KCLDictObject, - KCLSchemaObject, - to_python_obj, - to_kcl_obj, -) - - -def plus(left: KCLObject, right: KCLObject): - if isinstance(left, KCLStringObject) and isinstance(right, KCLStringObject): - return KCLStringObject(value=left.value + right.value) - if isinstance(left, KCLListObject) and isinstance(right, KCLListObject): - return KCLListObject(items=left.items + right.items) - return to_kcl_obj(to_python_obj(left) + to_python_obj(right)) - - -def handle_subscript(obj: KCLObject, slice: KCLObject): - return to_kcl_obj( - obj.get(to_python_obj(slice)) - if isinstance(obj, (KCLDictObject, KCLSchemaObject)) - else obj.value[to_python_obj(slice)] - ) diff --git a/internal/kclvm_py/vm/runtime/evaluator/eval.py b/internal/kclvm_py/vm/runtime/evaluator/eval.py deleted file mode 100644 index 3e6cbbfb4..000000000 --- a/internal/kclvm_py/vm/runtime/evaluator/eval.py +++ /dev/null @@ -1,429 +0,0 @@ -from dataclasses import dataclass -from typing import List, Tuple, Union, cast -from copy import deepcopy - -import kclvm.kcl.error as kcl -import kclvm.kcl.ast as ast -import kclvm.api.object as objpkg -from kclvm.vm.code import Opcode -from kclvm.compiler.check.check_type import type_pack_and_check -from kclvm.compiler.extension.builtin.system_module import json as _json -from kclvm.compiler.extension.builtin.system_module import yaml as _yaml - -from .union import union, resolve_schema_obj -from .common import plus, handle_subscript - - -BINARY_FUNCTIONS = { - Opcode.BINARY_ADD: lambda x, y: plus(x, y), - Opcode.BINARY_SUBTRACT: lambda x, y: x - y, - Opcode.BINARY_MULTIPLY: lambda x, y: x * y, - Opcode.BINARY_TRUE_DIVIDE: lambda x, y: x / y, - Opcode.BINARY_FLOOR_DIVIDE: lambda x, y: x // y, - Opcode.BINARY_LSHIFT: lambda x, y: x << y, - Opcode.BINARY_RSHIFT: lambda x, y: x >> y, - Opcode.BINARY_POWER: lambda x, y: x ** y, - Opcode.BINARY_SUBSCR: lambda x, y: handle_subscript(x, y), - Opcode.BINARY_XOR: lambda x, y: x ^ y, - Opcode.BINARY_AND: lambda x, y: x & y, - Opcode.BINARY_OR: lambda x, y: union(x, y), - Opcode.BINARY_MODULO: lambda x, y: x % y, - Opcode.BINARY_LOGIC_AND: lambda x, y: x and y, - Opcode.BINARY_LOGIC_OR: lambda x, y: x or y, - Opcode.COMPARE_EQUAL_TO: lambda x, y: x == y, - Opcode.COMPARE_NOT_EQUAL_TO: lambda x, y: x != y, - Opcode.COMPARE_LESS_THAN: lambda x, y: x < y, - Opcode.COMPARE_LESS_THAN_OR_EQUAL_TO: lambda x, y: x <= y, - Opcode.COMPARE_GREATER_THAN: lambda x, y: x > y, - Opcode.COMPARE_GREATER_THAN_OR_EQUAL_TO: lambda x, y: x >= y, - Opcode.COMPARE_IS: lambda x, y: x is y, - Opcode.COMPARE_IS_NOT: lambda x, y: x is not y, - Opcode.COMPARE_IN: lambda x, y: x in y, - Opcode.COMPARE_NOT_IN: lambda x, y: x not in y, -} - -UNARY_FUNCTIONS = { - Opcode.UNARY_INVERT: lambda x: ~x, - Opcode.UNARY_NOT: lambda x: not x, - Opcode.UNARY_POSITIVE: lambda x: +x, - Opcode.UNARY_NEGATIVE: lambda x: -x, -} - -INPLACE_FUNCTIONS = { - Opcode.INPLACE_ADD: lambda x, y: plus(x, y), - Opcode.INPLACE_SUBTRACT: lambda x, y: x - y, - Opcode.INPLACE_MULTIPLY: lambda x, y: x * y, - Opcode.INPLACE_TRUE_DIVIDE: lambda x, y: x / y, - Opcode.INPLACE_FLOOR_DIVIDE: lambda x, y: x // y, - Opcode.INPLACE_LSHIFT: lambda x, y: x << y, - Opcode.INPLACE_RSHIFT: lambda x, y: x >> y, - Opcode.INPLACE_POWER: lambda x, y: x ** y, - Opcode.INPLACE_XOR: lambda x, y: x ^ y, - Opcode.INPLACE_AND: lambda x, y: x & y, - Opcode.INPLACE_OR: lambda x, y: union(x, y), - Opcode.INPLACE_MODULO: lambda x, y: x % y, -} - - -@dataclass -class Evaluator: - """Evaluator is a class responsible for parsing - KCL objects and performing interpretation to get results - """ - - # Binary - - def eval_binary_op( - self, - left: objpkg.KCLObject, - right: objpkg.KCLObject, - code: Union[int, Opcode], - vm=None, - ) -> objpkg.KCLObject: - if not left or not right or not code: - raise Exception(f"invalid binary opcode action {left}, {right} and {code}") - func = BINARY_FUNCTIONS.get(code) - if not func: - raise Exception(f"invalid binary opcode {code}") - if code == Opcode.BINARY_OR: - result = union( - deepcopy(left), - right, - or_mode=True, - should_config_resolve=True, - should_idempotent_check=True, - vm=vm, - ) - elif code == Opcode.BINARY_ADD or code == Opcode.BINARY_SUBSCR: - result = func(left, right) - else: - result = objpkg.to_kcl_obj( - func(objpkg.to_python_obj(left), objpkg.to_python_obj(right)) - ) - return result - - # Unary - - def eval_unary_op( - self, obj: objpkg.KCLObject, code: Union[int, Opcode] - ) -> objpkg.KCLObject: - if not obj or not code: - raise Exception(f"invalid binary opcode action {obj} and {code}") - func = UNARY_FUNCTIONS.get(code) - if not func: - raise Exception(f"invalid unary opcode {code}") - r = objpkg.to_kcl_obj(func(obj.value)) - return r - - # Inplace operator - - def eval_inplace_op( - self, - left: objpkg.KCLObject, - right: objpkg.KCLObject, - code: Union[int, Opcode], - vm=None, - ) -> objpkg.KCLObject: - if not left or not right or not code: - raise Exception(f"invalid inpalce opcode action {left}, {right} and {code}") - func = INPLACE_FUNCTIONS.get(code) - if not func: - raise Exception(f"invalid inplace opcode {code}") - if code == Opcode.INPLACE_OR: - result = union( - left, - right, - or_mode=True, - should_config_resolve=True, - should_idempotent_check=True, - vm=vm, - ) - elif code == Opcode.INPLACE_ADD: - result = func(left, right) - else: - result = objpkg.to_kcl_obj( - func( - objpkg.to_python_obj(left.value), objpkg.to_python_obj(right.value) - ) - ) - return result - - # Compare - - def eval_compare_op( - self, - left: objpkg.KCLObject, - right: objpkg.KCLObject, - code: Union[int, Opcode], - vm=None, - ) -> objpkg.KCLObject: - # Avoid the overhead of boxing and unboxing large objects. - if isinstance(right, (objpkg.KCLDictObject, objpkg.KCLSchemaObject)): - if code == Opcode.COMPARE_IN: - return objpkg.to_kcl_obj(left in right) - elif code == Opcode.COMPARE_NOT_IN: - return objpkg.to_kcl_obj(left not in right) - else: - return self.eval_binary_op(left, right, code, vm=vm) - else: - return self.eval_binary_op(left, right, code, vm=vm) - - # Iterable - - def iter_next(self, obj: objpkg.KCLObject) -> objpkg.KCLObject: - if obj.type() != objpkg.KCLObjectType.ITER: - kcl.report_exception( - err_type=kcl.ErrType.EvaluationError_TYPE, - arg_msg="only iterable object has next function", - ) - return objpkg.to_kcl_obj(obj.next()) - - # Functions - - def call_vars_and_keywords( - self, argc: int, vm - ) -> Tuple[List[objpkg.KCLObject], List[objpkg.KWArg]]: - n_args = int(argc & 0xFF) - n_kwargs = int((argc >> 8) & 0xFF) - p, q = len(vm.stack) - 2 * n_kwargs, len(vm.stack) - args = [] - kwargs = [] - for i in range((q - p) // 2 - 1, -1, -1): - v = vm.pop() - kstr = vm.pop() - kwargs.append(objpkg.KWArg(name=kstr, value=v)) - p, q = p - n_args, p - for i in range(q - p - 1, -1, -1): - arg = vm.pop() - args.append(arg) - return args[::-1], kwargs[::-1] - - def eval_call(self, code: Union[int, Opcode], argc: int, vm) -> objpkg.KCLObject: - if code == Opcode.CALL_FUNCTION: - # Function callable without `*args` and `**kwargs` - args, kwargs = self.call_vars_and_keywords(argc, vm) - callable_obj = vm.pop() - if isinstance(callable_obj, objpkg.KCLCompiledFunctionObject): - vm.push_frame_using_callable( - callable_obj.pkgpath, - callable_obj, - (args if args else []), - kwargs, - args_len=len(args), - ) - return objpkg.NONE_INSTANCE - elif isinstance(callable_obj, objpkg.KCLFunctionObject): - result_obj = callable_obj.call(args, kwargs, vm) - vm.push(result_obj) - return result_obj - elif isinstance(callable_obj, objpkg.KCLSchemaTypeObject): - schema_type_obj = cast(objpkg.KCLSchemaTypeObject, callable_obj) - inst = schema_type_obj.new_instance({}, {}, args, kwargs, vm) - vm.push(inst) - return inst - elif isinstance( - callable_obj, (objpkg.KCLNoneObject, objpkg.KCLUndefinedObject) - ): - # Ignore the user None callable - vm.push(callable_obj) - return callable_obj - else: - kcl.report_exception( - err_type=kcl.ErrType.EvaluationError_TYPE, - arg_msg=f"'{callable_obj.type()}' object is not callable", - ) - - # Attribute and subscript - - def load_attr(self, obj: objpkg.KCLObject, attr: str) -> objpkg.KCLObject: - """Get attribute value of a KCL object""" - if obj.type() in [ - objpkg.KCLObjectType.DICT, - objpkg.KCLObjectType.SCHEMA, - objpkg.KCLObjectType.MODULE, - ]: - return obj.get(attr) - elif obj.type() in [ - objpkg.KCLObjectType.STRING, - objpkg.KCLObjectType.SCHEMA_TYPE, - ]: - return obj.get_member_method(attr) - else: - kcl.report_exception( - err_type=kcl.ErrType.EvaluationError_TYPE, - arg_msg=f"'{obj.type_str()}' object has no attribute '{attr}'", - ) - - def set_attr( - self, - obj: objpkg.KCLObject, - item: objpkg.KCLObject, - value: objpkg.KCLObject, - vm=None, - ) -> objpkg.KCLObject: - """Set attribute value of KCL object""" - if not isinstance(obj, (objpkg.KCLDictObject, objpkg.KCLSchemaObject)): - kcl.report_exception( - err_type=kcl.ErrType.EvaluationError_TYPE, - arg_msg="only schema and dict object can be updated attribute", - ) - obj.update_key_value(item, value) - if isinstance(obj, objpkg.KCLSchemaObject): - obj = resolve_schema_obj(obj, obj.config_keys | {item.value}, vm=vm) - return obj - - def set_item( - self, obj: objpkg.KCLObject, item: objpkg.KCLObject, value: objpkg.KCLObject - ) -> objpkg.KCLObject: - """Set subscript value of a KCL object""" - obj.value[item.value] = value - return obj - - # List - - def list_append( - self, obj: objpkg.KCLObject, item: objpkg.KCLObject - ) -> objpkg.KCLObject: - """Append an item into list""" - if obj.type() != objpkg.KCLObjectType.LIST: - kcl.report_exception( - err_type=kcl.ErrType.EvaluationError_TYPE, - arg_msg="only list object can append value", - ) - obj.append(item) - return obj - - # Dict - - def dict_append( - self, obj: objpkg.KCLObject, key: objpkg.KCLObject, value: objpkg.KCLObject - ) -> objpkg.KCLObject: - """Append an key-value pair into dict""" - if obj.type() != objpkg.KCLObjectType.DICT: - if obj.type() != objpkg.KCLObjectType.LIST: - kcl.report_exception( - err_type=kcl.ErrType.EvaluationError_TYPE, - arg_msg="only dict object can append key-value pair", - ) - obj.update_key_value(key, value) - return obj - - # String Format value - - def format_value( - self, obj: objpkg.KCLObject, format_spec: str - ) -> objpkg.KCLStringObject: - if not format_spec: - value = "{}".format(objpkg.to_python_obj(obj)) - return objpkg.KCLStringObject(value=value) - assert isinstance(format_spec, str) - if format_spec.lower() == "#json": - value = _json.KMANGLED_encode(objpkg.to_python_obj(obj)) - return objpkg.KCLStringObject(value=value) - if format_spec.lower() == "#yaml": - value = _yaml.KMANGLED_encode(objpkg.to_python_obj(obj)) - return objpkg.KCLStringObject(value=value) - kcl.report_exception( - err_type=kcl.ErrType.InvalidFormatSpec_TYPE, - arg_msg=kcl.INVALID_FORMAT_SPEC_MSG.format(format_spec), - ) - - # Schema config operation expression - - def update_schema_attr( - self, - attr: str, - schema_obj: objpkg.KCLSchemaObject, - config_value: objpkg.KCLObject, - conf_meta: dict, - expected_types: List[str], - operation=ast.ConfigEntryOperation.UNION, - index=None, - vm=None, - filename=None, - lineno=None, - columnno=None, - ): - """Update schema attr value with config dict""" - if index is None or index < 0: - config_value_checked = type_pack_and_check( - config_value, - expected_types, - vm=vm, - filename=filename, - lineno=lineno, - columno=columnno, - config_meta=conf_meta.get("$conf_meta"), - ) - else: - value = schema_obj.get(attr) - if not isinstance(value, objpkg.KCLListObject): - kcl.report_exception( - err_type=kcl.ErrType.EvaluationError_TYPE, - arg_msg="only list attribute can be inserted value", - ) - config_value_checked = type_pack_and_check( - objpkg.KCLListObject(items=[config_value]), - expected_types, - vm=vm, - filename=filename, - lineno=lineno, - columno=columnno, - config_meta=conf_meta.get("$conf_meta"), - ) - config_value_checked = cast( - objpkg.KCLListObject, config_value_checked - ).items[0] - SCHEMA_CONFIG_OP_MAPPING = { - ast.ConfigEntryOperation.UNION: self.union_schema_attr, - ast.ConfigEntryOperation.OVERRIDE: self.override_schema_attr, - ast.ConfigEntryOperation.INSERT: self.insert_schema_attr, - } - func = SCHEMA_CONFIG_OP_MAPPING.get(operation) - if not func: - raise Exception(f"Invalid schema config object operation: {operation}") - func(attr, schema_obj, config_value_checked, index, vm) - - def union_schema_attr( - self, - attr: str, - schema_obj: objpkg.KCLSchemaObject, - config_value: objpkg.KCLObject, - index=None, - vm=None, - ): - if index is None or index < 0: - # TODO: modify `should_idempotent_check` to False after Konfig code update finish - schema_obj.union_with({attr: config_value}, should_idempotent_check=False) - else: - # Union with list internal index value - value = schema_obj.get(attr) - value.items[index] = union( - value.items[index], config_value, should_idempotent_check=False, vm=vm - ) - schema_obj.union_with({attr: value}, should_idempotent_check=False) - - def override_schema_attr( - self, - attr: str, - schema_obj: objpkg.KCLSchemaObject, - config_value: objpkg.KCLObject, - index=None, - vm=None, - ): - if index is None or index < 0: - schema_obj.update_key_value(attr, config_value) - else: - schema_obj.list_key_override(attr, config_value, index) - - def insert_schema_attr( - self, - attr: str, - schema_obj: objpkg.KCLSchemaObject, - config_value: objpkg.KCLObject, - index=None, - vm=None, - ): - if index is not None and index >= 0: - config_value = objpkg.KCLListObject(items=[config_value]) - schema_obj.insert_with(attr, config_value, index) diff --git a/internal/kclvm_py/vm/runtime/evaluator/lazy.py b/internal/kclvm_py/vm/runtime/evaluator/lazy.py deleted file mode 100644 index 01a59365c..000000000 --- a/internal/kclvm_py/vm/runtime/evaluator/lazy.py +++ /dev/null @@ -1,461 +0,0 @@ -# Copyright 2021 The KCL Authors. All rights reserved. - -import inspect - -from dataclasses import dataclass, field -from typing import List, Dict, Union, Optional, Callable, TypeVar -from enum import IntEnum - -import kclvm.kcl.error as kcl_error -import kclvm.api.object as obj -import kclvm.vm.code as vm_code -import kclvm.compiler.extension.builtin as builtin - - -# -------------------- -# Type alias -# -------------------- - -SchemaKeyNativeType = Union[str, int, float] -SchemaKeyObjectType = Union[obj.KCLStringObject, obj.KCLIntObject, obj.KCLFloatObject] -SchemaKeyType = Union[SchemaKeyNativeType, SchemaKeyObjectType] -VirtualMachine = TypeVar("vm.VirtualMachine") - - -# ------------------------------------ -# Schema attribute value place holder -# ------------------------------------ - - -class ValuePlaceHolderPriority(IntEnum): - """ - Value place holder override priority (Ascending) - ------------------------------------------------ - 1. base_default (default value of the base class schema attribute) - 2. base_templating (base schema writing general expression context) - 3. base_mixin (base class schema attribute) - 4. sub_default (the default value of the schema attribute of the subclass) - 5. sub_templating (subclass schema writing general expression context) - 6. sub_mixin (context of subclass schema) - 7. config (schema instantiation configuration value) - """ - - BASE_DEFAULT = 1 - BASE_TEMPLATING = 2 - BASE_MIXIN = 3 - SUB_DEFAULT = 4 - SUB_TEMPLATING = 5 - SUB_MIXIN = 6 - CONFIG = 7 - - -@dataclass -class ValuePlaceHolder: - """The real value of the schema attribute can be regarded - as a placeholder for a non-literal expression before it is calculated - - Please note that all optional attribute checks, relaxed attr append, - schema index signature and decorator execution and check block are executed - after the calculation of the above process is completed. - """ - - name: str # Attribute name - priority: ValuePlaceHolderPriority - types: List[str] = field(default_factory=list) # Attribute type annotation list - value: obj.KCLObject = None # Actual value - config_value: obj.KCLObject = None # Config value - codes: List[vm_code.SchemaBodyOpcodeFactory] = field( - default_factory=list - ) # VM eval byte codes - - -# -------------------- -# Cache definition -# -------------------- - - -class ValueCache: - """Key-value pair cache - - The key is a valid key type including `str`, `int` and `float` - - The value is a KCL object - """ - - def __init__(self): - self._cache: Dict[SchemaKeyNativeType, obj.KCLObject] = {} - - def __getitem__(self, key): - return self.get(key) - - def __contains__(self, key): - return key in self._cache - - def clear(self): - self._cache.clear() - - def get( - self, key: SchemaKeyNativeType, eval_func: Callable = None, *args, **kwargs - ) -> Optional[obj.KCLObject]: - """Get the value from the cache. When the parameter `eval_func` is - provided and there is no such value in the cache, the value is calculated - by calling `eval_func` - """ - if key not in self._cache and eval_func and inspect.isfunction(eval_func): - self._cache[key] = eval_func(*args, **kwargs) - return self._cache.get(key) - - def set(self, key: SchemaKeyNativeType, value: obj.KCLObject): - if not key: - raise ValueError(f"Invalid key {key}") - if not value or not isinstance(value, obj.KCLObject): - raise ValueError(f"Invalid kcl object {value}") - self._cache[key] = value - - -# -------------------- -# Backtracking -# -------------------- - - -@dataclass -class Backtracking: - """Backtracking calculation set - - `__enter__` and `__exit__` function can be used as follows: - - backtracking = Backtracking() - with backtracking.catch(name): - assert Backtracking.tracking_level(name) == 1 - with backtracking.catch(name): - assert Backtracking.tracking_level(name) == 2 - assert Backtracking.tracking_level(name) == 1 - assert Backtracking.tracking_level(name) == 0 - """ - - _set: dict = field(default_factory=dict) - _key: Optional[str] = None - - def __enter__(self): - if self._key not in self._set: - self._set[self._key] = 1 - else: - self._set[self._key] += 1 - - def __exit__(self, e_t, e_v, t_b): - if self._key in self._set: - self._set[self._key] -= 1 - if self._set[self._key] == 0: - del self._set[self._key] - - def catch(self, key: str): - self._key = key - return self - - def is_backtracking(self, key: str): - return key in self._set and self.tracking_level(key) > 0 - - def tracking_level(self, key: str): - return self._set.get(key, 0) - - def reset(self): - self._set.clear() - - -# -------------------- -# Schema eval context -# -------------------- - - -@dataclass -class SchemaEvalContext: - """Schema irrelevant order calculation context - - TODO: Need to be combined with configuration merging technology and - move it into the compiler stage. - """ - - type_obj: obj.KCLSchemaTypeObject - schema_obj: obj.KCLSchemaObject - config: obj.KCLDictObject - config_meta: dict - args: List[obj.KCLObject] - kwargs: List[obj.KWArg] - vm: VirtualMachine - cache: ValueCache = ValueCache() - - place_holder_map: Dict[str, ValuePlaceHolder] = None - backtracking: Backtracking = Backtracking() - - def eval_reset(self): - """Eval status reset to prevent reference interference""" - self.cache.clear() - self.backtracking.reset() - - # ---------------------------- - # Code to value place holders - # ---------------------------- - - def code_to_place_holder( - self, - code: vm_code.SchemaBodyOpcodeFactory, - name: str, - priority: ValuePlaceHolderPriority, - ) -> ValuePlaceHolder: - """Covert schema body code to value place holder""" - assert ( - name - and isinstance(name, str) - and code - and isinstance(code, vm_code.SchemaBodyOpcodeFactory) - ) - place_holder = ValuePlaceHolder( - name=name, - priority=priority, - types=self.schema_obj.get_attr_type(name), - codes=[code], - config_value=self.config.get(name), - ) - return place_holder - - def get_all_place_holders(self) -> Dict[str, ValuePlaceHolder]: - """Get all schema attribute value place holders""" - self.place_holder_map = self.get_place_holders_by_type_obj( - self.type_obj, {}, ValuePlaceHolderPriority.SUB_DEFAULT - ) - return self.place_holder_map - - def get_place_holders_by_type_obj( - self, - type_obj: obj.KCLSchemaTypeObject, - map_ref: dict, - priority: ValuePlaceHolderPriority, - ) -> Dict[str, ValuePlaceHolder]: - """Get schema place holders using the schema type object""" - if not type_obj or not isinstance(type_obj, obj.KCLSchemaTypeObject): - return {} - # Get the base schema place holders - if type_obj.base: - self.get_place_holders_by_type_obj( - type_obj.base, map_ref, ValuePlaceHolderPriority.BASE_DEFAULT - ) - code_factory = vm_code.SchemaBodyOpcodeFactory.build_from_codes( - type_obj.func.instructions, - type_obj.pkgpath, - type_obj.name, - ) - # Split opcodes into key-value pair `{attr_name}-{opcode_list}` - codes = code_factory.split_to_schema_attr_codes() - assert len(codes) == len( - type_obj.attr_list - ), f"{len(codes)} != {len(type_obj.attr_list)}" - for i, code in enumerate(codes): - place_holder = self.code_to_place_holder( - code, type_obj.attr_list[i], priority + 1 - ) - if ( - place_holder - and place_holder.name in map_ref - and place_holder.priority >= map_ref[place_holder.name].priority - ): - # Schema attribute multi-override - map_ref[place_holder.name].codes.extend(place_holder.codes) - else: - # First default value place holder - map_ref[place_holder.name] = place_holder - # Get the mixin place holders - for mixin in type_obj.mixins or []: - self.get_place_holders_by_type_obj(mixin, map_ref, priority + 2) - return map_ref - - # ---------------------------- - # Back track - # ---------------------------- - - def back_track(self, name: str, place_holder: ValuePlaceHolder): - if not name or not place_holder: - return - try: - if self.backtracking.is_backtracking(name): - pass - """ - # Please note that KCL variable reference is not considered a self circular reference, - # and the value may be overwritten such as `a = 1; a += 2` will be treated as `a = 1 + 2` - raise kcl_error.KCLRuntimeError( - "RecursionError", None, None, None, f"Attribute '{name}' reference cycle" - ) - """ - with self.backtracking.catch(name): - # Number of variable backtracking - level = self.backtracking.tracking_level(name) - # Get the place holder code. Please note the negative index `-level` - # because the later value place holders are placed at the end of the array - code: vm_code.SchemaBodyOpcodeFactory = place_holder.codes[-level] - # Run schema attribute place holder code - self.vm_run_schema_code(code) - # When the traceback ends, save the value to the cache - self.cache.set(name, self.schema_obj.get(name)) - except IndexError: - kcl_error.report_exception( - err_type=kcl_error.ErrType.RecursionError_TYPE, - arg_msg=f"Attribute '{name}' reference cycle", - ) - - # ------------------------------- - # Schema Attribute Getter/Setter - # ------------------------------- - - def set_value(self, name: SchemaKeyNativeType, value: obj.KCLObject): - self.schema_obj.update({name: value}) - # If the attribute has only one place holder, its value is also the cache value - if name in self.place_holder_map: - if len(self.place_holder_map[name].codes) <= 1: - self.cache.set(name, value) - elif ( - self.place_holder_map[name].codes[-1].begin_index - < self.vm.ctx.isp - < self.place_holder_map[name].codes[-1].end_index - and self.place_holder_map[name].codes[-1].schema_name - == self.vm.ctx.name - ): - self.cache.set(name, value) - - def get_value(self, name: SchemaKeyNativeType) -> Optional[obj.KCLObject]: - if not name: - raise ValueError(f"Invalid name: {name}") - # Deal in-place modify and return it self immediately - if self.is_target_attr(name) and not self.backtracking.is_backtracking(name): - return self.schema_obj.get(name) - - if name in self.cache: - return self.cache[name] - elif name in self.place_holder_map: - self.back_track(name, self.place_holder_map.get(name)) - - # 1. Load from schema self - if name in self.schema_obj: - value = self.schema_obj.get(name) - return value - - # 2. Load from frame locals such as loop variables and schema args - value = self.get_from_frame_locals(name) - if value is not None: - return value - - # 3. Load from globals - value = self.get_from_frame_globals(name) - if value is not None: - return value - - # 4. Load from builtin - built_obj_list = builtin.get_builtin_func_objects() - for value in built_obj_list: - if value.name == name: - return value - - # 5. Load from pkg because the name may be a package variable that starts with `@` character - pkgpath = name[1:] if name.startswith("@") else name - if pkgpath in self.vm.state.modules: - value = self.vm.state.modules[pkgpath] - return value - kcl_error.report_exception( - err_type=kcl_error.ErrType.EvaluationError_TYPE, - arg_msg=f"'{name}' is not defined", - ) - - def is_target_attr(self, key: str) -> bool: - if key not in self.place_holder_map: - return False - place_holders = self.place_holder_map.get(key) - for code in place_holders.codes: - if code.schema_name != self.vm.ctx.name: - continue - if code.begin_index <= self.vm.ctx.isp <= code.end_index: - return True - return False - - # ------------------------------------- - # VM schema body code runner - # ------------------------------------- - - def vm_run_schema_code(self, code: vm_code.SchemaBodyOpcodeFactory): - if not code or not isinstance(code, vm_code.SchemaBodyOpcodeFactory): - return - codes_run: list = code.to_run_code_list() - func = obj.KCLCompiledFunctionObject( - name=code.schema_name, - params=self.type_obj.func.params, - names=self.type_obj.func.names, - constants=self.type_obj.func.constants, - ) - func.instructions = codes_run - self.vm.push_frame_using_callable( - code.pkgpath, - func, - [*self.args, self.config_meta, self.config, self.schema_obj] - if self.args - else [self.config_meta, self.config, self.schema_obj], - self.kwargs, - args_len=len(self.args), - ) - # Run the schema compiled function body - self.vm.run(run_current=True, ignore_nop=True) - - # ------------------------------------- - # VM frame locals/globals - # ------------------------------------- - - def get_from_frame_locals(self, key: str) -> Optional[obj.KCLDictObject]: - """Get kcl object from vm frame locals dict""" - if self.key_is_in_frame_locals(key): - return self.vm.ctx.locals[key] - index = self.vm.frame_index - # Search the local variables from the inside to the outside schema - while index >= self.vm.frame_index: - index -= 1 - if key in self.vm.frames[index].locals: - return self.vm.frames[index].locals[key] - return None - - def get_from_frame_globals(self, key: str) -> Optional[obj.KCLDictObject]: - """Get kcl object from vm frame locals dict""" - return self.vm.ctx.globals[key] if self.key_is_in_frame_globals(key) else None - - def key_is_in_frame_locals(self, key: str) -> bool: - return key and isinstance(key, str) and key in self.vm.ctx.locals - - def key_is_in_frame_globals(self, key: str) -> bool: - return key and isinstance(key, str) and key in self.vm.ctx.globals - - # --------------- - # Static methods - # --------------- - - @staticmethod - def build_from_vm( - vm: VirtualMachine, - type_obj: obj.KCLSchemaTypeObject, - schema_obj: obj.KCLSchemaObject, - config: obj.KCLDictObject, - config_meta: dict, - args: List[obj.KCLObject], - kwargs: List[obj.KWArg], - ) -> "SchemaEvalContext": - if not type_obj or not isinstance(type_obj, obj.KCLSchemaTypeObject): - raise ValueError(f"Invalid kcl type object {type_obj}") - context = SchemaEvalContext( - type_obj=type_obj, - schema_obj=schema_obj - or obj.KCLSchemaObject( - attrs={ - obj.SCHEMA_SETTINGS_ATTR_NAME: obj.to_kcl_obj(type_obj.settings) - }, - name=type_obj.name, - runtime_type=type_obj.runtime_type, - ), - config=config, - config_meta=config_meta, - args=args, - kwargs=kwargs, - vm=vm, - cache=ValueCache(), - ) - return context diff --git a/internal/kclvm_py/vm/runtime/evaluator/union.py b/internal/kclvm_py/vm/runtime/evaluator/union.py deleted file mode 100644 index ce9d9524c..000000000 --- a/internal/kclvm_py/vm/runtime/evaluator/union.py +++ /dev/null @@ -1,290 +0,0 @@ -# Copyright 2021 The KCL Authors. All rights reserved. - -from typing import List, Union, cast - -import kclvm.kcl.error as kcl_error -import kclvm.kcl.ast as ast -from kclvm.api.object import ( - KCLObject, - KCLSchemaObject, - KCLSchemaTypeObject, - KCLListObject, - KCLDictObject, - KCLNoneObject, - KCLUndefinedObject, - KCLStringObject, - KCLLiteralObject, - KCLSchemaConfigObject, - KCLConfigObjectMixin, - to_python_obj, - to_kcl_obj, -) -from kclvm.api.object.internal import Undefined, UndefinedType -from kclvm.compiler.check.check_type import check_type_builtin -from kclvm.unification import value_subsume - - -def override_config_attr( - attr: str, - obj: Union[KCLDictObject, KCLSchemaObject], - config_value: KCLObject, - index: int = None, -): - if index is None or index < 0: - obj.update_key_value(attr, config_value) - else: - obj.list_key_override(attr, config_value, index) - - -def insert_config_attr( - attr: str, - obj: Union[KCLDictObject, KCLSchemaObject], - config_value: KCLObject, - index: int = None, -): - if index is not None and index >= 0: - config_value = KCLListObject(items=[config_value]) - obj.insert_with_key(attr, config_value, index) - - -def resolve_schema_obj( - schema_obj: KCLSchemaObject, keys: set, vm=None -) -> KCLSchemaObject: - """Using a schema object config to resolve and generate a new schema""" - if not vm or not schema_obj or not isinstance(schema_obj, KCLSchemaObject): - return schema_obj - schema_type_obj = cast( - KCLSchemaTypeObject, - vm.all_schema_types.get(f"{schema_obj.pkgpath}.{schema_obj.name}"), - ) - if not schema_type_obj: - return schema_obj - filename, line, column = vm.get_info() - config_meta = { - "$filename": filename, - "$lineno": line, - "$columnno": column, - } - config = KCLSchemaConfigObject( - value={k: schema_obj.attrs[k] for k in schema_obj.attrs if k in keys}, - operation_map=schema_obj.operation_map, - ) - return schema_type_obj.new_instance(config, config_meta, [], [], vm) - - -def do_union( - obj: KCLObject, - delta: KCLObject, - should_list_override: bool = False, - should_idempotent_check: bool = False, - should_config_resolve: bool = False, - vm=None, -) -> KCLObject: - """ - Union delta to obj recursively - """ - obj_tpe = obj.type_str() - delta_tpe = delta.type_str() - if isinstance(delta, KCLStringObject): - delta_tpe = "str" - if isinstance(obj, KCLListObject): - if not isinstance(delta, KCLListObject): - kcl_error.report_exception( - err_type=kcl_error.ErrType.TypeError_Runtime_TYPE, - arg_msg=f"union failure, expect list, got {delta_tpe}", - ) - - length = ( - len(obj.value) if len(obj.value) > len(delta.value) else len(delta.value) - ) - if should_list_override: - return delta - result_list = obj - for idx in range(length): - if idx >= len(obj.value): - result_list.value.append(delta.value[idx]) - elif idx < len(delta.value): - result_list.value[idx] = union( - result_list.value[idx], - delta.value[idx], - should_list_override=should_list_override, - should_idempotent_check=should_idempotent_check, - should_config_resolve=should_config_resolve, - vm=vm, - ) - return result_list - if isinstance(obj, KCLDictObject): - if not isinstance(delta, KCLDictObject): - kcl_error.report_exception( - err_type=kcl_error.ErrType.TypeError_Runtime_TYPE, - arg_msg=f"union failure, expect dict, got {delta_tpe}", - ) - result_dict = obj - if isinstance(obj, KCLConfigObjectMixin): - obj.update_attr_op_using_obj(delta) - for k in delta.value: - operation = ( - delta.get_operation(k) - if isinstance(delta, KCLConfigObjectMixin) - else ast.ConfigEntryOperation.UNION - ) - insert_index = ( - delta.get_insert_index(k) - if isinstance(delta, KCLConfigObjectMixin) - else None - ) - if k not in obj.value: - result_dict.value[k] = delta.value[k] - else: - if operation == ast.ConfigEntryOperation.OVERRIDE: - override_config_attr(k, result_dict, delta.value[k], insert_index) - if operation == ast.ConfigEntryOperation.INSERT: - insert_config_attr(k, result_dict, delta.value[k], insert_index) - else: - if ( - should_idempotent_check - and k in obj.value - and not value_subsume(delta.value[k], obj.value[k], False) - ): - kcl_error.report_exception( - err_type=kcl_error.ErrType.EvaluationError_TYPE, - arg_msg=f"conflicting values on the attribute '{k}' between " - f"{to_python_obj(delta)} and {to_python_obj(obj)}", - ) - result_dict.value[k] = union( - obj.value[k], - delta.value[k], - should_list_override=should_list_override, - should_idempotent_check=should_idempotent_check, - should_config_resolve=should_config_resolve, - vm=vm, - ) - return result_dict - if isinstance(obj, KCLSchemaObject): - delta_dict = {} - if isinstance(delta, (KCLDictObject, KCLSchemaObject)): - delta_dict = delta.value - else: - kcl_error.report_exception( - err_type=kcl_error.ErrType.TypeError_Runtime_TYPE, - arg_msg=f"union failure, expect {obj_tpe}, got {delta_tpe}", - ) - if should_config_resolve: - common_keys = obj.config_keys | delta.config_keys - if isinstance(obj, KCLConfigObjectMixin): - obj.update_attr_op_using_obj(delta) - for k in delta_dict: - if should_config_resolve and k not in common_keys: - continue - operation = ( - delta.get_operation(k) - if isinstance(delta, KCLConfigObjectMixin) - else ast.ConfigEntryOperation.UNION - ) - insert_index = ( - delta.get_insert_index(k) - if isinstance(delta, KCLConfigObjectMixin) - else None - ) - if ( - should_config_resolve - and k not in obj.attrs - and not obj.should_add_attr(k) - ): - kcl_error.report_exception( - err_type=kcl_error.ErrType.CannotAddMembers_Runtime_TYPE, - arg_msg=kcl_error.CANNOT_ADD_MEMBERS_MSG.format(k, obj.name), - ) - if operation == ast.ConfigEntryOperation.OVERRIDE: - override_config_attr(k, obj, delta_dict[k], insert_index) - if operation == ast.ConfigEntryOperation.INSERT: - insert_config_attr(k, obj, delta_dict[k], insert_index) - else: - if ( - should_idempotent_check - and k in obj.attrs - and not value_subsume(delta_dict[k], obj.attrs[k], False) - ): - kcl_error.report_exception( - err_type=kcl_error.ErrType.EvaluationError_TYPE, - arg_msg=f"conflicting values on the attribute '{k}' between " - f"{to_python_obj(obj)} and {to_python_obj(delta_dict)}", - ) - obj.attrs[k] = union( - obj.attrs.get(k), - delta_dict[k], - should_list_override=should_list_override, - should_idempotent_check=should_idempotent_check, - should_config_resolve=should_config_resolve, - vm=vm, - ) - # Do type check and pack - if isinstance(obj.attrs[k], KCLLiteralObject): - check_type_builtin(obj.attrs[k], obj.get_attr_type(k)) - if should_config_resolve: - obj = resolve_schema_obj(obj, common_keys, vm=vm) - obj.config_keys = common_keys - return obj - if type(obj) != type(delta): - kcl_error.report_exception( - err_type=kcl_error.ErrType.TypeError_Runtime_TYPE, - arg_msg=f"union failure, expect {obj_tpe}, got {delta_tpe}", - ) - return delta - - -def union( - obj: KCLObject, - delta: KCLObject, - or_mode: bool = False, - should_list_override: bool = False, - should_idempotent_check: bool = False, - should_config_resolve: bool = False, - vm=None, -) -> KCLObject: - if ( - obj is None - or obj is Undefined - or isinstance(obj, UndefinedType) - or isinstance(obj, (KCLNoneObject, KCLUndefinedObject)) - ): - return delta - if ( - delta is None - or delta is Undefined - or isinstance(delta, UndefinedType) - or isinstance(delta, (KCLNoneObject, KCLUndefinedObject)) - ): - return obj - if isinstance(obj, (KCLListObject, KCLSchemaObject, KCLDictObject)) or isinstance( - delta, (KCLListObject, KCLSchemaObject, KCLDictObject) - ): - return do_union( - obj, - delta, - should_list_override=should_list_override, - should_idempotent_check=should_idempotent_check, - should_config_resolve=should_config_resolve, - vm=vm, - ) - if or_mode: - return to_kcl_obj(to_python_obj(obj) | to_python_obj(delta)) - else: - return obj if isinstance(delta, (KCLNoneObject, KCLUndefinedObject)) else delta - - -def merge(objs: List[KCLObject], vm=None) -> KCLObject: - """Merge all objects recursively - - - literal variables, override - - list variables, override - - dict/schema variables, union - """ - initial_object = KCLNoneObject.instance() - if not objs: - return initial_object - for obj in objs: - if not obj or isinstance(obj, (KCLNoneObject, KCLUndefinedObject)): - continue - initial_object = union(initial_object, obj, should_list_override=True, vm=vm) - return initial_object diff --git a/internal/kclvm_py/vm/vm.py b/internal/kclvm_py/vm/vm.py deleted file mode 100644 index 195b68320..000000000 --- a/internal/kclvm_py/vm/vm.py +++ /dev/null @@ -1,476 +0,0 @@ -"""The `vm` file mainly contains the function `Run` which is used -# Copyright 2021 The KCL Authors. All rights reserved. -to execute the KCL bytecode obtained by the compiler module into -KCL result used to generate YAML/JSON data. -The KCL virtual machine receives a set of bytecode and uses its -own stack structure to store variables and the calculation results -of the variables, which includes `Frame` for context switching and -`VMState` for storing the import cache and executes the program -according to the corresponding opcode sequence and its operands. -When all the operation codes are executed, the entire KCL program -is also executed. -:copyright: Copyright 2020 The KCL Authors. All rights reserved. -""" - -import pathlib -import dataclasses -import typing - -import kclvm.kcl.error as kcl_error -import kclvm.config -import kclvm.compiler.extension.builtin -import kclvm.compiler.extension.plugin -import kclvm.compiler.check.check_type - -from kclvm.api.object import ( - KCLObject, - KCLProgram, - KCLResult, - KCLCompiledFunctionObject, - KCLModuleObject, - KCLSchemaTypeObject, - KWArg, -) - -from .code import Opcode, VM_OP_ACTIONS - - -@dataclasses.dataclass -class Frame: - isp: int = 0 - name: str = None - filename: str = None - colno: int = 0 - lineno: int = 0 - pkgpath: str = None - locals: dict = None - globals: dict = None # Global symbol and KCL object reference - free_vars: list = None # Free symbols - codes: typing.List[int] = None - - def update_info(self, filename: str, lineno: int, colno: int): - self.filename, self.lineno, self.colno = filename, lineno, colno - - def get_info(self) -> typing.Tuple[str, int, int]: - return self.filename, self.lineno, self.colno - - -class VMState: - def __init__(self): - self.modules: typing.Dict[str, KCLModuleObject] = {} # {pkgpath:module} - self.globals_table: typing.Dict[ - str, typing.Dict[str, KCLObject] - ] = {} # {pkgpath:globals} - - -class VirtualMachine: - """KCL Virtual Machine""" - - pkgpath_stack: typing.List[str] = [] - - @staticmethod - def RunApp(app: KCLProgram, *, pkg: str = None) -> KCLResult: - # Reset cache - KCLSchemaTypeObject._eval_cache = {} - VirtualMachine.pkgpath_stack = [] - return VirtualMachine(app).Run(pkg=pkg) - - def __init__(self, app: KCLProgram, state: VMState = None): - super().__init__() - - self.app: KCLProgram = app - self.state: VMState = state or VMState() - - self.names: typing.List[str] = [] - self.constants: typing.List[KCLObject] = [] - self.stack: typing.List[KCLObject] = [] - self.last_obj: typing.Optional[KCLObject] = None - self.ctx: typing.Optional[Frame] = None - self.frames: typing.List[Frame] = [] - self.frame_index = 1 - self.last_popped_frame = None - self.sp: int = 0 # Stack Pointer - - self.cur_run_pkg: str = "" - - self.all_schema_types: typing.Dict[ - str, KCLSchemaTypeObject - ] = {} # [f"{pkgpath}.{name}": obj] - - self.lazy_eval_ctx = None - - self._reset(app.main) - - def Run(self, *, pkg: str = None) -> KCLResult: - pkgpath = pkg if pkg else self.app.main - if pkgpath in self.pkgpath_stack: - kcl_error.report_exception( - err_type=kcl_error.ErrType.RecursiveLoad_TYPE, - arg_msg=kcl_error.RECURSIVE_LOADING_MODULE_MSG.format( - pkgpath, ", ".join(self.pkgpath_stack) - ), - ) - if pkg: - self.pkgpath_stack.append(pkgpath) - self._reset(pkgpath) - return KCLResult(self.run(), self.get_filename()) - - def define_schema_type(self, absname: str, schema_type: KCLSchemaTypeObject): - if absname.startswith("@"): - absname = absname[1:] - self.all_schema_types[absname] = schema_type - - def find_schema_type(self, absname: str) -> typing.Optional[KCLSchemaTypeObject]: - if absname.startswith("@"): - absname = absname[1:] - return self.all_schema_types.get(absname) - - def import_name(self, _code: int, arg: int) -> typing.Optional[KCLModuleObject]: - self.pop() - - pkgpath = self.names[arg] - asname = self.names[arg + 1] - - assert pkgpath and asname - - if pkgpath.startswith("@"): - pkgpath = pkgpath[1:] - if asname.startswith("@"): - asname = asname[1:] - - if pkgpath in self.state.modules: - # Read from module cache - module = self.state.modules[pkgpath] - - self.update_local(asname, module) - self.update_global(f"@{pkgpath}", module) - self.push(module) - - return module - - if pkgpath in kclvm.compiler.extension.builtin.STANDARD_SYSTEM_MODULES: - module = KCLModuleObject( - name=pkgpath, - asname=asname, - value=kclvm.compiler.extension.builtin.get_system_module_func_objects( - pkgpath - ), - ) - - self.update_local(asname, module) - self.update_global(f"@{pkgpath}", module) - self.push(module) - - # Module cache - self.state.modules[pkgpath] = module - self.state.globals_table[pkgpath] = {} - - return module - - if pkgpath.startswith(kclvm.compiler.extension.plugin.PLUGIN_MODULE_NAME): - module = KCLModuleObject( - name=pkgpath.replace( - kclvm.compiler.extension.plugin.PLUGIN_MODULE_NAME, "" - ), - asname=asname, - value=kclvm.compiler.extension.plugin.get_plugin_func_objects(pkgpath), - ) - - self.update_local(asname, module) - self.update_global(f"@{pkgpath}", module) - self.push(module) - - self.state.modules[pkgpath] = module - self.state.globals_table[pkgpath] = {} - - return module - - if pkgpath in self.app.pkgs: - pkg_vm = VirtualMachine(self.app, self.state) - pkg_vm.all_schema_types = self.all_schema_types - - result = pkg_vm.Run(pkg=pkgpath) - - module = KCLModuleObject(name=pkgpath, asname=asname, value=result.m) - - self.update_local(asname, module) - self.update_global(f"@{pkgpath}", module) - self.push(module) - - self.state.modules[pkgpath] = module - self.state.globals_table[pkgpath] = result.m - - return module - kcl_error.report_exception( - err_type=kcl_error.ErrType.CannotFindModule_TYPE, - arg_msg=kcl_error.CANNOT_FIND_MODULE_MSG.format( - pkgpath, - str( - pathlib.Path(self.get_filename()).parent - / (pkgpath.replace(".", "/")) - ), - ), - ) - - def _reset(self, pkg: str): - assert pkg in self.app.pkgs - - self.cur_run_pkg = pkg - bytecode = self.app.pkgs[pkg] - - self.names: typing.List[str] = bytecode.names - self.constants: typing.List[KCLObject] = bytecode.constants - self.stack: typing.List[KCLObject] = [] - self.last_obj: typing.Optional[KCLObject] = None - self.ctx: typing.Optional[Frame] = None - self.frames: typing.List[Frame] = [ - Frame( - codes=bytecode.instructions, - pkgpath=pkg, - locals={}, - globals={}, - free_vars=[], - ) - ] - self.frame_index = 1 - self.last_popped_frame = None - self.sp: int = 0 # Stack Pointer - - def run(self, run_current=False, ignore_nop=False): - try: - self.ctx = self.current_frame() - while self.ctx.codes and self.ctx.isp < len(self.ctx.codes): - codes = self.ctx.codes - code = self.ctx.codes[self.ctx.isp] - self.ctx.isp += 1 - # Skip the invalid opcode - if code == Opcode.INVALID: - continue - arg = None - if Opcode.has_arg(code): - arg = ( - codes[self.ctx.isp] - + (codes[self.ctx.isp + 1] << 8) - + (codes[self.ctx.isp + 2] << 16) - ) - self.ctx.isp += 3 - info = self.ctx.codes[self.ctx.isp] - info = typing.cast(tuple, info) - self.ctx.isp += 1 - self.ctx.update_info(*info) - action = VM_OP_ACTIONS.get(code) - if ignore_nop and (code == Opcode.NOP or code == Opcode.SCHEMA_NOP): - continue - if not action: - raise Exception(f"invalid opcode {code}") - action(self, code, arg) - if code == Opcode.RETURN_VALUE and run_current: - break - except kcl_error.KCLException as err: - if not err.lineno: - filename, line, _ = self.get_info() - errfile = err.pop_err_info() - errfile.filename, errfile.line_no = filename, line or None - err.append_err_info(errfile) - raise err - except Exception as err: - if kclvm.config.debug and kclvm.config.verbose > 2: - raise - filename, lineno, _ = self.get_info() - if isinstance(err, AttributeError): - kcl_error.report_exception( - err_type=kcl_error.ErrType.AttributeError_Runtime_TYPE, - file_msgs=[kcl_error.ErrFileMsg(filename=filename, line_no=lineno)], - arg_msg=str(err), - ) - if isinstance(err, RecursionError): - kcl_error.report_exception( - err_type=kcl_error.ErrType.RecursionError_TYPE, - file_msgs=[kcl_error.ErrFileMsg(filename=filename, line_no=lineno)], - arg_msg=str(err), - ) - kcl_error.report_exception( - err_type=kcl_error.ErrType.EvaluationError_TYPE, - file_msgs=[kcl_error.ErrFileMsg(filename=filename, line_no=lineno)], - arg_msg=str(err), - ) - - return self.ctx.globals - - def get_info(self, with_column=False) -> typing.Tuple[str, int, int]: - filename, line, column = self.ctx.get_info() - return filename, line, column if with_column else None - - def get_filename(self) -> str: - filename, _, _ = self.ctx.get_info() - return filename - - def load_const(self, index: int) -> KCLObject: - cst = self.constants[index] - self.push(cst) - return cst - - def load_name(self, index: int) -> KCLObject: - name = self.names[index] - self.push(self.ctx.globals[name]) - return self.ctx.globals[name] - - def store_name(self, index: int): - name = self.names[index] - self.ctx.globals[name] = kclvm.compiler.check.check_type.check( - self.stack_top(), *self.get_info() - ) - - def load_local(self, index: int): - name = self.names[index] - self.push(self.ctx.locals[name]) - - def store_local(self, index: int): - name = self.names[index] - self.ctx.locals[name] = self.stack_top() - - def update_local(self, name: str, value: KCLObject): - self.ctx.locals[name] = value - - def update_global(self, name: str, value: KCLObject): - self.ctx.globals[name] = kclvm.compiler.check.check_type.check( - value, *self.get_info() - ) - - def load_builtin(self, index: int): - built_obj_list = kclvm.compiler.extension.builtin.get_builtin_func_objects() - self.push(built_obj_list[index]) - - def set_instruction_pointer(self, index: int): - self.ctx.isp = int(index) - - def stack_top(self) -> KCLObject: - return self.stack[-1] - - def current_frame(self) -> Frame: - return self.frames[-1] - - def push_frame(self, frame: Frame, names=None, constants=None): - self.frames.append(frame) - self.ctx = self.frames[-1] - self.frame_index += 1 - - def push_frame_using_callable( - self, - pkgpath: str, - func: KCLCompiledFunctionObject, - args: typing.List[KCLObject], - kwargs: typing.List[KWArg], - args_len: int = 0, - ): - assert isinstance(func, KCLCompiledFunctionObject) - - filename, line, column = self.get_info() - - ctx_globals = self.frames[-1].globals - if pkgpath in self.state.globals_table: - ctx_globals = self.state.globals_table[pkgpath] - self.cur_run_pkg = pkgpath - - self.push_frame( - Frame( - name=func.name, - codes=func.instructions, - pkgpath=pkgpath, - locals={}, - globals=ctx_globals, - free_vars=[], - ), - func.names, - func.constants, - ) - arg_index = 0 - for arg in args[args_len:] or []: - self.push(arg) - for default_arg in func.params: - if default_arg.value: - self.update_local(default_arg.name, default_arg.value) - # args[3:] - schema args - for arg in args[:args_len]: - name = func.params[arg_index].name - self.update_local(name, arg) - arg_index += 1 - for kwarg in kwargs or []: - name = kwarg.name.value - if name not in [p.name for p in func.params]: - kcl_error.report_exception( - err_type=kcl_error.ErrType.EvaluationError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=filename, line_no=line, col_no=column - ) - ], - arg_msg=f"schema arguments got an unexpected keyword argument '{name}'", - ) - self.update_local(name, kwarg.value) - - def pop_frame(self) -> Frame: - self.last_popped_frame = self.frames.pop() - self.ctx = self.frames[-1] - self.frame_index -= 1 - return self.last_popped_frame - - def push_function(self, index: int): - func_obj = self.constants[index] - self.push(func_obj) - - def push(self, obj: KCLObject): - self.stack.append(obj) - - def pop(self): - self.last_obj = self.stack.pop() - return self.last_obj - - def peek(self) -> KCLObject: - return self.stack[-1] - - def peek_nth(self, index: int) -> KCLObject: - """View the Nth top item on the stack from index 0""" - return self.stack[-index] - - def top(self) -> KCLObject: - """Get the top of the VM stack""" - return self.stack[-1] - - def set_top(self, obj: KCLObject): - """Set the top of the VM stack""" - self.stack[-1] = obj - - def clear(self): - self.stack.clear() - - def last_popped_obj(self) -> KCLObject: - return self.last_obj - - def debug_stack(self, idx: int, at: int = 0): - if at > 0: - print(f"vm.stack[{-1-idx}]={self.stack[-1-idx]} # at({at})") - else: - print(f"vm.stack[{-1-idx}]={self.stack[-1-idx]}") - - def debug_locals(self, _arg: int, at: int = 0): - if at > 0: - print(f"vm.ctx.locals={self.ctx.locals} # at({at})") - else: - print(f"vm.ctx.locals={self.ctx.locals}") - - def debug_globals(self, _arg: int, at: int = 0): - if at > 0: - print(f"vm.ctx.globals={self.ctx.globals} # at({at})") - else: - print(f"vm.ctx.globals={self.ctx.globals}") - - def debug_names(self, _arg: int, at: int = 0): - if at > 0: - print(f"vm.names={self.names} # at({at})") - else: - print(f"vm.names={self.names}") - - -def Run(app: KCLProgram, *, pkg: str = None) -> KCLResult: - return VirtualMachine.RunApp(app, pkg=pkg) diff --git a/kclvm/3rdparty/rustc_data_structures/Cargo.lock b/kclvm/3rdparty/rustc_data_structures/Cargo.lock deleted file mode 100644 index 71a2500cd..000000000 --- a/kclvm/3rdparty/rustc_data_structures/Cargo.lock +++ /dev/null @@ -1,445 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "arrayvec" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6" - -[[package]] -name = "autocfg" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "cc" -version = "1.0.73" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" - -[[package]] -name = "cfg-if" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "crossbeam-deque" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e" -dependencies = [ - "cfg-if 1.0.0", - "crossbeam-epoch", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-epoch" -version = "0.9.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1145cf131a2c6ba0615079ab6a638f7e1973ac9c2634fcbeaaad6114246efe8c" -dependencies = [ - "autocfg", - "cfg-if 1.0.0", - "crossbeam-utils", - "lazy_static", - "memoffset", - "scopeguard", -] - -[[package]] -name = "crossbeam-utils" -version = "0.8.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bf124c720b7686e3c2663cf54062ab0f68a88af2fb6a030e87e30bf721fcb38" -dependencies = [ - "cfg-if 1.0.0", - "lazy_static", -] - -[[package]] -name = "either" -version = "1.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" - -[[package]] -name = "ena" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7402b94a93c24e742487327a7cd839dc9d36fec9de9fb25b09f2dae459f36c3" -dependencies = [ - "log", -] - -[[package]] -name = "fastrand" -version = "1.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3fcf0cee53519c866c09b5de1f6c56ff9d647101f81c1964fa632e148896cdf" -dependencies = [ - "instant", -] - -[[package]] -name = "hashbrown" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" - -[[package]] -name = "hermit-abi" -version = "0.1.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" -dependencies = [ - "libc", -] - -[[package]] -name = "indexmap" -version = "1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f647032dfaa1f8b6dc29bd3edb7bbef4861b8b8007ebb118d6db284fd59f6ee" -dependencies = [ - "autocfg", - "hashbrown", - "rustc-rayon", -] - -[[package]] -name = "instant" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" -dependencies = [ - "cfg-if 1.0.0", -] - -[[package]] -name = "jobserver" -version = "0.1.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af25a77299a7f711a01975c35a6a424eb6862092cc2d6c72c4ed6cbc56dfc1fa" -dependencies = [ - "libc", -] - -[[package]] -name = "lazy_static" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" - -[[package]] -name = "libc" -version = "0.2.123" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb691a747a7ab48abc15c5b42066eaafde10dc427e3b6ee2a1cf43db04c763bd" - -[[package]] -name = "lock_api" -version = "0.4.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "327fa5b6a6940e4699ec49a9beae1ea4845c6bab9314e4f84ac68742139d8c53" -dependencies = [ - "autocfg", - "scopeguard", -] - -[[package]] -name = "log" -version = "0.4.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6389c490849ff5bc16be905ae24bc913a9c8892e19b2341dbc175e14c341c2b8" -dependencies = [ - "cfg-if 1.0.0", -] - -[[package]] -name = "memmap2" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "723e3ebdcdc5c023db1df315364573789f8857c11b631a2fdfad7c00f5c046b4" -dependencies = [ - "libc", -] - -[[package]] -name = "memoffset" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" -dependencies = [ - "autocfg", -] - -[[package]] -name = "num_cpus" -version = "1.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" -dependencies = [ - "hermit-abi", - "libc", -] - -[[package]] -name = "parking_lot" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" -dependencies = [ - "instant", - "lock_api", - "parking_lot_core", -] - -[[package]] -name = "parking_lot_core" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216" -dependencies = [ - "cfg-if 1.0.0", - "instant", - "libc", - "redox_syscall", - "smallvec", - "winapi", -] - -[[package]] -name = "pin-project-lite" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e280fbe77cc62c91527259e9442153f4688736748d24660126286329742b4c6c" - -[[package]] -name = "proc-macro2" -version = "1.0.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec757218438d5fda206afc041538b2f6d889286160d649a86a24d37e1235afd1" -dependencies = [ - "unicode-xid", -] - -[[package]] -name = "psm" -version = "0.1.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "871372391786ccec00d3c5d3d6608905b3d4db263639cfe075d3b60a736d115a" -dependencies = [ - "cc", -] - -[[package]] -name = "quote" -version = "1.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "redox_syscall" -version = "0.2.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42" -dependencies = [ - "bitflags", -] - -[[package]] -name = "remove_dir_all" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" -dependencies = [ - "winapi", -] - -[[package]] -name = "rustc-hash" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" - -[[package]] -name = "rustc-rayon" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9974ab223660e61c1b4e7b43b827379df286736ca988308ce7e16f59f2d89246" -dependencies = [ - "crossbeam-deque", - "either", - "rustc-rayon-core", -] - -[[package]] -name = "rustc-rayon-core" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "564bfd27be8db888d0fa76aa4335e7851aaed0c2c11ad1e93aeb9349f6b88500" -dependencies = [ - "crossbeam-deque", - "crossbeam-utils", - "lazy_static", - "num_cpus", -] - -[[package]] -name = "rustc_data_structures" -version = "0.0.0" -dependencies = [ - "arrayvec", - "bitflags", - "cfg-if 0.1.10", - "ena", - "indexmap", - "jobserver", - "libc", - "memmap2", - "parking_lot", - "rustc-hash", - "rustc-rayon", - "rustc-rayon-core", - "stable_deref_trait", - "stacker", - "tempfile", - "tracing", - "winapi", -] - -[[package]] -name = "scopeguard" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" - -[[package]] -name = "smallvec" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83" - -[[package]] -name = "stable_deref_trait" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" - -[[package]] -name = "stacker" -version = "0.1.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90939d5171a4420b3ff5fbc8954d641e7377335454c259dcb80786f3f21dc9b4" -dependencies = [ - "cc", - "cfg-if 1.0.0", - "libc", - "psm", - "winapi", -] - -[[package]] -name = "syn" -version = "1.0.91" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b683b2b825c8eef438b77c36a06dc262294da3d5a5813fac20da149241dcd44d" -dependencies = [ - "proc-macro2", - "quote", - "unicode-xid", -] - -[[package]] -name = "tempfile" -version = "3.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" -dependencies = [ - "cfg-if 1.0.0", - "fastrand", - "libc", - "redox_syscall", - "remove_dir_all", - "winapi", -] - -[[package]] -name = "tracing" -version = "0.1.34" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d0ecdcb44a79f0fe9844f0c4f33a342cbcbb5117de8001e6ba0dc2351327d09" -dependencies = [ - "cfg-if 1.0.0", - "pin-project-lite", - "tracing-attributes", - "tracing-core", -] - -[[package]] -name = "tracing-attributes" -version = "0.1.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e65ce065b4b5c53e73bb28912318cb8c9e9ad3921f1d669eb0e68b4c8143a2b" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "tracing-core" -version = "0.1.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f54c8ca710e81886d498c2fd3331b56c93aa248d49de2222ad2742247c60072f" -dependencies = [ - "lazy_static", -] - -[[package]] -name = "unicode-xid" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/kclvm/3rdparty/rustc_data_structures/Cargo.toml b/kclvm/3rdparty/rustc_data_structures/Cargo.toml deleted file mode 100644 index 971e19a87..000000000 --- a/kclvm/3rdparty/rustc_data_structures/Cargo.toml +++ /dev/null @@ -1,33 +0,0 @@ -[package] -name = "rustc_data_structures" -version = "0.0.0" -edition = "2021" - -[lib] -doctest = false - -[dependencies] -arrayvec = { version = "0.7", default-features = false } -ena = "0.14" -indexmap = { version = "1.8.0", features = ["rustc-rayon"] } -tracing = "0.1" -jobserver_crate = { version = "0.1.13", package = "jobserver" } - -cfg-if = "0.1.2" -stable_deref_trait = "1.0.0" -rayon = { version = "0.3.2", package = "rustc-rayon" } -rayon-core = { version = "0.3.2", package = "rustc-rayon-core" } -rustc-hash = "1.1.0" -bitflags = "1.2.1" -libc = "0.2" -stacker = "0.1.14" -tempfile = "3.2" - -[dependencies.parking_lot] -version = "0.12" - -[target.'cfg(windows)'.dependencies] -winapi = { version = "0.3", features = ["fileapi", "psapi", "winerror"] } - -[target.'cfg(not(target_arch = "wasm32"))'.dependencies] -memmap2 = "0.2.1" diff --git a/kclvm/3rdparty/rustc_data_structures/src/lib.rs b/kclvm/3rdparty/rustc_data_structures/src/lib.rs deleted file mode 100644 index aa2ec1022..000000000 --- a/kclvm/3rdparty/rustc_data_structures/src/lib.rs +++ /dev/null @@ -1,78 +0,0 @@ -//! Various data structures used by the Rust compiler. The intention -//! is that code in here should be not be *specific* to rustc, so that -//! it can be easily unit tested and so forth. -//! -//! # Note -//! -//! This API is completely unstable and subject to change. - -#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] -#![allow(rustc::default_hash_types)] -#![deny(unaligned_references)] -#![allow(rustc::potential_query_instability)] - -extern crate tracing; -#[macro_use] -extern crate cfg_if; - -#[inline(never)] -#[cold] -pub fn cold_path R, R>(f: F) -> R { - f() -} - -#[macro_export] -macro_rules! likely { - ($e:expr) => { - match $e { - #[allow(unused_unsafe)] - e => unsafe { std::intrinsics::likely(e) }, - } - }; -} - -pub mod base_n; - -pub mod captures; -pub mod flock; -pub mod fx; - -pub mod macros; -pub mod stable_map; -pub use ena::snapshot_vec; -pub mod stable_set; -#[macro_use] - -mod atomic_ref; -pub mod stack; -pub mod sync; -pub use atomic_ref::AtomicRef; -pub mod frozen; - -pub mod temp_dir; -pub mod unhash; - -pub use ena::undo_log; -pub use ena::unify; - -pub struct OnDrop(pub F); - -impl OnDrop { - /// Forgets the function which prevents it from running. - /// Ensure that the function owns no memory, otherwise it will be leaked. - #[inline] - pub fn disable(self) { - std::mem::forget(self); - } -} - -impl Drop for OnDrop { - #[inline] - fn drop(&mut self) { - (self.0)(); - } -} - -// See comments in src/librustc_middle/lib.rs -#[doc(hidden)] -pub fn __noop_fix_for_27438() {} diff --git a/kclvm/3rdparty/rustc_data_structures/src/stack.rs b/kclvm/3rdparty/rustc_data_structures/src/stack.rs deleted file mode 100644 index 3bdd67512..000000000 --- a/kclvm/3rdparty/rustc_data_structures/src/stack.rs +++ /dev/null @@ -1,18 +0,0 @@ -// This is the amount of bytes that need to be left on the stack before increasing the size. -// It must be at least as large as the stack required by any code that does not call -// `ensure_sufficient_stack`. -const RED_ZONE: usize = 100 * 1024; // 100k - -// Only the first stack that is pushed, grows exponentially (2^n * STACK_PER_RECURSION) from then -// on. This flag has performance relevant characteristics. Don't set it too high. -const STACK_PER_RECURSION: usize = 1 * 1024 * 1024; // 1MB - -/// Grows the stack on demand to prevent stack overflow. Call this in strategic locations -/// to "break up" recursive calls. E.g. almost any call to `visit_expr` or equivalent can benefit -/// from this. -/// -/// Should not be sprinkled around carelessly, as it causes a little bit of overhead. -#[inline] -pub fn ensure_sufficient_stack(f: impl FnOnce() -> R) -> R { - stacker::maybe_grow(RED_ZONE, STACK_PER_RECURSION, f) -} diff --git a/kclvm/3rdparty/rustc_data_structures/src/sync.rs b/kclvm/3rdparty/rustc_data_structures/src/sync.rs deleted file mode 100644 index 3f0908da1..000000000 --- a/kclvm/3rdparty/rustc_data_structures/src/sync.rs +++ /dev/null @@ -1,110 +0,0 @@ -//! This module defines types which are thread safe if cfg!(parallel_compiler) is true. -//! -//! `Lrc` is an alias of `Arc` if cfg!(parallel_compiler) is true, `Rc` otherwise. -//! -//! `Lock` is a mutex. -//! It internally uses `parking_lot::Mutex` if cfg!(parallel_compiler) is true, -//! `RefCell` otherwise. -//! -//! `RwLock` is a read-write lock. -//! It internally uses `parking_lot::RwLock` if cfg!(parallel_compiler) is true, -//! `RefCell` otherwise. -//! -//! `MTLock` is a mutex which disappears if cfg!(parallel_compiler) is false. -//! -//! `MTRef` is an immutable reference if cfg!(parallel_compiler), and a mutable reference otherwise. -//! -//! `rustc_erase_owner!` erases an OwningRef owner into Erased or Erased + Send + Sync -//! depending on the value of cfg!(parallel_compiler). - -use std::collections::HashMap; -use std::hash::{BuildHasher, Hash}; - -pub use std::sync::atomic::Ordering; -pub use std::sync::atomic::Ordering::SeqCst; - - pub use std::marker::Send as Send; - pub use std::marker::Sync as Sync; - - pub use parking_lot::RwLockReadGuard as ReadGuard; - pub use parking_lot::MappedRwLockReadGuard as MappedReadGuard; - pub use parking_lot::RwLockWriteGuard as WriteGuard; - pub use parking_lot::MappedRwLockWriteGuard as MappedWriteGuard; - - pub use parking_lot::MutexGuard as LockGuard; - pub use parking_lot::MappedMutexGuard as MappedLockGuard; - - pub use std::sync::atomic::{AtomicBool, AtomicUsize, AtomicU32, AtomicU64}; - - pub use std::sync::Arc as Lrc; - pub use std::sync::Weak as Weak; - - pub type MTRef<'a, T> = &'a T; - - pub use rayon::{join, scope}; - - /// Runs a list of blocks in parallel. The first block is executed immediately on - /// the current thread. Use that for the longest running block. - #[macro_export] - macro_rules! parallel { - (impl $fblock:tt [$($c:tt,)*] [$block:tt $(, $rest:tt)*]) => { - parallel!(impl $fblock [$block, $($c,)*] [$($rest),*]) - }; - (impl $fblock:tt [$($blocks:tt,)*] []) => { - ::rustc_data_structures::sync::scope(|s| { - $( - s.spawn(|_| $blocks); - )* - $fblock; - }) - }; - ($fblock:tt, $($blocks:tt),*) => { - // Reverse the order of the later blocks since Rayon executes them in reverse order - // when using a single thread. This ensures the execution order matches that - // of a single threaded rustc - parallel!(impl $fblock [] [$($blocks),*]); - }; - } - - pub use rayon_core::WorkerLocal; - - pub use rayon::iter::ParallelIterator; - use rayon::iter::IntoParallelIterator; - - pub fn par_iter(t: T) -> T::Iter { - t.into_par_iter() - } - - pub fn par_for_each_in( - t: T, - for_each: impl Fn(T::Item) + Sync + Send, - ) { - t.into_par_iter().for_each(for_each) - } - - #[macro_export] - macro_rules! rustc_erase_owner { - ($v:expr) => {{ - let v = $v; - ::rustc_data_structures::sync::assert_send_val(&v); - v.erase_send_sync_owner() - }} - } - - -pub fn assert_sync() {} -pub fn assert_send() {} -pub fn assert_send_val(_t: &T) {} -pub fn assert_send_sync_val(_t: &T) {} - -pub trait HashMapExt { - /// Same as HashMap::insert, but it may panic if there's already an - /// entry for `key` with a value not equal to `value` - fn insert_same(&mut self, key: K, value: V); -} - -impl HashMapExt for HashMap { - fn insert_same(&mut self, key: K, value: V) { - self.entry(key).and_modify(|old| assert!(*old == value)).or_insert(value); - } -} diff --git a/kclvm/3rdparty/rustc_span/Cargo.lock b/kclvm/3rdparty/rustc_span/Cargo.lock deleted file mode 100644 index 04210119d..000000000 --- a/kclvm/3rdparty/rustc_span/Cargo.lock +++ /dev/null @@ -1,586 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "arrayvec" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6" - -[[package]] -name = "autocfg" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "block-buffer" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bf7fe51849ea569fd452f37822f606a5cabb684dc918707a0193fd4664ff324" -dependencies = [ - "generic-array", -] - -[[package]] -name = "cc" -version = "1.0.73" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" - -[[package]] -name = "cfg-if" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "cpufeatures" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59a6001667ab124aebae2a495118e11d30984c3a653e99d86d58971708cf5e4b" -dependencies = [ - "libc", -] - -[[package]] -name = "crossbeam-deque" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e" -dependencies = [ - "cfg-if 1.0.0", - "crossbeam-epoch", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-epoch" -version = "0.9.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1145cf131a2c6ba0615079ab6a638f7e1973ac9c2634fcbeaaad6114246efe8c" -dependencies = [ - "autocfg", - "cfg-if 1.0.0", - "crossbeam-utils", - "lazy_static", - "memoffset", - "scopeguard", -] - -[[package]] -name = "crossbeam-utils" -version = "0.8.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bf124c720b7686e3c2663cf54062ab0f68a88af2fb6a030e87e30bf721fcb38" -dependencies = [ - "cfg-if 1.0.0", - "lazy_static", -] - -[[package]] -name = "crypto-common" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57952ca27b5e3606ff4dd79b0020231aaf9d6aa76dc05fd30137538c50bd3ce8" -dependencies = [ - "generic-array", - "typenum", -] - -[[package]] -name = "digest" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2fb860ca6fafa5552fb6d0e816a69c8e49f0908bf524e30a90d97c85892d506" -dependencies = [ - "block-buffer", - "crypto-common", -] - -[[package]] -name = "either" -version = "1.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" - -[[package]] -name = "ena" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7402b94a93c24e742487327a7cd839dc9d36fec9de9fb25b09f2dae459f36c3" -dependencies = [ - "log", -] - -[[package]] -name = "fastrand" -version = "1.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3fcf0cee53519c866c09b5de1f6c56ff9d647101f81c1964fa632e148896cdf" -dependencies = [ - "instant", -] - -[[package]] -name = "generic-array" -version = "0.14.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd48d33ec7f05fbfa152300fdad764757cbded343c1aa1cff2fbaf4134851803" -dependencies = [ - "typenum", - "version_check", -] - -[[package]] -name = "hashbrown" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" - -[[package]] -name = "hermit-abi" -version = "0.1.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" -dependencies = [ - "libc", -] - -[[package]] -name = "indexmap" -version = "1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f647032dfaa1f8b6dc29bd3edb7bbef4861b8b8007ebb118d6db284fd59f6ee" -dependencies = [ - "autocfg", - "hashbrown", - "rustc-rayon", -] - -[[package]] -name = "instant" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" -dependencies = [ - "cfg-if 1.0.0", -] - -[[package]] -name = "jobserver" -version = "0.1.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af25a77299a7f711a01975c35a6a424eb6862092cc2d6c72c4ed6cbc56dfc1fa" -dependencies = [ - "libc", -] - -[[package]] -name = "lazy_static" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" - -[[package]] -name = "libc" -version = "0.2.123" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb691a747a7ab48abc15c5b42066eaafde10dc427e3b6ee2a1cf43db04c763bd" - -[[package]] -name = "lock_api" -version = "0.4.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "327fa5b6a6940e4699ec49a9beae1ea4845c6bab9314e4f84ac68742139d8c53" -dependencies = [ - "autocfg", - "scopeguard", -] - -[[package]] -name = "log" -version = "0.4.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6389c490849ff5bc16be905ae24bc913a9c8892e19b2341dbc175e14c341c2b8" -dependencies = [ - "cfg-if 1.0.0", -] - -[[package]] -name = "md-5" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "658646b21e0b72f7866c7038ab086d3d5e1cd6271f060fd37defb241949d0582" -dependencies = [ - "digest", -] - -[[package]] -name = "measureme" -version = "10.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd460fad6e55ca82fa0cd9dab0d315294188fd9ec6efbf4105e5635d4872ef9c" -dependencies = [ - "log", - "memmap2", - "parking_lot", - "perf-event-open-sys", - "rustc-hash", - "smallvec", -] - -[[package]] -name = "memmap2" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "723e3ebdcdc5c023db1df315364573789f8857c11b631a2fdfad7c00f5c046b4" -dependencies = [ - "libc", -] - -[[package]] -name = "memoffset" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" -dependencies = [ - "autocfg", -] - -[[package]] -name = "num_cpus" -version = "1.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" -dependencies = [ - "hermit-abi", - "libc", -] - -[[package]] -name = "parking_lot" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" -dependencies = [ - "instant", - "lock_api", - "parking_lot_core", -] - -[[package]] -name = "parking_lot_core" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216" -dependencies = [ - "cfg-if 1.0.0", - "instant", - "libc", - "redox_syscall", - "smallvec", - "winapi", -] - -[[package]] -name = "perf-event-open-sys" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce9bedf5da2c234fdf2391ede2b90fabf585355f33100689bc364a3ea558561a" -dependencies = [ - "libc", -] - -[[package]] -name = "pin-project-lite" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e280fbe77cc62c91527259e9442153f4688736748d24660126286329742b4c6c" - -[[package]] -name = "proc-macro2" -version = "1.0.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec757218438d5fda206afc041538b2f6d889286160d649a86a24d37e1235afd1" -dependencies = [ - "unicode-xid", -] - -[[package]] -name = "psm" -version = "0.1.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "871372391786ccec00d3c5d3d6608905b3d4db263639cfe075d3b60a736d115a" -dependencies = [ - "cc", -] - -[[package]] -name = "quote" -version = "1.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "redox_syscall" -version = "0.2.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42" -dependencies = [ - "bitflags", -] - -[[package]] -name = "remove_dir_all" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" -dependencies = [ - "winapi", -] - -[[package]] -name = "rustc-hash" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" - -[[package]] -name = "rustc-rayon" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9974ab223660e61c1b4e7b43b827379df286736ca988308ce7e16f59f2d89246" -dependencies = [ - "crossbeam-deque", - "either", - "rustc-rayon-core", -] - -[[package]] -name = "rustc-rayon-core" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "564bfd27be8db888d0fa76aa4335e7851aaed0c2c11ad1e93aeb9349f6b88500" -dependencies = [ - "crossbeam-deque", - "crossbeam-utils", - "lazy_static", - "num_cpus", -] - -[[package]] -name = "rustc_data_structures" -version = "0.0.0" -dependencies = [ - "arrayvec", - "bitflags", - "cfg-if 0.1.10", - "ena", - "indexmap", - "jobserver", - "libc", - "measureme", - "memmap2", - "parking_lot", - "rustc-hash", - "rustc-rayon", - "rustc-rayon-core", - "stable_deref_trait", - "stacker", - "tempfile", - "tracing", - "winapi", -] - -[[package]] -name = "rustc_span" -version = "0.0.0" -dependencies = [ - "cfg-if 0.1.10", - "md-5", - "rustc_data_structures", - "scoped-tls", - "sha-1", - "sha2", - "tracing", - "unicode-width", -] - -[[package]] -name = "scoped-tls" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2" - -[[package]] -name = "scopeguard" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" - -[[package]] -name = "sha-1" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "028f48d513f9678cda28f6e4064755b3fbb2af6acd672f2c209b62323f7aea0f" -dependencies = [ - "cfg-if 1.0.0", - "cpufeatures", - "digest", -] - -[[package]] -name = "sha2" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55deaec60f81eefe3cce0dc50bda92d6d8e88f2a27df7c5033b42afeb1ed2676" -dependencies = [ - "cfg-if 1.0.0", - "cpufeatures", - "digest", -] - -[[package]] -name = "smallvec" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83" - -[[package]] -name = "stable_deref_trait" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" - -[[package]] -name = "stacker" -version = "0.1.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90939d5171a4420b3ff5fbc8954d641e7377335454c259dcb80786f3f21dc9b4" -dependencies = [ - "cc", - "cfg-if 1.0.0", - "libc", - "psm", - "winapi", -] - -[[package]] -name = "syn" -version = "1.0.91" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b683b2b825c8eef438b77c36a06dc262294da3d5a5813fac20da149241dcd44d" -dependencies = [ - "proc-macro2", - "quote", - "unicode-xid", -] - -[[package]] -name = "tempfile" -version = "3.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" -dependencies = [ - "cfg-if 1.0.0", - "fastrand", - "libc", - "redox_syscall", - "remove_dir_all", - "winapi", -] - -[[package]] -name = "tracing" -version = "0.1.34" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d0ecdcb44a79f0fe9844f0c4f33a342cbcbb5117de8001e6ba0dc2351327d09" -dependencies = [ - "cfg-if 1.0.0", - "pin-project-lite", - "tracing-attributes", - "tracing-core", -] - -[[package]] -name = "tracing-attributes" -version = "0.1.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e65ce065b4b5c53e73bb28912318cb8c9e9ad3921f1d669eb0e68b4c8143a2b" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "tracing-core" -version = "0.1.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f54c8ca710e81886d498c2fd3331b56c93aa248d49de2222ad2742247c60072f" -dependencies = [ - "lazy_static", -] - -[[package]] -name = "typenum" -version = "1.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" - -[[package]] -name = "unicode-width" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" - -[[package]] -name = "unicode-xid" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" - -[[package]] -name = "version_check" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/kclvm/3rdparty/rustc_span/Cargo.toml b/kclvm/3rdparty/rustc_span/Cargo.toml deleted file mode 100644 index 134fe0143..000000000 --- a/kclvm/3rdparty/rustc_span/Cargo.toml +++ /dev/null @@ -1,17 +0,0 @@ -[package] -name = "rustc_span" -version = "0.0.0" -edition = "2021" - -[lib] -doctest = false - -[dependencies] -rustc_data_structures = { path = "../rustc_data_structures" } -scoped-tls = "1.0" -unicode-width = "0.1.4" -cfg-if = "0.1.2" -tracing = "0.1" -sha1 = { package = "sha-1", version = "0.10.0" } -sha2 = "0.10.1" -md5 = { package = "md-5", version = "0.10.0" } \ No newline at end of file diff --git a/kclvm/3rdparty/rustc_span/src/lib.rs b/kclvm/3rdparty/rustc_span/src/lib.rs deleted file mode 100644 index 83d6f1a24..000000000 --- a/kclvm/3rdparty/rustc_span/src/lib.rs +++ /dev/null @@ -1,1195 +0,0 @@ -//! Source positions and related helper functions. -//! -//! Important concepts in this module include: -//! -//! - the *span*, represented by [`SpanData`] and related types; -//! - source code as represented by a [`SourceMap`]; and -//! - interned strings, represented by [`Symbol`]s, with some common symbols available statically in the [`sym`] module. -//! -//! Unlike most compilers, the span contains not only the position in the source code, but also various other metadata, -//! such as the edition and macro hygiene. This metadata is stored in [`SyntaxContext`] and [`ExpnData`]. -//! -//! ## Note -//! -//! This API is completely unstable and subject to change. - -mod caching_source_map_view; -mod fatal_error; -pub mod source_map; -pub use self::caching_source_map_view::CachingSourceMapView; -use rustc_data_structures::sync::Lrc; -pub use source_map::SourceMap; - -mod span_encoding; -pub use span_encoding::{Span, DUMMY_SP}; - -mod analyze_source_file; - -use std::borrow::Cow; -use std::cmp::{self, Ordering}; -use std::collections::hash_map::DefaultHasher; -use std::fmt; -use std::hash::{Hash, Hasher}; -use std::ops::{Add, Range, Sub}; -use std::path::{Path, PathBuf}; -use std::rc::Rc; -use std::str::FromStr; - -use md5::Digest; -use md5::Md5; -use sha1::Sha1; -use sha2::Sha256; - -use tracing::debug; - -// FIXME: We should use this enum or something like it to get rid of the -// use of magic `/rust/1.x/...` paths across the board. -#[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd)] -pub enum RealFileName { - LocalPath(PathBuf), - /// For remapped paths (namely paths into libstd that have been mapped - /// to the appropriate spot on the local host's file system, and local file - /// system paths that have been remapped with `FilePathMapping`), - Remapped { - /// `local_path` is the (host-dependent) local path to the file. This is - /// None if the file was imported from another crate - local_path: Option, - /// `virtual_name` is the stable path rustc will store internally within - /// build artifacts. - virtual_name: PathBuf, - }, -} - -impl Hash for RealFileName { - fn hash(&self, state: &mut H) { - // To prevent #70924 from happening again we should only hash the - // remapped (virtualized) path if that exists. This is because - // virtualized paths to sysroot crates (/rust/$hash or /rust/$version) - // remain stable even if the corresponding local_path changes - self.remapped_path_if_available().hash(state) - } -} - -impl RealFileName { - /// Returns the path suitable for reading from the file system on the local host, - /// if this information exists. - /// Avoid embedding this in build artifacts; see `remapped_path_if_available()` for that. - pub fn local_path(&self) -> Option<&Path> { - match self { - RealFileName::LocalPath(p) => Some(p), - RealFileName::Remapped { - local_path: p, - virtual_name: _, - } => p.as_ref().map(PathBuf::as_path), - } - } - - /// Returns the path suitable for reading from the file system on the local host, - /// if this information exists. - /// Avoid embedding this in build artifacts; see `remapped_path_if_available()` for that. - pub fn into_local_path(self) -> Option { - match self { - RealFileName::LocalPath(p) => Some(p), - RealFileName::Remapped { - local_path: p, - virtual_name: _, - } => p, - } - } - - /// Returns the path suitable for embedding into build artifacts. This would still - /// be a local path if it has not been remapped. A remapped path will not correspond - /// to a valid file system path: see `local_path_if_available()` for something that - /// is more likely to return paths into the local host file system. - pub fn remapped_path_if_available(&self) -> &Path { - match self { - RealFileName::LocalPath(p) - | RealFileName::Remapped { - local_path: _, - virtual_name: p, - } => &p, - } - } - - /// Returns the path suitable for reading from the file system on the local host, - /// if this information exists. Otherwise returns the remapped name. - /// Avoid embedding this in build artifacts; see `remapped_path_if_available()` for that. - pub fn local_path_if_available(&self) -> &Path { - match self { - RealFileName::LocalPath(path) - | RealFileName::Remapped { - local_path: None, - virtual_name: path, - } - | RealFileName::Remapped { - local_path: Some(path), - virtual_name: _, - } => path, - } - } - - pub fn to_string_lossy(&self, display_pref: FileNameDisplayPreference) -> Cow<'_, str> { - match display_pref { - FileNameDisplayPreference::Local => self.local_path_if_available().to_string_lossy(), - FileNameDisplayPreference::Remapped => { - self.remapped_path_if_available().to_string_lossy() - } - } - } -} - -/// Differentiates between real files and common virtual files. -#[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd, Hash)] -pub enum FileName { - Real(RealFileName), - /// Call to `quote!`. - QuoteExpansion(u64), - /// Command line. - Anon(u64), - /// Hack in `src/librustc_ast/parse.rs`. - // FIXME(jseyfried) - MacroExpansion(u64), - ProcMacroSourceCode(u64), - /// Strings provided as `--cfg [cfgspec]` stored in a `crate_cfg`. - CfgSpec(u64), - /// Strings provided as crate attributes in the CLI. - CliCrateAttr(u64), - /// Custom sources for explicit parser calls from plugins and drivers. - Custom(String), - DocTest(PathBuf, isize), - /// Post-substitution inline assembly from LLVM. - InlineAsm(u64), -} - -impl From for FileName { - fn from(p: PathBuf) -> Self { - assert!(!p.to_string_lossy().ends_with('>')); - FileName::Real(RealFileName::LocalPath(p)) - } -} - -#[derive(Clone, Copy, Eq, PartialEq, Hash, Debug)] -pub enum FileNameDisplayPreference { - Remapped, - Local, -} - -pub struct FileNameDisplay<'a> { - inner: &'a FileName, - display_pref: FileNameDisplayPreference, -} - -impl fmt::Display for FileNameDisplay<'_> { - fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - use FileName::*; - match *self.inner { - Real(ref name) => { - write!(fmt, "{}", name.to_string_lossy(self.display_pref)) - } - QuoteExpansion(_) => write!(fmt, ""), - MacroExpansion(_) => write!(fmt, ""), - Anon(_) => write!(fmt, ""), - ProcMacroSourceCode(_) => write!(fmt, ""), - CfgSpec(_) => write!(fmt, ""), - CliCrateAttr(_) => write!(fmt, ""), - Custom(ref s) => write!(fmt, "<{}>", s), - DocTest(ref path, _) => write!(fmt, "{}", path.display()), - InlineAsm(_) => write!(fmt, ""), - } - } -} - -impl FileNameDisplay<'_> { - pub fn to_string_lossy(&self) -> Cow<'_, str> { - match self.inner { - FileName::Real(ref inner) => inner.to_string_lossy(self.display_pref), - _ => Cow::from(format!("{}", self)), - } - } -} - -impl FileName { - pub fn is_real(&self) -> bool { - use FileName::*; - match *self { - Real(_) => true, - Anon(_) - | MacroExpansion(_) - | ProcMacroSourceCode(_) - | CfgSpec(_) - | CliCrateAttr(_) - | Custom(_) - | QuoteExpansion(_) - | DocTest(_, _) - | InlineAsm(_) => false, - } - } - - pub fn prefer_remapped(&self) -> FileNameDisplay<'_> { - FileNameDisplay { - inner: self, - display_pref: FileNameDisplayPreference::Remapped, - } - } - - // This may include transient local filesystem information. - // Must not be embedded in build outputs. - pub fn prefer_local(&self) -> FileNameDisplay<'_> { - FileNameDisplay { - inner: self, - display_pref: FileNameDisplayPreference::Local, - } - } - - pub fn display(&self, display_pref: FileNameDisplayPreference) -> FileNameDisplay<'_> { - FileNameDisplay { - inner: self, - display_pref, - } - } -} - -/// Represents a span. -/// -/// Spans represent a region of code, used for error reporting. Positions in spans -/// are *absolute* positions from the beginning of the [`SourceMap`], not positions -/// relative to [`SourceFile`]s. Methods on the `SourceMap` can be used to relate spans back -/// to the original source. -/// -/// You must be careful if the span crosses more than one file, since you will not be -/// able to use many of the functions on spans in source_map and you cannot assume -/// that the length of the span is equal to `span.hi - span.lo`; there may be space in the -/// [`BytePos`] range between files. -/// -/// `SpanData` is public because `Span` uses a thread-local interner and can't be -/// sent to other threads, but some pieces of performance infra run in a separate thread. -/// Using `Span` is generally preferred. -#[derive(Clone, Copy, Hash, PartialEq, Eq)] -pub struct SpanData { - pub lo: BytePos, - pub hi: BytePos, -} - -// Order spans by position in the file. -impl Ord for SpanData { - fn cmp(&self, other: &Self) -> Ordering { - let SpanData { lo: s_lo, hi: s_hi } = self; - let SpanData { lo: o_lo, hi: o_hi } = other; - - (s_lo, s_hi).cmp(&(o_lo, o_hi)) - } -} - -impl PartialOrd for SpanData { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} - -impl SpanData { - #[inline] - pub fn span(&self) -> Span { - Span::new(self.lo, self.hi) - } - #[inline] - pub fn with_lo(&self, lo: BytePos) -> Span { - Span::new(lo, self.hi) - } - #[inline] - pub fn with_hi(&self, hi: BytePos) -> Span { - Span::new(self.lo, hi) - } - /// Returns `true` if this is a dummy span with any hygienic context. - #[inline] - pub fn is_dummy(self) -> bool { - self.lo.0 == 0 && self.hi.0 == 0 - } - /// Returns `true` if `self` fully encloses `other`. - pub fn contains(self, other: Self) -> bool { - self.lo <= other.lo && other.hi <= self.hi - } -} - -impl PartialOrd for Span { - fn partial_cmp(&self, rhs: &Self) -> Option { - PartialOrd::partial_cmp(&self.data(), &rhs.data()) - } -} -impl Ord for Span { - fn cmp(&self, rhs: &Self) -> Ordering { - Ord::cmp(&self.data(), &rhs.data()) - } -} - -impl Span { - #[inline] - pub fn lo(self) -> BytePos { - self.data().lo - } - #[inline] - pub fn with_lo(self, lo: BytePos) -> Span { - self.data().with_lo(lo) - } - #[inline] - pub fn hi(self) -> BytePos { - self.data().hi - } - #[inline] - pub fn with_hi(self, hi: BytePos) -> Span { - self.data().with_hi(hi) - } - - /// Returns `true` if this is a dummy span with any hygienic context. - #[inline] - pub fn is_dummy(self) -> bool { - self.data_untracked().is_dummy() - } - - /// Returns a new span representing an empty span at the beginning of this span. - #[inline] - pub fn shrink_to_lo(self) -> Span { - let span = self.data_untracked(); - span.with_hi(span.lo) - } - /// Returns a new span representing an empty span at the end of this span. - #[inline] - pub fn shrink_to_hi(self) -> Span { - let span = self.data_untracked(); - span.with_lo(span.hi) - } - - #[inline] - /// Returns `true` if `hi == lo`. - pub fn is_empty(self) -> bool { - let span = self.data_untracked(); - span.hi == span.lo - } - - /// Returns `self` if `self` is not the dummy span, and `other` otherwise. - pub fn substitute_dummy(self, other: Span) -> Span { - if self.is_dummy() { - other - } else { - self - } - } - - /// Returns `true` if `self` fully encloses `other`. - pub fn contains(self, other: Span) -> bool { - let span = self.data(); - let other = other.data(); - span.contains(other) - } - - /// Returns `true` if `self` touches `other`. - pub fn overlaps(self, other: Span) -> bool { - let span = self.data(); - let other = other.data(); - span.lo < other.hi && other.lo < span.hi - } - - /// Returns `true` if the spans are equal with regards to the source text. - /// - /// Use this instead of `==` when either span could be generated code, - /// and you only care that they point to the same bytes of source text. - pub fn source_equal(self, other: Span) -> bool { - let span = self.data(); - let other = other.data(); - span.lo == other.lo && span.hi == other.hi - } - - /// Returns `Some(span)`, where the start is trimmed by the end of `other`. - pub fn trim_start(self, other: Span) -> Option { - let span = self.data(); - let other = other.data(); - if span.hi > other.hi { - Some(span.with_lo(cmp::max(span.lo, other.hi))) - } else { - None - } - } - - /// Returns a `Span` that would enclose both `self` and `end`. - /// - /// ```text - /// ____ ___ - /// self lorem ipsum end - /// ^^^^^^^^^^^^^^^^^^^^ - /// ``` - pub fn to(self, end: Span) -> Span { - let span_data = self.data(); - let end_data = end.data(); - Span::new( - cmp::min(span_data.lo, end_data.lo), - cmp::max(span_data.hi, end_data.hi), - ) - } - - /// Returns a `Span` between the end of `self` to the beginning of `end`. - /// - /// ```text - /// ____ ___ - /// self lorem ipsum end - /// ^^^^^^^^^^^^^ - /// ``` - pub fn between(self, end: Span) -> Span { - let span = self.data(); - let end = end.data(); - Span::new(span.hi, end.lo) - } - - /// Returns a `Span` from the beginning of `self` until the beginning of `end`. - /// - /// ```text - /// ____ ___ - /// self lorem ipsum end - /// ^^^^^^^^^^^^^^^^^ - /// ``` - pub fn until(self, end: Span) -> Span { - // Most of this function's body is copied from `to`. - // We can't just do `self.to(end.shrink_to_lo())`, - // because to also does some magic where it uses min/max so - // it can handle overlapping spans. Some advanced mis-use of - // `until` with different ctxts makes this visible. - let span_data = self.data(); - let end_data = end.data(); - Span::new(span_data.lo, end_data.lo) - } - - pub fn from_inner(self, inner: InnerSpan) -> Span { - let span = self.data(); - Span::new( - span.lo + BytePos::from_usize(inner.start), - span.lo + BytePos::from_usize(inner.end), - ) - } -} - -impl Default for Span { - fn default() -> Self { - DUMMY_SP - } -} - -impl fmt::Debug for SpanData { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Debug::fmt(&Span::new(self.lo, self.hi), f) - } -} - -/// Identifies an offset of a multi-byte character in a `SourceFile`. -#[derive(Copy, Clone, Eq, PartialEq, Debug)] -pub struct MultiByteChar { - /// The absolute offset of the character in the `SourceMap`. - pub pos: BytePos, - /// The number of bytes, `>= 2`. - pub bytes: u8, -} - -/// Identifies an offset of a non-narrow character in a `SourceFile`. -#[derive(Copy, Clone, Eq, PartialEq, Debug)] -pub enum NonNarrowChar { - /// Represents a zero-width character. - ZeroWidth(BytePos), - /// Represents a wide (full-width) character. - Wide(BytePos), - /// Represents a tab character, represented visually with a width of 4 characters. - Tab(BytePos), -} - -impl NonNarrowChar { - fn new(pos: BytePos, width: usize) -> Self { - match width { - 0 => NonNarrowChar::ZeroWidth(pos), - 2 => NonNarrowChar::Wide(pos), - 4 => NonNarrowChar::Tab(pos), - _ => panic!("width {} given for non-narrow character", width), - } - } - - /// Returns the absolute offset of the character in the `SourceMap`. - pub fn pos(&self) -> BytePos { - match *self { - NonNarrowChar::ZeroWidth(p) | NonNarrowChar::Wide(p) | NonNarrowChar::Tab(p) => p, - } - } - - /// Returns the width of the character, 0 (zero-width) or 2 (wide). - pub fn width(&self) -> usize { - match *self { - NonNarrowChar::ZeroWidth(_) => 0, - NonNarrowChar::Wide(_) => 2, - NonNarrowChar::Tab(_) => 4, - } - } -} - -impl Add for NonNarrowChar { - type Output = Self; - - fn add(self, rhs: BytePos) -> Self { - match self { - NonNarrowChar::ZeroWidth(pos) => NonNarrowChar::ZeroWidth(pos + rhs), - NonNarrowChar::Wide(pos) => NonNarrowChar::Wide(pos + rhs), - NonNarrowChar::Tab(pos) => NonNarrowChar::Tab(pos + rhs), - } - } -} - -impl Sub for NonNarrowChar { - type Output = Self; - - fn sub(self, rhs: BytePos) -> Self { - match self { - NonNarrowChar::ZeroWidth(pos) => NonNarrowChar::ZeroWidth(pos - rhs), - NonNarrowChar::Wide(pos) => NonNarrowChar::Wide(pos - rhs), - NonNarrowChar::Tab(pos) => NonNarrowChar::Tab(pos - rhs), - } - } -} - -/// Identifies an offset of a character that was normalized away from `SourceFile`. -#[derive(Copy, Clone, Eq, PartialEq, Debug)] -pub struct NormalizedPos { - /// The absolute offset of the character in the `SourceMap`. - pub pos: BytePos, - /// The difference between original and normalized string at position. - pub diff: u32, -} - -#[derive(PartialEq, Eq, Clone, Debug)] -pub enum ExternalSource { - /// No external source has to be loaded, since the `SourceFile` represents a local crate. - Unneeded, - Foreign { - kind: ExternalSourceKind, - /// This SourceFile's byte-offset within the source_map of its original crate. - original_start_pos: BytePos, - /// The end of this SourceFile within the source_map of its original crate. - original_end_pos: BytePos, - }, -} - -/// The state of the lazy external source loading mechanism of a `SourceFile`. -#[derive(PartialEq, Eq, Clone, Debug)] -pub enum ExternalSourceKind { - /// The external source has been loaded already. - Present(Rc), - /// No attempt has been made to load the external source. - AbsentOk, - /// A failed attempt has been made to load the external source. - AbsentErr, - Unneeded, -} - -impl ExternalSource { - pub fn get_source(&self) -> Option<&Rc> { - match self { - ExternalSource::Foreign { - kind: ExternalSourceKind::Present(ref src), - .. - } => Some(src), - _ => None, - } - } -} - -#[derive(Debug)] -pub struct OffsetOverflowError; - -#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub enum SourceFileHashAlgorithm { - Md5, - Sha1, - Sha256, -} - -impl FromStr for SourceFileHashAlgorithm { - type Err = (); - - fn from_str(s: &str) -> Result { - match s { - "md5" => Ok(SourceFileHashAlgorithm::Md5), - "sha1" => Ok(SourceFileHashAlgorithm::Sha1), - "sha256" => Ok(SourceFileHashAlgorithm::Sha256), - _ => Err(()), - } - } -} - -/// The hash of the on-disk source file used for debug info. -#[derive(Copy, Clone, PartialEq, Eq, Debug)] -pub struct SourceFileHash { - pub kind: SourceFileHashAlgorithm, - value: [u8; 32], -} - -impl SourceFileHash { - pub fn new(kind: SourceFileHashAlgorithm, src: &str) -> SourceFileHash { - let mut hash = SourceFileHash { - kind, - value: Default::default(), - }; - let len = hash.hash_len(); - let value = &mut hash.value[..len]; - let data = src.as_bytes(); - match kind { - SourceFileHashAlgorithm::Md5 => { - value.copy_from_slice(&Md5::digest(data)); - } - SourceFileHashAlgorithm::Sha1 => { - value.copy_from_slice(&Sha1::digest(data)); - } - SourceFileHashAlgorithm::Sha256 => { - value.copy_from_slice(&Sha256::digest(data)); - } - } - hash - } - - /// Check if the stored hash matches the hash of the string. - pub fn matches(&self, src: &str) -> bool { - Self::new(self.kind, src) == *self - } - - /// The bytes of the hash. - pub fn hash_bytes(&self) -> &[u8] { - let len = self.hash_len(); - &self.value[..len] - } - - fn hash_len(&self) -> usize { - match self.kind { - SourceFileHashAlgorithm::Md5 => 16, - SourceFileHashAlgorithm::Sha1 => 20, - SourceFileHashAlgorithm::Sha256 => 32, - } - } -} - -/// A single source in the [`SourceMap`]. -#[derive(Clone)] -pub struct SourceFile { - /// The name of the file that the source came from. Source that doesn't - /// originate from files has names between angle brackets by convention - /// (e.g., ``). - pub name: FileName, - /// The complete source code. - pub src: Option>, - /// The source code's hash. - pub src_hash: SourceFileHash, - /// The start position of this source in the `SourceMap`. - pub start_pos: BytePos, - /// The end position of this source in the `SourceMap`. - pub end_pos: BytePos, - /// Locations of lines beginnings in the source code. - pub lines: Vec, - /// Locations of multi-byte characters in the source code. - pub multibyte_chars: Vec, - /// Width of characters that are not narrow in the source code. - pub non_narrow_chars: Vec, - /// Locations of characters removed during normalization. - pub normalized_pos: Vec, - /// A hash of the filename, used for speeding up hashing in incremental compilation. - pub name_hash: u64, -} - -impl fmt::Debug for SourceFile { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(fmt, "SourceFile({:?})", self.name) - } -} - -impl SourceFile { - pub fn new( - name: FileName, - mut src: String, - start_pos: BytePos, - hash_kind: SourceFileHashAlgorithm, - ) -> Self { - // Compute the file hash before any normalization. - let src_hash = SourceFileHash::new(hash_kind, &src); - let normalized_pos = normalize_src(&mut src, start_pos); - - let name_hash = { - let mut hasher = DefaultHasher::new(); - name.hash(&mut hasher); - hasher.finish() - }; - let end_pos = start_pos.to_usize() + src.len(); - assert!(end_pos <= u32::MAX as usize); - - let (lines, multibyte_chars, non_narrow_chars) = - analyze_source_file::analyze_source_file(&src, start_pos); - - SourceFile { - name, - src: Some(Rc::new(src)), - src_hash, - start_pos, - end_pos: Pos::from_usize(end_pos), - lines, - multibyte_chars, - non_narrow_chars, - normalized_pos, - name_hash, - } - } - - /// Returns the `BytePos` of the beginning of the current line. - pub fn line_begin_pos(&self, pos: BytePos) -> BytePos { - let line_index = self.lookup_line(pos).unwrap(); - self.lines[line_index] - } - - /// Gets a line from the list of pre-computed line-beginnings. - /// The line number here is 0-based. - pub fn get_line(&self, line_number: usize) -> Option> { - fn get_until_newline(src: &str, begin: usize) -> &str { - // We can't use `lines.get(line_number+1)` because we might - // be parsing when we call this function and thus the current - // line is the last one we have line info for. - let slice = &src[begin..]; - match slice.find('\n') { - Some(e) => &slice[..e], - None => slice, - } - } - - let begin = { - let line = self.lines.get(line_number)?; - let begin: BytePos = *line - self.start_pos; - begin.to_usize() - }; - - if let Some(ref src) = self.src { - Some(Cow::from(get_until_newline(src, begin))) - } else { - None - } - } - - pub fn is_real_file(&self) -> bool { - self.name.is_real() - } - - pub fn is_imported(&self) -> bool { - self.src.is_none() - } - - pub fn count_lines(&self) -> usize { - self.lines.len() - } - - /// Finds the line containing the given position. The return value is the - /// index into the `lines` array of this `SourceFile`, not the 1-based line - /// number. If the source_file is empty or the position is located before the - /// first line, `None` is returned. - pub fn lookup_line(&self, pos: BytePos) -> Option { - match self.lines.binary_search(&pos) { - Ok(idx) => Some(idx), - Err(0) => None, - Err(idx) => Some(idx - 1), - } - } - - pub fn line_bounds(&self, line_index: usize) -> Range { - if self.is_empty() { - return self.start_pos..self.end_pos; - } - - assert!(line_index < self.lines.len()); - if line_index == (self.lines.len() - 1) { - self.lines[line_index]..self.end_pos - } else { - self.lines[line_index]..self.lines[line_index + 1] - } - } - - /// Returns whether or not the file contains the given `SourceMap` byte - /// position. The position one past the end of the file is considered to be - /// contained by the file. This implies that files for which `is_empty` - /// returns true still contain one byte position according to this function. - #[inline] - pub fn contains(&self, byte_pos: BytePos) -> bool { - byte_pos >= self.start_pos && byte_pos <= self.end_pos - } - - #[inline] - pub fn is_empty(&self) -> bool { - self.start_pos == self.end_pos - } - - /// Calculates the original byte position relative to the start of the file - /// based on the given byte position. - pub fn original_relative_byte_pos(&self, pos: BytePos) -> BytePos { - // Diff before any records is 0. Otherwise use the previously recorded - // diff as that applies to the following characters until a new diff - // is recorded. - let diff = match self.normalized_pos.binary_search_by(|np| np.pos.cmp(&pos)) { - Ok(i) => self.normalized_pos[i].diff, - Err(i) if i == 0 => 0, - Err(i) => self.normalized_pos[i - 1].diff, - }; - - BytePos::from_u32(pos.0 - self.start_pos.0 + diff) - } - - /// Converts an absolute `BytePos` to a `CharPos` relative to the `SourceFile`. - pub fn bytepos_to_file_charpos(&self, bpos: BytePos) -> CharPos { - // The number of extra bytes due to multibyte chars in the `SourceFile`. - let mut total_extra_bytes = 0; - - for mbc in self.multibyte_chars.iter() { - debug!("{}-byte char at {:?}", mbc.bytes, mbc.pos); - if mbc.pos < bpos { - // Every character is at least one byte, so we only - // count the actual extra bytes. - total_extra_bytes += mbc.bytes as u32 - 1; - // We should never see a byte position in the middle of a - // character. - assert!(bpos.to_u32() >= mbc.pos.to_u32() + mbc.bytes as u32); - } else { - break; - } - } - - assert!(self.start_pos.to_u32() + total_extra_bytes <= bpos.to_u32()); - CharPos(bpos.to_usize() - self.start_pos.to_usize() - total_extra_bytes as usize) - } - - /// Looks up the file's (1-based) line number and (0-based `CharPos`) column offset, for a - /// given `BytePos`. - pub fn lookup_file_pos(&self, pos: BytePos) -> (usize, CharPos) { - let chpos = self.bytepos_to_file_charpos(pos); - match self.lookup_line(pos) { - Some(a) => { - let line = a + 1; // Line numbers start at 1 - let linebpos = self.lines[a]; - let linechpos = self.bytepos_to_file_charpos(linebpos); - let col = chpos - linechpos; - debug!( - "byte pos {:?} is on the line at byte pos {:?}", - pos, linebpos - ); - debug!( - "char pos {:?} is on the line at char pos {:?}", - chpos, linechpos - ); - debug!("byte is on line: {}", line); - assert!(chpos >= linechpos); - (line, col) - } - None => (0, chpos), - } - } - - /// Looks up the file's (1-based) line number, (0-based `CharPos`) column offset, and (0-based) - /// column offset when displayed, for a given `BytePos`. - pub fn lookup_file_pos_with_col_display(&self, pos: BytePos) -> (usize, CharPos, usize) { - let (line, col_or_chpos) = self.lookup_file_pos(pos); - if line > 0 { - let col = col_or_chpos; - let linebpos = self.lines[line - 1]; - let col_display = { - let start_width_idx = self - .non_narrow_chars - .binary_search_by_key(&linebpos, |x| x.pos()) - .unwrap_or_else(|x| x); - let end_width_idx = self - .non_narrow_chars - .binary_search_by_key(&pos, |x| x.pos()) - .unwrap_or_else(|x| x); - let special_chars = end_width_idx - start_width_idx; - let non_narrow: usize = self.non_narrow_chars[start_width_idx..end_width_idx] - .iter() - .map(|x| x.width()) - .sum(); - col.0 - special_chars + non_narrow - }; - (line, col, col_display) - } else { - let chpos = col_or_chpos; - let col_display = { - let end_width_idx = self - .non_narrow_chars - .binary_search_by_key(&pos, |x| x.pos()) - .unwrap_or_else(|x| x); - let non_narrow: usize = self.non_narrow_chars[0..end_width_idx] - .iter() - .map(|x| x.width()) - .sum(); - chpos.0 - end_width_idx + non_narrow - }; - (0, chpos, col_display) - } - } -} - -/// Normalizes the source code and records the normalizations. -fn normalize_src(src: &mut String, start_pos: BytePos) -> Vec { - let mut normalized_pos = vec![]; - remove_bom(src, &mut normalized_pos); - normalize_newlines(src, &mut normalized_pos); - - // Offset all the positions by start_pos to match the final file positions. - for np in &mut normalized_pos { - np.pos.0 += start_pos.0; - } - - normalized_pos -} - -/// Removes UTF-8 BOM, if any. -fn remove_bom(src: &mut String, normalized_pos: &mut Vec) { - if src.starts_with('\u{feff}') { - src.drain(..3); - normalized_pos.push(NormalizedPos { - pos: BytePos(0), - diff: 3, - }); - } -} - -/// Replaces `\r\n` with `\n` in-place in `src`. -/// -/// Returns error if there's a lone `\r` in the string. -fn normalize_newlines(src: &mut String, normalized_pos: &mut Vec) { - if !src.as_bytes().contains(&b'\r') { - return; - } - - // We replace `\r\n` with `\n` in-place, which doesn't break utf-8 encoding. - // While we *can* call `as_mut_vec` and do surgery on the live string - // directly, let's rather steal the contents of `src`. This makes the code - // safe even if a panic occurs. - - let mut buf = std::mem::replace(src, String::new()).into_bytes(); - let mut gap_len = 0; - let mut tail = buf.as_mut_slice(); - let mut cursor = 0; - let original_gap = normalized_pos.last().map_or(0, |l| l.diff); - loop { - let idx = match find_crlf(&tail[gap_len..]) { - None => tail.len(), - Some(idx) => idx + gap_len, - }; - tail.copy_within(gap_len..idx, 0); - tail = &mut tail[idx - gap_len..]; - if tail.len() == gap_len { - break; - } - cursor += idx - gap_len; - gap_len += 1; - normalized_pos.push(NormalizedPos { - pos: BytePos::from_usize(cursor + 1), - diff: original_gap + gap_len as u32, - }); - } - - // Account for removed `\r`. - // After `set_len`, `buf` is guaranteed to contain utf-8 again. - let new_len = buf.len() - gap_len; - unsafe { - buf.set_len(new_len); - *src = String::from_utf8_unchecked(buf); - } - - fn find_crlf(src: &[u8]) -> Option { - let mut search_idx = 0; - while let Some(idx) = find_cr(&src[search_idx..]) { - if src[search_idx..].get(idx + 1) != Some(&b'\n') { - search_idx += idx + 1; - continue; - } - return Some(search_idx + idx); - } - None - } - - fn find_cr(src: &[u8]) -> Option { - src.iter().position(|&b| b == b'\r') - } -} - -// _____________________________________________________________________________ -// Pos, BytePos, CharPos -// - -pub trait Pos { - fn from_usize(n: usize) -> Self; - fn to_usize(&self) -> usize; - fn from_u32(n: u32) -> Self; - fn to_u32(&self) -> u32; -} - -macro_rules! impl_pos { - ( - $( - $(#[$attr:meta])* - $vis:vis struct $ident:ident($inner_vis:vis $inner_ty:ty); - )* - ) => { - $( - $(#[$attr])* - $vis struct $ident($inner_vis $inner_ty); - - impl Pos for $ident { - #[inline(always)] - fn from_usize(n: usize) -> $ident { - $ident(n as $inner_ty) - } - - #[inline(always)] - fn to_usize(&self) -> usize { - self.0 as usize - } - - #[inline(always)] - fn from_u32(n: u32) -> $ident { - $ident(n as $inner_ty) - } - - #[inline(always)] - fn to_u32(&self) -> u32 { - self.0 as u32 - } - } - - impl Add for $ident { - type Output = $ident; - - #[inline(always)] - fn add(self, rhs: $ident) -> $ident { - $ident(self.0 + rhs.0) - } - } - - impl Sub for $ident { - type Output = $ident; - - #[inline(always)] - fn sub(self, rhs: $ident) -> $ident { - $ident(self.0 - rhs.0) - } - } - - impl fmt::Display for $ident { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}", self.0) - } - } - )* - }; -} - -impl_pos! { - /// A byte offset. - /// - /// Keep this small (currently 32-bits), as AST contains a lot of them. - #[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)] - pub struct BytePos(pub u32); - - /// A character offset. - /// - /// Because of multibyte UTF-8 characters, a byte offset - /// is not equivalent to a character offset. The [`SourceMap`] will convert [`BytePos`] - /// values to `CharPos` values as necessary. - #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)] - pub struct CharPos(pub usize); -} - -impl BytePos {} - -// _____________________________________________________________________________ -// Loc, SourceFileAndLine, SourceFileAndBytePos -// - -/// A source code location used for error reporting. -#[derive(Debug, Clone)] -pub struct Loc { - /// Information about the original source. - pub file: Lrc, - /// The (1-based) line number. - pub line: usize, - /// The (0-based) column offset. - pub col: CharPos, - /// The (0-based) column offset when displayed. - pub col_display: usize, -} - -// Used to be structural records. -#[derive(Debug)] -pub struct SourceFileAndLine { - pub sf: Lrc, - /// Index of line, starting from 0. - pub line: usize, -} -#[derive(Debug)] -pub struct SourceFileAndBytePos { - pub sf: Lrc, - pub pos: BytePos, -} - -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub struct LineInfo { - /// Index of line, starting from 0. - pub line_index: usize, - - /// Column in line where span begins, starting from 0. - pub start_col: CharPos, - - /// Column in line where span ends, starting from 0, exclusive. - pub end_col: CharPos, -} - -pub struct FileLines { - pub file: Lrc, - pub lines: Vec, -} - -// _____________________________________________________________________________ -// SpanLinesError, SpanSnippetError, DistinctSources, MalformedSourceMapPositions -// - -pub type FileLinesResult = Result; - -#[derive(Clone, PartialEq, Eq, Debug)] -pub enum SpanLinesError { - DistinctSources(DistinctSources), -} - -#[derive(Clone, PartialEq, Eq, Debug)] -pub enum SpanSnippetError { - IllFormedSpan(Span), - DistinctSources(DistinctSources), - MalformedForSourcemap(MalformedSourceMapPositions), - SourceNotAvailable { filename: FileName }, -} - -#[derive(Clone, PartialEq, Eq, Debug)] -pub struct DistinctSources { - pub begin: (FileName, BytePos), - pub end: (FileName, BytePos), -} - -#[derive(Clone, PartialEq, Eq, Debug)] -pub struct MalformedSourceMapPositions { - pub name: FileName, - pub source_len: usize, - pub begin_pos: BytePos, - pub end_pos: BytePos, -} - -/// Range inside of a `Span` used for diagnostics when we only have access to relative positions. -#[derive(Copy, Clone, PartialEq, Eq, Debug)] -pub struct InnerSpan { - pub start: usize, - pub end: usize, -} - -impl InnerSpan { - pub fn new(start: usize, end: usize) -> InnerSpan { - InnerSpan { start, end } - } -} diff --git a/kclvm/Cargo.lock b/kclvm/Cargo.lock index 270ecf918..28d20ba40 100644 --- a/kclvm/Cargo.lock +++ b/kclvm/Cargo.lock @@ -2,11 +2,26 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "addr2line" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + [[package]] name = "ahash" -version = "0.7.6" +version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" +checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" dependencies = [ "getrandom", "once_cell", @@ -15,1692 +30,5357 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "0.7.18" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" dependencies = [ "memchr", ] [[package]] -name = "annotate-snippets" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d78ea013094e5ea606b1c05fe35f1dd7ea1eb1ea259908d040b25bd5ec677ee5" - -[[package]] -name = "ansi_term" -version = "0.11.0" +name = "always-assert" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" +checksum = "4436e0292ab1bb631b42973c61205e704475fe8126af845c8d923c0996328127" dependencies = [ - "winapi", + "log", ] [[package]] -name = "arrayvec" -version = "0.7.2" +name = "android-tzdata" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" [[package]] -name = "atty" -version = "0.2.14" +name = "android_system_properties" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" dependencies = [ - "hermit-abi", "libc", - "winapi", ] [[package]] -name = "autocfg" -version = "1.1.0" +name = "anes" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" [[package]] -name = "base64" -version = "0.13.0" +name = "annotate-snippets" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" +checksum = "ccaf7e9dfbb6ab22c82e473cd1a8a7bd313c19a5b7e40970f3d89ef5a5c9e81e" +dependencies = [ + "unicode-width", + "yansi-term", +] [[package]] -name = "bit-set" -version = "0.5.2" +name = "anstream" +version = "0.6.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e11e16035ea35e4e5997b393eacbf6f63983188f7a2ad25bfb13465f5ad59de" +checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526" dependencies = [ - "bit-vec", + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", ] [[package]] -name = "bit-vec" -version = "0.6.3" +name = "anstyle" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" +checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" [[package]] -name = "bitflags" -version = "1.3.2" +name = "anstyle-parse" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb" +dependencies = [ + "utf8parse", +] [[package]] -name = "block-buffer" -version = "0.9.0" +name = "anstyle-query" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a" dependencies = [ - "generic-array", + "windows-sys 0.52.0", ] [[package]] -name = "block-buffer" -version = "0.10.2" +name = "anstyle-wincon" +version = "3.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bf7fe51849ea569fd452f37822f606a5cabb684dc918707a0193fd4664ff324" +checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8" dependencies = [ - "generic-array", + "anstyle", + "windows-sys 0.52.0", ] [[package]] -name = "bstr" -version = "0.2.17" +name = "anyhow" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223" +checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" dependencies = [ - "lazy_static", - "memchr", - "regex-automata", + "backtrace", ] [[package]] -name = "cc" -version = "1.0.70" +name = "arrayref" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d26a6ce4b6a484fa3edb70f7efa6fc430fd2b87285fe8b84304fd0936faa0dc0" +checksum = "9d151e35f61089500b617991b791fc8bfd237ae50cd5950803758a179b41e67a" [[package]] -name = "cfg-if" -version = "0.1.10" +name = "arrayvec" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" +checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" [[package]] -name = "cfg-if" -version = "1.0.0" +name = "async-stream" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +checksum = "cd56dd203fef61ac097dd65721a419ddccb106b2d2b70ba60a6b529f03961a51" +dependencies = [ + "async-stream-impl", + "futures-core", + "pin-project-lite", +] [[package]] -name = "chrono" -version = "0.4.19" +name = "async-stream-impl" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73" +checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" dependencies = [ - "libc", - "num-integer", - "num-traits", - "time", - "winapi", + "proc-macro2", + "quote", + "syn 2.0.72", ] [[package]] -name = "clap" -version = "2.33.3" +name = "autocfg" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002" -dependencies = [ - "ansi_term", - "atty", - "bitflags", - "strsim", - "textwrap", - "unicode-width", - "vec_map", -] +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" [[package]] -name = "cpufeatures" -version = "0.2.1" +name = "backtrace" +version = "0.3.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95059428f66df56b63431fdb4e1947ed2190586af5c5a8a8b71122bdf5a7f469" +checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a" dependencies = [ + "addr2line", + "cc", + "cfg-if 1.0.0", "libc", + "miniz_oxide", + "object", + "rustc-demangle", ] [[package]] -name = "crossbeam-deque" -version = "0.8.1" +name = "base-x" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e" -dependencies = [ - "cfg-if 1.0.0", - "crossbeam-epoch", - "crossbeam-utils", -] +checksum = "4cbbc9d0964165b47557570cce6c952866c2678457aca742aafc9fb771d30270" [[package]] -name = "crossbeam-epoch" -version = "0.9.8" +name = "base64" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1145cf131a2c6ba0615079ab6a638f7e1973ac9c2634fcbeaaad6114246efe8c" -dependencies = [ - "autocfg", - "cfg-if 1.0.0", - "crossbeam-utils", - "lazy_static", - "memoffset", - "scopeguard", -] +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" [[package]] -name = "crossbeam-utils" -version = "0.8.8" +name = "base64" +version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bf124c720b7686e3c2663cf54062ab0f68a88af2fb6a030e87e30bf721fcb38" -dependencies = [ - "cfg-if 1.0.0", - "lazy_static", -] +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] -name = "crypto-common" -version = "0.1.3" +name = "bit-set" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57952ca27b5e3606ff4dd79b0020231aaf9d6aa76dc05fd30137538c50bd3ce8" +checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" dependencies = [ - "generic-array", - "typenum", + "bit-vec", ] [[package]] -name = "digest" -version = "0.9.0" +name = "bit-vec" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" + +[[package]] +name = "bitmaps" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "031043d04099746d8db04daf1fa424b2bc8bd69d92b25962dcde24da39ab64a2" dependencies = [ - "generic-array", + "typenum", ] [[package]] -name = "digest" -version = "0.10.3" +name = "blake3" +version = "1.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2fb860ca6fafa5552fb6d0e816a69c8e49f0908bf524e30a90d97c85892d506" +checksum = "d82033247fd8e890df8f740e407ad4d038debb9eb1f40533fffb32e7d17dc6f7" dependencies = [ - "block-buffer 0.10.2", - "crypto-common", + "arrayref", + "arrayvec", + "cc", + "cfg-if 1.0.0", + "constant_time_eq", ] [[package]] -name = "either" -version = "1.6.1" +name = "block-buffer" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" +checksum = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b" +dependencies = [ + "block-padding", + "byte-tools", + "byteorder", + "generic-array 0.12.4", +] [[package]] -name = "ena" -version = "0.14.0" +name = "block-buffer" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7402b94a93c24e742487327a7cd839dc9d36fec9de9fb25b09f2dae459f36c3" +checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" dependencies = [ - "log", + "generic-array 0.14.7", ] [[package]] -name = "enquote" -version = "1.1.0" +name = "block-buffer" +version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06c36cb11dbde389f4096111698d8b567c0720e3452fd5ac3e6b4e47e1939932" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" dependencies = [ - "thiserror", + "generic-array 0.14.7", ] [[package]] -name = "fancy-regex" -version = "0.7.1" +name = "block-padding" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d6b8560a05112eb52f04b00e5d3790c0dd75d9d980eb8a122fb23b92a623ccf" +checksum = "fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5" dependencies = [ - "bit-set", - "regex", + "byte-tools", ] [[package]] -name = "fastrand" -version = "1.7.0" +name = "bstr" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3fcf0cee53519c866c09b5de1f6c56ff9d647101f81c1964fa632e148896cdf" +checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223" dependencies = [ - "instant", + "lazy_static", + "memchr", + "regex-automata 0.1.10", ] [[package]] -name = "fixedbitset" -version = "0.4.1" +name = "bumpalo" +version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "279fb028e20b3c4c320317955b77c5e0c9701f05a1d309905d6fc702cdc5053e" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" [[package]] -name = "fslock" -version = "0.2.1" +name = "byte-tools" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04412b8935272e3a9bae6f48c7bfff74c2911f60525404edfdd28e49884c3bfb" -dependencies = [ - "libc", - "winapi", -] +checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" [[package]] -name = "fuchsia-cprng" -version = "0.1.1" +name = "byteorder" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] -name = "gcc" -version = "0.3.55" +name = "bytes" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f5f3913fa0bfe7ee1fd8248b6b9f42a5af4b9d65ec2dd2c3c26132b950ecfc2" +checksum = "a12916984aab3fa6e39d655a33e09c0071eb36d6ab3aea5c2d78551f1df6d952" [[package]] -name = "generic-array" -version = "0.14.4" +name = "cast" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "501466ecc8a30d1d3b7fc9229b122b2ce8ed6e9d9223f1138d4babb253e51817" -dependencies = [ - "typenum", - "version_check", -] +checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] -name = "getrandom" -version = "0.2.3" +name = "cc" +version = "1.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753" +checksum = "57b6a275aa2903740dc87da01c62040406b8812552e97129a63ea8850a17c6e6" dependencies = [ - "cfg-if 1.0.0", - "libc", - "wasi", + "shlex", ] [[package]] -name = "glob" -version = "0.3.0" +name = "cfg-if" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" +checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" [[package]] -name = "hashbrown" -version = "0.11.2" +name = "cfg-if" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] -name = "hermit-abi" -version = "0.1.19" +name = "chrono" +version = "0.4.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" dependencies = [ - "libc", + "android-tzdata", + "iana-time-zone", + "js-sys", + "num-traits", + "serde", + "wasm-bindgen", + "windows-targets 0.52.6", ] [[package]] -name = "indexmap" -version = "1.8.1" +name = "ciborium" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f647032dfaa1f8b6dc29bd3edb7bbef4861b8b8007ebb118d6db284fd59f6ee" +checksum = "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e" dependencies = [ - "autocfg", - "hashbrown", - "rustc-rayon", + "ciborium-io", + "ciborium-ll", + "serde", ] [[package]] -name = "inkwell" -version = "0.1.0" -source = "git+https://github.com/TheDan64/inkwell?branch=master#bff378bee02bcbb5bed35f47e9ed69e6642e9188" +name = "ciborium-io" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757" + +[[package]] +name = "ciborium-ll" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9" dependencies = [ - "either", - "inkwell_internals", - "libc", - "llvm-sys", - "once_cell", - "parking_lot", + "ciborium-io", + "half", ] [[package]] -name = "inkwell_internals" -version = "0.5.0" -source = "git+https://github.com/TheDan64/inkwell?branch=master#bff378bee02bcbb5bed35f47e9ed69e6642e9188" +name = "clap" +version = "4.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35723e6a11662c2afb578bcf0b88bf6ea8e21282a953428f240574fcc3a2b5b3" dependencies = [ - "proc-macro2", - "quote", - "syn", + "clap_builder", ] [[package]] -name = "instant" -version = "0.1.10" +name = "clap_builder" +version = "4.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bee0328b1209d157ef001c94dd85b4f8f64139adb0eac2659f4b08382b2f474d" +checksum = "49eb96cbfa7cfa35017b7cd548c75b14c3118c98b423041d70562665e07fb0fa" dependencies = [ - "cfg-if 1.0.0", + "anstream", + "anstyle", + "clap_lex", + "strsim 0.11.1", ] [[package]] -name = "itertools" -version = "0.10.3" +name = "clap_lex" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3" +checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" + +[[package]] +name = "colorchoice" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" + +[[package]] +name = "compiler_base_error" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32e6a143200e9657a565b093fde64a590af93884d1f820829db6461de1ff0086" dependencies = [ - "either", + "anyhow", + "compiler_base_macros", + "compiler_base_span", + "fluent", + "pretty_assertions", + "rustc_errors", + "rustc_span", + "termcolor", + "unic-langid", + "walkdir", ] [[package]] -name = "itoa" -version = "0.4.8" +name = "compiler_base_macros" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" +checksum = "21900034f34b69f860a5ff66e0577b8e66d310090b04bf0334afea9a041e0cee" [[package]] -name = "jobserver" -version = "0.1.24" +name = "compiler_base_session" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af25a77299a7f711a01975c35a6a424eb6862092cc2d6c72c4ed6cbc56dfc1fa" +checksum = "67411f0b5421d9c9f045ec08c4d01fe3861197d11215d1e2e448be663aff9ad9" dependencies = [ - "libc", + "anyhow", + "compiler_base_error", + "compiler_base_span", ] [[package]] -name = "json_minimal" +name = "compiler_base_span" version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a42aae2adfa4b418441ede52835f3c96e9ca63d595f0ac861d94935757e9cb2e" +dependencies = [ + "rustc_span", +] [[package]] -name = "kclvm" -version = "0.1.0" +name = "console" +version = "0.15.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e1f83fc076bd6dd27517eacdf25fef6c4dfe5f1d7448bafaaf3a26f13b5e4eb" dependencies = [ - "chrono", - "clap", - "fslock", - "glob", - "indexmap", - "kclvm-ast", - "kclvm-compiler", - "kclvm-config", - "kclvm-error", - "kclvm-parser", - "kclvm-runner", - "kclvm-runtime", - "kclvm-sema", - "kclvm-tools", - "kclvm-version", + "encode_unicode", + "lazy_static", "libc", - "libloading", + "windows-sys 0.52.0", +] + +[[package]] +name = "const_fn" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "373e9fafaa20882876db20562275ff58d50e0caa2590077fe7ce7bef90211d0d" + +[[package]] +name = "constant_time_eq" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6" + +[[package]] +name = "core-foundation-sys" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" + +[[package]] +name = "cpufeatures" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" +dependencies = [ + "libc", +] + +[[package]] +name = "crc32fast" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" +dependencies = [ + "cfg-if 1.0.0", +] + +[[package]] +name = "criterion" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2b12d017a929603d80db1831cd3a24082f8137ce19c69e6447f54f5fc8d692f" +dependencies = [ + "anes", + "cast", + "ciborium", + "clap", + "criterion-plot", + "is-terminal", + "itertools", + "num-traits", + "once_cell", + "oorandom", + "plotters", + "rayon", + "regex", "serde", + "serde_derive", "serde_json", - "threadpool", + "tinytemplate", "walkdir", ] [[package]] -name = "kclvm-ast" -version = "0.1.0" +name = "criterion-plot" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1" dependencies = [ - "kclvm-span", - "rustc_span", - "serde", - "serde_json", + "cast", + "itertools", ] [[package]] -name = "kclvm-compiler" -version = "0.1.0" +name = "crossbeam-channel" +version = "0.5.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33480d6946193aa8033910124896ca395333cae7e2d1113d1fef6c3272217df2" dependencies = [ - "ahash", - "bit-set", - "bitflags", - "fancy-regex", - "indexmap", - "inkwell", - "kclvm-ast", - "kclvm-error", - "kclvm-runtime", - "kclvm-sema", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" + +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array 0.14.7", + "typenum", +] + +[[package]] +name = "darling" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim 0.11.1", + "syn 2.0.72", +] + +[[package]] +name = "darling_macro" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" +dependencies = [ + "darling_core", + "quote", + "syn 2.0.72", +] + +[[package]] +name = "dashmap" +version = "5.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" +dependencies = [ + "cfg-if 1.0.0", + "hashbrown 0.14.5", + "lock_api", "once_cell", - "phf", - "time", - "unicode_names2", + "parking_lot_core 0.9.10", ] [[package]] -name = "kclvm-config" -version = "0.1.0" +name = "deranged" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" dependencies = [ - "ahash", - "chrono", - "fslock", - "glob", - "indexmap", - "kclvm-version", - "pathdiff", - "ron", - "rust-crypto", - "serde", - "serde_yaml", - "toml", + "powerfmt", +] + +[[package]] +name = "derive_builder" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0350b5cb0331628a5916d6c5c0b72e97393b8b6b03b47a9284f4e7f5a405ffd7" +dependencies = [ + "derive_builder_macro", +] + +[[package]] +name = "derive_builder_core" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d48cda787f839151732d396ac69e3473923d54312c070ee21e9effcaa8ca0b1d" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 2.0.72", +] + +[[package]] +name = "derive_builder_macro" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "206868b8242f27cecce124c19fd88157fbd0dd334df2587f36417bafbc85097b" +dependencies = [ + "derive_builder_core", + "syn 2.0.72", +] + +[[package]] +name = "diff" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" + +[[package]] +name = "digest" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5" +dependencies = [ + "generic-array 0.12.4", +] + +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array 0.14.7", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer 0.10.4", + "crypto-common", + "subtle", +] + +[[package]] +name = "dirs" +version = "5.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225" +dependencies = [ + "dirs-sys", +] + +[[package]] +name = "dirs-sys" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" +dependencies = [ + "libc", + "option-ext", + "redox_users", + "windows-sys 0.48.0", +] + +[[package]] +name = "discard" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0" + +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.72", +] + +[[package]] +name = "dissimilar" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59f8e79d1fbf76bdfbde321e902714bf6c49df88a7dda6fc682fc2979226962d" + +[[package]] +name = "dns-lookup" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5766087c2235fec47fafa4cfecc81e494ee679d0fd4a59887ea0919bfb0e4fc" +dependencies = [ + "cfg-if 1.0.0", + "libc", + "socket2", + "windows-sys 0.48.0", +] + +[[package]] +name = "either" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" + +[[package]] +name = "ena" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d248bdd43ce613d87415282f69b9bb99d947d290b10962dd6c56233312c2ad5" +dependencies = [ + "log", +] + +[[package]] +name = "encode_unicode" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" + +[[package]] +name = "encoding" +version = "0.2.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b0d943856b990d12d3b55b359144ff341533e516d94098b1d3fc1ac666d36ec" +dependencies = [ + "encoding-index-japanese", + "encoding-index-korean", + "encoding-index-simpchinese", + "encoding-index-singlebyte", + "encoding-index-tradchinese", +] + +[[package]] +name = "encoding-index-japanese" +version = "1.20141219.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04e8b2ff42e9a05335dbf8b5c6f7567e5591d0d916ccef4e0b1710d32a0d0c91" +dependencies = [ + "encoding_index_tests", +] + +[[package]] +name = "encoding-index-korean" +version = "1.20141219.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4dc33fb8e6bcba213fe2f14275f0963fd16f0a02c878e3095ecfdf5bee529d81" +dependencies = [ + "encoding_index_tests", +] + +[[package]] +name = "encoding-index-simpchinese" +version = "1.20141219.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d87a7194909b9118fc707194baa434a4e3b0fb6a5a757c73c3adb07aa25031f7" +dependencies = [ + "encoding_index_tests", +] + +[[package]] +name = "encoding-index-singlebyte" +version = "1.20141219.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3351d5acffb224af9ca265f435b859c7c01537c0849754d3db3fdf2bfe2ae84a" +dependencies = [ + "encoding_index_tests", +] + +[[package]] +name = "encoding-index-tradchinese" +version = "1.20141219.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd0e20d5688ce3cab59eb3ef3a2083a5c77bf496cb798dc6fcdb75f323890c18" +dependencies = [ + "encoding_index_tests", +] + +[[package]] +name = "encoding_index_tests" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a246d82be1c9d791c5dfde9a2bd045fc3cbba3fa2b11ad558f27d01712f00569" + +[[package]] +name = "enquote" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06c36cb11dbde389f4096111698d8b567c0720e3452fd5ac3e6b4e47e1939932" +dependencies = [ + "thiserror", +] + +[[package]] +name = "env_filter" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f2c92ceda6ceec50f43169f9ee8424fe2db276791afde7b2cd8bc084cb376ab" +dependencies = [ + "log", + "regex", +] + +[[package]] +name = "env_logger" +version = "0.11.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13fa619b91fb2381732789fc5de83b45675e882f66623b7d8cb4f643017018d" +dependencies = [ + "anstream", + "anstyle", + "env_filter", + "humantime", + "log", +] + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "erased-serde" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24e2389d65ab4fab27dc2a5de7b191e1f6617d1f1c8855c0dc569c94a4cbb18d" +dependencies = [ + "serde", + "typeid", +] + +[[package]] +name = "errno" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "expect-test" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e0be0a561335815e06dab7c62e50353134c796e7a6155402a64bcff66b6a5e0" +dependencies = [ + "dissimilar", + "once_cell", +] + +[[package]] +name = "fancy-regex" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d6b8560a05112eb52f04b00e5d3790c0dd75d9d980eb8a122fb23b92a623ccf" +dependencies = [ + "bit-set", + "regex", +] + +[[package]] +name = "fastrand" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" + +[[package]] +name = "filetime" +version = "0.2.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ee447700ac8aa0b2f2bd7bc4462ad686ba06baa6727ac149a2d6277f0d240fd" +dependencies = [ + "cfg-if 1.0.0", + "libc", + "redox_syscall 0.4.1", + "windows-sys 0.52.0", +] + +[[package]] +name = "fixedbitset" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" + +[[package]] +name = "flate2" +version = "1.0.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f54427cfd1c7829e2a139fcefea601bf088ebca651d2bf53ebc600eac295dae" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "fluent" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb74634707bebd0ce645a981148e8fb8c7bccd4c33c652aeffd28bf2f96d555a" +dependencies = [ + "fluent-bundle", + "unic-langid", +] + +[[package]] +name = "fluent-bundle" +version = "0.15.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fe0a21ee80050c678013f82edf4b705fe2f26f1f9877593d13198612503f493" +dependencies = [ + "fluent-langneg", + "fluent-syntax", + "intl-memoizer", + "intl_pluralrules", + "rustc-hash", + "self_cell 0.10.3", + "smallvec", + "unic-langid", +] + +[[package]] +name = "fluent-langneg" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c4ad0989667548f06ccd0e306ed56b61bd4d35458d54df5ec7587c0e8ed5e94" +dependencies = [ + "unic-langid", +] + +[[package]] +name = "fluent-syntax" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a530c4694a6a8d528794ee9bbd8ba0122e779629ac908d15ad5a7ae7763a33d" +dependencies = [ + "thiserror", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "form_urlencoded" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "fsevent-sys" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76ee7a02da4d231650c7cea31349b889be2f45ddb3ef3032d2ec8185f6313fd2" +dependencies = [ + "libc", +] + +[[package]] +name = "fslock" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04412b8935272e3a9bae6f48c7bfff74c2911f60525404edfdd28e49884c3bfb" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "fst" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ab85b9b05e3978cc9a9cf8fea7f01b494e1a09ed3037e16ba39edc7a29eb61a" + +[[package]] +name = "futures" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" + +[[package]] +name = "futures-executor" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" + +[[package]] +name = "futures-macro" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.72", +] + +[[package]] +name = "futures-sink" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" + +[[package]] +name = "futures-task" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" + +[[package]] +name = "futures-util" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "generational-arena" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877e94aff08e743b651baaea359664321055749b398adff8740a7399af7796e7" +dependencies = [ + "cfg-if 1.0.0", +] + +[[package]] +name = "generic-array" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffdf9f34f1447443d37393cc6c2b8313aebddcd96906caf34e54c68d8e57d7bd" +dependencies = [ + "typenum", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +dependencies = [ + "cfg-if 1.0.0", + "libc", + "wasi", +] + +[[package]] +name = "getset" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e45727250e75cc04ff2846a66397da8ef2b3db8e40e0cef4df67950a07621eb9" +dependencies = [ + "proc-macro-error", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "gimli" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" + +[[package]] +name = "glob" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" + +[[package]] +name = "half" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888" +dependencies = [ + "cfg-if 1.0.0", + "crunchy", +] + +[[package]] +name = "handlebars" +version = "5.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d08485b96a0e6393e9e4d1b8d48cf74ad6c063cd905eb33f42c1ce3f0377539b" +dependencies = [ + "log", + "pest", + "pest_derive", + "serde", + "serde_json", + "thiserror", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" + +[[package]] +name = "heck" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + +[[package]] +name = "hermit-abi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest 0.10.7", +] + +[[package]] +name = "home" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "hostname" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9c7c7c8ac16c798734b8a24560c1362120597c40d5e1459f09498f8f6c8f2ba" +dependencies = [ + "cfg-if 1.0.0", + "libc", + "windows", +] + +[[package]] +name = "http" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-auth" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "643c9bbf6a4ea8a656d6b4cd53d34f79e3f841ad5203c1a55fb7d761923bc255" +dependencies = [ + "memchr", +] + +[[package]] +name = "http-body" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" +dependencies = [ + "bytes", + "http", +] + +[[package]] +name = "http-body-util" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" +dependencies = [ + "bytes", + "futures-util", + "http", + "http-body", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fcc0b4a115bf80b728eb8ea024ad5bd707b615bfed49e0665b6e0f86fd082d9" + +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + +[[package]] +name = "hyper" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50dfd22e0e76d0f662d429a5f80fcaf3855009297eab6a0a9f8543834744ba05" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "http", + "http-body", + "httparse", + "itoa", + "pin-project-lite", + "smallvec", + "tokio", + "want", +] + +[[package]] +name = "hyper-rustls" +version = "0.27.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ee4be2c948921a1a5320b629c4193916ed787a7f7f293fd3f7f5a6c9de74155" +dependencies = [ + "futures-util", + "http", + "hyper", + "hyper-util", + "rustls", + "rustls-pki-types", + "tokio", + "tokio-rustls", + "tower-service", + "webpki-roots", +] + +[[package]] +name = "hyper-util" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ab92f4f49ee4fb4f997c784b7a2e0fa70050211e0b6a287f898c3c9785ca956" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "http", + "http-body", + "hyper", + "pin-project-lite", + "socket2", + "tokio", + "tower", + "tower-service", + "tracing", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "icu_collections" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locid" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_locid_transform" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_locid_transform_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_locid_transform_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" + +[[package]] +name = "icu_normalizer" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "utf16_iter", + "utf8_iter", + "write16", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516" + +[[package]] +name = "icu_properties" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_locid_transform", + "icu_properties_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569" + +[[package]] +name = "icu_provider" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_provider_macros", + "stable_deref_trait", + "tinystr", + "writeable", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_provider_macros" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.72", +] + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "idna" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + +[[package]] +name = "im-rc" +version = "15.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af1955a75fa080c677d3972822ec4bad316169ab1cfc6c257a942c2265dbe5fe" +dependencies = [ + "bitmaps", + "rand_core", + "rand_xoshiro", + "sized-chunks", + "typenum", + "version_check", +] + +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown 0.12.3", + "rustc-rayon 0.5.0", +] + +[[package]] +name = "indexmap" +version = "2.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" +dependencies = [ + "equivalent", + "hashbrown 0.14.5", +] + +[[package]] +name = "indoc" +version = "2.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b248f5224d1d606005e02c97f5aa4e88eeb230488bcc03bc9ca4d7991399f2b5" + +[[package]] +name = "inkwell" +version = "0.2.0" +source = "git+https://github.com/TheDan64/inkwell?branch=master#4030f764f1c889f36429ac02ef32e04fcfa8ce33" +dependencies = [ + "either", + "inkwell_internals", + "libc", + "llvm-sys", + "once_cell", + "parking_lot 0.12.3", +] + +[[package]] +name = "inkwell_internals" +version = "0.8.0" +source = "git+https://github.com/TheDan64/inkwell?branch=master#4030f764f1c889f36429ac02ef32e04fcfa8ce33" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.72", +] + +[[package]] +name = "inotify" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8069d3ec154eb856955c1c0fbffefbf5f3c40a104ec912d4797314c1801abff" +dependencies = [ + "bitflags 1.3.2", + "inotify-sys", + "libc", +] + +[[package]] +name = "inotify" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdd168d97690d0b8c412d6b6c10360277f4d7ee495c5d0d5d5fe0854923255cc" +dependencies = [ + "bitflags 1.3.2", + "inotify-sys", + "libc", +] + +[[package]] +name = "inotify-sys" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e05c02b5e89bff3b946cedeca278abc628fe811e604f027c45a8aa3cf793d0eb" +dependencies = [ + "libc", +] + +[[package]] +name = "insta" +version = "1.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "810ae6042d48e2c9e9215043563a58a80b877bc863228a74cf10c49d4620a6f5" +dependencies = [ + "console", + "lazy_static", + "linked-hash-map", + "similar", +] + +[[package]] +name = "instant" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" +dependencies = [ + "cfg-if 1.0.0", +] + +[[package]] +name = "intl-memoizer" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe22e020fce238ae18a6d5d8c502ee76a52a6e880d99477657e6acc30ec57bda" +dependencies = [ + "type-map", + "unic-langid", +] + +[[package]] +name = "intl_pluralrules" +version = "7.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "078ea7b7c29a2b4df841a7f6ac8775ff6074020c6776d48491ce2268e068f972" +dependencies = [ + "unic-langid", +] + +[[package]] +name = "inventory" +version = "0.3.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f958d3d68f4167080a18141e10381e7634563984a537f2a49a30fd8e53ac5767" + +[[package]] +name = "ipnet" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" + +[[package]] +name = "is-terminal" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f23ff5ef2b80d608d61efee834934d862cd92461afc0560dedf493e4c033738b" +dependencies = [ + "hermit-abi", + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" + +[[package]] +name = "jobserver" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0" +dependencies = [ + "libc", +] + +[[package]] +name = "jod-thread" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b23360e99b8717f20aaa4598f5a6541efbe30630039fbc7706cf954a87947ae" + +[[package]] +name = "js-sys" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "json-spanned-value" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb343fa4e3b1b22b344937deedac88da995abf139c2232cbeaa436c38380a210" +dependencies = [ + "serde", + "serde_json", +] + +[[package]] +name = "jsonrpc-core" +version = "18.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14f7f76aef2d054868398427f6c54943cf3d1caa9a7ec7d0c38d69df97a965eb" +dependencies = [ + "futures", + "futures-executor", + "futures-util", + "log", + "serde", + "serde_derive", + "serde_json", +] + +[[package]] +name = "jsonrpc-stdio-server" +version = "18.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6878586767497326eb3d011bd6dbb583e9f008b11528f82fd47798ec46bb6c26" +dependencies = [ + "futures", + "jsonrpc-core", + "log", + "tokio", + "tokio-util 0.6.10", +] + +[[package]] +name = "jwt" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6204285f77fe7d9784db3fdc449ecce1a0114927a51d5a41c4c7a292011c015f" +dependencies = [ + "base64 0.13.1", + "crypto-common", + "digest 0.10.7", + "hmac", + "serde", + "serde_json", + "sha2 0.10.8", +] + +[[package]] +name = "kcl-language-server" +version = "0.11.0" +dependencies = [ + "anyhow", + "chrono", + "clap", + "compiler_base_session", + "crossbeam-channel", + "dashmap", + "env_logger", + "im-rc", + "indexmap 1.9.3", + "insta", + "kclvm-ast", + "kclvm-config", + "kclvm-driver", + "kclvm-error", + "kclvm-parser", + "kclvm-query", + "kclvm-sema", + "kclvm-span", + "kclvm-tools", + "kclvm-utils", + "kclvm-version", + "log", + "lsp-server", + "lsp-types", + "maplit", + "notify 7.0.0", + "parking_lot 0.12.3", + "proc_macro_crate", + "ra_ap_vfs", + "ra_ap_vfs-notify", + "ropey", + "rustc-hash", + "rustc_lexer", + "salsa", + "serde", + "serde_json", + "threadpool", + "tokio", + "tokio-test", +] + +[[package]] +name = "kclvm" +version = "0.11.0" +dependencies = [ + "kclvm-api", + "kclvm-ast", + "kclvm-cmd", + "kclvm-compiler", + "kclvm-config", + "kclvm-driver", + "kclvm-error", + "kclvm-evaluator", + "kclvm-loader", + "kclvm-parser", + "kclvm-query", + "kclvm-runner", + "kclvm-runtime", + "kclvm-sema", + "kclvm-tools", + "kclvm-version", +] + +[[package]] +name = "kclvm-api" +version = "0.11.0" +dependencies = [ + "anyhow", + "criterion", + "futures", + "indexmap 1.9.3", + "jsonrpc-stdio-server", + "kcl-language-server", + "kclvm-ast", + "kclvm-ast-pretty", + "kclvm-config", + "kclvm-driver", + "kclvm-error", + "kclvm-loader", + "kclvm-parser", + "kclvm-query", + "kclvm-runner", + "kclvm-runtime", + "kclvm-sema", + "kclvm-tools", + "kclvm-utils", + "kclvm-version", + "maplit", + "once_cell", + "prost", + "prost-build", + "prost-types", + "prost-wkt", + "prost-wkt-build", + "prost-wkt-types", + "protoc-bin-vendored", + "serde", + "serde_json", + "serde_yaml", + "tempfile", + "tokio", +] + +[[package]] +name = "kclvm-ast" +version = "0.11.0" +dependencies = [ + "anyhow", + "compiler_base_span", + "kclvm-error", + "kclvm-parser", + "kclvm-span", + "kclvm-utils", + "serde", + "serde_json", + "thread_local", + "uuid", +] + +[[package]] +name = "kclvm-ast-pretty" +version = "0.11.0" +dependencies = [ + "compiler_base_macros", + "compiler_base_session", + "fancy-regex", + "indexmap 1.9.3", + "kclvm-ast", + "kclvm-error", + "kclvm-parser", + "pretty_assertions", +] + +[[package]] +name = "kclvm-cmd" +version = "0.11.0" +dependencies = [ + "anyhow", + "clap", + "compiler_base_session", + "kclvm-api", + "kclvm-config", + "kclvm-driver", + "kclvm-error", + "kclvm-parser", + "kclvm-runner", + "kclvm-runtime", + "kclvm-tools", + "kclvm-version", +] + +[[package]] +name = "kclvm-compiler" +version = "0.11.0" +dependencies = [ + "ahash", + "bit-set", + "bitflags 1.3.2", + "fancy-regex", + "indexmap 1.9.3", + "inkwell", + "kclvm-ast", + "kclvm-error", + "kclvm-runtime", + "kclvm-sema", + "once_cell", + "phf", + "time 0.2.27", + "unicode_names2", +] + +[[package]] +name = "kclvm-config" +version = "0.11.0" +dependencies = [ + "ahash", + "anyhow", + "chrono", + "dirs", + "glob", + "indexmap 1.9.3", + "kclvm-ast", + "kclvm-utils", + "kclvm-version", + "md-5 0.8.0", + "pathdiff", + "regex", + "ron", + "serde", + "serde_json", + "serde_yaml", + "toml", + "url", +] + +[[package]] +name = "kclvm-driver" +version = "0.11.0" +dependencies = [ + "anyhow", + "flate2", + "indexmap 2.2.6", + "kclvm-ast", + "kclvm-config", + "kclvm-parser", + "kclvm-runtime", + "kclvm-utils", + "oci-distribution", + "once_cell", + "parking_lot 0.12.3", + "serde", + "serde_json", + "tar", + "tokio", + "walkdir", +] + +[[package]] +name = "kclvm-error" +version = "0.11.0" +dependencies = [ + "annotate-snippets", + "anyhow", + "compiler_base_error", + "compiler_base_macros", + "compiler_base_session", + "compiler_base_span", + "indexmap 1.9.3", + "kclvm-runtime", + "kclvm-span", + "kclvm-utils", + "serde", + "serde_json", + "termize", + "thiserror", + "tracing", +] + +[[package]] +name = "kclvm-evaluator" +version = "0.11.0" +dependencies = [ + "anyhow", + "generational-arena", + "indexmap 1.9.3", + "insta", + "kclvm-ast", + "kclvm-error", + "kclvm-loader", + "kclvm-parser", + "kclvm-runtime", + "kclvm-sema", + "scopeguard", +] + +[[package]] +name = "kclvm-lexer" +version = "0.11.0" +dependencies = [ + "expect-test", + "kclvm-error", + "rustc_lexer", + "unic-emoji-char", +] + +[[package]] +name = "kclvm-loader" +version = "0.11.0" +dependencies = [ + "anyhow", + "indexmap 1.9.3", + "insta", + "kclvm-ast", + "kclvm-ast-pretty", + "kclvm-error", + "kclvm-parser", + "kclvm-query", + "kclvm-sema", + "kclvm-utils", + "maplit", +] + +[[package]] +name = "kclvm-macros" +version = "0.11.0" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", + "synstructure 0.12.6", +] + +[[package]] +name = "kclvm-parser" +version = "0.11.0" +dependencies = [ + "anyhow", + "bstr", + "compiler_base_error", + "compiler_base_macros", + "compiler_base_session", + "compiler_base_span", + "either", + "enquote", + "expect-test", + "glob", + "indexmap 1.9.3", + "insta", + "kclvm-ast", + "kclvm-config", + "kclvm-error", + "kclvm-lexer", + "kclvm-sema", + "kclvm-span", + "kclvm-utils", + "num-bigint", + "parking_lot 0.12.3", + "petgraph", + "regex", + "rustc_lexer", + "serde", + "serde_json", + "tracing", + "unicode_names2", + "walkdir", +] + +[[package]] +name = "kclvm-query" +version = "0.11.0" +dependencies = [ + "anyhow", + "compiler_base_macros", + "compiler_base_session", + "fancy-regex", + "indexmap 1.9.3", + "insta", + "kclvm-ast", + "kclvm-ast-pretty", + "kclvm-error", + "kclvm-parser", + "kclvm-sema", + "kclvm-utils", + "maplit", + "pretty_assertions", + "serde", + "serde_json", +] + +[[package]] +name = "kclvm-runner" +version = "0.11.0" +dependencies = [ + "anyhow", + "cc", + "chrono", + "compiler_base_macros", + "compiler_base_session", + "criterion", + "glob", + "indexmap 1.9.3", + "kclvm-ast", + "kclvm-compiler", + "kclvm-config", + "kclvm-driver", + "kclvm-error", + "kclvm-evaluator", + "kclvm-parser", + "kclvm-query", + "kclvm-runtime", + "kclvm-sema", + "kclvm-utils", + "kclvm-version", + "libc", + "libloading", + "once_cell", + "serde", + "serde_json", + "tempfile", + "threadpool", + "uuid", + "walkdir", +] + +[[package]] +name = "kclvm-runtime" +version = "0.11.0" +dependencies = [ + "ahash", + "anyhow", + "base64 0.13.1", + "blake3", + "bstr", + "chrono", + "dns-lookup", + "encoding", + "fancy-regex", + "generational-arena", + "glob", + "handlebars", + "hostname", + "indexmap 1.9.3", + "itertools", + "kclvm_runtime_internal_macros", + "lazy_static", + "libc", + "md5", + "num-integer", + "phf", + "regex", + "serde", + "serde_json", + "serde_yaml", + "sha1", + "sha2 0.9.9", + "unic-ucd-bidi", + "unic-ucd-category", + "unicode-casing", + "uuid", + "walkdir", +] + +[[package]] +name = "kclvm-sema" +version = "0.11.0" +dependencies = [ + "ahash", + "anyhow", + "bit-set", + "bitflags 1.3.2", + "compiler_base_error", + "compiler_base_macros", + "compiler_base_session", + "compiler_base_span", + "criterion", + "fancy-regex", + "generational-arena", + "indexmap 1.9.3", + "kclvm-ast", + "kclvm-ast-pretty", + "kclvm-error", + "kclvm-parser", + "kclvm-runtime", + "kclvm-span", + "kclvm-utils", + "lazy_static", + "once_cell", + "parking_lot 0.12.3", + "petgraph", + "phf", + "regex", + "serde", + "serde_json", + "suggestions", + "unicode_names2", +] + +[[package]] +name = "kclvm-span" +version = "0.11.0" +dependencies = [ + "compiler_base_span", + "kclvm-macros", + "parking_lot 0.11.2", + "scoped-tls", +] + +[[package]] +name = "kclvm-tools" +version = "0.11.0" +dependencies = [ + "anyhow", + "compiler_base_session", + "compiler_base_span", + "criterion", + "fancy-regex", + "indexmap 1.9.3", + "insta", + "json-spanned-value", + "kclvm-ast", + "kclvm-ast-pretty", + "kclvm-config", + "kclvm-driver", + "kclvm-error", + "kclvm-parser", + "kclvm-query", + "kclvm-runner", + "kclvm-runtime", + "kclvm-sema", + "kclvm-utils", + "located_yaml", + "once_cell", + "pretty_assertions", + "regex", + "rustc_lexer", + "serde_json", + "serde_yaml", + "walkdir", +] + +[[package]] +name = "kclvm-utils" +version = "0.11.0" +dependencies = [ + "anyhow", + "fslock", + "regex", +] + +[[package]] +name = "kclvm-version" +version = "0.11.0" +dependencies = [ + "vergen-gitcl", +] + +[[package]] +name = "kclvm_runtime_internal_macros" +version = "0.5.0" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "kqueue" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7447f1ca1b7b563588a205fe93dea8df60fd981423a768bc1c0ded35ed147d0c" +dependencies = [ + "kqueue-sys", + "libc", +] + +[[package]] +name = "kqueue-sys" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed9625ffda8729b85e45cf04090035ac368927b8cebc34898e7c120f52e4838b" +dependencies = [ + "bitflags 1.3.2", + "libc", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "libc" +version = "0.2.155" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" + +[[package]] +name = "libloading" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" +dependencies = [ + "cfg-if 1.0.0", + "winapi", +] + +[[package]] +name = "libredox" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" +dependencies = [ + "bitflags 2.6.0", + "libc", +] + +[[package]] +name = "linked-hash-map" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" +dependencies = [ + "serde", +] + +[[package]] +name = "linux-raw-sys" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" + +[[package]] +name = "litemap" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ee93343901ab17bd981295f2cf0026d4ad018c7c31ba84549a4ddbb47a45104" + +[[package]] +name = "llvm-sys" +version = "120.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "624f2692f436769c7eb85a13eeca3f6fb9705a4b2bd0473ac9577c90f19e21ef" +dependencies = [ + "cc", + "lazy_static", + "libc", + "regex", + "semver 0.11.0", +] + +[[package]] +name = "located_yaml" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bc68ee6f87a1be7fdba1dcfd854528371aa84a8390279b5d7a99d5da82add76" +dependencies = [ + "linked-hash-map", + "serde", + "yaml-rust", +] + +[[package]] +name = "lock_api" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" + +[[package]] +name = "lsp-server" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "550446e84739dcaf6d48a4a093973850669e13e8a34d8f8d64851041be267cd9" +dependencies = [ + "crossbeam-channel", + "log", + "serde", + "serde_json", +] + +[[package]] +name = "lsp-types" +version = "0.93.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9be6e9c7e2d18f651974370d7aff703f9513e0df6e464fd795660edc77e6ca51" +dependencies = [ + "bitflags 1.3.2", + "serde", + "serde_json", + "serde_repr", + "url", +] + +[[package]] +name = "maplit" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d" + +[[package]] +name = "matches" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5" + +[[package]] +name = "md-5" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a18af3dcaf2b0219366cdb4e2af65a6101457b415c3d1a5c71dd9c2b7c77b9c8" +dependencies = [ + "block-buffer 0.7.3", + "digest 0.8.1", + "opaque-debug 0.2.3", +] + +[[package]] +name = "md-5" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" +dependencies = [ + "cfg-if 1.0.0", + "digest 0.10.7", +] + +[[package]] +name = "md5" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "490cc448043f947bae3cbee9c203358d62dbee0db12107a74be5c30ccfd09771" + +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "memmap2" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "723e3ebdcdc5c023db1df315364573789f8857c11b631a2fdfad7c00f5c046b4" +dependencies = [ + "libc", +] + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "miniz_oxide" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" +dependencies = [ + "adler", +] + +[[package]] +name = "mio" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" +dependencies = [ + "libc", + "log", + "wasi", + "windows-sys 0.48.0", +] + +[[package]] +name = "mio" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4569e456d394deccd22ce1c1913e6ea0e54519f577285001215d33557431afe4" +dependencies = [ + "hermit-abi", + "libc", + "log", + "wasi", + "windows-sys 0.52.0", +] + +[[package]] +name = "miow" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52ffbca2f655e33c08be35d87278e5b18b89550a37dbd598c20db92f6a471123" +dependencies = [ + "windows-sys 0.42.0", +] + +[[package]] +name = "multimap" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a" + +[[package]] +name = "notify" +version = "5.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "729f63e1ca555a43fe3efa4f3efdf4801c479da85b432242a7b726f353c88486" +dependencies = [ + "bitflags 1.3.2", + "crossbeam-channel", + "filetime", + "fsevent-sys", + "inotify 0.9.6", + "kqueue", + "libc", + "mio 0.8.11", + "walkdir", + "windows-sys 0.45.0", +] + +[[package]] +name = "notify" +version = "7.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c533b4c39709f9ba5005d8002048266593c1cfaf3c5f0739d5b8ab0c6c504009" +dependencies = [ + "bitflags 2.6.0", + "filetime", + "fsevent-sys", + "inotify 0.10.2", + "kqueue", + "libc", + "log", + "mio 1.0.1", + "notify-types", + "walkdir", + "windows-sys 0.52.0", +] + +[[package]] +name = "notify-types" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7393c226621f817964ffb3dc5704f9509e107a8b024b489cc2c1b217378785df" +dependencies = [ + "instant", +] + +[[package]] +name = "num-bigint" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_cpus" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "num_threads" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c7398b9c8b70908f6371f47ed36737907c87c52af34c268fed0bf0ceb92ead9" +dependencies = [ + "libc", +] + +[[package]] +name = "object" +version = "0.36.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f203fa8daa7bb185f760ae12bd8e097f63d17041dcdcaf675ac54cdf863170e" +dependencies = [ + "memchr", +] + +[[package]] +name = "oci-distribution" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b95a2c51531af0cb93761f66094044ca6ea879320bccd35ab747ff3fcab3f422" +dependencies = [ + "bytes", + "chrono", + "futures-util", + "http", + "http-auth", + "jwt", + "lazy_static", + "olpc-cjson", + "regex", + "reqwest", + "serde", + "serde_json", + "sha2 0.10.8", + "thiserror", + "tokio", + "tracing", + "unicase", +] + +[[package]] +name = "olpc-cjson" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d637c9c15b639ccff597da8f4fa968300651ad2f1e968aefc3b4927a6fb2027a" +dependencies = [ + "serde", + "serde_json", + "unicode-normalization", +] + +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "oorandom" +version = "11.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b410bbe7e14ab526a0e86877eb47c6996a2bd7746f027ba551028c925390e4e9" + +[[package]] +name = "opaque-debug" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" + +[[package]] +name = "opaque-debug" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" + +[[package]] +name = "option-ext" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" + +[[package]] +name = "parking_lot" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" +dependencies = [ + "instant", + "lock_api", + "parking_lot_core 0.8.6", +] + +[[package]] +name = "parking_lot" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" +dependencies = [ + "lock_api", + "parking_lot_core 0.9.10", +] + +[[package]] +name = "parking_lot_core" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc" +dependencies = [ + "cfg-if 1.0.0", + "instant", + "libc", + "redox_syscall 0.2.16", + "smallvec", + "winapi", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +dependencies = [ + "cfg-if 1.0.0", + "libc", + "redox_syscall 0.5.3", + "smallvec", + "windows-targets 0.52.6", +] + +[[package]] +name = "pathdiff" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd" + +[[package]] +name = "percent-encoding" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" + +[[package]] +name = "pest" +version = "2.7.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd53dff83f26735fdc1ca837098ccf133605d794cdae66acfc2bfac3ec809d95" +dependencies = [ + "memchr", + "thiserror", + "ucd-trie", +] + +[[package]] +name = "pest_derive" +version = "2.7.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a548d2beca6773b1c244554d36fcf8548a8a58e74156968211567250e48e49a" +dependencies = [ + "pest", + "pest_generator", +] + +[[package]] +name = "pest_generator" +version = "2.7.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c93a82e8d145725dcbaf44e5ea887c8a869efdcc28706df2d08c69e17077183" +dependencies = [ + "pest", + "pest_meta", + "proc-macro2", + "quote", + "syn 2.0.72", +] + +[[package]] +name = "pest_meta" +version = "2.7.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a941429fea7e08bedec25e4f6785b6ffaacc6b755da98df5ef3e7dcf4a124c4f" +dependencies = [ + "once_cell", + "pest", + "sha2 0.10.8", +] + +[[package]] +name = "petgraph" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" +dependencies = [ + "fixedbitset", + "indexmap 2.2.6", +] + +[[package]] +name = "phf" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2ac8b67553a7ca9457ce0e526948cad581819238f4a9d1ea74545851fa24f37" +dependencies = [ + "phf_macros", + "phf_shared", + "proc-macro-hack", +] + +[[package]] +name = "phf_generator" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d43f3220d96e0080cc9ea234978ccd80d904eafb17be31bb0f76daaea6493082" +dependencies = [ + "phf_shared", + "rand", +] + +[[package]] +name = "phf_macros" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b706f5936eb50ed880ae3009395b43ed19db5bff2ebd459c95e7bf013a89ab86" +dependencies = [ + "phf_generator", + "phf_shared", + "proc-macro-hack", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "phf_shared" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a68318426de33640f02be62b4ae8eb1261be2efbc337b60c54d845bf4484e0d9" +dependencies = [ + "siphasher", +] + +[[package]] +name = "pin-project" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.72", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "plotters" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a15b6eccb8484002195a3e44fe65a4ce8e93a625797a063735536fd59cb01cf3" +dependencies = [ + "num-traits", + "plotters-backend", + "plotters-svg", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "plotters-backend" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "414cec62c6634ae900ea1c56128dfe87cf63e7caece0852ec76aba307cebadb7" + +[[package]] +name = "plotters-svg" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81b30686a7d9c3e010b84284bdd26a29f2138574f52f5eb6f794fc0ad924e705" +dependencies = [ + "plotters-backend", +] + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "pretty_assertions" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af7cee1a6c8a5b9208b3cb1061f10c0cb689087b3d8ce85fb9d2dd7a29b6ba66" +dependencies = [ + "diff", + "yansi", +] + +[[package]] +name = "prettyplease" +version = "0.1.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c8646e95016a7a6c4adea95bafa8a16baab64b583356217f2c85db4a39d9a86" +dependencies = [ + "proc-macro2", + "syn 1.0.109", +] + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn 1.0.109", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro-hack" +version = "0.5.20+deprecated" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" + +[[package]] +name = "proc-macro2" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "proc_macro_crate" +version = "0.1.0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.72", +] + +[[package]] +name = "prost" +version = "0.11.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b82eaa1d779e9a4bc1c3217db8ffbeabaae1dca241bf70183242128d48681cd" +dependencies = [ + "bytes", + "prost-derive", +] + +[[package]] +name = "prost-build" +version = "0.11.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "119533552c9a7ffacc21e099c24a0ac8bb19c2a2a3f363de84cd9b844feab270" +dependencies = [ + "bytes", + "heck 0.4.1", + "itertools", + "lazy_static", + "log", + "multimap", + "petgraph", + "prettyplease", + "prost", + "prost-types", + "regex", + "syn 1.0.109", + "tempfile", + "which", +] + +[[package]] +name = "prost-derive" +version = "0.11.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5d2d8d10f3c6ded6da8b05b5fb3b8a5082514344d56c9f871412d29b4e075b4" +dependencies = [ + "anyhow", + "itertools", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "prost-types" +version = "0.11.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "213622a1460818959ac1181aaeb2dc9c7f63df720db7d788b3e24eacd1983e13" +dependencies = [ + "prost", +] + +[[package]] +name = "prost-wkt" +version = "0.4.1" +dependencies = [ + "chrono", + "inventory", + "prost", + "serde", + "serde_derive", + "serde_json", + "typetag", +] + +[[package]] +name = "prost-wkt-build" +version = "0.4.1" +dependencies = [ + "heck 0.4.1", + "prost", + "prost-build", + "prost-types", + "quote", +] + +[[package]] +name = "prost-wkt-types" +version = "0.4.1" +dependencies = [ + "chrono", + "prost", + "prost-build", + "prost-types", + "prost-wkt", + "prost-wkt-build", + "protoc-bin-vendored", + "regex", + "serde", + "serde_derive", + "serde_json", +] + +[[package]] +name = "protoc-bin-vendored" +version = "3.2.0" +source = "git+https://github.com/kcl-lang/rust-protoc-bin-vendored#53c1f87ffc3027642ea6b822025b1dc699a3135b" +dependencies = [ + "protoc-bin-vendored-linux-aarch_64", + "protoc-bin-vendored-linux-ppcle_64", + "protoc-bin-vendored-linux-x86_32", + "protoc-bin-vendored-linux-x86_64", + "protoc-bin-vendored-macos-aarch_64", + "protoc-bin-vendored-macos-x86_64", + "protoc-bin-vendored-win32", +] + +[[package]] +name = "protoc-bin-vendored-linux-aarch_64" +version = "3.2.0" +source = "git+https://github.com/kcl-lang/rust-protoc-bin-vendored#53c1f87ffc3027642ea6b822025b1dc699a3135b" + +[[package]] +name = "protoc-bin-vendored-linux-ppcle_64" +version = "3.2.0" +source = "git+https://github.com/kcl-lang/rust-protoc-bin-vendored#53c1f87ffc3027642ea6b822025b1dc699a3135b" + +[[package]] +name = "protoc-bin-vendored-linux-x86_32" +version = "3.2.0" +source = "git+https://github.com/kcl-lang/rust-protoc-bin-vendored#53c1f87ffc3027642ea6b822025b1dc699a3135b" + +[[package]] +name = "protoc-bin-vendored-linux-x86_64" +version = "3.2.0" +source = "git+https://github.com/kcl-lang/rust-protoc-bin-vendored#53c1f87ffc3027642ea6b822025b1dc699a3135b" + +[[package]] +name = "protoc-bin-vendored-macos-aarch_64" +version = "3.2.0" +source = "git+https://github.com/kcl-lang/rust-protoc-bin-vendored#53c1f87ffc3027642ea6b822025b1dc699a3135b" + +[[package]] +name = "protoc-bin-vendored-macos-x86_64" +version = "3.2.0" +source = "git+https://github.com/kcl-lang/rust-protoc-bin-vendored#53c1f87ffc3027642ea6b822025b1dc699a3135b" + +[[package]] +name = "protoc-bin-vendored-win32" +version = "3.2.0" +source = "git+https://github.com/kcl-lang/rust-protoc-bin-vendored#53c1f87ffc3027642ea6b822025b1dc699a3135b" + +[[package]] +name = "quinn" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4ceeeeabace7857413798eb1ffa1e9c905a9946a57d81fb69b4b71c4d8eb3ad" +dependencies = [ + "bytes", + "pin-project-lite", + "quinn-proto", + "quinn-udp", + "rustc-hash", + "rustls", + "thiserror", + "tokio", + "tracing", +] + +[[package]] +name = "quinn-proto" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddf517c03a109db8100448a4be38d498df8a210a99fe0e1b9eaf39e78c640efe" +dependencies = [ + "bytes", + "rand", + "ring", + "rustc-hash", + "rustls", + "slab", + "thiserror", + "tinyvec", + "tracing", +] + +[[package]] +name = "quinn-udp" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8bffec3605b73c6f1754535084a85229fa8a30f86014e6c81aeec4abb68b0285" +dependencies = [ + "libc", + "once_cell", + "socket2", + "windows-sys 0.52.0", +] + +[[package]] +name = "quote" +version = "1.0.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "ra_ap_paths" +version = "0.0.149" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d780b450680460bd7ea3e2483dcf15a3ac0ce0ec028696caa342c577d65e5506" + +[[package]] +name = "ra_ap_stdx" +version = "0.0.149" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d776542bf771f4fdf40c21ced864bf213924d8a60d580c970715818471ebd74c" +dependencies = [ + "always-assert", + "libc", + "miow", + "winapi", +] + +[[package]] +name = "ra_ap_vfs" +version = "0.0.149" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8cd60adecd0947e1dd41a3077713381aa0cdcba6dc8777300d7d5b83b9fbe84" +dependencies = [ + "fst", + "indexmap 1.9.3", + "ra_ap_paths", + "ra_ap_stdx", + "rustc-hash", +] + +[[package]] +name = "ra_ap_vfs-notify" +version = "0.0.149" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a680f2dbd796844ebeaa2a4d01ae209f412ddc2981f6512ab8bc9b471156e6cd" +dependencies = [ + "crossbeam-channel", + "jod-thread", + "notify 5.2.0", + "ra_ap_paths", + "ra_ap_vfs", + "tracing", + "walkdir", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rand_xoshiro" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f97cdb2a36ed4183de61b2f824cc45c9f1037f28afe0a322e9fff4c108b5aaa" +dependencies = [ + "rand_core", +] + +[[package]] +name = "rayon" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + +[[package]] +name = "redox_syscall" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" +dependencies = [ + "bitflags 1.3.2", +] + +[[package]] +name = "redox_syscall" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +dependencies = [ + "bitflags 1.3.2", +] + +[[package]] +name = "redox_syscall" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4" +dependencies = [ + "bitflags 2.6.0", +] + +[[package]] +name = "redox_users" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd283d9651eeda4b2a83a43c1c91b266c40fd76ecd39a50a8c630ae69dc72891" +dependencies = [ + "getrandom", + "libredox", + "thiserror", +] + +[[package]] +name = "regex" +version = "1.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b91213439dad192326a0d7c6ee3955910425f441d7038e0d6933b0aec5c4517f" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata 0.4.7", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" + +[[package]] +name = "regex-automata" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" + +[[package]] +name = "reqwest" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7d6d2a27d57148378eb5e111173f4276ad26340ecc5c49a4a2152167a2d6a37" +dependencies = [ + "base64 0.22.1", + "bytes", + "futures-core", + "futures-util", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-rustls", + "hyper-util", + "ipnet", + "js-sys", + "log", + "mime", + "once_cell", + "percent-encoding", + "pin-project-lite", + "quinn", + "rustls", + "rustls-pemfile", + "rustls-pki-types", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper", + "tokio", + "tokio-rustls", + "tokio-util 0.7.11", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "wasm-streams", + "web-sys", + "webpki-roots", + "winreg", +] + +[[package]] +name = "ring" +version = "0.17.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" +dependencies = [ + "cc", + "cfg-if 1.0.0", + "getrandom", + "libc", + "spin", + "untrusted", + "windows-sys 0.52.0", +] + +[[package]] +name = "ron" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88073939a61e5b7680558e6be56b419e208420c2adb92be54921fa6b72283f1a" +dependencies = [ + "base64 0.13.1", + "bitflags 1.3.2", + "serde", +] + +[[package]] +name = "ropey" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93411e420bcd1a75ddd1dc3caf18c23155eda2c090631a85af21ba19e97093b5" +dependencies = [ + "smallvec", + "str_indices", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "rustc-rayon" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9974ab223660e61c1b4e7b43b827379df286736ca988308ce7e16f59f2d89246" +dependencies = [ + "crossbeam-deque", + "either", + "rustc-rayon-core 0.3.2", +] + +[[package]] +name = "rustc-rayon" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb81aadc8837ca6ecebe0fe1353f15df83b3b3cc2cf7a8afd571bc22aa121710" +dependencies = [ + "either", + "rustc-rayon-core 0.5.0", +] + +[[package]] +name = "rustc-rayon-core" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "564bfd27be8db888d0fa76aa4335e7851aaed0c2c11ad1e93aeb9349f6b88500" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", + "lazy_static", + "num_cpus", +] + +[[package]] +name = "rustc-rayon-core" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67668daaf00e359c126f6dcb40d652d89b458a008c8afa727a42a2d20fca0b7f" +dependencies = [ + "crossbeam-channel", + "crossbeam-deque", + "crossbeam-utils", + "num_cpus", +] + +[[package]] +name = "rustc_data_structures" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a38bae9c6afa27015bcaa2869e03bb111ecf0d0e0edc2da559a91d4057174c9a" +dependencies = [ + "arrayvec", + "bitflags 1.3.2", + "cfg-if 0.1.10", + "ena", + "indexmap 1.9.3", + "jobserver", + "libc", + "memmap2", + "parking_lot 0.12.3", + "rustc-hash", + "rustc-rayon 0.3.2", + "rustc-rayon-core 0.3.2", + "stable_deref_trait", + "tempfile", + "tracing", + "winapi", +] + +[[package]] +name = "rustc_errors" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00299b1841816d2c41129e6d4f86b0b446ee387e8203871c2551e1c405b1243c" +dependencies = [ + "termcolor", + "winapi", +] + +[[package]] +name = "rustc_lexer" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c86aae0c77166108c01305ee1a36a1e77289d7dc6ca0a3cd91ff4992de2d16a5" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "rustc_span" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "043e9cc06c53de1f6a125e41e4b915d23a130241610a114ad4fe4f654617eae4" +dependencies = [ + "cfg-if 0.1.10", + "md-5 0.10.6", + "rustc_data_structures", + "scoped-tls", + "sha-1", + "sha2 0.10.8", + "tracing", + "unicode-width", +] + +[[package]] +name = "rustc_version" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" +dependencies = [ + "semver 0.9.0", +] + +[[package]] +name = "rustc_version" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +dependencies = [ + "semver 1.0.23", +] + +[[package]] +name = "rustix" +version = "0.38.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" +dependencies = [ + "bitflags 2.6.0", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.52.0", +] + +[[package]] +name = "rustls" +version = "0.23.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c58f8c84392efc0a126acce10fa59ff7b3d2ac06ab451a33f2741989b806b044" +dependencies = [ + "once_cell", + "ring", + "rustls-pki-types", + "rustls-webpki", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-pemfile" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29993a25686778eb88d4189742cd713c9bce943bc54251a33509dc63cbacf73d" +dependencies = [ + "base64 0.22.1", + "rustls-pki-types", +] + +[[package]] +name = "rustls-pki-types" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "976295e77ce332211c0d24d92c0e83e50f5c5f046d11082cea19f3df13a3562d" + +[[package]] +name = "rustls-webpki" +version = "0.102.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e6b52d4fda176fd835fdc55a835d4a89b8499cad995885a21149d5ad62f852e" +dependencies = [ + "ring", + "rustls-pki-types", + "untrusted", +] + +[[package]] +name = "rustversion" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" + +[[package]] +name = "ryu" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" + +[[package]] +name = "salsa" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b84d9f96071f3f3be0dc818eae3327625d8ebc95b58da37d6850724f31d3403" +dependencies = [ + "crossbeam-utils", + "indexmap 1.9.3", + "lock_api", + "log", + "oorandom", + "parking_lot 0.11.2", + "rustc-hash", + "salsa-macros", + "smallvec", +] + +[[package]] +name = "salsa-macros" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd3904a4ba0a9d0211816177fd34b04c7095443f8cdacd11175064fe541c8fe2" +dependencies = [ + "heck 0.3.3", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "scoped-tls" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "self_cell" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e14e4d63b804dc0c7ec4a1e52bcb63f02c7ac94476755aa579edac21e01f915d" +dependencies = [ + "self_cell 1.0.4", +] + +[[package]] +name = "self_cell" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d369a96f978623eb3dc28807c4852d6cc617fed53da5d3c400feff1ef34a714a" + +[[package]] +name = "semver" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" +dependencies = [ + "semver-parser 0.7.0", +] + +[[package]] +name = "semver" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6" +dependencies = [ + "semver-parser 0.10.2", +] + +[[package]] +name = "semver" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" + +[[package]] +name = "semver-parser" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" + +[[package]] +name = "semver-parser" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0bef5b7f9e0df16536d3961cfb6e84331c065b4066afb39768d0e319411f7" +dependencies = [ + "pest", +] + +[[package]] +name = "serde" +version = "1.0.204" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.204" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.72", +] + +[[package]] +name = "serde_json" +version = "1.0.115" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12dc5c46daa8e9fdf4f5e71b6cf9a53f2487da0e86e55808e2d35539666497dd" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_repr" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.72", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_yaml" +version = "0.9.34+deprecated" +dependencies = [ + "anyhow", + "indexmap 2.2.6", + "indoc", + "itoa", + "ryu", + "serde", + "serde_derive", + "unsafe-libyaml", +] + +[[package]] +name = "sha-1" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5058ada175748e33390e40e872bd0fe59a19f265d0158daa551c5a88a76009c" +dependencies = [ + "cfg-if 1.0.0", + "cpufeatures", + "digest 0.10.7", +] + +[[package]] +name = "sha1" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1da05c97445caa12d05e848c4a4fcbbea29e748ac28f7e80e9b010392063770" +dependencies = [ + "sha1_smol", +] + +[[package]] +name = "sha1_smol" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbfa15b3dddfee50a0fff136974b3e1bde555604ba463834a7eb7deb6417705d" + +[[package]] +name = "sha2" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" +dependencies = [ + "block-buffer 0.9.0", + "cfg-if 1.0.0", + "cpufeatures", + "digest 0.9.0", + "opaque-debug 0.3.1", +] + +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if 1.0.0", + "cpufeatures", + "digest 0.10.7", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "signal-hook-registry" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" +dependencies = [ + "libc", +] + +[[package]] +name = "similar" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1de1d4f81173b03af4c0cbed3c898f6bff5b870e4a7f5d6f4057d62a7a4b686e" + +[[package]] +name = "siphasher" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" + +[[package]] +name = "sized-chunks" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16d69225bde7a69b235da73377861095455d298f2b970996eec25ddbb42b3d1e" +dependencies = [ + "bitmaps", + "typenum", +] + +[[package]] +name = "slab" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] + +[[package]] +name = "smallvec" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" + +[[package]] +name = "socket2" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" + +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + +[[package]] +name = "standback" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e113fb6f3de07a243d434a56ec6f186dfd51cb08448239fe7bcae73f87ff28ff" +dependencies = [ + "version_check", +] + +[[package]] +name = "stdweb" +version = "0.4.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d022496b16281348b52d0e30ae99e01a73d737b2f45d38fed4edf79f9325a1d5" +dependencies = [ + "discard", + "rustc_version 0.2.3", + "stdweb-derive", + "stdweb-internal-macros", + "stdweb-internal-runtime", + "wasm-bindgen", +] + +[[package]] +name = "stdweb-derive" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c87a60a40fccc84bef0652345bbbbbe20a605bf5d0ce81719fc476f5c03b50ef" +dependencies = [ + "proc-macro2", + "quote", + "serde", + "serde_derive", + "syn 1.0.109", +] + +[[package]] +name = "stdweb-internal-macros" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58fa5ff6ad0d98d1ffa8cb115892b6e69d67799f6763e162a1c9db421dc22e11" +dependencies = [ + "base-x", + "proc-macro2", + "quote", + "serde", + "serde_derive", + "serde_json", + "sha1", + "syn 1.0.109", +] + +[[package]] +name = "stdweb-internal-runtime" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "213701ba3370744dcd1a12960caa4843b3d68b4d1c0a5d575e0d65b2ee9d16c0" + +[[package]] +name = "str_indices" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9557cb6521e8d009c51a8666f09356f4b817ba9ba0981a305bd86aee47bd35c" + +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] +name = "suggestions" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5441c382482e49aaac2c3ea9cbcd24290531246e879ee94af5dfc4b144f11e80" +dependencies = [ + "strsim 0.10.0", +] + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.72" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc4b9b9bf2add8093d3f2c0204471e951b2285580335de42f9d2534f3ae7a8af" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "sync_wrapper" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394" + +[[package]] +name = "synstructure" +version = "0.12.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", + "unicode-xid", +] + +[[package]] +name = "synstructure" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.72", ] [[package]] -name = "kclvm-error" -version = "0.1.0" +name = "tar" +version = "0.4.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb797dad5fb5b76fcf519e702f4a589483b5ef06567f160c392832c1f5e44909" dependencies = [ - "annotate-snippets", - "atty", - "indexmap", - "kclvm-runtime", - "kclvm-span", - "rustc_span", - "termcolor", - "termize", - "tracing", + "filetime", + "libc", + "xattr", ] [[package]] -name = "kclvm-lexer" -version = "0.1.0" +name = "tempfile" +version = "3.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" dependencies = [ - "kclvm-error", - "rustc_lexer", - "unic-emoji-char", + "cfg-if 1.0.0", + "fastrand", + "rustix", + "windows-sys 0.52.0", ] [[package]] -name = "kclvm-macros" -version = "0.1.0" +name = "termcolor" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" dependencies = [ - "proc-macro2", - "quote", - "syn", - "synstructure", + "winapi-util", ] [[package]] -name = "kclvm-parser" -version = "0.1.0" +name = "termize" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1706be6b564323ce7092f5f7e6b118a14c8ef7ed0e69c8c5329c914a9f101295" dependencies = [ - "bstr", - "either", - "enquote", - "kclvm-ast", - "kclvm-config", - "kclvm-error", - "kclvm-lexer", - "kclvm-runtime", - "kclvm-sema", - "kclvm-span", - "num-bigint", - "rustc_data_structures", - "rustc_lexer", - "rustc_span", - "serde", - "serde_json", - "tracing", - "unicode_names2", + "libc", + "winapi", ] [[package]] -name = "kclvm-runner" -version = "0.1.0" +name = "thiserror" +version = "1.0.63" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" dependencies = [ - "clap", - "fslock", - "glob", - "indexmap", - "kclvm-ast", - "kclvm-compiler", - "kclvm-config", - "kclvm-parser", - "kclvm-runtime", - "kclvm-sema", - "kclvm-version", - "libc", - "libloading", - "serde", - "serde_json", - "walkdir", + "thiserror-impl", ] [[package]] -name = "kclvm-runtime" -version = "0.1.0" +name = "thiserror-impl" +version = "1.0.63" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" dependencies = [ - "ahash", - "base64", - "bstr", - "chrono", - "fancy-regex", - "indexmap", - "itertools", - "json_minimal", - "kclvm_runtime_internal_macros", - "libc", - "md5", - "num-integer", - "phf", - "regex", - "serde", - "serde_json", - "serde_yaml", - "sha1", - "sha2 0.9.8", - "unic-ucd-bidi", - "unic-ucd-category", - "unicode-casing", + "proc-macro2", + "quote", + "syn 2.0.72", ] [[package]] -name = "kclvm-sema" -version = "0.1.0" +name = "thread_local" +version = "1.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" dependencies = [ - "ahash", - "bit-set", - "bitflags", - "fancy-regex", - "indexmap", - "kclvm-ast", - "kclvm-error", - "kclvm-runtime", - "kclvm-span", + "cfg-if 1.0.0", "once_cell", - "petgraph", - "phf", - "unicode_names2", ] [[package]] -name = "kclvm-span" -version = "0.1.0" +name = "threadpool" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d050e60b33d41c19108b32cea32164033a9013fe3b46cbd4457559bfbf77afaa" dependencies = [ - "kclvm-macros", - "rustc_span", - "scoped-tls", + "num_cpus", ] [[package]] -name = "kclvm-tools" -version = "0.1.0" +name = "time" +version = "0.2.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4752a97f8eebd6854ff91f1c1824cd6160626ac4bd44287f7f4ea2035a02a242" dependencies = [ - "fancy-regex", - "indexmap", - "kclvm-ast", - "kclvm-error", - "kclvm-parser", + "const_fn", + "libc", + "standback", + "stdweb", + "time-macros 0.1.1", + "version_check", + "winapi", ] [[package]] -name = "kclvm-version" -version = "0.1.0" - -[[package]] -name = "kclvm_runtime_internal_macros" -version = "0.1.0" +name = "time" +version = "0.3.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" dependencies = [ - "proc-macro2", - "quote", - "syn", + "deranged", + "itoa", + "libc", + "num-conv", + "num_threads", + "powerfmt", + "serde", + "time-core", + "time-macros 0.2.18", ] [[package]] -name = "lazy_static" -version = "1.4.0" +name = "time-core" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" [[package]] -name = "libc" -version = "0.2.112" +name = "time-macros" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b03d17f364a3a042d5e5d46b053bbbf82c92c9430c592dd4c064dc6ee997125" +checksum = "957e9c6e26f12cb6d0dd7fc776bb67a706312e7299aed74c8dd5b17ebb27e2f1" +dependencies = [ + "proc-macro-hack", + "time-macros-impl", +] [[package]] -name = "libloading" -version = "0.7.3" +name = "time-macros" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efbc0f03f9a775e9f6aed295c6a1ba2253c5757a9e03d55c6caa46a681abcddd" +checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" dependencies = [ - "cfg-if 1.0.0", - "winapi", + "num-conv", + "time-core", ] [[package]] -name = "linked-hash-map" -version = "0.5.4" +name = "time-macros-impl" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fb9b38af92608140b86b693604b9ffcc5824240a484d1ecd4795bacb2fe88f3" +checksum = "fd3c141a1b43194f3f56a1411225df8646c55781d5f26db825b3d98507eb482f" +dependencies = [ + "proc-macro-hack", + "proc-macro2", + "quote", + "standback", + "syn 1.0.109", +] [[package]] -name = "llvm-sys" -version = "120.2.4" +name = "tinystr" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09b716322964966a62377cf86e64f00ca7043505fdf27bd2ec7d41ae6682d1e7" +checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" dependencies = [ - "cc", - "lazy_static", - "libc", - "regex", - "semver", + "displaydoc", + "zerovec", ] [[package]] -name = "lock_api" -version = "0.4.7" +name = "tinytemplate" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "327fa5b6a6940e4699ec49a9beae1ea4845c6bab9314e4f84ac68742139d8c53" +checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc" dependencies = [ - "autocfg", - "scopeguard", + "serde", + "serde_json", ] [[package]] -name = "log" -version = "0.4.16" +name = "tinyvec" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6389c490849ff5bc16be905ae24bc913a9c8892e19b2341dbc175e14c341c2b8" +checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938" dependencies = [ - "cfg-if 1.0.0", + "tinyvec_macros", ] [[package]] -name = "matches" -version = "0.1.9" +name = "tinyvec_macros" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] -name = "md-5" -version = "0.10.1" +name = "tokio" +version = "1.39.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "658646b21e0b72f7866c7038ab086d3d5e1cd6271f060fd37defb241949d0582" +checksum = "daa4fb1bc778bd6f04cbfc4bb2d06a7396a8f299dc33ea1900cedaa316f467b1" dependencies = [ - "digest 0.10.3", + "backtrace", + "bytes", + "libc", + "mio 1.0.1", + "parking_lot 0.12.3", + "pin-project-lite", + "signal-hook-registry", + "socket2", + "tokio-macros", + "windows-sys 0.52.0", ] [[package]] -name = "md5" -version = "0.7.0" +name = "tokio-macros" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "490cc448043f947bae3cbee9c203358d62dbee0db12107a74be5c30ccfd09771" +checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.72", +] [[package]] -name = "memchr" -version = "2.4.1" +name = "tokio-rustls" +version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" +checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4" +dependencies = [ + "rustls", + "rustls-pki-types", + "tokio", +] [[package]] -name = "memmap2" -version = "0.2.3" +name = "tokio-stream" +version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "723e3ebdcdc5c023db1df315364573789f8857c11b631a2fdfad7c00f5c046b4" +checksum = "267ac89e0bec6e691e5813911606935d77c476ff49024f98abcea3e7b15e37af" dependencies = [ - "libc", + "futures-core", + "pin-project-lite", + "tokio", ] [[package]] -name = "memoffset" -version = "0.6.5" +name = "tokio-test" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" +checksum = "2468baabc3311435b55dd935f702f42cd1b8abb7e754fb7dfb16bd36aa88f9f7" dependencies = [ - "autocfg", + "async-stream", + "bytes", + "futures-core", + "tokio", + "tokio-stream", ] [[package]] -name = "num-bigint" -version = "0.4.3" +name = "tokio-util" +version = "0.6.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f" +checksum = "36943ee01a6d67977dd3f84a5a1d2efeb4ada3a1ae771cadfaa535d9d9fc6507" dependencies = [ - "autocfg", - "num-integer", - "num-traits", + "bytes", + "futures-core", + "futures-sink", + "log", + "pin-project-lite", + "tokio", ] [[package]] -name = "num-integer" -version = "0.1.44" +name = "tokio-util" +version = "0.7.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" +checksum = "9cf6b47b3771c49ac75ad09a6162f53ad4b8088b76ac60e8ec1455b31a189fe1" dependencies = [ - "autocfg", - "num-traits", + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", ] [[package]] -name = "num-traits" -version = "0.2.14" +name = "toml" +version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" +checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" dependencies = [ - "autocfg", + "serde", ] [[package]] -name = "num_cpus" -version = "1.13.1" +name = "tower" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" +checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" dependencies = [ - "hermit-abi", - "libc", + "futures-core", + "futures-util", + "pin-project", + "pin-project-lite", + "tokio", + "tower-layer", + "tower-service", ] [[package]] -name = "once_cell" -version = "1.8.0" +name = "tower-layer" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56" +checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" [[package]] -name = "opaque-debug" -version = "0.3.0" +name = "tower-service" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" +checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" [[package]] -name = "parking_lot" -version = "0.12.0" +name = "tracing" +version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87f5ec2493a61ac0506c0f4199f99070cbe83857b0337006a30f3e6719b8ef58" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ - "lock_api", - "parking_lot_core", + "log", + "pin-project-lite", + "tracing-attributes", + "tracing-core", ] [[package]] -name = "parking_lot_core" -version = "0.9.2" +name = "tracing-attributes" +version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "995f667a6c822200b0433ac218e05582f0e2efa1b922a3fd2fbaadc5f87bab37" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ - "cfg-if 1.0.0", - "libc", - "redox_syscall", - "smallvec", - "windows-sys", + "proc-macro2", + "quote", + "syn 2.0.72", ] [[package]] -name = "pathdiff" -version = "0.2.1" +name = "tracing-core" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +dependencies = [ + "once_cell", +] + +[[package]] +name = "try-lock" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] -name = "pest" -version = "2.1.3" +name = "type-map" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10f4872ae94d7b90ae48754df22fd42ad52ce740b8f370b03da4835417403e53" +checksum = "deb68604048ff8fa93347f02441e4487594adc20bb8a084f9e564d2b827a0a9f" dependencies = [ - "ucd-trie", + "rustc-hash", ] [[package]] -name = "petgraph" -version = "0.6.0" +name = "typeid" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a13a2fa9d0b63e5f22328828741e523766fff0ee9e779316902290dff3f824f" -dependencies = [ - "fixedbitset", - "indexmap", -] +checksum = "059d83cc991e7a42fc37bd50941885db0888e34209f8cfd9aab07ddec03bc9cf" [[package]] -name = "phf" -version = "0.9.0" +name = "typenum" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2ac8b67553a7ca9457ce0e526948cad581819238f4a9d1ea74545851fa24f37" -dependencies = [ - "phf_macros", - "phf_shared", - "proc-macro-hack", -] +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" [[package]] -name = "phf_generator" -version = "0.9.1" +name = "typetag" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d43f3220d96e0080cc9ea234978ccd80d904eafb17be31bb0f76daaea6493082" +checksum = "1f7ec175048b96728c30152928c52161bfcc8ea2bd3fb7ed4ccb7dec060b2834" dependencies = [ - "phf_shared", - "rand 0.8.4", + "erased-serde", + "inventory", + "once_cell", + "serde", + "typetag-impl", ] [[package]] -name = "phf_macros" -version = "0.9.0" +name = "typetag-impl" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b706f5936eb50ed880ae3009395b43ed19db5bff2ebd459c95e7bf013a89ab86" +checksum = "84b5474fd169a5b02b6782b56bbbbff27e85947d4488e5501123687db3148647" dependencies = [ - "phf_generator", - "phf_shared", - "proc-macro-hack", "proc-macro2", "quote", - "syn", + "syn 2.0.72", ] [[package]] -name = "phf_shared" +name = "ucd-trie" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9" + +[[package]] +name = "unic-char-property" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a68318426de33640f02be62b4ae8eb1261be2efbc337b60c54d845bf4484e0d9" +checksum = "a8c57a407d9b6fa02b4795eb81c5b6652060a15a7903ea981f3d723e6c0be221" dependencies = [ - "siphasher", + "unic-char-range", ] [[package]] -name = "pin-project-lite" -version = "0.2.8" +name = "unic-char-range" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e280fbe77cc62c91527259e9442153f4688736748d24660126286329742b4c6c" +checksum = "0398022d5f700414f6b899e10b8348231abf9173fa93144cbc1a43b9793c1fbc" [[package]] -name = "ppv-lite86" -version = "0.2.15" +name = "unic-common" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed0cfbc8191465bed66e1718596ee0b0b35d5ee1f41c5df2189d0fe8bde535ba" +checksum = "80d7ff825a6a654ee85a63e80f92f054f904f21e7d12da4e22f9834a4aaa35bc" [[package]] -name = "proc-macro-hack" -version = "0.5.19" +name = "unic-emoji-char" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" +checksum = "0b07221e68897210270a38bde4babb655869637af0f69407f96053a34f76494d" +dependencies = [ + "unic-char-property", + "unic-char-range", + "unic-ucd-version", +] [[package]] -name = "proc-macro2" -version = "1.0.36" +name = "unic-langid" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029" +checksum = "23dd9d1e72a73b25e07123a80776aae3e7b0ec461ef94f9151eed6ec88005a44" dependencies = [ - "unicode-xid", + "unic-langid-impl", + "unic-langid-macros", ] [[package]] -name = "psm" -version = "0.1.18" +name = "unic-langid-impl" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "871372391786ccec00d3c5d3d6608905b3d4db263639cfe075d3b60a736d115a" +checksum = "0a5422c1f65949306c99240b81de9f3f15929f5a8bfe05bb44b034cc8bf593e5" dependencies = [ - "cc", + "tinystr", ] [[package]] -name = "quote" -version = "1.0.15" +name = "unic-langid-macros" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "864d3e96a899863136fc6e99f3d7cae289dafe43bf2c5ac19b70df7210c0a145" +checksum = "0da1cd2c042d3c7569a1008806b02039e7a4a2bdf8f8e96bd3c792434a0e275e" dependencies = [ - "proc-macro2", + "proc-macro-hack", + "tinystr", + "unic-langid-impl", + "unic-langid-macros-impl", ] [[package]] -name = "rand" -version = "0.3.23" +name = "unic-langid-macros-impl" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64ac302d8f83c0c1974bf758f6b041c6c8ada916fbb44a609158ca8b064cc76c" +checksum = "1ed7f4237ba393424195053097c1516bd4590dc82b84f2f97c5c69e12704555b" dependencies = [ - "libc", - "rand 0.4.6", + "proc-macro-hack", + "quote", + "syn 2.0.72", + "unic-langid-impl", ] [[package]] -name = "rand" -version = "0.4.6" +name = "unic-ucd-bidi" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" +checksum = "d1d568b51222484e1f8209ce48caa6b430bf352962b877d592c29ab31fb53d8c" dependencies = [ - "fuchsia-cprng", - "libc", - "rand_core 0.3.1", - "rdrand", - "winapi", + "unic-char-property", + "unic-char-range", + "unic-ucd-version", ] [[package]] -name = "rand" -version = "0.8.4" +name = "unic-ucd-category" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8" +checksum = "1b8d4591f5fcfe1bd4453baaf803c40e1b1e69ff8455c47620440b46efef91c0" dependencies = [ - "libc", - "rand_chacha", - "rand_core 0.6.3", - "rand_hc", + "matches", + "unic-char-property", + "unic-char-range", + "unic-ucd-version", ] [[package]] -name = "rand_chacha" -version = "0.3.1" +name = "unic-ucd-version" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +checksum = "96bd2f2237fe450fcd0a1d2f5f4e91711124f7857ba2e964247776ebeeb7b0c4" dependencies = [ - "ppv-lite86", - "rand_core 0.6.3", + "unic-common", ] [[package]] -name = "rand_core" -version = "0.3.1" +name = "unicase" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" +checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89" dependencies = [ - "rand_core 0.4.2", + "version_check", ] [[package]] -name = "rand_core" -version = "0.4.2" +name = "unicode-casing" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" +checksum = "623f59e6af2a98bdafeb93fa277ac8e1e40440973001ca15cf4ae1541cd16d56" [[package]] -name = "rand_core" -version = "0.6.3" +name = "unicode-ident" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" -dependencies = [ - "getrandom", -] +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] -name = "rand_hc" -version = "0.3.1" +name = "unicode-normalization" +version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d51e9f596de227fda2ea6c84607f5558e196eeaf43c986b724ba4fb8fdf497e7" +checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" dependencies = [ - "rand_core 0.6.3", + "tinyvec", ] [[package]] -name = "rdrand" -version = "0.4.0" +name = "unicode-segmentation" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" -dependencies = [ - "rand_core 0.3.1", -] +checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" [[package]] -name = "redox_syscall" -version = "0.2.10" +name = "unicode-width" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff" -dependencies = [ - "bitflags", -] +checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d" [[package]] -name = "regex" -version = "1.5.4" +name = "unicode-xid" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] +checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" [[package]] -name = "regex-automata" -version = "0.1.10" +name = "unicode_names2" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" +checksum = "87d6678d7916394abad0d4b19df4d3802e1fd84abd7d701f39b75ee71b9e8cf1" [[package]] -name = "regex-syntax" -version = "0.6.25" +name = "unsafe-libyaml" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" +checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" [[package]] -name = "remove_dir_all" -version = "0.5.3" +name = "untrusted" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" -dependencies = [ - "winapi", -] +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] -name = "ron" -version = "0.7.0" +name = "url" +version = "2.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b861ecaade43ac97886a512b360d01d66be9f41f3c61088b42cedf92e03d678" +checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" dependencies = [ - "base64", - "bitflags", + "form_urlencoded", + "idna", + "percent-encoding", "serde", ] [[package]] -name = "rust-crypto" -version = "0.2.36" +name = "utf16_iter" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f76d05d3993fd5f4af9434e8e436db163a12a9d40e1a58a726f27a01dfd12a2a" -dependencies = [ - "gcc", - "libc", - "rand 0.3.23", - "rustc-serialize", - "time", -] +checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" [[package]] -name = "rustc-hash" -version = "1.1.0" +name = "utf8_iter" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" [[package]] -name = "rustc-rayon" -version = "0.3.2" +name = "utf8parse" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9974ab223660e61c1b4e7b43b827379df286736ca988308ce7e16f59f2d89246" -dependencies = [ - "crossbeam-deque", - "either", - "rustc-rayon-core", -] +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] -name = "rustc-rayon-core" -version = "0.3.2" +name = "uuid" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "564bfd27be8db888d0fa76aa4335e7851aaed0c2c11ad1e93aeb9349f6b88500" +checksum = "81dfa00651efa65069b0b6b651f4aaa31ba9e3c3ce0137aaad053604ee7e0314" dependencies = [ - "crossbeam-deque", - "crossbeam-utils", - "lazy_static", - "num_cpus", + "getrandom", + "serde", ] [[package]] -name = "rustc-serialize" -version = "0.3.24" +name = "vergen" +version = "9.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda" - -[[package]] -name = "rustc_data_structures" -version = "0.0.0" +checksum = "c32e7318e93a9ac53693b6caccfb05ff22e04a44c7cf8a279051f24c09da286f" dependencies = [ - "arrayvec", - "bitflags", - "cfg-if 0.1.10", - "ena", - "indexmap", - "jobserver", - "libc", - "memmap2", - "parking_lot", - "rustc-hash", - "rustc-rayon", - "rustc-rayon-core", - "stable_deref_trait", - "stacker", - "tempfile", - "tracing", - "winapi", + "anyhow", + "derive_builder", + "rustc_version 0.4.0", + "rustversion", + "vergen-lib", ] [[package]] -name = "rustc_lexer" -version = "0.1.0" +name = "vergen-gitcl" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c86aae0c77166108c01305ee1a36a1e77289d7dc6ca0a3cd91ff4992de2d16a5" +checksum = "3bbdc9746577cb4767f218d320ee0b623d415e8130332f8f562b910b61cc2c4e" dependencies = [ - "unicode-xid", + "anyhow", + "derive_builder", + "rustversion", + "time 0.3.36", + "vergen", + "vergen-lib", ] [[package]] -name = "rustc_span" -version = "0.0.0" +name = "vergen-lib" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e06bee42361e43b60f363bad49d63798d0f42fb1768091812270eca00c784720" dependencies = [ - "cfg-if 0.1.10", - "md-5", - "rustc_data_structures", - "scoped-tls", - "sha-1", - "sha2 0.10.2", - "tracing", - "unicode-width", + "anyhow", + "derive_builder", + "getset", + "rustversion", ] [[package]] -name = "ryu" -version = "1.0.5" +name = "version_check" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] -name = "same-file" -version = "1.0.6" +name = "walkdir" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" dependencies = [ + "same-file", "winapi-util", ] [[package]] -name = "scoped-tls" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2" - -[[package]] -name = "scopeguard" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" - -[[package]] -name = "semver" -version = "0.11.0" +name = "want" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" dependencies = [ - "semver-parser", + "try-lock", ] [[package]] -name = "semver-parser" -version = "0.10.2" +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0bef5b7f9e0df16536d3961cfb6e84331c065b4066afb39768d0e319411f7" -dependencies = [ - "pest", -] +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] -name = "serde" -version = "1.0.130" +name = "wasm-bindgen" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f12d06de37cf59146fbdecab66aa99f9fe4f78722e3607577a5375d66bd0c913" +checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" dependencies = [ - "serde_derive", + "cfg-if 1.0.0", + "wasm-bindgen-macro", ] [[package]] -name = "serde_derive" -version = "1.0.130" +name = "wasm-bindgen-backend" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7bc1a1ab1961464eae040d96713baa5a724a8152c1222492465b54322ec508b" +checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" dependencies = [ + "bumpalo", + "log", + "once_cell", "proc-macro2", "quote", - "syn", + "syn 2.0.72", + "wasm-bindgen-shared", ] [[package]] -name = "serde_json" -version = "1.0.69" +name = "wasm-bindgen-futures" +version = "0.4.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e466864e431129c7e0d3476b92f20458e5879919a0596c6472738d9fa2d342f8" +checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0" dependencies = [ - "itoa", - "ryu", - "serde", + "cfg-if 1.0.0", + "js-sys", + "wasm-bindgen", + "web-sys", ] [[package]] -name = "serde_yaml" -version = "0.8.23" +name = "wasm-bindgen-macro" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a521f2940385c165a24ee286aa8599633d162077a54bdcae2a6fd5a7bfa7a0" +checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" dependencies = [ - "indexmap", - "ryu", - "serde", - "yaml-rust", + "quote", + "wasm-bindgen-macro-support", ] [[package]] -name = "sha-1" -version = "0.10.0" +name = "wasm-bindgen-macro-support" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "028f48d513f9678cda28f6e4064755b3fbb2af6acd672f2c209b62323f7aea0f" +checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ - "cfg-if 1.0.0", - "cpufeatures", - "digest 0.10.3", + "proc-macro2", + "quote", + "syn 2.0.72", + "wasm-bindgen-backend", + "wasm-bindgen-shared", ] [[package]] -name = "sha1" -version = "0.6.0" +name = "wasm-bindgen-shared" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" + +[[package]] +name = "wasm-streams" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2579985fda508104f7587689507983eadd6a6e84dd35d6d115361f530916fa0d" +checksum = "b65dc4c90b63b118468cf747d8bf3566c1913ef60be765b5730ead9e0a3ba129" +dependencies = [ + "futures-util", + "js-sys", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] [[package]] -name = "sha2" -version = "0.9.8" +name = "web-sys" +version = "0.3.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b69f9a4c9740d74c5baa3fd2e547f9525fa8088a8a958e0ca2409a514e33f5fa" +checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" dependencies = [ - "block-buffer 0.9.0", - "cfg-if 1.0.0", - "cpufeatures", - "digest 0.9.0", - "opaque-debug", + "js-sys", + "wasm-bindgen", ] [[package]] -name = "sha2" -version = "0.10.2" +name = "webpki-roots" +version = "0.26.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55deaec60f81eefe3cce0dc50bda92d6d8e88f2a27df7c5033b42afeb1ed2676" +checksum = "bd7c23921eeb1713a4e851530e9b9756e4fb0e89978582942612524cf09f01cd" dependencies = [ - "cfg-if 1.0.0", - "cpufeatures", - "digest 0.10.3", + "rustls-pki-types", ] [[package]] -name = "siphasher" -version = "0.3.7" +name = "which" +version = "4.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "533494a8f9b724d33625ab53c6c4800f7cc445895924a8ef649222dcb76e938b" +checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" +dependencies = [ + "either", + "home", + "once_cell", + "rustix", +] [[package]] -name = "smallvec" -version = "1.6.1" +name = "winapi" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] [[package]] -name = "stable_deref_trait" -version = "1.2.0" +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] -name = "stacker" -version = "0.1.14" +name = "winapi-util" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90939d5171a4420b3ff5fbc8954d641e7377335454c259dcb80786f3f21dc9b4" +checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b" dependencies = [ - "cc", - "cfg-if 1.0.0", - "libc", - "psm", - "winapi", + "windows-sys 0.52.0", ] [[package]] -name = "strsim" -version = "0.8.0" +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] -name = "syn" -version = "1.0.86" +name = "windows" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a65b3f4ffa0092e9887669db0eae07941f023991ab58ea44da8fe8e2d511c6b" +checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be" dependencies = [ - "proc-macro2", - "quote", - "unicode-xid", + "windows-core", + "windows-targets 0.52.6", ] [[package]] -name = "synstructure" -version = "0.12.6" +name = "windows-core" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" dependencies = [ - "proc-macro2", - "quote", - "syn", - "unicode-xid", + "windows-targets 0.52.6", ] [[package]] -name = "tempfile" -version = "3.3.0" +name = "windows-sys" +version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" +checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" dependencies = [ - "cfg-if 1.0.0", - "fastrand", - "libc", - "redox_syscall", - "remove_dir_all", - "winapi", + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", ] [[package]] -name = "termcolor" -version = "1.1.3" +name = "windows-sys" +version = "0.45.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" dependencies = [ - "winapi-util", + "windows-targets 0.42.2", ] [[package]] -name = "termize" -version = "0.1.1" +name = "windows-sys" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1706be6b564323ce7092f5f7e6b118a14c8ef7ed0e69c8c5329c914a9f101295" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ - "libc", - "winapi", + "windows-targets 0.48.5", ] [[package]] -name = "textwrap" -version = "0.11.0" +name = "windows-sys" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "unicode-width", + "windows-targets 0.52.6", ] [[package]] -name = "thiserror" -version = "1.0.30" +name = "windows-targets" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417" +checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" dependencies = [ - "thiserror-impl", + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", ] [[package]] -name = "thiserror-impl" -version = "1.0.30" +name = "windows-targets" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" dependencies = [ - "proc-macro2", - "quote", - "syn", + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", ] [[package]] -name = "threadpool" -version = "1.8.1" +name = "windows-targets" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d050e60b33d41c19108b32cea32164033a9013fe3b46cbd4457559bfbf77afaa" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "num_cpus", + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", ] [[package]] -name = "time" -version = "0.1.44" +name = "windows_aarch64_gnullvm" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255" -dependencies = [ - "libc", - "wasi", - "winapi", -] +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" [[package]] -name = "toml" -version = "0.5.8" +name = "windows_aarch64_gnullvm" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa" -dependencies = [ - "serde", -] +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] -name = "tracing" -version = "0.1.32" +name = "windows_aarch64_gnullvm" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a1bdf54a7c28a2bbf701e1d2233f6c77f473486b94bee4f9678da5a148dca7f" -dependencies = [ - "cfg-if 1.0.0", - "pin-project-lite", - "tracing-attributes", - "tracing-core", -] +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] -name = "tracing-attributes" -version = "0.1.20" +name = "windows_aarch64_msvc" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e65ce065b4b5c53e73bb28912318cb8c9e9ad3921f1d669eb0e68b4c8143a2b" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" [[package]] -name = "tracing-core" -version = "0.1.23" +name = "windows_aarch64_msvc" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa31669fa42c09c34d94d8165dd2012e8ff3c66aca50f3bb226b68f216f2706c" -dependencies = [ - "lazy_static", -] +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] -name = "typenum" -version = "1.14.0" +name = "windows_aarch64_msvc" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b63708a265f51345575b27fe43f9500ad611579e764c79edbc2037b1121959ec" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] -name = "ucd-trie" -version = "0.1.3" +name = "windows_i686_gnu" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" [[package]] -name = "unic-char-property" -version = "0.9.0" +name = "windows_i686_gnu" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8c57a407d9b6fa02b4795eb81c5b6652060a15a7903ea981f3d723e6c0be221" -dependencies = [ - "unic-char-range", -] +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] -name = "unic-char-range" -version = "0.9.0" +name = "windows_i686_gnu" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0398022d5f700414f6b899e10b8348231abf9173fa93144cbc1a43b9793c1fbc" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" [[package]] -name = "unic-common" -version = "0.9.0" +name = "windows_i686_gnullvm" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80d7ff825a6a654ee85a63e80f92f054f904f21e7d12da4e22f9834a4aaa35bc" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] -name = "unic-emoji-char" -version = "0.9.0" +name = "windows_i686_msvc" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b07221e68897210270a38bde4babb655869637af0f69407f96053a34f76494d" -dependencies = [ - "unic-char-property", - "unic-char-range", - "unic-ucd-version", -] +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" [[package]] -name = "unic-ucd-bidi" -version = "0.9.0" +name = "windows_i686_msvc" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1d568b51222484e1f8209ce48caa6b430bf352962b877d592c29ab31fb53d8c" -dependencies = [ - "unic-char-property", - "unic-char-range", - "unic-ucd-version", -] +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] -name = "unic-ucd-category" -version = "0.9.0" +name = "windows_i686_msvc" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b8d4591f5fcfe1bd4453baaf803c40e1b1e69ff8455c47620440b46efef91c0" -dependencies = [ - "matches", - "unic-char-property", - "unic-char-range", - "unic-ucd-version", -] +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] -name = "unic-ucd-version" -version = "0.9.0" +name = "windows_x86_64_gnu" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96bd2f2237fe450fcd0a1d2f5f4e91711124f7857ba2e964247776ebeeb7b0c4" -dependencies = [ - "unic-common", -] +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" [[package]] -name = "unicode-casing" -version = "0.1.0" +name = "windows_x86_64_gnu" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "623f59e6af2a98bdafeb93fa277ac8e1e40440973001ca15cf4ae1541cd16d56" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] -name = "unicode-width" -version = "0.1.8" +name = "windows_x86_64_gnu" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] -name = "unicode-xid" -version = "0.2.2" +name = "windows_x86_64_gnullvm" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" [[package]] -name = "unicode_names2" -version = "0.4.0" +name = "windows_x86_64_gnullvm" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87d6678d7916394abad0d4b19df4d3802e1fd84abd7d701f39b75ee71b9e8cf1" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] -name = "vec_map" -version = "0.8.2" +name = "windows_x86_64_gnullvm" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] -name = "version_check" -version = "0.9.3" +name = "windows_x86_64_msvc" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" [[package]] -name = "walkdir" -version = "2.3.2" +name = "windows_x86_64_msvc" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" -dependencies = [ - "same-file", - "winapi", - "winapi-util", -] +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] -name = "wasi" -version = "0.10.0+wasi-snapshot-preview1" +name = "windows_x86_64_msvc" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] -name = "winapi" -version = "0.3.9" +name = "winreg" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +checksum = "a277a57398d4bfa075df44f501a17cfdf8542d224f0d36095a2adc7aee4ef0a5" dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", + "cfg-if 1.0.0", + "windows-sys 0.48.0", ] [[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" +name = "write16" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" [[package]] -name = "winapi-util" -version = "0.1.5" +name = "writeable" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" + +[[package]] +name = "xattr" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +checksum = "8da84f1a25939b27f6820d92aed108f83ff920fdf11a7b19366c27c4cda81d4f" dependencies = [ - "winapi", + "libc", + "linux-raw-sys", + "rustix", ] [[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" +name = "yaml-rust" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85" +dependencies = [ + "linked-hash-map", +] [[package]] -name = "windows-sys" -version = "0.34.0" +name = "yansi" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" + +[[package]] +name = "yansi-term" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5acdd78cb4ba54c0045ac14f62d8f94a03d10047904ae2a40afa1e99d8f70825" +checksum = "fe5c30ade05e61656247b2e334a031dfd0cc466fadef865bdcdea8d537951bf1" dependencies = [ - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_msvc", + "winapi", ] [[package]] -name = "windows_aarch64_msvc" -version = "0.34.0" +name = "yoke" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" +dependencies = [ + "serde", + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17cffbe740121affb56fad0fc0e421804adf0ae00891205213b5cecd30db881d" +checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.72", + "synstructure 0.13.1", +] [[package]] -name = "windows_i686_gnu" -version = "0.34.0" +name = "zerofrom" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2564fde759adb79129d9b4f54be42b32c89970c18ebf93124ca8870a498688ed" +checksum = "cff3ee08c995dee1859d998dea82f7374f2826091dd9cd47def953cae446cd2e" +dependencies = [ + "zerofrom-derive", +] [[package]] -name = "windows_i686_msvc" -version = "0.34.0" +name = "zerofrom-derive" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cd9d32ba70453522332c14d38814bceeb747d80b3958676007acadd7e166956" +checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.72", + "synstructure 0.13.1", +] [[package]] -name = "windows_x86_64_gnu" -version = "0.34.0" +name = "zeroize" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfce6deae227ee8d356d19effc141a509cc503dfd1f850622ec4b0f84428e1f4" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" [[package]] -name = "windows_x86_64_msvc" -version = "0.34.0" +name = "zerovec" +version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d19538ccc21819d01deaf88d6a17eae6596a12e9aafdbb97916fb49896d89de9" +checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] [[package]] -name = "yaml-rust" -version = "0.4.5" +name = "zerovec-derive" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85" +checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" dependencies = [ - "linked-hash-map", + "proc-macro2", + "quote", + "syn 2.0.72", ] diff --git a/kclvm/Cargo.toml b/kclvm/Cargo.toml index 98a49db0c..f2cf647a5 100644 --- a/kclvm/Cargo.toml +++ b/kclvm/Cargo.toml @@ -1,39 +1,64 @@ [package] name = "kclvm" -version = "0.1.0" +version = "0.11.0" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [lib] -crate-type = ["cdylib"] +crate-type = ["cdylib", "staticlib"] path = "src/lib.rs" name = "kclvm_cli_cdylib" -[[bin]] -path = "src/main.rs" -name = "kclvm_cli" - [dependencies] -clap = "2.33.3" -serde_json = "1.0" -serde = { version = "1", features = ["derive"] } -glob = "0.3.0" -walkdir = "2" -libc = "0.2.112" -indexmap = "1.0" -fslock = "0.2.1" -libloading = "0.7.3" -chrono = "0.4.19" -threadpool = "1.0" +kclvm-api = {path = "./api"} +kclvm-cmd = {path = "./cmd"} +kclvm-ast = {path = "./ast"} +kclvm-runner = {path = "./runner"} +kclvm-parser = {path = "./parser"} +kclvm-compiler = {path = "./compiler"} +kclvm-config = {path = "./config"} +kclvm-loader = {path = "./loader"} +kclvm-runtime = {path = "./runtime"} +kclvm-sema = {path = "./sema"} +kclvm-tools = {path = "./tools"} +kclvm-version = {path = "./version"} +kclvm-error = {path = "./error"} +kclvm-evaluator = {path = "./evaluator"} +kclvm-query = {path = "./query"} +kclvm-driver = {path = "./driver"} + +[profile.release] +rpath = true +panic = "unwind" +opt-level = "z" # Optimize for size. +lto = true + +[workspace] +members = [ + "third-party/prost-wkt", + "third-party/prost-wkt/wkt-build", + "third-party/prost-wkt/wkt-types", + "api", + "cmd", + "ast", + "ast_pretty", + "compiler", + "config", + "error", + "lexer", + "macros", + "parser", + "runner", + "runtime", + "sema", + "span", + "tools", + "version", + "query", + "utils", + "tools/src/LSP" +] -kclvm-ast = {path = "./ast", version = "0.1.0"} -kclvm-runner = {path = "./runner", version = "0.1.0"} -kclvm-parser = {path = "./parser", version = "0.1.0"} -kclvm-compiler = {path = "./compiler", version = "0.1.0"} -kclvm-config = {path = "./config", version = "0.1.0"} -kclvm-runtime = {path = "./runtime", version = "0.1.0"} -kclvm-sema = {path = "./sema", version = "0.1.0"} -kclvm-tools = {path = "./tools", version = "0.1.0"} -kclvm-version = {path = "./version", version = "0.1.0"} -kclvm-error = {path = "./error", version = "0.1.0"} +[features] +llvm = ["kclvm-compiler/llvm", "kclvm-runner/llvm", "kclvm-tools/llvm", "kclvm-api/llvm"] diff --git a/kclvm/README.md b/kclvm/README.md index 4cb36dfde..bfee41bd5 100644 --- a/kclvm/README.md +++ b/kclvm/README.md @@ -6,45 +6,36 @@ A high-performance implementation of KCL written in Rust that uses LLVM as the c Firstly, see [KCLVM CONTRIBUTING](../CONTRIBUTING.md) to build KCLVM. Secondly, we need to download the [Rust](https://www.rust-lang.org/), [SWIG](http://www.swig.org/), [LLVM 12](https://releases.llvm.org/download.html), and add the LLVM installation location to `LLVM_SYS_120_PREFIX` and the `$PATH`. -``` +```shell export LLVM_SYS_120_PREFIX= export PATH=/bin:$PATH ``` -Thirdly, install wasm target dependencies. - -``` -make install-rustc-wasm -``` - To build everything, run: -``` +```shell make ``` After building, we can add the following command line parameters to use the KCL high-performance version: -``` -kcl --target native main.k +```shell +kclvm_cli run main.k ``` To test, run: -``` +```shell make test ``` ## Building and Testing in Docker 1. `make -C .. sh-in-docker` -2. `./run.sh -a build-cpython` only once -3. `./run.sh -a build-kclvm` -4. `export PATH=$PATH:/root/kclvm/_build/dist/ubuntu/kclvm/bin` -5. `which kcl` -6. `kcl hello.k` -7. `kcl hello.k --target native` -8. `cd kclvm && make test-grammar` +2. `make build` +3. `export PATH=$PATH:/root/kclvm/_build/dist/ubuntu/kclvm/bin` +4. `kcl ./samples/hello.k` +5. `cd kclvm && make test` ## IDE @@ -52,11 +43,10 @@ You can choose any IDE you like for development, but we recommend a combination ## Notes -1. If you encounter problems compiling KCLVM and using LLVM 12 on Apple M1, you can refer to the [documentation](./docs/m1-mac-setup.md) -2. If you wanna start over, you `MUST` clean up all cached building files, such as `LLVM build files`, `kclvm/target`, etc. -3. If your updating-cargo-index is extremely slow, setup `~/.cargo/config` file. +1. If you wanna start over, you `MUST` clean up all cached building files, such as `LLVM build files`, `kclvm/target`, etc. +2. If your updating-cargo-index is extremely slow, setup `~/.cargo/config` file. -``` +```toml [source.crates-io] registry = "https://github.com/rust-lang/crates.io-index" replace-with = 'ustc' diff --git a/kclvm/api/Cargo.toml b/kclvm/api/Cargo.toml new file mode 100644 index 000000000..4d4ab7953 --- /dev/null +++ b/kclvm/api/Cargo.toml @@ -0,0 +1,51 @@ +[package] +name = "kclvm-api" +version = "0.11.0" +edition = "2021" + +[dependencies] +futures = "0.3.28" +tempfile = "3.5.0" +maplit = "1.0.2" +prost = "0.11.8" +prost-types = "0.11.8" +serde_json = "1.0" +serde_yaml = {path = "../third-party/serde_yaml"} +anyhow = "1.0.70" +serde = { version = "1", features = ["derive"] } +indexmap = "1.0" +once_cell = "1.5.2" + +prost-wkt = {path = "../third-party/prost-wkt", version = "0.4.1"} +prost-wkt-types = {path = "../third-party/prost-wkt/wkt-types", version = "0.4.1"} + +kclvm-runner = {path = "../runner"} +kclvm-config = {path = "../config"} +kclvm-driver = {path = "../driver"} +kclvm-error = {path = "../error"} +kclvm-parser = {path = "../parser"} +kclvm-loader = {path = "../loader"} +kclvm-sema = {path = "../sema"} +kclvm-ast = {path = "../ast"} +kclvm-ast-pretty = {path = "../ast_pretty"} +kclvm-runtime = {path = "../runtime"} +kclvm-tools = {path = "../tools" } +kclvm-query = {path = "../query"} +kclvm-version = { path = "../version" } +kcl-language-server = {path = "../tools/src/LSP"} +kclvm-utils = {path = "../utils"} + +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +jsonrpc-stdio-server = "18.0.0" +tokio = { version = "1.37.0", features = ["full"] } + +[dev-dependencies] +criterion = "0.5" + +[build-dependencies] +protoc-bin-vendored = { git = "https://github.com/kcl-lang/rust-protoc-bin-vendored", version = "3.2.0" } +prost-build = "0.11.8" +prost-wkt-build = {path = "../third-party/prost-wkt/wkt-build", version = "0.4.1"} + +[features] +llvm = ["kclvm-runner/llvm"] diff --git a/kclvm/api/build.rs b/kclvm/api/build.rs new file mode 100644 index 000000000..7d1c39b77 --- /dev/null +++ b/kclvm/api/build.rs @@ -0,0 +1,34 @@ +use std::{env, path::PathBuf}; + +use prost_wkt_build::{FileDescriptorSet, Message}; + +/// According to the file kclvm/spec/gpyrpc/gpyrpc.proto, automatically generate +/// the corresponding rust source file to the directory src/model +fn main() { + if env::var("PROTOC").is_err() { + env::set_var( + "PROTOC", + protoc_bin_vendored::protoc_bin_path().unwrap().as_os_str(), + ); + } + + let out = PathBuf::from(env::var("OUT_DIR").unwrap()); + let descriptor_file = out.join("kclvm_service_descriptor.bin"); + + let mut prost_build = prost_build::Config::new(); + prost_build + .type_attribute(".", "#[derive(serde::Serialize,serde::Deserialize)]") + .field_attribute(".", "#[serde(default)]") + .extern_path(".google.protobuf.Any", "::prost_wkt_types::Any") + .extern_path(".google.protobuf.Timestamp", "::prost_wkt_types::Timestamp") + .extern_path(".google.protobuf.Value", "::prost_wkt_types::Value") + .file_descriptor_set_path(&descriptor_file) + .compile_protos(&["../spec/gpyrpc/gpyrpc.proto"], &["../spec/gpyrpc/"]) + .expect("Running prost build failed."); + + let descriptor_bytes = std::fs::read(descriptor_file).unwrap(); + + let descriptor = FileDescriptorSet::decode(&descriptor_bytes[..]).unwrap(); + + prost_wkt_build::add_serde(out, descriptor); +} diff --git a/kclvm/api/src/capi_test.rs b/kclvm/api/src/capi_test.rs new file mode 100644 index 000000000..24ca0b32d --- /dev/null +++ b/kclvm/api/src/capi_test.rs @@ -0,0 +1,387 @@ +use crate::service::capi::*; +use crate::{call, gpyrpc::*}; +use kclvm_utils::path::PathPrefix; +use once_cell::sync::Lazy; +use prost::Message; +use serde::de::DeserializeOwned; +use std::default::Default; +use std::ffi::{CStr, CString}; +use std::fs; +use std::os::raw::c_char; +use std::path::{Path, PathBuf}; +use std::sync::Mutex; +const TEST_DATA_PATH: &str = "./src/testdata"; +static TEST_MUTEX: Lazy> = Lazy::new(|| Mutex::new(0i32)); + +#[test] +fn test_c_api_call_exec_program() { + test_c_api::( + "KclvmService.ExecProgram", + "exec-program.json", + "exec-program.response.json", + |_| {}, + ); +} + +#[test] +fn test_c_api_call_exec_program_with_external_pkg() { + test_c_api::( + "KclvmService.ExecProgram", + "exec-program-with-external-pkg.json", + "exec-program-with-external-pkg.response.json", + |_| {}, + ); +} + +#[test] +fn test_c_api_call_exec_program_with_include_schema_type_path() { + test_c_api::( + "KclvmService.ExecProgram", + "exec-program-with-include-schema-type-path.json", + "exec-program-with-include-schema-type-path.response.json", + |_| {}, + ); +} + +#[test] +fn test_c_api_call_exec_program_with_path_selector() { + test_c_api::( + "KclvmService.ExecProgram", + "exec-program-with-path-selector.json", + "exec-program-with-path-selector.response.json", + |_| {}, + ); +} + +#[test] +fn test_c_api_call_exec_program_with_print() { + test_c_api::( + "KclvmService.ExecProgram", + "exec-program-with-print.json", + "exec-program-with-print.response.json", + |_| {}, + ); +} + +#[test] +fn test_c_api_call_override_file() { + let test_cases = [ + ("override-file.json", "override-file.response.json"), + ( + "override-file-dict.json", + "override-file-dict.response.json", + ), + ( + "override-file-dict_0.json", + "override-file-dict_0.response.json", + ), + ( + "override-file-list.json", + "override-file-list.response.json", + ), + ( + "override-file-bool.json", + "override-file-bool.response.json", + ), + ]; + + for (input, output) in &test_cases { + test_c_api_without_wrapper::( + "KclvmService.OverrideFile", + input, + output, + ); + } +} + +#[test] +fn test_c_api_get_schema_type_mapping() { + test_c_api::( + "KclvmService.GetSchemaTypeMapping", + "get-schema-type-mapping.json", + "get-schema-type-mapping.response.json", + |r| { + let root = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + for (_, s_ty) in &mut r.schema_type_mapping { + let filename = { + let filename = s_ty.filename.adjust_canonicalization(); + match filename.strip_prefix(root.to_str().unwrap()) { + Some(f) => f.to_string(), + None => s_ty.filename.clone(), + } + }; + + s_ty.filename = filename.replace('.', "").replace('/', "").replace('\\', "") + } + }, + ); +} + +#[test] +fn test_c_api_format_code() { + test_c_api_without_wrapper::( + "KclvmService.FormatCode", + "format-code.json", + "format-code.response.json", + ); +} + +#[test] +fn test_c_api_format_path() { + test_c_api_without_wrapper::( + "KclvmService.FormatPath", + "format-path.json", + "format-path.response.json", + ); +} + +#[test] +fn test_c_api_lint_path() { + test_c_api_without_wrapper::( + "KclvmService.LintPath", + "lint-path.json", + "lint-path.response.json", + ); +} + +#[test] +fn test_c_api_call_exec_program_with_compile_only() { + test_c_api_panic::( + "KclvmService.ExecProgram", + "exec-program-with-compile-only.json", + "exec-program-with-compile-only.response.panic", + ); +} + +#[test] +fn test_c_api_validate_code() { + test_c_api_without_wrapper::( + "KclvmService.ValidateCode", + "validate-code.json", + "validate-code.response.json", + ); +} + +#[test] +fn test_c_api_validate_code_file() { + test_c_api_without_wrapper::( + "KclvmService.ValidateCode", + "validate-code-file.json", + "validate-code-file.response.json", + ); +} + +#[test] +fn test_c_api_load_settings_files() { + test_c_api_without_wrapper::( + "KclvmService.LoadSettingsFiles", + "load-settings-files.json", + "load-settings-files.response.json", + ); +} + +#[test] +fn test_c_api_rename() { + // before test, load template from .bak + let path = Path::new(TEST_DATA_PATH).join("rename").join("main.k"); + let backup_path = path.with_extension("bak"); + let content = fs::read_to_string(backup_path.clone()).unwrap(); + fs::write(path.clone(), content).unwrap(); + + test_c_api::( + "KclvmService.Rename", + "rename.json", + "rename.response.json", + |r| { + r.changed_files = r + .changed_files + .iter() + .map(|f| { + PathBuf::from(f) + .canonicalize() + .unwrap() + .display() + .to_string() + }) + .collect(); + }, + ); + + // after test, restore template from .bak + fs::remove_file(path.clone()).unwrap(); +} + +#[test] +fn test_c_api_rename_code() { + test_c_api_without_wrapper::( + "KclvmService.RenameCode", + "rename-code.json", + "rename-code.response.json", + ); +} + +#[test] +fn test_c_api_list_options() { + test_c_api_without_wrapper::( + "KclvmService.ListOptions", + "list-options.json", + "list-options.response.json", + ); +} + +#[test] +fn test_c_api_list_variables() { + test_c_api_without_wrapper::( + "KclvmService.ListVariables", + "list-variables.json", + "list-variables.response.json", + ); +} + +#[test] +fn test_c_api_parse_file() { + test_c_api_without_wrapper::( + "KclvmService.ParseFile", + "parse-file.json", + "parse-file.response.json", + ); +} + +#[test] +fn test_c_api_testing() { + test_c_api::( + "KclvmService.Test", + "test.json", + "test.response.json", + |r| { + for i in &mut r.info { + i.duration = 0; + } + }, + ); +} + +fn test_c_api_without_wrapper(svc_name: &str, input: &str, output: &str) +where + A: Message + DeserializeOwned, + R: Message + Default + PartialEq + DeserializeOwned + serde::Serialize, +{ + test_c_api::(svc_name, input, output, |_| {}) +} + +fn test_c_api(svc_name: &str, input: &str, output: &str, wrapper: F) +where + A: Message + DeserializeOwned, + R: Message + Default + PartialEq + DeserializeOwned + serde::Serialize + ?Sized, + F: Fn(&mut R), +{ + let _test_lock = TEST_MUTEX.lock().unwrap(); + let serv = kclvm_service_new(0); + + let input_path = Path::new(TEST_DATA_PATH).join(input); + let input = fs::read_to_string(&input_path) + .unwrap_or_else(|_| panic!("Something went wrong reading {}", input_path.display())); + let args_vec = serde_json::from_str::(&input).unwrap().encode_to_vec(); + let args = unsafe { CString::from_vec_unchecked(args_vec.clone()) }; + let call = CString::new(svc_name).unwrap(); + let mut result_len: usize = 0; + let src_ptr = kclvm_service_call_with_length( + serv, + call.as_ptr(), + args.as_ptr(), + args_vec.len(), + &mut result_len, + ); + + let mut dest_data: Vec = Vec::with_capacity(result_len); + unsafe { + let dest_ptr: *mut u8 = dest_data.as_mut_ptr(); + std::ptr::copy_nonoverlapping(src_ptr as *const u8, dest_ptr, result_len); + dest_data.set_len(result_len); + } + + let mut result = R::decode(dest_data.as_slice()).unwrap(); + let result_json = serde_json::to_string(&result).unwrap(); + + let except_result_path = Path::new(TEST_DATA_PATH).join(output); + let except_result_json = fs::read_to_string(&except_result_path).unwrap_or_else(|_| { + panic!( + "Something went wrong reading {}", + except_result_path.display() + ) + }); + let mut except_result = serde_json::from_str::(&except_result_json).unwrap(); + wrapper(&mut result); + wrapper(&mut except_result); + assert_eq!(result, except_result, "\nresult json is {result_json}"); + unsafe { + kclvm_service_delete(serv); + kclvm_service_free_string(src_ptr as *mut c_char); + } +} + +fn test_c_api_panic(svc_name: &str, input: &str, output: &str) +where + A: Message + DeserializeOwned, +{ + let _test_lock = TEST_MUTEX.lock().unwrap(); + let serv = kclvm_service_new(0); + let prev_hook = std::panic::take_hook(); + // disable print panic info + std::panic::set_hook(Box::new(|_info| {})); + let result = std::panic::catch_unwind(|| { + let input_path = Path::new(TEST_DATA_PATH).join(input); + let input = fs::read_to_string(&input_path) + .unwrap_or_else(|_| panic!("Something went wrong reading {}", input_path.display())); + let args_vec = serde_json::from_str::(&input).unwrap().encode_to_vec(); + let args = unsafe { CString::from_vec_unchecked(args_vec.clone()) }; + let call = CString::new(svc_name).unwrap(); + kclvm_service_call(serv, call.as_ptr(), args.as_ptr(), args_vec.len()) + }); + std::panic::set_hook(prev_hook); + match result { + Ok(result_ptr) => { + let result = unsafe { CStr::from_ptr(result_ptr) }; + let except_result_path = Path::new(TEST_DATA_PATH).join(output); + let except_result_panic_msg = + fs::read_to_string(&except_result_path).unwrap_or_else(|_| { + panic!( + "Something went wrong reading {}", + except_result_path.display() + ) + }); + assert!( + result.to_string_lossy().contains(&except_result_panic_msg), + "{}", + result.to_string_lossy() + ); + unsafe { + kclvm_service_delete(serv); + kclvm_service_free_string(result_ptr as *mut c_char); + } + } + Err(_) => { + panic!("unreachable code") + } + } +} + +#[test] +fn test_call_exec_program() { + let name = b"KclvmService.ExecProgram"; + let args = b"\x12\x1a./src/testdata/test_call.k"; + let result = call(name, args).unwrap(); + assert!( + !result.starts_with(b"ERROR"), + "{}", + String::from_utf8(result).unwrap() + ); +} + +#[test] +fn test_call_get_version() { + let name = b"KclvmService.GetVersion"; + let args = b""; + let result = call(name, args).unwrap(); + assert!(!result.starts_with(b"ERROR")) +} diff --git a/kclvm/api/src/lib.rs b/kclvm/api/src/lib.rs new file mode 100644 index 000000000..1ccf47a3a --- /dev/null +++ b/kclvm/api/src/lib.rs @@ -0,0 +1,104 @@ +//! # KCL Rust SDK +//! +//! ## How to Use +//! +//! ```no_check,no_run +//! cargo add --git https://github.com/kcl-lang/kcl kclvm_api +//! ``` +//! +//! Write the Code +//! +//! ```no_run +//! use kclvm_api::*; +//! use std::path::Path; +//! use anyhow::Result; +//! +//! fn main() -> Result<()> { +//! let api = API::default(); +//! let args = &ExecProgramArgs { +//! work_dir: Path::new(".").join("testdata").canonicalize().unwrap().display().to_string(), +//! k_filename_list: vec!["test.k".to_string()], +//! ..Default::default() +//! }; +//! let exec_result = api.exec_program(args)?; +//! assert_eq!(exec_result.yaml_result, "alice:\n age: 18"); +//! Ok(()) +//! } +//! ``` +#[cfg(test)] +pub mod capi_test; +pub mod service; + +pub mod gpyrpc { + include!(concat!(env!("OUT_DIR"), "/gpyrpc.rs")); +} + +pub use crate::gpyrpc::*; +use crate::service::capi::{kclvm_service_call_with_length, kclvm_service_new}; +use crate::service::service_impl::KclvmServiceImpl; +use anyhow::Result; +use std::ffi::{c_char, CString}; + +pub type API = KclvmServiceImpl; + +/// Call KCL API with the API name and argument protobuf bytes. +#[inline] +pub fn call<'a>(name: &'a [u8], args: &'a [u8]) -> Result> { + call_with_plugin_agent(name, args, 0) +} + +/// Call KCL API with the API name, argument protobuf bytes and the plugin agent pointer address. +pub fn call_with_plugin_agent<'a>( + name: &'a [u8], + args: &'a [u8], + plugin_agent: u64, +) -> Result> { + let mut result_len: usize = 0; + let result_ptr = { + let serv = kclvm_service_new(plugin_agent); + let args_len = args.len(); + let name = unsafe { CString::from_vec_unchecked(name.to_vec()) }; + let args = unsafe { CString::from_vec_unchecked(args.to_vec()) }; + kclvm_service_call_with_length( + serv, + name.as_ptr(), + args.as_ptr() as *const c_char, + args_len, + &mut result_len, + ) + }; + let result = unsafe { + let mut dest_data: Vec = Vec::with_capacity(result_len); + let dest_ptr: *mut u8 = dest_data.as_mut_ptr(); + std::ptr::copy_nonoverlapping(result_ptr as *const u8, dest_ptr, result_len); + dest_data.set_len(result_len); + dest_data + }; + + Ok(result) +} + +/// call_native is a universal KCL API interface that is consistent with the methods and parameters defined in Protobuf. +/// The first two parameters represent the name and length of the calling method, the middle two parameters represent +/// the Protobuf byte sequence and length of the calling parameter, and the return parameter is the byte sequence and +/// length of Protobuf. +#[no_mangle] +pub extern "C" fn call_native( + name_ptr: *const u8, + name_len: usize, + args_ptr: *const u8, + args_len: usize, + result_ptr: *mut u8, +) -> usize { + let name = unsafe { std::slice::from_raw_parts(name_ptr, name_len) }; + let args = unsafe { std::slice::from_raw_parts(args_ptr, args_len) }; + let res = call(name, args); + let result = match res { + Ok(res) => res, + Err(err) => err.to_string().into_bytes(), + }; + unsafe { + std::ptr::copy_nonoverlapping(result.as_ptr(), result_ptr, result.len()); + } + result.len() +} diff --git a/kclvm/api/src/service/capi.rs b/kclvm/api/src/service/capi.rs new file mode 100644 index 000000000..82038698d --- /dev/null +++ b/kclvm/api/src/service/capi.rs @@ -0,0 +1,706 @@ +use prost::Message; + +use crate::gpyrpc::*; +use crate::service::service_impl::KclvmServiceImpl; +use std::ffi::CString; +use std::os::raw::c_char; +use std::slice; + +#[allow(non_camel_case_types)] +type kclvm_service = KclvmServiceImpl; + +fn c_char_to_vec(args: *const c_char, args_len: usize) -> Vec { + if args.is_null() { + return Vec::new(); + } + // Create a slice from the raw pointer + let slice = unsafe { slice::from_raw_parts(args as *const u8, args_len) }; + // Convert slice to Vec + slice.to_vec() +} + +/// Create an instance of kclvm_service and return its pointer +#[no_mangle] +pub extern "C" fn kclvm_service_new(plugin_agent: u64) -> *mut kclvm_service { + let serv = kclvm_service { plugin_agent }; + Box::into_raw(Box::new(serv)) +} + +/// # Safety +/// +/// This function should not be called twice on the same ptr. +/// Delete KclvmService +#[no_mangle] +pub unsafe extern "C" fn kclvm_service_delete(serv: *mut kclvm_service) { + if !serv.is_null() { + unsafe { + drop(Box::from_raw(serv)); + } + } +} + +/// # Safety +/// +/// This function should not be called twice on the same ptr. +/// Free memory for string returned to the outside +#[no_mangle] +pub unsafe extern "C" fn kclvm_service_free_string(res: *mut c_char) { + if !res.is_null() { + unsafe { + let _ = CString::from_raw(res); + }; + } +} + +macro_rules! call { + ($serv:expr, $args:expr, $args_len:expr, $result_len:expr, $arg_name:ident, $serv_name:ident) => {{ + unsafe { + let serv_ref = &mut *$serv; + let args = c_char_to_vec($args, $args_len); + let args = args.as_slice(); + let args = $arg_name::decode(args).unwrap(); + let res = serv_ref.$serv_name(&args); + let result_byte = match res { + Ok(res) => res.encode_to_vec(), + Err(err) => format!("ERROR:{}", err.to_string()).into_bytes(), + }; + *$result_len = result_byte.len(); + CString::from_vec_unchecked(result_byte).into_raw() + } + }}; +} + +/// Call kclvm service by C API. **Note that it is not thread safe.** +/// +/// # Parameters +/// +/// `serv`: [*mut kclvm_service] +/// The pointer of &\[[KclvmServiceImpl]] +/// +/// `call`: [*const c_char] +/// The C str of the name of the called service, +/// with the format "KclvmService.{MethodName}" +/// +/// `args`: [*const c_char] +/// Arguments of the call serialized as protobuf byte sequence, +/// refer to kclvm/spec/gpyrpc/gpyrpc.proto for the specific definitions of arguments +/// +/// # Returns +/// +/// result: [*const c_char] +/// Result of the call serialized as protobuf byte sequence +#[no_mangle] +pub extern "C" fn kclvm_service_call( + serv: *mut kclvm_service, + name: *const c_char, + args: *const c_char, + args_len: usize, +) -> *const c_char { + let mut _result_len = 0; + kclvm_service_call_with_length(serv, name, args, args_len, &mut _result_len) +} + +/// Call kclvm service by C API. **Note that it is not thread safe.** +/// +/// # Parameters +/// +/// `serv`: [*mut kclvm_service] +/// The pointer of &\[[KclvmServiceImpl]] +/// +/// `call`: [*const c_char] +/// The C str of the name of the called service, +/// with the format "KclvmService.{MethodName}" +/// +/// `args`: [*const c_char] +/// Arguments of the call serialized as protobuf byte sequence, +/// refer to kclvm/spec/gpyrpc/gpyrpc.proto for the specific definitions of arguments +/// +/// # Returns +/// +/// result: [*const c_char] +/// Result of the call serialized as protobuf byte sequence +#[no_mangle] +pub extern "C" fn kclvm_service_call_with_length( + serv: *mut kclvm_service, + name: *const c_char, + args: *const c_char, + args_len: usize, + result_len: *mut usize, +) -> *const c_char { + let result = std::panic::catch_unwind(|| { + let name = unsafe { std::ffi::CStr::from_ptr(name) }.to_str().unwrap(); + let call = kclvm_get_service_fn_ptr_by_name(name); + if call == 0 { + panic!("null fn ptr"); + } + let call = (&call as *const u64) as *const () + as *const fn( + serv: *mut kclvm_service, + args: *const c_char, + args_len: usize, + result_len: *mut usize, + ) -> *const c_char; + unsafe { (*call)(serv, args, args_len, result_len) } + }); + match result { + Ok(result) => result, + Err(panic_err) => { + let err_message = kclvm_error::err_to_str(panic_err); + + let c_string = std::ffi::CString::new(format!("ERROR:{}", err_message.as_str())) + .expect("CString::new failed"); + let ptr = c_string.into_raw(); + ptr as *const c_char + } + } +} + +pub(crate) fn kclvm_get_service_fn_ptr_by_name(name: &str) -> u64 { + match name { + "KclvmService.Ping" => ping as *const () as u64, + "KclvmService.GetVersion" => get_version as *const () as u64, + "KclvmService.ParseFile" => parse_file as *const () as u64, + "KclvmService.ParseProgram" => parse_program as *const () as u64, + "KclvmService.LoadPackage" => load_package as *const () as u64, + "KclvmService.ListOptions" => list_options as *const () as u64, + "KclvmService.ListVariables" => list_variables as *const () as u64, + "KclvmService.ExecProgram" => exec_program as *const () as u64, + #[cfg(feature = "llvm")] + "KclvmService.BuildProgram" => build_program as *const () as u64, + #[cfg(feature = "llvm")] + "KclvmService.ExecArtifact" => exec_artifact as *const () as u64, + "KclvmService.OverrideFile" => override_file as *const () as u64, + "KclvmService.GetSchemaTypeMapping" => get_schema_type_mapping as *const () as u64, + "KclvmService.GetSchemaTypeMappingUnderPath" => { + get_schema_type_mapping_under_path as *const () as u64 + } + "KclvmService.FormatCode" => format_code as *const () as u64, + "KclvmService.FormatPath" => format_path as *const () as u64, + "KclvmService.LintPath" => lint_path as *const () as u64, + "KclvmService.ValidateCode" => validate_code as *const () as u64, + "KclvmService.LoadSettingsFiles" => load_settings_files as *const () as u64, + "KclvmService.Rename" => rename as *const () as u64, + "KclvmService.RenameCode" => rename_code as *const () as u64, + "KclvmService.Test" => test as *const () as u64, + #[cfg(not(target_arch = "wasm32"))] + "KclvmService.UpdateDependencies" => update_dependencies as *const () as u64, + _ => panic!("unknown method name : {name}"), + } +} + +/// ping is used to test whether kclvm service is successfully imported +/// arguments and return results should be consistent +pub(crate) fn ping( + serv: *mut kclvm_service, + args: *const c_char, + args_len: usize, + result_len: *mut usize, +) -> *const c_char { + call!(serv, args, args_len, result_len, PingArgs, ping) +} + +/// get_version is used to get kclvm service version +pub(crate) fn get_version( + serv: *mut kclvm_service, + args: *const c_char, + args_len: usize, + result_len: *mut usize, +) -> *const c_char { + call!( + serv, + args, + args_len, + result_len, + GetVersionArgs, + get_version + ) +} + +/// parse_file provides users with the ability to parse kcl single file +/// +/// # Parameters +/// +/// `serv`: [*mut kclvm_service] +/// The pointer of &\[[KclvmServiceImpl]] +/// +/// +/// `args`: [*const c_char] +/// the items and compile parameters selected by the user in the KCL CLI +/// serialized as protobuf byte sequence +/// +/// # Returns +/// +/// result: [*const c_char] +/// Result of the call serialized as protobuf byte sequence +pub(crate) fn parse_file( + serv: *mut kclvm_service, + args: *const c_char, + args_len: usize, + result_len: *mut usize, +) -> *const c_char { + call!(serv, args, args_len, result_len, ParseFileArgs, parse_file) +} + +/// parse_program provides users with the ability to parse kcl program +/// +/// # Parameters +/// +/// `serv`: [*mut kclvm_service] +/// The pointer of &\[[KclvmServiceImpl]] +/// +/// +/// `args`: [*const c_char] +/// the items and compile parameters selected by the user in the KCL CLI +/// serialized as protobuf byte sequence +/// +/// # Returns +/// +/// result: [*const c_char] +/// Result of the call serialized as protobuf byte sequence +pub(crate) fn parse_program( + serv: *mut kclvm_service, + args: *const c_char, + args_len: usize, + result_len: *mut usize, +) -> *const c_char { + call!( + serv, + args, + args_len, + result_len, + ParseProgramArgs, + parse_program + ) +} + +/// load_package provides users with the ability to parse kcl program and sematic model +/// information including symbols, types, definitions, etc, +/// +/// # Parameters +/// +/// `serv`: [*mut kclvm_service] +/// The pointer of &\[[KclvmServiceImpl]] +/// +/// +/// `args`: [*const c_char] +/// the items and compile parameters selected by the user in the KCL CLI +/// serialized as protobuf byte sequence +/// +/// # Returns +/// +/// result: [*const c_char] +/// Result of the call serialized as protobuf byte sequence +pub(crate) fn load_package( + serv: *mut kclvm_service, + args: *const c_char, + args_len: usize, + result_len: *mut usize, +) -> *const c_char { + call!( + serv, + args, + args_len, + result_len, + LoadPackageArgs, + load_package + ) +} + +/// list_options provides users with the ability to parse kcl program and get all option +/// calling information. +/// +/// # Parameters +/// +/// `serv`: [*mut kclvm_service] +/// The pointer of &\[[KclvmServiceImpl]] +/// +/// +/// `args`: [*const c_char] +/// the items and compile parameters selected by the user in the KCL CLI +/// serialized as protobuf byte sequence +/// +/// # Returns +/// +/// result: [*const c_char] +/// Result of the call serialized as protobuf byte sequence +pub(crate) fn list_options( + serv: *mut kclvm_service, + args: *const c_char, + args_len: usize, + result_len: *mut usize, +) -> *const c_char { + call!( + serv, + args, + args_len, + result_len, + ParseProgramArgs, + list_options + ) +} + +/// list_variables provides users with the ability to parse kcl program and get all variables +/// calling information. +/// +/// # Parameters +/// +/// `serv`: [*mut kclvm_service] +/// The pointer of &\[[KclvmServiceImpl]] +/// +/// +/// `args`: [*const c_char] +/// the items and compile parameters selected by the user in the KCL CLI +/// serialized as protobuf byte sequence +/// +/// # Returns +/// +/// result: [*const c_char] +/// Result of the call serialized as protobuf byte sequence +pub(crate) fn list_variables( + serv: *mut kclvm_service, + args: *const c_char, + args_len: usize, + result_len: *mut usize, +) -> *const c_char { + call!( + serv, + args, + args_len, + result_len, + ListVariablesArgs, + list_variables + ) +} + +/// exec_program provides users with the ability to execute KCL code +/// +/// # Parameters +/// +/// `serv`: [*mut kclvm_service] +/// The pointer of &\[[KclvmServiceImpl]] +/// +/// +/// `args`: [*const c_char] +/// the items and compile parameters selected by the user in the KCL CLI +/// serialized as protobuf byte sequence +/// +/// # Returns +/// +/// result: [*const c_char] +/// Result of the call serialized as protobuf byte sequence +pub(crate) fn exec_program( + serv: *mut kclvm_service, + args: *const c_char, + args_len: usize, + result_len: *mut usize, +) -> *const c_char { + call!( + serv, + args, + args_len, + result_len, + ExecProgramArgs, + exec_program + ) +} + +/// build_program provides users with the ability to build the KCL program to an artifact. +/// +/// # Parameters +/// +/// `serv`: [*mut kclvm_service] +/// The pointer of &\[[KclvmServiceImpl]] +/// +/// +/// `args`: [*const c_char] +/// the items and compile parameters selected by the user in the KCL CLI +/// serialized as protobuf byte sequence +/// +/// # Returns +/// +/// result: [*const c_char] +/// Result of the call serialized as protobuf byte sequence +#[cfg(feature = "llvm")] +pub(crate) fn build_program( + serv: *mut kclvm_service, + args: *const c_char, + args_len: usize, + result_len: *mut usize, +) -> *const c_char { + call!( + serv, + args, + args_len, + result_len, + BuildProgramArgs, + build_program + ) +} + +/// build_program provides users with the ability to execute the KCL artifact. +/// +/// # Parameters +/// +/// `serv`: [*mut kclvm_service] +/// The pointer of &\[[KclvmServiceImpl]] +/// +/// +/// `args`: [*const c_char] +/// the items and compile parameters selected by the user in the KCL CLI +/// serialized as protobuf byte sequence +/// +/// # Returns +/// +/// result: [*const c_char] +/// Result of the call serialized as protobuf byte sequence +#[cfg(feature = "llvm")] +pub(crate) fn exec_artifact( + serv: *mut kclvm_service, + args: *const c_char, + args_len: usize, + result_len: *mut usize, +) -> *const c_char { + call!( + serv, + args, + args_len, + result_len, + ExecArtifactArgs, + exec_artifact + ) +} + +/// override_file enable users override existing KCL file with specific KCl code +/// +/// # Parameters +/// +/// `serv`: [*mut kclvm_service] +/// The pointer of &\[[KclvmServiceImpl]] +/// +/// +/// `args`: [*const c_char] +/// kcl file , override specs and import paths selected by the user in the KCL CLI +/// serialized as protobuf byte sequence +/// +/// # Returns +/// +/// result: [*const c_char] +/// Result of the call serialized as protobuf byte sequence +pub(crate) fn override_file( + serv: *mut kclvm_service, + args: *const c_char, + args_len: usize, + result_len: *mut usize, +) -> *const c_char { + call!( + serv, + args, + args_len, + result_len, + OverrideFileArgs, + override_file + ) +} + +/// Get schema types from a kcl file or code. +/// +/// # Parameters +/// file: [&str]. The kcl filename. +/// +/// code: [Option<&str>]. The kcl code string +/// +/// schema_name: [Option<&str>]. The schema name, when the schema name is empty, all schemas are returned. +pub(crate) fn get_schema_type_mapping( + serv: *mut kclvm_service, + args: *const c_char, + args_len: usize, + result_len: *mut usize, +) -> *const c_char { + call!( + serv, + args, + args_len, + result_len, + GetSchemaTypeMappingArgs, + get_schema_type_mapping + ) +} + +/// Get schema types under path +/// +/// # Parameters +/// file: [&str]. The kcl filename. +/// +/// code: [Option<&str>]. The kcl code string +/// +/// schema_name: [Option<&str>]. The schema name, when the schema name is empty, all schemas are returned. +pub(crate) fn get_schema_type_mapping_under_path( + serv: *mut kclvm_service, + args: *const c_char, + args_len: usize, + result_len: *mut usize, +) -> *const c_char { + call!( + serv, + args, + args_len, + result_len, + GetSchemaTypeMappingArgs, + get_schema_type_mapping_under_path + ) +} + +/// Service for formatting a code source and returns the formatted source and +/// whether the source is changed. +pub(crate) fn format_code( + serv: *mut kclvm_service, + args: *const c_char, + args_len: usize, + result_len: *mut usize, +) -> *const c_char { + call!( + serv, + args, + args_len, + result_len, + FormatCodeArgs, + format_code + ) +} + +/// Service for formatting kcl file or directory path contains kcl files and +/// returns the changed file paths. +pub(crate) fn format_path( + serv: *mut kclvm_service, + args: *const c_char, + args_len: usize, + result_len: *mut usize, +) -> *const c_char { + call!( + serv, + args, + args_len, + result_len, + FormatPathArgs, + format_path + ) +} + +/// Service for KCL Lint API, check a set of files, skips execute, +/// returns error message including errors and warnings. +pub(crate) fn lint_path( + serv: *mut kclvm_service, + args: *const c_char, + args_len: usize, + result_len: *mut usize, +) -> *const c_char { + call!(serv, args, args_len, result_len, LintPathArgs, lint_path) +} + +/// Service for validating the data string using the schema code string, when the parameter +/// `schema` is omitted, use the first schema appeared in the kcl code. +pub(crate) fn validate_code( + serv: *mut kclvm_service, + args: *const c_char, + args_len: usize, + result_len: *mut usize, +) -> *const c_char { + call!( + serv, + args, + args_len, + result_len, + ValidateCodeArgs, + validate_code + ) +} + +/// Service for building setting file config from args. +pub(crate) fn load_settings_files( + serv: *mut kclvm_service, + args: *const c_char, + args_len: usize, + result_len: *mut usize, +) -> *const c_char { + call!( + serv, + args, + args_len, + result_len, + LoadSettingsFilesArgs, + load_settings_files + ) +} + +/// Service for renaming all the occurrences of the target symbol in the files. This API will rewrite files if they contain symbols to be renamed. +/// return the file paths got changed. +pub(crate) fn rename( + serv: *mut kclvm_service, + args: *const c_char, + args_len: usize, + result_len: *mut usize, +) -> *const c_char { + call!(serv, args, args_len, result_len, RenameArgs, rename) +} + +/// Service for renaming all the occurrences of the target symbol in the code. This API won't rewrite files but return the modified code if any code has been changed. +/// return the changed code. +pub(crate) fn rename_code( + serv: *mut kclvm_service, + args: *const c_char, + args_len: usize, + result_len: *mut usize, +) -> *const c_char { + call!( + serv, + args, + args_len, + result_len, + RenameCodeArgs, + rename_code + ) +} + +/// Service for the testing tool. +pub(crate) fn test( + serv: *mut kclvm_service, + args: *const c_char, + args_len: usize, + result_len: *mut usize, +) -> *const c_char { + call!(serv, args, args_len, result_len, TestArgs, test) +} + +#[cfg(not(target_arch = "wasm32"))] +/// Service for the dependencies updating +/// calling information. +/// +/// # Parameters +/// +/// `serv`: [*mut kclvm_service] +/// The pointer of &\[[KclvmServiceImpl]] +/// +/// +/// `args`: [*const c_char] +/// the items and compile parameters selected by the user in the KCL CLI +/// serialized as protobuf byte sequence +/// +/// # Returns +/// +/// result: [*const c_char] +/// Result of the call serialized as protobuf byte sequence +pub(crate) fn update_dependencies( + serv: *mut kclvm_service, + args: *const c_char, + args_len: usize, + result_len: *mut usize, +) -> *const c_char { + call!( + serv, + args, + args_len, + result_len, + UpdateDependenciesArgs, + update_dependencies + ) +} diff --git a/kclvm/api/src/service/into.rs b/kclvm/api/src/service/into.rs new file mode 100644 index 000000000..fb179a43a --- /dev/null +++ b/kclvm/api/src/service/into.rs @@ -0,0 +1,138 @@ +use crate::gpyrpc::{ + CliConfig, Error, KeyValuePair, LoadSettingsFilesResult, Message, Position, Scope, ScopeIndex, + Symbol, SymbolIndex, +}; +use crate::service::ty::kcl_ty_to_pb_ty; +use kclvm_config::settings::SettingsFile; +use kclvm_error::Diagnostic; +use kclvm_loader::{ScopeInfo, SymbolInfo}; +use kclvm_sema::core::{scope::ScopeRef, symbol::SymbolRef}; + +pub(crate) trait IntoLoadSettingsFiles { + /// Convert self into the LoadSettingsFiles structure. + fn into_load_settings_files(self, files: &[String]) -> LoadSettingsFilesResult; +} + +pub(crate) trait IntoError { + fn into_error(self) -> Error; +} + +pub(crate) trait IntoSymbolIndex { + fn into_symbol_index(self) -> SymbolIndex; +} + +pub(crate) trait IntoSymbol { + fn into_symbol(self) -> Symbol; +} + +pub(crate) trait IntoScope { + fn into_scope(self) -> Scope; +} + +pub(crate) trait IntoScopeIndex { + fn into_scope_index(self) -> ScopeIndex; +} + +impl IntoLoadSettingsFiles for SettingsFile { + fn into_load_settings_files(self, files: &[String]) -> LoadSettingsFilesResult { + LoadSettingsFilesResult { + kcl_cli_configs: self.kcl_cli_configs.map(|config| CliConfig { + files: files.to_vec(), + output: config.output.unwrap_or_default(), + overrides: config.overrides.unwrap_or_default(), + path_selector: config.path_selector.unwrap_or_default(), + strict_range_check: config.strict_range_check.unwrap_or_default(), + disable_none: config.disable_none.unwrap_or_default(), + verbose: config.verbose.unwrap_or_default() as i64, + debug: config.debug.unwrap_or_default(), + sort_keys: config.sort_keys.unwrap_or_default(), + show_hidden: config.show_hidden.unwrap_or_default(), + fast_eval: config.fast_eval.unwrap_or_default(), + include_schema_type_path: config.include_schema_type_path.unwrap_or_default(), + }), + kcl_options: match self.kcl_options { + Some(opts) => opts + .iter() + .map(|o| KeyValuePair { + key: o.key.to_string(), + value: o.value.to_string(), + }) + .collect(), + None => vec![], + }, + } + } +} + +impl IntoError for Diagnostic { + fn into_error(self) -> Error { + Error { + level: self.level.to_string(), + code: format!( + "{:?}", + self.code.unwrap_or(kclvm_error::DiagnosticId::Error( + kclvm_error::ErrorKind::InvalidSyntax, + )) + ), + messages: self + .messages + .iter() + .map(|m| Message { + msg: m.message.clone(), + pos: Some(Position { + filename: m.range.0.filename.clone(), + line: m.range.0.line as i64, + column: m.range.0.column.unwrap_or_default() as i64, + }), + }) + .collect(), + } + } +} + +impl IntoSymbolIndex for SymbolRef { + fn into_symbol_index(self) -> SymbolIndex { + let (index, generation) = self.get_id().into_raw_parts(); + SymbolIndex { + i: index as u64, + g: generation, + kind: format!("{:?}", self.get_kind()), + } + } +} + +impl IntoScopeIndex for ScopeRef { + fn into_scope_index(self) -> ScopeIndex { + let (index, generation) = self.get_id().into_raw_parts(); + ScopeIndex { + i: index as u64, + g: generation, + kind: format!("{:?}", self.get_kind()), + } + } +} + +impl IntoSymbol for SymbolInfo { + fn into_symbol(self) -> Symbol { + Symbol { + ty: Some(kcl_ty_to_pb_ty(&self.ty)), + name: self.name, + owner: self.owner.map(|o| o.into_symbol_index()), + def: self.def.map(|d| d.into_symbol_index()), + attrs: self.attrs.iter().map(|a| a.into_symbol_index()).collect(), + is_global: self.is_global, + } + } +} + +impl IntoScope for ScopeInfo { + fn into_scope(self) -> Scope { + Scope { + kind: format!("{:?}", self.kind), + parent: self.parent.map(|o| o.into_scope_index()), + owner: self.owner.map(|o| o.into_symbol_index()), + children: self.children.iter().map(|a| a.into_scope_index()).collect(), + defs: self.defs.iter().map(|a| a.into_symbol_index()).collect(), + } + } +} diff --git a/kclvm/api/src/service/jsonrpc.rs b/kclvm/api/src/service/jsonrpc.rs new file mode 100644 index 000000000..00f63c15f --- /dev/null +++ b/kclvm/api/src/service/jsonrpc.rs @@ -0,0 +1,284 @@ +use crate::gpyrpc::*; +use crate::service::service_impl::KclvmServiceImpl; +use core::fmt::Display; +use jsonrpc_stdio_server::jsonrpc_core::{Error, ErrorCode, IoHandler, Params}; +use jsonrpc_stdio_server::ServerBuilder; +use serde::Serialize; +const KCLVM_SERVER_ERROR_CODE: i64 = 0x4B434C; // the ASCII code of "KCL" + +/// Start a json rpc server via Stdin/Stdout +#[tokio::main] +pub async fn start_stdio_server() -> Result<(), anyhow::Error> { + let mut io = IoHandler::default(); + // KclvmService + register_kclvm_service(&mut io); + // BuiltinService + register_builtin_service(&mut io); + let server = ServerBuilder::new(io).build(); + server.await; + Ok(()) +} + +macro_rules! catch { + ($serv:expr, $args:expr, $serv_name:ident) => {{ + let prev_hook = std::panic::take_hook(); + + // disable print panic info + std::panic::set_hook(Box::new(|_info| {})); + let result = std::panic::catch_unwind(|| to_json_result(&$serv.$serv_name(&$args))); + std::panic::set_hook(prev_hook); + match result { + Ok(result) => result, + Err(panic_err) => { + let err_message = kclvm_error::err_to_str(panic_err); + Err(Error { + code: ErrorCode::from(KCLVM_SERVER_ERROR_CODE), + message: err_message, + data: None, + }) + } + } + }}; +} + +/// Transform the [`Result`] into [`Result`] +#[inline] +fn to_json_result(val: &Result) -> Result +where + V: Serialize, + E: Display, +{ + match val { + Ok(val) => Ok(serde_json::to_value(val).unwrap()), + Err(err) => Err(Error { + code: ErrorCode::from(KCLVM_SERVER_ERROR_CODE), + message: err.to_string(), + data: None, + }), + } +} + +fn register_kclvm_service(io: &mut IoHandler) { + io.add_method("KclvmService.Ping", |params: Params| { + let kclvm_service_impl = KclvmServiceImpl::default(); + let args: PingArgs = match params.parse() { + Ok(val) => val, + Err(err) => return futures::future::ready(Err(err)), + }; + futures::future::ready(catch!(kclvm_service_impl, args, ping)) + }); + io.add_method("KclvmService.GetVersion", |params: Params| { + let kclvm_service_impl = KclvmServiceImpl::default(); + let args: GetVersionArgs = match params.parse() { + Ok(val) => val, + Err(err) => return futures::future::ready(Err(err)), + }; + futures::future::ready(catch!(kclvm_service_impl, args, get_version)) + }); + io.add_method("KclvmService.ParseFile", |params: Params| { + let kclvm_service_impl = KclvmServiceImpl::default(); + let args: ParseFileArgs = match params.parse() { + Ok(val) => val, + Err(err) => return futures::future::ready(Err(err)), + }; + futures::future::ready(catch!(kclvm_service_impl, args, parse_file)) + }); + io.add_method("KclvmService.ParseProgram", |params: Params| { + let kclvm_service_impl = KclvmServiceImpl::default(); + let args: ParseProgramArgs = match params.parse() { + Ok(val) => val, + Err(err) => return futures::future::ready(Err(err)), + }; + futures::future::ready(catch!(kclvm_service_impl, args, parse_program)) + }); + io.add_method("KclvmService.LoadPackage", |params: Params| { + let kclvm_service_impl = KclvmServiceImpl::default(); + let args: LoadPackageArgs = match params.parse() { + Ok(val) => val, + Err(err) => return futures::future::ready(Err(err)), + }; + futures::future::ready(catch!(kclvm_service_impl, args, load_package)) + }); + io.add_method("KclvmService.ListOptions", |params: Params| { + let kclvm_service_impl = KclvmServiceImpl::default(); + let args: ParseProgramArgs = match params.parse() { + Ok(val) => val, + Err(err) => return futures::future::ready(Err(err)), + }; + futures::future::ready(catch!(kclvm_service_impl, args, list_options)) + }); + io.add_method("KclvmService.ListVariables", |params: Params| { + let kclvm_service_impl = KclvmServiceImpl::default(); + let args: ListVariablesArgs = match params.parse() { + Ok(val) => val, + Err(err) => return futures::future::ready(Err(err)), + }; + futures::future::ready(catch!(kclvm_service_impl, args, list_variables)) + }); + io.add_method("KclvmService.ExecProgram", |params: Params| { + let kclvm_service_impl = KclvmServiceImpl::default(); + let args: ExecProgramArgs = match params.parse() { + Ok(val) => val, + Err(err) => return futures::future::ready(Err(err)), + }; + futures::future::ready(catch!(kclvm_service_impl, args, exec_program)) + }); + #[cfg(feature = "llvm")] + io.add_method("KclvmService.BuildProgram", |params: Params| { + let kclvm_service_impl = KclvmServiceImpl::default(); + let args: BuildProgramArgs = match params.parse() { + Ok(val) => val, + Err(err) => return futures::future::ready(Err(err)), + }; + futures::future::ready(catch!(kclvm_service_impl, args, build_program)) + }); + #[cfg(feature = "llvm")] + io.add_method("KclvmService.ExecArtifact", |params: Params| { + let kclvm_service_impl = KclvmServiceImpl::default(); + let args: ExecArtifactArgs = match params.parse() { + Ok(val) => val, + Err(err) => return futures::future::ready(Err(err)), + }; + futures::future::ready(catch!(kclvm_service_impl, args, exec_artifact)) + }); + io.add_method("KclvmService.OverrideFile", |params: Params| { + let kclvm_service_impl = KclvmServiceImpl::default(); + let args: OverrideFileArgs = match params.parse() { + Ok(val) => val, + Err(err) => return futures::future::ready(Err(err)), + }; + futures::future::ready(catch!(kclvm_service_impl, args, override_file)) + }); + io.add_method("KclvmService.GetSchemaTypeMapping", |params: Params| { + let kclvm_service_impl = KclvmServiceImpl::default(); + let args: GetSchemaTypeMappingArgs = match params.parse() { + Ok(val) => val, + Err(err) => return futures::future::ready(Err(err)), + }; + futures::future::ready(catch!(kclvm_service_impl, args, get_schema_type_mapping)) + }); + io.add_method( + "KclvmService.GetSchemaTypeMappingUnderPath", + |params: Params| { + let kclvm_service_impl = KclvmServiceImpl::default(); + let args: GetSchemaTypeMappingArgs = match params.parse() { + Ok(val) => val, + Err(err) => return futures::future::ready(Err(err)), + }; + futures::future::ready(catch!( + kclvm_service_impl, + args, + get_schema_type_mapping_under_path + )) + }, + ); + io.add_method("KclvmService.FormatCode", |params: Params| { + let kclvm_service_impl = KclvmServiceImpl::default(); + let args: FormatCodeArgs = match params.parse() { + Ok(val) => val, + Err(err) => return futures::future::ready(Err(err)), + }; + futures::future::ready(catch!(kclvm_service_impl, args, format_code)) + }); + io.add_method("KclvmService.FormatPath", |params: Params| { + let kclvm_service_impl = KclvmServiceImpl::default(); + let args: FormatPathArgs = match params.parse() { + Ok(val) => val, + Err(err) => return futures::future::ready(Err(err)), + }; + futures::future::ready(catch!(kclvm_service_impl, args, format_path)) + }); + io.add_method("KclvmService.LintPath", |params: Params| { + let kclvm_service_impl = KclvmServiceImpl::default(); + let args: LintPathArgs = match params.parse() { + Ok(val) => val, + Err(err) => return futures::future::ready(Err(err)), + }; + futures::future::ready(catch!(kclvm_service_impl, args, lint_path)) + }); + io.add_method("KclvmService.ValidateCode", |params: Params| { + let kclvm_service_impl = KclvmServiceImpl::default(); + let args: ValidateCodeArgs = match params.parse() { + Ok(val) => val, + Err(err) => return futures::future::ready(Err(err)), + }; + futures::future::ready(catch!(kclvm_service_impl, args, validate_code)) + }); + io.add_method("KclvmService.LoadSettingsFiles", |params: Params| { + let kclvm_service_impl = KclvmServiceImpl::default(); + let args: LoadSettingsFilesArgs = match params.parse() { + Ok(val) => val, + Err(err) => return futures::future::ready(Err(err)), + }; + futures::future::ready(catch!(kclvm_service_impl, args, load_settings_files)) + }); + io.add_method("KclvmService.Rename", |params: Params| { + let kclvm_service_impl = KclvmServiceImpl::default(); + let args: RenameArgs = match params.parse() { + Ok(val) => val, + Err(err) => return futures::future::ready(Err(err)), + }; + futures::future::ready(catch!(kclvm_service_impl, args, rename)) + }); + io.add_method("KclvmService.RenameCode", |params: Params| { + let kclvm_service_impl = KclvmServiceImpl::default(); + let args: RenameCodeArgs = match params.parse() { + Ok(val) => val, + Err(err) => return futures::future::ready(Err(err)), + }; + futures::future::ready(catch!(kclvm_service_impl, args, rename_code)) + }); + io.add_method("KclvmService.Test", |params: Params| { + let kclvm_service_impl = KclvmServiceImpl::default(); + let args: TestArgs = match params.parse() { + Ok(val) => val, + Err(err) => return futures::future::ready(Err(err)), + }; + futures::future::ready(catch!(kclvm_service_impl, args, test)) + }); + io.add_method("KclvmService.UpdateDependencies", |params: Params| { + let kclvm_service_impl = KclvmServiceImpl::default(); + let args: UpdateDependenciesArgs = match params.parse() { + Ok(val) => val, + Err(err) => return futures::future::ready(Err(err)), + }; + futures::future::ready(catch!(kclvm_service_impl, args, update_dependencies)) + }); +} + +fn register_builtin_service(io: &mut IoHandler) { + io.add_sync_method("BuiltinService.Ping", |params: Params| { + let args: PingArgs = params.parse()?; + let result = PingResult { value: args.value }; + Ok(serde_json::to_value(result).unwrap()) + }); + io.add_sync_method("BuiltinService.ListMethod", |_params: Params| { + let result = ListMethodResult { + method_name_list: vec![ + "KclvmService.Ping".to_owned(), + "KclvmService.GetVersion".to_owned(), + "KclvmService.ParseFile".to_owned(), + "KclvmService.ParseProgram".to_owned(), + "KclvmService.ExecProgram".to_owned(), + "KclvmService.BuildProgram".to_owned(), + "KclvmService.ExecArtifact".to_owned(), + "KclvmService.OverrideFile".to_owned(), + "KclvmService.GetSchemaType".to_owned(), + "KclvmService.GetFullSchemaType".to_owned(), + "KclvmService.GetSchemaTypeMapping".to_owned(), + "KclvmService.FormatCode".to_owned(), + "KclvmService.FormatPath".to_owned(), + "KclvmService.LintPath".to_owned(), + "KclvmService.ValidateCode".to_owned(), + "KclvmService.LoadSettingsFiles".to_owned(), + "KclvmService.Rename".to_owned(), + "KclvmService.RenameCode".to_owned(), + "KclvmService.Test".to_owned(), + "KclvmService.UpdateDependencies".to_owned(), + "BuiltinService.Ping".to_owned(), + "BuiltinService.PingListMethod".to_owned(), + ], + }; + Ok(serde_json::to_value(result).unwrap()) + }); +} diff --git a/kclvm/api/src/service/mod.rs b/kclvm/api/src/service/mod.rs new file mode 100644 index 000000000..1cea8033c --- /dev/null +++ b/kclvm/api/src/service/mod.rs @@ -0,0 +1,9 @@ +pub mod capi; +pub(crate) mod into; +#[cfg(not(target_arch = "wasm32"))] +pub mod jsonrpc; +pub mod service_impl; +pub(crate) mod ty; +pub(crate) mod util; + +pub use service_impl::KclvmServiceImpl; diff --git a/kclvm/api/src/service/service_impl.rs b/kclvm/api/src/service/service_impl.rs new file mode 100644 index 000000000..a53716bbd --- /dev/null +++ b/kclvm/api/src/service/service_impl.rs @@ -0,0 +1,1129 @@ +use std::collections::HashMap; +use std::io::Write; +use std::path::PathBuf; +use std::string::String; + +use crate::gpyrpc::{self, *}; + +use kcl_language_server::rename; +use kclvm_ast::ast::SerializeProgram; +use kclvm_config::settings::build_settings_pathbuf; +use kclvm_loader::option::list_options; +use kclvm_loader::{load_packages_with_cache, LoadPackageOptions}; +use kclvm_parser::entry::{canonicalize_input_file, get_normalized_k_files_from_paths}; +use kclvm_parser::load_program; +use kclvm_parser::parse_single_file; +use kclvm_parser::KCLModuleCache; +use kclvm_parser::LoadProgramOptions; +use kclvm_parser::ParseSessionRef; +use kclvm_query::override_file; +use kclvm_query::query::CompilationOptions; +use kclvm_query::query::{get_full_schema_type, get_full_schema_type_under_path}; +use kclvm_query::selector::{list_variables, ListOptions}; +use kclvm_query::GetSchemaOption; +use kclvm_runner::exec_program; +#[cfg(feature = "llvm")] +use kclvm_runner::{build_program, exec_artifact}; +use kclvm_sema::core::global_state::GlobalState; +use kclvm_sema::resolver::scope::KCLScopeCache; +use kclvm_sema::resolver::Options; +use kclvm_tools::format::{format, format_source, FormatOptions}; +use kclvm_tools::lint::lint_files; +use kclvm_tools::testing; +use kclvm_tools::testing::TestRun; +use kclvm_tools::vet::validator::validate; +use kclvm_tools::vet::validator::LoaderKind; +use kclvm_tools::vet::validator::ValidateOption; +use tempfile::NamedTempFile; + +use super::into::*; +use super::ty::kcl_schema_ty_to_pb_ty; +use super::util::{transform_exec_para, transform_str_para}; + +/// Specific implementation of calling service +#[derive(Debug, Clone, Default)] +pub struct KclvmServiceImpl { + pub plugin_agent: u64, +} + +impl From<&kclvm_query::selector::Variable> for Variable { + fn from(var: &kclvm_query::selector::Variable) -> Self { + Variable { + value: var.value.to_string(), + type_name: var.type_name.to_string(), + op_sym: var.op_sym.to_string(), + list_items: var.list_items.iter().map(|item| item.into()).collect(), + dict_entries: var + .dict_entries + .iter() + .map(|entry| MapEntry { + key: entry.key.to_string(), + value: Some((&entry.value).into()), + }) + .collect(), + } + } +} + +impl KclvmServiceImpl { + /// Ping KclvmService, return the same value as the parameter + /// + /// # Examples + /// + /// ``` + /// use kclvm_api::service::service_impl::KclvmServiceImpl; + /// use kclvm_api::gpyrpc::*; + /// let serv = KclvmServiceImpl::default(); + /// let args = &PingArgs { + /// value: "hello".to_string(), + /// ..Default::default() + /// }; + /// let ping_result = serv.ping(args).unwrap(); + /// assert_eq!(ping_result.value, "hello".to_string()); + /// ``` + /// + pub fn ping(&self, args: &PingArgs) -> anyhow::Result { + Ok(PingResult { + value: (args.value.clone()), + }) + } + + /// GetVersion KclvmService, return the kclvm service version information + /// + /// # Examples + /// + /// ``` + /// use kclvm_api::service::service_impl::KclvmServiceImpl; + /// use kclvm_api::gpyrpc::*; + /// let serv = KclvmServiceImpl::default(); + /// let args = &GetVersionArgs { + /// ..Default::default() + /// }; + /// let get_version_result = serv.get_version(args).unwrap(); + /// assert!(get_version_result.version_info.to_string().contains("Version"), "{0}", get_version_result.version_info); + /// ``` + /// + pub fn get_version(&self, _args: &GetVersionArgs) -> anyhow::Result { + Ok(GetVersionResult { + version: kclvm_version::VERSION.to_string(), + checksum: kclvm_version::CHECK_SUM.to_string(), + git_sha: kclvm_version::GIT_SHA.to_string(), + version_info: kclvm_version::get_version_info(), + }) + } + + /// Parse KCL program with entry files. + /// + /// # Examples + /// + /// ``` + /// use kclvm_api::service::service_impl::KclvmServiceImpl; + /// use kclvm_api::gpyrpc::*; + /// use std::path::Path; + /// // File case + /// let serv = KclvmServiceImpl::default(); + /// let args = &ParseProgramArgs { + /// paths: vec![Path::new(".").join("src").join("testdata").join("test.k").canonicalize().unwrap().display().to_string()], + /// ..Default::default() + /// }; + /// let result = serv.parse_program(args).unwrap(); + /// assert_eq!(result.errors.len(), 0); + /// assert_eq!(result.paths.len(), 1); + /// ``` + pub fn parse_program(&self, args: &ParseProgramArgs) -> anyhow::Result { + let sess = ParseSessionRef::default(); + let mut package_maps = HashMap::new(); + for p in &args.external_pkgs { + package_maps.insert(p.pkg_name.to_string(), p.pkg_path.to_string()); + } + let paths: Vec<&str> = args.paths.iter().map(|p| p.as_str()).collect(); + let result = load_program( + sess, + &paths, + Some(LoadProgramOptions { + k_code_list: args.sources.clone(), + package_maps, + load_plugins: true, + ..Default::default() + }), + Some(KCLModuleCache::default()), + )?; + let serialize_program: SerializeProgram = result.program.into(); + let ast_json = serde_json::to_string(&serialize_program)?; + + Ok(ParseProgramResult { + ast_json, + paths: result + .paths + .iter() + .map(|p| p.to_str().unwrap().to_string()) + .collect(), + errors: result.errors.into_iter().map(|e| e.into_error()).collect(), + }) + } + + /// Parse KCL single file to Module AST JSON string with import + /// dependencies and parse errors. + /// + /// # Examples + /// + /// ``` + /// use kclvm_api::service::service_impl::KclvmServiceImpl; + /// use kclvm_api::gpyrpc::*; + /// use std::path::Path; + /// // File case + /// let serv = KclvmServiceImpl::default(); + /// let args = &ParseFileArgs { + /// path: Path::new(".").join("src").join("testdata").join("parse").join("main.k").canonicalize().unwrap().display().to_string(), + /// ..Default::default() + /// }; + /// let result = serv.parse_file(args).unwrap(); + /// assert_eq!(result.errors.len(), 0); + /// assert_eq!(result.deps.len(), 2); + /// ``` + pub fn parse_file(&self, args: &ParseFileArgs) -> anyhow::Result { + let file = canonicalize_input_file(&args.path, ""); + let result = parse_single_file(&file, transform_str_para(&args.source))?; + let ast_json = serde_json::to_string(&result.module)?; + + Ok(ParseFileResult { + ast_json, + deps: result + .deps + .iter() + .map(|p| p.get_path().to_str().unwrap().to_string()) + .collect(), + errors: result.errors.into_iter().map(|e| e.into_error()).collect(), + }) + } + + /// load_package provides users with the ability to parse kcl program and sematic model + /// information including symbols, types, definitions, etc. + /// + /// # Examples + /// + /// ``` + /// use kclvm_api::service::service_impl::KclvmServiceImpl; + /// use kclvm_api::gpyrpc::*; + /// use std::path::Path; + /// use kclvm_utils::path::PathPrefix; + /// + /// let serv = KclvmServiceImpl::default(); + /// let args = &LoadPackageArgs { + /// parse_args: Some(ParseProgramArgs { + /// paths: vec![Path::new(".").join("src").join("testdata").join("parse").join("main.k").canonicalize().unwrap().display().to_string().adjust_canonicalization()], + /// ..Default::default() + /// }), + /// resolve_ast: true, + /// ..Default::default() + /// }; + /// let result = serv.load_package(args).unwrap(); + /// assert_eq!(result.paths.len(), 3); + /// assert_eq!(result.parse_errors.len(), 0); + /// assert_eq!(result.type_errors.len(), 0); + /// assert_eq!(result.symbols.len(), 12); + /// assert_eq!(result.scopes.len(), 3); + /// assert_eq!(result.node_symbol_map.len(), 183); + /// assert_eq!(result.symbol_node_map.len(), 183); + /// assert_eq!(result.fully_qualified_name_map.len(), 193); + /// assert_eq!(result.pkg_scope_map.len(), 3); + /// ``` + #[inline] + pub fn load_package(&self, args: &LoadPackageArgs) -> anyhow::Result { + self.load_package_with_cache(args, KCLModuleCache::default(), KCLScopeCache::default()) + } + + /// load_package_with_cache provides users with the ability to parse kcl program and sematic model + /// information including symbols, types, definitions, etc. + pub fn load_package_with_cache( + &self, + args: &LoadPackageArgs, + module_cache: KCLModuleCache, + scope_cache: KCLScopeCache, + ) -> anyhow::Result { + let mut package_maps = HashMap::new(); + let parse_args = args.parse_args.clone().unwrap_or_default(); + for p in &parse_args.external_pkgs { + package_maps.insert(p.pkg_name.to_string(), p.pkg_path.to_string()); + } + let packages = load_packages_with_cache( + &LoadPackageOptions { + paths: parse_args.paths, + load_opts: Some(LoadProgramOptions { + k_code_list: parse_args.sources.clone(), + package_maps, + load_plugins: true, + ..Default::default() + }), + resolve_ast: args.resolve_ast, + load_builtin: args.load_builtin, + }, + module_cache, + scope_cache, + &mut GlobalState::default(), + )?; + if args.with_ast_index { + // Thread local options + kclvm_ast::ast::set_should_serialize_id(true); + } + let serialize_program: SerializeProgram = packages.program.into(); + let program_json = serde_json::to_string(&serialize_program)?; + let mut node_symbol_map = HashMap::new(); + let mut symbol_node_map = HashMap::new(); + let mut fully_qualified_name_map = HashMap::new(); + let mut pkg_scope_map = HashMap::new(); + let mut symbols = HashMap::new(); + let mut scopes = HashMap::new(); + // Build sematic mappings + for (k, s) in packages.node_symbol_map { + node_symbol_map.insert(k.id.to_string(), s.into_symbol_index()); + } + for (s, k) in packages.symbol_node_map { + let symbol_index_string = serde_json::to_string(&s)?; + symbol_node_map.insert(symbol_index_string, k.id.to_string()); + } + for (s, k) in packages.fully_qualified_name_map { + fully_qualified_name_map.insert(s, k.into_symbol_index()); + } + for (k, s) in packages.pkg_scope_map { + pkg_scope_map.insert(k, s.into_scope_index()); + } + for (k, s) in packages.symbols { + let symbol_index_string = serde_json::to_string(&k)?; + symbols.insert(symbol_index_string, s.into_symbol()); + } + for (k, s) in packages.scopes { + let scope_index_string = serde_json::to_string(&k)?; + scopes.insert(scope_index_string, s.into_scope()); + } + Ok(LoadPackageResult { + program: program_json, + paths: packages + .paths + .iter() + .map(|p| p.to_str().unwrap().to_string()) + .collect(), + node_symbol_map, + symbol_node_map, + fully_qualified_name_map, + pkg_scope_map, + symbols, + scopes, + parse_errors: packages + .parse_errors + .into_iter() + .map(|e| e.into_error()) + .collect(), + type_errors: packages + .type_errors + .into_iter() + .map(|e| e.into_error()) + .collect(), + }) + } + + /// list_options provides users with the ability to parse kcl program and get all option + /// calling information. + /// + /// # Examples + /// + /// ``` + /// use kclvm_api::service::service_impl::KclvmServiceImpl; + /// use kclvm_api::gpyrpc::*; + /// use std::path::Path; + /// + /// let serv = KclvmServiceImpl::default(); + /// let args = &ParseProgramArgs { + /// paths: vec![Path::new(".").join("src").join("testdata").join("option").join("main.k").canonicalize().unwrap().display().to_string()], + /// ..Default::default() + /// }; + /// let result = serv.list_options(args).unwrap(); + /// assert_eq!(result.options.len(), 3); + /// ``` + pub fn list_options(&self, args: &ParseProgramArgs) -> anyhow::Result { + let mut package_maps = HashMap::new(); + for p in &args.external_pkgs { + package_maps.insert(p.pkg_name.to_string(), p.pkg_path.to_string()); + } + let options = list_options(&LoadPackageOptions { + paths: args.paths.clone(), + load_opts: Some(LoadProgramOptions { + k_code_list: args.sources.clone(), + package_maps, + load_plugins: true, + ..Default::default() + }), + resolve_ast: true, + load_builtin: false, + })?; + Ok(ListOptionsResult { + options: options + .iter() + .map(|o| OptionHelp { + name: o.name.clone(), + r#type: o.ty.clone(), + required: o.required.clone(), + default_value: o.default_value.clone(), + help: o.help.clone(), + }) + .collect(), + }) + } + + /// list_variables provides users with the ability to parse kcl program and get all variables by specs. + /// + /// # Examples + /// + /// ``` + /// use kclvm_api::service::service_impl::KclvmServiceImpl; + /// use kclvm_api::gpyrpc::*; + /// use std::path::Path; + /// + /// let serv = KclvmServiceImpl::default(); + /// let args = &ListVariablesArgs { + /// files: vec![Path::new(".").join("src").join("testdata").join("variables").join("main.k").canonicalize().unwrap().display().to_string()], + /// specs: vec!["a".to_string()], + /// options: None, + /// }; + /// let result = serv.list_variables(args).unwrap(); + /// assert_eq!(result.variables.len(), 1); + /// assert_eq!(result.variables.get("a").unwrap().variables.get(0).unwrap().value, "1"); + /// ``` + pub fn list_variables(&self, args: &ListVariablesArgs) -> anyhow::Result { + let k_files = args.files.clone(); + let specs = args.specs.clone(); + + let select_res; + if let Some(opts) = args.options.as_ref() { + let list_opts = ListOptions { + merge_program: opts.merge_program, + }; + select_res = list_variables(k_files, specs, Some(&list_opts))?; + } else { + select_res = list_variables(k_files, specs, None)?; + } + + let variables: HashMap> = select_res + .variables + .iter() + .map(|(key, vars)| { + let new_vars = vars.iter().map(|v| v.into()).collect(); + (key.clone(), new_vars) + }) + .collect(); + + let unsupported_codes: Vec = select_res + .unsupported + .iter() + .map(|code| code.code.to_string()) + .collect(); + + let variable_list: HashMap = variables + .into_iter() + .map(|(key, vars)| (key, VariableList { variables: vars })) + .collect(); + + return Ok(ListVariablesResult { + variables: variable_list, + unsupported_codes, + parse_errors: select_res + .parse_errors + .into_iter() + .map(|e| e.into_error()) + .collect(), + }); + } + + /// Execute KCL file with arguments and return the JSON/YAML result. + /// + /// **Note that it is not thread safe when the llvm feature is enabled.** + /// + /// # Examples + /// + /// ``` + /// use kclvm_api::service::service_impl::KclvmServiceImpl; + /// use kclvm_api::gpyrpc::*; + /// use std::path::Path; + /// // File case + /// let serv = KclvmServiceImpl::default(); + /// let args = &ExecProgramArgs { + /// work_dir: Path::new(".").join("src").join("testdata").canonicalize().unwrap().display().to_string(), + /// k_filename_list: vec!["test.k".to_string()], + /// ..Default::default() + /// }; + /// let exec_result = serv.exec_program(args).unwrap(); + /// assert_eq!(exec_result.yaml_result, "alice:\n age: 18"); + /// + /// // Code case + /// let args = &ExecProgramArgs { + /// k_filename_list: vec!["file.k".to_string()], + /// k_code_list: vec!["alice = {age = 18}".to_string()], + /// ..Default::default() + /// }; + /// let exec_result = serv.exec_program(args).unwrap(); + /// assert_eq!(exec_result.yaml_result, "alice:\n age: 18"); + /// + /// // Error case + /// let args = &ExecProgramArgs { + /// k_filename_list: vec!["invalid_file.k".to_string()], + /// ..Default::default() + /// }; + /// let error = serv.exec_program(args).unwrap_err(); + /// assert!(error.to_string().contains("Cannot find the kcl file"), "{error}"); + /// + /// let args = &ExecProgramArgs { + /// k_filename_list: vec![], + /// ..Default::default() + /// }; + /// let error = serv.exec_program(args).unwrap_err(); + /// assert!(error.to_string().contains("No input KCL files or paths"), "{error}"); + /// ``` + pub fn exec_program(&self, args: &ExecProgramArgs) -> anyhow::Result { + // transform args to json + let exec_args = transform_exec_para(&Some(args.clone()), self.plugin_agent)?; + let sess = ParseSessionRef::default(); + let result = exec_program(sess, &exec_args)?; + + Ok(ExecProgramResult { + json_result: result.json_result, + yaml_result: result.yaml_result, + log_message: result.log_message, + err_message: result.err_message, + }) + } + + /// Build the KCL program to an artifact. + /// + /// # Examples + /// + /// ``` + /// use kclvm_api::service::service_impl::KclvmServiceImpl; + /// use kclvm_api::gpyrpc::*; + /// use std::path::Path; + /// // File case + /// let serv = KclvmServiceImpl::default(); + /// let exec_args = ExecProgramArgs { + /// work_dir: Path::new(".").join("src").join("testdata").canonicalize().unwrap().display().to_string(), + /// k_filename_list: vec!["test.k".to_string()], + /// ..Default::default() + /// }; + /// let artifact = serv.build_program(&BuildProgramArgs { + /// exec_args: Some(exec_args), + /// output: "".to_string(), + /// }).unwrap(); + /// assert!(!artifact.path.is_empty()); + /// ``` + #[cfg(feature = "llvm")] + pub fn build_program(&self, args: &BuildProgramArgs) -> anyhow::Result { + let exec_args = transform_exec_para(&args.exec_args, self.plugin_agent)?; + let artifact = build_program( + ParseSessionRef::default(), + &exec_args, + transform_str_para(&args.output), + )?; + Ok(BuildProgramResult { + path: artifact.get_path().to_string(), + }) + } + + /// Execute the KCL artifact with arguments and return the JSON/YAML result. + /// + /// ***Note that it is not thread safe when the llvm feature is enabled.* + /// + /// # Examples + /// + /// ```no_run + /// use kclvm_api::service::service_impl::KclvmServiceImpl; + /// use kclvm_api::gpyrpc::*; + /// use std::path::Path; + /// // File case + /// let serv = KclvmServiceImpl::default(); + /// let exec_args = ExecProgramArgs { + /// work_dir: Path::new(".").join("src").join("testdata").canonicalize().unwrap().display().to_string(), + /// k_filename_list: vec!["test.k".to_string()], + /// ..Default::default() + /// }; + /// let artifact = serv.build_program(&BuildProgramArgs { + /// exec_args: Some(exec_args.clone()), + /// output: "./lib".to_string(), + /// }).unwrap(); + /// assert!(!artifact.path.is_empty()); + /// let exec_result = serv.exec_artifact(&ExecArtifactArgs { + /// exec_args: Some(exec_args), + /// path: artifact.path, + /// }).unwrap(); + /// assert_eq!(exec_result.err_message, ""); + /// assert_eq!(exec_result.yaml_result, "alice:\n age: 18"); + /// ``` + #[cfg(feature = "llvm")] + pub fn exec_artifact(&self, args: &ExecArtifactArgs) -> anyhow::Result { + let exec_args = transform_exec_para(&args.exec_args, self.plugin_agent)?; + let result = exec_artifact(&args.path, &exec_args)?; + Ok(ExecProgramResult { + json_result: result.json_result, + yaml_result: result.yaml_result, + log_message: result.log_message, + err_message: result.err_message, + }) + } + + /// Override KCL file with args + /// + /// # Examples + /// + /// ``` + /// use kclvm_api::service::service_impl::KclvmServiceImpl; + /// use kclvm_api::gpyrpc::*; + /// + /// let serv = KclvmServiceImpl::default(); + /// let args = &OverrideFileArgs { + /// file: "./src/testdata/test.k".to_string(), + /// specs: vec!["alice.age=18".to_string()], + /// import_paths: vec![], + /// ..Default::default() + /// }; + /// let override_result = serv.override_file(args).unwrap(); + /// assert!(override_result.result); + /// ``` + /// + /// - test.k (after override) + /// + /// ```kcl + /// schema Person: + /// age: int + /// + /// alice = Person { + /// age = 18 + /// } + /// ``` + pub fn override_file(&self, args: &OverrideFileArgs) -> anyhow::Result { + override_file(&args.file, &args.specs, &args.import_paths).map(|result| { + OverrideFileResult { + result: result.result, + parse_errors: result + .parse_errors + .into_iter() + .map(|e| e.into_error()) + .collect(), + } + }) + } + + /// Service for getting the schema mapping. + /// + /// # Examples + /// + /// ``` + /// use kclvm_api::service::service_impl::KclvmServiceImpl; + /// use kclvm_api::gpyrpc::*; + /// use std::path::Path; + /// + /// let serv = KclvmServiceImpl::default(); + /// let work_dir_parent = Path::new(".").join("src").join("testdata").join("get_schema_ty"); + /// let args = ExecProgramArgs { + /// work_dir: work_dir_parent.join("aaa").canonicalize().unwrap().display().to_string(), + /// k_filename_list: vec![ + /// work_dir_parent.join("aaa").join("main.k").canonicalize().unwrap().display().to_string() + /// ], + /// external_pkgs: vec![ + /// ExternalPkg { + /// pkg_name:"bbb".to_string(), + /// pkg_path: work_dir_parent.join("bbb").canonicalize().unwrap().display().to_string() + /// } + /// ], + /// ..Default::default() + /// }; + /// + /// let result = serv.get_schema_type_mapping(&GetSchemaTypeMappingArgs { + /// exec_args: Some(args), + /// ..Default::default() + /// }).unwrap(); + /// assert_eq!(result.schema_type_mapping.len(), 1); + /// ``` + pub fn get_schema_type_mapping( + &self, + args: &GetSchemaTypeMappingArgs, + ) -> anyhow::Result { + let mut type_mapping = HashMap::new(); + let exec_args = transform_exec_para(&args.exec_args, self.plugin_agent)?; + for (k, schema_ty) in get_full_schema_type( + Some(&args.schema_name), + CompilationOptions { + paths: exec_args.clone().k_filename_list, + loader_opts: Some(exec_args.get_load_program_options()), + resolve_opts: Options { + resolve_val: true, + ..Default::default() + }, + get_schema_opts: GetSchemaOption::default(), + }, + )? { + type_mapping.insert(k, kcl_schema_ty_to_pb_ty(&schema_ty)); + } + + Ok(GetSchemaTypeMappingResult { + schema_type_mapping: type_mapping, + }) + } + + /// Service for getting the schema mapping under path. + /// + /// # Examples + /// + /// ``` + /// use kclvm_api::service::service_impl::KclvmServiceImpl; + /// use kclvm_api::gpyrpc::*; + /// use std::path::Path; + /// use kclvm_ast::MAIN_PKG; + /// + /// let serv = KclvmServiceImpl::default(); + /// let work_dir_parent = Path::new(".").join("src").join("testdata").join("get_schema_ty_under_path"); + /// let args = ExecProgramArgs { + /// k_filename_list: vec![ + /// work_dir_parent.join("aaa").canonicalize().unwrap().display().to_string() + /// ], + /// external_pkgs: vec![ + /// ExternalPkg { + /// pkg_name:"bbb".to_string(), + /// pkg_path: work_dir_parent.join("bbb").canonicalize().unwrap().display().to_string() + /// }, + /// ExternalPkg { + /// pkg_name:"helloworld".to_string(), + /// pkg_path: work_dir_parent.join("helloworld_0.0.1").canonicalize().unwrap().display().to_string() + /// }, + /// ], + /// ..Default::default() + /// }; + /// + /// let result = serv.get_schema_type_mapping_under_path(&GetSchemaTypeMappingArgs { + /// exec_args: Some(args), + /// ..Default::default() + /// }).unwrap(); + /// assert_eq!(result.schema_type_mapping.get(MAIN_PKG).unwrap().schema_type.len(), 1); + /// assert_eq!(result.schema_type_mapping.get("bbb").unwrap().schema_type.len(), 2); + /// assert_eq!(result.schema_type_mapping.get("helloworld").unwrap().schema_type.len(), 1); + /// assert_eq!(result.schema_type_mapping.get("sub").unwrap().schema_type.len(), 1); + /// ``` + pub fn get_schema_type_mapping_under_path( + &self, + args: &GetSchemaTypeMappingArgs, + ) -> anyhow::Result { + let mut type_mapping = HashMap::new(); + let exec_args = transform_exec_para(&args.exec_args, self.plugin_agent)?; + for (k, schema_tys) in get_full_schema_type_under_path( + Some(&args.schema_name), + CompilationOptions { + paths: exec_args.clone().k_filename_list, + loader_opts: Some(exec_args.get_load_program_options()), + resolve_opts: Options { + resolve_val: true, + ..Default::default() + }, + get_schema_opts: GetSchemaOption::Definitions, + }, + )? { + let mut tys = vec![]; + for schema_ty in schema_tys { + tys.push(kcl_schema_ty_to_pb_ty(&schema_ty)); + } + type_mapping.insert(k, gpyrpc::SchemaTypes { schema_type: tys }); + } + + Ok(GetSchemaTypeMappingUnderPathResult { + schema_type_mapping: type_mapping, + }) + } + + /// Service for formatting a code source and returns the formatted source and + /// whether the source is changed. + /// + /// # Examples + /// + /// ``` + /// use kclvm_api::service::service_impl::KclvmServiceImpl; + /// use kclvm_api::gpyrpc::*; + /// + /// let serv = KclvmServiceImpl::default(); + /// let source = r#"schema Person: + /// name: str + /// age: int + /// + /// person = Person { + /// name = "Alice" + /// age = 18 + /// } + /// "#.to_string(); + /// let result = serv.format_code(&FormatCodeArgs { + /// source: source.clone(), + /// ..Default::default() + /// }).unwrap(); + /// assert_eq!(result.formatted, source.as_bytes().to_vec()); + /// ``` + pub fn format_code(&self, args: &FormatCodeArgs) -> anyhow::Result { + let (formatted, _) = format_source( + "", + &args.source, + &FormatOptions { + is_stdout: false, + recursively: false, + omit_errors: true, + }, + )?; + Ok(FormatCodeResult { + formatted: formatted.as_bytes().to_vec(), + }) + } + + /// Service for formatting kcl file or directory path contains kcl files and + /// returns the changed file paths. + /// + /// # Examples + /// + /// ``` + /// use kclvm_api::service::service_impl::KclvmServiceImpl; + /// use kclvm_api::gpyrpc::*; + /// + /// let serv = KclvmServiceImpl::default(); + /// let result = serv.format_path(&FormatPathArgs { + /// path: "./src/testdata/test.k".to_string(), + /// ..Default::default() + /// }).unwrap(); + /// assert!(result.changed_paths.is_empty()); + /// ``` + pub fn format_path(&self, args: &FormatPathArgs) -> anyhow::Result { + let path = &args.path; + let (path, recursively) = if path.ends_with("...") { + let path = &path[0..path.len() - 3]; + (if path.is_empty() { "." } else { path }, true) + } else { + (args.path.as_str(), false) + }; + let changed_paths = format( + path, + &FormatOptions { + recursively, + is_stdout: false, + omit_errors: true, + }, + )?; + Ok(FormatPathResult { changed_paths }) + } + + /// Service for KCL Lint API, check a set of files, skips execute, + /// returns error message including errors and warnings. + /// + /// # Examples + /// + /// ``` + /// use kclvm_api::service::service_impl::KclvmServiceImpl; + /// use kclvm_api::gpyrpc::*; + /// + /// let serv = KclvmServiceImpl::default(); + /// let result = serv.lint_path(&LintPathArgs { + /// paths: vec!["./src/testdata/test-lint.k".to_string()], + /// ..Default::default() + /// }).unwrap(); + /// assert_eq!(result.results, vec!["Module 'math' imported but unused".to_string()]); + /// ``` + pub fn lint_path(&self, args: &LintPathArgs) -> anyhow::Result { + let (errs, warnings) = lint_files( + &args.paths.iter().map(|p| p.as_str()).collect::>(), + None, + ); + let mut results = vec![]; + // Append errors. + for err in errs { + for msg in err.messages { + results.push(msg.message) + } + } + // Append warnings. + for warning in warnings { + for msg in warning.messages { + results.push(msg.message) + } + } + Ok(LintPathResult { results }) + } + + /// Service for validating the data string using the schema code string, when the parameter + /// `schema` is omitted, use the first schema appeared in the kcl code. + /// + /// **Note that it is not thread safe.** + /// + /// # Examples + /// + /// ```no_run + /// use kclvm_api::service::service_impl::KclvmServiceImpl; + /// use kclvm_api::gpyrpc::*; + /// + /// let serv = KclvmServiceImpl::default(); + /// let code = r#" + /// schema Person: + /// name: str + /// age: int + /// + /// check: + /// 0 < age < 120 + /// "#.to_string(); + /// let data = r#" + /// { + /// "name": "Alice", + /// "age": 10 + /// } + /// "#.to_string(); + /// let result = serv.validate_code(&ValidateCodeArgs { + /// code, + /// data, + /// ..Default::default() + /// }).unwrap(); + /// assert_eq!(result.success, true); + /// ``` + pub fn validate_code(&self, args: &ValidateCodeArgs) -> anyhow::Result { + let mut file = NamedTempFile::new()?; + let file_path = if args.datafile.is_empty() { + // Write some test data to the first handle. + file.write_all(args.data.as_bytes())?; + file.path().to_string_lossy().to_string() + } else { + args.datafile.clone() + }; + + let (success, err_message) = match validate(ValidateOption::new( + transform_str_para(&args.schema), + args.attribute_name.clone(), + file_path, + match args.format.to_lowercase().as_str() { + "yaml" | "yml" => LoaderKind::YAML, + "json" => LoaderKind::JSON, + _ => LoaderKind::JSON, + }, + transform_str_para(&args.file), + transform_str_para(&args.code), + )) { + Ok(success) => (success, "".to_string()), + Err(err) => (false, err.to_string()), + }; + Ok(ValidateCodeResult { + success, + err_message, + }) + } + + /// Service for building setting file config from args. + /// + /// # Examples + /// + /// ``` + /// use kclvm_api::service::service_impl::KclvmServiceImpl; + /// use kclvm_api::gpyrpc::*; + /// + /// let serv = KclvmServiceImpl::default(); + /// let result = serv.load_settings_files(&LoadSettingsFilesArgs { + /// files: vec!["./src/testdata/settings/kcl.yaml".to_string()], + /// work_dir: "./src/testdata/settings".to_string(), + /// ..Default::default() + /// }).unwrap(); + /// assert_eq!(result.kcl_options.len(), 1); + /// ``` + pub fn load_settings_files( + &self, + args: &LoadSettingsFilesArgs, + ) -> anyhow::Result { + let settings_files = args.files.iter().map(|f| f.as_str()).collect::>(); + let settings_pathbuf = build_settings_pathbuf(&[], Some(settings_files), None)?; + let files = if !settings_pathbuf.settings().input().is_empty() { + get_normalized_k_files_from_paths( + &settings_pathbuf.settings().input(), + &LoadProgramOptions { + work_dir: args.work_dir.clone(), + ..Default::default() + }, + )? + } else { + vec![] + }; + Ok(settings_pathbuf + .settings() + .clone() + .into_load_settings_files(&files)) + } + + /// Service for renaming all the occurrences of the target symbol in the files. This API will rewrite files if they contain symbols to be renamed. + /// return the file paths got changed. + /// + /// # Examples + /// + /// ``` + /// use kclvm_api::service::service_impl::KclvmServiceImpl; + /// use kclvm_api::gpyrpc::*; + /// # use std::path::PathBuf; + /// # use std::fs; + /// # + /// # let serv = KclvmServiceImpl::default(); + /// # // before test, load template from .bak + /// # let path = PathBuf::from(".").join("src").join("testdata").join("rename_doc").join("main.k"); + /// # let backup_path = path.with_extension("bak"); + /// # let content = fs::read_to_string(backup_path.clone()).unwrap(); + /// # fs::write(path.clone(), content).unwrap(); + /// + /// let result = serv.rename(&RenameArgs { + /// package_root: "./src/testdata/rename_doc".to_string(), + /// symbol_path: "a".to_string(), + /// file_paths: vec!["./src/testdata/rename_doc/main.k".to_string()], + /// new_name: "a2".to_string(), + /// }).unwrap(); + /// assert_eq!(result.changed_files.len(), 1); + /// + /// # // after test, restore template from .bak + /// # fs::remove_file(path.clone()).unwrap(); + /// ``` + pub fn rename(&self, args: &RenameArgs) -> anyhow::Result { + let pkg_root = PathBuf::from(args.package_root.clone()) + .canonicalize()? + .display() + .to_string(); + let symbol_path = args.symbol_path.clone(); + let mut file_paths = vec![]; + for path in args.file_paths.iter() { + file_paths.push(PathBuf::from(path).canonicalize()?.display().to_string()); + } + let new_name = args.new_name.clone(); + Ok(RenameResult { + changed_files: rename::rename_symbol_on_file( + &pkg_root, + &symbol_path, + &file_paths, + new_name, + )?, + }) + } + + /// Service for renaming all the occurrences of the target symbol and rename them. This API won't rewrite files but return the modified code if any code has been changed. + /// return the changed code. + /// + /// # Examples + /// + /// ``` + /// use kclvm_api::service::service_impl::KclvmServiceImpl; + /// use kclvm_api::gpyrpc::*; + /// + /// let serv = KclvmServiceImpl::default(); + /// let result = serv.rename_code(&RenameCodeArgs { + /// package_root: "/mock/path".to_string(), + /// symbol_path: "a".to_string(), + /// source_codes: vec![("/mock/path/main.k".to_string(), "a = 1\nb = a".to_string())].into_iter().collect(), + /// new_name: "a2".to_string(), + /// }).unwrap(); + /// assert_eq!(result.changed_codes.len(), 1); + /// assert_eq!(result.changed_codes.get("/mock/path/main.k").unwrap(), "a2 = 1\nb = a2"); + /// ``` + pub fn rename_code(&self, args: &RenameCodeArgs) -> anyhow::Result { + Ok(RenameCodeResult { + changed_codes: rename::rename_symbol_on_code( + &args.package_root, + &args.symbol_path, + args.source_codes.clone(), + args.new_name.clone(), + )?, + }) + } + + /// Service for the testing tool. + /// + /// # Examples + /// + /// ``` + /// use kclvm_api::service::service_impl::KclvmServiceImpl; + /// use kclvm_api::gpyrpc::*; + /// + /// let serv = KclvmServiceImpl::default(); + /// let result = serv.test(&TestArgs { + /// pkg_list: vec!["./src/testdata/testing/module/...".to_string()], + /// ..TestArgs::default() + /// }).unwrap(); + /// assert_eq!(result.info.len(), 2); + /// // Passed case + /// assert!(result.info[0].error.is_empty()); + /// // Failed case + /// assert!(result.info[1].error.is_empty()); + /// ``` + pub fn test(&self, args: &TestArgs) -> anyhow::Result { + let mut result = TestResult::default(); + let exec_args = transform_exec_para(&args.exec_args, self.plugin_agent)?; + let opts = testing::TestOptions { + exec_args, + run_regexp: args.run_regexp.clone(), + fail_fast: args.fail_fast, + }; + for pkg in &args.pkg_list { + let suites = testing::load_test_suites(pkg, &opts)?; + for suite in &suites { + let suite_result = suite.run(&opts)?; + for (name, info) in &suite_result.info { + result.info.push(TestCaseInfo { + name: name.clone(), + error: info + .error + .as_ref() + .map(|e| e.to_string()) + .unwrap_or_default(), + duration: info.duration.as_micros() as u64, + log_message: info.log_message.clone(), + }) + } + } + } + Ok(result) + } + + #[cfg(not(target_arch = "wasm32"))] + /// update_dependencies provides users with the ability to update kcl module dependencies. + /// + /// # Examples + /// + /// ``` + /// use kclvm_api::service::service_impl::KclvmServiceImpl; + /// use kclvm_api::gpyrpc::*; + /// use std::path::Path; + /// use std::fs::remove_dir_all; + /// + /// let serv = KclvmServiceImpl::default(); + /// let result = serv.update_dependencies(&UpdateDependenciesArgs { + /// manifest_path: "./src/testdata/update_dependencies".to_string(), + /// ..Default::default() + /// }).unwrap(); + /// assert_eq!(result.external_pkgs.len(), 1); + /// + /// let result = serv.update_dependencies(&UpdateDependenciesArgs { + /// manifest_path: "./src/testdata/update_dependencies".to_string(), + /// vendor: true, + /// }).unwrap(); + /// assert_eq!(result.external_pkgs.len(), 1); + /// let vendor_path = Path::new("./src/testdata/update_dependencies/vendor"); + /// remove_dir_all(vendor_path); + /// ``` + pub fn update_dependencies( + &self, + args: &UpdateDependenciesArgs, + ) -> anyhow::Result { + use kclvm_driver::client::ModClient; + use std::path::Path; + let mut client = ModClient::new(&args.manifest_path)?; + if args.vendor { + client.set_vendor(&Path::new(&args.manifest_path).join("vendor")); + } + client.auth()?; + let metadata = client.resolve_all_deps(true)?; + Ok(UpdateDependenciesResult { + external_pkgs: metadata + .packages + .iter() + .map(|(n, p)| ExternalPkg { + pkg_name: n.to_string(), + pkg_path: p.manifest_path.to_string_lossy().to_string(), + }) + .collect(), + }) + } +} diff --git a/kclvm/api/src/service/ty.rs b/kclvm/api/src/service/ty.rs new file mode 100644 index 000000000..f171d46eb --- /dev/null +++ b/kclvm/api/src/service/ty.rs @@ -0,0 +1,121 @@ +use crate::gpyrpc::{Decorator, Example, KclType}; +use indexmap::IndexSet; +use kclvm_sema::ty::{DictType, SchemaType, Type}; +use std::collections::HashMap; + +/// Convert the kcl sematic type to the kcl protobuf type. +pub(crate) fn kcl_ty_to_pb_ty(ty: &Type) -> KclType { + match &ty.kind { + kclvm_sema::ty::TypeKind::List(item_ty) => KclType { + r#type: "list".to_string(), + item: Some(Box::new(kcl_ty_to_pb_ty(item_ty))), + ..Default::default() + }, + kclvm_sema::ty::TypeKind::Dict(DictType { key_ty, val_ty, .. }) => KclType { + r#type: "dict".to_string(), + key: Some(Box::new(kcl_ty_to_pb_ty(key_ty))), + item: Some(Box::new(kcl_ty_to_pb_ty(val_ty))), + ..Default::default() + }, + kclvm_sema::ty::TypeKind::Union(types) => KclType { + r#type: "union".to_string(), + union_types: types.iter().map(|ty| kcl_ty_to_pb_ty(ty)).collect(), + ..Default::default() + }, + kclvm_sema::ty::TypeKind::Schema(schema_ty) => kcl_schema_ty_to_pb_ty(schema_ty), + _ => KclType { + r#type: ty.ty_str(), + ..Default::default() + }, + } +} + +/// Convert the kcl sematic type to the kcl protobuf type. +pub(crate) fn kcl_schema_ty_to_pb_ty(schema_ty: &SchemaType) -> KclType { + KclType { + r#type: "schema".to_string(), + schema_name: schema_ty.name.clone(), + schema_doc: schema_ty.doc.clone(), + examples: get_schema_ty_examples(schema_ty), + properties: get_schema_ty_attributes(schema_ty, &mut 1), + required: get_schema_ty_required_attributes(schema_ty), + decorators: schema_ty + .decorators + .iter() + .map(|d| Decorator { + name: d.name.clone(), + arguments: d.arguments.clone(), + keywords: d.keywords.clone(), + }) + .collect(), + filename: schema_ty.filename.clone(), + pkg_path: schema_ty.pkgpath.clone(), + description: schema_ty.doc.clone(), + base_schema: schema_ty + .base + .as_ref() + .map(|base| Box::new(kcl_schema_ty_to_pb_ty(&**base))), + ..Default::default() + } +} + +fn get_schema_ty_examples(schema_ty: &SchemaType) -> HashMap { + let mut examples = HashMap::new(); + for (key, example) in &schema_ty.examples { + let exa = Example { + summary: example.summary.clone(), + description: example.description.clone(), + value: example.value.clone(), + }; + examples.insert(key.clone(), exa); + } + examples +} + +fn get_schema_ty_attributes(schema_ty: &SchemaType, line: &mut i32) -> HashMap { + let mut base_type_mapping = if let Some(base) = &schema_ty.base { + get_schema_ty_attributes(base, line) + } else { + HashMap::new() + }; + let mut type_mapping = HashMap::new(); + for (key, attr) in &schema_ty.attrs { + let mut ty = kcl_ty_to_pb_ty(&attr.ty); + ty.line = *line; + ty.description = attr.doc.clone().unwrap_or_default(); + ty.decorators = attr + .decorators + .iter() + .map(|d| Decorator { + name: d.name.clone(), + arguments: d.arguments.clone(), + keywords: d.keywords.clone(), + }) + .collect(); + ty.default = attr.default.clone().unwrap_or_default(); + type_mapping.insert(key.to_string(), ty); + *line += 1 + } + for (k, ty) in type_mapping { + base_type_mapping.insert(k, ty); + } + base_type_mapping +} + +fn get_schema_ty_required_attributes(schema_ty: &SchemaType) -> Vec { + let base_attr_set = if let Some(base) = &schema_ty.base { + get_schema_ty_required_attributes(base) + } else { + Vec::new() + }; + let mut attr_set = IndexSet::new(); + for (key, attr) in &schema_ty.attrs { + if !attr.is_optional { + attr_set.insert(key.to_string()); + } + } + for k in base_attr_set { + attr_set.insert(k); + } + attr_set.iter().cloned().collect() +} diff --git a/kclvm/api/src/service/util.rs b/kclvm/api/src/service/util.rs new file mode 100644 index 000000000..f74b5fa1f --- /dev/null +++ b/kclvm/api/src/service/util.rs @@ -0,0 +1,27 @@ +use crate::gpyrpc::ExecProgramArgs; + +/// Transform the str with zero value into [`Option`] +#[inline] +pub(crate) fn transform_str_para(para: &str) -> Option { + if para.is_empty() { + None + } else { + Some(para.to_string()) + } +} + +#[inline] +pub(crate) fn transform_exec_para( + exec_args: &Option, + plugin_agent: u64, +) -> anyhow::Result { + let mut args = match exec_args { + Some(exec_args) => { + let args_json = serde_json::to_string(exec_args)?; + kclvm_runner::ExecProgramArgs::from_str(args_json.as_str()) + } + None => kclvm_runner::ExecProgramArgs::default(), + }; + args.plugin_agent = plugin_agent; + Ok(args) +} diff --git a/kclvm/api/src/testdata/compile_recursive/kcl1/main.k b/kclvm/api/src/testdata/compile_recursive/kcl1/main.k new file mode 100644 index 000000000..23d3c668c --- /dev/null +++ b/kclvm/api/src/testdata/compile_recursive/kcl1/main.k @@ -0,0 +1 @@ +k1 = 'Hello k1!' \ No newline at end of file diff --git a/kclvm/api/src/testdata/compile_recursive/kcl2/main.k b/kclvm/api/src/testdata/compile_recursive/kcl2/main.k new file mode 100644 index 000000000..0cc5f31c5 --- /dev/null +++ b/kclvm/api/src/testdata/compile_recursive/kcl2/main.k @@ -0,0 +1 @@ +k2 = 'Hello k2!' \ No newline at end of file diff --git a/kclvm/api/src/testdata/compile_recursive/main.k b/kclvm/api/src/testdata/compile_recursive/main.k new file mode 100644 index 000000000..fa7048e63 --- /dev/null +++ b/kclvm/api/src/testdata/compile_recursive/main.k @@ -0,0 +1 @@ +The_first_kcl_program = 'Hello World!' \ No newline at end of file diff --git a/kclvm/api/src/testdata/exec-program-with-compile-only.json b/kclvm/api/src/testdata/exec-program-with-compile-only.json new file mode 100644 index 000000000..4e6096eee --- /dev/null +++ b/kclvm/api/src/testdata/exec-program-with-compile-only.json @@ -0,0 +1,17 @@ +{ + "work_dir" : "./src/testdata", + "k_filename_list":[ + "test-lint-import.k" + ], + "compile_only": true, + "external_pkgs": [ + { + "pkg_name": "external", + "pkg_path": "./src/testdata_external/external" + }, + { + "pkg_name": "external_1", + "pkg_path": "./src/testdata_external/external_1" + } + ] +} \ No newline at end of file diff --git a/kclvm/api/src/testdata/exec-program-with-compile-only.response.panic b/kclvm/api/src/testdata/exec-program-with-compile-only.response.panic new file mode 100644 index 000000000..c90f20cba --- /dev/null +++ b/kclvm/api/src/testdata/exec-program-with-compile-only.response.panic @@ -0,0 +1 @@ +Module 'ext' imported but unused \ No newline at end of file diff --git a/kclvm/api/src/testdata/exec-program-with-external-pkg.json b/kclvm/api/src/testdata/exec-program-with-external-pkg.json new file mode 100644 index 000000000..b936fa822 --- /dev/null +++ b/kclvm/api/src/testdata/exec-program-with-external-pkg.json @@ -0,0 +1,16 @@ +{ + "work_dir" : "./src/testdata", + "k_filename_list":[ + "hello_import.k" + ], + "external_pkgs": [ + { + "pkg_name": "external", + "pkg_path": "./src/testdata_external/external" + }, + { + "pkg_name": "external_1", + "pkg_path": "./src/testdata_external/external_1" + } + ] +} \ No newline at end of file diff --git a/kclvm/api/src/testdata/exec-program-with-external-pkg.response.json b/kclvm/api/src/testdata/exec-program-with-external-pkg.response.json new file mode 100644 index 000000000..a4183d7d1 --- /dev/null +++ b/kclvm/api/src/testdata/exec-program-with-external-pkg.response.json @@ -0,0 +1,5 @@ +{ + "json_result": "{\"a\": \"Hello External World!\", \"a1\": \"Hello External_1 World!\"}", + "yaml_result": "a: Hello External World!\na1: Hello External_1 World!", + "escaped_time": "0.002061128616333008" +} diff --git a/kclvm/api/src/testdata/exec-program-with-include-schema-type-path.json b/kclvm/api/src/testdata/exec-program-with-include-schema-type-path.json new file mode 100644 index 000000000..6c42c2fc8 --- /dev/null +++ b/kclvm/api/src/testdata/exec-program-with-include-schema-type-path.json @@ -0,0 +1,8 @@ + +{ + "work_dir" : "./src/testdata", + "k_filename_list":[ + "test.k" + ], + "include_schema_type_path": true +} diff --git a/kclvm/api/src/testdata/exec-program-with-include-schema-type-path.response.json b/kclvm/api/src/testdata/exec-program-with-include-schema-type-path.response.json new file mode 100644 index 000000000..d37182c19 --- /dev/null +++ b/kclvm/api/src/testdata/exec-program-with-include-schema-type-path.response.json @@ -0,0 +1,6 @@ +{ + "json_result": "{\"alice\": {\"age\": 18, \"_type\": \"Person\"}}", + "yaml_result": "alice:\n age: 18\n _type: Person", + "log_message": "", + "err_message": "" +} \ No newline at end of file diff --git a/kclvm/api/src/testdata/exec-program-with-path-selector.json b/kclvm/api/src/testdata/exec-program-with-path-selector.json new file mode 100644 index 000000000..3a3b473af --- /dev/null +++ b/kclvm/api/src/testdata/exec-program-with-path-selector.json @@ -0,0 +1,9 @@ +{ + "work_dir" : "./src/testdata", + "k_filename_list": [ + "test.k" + ], + "path_selector": [ + "alice" + ] +} diff --git a/kclvm/api/src/testdata/exec-program-with-path-selector.response.json b/kclvm/api/src/testdata/exec-program-with-path-selector.response.json new file mode 100644 index 000000000..20f0c8003 --- /dev/null +++ b/kclvm/api/src/testdata/exec-program-with-path-selector.response.json @@ -0,0 +1,4 @@ +{ + "json_result": "{\"age\": 18}", + "yaml_result": "age: 18" +} diff --git a/kclvm/api/src/testdata/exec-program-with-print.json b/kclvm/api/src/testdata/exec-program-with-print.json new file mode 100644 index 000000000..55459c183 --- /dev/null +++ b/kclvm/api/src/testdata/exec-program-with-print.json @@ -0,0 +1,6 @@ +{ + "work_dir" : "./src/testdata", + "k_filename_list":[ + "hello_with_print.k" + ] +} \ No newline at end of file diff --git a/kclvm/api/src/testdata/exec-program-with-print.response.json b/kclvm/api/src/testdata/exec-program-with-print.response.json new file mode 100644 index 000000000..bf88fa06c --- /dev/null +++ b/kclvm/api/src/testdata/exec-program-with-print.response.json @@ -0,0 +1,6 @@ +{ + "json_result": "{\"a\": 1}", + "yaml_result": "a: 1", + "log_message": "Hello world\n", + "err_message": "" +} \ No newline at end of file diff --git a/kclvm/api/src/testdata/exec-program.json b/kclvm/api/src/testdata/exec-program.json new file mode 100644 index 000000000..ef8423801 --- /dev/null +++ b/kclvm/api/src/testdata/exec-program.json @@ -0,0 +1,7 @@ + +{ + "work_dir" : "./src/testdata", + "k_filename_list":[ + "hello.k" + ] +} diff --git a/kclvm/api/src/testdata/exec-program.response.json b/kclvm/api/src/testdata/exec-program.response.json new file mode 100644 index 000000000..b45c912fe --- /dev/null +++ b/kclvm/api/src/testdata/exec-program.response.json @@ -0,0 +1,5 @@ +{ + "json_result": "{\"a\": 1}", + "yaml_result": "a: 1", + "escaped_time": "0.002061128616333008" +} \ No newline at end of file diff --git a/kclvm/api/src/testdata/format-code.json b/kclvm/api/src/testdata/format-code.json new file mode 100644 index 000000000..d27b3a1cf --- /dev/null +++ b/kclvm/api/src/testdata/format-code.json @@ -0,0 +1,3 @@ +{ + "source": "schema Person:\n name: str\n age: int\n\nperson = Person {\n name = \"Alice\"\n age = 18\n}\n" +} diff --git a/kclvm/api/src/testdata/format-code.response.json b/kclvm/api/src/testdata/format-code.response.json new file mode 100644 index 000000000..1c332b4ea --- /dev/null +++ b/kclvm/api/src/testdata/format-code.response.json @@ -0,0 +1,99 @@ +{ + "formatted": [ + 115, + 99, + 104, + 101, + 109, + 97, + 32, + 80, + 101, + 114, + 115, + 111, + 110, + 58, + 10, + 32, + 32, + 32, + 32, + 110, + 97, + 109, + 101, + 58, + 32, + 115, + 116, + 114, + 10, + 32, + 32, + 32, + 32, + 97, + 103, + 101, + 58, + 32, + 105, + 110, + 116, + 10, + 10, + 112, + 101, + 114, + 115, + 111, + 110, + 32, + 61, + 32, + 80, + 101, + 114, + 115, + 111, + 110, + 32, + 123, + 10, + 32, + 32, + 32, + 32, + 110, + 97, + 109, + 101, + 32, + 61, + 32, + 34, + 65, + 108, + 105, + 99, + 101, + 34, + 10, + 32, + 32, + 32, + 32, + 97, + 103, + 101, + 32, + 61, + 32, + 49, + 56, + 10, + 125, + 10 + ] +} \ No newline at end of file diff --git a/kclvm/api/src/testdata/format-path.json b/kclvm/api/src/testdata/format-path.json new file mode 100644 index 000000000..f25df2461 --- /dev/null +++ b/kclvm/api/src/testdata/format-path.json @@ -0,0 +1,3 @@ +{ + "path": "./testdata/test.k" +} diff --git a/kclvm/api/src/testdata/format-path.response.json b/kclvm/api/src/testdata/format-path.response.json new file mode 100644 index 000000000..fc0aa1d97 --- /dev/null +++ b/kclvm/api/src/testdata/format-path.response.json @@ -0,0 +1,3 @@ +{ + "changed_paths": [] +} diff --git a/kclvm/api/src/testdata/get-schema-type-mapping.json b/kclvm/api/src/testdata/get-schema-type-mapping.json new file mode 100644 index 000000000..0deb44914 --- /dev/null +++ b/kclvm/api/src/testdata/get-schema-type-mapping.json @@ -0,0 +1,19 @@ +{ + "exec_args": { + "work_dir" : "./src/testdata/get_schema_ty/aaa", + "k_filename_list":[ + "./src/testdata/get_schema_ty/aaa/main.k" + ], + "external_pkgs": [ + { + "pkg_name": "bbb", + "pkg_path": "./src/testdata/get_schema_ty/bbb" + }, + { + "pkg_name": "ccc", + "pkg_path": "./src/testdata/get_schema_ty/ccc" + } + ] + }, + "schema_name": "" +} diff --git a/kclvm/api/src/testdata/get-schema-type-mapping.response.json b/kclvm/api/src/testdata/get-schema-type-mapping.response.json new file mode 100644 index 000000000..83614f47b --- /dev/null +++ b/kclvm/api/src/testdata/get-schema-type-mapping.response.json @@ -0,0 +1,82 @@ +{ + "schema_type_mapping": { + "a_c": { + "type": "schema", + "union_types": [], + "default": "", + "schema_name": "C", + "schema_doc": "", + "properties": { + "name": { + "type": "str", + "union_types": [], + "default": "", + "schema_name": "", + "schema_doc": "", + "properties": {}, + "required": [], + "key": null, + "item": null, + "line": 1, + "decorators": [], + "filename": "", + "pkg_path": "", + "description": "", + "examples": {}, + "base_schema": null + } + }, + "required": [ + "name" + ], + "key": null, + "item": null, + "line": 0, + "decorators": [], + "filename": "./src/testdata/get_schema_ty/ccc/main.k", + "pkg_path": "ccc", + "description": "", + "examples": {}, + "base_schema": null + }, + "a": { + "type": "schema", + "union_types": [], + "default": "", + "schema_name": "B", + "schema_doc": "", + "properties": { + "name": { + "type": "str", + "union_types": [], + "default": "", + "schema_name": "", + "schema_doc": "", + "properties": {}, + "required": [], + "key": null, + "item": null, + "line": 1, + "decorators": [], + "filename": "", + "pkg_path": "", + "description": "", + "examples": {}, + "base_schema": null + } + }, + "required": [ + "name" + ], + "key": null, + "item": null, + "line": 0, + "decorators": [], + "filename": "./src/testdata/get_schema_ty/bbb/main.k", + "pkg_path": "bbb", + "description": "", + "examples": {}, + "base_schema": null + } + } +} diff --git a/kclvm/api/src/testdata/get_schema_ty/aaa/kcl.mod b/kclvm/api/src/testdata/get_schema_ty/aaa/kcl.mod new file mode 100644 index 000000000..1e29d9eb2 --- /dev/null +++ b/kclvm/api/src/testdata/get_schema_ty/aaa/kcl.mod @@ -0,0 +1,5 @@ +[package] +name = "aaa" +edition = "0.0.1" +version = "0.0.1" + diff --git a/kclvm/api/src/testdata/get_schema_ty/aaa/main.k b/kclvm/api/src/testdata/get_schema_ty/aaa/main.k new file mode 100644 index 000000000..bba48edf6 --- /dev/null +++ b/kclvm/api/src/testdata/get_schema_ty/aaa/main.k @@ -0,0 +1,10 @@ +import bbb as b +import ccc as c + +a = b.B { + name: "b instance in a" +} + +a_c = c.C { + name: "c instance in a" +} \ No newline at end of file diff --git a/kclvm/api/src/testdata/get_schema_ty/bbb/kcl.mod b/kclvm/api/src/testdata/get_schema_ty/bbb/kcl.mod new file mode 100644 index 000000000..e9ea10a52 --- /dev/null +++ b/kclvm/api/src/testdata/get_schema_ty/bbb/kcl.mod @@ -0,0 +1,5 @@ +[package] +name = "bbb" +edition = "0.0.1" +version = "0.0.1" + diff --git a/kclvm/api/src/testdata/get_schema_ty/bbb/main.k b/kclvm/api/src/testdata/get_schema_ty/bbb/main.k new file mode 100644 index 000000000..21dad4f9e --- /dev/null +++ b/kclvm/api/src/testdata/get_schema_ty/bbb/main.k @@ -0,0 +1,2 @@ +schema B: + name: str \ No newline at end of file diff --git a/kclvm/api/src/testdata/get_schema_ty/ccc/kcl.mod b/kclvm/api/src/testdata/get_schema_ty/ccc/kcl.mod new file mode 100644 index 000000000..9a762a4fa --- /dev/null +++ b/kclvm/api/src/testdata/get_schema_ty/ccc/kcl.mod @@ -0,0 +1,5 @@ +[package] +name = "ccc" +edition = "0.0.1" +version = "0.0.1" + diff --git a/kclvm/api/src/testdata/get_schema_ty/ccc/main.k b/kclvm/api/src/testdata/get_schema_ty/ccc/main.k new file mode 100644 index 000000000..463ff966a --- /dev/null +++ b/kclvm/api/src/testdata/get_schema_ty/ccc/main.k @@ -0,0 +1,2 @@ +schema C: + name: str \ No newline at end of file diff --git a/kclvm/api/src/testdata/get_schema_ty_under_path/aaa/kcl.mod b/kclvm/api/src/testdata/get_schema_ty_under_path/aaa/kcl.mod new file mode 100644 index 000000000..062218adb --- /dev/null +++ b/kclvm/api/src/testdata/get_schema_ty_under_path/aaa/kcl.mod @@ -0,0 +1,8 @@ +[package] +name = "aaa" +edition = "0.0.1" +version = "0.0.1" + +[dependencies] +bbb = { path = "../bbb" } +helloworld = "0.0.1" \ No newline at end of file diff --git a/kclvm/api/src/testdata/get_schema_ty_under_path/aaa/main.k b/kclvm/api/src/testdata/get_schema_ty_under_path/aaa/main.k new file mode 100644 index 000000000..5dcba578f --- /dev/null +++ b/kclvm/api/src/testdata/get_schema_ty_under_path/aaa/main.k @@ -0,0 +1,8 @@ +import bbb + +schema A: + name: str + +a = bbb.B { + name: "b instance in a" +} \ No newline at end of file diff --git a/kclvm/api/src/testdata/get_schema_ty_under_path/aaa/sub/sub.k b/kclvm/api/src/testdata/get_schema_ty_under_path/aaa/sub/sub.k new file mode 100644 index 000000000..8000c5ff0 --- /dev/null +++ b/kclvm/api/src/testdata/get_schema_ty_under_path/aaa/sub/sub.k @@ -0,0 +1,3 @@ +schema Sub: + name: str + \ No newline at end of file diff --git a/kclvm/api/src/testdata/get_schema_ty_under_path/bbb/kcl.mod b/kclvm/api/src/testdata/get_schema_ty_under_path/bbb/kcl.mod new file mode 100644 index 000000000..e9ea10a52 --- /dev/null +++ b/kclvm/api/src/testdata/get_schema_ty_under_path/bbb/kcl.mod @@ -0,0 +1,5 @@ +[package] +name = "bbb" +edition = "0.0.1" +version = "0.0.1" + diff --git a/kclvm/api/src/testdata/get_schema_ty_under_path/bbb/main.k b/kclvm/api/src/testdata/get_schema_ty_under_path/bbb/main.k new file mode 100644 index 000000000..15b434862 --- /dev/null +++ b/kclvm/api/src/testdata/get_schema_ty_under_path/bbb/main.k @@ -0,0 +1,4 @@ +schema Base: + n: str +schema B(Base): + name: str \ No newline at end of file diff --git a/kclvm/api/src/testdata/get_schema_ty_under_path/helloworld_0.0.1/README.md b/kclvm/api/src/testdata/get_schema_ty_under_path/helloworld_0.0.1/README.md new file mode 100644 index 000000000..4d63fef38 --- /dev/null +++ b/kclvm/api/src/testdata/get_schema_ty_under_path/helloworld_0.0.1/README.md @@ -0,0 +1,2 @@ +## Introduction +This is a kcl package named helloworld. diff --git a/kclvm/api/src/testdata/get_schema_ty_under_path/helloworld_0.0.1/kcl.mod b/kclvm/api/src/testdata/get_schema_ty_under_path/helloworld_0.0.1/kcl.mod new file mode 100644 index 000000000..bef7e7f76 --- /dev/null +++ b/kclvm/api/src/testdata/get_schema_ty_under_path/helloworld_0.0.1/kcl.mod @@ -0,0 +1,5 @@ +[package] +name = "helloworld" +edition = "0.0.1" +version = "0.0.1" + diff --git a/kclvm/api/src/testdata/get_schema_ty_under_path/helloworld_0.0.1/main.k b/kclvm/api/src/testdata/get_schema_ty_under_path/helloworld_0.0.1/main.k new file mode 100644 index 000000000..571977787 --- /dev/null +++ b/kclvm/api/src/testdata/get_schema_ty_under_path/helloworld_0.0.1/main.k @@ -0,0 +1,3 @@ +The_first_kcl_program = 'Hello World!' +schema Hello: + name: str \ No newline at end of file diff --git a/test/test_units/test_kclvm/test_compiler/test_build/cache_expired_testdata/pkg/pkg1/pkg2/pkg.k b/kclvm/api/src/testdata/hello.k similarity index 100% rename from test/test_units/test_kclvm/test_compiler/test_build/cache_expired_testdata/pkg/pkg1/pkg2/pkg.k rename to kclvm/api/src/testdata/hello.k diff --git a/kclvm/api/src/testdata/hello_import.k b/kclvm/api/src/testdata/hello_import.k new file mode 100644 index 000000000..7e1d0e41c --- /dev/null +++ b/kclvm/api/src/testdata/hello_import.k @@ -0,0 +1,5 @@ +import external as ext +import external_1 as ext_1 + +a = ext.a +a1 = ext_1.a \ No newline at end of file diff --git a/kclvm/api/src/testdata/hello_with_print.k b/kclvm/api/src/testdata/hello_with_print.k new file mode 100644 index 000000000..5c0f43e6d --- /dev/null +++ b/kclvm/api/src/testdata/hello_with_print.k @@ -0,0 +1,2 @@ +print("Hello world") +a = 1 diff --git a/kclvm/api/src/testdata/lint-path.json b/kclvm/api/src/testdata/lint-path.json new file mode 100644 index 000000000..4b6a1f453 --- /dev/null +++ b/kclvm/api/src/testdata/lint-path.json @@ -0,0 +1,5 @@ +{ + "paths":[ + "./src/testdata/test-lint.k" + ] +} diff --git a/kclvm/api/src/testdata/lint-path.response.json b/kclvm/api/src/testdata/lint-path.response.json new file mode 100644 index 000000000..29747dedf --- /dev/null +++ b/kclvm/api/src/testdata/lint-path.response.json @@ -0,0 +1,3 @@ +{ + "results": ["Module 'math' imported but unused"] +} diff --git a/kclvm/api/src/testdata/list-options.json b/kclvm/api/src/testdata/list-options.json new file mode 100644 index 000000000..cac1b3c81 --- /dev/null +++ b/kclvm/api/src/testdata/list-options.json @@ -0,0 +1,3 @@ +{ + "paths": ["./src/testdata/option/main.k"] +} diff --git a/kclvm/api/src/testdata/list-options.response.json b/kclvm/api/src/testdata/list-options.response.json new file mode 100644 index 000000000..f14a223ca --- /dev/null +++ b/kclvm/api/src/testdata/list-options.response.json @@ -0,0 +1,25 @@ +{ + "options": [ + { + "name": "key1", + "type": "", + "required": false, + "default_value": "", + "help": "" + }, + { + "name": "key2", + "type": "", + "required": true, + "default_value": "", + "help": "" + }, + { + "name": "metadata-key", + "type": "", + "required": false, + "default_value": "", + "help": "" + } + ] +} \ No newline at end of file diff --git a/kclvm/api/src/testdata/list-variables.json b/kclvm/api/src/testdata/list-variables.json new file mode 100644 index 000000000..db27f88b9 --- /dev/null +++ b/kclvm/api/src/testdata/list-variables.json @@ -0,0 +1,4 @@ +{ + "files": ["./src/testdata/variables/main.k"], + "specs": ["a", "b", "c"] +} diff --git a/kclvm/api/src/testdata/list-variables.response.json b/kclvm/api/src/testdata/list-variables.response.json new file mode 100644 index 000000000..73d36da75 --- /dev/null +++ b/kclvm/api/src/testdata/list-variables.response.json @@ -0,0 +1,72 @@ +{ + "variables": { + "c": { + "variables": [ + { + "value": "{\n \"a\": \"b\"\n}", + "type_name": "", + "op_sym": "=", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "value": "\"b\"", + "type_name": "", + "op_sym": ":", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ] + }, + "a": { + "variables": [ + { + "value": "1", + "type_name": "", + "op_sym": "=", + "list_items": [], + "dict_entries": [] + } + ] + }, + "b": { + "variables": [ + { + "value": "[\n 1\n 2\n 3\n]", + "type_name": "", + "op_sym": "=", + "list_items": [ + { + "value": "1", + "type_name": "", + "op_sym": "", + "list_items": [], + "dict_entries": [] + }, + { + "value": "2", + "type_name": "", + "op_sym": "", + "list_items": [], + "dict_entries": [] + }, + { + "value": "3", + "type_name": "", + "op_sym": "", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + ] + } + }, + "unsupported_codes": [], + "parse_errors": [] +} \ No newline at end of file diff --git a/kclvm/api/src/testdata/load-settings-files.json b/kclvm/api/src/testdata/load-settings-files.json new file mode 100644 index 000000000..82126f579 --- /dev/null +++ b/kclvm/api/src/testdata/load-settings-files.json @@ -0,0 +1,6 @@ +{ + "work_dir": "./src/testdata/settings", + "files":[ + "./src/testdata/settings/kcl.yaml" + ] +} diff --git a/kclvm/api/src/testdata/load-settings-files.response.json b/kclvm/api/src/testdata/load-settings-files.response.json new file mode 100644 index 000000000..18e1b4e88 --- /dev/null +++ b/kclvm/api/src/testdata/load-settings-files.response.json @@ -0,0 +1,18 @@ +{ + "kcl_cli_configs": { + "files": [], + "output": "", + "overrides": [], + "path_selector": [], + "strict_range_check": true, + "disable_none": false, + "verbose": 0, + "debug": false + }, + "kcl_options": [ + { + "key": "key", + "value": "\"value\"" + } + ] +} \ No newline at end of file diff --git a/kclvm/api/src/testdata/option/main.k b/kclvm/api/src/testdata/option/main.k new file mode 100644 index 000000000..1f6edf46c --- /dev/null +++ b/kclvm/api/src/testdata/option/main.k @@ -0,0 +1,5 @@ +a = option("key1") +b = option("key2", required=True) +c = { + metadata.key = option("metadata-key") +} diff --git a/kclvm/api/src/testdata/override-file-bool.json b/kclvm/api/src/testdata/override-file-bool.json new file mode 100644 index 000000000..96bedbc3d --- /dev/null +++ b/kclvm/api/src/testdata/override-file-bool.json @@ -0,0 +1,7 @@ +{ + "file": "./src/testdata/override_bool.k", + "specs": [ + "isExist=False" + ], + "import_paths": [] +} \ No newline at end of file diff --git a/kclvm/api/src/testdata/override-file-bool.response.json b/kclvm/api/src/testdata/override-file-bool.response.json new file mode 100644 index 000000000..da895dacb --- /dev/null +++ b/kclvm/api/src/testdata/override-file-bool.response.json @@ -0,0 +1,3 @@ +{ + "result": true +} \ No newline at end of file diff --git a/kclvm/api/src/testdata/override-file-dict.json b/kclvm/api/src/testdata/override-file-dict.json new file mode 100644 index 000000000..8a0c2deaa --- /dev/null +++ b/kclvm/api/src/testdata/override-file-dict.json @@ -0,0 +1,7 @@ +{ + "file": "./src/testdata/override_dict.k", + "specs": [ + "alice1.age=18" + ], + "import_paths": [] +} \ No newline at end of file diff --git a/kclvm/api/src/testdata/override-file-dict.response.json b/kclvm/api/src/testdata/override-file-dict.response.json new file mode 100644 index 000000000..da895dacb --- /dev/null +++ b/kclvm/api/src/testdata/override-file-dict.response.json @@ -0,0 +1,3 @@ +{ + "result": true +} \ No newline at end of file diff --git a/kclvm/api/src/testdata/override-file-dict_0.json b/kclvm/api/src/testdata/override-file-dict_0.json new file mode 100644 index 000000000..a1576e775 --- /dev/null +++ b/kclvm/api/src/testdata/override-file-dict_0.json @@ -0,0 +1,7 @@ +{ + "file": "./src/testdata/override_dict_0.k", + "specs": [ + "alice3={\"age\": 18}" + ], + "import_paths": [] +} \ No newline at end of file diff --git a/kclvm/api/src/testdata/override-file-dict_0.response.json b/kclvm/api/src/testdata/override-file-dict_0.response.json new file mode 100644 index 000000000..da895dacb --- /dev/null +++ b/kclvm/api/src/testdata/override-file-dict_0.response.json @@ -0,0 +1,3 @@ +{ + "result": true +} \ No newline at end of file diff --git a/kclvm/api/src/testdata/override-file-list.json b/kclvm/api/src/testdata/override-file-list.json new file mode 100644 index 000000000..e42a01233 --- /dev/null +++ b/kclvm/api/src/testdata/override-file-list.json @@ -0,0 +1,7 @@ +{ + "file": "./src/testdata/override_list.k", + "specs": [ + "alice2=[1,2,3]" + ], + "import_paths": [] +} \ No newline at end of file diff --git a/kclvm/api/src/testdata/override-file-list.response.json b/kclvm/api/src/testdata/override-file-list.response.json new file mode 100644 index 000000000..da895dacb --- /dev/null +++ b/kclvm/api/src/testdata/override-file-list.response.json @@ -0,0 +1,3 @@ +{ + "result": true +} \ No newline at end of file diff --git a/kclvm/api/src/testdata/override-file.json b/kclvm/api/src/testdata/override-file.json new file mode 100644 index 000000000..f34d4c4a4 --- /dev/null +++ b/kclvm/api/src/testdata/override-file.json @@ -0,0 +1,7 @@ +{ + "file": "./src/testdata/test.k", + "specs": [ + "alice.age=18" + ], + "import_paths": [] +} \ No newline at end of file diff --git a/kclvm/api/src/testdata/override-file.response.json b/kclvm/api/src/testdata/override-file.response.json new file mode 100644 index 000000000..da895dacb --- /dev/null +++ b/kclvm/api/src/testdata/override-file.response.json @@ -0,0 +1,3 @@ +{ + "result": true +} \ No newline at end of file diff --git a/kclvm/api/src/testdata/override_bool.k b/kclvm/api/src/testdata/override_bool.k new file mode 100644 index 000000000..f3631c0d3 --- /dev/null +++ b/kclvm/api/src/testdata/override_bool.k @@ -0,0 +1 @@ +isExist = False diff --git a/kclvm/api/src/testdata/override_dict.k b/kclvm/api/src/testdata/override_dict.k new file mode 100644 index 000000000..6f5825d9a --- /dev/null +++ b/kclvm/api/src/testdata/override_dict.k @@ -0,0 +1 @@ +alice1 = {"age": 18} diff --git a/kclvm/api/src/testdata/override_dict_0.k b/kclvm/api/src/testdata/override_dict_0.k new file mode 100644 index 000000000..a739134d4 --- /dev/null +++ b/kclvm/api/src/testdata/override_dict_0.k @@ -0,0 +1 @@ +alice3 = {"age": 18} diff --git a/kclvm/api/src/testdata/override_list.k b/kclvm/api/src/testdata/override_list.k new file mode 100644 index 000000000..90627ec8e --- /dev/null +++ b/kclvm/api/src/testdata/override_list.k @@ -0,0 +1 @@ +alice2 = [1, 2, 3] diff --git a/kclvm/api/src/testdata/parse-file.json b/kclvm/api/src/testdata/parse-file.json new file mode 100644 index 000000000..c55faaeac --- /dev/null +++ b/kclvm/api/src/testdata/parse-file.json @@ -0,0 +1,4 @@ +{ + "path": "source.k", + "source": "import units\nimport data.cloud as cloud_pkg\n\ndata1 = 32 * units.Ki\nData2 = 42 * units.Ki * cloud_pkg.Foo\n\nlambda1 = lambda x: int, y: int -> int {\n x - y\n}\nLambda2 = lambda x: int, y: int -> int {\n x + y\n}\n" +} diff --git a/kclvm/api/src/testdata/parse-file.response.json b/kclvm/api/src/testdata/parse-file.response.json new file mode 100644 index 000000000..ec6068f5d --- /dev/null +++ b/kclvm/api/src/testdata/parse-file.response.json @@ -0,0 +1,48 @@ +{ + "ast_json": "{\"filename\":\"source.k\",\"doc\":null,\"body\":[{\"node\":{\"type\":\"Import\",\"path\":{\"node\":\"units\",\"filename\":\"source.k\",\"line\":1,\"column\":7,\"end_line\":1,\"end_column\":12},\"rawpath\":\"units\",\"name\":\"units\",\"asname\":null,\"pkg_name\":\"__main__\"},\"filename\":\"source.k\",\"line\":1,\"column\":0,\"end_line\":1,\"end_column\":12},{\"node\":{\"type\":\"Import\",\"path\":{\"node\":\"data.cloud\",\"filename\":\"source.k\",\"line\":2,\"column\":7,\"end_line\":2,\"end_column\":17},\"rawpath\":\"data.cloud\",\"name\":\"cloud_pkg\",\"asname\":{\"node\":\"cloud_pkg\",\"filename\":\"source.k\",\"line\":2,\"column\":21,\"end_line\":2,\"end_column\":30},\"pkg_name\":\"__main__\"},\"filename\":\"source.k\",\"line\":2,\"column\":0,\"end_line\":2,\"end_column\":30},{\"node\":{\"type\":\"Assign\",\"targets\":[{\"node\":{\"name\":{\"node\":\"data1\",\"filename\":\"source.k\",\"line\":4,\"column\":0,\"end_line\":4,\"end_column\":5},\"paths\":[],\"pkgpath\":\"\"},\"filename\":\"source.k\",\"line\":4,\"column\":0,\"end_line\":4,\"end_column\":5}],\"value\":{\"node\":{\"type\":\"Binary\",\"left\":{\"node\":{\"type\":\"NumberLit\",\"binary_suffix\":null,\"value\":{\"type\":\"Int\",\"value\":32}},\"filename\":\"source.k\",\"line\":4,\"column\":8,\"end_line\":4,\"end_column\":10},\"op\":\"Mul\",\"right\":{\"node\":{\"type\":\"Identifier\",\"names\":[{\"node\":\"units\",\"filename\":\"source.k\",\"line\":4,\"column\":13,\"end_line\":4,\"end_column\":18},{\"node\":\"Ki\",\"filename\":\"source.k\",\"line\":4,\"column\":19,\"end_line\":4,\"end_column\":21}],\"pkgpath\":\"\",\"ctx\":\"Load\"},\"filename\":\"source.k\",\"line\":4,\"column\":13,\"end_line\":4,\"end_column\":21}},\"filename\":\"source.k\",\"line\":4,\"column\":8,\"end_line\":4,\"end_column\":21},\"ty\":null},\"filename\":\"source.k\",\"line\":4,\"column\":0,\"end_line\":4,\"end_column\":21},{\"node\":{\"type\":\"Assign\",\"targets\":[{\"node\":{\"name\":{\"node\":\"Data2\",\"filename\":\"source.k\",\"line\":5,\"column\":0,\"end_line\":5,\"end_column\":5},\"paths\":[],\"pkgpath\":\"\"},\"filename\":\"source.k\",\"line\":5,\"column\":0,\"end_line\":5,\"end_column\":5}],\"value\":{\"node\":{\"type\":\"Binary\",\"left\":{\"node\":{\"type\":\"Binary\",\"left\":{\"node\":{\"type\":\"NumberLit\",\"binary_suffix\":null,\"value\":{\"type\":\"Int\",\"value\":42}},\"filename\":\"source.k\",\"line\":5,\"column\":8,\"end_line\":5,\"end_column\":10},\"op\":\"Mul\",\"right\":{\"node\":{\"type\":\"Identifier\",\"names\":[{\"node\":\"units\",\"filename\":\"source.k\",\"line\":5,\"column\":13,\"end_line\":5,\"end_column\":18},{\"node\":\"Ki\",\"filename\":\"source.k\",\"line\":5,\"column\":19,\"end_line\":5,\"end_column\":21}],\"pkgpath\":\"\",\"ctx\":\"Load\"},\"filename\":\"source.k\",\"line\":5,\"column\":13,\"end_line\":5,\"end_column\":21}},\"filename\":\"source.k\",\"line\":5,\"column\":8,\"end_line\":5,\"end_column\":21},\"op\":\"Mul\",\"right\":{\"node\":{\"type\":\"Identifier\",\"names\":[{\"node\":\"cloud_pkg\",\"filename\":\"source.k\",\"line\":5,\"column\":24,\"end_line\":5,\"end_column\":33},{\"node\":\"Foo\",\"filename\":\"source.k\",\"line\":5,\"column\":34,\"end_line\":5,\"end_column\":37}],\"pkgpath\":\"\",\"ctx\":\"Load\"},\"filename\":\"source.k\",\"line\":5,\"column\":24,\"end_line\":5,\"end_column\":37}},\"filename\":\"source.k\",\"line\":5,\"column\":8,\"end_line\":5,\"end_column\":37},\"ty\":null},\"filename\":\"source.k\",\"line\":5,\"column\":0,\"end_line\":5,\"end_column\":37},{\"node\":{\"type\":\"Assign\",\"targets\":[{\"node\":{\"name\":{\"node\":\"lambda1\",\"filename\":\"source.k\",\"line\":7,\"column\":0,\"end_line\":7,\"end_column\":7},\"paths\":[],\"pkgpath\":\"\"},\"filename\":\"source.k\",\"line\":7,\"column\":0,\"end_line\":7,\"end_column\":7}],\"value\":{\"node\":{\"type\":\"Lambda\",\"args\":{\"node\":{\"args\":[{\"node\":{\"names\":[{\"node\":\"x\",\"filename\":\"source.k\",\"line\":7,\"column\":17,\"end_line\":7,\"end_column\":18}],\"pkgpath\":\"\",\"ctx\":\"Load\"},\"filename\":\"source.k\",\"line\":7,\"column\":17,\"end_line\":7,\"end_column\":18},{\"node\":{\"names\":[{\"node\":\"y\",\"filename\":\"source.k\",\"line\":7,\"column\":25,\"end_line\":7,\"end_column\":26}],\"pkgpath\":\"\",\"ctx\":\"Load\"},\"filename\":\"source.k\",\"line\":7,\"column\":25,\"end_line\":7,\"end_column\":26}],\"defaults\":[null,null],\"ty_list\":[{\"node\":{\"type\":\"Basic\",\"value\":\"Int\"},\"filename\":\"source.k\",\"line\":7,\"column\":20,\"end_line\":7,\"end_column\":23},{\"node\":{\"type\":\"Basic\",\"value\":\"Int\"},\"filename\":\"source.k\",\"line\":7,\"column\":28,\"end_line\":7,\"end_column\":31}]},\"filename\":\"source.k\",\"line\":7,\"column\":17,\"end_line\":7,\"end_column\":31},\"body\":[{\"node\":{\"type\":\"Expr\",\"exprs\":[{\"node\":{\"type\":\"Binary\",\"left\":{\"node\":{\"type\":\"Identifier\",\"names\":[{\"node\":\"x\",\"filename\":\"source.k\",\"line\":8,\"column\":4,\"end_line\":8,\"end_column\":5}],\"pkgpath\":\"\",\"ctx\":\"Load\"},\"filename\":\"source.k\",\"line\":8,\"column\":4,\"end_line\":8,\"end_column\":5},\"op\":\"Sub\",\"right\":{\"node\":{\"type\":\"Identifier\",\"names\":[{\"node\":\"y\",\"filename\":\"source.k\",\"line\":8,\"column\":8,\"end_line\":8,\"end_column\":9}],\"pkgpath\":\"\",\"ctx\":\"Load\"},\"filename\":\"source.k\",\"line\":8,\"column\":8,\"end_line\":8,\"end_column\":9}},\"filename\":\"source.k\",\"line\":8,\"column\":4,\"end_line\":8,\"end_column\":9}]},\"filename\":\"source.k\",\"line\":8,\"column\":4,\"end_line\":8,\"end_column\":9}],\"return_ty\":{\"node\":{\"type\":\"Basic\",\"value\":\"Int\"},\"filename\":\"source.k\",\"line\":7,\"column\":35,\"end_line\":7,\"end_column\":38}},\"filename\":\"source.k\",\"line\":7,\"column\":10,\"end_line\":9,\"end_column\":1},\"ty\":null},\"filename\":\"source.k\",\"line\":7,\"column\":0,\"end_line\":9,\"end_column\":1},{\"node\":{\"type\":\"Assign\",\"targets\":[{\"node\":{\"name\":{\"node\":\"Lambda2\",\"filename\":\"source.k\",\"line\":10,\"column\":0,\"end_line\":10,\"end_column\":7},\"paths\":[],\"pkgpath\":\"\"},\"filename\":\"source.k\",\"line\":10,\"column\":0,\"end_line\":10,\"end_column\":7}],\"value\":{\"node\":{\"type\":\"Lambda\",\"args\":{\"node\":{\"args\":[{\"node\":{\"names\":[{\"node\":\"x\",\"filename\":\"source.k\",\"line\":10,\"column\":17,\"end_line\":10,\"end_column\":18}],\"pkgpath\":\"\",\"ctx\":\"Load\"},\"filename\":\"source.k\",\"line\":10,\"column\":17,\"end_line\":10,\"end_column\":18},{\"node\":{\"names\":[{\"node\":\"y\",\"filename\":\"source.k\",\"line\":10,\"column\":25,\"end_line\":10,\"end_column\":26}],\"pkgpath\":\"\",\"ctx\":\"Load\"},\"filename\":\"source.k\",\"line\":10,\"column\":25,\"end_line\":10,\"end_column\":26}],\"defaults\":[null,null],\"ty_list\":[{\"node\":{\"type\":\"Basic\",\"value\":\"Int\"},\"filename\":\"source.k\",\"line\":10,\"column\":20,\"end_line\":10,\"end_column\":23},{\"node\":{\"type\":\"Basic\",\"value\":\"Int\"},\"filename\":\"source.k\",\"line\":10,\"column\":28,\"end_line\":10,\"end_column\":31}]},\"filename\":\"source.k\",\"line\":10,\"column\":17,\"end_line\":10,\"end_column\":31},\"body\":[{\"node\":{\"type\":\"Expr\",\"exprs\":[{\"node\":{\"type\":\"Binary\",\"left\":{\"node\":{\"type\":\"Identifier\",\"names\":[{\"node\":\"x\",\"filename\":\"source.k\",\"line\":11,\"column\":4,\"end_line\":11,\"end_column\":5}],\"pkgpath\":\"\",\"ctx\":\"Load\"},\"filename\":\"source.k\",\"line\":11,\"column\":4,\"end_line\":11,\"end_column\":5},\"op\":\"Add\",\"right\":{\"node\":{\"type\":\"Identifier\",\"names\":[{\"node\":\"y\",\"filename\":\"source.k\",\"line\":11,\"column\":8,\"end_line\":11,\"end_column\":9}],\"pkgpath\":\"\",\"ctx\":\"Load\"},\"filename\":\"source.k\",\"line\":11,\"column\":8,\"end_line\":11,\"end_column\":9}},\"filename\":\"source.k\",\"line\":11,\"column\":4,\"end_line\":11,\"end_column\":9}]},\"filename\":\"source.k\",\"line\":11,\"column\":4,\"end_line\":11,\"end_column\":9}],\"return_ty\":{\"node\":{\"type\":\"Basic\",\"value\":\"Int\"},\"filename\":\"source.k\",\"line\":10,\"column\":35,\"end_line\":10,\"end_column\":38}},\"filename\":\"source.k\",\"line\":10,\"column\":10,\"end_line\":12,\"end_column\":1},\"ty\":null},\"filename\":\"source.k\",\"line\":10,\"column\":0,\"end_line\":12,\"end_column\":1}],\"comments\":[]}", + "deps": [], + "errors": [ + { + "level": "error", + "code": "Error(CannotFindModule)", + "messages": [ + { + "msg": "pkgpath data.cloud not found in the program", + "pos": { + "line": 2, + "column": 0, + "filename": "source.k" + } + } + ] + }, + { + "level": "suggestions", + "code": "Suggestions", + "messages": [ + { + "msg": "try 'kcl mod add data' to download the missing package", + "pos": { + "line": 0, + "column": 0, + "filename": "" + } + } + ] + }, + { + "level": "suggestions", + "code": "Suggestions", + "messages": [ + { + "msg": "browse more packages at 'https://artifacthub.io'", + "pos": { + "line": 0, + "column": 0, + "filename": "" + } + } + ] + } + ] +} \ No newline at end of file diff --git a/test/grammar/import/empty_import_fail/kcl.mod b/kclvm/api/src/testdata/parse/kcl.mod similarity index 100% rename from test/grammar/import/empty_import_fail/kcl.mod rename to kclvm/api/src/testdata/parse/kcl.mod diff --git a/kclvm/api/src/testdata/parse/main.k b/kclvm/api/src/testdata/parse/main.k new file mode 100644 index 000000000..1f0792f7b --- /dev/null +++ b/kclvm/api/src/testdata/parse/main.k @@ -0,0 +1,5 @@ +import pkg1 +import pkg2 + +a1 = pkg1.a +a2 = pkg2.a diff --git a/test/test_units/test_kclvm/test_compiler/test_build/invalid_testdata/pkg/pkg.k b/kclvm/api/src/testdata/parse/pkg1/pkg.k similarity index 100% rename from test/test_units/test_kclvm/test_compiler/test_build/invalid_testdata/pkg/pkg.k rename to kclvm/api/src/testdata/parse/pkg1/pkg.k diff --git a/test/test_units/test_kclvm/test_compiler/test_vfs/test_data_bytecode_cache/pkg/pkg.k b/kclvm/api/src/testdata/parse/pkg2/pkg.k similarity index 100% rename from test/test_units/test_kclvm/test_compiler/test_vfs/test_data_bytecode_cache/pkg/pkg.k rename to kclvm/api/src/testdata/parse/pkg2/pkg.k diff --git a/kclvm/api/src/testdata/rename-code.json b/kclvm/api/src/testdata/rename-code.json new file mode 100644 index 000000000..effad17c9 --- /dev/null +++ b/kclvm/api/src/testdata/rename-code.json @@ -0,0 +1,6 @@ +{ + "package_root": "/mock/path", + "source_codes": {"/mock/path/main.k": "a = 1\nb = a"}, + "symbol_path": "a", + "new_name": "a2" +} diff --git a/kclvm/api/src/testdata/rename-code.response.json b/kclvm/api/src/testdata/rename-code.response.json new file mode 100644 index 000000000..d71f32d5c --- /dev/null +++ b/kclvm/api/src/testdata/rename-code.response.json @@ -0,0 +1,3 @@ +{ + "changed_codes": {"/mock/path/main.k": "a2 = 1\nb = a2"} +} \ No newline at end of file diff --git a/kclvm/api/src/testdata/rename.json b/kclvm/api/src/testdata/rename.json new file mode 100644 index 000000000..38f0cbb86 --- /dev/null +++ b/kclvm/api/src/testdata/rename.json @@ -0,0 +1,6 @@ +{ + "package_root": "./src/testdata/rename/", + "file_paths": ["./src/testdata/rename/main.k"], + "symbol_path": "a", + "new_name": "a2" +} diff --git a/kclvm/api/src/testdata/rename.response.json b/kclvm/api/src/testdata/rename.response.json new file mode 100644 index 000000000..c171a4b0b --- /dev/null +++ b/kclvm/api/src/testdata/rename.response.json @@ -0,0 +1,3 @@ +{ + "changed_files": ["./src/testdata/rename/main.k"] +} \ No newline at end of file diff --git a/kclvm/api/src/testdata/rename/main.bak b/kclvm/api/src/testdata/rename/main.bak new file mode 100644 index 000000000..3a0fa5834 --- /dev/null +++ b/kclvm/api/src/testdata/rename/main.bak @@ -0,0 +1,2 @@ +a = 1 +b = a \ No newline at end of file diff --git a/kclvm/api/src/testdata/rename_doc/main.bak b/kclvm/api/src/testdata/rename_doc/main.bak new file mode 100644 index 000000000..3a0fa5834 --- /dev/null +++ b/kclvm/api/src/testdata/rename_doc/main.bak @@ -0,0 +1,2 @@ +a = 1 +b = a \ No newline at end of file diff --git a/kclvm/api/src/testdata/settings/kcl.yaml b/kclvm/api/src/testdata/settings/kcl.yaml new file mode 100644 index 000000000..7b7300d71 --- /dev/null +++ b/kclvm/api/src/testdata/settings/kcl.yaml @@ -0,0 +1,5 @@ +kcl_cli_configs: + strict_range_check: true +kcl_options: + - key: key + value: value diff --git a/kclvm/api/src/testdata/test-lint-import.k b/kclvm/api/src/testdata/test-lint-import.k new file mode 100644 index 000000000..c452e62cd --- /dev/null +++ b/kclvm/api/src/testdata/test-lint-import.k @@ -0,0 +1,4 @@ +import external as ext +import external_1 as ext_1 + +a1 = ext_1.a \ No newline at end of file diff --git a/kclvm/api/src/testdata/test-lint.k b/kclvm/api/src/testdata/test-lint.k new file mode 100644 index 000000000..0f43f2af1 --- /dev/null +++ b/kclvm/api/src/testdata/test-lint.k @@ -0,0 +1 @@ +import math diff --git a/kclvm/api/src/testdata/test-validate.json b/kclvm/api/src/testdata/test-validate.json new file mode 100644 index 000000000..cafe9fd3c --- /dev/null +++ b/kclvm/api/src/testdata/test-validate.json @@ -0,0 +1,10 @@ +{ + "foo": "ThehFoo", + "bar": 2, + "fooList": [ + "a", + "b" + ], + "color": "Red", + "id": 100 +} \ No newline at end of file diff --git a/kclvm/api/src/testdata/test.json b/kclvm/api/src/testdata/test.json new file mode 100644 index 000000000..8ab1bd206 --- /dev/null +++ b/kclvm/api/src/testdata/test.json @@ -0,0 +1,3 @@ +{ + "pkg_list": ["./src/testdata/testing/module/..."] +} diff --git a/kclvm/api/src/testdata/test.k b/kclvm/api/src/testdata/test.k new file mode 100644 index 000000000..d7766298b --- /dev/null +++ b/kclvm/api/src/testdata/test.k @@ -0,0 +1,4 @@ +schema Person: + age: int + +alice = Person {age = 18} diff --git a/kclvm/api/src/testdata/test.response.json b/kclvm/api/src/testdata/test.response.json new file mode 100644 index 000000000..969db3e7f --- /dev/null +++ b/kclvm/api/src/testdata/test.response.json @@ -0,0 +1,14 @@ +{ + "info": [ + { + "name": "test_func_0", + "error": "", + "log_message": "" + }, + { + "name": "test_func_1", + "error": "", + "log_message": "" + } + ] +} \ No newline at end of file diff --git a/kclvm/api/src/testdata/test_call.k b/kclvm/api/src/testdata/test_call.k new file mode 100644 index 000000000..40c6fcaff --- /dev/null +++ b/kclvm/api/src/testdata/test_call.k @@ -0,0 +1,4 @@ +schema Config: + name?: str + +config = Config {} diff --git a/kclvm/api/src/testdata/testing/module/kcl.mod b/kclvm/api/src/testdata/testing/module/kcl.mod new file mode 100644 index 000000000..35d888aa7 --- /dev/null +++ b/kclvm/api/src/testdata/testing/module/kcl.mod @@ -0,0 +1,3 @@ +[package] +name = "test_data" + diff --git a/kclvm/api/src/testdata/testing/module/pkg/func.k b/kclvm/api/src/testdata/testing/module/pkg/func.k new file mode 100644 index 000000000..26df9cf5a --- /dev/null +++ b/kclvm/api/src/testdata/testing/module/pkg/func.k @@ -0,0 +1,3 @@ +func = lambda x { + x +} diff --git a/kclvm/api/src/testdata/testing/module/pkg/func_test.k b/kclvm/api/src/testdata/testing/module/pkg/func_test.k new file mode 100644 index 000000000..b02295046 --- /dev/null +++ b/kclvm/api/src/testdata/testing/module/pkg/func_test.k @@ -0,0 +1,7 @@ +test_func_0 = lambda { + assert func("a") == "a" +} + +test_func_1 = lambda { + assert func("b") == "b" +} diff --git a/kclvm/api/src/testdata/update_dependencies/kcl.mod b/kclvm/api/src/testdata/update_dependencies/kcl.mod new file mode 100644 index 000000000..33fd0c452 --- /dev/null +++ b/kclvm/api/src/testdata/update_dependencies/kcl.mod @@ -0,0 +1,6 @@ +[package] +name = "update_dependencies" +version = "0.0.1" + +[dependencies] +helloworld = { oci = "oci://ghcr.io/kcl-lang/helloworld", tag = "0.1.0" } diff --git a/kclvm/api/src/testdata/validate-code-file.json b/kclvm/api/src/testdata/validate-code-file.json new file mode 100644 index 000000000..5f94a5836 --- /dev/null +++ b/kclvm/api/src/testdata/validate-code-file.json @@ -0,0 +1,4 @@ +{ + "code": "import regex\n\nschema Sample:\n foo: str\n bar: int\n fooList: [str]\n color: \"Red\" | \"Yellow\" | \"Blue\"\n id?: int\n \n check:\n bar >= 0\n bar < 100\n len(fooList) > 0\n len(fooList) < 100\n regex.match(foo, \"^The.*Foo$\")\n bar in range(100)\n bar in [2, 4, 6, 8]\n bar % 2 == 0\n abs(id) > 10 if id is not None\n", + "datafile": "./src/testdata/test-validate.json" +} diff --git a/kclvm/api/src/testdata/validate-code-file.response.json b/kclvm/api/src/testdata/validate-code-file.response.json new file mode 100644 index 000000000..9fadf3dd6 --- /dev/null +++ b/kclvm/api/src/testdata/validate-code-file.response.json @@ -0,0 +1,4 @@ +{ + "success": true, + "err_message": "" +} \ No newline at end of file diff --git a/kclvm/api/src/testdata/validate-code.json b/kclvm/api/src/testdata/validate-code.json new file mode 100644 index 000000000..c476e4f12 --- /dev/null +++ b/kclvm/api/src/testdata/validate-code.json @@ -0,0 +1,4 @@ +{ + "code": "import regex\n\nschema Sample:\n foo: str # Required, 不能为None, 且类型必须为str\n bar: int # Required, 不能为None, 且类型必须为int\n fooList: [str] # Required, 不能为None, 且类型必须为str列表\n color: \"Red\" | \"Yellow\" | \"Blue\" # Required, 字面值联合类型,且必须为\"Red\", \"Yellow\", \"Blue\"中的一个,枚举作用\n id?: int # Optional,可以留空,类型必须为int\n \n check:\n bar >= 0 # bar必须大于等于0\n bar < 100 # bar必须小于100\n len(fooList) > 0 # fooList不能为None,并且长度必须大于0\n len(fooList) < 100 # fooList不能为None,并且长度必须小于100\n regex.match(foo, \"^The.*Foo$\") # regex 正则表达式匹配\n bar in range(100) # range, bar范围只能为1到99\n bar in [2, 4, 6, 8] # enum, bar只能取2, 4, 6, 8\n bar % 2 == 0 # bar必须为2的倍数\n abs(id) > 10 if id is not None # check if 表达式,当 id 不为空时,id的绝对值必须大于10\n", + "data": "{\n \"foo\": \"ThehFoo\",\n \"bar\": 2,\n \"fooList\": [\n \"a\",\n \"b\"\n ],\n \"color\": \"Red\",\n \"id\": 100\n}" +} diff --git a/kclvm/api/src/testdata/validate-code.response.json b/kclvm/api/src/testdata/validate-code.response.json new file mode 100644 index 000000000..9fadf3dd6 --- /dev/null +++ b/kclvm/api/src/testdata/validate-code.response.json @@ -0,0 +1,4 @@ +{ + "success": true, + "err_message": "" +} \ No newline at end of file diff --git a/kclvm/api/src/testdata/variables/main.k b/kclvm/api/src/testdata/variables/main.k new file mode 100644 index 000000000..23979c52c --- /dev/null +++ b/kclvm/api/src/testdata/variables/main.k @@ -0,0 +1,3 @@ +a = 1 +b = [1, 2, 3] +c = {"a": "b"} \ No newline at end of file diff --git a/kclvm/api/src/testdata_external/external/kcl.mod b/kclvm/api/src/testdata_external/external/kcl.mod new file mode 100644 index 000000000..657517ec5 --- /dev/null +++ b/kclvm/api/src/testdata_external/external/kcl.mod @@ -0,0 +1,6 @@ +[package] +name = "external" +edition = "0.0.1" +version = "0.0.1" + +[dependencies] \ No newline at end of file diff --git a/kclvm/api/src/testdata_external/external/main.k b/kclvm/api/src/testdata_external/external/main.k new file mode 100644 index 000000000..f2dfb89dd --- /dev/null +++ b/kclvm/api/src/testdata_external/external/main.k @@ -0,0 +1 @@ +a = 'Hello External World!' \ No newline at end of file diff --git a/kclvm/api/src/testdata_external/external_1/kcl.mod b/kclvm/api/src/testdata_external/external_1/kcl.mod new file mode 100644 index 000000000..3ecf139af --- /dev/null +++ b/kclvm/api/src/testdata_external/external_1/kcl.mod @@ -0,0 +1,6 @@ +[package] +name = "external_1" +edition = "0.0.1" +version = "0.0.1" + +[dependencies] \ No newline at end of file diff --git a/kclvm/api/src/testdata_external/external_1/main.k b/kclvm/api/src/testdata_external/external_1/main.k new file mode 100644 index 000000000..aa278d78a --- /dev/null +++ b/kclvm/api/src/testdata_external/external_1/main.k @@ -0,0 +1 @@ +a = 'Hello External_1 World!' \ No newline at end of file diff --git a/kclvm/ast/Cargo.lock b/kclvm/ast/Cargo.lock index d7fa326c8..dc0cb57cc 100644 --- a/kclvm/ast/Cargo.lock +++ b/kclvm/ast/Cargo.lock @@ -2,24 +2,91 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "ahash" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" +dependencies = [ + "getrandom", + "once_cell", + "version_check", +] + +[[package]] +name = "aho-corasick" +version = "0.7.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" +dependencies = [ + "memchr", +] + +[[package]] +name = "annotate-snippets" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d78ea013094e5ea606b1c05fe35f1dd7ea1eb1ea259908d040b25bd5ec677ee5" + [[package]] name = "arrayvec" version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6" +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi", + "libc", + "winapi", +] + [[package]] name = "autocfg" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +[[package]] +name = "base64" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" + +[[package]] +name = "bit-set" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e11e16035ea35e4e5997b393eacbf6f63983188f7a2ad25bfb13465f5ad59de" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" + [[package]] name = "bitflags" version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "block-buffer" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +dependencies = [ + "generic-array", +] + [[package]] name = "block-buffer" version = "0.10.2" @@ -29,6 +96,17 @@ dependencies = [ "generic-array", ] +[[package]] +name = "bstr" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223" +dependencies = [ + "lazy_static", + "memchr", + "regex-automata", +] + [[package]] name = "cc" version = "1.0.73" @@ -47,6 +125,19 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "chrono" +version = "0.4.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73" +dependencies = [ + "libc", + "num-integer", + "num-traits", + "time", + "winapi", +] + [[package]] name = "cpufeatures" version = "0.2.2" @@ -101,13 +192,22 @@ dependencies = [ "typenum", ] +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array", +] + [[package]] name = "digest" version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2fb860ca6fafa5552fb6d0e816a69c8e49f0908bf524e30a90d97c85892d506" dependencies = [ - "block-buffer", + "block-buffer 0.10.2", "crypto-common", ] @@ -126,6 +226,25 @@ dependencies = [ "log", ] +[[package]] +name = "enquote" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06c36cb11dbde389f4096111698d8b567c0720e3452fd5ac3e6b4e47e1939932" +dependencies = [ + "thiserror", +] + +[[package]] +name = "fancy-regex" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d6b8560a05112eb52f04b00e5d3790c0dd75d9d980eb8a122fb23b92a623ccf" +dependencies = [ + "bit-set", + "regex", +] + [[package]] name = "fastrand" version = "1.7.0" @@ -135,6 +254,34 @@ dependencies = [ "instant", ] +[[package]] +name = "fixedbitset" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "279fb028e20b3c4c320317955b77c5e0c9701f05a1d309905d6fc702cdc5053e" + +[[package]] +name = "fslock" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04412b8935272e3a9bae6f48c7bfff74c2911f60525404edfdd28e49884c3bfb" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "fuchsia-cprng" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" + +[[package]] +name = "gcc" +version = "0.3.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f5f3913fa0bfe7ee1fd8248b6b9f42a5af4b9d65ec2dd2c3c26132b950ecfc2" + [[package]] name = "generic-array" version = "0.14.5" @@ -145,6 +292,23 @@ dependencies = [ "version_check", ] +[[package]] +name = "getrandom" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9be70c98951c83b8d2f8f60d7065fa6d5146873094452a1008da8c2f1e4205ad" +dependencies = [ + "cfg-if 1.0.0", + "libc", + "wasi", +] + +[[package]] +name = "glob" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" + [[package]] name = "hashbrown" version = "0.11.2" @@ -180,6 +344,15 @@ dependencies = [ "cfg-if 1.0.0", ] +[[package]] +name = "itertools" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "1.0.1" @@ -195,16 +368,63 @@ dependencies = [ "libc", ] +[[package]] +name = "json_minimal" +version = "0.1.3" + [[package]] name = "kclvm-ast" version = "0.1.0" dependencies = [ + "kclvm-parser", "kclvm-span", "rustc_span", "serde", "serde_json", ] +[[package]] +name = "kclvm-config" +version = "0.1.0" +dependencies = [ + "ahash", + "chrono", + "fslock", + "glob", + "indexmap", + "kclvm-version", + "pathdiff", + "ron", + "rust-crypto", + "serde", + "serde_yaml", + "toml", +] + +[[package]] +name = "kclvm-error" +version = "0.1.0" +dependencies = [ + "annotate-snippets", + "atty", + "indexmap", + "kclvm-runtime", + "kclvm-span", + "rustc_span", + "termcolor", + "termize", + "tracing", +] + +[[package]] +name = "kclvm-lexer" +version = "0.1.0" +dependencies = [ + "kclvm-error", + "rustc_lexer", + "unic-emoji-char", +] + [[package]] name = "kclvm-macros" version = "0.1.0" @@ -215,6 +435,77 @@ dependencies = [ "synstructure", ] +[[package]] +name = "kclvm-parser" +version = "0.1.0" +dependencies = [ + "bstr", + "either", + "enquote", + "kclvm-ast", + "kclvm-config", + "kclvm-error", + "kclvm-lexer", + "kclvm-runtime", + "kclvm-sema", + "kclvm-span", + "num-bigint", + "rustc_data_structures", + "rustc_lexer", + "rustc_span", + "serde", + "serde_json", + "tracing", + "unicode_names2", +] + +[[package]] +name = "kclvm-runtime" +version = "0.1.0" +dependencies = [ + "ahash", + "base64", + "bstr", + "chrono", + "fancy-regex", + "indexmap", + "itertools", + "json_minimal", + "kclvm_runtime_internal_macros", + "libc", + "md5", + "num-integer", + "phf", + "regex", + "serde", + "serde_json", + "serde_yaml", + "sha1", + "sha2 0.9.9", + "unic-ucd-bidi", + "unic-ucd-category", + "unicode-casing", +] + +[[package]] +name = "kclvm-sema" +version = "0.1.0" +dependencies = [ + "ahash", + "bit-set", + "bitflags", + "fancy-regex", + "indexmap", + "kclvm-ast", + "kclvm-error", + "kclvm-runtime", + "kclvm-span", + "once_cell", + "petgraph", + "phf", + "unicode_names2", +] + [[package]] name = "kclvm-span" version = "0.1.0" @@ -224,6 +515,19 @@ dependencies = [ "scoped-tls", ] +[[package]] +name = "kclvm-version" +version = "0.1.0" + +[[package]] +name = "kclvm_runtime_internal_macros" +version = "0.1.0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "lazy_static" version = "1.4.0" @@ -236,6 +540,12 @@ version = "0.2.124" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "21a41fed9d98f27ab1c6d161da622a4fa35e8a54a8adc24bbf3ddd0ef70b0e50" +[[package]] +name = "linked-hash-map" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fb9b38af92608140b86b693604b9ffcc5824240a484d1ecd4795bacb2fe88f3" + [[package]] name = "lock_api" version = "0.4.7" @@ -255,15 +565,33 @@ dependencies = [ "cfg-if 1.0.0", ] +[[package]] +name = "matches" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" + [[package]] name = "md-5" version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "658646b21e0b72f7866c7038ab086d3d5e1cd6271f060fd37defb241949d0582" dependencies = [ - "digest", + "digest 0.10.3", ] +[[package]] +name = "md5" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "490cc448043f947bae3cbee9c203358d62dbee0db12107a74be5c30ccfd09771" + +[[package]] +name = "memchr" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" + [[package]] name = "memmap2" version = "0.2.3" @@ -282,6 +610,36 @@ dependencies = [ "autocfg", ] +[[package]] +name = "num-bigint" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-integer" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +dependencies = [ + "autocfg", +] + [[package]] name = "num_cpus" version = "1.13.1" @@ -292,6 +650,18 @@ dependencies = [ "libc", ] +[[package]] +name = "once_cell" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7709cef83f0c1f58f666e746a08b21e0085f7440fa6a29cc194d68aac97a4225" + +[[package]] +name = "opaque-debug" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" + [[package]] name = "parking_lot" version = "0.12.0" @@ -315,12 +685,84 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "pathdiff" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd" + +[[package]] +name = "petgraph" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5014253a1331579ce62aa67443b4a658c5e7dd03d4bc6d302b94474888143" +dependencies = [ + "fixedbitset", + "indexmap", +] + +[[package]] +name = "phf" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2ac8b67553a7ca9457ce0e526948cad581819238f4a9d1ea74545851fa24f37" +dependencies = [ + "phf_macros", + "phf_shared", + "proc-macro-hack", +] + +[[package]] +name = "phf_generator" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d43f3220d96e0080cc9ea234978ccd80d904eafb17be31bb0f76daaea6493082" +dependencies = [ + "phf_shared", + "rand 0.8.5", +] + +[[package]] +name = "phf_macros" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b706f5936eb50ed880ae3009395b43ed19db5bff2ebd459c95e7bf013a89ab86" +dependencies = [ + "phf_generator", + "phf_shared", + "proc-macro-hack", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "phf_shared" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a68318426de33640f02be62b4ae8eb1261be2efbc337b60c54d845bf4484e0d9" +dependencies = [ + "siphasher", +] + [[package]] name = "pin-project-lite" version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e280fbe77cc62c91527259e9442153f4688736748d24660126286329742b4c6c" +[[package]] +name = "ppv-lite86" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" + +[[package]] +name = "proc-macro-hack" +version = "0.5.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" + [[package]] name = "proc-macro2" version = "1.0.37" @@ -348,6 +790,83 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "rand" +version = "0.3.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64ac302d8f83c0c1974bf758f6b041c6c8ada916fbb44a609158ca8b064cc76c" +dependencies = [ + "libc", + "rand 0.4.6", +] + +[[package]] +name = "rand" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" +dependencies = [ + "fuchsia-cprng", + "libc", + "rand_core 0.3.1", + "rdrand", + "winapi", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core 0.6.3", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.3", +] + +[[package]] +name = "rand_core" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" +dependencies = [ + "rand_core 0.4.2", +] + +[[package]] +name = "rand_core" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" + +[[package]] +name = "rand_core" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rdrand" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" +dependencies = [ + "rand_core 0.3.1", +] + [[package]] name = "redox_syscall" version = "0.2.13" @@ -357,6 +876,29 @@ dependencies = [ "bitflags", ] +[[package]] +name = "regex" +version = "1.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d83f127d94bdbcda4c8cc2e50f6f84f4b611f69c902699ca385a39c3a75f9ff1" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" + +[[package]] +name = "regex-syntax" +version = "0.6.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49b3de9ec5dc0a3417da371aab17d729997c15010e7fd24ff707773a33bddb64" + [[package]] name = "remove_dir_all" version = "0.5.3" @@ -366,6 +908,30 @@ dependencies = [ "winapi", ] +[[package]] +name = "ron" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b861ecaade43ac97886a512b360d01d66be9f41f3c61088b42cedf92e03d678" +dependencies = [ + "base64", + "bitflags", + "serde", +] + +[[package]] +name = "rust-crypto" +version = "0.2.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f76d05d3993fd5f4af9434e8e436db163a12a9d40e1a58a726f27a01dfd12a2a" +dependencies = [ + "gcc", + "libc", + "rand 0.3.23", + "rustc-serialize", + "time", +] + [[package]] name = "rustc-hash" version = "1.1.0" @@ -395,6 +961,12 @@ dependencies = [ "num_cpus", ] +[[package]] +name = "rustc-serialize" +version = "0.3.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda" + [[package]] name = "rustc_data_structures" version = "0.0.0" @@ -418,6 +990,15 @@ dependencies = [ "winapi", ] +[[package]] +name = "rustc_lexer" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c86aae0c77166108c01305ee1a36a1e77289d7dc6ca0a3cd91ff4992de2d16a5" +dependencies = [ + "unicode-xid", +] + [[package]] name = "rustc_span" version = "0.0.0" @@ -427,7 +1008,7 @@ dependencies = [ "rustc_data_structures", "scoped-tls", "sha-1", - "sha2", + "sha2 0.10.2", "tracing", "unicode-width", ] @@ -481,6 +1062,18 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_yaml" +version = "0.8.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "707d15895415db6628332b737c838b88c598522e4dc70647e59b72312924aebc" +dependencies = [ + "indexmap", + "ryu", + "serde", + "yaml-rust", +] + [[package]] name = "sha-1" version = "0.10.0" @@ -489,7 +1082,35 @@ checksum = "028f48d513f9678cda28f6e4064755b3fbb2af6acd672f2c209b62323f7aea0f" dependencies = [ "cfg-if 1.0.0", "cpufeatures", - "digest", + "digest 0.10.3", +] + +[[package]] +name = "sha1" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1da05c97445caa12d05e848c4a4fcbbea29e748ac28f7e80e9b010392063770" +dependencies = [ + "sha1_smol", +] + +[[package]] +name = "sha1_smol" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae1a47186c03a32177042e55dbc5fd5aee900b8e0069a8d70fba96a9375cd012" + +[[package]] +name = "sha2" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" +dependencies = [ + "block-buffer 0.9.0", + "cfg-if 1.0.0", + "cpufeatures", + "digest 0.9.0", + "opaque-debug", ] [[package]] @@ -500,9 +1121,15 @@ checksum = "55deaec60f81eefe3cce0dc50bda92d6d8e88f2a27df7c5033b42afeb1ed2676" dependencies = [ "cfg-if 1.0.0", "cpufeatures", - "digest", + "digest 0.10.3", ] +[[package]] +name = "siphasher" +version = "0.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7bd3e3206899af3f8b12af284fafc038cc1dc2b41d1b89dd17297221c5d225de" + [[package]] name = "smallvec" version = "1.8.0" @@ -565,6 +1192,65 @@ dependencies = [ "winapi", ] +[[package]] +name = "termcolor" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "termize" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1706be6b564323ce7092f5f7e6b118a14c8ef7ed0e69c8c5329c914a9f101295" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "thiserror" +version = "1.0.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd829fe32373d27f76265620b5309d0340cb8550f523c1dda251d6298069069a" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0396bc89e626244658bef819e22d0cc459e795a5ebe878e6ec336d1674a8d79a" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "time" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255" +dependencies = [ + "libc", + "wasi", + "winapi", +] + +[[package]] +name = "toml" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d82e1a7758622a465f8cee077614c73484dac5b836c02ff6a40d5d1010324d7" +dependencies = [ + "serde", +] + [[package]] name = "tracing" version = "0.1.34" @@ -603,6 +1289,76 @@ version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" +[[package]] +name = "unic-char-property" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8c57a407d9b6fa02b4795eb81c5b6652060a15a7903ea981f3d723e6c0be221" +dependencies = [ + "unic-char-range", +] + +[[package]] +name = "unic-char-range" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0398022d5f700414f6b899e10b8348231abf9173fa93144cbc1a43b9793c1fbc" + +[[package]] +name = "unic-common" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80d7ff825a6a654ee85a63e80f92f054f904f21e7d12da4e22f9834a4aaa35bc" + +[[package]] +name = "unic-emoji-char" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b07221e68897210270a38bde4babb655869637af0f69407f96053a34f76494d" +dependencies = [ + "unic-char-property", + "unic-char-range", + "unic-ucd-version", +] + +[[package]] +name = "unic-ucd-bidi" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1d568b51222484e1f8209ce48caa6b430bf352962b877d592c29ab31fb53d8c" +dependencies = [ + "unic-char-property", + "unic-char-range", + "unic-ucd-version", +] + +[[package]] +name = "unic-ucd-category" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b8d4591f5fcfe1bd4453baaf803c40e1b1e69ff8455c47620440b46efef91c0" +dependencies = [ + "matches", + "unic-char-property", + "unic-char-range", + "unic-ucd-version", +] + +[[package]] +name = "unic-ucd-version" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96bd2f2237fe450fcd0a1d2f5f4e91711124f7857ba2e964247776ebeeb7b0c4" +dependencies = [ + "unic-common", +] + +[[package]] +name = "unicode-casing" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "623f59e6af2a98bdafeb93fa277ac8e1e40440973001ca15cf4ae1541cd16d56" + [[package]] name = "unicode-width" version = "0.1.9" @@ -615,12 +1371,24 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" +[[package]] +name = "unicode_names2" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87d6678d7916394abad0d4b19df4d3802e1fd84abd7d701f39b75ee71b9e8cf1" + [[package]] name = "version_check" version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +[[package]] +name = "wasi" +version = "0.10.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" + [[package]] name = "winapi" version = "0.3.9" @@ -637,6 +1405,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi", +] + [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" @@ -685,3 +1462,12 @@ name = "windows_x86_64_msvc" version = "0.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d19538ccc21819d01deaf88d6a17eae6596a12e9aafdbb97916fb49896d89de9" + +[[package]] +name = "yaml-rust" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85" +dependencies = [ + "linked-hash-map", +] diff --git a/kclvm/ast/Cargo.toml b/kclvm/ast/Cargo.toml index e6cc20a37..732749011 100644 --- a/kclvm/ast/Cargo.toml +++ b/kclvm/ast/Cargo.toml @@ -1,13 +1,21 @@ [package] name = "kclvm-ast" -version = "0.1.0" +version = "0.11.0" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -rustc_span = { path = "../3rdparty/rustc_span" } +uuid = { version = "1.4.1", features = ["v4"] } +compiler_base_span = "0.1.2" serde = { version = "1", features = ["derive"] } serde_json = "1.0" -kclvm-span = {path = "../span", version = "0.1.0"} +kclvm-span = { path = "../span" } +kclvm-error = { path = "../error" } +thread_local = "1.1.7" +kclvm-utils = {path = "../utils"} +anyhow = "1.0" + +[dev-dependencies] +kclvm-parser = { path = "../parser" } diff --git a/kclvm/ast/src/ast.rs b/kclvm/ast/src/ast.rs index 0fe087dc6..9dbae2924 100644 --- a/kclvm/ast/src/ast.rs +++ b/kclvm/ast/src/ast.rs @@ -31,22 +31,104 @@ //! :note: When the definition of any AST node is modified or the AST node //! is added/deleted, it is necessary to modify the corresponding processing //! in the compiler and regenerate the walker code. -//! :copyright: Copyright 2020 The KCL Authors. All rights reserved. -//! -//! todo: remove type_str fields after python frontend removed. +//! :copyright: Copyright The KCL Authors. All rights reserved. -use serde::{Deserialize, Serialize}; -use std::collections::HashMap; +use kclvm_utils::path::PathPrefix; +use serde::{ser::SerializeStruct, Deserialize, Serialize, Serializer}; +use std::{ + collections::HashMap, + sync::{RwLock, RwLockReadGuard, RwLockWriteGuard}, +}; -use kclvm_span::Loc; -use rustc_span::Pos; +use compiler_base_span::{Loc, Span}; +use std::fmt::Debug; +use std::sync::Arc; +use uuid; use super::token; -use crate::node_ref; +use crate::{node_ref, pos::ContainsPos}; +use kclvm_error::{diagnostic::Range, Position}; +use std::cell::RefCell; + +thread_local! { + static SHOULD_SERIALIZE_ID: RefCell = RefCell::new(false); +} + +/// PosTuple denotes the tuple `(filename, line, column, end_line, end_column)`. +pub type PosTuple = (String, u64, u64, u64, u64); +/// Pos denotes the struct tuple `(filename, line, column, end_line, end_column)`. +#[derive(Clone)] +pub struct Pos(String, u64, u64, u64, u64); + +impl From for Pos { + fn from(value: PosTuple) -> Self { + Self( + value.0.adjust_canonicalization(), + value.1, + value.2, + value.3, + value.4, + ) + } +} + +impl From for PosTuple { + fn from(val: Pos) -> Self { + (val.0.adjust_canonicalization(), val.1, val.2, val.3, val.4) + } +} + +impl From for Range { + fn from(val: Pos) -> Self { + ( + Position { + filename: val.0.clone().adjust_canonicalization(), + line: val.1, + column: Some(val.2), + }, + Position { + filename: val.0.adjust_canonicalization(), + line: val.3, + column: Some(val.4), + }, + ) + } +} + +/// The unique index of AST, used for KCL semantic analysis to record AST +/// node semantic information. +#[derive(Debug, PartialEq, Eq, Hash, Clone)] +pub struct AstIndex(uuid::Uuid); + +impl Serialize for AstIndex { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + serializer.serialize_str(&self.to_string()) + } +} + +impl Default for AstIndex { + fn default() -> Self { + Self(uuid::Uuid::new_v4()) + } +} + +impl ToString for AstIndex { + fn to_string(&self) -> String { + self.0.to_string() + } +} + /// Node is the file, line and column number information /// that all AST nodes need to contain. -#[derive(Serialize, Deserialize, Debug, Clone)] +/// In fact, column and end_column are the counts of character, +/// For example, `\t` is counted as 1 character, so it is recorded as 1 here, but generally col is 4. +#[derive(Deserialize, Clone, PartialEq)] pub struct Node { + #[serde(serialize_with = "serialize_id", skip_deserializing, default)] + pub id: AstIndex, pub node: T, pub filename: String, pub line: u64, @@ -55,6 +137,46 @@ pub struct Node { pub end_column: u64, } +impl Serialize for Node { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + let should_serialize_id = SHOULD_SERIALIZE_ID.with(|f| *f.borrow()); + let mut state = + serializer.serialize_struct("Node", if should_serialize_id { 7 } else { 6 })?; + if should_serialize_id { + state.serialize_field("id", &self.id)?; + } + state.serialize_field("node", &self.node)?; + state.serialize_field("filename", &self.filename)?; + state.serialize_field("line", &self.line)?; + state.serialize_field("column", &self.column)?; + state.serialize_field("end_line", &self.end_line)?; + state.serialize_field("end_column", &self.end_column)?; + state.end() + } +} + +pub fn set_should_serialize_id(value: bool) { + SHOULD_SERIALIZE_ID.with(|f| { + *f.borrow_mut() = value; + }); +} + +impl Debug for Node { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("Node") + .field("node", &self.node) + .field("filename", &self.filename) + .field("line", &self.line) + .field("column", &self.column) + .field("end_line", &self.end_line) + .field("end_column", &self.end_column) + .finish() + } +} + impl Node { pub fn new( node: T, @@ -65,8 +187,9 @@ impl Node { end_column: u64, ) -> Self { Self { + id: AstIndex::default(), node, - filename, + filename: filename.adjust_canonicalization(), line, column, end_line, @@ -76,6 +199,7 @@ impl Node { pub fn dummy_node(node: T) -> Self { Self { + id: AstIndex::default(), node, filename: "".to_string(), line: 1, @@ -86,20 +210,39 @@ impl Node { } pub fn node(node: T, (lo, hi): (Loc, Loc)) -> Self { + let filename = kclvm_utils::path::convert_windows_drive_letter(&format!( + "{}", + lo.file.name.prefer_remapped() + )) + .adjust_canonicalization(); Self { + id: AstIndex::default(), node, - filename: format!("{}", lo.file.name.prefer_remapped()), + filename, line: lo.line as u64, - column: lo.col.to_usize() as u64, + column: lo.col.0 as u64, end_line: hi.line as u64, - end_column: hi.col.to_usize() as u64, + end_column: hi.col.0 as u64, + } + } + + pub fn node_with_pos_and_id(node: T, pos: PosTuple, id: AstIndex) -> Self { + Self { + id, + node, + filename: pos.0.clone().adjust_canonicalization(), + line: pos.1, + column: pos.2, + end_line: pos.3, + end_column: pos.4, } } - pub fn node_with_pos(node: T, pos: (String, u64, u64, u64, u64)) -> Self { + pub fn node_with_pos(node: T, pos: PosTuple) -> Self { Self { + id: AstIndex::default(), node, - filename: pos.0.clone(), + filename: pos.0.clone().adjust_canonicalization(), line: pos.1, column: pos.2, end_line: pos.3, @@ -107,9 +250,9 @@ impl Node { } } - pub fn pos(&self) -> (String, u64, u64, u64, u64) { + pub fn pos(&self) -> PosTuple { ( - self.filename.clone(), + self.filename.clone().adjust_canonicalization(), self.line, self.column, self.end_line, @@ -117,8 +260,8 @@ impl Node { ) } - pub fn set_pos(&mut self, pos: (String, u64, u64, u64, u64)) { - self.filename = pos.0.clone(); + pub fn set_pos(&mut self, pos: PosTuple) { + self.filename = pos.0.clone().adjust_canonicalization(); self.line = pos.1; self.column = pos.2; self.end_line = pos.3; @@ -126,12 +269,21 @@ impl Node { } } +/// Spanned is the span information that all AST nodes need to contain. +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] +pub struct Spanned { + pub node: T, + #[serde(skip)] + pub span: Span, +} + impl TryInto> for Node { type Error = &'static str; fn try_into(self) -> Result, Self::Error> { match self.node { Expr::Identifier(ident) => Ok(Node { + id: self.id, node: ident, filename: self.filename, line: self.line, @@ -144,12 +296,32 @@ impl TryInto> for Node { } } +impl Node { + /// Into a missing identifier. + pub fn into_missing_identifier(&self) -> Node { + Node { + id: self.id.clone(), + node: Identifier { + names: vec![], + pkgpath: String::new(), + ctx: ExprContext::Load, + }, + filename: self.filename.clone(), + line: self.line, + column: self.column, + end_line: self.end_line, + end_column: self.end_column, + } + } +} + impl TryInto> for Node { type Error = &'static str; fn try_into(self) -> Result, Self::Error> { match self.node { Expr::Schema(schema_expr) => Ok(Node { + id: self.id, node: schema_expr, filename: self.filename, line: self.line, @@ -166,61 +338,182 @@ impl TryInto> for Node { /// AST node type T pub type NodeRef = Box>; -#[derive(Serialize, Deserialize, Debug, Clone)] -pub enum ParseMode { - Null, - ParseComments, +/// KCL command line argument spec, e.g. `kcl main.k -E pkg_name=pkg_path` +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] +pub struct ExternalPkg { + pub pkg_name: String, + pub pkg_path: String, } /// KCL command line argument spec, e.g. `kcl main.k -D name=value` -#[derive(Serialize, Deserialize, Debug, Clone)] -pub struct CmdArgSpec { +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] +pub struct Argument { pub name: String, pub value: String, } /// KCL command line override spec, e.g. `kcl main.k -O pkgpath:path.to.field=field_value` -#[derive(Serialize, Deserialize, Debug, Clone)] -pub struct CmdOverrideSpec { - pub pkgpath: String, +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] +pub struct OverrideSpec { pub field_path: String, pub field_value: String, pub action: OverrideAction, + pub operation: ConfigEntryOperation, } -#[derive(Serialize, Deserialize, Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] pub enum OverrideAction { - CreateOrUpdate, Delete, + #[serde(other)] + CreateOrUpdate, +} + +/// KCL API symbol selector Spec, eg: `pkgpath:path.to.field` +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] +pub struct SymbolSelectorSpec { + pub pkg_root: String, + pub pkgpath: String, + pub field_path: String, } /// Program is the AST collection of all files of the running KCL program. -#[derive(Serialize, Deserialize, Debug, Clone)] -pub struct Program { +#[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq)] +pub struct SerializeProgram { pub root: String, - pub main: String, pub pkgs: HashMap>, - pub cmd_args: Vec, - pub cmd_overrides: Vec, +} + +impl Into for Program { + fn into(self) -> SerializeProgram { + SerializeProgram { + root: self.root.clone(), + pkgs: self + .pkgs + .iter() + .map(|(name, modules)| { + ( + name.clone(), + modules + .iter() + .map(|m| { + self.get_module(m) + .expect("Failed to acquire module lock") + .expect(&format!("module {:?} not found in program", m)) + .clone() + }) + .collect(), + ) + }) + .collect(), + } + } +} + +#[derive(Debug, Clone, Default)] +pub struct Program { + pub root: String, + pub pkgs: HashMap>, + pub pkgs_not_imported: HashMap>, + pub modules: HashMap>>, + pub modules_not_imported: HashMap>>, } impl Program { /// Get main entry files. pub fn get_main_files(&self) -> Vec { match self.pkgs.get(crate::MAIN_PKG) { - Some(modules) => modules.iter().map(|m| m.filename.clone()).collect(), + Some(modules) => modules.clone(), None => vec![], } } + /// Get the first module in the main package. + pub fn get_main_package_first_module(&self) -> Option> { + match self.pkgs.get(crate::MAIN_PKG) { + Some(modules) => match modules.first() { + Some(first_module_path) => self.get_module(&first_module_path).unwrap_or(None), + None => None, + }, + None => None, + } + } + /// Get stmt on position + pub fn pos_to_stmt(&self, pos: &Position) -> Option> { + for (_, v) in &self.pkgs { + for m in v { + if let Ok(m) = self.get_module(m) { + let m = m?; + if m.filename == pos.filename { + return m.pos_to_stmt(pos); + } + } + } + } + None + } + + pub fn get_module( + &self, + module_path: &str, + ) -> anyhow::Result>> { + match self + .modules + .get(module_path) + .or(self.modules_not_imported.get(module_path)) + { + Some(module_ref) => match module_ref.read() { + Ok(m) => Ok(Some(m)), + Err(_) => Err(anyhow::anyhow!("Failed to acquire module lock")), + }, + None => Ok(None), + } + } + + pub fn get_module_mut( + &self, + module_path: &str, + ) -> anyhow::Result>> { + match self + .modules + .get(module_path) + .or(self.modules_not_imported.get(module_path)) + { + Some(module_ref) => match module_ref.write() { + Ok(m) => Ok(Some(m)), + Err(_) => Err(anyhow::anyhow!("Failed to acquire module lock")), + }, + None => Ok(None), + } + } + + pub fn get_module_ref(&self, module_path: &str) -> Option>> { + self.modules + .get(module_path) + .cloned() + .or(self.modules_not_imported.get(module_path).cloned()) + } + + pub fn get_modules_for_pkg(&self, pkg_name: &str) -> Vec>> { + let mut result = Vec::new(); + if let Some(module_names) = self + .pkgs + .get(pkg_name) + .or(self.pkgs_not_imported.get(pkg_name)) + { + for module_name in module_names { + if let Some(module) = self.get_module_ref(module_name) { + result.push(module); + } + } + } + result + } } /// Module is an abstract syntax tree for a single KCL file. -#[derive(Serialize, Deserialize, Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq)] pub struct Module { pub filename: String, - pub pkg: String, - pub doc: String, - pub name: String, + pub doc: Option>, pub body: Vec>, pub comments: Vec>, } @@ -231,10 +524,20 @@ impl Module { let mut stmts = Vec::new(); for stmt in &self.body { if let Stmt::Schema(schema_stmt) = &stmt.node { - stmts.push(node_ref!(schema_stmt.clone())); + stmts.push(node_ref!(schema_stmt.clone(), stmt.pos())); + } + } + stmts + } + + /// Get stmt on position + pub fn pos_to_stmt(&self, pos: &Position) -> Option> { + for stmt in &self.body { + if stmt.contains_pos(pos) { + return Some(*stmt.clone()); } } - return stmts; + None } } @@ -243,7 +546,8 @@ impl Module { */ /// A statement -#[derive(Serialize, Deserialize, Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] +#[serde(tag = "type")] pub enum Stmt { TypeAlias(TypeAliasStmt), Expr(ExprStmt), @@ -262,13 +566,12 @@ pub enum Stmt { /// ```kcl /// type StrOrInt = str | int /// ``` -#[derive(Serialize, Deserialize, Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] pub struct TypeAliasStmt { pub type_name: NodeRef, pub type_value: NodeRef, - #[serde(skip_serializing)] - pub ty: Option>, + pub ty: NodeRef, } /// ExprStmt represents a expression statement, e.g. @@ -276,7 +579,7 @@ pub struct TypeAliasStmt { /// 1 /// """A long string""" /// ``` -#[derive(Serialize, Deserialize, Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] pub struct ExprStmt { pub exprs: Vec>, } @@ -285,7 +588,7 @@ pub struct ExprStmt { /// ```kcl /// data: ASchema {} /// ``` -#[derive(Serialize, Deserialize, Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] pub struct UnificationStmt { pub target: NodeRef, pub value: NodeRef, @@ -294,24 +597,28 @@ pub struct UnificationStmt { /// AssignStmt represents an assignment, e.g. /// ```kcl /// a: int = 1 +/// a["key"] = "value" +/// a.b["key"].c = "value" +/// a[0] = 1 /// ``` -#[derive(Serialize, Deserialize, Debug, Clone)] +/// Valid left-hand side of an assignment expressions: +/// - Expr::Identifier a +/// - Expr::Subscript e.g. `a[0]`, `b["k"]` +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] pub struct AssignStmt { - pub targets: Vec>, + pub targets: Vec>, pub value: NodeRef, - pub type_annotation: Option>, - - #[serde(skip_serializing)] pub ty: Option>, } /// AugAssignStmt represents an argument assignment, e.g. /// ```kcl /// a += 1 +/// a[0] += 2 /// ``` -#[derive(Serialize, Deserialize, Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] pub struct AugAssignStmt { - pub target: NodeRef, + pub target: NodeRef, pub value: NodeRef, pub op: AugOp, } @@ -320,7 +627,7 @@ pub struct AugAssignStmt { /// ```kcl /// assert True if condition, "Assert failed message" /// ``` -#[derive(Serialize, Deserialize, Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] pub struct AssertStmt { pub test: NodeRef, pub if_cond: Option>, @@ -337,7 +644,7 @@ pub struct AssertStmt { /// else: /// c = 3 /// ``` -#[derive(Serialize, Deserialize, Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] pub struct IfStmt { pub body: Vec>, pub cond: NodeRef, @@ -348,12 +655,21 @@ pub struct IfStmt { /// ```kcl /// import pkg as pkg_alias /// ``` -#[derive(Serialize, Deserialize, Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] pub struct ImportStmt { - pub path: String, + /// `path` is the import path, if 'import a.b.c' in kcl, `path` is a.b.c + pub path: Node, pub rawpath: String, pub name: String, - pub asname: Option, + pub asname: Option>, + /// `pkg_name` means the name of the package that the current import statement indexs to. + /// + /// 1. If the current import statement indexs to the kcl plugins, kcl builtin methods or the internal kcl packages, + /// `pkg_name` is `__main__` + /// + /// 2. If the current import statement indexs to the external kcl packages, `pkg_name` is the name of the package. + /// if `import k8s.example.apps`, `k8s` is another kcl package, `pkg_name` is `k8s`. + pub pkg_name: String, } /// SchemaStmt, e.g. @@ -372,9 +688,9 @@ pub struct ImportStmt { /// protocol ProtocolExample: /// attr: int /// ``` -#[derive(Serialize, Deserialize, Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] pub struct SchemaStmt { - pub doc: String, + pub doc: Option>, pub name: NodeRef, pub parent_name: Option>, pub for_host_name: Option>, @@ -396,11 +712,13 @@ impl SchemaStmt { fn loop_body(body: &[NodeRef], attr_list: &mut Vec<(u64, u64, String)>) { for stmt in body { match &stmt.node { - Stmt::Unification(unification_stmt) => { + Stmt::Unification(unification_stmt) + if !unification_stmt.target.node.names.is_empty() => + { attr_list.push(( unification_stmt.target.line, unification_stmt.target.column, - unification_stmt.target.node.names[0].to_string(), + unification_stmt.target.node.names[0].node.to_string(), )); } Stmt::Assign(assign_stmt) => { @@ -408,7 +726,7 @@ impl SchemaStmt { attr_list.push(( target.line, target.column, - target.node.names[0].to_string(), + target.node.name.node.to_string(), )); } } @@ -416,7 +734,7 @@ impl SchemaStmt { attr_list.push(( aug_assign_stmt.target.line, aug_assign_stmt.target.column, - aug_assign_stmt.target.node.names[0].to_string(), + aug_assign_stmt.target.node.name.node.to_string(), )); } Stmt::If(if_stmt) => { @@ -455,16 +773,13 @@ impl SchemaStmt { /// schema SchemaIndexSignatureExample: /// [str]: int /// ``` -#[derive(Serialize, Deserialize, Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] pub struct SchemaIndexSignature { - pub key_name: Option, - pub key_type: NodeRef, - pub value_type: NodeRef, + pub key_name: Option>, pub value: Option>, pub any_other: bool, - - #[serde(skip_serializing)] - pub value_ty: Option>, + pub key_ty: NodeRef, + pub value_ty: NodeRef, } /// SchemaAttr, e.g. @@ -473,18 +788,23 @@ pub struct SchemaIndexSignature { /// x: int /// y: str /// ``` -#[derive(Serialize, Deserialize, Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] pub struct SchemaAttr { pub doc: String, pub name: NodeRef, - pub type_str: NodeRef, - pub op: Option, + pub op: Option, pub value: Option>, pub is_optional: bool, pub decorators: Vec>, - #[serde(skip_serializing)] - pub ty: Option>, + pub ty: NodeRef, +} + +impl SchemaAttr { + #[inline] + pub fn is_ident_attr(&self) -> bool { + self.name.end_column - self.name.column <= self.name.node.chars().count() as u64 + } } /// RuleStmt, e.g. @@ -493,9 +813,9 @@ pub struct SchemaAttr { /// a > 1 /// b < 0 /// ``` -#[derive(Serialize, Deserialize, Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] pub struct RuleStmt { - pub doc: String, + pub doc: Option>, pub name: NodeRef, pub parent_rules: Vec>, pub decorators: Vec>, @@ -505,8 +825,10 @@ pub struct RuleStmt { } /// A expression -#[derive(Serialize, Deserialize, Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] +#[serde(tag = "type")] pub enum Expr { + Target(Target), Identifier(Identifier), Unary(UnaryExpr), Binary(BinaryExpr), @@ -535,6 +857,87 @@ pub enum Expr { NameConstantLit(NameConstantLit), JoinedString(JoinedString), FormattedValue(FormattedValue), + /// A place holder for expression parse error. + Missing(MissingExpr), +} + +impl Expr { + pub fn get_expr_name(&self) -> String { + match self { + Expr::Target(_) => "TargetExpression", + Expr::Identifier(_) => "IdentifierExpression", + Expr::Unary(_) => "UnaryExpression", + Expr::Binary(_) => "BinaryExpression", + Expr::If(_) => "IfExpression", + Expr::Selector(_) => "SelectorExpression", + Expr::Call(_) => "CallExpression", + Expr::Paren(_) => "ParenExpression", + Expr::Quant(_) => "QuantExpression", + Expr::List(_) => "ListExpression", + Expr::ListIfItem(_) => "ListIfItemExpression", + Expr::ListComp(_) => "ListCompExpression", + Expr::Starred(_) => "StarredExpression", + Expr::DictComp(_) => "DictCompExpression", + Expr::ConfigIfEntry(_) => "ConfigIfEntryExpression", + Expr::CompClause(_) => "CompClauseExpression", + Expr::Schema(_) => "SchemaExpression", + Expr::Config(_) => "ConfigExpression", + Expr::Check(_) => "CheckExpression", + Expr::Lambda(_) => "LambdaExpression", + Expr::Subscript(_) => "SubscriptExpression", + Expr::Keyword(_) => "KeywordExpression", + Expr::Arguments(_) => "ArgumentsExpression", + Expr::Compare(_) => "CompareExpression", + Expr::NumberLit(_) => "NumberLitExpression", + Expr::StringLit(_) => "StringLitExpression", + Expr::NameConstantLit(_) => "NameConstantLitExpression", + Expr::JoinedString(_) => "JoinedStringExpression", + Expr::FormattedValue(_) => "FormattedValueExpression", + Expr::Missing(_) => "MissingExpression", + } + .to_string() + } +} + +/// Target, e.g. +/// ```kcl +/// a.b.c +/// b +/// _c +/// a["b"][0].c +/// ``` +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] +pub struct Target { + pub name: Node, + pub paths: Vec, + pub pkgpath: String, +} + +impl Target { + #[inline] + pub fn get_name(&self) -> &str { + self.name.node.as_str() + } +} + +/// Member or index expression +/// - `a.` +/// - `b[]` +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] +#[serde(tag = "type", content = "value")] +pub enum MemberOrIndex { + Member(NodeRef), + Index(NodeRef), +} + +impl MemberOrIndex { + #[inline] + pub fn id(&self) -> AstIndex { + match self { + MemberOrIndex::Member(member) => member.id.clone(), + MemberOrIndex::Index(index) => index.id.clone(), + } + } } /// Identifier, e.g. @@ -544,16 +947,25 @@ pub enum Expr { /// _c /// pkg.a /// ``` -#[derive(Serialize, Deserialize, Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] pub struct Identifier { - pub names: Vec, + pub names: Vec>, pub pkgpath: String, pub ctx: ExprContext, } impl Identifier { + #[inline] pub fn get_name(&self) -> String { - self.names.join(".") + self.get_names().join(".") + } + + #[inline] + pub fn get_names(&self) -> Vec { + self.names + .iter() + .map(|node| node.node.clone()) + .collect::>() } } @@ -564,7 +976,7 @@ impl Identifier { /// ~3 /// not True /// ``` -#[derive(Serialize, Deserialize, Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] pub struct UnaryExpr { pub op: UnaryOp, pub operand: NodeRef, @@ -577,10 +989,10 @@ pub struct UnaryExpr { /// 5 / 2 /// a is None /// ``` -#[derive(Serialize, Deserialize, Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] pub struct BinaryExpr { pub left: NodeRef, - pub op: BinOrCmpOp, + pub op: BinOp, pub right: NodeRef, } @@ -588,7 +1000,7 @@ pub struct BinaryExpr { /// ```kcl /// 1 if condition else 2 /// ``` -#[derive(Serialize, Deserialize, Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] pub struct IfExpr { pub body: NodeRef, pub cond: NodeRef, @@ -600,7 +1012,7 @@ pub struct IfExpr { /// x.y /// x?.y /// ``` -#[derive(Serialize, Deserialize, Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] pub struct SelectorExpr { pub value: NodeRef, pub attr: NodeRef, @@ -614,7 +1026,7 @@ pub struct SelectorExpr { /// func2(1) /// func3(x=2) /// ``` -#[derive(Serialize, Deserialize, Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] pub struct CallExpr { pub func: NodeRef, pub args: Vec>, @@ -625,19 +1037,19 @@ pub struct CallExpr { /// ```kcl /// 1 + (2 - 3) /// ``` -#[derive(Serialize, Deserialize, Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] pub struct ParenExpr { pub expr: NodeRef, } -/// QuantExpr, e.g. +/// QuantExpr, in { } e.g. /// ```kcl /// all x in collection {x > 0} /// any y in collection {y < 0} /// map x in collection {x + 1} /// filter x in collection {x > 1} /// ``` -#[derive(Serialize, Deserialize, Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] pub struct QuantExpr { pub target: NodeRef, pub variables: Vec>, @@ -647,7 +1059,7 @@ pub struct QuantExpr { pub ctx: ExprContext, } -#[derive(Serialize, Deserialize, Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] pub enum QuantOperation { All, Any, @@ -655,9 +1067,9 @@ pub enum QuantOperation { Map, } -impl Into for QuantOperation { - fn into(self) -> String { - let s = match self { +impl From for String { + fn from(val: QuantOperation) -> Self { + let s = match val { QuantOperation::All => "all", QuantOperation::Any => "any", QuantOperation::Filter => "filter", @@ -672,7 +1084,7 @@ impl Into for QuantOperation { /// ```kcl /// [1, 2, 3] /// ``` -#[derive(Serialize, Deserialize, Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] pub struct ListExpr { pub elts: Vec>, pub ctx: ExprContext, @@ -682,13 +1094,14 @@ pub struct ListExpr { /// ```kcl /// [1, if condition: 2, 3] /// ``` -#[derive(Serialize, Deserialize, Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] pub struct ListIfItemExpr { pub if_cond: NodeRef, pub exprs: Vec>, pub orelse: Option>, } +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] pub enum CompType { List, Dict, @@ -698,7 +1111,7 @@ pub enum CompType { /// ```kcl /// [x ** 2 for x in [1, 2, 3]] /// ``` -#[derive(Serialize, Deserialize, Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] pub struct ListComp { pub elt: NodeRef, pub generators: Vec>, @@ -708,7 +1121,7 @@ pub struct ListComp { /// ```kcl /// [1, 2, *[3, 4]] /// ``` -#[derive(Serialize, Deserialize, Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] pub struct StarredExpr { pub value: NodeRef, pub ctx: ExprContext, @@ -718,7 +1131,7 @@ pub struct StarredExpr { /// ```kcl /// {k: v + 1 for k, v in {k1 = 1, k2 = 2}} /// ``` -#[derive(Serialize, Deserialize, Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] pub struct DictComp { pub entry: ConfigEntry, pub generators: Vec>, @@ -732,7 +1145,7 @@ pub struct DictComp { /// k2 = 2 /// } /// ``` -#[derive(Serialize, Deserialize, Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] pub struct ConfigIfEntryExpr { pub if_cond: NodeRef, pub items: Vec>, @@ -743,7 +1156,7 @@ pub struct ConfigIfEntryExpr { /// ```kcl /// i, a in [1, 2, 3] if i > 1 and a > 1 /// ``` -#[derive(Serialize, Deserialize, Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] pub struct CompClause { pub targets: Vec>, pub iter: NodeRef, @@ -757,7 +1170,7 @@ pub struct CompClause { /// attr2 = 2 /// } /// ``` -#[derive(Serialize, Deserialize, Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] pub struct SchemaExpr { pub name: NodeRef, pub args: Vec>, @@ -772,12 +1185,12 @@ pub struct SchemaExpr { /// attr2 = 2 /// } /// ``` -#[derive(Serialize, Deserialize, Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] pub struct ConfigExpr { pub items: Vec>, } -#[derive(Serialize, Deserialize, Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] pub enum ConfigEntryOperation { Union, Override, @@ -810,19 +1223,18 @@ impl ConfigEntryOperation { /// c += [0] /// } /// ``` -#[derive(Serialize, Deserialize, Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] pub struct ConfigEntry { pub key: Option>, pub value: NodeRef, pub operation: ConfigEntryOperation, - pub insert_index: isize, } /// CheckExpr, e.g. /// ```kcl /// len(attr) > 3 if attr, "Check failed message" /// ``` -#[derive(Serialize, Deserialize, Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] pub struct CheckExpr { pub test: NodeRef, pub if_cond: Option>, @@ -836,13 +1248,10 @@ pub struct CheckExpr { /// z + y /// } /// ``` -#[derive(Serialize, Deserialize, Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] pub struct LambdaExpr { pub args: Option>, - pub return_type_str: Option, pub body: Vec>, - - #[serde(skip_serializing)] pub return_ty: Option>, } @@ -852,7 +1261,7 @@ pub struct LambdaExpr { /// b["k"] /// c?[1] /// ``` -#[derive(Serialize, Deserialize, Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] pub struct Subscript { pub value: NodeRef, pub index: Option>, @@ -863,11 +1272,38 @@ pub struct Subscript { pub has_question: bool, } +impl Subscript { + /// Whether the subscript is the a[1] or a[-1] form. + pub fn has_name_and_constant_index(&self) -> bool { + if let Expr::Identifier(_) = &self.value.node { + if let Some(index_node) = &self.index { + // Positive index constant + if let Expr::NumberLit(number) = &index_node.node { + matches!(number.value, NumberLitValue::Int(_)) + } else if let Expr::Unary(unary_expr) = &index_node.node { + // Negative index constant + if let Expr::NumberLit(number) = &unary_expr.operand.node { + matches!(number.value, NumberLitValue::Int(_)) + } else { + false + } + } else { + false + } + } else { + false + } + } else { + false + } + } +} + /// Keyword, e.g. /// ```kcl /// arg=value /// ``` -#[derive(Serialize, Deserialize, Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] pub struct Keyword { pub arg: NodeRef, pub value: Option>, @@ -879,14 +1315,10 @@ pub struct Keyword { /// x + y /// } /// ``` -#[derive(Serialize, Deserialize, Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] pub struct Arguments { pub args: Vec>, pub defaults: Vec>>, - pub type_annotation_list: Vec>>, - - #[serde(skip_serializing)] - #[serde(default)] pub ty_list: Vec>>, } @@ -896,6 +1328,18 @@ impl Arguments { .as_ref() .map_or(Type::Any, |ty| ty.node.clone()) } + + pub fn get_arg_type_node(&self, i: usize) -> Option<&Node> { + if let Some(ty) = self.ty_list.get(i) { + if let Some(ty) = ty { + Some(ty.as_ref()) + } else { + None + } + } else { + None + } + } } /// Compare, e.g. @@ -904,7 +1348,7 @@ impl Arguments { /// b is not None /// c != d /// ``` -#[derive(Serialize, Deserialize, Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] pub struct Compare { pub left: NodeRef, pub ops: Vec, @@ -918,7 +1362,8 @@ pub struct Compare { /// "string literal" /// """long string literal""" /// ``` -#[derive(Serialize, Deserialize, Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] +#[serde(tag = "type")] pub enum Literal { Number(NumberLit), String(StringLit), @@ -926,7 +1371,7 @@ pub enum Literal { } #[allow(non_camel_case_types)] -#[derive(Serialize, Deserialize, Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] pub enum NumberBinarySuffix { n, u, @@ -981,7 +1426,8 @@ impl NumberBinarySuffix { } } -#[derive(Serialize, Deserialize, Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] +#[serde(tag = "type", content = "value")] pub enum NumberLitValue { Int(i64), Float(f64), @@ -993,18 +1439,31 @@ pub enum NumberLitValue { /// 1K /// 1Mi /// ``` -#[derive(Serialize, Deserialize, Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] pub struct NumberLit { pub binary_suffix: Option, pub value: NumberLitValue, } +impl ToString for NumberLit { + fn to_string(&self) -> String { + let mut result = match self.value { + NumberLitValue::Int(v) => v.to_string(), + NumberLitValue::Float(v) => v.to_string(), + }; + if let Some(suffix) = &self.binary_suffix { + result.push_str(&suffix.value()); + } + result + } +} + /// StringLit, e.g. /// ```kcl /// "string literal" /// """long string literal""" /// ``` -#[derive(Serialize, Deserialize, Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] pub struct StringLit { pub is_long_string: bool, pub raw_value: String, @@ -1012,15 +1471,13 @@ pub struct StringLit { } /// Generate ast.StringLit from String -impl TryFrom for StringLit { - type Error = &'static str; - - fn try_from(value: String) -> Result { - Ok(Self { +impl From for StringLit { + fn from(value: String) -> Self { + Self { value: value.clone(), raw_value: format!("{:?}", value), is_long_string: false, - }) + } } } @@ -1031,7 +1488,7 @@ impl TryFrom for StringLit { /// None /// Undefined /// ``` -#[derive(Serialize, Deserialize, Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] pub enum NameConstant { True, False, @@ -1040,6 +1497,7 @@ pub enum NameConstant { } impl NameConstant { + /// Returns the symbol pub fn symbol(&self) -> &'static str { match self { NameConstant::True => "True", @@ -1048,6 +1506,15 @@ impl NameConstant { NameConstant::Undefined => "Undefined", } } + + // Returns the json value + pub fn json_value(&self) -> &'static str { + match self { + NameConstant::True => "true", + NameConstant::False => "false", + NameConstant::None | NameConstant::Undefined => "null", + } + } } /// Generate ast.NameConstant from Bool @@ -1062,13 +1529,13 @@ impl TryFrom for NameConstant { } } -#[derive(Serialize, Deserialize, Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] pub struct NameConstantLit { pub value: NameConstant, } /// JoinedString, e.g. abc in the string interpolation "${var1} abc ${var2}" -#[derive(Serialize, Deserialize, Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] pub struct JoinedString { pub is_long_string: bool, pub values: Vec>, @@ -1076,18 +1543,22 @@ pub struct JoinedString { } /// FormattedValue, e.g. var1 and var2 in the string interpolation "${var1} abc ${var2}" -#[derive(Serialize, Deserialize, Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] pub struct FormattedValue { pub is_long_string: bool, pub value: NodeRef, pub format_spec: Option, } +/// MissingExpr placeholder for error recovery. +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] +pub struct MissingExpr; + /// Comment, e.g. /// ```kcl /// # This is a comment /// ``` -#[derive(Serialize, Deserialize, Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] pub struct Comment { pub text: String, } @@ -1097,7 +1568,7 @@ pub struct Comment { */ /// BinOp is the set of all binary operators in KCL. -#[derive(Serialize, Deserialize, Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] pub enum BinOp { /// The `+` operator (addition) Add, @@ -1174,7 +1645,7 @@ impl BinOp { } /// BinOp is the set of all argument operators in KCL. -#[derive(Serialize, Deserialize, Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] pub enum AugOp { // The `=` operator (assign) Assign, @@ -1239,7 +1710,7 @@ impl TryInto for AugOp { AugOp::LShift => Ok(BinOp::LShift), AugOp::RShift => Ok(BinOp::RShift), AugOp::BitXor => Ok(BinOp::BitXor), - AugOp::BitAnd => Ok(BinOp::And), + AugOp::BitAnd => Ok(BinOp::BitAnd), AugOp::BitOr => Ok(BinOp::BitOr), _ => Err("aug assign op can not into bin op"), } @@ -1247,7 +1718,7 @@ impl TryInto for AugOp { } /// UnaryOp is the set of all unary operators in KCL. -#[derive(Serialize, Deserialize, Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] pub enum UnaryOp { /// The `+` operator for positive UAdd, @@ -1271,7 +1742,7 @@ impl UnaryOp { } /// CmpOp is the set of all comparison operators in KCL. -#[derive(Serialize, Deserialize, Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] pub enum CmpOp { /// The `==` operator (equality) Eq, @@ -1332,30 +1803,25 @@ impl CmpOp { } /// BinOrCmpOp is the set of all binary and comparison operators in KCL. -#[derive(Serialize, Deserialize, Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] +#[serde(tag = "type")] pub enum BinOrCmpOp { Bin(BinOp), Cmp(CmpOp), } -/// BinOrAugOp is the set of all binary and argument operators in KCL. -#[derive(Serialize, Deserialize, Debug, Clone)] -pub enum BinOrAugOp { - Bin(BinOp), - Aug(AugOp), -} - /// ExprContext represents the location information of the AST node. /// The left side of the assignment symbol represents `Store`, /// and the right side represents `Load`. -#[derive(Serialize, Deserialize, Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] pub enum ExprContext { Load, Store, } /// A expression -#[derive(Serialize, Deserialize, Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] +#[serde(tag = "type", content = "value")] pub enum Type { Any, Named(Identifier), @@ -1364,9 +1830,16 @@ pub enum Type { Dict(DictType), Union(UnionType), Literal(LiteralType), + Function(FunctionType), } -#[derive(Serialize, Deserialize, Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] +pub struct FunctionType { + pub params_ty: Option>>, + pub ret_ty: Option>, +} + +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] pub enum BasicType { Bool, Int, @@ -1374,37 +1847,44 @@ pub enum BasicType { Str, } -#[derive(Serialize, Deserialize, Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] pub struct ListType { pub inner_type: Option>, } -#[derive(Serialize, Deserialize, Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] pub struct DictType { pub key_type: Option>, pub value_type: Option>, } -#[derive(Serialize, Deserialize, Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] pub struct UnionType { pub type_elements: Vec>, } -#[derive(Serialize, Deserialize, Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] +#[serde(tag = "type", content = "value")] pub enum LiteralType { Bool(bool), - Int(i64, Option), // value + suffix + Int(IntLiteralType), // value + suffix Float(f64), Str(String), } +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] +pub struct IntLiteralType { + pub value: i64, + pub suffix: Option, +} + impl ToString for Type { fn to_string(&self) -> String { fn to_str(typ: &Type, w: &mut String) { match typ { Type::Any => w.push_str("any"), Type::Named(x) => { - w.push_str(&x.names.join(".")); + w.push_str(&x.get_name()); } Type::Basic(x) => { w.push_str(match x { @@ -1439,7 +1919,7 @@ impl ToString for Type { } for (i, t) in x.type_elements.iter().enumerate() { if i > 0 { - w.push('|'); + w.push_str(" | ") } to_str(&t.node, w); } @@ -1453,7 +1933,7 @@ impl ToString for Type { w.push_str("False"); } } - LiteralType::Int(v, suffix) => { + LiteralType::Int(IntLiteralType { value: v, suffix }) => { if let Some(suffix) = suffix { w.push_str(&format!("{}{}", v, suffix.value())); } else { @@ -1471,6 +1951,22 @@ impl ToString for Type { w.push_str(&format!("\"{}\"", v.replace('"', "\\\""))); } }, + Type::Function(v) => { + w.push('('); + if let Some(params) = &v.params_ty { + for (i, param) in params.iter().enumerate() { + if i > 0 { + w.push_str(", "); + } + to_str(¶m.node, w); + } + } + w.push(')'); + if let Some(ret) = &v.ret_ty { + w.push_str(" -> "); + to_str(&ret.node, w); + } + } } } @@ -1480,6 +1976,17 @@ impl ToString for Type { } } +impl From for Type { + /// Build a named type from the string. + fn from(value: String) -> Self { + Type::Named(Identifier { + names: vec![Node::dummy_node(value)], + pkgpath: "".to_string(), + ctx: ExprContext::Load, + }) + } +} + impl From for AugOp { fn from(op_kind: token::BinOpToken) -> Self { match op_kind { @@ -1489,7 +1996,7 @@ impl From for AugOp { token::BinOpToken::Slash => AugOp::Div, token::BinOpToken::Percent => AugOp::Mod, token::BinOpToken::StarStar => AugOp::Pow, - token::BinOpToken::SlashSlash => AugOp::Add, + token::BinOpToken::SlashSlash => AugOp::FloorDiv, token::BinOpToken::Caret => AugOp::BitXor, token::BinOpToken::And => AugOp::BitAnd, token::BinOpToken::Or => AugOp::BitOr, diff --git a/kclvm/ast/src/config.rs b/kclvm/ast/src/config.rs new file mode 100644 index 000000000..510805add --- /dev/null +++ b/kclvm/ast/src/config.rs @@ -0,0 +1,34 @@ +use crate::ast; + +/// Try get a config expr mut ref from a expr if the expr is a schema or a config. +/// If not, return [None]. +/// TODO: use [TryInto]? +/// +/// # Examples +/// +/// ``` +/// use kclvm_parser::parse_expr; +/// use kclvm_ast::ast; +/// use kclvm_ast::config::try_get_config_expr_mut; +/// +/// let mut expr = parse_expr(r#"{ +/// a: {b: {c = 1}} +/// } +/// "#).unwrap(); +/// assert!(matches!(try_get_config_expr_mut(&mut expr.node), Some(_))); +/// let mut expr = parse_expr(r#"1"#).unwrap(); +/// assert!(matches!(try_get_config_expr_mut(&mut expr.node), None)); +/// ``` +pub fn try_get_config_expr_mut(expr: &mut ast::Expr) -> Option<&mut ast::ConfigExpr> { + match expr { + ast::Expr::Schema(schema_expr) => { + if let ast::Expr::Config(config_expr) = &mut schema_expr.config.node { + Some(config_expr) + } else { + None + } + } + ast::Expr::Config(config_expr) => Some(config_expr), + _ => None, + } +} diff --git a/kclvm/ast/src/lib.rs b/kclvm/ast/src/lib.rs index d0cc4279e..a6bed9d3c 100644 --- a/kclvm/ast/src/lib.rs +++ b/kclvm/ast/src/lib.rs @@ -1,7 +1,9 @@ -// Copyright 2021 The KCL Authors. All rights reserved. -use crate::ast::*; +//! Copyright The KCL Authors. All rights reserved. pub mod ast; +pub mod config; +pub mod path; +pub mod pos; pub mod token; pub mod token_stream; pub mod walker; @@ -42,19 +44,3 @@ macro_rules! stmt_as { } }; } - -/// Construct an AssignStmt node with assign_value as value -pub fn build_assign_node(attr_name: &str, assign_value: NodeRef) -> NodeRef { - let iden = node_ref!(Identifier { - names: vec![attr_name.to_string()], - pkgpath: String::new(), - ctx: ExprContext::Store - }); - - node_ref!(Stmt::Assign(AssignStmt { - value: assign_value, - targets: vec![iden], - type_annotation: None, - ty: None - })) -} diff --git a/kclvm/ast/src/path.rs b/kclvm/ast/src/path.rs new file mode 100644 index 000000000..4d8b06654 --- /dev/null +++ b/kclvm/ast/src/path.rs @@ -0,0 +1,170 @@ +use crate::ast; + +/// Get config key path from the AST key node and convert string-based AST nodes including +/// `ast::Expr::Identifier` and `ast::Expr::StringLit` to strings. +/// +/// # Examples +/// +/// ``` +/// use kclvm_ast::ast; +/// use kclvm_ast::path::get_key_path; +/// +/// let ident = Some(Box::new(ast::Node::dummy_node(ast::Expr::Identifier(ast::Identifier { +/// names: vec![ast::Node::dummy_node("alice".to_string())], +/// pkgpath: "".to_string(), +/// ctx: ast::ExprContext::Load, +/// })))); +/// assert_eq!(get_key_path(&ident), "alice"); +/// let str_lit = Some(Box::new(ast::Node::dummy_node(ast::Expr::StringLit(ast::StringLit { +/// is_long_string: false, +/// raw_value: "\"Alice\"".to_string(), +/// value: "Alice".to_string(), +/// })))); +/// assert_eq!(get_key_path(&str_lit), "Alice"); +/// ``` +#[inline] +pub fn get_key_path(key: &Option>) -> String { + match key { + Some(key) => match &key.node { + ast::Expr::Identifier(identifier) => identifier.get_name(), + ast::Expr::StringLit(string_lit) => string_lit.value.clone(), + _ => "".to_string(), + }, + None => "".to_string(), + } +} + +/// Get config key parts from the AST key node and convert string-based AST nodes including +/// `ast::Expr::Identifier` and `ast::Expr::StringLit` to strings. +#[inline] +pub fn get_key_parts(key: &Option>) -> Vec<&str> { + match key { + Some(key) => match &key.node { + ast::Expr::Identifier(identifier) => { + identifier.names.iter().map(|v| v.node.as_str()).collect() + } + ast::Expr::StringLit(string_lit) => vec![string_lit.value.as_str()], + _ => vec![], + }, + None => vec![], + } +} + +/// Get assign target path from the AST key node and convert string-based AST nodes including +/// `ast::Expr::Identifier` and `ast::Expr::StringLit` to strings. +/// +/// # Examples +/// +/// ``` +/// use kclvm_ast::ast; +/// use kclvm_ast::path::get_target_path; +/// +/// let target = ast::Target { +/// name: ast::Node::dummy_node("alice".to_string()), +/// paths: vec![], +/// pkgpath: "".to_string(), +/// }; +/// assert_eq!(get_target_path(&target), "alice"); +/// ``` +#[inline] +pub fn get_target_path(key: &ast::Target) -> String { + let mut result = key.name.node.to_string(); + for path in &key.paths { + match path { + ast::MemberOrIndex::Member(member) => { + result.push('.'); + result.push_str(&member.node); + } + ast::MemberOrIndex::Index(index) => { + result.push('['); + match &index.node { + ast::Expr::Unary(unary_expr) => match &unary_expr.operand.node { + ast::Expr::NumberLit(number) => { + result.push_str(&unary_expr.op.symbol()); + result.push_str(&number.to_string()); + } + _ => { + result.push_str("..."); + } + }, + ast::Expr::NumberLit(number) => { + result.push_str(&number.to_string()); + } + ast::Expr::StringLit(string_lit) => { + result.push_str(&format!("{:?}", string_lit.value)); + } + _ => { + result.push_str("..."); + } + } + result.push(']'); + } + } + } + result +} + +/// Get all attribute paths recursively from a config expression AST node. +/// +/// # Examples +/// +/// ``` +/// use kclvm_parser::parse_expr; +/// use kclvm_ast::ast; +/// use kclvm_ast::path::get_attr_paths_from_config_expr; +/// +/// let expr = parse_expr(r#"{ +/// a: {b: {c = 1}} +/// } +/// "#).unwrap(); +/// if let ast::Expr::Config(config_expr) = &expr.node { +/// assert_eq!(get_attr_paths_from_config_expr(&config_expr), vec![ +/// "a".to_string(), +/// "a.b".to_string(), +/// "a.b.c".to_string(), +/// ]) +/// } else { +/// panic!("invalid config expr {:?}", expr) +/// } +/// ``` +pub fn get_attr_paths_from_config_expr(config: &ast::ConfigExpr) -> Vec { + let mut paths = vec![]; + for entry in &config.items { + let mut entry_paths = get_entry_paths(&entry.node); + paths.append(&mut entry_paths); + } + paths +} + +/// Get all attribute paths from a config entry. +fn get_entry_paths(entry: &ast::ConfigEntry) -> Vec { + let mut paths = vec![]; + let path = get_key_path(&entry.key); + if path.is_empty() || path.trim().is_empty() { + return paths; + } + paths.push(path.clone()); + let option_config_expr = match &entry.value.node { + ast::Expr::Schema(schema_expr) => { + if let ast::Expr::Config(config_expr) = &schema_expr.config.node { + Some(config_expr) + } else { + None + } + } + ast::Expr::Config(config_expr) => Some(config_expr), + _ => None, + }; + if let Some(config_expr) = option_config_expr { + let value_paths = get_attr_paths_from_config_expr(config_expr); + if !value_paths.is_empty() { + paths.append( + &mut value_paths + .iter() + .map(|value_path| format!("{}.{}", path, value_path)) + .collect::>(), + ); + } + } + paths +} diff --git a/kclvm/sema/src/resolver/pos.rs b/kclvm/ast/src/pos.rs similarity index 88% rename from kclvm/sema/src/resolver/pos.rs rename to kclvm/ast/src/pos.rs index 8ab6723fa..f8d56fa2c 100644 --- a/kclvm/sema/src/resolver/pos.rs +++ b/kclvm/ast/src/pos.rs @@ -1,5 +1,6 @@ -use kclvm_ast::ast; -use kclvm_error::Position; +use kclvm_error::{diagnostic::Range, Position}; + +use crate::ast; pub trait ContainsPos { /// Check if current scope or node contains a position. @@ -8,7 +9,7 @@ pub trait ContainsPos { pub trait GetPos { /// Get start and end position from node. - fn get_span_pos(&self) -> (Position, Position) { + fn get_span_pos(&self) -> Range { (self.get_pos(), self.get_end_pos()) } /// Get start pos from node. @@ -24,6 +25,12 @@ impl ContainsPos for ast::Node { } } +impl ContainsPos for Range { + fn contains_pos(&self, pos: &Position) -> bool { + self.0.filename == pos.filename && self.0.less_equal(pos) && pos.less_equal(&self.1) + } +} + impl GetPos for ast::Node { fn get_pos(&self) -> Position { Position { diff --git a/kclvm/ast/src/tests.rs b/kclvm/ast/src/tests.rs index 5ab8b4fdd..71cad0033 100644 --- a/kclvm/ast/src/tests.rs +++ b/kclvm/ast/src/tests.rs @@ -1,5 +1,21 @@ +use crate::node_ref; use crate::walker::MutSelfMutWalker; -use crate::{ast, build_assign_node, node_ref, Identifier, Module, Node, NodeRef, SchemaStmt}; +use crate::{ast, ast::*}; + +/// Construct an AssignStmt node with assign_value as value +fn build_assign_node(attr_name: &str, assign_value: NodeRef) -> NodeRef { + let target = node_ref!(Target { + name: Node::dummy_node(attr_name.to_string()), + paths: vec![], + pkgpath: "".to_string() + }); + + node_ref!(Stmt::Assign(AssignStmt { + value: assign_value, + targets: vec![target], + ty: None + })) +} fn get_dummy_assign_ast() -> ast::Node { let filename = "main.k"; @@ -10,10 +26,10 @@ fn get_dummy_assign_ast() -> ast::Node { ast::Node::new( ast::AssignStmt { targets: vec![Box::new(ast::Node::new( - ast::Identifier { - names: vec![String::from("a")], - pkgpath: String::from(filename), - ctx: ast::ExprContext::Load, + ast::Target { + name: Node::dummy_node(String::from("a")), + paths: vec![], + pkgpath: "".to_string(), }, String::from(filename), line, @@ -33,7 +49,6 @@ fn get_dummy_assign_ast() -> ast::Node { end_line, end_column, )), - type_annotation: None, ty: None, }, String::from(filename), @@ -53,10 +68,10 @@ fn get_dummy_assign_binary_ast() -> ast::Node { ast::Node::new( ast::AssignStmt { targets: vec![Box::new(ast::Node::new( - ast::Identifier { - names: vec![String::from("a")], - pkgpath: String::from(filename), - ctx: ast::ExprContext::Load, + ast::Target { + name: Node::dummy_node(String::from("a")), + paths: vec![], + pkgpath: "".to_string(), }, String::from(filename), line, @@ -66,10 +81,10 @@ fn get_dummy_assign_binary_ast() -> ast::Node { ))], value: Box::new(ast::Node::new( ast::Expr::Binary(ast::BinaryExpr { - op: ast::BinOrCmpOp::Bin(ast::BinOp::Add), + op: ast::BinOp::Add, left: Box::new(ast::Node::new( ast::Expr::Identifier(ast::Identifier { - names: vec![String::from("a")], + names: vec![Node::dummy_node(String::from("a"))], pkgpath: String::from(filename), ctx: ast::ExprContext::Load, }), @@ -81,7 +96,7 @@ fn get_dummy_assign_binary_ast() -> ast::Node { )), right: Box::new(ast::Node::new( ast::Expr::Identifier(ast::Identifier { - names: vec![String::from("a")], + names: vec![Node::dummy_node(String::from("a"))], pkgpath: String::from(filename), ctx: ast::ExprContext::Load, }), @@ -98,7 +113,6 @@ fn get_dummy_assign_binary_ast() -> ast::Node { end_line, end_column, )), - type_annotation: None, ty: None, }, String::from(filename), @@ -129,16 +143,15 @@ fn test_ast_print_assign_binary() { fn test_mut_walker() { pub struct VarMutSelfMutWalker; impl<'ctx> MutSelfMutWalker<'ctx> for VarMutSelfMutWalker { - fn walk_identifier(&mut self, identifier: &'ctx mut ast::Identifier) { - if identifier.names[0] == "a" { - let id_mut = identifier.names.get_mut(0).unwrap(); - *id_mut = "x".to_string(); + fn walk_target(&mut self, target: &'ctx mut ast::Target) { + if target.name.node == "a" { + target.name.node = "x".to_string(); } } } let mut assign_stmt = get_dummy_assign_ast(); VarMutSelfMutWalker {}.walk_assign_stmt(&mut assign_stmt.node); - assert_eq!(assign_stmt.node.targets[0].node.names[0], "x") + assert_eq!(assign_stmt.node.targets[0].node.name.node, "x") } #[test] @@ -166,9 +179,7 @@ fn test_try_from_for_nameconstant() { fn test_filter_schema_with_no_schema() { let ast_mod = Module { filename: "".to_string(), - pkg: "".to_string(), - doc: "".to_string(), - name: "".to_string(), + doc: Some(node_ref!("".to_string())), body: vec![], comments: vec![], }; @@ -180,9 +191,7 @@ fn test_filter_schema_with_no_schema() { fn test_filter_schema_with_one_schema() { let mut ast_mod = Module { filename: "".to_string(), - pkg: "".to_string(), - doc: "".to_string(), - name: "".to_string(), + doc: Some(node_ref!("".to_string())), body: vec![], comments: vec![], }; @@ -197,9 +206,7 @@ fn test_filter_schema_with_one_schema() { fn test_filter_schema_with_mult_schema() { let mut ast_mod = Module { filename: "".to_string(), - pkg: "".to_string(), - doc: "".to_string(), - name: "".to_string(), + doc: Some(node_ref!("".to_string())), body: vec![], comments: vec![], }; @@ -218,7 +225,10 @@ fn test_filter_schema_with_mult_schema() { #[test] fn test_build_assign_stmt() { let test_expr = node_ref!(ast::Expr::Identifier(Identifier { - names: vec!["name1".to_string(), "name2".to_string()], + names: vec![ + Node::dummy_node("name1".to_string()), + Node::dummy_node("name2".to_string()) + ], pkgpath: "test".to_string(), ctx: ast::ExprContext::Load })); @@ -227,8 +237,8 @@ fn test_build_assign_stmt() { if let ast::Stmt::Assign(ref assign) = assgin_stmt.node { if let ast::Expr::Identifier(ref iden) = &assign.value.node { assert_eq!(iden.names.len(), 2); - assert_eq!(iden.names[0], "name1".to_string()); - assert_eq!(iden.names[1], "name2".to_string()); + assert_eq!(iden.names[0].node, "name1".to_string()); + assert_eq!(iden.names[1].node, "name2".to_string()); assert_eq!(iden.pkgpath, "test".to_string()); match iden.ctx { ast::ExprContext::Load => {} @@ -248,7 +258,7 @@ fn gen_schema_stmt(count: i32) -> Vec> { let mut schema_stmts = Vec::new(); for c in 0..count { schema_stmts.push(node_ref!(ast::Stmt::Schema(SchemaStmt { - doc: "".to_string(), + doc: Some(node_ref!("".to_string())), name: node_ref!("schema_stmt_".to_string() + &c.to_string()), parent_name: None, for_host_name: None, diff --git a/kclvm/ast/src/token.rs b/kclvm/ast/src/token.rs index b925c2e55..d375b4c07 100644 --- a/kclvm/ast/src/token.rs +++ b/kclvm/ast/src/token.rs @@ -4,15 +4,15 @@ //! Including indent and dedent tokens. //! Not Include some tokens of low level tokens, such as ';', '..', '..=', '<-'. pub use BinCmpToken::*; -pub use BinCmpToken::*; pub use BinOpToken::*; pub use DelimToken::*; pub use LitKind::*; pub use TokenKind::*; pub use UnaryOpToken::*; -use kclvm_span::symbol::{Ident, Symbol}; -use kclvm_span::{Span, DUMMY_SP}; +use compiler_base_span::{Span, DUMMY_SP}; +pub use kclvm_span::symbol::{Ident, Symbol}; +pub const VALID_SPACES_LENGTH: usize = 0; #[derive(Clone, Copy, PartialEq, Debug)] pub enum CommentKind { @@ -122,9 +122,9 @@ pub enum LitKind { Err, } -impl Into for LitKind { - fn into(self) -> String { - let s = match self { +impl From for String { + fn from(val: LitKind) -> Self { + let s = match val { Bool => "bool", Integer => "int", Float => "float", @@ -180,10 +180,10 @@ pub enum TokenKind { DocComment(CommentKind), /// '\t' or ' ' - Indent, + Indent(usize), /// Remove an indent - Dedent, + Dedent(usize), /// '\n' Newline, @@ -203,9 +203,9 @@ impl TokenKind { } } -impl Into for TokenKind { - fn into(self) -> String { - let s = match self { +impl From for String { + fn from(val: TokenKind) -> Self { + let s = match val { UnaryOp(unary_op) => match unary_op { UTilde => "~", UNot => "not", @@ -280,8 +280,8 @@ impl Into for TokenKind { DocComment(kind) => match kind { CommentKind::Line(_) => "inline_comment", }, - Indent => "indent", - Dedent => "dedent", + Indent(_) => "indent", + Dedent(_) => "dedent", Newline => "newline", Dummy => "dummy", Eof => "eof", @@ -296,33 +296,37 @@ pub struct Token { pub span: Span, } -impl Into for Token { - fn into(self) -> String { - match self.kind { +impl From for String { + fn from(val: Token) -> Self { + match val.kind { Literal(lk) => { - let sym = lk.symbol.as_str().to_string(); + let sym = lk.symbol.as_str(); match lk.suffix { - Some(suf) => sym + suf.as_str(), + Some(suf) => sym + &suf.as_str(), _other_none => sym, } } - _ => self.kind.into(), + _ => val.kind.into(), } } } impl Token { + /// New a token using the kind and span. + #[inline] pub fn new(kind: TokenKind, span: Span) -> Self { Token { kind, span } } /// Some token that will be thrown away later. + #[inline] pub fn dummy() -> Self { Token::new(TokenKind::Dummy, DUMMY_SP) } /// Returns an identifier if this token is an identifier. + #[inline] pub fn ident(&self) -> Option { match self.kind { Ident(name) => Some(Ident::new(name, self.span)), @@ -330,16 +334,42 @@ impl Token { } } + /// Whether the token is keyword. + #[inline] pub fn is_keyword(&self, kw: Symbol) -> bool { self.run_on_ident(|id| id.name == kw) } + /// Whether the token is a string literal token. + #[inline] + pub fn is_string_lit(&self) -> bool { + match self.kind { + TokenKind::Literal(lit) => { + if let LitKind::Str { .. } = lit.kind { + true + } else { + false + } + } + _ => false, + } + } + fn run_on_ident(&self, pred: impl FnOnce(Ident) -> bool) -> bool { match self.ident() { Some(id) => pred(id), _ => false, } } + + /// Whether the token kind is in the recovery token set, when meets errors, drop it. + #[inline] + pub fn is_in_recovery_set(&self) -> bool { + matches!( + self.kind, + TokenKind::Indent(VALID_SPACES_LENGTH) | TokenKind::Dummy + ) + } } impl PartialEq for Token { diff --git a/kclvm/ast/src/token_stream.rs b/kclvm/ast/src/token_stream.rs index 920cd867e..25ab71b05 100644 --- a/kclvm/ast/src/token_stream.rs +++ b/kclvm/ast/src/token_stream.rs @@ -37,10 +37,12 @@ impl Cursor { Cursor { stream, index: 0 } } + /// Get the next token index. pub fn index(&self) -> usize { self.index } + /// Peek next token. pub fn peek(&self) -> Option { if self.index < self.stream.len() { Some(self.stream[self.index]) @@ -48,6 +50,15 @@ impl Cursor { None } } + + /// Peek next two token. + pub fn peek2(&self) -> Option { + if self.index + 1 < self.stream.len() { + Some(self.stream[self.index + 1]) + } else { + None + } + } } impl Iterator for Cursor { diff --git a/kclvm/ast/src/walker.rs b/kclvm/ast/src/walker.rs index 365825eb6..916eb1b9a 100644 --- a/kclvm/ast/src/walker.rs +++ b/kclvm/ast/src/walker.rs @@ -110,6 +110,7 @@ pub trait TypedResultWalker<'ctx>: Sized { fn walk_arguments(&self, arguments: &'ctx ast::Arguments) -> Self::Result; fn walk_compare(&self, compare: &'ctx ast::Compare) -> Self::Result; fn walk_identifier(&self, identifier: &'ctx ast::Identifier) -> Self::Result; + fn walk_target(&self, target: &'ctx ast::Target) -> Self::Result; fn walk_number_lit(&self, number_lit: &'ctx ast::NumberLit) -> Self::Result; fn walk_string_lit(&self, string_lit: &'ctx ast::StringLit) -> Self::Result; fn walk_name_constant_lit(&self, name_constant_lit: &'ctx ast::NameConstantLit) @@ -117,6 +118,7 @@ pub trait TypedResultWalker<'ctx>: Sized { fn walk_joined_string(&self, joined_string: &'ctx ast::JoinedString) -> Self::Result; fn walk_formatted_value(&self, formatted_value: &'ctx ast::FormattedValue) -> Self::Result; fn walk_comment(&self, comment: &'ctx ast::Comment) -> Self::Result; + fn walk_missing_expr(&self, missing_expr: &'ctx ast::MissingExpr) -> Self::Result; } /// Each method of the `MutSelfTypedResultWalker` trait returns a typed result. @@ -173,6 +175,7 @@ pub trait MutSelfTypedResultWalker<'ctx>: Sized { fn walk_expr(&mut self, expr: &'ctx ast::Expr) -> Self::Result { match expr { + ast::Expr::Target(target) => self.walk_target(target), ast::Expr::Identifier(identifier) => self.walk_identifier(identifier), ast::Expr::Unary(unary_expr) => self.walk_unary_expr(unary_expr), ast::Expr::Binary(binary_expr) => self.walk_binary_expr(binary_expr), @@ -209,6 +212,7 @@ pub trait MutSelfTypedResultWalker<'ctx>: Sized { ast::Expr::FormattedValue(formatted_value) => { self.walk_formatted_value(formatted_value) } + ast::Expr::Missing(miss_expr) => self.walk_missing_expr(miss_expr), } } fn walk_quant_expr(&mut self, quant_expr: &'ctx ast::QuantExpr) -> Self::Result; @@ -241,6 +245,7 @@ pub trait MutSelfTypedResultWalker<'ctx>: Sized { fn walk_arguments(&mut self, arguments: &'ctx ast::Arguments) -> Self::Result; fn walk_compare(&mut self, compare: &'ctx ast::Compare) -> Self::Result; fn walk_identifier(&mut self, identifier: &'ctx ast::Identifier) -> Self::Result; + fn walk_target(&mut self, target: &'ctx ast::Target) -> Self::Result; fn walk_number_lit(&mut self, number_lit: &'ctx ast::NumberLit) -> Self::Result; fn walk_string_lit(&mut self, string_lit: &'ctx ast::StringLit) -> Self::Result; fn walk_name_constant_lit( @@ -250,6 +255,7 @@ pub trait MutSelfTypedResultWalker<'ctx>: Sized { fn walk_joined_string(&mut self, joined_string: &'ctx ast::JoinedString) -> Self::Result; fn walk_formatted_value(&mut self, formatted_value: &'ctx ast::FormattedValue) -> Self::Result; fn walk_comment(&mut self, comment: &'ctx ast::Comment) -> Self::Result; + fn walk_missing_expr(&mut self, missing_expr: &'ctx ast::MissingExpr) -> Self::Result; } /// Each method of the `MutSelfMutWalker` trait returns void type. @@ -263,6 +269,7 @@ pub trait MutSelfMutWalker<'ctx> { } fn walk_type_alias_stmt(&mut self, type_alias_stmt: &'ctx mut ast::TypeAliasStmt) { self.walk_identifier(&mut type_alias_stmt.type_name.node); + self.walk_type(&mut type_alias_stmt.ty.node); } fn walk_unification_stmt(&mut self, unification_stmt: &'ctx mut ast::UnificationStmt) { self.walk_identifier(&mut unification_stmt.target.node); @@ -270,12 +277,13 @@ pub trait MutSelfMutWalker<'ctx> { } fn walk_assign_stmt(&mut self, assign_stmt: &'ctx mut ast::AssignStmt) { for target in assign_stmt.targets.iter_mut() { - self.walk_identifier(&mut target.node) + self.walk_target(&mut target.node) } self.walk_expr(&mut assign_stmt.value.node); + walk_if_mut!(self, walk_type, assign_stmt.ty); } fn walk_aug_assign_stmt(&mut self, aug_assign_stmt: &'ctx mut ast::AugAssignStmt) { - self.walk_identifier(&mut aug_assign_stmt.target.node); + self.walk_target(&mut aug_assign_stmt.target.node); self.walk_expr(&mut aug_assign_stmt.value.node); } fn walk_assert_stmt(&mut self, assert_stmt: &'ctx mut ast::AssertStmt) { @@ -294,6 +302,33 @@ pub trait MutSelfMutWalker<'ctx> { fn walk_schema_attr(&mut self, schema_attr: &'ctx mut ast::SchemaAttr) { walk_list_mut!(self, walk_call_expr, schema_attr.decorators); walk_if_mut!(self, walk_expr, schema_attr.value); + self.walk_type(&mut schema_attr.ty.node); + } + + fn walk_type(&mut self, ty: &'ctx mut ast::Type) { + match ty { + ast::Type::Named(id) => self.walk_identifier(id), + ast::Type::List(list_ty) => { + if let Some(ty) = &mut list_ty.inner_type { + self.walk_type(&mut ty.node) + } + } + ast::Type::Dict(dict_ty) => { + if let Some(ty) = &mut dict_ty.key_type { + self.walk_type(&mut ty.node) + } + if let Some(ty) = &mut dict_ty.value_type { + self.walk_type(&mut ty.node) + } + } + ast::Type::Union(union_ty) => { + union_ty + .type_elements + .iter_mut() + .for_each(|ty| self.walk_type(&mut ty.node)); + } + _ => {} + } } fn walk_schema_stmt(&mut self, schema_stmt: &'ctx mut ast::SchemaStmt) { walk_if_mut!(self, walk_identifier, schema_stmt.parent_name); @@ -410,6 +445,7 @@ pub trait MutSelfMutWalker<'ctx> { fn walk_lambda_expr(&mut self, lambda_expr: &'ctx mut ast::LambdaExpr) { walk_if_mut!(self, walk_arguments, lambda_expr.args); walk_list_mut!(self, walk_stmt, lambda_expr.body); + walk_if_mut!(self, walk_type, lambda_expr.return_ty); } fn walk_keyword(&mut self, keyword: &'ctx mut ast::Keyword) { self.walk_identifier(&mut keyword.arg.node); @@ -424,6 +460,11 @@ pub trait MutSelfMutWalker<'ctx> { self.walk_expr(&mut d.node) } } + for ty in arguments.ty_list.iter_mut() { + if let Some(ty) = ty.as_deref_mut() { + self.walk_type(&mut ty.node); + } + } } fn walk_compare(&mut self, compare: &'ctx mut ast::Compare) { self.walk_expr(&mut compare.left.node); @@ -433,6 +474,13 @@ pub trait MutSelfMutWalker<'ctx> { // Nothing to do. let _ = identifier; } + fn walk_target(&mut self, target: &'ctx mut ast::Target) { + for path in target.paths.iter_mut() { + if let ast::MemberOrIndex::Index(index) = path { + self.walk_expr(&mut index.node) + } + } + } fn walk_number_lit(&mut self, number_lit: &'ctx mut ast::NumberLit) { let _ = number_lit; } @@ -454,6 +502,10 @@ pub trait MutSelfMutWalker<'ctx> { // Nothing to do. let _ = comment; } + fn walk_missing_expr(&mut self, missing_expr: &'ctx mut ast::MissingExpr) { + // Nothing to do. + let _ = missing_expr; + } fn walk_module(&mut self, module: &'ctx mut ast::Module) { walk_list_mut!(self, walk_stmt, module.body) } @@ -476,6 +528,7 @@ pub trait MutSelfMutWalker<'ctx> { } fn walk_expr(&mut self, expr: &'ctx mut ast::Expr) { match expr { + ast::Expr::Target(target) => self.walk_target(target), ast::Expr::Identifier(identifier) => self.walk_identifier(identifier), ast::Expr::Unary(unary_expr) => self.walk_unary_expr(unary_expr), ast::Expr::Binary(binary_expr) => self.walk_binary_expr(binary_expr), @@ -512,6 +565,7 @@ pub trait MutSelfMutWalker<'ctx> { ast::Expr::FormattedValue(formatted_value) => { self.walk_formatted_value(formatted_value) } + ast::Expr::Missing(missing_expr) => self.walk_missing_expr(missing_expr), } } } @@ -628,6 +682,9 @@ pub trait Walker<'ctx>: TypedResultWalker<'ctx> { fn walk_identifier(&mut self, identifier: &'ctx ast::Identifier) { walk_identifier(self, identifier); } + fn walk_target(&mut self, target: &'ctx ast::Target) { + walk_target(self, target); + } fn walk_number_lit(&mut self, number_lit: &'ctx ast::NumberLit) { walk_number_lit(self, number_lit); } @@ -646,6 +703,7 @@ pub trait Walker<'ctx>: TypedResultWalker<'ctx> { fn walk_comment(&mut self, comment: &'ctx ast::Comment) { walk_comment(self, comment); } + fn walk_missing_expr(&mut self, missing_expr: &'ctx ast::MissingExpr); fn walk_module(&mut self, module: &'ctx ast::Module) { walk_module(self, module); } @@ -659,6 +717,7 @@ pub trait Walker<'ctx>: TypedResultWalker<'ctx> { pub fn walk_expr<'ctx, V: Walker<'ctx>>(walker: &mut V, expr: &'ctx ast::Expr) { match expr { + ast::Expr::Target(target) => walker.walk_target(target), ast::Expr::Identifier(identifier) => walker.walk_identifier(identifier), ast::Expr::Unary(unary_expr) => walker.walk_unary_expr(unary_expr), ast::Expr::Binary(binary_expr) => walker.walk_binary_expr(binary_expr), @@ -693,6 +752,7 @@ pub fn walk_expr<'ctx, V: Walker<'ctx>>(walker: &mut V, expr: &'ctx ast::Expr) { } ast::Expr::JoinedString(joined_string) => walker.walk_joined_string(joined_string), ast::Expr::FormattedValue(formatted_value) => walker.walk_formatted_value(formatted_value), + ast::Expr::Missing(missing_expr) => walker.walk_missing_expr(missing_expr), } } @@ -732,7 +792,9 @@ pub fn walk_type_alias_stmt<'ctx, V: Walker<'ctx>>( } pub fn walk_assign_stmt<'ctx, V: Walker<'ctx>>(walker: &mut V, assign_stmt: &'ctx ast::AssignStmt) { - walk_list!(walker, walk_identifier, assign_stmt.targets); + for target in &assign_stmt.targets { + walker.walk_target(&target.node) + } walker.walk_expr(&assign_stmt.value.node); } @@ -740,7 +802,7 @@ pub fn walk_aug_assign_stmt<'ctx, V: Walker<'ctx>>( walker: &mut V, aug_assign_stmt: &'ctx ast::AugAssignStmt, ) { - walker.walk_identifier(&aug_assign_stmt.target.node); + walker.walk_target(&aug_assign_stmt.target.node); walker.walk_expr(&aug_assign_stmt.value.node); } @@ -946,6 +1008,14 @@ pub fn walk_identifier<'ctx, V: Walker<'ctx>>(walker: &mut V, identifier: &'ctx let _ = identifier; } +pub fn walk_target<'ctx, V: Walker<'ctx>>(walker: &mut V, target: &'ctx ast::Target) { + for path in target.paths.iter() { + if let ast::MemberOrIndex::Index(index) = path { + walk_expr(walker, &index.node); + } + } +} + pub fn walk_number_lit<'ctx, V: Walker<'ctx>>(walker: &mut V, number_lit: &'ctx ast::NumberLit) { // Nothing to do. let _ = walker; @@ -990,3 +1060,276 @@ pub fn walk_comment<'ctx, V: Walker<'ctx>>(walker: &mut V, comment: &'ctx ast::C pub fn walk_module<'ctx, V: Walker<'ctx>>(walker: &mut V, module: &'ctx ast::Module) { walk_list!(walker, walk_stmt, module.body) } + +/// Each method of the `MutSelfWalker` trait returns void type and does not need to modify the AST. +/// We can use it to traverse the AST and do some check at the same time, For example, in the process +/// of lint checking, we can use it to check each AST node and generate diagnostcs. +pub trait MutSelfWalker { + fn walk_expr_stmt(&mut self, expr_stmt: &ast::ExprStmt) { + for expr in &expr_stmt.exprs { + self.walk_expr(&expr.node) + } + } + + fn walk_type_alias_stmt(&mut self, type_alias_stmt: &ast::TypeAliasStmt) { + self.walk_identifier(&type_alias_stmt.type_name.node); + } + fn walk_unification_stmt(&mut self, unification_stmt: &ast::UnificationStmt) { + self.walk_identifier(&unification_stmt.target.node); + self.walk_schema_expr(&unification_stmt.value.node); + } + fn walk_assign_stmt(&mut self, assign_stmt: &ast::AssignStmt) { + for target in &assign_stmt.targets { + self.walk_target(&target.node) + } + self.walk_expr(&assign_stmt.value.node); + } + fn walk_aug_assign_stmt(&mut self, aug_assign_stmt: &ast::AugAssignStmt) { + self.walk_target(&aug_assign_stmt.target.node); + self.walk_expr(&aug_assign_stmt.value.node); + } + fn walk_assert_stmt(&mut self, assert_stmt: &ast::AssertStmt) { + self.walk_expr(&assert_stmt.test.node); + walk_if!(self, walk_expr, assert_stmt.if_cond); + walk_if!(self, walk_expr, assert_stmt.msg); + } + fn walk_if_stmt(&mut self, if_stmt: &ast::IfStmt) { + self.walk_expr(&if_stmt.cond.node); + walk_list!(self, walk_stmt, if_stmt.body); + walk_list!(self, walk_stmt, if_stmt.orelse); + } + fn walk_import_stmt(&mut self, _import_stmt: &ast::ImportStmt) { + // Nothing to do + } + fn walk_schema_attr(&mut self, schema_attr: &ast::SchemaAttr) { + walk_list!(self, walk_call_expr, schema_attr.decorators); + walk_if!(self, walk_expr, schema_attr.value); + } + fn walk_schema_stmt(&mut self, schema_stmt: &ast::SchemaStmt) { + walk_if!(self, walk_identifier, schema_stmt.parent_name); + walk_if!(self, walk_identifier, schema_stmt.for_host_name); + walk_if!(self, walk_arguments, schema_stmt.args); + if let Some(schema_index_signature) = &schema_stmt.index_signature { + let value = &schema_index_signature.node.value; + walk_if!(self, walk_expr, value); + } + walk_list!(self, walk_identifier, schema_stmt.mixins); + walk_list!(self, walk_call_expr, schema_stmt.decorators); + walk_list!(self, walk_check_expr, schema_stmt.checks); + walk_list!(self, walk_stmt, schema_stmt.body); + } + fn walk_rule_stmt(&mut self, rule_stmt: &ast::RuleStmt) { + walk_list!(self, walk_identifier, rule_stmt.parent_rules); + walk_list!(self, walk_call_expr, rule_stmt.decorators); + walk_list!(self, walk_check_expr, rule_stmt.checks); + walk_if!(self, walk_arguments, rule_stmt.args); + walk_if!(self, walk_identifier, rule_stmt.for_host_name); + } + fn walk_quant_expr(&mut self, quant_expr: &ast::QuantExpr) { + self.walk_expr(&quant_expr.target.node); + walk_list!(self, walk_identifier, quant_expr.variables); + self.walk_expr(&quant_expr.test.node); + walk_if!(self, walk_expr, quant_expr.if_cond); + } + fn walk_if_expr(&mut self, if_expr: &ast::IfExpr) { + self.walk_expr(&if_expr.cond.node); + self.walk_expr(&if_expr.body.node); + self.walk_expr(&if_expr.orelse.node); + } + fn walk_unary_expr(&mut self, unary_expr: &ast::UnaryExpr) { + self.walk_expr(&unary_expr.operand.node); + } + fn walk_binary_expr(&mut self, binary_expr: &ast::BinaryExpr) { + self.walk_expr(&binary_expr.left.node); + self.walk_expr(&binary_expr.right.node); + } + fn walk_selector_expr(&mut self, selector_expr: &ast::SelectorExpr) { + self.walk_expr(&selector_expr.value.node); + self.walk_identifier(&selector_expr.attr.node); + } + fn walk_call_expr(&mut self, call_expr: &ast::CallExpr) { + self.walk_expr(&call_expr.func.node); + walk_list!(self, walk_expr, call_expr.args); + walk_list!(self, walk_keyword, call_expr.keywords); + } + fn walk_subscript(&mut self, subscript: &ast::Subscript) { + self.walk_expr(&subscript.value.node); + walk_if!(self, walk_expr, subscript.index); + walk_if!(self, walk_expr, subscript.lower); + walk_if!(self, walk_expr, subscript.upper); + walk_if!(self, walk_expr, subscript.step); + } + fn walk_paren_expr(&mut self, paren_expr: &ast::ParenExpr) { + self.walk_expr(&paren_expr.expr.node); + } + fn walk_list_expr(&mut self, list_expr: &ast::ListExpr) { + walk_list!(self, walk_expr, list_expr.elts); + } + fn walk_list_comp(&mut self, list_comp: &ast::ListComp) { + self.walk_expr(&list_comp.elt.node); + walk_list!(self, walk_comp_clause, list_comp.generators); + } + fn walk_list_if_item_expr(&mut self, list_if_item_expr: &ast::ListIfItemExpr) { + self.walk_expr(&list_if_item_expr.if_cond.node); + walk_list!(self, walk_expr, list_if_item_expr.exprs); + walk_if!(self, walk_expr, list_if_item_expr.orelse); + } + fn walk_starred_expr(&mut self, starred_expr: &ast::StarredExpr) { + self.walk_expr(&starred_expr.value.node); + } + fn walk_dict_comp(&mut self, dict_comp: &ast::DictComp) { + if let Some(key) = &dict_comp.entry.key { + self.walk_expr(&key.node); + } + self.walk_expr(&dict_comp.entry.value.node); + walk_list!(self, walk_comp_clause, dict_comp.generators); + } + fn walk_config_if_entry_expr(&mut self, config_if_entry_expr: &ast::ConfigIfEntryExpr) { + self.walk_expr(&config_if_entry_expr.if_cond.node); + for config_entry in &config_if_entry_expr.items { + walk_if!(self, walk_expr, config_entry.node.key); + self.walk_expr(&config_entry.node.value.node); + } + walk_if!(self, walk_expr, config_if_entry_expr.orelse); + } + fn walk_comp_clause(&mut self, comp_clause: &ast::CompClause) { + walk_list!(self, walk_identifier, comp_clause.targets); + self.walk_expr(&comp_clause.iter.node); + walk_list!(self, walk_expr, comp_clause.ifs); + } + fn walk_schema_expr(&mut self, schema_expr: &ast::SchemaExpr) { + self.walk_identifier(&schema_expr.name.node); + walk_list!(self, walk_expr, schema_expr.args); + walk_list!(self, walk_keyword, schema_expr.kwargs); + self.walk_expr(&schema_expr.config.node); + } + fn walk_config_expr(&mut self, config_expr: &ast::ConfigExpr) { + for config_entry in &config_expr.items { + walk_if!(self, walk_expr, config_entry.node.key); + self.walk_expr(&config_entry.node.value.node); + } + } + fn walk_check_expr(&mut self, check_expr: &ast::CheckExpr) { + self.walk_expr(&check_expr.test.node); + walk_if!(self, walk_expr, check_expr.if_cond); + walk_if!(self, walk_expr, check_expr.msg); + } + fn walk_lambda_expr(&mut self, lambda_expr: &ast::LambdaExpr) { + walk_if!(self, walk_arguments, lambda_expr.args); + walk_list!(self, walk_stmt, lambda_expr.body); + } + fn walk_keyword(&mut self, keyword: &ast::Keyword) { + self.walk_identifier(&keyword.arg.node); + if let Some(v) = &keyword.value { + self.walk_expr(&v.node) + } + } + fn walk_arguments(&mut self, arguments: &ast::Arguments) { + walk_list!(self, walk_identifier, arguments.args); + for default in arguments.defaults.iter().flatten() { + self.walk_expr(&default.node) + } + } + fn walk_compare(&mut self, compare: &ast::Compare) { + self.walk_expr(&compare.left.node); + walk_list!(self, walk_expr, compare.comparators); + } + fn walk_identifier(&mut self, identifier: &ast::Identifier) { + // Nothing to do. + let _ = identifier; + } + fn walk_target(&mut self, target: &ast::Target) { + for path in target.paths.iter() { + if let ast::MemberOrIndex::Index(index) = path { + self.walk_expr(&index.node) + } + } + } + fn walk_number_lit(&mut self, number_lit: &ast::NumberLit) { + let _ = number_lit; + } + fn walk_string_lit(&mut self, string_lit: &ast::StringLit) { + // Nothing to do. + let _ = string_lit; + } + fn walk_name_constant_lit(&mut self, name_constant_lit: &ast::NameConstantLit) { + // Nothing to do. + let _ = name_constant_lit; + } + fn walk_joined_string(&mut self, joined_string: &ast::JoinedString) { + walk_list!(self, walk_expr, joined_string.values); + } + fn walk_formatted_value(&mut self, formatted_value: &ast::FormattedValue) { + self.walk_expr(&formatted_value.value.node); + } + fn walk_comment(&mut self, comment: &ast::Comment) { + // Nothing to do. + let _ = comment; + } + fn walk_missing_expr(&mut self, missing_expr: &ast::MissingExpr) { + // Nothing to do. + let _ = missing_expr; + } + fn walk_module(&mut self, module: &ast::Module) { + walk_list!(self, walk_stmt, module.body) + } + fn walk_stmt(&mut self, stmt: &ast::Stmt) { + match stmt { + ast::Stmt::TypeAlias(type_alias) => self.walk_type_alias_stmt(type_alias), + ast::Stmt::Expr(expr_stmt) => self.walk_expr_stmt(expr_stmt), + ast::Stmt::Unification(unification_stmt) => { + self.walk_unification_stmt(unification_stmt) + } + ast::Stmt::Assign(assign_stmt) => self.walk_assign_stmt(assign_stmt), + ast::Stmt::AugAssign(aug_assign_stmt) => self.walk_aug_assign_stmt(aug_assign_stmt), + ast::Stmt::Assert(assert_stmt) => self.walk_assert_stmt(assert_stmt), + ast::Stmt::If(if_stmt) => self.walk_if_stmt(if_stmt), + ast::Stmt::Import(import_stmt) => self.walk_import_stmt(import_stmt), + ast::Stmt::SchemaAttr(schema_attr) => self.walk_schema_attr(schema_attr), + ast::Stmt::Schema(schema_stmt) => self.walk_schema_stmt(schema_stmt), + ast::Stmt::Rule(rule_stmt) => self.walk_rule_stmt(rule_stmt), + } + } + fn walk_expr(&mut self, expr: &ast::Expr) { + match expr { + ast::Expr::Target(target) => self.walk_target(target), + ast::Expr::Identifier(identifier) => self.walk_identifier(identifier), + ast::Expr::Unary(unary_expr) => self.walk_unary_expr(unary_expr), + ast::Expr::Binary(binary_expr) => self.walk_binary_expr(binary_expr), + ast::Expr::If(if_expr) => self.walk_if_expr(if_expr), + ast::Expr::Selector(selector_expr) => self.walk_selector_expr(selector_expr), + ast::Expr::Call(call_expr) => self.walk_call_expr(call_expr), + ast::Expr::Paren(paren_expr) => self.walk_paren_expr(paren_expr), + ast::Expr::Quant(quant_expr) => self.walk_quant_expr(quant_expr), + ast::Expr::List(list_expr) => self.walk_list_expr(list_expr), + ast::Expr::ListIfItem(list_if_item_expr) => { + self.walk_list_if_item_expr(list_if_item_expr) + } + ast::Expr::ListComp(list_comp) => self.walk_list_comp(list_comp), + ast::Expr::Starred(starred_expr) => self.walk_starred_expr(starred_expr), + ast::Expr::DictComp(dict_comp) => self.walk_dict_comp(dict_comp), + ast::Expr::ConfigIfEntry(config_if_entry_expr) => { + self.walk_config_if_entry_expr(config_if_entry_expr) + } + ast::Expr::CompClause(comp_clause) => self.walk_comp_clause(comp_clause), + ast::Expr::Schema(schema_expr) => self.walk_schema_expr(schema_expr), + ast::Expr::Config(config_expr) => self.walk_config_expr(config_expr), + ast::Expr::Check(check) => self.walk_check_expr(check), + ast::Expr::Lambda(lambda) => self.walk_lambda_expr(lambda), + ast::Expr::Subscript(subscript) => self.walk_subscript(subscript), + ast::Expr::Keyword(keyword) => self.walk_keyword(keyword), + ast::Expr::Arguments(arguments) => self.walk_arguments(arguments), + ast::Expr::Compare(compare) => self.walk_compare(compare), + ast::Expr::NumberLit(number_lit) => self.walk_number_lit(number_lit), + ast::Expr::StringLit(string_lit) => self.walk_string_lit(string_lit), + ast::Expr::NameConstantLit(name_constant_lit) => { + self.walk_name_constant_lit(name_constant_lit) + } + ast::Expr::JoinedString(joined_string) => self.walk_joined_string(joined_string), + ast::Expr::FormattedValue(formatted_value) => { + self.walk_formatted_value(formatted_value) + } + ast::Expr::Missing(missing_expr) => self.walk_missing_expr(missing_expr), + } + } +} diff --git a/kclvm/ast_pretty/Cargo.toml b/kclvm/ast_pretty/Cargo.toml new file mode 100644 index 000000000..eacb583f8 --- /dev/null +++ b/kclvm/ast_pretty/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "kclvm-ast-pretty" +version = "0.11.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +kclvm-error = {path = "../error"} +kclvm-ast = {path = "../ast"} + +indexmap = "1.0" +fancy-regex = "0.7.1" +pretty_assertions = "1.3.0" +compiler_base_session = "0.1.3" +compiler_base_macros = "0.1.1" + +[dev-dependencies] +kclvm-parser = {path = "../parser"} diff --git a/kclvm/ast_pretty/src/lib.rs b/kclvm/ast_pretty/src/lib.rs new file mode 100644 index 000000000..b4074971e --- /dev/null +++ b/kclvm/ast_pretty/src/lib.rs @@ -0,0 +1,291 @@ +use indexmap::IndexMap; +use kclvm_ast::{ + ast::{self, Module}, + token::TokenKind, + walker::MutSelfTypedResultWalker, +}; +use std::collections::VecDeque; +mod node; + +#[cfg(test)] +mod tests; + +pub const WHITESPACE: &str = " "; +pub const TAB: &str = "\t"; +pub const NEWLINE: &str = "\n"; + +#[derive(Debug, Clone)] +pub enum Indentation { + Indent = 0, + Dedent = 1, + Newline = 2, + IndentWithNewline = 3, + DedentWithNewline = 4, + Fill = 5, +} + +/// Printer config +#[derive(Debug)] +pub struct Config { + pub tab_len: usize, + pub indent_len: usize, + pub use_spaces: bool, + pub write_comments: bool, +} + +impl Default for Config { + fn default() -> Self { + Self { + tab_len: 4, + indent_len: 4, + use_spaces: true, + write_comments: true, + } + } +} + +#[derive(Copy, Clone)] +pub struct NoHook; + +impl PrinterHook for NoHook {} + +pub enum ASTNode<'p> { + Stmt(&'p ast::NodeRef), + Expr(&'p ast::NodeRef), +} + +pub trait PrinterHook { + fn pre(&self, _printer: &mut Printer<'_>, _node: ASTNode<'_>) {} + fn post(&self, _printer: &mut Printer<'_>, _node: ASTNode<'_>) {} +} + +pub struct Printer<'p> { + /// Output string buffer. + pub out: String, + pub indent: usize, + pub cfg: Config, + /// Print comments, + pub comments: VecDeque>, + pub import_spec: IndexMap, + pub hook: &'p (dyn PrinterHook + 'p), + /// Last AST expr/stmt line, default is 0. + last_ast_line: u64, +} + +impl Default for Printer<'_> { + fn default() -> Self { + Self { + hook: &NoHook, + out: Default::default(), + indent: Default::default(), + cfg: Default::default(), + comments: Default::default(), + import_spec: Default::default(), + last_ast_line: Default::default(), + } + } +} + +impl<'p> Printer<'p> { + pub fn new(cfg: Config, hook: &'p (dyn PrinterHook + 'p)) -> Self { + Self { + out: "".to_string(), + indent: 0, + cfg, + comments: VecDeque::default(), + import_spec: IndexMap::default(), + hook, + last_ast_line: 0, + } + } + + // -------------------------- + // Write functions + // -------------------------- + + /// Write a string + #[inline] + pub fn write(&mut self, text: &str) { + self.write_string(text); + } + + /// Write a string with newline. + #[inline] + pub fn writeln(&mut self, text: &str) { + self.write_string(text); + self.write_string(NEWLINE); + self.fill(""); + } + + /// Write a space. + #[inline] + pub fn write_space(&mut self) { + self.write_string(WHITESPACE); + } + + /// Fill a indent + pub fn fill(&mut self, text: &str) { + if self.cfg.use_spaces { + self.write(&format!( + "{}{}", + WHITESPACE.repeat(self.indent * self.cfg.indent_len), + text + )); + } else { + self.write(&format!("{}{}", TAB.repeat(self.indent), text)); + } + } + + /// Print string + #[inline] + pub fn write_string(&mut self, string: &str) { + self.out.push_str(string); + } + + pub fn write_indentation(&mut self, indentation: Indentation) { + match indentation { + Indentation::Indent => self.enter(), + Indentation::Dedent => self.leave(), + Indentation::Newline => self.write_newline(), + Indentation::IndentWithNewline => { + self.enter(); + self.write_newline() + } + Indentation::DedentWithNewline => { + self.leave(); + self.write_newline(); + } + Indentation::Fill => self.fill(""), + } + } + + #[inline] + pub fn write_newline(&mut self) { + self.writeln("") + } + + #[inline] + pub fn write_newline_without_fill(&mut self) { + self.write_string(NEWLINE); + } + + /// Print value + #[inline] + pub fn write_value(&mut self, value: T) { + self.write(&format!("{}", value)); + } + + /// Print ast token + #[inline] + pub fn write_token(&mut self, tok: TokenKind) { + let tok_str: String = tok.into(); + self.write_string(&tok_str); + } + + /// Print ast node + #[inline] + pub fn write_node(&mut self, node: ASTNode<'_>) { + match node { + ASTNode::Stmt(stmt) => self.stmt(stmt), + ASTNode::Expr(expr) => self.expr(expr), + } + } + + /// Print ast module. + #[inline] + pub fn write_module(&mut self, module: &ast::Module) { + self.walk_module(module); + while let Some(comment) = self.comments.pop_front() { + self.writeln(&comment.node.text); + self.fill(""); + } + } + + /// Wether has comments on ast node. + pub(crate) fn has_comments_on_node(&mut self, node: &ast::NodeRef) -> bool { + if !self.cfg.write_comments { + return false; + } + let mut index = None; + for (i, comment) in self.comments.iter().enumerate() { + if comment.line <= node.line { + index = Some(i); + } else { + break; + } + } + index.is_some() + } + + /// Print ast comments. + pub fn update_last_ast_line(&mut self, node: &ast::NodeRef) { + if node.line > self.last_ast_line { + self.last_ast_line = node.line; + } + } + + /// Print ast comments. + pub fn write_comments_before_node(&mut self, node: &ast::NodeRef) { + if !self.cfg.write_comments { + return; + } + if node.line > self.last_ast_line { + self.last_ast_line = node.line; + let mut index = None; + for (i, comment) in self.comments.iter().enumerate() { + if comment.line <= node.line { + index = Some(i); + } else { + break; + } + } + if let Some(index) = index { + let mut count = index as isize; + while count >= 0 { + match self.comments.pop_front() { + Some(comment) => { + self.writeln(&comment.node.text); + } + None => break, + } + count -= 1; + } + } + } + } + + // -------------------------- + // Indent and scope functions + // -------------------------- + + /// Enter with a indent + pub fn enter(&mut self) { + self.indent += 1; + } + + /// Leave with a dedent + pub fn leave(&mut self) { + self.indent -= 1; + } +} + +/// Print AST to string. The default format is according to the KCL code style defined here: https://kcl-lang.io/docs/reference/lang/spec/codestyle +pub fn print_ast_module(module: &Module) -> String { + let mut printer = Printer::default(); + printer.write_module(module); + printer.out +} + +/// Print AST to string +pub fn print_ast_node(node: ASTNode) -> String { + let mut printer = Printer::default(); + printer.write_node(node); + printer.out +} + +/// Print schema expression AST node to string. +pub fn print_schema_expr(schema_expr: &ast::SchemaExpr) -> String { + let mut printer = Printer::default(); + printer.walk_schema_expr(schema_expr); + printer.out +} diff --git a/kclvm/ast_pretty/src/node.rs b/kclvm/ast_pretty/src/node.rs new file mode 100644 index 000000000..3f4c7f21a --- /dev/null +++ b/kclvm/ast_pretty/src/node.rs @@ -0,0 +1,1009 @@ +use std::collections::HashSet; + +use compiler_base_macros::bug; +use kclvm_ast::{ + ast::{self, CallExpr}, + token::{DelimToken, TokenKind}, + walker::MutSelfTypedResultWalker, +}; + +use super::{Indentation, Printer}; + +type ParameterType<'a> = ( + (&'a ast::NodeRef, Option), + &'a Option>, +); + +const COMMA_WHITESPACE: &str = ", "; +const IDENTIFIER_REGEX: &str = r#"^\$?[a-zA-Z_]\w*$"#; + +macro_rules! interleave { + ($inter: expr, $f: expr, $seq: expr) => { + if !$seq.is_empty() { + $f(&$seq[0]); + for s in &$seq[1..] { + $inter(); + $f(s); + } + } + }; +} + +impl<'p, 'ctx> MutSelfTypedResultWalker<'ctx> for Printer<'p> { + type Result = (); + + fn walk_module(&mut self, module: &'ctx ast::Module) -> Self::Result { + for comment in &module.comments { + self.comments.push_back(comment.clone()); + } + if let Some(doc) = &module.doc { + self.write(&doc.node); + self.write_newline(); + } + + self.stmts(&module.body); + } + + fn walk_expr_stmt(&mut self, expr_stmt: &'ctx ast::ExprStmt) -> Self::Result { + interleave!( + || self.write(COMMA_WHITESPACE), + |expr| self.expr(expr), + expr_stmt.exprs + ); + self.write_newline_without_fill(); + } + + fn walk_unification_stmt( + &mut self, + unification_stmt: &'ctx ast::UnificationStmt, + ) -> Self::Result { + self.walk_identifier(&unification_stmt.target.node); + self.write(": "); + self.walk_schema_expr(&unification_stmt.value.node); + self.write_newline_without_fill(); + } + + fn walk_type_alias_stmt(&mut self, type_alias_stmt: &'ctx ast::TypeAliasStmt) -> Self::Result { + self.write("type"); + self.write_space(); + self.walk_identifier(&type_alias_stmt.type_name.node); + self.write(" = "); + self.write(&type_alias_stmt.type_value.node); + self.write_newline_without_fill(); + } + + fn walk_assign_stmt(&mut self, assign_stmt: &'ctx ast::AssignStmt) -> Self::Result { + for (i, target) in assign_stmt.targets.iter().enumerate() { + self.walk_target(&target.node); + if i == 0 { + if let Some(ty) = &assign_stmt.ty { + self.write(": "); + self.write(&ty.node.to_string()); + } + } + self.write(" = "); + } + self.expr(&assign_stmt.value); + self.write_newline_without_fill(); + } + + fn walk_aug_assign_stmt(&mut self, aug_assign_stmt: &'ctx ast::AugAssignStmt) -> Self::Result { + self.walk_target(&aug_assign_stmt.target.node); + self.write_space(); + self.write(aug_assign_stmt.op.symbol()); + self.write_space(); + self.expr(&aug_assign_stmt.value); + self.write_newline_without_fill(); + } + + fn walk_assert_stmt(&mut self, assert_stmt: &'ctx ast::AssertStmt) -> Self::Result { + self.write("assert "); + self.expr(&assert_stmt.test); + if let Some(if_cond) = &assert_stmt.if_cond { + self.write(" if "); + self.expr(if_cond); + } + if let Some(msg) = &assert_stmt.msg { + self.write(COMMA_WHITESPACE); + self.expr(msg); + } + self.write_newline_without_fill(); + } + + fn walk_if_stmt(&mut self, if_stmt: &'ctx ast::IfStmt) -> Self::Result { + self.write("if "); + self.expr(&if_stmt.cond); + self.write_token(TokenKind::Colon); + self.write_newline_without_fill(); + self.write_indentation(Indentation::Indent); + self.stmts(&if_stmt.body); + self.write_indentation(Indentation::Dedent); + + if !if_stmt.orelse.is_empty() { + // Check if orelse contains exactly one if statement + if if_stmt.orelse.len() == 1 { + if let ast::Stmt::If(elif_stmt) = &if_stmt.orelse[0].node { + // Nested if statements need to be considered, + // so `el` needs to be preceded by the current indentation. + self.fill("el"); + self.walk_if_stmt(elif_stmt); + } else { + self.fill("else:"); + self.write_newline_without_fill(); + self.write_indentation(Indentation::Indent); + self.stmts(&if_stmt.orelse); + self.write_indentation(Indentation::Dedent); + } + } else { + // Handle multiple else statements + self.fill("else:"); + self.write_newline_without_fill(); + self.write_indentation(Indentation::Indent); + self.stmts(&if_stmt.orelse); + self.write_indentation(Indentation::Dedent); + } + } else { + self.write_newline_without_fill(); + } + } + + fn walk_import_stmt(&mut self, import_stmt: &'ctx ast::ImportStmt) -> Self::Result { + self.write("import "); + // use `import_stmt.rawpath` to write the raw path + // otherwise, use `import_stmt.path` will replace `import .xxx` with `import xxx` + self.write(&import_stmt.rawpath); + if let Some(as_name) = &import_stmt.asname { + self.write(" as "); + self.write(&as_name.node); + } + self.write_newline_without_fill(); + } + + fn walk_schema_stmt(&mut self, schema_stmt: &'ctx ast::SchemaStmt) -> Self::Result { + interleave!( + || self.write_newline(), + |expr: &ast::NodeRef| { + self.write_comments_before_node(&expr); + self.write("@"); + self.walk_call_expr(&expr.node); + }, + schema_stmt.decorators + ); + if !schema_stmt.decorators.is_empty() { + self.write_newline(); + } + if schema_stmt.is_mixin { + self.write("mixin "); + } else if schema_stmt.is_protocol { + self.write("protocol "); + } else { + self.write("schema "); + } + self.write(&schema_stmt.name.node); + if let Some(args) = &schema_stmt.args { + self.write("["); + self.walk_arguments(&args.node); + self.write("]"); + } + if let Some(parent_name) = &schema_stmt.parent_name { + self.write("("); + self.walk_identifier(&parent_name.node); + self.write(")"); + } + if let Some(host_name) = &schema_stmt.for_host_name { + self.write(" for "); + self.walk_identifier(&host_name.node); + } + self.write_token(TokenKind::Colon); + self.write_newline_without_fill(); + self.write_indentation(Indentation::Indent); + + if let Some(doc) = &schema_stmt.doc { + self.fill(""); + self.write(&doc.node); + self.write_newline_without_fill(); + } + + if !schema_stmt.mixins.is_empty() { + self.fill(""); + self.write("mixin ["); + self.write_indentation(Indentation::IndentWithNewline); + interleave!( + || { + self.write(","); + self.write_newline(); + }, + |mixin_name: &ast::NodeRef| { + self.write_comments_before_node(&mixin_name); + self.walk_identifier(&mixin_name.node); + }, + schema_stmt.mixins + ); + self.write_indentation(Indentation::Dedent); + self.write_newline(); + self.write("]"); + self.write_newline_without_fill(); + } + if let Some(index_signature) = &schema_stmt.index_signature { + self.fill(""); + self.write_comments_before_node(index_signature); + self.write_token(TokenKind::OpenDelim(DelimToken::Bracket)); + if index_signature.node.any_other { + self.write_token(TokenKind::DotDotDot); + } + if let Some(key_name) = &index_signature.node.key_name { + self.write(&format!("{}: ", key_name.node)); + } + self.write(&index_signature.node.key_ty.node.to_string()); + self.write_token(TokenKind::CloseDelim(DelimToken::Bracket)); + self.write_token(TokenKind::Colon); + self.write_space(); + self.write(&index_signature.node.value_ty.node.to_string()); + if let Some(value) = &index_signature.node.value { + self.write(" = "); + self.expr(value); + } + self.write_newline_without_fill(); + } + self.stmts(&schema_stmt.body); + self.write_newline_without_fill(); + if !schema_stmt.checks.is_empty() { + self.fill("check:"); + // Schema check indent + self.write_indentation(Indentation::IndentWithNewline); + interleave!( + || self.write_newline(), + |check_expr: &ast::NodeRef| { + self.write_comments_before_node(&check_expr); + self.walk_check_expr(&check_expr.node); + }, + schema_stmt.checks + ); + self.write_newline_without_fill(); + // Schema check dedent + self.write_indentation(Indentation::Dedent); + self.write_newline_without_fill(); + } + // Schema Stmt dedent + self.write_indentation(Indentation::Dedent); + } + + fn walk_rule_stmt(&mut self, rule_stmt: &'ctx ast::RuleStmt) -> Self::Result { + interleave!( + || self.write_newline(), + |expr: &ast::NodeRef| { + self.write("@"); + self.walk_call_expr(&expr.node); + }, + rule_stmt.decorators + ); + if !rule_stmt.decorators.is_empty() { + self.write_newline(); + } + self.write("rule "); + self.write(&rule_stmt.name.node); + if let Some(args) = &rule_stmt.args { + self.write("["); + self.walk_arguments(&args.node); + self.write("]"); + } + if !rule_stmt.parent_rules.is_empty() { + self.write("("); + interleave!( + || self.write(COMMA_WHITESPACE), + |identifier: &ast::NodeRef| self.walk_identifier(&identifier.node), + rule_stmt.parent_rules + ); + self.write(")"); + } + if let Some(host_name) = &rule_stmt.for_host_name { + self.write(" for "); + self.walk_identifier(&host_name.node); + } + self.write_token(TokenKind::Colon); + // Rule Stmt indent + self.write_indentation(Indentation::IndentWithNewline); + if let Some(doc) = &rule_stmt.doc { + self.write(&doc.node); + self.write_newline(); + } + if !rule_stmt.checks.is_empty() { + interleave!( + || self.write_newline(), + |check_expr: &ast::NodeRef| { + self.write_comments_before_node(&check_expr); + self.walk_check_expr(&check_expr.node); + }, + rule_stmt.checks + ); + self.write_newline_without_fill(); + } + // Rule Stmt dedent + self.write_indentation(Indentation::Dedent); + } + + fn walk_quant_expr(&mut self, quant_expr: &'ctx ast::QuantExpr) -> Self::Result { + let in_one_line = self.last_ast_line > 0 && quant_expr.test.line == self.last_ast_line; + let quant_op_string: String = quant_expr.op.clone().into(); + self.write(&quant_op_string); + self.write_space(); + interleave!( + || self.write(COMMA_WHITESPACE), + |identifier: &ast::NodeRef| self.walk_identifier(&identifier.node), + quant_expr.variables + ); + self.write(" in "); + self.expr(&quant_expr.target); + self.write(" {"); + if !in_one_line { + self.write_indentation(Indentation::IndentWithNewline); + } + self.expr(&quant_expr.test); + if let Some(if_cond) = &quant_expr.if_cond { + self.write(" if "); + self.expr(if_cond); + } + if !in_one_line { + self.write_indentation(Indentation::DedentWithNewline) + } + self.write("}") + } + + fn walk_schema_attr(&mut self, schema_attr: &'ctx ast::SchemaAttr) -> Self::Result { + interleave!( + || self.write_newline(), + |expr: &ast::NodeRef| { + self.write_comments_before_node(&expr); + self.write("@"); + self.walk_call_expr(&expr.node) + }, + schema_attr.decorators + ); + if !schema_attr.decorators.is_empty() { + self.write_newline(); + } + // A schema string attribute needs quote. + if !schema_attr.is_ident_attr() { + self.write(&format!("{:?}", schema_attr.name.node)); + } else { + self.write_attribute(&schema_attr.name); + } + if schema_attr.is_optional { + self.write("?"); + } + self.write(": "); + self.write(&schema_attr.ty.node.to_string()); + if let Some(op) = &schema_attr.op { + let symbol = op.symbol(); + self.write_space(); + self.write(symbol); + self.write_space(); + } + if let Some(value) = &schema_attr.value { + self.expr(value); + } + self.write_newline_without_fill(); + } + + fn walk_if_expr(&mut self, if_expr: &'ctx ast::IfExpr) -> Self::Result { + self.expr(&if_expr.body); + self.write(" if "); + self.expr(&if_expr.cond); + self.write(" else "); + self.expr(&if_expr.orelse); + } + + fn walk_unary_expr(&mut self, unary_expr: &'ctx ast::UnaryExpr) -> Self::Result { + self.write(unary_expr.op.symbol()); + // Four forms: `+expr`, `-expr`, `~expr`, `not expr` + // `not expr` needs a space between `not` and `expr` + if matches!(unary_expr.op, ast::UnaryOp::Not) { + self.write_space(); + } + self.expr(&unary_expr.operand); + } + + fn walk_binary_expr(&mut self, binary_expr: &'ctx ast::BinaryExpr) -> Self::Result { + let symbol = binary_expr.op.symbol(); + self.expr(&binary_expr.left); + self.write_space(); + self.write(symbol); + self.write_space(); + self.expr(&binary_expr.right); + } + + fn walk_selector_expr(&mut self, selector_expr: &'ctx ast::SelectorExpr) -> Self::Result { + self.expr(&selector_expr.value); + self.write(if selector_expr.has_question { + "?." + } else { + "." + }); + self.walk_identifier(&selector_expr.attr.node); + } + + fn walk_call_expr(&mut self, call_expr: &'ctx ast::CallExpr) -> Self::Result { + self.expr(&call_expr.func); + self.write("("); + self.write_args_and_kwargs(&call_expr.args, &call_expr.keywords); + self.write(")"); + } + + fn walk_subscript(&mut self, subscript: &'ctx ast::Subscript) -> Self::Result { + self.expr(&subscript.value); + if subscript.has_question { + self.write("?"); + } + self.write("["); + if let Some(index) = &subscript.index { + self.expr(index); + } else { + if let Some(lower) = &subscript.lower { + self.expr(lower); + } + self.write_token(TokenKind::Colon); + if let Some(upper) = &subscript.upper { + self.expr(upper); + } + self.write_token(TokenKind::Colon); + if let Some(step) = &subscript.step { + self.expr(step); + } + } + self.write("]"); + } + + fn walk_paren_expr(&mut self, paren_expr: &'ctx ast::ParenExpr) -> Self::Result { + self.write_token(TokenKind::OpenDelim(DelimToken::Paren)); + self.expr(&paren_expr.expr); + self.write_token(TokenKind::CloseDelim(DelimToken::Paren)); + } + + fn walk_list_expr(&mut self, list_expr: &'ctx ast::ListExpr) -> Self::Result { + let mut line_set = list_expr + .elts + .iter() + .map(|e| e.line) + .filter(|l| *l > 0) + .collect::>(); + if self.last_ast_line > 0 { + line_set.insert(self.last_ast_line); + } + // There are comments in the configuration block. + let has_comment = !list_expr.elts.is_empty() + && list_expr + .elts + .iter() + .map(|e| self.has_comments_on_node(e)) + .all(|r| r); + // When there are comments in the configuration block, print them as multiline configurations. + let mut in_one_line = line_set.len() <= 1 && !has_comment; + if let Some(elt) = list_expr.elts.first() { + if let ast::Expr::ListIfItem(_) = &elt.node { + in_one_line = false; + } + } + self.write_token(TokenKind::OpenDelim(DelimToken::Bracket)); + if !in_one_line { + self.write_indentation(Indentation::IndentWithNewline); + } + interleave!( + || if in_one_line { + self.write(COMMA_WHITESPACE); + } else { + self.write_newline(); + }, + |elt| { + self.write_comments_before_node(elt); + self.expr(elt); + }, + list_expr.elts + ); + if !in_one_line { + self.write_indentation(Indentation::DedentWithNewline); + } + self.write_token(TokenKind::CloseDelim(DelimToken::Bracket)); + } + + fn walk_list_comp(&mut self, list_comp: &'ctx ast::ListComp) -> Self::Result { + self.write_token(TokenKind::OpenDelim(DelimToken::Bracket)); + self.expr(&list_comp.elt); + for gen in &list_comp.generators { + self.walk_comp_clause(&gen.node); + } + self.write_token(TokenKind::CloseDelim(DelimToken::Bracket)); + } + + fn walk_list_if_item_expr( + &mut self, + list_if_item_expr: &'ctx ast::ListIfItemExpr, + ) -> Self::Result { + self.write("if "); + self.expr(&list_if_item_expr.if_cond); + self.write(":"); + self.write_indentation(Indentation::IndentWithNewline); + interleave!( + || self.write_newline(), + |expr| { + self.write_comments_before_node(expr); + self.expr(expr); + }, + list_if_item_expr.exprs + ); + self.write_indentation(Indentation::Dedent); + if let Some(orelse) = &list_if_item_expr.orelse { + self.write_newline(); + match &orelse.node { + ast::Expr::List(list_expr) => { + self.write("else:"); + self.write_indentation(Indentation::IndentWithNewline); + interleave!( + || self.write_newline(), + |expr| { + self.write_comments_before_node(expr); + self.expr(expr); + }, + list_expr.elts + ); + self.write_indentation(Indentation::Dedent); + } + ast::Expr::ListIfItem(_) => { + self.write("el"); + self.expr(orelse); + } + _ => bug!("Invalid list if expr orelse node {:?}", orelse.node), + } + } + } + + fn walk_starred_expr(&mut self, starred_expr: &'ctx ast::StarredExpr) -> Self::Result { + self.write("*"); + self.expr(&starred_expr.value) + } + + fn walk_dict_comp(&mut self, dict_comp: &'ctx ast::DictComp) -> Self::Result { + self.write_token(TokenKind::OpenDelim(DelimToken::Brace)); + self.expr(match &dict_comp.entry.key { + Some(key) => key, + None => bug!("Invalid dict comp key"), + }); + if !matches!(dict_comp.entry.operation, ast::ConfigEntryOperation::Union) { + self.write_space(); + } + self.write(dict_comp.entry.operation.symbol()); + self.write_space(); + self.expr(&dict_comp.entry.value); + for gen in &dict_comp.generators { + self.walk_comp_clause(&gen.node); + } + self.write_token(TokenKind::CloseDelim(DelimToken::Brace)); + } + + fn walk_config_if_entry_expr( + &mut self, + config_if_entry_expr: &'ctx ast::ConfigIfEntryExpr, + ) -> Self::Result { + self.write("if "); + self.expr(&config_if_entry_expr.if_cond); + self.write_token(TokenKind::Colon); + self.write_indentation(Indentation::IndentWithNewline); + interleave!( + || self.write_newline(), + |entry: &ast::NodeRef| self.write_entry(entry), + config_if_entry_expr.items + ); + self.write_indentation(Indentation::Dedent); + if let Some(orelse) = &config_if_entry_expr.orelse { + self.write_newline(); + match &orelse.node { + ast::Expr::Config(config_expr) => { + self.write("else:"); + self.write_indentation(Indentation::IndentWithNewline); + interleave!( + || self.write_newline(), + |entry: &ast::NodeRef| self.write_entry(entry), + config_expr.items + ); + self.write_indentation(Indentation::Dedent); + } + ast::Expr::ConfigIfEntry(_) => { + self.write("el"); + self.expr(orelse); + } + _ => bug!("Invalid config if expr orelse node {:?}", orelse.node), + } + } + } + + fn walk_comp_clause(&mut self, comp_clause: &'ctx ast::CompClause) -> Self::Result { + self.write(" for "); + interleave!( + || self.write(COMMA_WHITESPACE), + |target: &ast::NodeRef| self.walk_identifier(&target.node), + comp_clause.targets + ); + self.write(" in "); + self.expr(&comp_clause.iter); + for if_clause in &comp_clause.ifs { + self.write(" if "); + self.expr(if_clause); + } + } + + fn walk_schema_expr(&mut self, schema_expr: &'ctx ast::SchemaExpr) -> Self::Result { + self.walk_identifier(&schema_expr.name.node); + if !schema_expr.args.is_empty() || !schema_expr.kwargs.is_empty() { + self.write_token(TokenKind::OpenDelim(DelimToken::Paren)); + self.write_args_and_kwargs(&schema_expr.args, &schema_expr.kwargs); + self.write_token(TokenKind::CloseDelim(DelimToken::Paren)); + } + self.write_space(); + self.expr(&schema_expr.config) + } + + fn walk_config_expr(&mut self, config_expr: &'ctx ast::ConfigExpr) -> Self::Result { + let mut line_set: HashSet = config_expr + .items + .iter() + .map(|item| item.line) + .filter(|l| *l > 0) + .collect(); + if self.last_ast_line > 0 { + line_set.insert(self.last_ast_line); + } + // There are comments in the configuration block. + let has_comment = !config_expr.items.is_empty() + && config_expr + .items + .iter() + .map(|item| self.has_comments_on_node(item)) + .all(|r| r); + // When there are comments in the configuration block, print them as multiline configurations. + let mut in_one_line = line_set.len() <= 1 && !has_comment; + // When there are complex configuration blocks in the configuration block, print them as multiline configurations. + if config_expr.items.len() == 1 && in_one_line { + if let Some(item) = config_expr.items.first() { + if matches!( + &item.node.value.node, + ast::Expr::ConfigIfEntry(_) | ast::Expr::Config(_) | ast::Expr::Schema(_) + ) { + in_one_line = false; + } + } + } + self.write_token(TokenKind::OpenDelim(DelimToken::Brace)); + if !config_expr.items.is_empty() { + if !in_one_line { + self.write_indentation(Indentation::IndentWithNewline); + } + interleave!( + || if in_one_line { + self.write(COMMA_WHITESPACE); + } else { + self.write_newline(); + }, + |entry: &ast::NodeRef| self.write_entry(entry), + config_expr.items + ); + if !in_one_line { + self.write_indentation(Indentation::DedentWithNewline); + } + } + self.write_token(TokenKind::CloseDelim(DelimToken::Brace)); + } + + fn walk_check_expr(&mut self, check_expr: &'ctx ast::CheckExpr) -> Self::Result { + self.expr(&check_expr.test); + if let Some(if_cond) = &check_expr.if_cond { + self.write(" if "); + self.expr(if_cond); + } + if let Some(msg) = &check_expr.msg { + self.write(COMMA_WHITESPACE); + self.expr(msg); + } + } + + fn walk_lambda_expr(&mut self, lambda_expr: &'ctx ast::LambdaExpr) -> Self::Result { + self.write("lambda"); + if let Some(args) = &lambda_expr.args { + self.write_space(); + self.walk_arguments(&args.node); + } + if let Some(ty_str) = &lambda_expr.return_ty { + self.write_space(); + self.write_token(TokenKind::RArrow); + self.write_space(); + self.write(&ty_str.node.to_string()); + } + self.write_space(); + self.write_token(TokenKind::OpenDelim(DelimToken::Brace)); + self.write_newline_without_fill(); + self.write_indentation(Indentation::Indent); + + // lambda body + self.stmts(&lambda_expr.body); + + self.write_indentation(Indentation::Dedent); + self.fill(""); + self.write_token(TokenKind::CloseDelim(DelimToken::Brace)); + } + + fn walk_keyword(&mut self, keyword: &'ctx ast::Keyword) -> Self::Result { + self.walk_identifier(&keyword.arg.node); + if let Some(value) = &keyword.value { + self.write("="); + self.expr(value); + } + } + + fn walk_arguments(&mut self, arguments: &'ctx ast::Arguments) -> Self::Result { + let parameter_zip_list: Vec> = arguments + .args + .iter() + .zip( + arguments + .ty_list + .iter() + .map(|ty| ty.clone().map(|n| n.node.to_string())), + ) + .zip(arguments.defaults.iter()) + .collect(); + interleave!( + || self.write(COMMA_WHITESPACE), + |para: &ParameterType<'_>| { + let ((arg, ty_str), default) = para; + self.walk_identifier(&arg.node); + if let Some(ty_str) = ty_str { + self.write(&format!(": {}", ty_str)); + } + if let Some(default) = default { + self.write(" = "); + self.expr(default); + } + }, + parameter_zip_list + ); + } + + fn walk_compare(&mut self, compare: &'ctx ast::Compare) -> Self::Result { + self.expr(&compare.left); + for (op, expr) in compare.ops.iter().zip(compare.comparators.iter()) { + self.write_space(); + self.write(op.symbol()); + self.write_space(); + self.expr(expr); + } + } + + #[inline] + fn walk_identifier(&mut self, identifier: &'ctx ast::Identifier) -> Self::Result { + self.write(&identifier.get_name()); + } + + #[inline] + fn walk_target(&mut self, target: &'ctx ast::Target) -> Self::Result { + self.write(target.get_name()); + for path in &target.paths { + match path { + ast::MemberOrIndex::Member(member) => { + self.write("."); + self.write(&member.node) + } + ast::MemberOrIndex::Index(index) => { + self.write("["); + self.walk_expr(&index.node); + self.write("]"); + } + } + } + } + + fn walk_number_lit(&mut self, number_lit: &'ctx ast::NumberLit) -> Self::Result { + match &number_lit.value { + ast::NumberLitValue::Int(int_val) => self.write(&int_val.to_string()), + ast::NumberLitValue::Float(float_val) => self.write(&float_val.to_string()), + } + // Number suffix e.g., 1Gi + if let Some(binary_suffix) = &number_lit.binary_suffix { + self.write(&binary_suffix.value()) + } + } + + fn walk_string_lit(&mut self, string_lit: &'ctx ast::StringLit) -> Self::Result { + if !string_lit.raw_value.is_empty() { + self.write(&string_lit.raw_value) + } else { + self.write(&if string_lit.is_long_string { + format!("\"\"\"{}\"\"\"", string_lit.value.replace('\"', "\\\"")) + } else { + format!("\"{}\"", string_lit.value.replace('\"', "\\\"")) + }); + } + } + + #[inline] + fn walk_name_constant_lit( + &mut self, + name_constant_lit: &'ctx ast::NameConstantLit, + ) -> Self::Result { + self.write(name_constant_lit.value.symbol()); + } + + fn walk_joined_string(&mut self, joined_string: &'ctx ast::JoinedString) -> Self::Result { + if !joined_string.raw_value.is_empty() { + self.write(&joined_string.raw_value) + } else { + let quote_str = if joined_string.is_long_string { + "\"\"\"" + } else { + "\"" + }; + self.write(quote_str); + for value in &joined_string.values { + match &value.node { + ast::Expr::StringLit(string_lit) => { + self.write(&string_lit.value.replace('\"', "\\\"")); + } + _ => self.expr(value), + } + } + self.write(quote_str); + } + } + + fn walk_formatted_value(&mut self, formatted_value: &'ctx ast::FormattedValue) -> Self::Result { + self.write("${"); + self.expr(&formatted_value.value); + if let Some(spec) = &formatted_value.format_spec { + self.write(&format!(": {}", spec)); + } + self.write("}"); + } + + fn walk_comment(&mut self, comment: &'ctx ast::Comment) -> Self::Result { + self.writeln(&comment.text); + self.fill(""); + } + + fn walk_missing_expr(&mut self, _missing_expr: &'ctx ast::MissingExpr) -> Self::Result { + // Nothing to do + } +} + +impl<'p> Printer<'p> { + pub fn write_args_and_kwargs( + &mut self, + args: &[ast::NodeRef], + kwargs: &[ast::NodeRef], + ) { + interleave!(|| self.write(COMMA_WHITESPACE), |arg| self.expr(arg), args); + if !args.is_empty() && !kwargs.is_empty() { + self.write(COMMA_WHITESPACE); + } + interleave!( + || self.write(COMMA_WHITESPACE), + |kwarg: &ast::NodeRef| self.walk_keyword(&kwarg.node), + kwargs + ); + } + + pub fn write_entry(&mut self, item: &ast::NodeRef) { + match &item.node.key { + Some(key) => { + let print_right_brace_count = self.write_config_key(key); + if !matches!(item.node.operation, ast::ConfigEntryOperation::Union) { + self.write_space(); + } + self.write(item.node.operation.symbol()); + self.write_space(); + self.expr(&item.node.value); + self.write(&"}".repeat(print_right_brace_count)); + } + None => { + self.write_comments_before_node(&item); + if !matches!(&item.node.value.node, ast::Expr::ConfigIfEntry(_)) { + self.write("**"); + } + self.expr(&item.node.value) + } + }; + } + + fn write_config_key(&mut self, key: &ast::NodeRef) -> usize { + match &key.node { + ast::Expr::Identifier(identifier) => { + self.hook.pre(self, super::ASTNode::Expr(key)); + self.write_comments_before_node(key); + // Judge contains string or dot identifier, e.g., "x-y-z" and "a.b.c" + let names = &identifier.names; + + let re = fancy_regex::Regex::new(IDENTIFIER_REGEX).unwrap(); + let need_right_brace = !names.iter().all(|n| re.is_match(&n.node).unwrap_or(false)); + let count = if need_right_brace { + self.write( + &names + .iter() + .map(|n| format!("{:?}", n.node)) + .collect::>() + .join(": {"), + ); + names.len() - 1 + } else { + self.expr(key); + 0 + }; + self.hook.post(self, super::ASTNode::Expr(key)); + count + } + _ => { + self.write_comments_before_node(key); + self.expr(key); + 0 + } + } + } + + fn write_attribute(&mut self, attr: &ast::NodeRef) { + let re = fancy_regex::Regex::new(IDENTIFIER_REGEX).unwrap(); + let need_quote = !re.is_match(&attr.node).unwrap(); + if need_quote { + self.write(&format!("{:?}", attr.node)); + } else { + self.write(&attr.node); + }; + } +} + +impl<'p> Printer<'p> { + // ------------------------------ + // Expr and Stmt walker functions + // ------------------------------ + + pub fn expr(&mut self, expr: &ast::NodeRef) { + self.hook.pre(self, super::ASTNode::Expr(expr)); + self.update_last_ast_line(expr); + self.walk_expr(&expr.node); + self.hook.post(self, super::ASTNode::Expr(expr)); + } + + pub fn stmt(&mut self, stmt: &ast::NodeRef) { + self.hook.pre(self, super::ASTNode::Stmt(stmt)); + self.fill(""); + self.write_comments_before_node(stmt); + self.walk_stmt(&stmt.node); + self.hook.post(self, super::ASTNode::Stmt(stmt)); + } + + pub fn exprs(&mut self, exprs: &[ast::NodeRef]) { + for expr in exprs { + self.expr(expr); + } + } + + pub fn stmts(&mut self, stmts: &[ast::NodeRef]) { + // Hold the prev statement pointer. + let mut prev_stmt: Option<&ast::NodeRef> = None; + for stmt in stmts { + let import_stmt_alter = match (prev_stmt.map(|s| &s.node).as_ref(), &stmt.node) { + (Some(ast::Stmt::Import(_)), ast::Stmt::Import(_)) => false, + (Some(ast::Stmt::Import(_)), _) => true, + _ => false, + }; + // Do not format out user-reserved blank lines: which does not mean that to preserve all user-written blank lines. + // For situations where there are more than two blank lines, we only keep one blank line. + let need_newline = if let Some(prev_stmt) = prev_stmt { + stmt.line > 0 + && stmt.line >= prev_stmt.end_line + 2 + && !self.has_comments_on_node(stmt) + } else { + false + }; + if import_stmt_alter || need_newline { + self.write_newline_without_fill(); + } + self.stmt(stmt); + prev_stmt = Some(stmt); + } + } +} diff --git a/kclvm/tools/src/printer/test_data/arguments.input b/kclvm/ast_pretty/src/test_data/arguments.input similarity index 100% rename from kclvm/tools/src/printer/test_data/arguments.input rename to kclvm/ast_pretty/src/test_data/arguments.input diff --git a/kclvm/tools/src/printer/test_data/arguments.output b/kclvm/ast_pretty/src/test_data/arguments.output similarity index 100% rename from kclvm/tools/src/printer/test_data/arguments.output rename to kclvm/ast_pretty/src/test_data/arguments.output diff --git a/kclvm/ast_pretty/src/test_data/codelayout.input b/kclvm/ast_pretty/src/test_data/codelayout.input new file mode 100644 index 000000000..54b6713b5 --- /dev/null +++ b/kclvm/ast_pretty/src/test_data/codelayout.input @@ -0,0 +1,174 @@ +""" +Module documents +""" + + +import math as alias_math +schema Person ( Base): + name:str + age:int + + "attr": str + "attr-x": str + check : + age>0 if age , "age must > 0" +person = Person{ + name:"Alice" + age:18 +} +if True: + a = 1 + + b = 2 + + + c = 3 +elif True: + b = 2 +else: + c = 3 +d = 1 + 2 +e = ( 1 + 2 ) +f=[ 1, 2, 3 ] +g = { "key" : "value" } +print (1) +dct={"key": "value"} +lst=[1,2,3] +h = dct [ 'key' ] +i = lst [ 1 ] +x = 1 +y = 2 +long_variable = 3 +i = i+1 +submitted+=1 +x = x*2 - 1 +hypot2 = x*x + y*y +_c = (a+b) * (a-b) +_b=2 +_c= 3 +_d =4 + +_value = (1 + 2 * 3) +_value = (1+2*3) +_value =1+ - 2 * ~ 3 +_list = [1, 2, 3] +_list = [*_list, [4, 5 ,6]] +_list = [* _list, [4, 5 ,6]] + +_dict = {** {"k": "v"}, ** {"k": "v"}} +a = [1,2,3] +b = [ + 1,2,3, + 4,5,6, +] +_dict={ + "k1":"v1" + "k2" :"v2" + "k3": "v3" + "k4" : "v4" + "k5" : "v5" +} +foo=1 +if foo is not None: + _a = 1 + _dict|={} + hello = "world{}" . format( 1 )[2 : 4] . lower( ) + range_int = [ i for i in range( 10 ) ] +op = 1+2 - - 3 + (3 - 1) // 3 +op += 1 +op -= 12 + 23 +print( " " , end= '') +log = math. log(12) +aa = 1 +assert aa == 1,"message" +assert aa == 1 if aa,"message" +aaaa = (1 + 2 / 2) if _a == 2 + + 134.3 else ("a"*3) +bbbb = "{}". format(a) +empty_list = [] +empty_config = {} +number_suffix = 1Gi +long_string_0 = """ +value +""" +long_string_1 = """\ +value +""" +long_string_2 = """\ +value""" +joined_data_0 = '\"false\" ${item.kind}: ${item.metadata.name}' +joined_data_1 = "\"false\" ${item.kind}: ${item.metadata.name}" +joined_data_2 = '''\ + ${CC} +''' +joined_data_3 = '''\ + $${CC} +''' +joined_data_4 = '''\ + \${CC} +''' + +# Member access and index assign targets +a[0].b -= 1 +a.b[0] += 1 +a.b[1].c /= 1 +a.b[c.d].e == 1 +a.b[1 + 1].e = 1 +a.b[f()].e = 1 + + +a=1 + + +b= 2 + + +c =3 + + + +d = 4 +e = 5 +f = lambda { + + +a=1 + + +b= 2 + + +c =3 + + + +d = 4 +e = 5 +} +config_if_entry = { + if True: a = 1 + elif False: + b = 2 + else: + c = 3 + d = 4 + **e + if a > 3: + e = 5 + elif a < 2: + f =6 + if True: + g = 7 +} +list_if_item = [ + if True: 1 + elif False: + 2 + else: + 3, 4 + *[5, 6] + if False: 2 +] + +longString = "Too long expression " + \ + "Too long expression " + \ + "Too long expression " # recommended diff --git a/kclvm/ast_pretty/src/test_data/codelayout.output b/kclvm/ast_pretty/src/test_data/codelayout.output new file mode 100644 index 000000000..2fcf3afca --- /dev/null +++ b/kclvm/ast_pretty/src/test_data/codelayout.output @@ -0,0 +1,170 @@ +""" +Module documents +""" +import math as alias_math + +schema Person(Base): + name: str + age: int + + "attr": str + "attr-x": str + + check: + age > 0 if age, "age must > 0" + +person = Person { + name: "Alice" + age: 18 +} +if True: + a = 1 + + b = 2 + + c = 3 +elif True: + b = 2 +else: + c = 3 +d = 1 + 2 +e = (1 + 2) +f = [1, 2, 3] +g = {"key": "value"} +print(1) +dct = {"key": "value"} +lst = [1, 2, 3] +h = dct['key'] +i = lst[1] +x = 1 +y = 2 +long_variable = 3 +i = i + 1 +submitted += 1 +x = x * 2 - 1 +hypot2 = x * x + y * y +_c = (a + b) * (a - b) +_b = 2 +_c = 3 +_d = 4 + +_value = (1 + 2 * 3) +_value = (1 + 2 * 3) +_value = 1 + -2 * ~3 +_list = [1, 2, 3] +_list = [*_list, [4, 5, 6]] +_list = [*_list, [4, 5, 6]] + +_dict = {**{"k": "v"}, **{"k": "v"}} +a = [1, 2, 3] +b = [ + 1 + 2 + 3 + 4 + 5 + 6 +] +_dict = { + "k1": "v1" + "k2": "v2" + "k3": "v3" + "k4": "v4" + "k5": "v5" +} +foo = 1 +if foo is not None: + _a = 1 + _dict |= {} + hello = "world{}".format(1)[2:4:].lower() + range_int = [i for i in range(10)] + +op = 1 + 2 - -3 + (3 - 1) // 3 +op += 1 +op -= 12 + 23 +print(" ", end='') +log = math.log(12) +aa = 1 +assert aa == 1, "message" +assert aa == 1 if aa, "message" +aaaa = (1 + 2 / 2) if _a == 2 + +134.3 else ("a" * 3) +bbbb = "{}".format(a) +empty_list = [] +empty_config = {} +number_suffix = 1Gi +long_string_0 = """ +value +""" +long_string_1 = """\ +value +""" +long_string_2 = """\ +value""" +joined_data_0 = '\"false\" ${item.kind}: ${item.metadata.name}' +joined_data_1 = "\"false\" ${item.kind}: ${item.metadata.name}" +joined_data_2 = '''\ + ${CC} +''' +joined_data_3 = '''\ + $${CC} +''' +joined_data_4 = '''\ + \${CC} +''' +# Member access and index assign targets +a[0].b -= 1 +a.b[0] += 1 +a.b[1].c /= 1 +a.b[c.d].e == 1 +a.b[1 + 1].e = 1 +a.b[f()].e = 1 + +a = 1 + +b = 2 + +c = 3 + +d = 4 +e = 5 +f = lambda { + a = 1 + + b = 2 + + c = 3 + + d = 4 + e = 5 +} +config_if_entry = { + if True: + a = 1 + elif False: + b = 2 + else: + c = 3 + d = 4 + **e + if a > 3: + e = 5 + elif a < 2: + f = 6 + if True: + g = 7 +} +list_if_item = [ + if True: + 1 + elif False: + 2 + else: + 3 + 4 + *[5, 6] + if False: + 2 +] + +longString = "Too long expression " + "Too long expression " + "Too long expression " +# recommended diff --git a/kclvm/ast_pretty/src/test_data/collection_if.input b/kclvm/ast_pretty/src/test_data/collection_if.input new file mode 100644 index 000000000..a263732a7 --- /dev/null +++ b/kclvm/ast_pretty/src/test_data/collection_if.input @@ -0,0 +1,53 @@ +schema Config: + name: str + env: str + data: [int] +env = "env" +data1 = Config { + if env == "env": + name: env + env: env + data += [0] + else: + name = "name" + env = "name" + data += [1] +} +data1 = Config { + if env == "env": + name: env + env: env + else: + name: "name" + env: "name" +} +data2 = Config { + if env != "env": + name: env + env: env + else: + name: "name" + env: "name" +} +data3 = { + if True: + key1: "value1" + elif True: + key2: "value2" + elif True: + key3: "value3" + else: + key4: "value4" +} + + +data4 = [ + if True: + "value1" + elif True: + "value2" + elif True: + "value3" + else: + "value4" +] diff --git a/kclvm/ast_pretty/src/test_data/collection_if.output b/kclvm/ast_pretty/src/test_data/collection_if.output new file mode 100644 index 000000000..3a092a9a5 --- /dev/null +++ b/kclvm/ast_pretty/src/test_data/collection_if.output @@ -0,0 +1,53 @@ +schema Config: + name: str + env: str + data: [int] + +env = "env" +data1 = Config { + if env == "env": + name: env + env: env + data += [0] + else: + name = "name" + env = "name" + data += [1] +} +data1 = Config { + if env == "env": + name: env + env: env + else: + name: "name" + env: "name" +} +data2 = Config { + if env != "env": + name: env + env: env + else: + name: "name" + env: "name" +} +data3 = { + if True: + key1: "value1" + elif True: + key2: "value2" + elif True: + key3: "value3" + else: + key4: "value4" +} + +data4 = [ + if True: + "value1" + elif True: + "value2" + elif True: + "value3" + else: + "value4" +] diff --git a/kclvm/ast_pretty/src/test_data/comment.input b/kclvm/ast_pretty/src/test_data/comment.input new file mode 100644 index 000000000..7052c4f7a --- /dev/null +++ b/kclvm/ast_pretty/src/test_data/comment.input @@ -0,0 +1,80 @@ +# Comment One +schema Main: + name?: str + env?: [{str:}] + +# Comment Two +schema AppConfiguration: + appName: str + image: str + overQuota: bool = False + resource: {str:} + mainContainer?: Main + labels: {str:} + +# Comment Three +appConfiguration = AppConfiguration { + # Comment Four + appName: "kusion" + image: "test-image:v1" # Comment Five + resource: { + cpu: "4" + disk: "50Gi" + memory: "12Gi" + } + labels: { + key1: { + key1: 12 + } + key2: {key2: 34} + } + # Comment Six + mainContainer: Main { + name: "kusion_override" + }# Comment Seven + + # Comment Eight + overQuota: True +} +# Comment Nine + +@Deprecated # Deprecated +schema Foo: + mixin [ + AMixin, # AMixin + # BMixin + BMixin + ] + # Comment for index signature + [k: str]: int + # Comment for `x` field + x: int + + check: + x > 0 # x > 0 + # x < 0 + x < 0 + +config = { # Comment One + # Comment Two + key1 = "value1" # Comment Three + # Comment Four + key2 = \ + "value2" # Comment Five + key3 = "value3" + # Comment Six + "key4" = "value4" + # Comment Seven + key5.v = "value5" + **key6 # Comment Eight + if True: # Comment Nine + key7 = "value7" # Comment Ten +} +data = [ # Comment One + # Comment Two + 1 # Comment Three + if True: # Comment Four + 2 # Comment Five + # Comment Six + *[3, 4] # Comment Seven +] \ No newline at end of file diff --git a/kclvm/ast_pretty/src/test_data/comment.output b/kclvm/ast_pretty/src/test_data/comment.output new file mode 100644 index 000000000..5547687b3 --- /dev/null +++ b/kclvm/ast_pretty/src/test_data/comment.output @@ -0,0 +1,93 @@ +# Comment One +schema Main: + name?: str + env?: [{str:}] + +# Comment Two +schema AppConfiguration: + appName: str + image: str + overQuota: bool = False + resource: {str:} + mainContainer?: Main + labels: {str:} + +# Comment Three +appConfiguration = AppConfiguration { + # Comment Four + appName: "kusion" + # Comment Five + image: "test-image:v1" + resource: { + cpu: "4" + disk: "50Gi" + memory: "12Gi" + } + labels: { + key1: { + key1: 12 + } + key2: {key2: 34} + } + # Comment Six + mainContainer: Main { + name: "kusion_override" + } + # Comment Seven + # Comment Eight + overQuota: True +} +# Comment Nine +# Deprecated +@Deprecated() +schema Foo: + mixin [ + # AMixin + AMixin, + # BMixin + BMixin + ] + # Comment for index signature + [k: str]: int + # Comment for `x` field + x: int + + check: + # x > 0 + x > 0 + # x < 0 + x < 0 + +# Comment One +config = { + # Comment Two + # Comment Three + key1 = "value1" + # Comment Four + key2 = "value2" + # Comment Five + key3 = "value3" + # Comment Six + "key4" = "value4" + # Comment Seven + key5.v = "value5" + # Comment Eight + **key6 + # Comment Nine + if True: + # Comment Ten + key7 = "value7" +} +# Comment One +data = [ + # Comment Two + # Comment Three + 1 + # Comment Four + if True: + # Comment Five + 2 + # Comment Six + # Comment Seven + *[3, 4] +] diff --git a/kclvm/tools/src/printer/test_data/empty.input b/kclvm/ast_pretty/src/test_data/empty.input similarity index 100% rename from kclvm/tools/src/printer/test_data/empty.input rename to kclvm/ast_pretty/src/test_data/empty.input diff --git a/kclvm/tools/src/printer/test_data/empty.output b/kclvm/ast_pretty/src/test_data/empty.output similarity index 100% rename from kclvm/tools/src/printer/test_data/empty.output rename to kclvm/ast_pretty/src/test_data/empty.output diff --git a/kclvm/ast_pretty/src/test_data/if_stmt.input b/kclvm/ast_pretty/src/test_data/if_stmt.input new file mode 100644 index 000000000..40aeb4d0a --- /dev/null +++ b/kclvm/ast_pretty/src/test_data/if_stmt.input @@ -0,0 +1,16 @@ +if True: + a = 1 +elif True: + b = 2 +else: + c = 3 + +if True: + if False: + d = 4 + elif True: + e = 5 + else: + f = 6 +else: + g = 7 diff --git a/kclvm/ast_pretty/src/test_data/if_stmt.output b/kclvm/ast_pretty/src/test_data/if_stmt.output new file mode 100644 index 000000000..8a20e1acd --- /dev/null +++ b/kclvm/ast_pretty/src/test_data/if_stmt.output @@ -0,0 +1,15 @@ +if True: + a = 1 +elif True: + b = 2 +else: + c = 3 +if True: + if False: + d = 4 + elif True: + e = 5 + else: + f = 6 +else: + g = 7 diff --git a/kclvm/ast_pretty/src/test_data/import.input b/kclvm/ast_pretty/src/test_data/import.input new file mode 100644 index 000000000..c25142c17 --- /dev/null +++ b/kclvm/ast_pretty/src/test_data/import.input @@ -0,0 +1,4 @@ +import path.to.pkg +import path.to.pkg as abs_pkg_alias +import .relative.path +import .relative.path as re_pkg_alias diff --git a/kclvm/ast_pretty/src/test_data/import.output b/kclvm/ast_pretty/src/test_data/import.output new file mode 100644 index 000000000..c25142c17 --- /dev/null +++ b/kclvm/ast_pretty/src/test_data/import.output @@ -0,0 +1,4 @@ +import path.to.pkg +import path.to.pkg as abs_pkg_alias +import .relative.path +import .relative.path as re_pkg_alias diff --git a/kclvm/tools/src/printer/test_data/index_sign.input b/kclvm/ast_pretty/src/test_data/index_sign.input similarity index 100% rename from kclvm/tools/src/printer/test_data/index_sign.input rename to kclvm/ast_pretty/src/test_data/index_sign.input diff --git a/kclvm/tools/src/printer/test_data/index_sign.output b/kclvm/ast_pretty/src/test_data/index_sign.output similarity index 100% rename from kclvm/tools/src/printer/test_data/index_sign.output rename to kclvm/ast_pretty/src/test_data/index_sign.output diff --git a/kclvm/tools/src/printer/test_data/joined_str.input b/kclvm/ast_pretty/src/test_data/joined_str.input similarity index 100% rename from kclvm/tools/src/printer/test_data/joined_str.input rename to kclvm/ast_pretty/src/test_data/joined_str.input diff --git a/kclvm/tools/src/printer/test_data/joined_str.output b/kclvm/ast_pretty/src/test_data/joined_str.output similarity index 100% rename from kclvm/tools/src/printer/test_data/joined_str.output rename to kclvm/ast_pretty/src/test_data/joined_str.output diff --git a/kclvm/ast_pretty/src/test_data/lambda.input b/kclvm/ast_pretty/src/test_data/lambda.input new file mode 100644 index 000000000..082f1f0f6 --- /dev/null +++ b/kclvm/ast_pretty/src/test_data/lambda.input @@ -0,0 +1,29 @@ +sumFunc1 = lambda x, y { + # Inline comments 1 + z = x + y + # Inline comments 2 + z + x +} +sumFunc2 = lambda x, y = 1 { + x + y + +} +sumFunc3 = lambda x = 1, y = 1 { + x + y + +} +sumFunc4 = lambda x: int = 1, y: int = 1 -> int { + x + y + +} +x0 = sumFunc1(1, 2) +x1 = sumFunc1(2, 3) +x2 = sumFunc1(3, 4) +x3 = sumFunc1(4, 5) + +x = lambda { + # Inline comments + 1 + +}() + diff --git a/kclvm/ast_pretty/src/test_data/lambda.output b/kclvm/ast_pretty/src/test_data/lambda.output new file mode 100644 index 000000000..543cb0b1f --- /dev/null +++ b/kclvm/ast_pretty/src/test_data/lambda.output @@ -0,0 +1,24 @@ +sumFunc1 = lambda x, y { + # Inline comments 1 + z = x + y + # Inline comments 2 + z + x +} +sumFunc2 = lambda x, y = 1 { + x + y +} +sumFunc3 = lambda x = 1, y = 1 { + x + y +} +sumFunc4 = lambda x: int = 1, y: int = 1 -> int { + x + y +} +x0 = sumFunc1(1, 2) +x1 = sumFunc1(2, 3) +x2 = sumFunc1(3, 4) +x3 = sumFunc1(4, 5) + +x = lambda { + # Inline comments + 1 +}() diff --git a/kclvm/ast_pretty/src/test_data/orelse.input b/kclvm/ast_pretty/src/test_data/orelse.input new file mode 100644 index 000000000..613d7ec74 --- /dev/null +++ b/kclvm/ast_pretty/src/test_data/orelse.input @@ -0,0 +1,31 @@ +if True: + a = 1 +else: + if True: + b = 2 + + if True: + c = 3 + +d = [ + if True: + 1 + else: + if True: + 2 + + if True: + 3 + +] +e = { + if True: + a = 1 + else: + if True: + b = 2 + + if True: + c = 3 + +} diff --git a/kclvm/ast_pretty/src/test_data/orelse.output b/kclvm/ast_pretty/src/test_data/orelse.output new file mode 100644 index 000000000..04de3aa85 --- /dev/null +++ b/kclvm/ast_pretty/src/test_data/orelse.output @@ -0,0 +1,27 @@ +if True: + a = 1 +else: + if True: + b = 2 + + if True: + c = 3 + +d = [ + if True: + 1 + else: + if True: + 2 + if True: + 3 +] +e = { + if True: + a = 1 + else: + if True: + b = 2 + if True: + c = 3 +} diff --git a/kclvm/tools/src/printer/test_data/quant.input b/kclvm/ast_pretty/src/test_data/quant.input similarity index 100% rename from kclvm/tools/src/printer/test_data/quant.input rename to kclvm/ast_pretty/src/test_data/quant.input diff --git a/test/test_units/test_kclvm/test_tools/test_printer/test_data/quant.output b/kclvm/ast_pretty/src/test_data/quant.output similarity index 100% rename from test/test_units/test_kclvm/test_tools/test_printer/test_data/quant.output rename to kclvm/ast_pretty/src/test_data/quant.output diff --git a/kclvm/tools/src/printer/test_data/rule.input b/kclvm/ast_pretty/src/test_data/rule.input similarity index 100% rename from kclvm/tools/src/printer/test_data/rule.input rename to kclvm/ast_pretty/src/test_data/rule.input diff --git a/kclvm/ast_pretty/src/test_data/rule.output b/kclvm/ast_pretty/src/test_data/rule.output new file mode 100644 index 000000000..0eacfb0da --- /dev/null +++ b/kclvm/ast_pretty/src/test_data/rule.output @@ -0,0 +1,17 @@ +age = 1 + +protocol MainProtocol: + """Protocol doc""" + var: int + +mixin MainMixin for MainProtocol: + var: int + +@deprecated() +rule Base: + """Rule doc""" + age > 0 + age < 10 +rule Main[var](Base) for MainProtocol: + var +Main(1) diff --git a/kclvm/ast_pretty/src/test_data/str.input b/kclvm/ast_pretty/src/test_data/str.input new file mode 100644 index 000000000..f9f69d934 --- /dev/null +++ b/kclvm/ast_pretty/src/test_data/str.input @@ -0,0 +1,8 @@ +a = "1" +b = "${a}" +c = """1""" +d = """${c}""" +e = '1' +f = '${a}' +g = '''1''' +h = '''${c}''' diff --git a/kclvm/ast_pretty/src/test_data/str.output b/kclvm/ast_pretty/src/test_data/str.output new file mode 100644 index 000000000..f9f69d934 --- /dev/null +++ b/kclvm/ast_pretty/src/test_data/str.output @@ -0,0 +1,8 @@ +a = "1" +b = "${a}" +c = """1""" +d = """${c}""" +e = '1' +f = '${a}' +g = '''1''' +h = '''${c}''' diff --git a/kclvm/tools/src/printer/test_data/type_alias.input b/kclvm/ast_pretty/src/test_data/type_alias.input similarity index 100% rename from kclvm/tools/src/printer/test_data/type_alias.input rename to kclvm/ast_pretty/src/test_data/type_alias.input diff --git a/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/type_alias.k b/kclvm/ast_pretty/src/test_data/type_alias.output similarity index 100% rename from test/test_units/test_kclvm/test_compiler/test_eval/eval_data/type_alias.k rename to kclvm/ast_pretty/src/test_data/type_alias.output diff --git a/kclvm/ast_pretty/src/test_data/unary.input b/kclvm/ast_pretty/src/test_data/unary.input new file mode 100644 index 000000000..613bcab7c --- /dev/null +++ b/kclvm/ast_pretty/src/test_data/unary.input @@ -0,0 +1,6 @@ +a = + 1 +b = - 1 +c = ~ 1 +d = not True +e = + 1 + + 1 +f = + 1 - - 1 diff --git a/kclvm/ast_pretty/src/test_data/unary.output b/kclvm/ast_pretty/src/test_data/unary.output new file mode 100644 index 000000000..552bdc5d0 --- /dev/null +++ b/kclvm/ast_pretty/src/test_data/unary.output @@ -0,0 +1,6 @@ +a = +1 +b = -1 +c = ~1 +d = not True +e = +1 + +1 +f = +1 - -1 diff --git a/kclvm/tools/src/printer/test_data/unification.input b/kclvm/ast_pretty/src/test_data/unification.input similarity index 100% rename from kclvm/tools/src/printer/test_data/unification.input rename to kclvm/ast_pretty/src/test_data/unification.input diff --git a/test/test_units/test_kclvm/test_tools/test_printer/test_data/unification.output b/kclvm/ast_pretty/src/test_data/unification.output similarity index 100% rename from test/test_units/test_kclvm/test_tools/test_printer/test_data/unification.output rename to kclvm/ast_pretty/src/test_data/unification.output diff --git a/kclvm/ast_pretty/src/tests.rs b/kclvm/ast_pretty/src/tests.rs new file mode 100644 index 000000000..5ef2f2494 --- /dev/null +++ b/kclvm/ast_pretty/src/tests.rs @@ -0,0 +1,65 @@ +use std::path::{Path, PathBuf}; + +use super::print_ast_module; +use kclvm_parser::parse_file_force_errors; +use pretty_assertions::assert_eq; + +const FILE_INPUT_SUFFIX: &str = ".input"; +const FILE_OUTPUT_SUFFIX: &str = ".output"; +const TEST_CASES: &[&str] = &[ + "arguments", + "empty", + "if_stmt", + "import", + "unary", + "codelayout", + "collection_if", + "comment", + "index_sign", + "joined_str", + "lambda", + "orelse", + "quant", + "rule", + "str", + "type_alias", + "unification", +]; + +fn read_data(data_name: &str) -> (String, String) { + let mut filename = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + filename.push( + Path::new("src") + .join("test_data") + .join(format!("{}{}", data_name, FILE_INPUT_SUFFIX)) + .display() + .to_string(), + ); + + let module = parse_file_force_errors(filename.to_str().unwrap(), None); + + let mut filename_expect = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + filename_expect.push( + Path::new("src") + .join("test_data") + .join(format!("{}{}", data_name, FILE_OUTPUT_SUFFIX)) + .display() + .to_string(), + ); + ( + print_ast_module(&module.unwrap()), + std::fs::read_to_string(filename_expect.to_str().unwrap()).unwrap(), + ) +} + +#[test] +fn test_ast_printer() { + for case in TEST_CASES { + let (data_input, data_output) = read_data(case); + + #[cfg(target_os = "windows")] + let data_output = data_output.replace("\r\n", "\n"); + + assert_eq!(data_input, data_output, "Test failed on {}", case); + } +} diff --git a/kclvm/cmd/Cargo.toml b/kclvm/cmd/Cargo.toml new file mode 100644 index 000000000..5aa586ae3 --- /dev/null +++ b/kclvm/cmd/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "kclvm-cmd" +version = "0.11.0" +edition = "2021" + +[dependencies] +anyhow = "1.0" +clap = "4.3.0" +compiler_base_session = "0.1.3" + +kclvm-api = {path = "../api"} +kclvm-parser = {path = "../parser"} +kclvm-runner = {path = "../runner"} +kclvm-config = {path = "../config"} +kclvm-driver = {path = "../driver"} +kclvm-runtime = {path = "../runtime"} +kclvm-tools = {path = "../tools"} +kclvm-error = {path = "../error"} +kclvm-version = {path = "../version"} diff --git a/kclvm/cmd/src/lib.rs b/kclvm/cmd/src/lib.rs new file mode 100644 index 000000000..e85ade250 --- /dev/null +++ b/kclvm/cmd/src/lib.rs @@ -0,0 +1,64 @@ +//! The `kclvm` command-line interface. + +#[macro_use] +extern crate clap; + +pub mod run; +pub mod settings; +pub(crate) mod util; + +#[cfg(test)] +mod tests; + +use clap::{ArgAction, Command}; + +use std::io; + +use anyhow::Result; +use run::run_command; + +/// Run the KCL main command. +pub fn main(args: &[&str]) -> Result<()> { + let matches = app().arg_required_else_help(true).get_matches_from(args); + // Sub commands + match matches.subcommand() { + Some(("run", sub_matches)) => run_command(sub_matches, &mut io::stdout()), + Some(("version", _)) => { + println!("{}", kclvm_version::get_version_info()); + Ok(()) + } + #[cfg(not(target_arch = "wasm32"))] + Some(("server", _)) => kclvm_api::service::jsonrpc::start_stdio_server(), + _ => Ok(()), + } +} + +/// Get the CLI application including a run command and +/// a gPRC server command to interacting with external systems. +pub fn app() -> Command { + Command::new("kclvm_cli") + .version(kclvm_version::VERSION) + .about("KCL main CLI.") + .subcommand( + Command::new("run") + .about("run") + .arg(arg!([input] ... "Specify the input files to run").num_args(0..)) + .arg(arg!(output: -o --output "Specify the YAML output file path")) + .arg(arg!(setting: -Y --setting ... "Specify the input setting file").num_args(1..)) + .arg(arg!(verbose: -v --verbose "Print test information verbosely").action(ArgAction::Count)) + .arg(arg!(disable_none: -n --disable_none "Disable dumping None values")) + .arg(arg!(strict_range_check: -r --strict_range_check "Do perform strict numeric range checks")) + .arg(arg!(debug: -d --debug "Run in debug mode (for developers only)")) + .arg(arg!(sort_keys: -k --sort_keys "Sort result keys")) + .arg(arg!(show_hidden: -H --show_hidden "Display hidden attributes")) + .arg(arg!(fast_eval: -K --fast_eval "Use the fast evaluation mode")) + .arg(arg!(arguments: -D --argument ... "Specify the top-level argument").num_args(1..)) + .arg(arg!(path_selector: -S --path_selector ... "Specify the path selector").num_args(1..)) + .arg(arg!(overrides: -O --overrides ... "Specify the configuration override path and value").num_args(1..)) + .arg(arg!(target: --target "Specify the target type")) + .arg(arg!(recursive: -R --recursive "Compile the files directory recursively")) + .arg(arg!(package_map: -E --external ... "Mapping of package name and path where the package is located").num_args(1..)), + ) + .subcommand(Command::new("server").about("Start a rpc server for APIs")) + .subcommand(Command::new("version").about("Show the KCL version")) +} diff --git a/kclvm/cmd/src/run.rs b/kclvm/cmd/src/run.rs new file mode 100644 index 000000000..9ab1fd469 --- /dev/null +++ b/kclvm/cmd/src/run.rs @@ -0,0 +1,48 @@ +use anyhow::Result; +use clap::ArgMatches; +use kclvm_error::StringError; +use kclvm_parser::ParseSession; +use kclvm_runner::exec_program; +use std::io::Write; +use std::sync::Arc; + +use crate::settings::must_build_settings; + +/// Run the KCL run command. +pub fn run_command(matches: &ArgMatches, writer: &mut W) -> Result<()> { + // Config settings building + let settings = must_build_settings(matches); + let output = settings.output(); + let sess = Arc::new(ParseSession::default()); + match exec_program(sess.clone(), &settings.try_into()?) { + Ok(result) => { + // Output log message + if !result.log_message.is_empty() { + write!(writer, "{}", result.log_message)?; + } + // Output execute error message + if !result.err_message.is_empty() { + if !sess.0.diag_handler.has_errors()? { + sess.0.add_err(StringError(result.err_message))?; + } + sess.0.emit_stashed_diagnostics_and_abort()?; + } + if !result.yaml_result.is_empty() { + match output { + Some(o) => std::fs::write(o, result.yaml_result)?, + // [`println!`] is not a good way to output content to stdout, + // using [`writeln`] can be better to redirect the output. + None => writeln!(writer, "{}", result.yaml_result)?, + } + } + } + // Other error message + Err(msg) => { + if !sess.0.diag_handler.has_errors()? { + sess.0.add_err(StringError(msg.to_string()))?; + } + sess.0.emit_stashed_diagnostics_and_abort()?; + } + } + Ok(()) +} diff --git a/kclvm/cmd/src/settings.rs b/kclvm/cmd/src/settings.rs new file mode 100644 index 000000000..cbdd6aa73 --- /dev/null +++ b/kclvm/cmd/src/settings.rs @@ -0,0 +1,73 @@ +use crate::util::*; +use anyhow::Result; +use clap::ArgMatches; +use kclvm_config::settings::{build_settings_pathbuf, Config, SettingsFile, SettingsPathBuf}; +use kclvm_driver::arguments::parse_key_value_pair; +use kclvm_error::Handler; +use kclvm_runtime::PanicInfo; + +/// Build settings from arg matches. +pub(crate) fn must_build_settings(matches: &ArgMatches) -> SettingsPathBuf { + match build_settings(matches) { + Ok(settings) => settings, + Err(err) => { + // New an error handler. + let mut handler = Handler::default(); + handler + .add_panic_info(&PanicInfo { + message: err.to_string(), + ..Default::default() + }) + .abort_if_any_errors(); + SettingsPathBuf::default() + } + } +} + +/// Build settings from arg matches. +pub(crate) fn build_settings(matches: &ArgMatches) -> Result { + let files: Vec<&str> = match matches.get_many::("input") { + Some(files) => files.into_iter().map(|f| f.as_str()).collect::>(), + None => vec![], + }; + + let setting_files = matches + .get_many::("setting") + .map(|files| files.into_iter().map(|f| f.as_str()).collect::>()); + + let arguments = strings_from_matches(matches, "arguments"); + + let package_maps = hashmaps_from_matches(matches, "package_map").transpose()?; + + build_settings_pathbuf( + files.as_slice(), + setting_files, + Some(SettingsFile { + kcl_cli_configs: Some(Config { + output: matches.get_one::("output").map(|v| v.to_string()), + overrides: strings_from_matches(matches, "overrides"), + path_selector: strings_from_matches(matches, "path_selector"), + strict_range_check: bool_from_matches(matches, "strict_range_check"), + disable_none: bool_from_matches(matches, "disable_none"), + verbose: u32_from_matches(matches, "verbose"), + debug: bool_from_matches(matches, "debug"), + sort_keys: bool_from_matches(matches, "sort_keys"), + show_hidden: bool_from_matches(matches, "show_hidden"), + fast_eval: bool_from_matches(matches, "fast_eval"), + package_maps, + ..Default::default() + }), + kcl_options: if arguments.is_some() { + let mut key_value_pairs = vec![]; + if let Some(arguments) = arguments { + for arg in arguments { + key_value_pairs.push(parse_key_value_pair(&arg)?); + } + } + Some(key_value_pairs) + } else { + None + }, + }), + ) +} diff --git a/kclvm/cmd/src/test_data/cache/main/kcl.mod b/kclvm/cmd/src/test_data/cache/main/kcl.mod new file mode 100644 index 000000000..c4bd68a7d --- /dev/null +++ b/kclvm/cmd/src/test_data/cache/main/kcl.mod @@ -0,0 +1,6 @@ +[package] +name = "main" +edition = "0.0.1" +version = "0.0.1" + +[dependencies] \ No newline at end of file diff --git a/kclvm/cmd/src/test_data/cache/main/main.k b/kclvm/cmd/src/test_data/cache/main/main.k new file mode 100644 index 000000000..472cc7fcd --- /dev/null +++ b/kclvm/cmd/src/test_data/cache/main/main.k @@ -0,0 +1,5 @@ +import kcl1 +The_first_kcl_program = kcl1.kcl1 +kcl1_schema = kcl1.Kcl1 { + name = "kcl1", +} \ No newline at end of file diff --git a/kclvm/cmd/src/test_data/cache/main/main.k.v1 b/kclvm/cmd/src/test_data/cache/main/main.k.v1 new file mode 100644 index 000000000..88b7e5193 --- /dev/null +++ b/kclvm/cmd/src/test_data/cache/main/main.k.v1 @@ -0,0 +1,2 @@ +import kcl1 +The_first_kcl_program = kcl1.kcl1 diff --git a/kclvm/cmd/src/test_data/cache/main/main.k.v2 b/kclvm/cmd/src/test_data/cache/main/main.k.v2 new file mode 100644 index 000000000..472cc7fcd --- /dev/null +++ b/kclvm/cmd/src/test_data/cache/main/main.k.v2 @@ -0,0 +1,5 @@ +import kcl1 +The_first_kcl_program = kcl1.kcl1 +kcl1_schema = kcl1.Kcl1 { + name = "kcl1", +} \ No newline at end of file diff --git a/kclvm/cmd/src/test_data/cache/v1/kcl1/kcl.mod b/kclvm/cmd/src/test_data/cache/v1/kcl1/kcl.mod new file mode 100644 index 000000000..3d22b7485 --- /dev/null +++ b/kclvm/cmd/src/test_data/cache/v1/kcl1/kcl.mod @@ -0,0 +1,6 @@ +[package] +name = "kcl1" +edition = "0.0.1" +version = "0.0.1" + +[dependencies] \ No newline at end of file diff --git a/kclvm/cmd/src/test_data/cache/v1/kcl1/main.k b/kclvm/cmd/src/test_data/cache/v1/kcl1/main.k new file mode 100644 index 000000000..3263156e9 --- /dev/null +++ b/kclvm/cmd/src/test_data/cache/v1/kcl1/main.k @@ -0,0 +1 @@ +kcl1 = 1 \ No newline at end of file diff --git a/kclvm/cmd/src/test_data/cache/v2/kcl1/kcl.mod b/kclvm/cmd/src/test_data/cache/v2/kcl1/kcl.mod new file mode 100644 index 000000000..3d22b7485 --- /dev/null +++ b/kclvm/cmd/src/test_data/cache/v2/kcl1/kcl.mod @@ -0,0 +1,6 @@ +[package] +name = "kcl1" +edition = "0.0.1" +version = "0.0.1" + +[dependencies] \ No newline at end of file diff --git a/kclvm/cmd/src/test_data/cache/v2/kcl1/main.k b/kclvm/cmd/src/test_data/cache/v2/kcl1/main.k new file mode 100644 index 000000000..17b2b021c --- /dev/null +++ b/kclvm/cmd/src/test_data/cache/v2/kcl1/main.k @@ -0,0 +1,4 @@ +schema Kcl1: + name: str + +kcl1 = 1 \ No newline at end of file diff --git a/kclvm/cmd/src/test_data/cache_test/kcl.mod b/kclvm/cmd/src/test_data/cache_test/kcl.mod new file mode 100644 index 000000000..45eec5c29 --- /dev/null +++ b/kclvm/cmd/src/test_data/cache_test/kcl.mod @@ -0,0 +1,7 @@ +[package] +name = "cache_test" +edition = "0.0.1" +version = "0.0.1" + +[dependencies] +helloworld = "0.1.0" diff --git a/kclvm/cmd/src/test_data/cache_test/main.k b/kclvm/cmd/src/test_data/cache_test/main.k new file mode 100644 index 000000000..7d2efc690 --- /dev/null +++ b/kclvm/cmd/src/test_data/cache_test/main.k @@ -0,0 +1,3 @@ +import helloworld as hw + +a = hw.The_first_kcl_program \ No newline at end of file diff --git a/kclvm/cmd/src/test_data/cases/import_1/main.k b/kclvm/cmd/src/test_data/cases/import_1/main.k new file mode 100644 index 000000000..2cb81c7e7 --- /dev/null +++ b/kclvm/cmd/src/test_data/cases/import_1/main.k @@ -0,0 +1,15 @@ +import kcl4 +import kcl4.container + + +main = container.Main { + name = "sss" +} + +appConfiguration1 = kcl4.Server { + mainContainer = main +} + +aa = typeof(main, full_name=True) +cc = typeof(appConfiguration1.mainContainer, full_name=True) + diff --git a/kclvm/cmd/src/test_data/cases/import_1/stdout b/kclvm/cmd/src/test_data/cases/import_1/stdout new file mode 100644 index 000000000..161322060 --- /dev/null +++ b/kclvm/cmd/src/test_data/cases/import_1/stdout @@ -0,0 +1,7 @@ +main: + name: sss +appConfiguration1: + mainContainer: + name: sss +aa: kcl4.container.Main +cc: kcl4.container.Main diff --git a/kclvm/cmd/src/test_data/cases/import_konfig_1/main.k b/kclvm/cmd/src/test_data/cases/import_konfig_1/main.k new file mode 100644 index 000000000..16cc52969 --- /dev/null +++ b/kclvm/cmd/src/test_data/cases/import_konfig_1/main.k @@ -0,0 +1,15 @@ +import konfig.base.pkg.kusion_models.kube.frontend +import konfig.base.pkg.kusion_models.kube.frontend.container + +## aa2-vendor/konfig/base/pkg/kusion_models/kube/frontend + +main = container.Main { + name = "sss" +} +aa = typeof(main, full_name=True) +cc = typeof(frontend.Server { + image = "nginx" + mainContainer = { + name = "nginx" + } +}.mainContainer, full_name=True) diff --git a/kclvm/cmd/src/test_data/cases/import_konfig_1/stdout b/kclvm/cmd/src/test_data/cases/import_konfig_1/stdout new file mode 100644 index 000000000..0a0f03274 --- /dev/null +++ b/kclvm/cmd/src/test_data/cases/import_konfig_1/stdout @@ -0,0 +1,5 @@ +main: + name: sss + useBuiltInEnv: false +aa: konfig.base.pkg.kusion_models.kube.frontend.container.Main +cc: konfig.base.pkg.kusion_models.kube.frontend.container.Main diff --git a/kclvm/cmd/src/test_data/cases/vendor/kcl4/container/kcl4.k b/kclvm/cmd/src/test_data/cases/vendor/kcl4/container/kcl4.k new file mode 100644 index 000000000..cf891d22b --- /dev/null +++ b/kclvm/cmd/src/test_data/cases/vendor/kcl4/container/kcl4.k @@ -0,0 +1,2 @@ +schema Main: + name: str diff --git a/kclvm/cmd/src/test_data/cases/vendor/kcl4/kcl.mod b/kclvm/cmd/src/test_data/cases/vendor/kcl4/kcl.mod new file mode 100644 index 000000000..52280a04b --- /dev/null +++ b/kclvm/cmd/src/test_data/cases/vendor/kcl4/kcl.mod @@ -0,0 +1,6 @@ +[package] +name = "kcl4" +edition = "0.0.1" +version = "0.0.1" + +[dependencies] \ No newline at end of file diff --git a/kclvm/cmd/src/test_data/cases/vendor/kcl4/kcl4.k b/kclvm/cmd/src/test_data/cases/vendor/kcl4/kcl4.k new file mode 100644 index 000000000..8233169b1 --- /dev/null +++ b/kclvm/cmd/src/test_data/cases/vendor/kcl4/kcl4.k @@ -0,0 +1,4 @@ +import container + +schema Server: + mainContainer: container.Main diff --git a/kclvm/cmd/src/test_data/failed/keyword_argument_error.k b/kclvm/cmd/src/test_data/failed/keyword_argument_error.k new file mode 100644 index 000000000..e034af544 --- /dev/null +++ b/kclvm/cmd/src/test_data/failed/keyword_argument_error.k @@ -0,0 +1 @@ +a = "{ID}".format(2) # keyword argument not found -> keyword argument 'ID' not found \ No newline at end of file diff --git a/kclvm/cmd/src/test_data/fmt/test.k b/kclvm/cmd/src/test_data/fmt/test.k new file mode 100644 index 000000000..b6febb947 --- /dev/null +++ b/kclvm/cmd/src/test_data/fmt/test.k @@ -0,0 +1,10 @@ +name = "kcl" +age = 1 +schema Person: + name: str = "kcl" + age: int = 1 + +x0 = Person {} + +x1 = Person {age = 101} + diff --git a/kclvm/cmd/src/test_data/fuzz_match/main.k b/kclvm/cmd/src/test_data/fuzz_match/main.k new file mode 100644 index 000000000..1a5682818 --- /dev/null +++ b/kclvm/cmd/src/test_data/fuzz_match/main.k @@ -0,0 +1,6 @@ +schema Person: + aa?: int + aaa?: int + +p = Person {} +a = p.a # Error, attribute 'a' not found in `Person`, did you mean `aa`? \ No newline at end of file diff --git a/kclvm/cmd/src/test_data/fuzz_match/main_unmatched.k b/kclvm/cmd/src/test_data/fuzz_match/main_unmatched.k new file mode 100644 index 000000000..f802a7d70 --- /dev/null +++ b/kclvm/cmd/src/test_data/fuzz_match/main_unmatched.k @@ -0,0 +1,6 @@ +schema Person: + en?: int + sd?: int + +p = Person {} +a = p.a # Error, attribute 'a' not found in `Person` \ No newline at end of file diff --git a/kclvm/cmd/src/test_data/instances/test_inst_1/expected b/kclvm/cmd/src/test_data/instances/test_inst_1/expected new file mode 100644 index 000000000..068711d7a --- /dev/null +++ b/kclvm/cmd/src/test_data/instances/test_inst_1/expected @@ -0,0 +1,4 @@ +a: + id: 1 +k1_inst: +- id: 1 diff --git a/kclvm/cmd/src/test_data/instances/test_inst_1/kcl.mod b/kclvm/cmd/src/test_data/instances/test_inst_1/kcl.mod new file mode 100644 index 000000000..ab572545d --- /dev/null +++ b/kclvm/cmd/src/test_data/instances/test_inst_1/kcl.mod @@ -0,0 +1,5 @@ +[package] +name = "kcl1" +edition = "0.0.1" +version = "0.0.1" + diff --git a/kclvm/cmd/src/test_data/instances/test_inst_1/kcl.yaml b/kclvm/cmd/src/test_data/instances/test_inst_1/kcl.yaml new file mode 100644 index 000000000..77eae8d83 --- /dev/null +++ b/kclvm/cmd/src/test_data/instances/test_inst_1/kcl.yaml @@ -0,0 +1,4 @@ +kcl_cli_configs: + file: + - ./main.k + - ./main1.k \ No newline at end of file diff --git a/kclvm/cmd/src/test_data/instances/test_inst_1/main.k b/kclvm/cmd/src/test_data/instances/test_inst_1/main.k new file mode 100644 index 000000000..5fb051abc --- /dev/null +++ b/kclvm/cmd/src/test_data/instances/test_inst_1/main.k @@ -0,0 +1,3 @@ +a = K1 { + id: 1 +} \ No newline at end of file diff --git a/kclvm/cmd/src/test_data/instances/test_inst_1/main1.k b/kclvm/cmd/src/test_data/instances/test_inst_1/main1.k new file mode 100644 index 000000000..ee0e11d82 --- /dev/null +++ b/kclvm/cmd/src/test_data/instances/test_inst_1/main1.k @@ -0,0 +1,5 @@ +schema K1: + id: int + +k1_inst = K1.instances() + \ No newline at end of file diff --git a/kclvm/cmd/src/test_data/instances/test_inst_10/expected b/kclvm/cmd/src/test_data/instances/test_inst_10/expected new file mode 100644 index 000000000..2e394772b --- /dev/null +++ b/kclvm/cmd/src/test_data/instances/test_inst_10/expected @@ -0,0 +1,3 @@ +a: + id: 102 +inst102: [] diff --git a/kclvm/cmd/src/test_data/instances/test_inst_10/kcl.yaml b/kclvm/cmd/src/test_data/instances/test_inst_10/kcl.yaml new file mode 100644 index 000000000..0dfc987fd --- /dev/null +++ b/kclvm/cmd/src/test_data/instances/test_inst_10/kcl.yaml @@ -0,0 +1,7 @@ +kcl_cli_configs: + file: + - ./test_inst_101/main.k + - ${test_inst_102:KCL_MOD}/main.k + package_maps: + test_inst_102: ./src/test_data/instances/test_inst_10/test_inst_102 + diff --git a/kclvm/cmd/src/test_data/instances/test_inst_10/test_inst_101/kcl.mod b/kclvm/cmd/src/test_data/instances/test_inst_10/test_inst_101/kcl.mod new file mode 100644 index 000000000..3040fb9e1 --- /dev/null +++ b/kclvm/cmd/src/test_data/instances/test_inst_10/test_inst_101/kcl.mod @@ -0,0 +1,5 @@ +[package] +name = "test_inst_101" +edition = "0.0.1" +version = "0.0.1" + diff --git a/kclvm/cmd/src/test_data/instances/test_inst_10/test_inst_101/main.k b/kclvm/cmd/src/test_data/instances/test_inst_10/test_inst_101/main.k new file mode 100644 index 000000000..12d2fe392 --- /dev/null +++ b/kclvm/cmd/src/test_data/instances/test_inst_10/test_inst_101/main.k @@ -0,0 +1,5 @@ +import test_inst_102 as k102 + +a = k102.K102 { + id: 102 +} \ No newline at end of file diff --git a/kclvm/cmd/src/test_data/instances/test_inst_10/test_inst_102/kcl.mod b/kclvm/cmd/src/test_data/instances/test_inst_10/test_inst_102/kcl.mod new file mode 100644 index 000000000..341192b5c --- /dev/null +++ b/kclvm/cmd/src/test_data/instances/test_inst_10/test_inst_102/kcl.mod @@ -0,0 +1,5 @@ +[package] +name = "test_inst_102" +edition = "0.0.1" +version = "0.0.1" + diff --git a/kclvm/cmd/src/test_data/instances/test_inst_10/test_inst_102/main.k b/kclvm/cmd/src/test_data/instances/test_inst_10/test_inst_102/main.k new file mode 100644 index 000000000..27b218bce --- /dev/null +++ b/kclvm/cmd/src/test_data/instances/test_inst_10/test_inst_102/main.k @@ -0,0 +1,4 @@ +schema K102: + id: int + +inst102 = K102.instances() \ No newline at end of file diff --git a/kclvm/cmd/src/test_data/instances/test_inst_11/kcl.mod b/kclvm/cmd/src/test_data/instances/test_inst_11/kcl.mod new file mode 100644 index 000000000..a626cfb0f --- /dev/null +++ b/kclvm/cmd/src/test_data/instances/test_inst_11/kcl.mod @@ -0,0 +1,5 @@ +[package] +name = "test_inst_11" +edition = "0.0.1" +version = "0.0.1" + diff --git a/kclvm/cmd/src/test_data/instances/test_inst_11/model/main.k b/kclvm/cmd/src/test_data/instances/test_inst_11/model/main.k new file mode 100644 index 000000000..b43778076 --- /dev/null +++ b/kclvm/cmd/src/test_data/instances/test_inst_11/model/main.k @@ -0,0 +1,3 @@ +schema K11: + msg: str + \ No newline at end of file diff --git a/kclvm/cmd/src/test_data/instances/test_inst_11/sub/main.k b/kclvm/cmd/src/test_data/instances/test_inst_11/sub/main.k new file mode 100644 index 000000000..2804a67a1 --- /dev/null +++ b/kclvm/cmd/src/test_data/instances/test_inst_11/sub/main.k @@ -0,0 +1,5 @@ +import model as subm + +k11_inst: subm.K11 { + msg: "k11_in_sub" +} \ No newline at end of file diff --git a/kclvm/cmd/src/test_data/instances/test_inst_11/test_inst_111/expected b/kclvm/cmd/src/test_data/instances/test_inst_11/test_inst_111/expected new file mode 100644 index 000000000..3ad7b524b --- /dev/null +++ b/kclvm/cmd/src/test_data/instances/test_inst_11/test_inst_111/expected @@ -0,0 +1,2 @@ +k11_inst: + msg: k11_in_main diff --git a/kclvm/cmd/src/test_data/instances/test_inst_11/test_inst_111/kcl.mod b/kclvm/cmd/src/test_data/instances/test_inst_11/test_inst_111/kcl.mod new file mode 100644 index 000000000..5c0234dc8 --- /dev/null +++ b/kclvm/cmd/src/test_data/instances/test_inst_11/test_inst_111/kcl.mod @@ -0,0 +1,5 @@ +[package] +name = "test_inst_111" +edition = "0.0.1" +version = "0.0.1" + diff --git a/kclvm/cmd/src/test_data/instances/test_inst_11/test_inst_111/kcl.yaml b/kclvm/cmd/src/test_data/instances/test_inst_11/test_inst_111/kcl.yaml new file mode 100644 index 000000000..553e82d00 --- /dev/null +++ b/kclvm/cmd/src/test_data/instances/test_inst_11/test_inst_111/kcl.yaml @@ -0,0 +1,6 @@ +kcl_cli_configs: + file: + - ../sub/main.k + - ./main.k + package_maps: + test_inst_11: ./src/test_data/instances/test_inst_11 diff --git a/kclvm/cmd/src/test_data/instances/test_inst_11/test_inst_111/main.k b/kclvm/cmd/src/test_data/instances/test_inst_11/test_inst_111/main.k new file mode 100644 index 000000000..c6985755e --- /dev/null +++ b/kclvm/cmd/src/test_data/instances/test_inst_11/test_inst_111/main.k @@ -0,0 +1,5 @@ +import test_inst_11.model as m + +k11_inst: m.K11 { + msg= "k11_in_main" +} \ No newline at end of file diff --git a/kclvm/cmd/src/test_data/instances/test_inst_2/expected b/kclvm/cmd/src/test_data/instances/test_inst_2/expected new file mode 100644 index 000000000..96310e046 --- /dev/null +++ b/kclvm/cmd/src/test_data/instances/test_inst_2/expected @@ -0,0 +1,4 @@ +a: + id: 2 +k2_inst: +- id: 2 diff --git a/kclvm/cmd/src/test_data/instances/test_inst_2/kcl.mod b/kclvm/cmd/src/test_data/instances/test_inst_2/kcl.mod new file mode 100644 index 000000000..5fb058acd --- /dev/null +++ b/kclvm/cmd/src/test_data/instances/test_inst_2/kcl.mod @@ -0,0 +1,5 @@ +[package] +name = "kcl2" +edition = "0.0.1" +version = "0.0.1" + diff --git a/kclvm/cmd/src/test_data/instances/test_inst_2/kcl.yaml b/kclvm/cmd/src/test_data/instances/test_inst_2/kcl.yaml new file mode 100644 index 000000000..9dcc889ec --- /dev/null +++ b/kclvm/cmd/src/test_data/instances/test_inst_2/kcl.yaml @@ -0,0 +1,4 @@ +kcl_cli_configs: + file: + - ./main.k + - ./sub/main.k \ No newline at end of file diff --git a/kclvm/cmd/src/test_data/instances/test_inst_2/main.k b/kclvm/cmd/src/test_data/instances/test_inst_2/main.k new file mode 100644 index 000000000..2a75ebbf4 --- /dev/null +++ b/kclvm/cmd/src/test_data/instances/test_inst_2/main.k @@ -0,0 +1,3 @@ +a = K2 { + id: 2 +} \ No newline at end of file diff --git a/kclvm/cmd/src/test_data/instances/test_inst_2/sub/main.k b/kclvm/cmd/src/test_data/instances/test_inst_2/sub/main.k new file mode 100644 index 000000000..8e53dab35 --- /dev/null +++ b/kclvm/cmd/src/test_data/instances/test_inst_2/sub/main.k @@ -0,0 +1,5 @@ +schema K2: + id: int + +k2_inst = K2.instances() + \ No newline at end of file diff --git a/kclvm/cmd/src/test_data/instances/test_inst_3/expected b/kclvm/cmd/src/test_data/instances/test_inst_3/expected new file mode 100644 index 000000000..d22191949 --- /dev/null +++ b/kclvm/cmd/src/test_data/instances/test_inst_3/expected @@ -0,0 +1,4 @@ +a: + id: 3 +k3_inst: +- id: 3 diff --git a/kclvm/cmd/src/test_data/instances/test_inst_3/kcl.mod b/kclvm/cmd/src/test_data/instances/test_inst_3/kcl.mod new file mode 100644 index 000000000..b99124970 --- /dev/null +++ b/kclvm/cmd/src/test_data/instances/test_inst_3/kcl.mod @@ -0,0 +1,5 @@ +[package] +name = "kcl3" +edition = "0.0.1" +version = "0.0.1" + diff --git a/kclvm/cmd/src/test_data/instances/test_inst_3/kcl.yaml b/kclvm/cmd/src/test_data/instances/test_inst_3/kcl.yaml new file mode 100644 index 000000000..2d7b7fdcd --- /dev/null +++ b/kclvm/cmd/src/test_data/instances/test_inst_3/kcl.yaml @@ -0,0 +1,5 @@ +kcl_cli_configs: + file: + - ./main.k + - ./sub/main.k + - ./main1.k \ No newline at end of file diff --git a/kclvm/cmd/src/test_data/instances/test_inst_3/main.k b/kclvm/cmd/src/test_data/instances/test_inst_3/main.k new file mode 100644 index 000000000..60db6eef8 --- /dev/null +++ b/kclvm/cmd/src/test_data/instances/test_inst_3/main.k @@ -0,0 +1,3 @@ +a = K3 { + id: 3 +} \ No newline at end of file diff --git a/kclvm/cmd/src/test_data/instances/test_inst_3/main1.k b/kclvm/cmd/src/test_data/instances/test_inst_3/main1.k new file mode 100644 index 000000000..d312a229e --- /dev/null +++ b/kclvm/cmd/src/test_data/instances/test_inst_3/main1.k @@ -0,0 +1 @@ +k3_inst = K3.instances() \ No newline at end of file diff --git a/kclvm/cmd/src/test_data/instances/test_inst_3/sub/main.k b/kclvm/cmd/src/test_data/instances/test_inst_3/sub/main.k new file mode 100644 index 000000000..cdcb7ca7e --- /dev/null +++ b/kclvm/cmd/src/test_data/instances/test_inst_3/sub/main.k @@ -0,0 +1,2 @@ +schema K3: + id: int diff --git a/kclvm/cmd/src/test_data/instances/test_inst_4/expected b/kclvm/cmd/src/test_data/instances/test_inst_4/expected new file mode 100644 index 000000000..f01127b25 --- /dev/null +++ b/kclvm/cmd/src/test_data/instances/test_inst_4/expected @@ -0,0 +1,4 @@ +a: + id: 4 +k4_inst: +- id: 4 diff --git a/kclvm/cmd/src/test_data/instances/test_inst_4/kcl.yaml b/kclvm/cmd/src/test_data/instances/test_inst_4/kcl.yaml new file mode 100644 index 000000000..e5d69adb0 --- /dev/null +++ b/kclvm/cmd/src/test_data/instances/test_inst_4/kcl.yaml @@ -0,0 +1,6 @@ +kcl_cli_configs: + file: + - ./test_inst_41/main.k + - ${test_inst_42:KCL_MOD}/main.k + package_maps: + test_inst_42: ./src/test_data/instances/test_inst_4/test_inst_42 \ No newline at end of file diff --git a/kclvm/cmd/src/test_data/instances/test_inst_4/test_inst_41/kcl.mod b/kclvm/cmd/src/test_data/instances/test_inst_4/test_inst_41/kcl.mod new file mode 100644 index 000000000..d091b26c8 --- /dev/null +++ b/kclvm/cmd/src/test_data/instances/test_inst_4/test_inst_41/kcl.mod @@ -0,0 +1,5 @@ +[package] +name = "test_inst_41" +edition = "0.0.1" +version = "0.0.1" + diff --git a/kclvm/cmd/src/test_data/instances/test_inst_4/test_inst_41/main.k b/kclvm/cmd/src/test_data/instances/test_inst_4/test_inst_41/main.k new file mode 100644 index 000000000..369306369 --- /dev/null +++ b/kclvm/cmd/src/test_data/instances/test_inst_4/test_inst_41/main.k @@ -0,0 +1,3 @@ +a = K4 { + id: 4 +} \ No newline at end of file diff --git a/kclvm/cmd/src/test_data/instances/test_inst_4/test_inst_42/kcl.mod b/kclvm/cmd/src/test_data/instances/test_inst_4/test_inst_42/kcl.mod new file mode 100644 index 000000000..48145caaa --- /dev/null +++ b/kclvm/cmd/src/test_data/instances/test_inst_4/test_inst_42/kcl.mod @@ -0,0 +1,5 @@ +[package] +name = "test_inst_42" +edition = "0.0.1" +version = "0.0.1" + diff --git a/kclvm/cmd/src/test_data/instances/test_inst_4/test_inst_42/main.k b/kclvm/cmd/src/test_data/instances/test_inst_4/test_inst_42/main.k new file mode 100644 index 000000000..4ea096248 --- /dev/null +++ b/kclvm/cmd/src/test_data/instances/test_inst_4/test_inst_42/main.k @@ -0,0 +1,5 @@ +schema K4: + id: int + +k4_inst = K4.instances() + \ No newline at end of file diff --git a/kclvm/cmd/src/test_data/instances/test_inst_5/expected b/kclvm/cmd/src/test_data/instances/test_inst_5/expected new file mode 100644 index 000000000..41fa02201 --- /dev/null +++ b/kclvm/cmd/src/test_data/instances/test_inst_5/expected @@ -0,0 +1,5 @@ +a: + id: 5 +b: 5 +k5_inst: +- id: 5 diff --git a/kclvm/cmd/src/test_data/instances/test_inst_5/kcl.yaml b/kclvm/cmd/src/test_data/instances/test_inst_5/kcl.yaml new file mode 100644 index 000000000..e28df2d75 --- /dev/null +++ b/kclvm/cmd/src/test_data/instances/test_inst_5/kcl.yaml @@ -0,0 +1,8 @@ +kcl_cli_configs: + file: + - ./test_inst_51/ + - ${test_inst_52:KCL_MOD}/main.k + - ${test_inst_53:KCL_MOD}/main.k + package_maps: + test_inst_52: ./src/test_data/instances/test_inst_5/test_inst_52 + test_inst_53: ./src/test_data/instances/test_inst_5/test_inst_53 \ No newline at end of file diff --git a/kclvm/cmd/src/test_data/instances/test_inst_5/test_inst_51/kcl.mod b/kclvm/cmd/src/test_data/instances/test_inst_5/test_inst_51/kcl.mod new file mode 100644 index 000000000..dfbf2645d --- /dev/null +++ b/kclvm/cmd/src/test_data/instances/test_inst_5/test_inst_51/kcl.mod @@ -0,0 +1,5 @@ +[package] +name = "test_inst_51" +edition = "0.0.1" +version = "0.0.1" + diff --git a/kclvm/cmd/src/test_data/instances/test_inst_5/test_inst_51/main.k b/kclvm/cmd/src/test_data/instances/test_inst_5/test_inst_51/main.k new file mode 100644 index 000000000..18fa27a97 --- /dev/null +++ b/kclvm/cmd/src/test_data/instances/test_inst_5/test_inst_51/main.k @@ -0,0 +1,3 @@ +a = K5 { + id: 5 +} diff --git a/kclvm/cmd/src/test_data/instances/test_inst_5/test_inst_51/main1.k b/kclvm/cmd/src/test_data/instances/test_inst_5/test_inst_51/main1.k new file mode 100644 index 000000000..b3c0d6826 --- /dev/null +++ b/kclvm/cmd/src/test_data/instances/test_inst_5/test_inst_51/main1.k @@ -0,0 +1 @@ +b = 5 \ No newline at end of file diff --git a/kclvm/cmd/src/test_data/instances/test_inst_5/test_inst_52/kcl.mod b/kclvm/cmd/src/test_data/instances/test_inst_5/test_inst_52/kcl.mod new file mode 100644 index 000000000..275d64c97 --- /dev/null +++ b/kclvm/cmd/src/test_data/instances/test_inst_5/test_inst_52/kcl.mod @@ -0,0 +1,5 @@ +[package] +name = "test_inst_52" +edition = "0.0.1" +version = "0.0.1" + diff --git a/kclvm/cmd/src/test_data/instances/test_inst_5/test_inst_52/main.k b/kclvm/cmd/src/test_data/instances/test_inst_5/test_inst_52/main.k new file mode 100644 index 000000000..d61010865 --- /dev/null +++ b/kclvm/cmd/src/test_data/instances/test_inst_5/test_inst_52/main.k @@ -0,0 +1,2 @@ +schema K5: + id: int diff --git a/kclvm/cmd/src/test_data/instances/test_inst_5/test_inst_53/kcl.mod b/kclvm/cmd/src/test_data/instances/test_inst_5/test_inst_53/kcl.mod new file mode 100644 index 000000000..02ba5f429 --- /dev/null +++ b/kclvm/cmd/src/test_data/instances/test_inst_5/test_inst_53/kcl.mod @@ -0,0 +1,5 @@ +[package] +name = "test_inst_53" +edition = "0.0.1" +version = "0.0.1" + diff --git a/kclvm/cmd/src/test_data/instances/test_inst_5/test_inst_53/main.k b/kclvm/cmd/src/test_data/instances/test_inst_5/test_inst_53/main.k new file mode 100644 index 000000000..696729ce2 --- /dev/null +++ b/kclvm/cmd/src/test_data/instances/test_inst_5/test_inst_53/main.k @@ -0,0 +1 @@ +k5_inst = K5.instances() \ No newline at end of file diff --git a/kclvm/cmd/src/test_data/instances/test_inst_6/expected b/kclvm/cmd/src/test_data/instances/test_inst_6/expected new file mode 100644 index 000000000..af351576e --- /dev/null +++ b/kclvm/cmd/src/test_data/instances/test_inst_6/expected @@ -0,0 +1,4 @@ +a: + id: 6 +k6_inst: +- id: 6 diff --git a/kclvm/cmd/src/test_data/instances/test_inst_6/kcl.yaml b/kclvm/cmd/src/test_data/instances/test_inst_6/kcl.yaml new file mode 100644 index 000000000..8770ea1e8 --- /dev/null +++ b/kclvm/cmd/src/test_data/instances/test_inst_6/kcl.yaml @@ -0,0 +1,8 @@ +kcl_cli_configs: + file: + - ${test_inst_61:KCL_MOD}/main.k + - ./test_inst_62/ + - ${test_inst_63:KCL_MOD}/main.k + package_maps: + test_inst_61: ./src/test_data/instances/test_inst_6/test_inst_61 + test_inst_63: ./src/test_data/instances/test_inst_6/test_inst_63 \ No newline at end of file diff --git a/kclvm/cmd/src/test_data/instances/test_inst_6/test_inst_61/kcl.mod b/kclvm/cmd/src/test_data/instances/test_inst_6/test_inst_61/kcl.mod new file mode 100644 index 000000000..dfbf2645d --- /dev/null +++ b/kclvm/cmd/src/test_data/instances/test_inst_6/test_inst_61/kcl.mod @@ -0,0 +1,5 @@ +[package] +name = "test_inst_51" +edition = "0.0.1" +version = "0.0.1" + diff --git a/kclvm/cmd/src/test_data/instances/test_inst_6/test_inst_61/main.k b/kclvm/cmd/src/test_data/instances/test_inst_6/test_inst_61/main.k new file mode 100644 index 000000000..355fc8f4d --- /dev/null +++ b/kclvm/cmd/src/test_data/instances/test_inst_6/test_inst_61/main.k @@ -0,0 +1,3 @@ +a = K6 { + id: 6 +} diff --git a/kclvm/cmd/src/test_data/instances/test_inst_6/test_inst_62/kcl.mod b/kclvm/cmd/src/test_data/instances/test_inst_6/test_inst_62/kcl.mod new file mode 100644 index 000000000..275d64c97 --- /dev/null +++ b/kclvm/cmd/src/test_data/instances/test_inst_6/test_inst_62/kcl.mod @@ -0,0 +1,5 @@ +[package] +name = "test_inst_52" +edition = "0.0.1" +version = "0.0.1" + diff --git a/kclvm/cmd/src/test_data/instances/test_inst_6/test_inst_62/main.k b/kclvm/cmd/src/test_data/instances/test_inst_6/test_inst_62/main.k new file mode 100644 index 000000000..2d4badc7e --- /dev/null +++ b/kclvm/cmd/src/test_data/instances/test_inst_6/test_inst_62/main.k @@ -0,0 +1,2 @@ +schema K6: + id: int diff --git a/kclvm/cmd/src/test_data/instances/test_inst_6/test_inst_63/kcl.mod b/kclvm/cmd/src/test_data/instances/test_inst_6/test_inst_63/kcl.mod new file mode 100644 index 000000000..02ba5f429 --- /dev/null +++ b/kclvm/cmd/src/test_data/instances/test_inst_6/test_inst_63/kcl.mod @@ -0,0 +1,5 @@ +[package] +name = "test_inst_53" +edition = "0.0.1" +version = "0.0.1" + diff --git a/kclvm/cmd/src/test_data/instances/test_inst_6/test_inst_63/main.k b/kclvm/cmd/src/test_data/instances/test_inst_6/test_inst_63/main.k new file mode 100644 index 000000000..7eb738e2c --- /dev/null +++ b/kclvm/cmd/src/test_data/instances/test_inst_6/test_inst_63/main.k @@ -0,0 +1 @@ +k6_inst = K6.instances() \ No newline at end of file diff --git a/kclvm/cmd/src/test_data/instances/test_inst_7/expected b/kclvm/cmd/src/test_data/instances/test_inst_7/expected new file mode 100644 index 000000000..27cd4a719 --- /dev/null +++ b/kclvm/cmd/src/test_data/instances/test_inst_7/expected @@ -0,0 +1,4 @@ +a: + id: 7 +k7_inst: +- id: 7 diff --git a/kclvm/cmd/src/test_data/instances/test_inst_7/kcl.yaml b/kclvm/cmd/src/test_data/instances/test_inst_7/kcl.yaml new file mode 100644 index 000000000..13ba11147 --- /dev/null +++ b/kclvm/cmd/src/test_data/instances/test_inst_7/kcl.yaml @@ -0,0 +1,8 @@ +kcl_cli_configs: + file: + - ${test_inst_71:KCL_MOD}/main.k + - ${test_inst_72:KCL_MOD}/main.k + - ./test_inst_73/ + package_maps: + test_inst_71: ./src/test_data/instances/test_inst_7/test_inst_71 + test_inst_72: ./src/test_data/instances/test_inst_7/test_inst_72 \ No newline at end of file diff --git a/kclvm/cmd/src/test_data/instances/test_inst_7/test_inst_71/kcl.mod b/kclvm/cmd/src/test_data/instances/test_inst_7/test_inst_71/kcl.mod new file mode 100644 index 000000000..dfbf2645d --- /dev/null +++ b/kclvm/cmd/src/test_data/instances/test_inst_7/test_inst_71/kcl.mod @@ -0,0 +1,5 @@ +[package] +name = "test_inst_51" +edition = "0.0.1" +version = "0.0.1" + diff --git a/kclvm/cmd/src/test_data/instances/test_inst_7/test_inst_71/main.k b/kclvm/cmd/src/test_data/instances/test_inst_7/test_inst_71/main.k new file mode 100644 index 000000000..4093b9ac7 --- /dev/null +++ b/kclvm/cmd/src/test_data/instances/test_inst_7/test_inst_71/main.k @@ -0,0 +1,3 @@ +a = K7 { + id: 7 +} diff --git a/kclvm/cmd/src/test_data/instances/test_inst_7/test_inst_72/kcl.mod b/kclvm/cmd/src/test_data/instances/test_inst_7/test_inst_72/kcl.mod new file mode 100644 index 000000000..275d64c97 --- /dev/null +++ b/kclvm/cmd/src/test_data/instances/test_inst_7/test_inst_72/kcl.mod @@ -0,0 +1,5 @@ +[package] +name = "test_inst_52" +edition = "0.0.1" +version = "0.0.1" + diff --git a/kclvm/cmd/src/test_data/instances/test_inst_7/test_inst_72/main.k b/kclvm/cmd/src/test_data/instances/test_inst_7/test_inst_72/main.k new file mode 100644 index 000000000..44c5fd90a --- /dev/null +++ b/kclvm/cmd/src/test_data/instances/test_inst_7/test_inst_72/main.k @@ -0,0 +1,2 @@ +schema K7: + id: int diff --git a/kclvm/cmd/src/test_data/instances/test_inst_7/test_inst_73/kcl.mod b/kclvm/cmd/src/test_data/instances/test_inst_7/test_inst_73/kcl.mod new file mode 100644 index 000000000..02ba5f429 --- /dev/null +++ b/kclvm/cmd/src/test_data/instances/test_inst_7/test_inst_73/kcl.mod @@ -0,0 +1,5 @@ +[package] +name = "test_inst_53" +edition = "0.0.1" +version = "0.0.1" + diff --git a/kclvm/cmd/src/test_data/instances/test_inst_7/test_inst_73/main.k b/kclvm/cmd/src/test_data/instances/test_inst_7/test_inst_73/main.k new file mode 100644 index 000000000..d13a3dec5 --- /dev/null +++ b/kclvm/cmd/src/test_data/instances/test_inst_7/test_inst_73/main.k @@ -0,0 +1 @@ +k7_inst = K7.instances() \ No newline at end of file diff --git a/kclvm/cmd/src/test_data/instances/test_inst_8/expected b/kclvm/cmd/src/test_data/instances/test_inst_8/expected new file mode 100644 index 000000000..f4401ec70 --- /dev/null +++ b/kclvm/cmd/src/test_data/instances/test_inst_8/expected @@ -0,0 +1,17 @@ +a: + id: 8 +b: + id: 81 +c: + id: 82 +k8_inst_1: +- id: 8 +- id: 81 +- id: 82 +d: + id: 83 +k8_inst_2: +- id: 8 +- id: 81 +- id: 82 +- id: 83 diff --git a/kclvm/cmd/src/test_data/instances/test_inst_8/kcl.mod b/kclvm/cmd/src/test_data/instances/test_inst_8/kcl.mod new file mode 100644 index 000000000..f94033c0d --- /dev/null +++ b/kclvm/cmd/src/test_data/instances/test_inst_8/kcl.mod @@ -0,0 +1,5 @@ +[package] +name = "test_inst_8" +edition = "0.0.1" +version = "0.0.1" + diff --git a/kclvm/cmd/src/test_data/instances/test_inst_8/kcl.yaml b/kclvm/cmd/src/test_data/instances/test_inst_8/kcl.yaml new file mode 100644 index 000000000..f72877684 --- /dev/null +++ b/kclvm/cmd/src/test_data/instances/test_inst_8/kcl.yaml @@ -0,0 +1,14 @@ +kcl_cli_configs: + file: + - ${test_inst_81:KCL_MOD}/main.k + - ./main.k + - ${test_inst_82:KCL_MOD}/main.k + - ./main1.k + - ${test_inst_83:KCL_MOD}/main.k + - ./main2.k + - ${test_inst_84:KCL_MOD}/main.k + package_maps: + test_inst_81: ./src/test_data/instances/test_inst_8/test_inst_81 + test_inst_82: ./src/test_data/instances/test_inst_8/test_inst_82 + test_inst_83: ./src/test_data/instances/test_inst_8/test_inst_83 + test_inst_84: ./src/test_data/instances/test_inst_8/test_inst_84 diff --git a/kclvm/cmd/src/test_data/instances/test_inst_8/main.k b/kclvm/cmd/src/test_data/instances/test_inst_8/main.k new file mode 100644 index 000000000..c62b3d2f3 --- /dev/null +++ b/kclvm/cmd/src/test_data/instances/test_inst_8/main.k @@ -0,0 +1,3 @@ +b = K8 { + id: 81 +} \ No newline at end of file diff --git a/kclvm/cmd/src/test_data/instances/test_inst_8/main1.k b/kclvm/cmd/src/test_data/instances/test_inst_8/main1.k new file mode 100644 index 000000000..17acf70a6 --- /dev/null +++ b/kclvm/cmd/src/test_data/instances/test_inst_8/main1.k @@ -0,0 +1,3 @@ +c = K8 { + id: 82 +} \ No newline at end of file diff --git a/kclvm/cmd/src/test_data/instances/test_inst_8/main2.k b/kclvm/cmd/src/test_data/instances/test_inst_8/main2.k new file mode 100644 index 000000000..c99980af3 --- /dev/null +++ b/kclvm/cmd/src/test_data/instances/test_inst_8/main2.k @@ -0,0 +1,3 @@ +d = K8 { + id: 83 +} \ No newline at end of file diff --git a/kclvm/cmd/src/test_data/instances/test_inst_8/test_inst_81/kcl.mod b/kclvm/cmd/src/test_data/instances/test_inst_8/test_inst_81/kcl.mod new file mode 100644 index 000000000..dfbf2645d --- /dev/null +++ b/kclvm/cmd/src/test_data/instances/test_inst_8/test_inst_81/kcl.mod @@ -0,0 +1,5 @@ +[package] +name = "test_inst_51" +edition = "0.0.1" +version = "0.0.1" + diff --git a/kclvm/cmd/src/test_data/instances/test_inst_8/test_inst_81/main.k b/kclvm/cmd/src/test_data/instances/test_inst_8/test_inst_81/main.k new file mode 100644 index 000000000..cb29f08b7 --- /dev/null +++ b/kclvm/cmd/src/test_data/instances/test_inst_8/test_inst_81/main.k @@ -0,0 +1,3 @@ +a = K8 { + id: 8 +} diff --git a/kclvm/cmd/src/test_data/instances/test_inst_8/test_inst_82/kcl.mod b/kclvm/cmd/src/test_data/instances/test_inst_8/test_inst_82/kcl.mod new file mode 100644 index 000000000..275d64c97 --- /dev/null +++ b/kclvm/cmd/src/test_data/instances/test_inst_8/test_inst_82/kcl.mod @@ -0,0 +1,5 @@ +[package] +name = "test_inst_52" +edition = "0.0.1" +version = "0.0.1" + diff --git a/kclvm/cmd/src/test_data/instances/test_inst_8/test_inst_82/main.k b/kclvm/cmd/src/test_data/instances/test_inst_8/test_inst_82/main.k new file mode 100644 index 000000000..706da08e9 --- /dev/null +++ b/kclvm/cmd/src/test_data/instances/test_inst_8/test_inst_82/main.k @@ -0,0 +1,2 @@ +schema K8: + id: int diff --git a/kclvm/cmd/src/test_data/instances/test_inst_8/test_inst_83/kcl.mod b/kclvm/cmd/src/test_data/instances/test_inst_8/test_inst_83/kcl.mod new file mode 100644 index 000000000..02ba5f429 --- /dev/null +++ b/kclvm/cmd/src/test_data/instances/test_inst_8/test_inst_83/kcl.mod @@ -0,0 +1,5 @@ +[package] +name = "test_inst_53" +edition = "0.0.1" +version = "0.0.1" + diff --git a/kclvm/cmd/src/test_data/instances/test_inst_8/test_inst_83/main.k b/kclvm/cmd/src/test_data/instances/test_inst_8/test_inst_83/main.k new file mode 100644 index 000000000..71513c9f9 --- /dev/null +++ b/kclvm/cmd/src/test_data/instances/test_inst_8/test_inst_83/main.k @@ -0,0 +1 @@ +k8_inst_1 = K8.instances() \ No newline at end of file diff --git a/kclvm/cmd/src/test_data/instances/test_inst_8/test_inst_84/kcl.mod b/kclvm/cmd/src/test_data/instances/test_inst_8/test_inst_84/kcl.mod new file mode 100644 index 000000000..02ba5f429 --- /dev/null +++ b/kclvm/cmd/src/test_data/instances/test_inst_8/test_inst_84/kcl.mod @@ -0,0 +1,5 @@ +[package] +name = "test_inst_53" +edition = "0.0.1" +version = "0.0.1" + diff --git a/kclvm/cmd/src/test_data/instances/test_inst_8/test_inst_84/main.k b/kclvm/cmd/src/test_data/instances/test_inst_8/test_inst_84/main.k new file mode 100644 index 000000000..e257da19c --- /dev/null +++ b/kclvm/cmd/src/test_data/instances/test_inst_8/test_inst_84/main.k @@ -0,0 +1 @@ +k8_inst_2 = K8.instances() \ No newline at end of file diff --git a/kclvm/cmd/src/test_data/instances/test_inst_9/expected b/kclvm/cmd/src/test_data/instances/test_inst_9/expected new file mode 100644 index 000000000..f27fc6f83 --- /dev/null +++ b/kclvm/cmd/src/test_data/instances/test_inst_9/expected @@ -0,0 +1,4 @@ +a: + id: 92 +inst92: +- id: 92 diff --git a/kclvm/cmd/src/test_data/instances/test_inst_9/kcl.yaml b/kclvm/cmd/src/test_data/instances/test_inst_9/kcl.yaml new file mode 100644 index 000000000..506e7a6d6 --- /dev/null +++ b/kclvm/cmd/src/test_data/instances/test_inst_9/kcl.yaml @@ -0,0 +1,7 @@ +kcl_cli_configs: + file: + - ./test_inst_91/main.k + - ${test_inst_92:KCL_MOD}/main.k + package_maps: + test_inst_92: ./src/test_data/instances/test_inst_9/test_inst_92 + diff --git a/kclvm/cmd/src/test_data/instances/test_inst_9/test_inst_91/kcl.mod b/kclvm/cmd/src/test_data/instances/test_inst_9/test_inst_91/kcl.mod new file mode 100644 index 000000000..3040fb9e1 --- /dev/null +++ b/kclvm/cmd/src/test_data/instances/test_inst_9/test_inst_91/kcl.mod @@ -0,0 +1,5 @@ +[package] +name = "test_inst_101" +edition = "0.0.1" +version = "0.0.1" + diff --git a/kclvm/cmd/src/test_data/instances/test_inst_9/test_inst_91/main.k b/kclvm/cmd/src/test_data/instances/test_inst_9/test_inst_91/main.k new file mode 100644 index 000000000..990f4bb24 --- /dev/null +++ b/kclvm/cmd/src/test_data/instances/test_inst_9/test_inst_91/main.k @@ -0,0 +1,5 @@ +import test_inst_92.sub as k92 + +a = k92.K92 { + id: 92 +} \ No newline at end of file diff --git a/kclvm/cmd/src/test_data/instances/test_inst_9/test_inst_92/kcl.mod b/kclvm/cmd/src/test_data/instances/test_inst_9/test_inst_92/kcl.mod new file mode 100644 index 000000000..341192b5c --- /dev/null +++ b/kclvm/cmd/src/test_data/instances/test_inst_9/test_inst_92/kcl.mod @@ -0,0 +1,5 @@ +[package] +name = "test_inst_102" +edition = "0.0.1" +version = "0.0.1" + diff --git a/kclvm/cmd/src/test_data/instances/test_inst_9/test_inst_92/main.k b/kclvm/cmd/src/test_data/instances/test_inst_9/test_inst_92/main.k new file mode 100644 index 000000000..1d27555ca --- /dev/null +++ b/kclvm/cmd/src/test_data/instances/test_inst_9/test_inst_92/main.k @@ -0,0 +1,3 @@ +import sub as s + +inst92 = s.K92.instances() \ No newline at end of file diff --git a/kclvm/cmd/src/test_data/instances/test_inst_9/test_inst_92/sub/main.k b/kclvm/cmd/src/test_data/instances/test_inst_9/test_inst_92/sub/main.k new file mode 100644 index 000000000..73354a6ef --- /dev/null +++ b/kclvm/cmd/src/test_data/instances/test_inst_9/test_inst_92/sub/main.k @@ -0,0 +1,2 @@ +schema K92: + id: int \ No newline at end of file diff --git a/kclvm/cmd/src/test_data/lint/test.k b/kclvm/cmd/src/test_data/lint/test.k new file mode 100644 index 000000000..7a72a2df5 --- /dev/null +++ b/kclvm/cmd/src/test_data/lint/test.k @@ -0,0 +1,9 @@ +name = "kcl" +age = 1 +schema Person: + name: str = "kcl" + age: int = 1 + +x0 = Person {} + +x1 = Person {age = 101} diff --git a/kclvm/cmd/src/test_data/multimod/kcl1/kcl.mod b/kclvm/cmd/src/test_data/multimod/kcl1/kcl.mod new file mode 100644 index 000000000..ab572545d --- /dev/null +++ b/kclvm/cmd/src/test_data/multimod/kcl1/kcl.mod @@ -0,0 +1,5 @@ +[package] +name = "kcl1" +edition = "0.0.1" +version = "0.0.1" + diff --git a/kclvm/cmd/src/test_data/multimod/kcl1/main.k b/kclvm/cmd/src/test_data/multimod/kcl1/main.k new file mode 100644 index 000000000..45ada83b6 --- /dev/null +++ b/kclvm/cmd/src/test_data/multimod/kcl1/main.k @@ -0,0 +1 @@ +kcl1 = 'hello 1' \ No newline at end of file diff --git a/kclvm/cmd/src/test_data/multimod/kcl2/kcl.mod b/kclvm/cmd/src/test_data/multimod/kcl2/kcl.mod new file mode 100644 index 000000000..5fb058acd --- /dev/null +++ b/kclvm/cmd/src/test_data/multimod/kcl2/kcl.mod @@ -0,0 +1,5 @@ +[package] +name = "kcl2" +edition = "0.0.1" +version = "0.0.1" + diff --git a/kclvm/cmd/src/test_data/multimod/kcl2/main.k b/kclvm/cmd/src/test_data/multimod/kcl2/main.k new file mode 100644 index 000000000..9c30e151e --- /dev/null +++ b/kclvm/cmd/src/test_data/multimod/kcl2/main.k @@ -0,0 +1 @@ +kcl2 = "hello 2" \ No newline at end of file diff --git a/kclvm/cmd/src/test_data/multimod/kcl3/kcl.mod b/kclvm/cmd/src/test_data/multimod/kcl3/kcl.mod new file mode 100644 index 000000000..b99124970 --- /dev/null +++ b/kclvm/cmd/src/test_data/multimod/kcl3/kcl.mod @@ -0,0 +1,5 @@ +[package] +name = "kcl3" +edition = "0.0.1" +version = "0.0.1" + diff --git a/kclvm/cmd/src/test_data/multimod/kcl3/kcl4/kcl.mod b/kclvm/cmd/src/test_data/multimod/kcl3/kcl4/kcl.mod new file mode 100644 index 000000000..98f429002 --- /dev/null +++ b/kclvm/cmd/src/test_data/multimod/kcl3/kcl4/kcl.mod @@ -0,0 +1,5 @@ +[package] +name = "kcl4" +edition = "0.0.1" +version = "0.0.1" + diff --git a/kclvm/cmd/src/test_data/multimod/kcl3/kcl4/main.k b/kclvm/cmd/src/test_data/multimod/kcl3/kcl4/main.k new file mode 100644 index 000000000..f91707fe6 --- /dev/null +++ b/kclvm/cmd/src/test_data/multimod/kcl3/kcl4/main.k @@ -0,0 +1 @@ +k4 = 'Hello World 4' \ No newline at end of file diff --git a/kclvm/cmd/src/test_data/multimod/kcl3/main.k b/kclvm/cmd/src/test_data/multimod/kcl3/main.k new file mode 100644 index 000000000..3b9852426 --- /dev/null +++ b/kclvm/cmd/src/test_data/multimod/kcl3/main.k @@ -0,0 +1 @@ +k3 = 'Hello World 3' \ No newline at end of file diff --git a/kclvm/cmd/src/test_data/plugin/plugin_not_found/kcl.mod b/kclvm/cmd/src/test_data/plugin/plugin_not_found/kcl.mod new file mode 100644 index 000000000..4054bce69 --- /dev/null +++ b/kclvm/cmd/src/test_data/plugin/plugin_not_found/kcl.mod @@ -0,0 +1,5 @@ +[package] +name = "plugin_not_found" +edition = "0.0.1" +version = "0.0.1" + diff --git a/kclvm/cmd/src/test_data/plugin/plugin_not_found/main.k b/kclvm/cmd/src/test_data/plugin/plugin_not_found/main.k new file mode 100644 index 000000000..a227182df --- /dev/null +++ b/kclvm/cmd/src/test_data/plugin/plugin_not_found/main.k @@ -0,0 +1,3 @@ +import kcl_plugin.not_exist + +The_first_kcl_program = 'Hello World!' \ No newline at end of file diff --git a/kclvm/cmd/src/test_data/settings/kcl.yaml b/kclvm/cmd/src/test_data/settings/kcl.yaml new file mode 100644 index 000000000..64d12f2f0 --- /dev/null +++ b/kclvm/cmd/src/test_data/settings/kcl.yaml @@ -0,0 +1,4 @@ +kcl_cli_configs: + files: + - hello.k + disable_none: true diff --git a/kclvm/cmd/src/test_data/sym_link/origin/a.k b/kclvm/cmd/src/test_data/sym_link/origin/a.k new file mode 100644 index 000000000..7813c6f92 --- /dev/null +++ b/kclvm/cmd/src/test_data/sym_link/origin/a.k @@ -0,0 +1,3 @@ +import .sub + +a = sub.a \ No newline at end of file diff --git a/kclvm/cmd/src/test_data/sym_link/origin/sub/a.k b/kclvm/cmd/src/test_data/sym_link/origin/sub/a.k new file mode 100644 index 000000000..1c377f29b --- /dev/null +++ b/kclvm/cmd/src/test_data/sym_link/origin/sub/a.k @@ -0,0 +1 @@ +a=1 \ No newline at end of file diff --git a/test/test_units/test_kclvm/test_tools/test_validation/json_test_data/schema_with_check.k.json b/kclvm/cmd/src/test_data/vet/data.json similarity index 100% rename from test/test_units/test_kclvm/test_tools/test_validation/json_test_data/schema_with_check.k.json rename to kclvm/cmd/src/test_data/vet/data.json diff --git a/kclvm/cmd/src/test_data/vet/test.k b/kclvm/cmd/src/test_data/vet/test.k new file mode 100644 index 000000000..c45670065 --- /dev/null +++ b/kclvm/cmd/src/test_data/vet/test.k @@ -0,0 +1,7 @@ +schema Person: + name: str + age: int + message: str + + check: + age > 0 diff --git a/kclvm/cmd/src/tests.rs b/kclvm/cmd/src/tests.rs new file mode 100644 index 000000000..016b04876 --- /dev/null +++ b/kclvm/cmd/src/tests.rs @@ -0,0 +1,589 @@ +use std::{ + env, + fs::{self, remove_file}, + path::{Path, PathBuf}, + sync::Arc, +}; + +use kclvm_config::modfile::KCL_PKG_PATH; +use kclvm_parser::ParseSession; +use kclvm_runner::{exec_program, MapErrorResult}; + +use crate::{ + app, + run::run_command, + settings::{build_settings, must_build_settings}, + util::hashmaps_from_matches, +}; + +#[cfg(unix)] +use std::os::unix::fs::symlink; +#[cfg(windows)] +use std::os::windows::fs::symlink_file as symlink; + +const ROOT_CMD: &str = "kclvm_cli"; + +#[test] +fn test_build_settings() { + let work_dir = work_dir(); + let matches = app().get_matches_from(settings_arguments(work_dir.join("kcl.yaml"))); + let matches = matches.subcommand_matches("run").unwrap(); + let s = build_settings(matches).unwrap(); + // Testing work directory + assert_eq!(s.path().as_ref().unwrap().to_str(), work_dir.to_str()); + // Testing CLI configs + assert_eq!( + s.settings().kcl_cli_configs.as_ref().unwrap().files, + Some(vec!["hello.k".to_string()]) + ); + assert_eq!( + s.settings().kcl_cli_configs.as_ref().unwrap().disable_none, + Some(true) + ); + assert_eq!( + s.settings() + .kcl_cli_configs + .as_ref() + .unwrap() + .strict_range_check, + Some(true) + ); + assert_eq!( + s.settings().kcl_cli_configs.as_ref().unwrap().overrides, + Some(vec!["c.a=1".to_string(), "c.b=1".to_string(),]) + ); + assert_eq!( + s.settings().kcl_cli_configs.as_ref().unwrap().path_selector, + Some(vec!["a.b.c".to_string()]) + ); + assert_eq!(s.settings().input(), vec!["hello.k".to_string()]); +} + +#[test] +fn test_build_settings_fail() { + let matches = app().get_matches_from(settings_arguments(work_dir().join("error_kcl.yaml"))); + let matches = matches.subcommand_matches("run").unwrap(); + assert!(build_settings(matches).is_err()); +} + +fn work_dir() -> std::path::PathBuf { + std::path::Path::new(".") + .join("src") + .join("test_data") + .join("settings") +} + +fn settings_arguments(path: std::path::PathBuf) -> Vec { + vec![ + ROOT_CMD.to_string(), + "run".to_string(), + "-Y".to_string(), + path.to_str().unwrap().to_string(), + "-r".to_string(), + "-O".to_string(), + "c.a=1".to_string(), + "-O".to_string(), + "c.b=1".to_string(), + "-S".to_string(), + "a.b.c".to_string(), + ] +} + +#[test] +fn test_external_cmd() { + let matches = app().get_matches_from(&[ROOT_CMD, "run", "-E", "test_name=test_path"]); + let matches = matches.subcommand_matches("run").unwrap(); + let pair = hashmaps_from_matches(matches, "package_map") + .unwrap() + .unwrap(); + assert_eq!(pair.len(), 1); + assert!(pair.contains_key("test_name")); + assert_eq!(pair.get("test_name").unwrap(), "test_path"); +} + +#[test] +fn test_version_cmd() { + let matches = app().get_matches_from(&[ROOT_CMD, "version"]); + assert!(matches.subcommand_matches("version").is_some()) +} + +#[test] +fn test_multi_external_cmd() { + let matches = app().get_matches_from(&[ + ROOT_CMD, + "run", + "-E", + "test_name=test_path", + "-E", + "test_name1=test_path1", + ]); + let matches = matches.subcommand_matches("run").unwrap(); + let pair = hashmaps_from_matches(matches, "package_map") + .unwrap() + .unwrap(); + + assert_eq!(pair.len(), 2); + assert!(pair.contains_key("test_name")); + assert!(pair.contains_key("test_name1")); + assert_eq!(pair.get("test_name").unwrap(), "test_path"); + assert_eq!(pair.get("test_name1").unwrap(), "test_path1"); +} + +#[test] +fn test_multi_external_with_same_key_cmd() { + let matches = app().get_matches_from(&[ + ROOT_CMD, + "run", + "-E", + "test_name=test_path", + "-E", + "test_name=test_path1", + ]); + let matches = matches.subcommand_matches("run").unwrap(); + let pair = hashmaps_from_matches(matches, "package_map") + .unwrap() + .unwrap(); + assert_eq!(pair.len(), 1); + assert!(pair.contains_key("test_name")); + assert_eq!(pair.get("test_name").unwrap(), "test_path1"); +} + +#[test] +fn test_external_cmd_invalid() { + let invalid_cases: [&str; 5] = [ + "test_nametest_path", + "test_name=test_path=test_suffix", + "=test_path", + "test_name=", + "=test_name=test_path=", + ]; + for case in invalid_cases { + let matches = app().get_matches_from(&[ROOT_CMD, "run", "-E", case]); + let matches = matches.subcommand_matches("run").unwrap(); + match hashmaps_from_matches(matches, "package_map").unwrap() { + Ok(_) => { + panic!("unreachable code.") + } + Err(err) => { + assert!(format!("{:?}", err).contains("Invalid value for top level arguments")); + } + }; + } +} + +#[test] +#[cfg(not(windows))] +// All the unit test cases in [`test_run_command`] can not be executed concurrently. +fn test_run_command() { + test_run_command_with_import(); + test_run_command_with_konfig(); + test_load_cache_with_different_pkg(); + test_kcl_path_is_sym_link(); + test_compile_two_kcl_mod(); + test_main_pkg_not_found(); + test_multi_mod_file(); + test_instances_with_yaml(); + test_plugin_not_found(); + test_error_message_fuzz_matched(); + test_error_message_fuzz_unmatched(); + test_keyword_argument_error_message(); +} + +fn test_run_command_with_import() { + let vendor_path = PathBuf::from("./src/test_data/cases/vendor"); + + let test_cases = vec!["import_1"]; + let test_case_root = PathBuf::from("./src/test_data/cases") + .canonicalize() + .unwrap(); + + for test_case in test_cases { + check_run_command_with_env( + test_case_root.join(test_case), + vendor_path.canonicalize().unwrap().display().to_string(), + ); + } +} + +fn test_run_command_with_konfig() { + let vendor_path = PathBuf::from("../../test/integration"); + + let test_cases = vec!["import_konfig_1"]; + let test_case_root = PathBuf::from("./src/test_data/cases") + .canonicalize() + .unwrap(); + + for test_case in test_cases { + check_run_command_with_env( + test_case_root.join(test_case), + vendor_path.canonicalize().unwrap().display().to_string(), + ); + } +} + +fn test_load_cache_with_different_pkg() { + let main_path = PathBuf::from("./src/test_data/cache/main/main.k"); + let main_v1_path = PathBuf::from("./src/test_data/cache/main/main.k.v1"); + let main_v2_path = PathBuf::from("./src/test_data/cache/main/main.k.v2"); + let kcl1_v1_path = PathBuf::from("./src/test_data/cache/v1/kcl1"); + let kcl1_v2_path = PathBuf::from("./src/test_data/cache/v2/kcl1"); + + // Copy the content from main.k.v1 to main.k + fs::copy(main_v1_path, &main_path).unwrap(); + let matches = app().get_matches_from(&[ + ROOT_CMD, + "run", + main_path.to_str().unwrap(), + "-E", + format!("kcl1={}", kcl1_v1_path.display()).as_str(), + ]); + + let matches = matches.subcommand_matches("run").unwrap(); + let mut buf = Vec::new(); + run_command(matches, &mut buf).unwrap(); + assert_eq!( + String::from_utf8(buf).unwrap(), + "The_first_kcl_program: 1\n" + ); + + // Copy the content from main.k.v2 to main.k + fs::copy(main_v2_path, &main_path).unwrap(); + let matches = app().get_matches_from(&[ + ROOT_CMD, + "run", + main_path.to_str().unwrap(), + "-E", + format!("kcl1={}", kcl1_v2_path.display()).as_str(), + ]); + + let matches = matches.subcommand_matches("run").unwrap(); + let mut buf = Vec::new(); + run_command(matches, &mut buf).unwrap(); + assert_eq!( + String::from_utf8(buf).unwrap(), + "The_first_kcl_program: 1\nkcl1_schema:\n name: kcl1\n" + ); +} + +/// rust crate [`gag`]: https://crates.io/crates/gag +/// allows redirecting stderr or stdout either to a file or to nothing, +/// but it only works on unix systems. +/// After [`gag`] can better support windows in the future, it may be considered to test the `println!`. +fn check_run_command_with_env(test_case_path: PathBuf, kcl_pkg_path_env: String) { + env::set_var(KCL_PKG_PATH, kcl_pkg_path_env); + + let test_case_expect_file = test_case_path.join("stdout").display().to_string(); + let expect = fs::read_to_string(test_case_expect_file).expect("Unable to read file"); + + let matches = app().arg_required_else_help(true).get_matches_from(&[ + ROOT_CMD, + "run", + &test_case_path.join("main.k").display().to_string(), + ]); + + let mut buf = Vec::new(); + run_command(matches.subcommand_matches("run").unwrap(), &mut buf).unwrap(); + + #[cfg(target_os = "windows")] + let expect = expect.replace("\r\n", "\n"); + assert_eq!(String::from_utf8(buf).unwrap(), expect); +} + +fn test_kcl_path_is_sym_link() { + let origin = "./src/test_data/sym_link/origin"; + let link = "./src/test_data/sym_link/sym_link"; + + let origin_k_file_path = PathBuf::from(origin).join("a.k"); + let origin_matches = app().arg_required_else_help(true).get_matches_from(&[ + ROOT_CMD, + "run", + origin_k_file_path.to_str().unwrap(), + ]); + + let mut origin_res = Vec::new(); + run_command( + origin_matches.subcommand_matches("run").unwrap(), + &mut origin_res, + ) + .unwrap(); + + // Create a symlink + symlink( + PathBuf::from(origin).canonicalize().unwrap(), + Path::new(link), + ) + .unwrap(); + + let sym_link_k_file_path = PathBuf::from(link).join("a.k"); + let mut sym_link_res = Vec::new(); + let sym_link_matches = app().arg_required_else_help(true).get_matches_from(&[ + ROOT_CMD, + "run", + sym_link_k_file_path.to_str().unwrap(), + ]); + run_command( + sym_link_matches.subcommand_matches("run").unwrap(), + &mut sym_link_res, + ) + .unwrap(); + + // compare the result from origin kcl path and symlink kcl path. + assert_eq!( + String::from_utf8(sym_link_res), + String::from_utf8(origin_res) + ); + + // clean up the symlink + remove_file(link).unwrap(); +} + +fn test_compile_two_kcl_mod() { + let test_case_path = PathBuf::from("./src/test_data/multimod"); + + let matches = app().arg_required_else_help(true).get_matches_from(&[ + ROOT_CMD, + "run", + &test_case_path.join("kcl1/main.k").display().to_string(), + "${kcl2:KCL_MOD}/main.k", + "-E", + &format!("kcl2={}", test_case_path.join("kcl2").display().to_string()), + ]); + + let mut buf = Vec::new(); + run_command(matches.subcommand_matches("run").unwrap(), &mut buf).unwrap(); + + assert_eq!( + "kcl1: hello 1\nkcl2: hello 2\n", + String::from_utf8(buf).unwrap() + ); + + let matches = app().arg_required_else_help(true).get_matches_from(&[ + ROOT_CMD, + "run", + &test_case_path.join("kcl2/main.k").display().to_string(), + "${kcl1:KCL_MOD}/main.k", + "-E", + &format!("kcl1={}", test_case_path.join("kcl1").display().to_string()), + ]); + + let mut buf = Vec::new(); + run_command(matches.subcommand_matches("run").unwrap(), &mut buf).unwrap(); + + assert_eq!( + "kcl2: hello 2\nkcl1: hello 1\n", + String::from_utf8(buf).unwrap() + ); + + let matches = app().arg_required_else_help(true).get_matches_from(&[ + ROOT_CMD, + "run", + &test_case_path.join("kcl3/main.k").display().to_string(), + "${kcl4:KCL_MOD}/main.k", + "-E", + &format!( + "kcl4={}", + test_case_path + .join("kcl3") + .join("kcl4") + .display() + .to_string() + ), + ]); + + let mut buf = Vec::new(); + run_command(matches.subcommand_matches("run").unwrap(), &mut buf).unwrap(); + + assert_eq!( + "k3: Hello World 3\nk4: Hello World 4\n", + String::from_utf8(buf).unwrap() + ); + + let matches = app().arg_required_else_help(true).get_matches_from(&[ + ROOT_CMD, + "run", + &test_case_path + .join("kcl3/kcl4/main.k") + .display() + .to_string(), + "${kcl3:KCL_MOD}/main.k", + "-E", + &format!("kcl3={}", test_case_path.join("kcl3").display().to_string()), + ]); + + let mut buf = Vec::new(); + run_command(matches.subcommand_matches("run").unwrap(), &mut buf).unwrap(); + + assert_eq!( + "k4: Hello World 4\nk3: Hello World 3\n", + String::from_utf8(buf).unwrap() + ); +} + +fn test_instances_with_yaml() { + let test_cases = [ + "test_inst_1", + "test_inst_2", + "test_inst_3", + "test_inst_4", + "test_inst_5", + "test_inst_6", + "test_inst_7", + "test_inst_8", + "test_inst_9", + "test_inst_10", + "test_inst_11/test_inst_111", + ]; + + for case in &test_cases { + let expected = format!("{}/expected", case); + let case_yaml = format!("{}/kcl.yaml", case); + test_instances(&case_yaml, &expected); + } +} + +fn test_instances(kcl_yaml_path: &str, expected_file_path: &str) { + let test_case_path = PathBuf::from("./src/test_data/instances"); + let matches = app().arg_required_else_help(true).get_matches_from(&[ + ROOT_CMD, + "run", + "-Y", + &test_case_path.join(kcl_yaml_path).display().to_string(), + ]); + + let mut buf = Vec::new(); + run_command(matches.subcommand_matches("run").unwrap(), &mut buf).unwrap(); + let expect = fs::read_to_string( + test_case_path + .join(expected_file_path) + .display() + .to_string(), + ) + .unwrap(); + + assert_eq!( + expect.replace("\r\n", "\n"), + String::from_utf8(buf).unwrap() + ); +} + +fn test_main_pkg_not_found() { + let test_case_path = PathBuf::from("./src/test_data/multimod"); + + let matches = app().arg_required_else_help(true).get_matches_from(&[ + ROOT_CMD, + "run", + "${kcl3:KCL_MOD}/main.k", + "-E", + &format!("kcl3={}", test_case_path.join("kcl3").display().to_string()), + ]); + let settings = must_build_settings(matches.subcommand_matches("run").unwrap()); + let sess = Arc::new(ParseSession::default()); + match exec_program(sess.clone(), &settings.try_into().unwrap()) + .map_err_to_result() + .map_err(|e| e.to_string()) + { + Ok(_) => panic!("unreachable code."), + Err(msg) => assert_eq!( + msg, + "Cannot find the kcl file, please check the file path ${kcl3:KCL_MOD}/main.k" + ), + } +} + +fn test_multi_mod_file() { + let test_case_path = PathBuf::from("./src/test_data/multimod"); + + let matches = app().arg_required_else_help(true).get_matches_from(&[ + ROOT_CMD, + "run", + &test_case_path.join("kcl1").display().to_string(), + &test_case_path.join("kcl2").display().to_string(), + ]); + let settings = must_build_settings(matches.subcommand_matches("run").unwrap()); + let sess = Arc::new(ParseSession::default()); + match exec_program(sess.clone(), &settings.try_into().unwrap()) { + Ok(res) => { + assert_eq!(res.yaml_result, "kcl1: hello 1\nkcl2: hello 2"); + assert_eq!( + res.json_result, + "{\"kcl1\": \"hello 1\", \"kcl2\": \"hello 2\"}" + ); + } + Err(_) => panic!("unreachable code."), + } +} + +fn test_plugin_not_found() { + let test_case_path = PathBuf::from("./src/test_data/plugin/plugin_not_found"); + let matches = app().arg_required_else_help(true).get_matches_from(&[ + ROOT_CMD, + "run", + test_case_path.as_path().display().to_string().as_str(), + ]); + let settings = must_build_settings(matches.subcommand_matches("run").unwrap()); + let sess = Arc::new(ParseSession::default()); + match exec_program(sess.clone(), &settings.try_into().unwrap()).map_err_to_result().map_err(|e|e.to_string()) { + Ok(_) => panic!("unreachable code."), + Err(msg) => assert!(msg.contains("the plugin package `kcl_plugin.not_exist` is not found, please confirm if plugin mode is enabled")), + } +} + +fn test_error_message_fuzz_matched() { + let test_case_path = PathBuf::from("./src/test_data/fuzz_match/main.k"); + let matches = app().arg_required_else_help(true).get_matches_from(&[ + ROOT_CMD, + "run", + &test_case_path.canonicalize().unwrap().display().to_string(), + ]); + let settings = must_build_settings(matches.subcommand_matches("run").unwrap()); + let sess = Arc::new(ParseSession::default()); + match exec_program(sess.clone(), &settings.try_into().unwrap()) + .map_err_to_result() + .map_err(|e| e.to_string()) + { + Ok(_) => panic!("unreachable code."), + Err(msg) => { + assert!(msg.contains("attribute 'a' not found in 'Person', did you mean '[\"aa\"]'?")) + } + } +} + +fn test_error_message_fuzz_unmatched() { + let test_case_path = PathBuf::from("./src/test_data/fuzz_match/main_unmatched.k"); + let matches = app().arg_required_else_help(true).get_matches_from(&[ + ROOT_CMD, + "run", + &test_case_path.canonicalize().unwrap().display().to_string(), + ]); + let settings = must_build_settings(matches.subcommand_matches("run").unwrap()); + let sess = Arc::new(ParseSession::default()); + match exec_program(sess.clone(), &settings.try_into().unwrap()) + .map_err_to_result() + .map_err(|e| e.to_string()) + { + Ok(_) => panic!("unreachable code."), + Err(msg) => { + assert!(msg.contains("attribute 'a' not found in 'Person'")) + } + } +} + +fn test_keyword_argument_error_message() { + let test_case_path = PathBuf::from("./src/test_data/failed/keyword_argument_error.k"); + let matches = app().arg_required_else_help(true).get_matches_from(&[ + ROOT_CMD, + "run", + &test_case_path.canonicalize().unwrap().display().to_string(), + ]); + let settings = must_build_settings(matches.subcommand_matches("run").unwrap()); + let sess = Arc::new(ParseSession::default()); + match exec_program(sess.clone(), &settings.try_into().unwrap()) + .map_err_to_result() + .map_err(|e| e.to_string()) + { + Ok(_) => panic!("unreachable code."), + Err(msg) => { + assert!(msg.contains("keyword argument 'ID' not found")); + } + } +} diff --git a/kclvm/cmd/src/util.rs b/kclvm/cmd/src/util.rs new file mode 100644 index 000000000..17079e05a --- /dev/null +++ b/kclvm/cmd/src/util.rs @@ -0,0 +1,55 @@ +use anyhow::Result; +use clap::ArgMatches; +use std::collections::HashMap; + +#[inline] +pub(crate) fn strings_from_matches(matches: &ArgMatches, key: &str) -> Option> { + matches.get_many::(key).map(|files| { + files + .into_iter() + .map(|v| v.to_string()) + .collect::>() + }) +} + +#[inline] +pub(crate) fn hashmaps_from_matches( + matches: &ArgMatches, + key: &str, +) -> Option>> { + matches.get_many::(key).map(|files| { + files + .into_iter() + .map(|s| { + let split_values = s.split('=').collect::>(); + if split_values.len() == 2 + && !split_values[0].trim().is_empty() + && !split_values[1].trim().is_empty() + { + Ok((split_values[0].to_string(), split_values[1].to_string())) + } else { + Err(anyhow::anyhow!("Invalid value for top level arguments")) + } + }) + .collect::>>() + }) +} + +#[inline] +pub(crate) fn bool_from_matches(matches: &ArgMatches, key: &str) -> Option { + if matches.get_flag(key) == true { + Some(true) + } else { + None + } +} + +#[inline] +pub(crate) fn u32_from_matches(matches: &ArgMatches, key: &str) -> Option { + let occurrences = matches.get_count(key); + if occurrences > 0 { + Some(occurrences as u32) + } else { + None + } +} diff --git a/kclvm/compiler/Cargo.lock b/kclvm/compiler/Cargo.lock deleted file mode 100644 index ccd9c6f4a..000000000 --- a/kclvm/compiler/Cargo.lock +++ /dev/null @@ -1,1327 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "ahash" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" -dependencies = [ - "getrandom", - "once_cell", - "version_check", -] - -[[package]] -name = "aho-corasick" -version = "0.7.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" -dependencies = [ - "memchr", -] - -[[package]] -name = "annotate-snippets" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d78ea013094e5ea606b1c05fe35f1dd7ea1eb1ea259908d040b25bd5ec677ee5" - -[[package]] -name = "arrayvec" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6" - -[[package]] -name = "atty" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" -dependencies = [ - "hermit-abi", - "libc", - "winapi", -] - -[[package]] -name = "autocfg" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" - -[[package]] -name = "base64" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" - -[[package]] -name = "bit-set" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e11e16035ea35e4e5997b393eacbf6f63983188f7a2ad25bfb13465f5ad59de" -dependencies = [ - "bit-vec", -] - -[[package]] -name = "bit-vec" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" - -[[package]] -name = "bitflags" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" - -[[package]] -name = "block-buffer" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" -dependencies = [ - "generic-array", -] - -[[package]] -name = "block-buffer" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bf7fe51849ea569fd452f37822f606a5cabb684dc918707a0193fd4664ff324" -dependencies = [ - "generic-array", -] - -[[package]] -name = "bstr" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223" -dependencies = [ - "lazy_static", - "memchr", - "regex-automata", -] - -[[package]] -name = "cc" -version = "1.0.72" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22a9137b95ea06864e018375b72adfb7db6e6f68cfc8df5a04d00288050485ee" - -[[package]] -name = "cfg-if" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "chrono" -version = "0.4.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73" -dependencies = [ - "libc", - "num-integer", - "num-traits", - "time", - "winapi", -] - -[[package]] -name = "cpufeatures" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95059428f66df56b63431fdb4e1947ed2190586af5c5a8a8b71122bdf5a7f469" -dependencies = [ - "libc", -] - -[[package]] -name = "crossbeam-deque" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e" -dependencies = [ - "cfg-if 1.0.0", - "crossbeam-epoch", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-epoch" -version = "0.9.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1145cf131a2c6ba0615079ab6a638f7e1973ac9c2634fcbeaaad6114246efe8c" -dependencies = [ - "autocfg", - "cfg-if 1.0.0", - "crossbeam-utils", - "lazy_static", - "memoffset", - "scopeguard", -] - -[[package]] -name = "crossbeam-utils" -version = "0.8.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bf124c720b7686e3c2663cf54062ab0f68a88af2fb6a030e87e30bf721fcb38" -dependencies = [ - "cfg-if 1.0.0", - "lazy_static", -] - -[[package]] -name = "crypto-common" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57952ca27b5e3606ff4dd79b0020231aaf9d6aa76dc05fd30137538c50bd3ce8" -dependencies = [ - "generic-array", - "typenum", -] - -[[package]] -name = "digest" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" -dependencies = [ - "generic-array", -] - -[[package]] -name = "digest" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2fb860ca6fafa5552fb6d0e816a69c8e49f0908bf524e30a90d97c85892d506" -dependencies = [ - "block-buffer 0.10.2", - "crypto-common", -] - -[[package]] -name = "either" -version = "1.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" - -[[package]] -name = "ena" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7402b94a93c24e742487327a7cd839dc9d36fec9de9fb25b09f2dae459f36c3" -dependencies = [ - "log", -] - -[[package]] -name = "fancy-regex" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d6b8560a05112eb52f04b00e5d3790c0dd75d9d980eb8a122fb23b92a623ccf" -dependencies = [ - "bit-set", - "regex", -] - -[[package]] -name = "fastrand" -version = "1.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3fcf0cee53519c866c09b5de1f6c56ff9d647101f81c1964fa632e148896cdf" -dependencies = [ - "instant", -] - -[[package]] -name = "fixedbitset" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "279fb028e20b3c4c320317955b77c5e0c9701f05a1d309905d6fc702cdc5053e" - -[[package]] -name = "generic-array" -version = "0.14.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "501466ecc8a30d1d3b7fc9229b122b2ce8ed6e9d9223f1138d4babb253e51817" -dependencies = [ - "typenum", - "version_check", -] - -[[package]] -name = "getrandom" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753" -dependencies = [ - "cfg-if 1.0.0", - "libc", - "wasi", -] - -[[package]] -name = "hashbrown" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" - -[[package]] -name = "hermit-abi" -version = "0.1.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" -dependencies = [ - "libc", -] - -[[package]] -name = "indexmap" -version = "1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f647032dfaa1f8b6dc29bd3edb7bbef4861b8b8007ebb118d6db284fd59f6ee" -dependencies = [ - "autocfg", - "hashbrown", - "rustc-rayon", -] - -[[package]] -name = "inkwell" -version = "0.1.0" -source = "git+https://github.com/TheDan64/inkwell?branch=master#bff378bee02bcbb5bed35f47e9ed69e6642e9188" -dependencies = [ - "either", - "inkwell_internals", - "libc", - "llvm-sys", - "once_cell", - "parking_lot", -] - -[[package]] -name = "inkwell_internals" -version = "0.5.0" -source = "git+https://github.com/TheDan64/inkwell?branch=master#bff378bee02bcbb5bed35f47e9ed69e6642e9188" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "instant" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" -dependencies = [ - "cfg-if 1.0.0", -] - -[[package]] -name = "itertools" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3" -dependencies = [ - "either", -] - -[[package]] -name = "itoa" -version = "0.4.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" - -[[package]] -name = "jobserver" -version = "0.1.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af25a77299a7f711a01975c35a6a424eb6862092cc2d6c72c4ed6cbc56dfc1fa" -dependencies = [ - "libc", -] - -[[package]] -name = "json_minimal" -version = "0.1.3" - -[[package]] -name = "kclvm-ast" -version = "0.1.0" -dependencies = [ - "kclvm-span", - "rustc_span", - "serde", - "serde_json", -] - -[[package]] -name = "kclvm-compiler" -version = "0.1.0" -dependencies = [ - "ahash", - "bit-set", - "bitflags", - "fancy-regex", - "indexmap", - "inkwell", - "kclvm-ast", - "kclvm-error", - "kclvm-runtime", - "kclvm-sema", - "once_cell", - "phf", - "time", - "unicode_names2", -] - -[[package]] -name = "kclvm-error" -version = "0.1.0" -dependencies = [ - "annotate-snippets", - "atty", - "indexmap", - "kclvm-runtime", - "kclvm-span", - "rustc_span", - "termcolor", - "termize", - "tracing", -] - -[[package]] -name = "kclvm-macros" -version = "0.1.0" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "synstructure", -] - -[[package]] -name = "kclvm-runtime" -version = "0.1.0" -dependencies = [ - "ahash", - "base64", - "bstr", - "chrono", - "fancy-regex", - "indexmap", - "itertools", - "json_minimal", - "kclvm_runtime_internal_macros", - "libc", - "md5", - "num-integer", - "phf", - "regex", - "serde", - "serde_json", - "serde_yaml", - "sha1", - "sha2 0.9.8", - "unic-ucd-bidi", - "unic-ucd-category", - "unicode-casing", -] - -[[package]] -name = "kclvm-sema" -version = "0.1.0" -dependencies = [ - "ahash", - "bit-set", - "bitflags", - "fancy-regex", - "indexmap", - "kclvm-ast", - "kclvm-error", - "kclvm-runtime", - "kclvm-span", - "once_cell", - "petgraph", - "phf", - "unicode_names2", -] - -[[package]] -name = "kclvm-span" -version = "0.1.0" -dependencies = [ - "kclvm-macros", - "rustc_span", - "scoped-tls", -] - -[[package]] -name = "kclvm_runtime_internal_macros" -version = "0.1.0" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "lazy_static" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" - -[[package]] -name = "libc" -version = "0.2.112" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b03d17f364a3a042d5e5d46b053bbbf82c92c9430c592dd4c064dc6ee997125" - -[[package]] -name = "linked-hash-map" -version = "0.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fb9b38af92608140b86b693604b9ffcc5824240a484d1ecd4795bacb2fe88f3" - -[[package]] -name = "llvm-sys" -version = "120.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09b716322964966a62377cf86e64f00ca7043505fdf27bd2ec7d41ae6682d1e7" -dependencies = [ - "cc", - "lazy_static", - "libc", - "regex", - "semver", -] - -[[package]] -name = "lock_api" -version = "0.4.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "327fa5b6a6940e4699ec49a9beae1ea4845c6bab9314e4f84ac68742139d8c53" -dependencies = [ - "autocfg", - "scopeguard", -] - -[[package]] -name = "log" -version = "0.4.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6389c490849ff5bc16be905ae24bc913a9c8892e19b2341dbc175e14c341c2b8" -dependencies = [ - "cfg-if 1.0.0", -] - -[[package]] -name = "matches" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" - -[[package]] -name = "md-5" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "658646b21e0b72f7866c7038ab086d3d5e1cd6271f060fd37defb241949d0582" -dependencies = [ - "digest 0.10.3", -] - -[[package]] -name = "md5" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "490cc448043f947bae3cbee9c203358d62dbee0db12107a74be5c30ccfd09771" - -[[package]] -name = "memchr" -version = "2.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" - -[[package]] -name = "memmap2" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "723e3ebdcdc5c023db1df315364573789f8857c11b631a2fdfad7c00f5c046b4" -dependencies = [ - "libc", -] - -[[package]] -name = "memoffset" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" -dependencies = [ - "autocfg", -] - -[[package]] -name = "num-integer" -version = "0.1.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" -dependencies = [ - "autocfg", - "num-traits", -] - -[[package]] -name = "num-traits" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" -dependencies = [ - "autocfg", -] - -[[package]] -name = "num_cpus" -version = "1.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" -dependencies = [ - "hermit-abi", - "libc", -] - -[[package]] -name = "once_cell" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56" - -[[package]] -name = "opaque-debug" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" - -[[package]] -name = "parking_lot" -version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87f5ec2493a61ac0506c0f4199f99070cbe83857b0337006a30f3e6719b8ef58" -dependencies = [ - "lock_api", - "parking_lot_core", -] - -[[package]] -name = "parking_lot_core" -version = "0.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "995f667a6c822200b0433ac218e05582f0e2efa1b922a3fd2fbaadc5f87bab37" -dependencies = [ - "cfg-if 1.0.0", - "libc", - "redox_syscall", - "smallvec", - "windows-sys", -] - -[[package]] -name = "pest" -version = "2.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10f4872ae94d7b90ae48754df22fd42ad52ce740b8f370b03da4835417403e53" -dependencies = [ - "ucd-trie", -] - -[[package]] -name = "petgraph" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a13a2fa9d0b63e5f22328828741e523766fff0ee9e779316902290dff3f824f" -dependencies = [ - "fixedbitset", - "indexmap", -] - -[[package]] -name = "phf" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2ac8b67553a7ca9457ce0e526948cad581819238f4a9d1ea74545851fa24f37" -dependencies = [ - "phf_macros", - "phf_shared", - "proc-macro-hack", -] - -[[package]] -name = "phf_generator" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d43f3220d96e0080cc9ea234978ccd80d904eafb17be31bb0f76daaea6493082" -dependencies = [ - "phf_shared", - "rand", -] - -[[package]] -name = "phf_macros" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b706f5936eb50ed880ae3009395b43ed19db5bff2ebd459c95e7bf013a89ab86" -dependencies = [ - "phf_generator", - "phf_shared", - "proc-macro-hack", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "phf_shared" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a68318426de33640f02be62b4ae8eb1261be2efbc337b60c54d845bf4484e0d9" -dependencies = [ - "siphasher", -] - -[[package]] -name = "pin-project-lite" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e280fbe77cc62c91527259e9442153f4688736748d24660126286329742b4c6c" - -[[package]] -name = "ppv-lite86" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed0cfbc8191465bed66e1718596ee0b0b35d5ee1f41c5df2189d0fe8bde535ba" - -[[package]] -name = "proc-macro-hack" -version = "0.5.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" - -[[package]] -name = "proc-macro2" -version = "1.0.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9f5105d4fdaab20335ca9565e106a5d9b82b6219b5ba735731124ac6711d23d" -dependencies = [ - "unicode-xid", -] - -[[package]] -name = "psm" -version = "0.1.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "871372391786ccec00d3c5d3d6608905b3d4db263639cfe075d3b60a736d115a" -dependencies = [ - "cc", -] - -[[package]] -name = "quote" -version = "1.0.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38bc8cc6a5f2e3655e0899c1b848643b2562f853f114bfec7be120678e3ace05" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "rand" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8" -dependencies = [ - "libc", - "rand_chacha", - "rand_core", - "rand_hc", -] - -[[package]] -name = "rand_chacha" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" -dependencies = [ - "ppv-lite86", - "rand_core", -] - -[[package]] -name = "rand_core" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" -dependencies = [ - "getrandom", -] - -[[package]] -name = "rand_hc" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d51e9f596de227fda2ea6c84607f5558e196eeaf43c986b724ba4fb8fdf497e7" -dependencies = [ - "rand_core", -] - -[[package]] -name = "redox_syscall" -version = "0.2.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff" -dependencies = [ - "bitflags", -] - -[[package]] -name = "regex" -version = "1.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] - -[[package]] -name = "regex-automata" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" - -[[package]] -name = "regex-syntax" -version = "0.6.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" - -[[package]] -name = "remove_dir_all" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" -dependencies = [ - "winapi", -] - -[[package]] -name = "rustc-hash" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" - -[[package]] -name = "rustc-rayon" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9974ab223660e61c1b4e7b43b827379df286736ca988308ce7e16f59f2d89246" -dependencies = [ - "crossbeam-deque", - "either", - "rustc-rayon-core", -] - -[[package]] -name = "rustc-rayon-core" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "564bfd27be8db888d0fa76aa4335e7851aaed0c2c11ad1e93aeb9349f6b88500" -dependencies = [ - "crossbeam-deque", - "crossbeam-utils", - "lazy_static", - "num_cpus", -] - -[[package]] -name = "rustc_data_structures" -version = "0.0.0" -dependencies = [ - "arrayvec", - "bitflags", - "cfg-if 0.1.10", - "ena", - "indexmap", - "jobserver", - "libc", - "memmap2", - "parking_lot", - "rustc-hash", - "rustc-rayon", - "rustc-rayon-core", - "stable_deref_trait", - "stacker", - "tempfile", - "tracing", - "winapi", -] - -[[package]] -name = "rustc_span" -version = "0.0.0" -dependencies = [ - "cfg-if 0.1.10", - "md-5", - "rustc_data_structures", - "scoped-tls", - "sha-1", - "sha2 0.10.2", - "tracing", - "unicode-width", -] - -[[package]] -name = "ryu" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" - -[[package]] -name = "scoped-tls" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2" - -[[package]] -name = "scopeguard" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" - -[[package]] -name = "semver" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6" -dependencies = [ - "semver-parser", -] - -[[package]] -name = "semver-parser" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0bef5b7f9e0df16536d3961cfb6e84331c065b4066afb39768d0e319411f7" -dependencies = [ - "pest", -] - -[[package]] -name = "serde" -version = "1.0.130" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f12d06de37cf59146fbdecab66aa99f9fe4f78722e3607577a5375d66bd0c913" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.130" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7bc1a1ab1961464eae040d96713baa5a724a8152c1222492465b54322ec508b" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "serde_json" -version = "1.0.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e466864e431129c7e0d3476b92f20458e5879919a0596c6472738d9fa2d342f8" -dependencies = [ - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "serde_yaml" -version = "0.8.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a521f2940385c165a24ee286aa8599633d162077a54bdcae2a6fd5a7bfa7a0" -dependencies = [ - "indexmap", - "ryu", - "serde", - "yaml-rust", -] - -[[package]] -name = "sha-1" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "028f48d513f9678cda28f6e4064755b3fbb2af6acd672f2c209b62323f7aea0f" -dependencies = [ - "cfg-if 1.0.0", - "cpufeatures", - "digest 0.10.3", -] - -[[package]] -name = "sha1" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2579985fda508104f7587689507983eadd6a6e84dd35d6d115361f530916fa0d" - -[[package]] -name = "sha2" -version = "0.9.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b69f9a4c9740d74c5baa3fd2e547f9525fa8088a8a958e0ca2409a514e33f5fa" -dependencies = [ - "block-buffer 0.9.0", - "cfg-if 1.0.0", - "cpufeatures", - "digest 0.9.0", - "opaque-debug", -] - -[[package]] -name = "sha2" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55deaec60f81eefe3cce0dc50bda92d6d8e88f2a27df7c5033b42afeb1ed2676" -dependencies = [ - "cfg-if 1.0.0", - "cpufeatures", - "digest 0.10.3", -] - -[[package]] -name = "siphasher" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "533494a8f9b724d33625ab53c6c4800f7cc445895924a8ef649222dcb76e938b" - -[[package]] -name = "smallvec" -version = "1.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ecab6c735a6bb4139c0caafd0cc3635748bbb3acf4550e8138122099251f309" - -[[package]] -name = "stable_deref_trait" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" - -[[package]] -name = "stacker" -version = "0.1.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90939d5171a4420b3ff5fbc8954d641e7377335454c259dcb80786f3f21dc9b4" -dependencies = [ - "cc", - "cfg-if 1.0.0", - "libc", - "psm", - "winapi", -] - -[[package]] -name = "syn" -version = "1.0.76" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6f107db402c2c2055242dbf4d2af0e69197202e9faacbef9571bbe47f5a1b84" -dependencies = [ - "proc-macro2", - "quote", - "unicode-xid", -] - -[[package]] -name = "synstructure" -version = "0.12.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "unicode-xid", -] - -[[package]] -name = "tempfile" -version = "3.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" -dependencies = [ - "cfg-if 1.0.0", - "fastrand", - "libc", - "redox_syscall", - "remove_dir_all", - "winapi", -] - -[[package]] -name = "termcolor" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" -dependencies = [ - "winapi-util", -] - -[[package]] -name = "termize" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1706be6b564323ce7092f5f7e6b118a14c8ef7ed0e69c8c5329c914a9f101295" -dependencies = [ - "libc", - "winapi", -] - -[[package]] -name = "time" -version = "0.1.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255" -dependencies = [ - "libc", - "wasi", - "winapi", -] - -[[package]] -name = "tracing" -version = "0.1.33" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80b9fa4360528139bc96100c160b7ae879f5567f49f1782b0b02035b0358ebf3" -dependencies = [ - "cfg-if 1.0.0", - "pin-project-lite", - "tracing-attributes", - "tracing-core", -] - -[[package]] -name = "tracing-attributes" -version = "0.1.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e65ce065b4b5c53e73bb28912318cb8c9e9ad3921f1d669eb0e68b4c8143a2b" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "tracing-core" -version = "0.1.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90442985ee2f57c9e1b548ee72ae842f4a9a20e3f417cc38dbc5dc684d9bb4ee" -dependencies = [ - "lazy_static", -] - -[[package]] -name = "typenum" -version = "1.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b63708a265f51345575b27fe43f9500ad611579e764c79edbc2037b1121959ec" - -[[package]] -name = "ucd-trie" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c" - -[[package]] -name = "unic-char-property" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8c57a407d9b6fa02b4795eb81c5b6652060a15a7903ea981f3d723e6c0be221" -dependencies = [ - "unic-char-range", -] - -[[package]] -name = "unic-char-range" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0398022d5f700414f6b899e10b8348231abf9173fa93144cbc1a43b9793c1fbc" - -[[package]] -name = "unic-common" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80d7ff825a6a654ee85a63e80f92f054f904f21e7d12da4e22f9834a4aaa35bc" - -[[package]] -name = "unic-ucd-bidi" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1d568b51222484e1f8209ce48caa6b430bf352962b877d592c29ab31fb53d8c" -dependencies = [ - "unic-char-property", - "unic-char-range", - "unic-ucd-version", -] - -[[package]] -name = "unic-ucd-category" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b8d4591f5fcfe1bd4453baaf803c40e1b1e69ff8455c47620440b46efef91c0" -dependencies = [ - "matches", - "unic-char-property", - "unic-char-range", - "unic-ucd-version", -] - -[[package]] -name = "unic-ucd-version" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96bd2f2237fe450fcd0a1d2f5f4e91711124f7857ba2e964247776ebeeb7b0c4" -dependencies = [ - "unic-common", -] - -[[package]] -name = "unicode-casing" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "623f59e6af2a98bdafeb93fa277ac8e1e40440973001ca15cf4ae1541cd16d56" - -[[package]] -name = "unicode-width" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" - -[[package]] -name = "unicode-xid" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" - -[[package]] -name = "unicode_names2" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87d6678d7916394abad0d4b19df4d3802e1fd84abd7d701f39b75ee71b9e8cf1" - -[[package]] -name = "version_check" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" - -[[package]] -name = "wasi" -version = "0.10.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-util" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" -dependencies = [ - "winapi", -] - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "windows-sys" -version = "0.34.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5acdd78cb4ba54c0045ac14f62d8f94a03d10047904ae2a40afa1e99d8f70825" -dependencies = [ - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_msvc", -] - -[[package]] -name = "windows_aarch64_msvc" -version = "0.34.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17cffbe740121affb56fad0fc0e421804adf0ae00891205213b5cecd30db881d" - -[[package]] -name = "windows_i686_gnu" -version = "0.34.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2564fde759adb79129d9b4f54be42b32c89970c18ebf93124ca8870a498688ed" - -[[package]] -name = "windows_i686_msvc" -version = "0.34.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cd9d32ba70453522332c14d38814bceeb747d80b3958676007acadd7e166956" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.34.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfce6deae227ee8d356d19effc141a509cc503dfd1f850622ec4b0f84428e1f4" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.34.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d19538ccc21819d01deaf88d6a17eae6596a12e9aafdbb97916fb49896d89de9" - -[[package]] -name = "yaml-rust" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85" -dependencies = [ - "linked-hash-map", -] diff --git a/kclvm/compiler/Cargo.toml b/kclvm/compiler/Cargo.toml index 06027a04c..c646865c4 100644 --- a/kclvm/compiler/Cargo.toml +++ b/kclvm/compiler/Cargo.toml @@ -1,13 +1,13 @@ [package] name = "kclvm-compiler" -version = "0.1.0" +version = "0.11.0" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -inkwell = { git = "https://github.com/TheDan64/inkwell", branch = "master", features = ["llvm12-0"] } -time = "0.1" +inkwell = { git = "https://github.com/TheDan64/inkwell", branch = "master", optional = true } +time = "0.2.23" phf = { version = "0.9", features = ["macros"] } ahash = "0.7.2" indexmap = "1.0" @@ -16,7 +16,10 @@ bitflags = "1.2.1" once_cell = "1.5.2" fancy-regex = "0.7.1" unicode_names2 = "0.4" -kclvm-ast = {path = "../ast", version = "0.1.0"} -kclvm-sema = {path = "../sema", version = "0.1.0"} -kclvm-runtime = {path = "../runtime", version = "0.1.0"} -kclvm-error = {path = "../error", version = "0.1.0"} +kclvm-ast = {path = "../ast"} +kclvm-sema = {path = "../sema"} +kclvm-runtime = {path = "../runtime"} +kclvm-error = {path = "../error"} + +[features] +llvm = ["inkwell/target-webassembly", "inkwell/llvm12-0"] diff --git a/kclvm/compiler/makefile b/kclvm/compiler/makefile deleted file mode 100644 index c87b1b251..000000000 --- a/kclvm/compiler/makefile +++ /dev/null @@ -1,16 +0,0 @@ -default: - cargo run --release - -llvm: - clang++ -O3 -emit-llvm ./C/test.c -S -o ./C/test.ll - llvm-as ./C/test.ll - lli ./C/test.bc - -fmt: - cargo fmt - -check: - cargo check --release - -lint: - cargo clippy diff --git a/kclvm/compiler/src/codegen/abi.rs b/kclvm/compiler/src/codegen/abi.rs index 4b2b1e71c..68b5cb09c 100644 --- a/kclvm/compiler/src/codegen/abi.rs +++ b/kclvm/compiler/src/codegen/abi.rs @@ -1,4 +1,4 @@ -//! Copyright 2021 The KCL Authors. All rights reserved. +//! Copyright The KCL Authors. All rights reserved. //! Reference: https://github.com/rust-lang/rust/blob/master/compiler/rustc_target/src/lib.rs #![allow(dead_code)] diff --git a/kclvm/compiler/src/codegen/error.rs b/kclvm/compiler/src/codegen/error.rs index 50cc0fb2c..dcf2b2406 100644 --- a/kclvm/compiler/src/codegen/error.rs +++ b/kclvm/compiler/src/codegen/error.rs @@ -1,17 +1,18 @@ -// Copyright 2021 The KCL Authors. All rights reserved. +//! Copyright The KCL Authors. All rights reserved. use std::error; use std::fmt::{self, Debug}; -pub(crate) const VALUE_TYPE_NOT_FOUND_MSG: &str = "Type is not found"; -pub(crate) const CONTEXT_VAR_NOT_FOUND_MSG: &str = "Context variable is not found"; -pub(crate) const FUNCTION_RETURN_VALUE_NOT_FOUND_MSG: &str = "Function return value is not found"; -pub(crate) const COMPILE_ERROR_MSG: &str = "Compile error"; -pub(crate) const INTERNAL_ERROR_MSG: &str = "Internal error, please report a bug to us"; -pub(crate) const CODE_GEN_ERROR_MSG: &str = "Code gen error"; -pub(crate) const INVALID_OPERATOR_MSG: &str = "Invalid operator"; -pub(crate) const INVALID_JOINED_STR_MSG: &str = "Invalid AST JoinedString value"; -pub(crate) const INVALID_STR_INTERPOLATION_SPEC_MSG: &str = +pub const VALUE_TYPE_NOT_FOUND_MSG: &str = "Internal error, value type is not found"; +pub const CONTEXT_VAR_NOT_FOUND_MSG: &str = "Internal error, context variable is not found"; +pub const INTERNAL_ERROR_MSG: &str = "Internal error, please report a bug to us"; +pub const FUNCTION_RETURN_VALUE_NOT_FOUND_MSG: &str = + "Internal error, function return value is not found"; +pub const COMPILE_ERROR_MSG: &str = "Compile error"; +pub const CODE_GEN_ERROR_MSG: &str = "Code gen error"; +pub const INVALID_OPERATOR_MSG: &str = "Invalid operator"; +pub const INVALID_JOINED_STR_MSG: &str = "Invalid AST JoinedString value"; +pub const INVALID_STR_INTERPOLATION_SPEC_MSG: &str = "Invalid string interpolation format specification"; #[derive(Debug, Clone, PartialEq, Eq)] diff --git a/kclvm/compiler/src/codegen/llvm/backtrack.rs b/kclvm/compiler/src/codegen/llvm/backtrack.rs new file mode 100644 index 000000000..937ea29dc --- /dev/null +++ b/kclvm/compiler/src/codegen/llvm/backtrack.rs @@ -0,0 +1,44 @@ +// Copyright The KCL Authors. All rights reserved. + +use super::context::LLVMCodeGenContext; +use crate::codegen::llvm::context::BacktrackKind; +use crate::codegen::traits::BuilderMethods; +use inkwell::values::BasicValueEnum; + +impl<'ctx> LLVMCodeGenContext<'ctx> { + pub(crate) fn update_backtrack_meta( + &self, + name: &str, + schema_value: BasicValueEnum<'ctx>, + ) -> bool { + if let Some(backtrack_meta) = self.backtrack_meta.borrow_mut().as_mut() { + if name == backtrack_meta.target { + backtrack_meta.count += 1; + if backtrack_meta.count >= backtrack_meta.level { + backtrack_meta.stop = true; + self.ret(schema_value); + return true; + } + } + } + false + } + + #[inline] + pub(crate) fn is_backtrack_only_if(&self) -> bool { + if let Some(backtrack_meta) = self.backtrack_meta.borrow_mut().as_ref() { + matches!(backtrack_meta.kind, BacktrackKind::If) + } else { + false + } + } + + #[inline] + pub(crate) fn is_backtrack_only_or_else(&self) -> bool { + if let Some(backtrack_meta) = self.backtrack_meta.borrow_mut().as_ref() { + matches!(backtrack_meta.kind, BacktrackKind::OrElse) + } else { + false + } + } +} diff --git a/kclvm/compiler/src/codegen/llvm/context.rs b/kclvm/compiler/src/codegen/llvm/context.rs index 17f453686..0f31dde83 100644 --- a/kclvm/compiler/src/codegen/llvm/context.rs +++ b/kclvm/compiler/src/codegen/llvm/context.rs @@ -1,10 +1,13 @@ -// Copyright 2021 The KCL Authors. All rights reserved. +// Copyright The KCL Authors. All rights reserved. -use indexmap::IndexMap; +use indexmap::{IndexMap, IndexSet}; use inkwell::basic_block::BasicBlock; use inkwell::builder::Builder; use inkwell::context::Context; +use inkwell::memory_buffer::MemoryBuffer; use inkwell::module::{Linkage, Module}; +use inkwell::support::LLVMString; +use inkwell::targets::{CodeModel, FileType, RelocMode}; use inkwell::types::{BasicMetadataTypeEnum, BasicType, BasicTypeEnum, FunctionType}; use inkwell::values::{ BasicMetadataValueEnum, BasicValueEnum, FunctionValue, IntValue, PointerValue, @@ -14,26 +17,30 @@ use phf::{phf_map, Map}; use std::cell::RefCell; use std::collections::{HashMap, HashSet}; use std::error::Error; +use std::path::Path; use std::rc::Rc; use std::str; -use kclvm::{ApiFunc, MAIN_PKG_PATH, PKG_PATH_PREFIX}; use kclvm_ast::ast; use kclvm_ast::walker::TypedResultWalker; use kclvm_error::*; +use kclvm_runtime::{ApiFunc, MAIN_PKG_PATH, PKG_PATH_PREFIX}; use kclvm_sema::builtin; +use kclvm_sema::pkgpath_without_prefix; use kclvm_sema::plugin; use crate::codegen::abi::Align; -use crate::codegen::CodeGenContext; +use crate::codegen::llvm::utils; +use crate::codegen::OBJECT_FILE_SUFFIX; use crate::codegen::{error as kcl_error, EmitOptions}; use crate::codegen::{ - traits::*, ENTRY_NAME, GLOBAL_VAL_ALIGNMENT, KCL_CONTEXT_VAR_NAME, MODULE_NAME, - PKG_INIT_FUNCTION_SUFFIX, + traits::*, ENTRY_NAME, GLOBAL_VAL_ALIGNMENT, MODULE_NAME, PKG_INIT_FUNCTION_SUFFIX, }; -use crate::pkgpath_without_prefix; +use crate::codegen::{CodeGenContext, GLOBAL_LEVEL}; use crate::value; +/// SCALAR_KEY denotes the temp scalar key for the global variable json plan process. +const SCALAR_KEY: &str = ""; /// Float type string width mapping pub const FLOAT_TYPE_WIDTH_MAPPING: Map<&str, usize> = phf_map! { "half" => 16, @@ -48,17 +55,39 @@ pub const FLOAT_TYPE_WIDTH_MAPPING: Map<&str, usize> = phf_map! { pub type CompileResult<'a> = Result, kcl_error::KCLError>; /// The compiler scope. +#[derive(Debug, Default)] pub struct Scope<'ctx> { - pub variables: RefCell>>, - pub closures: RefCell>>, + /// Scalars denotes the expression statement values without attribute. + pub(crate) scalars: RefCell>>, + /// schema_scalar_idx denotes whether a schema exists in the scalar list. + pub(crate) schema_scalar_idx: RefCell, + /// Scope normal variables + pub(crate) variables: RefCell>>, + /// Scope normal initialized variables + pub(crate) uninitialized: RefCell>, + /// Potential arguments in the current scope, such as schema/lambda arguments. + pub(crate) arguments: RefCell>, } -/// Schema internal order independent computation backtracking meta information. +/// Setter kind. +/// - If it is a normal kind, traverse all statements in the setter. +/// - If it is an if type, only traverse the if statement in the if stmt, skipping the else stmt. +/// - If it is an orelse type, only traverse the else statement, and make conditional judgments based on the inverse of the if stmt's cond. +#[derive(Default, Debug, Clone, PartialEq)] +pub enum BacktrackKind { + #[default] + Normal, + If, + OrElse, +} + +/// Schema or Global internal order independent computation backtracking meta information. pub struct BacktrackMeta { pub target: String, pub level: usize, pub count: usize, pub stop: bool, + pub kind: BacktrackKind, } /// The LLVM code generator @@ -67,27 +96,43 @@ pub struct LLVMCodeGenContext<'ctx> { pub module: Module<'ctx>, pub builder: Builder<'ctx>, pub program: &'ctx ast::Program, - pub pkg_scopes: RefCell>>>>, pub functions: RefCell>>>, pub imported: RefCell>, - pub local_vars: RefCell>, + pub setter_keys: RefCell>, pub schema_stack: RefCell>, - pub lambda_stack: RefCell>, + pub lambda_stack: RefCell>, + pub schema_expr_stack: RefCell>, pub pkgpath_stack: RefCell>, pub filename_stack: RefCell>, + /// Package scope to store variable pointers. + pub pkg_scopes: RefCell>>>>, + /// Local variables in the loop. + pub local_vars: RefCell>, + /// The names of possible assignment objects for the current instruction. pub target_vars: RefCell>, + /// Global string caches pub global_strings: RefCell>>>, + /// Global variable pointers cross different packages. pub global_vars: RefCell>>>, - pub current_filename: RefCell, + /// The line number of the source file corresponding to the current instruction pub current_line: RefCell, + /// Error handler to store compile errors. pub handler: RefCell, - // Schema attr backtrack meta + /// Schema attr backtrack meta pub backtrack_meta: RefCell>, /// Import names mapping pub import_names: IndexMap>, - // No link mode + /// No link mode pub no_link: bool, - pub modules: RefCell>>>, + /// Program modules according to AST modules + pub modules: RefCell>>>, + /// Program workdir + pub workdir: String, +} + +/// LLVM module with debug info builder and compile unit. +pub struct DebugModule<'ctx> { + pub inner: Module<'ctx>, } impl<'ctx> CodeGenObject for BasicValueEnum<'ctx> {} @@ -296,9 +341,9 @@ impl<'ctx> BuilderMethods for LLVMCodeGenContext<'ctx> { fn lookup_function(&self, name: &str) -> Self::Function { if self.no_link { let pkgpath = self.current_pkgpath(); - let modules = self.modules.borrow_mut(); + let modules = self.modules.borrow(); let msg = format!("pkgpath {} is not found", pkgpath); - let module = modules.get(&pkgpath).expect(&msg).borrow_mut(); + let module = &modules.get(&pkgpath).expect(&msg).borrow().inner; if let Some(function) = module.get_function(name) { function } else { @@ -322,12 +367,26 @@ impl<'ctx> BuilderMethods for LLVMCodeGenContext<'ctx> { let pkgpath = self.current_pkgpath(); let msg = format!("pkgpath {} is not found", pkgpath); let modules = self.modules.borrow_mut(); - let module = modules.get(&pkgpath).expect(&msg).borrow_mut(); + let module = &modules.get(&pkgpath).expect(&msg).borrow_mut().inner; module.add_function(name, fn_ty, None) } else { self.module.add_function(name, fn_ty, None) } } + + /// Add a setter function named `name`. + fn add_setter_function(&self, name: &str) -> Self::Function { + let fn_ty = self.setter_func_type(); + if self.no_link { + let pkgpath = self.current_pkgpath(); + let msg = format!("pkgpath {} is not found", pkgpath); + let modules = self.modules.borrow_mut(); + let module = modules.get(&pkgpath).expect(&msg).borrow_mut(); + module.inner.add_function(name, fn_ty, None) + } else { + self.module.add_function(name, fn_ty, None) + } + } } /* Value methods */ @@ -338,7 +397,10 @@ impl<'ctx> ValueMethods for LLVMCodeGenContext<'ctx> { let i64_type = self.context.i64_type(); self.build_call( &ApiFunc::kclvm_value_Int.name(), - &[i64_type.const_int(v as u64, false).into()], + &[ + self.current_runtime_ctx_ptr(), + i64_type.const_int(v as u64, false).into(), + ], ) } @@ -347,14 +409,20 @@ impl<'ctx> ValueMethods for LLVMCodeGenContext<'ctx> { let f64_type = self.context.f64_type(); self.build_call( &ApiFunc::kclvm_value_Float.name(), - &[f64_type.const_float(v).into()], + &[ + self.current_runtime_ctx_ptr(), + f64_type.const_float(v).into(), + ], ) } /// Construct a string value using &str fn string_value(&self, v: &str) -> Self::Value { let string_ptr_value = self.native_global_string(v, ""); - self.build_call(&ApiFunc::kclvm_value_Str.name(), &[string_ptr_value.into()]) + self.build_call( + &ApiFunc::kclvm_value_Str.name(), + &[self.current_runtime_ctx_ptr(), string_ptr_value.into()], + ) } /// Construct a bool value @@ -362,36 +430,55 @@ impl<'ctx> ValueMethods for LLVMCodeGenContext<'ctx> { let i8_type = self.context.i8_type(); self.build_call( &ApiFunc::kclvm_value_Bool.name(), - &[i8_type.const_int(v as u64, false).into()], + &[ + self.current_runtime_ctx_ptr(), + i8_type.const_int(v as u64, false).into(), + ], ) } /// Construct a None value fn none_value(&self) -> Self::Value { - self.build_call(&ApiFunc::kclvm_value_None.name(), &[]) + self.build_call( + &ApiFunc::kclvm_value_None.name(), + &[self.current_runtime_ctx_ptr()], + ) } /// Construct a Undefined value fn undefined_value(&self) -> Self::Value { - self.build_call(&ApiFunc::kclvm_value_Undefined.name(), &[]) + self.build_call( + &ApiFunc::kclvm_value_Undefined.name(), + &[self.current_runtime_ctx_ptr()], + ) } /// Construct a empty kcl list value fn list_value(&self) -> Self::Value { - self.build_call(&ApiFunc::kclvm_value_List.name(), &[]) + self.build_call( + &ApiFunc::kclvm_value_List.name(), + &[self.current_runtime_ctx_ptr()], + ) } /// Construct a list value with `n` elements fn list_values(&self, values: &[Self::Value]) -> Self::Value { + let mut args = vec![self.current_runtime_ctx_ptr()]; + for value in values { + args.push(*value); + } self.build_call( &format!("{}{}", ApiFunc::kclvm_value_List.name(), values.len()), - values, + args.as_slice(), ) } /// Construct a empty kcl dict value. fn dict_value(&self) -> Self::Value { - self.build_call(&ApiFunc::kclvm_value_Dict.name(), &[]) + self.build_call( + &ApiFunc::kclvm_value_Dict.name(), + &[self.current_runtime_ctx_ptr()], + ) } /// Construct a unit value @@ -402,6 +489,7 @@ impl<'ctx> ValueMethods for LLVMCodeGenContext<'ctx> { self.build_call( &ApiFunc::kclvm_value_Unit.name(), &[ + self.current_runtime_ctx_ptr(), f64_type.const_float(v).into(), i64_type.const_int(raw as u64, false).into(), unit_native_str.into(), @@ -410,34 +498,44 @@ impl<'ctx> ValueMethods for LLVMCodeGenContext<'ctx> { } /// Construct a function value using a native function. fn function_value(&self, function: FunctionValue<'ctx>) -> Self::Value { + let func_name = function.get_name().to_str().unwrap(); + let func_name_ptr = self.native_global_string(func_name, func_name).into(); let lambda_fn_ptr = self.builder.build_bitcast( function.as_global_value().as_pointer_value(), - self.context.i64_type().ptr_type(AddressSpace::Generic), + self.context.i64_type().ptr_type(AddressSpace::default()), "", ); self.build_call( &ApiFunc::kclvm_value_Function_using_ptr.name(), - &[lambda_fn_ptr], + &[self.current_runtime_ctx_ptr(), lambda_fn_ptr, func_name_ptr], ) } /// Construct a closure function value with the closure variable. fn closure_value(&self, function: FunctionValue<'ctx>, closure: Self::Value) -> Self::Value { + let func_name = function.get_name().to_str().unwrap(); + let func_name_ptr = self.native_global_string(func_name, func_name).into(); // Convert the function to a i64 pointer to store it into the function value. let fn_ptr = self.builder.build_bitcast( function.as_global_value().as_pointer_value(), - self.context.i64_type().ptr_type(AddressSpace::Generic), + self.context.i64_type().ptr_type(AddressSpace::default()), "", ); - let name = self.native_global_string("", "").into(); self.build_call( &ApiFunc::kclvm_value_Function.name(), - &[fn_ptr, closure, name], + &[ + self.current_runtime_ctx_ptr(), + fn_ptr, + closure, + func_name_ptr, + self.native_i8_zero().into(), + ], ) } /// Construct a schema function value using native functions. fn struct_function_value( &self, functions: &[FunctionValue<'ctx>], + attr_functions: &HashMap>>, runtime_type: &str, ) -> Self::Value { if functions.is_empty() { @@ -446,30 +544,36 @@ impl<'ctx> ValueMethods for LLVMCodeGenContext<'ctx> { // Convert the function to a i64 pointer to store it into the function value. let schema_body_fn_ptr = self.builder.build_bitcast( functions[0].as_global_value().as_pointer_value(), - self.context.i64_type().ptr_type(AddressSpace::Generic), + self.context.i64_type().ptr_type(AddressSpace::default()), "", ); // Convert the function to a i64 pointer to store it into the function value. let check_block_fn_ptr = if functions.len() > 1 { self.builder.build_bitcast( functions[1].as_global_value().as_pointer_value(), - self.context.i64_type().ptr_type(AddressSpace::Generic), + self.context.i64_type().ptr_type(AddressSpace::default()), "", ) } else { self.context .i64_type() - .ptr_type(AddressSpace::Generic) + .ptr_type(AddressSpace::default()) .const_zero() .into() }; let runtime_type_native_str = self.native_global_string_value(runtime_type); + let attr_map = self.dict_value(); + for attr in attr_functions.keys() { + self.dict_insert_override_item(attr_map, attr, self.undefined_value()) + } self.builder .build_call( self.lookup_function(&ApiFunc::kclvm_value_schema_function.name()), &[ + self.current_runtime_ctx_ptr().into(), schema_body_fn_ptr.into(), check_block_fn_ptr.into(), + attr_map.into(), runtime_type_native_str.into(), ], runtime_type, @@ -488,7 +592,7 @@ impl<'ctx> ValueMethods for LLVMCodeGenContext<'ctx> { let pkgpath = self.current_pkgpath(); let modules = self.modules.borrow_mut(); let msg = format!("pkgpath {} is not found", pkgpath); - let module = modules.get(&pkgpath).expect(&msg).borrow_mut(); + let module = &modules.get(&pkgpath).expect(&msg).borrow_mut().inner; let fn_type = function.get_type(); function = module.add_function(function_name, fn_type, Some(Linkage::External)); } @@ -502,137 +606,213 @@ impl<'ctx> ValueMethods for LLVMCodeGenContext<'ctx> { let pkgpath = self.current_pkgpath(); let msg = format!("pkgpath {} is not found", pkgpath); let modules = self.modules.borrow_mut(); - let module = modules.get(&pkgpath).expect(&msg).borrow_mut(); - module.add_global(tpe, Some(AddressSpace::Generic), name) + let module = &modules.get(&pkgpath).expect(&msg).borrow_mut().inner; + module.add_global(tpe, Some(AddressSpace::default()), name) } else { self.module - .add_global(tpe, Some(AddressSpace::Generic), name) + .add_global(tpe, Some(AddressSpace::default()), name) }; global_var.set_alignment(GLOBAL_VAL_ALIGNMENT); global_var.set_initializer(&tpe.const_zero()); global_var.as_pointer_value().into() } /// Get the global runtime context pointer. - fn global_ctx_ptr(&self) -> Self::Value { - if self.no_link { - self.build_call(&ApiFunc::kclvm_context_current.name(), &[]) - } else { - let ctx_ptr = self - .module - .get_global(KCL_CONTEXT_VAR_NAME) - .expect(kcl_error::CONTEXT_VAR_NOT_FOUND_MSG) - .as_pointer_value(); - self.builder.build_load(ctx_ptr, "") - } + fn current_runtime_ctx_ptr(&self) -> Self::Value { + self.builder + .get_insert_block() + .unwrap() + .get_parent() + .unwrap() + .get_first_param() + .expect(kcl_error::CONTEXT_VAR_NOT_FOUND_MSG) + } + /// Get the global evaluation scope pointer. + fn current_scope_ptr(&self) -> Self::Value { + self.builder + .get_insert_block() + .unwrap() + .get_parent() + .unwrap() + .get_nth_param(1) + .expect(kcl_error::CONTEXT_VAR_NOT_FOUND_MSG) } } impl<'ctx> ValueCalculationMethods for LLVMCodeGenContext<'ctx> { /// lhs + rhs fn add(&self, lhs: Self::Value, rhs: Self::Value) -> Self::Value { - self.build_call(&ApiFunc::kclvm_value_op_add.name(), &[lhs, rhs]) + self.build_call( + &ApiFunc::kclvm_value_op_add.name(), + &[self.current_runtime_ctx_ptr(), lhs, rhs], + ) } /// lhs - rhs fn sub(&self, lhs: Self::Value, rhs: Self::Value) -> Self::Value { - self.build_call(&ApiFunc::kclvm_value_op_sub.name(), &[lhs, rhs]) + self.build_call( + &ApiFunc::kclvm_value_op_sub.name(), + &[self.current_runtime_ctx_ptr(), lhs, rhs], + ) } /// lhs * rhs fn mul(&self, lhs: Self::Value, rhs: Self::Value) -> Self::Value { - self.build_call(&ApiFunc::kclvm_value_op_mul.name(), &[lhs, rhs]) + self.build_call( + &ApiFunc::kclvm_value_op_mul.name(), + &[self.current_runtime_ctx_ptr(), lhs, rhs], + ) } /// lhs / rhs fn div(&self, lhs: Self::Value, rhs: Self::Value) -> Self::Value { - self.build_call(&ApiFunc::kclvm_value_op_div.name(), &[lhs, rhs]) + self.build_call( + &ApiFunc::kclvm_value_op_div.name(), + &[self.current_runtime_ctx_ptr(), lhs, rhs], + ) } /// lhs // rhs fn floor_div(&self, lhs: Self::Value, rhs: Self::Value) -> Self::Value { - self.build_call(&ApiFunc::kclvm_value_op_floor_div.name(), &[lhs, rhs]) + self.build_call( + &ApiFunc::kclvm_value_op_floor_div.name(), + &[self.current_runtime_ctx_ptr(), lhs, rhs], + ) } /// lhs % rhs fn r#mod(&self, lhs: Self::Value, rhs: Self::Value) -> Self::Value { - self.build_call(&ApiFunc::kclvm_value_op_mod.name(), &[lhs, rhs]) + self.build_call( + &ApiFunc::kclvm_value_op_mod.name(), + &[self.current_runtime_ctx_ptr(), lhs, rhs], + ) } /// lhs ** rhs fn pow(&self, lhs: Self::Value, rhs: Self::Value) -> Self::Value { - self.build_call(&ApiFunc::kclvm_value_op_pow.name(), &[lhs, rhs]) + self.build_call( + &ApiFunc::kclvm_value_op_pow.name(), + &[self.current_runtime_ctx_ptr(), lhs, rhs], + ) } /// lhs << rhs fn bit_lshift(&self, lhs: Self::Value, rhs: Self::Value) -> Self::Value { - self.build_call(&ApiFunc::kclvm_value_op_bit_lshift.name(), &[lhs, rhs]) + self.build_call( + &ApiFunc::kclvm_value_op_bit_lshift.name(), + &[self.current_runtime_ctx_ptr(), lhs, rhs], + ) } /// lhs >> rhs fn bit_rshift(&self, lhs: Self::Value, rhs: Self::Value) -> Self::Value { - self.build_call(&ApiFunc::kclvm_value_op_bit_rshift.name(), &[lhs, rhs]) + self.build_call( + &ApiFunc::kclvm_value_op_bit_rshift.name(), + &[self.current_runtime_ctx_ptr(), lhs, rhs], + ) } /// lhs & rhs fn bit_and(&self, lhs: Self::Value, rhs: Self::Value) -> Self::Value { - self.build_call(&ApiFunc::kclvm_value_op_bit_and.name(), &[lhs, rhs]) + self.build_call( + &ApiFunc::kclvm_value_op_bit_and.name(), + &[self.current_runtime_ctx_ptr(), lhs, rhs], + ) } /// lhs | rhs fn bit_or(&self, lhs: Self::Value, rhs: Self::Value) -> Self::Value { - self.build_call(&ApiFunc::kclvm_value_op_bit_or.name(), &[lhs, rhs]) + self.build_call( + &ApiFunc::kclvm_value_op_bit_or.name(), + &[self.current_runtime_ctx_ptr(), lhs, rhs], + ) } /// lhs ^ rhs fn bit_xor(&self, lhs: Self::Value, rhs: Self::Value) -> Self::Value { - self.build_call(&ApiFunc::kclvm_value_op_bit_xor.name(), &[lhs, rhs]) + self.build_call( + &ApiFunc::kclvm_value_op_bit_xor.name(), + &[self.current_runtime_ctx_ptr(), lhs, rhs], + ) } /// lhs and rhs fn logic_and(&self, lhs: Self::Value, rhs: Self::Value) -> Self::Value { - self.build_call(&ApiFunc::kclvm_value_logic_and.name(), &[lhs, rhs]) + self.build_call( + &ApiFunc::kclvm_value_logic_and.name(), + &[self.current_runtime_ctx_ptr(), lhs, rhs], + ) } /// lhs or rhs fn logic_or(&self, lhs: Self::Value, rhs: Self::Value) -> Self::Value { - self.build_call(&ApiFunc::kclvm_value_logic_or.name(), &[lhs, rhs]) + self.build_call( + &ApiFunc::kclvm_value_logic_or.name(), + &[self.current_runtime_ctx_ptr(), lhs, rhs], + ) } /// lhs == rhs fn cmp_equal_to(&self, lhs: Self::Value, rhs: Self::Value) -> Self::Value { - self.build_call(&ApiFunc::kclvm_value_cmp_equal_to.name(), &[lhs, rhs]) + self.build_call( + &ApiFunc::kclvm_value_cmp_equal_to.name(), + &[self.current_runtime_ctx_ptr(), lhs, rhs], + ) } /// lhs != rhs fn cmp_not_equal_to(&self, lhs: Self::Value, rhs: Self::Value) -> Self::Value { - self.build_call(&ApiFunc::kclvm_value_cmp_not_equal_to.name(), &[lhs, rhs]) + self.build_call( + &ApiFunc::kclvm_value_cmp_not_equal_to.name(), + &[self.current_runtime_ctx_ptr(), lhs, rhs], + ) } /// lhs > rhs fn cmp_greater_than(&self, lhs: Self::Value, rhs: Self::Value) -> Self::Value { - self.build_call(&ApiFunc::kclvm_value_cmp_greater_than.name(), &[lhs, rhs]) + self.build_call( + &ApiFunc::kclvm_value_cmp_greater_than.name(), + &[self.current_runtime_ctx_ptr(), lhs, rhs], + ) } /// lhs >= rhs fn cmp_greater_than_or_equal(&self, lhs: Self::Value, rhs: Self::Value) -> Self::Value { self.build_call( &ApiFunc::kclvm_value_cmp_greater_than_or_equal.name(), - &[lhs, rhs], + &[self.current_runtime_ctx_ptr(), lhs, rhs], ) } /// lhs < rhs fn cmp_less_than(&self, lhs: Self::Value, rhs: Self::Value) -> Self::Value { - self.build_call(&ApiFunc::kclvm_value_cmp_less_than.name(), &[lhs, rhs]) + self.build_call( + &ApiFunc::kclvm_value_cmp_less_than.name(), + &[self.current_runtime_ctx_ptr(), lhs, rhs], + ) } /// lhs <= rhs fn cmp_less_than_or_equal(&self, lhs: Self::Value, rhs: Self::Value) -> Self::Value { self.build_call( &ApiFunc::kclvm_value_cmp_less_than_or_equal.name(), - &[lhs, rhs], + &[self.current_runtime_ctx_ptr(), lhs, rhs], ) } /// lhs as rhs fn r#as(&self, lhs: Self::Value, rhs: Self::Value) -> Self::Value { - self.build_call(&ApiFunc::kclvm_value_as.name(), &[lhs, rhs]) + self.build_call( + &ApiFunc::kclvm_value_as.name(), + &[self.current_runtime_ctx_ptr(), lhs, rhs], + ) } /// lhs is rhs fn is(&self, lhs: Self::Value, rhs: Self::Value) -> Self::Value { - self.build_call(&ApiFunc::kclvm_value_is.name(), &[lhs, rhs]) + self.build_call( + &ApiFunc::kclvm_value_is.name(), + &[self.current_runtime_ctx_ptr(), lhs, rhs], + ) } /// lhs is not rhs fn is_not(&self, lhs: Self::Value, rhs: Self::Value) -> Self::Value { - self.build_call(&ApiFunc::kclvm_value_is_not.name(), &[lhs, rhs]) + self.build_call( + &ApiFunc::kclvm_value_is_not.name(), + &[self.current_runtime_ctx_ptr(), lhs, rhs], + ) } /// lhs in rhs fn r#in(&self, lhs: Self::Value, rhs: Self::Value) -> Self::Value { - self.build_call(&ApiFunc::kclvm_value_in.name(), &[lhs, rhs]) + self.build_call( + &ApiFunc::kclvm_value_in.name(), + &[self.current_runtime_ctx_ptr(), lhs, rhs], + ) } /// lhs not in rhs fn not_in(&self, lhs: Self::Value, rhs: Self::Value) -> Self::Value { - self.build_call(&ApiFunc::kclvm_value_not_in.name(), &[lhs, rhs]) + self.build_call( + &ApiFunc::kclvm_value_not_in.name(), + &[self.current_runtime_ctx_ptr(), lhs, rhs], + ) } } @@ -640,7 +820,10 @@ impl<'ctx> DerivedValueCalculationMethods for LLVMCodeGenContext<'ctx> { /// Value subscript a[b] #[inline] fn value_subscript(&self, value: Self::Value, item: Self::Value) -> Self::Value { - self.build_call(&ApiFunc::kclvm_value_subscr.name(), &[value, item]) + self.build_call( + &ApiFunc::kclvm_value_subscr.name(), + &[self.current_runtime_ctx_ptr(), value, item], + ) } /// Value is truth function, return i1 value. fn value_is_truthy(&self, value: Self::Value) -> Self::Value { @@ -654,17 +837,26 @@ impl<'ctx> DerivedValueCalculationMethods for LLVMCodeGenContext<'ctx> { /// Value deep copy #[inline] fn value_deep_copy(&self, value: Self::Value) -> Self::Value { - self.build_call(&ApiFunc::kclvm_value_deep_copy.name(), &[value]) + self.build_call( + &ApiFunc::kclvm_value_deep_copy.name(), + &[self.current_runtime_ctx_ptr(), value], + ) } /// value_union unions two collection elements. #[inline] fn value_union(&self, lhs: Self::Value, rhs: Self::Value) { - self.build_void_call(&ApiFunc::kclvm_value_union.name(), &[lhs, rhs]); + self.build_void_call( + &ApiFunc::kclvm_value_union.name(), + &[self.current_runtime_ctx_ptr(), lhs, rhs], + ); } // List get the item using the index. #[inline] fn list_get(&self, list: Self::Value, index: Self::Value) -> Self::Value { - self.build_call(&ApiFunc::kclvm_list_get.name(), &[list, index]) + self.build_call( + &ApiFunc::kclvm_list_get.name(), + &[self.current_runtime_ctx_ptr(), list, index], + ) } // List set the item using the index. #[inline] @@ -682,7 +874,7 @@ impl<'ctx> DerivedValueCalculationMethods for LLVMCodeGenContext<'ctx> { ) -> Self::Value { self.build_call( &ApiFunc::kclvm_value_slice.name(), - &[list, start, stop, step], + &[self.current_runtime_ctx_ptr(), list, start, stop, step], ) } /// Append a item into the list. @@ -698,12 +890,18 @@ impl<'ctx> DerivedValueCalculationMethods for LLVMCodeGenContext<'ctx> { /// Runtime list value pop #[inline] fn list_pop(&self, list: Self::Value) -> Self::Value { - self.build_call(&ApiFunc::kclvm_list_pop.name(), &[list]) + self.build_call( + &ApiFunc::kclvm_list_pop.name(), + &[self.current_runtime_ctx_ptr(), list], + ) } /// Runtime list pop the first value #[inline] fn list_pop_first(&self, list: Self::Value) -> Self::Value { - self.build_call(&ApiFunc::kclvm_list_pop_first.name(), &[list]) + self.build_call( + &ApiFunc::kclvm_list_pop_first.name(), + &[self.current_runtime_ctx_ptr(), list], + ) } /// List clear value. #[inline] @@ -713,12 +911,18 @@ impl<'ctx> DerivedValueCalculationMethods for LLVMCodeGenContext<'ctx> { /// Return number of occurrences of the list value. #[inline] fn list_count(&self, list: Self::Value, item: Self::Value) -> Self::Value { - self.build_call(&ApiFunc::kclvm_list_count.name(), &[list, item]) + self.build_call( + &ApiFunc::kclvm_list_count.name(), + &[self.current_runtime_ctx_ptr(), list, item], + ) } /// Return first index of the list value. Panic if the value is not present. #[inline] fn list_find(&self, list: Self::Value, item: Self::Value) -> Self::Value { - self.build_call(&ApiFunc::kclvm_list_find.name(), &[list, item]) + self.build_call( + &ApiFunc::kclvm_list_find.name(), + &[self.current_runtime_ctx_ptr(), list, item], + ) } /// Insert object before index of the list value. #[inline] @@ -733,27 +937,42 @@ impl<'ctx> DerivedValueCalculationMethods for LLVMCodeGenContext<'ctx> { /// Dict get the value of the key. #[inline] fn dict_get(&self, dict: Self::Value, key: Self::Value) -> Self::Value { - self.build_call(&ApiFunc::kclvm_dict_get_value.name(), &[dict, key]) + self.build_call( + &ApiFunc::kclvm_dict_get_value.name(), + &[self.current_runtime_ctx_ptr(), dict, key], + ) } /// Dict set the value of the key. #[inline] fn dict_set(&self, dict: Self::Value, key: Self::Value, value: Self::Value) { - self.build_void_call(&ApiFunc::kclvm_dict_set_value.name(), &[dict, key, value]) + self.build_void_call( + &ApiFunc::kclvm_dict_set_value.name(), + &[self.current_runtime_ctx_ptr(), dict, key, value], + ) } /// Return all dict keys. #[inline] fn dict_keys(&self, dict: Self::Value) -> Self::Value { - self.build_call(&ApiFunc::kclvm_dict_keys.name(), &[dict]) + self.build_call( + &ApiFunc::kclvm_dict_keys.name(), + &[self.current_runtime_ctx_ptr(), dict], + ) } /// Return all dict values. #[inline] fn dict_values(&self, dict: Self::Value) -> Self::Value { - self.build_call(&ApiFunc::kclvm_dict_values.name(), &[dict]) + self.build_call( + &ApiFunc::kclvm_dict_values.name(), + &[self.current_runtime_ctx_ptr(), dict], + ) } /// Dict clear value. #[inline] fn dict_clear(&self, dict: Self::Value) { - self.build_void_call(&ApiFunc::kclvm_dict_insert_value.name(), &[dict]) + self.build_void_call( + &ApiFunc::kclvm_dict_insert_value.name(), + &[self.current_runtime_ctx_ptr(), dict], + ) } /// Dict pop the value of the key. #[inline] @@ -774,14 +993,24 @@ impl<'ctx> DerivedValueCalculationMethods for LLVMCodeGenContext<'ctx> { key: &str, value: Self::Value, op: i32, - insert_index: i32, + insert_index: Option, ) { let name = self.native_global_string(key, "").into(); let op = self.native_int_value(op); - let insert_index = self.native_int_value(insert_index); + let has_insert_index = insert_index.is_some(); + let has_insert_index = self.native_i8_value(if has_insert_index { 1 } else { 0 }); + let insert_index = self.native_int_value(insert_index.unwrap_or(-1)); self.build_void_call( &ApiFunc::kclvm_dict_insert.name(), - &[dict, name, value, op, insert_index], + &[ + self.current_runtime_ctx_ptr(), + dict, + name, + value, + op, + insert_index, + has_insert_index, + ], ); } @@ -794,13 +1023,23 @@ impl<'ctx> DerivedValueCalculationMethods for LLVMCodeGenContext<'ctx> { key: Self::Value, value: Self::Value, op: i32, - insert_index: i32, + insert_index: Option, ) { let op = self.native_int_value(op); - let insert_index = self.native_int_value(insert_index); + let has_insert_index = insert_index.is_some(); + let has_insert_index = self.native_i8_value(if has_insert_index { 1 } else { 0 }); + let insert_index = self.native_int_value(insert_index.unwrap_or(-1)); self.build_void_call( &ApiFunc::kclvm_dict_insert_value.name(), - &[dict, key, value, op, insert_index], + &[ + self.current_runtime_ctx_ptr(), + dict, + key, + value, + op, + insert_index, + has_insert_index, + ], ); } } @@ -925,6 +1164,7 @@ impl<'ctx> TypeCodeGen for LLVMCodeGenContext<'ctx> {} impl<'ctx> ProgramCodeGen for LLVMCodeGenContext<'ctx> { /// Current package path + #[inline] fn current_pkgpath(&self) -> String { self.pkgpath_stack .borrow_mut() @@ -934,6 +1174,7 @@ impl<'ctx> ProgramCodeGen for LLVMCodeGenContext<'ctx> { } /// Current filename + #[inline] fn current_filename(&self) -> String { self.filename_stack .borrow_mut() @@ -948,17 +1189,14 @@ impl<'ctx> ProgramCodeGen for LLVMCodeGenContext<'ctx> { if pkg_scopes.contains_key(pkgpath) { return; } - let scopes = vec![Rc::new(Scope { - variables: RefCell::new(IndexMap::default()), - closures: RefCell::new(IndexMap::default()), - })]; + let scopes = vec![Rc::new(Scope::default())]; pkg_scopes.insert(String::from(pkgpath), scopes); } let msg = format!("pkgpath {} is not found", pkgpath); // Init all global types including schema and rule let module_list: &Vec = if self.program.pkgs.contains_key(pkgpath) { self.program.pkgs.get(pkgpath).expect(&msg) - } else if pkgpath.starts_with(kclvm::PKG_PATH_PREFIX) + } else if pkgpath.starts_with(kclvm_runtime::PKG_PATH_PREFIX) && self.program.pkgs.contains_key(&pkgpath[1..]) { self.program @@ -1017,10 +1255,7 @@ impl<'ctx> ProgramCodeGen for LLVMCodeGenContext<'ctx> { let mut pkg_scopes = self.pkg_scopes.borrow_mut(); let msg = format!("pkgpath {} is not found", current_pkgpath); let scopes = pkg_scopes.get_mut(¤t_pkgpath).expect(&msg); - let scope = Rc::new(Scope { - variables: RefCell::new(IndexMap::default()), - closures: RefCell::new(IndexMap::default()), - }); + let scope = Rc::new(Scope::default()); scopes.push(scope); } @@ -1049,6 +1284,7 @@ impl<'ctx> LLVMCodeGenContext<'ctx> { program: &'ctx ast::Program, import_names: IndexMap>, no_link: bool, + workdir: String, ) -> LLVMCodeGenContext<'ctx> { LLVMCodeGenContext { context, @@ -1059,20 +1295,24 @@ impl<'ctx> LLVMCodeGenContext<'ctx> { functions: RefCell::new(vec![]), imported: RefCell::new(HashSet::new()), local_vars: RefCell::new(HashSet::new()), + setter_keys: RefCell::new(HashSet::new()), schema_stack: RefCell::new(vec![]), - lambda_stack: RefCell::new(vec![false]), + // 1 denotes the top global main function lambda and 0 denotes the builtin scope. + // Any user-defined lambda scope greater than 1. + lambda_stack: RefCell::new(vec![GLOBAL_LEVEL]), + schema_expr_stack: RefCell::new(vec![]), pkgpath_stack: RefCell::new(vec![String::from(MAIN_PKG_PATH)]), filename_stack: RefCell::new(vec![String::from("")]), target_vars: RefCell::new(vec![String::from("")]), global_strings: RefCell::new(IndexMap::default()), global_vars: RefCell::new(IndexMap::default()), - current_filename: RefCell::new(String::new()), current_line: RefCell::new(0), handler: RefCell::new(Handler::default()), backtrack_meta: RefCell::new(None), import_names, no_link, modules: RefCell::new(HashMap::new()), + workdir, } } @@ -1084,35 +1324,36 @@ impl<'ctx> LLVMCodeGenContext<'ctx> { let tpe = self.value_ptr_type().into_pointer_type(); let void_type = self.context.void_type(); let context_ptr_type = self.context_ptr_type(); - let fn_type = tpe.fn_type(&[context_ptr_type.into()], false); - let void_fn_type = void_type.fn_type(&[context_ptr_type.into()], false); + let scope_ptr_type = self.scope_ptr_type(); + let fn_type = tpe.fn_type(&[context_ptr_type.into(), scope_ptr_type.into()], false); + let void_fn_type = + void_type.fn_type(&[context_ptr_type.into(), scope_ptr_type.into()], false); let has_main_pkg = self.program.pkgs.contains_key(MAIN_PKG_PATH); let function = if self.no_link { let mut modules = self.modules.borrow_mut(); - let name = if has_main_pkg { - MAIN_PKG_PATH.to_string() + let (pkgpath, function_name) = if has_main_pkg { + (MAIN_PKG_PATH.to_string(), MODULE_NAME.to_string()) } else { assert!(self.program.pkgs.len() == 1); - format!( + let pkgpath = format!( "{}{}", - kclvm::PKG_PATH_PREFIX, + kclvm_runtime::PKG_PATH_PREFIX, self.program .pkgs .keys() .next() .expect(kcl_error::INTERNAL_ERROR_MSG) + ); + ( + pkgpath.clone(), + format!( + "${}.{}", + pkgpath_without_prefix!(pkgpath), + PKG_INIT_FUNCTION_SUFFIX + ), ) }; - let module = self.context.create_module(name.as_str()); - let function_name = if has_main_pkg { - MODULE_NAME.to_string() - } else { - format!( - "${}.{}", - pkgpath_without_prefix!(name), - PKG_INIT_FUNCTION_SUFFIX - ) - }; + let module = self.context.create_module(pkgpath.as_str()); let function = module.add_function( // Function name function_name.as_str(), @@ -1120,7 +1361,10 @@ impl<'ctx> LLVMCodeGenContext<'ctx> { if has_main_pkg { fn_type } else { void_fn_type }, None, ); - modules.insert(name.to_string(), RefCell::new(module)); + modules.insert( + pkgpath.to_string(), + RefCell::new(self.create_debug_module(module)), + ); function } else { self.module.add_function( @@ -1142,8 +1386,8 @@ impl<'ctx> LLVMCodeGenContext<'ctx> { .expect(kcl_error::INTERNAL_ERROR_MSG); if self.no_link && !has_main_pkg { for pkgpath in self.program.pkgs.keys() { - let pkgpath = format!("{}{}", kclvm::PKG_PATH_PREFIX, pkgpath); - self.pkgpath_stack.borrow_mut().push(pkgpath.clone()); + let pkgpath = format!("{}{}", kclvm_runtime::PKG_PATH_PREFIX, pkgpath); + self.push_pkgpath(&pkgpath); } } if !self.import_names.is_empty() { @@ -1164,48 +1408,36 @@ impl<'ctx> LLVMCodeGenContext<'ctx> { &[ctx_value, import_names], ); } - // Store the runtime context to global - if !self.no_link { - let global_ctx = self.module.add_global( - context_ptr_type, - Some(AddressSpace::Generic), - KCL_CONTEXT_VAR_NAME, - ); - global_ctx.set_alignment(GLOBAL_VAL_ALIGNMENT); - global_ctx.set_initializer(&context_ptr_type.const_zero()); - self.builder - .build_store(global_ctx.as_pointer_value(), ctx_value); - } + // Main package if self.no_link && !has_main_pkg { // When compiling a pkgpath separately, only one pkgpath is required in the AST Program assert!(self.program.pkgs.len() == 1); // pkgs may not contains main pkg in no link mode for (pkgpath, modules) in &self.program.pkgs { - let pkgpath = format!("{}{}", kclvm::PKG_PATH_PREFIX, pkgpath); - self.pkgpath_stack.borrow_mut().push(pkgpath.clone()); + let pkgpath = format!("{}{}", kclvm_runtime::PKG_PATH_PREFIX, pkgpath); + self.push_pkgpath(&pkgpath); // Init all builtin functions. self.init_scope(pkgpath.as_str()); - // Compile the ast module in the pkgpath. - for ast_module in modules { - { - self.filename_stack - .borrow_mut() - .push(ast_module.filename.clone()); - } - self.compile_module_import_and_types(ast_module) - } - for ast_module in modules { - { - self.filename_stack - .borrow_mut() - .push(ast_module.filename.clone()); - } - self.walk_stmts_except_import(&ast_module.body) - .expect(kcl_error::COMPILE_ERROR_MSG); - } + self.compile_ast_modules(modules); } self.ret_void(); } else { + // Set the kcl module path to the runtime context only in the main package. + self.build_void_call( + &ApiFunc::kclvm_context_set_kcl_modpath.name(), + &[ + self.current_runtime_ctx_ptr(), + self.native_global_string_value(&self.program.root), + ], + ); + // Set the kcl workdir to the runtime context + self.build_void_call( + &ApiFunc::kclvm_context_set_kcl_workdir.name(), + &[ + self.current_runtime_ctx_ptr(), + self.native_global_string_value(&self.workdir), + ], + ); // Init scope and all builtin functions self.init_scope(MAIN_PKG_PATH); let main_pkg_modules = self @@ -1213,16 +1445,7 @@ impl<'ctx> LLVMCodeGenContext<'ctx> { .pkgs .get(MAIN_PKG_PATH) .expect(kcl_error::INTERNAL_ERROR_MSG); - // Compile the AST Program to LLVM IR - for ast_module in main_pkg_modules { - { - self.filename_stack - .borrow_mut() - .push(ast_module.filename.clone()); - } - self.walk_module(ast_module) - .expect(kcl_error::COMPILE_ERROR_MSG); - } + self.compile_ast_modules(main_pkg_modules); // Get the JSON string including all global variables let json_str_value = self.globals_to_json_str(); // Build a return in the current block @@ -1236,24 +1459,51 @@ impl<'ctx> LLVMCodeGenContext<'ctx> { let modules = self.modules.borrow_mut(); for (index, (_, module)) in modules.iter().enumerate() { let path = if modules.len() == 1 { - format!("{}.ll", path_str) + format!("{}{}", path_str, OBJECT_FILE_SUFFIX) } else { - format!("{}_{}.ll", path_str, index) + format!("{}_{}{}", path_str, index, OBJECT_FILE_SUFFIX) }; let path = std::path::Path::new(&path); - module - .borrow_mut() - .print_to_file(path) - .expect(kcl_error::CODE_GEN_ERROR_MSG); + // Build LLVM module to a `.o` object file. + self.build_object_file(&module.borrow().inner, path)?; } } else { - self.module - .print_to_file(path) - .expect(kcl_error::CODE_GEN_ERROR_MSG); + // Build LLVM module to a `.o` object file. + self.build_object_file(&self.module, path)?; } } Ok(()) } + + /// Build LLVM module to a `.o` object file. + /// + /// TODO: WASM and cross platform build. + fn build_object_file( + self: &LLVMCodeGenContext<'ctx>, + module: &Module, + path: &Path, + ) -> Result<(), LLVMString> { + let triple = inkwell::targets::TargetMachine::get_default_triple(); + let target = inkwell::targets::Target::from_triple(&triple)?; + // Convert LLVM module to ll file. + module.print_to_file(path)?; + let buf = MemoryBuffer::create_from_file(path)?; + let module = self.context.create_module_from_ir(buf)?; + // Read ll file and use target machine to generate native object file. + let target_machine = target + .create_target_machine( + &triple, + "", + "", + // We do not enable any optimization, so that + // the sum of compile time and run time is as small as possible + inkwell::OptimizationLevel::None, + RelocMode::PIC, + CodeModel::Default, + ) + .expect(kcl_error::CODE_GEN_ERROR_MSG); + target_machine.write_to_file(&module, FileType::Object, path) + } } impl<'ctx> LLVMCodeGenContext<'ctx> { @@ -1327,6 +1577,12 @@ impl<'ctx> LLVMCodeGenContext<'ctx> { i8_type.const_int(v as u64, false) } + /// Get LLVM i8 zero value + pub fn native_i8_value(&self, v: i8) -> BasicValueEnum<'ctx> { + let i8_type = self.context.i8_type(); + i8_type.const_int(v as u64, false).into() + } + /// Construct a LLVM int value using i32 pub fn native_int_value(&self, v: i32) -> BasicValueEnum<'ctx> { let i32_type = self.context.i32_type(); @@ -1341,17 +1597,42 @@ impl<'ctx> LLVMCodeGenContext<'ctx> { let pkgpath = self.current_pkgpath(); let msg = format!("pkgpath {} is not found", pkgpath); let modules = self.modules.borrow_mut(); - let module = modules.get(&pkgpath).expect(&msg).borrow_mut(); - module.add_global(tpe, Some(AddressSpace::Generic), name) + let module = &modules.get(&pkgpath).expect(&msg).borrow_mut().inner; + module.add_global(tpe, Some(AddressSpace::default()), name) } else { self.module - .add_global(tpe, Some(AddressSpace::Generic), name) + .add_global(tpe, Some(AddressSpace::default()), name) }; global_var.set_alignment(GLOBAL_VAL_ALIGNMENT); global_var.set_initializer(&tpe.const_zero()); global_var.as_pointer_value() } + /// Append a scalar value into the scope. + pub fn add_scalar(&self, scalar: BasicValueEnum<'ctx>, is_schema: bool) { + let current_pkgpath = self.current_pkgpath(); + let mut pkg_scopes = self.pkg_scopes.borrow_mut(); + let scopes = pkg_scopes + .get_mut(¤t_pkgpath) + .unwrap_or_else(|| panic!("pkgpath {} is not found", current_pkgpath)); + if let Some(last) = scopes.last_mut() { + let mut scalars = last.scalars.borrow_mut(); + // TODO: To avoid conflicts, only the last schema scalar expressions are allowed. + let mut schema_scalar_idx = last.schema_scalar_idx.borrow_mut(); + if is_schema { + // Remove the last schema scalar. + if *schema_scalar_idx < scalars.len() { + scalars.remove(*schema_scalar_idx); + } + // Override the last schema scalar. + scalars.push(scalar); + *schema_scalar_idx = scalars.len() - 1; + } else { + scalars.push(scalar); + } + } + } + /// Append a variable into the scope pub fn add_variable(&self, name: &str, pointer: PointerValue<'ctx>) { let current_pkgpath = self.current_pkgpath(); @@ -1366,16 +1647,28 @@ impl<'ctx> LLVMCodeGenContext<'ctx> { } } - /// Store the variable named `name` with `value` from the current scope, return false when not found - pub fn store_variable_in_current_scope(&self, name: &str, value: BasicValueEnum<'ctx>) -> bool { + /// Store the argument named `name` in the current scope. + pub(crate) fn store_argument_in_current_scope(&self, name: &str) { // Find argument name in the scope let current_pkgpath = self.current_pkgpath(); let mut pkg_scopes = self.pkg_scopes.borrow_mut(); let msg = format!("pkgpath {} is not found", current_pkgpath); let scopes = pkg_scopes.get_mut(¤t_pkgpath).expect(&msg); let index = scopes.len() - 1; - let variables_mut = scopes[index].variables.borrow_mut(); - if let Some(var) = variables_mut.get(&name.to_string()) { + let mut arguments_mut = scopes[index].arguments.borrow_mut(); + arguments_mut.insert(name.to_string()); + } + + /// Store the variable named `name` with `value` from the current scope, return false when not found + pub fn store_variable_in_current_scope(&self, name: &str, value: BasicValueEnum<'ctx>) -> bool { + // Find argument name in the scope + let current_pkgpath = self.current_pkgpath(); + let pkg_scopes = self.pkg_scopes.borrow(); + let msg = format!("pkgpath {} is not found", current_pkgpath); + let scopes = pkg_scopes.get(¤t_pkgpath).expect(&msg); + let index = scopes.len() - 1; + let variables = scopes[index].variables.borrow(); + if let Some(var) = variables.get(&name.to_string()) { self.builder.build_store(*var, value); return true; } @@ -1386,13 +1679,13 @@ impl<'ctx> LLVMCodeGenContext<'ctx> { pub fn store_variable(&self, name: &str, value: BasicValueEnum<'ctx>) -> bool { // Find argument name in the scope let current_pkgpath = self.current_pkgpath(); - let mut pkg_scopes = self.pkg_scopes.borrow_mut(); + let pkg_scopes = self.pkg_scopes.borrow(); let msg = format!("pkgpath {} is not found", current_pkgpath); - let scopes = pkg_scopes.get_mut(¤t_pkgpath).expect(&msg); + let scopes = pkg_scopes.get(¤t_pkgpath).expect(&msg); for i in 0..scopes.len() { let index = scopes.len() - i - 1; - let variables_mut = scopes[index].variables.borrow_mut(); - if let Some(var) = variables_mut.get(&name.to_string()) { + let variables = scopes[index].variables.borrow(); + if let Some(var) = variables.get(&name.to_string()) { self.builder.build_store(*var, value); return true; } @@ -1400,27 +1693,82 @@ impl<'ctx> LLVMCodeGenContext<'ctx> { false } - /// Resolve variable in scope, return false when not found + /// Resolve variable in scope, return false when not found. + #[inline] pub fn resolve_variable(&self, name: &str) -> bool { + self.resolve_variable_level(name).is_some() + } + + /// Resolve variable level in scope, return None when not found. + pub fn resolve_variable_level(&self, name: &str) -> Option { // Find argument name in the scope let current_pkgpath = self.current_pkgpath(); - let mut pkg_scopes = self.pkg_scopes.borrow_mut(); + let pkg_scopes = self.pkg_scopes.borrow(); let msg = format!("pkgpath {} is not found", current_pkgpath); - let scopes = pkg_scopes.get_mut(¤t_pkgpath).expect(&msg); - let mut existed = false; + let scopes = pkg_scopes.get(¤t_pkgpath).expect(&msg); + let mut level = None; for i in 0..scopes.len() { let index = scopes.len() - i - 1; - let variables_mut = scopes[index].variables.borrow_mut(); - if variables_mut.get(&name.to_string()).is_some() { - existed = true; + let variables = scopes[index].variables.borrow(); + let arguments = scopes[index].arguments.borrow(); + if variables.get(name).is_some() { + level = Some(index); + break; + } + if arguments.contains(name) { + level = Some(index); break; } } - existed + level + } + + /// Append a variable or update the existed closure variable within the current scope. + pub fn add_or_update_local_variable_within_scope( + &self, + name: &str, + value: Option>, + ) { + let current_pkgpath = self.current_pkgpath(); + let mut pkg_scopes = self.pkg_scopes.borrow_mut(); + let msg = format!("pkgpath {} is not found", current_pkgpath); + let scopes = pkg_scopes.get_mut(¤t_pkgpath).expect(&msg); + let index = scopes.len() - 1; + if let Some(scope) = scopes.last_mut() { + let mut variables_mut = scope.variables.borrow_mut(); + let mut uninitialized = scope.uninitialized.borrow_mut(); + if value.is_none() { + uninitialized.insert(name.to_string()); + } else { + uninitialized.remove(name); + } + match variables_mut.get(&name.to_string()) { + // If the local variable is found, store the new value for the variable. + // We cannot update rule/lambda/schema arguments because they are read-only. + Some(ptr) if index > GLOBAL_LEVEL => { + if let Some(value) = value { + self.builder.build_store(*ptr, value); + } + } + _ => { + let ptr = self.builder.build_alloca(self.value_ptr_type(), name); + if let Some(value) = value { + self.builder.build_store(ptr, value); + } + // Store the value for the variable and add the variable into the current scope. + variables_mut.insert(name.to_string(), ptr); + } + }; + } } /// Append a variable or update the existed variable - pub fn add_or_update_global_variable(&self, name: &str, value: BasicValueEnum<'ctx>) { + pub fn add_or_update_global_variable( + &self, + name: &str, + value: BasicValueEnum<'ctx>, + save_scope: bool, + ) { // Find argument name in the scope let current_pkgpath = self.current_pkgpath(); let mut pkg_scopes = self.pkg_scopes.borrow_mut(); @@ -1428,9 +1776,21 @@ impl<'ctx> LLVMCodeGenContext<'ctx> { let scopes = pkg_scopes.get_mut(¤t_pkgpath).expect(&msg); let mut existed = false; if let Some(last) = scopes.last_mut() { - let variables_mut = last.variables.borrow_mut(); - if let Some(var) = variables_mut.get(&name.to_string()) { + let variables = last.variables.borrow(); + if let Some(var) = variables.get(&name.to_string()) { self.builder.build_store(*var, value); + if save_scope { + self.build_void_call( + &ApiFunc::kclvm_scope_set.name(), + &[ + self.current_runtime_ctx_ptr(), + self.current_scope_ptr(), + self.native_global_string(¤t_pkgpath, "").into(), + self.native_global_string(name, "").into(), + value, + ], + ); + } existed = true; } } @@ -1441,6 +1801,18 @@ impl<'ctx> LLVMCodeGenContext<'ctx> { let var_name = format!("${}.${}", pkgpath_without_prefix!(pkgpath), name); let pointer = self.new_global_kcl_value_ptr(&var_name); self.builder.build_store(pointer, value); + if save_scope { + self.build_void_call( + &ApiFunc::kclvm_scope_set.name(), + &[ + self.current_runtime_ctx_ptr(), + self.current_scope_ptr(), + self.native_global_string(¤t_pkgpath, "").into(), + self.native_global_string(name, "").into(), + value, + ], + ); + } if !variables.contains_key(name) { variables.insert(name.to_string(), pointer); } @@ -1490,7 +1862,7 @@ impl<'ctx> LLVMCodeGenContext<'ctx> { self.builder.position_at_end(then_block); let target_attr = self .target_vars - .borrow_mut() + .borrow() .last() .expect(kcl_error::INTERNAL_ERROR_MSG) .clone(); @@ -1517,6 +1889,7 @@ impl<'ctx> LLVMCodeGenContext<'ctx> { self.build_call( &ApiFunc::kclvm_schema_get_value.name(), &[ + self.current_runtime_ctx_ptr(), schema_value, string_ptr_value, config, @@ -1549,16 +1922,18 @@ impl<'ctx> LLVMCodeGenContext<'ctx> { /// Get the variable value named `name` from the scope named `pkgpath`, return Err when not found pub fn get_variable_in_pkgpath(&self, name: &str, pkgpath: &str) -> CompileResult<'ctx> { - let pkg_scopes = self.pkg_scopes.borrow_mut(); - let pkgpath = if !pkgpath.starts_with(kclvm::PKG_PATH_PREFIX) && pkgpath != MAIN_PKG_PATH { - format!("{}{}", kclvm::PKG_PATH_PREFIX, pkgpath) - } else { - pkgpath.to_string() - }; + let pkg_scopes = self.pkg_scopes.borrow(); + let pkgpath = + if !pkgpath.starts_with(kclvm_runtime::PKG_PATH_PREFIX) && pkgpath != MAIN_PKG_PATH { + format!("{}{}", kclvm_runtime::PKG_PATH_PREFIX, pkgpath) + } else { + pkgpath.to_string() + }; let mut result = Err(kcl_error::KCLError { message: format!("name '{}' is not defined", name), ty: kcl_error::KCLErrorType::Compile, }); + let is_in_schema = self.is_in_schema(); // System module if builtin::STANDARD_SYSTEM_MODULE_NAMES_WITH_AT.contains(&pkgpath.as_str()) { let pkgpath = &pkgpath[1..]; @@ -1571,8 +1946,8 @@ impl<'ctx> LLVMCodeGenContext<'ctx> { let value = if pkgpath == builtin::system_module::UNITS && builtin::system_module::UNITS_FIELD_NAMES.contains(&name) { - let value_float: f64 = kclvm::f64_unit_value(name); - let value_int: u64 = kclvm::u64_unit_value(name); + let value_float: f64 = kclvm_runtime::f64_unit_value(name); + let value_int: u64 = kclvm_runtime::u64_unit_value(name); if value_int != 1 { self.int_value(value_int as i64) } else { @@ -1583,14 +1958,21 @@ impl<'ctx> LLVMCodeGenContext<'ctx> { // Convert the function to a i64 pointer to store it into the function value. let lambda_fn_ptr = self.builder.build_bitcast( function.as_global_value().as_pointer_value(), - self.context.i64_type().ptr_type(AddressSpace::Generic), + self.context.i64_type().ptr_type(AddressSpace::default()), "", ); - let name = self.native_global_string("", "").into(); + let func_name = function.get_name().to_str().unwrap(); + let func_name_ptr = self.native_global_string(func_name, func_name).into(); let none_value = self.none_value(); self.build_call( &ApiFunc::kclvm_value_Function.name(), - &[lambda_fn_ptr, none_value, name], + &[ + self.current_runtime_ctx_ptr(), + lambda_fn_ptr, + none_value, + func_name_ptr, + self.native_i8_zero().into(), + ], ) }; Ok(value) @@ -1600,7 +1982,7 @@ impl<'ctx> LLVMCodeGenContext<'ctx> { let null_fn_ptr = self .context .i64_type() - .ptr_type(AddressSpace::Generic) + .ptr_type(AddressSpace::default()) .const_zero() .into(); let name = format!("{}.{}", &pkgpath[1..], name); @@ -1608,41 +1990,96 @@ impl<'ctx> LLVMCodeGenContext<'ctx> { let none_value = self.none_value(); return Ok(self.build_call( &ApiFunc::kclvm_value_Function.name(), - &[null_fn_ptr, none_value, name], + &[ + self.current_runtime_ctx_ptr(), + null_fn_ptr, + none_value, + name, + self.native_i8(1).into(), + ], )); // User pkgpath } else { + // Global or local variables. let scopes = pkg_scopes .get(&pkgpath) .unwrap_or_else(|| panic!("package {} is not found", pkgpath)); // Scopes 0 is builtin scope, Scopes 1 is the global scope, Scopes 2~ are the local scopes let scopes_len = scopes.len(); - let last_scopes = scopes.last().expect(kcl_error::INTERNAL_ERROR_MSG); - let mut closures_mut = last_scopes.closures.borrow_mut(); for i in 0..scopes_len { let index = scopes_len - i - 1; - let variables_mut = scopes[index].variables.borrow_mut(); - if let Some(var) = variables_mut.get(&name.to_string()) { - // Closure vars, 2 denotes the builtin scope and the global scope + let variables = scopes[index].variables.borrow(); + // Skip uninitialized pointer value, which may cause NPE. + let uninitialized = scopes[index].uninitialized.borrow(); + if let Some(var) = variables.get(&name.to_string()) { + // Closure vars, 2 denotes the builtin scope and the global scope, here is a closure scope. let value = if i >= 1 && i < scopes_len - 2 { - closures_mut.insert(name.to_string(), *var); - let variables = last_scopes.variables.borrow(); - let ptr = variables.get(value::LAMBDA_CLOSURE); - // Lambda closure - match ptr { - Some(ptr) => { - let closure_map = self.builder.build_load(*ptr, ""); - let string_ptr_value = self.native_global_string(name, "").into(); - self.build_call( - &ApiFunc::kclvm_dict_get_value.name(), - &[closure_map, string_ptr_value], - ) + let last_lambda_scope = self.last_lambda_scope(); + // Local scope variable + if index >= last_lambda_scope { + self.builder.build_load(*var, name) + } else { + // Outer lambda closure + let variables = scopes[last_lambda_scope].variables.borrow(); + let ptr = variables.get(value::LAMBDA_CLOSURE); + // Lambda closure + match ptr { + Some(ptr) => { + let closure_map = self.builder.build_load(*ptr, ""); + let string_ptr_value = + self.native_global_string(name, "").into(); + // Not a closure, maybe a local variable + self.build_call( + &ApiFunc::kclvm_dict_get_value.name(), + &[ + self.current_runtime_ctx_ptr(), + closure_map, + string_ptr_value, + ], + ) + } + None => self.builder.build_load(*var, name), } - // Nest comp for - None => self.builder.build_load(*var, name), } } else { - self.builder.build_load(*var, name) + // Not a local schema attribute or a global type. + let key = format!("{}.{name}", pkgpath_without_prefix!(pkgpath)); + let is_in_lambda = self.is_in_lambda(); + if !is_in_schema + && !is_in_lambda + && index <= GLOBAL_LEVEL + && !self.local_vars.borrow().contains(name) + && self.setter_keys.borrow().contains(&key) + { + let target = self + .target_vars + .borrow_mut() + .last() + .expect(kcl_error::INTERNAL_ERROR_MSG) + .clone(); + self.build_call( + &ApiFunc::kclvm_scope_get.name(), + &[ + // Runtime context ptr + self.current_runtime_ctx_ptr(), + // Scope ptr + self.current_scope_ptr(), + // Package path + self.native_global_string(&pkgpath, "").into(), + // Attribute name + self.native_global_string(name, "").into(), + // Target + self.native_global_string(&target, "").into(), + // Default + self.builder.build_load(*var, name), + ], + ) + } else { + if uninitialized.contains(name) { + continue; + } + self.builder.build_load(*var, name) + } }; result = Ok(value); break; @@ -1651,21 +2088,17 @@ impl<'ctx> LLVMCodeGenContext<'ctx> { match result { Ok(_) => result, Err(ref err) => { - let is_in_schema = self.schema_stack.borrow().len() > 0; if !is_in_schema { let mut handler = self.handler.borrow_mut(); - handler.add_compile_error( - &err.message, - Position { - filename: self.current_filename().clone(), - line: self.current_line.borrow().clone(), - column: None, - }, - ); - handler.abort_if_errors() - } else { - result + let pos = Position { + filename: self.current_filename(), + line: *self.current_line.borrow(), + column: None, + }; + handler.add_compile_error(&err.message, (pos.clone(), pos)); + handler.abort_if_any_errors() } + result } } } @@ -1677,12 +2110,13 @@ impl<'ctx> LLVMCodeGenContext<'ctx> { name: &str, pkgpath: &str, ) -> CompileResult<'ctx> { - let ext_pkgpath = - if !pkgpath.starts_with(kclvm::PKG_PATH_PREFIX) && pkgpath != kclvm::MAIN_PKG_PATH { - format!("{}{}", kclvm::PKG_PATH_PREFIX, pkgpath) - } else { - pkgpath.to_string() - }; + let ext_pkgpath = if !pkgpath.starts_with(kclvm_runtime::PKG_PATH_PREFIX) + && pkgpath != kclvm_runtime::MAIN_PKG_PATH + { + format!("{}{}", kclvm_runtime::PKG_PATH_PREFIX, pkgpath) + } else { + pkgpath.to_string() + }; // System module or plugin module if builtin::STANDARD_SYSTEM_MODULE_NAMES_WITH_AT.contains(&ext_pkgpath.as_str()) || ext_pkgpath.starts_with(plugin::PLUGIN_PREFIX_WITH_AT) @@ -1692,9 +2126,9 @@ impl<'ctx> LLVMCodeGenContext<'ctx> { // User module external variable let external_var_name = format!("${}.${}", pkgpath_without_prefix!(ext_pkgpath), name); let current_pkgpath = self.current_pkgpath(); - let modules = self.modules.borrow_mut(); + let modules = self.modules.borrow(); let msg = format!("pkgpath {} is not found", current_pkgpath); - let module = modules.get(¤t_pkgpath).expect(&msg).borrow_mut(); + let module = &modules.get(¤t_pkgpath).expect(&msg).borrow().inner; let tpe = self.value_ptr_type(); let mut global_var_maps = self.global_vars.borrow_mut(); let pkgpath = self.current_pkgpath(); @@ -1707,7 +2141,7 @@ impl<'ctx> LLVMCodeGenContext<'ctx> { *ptr } else { let global_var = - module.add_global(tpe, Some(AddressSpace::Generic), &external_var_name); + module.add_global(tpe, Some(AddressSpace::default()), &external_var_name); global_var.set_alignment(GLOBAL_VAL_ALIGNMENT); global_var.set_linkage(Linkage::External); let ptr = global_var.as_pointer_value(); @@ -1718,46 +2152,245 @@ impl<'ctx> LLVMCodeGenContext<'ctx> { Ok(value) } - /// Get closure dict in the current scope. - pub(crate) fn get_closure_dict_in_current_scope(&self) -> BasicValueEnum<'ctx> { - let is_in_schema = self.schema_stack.borrow().len() > 0; - // Get closures in the current scope - let dict_value = self.dict_value(); - { + /// Get closure map in the current inner scope. + pub(crate) fn get_current_inner_scope_variable_map(&self) -> BasicValueEnum<'ctx> { + let var_map = { + let last_lambda_scope = self.last_lambda_scope(); + // Get variable map in the current scope. let pkgpath = self.current_pkgpath(); let pkgpath = if !pkgpath.starts_with(PKG_PATH_PREFIX) && pkgpath != MAIN_PKG_PATH { format!("{}{}", PKG_PATH_PREFIX, pkgpath) } else { pkgpath }; - let pkg_scopes = self.pkg_scopes.borrow_mut(); + let pkg_scopes = self.pkg_scopes.borrow(); let scopes = pkg_scopes .get(&pkgpath) .unwrap_or_else(|| panic!("package {} is not found", pkgpath)); - let closures_mut = scopes - .last() - .expect(kcl_error::INTERNAL_ERROR_MSG) - .closures - .borrow_mut(); - let variables_mut = scopes - .last() - .expect(kcl_error::INTERNAL_ERROR_MSG) - .variables - .borrow_mut(); - for (key, ptr) in &*closures_mut { - if variables_mut.contains_key(key) { - let value = self.builder.build_load(*ptr, ""); - self.dict_insert_override_item(dict_value, key.as_str(), value); + let current_scope = scopes.len() - 1; + // Get last closure map. + let var_map = if current_scope >= last_lambda_scope && last_lambda_scope > 0 { + let variables = scopes[last_lambda_scope].variables.borrow(); + let ptr = variables.get(value::LAMBDA_CLOSURE); + let var_map = match ptr { + Some(ptr) => self.builder.build_load(*ptr, ""), + None => self.dict_value(), + }; + // Get variable map including schema in the current scope. + for i in last_lambda_scope..current_scope + 1 { + let variables = scopes + .get(i) + .expect(kcl_error::INTERNAL_ERROR_MSG) + .variables + .borrow(); + for (key, ptr) in &*variables { + if key != value::LAMBDA_CLOSURE { + let value = self.builder.build_load(*ptr, ""); + self.dict_insert_override_item(var_map, key.as_str(), value); + } + } } + var_map + } else { + self.dict_value() + }; + var_map + }; + // Capture schema `self` closure. + if self.is_in_schema() { + for schema_closure_name in value::SCHEMA_VARIABLE_LIST { + let value = self + .get_variable(schema_closure_name) + .expect(kcl_error::INTERNAL_ERROR_MSG); + self.dict_insert_override_item(var_map, schema_closure_name, value); } } - if is_in_schema { - let schema_value = self - .get_variable(value::SCHEMA_SELF_NAME) - .expect(kcl_error::INTERNAL_ERROR_MSG); - self.dict_insert_override_item(dict_value, value::SCHEMA_SELF_NAME, schema_value); + var_map + } + + #[inline] + pub(crate) fn push_pkgpath(&self, pkgpath: &str) { + self.pkgpath_stack.borrow_mut().push(pkgpath.to_string()); + utils::update_ctx_pkgpath(self, pkgpath); + } + + #[inline] + pub(crate) fn pop_pkgpath(&self) { + if let Some(pkgpath) = self.pkgpath_stack.borrow_mut().pop() { + utils::update_ctx_pkgpath(self, &pkgpath); } - dict_value + } + + /// Load value from name. + pub fn load_value(&self, pkgpath: &str, names: &[&str]) -> CompileResult<'ctx> { + if names.is_empty() { + return Err(kcl_error::KCLError { + message: "error: read value from empty name".to_string(), + ty: kcl_error::KCLErrorType::Compile, + }); + } + let name = names[0]; + if names.len() == 1 { + self.load_name(name) + } else { + let mut value = if pkgpath.is_empty() { + self.load_name(name) + } else { + self.ok_result() + } + .expect(kcl_error::INTERNAL_ERROR_MSG); + for i in 0..names.len() - 1 { + let attr = names[i + 1]; + if i == 0 && !pkgpath.is_empty() { + value = if self.no_link { + self.get_external_variable_in_pkgpath(attr, pkgpath) + } else { + self.get_variable_in_pkgpath(attr, pkgpath) + } + .expect(kcl_error::INTERNAL_ERROR_MSG) + } else { + let attr = self.native_global_string(attr, "").into(); + value = self.build_call( + &ApiFunc::kclvm_value_load_attr.name(), + &[self.current_runtime_ctx_ptr(), value, attr], + ); + } + } + Ok(value) + } + } + + /// Load global or local value from name. + pub fn load_name(&self, name: &str) -> CompileResult<'ctx> { + match ( + self.is_in_schema(), + self.is_in_lambda(), + self.is_local_var(name), + ) { + // Get from local or global scope + (false, _, _) | (_, _, true) => self.get_variable(name), + // Get variable from the current schema scope. + (true, false, false) => self.get_variable_in_schema(name), + // Get from local scope including lambda arguments, lambda variables, + // loop variables or global variables. + (true, true, _) => + // Get from local scope including lambda arguments, lambda variables, + // loop variables or global variables. + { + match self.resolve_variable_level(name) { + // Closure variable or local variables + Some(level) if level > GLOBAL_LEVEL => self.get_variable(name), + // Schema closure or global variables + _ => self.get_variable_in_schema(name), + } + } + } + } + + /// Load value from assignment target. + pub fn load_target(&self, target: &'ctx ast::Target) -> CompileResult<'ctx> { + let mut value = self.load_name(target.get_name())?; + for path in &target.paths { + value = self.load_target_path(value, path)?; + } + Ok(value) + } + + /// Load value from assignment target path. + pub fn load_target_path( + &self, + value: BasicValueEnum<'ctx>, + path: &'ctx ast::MemberOrIndex, + ) -> CompileResult<'ctx> { + Ok(match path { + ast::MemberOrIndex::Member(member) => { + let attr = &member.node; + let attr = self.native_global_string(attr, "").into(); + self.build_call( + &ApiFunc::kclvm_value_load_attr.name(), + &[self.current_runtime_ctx_ptr(), value, attr], + ) + } + ast::MemberOrIndex::Index(index) => { + let index = self.walk_expr(index)?; + self.build_call( + &ApiFunc::kclvm_value_subscr.name(), + &[self.current_runtime_ctx_ptr(), value, index], + ) + } + }) + } + + pub fn store_target_path( + &self, + value: BasicValueEnum<'ctx>, + path: &'ctx ast::MemberOrIndex, + right_value: BasicValueEnum<'ctx>, + ) -> CompileResult<'ctx> { + match path { + ast::MemberOrIndex::Member(member) => { + let attr = &member.node; + let attr = self.native_global_string(attr, "").into(); + self.build_void_call( + &ApiFunc::kclvm_dict_set_value.name(), + &[self.current_runtime_ctx_ptr(), value, attr, right_value], + ); + } + ast::MemberOrIndex::Index(index) => { + let index = self.walk_expr(index)?; + self.build_void_call( + &ApiFunc::kclvm_value_subscr_set.name(), + &[self.current_runtime_ctx_ptr(), value, index, right_value], + ); + } + } + self.ok_result() + } + + /// Push a lambda definition scope into the lambda stack + #[inline] + pub fn push_lambda(&self, scope: usize) { + self.lambda_stack.borrow_mut().push(scope); + } + + /// Pop a lambda definition scope. + #[inline] + pub fn pop_lambda(&self) { + self.lambda_stack.borrow_mut().pop(); + } + + #[inline] + pub fn is_in_lambda(&self) -> bool { + *self + .lambda_stack + .borrow() + .last() + .expect(kcl_error::INTERNAL_ERROR_MSG) + > GLOBAL_LEVEL + } + + #[inline] + pub fn last_lambda_scope(&self) -> usize { + *self + .lambda_stack + .borrow() + .last() + .expect(kcl_error::INTERNAL_ERROR_MSG) + } + + #[inline] + pub fn is_in_schema(&self) -> bool { + self.schema_stack.borrow().len() > 0 + } + + #[inline] + pub fn is_in_schema_expr(&self) -> bool { + self.schema_expr_stack.borrow().len() > 0 + } + + #[inline] + pub fn is_local_var(&self, name: &str) -> bool { + self.local_vars.borrow().contains(name) } /// Push a function call frame into the function stack @@ -1785,24 +2418,45 @@ impl<'ctx> LLVMCodeGenContext<'ctx> { /// Plan globals to a json string pub fn globals_to_json_str(&self) -> BasicValueEnum<'ctx> { let current_pkgpath = self.current_pkgpath(); - let mut pkg_scopes = self.pkg_scopes.borrow_mut(); - let msg = format!("pkgpath {} is not found", current_pkgpath); - let scopes = pkg_scopes.get_mut(¤t_pkgpath).expect(&msg); - let globals = scopes - .last_mut() - .expect(kcl_error::INTERNAL_ERROR_MSG) - .variables - .borrow_mut(); + let pkg_scopes = self.pkg_scopes.borrow(); + let scopes = pkg_scopes + .get(¤t_pkgpath) + .unwrap_or_else(|| panic!("pkgpath {} is not found", current_pkgpath)); + // The global scope. + let scope = scopes.last().expect(kcl_error::INTERNAL_ERROR_MSG); + let scalars = scope.scalars.borrow(); + let globals = scope.variables.borrow(); + // Construct a plan object. let global_dict = self.dict_value(); + // Plan empty dict result. + if scalars.is_empty() && globals.is_empty() { + return self.build_call( + &ApiFunc::kclvm_value_plan_to_json.name(), + &[self.current_runtime_ctx_ptr(), global_dict], + ); + } + // Deal scalars + for scalar in scalars.iter() { + self.dict_safe_insert(global_dict, SCALAR_KEY, *scalar, 0, None); + } + // Deal global variables for (name, ptr) in globals.iter() { - // Omit private variables and function variables - if name.starts_with(kclvm::KCL_PRIVATE_VAR_PREFIX) { - continue; - } let value = self.builder.build_load(*ptr, ""); - self.dict_safe_insert(global_dict, name.as_str(), value, 0, -1); + let value_dict = self.dict_value(); + self.dict_safe_insert(value_dict, name.as_str(), value, 0, None); + self.dict_safe_insert(global_dict, SCALAR_KEY, value_dict, 0, None); } - self.build_call(&ApiFunc::kclvm_value_plan_to_json.name(), &[global_dict]) + // Plan result to json string. + self.build_call( + &ApiFunc::kclvm_value_plan_to_json.name(), + &[ + self.current_runtime_ctx_ptr(), + self.dict_get( + global_dict, + self.native_global_string(SCALAR_KEY, "").into(), + ), + ], + ) } /// Insert a dict entry including key, value, op and insert_index into the dict. @@ -1813,14 +2467,24 @@ impl<'ctx> LLVMCodeGenContext<'ctx> { key: &str, value: BasicValueEnum<'ctx>, op: i32, - insert_index: i32, + insert_index: Option, ) { let name = self.native_global_string(key, "").into(); let op = self.native_int_value(op); - let insert_index = self.native_int_value(insert_index); + let has_insert_index = insert_index.is_some(); + let has_insert_index = self.native_i8_value(if has_insert_index { 1 } else { 0 }); + let insert_index = self.native_int_value(insert_index.unwrap_or(-1)); self.build_void_call( &ApiFunc::kclvm_dict_safe_insert.name(), - &[dict, name, value, op, insert_index], + &[ + self.current_runtime_ctx_ptr(), + dict, + name, + value, + op, + insert_index, + has_insert_index, + ], ); } @@ -1833,14 +2497,24 @@ impl<'ctx> LLVMCodeGenContext<'ctx> { key: &str, value: BasicValueEnum<'ctx>, op: i32, - insert_index: i32, + insert_index: Option, ) { let name = self.native_global_string(key, "").into(); let op = self.native_int_value(op); - let insert_index = self.native_int_value(insert_index); + let has_insert_index = insert_index.is_some(); + let has_insert_index = self.native_i8_value(if has_insert_index { 1 } else { 0 }); + let insert_index = self.native_int_value(insert_index.unwrap_or(-1)); self.build_void_call( &ApiFunc::kclvm_dict_merge.name(), - &[dict, name, value, op, insert_index], + &[ + self.current_runtime_ctx_ptr(), + dict, + name, + value, + op, + insert_index, + has_insert_index, + ], ); } diff --git a/kclvm/compiler/src/codegen/llvm/emit.rs b/kclvm/compiler/src/codegen/llvm/emit.rs index 89838f38b..a795ae444 100644 --- a/kclvm/compiler/src/codegen/llvm/emit.rs +++ b/kclvm/compiler/src/codegen/llvm/emit.rs @@ -1,15 +1,17 @@ -// Copyright 2021 The KCL Authors. All rights reserved. +// Copyright The KCL Authors. All rights reserved. use indexmap::IndexMap; use inkwell::module::Module; use inkwell::{context::Context, memory_buffer::MemoryBuffer}; use kclvm_ast::ast; +use once_cell::sync::OnceCell; use std::error; use crate::codegen::{EmitOptions, MODULE_NAME}; use super::context::LLVMCodeGenContext; +static LLVM_INIT: OnceCell<()> = OnceCell::new(); static RUNTIME_LLVM_BC: &[u8] = include_bytes!("../../../../runtime/src/_kclvm.bc"); /// Load runtime libraries and parse it to a module. @@ -21,19 +23,38 @@ fn load_runtime(context: &'_ Context) -> Module<'_> { /// Generate LLVM IR of KCL ast module. pub fn emit_code( program: &ast::Program, + workdir: String, import_names: IndexMap>, - opt: &EmitOptions, + opts: &EmitOptions, ) -> Result<(), Box> { + // Init LLVM targets + LLVM_INIT.get_or_init(|| { + #[cfg(target_os = "linux")] + inkwell::targets::Target::initialize_x86(&Default::default()); + #[cfg(all(target_os = "linux", target_arch = "aarch64"))] + inkwell::targets::Target::initialize_aarch64(&Default::default()); + #[cfg(target_arch = "wasm32")] + inkwell::targets::Target::initialize_webassembly(&Default::default()); + #[cfg(not(any(target_os = "linux", target_arch = "wasm32")))] + inkwell::targets::Target::initialize_all(&Default::default()); + }); // Create a LLVM context let context = Context::create(); // Create a LLVM module using an exist LLVM bitcode file - let module = if let Some(path) = &opt.from_path { + let module = if let Some(path) = &opts.from_path { Module::parse_bitcode_from_path(std::path::Path::new(path), &context).unwrap() } else { load_runtime(&context) }; // Create a KCL LLVM code generator using the KCL AST and the LLVM module - let ctx = LLVMCodeGenContext::new(&context, module, program, import_names, opt.no_link); + let ctx = LLVMCodeGenContext::new( + &context, + module, + program, + import_names, + opts.no_link, + workdir, + ); // Generate user KCL code LLVM IR - crate::codegen::emit_code(ctx, opt) + crate::codegen::emit_code_with(ctx, opts) } diff --git a/kclvm/compiler/src/codegen/llvm/metadata.rs b/kclvm/compiler/src/codegen/llvm/metadata.rs new file mode 100644 index 000000000..1aadda9ed --- /dev/null +++ b/kclvm/compiler/src/codegen/llvm/metadata.rs @@ -0,0 +1,10 @@ +// Copyright The KCL Authors. All rights reserved. + +use super::context::{DebugModule, LLVMCodeGenContext}; +use inkwell::module::Module; + +impl<'ctx> LLVMCodeGenContext<'ctx> { + pub(crate) fn create_debug_module(&self, module: Module<'ctx>) -> DebugModule<'ctx> { + DebugModule { inner: module } + } +} diff --git a/kclvm/compiler/src/codegen/llvm/mod.rs b/kclvm/compiler/src/codegen/llvm/mod.rs index 58faddb77..3b800239b 100644 --- a/kclvm/compiler/src/codegen/llvm/mod.rs +++ b/kclvm/compiler/src/codegen/llvm/mod.rs @@ -3,10 +3,12 @@ //! module modules pass extern and declare keys. Declare and call them in words, and finally use clang to link //! them together. //! -//! Copyright 2021 The KCL Authors. All rights reserved. +//! Copyright The KCL Authors. All rights reserved. +mod backtrack; mod context; mod emit; +mod metadata; mod module; mod node; mod schema; diff --git a/kclvm/compiler/src/codegen/llvm/module.rs b/kclvm/compiler/src/codegen/llvm/module.rs index dc609d9da..7b9adc451 100644 --- a/kclvm/compiler/src/codegen/llvm/module.rs +++ b/kclvm/compiler/src/codegen/llvm/module.rs @@ -1,10 +1,18 @@ -// Copyright 2021 The KCL Authors. All rights reserved. +// Copyright The KCL Authors. All rights reserved. + +use indexmap::IndexMap; +use inkwell::values::FunctionValue; +use inkwell::AddressSpace; use kclvm_ast::ast; use kclvm_ast::walker::TypedResultWalker; +use kclvm_runtime::ApiFunc; +use kclvm_sema::pkgpath_without_prefix; -use super::context::LLVMCodeGenContext; -use crate::codegen::error as kcl_error; -use crate::codegen::traits::ValueMethods; +use super::context::{BacktrackMeta, LLVMCodeGenContext}; +use crate::codegen::llvm::context::BacktrackKind; +use crate::codegen::traits::{BuilderMethods, ProgramCodeGen, ValueMethods}; +use crate::codegen::{error as kcl_error, ENTRY_NAME}; +use crate::value; use std::str; impl<'ctx> LLVMCodeGenContext<'ctx> { @@ -16,15 +24,24 @@ impl<'ctx> LLVMCodeGenContext<'ctx> { .expect(kcl_error::COMPILE_ERROR_MSG); } ast::Stmt::Schema(schema_stmt) => { + // Pre define global types with undefined values self.predefine_global_types(&schema_stmt.name.node); + self.walk_schema_stmt(schema_stmt) + .expect(kcl_error::COMPILE_ERROR_MSG); } ast::Stmt::Rule(rule_stmt) => { + // Pre define global types with undefined values self.predefine_global_types(&rule_stmt.name.node); + self.walk_rule_stmt(rule_stmt) + .expect(kcl_error::COMPILE_ERROR_MSG); } _ => {} }; } + // Pre define global variables with setter functions. + self.predefine_global_setters(module); } + pub fn predefine_global_types(&self, name: &str) { // Store or add the variable in the scope let function = self.undefined_value(); @@ -34,4 +51,361 @@ impl<'ctx> LLVMCodeGenContext<'ctx> { self.add_variable(name, global_var_ptr); } } + + /// Predefine all global variables. + #[inline] + pub(crate) fn predefine_global_vars(&self, module: &'ctx ast::Module) { + self.emit_global_vars(&module.body); + } + + /// Predefine all global variables. + pub fn predefine_global_setters(&self, module: &'ctx ast::Module) { + // New a function block to the global setter construction process. + let global_setter_block = self.append_block(""); + self.br(global_setter_block); + self.builder.position_at_end(global_setter_block); + let mut place_holder_map: IndexMap>> = IndexMap::new(); + let mut body_map: IndexMap, BacktrackKind)>> = + IndexMap::new(); + let pkgpath = &self.current_pkgpath(); + // Setter function name format: "$set..$" + self.emit_global_setters( + &module.body, + &pkgpath, + false, + &mut place_holder_map, + &mut body_map, + &mut vec![], + ); + // Build global attribute backtrack functions. + { + for (k, functions) in &place_holder_map { + if k == kclvm_runtime::CAL_MAP_INDEX_SIGNATURE { + continue; + } + let stmt_list = body_map.get(k).expect(kcl_error::INTERNAL_ERROR_MSG); + let mut if_level = 0; + for (attr_func, (stmt, kind)) in functions.iter().zip(stmt_list) { + let function = *attr_func; + let name = function + .get_name() + .to_str() + .expect(kcl_error::INTERNAL_ERROR_MSG); + // Get attribute function from the module. + let function = self.lookup_function(name); + self.push_function(function); + let attr_block = self.append_block(ENTRY_NAME); + self.builder.position_at_end(attr_block); + // Backtrack meta begin + if matches!(&stmt.node, ast::Stmt::If(..)) { + if_level += 1; + *self.backtrack_meta.borrow_mut() = Some(BacktrackMeta { + target: k.clone(), + level: if_level, + count: 0, + stop: false, + kind: kind.clone(), + }); + } else { + if_level = 0; + } + let result = self.walk_stmt(stmt).expect(kcl_error::COMPILE_ERROR_MSG); + // Backtrack meta end + if matches!(&stmt.node, ast::Stmt::If(..)) { + *self.backtrack_meta.borrow_mut() = None + } + // Build return + self.builder.build_return(Some(&result)); + // Position at global main function block + self.builder.position_at_end(global_setter_block); + self.pop_function(); + } + } + } + } + + fn emit_global_vars(&self, body: &'ctx [Box>]) { + for stmt in body { + match &stmt.node { + ast::Stmt::Unification(unification_stmt) => { + let names = &unification_stmt.target.node.names; + if names.len() == 1 { + self.add_or_update_global_variable( + &names[0].node, + self.undefined_value(), + false, + ); + } + } + ast::Stmt::Assign(assign_stmt) => { + for target in &assign_stmt.targets { + self.add_or_update_global_variable( + target.node.get_name(), + self.undefined_value(), + false, + ); + } + } + ast::Stmt::If(if_stmt) => { + self.emit_global_vars(&if_stmt.body); + self.emit_global_vars(&if_stmt.orelse); + } + _ => {} + } + } + } + + pub(crate) fn emit_config_if_entry_expr_vars( + &self, + config_if_entry_expr: &'ctx ast::ConfigIfEntryExpr, + ) { + self.emit_config_entries_vars(&config_if_entry_expr.items); + if let Some(orelse) = &config_if_entry_expr.orelse { + // Config expr or config if entry expr. + if let ast::Expr::Config(config_expr) = &orelse.node { + self.emit_config_entries_vars(&config_expr.items); + } else if let ast::Expr::ConfigIfEntry(config_if_entry_expr) = &orelse.node { + self.emit_config_if_entry_expr_vars(config_if_entry_expr); + } + } + } + + pub(crate) fn emit_config_entries_vars(&self, items: &'ctx [ast::NodeRef]) { + for item in items { + if let ast::Expr::ConfigIfEntry(config_if_entry_expr) = &item.node.value.node { + self.emit_config_if_entry_expr_vars(config_if_entry_expr); + } + if let Some(key) = &item.node.key { + let optional_name = match &key.node { + ast::Expr::Identifier(identifier) => Some(identifier.names[0].node.clone()), + ast::Expr::StringLit(string_lit) => Some(string_lit.value.clone()), + ast::Expr::Subscript(subscript) => { + let mut name = None; + if let ast::Expr::Identifier(identifier) = &subscript.value.node { + if let Some(index_node) = &subscript.index { + if let ast::Expr::NumberLit(number) = &index_node.node { + if let ast::NumberLitValue::Int(_) = number.value { + name = Some(identifier.names[0].node.clone()) + } + } + } + } + name + } + _ => None, + }; + if let Some(name) = &optional_name { + self.add_or_update_local_variable_within_scope(name, None); + } + } + } + } + + /// Compile AST Modules, which requires traversing three times. + /// 1. scan all possible global variables and allocate undefined values to global pointers. + /// 2. build all user-defined schema/rule types. + /// 3. generate all LLVM IR codes for the third time. + pub(crate) fn compile_ast_modules(&self, modules: &'ctx [ast::Module]) { + // Scan global variables + for ast_module in modules { + { + self.filename_stack + .borrow_mut() + .push(ast_module.filename.clone()); + } + // Pre define global variables with undefined values + self.predefine_global_vars(ast_module); + { + self.filename_stack.borrow_mut().pop(); + } + } + // Scan global types + for ast_module in modules { + { + self.filename_stack + .borrow_mut() + .push(ast_module.filename.clone()); + } + self.compile_module_import_and_types(ast_module); + { + self.filename_stack.borrow_mut().pop(); + } + } + // Compile the ast module in the pkgpath. + for ast_module in modules { + { + self.filename_stack + .borrow_mut() + .push(ast_module.filename.clone()); + } + self.walk_module(ast_module) + .expect(kcl_error::COMPILE_ERROR_MSG); + { + self.filename_stack.borrow_mut().pop(); + } + } + } + + /// Emit setter functions for global variables. + pub(crate) fn emit_global_setters( + &self, + body: &'ctx [Box>], + pkgpath: &str, + is_in_if: bool, + place_holder_map: &mut IndexMap>>, + body_map: &mut IndexMap, BacktrackKind)>>, + in_if_names: &mut Vec, + ) { + let add_stmt = |name: &str, + stmt: &'ctx ast::Node, + kind: BacktrackKind, + place_holder_map: &mut IndexMap>>, + body_map: &mut IndexMap< + String, + Vec<(&'ctx ast::Node, BacktrackKind)>, + >| { + // The function form e.g., $set.__main__.a(&Context, &LazyScope, &ValueRef, &ValueRef) + let var_key = format!("{}.{name}", pkgpath_without_prefix!(pkgpath)); + let function = + self.add_setter_function(&format!("{}.{}", value::GLOBAL_SETTER, var_key)); + let lambda_fn_ptr = self.builder.build_bitcast( + function.as_global_value().as_pointer_value(), + self.context.i64_type().ptr_type(AddressSpace::default()), + "", + ); + if !place_holder_map.contains_key(name) { + place_holder_map.insert(name.to_string(), vec![]); + } + let name_vec = place_holder_map + .get_mut(name) + .expect(kcl_error::INTERNAL_ERROR_MSG); + name_vec.push(function); + self.build_void_call( + &ApiFunc::kclvm_scope_add_setter.name(), + &[ + self.current_runtime_ctx_ptr(), + self.current_scope_ptr(), + self.native_global_string(pkgpath, "").into(), + self.native_global_string(name, "").into(), + lambda_fn_ptr, + ], + ); + let key = format!("{}.{name}", pkgpath_without_prefix!(pkgpath)); + self.setter_keys.borrow_mut().insert(key); + if !body_map.contains_key(name) { + body_map.insert(name.to_string(), vec![]); + } + let body_vec = body_map.get_mut(name).expect(kcl_error::INTERNAL_ERROR_MSG); + body_vec.push((stmt, kind)); + }; + for stmt in body { + match &stmt.node { + ast::Stmt::Unification(unification_stmt) => { + let name = &unification_stmt.target.node.names[0].node; + if is_in_if { + in_if_names.push(name.to_string()); + } else { + add_stmt( + name, + stmt, + BacktrackKind::Normal, + place_holder_map, + body_map, + ); + } + } + ast::Stmt::Assign(assign_stmt) => { + for target in &assign_stmt.targets { + let name = &target.node.name.node; + if is_in_if { + in_if_names.push(name.to_string()); + } else { + add_stmt( + name, + stmt, + BacktrackKind::Normal, + place_holder_map, + body_map, + ); + } + } + } + ast::Stmt::AugAssign(aug_assign_stmt) => { + let target = &aug_assign_stmt.target; + let name = &target.node.name.node; + if is_in_if { + in_if_names.push(name.to_string()); + } else { + add_stmt( + name, + stmt, + BacktrackKind::Normal, + place_holder_map, + body_map, + ); + } + } + ast::Stmt::If(if_stmt) => { + let mut names: Vec = vec![]; + self.emit_global_setters( + &if_stmt.body, + pkgpath, + true, + place_holder_map, + body_map, + &mut names, + ); + if is_in_if { + for name in &names { + in_if_names.push(name.to_string()); + } + } else { + for name in &names { + add_stmt(name, stmt, BacktrackKind::If, place_holder_map, body_map); + } + } + names.clear(); + self.emit_global_setters( + &if_stmt.orelse, + pkgpath, + true, + place_holder_map, + body_map, + &mut names, + ); + if is_in_if { + for name in &names { + in_if_names.push(name.to_string()); + } + } else { + for name in &names { + add_stmt( + name, + stmt, + BacktrackKind::OrElse, + place_holder_map, + body_map, + ); + } + } + names.clear(); + } + ast::Stmt::SchemaAttr(schema_attr) => { + let name = schema_attr.name.node.as_str(); + if is_in_if { + in_if_names.push(name.to_string()); + } else { + add_stmt( + name, + stmt, + BacktrackKind::Normal, + place_holder_map, + body_map, + ); + } + } + _ => {} + } + } + } } diff --git a/kclvm/compiler/src/codegen/llvm/node.rs b/kclvm/compiler/src/codegen/llvm/node.rs index a725a5bcc..a8bdf4d7a 100644 --- a/kclvm/compiler/src/codegen/llvm/node.rs +++ b/kclvm/compiler/src/codegen/llvm/node.rs @@ -1,4 +1,4 @@ -// Copyright 2021 The KCL Authors. All rights reserved. +// Copyright The KCL Authors. All rights reserved. use std::cell::RefCell; use std::collections::HashMap; @@ -8,16 +8,19 @@ use inkwell::basic_block::BasicBlock; use inkwell::module::Linkage; use inkwell::values::{BasicValueEnum, CallableValue, FunctionValue}; use inkwell::{AddressSpace, IntPredicate}; -use kclvm::{ApiFunc, PKG_PATH_PREFIX}; -use kclvm_ast::ast::{self, CallExpr}; +use kclvm_ast::ast::{self, CallExpr, ConfigEntry, NodeRef}; use kclvm_ast::walker::TypedResultWalker; +use kclvm_runtime::{ApiFunc, PKG_PATH_PREFIX}; +use kclvm_sema::pkgpath_without_prefix; +use kclvm_sema::ty::{ANY_TYPE_STR, STR_TYPE_STR}; +use crate::check_backtrack_stop; use crate::codegen::error as kcl_error; +use crate::codegen::llvm::context::BacktrackKind; use crate::codegen::llvm::context::BacktrackMeta; use crate::codegen::llvm::utils; use crate::codegen::traits::*; -use crate::codegen::{ENTRY_NAME, GLOBAL_LEVEL, PKG_INIT_FUNCTION_SUFFIX, SCHEMA_LEVEL}; -use crate::{check_backtrack_stop, pkgpath_without_prefix}; +use crate::codegen::{ENTRY_NAME, GLOBAL_LEVEL, INNER_LEVEL, PKG_INIT_FUNCTION_SUFFIX}; use super::context::{CompileResult, LLVMCodeGenContext}; use crate::value; @@ -36,8 +39,7 @@ impl<'ctx> TypedResultWalker<'ctx> for LLVMCodeGenContext<'ctx> { check_backtrack_stop!(self); utils::update_ctx_filename(self, stmt); utils::update_ctx_line_col(self, stmt); - self.target_vars.borrow_mut().clear(); - self.target_vars.borrow_mut().push("".to_string()); + utils::reset_target_vars(self); match &stmt.node { ast::Stmt::TypeAlias(type_alias) => self.walk_type_alias_stmt(type_alias), ast::Stmt::Expr(expr_stmt) => self.walk_expr_stmt(expr_stmt), @@ -59,10 +61,12 @@ impl<'ctx> TypedResultWalker<'ctx> for LLVMCodeGenContext<'ctx> { check_backtrack_stop!(self); let mut result = self.ok_result(); for expr in &expr_stmt.exprs { - // Ignore the doc string - if !matches!(&expr.node, ast::Expr::StringLit(..)) { - result = self.walk_expr(expr); + let scalar = self.walk_expr(expr)?; + // Only non-call expressions are allowed to emit values because of the function void return type. + if !matches!(expr.node, ast::Expr::Call(_)) { + self.add_scalar(scalar, matches!(expr.node, ast::Expr::Schema(_))); } + result = Ok(scalar); } result } @@ -70,19 +74,13 @@ impl<'ctx> TypedResultWalker<'ctx> for LLVMCodeGenContext<'ctx> { fn walk_unification_stmt(&self, unification_stmt: &'ctx ast::UnificationStmt) -> Self::Result { check_backtrack_stop!(self); self.local_vars.borrow_mut().clear(); - let name = &unification_stmt.target.node.names[0]; + let name = &unification_stmt.target.node.names[0].node; self.target_vars.borrow_mut().push(name.clone()); // The right value of the unification_stmt is a schema_expr. let value = self .walk_schema_expr(&unification_stmt.value.node) .expect(kcl_error::COMPILE_ERROR_MSG); - if self.scope_level() == GLOBAL_LEVEL - || *self - .lambda_stack - .borrow_mut() - .last() - .expect(kcl_error::INTERNAL_ERROR_MSG) - { + if self.scope_level() == GLOBAL_LEVEL || self.is_in_lambda() { if self.resolve_variable(name) { let org_value = self .walk_identifier_with_ctx( @@ -92,7 +90,10 @@ impl<'ctx> TypedResultWalker<'ctx> for LLVMCodeGenContext<'ctx> { ) .expect(kcl_error::COMPILE_ERROR_MSG); let fn_name = ApiFunc::kclvm_value_op_aug_bit_or; - let value = self.build_call(&fn_name.name(), &[org_value, value]); + let value = self.build_call( + &fn_name.name(), + &[self.current_runtime_ctx_ptr(), org_value, value], + ); // Store the identifier value self.walk_identifier_with_ctx( &unification_stmt.target.node, @@ -111,7 +112,7 @@ impl<'ctx> TypedResultWalker<'ctx> for LLVMCodeGenContext<'ctx> { return Ok(value); } // Local variables including schema/rule/lambda - } else if self.schema_stack.borrow().len() > 0 { + } else if self.is_in_schema() { // Load the identifier value let org_value = self .walk_identifier_with_ctx( @@ -121,7 +122,10 @@ impl<'ctx> TypedResultWalker<'ctx> for LLVMCodeGenContext<'ctx> { ) .expect(kcl_error::COMPILE_ERROR_MSG); let fn_name = ApiFunc::kclvm_value_op_bit_or; - let value = self.build_call(&fn_name.name(), &[org_value, value]); + let value = self.build_call( + &fn_name.name(), + &[self.current_runtime_ctx_ptr(), org_value, value], + ); // Store the identifier value self.walk_identifier_with_ctx( &unification_stmt.target.node, @@ -142,31 +146,39 @@ impl<'ctx> TypedResultWalker<'ctx> for LLVMCodeGenContext<'ctx> { fn walk_assign_stmt(&self, assign_stmt: &'ctx ast::AssignStmt) -> Self::Result { check_backtrack_stop!(self); self.local_vars.borrow_mut().clear(); + // Set target vars. for name in &assign_stmt.targets { self.target_vars .borrow_mut() - .push(name.node.names[0].clone()); + .push(name.node.name.node.clone()); } // Load the right value let mut value = self .walk_expr(&assign_stmt.value) .expect(kcl_error::COMPILE_ERROR_MSG); - if let Some(type_annotation) = &assign_stmt.type_annotation { - let type_annotation = self.native_global_string_value(&type_annotation.node); + if let Some(ty) = &assign_stmt.ty { + let type_annotation = self.native_global_string_value(&ty.node.to_string()); + let is_in_schema = self.is_in_schema() || self.is_in_schema_expr(); value = self.build_call( &ApiFunc::kclvm_convert_collection_value.name(), - &[value, type_annotation], + &[ + self.current_runtime_ctx_ptr(), + value, + type_annotation, + self.bool_value(is_in_schema), + ], ); } if assign_stmt.targets.len() == 1 { + // Store the single target let name = &assign_stmt.targets[0]; - self.walk_identifier_with_ctx(&name.node, &name.node.ctx, Some(value)) + self.walk_target_with_value(&name.node, value) .expect(kcl_error::COMPILE_ERROR_MSG); } else { - // Store targets + // Store multiple targets for name in &assign_stmt.targets { let value = self.value_deep_copy(value); - self.walk_identifier_with_ctx(&name.node, &name.node.ctx, Some(value)) + self.walk_target_with_value(&name.node, value) .expect(kcl_error::COMPILE_ERROR_MSG); } } @@ -177,14 +189,14 @@ impl<'ctx> TypedResultWalker<'ctx> for LLVMCodeGenContext<'ctx> { check_backtrack_stop!(self); self.target_vars .borrow_mut() - .push(aug_assign_stmt.target.node.names[0].clone()); + .push(aug_assign_stmt.target.node.name.node.clone()); // Load the right value let right_value = self .walk_expr(&aug_assign_stmt.value) .expect(kcl_error::COMPILE_ERROR_MSG); - // Load the identifier value + // Load the value let org_value = self - .walk_identifier_with_ctx(&aug_assign_stmt.target.node, &ast::ExprContext::Load, None) + .load_target(&aug_assign_stmt.target.node) .expect(kcl_error::COMPILE_ERROR_MSG); let fn_name = match aug_assign_stmt.op { ast::AugOp::Add => ApiFunc::kclvm_value_op_aug_add, @@ -203,14 +215,13 @@ impl<'ctx> TypedResultWalker<'ctx> for LLVMCodeGenContext<'ctx> { return Err(kcl_error::KCLError::new(kcl_error::INVALID_OPERATOR_MSG)); } }; - let value = self.build_call(&fn_name.name(), &[org_value, right_value]); - // Store the identifier value - self.walk_identifier_with_ctx( - &aug_assign_stmt.target.node, - &ast::ExprContext::Store, - Some(value), - ) - .expect(kcl_error::COMPILE_ERROR_MSG); + let value = self.build_call( + &fn_name.name(), + &[self.current_runtime_ctx_ptr(), org_value, right_value], + ); + // Store the target value + self.walk_target_with_value(&aug_assign_stmt.target.node, value) + .expect(kcl_error::COMPILE_ERROR_MSG); Ok(value) } @@ -229,6 +240,7 @@ impl<'ctx> TypedResultWalker<'ctx> for LLVMCodeGenContext<'ctx> { let assert_result = self .walk_expr(&assert_stmt.test) .expect(kcl_error::COMPILE_ERROR_MSG); + // Assert statement error message. let msg = { if let Some(msg) = &assert_stmt.msg { self.walk_expr(msg).expect(kcl_error::COMPILE_ERROR_MSG) @@ -236,36 +248,59 @@ impl<'ctx> TypedResultWalker<'ctx> for LLVMCodeGenContext<'ctx> { self.string_value("") } }; - self.build_void_call(&ApiFunc::kclvm_assert.name(), &[assert_result, msg]); + self.build_void_call( + &ApiFunc::kclvm_assert.name(), + &[self.current_runtime_ctx_ptr(), assert_result, msg], + ); self.br(end_block); self.builder.position_at_end(end_block); - self.ok_result() + Ok(self.undefined_value()) } fn walk_if_stmt(&self, if_stmt: &'ctx ast::IfStmt) -> Self::Result { check_backtrack_stop!(self); - let cond = self - .walk_expr(&if_stmt.cond) - .expect(kcl_error::COMPILE_ERROR_MSG); + let cond = self.walk_expr(&if_stmt.cond)?; let then_block = self.append_block(""); let else_block = self.append_block(""); let end_block = self.append_block(""); let is_truth = self.value_is_truthy(cond); self.cond_br(is_truth, then_block, else_block); self.builder.position_at_end(then_block); - self.walk_stmts(&if_stmt.body) - .expect(kcl_error::COMPILE_ERROR_MSG); + // Is backtrack only orelse stmt? + if self.is_backtrack_only_or_else() { + self.ok_result()?; + self.br(end_block); + self.builder.position_at_end(else_block); + self.walk_stmts(&if_stmt.orelse)?; + self.br(end_block); + self.builder.position_at_end(end_block); + return Ok(self.none_value()); + } + // Is backtrack only if stmt? + if self.is_backtrack_only_if() { + self.walk_stmts(&if_stmt.body)?; + self.br(end_block); + self.builder.position_at_end(else_block); + self.ok_result()?; + self.br(end_block); + self.builder.position_at_end(end_block); + return Ok(self.none_value()); + } + // Normal full if stmt. + self.walk_stmts(&if_stmt.body)?; self.br(end_block); self.builder.position_at_end(else_block); - self.walk_stmts(&if_stmt.orelse) - .expect(kcl_error::COMPILE_ERROR_MSG); + self.walk_stmts(&if_stmt.orelse)?; self.br(end_block); self.builder.position_at_end(end_block); Ok(self.none_value()) } + fn walk_import_stmt(&self, import_stmt: &'ctx ast::ImportStmt) -> Self::Result { check_backtrack_stop!(self); - let pkgpath = import_stmt.path.as_str(); + let pkgpath = import_stmt.path.node.as_str(); + // Check if it has already been generated, there is no need to generate code + // for duplicate import statements. { let imported = self.imported.borrow_mut(); if imported.contains(pkgpath) { @@ -273,16 +308,16 @@ impl<'ctx> TypedResultWalker<'ctx> for LLVMCodeGenContext<'ctx> { } // Deref the borrow mut } + // Standard or plugin modules. if builtin::STANDARD_SYSTEM_MODULES.contains(&pkgpath) || pkgpath.starts_with(plugin::PLUGIN_MODULE_PREFIX) { // Nothing to do on the builtin system module import because the check has been done. return self.ok_result(); } else { - let pkgpath = format!("{}{}", PKG_PATH_PREFIX, import_stmt.path); - self.pkgpath_stack.borrow_mut().push(pkgpath); - let pkgpath = format!("{}{}", PKG_PATH_PREFIX, import_stmt.path); - let has_pkgpath = self.program.pkgs.contains_key(&import_stmt.path); + let pkgpath = format!("{}{}", PKG_PATH_PREFIX, import_stmt.path.node); + self.push_pkgpath(&pkgpath); + let has_pkgpath = self.program.pkgs.contains_key(&import_stmt.path.node); let func_before_block = if self.no_link { if has_pkgpath { let func_before_block = self.append_block(""); @@ -296,7 +331,10 @@ impl<'ctx> TypedResultWalker<'ctx> for LLVMCodeGenContext<'ctx> { PKG_INIT_FUNCTION_SUFFIX ); let tpe = self.context.void_type(); - let fn_type = tpe.fn_type(&[self.context_ptr_type().into()], false); + let fn_type = tpe.fn_type( + &[self.context_ptr_type().into(), self.scope_ptr_type().into()], + false, + ); let function = module.add_function( // Function name &module_name, @@ -308,7 +346,7 @@ impl<'ctx> TypedResultWalker<'ctx> for LLVMCodeGenContext<'ctx> { let basic_block = self.context.append_basic_block(function, ENTRY_NAME); self.builder.position_at_end(basic_block); self.push_function(function); - modules.insert(name, RefCell::new(module)); + modules.insert(name, RefCell::new(self.create_debug_module(module))); Some(func_before_block) } else { None @@ -319,42 +357,14 @@ impl<'ctx> TypedResultWalker<'ctx> for LLVMCodeGenContext<'ctx> { if has_pkgpath { // Init all builtin functions. self.init_scope(pkgpath.as_str()); - // Compile the ast module in the pkgpath. - for ast_module in self - .program - .pkgs - .get(&import_stmt.path) - .expect(kcl_error::INTERNAL_ERROR_MSG) - { - { - self.filename_stack - .borrow_mut() - .push(ast_module.filename.clone()); - } - self.compile_module_import_and_types(ast_module); - { - self.filename_stack.borrow_mut().pop(); - } - } - for ast_module in self - .program - .pkgs - .get(&import_stmt.path) - .expect(kcl_error::INTERNAL_ERROR_MSG) - { - { - self.filename_stack - .borrow_mut() - .push(ast_module.filename.clone()); - } - self.walk_stmts_except_import(&ast_module.body) - .expect(kcl_error::COMPILE_ERROR_MSG); - { - self.filename_stack.borrow_mut().pop(); - } - } + self.compile_ast_modules( + self.program + .pkgs + .get(&import_stmt.path.node) + .expect(kcl_error::INTERNAL_ERROR_MSG), + ); } - self.pkgpath_stack.borrow_mut().pop(); + self.pop_pkgpath(); if self.no_link { let name = format!( "${}.{}", @@ -365,7 +375,7 @@ impl<'ctx> TypedResultWalker<'ctx> for LLVMCodeGenContext<'ctx> { let pkgpath = self.current_pkgpath(); let modules = self.modules.borrow_mut(); let msg = format!("pkgpath {} is not found", pkgpath); - let module = modules.get(&pkgpath).expect(&msg).borrow_mut(); + let module = &modules.get(&pkgpath).expect(&msg).borrow_mut().inner; if has_pkgpath { self.ret_void(); self.pop_function(); @@ -374,15 +384,19 @@ impl<'ctx> TypedResultWalker<'ctx> for LLVMCodeGenContext<'ctx> { ); } let tpe = self.context.void_type(); - let fn_type = tpe.fn_type(&[self.context_ptr_type().into()], false); + let fn_type = tpe.fn_type( + &[self.context_ptr_type().into(), self.scope_ptr_type().into()], + false, + ); module.add_function(&name, fn_type, Some(Linkage::External)) }; - let ctx = self.global_ctx_ptr(); + let ctx = self.current_runtime_ctx_ptr(); + let scope = self.current_scope_ptr(); let pkgpath_value = self.native_global_string_value(&name); let is_imported = self .build_call( &ApiFunc::kclvm_context_pkgpath_is_imported.name(), - &[pkgpath_value], + &[self.current_runtime_ctx_ptr(), pkgpath_value], ) .into_int_value(); let is_not_imported = self.builder.build_int_compare( @@ -396,7 +410,8 @@ impl<'ctx> TypedResultWalker<'ctx> for LLVMCodeGenContext<'ctx> { self.builder .build_conditional_branch(is_not_imported, then_block, else_block); self.builder.position_at_end(then_block); - self.builder.build_call(function, &[ctx.into()], ""); + self.builder + .build_call(function, &[ctx.into(), scope.into()], ""); self.br(else_block); self.builder.position_at_end(else_block); } @@ -417,7 +432,7 @@ impl<'ctx> TypedResultWalker<'ctx> for LLVMCodeGenContext<'ctx> { let schema_name = &schema_stmt.name.node; let schema_pkgpath = &self.current_pkgpath(); let filename = &self.current_filename(); - let runtime_type = kclvm::schema_runtime_type(schema_name, schema_pkgpath); + let runtime_type = kclvm_runtime::schema_runtime_type(schema_name, schema_pkgpath); // Build schema body function let function = self.add_function(&format!( "{}.{}", @@ -431,7 +446,8 @@ impl<'ctx> TypedResultWalker<'ctx> for LLVMCodeGenContext<'ctx> { pkgpath_without_prefix!(runtime_type), )); let mut place_holder_map: HashMap>> = HashMap::new(); - let mut body_map: HashMap>> = HashMap::new(); + let mut body_map: HashMap, BacktrackKind)>> = + HashMap::new(); // Enter the function self.push_function(function); // Lambda function body @@ -439,7 +455,10 @@ impl<'ctx> TypedResultWalker<'ctx> for LLVMCodeGenContext<'ctx> { self.builder.position_at_end(block); self.build_void_call( &ApiFunc::kclvm_context_set_kcl_filename.name(), - &[self.native_global_string_value(filename)], + &[ + self.current_runtime_ctx_ptr(), + self.native_global_string_value(filename), + ], ); utils::update_ctx_pkgpath(self, schema_pkgpath); let args = function @@ -503,14 +522,14 @@ impl<'ctx> TypedResultWalker<'ctx> for LLVMCodeGenContext<'ctx> { &ApiFunc::kclvm_value_function_ptr.name(), &[base_constructor_func], ); - let fn_ty = self.function_type().ptr_type(AddressSpace::Generic); + let fn_ty = self.function_type().ptr_type(AddressSpace::default()); let func_ptr_cast = self.builder.build_bitcast(func_ptr, fn_ty, ""); self.builder .build_call( CallableValue::try_from(func_ptr_cast.into_pointer_value()) .expect(kcl_error::INTERNAL_ERROR_MSG), &[ - self.global_ctx_ptr().into(), + self.current_runtime_ctx_ptr().into(), list_value.into(), dict_value.into(), ], @@ -525,13 +544,17 @@ impl<'ctx> TypedResultWalker<'ctx> for LLVMCodeGenContext<'ctx> { if schema_stmt.parent_name.is_some() { self.build_void_call( &ApiFunc::kclvm_context_set_kcl_filename.name(), - &[self.native_global_string_value(filename)], + &[ + self.current_runtime_ctx_ptr(), + self.native_global_string_value(filename), + ], ); } self.schema_stack.borrow_mut().push(schema); add_variable(value::SCHEMA_SELF_NAME, schema_value); - self.emit_schema_left_identifiers( + self.emit_left_identifiers( &schema_stmt.body, + &schema_stmt.index_signature, cal_map, &runtime_type, false, @@ -553,12 +576,14 @@ impl<'ctx> TypedResultWalker<'ctx> for LLVMCodeGenContext<'ctx> { self.walk_decorator_with_name(&decorator.node, Some(schema_name), true) .expect(kcl_error::COMPILE_ERROR_MSG); } - // Append schema default settings + // Append schema default settings, args, kwargs and runtime type. self.build_void_call( &ApiFunc::kclvm_schema_default_settings.name(), &[ schema_value, schema_config, + args, + kwargs, self.native_global_string_value(&runtime_type), ], ); @@ -586,13 +611,13 @@ impl<'ctx> TypedResultWalker<'ctx> for LLVMCodeGenContext<'ctx> { let dict_value = self.dict_value(); let func_ptr = self.build_call(&ApiFunc::kclvm_value_function_ptr.name(), &[mixin_func]); - let fn_ty = self.function_type().ptr_type(AddressSpace::Generic); + let fn_ty = self.function_type().ptr_type(AddressSpace::default()); let func_ptr_cast = self.builder.build_bitcast(func_ptr, fn_ty, ""); self.builder.build_call( CallableValue::try_from(func_ptr_cast.into_pointer_value()) .expect(kcl_error::INTERNAL_ERROR_MSG), &[ - self.global_ctx_ptr().into(), + self.current_runtime_ctx_ptr().into(), list_value.into(), dict_value.into(), ], @@ -600,7 +625,10 @@ impl<'ctx> TypedResultWalker<'ctx> for LLVMCodeGenContext<'ctx> { ); self.build_void_call( &ApiFunc::kclvm_context_set_kcl_filename.name(), - &[self.native_global_string_value(filename)], + &[ + self.current_runtime_ctx_ptr(), + self.native_global_string_value(filename), + ], ); } // Schema Attribute optional check @@ -620,61 +648,6 @@ impl<'ctx> TypedResultWalker<'ctx> for LLVMCodeGenContext<'ctx> { self.builder.position_at_end(do_check_block); let schema_name_native_str = self.native_global_string_value(&schema_stmt.name.node); let schema_pkgpath_native_str = self.native_global_string_value(&self.current_pkgpath()); - // Schema runtime index signature and relaxed check - if let Some(index_signature) = &schema_stmt.index_signature { - let index_sign_value = if let Some(value) = &index_signature.node.value { - self.walk_expr(value).expect(kcl_error::COMPILE_ERROR_MSG) - } else { - self.none_value() - }; - let key_name_str_ptr = if let Some(key_name) = &index_signature.node.key_name { - self.native_global_string(key_name.as_str(), "") - } else { - self.native_global_string("", "") - }; - self.build_void_call( - &ApiFunc::kclvm_schema_value_check.name(), - &[ - schema_value, - schema_config, - schema_config_meta, - schema_name_native_str, - index_sign_value, - key_name_str_ptr.into(), - self.native_global_string(index_signature.node.key_type.node.as_str(), "") - .into(), - self.native_global_string(index_signature.node.value_type.node.as_str(), "") - .into(), - self.native_i8(index_signature.node.any_other as i8).into(), - self.native_i8(false as i8).into(), - ], - ); - } else { - self.build_void_call( - &ApiFunc::kclvm_schema_value_check.name(), - &[ - schema_value, - schema_config, - schema_config_meta, - schema_name_native_str, - self.none_value(), - self.native_global_string("", "").into(), - self.native_global_string("", "").into(), - self.native_global_string("", "").into(), - self.native_i8(0).into(), - self.native_i8(false as i8).into(), - ], - ); - } - self.build_void_call( - &ApiFunc::kclvm_schema_optional_check.name(), - &[ - schema_value, - attr_optional_mapping, - schema_name_native_str, - schema_config_meta, - ], - ); { let index_sign_key_name = if let Some(index_signature) = &schema_stmt.index_signature { if let Some(key_name) = &index_signature.node.key_name { @@ -699,7 +672,7 @@ impl<'ctx> TypedResultWalker<'ctx> for LLVMCodeGenContext<'ctx> { self.builder.build_call( check_function, &[ - self.global_ctx_ptr().into(), + self.current_runtime_ctx_ptr().into(), list_value.into(), dict_value.into(), ], @@ -709,7 +682,7 @@ impl<'ctx> TypedResultWalker<'ctx> for LLVMCodeGenContext<'ctx> { // Call schema check block function with index sign attribute name loop set let check_lambda_fn_ptr = self.builder.build_bitcast( check_function.as_global_value().as_pointer_value(), - self.context.i64_type().ptr_type(AddressSpace::Generic), + self.context.i64_type().ptr_type(AddressSpace::default()), "", ); let attr_name = self.native_global_string_value(index_sign_key_name); @@ -718,7 +691,7 @@ impl<'ctx> TypedResultWalker<'ctx> for LLVMCodeGenContext<'ctx> { .name() .as_str(), &[ - self.global_ctx_ptr(), + self.current_runtime_ctx_ptr(), list_value, dict_value, check_lambda_fn_ptr, @@ -733,13 +706,18 @@ impl<'ctx> TypedResultWalker<'ctx> for LLVMCodeGenContext<'ctx> { let schema_value = self.build_call( &ApiFunc::kclvm_value_schema_with_config.name(), &[ + self.current_runtime_ctx_ptr(), schema_value, schema_config, + schema_config_meta, schema_name_native_str, schema_pkgpath_native_str, is_sub_schema, record_instance, instance_pkgpath, + attr_optional_mapping, + args, + kwargs, ], ); // Schema constructor function returns a schema @@ -777,6 +755,58 @@ impl<'ctx> TypedResultWalker<'ctx> for LLVMCodeGenContext<'ctx> { .expect(kcl_error::INTERNAL_ERROR_MSG); self.walk_arguments(&schema_stmt.args, args, kwargs); self.schema_stack.borrow_mut().push(schema); + // Schema runtime index signature and relaxed check + if let Some(index_signature) = &schema_stmt.index_signature { + let index_sign_value = if let Some(value) = &index_signature.node.value { + self.walk_expr(value).expect(kcl_error::COMPILE_ERROR_MSG) + } else { + self.undefined_value() + }; + let key_name_str_ptr = if let Some(key_name) = &index_signature.node.key_name { + self.native_global_string(key_name.as_str(), "") + } else { + self.native_global_string("", "") + }; + self.build_void_call( + &ApiFunc::kclvm_schema_value_check.name(), + &[ + self.current_runtime_ctx_ptr(), + schema_value, + schema_config, + schema_config_meta, + schema_name_native_str, + index_sign_value, + key_name_str_ptr.into(), + self.native_global_string( + index_signature.node.key_ty.node.to_string().as_str(), + "", + ) + .into(), + self.native_global_string( + index_signature.node.value_ty.node.to_string().as_str(), + "", + ) + .into(), + self.native_i8(index_signature.node.any_other as i8).into(), + ], + ); + } else { + self.build_void_call( + &ApiFunc::kclvm_schema_value_check.name(), + &[ + self.current_runtime_ctx_ptr(), + schema_value, + schema_config, + schema_config_meta, + schema_name_native_str, + self.none_value(), + self.native_global_string("", "").into(), + self.native_global_string("", "").into(), + self.native_global_string("", "").into(), + self.native_i8(0).into(), + ], + ); + } // Call base check function if let Some(parent_name) = &schema_stmt.parent_name { let base_constructor_func = self @@ -786,7 +816,7 @@ impl<'ctx> TypedResultWalker<'ctx> for LLVMCodeGenContext<'ctx> { &ApiFunc::kclvm_value_check_function_ptr.name(), &[base_constructor_func], ); - let fn_ty = self.function_type().ptr_type(AddressSpace::Generic); + let fn_ty = self.function_type().ptr_type(AddressSpace::default()); let func_ptr_cast = self.builder.build_bitcast(func_ptr, fn_ty, ""); // Schema check function closure let list_value = self.list_values(&[ @@ -802,7 +832,7 @@ impl<'ctx> TypedResultWalker<'ctx> for LLVMCodeGenContext<'ctx> { CallableValue::try_from(func_ptr_cast.into_pointer_value()) .expect(kcl_error::INTERNAL_ERROR_MSG), &[ - self.global_ctx_ptr().into(), + self.current_runtime_ctx_ptr().into(), list_value.into(), dict_value.into(), ], @@ -810,7 +840,10 @@ impl<'ctx> TypedResultWalker<'ctx> for LLVMCodeGenContext<'ctx> { ); self.build_void_call( &ApiFunc::kclvm_context_set_kcl_filename.name(), - &[self.native_global_string_value(filename)], + &[ + self.current_runtime_ctx_ptr(), + self.native_global_string_value(filename), + ], ); } // Call self check function @@ -827,7 +860,7 @@ impl<'ctx> TypedResultWalker<'ctx> for LLVMCodeGenContext<'ctx> { &ApiFunc::kclvm_value_check_function_ptr.name(), &[mixin_func], ); - let fn_ty = self.function_type().ptr_type(AddressSpace::Generic); + let fn_ty = self.function_type().ptr_type(AddressSpace::default()); let func_ptr_cast = self.builder.build_bitcast(func_ptr, fn_ty, ""); // Schema check function closure let list_value = self.list_values(&[ @@ -843,7 +876,7 @@ impl<'ctx> TypedResultWalker<'ctx> for LLVMCodeGenContext<'ctx> { CallableValue::try_from(func_ptr_cast.into_pointer_value()) .expect(kcl_error::INTERNAL_ERROR_MSG), &[ - self.global_ctx_ptr().into(), + self.current_runtime_ctx_ptr().into(), list_value.into(), dict_value.into(), ], @@ -851,7 +884,10 @@ impl<'ctx> TypedResultWalker<'ctx> for LLVMCodeGenContext<'ctx> { ); self.build_void_call( &ApiFunc::kclvm_context_set_kcl_filename.name(), - &[self.native_global_string_value(filename)], + &[ + self.current_runtime_ctx_ptr(), + self.native_global_string_value(filename), + ], ); } self.builder.build_return(Some(&schema_value)); @@ -860,10 +896,13 @@ impl<'ctx> TypedResultWalker<'ctx> for LLVMCodeGenContext<'ctx> { } // Build schema attr backtrack functions { - for (k, functions) in place_holder_map { - let stmt_list = body_map.get(&k).expect(kcl_error::INTERNAL_ERROR_MSG); + for (k, functions) in &place_holder_map { + if k == kclvm_runtime::CAL_MAP_INDEX_SIGNATURE { + continue; + } + let stmt_list = body_map.get(k).expect(kcl_error::INTERNAL_ERROR_MSG); let mut if_level = 0; - for (attr_func, stmt) in functions.iter().zip(stmt_list) { + for (attr_func, (stmt, kind)) in functions.iter().zip(stmt_list) { let function = *attr_func; let name = function .get_name() @@ -900,7 +939,10 @@ impl<'ctx> TypedResultWalker<'ctx> for LLVMCodeGenContext<'ctx> { add_variable(value::SCHEMA_RUNTIME_TYPE, self.string_value(&runtime_type)); self.build_void_call( &ApiFunc::kclvm_context_set_kcl_filename.name(), - &[self.native_global_string_value(filename)], + &[ + self.current_runtime_ctx_ptr(), + self.native_global_string_value(filename), + ], ); let schema = self .schema_stack @@ -917,11 +959,12 @@ impl<'ctx> TypedResultWalker<'ctx> for LLVMCodeGenContext<'ctx> { level: if_level, count: 0, stop: false, + kind: kind.clone(), }); } else { if_level = 0; } - self.walk_stmt(*stmt).expect(kcl_error::COMPILE_ERROR_MSG); + self.walk_stmt(stmt).expect(kcl_error::COMPILE_ERROR_MSG); // Backtrack meta end if matches!(&stmt.node, ast::Stmt::If(..)) { *self.backtrack_meta.borrow_mut() = None @@ -935,7 +978,11 @@ impl<'ctx> TypedResultWalker<'ctx> for LLVMCodeGenContext<'ctx> { } } } - let function = self.struct_function_value(&[function, check_function], &runtime_type); + let function = self.struct_function_value( + &[function, check_function], + &place_holder_map, + &runtime_type, + ); self.leave_scope(); self.pop_function(); self.schema_stack.borrow_mut().pop(); @@ -956,7 +1003,7 @@ impl<'ctx> TypedResultWalker<'ctx> for LLVMCodeGenContext<'ctx> { let name = &rule_stmt.name.node; let pkgpath = &self.current_pkgpath(); let filename = &self.current_filename(); - let runtime_type = kclvm::schema_runtime_type(name, pkgpath); + let runtime_type = kclvm_runtime::schema_runtime_type(name, pkgpath); // Build schema body function let function = self.add_function(&format!( "{}.{}", @@ -976,7 +1023,10 @@ impl<'ctx> TypedResultWalker<'ctx> for LLVMCodeGenContext<'ctx> { self.builder.position_at_end(block); self.build_void_call( &ApiFunc::kclvm_context_set_kcl_filename.name(), - &[self.native_global_string_value(filename)], + &[ + self.current_runtime_ctx_ptr(), + self.native_global_string_value(filename), + ], ); let args = function .get_nth_param(1) @@ -986,12 +1036,12 @@ impl<'ctx> TypedResultWalker<'ctx> for LLVMCodeGenContext<'ctx> { .expect(kcl_error::INTERNAL_ERROR_MSG); self.enter_scope(); // Schema function closures - let _instance_pkgpath = self.list_pop(args); + let instance_pkgpath = self.list_pop(args); let record_instance = self.list_pop(args); let backtrack_cache = self.list_pop(args); let backtrack_level_map = self.list_pop(args); let cal_map = self.list_pop(args); - let _attr_optional_mapping = self.list_pop(args); + let attr_optional_mapping = self.list_pop(args); let schema_value = self.list_pop(args); let schema_config = self.list_pop(args); let schema_config_meta = self.list_pop(args); @@ -1013,6 +1063,68 @@ impl<'ctx> TypedResultWalker<'ctx> for LLVMCodeGenContext<'ctx> { let schema = value::SchemaType::new(name, pkgpath, &runtime_type, false); self.schema_stack.borrow_mut().push(schema); add_variable(value::SCHEMA_SELF_NAME, schema_value); + // construct for protocol + let schema_value = if let Some(for_host_name) = &rule_stmt.for_host_name { + let base_constructor_func = self + .walk_identifier_with_ctx(&for_host_name.node, &ast::ExprContext::Load, None) + .expect(kcl_error::COMPILE_ERROR_MSG); + // Schema function closures + let list_value = self.list_values(&[ + // is_sub_schema + self.bool_value(false), + schema_config_meta, + schema_config, + schema_value, + attr_optional_mapping, + cal_map, + backtrack_level_map, + backtrack_cache, + record_instance, + instance_pkgpath, + ]); + let dict_value = self.dict_value(); + let func_ptr = self.build_call( + &ApiFunc::kclvm_value_function_ptr.name(), + &[base_constructor_func], + ); + let fn_ty = self.function_type().ptr_type(AddressSpace::default()); + let func_ptr_cast = self.builder.build_bitcast(func_ptr, fn_ty, ""); + let schema_value = self + .builder + .build_call( + CallableValue::try_from(func_ptr_cast.into_pointer_value()) + .expect(kcl_error::INTERNAL_ERROR_MSG), + &[ + self.current_runtime_ctx_ptr().into(), + list_value.into(), + dict_value.into(), + ], + "", + ) + .try_as_basic_value() + .left() + .expect(kcl_error::FUNCTION_RETURN_VALUE_NOT_FOUND_MSG); + let protocol_name_native_str = + self.native_global_string_value(&for_host_name.node.get_name()); + self.build_void_call( + &ApiFunc::kclvm_schema_value_check.name(), + &[ + self.current_runtime_ctx_ptr(), + schema_value, + schema_config, + schema_config_meta, + protocol_name_native_str, + self.undefined_value(), + self.native_global_string("", "").into(), + self.native_global_string(STR_TYPE_STR, "").into(), + self.native_global_string(ANY_TYPE_STR, "").into(), + self.native_i8(1).into(), + ], + ); + schema_value + } else { + schema_value + }; let do_run_i1 = self.value_is_truthy(record_instance); let do_run_block = self.append_block(""); let end_run_block = self.append_block(""); @@ -1041,24 +1153,15 @@ impl<'ctx> TypedResultWalker<'ctx> for LLVMCodeGenContext<'ctx> { backtrack_cache, ]); let dict_value = self.dict_value(); - // Call schema check block function with index sign attribute name loop set - let check_lambda_fn_ptr = self.builder.build_bitcast( - check_function.as_global_value().as_pointer_value(), - self.context.i64_type().ptr_type(AddressSpace::Generic), - "", - ); - let attr_name = self.native_global_string_value(""); - self.build_void_call( - ApiFunc::kclvm_schema_do_check_with_index_sign_attr - .name() - .as_str(), + // Call schema check block function + self.builder.build_call( + check_function, &[ - self.global_ctx_ptr(), - list_value, - dict_value, - check_lambda_fn_ptr, - attr_name, + self.current_runtime_ctx_ptr().into(), + list_value.into(), + dict_value.into(), ], + "", ); } self.br(end_check_block); @@ -1107,7 +1210,7 @@ impl<'ctx> TypedResultWalker<'ctx> for LLVMCodeGenContext<'ctx> { &ApiFunc::kclvm_value_check_function_ptr.name(), &[base_constructor_func], ); - let fn_ty = self.function_type().ptr_type(AddressSpace::Generic); + let fn_ty = self.function_type().ptr_type(AddressSpace::default()); let func_ptr_cast = self.builder.build_bitcast(func_ptr, fn_ty, ""); // Schema check function closure let list_value = self.list_values(&[ @@ -1123,7 +1226,7 @@ impl<'ctx> TypedResultWalker<'ctx> for LLVMCodeGenContext<'ctx> { CallableValue::try_from(func_ptr_cast.into_pointer_value()) .expect(kcl_error::INTERNAL_ERROR_MSG), &[ - self.global_ctx_ptr().into(), + self.current_runtime_ctx_ptr().into(), list_value.into(), dict_value.into(), ], @@ -1139,7 +1242,8 @@ impl<'ctx> TypedResultWalker<'ctx> for LLVMCodeGenContext<'ctx> { self.builder.position_at_end(func_before_block); self.pop_function(); } - let function = self.struct_function_value(&[function, check_function], &runtime_type); + let function = + self.struct_function_value(&[function, check_function], &HashMap::new(), &runtime_type); self.leave_scope(); self.pop_function(); self.schema_stack.borrow_mut().pop(); @@ -1161,6 +1265,7 @@ impl<'ctx> TypedResultWalker<'ctx> for LLVMCodeGenContext<'ctx> { utils::update_ctx_filename(self, expr); utils::update_ctx_line_col(self, expr); match &expr.node { + ast::Expr::Target(target) => self.walk_target(target), ast::Expr::Identifier(identifier) => self.walk_identifier(identifier), ast::Expr::Unary(unary_expr) => self.walk_unary_expr(unary_expr), ast::Expr::Binary(binary_expr) => self.walk_binary_expr(binary_expr), @@ -1197,6 +1302,7 @@ impl<'ctx> TypedResultWalker<'ctx> for LLVMCodeGenContext<'ctx> { ast::Expr::FormattedValue(formatted_value) => { self.walk_formatted_value(formatted_value) } + ast::Expr::Missing(missing_expr) => self.walk_missing_expr(missing_expr), } } @@ -1248,14 +1354,14 @@ impl<'ctx> TypedResultWalker<'ctx> for LLVMCodeGenContext<'ctx> { { let mut local_vars = self.local_vars.borrow_mut(); for v in variables { - let name = &v.node.names[0]; + let name = &v.node.names[0].node; local_vars.insert(name.clone()); } } if variables.len() == 1 { // Store the target self.walk_identifier_with_ctx( - &variables.get(0).expect(kcl_error::INTERNAL_ERROR_MSG).node, + &variables.first().expect(kcl_error::INTERNAL_ERROR_MSG).node, &ast::ExprContext::Store, Some(next_value), ) @@ -1264,7 +1370,7 @@ impl<'ctx> TypedResultWalker<'ctx> for LLVMCodeGenContext<'ctx> { let value = self.build_call(&ApiFunc::kclvm_iterator_cur_value.name(), &[iter_value]); // Store the target self.walk_identifier_with_ctx( - &variables.get(0).expect(kcl_error::INTERNAL_ERROR_MSG).node, + &variables.first().expect(kcl_error::INTERNAL_ERROR_MSG).node, &ast::ExprContext::Store, Some(key), ) @@ -1336,6 +1442,7 @@ impl<'ctx> TypedResultWalker<'ctx> for LLVMCodeGenContext<'ctx> { ]); self.leave_scope(); self.local_vars.borrow_mut().clear(); + self.build_void_call(&ApiFunc::kclvm_iterator_delete.name(), &[iter_value]); Ok(phi.as_basic_value()) } @@ -1348,10 +1455,6 @@ impl<'ctx> TypedResultWalker<'ctx> for LLVMCodeGenContext<'ctx> { self.walk_decorator_with_name(&decorator.node, Some(name), false) .expect(kcl_error::COMPILE_ERROR_MSG); } - let value = match &schema_attr.value { - Some(value) => self.walk_expr(value).expect(kcl_error::COMPILE_ERROR_MSG), - None => self.undefined_value(), - }; let config_value = self .get_variable(value::SCHEMA_CONFIG_NAME) .expect(kcl_error::INTERNAL_ERROR_MSG); @@ -1360,28 +1463,12 @@ impl<'ctx> TypedResultWalker<'ctx> for LLVMCodeGenContext<'ctx> { .expect(kcl_error::INTERNAL_ERROR_MSG); let string_ptr_value = self.native_global_string(name, "").into(); let type_str_ptr_value = self - .native_global_string(&schema_attr.type_str.node, "") + .native_global_string(&schema_attr.ty.node.to_string(), "") .into(); self.build_void_call( &ApiFunc::kclvm_config_attr_map.name(), &[schema_value, string_ptr_value, type_str_ptr_value], ); - if let Some(op) = &schema_attr.op { - match op { - // Union - ast::BinOrAugOp::Aug(ast::AugOp::BitOr) => { - let org_value = self.build_call( - &ApiFunc::kclvm_dict_get_value.name(), - &[schema_value, string_ptr_value], - ); - let fn_name = ApiFunc::kclvm_value_op_bit_or; - let value = self.build_call(&fn_name.name(), &[org_value, value]); - self.dict_merge(schema_value, name, value, 1, -1); - } - // Assign - _ => self.dict_merge(schema_value, name, value, 1, -1), - } - } let has_key = self .build_call( &ApiFunc::kclvm_dict_has_value.name(), @@ -1393,13 +1480,69 @@ impl<'ctx> TypedResultWalker<'ctx> for LLVMCodeGenContext<'ctx> { .build_int_compare(IntPredicate::NE, has_key, self.native_i8_zero(), ""); let then_block = self.append_block(""); let else_block = self.append_block(""); + let end_block = self.append_block(""); self.builder .build_conditional_branch(has_key, then_block, else_block); self.builder.position_at_end(then_block); let config_attr_value = self.build_call( &ApiFunc::kclvm_dict_get_entry.name(), - &[config_value, string_ptr_value], + &[ + self.current_runtime_ctx_ptr(), + config_value, + string_ptr_value, + ], ); + // If the attribute operator is not `=`, eval the schema attribute value. + // if is_not_override: + let is_override_attr = self + .build_call( + &ApiFunc::kclvm_dict_is_override_attr.name(), + &[config_value, string_ptr_value], + ) + .into_int_value(); + let is_not_override_attr = self.builder.build_int_compare( + IntPredicate::EQ, + is_override_attr, + self.native_i8_zero(), + "", + ); + let is_not_override_then_block = self.append_block(""); + let is_not_override_else_block = self.append_block(""); + self.builder.build_conditional_branch( + is_not_override_attr, + is_not_override_then_block, + is_not_override_else_block, + ); + self.builder.position_at_end(is_not_override_then_block); + let value = match &schema_attr.value { + Some(value) => self.walk_expr(value).expect(kcl_error::COMPILE_ERROR_MSG), + None => self.undefined_value(), + }; + if let Some(op) = &schema_attr.op { + match op { + // Union + ast::AugOp::BitOr => { + let org_value = self.build_call( + &ApiFunc::kclvm_dict_get_value.name(), + &[ + self.current_runtime_ctx_ptr(), + schema_value, + string_ptr_value, + ], + ); + let fn_name = ApiFunc::kclvm_value_op_bit_or; + let value = self.build_call( + &fn_name.name(), + &[self.current_runtime_ctx_ptr(), org_value, value], + ); + self.dict_merge(schema_value, name, value, 1, None); + } + // Assign + _ => self.dict_merge(schema_value, name, value, 1, None), + } + } + self.br(is_not_override_else_block); + self.builder.position_at_end(is_not_override_else_block); self.value_union(schema_value, config_attr_value); let cal_map = self .get_variable(value::SCHEMA_CAL_MAP) @@ -1413,6 +1556,7 @@ impl<'ctx> TypedResultWalker<'ctx> for LLVMCodeGenContext<'ctx> { self.build_void_call( &ApiFunc::kclvm_schema_backtrack_cache.name(), &[ + self.current_runtime_ctx_ptr(), schema_value, backtrack_cache, cal_map, @@ -1421,20 +1565,41 @@ impl<'ctx> TypedResultWalker<'ctx> for LLVMCodeGenContext<'ctx> { ], ); // Update backtrack meta - { - if let Some(backtrack_meta) = self.backtrack_meta.borrow_mut().as_mut() { - if name == backtrack_meta.target { - backtrack_meta.count += 1; - if backtrack_meta.count >= backtrack_meta.level { - backtrack_meta.stop = true; - self.ret(schema_value); - return Ok(schema_value); - } + if self.update_backtrack_meta(name, schema_value) { + return Ok(schema_value); + } + self.br(end_block); + self.builder.position_at_end(else_block); + // Lazy eval for the schema attribute. + let value = match &schema_attr.value { + Some(value) => self.walk_expr(value).expect(kcl_error::COMPILE_ERROR_MSG), + None => self.undefined_value(), + }; + if let Some(op) = &schema_attr.op { + match op { + // Union + ast::AugOp::BitOr => { + let org_value = self.build_call( + &ApiFunc::kclvm_dict_get_value.name(), + &[ + self.current_runtime_ctx_ptr(), + schema_value, + string_ptr_value, + ], + ); + let fn_name = ApiFunc::kclvm_value_op_bit_or; + let value = self.build_call( + &fn_name.name(), + &[self.current_runtime_ctx_ptr(), org_value, value], + ); + self.dict_merge(schema_value, name, value, 1, None); } + // Assign + _ => self.dict_merge(schema_value, name, value, 1, None), } } - self.br(else_block); - self.builder.position_at_end(else_block); + self.br(end_block); + self.builder.position_at_end(end_block); Ok(schema_value) } @@ -1488,16 +1653,13 @@ impl<'ctx> TypedResultWalker<'ctx> for LLVMCodeGenContext<'ctx> { ast::UnaryOp::Invert => ApiFunc::kclvm_value_unary_not, ast::UnaryOp::Not => ApiFunc::kclvm_value_unary_l_not, }; - Ok(self.build_call(&fn_name.name(), &[value])) + Ok(self.build_call(&fn_name.name(), &[self.current_runtime_ctx_ptr(), value])) } fn walk_binary_expr(&self, binary_expr: &'ctx ast::BinaryExpr) -> Self::Result { check_backtrack_stop!(self); - let is_logic_op = matches!( - binary_expr.op, - ast::BinOrCmpOp::Bin(ast::BinOp::And) | ast::BinOrCmpOp::Bin(ast::BinOp::Or) - ); - let is_membership_as_op = matches!(binary_expr.op, ast::BinOrCmpOp::Bin(ast::BinOp::As)); + let is_logic_op = matches!(binary_expr.op, ast::BinOp::And | ast::BinOp::Or); + let is_membership_as_op = matches!(binary_expr.op, ast::BinOp::As); if !is_logic_op { let left_value = self .walk_expr(&binary_expr.left) @@ -1505,7 +1667,7 @@ impl<'ctx> TypedResultWalker<'ctx> for LLVMCodeGenContext<'ctx> { let right_value = if is_membership_as_op { match &binary_expr.right.node { ast::Expr::Identifier(id) => { - let name = id.names.join("."); + let name = id.get_names().join("."); self.string_value(&name) } _ => self.none_value(), @@ -1515,50 +1677,25 @@ impl<'ctx> TypedResultWalker<'ctx> for LLVMCodeGenContext<'ctx> { .expect(kcl_error::COMPILE_ERROR_MSG) }; let value = match binary_expr.op { - ast::BinOrCmpOp::Bin(ast::BinOp::Add) => self.add(left_value, right_value), - ast::BinOrCmpOp::Bin(ast::BinOp::Sub) => self.sub(left_value, right_value), - ast::BinOrCmpOp::Bin(ast::BinOp::Mul) => self.mul(left_value, right_value), - ast::BinOrCmpOp::Bin(ast::BinOp::Div) => self.div(left_value, right_value), - ast::BinOrCmpOp::Bin(ast::BinOp::FloorDiv) => { - self.floor_div(left_value, right_value) - } - ast::BinOrCmpOp::Bin(ast::BinOp::Mod) => self.r#mod(left_value, right_value), - ast::BinOrCmpOp::Bin(ast::BinOp::Pow) => self.pow(left_value, right_value), - ast::BinOrCmpOp::Bin(ast::BinOp::LShift) => { - self.bit_lshift(left_value, right_value) - } - ast::BinOrCmpOp::Bin(ast::BinOp::RShift) => { - self.bit_rshift(left_value, right_value) - } - ast::BinOrCmpOp::Bin(ast::BinOp::BitAnd) => self.bit_and(left_value, right_value), - ast::BinOrCmpOp::Bin(ast::BinOp::BitOr) => self.bit_or(left_value, right_value), - ast::BinOrCmpOp::Bin(ast::BinOp::BitXor) => self.bit_xor(left_value, right_value), - ast::BinOrCmpOp::Bin(ast::BinOp::And) => self.logic_and(left_value, right_value), - ast::BinOrCmpOp::Bin(ast::BinOp::Or) => self.logic_or(left_value, right_value), - ast::BinOrCmpOp::Bin(ast::BinOp::As) => self.r#as(left_value, right_value), - ast::BinOrCmpOp::Cmp(ast::CmpOp::Eq) => self.cmp_equal_to(left_value, right_value), - ast::BinOrCmpOp::Cmp(ast::CmpOp::NotEq) => { - self.cmp_not_equal_to(left_value, right_value) - } - ast::BinOrCmpOp::Cmp(ast::CmpOp::Gt) => { - self.cmp_greater_than(left_value, right_value) - } - ast::BinOrCmpOp::Cmp(ast::CmpOp::GtE) => { - self.cmp_greater_than_or_equal(left_value, right_value) - } - ast::BinOrCmpOp::Cmp(ast::CmpOp::Lt) => self.cmp_less_than(left_value, right_value), - ast::BinOrCmpOp::Cmp(ast::CmpOp::LtE) => { - self.cmp_less_than_or_equal(left_value, right_value) - } - ast::BinOrCmpOp::Cmp(ast::CmpOp::Is) => self.is(left_value, right_value), - ast::BinOrCmpOp::Cmp(ast::CmpOp::IsNot) => self.is_not(left_value, right_value), - ast::BinOrCmpOp::Cmp(ast::CmpOp::Not) => self.is_not(left_value, right_value), - ast::BinOrCmpOp::Cmp(ast::CmpOp::NotIn) => self.not_in(left_value, right_value), - ast::BinOrCmpOp::Cmp(ast::CmpOp::In) => self.r#in(left_value, right_value), + ast::BinOp::Add => self.add(left_value, right_value), + ast::BinOp::Sub => self.sub(left_value, right_value), + ast::BinOp::Mul => self.mul(left_value, right_value), + ast::BinOp::Div => self.div(left_value, right_value), + ast::BinOp::FloorDiv => self.floor_div(left_value, right_value), + ast::BinOp::Mod => self.r#mod(left_value, right_value), + ast::BinOp::Pow => self.pow(left_value, right_value), + ast::BinOp::LShift => self.bit_lshift(left_value, right_value), + ast::BinOp::RShift => self.bit_rshift(left_value, right_value), + ast::BinOp::BitAnd => self.bit_and(left_value, right_value), + ast::BinOp::BitOr => self.bit_or(left_value, right_value), + ast::BinOp::BitXor => self.bit_xor(left_value, right_value), + ast::BinOp::And => self.logic_and(left_value, right_value), + ast::BinOp::Or => self.logic_or(left_value, right_value), + ast::BinOp::As => self.r#as(left_value, right_value), }; Ok(value) } else { - let jump_if_false = matches!(binary_expr.op, ast::BinOrCmpOp::Bin(ast::BinOp::And)); + let jump_if_false = matches!(binary_expr.op, ast::BinOp::And); let start_block = self.append_block(""); let value_block = self.append_block(""); let end_block = self.append_block(""); @@ -1600,19 +1737,22 @@ impl<'ctx> TypedResultWalker<'ctx> for LLVMCodeGenContext<'ctx> { .walk_expr(&selector_expr.value) .expect(kcl_error::COMPILE_ERROR_MSG); let string_ptr_value = self - .native_global_string(selector_expr.attr.node.names[0].as_str(), "") + .native_global_string(selector_expr.attr.node.names[0].node.as_str(), "") .into(); let fn_name = if selector_expr.has_question { &ApiFunc::kclvm_value_load_attr_option } else { &ApiFunc::kclvm_value_load_attr }; - value = self.build_call(&fn_name.name(), &[value, string_ptr_value]); + value = self.build_call( + &fn_name.name(), + &[self.current_runtime_ctx_ptr(), value, string_ptr_value], + ); for name in &selector_expr.attr.node.names[1..] { - let string_ptr_value = self.native_global_string(name, "").into(); + let string_ptr_value = self.native_global_string(&name.node, "").into(); value = self.build_call( &ApiFunc::kclvm_value_load_attr.name(), - &[value, string_ptr_value], + &[self.current_runtime_ctx_ptr(), value, string_ptr_value], ); } Ok(value) @@ -1638,12 +1778,20 @@ impl<'ctx> TypedResultWalker<'ctx> for LLVMCodeGenContext<'ctx> { } else { self.none_value() }; - self.dict_insert(dict_value, name.as_str(), value, 0, -1); + self.dict_insert(dict_value, name.node.as_str(), value, 0, None); } let pkgpath = self.native_global_string_value(&self.current_pkgpath()); + let is_in_schema = self.is_in_schema() || self.is_in_schema_expr(); Ok(self.build_call( &ApiFunc::kclvm_value_function_invoke.name(), - &[func, self.global_ctx_ptr(), list_value, dict_value, pkgpath], + &[ + func, + self.current_runtime_ctx_ptr(), + list_value, + dict_value, + pkgpath, + self.bool_value(is_in_schema), + ], )) } @@ -1660,7 +1808,10 @@ impl<'ctx> TypedResultWalker<'ctx> for LLVMCodeGenContext<'ctx> { } else { &ApiFunc::kclvm_value_subscr }; - value = self.build_call(&fn_name.name(), &[value, index]); + value = self.build_call( + &fn_name.name(), + &[self.current_runtime_ctx_ptr(), value, index], + ); } else { let lower = { if let Some(lower) = &subscript.lower { @@ -1688,7 +1839,10 @@ impl<'ctx> TypedResultWalker<'ctx> for LLVMCodeGenContext<'ctx> { } else { &ApiFunc::kclvm_value_slice }; - value = self.build_call(&fn_name.name(), &[value, lower, upper, step]); + value = self.build_call( + &fn_name.name(), + &[self.current_runtime_ctx_ptr(), value, lower, upper, step], + ); } Ok(value) } @@ -1822,59 +1976,11 @@ impl<'ctx> TypedResultWalker<'ctx> for LLVMCodeGenContext<'ctx> { let else_block = self.append_block(""); let end_block = self.append_block(""); let is_truth = self.value_is_truthy(cond); + self.emit_config_if_entry_expr_vars(config_if_entry_expr); let tpe = self.value_ptr_type(); self.cond_br(is_truth, then_block, else_block); self.builder.position_at_end(then_block); - let then_value = self.dict_value(); - for item in &config_if_entry_expr.items { - let key = &item.node.key; - let value = &item.node.value; - let op = &item.node.operation; - let value = self.walk_expr(value).expect(kcl_error::COMPILE_ERROR_MSG); - if let Some(key) = key { - let mut insert_index = -1; - let key = match &key.node { - ast::Expr::Identifier(identifier) => { - let name = &identifier.names[0]; - self.string_value(name) - } - ast::Expr::StringLit(string_lit) => { - self.string_value(string_lit.value.as_str()) - } - ast::Expr::Subscript(subscript) => match &subscript.value.node { - ast::Expr::Identifier(identifier) => { - let has_index = match &subscript.index { - Some(index) => match &index.node { - ast::Expr::NumberLit(v) => match &v.value { - ast::NumberLitValue::Int(v) => { - insert_index = *v as i32; - true - } - _ => false, - }, - _ => false, - }, - _ => false, - }; - if has_index { - let name = &identifier.names[0]; - self.string_value(name) - } else { - self.walk_expr(key).expect(kcl_error::COMPILE_ERROR_MSG) - } - } - _ => self.walk_expr(key).expect(kcl_error::COMPILE_ERROR_MSG), - }, - _ => self.walk_expr(key).expect(kcl_error::COMPILE_ERROR_MSG), - }; - self.dict_insert_with_key_value(then_value, key, value, op.value(), insert_index); - } else { - self.build_void_call( - &ApiFunc::kclvm_dict_insert_unpack.name(), - &[then_value, value], - ); - } - } + let then_value = self.walk_config_entries(&config_if_entry_expr.items)?; let then_block = self.append_block(""); self.br(then_block); self.builder.position_at_end(then_block); @@ -1884,7 +1990,13 @@ impl<'ctx> TypedResultWalker<'ctx> for LLVMCodeGenContext<'ctx> { self.br(end_block); self.builder.position_at_end(else_block); let else_value = if let Some(orelse) = &config_if_entry_expr.orelse { - self.walk_expr(orelse).expect(kcl_error::COMPILE_ERROR_MSG) + // Config expr or config if entry expr. + if let ast::Expr::Config(config_expr) = &orelse.node { + self.walk_config_entries(&config_expr.items) + .expect(kcl_error::COMPILE_ERROR_MSG) + } else { + self.walk_expr(orelse).expect(kcl_error::COMPILE_ERROR_MSG) + } } else { self.none_value() }; @@ -1908,6 +2020,12 @@ impl<'ctx> TypedResultWalker<'ctx> for LLVMCodeGenContext<'ctx> { fn walk_schema_expr(&self, schema_expr: &'ctx ast::SchemaExpr) -> Self::Result { check_backtrack_stop!(self); + // Check the required attributes only when the values of all attributes + // in the final schema are solved. + let is_in_schema = self.is_in_schema() || self.is_in_schema_expr(); + { + self.schema_expr_stack.borrow_mut().push(()); + } let config_value = self .walk_expr(&schema_expr.config) .expect(kcl_error::COMPILE_ERROR_MSG); @@ -1932,13 +2050,13 @@ impl<'ctx> TypedResultWalker<'ctx> for LLVMCodeGenContext<'ctx> { } else { self.none_value() }; - self.dict_insert(dict_value, name.as_str(), value, 0, -1); + self.dict_insert(dict_value, name.node.as_str(), value, 0, None); } let pkgpath = self.native_global_string_value(&self.current_pkgpath()); let schema = self.build_call( &ApiFunc::kclvm_schema_value_new.name(), &[ - self.global_ctx_ptr(), + self.current_runtime_ctx_ptr(), list_value, dict_value, schema_type, @@ -1947,62 +2065,25 @@ impl<'ctx> TypedResultWalker<'ctx> for LLVMCodeGenContext<'ctx> { pkgpath, ], ); + if !is_in_schema { + self.build_void_call( + &ApiFunc::kclvm_schema_optional_check.name(), + &[self.current_runtime_ctx_ptr(), schema], + ); + } utils::update_ctx_filename(self, &schema_expr.config); + { + self.schema_expr_stack.borrow_mut().pop(); + } Ok(schema) } fn walk_config_expr(&self, config_expr: &'ctx ast::ConfigExpr) -> Self::Result { check_backtrack_stop!(self); - let config_value = self.dict_value(); - for item in &config_expr.items { - let value = &item.node.value; - let op = &item.node.operation; - let value = self.walk_expr(value).expect(kcl_error::COMPILE_ERROR_MSG); - if let Some(key) = &item.node.key { - let mut insert_index = -1; - let key = match &key.node { - ast::Expr::Identifier(identifier) => { - let name = &identifier.names[0]; - self.string_value(name) - } - ast::Expr::StringLit(string_lit) => { - self.string_value(string_lit.value.as_str()) - } - ast::Expr::Subscript(subscript) => match &subscript.value.node { - ast::Expr::Identifier(identifier) => { - let has_index = match &subscript.index { - Some(index) => match &index.node { - ast::Expr::NumberLit(v) => match &v.value { - ast::NumberLitValue::Int(v) => { - insert_index = *v as i32; - true - } - _ => false, - }, - _ => false, - }, - _ => false, - }; - if has_index { - let name = &identifier.names[0]; - self.string_value(name) - } else { - self.walk_expr(key).expect(kcl_error::COMPILE_ERROR_MSG) - } - } - _ => self.walk_expr(key).expect(kcl_error::COMPILE_ERROR_MSG), - }, - _ => self.walk_expr(key).expect(kcl_error::COMPILE_ERROR_MSG), - }; - self.dict_insert_with_key_value(config_value, key, value, op.value(), insert_index); - } else { - self.build_void_call( - &ApiFunc::kclvm_dict_insert_unpack.name(), - &[config_value, value], - ); - } - } - Ok(config_value) + self.enter_scope(); + let result = self.walk_config_entries(&config_expr.items); + self.leave_scope(); + result } fn walk_check_expr(&self, check_expr: &'ctx ast::CheckExpr) -> Self::Result { @@ -2033,7 +2114,12 @@ impl<'ctx> TypedResultWalker<'ctx> for LLVMCodeGenContext<'ctx> { utils::update_ctx_current_line(self); self.build_void_call( &ApiFunc::kclvm_schema_assert.name(), - &[check_result, msg, schema_config_meta], + &[ + self.current_runtime_ctx_ptr(), + check_result, + msg, + schema_config_meta, + ], ); self.br(end_block); self.builder.position_at_end(end_block); @@ -2042,13 +2128,22 @@ impl<'ctx> TypedResultWalker<'ctx> for LLVMCodeGenContext<'ctx> { fn walk_lambda_expr(&self, lambda_expr: &'ctx ast::LambdaExpr) -> Self::Result { check_backtrack_stop!(self); - let is_in_schema = self.schema_stack.borrow().len() > 0; + let pkgpath = &self.current_pkgpath(); + // Higher-order lambda requires capturing the current lambda closure variable + // as well as the closure of a more external scope. + let last_closure_map = self.get_current_inner_scope_variable_map(); let func_before_block = self.append_block(""); self.br(func_before_block); - let function = self.add_function(value::LAMBDA_NAME); + // Use "pkgpath"+"kclvm_lambda" to name 'function' to prevent conflicts between lambdas with the same name in different packages + let function = self.add_function(&format!( + "{}.{}", + pkgpath_without_prefix!(pkgpath), + value::LAMBDA_NAME + )); // Enter the function self.push_function(function); - self.lambda_stack.borrow_mut().push(true); + // Push the current lambda scope level in the lambda stack. + self.push_lambda(self.scope_level() + 1); // Lambda function body let block = self.context.append_basic_block(function, ENTRY_NAME); self.builder.position_at_end(block); @@ -2064,35 +2159,52 @@ impl<'ctx> TypedResultWalker<'ctx> for LLVMCodeGenContext<'ctx> { let var = self.builder.build_alloca(tpe, value::LAMBDA_CLOSURE); self.builder.build_store(var, closure_map); self.add_variable(value::LAMBDA_CLOSURE, var); - if is_in_schema { - let string_ptr_value = self - .native_global_string(value::SCHEMA_SELF_NAME, "") - .into(); - let schema_value = self.build_call( - &ApiFunc::kclvm_dict_get_value.name(), - &[closure_map, string_ptr_value], - ); - let value_ptr_type = self.value_ptr_type(); - let var = self - .builder - .build_alloca(value_ptr_type, value::SCHEMA_SELF_NAME); - self.builder.build_store(var, schema_value); - self.add_variable(value::SCHEMA_SELF_NAME, var); + if self.is_in_schema() { + for schema_closure_name in value::SCHEMA_VARIABLE_LIST { + let string_ptr_value = self.native_global_string(schema_closure_name, "").into(); + let schema_value = self.build_call( + &ApiFunc::kclvm_dict_get_value.name(), + &[ + self.current_runtime_ctx_ptr(), + closure_map, + string_ptr_value, + ], + ); + let value_ptr_type = self.value_ptr_type(); + let var = self + .builder + .build_alloca(value_ptr_type, schema_closure_name); + self.builder.build_store(var, schema_value); + self.add_variable(schema_closure_name, var); + } } self.walk_arguments(&lambda_expr.args, args, kwargs); - let val = self + let mut val = self .walk_stmts(&lambda_expr.body) .expect(kcl_error::COMPILE_ERROR_MSG); + if let Some(ty) = &lambda_expr.return_ty { + let type_annotation = self.native_global_string_value(&ty.node.to_string()); + val = self.build_call( + &ApiFunc::kclvm_convert_collection_value.name(), + &[ + self.current_runtime_ctx_ptr(), + val, + type_annotation, + self.bool_value(false), + ], + ); + } self.builder.build_return(Some(&val)); // Exist the function self.builder.position_at_end(func_before_block); let closure = self.list_value(); - let dict_value = self.get_closure_dict_in_current_scope(); - self.list_append(closure, dict_value); + // Use closure map in the last scope to construct current closure map. + // The default value of the closure map is `{}`. + self.list_append(closure, last_closure_map); let function = self.closure_value(function, closure); self.leave_scope(); self.pop_function(); - self.lambda_stack.borrow_mut().pop(); + self.pop_lambda(); Ok(function) } @@ -2136,7 +2248,10 @@ impl<'ctx> TypedResultWalker<'ctx> for LLVMCodeGenContext<'ctx> { ast::CmpOp::NotIn => ApiFunc::kclvm_value_not_in, ast::CmpOp::In => ApiFunc::kclvm_value_in, }; - let result_value = self.build_call(&fn_name.name(), &[left_value, right_value]); + let result_value = self.build_call( + &fn_name.name(), + &[self.current_runtime_ctx_ptr(), left_value, right_value], + ); let is_truth = self.value_is_truthy(result_value); left_value = right_value; // Get next value using a store/load temp block @@ -2179,7 +2294,10 @@ impl<'ctx> TypedResultWalker<'ctx> for LLVMCodeGenContext<'ctx> { ast::CmpOp::NotIn => ApiFunc::kclvm_value_not_in, ast::CmpOp::In => ApiFunc::kclvm_value_in, }; - left_value = self.build_call(&fn_name.name(), &[left_value, right_value]); + left_value = self.build_call( + &fn_name.name(), + &[self.current_runtime_ctx_ptr(), left_value, right_value], + ); Ok(left_value) } } @@ -2189,13 +2307,19 @@ impl<'ctx> TypedResultWalker<'ctx> for LLVMCodeGenContext<'ctx> { self.walk_identifier_with_ctx(identifier, &identifier.ctx, None) } + #[inline] + fn walk_target(&self, target: &'ctx ast::Target) -> Self::Result { + check_backtrack_stop!(self); + self.load_target(target) + } + fn walk_number_lit(&self, number_lit: &'ctx ast::NumberLit) -> Self::Result { check_backtrack_stop!(self); match number_lit.value { ast::NumberLitValue::Int(int_value) => match &number_lit.binary_suffix { Some(binary_suffix) => { let unit = binary_suffix.value(); - let value = kclvm::cal_num(int_value, unit.as_str()); + let value = kclvm_runtime::cal_num(int_value, unit.as_str()); Ok(self.unit_value(value, int_value, &unit)) } None => Ok(self.int_value(int_value)), @@ -2209,7 +2333,10 @@ impl<'ctx> TypedResultWalker<'ctx> for LLVMCodeGenContext<'ctx> { let string_ptr_value = self .native_global_string(string_lit.value.as_str(), "") .into(); - Ok(self.build_call(&ApiFunc::kclvm_value_Str.name(), &[string_ptr_value])) + Ok(self.build_call( + &ApiFunc::kclvm_value_Str.name(), + &[self.current_runtime_ctx_ptr(), string_ptr_value], + )) } fn walk_name_constant_lit( @@ -2239,8 +2366,10 @@ impl<'ctx> TypedResultWalker<'ctx> for LLVMCodeGenContext<'ctx> { .expect(kcl_error::INTERNAL_ERROR_MSG), _ => panic!("{}", kcl_error::INVALID_JOINED_STR_MSG), }; - result_value = - self.build_call(&ApiFunc::kclvm_value_op_add.name(), &[result_value, value]); + result_value = self.build_call( + &ApiFunc::kclvm_value_op_add.name(), + &[self.current_runtime_ctx_ptr(), result_value, value], + ); } Ok(result_value) } @@ -2258,7 +2387,10 @@ impl<'ctx> TypedResultWalker<'ctx> for LLVMCodeGenContext<'ctx> { _ => panic!("{}", kcl_error::INVALID_STR_INTERPOLATION_SPEC_MSG), }; } - Ok(self.build_call(&fn_name.name(), &[formatted_expr_value])) + Ok(self.build_call( + &fn_name.name(), + &[self.current_runtime_ctx_ptr(), formatted_expr_value], + )) } fn walk_comment(&self, _comment: &'ctx ast::Comment) -> Self::Result { @@ -2266,14 +2398,15 @@ impl<'ctx> TypedResultWalker<'ctx> for LLVMCodeGenContext<'ctx> { self.ok_result() } + fn walk_missing_expr(&self, _missing_expr: &'ctx ast::MissingExpr) -> Self::Result { + Err(kcl_error::KCLError::new( + "compile error: missing expression", + )) + } + fn walk_module(&self, module: &'ctx ast::Module) -> Self::Result { check_backtrack_stop!(self); - if !module.body.is_empty() { - utils::update_ctx_filename(self, &module.body[0]); - } - // Compile all schema and rule firstly - self.compile_module_import_and_types(module); - // Compile all statements of the module + // Compile all statements of the module except all import statements self.walk_stmts_except_import(&module.body) } } @@ -2303,6 +2436,107 @@ impl<'ctx> LLVMCodeGenContext<'ctx> { result } + pub fn walk_target_with_value( + &self, + target: &'ctx ast::Target, + right_value: BasicValueEnum<'ctx>, + ) -> CompileResult<'ctx> { + check_backtrack_stop!(self); + let is_in_schema = self.is_in_schema(); + if target.paths.is_empty() { + let name = target.get_name(); + let tpe = self.value_ptr_type(); + // Global variables + if self.scope_level() == GLOBAL_LEVEL { + self.add_or_update_global_variable(name, right_value, true); + // Lambda local variables. + } else if self.is_in_lambda() { + let value = right_value; + // If variable exists in the scope and update it, if not, add it to the scope. + if !self.store_variable_in_current_scope(name, value) { + let cur_bb = self.builder.get_insert_block().unwrap(); + let lambda_func = cur_bb.get_parent().unwrap(); + let entry_bb = lambda_func.get_first_basic_block().unwrap(); + match entry_bb.get_first_instruction() { + Some(inst) => self.builder.position_before(&inst), + None => self.builder.position_at_end(entry_bb), + }; + let var = self.builder.build_alloca(tpe, name); + let undefined_val = self.undefined_value(); + self.builder.build_store(var, undefined_val); + self.add_variable(name, var); + self.builder.position_at_end(cur_bb); + self.store_variable(name, value); + } + } else { + let is_local_var = self.is_local_var(name); + let value = right_value; + // Store schema attribute + if is_in_schema { + let schema_value = self.get_variable(value::SCHEMA_SELF_NAME)?; + // Schema config + let config_value = self.get_variable(value::SCHEMA_CONFIG_NAME)?; + // If is in the backtrack, return the schema value. + if self.update_schema_scope_value(schema_value, config_value, name, Some(value)) + { + return Ok(schema_value); + } + } + // Store loop variable + if is_local_var || !is_in_schema { + let var = self.builder.build_alloca(tpe, name); + self.builder.build_store(var, value); + self.add_variable(name, var); + } + } + } else { + let name = target.get_name(); + // In KCL, we cannot modify global variables in other packages, + // so pkgpath is empty here. + let mut value = self + .load_value("", &[name]) + .expect(kcl_error::INTERNAL_ERROR_MSG); + // Convert `store a.b.c = 1` -> `%t = load &a; %t = load_attr %t %b; store_attr %t %c with 1` + for (i, path) in target.paths.iter().enumerate() { + let ctx = if i < target.paths.len() - 1 { + ast::ExprContext::Load + } else { + ast::ExprContext::Store + }; + match ctx { + ast::ExprContext::Load => { + value = self.load_target_path(value, path)?; + } + ast::ExprContext::Store => { + self.store_target_path(value, path, right_value)?; + + let is_local_var = self.is_local_var(name); + let is_in_lambda = self.is_in_lambda(); + // Set config value for the schema attribute if the attribute is in the schema and + // it is not a local variable in the lambda function. + if self.scope_level() >= INNER_LEVEL + && is_in_schema + && !is_in_lambda + && !is_local_var + { + let schema_value = self.get_variable(value::SCHEMA_SELF_NAME)?; + let config_value = self.get_variable(value::SCHEMA_CONFIG_NAME)?; + if self.update_schema_scope_value( + schema_value, + config_value, + name, + None, + ) { + return Ok(schema_value); + } + } + } + } + } + } + Ok(right_value) + } + pub fn walk_identifier_with_ctx( &self, identifier: &'ctx ast::Identifier, @@ -2310,124 +2544,62 @@ impl<'ctx> LLVMCodeGenContext<'ctx> { right_value: Option>, ) -> CompileResult<'ctx> { check_backtrack_stop!(self); - let is_in_schema = self.schema_stack.borrow().len() > 0; + let is_in_schema = self.is_in_schema(); match identifier_ctx { + // Store a.b.c = 1 ast::ExprContext::Store => { if identifier.names.len() == 1 { - let name = identifier.names[0].as_str(); + let name = identifier.names[0].node.as_str(); let tpe = self.value_ptr_type(); // Global variables if self.scope_level() == GLOBAL_LEVEL { self.add_or_update_global_variable( name, right_value.expect(kcl_error::INTERNAL_ERROR_MSG), + true, ); - // Local variables including schema/rule/lambda - } else if *self - .lambda_stack - .borrow_mut() - .last() - .expect(kcl_error::INTERNAL_ERROR_MSG) - { + // Lambda local variables. + } else if self.is_in_lambda() { let value = right_value.expect(kcl_error::INTERNAL_ERROR_MSG); // If variable exists in the scope and update it, if not, add it to the scope. if !self.store_variable_in_current_scope(name, value) { + let cur_bb = self.builder.get_insert_block().unwrap(); + let lambda_func = cur_bb.get_parent().unwrap(); + let entry_bb = lambda_func.get_first_basic_block().unwrap(); + match entry_bb.get_first_instruction() { + Some(inst) => self.builder.position_before(&inst), + None => self.builder.position_at_end(entry_bb), + }; let var = self.builder.build_alloca(tpe, name); - self.builder.build_store(var, value); + let undefined_val = self.undefined_value(); + self.builder.build_store(var, undefined_val); self.add_variable(name, var); + self.builder.position_at_end(cur_bb); self.store_variable(name, value); } } else { - let is_local_var = { - let local_vars = self.local_vars.borrow_mut(); - local_vars.contains(name) - }; - let value = if is_in_schema { - let value = right_value.expect(kcl_error::INTERNAL_ERROR_MSG); + let is_local_var = self.is_local_var(name); + let value = right_value.expect(kcl_error::INTERNAL_ERROR_MSG); + // Store schema attribute + if is_in_schema { let schema_value = self .get_variable(value::SCHEMA_SELF_NAME) .expect(kcl_error::INTERNAL_ERROR_MSG); + // Schema config let config_value = self .get_variable(value::SCHEMA_CONFIG_NAME) .expect(kcl_error::INTERNAL_ERROR_MSG); - let string_ptr_value = self.native_global_string(name, "").into(); - let has_key = self - .build_call( - &ApiFunc::kclvm_dict_has_value.name(), - &[config_value, string_ptr_value], - ) - .into_int_value(); - let has_key = self.builder.build_int_compare( - IntPredicate::NE, - has_key, - self.native_i8_zero(), - "", - ); - let last_block = self.append_block(""); - let then_block = self.append_block(""); - let else_block = self.append_block(""); - self.br(last_block); - self.builder.position_at_end(last_block); - let none_value = self.none_value(); - self.builder - .build_conditional_branch(has_key, then_block, else_block); - self.builder.position_at_end(then_block); - let config_entry = self.build_call( - &ApiFunc::kclvm_dict_get_entry.name(), - &[config_value, string_ptr_value], - ); - self.br(else_block); - self.builder.position_at_end(else_block); - let tpe = self.value_ptr_type(); - let phi = self.builder.build_phi(tpe, ""); - phi.add_incoming(&[ - (&none_value, last_block), - (&config_entry, then_block), - ]); - let config_value = phi.as_basic_value(); - if self.scope_level() >= SCHEMA_LEVEL && !is_local_var { - self.dict_merge(schema_value, name, value, 1, -1); - self.value_union(schema_value, config_value); - let cal_map = self - .get_variable(value::SCHEMA_CAL_MAP) - .expect(kcl_error::INTERNAL_ERROR_MSG); - let backtrack_cache = self - .get_variable(value::BACKTRACK_CACHE) - .expect(kcl_error::INTERNAL_ERROR_MSG); - let runtime_type = self - .get_variable(value::SCHEMA_RUNTIME_TYPE) - .expect(kcl_error::INTERNAL_ERROR_MSG); - let name_native_str = self.native_global_string_value(name); - self.build_void_call( - &ApiFunc::kclvm_schema_backtrack_cache.name(), - &[ - schema_value, - backtrack_cache, - cal_map, - name_native_str, - runtime_type, - ], - ); - // Update backtrack meta - { - if let Some(backtrack_meta) = - self.backtrack_meta.borrow_mut().as_mut() - { - if name == backtrack_meta.target { - backtrack_meta.count += 1; - if backtrack_meta.count == backtrack_meta.level { - backtrack_meta.stop = true; - self.ret(schema_value); - return Ok(schema_value); - } - } - } - } + // If is in the backtrack, return the schema value. + if self.update_schema_scope_value( + schema_value, + config_value, + name, + Some(value), + ) { + return Ok(schema_value); } - value - } else { - right_value.expect(kcl_error::INTERNAL_ERROR_MSG) - }; + } + // Store loop variable if is_local_var || !is_in_schema { let var = self.builder.build_alloca(tpe, name); self.builder.build_store(var, value); @@ -2436,16 +2608,15 @@ impl<'ctx> LLVMCodeGenContext<'ctx> { } } else { let names = &identifier.names; - let name = names[0].as_str(); - let mut value = if is_in_schema { - self.get_variable_in_schema(name) - .expect(kcl_error::INTERNAL_ERROR_MSG) - } else { - self.get_variable(name) - .expect(kcl_error::INTERNAL_ERROR_MSG) - }; + let name = names[0].node.as_str(); + // In KCL, we cannot modify global variables in other packages, + // so pkgpath is empty here. + let mut value = self + .load_value("", &[name]) + .expect(kcl_error::INTERNAL_ERROR_MSG); + // Convert `store a.b.c = 1` -> `%t = load &a; %t = load_attr %t %b; store_attr %t %c with 1` for i in 0..names.len() - 1 { - let attr = names[i + 1].as_str(); + let attr = names[i + 1].node.as_str(); let ctx = if matches!(identifier_ctx, ast::ExprContext::Store) && i != names.len() - 2 && names.len() > 2 @@ -2459,7 +2630,7 @@ impl<'ctx> LLVMCodeGenContext<'ctx> { let attr = self.native_global_string(attr, "").into(); value = self.build_call( &ApiFunc::kclvm_value_load_attr.name(), - &[value, attr], + &[self.current_runtime_ctx_ptr(), value, attr], ); } ast::ExprContext::Store => { @@ -2467,90 +2638,52 @@ impl<'ctx> LLVMCodeGenContext<'ctx> { self.build_void_call( &ApiFunc::kclvm_dict_set_value.name(), &[ + self.current_runtime_ctx_ptr(), value, attr, right_value.expect(kcl_error::INTERNAL_ERROR_MSG), ], ); - } - } - } - } - Ok(right_value.expect(kcl_error::INTERNAL_ERROR_MSG)) - } - ast::ExprContext::Load => { - let name = identifier.names[0].as_str(); - let is_local_var = { - let local_vars = self.local_vars.borrow_mut(); - local_vars.contains(name) - }; - if identifier.names.len() == 1 { - if is_in_schema && !is_local_var { - self.get_variable_in_schema(name) - } else { - self.get_variable(name) - } - } else { - let names = &identifier.names; - let name = names[0].as_str(); - let mut value = if identifier.pkgpath.is_empty() { - if is_in_schema && !is_local_var { - self.get_variable_in_schema(name) - .expect(kcl_error::INTERNAL_ERROR_MSG) - } else { - self.get_variable(name) - .expect(kcl_error::INTERNAL_ERROR_MSG) - } - } else { - self.ok_result().expect(kcl_error::INTERNAL_ERROR_MSG) - }; - for i in 0..names.len() - 1 { - let attr = names[i + 1].as_str(); - let ctx = if matches!(identifier_ctx, ast::ExprContext::Store) - && i != names.len() - 2 - && names.len() > 2 - { - &ast::ExprContext::Load - } else { - identifier_ctx - }; - match ctx { - ast::ExprContext::Load => { - if i == 0 && !identifier.pkgpath.is_empty() { - value = if self.no_link { - self.get_external_variable_in_pkgpath( - attr, - &identifier.pkgpath, - ) - .expect(kcl_error::INTERNAL_ERROR_MSG) - } else { - self.get_variable_in_pkgpath(attr, &identifier.pkgpath) - .expect(kcl_error::INTERNAL_ERROR_MSG) + + let is_local_var = self.is_local_var(name); + let is_in_lambda = self.is_in_lambda(); + // Set config value for the schema attribute if the attribute is in the schema and + // it is not a local variable in the lambda function. + if self.scope_level() >= INNER_LEVEL + && is_in_schema + && !is_in_lambda + && !is_local_var + { + let schema_value = self + .get_variable(value::SCHEMA_SELF_NAME) + .expect(kcl_error::INTERNAL_ERROR_MSG); + let config_value = self + .get_variable(value::SCHEMA_CONFIG_NAME) + .expect(kcl_error::INTERNAL_ERROR_MSG); + if self.update_schema_scope_value( + schema_value, + config_value, + name, + None, + ) { + return Ok(schema_value); } - } else { - let attr = self.native_global_string(attr, "").into(); - value = self.build_call( - &ApiFunc::kclvm_value_load_attr.name(), - &[value, attr], - ); } } - ast::ExprContext::Store => { - let attr = self.native_global_string(attr, "").into(); - self.build_void_call( - &ApiFunc::kclvm_dict_set_value.name(), - &[ - value, - attr, - right_value.expect(kcl_error::INTERNAL_ERROR_MSG), - ], - ); - } } } - Ok(value) } + Ok(right_value.expect(kcl_error::INTERNAL_ERROR_MSG)) } + // Load .a.b.c + ast::ExprContext::Load => self.load_value( + &identifier.pkgpath, + &identifier + .names + .iter() + .map(|n| n.node.as_str()) + .collect::>(), + ), } } @@ -2580,7 +2713,7 @@ impl<'ctx> LLVMCodeGenContext<'ctx> { } else { self.none_value() }; - self.dict_insert(dict_value, name.as_str(), value, 0, -1); + self.dict_insert(dict_value, name.node.as_str(), value, 0, None); } let name = match &decorator.func.node { ast::Expr::Identifier(ident) if ident.names.len() == 1 => ident.names[0].clone(), @@ -2591,7 +2724,8 @@ impl<'ctx> LLVMCodeGenContext<'ctx> { Ok(self.build_call( &ApiFunc::kclvm_value_Decorator.name(), &[ - self.native_global_string_value(name.as_str()), + self.current_runtime_ctx_ptr(), + self.native_global_string_value(name.node.as_str()), list_value, dict_value, schema_config_meta, @@ -2609,30 +2743,48 @@ impl<'ctx> LLVMCodeGenContext<'ctx> { kwargs: BasicValueEnum<'ctx>, ) { // Arguments names and defaults - let (arg_names, arg_defaults) = if let Some(args) = &arguments { + let (arg_names, arg_types, arg_defaults) = if let Some(args) = &arguments { let names = &args.node.args; + let types = &args.node.ty_list; let defaults = &args.node.defaults; ( names.iter().map(|identifier| &identifier.node).collect(), + types.iter().collect(), defaults.iter().collect(), ) } else { - (vec![], vec![]) + (vec![], vec![], vec![]) }; // Default parameter values - for (arg_name, value) in arg_names.iter().zip(arg_defaults.iter()) { - let arg_value = if let Some(value) = value { + for ((arg_name, arg_type), value) in + arg_names.iter().zip(&arg_types).zip(arg_defaults.iter()) + { + let mut arg_value = if let Some(value) = value { self.walk_expr(value).expect(kcl_error::COMPILE_ERROR_MSG) } else { self.none_value() }; + if let Some(ty) = arg_type { + let type_annotation = self.native_global_string_value(&ty.node.to_string()); + arg_value = self.build_call( + &ApiFunc::kclvm_convert_collection_value.name(), + &[ + self.current_runtime_ctx_ptr(), + arg_value, + type_annotation, + self.bool_value(false), + ], + ); + } + // Arguments are immutable, so we place them in different scopes. + self.store_argument_in_current_scope(&arg_name.get_name()); self.walk_identifier_with_ctx(arg_name, &ast::ExprContext::Store, Some(arg_value)) .expect(kcl_error::COMPILE_ERROR_MSG); } // for loop in 0..argument_len in LLVM begin let argument_len = self.build_call(&ApiFunc::kclvm_list_len.name(), &[args]); let end_block = self.append_block(""); - for (i, arg_name) in arg_names.iter().enumerate() { + for (i, (arg_name, arg_type)) in arg_names.iter().zip(arg_types).enumerate() { // Positional arguments let is_in_range = self.builder.build_int_compare( IntPredicate::ULT, @@ -2644,18 +2796,34 @@ impl<'ctx> LLVMCodeGenContext<'ctx> { self.builder .build_conditional_branch(is_in_range, next_block, end_block); self.builder.position_at_end(next_block); - let arg_value = self.build_call( + let mut arg_value = self.build_call( &ApiFunc::kclvm_list_get_option.name(), - &[args, self.native_int_value(i as i32)], + &[ + self.current_runtime_ctx_ptr(), + args, + self.native_int_value(i as i32), + ], ); - self.store_variable(&arg_name.names[0], arg_value); + if let Some(ty) = arg_type { + let type_annotation = self.native_global_string_value(&ty.node.to_string()); + arg_value = self.build_call( + &ApiFunc::kclvm_convert_collection_value.name(), + &[ + self.current_runtime_ctx_ptr(), + arg_value, + type_annotation, + self.bool_value(false), + ], + ); + } + self.store_variable(&arg_name.names[0].node, arg_value); } // for loop in 0..argument_len in LLVM end self.br(end_block); self.builder.position_at_end(end_block); // Keyword arguments for arg_name in arg_names.iter() { - let name = &arg_name.names[0]; + let name = &arg_name.names[0].node; let string_ptr_value = self.native_global_string(name.as_str(), "").into(); let has_key = self .build_call( @@ -2676,10 +2844,10 @@ impl<'ctx> LLVMCodeGenContext<'ctx> { self.builder.position_at_end(then_block); let arg = self.build_call( &ApiFunc::kclvm_dict_get_value.name(), - &[kwargs, string_ptr_value], + &[self.current_runtime_ctx_ptr(), kwargs, string_ptr_value], ); // Find argument name in the scope - self.store_variable(&arg_name.names[0], arg); + self.store_variable(&arg_name.names[0].node, arg); self.br(else_block); self.builder.position_at_end(else_block); } @@ -2723,14 +2891,14 @@ impl<'ctx> LLVMCodeGenContext<'ctx> { { let mut local_vars = self.local_vars.borrow_mut(); for v in targets { - let name = &v.node.names[0]; + let name = &v.node.names[0].node; local_vars.insert(name.clone()); } } if targets.len() == 1 { // Store the target self.walk_identifier_with_ctx( - &targets.get(0).expect(kcl_error::INTERNAL_ERROR_MSG).node, + &targets.first().expect(kcl_error::INTERNAL_ERROR_MSG).node, &ast::ExprContext::Store, Some(next_value), ) @@ -2740,7 +2908,7 @@ impl<'ctx> LLVMCodeGenContext<'ctx> { let value = self.build_call(&ApiFunc::kclvm_iterator_cur_value.name(), &[iter_value]); // Store the target self.walk_identifier_with_ctx( - &targets.get(0).expect(kcl_error::INTERNAL_ERROR_MSG).node, + &targets.first().expect(kcl_error::INTERNAL_ERROR_MSG).node, &ast::ExprContext::Store, Some(key), ) @@ -2779,7 +2947,13 @@ impl<'ctx> LLVMCodeGenContext<'ctx> { .expect(kcl_error::COMPILE_ERROR_MSG); let key = self.walk_expr(elt).expect(kcl_error::COMPILE_ERROR_MSG); let op = op.expect(kcl_error::INTERNAL_ERROR_MSG); - self.dict_insert_with_key_value(collection_value, key, value, op.value(), -1); + self.dict_insert_with_key_value( + collection_value, + key, + self.value_deep_copy(value), + op.value(), + None, + ); } } } else { @@ -2795,6 +2969,78 @@ impl<'ctx> LLVMCodeGenContext<'ctx> { } self.br(start_block); self.builder.position_at_end(end_for_block); - self.local_vars.borrow_mut().clear(); + self.build_void_call(&ApiFunc::kclvm_iterator_delete.name(), &[iter_value]); + { + let mut local_vars = self.local_vars.borrow_mut(); + for v in targets { + let name = &v.node.names[0].node; + local_vars.remove(name); + } + } + } + + pub(crate) fn walk_config_entries( + &self, + items: &'ctx [NodeRef], + ) -> CompileResult<'ctx> { + let config_value = self.dict_value(); + for item in items { + let value = self.walk_expr(&item.node.value)?; + if let Some(key) = &item.node.key { + let mut insert_index = None; + let optional_name = match &key.node { + ast::Expr::Identifier(identifier) => Some(identifier.names[0].node.clone()), + ast::Expr::StringLit(string_lit) => Some(string_lit.value.clone()), + ast::Expr::Subscript(subscript) => { + let mut name = None; + if let ast::Expr::Identifier(identifier) = &subscript.value.node { + if let Some(index_node) = &subscript.index { + // Insert index + if let ast::Expr::NumberLit(number) = &index_node.node { + if let ast::NumberLitValue::Int(v) = number.value { + insert_index = Some(v as i32); + name = Some(identifier.names[0].node.clone()) + } + } else if let ast::Expr::Unary(unary_expr) = &index_node.node { + // Negative insert index + if let ast::Expr::NumberLit(number) = &unary_expr.operand.node { + if let ast::NumberLitValue::Int(v) = number.value { + insert_index = Some(-v as i32); + name = Some(identifier.names[0].node.clone()) + } + } + } + } + } + name + } + _ => None, + }; + // Store a local variable for every entry key. + let key = match &optional_name { + Some(name) if !self.is_local_var(name) => self.string_value(name), + _ => self.walk_expr(key)?, + }; + self.dict_insert_with_key_value( + config_value, + key, + value, + item.node.operation.value(), + insert_index, + ); + if let Some(name) = &optional_name { + let value = + self.dict_get(config_value, self.native_global_string(name, "").into()); + self.add_or_update_local_variable_within_scope(name, Some(value)); + } + } else { + // If the key does not exist, execute the logic of unpacking expression `**expr` here. + self.build_void_call( + &ApiFunc::kclvm_dict_insert_unpack.name(), + &[self.current_runtime_ctx_ptr(), config_value, value], + ); + } + } + Ok(config_value) } } diff --git a/kclvm/compiler/src/codegen/llvm/schema.rs b/kclvm/compiler/src/codegen/llvm/schema.rs index 379cef8dd..5d53dc6eb 100644 --- a/kclvm/compiler/src/codegen/llvm/schema.rs +++ b/kclvm/compiler/src/codegen/llvm/schema.rs @@ -1,110 +1,145 @@ -// Copyright 2021 The KCL Authors. All rights reserved. +// Copyright The KCL Authors. All rights reserved. use inkwell::values::{BasicValueEnum, FunctionValue}; -use inkwell::AddressSpace; +use inkwell::{AddressSpace, IntPredicate}; use kclvm_ast::ast; +use kclvm_runtime::ApiFunc; +use kclvm_sema::pkgpath_without_prefix; use std::collections::HashMap; use std::str; use super::context::LLVMCodeGenContext; -use crate::codegen::error as kcl_error; -use crate::codegen::traits::{BuilderMethods, DerivedValueCalculationMethods, ValueMethods}; +use crate::codegen::llvm::context::BacktrackKind; +use crate::codegen::traits::{ + BuilderMethods, DerivedTypeMethods, DerivedValueCalculationMethods, ProgramCodeGen, + ValueMethods, +}; +use crate::codegen::{error as kcl_error, INNER_LEVEL}; use crate::value; -use crate::pkgpath_without_prefix; - impl<'ctx> LLVMCodeGenContext<'ctx> { - /// Emit all schema left identifiers because all the schema attribute can be forward referenced - pub fn emit_schema_left_identifiers( + /// Emit all left identifiers because all the attribute can be forward referenced. + pub(crate) fn emit_left_identifiers( &self, body: &'ctx [Box>], + index_signature: &'ctx Option>, cal_map: BasicValueEnum<'ctx>, runtime_type: &str, is_in_if: bool, place_holder_map: &mut HashMap>>, - body_map: &mut HashMap>>, + body_map: &mut HashMap, BacktrackKind)>>, in_if_names: &mut Vec, ) { let schema_value = self .get_variable(value::SCHEMA_SELF_NAME) .expect(kcl_error::INTERNAL_ERROR_MSG); let value = self.undefined_value(); - let add_stmt = - |name: &str, - stmt: &'ctx ast::Node, - place_holder_map: &mut HashMap>>, - body_map: &mut HashMap>>| { - let function = self.add_function(&format!( - "{}.{}.{}", - value::SCHEMA_ATTR_NAME, - pkgpath_without_prefix!(runtime_type), - name - )); - let lambda_fn_ptr = self.builder.build_bitcast( - function.as_global_value().as_pointer_value(), - self.context.i64_type().ptr_type(AddressSpace::Generic), - "", - ); - if !place_holder_map.contains_key(name) { - place_holder_map.insert(name.to_string(), vec![]); - } - let name_vec = place_holder_map - .get_mut(name) - .expect(kcl_error::INTERNAL_ERROR_MSG); - name_vec.push(function); - self.default_collection_insert_int_pointer(cal_map, name, lambda_fn_ptr); - self.default_collection_insert_value( - cal_map, - &format!("{}_{}", name, kclvm::CAL_MAP_RUNTIME_TYPE), - self.string_value(runtime_type), - ); - self.default_collection_insert_value( - cal_map, - &format!("{}_{}", name, kclvm::CAL_MAP_META_LINE), - self.int_value(stmt.line as i64), - ); - if !body_map.contains_key(name) { - body_map.insert(name.to_string(), vec![]); - } - let body_vec = body_map.get_mut(name).expect(kcl_error::INTERNAL_ERROR_MSG); - body_vec.push(stmt); - }; + let add_stmt = |name: &str, + stmt: &'ctx ast::Node, + kind: BacktrackKind, + place_holder_map: &mut HashMap>>, + body_map: &mut HashMap< + String, + Vec<(&'ctx ast::Node, BacktrackKind)>, + >| { + let function = self.add_function(&format!( + "{}.{}.{}", + value::SCHEMA_ATTR_NAME, + pkgpath_without_prefix!(runtime_type), + name + )); + let lambda_fn_ptr = self.builder.build_bitcast( + function.as_global_value().as_pointer_value(), + self.context.i64_type().ptr_type(AddressSpace::default()), + "", + ); + if !place_holder_map.contains_key(name) { + place_holder_map.insert(name.to_string(), vec![]); + } + let name_vec = place_holder_map + .get_mut(name) + .expect(kcl_error::INTERNAL_ERROR_MSG); + name_vec.push(function); + self.default_collection_insert_int_pointer(cal_map, name, lambda_fn_ptr); + self.default_collection_insert_value( + cal_map, + &format!("{}_{}", name, kclvm_runtime::CAL_MAP_RUNTIME_TYPE), + self.string_value(runtime_type), + ); + self.default_collection_insert_value( + cal_map, + &format!("{}_{}", name, kclvm_runtime::CAL_MAP_META_LINE), + self.int_value(stmt.line as i64), + ); + if !body_map.contains_key(name) { + body_map.insert(name.to_string(), vec![]); + } + let body_vec = body_map.get_mut(name).expect(kcl_error::INTERNAL_ERROR_MSG); + body_vec.push((stmt, kind)); + }; + if let Some(index_signature) = index_signature { + self.default_collection_insert_value( + cal_map, + kclvm_runtime::CAL_MAP_INDEX_SIGNATURE, + self.int_value(index_signature.line as i64), + ); + place_holder_map.insert(kclvm_runtime::CAL_MAP_INDEX_SIGNATURE.to_string(), vec![]); + } for stmt in body { match &stmt.node { ast::Stmt::Unification(unification_stmt) => { - let name = &unification_stmt.target.node.names[0]; - self.dict_merge(schema_value, name, value, 0, -1); + let name = &unification_stmt.target.node.names[0].node; + self.dict_merge(schema_value, name, value, 0, None); if is_in_if { in_if_names.push(name.to_string()); } else { - add_stmt(name, stmt, place_holder_map, body_map); + add_stmt( + name, + stmt, + BacktrackKind::Normal, + place_holder_map, + body_map, + ); } } ast::Stmt::Assign(assign_stmt) => { for target in &assign_stmt.targets { - let name = &target.node.names[0]; - self.dict_merge(schema_value, name, value, 0, -1); + let name = &target.node.name.node; + self.dict_merge(schema_value, name, value, 0, None); if is_in_if { in_if_names.push(name.to_string()); } else { - add_stmt(name, stmt, place_holder_map, body_map); + add_stmt( + name, + stmt, + BacktrackKind::Normal, + place_holder_map, + body_map, + ); } } } ast::Stmt::AugAssign(aug_assign_stmt) => { let target = &aug_assign_stmt.target; - let name = &target.node.names[0]; - self.dict_merge(schema_value, name, value, 0, -1); + let name = &target.node.name.node; + self.dict_merge(schema_value, name, value, 0, None); if is_in_if { in_if_names.push(name.to_string()); } else { - add_stmt(name, stmt, place_holder_map, body_map); + add_stmt( + name, + stmt, + BacktrackKind::Normal, + place_holder_map, + body_map, + ); } } ast::Stmt::If(if_stmt) => { let mut names: Vec = vec![]; - self.emit_schema_left_identifiers( + self.emit_left_identifiers( &if_stmt.body, + &None, cal_map, runtime_type, true, @@ -118,12 +153,13 @@ impl<'ctx> LLVMCodeGenContext<'ctx> { } } else { for name in &names { - add_stmt(name, stmt, place_holder_map, body_map); + add_stmt(name, stmt, BacktrackKind::If, place_holder_map, body_map); } - names.clear(); } - self.emit_schema_left_identifiers( + names.clear(); + self.emit_left_identifiers( &if_stmt.orelse, + &None, cal_map, runtime_type, true, @@ -137,18 +173,30 @@ impl<'ctx> LLVMCodeGenContext<'ctx> { } } else { for name in &names { - add_stmt(name, stmt, place_holder_map, body_map); + add_stmt( + name, + stmt, + BacktrackKind::OrElse, + place_holder_map, + body_map, + ); } - names.clear(); } + names.clear(); } ast::Stmt::SchemaAttr(schema_attr) => { let name = schema_attr.name.node.as_str(); - self.dict_merge(schema_value, name, value, 0, -1); + self.dict_merge(schema_value, name, value, 0, None); if is_in_if { in_if_names.push(name.to_string()); } else { - add_stmt(name, stmt, place_holder_map, body_map); + add_stmt( + name, + stmt, + BacktrackKind::Normal, + place_holder_map, + body_map, + ); } } _ => {} @@ -156,7 +204,7 @@ impl<'ctx> LLVMCodeGenContext<'ctx> { } } - pub fn get_schema_config_meta( + pub(crate) fn get_schema_config_meta( &self, n: Option<&'ctx ast::Node>, t: &'ctx ast::ConfigExpr, @@ -164,27 +212,33 @@ impl<'ctx> LLVMCodeGenContext<'ctx> { let config_meta = self.dict_value(); if let Some(n) = n { let value = self.string_value(&n.filename); - self.dict_insert_override_item(config_meta, kclvm::CONFIG_META_FILENAME, value); + self.dict_insert_override_item(config_meta, kclvm_runtime::CONFIG_META_FILENAME, value); let value = self.int_value(n.line as i64); - self.dict_insert_override_item(config_meta, kclvm::CONFIG_META_LINE, value); + self.dict_insert_override_item(config_meta, kclvm_runtime::CONFIG_META_LINE, value); let value = self.int_value(n.column as i64); - self.dict_insert_override_item(config_meta, kclvm::CONFIG_META_COLUMN, value); + self.dict_insert_override_item(config_meta, kclvm_runtime::CONFIG_META_COLUMN, value); } for item in &t.items { if let Some(key) = &item.node.key { let name = match &key.node { - ast::Expr::Identifier(t) => t.names[0].clone(), + ast::Expr::Identifier(t) => t.names[0].node.clone(), ast::Expr::NumberLit(t) => match t.value { ast::NumberLitValue::Int(i) => i.to_string(), ast::NumberLitValue::Float(f) => f.to_string(), }, ast::Expr::StringLit(t) => t.value.clone(), ast::Expr::NameConstantLit(t) => match t.value { - ast::NameConstant::True => kclvm::KCL_NAME_CONSTANT_TRUE.to_string(), - ast::NameConstant::False => kclvm::KCL_NAME_CONSTANT_FALSE.to_string(), - ast::NameConstant::None => kclvm::KCL_NAME_CONSTANT_NONE.to_string(), + ast::NameConstant::True => { + kclvm_runtime::KCL_NAME_CONSTANT_TRUE.to_string() + } + ast::NameConstant::False => { + kclvm_runtime::KCL_NAME_CONSTANT_FALSE.to_string() + } + ast::NameConstant::None => { + kclvm_runtime::KCL_NAME_CONSTANT_NONE.to_string() + } ast::NameConstant::Undefined => { - kclvm::KCL_NAME_CONSTANT_UNDEFINED.to_string() + kclvm_runtime::KCL_NAME_CONSTANT_UNDEFINED.to_string() } }, _ => format!("{:?}", key.node), @@ -193,19 +247,19 @@ impl<'ctx> LLVMCodeGenContext<'ctx> { let value = self.string_value(&key.filename); self.dict_insert_override_item( config_item_meta, - kclvm::CONFIG_ITEM_META_FILENAME, + kclvm_runtime::CONFIG_ITEM_META_FILENAME, value, ); let value = self.int_value(key.line as i64); self.dict_insert_override_item( config_item_meta, - kclvm::CONFIG_ITEM_META_LINE, + kclvm_runtime::CONFIG_ITEM_META_LINE, value, ); let value = self.int_value(key.column as i64); self.dict_insert_override_item( config_item_meta, - kclvm::CONFIG_ITEM_META_COLUMN, + kclvm_runtime::CONFIG_ITEM_META_COLUMN, value, ); let value = match &item.node.value.node { @@ -214,10 +268,91 @@ impl<'ctx> LLVMCodeGenContext<'ctx> { } _ => self.dict_value(), }; - self.dict_insert_override_item(config_item_meta, kclvm::CONFIG_ITEM_META, value); + self.dict_insert_override_item( + config_item_meta, + kclvm_runtime::CONFIG_ITEM_META, + value, + ); self.dict_insert_override_item(config_meta, &name, config_item_meta) } } config_meta } + + pub(crate) fn update_schema_scope_value( + &self, + schema_value: BasicValueEnum<'ctx>, // Schema self value + config_value: BasicValueEnum<'ctx>, // Schema config value + name: &str, // Schema attribute name + value: Option>, // Optional right override value + ) -> bool { + // Attribute name + let string_ptr_value = self.native_global_string(name, "").into(); + // i8 has_key + let has_key = self + .build_call( + &ApiFunc::kclvm_dict_has_value.name(), + &[config_value, string_ptr_value], + ) + .into_int_value(); + // i1 has_key + let has_key = + self.builder + .build_int_compare(IntPredicate::NE, has_key, self.native_i8_zero(), ""); + let last_block = self.append_block(""); + let then_block = self.append_block(""); + let else_block = self.append_block(""); + self.br(last_block); + self.builder.position_at_end(last_block); + let none_value = self.none_value(); + self.builder + .build_conditional_branch(has_key, then_block, else_block); + self.builder.position_at_end(then_block); + let config_entry = self.build_call( + &ApiFunc::kclvm_dict_get_entry.name(), + &[ + self.current_runtime_ctx_ptr(), + config_value, + string_ptr_value, + ], + ); + self.br(else_block); + self.builder.position_at_end(else_block); + let tpe = self.value_ptr_type(); + let phi = self.builder.build_phi(tpe, ""); + phi.add_incoming(&[(&none_value, last_block), (&config_entry, then_block)]); + let config_value = phi.as_basic_value(); + if self.scope_level() >= INNER_LEVEL && !self.local_vars.borrow().contains(name) { + if let Some(value) = value { + self.dict_merge(schema_value, name, value, 1, None); + } + self.value_union(schema_value, config_value); + let cal_map = self + .get_variable(value::SCHEMA_CAL_MAP) + .expect(kcl_error::INTERNAL_ERROR_MSG); + let backtrack_cache = self + .get_variable(value::BACKTRACK_CACHE) + .expect(kcl_error::INTERNAL_ERROR_MSG); + let runtime_type = self + .get_variable(value::SCHEMA_RUNTIME_TYPE) + .expect(kcl_error::INTERNAL_ERROR_MSG); + let name_native_str = self.native_global_string_value(name); + self.build_void_call( + &ApiFunc::kclvm_schema_backtrack_cache.name(), + &[ + self.current_runtime_ctx_ptr(), + schema_value, + backtrack_cache, + cal_map, + name_native_str, + runtime_type, + ], + ); + // Update backtrack meta + if self.update_backtrack_meta(name, schema_value) { + return true; + } + } + false + } } diff --git a/kclvm/compiler/src/codegen/llvm/utils.rs b/kclvm/compiler/src/codegen/llvm/utils.rs index 0d200902d..7bffb4a2f 100644 --- a/kclvm/compiler/src/codegen/llvm/utils.rs +++ b/kclvm/compiler/src/codegen/llvm/utils.rs @@ -1,8 +1,7 @@ -// Copyright 2021 The KCL Authors. All rights reserved. +// Copyright The KCL Authors. All rights reserved. -use inkwell::values::BasicValueEnum; -use kclvm::ApiFunc; use kclvm_ast::ast; +use kclvm_runtime::ApiFunc; use std::str; use crate::codegen::traits::ValueMethods; @@ -14,34 +13,44 @@ use super::context::LLVMCodeGenContext; */ /// Update runtime context pkgpath -pub fn update_ctx_pkgpath<'ctx>(gen: &'ctx LLVMCodeGenContext, pkgpath: &str) { +pub(crate) fn update_ctx_pkgpath(gen: &LLVMCodeGenContext, pkgpath: &str) { gen.build_void_call( &ApiFunc::kclvm_context_set_kcl_pkgpath.name(), &[ - gen.global_ctx_ptr(), + gen.current_runtime_ctx_ptr(), gen.native_global_string_value(pkgpath), ], ); } /// Update runtime context filename -pub fn update_ctx_filename<'ctx, T>(gen: &'ctx LLVMCodeGenContext, node: &'ctx ast::Node) { +pub(crate) fn update_ctx_filename<'ctx, T>( + gen: &'ctx LLVMCodeGenContext, + node: &'ctx ast::Node, +) { if !node.filename.is_empty() { gen.build_void_call( &ApiFunc::kclvm_context_set_kcl_filename.name(), - &[gen.native_global_string_value(&node.filename)], + &[ + gen.current_runtime_ctx_ptr(), + gen.native_global_string_value(&node.filename), + ], ); } } /// Update runtime context line and column -pub fn update_ctx_line_col<'ctx, T>(gen: &'ctx LLVMCodeGenContext, node: &'ctx ast::Node) { +pub(crate) fn update_ctx_line_col<'ctx, T>( + gen: &'ctx LLVMCodeGenContext, + node: &'ctx ast::Node, +) { let mut current_line = gen.current_line.borrow_mut(); if node.line != *current_line { *current_line = node.line; gen.build_void_call( &ApiFunc::kclvm_context_set_kcl_line_col.name(), &[ + gen.current_runtime_ctx_ptr(), gen.native_int_value(node.line as i32), gen.native_int_value(0), ], @@ -50,22 +59,20 @@ pub fn update_ctx_line_col<'ctx, T>(gen: &'ctx LLVMCodeGenContext, node: &'ctx a } /// Update runtime context line and column -pub fn update_ctx_current_line(gen: &LLVMCodeGenContext) { +pub(crate) fn update_ctx_current_line(gen: &LLVMCodeGenContext) { let current_line = gen.current_line.borrow_mut(); gen.build_void_call( &ApiFunc::kclvm_context_set_kcl_line_col.name(), &[ + gen.current_runtime_ctx_ptr(), gen.native_int_value(*current_line as i32), gen.native_int_value(0), ], ); } -/// Runtime debug print value -#[allow(dead_code)] -pub fn runtime_print_value<'ctx>(gen: &'ctx LLVMCodeGenContext, value: BasicValueEnum<'ctx>) { - gen.build_void_call( - ApiFunc::kclvm_debug_print_value_json_string.name().as_str(), - &[value], - ); +/// Reset target vars +pub(crate) fn reset_target_vars(gen: &LLVMCodeGenContext) { + gen.target_vars.borrow_mut().clear(); + gen.target_vars.borrow_mut().push("".to_string()); } diff --git a/kclvm/compiler/src/codegen/mod.rs b/kclvm/compiler/src/codegen/mod.rs index 2e1d3b4e5..6b9bebac2 100644 --- a/kclvm/compiler/src/codegen/mod.rs +++ b/kclvm/compiler/src/codegen/mod.rs @@ -1,28 +1,39 @@ -//! Copyright 2021 The KCL Authors. All rights reserved. +//! Copyright The KCL Authors. All rights reserved. + +use indexmap::IndexMap; +use kclvm_ast::ast; mod abi; pub mod error; +#[cfg(feature = "llvm")] pub mod llvm; mod traits; /// The kclvm runner main function name. -pub(crate) const MODULE_NAME: &str = "kclvm_main"; +pub const MODULE_NAME: &str = "kclvm_main"; /// The kclvm runner main function entry block name. -pub(crate) const ENTRY_NAME: &str = "entry"; +pub const ENTRY_NAME: &str = "entry"; /// The kclvm runtime value type name. -pub(crate) const VALUE_TYPE_NAME: &str = "kclvm_value_ref_t"; +pub const VALUE_TYPE_NAME: &str = "kclvm_value_ref_t"; /// The kclvm runtime context type name. -pub(crate) const CONTEXT_TYPE_NAME: &str = "kclvm_context_t"; -/// The kclvm context variable name. -pub(crate) const KCL_CONTEXT_VAR_NAME: &str = "context"; +pub const CONTEXT_TYPE_NAME: &str = "kclvm_context_t"; +/// The kclvm runtime evaluation type name. +pub const SCOPE_TYPE_NAME: &str = "kclvm_eval_scope_t"; /// Package init function name suffix -pub(crate) const PKG_INIT_FUNCTION_SUFFIX: &str = "init"; +pub const PKG_INIT_FUNCTION_SUFFIX: &str = "init"; /// Global level -pub(crate) const GLOBAL_LEVEL: usize = 1; -/// Schema level -pub(crate) const SCHEMA_LEVEL: usize = 2; +pub const GLOBAL_LEVEL: usize = 1; +/// Inner level +pub const INNER_LEVEL: usize = 2; /// Global variable alignment -pub(crate) const GLOBAL_VAL_ALIGNMENT: u32 = 8; +pub const GLOBAL_VAL_ALIGNMENT: u32 = 8; +/// Object file type format suffix. +#[cfg(target_os = "windows")] +pub const OBJECT_FILE_SUFFIX: &str = ".obj"; +#[cfg(not(target_os = "windows"))] +pub const OBJECT_FILE_SUFFIX: &str = ".o"; +/// LLVM IR text format suffix .ll +pub const LL_FILE_SUFFIX: &str = ".ll"; /// CodeGenContext is a trait used by the compiler to emit code to different targets. pub trait CodeGenContext: traits::ProgramCodeGen { @@ -41,9 +52,31 @@ pub struct EmitOptions<'a> { } /// Emit code with the options using CodeGenContext. -pub fn emit_code( +pub fn emit_code_with( ctx: impl CodeGenContext, opt: &EmitOptions, ) -> Result<(), Box> { ctx.emit(opt) } + +/// Generate LLVM IR of KCL ast module. +#[inline] +pub fn emit_code( + program: &ast::Program, + workdir: String, + import_names: IndexMap>, + opts: &EmitOptions, +) -> Result<(), Box> { + #[cfg(feature = "llvm")] + { + llvm::emit_code(program, workdir, import_names, opts) + } + #[cfg(not(feature = "llvm"))] + { + let _ = program; + let _ = workdir; + let _ = import_names; + let _ = opts; + Err("error: llvm feature is not enabled. Note: Set KCL_FAST_EVAL=1 or rebuild the crate with the llvm feature.".to_string().into()) + } +} diff --git a/kclvm/compiler/src/codegen/traits/backend.rs b/kclvm/compiler/src/codegen/traits/backend.rs index 924724de7..da443797c 100644 --- a/kclvm/compiler/src/codegen/traits/backend.rs +++ b/kclvm/compiler/src/codegen/traits/backend.rs @@ -1,4 +1,4 @@ -//! Copyright 2021 The KCL Authors. All rights reserved. +//! Copyright The KCL Authors. All rights reserved. use std::fmt::Debug; diff --git a/kclvm/compiler/src/codegen/traits/builder.rs b/kclvm/compiler/src/codegen/traits/builder.rs index ebaaad66a..dac7577cb 100644 --- a/kclvm/compiler/src/codegen/traits/builder.rs +++ b/kclvm/compiler/src/codegen/traits/builder.rs @@ -1,4 +1,4 @@ -//! Copyright 2021 The KCL Authors. All rights reserved. +//! Copyright The KCL Authors. All rights reserved. use crate::codegen::abi::Align; @@ -82,4 +82,6 @@ pub trait BuilderMethods: BackendTypes { fn lookup_function(&self, name: &str) -> Self::Function; /// Add a function named `name`. fn add_function(&self, name: &str) -> Self::Function; + /// Add a setter function named `name`. + fn add_setter_function(&self, name: &str) -> Self::Function; } diff --git a/kclvm/compiler/src/codegen/traits/mod.rs b/kclvm/compiler/src/codegen/traits/mod.rs index 468680caf..f755896e4 100644 --- a/kclvm/compiler/src/codegen/traits/mod.rs +++ b/kclvm/compiler/src/codegen/traits/mod.rs @@ -1,4 +1,4 @@ -//! Copyright 2021 The KCL Authors. All rights reserved. +//! Copyright The KCL Authors. All rights reserved. mod backend; mod builder; diff --git a/kclvm/compiler/src/codegen/traits/type.rs b/kclvm/compiler/src/codegen/traits/type.rs index f1ed73d5f..a43fd1594 100644 --- a/kclvm/compiler/src/codegen/traits/type.rs +++ b/kclvm/compiler/src/codegen/traits/type.rs @@ -1,7 +1,7 @@ -//! Copyright 2021 The KCL Authors. All rights reserved. +//! Copyright The KCL Authors. All rights reserved. use crate::codegen::abi::AddressSpace; -use crate::codegen::{CONTEXT_TYPE_NAME, VALUE_TYPE_NAME}; +use crate::codegen::{CONTEXT_TYPE_NAME, SCOPE_TYPE_NAME, VALUE_TYPE_NAME}; use super::BackendTypes; @@ -53,6 +53,10 @@ pub trait DerivedTypeMethods: BaseTypeMethods { fn context_ptr_type(&self) -> Self::Type { self.ptr_type_to(self.get_intrinsic_type(CONTEXT_TYPE_NAME)) } + /// Get the context pointer type. + fn scope_ptr_type(&self) -> Self::Type { + self.ptr_type_to(self.get_intrinsic_type(SCOPE_TYPE_NAME)) + } /// Get the function type. fn function_type(&self) -> Self::FunctionLet { let value_ptr_type = self.value_ptr_type(); @@ -62,6 +66,13 @@ pub trait DerivedTypeMethods: BaseTypeMethods { value_ptr_type, ) } + /// Get the setter function type. + fn setter_func_type(&self) -> Self::FunctionLet { + let context_ptr_type = self.context_ptr_type(); + let scope_ptr_type = self.scope_ptr_type(); + let value_ptr_type = self.value_ptr_type(); + self.function_let(&[context_ptr_type, scope_ptr_type], value_ptr_type) + } } /// TypeCodeGen defines all type APIs. diff --git a/kclvm/compiler/src/codegen/traits/value.rs b/kclvm/compiler/src/codegen/traits/value.rs index 72f808eeb..89529440e 100644 --- a/kclvm/compiler/src/codegen/traits/value.rs +++ b/kclvm/compiler/src/codegen/traits/value.rs @@ -1,4 +1,6 @@ -//! Copyright 2021 The KCL Authors. All rights reserved. +//! Copyright The KCL Authors. All rights reserved. + +use std::collections::HashMap; use super::BackendTypes; @@ -32,14 +34,17 @@ pub trait ValueMethods: BackendTypes { fn struct_function_value( &self, functions: &[Self::Function], + attr_functions: &HashMap>, runtime_type: &str, ) -> Self::Value; /// Construct a builtin function value using the function name. fn builtin_function_value(&self, function_name: &str) -> Self::Value; /// Get a global value pointer named `name`. fn global_value_ptr(&self, name: &str) -> Self::Value; - /// Get the global runtime context pointer. - fn global_ctx_ptr(&self) -> Self::Value; + /// Get current runtime context pointer. + fn current_runtime_ctx_ptr(&self) -> Self::Value; + /// Get the global evaluation scope pointer. + fn current_scope_ptr(&self) -> Self::Value; } /// DerivedValueCalculationMethods defines all value base calculation APIs. @@ -160,7 +165,7 @@ pub trait DerivedValueCalculationMethods: ValueMethods + ValueCalculationMethods key: Self::Value, value: Self::Value, op: i32, - insert_index: i32, + insert_index: Option, ); /// Insert a dict entry including key, value, op and insert_index into the dict, /// and the type of key is `&str` @@ -170,13 +175,13 @@ pub trait DerivedValueCalculationMethods: ValueMethods + ValueCalculationMethods key: &str, value: Self::Value, op: i32, - insert_index: i32, + insert_index: Option, ) { self.dict_insert_with_key_value(dict, self.string_value(key), value, op, insert_index); } /// Insert a dict entry with the override = attribute operator including key, value into the dict. fn dict_insert_override_item(&self, dict: Self::Value, key: &str, value: Self::Value) { - self.dict_insert(dict, key, value, 1, -1); + self.dict_insert(dict, key, value, 1, None); } /// Dict contains key. fn dict_contains_key(&self, dict: Self::Value, key: &str) -> Self::Value { diff --git a/kclvm/compiler/src/lib.rs b/kclvm/compiler/src/lib.rs index 949b320cd..446c83911 100644 --- a/kclvm/compiler/src/lib.rs +++ b/kclvm/compiler/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2021 The KCL Authors. All rights reserved. +//! Copyright The KCL Authors. All rights reserved. pub mod codegen; pub mod value; diff --git a/kclvm/compiler/src/macros.rs b/kclvm/compiler/src/macros.rs index cc47ea8c4..31cd1e64d 100644 --- a/kclvm/compiler/src/macros.rs +++ b/kclvm/compiler/src/macros.rs @@ -1,4 +1,4 @@ -// Copyright 2021 The KCL Authors. All rights reserved. +//! Copyright The KCL Authors. All rights reserved. #[macro_export] macro_rules! check_backtrack_stop { @@ -10,13 +10,3 @@ macro_rules! check_backtrack_stop { } }; } - -#[macro_export] -macro_rules! pkgpath_without_prefix { - ($pkgpath: expr) => { - match $pkgpath.strip_prefix('@') { - Some(v) => v.to_string(), - None => $pkgpath.to_string(), - } - }; -} diff --git a/kclvm/compiler/src/value/lambda.rs b/kclvm/compiler/src/value/lambda.rs index 5948071d2..4e7c84440 100644 --- a/kclvm/compiler/src/value/lambda.rs +++ b/kclvm/compiler/src/value/lambda.rs @@ -1,4 +1,4 @@ -// Copyright 2021 The KCL Authors. All rights reserved. +//! Copyright The KCL Authors. All rights reserved. pub const LAMBDA_NAME: &str = "kclvm_lambda"; pub const LAMBDA_CLOSURE: &str = "$lambda_closure"; diff --git a/kclvm/compiler/src/value/mod.rs b/kclvm/compiler/src/value/mod.rs index 3d10ce495..1578aef2e 100644 --- a/kclvm/compiler/src/value/mod.rs +++ b/kclvm/compiler/src/value/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2021 The KCL Authors. All rights reserved. +//! Copyright The KCL Authors. All rights reserved. mod lambda; pub use self::lambda::*; diff --git a/kclvm/compiler/src/value/schema.rs b/kclvm/compiler/src/value/schema.rs index ab837b45b..2984672f4 100644 --- a/kclvm/compiler/src/value/schema.rs +++ b/kclvm/compiler/src/value/schema.rs @@ -1,4 +1,4 @@ -// Copyright 2021 The KCL Authors. All rights reserved. +//! Copyright The KCL Authors. All rights reserved. pub const SCHEMA_NAME: &str = "$kclvm_schema"; pub const SCHEMA_ATTR_NAME: &str = "$kclvm_schema_attr"; @@ -10,8 +10,20 @@ pub const SCHEMA_CAL_MAP: &str = "$schema_cal_map"; pub const SCHEMA_ARGS: &str = "$schema_args"; pub const SCHEMA_KWARGS: &str = "$schema_kwargs"; pub const SCHEMA_RUNTIME_TYPE: &str = "$schema_runtime_type"; +pub const SCHEMA_VARIABLE_LIST: &[&str] = &[ + BACKTRACK_CACHE, + BACKTRACK_LEVEL_MAP, + SCHEMA_CAL_MAP, + SCHEMA_CONFIG_NAME, + SCHEMA_CONFIG_META_NAME, + SCHEMA_SELF_NAME, + SCHEMA_ARGS, + SCHEMA_KWARGS, + SCHEMA_RUNTIME_TYPE, +]; pub const BACKTRACK_LEVEL_MAP: &str = "$backtrack_level_map"; pub const BACKTRACK_CACHE: &str = "$backtrack_cache"; +pub const GLOBAL_SETTER: &str = "$set"; /// KCL schema type pub struct SchemaType { diff --git a/kclvm/config/Cargo.toml b/kclvm/config/Cargo.toml index 10bab2ee0..0da52d958 100644 --- a/kclvm/config/Cargo.toml +++ b/kclvm/config/Cargo.toml @@ -1,21 +1,27 @@ [package] name = "kclvm-config" -version = "0.1.0" +version = "0.11.0" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] serde = { version = "1", features = ["derive"] } -serde_yaml = "0.8.7" +serde_yaml = {path = "../third-party/serde_yaml"} +serde_json = "1.0" indexmap = "1.0" ahash = "0.7.2" toml = "0.5.8" ron = "0.7.0" chrono = "0.4.19" -rust-crypto = "^0.2" glob = "0.3.0" -fslock = "0.2.1" pathdiff = "0.2.1" +anyhow = "1.0" -kclvm-version = {path = "../version", version = "0.1.0"} +kclvm-version = {path = "../version"} +kclvm-utils = {path = "../utils"} +kclvm-ast = {path = "../ast"} +dirs = "5.0.0" +md-5 = "0.8.0" +regex = "1.10.4" +url = "2.5.4" diff --git a/kclvm/config/src/cache.rs b/kclvm/config/src/cache.rs index 3a286789a..adf1b5bc5 100644 --- a/kclvm/config/src/cache.rs +++ b/kclvm/config/src/cache.rs @@ -1,9 +1,10 @@ -// Copyright 2021 The KCL Authors. All rights reserved. +//! Copyright The KCL Authors. All rights reserved. extern crate chrono; use super::modfile::KCL_FILE_SUFFIX; -use crypto::digest::Digest; -use crypto::md5::Md5; -use fslock::LockFile; +use anyhow::Result; +use kclvm_utils::fslock::open_lock_file; +use kclvm_utils::pkgpath::{parse_external_pkg_name, rm_external_pkg_name}; +use md5::{Digest, Md5}; use serde::{de::DeserializeOwned, Serialize}; use std::collections::HashMap; use std::error; @@ -17,11 +18,11 @@ const LOCK_SUFFIX: &str = ".lock"; const DEFAULT_CACHE_DIR: &str = ".kclvm/cache"; const CACHE_INFO_FILENAME: &str = "info"; const KCL_SUFFIX_PATTERN: &str = "*.k"; +pub const KCL_CACHE_PATH_ENV_VAR: &str = "KCL_CACHE_PATH"; -pub type CacheInfo = String; +pub type CacheInfo = Vec; pub type Cache = HashMap; -#[allow(dead_code)] pub struct CacheOption { cache_dir: String, } @@ -35,98 +36,148 @@ impl Default for CacheOption { } /// Load pkg cache. -pub fn load_pkg_cache(root: &str, pkgpath: &str, option: CacheOption) -> Option +pub fn load_pkg_cache( + root: &str, + target: &str, + pkgpath: &str, + option: CacheOption, + external_pkgs: &HashMap, +) -> Option where T: DeserializeOwned + Default, { if root.is_empty() || pkgpath.is_empty() { None } else { - let filename = get_cache_filename(root, pkgpath, Some(&option.cache_dir)); + // The cache file path + let filename = get_cache_filename(root, target, pkgpath, Some(&option.cache_dir)); if !Path::new(&filename).exists() { None } else { // Compare the md5 using cache let real_path = get_pkg_realpath_from_pkgpath(root, pkgpath); - if Path::new(&real_path).exists() { - let cache_info = read_info_cache(root, Some(&option.cache_dir)); - let relative_path = real_path.replacen(root, ".", 1); - match cache_info.get(&relative_path) { - Some(path_info_in_cache) => { - if get_cache_info(&real_path).ne(path_info_in_cache) { - return None; - } + // If the file exists and it is an internal package or an external package, + // Check the cache info. + let pkg_name = parse_external_pkg_name(pkgpath).ok()?; + + // If it is an internal package + let real_path = if Path::new(&real_path).exists() { + real_path + // If it is an external package + } else if external_pkgs.get(&pkg_name).is_some() + && Path::new(external_pkgs.get(&pkg_name)?).exists() + { + get_pkg_realpath_from_pkgpath( + external_pkgs.get(&pkg_name)?, + &rm_external_pkg_name(pkgpath).ok()?, + ) + } else { + return None; + }; + + // get the cache info from cache file "info" + let cache_info = read_info_cache(root, target, Some(&option.cache_dir)); + let relative_path = real_path.replacen(root, ".", 1); + match cache_info.get(&relative_path) { + Some(path_info_in_cache) => { + // calculate the md5 of the file and compare it with the cache info + if get_cache_info(&real_path).ne(path_info_in_cache) { + return None; } - None => return None, - }; - } + } + None => return None, + }; + // If the md5 is the same, load the cache file load_data_from_file(&filename) } } } /// Save pkg cache. -pub fn save_pkg_cache(root: &str, pkgpath: &str, data: T, option: CacheOption) +pub fn save_pkg_cache( + root: &str, + target: &str, + pkgpath: &str, + data: T, + option: CacheOption, + external_pkgs: &HashMap, +) -> Result<()> where T: Serialize, { if root.is_empty() || pkgpath.is_empty() { - return; + return Err(anyhow::anyhow!( + "failed to save package cache {} to root {}", + pkgpath, + root + )); } - let dst_filename = get_cache_filename(root, pkgpath, Some(&option.cache_dir)); + let dst_filename = get_cache_filename(root, target, pkgpath, Some(&option.cache_dir)); let real_path = get_pkg_realpath_from_pkgpath(root, pkgpath); if Path::new(&real_path).exists() { - write_info_cache(root, Some(&option.cache_dir), &real_path).unwrap(); + write_info_cache(root, target, Some(&option.cache_dir), &real_path).unwrap(); + } else { + // If the file does not exist, it is an external package. + let pkg_name = parse_external_pkg_name(pkgpath)?; + let real_path = get_pkg_realpath_from_pkgpath( + external_pkgs + .get(&pkg_name) + .ok_or(anyhow::anyhow!("failed to save cache"))?, + &rm_external_pkg_name(pkgpath)?, + ); + if Path::new(&real_path).exists() { + write_info_cache(root, target, Some(&option.cache_dir), &real_path).unwrap(); + } } let cache_dir = get_cache_dir(root, Some(&option.cache_dir)); create_dir_all(&cache_dir).unwrap(); let tmp_filename = temp_file(&cache_dir, pkgpath); save_data_to_file(&dst_filename, &tmp_filename, data) + .map_err(|e| anyhow::anyhow!(e.to_string()))?; + Ok(()) } #[inline] fn get_cache_dir(root: &str, cache_dir: Option<&str>) -> String { - let cache_dir = cache_dir.or(Some(DEFAULT_CACHE_DIR)).unwrap(); - format!( - "{}/{}/{}-{}", - root, - cache_dir, - version::VERSION, - version::CHECK_SUM - ) + let cache_dir = cache_dir.unwrap_or(DEFAULT_CACHE_DIR); + let root = std::env::var(KCL_CACHE_PATH_ENV_VAR).unwrap_or(root.to_string()); + Path::new(&root) + .join(cache_dir) + .join(format!("{}-{}", version::VERSION, version::CHECK_SUM)) + .display() + .to_string() } #[inline] -#[allow(dead_code)] -fn get_cache_filename(root: &str, pkgpath: &str, cache_dir: Option<&str>) -> String { - let cache_dir = cache_dir.or(Some(DEFAULT_CACHE_DIR)).unwrap(); - format!( - "{}/{}/{}-{}/{}", - root, - cache_dir, - version::VERSION, - version::CHECK_SUM, - pkgpath - ) +fn get_cache_filename(root: &str, target: &str, pkgpath: &str, cache_dir: Option<&str>) -> String { + let cache_dir = cache_dir.unwrap_or(DEFAULT_CACHE_DIR); + let root = std::env::var(KCL_CACHE_PATH_ENV_VAR).unwrap_or(root.to_string()); + Path::new(&root) + .join(cache_dir) + .join(format!("{}-{}", version::VERSION, version::CHECK_SUM)) + .join(target) + .join(pkgpath) + .display() + .to_string() } #[inline] -fn get_cache_info_filename(root: &str, cache_dir: Option<&str>) -> String { - let cache_dir = cache_dir.or(Some(DEFAULT_CACHE_DIR)).unwrap(); - format!( - "{}/{}/{}-{}/{}", - root, - cache_dir, - version::VERSION, - version::CHECK_SUM, - CACHE_INFO_FILENAME - ) +fn get_cache_info_filename(root: &str, target: &str, cache_dir: Option<&str>) -> String { + let cache_dir = cache_dir.unwrap_or(DEFAULT_CACHE_DIR); + let root = std::env::var(KCL_CACHE_PATH_ENV_VAR).unwrap_or(root.to_string()); + Path::new(&root) + .join(cache_dir) + .join(format!("{}-{}", version::VERSION, version::CHECK_SUM)) + .join(target) + .join(CACHE_INFO_FILENAME) + .display() + .to_string() } /// Read the cache if it exists and is well formed. /// If it is not well formed, the call to write_info_cache later should resolve the issue. -pub fn read_info_cache(root: &str, cache_dir: Option<&str>) -> Cache { - let cache_file = get_cache_info_filename(root, cache_dir); +pub fn read_info_cache(root: &str, target: &str, cache_dir: Option<&str>) -> Cache { + let cache_file = get_cache_info_filename(root, target, cache_dir); if !Path::new(&cache_file).exists() { return Cache::default(); } @@ -140,24 +191,25 @@ pub fn read_info_cache(root: &str, cache_dir: Option<&str>) -> Cache { /// Update the cache info file. pub fn write_info_cache( root: &str, + target: &str, cache_name: Option<&str>, filepath: &str, ) -> Result<(), Box> { - let dst_filename = get_cache_info_filename(root, cache_name); + let dst_filename = get_cache_info_filename(root, target, cache_name); let cache_dir = get_cache_dir(root, cache_name); let path = Path::new(&cache_dir); - create_dir_all(path).unwrap(); + create_dir_all(path)?; let relative_path = filepath.replacen(root, ".", 1); let cache_info = get_cache_info(filepath); let tmp_filename = temp_file(&cache_dir, ""); - let mut lock_file = LockFile::open(&format!("{}{}", dst_filename, LOCK_SUFFIX)).unwrap(); - lock_file.lock().unwrap(); - let mut cache = read_info_cache(root, cache_name); + let mut lock_file = open_lock_file(&format!("{}{}", dst_filename, LOCK_SUFFIX))?; + lock_file.lock()?; + let mut cache = read_info_cache(root, target, cache_name); cache.insert(relative_path, cache_info); - let mut file = File::create(&tmp_filename).unwrap(); - file.write_all(&ron::ser::to_string(&cache).unwrap().as_bytes()).unwrap(); - std::fs::rename(&tmp_filename, &dst_filename).unwrap(); - lock_file.unlock().unwrap(); + let mut file = File::create(&tmp_filename)?; + file.write_all(ron::ser::to_string(&cache)?.as_bytes())?; + std::fs::rename(&tmp_filename, &dst_filename)?; + lock_file.unlock()?; Ok(()) } @@ -171,7 +223,10 @@ fn get_cache_info(path_str: &str) -> CacheInfo { file.read_to_end(&mut buf).unwrap(); md5.input(buf.as_slice()); } else { - let pattern = format!("{}/{}", path_str, KCL_SUFFIX_PATTERN); + let pattern = Path::new(path_str) + .join(KCL_SUFFIX_PATTERN) + .display() + .to_string(); for file in glob::glob(&pattern).unwrap().flatten() { let mut file = File::open(file).unwrap(); let mut buf: Vec = vec![]; @@ -179,7 +234,7 @@ fn get_cache_info(path_str: &str) -> CacheInfo { md5.input(buf.as_slice()); } } - md5.result_str() + md5.result().to_vec() } pub fn get_pkg_realpath_from_pkgpath(root: &str, pkgpath: &str) -> String { @@ -204,21 +259,31 @@ where } } -pub fn save_data_to_file(dst_filename: &str, tmp_filename: &str, data: T) +pub fn save_data_to_file( + dst_filename: &str, + tmp_filename: &str, + data: T, +) -> Result<(), Box> where T: Serialize, { - let mut lock_file = LockFile::open(&format!("{}{}", dst_filename, LOCK_SUFFIX)).unwrap(); - lock_file.lock().unwrap(); - let file = File::create(tmp_filename).unwrap(); - ron::ser::to_writer(file, &data).unwrap(); - std::fs::rename(tmp_filename, dst_filename).unwrap(); - lock_file.unlock().unwrap(); + let mut lock_file = open_lock_file(&format!("{}{}", dst_filename, LOCK_SUFFIX))?; + lock_file.lock()?; + let file = File::create(tmp_filename)?; + ron::ser::to_writer(file, &data)?; + std::fs::rename(tmp_filename, dst_filename)?; + lock_file.unlock()?; + Ok(()) } #[inline] fn temp_file(cache_dir: &str, pkgpath: &str) -> String { - let timestamp = chrono::Local::now().timestamp_nanos(); + let timestamp = chrono::Local::now() + .timestamp_nanos_opt() + .unwrap_or_default(); let id = std::process::id(); - format!("{}/{}.{}.{}.tmp", cache_dir, pkgpath, id, timestamp) + Path::new(cache_dir) + .join(format!("{}.{}.{}.tmp", pkgpath, id, timestamp)) + .display() + .to_string() } diff --git a/kclvm/config/src/lib.rs b/kclvm/config/src/lib.rs index fc6c23d66..4856a040b 100644 --- a/kclvm/config/src/lib.rs +++ b/kclvm/config/src/lib.rs @@ -1,6 +1,11 @@ -// Copyright 2021 The KCL Authors. All rights reserved. +//! Copyright The KCL Authors. All rights reserved. pub mod cache; pub mod modfile; +pub mod path; pub mod settings; pub mod vfs; +pub mod workfile; + +#[cfg(test)] +pub(crate) mod tests; diff --git a/kclvm/config/src/modfile.rs b/kclvm/config/src/modfile.rs index 246fc045c..3c5410d2b 100644 --- a/kclvm/config/src/modfile.rs +++ b/kclvm/config/src/modfile.rs @@ -1,66 +1,282 @@ -// Copyright 2021 The KCL Authors. All rights reserved. +//! Copyright The KCL Authors. All rights reserved. -use serde::Deserialize; -use std::io::Read; +use anyhow::Result; +use kclvm_utils::path::PathPrefix; +use serde::{Deserialize, Serialize}; +use std::{ + collections::HashMap, + env, fs, + io::Read, + path::{Path, PathBuf}, +}; use toml; +use url::Url; + +use crate::path::ModRelativePath; pub const KCL_MOD_FILE: &str = "kcl.mod"; +pub const KCL_MOD_LOCK_FILE: &str = "kcl.mod.lock"; +pub const KCL_WORK_FILE: &str = "kcl.work"; pub const KCL_FILE_SUFFIX: &str = ".k"; +pub const KCL_FILE_EXTENSION: &str = "k"; pub const KCL_MOD_PATH_ENV: &str = "${KCL_MOD}"; +pub const KCL_PKG_PATH: &str = "KCL_PKG_PATH"; +pub const DEFAULT_KCL_HOME: &str = ".kcl"; +pub const DEFAULT_KPM_SUBDIR: &str = "kpm"; + +/// ModFile is kcl package file 'kcl.mod'. +#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq, Eq)] +pub struct ModFile { + pub package: Option, + pub profile: Option, + pub dependencies: Option, +} -#[allow(dead_code)] -#[derive(Default, Deserialize)] -pub struct KCLModFile { - pub root: Option, - pub root_pkg: Option, - pub build: Option, - pub expected: Option, +/// ModLockFile is kcl package file 'kc.mod.lock'. +#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq, Eq)] +pub struct ModLockFile { + pub dependencies: Option, } -#[allow(dead_code)] -#[derive(Default, Deserialize)] -pub struct KCLModFileBuildSection { - pub enable_pkg_cache: Option, - pub cached_pkg_prefix: Option, - pub target: Option, +/// Package is the kcl package section of 'kcl.mod'. +#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq, Eq)] +pub struct Package { + /// The name of the package. + pub name: Option, + /// The kcl compiler version + pub edition: Option, + /// The version of the package. + pub version: Option, + /// Description denotes the description of the package. + pub description: Option, + /// Exclude denote the files to include when publishing. + pub include: Option>, + /// Exclude denote the files to exclude when publishing. + pub exclude: Option>, } -#[allow(dead_code)] -#[derive(Default, Deserialize)] -pub struct KCLModFileExpectedSection { - pub min_build_time: Option, - pub max_build_time: Option, - pub kclvm_version: Option, - pub kcl_plugin_version: Option, - pub global_version: Option, +/// Profile is the profile section of 'kcl.mod'. +/// It is used to specify the compilation options of the current package. +#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq, Eq)] +pub struct Profile { + /// A list of entry-point files. + pub entries: Option>, + /// Flag that, when true, disables the emission of the special 'none' value in the output. + pub disable_none: Option, + /// Flag that, when true, ensures keys in maps are sorted. + pub sort_keys: Option, + /// A list of attribute selectors for conditional compilation. + pub selectors: Option>, + /// A list of override paths. + pub overrides: Option>, + /// A list of additional options for the KCL compiler. + pub options: Option>, } -pub fn get_pkg_root_from_paths(file_paths: &[String]) -> Result { +/// A map of package names to their respective dependency specifications. +pub type Dependencies = HashMap; +pub type LockDependencies = HashMap; + +/// Dependency represents a single dependency for a package, which may come in different forms +/// such as version, Git repository, OCI repository, or a local path. +#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)] +#[serde(untagged)] +pub enum Dependency { + /// Specifies a version dependency, e.g., "1.0.0". + Version(String), + /// Specifies a Git source dependency. + Git(GitSource), + /// Specifies an OCI (Open Container Initiative) image source dependency. + Oci(OciSource), + /// Specifies a local path dependency. + Local(LocalSource), +} + +#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)] +pub struct LockDependency { + /* Common field */ + pub name: String, + pub full_name: Option, + pub version: Option, + pub sum: Option, + + /* OCI Source */ + pub reg: Option, + pub repo: Option, + pub oci_tag: Option, + + /* Git Source */ + pub url: Option, + pub branch: Option, + pub commit: Option, + pub git_tag: Option, + + /* Local Source */ + pub path: Option, +} + +impl LockDependency { + pub fn gen_filename(&self) -> String { + if let Some(git_url) = &self.url { + if let Ok(parsed_url) = Url::parse(git_url) { + if let Some(last_segment) = parsed_url + .path_segments() + .and_then(|segments| segments.last()) + { + let trimmed_segment = last_segment.trim_end_matches(".git"); + return trimmed_segment.to_string(); + } + } + } + + if let Some(oci_repo) = &self.repo { + if let Ok(parsed_url) = Url::parse(oci_repo) { + if let Some(last_segment) = parsed_url + .path_segments() + .and_then(|segments| segments.last()) + { + return last_segment.to_string(); + } + } + } + + return self.name.replace('-', "_"); + } +} + +#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq, Eq)] +pub struct GitSource { + /// The URL of the Git repository. + pub git: String, + /// An optional branch name within the Git repository. + pub branch: Option, + /// An optional commit hash to check out from the Git repository. + pub commit: Option, + /// An optional tag name to check out from the Git repository. + pub tag: Option, + /// An optional version specification associated with Git source. + pub version: Option, +} + +/// Defines an OCI package as a source for a dependency. +#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq, Eq)] +pub struct OciSource { + // The URI of the OCI repository. + pub oci: String, + /// An optional tag of the OCI package in the registry. + pub tag: Option, +} + +/// Defines a local filesystem path as a source for a dependency. +#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq, Eq)] +pub struct LocalSource { + /// The path to the local directory or file. + pub path: String, +} + +impl ModFile { + #[inline] + pub fn get_entries(&self) -> Option> { + self.profile.as_ref().map(|p| p.entries.clone()).flatten() + } +} + +/// Load kcl mod file from path +pub fn load_mod_file>(path: P) -> Result { + let file_path = path.as_ref().join(KCL_MOD_FILE); + let mut file = std::fs::File::open(file_path)?; + let mut buffer: Vec = vec![]; + file.read_to_end(&mut buffer)?; + toml::from_slice(buffer.as_slice()).map_err(|e| anyhow::anyhow!(e)) +} + +/// Load kcl mod lock file from path +pub fn load_mod_lock_file>(path: P) -> Result { + let file_path = path.as_ref().join(KCL_MOD_LOCK_FILE); + let mut file = std::fs::File::open(file_path)?; + let mut buffer: Vec = vec![]; + file.read_to_end(&mut buffer)?; + toml::from_slice(buffer.as_slice()).map_err(|e| anyhow::anyhow!(e)) +} + +/// Get the path holding the external kcl package. +/// From the environment variable KCL_PKG_PATH. +/// If `KCL_PKG_PATH` is not present, then the user root string is returned. +/// If the user root directory cannot be found, an empty string will be returned. +pub fn get_vendor_home() -> String { + match env::var(KCL_PKG_PATH) { + Ok(path) => path.adjust_canonicalization(), + Err(_) => create_default_vendor_home() + .unwrap_or_default() + .adjust_canonicalization(), + } +} + +/// Create a '.kcl/kpm' folder in the user's root directory, +/// returning the folder path in [Option::Some] if it already exists. +/// +/// If the folder does not exist, create it and return the file path +/// in [Option::Some]. +/// +/// If creating the folder failed, [`Option::None`] is returned. +pub fn create_default_vendor_home() -> Option { + #[cfg(target_os = "windows")] + let root_dir = match env::var("USERPROFILE") { + Ok(val) => val, + Err(_) => return None, + }; + #[cfg(not(target_os = "windows"))] + let root_dir = match env::var("HOME") { + Ok(val) => val, + Err(_) => return None, + }; + let kpm_home = PathBuf::from(root_dir) + .join(DEFAULT_KCL_HOME) + .join(DEFAULT_KPM_SUBDIR); + match kpm_home.canonicalize() { + Ok(path) => return Some(path.display().to_string()), + Err(_) => match fs::create_dir_all(kpm_home.clone()) { + Ok(_) => match kpm_home.canonicalize() { + Ok(p) => Some(p.display().to_string()), + Err(_) => None, + }, + Err(_) => None, + }, + } +} + +/// Get package root path from input file paths and workdir. +pub fn get_pkg_root_from_paths(file_paths: &[String], workdir: String) -> Result { if file_paths.is_empty() { - return Err("no files".to_string()); + return Err("No input KCL files or paths".to_string()); } let mut m = std::collections::HashMap::::new(); let mut last_root = "".to_string(); for s in file_paths { - if s.contains(KCL_MOD_PATH_ENV) { + let path = ModRelativePath::from(s.to_string()); + if path.is_relative_path().map_err(|err| err.to_string())? { continue; } + if let Some(root) = get_pkg_root(s) { m.insert(root.clone(), root.clone()); last_root = root.clone(); } } if m.is_empty() { - return Err("not found".to_string()); + return Ok("".to_string()); } if m.len() == 1 { - return Ok(last_root); + Ok(last_root) + } else if !workdir.is_empty() { + return Ok(workdir); + } else { + return Ok("".to_string()); } - - Err(format!("conflict kcl.mod file paths: {:?}", m)) } +/// Get package root path from the single input file path. pub fn get_pkg_root(k_file_path: &str) -> Option { if k_file_path.is_empty() { return None; @@ -71,7 +287,7 @@ pub fn get_pkg_root(k_file_path: &str) -> Option { while module_path.exists() { let kcl_mod_path = module_path.join(KCL_MOD_FILE); if kcl_mod_path.exists() && kcl_mod_path.is_file() { - return Some(module_path.to_str().unwrap().to_string()); + return Some(module_path.adjust_canonicalization()); } if let Some(path) = module_path.parent() { module_path = path.to_path_buf(); @@ -83,24 +299,13 @@ pub fn get_pkg_root(k_file_path: &str) -> Option { if k_file_path.ends_with(KCL_FILE_SUFFIX) { if let Ok(path) = std::path::Path::new(k_file_path).canonicalize() { if let Some(path) = path.parent() { - return Some(path.to_str().unwrap().to_string()); + return Some(path.adjust_canonicalization()); } } } None } -pub fn load_mod_file(root: &str) -> KCLModFile { - let k_mod_file_path = std::path::Path::new(root).join(KCL_MOD_FILE); - if !k_mod_file_path.exists() { - return KCLModFile::default(); - } - let mut file = std::fs::File::open(k_mod_file_path.to_str().unwrap()).unwrap(); - let mut buffer: Vec = vec![]; - file.read_to_end(&mut buffer).unwrap(); - toml::from_slice(buffer.as_slice()).unwrap() -} - #[cfg(test)] mod modfile_test { use crate::modfile::*; @@ -108,51 +313,77 @@ mod modfile_test { const TEST_ROOT: &str = "./src/testdata/"; const SETTINGS_FILE: &str = "./src/testdata/kcl.mod"; + #[test] + fn test_get_pkg_root_from_paths() { + assert_eq!( + get_pkg_root_from_paths(&[], "".to_string()), + Err("No input KCL files or paths".to_string()) + ); + assert_eq!( + get_pkg_root_from_paths(&["wrong_path".to_string()], "".to_string()), + Ok("".to_string()) + ); + let expected_root = std::path::Path::new(TEST_ROOT).canonicalize().unwrap(); + let expected = expected_root.adjust_canonicalization(); + assert_eq!( + get_pkg_root_from_paths(&[SETTINGS_FILE.to_string()], "".to_string()), + Ok(expected.to_string()) + ); + } + #[test] fn test_get_pkg_root() { let root = get_pkg_root(SETTINGS_FILE); assert!(root.is_some()); let expected_root = std::path::Path::new(TEST_ROOT).canonicalize().unwrap(); - let expected = expected_root.to_str().unwrap(); + let expected = expected_root.adjust_canonicalization(); assert_eq!(root.unwrap().as_str(), expected); } #[test] fn test_load_mod_file() { - let kcl_mod = load_mod_file(TEST_ROOT); + let kcl_mod = load_mod_file(TEST_ROOT).unwrap(); + assert_eq!( + kcl_mod.package.as_ref().unwrap().name.as_ref().unwrap(), + "test_add_deps" + ); + assert_eq!( + kcl_mod.package.as_ref().unwrap().version.as_ref().unwrap(), + "0.0.1" + ); + assert_eq!( + kcl_mod.package.as_ref().unwrap().edition.as_ref().unwrap(), + "0.0.1" + ); + assert_eq!( + kcl_mod.profile.as_ref().unwrap().entries.as_ref().unwrap(), + &vec!["main.k".to_string()] + ); assert_eq!( - kcl_mod.build.as_ref().unwrap().enable_pkg_cache.unwrap(), - true + kcl_mod.dependencies.as_ref().unwrap().get("pkg0"), + Some(&Dependency::Git(GitSource { + git: "test_url".to_string(), + tag: Some("test_tag".to_string()), + ..Default::default() + })) ); assert_eq!( - kcl_mod - .build - .as_ref() - .unwrap() - .cached_pkg_prefix - .as_ref() - .unwrap(), - "pkg.path" + kcl_mod.dependencies.as_ref().unwrap().get("pkg1"), + Some(&Dependency::Version("oci_tag1".to_string())) ); assert_eq!( - kcl_mod - .expected - .as_ref() - .unwrap() - .kclvm_version - .as_ref() - .unwrap(), - "v0.3.0" + kcl_mod.dependencies.as_ref().unwrap().get("pkg2"), + Some(&Dependency::Oci(OciSource { + oci: "oci://ghcr.io/kcl-lang/helloworld".to_string(), + tag: Some("0.1.1".to_string()), + ..Default::default() + })) ); assert_eq!( - kcl_mod - .expected - .as_ref() - .unwrap() - .kcl_plugin_version - .as_ref() - .unwrap(), - "v0.2.0" + kcl_mod.dependencies.as_ref().unwrap().get("pkg3"), + Some(&Dependency::Local(LocalSource { + path: "../pkg".to_string(), + })) ); } } diff --git a/kclvm/config/src/path.rs b/kclvm/config/src/path.rs new file mode 100644 index 000000000..3c54c74d3 --- /dev/null +++ b/kclvm/config/src/path.rs @@ -0,0 +1,201 @@ +//! The file provides the mod relative path type. +//! +//! The mod relative path is a path that is relative to the root package path. +//! The root package is can be specified by the prefix `${:KCL_MOD}`. +//! `` is the name of the root package. +//! If `` is omitted, the root package is the current package. +//! +//! # Examples +//! +//! `/usr/my_pkg` is the real path of the package `my_pkg`. +//! `${my_pkg:KCL_MOD}/sub/main.k` is a mod relative path. +//! The real path of `${my_pkg:KCL_MOD}/xxx/main.k` is `/usr/my_pkg/sub/main.k`. +use anyhow::Result; +use regex::Regex; +use std::path::PathBuf; + +#[derive(Clone, Debug, Default)] +/// [`ModRelativePath`] is a path that is relative to the root package path. +/// The root package is can be specified by the prefix `${:KCL_MOD}`. +/// `` is the name of the root package. +/// If `` is omitted, the root package is the current package. +/// +/// # Examples +/// +/// `/usr/my_pkg` is the real path of the package `my_pkg`. +/// `${my_pkg:KCL_MOD}/sub/main.k` is a mod relative path. +/// The real path of `${my_pkg:KCL_MOD}/xxx/main.k` is `/usr/my_pkg/sub/main.k`. +pub struct ModRelativePath { + path: String, +} + +/// The regular expression to match the mod relative path preffix. +const RELATIVE_PATH_PREFFIX: &str = r#"\$\{((?P[a-zA-Z0-9_-]+):)?KCL_MOD\}/"#; + +/// The name of the root package. +const ROOT_PKG_NAME_FLAG: &str = "name"; + +impl From for ModRelativePath { + fn from(path: String) -> Self { + ModRelativePath::new(path) + } +} + +impl ModRelativePath { + /// [`new`] creates a new [`ModRelativePath`] instance. + pub fn new(path: String) -> ModRelativePath { + ModRelativePath { path } + } + + /// [`get_path`] returns the clone string of path of the [`ModRelativePath`]. + pub fn get_path(&self) -> String { + self.path.clone() + } + + /// [`is_relative_path`] returns true if the path is a mod relative path. + /// + /// # Examples + /// + /// ```rust + /// use kclvm_config::path::ModRelativePath; + /// let path = ModRelativePath::new("${my_pkg:KCL_MOD}/src/path.rs".to_string()); + /// assert_eq!(path.is_relative_path().unwrap(), true); + /// + /// let path = ModRelativePath::new("${KCL_MOD}/src/path.rs".to_string()); + /// assert_eq!(path.is_relative_path().unwrap(), true); + /// + /// let path = ModRelativePath::new("/usr/${my_pkg:KCL_MOD}/src/path.rs".to_string()); + /// assert_eq!(path.is_relative_path().unwrap(), false); + /// + /// let path = ModRelativePath::new("/src/path.rs".to_string()); + /// assert_eq!(path.is_relative_path().unwrap(), false); + /// ``` + pub fn is_relative_path(&self) -> Result { + Ok(Regex::new(RELATIVE_PATH_PREFFIX)? + .find(&self.path) + .map_or(false, |mat| mat.start() == 0)) + } + + /// [`get_root_pkg_name`] returns the name of the root package. + /// + /// # Examples + /// + /// ```rust + /// use kclvm_config::path::ModRelativePath; + /// let path = ModRelativePath::new("${my_pkg:KCL_MOD}/src/path.rs".to_string()); + /// assert_eq!(path.get_root_pkg_name().unwrap(), Some("my_pkg".to_string())); + /// + /// let path = ModRelativePath::new("${KCL_MOD}/src/path.rs".to_string()); + /// assert_eq!(path.get_root_pkg_name().unwrap(), None); + /// + /// let path = ModRelativePath::new("/src/path.rs".to_string()); + /// assert_eq!(path.get_root_pkg_name().unwrap(), None); + /// ``` + pub fn get_root_pkg_name(&self) -> Result> { + if !self.is_relative_path()? { + return Ok(None); + } + + Ok(Regex::new(RELATIVE_PATH_PREFFIX)? + .captures(&self.path) + .and_then(|caps| caps.name(ROOT_PKG_NAME_FLAG)) + .map(|mat| mat.as_str().to_string())) + } + + /// [`canonicalize_by_root_path`] returns the canonicalized path by the root path. + /// + /// # Examples + /// + /// ```rust + /// use kclvm_config::path::ModRelativePath; + /// let path = ModRelativePath::new("${name:KCL_MOD}/src/path".to_string()); + /// #[cfg(target_os = "windows")] + /// assert_eq!(path.canonicalize_by_root_path("/usr/my_pkg").unwrap(), "/usr/my_pkg\\src/path"); + /// #[cfg(not(target_os = "windows"))] + /// assert_eq!(path.canonicalize_by_root_path("/usr/my_pkg").unwrap(), "/usr/my_pkg/src/path"); + /// + /// let path = ModRelativePath::new("/src/path".to_string()); + /// assert_eq!(path.canonicalize_by_root_path("/usr/my_pkg").unwrap(), "/src/path"); + /// ``` + pub fn canonicalize_by_root_path(&self, root_path: &str) -> Result { + if !self.is_relative_path()? { + return Ok(self.get_path()); + } + + Ok(Regex::new(RELATIVE_PATH_PREFFIX)? + .captures(&self.path) + .map_or_else( + || self.get_path(), + |caps| { + // Due to the path format is different between windows and linux, + // Can not use the replace method directly + // by 'replace(std::str::from_utf8(caps.get(0).unwrap().as_bytes()).unwrap(), root_path)'. + let sub_path = self.get_path().replace(caps.get(0).unwrap().as_str(), ""); + let res = PathBuf::from(root_path) + .join(sub_path) + .display() + .to_string(); + + res + }, + )) + } +} + +#[cfg(test)] +mod test_relative_path { + use super::*; + + #[test] + fn test_is_relative_path() { + let path = ModRelativePath::new("${name:KCL_MOD}/src/path.rs".to_string()); + assert!(path.is_relative_path().unwrap()); + let path = ModRelativePath::new("${KCL_MOD}/src/path.rs".to_string()); + assert!(path.is_relative_path().unwrap()); + let path = ModRelativePath::new("/usr/${name:KCL_MOD}/src/path.rs".to_string()); + assert!(!path.is_relative_path().unwrap()); + let path = ModRelativePath::new("/src/path.rs".to_string()); + assert!(!path.is_relative_path().unwrap()); + let path = ModRelativePath::new("./src/path.rs".to_string()); + assert!(!path.is_relative_path().unwrap()); + let path = ModRelativePath::new("${K_MOD}/src/path.rs".to_string()); + assert!(!path.is_relative_path().unwrap()); + let path = ModRelativePath::new("${:KCL_MOD}/src/path.rs".to_string()); + assert!(!path.is_relative_path().unwrap()); + } + + #[test] + fn test_get_root_pkg_name() { + let path = ModRelativePath::new("${my_pkg:KCL_MOD}/src/path.rs".to_string()); + assert_eq!( + path.get_root_pkg_name().unwrap(), + Some("my_pkg".to_string()) + ); + + let path = ModRelativePath::new("${KCL_MOD}/src/path.rs".to_string()); + assert_eq!(path.get_root_pkg_name().unwrap(), None); + + let path = ModRelativePath::new("/src/path.rs".to_string()); + assert_eq!(path.get_root_pkg_name().unwrap(), None); + } + + #[test] + fn test_canonicalize_by_root_path() { + let path = ModRelativePath::new("${name:KCL_MOD}/src/path".to_string()); + #[cfg(target_os = "windows")] + assert_eq!( + path.canonicalize_by_root_path("C:\\usr\\my_pkg").unwrap(), + "C:\\usr\\my_pkg\\src/path" + ); + #[cfg(not(target_os = "windows"))] + assert_eq!( + path.canonicalize_by_root_path("/usr/my_pkg").unwrap(), + "/usr/my_pkg/src/path" + ); + let path = ModRelativePath::new("/src/path".to_string()); + assert_eq!( + path.canonicalize_by_root_path("/usr/my_pkg").unwrap(), + "/src/path" + ); + } +} diff --git a/kclvm/config/src/settings.rs b/kclvm/config/src/settings.rs index 8af9b8a8a..30108e965 100644 --- a/kclvm/config/src/settings.rs +++ b/kclvm/config/src/settings.rs @@ -1,16 +1,46 @@ -// Copyright 2021 The KCL Authors. All rights reserved. -use serde::{Deserialize, Serialize}; - -const INVALID_KCL_OPTIONS_MSG: &str = "invalid kcl_options"; -const SETTINGS_FILE_PARA: &str = "-Y"; -const ARGUMENTS_PARA: &str = "-D"; -const OUTPUT_PARA: &str = "-o"; -const OVERRIDES_PARA: &str = "-O"; -const PATH_SELECTOR_PARA: &str = "-S"; -const STRICT_RANGE_CHECK_PARA: &str = "-r"; -const DISABLE_NONE_PARA: &str = "-n"; -const VERBOSE_PARA: &str = "-v"; -const DEBUG_PARA: &str = "-d"; +//! Copyright The KCL Authors. All rights reserved. +use anyhow::{Context, Result}; +use serde::{ + de::{DeserializeSeed, Error, MapAccess, SeqAccess, Unexpected, Visitor}, + Deserialize, Serialize, +}; +use std::{collections::HashMap, ops::Deref, path::PathBuf}; + +/// Default settings file `kcl.yaml` +pub const DEFAULT_SETTING_FILE: &str = "kcl.yaml"; + +/// Readonly settings with the filepath. +#[derive(Debug, Default, Clone)] +pub struct SettingsPathBuf(Option, SettingsFile); + +impl SettingsPathBuf { + /// New a settings with path and settings content. + #[inline] + pub fn new(path: Option, settings: SettingsFile) -> Self { + Self(path, settings) + } + + /// Get the output setting. + #[inline] + pub fn output(&self) -> Option { + match &self.1.kcl_cli_configs { + Some(c) => c.output.clone(), + None => None, + } + } + + /// Get the path. + #[inline] + pub fn path(&self) -> &Option { + &self.0 + } + + /// Get the settings. + #[inline] + pub fn settings(&self) -> &SettingsFile { + &self.1 + } +} #[derive(Serialize, Deserialize, Debug, Clone)] pub struct SettingsFile { @@ -18,7 +48,7 @@ pub struct SettingsFile { pub kcl_options: Option>, } -#[derive(Serialize, Deserialize, Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone, Default)] pub struct Config { pub files: Option>, pub file: Option>, @@ -29,6 +59,15 @@ pub struct Config { pub disable_none: Option, pub verbose: Option, pub debug: Option, + pub sort_keys: Option, + pub show_hidden: Option, + /// Whether including schema type in JSON/YAML result. + pub include_schema_type_path: Option, + /// kcl needs a mapping between the package name and the package path + /// to determine the source code path corresponding to different version package. + pub package_maps: Option>, + /// Use the evaluator to execute the AST program instead of AOT. + pub fast_eval: Option, } impl SettingsFile { @@ -44,10 +83,42 @@ impl SettingsFile { disable_none: Some(false), verbose: Some(0), debug: Some(false), + sort_keys: Some(false), + show_hidden: Some(false), + fast_eval: Some(false), + include_schema_type_path: Some(false), + package_maps: Some(HashMap::default()), }), kcl_options: Some(vec![]), } } + + /// Get the output setting. + #[inline] + pub fn output(&self) -> Option { + match &self.kcl_cli_configs { + Some(c) => c.output.clone(), + None => None, + } + } + + /// Get the input setting. + #[inline] + pub fn input(&self) -> Vec { + match &self.kcl_cli_configs { + Some(c) => match &c.file { + Some(file) => match &c.files { + Some(files) if !files.is_empty() => files.clone(), + _ => file.clone(), + }, + None => match &c.files { + Some(files) => files.clone(), + None => vec![], + }, + }, + None => vec![], + } + } } impl Default for SettingsFile { @@ -56,21 +127,236 @@ impl Default for SettingsFile { } } -#[derive(Serialize, Deserialize, Debug, Clone)] +/// Top level argument key value pair. +#[derive(Serialize, Deserialize, Debug, Clone, Default)] pub struct KeyValuePair { - key: String, - value: String, + /// key is the top level argument key. + pub key: String, + // Note: here is a normal json string including int, float, string, bool list and dict. + pub value: ValueString, } -#[derive(Serialize, Deserialize, Debug, Clone)] +#[macro_export] +macro_rules! tri { + ($e:expr $(,)?) => { + match $e { + core::result::Result::Ok(val) => val, + core::result::Result::Err(err) => return core::result::Result::Err(err), + } + }; +} + +/// MapStringKey denotes the map deserialize key. +struct MapStringKey; +impl<'de> DeserializeSeed<'de> for MapStringKey { + type Value = String; + + fn deserialize(self, deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + deserializer.deserialize_str(self) + } +} + +impl<'de> Visitor<'de> for MapStringKey { + type Value = String; + + fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { + formatter.write_str("a string key") + } + + fn visit_str(self, s: &str) -> Result + where + E: serde::de::Error, + { + Ok(s.to_owned()) + } + + fn visit_string(self, s: String) -> Result + where + E: serde::de::Error, + { + Ok(s) + } +} + +/// Top level argument value string. +/// Note: here is a normal json string including int, float, string, bool list and dict. +#[derive(Serialize, Debug, Clone, Default, PartialEq, Eq)] +pub struct ValueString(pub String); + +impl Deref for ValueString { + type Target = String; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl From for ValueString { + fn from(value: String) -> Self { + Self(value) + } +} + +impl From<&str> for ValueString { + fn from(value: &str) -> Self { + Self(value.to_string()) + } +} + +impl<'de> Deserialize<'de> for ValueString { + #[inline] + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + struct ValueVisitor; + + impl<'de> Visitor<'de> for ValueVisitor { + type Value = ValueString; + + fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { + formatter.write_str("any valid JSON value or KCL value expression") + } + + #[inline] + fn visit_bool(self, value: bool) -> Result + where + E: Error, + { + Ok(ValueString(serde_json::to_string(&value).map_err( + |_| Error::invalid_type(Unexpected::Bool(value), &self), + )?)) + } + + #[inline] + fn visit_i64(self, value: i64) -> Result + where + E: Error, + { + Ok(ValueString(serde_json::to_string(&value).map_err( + |_| Error::invalid_type(Unexpected::Signed(value), &self), + )?)) + } + + #[inline] + fn visit_u64(self, value: u64) -> Result + where + E: Error, + { + Ok(ValueString(serde_json::to_string(&value).map_err( + |_| Error::invalid_type(Unexpected::Unsigned(value), &self), + )?)) + } + + #[inline] + fn visit_f64(self, value: f64) -> Result + where + E: Error, + { + Ok(ValueString(serde_json::to_string(&value).map_err( + |_| Error::invalid_type(Unexpected::Float(value), &self), + )?)) + } + + #[inline] + fn visit_str(self, value: &str) -> Result + where + E: serde::de::Error, + { + self.visit_string(String::from(value)) + } + + #[inline] + fn visit_string(self, value: String) -> Result + where + E: Error, + { + Ok(ValueString(serde_json::to_string(&value).map_err( + |_| Error::invalid_type(Unexpected::Str(&value), &self), + )?)) + } + + #[inline] + fn visit_none(self) -> Result + where + E: Error, + { + Ok(ValueString("null".into())) + } + + #[inline] + fn visit_some(self, deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + D::Error: Error, + { + Deserialize::deserialize(deserializer) + } + + #[inline] + fn visit_unit(self) -> Result { + Ok(ValueString("null".into())) + } + + #[inline] + fn visit_seq(self, mut visitor: V) -> Result + where + V: SeqAccess<'de>, + V::Error: Error, + { + let mut vec: Vec = Vec::new(); + + while let Some(elem) = tri!(visitor.next_element()) { + vec.push(elem); + } + + Ok(ValueString(serde_json::to_string(&vec).map_err(|_| { + Error::invalid_type(Unexpected::Seq, &self) + })?)) + } + + fn visit_map(self, mut visitor: V) -> Result + where + V: MapAccess<'de>, + V::Error: Error, + { + match visitor.next_key_seed(MapStringKey)? { + Some(first_key) => { + let mut values: HashMap = HashMap::new(); + + values.insert(first_key, tri!(visitor.next_value())); + while let Some((key, value)) = tri!(visitor.next_entry()) { + values.insert(key, value); + } + + Ok(ValueString(serde_json::to_string(&values).map_err( + |_| Error::invalid_type(Unexpected::Map, &self), + )?)) + } + None => Ok(ValueString("{}".into())), + } + } + } + + deserializer.deserialize_any(ValueVisitor) + } +} + +#[derive(Serialize, Deserialize, Debug, Clone, Default)] pub struct TestSettingsFile { kcl_options: Option, } -pub fn load_file(filename: &str) -> SettingsFile { - let f = std::fs::File::open(filename).unwrap(); - let data: SettingsFile = serde_yaml::from_reader(f).unwrap(); - data +/// Load kcl settings file. +pub fn load_file(filename: &str) -> Result { + let f = std::fs::File::open(filename) + .with_context(|| format!("Failed to load '{}', no such file or directory", filename))?; + let data: SettingsFile = serde_yaml::from_reader(f) + .with_context(|| format!("Failed to load '{}', invalid setting file format", filename))?; + Ok(data) } macro_rules! set_if { @@ -81,138 +367,96 @@ macro_rules! set_if { }; } +/// Merge multiple settings into one settings. pub fn merge_settings(settings: &[SettingsFile]) -> SettingsFile { let mut result = SettingsFile::new(); for setting in settings { if let Some(kcl_cli_configs) = &setting.kcl_cli_configs { - let mut result_kcl_cli_configs = result.kcl_cli_configs.as_mut().unwrap(); - set_if!(result_kcl_cli_configs, files, kcl_cli_configs); - set_if!(result_kcl_cli_configs, file, kcl_cli_configs); - set_if!(result_kcl_cli_configs, output, kcl_cli_configs); - set_if!(result_kcl_cli_configs, overrides, kcl_cli_configs); - set_if!(result_kcl_cli_configs, path_selector, kcl_cli_configs); - set_if!(result_kcl_cli_configs, strict_range_check, kcl_cli_configs); - set_if!(result_kcl_cli_configs, disable_none, kcl_cli_configs); - set_if!(result_kcl_cli_configs, verbose, kcl_cli_configs); - set_if!(result_kcl_cli_configs, debug, kcl_cli_configs); - // debug: Option, + if result.kcl_cli_configs.is_none() { + result.kcl_cli_configs = Some(Config::default()); + } + if let Some(result_kcl_cli_configs) = result.kcl_cli_configs.as_mut() { + set_if!(result_kcl_cli_configs, files, kcl_cli_configs); + set_if!(result_kcl_cli_configs, file, kcl_cli_configs); + set_if!(result_kcl_cli_configs, output, kcl_cli_configs); + set_if!(result_kcl_cli_configs, overrides, kcl_cli_configs); + set_if!(result_kcl_cli_configs, path_selector, kcl_cli_configs); + set_if!(result_kcl_cli_configs, strict_range_check, kcl_cli_configs); + set_if!(result_kcl_cli_configs, disable_none, kcl_cli_configs); + set_if!(result_kcl_cli_configs, verbose, kcl_cli_configs); + set_if!(result_kcl_cli_configs, debug, kcl_cli_configs); + set_if!(result_kcl_cli_configs, sort_keys, kcl_cli_configs); + set_if!(result_kcl_cli_configs, show_hidden, kcl_cli_configs); + set_if!(result_kcl_cli_configs, fast_eval, kcl_cli_configs); + set_if!( + result_kcl_cli_configs, + include_schema_type_path, + kcl_cli_configs + ); + set_if!(result_kcl_cli_configs, package_maps, kcl_cli_configs); + } } if let Some(kcl_options) = &setting.kcl_options { - let result_kcl_options = result.kcl_options.as_mut().unwrap(); - for option in kcl_options { - result_kcl_options.push(option.clone()); + if result.kcl_options.is_none() { + result.kcl_options = Some(vec![]) + } + if let Some(result_kcl_options) = result.kcl_options.as_mut() { + for option in kcl_options { + result_kcl_options.push(option.clone()); + } } } } result } -pub fn decode_test_format_settings_file(filename: &str, workdir: &str) -> SettingsFile { - let f = std::fs::File::open(filename).unwrap(); - let data: TestSettingsFile = serde_yaml::from_reader(f).unwrap(); - let mut settings_file: SettingsFile = SettingsFile::new(); - match data.kcl_options { - Some(ref arg) => { - let args: Vec<&str> = arg.split(' ').collect(); - let mut i = 0; - while i < args.len() { - let arg = <&str>::clone(args.get(i).unwrap()); - match arg { - SETTINGS_FILE_PARA => { - i += 1; - let mut settings_vec: Vec = vec![settings_file]; - while i < args.len() && !args.get(i).unwrap().starts_with('-') { - let para = args - .get(i) - .unwrap_or_else(|| panic!("{}: {}", INVALID_KCL_OPTIONS_MSG, arg)); - let settings = load_file( - std::path::Path::new(workdir).join(para).to_str().unwrap(), - ); - settings_vec.push(settings); - } - settings_file = merge_settings(&settings_vec); - } - ARGUMENTS_PARA => { - i += 1; - let para = args - .get(i) - .unwrap_or_else(|| panic!("{}: {}", INVALID_KCL_OPTIONS_MSG, arg)); - let para = String::from(*para); - let paras: Vec<&str> = para.split('=').collect(); - if paras.len() != 2 { - panic!("{}: {}", INVALID_KCL_OPTIONS_MSG, arg); - } - (*settings_file.kcl_options.as_mut().unwrap()).push(KeyValuePair { - key: String::from(*paras.get(0).unwrap()), - value: String::from(*paras.get(1).unwrap()), - }); - } - DEBUG_PARA => { - (*settings_file.kcl_cli_configs.as_mut().unwrap()).debug = Some(true) - } - STRICT_RANGE_CHECK_PARA => { - (*settings_file.kcl_cli_configs.as_mut().unwrap()).strict_range_check = - Some(true) - } - DISABLE_NONE_PARA => { - (*settings_file.kcl_cli_configs.as_mut().unwrap()).disable_none = Some(true) - } - OVERRIDES_PARA => { - i += 1; - let para = args - .get(i) - .unwrap_or_else(|| panic!("{}: {}", INVALID_KCL_OPTIONS_MSG, arg)); - (*settings_file.kcl_cli_configs.as_mut().unwrap()) - .overrides - .as_mut() - .unwrap() - .push(para.to_string()); - } - PATH_SELECTOR_PARA => { - i += 1; - let para = args - .get(i) - .unwrap_or_else(|| panic!("{}: {}", INVALID_KCL_OPTIONS_MSG, arg)); - (*settings_file.kcl_cli_configs.as_mut().unwrap()) - .path_selector - .as_mut() - .unwrap() - .push(para.to_string()); - } - VERBOSE_PARA => { - let verbose = (*settings_file.kcl_cli_configs.as_mut().unwrap()) - .verbose - .as_mut() - .unwrap(); - *verbose += 1; - } - OUTPUT_PARA => { - i += 1; - let para = args - .get(i) - .unwrap_or_else(|| panic!("{}: {}", INVALID_KCL_OPTIONS_MSG, arg)); - (*settings_file.kcl_cli_configs.as_mut().unwrap()).output = - Some(para.to_string()); - } - _ => { - if arg.ends_with(".k") { - (*settings_file - .kcl_cli_configs - .as_mut() - .unwrap() - .files - .as_mut() - .unwrap()) - .push(String::from(arg)); - } - } - } - i += 1; +/// Build SettingsPathBuf from args. +pub fn build_settings_pathbuf( + files: &[&str], + setting_files: Option>, + setting_config: Option, +) -> Result { + let mut path = None; + let settings = if let Some(files) = setting_files { + let mut settings = vec![]; + for file in &files { + let s = load_file(file)?; + if !s.input().is_empty() { + path = Some( + PathBuf::from(file) + .parent() + .map(|p| p.to_path_buf()) + .ok_or(anyhow::anyhow!("The parent path of {file} is not found"))?, + ) } - settings_file + settings.push(s); + } + merge_settings(&settings) + // If exists default kcl.yaml, load it. + } else if std::fs::metadata(DEFAULT_SETTING_FILE).is_ok() { + path = Some( + PathBuf::from(DEFAULT_SETTING_FILE) + .parent() + .map(|p| p.to_path_buf()) + .ok_or(anyhow::anyhow!( + "The parent path of {DEFAULT_SETTING_FILE} is not found" + ))?, + ); + load_file(DEFAULT_SETTING_FILE)? + } else { + SettingsFile::default() + }; + let mut settings = if let Some(setting_config) = setting_config { + merge_settings(&[settings, setting_config]) + } else { + settings + }; + if let Some(config) = &mut settings.kcl_cli_configs { + if !files.is_empty() { + config.files = Some(files.iter().map(|f| f.to_string()).collect()); } - None => settings_file, } + Ok(SettingsPathBuf::new(path, settings)) } #[cfg(test)] @@ -223,7 +467,7 @@ mod settings_test { #[test] fn test_settings_load_file() { - let settings = load_file(SETTINGS_FILE); + let settings = load_file(SETTINGS_FILE).unwrap(); assert!(settings.kcl_cli_configs.is_some()); assert!(settings.kcl_options.is_some()); if let Some(kcl_cli_configs) = settings.kcl_cli_configs { @@ -239,19 +483,23 @@ mod settings_test { assert!(kcl_cli_configs.debug.is_some()); assert!(kcl_cli_configs.path_selector.is_none()); assert!(kcl_cli_configs.overrides.is_none()); + assert!(kcl_cli_configs.include_schema_type_path.is_none()); + assert!(kcl_cli_configs.show_hidden.is_none()); + assert!(kcl_cli_configs.fast_eval.is_none()); + assert_eq!(kcl_cli_configs.sort_keys, Some(true)); if let Some(config_files) = kcl_cli_configs.files { assert!(config_files == files); } } if let Some(kcl_options) = settings.kcl_options { - assert!(kcl_options.len() == 2); + assert!(kcl_options.len() == 6); } } #[test] - fn test_merge_settings() { - let settings1 = load_file(SETTINGS_FILE); - let settings2 = load_file(SETTINGS_FILE); + fn test_merge_settings() -> anyhow::Result<()> { + let settings1 = load_file(SETTINGS_FILE)?; + let settings2 = load_file(SETTINGS_FILE)?; let settings = merge_settings(&vec![settings1, settings2]); if let Some(kcl_cli_configs) = settings.kcl_cli_configs { let files = vec![ @@ -271,22 +519,8 @@ mod settings_test { } } if let Some(kcl_options) = settings.kcl_options { - assert!(kcl_options.len() == 4); + assert!(kcl_options.len() == 12); } - } - - #[test] - fn test_decode_test_format_settings_file() { - let settings = decode_test_format_settings_file("./src/testdata/test_settings.yaml", ""); - assert!(settings.kcl_cli_configs.as_ref().unwrap().debug.unwrap() == true); - assert!( - settings - .kcl_cli_configs - .as_ref() - .unwrap() - .strict_range_check - .unwrap() - == true - ); + Ok(()) } } diff --git a/internal/kclvm_py/internal/kclx/__init__.py b/kclvm/config/src/testdata/a/a.k similarity index 100% rename from internal/kclvm_py/internal/kclx/__init__.py rename to kclvm/config/src/testdata/a/a.k diff --git a/test/test_units/test_kclvm/test_tools/test_lint/test_checker/test_data/b.k b/kclvm/config/src/testdata/b/b.k similarity index 100% rename from test/test_units/test_kclvm/test_tools/test_lint/test_checker/test_data/b.k rename to kclvm/config/src/testdata/b/b.k diff --git a/kclvm/config/src/testdata/kcl.mod b/kclvm/config/src/testdata/kcl.mod index 3be7f7e6d..156f9a3ce 100644 --- a/kclvm/config/src/testdata/kcl.mod +++ b/kclvm/config/src/testdata/kcl.mod @@ -1,6 +1,13 @@ -[build] -enable_pkg_cache=true -cached_pkg_prefix="pkg.path" -[expected] -kclvm_version="v0.3.0" -kcl_plugin_version="v0.2.0" +[package] +name = "test_add_deps" +edition = "0.0.1" +version = "0.0.1" + +[dependencies] +pkg0 = { git = "test_url", tag = "test_tag" } +pkg1 = "oci_tag1" +pkg2 = { oci = "oci://ghcr.io/kcl-lang/helloworld", tag = "0.1.1" } +pkg3 = { path = "../pkg"} + +[profile] +entries = ["main.k"] diff --git a/kclvm/config/src/testdata/kcl.work b/kclvm/config/src/testdata/kcl.work new file mode 100644 index 000000000..6e0c727ea --- /dev/null +++ b/kclvm/config/src/testdata/kcl.work @@ -0,0 +1,3 @@ +workspace ./a +workspace ./b +workspace ./c/d \ No newline at end of file diff --git a/kclvm/config/src/testdata/settings.yaml b/kclvm/config/src/testdata/settings.yaml index 8b7a8a399..06c8d62df 100644 --- a/kclvm/config/src/testdata/settings.yaml +++ b/kclvm/config/src/testdata/settings.yaml @@ -7,8 +7,27 @@ kcl_cli_configs: disable_none: false strict_range_check: false debug: false + sort_keys: true kcl_options: - key: app-name value: kclvm - key: image value: kclvm:v0.0.1 + - key: env-type + value: TEST + - key: deploy-topology + value: + - cluster: my-cluster + id: '000123' + idc: my-idc + is_dev: true + replicas: 2 + value: null + workspace: my-workspace + zone: my-zone + - key: labels + value: + app: app + env: env + - key: ports + value: [80, 8080] diff --git a/kclvm/config/src/testdata/test_cache/kcl.mod b/kclvm/config/src/testdata/test_cache/kcl.mod new file mode 100644 index 000000000..0cb0782b7 --- /dev/null +++ b/kclvm/config/src/testdata/test_cache/kcl.mod @@ -0,0 +1,5 @@ +[package] +name = "test_cache" +edition = "0.0.1" +version = "0.0.1" + diff --git a/kclvm/config/src/testdata/test_cache/main.k b/kclvm/config/src/testdata/test_cache/main.k new file mode 100644 index 000000000..fa7048e63 --- /dev/null +++ b/kclvm/config/src/testdata/test_cache/main.k @@ -0,0 +1 @@ +The_first_kcl_program = 'Hello World!' \ No newline at end of file diff --git a/kclvm/config/src/testdata/test_vendor/kcl.mod b/kclvm/config/src/testdata/test_vendor/kcl.mod new file mode 100644 index 000000000..395df1caa --- /dev/null +++ b/kclvm/config/src/testdata/test_vendor/kcl.mod @@ -0,0 +1,5 @@ +[package] +name = "test_vendor" +edition = "0.0.1" +version = "0.0.1" + diff --git a/kclvm/config/src/testdata/test_vendor/main.k b/kclvm/config/src/testdata/test_vendor/main.k new file mode 100644 index 000000000..fa7048e63 --- /dev/null +++ b/kclvm/config/src/testdata/test_vendor/main.k @@ -0,0 +1 @@ +The_first_kcl_program = 'Hello World!' \ No newline at end of file diff --git a/kclvm/config/src/tests.rs b/kclvm/config/src/tests.rs new file mode 100644 index 000000000..cb5ef38fe --- /dev/null +++ b/kclvm/config/src/tests.rs @@ -0,0 +1,78 @@ +use kclvm_utils::path::PathPrefix; +use kclvm_version as version; +use std::{ + collections::HashMap, + env, + fs::{self, File}, + path::{Path, PathBuf}, +}; + +use crate::{ + cache::{load_pkg_cache, save_pkg_cache, CacheOption}, + modfile::{get_vendor_home, KCL_PKG_PATH}, +}; + +#[test] +fn test_vendor_home() { + env::set_var(KCL_PKG_PATH, "test_vendor_home"); + assert_eq!(get_vendor_home(), "test_vendor_home"); + env::remove_var(KCL_PKG_PATH); + + #[cfg(target_os = "windows")] + let root_dir = env::var("USERPROFILE").unwrap(); + #[cfg(not(target_os = "windows"))] + let root_dir = env::var("HOME").unwrap(); + + let kpm_home = PathBuf::from(root_dir) + .join(".kcl") + .join("kpm") + .canonicalize() + .unwrap(); + assert_eq!( + get_vendor_home(), + kpm_home.display().to_string().adjust_canonicalization() + ) +} + +#[test] +fn test_pkg_cache() { + let root = PathBuf::from("./src/testdata/test_cache/") + .canonicalize() + .unwrap() + .display() + .to_string(); + let mut external_pkgs = HashMap::new(); + external_pkgs.insert( + "test_vendor".to_string(), + "./src/testdata/test_vendor".to_string(), + ); + + let lock_path = Path::new(&root) + .join(".kclvm/cache") + .join(format!("{}-{}", version::VERSION, version::CHECK_SUM)) + .join("test_target"); + + fs::create_dir_all(lock_path.clone()).unwrap(); + File::create(lock_path.join("test_vendor.lock")).unwrap(); + + save_pkg_cache( + &root, + "test_target", + "test_vendor", + "test_data", + CacheOption::default(), + &external_pkgs, + ) + .unwrap(); + + assert_eq!( + load_pkg_cache( + &root, + "test_target", + "test_vendor", + CacheOption::default(), + &external_pkgs, + ), + Some("test_data".to_string()) + ) +} diff --git a/kclvm/config/src/vfs.rs b/kclvm/config/src/vfs.rs index aec95fc82..a0fbe3751 100644 --- a/kclvm/config/src/vfs.rs +++ b/kclvm/config/src/vfs.rs @@ -1,7 +1,9 @@ -extern crate pathdiff; - use std::path::Path; +use kclvm_utils::path::PathPrefix; + +extern crate pathdiff; + pub fn is_abs_pkgpath(pkgpath: &str) -> bool { if pkgpath.is_empty() { return false; @@ -29,18 +31,20 @@ pub fn is_rel_pkgpath(pkgpath: &str) -> bool { pub fn fix_import_path(root: &str, filepath: &str, import_path: &str) -> String { // relpath: import .sub - // FixImportPath(root, "path/to/app/file.k", ".sub") => path.to.app.sub - // FixImportPath(root, "path/to/app/file.k", "..sub") => path.to.sub - // FixImportPath(root, "path/to/app/file.k", "...sub") => path.sub - // FixImportPath(root, "path/to/app/file.k", "....sub") => sub - // FixImportPath(root, "path/to/app/file.k", ".....sub") => "" + // fix_import_path(root, "path/to/app/file.k", ".sub") => path.to.app.sub + // fix_import_path(root, "path/to/app/file.k", "..sub") => path.to.sub + // fix_import_path(root, "path/to/app/file.k", "...sub") => path.sub + // fix_import_path(root, "path/to/app/file.k", "....sub") => sub + // fix_import_path(root, "path/to/app/file.k", ".....sub") => "" // // abspath: import path.to.sub - // FixImportPath(root, "path/to/app/file.k", "path.to.sub") => path.to.sub + // fix_import_path(root, "path/to/app/file.k", "path.to.sub") => path.to.sub + + // Use canonicalize to convert the path to absolute path + // avoid the symbolic link issue caused the file not found - debug_assert!(!root.is_empty()); - debug_assert!(!filepath.is_empty()); - debug_assert!(!import_path.is_empty()); + let filepath = Path::new(filepath).adjust_canonicalization(); + let root = Path::new(root).adjust_canonicalization(); if !import_path.starts_with('.') { return import_path.to_string(); @@ -57,7 +61,7 @@ pub fn fix_import_path(root: &str, filepath: &str, import_path: &str) -> String dirpath.to_str().unwrap().to_string() }; - let pkgpath = pkgpath.replace('/', ".").replace('\\', "."); + let pkgpath = pkgpath.replace(['/', '\\'], "."); pkgpath.trim_end_matches('.').to_string() }; @@ -100,7 +104,10 @@ pub fn fix_import_path(root: &str, filepath: &str, import_path: &str) -> String #[test] fn test_fix_import_path() { + #[cfg(not(target_os = "windows"))] let root = "/home/konfig"; + #[cfg(target_os = "windows")] + let root = r#"c:\home\konfig"#; let s = fix_import_path(root, "path/to/app/file.k", ".sub"); assert_eq!(s, "path.to.app.sub"); diff --git a/kclvm/config/src/workfile.rs b/kclvm/config/src/workfile.rs new file mode 100644 index 000000000..fb09d7a16 --- /dev/null +++ b/kclvm/config/src/workfile.rs @@ -0,0 +1,190 @@ +//! The config for IDE/LSP workspace config file `kcl.work' + +use kclvm_utils::path::PathPrefix; +use serde::{Deserialize, Serialize}; +use std::{ + collections::HashMap, + io::{BufRead, BufReader}, + path::{Path, PathBuf}, +}; + +use crate::modfile::KCL_WORK_FILE; +use anyhow::Result; + +#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq, Eq)] +pub struct WorkFile { + pub workspaces: Vec, + pub failed: HashMap, +} + +#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq, Eq)] +pub struct WorkSpace { + pub content: String, + pub path: String, + pub abs_path: String, +} + +/// Load kcl work file from path +pub fn load_work_file + std::fmt::Debug>(path: P) -> Result { + let file = if path.as_ref().is_dir() { + let file_path = path.as_ref().join(KCL_WORK_FILE); + std::fs::File::open(file_path)? + } else if path.as_ref().is_file() { + std::fs::File::open(&path)? + } else { + return Err(anyhow::anyhow!("kcl.work not found for {:?}", path)); + }; + + let reader = BufReader::new(file); + let mut workfile = WorkFile::default(); + for line in reader.lines() { + if let Ok(line) = line { + let mut directive = line.split_whitespace(); + if let Some(key) = directive.next() { + match key { + "workspace" => { + if let Some(path) = directive.next() { + workfile.workspaces.push(WorkSpace { + content: line.clone(), + path: path.to_string(), + abs_path: "".to_string(), + }); + } + } + _ => { + workfile.failed.insert(line, "Unknown keyword".to_string()); + } + } + } + } + } + Ok(workfile) +} + +impl WorkFile { + pub fn canonicalize(&mut self, root: PathBuf) { + let mut new_workspaces = vec![]; + for workspace in self.workspaces.iter_mut() { + let path = Path::new(&workspace.path); + if !path.is_absolute() { + let filepath = root.join(Path::new(&workspace.path)); + match filepath.canonicalize() { + Ok(path) => new_workspaces.push(WorkSpace { + content: workspace.content.clone(), + path: workspace.path.clone(), + abs_path: path.adjust_canonicalization(), + }), + Err(e) => { + self.failed.insert( + workspace.content.clone(), + format!("path canonicalize failed: {:?}", e), + ); + } + } + } else { + new_workspaces.push(WorkSpace { + content: workspace.content.clone(), + path: workspace.path.clone(), + abs_path: workspace.path.clone(), + }) + }; + } + self.workspaces = new_workspaces; + } +} + +#[cfg(test)] +mod workfile_test { + use std::path::PathBuf; + + use crate::workfile::WorkSpace; + + use super::load_work_file; + #[test] + fn parse_workfile() { + let path = "./src/testdata/"; + let workfile = load_work_file(path).unwrap(); + assert_eq!( + workfile.workspaces, + vec![ + WorkSpace { + content: "workspace ./a".to_string(), + path: "./a".to_string(), + abs_path: "".to_string() + }, + WorkSpace { + content: "workspace ./b".to_string(), + path: "./b".to_string(), + abs_path: "".to_string() + }, + WorkSpace { + content: "workspace ./c/d".to_string(), + path: "./c/d".to_string(), + abs_path: "".to_string() + }, + ] + ); + } + + #[test] + fn parse_workfile1() { + let path = "./src/testdata/kcl.work"; + let workfile = load_work_file(path).unwrap(); + assert_eq!( + workfile.workspaces, + vec![ + WorkSpace { + content: "workspace ./a".to_string(), + path: "./a".to_string(), + abs_path: "".to_string() + }, + WorkSpace { + content: "workspace ./b".to_string(), + path: "./b".to_string(), + abs_path: "".to_string() + }, + WorkSpace { + content: "workspace ./c/d".to_string(), + path: "./c/d".to_string(), + abs_path: "".to_string() + }, + ] + ); + } + + #[test] + fn canonicalize_workfile() { + let path = "./src/testdata/kcl.work"; + let mut workfile = load_work_file(path).unwrap(); + let path = PathBuf::from(env!("CARGO_MANIFEST_DIR")) + .join("src") + .join("testdata"); + let mut a = path.clone(); + a.push("a"); + + let mut b = path.clone(); + b.push("b"); + + let mut cd = path.clone(); + cd.push("c"); + cd.push("d"); + + workfile.canonicalize(path); + assert_eq!( + workfile.workspaces, + vec![ + WorkSpace { + content: "workspace ./a".to_string(), + path: "./a".to_string(), + abs_path: a.to_str().unwrap().to_string(), + }, + WorkSpace { + content: "workspace ./b".to_string(), + path: "./b".to_string(), + abs_path: b.to_str().unwrap().to_string(), + }, + ] + ); + assert!(!workfile.failed.is_empty()); + } +} diff --git a/kclvm/docs/m1-mac-setup.md b/kclvm/docs/m1-mac-setup.md deleted file mode 100644 index 93595205e..000000000 --- a/kclvm/docs/m1-mac-setup.md +++ /dev/null @@ -1,75 +0,0 @@ -## Env - -+ OS: MacOS Manterey 12.1 -+ CPU: Apple M1 pro, 10 cores -+ Mem: 16GB -+ Rust: cargo 1.59.0 (49d8809dc 2022-02-10) - -## Prerequirements - -1. Make sure you have arm64e-version homebrew installed @`/opt/homebrew`, otherwise install it ➡ - ``` - /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" - export PATH=/opt/homebrew/bin:$PATH - ``` -2. Install openssl@1.1 ➡ brew install openssl@1.1 -3. Check out openssl installed @`/opt/homebrew/opt/openssl@1.1/lib/libssl.1.1.dylib` - -## Build LLVM from Source - -1. Go to the folder where you want to build the LLVM source -2. Download LLVM 12.0.0 source from [http://releases.llvm.org/download.html](http://releases.llvm.org/download.html) and unpack source .tar.xz with tar -xJf [archive] -3. Create a directory where you want to build LLVM files ➡ mkdir build-llvm-12.0.0 -4. Move into the build folder ➡ cd build-llvm-12.0.0; that's where you create `build.sh`. - -``` -#!usr/bin/env sh - -LLVMSRC="" -. "$HOME/.cargo/env" -LLVMTARGET="" - - -cmake \ - -G "Ninja" \ - -DCMAKE_INSTALL_PREFIX="$LLVMTARGET" \ - -DCMAKE_OSX_ARCHITECTURES='arm64' \ - -DCMAKE_C_COMPILER=`which clang` \ - -DCMAKE_CXX_COMPILER=`which clang++` \ - -DCMAKE_BUILD_TYPE="Release" \ - -DLLVM_TARGETS_TO_BUILD="AArch64" \ - -DLLVM_HOST_TRIPLE='aarch64-apple-darwin' \ - -DLLVM_DEFAULT_TARGET_TRIPLE='aarch64-apple-darwin' \ - -DLLVM_ENABLE_WERROR=FALSE \ - "$LLVMSRC" - -cmake --build . -cmake --build . --target install -``` - -5. You may not have ninja installed, so if you have brew installed, you need to install it ninja with ➡ brew install `ninja`. -6. Run the script ➡ sh build.sh -7. Took about 10-15mins. Check out @``. - -## Build KCLVM - -1. Build KCLVM according to `kclvm/README.md`. -2. Took about 5mins. -3. Done! - -## Notes - -1. If you've brew-updating and github brew-submodule-download issue, you'd better use a mirror to speed up. - ``` - cd "$(brew --repo)" - git remote set-url origin https://mirrors.aliyun.com/homebrew/brew.git - - cd "$(brew --repo)/Library/Taps/homebrew/homebrew-core" - git remote set-url origin https://mirrors.aliyun.com/homebrew/homebrew-core.git - - cd "$(brew --repo)/Library/Taps/homebrew/homebrew-cask" -git remote set-url origin https://mirrors.aliyun.com/homebrew/homebrew-cask.git - - echo 'export HOMEBREW_BOTTLE_DOMAIN=https://mirrors.aliyun.com/homebrew/homebrew-bottles' >> ~/.zshrc -source ~/.zshrc - ``` \ No newline at end of file diff --git a/kclvm/driver/Cargo.toml b/kclvm/driver/Cargo.toml new file mode 100644 index 000000000..66497d578 --- /dev/null +++ b/kclvm/driver/Cargo.toml @@ -0,0 +1,28 @@ +[package] +name = "kclvm-driver" +version = "0.11.0" +edition = "2021" + +# # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +serde_json = "1.0.86" + +kclvm-config ={ path = "../config"} +kclvm-runtime ={ path = "../runtime"} +kclvm-utils ={ path = "../utils"} +kclvm-parser ={ path = "../parser"} +kclvm-ast ={ path = "../ast"} +walkdir = "2" +serde = { version = "1.0", features = ["derive"] } +anyhow = { version = "1.0.70", features = ["backtrace"] } + +flate2 = "1.0.30" +tar = "0.4.40" +indexmap = "2.2.6" +once_cell = "1.19.0" +parking_lot = "0.12.3" + +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +oci-distribution = { default-features = false, version = "0.11.0", features = ["rustls-tls"] } +tokio = { version = "1.37.0", features = ["full"] } diff --git a/kclvm/driver/src/arguments.rs b/kclvm/driver/src/arguments.rs new file mode 100644 index 000000000..9655ba414 --- /dev/null +++ b/kclvm/driver/src/arguments.rs @@ -0,0 +1,40 @@ +use anyhow::Result; +use kclvm_ast::ast; +use kclvm_config::settings::KeyValuePair; +use kclvm_parser::parse_expr; + +/// Parse key value pair string k=v to [KeyValuePair], note the value will be convert a json string. +pub fn parse_key_value_pair(spec: &str) -> Result { + let split_values = spec.split('=').collect::>(); + if split_values.len() == 2 + && !split_values[0].trim().is_empty() + && !split_values[1].trim().is_empty() + { + Ok(KeyValuePair { + key: split_values[0].to_string(), + value: val_to_json(split_values[1]).into(), + }) + } else { + Err(anyhow::anyhow!("Invalid value for top level arguments")) + } +} + +/// Convert the value string to the json string. +fn val_to_json(value: &str) -> String { + // If it is a json string, returns it. + if serde_json::from_str::(value).is_ok() { + return value.to_string(); + } + // Is a KCL value, eval KCL value to a json string. + let expr = parse_expr(value); + match expr { + Some(expr) => match expr.node { + ast::Expr::NameConstantLit(lit) => lit.value.json_value().to_string(), + ast::Expr::NumberLit(_) | ast::Expr::StringLit(_) => value.to_string(), + // Not a normal literal, regard it as a string value. + _ => format!("{:?}", value), + }, + // Invalid value, regard it as a string value. + None => format!("{:?}", value), + } +} diff --git a/kclvm/driver/src/client/fs.rs b/kclvm/driver/src/client/fs.rs new file mode 100644 index 000000000..3be013cb7 --- /dev/null +++ b/kclvm/driver/src/client/fs.rs @@ -0,0 +1,8 @@ +use std::path::Path; + +#[inline] +pub(crate) fn directory_is_not_empty>(path: P) -> bool { + std::fs::read_dir(path) + .map(|mut entries| entries.next().is_some()) + .is_ok() +} diff --git a/kclvm/driver/src/client/git.rs b/kclvm/driver/src/client/git.rs new file mode 100644 index 000000000..feb078d2b --- /dev/null +++ b/kclvm/driver/src/client/git.rs @@ -0,0 +1,65 @@ +use anyhow::bail; +use std::path::{Path, PathBuf}; +use std::process::Command; + +use crate::client::fs::directory_is_not_empty; +use anyhow::Result; +use kclvm_utils::path::PathPrefix; + +pub(crate) fn cmd_clone_git_repo_to( + url: &str, + branch: &Option, + tag: &Option, + commit: &Option, + path: &Path, +) -> Result { + if directory_is_not_empty(path) { + return Ok(path.to_path_buf()); + } + let path = path.adjust_canonicalization(); + let mut git_clone_cmd = Command::new("git"); + git_clone_cmd.args(["clone", url]); + if let Some(branch_name) = branch { + git_clone_cmd.args(["--branch", branch_name]); + } + git_clone_cmd.arg(&path); + + let output = git_clone_cmd.output()?; + if !output.status.success() { + bail!( + "Failed to clone Git repository {}: stdout: {} stderr: {}", + url, + String::from_utf8(output.stdout).unwrap(), + String::from_utf8(output.stderr).unwrap() + ); + } + if let Some(tag_name) = tag { + let output = Command::new("git") + .args(["checkout", tag_name]) + .current_dir(&path) + .output()?; + if !output.status.success() { + bail!( + "Failed to checkout Git tag {}: stdout: {} stderr: {}", + tag_name, + String::from_utf8(output.stdout).unwrap(), + String::from_utf8(output.stderr).unwrap() + ); + } + } else if let Some(commit_hash) = commit { + let output = Command::new("git") + .args(["checkout", commit_hash]) + .current_dir(&path) + .output()?; + if !output.status.success() { + bail!( + "Failed to checkout Git commit {}: stdout: {} stderr: {}", + commit_hash, + String::from_utf8(output.stdout).unwrap(), + String::from_utf8(output.stderr).unwrap() + ) + } + } + + Ok(path.into()) +} diff --git a/kclvm/driver/src/client/mod.rs b/kclvm/driver/src/client/mod.rs new file mode 100644 index 000000000..037c1e504 --- /dev/null +++ b/kclvm/driver/src/client/mod.rs @@ -0,0 +1,311 @@ +mod fs; +mod git; +mod oci; + +use anyhow::Result; +use git::cmd_clone_git_repo_to; +use indexmap::IndexSet; +use kclvm_config::modfile::{ + get_vendor_home, load_mod_file, load_mod_lock_file, LockDependency, ModLockFile, +}; +use kclvm_config::modfile::{Dependency, GitSource, ModFile, OciSource}; +use kclvm_utils::fslock::open_lock_file; +use oci_distribution::secrets::RegistryAuth; +use oci_distribution::{Client, Reference, RegistryOperation}; +use std::path::Path; +use std::path::PathBuf; +use std::sync::Arc; + +use crate::toolchain::{Metadata, Package}; + +pub const DEFAULT_OCI_REGISTRY: &str = "ghcr.io/kcl-lang"; +pub const KCL_SRC_URL_ENV_VAR: &str = "KCL_SRC_URL"; +pub const KCL_SRC_URL_USERNAME_ENV_VAR: &str = "KCL_SRC_USERNAME"; +pub const KCL_SRC_URL_PASSWORD_ENV_VAR: &str = "KCL_SRC_PASSWORD"; + +#[derive(Default)] +pub struct ModClient { + /// The mod file config of current module. + mod_file: ModFile, + /// The mod lock file config of current module. + mod_lock_file: Option, + /// The package search work directory. + work_dir: PathBuf, + /// Optional vendor home. + vendor: Option, + /// A lazy OCI client. + oci_client: Arc, +} + +unsafe impl Send for ModClient {} +unsafe impl Sync for ModClient {} + +impl ModClient { + /// New a default mod client to fetch metadata ot update dependencies. + #[inline] + pub fn new>(work_dir: P) -> Result { + Self::new_with_oci_client(work_dir, Arc::new(Client::default())) + } + + /// New a default mod client to fetch metadata ot update dependencies. + pub fn new_with_oci_client>( + work_dir: P, + oci_client: Arc, + ) -> Result { + Ok(Self { + work_dir: work_dir.as_ref().to_path_buf(), + mod_file: load_mod_file(&work_dir)?, + mod_lock_file: load_mod_lock_file(&work_dir).ok(), + vendor: None, + oci_client, + }) + } + + /// Auth the oci client + pub fn auth(&self) -> Result<()> { + if let (Ok(username), Ok(password)) = ( + std::env::var(KCL_SRC_URL_USERNAME_ENV_VAR), + std::env::var(KCL_SRC_URL_PASSWORD_ENV_VAR), + ) { + let rt = tokio::runtime::Runtime::new()?; + let image: Reference = self.default_oci_registry().parse()?; + let auth = RegistryAuth::Basic(username, password); + let _ = rt.block_on(async { + self.oci_client + .auth(&image, &auth, RegistryOperation::Pull) + .await + .ok()? + }); + } + Ok(()) + } + + #[inline] + pub fn default_oci_registry(&self) -> String { + std::env::var(KCL_SRC_URL_ENV_VAR).unwrap_or(DEFAULT_OCI_REGISTRY.to_string()) + } + + /// Change the work directory. + pub fn change_work_dir>(&mut self, work_dir: P) -> Result<()> { + let work_dir = work_dir.as_ref().to_path_buf(); + self.mod_file = load_mod_file(&work_dir)?; + if let Ok(mod_lock_file) = load_mod_lock_file(&work_dir) { + self.mod_lock_file = Some(mod_lock_file); + } + self.work_dir = work_dir; + Ok(()) + } + + /// Set the vendor path. + pub fn set_vendor>(&mut self, vendor: P) -> &mut Self { + let vendor = vendor.as_ref().to_path_buf(); + self.vendor = Some(vendor); + self + } + + /// Lock the kcl.mod file and resolve package deps to metadata, note this function will download + /// deps from remote sources. If the dependency is downloaded to the local path, calculate the + /// package metadata. + pub fn lock_and_resolve_all_deps>( + &mut self, + lock_file: P, + update: bool, + ) -> Result { + let mut lock_guard = + open_lock_file(lock_file.as_ref().to_string_lossy().to_string().as_str())?; + lock_guard.lock()?; + self.resolve_all_deps(update) + } + + /// Resolve package deps to metadata, note this function will download deps from remote sources. + /// If the dependency is downloaded to the local path, calculate the package metadata. + pub fn resolve_all_deps(&mut self, update: bool) -> Result { + let mut metadata = Metadata::default(); + match &self.mod_file.dependencies { + Some(dependencies) if !dependencies.is_empty() => { + let vendor = self.get_vendor_path()?; + let mut paths: IndexSet = IndexSet::default(); + for (name, dep) in dependencies { + let path = if update { + let path = self.download_dep_to_vendor(name, dep, &vendor)?; + paths.insert(path.clone()); + path + } else { + Default::default() + }; + metadata.packages.insert( + name.replace('-', "_"), + Package { + name: name.to_string(), + manifest_path: path, + }, + ); + } + for path in paths { + if let Ok(mut client) = + ModClient::new_with_oci_client(path, self.oci_client.clone()) + { + let new_metadata = client.resolve_all_deps(update)?; + for (name, package) in new_metadata.packages { + metadata.packages.entry(name).or_insert(package); + } + } + } + Ok(metadata) + } + _ => Ok(metadata), + } + } + + /// Download a dependency to the local path. + pub fn download_dep_to_vendor( + &self, + name: &str, + dep: &Dependency, + vendor: &Path, + ) -> Result { + let path = self.get_local_path_from_dep(name, dep); + let path = Path::new(vendor).join(path); + match dep { + Dependency::Version(version) => self.download_oci_source_to( + name, + &OciSource { + oci: oci::oci_reg_repo_join(&self.default_oci_registry(), name), + tag: Some(version.to_string()), + }, + &path, + ), + Dependency::Git(git_source) => self.download_git_source_to(git_source, &path), + Dependency::Oci(oci_source) => self.download_oci_source_to(name, oci_source, &path), + Dependency::Local(_) => { + // Nothing to do for the local source. + Ok(path) + } + } + } + + /// Get the vendor path. + pub fn get_vendor_path(&self) -> Result { + Ok(match &self.vendor { + Some(vendor) => { + std::fs::create_dir_all(vendor)?; + vendor.to_path_buf() + } + None => PathBuf::from(get_vendor_home()), + }) + } + + pub fn download_git_source_to(&self, git_source: &GitSource, path: &Path) -> Result { + let path = cmd_clone_git_repo_to( + &git_source.git, + &git_source.branch, + &git_source.tag, + &git_source.commit, + path, + )?; + Ok(path) + } + + pub fn download_oci_source_to( + &self, + name: &str, + oci_source: &OciSource, + path: &Path, + ) -> Result { + let rt = tokio::runtime::Runtime::new()?; + let path = rt.block_on(async { + oci::pull_oci_and_extract_layer( + &self.oci_client, + name, + &oci_source.oci, + &oci_source.tag, + path, + ) + .await + })?; + Ok(path) + } + + /// Get the dependency store path + pub fn get_local_path_from_dep(&self, name: &str, dep: &Dependency) -> String { + match dep { + Dependency::Version(version) => { + format!("{}_{}", name, version) + } + Dependency::Git(git_source) => { + if let Some(tag) = &git_source.tag { + format!("{}_{}", name, tag) + } else if let Some(commit) = &git_source.commit { + format!("{}_{}", name, commit) + } else if let Some(branch) = &git_source.branch { + format!("{}_{}", name, branch) + } else { + format!("{name}_latest") + } + } + // Just returns the folder. + Dependency::Oci(_) => "".to_string(), + Dependency::Local(local_source) => { + let local_path = PathBuf::from(&local_source.path); + if local_path.is_absolute() { + local_source.path.clone() + } else { + self.work_dir + .join(&local_source.path) + .to_string_lossy() + .to_string() + } + } + } + } + + /// Get the lock dependency store path + pub fn get_local_path_from_lock_dep(&self, lock_dep: &LockDependency) -> Option { + if lock_dep.reg.is_some() { + lock_dep.full_name.clone() + } else if let Some(git_url) = &lock_dep.url { + Some(self.get_local_path_from_dep( + &lock_dep.gen_filename(), + &Dependency::Git(GitSource { + git: git_url.to_string(), + branch: lock_dep.branch.clone(), + commit: lock_dep.commit.clone(), + tag: lock_dep.git_tag.clone(), + version: lock_dep.version.clone(), + }), + )) + } else { + match &self.mod_file.dependencies { + Some(dependencies) => dependencies + .get(&lock_dep.name) + .as_ref() + .map(|dep| self.get_local_path_from_dep(&lock_dep.name, dep)), + None => None, + } + } + } + + /// Get the package metadata from the kcl.mod.lock file. + pub fn get_metadata_from_mod_lock_file(&self) -> Option { + if let Some(mod_lock_file) = &self.mod_lock_file { + if let Some(dependencies) = &mod_lock_file.dependencies { + let vendor = self.get_vendor_path().ok()?; + let mut metadata = Metadata::default(); + for (name, dep) in dependencies { + metadata.packages.insert( + name.replace('-', "_").to_string(), + Package { + name: name.to_string(), + manifest_path: match self.get_local_path_from_lock_dep(dep) { + Some(path) => vendor.join(path), + None => "".into(), + }, + }, + ); + } + return Some(metadata); + } + } + None + } +} diff --git a/kclvm/driver/src/client/oci.rs b/kclvm/driver/src/client/oci.rs new file mode 100644 index 000000000..54582a871 --- /dev/null +++ b/kclvm/driver/src/client/oci.rs @@ -0,0 +1,85 @@ +use crate::client::fs::directory_is_not_empty; +use anyhow::Result; +use oci_distribution::manifest::IMAGE_LAYER_MEDIA_TYPE; +use oci_distribution::secrets::RegistryAuth; +use oci_distribution::{Client, Reference}; +use std::path::{Path, PathBuf}; + +const OCI_SCHEME_PREFIX: &str = "oci://"; + +#[inline] +pub(crate) fn strip_oci_scheme_prefix(image: &str) -> &str { + match image.strip_prefix(OCI_SCHEME_PREFIX) { + Some(image_without_oci_prefix) => image_without_oci_prefix, + None => image, + } +} + +pub(crate) fn oci_reg_repo_join(reg: &str, repo: &str) -> String { + let reg = match reg.strip_suffix('/') { + Some(reg) => reg, + None => reg, + }; + let repo = match repo.strip_prefix('/') { + Some(repo) => repo, + None => repo, + }; + format!("{reg}/{repo}") +} + +pub(crate) async fn pull_oci_and_extract_layer( + client: &Client, + name: &str, + image: &str, + tag: &Option, + save_dir: &Path, +) -> Result { + let image = strip_oci_scheme_prefix(image); + let auth = RegistryAuth::Anonymous; + let (img_data, path) = match &tag { + Some(tag) => { + let path = save_dir.join(format!("{name}_{tag}")); + if directory_is_not_empty(&path) { + return Ok(path); + } + let img_ref = Reference::try_from(format!("{image}:{tag}"))?; + ( + client + .pull(&img_ref, &auth, vec![IMAGE_LAYER_MEDIA_TYPE]) + .await?, + path, + ) + } + None => { + let img_ref = Reference::try_from(image)?; + let resp = client.list_tags(&img_ref, &auth, None, None).await?; + let tags = resp.tags; + let mut semver_tags: Vec = + tags.into_iter().filter(|tag| tag != "latest").collect(); + semver_tags.sort_by(|a, b| b.cmp(a)); + let (tag, img_tag_ref) = if let Some(newest_tag) = semver_tags.first() { + ( + newest_tag.as_str(), + Reference::try_from(format!("{image}:{newest_tag}"))?, + ) + } else { + ("latest", img_ref) + }; + let path = save_dir.join(format!("{name}_{tag}")); + if directory_is_not_empty(&path) { + return Ok(path); + } + ( + client + .pull(&img_tag_ref, &auth, vec![IMAGE_LAYER_MEDIA_TYPE]) + .await?, + path, + ) + } + }; + for layer in &img_data.layers { + let buf = layer.data.as_slice(); + tar::Archive::new(buf).unpack(&path)?; + } + Ok(path) +} diff --git a/kclvm/driver/src/lib.rs b/kclvm/driver/src/lib.rs new file mode 100644 index 000000000..a455e4e3e --- /dev/null +++ b/kclvm/driver/src/lib.rs @@ -0,0 +1,463 @@ +pub mod arguments; +#[cfg(not(target_arch = "wasm32"))] +pub mod client; +pub mod toolchain; + +#[cfg(test)] +mod tests; + +use anyhow::Result; +use kclvm_config::{ + modfile::{get_pkg_root, load_mod_file, KCL_FILE_EXTENSION, KCL_MOD_FILE, KCL_WORK_FILE}, + settings::{build_settings_pathbuf, DEFAULT_SETTING_FILE}, + workfile::load_work_file, +}; +use kclvm_parser::{get_kcl_files, LoadProgramOptions}; +use kclvm_utils::path::PathPrefix; +use std::iter; +use std::{collections::HashMap, env}; +use std::{ + collections::HashSet, + fs::read_dir, + io::{self, ErrorKind}, + path::{Path, PathBuf}, +}; +use toolchain::{fill_pkg_maps_for_k_file, Metadata, Toolchain}; +use walkdir::WalkDir; + +/// Get compile workspace(files and options) from a single file input. +/// 1. Lookup entry files in kcl.yaml +/// 2. Lookup entry files in kcl.mod +/// 3. If not found, consider the path or folder where the file is +/// located as the compilation entry point +pub fn lookup_compile_workspace( + tool: &dyn Toolchain, + file: &str, + load_pkg: bool, +) -> CompileUnitOptions { + fn default_res(tool: &dyn Toolchain, file: &str, load_pkg: bool) -> CompileUnitOptions { + let mut default_res: CompileUnitOptions = (vec![], None, None); + let mut load_opt = kclvm_parser::LoadProgramOptions::default(); + let metadata = fill_pkg_maps_for_k_file(tool, file.into(), &mut load_opt).unwrap_or(None); + let path = Path::new(file); + if let Some(ext) = path.extension() { + if load_pkg { + if let Some(parent) = path.parent() { + if let Ok(files) = get_kcl_files(parent, false) { + default_res = (files, Some(load_opt), metadata); + } + } + } else { + if ext == KCL_FILE_EXTENSION && path.is_file() { + default_res = (vec![file.to_string()], Some(load_opt), metadata); + } + } + } + default_res + } + + match lookup_compile_unit_path(file) { + Ok(CompileUnitPath::SettingFile(dir)) => { + let settings_files = lookup_setting_files(&dir); + let files = if settings_files.is_empty() { + default_res(tool, file, load_pkg) + .0 + .iter() + .map(|s| s.clone()) + .collect() + } else { + vec![] + }; + let files: Vec<&str> = files.iter().map(|s| s.as_str()).collect(); + let settings_files: Vec<&str> = + settings_files.iter().map(|f| f.to_str().unwrap()).collect(); + match build_settings_pathbuf(&files, Some(settings_files), None) { + Ok(setting_buf) => { + let setting = setting_buf.settings(); + let files = setting.input(); + + let work_dir = setting_buf + .path() + .clone() + .map(|p| p.to_string_lossy().to_string()) + .unwrap_or_default(); + + let mut load_opt = kclvm_parser::LoadProgramOptions { + work_dir: work_dir.clone(), + ..Default::default() + }; + let metadata = + fill_pkg_maps_for_k_file(tool, file.into(), &mut load_opt).unwrap_or(None); + if files.is_empty() { + default_res(tool, file, load_pkg) + } else { + (files, Some(load_opt), metadata) + } + } + Err(_) => default_res(tool, file, load_pkg), + } + } + Ok(CompileUnitPath::ModFile(dir)) => match load_mod_file(&dir) { + Ok(mod_file) => { + let mut load_opt = kclvm_parser::LoadProgramOptions::default(); + let metadata = + fill_pkg_maps_for_k_file(tool, file.into(), &mut load_opt).unwrap_or(None); + if let Some(files) = mod_file.get_entries() { + let work_dir = dir.to_string_lossy().to_string(); + load_opt.work_dir = work_dir.clone(); + (files, Some(load_opt), metadata) + } else { + default_res(tool, file, load_pkg) + } + } + Err(_) => default_res(tool, file, load_pkg), + }, + Ok(CompileUnitPath::NotFound) | Err(_) => default_res(tool, file, load_pkg), + } +} + +pub fn lookup_compile_workspaces( + tool: &dyn Toolchain, + path: &str, + load_pkg: bool, +) -> ( + HashMap, + Option>, +) { + let mut workspaces = HashMap::new(); + match lookup_workspace(path) { + Ok(workspace) => match &workspace { + WorkSpaceKind::WorkFile(work_file_path) => { + if let Ok(mut workfile) = load_work_file(work_file_path) { + let root = work_file_path.parent().unwrap(); + workfile.canonicalize(root.to_path_buf()); + for work in workfile.workspaces { + match lookup_workspace(&work.abs_path) { + Ok(workspace) => { + workspaces.insert( + workspace.clone(), + lookup_compile_workspace(tool, &work.abs_path, load_pkg), + ); + } + Err(_) => {} + } + } + return (workspaces, Some(workfile.failed.clone())); + } + } + WorkSpaceKind::Folder(folder) => { + let load_opt = kclvm_parser::LoadProgramOptions::default(); + let metadata = None; + + if load_pkg { + if folder.is_dir() { + if let Ok(files) = get_kcl_files(folder.clone(), false) { + workspaces.insert(workspace, (files, Some(load_opt), metadata)); + return (workspaces, None); + } + } + } + workspaces.insert( + workspace, + (vec![path.to_string()], Some(load_opt), metadata), + ); + } + WorkSpaceKind::SettingFile(setting_file) => { + workspaces.insert( + workspace.clone(), + lookup_compile_workspace( + tool, + &setting_file.as_path().adjust_canonicalization(), + load_pkg, + ), + ); + } + WorkSpaceKind::ModFile(mod_file) => { + workspaces.insert( + workspace.clone(), + lookup_compile_workspace( + tool, + &mod_file.as_path().adjust_canonicalization(), + load_pkg, + ), + ); + } + WorkSpaceKind::File(_) | WorkSpaceKind::NotFound => { + let pathbuf = PathBuf::from(path); + let file_path = pathbuf.as_path(); + if file_path.is_file() { + workspaces.insert(workspace, lookup_compile_workspace(tool, path, load_pkg)); + } + } + }, + Err(_) => {} + } + + (workspaces, None) +} + +/// Lookup default setting files e.g. kcl.yaml +pub fn lookup_setting_files(dir: &Path) -> Vec { + let mut settings = vec![]; + if let Ok(p) = lookup_kcl_yaml(dir) { + settings.push(p); + } + settings +} + +fn lookup_kcl_yaml(dir: &Path) -> io::Result { + let mut path = dir.to_path_buf(); + path.push(DEFAULT_SETTING_FILE); + if path.is_file() { + Ok(path) + } else { + Err(io::Error::new( + ErrorKind::NotFound, + "Ran out of places to find kcl.yaml", + )) + } +} + +pub type CompileUnitOptions = (Vec, Option, Option); + +/// CompileUnitPath is the kcl program default entries that are defined +/// in the config files. +#[derive(Debug, PartialEq, Eq, Clone)] +pub enum CompileUnitPath { + SettingFile(PathBuf), + ModFile(PathBuf), + NotFound, +} + +/// LSP workspace, will replace CompileUnitPath +#[derive(Debug, PartialEq, Eq, Clone, Hash)] +pub enum WorkSpaceKind { + WorkFile(PathBuf), + ModFile(PathBuf), + SettingFile(PathBuf), + Folder(PathBuf), + File(PathBuf), + NotFound, +} + +/// For the KCL project, some definitions may be introduced through multi-file +/// compilation (kcl.yaml). This function is used to start from a single file and try +/// to find a `compile unit` that contains all definitions +/// Given a file path, search for the nearest "kcl.yaml" file or the nearest "kcl.mod" file. +/// If a "kcl.yaml" file is found, return the path of the directory containing the file. +/// If a "kcl.mod" file is found, return the path of the directory containing the file. +/// If none of these files are found, return an error indicating that the files were not found. +/// +/// Example: +/// +-- project +/// | +-- base +/// | | +-- base.k +/// | +-- prod +/// | | +-- main.k +/// | | +-- kcl.yaml +/// | +-- test +/// | | +-- main.k +/// | | +-- kcl.yaml +/// | +-- kcl.mod +/// +/// If the input file is project/prod/main.k or project/test/main.k, it will return +/// Path("project/prod") or Path("project/test") +pub fn lookup_compile_unit_path(file: &str) -> io::Result { + let path = PathBuf::from(file); + let current_dir_path = path.as_path().parent().unwrap(); + let entries = read_dir(current_dir_path)?; + for entry in entries { + let entry = entry?; + // The entry priority of `kcl.yaml`` is higher than that of `kcl.mod`. + if entry.file_name() == *DEFAULT_SETTING_FILE { + // If find "kcl.yaml", the input file is in a compile stack, return the + // path of this compile stack + return Ok(CompileUnitPath::SettingFile(PathBuf::from( + current_dir_path, + ))); + } else if entry.file_name() == *KCL_MOD_FILE { + return Ok(CompileUnitPath::ModFile(PathBuf::from(current_dir_path))); + } + } + Ok(CompileUnitPath::NotFound) +} + +/// It will replace lookup_compile_unit_path() +pub fn lookup_workspace(path: &str) -> io::Result { + let pathbuf = PathBuf::from(path); + let path = pathbuf.as_path(); + if path.is_dir() { + for entry in read_dir(path)? { + let entry = entry?; + if entry.file_name() == *KCL_WORK_FILE { + return Ok(WorkSpaceKind::WorkFile(entry.path())); + } + } + + for entry in read_dir(path)? { + let entry = entry?; + if entry.file_name() == *KCL_MOD_FILE { + return Ok(WorkSpaceKind::ModFile(entry.path())); + } + } + + for entry in read_dir(path)? { + let entry = entry?; + if entry.file_name() == *DEFAULT_SETTING_FILE { + return Ok(WorkSpaceKind::SettingFile(entry.path())); + } + } + + return Ok(WorkSpaceKind::Folder(PathBuf::from(path))); + } + if path.is_file() { + if let Some(ext) = path.extension() { + if ext.to_str().unwrap() == KCL_FILE_EXTENSION { + return Ok(WorkSpaceKind::File(PathBuf::from(path))); + } + } + } + Ok(WorkSpaceKind::NotFound) +} + +/// Get the package string list form the package path. +pub fn get_pkg_list(pkgpath: &str) -> Result> { + let mut dir_list: Vec = Vec::new(); + let mut dir_map: HashSet = HashSet::new(); + let cwd = std::env::current_dir()?; + + let pkgpath = if pkgpath.is_empty() { + cwd.to_string_lossy().to_string() + } else { + pkgpath.to_string() + }; + + let include_sub_pkg = pkgpath.ends_with("/..."); + let pkgpath = if include_sub_pkg { + pkgpath.trim_end_matches("/...").to_string() + } else { + pkgpath + }; + + if pkgpath != "." && pkgpath.ends_with('.') { + return Ok(Vec::new()); + } + + if pkgpath.is_empty() { + return Ok(Vec::new()); + } + + match pkgpath.chars().next() { + Some('.') => { + let pkgpath = Path::new(&cwd).join(&pkgpath); + pkgpath.to_string_lossy().to_string() + } + _ => { + if Path::new(&pkgpath).is_absolute() { + pkgpath.clone() + } else if !pkgpath.contains('/') && !pkgpath.contains('\\') { + pkgpath.replace('.', "/") + } else { + let pkgroot = + get_pkg_root(cwd.to_str().ok_or(anyhow::anyhow!("cwd path not found"))?) + .unwrap_or_default(); + if !pkgroot.is_empty() { + PathBuf::from(pkgroot) + .join(&pkgpath) + .to_string_lossy() + .to_string() + } else { + Path::new(&cwd).join(&pkgpath).to_string_lossy().to_string() + } + } + } + }; + + if !include_sub_pkg { + return Ok(vec![pkgpath]); + } + + for entry in WalkDir::new(&pkgpath).into_iter().filter_map(|e| e.ok()) { + let path = entry.path(); + if !path.is_dir() + && path.extension().and_then(|ext| ext.to_str()) == Some(KCL_FILE_EXTENSION) + && !path + .file_name() + .map(|name| name.to_string_lossy().starts_with('_')) + .unwrap_or(false) + { + if let Some(dir) = path.parent().map(|p| p.to_string_lossy().to_string()) { + if !dir_map.contains(&dir) { + dir_list.push(dir.clone()); + dir_map.insert(dir); + } + } + } + } + + Ok(dir_list) +} + +/// [`lookup_the_nearest_file_dir`] will start from [`from`] and search for file [`the_nearest_file`] in the parent directories. +/// If found, it will return the [`Some`] of [`the_nearest_file`] file path. If not found, it will return [`None`] +pub(crate) fn lookup_the_nearest_file_dir( + from: PathBuf, + the_nearest_file: &str, +) -> Option { + let mut current_dir = from; + + loop { + let found_path = current_dir.join(the_nearest_file); + if found_path.is_file() { + return current_dir.canonicalize().ok(); + } + + match current_dir.parent() { + Some(parent) => current_dir = parent.to_path_buf(), + None => return None, + } + } +} + +/// [`kcl`] will return the path for executable kcl binary. +pub fn kcl() -> PathBuf { + get_path_for_executable("kcl") +} + +/// [`get_path_for_executable`] will return the path for [`executable_name`]. +pub fn get_path_for_executable(executable_name: &'static str) -> PathBuf { + // The current implementation checks $PATH for an executable to use: + // `` + // example: for , this tries just , which will succeed if is on the $PATH + + if lookup_in_path(executable_name) { + return executable_name.into(); + } + + executable_name.into() +} + +/// [`lookup_in_path`] will search for an executable file [`exec`] in the environment variable ‘PATH’. +/// If found, return true, otherwise return false. +fn lookup_in_path(exec: &str) -> bool { + let paths = env::var_os("PATH").unwrap_or_default(); + env::split_paths(&paths) + .map(|path| path.join(exec)) + .find_map(probe) + .is_some() +} + +/// [`probe`] check if the given path points to a file. +/// If it does, return [`Some`] of the path. +/// If not, check if adding the current operating system's executable file extension (if any) to the path points to a file. +/// If it does, return [`Some`] of the path with the extension added. +/// If neither, return [`None`]. +fn probe(path: PathBuf) -> Option { + let with_extension = match env::consts::EXE_EXTENSION { + "" => None, + it => Some(path.with_extension(it)), + }; + iter::once(path) + .chain(with_extension) + .find(|it| it.is_file()) +} diff --git a/kclvm/driver/src/test_data/kpm_metadata/kcl.mod b/kclvm/driver/src/test_data/kpm_metadata/kcl.mod new file mode 100644 index 000000000..58b2a49f8 --- /dev/null +++ b/kclvm/driver/src/test_data/kpm_metadata/kcl.mod @@ -0,0 +1,7 @@ +[package] +name = "kcl1" +edition = "0.0.1" +version = "0.0.4" + +[dependencies] +flask_manifests = { git = "https://github.com/kcl-lang/flask-demo-kcl-manifests.git", commit = "ade147b", version = "0.0.1" } diff --git a/kclvm/driver/src/test_data/kpm_metadata/kcl.mod.lock b/kclvm/driver/src/test_data/kpm_metadata/kcl.mod.lock new file mode 100644 index 000000000..4dc847701 --- /dev/null +++ b/kclvm/driver/src/test_data/kpm_metadata/kcl.mod.lock @@ -0,0 +1,7 @@ +[dependencies] + [dependencies.flask_manifests] + name = "flask_manifests" + full_name = "flask_manifests_0.0.1" + version = "0.0.1" + url = "https://github.com/kcl-lang/flask-demo-kcl-manifests.git" + commit = "ade147b" diff --git a/test/test_units/test_kclvm/test_config/test_data/main.k b/kclvm/driver/src/test_data/kpm_metadata/subdir/main.k similarity index 100% rename from test/test_units/test_kclvm/test_config/test_data/main.k rename to kclvm/driver/src/test_data/kpm_metadata/subdir/main.k diff --git a/kclvm/driver/src/test_data/kpm_metadata_with_line/dep-with-line/kcl.mod b/kclvm/driver/src/test_data/kpm_metadata_with_line/dep-with-line/kcl.mod new file mode 100644 index 000000000..2f4e3935d --- /dev/null +++ b/kclvm/driver/src/test_data/kpm_metadata_with_line/dep-with-line/kcl.mod @@ -0,0 +1,5 @@ +[package] +name = "dep-with-line" +edition = "0.0.1" +version = "0.0.1" + diff --git a/internal/kclvm_py/tools/__init__.py b/kclvm/driver/src/test_data/kpm_metadata_with_line/dep-with-line/kcl.mod.lock similarity index 100% rename from internal/kclvm_py/tools/__init__.py rename to kclvm/driver/src/test_data/kpm_metadata_with_line/dep-with-line/kcl.mod.lock diff --git a/kclvm/driver/src/test_data/kpm_metadata_with_line/dep-with-line/main.k b/kclvm/driver/src/test_data/kpm_metadata_with_line/dep-with-line/main.k new file mode 100644 index 000000000..bfdcb0932 --- /dev/null +++ b/kclvm/driver/src/test_data/kpm_metadata_with_line/dep-with-line/main.k @@ -0,0 +1 @@ +The_first_kcl_program = 'Hello World dep-with-line!' \ No newline at end of file diff --git a/kclvm/driver/src/test_data/kpm_metadata_with_line/main_pkg/kcl.mod b/kclvm/driver/src/test_data/kpm_metadata_with_line/main_pkg/kcl.mod new file mode 100644 index 000000000..34b4be7eb --- /dev/null +++ b/kclvm/driver/src/test_data/kpm_metadata_with_line/main_pkg/kcl.mod @@ -0,0 +1,7 @@ +[package] +name = "main_pkg" +edition = "0.0.1" +version = "0.0.1" + +[dependencies] +dep-with-line = { path = "../dep-with-line" } diff --git a/kclvm/driver/src/test_data/kpm_metadata_with_line/main_pkg/kcl.mod.lock b/kclvm/driver/src/test_data/kpm_metadata_with_line/main_pkg/kcl.mod.lock new file mode 100644 index 000000000..8165e52f9 --- /dev/null +++ b/kclvm/driver/src/test_data/kpm_metadata_with_line/main_pkg/kcl.mod.lock @@ -0,0 +1,5 @@ +[dependencies] + [dependencies.dep-with-line] + name = "dep-with-line" + full_name = "dep-with-line_0.0.1" + version = "0.0.1" diff --git a/kclvm/driver/src/test_data/kpm_metadata_with_line/main_pkg/main.k b/kclvm/driver/src/test_data/kpm_metadata_with_line/main_pkg/main.k new file mode 100644 index 000000000..e78a5fba4 --- /dev/null +++ b/kclvm/driver/src/test_data/kpm_metadata_with_line/main_pkg/main.k @@ -0,0 +1,3 @@ +import dep_with_line as dwl + +The_first_kcl_program = dwl.The_first_kcl_program \ No newline at end of file diff --git a/kclvm/driver/src/test_data/kpm_update/kcl.mod b/kclvm/driver/src/test_data/kpm_update/kcl.mod new file mode 100644 index 000000000..7543c05d5 --- /dev/null +++ b/kclvm/driver/src/test_data/kpm_update/kcl.mod @@ -0,0 +1,8 @@ +[package] +name = "kpm_update" +edition = "0.0.1" +version = "0.0.1" + +[dependencies] +flask = { git = "https://github.com/kcl-lang/flask-demo-kcl-manifests", commit = "ade147b" } +helloworld = { oci = "oci://ghcr.io/kcl-lang/helloworld", tag = "0.1.0" } diff --git a/test/test_units/test_kclvm/test_compiler/test_build/cache_testdata/pkg/pkg1/pkg2/pkg.k b/kclvm/driver/src/test_data/pkg_list/pkg1/pkg.k similarity index 100% rename from test/test_units/test_kclvm/test_compiler/test_build/cache_testdata/pkg/pkg1/pkg2/pkg.k rename to kclvm/driver/src/test_data/pkg_list/pkg1/pkg.k diff --git a/test/test_units/test_kclvm/test_types/invalid_test_data/module/pkg/pkg.k b/kclvm/driver/src/test_data/pkg_list/pkg1/sub_pkg1/pkg.k similarity index 100% rename from test/test_units/test_kclvm/test_types/invalid_test_data/module/pkg/pkg.k rename to kclvm/driver/src/test_data/pkg_list/pkg1/sub_pkg1/pkg.k diff --git a/kclvm/driver/src/test_data/pkg_list/pkg2/pkg.k b/kclvm/driver/src/test_data/pkg_list/pkg2/pkg.k new file mode 100644 index 000000000..a668ca34b --- /dev/null +++ b/kclvm/driver/src/test_data/pkg_list/pkg2/pkg.k @@ -0,0 +1 @@ +a = 2 \ No newline at end of file diff --git a/kclvm/driver/src/test_data/test_vendor/.kpm/config/kpm.json b/kclvm/driver/src/test_data/test_vendor/.kpm/config/kpm.json new file mode 100644 index 000000000..c2aa99813 --- /dev/null +++ b/kclvm/driver/src/test_data/test_vendor/.kpm/config/kpm.json @@ -0,0 +1 @@ +{"DefaultOciRegistry":"ghcr.io","DefaultOciRepo":"kcl-lang"} \ No newline at end of file diff --git a/internal/kclvm_py/tools/docs/templates/md.mako b/kclvm/driver/src/test_data/test_vendor/.kpm/config/package-cache similarity index 100% rename from internal/kclvm_py/tools/docs/templates/md.mako rename to kclvm/driver/src/test_data/test_vendor/.kpm/config/package-cache diff --git a/kclvm/driver/src/test_data/test_vendor/helloworld_0.1.0/0.0.1/README.md b/kclvm/driver/src/test_data/test_vendor/helloworld_0.1.0/0.0.1/README.md new file mode 100644 index 000000000..4d63fef38 --- /dev/null +++ b/kclvm/driver/src/test_data/test_vendor/helloworld_0.1.0/0.0.1/README.md @@ -0,0 +1,2 @@ +## Introduction +This is a kcl package named helloworld. diff --git a/kclvm/driver/src/test_data/test_vendor/helloworld_0.1.0/0.0.1/artifacthub-pkg.yaml b/kclvm/driver/src/test_data/test_vendor/helloworld_0.1.0/0.0.1/artifacthub-pkg.yaml new file mode 100644 index 000000000..b8a9ecf50 --- /dev/null +++ b/kclvm/driver/src/test_data/test_vendor/helloworld_0.1.0/0.0.1/artifacthub-pkg.yaml @@ -0,0 +1,25 @@ +version: 0.0.1 +name: helloworld +displayName: helloworld +createdAt: "2023-10-24T12:25:12Z" +description: "This is a KCL package" +links: +- name: KCL homepage + url: https://kcl-lang.io/ +- name: KCL repo + url: https://github.com/kcl-lang/kcl +install: | + #### Add `helloworld` with tag `0.0.1` as dependency + ``` + kpm add helloworld:0.0.1 + ``` + + #### Pull `helloworld` with tag `0.0.1` to local + ``` + kpm pull helloworld:0.0.1 + ``` +maintainers: +- name: kcl-lang.io + email: kcl-lang.io@domainsbyproxy.com +provider: + name: kcl-lang.io diff --git a/kclvm/driver/src/test_data/test_vendor/helloworld_0.1.0/README.md b/kclvm/driver/src/test_data/test_vendor/helloworld_0.1.0/README.md new file mode 100644 index 000000000..4d63fef38 --- /dev/null +++ b/kclvm/driver/src/test_data/test_vendor/helloworld_0.1.0/README.md @@ -0,0 +1,2 @@ +## Introduction +This is a kcl package named helloworld. diff --git a/kclvm/driver/src/test_data/test_vendor/helloworld_0.1.0/kcl.mod b/kclvm/driver/src/test_data/test_vendor/helloworld_0.1.0/kcl.mod new file mode 100644 index 000000000..d71c44407 --- /dev/null +++ b/kclvm/driver/src/test_data/test_vendor/helloworld_0.1.0/kcl.mod @@ -0,0 +1,5 @@ +[package] +name = "helloworld" +edition = "*" +version = "0.1.0" + diff --git a/kclvm/driver/src/test_data/test_vendor/helloworld_0.1.0/main.k b/kclvm/driver/src/test_data/test_vendor/helloworld_0.1.0/main.k new file mode 100644 index 000000000..fa7048e63 --- /dev/null +++ b/kclvm/driver/src/test_data/test_vendor/helloworld_0.1.0/main.k @@ -0,0 +1 @@ +The_first_kcl_program = 'Hello World!' \ No newline at end of file diff --git a/kclvm/driver/src/test_data/test_vendor/kcl4_v0.0.1/k4/main.k b/kclvm/driver/src/test_data/test_vendor/kcl4_v0.0.1/k4/main.k new file mode 100644 index 000000000..97eac82ed --- /dev/null +++ b/kclvm/driver/src/test_data/test_vendor/kcl4_v0.0.1/k4/main.k @@ -0,0 +1 @@ +demo = 4 \ No newline at end of file diff --git a/kclvm/driver/src/test_data/test_vendor/kcl4_v0.0.1/kcl.mod b/kclvm/driver/src/test_data/test_vendor/kcl4_v0.0.1/kcl.mod new file mode 100644 index 000000000..52280a04b --- /dev/null +++ b/kclvm/driver/src/test_data/test_vendor/kcl4_v0.0.1/kcl.mod @@ -0,0 +1,6 @@ +[package] +name = "kcl4" +edition = "0.0.1" +version = "0.0.1" + +[dependencies] \ No newline at end of file diff --git a/internal/kclvm_py/tools/langserver/__init__.py b/kclvm/driver/src/test_data/test_vendor/kcl4_v0.0.1/kcl.mod.lock similarity index 100% rename from internal/kclvm_py/tools/langserver/__init__.py rename to kclvm/driver/src/test_data/test_vendor/kcl4_v0.0.1/kcl.mod.lock diff --git a/kclvm/driver/src/tests.rs b/kclvm/driver/src/tests.rs new file mode 100644 index 000000000..e98fddcf1 --- /dev/null +++ b/kclvm/driver/src/tests.rs @@ -0,0 +1,372 @@ +use std::path::PathBuf; +use std::{env, fs, panic}; + +use kclvm_config::modfile::get_vendor_home; +use kclvm_config::settings::KeyValuePair; +use kclvm_parser::LoadProgramOptions; +use walkdir::WalkDir; + +use crate::arguments::parse_key_value_pair; +use crate::toolchain::Toolchain; +use crate::toolchain::{fill_pkg_maps_for_k_file, CommandToolchain, NativeToolchain}; +use crate::{get_pkg_list, lookup_the_nearest_file_dir, toolchain}; + +#[test] +fn test_parse_key_value_pair() { + let cases = [ + ( + "k=v", + KeyValuePair { + key: "k".to_string(), + value: "\"v\"".into(), + }, + ), + ( + "k=1", + KeyValuePair { + key: "k".to_string(), + value: "1".into(), + }, + ), + ( + "k=None", + KeyValuePair { + key: "k".to_string(), + value: "null".into(), + }, + ), + ( + "k=True", + KeyValuePair { + key: "k".to_string(), + value: "true".into(), + }, + ), + ( + "k=true", + KeyValuePair { + key: "k".to_string(), + value: "true".into(), + }, + ), + ( + "k={\"key\": \"value\"}", + KeyValuePair { + key: "k".to_string(), + value: "{\"key\": \"value\"}".into(), + }, + ), + ( + "k=[1, 2, 3]", + KeyValuePair { + key: "k".to_string(), + value: "[1, 2, 3]".into(), + }, + ), + ]; + for (value, pair) in cases { + let result = parse_key_value_pair(value).unwrap(); + assert_eq!(result.key, pair.key); + assert_eq!(result.value, pair.value); + } +} + +fn clear_path(path: PathBuf) { + WalkDir::new(path) + .into_iter() + .filter_map(|e| e.ok()) + .for_each(|e| { + fs::remove_file(e.path()) + .or_else(|_| fs::remove_dir(e.path())) + .ok(); + }); +} + +#[test] +fn test_parse_key_value_pair_fail() { + let cases = ["=v", "k=", "="]; + for case in cases { + assert!(parse_key_value_pair(case).is_err()); + } +} + +fn test_fill_pkg_maps_for_k_file_with_line() { + let root_path = PathBuf::from(".") + .join("src") + .join("test_data") + .join("kpm_metadata_with_line"); + + let main_pkg_path = root_path.join("main_pkg").join("main.k"); + let dep_with_line_path = root_path.join("dep-with-line"); + + let mut opts = LoadProgramOptions::default(); + assert_eq!(format!("{:?}", opts.package_maps), "{}"); + + let res = fill_pkg_maps_for_k_file(&toolchain::default(), main_pkg_path.clone(), &mut opts); + assert!(res.is_ok()); + + let pkg_maps = opts.package_maps.clone(); + assert_eq!(pkg_maps.len(), 1); + assert!(pkg_maps.get("dep_with_line").is_some()); + + assert_eq!( + PathBuf::from(pkg_maps.get("dep_with_line").unwrap().clone()) + .canonicalize() + .unwrap() + .display() + .to_string(), + dep_with_line_path + .canonicalize() + .unwrap() + .display() + .to_string() + ); +} + +#[test] +fn test_native_fill_pkg_maps_for_k_file_with_line() { + let root_path = PathBuf::from(".") + .join("src") + .join("test_data") + .join("kpm_metadata_with_line"); + + let main_pkg_path = root_path.join("main_pkg").join("main.k"); + let dep_with_line_path = root_path.join("dep-with-line"); + + let mut opts = LoadProgramOptions::default(); + assert_eq!(format!("{:?}", opts.package_maps), "{}"); + + let res = fill_pkg_maps_for_k_file( + &NativeToolchain::default(), + main_pkg_path.clone(), + &mut opts, + ); + assert!(res.is_ok()); + + let pkg_maps = opts.package_maps.clone(); + assert_eq!(pkg_maps.len(), 1); + assert!(pkg_maps.get("dep_with_line").is_some()); + + assert_eq!( + PathBuf::from(pkg_maps.get("dep_with_line").unwrap().clone()) + .canonicalize() + .unwrap() + .display() + .to_string(), + dep_with_line_path + .canonicalize() + .unwrap() + .display() + .to_string() + ); +} + +fn test_fill_pkg_maps_for_k_file() { + let path = PathBuf::from(".") + .join("src") + .join("test_data") + .join("kpm_metadata") + .join("subdir") + .join("main.k"); + + let vendor_path = PathBuf::from(".") + .join("src") + .join("test_data") + .join("test_vendor"); + + env::set_var( + "KCL_PKG_PATH", + vendor_path.canonicalize().unwrap().display().to_string(), + ); + + let mut opts = LoadProgramOptions::default(); + assert_eq!(format!("{:?}", opts.package_maps), "{}"); + + let res = fill_pkg_maps_for_k_file(&toolchain::default(), path.clone(), &mut opts); + assert!(res.is_ok()); + let vendor_home = get_vendor_home(); + + let pkg_maps = opts.package_maps.clone(); + assert_eq!(pkg_maps.len(), 1); + assert!(pkg_maps.get("flask_manifests").is_some()); + assert_eq!( + PathBuf::from(pkg_maps.get("flask_manifests").unwrap().clone()) + .canonicalize() + .unwrap() + .display() + .to_string(), + PathBuf::from(vendor_home) + .join("flask-demo-kcl-manifests_ade147b") + .canonicalize() + .unwrap() + .display() + .to_string() + ); + + clear_path(vendor_path.join(".kpm")) +} + +#[test] +fn test_lookup_the_nearest_file_dir() { + let path = PathBuf::from(".") + .join("src") + .join("test_data") + .join("kpm_metadata"); + let result = lookup_the_nearest_file_dir(path.clone(), "kcl.mod"); + assert!(result.is_some()); + assert_eq!( + result.unwrap().display().to_string(), + path.canonicalize().unwrap().display().to_string() + ); + + let main_path = path.join("subdir").join("main.k"); + let result = lookup_the_nearest_file_dir(main_path, "kcl.mod"); + assert!(result.is_some()); + assert_eq!( + result.unwrap().display().to_string(), + path.canonicalize().unwrap().display().to_string() + ); +} + +#[test] +fn test_fetch_metadata_in_order() { + test_cmd_tool_fetch_metadata(); + println!("test_cmd_tool_fetch_metadata() passed"); + test_native_tool_fetch_metadata(); + println!("test_native_tool_fetch_metadata() passed"); + test_fill_pkg_maps_for_k_file(); + println!("test_fill_pkg_maps_for_k_file() passed"); + test_native_fill_pkg_maps_for_k_file_with_line(); + println!("test_native_fill_pkg_maps_for_k_file_with_line() passed"); + test_fill_pkg_maps_for_k_file_with_line(); + println!("test_fill_pkg_maps_for_k_file_with_line() passed"); + test_native_update_dependencies(); + println!("test_native_update_dependencies() passed"); + test_update_dependencies(); + println!("test_update_dependencies() passed"); +} + +fn test_cmd_tool_fetch_metadata() { + test_tool_fetch_metadata(CommandToolchain::default()) +} + +fn test_native_tool_fetch_metadata() { + test_tool_fetch_metadata(NativeToolchain::default()) +} + +fn test_tool_fetch_metadata(tool: impl Toolchain) { + let path = PathBuf::from(".") + .join("src") + .join("test_data") + .join("kpm_metadata"); + + let vendor_path = PathBuf::from(".") + .join("src") + .join("test_data") + .join("test_vendor"); + + env::set_var( + "KCL_PKG_PATH", + vendor_path.canonicalize().unwrap().display().to_string(), + ); + let vendor_home = get_vendor_home(); + let metadata = tool.fetch_metadata(path.clone()); + let pkgs = metadata.unwrap().packages.clone(); + assert_eq!(pkgs.len(), 1); + assert!(pkgs.get("flask_manifests").is_some()); + assert_eq!(pkgs.get("flask_manifests").unwrap().name, "flask_manifests"); + + let manifest_path = pkgs.get("flask_manifests").unwrap().manifest_path.clone(); + println!("Manifest path: {:?}", manifest_path); + + let canonicalized_manifest_path = manifest_path.canonicalize(); + println!( + "Canonicalized manifest path: {:?}", + canonicalized_manifest_path + ); + + assert_eq!( + canonicalized_manifest_path.unwrap().display().to_string(), + PathBuf::from(vendor_home) + .join("flask-demo-kcl-manifests_ade147b") + .canonicalize() + .unwrap() + .display() + .to_string() + ); + clear_path(vendor_path.join(".kpm")) +} + +#[test] +fn test_fetch_metadata_invalid() { + let result = panic::catch_unwind(|| { + let tool = toolchain::default(); + let result = tool.fetch_metadata("invalid_path".to_string().into()); + match result { + Ok(_) => { + panic!("The method should not return Ok") + } + Err(_) => { + println!("return with an error.") + } + } + }); + + match result { + Ok(_) => println!("no panic"), + Err(e) => panic!("The method should not panic forever.: {:?}", e), + } +} + +#[test] +fn test_native_fetch_metadata_invalid() { + let result = panic::catch_unwind(|| { + let tool = NativeToolchain::default(); + let result = tool.fetch_metadata("invalid_path".to_string().into()); + match result { + Ok(_) => { + panic!("The method should not return Ok") + } + Err(_) => { + println!("return with an error.") + } + } + }); + + match result { + Ok(_) => println!("no panic"), + Err(e) => panic!("The method should not panic forever.: {:?}", e), + } +} + +#[test] +fn test_get_pkg_list() { + assert_eq!(get_pkg_list("./src/test_data/pkg_list/").unwrap().len(), 1); + assert_eq!( + get_pkg_list("./src/test_data/pkg_list/...").unwrap().len(), + 3 + ); +} + +fn test_update_dependencies() { + let path = PathBuf::from(".") + .join("src") + .join("test_data") + .join("kpm_update"); + + let tool = toolchain::default(); + let update_mod = tool.update_dependencies(path.clone()); + // Show more information when the test fails. + println!("{:?}", update_mod); + assert!(update_mod.is_ok()); +} + +fn test_native_update_dependencies() { + let path = PathBuf::from(".") + .join("src") + .join("test_data") + .join("kpm_update"); + + let tool = NativeToolchain::default(); + tool.update_dependencies(path.clone()).unwrap(); +} diff --git a/kclvm/driver/src/toolchain.rs b/kclvm/driver/src/toolchain.rs new file mode 100644 index 000000000..13774c6ed --- /dev/null +++ b/kclvm/driver/src/toolchain.rs @@ -0,0 +1,228 @@ +use crate::{kcl, lookup_the_nearest_file_dir}; +use anyhow::{bail, Result}; +use kclvm_config::modfile::KCL_MOD_FILE; +use kclvm_parser::LoadProgramOptions; +use kclvm_utils::pkgpath::rm_external_pkg_name; +use serde::{Deserialize, Serialize}; +use std::ffi::OsStr; +use std::{collections::HashMap, path::PathBuf, process::Command}; +#[cfg(not(target_arch = "wasm32"))] +use {crate::client::ModClient, parking_lot::Mutex, std::sync::Arc}; + +/// `Toolchain` is a trait that outlines a standard set of operations that must be +/// implemented for a KCL module (mod), typically involving fetching metadata from, +/// and updating dependencies within, a specified path. +pub trait Toolchain: Send + Sync { + /// Fetches the metadata from the given manifest file path. + /// + /// The `manifest_path` parameter is generic over P, meaning it can be any type that + /// implements the `AsRef` trait. It is commonly a reference to a file path or a type + /// that can be converted into a file path reference, such as `String` or `PathBuf`. + /// + /// The return type `Result` indicates that this method will either return an + /// instance of `Metadata` or an error. + /// + /// # Parameters + /// + /// * `manifest_path` - A reference to the path of the manifest file, expected to be a type + /// that can be converted into a reference to a filesystem path. + fn fetch_metadata(&self, manifest_path: PathBuf) -> Result; + + /// Updates the dependencies as defined within the given manifest file path. + /// + /// The `manifest_path` parameter is generic over P, just like in the `fetch_metadata` method, + /// and is used to specify the location of the manifest file. + /// + /// The return type `Result<()>` indicates that this method will execute without returning a + /// value upon success but may return an error. + /// + /// # Parameters + /// + /// * `manifest_path` - A reference to the path of the manifest file, expected to be a type + /// that can be converted into a reference to a filesystem path. + fn update_dependencies(&self, manifest_path: PathBuf) -> Result<()>; +} + +#[derive(Debug, Clone)] +pub struct CommandToolchain> { + path: S, +} + +impl Default for CommandToolchain { + fn default() -> Self { + Self { path: kcl() } + } +} + +impl + Send + Sync> Toolchain for CommandToolchain { + fn fetch_metadata(&self, manifest_path: PathBuf) -> Result { + match Command::new(&self.path) + .arg("mod") + .arg("metadata") + .arg("--update") + .current_dir(manifest_path) + .output() + { + Ok(output) => { + if !output.status.success() { + bail!( + "fetch metadata failed with error: {}", + String::from_utf8_lossy(&output.stderr) + ); + } + Ok(Metadata::parse( + String::from_utf8_lossy(&output.stdout).to_string(), + )?) + } + Err(err) => bail!("fetch metadata failed with error: {}", err), + } + } + + fn update_dependencies(&self, manifest_path: PathBuf) -> Result<()> { + match Command::new(&self.path) + .arg("mod") + .arg("update") + .current_dir(manifest_path) + .output() + { + Ok(output) => { + if !output.status.success() { + bail!( + "update failed with error: {}", + String::from_utf8_lossy(&output.stderr) + ); + } + Ok(()) + } + Err(err) => bail!("update failed with error: {}", err), + } + } +} + +#[cfg(not(target_arch = "wasm32"))] +#[derive(Default)] +pub struct NativeToolchain { + client: Arc>, +} + +#[cfg(not(target_arch = "wasm32"))] +impl Toolchain for NativeToolchain { + fn fetch_metadata(&self, manifest_path: PathBuf) -> Result { + let mut client = self.client.lock(); + client.change_work_dir(manifest_path)?; + match client.get_metadata_from_mod_lock_file() { + Some(metadata) => Ok(metadata), + None => client.resolve_all_deps(false), + } + } + + fn update_dependencies(&self, manifest_path: PathBuf) -> Result<()> { + let mut client = self.client.lock(); + client.change_work_dir(manifest_path)?; + let _ = client.resolve_all_deps(true)?; + Ok(()) + } +} + +/// [`Metadata`] is the metadata of the current KCL module, +/// currently only the mapping between the name and path of the external dependent package is included. +#[derive(Deserialize, Serialize, Default, Debug, Clone)] +pub struct Metadata { + pub packages: HashMap, +} + +/// [`Package`] is a structure representing a package. +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct Package { + /// Name as given in the `kcl.mod` + pub name: String, + /// Path containing the `kcl.mod` + pub manifest_path: PathBuf, +} + +impl Metadata { + /// Parses metadata from a string. + /// + /// # Arguments + /// + /// * `data` - The string containing metadata. + /// + /// # Returns + /// + /// * `Result` - Metadata if successful, error otherwise. + fn parse(data: String) -> Result { + let meta = serde_json::from_str(data.as_ref())?; + Ok(meta) + } +} + +/// [`default`] returns the default toolchain. +#[inline] +pub fn default() -> impl Toolchain { + CommandToolchain::default() +} + +/// Searches for the nearest kcl.mod directory containing the given file and fills the compilation options +/// with metadata of dependent packages. +/// +/// # Arguments +/// +/// * `k_file_path` - Path to the K file for which metadata is needed. +/// * `opts` - Mutable reference to the compilation options to fill. +/// +/// # Returns +/// +/// * `Result<()>` - Empty result if successful, error otherwise. +pub(crate) fn fill_pkg_maps_for_k_file( + tool: &dyn Toolchain, + k_file_path: PathBuf, + opts: &mut LoadProgramOptions, +) -> Result> { + match lookup_the_nearest_file_dir(k_file_path, KCL_MOD_FILE) { + Some(mod_dir) => { + let metadata = tool.fetch_metadata(mod_dir.canonicalize()?)?; + let maps: HashMap = metadata + .packages + .iter() + .map(|(name, pkg)| (name.clone(), pkg.manifest_path.display().to_string())) + .collect(); + opts.package_maps.extend(maps); + Ok(Some(metadata)) + } + None => Ok(None), + } +} + +/// [`get_real_path_from_external`] will ask for the local path for [`pkg_name`] with subdir [`pkgpath`]. +/// If the external package, whose [`pkg_name`] is 'my_package', is stored in '\user\my_package_v0.0.1'. +/// The [`pkgpath`] is 'my_package.examples.apps'. +/// +/// [`get_real_path_from_external`] will return '\user\my_package_v0.0.1\examples\apps' +/// +/// # Note +/// [`get_real_path_from_external`] is just a method for calculating a path, it doesn't check whether a path exists. +pub fn get_real_path_from_external( + tool: &dyn Toolchain, + pkg_name: &str, + pkgpath: &str, + current_pkg_path: PathBuf, +) -> PathBuf { + let mut real_path = PathBuf::new(); + let pkg_root = tool + .fetch_metadata(current_pkg_path) + .map(|metadata| { + metadata + .packages + .get(pkg_name) + .map_or(PathBuf::new(), |pkg| pkg.manifest_path.clone()) + }) + .unwrap_or_else(|_| PathBuf::new()); + real_path = real_path.join(pkg_root); + + let pkgpath = match rm_external_pkg_name(pkgpath) { + Ok(path) => path, + Err(_) => String::new(), + }; + pkgpath.split('.').for_each(|s| real_path.push(s)); + real_path +} diff --git a/kclvm/error/Cargo.toml b/kclvm/error/Cargo.toml index 111b07143..8ce827d03 100644 --- a/kclvm/error/Cargo.toml +++ b/kclvm/error/Cargo.toml @@ -1,18 +1,24 @@ [package] name = "kclvm-error" -version = "0.1.0" +version = "0.11.0" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -rustc_span = { path = "../3rdparty/rustc_span" } -kclvm-span = {path = "../span", version = "0.1.0"} -kclvm-runtime = {path = "../runtime", version = "0.1.0"} +compiler_base_span = "0.1.2" +compiler_base_session = "0.1.3" +compiler_base_error = "0.1.6" +compiler_base_macros = "0.1.1" +kclvm-span = {path = "../span"} +kclvm-runtime = {path = "../runtime"} +kclvm-utils = {path = "../utils"} +anyhow = "1.0" tracing = "0.1" -atty = "0.2" -termcolor = "1.0" -annotate-snippets = "0.8.0" +annotate-snippets = { version = "0.9.2", default-features = false, features = ["color"] } +serde = { version = "1.0", features = ["derive"] } termize = "0.1.1" indexmap = "1.0" +serde_json = "1.0" +thiserror = "1.0.61" diff --git a/kclvm/error/src/diagnostic.rs b/kclvm/error/src/diagnostic.rs index f88b6cc05..c15c14d4f 100644 --- a/kclvm/error/src/diagnostic.rs +++ b/kclvm/error/src/diagnostic.rs @@ -1,11 +1,11 @@ +use indexmap::IndexSet; +use kclvm_span::Loc; use std::fmt; use std::hash::Hash; -use kclvm_span::Loc; -use rustc_span::Pos; -use termcolor::{Color, ColorSpec}; +use crate::{ErrorKind, WarningKind}; -use crate::ErrorKind; +pub type Errors = IndexSet; /// Diagnostic structure. #[derive(Clone, Debug, PartialEq, Eq, Hash)] @@ -19,7 +19,7 @@ pub struct Diagnostic { /// line, and column location. /// /// A Position is valid if the line number is > 0. -/// The line and column are both 1 based. +/// The line is 1-based and the column is 0-based. #[derive(PartialEq, Clone, Eq, Hash, Debug, Default)] pub struct Position { pub filename: String, @@ -68,24 +68,32 @@ impl Position { } pub fn info(&self) -> String { - let mut info = "---> File ".to_string(); - info += &self.filename; - info += &format!(":{}", self.line); - if let Some(column) = self.column { - info += &format!(":{}", column + 1); + if !self.filename.is_empty() { + let mut info = "---> File ".to_string(); + info += &self.filename; + info += &format!(":{}", self.line); + if let Some(column) = self.column { + info += &format!(":{}", column + 1); + } + info + } else { + "".to_string() } - info } } impl From for Position { fn from(loc: Loc) -> Self { + let filename = kclvm_utils::path::convert_windows_drive_letter(&format!( + "{}", + loc.file.name.prefer_remapped() + )); Self { - filename: format!("{}", loc.file.name.prefer_remapped()), + filename, line: loc.line as u64, column: if loc.col_display > 0 { // Loc col is the (0-based) column offset. - Some(loc.col.to_usize() as u64 + 1) + Some(loc.col.0 as u64) } else { None }, @@ -94,24 +102,27 @@ impl From for Position { } impl Diagnostic { - pub fn new(level: Level, message: &str, pos: Position) -> Self { - Diagnostic::new_with_code(level, message, pos, None) + pub fn new(level: Level, message: &str, range: Range) -> Self { + Diagnostic::new_with_code(level, message, None, range, None, None) } /// New a diagnostic with error code. pub fn new_with_code( level: Level, message: &str, - pos: Position, + note: Option<&str>, + range: Range, code: Option, + suggestions: Option>, ) -> Self { Diagnostic { level, messages: vec![Message { - pos, + range, style: Style::LineAndColumn, message: message.to_string(), - note: None, + note: note.map(String::from), + suggested_replacement: suggestions, }], code, } @@ -123,18 +134,28 @@ impl Diagnostic { } } +pub type Range = (Position, Position); + +/// Returns a dummy range whose filename is empty, line is 1 and column is None. +#[inline] +pub fn dummy_range() -> Range { + (Position::dummy_pos(), Position::dummy_pos()) +} + #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct Message { - pub pos: Position, + pub range: Range, pub style: Style, pub message: String, pub note: Option, + pub suggested_replacement: Option>, } #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub enum DiagnosticId { Error(ErrorKind), - Warning(String), + Warning(WarningKind), + Suggestions, } #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] @@ -142,31 +163,17 @@ pub enum Level { Error, Warning, Note, + Suggestions, } impl Level { pub fn to_str(self) -> &'static str { match self { - Level::Error => "Error", - Level::Warning => "Warning", - Level::Note => "Note", - } - } - - pub fn color(&self) -> ColorSpec { - let mut spec = ColorSpec::new(); - match self { - Level::Error => { - spec.set_fg(Some(Color::Red)).set_intense(true); - } - Level::Warning => { - spec.set_fg(Some(Color::Yellow)).set_intense(cfg!(windows)); - } - Level::Note => { - spec.set_fg(Some(Color::Green)).set_intense(true); - } + Level::Error => "error", + Level::Warning => "warning", + Level::Note => "note", + Level::Suggestions => "suggestions", } - spec } } diff --git a/kclvm/error/src/emitter.rs b/kclvm/error/src/emitter.rs deleted file mode 100644 index 2570864d1..000000000 --- a/kclvm/error/src/emitter.rs +++ /dev/null @@ -1,238 +0,0 @@ -use crate::{ - diagnostic::{Diagnostic, Style}, - DiagnosticId, Level, -}; - -use kclvm_span::{FilePathMapping, SourceMap}; -use std::sync::Arc; -use std::{ - io::{self, Write}, - path::Path, -}; -use termcolor::{BufferWriter, Color, ColorChoice, ColorSpec, StandardStream, WriteColor}; - -/// Emitter trait for emitting errors. -pub trait Emitter { - fn format_diagnostic(&mut self, diag: &Diagnostic) -> Vec; - /// Emit a structured diagnostic. - fn emit_diagnostic(&mut self, diag: &Diagnostic); - /// Checks if we can use colors in the current output stream. - fn supports_color(&self) -> bool { - false - } -} - -/// Emitter writer. -pub struct EmitterWriter { - dst: Destination, - short_message: bool, - source_map: Option>, -} - -impl Default for EmitterWriter { - fn default() -> Self { - Self { - dst: Destination::from_stderr(), - short_message: false, - source_map: None, - } - } -} - -impl EmitterWriter { - pub fn from_stderr(source_map: Arc) -> Self { - Self { - dst: Destination::from_stderr(), - short_message: false, - source_map: Some(source_map), - } - } -} - -/// Emit destinations -pub enum Destination { - Terminal(StandardStream), - Buffered(BufferWriter), - // The bool denotes whether we should be emitting ansi color codes or not - Raw(Box<(dyn Write + Send)>, bool), -} - -impl Destination { - #[allow(dead_code)] - pub fn from_raw(dst: Box, colored: bool) -> Self { - Destination::Raw(dst, colored) - } - - pub fn from_stderr() -> Self { - // On Windows we'll be performing global synchronization on the entire - // system for emitting rustc errors, so there's no need to buffer - // anything. - // - // On non-Windows we rely on the atomicity of `write` to ensure errors - // don't get all jumbled up. - if !cfg!(windows) { - Destination::Terminal(StandardStream::stderr(ColorChoice::Auto)) - } else { - Destination::Buffered(BufferWriter::stderr(ColorChoice::Auto)) - } - } - - fn supports_color(&self) -> bool { - match *self { - Self::Terminal(ref stream) => stream.supports_color(), - Self::Buffered(ref buffer) => buffer.buffer().supports_color(), - Self::Raw(_, supports_color) => supports_color, - } - } - - fn apply_style(&mut self, lvl: Level, style: Style) -> io::Result<()> { - let mut spec = ColorSpec::new(); - match style { - Style::Empty | Style::LineAndColumn => { - spec.set_bold(true); - spec = lvl.color(); - } - Style::Line => { - spec.set_bold(true); - spec.set_intense(true); - if cfg!(windows) { - spec.set_fg(Some(Color::Cyan)); - } else { - spec.set_fg(Some(Color::Blue)); - } - } - } - self.set_color(&spec) - } - - fn set_color(&mut self, color: &ColorSpec) -> io::Result<()> { - match *self { - Destination::Terminal(ref mut t) => t.set_color(color), - Destination::Buffered(ref mut t) => t.buffer().set_color(color), - Destination::Raw(_, _) => Ok(()), - } - } - - fn reset(&mut self) -> io::Result<()> { - match *self { - Destination::Terminal(ref mut t) => t.reset(), - Destination::Buffered(ref mut t) => t.buffer().reset(), - Destination::Raw(..) => Ok(()), - } - } -} - -impl<'a> Write for Destination { - fn write(&mut self, bytes: &[u8]) -> io::Result { - match *self { - Destination::Terminal(ref mut t) => t.write(bytes), - Destination::Buffered(ref mut t) => t.buffer().write(bytes), - Destination::Raw(ref mut t, _) => t.write(bytes), - } - } - - fn flush(&mut self) -> io::Result<()> { - match *self { - Destination::Terminal(ref mut t) => t.flush(), - Destination::Buffered(ref mut t) => t.buffer().flush(), - Destination::Raw(ref mut t, _) => t.flush(), - } - } -} - -impl Emitter for EmitterWriter { - fn supports_color(&self) -> bool { - self.dst.supports_color() - } - - fn emit_diagnostic(&mut self, diag: &Diagnostic) { - let buffer = self.format_diagnostic(diag); - if let Err(e) = emit_to_destination(&buffer, &diag.level, &mut self.dst, self.short_message) - { - panic!("failed to emit error: {}", e) - } - } - - fn format_diagnostic(&mut self, diag: &Diagnostic) -> Vec { - let mut buffer: Vec = vec![]; - let mut diag_str = "KCL ".to_string(); - diag_str += diag.level.to_str(); - if let Some(code) = &diag.code { - let code_str = match code { - DiagnosticId::Error(kind) => kind.name(), - DiagnosticId::Warning(warn_msg) => warn_msg.to_string(), - }; - diag_str += &format!(" [{}]", code_str); - } - buffer.push(diag_str); - for (i, msg) in diag.messages.iter().enumerate() { - buffer.push(" ".repeat(i) + &msg.pos.info()); - let mut line_source = format!("{} |", msg.pos.line); - let line_hint_len = line_source.len(); - if let Some(sm) = &self.source_map { - if let Some(source_file) = sm.source_file_by_filename(&msg.pos.filename) { - if let Some(line) = source_file.get_line(msg.pos.line as usize - 1) { - line_source += &line.to_string(); - } - } - } else { - let sm = SourceMap::new(FilePathMapping::empty()); - if let Ok(source_file) = sm.load_file(Path::new(&msg.pos.filename)) { - if let Some(line) = source_file.get_line(msg.pos.line as usize - 1) { - line_source += &line.to_string(); - } - } - } - buffer.push(" ".repeat(i) + &line_source); - if let Style::LineAndColumn = msg.style { - if let Some(column) = msg.pos.column { - let column = column + 1; - let column_source = format!("{} ^", column); - let prefix_space = line_hint_len + column as usize - column_source.len(); - let column_source = " ".repeat(prefix_space) + &column_source; - buffer.push(" ".repeat(i) + &column_source); - } - } - buffer.push(" ".repeat(i) + &msg.message.clone()); - if !self.short_message { - if let Some(note) = &msg.note { - buffer.push(" ".repeat(i) + &format!("Note: {}", note)); - } - } - buffer.push("".to_string()); - } - buffer - } -} - -fn emit_to_destination( - rendered_buffer: &[String], - lvl: &Level, - dst: &mut Destination, - short_message: bool, -) -> io::Result<()> { - // In order to prevent error message interleaving, where multiple error lines get intermixed - // when multiple compiler processes error simultaneously, we emit errors with additional - // steps. - // - // On Unix systems, we write into a buffered terminal rather than directly to a terminal. When - // the .flush() is called we take the buffer created from the buffered writes and write it at - // one shot. Because the Unix systems use ANSI for the colors, which is a text-based styling - // scheme, this buffered approach works and maintains the styling. - // - // On Windows, styling happens through calls to a terminal API. This prevents us from using the - // same buffering approach. Instead, we use a global Windows mutex, which we acquire long - // enough to output the full error message, then we release. - for (pos, line) in rendered_buffer.iter().enumerate() { - if line.starts_with("KCL") { - dst.apply_style(*lvl, Style::LineAndColumn)?; - } - write!(dst, "{}", line)?; - dst.reset()?; - if !short_message || pos != rendered_buffer.len() - 1 { - writeln!(dst)?; - } - } - dst.flush()?; - Ok(()) -} diff --git a/kclvm/error/src/error.rs b/kclvm/error/src/error.rs index b10c73d17..f6d5df5c5 100644 --- a/kclvm/error/src/error.rs +++ b/kclvm/error/src/error.rs @@ -18,16 +18,46 @@ macro_rules! register_errors { ) } +macro_rules! register_warnings { + ($($ecode:ident: $kind:expr, $message:expr,)*) => ( + pub static WARNINGS: &[(&str, Warning)] = &[ + $( (stringify!($ecode), Warning { + code: stringify!($ecode), + kind: $kind, + message: Some($message), + }), )* + ]; + $(pub const $ecode: Warning = Warning { + code: stringify!($ecode), + kind: $kind, + message: Some($message), + };)* + ) +} + // Error messages for EXXXX errors. Each message should start and end with a // new line. register_errors! { + // E1XXX Syntax Errors E1001: ErrorKind::InvalidSyntax, include_str!("./error_codes/E1001.md"), + E1002: ErrorKind::TabError, include_str!("./error_codes/E1002.md"), + E1003: ErrorKind::IndentationError, include_str!("./error_codes/E1003.md"), + E1I37: ErrorKind::IllegalArgumentSyntax, include_str!("./error_codes/E1I37.md"), + // E2XXX Compile Errors E2G22: ErrorKind::TypeError, include_str!("./error_codes/E2G22.md"), E2F04: ErrorKind::CannotFindModule, include_str!("./error_codes/E2F04.md"), E2L23: ErrorKind::CompileError, include_str!("./error_codes/E2L23.md"), E2A31: ErrorKind::IllegalAttributeError, include_str!("./error_codes/E2A31.md"), E2L28: ErrorKind::UniqueKeyError, include_str!("./error_codes/E2L28.md"), E2D34: ErrorKind::IllegalInheritError, include_str!("./error_codes/E2D34.md"), + // E3XXX Runtime Errors + E3M38: ErrorKind::EvaluationError, include_str!("./error_codes/E2D34.md"), +} + +// Error messages for WXXXX errors. Each message should start and end with a +// new line. +register_warnings! { + W1001: WarningKind::CompilerWarning, include_str!("./warning_codes/W1001.md"), } #[derive(Debug, Clone, PartialEq, Eq, Hash)] @@ -39,9 +69,12 @@ pub struct Error { #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub enum ErrorKind { + // Syntax Errors InvalidSyntax, TabError, - Indentation, + IndentationError, + IllegalArgumentSyntax, + // Compile Errors CannotFindModule, RecursiveLoad, FloatOverflow, @@ -59,6 +92,7 @@ pub enum ErrorKind { ValueError, KeyError, AttributeError, + // Runtime Errors AssertionError, ImmutableError, MultiInheritError, @@ -76,13 +110,106 @@ pub enum ErrorKind { impl std::fmt::Display for ErrorKind { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - write!(f, "{:?}", self) + write!(f, "{self:?}") } } impl ErrorKind { - #[allow(dead_code)] + /// Returns the error name. + pub fn name(&self) -> String { + format!("{self:?}") + } + /// Returns the error code. + pub fn code(&self) -> String { + match ERRORS.iter().find(|&error_pair| error_pair.1.kind == *self) { + Some(r) => r.0.to_string(), + None => E1001.code.to_string(), + } + } +} + +/// Warning information of KCL. Usually something that does not conform to the specification but does not cause an error. +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct Warning { + pub code: &'static str, + pub kind: WarningKind, + pub message: Option<&'static str>, +} + +// Kind of KCL warning. +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub enum WarningKind { + // Compile Warnings + CompilerWarning, + UnusedImportWarning, + ReimportWarning, + ImportPositionWarning, +} + +/// Test warning `fmt` +/// ``` +/// use kclvm_error::*; +/// use kclvm_error::DiagnosticId::Warning; +/// let mut handler = Handler::default(); +/// handler.add_warning(WarningKind::UnusedImportWarning, &[ +/// Message { +/// range: (Position::dummy_pos(), Position::dummy_pos()), +/// style: Style::LineAndColumn, +/// message: "Module 'a' imported but unused.".to_string(), +/// note: None, +/// suggested_replacement: None, +/// }], +/// ); +/// for diag in &handler.diagnostics { +/// if let Warning(warningkind) = diag.code.as_ref().unwrap() { +/// println!("{}",warningkind); +/// } +/// } +/// ``` +/// +impl std::fmt::Display for WarningKind { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(f, "{self:?}") + } +} + +/// Test warning `name` +/// ``` +/// use kclvm_error::*; +/// use kclvm_error::DiagnosticId::Warning; +/// let mut handler = Handler::default(); +/// handler.add_warning(WarningKind::UnusedImportWarning, &[ +/// Message { +/// range: (Position::dummy_pos(), Position::dummy_pos()), +/// style: Style::LineAndColumn, +/// message: "Module 'a' imported but unused.".to_string(), +/// note: None, +/// suggested_replacement: None, +/// }], +/// ); +/// for diag in &handler.diagnostics { +/// match diag.code.as_ref().unwrap() { +/// Warning(warningkind) => { +/// println!("{}",warningkind.name()); +/// } +/// _ => {} +/// } +/// +/// } +/// ``` +impl WarningKind { + /// Returns the warning name. pub fn name(&self) -> String { - return format!("{:?}", self); + format!("{self:?}") + } + /// Returns the warning code. + pub fn code(&self) -> String { + match WARNINGS + .iter() + .find(|&error_pair| error_pair.1.kind == *self) + { + Some(r) => r.0.to_string(), + None => W1001.code.to_string(), + } } } diff --git a/kclvm/error/src/error_codes/E1001.md b/kclvm/error/src/error_codes/E1001.md index 30c1ae3ca..60b9c6f42 100644 --- a/kclvm/error/src/error_codes/E1001.md +++ b/kclvm/error/src/error_codes/E1001.md @@ -1,9 +1,26 @@ +### InvalidSyntaxError (E1001) -This error indicates that the compiler syntax error has occurred. +KCL will report InvalidSyntaxError when KCL has a syntax error. -Erroneous code example: +The error code of InvalidSyntaxError is E1001. -```kcl,E1001 -x = f( - 7 ^ -> Expected one of ['all', 'any', 'bin_number', 'dec_number', '**', 'False', 'filter', 'float_number','hex_number', 'lambda', '{', '[', '(', 'long_string', 'not', 'map', '-', '*', 'name', 'None', '~', 'oct_number', '+',')', 'string', 'True', 'Undefined'] +For example: + +``` +a, b = 1, 2 # Multiple assign is illegal in KCL syntax ``` + +The KCL program will cause the following error message. + +```kcl,e1001 +error[E1001]: InvalidSyntax + --> /syntax_error/general/multiple_assign/case0/main.k:1:2 + | +1 | a, b = 1, 2 # Multiple assign is illegal in KCL syntax + | ^ expected statement + | +``` + +Possible resolution: + +Check and fix KCL syntax errors based on the KCL Language Standard diff --git a/kclvm/error/src/error_codes/E1002.md b/kclvm/error/src/error_codes/E1002.md new file mode 100644 index 000000000..41a437c40 --- /dev/null +++ b/kclvm/error/src/error_codes/E1002.md @@ -0,0 +1,29 @@ +### KCLTabError (E1002) + +KCL will report `KCLTabError` when KCL has a tab and white space syntax error. + +In KCL, it is forbidden to mix tabs and four spaces in one indentation block. And we recommend only using white spaces or tabs for indentation in the entire KCL project, don’t mix them. + +For example: + +```python +schema Person: + name: str # begin with a tab + age: int # begin with four white spaces, + # and four white spaces != tab in the env +``` + +The KCL program will cause the following error message. + +```shell +error[E1001]: InvalidSyntax + --> File /syntax_error/tab/tab_error_0/main.k:6:5 + | +3 | age: int = 1 + | ^ inconsistent use of tabs and spaces in indentation + | +``` + +Possible resolution: + +- Only use a tab or four white spaces in KCL, do not mix them. diff --git a/kclvm/error/src/error_codes/E1003.md b/kclvm/error/src/error_codes/E1003.md new file mode 100644 index 000000000..13b8625aa --- /dev/null +++ b/kclvm/error/src/error_codes/E1003.md @@ -0,0 +1,29 @@ +### IndentationError (E1003) + +KCL will report `KCLIndentationError` when KCL has an indentation syntax error. + +The KCL syntax includes indentation. A tab or four white spaces in KCL represents an indentation. The other cases will be regarded as syntax errors by KCL. + +For example: + +```python +schema Person: + name: str # a tab or four white spaces is legal. + age: int # three white spaces are illegal + info: str # two white spaces is illegal +``` + +The KCL program will cause the following error message. + +```shell +error[E1001]: InvalidSyntax + --> /syntax_error/indent/indent_error_0/main.k:3:4 + | +3 | age: int # three white spaces are illegal + | ^ unindent 3 does not match any outer indentation level + | +``` + +Possible resolution: + +- Only use a tab or four white spaces in the KCL program for indentation. diff --git a/kclvm/error/src/error_codes/E1I37.md b/kclvm/error/src/error_codes/E1I37.md new file mode 100644 index 000000000..298ec5846 --- /dev/null +++ b/kclvm/error/src/error_codes/E1I37.md @@ -0,0 +1,28 @@ +### IllegalArgumentSyntaxError (E1I37) + +KCL will report `IllegalArgumentSyntaxError` when KCL has an illegal argument in KCL syntax. + +For example: + +```python +# Parameters without default values +# must be in front of parameters with default values. +a = option(type="list", default={"key": "value"}, "key1") +``` + +The KCL program will cause the following error message. + +```shell +error[E1001]: InvalidSyntax + --> /option/type_convert_fail_2/main.k:3:57 + | +3 | a = option(type="list", default={"key": "value"}, "key1") + | ^ positional argument follows keyword argument + | +``` + +Possible resolution: + +```python +func(input_1, ..., input_n, param_with_key_1 = input_with_key_1, ..., param_with_key_n = input_with_key_n) +``` diff --git a/kclvm/error/src/error_codes/E2A31.md b/kclvm/error/src/error_codes/E2A31.md index 6d1d8dac2..9091357b2 100644 --- a/kclvm/error/src/error_codes/E2A31.md +++ b/kclvm/error/src/error_codes/E2A31.md @@ -4,8 +4,10 @@ This error indicates that the illegal attribute error has occurred. Erroneous code example: ```kcl,E2A31 -KCL Compile Error[E2A31] : Illegal attribute -1 |x = {None: None} - 6 ^ -> Failure -type 'NoneType' +error[E2A31]: IllegalAttributeError + --> /path/to/file.k:1:6 + | +1 | x = {None: None} + | ^ A attribute must be string type, got 'NoneType' + | ``` diff --git a/kclvm/error/src/error_codes/E2D34.md b/kclvm/error/src/error_codes/E2D34.md index 6ebda5fee..c1b2f2c4c 100644 --- a/kclvm/error/src/error_codes/E2D34.md +++ b/kclvm/error/src/error_codes/E2D34.md @@ -1,20 +1,30 @@ +### IllegalInheritError (E2D34) -This error indicates that invalid inheritance structure has occurred. +KCL will report `IllegalInheritError` when an illegal inheritance occurs in the schema. -Erroneous code example: +The `ewcode` of `IllegalInheritError` is `E2D34`. -```kcl +For example: + +```python schema FullnameMixin: fullName = "{} {}".format(firstName, lastName) -schema Scholar(FullnameMixin): +schema Scholar(FullnameMixin): # mixin inheritance is illegal school: str ``` -```kcl,E2D34 -KCL Complier Error[E2D34] : Illegal inheritance ----> File /schema/inherit/inherit_mixin_fail/main.k:8:1 -8 |schema Scholar(FullnameMixin): - 1 ^ -> Failure -mixin inheritance FullnameMixin is prohibited +The KCL program will cause the following error message. + +```shell +error[E2D34]: IllegalInheritError + --> /schema/inherit/inherit_mixin_fail/main.k:4:16 + | +4 | schema Scholar(FullnameMixin): + | ^ invalid schema inherit object type, expect schema, got 'FullnameMixin' + | ``` + +Possible resolution: + +- Schema supports single inheritance of schema in KCL. diff --git a/kclvm/error/src/error_codes/E2F04.md b/kclvm/error/src/error_codes/E2F04.md index 29f438dfd..4817d1c6e 100644 --- a/kclvm/error/src/error_codes/E2F04.md +++ b/kclvm/error/src/error_codes/E2F04.md @@ -1,10 +1,24 @@ +## CannotFindModule (E2F04) -This error indicates that the import module is not found. +KCL will report `CannotFindModule` when KCL imports a module that does not exist. -Erroneous code example: +The `ewcode` of `CannotFindModule` is `E2F04`. -```kcl,E2F04 -1 |import not_existed_pkg - 1 ^^^^^^^^^^^^^^^^^^^^^^ -> Failure -Cannot find the module not_existed_pkg from ./not_existed_pkg +For example: + +```python +import .some0.pkg1 as some00 # some0 not found in package + +Name1 = some00.Name # some0.pkg1.name ``` + +The KCL program will cause the following error message. + +```shell +error[E2F04]: CannotFindModule + --> import_abs_fail_0/app-main/main.k:1:1 + | +1 | import .some0.pkg1 as some00 # some0 not found in package + | Cannot find the module .some0.pkg1 + | +``` \ No newline at end of file diff --git a/kclvm/error/src/error_codes/E2G22.md b/kclvm/error/src/error_codes/E2G22.md index a5d79d0a0..c48127374 100644 --- a/kclvm/error/src/error_codes/E2G22.md +++ b/kclvm/error/src/error_codes/E2G22.md @@ -1,10 +1,35 @@ +### TypeError (E2G22) -This error indicates that the compiler type error has occurred. +KCL will report `TypeError` when a type error occurs in compiling type check. -Erroneous code example: +The `ewcode` of `TypeError` is `E2G22`. -```kcl,E2G22 -1 |a: int = "1" - 1 ^ -> got str(1) -expect int, got str(1) +For example: + +```python +schema Person: + firstName: str + lastName: int + +JohnDoe = Person { + "firstName": "John", + "lastName": "Doe" # Type Error,lastName: int,“Doe” is a string. +} +``` + +The KCL program will cause the following error message. + +```shell +error[E2G22]: TypeError + --> type/type_fail_0/main.k:7:5 + | +7 | "lastName": "Doe" # Type Error,lastName: int,“Doe” is a string. + | ^ expected int, got str(Doe) + | + + --> type/type_fail_0/main.k:3:5 + | +3 | lastName: int + | ^ variable is defined here, its type is int, but got str(Doe) + | ``` diff --git a/kclvm/error/src/error_codes/E2H13.md b/kclvm/error/src/error_codes/E2H13.md new file mode 100644 index 000000000..4c4908174 --- /dev/null +++ b/kclvm/error/src/error_codes/E2H13.md @@ -0,0 +1,34 @@ +### UnKnownDecoratorError (E2H13) + +KCL will report `UnKnownDecoratorError` when an unknown decorator is used in KCL. + +The `ewcode` of `UnKnownDecoratorError` is `E2H13`. + +For example: + +```python +@err_deprecated # It is an unknown decorator +schema Person: + firstName: str = "John" + lastName: str + name: str + +JohnDoe = Person { + name: "deprecated" +} +``` + +The KCL program will cause the following error message. + +```shell +error[E2L23]: CompileError + --> deprecated/unknown_fail_1/main.k:1:2 + | +1 | @err_deprecated # This is a error decorator + | ^ UnKnown decorator err_deprecated + | +``` + +Possible resolution: + +- Check whether the decorator exists. diff --git a/kclvm/error/src/error_codes/E2L28.md b/kclvm/error/src/error_codes/E2L28.md index d0c7cc8a2..9461f4a9b 100644 --- a/kclvm/error/src/error_codes/E2L28.md +++ b/kclvm/error/src/error_codes/E2L28.md @@ -1,21 +1,40 @@ +### UniqueKeyError (E2L28) -This error indicates that variables with the same name or duplicate definitions. +KCL will report `UniqueKeyError` when duplicate names appear in the KCL code. -Erroneous code example: +The `ewcode` of `UniqueKeyError` is `E2L28`. -```kcl +For example: + +```python schema Person: name: str = "kcl" age: int = 1 schema Person: aa: int + +x0 = Person{} +x1 = Person{age:101} ``` -```kcl,E2L28 -KCL Complier Error[E2L28] : Unique key error ----> File /schema/same_name/main.k:5:1 -5 |schema Person: - 1 ^ -> Failure -Variable name 'Person' must be unique in package context +The KCL program will cause the following error message. + +```shell +error[E2L28]: UniqueKeyError + --> /schema/same_name/main.k:5:8 + | +5 | schema Person: + | ^ Unique key error name 'Person' + | + + --> /schema/same_name/main.k:1:8 + | +1 | schema Person: + | ^ The variable 'Person' is declared here + | ``` + +Possible resolution: + +- Check if the name with error has been used. diff --git a/kclvm/error/src/error_codes/E3M38.md b/kclvm/error/src/error_codes/E3M38.md new file mode 100644 index 000000000..f6ade46e5 --- /dev/null +++ b/kclvm/error/src/error_codes/E3M38.md @@ -0,0 +1,9 @@ + +This error indicates that the runtime evaluation error has occurred. + +Erroneous code example: + +```kcl,E3M38 +1 |a = [][0] -> Failure +list index out of range +``` diff --git a/kclvm/error/src/lib.rs b/kclvm/error/src/lib.rs index 6cb2060cc..facd304db 100644 --- a/kclvm/error/src/lib.rs +++ b/kclvm/error/src/lib.rs @@ -3,66 +3,44 @@ //! //! We can use `Handler` to create and emit diagnostics. -use kclvm::{ErrType, PanicInfo}; - -#[macro_use] -pub mod bug; -mod diagnostic; -mod emitter; +pub mod diagnostic; mod error; -#[cfg(test)] -mod tests; -use std::sync::Arc; +use annotate_snippets::{ + display_list::DisplayList, + display_list::FormatOptions, + snippet::{AnnotationType, Slice, Snippet, SourceAnnotation}, +}; +use anyhow::Result; +use compiler_base_error::errors::ComponentFormatError; +use compiler_base_error::StyledBuffer; +use compiler_base_error::{ + components::{CodeSnippet, Label}, + Component, Diagnostic as DiagnosticTrait, DiagnosticStyle, +}; +use compiler_base_session::{Session, SessionDiagnostic}; +use compiler_base_span::{span::new_byte_pos, Span}; +use diagnostic::Range; +use indexmap::IndexSet; +use kclvm_runtime::PanicInfo; +use std::{any::Any, sync::Arc}; +use thiserror::Error; pub use diagnostic::{Diagnostic, DiagnosticId, Level, Message, Position, Style}; -pub use emitter::{Emitter, EmitterWriter}; pub use error::*; -use indexmap::IndexSet; -use kclvm_span::SourceMap; /// A handler deals with errors and other compiler output. /// Certain errors (error, bug) may cause immediate exit, /// others log errors for later reporting. -/// ```no_check -/// use kclvm_error::{Handler, Position, ParseError}; -/// let mut handler = Handler::default(); -/// handler.add_parse_error( -/// ParseError::unexpected_token(&["+", "-", "*", "/"], "//"), -/// Position::dummy_pos(), -/// ); -/// handler.abort_if_errors(); -/// ``` +#[derive(Clone, Debug, PartialEq, Eq, Default)] pub struct Handler { - /// The number of errors that have been emitted, including duplicates. - /// - /// This is not necessarily the count that's reported to the user once - /// compilation ends. - emitter: Box, pub diagnostics: IndexSet, } -impl Default for Handler { - fn default() -> Self { - Self { - emitter: Box::new(EmitterWriter::default()), - diagnostics: Default::default(), - } - } -} - impl Handler { /// New a handler using a emitter - pub fn new(emitter: Box) -> Self { - Self { - emitter, - diagnostics: Default::default(), - } - } - - pub fn with_source_map(source_map: Arc) -> Self { + pub fn new() -> Self { Self { - emitter: Box::new(EmitterWriter::from_stderr(source_map)), diagnostics: Default::default(), } } @@ -70,7 +48,7 @@ impl Handler { /// Panic program and report a bug #[inline] pub fn bug(&self, msg: &str) -> ! { - bug!("{}", msg) + compiler_base_macros::bug!("{}", msg) } #[inline] @@ -81,98 +59,66 @@ impl Handler { } /// Emit all diagnostics and return whether has errors. - pub fn emit(&mut self) -> bool { + pub fn emit(&mut self) -> Result { + let sess = Session::default(); for diag in &self.diagnostics { - self.emitter.emit_diagnostic(diag); + sess.add_err(diag.clone())?; } - self.has_errors() + sess.emit_stashed_diagnostics()?; + Ok(self.has_errors()) } - /// Format and return all diagnostics msg. - pub fn format_diagnostic(&mut self) -> Vec { - let mut dia_msgs = Vec::new(); + + /// Emit diagnostic to string. + pub fn emit_to_string(&mut self) -> Result { + let sess = Session::default(); for diag in &self.diagnostics { - dia_msgs.append(&mut self.emitter.format_diagnostic(diag)); + sess.add_err(diag.clone())?; } - dia_msgs - } - - /// Emit all diagnostics and abort if has any errors. - pub fn abort_if_errors(&mut self) -> ! { - if self.emit() { - std::process::exit(1) - } else { - panic!("compiler internal error") + let errors = sess.emit_all_diags_into_string()?; + let mut error_strings = vec![]; + for error in errors { + error_strings.push(error?); } + Ok(error_strings.join("\n")) } /// Emit all diagnostics and abort if has any errors. pub fn abort_if_any_errors(&mut self) { - if self.emit() { - std::process::exit(1) - } - } - - /// Emit all diagnostics but do not abort. - #[inline] - pub fn alert_if_any_errors(&mut self) { - if self.has_errors() { - for diag in &self.diagnostics { - let pos = diag.messages[0].pos.clone(); - let message = diag.messages[0].message.clone(); - - let mut panic_info = PanicInfo::default(); - - panic_info.__kcl_PanicInfo__ = true; - panic_info.message = message; - panic_info.err_type_code = ErrType::CompileError_TYPE as i32; - - panic_info.kcl_file = pos.filename.clone(); - panic_info.kcl_line = pos.line as i32; - panic_info.kcl_col = pos.column.unwrap_or(0) as i32; - - panic!("{}", panic_info.to_json_string()); + match self.emit() { + Ok(has_error) => { + if has_error { + std::process::exit(1); + } } + Err(err) => self.bug(&format!("{err}")), } } /// Construct a parse error and put it into the handler diagnostic buffer - pub fn add_syntex_error(&mut self, msg: &str, pos: Position) -> &mut Self { - let message = format!("Invalid syntax: {}", msg); + pub fn add_syntex_error(&mut self, msg: &str, range: Range) -> &mut Self { + let message = format!("Invalid syntax: {msg}"); let diag = Diagnostic::new_with_code( Level::Error, &message, - pos, + None, + range, Some(DiagnosticId::Error(E1001.kind)), + None, ); self.add_diagnostic(diag); self } - /// Construct a parse error and put it into the handler diagnostic buffer - pub fn add_parse_error(&mut self, err: ParseError, pos: Position) -> &mut Self { - match err { - ParseError::UnexpectedToken { expected, got } => { - let message = format!("expect {:?} got {}", expected, got); - let diag = Diagnostic::new_with_code( - Level::Error, - &message, - pos, - Some(DiagnosticId::Error(E1001.kind)), - ); - self.add_diagnostic(diag); - } - } - self - } - /// Construct a type error and put it into the handler diagnostic buffer - pub fn add_type_error(&mut self, msg: &str, pos: Position) -> &mut Self { + pub fn add_type_error(&mut self, msg: &str, range: Range) -> &mut Self { let diag = Diagnostic::new_with_code( Level::Error, msg, - pos, + None, + range, Some(DiagnosticId::Error(E2G22.kind)), + None, ); self.add_diagnostic(diag); @@ -180,28 +126,47 @@ impl Handler { } /// Construct a type error and put it into the handler diagnostic buffer - pub fn add_compile_error(&mut self, msg: &str, pos: Position) -> &mut Self { + pub fn add_compile_error(&mut self, msg: &str, range: Range) -> &mut Self { + self.add_compile_error_with_suggestions(msg, range, None) + } + + pub fn add_compile_error_with_suggestions( + &mut self, + msg: &str, + range: Range, + suggestions: Option>, + ) -> &mut Self { let diag = Diagnostic::new_with_code( Level::Error, msg, - pos, + None, + range, Some(DiagnosticId::Error(E2L23.kind)), + suggestions, ); self.add_diagnostic(diag); self } + /// Put a runtime panic info the handler diagnostic buffer. + pub fn add_panic_info(&mut self, panic_info: &PanicInfo) -> &mut Self { + self.add_diagnostic(panic_info.clone().into()); + + self + } + /// Add an error into the handler /// ``` /// use kclvm_error::*; /// let mut handler = Handler::default(); /// handler.add_error(ErrorKind::InvalidSyntax, &[ /// Message { - /// pos: Position::dummy_pos(), + /// range: (Position::dummy_pos(), Position::dummy_pos()), /// style: Style::LineAndColumn, /// message: "Invalid syntax: expected '+', got '-'".to_string(), /// note: None, + /// suggested_replacement: None, /// } /// ]); /// ``` @@ -216,51 +181,435 @@ impl Handler { self } - /// Store a diagnostics + pub fn add_suggestions(&mut self, msgs: Vec) -> &mut Self { + msgs.iter().for_each(|s| { + self.add_diagnostic(Diagnostic { + level: Level::Suggestions, + messages: vec![Message { + range: Range::default(), + style: Style::Line, + message: s.to_string(), + note: None, + suggested_replacement: None, + }], + code: Some(DiagnosticId::Suggestions), + }); + }); + + self + } + + /// Add an warning into the handler + /// ``` + /// use kclvm_error::*; + /// let mut handler = Handler::default(); + /// handler.add_warning(WarningKind::UnusedImportWarning, &[ + /// Message { + /// range: (Position::dummy_pos(), Position::dummy_pos()), + /// style: Style::LineAndColumn, + /// message: "Module 'a' imported but unused.".to_string(), + /// note: None, + /// suggested_replacement: None, + /// }], + /// ); + /// ``` + pub fn add_warning(&mut self, warning: WarningKind, msgs: &[Message]) -> &mut Self { + let diag = Diagnostic { + level: Level::Warning, + messages: msgs.to_owned(), + code: Some(DiagnosticId::Warning(warning)), + }; + self.add_diagnostic(diag); + + self + } + + /// Classify diagnostics into errors and warnings. + pub fn classification(&self) -> (IndexSet, IndexSet) { + let (mut errs, mut warnings) = (IndexSet::new(), IndexSet::new()); + for diag in &self.diagnostics { + if diag.level == Level::Error || diag.level == Level::Suggestions { + errs.insert(diag.clone()); + } else if diag.level == Level::Warning { + warnings.insert(diag.clone()); + } else { + continue; + } + } + (errs, warnings) + } + + /// Store a diagnostics into the handler. + /// + /// # Example + /// + /// ``` + /// use kclvm_error::*; + /// let mut handler = Handler::default(); + /// handler.add_diagnostic(Diagnostic::new_with_code(Level::Error, "error message", None, (Position::dummy_pos(), Position::dummy_pos()), Some(DiagnosticId::Error(E1001.kind)), None)); + /// ``` #[inline] - fn add_diagnostic(&mut self, diagnostic: Diagnostic) -> &mut Self { + pub fn add_diagnostic(&mut self, diagnostic: Diagnostic) -> &mut Self { self.diagnostics.insert(diagnostic); self } } +impl From for Diagnostic { + fn from(panic_info: PanicInfo) -> Self { + let panic_msg = if panic_info.kcl_arg_msg.is_empty() { + &panic_info.message + } else { + &panic_info.kcl_arg_msg + }; + + let mut diag = if panic_info.backtrace.is_empty() { + let pos = Position { + filename: panic_info.kcl_file.clone(), + line: panic_info.kcl_line as u64, + column: None, + }; + Diagnostic::new_with_code( + Level::Error, + panic_msg, + None, + (pos.clone(), pos), + None, + None, + ) + } else { + let mut backtrace_msg = "backtrace:\n".to_string(); + let mut backtrace = panic_info.backtrace.clone(); + backtrace.reverse(); + for (index, frame) in backtrace.iter().enumerate() { + backtrace_msg.push_str(&format!( + "\t{index}: {}\n\t\tat {}:{}", + frame.func, frame.file, frame.line + )); + if frame.col != 0 { + backtrace_msg.push_str(&format!(":{}", frame.col)) + } + backtrace_msg.push('\n') + } + let pos = Position { + filename: panic_info.kcl_file.clone(), + line: panic_info.kcl_line as u64, + column: None, + }; + Diagnostic::new_with_code( + Level::Error, + panic_msg, + Some(&backtrace_msg), + (pos.clone(), pos), + None, + None, + ) + }; + + if panic_info.kcl_config_meta_file.is_empty() { + return diag; + } + let pos = Position { + filename: panic_info.kcl_config_meta_file.clone(), + line: panic_info.kcl_config_meta_line as u64, + column: Some(panic_info.kcl_config_meta_col as u64), + }; + let mut config_meta_diag = Diagnostic::new_with_code( + Level::Error, + &panic_info.kcl_config_meta_arg_msg, + None, + (pos.clone(), pos), + None, + None, + ); + config_meta_diag.messages.append(&mut diag.messages); + config_meta_diag + } +} + +#[derive(Error, Debug, Clone)] +pub enum ParseErrorMessage { + #[error("invalid token '!', consider using 'not '")] + InvalidTokenNot, + #[error("'else if' here is invalid in KCL, consider using the 'elif' keyword")] + InvalidTokenElseIf, + #[error("unterminated string")] + UnterminatedString, + #[error("unexpected character after line continuation character")] + CharAfterLineContinuationToken, + #[error("the semicolon ';' here is unnecessary, please remove it")] + RedundantSemicolon, + #[error("expected expression, got {0}")] + ExpectExpr(String), + #[error("invalid string interpolation expression: '{0}'")] + InvalidStringInterpolationExpr(String), + #[error("invalid joined string spec without #")] + InvalidJoinedStringSpec, + #[error("invalid joined string")] + InvalidJoinedStringExpr, +} + #[derive(Debug, Clone)] pub enum ParseError { - UnexpectedToken { expected: Vec, got: String }, + UnexpectedToken { + expected: Vec, + got: String, + span: Span, + }, + Message { + message: ParseErrorMessage, + span: Span, + suggestions: Option>, + }, + String { + message: String, + span: Span, + }, } +/// A single string error. +pub struct StringError(pub String); + impl ParseError { - pub fn unexpected_token(expected: &[&str], got: &str) -> Self { + /// New a unexpected token parse error with span and token information. + pub fn unexpected_token(expected: &[&str], got: &str, span: Span) -> Self { ParseError::UnexpectedToken { expected: expected .iter() .map(|v| v.to_string()) .collect::>(), got: got.to_string(), + span, + } + } + + /// New a message parse error with span. + pub fn message( + message: ParseErrorMessage, + span: Span, + suggestions: Option>, + ) -> Self { + ParseError::Message { + message, + span, + suggestions, } } } -/// Used as a return value to signify a fatal error occurred. (It is also -/// used as the argument to panic at the moment, but that will eventually -/// not be true.) -#[derive(Copy, Clone, Debug)] -#[must_use] -pub struct FatalError; +impl ParseError { + /// Convert a parse error into an error diagnostic. + pub fn into_diag(self, sess: &Session) -> Result { + let span = match self { + ParseError::UnexpectedToken { span, .. } => span, + ParseError::Message { span, .. } => span, + ParseError::String { span, .. } => span, + }; + let start_pos = sess.sm.lookup_char_pos(span.lo()).into(); + let end_pos = sess.sm.lookup_char_pos(span.hi()).into(); + let suggestions = match &self { + ParseError::Message { suggestions, .. } => suggestions.clone(), + _ => None, + }; + Ok(Diagnostic::new_with_code( + Level::Error, + &self.to_string(), + None, + (start_pos, end_pos), + Some(DiagnosticId::Error(ErrorKind::InvalidSyntax)), + suggestions, + )) + } +} -pub struct FatalErrorMarker; +impl ToString for ParseError { + fn to_string(&self) -> String { + match self { + ParseError::UnexpectedToken { expected, got, .. } => { + format!("expected one of {expected:?} got {got}") + } + ParseError::Message { message, .. } => message.to_string(), + ParseError::String { message, .. } => message.to_string(), + } + } +} -impl FatalError { - pub fn raise(self) -> ! { - std::panic::panic_any(Box::new(FatalErrorMarker)) +impl SessionDiagnostic for ParseError { + fn into_diagnostic(self, sess: &Session) -> Result> { + let mut diag = DiagnosticTrait::::new(); + diag.append_component(Box::new(Label::Error(E1001.code.to_string()))); + diag.append_component(Box::new(": invalid syntax\n".to_string())); + match self { + ParseError::UnexpectedToken { span, .. } => { + let code_snippet = CodeSnippet::new(span, Arc::clone(&sess.sm)); + diag.append_component(Box::new(code_snippet)); + diag.append_component(Box::new(format!(" {}\n", self.to_string()))); + Ok(diag) + } + ParseError::Message { message, span, .. } => { + let code_snippet = CodeSnippet::new(span, Arc::clone(&sess.sm)); + diag.append_component(Box::new(code_snippet)); + diag.append_component(Box::new(format!(" {message}\n"))); + Ok(diag) + } + ParseError::String { message, span } => { + let code_snippet = CodeSnippet::new(span, Arc::clone(&sess.sm)); + diag.append_component(Box::new(code_snippet)); + diag.append_component(Box::new(format!(" {message}\n"))); + Ok(diag) + } + } } } -impl std::fmt::Display for FatalError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "fatal error") +#[derive(Default)] +pub struct SuggestionsLabel; + +impl Component for SuggestionsLabel { + fn format(&self, sb: &mut StyledBuffer, _: &mut Vec) { + sb.appendl("suggestion: ", Some(DiagnosticStyle::NeedAttention)); + } +} + +impl SessionDiagnostic for Diagnostic { + fn into_diagnostic(self, _: &Session) -> Result> { + let mut diag = DiagnosticTrait::::new(); + match self.code { + Some(id) => match id { + DiagnosticId::Error(error) => { + diag.append_component(Box::new(Label::Error(error.code()))); + diag.append_component(Box::new(format!(": {}\n", error.name()))); + } + DiagnosticId::Warning(warning) => { + diag.append_component(Box::new(Label::Warning(warning.code()))); + diag.append_component(Box::new(format!(": {}\n", warning.name()))); + } + DiagnosticId::Suggestions => { + diag.append_component(Box::new(SuggestionsLabel)); + } + }, + None => match self.level { + Level::Error => { + diag.append_component(Box::new(format!("{}\n", ErrorKind::EvaluationError))); + } + Level::Warning => { + diag.append_component(Box::new(format!("{}\n", WarningKind::CompilerWarning))); + } + Level::Note => { + diag.append_component(Box::new(Label::Note)); + } + Level::Suggestions => { + diag.append_component(Box::new(SuggestionsLabel)); + } + }, + } + for msg in &self.messages { + match Session::new_with_file_and_code(&msg.range.0.filename, None) { + Ok(sess) => { + let source = sess.sm.lookup_source_file(new_byte_pos(0)); + let line = source.get_line( + (if msg.range.0.line >= 1 { + msg.range.0.line - 1 + } else { + 0 + }) as usize, + ); + match line.as_ref() { + Some(content) => { + let length = content.chars().count(); + let snippet = Snippet { + title: None, + footer: vec![], + slices: vec![Slice { + source: content, + line_start: msg.range.0.line as usize, + origin: Some(&msg.range.0.filename), + annotations: vec![SourceAnnotation { + range: match msg.range.0.column { + Some(column) if length >= 1 => { + let column = column as usize; + // If the position exceeds the length of the content, + // put the annotation at the end of the line. + if column >= length { + (length - 1, length) + } else { + (column, column + 1) + } + } + _ => (0, 0), + }, + label: &msg.message, + annotation_type: AnnotationType::Error, + }], + fold: true, + }], + opt: FormatOptions { + color: true, + anonymized_line_numbers: false, + margin: None, + }, + }; + let dl = DisplayList::from(snippet); + diag.append_component(Box::new(format!("{dl}\n"))); + } + None => { + let info = msg.range.0.info(); + if !info.is_empty() { + diag.append_component(Box::new(format!( + "{}: {}\n", + info, msg.message + ))); + } else { + diag.append_component(Box::new(format!("{}\n", msg.message))); + } + } + }; + } + Err(_) => { + let info = msg.range.0.info(); + if !info.is_empty() { + diag.append_component(Box::new(format!("{}: {}\n", info, msg.message))); + } else { + diag.append_component(Box::new(format!("{}\n", msg.message))); + } + } + }; + if let Some(note) = &msg.note { + diag.append_component(Box::new(Label::Note)); + diag.append_component(Box::new(format!(": {note}\n"))); + } + // Append a new line. + diag.append_component(Box::new(String::from("\n"))); + } + Ok(diag) } } -impl std::error::Error for FatalError {} +impl SessionDiagnostic for StringError { + fn into_diagnostic(self, _: &Session) -> Result> { + let mut diag = DiagnosticTrait::::new(); + diag.append_component(Box::new(Label::Error(E3M38.code.to_string()))); + diag.append_component(Box::new(format!(": {}\n", self.0))); + Ok(diag) + } +} + +/// Convert an error to string. +/// +/// ``` +/// use kclvm_error::err_to_str; +/// +/// assert_eq!(err_to_str(Box::new("error_string".to_string())), "error_string"); +/// ``` +pub fn err_to_str(err: Box) -> String { + if let Some(s) = err.downcast_ref::<&str>() { + s.to_string() + } else if let Some(s) = err.downcast_ref::<&String>() { + (*s).clone() + } else if let Some(s) = err.downcast_ref::() { + (*s).clone() + } else { + "".to_string() + } +} diff --git a/kclvm/error/src/tests.rs b/kclvm/error/src/tests.rs deleted file mode 100644 index 7fd5b76ec..000000000 --- a/kclvm/error/src/tests.rs +++ /dev/null @@ -1,17 +0,0 @@ -use crate::*; - -#[test] -fn test_bug_macro() { - let result = std::panic::catch_unwind(|| { - bug!(); - }); - assert!(result.is_err()); - let result = std::panic::catch_unwind(|| { - bug!("an error msg"); - }); - assert!(result.is_err()); - let result = std::panic::catch_unwind(|| { - bug!("an error msg with string format {}", "msg"); - }); - assert!(result.is_err()); -} diff --git a/kclvm/error/src/warning_codes/W1001.md b/kclvm/error/src/warning_codes/W1001.md new file mode 100644 index 000000000..8f09bd85f --- /dev/null +++ b/kclvm/error/src/warning_codes/W1001.md @@ -0,0 +1 @@ +This warning indicates that the compiler warning has occurred. diff --git a/kclvm/evaluator/Cargo.toml b/kclvm/evaluator/Cargo.toml new file mode 100644 index 000000000..d4338b1cf --- /dev/null +++ b/kclvm/evaluator/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "kclvm-evaluator" +version = "0.11.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +indexmap = "1.0" +anyhow = "1.0" +generational-arena = "0.2.9" +kclvm-ast = {path = "../ast"} +kclvm-sema = {path = "../sema"} +kclvm-runtime = {path = "../runtime"} +kclvm-error = {path = "../error"} +scopeguard = "1.2.0" + +[dev-dependencies] +kclvm-parser = {path = "../parser"} +kclvm-loader = {path = "../loader"} +insta = "1.8.0" diff --git a/kclvm/evaluator/src/calculation.rs b/kclvm/evaluator/src/calculation.rs new file mode 100644 index 000000000..c526e632a --- /dev/null +++ b/kclvm/evaluator/src/calculation.rs @@ -0,0 +1,327 @@ +/* Calculation methods */ + +use kclvm_ast::ast; +use kclvm_runtime::{ConfigEntryOperationKind, DictValue, UnionOptions, Value, ValueRef}; + +use crate::ty::{resolve_schema, type_pack_and_check}; +use crate::union::union_entry; +use crate::Evaluator; + +impl<'ctx> Evaluator<'ctx> { + /// lhs + rhs + #[inline] + pub(crate) fn add(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef { + lhs.bin_add(&mut self.runtime_ctx.borrow_mut(), &rhs) + } + /// lhs - rhs + #[inline] + pub(crate) fn sub(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef { + lhs.bin_sub(&mut self.runtime_ctx.borrow_mut(), &rhs) + } + /// lhs * rhs + #[inline] + pub(crate) fn mul(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef { + lhs.bin_mul(&mut self.runtime_ctx.borrow_mut(), &rhs) + } + /// lhs / rhs + #[inline] + pub(crate) fn div(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef { + lhs.bin_div(&rhs) + } + /// lhs // rhs + #[inline] + pub(crate) fn floor_div(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef { + lhs.bin_floor_div(&rhs) + } + /// lhs % rhs + #[inline] + pub(crate) fn r#mod(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef { + lhs.bin_mod(&rhs) + } + /// lhs ** rhs + #[inline] + pub(crate) fn pow(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef { + lhs.bin_pow(&mut self.runtime_ctx.borrow_mut(), &rhs) + } + /// lhs << rhs + #[inline] + pub(crate) fn bit_lshift(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef { + lhs.bin_bit_lshift(&mut self.runtime_ctx.borrow_mut(), &rhs) + } + /// lhs >> rhs + #[inline] + pub(crate) fn bit_rshift(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef { + lhs.bin_bit_rshift(&mut self.runtime_ctx.borrow_mut(), &rhs) + } + /// lhs & rhs + #[inline] + pub(crate) fn bit_and(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef { + lhs.bin_bit_and(&rhs) + } + /// lhs | rhs + #[inline] + pub(crate) fn bit_or(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef { + if let (Value::int_value(a), Value::int_value(b)) = (&*lhs.rc.borrow(), &*rhs.rc.borrow()) { + return ValueRef::int(*a | *b); + }; + union_entry( + self, + &mut lhs.deep_copy(), + &rhs, + true, + &UnionOptions::default(), + ) + } + /// lhs ^ rhs + #[inline] + pub(crate) fn bit_xor(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef { + lhs.bin_bit_xor(&rhs) + } + /// lhs and rhs + #[inline] + pub(crate) fn logic_and(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef { + lhs.logic_and(&rhs).into() + } + /// lhs or rhs + #[inline] + pub(crate) fn logic_or(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef { + lhs.logic_or(&rhs).into() + } + /// lhs == rhs + #[inline] + pub(crate) fn cmp_equal_to(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef { + lhs.cmp_equal(&rhs).into() + } + /// lhs != rhs + #[inline] + pub(crate) fn cmp_not_equal_to(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef { + lhs.cmp_not_equal(&rhs).into() + } + /// lhs > rhs + #[inline] + pub(crate) fn cmp_greater_than(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef { + lhs.cmp_greater_than(&rhs).into() + } + /// lhs >= rhs + #[inline] + pub(crate) fn cmp_greater_than_or_equal(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef { + lhs.cmp_greater_than_or_equal(&rhs).into() + } + /// lhs < rhs + #[inline] + pub(crate) fn cmp_less_than(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef { + lhs.cmp_less_than(&rhs).into() + } + /// lhs <= rhs + #[inline] + pub(crate) fn cmp_less_than_or_equal(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef { + lhs.cmp_less_than_or_equal(&rhs).into() + } + /// lhs as rhs + #[inline] + pub(crate) fn r#as(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef { + type_pack_and_check(self, &lhs, vec![&rhs.as_str()], true) + } + /// lhs is rhs + #[inline] + pub(crate) fn is(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef { + (lhs == rhs).into() + } + /// lhs is not rhs + #[inline] + pub(crate) fn is_not(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef { + (lhs != rhs).into() + } + /// lhs in rhs + #[inline] + pub(crate) fn r#in(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef { + lhs.r#in(&rhs).into() + } + /// lhs not in rhs + #[inline] + pub(crate) fn not_in(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef { + lhs.not_in(&rhs).into() + } +} + +impl<'ctx> Evaluator<'ctx> { + /// Value is truth function, return i1 value. + #[inline] + pub(crate) fn value_is_truthy(&self, value: &ValueRef) -> bool { + value.is_truthy() + } + /// Value deep copy + #[inline] + pub(crate) fn value_deep_copy(&self, value: &ValueRef) -> ValueRef { + value.deep_copy() + } + /// value_union unions two collection elements. + pub(crate) fn value_union(&self, lhs: &mut ValueRef, rhs: &ValueRef) -> ValueRef { + let attr_map = match &*lhs.rc.borrow() { + Value::dict_value(dict) => dict.attr_map.clone(), + Value::schema_value(schema) => schema.config.attr_map.clone(), + _ => panic!("invalid object '{}' in attr_map", lhs.type_str()), + }; + let opts = UnionOptions { + list_override: false, + idempotent_check: false, + config_resolve: true, + }; + if rhs.is_config() { + let dict = rhs.as_dict_ref(); + for k in dict.values.keys() { + let entry = rhs.dict_get_entry(k).unwrap(); + union_entry(self, lhs, &entry, true, &opts); + // Has type annotation + if let Some(ty) = attr_map.get(k) { + let value = lhs.dict_get_value(k).unwrap(); + lhs.dict_update_key_value( + k, + type_pack_and_check(self, &value, vec![ty], false), + ); + } + } + lhs.clone() + } else { + union_entry(self, lhs, rhs, true, &opts) + } + } + /// Append a item into the list. + #[inline] + pub(crate) fn list_append(&self, list: &mut ValueRef, item: &ValueRef) { + list.list_append(item) + } + /// Append a list item and unpack it into the list. + #[inline] + pub(crate) fn list_append_unpack(&self, list: &mut ValueRef, item: &ValueRef) { + list.list_append_unpack(item) + } + #[inline] + pub(crate) fn dict_get_value(&self, dict: &ValueRef, key: &str) -> ValueRef { + dict.dict_get_value(key).unwrap_or(self.undefined_value()) + } + /// Insert a dict entry including key, value, op and insert_index into the dict, + /// and the type of key is `&str` + #[inline] + pub(crate) fn dict_insert( + &self, + dict: &mut ValueRef, + key: &str, + value: &ValueRef, + op: &ast::ConfigEntryOperation, + insert_index: Option, + ) { + let op = match op { + ast::ConfigEntryOperation::Union => ConfigEntryOperationKind::Union, + ast::ConfigEntryOperation::Override => ConfigEntryOperationKind::Override, + ast::ConfigEntryOperation::Insert => ConfigEntryOperationKind::Insert, + }; + self.dict_merge_key_value_pair(dict, key, value, op, insert_index, true); + } + + /// Insert a dict entry including key, value, op and insert_index into the dict, + /// and the type of key is `&str` + #[inline] + pub(crate) fn schema_dict_merge( + &self, + dict: &mut ValueRef, + key: &str, + value: &ValueRef, + op: &ast::ConfigEntryOperation, + insert_index: Option, + ) { + let op = match op { + ast::ConfigEntryOperation::Union => ConfigEntryOperationKind::Union, + ast::ConfigEntryOperation::Override => ConfigEntryOperationKind::Override, + ast::ConfigEntryOperation::Insert => ConfigEntryOperationKind::Insert, + }; + let attr_map = { + match &*dict.rc.borrow() { + Value::dict_value(dict) => dict.attr_map.clone(), + Value::schema_value(schema) => schema.config.attr_map.clone(), + _ => panic!("invalid object '{}' in attr_map", dict.type_str()), + } + }; + if attr_map.contains_key(key) { + let v = type_pack_and_check(self, value, vec![attr_map.get(key).unwrap()], false); + self.dict_merge_key_value_pair(dict, key, &v, op, insert_index, false); + } else { + self.dict_merge_key_value_pair(dict, key, value, op, insert_index, false); + } + } + + /// Insert an entry including key and value into the dict. + #[inline] + pub(crate) fn dict_insert_value(&self, dict: &mut ValueRef, key: &str, value: &ValueRef) { + dict.dict_update_key_value(key, value.clone()) + } + + /// Insert an entry including key and value into the dict, and merge the original entry. + #[inline] + pub(crate) fn dict_insert_merge_value(&self, dict: &mut ValueRef, key: &str, value: &ValueRef) { + self.dict_merge_key_value_pair( + dict, + key, + value, + ConfigEntryOperationKind::Union, + None, + true, + ); + } + + /// Set dict key with the value. When the dict is a schema and resolve schema validations. + pub(crate) fn dict_set_value(&self, p: &mut ValueRef, key: &str, val: &ValueRef) { + if p.is_config() { + p.dict_update_key_value(key, val.clone()); + if p.is_schema() { + let schema: ValueRef; + { + let schema_value = p.as_schema(); + let mut config_keys = schema_value.config_keys.clone(); + config_keys.push(key.to_string()); + schema = resolve_schema(self, p, &config_keys); + } + p.schema_update_with_schema(&schema); + } + } else { + panic!( + "failed to update the dict. An iterable of key-value pairs was expected, but got {}. Check if the syntax for updating the dictionary with the attribute '{}' is correct", + p.type_str(), + key + ); + } + } + + /// Private dict merge key value pair with the idempotent check option + pub(crate) fn dict_merge_key_value_pair( + &self, + p: &mut ValueRef, + key: &str, + v: &ValueRef, + op: ConfigEntryOperationKind, + insert_index: Option, + idempotent_check: bool, + ) { + if p.is_config() { + let mut dict: DictValue = Default::default(); + dict.values.insert(key.to_string(), v.clone()); + dict.ops.insert(key.to_string(), op); + if let Some(index) = insert_index { + dict.insert_indexs.insert(key.to_string(), index); + } + union_entry( + self, + p, + &ValueRef::from(Value::dict_value(Box::new(dict))), + true, + &UnionOptions { + config_resolve: false, + idempotent_check, + ..Default::default() + }, + ); + } else { + panic!("invalid dict insert value: {}", p.type_str()) + } + } +} diff --git a/kclvm/evaluator/src/context.rs b/kclvm/evaluator/src/context.rs new file mode 100644 index 000000000..2efa39898 --- /dev/null +++ b/kclvm/evaluator/src/context.rs @@ -0,0 +1,313 @@ +use std::{collections::HashSet, rc::Rc}; + +use generational_arena::Index; +use kclvm_ast::ast; +use kclvm_runtime::{BacktraceFrame, MAIN_PKG_PATH}; + +use crate::{ + error as kcl_error, + func::{FunctionCaller, FunctionEvalContextRef}, + lazy::{BacktrackMeta, Setter, SetterKind}, + proxy::{Frame, Proxy}, + rule::RuleCaller, + schema::SchemaCaller, + EvalContext, Evaluator, +}; + +impl<'ctx> Evaluator<'ctx> { + /// Current package path + #[inline] + pub(crate) fn current_pkgpath(&self) -> String { + self.pkgpath_stack + .borrow() + .last() + .expect(kcl_error::INTERNAL_ERROR_MSG) + .to_string() + } + + /// Last package path + #[inline] + pub(crate) fn last_pkgpath(&self) -> String { + let len = self.pkgpath_stack.borrow().len(); + self.pkgpath_stack + .borrow() + .get(if len > 2 { len - 2 } else { 2 - len }) + .unwrap_or(&MAIN_PKG_PATH.to_string()) + .to_string() + } + + /// Update current runtime context kcl filename and line + #[inline] + pub(crate) fn update_ctx_panic_info(&self, node: &'ctx ast::Node) { + let mut ctx = self.runtime_ctx.borrow_mut(); + ctx.panic_info.kcl_file = node.filename.clone(); + ctx.panic_info.kcl_line = node.line as i32; + } + + /// Update current AST index. + #[inline] + pub(crate) fn update_ast_id(&self, node: &'ctx ast::Node) { + *self.ast_id.borrow_mut() = node.id.clone(); + } + + /// Push a lambda definition scope into the lambda stack + #[inline] + pub fn push_lambda( + &self, + lambda_ctx: FunctionEvalContextRef, + current_pkgpath: &str, + frame_pkgpath: &str, + level: usize, + ) { + // Capture function schema this reference. + if let Some(this) = &lambda_ctx.this { + self.push_schema(this.eval_ctx()); + } + // Inner scope function calling. + // Note the minimum lambda.ctx.level is 2 for the top level lambda definitions. + if frame_pkgpath == current_pkgpath && level >= lambda_ctx.level { + // The scope cover is [lambda.ctx.level, self.scope_level()] + self.push_scope_cover(lambda_ctx.level, level); + } + self.lambda_stack.borrow_mut().push(lambda_ctx); + } + + /// Pop a lambda definition scope. + #[inline] + pub fn pop_lambda( + &self, + lambda_ctx: FunctionEvalContextRef, + current_pkgpath: &str, + frame_pkgpath: &str, + level: usize, + ) { + self.lambda_stack.borrow_mut().pop(); + // Inner scope function calling. + if frame_pkgpath == current_pkgpath && level >= lambda_ctx.level { + self.pop_scope_cover(); + } + // Release function schema this reference. + if lambda_ctx.this.is_some() { + self.pop_schema() + } + } + + #[inline] + pub fn is_in_lambda(&self) -> bool { + !self.lambda_stack.borrow().is_empty() + } + + #[inline] + pub fn last_lambda_ctx(&self) -> Option { + self.lambda_stack.borrow().last().cloned() + } + + #[inline] + pub fn push_schema(&self, v: EvalContext) { + self.schema_stack.borrow_mut().push(v); + } + + #[inline] + pub fn pop_schema(&self) { + self.schema_stack.borrow_mut().pop(); + } + + #[inline] + pub fn is_in_schema(&self) -> bool { + !self.schema_stack.borrow().is_empty() + } + + #[inline] + pub fn push_schema_expr(&self) { + self.schema_expr_stack.borrow_mut().push(()); + } + + #[inline] + pub fn pop_schema_expr(&self) { + self.schema_expr_stack.borrow_mut().pop(); + } + + #[inline] + pub fn is_in_schema_expr(&self) -> bool { + !self.schema_expr_stack.borrow().is_empty() + } + + #[inline] + pub fn add_local_var(&self, name: &str) { + self.local_vars.borrow_mut().insert(name.to_string()); + } + + #[inline] + pub fn remove_local_var(&self, name: &str) { + self.local_vars.borrow_mut().remove(name); + } + + #[inline] + pub fn is_local_var(&self, name: &str) -> bool { + self.local_vars.borrow().contains(name) + } + + #[inline] + pub(crate) fn clear_local_vars(&self) { + self.local_vars.borrow_mut().clear(); + } + + #[inline] + pub(crate) fn clean_and_cloned_local_vars(&self) -> HashSet { + let mut local_vars = self.local_vars.borrow_mut(); + let r = local_vars.clone(); + local_vars.clear(); + r + } + + #[inline] + pub(crate) fn set_local_vars(&self, vars: HashSet) { + self.local_vars.borrow_mut().extend(vars); + } + + #[inline] + pub(crate) fn add_target_var(&self, name: &str) { + self.target_vars.borrow_mut().push(name.to_string()); + } + + #[inline] + pub(crate) fn pop_target_var(&self) { + self.target_vars.borrow_mut().pop(); + } + + #[inline] + pub(crate) fn get_target_var(&self) -> String { + self.target_vars + .borrow() + .last() + .cloned() + .unwrap_or_default() + } + + #[inline] + pub(crate) fn check_imported(&self, pkgpath: &str) -> bool { + let imported = &mut self.imported.borrow_mut(); + imported.contains(pkgpath) + } + + #[inline] + pub(crate) fn mark_imported(&self, pkgpath: &str) { + let imported = &mut self.imported.borrow_mut(); + (*imported).insert(pkgpath.to_string()); + } + + #[inline] + pub(crate) fn push_pkgpath(&self, pkgpath: &str) { + self.pkgpath_stack.borrow_mut().push(pkgpath.to_string()); + self.runtime_ctx.borrow_mut().set_kcl_pkgpath(pkgpath); + } + + #[inline] + pub(crate) fn pop_pkgpath(&self) { + if let Some(pkgpath) = self.pkgpath_stack.borrow_mut().pop() { + self.runtime_ctx.borrow_mut().set_kcl_pkgpath(&pkgpath); + } + } + + /// Append a global body into the scope. + #[inline] + pub(crate) fn add_global_body(&self, index: usize) -> Index { + let pkgpath = self.current_pkgpath(); + self.frames.borrow_mut().insert(Rc::new(Frame { + pkgpath, + proxy: Proxy::Global(index), + })) + } + + /// Append a function into the scope. + #[inline] + pub(crate) fn add_function(&self, function: FunctionCaller) -> Index { + let pkgpath = self.current_pkgpath(); + self.frames.borrow_mut().insert(Rc::new(Frame { + pkgpath, + proxy: Proxy::Lambda(function), + })) + } + + /// Append a schema into the scope. + #[inline] + pub(crate) fn add_schema(&self, schema: SchemaCaller) -> Index { + let pkgpath = self.current_pkgpath(); + self.frames.borrow_mut().insert(Rc::new(Frame { + pkgpath, + proxy: Proxy::Schema(schema), + })) + } + + /// Append a rule into the scope. + #[inline] + pub(crate) fn add_rule(&self, rule: RuleCaller) -> Index { + let pkgpath = self.current_pkgpath(); + self.frames.borrow_mut().insert(Rc::new(Frame { + pkgpath, + proxy: Proxy::Rule(rule), + })) + } + + pub(crate) fn push_backtrace(&self, frame: &Frame) { + let ctx = &mut self.runtime_ctx.borrow_mut(); + if ctx.cfg.debug_mode { + let backtrace_frame = BacktraceFrame::from_panic_info(&ctx.panic_info); + ctx.backtrace.push(backtrace_frame); + ctx.panic_info.kcl_func = frame.proxy.get_name(); + } + } + + pub(crate) fn pop_backtrace(&self) { + let ctx = &mut self.runtime_ctx.borrow_mut(); + if ctx.cfg.debug_mode { + if let Some(backtrace_frame) = ctx.backtrace.pop() { + ctx.panic_info.kcl_func = backtrace_frame.func; + ctx.panic_info.kcl_line = backtrace_frame.line; + ctx.panic_info.kcl_file = backtrace_frame.file; + } + } + } + + #[inline] + pub(crate) fn push_backtrack_meta(&self, setter: &Setter) { + let meta = &mut self.backtrack_meta.borrow_mut(); + meta.push(BacktrackMeta { + stopped: setter.stopped.clone(), + is_break: false, + kind: setter.kind.clone(), + }); + } + + #[inline] + pub(crate) fn pop_backtrack_meta(&self) { + let meta = &mut self.backtrack_meta.borrow_mut(); + meta.pop(); + } + + #[inline] + pub(crate) fn is_backtrack_only_if(&self) -> bool { + let meta = &mut self.backtrack_meta.borrow_mut(); + match meta.last().map(|m| matches!(m.kind, SetterKind::If)) { + Some(r) => r, + None => false, + } + } + + #[inline] + pub(crate) fn is_backtrack_only_or_else(&self) -> bool { + let meta = &mut self.backtrack_meta.borrow_mut(); + match meta.last().map(|m| matches!(m.kind, SetterKind::OrElse)) { + Some(r) => r, + None => false, + } + } + + pub(crate) fn push_scope_cover(&self, start: usize, stop: usize) { + self.scope_covers.borrow_mut().push((start, stop)); + } + + pub(crate) fn pop_scope_cover(&self) { + self.scope_covers.borrow_mut().pop(); + } +} diff --git a/kclvm/evaluator/src/error.rs b/kclvm/evaluator/src/error.rs new file mode 100644 index 000000000..c274c51d9 --- /dev/null +++ b/kclvm/evaluator/src/error.rs @@ -0,0 +1,8 @@ +//! Copyright The KCL Authors. All rights reserved. + +pub(crate) const RUNTIME_ERROR_MSG: &str = "Runtime error"; +pub(crate) const INTERNAL_ERROR_MSG: &str = "Internal error, please report a bug to us"; +pub(crate) const INVALID_OPERATOR_MSG: &str = "Invalid operator"; +pub(crate) const INVALID_JOINED_STR_MSG: &str = "Invalid AST JoinedString value"; +pub(crate) const INVALID_STR_INTERPOLATION_SPEC_MSG: &str = + "Invalid string interpolation format specification"; diff --git a/kclvm/evaluator/src/func.rs b/kclvm/evaluator/src/func.rs new file mode 100644 index 000000000..47d2b26a4 --- /dev/null +++ b/kclvm/evaluator/src/func.rs @@ -0,0 +1,159 @@ +use std::fmt::Debug; +use std::sync::Arc; + +use generational_arena::Index; +use indexmap::IndexMap; +use kclvm_ast::ast; +use kclvm_runtime::ValueRef; +use scopeguard::defer; + +use crate::proxy::Proxy; +use crate::ty::type_pack_and_check; +use crate::Evaluator; +use crate::{error as kcl_error, EvalContext}; + +pub type FunctionHandler = + Arc ValueRef>; + +pub type ClosureMap = IndexMap; + +pub type FunctionEvalContextRef = Arc; + +#[derive(Clone)] +pub struct FunctionEvalContext { + /// AST node. + pub node: ast::LambdaExpr, + /// Captured schema or rule eval context. + pub this: Option, + /// Captured closure local variables. + pub closure: ClosureMap, + /// The scope level of the function definition. + pub level: usize, +} + +#[derive(Clone)] +pub struct FunctionEvalThis { + pub ctx: EvalContext, + pub value: ValueRef, + pub config: ValueRef, +} + +impl FunctionEvalThis { + #[inline] + pub fn eval_ctx(&self) -> EvalContext { + match &self.ctx { + EvalContext::Schema(schema_ctx) => EvalContext::Schema( + schema_ctx + .borrow() + .new_with_value(&self.value, &self.config), + ), + EvalContext::Rule(rule_ctx) => { + EvalContext::Rule(rule_ctx.borrow().new_with_value(&self.value, &self.config)) + } + } + } +} + +/// Proxy functions represent the saved functions of the runtime itself, +/// rather than executing KCL defined functions or plugin functions. +#[derive(Clone)] +pub struct FunctionCaller { + pub ctx: FunctionEvalContextRef, + pub body: FunctionHandler, +} + +impl Debug for FunctionCaller { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let ptr_value = Arc::as_ptr(&self.body); + f.debug_struct("FunctionProxy") + .field("inner", &format!("{ptr_value:p}")) + .finish() + } +} + +impl FunctionCaller { + #[inline] + pub fn new(ctx: FunctionEvalContext, proxy: FunctionHandler) -> Self { + Self { + ctx: Arc::new(ctx), + body: proxy, + } + } +} + +impl<'ctx> Evaluator<'ctx> { + #[inline] + pub(crate) fn invoke_proxy_function( + &'ctx self, + proxy_index: Index, + args: &ValueRef, + kwargs: &ValueRef, + ) -> ValueRef { + let frame = { + let frames = self.frames.borrow(); + frames + .get(proxy_index) + .expect(kcl_error::INTERNAL_ERROR_MSG) + .clone() + }; + // Change the package path scope. + self.push_pkgpath(&frame.pkgpath); + // Change the backtrace metadata: filename, line, etc. + self.push_backtrace(&frame); + defer! { + // Recover the backtrace metadata: filename, line, etc. + self.pop_backtrace(); + // Recover the package path scope. + self.pop_pkgpath(); + } + let value = match &frame.proxy { + // Call a function and return the value + Proxy::Lambda(lambda) => { + // Push the current lambda scope level in the lambda stack. + let pkgpath = self.current_pkgpath(); + let level = self.scope_level(); + self.push_lambda(lambda.ctx.clone(), &pkgpath, &frame.pkgpath, level); + let value = (lambda.body)(self, &lambda.ctx, args, kwargs); + self.pop_lambda(lambda.ctx.clone(), &pkgpath, &frame.pkgpath, level); + value + } + // Call a schema and return the schema value. + Proxy::Schema(schema) => (schema.body)( + self, + &schema + .ctx + .borrow() + .snapshot(self.dict_value(), self.dict_value()), + args, + kwargs, + ), + // Call a rule and return the rule value. + Proxy::Rule(rule) => (rule.body)(self, &rule.ctx, args, kwargs), + // The built-in lazy eval semantics prevent invoking + Proxy::Global(_) => self.undefined_value(), + }; + value + } +} + +/// Lambda function body +pub fn func_body( + s: &Evaluator, + ctx: &FunctionEvalContext, + args: &ValueRef, + kwargs: &ValueRef, +) -> ValueRef { + s.enter_scope(); + defer! { + s.leave_scope(); + } + // Evaluate arguments and keyword arguments and store values to local variables. + s.walk_arguments(&ctx.node.args, args, kwargs); + let mut result = s + .walk_stmts(&ctx.node.body) + .expect(kcl_error::RUNTIME_ERROR_MSG); + if let Some(ty) = &ctx.node.return_ty { + result = type_pack_and_check(s, &result, vec![&ty.node.to_string()], false); + } + result +} diff --git a/kclvm/evaluator/src/lazy.rs b/kclvm/evaluator/src/lazy.rs new file mode 100644 index 000000000..54b427f9e --- /dev/null +++ b/kclvm/evaluator/src/lazy.rs @@ -0,0 +1,392 @@ +use std::cell::RefCell; +use std::rc::Rc; + +use generational_arena::Index; +use indexmap::IndexMap; +use kclvm_ast::ast; +use kclvm_ast::ast::AstIndex; +use kclvm_runtime::ValueRef; + +use crate::error as kcl_error; +use crate::error::INTERNAL_ERROR_MSG; +use crate::Evaluator; +pub type LazyEvalScopeRef = Rc>; + +#[macro_export] +macro_rules! backtrack_break_here { + ($ctx: expr, $stmt: expr) => {{ + // If is break, do not execute the stmt and return immediately. + if let Some(meta) = $ctx.backtrack_meta.borrow().last() { + if meta.is_break { + return $ctx.ok_result(); + } + } + }}; +} + +#[macro_export] +macro_rules! backtrack_update_break { + ($ctx: expr, $stmt: expr) => {{ + // Check whether pass the breakpoint. + if let Some(meta) = $ctx.backtrack_meta.borrow_mut().last_mut() { + if let Some(stopped) = &meta.stopped { + if stopped == &$stmt.id { + meta.is_break = true + } + } + } + }}; +} + +/// LazyEvalScope represents a scope of sequentially independent calculations, where +/// the calculation of values is lazy and only recursively performed through +/// backtracking when needed. +#[derive(PartialEq, Clone, Default, Debug)] +pub struct LazyEvalScope { + /// Variable value cache. + pub cache: IndexMap, + /// Backtrack levels. + pub levels: IndexMap, + /// Variable setter function pointers. + pub setters: IndexMap>, + /// Calculate times without backtracking. + pub cal_times: IndexMap, +} + +impl LazyEvalScope { + #[inline] + pub fn is_backtracking(&self, key: &str) -> bool { + let level = self.levels.get(key).unwrap_or(&0); + *level > 0 + } + + #[inline] + pub fn setter_len(&self, key: &str) -> usize { + self.setters.get(key).unwrap_or(&vec![]).len() + } + + #[inline] + pub fn cal_increment(&mut self, key: &str) -> bool { + if self.is_backtracking(key) { + false + } else { + let cal_time = *self.cal_times.get(key).unwrap_or(&0); + let next_cal_time = cal_time + 1; + self.cal_times.insert(key.to_string(), next_cal_time); + next_cal_time >= self.setter_len(key) + } + } + + /// Whether the current target walker stmt index is the last setter stmt index. + #[inline] + pub fn is_last_setter_ast_index(&mut self, key: &str, id: &AstIndex) -> bool { + if self.is_backtracking(key) { + false + } else { + if let Some(setters) = self.setters.get(key) { + if let Some(s) = setters.last() { + if let Some(stopped) = &s.stopped { + stopped == id + } else { + &s.stmt_id == id + } + } else { + false + } + } else { + false + } + } + } +} + +/// Setter kind. +/// - If it is a normal kind, traverse all statements in the setter. +/// - If it is an if type, only traverse the if statement in the if stmt, skipping the else stmt. +/// - If it is an orelse type, only traverse the else statement, and make conditional judgments based on the inverse of the if stmt's cond. +#[derive(PartialEq, Clone, Default, Debug)] +pub enum SetterKind { + #[default] + Normal, + If, + OrElse, +} + +/// Setter function definition. +#[derive(PartialEq, Clone, Default, Debug)] +pub struct Setter { + /// Schema or body index, none denotes the current schema or body. + pub index: Option, + /// Statement index in the schema or body in the body array. + pub stmt: usize, + /// Statement AST index. + pub stmt_id: AstIndex, + /// If the statement is a if statement, stop the backtrack process at the stopped statement index. + pub stopped: Option, + /// Setter kind. + /// - If it is a normal kind, traverse all statements in the setter. + /// - If it is an if type, only traverse the if statement in the if stmt, skipping the else stmt. + /// - If it is an orelse type, only traverse the else statement, and make conditional judgments based on the inverse of the if stmt's cond. + pub kind: SetterKind, +} + +/// Merge setters and set the value with default undefined value. +pub(crate) fn merge_variables_and_setters( + v: &mut ValueRef, + s: &mut IndexMap>, + other: &IndexMap>, +) { + for (key, setters) in other { + if let Some(values) = s.get_mut(key) { + for setter in setters { + values.push(setter.clone()); + } + } else { + s.insert(key.to_string(), setters.clone()); + } + // Store a undefined value for the setter initial value to + // prevent self referencing. + if v.get_by_key(key).is_none() { + v.dict_update_key_value(key, ValueRef::undefined()); + } + } +} + +/// Merge setters and set the value with default undefined value. +pub(crate) fn merge_setters( + s: &mut IndexMap>, + other: &IndexMap>, +) { + for (key, setters) in other { + if let Some(values) = s.get_mut(key) { + for setter in setters { + values.push(setter.clone()); + } + } else { + s.insert(key.to_string(), setters.clone()); + } + } +} + +/// Schema or Global internal order independent computation +/// backtracking meta information. +#[derive(Debug, Default)] +pub struct BacktrackMeta { + pub stopped: Option, + pub is_break: bool, + pub kind: SetterKind, +} + +impl<'ctx> Evaluator<'ctx> { + /// Emit setter functions for the AST body. + /// Separate if statements with the same targets using the backtrack meta, such as + /// ```no_check + /// a = 1 + /// if True: + /// a = 1 + /// a += 1 # a = 2 instead of a = 3 + /// ``` + pub(crate) fn emit_setters( + &self, + body: &'ctx [Box>], + index: Option, + ) -> IndexMap> { + let mut body_map: IndexMap> = IndexMap::new(); + self.emit_setters_with(body, &mut body_map, false, &mut vec![], index); + body_map + } + + /// Emit setter functions for the AST body. + pub(crate) fn emit_setters_with( + &self, + body: &'ctx [Box>], + body_map: &mut IndexMap>, + is_in_if: bool, + in_if_names: &mut Vec<(String, AstIndex)>, + index: Option, + ) { + let add_stmt = |name: &str, + i: usize, + stmt_id: &AstIndex, + stopped: Option, + body_map: &mut IndexMap>, + kind: SetterKind| { + if !body_map.contains_key(name) { + body_map.insert(name.to_string(), vec![]); + } + let body_vec = body_map.get_mut(name).expect(kcl_error::INTERNAL_ERROR_MSG); + body_vec.push(Setter { + index, + stmt: i, + stmt_id: stmt_id.clone(), + stopped, + kind, + }); + }; + for (i, stmt) in body.iter().enumerate() { + match &stmt.node { + ast::Stmt::Unification(unification_stmt) => { + let name = &unification_stmt.target.node.names[0].node; + if is_in_if { + in_if_names.push((name.to_string(), stmt.id.clone())); + } else { + add_stmt(name, i, &stmt.id, None, body_map, SetterKind::Normal); + } + } + ast::Stmt::Assign(assign_stmt) => { + for target in &assign_stmt.targets { + let name = &target.node.name.node; + if is_in_if { + in_if_names.push((name.to_string(), stmt.id.clone())); + } else { + add_stmt(name, i, &stmt.id, None, body_map, SetterKind::Normal); + } + } + } + ast::Stmt::AugAssign(aug_assign_stmt) => { + let target = &aug_assign_stmt.target; + let name = &target.node.name.node; + if is_in_if { + in_if_names.push((name.to_string(), stmt.id.clone())); + } else { + add_stmt(name, i, &stmt.id, None, body_map, SetterKind::Normal); + } + } + ast::Stmt::If(if_stmt) => { + let mut if_names: Vec<(String, AstIndex)> = vec![]; + self.emit_setters_with(&if_stmt.body, body_map, true, &mut if_names, index); + if is_in_if { + for (name, id) in &if_names { + in_if_names.push((name.to_string(), id.clone())); + } + } else { + for (name, id) in &if_names { + add_stmt( + name, + i, + &stmt.id, + Some(id.clone()), + body_map, + SetterKind::If, + ); + } + } + let mut or_else_names: Vec<(String, AstIndex)> = vec![]; + self.emit_setters_with( + &if_stmt.orelse, + body_map, + true, + &mut or_else_names, + index, + ); + if is_in_if { + for (name, id) in &or_else_names { + in_if_names.push((name.to_string(), id.clone())); + } + } else { + for (name, id) in &or_else_names { + add_stmt( + name, + i, + &stmt.id, + Some(id.clone()), + body_map, + SetterKind::OrElse, + ); + } + } + } + ast::Stmt::SchemaAttr(schema_attr) => { + let name = schema_attr.name.node.as_str(); + if is_in_if { + in_if_names.push((name.to_string(), stmt.id.clone())); + } else { + add_stmt(name, i, &stmt.id, None, body_map, SetterKind::Normal); + } + } + _ => {} + } + } + } + + /// Get the value from the context. + pub(crate) fn get_value_from_lazy_scope( + &self, + pkgpath: &str, + key: &str, + target: &str, + default: ValueRef, + ) -> ValueRef { + // Deal in-place modify and return it self immediately. + if key == target && { + let lazy_scopes = self.lazy_scopes.borrow(); + let scope = lazy_scopes.get(pkgpath).expect(INTERNAL_ERROR_MSG); + !scope.is_backtracking(key) || scope.setter_len(key) <= 1 + } { + default + } else { + let cached_value = { + let lazy_scopes = self.lazy_scopes.borrow(); + let scope = lazy_scopes.get(pkgpath).expect(INTERNAL_ERROR_MSG); + scope.cache.get(key).cloned() + }; + match cached_value { + Some(value) => value.clone(), + None => { + let setters = { + let lazy_scopes = self.lazy_scopes.borrow(); + let scope = lazy_scopes.get(pkgpath).expect(INTERNAL_ERROR_MSG); + scope.setters.get(key).cloned() + }; + match &setters { + Some(setters) if !setters.is_empty() => { + // Call all setters function to calculate the value recursively. + let level = { + let lazy_scopes = self.lazy_scopes.borrow(); + let scope = lazy_scopes.get(pkgpath).expect(INTERNAL_ERROR_MSG); + *scope.levels.get(key).unwrap_or(&0) + }; + let next_level = level + 1; + { + let mut lazy_scopes = self.lazy_scopes.borrow_mut(); + let scope = lazy_scopes.get_mut(pkgpath).expect(INTERNAL_ERROR_MSG); + scope.levels.insert(key.to_string(), next_level); + } + let n = setters.len(); + let index = n - next_level; + if index >= n { + default + } else { + // Call setter function. + self.walk_stmts_with_setter(&setters[index]); + // Store cache value. + { + let value = self.get_variable_in_pkgpath(key, pkgpath); + let mut lazy_scopes = self.lazy_scopes.borrow_mut(); + let scope = + lazy_scopes.get_mut(pkgpath).expect(INTERNAL_ERROR_MSG); + scope.levels.insert(key.to_string(), level); + scope.cache.insert(key.to_string(), value.clone()); + value + } + } + } + _ => default, + } + } + } + } + } + + /// Set value to the context. + #[inline] + pub(crate) fn set_value_to_lazy_scope(&self, pkgpath: &str, key: &str, value: &ValueRef) { + let mut lazy_scopes = self.lazy_scopes.borrow_mut(); + let scope = lazy_scopes.get_mut(pkgpath).expect(INTERNAL_ERROR_MSG); + if (scope.cal_increment(key) || scope.is_last_setter_ast_index(key, &self.ast_id.borrow())) + && scope.cache.get(key).is_none() + { + scope.cache.insert(key.to_string(), value.clone()); + } + } +} diff --git a/kclvm/evaluator/src/lib.rs b/kclvm/evaluator/src/lib.rs new file mode 100644 index 000000000..983f02615 --- /dev/null +++ b/kclvm/evaluator/src/lib.rs @@ -0,0 +1,234 @@ +//! Copyright The KCL Authors. All rights reserved. + +#[cfg(test)] +mod tests; + +mod calculation; +mod context; +mod error; +mod func; +#[macro_use] +mod lazy; +mod module; +mod node; +mod proxy; +mod rule; +mod runtime; +mod schema; +mod scope; +mod ty; +mod union; +mod value; + +extern crate kclvm_error; + +use func::FunctionEvalContextRef; +use generational_arena::{Arena, Index}; +use indexmap::IndexMap; +use kclvm_runtime::val_plan::KCL_PRIVATE_VAR_PREFIX; +use lazy::{BacktrackMeta, LazyEvalScope}; +use proxy::{Frame, Proxy}; +use rule::RuleEvalContextRef; +use schema::SchemaEvalContextRef; +use scope::Scope; +use std::collections::{HashMap, HashSet}; +use std::panic::RefUnwindSafe; +use std::rc::Rc; +use std::str; +use std::{cell::RefCell, panic::UnwindSafe}; + +use crate::error as kcl_error; +use anyhow::Result; +use kclvm_ast::ast::{self, AstIndex}; +use kclvm_runtime::{Context, ValueRef}; + +/// SCALAR_KEY denotes the temp scalar key for the global variable json plan process. +const SCALAR_KEY: &str = ""; +/// Global level +const GLOBAL_LEVEL: usize = 1; +/// Inner level +const INNER_LEVEL: usize = 2; + +/// The evaluator function result +pub type EvalResult = Result; + +/// The evaluator for the program +pub struct Evaluator<'ctx> { + pub program: &'ctx ast::Program, + /// All frames including functions, schemas and rules + pub frames: RefCell>>, + /// All schema index in the package path, we can find the frame through the index. + pub schemas: RefCell>, + /// Runtime evaluation context. + pub runtime_ctx: Rc>, + /// Package path stack. + pub pkgpath_stack: RefCell>, + /// Filename stack. + pub filename_stack: RefCell>, + /// The names of possible assignment objects for the current instruction. + pub target_vars: RefCell>, + /// Imported package path set to judge is there a duplicate import. + pub imported: RefCell>, + /// The lambda stack index denotes the scope level of the lambda function. + pub lambda_stack: RefCell>, + /// To judge is in the schema statement. + pub schema_stack: RefCell>, + /// To judge is in the schema expression. + pub schema_expr_stack: RefCell>, + /// Import names mapping + pub import_names: RefCell>>, + /// Package scope to store variable values. + pub pkg_scopes: RefCell>>, + /// Package lazy scope to store variable cached values. + pub lazy_scopes: RefCell>, + /// Scope cover to block the acquisition of certain scopes. + pub scope_covers: RefCell>, + /// Local variables in the loop. + pub local_vars: RefCell>, + /// Schema attr backtrack meta. + pub backtrack_meta: RefCell>, + /// Current AST id for the evaluator walker. + pub ast_id: RefCell, +} + +#[derive(Clone)] +pub enum EvalContext { + Schema(SchemaEvalContextRef), + Rule(RuleEvalContextRef), +} + +impl EvalContext { + #[inline] + pub fn value(&self) -> ValueRef { + match self { + EvalContext::Schema(schema) => schema.borrow().value.clone(), + EvalContext::Rule(rule) => rule.borrow().value.clone(), + } + } + + #[inline] + pub fn config(&self) -> ValueRef { + match self { + EvalContext::Schema(schema) => schema.borrow().config.clone(), + EvalContext::Rule(rule) => rule.borrow().config.clone(), + } + } +} + +impl<'ctx> Evaluator<'ctx> { + /// New aa Evaluator using the AST program + #[inline] + pub fn new(program: &'ctx ast::Program) -> Evaluator<'ctx> { + Self::new_with_runtime_ctx(program, Rc::new(RefCell::new(Context::new()))) + } + + /// New aa Evaluator using the AST program and runtime context + #[inline] + pub fn new_with_runtime_ctx( + program: &'ctx ast::Program, + runtime_ctx: Rc>, + ) -> Evaluator<'ctx> { + Evaluator { + runtime_ctx, + program, + frames: RefCell::new(Arena::new()), + schemas: RefCell::new(IndexMap::new()), + target_vars: RefCell::new(vec![]), + lambda_stack: RefCell::new(vec![]), + imported: RefCell::new(Default::default()), + schema_stack: RefCell::new(Default::default()), + schema_expr_stack: RefCell::new(Default::default()), + pkgpath_stack: RefCell::new(vec![kclvm_ast::MAIN_PKG.to_string()]), + filename_stack: RefCell::new(Default::default()), + import_names: RefCell::new(Default::default()), + pkg_scopes: RefCell::new(Default::default()), + lazy_scopes: RefCell::new(Default::default()), + scope_covers: RefCell::new(Default::default()), + local_vars: RefCell::new(Default::default()), + backtrack_meta: RefCell::new(Default::default()), + ast_id: RefCell::new(AstIndex::default()), + } + } + + /// Evaluate the program and return the JSON and YAML result. + pub fn run(self: &Evaluator<'ctx>) -> Result<(String, String)> { + let modules = self.program.get_modules_for_pkg(kclvm_ast::MAIN_PKG); + self.init_scope(kclvm_ast::MAIN_PKG); + self.compile_ast_modules(&modules); + Ok(self.plan_globals_to_string()) + } + + /// Evaluate the program with the function mode and return the JSON and YAML result, + /// which means treating the files in the entire main package as a function run to + /// return the result of the function run, rather than a dictionary composed of each + /// configuration attribute. + pub fn run_as_function(self: &Evaluator<'ctx>) -> ValueRef { + let modules = self.program.get_modules_for_pkg(kclvm_ast::MAIN_PKG); + if modules.is_empty() { + ValueRef::undefined() + } else { + self.init_scope(kclvm_ast::MAIN_PKG); + self.compile_ast_modules(&modules) + } + } + + /// Plan globals to a planed json and yaml string. + pub(crate) fn plan_globals_to_string(&self) -> (String, String) { + let current_pkgpath = self.current_pkgpath(); + let pkg_scopes = &self.pkg_scopes.borrow(); + let scopes = pkg_scopes + .get(¤t_pkgpath) + .unwrap_or_else(|| panic!("pkgpath {} is not found", current_pkgpath)); + // The global scope. + let scope = scopes.last().expect(kcl_error::INTERNAL_ERROR_MSG); + let scalars = &scope.scalars; + let globals = &scope.variables; + // Construct a plan object. + let mut global_dict = self.dict_value(); + // Plan empty dict result. + if scalars.is_empty() && globals.is_empty() { + return self.plan_value(&global_dict); + } + // Deal scalars + for scalar in scalars.iter() { + self.dict_insert_merge_value(&mut global_dict, SCALAR_KEY, scalar); + } + // Deal global variables + for (name, value) in globals.iter() { + if name.starts_with(KCL_PRIVATE_VAR_PREFIX) + && !self.runtime_ctx.borrow().plan_opts.show_hidden + { + continue; + } + let mut value_dict = self.dict_value(); + self.dict_insert_merge_value(&mut value_dict, name.as_str(), value); + self.dict_insert_merge_value(&mut global_dict, SCALAR_KEY, &value_dict); + } + // Plan result to JSON and YAML string. + match global_dict.dict_get_value(SCALAR_KEY) { + Some(value) => self.plan_value(&value), + None => self.plan_value(&self.dict_value()), + } + } + + /// Get evaluator default ok result + #[inline] + pub fn ok_result(&self) -> EvalResult { + Ok(self.undefined_value()) + } + + pub fn plan_value(&self, value: &ValueRef) -> (String, String) { + let mut ctx = self.runtime_ctx.borrow_mut(); + let value = match ctx.buffer.custom_manifests_output.clone() { + Some(output) => ValueRef::from_yaml_stream(&mut ctx, &output).unwrap(), + None => value.clone(), + }; + let (json_string, yaml_string) = value.plan(&ctx); + ctx.json_result = json_string.clone(); + ctx.yaml_result = yaml_string.clone(); + (json_string, yaml_string) + } +} + +impl UnwindSafe for Evaluator<'_> {} +impl RefUnwindSafe for Evaluator<'_> {} diff --git a/kclvm/evaluator/src/module.rs b/kclvm/evaluator/src/module.rs new file mode 100644 index 000000000..61c24ca15 --- /dev/null +++ b/kclvm/evaluator/src/module.rs @@ -0,0 +1,108 @@ +// Copyright The KCL Authors. All rights reserved. + +use std::sync::{Arc, RwLock}; + +use kclvm_ast::ast; +use kclvm_ast::walker::TypedResultWalker; +use kclvm_runtime::ValueRef; + +use super::Evaluator; +use crate::error as kcl_error; + +impl<'ctx> Evaluator<'_> { + pub fn compile_module_import_and_types(&self, module: &'ctx ast::Module) { + for stmt in &module.body { + match &stmt.node { + ast::Stmt::Import(import_stmt) => { + self.walk_import_stmt(import_stmt) + .expect(kcl_error::RUNTIME_ERROR_MSG); + } + ast::Stmt::Schema(schema_stmt) => { + // Pre define global types with undefined values + self.predefine_global_types(&schema_stmt.name.node); + self.walk_schema_stmt(schema_stmt) + .expect(kcl_error::RUNTIME_ERROR_MSG); + } + ast::Stmt::Rule(rule_stmt) => { + // Pre define global types with undefined values + self.predefine_global_types(&rule_stmt.name.node); + self.walk_rule_stmt(rule_stmt) + .expect(kcl_error::RUNTIME_ERROR_MSG); + } + _ => {} + }; + } + } + + pub fn predefine_global_types(&self, name: &str) { + // Store or add the variable in the scope + let function = self.undefined_value(); + if !self.store_variable(name, function.clone()) { + self.add_variable(name, function); + } + } + + /// Predefine all global variables. + #[inline] + pub(crate) fn predefine_global_vars(&self, module: &'ctx ast::Module) { + self.emit_global_vars(&module.body); + } + + fn emit_global_vars(&self, body: &'ctx [Box>]) { + for stmt in body { + match &stmt.node { + ast::Stmt::Unification(unification_stmt) => { + let names = &unification_stmt.target.node.names; + if names.len() == 1 { + self.add_or_update_global_variable( + &names[0].node, + self.undefined_value(), + false, + ); + } + } + ast::Stmt::Assign(assign_stmt) => { + for target in &assign_stmt.targets { + self.add_or_update_global_variable( + &target.node.get_name(), + self.undefined_value(), + false, + ); + } + } + ast::Stmt::If(if_stmt) => { + self.emit_global_vars(&if_stmt.body); + self.emit_global_vars(&if_stmt.orelse); + } + _ => {} + } + } + } + + /// Compile AST Modules, which requires traversing three times. + /// 1. scan all possible global variables and allocate undefined values to global pointers. + /// 2. build all user-defined schema/rule types. + /// 3. evaluate all codes for the third time. + pub(crate) fn compile_ast_modules(&self, modules: &[Arc>]) -> ValueRef { + // Scan global variables + for ast_module in modules { + let ast_module = ast_module.read().expect("Failed to acquire module lock"); + // Pre define global variables with undefined values + self.predefine_global_vars(&ast_module); + } + // Scan global types + for ast_module in modules { + let ast_module = ast_module.read().expect("Failed to acquire module lock"); + self.compile_module_import_and_types(&ast_module); + } + let mut result = ValueRef::undefined(); + // Compile the ast module in the pkgpath. + for ast_module in modules { + let ast_module = ast_module.read().expect("Failed to acquire module lock"); + result = self + .walk_module(&ast_module) + .expect(kcl_error::RUNTIME_ERROR_MSG); + } + result + } +} diff --git a/kclvm/evaluator/src/node.rs b/kclvm/evaluator/src/node.rs new file mode 100644 index 000000000..3490e5c62 --- /dev/null +++ b/kclvm/evaluator/src/node.rs @@ -0,0 +1,1667 @@ +// Copyright The KCL Authors. All rights reserved. + +use std::cell::RefCell; +use std::rc::Rc; +use std::sync::{Arc, RwLock}; + +use anyhow::Ok; +use generational_arena::Index; +use kclvm_ast::ast::{self, CallExpr, ConfigEntry, Module, NodeRef}; +use kclvm_ast::walker::TypedResultWalker; +use kclvm_runtime::{ + schema_assert, schema_runtime_type, ConfigEntryOperationKind, DecoratorValue, RuntimeErrorType, + UnionOptions, ValueRef, PKG_PATH_PREFIX, +}; +use kclvm_sema::{builtin, pkgpath_without_prefix, plugin}; +use scopeguard::defer; + +use crate::error::INTERNAL_ERROR_MSG; +use crate::func::{func_body, FunctionCaller, FunctionEvalContext, FunctionEvalThis}; +use crate::lazy::Setter; +use crate::proxy::Proxy; +use crate::rule::{rule_body, rule_check, RuleCaller, RuleEvalContext}; +use crate::runtime::invoke_function; +use crate::schema::{schema_body, schema_check, SchemaCaller, SchemaEvalContext}; +use crate::ty::type_pack_and_check; +use crate::union::union_entry; +use crate::{backtrack_break_here, backtrack_update_break}; +use crate::{error as kcl_error, GLOBAL_LEVEL, INNER_LEVEL}; +use crate::{EvalResult, Evaluator}; + +/// Impl TypedResultWalker for Evaluator to visit AST nodes to evaluate the result. +impl<'ctx> TypedResultWalker<'ctx> for Evaluator<'ctx> { + type Result = EvalResult; + + /* + * Stmt + */ + + fn walk_stmt(&self, stmt: &'ctx ast::Node) -> Self::Result { + backtrack_break_here!(self, stmt); + self.update_ctx_panic_info(stmt); + self.update_ast_id(stmt); + let value = match &stmt.node { + ast::Stmt::TypeAlias(type_alias) => self.walk_type_alias_stmt(type_alias), + ast::Stmt::Expr(expr_stmt) => self.walk_expr_stmt(expr_stmt), + ast::Stmt::Unification(unification_stmt) => { + self.walk_unification_stmt(unification_stmt) + } + ast::Stmt::Assign(assign_stmt) => self.walk_assign_stmt(assign_stmt), + ast::Stmt::AugAssign(aug_assign_stmt) => self.walk_aug_assign_stmt(aug_assign_stmt), + ast::Stmt::Assert(assert_stmt) => self.walk_assert_stmt(assert_stmt), + ast::Stmt::If(if_stmt) => self.walk_if_stmt(if_stmt), + ast::Stmt::Import(import_stmt) => self.walk_import_stmt(import_stmt), + ast::Stmt::SchemaAttr(schema_attr) => self.walk_schema_attr(schema_attr), + ast::Stmt::Schema(schema_stmt) => self.walk_schema_stmt(schema_stmt), + ast::Stmt::Rule(rule_stmt) => self.walk_rule_stmt(rule_stmt), + }; + backtrack_update_break!(self, stmt); + value + } + + fn walk_expr_stmt(&self, expr_stmt: &'ctx ast::ExprStmt) -> Self::Result { + let mut result = self.ok_result(); + for expr in &expr_stmt.exprs { + let scalar = self.walk_expr(expr)?; + // Only non-call expressions are allowed to emit values because of the function void return type. + if !matches!(expr.node, ast::Expr::Call(_)) { + self.add_scalar(scalar.clone(), matches!(expr.node, ast::Expr::Schema(_))); + } + result = Ok(scalar); + } + result + } + + fn walk_unification_stmt(&self, unification_stmt: &'ctx ast::UnificationStmt) -> Self::Result { + self.clear_local_vars(); + let name = &unification_stmt.target.node.names[0].node; + self.add_target_var(name); + // The right value of the unification_stmt is a schema_expr. + let value = self.walk_schema_expr(&unification_stmt.value.node)?; + // Load the identifier value + let org_value = self + .walk_identifier_with_ctx(&unification_stmt.target.node, &ast::ExprContext::Load, None) + .unwrap_or(self.undefined_value()); + let value = self.bit_or(org_value, value); + // Store the identifier value + self.walk_identifier_with_ctx( + &unification_stmt.target.node, + &ast::ExprContext::Store, + Some(value.clone()), + )?; + self.pop_target_var(); + Ok(value) + } + + fn walk_type_alias_stmt(&self, _type_alias_stmt: &'ctx ast::TypeAliasStmt) -> Self::Result { + // Nothing to do, because all type aliases have been replaced at compile time + self.ok_result() + } + + fn walk_assign_stmt(&self, assign_stmt: &'ctx ast::AssignStmt) -> Self::Result { + self.clear_local_vars(); + // Set target vars. + for name in &assign_stmt.targets { + self.add_target_var(&name.node.name.node) + } + // Load the right value + let mut value = self.walk_expr(&assign_stmt.value)?; + // Runtime type cast if exists the type annotation. + if let Some(ty) = &assign_stmt.ty { + value = type_pack_and_check(self, &value, vec![&ty.node.to_string()], false); + } + if assign_stmt.targets.len() == 1 { + // Store the single target + let name = &assign_stmt.targets[0]; + self.walk_target_with_value(&name.node, value.clone())?; + } else { + // Store multiple targets + for name in &assign_stmt.targets { + let value = self.value_deep_copy(&value); + self.walk_target_with_value(&name.node, value.clone())?; + } + } + // Pop target vars. + for _ in &assign_stmt.targets { + self.pop_target_var(); + } + Ok(value) + } + + fn walk_aug_assign_stmt(&self, aug_assign_stmt: &'ctx ast::AugAssignStmt) -> Self::Result { + self.add_target_var(&aug_assign_stmt.target.node.name.node); + // Load the right value + let right_value = self.walk_expr(&aug_assign_stmt.value)?; + // Load the identifier value + let org_value = self.load_target(&aug_assign_stmt.target.node)?; + let value = match aug_assign_stmt.op { + ast::AugOp::Add => self.add(org_value, right_value), + ast::AugOp::Sub => self.sub(org_value, right_value), + ast::AugOp::Mul => self.mul(org_value, right_value), + ast::AugOp::Div => self.div(org_value, right_value), + ast::AugOp::Mod => self.r#mod(org_value, right_value), + ast::AugOp::Pow => self.pow(org_value, right_value), + ast::AugOp::LShift => self.bit_lshift(org_value, right_value), + ast::AugOp::RShift => self.bit_rshift(org_value, right_value), + ast::AugOp::BitOr => self.bit_or(org_value, right_value), + ast::AugOp::BitXor => self.bit_xor(org_value, right_value), + ast::AugOp::BitAnd => self.bit_and(org_value, right_value), + ast::AugOp::FloorDiv => self.floor_div(org_value, right_value), + ast::AugOp::Assign => { + return Err(anyhow::anyhow!(kcl_error::INVALID_OPERATOR_MSG)); + } + }; + // Store the target value + self.walk_target_with_value(&aug_assign_stmt.target.node, value.clone())?; + self.pop_target_var(); + Ok(value) + } + + fn walk_assert_stmt(&self, assert_stmt: &'ctx ast::AssertStmt) -> Self::Result { + let do_assert = || { + let assert_result = self + .walk_expr(&assert_stmt.test) + .expect(kcl_error::RUNTIME_ERROR_MSG); + // Assert statement error message. + let msg = { + if let Some(msg) = &assert_stmt.msg { + self.walk_expr(msg).expect(kcl_error::RUNTIME_ERROR_MSG) + } else { + self.string_value("") + } + }; + if !assert_result.is_truthy() { + let mut ctx = self.runtime_ctx.borrow_mut(); + ctx.set_err_type(&RuntimeErrorType::AssertionError); + let msg = msg.as_str(); + panic!("{}", msg); + } + }; + if let Some(if_cond) = &assert_stmt.if_cond { + let if_value = self.walk_expr(if_cond)?; + let is_truth = self.value_is_truthy(&if_value); + if is_truth { + do_assert() + } + } else { + do_assert() + } + self.ok_result() + } + + fn walk_if_stmt(&self, if_stmt: &'ctx ast::IfStmt) -> Self::Result { + let cond = self.walk_expr(&if_stmt.cond)?; + let is_truth = self.value_is_truthy(&cond); + // Is backtrack only orelse stmt? + if self.is_backtrack_only_or_else() { + if !is_truth { + self.walk_stmts(&if_stmt.orelse)?; + } + return self.ok_result(); + } + // Is backtrack only if stmt? + if self.is_backtrack_only_if() { + if is_truth { + self.walk_stmts(&if_stmt.body)?; + } + return self.ok_result(); + } + // Normal full if stmt. + if is_truth { + self.walk_stmts(&if_stmt.body)?; + } else { + self.walk_stmts(&if_stmt.orelse)?; + } + self.ok_result() + } + + fn walk_import_stmt(&self, import_stmt: &'ctx ast::ImportStmt) -> Self::Result { + let pkgpath = import_stmt.path.node.as_str(); + // Check if it has already been generated, there is no need to generate code + // for duplicate import statements. + if self.check_imported(pkgpath) { + return self.ok_result(); + } + // Standard or plugin modules. + if builtin::STANDARD_SYSTEM_MODULES.contains(&pkgpath) + || pkgpath.starts_with(plugin::PLUGIN_MODULE_PREFIX) + { + // Nothing to do on the builtin system module import because the check has been done. + return self.ok_result(); + } else { + let pkgpath = format!("{}{}", PKG_PATH_PREFIX, import_stmt.path.node); + if let Some(modules) = self.program.pkgs.get(&import_stmt.path.node) { + self.push_pkgpath(&pkgpath); + self.init_scope(&pkgpath); + let modules: Vec>> = modules + .iter() + .map(|m| { + let m = self + .program + .get_module_ref(&m) + .expect(&format!("module {:?} not found in program", m)); + m + }) + .collect(); + self.compile_ast_modules(&modules); + self.pop_pkgpath(); + } + } + self.mark_imported(pkgpath); + self.ok_result() + } + + fn walk_schema_stmt(&self, schema_stmt: &'ctx ast::SchemaStmt) -> Self::Result { + let body = Arc::new(schema_body); + let check = Arc::new(schema_check); + let caller = SchemaCaller { + ctx: Rc::new(RefCell::new(SchemaEvalContext::new_with_node( + schema_stmt.clone(), + Index::from_raw_parts(self.frames.borrow().len(), 0), + SchemaEvalContext::get_parent_schema(self, &schema_stmt.parent_name), + SchemaEvalContext::get_mixin_schemas(self, &schema_stmt.mixins), + ))), + body, + check, + }; + // Add function to the global state + let index = self.add_schema(caller); + let runtime_type = schema_runtime_type(&schema_stmt.name.node, &self.current_pkgpath()); + let function = self.proxy_function_value_with_type(index, &runtime_type); + // Store or add the variable in the scope + let name = &schema_stmt.name.node; + if !self.store_variable(name, function.clone()) { + self.add_variable(name, function.clone()); + } + self.schemas.borrow_mut().insert(runtime_type, index); + Ok(function) + } + + fn walk_rule_stmt(&self, rule_stmt: &'ctx ast::RuleStmt) -> Self::Result { + let body = Arc::new(rule_body); + let check = Arc::new(rule_check); + let caller = RuleCaller { + ctx: Rc::new(RefCell::new(RuleEvalContext::new_with_node( + rule_stmt.clone(), + ))), + body, + check, + }; + // Add function to the global state + let index = self.add_rule(caller); + let runtime_type = schema_runtime_type(&rule_stmt.name.node, &self.current_pkgpath()); + let function = self.proxy_function_value_with_type(index, &runtime_type); + // Store or add the variable in the scope + let name = &rule_stmt.name.node; + if !self.store_variable(name, function.clone()) { + self.add_variable(name, function.clone()); + } + Ok(function) + } + + /* + * Expr + */ + + fn walk_expr(&self, expr: &'ctx ast::Node) -> Self::Result { + self.update_ctx_panic_info(expr); + match &expr.node { + ast::Expr::Target(target) => self.walk_target(target), + ast::Expr::Identifier(identifier) => self.walk_identifier(identifier), + ast::Expr::Unary(unary_expr) => self.walk_unary_expr(unary_expr), + ast::Expr::Binary(binary_expr) => self.walk_binary_expr(binary_expr), + ast::Expr::If(if_expr) => self.walk_if_expr(if_expr), + ast::Expr::Selector(selector_expr) => self.walk_selector_expr(selector_expr), + ast::Expr::Call(call_expr) => self.walk_call_expr(call_expr), + ast::Expr::Paren(paren_expr) => self.walk_paren_expr(paren_expr), + ast::Expr::Quant(quant_expr) => self.walk_quant_expr(quant_expr), + ast::Expr::List(list_expr) => self.walk_list_expr(list_expr), + ast::Expr::ListIfItem(list_if_item_expr) => { + self.walk_list_if_item_expr(list_if_item_expr) + } + ast::Expr::ListComp(list_comp) => self.walk_list_comp(list_comp), + ast::Expr::Starred(starred_expr) => self.walk_starred_expr(starred_expr), + ast::Expr::DictComp(dict_comp) => self.walk_dict_comp(dict_comp), + ast::Expr::ConfigIfEntry(config_if_entry_expr) => { + self.walk_config_if_entry_expr(config_if_entry_expr) + } + ast::Expr::CompClause(comp_clause) => self.walk_comp_clause(comp_clause), + ast::Expr::Schema(schema_expr) => self.walk_schema_expr(schema_expr), + ast::Expr::Config(config_expr) => self.walk_config_expr(config_expr), + ast::Expr::Check(check) => self.walk_check_expr(check), + ast::Expr::Lambda(lambda) => self.walk_lambda_expr(lambda), + ast::Expr::Subscript(subscript) => self.walk_subscript(subscript), + ast::Expr::Keyword(keyword) => self.walk_keyword(keyword), + ast::Expr::Arguments(..) => self.ok_result(), + ast::Expr::Compare(compare) => self.walk_compare(compare), + ast::Expr::NumberLit(number_lit) => self.walk_number_lit(number_lit), + ast::Expr::StringLit(string_lit) => self.walk_string_lit(string_lit), + ast::Expr::NameConstantLit(name_constant_lit) => { + self.walk_name_constant_lit(name_constant_lit) + } + ast::Expr::JoinedString(joined_string) => self.walk_joined_string(joined_string), + ast::Expr::FormattedValue(formatted_value) => { + self.walk_formatted_value(formatted_value) + } + ast::Expr::Missing(missing_expr) => self.walk_missing_expr(missing_expr), + } + } + + fn walk_quant_expr(&self, quant_expr: &'ctx ast::QuantExpr) -> Self::Result { + let mut result = match quant_expr.op { + ast::QuantOperation::All => self.bool_value(true), + ast::QuantOperation::Any => self.bool_value(false), + ast::QuantOperation::Map => self.list_value(), + ast::QuantOperation::Filter => { + self.value_deep_copy(&self.walk_expr(&quant_expr.target)?) + } + }; + // Iterator + let iter_host_value = if let ast::QuantOperation::Filter = quant_expr.op { + self.value_deep_copy(&result) + } else { + self.walk_expr(&quant_expr.target)? + }; + let mut iter_value = iter_host_value.iter(); + // Start iteration and enter the loop scope for the loop variable. + self.enter_scope(); + defer! { + self.leave_scope(); + self.clear_local_vars(); + } + // Start block + while let Some((next_value, key, value)) = iter_value.next_with_key_value(&iter_host_value) + { + // Next value block + let variables = &quant_expr.variables; + for v in variables { + self.add_local_var(&v.node.names[0].node); + } + if variables.len() == 1 { + // Store the target + self.walk_identifier_with_ctx( + &variables.first().expect(kcl_error::INTERNAL_ERROR_MSG).node, + &ast::ExprContext::Store, + Some(next_value.clone()), + )?; + } else if variables.len() == 2 { + // Store the target + self.walk_identifier_with_ctx( + &variables.first().expect(kcl_error::INTERNAL_ERROR_MSG).node, + &ast::ExprContext::Store, + Some(key.clone()), + )?; + self.walk_identifier_with_ctx( + &variables.get(1).expect(kcl_error::INTERNAL_ERROR_MSG).node, + &ast::ExprContext::Store, + Some(value.clone()), + )?; + } else { + panic!( + "the number of loop variables is {}, which can only be 1 or 2", + variables.len() + ) + } + // Check the if filter condition + if let Some(if_expr) = &quant_expr.if_cond { + let value = self.walk_expr(if_expr)?; + // Skip the iteration + if !value.is_truthy() { + continue; + } + } + // Loop var generation body block + let test = &quant_expr.test; + let value = self.walk_expr(test)?; + let is_truth = self.value_is_truthy(&value); + match quant_expr.op { + ast::QuantOperation::All => { + if !is_truth { + return Ok(self.bool_value(false)); + } + } + ast::QuantOperation::Any => { + if is_truth { + return Ok(self.bool_value(true)); + } + } + ast::QuantOperation::Filter => { + if !is_truth { + if result.is_dict() { + result.dict_remove(&next_value.as_str()); + } else if result.is_list() { + result.list_remove(&next_value); + } else { + panic!("only list, dict and schema can be removed item"); + } + } + } + ast::QuantOperation::Map => { + self.list_append(&mut result, &value); + } + } + } + // End for block. + Ok(result) + } + + fn walk_schema_attr(&self, schema_attr: &'ctx ast::SchemaAttr) -> Self::Result { + self.clear_local_vars(); + let name = schema_attr.name.node.as_str(); + self.add_target_var(name); + for decorator in &schema_attr.decorators { + self.walk_decorator_with_name(&decorator.node, Some(name), false) + .expect(kcl_error::INTERNAL_ERROR_MSG); + } + let (mut schema_value, config_value, _) = self + .get_schema_or_rule_config_info() + .expect(kcl_error::INTERNAL_ERROR_MSG); + schema_value.update_attr_map(name, &schema_attr.ty.node.to_string()); + if let Some(entry) = config_value.dict_get_entry(name) { + let is_override_attr = { + let is_override_op = matches!( + config_value.dict_get_attr_operator(name), + Some(ConfigEntryOperationKind::Override) + ); + let without_index = matches!(config_value.dict_get_insert_index(name), None); + is_override_op && without_index + }; + if !is_override_attr { + let value = match &schema_attr.value { + Some(value) => self.walk_expr(value)?, + None => self.undefined_value(), + }; + if let Some(op) = &schema_attr.op { + match op { + // Union + ast::AugOp::BitOr => { + let org_value = schema_value + .dict_get_value(name) + .unwrap_or(self.undefined_value()); + let value = self.bit_or(org_value, value); + self.schema_dict_merge( + &mut schema_value, + name, + &value, + &ast::ConfigEntryOperation::Override, + None, + ); + } + // Assign + _ => self.schema_dict_merge( + &mut schema_value, + name, + &value, + &ast::ConfigEntryOperation::Override, + None, + ), + } + } + } + self.value_union(&mut schema_value, &entry); + } else { + // Lazy eval for the schema attribute. + let value = match &schema_attr.value { + Some(value) => self.walk_expr(value)?, + None => { + let value = self.undefined_value(); + // When the schema has no default value and config value, + // set it with a undefined value. + // Note that do not override the existed attribute value. + if schema_value.dict_get_entry(name).is_none() { + self.dict_insert_value(&mut schema_value, name, &value); + } + value + } + }; + if let Some(op) = &schema_attr.op { + match op { + // Union + ast::AugOp::BitOr => { + let org_value = schema_value + .dict_get_value(name) + .unwrap_or(self.undefined_value()); + let value = self.bit_or(org_value, value); + self.schema_dict_merge( + &mut schema_value, + name, + &value, + &ast::ConfigEntryOperation::Override, + None, + ); + } + // Assign + _ => self.schema_dict_merge( + &mut schema_value, + name, + &value, + &ast::ConfigEntryOperation::Override, + None, + ), + } + } + } + // Set config cache for the schema eval context. + if let Some(schema_ctx) = self.get_schema_eval_context() { + schema_ctx.borrow().set_value(self, name); + } + self.pop_target_var(); + Ok(schema_value) + } + + fn walk_if_expr(&self, if_expr: &'ctx ast::IfExpr) -> Self::Result { + let cond = self.walk_expr(&if_expr.cond)?; + let is_truth = self.value_is_truthy(&cond); + if is_truth { + self.walk_expr(&if_expr.body) + } else { + self.walk_expr(&if_expr.orelse) + } + } + + fn walk_unary_expr(&self, unary_expr: &'ctx ast::UnaryExpr) -> Self::Result { + let value = self.walk_expr(&unary_expr.operand)?; + Ok(match unary_expr.op { + ast::UnaryOp::UAdd => value.unary_plus(), + ast::UnaryOp::USub => value.unary_minus(), + ast::UnaryOp::Invert => value.unary_not(), + ast::UnaryOp::Not => value.unary_l_not(), + }) + } + + fn walk_binary_expr(&self, binary_expr: &'ctx ast::BinaryExpr) -> Self::Result { + let is_logic_op = matches!(binary_expr.op, ast::BinOp::And | ast::BinOp::Or); + let is_membership_as_op = matches!(binary_expr.op, ast::BinOp::As); + if !is_logic_op { + let left_value = self.walk_expr(&binary_expr.left)?; + let right_value = if is_membership_as_op { + match &binary_expr.right.node { + ast::Expr::Identifier(id) => { + let name = id.get_names().join("."); + self.string_value(&name) + } + _ => self.none_value(), + } + } else { + self.walk_expr(&binary_expr.right)? + }; + let value = match binary_expr.op { + ast::BinOp::Add => self.add(left_value, right_value), + ast::BinOp::Sub => self.sub(left_value, right_value), + ast::BinOp::Mul => self.mul(left_value, right_value), + ast::BinOp::Div => self.div(left_value, right_value), + ast::BinOp::FloorDiv => self.floor_div(left_value, right_value), + ast::BinOp::Mod => self.r#mod(left_value, right_value), + ast::BinOp::Pow => self.pow(left_value, right_value), + ast::BinOp::LShift => self.bit_lshift(left_value, right_value), + ast::BinOp::RShift => self.bit_rshift(left_value, right_value), + ast::BinOp::BitAnd => self.bit_and(left_value, right_value), + ast::BinOp::BitOr => self.bit_or(left_value, right_value), + ast::BinOp::BitXor => self.bit_xor(left_value, right_value), + ast::BinOp::And => self.logic_and(left_value, right_value), + ast::BinOp::Or => self.logic_or(left_value, right_value), + ast::BinOp::As => self.r#as(left_value, right_value), + }; + Ok(value) + } else { + // Short circuit operation of logical operators + let jump_if_false = matches!(binary_expr.op, ast::BinOp::And); + let left_value = self.walk_expr(&binary_expr.left)?; + let is_truth = self.value_is_truthy(&left_value); + if jump_if_false { + // Jump if false on logic and + if is_truth { + let right_value = self.walk_expr(&binary_expr.right)?; + return Ok(right_value); + } + } else { + // Jump if true on logic or + if !is_truth { + let right_value = self.walk_expr(&binary_expr.right)?; + return Ok(right_value); + } + }; + Ok(left_value) + } + } + + fn walk_selector_expr(&self, selector_expr: &'ctx ast::SelectorExpr) -> Self::Result { + let value = self.walk_expr(&selector_expr.value)?; + let key = selector_expr.attr.node.names[0].node.as_str(); + let mut value = if selector_expr.has_question { + if value.is_truthy() { + value.load_attr(key) + } else { + self.none_value() + } + } else { + value.load_attr(key) + }; + for name in &selector_expr.attr.node.names[1..] { + value = value.load_attr(&name.node) + } + Ok(value) + } + + fn walk_call_expr(&self, call_expr: &'ctx ast::CallExpr) -> Self::Result { + let func = self.walk_expr(&call_expr.func)?; + // args + let mut list_value = self.list_value(); + for arg in &call_expr.args { + let value = self.walk_expr(arg)?; + self.list_append(&mut list_value, &value); + } + let mut dict_value = self.dict_value(); + // keyword arguments + for keyword in &call_expr.keywords { + let name = &keyword.node.arg.node.names[0]; + let value = if let Some(value) = &keyword.node.value { + self.walk_expr(value)? + } else { + self.none_value() + }; + self.dict_insert_value(&mut dict_value, name.node.as_str(), &value); + } + let vars = self.clean_and_cloned_local_vars(); + let result = if let Some(proxy) = func.try_get_proxy() { + // Invoke user defined functions, schemas or rules. + Ok(self.invoke_proxy_function(proxy, &list_value, &dict_value)) + } else { + // Invoke runtime builtin functions or external plugin functions. + Ok(invoke_function(self, &func, &mut list_value, &dict_value)) + }; + self.set_local_vars(vars); + result + } + + fn walk_subscript(&self, subscript: &'ctx ast::Subscript) -> Self::Result { + let mut value = self.walk_expr(&subscript.value)?; + if let Some(index) = &subscript.index { + // index + let index = self.walk_expr(index)?; + value = if subscript.has_question { + value.bin_subscr_option(&index) + } else { + value.bin_subscr(&index) + }; + } else { + let lower = { + if let Some(lower) = &subscript.lower { + self.walk_expr(lower)? + } else { + self.none_value() + } + }; + let upper = { + if let Some(upper) = &subscript.upper { + self.walk_expr(upper)? + } else { + self.none_value() + } + }; + let step = { + if let Some(step) = &subscript.step { + self.walk_expr(step)? + } else { + self.none_value() + } + }; + value = if subscript.has_question { + if value.is_truthy() { + value.list_slice(&lower, &upper, &step) + } else { + self.none_value() + } + } else { + value.list_slice(&lower, &upper, &step) + }; + } + Ok(value) + } + + fn walk_paren_expr(&self, paren_expr: &'ctx ast::ParenExpr) -> Self::Result { + self.walk_expr(&paren_expr.expr) + } + + fn walk_list_expr(&self, list_expr: &'ctx ast::ListExpr) -> Self::Result { + let mut list_value = self.list_value(); + for item in &list_expr.elts { + let value = self.walk_expr(item)?; + match &item.node { + ast::Expr::Starred(_) | ast::Expr::ListIfItem(_) => { + self.list_append_unpack(&mut list_value, &value); + } + _ => self.list_append(&mut list_value, &value), + }; + } + Ok(list_value) + } + + fn walk_list_if_item_expr(&self, list_if_item_expr: &'ctx ast::ListIfItemExpr) -> Self::Result { + let cond = self.walk_expr(&list_if_item_expr.if_cond)?; + let is_truth = self.value_is_truthy(&cond); + Ok(if is_truth { + let mut then_value = self.list_value(); + for expr in &list_if_item_expr.exprs { + let value = self.walk_expr(expr)?; + match &expr.node { + ast::Expr::Starred(_) | ast::Expr::ListIfItem(_) => { + self.list_append_unpack(&mut then_value, &value) + } + _ => self.list_append(&mut then_value, &value), + }; + } + then_value + } else if let Some(orelse) = &list_if_item_expr.orelse { + self.walk_expr(orelse)? + } else { + self.none_value() + }) + } + + fn walk_starred_expr(&self, starred_expr: &'ctx ast::StarredExpr) -> Self::Result { + self.walk_expr(&starred_expr.value) + } + + fn walk_list_comp(&self, list_comp: &'ctx ast::ListComp) -> Self::Result { + let mut collection_value = self.list_value(); + self.enter_scope(); + defer! { + self.leave_scope(); + } + self.walk_generator( + &list_comp.generators, + &list_comp.elt, + None, + None, + 0, + &mut collection_value, + &ast::CompType::List, + ); + Ok(collection_value) + } + + fn walk_dict_comp(&self, dict_comp: &'ctx ast::DictComp) -> Self::Result { + let mut collection_value = self.dict_value(); + self.enter_scope(); + defer! { + self.leave_scope(); + } + let key = dict_comp + .entry + .key + .as_ref() + .expect(kcl_error::INTERNAL_ERROR_MSG); + self.walk_generator( + &dict_comp.generators, + key, + Some(&dict_comp.entry.value), + Some(&dict_comp.entry.operation), + 0, + &mut collection_value, + &ast::CompType::Dict, + ); + + Ok(collection_value) + } + + fn walk_config_if_entry_expr( + &self, + config_if_entry_expr: &'ctx ast::ConfigIfEntryExpr, + ) -> Self::Result { + let cond = self.walk_expr(&config_if_entry_expr.if_cond)?; + let is_truth = self.value_is_truthy(&cond); + Ok(if is_truth { + self.walk_config_entries(&config_if_entry_expr.items)? + } else if let Some(orelse) = &config_if_entry_expr.orelse { + // Config expr or config if entry expr. + if let ast::Expr::Config(config_expr) = &orelse.node { + self.walk_config_entries(&config_expr.items)? + } else { + self.walk_expr(orelse)? + } + } else { + self.none_value() + }) + } + + fn walk_comp_clause(&self, _comp_clause: &'ctx ast::CompClause) -> Self::Result { + // Nothing to do on this AST node + self.ok_result() + } + + fn walk_schema_expr(&self, schema_expr: &'ctx ast::SchemaExpr) -> Self::Result { + // Check the required attributes only when the values of all attributes + // in the final schema are solved. + self.push_schema_expr(); + defer! { + self.pop_schema_expr(); + } + let config_value = self.walk_expr(&schema_expr.config)?; + let schema_type = self.walk_identifier_with_ctx( + &schema_expr.name.node, + &schema_expr.name.node.ctx, + None, + )?; + let config_expr = match &schema_expr.config.node { + ast::Expr::Config(config_expr) => config_expr, + _ => panic!("invalid schema config expr"), + }; + let config_meta = self.construct_schema_config_meta(Some(&schema_expr.name), config_expr); + let mut list_value = self.list_value(); + for arg in &schema_expr.args { + let value = self.walk_expr(arg)?; + self.list_append(&mut list_value, &value); + } + let mut dict_value = self.dict_value(); + for keyword in &schema_expr.kwargs { + let name = &keyword.node.arg.node.names[0]; + let value = if let Some(value) = &keyword.node.value { + self.walk_expr(value)? + } else { + self.none_value() + }; + self.dict_insert_merge_value(&mut dict_value, name.node.as_str(), &value); + } + let schema = if let Some(index) = schema_type.try_get_proxy() { + let frame = { + let frames = self.frames.borrow(); + frames + .get(index) + .expect(kcl_error::INTERNAL_ERROR_MSG) + .clone() + }; + if let Proxy::Schema(schema) = &frame.proxy { + self.push_pkgpath(&frame.pkgpath); + self.push_backtrace(&frame); + defer! { + self.pop_backtrace(); + self.pop_pkgpath(); + } + let value = (schema.body)( + self, + &schema.ctx.borrow().snapshot(config_value, config_meta), + &list_value, + &dict_value, + ); + value + } else if let Proxy::Rule(rule) = &frame.proxy { + self.push_pkgpath(&frame.pkgpath); + self.push_backtrace(&frame); + defer! { + self.pop_backtrace(); + self.pop_pkgpath(); + } + let value = (rule.body)( + self, + &rule.ctx.borrow().snapshot(config_value, config_meta), + &list_value, + &dict_value, + ); + value + } else { + self.undefined_value() + } + } else { + union_entry( + self, + &mut schema_type.deep_copy(), + &config_value, + true, + &UnionOptions::default(), + ) + }; + Ok(schema) + } + + #[inline] + fn walk_config_expr(&self, config_expr: &'ctx ast::ConfigExpr) -> Self::Result { + self.enter_scope(); + defer! { + self.leave_scope(); + } + let result = self.walk_config_entries(&config_expr.items); + result + } + + fn walk_check_expr(&self, check_expr: &'ctx ast::CheckExpr) -> Self::Result { + if let Some(if_cond) = &check_expr.if_cond { + let if_value = self.walk_expr(if_cond)?; + let is_truth = self.value_is_truthy(&if_value); + if !is_truth { + return self.ok_result(); + } + } + let check_result = self.walk_expr(&check_expr.test)?; + let msg = { + if let Some(msg) = &check_expr.msg { + self.walk_expr(msg).expect(kcl_error::INTERNAL_ERROR_MSG) + } else { + self.string_value("") + } + } + .as_str(); + let (_, _, config_meta) = self + .get_schema_or_rule_config_info() + .expect(kcl_error::INTERNAL_ERROR_MSG); + schema_assert( + &mut self.runtime_ctx.borrow_mut(), + &check_result, + &msg, + &config_meta, + ); + self.ok_result() + } + + fn walk_lambda_expr(&self, lambda_expr: &'ctx ast::LambdaExpr) -> Self::Result { + let func = Arc::new(func_body); + // Capture schema self + let proxy = FunctionCaller::new( + FunctionEvalContext { + node: lambda_expr.clone(), + this: self + .schema_stack + .borrow() + .last() + .map(|ctx| FunctionEvalThis { + ctx: ctx.clone(), + value: ctx.value(), + config: ctx.config(), + }), + closure: self.get_current_closure_map(), + level: self.scope_level() + 1, + }, + func, + ); + // Add function to the global state + let index = self.add_function(proxy); + Ok(self.proxy_function_value(index)) + } + + fn walk_keyword(&self, _keyword: &'ctx ast::Keyword) -> Self::Result { + // Nothing to do + self.ok_result() + } + + fn walk_arguments(&self, _arguments: &'ctx ast::Arguments) -> Self::Result { + // Nothing to do + self.ok_result() + } + + fn walk_compare(&self, compare: &'ctx ast::Compare) -> Self::Result { + let mut left_value = self.walk_expr(&compare.left)?; + if compare.comparators.len() > 1 { + let mut result_value = self.undefined_value(); + for (i, op) in compare.ops.iter().enumerate() { + let has_next = i < (compare.ops.len() - 1); + let right_value = self.walk_expr(&compare.comparators[i])?; + result_value = match op { + ast::CmpOp::Eq => self.cmp_equal_to(left_value, right_value.clone()), + ast::CmpOp::NotEq => self.cmp_not_equal_to(left_value, right_value.clone()), + ast::CmpOp::Gt => self.cmp_greater_than(left_value, right_value.clone()), + ast::CmpOp::GtE => { + self.cmp_greater_than_or_equal(left_value, right_value.clone()) + } + ast::CmpOp::Lt => self.cmp_less_than(left_value, right_value.clone()), + ast::CmpOp::LtE => self.cmp_less_than_or_equal(left_value, right_value.clone()), + ast::CmpOp::Is => self.is(left_value, right_value.clone()), + ast::CmpOp::IsNot => self.is_not(left_value, right_value.clone()), + ast::CmpOp::Not => self.is_not(left_value, right_value.clone()), + ast::CmpOp::NotIn => self.not_in(left_value, right_value.clone()), + ast::CmpOp::In => self.r#in(left_value, right_value.clone()), + }; + left_value = right_value; + let is_truth = self.value_is_truthy(&result_value); + if has_next { + if !is_truth { + break; + } + } else { + break; + } + } + Ok(result_value) + } else { + let right_value = self.walk_expr(&compare.comparators[0])?; + Ok(match &compare.ops[0] { + ast::CmpOp::Eq => self.cmp_equal_to(left_value, right_value), + ast::CmpOp::NotEq => self.cmp_not_equal_to(left_value, right_value), + ast::CmpOp::Gt => self.cmp_greater_than(left_value, right_value), + ast::CmpOp::GtE => self.cmp_greater_than_or_equal(left_value, right_value), + ast::CmpOp::Lt => self.cmp_less_than(left_value, right_value), + ast::CmpOp::LtE => self.cmp_less_than_or_equal(left_value, right_value), + ast::CmpOp::Is => self.is(left_value, right_value), + ast::CmpOp::IsNot => self.is_not(left_value, right_value), + ast::CmpOp::Not => self.is_not(left_value, right_value), + ast::CmpOp::NotIn => self.not_in(left_value, right_value), + ast::CmpOp::In => self.r#in(left_value, right_value), + }) + } + } + + #[inline] + fn walk_identifier(&self, identifier: &'ctx ast::Identifier) -> Self::Result { + self.walk_identifier_with_ctx(identifier, &identifier.ctx, None) + } + + #[inline] + fn walk_target(&self, target: &'ctx ast::Target) -> Self::Result { + self.load_target(target) + } + + fn walk_number_lit(&self, number_lit: &'ctx ast::NumberLit) -> Self::Result { + match number_lit.value { + ast::NumberLitValue::Int(int_value) => match &number_lit.binary_suffix { + Some(binary_suffix) => { + let unit = binary_suffix.value(); + let value = kclvm_runtime::cal_num(int_value, unit.as_str()); + Ok(self.unit_value(value, int_value, &unit)) + } + None => Ok(self.int_value(int_value)), + }, + ast::NumberLitValue::Float(float_value) => Ok(self.float_value(float_value)), + } + } + + #[inline] + fn walk_string_lit(&self, string_lit: &'ctx ast::StringLit) -> Self::Result { + Ok(ValueRef::str(string_lit.value.as_str())) + } + + #[inline] + fn walk_name_constant_lit( + &self, + name_constant_lit: &'ctx ast::NameConstantLit, + ) -> Self::Result { + match name_constant_lit.value { + ast::NameConstant::True => Ok(self.bool_value(true)), + ast::NameConstant::False => Ok(self.bool_value(false)), + ast::NameConstant::None => Ok(self.none_value()), + ast::NameConstant::Undefined => Ok(self.undefined_value()), + } + } + + fn walk_joined_string(&self, joined_string: &'ctx ast::JoinedString) -> Self::Result { + let mut result_value = self.string_value(""); + for value in &joined_string.values { + let value = &value.node; + let value = match value { + ast::Expr::FormattedValue(formatted_value) => self + .walk_formatted_value(formatted_value) + .expect(kcl_error::INTERNAL_ERROR_MSG), + ast::Expr::StringLit(string_lit) => self + .walk_string_lit(string_lit) + .expect(kcl_error::INTERNAL_ERROR_MSG), + _ => panic!("{}", kcl_error::INVALID_JOINED_STR_MSG), + }; + result_value = self.add(result_value, value) + } + Ok(result_value) + } + + fn walk_formatted_value(&self, formatted_value: &'ctx ast::FormattedValue) -> Self::Result { + let formatted_expr_value = self.walk_expr(&formatted_value.value)?; + let value = if let Some(spec) = &formatted_value.format_spec { + match spec.to_lowercase().as_str() { + "#json" => formatted_expr_value.to_json_string(), + "#yaml" => formatted_expr_value.to_yaml_string(), + _ => panic!("{}", kcl_error::INVALID_STR_INTERPOLATION_SPEC_MSG), + } + } else { + formatted_expr_value.to_string() + }; + Ok(ValueRef::str(&value)) + } + + fn walk_comment(&self, _comment: &'ctx ast::Comment) -> Self::Result { + // Nothing to do + self.ok_result() + } + + fn walk_missing_expr(&self, _missing_expr: &'ctx ast::MissingExpr) -> Self::Result { + Err(anyhow::anyhow!("compile error: missing expression",)) + } + + fn walk_module(&self, module: &'ctx ast::Module) -> Self::Result { + // Compile all statements of the module except all import statements + self.walk_stmts_except_import(&module.body) + } +} + +impl<'ctx> Evaluator<'ctx> { + pub fn walk_stmts_except_import(&self, stmts: &'ctx [Box>]) -> EvalResult { + let mut result = self.ok_result(); + for stmt in stmts { + if !matches!(&stmt.node, ast::Stmt::Import(..)) { + result = self.walk_stmt(stmt); + } + } + result + } + + pub fn walk_stmts(&self, stmts: &'ctx [Box>]) -> EvalResult { + // Empty statements return None value + let mut result = self.ok_result(); + for stmt in stmts { + result = self.walk_stmt(stmt); + } + result + } + + pub(crate) fn walk_stmts_with_setter(&self, setter: &Setter) { + if let Some(index) = setter.index { + let frame = { + let frames = self.frames.borrow(); + frames + .get(index) + .expect(kcl_error::INTERNAL_ERROR_MSG) + .clone() + }; + if let Proxy::Global(index) = &frame.proxy { + if let Some(module_list) = self + .program + .pkgs + .get(&pkgpath_without_prefix!(frame.pkgpath)) + { + if let Some(module) = module_list.get(*index) { + let module = self + .program + .get_module(module) + .expect("Failed to acquire module lock") + .expect(&format!("module {:?} not found in program", module)); + if let Some(stmt) = module.body.get(setter.stmt) { + self.push_backtrack_meta(setter); + self.walk_stmt(stmt).expect(INTERNAL_ERROR_MSG); + self.pop_backtrack_meta(); + } + } + } + } + } + } + + pub(crate) fn walk_schema_stmts_with_setter( + &self, + stmts: &'ctx [Box>], + setter: &Setter, + ) -> EvalResult { + if let Some(index) = setter.index { + let frame = { + let frames = self.frames.borrow(); + frames + .get(index) + .expect(kcl_error::INTERNAL_ERROR_MSG) + .clone() + }; + if let Proxy::Schema(schema) = &frame.proxy { + if let Some(stmt) = schema.ctx.borrow().node.body.get(setter.stmt) { + self.push_pkgpath(&frame.pkgpath); + self.enter_scope(); + self.push_backtrack_meta(setter); + defer! { + self.pop_backtrack_meta(); + self.leave_scope(); + self.pop_pkgpath(); + } + let value = self.walk_stmt(stmt); + value + } else { + self.ok_result() + } + } else { + self.ok_result() + } + } else if let Some(stmt) = stmts.get(setter.stmt) { + self.walk_stmt(stmt) + } else { + self.ok_result() + } + } + + pub fn walk_target_with_value( + &self, + target: &'ctx ast::Target, + right_value: ValueRef, + ) -> EvalResult { + let is_in_schema = self.is_in_schema(); + if target.paths.is_empty() { + let name = target.get_name(); + // Global variables + if self.scope_level() == GLOBAL_LEVEL { + self.add_or_update_global_variable(name, right_value.clone(), true); + // Lambda local variables. + } else if self.is_in_lambda() { + let value = right_value.clone(); + // schema frame in the lambda + if self.is_schema_scope() { + let is_local_var = self.is_local_var(name); + let value = right_value.clone(); + match (is_local_var, is_in_schema) { + (false, true) => self.update_schema_or_rule_scope_value(name, Some(&value)), + _ => self.add_variable(name, value), + } + } else { + // If variable exists in the scope and update it, if not, add it to the scope. + if !self.store_variable_in_current_scope(name, value.clone()) { + self.add_variable(name, self.undefined_value()); + self.store_variable(name, value); + } + } + } else { + let is_local_var = self.is_local_var(name); + let value = right_value.clone(); + match (is_local_var, is_in_schema) { + (false, true) => self.update_schema_or_rule_scope_value(name, Some(&value)), + _ => self.add_variable(name, value), + } + } + } else { + let name = target.get_name(); + // In KCL, we cannot modify global variables in other packages, + // so pkgpath is empty here. + let mut value = self.load_value("", &[name]); + // Convert `store a.b.c = 1` -> `%t = load &a; %t = load_attr %t %b; store_attr %t %c with 1` + for (i, path) in target.paths.iter().enumerate() { + let ctx = if i < target.paths.len() - 1 { + ast::ExprContext::Load + } else { + ast::ExprContext::Store + }; + match ctx { + ast::ExprContext::Load => { + value = self.load_target_path(&value, path)?; + } + ast::ExprContext::Store => { + self.store_target_path(&mut value, path, &right_value)?; + let is_local_var = self.is_local_var(name); + let is_in_lambda = self.is_in_lambda(); + // Set config value for the schema attribute if the attribute is in the schema and + // it is not a local variable in the lambda function. + if self.scope_level() >= INNER_LEVEL + && is_in_schema + && !is_in_lambda + && !is_local_var + { + self.update_schema_or_rule_scope_value(name, None); + } + } + } + } + } + Ok(right_value) + } + + pub fn walk_identifier_with_ctx( + &self, + identifier: &'ctx ast::Identifier, + identifier_ctx: &ast::ExprContext, + right_value: Option, + ) -> EvalResult { + let is_in_schema = self.is_in_schema(); + match identifier_ctx { + // Store a.b.c = 1 + ast::ExprContext::Store => { + if identifier.names.len() == 1 { + let name = identifier.names[0].node.as_str(); + // Global variables + if self.scope_level() == GLOBAL_LEVEL { + self.add_or_update_global_variable( + name, + right_value.clone().expect(kcl_error::INTERNAL_ERROR_MSG), + true, + ); + // Lambda local variables. + } else if self.is_in_lambda() { + let value = right_value.clone().expect(kcl_error::INTERNAL_ERROR_MSG); + // schema frame in the lambda + if self.is_schema_scope() { + let is_local_var = self.is_local_var(name); + let value = right_value.clone().expect(kcl_error::INTERNAL_ERROR_MSG); + match (is_local_var, is_in_schema) { + (false, true) => { + self.update_schema_or_rule_scope_value(name, Some(&value)) + } + _ => self.add_variable(name, value), + } + } else { + // If variable exists in the scope and update it, if not, add it to the scope. + if !self.store_variable_in_current_scope(name, value.clone()) { + self.add_variable(name, self.undefined_value()); + self.store_variable(name, value); + } + } + } else { + let is_local_var = self.is_local_var(name); + let value = right_value.clone().expect(kcl_error::INTERNAL_ERROR_MSG); + match (is_local_var, is_in_schema) { + (false, true) => { + self.update_schema_or_rule_scope_value(name, Some(&value)) + } + _ => self.add_variable(name, value), + } + } + } else { + let names = &identifier.names; + let name = names[0].node.as_str(); + // In KCL, we cannot modify global variables in other packages, + // so pkgpath is empty here. + let mut value = self.load_value("", &[name]); + // Convert `store a.b.c = 1` -> `%t = load &a; %t = load_attr %t %b; store_attr %t %c with 1` + for i in 0..names.len() - 1 { + let attr = names[i + 1].node.as_str(); + let ctx = if matches!(identifier_ctx, ast::ExprContext::Store) + && i != names.len() - 2 + && names.len() > 2 + { + &ast::ExprContext::Load + } else { + identifier_ctx + }; + match ctx { + ast::ExprContext::Load => { + value = value.load_attr(attr); + } + ast::ExprContext::Store => { + self.dict_set_value( + &mut value, + attr, + &right_value.clone().expect(kcl_error::INTERNAL_ERROR_MSG), + ); + let is_local_var = self.is_local_var(name); + let is_in_lambda = self.is_in_lambda(); + // Set config value for the schema attribute if the attribute is in the schema and + // it is not a local variable in the lambda function. + if self.scope_level() >= INNER_LEVEL + && is_in_schema + && !is_in_lambda + && !is_local_var + { + self.update_schema_or_rule_scope_value(name, None); + } + } + } + } + } + Ok(right_value.expect(kcl_error::INTERNAL_ERROR_MSG)) + } + // Load .a.b.c + ast::ExprContext::Load => Ok(self.load_value( + &identifier.pkgpath, + &identifier + .names + .iter() + .map(|n| n.node.as_str()) + .collect::>(), + )), + } + } + + pub fn walk_decorator_with_name( + &self, + decorator: &'ctx CallExpr, + attr_name: Option<&str>, + is_schema_target: bool, + ) -> EvalResult { + let mut list_value = self.list_value(); + let mut dict_value = self.dict_value(); + let (_, config_value, config_meta) = self + .get_schema_or_rule_config_info() + .expect(kcl_error::INTERNAL_ERROR_MSG); + for arg in &decorator.args { + let value = self.walk_expr(arg)?; + self.list_append(&mut list_value, &value); + } + for keyword in &decorator.keywords { + let name = &keyword.node.arg.node.names[0]; + let value = if let Some(value) = &keyword.node.value { + self.walk_expr(value)? + } else { + self.none_value() + }; + self.dict_insert_value(&mut dict_value, name.node.as_str(), &value); + } + let name = match &decorator.func.node { + ast::Expr::Identifier(ident) if ident.names.len() == 1 => ident.names[0].clone(), + _ => panic!("invalid decorator name, expect single identifier"), + }; + let attr_name = if let Some(v) = attr_name { v } else { "" }; + DecoratorValue::new(&name.node, &list_value, &dict_value).run( + &mut self.runtime_ctx.borrow_mut(), + attr_name, + is_schema_target, + &config_value, + &config_meta, + ); + self.ok_result() + } + + pub fn walk_arguments( + &self, + arguments: &'ctx Option>, + args: &ValueRef, + kwargs: &ValueRef, + ) { + // Arguments names and defaults + let (arg_names, arg_types, arg_defaults) = if let Some(args) = &arguments { + let names = &args.node.args; + let types = &args.node.ty_list; + let defaults = &args.node.defaults; + ( + names.iter().map(|identifier| &identifier.node).collect(), + types.iter().collect(), + defaults.iter().collect(), + ) + } else { + (vec![], vec![], vec![]) + }; + // Default parameter values + for ((arg_name, arg_type), value) in + arg_names.iter().zip(&arg_types).zip(arg_defaults.iter()) + { + let mut arg_value = if let Some(value) = value { + self.walk_expr(value).expect(kcl_error::RUNTIME_ERROR_MSG) + } else { + self.none_value() + }; + if let Some(ty) = arg_type { + arg_value = + type_pack_and_check(self, &arg_value, vec![&ty.node.to_string()], false); + } + // Arguments are immutable, so we place them in different scopes. + let name = arg_name.get_name(); + self.store_argument_in_current_scope(&name); + // Argument is a local variable instead of a global variable or schema attribute. + self.add_local_var(&name); + self.walk_identifier_with_ctx(arg_name, &ast::ExprContext::Store, Some(arg_value)) + .expect(kcl_error::RUNTIME_ERROR_MSG); + self.remove_local_var(&name); + } + // Positional arguments + let argument_len = args.len(); + for (i, (arg_name, arg_type)) in arg_names.iter().zip(arg_types).enumerate() { + // Positional arguments + let is_in_range = i < argument_len; + if is_in_range { + let mut arg_value = match args.list_get_option(i as isize) { + Some(v) => v, + None => self.undefined_value(), + }; + if let Some(ty) = arg_type { + arg_value = + type_pack_and_check(self, &arg_value, vec![&ty.node.to_string()], false); + } + self.store_variable(&arg_name.names[0].node, arg_value); + } else { + break; + } + } + // Keyword arguments + for arg_name in arg_names.iter() { + let name = &arg_name.names[0].node; + if let Some(arg) = kwargs.dict_get_value(name) { + // Find argument name in the scope + self.store_variable(&arg_name.names[0].node, arg); + } + } + } + + pub fn walk_generator( + &self, + generators: &'ctx [Box>], + elt: &'ctx ast::Node, + val: Option<&'ctx ast::Node>, + op: Option<&'ctx ast::ConfigEntryOperation>, + gen_index: usize, + collection_value: &mut ValueRef, + comp_type: &ast::CompType, + ) { + // Start block + let generator = &generators[gen_index]; + let iter_host_value = self + .walk_expr(&generator.node.iter) + .expect(kcl_error::RUNTIME_ERROR_MSG); + let mut iter_value = iter_host_value.iter(); + let targets = &generator.node.targets; + + while let Some((next_value, key, value)) = iter_value.next_with_key_value(&iter_host_value) + { + for v in targets { + self.add_local_var(&v.node.names[0].node) + } + if targets.len() == 1 { + // Store the target + self.walk_identifier_with_ctx( + &targets.first().expect(kcl_error::INTERNAL_ERROR_MSG).node, + &ast::ExprContext::Store, + Some(next_value), + ) + .expect(kcl_error::RUNTIME_ERROR_MSG); + } else if targets.len() == 2 { + // Store the target + self.walk_identifier_with_ctx( + &targets.first().expect(kcl_error::INTERNAL_ERROR_MSG).node, + &ast::ExprContext::Store, + Some(key), + ) + .expect(kcl_error::RUNTIME_ERROR_MSG); + self.walk_identifier_with_ctx( + &targets.get(1).expect(kcl_error::INTERNAL_ERROR_MSG).node, + &ast::ExprContext::Store, + Some(value), + ) + .expect(kcl_error::RUNTIME_ERROR_MSG); + } else { + panic!( + "the number of loop variables is {}, which can only be 1 or 2", + generator.node.targets.len() + ) + } + // Check the if filter + let mut skip = false; + for if_expr in &generator.node.ifs { + let value = self.walk_expr(if_expr).expect(kcl_error::RUNTIME_ERROR_MSG); + // Skip the iteration + if !value.is_truthy() { + skip = true; + } + } + if skip { + continue; + } + let next_gen_index = gen_index + 1; + if next_gen_index >= generators.len() { + match comp_type { + ast::CompType::List => { + let item = self.walk_expr(elt).expect(kcl_error::RUNTIME_ERROR_MSG); + self.list_append(collection_value, &item); + } + ast::CompType::Dict => { + let value = self + .walk_expr(val.expect(kcl_error::INTERNAL_ERROR_MSG)) + .expect(kcl_error::RUNTIME_ERROR_MSG); + let key = self.walk_expr(elt).expect(kcl_error::RUNTIME_ERROR_MSG); + let op = op.expect(kcl_error::INTERNAL_ERROR_MSG); + self.dict_insert( + collection_value, + &key.as_str(), + &value.deep_copy(), + op, + None, + ); + } + } + } else { + self.walk_generator( + generators, + elt, + val, + op, + next_gen_index, + collection_value, + comp_type, + ); + } + } + for v in targets { + self.remove_local_var(&v.node.names[0].node) + } + } + + pub(crate) fn walk_config_entries(&self, items: &'ctx [NodeRef]) -> EvalResult { + let mut config_value = self.dict_value(); + for item in items { + let value = self.walk_expr(&item.node.value)?; + if let Some(key_node) = &item.node.key { + let mut insert_index = None; + let optional_name = match &key_node.node { + ast::Expr::Identifier(identifier) => Some(identifier.names[0].node.clone()), + ast::Expr::StringLit(string_lit) => Some(string_lit.value.clone()), + ast::Expr::Subscript(subscript) => { + let mut name = None; + if let ast::Expr::Identifier(identifier) = &subscript.value.node { + if let Some(index_node) = &subscript.index { + // Insert index + if let ast::Expr::NumberLit(number) = &index_node.node { + if let ast::NumberLitValue::Int(v) = number.value { + insert_index = Some(v as i32); + name = Some(identifier.names[0].node.clone()) + } + } else if let ast::Expr::Unary(unary_expr) = &index_node.node { + // Negative insert index + if let ast::Expr::NumberLit(number) = &unary_expr.operand.node { + if let ast::NumberLitValue::Int(v) = number.value { + insert_index = Some(-v as i32); + name = Some(identifier.names[0].node.clone()) + } + } + } + } + } + name + } + _ => None, + }; + // Store a local variable for every entry key. + let key = match &optional_name { + Some(name) if !self.is_local_var(name) => self.string_value(name), + _ => self.walk_expr(key_node)?, + }; + self.dict_insert( + &mut config_value, + &key.as_str(), + &value, + &item.node.operation, + insert_index, + ); + if let Some(name) = &optional_name { + let value = self.dict_get_value(&config_value, name); + self.add_or_update_local_variable_within_scope(name, value); + } + } else { + // If the key does not exist, execute the logic of unpacking expression `**expr` here. + config_value.dict_insert_unpack(&mut self.runtime_ctx.borrow_mut(), &value) + } + } + Ok(config_value) + } +} diff --git a/kclvm/evaluator/src/proxy.rs b/kclvm/evaluator/src/proxy.rs new file mode 100644 index 000000000..7f5524493 --- /dev/null +++ b/kclvm/evaluator/src/proxy.rs @@ -0,0 +1,162 @@ +use kclvm_runtime::ValueRef; +use scopeguard::defer; + +use crate::error as kcl_error; +use crate::func::FunctionCaller; +use crate::rule::{RuleCaller, RuleEvalContextRef}; +use crate::schema::{SchemaCaller, SchemaEvalContextRef}; +use crate::Evaluator; + +/// Caller frame with the package path. When a caller occurs, +/// it is necessary to switch the frame to ensure that a suitable +/// scope is found. +pub struct Frame { + pub pkgpath: String, + pub proxy: Proxy, +} + +/// Caller proxy used by call_expr or schema_expr. +pub enum Proxy { + Lambda(FunctionCaller), + Schema(SchemaCaller), + Rule(RuleCaller), + Global(usize), +} + +impl Proxy { + /// Get the name of the proxy, if it is an anonymous function, returns "lambda" + /// if it is a schema or rule, returns its name. + #[inline] + pub fn get_name(&self) -> String { + match self { + Proxy::Lambda(_) => "lambda".to_string(), + Proxy::Schema(s) => s.ctx.borrow().node.name.node.to_string(), + Proxy::Rule(r) => r.ctx.borrow().node.name.node.to_string(), + Proxy::Global(index) => index.to_string(), + } + } +} + +/// Call the associated schemas including parent schema and mixin schema +pub(crate) fn call_schema_body( + s: &Evaluator, + func: &ValueRef, + args: &ValueRef, + kwargs: &ValueRef, + ctx: &SchemaEvalContextRef, +) -> ValueRef { + if let Some(index) = func.try_get_proxy() { + let frame = { + let frames = s.frames.borrow(); + frames + .get(index) + .expect(kcl_error::INTERNAL_ERROR_MSG) + .clone() + }; + if let Proxy::Schema(schema) = &frame.proxy { + s.push_pkgpath(&frame.pkgpath); + s.push_backtrace(&frame); + defer! { + s.pop_backtrace(); + s.pop_pkgpath(); + } + { + schema.ctx.borrow_mut().set_info_with_schema(&ctx.borrow()) + } + let value = (schema.body)(s, &schema.ctx, args, kwargs); + value + } else { + ctx.borrow().value.clone() + } + } else { + ctx.borrow().value.clone() + } +} + +/// Call the associated schemas including parent schema and mixin schema +pub(crate) fn call_schema_body_from_rule( + s: &Evaluator, + func: &ValueRef, + args: &ValueRef, + kwargs: &ValueRef, + ctx: &RuleEvalContextRef, +) -> ValueRef { + if let Some(index) = func.try_get_proxy() { + let frame = { + let frames = s.frames.borrow(); + frames + .get(index) + .expect(kcl_error::INTERNAL_ERROR_MSG) + .clone() + }; + if let Proxy::Schema(schema) = &frame.proxy { + s.push_pkgpath(&frame.pkgpath); + s.push_backtrace(&frame); + defer! { + s.pop_backtrace(); + s.pop_pkgpath(); + } + { + schema.ctx.borrow_mut().set_info_with_rule(&ctx.borrow()) + } + let value = (schema.body)(s, &schema.ctx, args, kwargs); + value + } else { + ctx.borrow().value.clone() + } + } else { + ctx.borrow().value.clone() + } +} + +pub(crate) fn call_schema_check( + s: &Evaluator, + func: &ValueRef, + schema_value: &ValueRef, + args: &ValueRef, + kwargs: &ValueRef, + ctx: Option<&SchemaEvalContextRef>, +) { + if let Some(index) = func.try_get_proxy() { + let frame = { + let frames = s.frames.borrow(); + frames + .get(index) + .expect(kcl_error::INTERNAL_ERROR_MSG) + .clone() + }; + if let Proxy::Schema(schema) = &frame.proxy { + s.push_pkgpath(&frame.pkgpath); + s.push_backtrace(&frame); + defer! { + s.pop_backtrace(); + s.pop_pkgpath(); + } + if let Some(ctx) = ctx { + schema.ctx.borrow_mut().set_info_with_schema(&ctx.borrow()) + } + (schema.check)(s, &schema.ctx, schema_value, args, kwargs); + } + } +} + +pub(crate) fn call_rule_check(s: &Evaluator, func: &ValueRef, args: &ValueRef, kwargs: &ValueRef) { + if let Some(index) = func.try_get_proxy() { + let frame = { + let frames = s.frames.borrow(); + frames + .get(index) + .expect(kcl_error::INTERNAL_ERROR_MSG) + .clone() + }; + if let Proxy::Rule(rule) = &frame.proxy { + s.push_pkgpath(&frame.pkgpath); + s.push_backtrace(&frame); + defer! { + s.pop_backtrace(); + s.pop_pkgpath(); + } + (rule.check)(s, &rule.ctx, args, kwargs); + } + } +} diff --git a/kclvm/evaluator/src/rule.rs b/kclvm/evaluator/src/rule.rs new file mode 100644 index 000000000..756ead23b --- /dev/null +++ b/kclvm/evaluator/src/rule.rs @@ -0,0 +1,149 @@ +use std::cell::RefCell; +use std::rc::Rc; +use std::sync::Arc; + +use kclvm_ast::ast; +use kclvm_ast::walker::TypedResultWalker; +use kclvm_runtime::ValueRef; +use scopeguard::defer; + +use crate::error as kcl_error; + +use crate::proxy::{call_rule_check, call_schema_body_from_rule}; +use crate::Evaluator; + +pub type RuleBodyHandler = + Arc ValueRef>; + +pub type RuleEvalContextRef = Rc>; + +/// Proxy functions represent the saved functions of the runtime its, +/// rather than executing KCL defined functions or plugin functions. +#[derive(Clone, Debug)] +pub struct RuleEvalContext { + pub node: Rc, + pub value: ValueRef, + pub config: ValueRef, + pub config_meta: ValueRef, + pub optional_mapping: ValueRef, + pub is_sub_schema: bool, +} + +impl RuleEvalContext { + #[inline] + pub fn new_with_node(node: ast::RuleStmt) -> Self { + RuleEvalContext { + node: Rc::new(node), + value: ValueRef::dict(None), + config: ValueRef::dict(None), + config_meta: ValueRef::dict(None), + optional_mapping: ValueRef::dict(None), + is_sub_schema: true, + } + } + + /// New a rule evaluation context with schema value and config. + #[inline] + pub fn new_with_value(&self, value: &ValueRef, config: &ValueRef) -> RuleEvalContextRef { + Rc::new(RefCell::new(Self { + node: self.node.clone(), + value: value.clone(), + config: config.clone(), + config_meta: ValueRef::dict(None), + optional_mapping: ValueRef::dict(None), + is_sub_schema: true, + })) + } + + /// Reset rule evaluation context state. + pub fn reset(&mut self) { + self.value = ValueRef::dict(None); + self.config = ValueRef::dict(None); + self.config_meta = ValueRef::dict(None); + self.optional_mapping = ValueRef::dict(None); + self.is_sub_schema = true; + } + + /// Reset schema evaluation context state. + #[inline] + pub fn snapshot(&self, config: ValueRef, config_meta: ValueRef) -> RuleEvalContextRef { + Rc::new(RefCell::new(Self { + node: self.node.clone(), + value: ValueRef::dict(None), + config, + config_meta, + optional_mapping: ValueRef::dict(None), + is_sub_schema: true, + })) + } +} + +#[derive(Clone)] +pub struct RuleCaller { + pub ctx: RuleEvalContextRef, + pub body: RuleBodyHandler, + pub check: RuleBodyHandler, +} + +/// Rule function body +pub fn rule_body( + s: &Evaluator, + ctx: &RuleEvalContextRef, + args: &ValueRef, + kwargs: &ValueRef, +) -> ValueRef { + // Schema Value + let rule_value = if let Some(for_host_name) = &ctx.borrow().node.for_host_name { + let base_constructor_func = s + .walk_identifier_with_ctx(&for_host_name.node, &ast::ExprContext::Load, None) + .expect(kcl_error::RUNTIME_ERROR_MSG); + // Call base schema function + call_schema_body_from_rule(s, &base_constructor_func, args, kwargs, ctx) + } else { + ctx.borrow().value.clone() + }; + let rule_name = &ctx.borrow().node.name.node; + s.push_schema(crate::EvalContext::Rule(ctx.clone())); + s.enter_scope(); + defer! { + s.leave_scope(); + s.pop_schema(); + } + // Evaluate arguments and keyword arguments and store values to local variables. + s.walk_arguments(&ctx.borrow().node.args, args, kwargs); + // Eval schema body and record schema instances. + { + // Rule decorators check + for decorator in &ctx.borrow().node.decorators { + s.walk_decorator_with_name(&decorator.node, Some(rule_name), true) + .expect(kcl_error::RUNTIME_ERROR_MSG); + } + } + // Do rule check for the sub rule. + if ctx.borrow().is_sub_schema { + // Call rule check block function + rule_check(s, ctx, args, kwargs); + } + rule_value +} + +pub fn rule_check( + s: &Evaluator, + ctx: &RuleEvalContextRef, + args: &ValueRef, + kwargs: &ValueRef, +) -> ValueRef { + // Call base check function + for parent_name in &ctx.borrow().node.parent_rules { + let base_constructor_func = s + .walk_identifier_with_ctx(&parent_name.node, &ast::ExprContext::Load, None) + .expect(kcl_error::RUNTIME_ERROR_MSG); + call_rule_check(s, &base_constructor_func, args, kwargs) + } + // Call self check function + for check_expr in &ctx.borrow().node.checks { + s.walk_check_expr(&check_expr.node) + .expect(kcl_error::RUNTIME_ERROR_MSG); + } + ctx.borrow().value.clone() +} diff --git a/kclvm/evaluator/src/runtime.rs b/kclvm/evaluator/src/runtime.rs new file mode 100644 index 000000000..fd90d95d9 --- /dev/null +++ b/kclvm/evaluator/src/runtime.rs @@ -0,0 +1,71 @@ +use std::os::raw::c_char; +use std::{ + mem::transmute_copy, + panic::{catch_unwind, AssertUnwindSafe}, +}; + +use kclvm_runtime::{ + get_call_arg, is_runtime_catch_function, kclvm_plugin_invoke, ptr_as_ref, Context, + SchemaTypeFunc, UnsafeWrapper, ValueRef, +}; + +use crate::Evaluator; + +/// Invoke functions with arguments and keyword arguments. +pub fn invoke_function( + s: &Evaluator, + func: &ValueRef, + args: &mut ValueRef, + kwargs: &ValueRef, +) -> ValueRef { + if func.is_func() { + let func = func.as_function(); + let fn_ptr = func.fn_ptr; + let closure = &func.closure; + if is_runtime_catch_function(fn_ptr) { + let value = runtime_catch(s, args, kwargs); + return value; + } else { + let ctx: &mut Context = &mut s.runtime_ctx.borrow_mut(); + unsafe { + // Call schema constructor twice + let value = if func.is_external { + let name = format!("{}\0", func.name); + kclvm_plugin_invoke(ctx, name.as_ptr() as *const c_char, args, kwargs) + } else { + let call_fn: SchemaTypeFunc = transmute_copy(&fn_ptr); + args.list_append_unpack_first(closure); + let args = args.clone().into_raw(ctx); + call_fn(ctx, args, kwargs) + }; + let value = ptr_as_ref(value); + value.clone() + } + } + } else { + ValueRef::undefined() + } +} + +/// Executes the provided function and catches any potential runtime errors. +/// Returns undefined if execution is successful, otherwise returns an error +/// message in case of a runtime panic. +pub fn runtime_catch(s: &Evaluator, args: &ValueRef, kwargs: &ValueRef) -> ValueRef { + if let Some(func) = get_call_arg(args, kwargs, 0, Some("func")) { + let wrapper = UnsafeWrapper::new(|| { + if let Some(proxy) = func.try_get_proxy() { + let args = ValueRef::list(None); + let kwargs = ValueRef::dict(None); + s.invoke_proxy_function(proxy, &args, &kwargs); + } + }); + let result = catch_unwind(AssertUnwindSafe(|| unsafe { + (wrapper.get())(); + })); + return match result { + Ok(_) => ValueRef::undefined(), + Err(err) => ValueRef::str(&kclvm_error::err_to_str(err)), + }; + } + panic!("catch() takes exactly one argument (0 given)"); +} diff --git a/kclvm/evaluator/src/schema.rs b/kclvm/evaluator/src/schema.rs new file mode 100644 index 000000000..93d832e75 --- /dev/null +++ b/kclvm/evaluator/src/schema.rs @@ -0,0 +1,896 @@ +use std::cell::RefCell; +use std::rc::Rc; +use std::sync::Arc; + +use generational_arena::Index; +use indexmap::IndexMap; +use kclvm_ast::ast; +use kclvm_ast::walker::TypedResultWalker; +use kclvm_runtime::{schema_runtime_type, ConfigEntryOperationKind, ValueRef}; +use scopeguard::defer; + +use crate::lazy::{merge_variables_and_setters, LazyEvalScope, LazyEvalScopeRef}; +use crate::proxy::{call_schema_body, call_schema_check}; +use crate::rule::RuleEvalContext; +use crate::ty::type_pack_and_check; +use crate::{error as kcl_error, Proxy}; +use crate::{Evaluator, INNER_LEVEL}; + +pub type SchemaBodyHandler = + Arc ValueRef>; + +pub type SchemaCheckHandler = + Arc ()>; + +pub type SchemaEvalContextRef = Rc>; + +/// Proxy functions represent the saved functions of the runtime its, +/// rather than executing KCL defined functions or plugin functions. +#[derive(Clone, Debug)] +pub struct SchemaEvalContext { + pub node: Rc, + pub scope: Option, + pub index: Index, + pub parent: Option, + pub mixins: Vec, + pub value: ValueRef, + pub config: ValueRef, + pub config_meta: ValueRef, + pub optional_mapping: ValueRef, + pub is_sub_schema: bool, +} + +impl SchemaEvalContext { + #[inline] + pub fn new_with_node( + node: ast::SchemaStmt, + index: Index, + parent: Option, + mixins: Vec, + ) -> Self { + Self { + node: Rc::new(node), + scope: None, + index, + parent, + mixins, + value: ValueRef::dict(None), + config: ValueRef::dict(None), + config_meta: ValueRef::dict(None), + optional_mapping: ValueRef::dict(None), + is_sub_schema: true, + } + } + + /// Reset schema evaluation context state. + #[inline] + pub fn snapshot(&self, config: ValueRef, config_meta: ValueRef) -> SchemaEvalContextRef { + Rc::new(RefCell::new(Self { + node: self.node.clone(), + index: self.index, + parent: self.parent, + mixins: self.mixins.clone(), + scope: None, + value: ValueRef::dict(None), + config, + config_meta, + optional_mapping: ValueRef::dict(None), + is_sub_schema: true, + })) + } + + /// New a schema evaluation context with schema value and config. + #[inline] + pub fn new_with_value(&self, value: &ValueRef, config: &ValueRef) -> SchemaEvalContextRef { + Rc::new(RefCell::new(Self { + node: self.node.clone(), + index: self.index, + parent: self.parent, + mixins: self.mixins.clone(), + scope: None, + value: value.clone(), + config: config.clone(), + config_meta: ValueRef::dict(None), + optional_mapping: ValueRef::dict(None), + is_sub_schema: true, + })) + } + + /// Pass value references from other schema eval context. + /// Note that do not change the schema node. + pub fn set_info_with_schema(&mut self, other: &SchemaEvalContext) { + self.config = other.config.clone(); + self.config_meta = other.config_meta.clone(); + self.value = other.value.clone(); + self.optional_mapping = other.optional_mapping.clone(); + self.is_sub_schema = false; + // Set lazy eval scope. + if let Some(other) = &other.scope { + if let Some(scope) = &self.scope { + let mut scope = scope.borrow_mut(); + let other = other.borrow(); + scope.cache = other.cache.clone(); + scope.levels = other.levels.clone(); + scope.cal_times = other.cal_times.clone(); + scope.setters = other.setters.clone(); + } else { + let other = other.borrow(); + self.scope = Some(Rc::new(RefCell::new(LazyEvalScope { + cache: other.cache.clone(), + levels: other.levels.clone(), + cal_times: other.cal_times.clone(), + setters: other.setters.clone(), + }))) + } + } + } + + /// Pass value references from other rule eval context. + /// Note that do not change the schema node. + pub fn set_info_with_rule(&mut self, other: &RuleEvalContext) { + self.config = other.config.clone(); + self.config_meta = other.config_meta.clone(); + self.value = other.value.clone(); + self.optional_mapping = other.optional_mapping.clone(); + // Note that for the host schema, it will evaluate the final value. + self.is_sub_schema = true; + } + + /// Update parent schema and mixin schema information in the current scope. + pub fn get_parent_schema( + s: &Evaluator, + parent: &Option>>, + ) -> Option { + if let Some(parent) = parent { + let func = s + .walk_identifier_with_ctx(&parent.node, &ast::ExprContext::Load, None) + .expect(kcl_error::RUNTIME_ERROR_MSG); + if let Some(index) = func.try_get_proxy() { + Some(index) + } else { + None + } + } else { + None + } + } + + /// Update parent schema and mixin schema information + pub fn get_mixin_schemas( + s: &Evaluator, + mixins: &[Box>], + ) -> Vec { + let mut results = vec![]; + for mixin in mixins { + let func = s + .walk_identifier_with_ctx(&mixin.node, &ast::ExprContext::Load, None) + .expect(kcl_error::RUNTIME_ERROR_MSG); + if let Some(index) = func.try_get_proxy() { + let frame = { + let frames = s.frames.borrow(); + frames + .get(index) + .expect(kcl_error::INTERNAL_ERROR_MSG) + .clone() + }; + if let Proxy::Schema(_) = &frame.proxy { + results.push(index); + } + } + } + results + } + + /// Whether the attribute is the schema context. + pub fn has_attr(s: &Evaluator, ctx: &SchemaEvalContextRef, name: &str) -> bool { + for stmt in &ctx.borrow().node.body { + if let ast::Stmt::SchemaAttr(attr) = &stmt.node { + if attr.name.node == name { + return true; + } + } + } + if let Some(index) = ctx.borrow().parent { + let frame = { + let frames = s.frames.borrow(); + frames + .get(index) + .expect(kcl_error::INTERNAL_ERROR_MSG) + .clone() + }; + if let Proxy::Schema(schema) = &frame.proxy { + return SchemaEvalContext::has_attr(s, &schema.ctx, name); + } + } + false + } + + /// Whether the index signature is the schema context. + pub fn has_index_signature(s: &Evaluator, ctx: &SchemaEvalContextRef) -> bool { + if ctx.borrow().node.index_signature.is_some() { + return true; + } + + if let Some(index) = ctx.borrow().parent { + let frame = { + let frames = s.frames.borrow(); + frames + .get(index) + .expect(kcl_error::INTERNAL_ERROR_MSG) + .clone() + }; + if let Proxy::Schema(schema) = &frame.proxy { + return SchemaEvalContext::has_index_signature(s, &schema.ctx); + } + } + false + } + + #[inline] + pub fn is_fit_config(s: &Evaluator, ctx: &SchemaEvalContextRef, value: &ValueRef) -> bool { + if value.is_config() { + let config = value.as_dict_ref(); + for (key, _) in &config.values { + let no_such_attr = + !SchemaEvalContext::has_attr(s, ctx, key) && !key.starts_with('_'); + let has_index_signature = SchemaEvalContext::has_index_signature(s, ctx); + if !has_index_signature && no_such_attr { + return false; + } + } + true + } else { + false + } + } + + /// Init the lazy scope used to cache the lazy evaluation result. + pub fn init_lazy_scope(&mut self, s: &Evaluator, index: Option) { + // TODO: cache the lazy scope cross different schema instances. + let mut setters = IndexMap::new(); + // Parent schema setters + if let Some(idx) = self.parent { + let frame = { + let frames = s.frames.borrow(); + frames + .get(idx) + .expect(kcl_error::INTERNAL_ERROR_MSG) + .clone() + }; + if let Proxy::Schema(schema) = &frame.proxy { + let mut parent = schema.ctx.borrow_mut(); + parent.init_lazy_scope(s, Some(idx)); + if let Some(scope) = &parent.scope { + merge_variables_and_setters( + &mut self.value, + &mut setters, + &scope.borrow().setters, + ); + } + } + } + // Self setters + merge_variables_and_setters( + &mut self.value, + &mut setters, + &s.emit_setters(&self.node.body, index), + ); + // Mixin schema setters + for idx in &self.mixins { + let frame = { + let frames = s.frames.borrow(); + frames + .get(*idx) + .expect(kcl_error::INTERNAL_ERROR_MSG) + .clone() + }; + if let Proxy::Schema(schema) = &frame.proxy { + let mut mixin = schema.ctx.borrow_mut(); + mixin.init_lazy_scope(s, Some(*idx)); + if let Some(scope) = &mixin.scope { + merge_variables_and_setters( + &mut self.value, + &mut setters, + &scope.borrow().setters, + ); + } + } + } + self.scope = Some(Rc::new(RefCell::new(LazyEvalScope { + setters, + ..Default::default() + }))) + } + + /// Get the value from the context. + pub fn get_value(&self, s: &Evaluator, key: &str, pkgpath: &str, target: &str) -> ValueRef { + if let Some(scope) = &self.scope { + let value = { + match self.value.get_by_key(key) { + Some(value) => value.clone(), + None => s.get_variable_in_pkgpath(key, pkgpath), + } + }; + // Deal in-place modify and return it self immediately. + if key == target && { + let scope = scope.borrow(); + !scope.is_backtracking(key) || scope.setter_len(key) <= 1 + } { + value + } else { + let cached_value = { + let scope = scope.borrow(); + scope.cache.get(key).cloned() + }; + match cached_value { + Some(value) => value.clone(), + None => { + let setters = { + let scope = scope.borrow(); + scope.setters.get(key).cloned() + }; + match &setters { + Some(setters) if !setters.is_empty() => { + // Call all setters function to calculate the value recursively. + let level = { + let scope = scope.borrow(); + *scope.levels.get(key).unwrap_or(&0) + }; + let next_level = level + 1; + { + let mut scope = scope.borrow_mut(); + scope.levels.insert(key.to_string(), next_level); + } + let n = setters.len(); + let index = n - next_level; + if index >= n { + value + } else { + // Call setter function + s.walk_schema_stmts_with_setter( + &self.node.body, + &setters[index], + ) + .expect(kcl_error::INTERNAL_ERROR_MSG); + { + let mut scope = scope.borrow_mut(); + scope.levels.insert(key.to_string(), level); + let value = match self.value.get_by_key(key) { + Some(value) => value.clone(), + None => s.undefined_value(), + }; + scope.cache.insert(key.to_string(), value.clone()); + value + } + } + } + _ => value, + } + } + } + } + } else if let Some(value) = self.value.dict_get_value(key) { + value + } else { + s.get_variable_in_pkgpath(key, pkgpath) + } + } + + /// Set value to the context. + #[inline] + pub fn set_value(&self, s: &Evaluator, key: &str) { + if let Some(scope) = &self.scope { + let mut scope = scope.borrow_mut(); + if (scope.cal_increment(key) || scope.is_last_setter_ast_index(key, &s.ast_id.borrow())) + && scope.cache.get(key).is_none() + { + scope + .cache + .insert(key.to_string(), s.dict_get_value(&self.value, key)); + } + } + } +} + +#[derive(Clone)] +pub struct SchemaCaller { + pub ctx: SchemaEvalContextRef, + pub body: SchemaBodyHandler, + pub check: SchemaCheckHandler, +} + +/// Init or reset the schema lazy eval scope. +pub(crate) fn init_lazy_scope(s: &Evaluator, ctx: &mut SchemaEvalContext) { + let is_sub_schema = { ctx.is_sub_schema }; + let index = { ctx.index }; + if is_sub_schema { + ctx.init_lazy_scope(s, Some(index)); + } +} + +/// Schema body function +pub(crate) fn schema_body( + s: &Evaluator, + ctx: &SchemaEvalContextRef, + args: &ValueRef, + kwargs: &ValueRef, +) -> ValueRef { + init_lazy_scope(s, &mut ctx.borrow_mut()); + // Schema self value or parent schema value; + let mut schema_ctx_value = if let Some(parent_name) = &ctx.borrow().node.parent_name { + let base_constructor_func = s.load_global_value( + &parent_name.node.pkgpath, + &parent_name + .node + .names + .iter() + .map(|n| n.node.as_str()) + .collect::>(), + ); + // Call base schema function + call_schema_body(s, &base_constructor_func, args, kwargs, ctx) + } else { + ctx.borrow().value.clone() + }; + let schema_name = { ctx.borrow().node.name.node.to_string() }; + s.push_schema(crate::EvalContext::Schema(ctx.clone())); + s.enter_schema_scope(true); + defer! { + s.leave_scope(); + s.pop_schema(); + } + // Evaluate arguments and keyword arguments and store values to local variables. + s.walk_arguments(&ctx.borrow().node.args, args, kwargs); + // Eval schema body and record schema instances. + { + let schema_pkgpath = &s.current_pkgpath(); + // To prevent schema recursive calling, thus clone the AST here. + let node = { + let ctx = ctx.borrow(); + ctx.node.clone() + }; + // Run schema compiled function + for stmt in &node.body { + s.walk_stmt(stmt).expect(kcl_error::RUNTIME_ERROR_MSG); + } + // Schema decorators check + for decorator in &node.decorators { + s.walk_decorator_with_name(&decorator.node, Some(&schema_name), true) + .expect(kcl_error::RUNTIME_ERROR_MSG); + } + let runtime_type = kclvm_runtime::schema_runtime_type(&schema_name, schema_pkgpath); + schema_ctx_value.set_potential_schema_type(&runtime_type); + // Set schema arguments and keyword arguments + schema_ctx_value.set_schema_args(args, kwargs); + } + // Schema Mixins + { + let ctx_ref = ctx.borrow(); + for mixin in &ctx_ref.node.mixins { + let mixin_func = s.load_global_value( + &mixin.node.pkgpath, + &mixin + .node + .names + .iter() + .map(|n| n.node.as_str()) + .collect::>(), + ); + schema_ctx_value = call_schema_body(s, &mixin_func, args, kwargs, ctx); + } + } + // Schema Attribute optional check + let mut optional_mapping = { ctx.borrow().optional_mapping.clone() }; + { + let ctx = ctx.borrow(); + for stmt in &ctx.node.body { + if let ast::Stmt::SchemaAttr(schema_attr) = &stmt.node { + s.dict_insert_value( + &mut optional_mapping, + &schema_attr.name.node, + &s.bool_value(schema_attr.is_optional), + ) + } + } + } + // Do schema check for the sub schema. + let is_sub_schema = { ctx.borrow().is_sub_schema }; + let schema = if is_sub_schema { + let index_sign_key_name = if let Some(index_signature) = &ctx.borrow().node.index_signature + { + if let Some(key_name) = &index_signature.node.key_name { + key_name.node.clone() + } else { + "".to_string() + } + } else { + "".to_string() + }; + if index_sign_key_name.is_empty() { + // Update schema relaxed attribute + update_schema_relaxed_attr(s, ctx, &mut schema_ctx_value); + // Construct schema instance + let schema = schema_with_config(s, ctx, &schema_ctx_value, args, kwargs); + // Do schema optional attribute check recursively before evaluate check expressions. + check_schema_optional_attr(s, &schema); + // Call schema check block function + schema_check(s, ctx, &schema, args, kwargs); + schema + } else { + // Do check function for every index signature key + let config = { + let ctx = ctx.borrow(); + ctx.config.clone() + }; + for (k, _) in &config.as_dict_ref().values { + // relaxed keys + if schema_ctx_value.attr_map_get(k).is_none() { + // Update index signature key value + let value = ValueRef::str(k); + schema_ctx_value.dict_update_key_value(&index_sign_key_name, value.clone()); + // Update schema relaxed attribute + update_schema_relaxed_attr(s, ctx, &mut schema_ctx_value); + // Call schema check block function + schema_check(s, ctx, &schema_ctx_value, args, kwargs); + } + } + schema_ctx_value.dict_remove(&index_sign_key_name); + // Construct schema instance + let schema = schema_with_config(s, ctx, &schema_ctx_value, args, kwargs); + // Do schema optional attribute check recursively before evaluate check expressions. + check_schema_optional_attr(s, &schema); + schema + } + } else { + // Record base schema instances. + schema_with_config(s, ctx, &schema_ctx_value, args, kwargs) + }; + schema +} + +// Schema check and index sign value update function +pub(crate) fn schema_check( + s: &Evaluator, + ctx: &SchemaEvalContextRef, + schema_value: &ValueRef, + args: &ValueRef, + kwargs: &ValueRef, +) { + // Call base check function + { + let ctx_ref = ctx.borrow(); + if let Some(parent_name) = &ctx_ref.node.parent_name { + let base_constructor_func = s + .walk_identifier_with_ctx(&parent_name.node, &ast::ExprContext::Load, None) + .expect(kcl_error::RUNTIME_ERROR_MSG); + call_schema_check( + s, + &base_constructor_func, + schema_value, + args, + kwargs, + Some(ctx), + ) + } + } + // Call self check function + { + let ctx = ctx.borrow(); + for check_expr in &ctx.node.checks { + s.walk_check_expr(&check_expr.node) + .expect(kcl_error::RUNTIME_ERROR_MSG); + } + } + + // Call mixin check functions + { + let ctx = ctx.borrow(); + for mixin in &ctx.node.mixins { + let mixin_func = s + .walk_identifier_with_ctx(&mixin.node, &ast::ExprContext::Load, None) + .expect(kcl_error::RUNTIME_ERROR_MSG); + if let Some(index) = mixin_func.try_get_proxy() { + let frame = { + let frames = s.frames.borrow(); + frames + .get(index) + .expect(kcl_error::INTERNAL_ERROR_MSG) + .clone() + }; + if let Proxy::Schema(schema) = &frame.proxy { + s.push_pkgpath(&frame.pkgpath); + s.push_backtrace(&frame); + defer! { + s.pop_backtrace(); + s.pop_pkgpath(); + } + (schema.check)(s, &schema.ctx, schema_value, args, kwargs); + } + } + } + } +} + +pub(crate) fn schema_with_config( + s: &Evaluator, + ctx: &SchemaEvalContextRef, + schema_ctx_value: &ValueRef, + args: &ValueRef, + kwargs: &ValueRef, +) -> ValueRef { + let name = { ctx.borrow().node.name.node.to_string() }; + let pkgpath = s.current_pkgpath(); + let config_keys: Vec = { + ctx.borrow() + .config + .as_dict_ref() + .values + .keys() + .cloned() + .collect() + }; + let runtime_type = schema_runtime_type(&name, &pkgpath); + // Instance package path is the last frame calling package path. + let instance_pkgpath = s.last_pkgpath(); + // Currently, `MySchema.instances()` it is only valid for files in the main package to + // avoid unexpected non idempotent calls. For example, I instantiated a MySchema in pkg1, + // but the length of the list returned by calling the instances method in other packages + // is uncertain. + { + let mut ctx = s.runtime_ctx.borrow_mut(); + // Record schema instance in the context + if !ctx.instances.contains_key(&runtime_type) { + ctx.instances + .insert(runtime_type.clone(), IndexMap::default()); + } + let pkg_instance_map = ctx.instances.get_mut(&runtime_type).unwrap(); + if !pkg_instance_map.contains_key(&instance_pkgpath) { + pkg_instance_map.insert(instance_pkgpath.clone(), vec![]); + } + pkg_instance_map + .get_mut(&instance_pkgpath) + .unwrap() + .push(schema_ctx_value.clone()); + } + // Dict to schema + let is_sub_schema = { ctx.borrow().is_sub_schema }; + if is_sub_schema { + let ctx = ctx.borrow(); + // Record instance copy and convert it to schema value. + schema_ctx_value.dict_to_schema( + &name, + &pkgpath, + &config_keys, + &ctx.config_meta, + &ctx.optional_mapping, + Some(args.clone()), + Some(kwargs.clone()), + ) + } else { + schema_ctx_value.clone() + } +} + +fn update_schema_relaxed_attr( + s: &Evaluator, + ctx: &SchemaEvalContextRef, + schema_value: &mut ValueRef, +) { + let schema_name = { ctx.borrow().node.name.node.to_string() }; + // Do check function + // Schema runtime index signature and relaxed check + { + let ctx = ctx.borrow(); + if let Some(index_signature) = &ctx.node.index_signature { + let index_sign_value = if let Some(value) = &index_signature.node.value { + s.walk_expr(value).expect(kcl_error::RUNTIME_ERROR_MSG) + } else { + s.undefined_value() + }; + let key_name = if let Some(key_name) = &index_signature.node.key_name { + key_name.node.as_str() + } else { + "" + }; + schema_relaxed_attr_update_and_check( + s, + schema_value, + &ctx.config, + &schema_name, + &index_sign_value, + key_name, + index_signature.node.key_ty.node.to_string().as_str(), + index_signature.node.value_ty.node.to_string().as_str(), + ); + } else { + schema_relaxed_attr_update_and_check( + s, + schema_value, + &ctx.config, + &schema_name, + &s.undefined_value(), + "", + "", + "", + ); + } + } +} + +fn check_schema_optional_attr(s: &Evaluator, schema_value: &ValueRef) { + if is_top_level_schema_instance(s) { + schema_value.schema_check_attr_optional(&mut s.runtime_ctx.borrow_mut(), true); + } +} + +/// Schema additional value check +fn schema_relaxed_attr_update_and_check( + s: &Evaluator, + schema_value: &mut ValueRef, + schema_config: &ValueRef, + schema_name: &str, + index_sign_value: &ValueRef, + index_key_name: &str, + key_type: &str, + value_type: &str, +) { + let has_index_signature = !key_type.is_empty(); + let config = schema_config.as_dict_ref(); + for (key, value) in &config.values { + let no_such_attr = schema_value.dict_get_value(key).is_none(); + if has_index_signature && no_such_attr { + // Allow index signature value has different values + // related to the index signature key name. + let should_update = + if let Some(index_key_value) = schema_value.dict_get_value(index_key_name) { + index_key_value.is_str() && key == &index_key_value.as_str() + } else { + true + }; + if should_update { + let op = config + .ops + .get(key) + .unwrap_or(&ConfigEntryOperationKind::Union); + schema_value.dict_update_entry( + key.as_str(), + &index_sign_value.deep_copy(), + &ConfigEntryOperationKind::Override, + None, + ); + s.dict_merge_key_value_pair( + schema_value, + key.as_str(), + value, + op.clone(), + None, + false, + ); + let value = schema_value.dict_get_value(key).unwrap(); + schema_value.dict_update_key_value( + key.as_str(), + type_pack_and_check(s, &value, vec![value_type], false), + ); + } + } else if !has_index_signature && no_such_attr { + panic!("No attribute named '{key}' in the schema '{schema_name}'"); + } + } +} + +/// For a schema instance returned by the schema body. Its schema and schema expr stack +/// length are both 1, if > 1, it's not a top level schema instance. +#[inline] +fn is_top_level_schema_instance(s: &Evaluator) -> bool { + !(s.schema_stack.borrow().len() > 1 || s.schema_expr_stack.borrow().len() > 1) +} + +impl<'ctx> Evaluator<'ctx> { + pub(crate) fn construct_schema_config_meta( + &self, + n: Option<&'ctx ast::Node>, + t: &'ctx ast::ConfigExpr, + ) -> ValueRef { + let mut config_meta = self.dict_value(); + if let Some(n) = n { + let value = self.string_value(&n.filename); + self.dict_insert_value( + &mut config_meta, + kclvm_runtime::CONFIG_META_FILENAME, + &value, + ); + let value = self.int_value(n.line as i64); + self.dict_insert_value(&mut config_meta, kclvm_runtime::CONFIG_META_LINE, &value); + let value = self.int_value(n.column as i64); + self.dict_insert_value(&mut config_meta, kclvm_runtime::CONFIG_META_COLUMN, &value); + } + for item in &t.items { + if let Some(key) = &item.node.key { + let name = match &key.node { + ast::Expr::Identifier(t) => t.names[0].node.clone(), + ast::Expr::NumberLit(t) => match t.value { + ast::NumberLitValue::Int(i) => i.to_string(), + ast::NumberLitValue::Float(f) => f.to_string(), + }, + ast::Expr::StringLit(t) => t.value.clone(), + ast::Expr::NameConstantLit(t) => match t.value { + ast::NameConstant::True => { + kclvm_runtime::KCL_NAME_CONSTANT_TRUE.to_string() + } + ast::NameConstant::False => { + kclvm_runtime::KCL_NAME_CONSTANT_FALSE.to_string() + } + ast::NameConstant::None => { + kclvm_runtime::KCL_NAME_CONSTANT_NONE.to_string() + } + ast::NameConstant::Undefined => { + kclvm_runtime::KCL_NAME_CONSTANT_UNDEFINED.to_string() + } + }, + _ => format!("{:?}", key.node), + }; + let mut config_item_meta = self.dict_value(); + let value = self.string_value(&key.filename); + self.dict_insert_value( + &mut config_item_meta, + kclvm_runtime::CONFIG_ITEM_META_FILENAME, + &value, + ); + let value = self.int_value(key.line as i64); + self.dict_insert_value( + &mut config_item_meta, + kclvm_runtime::CONFIG_ITEM_META_LINE, + &value, + ); + let value = self.int_value(key.column as i64); + self.dict_insert_value( + &mut config_item_meta, + kclvm_runtime::CONFIG_ITEM_META_COLUMN, + &value, + ); + let value = match &item.node.value.node { + ast::Expr::Config(config_expr) => { + self.construct_schema_config_meta(None, config_expr) + } + _ => self.dict_value(), + }; + self.dict_insert_value( + &mut config_item_meta, + kclvm_runtime::CONFIG_ITEM_META, + &value, + ); + self.dict_insert_value(&mut config_meta, &name, &config_item_meta) + } + } + config_meta + } + + pub(crate) fn update_schema_or_rule_scope_value( + &self, + name: &str, // Schema attribute name + value: Option<&ValueRef>, // Optional right override value + ) { + let (mut schema_value, config_value, _) = self + .get_schema_or_rule_config_info() + .expect(kcl_error::INTERNAL_ERROR_MSG); + let config_value = config_value + .dict_get_entry(name) + .unwrap_or(self.undefined_value()); + if self.scope_level() >= INNER_LEVEL && !self.is_local_var(name) { + if let Some(value) = value { + self.schema_dict_merge( + &mut schema_value, + name, + value, + &ast::ConfigEntryOperation::Override, + None, + ); + } + self.value_union(&mut schema_value, &config_value); + // Set config cache for the schema eval context. + if let Some(schema_ctx) = self.get_schema_eval_context() { + schema_ctx.borrow().set_value(self, name); + } + } + } +} diff --git a/kclvm/evaluator/src/scope.rs b/kclvm/evaluator/src/scope.rs new file mode 100644 index 000000000..27ff2f13f --- /dev/null +++ b/kclvm/evaluator/src/scope.rs @@ -0,0 +1,632 @@ +use std::sync::{Arc, RwLock}; + +use crate::func::ClosureMap; +use crate::lazy::merge_setters; +use crate::{ + error as kcl_error, lazy::LazyEvalScope, rule::RuleEvalContextRef, schema::SchemaEvalContextRef, +}; +use indexmap::{IndexMap, IndexSet}; +use kclvm_ast::ast; +use kclvm_ast::walker::TypedResultWalker; +use kclvm_runtime::{ValueRef, _kclvm_get_fn_ptr_by_name, MAIN_PKG_PATH}; +use kclvm_sema::{builtin, plugin}; + +use crate::{EvalResult, Evaluator, GLOBAL_LEVEL, INNER_LEVEL}; + +/// The evaluator scope. +#[derive(Debug, Default)] +pub struct Scope { + /// Scalars denotes the expression statement values without attribute. + pub scalars: Vec, + /// schema_scalar_idx denotes whether a schema exists in the scalar list. + pub schema_scalar_idx: usize, + /// is_schema denotes whether the scope is a schema. + pub is_schema: bool, + /// Scope normal variables + pub variables: IndexMap, + /// Potential arguments in the current scope, such as schema/lambda arguments. + pub arguments: IndexSet, +} + +impl<'ctx> Evaluator<'ctx> { + /// Init a scope named `pkgpath` with all builtin functions + pub(crate) fn init_scope(&self, pkgpath: &str) { + { + let pkg_scopes = &mut self.pkg_scopes.borrow_mut(); + if pkg_scopes.contains_key(pkgpath) { + return; + } + let scopes = vec![Scope::default()]; + pkg_scopes.insert(String::from(pkgpath), scopes); + } + // Get the AST module list in the package path. + let module_list: Vec>> = if self.program.pkgs.contains_key(pkgpath) + { + self.program.get_modules_for_pkg(pkgpath) + } else if pkgpath.starts_with(kclvm_runtime::PKG_PATH_PREFIX) + && self.program.pkgs.contains_key(&pkgpath[1..]) + { + self.program.get_modules_for_pkg(&pkgpath[1..]) + } else { + panic!("pkgpath {} not found", pkgpath); + }; + // Init all global types including schema and rule. + for module in &module_list { + let module = module.read().expect("Failed to acquire module lock"); + for stmt in &module.body { + let name = match &stmt.node { + ast::Stmt::Schema(schema_stmt) => schema_stmt.name.node.clone(), + ast::Stmt::Rule(rule_stmt) => rule_stmt.name.node.clone(), + _ => "".to_string(), + }; + if !name.is_empty() { + self.add_variable(&name, self.undefined_value()); + } + } + } + // Init all builtin functions + for symbol in builtin::BUILTIN_FUNCTION_NAMES { + let function_name = + format!("{}_{}", builtin::KCL_BUILTIN_FUNCTION_MANGLE_PREFIX, symbol); + let function_ptr = _kclvm_get_fn_ptr_by_name(&function_name); + self.add_variable(symbol, self.function_value_with_ptr(function_ptr)); + } + // Init lazy scopes. + { + let mut lazy_scopes = self.lazy_scopes.borrow_mut(); + let mut setters = IndexMap::new(); + for (index, module) in module_list.iter().enumerate() { + let index = self.add_global_body(index); + let module = module.read().expect("Failed to acquire module lock"); + merge_setters(&mut setters, &self.emit_setters(&module.body, Some(index))) + } + if !lazy_scopes.contains_key(pkgpath) { + lazy_scopes.insert( + pkgpath.to_string(), + LazyEvalScope { + setters, + ..Default::default() + }, + ); + } + } + // Enter the global scope. + self.enter_scope(); + } + + /// Get the scope level + pub(crate) fn scope_level(&self) -> usize { + let current_pkgpath = self.current_pkgpath(); + let pkg_scopes = &self.pkg_scopes.borrow(); + let msg = format!("pkgpath {} is not found", current_pkgpath); + let scopes = pkg_scopes.get(¤t_pkgpath).expect(&msg); + // Sub the builtin global scope + scopes.len() - 1 + } + + /// Get the scope level + pub(crate) fn is_schema_scope(&self) -> bool { + let current_pkgpath = self.current_pkgpath(); + let pkg_scopes = &self.pkg_scopes.borrow(); + let msg = format!("pkgpath {} is not found", current_pkgpath); + let scopes = pkg_scopes.get(¤t_pkgpath).expect(&msg); + if let Some(last_scope) = scopes.last() { + last_scope.is_schema + } else { + false + } + } + + /// Enter a schema scope + pub(crate) fn enter_schema_scope(&self, is_schema: bool) { + let current_pkgpath = self.current_pkgpath(); + let pkg_scopes = &mut self.pkg_scopes.borrow_mut(); + let msg = format!("pkgpath {} is not found", current_pkgpath); + let scopes = pkg_scopes.get_mut(¤t_pkgpath).expect(&msg); + let mut scope = Scope::default(); + scope.is_schema = is_schema; + scopes.push(scope); + } + + /// Enter scope + #[inline] + pub(crate) fn enter_scope(&self) { + self.enter_schema_scope(false); + } + + /// Leave scope + pub(crate) fn leave_scope(&self) { + let current_pkgpath = self.current_pkgpath(); + let pkg_scopes = &mut self.pkg_scopes.borrow_mut(); + let msg = format!("pkgpath {} is not found", current_pkgpath); + let scopes = pkg_scopes.get_mut(¤t_pkgpath).expect(&msg); + scopes.pop(); + } + + pub(crate) fn get_schema_eval_context(&self) -> Option { + match self.schema_stack.borrow().last() { + Some(ctx) => match ctx { + crate::EvalContext::Schema(schema) => Some(schema.clone()), + crate::EvalContext::Rule(_) => None, + }, + None => None, + } + } + + pub(crate) fn get_rule_eval_context(&self) -> Option { + match self.schema_stack.borrow().last() { + Some(ctx) => match ctx { + crate::EvalContext::Schema(_) => None, + crate::EvalContext::Rule(rule) => Some(rule.clone()), + }, + None => None, + } + } + + /// Returns (value, config, config_meta) + #[inline] + pub(crate) fn get_schema_or_rule_config_info(&self) -> Option<(ValueRef, ValueRef, ValueRef)> { + match self.get_schema_eval_context() { + Some(v) => Some(( + v.borrow().value.clone(), + v.borrow().config.clone(), + v.borrow().config_meta.clone(), + )), + None => self.get_rule_eval_context().map(|v| { + ( + v.borrow().value.clone(), + v.borrow().config.clone(), + v.borrow().config_meta.clone(), + ) + }), + } + } + + /// Append a scalar value into the scope. + pub fn add_scalar(&self, scalar: ValueRef, is_schema: bool) { + let current_pkgpath = self.current_pkgpath(); + let pkg_scopes = &mut self.pkg_scopes.borrow_mut(); + let scopes = pkg_scopes + .get_mut(¤t_pkgpath) + .unwrap_or_else(|| panic!("pkgpath {} is not found", current_pkgpath)); + if let Some(last) = scopes.last_mut() { + let scalars = &mut last.scalars; + let schema_scalar_idx = &mut last.schema_scalar_idx; + if is_schema { + // Remove the last schema scalar. + if *schema_scalar_idx < scalars.len() { + scalars.remove(*schema_scalar_idx); + } + // Override the last schema scalar. + scalars.push(scalar); + *schema_scalar_idx = scalars.len() - 1; + } else { + scalars.push(scalar); + } + } + } + + /// Append a variable into the scope + pub fn add_variable(&self, name: &str, pointer: ValueRef) { + let current_pkgpath = self.current_pkgpath(); + let pkg_scopes = &mut self.pkg_scopes.borrow_mut(); + let msg = format!("pkgpath {} is not found", current_pkgpath); + let scopes = pkg_scopes.get_mut(¤t_pkgpath).expect(&msg); + if let Some(last) = scopes.last_mut() { + let variables = &mut last.variables; + variables.insert(name.to_string(), pointer); + } + } + + /// Store the argument named `name` in the current scope. + pub(crate) fn store_argument_in_current_scope(&self, name: &str) { + // Find argument name in the scope + let current_pkgpath = self.current_pkgpath(); + let pkg_scopes = &mut self.pkg_scopes.borrow_mut(); + let msg = format!("pkgpath {} is not found", current_pkgpath); + let scopes = pkg_scopes.get_mut(¤t_pkgpath).expect(&msg); + let index = scopes.len() - 1; + let arguments_mut = &mut scopes[index].arguments; + arguments_mut.insert(name.to_string()); + } + + /// Store the variable named `name` with `value` from the current scope, return false when not found + pub fn store_variable_in_current_scope(&self, name: &str, value: ValueRef) -> bool { + // Find argument name in the scope + let current_pkgpath = self.current_pkgpath(); + let pkg_scopes = &mut self.pkg_scopes.borrow_mut(); + let msg = format!("pkgpath {} is not found", current_pkgpath); + let scopes = pkg_scopes.get_mut(¤t_pkgpath).expect(&msg); + let index = scopes.len() - 1; + let variables = &mut scopes[index].variables; + // If exists and update it + if variables.get(&name.to_string()).is_some() { + variables.insert(name.to_string(), value); + return true; + } + false + } + + /// Store the variable named `name` with `value` from the scope, return false when not found + pub fn store_variable(&self, name: &str, value: ValueRef) -> bool { + // Find argument name in the scope + let current_pkgpath = self.current_pkgpath(); + let pkg_scopes = &mut self.pkg_scopes.borrow_mut(); + let msg = format!("pkgpath {} is not found", current_pkgpath); + let scopes = pkg_scopes.get_mut(¤t_pkgpath).expect(&msg); + for i in 0..scopes.len() { + let index = scopes.len() - i - 1; + let variables = &mut scopes[index].variables; + // If exists and update it + if variables.get(&name.to_string()).is_some() { + variables.insert(name.to_string(), value); + return true; + } + } + false + } + + /// Resolve variable in scope, return false when not found. + #[inline] + pub fn resolve_variable(&self, name: &str) -> bool { + self.resolve_variable_level(name).is_some() + } + + /// Resolve variable level in scope, return None when not found. + pub fn resolve_variable_level(&self, name: &str) -> Option { + // Find argument name in the scope + let current_pkgpath = self.current_pkgpath(); + let pkg_scopes = &self.pkg_scopes.borrow(); + let msg = format!("pkgpath {} is not found", current_pkgpath); + let scopes = pkg_scopes.get(¤t_pkgpath).expect(&msg); + let mut level = None; + for i in 0..scopes.len() { + let index = scopes.len() - i - 1; + let variables = &scopes[index].variables; + let arguments = &scopes[index].arguments; + if variables.get(name).is_some() { + level = Some(index); + break; + } + if arguments.contains(name) { + level = Some(index); + break; + } + } + level + } + + /// Append a variable or update the existed local variable within the current scope. + pub(crate) fn add_or_update_local_variable_within_scope(&self, name: &str, value: ValueRef) { + let current_pkgpath = self.current_pkgpath(); + let pkg_scopes = &mut self.pkg_scopes.borrow_mut(); + let msg = format!("pkgpath {} is not found", current_pkgpath); + let scopes = pkg_scopes.get_mut(¤t_pkgpath).expect(&msg); + let index = scopes.len() - 1; + if let Some(scope) = scopes.last_mut() { + let variables_mut = &mut scope.variables; + if index > GLOBAL_LEVEL { + variables_mut.insert(name.to_string(), value.clone()); + } + } + } + + /// Append a variable or update the existed variable + pub fn add_or_update_global_variable( + &self, + name: &str, + value: ValueRef, + save_lazy_scope: bool, + ) { + // Find argument name in the scope + let current_pkgpath = self.current_pkgpath(); + let pkg_scopes = &mut self.pkg_scopes.borrow_mut(); + let msg = format!("pkgpath {} is not found", current_pkgpath); + let scopes = pkg_scopes.get_mut(¤t_pkgpath).expect(&msg); + let mut existed = false; + if let Some(last) = scopes.last_mut() { + let variables = &mut last.variables; + if variables.get(&name.to_string()).is_some() { + variables.insert(name.to_string(), value.clone()); + if save_lazy_scope { + self.set_value_to_lazy_scope(¤t_pkgpath, name, &value) + } + existed = true; + } + } + if !existed { + if let Some(last) = scopes.last_mut() { + let variables = &mut last.variables; + if !variables.contains_key(name) { + variables.insert(name.to_string(), value.clone()); + if save_lazy_scope { + self.set_value_to_lazy_scope(¤t_pkgpath, name, &value) + } + } + } + } + } + + /// Get the variable value named `name` from the scope, return Err when not found + pub fn get_variable(&self, name: &str) -> ValueRef { + let current_pkgpath = self.current_pkgpath(); + self.get_variable_in_pkgpath(name, ¤t_pkgpath) + } + + /// Get the variable value named `name` from the scope, return Err when not found + pub fn get_variable_in_schema_or_rule(&self, name: &str) -> ValueRef { + let pkgpath = self.current_pkgpath(); + if let Some(schema_ctx) = self.get_schema_eval_context() { + return schema_ctx + .borrow() + .get_value(self, name, &pkgpath, &self.get_target_var()); + } else if let Some(rule_ctx) = self.get_rule_eval_context() { + let rule_value: ValueRef = rule_ctx.borrow().value.clone(); + return if let Some(value) = rule_value.dict_get_value(name) { + value + } else { + self.get_variable_in_pkgpath(name, &pkgpath) + }; + } else { + self.get_variable_in_pkgpath(name, &pkgpath) + } + } + + /// Get the variable value named `name` from the scope named `pkgpath`, return Err when not found + pub fn get_variable_in_pkgpath(&self, name: &str, pkgpath: &str) -> ValueRef { + let pkg_scopes = self.pkg_scopes.borrow(); + let pkgpath = + if !pkgpath.starts_with(kclvm_runtime::PKG_PATH_PREFIX) && pkgpath != MAIN_PKG_PATH { + format!("{}{}", kclvm_runtime::PKG_PATH_PREFIX, pkgpath) + } else { + pkgpath.to_string() + }; + let mut result = self.undefined_value(); + // System module + if builtin::STANDARD_SYSTEM_MODULE_NAMES_WITH_AT.contains(&pkgpath.as_str()) { + let pkgpath = &pkgpath[1..]; + + if pkgpath == builtin::system_module::UNITS + && builtin::system_module::UNITS_FIELD_NAMES.contains(&name) + { + let value_float: f64 = kclvm_runtime::f64_unit_value(name); + let value_int: u64 = kclvm_runtime::u64_unit_value(name); + if value_int != 1 { + self.int_value(value_int as i64) + } else { + self.float_value(value_float) + } + } else { + let func_name = format!( + "{}{}_{}", + builtin::KCL_SYSTEM_MODULE_MANGLE_PREFIX, + pkgpath, + name + ); + let function_ptr = _kclvm_get_fn_ptr_by_name(&func_name); + self.function_value_with_ptr(function_ptr) + } + } + // Plugin pkgpath + else if pkgpath.starts_with(plugin::PLUGIN_PREFIX_WITH_AT) { + // Strip the @kcl_plugin to kcl_plugin. + let name = format!("{}.{}", &pkgpath[1..], name); + ValueRef::func(0, 0, self.undefined_value(), &name, "", true) + // User pkgpath + } else { + // Global or local variables. + let scopes = pkg_scopes + .get(&pkgpath) + .unwrap_or_else(|| panic!("package {} is not found", pkgpath)); + // Scopes 0 is builtin scope, Scopes 1 is the global scope, Scopes 2~ are the local scopes + let scopes_len = scopes.len(); + let mut found = false; + for i in 0..scopes_len { + let index = scopes_len - i - 1; + let variables = &scopes[index].variables; + if let Some(var) = variables.get(name) { + // Closure vars, 2 denotes the builtin scope and the global scope, here is a closure scope. + result = if let Some(lambda_ctx) = self.last_lambda_ctx() { + let last_lambda_scope = lambda_ctx.level; + // Local scope variable or lambda closure variable. + let ignore = if let Some((start, end)) = self.scope_covers.borrow().last() { + *start <= index && index <= *end + } else { + false + }; + if index >= last_lambda_scope && !ignore { + var.clone() + } else { + lambda_ctx.closure.get(name).unwrap_or(var).clone() + } + } else { + // Not in the lambda, maybe a local variable. + var.clone() + }; + found = true; + break; + } + } + if found { + result + } else { + // Not found variable in the scope, maybe lambda closures captured in other package scopes. + self.last_lambda_ctx() + .map(|ctx| ctx.closure.get(name).cloned().unwrap_or(result.clone())) + .unwrap_or(result) + } + } + } + + /// Get closure map in the current inner scope. + pub(crate) fn get_current_closure_map(&self) -> ClosureMap { + // Get variable map in the current scope. + let pkgpath = self.current_pkgpath(); + let pkg_scopes = self.pkg_scopes.borrow(); + let scopes = pkg_scopes + .get(&pkgpath) + .unwrap_or_else(|| panic!("package {} is not found", pkgpath)); + let last_lambda_ctx = self.last_lambda_ctx(); + // Get current closure map. + let mut closure_map = last_lambda_ctx + .as_ref() + .map(|ctx| ctx.closure.clone()) + .unwrap_or_default(); + // Get variable map including schema in the current scope. + for i in INNER_LEVEL..scopes.len() { + let variables = &scopes + .get(i) + .expect(kcl_error::INTERNAL_ERROR_MSG) + .variables; + for (k, v) in variables { + closure_map.insert(k.to_string(), v.clone()); + } + } + closure_map + } + + /// Load value from name. + pub fn load_value(&self, pkgpath: &str, names: &[&str]) -> ValueRef { + if names.is_empty() { + return self.undefined_value(); + } + let name = names[0]; + if names.len() == 1 { + self.load_name(name) + } else { + let mut value = if pkgpath.is_empty() { + self.load_name(name) + } else { + self.undefined_value() + }; + for i in 0..names.len() - 1 { + let attr = names[i + 1]; + if i == 0 && !pkgpath.is_empty() { + value = self.get_variable_in_pkgpath(attr, pkgpath); + } else { + value = value.load_attr(attr) + } + } + value + } + } + + /// Load global value from name. + pub fn load_global_value(&self, pkgpath: &str, names: &[&str]) -> ValueRef { + if names.is_empty() { + return self.undefined_value(); + } + let name = names[0]; + if names.len() == 1 { + self.get_variable(name) + } else { + let mut value = if pkgpath.is_empty() { + self.get_variable(name) + } else { + self.undefined_value() + }; + for i in 0..names.len() - 1 { + let attr = names[i + 1]; + if i == 0 && !pkgpath.is_empty() { + value = self.get_variable_in_pkgpath(attr, pkgpath); + } else { + value = value.load_attr(attr) + } + } + value + } + } + + /// Load global or local value from name. + pub fn load_name(&self, name: &str) -> ValueRef { + match ( + self.is_in_schema(), + self.is_in_lambda(), + self.is_local_var(name), + ) { + // Get variable from the global lazy scope. + (false, _, false) => { + let variable = self.get_variable(name); + match self.resolve_variable_level(name) { + // Closure variable or local variables + Some(level) if level <= GLOBAL_LEVEL => self.get_value_from_lazy_scope( + &self.current_pkgpath(), + name, + &self.get_target_var(), + variable, + ), + // Schema closure or global variables + _ => variable, + } + } + // Get variable from the local or global scope. + (false, _, _) | (_, _, true) => self.get_variable(name), + // Get variable from the current schema scope. + (true, false, false) => self.get_variable_in_schema_or_rule(name), + // Get from local scope including lambda arguments, lambda variables, + // loop variables or global variables. + (true, true, _) => + // Get from local scope including lambda arguments, lambda variables, + // loop variables or global variables. + { + match self.resolve_variable_level(name) { + // Closure variable or local variables + Some(level) if level > GLOBAL_LEVEL => self.get_variable(name), + // Schema closure or global variables + _ => self.get_variable_in_schema_or_rule(name), + } + } + } + } + + /// Load assignment target value. + pub fn load_target(&self, target: &'ctx ast::Target) -> EvalResult { + let mut value = self.load_name(target.get_name()); + for path in &target.paths { + match path { + ast::MemberOrIndex::Member(member) => { + let attr = &member.node; + value = value.load_attr(attr); + } + ast::MemberOrIndex::Index(index) => { + let index = self.walk_expr(index)?; + value = value.bin_subscr(&index); + } + } + } + Ok(value) + } + + /// Load value from assignment target path. + pub fn load_target_path(&self, value: &ValueRef, path: &'ctx ast::MemberOrIndex) -> EvalResult { + Ok(match path { + ast::MemberOrIndex::Member(member) => { + let attr = &member.node; + value.load_attr(attr) + } + ast::MemberOrIndex::Index(index) => { + let index = self.walk_expr(index)?; + value.bin_subscr(&index) + } + }) + } + + pub fn store_target_path( + &self, + value: &mut ValueRef, + path: &'ctx ast::MemberOrIndex, + right_value: &ValueRef, + ) -> EvalResult { + match path { + ast::MemberOrIndex::Member(member) => { + let attr = &member.node; + self.dict_set_value(value, attr, &right_value); + } + ast::MemberOrIndex::Index(index) => { + let index = self.walk_expr(index)?; + value.bin_subscr_set(&mut self.runtime_ctx.borrow_mut(), &index, &right_value); + } + } + self.ok_result() + } +} diff --git a/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__assert_stmt_0.snap b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__assert_stmt_0.snap new file mode 100644 index 000000000..36e89bb3f --- /dev/null +++ b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__assert_stmt_0.snap @@ -0,0 +1,5 @@ +--- +source: evaluator/src/tests.rs +expression: "format!(\"{}\", evaluator.run().unwrap().1)" +--- +a: 1 diff --git a/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__assert_stmt_1.snap b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__assert_stmt_1.snap new file mode 100644 index 000000000..36e89bb3f --- /dev/null +++ b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__assert_stmt_1.snap @@ -0,0 +1,5 @@ +--- +source: evaluator/src/tests.rs +expression: "format!(\"{}\", evaluator.run().unwrap().1)" +--- +a: 1 diff --git a/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__assign_stmt_0.snap b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__assign_stmt_0.snap new file mode 100644 index 000000000..36e89bb3f --- /dev/null +++ b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__assign_stmt_0.snap @@ -0,0 +1,5 @@ +--- +source: evaluator/src/tests.rs +expression: "format!(\"{}\", evaluator.run().unwrap().1)" +--- +a: 1 diff --git a/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__assign_stmt_1.snap b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__assign_stmt_1.snap new file mode 100644 index 000000000..5e4bff410 --- /dev/null +++ b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__assign_stmt_1.snap @@ -0,0 +1,5 @@ +--- +source: evaluator/src/tests.rs +expression: "format!(\"{}\", evaluator.run().unwrap().1)" +--- +a: 2 diff --git a/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__assign_stmt_2.snap b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__assign_stmt_2.snap new file mode 100644 index 000000000..6742ebd45 --- /dev/null +++ b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__assign_stmt_2.snap @@ -0,0 +1,5 @@ +--- +source: evaluator/src/tests.rs +expression: "format!(\"{}\", evaluator.run().unwrap().1)" +--- +a: 3 diff --git a/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__assign_stmt_3.snap b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__assign_stmt_3.snap new file mode 100644 index 000000000..7a404a65f --- /dev/null +++ b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__assign_stmt_3.snap @@ -0,0 +1,6 @@ +--- +source: evaluator/src/tests.rs +expression: "format!(\"{}\", evaluator.run().unwrap().1)" +--- +a: 1 +b: 2 diff --git a/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__assign_stmt_4.snap b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__assign_stmt_4.snap new file mode 100644 index 000000000..7a404a65f --- /dev/null +++ b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__assign_stmt_4.snap @@ -0,0 +1,6 @@ +--- +source: evaluator/src/tests.rs +expression: "format!(\"{}\", evaluator.run().unwrap().1)" +--- +a: 1 +b: 2 diff --git a/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__assign_stmt_5.snap b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__assign_stmt_5.snap new file mode 100644 index 000000000..e56d37d9b --- /dev/null +++ b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__assign_stmt_5.snap @@ -0,0 +1,7 @@ +--- +source: evaluator/src/tests.rs +expression: "format!(\"{}\", evaluator.run().unwrap().1)" +--- +a: +- 1 +- 0 diff --git a/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__assign_stmt_6.snap b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__assign_stmt_6.snap new file mode 100644 index 000000000..5a0777795 --- /dev/null +++ b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__assign_stmt_6.snap @@ -0,0 +1,7 @@ +--- +source: evaluator/src/tests.rs +expression: "format!(\"{}\", evaluator.run().unwrap().1)" +--- +a: +- key: 1 +- key: 0 diff --git a/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__assign_stmt_7.snap b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__assign_stmt_7.snap new file mode 100644 index 000000000..9b744ff8d --- /dev/null +++ b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__assign_stmt_7.snap @@ -0,0 +1,13 @@ +--- +source: evaluator/src/tests.rs +expression: "format!(\"{}\", evaluator.run().unwrap().1)" +--- +a: +- key: + key: + - 1 + - 0 +- key: + key: + - 0 + - 0 diff --git a/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__aug_assign_stmt_0.snap b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__aug_assign_stmt_0.snap new file mode 100644 index 000000000..5e4bff410 --- /dev/null +++ b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__aug_assign_stmt_0.snap @@ -0,0 +1,5 @@ +--- +source: evaluator/src/tests.rs +expression: "format!(\"{}\", evaluator.run().unwrap().1)" +--- +a: 2 diff --git a/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__aug_assign_stmt_1.snap b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__aug_assign_stmt_1.snap new file mode 100644 index 000000000..d1fb2f6b6 --- /dev/null +++ b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__aug_assign_stmt_1.snap @@ -0,0 +1,5 @@ +--- +source: evaluator/src/tests.rs +expression: "format!(\"{}\", evaluator.run().unwrap().1)" +--- +a: 0 diff --git a/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__aug_assign_stmt_10.snap b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__aug_assign_stmt_10.snap new file mode 100644 index 000000000..36e89bb3f --- /dev/null +++ b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__aug_assign_stmt_10.snap @@ -0,0 +1,5 @@ +--- +source: evaluator/src/tests.rs +expression: "format!(\"{}\", evaluator.run().unwrap().1)" +--- +a: 1 diff --git a/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__aug_assign_stmt_11.snap b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__aug_assign_stmt_11.snap new file mode 100644 index 000000000..36e89bb3f --- /dev/null +++ b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__aug_assign_stmt_11.snap @@ -0,0 +1,5 @@ +--- +source: evaluator/src/tests.rs +expression: "format!(\"{}\", evaluator.run().unwrap().1)" +--- +a: 1 diff --git a/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__aug_assign_stmt_12.snap b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__aug_assign_stmt_12.snap new file mode 100644 index 000000000..1f84c9b2b --- /dev/null +++ b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__aug_assign_stmt_12.snap @@ -0,0 +1,10 @@ +--- +source: evaluator/src/tests.rs +expression: "format!(\"{}\", evaluator.run().unwrap().1)" +--- +a: +- 1 +- 0 +- 0 +- 0 +- 0 diff --git a/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__aug_assign_stmt_13.snap b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__aug_assign_stmt_13.snap new file mode 100644 index 000000000..1afd0a31d --- /dev/null +++ b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__aug_assign_stmt_13.snap @@ -0,0 +1,10 @@ +--- +source: evaluator/src/tests.rs +expression: "format!(\"{}\", evaluator.run().unwrap().1)" +--- +a: +- key: 2 +- key: 1 +- key: 1 +- key: 1 +- key: 1 diff --git a/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__aug_assign_stmt_14.snap b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__aug_assign_stmt_14.snap new file mode 100644 index 000000000..eecfa14bb --- /dev/null +++ b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__aug_assign_stmt_14.snap @@ -0,0 +1,25 @@ +--- +source: evaluator/src/tests.rs +expression: "format!(\"{}\", evaluator.run().unwrap().1)" +--- +a: +- key: + key: + - 1 + - 0 +- key: + key: + - 0 + - 0 +- key: + key: + - 0 + - 0 +- key: + key: + - 0 + - 0 +- key: + key: + - 0 + - 0 diff --git a/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__aug_assign_stmt_2.snap b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__aug_assign_stmt_2.snap new file mode 100644 index 000000000..5e4bff410 --- /dev/null +++ b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__aug_assign_stmt_2.snap @@ -0,0 +1,5 @@ +--- +source: evaluator/src/tests.rs +expression: "format!(\"{}\", evaluator.run().unwrap().1)" +--- +a: 2 diff --git a/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__aug_assign_stmt_3.snap b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__aug_assign_stmt_3.snap new file mode 100644 index 000000000..b6f161a65 --- /dev/null +++ b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__aug_assign_stmt_3.snap @@ -0,0 +1,5 @@ +--- +source: evaluator/src/tests.rs +expression: "format!(\"{}\", evaluator.run().unwrap().1)" +--- +a: 1.0 diff --git a/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__aug_assign_stmt_4.snap b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__aug_assign_stmt_4.snap new file mode 100644 index 000000000..36e89bb3f --- /dev/null +++ b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__aug_assign_stmt_4.snap @@ -0,0 +1,5 @@ +--- +source: evaluator/src/tests.rs +expression: "format!(\"{}\", evaluator.run().unwrap().1)" +--- +a: 1 diff --git a/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__aug_assign_stmt_5.snap b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__aug_assign_stmt_5.snap new file mode 100644 index 000000000..97594b724 --- /dev/null +++ b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__aug_assign_stmt_5.snap @@ -0,0 +1,5 @@ +--- +source: evaluator/src/tests.rs +expression: "format!(\"{}\", evaluator.run().unwrap().1)" +--- +a: 9 diff --git a/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__aug_assign_stmt_6.snap b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__aug_assign_stmt_6.snap new file mode 100644 index 000000000..07db3ae4a --- /dev/null +++ b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__aug_assign_stmt_6.snap @@ -0,0 +1,5 @@ +--- +source: evaluator/src/tests.rs +expression: "format!(\"{}\", evaluator.run().unwrap().1)" +--- +a: 6 diff --git a/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__aug_assign_stmt_7.snap b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__aug_assign_stmt_7.snap new file mode 100644 index 000000000..36e89bb3f --- /dev/null +++ b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__aug_assign_stmt_7.snap @@ -0,0 +1,5 @@ +--- +source: evaluator/src/tests.rs +expression: "format!(\"{}\", evaluator.run().unwrap().1)" +--- +a: 1 diff --git a/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__aug_assign_stmt_8.snap b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__aug_assign_stmt_8.snap new file mode 100644 index 000000000..6742ebd45 --- /dev/null +++ b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__aug_assign_stmt_8.snap @@ -0,0 +1,5 @@ +--- +source: evaluator/src/tests.rs +expression: "format!(\"{}\", evaluator.run().unwrap().1)" +--- +a: 3 diff --git a/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__aug_assign_stmt_9.snap b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__aug_assign_stmt_9.snap new file mode 100644 index 000000000..5e4bff410 --- /dev/null +++ b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__aug_assign_stmt_9.snap @@ -0,0 +1,5 @@ +--- +source: evaluator/src/tests.rs +expression: "format!(\"{}\", evaluator.run().unwrap().1)" +--- +a: 2 diff --git a/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__binary_expr_0.snap b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__binary_expr_0.snap new file mode 100644 index 000000000..78fdeb343 --- /dev/null +++ b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__binary_expr_0.snap @@ -0,0 +1,5 @@ +--- +source: evaluator/src/tests.rs +expression: "format!(\"{}\", evaluator.run().unwrap().1)" +--- +a: -1 diff --git a/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__binary_expr_1.snap b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__binary_expr_1.snap new file mode 100644 index 000000000..fc2c22613 --- /dev/null +++ b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__binary_expr_1.snap @@ -0,0 +1,6 @@ +--- +source: evaluator/src/tests.rs +expression: "format!(\"{}\", evaluator.run().unwrap().1)" +--- +a: {} +b: [] diff --git a/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__compare_expr_0.snap b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__compare_expr_0.snap new file mode 100644 index 000000000..54215b924 --- /dev/null +++ b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__compare_expr_0.snap @@ -0,0 +1,8 @@ +--- +source: evaluator/src/tests.rs +expression: "format!(\"{}\", evaluator.run().unwrap().1)" +--- +a: true +b: true +c: false +d: false diff --git a/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__dict_expr_0.snap b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__dict_expr_0.snap new file mode 100644 index 000000000..0f2e7e449 --- /dev/null +++ b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__dict_expr_0.snap @@ -0,0 +1,15 @@ +--- +source: evaluator/src/tests.rs +expression: "format!(\"{}\", evaluator.run().unwrap().1)" +--- +a: + k1: v1 + k2: v2 +b: + k1: v1 + k2: v2 +c: + k1: v1 +d: + k1: v1 + k2: v2 diff --git a/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__exec_with_plugin.snap b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__exec_with_plugin.snap new file mode 100644 index 000000000..7541ff36e --- /dev/null +++ b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__exec_with_plugin.snap @@ -0,0 +1,5 @@ +--- +source: evaluator/src/tests.rs +expression: "format!(\"{}\", evaluator.run().unwrap().1)" +--- +sum: 2 diff --git a/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__expr_stmt_0.snap b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__expr_stmt_0.snap new file mode 100644 index 000000000..49182c57f --- /dev/null +++ b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__expr_stmt_0.snap @@ -0,0 +1,6 @@ +--- +source: evaluator/src/tests.rs +expression: "format!(\"{}\", evaluator.run().unwrap().1)" +--- +1 + diff --git a/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__expr_stmt_1.snap b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__expr_stmt_1.snap new file mode 100644 index 000000000..59eed1b6b --- /dev/null +++ b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__expr_stmt_1.snap @@ -0,0 +1,6 @@ +--- +source: evaluator/src/tests.rs +expression: "format!(\"{}\", evaluator.run().unwrap().1)" +--- +2.0 + diff --git a/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__expr_stmt_2.snap b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__expr_stmt_2.snap new file mode 100644 index 000000000..5148a004e --- /dev/null +++ b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__expr_stmt_2.snap @@ -0,0 +1,6 @@ +--- +source: evaluator/src/tests.rs +expression: "format!(\"{}\", evaluator.run().unwrap().1)" +--- +true + diff --git a/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__expr_stmt_3.snap b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__expr_stmt_3.snap new file mode 100644 index 000000000..81e7a4fec --- /dev/null +++ b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__expr_stmt_3.snap @@ -0,0 +1,6 @@ +--- +source: evaluator/src/tests.rs +expression: "format!(\"{}\", evaluator.run().unwrap().1)" +--- +null + diff --git a/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__expr_stmt_4.snap b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__expr_stmt_4.snap new file mode 100644 index 000000000..aa2a630ba --- /dev/null +++ b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__expr_stmt_4.snap @@ -0,0 +1,9 @@ +--- +source: evaluator/src/tests.rs +expression: "format!(\"{}\", evaluator.run().unwrap().1)" +--- +1 +--- +2 +--- +3 diff --git a/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__expr_stmt_5.snap b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__expr_stmt_5.snap new file mode 100644 index 000000000..c4f84418b --- /dev/null +++ b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__expr_stmt_5.snap @@ -0,0 +1,5 @@ +--- +source: evaluator/src/tests.rs +expression: "format!(\"{}\", evaluator.run().unwrap().1)" +--- +k: v diff --git a/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__function_stmt_0.snap b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__function_stmt_0.snap new file mode 100644 index 000000000..3d3de056a --- /dev/null +++ b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__function_stmt_0.snap @@ -0,0 +1,5 @@ +--- +source: evaluator/src/tests.rs +expression: "format!(\"{}\", evaluator.run_as_function().to_string())" +--- +"bar" diff --git a/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__if_expr_0.snap b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__if_expr_0.snap new file mode 100644 index 000000000..36e89bb3f --- /dev/null +++ b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__if_expr_0.snap @@ -0,0 +1,5 @@ +--- +source: evaluator/src/tests.rs +expression: "format!(\"{}\", evaluator.run().unwrap().1)" +--- +a: 1 diff --git a/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__if_expr_1.snap b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__if_expr_1.snap new file mode 100644 index 000000000..d1fb2f6b6 --- /dev/null +++ b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__if_expr_1.snap @@ -0,0 +1,5 @@ +--- +source: evaluator/src/tests.rs +expression: "format!(\"{}\", evaluator.run().unwrap().1)" +--- +a: 0 diff --git a/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__if_expr_2.snap b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__if_expr_2.snap new file mode 100644 index 000000000..5e4bff410 --- /dev/null +++ b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__if_expr_2.snap @@ -0,0 +1,5 @@ +--- +source: evaluator/src/tests.rs +expression: "format!(\"{}\", evaluator.run().unwrap().1)" +--- +a: 2 diff --git a/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__if_stmt_0.snap b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__if_stmt_0.snap new file mode 100644 index 000000000..36e89bb3f --- /dev/null +++ b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__if_stmt_0.snap @@ -0,0 +1,5 @@ +--- +source: evaluator/src/tests.rs +expression: "format!(\"{}\", evaluator.run().unwrap().1)" +--- +a: 1 diff --git a/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__if_stmt_1.snap b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__if_stmt_1.snap new file mode 100644 index 000000000..b49088fc6 --- /dev/null +++ b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__if_stmt_1.snap @@ -0,0 +1,5 @@ +--- +source: evaluator/src/tests.rs +expression: "format!(\"{}\", evaluator.run().unwrap().1)" +--- +b: 2 diff --git a/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__if_stmt_3.snap b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__if_stmt_3.snap new file mode 100644 index 000000000..b49088fc6 --- /dev/null +++ b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__if_stmt_3.snap @@ -0,0 +1,5 @@ +--- +source: evaluator/src/tests.rs +expression: "format!(\"{}\", evaluator.run().unwrap().1)" +--- +b: 2 diff --git a/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__if_stmt_4.snap b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__if_stmt_4.snap new file mode 100644 index 000000000..fb00bbfd6 --- /dev/null +++ b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__if_stmt_4.snap @@ -0,0 +1,5 @@ +--- +source: evaluator/src/tests.rs +expression: "format!(\"{}\", evaluator.run().unwrap().1)" +--- +c: 3 diff --git a/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__if_stmt_5.snap b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__if_stmt_5.snap new file mode 100644 index 000000000..b49088fc6 --- /dev/null +++ b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__if_stmt_5.snap @@ -0,0 +1,5 @@ +--- +source: evaluator/src/tests.rs +expression: "format!(\"{}\", evaluator.run().unwrap().1)" +--- +b: 2 diff --git a/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__if_stmt_6.snap b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__if_stmt_6.snap new file mode 100644 index 000000000..fe81f5423 --- /dev/null +++ b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__if_stmt_6.snap @@ -0,0 +1,6 @@ +--- +source: evaluator/src/tests.rs +expression: "format!(\"{}\", evaluator.run().unwrap().1)" +--- +b: 1 +c: 1 diff --git a/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__if_stmt_7.snap b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__if_stmt_7.snap new file mode 100644 index 000000000..afb873c8d --- /dev/null +++ b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__if_stmt_7.snap @@ -0,0 +1,7 @@ +--- +source: evaluator/src/tests.rs +expression: "format!(\"{}\", evaluator.run().unwrap().1)" +--- +a: 3 +c: + a: 3 diff --git a/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__if_stmt_8.snap b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__if_stmt_8.snap new file mode 100644 index 000000000..10f5ca505 --- /dev/null +++ b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__if_stmt_8.snap @@ -0,0 +1,9 @@ +--- +source: evaluator/src/tests.rs +expression: "format!(\"{}\", evaluator.run().unwrap().1)" +--- +items: +- key2: value2 +c: + items: + - key2: value2 diff --git a/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__import_stmt_0.snap b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__import_stmt_0.snap new file mode 100644 index 000000000..36e89bb3f --- /dev/null +++ b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__import_stmt_0.snap @@ -0,0 +1,5 @@ +--- +source: evaluator/src/tests.rs +expression: "format!(\"{}\", evaluator.run().unwrap().1)" +--- +a: 1 diff --git a/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__import_stmt_1.snap b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__import_stmt_1.snap new file mode 100644 index 000000000..b49088fc6 --- /dev/null +++ b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__import_stmt_1.snap @@ -0,0 +1,5 @@ +--- +source: evaluator/src/tests.rs +expression: "format!(\"{}\", evaluator.run().unwrap().1)" +--- +b: 2 diff --git a/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__import_stmt_2.snap b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__import_stmt_2.snap new file mode 100644 index 000000000..23788f0ea --- /dev/null +++ b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__import_stmt_2.snap @@ -0,0 +1,6 @@ +--- +source: evaluator/src/tests.rs +expression: "format!(\"{}\", evaluator.run().unwrap().1)" +--- +v: null +x: true diff --git a/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__import_stmt_3.snap b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__import_stmt_3.snap new file mode 100644 index 000000000..05da1a0b2 --- /dev/null +++ b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__import_stmt_3.snap @@ -0,0 +1,5 @@ +--- +source: evaluator/src/tests.rs +expression: "format!(\"{}\", evaluator.run().unwrap().1)" +--- +x: 2 diff --git a/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__lambda_0.snap b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__lambda_0.snap new file mode 100644 index 000000000..8ab678285 --- /dev/null +++ b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__lambda_0.snap @@ -0,0 +1,6 @@ +--- +source: evaluator/src/tests.rs +expression: "format!(\"{}\", evaluator.run().unwrap().1)" +--- +a: 2 +b: 4 diff --git a/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__lambda_1.snap b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__lambda_1.snap new file mode 100644 index 000000000..8ab678285 --- /dev/null +++ b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__lambda_1.snap @@ -0,0 +1,6 @@ +--- +source: evaluator/src/tests.rs +expression: "format!(\"{}\", evaluator.run().unwrap().1)" +--- +a: 2 +b: 4 diff --git a/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__lambda_2.snap b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__lambda_2.snap new file mode 100644 index 000000000..e4e42ff0f --- /dev/null +++ b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__lambda_2.snap @@ -0,0 +1,7 @@ +--- +source: evaluator/src/tests.rs +expression: "format!(\"{}\", evaluator.run().unwrap().1)" +--- +a: 2 +b: 3 +c: 2 diff --git a/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__lambda_3.snap b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__lambda_3.snap new file mode 100644 index 000000000..05da1a0b2 --- /dev/null +++ b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__lambda_3.snap @@ -0,0 +1,5 @@ +--- +source: evaluator/src/tests.rs +expression: "format!(\"{}\", evaluator.run().unwrap().1)" +--- +x: 2 diff --git a/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__lambda_4.snap b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__lambda_4.snap new file mode 100644 index 000000000..536a7cb4e --- /dev/null +++ b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__lambda_4.snap @@ -0,0 +1,5 @@ +--- +source: evaluator/src/tests.rs +expression: "format!(\"{}\", evaluator.run().unwrap().1)" +--- +x: 6 diff --git a/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__lambda_5.snap b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__lambda_5.snap new file mode 100644 index 000000000..2301a537b --- /dev/null +++ b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__lambda_5.snap @@ -0,0 +1,6 @@ +--- +source: evaluator/src/tests.rs +expression: "format!(\"{}\", evaluator.run().unwrap().1)" +--- +x: + value: 4 diff --git a/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__lazy_scope_0.snap b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__lazy_scope_0.snap new file mode 100644 index 000000000..79c9ffcea --- /dev/null +++ b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__lazy_scope_0.snap @@ -0,0 +1,7 @@ +--- +source: evaluator/src/tests.rs +expression: "format!(\"{}\", evaluator.run().unwrap().1)" +--- +b: 3 +a: 1 +c: 2 diff --git a/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__lazy_scope_1.snap b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__lazy_scope_1.snap new file mode 100644 index 000000000..88f118d5c --- /dev/null +++ b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__lazy_scope_1.snap @@ -0,0 +1,8 @@ +--- +source: evaluator/src/tests.rs +expression: "format!(\"{}\", evaluator.run().unwrap().1)" +--- +data: + b: 3 + a: 1 + c: 2 diff --git a/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__lazy_scope_2.snap b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__lazy_scope_2.snap new file mode 100644 index 000000000..0841b0bf1 --- /dev/null +++ b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__lazy_scope_2.snap @@ -0,0 +1,10 @@ +--- +source: evaluator/src/tests.rs +expression: "format!(\"{}\", evaluator.run().unwrap().1)" +--- +data1: + name: '1' +data2: + name: '1' + version: v0.1.0 +version: v0.1.0 diff --git a/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__list_comp1.snap b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__list_comp1.snap new file mode 100644 index 000000000..07d14f179 --- /dev/null +++ b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__list_comp1.snap @@ -0,0 +1,7 @@ +--- +source: evaluator/src/tests.rs +expression: "format! (\"{}\", evaluator.run().unwrap().1)" +--- +a: +- 你 +- 好 diff --git a/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__list_expr_0.snap b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__list_expr_0.snap new file mode 100644 index 000000000..6c52f64c4 --- /dev/null +++ b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__list_expr_0.snap @@ -0,0 +1,19 @@ +--- +source: evaluator/src/tests.rs +expression: "format!(\"{}\", evaluator.run().unwrap().1)" +--- +a: +- 1 +- 2 +- 3 +b: +- 1 +- 2 +- 3 +c: +- 1 +- 3 +d: +- 1 +- 2 +- 3 diff --git a/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__literal_0.snap b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__literal_0.snap new file mode 100644 index 000000000..e6371b1b8 --- /dev/null +++ b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__literal_0.snap @@ -0,0 +1,7 @@ +--- +source: evaluator/src/tests.rs +expression: "format!(\"{}\", evaluator.run().unwrap().1)" +--- +longStringStartWithNewline: | + This is the second line + This is the third line diff --git a/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__literal_1.snap b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__literal_1.snap new file mode 100644 index 000000000..007822861 --- /dev/null +++ b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__literal_1.snap @@ -0,0 +1,7 @@ +--- +source: evaluator/src/tests.rs +expression: "format!(\"{}\", evaluator.run().unwrap().1)" +--- +a: + k: v +b: '{"k": "v"}' diff --git a/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__literal_2.snap b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__literal_2.snap new file mode 100644 index 000000000..09411b88c --- /dev/null +++ b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__literal_2.snap @@ -0,0 +1,6 @@ +--- +source: evaluator/src/tests.rs +expression: "format!(\"{}\", evaluator.run().unwrap().1)" +--- +a: 1048576.0 +b: 2000.0 diff --git a/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__loop_0.snap b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__loop_0.snap new file mode 100644 index 000000000..60fa5c9b3 --- /dev/null +++ b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__loop_0.snap @@ -0,0 +1,8 @@ +--- +source: evaluator/src/tests.rs +expression: "format!(\"{}\", evaluator.run().unwrap().1)" +--- +a: +- 1 +- 4 +- 9 diff --git a/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__loop_1.snap b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__loop_1.snap new file mode 100644 index 000000000..4940f8f17 --- /dev/null +++ b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__loop_1.snap @@ -0,0 +1,8 @@ +--- +source: evaluator/src/tests.rs +expression: "format!(\"{}\", evaluator.run().unwrap().1)" +--- +a: +- 3 +- 4 +- 5 diff --git a/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__paren_expr_0.snap b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__paren_expr_0.snap new file mode 100644 index 000000000..bb3e7496e --- /dev/null +++ b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__paren_expr_0.snap @@ -0,0 +1,6 @@ +--- +source: evaluator/src/tests.rs +expression: "format!(\"{}\", evaluator.run().unwrap().1)" +--- +a: 4 +b: 4 diff --git a/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__quant_expr_0.snap b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__quant_expr_0.snap new file mode 100644 index 000000000..d7b389385 --- /dev/null +++ b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__quant_expr_0.snap @@ -0,0 +1,5 @@ +--- +source: evaluator/src/tests.rs +expression: "format!(\"{}\", evaluator.run().unwrap().1)" +--- +b: true diff --git a/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__quant_expr_1.snap b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__quant_expr_1.snap new file mode 100644 index 000000000..d7b389385 --- /dev/null +++ b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__quant_expr_1.snap @@ -0,0 +1,5 @@ +--- +source: evaluator/src/tests.rs +expression: "format!(\"{}\", evaluator.run().unwrap().1)" +--- +b: true diff --git a/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__quant_expr_2.snap b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__quant_expr_2.snap new file mode 100644 index 000000000..21f291ddd --- /dev/null +++ b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__quant_expr_2.snap @@ -0,0 +1,5 @@ +--- +source: evaluator/src/tests.rs +expression: "format!(\"{}\", evaluator.run().unwrap().1)" +--- +b: false diff --git a/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__quant_expr_3.snap b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__quant_expr_3.snap new file mode 100644 index 000000000..21f291ddd --- /dev/null +++ b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__quant_expr_3.snap @@ -0,0 +1,5 @@ +--- +source: evaluator/src/tests.rs +expression: "format!(\"{}\", evaluator.run().unwrap().1)" +--- +b: false diff --git a/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__quant_expr_4.snap b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__quant_expr_4.snap new file mode 100644 index 000000000..5134cc404 --- /dev/null +++ b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__quant_expr_4.snap @@ -0,0 +1,8 @@ +--- +source: evaluator/src/tests.rs +expression: "format!(\"{}\", evaluator.run().unwrap().1)" +--- +b: +- 2 +- 3 +- 4 diff --git a/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__quant_expr_5.snap b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__quant_expr_5.snap new file mode 100644 index 000000000..d2a641e73 --- /dev/null +++ b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__quant_expr_5.snap @@ -0,0 +1,7 @@ +--- +source: evaluator/src/tests.rs +expression: "format!(\"{}\", evaluator.run().unwrap().1)" +--- +b: +- 2 +- 3 diff --git a/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__quant_expr_6.snap b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__quant_expr_6.snap new file mode 100644 index 000000000..a131910c6 --- /dev/null +++ b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__quant_expr_6.snap @@ -0,0 +1,8 @@ +--- +source: evaluator/src/tests.rs +expression: "format!(\"{}\", evaluator.run().unwrap().1)" +--- +b: +- 1 +- 4 +- 9 diff --git a/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__quant_expr_7.snap b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__quant_expr_7.snap new file mode 100644 index 000000000..0a75719c6 --- /dev/null +++ b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__quant_expr_7.snap @@ -0,0 +1,5 @@ +--- +source: evaluator/src/tests.rs +expression: "format!(\"{}\", evaluator.run().unwrap().1)" +--- +b: [] diff --git a/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__schema_0.snap b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__schema_0.snap new file mode 100644 index 000000000..07d05c98a --- /dev/null +++ b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__schema_0.snap @@ -0,0 +1,10 @@ +--- +source: evaluator/src/tests.rs +expression: "format!(\"{}\", evaluator.run().unwrap().1)" +--- +alice: + name: Alice + age: 10 +bob: + name: Bob + age: 18 diff --git a/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__schema_1.snap b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__schema_1.snap new file mode 100644 index 000000000..07d05c98a --- /dev/null +++ b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__schema_1.snap @@ -0,0 +1,10 @@ +--- +source: evaluator/src/tests.rs +expression: "format!(\"{}\", evaluator.run().unwrap().1)" +--- +alice: + name: Alice + age: 10 +bob: + name: Bob + age: 18 diff --git a/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__schema_2.snap b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__schema_2.snap new file mode 100644 index 000000000..43c6b8277 --- /dev/null +++ b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__schema_2.snap @@ -0,0 +1,15 @@ +--- +source: evaluator/src/tests.rs +expression: "format!(\"{}\", evaluator.run().unwrap().1)" +--- +VALUES_MAP: + '1': + attr1: foobar + '2': + attr2: bar +config: + provider: '1' + values: + attr1: foobar + provider_values: + attr1: foobar diff --git a/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__selector_expr_0.snap b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__selector_expr_0.snap new file mode 100644 index 000000000..81597c887 --- /dev/null +++ b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__selector_expr_0.snap @@ -0,0 +1,7 @@ +--- +source: evaluator/src/tests.rs +expression: "format!(\"{}\", evaluator.run().unwrap().1)" +--- +a: v +b: v +c: null diff --git a/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__selector_expr_1.snap b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__selector_expr_1.snap new file mode 100644 index 000000000..d133972ec --- /dev/null +++ b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__selector_expr_1.snap @@ -0,0 +1,11 @@ +--- +source: evaluator/src/tests.rs +expression: "format!(\"{}\", evaluator.run().unwrap().1)" +--- +a: +- 3 +- 2 +- 1 +b: 1 +c: 3 +d: null diff --git a/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__subscript_expr_0.snap b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__subscript_expr_0.snap new file mode 100644 index 000000000..ae5e13d61 --- /dev/null +++ b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__subscript_expr_0.snap @@ -0,0 +1,10 @@ +--- +source: evaluator/src/tests.rs +expression: "format!(\"{}\", evaluator.run().unwrap().1)" +--- +a: +- 3 +- 2 +- 1 +b: 1 +c: 3 diff --git a/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__subscript_expr_1.snap b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__subscript_expr_1.snap new file mode 100644 index 000000000..d133972ec --- /dev/null +++ b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__subscript_expr_1.snap @@ -0,0 +1,11 @@ +--- +source: evaluator/src/tests.rs +expression: "format!(\"{}\", evaluator.run().unwrap().1)" +--- +a: +- 3 +- 2 +- 1 +b: 1 +c: 3 +d: null diff --git a/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__unary_expr_0.snap b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__unary_expr_0.snap new file mode 100644 index 000000000..36e89bb3f --- /dev/null +++ b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__unary_expr_0.snap @@ -0,0 +1,5 @@ +--- +source: evaluator/src/tests.rs +expression: "format!(\"{}\", evaluator.run().unwrap().1)" +--- +a: 1 diff --git a/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__unary_expr_1.snap b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__unary_expr_1.snap new file mode 100644 index 000000000..78fdeb343 --- /dev/null +++ b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__unary_expr_1.snap @@ -0,0 +1,5 @@ +--- +source: evaluator/src/tests.rs +expression: "format!(\"{}\", evaluator.run().unwrap().1)" +--- +a: -1 diff --git a/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__unary_expr_2.snap b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__unary_expr_2.snap new file mode 100644 index 000000000..d38bc7238 --- /dev/null +++ b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__unary_expr_2.snap @@ -0,0 +1,5 @@ +--- +source: evaluator/src/tests.rs +expression: "format!(\"{}\", evaluator.run().unwrap().1)" +--- +a: -2 diff --git a/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__unary_expr_3.snap b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__unary_expr_3.snap new file mode 100644 index 000000000..dc5414160 --- /dev/null +++ b/kclvm/evaluator/src/snapshots/kclvm_evaluator__tests__unary_expr_3.snap @@ -0,0 +1,5 @@ +--- +source: evaluator/src/tests.rs +expression: "format!(\"{}\", evaluator.run().unwrap().1)" +--- +a: true diff --git a/kclvm/evaluator/src/tests.rs b/kclvm/evaluator/src/tests.rs new file mode 100644 index 000000000..992728a9f --- /dev/null +++ b/kclvm/evaluator/src/tests.rs @@ -0,0 +1,606 @@ +use crate::Evaluator; +use kclvm_ast::MAIN_PKG; +use kclvm_loader::{load_packages, LoadPackageOptions}; +use kclvm_parser::LoadProgramOptions; +use kclvm_runtime::{Context, ValueRef}; + +#[macro_export] +macro_rules! evaluator_snapshot { + ($name:ident, $src:expr) => { + #[test] + fn $name() { + let p = load_packages(&LoadPackageOptions { + paths: vec!["test.k".to_string()], + load_opts: Some(LoadProgramOptions { + k_code_list: vec![$src.to_string()], + ..Default::default() + }), + load_builtin: false, + ..Default::default() + }) + .unwrap(); + let evaluator = Evaluator::new(&p.program); + insta::assert_snapshot!(format!("{}", evaluator.run().unwrap().1)); + } + }; +} + +#[macro_export] +macro_rules! evaluator_function_snapshot { + ($name:ident, $src:expr) => { + #[test] + fn $name() { + let p = load_packages(&LoadPackageOptions { + paths: vec!["test.k".to_string()], + load_opts: Some(LoadProgramOptions { + k_code_list: vec![$src.to_string()], + ..Default::default() + }), + load_builtin: false, + ..Default::default() + }) + .unwrap(); + let evaluator = Evaluator::new(&p.program); + insta::assert_snapshot!(format!("{}", evaluator.run_as_function().to_string())); + } + }; +} + +evaluator_function_snapshot! {function_stmt_0, r#" +import json + +config = { + foo: "bar" +} + +json.encode("${config.foo}") +"#} + +evaluator_snapshot! {expr_stmt_0, "1"} +evaluator_snapshot! {expr_stmt_1, "2.0"} +evaluator_snapshot! {expr_stmt_2, "True"} +evaluator_snapshot! {expr_stmt_3, r#"None"#} +evaluator_snapshot! {expr_stmt_4, r#"[1, 2, 3]"#} +evaluator_snapshot! {expr_stmt_5, r#"{k = "v"}"#} + +evaluator_snapshot! {assign_stmt_0, "a = 1"} +evaluator_snapshot! {assign_stmt_1, "a = 1 + 1"} +evaluator_snapshot! {assign_stmt_2, "a = (1 + 2)"} +evaluator_snapshot! {assign_stmt_3, r#"a = 1 +b = a + 1 +"#} +evaluator_snapshot! {assign_stmt_4, r#"a: int = 1 +b: int = a + 1 +"#} +evaluator_snapshot! {assign_stmt_5, r#"_a = [0] * 2 +_a[0] = 1 +a = _a +"#} +evaluator_snapshot! {assign_stmt_6, r#"_a = [{"key": 0}] * 2 +_a[0].key = 1 +a = _a +"#} +evaluator_snapshot! {assign_stmt_7, r#"_a = [{key.key = [0] * 2}] * 2 +_a[0].key.key[0] = 1 +a = _a +"#} + +evaluator_snapshot! {aug_assign_stmt_0, r#"_a = 1 +_a += 1 +a = _a +"#} +evaluator_snapshot! {aug_assign_stmt_1, r#"_a = 1 +_a -= 1 +a = _a +"#} +evaluator_snapshot! {aug_assign_stmt_2, r#"_a = 1 +_a *= 2 +a = _a +"#} +evaluator_snapshot! {aug_assign_stmt_3, r#"_a = 2 +_a /= 2 +a = _a +"#} +evaluator_snapshot! {aug_assign_stmt_4, r#"_a = 3 +_a %= 2 +a = _a +"#} +evaluator_snapshot! {aug_assign_stmt_5, r#"_a = 3 +_a **= 2 +a = _a +"#} +evaluator_snapshot! {aug_assign_stmt_6, r#"_a = 3 +_a <<= 1 +a = _a +"#} +evaluator_snapshot! {aug_assign_stmt_7, r#"_a = 3 +_a >>= 1 +a = _a +"#} +evaluator_snapshot! {aug_assign_stmt_8, r#"_a = 3 +_a |= 1 +a = _a +"#} +evaluator_snapshot! {aug_assign_stmt_9, r#"_a = 3 +_a ^= 1 +a = _a +"#} +evaluator_snapshot! {aug_assign_stmt_10, r#"_a = 3 +_a &= 1 +a = _a +"#} +evaluator_snapshot! {aug_assign_stmt_11, r#"_a = 3 +_a //= 2 +a = _a +"#} +evaluator_snapshot! {aug_assign_stmt_12, r#"_a = [0] * 5 +_a[0] += 1 +a = _a +"#} +evaluator_snapshot! {aug_assign_stmt_13, r#"_a = [{"key": 1}] * 5 +_a[0].key += 1 +a = _a +"#} +evaluator_snapshot! {aug_assign_stmt_14, r#"_a = [{key.key = [0, 0]}] * 5 +_a[0].key.key[0] += 1 +a = _a +"#} + +evaluator_snapshot! {assert_stmt_0, r#"assert True, "msg" +a = 1 +"#} + +evaluator_snapshot! {assert_stmt_1, r#"assert False if False, "msg" +a = 1 +"#} + +evaluator_snapshot! {if_stmt_0, r#"if True: + a = 1 +else: + b = 2 +"#} +evaluator_snapshot! {if_stmt_1, r#"if False: + a = 1 +else: + b = 2 +"#} +evaluator_snapshot! {if_stmt_3, r#"if False: + a = 1 +elif True: + b = 2 +else: + c = 3 +"#} +evaluator_snapshot! {if_stmt_4, r#"if False: + a = 1 +elif False: + b = 2 +else: + c = 3 +"#} +evaluator_snapshot! {if_stmt_5, r#"if False: + a = 1 +else: + if True: + b = 2 + else: + c = 3 +"#} +evaluator_snapshot! {if_stmt_6, r#" +if False: + a = 1 +else: + if True: + b = 1 + if True: + c = 1 +"#} +evaluator_snapshot! {if_stmt_7, r#" +_a = 1 +if True: + _a = 2 + _a += 1 +a = _a + +schema Config: + _a = 1 + if True: + _a = 2 + _a += 1 + a = _a + +c = Config {} +"#} +evaluator_snapshot! {if_stmt_8, r#" +_items = [] +if False: + _items += [ {key1 = "value1"} ] +if True: + _items += [ {key2 = "value2"} ] +items = _items + +schema Config: + _items = [] + if False: + _items += [ {key1 = "value1"} ] + if True: + _items += [ {key2 = "value2"} ] + items = _items + +c = Config {} +"#} + +evaluator_snapshot! {import_stmt_0, r#"import math +a = 1 +"#} +evaluator_snapshot! {import_stmt_1, r#"import math +import math +b = 2 +"#} +evaluator_snapshot! {import_stmt_2, r#" +import regex + +v = option("foo") +x = regex.match("foo", "^\\w+$") +"#} +evaluator_snapshot! {import_stmt_3, r#"import math + +x = math.log(10) +"#} + +evaluator_snapshot! {quant_expr_0, r#"b = all a in [1, 2, 3] { + a > 0 +} +"#} +evaluator_snapshot! {quant_expr_1, r#"b = any a in [1, 2, 3] { + a > 2 +} +"#} +evaluator_snapshot! {quant_expr_2, r#"b = all a in [1, 2, 3] { + a > 5 +} +"#} +evaluator_snapshot! {quant_expr_3, r#"b = any a in [1, 2, 3] { + a > 5 +} +"#} +evaluator_snapshot! {quant_expr_4, r#"b = map a in [1, 2, 3] { + a + 1 +} +"#} +evaluator_snapshot! {quant_expr_5, r#"b = filter a in [1, 2, 3] { + a > 1 +} +"#} +evaluator_snapshot! {quant_expr_6, r#"b = map a in [1, 2, 3] { + a ** 2 +} +"#} +evaluator_snapshot! {quant_expr_7, r#"b = filter a in [1, 2, 3] { + a == 0 +} +"#} + +evaluator_snapshot! {if_expr_0, r#"a = 1 if True else 0"#} +evaluator_snapshot! {if_expr_1, r#"a = 1 if False else 0"#} +evaluator_snapshot! {if_expr_2, r#"a = 1 if False else 0 if False else 2"#} + +evaluator_snapshot! {unary_expr_0, r#"a = +1"#} +evaluator_snapshot! {unary_expr_1, r#"a = -1"#} +evaluator_snapshot! {unary_expr_2, r#"a = ~1"#} +evaluator_snapshot! {unary_expr_3, r#"a = not None"#} + +evaluator_snapshot! {binary_expr_0, r#"a = 1 + 1 * 2 - 4"#} +evaluator_snapshot! {binary_expr_1, r#"a = None or {} +b = [] and {} +"#} + +evaluator_snapshot! {selector_expr_0, r#"a = {k = "v"}.k +b = {k = "v"}?.k +c = None?.k +"#} +evaluator_snapshot! {selector_expr_1, r#"a = [1, 2, 3]?[::-1] +b = a?[-1] +c = a?[0] +d = None?[1] +"#} + +evaluator_snapshot! {subscript_expr_0, r#"a = [1, 2, 3][::-1] +b = a[-1] +c = a[0] +"#} +evaluator_snapshot! {subscript_expr_1, r#"a = [1, 2, 3]?[::-1] +b = a?[-1] +c = a?[0] +d = None?[1] +"#} + +evaluator_snapshot! {compare_expr_0, r#"a = 1 < 10 +b = 1 < 10 < 100 +c = 1 > 10 > 100 +d = 1 < 10 > 100 +"#} + +evaluator_snapshot! {paren_expr_0, r#"a = 2 * (1 + 1) +b = (((1 + 1))) * 2 +"#} + +evaluator_snapshot! {list_expr_0, r#"a = [1, 2, 3] +b = [1, if True: 2, 3] +c = [1, if False: 2, 3] +d = [1, *[2, 3]] +"#} + +evaluator_snapshot! {dict_expr_0, r#"a = {k1 = "v1", k2 = "v2"} +b = {k1 = "v1", if True: k2 = "v2"} +c = {k1 = "v1", if False: k2 = "v2"} +d = {k1 = "v1", **{k2 = "v2"}} +"#} + +evaluator_snapshot! {loop_0, r#"a = [i ** 2 for i in [1, 2, 3]]"#} +evaluator_snapshot! {loop_1, r#"a = [i + j for i in [1, 2, 3] for j in [1, 2, 3] if i < j]"#} + +evaluator_snapshot! {literal_0, r#"longStringStartWithNewline = """\ +This is the second line +This is the third line +""" +"#} +evaluator_snapshot! {literal_1, r#"a = {k = "v"} +b = "${a: #json}" +"#} +evaluator_snapshot! {literal_2, r#"a = 1Mi +b = 2K +"#} + +evaluator_snapshot! {lambda_0, r#"f = lambda x {x * 2} +a = f(1) +b = f(2) +"#} +evaluator_snapshot! {lambda_1, r#"a = lambda x {x * 2}(1) +b = lambda x {x * 2}(2) +"#} +evaluator_snapshot! {lambda_2, r#"import math +a = math.log(10) +b = len("abc") +c = len([1, 2]) +"#} +evaluator_snapshot! {lambda_3, r#" +x = lambda { + a = 1 + lambda { + a + 1 + }() +}() +"#} +evaluator_snapshot! {lambda_4, r#" +x = lambda { + a = 1 + b = 2 + lambda x { + a + b + x + }(3) +}() +"#} +evaluator_snapshot! {lambda_5, r#" +func = lambda config: {str:} { + x = 1 + lambda { + y = 1 + lambda { + z = 1 + lambda { + {value = x + y + z + config.key} + }() + }() + }() +} + +x = func({key = 1}) +"#} + +evaluator_snapshot! {schema_0, r#" +schema Person: + name: str = "Alice" + age: int = 10 + +alice = Person {} +bob = Person { + name = "Bob" + age = 18 +} +"#} +evaluator_snapshot! {schema_1, r#" +schema Person: + name: str = "Alice" + age: int = 10 + +alice: Person {} +bob: Person { + name: "Bob" + age: 18 +} +"#} +evaluator_snapshot! {schema_2, r#" +VALUES_MAP = { + "1": Values1{ + attr1 = "foo" + } + "2": Values2 { + attr2 = "bar" + } +} + +schema Config: + provider: "1" | "2" + values = VALUES_MAP[provider] + provider_values: Values1 | Values2 = values + +schema CommonValues: + +schema Values1(CommonValues): + attr1: str + +schema Values2(CommonValues): + attr2: str + +config: Config { + provider = "1" + provider_values.attr1 = "foobar" +} +"#} +evaluator_snapshot! {lazy_scope_0, r#" +b = a + c +a = 1 +c = a + 1 +"#} +evaluator_snapshot! {lazy_scope_1, r#" +schema Data: + b = a + c + a = 1 + c = a + 1 + +data = Data {} +"#} +evaluator_snapshot! {lazy_scope_2, r#" +schema Data: + name: str + version?: str + +data1 = Data { + name = data2.name +} + +data2 = Data { + name = "1" + version = version +} + +version = "v0.1.0" +"#} + +evaluator_snapshot! {list_comp1, r#" +a = [ x for x in "你好"] +"#} + +#[test] +fn test_if_stmt_setters() { + let p = load_packages(&LoadPackageOptions { + paths: vec!["test.k".to_string()], + load_opts: Some(LoadProgramOptions { + k_code_list: vec![r#" + _a = 1 + if True: + _a += 1 + elif False: + _a += 1 + a=_a + "# + .to_string()], + ..Default::default() + }), + load_builtin: false, + ..Default::default() + }) + .unwrap(); + let evaluator = Evaluator::new(&p.program); + evaluator.run().unwrap(); + let scopes = evaluator.lazy_scopes.borrow(); + let var_setters = scopes.get(MAIN_PKG).unwrap().setters.get("_a").unwrap(); + assert_eq!(var_setters.len(), 3); +} + +use std::cell::RefCell; +use std::rc::Rc; +use std::sync::Arc; +use std::thread; + +const MULTI_THREAD_SOURCE: &str = r#" +import regex +foo = option("foo") +bar = option("bar") +x = regex.match("", "") +"#; + +#[test] +fn test_multithread_exec() { + let threads = 10; + multithread_check(threads, |thread| { + println!("run: {}", thread); + for _ in 0..1000 { + run_code(MULTI_THREAD_SOURCE); + } + println!("done: {}", thread); + }); +} + +fn multithread_check(threads: i32, check: impl Fn(i32) + Send + Sync + 'static) { + let check_shared = Arc::new(check); + let mut handles = vec![]; + for thread in 0..threads { + let check_shared = Arc::clone(&check_shared); + let handle = thread::spawn(move || { + check_shared(thread); + }); + handles.push(handle); + } + for handle in handles { + handle.join().unwrap(); + } +} + +fn run_code(source: &str) -> (String, String) { + let p = load_packages(&LoadPackageOptions { + paths: vec!["test.k".to_string()], + load_opts: Some(LoadProgramOptions { + k_code_list: vec![source.to_string()], + ..Default::default() + }), + load_builtin: false, + ..Default::default() + }) + .unwrap(); + let evaluator = Evaluator::new(&p.program); + evaluator.run().unwrap() +} + +fn testing_sum(_: &Context, args: &ValueRef, _: &ValueRef) -> anyhow::Result { + let a = args + .arg_i_int(0, Some(0)) + .ok_or(anyhow::anyhow!("expect int value for the first param"))?; + let b = args + .arg_i_int(1, Some(0)) + .ok_or(anyhow::anyhow!("expect int value for the second param"))?; + Ok((a + b).into()) +} + +fn context_with_plugin() -> Rc> { + let mut plugin_functions: kclvm_runtime::IndexMap = + Default::default(); + let func = Arc::new(testing_sum); + plugin_functions.insert("testing.add".to_string(), func); + let mut ctx = Context::new(); + ctx.plugin_functions = plugin_functions; + Rc::new(RefCell::new(ctx)) +} + +#[test] +fn test_exec_with_plugin() { + let src = r#" +import kcl_plugin.testing + +sum = testing.add(1, 1) +"#; + let p = load_packages(&LoadPackageOptions { + paths: vec!["test.k".to_string()], + load_opts: Some(LoadProgramOptions { + load_plugins: true, + k_code_list: vec![src.to_string()], + ..Default::default() + }), + load_builtin: false, + ..Default::default() + }) + .unwrap(); + let evaluator = Evaluator::new_with_runtime_ctx(&p.program, context_with_plugin()); + insta::assert_snapshot!(format!("{}", evaluator.run().unwrap().1)); +} diff --git a/kclvm/evaluator/src/ty.rs b/kclvm/evaluator/src/ty.rs new file mode 100644 index 000000000..6b7b694d3 --- /dev/null +++ b/kclvm/evaluator/src/ty.rs @@ -0,0 +1,220 @@ +use kclvm_runtime::{ + check_type, dereference_type, is_dict_type, is_list_type, is_type_union, schema_config_meta, + schema_runtime_type, separate_kv, split_type_union, val_plan, ConfigEntryOperationKind, + ValueRef, BUILTIN_TYPES, KCL_TYPE_ANY, PKG_PATH_PREFIX, +}; +use scopeguard::defer; + +use crate::error as kcl_error; +use crate::schema::SchemaEvalContext; +use crate::{proxy::Proxy, Evaluator}; + +/// Use the schema instance to build a new schema instance using the schema construct function +pub fn resolve_schema(s: &Evaluator, schema: &ValueRef, keys: &[String]) -> ValueRef { + if !schema.is_schema() { + return schema.clone(); + } + let schema_value = schema.as_schema(); + let schema_type_name = schema_runtime_type(&schema_value.name, &schema_value.pkgpath); + if let Some(index) = s.schemas.borrow().get(&schema_type_name) { + let keys = keys.iter().map(|v| v.as_str()).collect(); + let config_value = + schema.dict_get_entries_with_op(keys, &ConfigEntryOperationKind::Override); + let config_meta = { + let ctx = s.runtime_ctx.borrow(); + schema_config_meta( + &ctx.panic_info.kcl_file, + ctx.panic_info.kcl_line as u64, + ctx.panic_info.kcl_col as u64, + ) + }; + + let frame = { + let frames = s.frames.borrow(); + frames + .get(*index) + .expect(kcl_error::INTERNAL_ERROR_MSG) + .clone() + }; + let schema = if let Proxy::Schema(caller) = &frame.proxy { + s.push_pkgpath(&frame.pkgpath); + s.push_backtrace(&frame); + defer! { + s.pop_backtrace(); + s.pop_pkgpath(); + } + let value = (caller.body)( + s, + &caller.ctx.borrow().snapshot(config_value, config_meta), + &schema_value.args, + &schema_value.kwargs, + ); + value + } else { + schema.clone() + }; + return schema; + } + schema.clone() +} + +/// Type pack and check ValueRef with the expected type vector +pub fn type_pack_and_check( + s: &Evaluator, + value: &ValueRef, + expected_types: Vec<&str>, + strict: bool, +) -> ValueRef { + if value.is_none_or_undefined() || expected_types.is_empty() { + return value.clone(); + } + let is_schema = value.is_schema(); + let mut checked = false; + let mut converted_value = value.clone(); + let expected_type = &expected_types.join(" | ").replace('@', ""); + for tpe in expected_types { + if !is_schema { + converted_value = convert_collection_value(s, value, tpe); + } + // Runtime type check + checked = check_type( + &converted_value, + &s.runtime_ctx.borrow().panic_info.kcl_pkgpath, + tpe, + strict, + ); + if checked { + break; + } + } + if !checked { + panic!( + "expect {expected_type}, got {}", + val_plan::type_of(value, true) + ); + } + converted_value +} + +/// Convert collection value including dict/list to the potential schema +pub fn convert_collection_value(s: &Evaluator, value: &ValueRef, tpe: &str) -> ValueRef { + if tpe.is_empty() || tpe == KCL_TYPE_ANY { + return value.clone(); + } + let is_collection = value.is_list() || value.is_dict(); + let invalid_match_dict = is_dict_type(tpe) && !value.is_dict(); + let invalid_match_list = is_list_type(tpe) && !value.is_list(); + let invalid_match = invalid_match_dict || invalid_match_list; + if !is_collection || invalid_match { + return value.clone(); + } + // Convert a value to union types e.g., {a: 1} => A | B + if is_type_union(tpe) { + let types = split_type_union(tpe); + convert_collection_value_with_union_types(s, value, &types) + } else if is_dict_type(tpe) { + //let (key_tpe, value_tpe) = separate_kv(tpe); + let (_, value_tpe) = separate_kv(&dereference_type(tpe)); + let mut expected_dict = ValueRef::dict(None); + let dict_ref = value.as_dict_ref(); + expected_dict + .set_potential_schema_type(&dict_ref.potential_schema.clone().unwrap_or_default()); + for (k, v) in &dict_ref.values { + let expected_value = convert_collection_value(s, v, &value_tpe); + let op = dict_ref + .ops + .get(k) + .unwrap_or(&ConfigEntryOperationKind::Union); + let index = dict_ref.insert_indexs.get(k); + expected_dict.dict_update_entry(k, &expected_value, op, index) + } + expected_dict + } else if is_list_type(tpe) { + let expected_type = dereference_type(tpe); + let mut expected_list = ValueRef::list(None); + let list_ref = value.as_list_ref(); + for v in &list_ref.values { + let expected_value = convert_collection_value(s, v, &expected_type); + expected_list.list_append(&expected_value) + } + expected_list + } else if BUILTIN_TYPES.contains(&tpe) { + value.clone() + } else { + // Get the type form @pkg.Schema + let schema_type_name = if tpe.contains('.') { + if tpe.starts_with(PKG_PATH_PREFIX) { + tpe.to_string() + } else { + format!("{PKG_PATH_PREFIX}{tpe}") + } + } else { + format!("{}.{}", s.current_pkgpath(), tpe) + }; + if let Some(index) = s.schemas.borrow().get(&schema_type_name) { + let config_meta = { + let ctx = s.runtime_ctx.borrow(); + schema_config_meta( + &ctx.panic_info.kcl_file, + ctx.panic_info.kcl_line as u64, + ctx.panic_info.kcl_col as u64, + ) + }; + let frame = { + let frames = s.frames.borrow(); + frames + .get(*index) + .expect(kcl_error::INTERNAL_ERROR_MSG) + .clone() + }; + let schema = if let Proxy::Schema(caller) = &frame.proxy { + // Try convert the config to schema, if failed, return the config directly. + if !SchemaEvalContext::is_fit_config(s, &caller.ctx, value) { + return value.clone(); + } + s.push_pkgpath(&frame.pkgpath); + s.push_backtrace(&frame); + let value = (caller.body)( + s, + &caller.ctx.borrow().snapshot(value.clone(), config_meta), + &s.list_value(), + &s.dict_value(), + ); + s.pop_backtrace(); + s.pop_pkgpath(); + value + } else { + value.clone() + }; + // ctx.panic_info = now_panic_info; + return schema.clone(); + } + // ctx.panic_info = now_meta_info; + value.clone() + } +} + +/// Convert collection value including dict/list to the potential schema and return errors. +pub fn convert_collection_value_with_union_types( + s: &Evaluator, + value: &ValueRef, + types: &[&str], +) -> ValueRef { + if value.is_schema() { + value.clone() + } else { + for tpe in types { + // Try match every type and convert the value, if matched, return the value. + let value = convert_collection_value(s, value, tpe); + if check_type( + &value, + &s.runtime_ctx.borrow().panic_info.kcl_pkgpath, + tpe, + false, + ) { + return value; + } + } + value.clone() + } +} diff --git a/kclvm/evaluator/src/union.rs b/kclvm/evaluator/src/union.rs new file mode 100644 index 000000000..81cda4056 --- /dev/null +++ b/kclvm/evaluator/src/union.rs @@ -0,0 +1,384 @@ +//! Copyright The KCL Authors. All rights reserved. + +use crate::*; +use kclvm_runtime::unification::value_subsume; +use kclvm_runtime::{ + must_normalize_index, ConfigEntryOperationKind, DictValue, UnionContext, UnionOptions, Value, +}; + +use self::ty::resolve_schema; + +fn do_union( + s: &Evaluator, + p: &mut ValueRef, + x: &ValueRef, + opts: &UnionOptions, + union_context: &mut UnionContext, +) -> ValueRef { + if p.is_same_ref(x) { + return p.clone(); + } + + let mut union_fn = |obj: &mut DictValue, delta: &DictValue| { + // Update potential schema type + obj.potential_schema = delta.potential_schema.clone(); + // Update attribute map + for (k, v) in &delta.ops { + obj.ops.insert(k.clone(), v.clone()); + } + // Update index map + for (k, v) in &delta.insert_indexs { + obj.insert_indexs.insert(k.clone(), *v); + } + // Update values + for (k, v) in &delta.values { + let operation = if let Some(op) = delta.ops.get(k) { + op + } else { + &ConfigEntryOperationKind::Union + }; + let index = delta.insert_indexs.get(k); + if !obj.values.contains_key(k) && index.is_none() { + obj.values.insert(k.clone(), v.clone()); + } else { + match operation { + ConfigEntryOperationKind::Union => match index { + Some(index) => { + let index = *index; + if let Some(origin_value) = obj.values.get_mut(k) { + if !origin_value.is_list() { + panic!( + "only list attribute can be union value with the index {}", + index + ); + } + let value = origin_value.list_get(index as isize); + if let Some(mut value) = value { + if opts.idempotent_check && !value_subsume(v, &value, false) { + union_context.conflict = true; + union_context + .path_backtrace + .push(format!("{}[{}]", k, index)); + union_context.obj_json = if value.is_config() { + "{...}".to_string() + } else if value.is_list() { + "[...]".to_string() + } else { + value.to_json_string() + }; + + union_context.delta_json = if v.is_config() { + "{...}".to_string() + } else if v.is_list() { + "[...]".to_string() + } else { + v.to_json_string() + }; + return; + } + let union_value = + union(s, &mut value, v, false, opts, union_context); + if union_context.conflict { + union_context.path_backtrace.push(k.clone()); + return; + } + let index = must_normalize_index(index, origin_value.len()); + origin_value.list_set(index, &union_value); + } else { + panic!("only non-empty list attribute can be union value with the index {}", index); + } + } else { + panic!("only non-empty list attribute can be union value with the index {}", index); + } + } + None => { + if let Some(obj_value) = obj.values.get_mut(k) { + if opts.idempotent_check && !value_subsume(v, obj_value, false) { + union_context.conflict = true; + union_context.path_backtrace.push(k.clone()); + union_context.obj_json = if obj_value.is_config() { + "{...}".to_string() + } else if obj_value.is_list() { + "[...]".to_string() + } else { + obj_value.to_json_string() + }; + + union_context.delta_json = if v.is_config() { + "{...}".to_string() + } else if v.is_list() { + "[...]".to_string() + } else { + v.to_json_string() + }; + return; + } + union(s, obj_value, v, false, opts, union_context); + if union_context.conflict { + union_context.path_backtrace.push(k.clone()); + return; + } + } else { + obj.values.insert(k.clone(), v.clone()); + } + } + }, + ConfigEntryOperationKind::Override => { + match index { + Some(index) => { + let index = *index; + let origin_value = obj.values.get_mut(k); + if let Some(origin_value) = origin_value { + if !origin_value.is_list() { + panic!("only list attribute can be override value with the index {}", index); + } + let index = must_normalize_index(index, origin_value.len()); + if v.is_undefined() { + origin_value.list_remove_at(index as usize); + } else { + origin_value.list_must_set(index as usize, v); + } + } else { + panic!("only list attribute can be override value with the index {}", index); + } + } + None => { + obj.values.insert(k.clone(), v.clone()); + } + } + } + ConfigEntryOperationKind::Insert => { + let origin_value = obj.values.get_mut(k); + if origin_value.is_none() || origin_value.unwrap().is_none_or_undefined() { + let list = ValueRef::list(None); + obj.values.insert(k.to_string(), list); + } + let origin_value = obj.values.get_mut(k).unwrap(); + if origin_value.is_same_ref(v) { + continue; + } + match (&mut *origin_value.rc.borrow_mut(), &*v.rc.borrow()) { + (Value::list_value(origin_value), Value::list_value(value)) => { + match index { + Some(index) => { + let index = *index; + let mut insert_index = + must_normalize_index(index, origin_value.values.len()); + for v in &value.values { + origin_value.values.insert(insert_index, v.clone()); + insert_index += 1; + } + } + None => { + for elem in value.values.iter() { + origin_value.values.push(elem.clone()); + } + } + } + } + _ => panic!( + "only list attribute can be inserted value, the origin value type is {} and got value type is {}", + origin_value.type_str(), v.type_str() + ), + }; + } + } + } + } + }; + + // Whether to union schema vars and resolve it and do the check of schema. + let mut union_schema = false; + let mut pkgpath: String = "".to_string(); + let mut name: String = "".to_string(); + let mut common_keys: Vec = vec![]; + let mut args = None; + let mut kwargs = None; + let mut valid = true; + match (&mut *p.rc.borrow_mut(), &*x.rc.borrow()) { + (Value::list_value(obj), Value::list_value(delta)) => { + if !opts.list_override { + let length = if obj.values.len() > delta.values.len() { + obj.values.len() + } else { + delta.values.len() + }; + let obj_len = obj.values.len(); + let delta_len = delta.values.len(); + for idx in 0..length { + if idx >= obj_len { + obj.values.push(delta.values[idx].clone()); + } else if idx < delta_len { + union( + s, + &mut obj.values[idx], + &delta.values[idx], + false, + opts, + union_context, + ); + if union_context.conflict { + union_context.path_backtrace.push(format!("list[{idx}]")); + } + } + } + } + } + (Value::dict_value(obj), Value::dict_value(delta)) => union_fn(obj, delta), + (Value::schema_value(obj), Value::dict_value(delta)) => { + name = obj.name.clone(); + pkgpath = obj.pkgpath.clone(); + let obj_value = obj.config.as_mut(); + union_fn(obj_value, delta); + common_keys = obj.config_keys.clone(); + let mut other_keys: Vec = delta.values.keys().cloned().collect(); + common_keys.append(&mut other_keys); + args = Some(obj.args.clone()); + kwargs = Some(obj.kwargs.clone()); + union_schema = true; + } + (Value::schema_value(obj), Value::schema_value(delta)) => { + name = obj.name.clone(); + pkgpath = obj.pkgpath.clone(); + let obj_value = obj.config.as_mut(); + let delta_value = delta.config.as_ref(); + union_fn(obj_value, delta_value); + common_keys = obj.config_keys.clone(); + let mut other_keys: Vec = delta.config_keys.clone(); + common_keys.append(&mut other_keys); + args = Some(delta.args.clone()); + kwargs = Some(delta.kwargs.clone()); + union_schema = true; + } + (Value::dict_value(obj), Value::schema_value(delta)) => { + name = delta.name.clone(); + pkgpath = delta.pkgpath.clone(); + let delta_value = delta.config.as_ref(); + union_fn(obj, delta_value); + common_keys = delta.config_keys.clone(); + let mut other_keys: Vec = obj.values.keys().cloned().collect(); + common_keys.append(&mut other_keys); + args = Some(delta.args.clone()); + kwargs = Some(delta.kwargs.clone()); + union_schema = true; + } + _ => valid = false, + } + if !valid { + panic!( + "union failure, expect {:?}, got {:?}", + p.type_str(), + x.type_str() + ) + } + if union_context.conflict { + return p.clone(); + } + if union_schema { + // Override schema arguments and keyword arguments. + let mut result = p.clone(); + if let (Some(args), Some(kwargs)) = (&args, &kwargs) { + result.set_schema_args(args, kwargs); + } + let optional_mapping = if p.is_schema() { + p.schema_optional_mapping() + } else { + x.schema_optional_mapping() + }; + let schema = result.dict_to_schema( + name.as_str(), + pkgpath.as_str(), + &common_keys, + &x.schema_config_meta(), + &optional_mapping, + args, + kwargs, + ); + if opts.config_resolve { + *p = resolve_schema(s, &schema, &common_keys); + } else { + *p = schema; + } + } + p.clone() +} + +fn union( + s: &Evaluator, + p: &mut ValueRef, + x: &ValueRef, + or_mode: bool, + opts: &UnionOptions, + union_context: &mut UnionContext, +) -> ValueRef { + if p.is_none_or_undefined() { + *p = x.clone(); + return p.clone(); + } + if x.is_none_or_undefined() { + return p.clone(); + } + if p.is_list_or_config() && x.is_list_or_config() { + do_union(s, p, x, opts, union_context); + } else if or_mode { + if let (Value::int_value(a), Value::int_value(b)) = + (&mut *p.rc.borrow_mut(), &*x.rc.borrow()) + { + *a |= *b; + return p.clone(); + }; + panic!( + "unsupported operand type(s) for |: '{:?}' and '{:?}'", + p.type_str(), + x.type_str() + ) + } else { + *p = x.clone(); + } + p.clone() +} + +pub fn union_entry( + s: &Evaluator, + p: &mut ValueRef, + x: &ValueRef, + or_mode: bool, + opts: &UnionOptions, +) -> ValueRef { + let mut union_context = UnionContext::default(); + let ret = union(s, p, x, or_mode, opts, &mut union_context); + if union_context.conflict { + union_context.path_backtrace.reverse(); + let conflict_key = union_context.path_backtrace.last().unwrap(); + let path_string = union_context.path_backtrace.join("."); + + // build note + // it will be like: + // {...} | { + // ... + // b = {...} + // ... + // } + + let note = format!( + " {{...}} | {{\n ...\n {} = {}\n ...\n }}", + conflict_key, union_context.delta_json + ); + if conflict_key.is_empty() { + panic!( + "conflicting values between {} and {}", + union_context.delta_json, union_context.obj_json + ); + } else { + panic!( + "conflicting values on the attribute '{}' between :\n {}\nand\n {}\nwith union path :\n {}\ntry operator '=' to override the attribute, like:\n{}", + conflict_key, + union_context.obj_json, + union_context.delta_json, + path_string, + note, + ); + } + } + ret +} diff --git a/kclvm/evaluator/src/value.rs b/kclvm/evaluator/src/value.rs new file mode 100644 index 000000000..90ca7bb0b --- /dev/null +++ b/kclvm/evaluator/src/value.rs @@ -0,0 +1,84 @@ +/* Value methods */ + +use generational_arena::Index; +use kclvm_runtime::ValueRef; + +use crate::Evaluator; + +impl<'ctx> Evaluator<'ctx> { + /// Construct a 64-bit int value using i64 + #[inline] + pub(crate) fn int_value(&self, v: i64) -> ValueRef { + ValueRef::int(v) + } + + /// Construct a 64-bit float value using f64 + #[inline] + pub(crate) fn float_value(&self, v: f64) -> ValueRef { + ValueRef::float(v) + } + + /// Construct a string value using &str + #[inline] + pub(crate) fn string_value(&self, v: &str) -> ValueRef { + ValueRef::str(v) + } + + /// Construct a bool value + #[inline] + pub(crate) fn bool_value(&self, v: bool) -> ValueRef { + ValueRef::bool(v) + } + + /// Construct a None value + #[inline] + pub(crate) fn none_value(&self) -> ValueRef { + ValueRef::none() + } + + /// Construct a Undefined value + #[inline] + pub(crate) fn undefined_value(&self) -> ValueRef { + ValueRef::undefined() + } + + /// Construct a empty kcl list value + #[inline] + pub(crate) fn list_value(&self) -> ValueRef { + ValueRef::list(None) + } + + /// Construct a empty kcl dict value. + #[inline] + pub(crate) fn dict_value(&self) -> ValueRef { + ValueRef::dict(None) + } + + /// Construct a unit value + #[inline] + pub(crate) fn unit_value(&self, v: f64, raw: i64, unit: &str) -> ValueRef { + ValueRef::unit(v, raw, unit) + } + + /// Construct a function value using a native function. + #[inline] + pub(crate) fn proxy_function_value(&self, proxy: Index) -> ValueRef { + ValueRef::proxy_func(proxy) + } + + /// Construct a function value using a native function. + #[inline] + pub(crate) fn proxy_function_value_with_type( + &self, + proxy: Index, + runtime_type: &str, + ) -> ValueRef { + ValueRef::proxy_func_with_type(proxy, runtime_type) + } + + /// Construct a function value using a native function. + #[inline] + pub(crate) fn function_value_with_ptr(&self, function_ptr: u64) -> ValueRef { + ValueRef::func(function_ptr, 0, self.list_value(), "", "", false) + } +} diff --git a/kclvm/lexer/Cargo.toml b/kclvm/lexer/Cargo.toml index d0ff55a9f..e4b147304 100644 --- a/kclvm/lexer/Cargo.toml +++ b/kclvm/lexer/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "kclvm-lexer" -version = "0.1.0" +version = "0.11.0" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html @@ -8,7 +8,7 @@ edition = "2021" [dependencies] rustc_lexer = "0.1.0" unic-emoji-char = "0.9.0" -kclvm-error = {path = "../error", version = "0.1.0"} +kclvm-error = {path = "../error"} [dev-dependencies] expect-test = "1.0" \ No newline at end of file diff --git a/kclvm/lexer/src/kcl_cursor.rs b/kclvm/lexer/src/kcl_cursor.rs index 6d376416c..5731c1d07 100644 --- a/kclvm/lexer/src/kcl_cursor.rs +++ b/kclvm/lexer/src/kcl_cursor.rs @@ -6,10 +6,11 @@ //! and enable implemente Cursor structs in different crate. use crate::cursor::DOLLAR_CHAR; +use crate::cursor::EOF_CHAR; use crate::Cursor; use crate::DocStyle; use crate::ICommentCursor; -use crate::IIdentCurosr; +use crate::IIdentCursor; use crate::IStringCursor; use crate::Literal; use crate::LiteralKind::*; @@ -45,7 +46,7 @@ impl<'a> IStringCursor for Cursor<'a> { 'r' | 'R' => match self.peek() { '\'' | '\"' => { // R string - let quote = self.bump().unwrap(); + let quote = self.bump().unwrap_or(EOF_CHAR); self.eat_quoted_string(quote) } _ => Unknown, @@ -107,6 +108,9 @@ impl<'a> Cursor<'a> { }; } } + // If we encounter an unclosed single quote string, + // we end at the eof and newline characters '\r' or '\n'. + _ if !triple_quoted && matches!(self.peek(), '\r' | '\n' | EOF_CHAR) => break, _ => (), } } @@ -122,7 +126,7 @@ impl<'a> Cursor<'a> { } } -impl<'a> IIdentCurosr for Cursor<'a> { +impl<'a> IIdentCursor for Cursor<'a> { fn try_ident_magic(&self, c: char) -> bool { match c { DOLLAR_CHAR => rustc_lexer::is_id_start(self.peek()), diff --git a/kclvm/lexer/src/lib.rs b/kclvm/lexer/src/lib.rs index 149f4cdef..a7f1fa17d 100644 --- a/kclvm/lexer/src/lib.rs +++ b/kclvm/lexer/src/lib.rs @@ -255,15 +255,11 @@ pub enum DocStyle { #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] pub enum LiteralKind { - /// "12_u8", "0o100", "0b120i99" + /// "12", "0o100", "0b120199" Int { base: Base, empty_int: bool }, - /// "12.34f32", "0b100.100" + /// "12.34", "0b100.100" Float { base: Base, empty_exponent: bool }, - /// "'a'", "'\\'", "'''", "';" - Char { terminated: bool }, - /// "b'a'", "b'\\'", "b'''", "b';" - Byte { terminated: bool }, - /// ""abc"", ""abc" + /// ""abc"", "'abc'", "'''abc'''" Str { terminated: bool, triple_quoted: bool, @@ -285,6 +281,18 @@ pub enum Base { Decimal, } +impl Base { + /// Returns the description string of the numeric literal base. + pub fn describe(&self) -> &'static str { + match self { + Base::Binary => "binary", + Base::Octal => "octal", + Base::Hexadecimal => "hexadecimal", + Base::Decimal => "decimal", + } + } +} + /// Parses the first token from the provided input string. pub fn first_token(input: &str) -> Token { debug_assert!(!input.is_empty()); @@ -351,7 +359,7 @@ pub trait IStringCursor { // Cursor trait to read identifier. // Simple identifier, raw identifier, and more identifier cases should be considered here. -pub trait IIdentCurosr { +pub trait IIdentCursor { // If we encounter a identifier. // Returns true if exists, otherwise returns false. fn try_ident_magic(&self, _c: char) -> bool { @@ -359,24 +367,46 @@ pub trait IIdentCurosr { } // Eat it if so. - // This mehod **MUST** be called after 'try_ident_magic'. - // No gurantee to ensure the correctness if no identifier here, + // This method **MUST** be called after 'try_ident_magic'. + // No guarantee to ensure the correctness if no identifier here, // and return 'Unknown' if it happens. fn eat_ident(&mut self) -> TokenKind { Unknown } } +/// True if `c` is considered a whitespace. +pub fn is_whitespace(c: char) -> bool { + match c { + // Usual ASCII suspects + | '\u{000B}' // vertical tab + | '\u{000C}' // form feed + | '\u{000D}' // \r + // NEXT LINE from latin1 + | '\u{0085}' + + // Bidi markers + | '\u{200E}' // LEFT-TO-RIGHT MARK + | '\u{200F}' // RIGHT-TO-LEFT MARK + + // Dedicated whitespace characters from Unicode + | '\u{2028}' // LINE SEPARATOR + | '\u{2029}' // PARAGRAPH SEPARATOR + => true, + _ => false, + } +} + impl<'a> ITokenCursor for Cursor<'a> { fn token(&mut self) -> Token { - let char = self.bump().unwrap(); + let char = self.bump().unwrap_or(EOF_CHAR); let token_kind = match char { // Comment or block comment, or a simple token c if self.try_comment_magic(c) => self.eat_comment(), // Whitespace sequence. - c if rustc_lexer::is_whitespace(c) => self.whitespace(c), + c if is_whitespace(c) => Whitespace, // Various of string. E.g., quoted string, raw string. c if self.try_string_magic(c) => self.eat_string(c), @@ -394,6 +424,11 @@ impl<'a> ITokenCursor for Cursor<'a> { TokenKind::Literal { kind, suffix_start } } + // '\r' will be considered as a 'WhiteSpace'. + '\u{0009}' => Tab, + '\u{0020}' => Space, + '\u{000A}' => Newline, + ';' => Semi, ',' => Comma, '.' => match (self.peek(), self.peek1th()) { @@ -440,7 +475,7 @@ impl<'a> ITokenCursor for Cursor<'a> { match self.peek() { '=' => { self.bump(); - LtEq + LtLtEq } _ => LtLt, } @@ -559,18 +594,6 @@ impl<'a> ITokenCursor for Cursor<'a> { } impl<'a> Cursor<'a> { - fn whitespace(&mut self, c: char) -> TokenKind { - debug_assert!(rustc_lexer::is_whitespace(c)); - - match c { - '\u{0009}' => Tab, - '\u{0020}' => Space, - '\u{000D}' => CarriageReturn, - '\u{000A}' => Newline, - _ => Whitespace, - } - } - // Eats the suffix of the literal, e.g. 'Ki', 'M', etc. fn eat_lit_suffix(&mut self) { if !rustc_lexer::is_id_start(self.peek()) { diff --git a/kclvm/lexer/src/number.rs b/kclvm/lexer/src/number.rs index f9f7d9ab2..0458b1fd1 100644 --- a/kclvm/lexer/src/number.rs +++ b/kclvm/lexer/src/number.rs @@ -66,7 +66,7 @@ impl<'a> Cursor<'a> { // with a number self.bump(); let mut empty_exponent = false; - if self.peek().is_digit(10) { + if self.peek().is_ascii_digit() { self.eat_decimal_digits(); match self.peek() { 'e' | 'E' => { diff --git a/kclvm/lexer/src/tests.rs b/kclvm/lexer/src/tests.rs index 41eb852f3..6b430f45e 100644 --- a/kclvm/lexer/src/tests.rs +++ b/kclvm/lexer/src/tests.rs @@ -1,10 +1,12 @@ use super::*; use expect_test::{expect, Expect}; +use std::fmt::Write; fn check_lexing(src: &str, expect: Expect) { - let actual: String = tokenize(src) - .map(|token| format!("{:?}\n", token)) - .collect(); + let actual: String = tokenize(src).fold(String::new(), |mut acc, token| { + writeln!(acc, "{:?}", token).expect("Failed to write to string"); + acc + }); expect.assert_eq(&actual) } @@ -195,7 +197,7 @@ $ Token { kind: Newline, len: 1 } Token { kind: SlashSlashEq, len: 3 } Token { kind: Newline, len: 1 } - Token { kind: LtEq, len: 3 } + Token { kind: LtLtEq, len: 3 } Token { kind: Newline, len: 1 } Token { kind: GtGtEq, len: 3 } Token { kind: Newline, len: 1 } @@ -319,3 +321,49 @@ fn line_continue() { "#]], ) } + +#[test] +fn newline_r_n() { + check_lexing( + "\r\n", + expect![[r#" + Token { kind: Whitespace, len: 1 } + Token { kind: Newline, len: 1 } + "#]], + ) +} + +#[test] +fn newline_r_n_r_n() { + check_lexing( + "\r\n\r\n", + expect![[r#" + Token { kind: Whitespace, len: 1 } + Token { kind: Newline, len: 1 } + Token { kind: Whitespace, len: 1 } + Token { kind: Newline, len: 1 } + "#]], + ) +} + +#[test] +fn newline_r() { + check_lexing( + "\r", + expect![[r#" + Token { kind: Whitespace, len: 1 } + "#]], + ) +} + +#[test] +fn newline_r_n_n() { + check_lexing( + "\r\n\n", + expect![[r#" + Token { kind: Whitespace, len: 1 } + Token { kind: Newline, len: 1 } + Token { kind: Newline, len: 1 } + "#]], + ) +} diff --git a/kclvm/loader/Cargo.toml b/kclvm/loader/Cargo.toml new file mode 100644 index 000000000..b89dd0079 --- /dev/null +++ b/kclvm/loader/Cargo.toml @@ -0,0 +1,22 @@ +[package] +name = "kclvm-loader" +version = "0.11.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +indexmap = "1.0" +anyhow = "1.0" + +kclvm-ast = {path = "../ast"} +kclvm-ast-pretty = { path = "../ast_pretty" } +kclvm-parser = {path = "../parser"} +kclvm-sema = {path = "../sema"} +kclvm-error = {path = "../error"} +kclvm-query = {path = "../query"} +kclvm-utils = {path = "../utils"} +maplit = "1.0.2" + +[dev-dependencies] +insta = "1.8.0" diff --git a/kclvm/loader/src/lib.rs b/kclvm/loader/src/lib.rs new file mode 100644 index 000000000..721657fa4 --- /dev/null +++ b/kclvm/loader/src/lib.rs @@ -0,0 +1,296 @@ +#[cfg(test)] +mod tests; + +pub mod option; +pub mod util; + +use anyhow::Result; +use indexmap::{IndexMap, IndexSet}; +use kclvm_ast::ast::Program; +use kclvm_error::{diagnostic::Range, Diagnostic}; +use kclvm_parser::{load_program, KCLModuleCache, LoadProgramOptions, ParseSessionRef}; +use kclvm_sema::{ + advanced_resolver::AdvancedResolver, + core::{ + global_state::GlobalState, + scope::{LocalSymbolScopeKind, ScopeData, ScopeRef}, + symbol::{SymbolData, SymbolRef}, + }, + namer::Namer, + resolver::{ + resolve_program_with_opts, + scope::{KCLScopeCache, NodeKey}, + }, + ty::{Type, TypeRef}, +}; +use kclvm_utils::path::PathPrefix; +use std::path::PathBuf; + +type Errors = IndexSet; + +#[derive(Debug, Clone)] +pub struct LoadPackageOptions { + pub paths: Vec, + pub load_opts: Option, + pub resolve_ast: bool, + pub load_builtin: bool, +} + +impl Default for LoadPackageOptions { + fn default() -> Self { + Self { + paths: Default::default(), + load_opts: Default::default(), + resolve_ast: true, + load_builtin: false, + } + } +} + +#[derive(Debug, Clone, Default)] +pub struct Packages { + /// AST Program + pub program: Program, + /// All compiled files in the package + pub paths: Vec, + /// All Parse errors + pub parse_errors: Errors, + /// Type errors + pub type_errors: Errors, + /// Symbol information + pub symbols: IndexMap, + /// Scope information + pub scopes: IndexMap, + /// AST Node-Symbol mapping + pub node_symbol_map: IndexMap, + /// - mapping + pub pkg_scope_map: IndexMap, + /// Symbol-AST Node mapping + pub symbol_node_map: IndexMap, + /// Fully qualified name mapping + pub fully_qualified_name_map: IndexMap, +} + +#[derive(Debug, Clone)] +pub struct SymbolInfo { + pub ty: TypeRef, + pub name: String, + pub range: Range, + pub owner: Option, + pub def: Option, + pub attrs: Vec, + pub is_global: bool, +} + +#[derive(Debug, Clone)] +pub struct ScopeInfo { + /// Scope kind + pub kind: ScopeKind, + /// Scope parent + pub parent: Option, + /// Scope owner + pub owner: Option, + /// Children scopes + pub children: Vec, + /// Definitions + pub defs: Vec, +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum ScopeKind { + Package, + Module, + List, + Dict, + Quant, + Lambda, + SchemaDef, + Config, + Check, + Callable, +} + +/// load_package provides users with the ability to parse kcl program and sematic model +/// information including symbols, types, definitions, etc. +pub fn load_packages(opts: &LoadPackageOptions) -> Result { + load_packages_with_cache( + opts, + KCLModuleCache::default(), + KCLScopeCache::default(), + &mut GlobalState::default(), + ) +} + +/// load_package_with_cache provides users with the ability to parse kcl program and sematic model +/// information including symbols, types, definitions, etc. +pub fn load_packages_with_cache( + opts: &LoadPackageOptions, + module_cache: KCLModuleCache, + scope_cache: KCLScopeCache, + gs: &mut GlobalState, +) -> Result { + let sess = ParseSessionRef::default(); + let paths: Vec<&str> = opts.paths.iter().map(|s| s.as_str()).collect(); + let parse_result = load_program( + sess.clone(), + &paths, + opts.load_opts.clone(), + Some(module_cache), + )?; + let parse_errors = parse_result.errors; + let (program, type_errors, gs) = if opts.resolve_ast { + let mut program = parse_result.program; + let prog_scope = resolve_program_with_opts( + &mut program, + kclvm_sema::resolver::Options { + merge_program: false, + type_erasure: false, + ..Default::default() + }, + Some(scope_cache), + ); + let node_ty_map = prog_scope.node_ty_map; + Namer::find_symbols(&program, gs); + AdvancedResolver::resolve_program(&program, gs, node_ty_map.clone())?; + (program, prog_scope.handler.diagnostics.clone(), gs) + } else { + (parse_result.program, IndexSet::default(), gs) + }; + let mut packages = Packages { + program, + paths: parse_result.paths, + parse_errors, + type_errors, + ..Default::default() + }; + if !opts.resolve_ast { + return Ok(packages); + } + let symbols = gs.get_symbols(); + if opts.load_builtin { + for (_, symbol_ref) in symbols.get_builtin_symbols() { + if let Some(symbol) = symbols.get_symbol(*symbol_ref) { + let def_ty = match symbol.get_definition() { + Some(def) => symbols + .get_symbol(def) + .unwrap() + .get_sema_info() + .ty + .clone() + .unwrap_or(Type::any_ref()), + None => symbol.get_sema_info().ty.clone().unwrap_or(Type::any_ref()), + }; + let info = SymbolInfo { + ty: def_ty, + range: symbol.get_range(), + name: symbol.get_name(), + owner: symbol.get_owner(), + def: symbol.get_definition(), + attrs: symbol.get_all_attributes(symbols, None), + is_global: symbol.is_global(), + }; + packages.symbols.insert(*symbol_ref, info); + } + } + } + for path in &packages.paths { + let path_str = path + .to_str() + .ok_or(anyhow::anyhow!("path {} to str failed", path.display()))? + .adjust_canonicalization(); + if let Some(files) = gs.get_sema_db().get_file_sema(&path_str) { + for symbol_ref in files.get_symbols() { + if let Some(symbol) = symbols.get_symbol(*symbol_ref) { + let def_ty = match symbol.get_definition() { + Some(def) => symbols + .get_symbol(def) + .unwrap() + .get_sema_info() + .ty + .clone() + .unwrap_or(Type::any_ref()), + None => symbol.get_sema_info().ty.clone().unwrap_or(Type::any_ref()), + }; + let info = SymbolInfo { + ty: def_ty, + range: symbol.get_range(), + name: symbol.get_name(), + owner: symbol.get_owner(), + def: symbol.get_definition(), + attrs: symbol.get_all_attributes(symbols, None), + is_global: symbol.is_global(), + }; + packages.symbols.insert(*symbol_ref, info); + } + } + } + } + let scopes = gs.get_scopes(); + for (path, scope_ref) in scopes.get_root_scope_map() { + packages.pkg_scope_map.insert(path.clone(), *scope_ref); + // Root scopes + if let Some(scope_ref) = scopes.get_root_scope(path.clone()) { + collect_scope_info( + &mut packages.scopes, + &scope_ref, + scopes, + symbols, + ScopeKind::Package, + ); + } + } + // Update package semantic mappings + packages.node_symbol_map = symbols.get_node_symbol_map().clone(); + packages.symbol_node_map = symbols.get_symbol_node_map().clone(); + packages.fully_qualified_name_map = symbols.get_fully_qualified_name_map().clone(); + Ok(packages) +} + +impl From for ScopeKind { + fn from(value: LocalSymbolScopeKind) -> Self { + match value { + LocalSymbolScopeKind::List => ScopeKind::List, + LocalSymbolScopeKind::Dict => ScopeKind::Dict, + LocalSymbolScopeKind::Quant => ScopeKind::Quant, + LocalSymbolScopeKind::Lambda => ScopeKind::Lambda, + LocalSymbolScopeKind::SchemaDef => ScopeKind::SchemaDef, + LocalSymbolScopeKind::Config => ScopeKind::Config, + LocalSymbolScopeKind::Check => ScopeKind::Check, + LocalSymbolScopeKind::Callable => ScopeKind::Callable, + } + } +} + +fn collect_scope_info( + scopes: &mut IndexMap, + scope_ref: &ScopeRef, + scope_data: &ScopeData, + symbol_data: &SymbolData, + kind: ScopeKind, +) { + if let Some(scope) = scope_data.get_scope(scope_ref) { + let kind = if let Some(scope) = scope_data.try_get_local_scope(scope_ref) { + scope.get_kind().clone().into() + } else { + kind + }; + scopes.insert( + *scope_ref, + ScopeInfo { + kind, + parent: scope.get_parent(), + owner: scope.get_owner(), + children: scope.get_children(), + defs: scope + .get_all_defs(scope_data, symbol_data, None, false, true) + .values() + .copied() + .collect::>(), + }, + ); + + for s in scope.get_children() { + collect_scope_info(scopes, &s, scope_data, symbol_data, ScopeKind::Module); + } + } +} diff --git a/kclvm/loader/src/option.rs b/kclvm/loader/src/option.rs new file mode 100644 index 000000000..fca192ada --- /dev/null +++ b/kclvm/loader/src/option.rs @@ -0,0 +1,67 @@ +use anyhow::Result; +use kclvm_ast::{ast, walker::MutSelfWalker}; +use kclvm_sema::builtin::BUILTIN_FUNCTIONS; +use kclvm_sema::{builtin::option::OptionHelp, resolver::scope::NodeKey}; + +use crate::util::{get_call_args_string, get_call_args_strip_string}; +use crate::{load_packages, util::get_call_args_bool, LoadPackageOptions, Packages}; + +#[derive(Debug)] +struct OptionHelpExtractor<'ctx> { + pkgpath: String, + options: Vec, + packages: &'ctx Packages, +} + +impl<'ctx> MutSelfWalker for OptionHelpExtractor<'ctx> { + fn walk_call_expr(&mut self, call_expr: &ast::CallExpr) { + if let ast::Expr::Identifier(identifier) = &call_expr.func.node { + if identifier.names.len() == 1 { + let node_key = NodeKey { + pkgpath: self.pkgpath.clone(), + id: identifier.names[0].id.clone(), + }; + let symbol_ref = self.packages.node_symbol_map.get(&node_key).unwrap(); + let symbol = self.packages.symbols.get(symbol_ref).unwrap(); + let binding = BUILTIN_FUNCTIONS; + let builtin_option_type = binding.get("option").unwrap(); + if !symbol.is_global + && symbol.ty.is_func() + && symbol.ty.ty_str() == builtin_option_type.ty_str() + { + self.options.push(OptionHelp { + name: get_call_args_strip_string(call_expr, 0, Some("key")), + ty: get_call_args_strip_string(call_expr, 1, Some("type")), + required: get_call_args_bool(call_expr, 2, Some("required")), + default_value: get_call_args_string(call_expr, 3, Some("default")), + help: get_call_args_strip_string(call_expr, 3, Some("help")), + }) + } + } + } + } +} + +/// list_options provides users with the ability to parse kcl program and get all option +/// calling information. +pub fn list_options(opts: &LoadPackageOptions) -> Result> { + let packages = load_packages(opts)?; + let mut extractor = OptionHelpExtractor { + pkgpath: String::new(), + options: vec![], + packages: &packages, + }; + + for (pkgpath, modules) in &packages.program.pkgs { + extractor.pkgpath = pkgpath.clone(); + for module in modules { + let module = packages + .program + .get_module(module) + .expect("Failed to acquire module lock") + .expect(&format!("module {:?} not found in program", module)); + extractor.walk_module(&module) + } + } + Ok(extractor.options) +} diff --git a/kclvm/loader/src/snapshots/kclvm_loader__tests__assign_stmt_0.snap b/kclvm/loader/src/snapshots/kclvm_loader__tests__assign_stmt_0.snap new file mode 100644 index 000000000..489dfac0a --- /dev/null +++ b/kclvm/loader/src/snapshots/kclvm_loader__tests__assign_stmt_0.snap @@ -0,0 +1,88 @@ +--- +source: loader/src/tests.rs +expression: "format!(\"{:#?}\", p.symbols.values())" +--- +[ + SymbolInfo { + ty: Type { + kind: Int, + is_type_alias: false, + flags: INT, + }, + name: "a", + range: ( + Position { + filename: "test.k", + line: 1, + column: Some( + 0, + ), + }, + Position { + filename: "test.k", + line: 1, + column: Some( + 1, + ), + }, + ), + owner: Some( + SymbolRef { + id: Index { + index: 15, + generation: 0, + }, + kind: Package, + }, + ), + def: Some( + SymbolRef { + id: Index { + index: 0, + generation: 0, + }, + kind: Value, + }, + ), + attrs: [], + is_global: true, + }, + SymbolInfo { + ty: Type { + kind: IntLit( + 1, + ), + is_type_alias: false, + flags: INT | LITERAL, + }, + name: "@NumberLitExpression", + range: ( + Position { + filename: "test.k", + line: 1, + column: Some( + 5, + ), + }, + Position { + filename: "test.k", + line: 1, + column: Some( + 5, + ), + }, + ), + owner: None, + def: Some( + SymbolRef { + id: Index { + index: 0, + generation: 0, + }, + kind: Expression, + }, + ), + attrs: [], + is_global: false, + }, +] diff --git a/kclvm/loader/src/snapshots/kclvm_loader__tests__assign_stmt_1.snap b/kclvm/loader/src/snapshots/kclvm_loader__tests__assign_stmt_1.snap new file mode 100644 index 000000000..631cc7a51 --- /dev/null +++ b/kclvm/loader/src/snapshots/kclvm_loader__tests__assign_stmt_1.snap @@ -0,0 +1,126 @@ +--- +source: loader/src/tests.rs +expression: "format!(\"{:#?}\", p.symbols.values())" +--- +[ + SymbolInfo { + ty: Type { + kind: Int, + is_type_alias: false, + flags: INT, + }, + name: "a", + range: ( + Position { + filename: "test.k", + line: 1, + column: Some( + 0, + ), + }, + Position { + filename: "test.k", + line: 1, + column: Some( + 1, + ), + }, + ), + owner: Some( + SymbolRef { + id: Index { + index: 15, + generation: 0, + }, + kind: Package, + }, + ), + def: Some( + SymbolRef { + id: Index { + index: 0, + generation: 0, + }, + kind: Value, + }, + ), + attrs: [], + is_global: true, + }, + SymbolInfo { + ty: Type { + kind: IntLit( + 1, + ), + is_type_alias: false, + flags: INT | LITERAL, + }, + name: "@NumberLitExpression", + range: ( + Position { + filename: "test.k", + line: 1, + column: Some( + 5, + ), + }, + Position { + filename: "test.k", + line: 1, + column: Some( + 5, + ), + }, + ), + owner: None, + def: Some( + SymbolRef { + id: Index { + index: 0, + generation: 0, + }, + kind: Expression, + }, + ), + attrs: [], + is_global: false, + }, + SymbolInfo { + ty: Type { + kind: IntLit( + 1, + ), + is_type_alias: false, + flags: INT | LITERAL, + }, + name: "@NumberLitExpression", + range: ( + Position { + filename: "test.k", + line: 1, + column: Some( + 9, + ), + }, + Position { + filename: "test.k", + line: 1, + column: Some( + 9, + ), + }, + ), + owner: None, + def: Some( + SymbolRef { + id: Index { + index: 1, + generation: 0, + }, + kind: Expression, + }, + ), + attrs: [], + is_global: false, + }, +] diff --git a/kclvm/loader/src/snapshots/kclvm_loader__tests__assign_stmt_2.snap b/kclvm/loader/src/snapshots/kclvm_loader__tests__assign_stmt_2.snap new file mode 100644 index 000000000..d3218d0e2 --- /dev/null +++ b/kclvm/loader/src/snapshots/kclvm_loader__tests__assign_stmt_2.snap @@ -0,0 +1,162 @@ +--- +source: loader/src/tests.rs +expression: "format!(\"{:#?}\", p.symbols.values())" +--- +[ + SymbolInfo { + ty: Type { + kind: Int, + is_type_alias: false, + flags: INT, + }, + name: "a", + range: ( + Position { + filename: "test.k", + line: 1, + column: Some( + 0, + ), + }, + Position { + filename: "test.k", + line: 1, + column: Some( + 1, + ), + }, + ), + owner: Some( + SymbolRef { + id: Index { + index: 15, + generation: 0, + }, + kind: Package, + }, + ), + def: Some( + SymbolRef { + id: Index { + index: 0, + generation: 0, + }, + kind: Value, + }, + ), + attrs: [], + is_global: true, + }, + SymbolInfo { + ty: Type { + kind: IntLit( + 1, + ), + is_type_alias: false, + flags: INT | LITERAL, + }, + name: "@NumberLitExpression", + range: ( + Position { + filename: "test.k", + line: 1, + column: Some( + 6, + ), + }, + Position { + filename: "test.k", + line: 1, + column: Some( + 6, + ), + }, + ), + owner: None, + def: Some( + SymbolRef { + id: Index { + index: 0, + generation: 0, + }, + kind: Expression, + }, + ), + attrs: [], + is_global: false, + }, + SymbolInfo { + ty: Type { + kind: IntLit( + 1, + ), + is_type_alias: false, + flags: INT | LITERAL, + }, + name: "@NumberLitExpression", + range: ( + Position { + filename: "test.k", + line: 1, + column: Some( + 10, + ), + }, + Position { + filename: "test.k", + line: 1, + column: Some( + 10, + ), + }, + ), + owner: None, + def: Some( + SymbolRef { + id: Index { + index: 1, + generation: 0, + }, + kind: Expression, + }, + ), + attrs: [], + is_global: false, + }, + SymbolInfo { + ty: Type { + kind: Int, + is_type_alias: false, + flags: INT, + }, + name: "@ParenExpression", + range: ( + Position { + filename: "test.k", + line: 1, + column: Some( + 11, + ), + }, + Position { + filename: "test.k", + line: 1, + column: Some( + 11, + ), + }, + ), + owner: None, + def: Some( + SymbolRef { + id: Index { + index: 2, + generation: 0, + }, + kind: Expression, + }, + ), + attrs: [], + is_global: false, + }, +] diff --git a/kclvm/loader/src/snapshots/kclvm_loader__tests__builtin_call_0.snap b/kclvm/loader/src/snapshots/kclvm_loader__tests__builtin_call_0.snap new file mode 100644 index 000000000..75f13b884 --- /dev/null +++ b/kclvm/loader/src/snapshots/kclvm_loader__tests__builtin_call_0.snap @@ -0,0 +1,340 @@ +--- +source: loader/src/tests.rs +expression: "format! (\"{:#?}\", p.symbols.values())" +--- +[ + SymbolInfo { + ty: Type { + kind: Function( + FunctionType { + doc: "Prints the values to a stream, or to the system stdout by default.\nOptional keyword arguments:\nsep: string inserted between values, default a space.\nend: string appended after the last value, default a newline.", + params: [], + self_ty: None, + return_ty: Type { + kind: None, + is_type_alias: false, + flags: NONE, + }, + is_variadic: true, + kw_only_index: None, + }, + ), + is_type_alias: false, + flags: FUNCTION, + }, + name: "print", + range: ( + Position { + filename: "test.k", + line: 1, + column: Some( + 0, + ), + }, + Position { + filename: "test.k", + line: 1, + column: Some( + 5, + ), + }, + ), + owner: None, + def: Some( + SymbolRef { + id: Index { + index: 1, + generation: 0, + }, + kind: Function, + }, + ), + attrs: [], + is_global: false, + }, + SymbolInfo { + ty: Type { + kind: StrLit( + "hello world", + ), + is_type_alias: false, + flags: STR | LITERAL, + }, + name: "@StringLitExpression", + range: ( + Position { + filename: "test.k", + line: 1, + column: Some( + 19, + ), + }, + Position { + filename: "test.k", + line: 1, + column: Some( + 19, + ), + }, + ), + owner: None, + def: Some( + SymbolRef { + id: Index { + index: 0, + generation: 0, + }, + kind: Expression, + }, + ), + attrs: [ + SymbolRef { + id: Index { + index: 141, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 142, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 143, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 144, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 145, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 146, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 147, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 148, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 149, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 150, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 151, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 152, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 153, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 154, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 155, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 156, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 157, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 158, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 159, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 160, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 161, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 162, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 163, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 164, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 165, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 166, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 167, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 168, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 169, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 170, + generation: 0, + }, + kind: Function, + }, + ], + is_global: false, + }, + SymbolInfo { + ty: Type { + kind: None, + is_type_alias: false, + flags: NONE, + }, + name: "@CallExpression", + range: ( + Position { + filename: "test.k", + line: 1, + column: Some( + 20, + ), + }, + Position { + filename: "test.k", + line: 1, + column: Some( + 20, + ), + }, + ), + owner: None, + def: Some( + SymbolRef { + id: Index { + index: 1, + generation: 0, + }, + kind: Expression, + }, + ), + attrs: [], + is_global: false, + }, +] diff --git a/kclvm/loader/src/snapshots/kclvm_loader__tests__builtin_call_1.snap b/kclvm/loader/src/snapshots/kclvm_loader__tests__builtin_call_1.snap new file mode 100644 index 000000000..37124b641 --- /dev/null +++ b/kclvm/loader/src/snapshots/kclvm_loader__tests__builtin_call_1.snap @@ -0,0 +1,1071 @@ +--- +source: loader/src/tests.rs +expression: "format! (\"{:#?}\", p.symbols.values())" +--- +[ + SymbolInfo { + ty: Type { + kind: Any, + is_type_alias: false, + flags: ANY, + }, + name: "a", + range: ( + Position { + filename: "test.k", + line: 1, + column: Some( + 0, + ), + }, + Position { + filename: "test.k", + line: 1, + column: Some( + 1, + ), + }, + ), + owner: Some( + SymbolRef { + id: Index { + index: 15, + generation: 0, + }, + kind: Package, + }, + ), + def: Some( + SymbolRef { + id: Index { + index: 0, + generation: 0, + }, + kind: Value, + }, + ), + attrs: [], + is_global: true, + }, + SymbolInfo { + ty: Type { + kind: Function( + FunctionType { + doc: "Return the top level argument by the key", + params: [ + Parameter { + name: "key", + ty: Type { + kind: Str, + is_type_alias: false, + flags: STR, + }, + has_default: false, + default_value: None, + range: ( + Position { + filename: "", + line: 1, + column: None, + }, + Position { + filename: "", + line: 1, + column: None, + }, + ), + }, + Parameter { + name: "type", + ty: Type { + kind: Str, + is_type_alias: false, + flags: STR, + }, + has_default: true, + default_value: None, + range: ( + Position { + filename: "", + line: 1, + column: None, + }, + Position { + filename: "", + line: 1, + column: None, + }, + ), + }, + Parameter { + name: "required", + ty: Type { + kind: Bool, + is_type_alias: false, + flags: BOOL, + }, + has_default: true, + default_value: None, + range: ( + Position { + filename: "", + line: 1, + column: None, + }, + Position { + filename: "", + line: 1, + column: None, + }, + ), + }, + Parameter { + name: "default", + ty: Type { + kind: Any, + is_type_alias: false, + flags: ANY, + }, + has_default: true, + default_value: None, + range: ( + Position { + filename: "", + line: 1, + column: None, + }, + Position { + filename: "", + line: 1, + column: None, + }, + ), + }, + Parameter { + name: "help", + ty: Type { + kind: Str, + is_type_alias: false, + flags: STR, + }, + has_default: true, + default_value: None, + range: ( + Position { + filename: "", + line: 1, + column: None, + }, + Position { + filename: "", + line: 1, + column: None, + }, + ), + }, + ], + self_ty: None, + return_ty: Type { + kind: Any, + is_type_alias: false, + flags: ANY, + }, + is_variadic: false, + kw_only_index: Some( + 1, + ), + }, + ), + is_type_alias: false, + flags: FUNCTION, + }, + name: "option", + range: ( + Position { + filename: "test.k", + line: 1, + column: Some( + 4, + ), + }, + Position { + filename: "test.k", + line: 1, + column: Some( + 10, + ), + }, + ), + owner: None, + def: Some( + SymbolRef { + id: Index { + index: 0, + generation: 0, + }, + kind: Function, + }, + ), + attrs: [], + is_global: false, + }, + SymbolInfo { + ty: Type { + kind: StrLit( + "key", + ), + is_type_alias: false, + flags: STR | LITERAL, + }, + name: "@StringLitExpression", + range: ( + Position { + filename: "test.k", + line: 1, + column: Some( + 16, + ), + }, + Position { + filename: "test.k", + line: 1, + column: Some( + 16, + ), + }, + ), + owner: None, + def: Some( + SymbolRef { + id: Index { + index: 0, + generation: 0, + }, + kind: Expression, + }, + ), + attrs: [ + SymbolRef { + id: Index { + index: 141, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 142, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 143, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 144, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 145, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 146, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 147, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 148, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 149, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 150, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 151, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 152, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 153, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 154, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 155, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 156, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 157, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 158, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 159, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 160, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 161, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 162, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 163, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 164, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 165, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 166, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 167, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 168, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 169, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 170, + generation: 0, + }, + kind: Function, + }, + ], + is_global: false, + }, + SymbolInfo { + ty: Type { + kind: StrLit( + "str", + ), + is_type_alias: false, + flags: STR | LITERAL, + }, + name: "type", + range: ( + Position { + filename: "test.k", + line: 1, + column: Some( + 18, + ), + }, + Position { + filename: "test.k", + line: 1, + column: Some( + 22, + ), + }, + ), + owner: None, + def: Some( + SymbolRef { + id: Index { + index: 1, + generation: 0, + }, + kind: Value, + }, + ), + attrs: [ + SymbolRef { + id: Index { + index: 141, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 142, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 143, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 144, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 145, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 146, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 147, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 148, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 149, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 150, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 151, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 152, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 153, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 154, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 155, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 156, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 157, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 158, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 159, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 160, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 161, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 162, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 163, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 164, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 165, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 166, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 167, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 168, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 169, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 170, + generation: 0, + }, + kind: Function, + }, + ], + is_global: false, + }, + SymbolInfo { + ty: Type { + kind: StrLit( + "str", + ), + is_type_alias: false, + flags: STR | LITERAL, + }, + name: "@StringLitExpression", + range: ( + Position { + filename: "test.k", + line: 1, + column: Some( + 28, + ), + }, + Position { + filename: "test.k", + line: 1, + column: Some( + 28, + ), + }, + ), + owner: None, + def: Some( + SymbolRef { + id: Index { + index: 1, + generation: 0, + }, + kind: Expression, + }, + ), + attrs: [ + SymbolRef { + id: Index { + index: 141, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 142, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 143, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 144, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 145, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 146, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 147, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 148, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 149, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 150, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 151, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 152, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 153, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 154, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 155, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 156, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 157, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 158, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 159, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 160, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 161, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 162, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 163, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 164, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 165, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 166, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 167, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 168, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 169, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 170, + generation: 0, + }, + kind: Function, + }, + ], + is_global: false, + }, + SymbolInfo { + ty: Type { + kind: BoolLit( + true, + ), + is_type_alias: false, + flags: BOOL | LITERAL, + }, + name: "required", + range: ( + Position { + filename: "test.k", + line: 1, + column: Some( + 30, + ), + }, + Position { + filename: "test.k", + line: 1, + column: Some( + 38, + ), + }, + ), + owner: None, + def: Some( + SymbolRef { + id: Index { + index: 2, + generation: 0, + }, + kind: Value, + }, + ), + attrs: [], + is_global: false, + }, + SymbolInfo { + ty: Type { + kind: BoolLit( + true, + ), + is_type_alias: false, + flags: BOOL | LITERAL, + }, + name: "@NameConstantLitExpression", + range: ( + Position { + filename: "test.k", + line: 1, + column: Some( + 43, + ), + }, + Position { + filename: "test.k", + line: 1, + column: Some( + 43, + ), + }, + ), + owner: None, + def: Some( + SymbolRef { + id: Index { + index: 2, + generation: 0, + }, + kind: Expression, + }, + ), + attrs: [], + is_global: false, + }, + SymbolInfo { + ty: Type { + kind: Any, + is_type_alias: false, + flags: ANY, + }, + name: "@CallExpression", + range: ( + Position { + filename: "test.k", + line: 1, + column: Some( + 44, + ), + }, + Position { + filename: "test.k", + line: 1, + column: Some( + 44, + ), + }, + ), + owner: None, + def: Some( + SymbolRef { + id: Index { + index: 3, + generation: 0, + }, + kind: Expression, + }, + ), + attrs: [], + is_global: false, + }, +] diff --git a/kclvm/loader/src/snapshots/kclvm_loader__tests__builtin_call_2.snap b/kclvm/loader/src/snapshots/kclvm_loader__tests__builtin_call_2.snap new file mode 100644 index 000000000..ed383b2de --- /dev/null +++ b/kclvm/loader/src/snapshots/kclvm_loader__tests__builtin_call_2.snap @@ -0,0 +1,1403 @@ +--- +source: loader/src/tests.rs +expression: "format! (\"{:#?}\", p.symbols.values())" +--- +[ + SymbolInfo { + ty: Type { + kind: Function( + FunctionType { + doc: "Return the top level argument by the key", + params: [ + Parameter { + name: "key", + ty: Type { + kind: Str, + is_type_alias: false, + flags: STR, + }, + has_default: false, + default_value: None, + range: ( + Position { + filename: "", + line: 1, + column: None, + }, + Position { + filename: "", + line: 1, + column: None, + }, + ), + }, + Parameter { + name: "type", + ty: Type { + kind: Str, + is_type_alias: false, + flags: STR, + }, + has_default: true, + default_value: None, + range: ( + Position { + filename: "", + line: 1, + column: None, + }, + Position { + filename: "", + line: 1, + column: None, + }, + ), + }, + Parameter { + name: "required", + ty: Type { + kind: Bool, + is_type_alias: false, + flags: BOOL, + }, + has_default: true, + default_value: None, + range: ( + Position { + filename: "", + line: 1, + column: None, + }, + Position { + filename: "", + line: 1, + column: None, + }, + ), + }, + Parameter { + name: "default", + ty: Type { + kind: Any, + is_type_alias: false, + flags: ANY, + }, + has_default: true, + default_value: None, + range: ( + Position { + filename: "", + line: 1, + column: None, + }, + Position { + filename: "", + line: 1, + column: None, + }, + ), + }, + Parameter { + name: "help", + ty: Type { + kind: Str, + is_type_alias: false, + flags: STR, + }, + has_default: true, + default_value: None, + range: ( + Position { + filename: "", + line: 1, + column: None, + }, + Position { + filename: "", + line: 1, + column: None, + }, + ), + }, + ], + self_ty: None, + return_ty: Type { + kind: Any, + is_type_alias: false, + flags: ANY, + }, + is_variadic: false, + kw_only_index: Some( + 1, + ), + }, + ), + is_type_alias: false, + flags: FUNCTION, + }, + name: "opt", + range: ( + Position { + filename: "test.k", + line: 1, + column: Some( + 0, + ), + }, + Position { + filename: "test.k", + line: 1, + column: Some( + 3, + ), + }, + ), + owner: Some( + SymbolRef { + id: Index { + index: 15, + generation: 0, + }, + kind: Package, + }, + ), + def: Some( + SymbolRef { + id: Index { + index: 0, + generation: 0, + }, + kind: Value, + }, + ), + attrs: [], + is_global: true, + }, + SymbolInfo { + ty: Type { + kind: Function( + FunctionType { + doc: "Return the top level argument by the key", + params: [ + Parameter { + name: "key", + ty: Type { + kind: Str, + is_type_alias: false, + flags: STR, + }, + has_default: false, + default_value: None, + range: ( + Position { + filename: "", + line: 1, + column: None, + }, + Position { + filename: "", + line: 1, + column: None, + }, + ), + }, + Parameter { + name: "type", + ty: Type { + kind: Str, + is_type_alias: false, + flags: STR, + }, + has_default: true, + default_value: None, + range: ( + Position { + filename: "", + line: 1, + column: None, + }, + Position { + filename: "", + line: 1, + column: None, + }, + ), + }, + Parameter { + name: "required", + ty: Type { + kind: Bool, + is_type_alias: false, + flags: BOOL, + }, + has_default: true, + default_value: None, + range: ( + Position { + filename: "", + line: 1, + column: None, + }, + Position { + filename: "", + line: 1, + column: None, + }, + ), + }, + Parameter { + name: "default", + ty: Type { + kind: Any, + is_type_alias: false, + flags: ANY, + }, + has_default: true, + default_value: None, + range: ( + Position { + filename: "", + line: 1, + column: None, + }, + Position { + filename: "", + line: 1, + column: None, + }, + ), + }, + Parameter { + name: "help", + ty: Type { + kind: Str, + is_type_alias: false, + flags: STR, + }, + has_default: true, + default_value: None, + range: ( + Position { + filename: "", + line: 1, + column: None, + }, + Position { + filename: "", + line: 1, + column: None, + }, + ), + }, + ], + self_ty: None, + return_ty: Type { + kind: Any, + is_type_alias: false, + flags: ANY, + }, + is_variadic: false, + kw_only_index: Some( + 1, + ), + }, + ), + is_type_alias: false, + flags: FUNCTION, + }, + name: "option", + range: ( + Position { + filename: "test.k", + line: 1, + column: Some( + 6, + ), + }, + Position { + filename: "test.k", + line: 1, + column: Some( + 12, + ), + }, + ), + owner: None, + def: Some( + SymbolRef { + id: Index { + index: 0, + generation: 0, + }, + kind: Function, + }, + ), + attrs: [], + is_global: false, + }, + SymbolInfo { + ty: Type { + kind: Any, + is_type_alias: false, + flags: ANY, + }, + name: "a", + range: ( + Position { + filename: "test.k", + line: 3, + column: Some( + 0, + ), + }, + Position { + filename: "test.k", + line: 3, + column: Some( + 1, + ), + }, + ), + owner: Some( + SymbolRef { + id: Index { + index: 15, + generation: 0, + }, + kind: Package, + }, + ), + def: Some( + SymbolRef { + id: Index { + index: 1, + generation: 0, + }, + kind: Value, + }, + ), + attrs: [], + is_global: true, + }, + SymbolInfo { + ty: Type { + kind: Function( + FunctionType { + doc: "Return the top level argument by the key", + params: [ + Parameter { + name: "key", + ty: Type { + kind: Str, + is_type_alias: false, + flags: STR, + }, + has_default: false, + default_value: None, + range: ( + Position { + filename: "", + line: 1, + column: None, + }, + Position { + filename: "", + line: 1, + column: None, + }, + ), + }, + Parameter { + name: "type", + ty: Type { + kind: Str, + is_type_alias: false, + flags: STR, + }, + has_default: true, + default_value: None, + range: ( + Position { + filename: "", + line: 1, + column: None, + }, + Position { + filename: "", + line: 1, + column: None, + }, + ), + }, + Parameter { + name: "required", + ty: Type { + kind: Bool, + is_type_alias: false, + flags: BOOL, + }, + has_default: true, + default_value: None, + range: ( + Position { + filename: "", + line: 1, + column: None, + }, + Position { + filename: "", + line: 1, + column: None, + }, + ), + }, + Parameter { + name: "default", + ty: Type { + kind: Any, + is_type_alias: false, + flags: ANY, + }, + has_default: true, + default_value: None, + range: ( + Position { + filename: "", + line: 1, + column: None, + }, + Position { + filename: "", + line: 1, + column: None, + }, + ), + }, + Parameter { + name: "help", + ty: Type { + kind: Str, + is_type_alias: false, + flags: STR, + }, + has_default: true, + default_value: None, + range: ( + Position { + filename: "", + line: 1, + column: None, + }, + Position { + filename: "", + line: 1, + column: None, + }, + ), + }, + ], + self_ty: None, + return_ty: Type { + kind: Any, + is_type_alias: false, + flags: ANY, + }, + is_variadic: false, + kw_only_index: Some( + 1, + ), + }, + ), + is_type_alias: false, + flags: FUNCTION, + }, + name: "opt", + range: ( + Position { + filename: "test.k", + line: 3, + column: Some( + 4, + ), + }, + Position { + filename: "test.k", + line: 3, + column: Some( + 7, + ), + }, + ), + owner: None, + def: Some( + SymbolRef { + id: Index { + index: 0, + generation: 0, + }, + kind: Value, + }, + ), + attrs: [], + is_global: false, + }, + SymbolInfo { + ty: Type { + kind: StrLit( + "key", + ), + is_type_alias: false, + flags: STR | LITERAL, + }, + name: "@StringLitExpression", + range: ( + Position { + filename: "test.k", + line: 3, + column: Some( + 13, + ), + }, + Position { + filename: "test.k", + line: 3, + column: Some( + 13, + ), + }, + ), + owner: None, + def: Some( + SymbolRef { + id: Index { + index: 0, + generation: 0, + }, + kind: Expression, + }, + ), + attrs: [ + SymbolRef { + id: Index { + index: 141, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 142, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 143, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 144, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 145, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 146, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 147, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 148, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 149, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 150, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 151, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 152, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 153, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 154, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 155, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 156, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 157, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 158, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 159, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 160, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 161, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 162, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 163, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 164, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 165, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 166, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 167, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 168, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 169, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 170, + generation: 0, + }, + kind: Function, + }, + ], + is_global: false, + }, + SymbolInfo { + ty: Type { + kind: StrLit( + "str", + ), + is_type_alias: false, + flags: STR | LITERAL, + }, + name: "type", + range: ( + Position { + filename: "test.k", + line: 3, + column: Some( + 15, + ), + }, + Position { + filename: "test.k", + line: 3, + column: Some( + 19, + ), + }, + ), + owner: None, + def: Some( + SymbolRef { + id: Index { + index: 2, + generation: 0, + }, + kind: Value, + }, + ), + attrs: [ + SymbolRef { + id: Index { + index: 141, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 142, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 143, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 144, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 145, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 146, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 147, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 148, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 149, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 150, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 151, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 152, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 153, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 154, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 155, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 156, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 157, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 158, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 159, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 160, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 161, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 162, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 163, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 164, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 165, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 166, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 167, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 168, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 169, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 170, + generation: 0, + }, + kind: Function, + }, + ], + is_global: false, + }, + SymbolInfo { + ty: Type { + kind: StrLit( + "str", + ), + is_type_alias: false, + flags: STR | LITERAL, + }, + name: "@StringLitExpression", + range: ( + Position { + filename: "test.k", + line: 3, + column: Some( + 25, + ), + }, + Position { + filename: "test.k", + line: 3, + column: Some( + 25, + ), + }, + ), + owner: None, + def: Some( + SymbolRef { + id: Index { + index: 1, + generation: 0, + }, + kind: Expression, + }, + ), + attrs: [ + SymbolRef { + id: Index { + index: 141, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 142, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 143, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 144, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 145, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 146, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 147, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 148, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 149, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 150, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 151, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 152, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 153, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 154, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 155, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 156, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 157, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 158, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 159, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 160, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 161, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 162, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 163, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 164, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 165, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 166, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 167, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 168, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 169, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 170, + generation: 0, + }, + kind: Function, + }, + ], + is_global: false, + }, + SymbolInfo { + ty: Type { + kind: BoolLit( + true, + ), + is_type_alias: false, + flags: BOOL | LITERAL, + }, + name: "required", + range: ( + Position { + filename: "test.k", + line: 3, + column: Some( + 27, + ), + }, + Position { + filename: "test.k", + line: 3, + column: Some( + 35, + ), + }, + ), + owner: None, + def: Some( + SymbolRef { + id: Index { + index: 3, + generation: 0, + }, + kind: Value, + }, + ), + attrs: [], + is_global: false, + }, + SymbolInfo { + ty: Type { + kind: BoolLit( + true, + ), + is_type_alias: false, + flags: BOOL | LITERAL, + }, + name: "@NameConstantLitExpression", + range: ( + Position { + filename: "test.k", + line: 3, + column: Some( + 40, + ), + }, + Position { + filename: "test.k", + line: 3, + column: Some( + 40, + ), + }, + ), + owner: None, + def: Some( + SymbolRef { + id: Index { + index: 2, + generation: 0, + }, + kind: Expression, + }, + ), + attrs: [], + is_global: false, + }, + SymbolInfo { + ty: Type { + kind: Any, + is_type_alias: false, + flags: ANY, + }, + name: "@CallExpression", + range: ( + Position { + filename: "test.k", + line: 3, + column: Some( + 41, + ), + }, + Position { + filename: "test.k", + line: 3, + column: Some( + 41, + ), + }, + ), + owner: None, + def: Some( + SymbolRef { + id: Index { + index: 3, + generation: 0, + }, + kind: Expression, + }, + ), + attrs: [], + is_global: false, + }, +] diff --git a/kclvm/loader/src/snapshots/kclvm_loader__tests__import_stmt_0.snap b/kclvm/loader/src/snapshots/kclvm_loader__tests__import_stmt_0.snap new file mode 100644 index 000000000..254a718db --- /dev/null +++ b/kclvm/loader/src/snapshots/kclvm_loader__tests__import_stmt_0.snap @@ -0,0 +1,545 @@ +--- +source: loader/src/tests.rs +expression: "format!(\"{:#?}\", p.symbols.values())" +--- +[ + SymbolInfo { + ty: Type { + kind: Module( + ModuleType { + pkgpath: "math", + imported: [ + "test.k", + ], + kind: System, + }, + ), + is_type_alias: false, + flags: MODULE, + }, + name: "math", + range: ( + Position { + filename: "test.k", + line: 1, + column: Some( + 7, + ), + }, + Position { + filename: "test.k", + line: 1, + column: Some( + 11, + ), + }, + ), + owner: None, + def: Some( + SymbolRef { + id: Index { + index: 3, + generation: 0, + }, + kind: Package, + }, + ), + attrs: [ + SymbolRef { + id: Index { + index: 46, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 47, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 48, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 49, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 50, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 51, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 52, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 53, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 54, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 55, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 56, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 57, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 58, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 59, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 60, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 61, + generation: 0, + }, + kind: Function, + }, + ], + is_global: false, + }, + SymbolInfo { + ty: Type { + kind: Float, + is_type_alias: false, + flags: FLOAT, + }, + name: "a", + range: ( + Position { + filename: "test.k", + line: 3, + column: Some( + 0, + ), + }, + Position { + filename: "test.k", + line: 3, + column: Some( + 1, + ), + }, + ), + owner: Some( + SymbolRef { + id: Index { + index: 15, + generation: 0, + }, + kind: Package, + }, + ), + def: Some( + SymbolRef { + id: Index { + index: 0, + generation: 0, + }, + kind: Value, + }, + ), + attrs: [], + is_global: true, + }, + SymbolInfo { + ty: Type { + kind: Module( + ModuleType { + pkgpath: "math", + imported: [ + "test.k", + ], + kind: System, + }, + ), + is_type_alias: false, + flags: MODULE, + }, + name: "math", + range: ( + Position { + filename: "test.k", + line: 3, + column: Some( + 4, + ), + }, + Position { + filename: "test.k", + line: 3, + column: Some( + 8, + ), + }, + ), + owner: None, + def: Some( + SymbolRef { + id: Index { + index: 3, + generation: 0, + }, + kind: Package, + }, + ), + attrs: [ + SymbolRef { + id: Index { + index: 46, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 47, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 48, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 49, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 50, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 51, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 52, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 53, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 54, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 55, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 56, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 57, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 58, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 59, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 60, + generation: 0, + }, + kind: Function, + }, + SymbolRef { + id: Index { + index: 61, + generation: 0, + }, + kind: Function, + }, + ], + is_global: false, + }, + SymbolInfo { + ty: Type { + kind: Function( + FunctionType { + doc: "Return the logarithm of `x` to the base `e`.", + params: [ + Parameter { + name: "x", + ty: Type { + kind: Union( + [ + Type { + kind: Int, + is_type_alias: false, + flags: INT, + }, + Type { + kind: Float, + is_type_alias: false, + flags: FLOAT, + }, + ], + ), + is_type_alias: false, + flags: UNION, + }, + has_default: false, + default_value: None, + range: ( + Position { + filename: "", + line: 1, + column: None, + }, + Position { + filename: "", + line: 1, + column: None, + }, + ), + }, + Parameter { + name: "e", + ty: Type { + kind: Float, + is_type_alias: false, + flags: FLOAT, + }, + has_default: true, + default_value: None, + range: ( + Position { + filename: "", + line: 1, + column: None, + }, + Position { + filename: "", + line: 1, + column: None, + }, + ), + }, + ], + self_ty: None, + return_ty: Type { + kind: Float, + is_type_alias: false, + flags: FLOAT, + }, + is_variadic: false, + kw_only_index: None, + }, + ), + is_type_alias: false, + flags: FUNCTION, + }, + name: "log", + range: ( + Position { + filename: "test.k", + line: 3, + column: Some( + 9, + ), + }, + Position { + filename: "test.k", + line: 3, + column: Some( + 12, + ), + }, + ), + owner: None, + def: Some( + SymbolRef { + id: Index { + index: 56, + generation: 0, + }, + kind: Function, + }, + ), + attrs: [], + is_global: false, + }, + SymbolInfo { + ty: Type { + kind: IntLit( + 10, + ), + is_type_alias: false, + flags: INT | LITERAL, + }, + name: "@NumberLitExpression", + range: ( + Position { + filename: "test.k", + line: 3, + column: Some( + 15, + ), + }, + Position { + filename: "test.k", + line: 3, + column: Some( + 15, + ), + }, + ), + owner: None, + def: Some( + SymbolRef { + id: Index { + index: 0, + generation: 0, + }, + kind: Expression, + }, + ), + attrs: [], + is_global: false, + }, + SymbolInfo { + ty: Type { + kind: Float, + is_type_alias: false, + flags: FLOAT, + }, + name: "@CallExpression", + range: ( + Position { + filename: "test.k", + line: 3, + column: Some( + 16, + ), + }, + Position { + filename: "test.k", + line: 3, + column: Some( + 16, + ), + }, + ), + owner: None, + def: Some( + SymbolRef { + id: Index { + index: 1, + generation: 0, + }, + kind: Expression, + }, + ), + attrs: [], + is_global: false, + }, +] diff --git a/kclvm/loader/src/snapshots/kclvm_loader__tests__import_stmt_1.snap b/kclvm/loader/src/snapshots/kclvm_loader__tests__import_stmt_1.snap new file mode 100644 index 000000000..e6ca9fbb4 --- /dev/null +++ b/kclvm/loader/src/snapshots/kclvm_loader__tests__import_stmt_1.snap @@ -0,0 +1,86 @@ +--- +source: loader/src/tests.rs +expression: "format!(\"{:#?}\", p.symbols.values())" +--- +[ + SymbolInfo { + ty: Type { + kind: Any, + is_type_alias: false, + flags: ANY, + }, + name: "a", + range: ( + Position { + filename: "test.k", + line: 3, + column: Some( + 0, + ), + }, + Position { + filename: "test.k", + line: 3, + column: Some( + 1, + ), + }, + ), + owner: Some( + SymbolRef { + id: Index { + index: 15, + generation: 0, + }, + kind: Package, + }, + ), + def: Some( + SymbolRef { + id: Index { + index: 0, + generation: 0, + }, + kind: Value, + }, + ), + attrs: [], + is_global: true, + }, + SymbolInfo { + ty: Type { + kind: Any, + is_type_alias: false, + flags: ANY, + }, + name: "@IdentifierExpression", + range: ( + Position { + filename: "test.k", + line: 3, + column: Some( + 9, + ), + }, + Position { + filename: "test.k", + line: 3, + column: Some( + 9, + ), + }, + ), + owner: None, + def: Some( + SymbolRef { + id: Index { + index: 0, + generation: 0, + }, + kind: Expression, + }, + ), + attrs: [], + is_global: false, + }, +] diff --git a/kclvm/loader/src/snapshots/kclvm_loader__tests__list_options_0.snap b/kclvm/loader/src/snapshots/kclvm_loader__tests__list_options_0.snap new file mode 100644 index 000000000..91d15361f --- /dev/null +++ b/kclvm/loader/src/snapshots/kclvm_loader__tests__list_options_0.snap @@ -0,0 +1,13 @@ +--- +source: loader/src/tests.rs +expression: "format!(\"{:#?}\", options)" +--- +[ + OptionHelp { + name: "key", + ty: "int", + required: false, + default_value: "", + help: "", + }, +] diff --git a/kclvm/loader/src/snapshots/kclvm_loader__tests__list_options_1.snap b/kclvm/loader/src/snapshots/kclvm_loader__tests__list_options_1.snap new file mode 100644 index 000000000..2fbb45c5d --- /dev/null +++ b/kclvm/loader/src/snapshots/kclvm_loader__tests__list_options_1.snap @@ -0,0 +1,20 @@ +--- +source: loader/src/tests.rs +expression: "format!(\"{:#?}\", options)" +--- +[ + OptionHelp { + name: "key1", + ty: "str", + required: true, + default_value: "", + help: "", + }, + OptionHelp { + name: "key2", + ty: "int", + required: false, + default_value: "", + help: "", + }, +] diff --git a/kclvm/loader/src/snapshots/kclvm_loader__tests__list_options_2.snap b/kclvm/loader/src/snapshots/kclvm_loader__tests__list_options_2.snap new file mode 100644 index 000000000..df9e327c3 --- /dev/null +++ b/kclvm/loader/src/snapshots/kclvm_loader__tests__list_options_2.snap @@ -0,0 +1,20 @@ +--- +source: loader/src/tests.rs +expression: "format!(\"{:#?}\", options)" +--- +[ + OptionHelp { + name: "key1", + ty: "str", + required: true, + default_value: "\"value\"", + help: "help me", + }, + OptionHelp { + name: "key2", + ty: "", + required: false, + default_value: "", + help: "", + }, +] diff --git a/kclvm/loader/src/snapshots/kclvm_loader__tests__list_options_3.snap b/kclvm/loader/src/snapshots/kclvm_loader__tests__list_options_3.snap new file mode 100644 index 000000000..74b6ab044 --- /dev/null +++ b/kclvm/loader/src/snapshots/kclvm_loader__tests__list_options_3.snap @@ -0,0 +1,13 @@ +--- +source: loader/src/tests.rs +expression: "format!(\"{:#?}\", options)" +--- +[ + OptionHelp { + name: "key1", + ty: "int", + required: false, + default_value: "123", + help: "help me", + }, +] diff --git a/kclvm/loader/src/test_data/test_list_variables/supported.k b/kclvm/loader/src/test_data/test_list_variables/supported.k new file mode 100644 index 000000000..5ba6be574 --- /dev/null +++ b/kclvm/loader/src/test_data/test_list_variables/supported.k @@ -0,0 +1,72 @@ +a = 1 +a1 = 2 +a3 = 3m + +b1 = True +b2 = False + +s1 = "Hello" + +array1 = [1, 2, 3] + +dict1 = {"a": 1, "b": 2} +dict2 = { + "a": 1 + "b": { + "c": 2 + "d": 3 + } +} + +schema A: + name: str + ids: [int] + data?: {str: {str: {str: int}}} + +sha = A { + name: "Hello" + ids: [1, 2, 3] + data: { + "a": { + "b": { + "c": 2 + } + } + } +} + +schema B: + a: A + +shb = B { + a: { + name: "HelloB" + ids: [4, 5, 6] + data: { + "d": { + "e": { + "f": 3 + } + } + } + } +} + +schema UnificationConf: + name: str + +uconfa = UnificationConf{ + name = "a" +} + +uconfa : UnificationConf { + name = "b" +} + +schema C: + a: A + +c = C { + a: {name: "Hello"} + a: {ids: [7, 8, 9]} +} \ No newline at end of file diff --git a/kclvm/loader/src/test_data/test_list_variables/unsupported.k b/kclvm/loader/src/test_data/test_list_variables/unsupported.k new file mode 100644 index 000000000..612176f1a --- /dev/null +++ b/kclvm/loader/src/test_data/test_list_variables/unsupported.k @@ -0,0 +1,18 @@ +list = [ _x for _x in range(20) if _x % 2 == 0] +list1 = [i if i > 2 else i + 1 for i in [1,2,3]] + + +dict = {str(i): 2 * i for i in range(3)} + +func = lambda x: int, y: int -> int { x + y } + +schema IfSchema: + trueValue?: int + falseValue?: int + +if_schema = IfSchema { + if True : + trueValue: 1 + else : + falseValue: 2 +} \ No newline at end of file diff --git a/kclvm/loader/src/tests.rs b/kclvm/loader/src/tests.rs new file mode 100644 index 000000000..363d115cc --- /dev/null +++ b/kclvm/loader/src/tests.rs @@ -0,0 +1,76 @@ +use crate::option::list_options; +use crate::{load_packages, LoadPackageOptions}; +use kclvm_parser::LoadProgramOptions; + +#[macro_export] +macro_rules! load_package_snapshot { + ($name:ident, $src:expr) => { + #[test] + fn $name() { + let p = load_packages(&LoadPackageOptions { + paths: vec!["test.k".to_string()], + load_opts: Some(LoadProgramOptions { + k_code_list: vec![$src.to_string()], + ..Default::default() + }), + load_builtin: false, + ..Default::default() + }) + .unwrap(); + insta::assert_snapshot!(format!("{:#?}", p.symbols.values())); + } + }; +} + +load_package_snapshot! {assign_stmt_0, "a = 1"} +load_package_snapshot! {assign_stmt_1, "a = 1 + 1"} +load_package_snapshot! {assign_stmt_2, "a = (1 + 1)"} + +load_package_snapshot! {import_stmt_0, r#"import math + +a = math.log(10) +"#} +load_package_snapshot! {import_stmt_1, r#"import pkg + +a = pkg.a +"#} +load_package_snapshot! {builtin_call_0, r#"print("hello world")"#} +load_package_snapshot! {builtin_call_1, r#"a = option("key", type="str", required=True)"#} +load_package_snapshot! {builtin_call_2, r#"opt = option + +a = opt("key", type="str", required=True) +"#} + +#[macro_export] +macro_rules! list_options_snapshot { + ($name:ident, $src:expr) => { + #[test] + fn $name() { + let options = list_options(&LoadPackageOptions { + paths: vec!["test.k".to_string()], + load_opts: Some(LoadProgramOptions { + k_code_list: vec![$src.to_string()], + ..Default::default() + }), + load_builtin: false, + ..Default::default() + }) + .unwrap(); + insta::assert_snapshot!(format!("{:#?}", options)); + } + }; +} +list_options_snapshot! {list_options_0, r#"a = option("key", type="int")"#} +list_options_snapshot! {list_options_1, r#"opt = option + +a = opt("key1", type="str", required=True) +b = option("key2", type="int") +"#} +list_options_snapshot! {list_options_2, r#" +a = option("key1", type="str", required=True, default="value", help="help me") +if True: + b = option("key2") +"#} +list_options_snapshot! {list_options_3, r#" +a = option("key1", type="int", required=False, default=123, help="help me") +"#} diff --git a/kclvm/loader/src/util.rs b/kclvm/loader/src/util.rs new file mode 100644 index 000000000..c890b6aa5 --- /dev/null +++ b/kclvm/loader/src/util.rs @@ -0,0 +1,68 @@ +use std::collections::HashMap; + +use kclvm_ast::ast; +use kclvm_ast_pretty::{print_ast_node, ASTNode}; +use kclvm_sema::eval::str_literal_eval; + +pub(crate) fn get_call_args_bool( + call_expr: &ast::CallExpr, + index: usize, + key: Option<&str>, +) -> bool { + let val = get_call_args_string(call_expr, index, key); + val == "True" || val == "true" +} + +pub(crate) fn get_call_args_strip_string( + call_expr: &ast::CallExpr, + index: usize, + key: Option<&str>, +) -> String { + let value = get_call_args_string(call_expr, index, key); + match str_literal_eval(&value, false, false) { + Some(value) => value, + None => value, + } +} + +pub(crate) fn get_call_args_string( + call_expr: &ast::CallExpr, + index: usize, + key: Option<&str>, +) -> String { + let (args, kwargs) = arguments_to_string(&call_expr.args, &call_expr.keywords); + if let Some(key) = key { + if let Some(val) = kwargs.get(key) { + return val.to_string(); + } + } + if index < args.len() { + return args[index].to_string(); + } + "".to_string() +} + +/// Print call arguments to argument vector and keyword mapping. +pub fn arguments_to_string( + args: &[ast::NodeRef], + kwargs: &[ast::NodeRef], +) -> (Vec, HashMap) { + ( + args.iter() + .map(|a| print_ast_node(ASTNode::Expr(a))) + .collect(), + kwargs + .iter() + .map(|a| { + ( + a.node.arg.node.get_name(), + a.node + .value + .as_ref() + .map(|v| print_ast_node(ASTNode::Expr(v))) + .unwrap_or_default(), + ) + }) + .collect(), + ) +} diff --git a/kclvm/macros/Cargo.toml b/kclvm/macros/Cargo.toml index 7945b7958..273f91274 100644 --- a/kclvm/macros/Cargo.toml +++ b/kclvm/macros/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "kclvm-macros" -version = "0.1.0" +version = "0.11.0" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/kclvm/macros/src/symbols.rs b/kclvm/macros/src/symbols.rs index f218f9f60..144f33b80 100644 --- a/kclvm/macros/src/symbols.rs +++ b/kclvm/macros/src/symbols.rs @@ -115,6 +115,7 @@ fn symbols_with_errors(input: TokenStream) -> (TokenStream, Vec) { let mut keyword_stream = quote! {}; let mut symbols_stream = quote! {}; let mut prefill_stream = quote! {}; + let mut reserved_word_stream = quote! {}; let mut counter = 0u32; let mut keys = HashMap::::with_capacity(input.keywords.len() + input.symbols.len() + 10); @@ -151,6 +152,7 @@ fn symbols_with_errors(input: TokenStream) -> (TokenStream, Vec) { let value = &keyword.value; let value_string = value.value(); check_dup(keyword.name.span(), &value_string, &mut errors); + reserved_word_stream.extend(quote! {#value_string,}); prefill_stream.extend(quote! { #value, }); @@ -170,6 +172,7 @@ fn symbols_with_errors(input: TokenStream) -> (TokenStream, Vec) { check_dup(symbol.name.span(), &value, &mut errors); check_order(symbol.name.span(), &name.to_string(), &mut errors); + reserved_word_stream.extend(quote! {#value,}); prefill_stream.extend(quote! { #value, }); @@ -178,6 +181,7 @@ fn symbols_with_errors(input: TokenStream) -> (TokenStream, Vec) { }); counter += 1; } + let reserved_count = counter as usize; // Generate symbols for the strings "0", "1", ..., "9". let digits_base = counter; @@ -208,6 +212,12 @@ fn symbols_with_errors(input: TokenStream) -> (TokenStream, Vec) { #symbols_stream } + #[doc(hidden)] + #[allow(non_upper_case_globals)] + pub mod reserved_word { + pub const reserved_words : [&str; #reserved_count] = [#reserved_word_stream]; + } + impl Interner { pub(crate) fn fresh() -> Self { Interner::prefill(&[ diff --git a/kclvm/makefile b/kclvm/makefile index 3cfc02fe0..755a9df0c 100644 --- a/kclvm/makefile +++ b/kclvm/makefile @@ -1,45 +1,98 @@ default: run PWD:=$(shell pwd) -RUNTIME_NATIVE_BC_PATH:=./runtime/src/_kclvm.bc -COVER_TEST_FILE_PATH:=$(PWD)/../cover/TEST.xml -COVER_REPORT_FILE_PATH:=$(PWD)/../cover/report.html -CARGO_LIBS = $(shell find . -maxdepth 1 -type d) +COVER_REPORT_FILE_PATH:=$(PWD)/target/llvm-cov/html/index.html +# ------------------------ +# Building and tesing deps +# ------------------------ + +# Generate runtime libraries when the runtime code is changed. +gen-runtime-api: + make -C ./runtime gen-api-spec + make fmt + +# Install the wasm32-unknown-unknown target +install-rustc-wasm: + rustup target add wasm32-unknown-unknown + +# Install the wasm-wasi target +install-rustc-wasm-wasi: + rustup target add wasm32-wasi + +# Install python3 pytest +install-test-deps: + python3 -mpip install --user -U pytest pytest-html pytest-xdist ruamel.yaml + +# ------------------------ +# Compile and run +# ------------------------ + +# E2E compile and run run: - cd .. && ./run.sh -a update-kclvm && cd kclvm - kcl ../samples/hello.k --target native + cd .. && make build && cd kclvm + kclvm_cli run ../samples/hello.k +# Cargo check all packages check: cargo check --release +# Cargo fmt all packages fmt: cargo fmt --all +# Cargo clippy all packages lint: - @for i in $(CARGO_LIBS); do cd $(PWD)/$$i && cargo clippy && cd ..; done + cargo clippy -test: - @for i in $(CARGO_LIBS); do cd $(PWD)/$$i && cargo test || { echo 'test kclvm/' $$i 'crate failed' ; exit 1; } && cd ..; done +# Cargo clippy all packages witj auto ix +fix: + cargo clippy --fix --allow-dirty -test-runtime: - cd ./tests/test_units && python3 -m pip install pytest && PYTHONPATH=./../../plugin python3 -m pytest -vv || { echo 'kclvm/tests/test_units failed' ; exit 1; } +build-wasm: + cargo build --target=wasm32-wasi --release -test-grammar: install-pytest - cd tests/integration/grammar && kclvm -m pytest -v -n 5 --junitxml $(COVER_TEST_FILE_PATH) --html=$(COVER_REPORT_FILE_PATH) +build-lsp: + cargo build --release --manifest-path tools/src/LSP/Cargo.toml -fuzz-parser: - cd tests && cargo fuzz run fuzz_parser +# ------------------------ +# Tests +# ------------------------ -install-pytest: - kclvm -mpip install pytest-html +# Unit tests without code cov +test: + cargo test --workspace -r -- --nocapture -release: - cargo build --release +# Unit tests with code cov (Requires rust 1.60+) +codecov: + rustup component add llvm-tools-preview + cargo install cargo-llvm-cov + cargo llvm-cov --workspace --ignore-filename-regex gpyrpc.rs --html --open -- --nocapture +# Unit tests with code cov and output the lcov file (Requires rust 1.60+) +codecov-lcov: + rustup component add llvm-tools-preview + cargo install cargo-llvm-cov + rm -rf $(PWD)/.kclvm_cov + mkdir $(PWD)/.kclvm_cov + cargo llvm-cov --lcov --output-path $(PWD)/.kclvm_cov/lcov.info -r --workspace --ignore-filename-regex gpyrpc.rs -- --nocapture -gen-runtime-api: - make -C ./runtime gen-api-spec +# Test runtime libaries using python functions +test-runtime: install-test-deps + cd ./tests/test_units && PYTHONPATH=./../../tests/test_units/runtime python3 -m pytest -vv || { echo 'kclvm/tests/test_units failed' ; exit 1; } -install-rustc-wasm: - rustup target add wasm32-unknown-unknown +# E2E grammar tests. +test-grammar: install-test-deps + cd tests/integration/grammar && python3 -m pytest -v -n 5 + +# E2E grammar tests with the fast evaluator +test-grammar-evaluator: install-test-deps + cd tests/integration/grammar && KCL_FAST_EVAL=1 python3 -m pytest -v -n 5 + +# E2E konfig tests. +test-konfig: install-test-deps + cd tests/integration/konfig && python3 -m pytest -v -n 5 + +# Parser fuzz. +fuzz-parser: + cd tests && cargo fuzz run fuzz_parser diff --git a/kclvm/parser/Cargo.toml b/kclvm/parser/Cargo.toml index be3246e08..ed82afe41 100644 --- a/kclvm/parser/Cargo.toml +++ b/kclvm/parser/Cargo.toml @@ -1,14 +1,15 @@ [package] name = "kclvm-parser" -version = "0.1.0" +version = "0.11.0" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -rustc_span = { path = "../3rdparty/rustc_span" } -rustc_data_structures = { path = "../3rdparty/rustc_data_structures" } - +compiler_base_span = "0.1.2" +compiler_base_session = "0.1.3" +compiler_base_error = "0.1.6" +compiler_base_macros = "0.1.1" tracing = "0.1" serde = { version = "1", features = ["derive"] } serde_json = "1.0" @@ -17,16 +18,23 @@ either = "1.1.0" enquote = "1.1.0" unicode_names2 = "0.4" bstr = "0.2.16" +petgraph = "0.6.0" num-bigint = "0.4" +regex = "1.7.0" +anyhow = "1.0" +indexmap = "1.0" +parking_lot = "0.12.3" +glob = "0.3.1" -kclvm-lexer = {path = "../lexer", version = "0.1.0"} -kclvm-ast = {path = "../ast", version = "0.1.0"} -kclvm-span = {path = "../span", version = "0.1.0"} -kclvm-error = {path = "../error", version = "0.1.0"} -kclvm-config = {path = "../config", version = "0.1.0"} -kclvm-sema = {path = "../sema", version = "0.1.0"} -kclvm-runtime = {path = "../runtime", version = "0.1.0"} - +kclvm-lexer = {path = "../lexer"} +kclvm-ast = {path = "../ast"} +kclvm-span = {path = "../span"} +kclvm-error = {path = "../error"} +kclvm-config = {path = "../config"} +kclvm-sema = {path = "../sema"} +kclvm-utils = {path = "../utils"} +walkdir = "2" [dev-dependencies] -expect-test = "1.0" \ No newline at end of file +expect-test = "1.0" +insta = "1.8.0" diff --git a/kclvm/parser/Makefile b/kclvm/parser/Makefile deleted file mode 100644 index 5bc0e2252..000000000 --- a/kclvm/parser/Makefile +++ /dev/null @@ -1,31 +0,0 @@ -TARG:=hello.k - -IGNORED_KEYS:=line,column,end_line,end_column,comments,filename - -dev: - -@cargo fmt - - cargo build - ./target/debug/parse_module ${TARG} 2>&1 1> ./a.out.json - - cat ./a.out.json | jq - - -@rm ./a.out.json - -debug: - RUST_BACKTRACE=1 cargo run --bin parse_module ${TARG} - -diff: - -@ rm *.out.json - cargo run --bin load_program ${TARG} | jq -S > 1.out.json - kclvm -m kclvm.internal.kclx -f=${TARG} | jq -S > 0.out.json - code --diff 0.out.json 1.out.json - -ast: - @kclvm -m kclvm.internal.kclx -f=${TARG} | jq - -lint: - cargo clippy - -clean: - cargo clean diff --git a/kclvm/parser/src/bin/load_program.rs b/kclvm/parser/src/bin/load_program.rs deleted file mode 100644 index 4d50dc81f..000000000 --- a/kclvm/parser/src/bin/load_program.rs +++ /dev/null @@ -1,8 +0,0 @@ -extern crate kclvm_parser; - -fn main() { - let filename = std::env::args().nth(1).expect("filename missing"); - let m = kclvm_parser::load_program(&[filename.as_str()], None); - let json = serde_json::ser::to_string(&m).unwrap(); - println!("{}", json); -} diff --git a/kclvm/parser/src/bin/parse_file.rs b/kclvm/parser/src/bin/parse_file.rs deleted file mode 100644 index 8c40aa5cf..000000000 --- a/kclvm/parser/src/bin/parse_file.rs +++ /dev/null @@ -1,8 +0,0 @@ -extern crate kclvm_parser; - -fn main() { - let filename = std::env::args().nth(1).expect("filename missing"); - let m = kclvm_parser::parse_file(filename.as_str(), None); - let json = serde_json::ser::to_string(&m).unwrap(); - println!("{}", json); -} diff --git a/kclvm/parser/src/bin/parse_module.rs b/kclvm/parser/src/bin/parse_module.rs deleted file mode 100644 index 81c01dcb0..000000000 --- a/kclvm/parser/src/bin/parse_module.rs +++ /dev/null @@ -1,8 +0,0 @@ -extern crate kclvm_parser; - -fn main() { - let filename = std::env::args().nth(1).expect("filename missing"); - let m = kclvm_parser::parse_program(filename.as_str()); - let json = serde_json::ser::to_string(&m).unwrap(); - println!("{}", json); -} diff --git a/kclvm/parser/src/entry.rs b/kclvm/parser/src/entry.rs new file mode 100644 index 000000000..1fa951624 --- /dev/null +++ b/kclvm/parser/src/entry.rs @@ -0,0 +1,580 @@ +use anyhow::Result; +use glob::glob; +use kclvm_config::modfile::get_pkg_root; +use kclvm_config::modfile::KCL_FILE_SUFFIX; +use kclvm_config::path::ModRelativePath; +use kclvm_utils::path::PathPrefix; +use kclvm_utils::path::{is_absolute, is_dir, path_exist}; +use std::collections::VecDeque; +use std::fs; +use std::path::Path; +use std::path::PathBuf; + +use crate::LoadProgramOptions; + +/// [`Entries`] is a map of package name to package root path for one compilation +/// # note +/// +/// The [`entries`] in [`Entries`] is ordered, and the order of Entrys may affect the result of the compilation. +/// The reason why the [`Entries`] is not an [`IndexMap`] is that the [`entries`] is duplicable and ordered. +#[derive(Default, Debug)] +pub struct Entries { + root_path: String, + entries: VecDeque, +} + +impl Entries { + /// [`get_unique_normal_paths_by_name`] will return all the unique normal paths of [`Entry`] with the given name in [`Entries`]. + pub fn get_unique_normal_paths_by_name(&self, name: &str) -> Vec { + let paths = self + .get_unique_paths_by_name(name) + .iter() + .filter(|path| { + // All the paths contains the normal paths and the mod relative paths start with ${KCL_MOD}. + // If the number of 'kcl.mod' paths is 0, except for the mod relative paths start with ${KCL_MOD}, + // then use empty path "" as the default. + !ModRelativePath::new(path.to_string()) + .is_relative_path() + .unwrap_or(false) + }) + .map(|entry| entry.to_string()) + .collect::>(); + paths + } + + /// [`get_unique_paths_by_name`] will return all the unique paths of [`Entry`] with the given name in [`Entries`]. + pub fn get_unique_paths_by_name(&self, name: &str) -> Vec { + let mut paths = self + .entries + .iter() + .filter(|entry| entry.name() == name) + .map(|entry| entry.path().to_string()) + .collect::>(); + paths.sort(); + paths.dedup(); + paths + } + + /// [`push_entry`] will push a new [`Entry`] into [`Entries`]. + pub fn push_entry(&mut self, entry: Entry) { + self.entries.push_back(entry); + } + + /// [`push`] will push a new [`Entry`] into [`Entries`] with the given name and path. + pub fn push(&mut self, name: String, path: String) { + self.entries.push_back(Entry::new(name, path)); + } + + /// [`contains_pkg_name`] will return [`Option::Some`] if there is an [`Entry`] with the given name in [`Entries`]. + pub fn contains_pkg_name(&self, name: &String) -> Option<&Entry> { + self.entries.iter().find(|entry| entry.name() == name) + } + + /// [`iter`] will return an iterator of [`Entry`] in [`Entries`]. + pub fn iter(&self) -> std::collections::vec_deque::Iter { + self.entries.iter() + } + + /// [`len`] will return the length of [`Entries`]. + pub fn len(&self) -> usize { + self.entries.len() + } + + /// [`get_nth_entry`] will return the nth [`Entry`] in [`Entries`]. + #[allow(dead_code)] + pub fn get_nth_entry(&self, n: usize) -> Option<&Entry> { + if n >= self.len() { + return None; + } + let mut count = 0; + for entry in self.entries.iter() { + if count == n { + return Some(entry); + } + count += 1; + } + None + } + + /// [`get_nth_entry_by_name`] will return the nth [`Entry`] by name in [`Entries`]. + pub fn get_nth_entry_by_name(&self, n: usize, name: &str) -> Option<&Entry> { + self.entries + .iter() + .enumerate() + .filter(|(_, entry)| name == entry.name()) + .nth(n) + .map(|(_, entry)| entry) + } + + /// [`apply_to_all_entries`] will apply the given function to all [`Entry`] in [`Entries`]. + pub fn apply_to_all_entries(&mut self, f: F) -> Result<()> + where + F: FnMut(&mut Entry) -> Result<()>, + { + self.entries.iter_mut().try_for_each(f)?; + Ok(()) + } + + /// [`get_root_path`] will return the root path of [`Entries`]. + pub fn get_root_path(&self) -> &String { + &self.root_path + } +} + +/// [`Entry`] is a package name and package root path pair. +#[derive(Default, Debug)] +pub struct Entry { + name: String, + path: String, + k_files: Vec, + k_code_lists: Vec>, +} + +impl Entry { + /// [`new`] will create a new [`Entry`] with the given name and path. + pub fn new(name: String, path: String) -> Self { + Self { + name, + path, + k_files: vec![], + k_code_lists: vec![], + } + } + + /// [`name`] will return the name of [`Entry`]. + pub fn name(&self) -> &String { + &self.name + } + + /// [`path`] will return the path of [`Entry`]. + pub fn path(&self) -> &String { + &self.path + } + + /// [`set_path`] will set the path of [`Entry`] to the given path. + pub fn set_path(&mut self, path: String) { + self.path = path; + } + + /// [`extend_k_files`] will extend the k files of [`Entry`] to the given k file. + pub fn extend_k_files(&mut self, k_files: Vec) { + self.k_files.extend(k_files); + } + + /// [`extend_k_files_and_codes`] will extend the k files and k codes of [`Entry`] to the given k file and k code. + pub fn extend_k_files_and_codes( + &mut self, + k_files: Vec, + k_codes: &mut VecDeque, + ) { + for k_file in k_files.iter() { + self.k_code_lists.push(k_codes.pop_front()); + self.k_files.push(k_file.to_string()); + } + } + + /// [`push_k_code`] will push the k code of [`Entry`] to the given k code. + pub fn push_k_code(&mut self, k_code: Option) { + self.k_code_lists.push(k_code); + } + + /// [`get_k_files`] will return the k files of [`Entry`]. + pub fn get_k_files(&self) -> &Vec { + &self.k_files + } + + /// [`get_k_codes`] will return the k codes of [`Entry`]. + pub fn get_k_codes(&self) -> &Vec> { + &self.k_code_lists + } +} + +/// [`get_normalized_k_files_from_paths`] returns all the [`String`] for compilation from the given [`file_paths`]. +pub fn get_normalized_k_files_from_paths( + file_paths: &[String], + opts: &LoadProgramOptions, +) -> Result> { + let mut files = vec![]; + let entries = get_compile_entries_from_paths(file_paths, opts)?; + for entry in entries.iter() { + files.append(&mut entry.get_k_files().clone()) + } + Ok(files) +} + +/// [`get_compile_entries_from_paths`] returns all the [`Entries`] for compilation from the given [`file_paths`]. +/// +/// # Note +/// If the path in [`file_paths`] is a normal path or a [`ModRelativePath`] with prefix `${KCL_MOD}`, the package will be named as `__main__`. +/// If the path in [`file_paths`] is a [`ModRelativePath`], the package will be named by the suffix of [`ModRelativePath`]. +/// +/// # Error +/// The package root path for package name `__main__` is only used once. If there are multiple +/// package root paths for `__main__`, an error `conflict kcl.mod file` is returned. +/// +/// # Example +/// +/// ```rust +/// use std::path::PathBuf; +/// use kclvm_parser::entry::get_compile_entries_from_paths; +/// use kclvm_parser::LoadProgramOptions; +/// let testpath = PathBuf::from("./src/testdata/multimods").canonicalize().unwrap(); +/// +/// // [`kcl1_path`] is a normal path of the package [`kcl1`] root directory. +/// // It looks like `/xxx/xxx/xxx`. +/// let kcl1_path = testpath.join("kcl1"); +/// +/// // [`kcl2_path`] is a mod relative path of the packege [`kcl2`] root directory. +/// // It looks like `${kcl2:KCL_MOD}/xxx/xxx` +/// let kcl2_path = PathBuf::from("${kcl2:KCL_MOD}/main.k"); +/// +/// // [`kcl3_path`] is a mod relative path of the [`__main__`] packege. +/// // It looks like `${KCL_MOD}/xxx/xxx` +/// let kcl3_path = PathBuf::from("${KCL_MOD}/main.k"); +/// +/// // [`package_maps`] is a map to show the real path of the mod relative path [`kcl2`]. +/// let mut opts = LoadProgramOptions::default(); +/// opts.package_maps.insert("kcl2".to_string(), testpath.join("kcl2").to_str().unwrap().to_string()); +/// +/// // [`get_compile_entries_from_paths`] will return the map of package name to package root real path. +/// let entries = get_compile_entries_from_paths( +/// &[ +/// kcl1_path.to_str().unwrap().to_string(), +/// kcl2_path.display().to_string(), +/// kcl3_path.display().to_string(), +/// ], +/// &opts, +/// ).unwrap(); +/// +/// // [`entries`] will contain 3 entries. +/// // <__main__, "/usr/xxx/src/testdata/multimods/kcl1"> +/// // +/// // <__main__, "/usr/xxx/src/testdata/multimods/kcl1"> +/// assert_eq!(entries.len(), 3); +/// +/// // <__main__, "/usr/xxx/src/testdata/multimods/kcl1"> +/// assert_eq!(entries.get_nth_entry(0).unwrap().name(), "__main__"); +/// assert_eq!( +/// PathBuf::from(entries.get_nth_entry(0).unwrap().path()) +/// .canonicalize() +/// .unwrap() +/// .display() +/// .to_string(), +/// kcl1_path.canonicalize().unwrap().to_str().unwrap() +/// ); +/// +/// // +/// assert_eq!(entries.get_nth_entry(1).unwrap().name(), "kcl2"); +/// assert_eq!( +/// PathBuf::from(entries.get_nth_entry(1).unwrap().path()) +/// .canonicalize() +/// .unwrap() +/// .display() +/// .to_string(), +/// testpath +/// .join("kcl2") +/// .canonicalize() +/// .unwrap() +/// .to_str() +/// .unwrap() +/// ); +/// +/// // <__main__, "/usr/xxx/src/testdata/multimods/kcl1"> +/// assert_eq!(entries.get_nth_entry(2).unwrap().name(), "__main__"); +/// assert_eq!( +/// PathBuf::from(entries.get_nth_entry(2).unwrap().path()) +/// .canonicalize() +/// .unwrap() +/// .to_str() +/// .unwrap(), +/// kcl1_path.canonicalize().unwrap().to_str().unwrap() +/// ); +/// ``` +pub fn get_compile_entries_from_paths( + file_paths: &[String], + opts: &LoadProgramOptions, +) -> Result { + if file_paths.is_empty() { + return Err(anyhow::anyhow!("No input KCL files or paths")); + } + let mut result = Entries::default(); + let mut k_code_queue = VecDeque::from(opts.k_code_list.clone()); + let file_paths = expand_input_files(file_paths); + for file in &file_paths { + let file = canonicalize_input_file(file, &opts.work_dir); + let path = ModRelativePath::from(file.to_string()); + + // If the path is a [`ModRelativePath`] with prefix '${:KCL_MOD}', + // calculate the real path and the package name. + if let Some((pkg_name, pkg_path)) = path.get_root_pkg_name()?.and_then(|name| { + opts.package_maps + .get(&name) + .map(|pkg_path: &String| (name, pkg_path)) + }) { + // Replace the mod relative path prefix '${:KCL_MOD}' with the real path. + let file = path.canonicalize_by_root_path(pkg_path)?; + if let Some(root) = get_pkg_root(&file) { + let mut entry: Entry = Entry::new(pkg_name.clone(), root.clone()); + entry.extend_k_files_and_codes( + get_main_files_from_pkg_path(&file, &root, &pkg_name, opts)?, + &mut k_code_queue, + ); + result.push_entry(entry); + continue; + } + // If the [`ModRelativePath`] with prefix '${KCL_MOD}' + } else if path.is_relative_path()? && path.get_root_pkg_name()?.is_none() { + // Push it into `result`, and deal it later. + let mut entry = Entry::new(kclvm_ast::MAIN_PKG.to_string(), path.get_path()); + entry.push_k_code(k_code_queue.pop_front()); + result.push_entry(entry); + continue; + } else if let Some(root) = get_pkg_root(&file) { + // If the path is a normal path. + let mut entry: Entry = Entry::new(kclvm_ast::MAIN_PKG.to_string(), root.clone()); + entry.extend_k_files_and_codes( + get_main_files_from_pkg_path(&file, &root, kclvm_ast::MAIN_PKG, opts)?, + &mut k_code_queue, + ); + result.push_entry(entry); + } + } + + // The main 'kcl.mod' can not be found, the empty path "" will be took by default. + if result + .get_unique_normal_paths_by_name(kclvm_ast::MAIN_PKG) + .is_empty() + { + let mut entry = Entry::new(kclvm_ast::MAIN_PKG.to_string(), "".to_string()); + for file in &file_paths { + entry.extend_k_files_and_codes( + get_main_files_from_pkg_path(&file, "", kclvm_ast::MAIN_PKG, opts)?, + &mut k_code_queue, + ); + } + result.push_entry(entry); + } + + let pkg_root = if result + .get_unique_normal_paths_by_name(kclvm_ast::MAIN_PKG) + .len() + == 1 + && opts.work_dir.is_empty() + { + // If the 'kcl.mod' can be found only once, the package root path will be the path of the 'kcl.mod'. + result + .get_unique_normal_paths_by_name(kclvm_ast::MAIN_PKG) + .get(0) + .unwrap() + .to_string() + } else if !opts.work_dir.is_empty() { + // If the 'kcl.mod' can be found more than once, the package root path will be the 'work_dir'. + if let Some(root_work_dir) = get_pkg_root(&opts.work_dir) { + root_work_dir + } else { + "".to_string() + } + } else { + "".to_string() + }; + result.root_path = pkg_root.clone(); + // Replace the '${KCL_MOD}' of all the paths with package name '__main__'. + result.apply_to_all_entries(|entry| { + let path = ModRelativePath::from(entry.path().to_string()); + if entry.name() == kclvm_ast::MAIN_PKG && path.is_relative_path()? { + entry.set_path(pkg_root.to_string()); + entry.extend_k_files(get_main_files_from_pkg_path( + &path.canonicalize_by_root_path(&pkg_root)?, + &pkg_root, + kclvm_ast::MAIN_PKG, + opts, + )?); + } + Ok(()) + })?; + + Ok(result) +} + +/// Get files in the main package with the package root. +fn get_main_files_from_pkg_path( + pkg_path: &str, + root: &str, + pkg_name: &str, + opts: &LoadProgramOptions, +) -> Result> { + // fix path + let mut path_list = Vec::new(); + let mut s = pkg_path.to_string(); + + let path = ModRelativePath::from(s.to_string()); + + if path.is_relative_path()? { + if let Some(name) = path.get_root_pkg_name()? { + if name == pkg_name { + s = path.canonicalize_by_root_path(root)?; + } + } else if path.is_relative_path()? { + return Err(anyhow::anyhow!("Can not find {} in the path: {}", s, root)); + } + } + if !root.is_empty() && !is_absolute(s.as_str()) { + let p = std::path::Path::new(s.as_str()); + if let Ok(x) = std::fs::canonicalize(p) { + s = x.adjust_canonicalization(); + } + } + + match PathBuf::from(s.clone()).canonicalize() { + Ok(path) => { + path_list.push(path.to_str().unwrap().to_string()); + } + // path from virtual file system + Err(_) => path_list.push(s), + } + + // get k files + let mut k_files: Vec = Vec::new(); + + for (i, path) in path_list.iter().enumerate() { + // read dir/*.k + if !path.is_empty() && is_dir(path) { + if opts.k_code_list.len() > i { + return Err(anyhow::anyhow!("Invalid code list for the path {}", path)); + } + // k_code_list + for s in get_dir_files(path, false)? { + k_files.push(s); + } + continue; + } else { + k_files.push(path.to_string()); + } + } + + if k_files.is_empty() { + return Err(anyhow::anyhow!("No input KCL files")); + } + + // check all file exists + for (i, filename) in k_files.iter().enumerate() { + if i < opts.k_code_list.len() { + continue; + } + + if !path_exist(filename.as_str()) { + return Err(anyhow::anyhow!( + "Cannot find the kcl file, please check the file path {}", + filename.as_str(), + )); + } + } + Ok(k_files) +} + +/// Get file list in the directory. +pub fn get_dir_files(dir: &str, is_recursive: bool) -> Result> { + if !std::path::Path::new(dir).exists() { + return Ok(Vec::new()); + } + + let mut list = Vec::new(); + let mut queue: VecDeque = VecDeque::new(); + queue.push_back(dir.to_string()); + // BFS all the files in the directory. + while let Some(path) = queue.pop_front() { + let path = Path::new(&path); + if path.is_dir() { + match fs::read_dir(path) { + Ok(entries) => { + for entry in entries { + if let Ok(entry) = entry { + let path = entry.path(); + if path.is_dir() && is_recursive { + queue.push_back(path.to_string_lossy().to_string()); + } else if !is_ignored_file(&path.display().to_string()) { + list.push(path.display().to_string()); + } + } + } + } + Err(err) => { + return Err(anyhow::anyhow!( + "Failed to read directory: {},{}", + path.display(), + err + )); + } + } + } else if !is_ignored_file(&path.display().to_string()) { + list.push(path.display().to_string()); + } + } + + list.sort(); + Ok(list) +} + +/// Check if the file is ignored. +/// The file is ignored if +/// it is not a kcl file (end with '*.k') +/// or it is a test file (end with '_test.k') +/// or it is a hidden file. (start with '_') +fn is_ignored_file(filename: &str) -> bool { + (!filename.ends_with(KCL_FILE_SUFFIX)) + || (filename.ends_with("_test.k")) + || (filename.starts_with('_')) +} + +/// Normalize the input file with the working directory and replace ${KCL_MOD} with the module root path. +pub fn canonicalize_input_file(file: &str, work_dir: &str) -> String { + let path = std::path::Path::new(file); + let is_absolute = path.is_absolute(); + // If the input file or path is a relative path and it is not a absolute path in the KCL module VFS, + // join with the work directory path and convert it to a absolute path. + let path = ModRelativePath::from(file.to_string()); + let is_relative_path = match path.is_relative_path() { + Ok(is_relative_path) => is_relative_path, + _ => return file.to_string(), + }; + + let abs_path = if !is_absolute && !is_relative_path { + let filepath = std::path::Path::new(work_dir).join(file); + match filepath.canonicalize() { + Ok(path) => Some(path.adjust_canonicalization()), + Err(_) => Some(filepath.to_string_lossy().to_string()), + } + } else { + None + }; + abs_path.unwrap_or(file.to_string()) +} + +/// Expand the single file pattern to a list of files. +pub fn expand_if_file_pattern(file_pattern: String) -> Result> { + let paths = glob(&file_pattern)?; + let mut matched_files = vec![]; + + for path in paths.flatten() { + matched_files.push(path.to_string_lossy().to_string()); + } + + Ok(matched_files) +} + +/// Expand input kcl files with the file patterns e.g. `/path/to/kcl/*.k`, `**/**/*.k` +pub fn expand_input_files(k_files: &[String]) -> Vec { + let mut res = vec![]; + for file in k_files { + if let Ok(files) = expand_if_file_pattern(file.to_string()) { + if !files.is_empty() { + res.extend(files); + } else { + res.push(file.to_string()) + } + } else { + res.push(file.to_string()) + } + } + res +} diff --git a/kclvm/parser/src/file_graph.rs b/kclvm/parser/src/file_graph.rs new file mode 100644 index 000000000..de1d42182 --- /dev/null +++ b/kclvm/parser/src/file_graph.rs @@ -0,0 +1,227 @@ +use std::{collections::HashMap, path::PathBuf}; + +use indexmap::IndexMap; +use kclvm_ast::ast::Module; +use kclvm_utils::path::PathPrefix; +use petgraph::{prelude::StableDiGraph, visit::EdgeRef}; +use std::hash::Hash; +/// File with package info +#[derive(Debug, Clone, Hash, Eq, PartialEq)] +pub struct PkgFile { + path: PathBuf, + pub pkg_path: String, +} + +impl PkgFile { + pub fn new(path: PathBuf, pkg_path: String) -> PkgFile { + match path.canonicalize() { + Ok(p) => PkgFile { + path: PathBuf::from(p.adjust_canonicalization()), + pkg_path, + }, + Err(_) => PkgFile { path, pkg_path }, + } + } + + pub fn get_path(&self) -> &PathBuf { + &self.path + } +} + +#[derive(Debug, Clone, Hash, Eq, PartialEq)] +pub struct Pkg { + pub pkg_name: String, + pub pkg_root: String, +} + +pub type PkgMap = IndexMap; + +/// A graph of files, where each file depends on zero or more other files. +#[derive(Default, Debug)] +pub struct PkgFileGraph { + graph: StableDiGraph, + path_to_node_index: IndexMap, +} + +impl PkgFileGraph { + /// Sets a file to depend on the given other files. + /// + /// For example, if the current graph has file A depending on B, and + /// `update_file(pathA, &[pathC])` was called, then this function will remove the edge + /// from A to B, and add an edge from A to C. + pub fn update_file<'a, I: IntoIterator>( + &mut self, + from_path: &PkgFile, + to_paths: I, + ) { + let from_node_index = self.get_or_insert_node_index(from_path); + + // remove all current out coming edges from this node + self.graph.retain_edges(|g, edge| { + if let Some((source, _)) = g.edge_endpoints(edge) { + if source == from_node_index { + return false; + } + } + true + }); + + for to_path in to_paths { + let to_node_index = self.get_or_insert_node_index(to_path); + self.graph.add_edge(from_node_index, to_node_index, ()); + } + } + + /// Returns true if the given file is in the graph + pub fn contains_file(&self, file: &PkgFile) -> bool { + contains_file(file, &self.path_to_node_index) + } + + /// Returns a list of the direct dependencies of the given file. + /// (does not include all transitive dependencies) + /// The file path must be relative to the root of the file graph. + pub fn dependencies_of(&self, file: &PkgFile) -> Vec { + dependencies_of(file, &self.graph, &self.path_to_node_index) + } + + /// Returns a list of files in the order they should be compiled + /// Or a list of files that are part of a cycle, if one exists + pub fn toposort(&self) -> Result, Vec> { + toposort(&self.graph) + } + + /// Returns all paths. + #[inline] + pub fn paths(&self) -> Vec { + self.path_to_node_index.keys().cloned().collect::>() + } + + fn get_or_insert_node_index(&mut self, file: &PkgFile) -> petgraph::graph::NodeIndex { + if let Some(node_index) = self.path_to_node_index.get(file) { + return *node_index; + } + + let node_index = self.graph.add_node(file.to_owned()); + self.path_to_node_index.insert(file.to_owned(), node_index); + node_index + } + + pub fn file_path_graph( + &self, + ) -> ( + StableDiGraph, + IndexMap, + ) { + let mut graph = StableDiGraph::new(); + let mut node_map = IndexMap::new(); + for node in self.graph.node_indices() { + let path = self.graph[node].path.clone(); + let idx = graph.add_node(path.clone()); + node_map.insert(path, idx); + } + for edge in self.graph.edge_indices() { + if let Some((source, target)) = self.graph.edge_endpoints(edge) { + let source_path = self.graph[source].path.clone(); + let target_path = self.graph[target].path.clone(); + match (node_map.get(&source_path), node_map.get(&target_path)) { + (Some(source), Some(target)) => { + graph.add_edge(source.clone(), target.clone(), ()); + } + _ => {} + } + } + } + (graph, node_map) + } + + pub fn pkg_graph( + &self, + pkgs: &HashMap>, + ) -> ( + StableDiGraph, + IndexMap, + ) { + let mut graph = StableDiGraph::new(); + let mut node_map = IndexMap::new(); + + for pkg in pkgs.keys() { + let idx = graph.add_node(pkg.clone()); + node_map.insert(pkg.clone(), idx); + } + + for node in self.graph.node_indices() { + let path = self.graph[node].pkg_path.clone(); + let idx = graph.add_node(path.clone()); + node_map.insert(path, idx); + } + for edge in self.graph.edge_indices() { + if let Some((source, target)) = self.graph.edge_endpoints(edge) { + let source_path = self.graph[source].pkg_path.clone(); + let target_path = self.graph[target].pkg_path.clone(); + graph.add_edge( + node_map.get(&source_path).unwrap().clone(), + node_map.get(&target_path).unwrap().clone(), + (), + ); + } + } + (graph, node_map) + } +} + +/// Returns a list of files in the order they should be compiled +/// Or a list of files that are part of a cycle, if one exists +pub fn toposort(graph: &StableDiGraph) -> Result, Vec> +where + T: Clone, +{ + match petgraph::algo::toposort(graph, None) { + Ok(indices) => Ok(indices + .into_iter() + .rev() + .map(|n| graph[n].clone()) + .collect::>()), + Err(err) => { + // toposort function in the `petgraph` library doesn't return the cycle itself, + // so we need to use Tarjan's algorithm to find one instead + let strongly_connected_components = petgraph::algo::tarjan_scc(&graph); + // a strongly connected component is a cycle if it has more than one node + // let's just return the first one we find + let cycle = match strongly_connected_components + .into_iter() + .find(|component| component.len() > 1) + { + Some(vars) => vars, + None => vec![err.node_id()], + }; + Err(cycle.iter().map(|n| graph[*n].clone()).collect::>()) + } + } +} + +/// Returns a list of the direct dependencies of the given file. +/// (does not include all transitive dependencies) +/// The file path must be relative to the root of the file graph. +pub fn dependencies_of( + node: &T, + graph: &StableDiGraph, + id_map: &IndexMap, +) -> Vec +where + T: Clone + Hash + Eq + PartialEq, +{ + let node_index = id_map.get(node).expect("node not in graph"); + graph + .edges(*node_index) + .map(|edge| &graph[edge.target()]) + .map(|node| node.clone()) + .collect::>() +} + +/// Returns true if the given file is in the graph +pub fn contains_file(node: &T, id_map: &IndexMap) -> bool +where + T: Clone + Hash + Eq + PartialEq, +{ + id_map.contains_key(node) +} diff --git a/kclvm/parser/src/lexer/indent.rs b/kclvm/parser/src/lexer/indent.rs index d5361d0f5..f53ee8ff3 100644 --- a/kclvm/parser/src/lexer/indent.rs +++ b/kclvm/parser/src/lexer/indent.rs @@ -1,10 +1,10 @@ //! KCL indent handling. -//! See details defined in KCL Grammar ['./spec/grammar']. use std::cmp::Ordering; use crate::lexer::IndentOrDedents; use crate::lexer::Lexer; +use kclvm_ast::token::VALID_SPACES_LENGTH; use kclvm_ast::token::{self, Token}; #[derive(Clone, Copy, PartialEq, Debug, Default)] @@ -77,22 +77,26 @@ impl<'a> Lexer<'a> { self.indent_cxt.spaces = 0; // process indent at the end of the newline - let mut cur_indent = self.indent_cxt.indents.last().unwrap(); - let indet = IndentLevel { tabs, spaces }; - let mut ordering = indet.cmp(cur_indent); + let mut cur_indent = self.last_indent(); + let indent = IndentLevel { tabs, spaces }; + let mut ordering = indent.cmp(cur_indent); match ordering { Ok(order) => { Some(match order { Ordering::Greater => { - self.indent_cxt.indents.push(indet); + self.indent_cxt.indents.push(indent); // For indent token, we ignore the length - let indent = Token::new(token::Indent, self.span(self.pos, self.pos)); + let indent = Token::new( + token::Indent(VALID_SPACES_LENGTH), + self.span(self.pos, self.pos), + ); IndentOrDedents::Indent { token: indent } } Ordering::Less => { let mut dedents = Vec::new(); + let mut indents = Vec::new(); loop { match ordering { @@ -100,11 +104,13 @@ impl<'a> Lexer<'a> { match order { Ordering::Less => { // Pop indents util we find an equal ident level - self.indent_cxt.indents.pop(); + if let Some(indent) = self.indent_cxt.indents.pop() { + indents.push(indent); + } // update pos & collect dedent // For dedent token, we ignore the length let dedent = Token::new( - token::Dedent, + token::Dedent(VALID_SPACES_LENGTH), self.span(self.pos, self.pos), ); dedents.push(dedent); @@ -113,30 +119,51 @@ impl<'a> Lexer<'a> { // Proper indent level found. break; } - Ordering::Greater => self.sess.struct_span_error( - "fatal: logic error on dedenting.", - self.span(self.pos, self.pos), - ), + Ordering::Greater => { + let spaces_diff = indent.spaces - cur_indent.spaces; + if let Some(indent) = indents.pop() { + self.indent_cxt.indents.push(indent); + } + dedents.pop(); + dedents.push(Token::new( + token::Dedent(spaces_diff), + self.span(self.pos, self.pos), + )); + break; + } } // update cur indent and ordering - cur_indent = self.indent_cxt.indents.last().unwrap(); - ordering = indet.cmp(cur_indent); + cur_indent = self.last_indent(); + ordering = indent.cmp(cur_indent); + } + Err(msg) => { + self.sess + .struct_span_error(msg, self.span(self.pos, self.pos)); + break; } - Err(msg) => self - .sess - .struct_span_error(msg, self.span(self.pos, self.pos)), } } - IndentOrDedents::Dedents { tokens: dedents } } _ => return None, }) } - Err(msg) => self - .sess - .struct_span_error(msg, self.span(self.pos, self.pos)), + Err(msg) => { + self.sess + .struct_span_error(msg, self.span(self.pos, self.pos)); + None + } + } + } + + /// Get the last indent, if not exists, return a default level for error recovery. + fn last_indent(&mut self) -> &IndentLevel { + if self.indent_cxt.indents.is_empty() { + self.sess + .struct_span_error("mismatched indent level", self.span(self.pos, self.pos)); + self.indent_cxt.indents.push(IndentLevel::default()); } + self.indent_cxt.indents.last().unwrap() } } diff --git a/kclvm/parser/src/lexer/mod.rs b/kclvm/parser/src/lexer/mod.rs index 590e6fd2d..4ec4dc5eb 100644 --- a/kclvm/parser/src/lexer/mod.rs +++ b/kclvm/parser/src/lexer/mod.rs @@ -1,7 +1,6 @@ //! A KCL lexer. //! -//! The lexer is built on the low level [`kclvm_lexer`], and works -//! based on the rules defined by the KCL grammar ['./spec/grammar']. +//! The lexer is built on the low level [`kclvm_lexer`] //! //! It's main responsibilities: //! 1. Mapping low level [`kclvm_lexer::Token`] tokens into [`kclvm_ast::Token`] tokens, @@ -21,13 +20,15 @@ mod string; #[cfg(test)] mod tests; +use compiler_base_macros::bug; +use compiler_base_span::{self, span::new_byte_pos, BytePos, Span}; use kclvm_ast::ast::NumberBinarySuffix; -use kclvm_ast::token::{self, CommentKind, Token, TokenKind}; +use kclvm_ast::token::VALID_SPACES_LENGTH; +use kclvm_ast::token::{self, BinOpToken, CommentKind, Token, TokenKind}; use kclvm_ast::token_stream::TokenStream; +use kclvm_error::ParseErrorMessage; use kclvm_lexer::Base; use kclvm_span::symbol::Symbol; -use kclvm_span::{self, BytePos, Span}; -use rustc_span::Pos; pub(crate) use string::str_content_eval; use self::indent::IndentLevel; @@ -41,13 +42,14 @@ pub fn parse_token_streams(sess: &ParseSession, src: &str, start_pos: BytePos) - sess, start_pos, pos: start_pos, + tok_start_pos: start_pos, end_src_index: src.len(), src, token: TokenWithIndents::Token { token: Token::dummy(), }, indent_cxt: IndentContext { - nesting: 0, + delims: Vec::new(), tabs: 0, spaces: 0, new_line_beginning: false, @@ -112,6 +114,9 @@ struct Lexer<'a> { /// The absolute offset within the source_map of the current character. pos: BytePos, + /// The start position of the current token. + tok_start_pos: BytePos, + /// Stop reading src at this index. end_src_index: usize, @@ -129,12 +134,12 @@ struct Lexer<'a> { } struct IndentContext { - /// nested level counter - nesting: usize, - /// A new line flag new_line_beginning: bool, + /// Delim stack + delims: Vec, + /// tab counter tabs: usize, @@ -148,18 +153,23 @@ struct IndentContext { impl<'a> Lexer<'a> { fn into_tokens(mut self) -> TokenStream { let mut buf = TokenStreamBuilder::default(); - self.token = self.token(); + // In the process of look-behind lexing, it is necessary to check the type of the previous token in 'buf', + // If the previous token and the current token can form a multi-character token, + // then the previous token will be popped from 'buf'. + // + // Therefore, the method 'self.token()' needs to take the mutable reference of 'buf' as an incoming argument. + self.token = self.token(&mut buf); while !self.token.is_eof() { self.token.append_to(&mut buf); - self.token = self.token(); + self.token = self.token(&mut buf); } self.eof(&mut buf); buf.into_token_stream() } - fn token(&mut self) -> TokenWithIndents { + fn token(&mut self, tok_stream_builder: &mut TokenStreamBuilder) -> TokenWithIndents { loop { let start_src_index = self.src_index(self.pos); let text: &str = &self.src[start_src_index..self.end_src_index]; @@ -176,12 +186,19 @@ impl<'a> Lexer<'a> { // Detect and handle indent cases before lexing on-going token let indent = self.lex_indent_context(token.kind); - let start = self.pos; + // Because of the 'look-behind', the 'start' of the current token becomes a two-way cursor, + // which can not only move forward, but also move backward when 'look-behind'. + // Therefore, the value of 'self.tok_start_pos' can be changed in 'self.lex_token()'. + self.tok_start_pos = self.pos; // update pos after token and indent handling - self.pos = self.pos + BytePos::from_usize(token.len); + self.pos = self.pos + new_byte_pos(token.len as u32); - if let Some(kind) = self.lex_token(token, start) { - let span = self.span(start, self.pos); + // In the process of look-behind lexing, it is necessary to check the type of the previous token in 'tok_stream_builder', + // If the previous token and the current token can form a multi-character token, + // then the previous token will be popped from 'tok_stream_builder'. + // Therefore, the method 'self.lex_token()' needs to take the mutable reference of 'tok_stream_builder' as an incoming argument. + if let Some(kind) = self.lex_token(token, self.tok_start_pos, tok_stream_builder) { + let span = self.span(self.tok_start_pos, self.pos); match indent { Some(iord) => { @@ -203,7 +220,12 @@ impl<'a> Lexer<'a> { } /// Turns `kclvm_lexer::TokenKind` into a rich `kclvm_ast::TokenKind`. - fn lex_token(&mut self, token: kclvm_lexer::Token, start: BytePos) -> Option { + fn lex_token( + &mut self, + token: kclvm_lexer::Token, + start: BytePos, + tok_stream_builder: &mut TokenStreamBuilder, + ) -> Option { Some(match token.kind { kclvm_lexer::TokenKind::LineComment { doc_style: _ } => { let s = self.str_from(start); @@ -225,7 +247,7 @@ impl<'a> Lexer<'a> { } // Literal kclvm_lexer::TokenKind::Literal { kind, suffix_start } => { - let suffix_start = start + BytePos::from_u32(suffix_start as u32); + let suffix_start = start + new_byte_pos(suffix_start as u32); let (kind, symbol, suffix, raw) = self.lex_literal(start, suffix_start, kind); token::Literal(token::Lit { kind, @@ -236,26 +258,17 @@ impl<'a> Lexer<'a> { } // Unary op kclvm_lexer::TokenKind::Tilde => token::UnaryOp(token::UTilde), - kclvm_lexer::TokenKind::Bang => token::UnaryOp(token::UNot), + kclvm_lexer::TokenKind::Bang => { + self.sess.struct_message_error_with_suggestions( + ParseErrorMessage::InvalidTokenNot, + self.span(start, self.pos), + Some(vec!["not ".to_string()]), + ); + token::UnaryOp(token::UNot) + } // Binary op kclvm_lexer::TokenKind::Plus => token::BinOp(token::Plus), - kclvm_lexer::TokenKind::Minus => { - let head = start + BytePos::from_u32(1); - let tail = start + BytePos::from_u32(2); - if self.has_next_token(head, tail){ - let next_tkn = - self.str_from_to(head, tail); - if next_tkn == ">" { - // waste '>' token - self.pos = self.pos + BytePos::from_usize(1); - token::RArrow - } else { - token::BinOp(token::Minus) - } - }else{ - token::BinOp(token::Minus) - } - } + kclvm_lexer::TokenKind::Minus => token::BinOp(token::Minus), kclvm_lexer::TokenKind::Star => token::BinOp(token::Star), kclvm_lexer::TokenKind::Slash => token::BinOp(token::Slash), kclvm_lexer::TokenKind::Percent => token::BinOp(token::Percent), @@ -284,7 +297,13 @@ impl<'a> Lexer<'a> { kclvm_lexer::TokenKind::BangEq => token::BinCmp(token::NotEq), kclvm_lexer::TokenKind::Lt => token::BinCmp(token::Lt), kclvm_lexer::TokenKind::LtEq => token::BinCmp(token::LtEq), - kclvm_lexer::TokenKind::Gt => token::BinCmp(token::Gt), + // If the current token is '>', + // then lexer need to check whether the previous token is '-', + // if yes, return token '->', if not return token '>'. + kclvm_lexer::TokenKind::Gt => match self.look_behind(&token, tok_stream_builder) { + Some(tok_kind) => tok_kind, + None => token::BinCmp(token::Gt), + }, kclvm_lexer::TokenKind::GtEq => token::BinCmp(token::GtEq), // Structural symbols kclvm_lexer::TokenKind::At => token::At, @@ -297,58 +316,177 @@ impl<'a> Lexer<'a> { kclvm_lexer::TokenKind::Eq => token::Assign, // Delim tokens kclvm_lexer::TokenKind::OpenParen => { - self.indent_cxt.nesting += 1; + self.indent_cxt.delims.push(token::OpenDelim(token::Paren)); token::OpenDelim(token::Paren) } - kclvm_lexer::TokenKind::CloseParen => { - if self.indent_cxt.nesting == 0 { + kclvm_lexer::TokenKind::CloseParen => match self.indent_cxt.delims.pop() { + // check delim stack + Some(delim) => match delim { + // expected case + token::OpenDelim(token::Paren) => token::CloseDelim(token::Paren), + // error recovery + token::OpenDelim(token::Brace) => { + self.sess.struct_span_error( + "error nesting on close paren", + self.span(start, self.pos), + ); + token::CloseDelim(token::Brace) + } + // error recovery + token::OpenDelim(token::Bracket) => { + self.sess.struct_span_error( + "error nesting on close paren", + self.span(start, self.pos), + ); + token::CloseDelim(token::Bracket) + } + // impossible case + _ => bug!("Impossible!"), + }, + // error recovery + None => { self.sess.struct_span_error( "error nesting on close paren", self.span(start, self.pos), - ) + ); + token::CloseDelim(token::Paren) } - self.indent_cxt.nesting -= 1; - token::CloseDelim(token::Paren) - } + }, kclvm_lexer::TokenKind::OpenBrace => { - self.indent_cxt.nesting += 1; + self.indent_cxt.delims.push(token::OpenDelim(token::Brace)); token::OpenDelim(token::Brace) } - kclvm_lexer::TokenKind::CloseBrace => { - if self.indent_cxt.nesting == 0 { + kclvm_lexer::TokenKind::CloseBrace => match self.indent_cxt.delims.pop() { + // check delim stack + Some(delim) => match delim { + // expected case + token::OpenDelim(token::Brace) => token::CloseDelim(token::Brace), + // error recovery + token::OpenDelim(token::Paren) => { + self.sess.struct_span_error( + "error nesting on close brace", + self.span(start, self.pos), + ); + token::CloseDelim(token::Paren) + } + // error recovery + token::OpenDelim(token::Bracket) => { + self.sess.struct_span_error( + "error nesting on close brace", + self.span(start, self.pos), + ); + token::CloseDelim(token::Bracket) + } + // impossible case + _ => bug!("Impossible!"), + }, + // error recovery + None => { self.sess.struct_span_error( "error nesting on close brace", self.span(start, self.pos), - ) + ); + token::CloseDelim(token::Brace) } - self.indent_cxt.nesting -= 1; - token::CloseDelim(token::Brace) - } + }, kclvm_lexer::TokenKind::OpenBracket => { - self.indent_cxt.nesting += 1; + self.indent_cxt + .delims + .push(token::OpenDelim(token::Bracket)); token::OpenDelim(token::Bracket) } - kclvm_lexer::TokenKind::CloseBracket => { - if self.indent_cxt.nesting == 0 { + kclvm_lexer::TokenKind::CloseBracket => match self.indent_cxt.delims.pop() { + // check delim stack + Some(delim) => match delim { + // expected case + token::OpenDelim(token::Bracket) => token::CloseDelim(token::Bracket), + // error recovery + token::OpenDelim(token::Brace) => { + self.sess.struct_span_error( + "mismatched closing delimiter", + self.span(start, self.pos), + ); + token::CloseDelim(token::Brace) + } + // error recovery + token::OpenDelim(token::Paren) => { + self.sess.struct_span_error( + "mismatched closing delimiter", + self.span(start, self.pos), + ); + token::CloseDelim(token::Paren) + } + // impossible case + _ => bug!("Impossible!"), + }, + // error recovery + None => { self.sess.struct_span_error( - "error nesting on close bracket", + "mismatched closing delimiter", self.span(start, self.pos), - ) + ); + token::CloseDelim(token::Bracket) } - self.indent_cxt.nesting -= 1; - token::CloseDelim(token::Bracket) - } + }, kclvm_lexer::TokenKind::LineContinue => return None, - kclvm_lexer::TokenKind::InvalidLineContinue => self.sess.struct_span_error( - "unexpected character after line continuation character", - self.span(start, self.pos), - ), - _ => self - .sess - .struct_span_error("unknown start of token", self.span(start, self.pos)), + kclvm_lexer::TokenKind::InvalidLineContinue => { + // If we encounter an illegal line continuation character, + // we will restore it to a normal line continuation character. + self.sess.struct_message_error_with_suggestions( + ParseErrorMessage::CharAfterLineContinuationToken, + self.span(start, self.pos), + None, + ); + return None; + } + kclvm_lexer::TokenKind::Semi => { + // If we encounter an illegal semi token ';', raise a friendly error. + self.sess.struct_message_error_with_suggestions( + ParseErrorMessage::RedundantSemicolon, + self.span(start, self.pos), + Some(vec!["".to_string()]), + ); + return None; + } + _ => { + self.sess + .struct_span_error("unknown start of token", self.span(start, self.pos)); + return None; + } }) } + /// From the lexed tokens stack, check whether the token at the top of the stack and the current character can combine a new token. + /// If yes, lexer will pop the token at the top of the stack and return a new token combined with the token poped and the current character. + /// If not, return None. + fn look_behind( + &mut self, + tok: &kclvm_lexer::Token, + tok_stream_builder: &mut TokenStreamBuilder, + ) -> Option { + match tok.kind { + // Most multi-character tokens are lexed in ['kclvm-lexer'], + // and the multi-character tokens that need to be lexed in ['kclvm-parser/lexer'] are only token '->'. + // If a new multi-character token is added later, the corresponding operation can be added here. + kclvm_lexer::TokenKind::Gt => { + if tok_stream_builder + .pop_if_tok_kind(&TokenKind::BinOp(BinOpToken::Minus)) + .is_some() + { + // After the previous token pops up, 'self.tok_start_pos' needs to be updated. + if self.tok_start_pos >= new_byte_pos(1) { + self.tok_start_pos = self.tok_start_pos - new_byte_pos(1); + return Some(TokenKind::RArrow); + } else { + bug!("Internal Bugs: Please connect us to fix it, invalid token start pos") + } + } + } + _ => return None, + } + None + } + fn lex_literal( &self, start: BytePos, @@ -360,19 +498,22 @@ impl<'a> Lexer<'a> { terminated, triple_quoted, } => { - if !terminated { - self.sess - .struct_span_error("unterminated string", self.span(start, self.pos)) - } - let start_char = self.char_from(start); - let (is_raw, quote_char) = match start_char { - 'r' | 'R' => (true, self.char_from(start + BytePos::from_u32(1))), - _ => (false, start_char), + let (is_raw, quote_char_pos, quote_char) = match start_char { + 'r' | 'R' => { + let pos = start + new_byte_pos(1); + (true, pos, self.char_from(pos)) + } + _ => (false, start, start_char), }; - - // cut offset before validation - let offset = if triple_quoted { + if !terminated { + self.sess.struct_span_error( + "unterminated string", + self.span(quote_char_pos, self.pos), + ); + } + // Cut offset before validation. + let offset: u32 = if triple_quoted { if is_raw { 4 } else { @@ -384,24 +525,39 @@ impl<'a> Lexer<'a> { 1 }; - let content_start = start + BytePos::from_u32(offset); - let mut content_end = suffix_start - BytePos::from_u32(offset); + let content_start = start + new_byte_pos(offset); + let mut content_end = suffix_start - new_byte_pos(offset); if is_raw { - content_end = content_end + BytePos::from_u32(1); + content_end = content_end + new_byte_pos(1); + } + // For unclosed quote string, cut offset of the string content. + if !terminated { + content_end = content_end + new_byte_pos(if triple_quoted { 3 } else { 1 }) } - let string_content = self.str_from_to(content_start, content_end); - let value = match str_content_eval( - string_content, - quote_char, - triple_quoted, - false, - is_raw, - ) { - Some(v) => v, - None => self.sess.struct_span_error( - "Invalid string syntax", + // If start > end, it is a invalid string content. + let value = if content_start > content_end { + // If get an error string from the eval process, + // directly return an empty string. + self.sess.struct_span_error( + "invalid string syntax", self.span(content_start, self.pos), - ), + ); + "".to_string() + } else { + let string_content = self.str_from_to(content_start, content_end); + match str_content_eval(string_content, quote_char, triple_quoted, false, is_raw) + { + Some(v) => v, + None => { + // If get an error string from the eval process, + // directly return an empty string. + self.sess.struct_span_error( + "invalid string syntax", + self.span(content_start, self.pos), + ); + "".to_string() + } + } }; ( @@ -419,9 +575,15 @@ impl<'a> Lexer<'a> { self.sess.struct_span_error( "no valid digits found for number", self.span(start, self.pos), - ) + ); + // If it is a empty int, returns number 0. + (token::Integer, Symbol::intern("0"), None, None) } else { - self.validate_literal_int(base, start, suffix_start); + let symbol = if self.validate_literal_int(base, start, suffix_start) { + self.symbol_from_to(start, suffix_start) + } else { + Symbol::intern("0") + }; let suffix = if suffix_start < self.pos { let suffix_str = self.str_from(suffix_start); @@ -430,19 +592,16 @@ impl<'a> Lexer<'a> { self.sess.struct_span_error( "invalid int binary suffix", self.span(start, self.pos), - ) + ); + None + } else { + Some(Symbol::intern(suffix_str)) } - Some(Symbol::intern(suffix_str)) } else { None }; - ( - token::Integer, - self.symbol_from_to(start, suffix_start), - suffix, - None, - ) + (token::Integer, symbol, suffix, None) } } @@ -450,13 +609,12 @@ impl<'a> Lexer<'a> { base, empty_exponent, } => { - self.validate_literal_float(base, start, empty_exponent); - ( - token::Float, - self.symbol_from_to(start, suffix_start), - None, - None, - ) + let symbol = if self.validate_literal_float(base, start, empty_exponent) { + self.symbol_from_to(start, suffix_start) + } else { + Symbol::intern("0") + }; + (token::Float, symbol, None, None) } kclvm_lexer::LiteralKind::Bool { terminated: _ } => ( token::Bool, @@ -464,60 +622,58 @@ impl<'a> Lexer<'a> { None, None, ), - _ => self.sess.struct_span_error( - &format!("invalid lit kind {:?}", kind), - self.span(start, self.pos), - ), } } - fn validate_literal_int(&self, base: Base, content_start: BytePos, content_end: BytePos) { + fn validate_literal_int( + &self, + base: Base, + content_start: BytePos, + content_end: BytePos, + ) -> bool { let base = match base { Base::Binary => 2, Base::Octal => 8, Base::Hexadecimal => 16, - _ => return, + Base::Decimal => return true, }; - let s = self.str_from_to(content_start + BytePos::from_u32(2), content_end); + let s = self.str_from_to(content_start + new_byte_pos(2), content_end); for (idx, c) in s.char_indices() { let idx = idx as u32; if c != '_' && c.to_digit(base).is_none() { - let lo = content_start + BytePos::from_u32(2 + idx); - let hi = content_start + BytePos::from_u32(2 + idx + c.len_utf8() as u32); + let lo = content_start + new_byte_pos(2 + idx); + let hi = content_start + new_byte_pos(2 + idx + c.len_utf8() as u32); self.sess.struct_span_error( - &format!( - "invalid digit for a base {} literal, start: {}, stop: {}", - base, lo, hi - ), + &format!("invalid digit for a base {base} literal, start: {lo}, stop: {hi}"), self.span(lo, self.pos), - ) + ); + return false; } } + true } - fn validate_literal_float(&self, base: Base, start: BytePos, empty_exponent: bool) { + fn validate_literal_float(&self, base: Base, start: BytePos, empty_exponent: bool) -> bool { if empty_exponent { self.sess.struct_span_error( "expected at least one digit in exponent", self.span(start, self.pos), - ) - } - - match base { - kclvm_lexer::Base::Hexadecimal => self.sess.struct_span_error( - "hexadecimal float literal is not supported", - self.span(start, self.pos), - ), - kclvm_lexer::Base::Octal => self.sess.struct_span_error( - "octal float literal is not supported", - self.span(start, self.pos), - ), - kclvm_lexer::Base::Binary => self.sess.struct_span_error( - "binary float literal is not supported", - self.span(start, self.pos), - ), - _ => (), + ); + false + } else { + match base { + kclvm_lexer::Base::Hexadecimal + | kclvm_lexer::Base::Octal + | kclvm_lexer::Base::Binary => { + self.sess.struct_span_error( + &format!("{} float literal is not supported", base.describe()), + self.span(start, self.pos), + ); + false + } + _ => true, + } } } @@ -527,7 +683,7 @@ impl<'a> Lexer<'a> { #[inline] fn src_index(&self, pos: BytePos) -> usize { - (pos - self.start_pos).to_usize() + (pos - self.start_pos).0 as usize } /// Char at `pos` in the source @@ -546,24 +702,11 @@ impl<'a> Lexer<'a> { &self.src[self.src_index(start)..self.src_index(end)] } - fn has_next_token(&self, start: BytePos, end: BytePos) -> bool{ - if self.src_index(start) > self.src_index(end) || self.src_index(end) > self.src.len(){ false }else{ true } - } - fn symbol_from_to(&self, start: BytePos, end: BytePos) -> Symbol { Symbol::intern(self.str_from_to(start, end)) } fn eof(&mut self, buf: &mut TokenStreamBuilder) { - let start = self.pos; - - if self.indent_cxt.nesting > 0 { - self.sess.struct_span_error( - "Unclosed nesting at the end of the file", - self.span(start, self.pos), - ) - } - if !self.indent_cxt.new_line_beginning { self.indent_cxt.new_line_beginning = true; buf.push(Token::new(token::Newline, self.span(self.pos, self.pos))); @@ -571,7 +714,10 @@ impl<'a> Lexer<'a> { while self.indent_cxt.indents.len() > 1 { self.indent_cxt.indents.pop(); - buf.push(Token::new(token::Dedent, self.span(self.pos, self.pos))); + buf.push(Token::new( + token::Dedent(VALID_SPACES_LENGTH), + self.span(self.pos, self.pos), + )); } buf.push(Token::new(token::Eof, self.span(self.pos, self.pos))); @@ -591,4 +737,27 @@ impl TokenStreamBuilder { fn into_token_stream(self) -> TokenStream { TokenStream::new(self.buf) } + + /// Pop the token at the top of the stack, and return None if the stack is empty. + fn pop(&mut self) -> Option { + self.buf.pop() + } + + /// If the token kind at the top of the stack is 'expected_tok_kind', + /// pop the token and return it, otherwise do nothing and return None. + fn pop_if_tok_kind(&mut self, expected_tok_kind: &TokenKind) -> Option { + if self.peek_tok_kind() == expected_tok_kind { + self.pop() + } else { + None + } + } + + /// Peek the kind of the token on the top of the stack. + fn peek_tok_kind(&self) -> &TokenKind { + match self.buf.last() { + Some(tok) => &tok.kind, + None => &TokenKind::Dummy, + } + } } diff --git a/kclvm/parser/src/lexer/string.rs b/kclvm/parser/src/lexer/string.rs index fd490c105..246d6d1db 100644 --- a/kclvm/parser/src/lexer/string.rs +++ b/kclvm/parser/src/lexer/string.rs @@ -105,10 +105,9 @@ fn parse_octet(first: char, chars: &mut std::iter::Peekable) -> char { octet_content.push(first); while octet_content.len() < 3 { let next_char = chars.next(); - if let Some('0'..='7') = next_char { - octet_content.push(next_char.unwrap()) - } else { - break; + match next_char { + Some(o @ '0'..='7') => octet_content.push(o), + _ => break, } } let value = u32::from_str_radix(&octet_content, 8).unwrap(); diff --git a/kclvm/parser/src/lexer/tests.rs b/kclvm/parser/src/lexer/tests.rs index a5216d53d..bda1cc021 100644 --- a/kclvm/parser/src/lexer/tests.rs +++ b/kclvm/parser/src/lexer/tests.rs @@ -1,20 +1,84 @@ use super::*; use crate::lexer::str_content_eval; use crate::session::ParseSession; +use compiler_base_error::diagnostic_handler::DiagnosticHandler; +use compiler_base_session::Session; +use compiler_base_span::{span::new_byte_pos, FilePathMapping, SourceMap}; use expect_test::{expect, Expect}; -use kclvm_span::{create_session_globals_then, BytePos, FilePathMapping, SourceMap}; +use kclvm_error::Handler; +use kclvm_span::create_session_globals_then; +use parking_lot::RwLock; use std::path::PathBuf; use std::sync::Arc; -fn check_lexing(src: &str, expect: Expect) { +impl ParseSession { + #[inline] + pub(crate) fn with_source_map(sm: Arc) -> Self { + Self( + Arc::new(Session::new(sm, Arc::new(DiagnosticHandler::default()))), + RwLock::new(Handler::default()), + ) + } +} + +/// lexing the 'src'. +fn lex(src: &str) -> (String, String) { let sm = SourceMap::new(FilePathMapping::empty()); sm.new_source_file(PathBuf::from("").into(), src.to_string()); let sess = &ParseSession::with_source_map(Arc::new(sm)); - create_session_globals_then(|| { - let actual: String = parse_token_streams(sess, src, BytePos::from_u32(0)) + // preprocess the input str by [`SourceFile`] + let sf = sess + .0 + .sm + .new_source_file(PathBuf::from("").into(), src.to_string()); + + let src_from_sf = match sf.src.as_ref() { + Some(src) => src, + None => { + panic!("Unreachable code") + } + }; + + let res = create_session_globals_then(|| { + parse_token_streams(sess, src_from_sf, new_byte_pos(0)) .iter() .map(|token| format!("{:?}\n", token)) + .collect() + }); + + let err_msgs = sess + .0 + .emit_all_diags_into_string() + .unwrap() + .iter() + .map(|err| err.as_ref().unwrap().to_string()) + .collect(); + + (res, err_msgs) +} + +/// check the invalid panic message. +fn check_lexing_with_err_msg(src: &str, expect: Expect, expect_err_msg: Expect) { + let (got, got_err) = lex(src); + expect.assert_eq(&got); + expect_err_msg.assert_eq(&got_err); +} + +fn check_lexing(src: &str, expect: Expect) { + expect.assert_eq(&lex(src).0); +} + +// Get the code snippets from 'src' by token.span, and compare with expect. +fn check_span(src: &str, expect: Expect) { + let sm = SourceMap::new(FilePathMapping::empty()); + sm.new_source_file(PathBuf::from("").into(), src.to_string()); + let sess = &ParseSession::with_source_map(Arc::new(SourceMap::new(FilePathMapping::empty()))); + + create_session_globals_then(move || { + let actual: String = parse_token_streams(sess, src, new_byte_pos(0)) + .iter() + .map(|token| format!("{:?}\n", sm.span_to_snippet(token.span).unwrap())) .collect(); expect.assert_eq(&actual) }); @@ -43,8 +107,7 @@ fn test_str_content_eval() { assert_eq!( str_content_eval(input, quote_char, triple_quoted, is_bytes, is_raw), expected, - "test failed, input: {}", - input + "test failed, input: {input}" ) } } @@ -227,7 +290,7 @@ $ Token { kind: Newline, span: Span { base_or_index: 108, len_or_tag: 1 } } Token { kind: BinOpEq(SlashSlash), span: Span { base_or_index: 109, len_or_tag: 3 } } Token { kind: Newline, span: Span { base_or_index: 112, len_or_tag: 1 } } - Token { kind: BinCmp(LtEq), span: Span { base_or_index: 113, len_or_tag: 3 } } + Token { kind: BinOpEq(Shl), span: Span { base_or_index: 113, len_or_tag: 3 } } Token { kind: Newline, span: Span { base_or_index: 116, len_or_tag: 1 } } Token { kind: BinOpEq(Shr), span: Span { base_or_index: 117, len_or_tag: 3 } } Token { kind: Newline, span: Span { base_or_index: 120, len_or_tag: 1 } } @@ -339,29 +402,29 @@ println("end") Token { kind: Ident(Symbol(SymbolIndex { idx: 42 })), span: Span { base_or_index: 4, len_or_tag: 5 } } Token { kind: Colon, span: Span { base_or_index: 9, len_or_tag: 1 } } Token { kind: Newline, span: Span { base_or_index: 10, len_or_tag: 1 } } - Token { kind: Indent, span: Span { base_or_index: 15, len_or_tag: 0 } } + Token { kind: Indent(0), span: Span { base_or_index: 15, len_or_tag: 0 } } Token { kind: Ident(Symbol(SymbolIndex { idx: 10 })), span: Span { base_or_index: 15, len_or_tag: 2 } } Token { kind: Ident(Symbol(SymbolIndex { idx: 43 })), span: Span { base_or_index: 18, len_or_tag: 5 } } Token { kind: Colon, span: Span { base_or_index: 23, len_or_tag: 1 } } Token { kind: Newline, span: Span { base_or_index: 24, len_or_tag: 1 } } - Token { kind: Indent, span: Span { base_or_index: 33, len_or_tag: 0 } } + Token { kind: Indent(0), span: Span { base_or_index: 33, len_or_tag: 0 } } Token { kind: Ident(Symbol(SymbolIndex { idx: 44 })), span: Span { base_or_index: 33, len_or_tag: 7 } } Token { kind: OpenDelim(Paren), span: Span { base_or_index: 40, len_or_tag: 1 } } Token { kind: Literal(Lit { kind: Str { is_long_string: false, is_raw: false }, symbol: Symbol(SymbolIndex { idx: 45 }), suffix: None, raw: Some(Symbol(SymbolIndex { idx: 46 })) }), span: Span { base_or_index: 41, len_or_tag: 11 } } Token { kind: CloseDelim(Paren), span: Span { base_or_index: 52, len_or_tag: 1 } } Token { kind: Newline, span: Span { base_or_index: 53, len_or_tag: 1 } } - Token { kind: Dedent, span: Span { base_or_index: 58, len_or_tag: 0 } } + Token { kind: Dedent(0), span: Span { base_or_index: 58, len_or_tag: 0 } } Token { kind: Ident(Symbol(SymbolIndex { idx: 12 })), span: Span { base_or_index: 58, len_or_tag: 4 } } Token { kind: Colon, span: Span { base_or_index: 62, len_or_tag: 1 } } Token { kind: Newline, span: Span { base_or_index: 63, len_or_tag: 1 } } - Token { kind: Indent, span: Span { base_or_index: 72, len_or_tag: 0 } } + Token { kind: Indent(0), span: Span { base_or_index: 72, len_or_tag: 0 } } Token { kind: Ident(Symbol(SymbolIndex { idx: 44 })), span: Span { base_or_index: 72, len_or_tag: 7 } } Token { kind: OpenDelim(Paren), span: Span { base_or_index: 79, len_or_tag: 1 } } Token { kind: Literal(Lit { kind: Str { is_long_string: false, is_raw: false }, symbol: Symbol(SymbolIndex { idx: 47 }), suffix: None, raw: Some(Symbol(SymbolIndex { idx: 48 })) }), span: Span { base_or_index: 80, len_or_tag: 12 } } Token { kind: CloseDelim(Paren), span: Span { base_or_index: 92, len_or_tag: 1 } } Token { kind: Newline, span: Span { base_or_index: 93, len_or_tag: 1 } } - Token { kind: Dedent, span: Span { base_or_index: 94, len_or_tag: 0 } } - Token { kind: Dedent, span: Span { base_or_index: 94, len_or_tag: 0 } } + Token { kind: Dedent(0), span: Span { base_or_index: 94, len_or_tag: 0 } } + Token { kind: Dedent(0), span: Span { base_or_index: 94, len_or_tag: 0 } } Token { kind: Ident(Symbol(SymbolIndex { idx: 44 })), span: Span { base_or_index: 94, len_or_tag: 7 } } Token { kind: OpenDelim(Paren), span: Span { base_or_index: 101, len_or_tag: 1 } } Token { kind: Literal(Lit { kind: Str { is_long_string: false, is_raw: false }, symbol: Symbol(SymbolIndex { idx: 49 }), suffix: None, raw: Some(Symbol(SymbolIndex { idx: 50 })) }), span: Span { base_or_index: 102, len_or_tag: 5 } } @@ -406,12 +469,12 @@ Schema (1, 2) { Token { kind: CloseDelim(Paren), span: Span { base_or_index: 13, len_or_tag: 1 } } Token { kind: OpenDelim(Brace), span: Span { base_or_index: 15, len_or_tag: 1 } } Token { kind: Newline, span: Span { base_or_index: 16, len_or_tag: 1 } } - Token { kind: Indent, span: Span { base_or_index: 21, len_or_tag: 0 } } + Token { kind: Indent(0), span: Span { base_or_index: 21, len_or_tag: 0 } } Token { kind: Ident(Symbol(SymbolIndex { idx: 43 })), span: Span { base_or_index: 21, len_or_tag: 1 } } Token { kind: Assign, span: Span { base_or_index: 22, len_or_tag: 1 } } Token { kind: Ident(Symbol(SymbolIndex { idx: 44 })), span: Span { base_or_index: 23, len_or_tag: 1 } } Token { kind: Newline, span: Span { base_or_index: 24, len_or_tag: 1 } } - Token { kind: Dedent, span: Span { base_or_index: 25, len_or_tag: 0 } } + Token { kind: Dedent(0), span: Span { base_or_index: 25, len_or_tag: 0 } } Token { kind: CloseDelim(Brace), span: Span { base_or_index: 25, len_or_tag: 1 } } Token { kind: Newline, span: Span { base_or_index: 26, len_or_tag: 1 } } Token { kind: Eof, span: Span { base_or_index: 27, len_or_tag: 0 } } @@ -434,12 +497,12 @@ fn schema_expr_1() { Token { kind: CloseDelim(Paren), span: Span { base_or_index: 12, len_or_tag: 1 } } Token { kind: OpenDelim(Brace), span: Span { base_or_index: 14, len_or_tag: 1 } } Token { kind: Newline, span: Span { base_or_index: 15, len_or_tag: 1 } } - Token { kind: Indent, span: Span { base_or_index: 20, len_or_tag: 0 } } + Token { kind: Indent(0), span: Span { base_or_index: 20, len_or_tag: 0 } } Token { kind: Ident(Symbol(SymbolIndex { idx: 43 })), span: Span { base_or_index: 20, len_or_tag: 1 } } Token { kind: Assign, span: Span { base_or_index: 21, len_or_tag: 1 } } Token { kind: Ident(Symbol(SymbolIndex { idx: 44 })), span: Span { base_or_index: 22, len_or_tag: 1 } } Token { kind: Newline, span: Span { base_or_index: 23, len_or_tag: 1 } } - Token { kind: Dedent, span: Span { base_or_index: 24, len_or_tag: 0 } } + Token { kind: Dedent(0), span: Span { base_or_index: 24, len_or_tag: 0 } } Token { kind: CloseDelim(Brace), span: Span { base_or_index: 24, len_or_tag: 1 } } Token { kind: Newline, span: Span { base_or_index: 25, len_or_tag: 0 } } Token { kind: Eof, span: Span { base_or_index: 25, len_or_tag: 0 } } @@ -452,21 +515,21 @@ fn test_peek() { let src = "\na=1"; let sm = SourceMap::new(FilePathMapping::empty()); sm.new_source_file(PathBuf::from("").into(), src.to_string()); - let mut sess = ParseSession::with_source_map(Arc::new(sm)); + let sess = ParseSession::with_source_map(Arc::new(sm)); create_session_globals_then(|| { - let stream = parse_token_streams(&mut sess, src, BytePos::from_u32(0)); + let stream = parse_token_streams(&sess, src, new_byte_pos(0)); let mut cursor = stream.cursor(); let tok0 = cursor.next(); assert_eq!( - format!("{:?}", tok0), + format!("{tok0:?}"), "Some(Token { kind: Newline, span: Span { base_or_index: 0, len_or_tag: 1 } })" ); let peek = cursor.peek(); assert_eq!( - format!("{:?}", peek), + format!("{peek:?}"), "Some(Token { kind: Ident(Symbol(SymbolIndex { idx: 42 })), span: Span { base_or_index: 1, len_or_tag: 1 } })" ); }); @@ -488,3 +551,301 @@ a=1 "#]], ) } + +#[test] +fn test_token_span() { + let src = r#" +schema Person: + name: str = "kcl" + +x0 = Person {} + "#; + check_span( + src, + expect![ + r#""\n" +"schema" +"Person" +":" +"\n" +"" +"name" +":" +"str" +"=" +"\"kcl\"" +"\n" +"\n" +"" +"x0" +"=" +"Person" +"{" +"}" +"\n" +"" +"# + ], + ) +} + +#[test] +fn test_source_file() { + let src = "\r\n\r\n\r\r\n\n\n\r".to_string(); + let sm = kclvm_span::SourceMap::new(FilePathMapping::empty()); + let sf = sm.new_source_file(PathBuf::from("").into(), src); + match sf.src.as_ref() { + Some(src_from_sf) => { + assert_eq!(src_from_sf.as_str(), "\n\n\r\n\n\n\r"); + } + None => { + unreachable!(); + } + }; +} + +#[test] +fn test_parse_token_stream() { + check_lexing( + "\n\r\n\r\n\r\r\n", + expect![[r#" + Token { kind: Newline, span: Span { base_or_index: 0, len_or_tag: 1 } } + Token { kind: Newline, span: Span { base_or_index: 1, len_or_tag: 1 } } + Token { kind: Newline, span: Span { base_or_index: 2, len_or_tag: 1 } } + Token { kind: Newline, span: Span { base_or_index: 4, len_or_tag: 1 } } + Token { kind: Eof, span: Span { base_or_index: 5, len_or_tag: 0 } } + "#]], + ); +} + +#[cfg(target_os = "windows")] +#[test] +fn test_parse_token_stream_on_win() { + use std::{fs, path::Path}; + let src = fs::read_to_string( + Path::new(".") + .join("testdata") + .join("hello_win.k") + .display() + .to_string(), + ) + .unwrap(); + assert_eq!( + src, + "\r\nschema Person:\r\n name: str = \"kcl\"\r\n\r\nx0 = Person {}\r\n" + ); + + check_lexing( + &src, + expect![[r#" + Token { kind: Newline, span: Span { base_or_index: 0, len_or_tag: 1 } } + Token { kind: Ident(Symbol(SymbolIndex { idx: 4 })), span: Span { base_or_index: 1, len_or_tag: 6 } } + Token { kind: Ident(Symbol(SymbolIndex { idx: 42 })), span: Span { base_or_index: 8, len_or_tag: 6 } } + Token { kind: Colon, span: Span { base_or_index: 14, len_or_tag: 1 } } + Token { kind: Newline, span: Span { base_or_index: 15, len_or_tag: 1 } } + Token { kind: Indent(0), span: Span { base_or_index: 20, len_or_tag: 0 } } + Token { kind: Ident(Symbol(SymbolIndex { idx: 43 })), span: Span { base_or_index: 20, len_or_tag: 4 } } + Token { kind: Colon, span: Span { base_or_index: 24, len_or_tag: 1 } } + Token { kind: Ident(Symbol(SymbolIndex { idx: 31 })), span: Span { base_or_index: 26, len_or_tag: 3 } } + Token { kind: Assign, span: Span { base_or_index: 30, len_or_tag: 1 } } + Token { kind: Literal(Lit { kind: Str { is_long_string: false, is_raw: false }, symbol: Symbol(SymbolIndex { idx: 44 }), suffix: None, raw: Some(Symbol(SymbolIndex { idx: 45 })) }), span: Span { base_or_index: 32, len_or_tag: 5 } } + Token { kind: Newline, span: Span { base_or_index: 37, len_or_tag: 1 } } + Token { kind: Newline, span: Span { base_or_index: 38, len_or_tag: 1 } } + Token { kind: Dedent(0), span: Span { base_or_index: 39, len_or_tag: 0 } } + Token { kind: Ident(Symbol(SymbolIndex { idx: 46 })), span: Span { base_or_index: 39, len_or_tag: 2 } } + Token { kind: Assign, span: Span { base_or_index: 42, len_or_tag: 1 } } + Token { kind: Ident(Symbol(SymbolIndex { idx: 42 })), span: Span { base_or_index: 44, len_or_tag: 6 } } + Token { kind: OpenDelim(Brace), span: Span { base_or_index: 51, len_or_tag: 1 } } + Token { kind: CloseDelim(Brace), span: Span { base_or_index: 52, len_or_tag: 1 } } + Token { kind: Newline, span: Span { base_or_index: 53, len_or_tag: 1 } } + Token { kind: Eof, span: Span { base_or_index: 54, len_or_tag: 0 } } + "#]], + ); +} + +#[test] +fn test_rarrow() { + check_lexing( + "lambda x: int, y: int -> int { x + y }\n", + expect![[r#" + Token { kind: Ident(Symbol(SymbolIndex { idx: 18 })), span: Span { base_or_index: 0, len_or_tag: 6 } } + Token { kind: Ident(Symbol(SymbolIndex { idx: 42 })), span: Span { base_or_index: 7, len_or_tag: 1 } } + Token { kind: Colon, span: Span { base_or_index: 8, len_or_tag: 1 } } + Token { kind: Ident(Symbol(SymbolIndex { idx: 30 })), span: Span { base_or_index: 10, len_or_tag: 3 } } + Token { kind: Comma, span: Span { base_or_index: 13, len_or_tag: 1 } } + Token { kind: Ident(Symbol(SymbolIndex { idx: 43 })), span: Span { base_or_index: 15, len_or_tag: 1 } } + Token { kind: Colon, span: Span { base_or_index: 16, len_or_tag: 1 } } + Token { kind: Ident(Symbol(SymbolIndex { idx: 30 })), span: Span { base_or_index: 18, len_or_tag: 3 } } + Token { kind: RArrow, span: Span { base_or_index: 22, len_or_tag: 2 } } + Token { kind: Ident(Symbol(SymbolIndex { idx: 30 })), span: Span { base_or_index: 25, len_or_tag: 3 } } + Token { kind: OpenDelim(Brace), span: Span { base_or_index: 29, len_or_tag: 1 } } + Token { kind: Ident(Symbol(SymbolIndex { idx: 42 })), span: Span { base_or_index: 31, len_or_tag: 1 } } + Token { kind: BinOp(Plus), span: Span { base_or_index: 33, len_or_tag: 1 } } + Token { kind: Ident(Symbol(SymbolIndex { idx: 43 })), span: Span { base_or_index: 35, len_or_tag: 1 } } + Token { kind: CloseDelim(Brace), span: Span { base_or_index: 37, len_or_tag: 1 } } + Token { kind: Newline, span: Span { base_or_index: 38, len_or_tag: 1 } } + Token { kind: Eof, span: Span { base_or_index: 39, len_or_tag: 0 } } + "#]], + ); +} + +#[test] +fn test_minus_unicode_gt_invalid() { + check_lexing_with_err_msg( + "lambda x: int, y: int -\u{feff}> int { x + y }\n", + expect![[r#" + Token { kind: Ident(Symbol(SymbolIndex { idx: 18 })), span: Span { base_or_index: 0, len_or_tag: 6 } } + Token { kind: Ident(Symbol(SymbolIndex { idx: 42 })), span: Span { base_or_index: 7, len_or_tag: 1 } } + Token { kind: Colon, span: Span { base_or_index: 8, len_or_tag: 1 } } + Token { kind: Ident(Symbol(SymbolIndex { idx: 30 })), span: Span { base_or_index: 10, len_or_tag: 3 } } + Token { kind: Comma, span: Span { base_or_index: 13, len_or_tag: 1 } } + Token { kind: Ident(Symbol(SymbolIndex { idx: 43 })), span: Span { base_or_index: 15, len_or_tag: 1 } } + Token { kind: Colon, span: Span { base_or_index: 16, len_or_tag: 1 } } + Token { kind: Ident(Symbol(SymbolIndex { idx: 30 })), span: Span { base_or_index: 18, len_or_tag: 3 } } + Token { kind: RArrow, span: Span { base_or_index: 25, len_or_tag: 2 } } + Token { kind: Ident(Symbol(SymbolIndex { idx: 30 })), span: Span { base_or_index: 28, len_or_tag: 3 } } + Token { kind: OpenDelim(Brace), span: Span { base_or_index: 32, len_or_tag: 1 } } + Token { kind: Ident(Symbol(SymbolIndex { idx: 42 })), span: Span { base_or_index: 34, len_or_tag: 1 } } + Token { kind: BinOp(Plus), span: Span { base_or_index: 36, len_or_tag: 1 } } + Token { kind: Ident(Symbol(SymbolIndex { idx: 43 })), span: Span { base_or_index: 38, len_or_tag: 1 } } + Token { kind: CloseDelim(Brace), span: Span { base_or_index: 40, len_or_tag: 1 } } + Token { kind: Newline, span: Span { base_or_index: 41, len_or_tag: 1 } } + Token { kind: Eof, span: Span { base_or_index: 42, len_or_tag: 0 } } + "#]], + expect![["error[E1001]: InvalidSyntax\nunknown start of token\n\n"]], + ); +} + +#[test] +fn test_unicode_minus_gt_invalid() { + check_lexing_with_err_msg( + "lambda x: int, y: int \u{feff}-> int { x + y }\n", + expect![[r#" + Token { kind: Ident(Symbol(SymbolIndex { idx: 18 })), span: Span { base_or_index: 0, len_or_tag: 6 } } + Token { kind: Ident(Symbol(SymbolIndex { idx: 42 })), span: Span { base_or_index: 7, len_or_tag: 1 } } + Token { kind: Colon, span: Span { base_or_index: 8, len_or_tag: 1 } } + Token { kind: Ident(Symbol(SymbolIndex { idx: 30 })), span: Span { base_or_index: 10, len_or_tag: 3 } } + Token { kind: Comma, span: Span { base_or_index: 13, len_or_tag: 1 } } + Token { kind: Ident(Symbol(SymbolIndex { idx: 43 })), span: Span { base_or_index: 15, len_or_tag: 1 } } + Token { kind: Colon, span: Span { base_or_index: 16, len_or_tag: 1 } } + Token { kind: Ident(Symbol(SymbolIndex { idx: 30 })), span: Span { base_or_index: 18, len_or_tag: 3 } } + Token { kind: RArrow, span: Span { base_or_index: 25, len_or_tag: 2 } } + Token { kind: Ident(Symbol(SymbolIndex { idx: 30 })), span: Span { base_or_index: 28, len_or_tag: 3 } } + Token { kind: OpenDelim(Brace), span: Span { base_or_index: 32, len_or_tag: 1 } } + Token { kind: Ident(Symbol(SymbolIndex { idx: 42 })), span: Span { base_or_index: 34, len_or_tag: 1 } } + Token { kind: BinOp(Plus), span: Span { base_or_index: 36, len_or_tag: 1 } } + Token { kind: Ident(Symbol(SymbolIndex { idx: 43 })), span: Span { base_or_index: 38, len_or_tag: 1 } } + Token { kind: CloseDelim(Brace), span: Span { base_or_index: 40, len_or_tag: 1 } } + Token { kind: Newline, span: Span { base_or_index: 41, len_or_tag: 1 } } + Token { kind: Eof, span: Span { base_or_index: 42, len_or_tag: 0 } } + "#]], + expect![["error[E1001]: InvalidSyntax\nunknown start of token\n\n"]], + ); +} + +#[test] +fn test_minus_gt_unicode_invalid() { + check_lexing_with_err_msg( + "lambda x: int, y: int ->\u{feff} int { x + y }\n", + expect![[r#" + Token { kind: Ident(Symbol(SymbolIndex { idx: 18 })), span: Span { base_or_index: 0, len_or_tag: 6 } } + Token { kind: Ident(Symbol(SymbolIndex { idx: 42 })), span: Span { base_or_index: 7, len_or_tag: 1 } } + Token { kind: Colon, span: Span { base_or_index: 8, len_or_tag: 1 } } + Token { kind: Ident(Symbol(SymbolIndex { idx: 30 })), span: Span { base_or_index: 10, len_or_tag: 3 } } + Token { kind: Comma, span: Span { base_or_index: 13, len_or_tag: 1 } } + Token { kind: Ident(Symbol(SymbolIndex { idx: 43 })), span: Span { base_or_index: 15, len_or_tag: 1 } } + Token { kind: Colon, span: Span { base_or_index: 16, len_or_tag: 1 } } + Token { kind: Ident(Symbol(SymbolIndex { idx: 30 })), span: Span { base_or_index: 18, len_or_tag: 3 } } + Token { kind: RArrow, span: Span { base_or_index: 22, len_or_tag: 2 } } + Token { kind: Ident(Symbol(SymbolIndex { idx: 30 })), span: Span { base_or_index: 28, len_or_tag: 3 } } + Token { kind: OpenDelim(Brace), span: Span { base_or_index: 32, len_or_tag: 1 } } + Token { kind: Ident(Symbol(SymbolIndex { idx: 42 })), span: Span { base_or_index: 34, len_or_tag: 1 } } + Token { kind: BinOp(Plus), span: Span { base_or_index: 36, len_or_tag: 1 } } + Token { kind: Ident(Symbol(SymbolIndex { idx: 43 })), span: Span { base_or_index: 38, len_or_tag: 1 } } + Token { kind: CloseDelim(Brace), span: Span { base_or_index: 40, len_or_tag: 1 } } + Token { kind: Newline, span: Span { base_or_index: 41, len_or_tag: 1 } } + Token { kind: Eof, span: Span { base_or_index: 42, len_or_tag: 0 } } + "#]], + expect![["error[E1001]: InvalidSyntax\nunknown start of token\n\n"]], + ); +} + +#[test] +fn test_only_minus() { + check_lexing( + "-", + expect![[r#" + Token { kind: BinOp(Minus), span: Span { base_or_index: 0, len_or_tag: 1 } } + Token { kind: Newline, span: Span { base_or_index: 1, len_or_tag: 0 } } + Token { kind: Eof, span: Span { base_or_index: 1, len_or_tag: 0 } } + "#]], + ); +} + +#[test] +fn test_begin_with_minus() { + check_lexing( + "-123", + expect![[r#" + Token { kind: BinOp(Minus), span: Span { base_or_index: 0, len_or_tag: 1 } } + Token { kind: Literal(Lit { kind: Integer, symbol: Symbol(SymbolIndex { idx: 42 }), suffix: None, raw: None }), span: Span { base_or_index: 1, len_or_tag: 3 } } + Token { kind: Newline, span: Span { base_or_index: 4, len_or_tag: 0 } } + Token { kind: Eof, span: Span { base_or_index: 4, len_or_tag: 0 } } + "#]], + ); +} + +#[test] +fn test_only_gt() { + check_lexing( + ">", + expect![[r#" + Token { kind: BinCmp(Gt), span: Span { base_or_index: 0, len_or_tag: 1 } } + Token { kind: Newline, span: Span { base_or_index: 1, len_or_tag: 0 } } + Token { kind: Eof, span: Span { base_or_index: 1, len_or_tag: 0 } } + "#]], + ); +} + +#[test] +fn test_begin_with_gt() { + check_lexing( + ">sdjkd + ==", + expect![[r#" + Token { kind: BinCmp(Gt), span: Span { base_or_index: 0, len_or_tag: 1 } } + Token { kind: Ident(Symbol(SymbolIndex { idx: 42 })), span: Span { base_or_index: 1, len_or_tag: 5 } } + Token { kind: BinOp(Plus), span: Span { base_or_index: 7, len_or_tag: 1 } } + Token { kind: BinCmp(Eq), span: Span { base_or_index: 9, len_or_tag: 2 } } + Token { kind: Newline, span: Span { base_or_index: 11, len_or_tag: 0 } } + Token { kind: Eof, span: Span { base_or_index: 11, len_or_tag: 0 } } + "#]], + ); +} + +#[test] +fn test_double_rarrow() { + check_lexing( + "->->", + expect![[r#" + Token { kind: RArrow, span: Span { base_or_index: 0, len_or_tag: 2 } } + Token { kind: RArrow, span: Span { base_or_index: 2, len_or_tag: 2 } } + Token { kind: Newline, span: Span { base_or_index: 4, len_or_tag: 0 } } + Token { kind: Eof, span: Span { base_or_index: 4, len_or_tag: 0 } } + "#]], + ); +} + +#[test] +fn test_mess_rarrow() { + check_lexing( + "-->>->", + expect![[r#" + Token { kind: BinOp(Minus), span: Span { base_or_index: 0, len_or_tag: 1 } } + Token { kind: BinOp(Minus), span: Span { base_or_index: 1, len_or_tag: 1 } } + Token { kind: BinOp(Shr), span: Span { base_or_index: 2, len_or_tag: 2 } } + Token { kind: RArrow, span: Span { base_or_index: 4, len_or_tag: 2 } } + Token { kind: Newline, span: Span { base_or_index: 6, len_or_tag: 0 } } + Token { kind: Eof, span: Span { base_or_index: 6, len_or_tag: 0 } } + "#]], + ); +} diff --git a/kclvm/parser/src/lib.rs b/kclvm/parser/src/lib.rs index d997d5bc4..9c72492a7 100644 --- a/kclvm/parser/src/lib.rs +++ b/kclvm/parser/src/lib.rs @@ -1,5 +1,7 @@ -// Copyright 2021 The KCL Authors. All rights reserved. +//! Copyright The KCL Authors. All rights reserved. +pub mod entry; +pub mod file_graph; mod lexer; mod parser; mod session; @@ -9,24 +11,62 @@ mod tests; extern crate kclvm_error; -use crate::session::ParseSession; -use kclvm::{ErrType, PanicInfo}; -use kclvm_ast::ast; -use kclvm_span::{self, FilePathMapping, SourceMap}; - +use crate::entry::get_compile_entries_from_paths; +pub use crate::session::{ParseSession, ParseSessionRef}; +use compiler_base_macros::bug; +use compiler_base_session::Session; +use compiler_base_span::span::new_byte_pos; +use file_graph::{toposort, Pkg, PkgFile, PkgFileGraph, PkgMap}; +use indexmap::IndexMap; +use kclvm_ast::ast::Module; +use kclvm_ast::{ast, MAIN_PKG}; +use kclvm_config::modfile::{get_vendor_home, KCL_FILE_EXTENSION, KCL_FILE_SUFFIX, KCL_MOD_FILE}; +use kclvm_error::diagnostic::{Errors, Range}; +use kclvm_error::{ErrorKind, Message, Position, Style}; +use kclvm_sema::plugin::PLUGIN_MODULE_PREFIX; +use kclvm_utils::path::PathPrefix; +use kclvm_utils::pkgpath::parse_external_pkg_name; +use kclvm_utils::pkgpath::rm_external_pkg_name; + +use anyhow::Result; use lexer::parse_token_streams; use parser::Parser; -use rustc_span::BytePos; -use rustc_span::Pos; - -use std::error::Error; -use std::fs::File; -use std::io::BufReader; -use std::path::PathBuf; -use std::sync::Arc; +use std::collections::{HashMap, HashSet, VecDeque}; +use std::path::{Path, PathBuf}; +use std::sync::{Arc, RwLock}; use kclvm_span::create_session_globals_then; +#[derive(Default, Debug)] +/// [`PkgInfo`] is some basic information about a kcl package. +pub(crate) struct PkgInfo { + /// the name of the kcl package. + pkg_name: String, + /// path to save the package locally. e.g. /usr/xxx + pkg_root: String, + /// package path. e.g. konfig.base.xxx + pkg_path: String, + /// The kcl files that need to be compiled in this package. + k_files: Vec, +} + +impl PkgInfo { + /// New a [`PkgInfo`]. + pub(crate) fn new( + pkg_name: String, + pkg_root: String, + pkg_path: String, + k_files: Vec, + ) -> Self { + PkgInfo { + pkg_name, + pkg_root, + pkg_path, + k_files, + } + } +} + /// parser mode #[derive(Debug, Clone)] pub enum ParseMode { @@ -34,429 +74,1239 @@ pub enum ParseMode { ParseComments, } -/// Get the AST program from json file. -pub fn parse_program_from_json_file(path: &str) -> Result> { - let file = File::open(path)?; - let reader = BufReader::new(file); - let u = serde_json::from_reader(reader)?; - Ok(u) +/// LoadProgramResult denotes the result of the whole program and a topological +/// ordering of all known files, +#[derive(Debug, Clone)] +pub struct LoadProgramResult { + /// Program AST + pub program: ast::Program, + /// Parse errors + pub errors: Errors, + /// The topological ordering of all known files. + pub paths: Vec, } -pub fn parse_program(filename: &str) -> Result { - let abspath = std::fs::canonicalize(&std::path::PathBuf::from(filename)).unwrap(); +/// ParseFileResult denotes the result of a single file including AST, +/// errors and import dependencies. +#[derive(Debug, Clone)] +pub struct ParseFileResult { + /// Module AST + pub module: ast::Module, + /// Parse errors + pub errors: Errors, + /// Dependency paths. + pub deps: Vec, +} - let mut prog = ast::Program { - root: abspath.parent().unwrap().to_str().unwrap().to_string(), - main: "__main__".to_string(), - pkgs: std::collections::HashMap::new(), - cmd_args: Vec::new(), - cmd_overrides: Vec::new(), +/// Parse a KCL file to the AST module with parse errors. +pub fn parse_single_file(filename: &str, code: Option) -> Result { + let filename = filename.adjust_canonicalization(); + let sess = Arc::new(ParseSession::default()); + let mut loader = Loader::new( + sess, + &[&filename], + Some(LoadProgramOptions { + load_packages: false, + k_code_list: if let Some(code) = code { + vec![code] + } else { + vec![] + }, + ..Default::default() + }), + None, + ); + let result = loader.load_main()?; + let module = match result.program.get_main_package_first_module() { + Some(module) => module.clone(), + None => ast::Module::default(), }; + let file_graph = match loader.file_graph.read() { + Ok(file_graph) => file_graph, + Err(e) => { + return Err(anyhow::anyhow!( + "Failed to read KCL file graph. Because '{e}'" + )) + } + }; + let file = PkgFile::new(PathBuf::from(filename), MAIN_PKG.to_string()); + let deps = if file_graph.contains_file(&file) { + file_graph.dependencies_of(&file).into_iter().collect() + } else { + vec![] + }; + Ok(ParseFileResult { + module, + errors: result.errors.clone(), + deps, + }) +} - let mainpkg = "__main__"; - - let mut module = parse_file(abspath.to_str().unwrap(), None)?; - module.filename = filename.to_string(); - module.pkg = mainpkg.to_string(); - module.name = mainpkg.to_string(); - - prog.pkgs.insert(mainpkg.to_string(), vec![module]); - - Ok(prog) +/// Parse a KCL file to the AST module and return errors when meets parse errors as result. +pub fn parse_file_force_errors(filename: &str, code: Option) -> Result { + let sess = Arc::new(ParseSession::default()); + let result = parse_file_with_global_session(sess.clone(), filename, code); + if sess.0.diag_handler.has_errors()? { + let err = sess + .0 + .emit_nth_diag_into_string(0)? + .unwrap_or(Ok(ErrorKind::InvalidSyntax.name()))?; + Err(anyhow::anyhow!(err)) + } else { + result + } } -pub fn parse_file(filename: &str, code: Option) -> Result { - create_session_globals_then(move || { - let src = if let Some(s) = code { - s - } else { - std::fs::read_to_string(filename).unwrap() - }; +/// Parse a KCL file to the AST module with the parse session . +pub fn parse_file_with_session( + sess: ParseSessionRef, + filename: &str, + code: Option, +) -> Result { + // Code source. + let src = if let Some(s) = code { + s + } else { + match std::fs::read_to_string(filename) { + Ok(src) => src, + Err(err) => { + return Err(anyhow::anyhow!( + "Failed to load KCL file '{filename}'. Because '{err}'" + )); + } + } + }; - let sm = kclvm_span::SourceMap::new(FilePathMapping::empty()); - let sf = sm.new_source_file(PathBuf::from(filename).into(), src.to_string()); - let sess = &ParseSession::with_source_map(std::sync::Arc::new(sm)); + // Build a source map to store file sources. + let sf = sess + .0 + .sm + .new_source_file(PathBuf::from(filename).into(), src); + + let src_from_sf = match sf.src.as_ref() { + Some(src) => src, + None => { + return Err(anyhow::anyhow!( + "Internal Bug: Failed to load KCL file '{filename}'." + )); + } + }; - let stream = lexer::parse_token_streams(sess, src.as_str(), sf.start_pos); - let mut p = parser::Parser::new(sess, stream); - let mut m = p.parse_module(); + // Lexer + let stream = lexer::parse_token_streams(&sess, src_from_sf.as_str(), sf.start_pos); + // Parser + let mut p = parser::Parser::new(&sess, stream); + let mut m = p.parse_module(); + m.filename = filename.to_string().adjust_canonicalization(); - m.filename = filename.to_string(); - m.pkg = kclvm_ast::MAIN_PKG.to_string(); - m.name = kclvm_ast::MAIN_PKG.to_string(); + Ok(m) +} - Ok(m) - }) +/// Parse a KCL file to the AST module with the parse session and the global session +#[inline] +pub fn parse_file_with_global_session( + sess: ParseSessionRef, + filename: &str, + code: Option, +) -> Result { + create_session_globals_then(move || parse_file_with_session(sess, filename, code)) } -pub fn parse_expr(src: &str) -> ast::NodeRef { - let sm = SourceMap::new(FilePathMapping::empty()); - sm.new_source_file(PathBuf::from("").into(), src.to_string()); - let sess = &ParseSession::with_source_map(Arc::new(sm)); +/// Parse a source string to a expression. When input empty string, it will return [None]. +/// +/// # Examples +/// ``` +/// use kclvm_ast::ast; +/// use kclvm_parser::parse_expr; +/// +/// let expr = parse_expr("'alice'").unwrap(); +/// assert!(matches!(expr.node, ast::Expr::StringLit(_))); +/// let expr = parse_expr(""); +/// assert!(matches!(expr, None)); +/// ``` +pub fn parse_expr(src: &str) -> Option> { + if src.is_empty() { + None + } else { + let sess = Arc::new(Session::default()); + let sf = sess + .sm + .new_source_file(PathBuf::from("").into(), src.to_string()); + let src_from_sf = match sf.src.as_ref() { + Some(src) => src, + None => { + bug!("Internal Bug: Failed to load KCL file."); + } + }; + + let sess = &&ParseSession::with_session(sess); - create_session_globals_then(|| { - let stream = parse_token_streams(sess, src, BytePos::from_u32(0)); - let mut parser = Parser::new(sess, stream); - parser.parse_expr() - }) + let expr: Option> = Some(create_session_globals_then(|| { + let stream = parse_token_streams(sess, src_from_sf.as_str(), new_byte_pos(0)); + let mut parser = Parser::new(sess, stream); + parser.parse_expr() + })); + expr + } } -#[derive(Debug, Default, Clone)] +#[derive(Debug, Clone)] pub struct LoadProgramOptions { pub work_dir: String, pub k_code_list: Vec, + pub vendor_dirs: Vec, + pub package_maps: HashMap, + /// The parser mode. + pub mode: ParseMode, + /// Whether to load packages. + pub load_packages: bool, + /// Whether to load plugins + pub load_plugins: bool, +} - pub cmd_args: Vec, - pub cmd_overrides: Vec, - - pub _mode: Option, - pub _load_packages: bool, +impl Default for LoadProgramOptions { + fn default() -> Self { + Self { + work_dir: Default::default(), + k_code_list: Default::default(), + vendor_dirs: vec![get_vendor_home()], + package_maps: Default::default(), + mode: ParseMode::ParseComments, + load_packages: true, + load_plugins: false, + } + } } +/// Load the KCL program by paths and options, +/// "module_cache" is used to cache parsed asts to support incremental parse, +/// if it is None, module caching will be disabled +/// +/// # Examples +/// +/// ``` +/// use kclvm_parser::{load_program, ParseSession}; +/// use kclvm_parser::KCLModuleCache; +/// use kclvm_ast::ast::Program; +/// use std::sync::Arc; +/// +/// // Create sessions +/// let sess = Arc::new(ParseSession::default()); +/// // Create module cache +/// let module_cache = KCLModuleCache::default(); +/// +/// // Parse kcl file +/// let kcl_path = "./testdata/import-01.k"; +/// let prog = load_program(sess.clone(), &[kcl_path], None, Some(module_cache.clone())).unwrap(); +/// +/// ``` pub fn load_program( + sess: ParseSessionRef, paths: &[&str], opts: Option, -) -> Result { - // todo: support cache - if let Some(opts) = opts { - Loader::new(paths, Some(opts)).load_main() - } else { - Loader::new(paths, None).load_main() - } + module_cache: Option, +) -> Result { + Loader::new(sess, paths, opts, module_cache).load_main() +} + +pub type KCLModuleCache = Arc>; + +#[derive(Default, Debug)] +pub struct ModuleCache { + /// File ast cache + pub ast_cache: IndexMap>>, + /// Which pkgs the file belongs to. Sometimes a file is not only contained in the pkg in the file system directory, but may also be in the main package. + pub file_pkg: IndexMap>, + /// File dependency cache + pub dep_cache: IndexMap, + /// File source code + pub source_code: IndexMap, + + pub last_compile_input: (Vec, Option), } +impl ModuleCache { + pub fn clear(&mut self, path: &PathBuf) { + self.ast_cache.remove(path); + self.source_code.remove(path); + if let Some(pkgs) = self.file_pkg.remove(path) { + for pkg in &pkgs { + self.dep_cache.remove(pkg); + } + } + } +} struct Loader { + sess: ParseSessionRef, paths: Vec, opts: LoadProgramOptions, - - pkgroot: String, - - modfile: kclvm_config::modfile::KCLModFile, - pkgs: std::collections::HashMap>, - missing_pkgs: Vec, - // todo: add shared source_map all parse_file. + module_cache: KCLModuleCache, + file_graph: FileGraphCache, + pkgmap: PkgMap, + parsed_file: HashSet, } impl Loader { - fn new(paths: &[&str], opts: Option) -> Self { + fn new( + sess: ParseSessionRef, + paths: &[&str], + opts: Option, + module_cache: Option, + ) -> Self { Self { - paths: paths.iter().map(|s| s.to_string()).collect(), + sess, + paths: paths + .iter() + .map(|s| kclvm_utils::path::convert_windows_drive_letter(s)) + .collect(), opts: opts.unwrap_or_default(), + module_cache: module_cache.unwrap_or_default(), + file_graph: FileGraphCache::default(), + pkgmap: PkgMap::new(), + parsed_file: HashSet::new(), + } + } - pkgroot: "".to_string(), + #[inline] + fn load_main(&mut self) -> Result { + create_session_globals_then(move || self._load_main()) + } - modfile: Default::default(), - pkgs: Default::default(), - missing_pkgs: Default::default(), - } + fn _load_main(&mut self) -> Result { + parse_program( + self.sess.clone(), + self.paths.clone(), + self.module_cache.clone(), + self.file_graph.clone(), + &mut self.pkgmap, + &mut self.parsed_file, + &self.opts, + ) } +} - fn load_main(&mut self) -> Result { - match self._load_main() { - Ok(x) => Ok(x), - Err(s) => Err(self.str_to_panic_info(&s).to_json_string()), +fn fix_rel_import_path_with_file( + pkgroot: &str, + m: &mut ast::Module, + file: &PkgFile, + pkgmap: &PkgMap, + opts: &LoadProgramOptions, + sess: ParseSessionRef, +) { + for stmt in &mut m.body { + let pos = stmt.pos().clone(); + if let ast::Stmt::Import(ref mut import_spec) = &mut stmt.node { + let fix_path = kclvm_config::vfs::fix_import_path( + pkgroot, + &m.filename, + import_spec.path.node.as_str(), + ); + import_spec.path.node = fix_path.clone(); + + let pkg = pkgmap.get(file).expect("file not in pkgmap"); + import_spec.pkg_name = pkg.pkg_name.clone(); + // Load the import package source code and compile. + let pkg_info = find_packages( + pos.into(), + &pkg.pkg_name, + &pkg.pkg_root, + &fix_path, + opts, + sess.clone(), + ) + .unwrap_or(None); + if let Some(pkg_info) = &pkg_info { + // Add the external package name as prefix of the [`kclvm_ast::ImportStmt`]'s member [`path`]. + import_spec.path.node = pkg_info.pkg_path.to_string(); + import_spec.pkg_name = pkg_info.pkg_name.clone(); + } } } +} - fn _load_main(&mut self) -> Result { - debug_assert!(!self.paths.is_empty()); +fn is_plugin_pkg(pkgpath: &str) -> bool { + pkgpath.starts_with(PLUGIN_MODULE_PREFIX) +} - self.pkgroot = kclvm_config::modfile::get_pkg_root_from_paths(&self.paths)?; +fn is_builtin_pkg(pkgpath: &str) -> bool { + let system_modules = kclvm_sema::builtin::system_module::STANDARD_SYSTEM_MODULES; + system_modules.contains(&pkgpath) +} - if !self.pkgroot.is_empty() { - debug_assert!(self.is_dir(self.pkgroot.as_str())); - debug_assert!(self.path_exist(self.pkgroot.as_str())); +fn find_packages( + pos: ast::Pos, + pkg_name: &str, + pkg_root: &str, + pkg_path: &str, + opts: &LoadProgramOptions, + sess: ParseSessionRef, +) -> Result> { + if pkg_path.is_empty() { + return Ok(None); + } - self.modfile = kclvm_config::modfile::load_mod_file(self.pkgroot.as_str()); + // plugin pkgs + if is_plugin_pkg(pkg_path) { + if !opts.load_plugins { + sess.1.write().add_error( + ErrorKind::CannotFindModule, + &[Message { + range: Into::::into(pos), + style: Style::Line, + message: format!("the plugin package `{}` is not found, please confirm if plugin mode is enabled", pkg_path), + note: None, + suggested_replacement: None, + }], + ); } + return Ok(None); + } - // fix path - let mut path_list = Vec::new(); - for s in &self.paths { - let mut s = s.clone(); - if s.contains(kclvm_config::modfile::KCL_MOD_PATH_ENV) { - debug_assert!(!self.pkgroot.is_empty()); - s = s.replace( - kclvm_config::modfile::KCL_MOD_PATH_ENV, - self.pkgroot.as_str(), + // builtin pkgs + if is_builtin_pkg(pkg_path) { + return Ok(None); + } + + // 1. Look for in the current package's directory. + let is_internal = is_internal_pkg(pkg_name, pkg_root, pkg_path)?; + // 2. Look for in the vendor path. + let is_external = is_external_pkg(pkg_path, opts)?; + + // 3. Internal and external packages cannot be duplicated + if is_external.is_some() && is_internal.is_some() { + sess.1.write().add_error( + ErrorKind::CannotFindModule, + &[Message { + range: Into::::into(pos), + style: Style::Line, + message: format!( + "the `{}` is found multiple times in the current package and vendor package", + pkg_path + ), + note: None, + suggested_replacement: None, + }], + ); + return Ok(None); + } + + // 4. Get package information based on whether the package is internal or external. + + match is_internal.or(is_external) { + Some(pkg_info) => Ok(Some(pkg_info)), + None => { + sess.1.write().add_error( + ErrorKind::CannotFindModule, + &[Message { + range: Into::::into(pos), + style: Style::Line, + message: format!("pkgpath {} not found in the program", pkg_path), + note: None, + suggested_replacement: None, + }], + ); + let mut suggestions = vec![format!("browse more packages at 'https://artifacthub.io'")]; + + if let Ok(pkg_name) = parse_external_pkg_name(pkg_path) { + suggestions.insert( + 0, + format!( + "try 'kcl mod add {}' to download the missing package", + pkg_name + ), ); } - if !self.pkgroot.is_empty() && !self.is_absolute(s.as_str()) { - let p = std::path::Path::new(s.as_str()); - if let Ok(x) = std::fs::canonicalize(p) { - s = x.to_str().unwrap_or(s.as_str()).to_string(); - } - } - - path_list.push(s); + sess.1.write().add_suggestions(suggestions); + Ok(None) } + } +} - // get k files - let mut k_files: Vec = Vec::new(); - for (i, path) in path_list.iter().enumerate() { - if path.ends_with(".k") { - k_files.push(path.to_string()); - continue; - } +/// Search [`pkgpath`] among all the paths in [`pkgroots`]. +/// +/// # Notes +/// +/// All paths in [`pkgpath`] must contain the kcl.mod file. +/// It returns the parent directory of kcl.mod if present, or none if not. +fn pkg_exists(pkgroots: &[String], pkgpath: &str) -> Option { + pkgroots + .into_iter() + .find(|root| pkg_exists_in_path(root, pkgpath)) + .cloned() +} - // read dir/*.k - if self.is_dir(path) { - if self.opts.k_code_list.len() > i { - return Err("invalid code list".to_string()); - } - //k_code_list - for s in self.get_dir_kfile_list(path)? { - k_files.push(s); - } - continue; - } - } +/// Search for [`pkgpath`] under [`path`]. +/// It only returns [`true`] if [`path`]/[`pkgpath`] or [`path`]/[`pkgpath.k`] exists. +fn pkg_exists_in_path(path: &str, pkgpath: &str) -> bool { + let mut pathbuf = PathBuf::from(path); + pkgpath.split('.').for_each(|s| pathbuf.push(s)); + pathbuf.exists() || pathbuf.with_extension(KCL_FILE_EXTENSION).exists() +} - if k_files.is_empty() { - return Err("No input KCL files".to_string()); +/// Look for [`pkgpath`] in the current package's [`pkgroot`]. +/// If found, return to the [`PkgInfo`], else return [`None`] +/// +/// # Error +/// +/// [`is_internal_pkg`] will return an error if the package's source files cannot be found. +fn is_internal_pkg(pkg_name: &str, pkg_root: &str, pkg_path: &str) -> Result> { + match pkg_exists(&[pkg_root.to_string()], pkg_path) { + Some(internal_pkg_root) => { + let fullpath = if pkg_name == kclvm_ast::MAIN_PKG { + pkg_path.to_string() + } else { + format!("{}.{}", pkg_name, pkg_path) + }; + let k_files = get_pkg_kfile_list(pkg_root, pkg_path)?; + Ok(Some(PkgInfo::new( + pkg_name.to_string(), + internal_pkg_root, + fullpath, + k_files, + ))) } + None => Ok(None), + } +} - // check all file exists - for (i, filename) in (&k_files).iter().enumerate() { - if i < self.opts.k_code_list.len() { - continue; - } - - if !self.pkgroot.is_empty() { - debug_assert!(self.is_file(filename.as_str())); - debug_assert!(self.is_absolute(filename.as_str()), "filename={}", filename); - } +fn get_pkg_kfile_list(pkgroot: &str, pkgpath: &str) -> Result> { + // plugin pkgs + if is_plugin_pkg(pkgpath) { + return Ok(Vec::new()); + } - if !self.path_exist(filename.as_str()) { - return Err(format!( - "Cannot find the kcl file, please check whether the file path {}", - filename.as_str(), - )); - } - } + // builtin pkgs + if is_builtin_pkg(pkgpath) { + return Ok(Vec::new()); + } - // load module - let mut pkg_files = Vec::new(); - for (i, filename) in (&k_files).iter().enumerate() { - // todo: add shared source map for all files - if i < self.opts.k_code_list.len() { - let mut m = parse_file(filename, Some(self.opts.k_code_list[i].clone()))?; - self.fix_rel_import_path(&mut m); - pkg_files.push(m) - } else { - let mut m = parse_file(filename, None)?; - self.fix_rel_import_path(&mut m); - pkg_files.push(m); - } - } + if pkgroot.is_empty() { + return Err(anyhow::anyhow!(format!("pkgroot not found: {:?}", pkgpath))); + } - let __kcl_main__ = kclvm_ast::MAIN_PKG; - let import_list = self.get_import_list(&pkg_files); + let mut pathbuf = std::path::PathBuf::new(); + pathbuf.push(pkgroot); - self.pkgs.insert(__kcl_main__.to_string(), pkg_files); + for s in pkgpath.split('.') { + pathbuf.push(s); + } - // load imported packages - for import_spec in import_list { - self.load_package(import_spec.path.to_string())?; - } + let abspath = match pathbuf.canonicalize() { + Ok(p) => p.to_str().unwrap().to_string(), + Err(_) => pathbuf.as_path().to_str().unwrap().to_string(), + }; + if std::path::Path::new(abspath.as_str()).exists() { + return get_dir_files(abspath.as_str()); + } - // Ok - Ok(ast::Program { - root: self.pkgroot.clone(), - main: __kcl_main__.to_string(), - pkgs: self.pkgs.clone(), - cmd_args: Vec::new(), - cmd_overrides: Vec::new(), - }) - } - - fn fix_rel_import_path(&mut self, m: &mut ast::Module) { - for stmt in &mut m.body { - if let ast::Stmt::Import(ref mut import_spec) = &mut stmt.node { - import_spec.path = kclvm_config::vfs::fix_import_path( - &self.pkgroot, - &m.filename, - import_spec.path.as_str(), - ); - } - } + let as_k_path = abspath + KCL_FILE_SUFFIX; + if std::path::Path::new((as_k_path).as_str()).exists() { + return Ok(vec![as_k_path]); } - fn load_package(&mut self, pkgpath: String) -> Result<(), String> { - if pkgpath.is_empty() { - return Ok(()); - } + Ok(Vec::new()) +} - if self.pkgs.contains_key(&pkgpath) { - return Ok(()); - } - if self.missing_pkgs.contains(&pkgpath) { - return Ok(()); - } +/// Get file list in the directory. +fn get_dir_files(dir: &str) -> Result> { + if !std::path::Path::new(dir).exists() { + return Ok(Vec::new()); + } - // plugin pkgs - if self.is_plugin_pkg(pkgpath.as_str()) { - return Ok(()); + let mut list = Vec::new(); + for path in std::fs::read_dir(dir)? { + let path = path?; + if !path + .file_name() + .to_str() + .unwrap() + .ends_with(KCL_FILE_SUFFIX) + { + continue; } - - // builtin pkgs - if self.is_builtin_pkg(pkgpath.as_str()) { - return Ok(()); + if path.file_name().to_str().unwrap().ends_with("_test.k") { + continue; } - - let k_files = self.get_pkg_kfile_list(pkgpath.as_str())?; - - if k_files.is_empty() { - self.missing_pkgs.push(pkgpath); - return Ok(()); + if path.file_name().to_str().unwrap().starts_with('_') { + continue; } - let mut pkg_files = Vec::new(); - for filename in k_files { - debug_assert!(self.is_file(filename.as_str())); - debug_assert!(self.path_exist(filename.as_str())); - - let mut m = parse_file(filename.as_str(), None)?; - - m.pkg = pkgpath.clone(); - m.name = "".to_string(); - self.fix_rel_import_path(&mut m); - - pkg_files.push(m); - } + let s = format!("{}", path.path().display()); + list.push(s); + } - let import_list = self.get_import_list(&pkg_files); - self.pkgs.insert(pkgpath, pkg_files); + list.sort(); + Ok(list) +} - for import_spec in import_list { - self.load_package(import_spec.path.to_string())?; +/// Look for [`pkgpath`] in the external package's home. +/// If found, return to the [`PkgInfo`], else return [`None`] +/// +/// # Error +/// +/// - [`is_external_pkg`] will return an error if the package's source files cannot be found. +/// - The name of the external package could not be resolved from [`pkg_path`]. +fn is_external_pkg(pkg_path: &str, opts: &LoadProgramOptions) -> Result> { + let pkg_name = parse_external_pkg_name(pkg_path)?; + let external_pkg_root = if let Some(root) = opts.package_maps.get(&pkg_name) { + PathBuf::from(root).join(KCL_MOD_FILE) + } else { + match pkg_exists(&opts.vendor_dirs, pkg_path) { + Some(path) => PathBuf::from(path).join(&pkg_name).join(KCL_MOD_FILE), + None => return Ok(None), } + }; - return Ok(()); + if external_pkg_root.exists() { + return Ok(Some(match external_pkg_root.parent() { + Some(root) => { + let abs_root: String = match root.canonicalize() { + Ok(p) => p.to_str().unwrap().to_string(), + Err(_) => root.display().to_string(), + }; + let k_files = get_pkg_kfile_list(&abs_root, &rm_external_pkg_name(pkg_path)?)?; + PkgInfo::new( + pkg_name.to_string(), + abs_root, + pkg_path.to_string(), + k_files, + ) + } + None => return Ok(None), + })); + } else { + Ok(None) } +} - fn get_import_list(&self, pkg: &[ast::Module]) -> Vec { - let mut import_list = Vec::new(); - for m in pkg { - for stmt in &m.body { - if let ast::Stmt::Import(import_spec) = &stmt.node { - let mut import_spec = import_spec.clone(); - import_spec.path = kclvm_config::vfs::fix_import_path( - &self.pkgroot, - &m.filename, - import_spec.path.as_str(), - ); - import_list.push(import_spec); +pub type ASTCache = Arc>>>; +pub type FileGraphCache = Arc>; + +pub fn parse_file( + sess: ParseSessionRef, + file: PkgFile, + src: Option, + module_cache: KCLModuleCache, + pkgs: &mut HashMap>, + pkgmap: &mut PkgMap, + file_graph: FileGraphCache, + opts: &LoadProgramOptions, +) -> Result> { + let src = match src { + Some(src) => Some(src), + None => match &module_cache.read() { + Ok(cache) => cache.source_code.get(file.get_path()), + Err(_) => None, + } + .cloned(), + }; + let m = parse_file_with_session(sess.clone(), file.get_path().to_str().unwrap(), src)?; + let deps = get_deps(&file, &m, pkgs, pkgmap, opts, sess)?; + let dep_files = deps.keys().map(|f| f.clone()).collect(); + pkgmap.extend(deps.clone()); + match &mut module_cache.write() { + Ok(module_cache) => { + module_cache + .ast_cache + .insert(file.get_path().clone(), Arc::new(RwLock::new(m))); + match module_cache.file_pkg.get_mut(&file.get_path().clone()) { + Some(s) => { + s.insert(file.clone()); + } + None => { + let mut s = HashSet::new(); + s.insert(file.clone()); + module_cache.file_pkg.insert(file.get_path().clone(), s); } } + module_cache.dep_cache.insert(file.clone(), deps); } - import_list + Err(e) => return Err(anyhow::anyhow!("Parse file failed: {e}")), } - fn get_pkg_kfile_list(&self, pkgpath: &str) -> Result, String> { - debug_assert!(!pkgpath.is_empty()); - - // plugin pkgs - if self.is_plugin_pkg(pkgpath) { - return Ok(Vec::new()); + match &mut file_graph.write() { + Ok(file_graph) => { + file_graph.update_file(&file, &dep_files); } + Err(e) => return Err(anyhow::anyhow!("Parse file failed: {e}")), + } - // builtin pkgs - if self.is_builtin_pkg(pkgpath) { - return Ok(Vec::new()); - } + Ok(dep_files) +} - if self.pkgroot.is_empty() { - return Err("pkgroot not found".to_string()); - } +pub fn get_deps( + file: &PkgFile, + m: &Module, + pkgs: &mut HashMap>, + pkgmap: &PkgMap, + opts: &LoadProgramOptions, + sess: ParseSessionRef, +) -> Result { + let mut deps = PkgMap::default(); + for stmt in &m.body { + let pos = stmt.pos().clone(); + let pkg = pkgmap.get(file).expect("file not in pkgmap").clone(); + if let ast::Stmt::Import(import_spec) = &stmt.node { + let fix_path = kclvm_config::vfs::fix_import_path( + &pkg.pkg_root, + &m.filename, + import_spec.path.node.as_str(), + ); + let pkg_info = find_packages( + pos.into(), + &pkg.pkg_name, + &pkg.pkg_root, + &fix_path, + opts, + sess.clone(), + )?; + if let Some(pkg_info) = &pkg_info { + // If k_files is empty, the pkg information will not be found in the file graph. + // Record the empty pkg to prevent loss. After the parse file is completed, fill in the modules + if pkg_info.k_files.is_empty() { + pkgs.insert(pkg_info.pkg_path.clone(), vec![]); + } - let mut pathbuf = std::path::PathBuf::new(); - pathbuf.push(&self.pkgroot); - for s in pkgpath.split('.') { - pathbuf.push(s); + pkg_info.k_files.iter().for_each(|p| { + let file = PkgFile::new(p.into(), pkg_info.pkg_path.clone()); + deps.insert( + file.clone(), + file_graph::Pkg { + pkg_name: pkg_info.pkg_name.clone(), + pkg_root: pkg_info.pkg_root.clone().into(), + }, + ); + }); + } } + } + Ok(deps) +} - let pkgpath: String = pathbuf.as_path().to_str().unwrap().to_string(); - let abspath: String = std::path::Path::new(&self.pkgroot) - .join(pkgpath) - .to_str() - .unwrap() - .to_string(); - - if std::path::Path::new(abspath.as_str()).exists() { - return self.get_dir_kfile_list(abspath.as_str()); - } +pub fn parse_pkg( + sess: ParseSessionRef, + files: Vec<(PkgFile, Option)>, + module_cache: KCLModuleCache, + pkgs: &mut HashMap>, + pkgmap: &mut PkgMap, + file_graph: FileGraphCache, + opts: &LoadProgramOptions, +) -> Result> { + let mut dependent = vec![]; + for (file, src) in files { + let deps = parse_file( + sess.clone(), + file.clone(), + src, + module_cache.clone(), + pkgs, + pkgmap, + file_graph.clone(), + opts, + )?; + dependent.extend(deps); + } + Ok(dependent) +} - let as_k_path = abspath + ".k"; - if std::path::Path::new((&as_k_path).as_str()).exists() { - return Ok(vec![as_k_path]); +pub fn parse_entry( + sess: ParseSessionRef, + entry: &entry::Entry, + module_cache: KCLModuleCache, + pkgs: &mut HashMap>, + pkgmap: &mut PkgMap, + file_graph: FileGraphCache, + opts: &LoadProgramOptions, + parsed_file: &mut HashSet, +) -> Result> { + let k_files = entry.get_k_files(); + let maybe_k_codes = entry.get_k_codes(); + let mut files = vec![]; + let mut new_files = HashSet::new(); + for (i, f) in k_files.iter().enumerate() { + let file = PkgFile::new(f.adjust_canonicalization().into(), MAIN_PKG.to_string()); + files.push((file.clone(), maybe_k_codes.get(i).unwrap_or(&None).clone())); + new_files.insert(file.clone()); + pkgmap.insert( + file, + Pkg { + pkg_name: entry.name().clone(), + pkg_root: entry.path().into(), + }, + ); + } + let dependent_paths = parse_pkg( + sess.clone(), + files, + module_cache.clone(), + pkgs, + pkgmap, + file_graph.clone(), + opts, + )?; + let mut unparsed_file: VecDeque = dependent_paths.into(); + + // Bfs unparsed and import files + while let Some(file) = unparsed_file.pop_front() { + match &mut module_cache.write() { + Ok(m_cache) => match m_cache.file_pkg.get_mut(file.get_path()) { + Some(s) => { + // The module ast has been parsed, but does not belong to the same package + if s.insert(file.clone()) { + new_files.insert(file.clone()); + } + } + None => { + let mut s = HashSet::new(); + s.insert(file.clone()); + m_cache.file_pkg.insert(file.get_path().clone(), s); + new_files.insert(file.clone()); + } + }, + Err(e) => return Err(anyhow::anyhow!("Parse file failed: {e}")), } - Ok(Vec::new()) + let module_cache_read = module_cache.read(); + match &module_cache_read { + Ok(m_cache) => match m_cache.ast_cache.get(file.get_path()) { + Some(m) => { + let deps = m_cache.dep_cache.get(&file).cloned().unwrap_or_else(|| { + get_deps(&file, &m.read().unwrap(), pkgs, pkgmap, opts, sess.clone()) + .unwrap() + }); + let dep_files: Vec = deps.keys().map(|f| f.clone()).collect(); + pkgmap.extend(deps.clone()); + + match &mut file_graph.write() { + Ok(file_graph) => { + file_graph.update_file(&file, &dep_files); + + for dep in dep_files { + if parsed_file.insert(dep.clone()) { + unparsed_file.push_back(dep.clone()); + } + } + + continue; + } + Err(e) => return Err(anyhow::anyhow!("Parse entry failed: {e}")), + } + } + None => { + new_files.insert(file.clone()); + drop(module_cache_read); + let deps = parse_file( + sess.clone(), + file, + None, + module_cache.clone(), + pkgs, + pkgmap, + file_graph.clone(), + &opts, + )?; + for dep in deps { + if parsed_file.insert(dep.clone()) { + unparsed_file.push_back(dep.clone()); + } + } + } + }, + Err(e) => return Err(anyhow::anyhow!("Parse entry failed: {e}")), + }; } - fn get_dir_kfile_list(&self, dir: &str) -> Result, String> { - if !std::path::Path::new(dir).exists() { - return Ok(Vec::new()); - } + Ok(new_files) +} - let mut list = Vec::new(); +pub fn parse_program( + sess: ParseSessionRef, + paths: Vec, + module_cache: KCLModuleCache, + file_graph: FileGraphCache, + pkgmap: &mut PkgMap, + parsed_file: &mut HashSet, + opts: &LoadProgramOptions, +) -> Result { + let compile_entries = get_compile_entries_from_paths(&paths, &opts)?; + let workdir = compile_entries + .get_root_path() + .to_string() + .adjust_canonicalization(); + let mut pkgs: HashMap> = HashMap::new(); + let mut new_files = HashSet::new(); + for entry in compile_entries.iter() { + new_files.extend(parse_entry( + sess.clone(), + entry, + module_cache.clone(), + &mut pkgs, + pkgmap, + file_graph.clone(), + &opts, + parsed_file, + )?); + } - for path in std::fs::read_dir(dir).unwrap() { - let path = path.unwrap(); - if !path.file_name().to_str().unwrap().ends_with(".k") { - continue; + let files = match file_graph.read() { + Ok(file_graph) => { + let files = match file_graph.toposort() { + Ok(files) => files, + Err(_) => file_graph.paths(), + }; + + let file_path_graph = file_graph.file_path_graph().0; + if let Err(cycle) = toposort(&file_path_graph) { + let formatted_cycle = cycle + .iter() + .map(|file| format!("- {}\n", file.to_string_lossy())) + .collect::(); + + sess.1.write().add_error( + ErrorKind::RecursiveLoad, + &[Message { + range: (Position::dummy_pos(), Position::dummy_pos()), + style: Style::Line, + message: format!( + "Could not compiles due to cyclic import statements\n{}", + formatted_cycle.trim_end() + ), + note: None, + suggested_replacement: None, + }], + ); } - if path.file_name().to_str().unwrap().ends_with("_test.k") { - continue; + files + } + Err(e) => return Err(anyhow::anyhow!("Parse program failed: {e}")), + }; + + let mut modules: HashMap>> = HashMap::new(); + for file in files.iter() { + let filename = file.get_path().to_str().unwrap().to_string(); + let m_ref = match module_cache.read() { + Ok(module_cache) => module_cache + .ast_cache + .get(file.get_path()) + .expect(&format!( + "Module not found in module: {:?}", + file.get_path() + )) + .clone(), + Err(e) => return Err(anyhow::anyhow!("Parse program failed: {e}")), + }; + if new_files.contains(file) { + let pkg = pkgmap.get(file).expect("file not in pkgmap"); + let mut m = m_ref.write().unwrap(); + fix_rel_import_path_with_file(&pkg.pkg_root, &mut m, file, &pkgmap, opts, sess.clone()); + } + modules.insert(filename.clone(), m_ref); + match pkgs.get_mut(&file.pkg_path) { + Some(pkg_modules) => { + pkg_modules.push(filename.clone()); } - if path.file_name().to_str().unwrap().starts_with('_') { - continue; + None => { + pkgs.insert(file.pkg_path.clone(), vec![filename]); } - - let s = format!("{}", path.path().display()); - list.push(s); } - - list.sort(); - Ok(list) } + let program = ast::Program { + root: workdir, + pkgs, + pkgs_not_imported: HashMap::new(), + modules, + modules_not_imported: HashMap::new(), + }; - fn is_builtin_pkg(&self, pkgpath: &str) -> bool { - let system_modules = kclvm_sema::builtin::system_module::STANDARD_SYSTEM_MODULES; - system_modules.contains(&pkgpath) - } + Ok(LoadProgramResult { + program, + errors: sess.1.read().diagnostics.clone(), + paths: files.iter().map(|file| file.get_path().clone()).collect(), + }) +} - fn is_plugin_pkg(&self, pkgpath: &str) -> bool { - pkgpath.starts_with("kcl_plugin.") - } +/// If there are too many files in the directory, it will affect the performance of lsp. Set a maximum number of files +const MAX_SCAN_FILES: usize = 1000; + +/// Parse all kcl files under path and dependencies from opts. +/// Different from `load_program`, this function will compile files that are not imported. +pub fn load_all_files_under_paths( + sess: ParseSessionRef, + paths: &[&str], + opts: Option, + module_cache: Option, +) -> Result { + let mut loader = Loader::new(sess.clone(), paths, opts.clone(), module_cache.clone()); + create_session_globals_then(move || { + match parse_program( + loader.sess.clone(), + loader.paths.clone(), + loader.module_cache.clone(), + loader.file_graph.clone(), + &mut loader.pkgmap, + &mut loader.parsed_file, + &loader.opts, + ) { + Ok(res) => { + let diag = sess.1.read().diagnostics.clone(); + let mut res = res.clone(); + let k_files_from_import = res.paths.clone(); + let mut paths = paths.to_vec(); + paths.push(&res.program.root); + let module_cache = loader.module_cache.clone(); + let mut module_cache_write = module_cache.write(); + match &mut module_cache_write { + Ok(m_cache) => { + let paths: Vec = paths.iter().map(|p| p.to_string()).collect(); + let paths_is_cached = paths == m_cache.last_compile_input.0; + let opt_is_cached = match (&m_cache.last_compile_input.1, &opts) { + (None, None) => true, + (Some(old), Some(new)) => old.package_maps == new.package_maps, + _ => false, + }; + if paths_is_cached && opt_is_cached { + return Ok(res); + } else { + m_cache.last_compile_input = (paths, opts.clone()) + } + } + Err(e) => return Err(anyhow::anyhow!("Parse entry failed: {e}")), + } + drop(module_cache_write); + + let (k_files_under_path, pkgmap) = + get_files_from_path(&res.program.root, &paths, opts)?; + + if k_files_under_path.len() > MAX_SCAN_FILES { + return Ok(res); + } + + loader.pkgmap.extend(pkgmap); + + // Filter unparsed file + let mut unparsed_file: VecDeque = VecDeque::new(); + for (pkg, paths) in &k_files_under_path { + for p in paths { + if !k_files_from_import.contains(p) { + let pkgfile = PkgFile::new(p.clone(), pkg.clone()); + let module_cache_read = module_cache.read(); + match &module_cache_read { + Ok(m_cache) => match m_cache.ast_cache.get(pkgfile.get_path()) { + Some(_) => continue, + None => { + unparsed_file.push_back(pkgfile); + } + }, + _ => {} + } + } + } + } + + let pkgs_not_imported = &mut res.program.pkgs_not_imported; + + let mut new_files = HashSet::new(); + // Bfs unparsed and import files + loader.parsed_file.extend(unparsed_file.clone()); + while let Some(file) = unparsed_file.pop_front() { + new_files.insert(file.clone()); + let module_cache_read = module_cache.read(); + match &module_cache_read { + Ok(m_cache) => match m_cache.ast_cache.get(file.get_path()) { + Some(_) => continue, + None => { + drop(module_cache_read); + let deps = parse_file( + sess.clone(), + file.clone(), + None, + module_cache.clone(), + pkgs_not_imported, + &mut loader.pkgmap, + loader.file_graph.clone(), + &loader.opts, + )?; + + let m_ref = match module_cache.read() { + Ok(module_cache) => module_cache + .ast_cache + .get(file.get_path()) + .expect(&format!( + "Module not found in module: {:?}", + file.get_path() + )) + .clone(), + Err(e) => { + return Err(anyhow::anyhow!("Parse program failed: {e}")) + } + }; + + let pkg = loader.pkgmap.get(&file).expect("file not in pkgmap"); + let mut m = m_ref.write().unwrap(); + fix_rel_import_path_with_file( + &pkg.pkg_root, + &mut m, + &file, + &loader.pkgmap, + &loader.opts, + sess.clone(), + ); + + for dep in deps { + if loader.parsed_file.insert(dep.clone()) { + unparsed_file.push_back(dep.clone()); + } + } + } + }, + Err(e) => return Err(anyhow::anyhow!("Parse entry failed: {e}")), + } + } + + // Merge unparsed module into res + let modules_not_imported = &mut res.program.modules_not_imported; + for file in &new_files { + let filename = file.get_path().to_str().unwrap().to_string(); + let m_ref = match module_cache.read() { + Ok(module_cache) => module_cache + .ast_cache + .get(file.get_path()) + .expect(&format!( + "Module not found in module: {:?}", + file.get_path() + )) + .clone(), + Err(e) => return Err(anyhow::anyhow!("Parse program failed: {e}")), + }; + modules_not_imported.insert(filename.clone(), m_ref); + match pkgs_not_imported.get_mut(&file.pkg_path) { + Some(pkg_modules) => { + pkg_modules.push(filename.clone()); + } + None => { + pkgs_not_imported.insert(file.pkg_path.clone(), vec![filename]); + } + } + } + sess.1.write().diagnostics = diag; + return Ok(res); + } + e => return e, + } + }) } -// utils -impl Loader { - fn is_file(&self, path: &str) -> bool { - std::path::Path::new(path).is_file() - } - fn is_dir(&self, path: &str) -> bool { - std::path::Path::new(path).is_dir() +/// Get all kcl files under path and dependencies from opts, regardless of whether they are imported or not +pub fn get_files_from_path( + root: &str, + paths: &[&str], + opts: Option, +) -> Result<(HashMap>, HashMap)> { + let mut k_files_under_path = HashMap::new(); + let mut pkgmap = HashMap::new(); + + // get files from config + if let Some(opt) = &opts { + for (name, path) in &opt.package_maps { + let path_buf = PathBuf::from(path.clone()); + if path_buf.is_dir() { + let all_k_files_under_path = get_kcl_files(path.clone(), true)?; + for f in &all_k_files_under_path { + let p = PathBuf::from(f); + let fix_path = { + match p.parent().unwrap().strip_prefix(Path::new(&path)) { + Ok(p) => Path::new(&name).join(p), + Err(_) => match p.parent().unwrap().strip_prefix(Path::new(&path)) { + Ok(p) => Path::new(&name).join(p), + Err(_) => Path::new(&name).to_path_buf(), + }, + } + } + .to_str() + .unwrap() + .to_string(); + let mut fix_path = fix_path + .replace(['/', '\\'], ".") + .trim_end_matches('.') + .to_string(); + + if fix_path.is_empty() { + fix_path = MAIN_PKG.to_string(); + } + + let pkgfile = PkgFile::new(p.clone(), fix_path.clone()); + pkgmap.insert( + pkgfile, + Pkg { + pkg_name: name.clone(), + pkg_root: path.clone(), + }, + ); + k_files_under_path + .entry(fix_path) + .or_insert(Vec::new()) + .push(p); + } + } + } } - fn is_absolute(&self, path: &str) -> bool { - std::path::Path::new(path).is_absolute() + // get files from input paths + for path in paths { + let path_buf = PathBuf::from(path); + if path_buf.is_dir() { + let all_k_files_under_path = get_kcl_files(path, true)?; + for f in &all_k_files_under_path { + let p = PathBuf::from(f.adjust_canonicalization()); + let fix_path = p + .parent() + .unwrap() + .strip_prefix(root) + .unwrap() + .to_str() + .unwrap() + .to_string(); + + let fix_path = fix_path + .replace(['/', '\\'], ".") + .trim_end_matches('.') + .to_string(); + + let pkgfile = PkgFile::new(p.clone(), fix_path.clone()); + pkgmap.insert( + pkgfile, + Pkg { + pkg_name: MAIN_PKG.to_owned(), + pkg_root: path.to_string(), + }, + ); + k_files_under_path + .entry(fix_path) + .or_insert(Vec::new()) + .push(p); + } + } } - fn path_exist(&self, path: &str) -> bool { - std::path::Path::new(path).exists() - } + Ok((k_files_under_path, pkgmap)) } -impl Loader { - fn str_to_panic_info(&self, s: &str) -> PanicInfo { - let mut panic_info = PanicInfo::default(); - - panic_info.__kcl_PanicInfo__ = true; - panic_info.message = format!("{}", s); - panic_info.err_type_code = ErrType::CompileError_TYPE as i32; - - panic_info +/// Get kcl files from path. +pub fn get_kcl_files>(path: P, recursively: bool) -> Result> { + let mut files = vec![]; + let walkdir = if recursively { + walkdir::WalkDir::new(path) + } else { + walkdir::WalkDir::new(path).max_depth(1) + }; + for entry in walkdir.into_iter().filter_map(|e| e.ok()) { + let path = entry.path(); + if path.is_file() { + let file = path.to_str().unwrap(); + if file.ends_with(KCL_FILE_SUFFIX) { + files.push(file.to_string()) + } + } } + files.sort(); + Ok(files) } diff --git a/kclvm/parser/src/parser/expr.rs b/kclvm/parser/src/parser/expr.rs index e14ca5756..45f886ff7 100644 --- a/kclvm/parser/src/parser/expr.rs +++ b/kclvm/parser/src/parser/expr.rs @@ -7,23 +7,62 @@ use std::vec; use super::int::bytes_to_int; use super::Parser; +use anyhow::bail; use either::{self, Either}; -use kclvm_ast::node_ref; use crate::parser::precedence::Precedence; +use anyhow::Result; +use compiler_base_error::unit_type::{TypeWithUnit, UnitUsize}; use kclvm_ast::ast::*; +use kclvm_ast::node_ref; use kclvm_ast::token; -use kclvm_ast::token::{BinOpToken, DelimToken, TokenKind}; +use kclvm_ast::token::{BinOpToken, DelimToken, TokenKind, VALID_SPACES_LENGTH}; use kclvm_span::symbol::kw; /// Parser implementation of expressions, which consists of sub-expressions, -/// operand and tokens. Like the general LL1 paser, parser constantly looking for +/// operand and tokens. Like the general LL1 parser, parser constantly looking for /// left-side derivation, priority is specified by matching code explicitly. /// The entrances of expression parsing are `parse_exprlist` and `parse_expr`. /// TODO: operand design is quite complex, can be simplified later. impl<'a> Parser<'a> { /// ~~~ Entrances + /// [`clean_all_indentations`] will bump all indent and dedent tokens. + pub(crate) fn clean_all_indentations(&mut self) { + self.clean_all_indent(); + self.clean_all_dedent(); + } + + // [`clean_all_indent`] will bump all indent tokens. + fn clean_all_indent(&mut self) { + while matches!(self.token.kind, TokenKind::Indent(_)) { + self.bump(); + } + } + + /// [`clean_all_dedent`] will bump all dedent tokens. + fn clean_all_dedent(&mut self) { + while matches!(self.token.kind, TokenKind::Dedent(_)) { + self.bump(); + } + } + + /// validate_dedent will check the number of spaces in indent and dedent tokens. + pub(crate) fn validate_dedent(&mut self) { + if let TokenKind::Dedent(n) = self.token.kind { + if n != 0 { + self.sess.struct_span_error( + &format!( + "invalid indentation with {}, try to align indents by adding or removing spaces", + UnitUsize(n, "space".to_string()).into_string_with_unit(), + ), + self.token.span, + ); + self.bump(); + } + } + } + /// Syntax: /// expr_list: expr (COMMA expr)* pub(crate) fn parse_exprlist(&mut self) -> Vec> { @@ -49,11 +88,19 @@ impl<'a> Parser<'a> { /// Syntax: /// test: if_expr | simple_expr pub(crate) fn parse_expr(&mut self) -> NodeRef { + if self.token.is_in_recovery_set() { + let tok: String = self.token.into(); + self.sess + .struct_span_error(&format!("unexpected token '{}'", tok), self.token.span); + self.bump(); + } + + let token = self.token; let operand = self.parse_simple_expr(); // try if expr if self.token.is_keyword(kw::If) { - return self.parse_if_expr(operand); + return self.parse_if_expr(operand, token); } operand @@ -119,21 +166,41 @@ impl<'a> Parser<'a> { } let op = if use_peek_op { - let peek = self.cursor.peek().unwrap(); + // If no peek is found, a dummy token is returned for error recovery. + let peek = match self.cursor.peek() { + Some(peek) => peek, + None => kclvm_ast::token::Token::dummy(), + }; if self.token.is_keyword(kw::Not) && peek.is_keyword(kw::In) { BinOrCmpOp::Cmp(CmpOp::NotIn) } else if self.token.is_keyword(kw::Is) && peek.is_keyword(kw::Not) { BinOrCmpOp::Cmp(CmpOp::IsNot) + } else if self.token.is_keyword(kw::Not) && peek.is_keyword(kw::Is) { + self.sess.struct_span_error( + "'not is' here is invalid, consider using 'is not'", + self.token.span, + ); + BinOrCmpOp::Cmp(CmpOp::IsNot) } else { - panic!("unreachable") + self.sess.struct_token_error( + &[ + kw::Not.into(), + kw::Is.into(), + TokenKind::BinOpEq(BinOpToken::Plus).into(), + ], + self.token, + ); + BinOrCmpOp::Cmp(CmpOp::Is) } } else { let result = BinOrCmpOp::try_from(self.token); match result { Ok(op) => op, - Err(()) => self - .sess - .struct_token_error(&BinOrCmpOp::all_symbols(), self.token), + Err(()) => { + self.sess + .struct_token_error(&BinOrCmpOp::all_symbols(), self.token); + return x; + } } }; @@ -144,33 +211,37 @@ impl<'a> Parser<'a> { let y = self.do_parse_simple_expr(oprec); - // compare: a == b == c - if let BinOrCmpOp::Cmp(cmp_op) = op.clone() { - if cmp_expr.ops.is_empty() { - cmp_expr.left = x.clone(); + match op { + // compare: a == b == c + BinOrCmpOp::Cmp(cmp_op) => { + if cmp_expr.ops.is_empty() { + cmp_expr.left = x.clone(); + } + cmp_expr.ops.push(cmp_op); + cmp_expr.comparators.push(y); + continue; } - cmp_expr.ops.push(cmp_op); - cmp_expr.comparators.push(y); - continue; - } + // binary a + b + BinOrCmpOp::Bin(bin_op) => { + if !cmp_expr.ops.is_empty() { + x = Box::new(Node::node( + Expr::Compare(cmp_expr.clone()), + self.sess.struct_token_loc(token, self.prev_token), + )); + cmp_expr.ops = Vec::new(); + cmp_expr.comparators = Vec::new(); + } - if !cmp_expr.ops.is_empty() { - x = Box::new(Node::node( - Expr::Compare(cmp_expr.clone()), - self.sess.struct_token_loc(token, self.prev_token), - )); - cmp_expr.ops = Vec::new(); - cmp_expr.comparators = Vec::new(); + x = Box::new(Node::node( + Expr::Binary(BinaryExpr { + left: x, + op: bin_op, + right: y, + }), + self.sess.struct_token_loc(token, self.prev_token), + )); + } } - - x = Box::new(Node::node( - Expr::Binary(BinaryExpr { - left: x, - op, - right: y, - }), - self.sess.struct_token_loc(token, self.prev_token), - )); } } @@ -179,8 +250,11 @@ impl<'a> Parser<'a> { /// Syntax: /// if_expr: simple_expr IF simple_expr ELSE test /// test: if_expr | simple_expr - fn parse_if_expr(&mut self, body: NodeRef) -> NodeRef { - let token = self.token; + fn parse_if_expr( + &mut self, + body: NodeRef, + token: kclvm_ast::token::Token, + ) -> NodeRef { if self.token.is_keyword(kw::If) { self.bump(); let cond = self.parse_simple_expr(); @@ -192,10 +266,19 @@ impl<'a> Parser<'a> { self.sess.struct_token_loc(token, self.prev_token), )) } else { - self.sess.struct_token_error(&[kw::Else.into()], self.token) + self.sess.struct_token_error(&[kw::Else.into()], self.token); + Box::new(Node::node( + Expr::If(IfExpr { + body, + cond, + orelse: self.missing_expr(), + }), + self.sess.struct_token_loc(token, self.prev_token), + )) } } else { - self.sess.struct_token_error(&[kw::If.into()], self.token) + self.sess.struct_token_error(&[kw::If.into()], self.token); + self.missing_expr() } } @@ -203,13 +286,14 @@ impl<'a> Parser<'a> { /// primary_expr: operand | primary_expr select_suffix | primary_expr call_suffix | primary_expr slice_suffix /// Note: we need to look ahead 2 tokens to match select_suffix and slice_suffix, which actually breaks LL1 rule. fn parse_primary_expr(&mut self) -> NodeRef { + let lo = self.token; let mut operand = self.parse_operand_expr(); loop { match self.token.kind { TokenKind::Dot => { // select_suffix - operand = self.parse_selector_expr(operand) + operand = self.parse_selector_expr(operand, lo) } TokenKind::Question => { match self.cursor.peek() { @@ -217,11 +301,11 @@ impl<'a> Parser<'a> { match token.kind { TokenKind::Dot => { // select_suffix - operand = self.parse_selector_expr(operand) + operand = self.parse_selector_expr(operand, lo) } TokenKind::OpenDelim(DelimToken::Bracket) => { // slice_suffix - operand = self.parse_subscript_expr(operand) + operand = self.parse_subscript_expr(operand, lo) } _ => break operand, } @@ -233,11 +317,11 @@ impl<'a> Parser<'a> { match dt { DelimToken::Paren => { // call_suffix - operand = self.parse_call_expr(operand) + operand = self.parse_call_expr(operand, lo) } DelimToken::Bracket => { // slice_suffix - operand = self.parse_subscript_expr(operand) + operand = self.parse_subscript_expr(operand, lo) } _ => break operand, } @@ -268,8 +352,7 @@ impl<'a> Parser<'a> { /// Syntax: /// select_suffix: [QUESTION] DOT NAME - fn parse_selector_expr(&mut self, value: NodeRef) -> NodeRef { - let token = self.token; + fn parse_selector_expr(&mut self, value: NodeRef, lo: token::Token) -> NodeRef { let has_question = match self.token.kind { TokenKind::Question => { self.bump(); @@ -279,30 +362,66 @@ impl<'a> Parser<'a> { }; // bump . self.bump(); - let attr = self.parse_identifier(); - Box::new(Node::node( - Expr::Selector(SelectorExpr { - value, - attr, - has_question, - ctx: ExprContext::Load, - }), - self.sess.struct_token_loc(token, self.prev_token), - )) + match self.token.ident() { + Some(_) => { + let attr = self.parse_identifier(); + Box::new(Node::node( + Expr::Selector(SelectorExpr { + value, + attr, + has_question, + ctx: ExprContext::Load, + }), + self.sess.struct_token_loc(lo, self.prev_token), + )) + } + _ => { + self.sess + .struct_token_error(&[TokenKind::ident_value()], self.token); + let attr = Box::new(Node::node( + Identifier { + names: vec![Node::node( + "".to_string(), + ( + self.sess.lookup_char_pos(self.token.span.lo()), + self.sess.lookup_char_pos(self.token.span.lo()), + ), + )], + pkgpath: "".to_string(), + ctx: ExprContext::Load, + }, + ( + self.sess.lookup_char_pos(self.token.span.lo()), + self.sess.lookup_char_pos(self.token.span.lo()), + ), + )); + Box::new(Node::node( + Expr::Selector(SelectorExpr { + value, + attr, + has_question, + ctx: ExprContext::Load, + }), + ( + self.sess.lookup_char_pos(lo.span.lo()), + self.sess.lookup_char_pos(self.token.span.lo()), + ), + )) + } + } } /// Syntax: /// call_suffix: LEFT_PARENTHESES [arguments [COMMA]] RIGHT_PARENTHESES - fn parse_call_expr(&mut self, func: NodeRef) -> NodeRef { - let token = self.token; + fn parse_call_expr(&mut self, func: NodeRef, lo: token::Token) -> NodeRef { let call_expr = self.parse_call(func); Box::new(Node::node( Expr::Call(call_expr), - self.sess.struct_token_loc(token, self.prev_token), + self.sess.struct_token_loc(lo, self.prev_token), )) } - fn parse_call(&mut self, func: NodeRef) -> CallExpr { + pub(crate) fn parse_call(&mut self, func: NodeRef) -> CallExpr { // LEFT_PARENTHESES match self.token.kind { TokenKind::OpenDelim(DelimToken::Paren) => self.bump(), @@ -312,11 +431,28 @@ impl<'a> Parser<'a> { ), } + let has_newline = if self.token.kind == TokenKind::Newline { + self.skip_newlines(); + self.clean_all_indentations(); + if self.token.kind == TokenKind::CloseDelim(DelimToken::Paren) { + // bump bracket close delim token `)` + self.bump(); + return CallExpr { + func, + args: vec![], + keywords: vec![], + }; + } + true + } else { + false + }; + // arguments or empty let (args, keywords) = if self.token.kind == TokenKind::CloseDelim(DelimToken::Paren) { (Vec::new(), Vec::new()) } else { - self.parse_arguments_expr() + self.parse_arguments_expr(has_newline) }; // [COMMA] @@ -342,8 +478,7 @@ impl<'a> Parser<'a> { /// Syntax: /// slice_suffix: [QUESTION] LEFT_BRACKETS (expr | [expr] COLON [expr] [COLON [expr]]) RIGHT_BRACKETS - fn parse_subscript_expr(&mut self, value: NodeRef) -> NodeRef { - let token = self.token; + fn parse_subscript_expr(&mut self, value: NodeRef, lo: token::Token) -> NodeRef { let mut has_question = false; // [QUESTION] if self.token.kind == TokenKind::Question { @@ -376,8 +511,13 @@ impl<'a> Parser<'a> { expr_index += 1; if colon_counter > 2 { - self.sess - .struct_token_error(&["expression".to_string()], self.token) + self.sess.struct_token_error( + &[ + "expression".to_string(), + TokenKind::CloseDelim(DelimToken::Bracket).into(), + ], + self.token, + ) } exprs_consecutive -= 1 } @@ -386,14 +526,15 @@ impl<'a> Parser<'a> { if !is_slice && round == 1 { // it just has one round for an array self.sess - .struct_compiler_bug("an list should have only one expr") + .struct_span_error("a list should have only one expr", self.token.span) } exprs[expr_index] = Some(self.parse_expr()); exprs_consecutive += 1; if exprs_consecutive > 1 { - self.sess.struct_compiler_bug("consecutive exprs found.") + self.sess + .struct_span_error("consecutive exprs found", self.token.span) } } } @@ -402,7 +543,7 @@ impl<'a> Parser<'a> { if exprs.len() != 3 { self.sess - .struct_compiler_bug("an slice should have three exprs.") + .struct_span_error("a slice should have three exprs", self.token.span) } // RIGHT_BRACKETS @@ -425,12 +566,19 @@ impl<'a> Parser<'a> { ctx: ExprContext::Load, has_question, }), - self.sess.struct_token_loc(token, self.prev_token), + self.sess.struct_token_loc(lo, self.prev_token), )) } else { + if exprs[0].is_none() { + let token_str: String = self.token.into(); + self.sess.struct_span_error( + &format!("expected expression got {}", token_str), + self.token.span, + ) + } if !(exprs[1].is_none() && exprs[2].is_none()) { self.sess - .struct_compiler_bug("an list should have only one expr.") + .struct_span_error("a list should have only one expr", self.token.span) } Box::new(Node::node( Expr::Subscript(Subscript { @@ -442,7 +590,7 @@ impl<'a> Parser<'a> { ctx: ExprContext::Load, has_question, }), - self.sess.struct_token_loc(token, self.prev_token), + self.sess.struct_token_loc(lo, self.prev_token), )) } } @@ -453,24 +601,24 @@ impl<'a> Parser<'a> { /// operand: identifier | number | string | constant | quant_expr | list_expr | list_comp | config_expr | dict_comp | identifier call_suffix | schema_expr | lambda_expr | paren_expr fn parse_operand_expr(&mut self) -> NodeRef { let token = self.token; + // try primary expr match self.token.kind { TokenKind::Ident(_) => { // None if self.token.is_keyword(kw::None) { - return self.parse_constant_expr(token::None); + self.parse_constant_expr(token::None) } // Undefined - if self.token.is_keyword(kw::Undefined) { + else if self.token.is_keyword(kw::Undefined) { return self.parse_constant_expr(token::Undefined); } // Bool: True/False - if self.token.is_keyword(kw::True) || self.token.is_keyword(kw::False) { + else if self.token.is_keyword(kw::True) || self.token.is_keyword(kw::False) { return self.parse_constant_expr(token::Bool); } - // lambda expression - if self.token.is_keyword(kw::Lambda) { + else if self.token.is_keyword(kw::Lambda) { self.parse_lambda_expr() // quant expression } else if self.token.is_keyword(kw::Any) @@ -512,22 +660,29 @@ impl<'a> Parser<'a> { TokenKind::Literal(lk) => { // lit expr match lk.kind { - token::LitKind::Bool => self.parse_constant_expr(lk.kind), + token::LitKind::Bool | token::LitKind::None | token::LitKind::Undefined => { + self.parse_constant_expr(lk.kind) + } token::LitKind::Integer | token::LitKind::Float => self.parse_num_expr(lk), token::LitKind::Str { .. } => self.parse_str_expr(lk), // Note: None and Undefined are handled in ident, skip handle them here. - _ => self.sess.struct_token_error( - &[ - token::LitKind::Bool.into(), - token::LitKind::Integer.into(), - token::LitKind::Str { - is_long_string: false, - is_raw: false, - } - .into(), - ], - self.token, - ), + _ => { + self.sess.struct_token_error( + &[ + token::LitKind::None.into(), + token::LitKind::Undefined.into(), + token::LitKind::Bool.into(), + token::LitKind::Integer.into(), + token::LitKind::Str { + is_long_string: false, + is_raw: false, + } + .into(), + ], + self.token, + ); + self.missing_expr() + } } } TokenKind::OpenDelim(dt) => { @@ -536,27 +691,35 @@ impl<'a> Parser<'a> { // paren expr DelimToken::Paren => self.parse_paren_expr(), // list expr or list comp - DelimToken::Bracket => self.parse_list_expr(), + DelimToken::Bracket => self.parse_list_expr(true), // dict expr or dict comp DelimToken::Brace => self.parse_config_expr(), - _ => self.sess.struct_token_error( - &[ - TokenKind::OpenDelim(DelimToken::Paren).into(), - TokenKind::OpenDelim(DelimToken::Bracket).into(), - TokenKind::OpenDelim(DelimToken::Brace).into(), - ], - self.token, - ), + _ => { + self.sess.struct_token_error( + &[ + TokenKind::OpenDelim(DelimToken::Paren).into(), + TokenKind::OpenDelim(DelimToken::Bracket).into(), + TokenKind::OpenDelim(DelimToken::Brace).into(), + ], + self.token, + ); + self.missing_expr() + } } } - _ => self.sess.struct_token_error( - &[ - TokenKind::ident_value(), - TokenKind::literal_value(), - TokenKind::OpenDelim(DelimToken::NoDelim).into(), - ], - self.token, - ), + _ => { + self.sess.struct_token_error( + &[ + TokenKind::ident_value(), + TokenKind::literal_value(), + TokenKind::OpenDelim(DelimToken::Paren).into(), + TokenKind::OpenDelim(DelimToken::Bracket).into(), + TokenKind::OpenDelim(DelimToken::Brace).into(), + ], + self.token, + ); + self.missing_expr() + } } } @@ -592,7 +755,8 @@ impl<'a> Parser<'a> { QuantOperation::Map.into(), ], self.token, - ) + ); + return self.missing_expr(); }; self.bump(); @@ -628,11 +792,13 @@ impl<'a> Parser<'a> { let has_newline = if self.token.kind == TokenKind::Newline { self.skip_newlines(); - if self.token.kind == TokenKind::Indent { + if self.token.kind == TokenKind::Indent(VALID_SPACES_LENGTH) { self.bump(); } else { - self.sess - .struct_token_error(&[TokenKind::Indent.into()], self.token) + self.sess.struct_token_error( + &[TokenKind::Indent(VALID_SPACES_LENGTH).into()], + self.token, + ) } true @@ -660,12 +826,14 @@ impl<'a> Parser<'a> { self.sess .struct_token_error(&[TokenKind::Newline.into()], self.token) } - - if self.token.kind == TokenKind::Dedent { + self.validate_dedent(); + if self.token.kind == TokenKind::Dedent(VALID_SPACES_LENGTH) { self.bump(); } else { - self.sess - .struct_token_error(&[TokenKind::Dedent.into()], self.token) + self.sess.struct_token_error( + &[TokenKind::Dedent(VALID_SPACES_LENGTH).into()], + self.token, + ) } } @@ -718,7 +886,8 @@ impl<'a> Parser<'a> { kw::Filter.into(), ], self.token, - ) + ); + self.missing_expr() } else { // identifier self.parse_identifier_expr() @@ -729,50 +898,61 @@ impl<'a> Parser<'a> { match lk.kind { token::LitKind::Str { .. } => self.parse_str_expr(lk), // Note: None and Undefined are handled in ident, skip handle them here. - _ => self.sess.struct_token_error( - &[token::LitKind::Str { - is_long_string: false, - is_raw: false, - } - .into()], - self.token, - ), + _ => { + self.sess.struct_token_error( + &[token::LitKind::Str { + is_long_string: false, + is_raw: false, + } + .into()], + self.token, + ); + self.missing_expr() + } } } TokenKind::OpenDelim(dt) => { // list expr, dict expr, paren expr match dt { // list expr or list comp - DelimToken::Bracket => self.parse_list_expr(), + DelimToken::Bracket => self.parse_list_expr(true), // dict expr or dict comp DelimToken::Brace => self.parse_config_expr(), - _ => self.sess.struct_token_error( - &[ - TokenKind::OpenDelim(DelimToken::Bracket).into(), - TokenKind::OpenDelim(DelimToken::Brace).into(), - ], - self.token, - ), + _ => { + self.sess.struct_token_error( + &[ + TokenKind::OpenDelim(DelimToken::Bracket).into(), + TokenKind::OpenDelim(DelimToken::Brace).into(), + ], + self.token, + ); + self.missing_expr() + } } } - _ => self.sess.struct_token_error( - &[ - TokenKind::ident_value(), - TokenKind::literal_value(), - TokenKind::OpenDelim(DelimToken::NoDelim).into(), - ], - self.token, - ), + _ => { + self.sess.struct_token_error( + &[TokenKind::ident_value(), TokenKind::literal_value()], + self.token, + ); + self.missing_expr() + } } } /// Syntax: /// list_expr: LEFT_BRACKETS [list_items | NEWLINE _INDENT list_items _DEDENT] RIGHT_BRACKETS /// list_comp: LEFT_BRACKETS (expr comp_clause+ | NEWLINE _INDENT expr comp_clause+ _DEDENT) RIGHT_BRACKETS - fn parse_list_expr(&mut self) -> NodeRef { - let token = self.token; - // LEFT_BRACKETS - self.bump(); + pub(crate) fn parse_list_expr(&mut self, bump_left_brackets: bool) -> NodeRef { + // List expr start token + let token = if bump_left_brackets { + // LEFT_BRACKETS + let token = self.token; + self.bump(); + token + } else { + self.prev_token + }; // try RIGHT_BRACKETS: empty config if let TokenKind::CloseDelim(DelimToken::Bracket) = self.token.kind { @@ -789,9 +969,9 @@ impl<'a> Parser<'a> { let has_newline = if self.token.kind == TokenKind::Newline { self.skip_newlines(); - if self.token.kind == TokenKind::Indent { - self.bump(); - } else if self.token.kind == TokenKind::CloseDelim(DelimToken::Bracket) { + self.clean_all_indentations(); + if self.token.kind == TokenKind::CloseDelim(DelimToken::Bracket) { + // bump bracket close delim token `]` self.bump(); return Box::new(Node::node( Expr::List(ListExpr { @@ -800,28 +980,19 @@ impl<'a> Parser<'a> { }), self.sess.struct_token_loc(token, self.prev_token), )); - } else { - self.sess - .struct_token_error(&[TokenKind::Indent.into()], self.token) } true } else { false }; - let items = self.parse_list_items(); + let item_start_token = self.token; + let items = self.parse_list_items(has_newline); let generators = self.parse_comp_clauses(); // _DEDENT - if has_newline { - self.skip_newlines(); - if self.token.kind == TokenKind::Dedent { - self.bump(); - } else { - self.sess - .struct_token_error(&[TokenKind::Dedent.into()], self.token) - } - } + self.skip_newlines(); + self.clean_all_indentations(); // RIGHT_BRACKETS match self.token.kind { @@ -836,16 +1007,41 @@ impl<'a> Parser<'a> { if !generators.is_empty() { if items.len() > 1 { - self.sess.struct_compiler_bug("multiple items found.") + self.sess.struct_span_error( + &format!( + "multiple list comp clause expression found: expected 1, got {}", + items.len() + ), + item_start_token.span, + ); + Box::new(Node::node( + Expr::ListComp(ListComp { + elt: items[0].clone(), + generators, + }), + self.sess.struct_token_loc(token, self.prev_token), + )) + } else if items.len() == 1 { + Box::new(Node::node( + Expr::ListComp(ListComp { + elt: items[0].clone(), + generators, + }), + self.sess.struct_token_loc(token, self.prev_token), + )) + } else { + self.sess.struct_span_error( + "missing list comp clause expression", + item_start_token.span, + ); + Box::new(Node::node( + Expr::List(ListExpr { + elts: items, + ctx: ExprContext::Load, + }), + self.sess.struct_token_loc(token, self.prev_token), + )) } - - Box::new(Node::node( - Expr::ListComp(ListComp { - elt: items[0].clone(), - generators, - }), - self.sess.struct_token_loc(token, self.prev_token), - )) } else { Box::new(Node::node( Expr::List(ListExpr { @@ -859,40 +1055,49 @@ impl<'a> Parser<'a> { /// Syntax: /// list_items: expr ((COMMA [NEWLINE] | NEWLINE) expr)* [COMMA] [NEWLINE] - pub(crate) fn parse_list_items(&mut self) -> Vec> { - if let TokenKind::CloseDelim(DelimToken::Bracket) = self.token.kind { + pub(crate) fn parse_list_items(&mut self, has_newline: bool) -> Vec> { + let is_terminator = |token: &kclvm_ast::token::Token| match &token.kind { + TokenKind::CloseDelim(DelimToken::Bracket) | TokenKind::Eof => true, + TokenKind::Newline if !has_newline => true, + _ => token.is_keyword(kw::For), + }; + + if is_terminator(&self.token) { return Vec::new(); } let mut items = vec![self.parse_list_item()]; + if let TokenKind::Comma = self.token.kind { self.bump(); } - self.skip_newlines(); - + if has_newline { + self.skip_newlines(); + } loop { - if matches!( - self.token.kind, - TokenKind::CloseDelim(DelimToken::Bracket) | TokenKind::Dedent - ) { - break; - } - if self.token.is_keyword(kw::For) { + let marker = self.mark(); + self.clean_all_indentations(); + if is_terminator(&self.token) { break; } - if let TokenKind::Comma = self.token.kind { + let item = self.parse_list_item(); + if matches!(item.node, Expr::Missing(_)) { + self.sess + .struct_token_error(&[TokenKind::Comma.into()], self.token); self.bump(); + } else { + items.push(item); } - self.skip_newlines(); - items.push(self.parse_list_item()); if let TokenKind::Comma = self.token.kind { self.bump(); } - self.skip_newlines(); + if has_newline { + self.skip_newlines(); + } + self.drop(marker); } - items } @@ -962,6 +1167,7 @@ impl<'a> Parser<'a> { // elif ... let mut elif_list = Vec::new(); loop { + let marker = self.mark(); if !self.token.is_keyword(kw::Elif) { break; } @@ -987,6 +1193,7 @@ impl<'a> Parser<'a> { x, self.sess.struct_token_loc(token, self.prev_token), ))); + self.drop(marker); } if let TokenKind::Newline = self.token.kind { @@ -1022,6 +1229,7 @@ impl<'a> Parser<'a> { x.node.orelse = if_item.orelse; let t = Node { + id: AstIndex::default(), node: Expr::ListIfItem(x.node), filename: x.filename, line: x.line, @@ -1052,12 +1260,14 @@ impl<'a> Parser<'a> { } self.skip_newlines(); - self.bump_token(TokenKind::Indent); + self.bump_token(TokenKind::Indent(VALID_SPACES_LENGTH)); let mut body = Vec::new(); loop { - if matches!(self.token.kind, TokenKind::Dedent) { + let marker = self.mark(); + self.validate_dedent(); + if matches!(self.token.kind, TokenKind::Dedent(VALID_SPACES_LENGTH)) { break; } @@ -1067,9 +1277,10 @@ impl<'a> Parser<'a> { self.bump(); } self.skip_newlines(); + self.drop(marker); } - - self.bump_token(TokenKind::Dedent); + self.validate_dedent(); + self.bump_token(TokenKind::Dedent(VALID_SPACES_LENGTH)); body } @@ -1094,36 +1305,26 @@ impl<'a> Parser<'a> { let has_newline = if self.token.kind == TokenKind::Newline { self.skip_newlines(); - if self.token.kind == TokenKind::Indent { - self.bump(); - } else if self.token.kind == TokenKind::CloseDelim(DelimToken::Brace) { + self.clean_all_indentations(); + if self.token.kind == TokenKind::CloseDelim(DelimToken::Brace) { self.bump(); return Box::new(Node::node( Expr::Config(ConfigExpr { items: vec![] }), self.sess.struct_token_loc(token, self.prev_token), )); - } else { - self.sess - .struct_token_error(&[TokenKind::Indent.into()], self.token) } true } else { false }; - let items = self.parse_config_entries(); + let item_start_token = self.token; + let items = self.parse_config_entries(has_newline); let generators = self.parse_comp_clauses(); // _DEDENT - if has_newline { - self.skip_newlines(); - if self.token.kind == TokenKind::Dedent { - self.bump(); - } else { - self.sess - .struct_token_error(&[TokenKind::Dedent.into()], self.token) - } - } + self.skip_newlines(); + self.clean_all_indentations(); // RIGHT_BRACE match self.token.kind { @@ -1138,16 +1339,38 @@ impl<'a> Parser<'a> { if !generators.is_empty() { if items.len() > 1 { - self.sess.struct_compiler_bug("multiple entries found.") + self.sess.struct_span_error( + &format!( + "multiple config comp clause expression found: expected 1, got {}", + items.len() + ), + item_start_token.span, + ); + Box::new(Node::node( + Expr::DictComp(DictComp { + entry: items[0].node.clone(), + generators, + }), + self.sess.struct_token_loc(token, self.prev_token), + )) + } else if items.len() == 1 { + Box::new(Node::node( + Expr::DictComp(DictComp { + entry: items[0].node.clone(), + generators, + }), + self.sess.struct_token_loc(token, self.prev_token), + )) + } else { + self.sess.struct_span_error( + "missing config comp clause expression", + item_start_token.span, + ); + Box::new(Node::node( + Expr::Config(ConfigExpr { items }), + self.sess.struct_token_loc(token, self.prev_token), + )) } - - Box::new(Node::node( - Expr::DictComp(DictComp { - entry: items[0].node.clone(), - generators, - }), - self.sess.struct_token_loc(token, self.prev_token), - )) } else { Box::new(Node::node( Expr::Config(ConfigExpr { items }), @@ -1158,35 +1381,44 @@ impl<'a> Parser<'a> { /// Syntax: /// config_entries: config_entry ((COMMA [NEWLINE] | NEWLINE) config_entry)* [COMMA] [NEWLINE] - fn parse_config_entries(&mut self) -> Vec> { + fn parse_config_entries(&mut self, has_newline: bool) -> Vec> { + let is_terminator = |token: &kclvm_ast::token::Token| match &token.kind { + TokenKind::CloseDelim(DelimToken::Brace) | TokenKind::Eof => true, + TokenKind::Newline if !has_newline => true, + _ => token.is_keyword(kw::For), + }; + + if is_terminator(&self.token) { + return Vec::new(); + } + let mut entries = vec![self.parse_config_entry()]; + if let TokenKind::Comma = self.token.kind { self.bump(); } - self.skip_newlines(); + if has_newline { + self.skip_newlines(); + } loop { - if matches!( - self.token.kind, - TokenKind::CloseDelim(DelimToken::Brace) | TokenKind::Dedent - ) { - break; - } - if self.token.is_keyword(kw::For) { - break; - } + let marker = self.mark(); + self.clean_all_indentations(); - if let TokenKind::Comma = self.token.kind { - self.bump(); + if is_terminator(&self.token) { + break; } - self.skip_newlines(); entries.push(self.parse_config_entry()); if let TokenKind::Comma = self.token.kind { self.bump(); } - self.skip_newlines(); + if has_newline { + self.skip_newlines(); + } + + self.drop(marker); } entries @@ -1226,14 +1458,17 @@ impl<'a> Parser<'a> { TokenKind::BinOpEq(BinOpToken::Plus) => { operation = ConfigEntryOperation::Insert; } - _ => self.sess.struct_token_error( - &[ - TokenKind::Colon.into(), - TokenKind::Assign.into(), - TokenKind::BinOpEq(BinOpToken::Plus).into(), - ], - self.token, - ), + _ => { + self.sess.struct_token_error( + &[ + TokenKind::Colon.into(), + TokenKind::Assign.into(), + TokenKind::BinOpEq(BinOpToken::Plus).into(), + ], + self.token, + ); + operation = ConfigEntryOperation::Override; + } } self.bump(); value = self.parse_expr(); @@ -1246,7 +1481,6 @@ impl<'a> Parser<'a> { key, value, operation, - insert_index: -1, }, self.sess.struct_token_loc(token, self.prev_token), )) @@ -1275,6 +1509,7 @@ impl<'a> Parser<'a> { /// loop_variables: identifier (COMMA identifier)* fn parse_comp_clause(&mut self) -> NodeRef { let token = self.token; + // bump the `for` keyword. self.bump(); let mut targets = vec![self.parse_identifier()]; @@ -1327,6 +1562,7 @@ impl<'a> Parser<'a> { /// (ELSE COLON if_entry_exec_block)? fn parse_if_entry_expr(&mut self) -> NodeRef { let mut need_skip_newlines = false; + let token = self.token; let mut if_entry = { self.bump_keyword(kw::If); @@ -1350,7 +1586,9 @@ impl<'a> Parser<'a> { // elif ... let mut need_skip_newlines = false; let mut elif_list = Vec::new(); + let mut last_token = self.token; loop { + let marker = self.mark(); if !self.token.is_keyword(kw::Elif) { break; } @@ -1376,6 +1614,8 @@ impl<'a> Parser<'a> { x, self.sess.struct_token_loc(token, self.prev_token), ))); + last_token = self.prev_token; + self.drop(marker); } if let TokenKind::Newline = self.token.kind { @@ -1405,6 +1645,7 @@ impl<'a> Parser<'a> { Expr::Config(orelse), self.sess.struct_token_loc(token, self.prev_token), )); + last_token = self.prev_token; if_entry.node.orelse = Some(t); } @@ -1421,6 +1662,7 @@ impl<'a> Parser<'a> { x.node.orelse = if_entry.node.orelse; let t = Node { + id: AstIndex::default(), node: Expr::ConfigIfEntry(x.node), filename: x.filename, line: x.line, @@ -1431,13 +1673,10 @@ impl<'a> Parser<'a> { if_entry.node.orelse = Some(Box::new(t)); } - Box::new(Node::new( + + Box::new(Node::node( Expr::ConfigIfEntry(if_entry.node), - if_entry.filename, - if_entry.line, - if_entry.column, - if_entry.end_line, - if_entry.end_column, + self.sess.struct_token_loc(token, last_token), )) } @@ -1456,13 +1695,13 @@ impl<'a> Parser<'a> { ) -> NodeRef { if need_skip_newlines { self.skip_newlines(); - self.bump_token(TokenKind::Indent); + self.bump_token(TokenKind::Indent(VALID_SPACES_LENGTH)); } let token = self.token; - let mut body = { let node = Node { + id: AstIndex::default(), node: Expr::NameConstantLit(NameConstantLit { value: NameConstant::None, // ignore }), @@ -1484,8 +1723,10 @@ impl<'a> Parser<'a> { body: &mut ConfigIfEntryExpr, need_skip_newlines: bool, ) -> bool { + let marker = this.mark(); if need_skip_newlines { - if let TokenKind::Dedent = this.token.kind { + if let TokenKind::Dedent(VALID_SPACES_LENGTH) = this.token.kind { + this.bump(); return false; } } else if let TokenKind::Newline = this.token.kind { @@ -1507,15 +1748,14 @@ impl<'a> Parser<'a> { key: expr0, value: expr1, operation: op, - insert_index: -1 }, pos )); return true; } - - if let TokenKind::Dedent = this.token.kind { + this.validate_dedent(); + if let TokenKind::Dedent(VALID_SPACES_LENGTH) = this.token.kind { return false; } if let TokenKind::Newline = this.token.kind { @@ -1537,15 +1777,14 @@ impl<'a> Parser<'a> { key: expr0, value: expr1, operation: op, - insert_index: -1 }, pos )); return true; } - - if let TokenKind::Dedent = this.token.kind { + this.validate_dedent(); + if let TokenKind::Dedent(VALID_SPACES_LENGTH) = this.token.kind { return false; } if let TokenKind::Newline = this.token.kind { @@ -1569,44 +1808,58 @@ impl<'a> Parser<'a> { ConfigEntryOperation::Insert } _ => { - panic!("invalid op: {:?}", this.token); + this.sess.struct_token_error( + &[ + TokenKind::Colon.into(), + TokenKind::Assign.into(), + TokenKind::BinOpEq(BinOpToken::Plus).into(), + ], + this.token, + ); + ConfigEntryOperation::Override } }; let expr1 = this.parse_expr(); - - let pos = expr1.pos(); + let expr0_pos = expr0.clone().unwrap().pos(); + let expr1_pos = expr1.pos(); + + let pos = ( + expr0_pos.0, + expr0_pos.1, + expr0_pos.2, + expr1_pos.3, + expr1_pos.4, + ); body.items.push(node_ref!( ConfigEntry { key: expr0, value: expr1, operation: op, - insert_index: -1 }, pos )); } - + this.drop(marker); true } - while parse_body_item(self, &mut body, need_skip_newlines) { - if let TokenKind::Comma = self.token.kind { - self.bump(); - } - if need_skip_newlines { + if !need_skip_newlines { + // Only parse one inline key-value pair. + parse_body_item(self, &mut body, need_skip_newlines); + } else { + while parse_body_item(self, &mut body, need_skip_newlines) { + // bump optional comma at the endline. + if let TokenKind::Comma = self.token.kind { + self.bump(); + } self.skip_newlines(); } } - if let TokenKind::Newline = self.token.kind { - self.bump(); - } if need_skip_newlines { self.skip_newlines(); - self.bump_token(TokenKind::Dedent); - Box::new(Node::node( body, self.sess.struct_token_loc(token, self.prev_token), @@ -1623,16 +1876,19 @@ impl<'a> Parser<'a> { /// schema_expr: identifier config_expr pub(crate) fn parse_schema_expr( &mut self, - identifier: Node, + expr: Node, lo: token::Token, ) -> NodeRef { - let result = identifier.try_into(); + let missing_ident = expr.into_missing_identifier(); + let result = expr.try_into(); let name = match result { Ok(v) => v, - Err(_) => self - .sess - .struct_token_error(&[TokenKind::ident_value()], self.token), + Err(_) => { + self.sess + .struct_token_error(&[TokenKind::ident_value()], self.token); + missing_ident + } }; // config_expr @@ -1650,14 +1906,20 @@ impl<'a> Parser<'a> { /// Syntax: /// schema_expr: identifier LEFT_PARENTHESES [arguments] RIGHT_PARENTHESES config_expr - fn parse_schema_expr_with_args(&mut self, call: CallExpr, lo: token::Token) -> NodeRef { + pub(crate) fn parse_schema_expr_with_args( + &mut self, + call: CallExpr, + lo: token::Token, + ) -> NodeRef { let result = call.func.as_ref().clone().try_into(); let name = match result { Ok(v) => v, - Err(_) => self - .sess - .struct_token_error(&[TokenKind::ident_value()], self.token), + Err(_) => { + self.sess + .struct_token_error(&[TokenKind::ident_value()], self.token); + call.func.as_ref().into_missing_identifier() + } }; // config_expr @@ -1683,7 +1945,6 @@ impl<'a> Parser<'a> { self.bump_keyword(kw::Lambda); let mut args = None; - let mut return_type_str = None; let mut return_ty = None; // schema_arguments @@ -1699,7 +1960,6 @@ impl<'a> Parser<'a> { if let TokenKind::RArrow = self.token.kind { self.bump_token(TokenKind::RArrow); let typ = self.parse_type_annotation(); - return_type_str = Some(typ.node.to_string()); return_ty = Some(typ); } @@ -1710,39 +1970,34 @@ impl<'a> Parser<'a> { // NEWLINE _INDENT let has_newline = if self.token.kind == TokenKind::Newline { self.skip_newlines(); - - if self.token.kind == TokenKind::Indent { - self.bump(); - } else { - self.sess - .struct_token_error(&[TokenKind::Indent.into()], self.token) - } + self.clean_all_indentations(); true } else { false }; loop { + let marker = self.mark(); + self.clean_all_indentations(); if matches!( self.token.kind, - TokenKind::CloseDelim(DelimToken::Brace) | TokenKind::Dedent + TokenKind::CloseDelim(DelimToken::Brace) | TokenKind::Eof ) { break; } if let Some(stmt) = self.parse_stmt() { stmt_list.push(stmt); self.skip_newlines(); + } else { + self.bump(); } + + self.drop(marker); } // _DEDENT if has_newline { - if self.token.kind == TokenKind::Dedent { - self.bump(); - } else { - self.sess - .struct_token_error(&[TokenKind::Dedent.into()], self.token) - } + self.clean_all_dedent(); } self.bump_token(TokenKind::CloseDelim(DelimToken::Brace)); @@ -1750,7 +2005,6 @@ impl<'a> Parser<'a> { Box::new(Node::node( Expr::Lambda(LambdaExpr { args, - return_type_str, return_ty, body: stmt_list, }), @@ -1758,32 +2012,6 @@ impl<'a> Parser<'a> { )) } - /// Return type of the lambda - fn parse_lambda_type(&mut self) -> String { - self.bump(); - - if self.token.is_keyword(kw::Type) { - self.bump(); - - // rules: append strings util a left brace. panic on a '\n'. - let mut s = String::new(); - - while let TokenKind::Literal(lt) = self.token.kind { - let token_str = lt.symbol.as_str(); - if token_str == "\n" { - self.sess - .struct_span_error("cross line type is not supported.", self.token.span) - } - - s.push_str(lt.symbol.as_str()) - } - - s.to_string() - } else { - self.sess.struct_token_error(&[kw::Type.into()], self.token) - } - } - /// Syntax: /// paren_expr: LEFT_PARENTHESES expr RIGHT_PARENTHESES fn parse_paren_expr(&mut self) -> NodeRef { @@ -1795,6 +2023,7 @@ impl<'a> Parser<'a> { TokenKind::CloseDelim(DelimToken::Paren) => { self.bump(); } + _ => self.sess.struct_token_error( &[token::TokenKind::CloseDelim(token::DelimToken::Paren).into()], self.token, @@ -1809,19 +2038,40 @@ impl<'a> Parser<'a> { /// Syntax: /// arguments: argument (COMMA argument)* - fn parse_arguments_expr(&mut self) -> (Vec>, Vec>) { + fn parse_arguments_expr( + &mut self, + has_newline: bool, + ) -> (Vec>, Vec>) { let mut args: Vec> = Vec::new(); let mut keywords: Vec> = Vec::new(); let mut has_keyword = false; + let is_terminator = |token: &kclvm_ast::token::Token| match &token.kind { + TokenKind::CloseDelim(DelimToken::Paren) | TokenKind::Eof => true, + TokenKind::Newline if !has_newline => true, + _ => token.is_keyword(kw::For), + }; loop { + let marker = self.mark(); + self.clean_all_indentations(); + if is_terminator(&self.token) { + break; + } + // Record the argument expression start token. + let token = self.token; match self.parse_argument_expr() { Either::Left(expr) => { - args.push(Box::new(expr)); + if matches!(expr.node, Expr::Missing(_)) { + self.sess + .struct_token_error(&[TokenKind::Comma.into()], self.token); + self.bump(); + } else { + args.push(Box::new(expr)); + } if has_keyword { self.sess.struct_span_error( - "positional argument follows keyword argument.", - self.token.span, + "positional argument follows keyword argument", + token.span, ) } } @@ -1833,9 +2083,11 @@ impl<'a> Parser<'a> { if self.token.kind == TokenKind::Comma { self.bump(); - } else { - break; } + if has_newline { + self.skip_newlines(); + } + self.drop(marker); } (args, keywords) @@ -1857,9 +2109,11 @@ impl<'a> Parser<'a> { let arg = match &expr.node { Expr::Identifier(x) => x.clone(), - _ => self - .sess - .struct_token_error(&[TokenKind::ident_value()], self.token), + _ => { + self.sess + .struct_token_error(&[TokenKind::ident_value()], self.token); + expr.into_missing_identifier().node + } }; // expr @@ -1890,7 +2144,7 @@ impl<'a> Parser<'a> { TokenKind::OpenDelim(DelimToken::Paren) => { self.bump(); - self.parse_call_expr(func) + self.parse_call_expr(func, token) } _ => Box::new(Node::node( Expr::Call(CallExpr { @@ -1935,18 +2189,42 @@ impl<'a> Parser<'a> { /// ~~~ Id - fn parse_identifier(&mut self) -> NodeRef { + pub(crate) fn parse_identifier(&mut self) -> NodeRef { let token = self.token; - let mut names = Vec::new(); + let mut names: Vec> = Vec::new(); let ident = self.token.ident(); match ident { Some(id) => { - names.push(id.as_str().to_string()); + names.push(Node::node( + id.as_str(), + self.sess.struct_token_loc(self.token, self.token), + )); self.bump(); } - None => self - .sess - .struct_token_error(&[TokenKind::ident_value()], self.token), + None => { + { + self.sess + .struct_token_error(&[TokenKind::ident_value()], self.token); + names.push(Node::node( + "".to_string(), + ( + self.sess.lookup_char_pos(self.token.span.lo()), + self.sess.lookup_char_pos(self.token.span.lo()), + ), + )); + return Box::new(Node::node( + Identifier { + names, + pkgpath: "".to_string(), + ctx: ExprContext::Load, + }, + ( + self.sess.lookup_char_pos(self.token.span.lo()), + self.sess.lookup_char_pos(self.token.span.lo()), + ), + )); + }; + } } loop { @@ -1957,12 +2235,23 @@ impl<'a> Parser<'a> { let ident = self.token.ident(); match ident { Some(id) => { - names.push(id.as_str().to_string()); + names.push(Node::node( + id.as_str(), + self.sess.struct_token_loc(self.token, self.token), + )); self.bump(); } - None => self - .sess - .struct_token_error(&[TokenKind::ident_value()], self.token), + None => { + self.sess + .struct_token_error(&[TokenKind::ident_value()], self.token); + names.push(Node::node( + "".to_string(), + ( + self.sess.lookup_char_pos(self.token.span.lo()), + self.sess.lookup_char_pos(self.token.span.lo()), + ), + )) + } } } _ => break, @@ -1988,21 +2277,42 @@ impl<'a> Parser<'a> { let (binary_suffix, value) = match lk.kind { token::LitKind::Integer => { - let value = bytes_to_int(lk.symbol.as_str().as_bytes(), 0).unwrap(); - + let result = bytes_to_int(lk.symbol.as_str().as_bytes(), 0); + let value = match result { + Some(value) => value, + None => { + self.sess + .struct_token_error(&[token::LitKind::Integer.into()], token); + 0 + } + }; match lk.suffix { - Some(suffix) => (suffix.as_str().try_into().ok(), NumberLitValue::Int(value)), + Some(suffix) => ( + suffix.as_str().as_str().try_into().ok(), + NumberLitValue::Int(value), + ), None => (None, NumberLitValue::Int(value)), } } token::LitKind::Float => { - let value = lk.symbol.as_str().parse().unwrap(); + let result = lk.symbol.as_str().parse(); + let value = match result { + Ok(value) => value, + _ => { + self.sess + .struct_token_error(&[token::LitKind::Float.into()], token); + 0.0 + } + }; (None, NumberLitValue::Float(value)) } - _ => self.sess.struct_token_error( - &[token::LitKind::Integer.into(), token::LitKind::Float.into()], - self.token, - ), + _ => { + self.sess.struct_token_error( + &[token::LitKind::Integer.into(), token::LitKind::Float.into()], + self.token, + ); + (None, NumberLitValue::Int(0)) + } }; self.bump(); @@ -2023,20 +2333,21 @@ impl<'a> Parser<'a> { let (is_long_string, raw_value, value) = match lk.kind { token::LitKind::Str { is_long_string, .. } => { - let value = lk.symbol.as_str().to_string(); - let raw_value = lk - .raw - .map_or("".to_string(), |raw| raw.as_str().to_string()); + let value = lk.symbol.as_str(); + let raw_value = lk.raw.map_or("".to_string(), |raw| raw.as_str()); (is_long_string, raw_value, value) } - _ => self.sess.struct_token_error( - &[token::LitKind::Str { - is_long_string: false, - is_raw: false, - } - .into()], - self.token, - ), + _ => { + self.sess.struct_token_error( + &[token::LitKind::Str { + is_long_string: false, + is_raw: false, + } + .into()], + self.token, + ); + (false, "\"\"".to_string(), "".to_string()) + } }; self.bump(); @@ -2071,19 +2382,23 @@ impl<'a> Parser<'a> { NameConstant::False } else { self.sess - .struct_token_error(&[token::LitKind::Bool.into()], self.token) + .struct_token_error(&[token::LitKind::Bool.into()], self.token); + NameConstant::False } } token::LitKind::None => NameConstant::None, token::LitKind::Undefined => NameConstant::Undefined, - _ => self.sess.struct_token_error( - &[ - token::LitKind::Bool.into(), - token::LitKind::None.into(), - token::LitKind::Undefined.into(), - ], - self.token, - ), + _ => { + self.sess.struct_token_error( + &[ + token::LitKind::Bool.into(), + token::LitKind::None.into(), + token::LitKind::Undefined.into(), + ], + self.token, + ); + NameConstant::Undefined + } }; self.bump(); @@ -2093,4 +2408,105 @@ impl<'a> Parser<'a> { self.sess.struct_token_loc(token, self.prev_token), )) } + + #[inline] + pub(crate) fn missing_expr(&self) -> NodeRef { + Box::new(Node::node( + Expr::Missing(MissingExpr), + // The text range of missing expression is zero. + self.sess.struct_token_loc(self.token, self.token), + )) + } + + /// Cast an expression into an identifier, else + /// store an error `expected identifier. + #[inline] + pub(crate) fn expr_as_identifier( + &mut self, + expr: NodeRef, + token: kclvm_ast::token::Token, + ) -> Identifier { + if let Expr::Identifier(x) = expr.node { + x + } else { + self.sess + .struct_span_error("expected identifier", token.span); + expr.into_missing_identifier().node + } + } + + /// Cast an expression into an assign target. + pub(crate) fn expr_as_assign_target(&self, expr: &NodeRef) -> Result { + let mut paths = self.expr_as_assign_target_paths(expr)?; + if paths.len() >= 1 { + let first = paths.remove(0); + match first { + MemberOrIndex::Member(member) => Ok(Target { + name: *member, + paths: paths.to_vec(), + pkgpath: "".to_string(), + }), + MemberOrIndex::Index(_) => bail!( + "'{}' is an illegal expression for assignment", + expr.node.get_expr_name() + ), + } + } else { + bail!( + "'{}' is an illegal expression for assignment", + expr.node.get_expr_name() + ); + } + } + + /// Cast an expression into an assign target paths. + pub(crate) fn expr_as_assign_target_paths( + &self, + expr: &NodeRef, + ) -> Result> { + match &expr.node { + Expr::Identifier(identifier) => Ok(self.identifier_as_assign_target_paths(identifier)), + Expr::Selector(selector) => { + if selector.has_question { + bail!("'{}' is an illegal expression for assignment, because the left-hand side of an assignment expression may not be an optional attribute access.", expr.node.get_expr_name()); + } else { + let mut value_paths = self.expr_as_assign_target_paths(&selector.value)?; + let mut attr_values = + self.identifier_as_assign_target_paths(&selector.attr.node); + value_paths.append(&mut attr_values); + Ok(value_paths) + } + } + Expr::Subscript(subscript) => { + if subscript.has_question { + bail!("'{}' is an illegal expression for assignment, because the left-hand side of an assignment expression may not be an optional subscript access.", expr.node.get_expr_name()); + } else { + let mut value_paths = self.expr_as_assign_target_paths(&subscript.value)?; + if let Some(index) = &subscript.index { + value_paths.push(MemberOrIndex::Index(index.clone())); + Ok(value_paths) + } else { + bail!("'{}' is an illegal expression for assignment, because the left-hand side of an assignment expression may not be a slice access.", expr.node.get_expr_name()); + } + } + } + _ => bail!( + "'{}' is an illegal expression for assignment", + expr.node.get_expr_name() + ), + } + } + + /// Cast a identifier into an assign target paths. + #[inline] + pub(crate) fn identifier_as_assign_target_paths( + &self, + identifier: &Identifier, + ) -> Vec { + identifier + .names + .iter() + .map(|i| MemberOrIndex::Member(Box::new(i.clone()))) + .collect() + } } diff --git a/kclvm/parser/src/parser/mod.rs b/kclvm/parser/src/parser/mod.rs index f82d4bab7..3e635f976 100644 --- a/kclvm/parser/src/parser/mod.rs +++ b/kclvm/parser/src/parser/mod.rs @@ -10,6 +10,8 @@ //! KCL syntax elements can be simply divided into statements, expressions and tokens, //! in which statement consists of expressions and tokens. In expression, operand is the most //! complex part to enable all kinds of ident, constant, list, dict, config exprs. +//! +//! The parser error recovery strategy design is [here](https://github.com/kcl-lang/kcl/issues/420). #![macro_use] @@ -17,7 +19,6 @@ mod expr; mod int; mod module; mod precedence; -mod schema; mod stmt; #[cfg(test)] mod tests; @@ -25,11 +26,16 @@ mod ty; use crate::session::ParseSession; -use kclvm_ast::ast::{Comment, NodeRef}; +use compiler_base_span::span::{new_byte_pos, BytePos}; +use kclvm_ast::ast::{Comment, NodeRef, PosTuple}; use kclvm_ast::token::{CommentKind, Token, TokenKind}; use kclvm_ast::token_stream::{Cursor, TokenStream}; +use kclvm_error::ParseErrorMessage; use kclvm_span::symbol::Symbol; +use kclvm_utils::path::PathPrefix; +/// The parser is built on top of the [`kclvm_parser::lexer`], and ordering KCL tokens +/// [`kclvm_ast::token`] to KCL ast nodes [`kclvm_ast::ast`]. pub struct Parser<'a> { /// The current token. pub token: Token, @@ -43,9 +49,15 @@ pub struct Parser<'a> { pub sess: &'a ParseSession, } +/// The DropMarker is used to mark whether to discard the token Mark whether to discard the token. +/// The principle is to store the index of the token in the token stream. When there is no index +/// change during the parse process, it is discarded and an error is output +#[derive(Debug, Default, Clone, Copy)] +pub(crate) struct DropMarker(usize); + impl<'a> Parser<'a> { pub fn new(sess: &'a ParseSession, stream: TokenStream) -> Self { - let (non_comment_tokens, comments) = Parser::split_token_stream(&sess, stream); + let (non_comment_tokens, comments) = Parser::split_token_stream(sess, stream); let mut parser = Parser { token: Token::dummy(), @@ -61,22 +73,29 @@ impl<'a> Parser<'a> { parser } - pub(crate) fn token_span_pos( - &mut self, - lo_tok: Token, - hi_tok: Token, - ) -> (String, u64, u64, u64, u64) { - use rustc_span::Pos; - let lo = self.sess.source_map.lookup_char_pos(lo_tok.span.lo()); - let hi = self.sess.source_map.lookup_char_pos(hi_tok.span.hi()); + /// Get an AST position from the token pair (lo_tok, hi_tok). + #[inline] + pub(crate) fn token_span_pos(&mut self, lo_tok: Token, hi_tok: Token) -> PosTuple { + self.byte_pos_to_pos(lo_tok.span.lo(), hi_tok.span.hi()) + } + + /// Get an AST position from the byte pos pair (lo, hi). + pub(crate) fn byte_pos_to_pos(&mut self, lo: BytePos, hi: BytePos) -> PosTuple { + let lo = self.sess.lookup_char_pos(lo); + let hi = self.sess.lookup_char_pos(hi); + + let filename = kclvm_utils::path::convert_windows_drive_letter(&format!( + "{}", + lo.file.name.prefer_remapped() + )) + .adjust_canonicalization(); - let filename: String = format!("{}", lo.file.name.prefer_remapped()); ( filename, lo.line as u64, - lo.col.to_usize() as u64, + lo.col.0 as u64, hi.line as u64, - hi.col.to_usize() as u64, + hi.col.0 as u64, ) } @@ -89,48 +108,28 @@ impl<'a> Parser<'a> { } } + /// Whether the parser has the next token in the token stream. + #[inline] + pub(crate) fn has_next(&mut self) -> bool { + self.cursor.next().is_some() + } + + #[inline] + /// Whether the parser has the next token in the token stream. + pub(crate) fn peek_has_next(&mut self) -> bool { + self.cursor.peek().is_some() + } + pub(crate) fn bump_keyword(&mut self, kw: Symbol) { if !self.token.is_keyword(kw) { - if let TokenKind::Ident(ident) = self.token.kind { - self.sess.struct_span_error( - &format!( - "bump keyword failed: expect={}, got={:?} # ident={}", - kw.to_ident_string(), - self.token, - ident - ), - self.token.span, - ); - } else { - self.sess.struct_span_error( - &format!( - "bump keyword failed: expect={}, {:?}", - kw.to_ident_string(), - self.token - ), - self.token.span, - ); - } + self.sess.struct_token_error(&[kw.into()], self.token); } self.bump(); } pub(crate) fn bump_token(&mut self, kind: TokenKind) { if self.token.kind != kind { - if let TokenKind::Ident(ident) = self.token.kind { - self.sess.struct_span_error( - &format!( - "bump token failed: expect={:?}, got={:?} # ident={}", - kind, self.token, ident - ), - self.token.span, - ); - } else { - self.sess.struct_span_error( - &format!("bump token failed: expect={:?}, {:?}", kind, self.token), - self.token.span, - ); - } + self.sess.struct_token_error(&[kind.into()], self.token); } self.bump(); } @@ -140,6 +139,24 @@ impl<'a> Parser<'a> { self.bump(); } } + + /// Mark the token index. + pub(crate) fn mark(&mut self) -> DropMarker { + DropMarker(self.cursor.index()) + } + + /// Decide to discard token according to the current index. + pub(crate) fn drop(&mut self, marker: DropMarker) -> bool { + if marker.0 == self.cursor.index() { + let token_str: String = self.token.into(); + self.sess + .struct_message_error(ParseErrorMessage::ExpectExpr(token_str), self.token.span); + self.bump(); + true + } else { + false + } + } } impl<'a> Parser<'a> { @@ -147,8 +164,6 @@ impl<'a> Parser<'a> { sess: &'a ParseSession, stream: TokenStream, ) -> (Vec, Vec>) { - use rustc_span::BytePos; - let mut comments = Vec::new(); let mut non_comment_tokens = Vec::new(); @@ -156,7 +171,7 @@ impl<'a> Parser<'a> { let prev_token = if i == 0 { Token { kind: TokenKind::Dummy, - span: kclvm_span::Span::new(BytePos(0), BytePos(0)), + span: kclvm_span::Span::new(new_byte_pos(0), new_byte_pos(0)), } } else { stream[i - 1] @@ -177,29 +192,31 @@ impl<'a> Parser<'a> { // split comments if matches!(tok.kind, TokenKind::DocComment(_)) { - match tok.kind { - TokenKind::DocComment(comment_kind) => match comment_kind { + if let TokenKind::DocComment(comment_kind) = tok.kind { + match comment_kind { CommentKind::Line(x) => { - use rustc_span::Pos; - let lo = sess.source_map.lookup_char_pos(tok.span.lo()); - let hi = sess.source_map.lookup_char_pos(tok.span.hi()); - let filename: String = format!("{}", lo.file.name.prefer_remapped()); + let lo = sess.lookup_char_pos(tok.span.lo()); + let hi = sess.lookup_char_pos(tok.span.hi()); + let filename = kclvm_utils::path::convert_windows_drive_letter( + &format!("{}", lo.file.name.prefer_remapped()), + ) + .adjust_canonicalization(); let node = kclvm_ast::ast::Node { + id: kclvm_ast::ast::AstIndex::default(), node: Comment { text: x.as_str().to_string(), }, - filename: filename, + filename, line: lo.line as u64, - column: lo.col.to_usize() as u64, + column: lo.col.0 as u64, end_line: hi.line as u64, - end_column: hi.col.to_usize() as u64, + end_column: hi.col.0 as u64, }; comments.push(NodeRef::new(node)); } - }, - _ => (), + } } continue; } diff --git a/kclvm/parser/src/parser/module.rs b/kclvm/parser/src/parser/module.rs index 1a4172b25..28d0bf40b 100644 --- a/kclvm/parser/src/parser/module.rs +++ b/kclvm/parser/src/parser/module.rs @@ -1,9 +1,10 @@ use kclvm_ast::ast::*; +use kclvm_ast::node_ref; use kclvm_ast::{token::LitKind, token::TokenKind}; use super::Parser; -impl<'a> Parser<'_> { +impl<'a> Parser<'a> { /// Syntax: /// start: (NEWLINE | statement)* pub fn parse_module(&mut self) -> Module { @@ -11,34 +12,57 @@ impl<'a> Parser<'_> { let body = self.parse_body(); Module { filename: "".to_string(), - pkg: "".to_string(), - name: "".to_string(), doc, comments: self.comments.clone(), body, } } - fn parse_doc(&mut self) -> String { - if let TokenKind::Literal(lit) = self.token.kind { - if let LitKind::Str { is_long_string, .. } = lit.kind { - if is_long_string { - let doc = format!("{:?}", self.token); - self.bump(); - return doc; + pub(crate) fn parse_doc(&mut self) -> Option> { + // doc string + match self.token.kind { + TokenKind::Literal(lit) => { + if let LitKind::Str { is_long_string, .. } = lit.kind { + if is_long_string { + let doc_expr = self.parse_str_expr(lit); + self.skip_newlines(); + match &doc_expr.node { + Expr::StringLit(str) => { + Some(node_ref!(str.raw_value.clone(), doc_expr.pos())) + } + Expr::JoinedString(str) => { + Some(node_ref!(str.raw_value.clone(), doc_expr.pos())) + } + _ => None, + } + } else { + None + } + } else { + None } } + _ => None, } - "".to_string() } fn parse_body(&mut self) -> Vec> { let mut stmts = Vec::new(); + loop { + if matches!(self.token.kind, TokenKind::Eof) { + self.bump(); + break; + } - while let Some(stmt) = self.parse_stmt() { - stmts.push(stmt) + if let Some(stmt) = self.parse_stmt() { + stmts.push(stmt); + } else { + // Error recovery from panic mode: Once an error is detected (the statement is None), + // the symbols in the input are continuously discarded (one symbol at a time), until the + // "synchronous lexical unit" is found (the statement start token e.g., import, schema, etc). + self.bump(); + } } - stmts } } diff --git a/kclvm/parser/src/parser/schema.rs b/kclvm/parser/src/parser/schema.rs deleted file mode 100644 index 8aaff84af..000000000 --- a/kclvm/parser/src/parser/schema.rs +++ /dev/null @@ -1,3 +0,0 @@ -use super::Parser; - -impl<'a> Parser<'_> {} diff --git a/kclvm/parser/src/parser/stmt.rs b/kclvm/parser/src/parser/stmt.rs index 0a877ffea..ab097099e 100644 --- a/kclvm/parser/src/parser/stmt.rs +++ b/kclvm/parser/src/parser/stmt.rs @@ -1,10 +1,11 @@ #![allow(dead_code)] #![allow(unused_macros)] -use core::panic; - -use kclvm_ast::token::{DelimToken, LitKind, Token, TokenKind}; +use compiler_base_span::{span::new_byte_pos, BytePos, Span}; +use kclvm_ast::token::VALID_SPACES_LENGTH; +use kclvm_ast::token::{CommentKind, DelimToken, LitKind, Token, TokenKind}; use kclvm_ast::{ast::*, expr_as, node_ref}; +use kclvm_error::ParseErrorMessage; use kclvm_span::symbol::kw; use super::Parser; @@ -13,7 +14,7 @@ use super::Parser; /// Parser uses `parse_exprlist` and `parse_expr` in [`kclvm_parser::parser::expr`] /// to get a expression node, and then concretize it into the specified expression node, /// and then assemble it into the corresponding statement node. -impl<'a> Parser<'_> { +impl<'a> Parser<'a> { /// Syntax: /// statement: simple_stmt | compound_stmt /// simple_stmt: (assign_stmt | expr_stmt | assert_stmt | import_stmt | type_alias_stmt) NEWLINE @@ -39,6 +40,10 @@ impl<'a> Parser<'_> { return Some(stmt); } + let tok: String = self.token.into(); + self.sess + .struct_span_error(&format!("unexpected token '{}'", tok), self.token.span); + None } @@ -57,7 +62,7 @@ impl<'a> Parser<'_> { // if ... if self.token.is_keyword(kw::If) { - return self.parse_if_stmt(); + return Some(self.parse_if_stmt()); } // @decorators @@ -68,17 +73,14 @@ impl<'a> Parser<'_> { }; // schema/mixin/protocol/rule ... - if self.token.is_keyword(kw::Schema) { - return self.parse_schema_stmt(decorators); - } - if self.token.is_keyword(kw::Mixin) { - return self.parse_schema_stmt(decorators); - } - if self.token.is_keyword(kw::Protocol) { - return self.parse_schema_stmt(decorators); + if self.token.is_keyword(kw::Schema) + || self.token.is_keyword(kw::Mixin) + || self.token.is_keyword(kw::Protocol) + { + return Some(self.parse_schema_stmt(decorators)); } if self.token.is_keyword(kw::Rule) { - return self.parse_rule_stmt(decorators); + return Some(self.parse_rule_stmt(decorators)); } None @@ -99,25 +101,32 @@ impl<'a> Parser<'_> { // import ... if self.token.is_keyword(kw::Import) { - return self.parse_import_stmt(); + return Some(self.parse_import_stmt()); } // type ... if self.token.is_keyword(kw::Type) { - return self.parse_type_alias_stmt(); + return Some(self.parse_type_alias_stmt()); } // assert ... if self.token.is_keyword(kw::Assert) { - return self.parse_assert_stmt(); + return Some(self.parse_assert_stmt()); } // unary expr if let TokenKind::UnaryOp(_) = self.token.kind { - return self.parse_expr_stmt(); + return Some(self.parse_expr_stmt()); } - // expr or assign - self.parse_expr_or_assign_stmt() + if matches!( + self.token.kind, + TokenKind::Ident(_) | TokenKind::Literal(_) | TokenKind::OpenDelim(_) + ) { + // expr or assign + self.parse_expr_or_assign_stmt(false) + } else { + None + } } /// Syntax: @@ -126,11 +135,17 @@ impl<'a> Parser<'_> { &mut self, open_tok: TokenKind, close_tok: TokenKind, - ) -> Vec>> { + ) -> Vec> { let mut stmt_list = Vec::new(); - + self.validate_dedent(); self.bump_token(open_tok); loop { + if self.token.kind == TokenKind::Eof { + self.bump(); + break; + } + + self.validate_dedent(); if self.token.kind == close_tok { self.bump_token(close_tok); break; @@ -138,6 +153,11 @@ impl<'a> Parser<'_> { if let Some(stmt) = self.parse_stmt() { stmt_list.push(stmt); + } else { + // Error recovery from panic mode: Once an error is detected (the statement is None), + // the symbols in the input are continuously discarded (one symbol at a time), until the + // "synchronous lexical unit" is found (the statement start token e.g., import, schema, etc). + self.bump(); } } @@ -147,7 +167,7 @@ impl<'a> Parser<'_> { /// Syntax: /// test: if_expr | simple_expr - fn parse_expr_stmt(&mut self) -> Option> { + fn parse_expr_stmt(&mut self) -> NodeRef { let token = self.token; let expr = vec![self.parse_expr()]; @@ -157,7 +177,7 @@ impl<'a> Parser<'_> { ); self.skip_newlines(); - Some(stmt) + stmt } /// Syntax: @@ -170,10 +190,10 @@ impl<'a> Parser<'_> { /// | COMP_DOUBLE_DIVIDE | COMP_MOD | COMP_AND | COMP_OR | COMP_XOR | COMP_SHIFT_LEFT /// | COMP_SHIFT_RIGHT | L_OR | L_AND) /// test - fn parse_expr_or_assign_stmt(&mut self) -> Option> { + fn parse_expr_or_assign_stmt(&mut self, is_in_schema_stmt: bool) -> Option> { let token = self.token; let mut targets = vec![self.parse_expr()]; - + let mut target_spans = vec![Span::new(token.span.lo(), self.prev_token.span.hi())]; let mut value_or_target = None; let mut type_annotation = None; let mut ty = None; @@ -183,13 +203,22 @@ impl<'a> Parser<'_> { let typ = self.parse_type_annotation(); type_annotation = Some(node_ref!(typ.node.to_string(), typ.pos())); - // Unification statement - if let TokenKind::OpenDelim(DelimToken::Brace) = self.token.kind { - // schema expression without args + // Maybe the unification statement with optional schema arguments + // `s: Schema {` or `s: Schema(` + if matches!( + self.token.kind, + TokenKind::OpenDelim(DelimToken::Brace) | TokenKind::OpenDelim(DelimToken::Paren) + ) { if let Type::Named(ref identifier) = typ.node { let identifier = node_ref!(Expr::Identifier(identifier.clone()), typ.pos()); - let schema_expr = self.parse_schema_expr(*identifier, token); - let mut ident = expr_as!(targets[0].clone(), Expr::Identifier).unwrap(); + let schema_expr = + if matches!(self.token.kind, TokenKind::OpenDelim(DelimToken::Paren)) { + let call = self.parse_call(identifier); + self.parse_schema_expr_with_args(call, token) + } else { + self.parse_schema_expr(*identifier, token) + }; + let mut ident = self.expr_as_identifier(targets[0].clone(), token); ident.ctx = ExprContext::Store; let unification_stmt = UnificationStmt { target: Box::new(Node::node_with_pos(ident, targets[0].pos())), @@ -206,38 +235,47 @@ impl<'a> Parser<'_> { } else if let TokenKind::BinOpEq(x) = self.token.kind { let op = AugOp::from(x); self.bump_token(self.token.kind); - - let value = self.parse_expr(); - let mut ident = expr_as!(targets[0].clone(), Expr::Identifier).unwrap(); - ident.ctx = ExprContext::Store; - - let t = node_ref!( - Stmt::AugAssign(AugAssignStmt { - target: Box::new(Node::node_with_pos(ident, targets[0].pos())), - value, - op, - }), - self.token_span_pos(token, self.prev_token) - ); - - self.skip_newlines(); - - return Some(t); + let target = self.expr_as_assign_target(&targets[0]); + match target { + Ok(target) => { + let value = self.parse_expr(); + let t = node_ref!( + Stmt::AugAssign(AugAssignStmt { + target: Box::new(Node::node_with_pos(target, targets[0].pos())), + value, + op, + }), + self.token_span_pos(token, self.prev_token) + ); + self.skip_newlines(); + return Some(t); + } + // 'expression' is an illegal expression for augmented assignment and drop the whole statement. + Err(err) => { + self.sess + .struct_span_error(&err.to_string(), target_spans[0]); + self.parse_expr(); + self.skip_newlines(); + return None; + } + } } while let TokenKind::Assign = self.token.kind { self.bump_token(TokenKind::Assign); - + let token = self.token; let expr = self.parse_expr(); + let expr_token = self.prev_token; if let Some(target) = value_or_target { targets.push(target); } - + // Put the `target = target = value` spans in the target_spans. + target_spans.push(Span::new(token.span.lo(), expr_token.span.hi())); value_or_target = Some(expr); } if let TokenKind::BinOpEq(x) = self.token.kind { - if targets.len() == 1 && type_annotation.is_some() { + if targets.len() == 1 && type_annotation.is_some() && is_in_schema_stmt { let aug_op = AugOp::from(x); self.bump_token(self.token.kind); let value = self.parse_expr(); @@ -246,10 +284,9 @@ impl<'a> Parser<'_> { return Some(node_ref!( Stmt::SchemaAttr(SchemaAttr { doc: "".to_string(), - name: node_ref!(target.names.join("."), targets[0].pos()), - type_str: type_annotation.unwrap(), - ty, - op: Some(BinOrAugOp::Aug(aug_op)), + name: node_ref!(target.get_name(), targets[0].pos()), + ty: ty.unwrap(), + op: Some(aug_op), value: Some(value), is_optional: false, decorators: Vec::new(), @@ -260,7 +297,7 @@ impl<'a> Parser<'_> { } } - self.skip_newlines(); + let stmt_end_token = self.prev_token; if let Some(value) = value_or_target { let mut pos = targets[0].pos(); @@ -269,62 +306,100 @@ impl<'a> Parser<'_> { let targets = targets .iter() - .map(|expr| match &expr.node { - Expr::Identifier(x) => { - let mut x = x.clone(); - x.ctx = ExprContext::Store; - Box::new(Node::node_with_pos(x, expr.pos())) + .enumerate() + .map(|(i, expr)| match self.expr_as_assign_target(expr) { + Ok(target) => Some(Box::new(Node::node_with_pos(target, expr.pos()))), + Err(err) => { + self.sess + .struct_span_error(&err.to_string(), target_spans[i]); + None } - _ => panic!("invalid target: {:?}", expr.node), }) + // Drop error assign target nodes. + .flatten() .collect(); + self.skip_newlines(); + Some(node_ref!( - Stmt::Assign(AssignStmt { - targets, - value, - type_annotation, - ty, - }), - self.token_span_pos(token, self.prev_token) + Stmt::Assign(AssignStmt { targets, value, ty }), + self.token_span_pos(token, stmt_end_token) )) } else { - if targets.len() == 1 && type_annotation.is_some() { + if targets.len() == 1 && type_annotation.is_some() && is_in_schema_stmt { if let Expr::Identifier(target) = &targets[0].node { + self.skip_newlines(); return Some(node_ref!( Stmt::SchemaAttr(SchemaAttr { doc: "".to_string(), - name: node_ref!(target.names.join("."), targets[0].pos()), - type_str: type_annotation.unwrap(), - ty, + name: node_ref!(target.get_names().join("."), targets[0].pos()), + ty: ty.unwrap(), op: None, value: None, is_optional: false, decorators: Vec::new(), }), - self.token_span_pos(token, self.prev_token) + self.token_span_pos(token, stmt_end_token) )); } } + if type_annotation.is_none() && !targets.is_empty() { + let mut pos = targets[0].pos(); + pos.3 = targets.last().unwrap().end_line; + pos.4 = targets.last().unwrap().end_column; + + let t = Box::new(Node::node_with_pos( + Stmt::Expr(ExprStmt { + exprs: targets.clone(), + }), + pos, + )); - let mut pos = targets[0].pos(); - pos.3 = targets.last().unwrap().end_line; - pos.4 = targets.last().unwrap().end_column; - - let t = Box::new(Node::node_with_pos( - Stmt::Expr(ExprStmt { - exprs: targets.clone(), - }), - pos, - )); + self.skip_newlines(); - Some(t) + Some(t) + } else { + let miss_expr = self.missing_expr(); + self.skip_newlines(); + self.sess + .struct_token_error(&[TokenKind::Assign.into()], self.token); + if type_annotation.is_some() && !targets.is_empty() && !is_in_schema_stmt { + let mut pos = targets[0].pos(); + pos.3 = targets.last().unwrap().end_line; + pos.4 = targets.last().unwrap().end_column; + + let targets = targets + .iter() + .enumerate() + .map(|(i, expr)| match self.expr_as_assign_target(expr) { + Ok(target) => Some(Box::new(Node::node_with_pos(target, expr.pos()))), + Err(err) => { + self.sess + .struct_span_error(&err.to_string(), target_spans[i]); + None + } + }) + // Drop error assign target nodes. + .flatten() + .collect(); + Some(Box::new(Node::node_with_pos( + Stmt::Assign(AssignStmt { + targets, + value: miss_expr, + ty, + }), + pos, + ))) + } else { + None + } + } } } /// Syntax: /// assert_stmt: ASSERT simple_expr (IF simple_expr)? (COMMA test)? - fn parse_assert_stmt(&mut self) -> Option> { + fn parse_assert_stmt(&mut self) -> NodeRef { let token = self.token; self.bump_keyword(kw::Assert); @@ -354,14 +429,15 @@ impl<'a> Parser<'_> { self.skip_newlines(); - Some(t) + t } /// Syntax: /// import_stmt: IMPORT dot_name (AS NAME)? - fn parse_import_stmt(&mut self) -> Option> { + fn parse_import_stmt(&mut self) -> NodeRef { let token = self.token; self.bump_keyword(kw::Import); + let dot_name_token = self.token; let mut leading_dot = Vec::new(); while let TokenKind::DotDotDot = self.token.kind { @@ -372,49 +448,63 @@ impl<'a> Parser<'_> { leading_dot.push(".".to_string()); self.bump_token(TokenKind::Dot); } + let dot_name = self.parse_identifier().node; + let dot_name_end_token = self.prev_token; - let dot_name = expr_as!(self.parse_identifier_expr(), Expr::Identifier).unwrap(); let asname = if self.token.is_keyword(kw::As) { self.bump_keyword(kw::As); - let ident = expr_as!(self.parse_identifier_expr(), Expr::Identifier).unwrap(); - Some(ident.names.join(".")) + let ident = self.parse_identifier().node; + match ident.names.len() { + 1 => Some(ident.names[0].clone()), + _ => { + self.sess + .struct_span_error("Invalid import asname", self.token.span); + None + } + } } else { None }; let mut path = leading_dot.join(""); - path.push_str(dot_name.names.join(".").as_str()); + path.push_str(dot_name.get_names().join(".").as_str()); let rawpath = path.clone(); + let path_node = Node::node_with_pos( + path, + self.token_span_pos(dot_name_token, dot_name_end_token), + ); let name = if let Some(as_name_value) = asname.clone() { - as_name_value + as_name_value.node } else { - dot_name.names.last().unwrap().clone() + dot_name.get_names().last().unwrap().clone() }; let t = node_ref!( Stmt::Import(ImportStmt { - path, + path: path_node, rawpath, name, asname, + pkg_name: String::new() }), self.token_span_pos(token, self.prev_token) ); self.skip_newlines(); - Some(t) + t } /// Syntax: /// type_alias_stmt: "type" NAME ASSIGN type - fn parse_type_alias_stmt(&mut self) -> Option> { + fn parse_type_alias_stmt(&mut self) -> NodeRef { self.bump_keyword(kw::Type); let type_name_pos = self.token; - let type_name = expr_as!(self.parse_expr(), Expr::Identifier).unwrap(); + let expr = self.parse_expr(); + let type_name = self.expr_as_identifier(expr, type_name_pos); let type_name_end = self.prev_token; self.bump_token(TokenKind::Assign); @@ -425,14 +515,14 @@ impl<'a> Parser<'_> { self.skip_newlines(); - Some(node_ref!( + node_ref!( Stmt::TypeAlias(TypeAliasStmt { type_name: node_ref!(type_name, self.token_span_pos(type_name_pos, type_name_end)), type_value: node_ref!(typ.node.to_string(), self.token_span_pos(typ_pos, typ_end)), - ty: Some(typ), + ty: typ, }), self.token_span_pos(type_name_pos, typ_end) - )) + ) } /// Syntax: @@ -440,7 +530,7 @@ impl<'a> Parser<'_> { /// execution_block: if_simple_stmt | NEWLINE _INDENT schema_init_stmt+ _DEDENT /// if_simple_stmt: (simple_assign_stmt | unification_stmt | expr_stmt | assert_stmt) NEWLINE /// schema_init_stmt: if_simple_stmt | if_stmt - fn parse_if_stmt(&mut self) -> Option> { + fn parse_if_stmt(&mut self) -> NodeRef { let token = self.token; // if @@ -452,10 +542,19 @@ impl<'a> Parser<'_> { self.bump_token(TokenKind::Colon); let body = if self.token.kind != TokenKind::Newline { - vec![self.parse_expr_or_assign_stmt().expect("invalid if_stmt")] + if let Some(stmt) = self.parse_expr_or_assign_stmt(false) { + vec![stmt] + } else { + // Error recovery from panic mode: Once an error is detected (the statement is None). + self.bump(); + vec![] + } } else { self.skip_newlines(); - self.parse_block_stmt_list(TokenKind::Indent, TokenKind::Dedent) + self.parse_block_stmt_list( + TokenKind::Indent(VALID_SPACES_LENGTH), + TokenKind::Dedent(VALID_SPACES_LENGTH), + ) }; IfStmt { @@ -480,10 +579,19 @@ impl<'a> Parser<'_> { self.bump_token(TokenKind::Colon); let body = if self.token.kind != TokenKind::Newline { - vec![self.parse_expr_or_assign_stmt().expect("invalid if_stmt")] + if let Some(stmt) = self.parse_expr_or_assign_stmt(false) { + vec![stmt] + } else { + // Error recovery from panic mode: Once an error is detected (the statement is None). + self.bump(); + vec![] + } } else { self.skip_newlines(); - self.parse_block_stmt_list(TokenKind::Indent, TokenKind::Dedent) + self.parse_block_stmt_list( + TokenKind::Indent(VALID_SPACES_LENGTH), + TokenKind::Dedent(VALID_SPACES_LENGTH), + ) }; let t = node_ref!( @@ -504,14 +612,39 @@ impl<'a> Parser<'_> { // else if self.token.is_keyword(kw::Else) { + let lo = self.token.span.lo(); self.bump_keyword(kw::Else); - self.bump_token(TokenKind::Colon); + + // `else if -> elif` error recovery. + if self.token.is_keyword(kw::If) { + self.sess.struct_message_error_with_suggestions( + ParseErrorMessage::InvalidTokenElseIf, + Span::new(lo, self.token.span.hi()), + Some(vec!["elif".to_string()]), + ); + self.bump_keyword(kw::If); + } + if self.token.kind != TokenKind::Colon { + self.sess + .struct_token_error(&[TokenKind::Colon.into()], self.token); + } + // Bump colon token. + self.bump(); let else_body = if self.token.kind != TokenKind::Newline { - vec![self.parse_expr_or_assign_stmt().expect("invalid if_stmt")] + if let Some(stmt) = self.parse_expr_or_assign_stmt(false) { + vec![stmt] + } else { + // Error recovery from panic mode: Once an error is detected (the statement is None). + self.bump(); + vec![] + } } else { self.skip_newlines(); - self.parse_block_stmt_list(TokenKind::Indent, TokenKind::Dedent) + self.parse_block_stmt_list( + TokenKind::Indent(VALID_SPACES_LENGTH), + TokenKind::Dedent(VALID_SPACES_LENGTH), + ) }; if_stmt.orelse = else_body; @@ -519,8 +652,20 @@ impl<'a> Parser<'_> { // fix elif-list and else while let Some(mut x) = elif_list.pop() { - x.node.orelse = if_stmt.orelse; - let pos = x.clone().pos(); + x.node.orelse = if_stmt.orelse.clone(); + let pos = if if_stmt.orelse.is_empty() { + x.clone().pos() + } else { + let start_pos = x.clone().pos(); + let end_pos = if_stmt.orelse.last().unwrap().pos(); + ( + start_pos.0.clone(), + start_pos.1, + start_pos.2, + end_pos.3, + end_pos.4, + ) + }; let t = Box::new(Node::node_with_pos(Stmt::If(x.node), pos)); if_stmt.orelse = vec![t]; } @@ -532,7 +677,7 @@ impl<'a> Parser<'_> { self.skip_newlines(); - Some(t) + t } /// Syntax: @@ -540,10 +685,7 @@ impl<'a> Parser<'_> { /// [LEFT_BRACKETS [schema_arguments] RIGHT_BRACKETS] /// [LEFT_PARENTHESES identifier (COMMA identifier)* RIGHT_PARENTHESES] /// [for_host] COLON NEWLINE [schema_body] - fn parse_schema_stmt( - &mut self, - decorators: Option>>, - ) -> Option> { + fn parse_schema_stmt(&mut self, decorators: Option>>) -> NodeRef { let token = self.token; // schema decorators @@ -568,10 +710,10 @@ impl<'a> Parser<'_> { } // schema Name - let name_expr = self.parse_identifier_expr(); + let name_expr = self.parse_identifier(); let name_pos = name_expr.pos(); - let name = expr_as!(name_expr, Expr::Identifier).unwrap(); - let name = node_ref!(name.names.join("."), name_pos); + let name = name_expr.node; + let name = node_ref!(name.get_names().join("."), name_pos); if name .node @@ -599,9 +741,9 @@ impl<'a> Parser<'_> { // schema Name [args...](Base) let parent_name = if let TokenKind::OpenDelim(DelimToken::Paren) = self.token.kind { self.bump_token(TokenKind::OpenDelim(DelimToken::Paren)); - let expr = self.parse_identifier_expr(); + let expr = self.parse_identifier(); let expr_pos = expr.pos(); - let base_schema_name = expr_as!(expr, Expr::Identifier).unwrap(); + let base_schema_name = expr.node; self.bump_token(TokenKind::CloseDelim(DelimToken::Paren)); Some(node_ref!(base_schema_name, expr_pos)) } else { @@ -611,9 +753,10 @@ impl<'a> Parser<'_> { // schema Name [args...](Base) for SomeProtocol let for_host_name = if self.token.is_keyword(kw::For) { self.bump_keyword(kw::For); + let token = self.token; let expr = self.parse_expr(); let expr_pos = expr.pos(); - let ident = expr_as!(expr, Expr::Identifier).unwrap(); + let ident = self.expr_as_identifier(expr, token); Some(node_ref!(ident, expr_pos)) } else { None @@ -623,12 +766,19 @@ impl<'a> Parser<'_> { self.skip_newlines(); - if let TokenKind::Indent = self.token.kind { + if let TokenKind::Indent(VALID_SPACES_LENGTH) = self.token.kind { let body = self.parse_schema_body(); - let pos = self.token_span_pos(token, self.prev_token); + let mut pos = self.token_span_pos(token, self.prev_token); + // Insert a fake newline character to expand the scope of the schema, + // used to complete the schema attributes at the end of the file + // FIXME: fix in lsp + if let TokenKind::Eof = self.prev_token.kind { + pos.3 += 1; + pos.4 = 0; + } - Some(node_ref!( + node_ref!( Stmt::Schema(SchemaStmt { doc: body.doc, name, @@ -644,12 +794,12 @@ impl<'a> Parser<'_> { index_signature: body.index_signature, }), pos - )) + ) } else { let pos = self.token_span_pos(token, self.prev_token); - Some(node_ref!( + node_ref!( Stmt::Schema(SchemaStmt { - doc: "".to_string(), + doc: None, name, parent_name, for_host_name, @@ -663,7 +813,7 @@ impl<'a> Parser<'_> { index_signature: None, }), pos - )) + ) } } @@ -690,9 +840,9 @@ impl<'a> Parser<'_> { Expr::Call(x) => { decorators.push(node_ref!(x, expr_pos)); } - _ => { - panic!("invalid Decorator: {:?}", expr); - } + _ => self + .sess + .struct_token_error(&[TokenKind::ident_value()], self.token), }; self.skip_newlines(); @@ -711,7 +861,6 @@ impl<'a> Parser<'_> { close_tokens: &[TokenKind], bump_close: bool, ) -> Option> { - debug_assert!(!close_tokens.is_empty()); let mut has_open_token = false; let token = self.token; @@ -729,11 +878,12 @@ impl<'a> Parser<'_> { let mut args = Arguments { args: Vec::new(), defaults: Vec::new(), - type_annotation_list: Vec::new(), ty_list: Vec::new(), }; loop { + let marker = self.mark(); + let mut has_close_token = false; for token in close_tokens { if *token == self.token.kind { @@ -748,20 +898,27 @@ impl<'a> Parser<'_> { break; } + if matches!(self.token.kind, TokenKind::Newline | TokenKind::Eof) { + let expect_tokens: Vec = close_tokens + .iter() + .map(|t| >::into(*t)) + .collect(); + self.sess.struct_token_error(&expect_tokens, self.token); + break; + } + let name_pos = self.token; - let name = expr_as!(self.parse_identifier_expr(), Expr::Identifier).unwrap(); + let name = self.parse_identifier().node; let name_end = self.prev_token; let name = node_ref!(name, self.token_span_pos(name_pos, name_end)); - let (type_annotation, type_annotation_node) = if let TokenKind::Colon = self.token.kind - { + let type_annotation_node = if let TokenKind::Colon = self.token.kind { self.bump_token(TokenKind::Colon); let typ = self.parse_type_annotation(); - - (Some(node_ref!(typ.node.to_string(), typ.pos())), Some(typ)) + Some(typ) } else { - (None, None) + None }; let default_value = if let TokenKind::Assign = self.token.kind { @@ -772,13 +929,14 @@ impl<'a> Parser<'_> { }; args.args.push(name); - args.type_annotation_list.push(type_annotation); args.ty_list.push(type_annotation_node); args.defaults.push(default_value); // Parameter interval comma if let TokenKind::Comma = self.token.kind { self.bump(); } + + self.drop(marker); } self.skip_newlines(); @@ -803,24 +961,18 @@ impl<'a> Parser<'_> { /// LEFT_BRACKETS [NAME COLON] [ELLIPSIS] basic_type RIGHT_BRACKETS /// COLON type [ASSIGN test] NEWLINE fn parse_schema_body(&mut self) -> SchemaStmt { - self.bump_token(TokenKind::Indent); + self.validate_dedent(); + self.bump_token(TokenKind::Indent(VALID_SPACES_LENGTH)); - // doc string - let body_doc = match self.token.kind { - TokenKind::Literal(lit) => { - if let LitKind::Str { .. } = lit.kind { - let doc_expr = self.parse_str_expr(lit); - self.skip_newlines(); - match &doc_expr.node { - Expr::StringLit(str) => str.raw_value.clone(), - Expr::JoinedString(str) => str.raw_value.clone(), - _ => "".to_string(), - } - } else { - "".to_string() - } + // doc string when it is not a string-like attribute statement. + let body_doc = if let Some(peek) = self.cursor.peek() { + if matches!(peek.kind, TokenKind::Colon) { + None + } else { + self.parse_doc() } - _ => "".to_string(), + } else { + self.parse_doc() }; // mixin @@ -837,24 +989,41 @@ impl<'a> Parser<'_> { let mut body_index_signature = None; loop { - if self.token.kind == TokenKind::Dedent || self.token.is_keyword(kw::Check) { + let marker = self.mark(); + self.validate_dedent(); + if matches!( + self.token.kind, + TokenKind::Dedent(VALID_SPACES_LENGTH) | TokenKind::Eof + ) || self.token.is_keyword(kw::Check) + { break; } - // assert stmt - if self.token.is_keyword(kw::Assert) { - body_body.push(self.parse_assert_stmt().unwrap()); + else if self.token.is_keyword(kw::Assert) { + body_body.push(self.parse_assert_stmt()); continue; } - // if stmt - if self.token.is_keyword(kw::If) { - body_body.push(self.parse_if_stmt().unwrap()); + else if self.token.is_keyword(kw::If) { + body_body.push(self.parse_if_stmt()); continue; } - + // schema_attribute_stmt: string COLON type_annotation + else if self.token.is_string_lit() { + if let Some(peek) = self.cursor.peek() { + if let TokenKind::Colon = peek.kind { + let token = self.token; + let attr = self.parse_schema_attribute(); + body_body.push(node_ref!( + Stmt::SchemaAttr(attr), + self.token_span_pos(token, self.prev_token) + )); + continue; + } + } + } // schema_attribute_stmt - if let TokenKind::At = self.token.kind { + else if let TokenKind::At = self.token.kind { let token = self.token; let attr = self.parse_schema_attribute(); body_body.push(node_ref!( @@ -882,18 +1051,27 @@ impl<'a> Parser<'_> { let (index_sig, or_list_expr) = self.parse_schema_index_signature_or_list(); if let Some(x) = index_sig { + if body_index_signature.is_some() { + self.sess.struct_span_error( + "duplicate schema index signature definitions, only one is allowed in the schema", + token.span, + ); + } body_index_signature = Some(node_ref!(x, self.token_span_pos(token, self.prev_token))); } else if let Some(list_expr) = or_list_expr { let stmt = Stmt::Expr(ExprStmt { - exprs: vec![node_ref!( - Expr::List(list_expr), - self.token_span_pos(token, self.prev_token) - )], + exprs: vec![list_expr], }); body_body.push(node_ref!(stmt, self.token_span_pos(token, self.prev_token))); } else { - self.sess.struct_compiler_bug("unreachable"); + self.sess.struct_span_error( + &format!( + "expected a index signature or list expression here, got {}", + Into::::into(self.token) + ), + self.token.span, + ); } self.skip_newlines(); @@ -901,7 +1079,7 @@ impl<'a> Parser<'_> { } // expr or attr - if let Some(x) = self.parse_expr_or_assign_stmt() { + if let Some(x) = self.parse_expr_or_assign_stmt(true) { if let Stmt::SchemaAttr(attr) = &x.node { body_body.push(node_ref!(Stmt::SchemaAttr(attr.clone()), x.pos())); continue; @@ -909,39 +1087,40 @@ impl<'a> Parser<'_> { if let Stmt::Assign(assign) = x.node.clone() { if assign.targets.len() == 1 { - let ident = assign.targets[0].clone().node; - if let Some(type_str) = assign.type_annotation { - if !type_str.node.is_empty() { - body_body.push(node_ref!( - Stmt::SchemaAttr(SchemaAttr { - doc: "".to_string(), - name: node_ref!( - ident.names.join("."), - assign.targets[0].pos() - ), - type_str, - ty: assign.ty, - op: Some(BinOrAugOp::Aug(AugOp::Assign)), - value: Some(assign.value), - is_optional: false, - decorators: Vec::new(), - }), - x.pos() - )); - continue; - } + let target = assign.targets[0].clone().node; + if assign.ty.is_some() { + body_body.push(node_ref!( + Stmt::SchemaAttr(SchemaAttr { + doc: "".to_string(), + name: node_ref!( + target.get_name().to_string(), + assign.targets[0].pos() + ), + ty: assign.ty.unwrap(), + op: Some(AugOp::Assign), + value: Some(assign.value), + is_optional: false, + decorators: Vec::new(), + }), + x.pos() + )); + continue; }; } } body_body.push(x); + } else { + // Error recovery from panic mode: Once an error is detected (the statement is None). + self.bump(); } + self.drop(marker); } // check_block let body_checks = self.parse_schema_check_block(); - - self.bump_token(TokenKind::Dedent); + self.validate_dedent(); + self.bump_token(TokenKind::Dedent(VALID_SPACES_LENGTH)); self.skip_newlines(); SchemaStmt { @@ -952,6 +1131,7 @@ impl<'a> Parser<'_> { index_signature: body_index_signature, name: Box::new(Node { + id: AstIndex::default(), node: "".to_string(), filename: "".to_string(), line: 0, @@ -982,12 +1162,13 @@ impl<'a> Parser<'_> { // NEWLINE _INDENT let has_newline = if self.token.kind == TokenKind::Newline { self.skip_newlines(); - - if self.token.kind == TokenKind::Indent { + if self.token.kind == TokenKind::Indent(VALID_SPACES_LENGTH) { self.bump(); } else { - self.sess - .struct_token_error(&[TokenKind::Indent.into()], self.token) + self.sess.struct_token_error( + &[TokenKind::Indent(VALID_SPACES_LENGTH).into()], + self.token, + ) } true } else { @@ -995,15 +1176,17 @@ impl<'a> Parser<'_> { }; loop { + let marker = self.mark(); + self.validate_dedent(); if matches!( self.token.kind, - TokenKind::CloseDelim(DelimToken::Bracket) | TokenKind::Dedent + TokenKind::CloseDelim(DelimToken::Bracket) | TokenKind::Dedent(VALID_SPACES_LENGTH) ) { break; } - let expr = self.parse_identifier_expr(); + let expr = self.parse_identifier(); let expr_pos = expr.pos(); - let ident = expr_as!(expr, Expr::Identifier).unwrap(); + let ident = expr.node; mixins.push(node_ref!(ident, expr_pos)); if let TokenKind::Comma = self.token.kind { self.bump(); @@ -1011,15 +1194,19 @@ impl<'a> Parser<'_> { if let TokenKind::Newline = self.token.kind { self.skip_newlines() } + self.drop(marker); } // _DEDENT if has_newline { - if self.token.kind == TokenKind::Dedent { + self.validate_dedent(); + if self.token.kind == TokenKind::Dedent(VALID_SPACES_LENGTH) { self.bump(); } else { - self.sess - .struct_token_error(&[TokenKind::Dedent.into()], self.token) + self.sess.struct_token_error( + &[TokenKind::Dedent(VALID_SPACES_LENGTH).into()], + self.token, + ) } } @@ -1030,7 +1217,7 @@ impl<'a> Parser<'_> { /// Syntax: /// schema_attribute_stmt: attribute_stmt NEWLINE - /// attribute_stmt: [decorators] identifier [QUESTION] COLON type [(ASSIGN|COMP_OR) test] + /// attribute_stmt: [decorators] (identifier | string) [QUESTION] COLON type [(ASSIGN|COMP_OR) test] fn parse_schema_attribute(&mut self) -> SchemaAttr { let doc = "".to_string(); @@ -1043,12 +1230,17 @@ impl<'a> Parser<'_> { Vec::new() }; - let name_expr = self.parse_identifier_expr(); - - let name_pos = name_expr.pos(); - let name = expr_as!(name_expr, Expr::Identifier).unwrap(); - let name = node_ref!(name.names.join("."), name_pos.clone()); + // Parse schema identifier-like or string-like attributes + let name = if let Some(name) = self.parse_string_attribute() { + name + } else { + let name_expr = self.parse_identifier(); + let name_pos = name_expr.pos(); + let name = name_expr.node; + node_ref!(name.get_names().join("."), name_pos) + }; + // Parse attribute optional annotation `?` let is_optional = if let TokenKind::Question = self.token.kind { self.bump_token(TokenKind::Question); true @@ -1056,17 +1248,18 @@ impl<'a> Parser<'_> { false }; + // Bump the schema attribute annotation token `:` self.bump_token(TokenKind::Colon); - let typ = self.parse_type_annotation(); - let type_str = node_ref!(typ.node.to_string(), name_pos); + // Parse the schema attribute type annotation. + let ty = self.parse_type_annotation(); let op = if self.token.kind == TokenKind::Assign { self.bump_token(TokenKind::Assign); - Some(BinOrAugOp::Aug(AugOp::Assign)) + Some(AugOp::Assign) } else if let TokenKind::BinOpEq(x) = self.token.kind { self.bump_token(self.token.kind); - Some(BinOrAugOp::Aug(x.into())) + Some(x.into()) } else { None }; @@ -1080,8 +1273,7 @@ impl<'a> Parser<'_> { SchemaAttr { doc, name, - type_str, - ty: Some(typ), + ty, op, value, is_optional, @@ -1095,105 +1287,74 @@ impl<'a> Parser<'_> { /// COLON type [ASSIGN test] NEWLINE fn parse_schema_index_signature_or_list( &mut self, - ) -> (Option, Option) { - //let mut list_elts: Vec> = Vec::new(); - let mut maybe_list_expr = true; - + ) -> (Option, Option>) { self.bump_token(TokenKind::OpenDelim(DelimToken::Bracket)); - let any_other = if let TokenKind::DotDotDot = self.token.kind { - maybe_list_expr = false; - self.bump(); - true - } else { - false + let peek_token_kind = match self.cursor.peek() { + Some(token) => token.kind, + None => TokenKind::Eof, }; + let peek2_token_kind = match self.cursor.peek2() { + Some(token) => token.kind, + None => TokenKind::Eof, + }; + match (self.token.kind, peek_token_kind) { + // Maybe a list expr or a list comp. + (TokenKind::Newline | TokenKind::CloseDelim(DelimToken::Bracket), _) => { + (None, Some(self.parse_list_expr(false))) + } + (TokenKind::Ident(_), _) + if !matches!(peek_token_kind, TokenKind::Colon) + && !matches!(peek2_token_kind, TokenKind::Colon) => + { + (None, Some(self.parse_list_expr(false))) + } + // Maybe a schema index signature. + (TokenKind::DotDotDot, _) if matches!(peek_token_kind, TokenKind::Ident(_)) => { + (Some(self.parse_schema_index_signature()), None) + } + (TokenKind::Ident(_), _) => (Some(self.parse_schema_index_signature()), None), + _ => (None, None), + } + } - self.skip_newlines(); - - let mut ident = None; - let (key_name, key_type, any_other) = if any_other { - let key_type = { - let typ = self.parse_type_annotation(); - node_ref!(typ.node.to_string(), typ.pos()) - }; - (None, key_type, any_other) + /// Syntax: + /// schema_index_signature: + /// LEFT_BRACKETS [NAME COLON] [ELLIPSIS] basic_type RIGHT_BRACKETS + /// COLON type [ASSIGN test] NEWLINE + fn parse_schema_index_signature(&mut self) -> SchemaIndexSignature { + let (key_name, key_ty, any_other) = if matches!(self.token.kind, TokenKind::DotDotDot) { + // bump token `...` + self.bump(); + (None, self.parse_type_annotation(), true) } else { - if maybe_list_expr && !matches!(self.token.kind, TokenKind::Ident(_)) { - let list_expr = ListExpr { - elts: self.parse_list_items(), - ctx: ExprContext::Load, - }; - - self.bump_token(TokenKind::CloseDelim(DelimToken::Bracket)); - return (None, Some(list_expr)); - } + let token = self.token; + let expr = self.parse_identifier_expr(); + let ident = self.expr_as_identifier(expr.clone(), token); + let pos = expr.pos(); + let key_name = ident.get_names().join("."); - ident = Some(self.parse_identifier_expr()); if let TokenKind::CloseDelim(DelimToken::Bracket) = self.token.kind { - let key_type = { - let pos = ident.clone().unwrap().pos(); - let ident_node = expr_as!(ident.clone().unwrap(), Expr::Identifier).unwrap(); - let typ = node_ref!(Type::Named(ident_node), pos); - node_ref!(typ.node.to_string(), typ.pos()) - }; - (None, key_type, false) + (None, node_ref!(Type::Named(ident), pos), false) } else { - maybe_list_expr = false; - self.bump_token(TokenKind::Colon); - let ident = expr_as!(ident.clone().unwrap(), Expr::Identifier).unwrap(); - let key_name = ident.names.join("."); let any_other = if let TokenKind::DotDotDot = self.token.kind { self.bump(); true } else { false }; - let key_type = { - let typ = self.parse_type_annotation(); - node_ref!(typ.node.to_string(), typ.pos()) - }; - (Some(key_name), key_type, any_other) + ( + Some(node_ref!(key_name, pos)), + self.parse_type_annotation(), + any_other, + ) } }; - if maybe_list_expr && !matches!(self.token.kind, TokenKind::CloseDelim(DelimToken::Bracket)) - { - let mut list_expr = ListExpr { - elts: vec![ident.unwrap()], - ctx: ExprContext::Load, - }; - - if let TokenKind::Comma = self.token.kind { - self.bump(); - } - - list_expr.elts.extend(self.parse_list_items()); - - self.bump_token(TokenKind::CloseDelim(DelimToken::Bracket)); - return (None, Some(list_expr)); - } - self.bump_token(TokenKind::CloseDelim(DelimToken::Bracket)); - - // must list - if maybe_list_expr { - if let TokenKind::Newline = self.token.kind { - let mut list_expr = ListExpr { - elts: vec![ident.unwrap()], - ctx: ExprContext::Load, - }; - list_expr.elts.extend(self.parse_list_items()); - - self.bump_token(TokenKind::CloseDelim(DelimToken::Bracket)); - return (None, Some(list_expr)); - } - } - self.bump_token(TokenKind::Colon); - let typ = self.parse_type_annotation(); - let value_type = node_ref!(typ.node.to_string(), typ.pos()); + let value_ty = self.parse_type_annotation(); let value = if let TokenKind::Assign = self.token.kind { self.bump(); @@ -1204,16 +1365,13 @@ impl<'a> Parser<'_> { self.skip_newlines(); - let index_sig = SchemaIndexSignature { + SchemaIndexSignature { key_name, - key_type, - value_type, - value_ty: Some(typ), + key_ty, + value_ty, value, any_other, - }; - - (Some(index_sig), None) + } } /// Syntax: @@ -1226,16 +1384,25 @@ impl<'a> Parser<'_> { self.bump_keyword(kw::Check); self.bump_token(TokenKind::Colon); self.skip_newlines(); + self.bump_token(TokenKind::Indent(VALID_SPACES_LENGTH)); + while self.token.kind != TokenKind::Dedent(VALID_SPACES_LENGTH) { + let marker = self.mark(); + if matches!(self.token.kind, TokenKind::Eof) { + self.sess + .struct_token_error(&[TokenKind::Newline.into()], self.token); + break; + } - self.bump_token(TokenKind::Indent); - while self.token.kind != TokenKind::Dedent { let expr = self.parse_check_expr(); let expr_pos = expr.pos(); let check_expr = expr_as!(expr, Expr::Check).unwrap(); check_expr_list.push(node_ref!(check_expr, expr_pos)); + self.skip_newlines(); + self.drop(marker); } - self.bump_token(TokenKind::Dedent); + self.validate_dedent(); + self.bump_token(TokenKind::Dedent(VALID_SPACES_LENGTH)); } check_expr_list @@ -1244,10 +1411,7 @@ impl<'a> Parser<'_> { /// Syntax: /// rule_stmt: [decorators] RULE NAME [LEFT_BRACKETS [schema_arguments] RIGHT_BRACKETS] [LEFT_PARENTHESES identifier (COMMA identifier)* RIGHT_PARENTHESES] [for_host] COLON NEWLINE [rule_body] /// rule_body: _INDENT (string NEWLINE)* check_expr+ _DEDENT - fn parse_rule_stmt( - &mut self, - decorators: Option>>, - ) -> Option> { + fn parse_rule_stmt(&mut self, decorators: Option>>) -> NodeRef { let token = self.token; self.bump_keyword(kw::Rule); @@ -1260,7 +1424,7 @@ impl<'a> Parser<'_> { let name_expr = self.parse_identifier_expr(); let name_pos = name_expr.pos(); let name = expr_as!(name_expr, Expr::Identifier).unwrap(); - let name = node_ref!(name.names.join("."), name_pos); + let name = node_ref!(name.get_names().join("."), name_pos); let args = if let TokenKind::OpenDelim(DelimToken::Bracket) = self.token.kind { self.parse_parameters( @@ -1280,18 +1444,53 @@ impl<'a> Parser<'_> { self.bump(); break; } + + if matches!(self.token.kind, TokenKind::Newline | TokenKind::Eof) { + self.sess.struct_token_error( + &[ + TokenKind::CloseDelim(DelimToken::Paren).into(), + TokenKind::Comma.into(), + ], + self.token, + ); + break; + } + + let token = self.token; let expr = self.parse_expr(); let expr_pos = expr.pos(); - let rule_name = expr_as!(expr, Expr::Identifier).unwrap(); + let rule_name = self.expr_as_identifier(expr, token); parent_rules.push(node_ref!(rule_name, expr_pos)); + + if !matches!( + self.token.kind, + TokenKind::Comma + | TokenKind::CloseDelim(DelimToken::Paren) + | TokenKind::Newline + | TokenKind::Eof + ) { + self.sess.struct_token_error( + &[ + TokenKind::Comma.into(), + TokenKind::CloseDelim(DelimToken::Paren).into(), + ], + self.token, + ); + self.bump(); + } + + if matches!(self.token.kind, TokenKind::Comma) { + self.bump() + } } } let for_host_name = if self.token.is_keyword(kw::For) { self.bump_keyword(kw::For); + let token = self.token; let expr = self.parse_expr(); let expr_pos = expr.pos(); - let ident = expr_as!(expr, Expr::Identifier).unwrap(); + let ident = self.expr_as_identifier(expr, token); Some(node_ref!(ident, expr_pos)) } else { None @@ -1299,40 +1498,35 @@ impl<'a> Parser<'_> { self.bump_token(TokenKind::Colon); self.skip_newlines(); - - self.bump_token(TokenKind::Indent); + self.bump_token(TokenKind::Indent(VALID_SPACES_LENGTH)); // doc string - let body_doc = match self.token.kind { - TokenKind::Literal(lit) => { - if let LitKind::Str { .. } = lit.kind { - let doc_expr = self.parse_str_expr(lit); - self.skip_newlines(); - match &doc_expr.node { - Expr::StringLit(str) => str.raw_value.clone(), - Expr::JoinedString(str) => str.raw_value.clone(), - _ => "".to_string(), - } - } else { - "".to_string() - } - } - _ => "".to_string(), - }; + let body_doc = self.parse_doc(); let mut check_expr_list = vec![]; - while self.token.kind != TokenKind::Dedent { + self.validate_dedent(); + while self.token.kind != TokenKind::Dedent(VALID_SPACES_LENGTH) { + let marker = self.mark(); + if matches!(self.token.kind, TokenKind::Eof) { + self.sess + .struct_token_error(&[TokenKind::Newline.into()], self.token); + break; + } + let expr = self.parse_check_expr(); let expr_pos = expr.pos(); let check_expr = expr_as!(expr, Expr::Check).unwrap(); check_expr_list.push(node_ref!(check_expr, expr_pos)); + self.skip_newlines(); + self.drop(marker); } - self.bump_token(TokenKind::Dedent); + self.validate_dedent(); + self.bump_token(TokenKind::Dedent(VALID_SPACES_LENGTH)); let pos = self.token_span_pos(token, self.prev_token); - Some(node_ref!( + node_ref!( Stmt::Rule(RuleStmt { doc: body_doc, name, @@ -1343,27 +1537,40 @@ impl<'a> Parser<'_> { for_host_name, }), pos - )) + ) + } + + pub(crate) fn parse_string_attribute(&mut self) -> Option> { + match self.token.kind { + TokenKind::Literal(lit) => { + if let LitKind::Str { .. } = lit.kind { + let str_expr = self.parse_str_expr(lit); + match &str_expr.node { + Expr::StringLit(str) => Some(node_ref!(str.value.clone(), str_expr.pos())), + _ => None, + } + } else { + None + } + } + _ => None, + } } pub(crate) fn parse_joined_string( &mut self, s: &StringLit, - pos: rustc_span::BytePos, + pos: BytePos, ) -> Option { // skip raw string - if s.raw_value.starts_with(&['r', 'R']) { + if s.raw_value.starts_with(['r', 'R']) { return None; } if !s.value.contains("${") { return None; } - let start_pos = if s.is_long_string { - pos + rustc_span::BytePos(3) - } else { - pos + rustc_span::BytePos(1) - }; + let quote_space = if s.is_long_string { 3 } else { 1 }; let mut joined_value = JoinedString { is_long_string: s.is_long_string, @@ -1371,22 +1578,21 @@ impl<'a> Parser<'_> { values: Vec::new(), }; - fn parse_expr( - this: &mut Parser, - src: &str, - start_pos: rustc_span::BytePos, - ) -> NodeRef { + fn parse_expr(this: &mut Parser, src: &str, start_pos: BytePos) -> NodeRef { use crate::lexer::parse_token_streams; - - debug_assert!(src.starts_with("${"), "{}", src); - debug_assert!(src.ends_with('}'), "{}", src); - + // The string interpolation end pos. + let end_pos = start_pos + new_byte_pos(src.len() as u32); + // Skip the start '${' and end '}' let src = &src[2..src.len() - 1]; if src.is_empty() { - panic!("string interpolation expression can not be empty") + this.sess.struct_message_error( + ParseErrorMessage::InvalidStringInterpolationExpr("".to_string()), + Span::new(start_pos, end_pos), + ); } - let start_pos = start_pos + rustc_span::BytePos(2); + // Expression start pos, and skip the start '${'. + let start_pos = start_pos + new_byte_pos(2); let stream = parse_token_streams(this.sess, src, start_pos); @@ -1401,7 +1607,6 @@ impl<'a> Parser<'_> { // bump to the first token parser.bump(); - let _token = parser.token; let expr = parser.parse_expr(); let mut formatted_value = FormattedValue { @@ -1411,61 +1616,128 @@ impl<'a> Parser<'_> { }; if let TokenKind::Colon = parser.token.kind { + // bump the format spec interval token `:`. parser.bump(); - if let TokenKind::DocComment(_) = parser.token.kind { - let format_spec = parser - .sess - .source_map - .span_to_snippet(parser.token.span) - .unwrap(); - formatted_value.format_spec = Some(format_spec); + if let TokenKind::DocComment(CommentKind::Line(symbol)) = parser.token.kind { + formatted_value.format_spec = Some(symbol.as_str()); } else { - panic!("invalid joined string spec"); + this.sess.struct_message_error( + ParseErrorMessage::InvalidJoinedStringSpec, + parser.token.span, + ); } + // Whether there is syntax error or not, bump the joined string spec token. + parser.bump(); } - node_ref!(Expr::FormattedValue(formatted_value)) + // The token pair (lo, hi). + let lo = start_pos; + let hi = start_pos + new_byte_pos(src.len() as u32); + // Bump the expression endline. + parser.skip_newlines(); + // If there are still remaining tokens, it indicates that an + // unexpected expression has occurred here. + if !src.is_empty() && parser.has_next() { + parser.sess.struct_message_error( + ParseErrorMessage::InvalidStringInterpolationExpr(src.to_string()), + Span::new(lo, hi), + ) + } + + node_ref!( + Expr::FormattedValue(formatted_value), + parser.byte_pos_to_pos(lo, hi) + ) } + // Here we use double pointers of data and raw_data, + // where data is used to obtain string literal data + // and raw_data is used to obtain string interpolation + // data to ensure that their respective positional + // information is correct. + let data = s.value.as_str(); - let mut off: usize = 0; + let raw_data = s.raw_value.as_str(); + let raw_data = &s.raw_value.as_str()[..raw_data.len() - quote_space]; + let mut data_off = 0; + let mut raw_off: usize = quote_space; loop { - if let Some(i) = data[off..].find("${") { - if let Some(j) = data[off + i..].find('}') { - let lo: usize = off + i; - let hi: usize = off + i + j + 1; - - let s0 = &data[off..lo]; - let s1 = &data[lo..hi]; - - let s0_expr = node_ref!(Expr::StringLit(StringLit { - is_long_string: false, - raw_value: s0.to_string(), - value: s0.to_string().replace("$$", "$"), - })); - - let s1_expr = parse_expr(self, s1, start_pos + rustc_span::BytePos(lo as u32)); - - joined_value.values.push(s0_expr); - joined_value.values.push(s1_expr); - - off = hi; + if raw_off >= raw_data.len() || data_off >= data.len() { + break; + } + if let (Some(raw_i), Some(data_i)) = + (raw_data[raw_off..].find("${"), data[data_off..].find("${")) + { + if let (Some(raw_j), Some(data_j)) = ( + raw_data[raw_off + raw_i..].find('}'), + data[data_off + data_i..].find('}'), + ) { + let raw_lo: usize = raw_off + raw_i; + let raw_hi: usize = raw_off + raw_i + raw_j + 1; + + let data_lo: usize = data_off + data_i; + let data_hi: usize = data_off + data_i + data_j + 1; + + let s0 = &data[data_off..data_lo]; + let s0_raw = &raw_data[raw_off..raw_lo]; + let s1_raw = &raw_data[raw_lo..raw_hi]; + + // Handling \${} Escapes + let is_escape = !s0_raw.is_empty() && &s0_raw[s0_raw.len() - 1..] == "\\"; + if is_escape { + let s_raw = &raw_data[raw_off..raw_hi]; + let s = &data[data_off..data_hi].replace("\\$", "$"); + joined_value + .values + .push(node_ref!(Expr::StringLit(StringLit { + is_long_string: false, + raw_value: s_raw.to_string(), + value: s.to_string(), + }))); + } else { + if !s0.is_empty() { + joined_value + .values + .push(node_ref!(Expr::StringLit(StringLit { + is_long_string: false, + raw_value: s0_raw.to_string(), + value: s0.to_string(), + }))); + } + joined_value.values.push(parse_expr( + self, + s1_raw, + pos + new_byte_pos(raw_lo as u32), + )); + } + data_off = data_hi; + raw_off = raw_hi; continue; } else { - panic!("invalid joined string"); + self.sess.struct_message_error( + ParseErrorMessage::InvalidJoinedStringExpr, + self.token.span, + ); + joined_value + .values + .push(node_ref!(Expr::StringLit(StringLit { + is_long_string: false, + raw_value: raw_data[raw_off..].to_string(), + value: data[data_off..].to_string(), + }))); + break; } } else { - if off >= s.value.as_str().len() { + if raw_off >= raw_data.len() || data_off >= data.len() { break; } - // todo: fix pos joined_value .values .push(node_ref!(Expr::StringLit(StringLit { is_long_string: false, - raw_value: data[off..].to_string(), - value: data[off..].to_string().replace("$$", "$"), + raw_value: raw_data[raw_off..].to_string(), + value: data[data_off..].to_string(), }))); break; } diff --git a/kclvm/parser/src/parser/tests.rs b/kclvm/parser/src/parser/tests.rs index 4fb219d7e..6315e36b7 100644 --- a/kclvm/parser/src/parser/tests.rs +++ b/kclvm/parser/src/parser/tests.rs @@ -1,1139 +1,18 @@ -use crate::lexer::parse_token_streams; -use crate::parser::Parser; -use crate::session::ParseSession; -use expect_test::{expect, Expect}; -use kclvm_ast::ast::*; -use kclvm_span::{create_session_globals_then, BytePos, FilePathMapping, SourceMap}; -use rustc_span::Pos; -use std::path::PathBuf; -use std::sync::Arc; - -fn check_parsing_expr(src: &str, expect: Expect) { - let sm = SourceMap::new(FilePathMapping::empty()); - sm.new_source_file(PathBuf::from("").into(), src.to_string()); - let sess = &ParseSession::with_source_map(Arc::new(sm)); - - create_session_globals_then(|| { - let stream = parse_token_streams(sess, src, BytePos::from_u32(0)); - let mut parser = Parser::new(sess, stream); - let expr = parser.parse_expr(); - let actual = format!("{:?}\n", expr); - expect.assert_eq(&actual) - }); -} - -fn check_parsing_file_ast_json(filename: &str, src: &str, expect: Expect) { - let m = crate::parse_file(filename, Some(src.into())).unwrap(); - let actual = serde_json::ser::to_string(&m).unwrap(); - let actual = format!("{}\n", actual); - expect.assert_eq(&actual) -} - -fn check_parsing_type(src: &str, expect: Expect) { - let sm = SourceMap::new(FilePathMapping::empty()); - sm.new_source_file(PathBuf::from("").into(), src.to_string()); - let sess = &ParseSession::with_source_map(Arc::new(sm)); - - create_session_globals_then(|| { - let stream = parse_token_streams(sess, src, BytePos::from_u32(0)); - let mut parser = Parser::new(sess, stream); - let typ = parser.parse_type_annotation(); - let actual = format!("{:?}\n", typ); - expect.assert_eq(&actual) - }); -} - -fn check_type_str(src: &str, expect: Expect) { - let sm = SourceMap::new(FilePathMapping::empty()); - sm.new_source_file(PathBuf::from("").into(), src.to_string()); - let sess = &ParseSession::with_source_map(Arc::new(sm)); - - create_session_globals_then(|| { - let stream = parse_token_streams(sess, src, BytePos::from_u32(0)); - let mut parser = Parser::new(sess, stream); - let typ = parser.parse_type_annotation(); - let actual = typ.node.to_string(); - expect.assert_eq(&actual) - }); -} - -fn check_type_stmt(src: &str, expect: Expect) { - let sm = SourceMap::new(FilePathMapping::empty()); - sm.new_source_file(PathBuf::from("").into(), src.to_string()); - let sess = &ParseSession::with_source_map(Arc::new(sm)); - - create_session_globals_then(|| { - let stream = parse_token_streams(sess, src, BytePos::from_u32(0)); - let mut parser = Parser::new(sess, stream); - let stmt = parser.parse_stmt().unwrap(); - let actual = format!("{:?}\n", stmt); - expect.assert_eq(&actual) - }); -} - -fn check_parsing_module(filename: &str, src: &str, expect: &str) { - let m = crate::parse_file(filename, Some(src.to_string())).unwrap(); - let actual = format!("{}\n", serde_json::ser::to_string(&m).unwrap()); - assert_eq!(actual, expect); -} - -#[test] -fn smoke_test_parsing_expr() { - check_parsing_expr( - "1\n", - expect![[r#" - Node { node: NumberLit(NumberLit { binary_suffix: None, value: Int(1) }), filename: "", line: 1, column: 0, end_line: 1, end_column: 1 } - "#]], - ); - check_parsing_expr( - "\"1\"\n", - expect![[r#" - Node { node: StringLit(StringLit { is_long_string: false, raw_value: "\"1\"", value: "1" }), filename: "", line: 1, column: 0, end_line: 1, end_column: 3 } - "#]], - ); -} - -#[test] -fn named_literal_expr() { - check_parsing_expr( - r####"Undefined"####, - expect![[r#" - Node { node: NameConstantLit(NameConstantLit { value: Undefined }), filename: "", line: 1, column: 0, end_line: 1, end_column: 9 } - "#]], - ); - check_parsing_expr( - r####"None"####, - expect![[r#" - Node { node: NameConstantLit(NameConstantLit { value: None }), filename: "", line: 1, column: 0, end_line: 1, end_column: 4 } - "#]], - ); - ( - r####"True"####, - expect![[r#" - Node { node: NameConstantLit(NameConstantLit { value: True }), filename: "", line: 1, column: 1, end_line: 1, end_column: 1 } - "#]], - ); - check_parsing_expr( - r####"False"####, - expect![[r#" - Node { node: NameConstantLit(NameConstantLit { value: False }), filename: "", line: 1, column: 0, end_line: 1, end_column: 5 } - "#]], - ); -} - -#[test] -fn nonstring_literal_expr() { - check_parsing_expr( - r####"1234"####, - expect![[r#" - Node { node: NumberLit(NumberLit { binary_suffix: None, value: Int(1234) }), filename: "", line: 1, column: 0, end_line: 1, end_column: 4 } - "#]], - ) -} - -#[test] -fn string_literal_expr_0() { - check_parsing_expr( - r####"'1234'"####, - expect![[r#" - Node { node: StringLit(StringLit { is_long_string: false, raw_value: "'1234'", value: "1234" }), filename: "", line: 1, column: 0, end_line: 1, end_column: 6 } - "#]], - ) -} - -#[test] -fn string_literal_expr_1() { - check_parsing_expr( - r####""1234""####, - expect![[r#" - Node { node: StringLit(StringLit { is_long_string: false, raw_value: "\"1234\"", value: "1234" }), filename: "", line: 1, column: 0, end_line: 1, end_column: 6 } - "#]], - ) -} - -#[test] -fn string_literal_expr_2() { - check_parsing_expr( - r####""1234\n""####, - expect![[r#" - Node { node: StringLit(StringLit { is_long_string: false, raw_value: "\"1234\\n\"", value: "1234\n" }), filename: "", line: 1, column: 0, end_line: 1, end_column: 8 } - "#]], - ) -} - -#[test] -fn number_bin_suffix_expr() { - check_parsing_expr( - r####"1234Ki"####, - expect![[r#" - Node { node: NumberLit(NumberLit { binary_suffix: Some(Ki), value: Int(1234) }), filename: "", line: 1, column: 0, end_line: 1, end_column: 6 } - "#]], - ) -} - -#[test] -fn unary_expr() { - check_parsing_expr( - r####"+1"####, - expect![[r#" - Node { node: Unary(UnaryExpr { op: UAdd, operand: Node { node: NumberLit(NumberLit { binary_suffix: None, value: Int(1) }), filename: "", line: 1, column: 1, end_line: 1, end_column: 2 } }), filename: "", line: 1, column: 0, end_line: 1, end_column: 2 } - "#]], - ); -} - -#[test] -fn binary_expr_0() { - check_parsing_expr( - r####"1+2+3"####, - expect![[r#" - Node { node: Binary(BinaryExpr { left: Node { node: Binary(BinaryExpr { left: Node { node: NumberLit(NumberLit { binary_suffix: None, value: Int(1) }), filename: "", line: 1, column: 0, end_line: 1, end_column: 1 }, op: Bin(Add), right: Node { node: NumberLit(NumberLit { binary_suffix: None, value: Int(2) }), filename: "", line: 1, column: 2, end_line: 1, end_column: 3 } }), filename: "", line: 1, column: 0, end_line: 1, end_column: 3 }, op: Bin(Add), right: Node { node: NumberLit(NumberLit { binary_suffix: None, value: Int(3) }), filename: "", line: 1, column: 4, end_line: 1, end_column: 5 } }), filename: "", line: 1, column: 0, end_line: 1, end_column: 5 } - "#]], - ); -} - -#[test] -fn binary_expr_1() { - check_parsing_expr( - r####"1+2*3-4"####, - expect![[r#" - Node { node: Binary(BinaryExpr { left: Node { node: Binary(BinaryExpr { left: Node { node: NumberLit(NumberLit { binary_suffix: None, value: Int(1) }), filename: "", line: 1, column: 0, end_line: 1, end_column: 1 }, op: Bin(Add), right: Node { node: Binary(BinaryExpr { left: Node { node: NumberLit(NumberLit { binary_suffix: None, value: Int(2) }), filename: "", line: 1, column: 2, end_line: 1, end_column: 3 }, op: Bin(Mul), right: Node { node: NumberLit(NumberLit { binary_suffix: None, value: Int(3) }), filename: "", line: 1, column: 4, end_line: 1, end_column: 5 } }), filename: "", line: 1, column: 2, end_line: 1, end_column: 5 } }), filename: "", line: 1, column: 0, end_line: 1, end_column: 5 }, op: Bin(Sub), right: Node { node: NumberLit(NumberLit { binary_suffix: None, value: Int(4) }), filename: "", line: 1, column: 6, end_line: 1, end_column: 7 } }), filename: "", line: 1, column: 0, end_line: 1, end_column: 7 } - "#]], - ); -} - -#[test] -fn binary_expr_2() { - check_parsing_expr( - r####"1+2*3/4"####, - expect![[r#" - Node { node: Binary(BinaryExpr { left: Node { node: NumberLit(NumberLit { binary_suffix: None, value: Int(1) }), filename: "", line: 1, column: 0, end_line: 1, end_column: 1 }, op: Bin(Add), right: Node { node: Binary(BinaryExpr { left: Node { node: Binary(BinaryExpr { left: Node { node: NumberLit(NumberLit { binary_suffix: None, value: Int(2) }), filename: "", line: 1, column: 2, end_line: 1, end_column: 3 }, op: Bin(Mul), right: Node { node: NumberLit(NumberLit { binary_suffix: None, value: Int(3) }), filename: "", line: 1, column: 4, end_line: 1, end_column: 5 } }), filename: "", line: 1, column: 2, end_line: 1, end_column: 5 }, op: Bin(Div), right: Node { node: NumberLit(NumberLit { binary_suffix: None, value: Int(4) }), filename: "", line: 1, column: 6, end_line: 1, end_column: 7 } }), filename: "", line: 1, column: 2, end_line: 1, end_column: 7 } }), filename: "", line: 1, column: 0, end_line: 1, end_column: 7 } - "#]], - ); -} - -#[test] -fn binary_expr_3() { - check_parsing_expr( - r####"a or b"####, - expect![[r#" - Node { node: Binary(BinaryExpr { left: Node { node: Identifier(Identifier { names: ["a"], pkgpath: "", ctx: Load }), filename: "", line: 1, column: 0, end_line: 1, end_column: 1 }, op: Bin(Or), right: Node { node: Identifier(Identifier { names: ["b"], pkgpath: "", ctx: Load }), filename: "", line: 1, column: 5, end_line: 1, end_column: 6 } }), filename: "", line: 1, column: 0, end_line: 1, end_column: 6 } - "#]], - ); -} - -#[test] -fn binary_expr_4() { - check_parsing_expr( - r####"x == a or b"####, - expect![[r#" - Node { node: Binary(BinaryExpr { left: Node { node: Compare(Compare { left: Node { node: Identifier(Identifier { names: ["x"], pkgpath: "", ctx: Load }), filename: "", line: 1, column: 0, end_line: 1, end_column: 1 }, ops: [Eq], comparators: [Node { node: Identifier(Identifier { names: ["a"], pkgpath: "", ctx: Load }), filename: "", line: 1, column: 5, end_line: 1, end_column: 6 }] }), filename: "", line: 1, column: 0, end_line: 1, end_column: 11 }, op: Bin(Or), right: Node { node: Identifier(Identifier { names: ["b"], pkgpath: "", ctx: Load }), filename: "", line: 1, column: 10, end_line: 1, end_column: 11 } }), filename: "", line: 1, column: 0, end_line: 1, end_column: 11 } - "#]], - ); - check_parsing_expr( - r####"22 > 11 and 111 < 222"####, - expect![[r#" - Node { node: Binary(BinaryExpr { left: Node { node: Compare(Compare { left: Node { node: NumberLit(NumberLit { binary_suffix: None, value: Int(22) }), filename: "", line: 1, column: 0, end_line: 1, end_column: 2 }, ops: [Gt], comparators: [Node { node: NumberLit(NumberLit { binary_suffix: None, value: Int(11) }), filename: "", line: 1, column: 5, end_line: 1, end_column: 7 }] }), filename: "", line: 1, column: 0, end_line: 1, end_column: 21 }, op: Bin(And), right: Node { node: Compare(Compare { left: Node { node: NumberLit(NumberLit { binary_suffix: None, value: Int(111) }), filename: "", line: 1, column: 12, end_line: 1, end_column: 15 }, ops: [Lt], comparators: [Node { node: NumberLit(NumberLit { binary_suffix: None, value: Int(222) }), filename: "", line: 1, column: 18, end_line: 1, end_column: 21 }] }), filename: "", line: 1, column: 12, end_line: 1, end_column: 21 } }), filename: "", line: 1, column: 0, end_line: 1, end_column: 21 } - "#]], - ); - check_parsing_expr( - r####"int(e.value) > 1 and i == 0"####, - expect![[r#" - Node { node: Binary(BinaryExpr { left: Node { node: Compare(Compare { left: Node { node: Call(CallExpr { func: Node { node: Identifier(Identifier { names: ["int"], pkgpath: "", ctx: Load }), filename: "", line: 1, column: 0, end_line: 1, end_column: 3 }, args: [Node { node: Identifier(Identifier { names: ["e", "value"], pkgpath: "", ctx: Load }), filename: "", line: 1, column: 4, end_line: 1, end_column: 11 }], keywords: [] }), filename: "", line: 1, column: 0, end_line: 1, end_column: 12 }, ops: [Gt], comparators: [Node { node: NumberLit(NumberLit { binary_suffix: None, value: Int(1) }), filename: "", line: 1, column: 15, end_line: 1, end_column: 16 }] }), filename: "", line: 1, column: 0, end_line: 1, end_column: 27 }, op: Bin(And), right: Node { node: Compare(Compare { left: Node { node: Identifier(Identifier { names: ["i"], pkgpath: "", ctx: Load }), filename: "", line: 1, column: 21, end_line: 1, end_column: 22 }, ops: [Eq], comparators: [Node { node: NumberLit(NumberLit { binary_suffix: None, value: Int(0) }), filename: "", line: 1, column: 26, end_line: 1, end_column: 27 }] }), filename: "", line: 1, column: 21, end_line: 1, end_column: 27 } }), filename: "", line: 1, column: 0, end_line: 1, end_column: 27 } - "#]], - ); - check_parsing_expr( - r####"key in ['key']"####, - expect![[r#" - Node { node: Compare(Compare { left: Node { node: Identifier(Identifier { names: ["key"], pkgpath: "", ctx: Load }), filename: "", line: 1, column: 0, end_line: 1, end_column: 3 }, ops: [In], comparators: [Node { node: List(ListExpr { elts: [Node { node: StringLit(StringLit { is_long_string: false, raw_value: "'key'", value: "key" }), filename: "", line: 1, column: 8, end_line: 1, end_column: 13 }], ctx: Load }), filename: "", line: 1, column: 7, end_line: 1, end_column: 14 }] }), filename: "", line: 1, column: 0, end_line: 1, end_column: 14 } - "#]], - ); - check_parsing_expr( - r####"key not in ['key']"####, - expect![[r#" - Node { node: Compare(Compare { left: Node { node: Identifier(Identifier { names: ["key"], pkgpath: "", ctx: Load }), filename: "", line: 1, column: 0, end_line: 1, end_column: 3 }, ops: [NotIn], comparators: [Node { node: List(ListExpr { elts: [Node { node: StringLit(StringLit { is_long_string: false, raw_value: "'key'", value: "key" }), filename: "", line: 1, column: 12, end_line: 1, end_column: 17 }], ctx: Load }), filename: "", line: 1, column: 11, end_line: 1, end_column: 18 }] }), filename: "", line: 1, column: 0, end_line: 1, end_column: 18 } - "#]], - ); - - check_parsing_expr( - r####"1 is 1 and 11 is not 22"####, - expect![[r#" - Node { node: Binary(BinaryExpr { left: Node { node: Compare(Compare { left: Node { node: NumberLit(NumberLit { binary_suffix: None, value: Int(1) }), filename: "", line: 1, column: 0, end_line: 1, end_column: 1 }, ops: [Is], comparators: [Node { node: NumberLit(NumberLit { binary_suffix: None, value: Int(1) }), filename: "", line: 1, column: 5, end_line: 1, end_column: 6 }] }), filename: "", line: 1, column: 0, end_line: 1, end_column: 23 }, op: Bin(And), right: Node { node: Compare(Compare { left: Node { node: NumberLit(NumberLit { binary_suffix: None, value: Int(11) }), filename: "", line: 1, column: 11, end_line: 1, end_column: 13 }, ops: [IsNot], comparators: [Node { node: NumberLit(NumberLit { binary_suffix: None, value: Int(22) }), filename: "", line: 1, column: 21, end_line: 1, end_column: 23 }] }), filename: "", line: 1, column: 11, end_line: 1, end_column: 23 } }), filename: "", line: 1, column: 0, end_line: 1, end_column: 23 } - "#]], - ); -} - -#[test] -fn binary_expr_5() { - check_parsing_expr( - r####"1 + a and b"####, - expect![[r#" - Node { node: Binary(BinaryExpr { left: Node { node: Binary(BinaryExpr { left: Node { node: NumberLit(NumberLit { binary_suffix: None, value: Int(1) }), filename: "", line: 1, column: 0, end_line: 1, end_column: 1 }, op: Bin(Add), right: Node { node: Identifier(Identifier { names: ["a"], pkgpath: "", ctx: Load }), filename: "", line: 1, column: 4, end_line: 1, end_column: 5 } }), filename: "", line: 1, column: 0, end_line: 1, end_column: 5 }, op: Bin(And), right: Node { node: Identifier(Identifier { names: ["b"], pkgpath: "", ctx: Load }), filename: "", line: 1, column: 10, end_line: 1, end_column: 11 } }), filename: "", line: 1, column: 0, end_line: 1, end_column: 11 } - "#]], - ); -} - -#[test] -fn binary_expr_with_paren() { - check_parsing_expr( - r####"1*(2+3)-4"####, - expect![[r#" - Node { node: Binary(BinaryExpr { left: Node { node: Binary(BinaryExpr { left: Node { node: NumberLit(NumberLit { binary_suffix: None, value: Int(1) }), filename: "", line: 1, column: 0, end_line: 1, end_column: 1 }, op: Bin(Mul), right: Node { node: Paren(ParenExpr { expr: Node { node: Binary(BinaryExpr { left: Node { node: NumberLit(NumberLit { binary_suffix: None, value: Int(2) }), filename: "", line: 1, column: 3, end_line: 1, end_column: 4 }, op: Bin(Add), right: Node { node: NumberLit(NumberLit { binary_suffix: None, value: Int(3) }), filename: "", line: 1, column: 5, end_line: 1, end_column: 6 } }), filename: "", line: 1, column: 3, end_line: 1, end_column: 6 } }), filename: "", line: 1, column: 2, end_line: 1, end_column: 7 } }), filename: "", line: 1, column: 0, end_line: 1, end_column: 7 }, op: Bin(Sub), right: Node { node: NumberLit(NumberLit { binary_suffix: None, value: Int(4) }), filename: "", line: 1, column: 8, end_line: 1, end_column: 9 } }), filename: "", line: 1, column: 0, end_line: 1, end_column: 9 } - "#]], - ); -} - -#[test] -fn if_expr() { - check_parsing_expr( - r####"1 if true else 2"####, - expect![[r#" - Node { node: If(IfExpr { body: Node { node: NumberLit(NumberLit { binary_suffix: None, value: Int(1) }), filename: "", line: 1, column: 0, end_line: 1, end_column: 1 }, cond: Node { node: Identifier(Identifier { names: ["true"], pkgpath: "", ctx: Load }), filename: "", line: 1, column: 5, end_line: 1, end_column: 9 }, orelse: Node { node: NumberLit(NumberLit { binary_suffix: None, value: Int(2) }), filename: "", line: 1, column: 15, end_line: 1, end_column: 16 } }), filename: "", line: 1, column: 2, end_line: 1, end_column: 16 } - "#]], - ); -} - -#[test] -fn primary_expr_0() { - check_parsing_expr( - r####"a.b.c"####, - expect![[r#" - Node { node: Identifier(Identifier { names: ["a", "b", "c"], pkgpath: "", ctx: Load }), filename: "", line: 1, column: 0, end_line: 1, end_column: 5 } - "#]], - ); -} - -#[test] -fn primary_expr_1() { - check_parsing_expr( - r####"'{}'.format(1)"####, - expect![[r#" - Node { node: Call(CallExpr { func: Node { node: Selector(SelectorExpr { value: Node { node: StringLit(StringLit { is_long_string: false, raw_value: "'{}'", value: "{}" }), filename: "", line: 1, column: 0, end_line: 1, end_column: 4 }, attr: Node { node: Identifier { names: ["format"], pkgpath: "", ctx: Load }, filename: "", line: 1, column: 5, end_line: 1, end_column: 11 }, ctx: Load, has_question: false }), filename: "", line: 1, column: 4, end_line: 1, end_column: 11 }, args: [Node { node: NumberLit(NumberLit { binary_suffix: None, value: Int(1) }), filename: "", line: 1, column: 12, end_line: 1, end_column: 13 }], keywords: [] }), filename: "", line: 1, column: 11, end_line: 1, end_column: 14 } - "#]], - ); -} - -#[test] -fn primary_expr_2() { - check_parsing_expr( - r####"str(1).isdigit()"####, - expect![[r#" - Node { node: Call(CallExpr { func: Node { node: Selector(SelectorExpr { value: Node { node: Call(CallExpr { func: Node { node: Identifier(Identifier { names: ["str"], pkgpath: "", ctx: Load }), filename: "", line: 1, column: 0, end_line: 1, end_column: 3 }, args: [Node { node: NumberLit(NumberLit { binary_suffix: None, value: Int(1) }), filename: "", line: 1, column: 4, end_line: 1, end_column: 5 }], keywords: [] }), filename: "", line: 1, column: 0, end_line: 1, end_column: 6 }, attr: Node { node: Identifier { names: ["isdigit"], pkgpath: "", ctx: Load }, filename: "", line: 1, column: 7, end_line: 1, end_column: 14 }, ctx: Load, has_question: false }), filename: "", line: 1, column: 6, end_line: 1, end_column: 14 }, args: [], keywords: [] }), filename: "", line: 1, column: 14, end_line: 1, end_column: 16 } - "#]], - ); -} - -#[test] -fn list_expr() { - check_parsing_expr( - r####"[1, 2, 3]"####, - expect![[r#" - Node { node: List(ListExpr { elts: [Node { node: NumberLit(NumberLit { binary_suffix: None, value: Int(1) }), filename: "", line: 1, column: 1, end_line: 1, end_column: 2 }, Node { node: NumberLit(NumberLit { binary_suffix: None, value: Int(2) }), filename: "", line: 1, column: 4, end_line: 1, end_column: 5 }, Node { node: NumberLit(NumberLit { binary_suffix: None, value: Int(3) }), filename: "", line: 1, column: 7, end_line: 1, end_column: 8 }], ctx: Load }), filename: "", line: 1, column: 0, end_line: 1, end_column: 9 } - "#]], - ); - - check_parsing_expr( - r####"[1, if True: 2, 3]"####, - expect![[r#" - Node { node: List(ListExpr { elts: [Node { node: NumberLit(NumberLit { binary_suffix: None, value: Int(1) }), filename: "", line: 1, column: 1, end_line: 1, end_column: 2 }, Node { node: ListIfItem(ListIfItemExpr { if_cond: Node { node: NameConstantLit(NameConstantLit { value: True }), filename: "", line: 1, column: 7, end_line: 1, end_column: 11 }, exprs: [Node { node: NumberLit(NumberLit { binary_suffix: None, value: Int(2) }), filename: "", line: 1, column: 13, end_line: 1, end_column: 14 }], orelse: None }), filename: "", line: 1, column: 4, end_line: 1, end_column: 14 }, Node { node: NumberLit(NumberLit { binary_suffix: None, value: Int(3) }), filename: "", line: 1, column: 16, end_line: 1, end_column: 17 }], ctx: Load }), filename: "", line: 1, column: 0, end_line: 1, end_column: 18 } - "#]], - ); -} - -#[test] -fn list_comp_expr_0() { - check_parsing_expr( - r####"[x ** 2 for x in [1, 2, 3]]"####, - expect![[r#" - Node { node: ListComp(ListComp { elt: Node { node: Binary(BinaryExpr { left: Node { node: Identifier(Identifier { names: ["x"], pkgpath: "", ctx: Load }), filename: "", line: 1, column: 1, end_line: 1, end_column: 2 }, op: Bin(Pow), right: Node { node: NumberLit(NumberLit { binary_suffix: None, value: Int(2) }), filename: "", line: 1, column: 6, end_line: 1, end_column: 7 } }), filename: "", line: 1, column: 1, end_line: 1, end_column: 7 }, generators: [Node { node: CompClause { targets: [Node { node: Identifier { names: ["x"], pkgpath: "", ctx: Load }, filename: "", line: 1, column: 12, end_line: 1, end_column: 13 }], iter: Node { node: List(ListExpr { elts: [Node { node: NumberLit(NumberLit { binary_suffix: None, value: Int(1) }), filename: "", line: 1, column: 18, end_line: 1, end_column: 19 }, Node { node: NumberLit(NumberLit { binary_suffix: None, value: Int(2) }), filename: "", line: 1, column: 21, end_line: 1, end_column: 22 }, Node { node: NumberLit(NumberLit { binary_suffix: None, value: Int(3) }), filename: "", line: 1, column: 24, end_line: 1, end_column: 25 }], ctx: Load }), filename: "", line: 1, column: 17, end_line: 1, end_column: 26 }, ifs: [] }, filename: "", line: 1, column: 8, end_line: 1, end_column: 26 }] }), filename: "", line: 1, column: 0, end_line: 1, end_column: 27 } - "#]], - ); -} - -#[test] -fn list_comp_expr_1() { - check_parsing_expr( - r####"[i for i in [1, 2, 3] if i > 2]"####, - expect![[r#" - Node { node: ListComp(ListComp { elt: Node { node: Identifier(Identifier { names: ["i"], pkgpath: "", ctx: Load }), filename: "", line: 1, column: 1, end_line: 1, end_column: 2 }, generators: [Node { node: CompClause { targets: [Node { node: Identifier { names: ["i"], pkgpath: "", ctx: Load }, filename: "", line: 1, column: 7, end_line: 1, end_column: 8 }], iter: Node { node: List(ListExpr { elts: [Node { node: NumberLit(NumberLit { binary_suffix: None, value: Int(1) }), filename: "", line: 1, column: 13, end_line: 1, end_column: 14 }, Node { node: NumberLit(NumberLit { binary_suffix: None, value: Int(2) }), filename: "", line: 1, column: 16, end_line: 1, end_column: 17 }, Node { node: NumberLit(NumberLit { binary_suffix: None, value: Int(3) }), filename: "", line: 1, column: 19, end_line: 1, end_column: 20 }], ctx: Load }), filename: "", line: 1, column: 12, end_line: 1, end_column: 21 }, ifs: [Node { node: Compare(Compare { left: Node { node: Identifier(Identifier { names: ["i"], pkgpath: "", ctx: Load }), filename: "", line: 1, column: 25, end_line: 1, end_column: 26 }, ops: [Gt], comparators: [Node { node: NumberLit(NumberLit { binary_suffix: None, value: Int(2) }), filename: "", line: 1, column: 29, end_line: 1, end_column: 30 }] }), filename: "", line: 1, column: 25, end_line: 1, end_column: 30 }] }, filename: "", line: 1, column: 3, end_line: 1, end_column: 30 }] }), filename: "", line: 1, column: 0, end_line: 1, end_column: 31 } - "#]], - ); -} - -#[test] -fn dict_expr() { - check_parsing_expr( - r####"{k0=v0, k1=v1}"####, - expect![[r#" - Node { node: Config(ConfigExpr { items: [Node { node: ConfigEntry { key: Some(Node { node: Identifier(Identifier { names: ["k0"], pkgpath: "", ctx: Load }), filename: "", line: 1, column: 1, end_line: 1, end_column: 3 }), value: Node { node: Identifier(Identifier { names: ["v0"], pkgpath: "", ctx: Load }), filename: "", line: 1, column: 4, end_line: 1, end_column: 6 }, operation: Override, insert_index: -1 }, filename: "", line: 1, column: 1, end_line: 1, end_column: 6 }, Node { node: ConfigEntry { key: Some(Node { node: Identifier(Identifier { names: ["k1"], pkgpath: "", ctx: Load }), filename: "", line: 1, column: 8, end_line: 1, end_column: 10 }), value: Node { node: Identifier(Identifier { names: ["v1"], pkgpath: "", ctx: Load }), filename: "", line: 1, column: 11, end_line: 1, end_column: 13 }, operation: Override, insert_index: -1 }, filename: "", line: 1, column: 8, end_line: 1, end_column: 13 }] }), filename: "", line: 1, column: 0, end_line: 1, end_column: 14 } - "#]], - ); -} - -#[test] -fn dict_comp_expr() { - check_parsing_expr( - r####"{k: v + 1 for k, v in {k1 = 1, k2 = 2}}"####, - expect![[r#" - Node { node: DictComp(DictComp { entry: ConfigEntry { key: Some(Node { node: Identifier(Identifier { names: ["k"], pkgpath: "", ctx: Load }), filename: "", line: 1, column: 1, end_line: 1, end_column: 2 }), value: Node { node: Binary(BinaryExpr { left: Node { node: Identifier(Identifier { names: ["v"], pkgpath: "", ctx: Load }), filename: "", line: 1, column: 4, end_line: 1, end_column: 5 }, op: Bin(Add), right: Node { node: NumberLit(NumberLit { binary_suffix: None, value: Int(1) }), filename: "", line: 1, column: 8, end_line: 1, end_column: 9 } }), filename: "", line: 1, column: 4, end_line: 1, end_column: 9 }, operation: Union, insert_index: -1 }, generators: [Node { node: CompClause { targets: [Node { node: Identifier { names: ["k"], pkgpath: "", ctx: Load }, filename: "", line: 1, column: 14, end_line: 1, end_column: 15 }, Node { node: Identifier { names: ["v"], pkgpath: "", ctx: Load }, filename: "", line: 1, column: 17, end_line: 1, end_column: 18 }], iter: Node { node: Config(ConfigExpr { items: [Node { node: ConfigEntry { key: Some(Node { node: Identifier(Identifier { names: ["k1"], pkgpath: "", ctx: Load }), filename: "", line: 1, column: 23, end_line: 1, end_column: 25 }), value: Node { node: NumberLit(NumberLit { binary_suffix: None, value: Int(1) }), filename: "", line: 1, column: 28, end_line: 1, end_column: 29 }, operation: Override, insert_index: -1 }, filename: "", line: 1, column: 23, end_line: 1, end_column: 29 }, Node { node: ConfigEntry { key: Some(Node { node: Identifier(Identifier { names: ["k2"], pkgpath: "", ctx: Load }), filename: "", line: 1, column: 31, end_line: 1, end_column: 33 }), value: Node { node: NumberLit(NumberLit { binary_suffix: None, value: Int(2) }), filename: "", line: 1, column: 36, end_line: 1, end_column: 37 }, operation: Override, insert_index: -1 }, filename: "", line: 1, column: 31, end_line: 1, end_column: 37 }] }), filename: "", line: 1, column: 22, end_line: 1, end_column: 38 }, ifs: [] }, filename: "", line: 1, column: 10, end_line: 1, end_column: 38 }] }), filename: "", line: 1, column: 0, end_line: 1, end_column: 39 } - "#]], - ); -} - -#[test] -fn subscript_expr_0() { - check_parsing_expr( - r####"a[0]"####, - expect![[r#" - Node { node: Subscript(Subscript { value: Node { node: Identifier(Identifier { names: ["a"], pkgpath: "", ctx: Load }), filename: "", line: 1, column: 0, end_line: 1, end_column: 1 }, index: Some(Node { node: NumberLit(NumberLit { binary_suffix: None, value: Int(0) }), filename: "", line: 1, column: 2, end_line: 1, end_column: 3 }), lower: None, upper: None, step: None, ctx: Load, has_question: false }), filename: "", line: 1, column: 1, end_line: 1, end_column: 4 } - "#]], - ); -} - -#[test] -fn subscript_expr_1() { - check_parsing_expr( - r####"b["k"]"####, - expect![[r#" - Node { node: Subscript(Subscript { value: Node { node: Identifier(Identifier { names: ["b"], pkgpath: "", ctx: Load }), filename: "", line: 1, column: 0, end_line: 1, end_column: 1 }, index: Some(Node { node: StringLit(StringLit { is_long_string: false, raw_value: "\"k\"", value: "k" }), filename: "", line: 1, column: 2, end_line: 1, end_column: 5 }), lower: None, upper: None, step: None, ctx: Load, has_question: false }), filename: "", line: 1, column: 1, end_line: 1, end_column: 6 } - "#]], - ); -} - -#[test] -fn subscript_expr_2() { - check_parsing_expr( - r####"c?[1]"####, - expect![[r#" - Node { node: Subscript(Subscript { value: Node { node: Identifier(Identifier { names: ["c"], pkgpath: "", ctx: Load }), filename: "", line: 1, column: 0, end_line: 1, end_column: 1 }, index: Some(Node { node: NumberLit(NumberLit { binary_suffix: None, value: Int(1) }), filename: "", line: 1, column: 3, end_line: 1, end_column: 4 }), lower: None, upper: None, step: None, ctx: Load, has_question: true }), filename: "", line: 1, column: 1, end_line: 1, end_column: 5 } - "#]], - ); -} - -#[test] -fn subscript_expr_3() { - check_parsing_expr( - r####"a[1:]"####, - expect![[r#" - Node { node: Subscript(Subscript { value: Node { node: Identifier(Identifier { names: ["a"], pkgpath: "", ctx: Load }), filename: "", line: 1, column: 0, end_line: 1, end_column: 1 }, index: None, lower: Some(Node { node: NumberLit(NumberLit { binary_suffix: None, value: Int(1) }), filename: "", line: 1, column: 2, end_line: 1, end_column: 3 }), upper: None, step: None, ctx: Load, has_question: false }), filename: "", line: 1, column: 1, end_line: 1, end_column: 5 } - "#]], - ); -} - -#[test] -fn subscript_expr_4() { - check_parsing_expr( - r####"a[:-1]"####, - expect![[r#" - Node { node: Subscript(Subscript { value: Node { node: Identifier(Identifier { names: ["a"], pkgpath: "", ctx: Load }), filename: "", line: 1, column: 0, end_line: 1, end_column: 1 }, index: None, lower: None, upper: Some(Node { node: Unary(UnaryExpr { op: USub, operand: Node { node: NumberLit(NumberLit { binary_suffix: None, value: Int(1) }), filename: "", line: 1, column: 4, end_line: 1, end_column: 5 } }), filename: "", line: 1, column: 3, end_line: 1, end_column: 5 }), step: None, ctx: Load, has_question: false }), filename: "", line: 1, column: 1, end_line: 1, end_column: 6 } - "#]], - ); -} - -#[test] -fn subscript_expr_5() { - check_parsing_expr( - r####"a[1:len]"####, - expect![[r#" - Node { node: Subscript(Subscript { value: Node { node: Identifier(Identifier { names: ["a"], pkgpath: "", ctx: Load }), filename: "", line: 1, column: 0, end_line: 1, end_column: 1 }, index: None, lower: Some(Node { node: NumberLit(NumberLit { binary_suffix: None, value: Int(1) }), filename: "", line: 1, column: 2, end_line: 1, end_column: 3 }), upper: Some(Node { node: Identifier(Identifier { names: ["len"], pkgpath: "", ctx: Load }), filename: "", line: 1, column: 4, end_line: 1, end_column: 7 }), step: None, ctx: Load, has_question: false }), filename: "", line: 1, column: 1, end_line: 1, end_column: 8 } - "#]], - ); -} - -#[test] -fn subscript_expr_6() { - check_parsing_expr( - r####"a[0:-1]"####, - expect![[r#" - Node { node: Subscript(Subscript { value: Node { node: Identifier(Identifier { names: ["a"], pkgpath: "", ctx: Load }), filename: "", line: 1, column: 0, end_line: 1, end_column: 1 }, index: None, lower: Some(Node { node: NumberLit(NumberLit { binary_suffix: None, value: Int(0) }), filename: "", line: 1, column: 2, end_line: 1, end_column: 3 }), upper: Some(Node { node: Unary(UnaryExpr { op: USub, operand: Node { node: NumberLit(NumberLit { binary_suffix: None, value: Int(1) }), filename: "", line: 1, column: 5, end_line: 1, end_column: 6 } }), filename: "", line: 1, column: 4, end_line: 1, end_column: 6 }), step: None, ctx: Load, has_question: false }), filename: "", line: 1, column: 1, end_line: 1, end_column: 7 } - "#]], - ); -} - -#[test] -fn subscript_expr_7() { - check_parsing_expr( - r####"a[::]"####, - expect![[r#" - Node { node: Subscript(Subscript { value: Node { node: Identifier(Identifier { names: ["a"], pkgpath: "", ctx: Load }), filename: "", line: 1, column: 0, end_line: 1, end_column: 1 }, index: None, lower: None, upper: None, step: None, ctx: Load, has_question: false }), filename: "", line: 1, column: 1, end_line: 1, end_column: 5 } - "#]], - ); -} - -#[test] -fn subscript_expr_8() { - check_parsing_expr( - r####"a[1::]"####, - expect![[r#" - Node { node: Subscript(Subscript { value: Node { node: Identifier(Identifier { names: ["a"], pkgpath: "", ctx: Load }), filename: "", line: 1, column: 0, end_line: 1, end_column: 1 }, index: None, lower: Some(Node { node: NumberLit(NumberLit { binary_suffix: None, value: Int(1) }), filename: "", line: 1, column: 2, end_line: 1, end_column: 3 }), upper: None, step: None, ctx: Load, has_question: false }), filename: "", line: 1, column: 1, end_line: 1, end_column: 6 } - "#]], - ); -} - -#[test] -fn subscript_expr_9() { - check_parsing_expr( - r####"a[:0:]"####, - expect![[r#" - Node { node: Subscript(Subscript { value: Node { node: Identifier(Identifier { names: ["a"], pkgpath: "", ctx: Load }), filename: "", line: 1, column: 0, end_line: 1, end_column: 1 }, index: None, lower: None, upper: Some(Node { node: NumberLit(NumberLit { binary_suffix: None, value: Int(0) }), filename: "", line: 1, column: 3, end_line: 1, end_column: 4 }), step: None, ctx: Load, has_question: false }), filename: "", line: 1, column: 1, end_line: 1, end_column: 6 } - "#]], - ); -} - -#[test] -fn subscript_expr_10() { - check_parsing_expr( - r####"a[::-1]"####, - expect![[r#" - Node { node: Subscript(Subscript { value: Node { node: Identifier(Identifier { names: ["a"], pkgpath: "", ctx: Load }), filename: "", line: 1, column: 0, end_line: 1, end_column: 1 }, index: None, lower: None, upper: None, step: Some(Node { node: Unary(UnaryExpr { op: USub, operand: Node { node: NumberLit(NumberLit { binary_suffix: None, value: Int(1) }), filename: "", line: 1, column: 5, end_line: 1, end_column: 6 } }), filename: "", line: 1, column: 4, end_line: 1, end_column: 6 }), ctx: Load, has_question: false }), filename: "", line: 1, column: 1, end_line: 1, end_column: 7 } - "#]], - ); -} - -#[test] -fn subscript_expr_11() { - check_parsing_expr( - r####"a[1::2]"####, - expect![[r#" - Node { node: Subscript(Subscript { value: Node { node: Identifier(Identifier { names: ["a"], pkgpath: "", ctx: Load }), filename: "", line: 1, column: 0, end_line: 1, end_column: 1 }, index: None, lower: Some(Node { node: NumberLit(NumberLit { binary_suffix: None, value: Int(1) }), filename: "", line: 1, column: 2, end_line: 1, end_column: 3 }), upper: None, step: Some(Node { node: NumberLit(NumberLit { binary_suffix: None, value: Int(2) }), filename: "", line: 1, column: 5, end_line: 1, end_column: 6 }), ctx: Load, has_question: false }), filename: "", line: 1, column: 1, end_line: 1, end_column: 7 } - "#]], - ); -} - -#[test] -fn subscript_expr_12() { - check_parsing_expr( - r####"a[:2:1]"####, - expect![[r#" - Node { node: Subscript(Subscript { value: Node { node: Identifier(Identifier { names: ["a"], pkgpath: "", ctx: Load }), filename: "", line: 1, column: 0, end_line: 1, end_column: 1 }, index: None, lower: None, upper: Some(Node { node: NumberLit(NumberLit { binary_suffix: None, value: Int(2) }), filename: "", line: 1, column: 3, end_line: 1, end_column: 4 }), step: Some(Node { node: NumberLit(NumberLit { binary_suffix: None, value: Int(1) }), filename: "", line: 1, column: 5, end_line: 1, end_column: 6 }), ctx: Load, has_question: false }), filename: "", line: 1, column: 1, end_line: 1, end_column: 7 } - "#]], - ); -} - -#[test] -fn subscript_expr_13() { - check_parsing_expr( - r####"a[1:2:]"####, - expect![[r#" - Node { node: Subscript(Subscript { value: Node { node: Identifier(Identifier { names: ["a"], pkgpath: "", ctx: Load }), filename: "", line: 1, column: 0, end_line: 1, end_column: 1 }, index: None, lower: Some(Node { node: NumberLit(NumberLit { binary_suffix: None, value: Int(1) }), filename: "", line: 1, column: 2, end_line: 1, end_column: 3 }), upper: Some(Node { node: NumberLit(NumberLit { binary_suffix: None, value: Int(2) }), filename: "", line: 1, column: 4, end_line: 1, end_column: 5 }), step: None, ctx: Load, has_question: false }), filename: "", line: 1, column: 1, end_line: 1, end_column: 7 } - "#]], - ); -} - -#[test] -fn subscript_expr_14() { - check_parsing_expr( - r####"a[1:3:1]"####, - expect![[r#" - Node { node: Subscript(Subscript { value: Node { node: Identifier(Identifier { names: ["a"], pkgpath: "", ctx: Load }), filename: "", line: 1, column: 0, end_line: 1, end_column: 1 }, index: None, lower: Some(Node { node: NumberLit(NumberLit { binary_suffix: None, value: Int(1) }), filename: "", line: 1, column: 2, end_line: 1, end_column: 3 }), upper: Some(Node { node: NumberLit(NumberLit { binary_suffix: None, value: Int(3) }), filename: "", line: 1, column: 4, end_line: 1, end_column: 5 }), step: Some(Node { node: NumberLit(NumberLit { binary_suffix: None, value: Int(1) }), filename: "", line: 1, column: 6, end_line: 1, end_column: 7 }), ctx: Load, has_question: false }), filename: "", line: 1, column: 1, end_line: 1, end_column: 8 } - "#]], - ); -} - -#[test] -fn call_expr_0() { - check_parsing_expr( - r####"func0()"####, - expect![[r#" - Node { node: Call(CallExpr { func: Node { node: Identifier(Identifier { names: ["func0"], pkgpath: "", ctx: Load }), filename: "", line: 1, column: 0, end_line: 1, end_column: 5 }, args: [], keywords: [] }), filename: "", line: 1, column: 0, end_line: 1, end_column: 7 } - "#]], - ); -} - -#[test] -fn call_expr_1() { - check_parsing_expr( - r####"func1(1)"####, - expect![[r#" - Node { node: Call(CallExpr { func: Node { node: Identifier(Identifier { names: ["func1"], pkgpath: "", ctx: Load }), filename: "", line: 1, column: 0, end_line: 1, end_column: 5 }, args: [Node { node: NumberLit(NumberLit { binary_suffix: None, value: Int(1) }), filename: "", line: 1, column: 6, end_line: 1, end_column: 7 }], keywords: [] }), filename: "", line: 1, column: 0, end_line: 1, end_column: 8 } - "#]], - ); -} - -#[test] -fn call_expr_2() { - check_parsing_expr( - r####"func2(x=2)"####, - expect![[r#" - Node { node: Call(CallExpr { func: Node { node: Identifier(Identifier { names: ["func2"], pkgpath: "", ctx: Load }), filename: "", line: 1, column: 0, end_line: 1, end_column: 5 }, args: [], keywords: [Node { node: Keyword { arg: Node { node: Identifier { names: ["x"], pkgpath: "", ctx: Load }, filename: "", line: 1, column: 6, end_line: 1, end_column: 7 }, value: Some(Node { node: NumberLit(NumberLit { binary_suffix: None, value: Int(2) }), filename: "", line: 1, column: 8, end_line: 1, end_column: 9 }) }, filename: "", line: 1, column: 6, end_line: 1, end_column: 9 }] }), filename: "", line: 1, column: 0, end_line: 1, end_column: 10 } - "#]], - ); -} - -#[test] -fn call_expr_3() { - check_parsing_expr( - r####"func3(1,x=2)"####, - expect![[r#" - Node { node: Call(CallExpr { func: Node { node: Identifier(Identifier { names: ["func3"], pkgpath: "", ctx: Load }), filename: "", line: 1, column: 0, end_line: 1, end_column: 5 }, args: [Node { node: NumberLit(NumberLit { binary_suffix: None, value: Int(1) }), filename: "", line: 1, column: 6, end_line: 1, end_column: 7 }], keywords: [Node { node: Keyword { arg: Node { node: Identifier { names: ["x"], pkgpath: "", ctx: Load }, filename: "", line: 1, column: 8, end_line: 1, end_column: 9 }, value: Some(Node { node: NumberLit(NumberLit { binary_suffix: None, value: Int(2) }), filename: "", line: 1, column: 10, end_line: 1, end_column: 11 }) }, filename: "", line: 1, column: 8, end_line: 1, end_column: 11 }] }), filename: "", line: 1, column: 0, end_line: 1, end_column: 12 } - "#]], - ); -} - -#[test] -fn quant_expr_0() { - check_parsing_expr( - r####"all x in collection {x > 0}"####, - expect![[r#" - Node { node: Quant(QuantExpr { target: Node { node: Identifier(Identifier { names: ["collection"], pkgpath: "", ctx: Load }), filename: "", line: 1, column: 9, end_line: 1, end_column: 19 }, variables: [Node { node: Identifier { names: ["x"], pkgpath: "", ctx: Load }, filename: "", line: 1, column: 4, end_line: 1, end_column: 5 }], op: All, test: Node { node: Compare(Compare { left: Node { node: Identifier(Identifier { names: ["x"], pkgpath: "", ctx: Load }), filename: "", line: 1, column: 21, end_line: 1, end_column: 22 }, ops: [Gt], comparators: [Node { node: NumberLit(NumberLit { binary_suffix: None, value: Int(0) }), filename: "", line: 1, column: 25, end_line: 1, end_column: 26 }] }), filename: "", line: 1, column: 21, end_line: 1, end_column: 26 }, if_cond: None, ctx: Load }), filename: "", line: 1, column: 0, end_line: 1, end_column: 27 } - "#]], - ); -} - -#[test] -fn quant_expr_1() { - check_parsing_expr( - r####"any y in collection {y < 0}"####, - expect![[r#" - Node { node: Quant(QuantExpr { target: Node { node: Identifier(Identifier { names: ["collection"], pkgpath: "", ctx: Load }), filename: "", line: 1, column: 9, end_line: 1, end_column: 19 }, variables: [Node { node: Identifier { names: ["y"], pkgpath: "", ctx: Load }, filename: "", line: 1, column: 4, end_line: 1, end_column: 5 }], op: Any, test: Node { node: Compare(Compare { left: Node { node: Identifier(Identifier { names: ["y"], pkgpath: "", ctx: Load }), filename: "", line: 1, column: 21, end_line: 1, end_column: 22 }, ops: [Lt], comparators: [Node { node: NumberLit(NumberLit { binary_suffix: None, value: Int(0) }), filename: "", line: 1, column: 25, end_line: 1, end_column: 26 }] }), filename: "", line: 1, column: 21, end_line: 1, end_column: 26 }, if_cond: None, ctx: Load }), filename: "", line: 1, column: 0, end_line: 1, end_column: 27 } - "#]], - ); -} - -#[test] -fn quant_expr_2() { - check_parsing_expr( - r####"map x in collection {x + 1}"####, - expect![[r#" - Node { node: Quant(QuantExpr { target: Node { node: Identifier(Identifier { names: ["collection"], pkgpath: "", ctx: Load }), filename: "", line: 1, column: 9, end_line: 1, end_column: 19 }, variables: [Node { node: Identifier { names: ["x"], pkgpath: "", ctx: Load }, filename: "", line: 1, column: 4, end_line: 1, end_column: 5 }], op: Map, test: Node { node: Binary(BinaryExpr { left: Node { node: Identifier(Identifier { names: ["x"], pkgpath: "", ctx: Load }), filename: "", line: 1, column: 21, end_line: 1, end_column: 22 }, op: Bin(Add), right: Node { node: NumberLit(NumberLit { binary_suffix: None, value: Int(1) }), filename: "", line: 1, column: 25, end_line: 1, end_column: 26 } }), filename: "", line: 1, column: 21, end_line: 1, end_column: 26 }, if_cond: None, ctx: Load }), filename: "", line: 1, column: 0, end_line: 1, end_column: 27 } - "#]], - ); -} - -#[test] -fn quant_expr_3() { - check_parsing_expr( - r####"filter x in collection {x > 1}"####, - expect![[r#" - Node { node: Quant(QuantExpr { target: Node { node: Identifier(Identifier { names: ["collection"], pkgpath: "", ctx: Load }), filename: "", line: 1, column: 12, end_line: 1, end_column: 22 }, variables: [Node { node: Identifier { names: ["x"], pkgpath: "", ctx: Load }, filename: "", line: 1, column: 7, end_line: 1, end_column: 8 }], op: Filter, test: Node { node: Compare(Compare { left: Node { node: Identifier(Identifier { names: ["x"], pkgpath: "", ctx: Load }), filename: "", line: 1, column: 24, end_line: 1, end_column: 25 }, ops: [Gt], comparators: [Node { node: NumberLit(NumberLit { binary_suffix: None, value: Int(1) }), filename: "", line: 1, column: 28, end_line: 1, end_column: 29 }] }), filename: "", line: 1, column: 24, end_line: 1, end_column: 29 }, if_cond: None, ctx: Load }), filename: "", line: 1, column: 0, end_line: 1, end_column: 30 } - "#]], - ); -} - -#[test] -fn quant_expr_4() { - check_parsing_expr( - r####"filter x in collection {x > 1}"####, - expect![[r#" - Node { node: Quant(QuantExpr { target: Node { node: Identifier(Identifier { names: ["collection"], pkgpath: "", ctx: Load }), filename: "", line: 1, column: 12, end_line: 1, end_column: 22 }, variables: [Node { node: Identifier { names: ["x"], pkgpath: "", ctx: Load }, filename: "", line: 1, column: 7, end_line: 1, end_column: 8 }], op: Filter, test: Node { node: Compare(Compare { left: Node { node: Identifier(Identifier { names: ["x"], pkgpath: "", ctx: Load }), filename: "", line: 1, column: 24, end_line: 1, end_column: 25 }, ops: [Gt], comparators: [Node { node: NumberLit(NumberLit { binary_suffix: None, value: Int(1) }), filename: "", line: 1, column: 28, end_line: 1, end_column: 29 }] }), filename: "", line: 1, column: 24, end_line: 1, end_column: 29 }, if_cond: None, ctx: Load }), filename: "", line: 1, column: 0, end_line: 1, end_column: 30 } - "#]], - ); -} - -#[test] -fn quant_expr_5() { - check_parsing_expr( - r####"map i, e in [{k1 = "v1", k2 = "v2"}] { e }"####, - expect![[r#" - Node { node: Quant(QuantExpr { target: Node { node: List(ListExpr { elts: [Node { node: Config(ConfigExpr { items: [Node { node: ConfigEntry { key: Some(Node { node: Identifier(Identifier { names: ["k1"], pkgpath: "", ctx: Load }), filename: "", line: 1, column: 14, end_line: 1, end_column: 16 }), value: Node { node: StringLit(StringLit { is_long_string: false, raw_value: "\"v1\"", value: "v1" }), filename: "", line: 1, column: 19, end_line: 1, end_column: 23 }, operation: Override, insert_index: -1 }, filename: "", line: 1, column: 14, end_line: 1, end_column: 23 }, Node { node: ConfigEntry { key: Some(Node { node: Identifier(Identifier { names: ["k2"], pkgpath: "", ctx: Load }), filename: "", line: 1, column: 25, end_line: 1, end_column: 27 }), value: Node { node: StringLit(StringLit { is_long_string: false, raw_value: "\"v2\"", value: "v2" }), filename: "", line: 1, column: 30, end_line: 1, end_column: 34 }, operation: Override, insert_index: -1 }, filename: "", line: 1, column: 25, end_line: 1, end_column: 34 }] }), filename: "", line: 1, column: 13, end_line: 1, end_column: 35 }], ctx: Load }), filename: "", line: 1, column: 12, end_line: 1, end_column: 36 }, variables: [Node { node: Identifier { names: ["i"], pkgpath: "", ctx: Load }, filename: "", line: 1, column: 4, end_line: 1, end_column: 5 }, Node { node: Identifier { names: ["e"], pkgpath: "", ctx: Load }, filename: "", line: 1, column: 7, end_line: 1, end_column: 8 }], op: Map, test: Node { node: Identifier(Identifier { names: ["e"], pkgpath: "", ctx: Load }), filename: "", line: 1, column: 39, end_line: 1, end_column: 40 }, if_cond: None, ctx: Load }), filename: "", line: 1, column: 0, end_line: 1, end_column: 42 } - "#]], - ); -} - -#[test] -fn quant_expr_6() { - check_parsing_expr( - r####"map i, e in [{k1 = "v1", k2 = "v2"}] { e if i > 0 }"####, - expect![[r#" - Node { node: Quant(QuantExpr { target: Node { node: List(ListExpr { elts: [Node { node: Config(ConfigExpr { items: [Node { node: ConfigEntry { key: Some(Node { node: Identifier(Identifier { names: ["k1"], pkgpath: "", ctx: Load }), filename: "", line: 1, column: 14, end_line: 1, end_column: 16 }), value: Node { node: StringLit(StringLit { is_long_string: false, raw_value: "\"v1\"", value: "v1" }), filename: "", line: 1, column: 19, end_line: 1, end_column: 23 }, operation: Override, insert_index: -1 }, filename: "", line: 1, column: 14, end_line: 1, end_column: 23 }, Node { node: ConfigEntry { key: Some(Node { node: Identifier(Identifier { names: ["k2"], pkgpath: "", ctx: Load }), filename: "", line: 1, column: 25, end_line: 1, end_column: 27 }), value: Node { node: StringLit(StringLit { is_long_string: false, raw_value: "\"v2\"", value: "v2" }), filename: "", line: 1, column: 30, end_line: 1, end_column: 34 }, operation: Override, insert_index: -1 }, filename: "", line: 1, column: 25, end_line: 1, end_column: 34 }] }), filename: "", line: 1, column: 13, end_line: 1, end_column: 35 }], ctx: Load }), filename: "", line: 1, column: 12, end_line: 1, end_column: 36 }, variables: [Node { node: Identifier { names: ["i"], pkgpath: "", ctx: Load }, filename: "", line: 1, column: 4, end_line: 1, end_column: 5 }, Node { node: Identifier { names: ["e"], pkgpath: "", ctx: Load }, filename: "", line: 1, column: 7, end_line: 1, end_column: 8 }], op: Map, test: Node { node: Identifier(Identifier { names: ["e"], pkgpath: "", ctx: Load }), filename: "", line: 1, column: 39, end_line: 1, end_column: 40 }, if_cond: Some(Node { node: Compare(Compare { left: Node { node: Identifier(Identifier { names: ["i"], pkgpath: "", ctx: Load }), filename: "", line: 1, column: 44, end_line: 1, end_column: 45 }, ops: [Gt], comparators: [Node { node: NumberLit(NumberLit { binary_suffix: None, value: Int(0) }), filename: "", line: 1, column: 48, end_line: 1, end_column: 49 }] }), filename: "", line: 1, column: 44, end_line: 1, end_column: 49 }), ctx: Load }), filename: "", line: 1, column: 0, end_line: 1, end_column: 51 } - "#]], - ); -} - -#[test] -fn lambda_expr_0() { - check_parsing_expr( - r####"lambda {}"####, - expect![[r#" - Node { node: Lambda(LambdaExpr { args: None, return_type_str: None, body: [], return_ty: None }), filename: "", line: 1, column: 0, end_line: 1, end_column: 9 } - "#]], - ); -} - -#[test] -fn lambda_expr_1() { - check_parsing_expr( - r####"lambda x {}"####, - expect![[r#" - Node { node: Lambda(LambdaExpr { args: Some(Node { node: Arguments { args: [Node { node: Identifier { names: ["x"], pkgpath: "", ctx: Load }, filename: "", line: 1, column: 7, end_line: 1, end_column: 8 }], defaults: [None], type_annotation_list: [None], ty_list: [None] }, filename: "", line: 1, column: 7, end_line: 1, end_column: 8 }), return_type_str: None, body: [], return_ty: None }), filename: "", line: 1, column: 0, end_line: 1, end_column: 11 } - "#]], - ); -} - -#[test] -fn lambda_expr_2() { - check_parsing_expr( - r####"lambda x: int -> int {x}"####, - expect![[r#" - Node { node: Lambda(LambdaExpr { args: Some(Node { node: Arguments { args: [Node { node: Identifier { names: ["x"], pkgpath: "", ctx: Load }, filename: "", line: 1, column: 7, end_line: 1, end_column: 8 }], defaults: [None], type_annotation_list: [Some(Node { node: "int", filename: "", line: 1, column: 10, end_line: 1, end_column: 13 })], ty_list: [Some(Node { node: Basic(Int), filename: "", line: 1, column: 10, end_line: 1, end_column: 13 })] }, filename: "", line: 1, column: 7, end_line: 1, end_column: 13 }), return_type_str: Some("int"), body: [Node { node: Expr(ExprStmt { exprs: [Node { node: Identifier(Identifier { names: ["x"], pkgpath: "", ctx: Load }), filename: "", line: 1, column: 22, end_line: 1, end_column: 23 }] }), filename: "", line: 1, column: 22, end_line: 1, end_column: 23 }], return_ty: Some(Node { node: Basic(Int), filename: "", line: 1, column: 17, end_line: 1, end_column: 20 }) }), filename: "", line: 1, column: 0, end_line: 1, end_column: 24 } - "#]], - ); -} - -#[test] -fn lambda_expr_3() { - check_parsing_expr( - r####"lambda { - if True: - _a = 1 - else: - _a = 2 - _a -}"####, - expect![[r#" - Node { node: Lambda(LambdaExpr { args: None, return_type_str: None, body: [Node { node: If(IfStmt { body: [Node { node: Assign(AssignStmt { targets: [Node { node: Identifier { names: ["_a"], pkgpath: "", ctx: Store }, filename: "", line: 3, column: 8, end_line: 3, end_column: 10 }], value: Node { node: NumberLit(NumberLit { binary_suffix: None, value: Int(1) }), filename: "", line: 3, column: 13, end_line: 3, end_column: 14 }, type_annotation: None, ty: None }), filename: "", line: 3, column: 8, end_line: 4, end_column: 0 }], cond: Node { node: NameConstantLit(NameConstantLit { value: True }), filename: "", line: 2, column: 7, end_line: 2, end_column: 11 }, orelse: [Node { node: Assign(AssignStmt { targets: [Node { node: Identifier { names: ["_a"], pkgpath: "", ctx: Store }, filename: "", line: 5, column: 8, end_line: 5, end_column: 10 }], value: Node { node: NumberLit(NumberLit { binary_suffix: None, value: Int(2) }), filename: "", line: 5, column: 13, end_line: 5, end_column: 14 }, type_annotation: None, ty: None }), filename: "", line: 5, column: 8, end_line: 6, end_column: 0 }] }), filename: "", line: 2, column: 4, end_line: 6, end_column: 4 }, Node { node: Expr(ExprStmt { exprs: [Node { node: Identifier(Identifier { names: ["_a"], pkgpath: "", ctx: Load }), filename: "", line: 6, column: 4, end_line: 6, end_column: 6 }] }), filename: "", line: 6, column: 4, end_line: 6, end_column: 6 }], return_ty: None }), filename: "", line: 1, column: 0, end_line: 7, end_column: 1 } - "#]], - ); -} - -#[test] -fn config_expr_0() { - check_parsing_expr( - r####"{ - "name" = { - "name": "alice" - }, - "gender" = "female" -}"####, - expect![[r#" - Node { node: Config(ConfigExpr { items: [Node { node: ConfigEntry { key: Some(Node { node: StringLit(StringLit { is_long_string: false, raw_value: "\"name\"", value: "name" }), filename: "", line: 2, column: 4, end_line: 2, end_column: 10 }), value: Node { node: Config(ConfigExpr { items: [Node { node: ConfigEntry { key: Some(Node { node: StringLit(StringLit { is_long_string: false, raw_value: "\"name\"", value: "name" }), filename: "", line: 3, column: 8, end_line: 3, end_column: 14 }), value: Node { node: StringLit(StringLit { is_long_string: false, raw_value: "\"alice\"", value: "alice" }), filename: "", line: 3, column: 16, end_line: 3, end_column: 23 }, operation: Union, insert_index: -1 }, filename: "", line: 3, column: 8, end_line: 3, end_column: 23 }] }), filename: "", line: 2, column: 13, end_line: 4, end_column: 5 }, operation: Override, insert_index: -1 }, filename: "", line: 2, column: 4, end_line: 4, end_column: 5 }, Node { node: ConfigEntry { key: Some(Node { node: StringLit(StringLit { is_long_string: false, raw_value: "\"gender\"", value: "gender" }), filename: "", line: 5, column: 4, end_line: 5, end_column: 12 }), value: Node { node: StringLit(StringLit { is_long_string: false, raw_value: "\"female\"", value: "female" }), filename: "", line: 5, column: 15, end_line: 5, end_column: 23 }, operation: Override, insert_index: -1 }, filename: "", line: 5, column: 4, end_line: 5, end_column: 23 }] }), filename: "", line: 1, column: 0, end_line: 6, end_column: 1 } - "#]], - ); -} - -#[test] -fn config_expr_1() { - check_parsing_expr( - r####"{ - "name" = { - "name": "alice" - } - "gender" = "female", -}"####, - expect![[r#" - Node { node: Config(ConfigExpr { items: [Node { node: ConfigEntry { key: Some(Node { node: StringLit(StringLit { is_long_string: false, raw_value: "\"name\"", value: "name" }), filename: "", line: 2, column: 4, end_line: 2, end_column: 10 }), value: Node { node: Config(ConfigExpr { items: [Node { node: ConfigEntry { key: Some(Node { node: StringLit(StringLit { is_long_string: false, raw_value: "\"name\"", value: "name" }), filename: "", line: 3, column: 8, end_line: 3, end_column: 14 }), value: Node { node: StringLit(StringLit { is_long_string: false, raw_value: "\"alice\"", value: "alice" }), filename: "", line: 3, column: 16, end_line: 3, end_column: 23 }, operation: Union, insert_index: -1 }, filename: "", line: 3, column: 8, end_line: 3, end_column: 23 }] }), filename: "", line: 2, column: 13, end_line: 4, end_column: 5 }, operation: Override, insert_index: -1 }, filename: "", line: 2, column: 4, end_line: 4, end_column: 5 }, Node { node: ConfigEntry { key: Some(Node { node: StringLit(StringLit { is_long_string: false, raw_value: "\"gender\"", value: "gender" }), filename: "", line: 5, column: 4, end_line: 5, end_column: 12 }), value: Node { node: StringLit(StringLit { is_long_string: false, raw_value: "\"female\"", value: "female" }), filename: "", line: 5, column: 15, end_line: 5, end_column: 23 }, operation: Override, insert_index: -1 }, filename: "", line: 5, column: 4, end_line: 5, end_column: 23 }] }), filename: "", line: 1, column: 0, end_line: 6, end_column: 1 } - "#]], - ); -} - -#[test] -fn config_expr_2() { - check_parsing_expr( - r####"{ - "name" = { - "name": "alice", - } - "gender" = "female" -}"####, - expect![[r#" - Node { node: Config(ConfigExpr { items: [Node { node: ConfigEntry { key: Some(Node { node: StringLit(StringLit { is_long_string: false, raw_value: "\"name\"", value: "name" }), filename: "", line: 2, column: 4, end_line: 2, end_column: 10 }), value: Node { node: Config(ConfigExpr { items: [Node { node: ConfigEntry { key: Some(Node { node: StringLit(StringLit { is_long_string: false, raw_value: "\"name\"", value: "name" }), filename: "", line: 3, column: 8, end_line: 3, end_column: 14 }), value: Node { node: StringLit(StringLit { is_long_string: false, raw_value: "\"alice\"", value: "alice" }), filename: "", line: 3, column: 16, end_line: 3, end_column: 23 }, operation: Union, insert_index: -1 }, filename: "", line: 3, column: 8, end_line: 3, end_column: 23 }] }), filename: "", line: 2, column: 13, end_line: 4, end_column: 5 }, operation: Override, insert_index: -1 }, filename: "", line: 2, column: 4, end_line: 4, end_column: 5 }, Node { node: ConfigEntry { key: Some(Node { node: StringLit(StringLit { is_long_string: false, raw_value: "\"gender\"", value: "gender" }), filename: "", line: 5, column: 4, end_line: 5, end_column: 12 }), value: Node { node: StringLit(StringLit { is_long_string: false, raw_value: "\"female\"", value: "female" }), filename: "", line: 5, column: 15, end_line: 5, end_column: 23 }, operation: Override, insert_index: -1 }, filename: "", line: 5, column: 4, end_line: 5, end_column: 23 }] }), filename: "", line: 1, column: 0, end_line: 6, end_column: 1 } - "#]], - ); -} - -#[test] -fn config_if_expr_0() { - check_parsing_expr( - r####"{ - if True: - a = 1 -}"####, - expect![[r#" - Node { node: Config(ConfigExpr { items: [Node { node: ConfigEntry { key: None, value: Node { node: ConfigIfEntry(ConfigIfEntryExpr { if_cond: Node { node: NameConstantLit(NameConstantLit { value: True }), filename: "", line: 2, column: 7, end_line: 2, end_column: 11 }, items: [Node { node: ConfigEntry { key: Some(Node { node: Identifier(Identifier { names: ["a"], pkgpath: "", ctx: Load }), filename: "", line: 3, column: 8, end_line: 3, end_column: 9 }), value: Node { node: NumberLit(NumberLit { binary_suffix: None, value: Int(1) }), filename: "", line: 3, column: 12, end_line: 3, end_column: 13 }, operation: Override, insert_index: -1 }, filename: "", line: 3, column: 12, end_line: 3, end_column: 13 }], orelse: None }), filename: "", line: 3, column: 8, end_line: 4, end_column: 0 }, operation: Union, insert_index: -1 }, filename: "", line: 2, column: 4, end_line: 4, end_column: 0 }] }), filename: "", line: 1, column: 0, end_line: 4, end_column: 1 } - "#]], - ); -} - -#[test] -fn config_if_expr_1() { - check_parsing_expr( - r####"{ - if True: - a = 1 - else: - a = 2 -}"####, - expect![[r#" - Node { node: Config(ConfigExpr { items: [Node { node: ConfigEntry { key: None, value: Node { node: ConfigIfEntry(ConfigIfEntryExpr { if_cond: Node { node: NameConstantLit(NameConstantLit { value: True }), filename: "", line: 2, column: 7, end_line: 2, end_column: 11 }, items: [Node { node: ConfigEntry { key: Some(Node { node: Identifier(Identifier { names: ["a"], pkgpath: "", ctx: Load }), filename: "", line: 3, column: 8, end_line: 3, end_column: 9 }), value: Node { node: NumberLit(NumberLit { binary_suffix: None, value: Int(1) }), filename: "", line: 3, column: 12, end_line: 3, end_column: 13 }, operation: Override, insert_index: -1 }, filename: "", line: 3, column: 12, end_line: 3, end_column: 13 }], orelse: Some(Node { node: Config(ConfigExpr { items: [Node { node: ConfigEntry { key: Some(Node { node: Identifier(Identifier { names: ["a"], pkgpath: "", ctx: Load }), filename: "", line: 5, column: 8, end_line: 5, end_column: 9 }), value: Node { node: NumberLit(NumberLit { binary_suffix: None, value: Int(2) }), filename: "", line: 5, column: 12, end_line: 5, end_column: 13 }, operation: Override, insert_index: -1 }, filename: "", line: 5, column: 12, end_line: 5, end_column: 13 }] }), filename: "", line: 4, column: 4, end_line: 6, end_column: 0 }) }), filename: "", line: 3, column: 8, end_line: 4, end_column: 4 }, operation: Union, insert_index: -1 }, filename: "", line: 2, column: 4, end_line: 6, end_column: 0 }] }), filename: "", line: 1, column: 0, end_line: 6, end_column: 1 } - "#]], - ); -} - -#[test] -fn config_if_expr_2() { - check_parsing_expr( - r####"{ - if True: - a = 1 - elif x > 1: - a = 2 - else: - a = 3 -}"####, - expect![[r#" - Node { node: Config(ConfigExpr { items: [Node { node: ConfigEntry { key: None, value: Node { node: ConfigIfEntry(ConfigIfEntryExpr { if_cond: Node { node: NameConstantLit(NameConstantLit { value: True }), filename: "", line: 2, column: 7, end_line: 2, end_column: 11 }, items: [Node { node: ConfigEntry { key: Some(Node { node: Identifier(Identifier { names: ["a"], pkgpath: "", ctx: Load }), filename: "", line: 3, column: 8, end_line: 3, end_column: 9 }), value: Node { node: NumberLit(NumberLit { binary_suffix: None, value: Int(1) }), filename: "", line: 3, column: 12, end_line: 3, end_column: 13 }, operation: Override, insert_index: -1 }, filename: "", line: 3, column: 12, end_line: 3, end_column: 13 }], orelse: Some(Node { node: ConfigIfEntry(ConfigIfEntryExpr { if_cond: Node { node: Compare(Compare { left: Node { node: Identifier(Identifier { names: ["x"], pkgpath: "", ctx: Load }), filename: "", line: 4, column: 9, end_line: 4, end_column: 10 }, ops: [Gt], comparators: [Node { node: NumberLit(NumberLit { binary_suffix: None, value: Int(1) }), filename: "", line: 4, column: 13, end_line: 4, end_column: 14 }] }), filename: "", line: 4, column: 9, end_line: 4, end_column: 14 }, items: [Node { node: ConfigEntry { key: Some(Node { node: Identifier(Identifier { names: ["a"], pkgpath: "", ctx: Load }), filename: "", line: 5, column: 8, end_line: 5, end_column: 9 }), value: Node { node: NumberLit(NumberLit { binary_suffix: None, value: Int(2) }), filename: "", line: 5, column: 12, end_line: 5, end_column: 13 }, operation: Override, insert_index: -1 }, filename: "", line: 5, column: 12, end_line: 5, end_column: 13 }], orelse: Some(Node { node: Config(ConfigExpr { items: [Node { node: ConfigEntry { key: Some(Node { node: Identifier(Identifier { names: ["a"], pkgpath: "", ctx: Load }), filename: "", line: 7, column: 8, end_line: 7, end_column: 9 }), value: Node { node: NumberLit(NumberLit { binary_suffix: None, value: Int(3) }), filename: "", line: 7, column: 12, end_line: 7, end_column: 13 }, operation: Override, insert_index: -1 }, filename: "", line: 7, column: 12, end_line: 7, end_column: 13 }] }), filename: "", line: 6, column: 4, end_line: 8, end_column: 0 }) }), filename: "", line: 4, column: 4, end_line: 6, end_column: 4 }) }), filename: "", line: 3, column: 8, end_line: 4, end_column: 4 }, operation: Union, insert_index: -1 }, filename: "", line: 2, column: 4, end_line: 8, end_column: 0 }] }), filename: "", line: 1, column: 0, end_line: 8, end_column: 1 } - "#]], - ); -} - -#[test] -fn config_if_expr_3() { - check_parsing_expr( - r####"{ - if True: - if False: - a = 1 -}"####, - expect![[r#" - Node { node: Config(ConfigExpr { items: [Node { node: ConfigEntry { key: None, value: Node { node: ConfigIfEntry(ConfigIfEntryExpr { if_cond: Node { node: NameConstantLit(NameConstantLit { value: True }), filename: "", line: 2, column: 7, end_line: 2, end_column: 11 }, items: [Node { node: ConfigEntry { key: None, value: Node { node: ConfigIfEntry(ConfigIfEntryExpr { if_cond: Node { node: NameConstantLit(NameConstantLit { value: False }), filename: "", line: 3, column: 11, end_line: 3, end_column: 16 }, items: [Node { node: ConfigEntry { key: Some(Node { node: Identifier(Identifier { names: ["a"], pkgpath: "", ctx: Load }), filename: "", line: 4, column: 12, end_line: 4, end_column: 13 }), value: Node { node: NumberLit(NumberLit { binary_suffix: None, value: Int(1) }), filename: "", line: 4, column: 16, end_line: 4, end_column: 17 }, operation: Override, insert_index: -1 }, filename: "", line: 4, column: 16, end_line: 4, end_column: 17 }], orelse: None }), filename: "", line: 4, column: 12, end_line: 5, end_column: 0 }, operation: Override, insert_index: -1 }, filename: "", line: 4, column: 12, end_line: 5, end_column: 0 }], orelse: None }), filename: "", line: 3, column: 8, end_line: 5, end_column: 0 }, operation: Union, insert_index: -1 }, filename: "", line: 2, column: 4, end_line: 5, end_column: 0 }] }), filename: "", line: 1, column: 0, end_line: 5, end_column: 1 } - "#]], - ); -} - -#[test] -fn schema_expr_0() { - check_parsing_expr( - r####"Schema {}"####, - expect![[r#" - Node { node: Schema(SchemaExpr { name: Node { node: Identifier { names: ["Schema"], pkgpath: "", ctx: Load }, filename: "", line: 1, column: 0, end_line: 1, end_column: 6 }, args: [], kwargs: [], config: Node { node: Config(ConfigExpr { items: [] }), filename: "", line: 1, column: 7, end_line: 1, end_column: 9 } }), filename: "", line: 1, column: 0, end_line: 1, end_column: 9 } - "#]], - ); -} - -#[test] -fn schema_expr_1() { - check_parsing_expr( - r####"Schema {k=v}"####, - expect![[r#" - Node { node: Schema(SchemaExpr { name: Node { node: Identifier { names: ["Schema"], pkgpath: "", ctx: Load }, filename: "", line: 1, column: 0, end_line: 1, end_column: 6 }, args: [], kwargs: [], config: Node { node: Config(ConfigExpr { items: [Node { node: ConfigEntry { key: Some(Node { node: Identifier(Identifier { names: ["k"], pkgpath: "", ctx: Load }), filename: "", line: 1, column: 8, end_line: 1, end_column: 9 }), value: Node { node: Identifier(Identifier { names: ["v"], pkgpath: "", ctx: Load }), filename: "", line: 1, column: 10, end_line: 1, end_column: 11 }, operation: Override, insert_index: -1 }, filename: "", line: 1, column: 8, end_line: 1, end_column: 11 }] }), filename: "", line: 1, column: 7, end_line: 1, end_column: 12 } }), filename: "", line: 1, column: 0, end_line: 1, end_column: 12 } - "#]], - ); -} - -#[test] -fn schema_expr_2() { - check_parsing_expr( - r####"Schema () {k=v}"####, - expect![[r#" - Node { node: Schema(SchemaExpr { name: Node { node: Identifier { names: ["Schema"], pkgpath: "", ctx: Load }, filename: "", line: 1, column: 0, end_line: 1, end_column: 6 }, args: [], kwargs: [], config: Node { node: Config(ConfigExpr { items: [Node { node: ConfigEntry { key: Some(Node { node: Identifier(Identifier { names: ["k"], pkgpath: "", ctx: Load }), filename: "", line: 1, column: 11, end_line: 1, end_column: 12 }), value: Node { node: Identifier(Identifier { names: ["v"], pkgpath: "", ctx: Load }), filename: "", line: 1, column: 13, end_line: 1, end_column: 14 }, operation: Override, insert_index: -1 }, filename: "", line: 1, column: 11, end_line: 1, end_column: 14 }] }), filename: "", line: 1, column: 10, end_line: 1, end_column: 15 } }), filename: "", line: 1, column: 0, end_line: 1, end_column: 15 } - "#]], - ); -} - -#[test] -fn schema_expr_3() { - check_parsing_expr( - r####"Schema (1, 2) {k=v}"####, - expect![[r#" - Node { node: Schema(SchemaExpr { name: Node { node: Identifier { names: ["Schema"], pkgpath: "", ctx: Load }, filename: "", line: 1, column: 0, end_line: 1, end_column: 6 }, args: [Node { node: NumberLit(NumberLit { binary_suffix: None, value: Int(1) }), filename: "", line: 1, column: 8, end_line: 1, end_column: 9 }, Node { node: NumberLit(NumberLit { binary_suffix: None, value: Int(2) }), filename: "", line: 1, column: 11, end_line: 1, end_column: 12 }], kwargs: [], config: Node { node: Config(ConfigExpr { items: [Node { node: ConfigEntry { key: Some(Node { node: Identifier(Identifier { names: ["k"], pkgpath: "", ctx: Load }), filename: "", line: 1, column: 15, end_line: 1, end_column: 16 }), value: Node { node: Identifier(Identifier { names: ["v"], pkgpath: "", ctx: Load }), filename: "", line: 1, column: 17, end_line: 1, end_column: 18 }, operation: Override, insert_index: -1 }, filename: "", line: 1, column: 15, end_line: 1, end_column: 18 }] }), filename: "", line: 1, column: 14, end_line: 1, end_column: 19 } }), filename: "", line: 1, column: 0, end_line: 1, end_column: 19 } - "#]], - ); -} - -#[test] -fn schema_expr_4() { - check_parsing_expr( - r####"Schema (1, 2) { - k=v -}"####, - expect![[r#" - Node { node: Schema(SchemaExpr { name: Node { node: Identifier { names: ["Schema"], pkgpath: "", ctx: Load }, filename: "", line: 1, column: 0, end_line: 1, end_column: 6 }, args: [Node { node: NumberLit(NumberLit { binary_suffix: None, value: Int(1) }), filename: "", line: 1, column: 8, end_line: 1, end_column: 9 }, Node { node: NumberLit(NumberLit { binary_suffix: None, value: Int(2) }), filename: "", line: 1, column: 11, end_line: 1, end_column: 12 }], kwargs: [], config: Node { node: Config(ConfigExpr { items: [Node { node: ConfigEntry { key: Some(Node { node: Identifier(Identifier { names: ["k"], pkgpath: "", ctx: Load }), filename: "", line: 2, column: 4, end_line: 2, end_column: 5 }), value: Node { node: Identifier(Identifier { names: ["v"], pkgpath: "", ctx: Load }), filename: "", line: 2, column: 6, end_line: 2, end_column: 7 }, operation: Override, insert_index: -1 }, filename: "", line: 2, column: 4, end_line: 2, end_column: 7 }] }), filename: "", line: 1, column: 14, end_line: 3, end_column: 1 } }), filename: "", line: 1, column: 0, end_line: 3, end_column: 1 } - "#]], - ); -} - -#[test] -fn line_continue() { - check_parsing_expr( - r####"1 + \ -2 -"####, - expect![[r#" - Node { node: Binary(BinaryExpr { left: Node { node: NumberLit(NumberLit { binary_suffix: None, value: Int(1) }), filename: "", line: 1, column: 0, end_line: 1, end_column: 1 }, op: Bin(Add), right: Node { node: NumberLit(NumberLit { binary_suffix: None, value: Int(2) }), filename: "", line: 2, column: 0, end_line: 2, end_column: 1 } }), filename: "", line: 1, column: 0, end_line: 2, end_column: 1 } - "#]], - ); -} - -#[test] -fn test_basic_type() { - check_parsing_type( - r####"bool"####, - expect![[r#" - Node { node: Basic(Bool), filename: "", line: 1, column: 0, end_line: 1, end_column: 4 } - "#]], - ); - check_parsing_type( - r####"int"####, - expect![[r#" - Node { node: Basic(Int), filename: "", line: 1, column: 0, end_line: 1, end_column: 3 } - "#]], - ); - check_parsing_type( - r####"float"####, - expect![[r#" - Node { node: Basic(Float), filename: "", line: 1, column: 0, end_line: 1, end_column: 5 } - "#]], - ); - check_parsing_type( - r####"str"####, - expect![[r#" - Node { node: Basic(Str), filename: "", line: 1, column: 0, end_line: 1, end_column: 3 } - "#]], - ); -} - -#[test] -fn test_any_type() { - check_parsing_type( - r####"any"####, - expect![[r#" - Node { node: Any, filename: "", line: 1, column: 0, end_line: 1, end_column: 3 } - "#]], - ); -} - -#[test] -fn test_list_type() { - check_parsing_type( - r####"[]"####, - expect![[r#" - Node { node: List(ListType { inner_type: None }), filename: "", line: 1, column: 0, end_line: 1, end_column: 2 } - "#]], - ); - check_parsing_type( - r####"[int]"####, - expect![[r#" - Node { node: List(ListType { inner_type: Some(Node { node: Basic(Int), filename: "", line: 1, column: 1, end_line: 1, end_column: 4 }) }), filename: "", line: 1, column: 0, end_line: 1, end_column: 5 } - "#]], - ); - check_parsing_type( - r####"[any]"####, - expect![[r#" - Node { node: List(ListType { inner_type: Some(Node { node: Any, filename: "", line: 1, column: 1, end_line: 1, end_column: 4 }) }), filename: "", line: 1, column: 0, end_line: 1, end_column: 5 } - "#]], - ); - - check_parsing_type( - r####"[[]]"####, - expect![[r#" - Node { node: List(ListType { inner_type: Some(Node { node: List(ListType { inner_type: None }), filename: "", line: 1, column: 1, end_line: 1, end_column: 3 }) }), filename: "", line: 1, column: 0, end_line: 1, end_column: 4 } - "#]], - ); - check_parsing_type( - r####"[[str]]"####, - expect![[r#" - Node { node: List(ListType { inner_type: Some(Node { node: List(ListType { inner_type: Some(Node { node: Basic(Str), filename: "", line: 1, column: 2, end_line: 1, end_column: 5 }) }), filename: "", line: 1, column: 1, end_line: 1, end_column: 6 }) }), filename: "", line: 1, column: 0, end_line: 1, end_column: 7 } - "#]], - ); -} - -#[test] -fn test_dict_type() { - check_parsing_type( - r####"{:}"####, - expect![[r#" - Node { node: Dict(DictType { key_type: None, value_type: None }), filename: "", line: 1, column: 0, end_line: 1, end_column: 3 } - "#]], - ); - check_parsing_type( - r####"{str:}"####, - expect![[r#" - Node { node: Dict(DictType { key_type: Some(Node { node: Basic(Str), filename: "", line: 1, column: 1, end_line: 1, end_column: 4 }), value_type: None }), filename: "", line: 1, column: 0, end_line: 1, end_column: 6 } - "#]], - ); - check_parsing_type( - r####"{:[]}"####, - expect![[r#" - Node { node: Dict(DictType { key_type: None, value_type: Some(Node { node: List(ListType { inner_type: None }), filename: "", line: 1, column: 2, end_line: 1, end_column: 4 }) }), filename: "", line: 1, column: 0, end_line: 1, end_column: 5 } - "#]], - ); - check_parsing_type( - r####"{str:{:float}}"####, - expect![[r#" - Node { node: Dict(DictType { key_type: Some(Node { node: Basic(Str), filename: "", line: 1, column: 1, end_line: 1, end_column: 4 }), value_type: Some(Node { node: Dict(DictType { key_type: None, value_type: Some(Node { node: Basic(Float), filename: "", line: 1, column: 7, end_line: 1, end_column: 12 }) }), filename: "", line: 1, column: 5, end_line: 1, end_column: 13 }) }), filename: "", line: 1, column: 0, end_line: 1, end_column: 14 } - "#]], - ); -} - -#[test] -fn test_union_type() { - check_parsing_type( - r####"int|str"####, - expect![[r#" - Node { node: Union(UnionType { type_elements: [Node { node: Basic(Int), filename: "", line: 1, column: 0, end_line: 1, end_column: 3 }, Node { node: Basic(Str), filename: "", line: 1, column: 4, end_line: 1, end_column: 7 }] }), filename: "", line: 1, column: 0, end_line: 1, end_column: 7 } - "#]], - ); - check_parsing_type( - r####"int | str | [] | {:}"####, - expect![[r#" - Node { node: Union(UnionType { type_elements: [Node { node: Basic(Int), filename: "", line: 1, column: 0, end_line: 1, end_column: 3 }, Node { node: Basic(Str), filename: "", line: 1, column: 6, end_line: 1, end_column: 9 }, Node { node: List(ListType { inner_type: None }), filename: "", line: 1, column: 12, end_line: 1, end_column: 14 }, Node { node: Dict(DictType { key_type: None, value_type: None }), filename: "", line: 1, column: 17, end_line: 1, end_column: 20 }] }), filename: "", line: 1, column: 0, end_line: 1, end_column: 20 } - "#]], - ); -} - -#[test] -fn test_named_type() { - check_parsing_type( - r####"Person"####, - expect![[r#" - Node { node: Named(Identifier { names: ["Person"], pkgpath: "", ctx: Load }), filename: "", line: 1, column: 0, end_line: 1, end_column: 6 } - "#]], - ); - check_parsing_type( - r####"some.pkg.Person"####, - expect![[r#" - Node { node: Named(Identifier { names: ["some", "pkg", "Person"], pkgpath: "", ctx: Load }), filename: "", line: 1, column: 0, end_line: 1, end_column: 15 } - "#]], - ) -} - -#[test] -fn test_literal_type() { - check_parsing_type( - r####"True"####, - expect![[r#" - Node { node: Literal(Bool(true)), filename: "", line: 1, column: 0, end_line: 1, end_column: 4 } - "#]], - ); - check_parsing_type( - r####" False "####, - expect![[r#" - Node { node: Literal(Bool(false)), filename: "", line: 1, column: 1, end_line: 1, end_column: 6 } - "#]], - ); - - check_parsing_type( - r####"123"####, - expect![[r#" - Node { node: Literal(Int(123, None)), filename: "", line: 1, column: 0, end_line: 1, end_column: 3 } - "#]], - ); - - check_parsing_type( - r####"123.0"####, - expect![[r#" - Node { node: Literal(Float(123.0)), filename: "", line: 1, column: 0, end_line: 1, end_column: 5 } - "#]], - ); - - check_parsing_type( - r####""abc""####, - expect![[r#" - Node { node: Literal(Str("abc")), filename: "", line: 1, column: 0, end_line: 1, end_column: 5 } - "#]], - ); - check_parsing_type( - r####"''"####, - expect![[r#" - Node { node: Literal(Str("")), filename: "", line: 1, column: 0, end_line: 1, end_column: 2 } - "#]], - ); -} - -#[test] -fn test_type_str() { - check_type_str(r####"int"####, expect![[r#"int"#]]); - check_type_str(r####" int "####, expect![[r#"int"#]]); - - check_type_str( - r####"bool | True | int | str|str"####, - expect![[r#"bool|True|int|str|str"#]], - ); - check_type_str( - r####"[ [{str: float}] | int]"####, - expect![[r#"[[{str:float}]|int]"#]], - ); -} - -#[test] -fn test_parse_if_stmt() { - check_parsing_file_ast_json( - "hello.k", - r####" -schema TestBool: - [] - [1 - 2, - ] - [str ]: int - "####, - expect![[r#" - {"filename":"hello.k","pkg":"__main__","doc":"","name":"__main__","body":[{"node":{"Schema":{"doc":"","name":{"node":"TestBool","filename":"hello.k","line":2,"column":7,"end_line":2,"end_column":15},"parent_name":null,"for_host_name":null,"is_mixin":false,"is_protocol":false,"args":null,"mixins":[],"body":[{"node":{"Expr":{"exprs":[{"node":{"List":{"elts":[],"ctx":"Load"}},"filename":"hello.k","line":3,"column":4,"end_line":3,"end_column":6}]}},"filename":"hello.k","line":3,"column":4,"end_line":3,"end_column":6},{"node":{"Expr":{"exprs":[{"node":{"List":{"elts":[{"node":{"NumberLit":{"binary_suffix":null,"value":{"Int":1}}},"filename":"hello.k","line":4,"column":5,"end_line":4,"end_column":6},{"node":{"NumberLit":{"binary_suffix":null,"value":{"Int":2}}},"filename":"hello.k","line":5,"column":4,"end_line":5,"end_column":5}],"ctx":"Load"}},"filename":"hello.k","line":4,"column":4,"end_line":6,"end_column":5}]}},"filename":"hello.k","line":4,"column":4,"end_line":6,"end_column":5}],"decorators":[],"checks":[],"index_signature":{"node":{"key_name":null,"key_type":{"node":"str","filename":"hello.k","line":7,"column":5,"end_line":7,"end_column":8},"value_type":{"node":"int","filename":"hello.k","line":7,"column":15,"end_line":7,"end_column":18},"value":null,"any_other":false},"filename":"hello.k","line":7,"column":4,"end_line":8,"end_column":0}}},"filename":"hello.k","line":2,"column":0,"end_line":8,"end_column":8}],"comments":[]} - "#]], - ); -} - -#[test] -fn test_parse_joined_string() { - // todo: fix joined_string - // check_type_stmt( - // r####"a='${123+200}'"####, - // expect![[r#" - // sss - // "#]], - // ); -} - -#[test] -fn test_parse_file() { - let filenames = vec![ - "testdata/assert-01.k", - "testdata/assert-02.k", - "testdata/assert-03.k", - "testdata/assert-if-0.k", - "testdata/assert-if-1.k", - "testdata/assert-if-2.k", - "testdata/assign-01.k", - "testdata/config_expr-01.k", - "testdata/config_expr-02.k", - "testdata/config_expr-03.k", - "testdata/config_expr-04.k", - "testdata/import-01.k", - "testdata/if-01.k", - "testdata/if-02.k", - "testdata/if-03.k", - "testdata/type-01.k", - ]; - for filename in filenames { - let code = std::fs::read_to_string(&filename).unwrap(); - let expect = std::fs::read_to_string(filename.to_string() + ".json").unwrap(); - check_parsing_module( - filename.trim_start_matches("testdata/"), - code.as_str(), - expect.as_str(), - ); +use crate::parse_file_force_errors; +use regex::Regex; + +#[test] +fn test_parse_file_not_found() { + match parse_file_force_errors("The file path is invalid", None) { + Ok(_) => { + panic!("unreachable") + } + Err(err_msg) => { + assert!( + Regex::new(r"^Failed to load KCL file 'The file path is invalid'. Because.*") + .unwrap() + .is_match(&err_msg.to_string()) + ); + } } } - -// TODO: enable file tests after pos & error added. -// #[test] -fn smoke_test_parsing_stmt() { - let code = "a=1"; - let node = Some(Node::dummy_node(Stmt::Assign(AssignStmt { - targets: vec![Box::new(Node::dummy_node(Identifier { - names: vec!["a".to_string()], - pkgpath: "".to_string(), - ctx: ExprContext::Store, - }))], - value: Box::new(Node::dummy_node(Expr::NumberLit(NumberLit { - binary_suffix: None, - value: NumberLitValue::Int(1), - }))), - type_annotation: None, - ty: None, - }))); - - create_session_globals_then(move || { - let sm = SourceMap::new(FilePathMapping::empty()); - sm.new_source_file(PathBuf::from("").into(), code.to_string()); - let sess = &ParseSession::with_source_map(Arc::new(sm)); - - let stream = parse_token_streams(sess, code, BytePos::from_u32(0)); - let mut parser = Parser::new(sess, stream); - let stmt = parser.parse_stmt(); - - let expect = format!("{:?}\n", node); - let got = format!("{:?}\n", stmt); - - assert_eq!(got, expect); - }); -} diff --git a/kclvm/parser/src/parser/ty.rs b/kclvm/parser/src/parser/ty.rs index 0a5548781..c2fac8d19 100644 --- a/kclvm/parser/src/parser/ty.rs +++ b/kclvm/parser/src/parser/ty.rs @@ -8,17 +8,18 @@ use kclvm_ast::token::{BinOpToken, DelimToken, TokenKind}; use kclvm_ast::{ast, expr_as}; use kclvm_span::symbol::{kw, sym}; -impl<'a> Parser<'_> { +impl<'a> Parser<'a> { /// Syntax: /// /// type: type_element (OR type_element)* - /// type_element: schema_type | basic_type | compound_type | literal_type + /// type_element: schema_type | function_type | basic_type | compound_type | literal_type + /// function_type: LEFT_PARENTHESES [type_element (COMMA type_element)*] RIGHT_PARENTHESES [RIGHT_ARROW type_element] /// schema_type: identifier /// basic_type: STRING_TYPE | INT_TYPE | FLOAT_TYPE | BOOL_TYPE | ANY_TYPE /// compound_type: list_type | dict_type /// list_type: LEFT_BRACKETS (type)? RIGHT_BRACKETS /// dict_type: LEFT_BRACE (type)? COLON (type)? RIGHT_BRACE - /// literal_type: string | number | TRUE | FALSE | NONE + /// literal_type: string | number | TRUE | FALSE pub(crate) fn parse_type_annotation(&mut self) -> NodeRef { let token = self.token; let mut type_node_list = vec![self.parse_type_element()]; @@ -58,49 +59,43 @@ impl<'a> Parser<'_> { self.sess.struct_token_loc(token, self.prev_token), )); } - // lit: true/false - if self.token.is_keyword(kw::True) { + else if self.token.is_keyword(kw::True) { self.bump_keyword(kw::True); return Box::new(Node::node( Type::Literal(ast::LiteralType::Bool(true)), self.sess.struct_token_loc(token, self.prev_token), )); - } - if self.token.is_keyword(kw::False) { + } else if self.token.is_keyword(kw::False) { self.bump_keyword(kw::False); return Box::new(Node::node( Type::Literal(ast::LiteralType::Bool(false)), self.sess.struct_token_loc(token, self.prev_token), )); } - // basic type - if self.token.is_keyword(sym::bool) { + else if self.token.is_keyword(sym::bool) { let t = Type::Basic(ast::BasicType::Bool); self.bump_keyword(sym::bool); return Box::new(Node::node( t, self.sess.struct_token_loc(token, self.prev_token), )); - } - if self.token.is_keyword(sym::int) { + } else if self.token.is_keyword(sym::int) { let t = Type::Basic(ast::BasicType::Int); self.bump_keyword(sym::int); return Box::new(Node::node( t, self.sess.struct_token_loc(token, self.prev_token), )); - } - if self.token.is_keyword(sym::float) { + } else if self.token.is_keyword(sym::float) { let t = Type::Basic(ast::BasicType::Float); self.bump_keyword(sym::float); return Box::new(Node::node( t, self.sess.struct_token_loc(token, self.prev_token), )); - } - if self.token.is_keyword(sym::str) { + } else if self.token.is_keyword(sym::str) { let t = Type::Basic(ast::BasicType::Str); self.bump_keyword(sym::str); return Box::new(Node::node( @@ -119,9 +114,8 @@ impl<'a> Parser<'_> { self.sess.struct_token_loc(token, self.prev_token), )); } - // lit type - if let TokenKind::Literal(lit) = self.token.kind { + else if let TokenKind::Literal(lit) = self.token.kind { let t = match lit.kind { token::LitKind::Bool => { if lit.symbol == kw::True { @@ -129,32 +123,40 @@ impl<'a> Parser<'_> { } else if lit.symbol == kw::False { ast::LiteralType::Bool(false) } else { - panic!("invalid lit type: {:?}", self.token); + self.sess + .struct_token_error(&[kw::True.into(), kw::False.into()], self.token); + ast::LiteralType::Bool(false) } } token::LitKind::Integer => { let v = lit.symbol.as_str().parse::().unwrap(); if let Some(suffix) = lit.suffix { - let x = ast::NumberBinarySuffix::try_from(suffix.as_str()); - ast::LiteralType::Int(v, Some(x.unwrap())) + let x = ast::NumberBinarySuffix::try_from(suffix.as_str().as_str()); + ast::LiteralType::Int(ast::IntLiteralType { + value: v, + suffix: Some(x.unwrap()), + }) } else { - ast::LiteralType::Int(v, None) + ast::LiteralType::Int(ast::IntLiteralType { + value: v, + suffix: None, + }) } } token::LitKind::Float => { let v = lit.symbol.as_str().parse::().unwrap(); ast::LiteralType::Float(v) } - token::LitKind::Str { .. } => { - ast::LiteralType::Str(lit.symbol.as_str().to_string()) - } + token::LitKind::Str { .. } => ast::LiteralType::Str(lit.symbol.as_str()), _ => { if self.token.is_keyword(kw::True) { ast::LiteralType::Bool(true) } else if self.token.is_keyword(kw::False) { ast::LiteralType::Bool(false) } else { - panic!("invalid lit type: {:?}", self.token); + self.sess + .struct_token_error(&[kw::True.into(), kw::False.into()], self.token); + ast::LiteralType::Bool(false) } } }; @@ -168,9 +170,8 @@ impl<'a> Parser<'_> { self.sess.struct_token_loc(token, self.prev_token), )); } - // [type] - if let TokenKind::OpenDelim(DelimToken::Bracket) = self.token.kind { + else if let TokenKind::OpenDelim(DelimToken::Bracket) = self.token.kind { self.bump_token(TokenKind::OpenDelim(DelimToken::Bracket)); if let TokenKind::CloseDelim(DelimToken::Bracket) = self.token.kind { @@ -195,9 +196,8 @@ impl<'a> Parser<'_> { )); } } - // {key:value} - if let TokenKind::OpenDelim(DelimToken::Brace) = self.token.kind { + else if let TokenKind::OpenDelim(DelimToken::Brace) = self.token.kind { self.bump_token(TokenKind::OpenDelim(DelimToken::Brace)); let key_type = if let TokenKind::Colon = self.token.kind { @@ -226,7 +226,66 @@ impl<'a> Parser<'_> { self.sess.struct_token_loc(token, self.prev_token), )); } + // (type) -> type + else if let TokenKind::OpenDelim(DelimToken::Paren) = self.token.kind { + self.bump_token(TokenKind::OpenDelim(DelimToken::Paren)); + let mut params_type = vec![]; + // Parse all the params type until the params list end ')' + while self.token.kind != TokenKind::CloseDelim(DelimToken::Paren) + && self.peek_has_next() + { + params_type.push(self.parse_type_annotation()); + // All the params type should be separated by ',' + if let TokenKind::Comma = self.token.kind { + self.bump_token(TokenKind::Comma); + } + } + // If there is no params type, set it to None + let params_ty = if params_type.is_empty() { + None + } else { + Some(params_type) + }; + + self.bump_token(TokenKind::CloseDelim(DelimToken::Paren)); + // If there is a return type, parse it + // Return type start with '->' + let ret_ty = if let TokenKind::RArrow = self.token.kind { + self.bump_token(TokenKind::RArrow); + Some(self.parse_type_annotation()) + } else { + None + }; + + let t = Type::Function(ast::FunctionType { params_ty, ret_ty }); - panic!("invalid type token: {:?}", self.token); + return Box::new(Node::node( + t, + self.sess.struct_token_loc(token, self.prev_token), + )); + } + // Expect type tokens + self.sess.struct_token_error( + &[ + kw::Any.into(), + sym::bool.into(), + sym::int.into(), + sym::float.into(), + sym::str.into(), + kw::True.into(), + kw::False.into(), + TokenKind::ident_value(), + TokenKind::literal_value(), + TokenKind::OpenDelim(DelimToken::Bracket).into(), + TokenKind::OpenDelim(DelimToken::Brace).into(), + TokenKind::CloseDelim(DelimToken::Paren).into(), + ], + self.token, + ); + self.bump(); + Box::new(Node::node( + Type::Any, + self.sess.struct_token_loc(token, self.prev_token), + )) } } diff --git a/kclvm/parser/src/session/mod.rs b/kclvm/parser/src/session/mod.rs index 7e307f8c9..56c8ae50d 100644 --- a/kclvm/parser/src/session/mod.rs +++ b/kclvm/parser/src/session/mod.rs @@ -1,72 +1,123 @@ -use kclvm::{ErrType, PanicInfo}; +use anyhow::Result; +use compiler_base_macros::bug; +use compiler_base_session::Session; +use indexmap::IndexSet; use kclvm_ast::token::Token; -use kclvm_error::{Handler, ParseError, Position}; -use kclvm_span::{Loc, SourceMap, Span}; -use std::cell::RefCell; +use kclvm_error::{Diagnostic, Handler, ParseError, ParseErrorMessage}; +use kclvm_span::{BytePos, Loc, Span}; +use parking_lot::RwLock; use std::sync::Arc; -pub struct ParseSession { - pub source_map: Arc, - pub handler: RefCell, -} +pub type ParseSessionRef = Arc; + +/// ParseSession represents the data associated with a parse session such as the +/// source map and the error handler. +#[derive(Default)] +pub struct ParseSession(pub Arc, pub RwLock); impl ParseSession { - pub fn with_source_map(source_map: Arc) -> Self { - let handler = Handler::with_source_map(source_map.clone()).into(); - Self { - handler, - source_map, - } + /// New a parse session with the global session. + #[inline] + pub fn with_session(sess: Arc) -> Self { + Self(sess, RwLock::new(Handler::default())) + } + + /// Lookup char pos from span. + #[inline] + pub(crate) fn lookup_char_pos(&self, pos: BytePos) -> Loc { + self.0.sm.lookup_char_pos(pos) + } + + /// Returns the source snippet as [String] corresponding to the given [Span]. + #[inline] + pub fn span_to_snippet(&self, span: Span) -> String { + self.0.sm.span_to_snippet(span).unwrap() } - // Struct an loc of first and last valid tokens in an expr, returns a loc tuple + /// Struct an loc of first and last valid tokens in an expr, returns a loc tuple pub fn struct_token_loc(&self, lot: Token, hit: Token) -> (Loc, Loc) { ( - self.source_map.lookup_char_pos(lot.span.lo()), - self.source_map.lookup_char_pos(hit.span.hi()), + self.lookup_char_pos(lot.span.lo()), + self.lookup_char_pos(hit.span.hi()), + ) + } + + /// Construct an loc of ont token. + pub fn token_loc(&self, tok: Token) -> (Loc, Loc) { + ( + self.lookup_char_pos(tok.span.lo()), + self.lookup_char_pos(tok.span.hi()), ) } - /// Struct and report an error based on a token and abort the compiler process. - pub fn struct_token_error(&self, expected: &[String], got: Token) -> ! { - let pos: Position = self.source_map.lookup_char_pos(got.span.lo()).into(); - let err = ParseError::UnexpectedToken { + /// Struct and report an error based on a token and not abort the compiler process. + #[inline] + pub fn struct_token_error(&self, expected: &[String], got: Token) { + self.add_parse_err(ParseError::UnexpectedToken { expected: expected.iter().map(|tok| tok.into()).collect(), got: got.into(), - }; - - let mut panic_info = PanicInfo::default(); - - panic_info.__kcl_PanicInfo__ = true; - panic_info.message = format!("{:?}", err); - panic_info.err_type_code = ErrType::CompileError_TYPE as i32; - - panic_info.kcl_file = pos.filename.clone(); - panic_info.kcl_line = pos.line as i32; - panic_info.kcl_col = pos.column.unwrap_or(0) as i32; - - panic!("{}", panic_info.to_json_string()) + span: got.span, + }); } - /// Struct and report an error based on a span and abort the compiler process. - pub fn struct_span_error(&self, msg: &str, span: Span) -> ! { - let pos: Position = self.source_map.lookup_char_pos(span.lo()).into(); + /// Struct and report an error based on a span and not abort the compiler process. + #[inline] + pub fn struct_span_error(&self, msg: &str, span: Span) { + self.add_parse_err(ParseError::String { + message: msg.to_string(), + span, + }); + } - let mut panic_info = PanicInfo::default(); + #[inline] + pub fn struct_message_error(&self, msg: ParseErrorMessage, span: Span) { + self.add_parse_err(ParseError::Message { + message: msg, + span, + suggestions: None, + }); + } - panic_info.__kcl_PanicInfo__ = true; - panic_info.message = format!("Invalid syntax: {}", msg); - panic_info.err_type_code = ErrType::CompileError_TYPE as i32; + #[inline] + pub fn struct_message_error_with_suggestions( + &self, + msg: ParseErrorMessage, + span: Span, + suggestions: Option>, + ) { + self.add_parse_err(ParseError::Message { + message: msg, + span, + suggestions, + }); + } - panic_info.kcl_file = pos.filename.clone(); - panic_info.kcl_line = pos.line as i32; - panic_info.kcl_col = pos.column.unwrap_or(0) as i32; + /// Add a error into the session. + #[inline] + fn add_parse_err(&self, err: ParseError) { + let add_error = || -> Result<()> { + self.0.add_err(err.clone().into_diag(&self.0)?)?; + self.1.write().add_diagnostic(err.into_diag(&self.0)?); + Ok(()) + }; + if let Err(err) = add_error() { + bug!( + "compiler session internal error occurs: {}", + err.to_string() + ) + } + } - panic!("{}", panic_info.to_json_string()) + /// Append diagnostics into the parse session. + pub fn append_diagnostic(&self, diagnostics: IndexSet) -> &Self { + for diagnostic in diagnostics { + self.1.write().add_diagnostic(diagnostic); + } + self } - /// Report a compiler bug - pub fn struct_compiler_bug(&self, msg: &str) -> ! { - self.handler.borrow_mut().bug(msg) + /// Classify diagnostics into errors and warnings. + pub fn classification(&self) -> (IndexSet, IndexSet) { + self.1.read().classification() } } diff --git a/kclvm/parser/src/testdata/multimods/kcl1/kcl.mod b/kclvm/parser/src/testdata/multimods/kcl1/kcl.mod new file mode 100644 index 000000000..ab572545d --- /dev/null +++ b/kclvm/parser/src/testdata/multimods/kcl1/kcl.mod @@ -0,0 +1,5 @@ +[package] +name = "kcl1" +edition = "0.0.1" +version = "0.0.1" + diff --git a/kclvm/parser/src/testdata/multimods/kcl1/main.k b/kclvm/parser/src/testdata/multimods/kcl1/main.k new file mode 100644 index 000000000..f44f8ed9f --- /dev/null +++ b/kclvm/parser/src/testdata/multimods/kcl1/main.k @@ -0,0 +1 @@ +The_first_kcl_program_1 = 'Hello World 1!' \ No newline at end of file diff --git a/kclvm/parser/src/testdata/multimods/kcl2/kcl.mod b/kclvm/parser/src/testdata/multimods/kcl2/kcl.mod new file mode 100644 index 000000000..5fb058acd --- /dev/null +++ b/kclvm/parser/src/testdata/multimods/kcl2/kcl.mod @@ -0,0 +1,5 @@ +[package] +name = "kcl2" +edition = "0.0.1" +version = "0.0.1" + diff --git a/kclvm/parser/src/testdata/multimods/kcl2/main.k b/kclvm/parser/src/testdata/multimods/kcl2/main.k new file mode 100644 index 000000000..ae85392dc --- /dev/null +++ b/kclvm/parser/src/testdata/multimods/kcl2/main.k @@ -0,0 +1 @@ +The_first_kcl_program_2 = 'Hello World 2!' \ No newline at end of file diff --git a/kclvm/parser/src/testdata/pkg_not_found/suggestions.k b/kclvm/parser/src/testdata/pkg_not_found/suggestions.k new file mode 100644 index 000000000..0655110e0 --- /dev/null +++ b/kclvm/parser/src/testdata/pkg_not_found/suggestions.k @@ -0,0 +1,3 @@ +import k9s + +a = k9s.a \ No newline at end of file diff --git a/kclvm/parser/src/testdata/test_k_code_list/main.k b/kclvm/parser/src/testdata/test_k_code_list/main.k new file mode 100644 index 000000000..deeb74230 --- /dev/null +++ b/kclvm/parser/src/testdata/test_k_code_list/main.k @@ -0,0 +1 @@ +test = "test" \ No newline at end of file diff --git a/kclvm/parser/src/testdata/test_k_code_list/main1.k b/kclvm/parser/src/testdata/test_k_code_list/main1.k new file mode 100644 index 000000000..d93edb624 --- /dev/null +++ b/kclvm/parser/src/testdata/test_k_code_list/main1.k @@ -0,0 +1 @@ +test1 = "test1" \ No newline at end of file diff --git a/kclvm/parser/src/tests.rs b/kclvm/parser/src/tests.rs index e81550767..b09c17829 100644 --- a/kclvm/parser/src/tests.rs +++ b/kclvm/parser/src/tests.rs @@ -1,106 +1,872 @@ -use std::panic::catch_unwind; +use std::{ + env, + panic::{catch_unwind, set_hook}, + path::Path, +}; + +use compiler_base_span::{FilePathMapping, SourceMap}; +use entry::expand_input_files; +use kclvm_config::modfile::{get_vendor_home, KCL_PKG_PATH}; use crate::*; -use expect_test::{expect, Expect}; use core::any::Any; -fn check_parsing_file_ast_json(filename: &str, src: &str, expect: Expect) { - let m = parse_file(filename, Some(src.into())).unwrap(); - let actual = serde_json::ser::to_string(&m).unwrap(); - let actual = format!("{}\n", actual); - expect.assert_eq(&actual) +mod ast; +mod error_recovery; +mod expr; +mod file; +mod types; + +#[macro_export] +macro_rules! parse_expr_snapshot { + ($name:ident, $src:expr) => { + #[test] + fn $name() { + insta::assert_snapshot!($crate::tests::parsing_expr_string($src)); + } + }; +} + +#[macro_export] +macro_rules! parse_module_snapshot { + ($name:ident, $src:expr) => { + #[test] + fn $name() { + insta::assert_snapshot!($crate::tests::parsing_module_string($src)); + } + }; } -fn check_load_program_ast_json(files: &[&str], opts: Option, expect: Expect) { - let prog = load_program(&files, opts).unwrap(); - let actual = serde_json::ser::to_string(&prog).unwrap(); - let actual = format!("{}\n", actual); - expect.assert_eq(&actual) +#[macro_export] +macro_rules! parse_type_snapshot { + ($name:ident, $src:expr) => { + #[test] + fn $name() { + insta::assert_snapshot!($crate::tests::parsing_type_string($src)); + } + }; +} + +#[macro_export] +macro_rules! parse_type_node_snapshot { + ($name:ident, $src:expr) => { + #[test] + fn $name() { + insta::assert_snapshot!($crate::tests::parsing_type_node_string($src)); + } + }; +} + +#[macro_export] +macro_rules! parse_file_ast_json_snapshot { + ($name:ident, $filename:expr, $src:expr) => { + #[test] + fn $name() { + insta::assert_snapshot!($crate::tests::parsing_file_ast_json($filename, $src)); + } + }; +} + +#[macro_export] +macro_rules! parse_file_snapshot { + ($name:ident, $filename:expr) => { + #[test] + fn $name() { + insta::assert_snapshot!($crate::tests::parsing_file_string($filename)); + } + }; +} + +pub(crate) fn parsing_expr_string(src: &str) -> String { + let sm = SourceMap::new(FilePathMapping::empty()); + let sf = sm.new_source_file(PathBuf::from("").into(), src.to_string()); + let sess = &ParseSession::with_source_map(Arc::new(sm)); + + match sf.src.as_ref() { + Some(src_from_sf) => create_session_globals_then(|| { + let stream = parse_token_streams(sess, src_from_sf.as_str(), new_byte_pos(0)); + let mut parser = Parser::new(sess, stream); + let expr = parser.parse_expr(); + format!("{expr:#?}\n") + }), + None => "".to_string(), + } +} + +pub(crate) fn parsing_module_string(src: &str) -> String { + let sm = SourceMap::new(FilePathMapping::empty()); + let sf = sm.new_source_file(PathBuf::from("").into(), src.to_string()); + let sess = &ParseSession::with_source_map(Arc::new(sm)); + + match sf.src.as_ref() { + Some(src_from_sf) => create_session_globals_then(|| { + let stream = parse_token_streams(sess, src_from_sf.as_str(), new_byte_pos(0)); + let mut parser = Parser::new(sess, stream); + let module = parser.parse_module(); + format!("{module:#?}\n") + }), + None => "".to_string(), + } +} + +pub(crate) fn parsing_type_string(src: &str) -> String { + let sm = SourceMap::new(FilePathMapping::empty()); + sm.new_source_file(PathBuf::from("").into(), src.to_string()); + let sess = &ParseSession::with_source_map(Arc::new(sm)); + + create_session_globals_then(|| { + let stream = parse_token_streams(sess, src, new_byte_pos(0)); + let mut parser = Parser::new(sess, stream); + let typ = parser.parse_type_annotation(); + format!("{typ:#?}\n") + }) +} + +pub(crate) fn parsing_type_node_string(src: &str) -> String { + let sm = SourceMap::new(FilePathMapping::empty()); + sm.new_source_file(PathBuf::from("").into(), src.to_string()); + let sess = &ParseSession::with_source_map(Arc::new(sm)); + + create_session_globals_then(|| { + let stream = parse_token_streams(sess, src, new_byte_pos(0)); + let mut parser = Parser::new(sess, stream); + let typ = parser.parse_type_annotation(); + typ.node.to_string() + }) +} + +pub(crate) fn parsing_file_ast_json(filename: &str, src: &str) -> String { + let m = crate::parse_file_with_global_session( + Arc::new(ParseSession::default()), + filename, + Some(src.into()), + ) + .unwrap(); + serde_json::ser::to_string_pretty(&m).unwrap() +} + +pub(crate) fn parsing_file_string(filename: &str) -> String { + let code = std::fs::read_to_string(filename).unwrap(); + let m = crate::parse_single_file(filename.trim_start_matches("testdata/"), Some(code)) + .expect(filename) + .module; + serde_json::ser::to_string_pretty(&m).unwrap() +} + +pub fn check_result_panic_info(result: Result<(), Box>) { + if let Err(e) = result { + assert!(e.downcast::().is_ok()); + }; +} + +const PARSE_EXPR_INVALID_TEST_CASES: &[&str] = + &["fs1_i1re1~s", "fh==-h==-", "8_________i", "1MM", "0x00x"]; + +#[test] +pub fn test_parse_expr_invalid() { + for case in PARSE_EXPR_INVALID_TEST_CASES { + set_hook(Box::new(|_| {})); + let result = catch_unwind(|| { + parse_expr(case); + }); + check_result_panic_info(result); + } +} + +const PARSE_FILE_INVALID_TEST_CASES: &[&str] = &[ + "a: int", // No initial value error + "a -", // Invalid binary expression error + "a?: int", // Invalid optional annotation error + "if a not is not b: a = 1", // Logic operator error + "if True:\n a=1\n b=2", // Indent error with recovery + "a[1::::]", // List slice error + "a[1 a]", // List index error + "{a ++ 1}", // Config attribute operator error + "func(a=1,b)", // Call argument error + "'${}'", // Empty string interpolation error + "'${a: jso}'", // Invalid string interpolation format spec error +]; + +#[test] +pub fn test_parse_file_invalid() { + for case in PARSE_FILE_INVALID_TEST_CASES { + let result = parse_file_force_errors("test.k", Some((&case).to_string())); + assert!(result.is_err(), "case: {case}, result {result:?}"); + } +} + +pub fn test_vendor_home() { + let vendor = &PathBuf::from(".") + .join("testdata") + .join("test_vendor") + .canonicalize() + .unwrap() + .display() + .to_string() + .adjust_canonicalization(); + env::set_var(KCL_PKG_PATH, vendor); + assert_eq!(get_vendor_home(), vendor.to_string()); +} + +fn set_vendor_home() -> String { + // set env vendor + let vendor = &PathBuf::from(".") + .join("testdata") + .join("test_vendor") + .canonicalize() + .unwrap() + .display() + .to_string() + .adjust_canonicalization(); + env::set_var(KCL_PKG_PATH, vendor); + debug_assert_eq!(get_vendor_home(), vendor.to_string()); + vendor.to_string() } #[test] -fn test_parse_file() { - check_parsing_file_ast_json( - "hello.k", - r####"a=123"####, - expect![[r#" - {"filename":"hello.k","pkg":"__main__","doc":"","name":"__main__","body":[{"node":{"Assign":{"targets":[{"node":{"names":["a"],"pkgpath":"","ctx":"Store"},"filename":"hello.k","line":1,"column":0,"end_line":1,"end_column":1}],"value":{"node":{"NumberLit":{"binary_suffix":null,"value":{"Int":123}}},"filename":"hello.k","line":1,"column":2,"end_line":1,"end_column":5},"type_annotation":null}},"filename":"hello.k","line":1,"column":0,"end_line":1,"end_column":5}],"comments":[]} - "#]], +/// The testing will set environment variables, +/// so can not to execute test cases concurrently. +fn test_in_order() { + test_import_vendor_by_external_arguments(); + println!("{:?} PASS", "test_import_vendor_by_external_arguments"); + test_import_vendor_without_vendor_home(); + println!("{:?} PASS", "test_import_vendor_without_vendor_home"); + test_import_vendor_without_kclmod(); + println!("{:?} PASS", "test_import_vendor_without_kclmod"); + test_import_vendor(); + println!("{:?} PASS", "test_import_vendor"); + test_import_vendor_with_same_internal_pkg(); + println!("{:?} PASS", "test_import_vendor_with_same_internal_pkg"); + test_import_vendor_without_kclmod_and_same_name(); + println!( + "{:?} PASS", + "test_import_vendor_without_kclmod_and_same_name" ); + test_vendor_home(); + println!("{:?} PASS", "test_vendor_home"); + test_pkg_not_found_suggestion(); + println!("{:?} PASS", "test_pkg_not_found_suggestion"); +} + +pub fn test_import_vendor() { + let module_cache = KCLModuleCache::default(); + let vendor = set_vendor_home(); + let sm = SourceMap::new(FilePathMapping::empty()); + let sess = Arc::new(ParseSession::with_source_map(Arc::new(sm))); + + let test_cases = vec![ + ("assign.k", vec!["__main__", "assign", "assign.assign"]), + ( + "config_expr.k", + vec!["__main__", "config_expr", "config_expr.config_expr_02"], + ), + ( + "nested_vendor.k", + vec![ + "__main__", + "nested_vendor", + "nested_vendor.nested_vendor", + "vendor_subpkg", + "vendor_subpkg.sub.sub1", + "vendor_subpkg.sub.sub2", + "vendor_subpkg.sub.sub", + "vendor_subpkg.sub", + ], + ), + ( + "subpkg.k", + vec![ + "__main__", + "vendor_subpkg", + "vendor_subpkg.sub.sub1", + "vendor_subpkg.sub.sub", + "vendor_subpkg.sub.sub2", + "vendor_subpkg.sub", + ], + ), + ]; + + let dir = &PathBuf::from(".") + .join("testdata") + .join("import_vendor") + .canonicalize() + .unwrap(); + + let test_fn = + |test_case_name: &&str, pkgs: &Vec<&str>, module_cache: Option| { + let test_case_path = dir + .join(test_case_name) + .display() + .to_string() + .adjust_canonicalization(); + let m = load_program(sess.clone(), &[&test_case_path], None, module_cache) + .unwrap() + .program; + assert_eq!(m.pkgs.len(), pkgs.len()); + m.pkgs.clone().into_iter().for_each(|(name, modules)| { + println!("{:?} - {:?}", test_case_name, name); + assert!(pkgs.contains(&name.as_str())); + for pkg in pkgs.clone() { + if name == pkg { + if name == "__main__" { + assert_eq!(modules.len(), 1); + let module = m.get_module(modules.get(0).unwrap()).unwrap().unwrap(); + assert_eq!(module.filename, test_case_path); + } else { + modules.into_iter().for_each(|module| { + let module = m.get_module(&module).unwrap().unwrap(); + assert!(module.filename.contains(&vendor)); + }); + } + break; + } + } + }); + }; + + test_cases + .iter() + .for_each(|(test_case_name, pkgs)| test_fn(test_case_name, pkgs, None)); + + test_cases.iter().for_each(|(test_case_name, pkgs)| { + test_fn(test_case_name, pkgs, Some(module_cache.clone())) + }); +} + +pub fn test_import_vendor_without_kclmod() { + let vendor = set_vendor_home(); + let sm = SourceMap::new(FilePathMapping::empty()); + let sess = Arc::new(ParseSession::with_source_map(Arc::new(sm))); + + let test_cases = vec![("import_vendor.k", vec!["__main__", "assign.assign"])]; + + let dir = &PathBuf::from(".") + .join("testdata_without_kclmod") + .canonicalize() + .unwrap(); + + test_cases.into_iter().for_each(|(test_case_name, pkgs)| { + let test_case_path = dir + .join(test_case_name) + .display() + .to_string() + .adjust_canonicalization(); + let m = load_program(sess.clone(), &[&test_case_path], None, None) + .unwrap() + .program; + assert_eq!(m.pkgs.len(), pkgs.len()); + m.pkgs.clone().into_iter().for_each(|(name, modules)| { + assert!(pkgs.contains(&name.as_str())); + for pkg in pkgs.clone() { + if name == pkg { + if name == "__main__" { + assert_eq!(modules.len(), 1); + let module = m.get_module(modules.get(0).unwrap()).unwrap().unwrap(); + assert_eq!(module.filename, test_case_path); + } else { + modules.into_iter().for_each(|module| { + let module = m.get_module(&module).unwrap().unwrap(); + assert!(module.filename.contains(&vendor)); + }); + } + break; + } + } + }); + }); +} + +pub fn test_import_vendor_without_vendor_home() { + env::set_var(KCL_PKG_PATH, ""); + let sm = SourceMap::new(FilePathMapping::empty()); + let sess = Arc::new(ParseSession::with_source_map(Arc::new(sm))); + let dir = &PathBuf::from(".") + .join("testdata") + .join("import_vendor") + .canonicalize() + .unwrap(); + let test_case_path = dir.join("assign.k").display().to_string(); + match load_program(sess.clone(), &[&test_case_path], None, None) { + Ok(_) => { + let errors = sess.classification().0; + let msgs = [ + "pkgpath assign not found in the program", + "try 'kcl mod add assign' to download the missing package", + "browse more packages at 'https://artifacthub.io'", + "pkgpath assign.assign not found in the program", + ]; + assert_eq!(errors.len(), msgs.len()); + for (diag, m) in errors.iter().zip(msgs.iter()) { + assert_eq!(diag.messages[0].message, m.to_string()); + } + } + Err(_) => { + panic!("Unreachable code.") + } + } + + match load_program( + sess.clone(), + &[&test_case_path], + None, + Some(KCLModuleCache::default()), + ) { + Ok(_) => { + let errors = sess.classification().0; + let msgs = [ + "pkgpath assign not found in the program", + "try 'kcl mod add assign' to download the missing package", + "browse more packages at 'https://artifacthub.io'", + "pkgpath assign.assign not found in the program", + ]; + assert_eq!(errors.len(), msgs.len()); + for (diag, m) in errors.iter().zip(msgs.iter()) { + assert_eq!(diag.messages[0].message, m.to_string()); + } + } + Err(_) => { + panic!("Unreachable code.") + } + } +} + +fn test_import_vendor_with_same_internal_pkg() { + set_vendor_home(); + let sm = SourceMap::new(FilePathMapping::empty()); + let sess = Arc::new(ParseSession::with_source_map(Arc::new(sm))); + let dir = &PathBuf::from(".") + .join("testdata") + .join("import_vendor") + .canonicalize() + .unwrap(); + let test_case_path = dir.join("same_name.k").display().to_string(); + match load_program(sess.clone(), &[&test_case_path], None, None) { + Ok(_) => { + let errors = sess.classification().0; + let msgs = [ + "the `same_vendor` is found multiple times in the current package and vendor package" + ]; + assert_eq!(errors.len(), msgs.len()); + for (diag, m) in errors.iter().zip(msgs.iter()) { + assert_eq!(diag.messages[0].message, m.to_string()); + } + } + Err(_) => { + panic!("Unreachable code.") + } + } + match load_program( + sess.clone(), + &[&test_case_path], + None, + Some(KCLModuleCache::default()), + ) { + Ok(_) => { + let errors = sess.classification().0; + let msgs = [ + "the `same_vendor` is found multiple times in the current package and vendor package" + ]; + assert_eq!(errors.len(), msgs.len()); + for (diag, m) in errors.iter().zip(msgs.iter()) { + assert_eq!(diag.messages[0].message, m.to_string()); + } + } + Err(_) => { + panic!("Unreachable code.") + } + } +} + +fn test_import_vendor_without_kclmod_and_same_name() { + set_vendor_home(); + let sm = SourceMap::new(FilePathMapping::empty()); + let sess = Arc::new(ParseSession::with_source_map(Arc::new(sm))); + let dir = &PathBuf::from(".") + .join("testdata_without_kclmod") + .join("same_name") + .canonicalize() + .unwrap(); + let test_case_path = dir.join("assign.k").display().to_string(); + match load_program(sess.clone(), &[&test_case_path], None, None) { + Ok(_) => { + let errors = sess.classification().0; + let msgs = [ + "the `assign` is found multiple times in the current package and vendor package", + ]; + assert_eq!(errors.len(), msgs.len()); + for (diag, m) in errors.iter().zip(msgs.iter()) { + assert_eq!(diag.messages[0].message, m.to_string()); + } + } + Err(_) => { + panic!("Unreachable code.") + } + } + + match load_program( + sess.clone(), + &[&test_case_path], + None, + Some(KCLModuleCache::default()), + ) { + Ok(_) => { + let errors = sess.classification().0; + let msgs = [ + "the `assign` is found multiple times in the current package and vendor package", + ]; + assert_eq!(errors.len(), msgs.len()); + for (diag, m) in errors.iter().zip(msgs.iter()) { + assert_eq!(diag.messages[0].message, m.to_string()); + } + } + Err(_) => { + panic!("Unreachable code.") + } + } +} + +fn test_import_vendor_by_external_arguments() { + let vendor = set_vendor_home(); + let sm = SourceMap::new(FilePathMapping::empty()); + let sess = Arc::new(ParseSession::with_source_map(Arc::new(sm))); + let module_cache = KCLModuleCache::default(); + let external_dir = &PathBuf::from(".") + .join("testdata") + .join("test_vendor") + .canonicalize() + .unwrap(); + + let test_cases = vec![ + ( + "import_by_external_assign.k", + "assign", + vec!["__main__", "assign"], + ), + ( + "import_by_external_config_expr.k", + "config_expr", + vec!["__main__", "config_expr"], + ), + ( + "import_by_external_nested_vendor.k", + "nested_vendor", + vec![ + "__main__", + "nested_vendor", + "vendor_subpkg", + "vendor_subpkg.sub.sub2", + "vendor_subpkg.sub.sub1", + "vendor_subpkg.sub.sub", + "vendor_subpkg.sub", + ], + ), + ( + "import_by_external_vendor_subpkg.k", + "vendor_subpkg", + vec![ + "__main__", + "vendor_subpkg", + "vendor_subpkg.sub.sub1", + "vendor_subpkg.sub.sub2", + "vendor_subpkg.sub.sub", + "vendor_subpkg.sub", + ], + ), + ]; + + let dir = &PathBuf::from(".") + .join("testdata_without_kclmod") + .canonicalize() + .unwrap(); + + let test_fn = |test_case_name: &&str, + dep_name: &&str, + pkgs: &Vec<&str>, + module_cache: Option| { + let mut opts = LoadProgramOptions::default(); + opts.package_maps.insert( + dep_name.to_string(), + external_dir.join(dep_name).display().to_string(), + ); + let test_case_path = dir + .join(test_case_name) + .display() + .to_string() + .adjust_canonicalization(); + let m = load_program(sess.clone(), &[&test_case_path], None, module_cache) + .unwrap() + .program; + assert_eq!(m.pkgs.len(), pkgs.len()); + m.pkgs.clone().into_iter().for_each(|(name, modules)| { + assert!(pkgs.contains(&name.as_str())); + for pkg in pkgs.clone() { + if name == pkg { + if name == "__main__" { + assert_eq!(modules.len(), 1); + let module = m.get_module(modules.get(0).unwrap()).unwrap().unwrap(); + assert_eq!(module.filename, test_case_path); + } else { + modules.into_iter().for_each(|module| { + let module = m.get_module(&module).unwrap().unwrap(); + assert!(module.filename.contains(&vendor)); + }); + } + break; + } + } + }); + }; + + test_cases + .iter() + .for_each(|(test_case_name, dep_name, pkgs)| test_fn(test_case_name, dep_name, pkgs, None)); + + test_cases + .iter() + .for_each(|(test_case_name, dep_name, pkgs)| { + test_fn(test_case_name, dep_name, pkgs, Some(module_cache.clone())) + }); } #[test] -fn test_parse_if_stmt() { - check_parsing_file_ast_json( - "hello.k", - r####" -a = 10 -b = 12 -_condition = 0 -if a == 11 or b == 13: _condition = 1 -elif a == 10 and b == 12: _condition = 2 -condition = _condition - "####, - expect![[r#" - {"filename":"hello.k","pkg":"__main__","doc":"","name":"__main__","body":[{"node":{"Assign":{"targets":[{"node":{"names":["a"],"pkgpath":"","ctx":"Store"},"filename":"hello.k","line":2,"column":0,"end_line":2,"end_column":1}],"value":{"node":{"NumberLit":{"binary_suffix":null,"value":{"Int":10}}},"filename":"hello.k","line":2,"column":4,"end_line":2,"end_column":6},"type_annotation":null}},"filename":"hello.k","line":2,"column":0,"end_line":3,"end_column":0},{"node":{"Assign":{"targets":[{"node":{"names":["b"],"pkgpath":"","ctx":"Store"},"filename":"hello.k","line":3,"column":0,"end_line":3,"end_column":1}],"value":{"node":{"NumberLit":{"binary_suffix":null,"value":{"Int":12}}},"filename":"hello.k","line":3,"column":4,"end_line":3,"end_column":6},"type_annotation":null}},"filename":"hello.k","line":3,"column":0,"end_line":4,"end_column":0},{"node":{"Assign":{"targets":[{"node":{"names":["_condition"],"pkgpath":"","ctx":"Store"},"filename":"hello.k","line":4,"column":0,"end_line":4,"end_column":10}],"value":{"node":{"NumberLit":{"binary_suffix":null,"value":{"Int":0}}},"filename":"hello.k","line":4,"column":13,"end_line":4,"end_column":14},"type_annotation":null}},"filename":"hello.k","line":4,"column":0,"end_line":5,"end_column":0},{"node":{"If":{"body":[{"node":{"Assign":{"targets":[{"node":{"names":["_condition"],"pkgpath":"","ctx":"Store"},"filename":"hello.k","line":5,"column":23,"end_line":5,"end_column":33}],"value":{"node":{"NumberLit":{"binary_suffix":null,"value":{"Int":1}}},"filename":"hello.k","line":5,"column":36,"end_line":5,"end_column":37},"type_annotation":null}},"filename":"hello.k","line":5,"column":23,"end_line":6,"end_column":0}],"cond":{"node":{"Binary":{"left":{"node":{"Compare":{"left":{"node":{"Identifier":{"names":["a"],"pkgpath":"","ctx":"Load"}},"filename":"hello.k","line":5,"column":3,"end_line":5,"end_column":4},"ops":["Eq"],"comparators":[{"node":{"NumberLit":{"binary_suffix":null,"value":{"Int":11}}},"filename":"hello.k","line":5,"column":8,"end_line":5,"end_column":10}]}},"filename":"hello.k","line":5,"column":3,"end_line":5,"end_column":21},"op":{"Bin":"Or"},"right":{"node":{"Compare":{"left":{"node":{"Identifier":{"names":["b"],"pkgpath":"","ctx":"Load"}},"filename":"hello.k","line":5,"column":14,"end_line":5,"end_column":15},"ops":["Eq"],"comparators":[{"node":{"NumberLit":{"binary_suffix":null,"value":{"Int":13}}},"filename":"hello.k","line":5,"column":19,"end_line":5,"end_column":21}]}},"filename":"hello.k","line":5,"column":14,"end_line":5,"end_column":21}}},"filename":"hello.k","line":5,"column":3,"end_line":5,"end_column":21},"orelse":[{"node":{"If":{"body":[{"node":{"Assign":{"targets":[{"node":{"names":["_condition"],"pkgpath":"","ctx":"Store"},"filename":"hello.k","line":6,"column":26,"end_line":6,"end_column":36}],"value":{"node":{"NumberLit":{"binary_suffix":null,"value":{"Int":2}}},"filename":"hello.k","line":6,"column":39,"end_line":6,"end_column":40},"type_annotation":null}},"filename":"hello.k","line":6,"column":26,"end_line":7,"end_column":0}],"cond":{"node":{"Binary":{"left":{"node":{"Compare":{"left":{"node":{"Identifier":{"names":["a"],"pkgpath":"","ctx":"Load"}},"filename":"hello.k","line":6,"column":5,"end_line":6,"end_column":6},"ops":["Eq"],"comparators":[{"node":{"NumberLit":{"binary_suffix":null,"value":{"Int":10}}},"filename":"hello.k","line":6,"column":10,"end_line":6,"end_column":12}]}},"filename":"hello.k","line":6,"column":5,"end_line":6,"end_column":24},"op":{"Bin":"And"},"right":{"node":{"Compare":{"left":{"node":{"Identifier":{"names":["b"],"pkgpath":"","ctx":"Load"}},"filename":"hello.k","line":6,"column":17,"end_line":6,"end_column":18},"ops":["Eq"],"comparators":[{"node":{"NumberLit":{"binary_suffix":null,"value":{"Int":12}}},"filename":"hello.k","line":6,"column":22,"end_line":6,"end_column":24}]}},"filename":"hello.k","line":6,"column":17,"end_line":6,"end_column":24}}},"filename":"hello.k","line":6,"column":5,"end_line":6,"end_column":24},"orelse":[]}},"filename":"hello.k","line":6,"column":0,"end_line":7,"end_column":0}]}},"filename":"hello.k","line":5,"column":0,"end_line":7,"end_column":0},{"node":{"Assign":{"targets":[{"node":{"names":["condition"],"pkgpath":"","ctx":"Store"},"filename":"hello.k","line":7,"column":0,"end_line":7,"end_column":9}],"value":{"node":{"Identifier":{"names":["_condition"],"pkgpath":"","ctx":"Load"}},"filename":"hello.k","line":7,"column":12,"end_line":7,"end_column":22},"type_annotation":null}},"filename":"hello.k","line":7,"column":0,"end_line":8,"end_column":0}],"comments":[]} - "#]], +fn test_get_compile_entries_from_paths() { + let testpath = PathBuf::from("./src/testdata/multimods") + .canonicalize() + .unwrap(); + + // [`kcl1_path`] is a normal path of the package [`kcl1`] root directory. + // It looks like `/xxx/xxx/xxx`. + let kcl1_path = testpath.join("kcl1"); + + // [`kcl2_path`] is a mod relative path of the packege [`kcl2`] root directory. + // It looks like `${kcl2:KCL_MOD}/xxx/xxx` + let kcl2_path = PathBuf::from("${kcl2:KCL_MOD}/main.k"); + + // [`kcl3_path`] is a mod relative path of the [`__main__`] packege. + let kcl3_path = PathBuf::from("${KCL_MOD}/main.k"); + + // [`package_maps`] is a map to show the real path of the mod relative path [`kcl2`]. + let mut opts = LoadProgramOptions::default(); + opts.package_maps.insert( + "kcl2".to_string(), + testpath.join("kcl2").to_str().unwrap().to_string(), + ); + + // [`get_compile_entries_from_paths`] will return the map of package name to package root real path. + let entries = get_compile_entries_from_paths( + &[ + kcl1_path.to_str().unwrap().to_string(), + kcl2_path.display().to_string(), + kcl3_path.display().to_string(), + ], + &opts, + ) + .unwrap(); + + assert_eq!(entries.len(), 3); + + assert_eq!(entries.get_nth_entry(0).unwrap().name(), "__main__"); + assert_eq!( + PathBuf::from(entries.get_nth_entry(0).unwrap().path()) + .canonicalize() + .unwrap() + .display() + .to_string(), + kcl1_path.canonicalize().unwrap().to_str().unwrap() ); - check_parsing_file_ast_json( - "hello.k", - r####" -data2 = { - **{key = "value1"} - if a == 123: if b == 456: key = "value2" -} - "####, - expect![[r#" - {"filename":"hello.k","pkg":"__main__","doc":"","name":"__main__","body":[{"node":{"Assign":{"targets":[{"node":{"names":["data2"],"pkgpath":"","ctx":"Store"},"filename":"hello.k","line":2,"column":0,"end_line":2,"end_column":5}],"value":{"node":{"Config":{"items":[{"node":{"key":null,"value":{"node":{"Config":{"items":[{"node":{"key":{"node":{"Identifier":{"names":["key"],"pkgpath":"","ctx":"Load"}},"filename":"hello.k","line":3,"column":7,"end_line":3,"end_column":10},"value":{"node":{"StringLit":{"is_long_string":false,"raw_value":"\"value1\"","value":"value1"}},"filename":"hello.k","line":3,"column":13,"end_line":3,"end_column":21},"operation":"Override","insert_index":-1},"filename":"hello.k","line":3,"column":7,"end_line":3,"end_column":21}]}},"filename":"hello.k","line":3,"column":6,"end_line":3,"end_column":22},"operation":"Union","insert_index":-1},"filename":"hello.k","line":3,"column":4,"end_line":3,"end_column":22},{"node":{"key":null,"value":{"node":{"ConfigIfEntry":{"if_cond":{"node":{"Compare":{"left":{"node":{"Identifier":{"names":["a"],"pkgpath":"","ctx":"Load"}},"filename":"hello.k","line":4,"column":7,"end_line":4,"end_column":8},"ops":["Eq"],"comparators":[{"node":{"NumberLit":{"binary_suffix":null,"value":{"Int":123}}},"filename":"hello.k","line":4,"column":12,"end_line":4,"end_column":15}]}},"filename":"hello.k","line":4,"column":7,"end_line":4,"end_column":15},"items":[{"node":{"key":null,"value":{"node":{"ConfigIfEntry":{"if_cond":{"node":{"Compare":{"left":{"node":{"Identifier":{"names":["b"],"pkgpath":"","ctx":"Load"}},"filename":"hello.k","line":4,"column":20,"end_line":4,"end_column":21},"ops":["Eq"],"comparators":[{"node":{"NumberLit":{"binary_suffix":null,"value":{"Int":456}}},"filename":"hello.k","line":4,"column":25,"end_line":4,"end_column":28}]}},"filename":"hello.k","line":4,"column":20,"end_line":4,"end_column":28},"items":[{"node":{"key":{"node":{"Identifier":{"names":["key"],"pkgpath":"","ctx":"Load"}},"filename":"hello.k","line":4,"column":30,"end_line":4,"end_column":33},"value":{"node":{"StringLit":{"is_long_string":false,"raw_value":"\"value2\"","value":"value2"}},"filename":"hello.k","line":4,"column":36,"end_line":4,"end_column":44},"operation":"Override","insert_index":-1},"filename":"hello.k","line":4,"column":36,"end_line":4,"end_column":44}],"orelse":null}},"filename":"hello.k","line":4,"column":30,"end_line":5,"end_column":0},"operation":"Override","insert_index":-1},"filename":"hello.k","line":4,"column":30,"end_line":5,"end_column":0}],"orelse":null}},"filename":"hello.k","line":4,"column":17,"end_line":5,"end_column":0},"operation":"Union","insert_index":-1},"filename":"hello.k","line":4,"column":4,"end_line":5,"end_column":0}]}},"filename":"hello.k","line":2,"column":8,"end_line":5,"end_column":1},"type_annotation":null}},"filename":"hello.k","line":2,"column":0,"end_line":6,"end_column":0}],"comments":[]} - "#]], + assert_eq!(entries.get_nth_entry(1).unwrap().name(), "kcl2"); + assert_eq!( + PathBuf::from(entries.get_nth_entry(1).unwrap().path()) + .canonicalize() + .unwrap() + .display() + .to_string(), + testpath + .join("kcl2") + .canonicalize() + .unwrap() + .to_str() + .unwrap() ); - check_parsing_file_ast_json( - "hello.k", - r####" -# comment1 -a = 1 -# comment22 -b = 2 -# comment333 -c = 3 # comment4444 - "####, - expect![[r###" - {"filename":"hello.k","pkg":"__main__","doc":"","name":"__main__","body":[{"node":{"Assign":{"targets":[{"node":{"names":["a"],"pkgpath":"","ctx":"Store"},"filename":"hello.k","line":3,"column":0,"end_line":3,"end_column":1}],"value":{"node":{"NumberLit":{"binary_suffix":null,"value":{"Int":1}}},"filename":"hello.k","line":3,"column":4,"end_line":3,"end_column":5},"type_annotation":null}},"filename":"hello.k","line":3,"column":0,"end_line":5,"end_column":0},{"node":{"Assign":{"targets":[{"node":{"names":["b"],"pkgpath":"","ctx":"Store"},"filename":"hello.k","line":5,"column":0,"end_line":5,"end_column":1}],"value":{"node":{"NumberLit":{"binary_suffix":null,"value":{"Int":2}}},"filename":"hello.k","line":5,"column":4,"end_line":5,"end_column":5},"type_annotation":null}},"filename":"hello.k","line":5,"column":0,"end_line":7,"end_column":0},{"node":{"Assign":{"targets":[{"node":{"names":["c"],"pkgpath":"","ctx":"Store"},"filename":"hello.k","line":7,"column":0,"end_line":7,"end_column":1}],"value":{"node":{"NumberLit":{"binary_suffix":null,"value":{"Int":3}}},"filename":"hello.k","line":7,"column":4,"end_line":7,"end_column":5},"type_annotation":null}},"filename":"hello.k","line":7,"column":0,"end_line":8,"end_column":0}],"comments":[{"node":{"text":"# comment1"},"filename":"hello.k","line":2,"column":0,"end_line":2,"end_column":10},{"node":{"text":"# comment22"},"filename":"hello.k","line":4,"column":0,"end_line":4,"end_column":11},{"node":{"text":"# comment333"},"filename":"hello.k","line":6,"column":0,"end_line":6,"end_column":12},{"node":{"text":"# comment4444"},"filename":"hello.k","line":7,"column":6,"end_line":7,"end_column":19}]} - "###]], + assert_eq!(entries.get_nth_entry(2).unwrap().name(), "__main__"); + assert_eq!( + PathBuf::from(entries.get_nth_entry(2).unwrap().path()) + .canonicalize() + .unwrap() + .to_str() + .unwrap(), + kcl1_path.canonicalize().unwrap().to_str().unwrap() ); } -pub fn check_result_panic_info(result: Result<(), Box>){ - match result { - Err(e) => match e.downcast::() { - Ok(_v) => { - let got = _v.to_string(); - let _u: PanicInfo = serde_json::from_str(&got).unwrap(); +#[test] +fn test_dir_with_k_code_list() { + let sm = SourceMap::new(FilePathMapping::empty()); + let sess = Arc::new(ParseSession::with_source_map(Arc::new(sm))); + let testpath = PathBuf::from("./src/testdata/test_k_code_list") + .canonicalize() + .unwrap(); + + let mut opts = LoadProgramOptions::default(); + opts.k_code_list = vec!["test_code = 1".to_string()]; + + match load_program( + sess.clone(), + &[&testpath.display().to_string()], + Some(opts.clone()), + None, + ) { + Ok(_) => panic!("unreachable code"), + Err(err) => assert!(err.to_string().contains("Invalid code list")), + } + + match load_program( + sess.clone(), + &[&testpath.display().to_string()], + Some(opts), + Some(KCLModuleCache::default()), + ) { + Ok(_) => panic!("unreachable code"), + Err(err) => assert!(err.to_string().contains("Invalid code list")), + } +} + +pub fn test_pkg_not_found_suggestion() { + let sm = SourceMap::new(FilePathMapping::empty()); + let sess = Arc::new(ParseSession::with_source_map(Arc::new(sm))); + let dir = &PathBuf::from("./src/testdata/pkg_not_found") + .canonicalize() + .unwrap(); + let test_case_path = dir.join("suggestions.k").display().to_string(); + match load_program(sess.clone(), &[&test_case_path], None, None) { + Ok(_) => { + let errors = sess.classification().0; + let msgs = [ + "pkgpath k9s not found in the program", + "try 'kcl mod add k9s' to download the missing package", + "browse more packages at 'https://artifacthub.io'", + ]; + assert_eq!(errors.len(), msgs.len()); + for (diag, m) in errors.iter().zip(msgs.iter()) { + assert_eq!(diag.messages[0].message, m.to_string()); } - _ => unreachable!(), - }, - _ => {} - }; + } + Err(_) => { + panic!("Unreachable code.") + } + } } #[test] -pub fn test_parse_expr_invalid_binary_expr() { - let result = catch_unwind(|| { - parse_expr("fs1_i1re1~s"); - }); - check_result_panic_info(result); +fn test_expand_input_files_with_kcl_mod() { + let path = PathBuf::from("testdata/expand_file_pattern"); + let input_files = vec![ + path.join("**").join("main.k").to_string_lossy().to_string(), + "${KCL_MOD}/testdata/expand_file_pattern/KCL_MOD".to_string(), + ]; + let expected_files = vec![ + path.join("kcl1/kcl2/main.k").to_string_lossy().to_string(), + path.join("kcl1/kcl4/main.k").to_string_lossy().to_string(), + path.join("kcl1/main.k").to_string_lossy().to_string(), + path.join("kcl3/main.k").to_string_lossy().to_string(), + path.join("main.k").to_string_lossy().to_string(), + "${KCL_MOD}/testdata/expand_file_pattern/KCL_MOD".to_string(), + ]; + let got_paths: Vec = expand_input_files(&input_files) + .iter() + .map(|s| s.replace(['/', '\\'], "")) + .collect(); + let expect_paths: Vec = expected_files + .iter() + .map(|s| s.replace(['/', '\\'], "")) + .collect(); + assert_eq!(got_paths, expect_paths); } #[test] -pub fn test_parse_expr_invalid_arr_out_of_bound_for_token_minus(){ - let result = catch_unwind(|| { - parse_expr("fh==-h==-"); - }); - check_result_panic_info(result); -} \ No newline at end of file +#[cfg(not(windows))] +fn test_expand_input_files() { + let input_files = vec!["./testdata/expand_file_pattern/**/main.k".to_string()]; + let mut expected_files = vec![ + Path::new("testdata/expand_file_pattern/kcl1/kcl2/main.k") + .to_string_lossy() + .to_string(), + Path::new("testdata/expand_file_pattern/kcl3/main.k") + .to_string_lossy() + .to_string(), + Path::new("testdata/expand_file_pattern/main.k") + .to_string_lossy() + .to_string(), + Path::new("testdata/expand_file_pattern/kcl1/main.k") + .to_string_lossy() + .to_string(), + Path::new("testdata/expand_file_pattern/kcl1/kcl4/main.k") + .to_string_lossy() + .to_string(), + ]; + expected_files.sort(); + let mut input = expand_input_files(&input_files); + input.sort(); + assert_eq!(input, expected_files); + + let input_files = vec![ + "./testdata/expand_file_pattern/kcl1/main.k".to_string(), + "./testdata/expand_file_pattern/**/main.k".to_string(), + ]; + let mut expected_files = vec![ + Path::new("testdata/expand_file_pattern/kcl1/main.k") + .to_string_lossy() + .to_string(), + Path::new("testdata/expand_file_pattern/kcl1/main.k") + .to_string_lossy() + .to_string(), + Path::new("testdata/expand_file_pattern/kcl1/kcl2/main.k") + .to_string_lossy() + .to_string(), + Path::new("testdata/expand_file_pattern/kcl1/kcl4/main.k") + .to_string_lossy() + .to_string(), + Path::new("testdata/expand_file_pattern/kcl3/main.k") + .to_string_lossy() + .to_string(), + Path::new("testdata/expand_file_pattern/main.k") + .to_string_lossy() + .to_string(), + ]; + expected_files.sort(); + let mut input = expand_input_files(&input_files); + input.sort(); + assert_eq!(input, expected_files); +} + +#[test] +fn parse_all_file_under_path() { + let testpath = PathBuf::from(env!("CARGO_MANIFEST_DIR")) + .join("testdata") + .join("parse_all_modules"); + + let main = testpath.join("a"); + let main = main.to_str().unwrap(); + let helloworld = testpath.join("helloworld_0.0.1"); + let b = testpath.join("b"); + + let sess = ParseSessionRef::default(); + let mut opt = LoadProgramOptions::default(); + opt.vendor_dirs = vec![get_vendor_home()]; + opt.package_maps + .insert("b".to_string(), b.to_str().unwrap().to_string()); + opt.package_maps.insert( + "helloworld".to_string(), + helloworld.to_str().unwrap().to_string(), + ); + + let res = load_all_files_under_paths(sess.clone(), &[main], Some(opt), None).unwrap(); + + assert_eq!(res.program.pkgs.keys().len(), 1); + assert_eq!(res.program.pkgs_not_imported.keys().len(), 3); + + assert_eq!(res.paths.len(), 1); +} diff --git a/kclvm/parser/src/tests/ast.rs b/kclvm/parser/src/tests/ast.rs new file mode 100644 index 000000000..337c6b4bd --- /dev/null +++ b/kclvm/parser/src/tests/ast.rs @@ -0,0 +1,70 @@ +use crate::tests::parse_file_ast_json_snapshot; + +parse_file_ast_json_snapshot!( + schema_stmt, + "hello.k", + r####" +schema TestBool: + [] + [str ]: int + [a: str]: int + [a: ...str]: int + [...str]: int + a: int + b?: str + c: int = 0 + d?: str = "" + + [a] + [a, b, c] + [ + 1 + ] + [ + a + ] + [a for a in [1, 2, 3]] + [ + a for a in [1, 2, 3] + ] + + check: + a > 1, "msg" + name not None, "we fail here" + "#### +); +parse_file_ast_json_snapshot!(assign_stmt, "hello.k", r####"a=123"####); +parse_file_ast_json_snapshot!( + if_stmt_0, + "hello.k", + r####" +a = 10 +b = 12 +_condition = 0 +if a == 11 or b == 13: _condition = 1 +elif a == 10 and b == 12: _condition = 2 +condition = _condition + "#### +); +parse_file_ast_json_snapshot!( + if_stmt_1, + "hello.k", + r####" +data2 = { + **{key = "value1"} + if a == 123: if b == 456: key = "value2" +} + "#### +); +parse_file_ast_json_snapshot!( + basic_stmt, + "hello.k", + r####" +# comment1 +a = 1 +# comment22 +b = 2 +# comment333 +c = 3 # comment4444 + "#### +); diff --git a/kclvm/parser/src/tests/error_recovery.rs b/kclvm/parser/src/tests/error_recovery.rs new file mode 100644 index 000000000..0f0c9052c --- /dev/null +++ b/kclvm/parser/src/tests/error_recovery.rs @@ -0,0 +1,425 @@ +use crate::tests::{parse_expr_snapshot, parse_module_snapshot}; + +/* Expr error recovery */ + +parse_expr_snapshot! { string_literal_recovery_0, "'abc" } +parse_expr_snapshot! { string_literal_recovery_1, "r'abc" } +parse_expr_snapshot! { string_literal_recovery_2, "'''abc" } +parse_expr_snapshot! { string_literal_recovery_3, "r'''abc" } +parse_expr_snapshot! { string_literal_recovery_4, "r''abc'" } +parse_expr_snapshot! { string_literal_recovery_5, "'" } +parse_expr_snapshot! { string_literal_recovery_6, "'''" } +parse_expr_snapshot! { string_literal_recovery_7, "'\n" } +parse_expr_snapshot! { string_literal_recovery_8, "r'abc\n" } +parse_expr_snapshot! { number_literal_recovery_0, "00" } +parse_expr_snapshot! { number_literal_recovery_1, "00a" } +parse_expr_snapshot! { number_literal_recovery_2, "0x112.3" } +parse_expr_snapshot! { number_literal_recovery_3, "0o" } +parse_expr_snapshot! { number_literal_recovery_4, "0oA" } +parse_expr_snapshot! { number_literal_recovery_5, "0x" } +parse_expr_snapshot! { number_literal_recovery_6, "0xH" } +parse_expr_snapshot! { number_literal_recovery_7, "0e0" } +parse_expr_snapshot! { number_literal_recovery_8, "0b333" } +parse_expr_snapshot! { number_literal_recovery_9, "10KI" } +parse_expr_snapshot! { number_literal_recovery_10, "100mm" } +parse_expr_snapshot! { line_continue_recovery_0, "0x\\2\n12" } +parse_expr_snapshot! { line_continue_recovery_1, "'abc\\ \ndef" } +parse_expr_snapshot! { line_continue_recovery_2, r#"'a' + \ +'b' +"# } +parse_expr_snapshot! { line_continue_recovery_3, r#"'a' + \1 +'b' +"# } +parse_expr_snapshot! { paren_recovery_0, "(a" } +parse_expr_snapshot! { paren_recovery_1, "(a + 1" } +parse_expr_snapshot! { paren_recovery_2, r#"("# } +parse_expr_snapshot! { paren_recovery_3, r#"(]"# } +parse_expr_snapshot! { paren_recovery_4, r#"(a"# } +parse_expr_snapshot! { paren_recovery_5, r#"(a +"# } +parse_expr_snapshot! { list_recovery_0, "[" } +parse_expr_snapshot! { list_recovery_1, "[0" } +parse_expr_snapshot! { list_recovery_2, "[0,1" } +parse_expr_snapshot! { list_recovery_3, "[[0,1]" } +parse_expr_snapshot! { list_recovery_4, "[[0,1" } +parse_expr_snapshot! { list_recovery_5, r#"[ + 0, + 1 + "# } +parse_expr_snapshot! { list_recovery_6, "[0 1]" } +parse_expr_snapshot! { list_recovery_7, "[0,, 1" } +parse_expr_snapshot! { list_recovery_8, "[0 ~ 1" } +parse_expr_snapshot! { list_recovery_9, "[*a, **b]" } +parse_expr_snapshot! { list_recovery_10, "[**a, *b" } +parse_expr_snapshot! { list_recovery_11, "[if True: a, b]" } +parse_expr_snapshot! { list_recovery_12, "[if True: **a, b]" } +parse_expr_snapshot! { list_recovery_13, r#"[ + if True: + b = [] +] +"# } +parse_expr_snapshot! { list_recovery_14, r#"[ + if True: + b = +] +"# } +parse_expr_snapshot! { list_recovery_15, r#"[ + if True: + b - +] +"# } +parse_expr_snapshot! { config_recovery_0, "{" } +parse_expr_snapshot! { config_recovery_1, "{a = 1" } +parse_expr_snapshot! { config_recovery_2, "{a = 1, b = 2" } +parse_expr_snapshot! { config_recovery_3, "{a = {a = 1}" } +parse_expr_snapshot! { config_recovery_4, "{a = {a = 1" } +parse_expr_snapshot! { config_recovery_5, r#"{ + a = 1 + b = 2 + "# } +parse_expr_snapshot! { config_recovery_6, "{a = 1 b = 2}" } +parse_expr_snapshot! { config_recovery_7, "{a = 1,, b = 2}" } +parse_expr_snapshot! { config_recovery_8, "{a = 1 ~ b = 2}" } +parse_expr_snapshot! { config_recovery_9, "{*a, **b}" } +parse_expr_snapshot! { config_recovery_10, "{**a, *b}" } +parse_expr_snapshot! { config_recovery_11, "{if True: a = , b = 2}" } +parse_expr_snapshot! { config_recovery_12, "{if True: *a, b = 2}" } +parse_expr_snapshot! { config_recovery_13, "{if True: key: {}}" } +parse_expr_snapshot! { config_recovery_14, "{if True: key: []}" } +parse_expr_snapshot! { config_recovery_15, "{你好" } +parse_expr_snapshot! { list_recovery_16, r#"{ + if True: + b = [] = [] +} +"# } +parse_expr_snapshot! { list_recovery_17, r#"{ + if True: + b = [] = +} +"# } +parse_expr_snapshot! { list_recovery_18, r#"{ + if True: + b = [] - +} +"# } +parse_expr_snapshot! { comp_clause_recovery_0, "[i for i in [1,2,3]]" } +parse_expr_snapshot! { comp_clause_recovery_1, "[i, j for i in [1,2,3]]" } +parse_expr_snapshot! { comp_clause_recovery_2, "[for i in [1,2,3]]" } +parse_expr_snapshot! { comp_clause_recovery_3, "{i for i in [1,2,3]}" } +parse_expr_snapshot! { comp_clause_recovery_4, "{i: for i in [1,2,3]}" } +parse_expr_snapshot! { comp_clause_recovery_5, "{i: 1, j for i in [1,2,3]}" } +parse_expr_snapshot! { comp_clause_recovery_6, "{for i in [1,2,3]}" } +parse_expr_snapshot! { unary_recovery_0, r#"!a"# } +parse_expr_snapshot! { unary_recovery_1, r#"!!a"# } +parse_expr_snapshot! { unary_recovery_2, r#"not (!a)"# } +parse_expr_snapshot! { unary_recovery_3, r#"! (not a)"# } +parse_expr_snapshot! { unary_recovery_5, r#"++i"# } +parse_expr_snapshot! { unary_recovery_6, r#"--i"# } +parse_expr_snapshot! { unary_recovery_7, r#"-+i"# } +parse_expr_snapshot! { unary_recovery_8, r#"~~i"# } +parse_expr_snapshot! { binary_recovery_0, r#"a not is b"# } +parse_expr_snapshot! { binary_recovery_1, r#"a is is not b"# } +parse_expr_snapshot! { binary_recovery_2, r#"a not b"# } +parse_expr_snapshot! { binary_recovery_3, r#"a not is in b"# } +parse_expr_snapshot! { binary_recovery_4, r#"a in in b"# } +parse_expr_snapshot! { binary_recovery_5, r#"a ++ b"# } +parse_expr_snapshot! { binary_recovery_6, r#"a -not- b"# } +parse_expr_snapshot! { binary_recovery_7, r#"a +is b"# } +parse_expr_snapshot! { binary_recovery_8, r#"a +=+ b"# } +parse_expr_snapshot! { compare_recovery_0, r#"a <> b"# } +parse_expr_snapshot! { compare_recovery_1, r#"a < !b >!1"# } +parse_expr_snapshot! { compare_recovery_2, r#"a < !b >!1"# } +parse_expr_snapshot! { compare_recovery_3, r#"a <<< b"# } +parse_expr_snapshot! { compare_recovery_4, r#"a <+< b"# } +parse_expr_snapshot! { compare_recovery_5, r#"a >+ b"# } +parse_expr_snapshot! { compare_recovery_6, r#"+ b"# } +parse_expr_snapshot! { if_recovery_0, r#"1 if"# } +parse_expr_snapshot! { if_recovery_1, r#"1 if"# } +parse_expr_snapshot! { if_recovery_2, r#"1 if True"# } +parse_expr_snapshot! { if_recovery_3, r#"1 if True else"# } +parse_expr_snapshot! { if_recovery_4, r#"if True else"# } +parse_expr_snapshot! { subscript_recovery_0, r#"a[b 1]"# } +parse_expr_snapshot! { subscript_recovery_1, r#"a[1,b]"# } +parse_expr_snapshot! { subscript_recovery_2, r#"a[b;;b]"# } +parse_expr_snapshot! { subscript_recovery_3, r#"a[b[b]"# } +parse_expr_snapshot! { subscript_recovery_4, r#"a[:::]"# } +parse_expr_snapshot! { subscript_recovery_5, r#"a[:1:2:]"# } +parse_expr_snapshot! { subscript_recovery_6, r#"[][a:b:c:d]"# } +parse_expr_snapshot! { subscript_recovery_7, r#"[][]"# } +parse_expr_snapshot! { subscript_recovery_8, r#"[][][]"# } +parse_expr_snapshot! { subscript_recovery_9, r#"[]?[]"# } +parse_expr_snapshot! { subscript_recovery_10, r#"[0]?.[0]"# } +parse_expr_snapshot! { subscript_recovery_11, r#"[0]??[0]"# } +parse_expr_snapshot! { subscript_recovery_12, r#"[0].?[0]"# } +parse_expr_snapshot! { select_recovery_0, r#"a."# } +parse_expr_snapshot! { select_recovery_1, r#"a.b."# } +parse_expr_snapshot! { select_recovery_2, r#"a.b.c."# } +parse_expr_snapshot! { select_recovery_3, r#"''."# } +parse_expr_snapshot! { select_recovery_4, r#"''.lower"# } +parse_expr_snapshot! { select_recovery_5, r#"''.lower()."# } +parse_expr_snapshot! { select_recovery_6, r#"a?."# } +parse_expr_snapshot! { select_recovery_7, r#"a?.b?."# } +parse_expr_snapshot! { select_recovery_8, r#"a?.b?.c?."# } +parse_expr_snapshot! { select_recovery_9, r#"a?"# } +parse_expr_snapshot! { select_recovery_10, r#"a?.b?"# } +parse_expr_snapshot! { select_recovery_11, r#"a?.b?.c?"# } +parse_expr_snapshot! { select_recovery_12, r#"a.0"# } +parse_expr_snapshot! { select_recovery_13, r#"a..0"# } +parse_expr_snapshot! { select_recovery_14, r#"a..."# } +parse_expr_snapshot! { call_recovery_0, r#"a("# } +parse_expr_snapshot! { call_recovery_1, r#"a(]"# } +parse_expr_snapshot! { call_recovery_2, r#"a(a,,)"# } +parse_expr_snapshot! { call_recovery_3, r#"a.b(a=1,2)"# } +parse_expr_snapshot! { call_recovery_4, r#"a(a.ba=1,2)"# } +parse_expr_snapshot! { call_recovery_5, r#"a(a.b+a=1,2)"# } +parse_expr_snapshot! { call_recovery_6, r#"a(a-1.b=1)"# } +parse_expr_snapshot! { call_recovery_7, r#"a(type="list", "key")"# } +parse_expr_snapshot! { call_recovery_8, r#"a( + 1,2 +)"# } +parse_expr_snapshot! { call_recovery_9, r#"a(1,2 +)"# } +parse_expr_snapshot! { call_recovery_10, r#"a( + 1, + 2 +)"# } +parse_expr_snapshot! { call_recovery_11, r#"a( + 1, +2, +)"# } +parse_expr_snapshot! { call_recovery_12, r#"a( + 1, +2, +)"# } +parse_expr_snapshot! { call_recovery_13, r#"a( + 1,, +2, +)"# } +parse_expr_snapshot! { call_recovery_14, r#"a( + 1, + 2, +]"# } +parse_expr_snapshot! { schema_recovery_0, r#"s {"# } +parse_expr_snapshot! { schema_recovery_1, r#"s {a=1"# } +parse_expr_snapshot! { schema_recovery_2, r#"s.0 {a=1}"# } +parse_expr_snapshot! { schema_recovery_3, r#"s?.a {a=1}"# } +parse_expr_snapshot! { schema_recovery_4, r#"s. {a=1}"# } +parse_expr_snapshot! { schema_recovery_5, r#"s( {a=1}"# } +parse_expr_snapshot! { schema_recovery_6, r#"s(] {a=1}"# } +parse_expr_snapshot! { joined_string_recovery_0, r#"'${}'"# } +parse_expr_snapshot! { joined_string_recovery_1, r#"'${a +}'"# } +parse_expr_snapshot! { joined_string_recovery_2, r#"'${(a +}'"# } +parse_expr_snapshot! { joined_string_recovery_3, r#"'${a'"# } +parse_expr_snapshot! { joined_string_recovery_5, r#"'${a + 1 = }'"# } +parse_expr_snapshot! { joined_string_recovery_6, r#"'${a: json}'"# } +parse_expr_snapshot! { joined_string_recovery_7, r#"'\n${a: #json}'"# } +parse_expr_snapshot! { joined_string_recovery_8, r#"'a\nb${a: #json}\n'"# } +parse_expr_snapshot! { joined_string_recovery_9, r#"'''\ + ${CC} +'''"# } +parse_expr_snapshot! { joined_string_recovery_10, r#"""" + ${CC} +""""# } +parse_expr_snapshot! { joined_string_recovery_11, r#"'\"false\" ${item.kind}: ${item.metadata.name}'"# } +parse_expr_snapshot! { joined_string_recovery_12, r#"'\"false\" ${item.kind}: ${item.metadata.name} \"true\" ${item} '"# } +parse_expr_snapshot! { joined_string_recovery_13, r#"'\"false\" \${item.kind}: a${item.metadata.name} \"true\" \${item} '"# } +parse_expr_snapshot! { lambda_recovery_0, r#"lambda"# } +parse_expr_snapshot! { lambda_recovery_1, r#"lambda {"# } +parse_expr_snapshot! { lambda_recovery_2, r#"lambda {}"# } +parse_expr_snapshot! { lambda_recovery_3, r#"{lambda}"# } +parse_expr_snapshot! { lambda_recovery_4, r#"{lambda{}"# } +parse_expr_snapshot! { lambda_recovery_5, r#"{lambda a{}"# } + +/* Stmt error recovery */ + +parse_module_snapshot! { assign_stmt_recovery_0, r#"a = "#} +parse_module_snapshot! { assign_stmt_recovery_1, r#" = 1"#} +parse_module_snapshot! { assign_stmt_recovery_2, r#"a: int ="#} +parse_module_snapshot! { assign_stmt_recovery_3, r#"a: a = 1"#} +parse_module_snapshot! { assign_stmt_recovery_4, r#"a:"#} +parse_module_snapshot! { assign_stmt_recovery_5, r#"a = b = "#} +parse_module_snapshot! { assign_stmt_recovery_6, r#"a() = b. = c"#} +parse_module_snapshot! { assign_stmt_recovery_7, r#"a: () = 0"#} +parse_module_snapshot! { assign_stmt_recovery_8, r#"a: () = 0"#} +parse_module_snapshot! { assign_stmt_recovery_9, r#"a ++= 1"#} +parse_module_snapshot! { assign_stmt_recovery_10, r#"a[0] -= 1"#} +parse_module_snapshot! { assign_stmt_recovery_11, r#"a[0].b -= 1"#} +parse_module_snapshot! { assign_stmt_recovery_12, r#"a.b[0] = 1"#} +parse_module_snapshot! { assign_stmt_recovery_13, r#"a().b = 1"#} +parse_module_snapshot! { assign_stmt_recovery_14, r#"a.b[1:2] = 1"#} +parse_module_snapshot! { assign_stmt_recovery_15, r#"a.b[1::2].c = 1"#} +parse_module_snapshot! { assign_stmt_recovery_16, r#"a.b[c.d].e = 1"#} +parse_module_snapshot! { assign_stmt_recovery_17, r#"a.b[1 + 1].e = 1"#} +parse_module_snapshot! { assign_stmt_recovery_18, r#"a.b[f()].e = 1"#} +parse_module_snapshot! { assert_stmt_recovery_0, r#"assert"#} +parse_module_snapshot! { assert_stmt_recovery_1, r#"assert a."#} +parse_module_snapshot! { assert_stmt_recovery_2, r#"assert True,,, 'msg'"#} +parse_module_snapshot! { assert_stmt_recovery_3, r#"assert True if data else 'msg'"#} +parse_module_snapshot! { unification_stmt_recovery_0, r#"s: Server {"#} +parse_module_snapshot! { unification_stmt_recovery_1, r#"s: Server {}"#} +parse_module_snapshot! { unification_stmt_recovery_2, r#"s: Server ("#} +parse_module_snapshot! { unification_stmt_recovery_3, r#"s: Server ()"#} +parse_module_snapshot! { unification_stmt_recovery_4, r#"s: Server () {"#} +parse_module_snapshot! { unification_stmt_recovery_5, r#"s: Server ( {"#} +parse_module_snapshot! { unification_stmt_recovery_6, r#"s: Server ( }"#} +parse_module_snapshot! { import_stmt_recovery_0, r#"import"#} +parse_module_snapshot! { import_stmt_recovery_1, r#"import 'pkg_path'"#} +parse_module_snapshot! { import_stmt_recovery_2, r#"import pkg_path."#} +parse_module_snapshot! { import_stmt_recovery_3, r#"import pkg_path[0]"#} +parse_module_snapshot! { import_stmt_recovery_4, r#"import .pkg_path."#} +parse_module_snapshot! { import_stmt_recovery_5, r#"import pkg_path as "#} +parse_module_snapshot! { import_stmt_recovery_6, r#"import pkg_path as 'data'"#} +parse_module_snapshot! { type_alias_recovery_0, r#"type"#} +parse_module_snapshot! { type_alias_recovery_1, r#"type 'pkg_path'"#} +parse_module_snapshot! { type_alias_recovery_2, r#"type pkg_path."#} +parse_module_snapshot! { type_alias_recovery_3, r#"type pkg_path[0]"#} +parse_module_snapshot! { type_alias_recovery_4, r#"type .pkg_path."#} +parse_module_snapshot! { type_alias_recovery_5, r#"type pkg_path = "#} +parse_module_snapshot! { type_alias_recovery_6, r#"type pkg_path = 'data'"#} +parse_module_snapshot! { if_stmt_recovery_0, r#"if True a = 1"#} +parse_module_snapshot! { if_stmt_recovery_1, r#"if True: a = 1 else if b = 2"#} +parse_module_snapshot! { if_stmt_recovery_2, r#"if : a = 1"#} +parse_module_snapshot! { if_stmt_recovery_3, r#"if True: a = 1 else b = 2"#} +parse_module_snapshot! { if_stmt_recovery_4, r#"if True: else: b = 2"#} +parse_module_snapshot! { if_stmt_recovery_5, r#"if"#} +parse_module_snapshot! { if_stmt_recovery_6, r#"if else"#} +parse_module_snapshot! { if_stmt_recovery_7, r#"if True:"#} +parse_module_snapshot! { if_stmt_recovery_8, r#"if True: a = 1 +else if False: b = 1"#} +parse_module_snapshot! { if_stmt_recovery_9, r#"if True: a = 1 +else False: b = 1"#} +parse_module_snapshot! { schema_stmt_recovery_0, r#"schema"#} +parse_module_snapshot! { schema_stmt_recovery_1, r#"schema A"#} +parse_module_snapshot! { schema_stmt_recovery_2, r#"schema A["#} +parse_module_snapshot! { schema_stmt_recovery_3, r#"schema A::"#} +parse_module_snapshot! { schema_stmt_recovery_4, r#"schema A:B"#} +parse_module_snapshot! { schema_stmt_recovery_5, r#"schema A(:"#} +parse_module_snapshot! { schema_stmt_recovery_6, r#"schema A():"#} +parse_module_snapshot! { schema_stmt_recovery_7, r#"schema A: +a:: int"#} +parse_module_snapshot! { schema_stmt_recovery_8, r#"schema A: +a: int ="#} +parse_module_snapshot! { schema_stmt_recovery_9, r#"schema A: +[]: []"#} +parse_module_snapshot! { schema_stmt_recovery_10, r#"schema A: +[str:]: []"#} +parse_module_snapshot! { schema_stmt_recovery_11, r#"schema A: +[str]: str = "#} +parse_module_snapshot! { schema_stmt_recovery_12, r#"schema A: +[str]: = "#} +parse_module_snapshot! { schema_stmt_recovery_13, r#"schema A: +[str]: ''= "#} +parse_module_snapshot! { schema_stmt_recovery_14, r#"schema A: +a??: int "#} +parse_module_snapshot! { schema_stmt_recovery_15, r#"schema A: +a!: int "#} +parse_module_snapshot! { schema_stmt_recovery_16, r#"schema A: +a!!: int "#} +parse_module_snapshot! { schema_stmt_recovery_17, r#"schema A: +a: "#} +parse_module_snapshot! { schema_stmt_recovery_19, r#"@deprecated +schema A: + a: "#} +parse_module_snapshot! { schema_stmt_recovery_20, r#"@deprecated( +schema A: + a: "#} +parse_module_snapshot! { schema_stmt_recovery_21, r#"@deprecated( +schema A: + a: "#} +parse_module_snapshot! { schema_stmt_recovery_22, r#"@deprecated(a +schema A: + a: "#} +parse_module_snapshot! { schema_stmt_recovery_23, r#"@deprecated(a, +schema A: + a: "#} +parse_module_snapshot! { schema_stmt_recovery_24, r#"@deprecated((), +schema A: + a: "#} +parse_module_snapshot! { schema_stmt_recovery_25, r#" +schema A: + check: "#} +parse_module_snapshot! { schema_stmt_recovery_26, r#" +schema A: + check: + @"#} +parse_module_snapshot! { schema_stmt_recovery_27, r#" +schema A: + [.str]: str "#} +parse_module_snapshot! { schema_stmt_recovery_28, r#" +schema A: + [....str]: str "#} +parse_module_snapshot! { schema_stmt_recovery_29, r#" +schema A: + @"#} +parse_module_snapshot! { schema_stmt_recovery_30, r#" +schema A: + ."#} +parse_module_snapshot! { schema_stmt_recovery_31, r#" +schema A: + [str]: str + [str]: int"#} +parse_module_snapshot! { schema_stmt_recovery_32, r#" +schema A: + "attr": str"#} +parse_module_snapshot! { schema_stmt_recovery_33, r#" +schema A: + """Schema Doc""" + "attr": str"#} +parse_module_snapshot! { schema_stmt_recovery_34, r#" +schema A: + "attr: str"#} +parse_module_snapshot! { schema_stmt_recovery_35, r#" +schema A: + "attr":"#} +parse_module_snapshot! { schema_stmt_recovery_36, r#" +schema A: + mixin: "#} +parse_module_snapshot! { schema_stmt_recovery_37, r#" +schema A: + mixin: ["#} +parse_module_snapshot! { schema_stmt_recovery_38, r#" +schema A: + mixin: []"#} +parse_module_snapshot! { schema_stmt_recovery_39, r#" +schema A: + mixin []"#} +parse_module_snapshot! { schema_stmt_recovery_40, r#" +schema A: + mixin ["#} +parse_module_snapshot! { rule_stmt_recovery_0, r#"rule"#} +parse_module_snapshot! { rule_stmt_recovery_1, r#"rule A"#} +parse_module_snapshot! { rule_stmt_recovery_2, r#"rule A["#} +parse_module_snapshot! { rule_stmt_recovery_3, r#"rule A::"#} +parse_module_snapshot! { rule_stmt_recovery_4, r#"rule A:B"#} +parse_module_snapshot! { rule_stmt_recovery_5, r#"rule A(:"#} +parse_module_snapshot! { rule_stmt_recovery_6, r#" +rule A: + True "#} +parse_module_snapshot! { rule_stmt_recovery_7, r#" +rule A: + @ +"#} +parse_module_snapshot! { fn_ty_annotation_recovery_0, r#"a:("#} +parse_module_snapshot! { fn_ty_annotation_recovery_1, r#"a:(i"#} +parse_module_snapshot! { fn_ty_annotation_recovery_2, r#"a:(int"#} +parse_module_snapshot! { fn_ty_annotation_recovery_3, r#"a:i)"#} +parse_module_snapshot! { fn_ty_annotation_recovery_4, r#"a:([i"#} +parse_module_snapshot! { fn_ty_annotation_recovery_5, r#"a:([i:"#} +parse_module_snapshot! { fn_ty_annotation_recovery_6, r#"a:([i]"#} +parse_module_snapshot! { fn_ty_annotation_recovery_7, r#"a:([int]"#} +parse_module_snapshot! { fn_ty_annotation_recovery_8, r#"a:([int"#} +parse_module_snapshot! { fn_ty_annotation_recovery_9, r#"a:({}"#} +parse_module_snapshot! { fn_ty_annotation_recovery_10, r#"a:({"#} +parse_module_snapshot! { fn_ty_annotation_recovery_11, r#"a:({i"#} +parse_module_snapshot! { fn_ty_annotation_recovery_12, r#"a:({i:"#} +parse_module_snapshot! { fn_ty_annotation_recovery_13, r#"a:({i:i"#} +parse_module_snapshot! { fn_ty_annotation_recovery_14, r#"a:({i:int"#} +parse_module_snapshot! { fn_ty_annotation_recovery_15, r#"a:({i:int]"#} +parse_module_snapshot! { fn_ty_annotation_recovery_16, r#"a:({str:int]"#} +parse_module_snapshot! { fn_ty_annotation_recovery_17, r#"a:({str:int}"#} +parse_module_snapshot! { fn_ty_annotation_recovery_18, r#"a:({str:int} ->"#} +parse_module_snapshot! { fn_ty_annotation_recovery_19, r#"a:({str:int}) -> i"#} +parse_module_snapshot! { fn_ty_annotation_recovery_20, r#"a:(str|int) -> i"#} +parse_module_snapshot! { fn_ty_annotation_recovery_21, r#"a:(str|int, int) -> i"#} +parse_module_snapshot! { fn_ty_annotation_recovery_22, r#"a:(str|int, int|"#} +parse_module_snapshot! { fn_ty_annotation_recovery_23, r#"a:(str|int, int|) ->"#} +parse_module_snapshot! { import_recovery_0, r#"import json as j.a"#} diff --git a/kclvm/parser/src/tests/expr.rs b/kclvm/parser/src/tests/expr.rs new file mode 100644 index 000000000..04437d688 --- /dev/null +++ b/kclvm/parser/src/tests/expr.rs @@ -0,0 +1,226 @@ +use crate::tests::parse_expr_snapshot; + +parse_expr_snapshot!(smoke_test_parsing_expr_0, "1\n"); +parse_expr_snapshot!(smoke_test_parsing_expr_1, "\"1\"\n"); +parse_expr_snapshot!(named_literal_expr_0, "Undefined"); +parse_expr_snapshot!(named_literal_expr_1, "None"); +parse_expr_snapshot!(named_literal_expr_2, "True"); +parse_expr_snapshot!(named_literal_expr_3, "False"); +parse_expr_snapshot!(nonstring_literal_expr, r####"1234"####); +parse_expr_snapshot!(string_literal_expr_0, r####"'1234'"####); +parse_expr_snapshot!(string_literal_expr_1, r####""1234""####); +parse_expr_snapshot!(string_literal_expr_2, r####""1234\n""####); +parse_expr_snapshot!(number_bin_suffix_expr, r####"1234Ki"####); +parse_expr_snapshot!(unary_expr, r####"+1"####); +parse_expr_snapshot!(binary_expr_0, r####"1+2+3"####); +parse_expr_snapshot!(binary_expr_1, r####"1+2*3-4"####); +parse_expr_snapshot!(binary_expr_2, r####"1+2*3/4"####); +parse_expr_snapshot!(binary_expr_3, r####"a or b"####); +parse_expr_snapshot!(binary_expr_4, r####"x == a or b"####); +parse_expr_snapshot!(binary_expr_5, r####"22 > 11 and 111 < 222"####); +parse_expr_snapshot!(binary_expr_6, r####"int(e.value) > 1 and i == 0"####); +parse_expr_snapshot!(binary_expr_7, r####"key in ['key']"####); +parse_expr_snapshot!(binary_expr_8, r####"key not in ['key']"####); +parse_expr_snapshot!(binary_expr_9, r####"1 is 1 and 11 is not 22"####); +parse_expr_snapshot!(binary_expr_10, r####"1 + a and b"####); +parse_expr_snapshot!(binary_expr_with_paren, r####"1*(2+3)-4"####); +parse_expr_snapshot!(logic_expr_0, r####"0 < a < 100"####); +parse_expr_snapshot!(logic_expr_1, r####"0 < a < 100 + a"####); +parse_expr_snapshot!(logic_expr_2, r####"100 > a > 0"####); +parse_expr_snapshot!(logic_expr_3, r####"100 + a > a > 0"####); +parse_expr_snapshot!(logic_expr_4, r####"a is b"####); +parse_expr_snapshot!(logic_expr_5, r####"a is not True"####); +parse_expr_snapshot!(logic_expr_6, r####"not False or a > 0 and b is True"####); +parse_expr_snapshot!(if_expr, r####"1 if true else 2"####); +parse_expr_snapshot!(primary_expr_0, r####"a.b.c"####); +parse_expr_snapshot!(primary_expr_1, r####"'{}'.format(1)"####); +parse_expr_snapshot!(primary_expr_2, r####"str(1).isdigit()"####); +parse_expr_snapshot!(primary_expr_3, r####"{}.a"####); +parse_expr_snapshot!(primary_expr_4, r####"{}..a"####); +parse_expr_snapshot!(primary_expr_5, r####"{}...a"####); +parse_expr_snapshot!(primary_expr_6, r####"[]..a"####); +parse_expr_snapshot!(primary_expr_7, r####"{}[[]"####); +parse_expr_snapshot!(list_expr_0, r####"[1, 2, 3]"####); +parse_expr_snapshot!(list_expr_1, r####"[1, if True: 2, 3]"####); +parse_expr_snapshot!(list_comp_expr_0, r####"[x ** 2 for x in [1, 2, 3]]"####); +parse_expr_snapshot!(list_comp_expr_1, r####"[i for i in [1, 2, 3] if i > 2]"####); +parse_expr_snapshot!(dict_expr, r####"{k0=v0, k1=v1}"####); +parse_expr_snapshot!( + dict_comp_expr, + r####"{k: v + 1 for k, v in {k1 = 1, k2 = 2}}"#### +); +parse_expr_snapshot!(subscript_expr_0, r####"a[0]"####); +parse_expr_snapshot!(subscript_expr_1, r####"b["k"]"####); +parse_expr_snapshot!(subscript_expr_2, r####"c?[1]"####); +parse_expr_snapshot!(subscript_expr_3, r####"a[1:]"####); +parse_expr_snapshot!(subscript_expr_4, r####"a[:-1]"####); +parse_expr_snapshot!(subscript_expr_5, r####"a[1:len]"####); +parse_expr_snapshot!(subscript_expr_6, r####"a[0:-1]"####); +parse_expr_snapshot!(subscript_expr_7, r####"a[::]"####); +parse_expr_snapshot!(subscript_expr_8, r####"a[1::]"####); +parse_expr_snapshot!(subscript_expr_9, r####"a[:0:]"####); +parse_expr_snapshot!(subscript_expr_10, r####"a[::-1]"####); +parse_expr_snapshot!(subscript_expr_11, r####"a[1::2]"####); +parse_expr_snapshot!(subscript_expr_12, r####"a[:2:1]"####); +parse_expr_snapshot!(subscript_expr_13, r####"a[1:2:]"####); +parse_expr_snapshot!(subscript_expr_14, r####"a[1:3:1]"####); +parse_expr_snapshot!(call_expr_0, r####"func0()"####); +parse_expr_snapshot!(call_expr_1, r####"func1(1)"####); +parse_expr_snapshot!(call_expr_2, r####"func2(x=2)"####); +parse_expr_snapshot!(call_expr_3, r####"func3(1,x=2)"####); +parse_expr_snapshot!(quant_expr_0, r####"all x in collection {x > 0}"####); +parse_expr_snapshot!(quant_expr_1, r####"any y in collection {y < 0}"####); +parse_expr_snapshot!(quant_expr_2, r####"map x in collection {x + 1}"####); +parse_expr_snapshot!(quant_expr_3, r####"filter x in collection {x > 1}"####); +parse_expr_snapshot!(quant_expr_4, r####"filter x in collection {x > 1}"####); +parse_expr_snapshot!( + quant_expr_5, + r####"map i, e in [{k1 = "v1", k2 = "v2"}] { e }"#### +); +parse_expr_snapshot!( + quant_expr_6, + r####"map i, e in [{k1 = "v1", k2 = "v2"}] { e if i > 0 }"#### +); +parse_expr_snapshot!(lambda_expr_0, r####"lambda {}"####); +parse_expr_snapshot!(lambda_expr_1, r####"lambda x {}"####); +parse_expr_snapshot!(lambda_expr_2, r####"lambda x: int -> int {x}"####); +parse_expr_snapshot!( + lambda_expr_3, + r####"lambda { + if True: + _a = 1 + else: + _a = 2 + _a +}"#### +); +parse_expr_snapshot!( + config_expr_0, + r####"{ + "name" = { + "name": "alice" + }, + "gender" = "female" +}"#### +); +parse_expr_snapshot!( + config_expr_1, + r####"{ + "name" = { + "name": "alice" + } + "gender" = "female", +}"#### +); +parse_expr_snapshot!( + config_expr_2, + r####"{ + "name" = { + "name": "alice", + } + "gender" = "female" +}"#### +); +parse_expr_snapshot!( + config_if_expr_0, + r####"{ + if True: + a = 1 +}"#### +); +parse_expr_snapshot!( + config_if_expr_1, + r####"{ + if True: + a = 1 + else: + a = 2 +}"#### +); +parse_expr_snapshot!( + config_if_expr_2, + r####"{ + if True: + a = 1 + elif x > 1: + a = 2 + else: + a = 3 +}"#### +); +parse_expr_snapshot!( + config_if_expr_3, + r####"{ + if True: + if False: + a = 1 +}"#### +); +parse_expr_snapshot!(schema_expr_0, r####"Schema {}"####); +parse_expr_snapshot!(schema_expr_1, r####"Schema {k=v}"####); +parse_expr_snapshot!(schema_expr_2, r####"Schema () {k=v}"####); +parse_expr_snapshot!(schema_expr_3, r####"Schema (1, 2) {k=v}"####); +parse_expr_snapshot!( + schema_expr_4, + r####"Schema (1, 2) { + k=v +}"#### +); +parse_expr_snapshot!( + line_continue, + r####"1 + \ +2 +"#### +); +parse_expr_snapshot!(parse_joined_string_0, r####"'${123+200}'"####); +parse_expr_snapshot!(parse_joined_string_1, r####"'abc${a+1}cde'"####); +parse_expr_snapshot!(expr_with_paren_0, r####"(2+3)"####); +parse_expr_snapshot!(expr_with_paren_1, r####"((2+3)"####); +parse_expr_snapshot!(expr_with_paren_2, r####"(2+3))"####); +parse_expr_snapshot!(expr_with_bracket_0, r####"[2,3]"####); +parse_expr_snapshot!(expr_with_bracket_1, r####"[[2,3]"####); +parse_expr_snapshot!(expr_with_bracket_2, r####"[2,3]]"####); +parse_expr_snapshot!(expr_with_bracket_3, r####"[2,3"####); +parse_expr_snapshot!(expr_with_bracket_4, r####"["####); +parse_expr_snapshot!( + expr_with_bracket_5, + r####"[ + 1 + 2, +] + "#### +); +parse_expr_snapshot!( + expr_with_bracket_6, + r####"[ + 1,2, +] + "#### +); +parse_expr_snapshot!( + expr_with_bracket_7, + r####"[ + 1,2, + + "#### +); +parse_expr_snapshot!(expr_with_brace_0, r####"{a=2}"####); +parse_expr_snapshot!(expr_with_brace_1, r####"{a=2}}"####); +parse_expr_snapshot!(expr_with_delim_0, r####"({a=2}"####); +parse_expr_snapshot!(expr_with_delim_1, r####"({a=(2}"####); +parse_expr_snapshot!(expr_with_delim_2, r####"{a=[2]"####); +parse_expr_snapshot!(expr_with_delim_3, r####"[{a=2}"####); +parse_expr_snapshot!(expr_with_delim_4, r####"({a=[2}"####); +parse_expr_snapshot!(expr_with_delim_5, r####"{"####); +parse_expr_snapshot!( + expr_with_delim_6, + r####"{ + a = 1 +}"#### +); +parse_expr_snapshot!( + expr_with_delim_7, + r####"{ + a = 1 +"#### +); diff --git a/kclvm/parser/src/tests/file.rs b/kclvm/parser/src/tests/file.rs new file mode 100644 index 000000000..83baf2e10 --- /dev/null +++ b/kclvm/parser/src/tests/file.rs @@ -0,0 +1,19 @@ +use crate::tests::parse_file_snapshot; + +parse_file_snapshot!(assert_1, "testdata/assert-01.k"); +parse_file_snapshot!(assert_2, "testdata/assert-02.k"); +parse_file_snapshot!(assert_3, "testdata/assert-03.k"); +parse_file_snapshot!(assert_if_0, "testdata/assert-if-0.k"); +parse_file_snapshot!(assert_if_1, "testdata/assert-if-1.k"); +parse_file_snapshot!(assert_if_2, "testdata/assert-if-2.k"); +parse_file_snapshot!(assign_1, "testdata/assign-01.k"); +parse_file_snapshot!(config_expr_1, "testdata/config_expr-01.k"); +parse_file_snapshot!(config_expr_2, "testdata/config_expr-02.k"); +parse_file_snapshot!(config_expr_3, "testdata/config_expr-03.k"); +parse_file_snapshot!(config_expr_4, "testdata/config_expr-04.k"); +parse_file_snapshot!(import_1, "testdata/import-01.k"); +parse_file_snapshot!(if_1, "testdata/if-01.k"); +parse_file_snapshot!(if_2, "testdata/if-02.k"); +parse_file_snapshot!(if_3, "testdata/if-03.k"); +parse_file_snapshot!(type_1, "testdata/type-01.k"); +parse_file_snapshot!(hello_win, "testdata/hello_win.k"); diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__ast__assign_stmt.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__ast__assign_stmt.snap new file mode 100644 index 000000000..25c93ab3e --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__ast__assign_stmt.snap @@ -0,0 +1,58 @@ +--- +source: parser/src/tests/ast.rs +expression: "crate::tests::parsing_file_ast_json(\"hello.k\", r####\"a=123\"####)" +--- +{ + "filename": "hello.k", + "doc": null, + "body": [ + { + "node": { + "type": "Assign", + "targets": [ + { + "node": { + "name": { + "node": "a", + "filename": "hello.k", + "line": 1, + "column": 0, + "end_line": 1, + "end_column": 1 + }, + "paths": [], + "pkgpath": "" + }, + "filename": "hello.k", + "line": 1, + "column": 0, + "end_line": 1, + "end_column": 1 + } + ], + "value": { + "node": { + "type": "NumberLit", + "binary_suffix": null, + "value": { + "type": "Int", + "value": 123 + } + }, + "filename": "hello.k", + "line": 1, + "column": 2, + "end_line": 1, + "end_column": 5 + }, + "ty": null + }, + "filename": "hello.k", + "line": 1, + "column": 0, + "end_line": 1, + "end_column": 5 + } + ], + "comments": [] +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__ast__basic_stmt.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__ast__basic_stmt.snap new file mode 100644 index 000000000..79fe9b520 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__ast__basic_stmt.snap @@ -0,0 +1,193 @@ +--- +source: parser/src/tests/ast.rs +expression: "crate::tests::parsing_file_ast_json(\"hello.k\",\n r####\"\n# comment1\na = 1\n# comment22\nb = 2\n# comment333\nc = 3 # comment4444\n \"####)" +--- +{ + "filename": "hello.k", + "doc": null, + "body": [ + { + "node": { + "type": "Assign", + "targets": [ + { + "node": { + "name": { + "node": "a", + "filename": "hello.k", + "line": 3, + "column": 0, + "end_line": 3, + "end_column": 1 + }, + "paths": [], + "pkgpath": "" + }, + "filename": "hello.k", + "line": 3, + "column": 0, + "end_line": 3, + "end_column": 1 + } + ], + "value": { + "node": { + "type": "NumberLit", + "binary_suffix": null, + "value": { + "type": "Int", + "value": 1 + } + }, + "filename": "hello.k", + "line": 3, + "column": 4, + "end_line": 3, + "end_column": 5 + }, + "ty": null + }, + "filename": "hello.k", + "line": 3, + "column": 0, + "end_line": 3, + "end_column": 5 + }, + { + "node": { + "type": "Assign", + "targets": [ + { + "node": { + "name": { + "node": "b", + "filename": "hello.k", + "line": 5, + "column": 0, + "end_line": 5, + "end_column": 1 + }, + "paths": [], + "pkgpath": "" + }, + "filename": "hello.k", + "line": 5, + "column": 0, + "end_line": 5, + "end_column": 1 + } + ], + "value": { + "node": { + "type": "NumberLit", + "binary_suffix": null, + "value": { + "type": "Int", + "value": 2 + } + }, + "filename": "hello.k", + "line": 5, + "column": 4, + "end_line": 5, + "end_column": 5 + }, + "ty": null + }, + "filename": "hello.k", + "line": 5, + "column": 0, + "end_line": 5, + "end_column": 5 + }, + { + "node": { + "type": "Assign", + "targets": [ + { + "node": { + "name": { + "node": "c", + "filename": "hello.k", + "line": 7, + "column": 0, + "end_line": 7, + "end_column": 1 + }, + "paths": [], + "pkgpath": "" + }, + "filename": "hello.k", + "line": 7, + "column": 0, + "end_line": 7, + "end_column": 1 + } + ], + "value": { + "node": { + "type": "NumberLit", + "binary_suffix": null, + "value": { + "type": "Int", + "value": 3 + } + }, + "filename": "hello.k", + "line": 7, + "column": 4, + "end_line": 7, + "end_column": 5 + }, + "ty": null + }, + "filename": "hello.k", + "line": 7, + "column": 0, + "end_line": 7, + "end_column": 5 + } + ], + "comments": [ + { + "node": { + "text": "# comment1" + }, + "filename": "hello.k", + "line": 2, + "column": 0, + "end_line": 2, + "end_column": 10 + }, + { + "node": { + "text": "# comment22" + }, + "filename": "hello.k", + "line": 4, + "column": 0, + "end_line": 4, + "end_column": 11 + }, + { + "node": { + "text": "# comment333" + }, + "filename": "hello.k", + "line": 6, + "column": 0, + "end_line": 6, + "end_column": 12 + }, + { + "node": { + "text": "# comment4444" + }, + "filename": "hello.k", + "line": 7, + "column": 6, + "end_line": 7, + "end_column": 19 + } + ] +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__ast__if_stmt_0.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__ast__if_stmt_0.snap new file mode 100644 index 000000000..63e1e6b78 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__ast__if_stmt_0.snap @@ -0,0 +1,557 @@ +--- +source: parser/src/tests/ast.rs +expression: "crate::tests::parsing_file_ast_json(\"hello.k\",\n r####\"\na = 10\nb = 12\n_condition = 0\nif a == 11 or b == 13: _condition = 1\nelif a == 10 and b == 12: _condition = 2\ncondition = _condition\n \"####)" +--- +{ + "filename": "hello.k", + "doc": null, + "body": [ + { + "node": { + "type": "Assign", + "targets": [ + { + "node": { + "name": { + "node": "a", + "filename": "hello.k", + "line": 2, + "column": 0, + "end_line": 2, + "end_column": 1 + }, + "paths": [], + "pkgpath": "" + }, + "filename": "hello.k", + "line": 2, + "column": 0, + "end_line": 2, + "end_column": 1 + } + ], + "value": { + "node": { + "type": "NumberLit", + "binary_suffix": null, + "value": { + "type": "Int", + "value": 10 + } + }, + "filename": "hello.k", + "line": 2, + "column": 4, + "end_line": 2, + "end_column": 6 + }, + "ty": null + }, + "filename": "hello.k", + "line": 2, + "column": 0, + "end_line": 2, + "end_column": 6 + }, + { + "node": { + "type": "Assign", + "targets": [ + { + "node": { + "name": { + "node": "b", + "filename": "hello.k", + "line": 3, + "column": 0, + "end_line": 3, + "end_column": 1 + }, + "paths": [], + "pkgpath": "" + }, + "filename": "hello.k", + "line": 3, + "column": 0, + "end_line": 3, + "end_column": 1 + } + ], + "value": { + "node": { + "type": "NumberLit", + "binary_suffix": null, + "value": { + "type": "Int", + "value": 12 + } + }, + "filename": "hello.k", + "line": 3, + "column": 4, + "end_line": 3, + "end_column": 6 + }, + "ty": null + }, + "filename": "hello.k", + "line": 3, + "column": 0, + "end_line": 3, + "end_column": 6 + }, + { + "node": { + "type": "Assign", + "targets": [ + { + "node": { + "name": { + "node": "_condition", + "filename": "hello.k", + "line": 4, + "column": 0, + "end_line": 4, + "end_column": 10 + }, + "paths": [], + "pkgpath": "" + }, + "filename": "hello.k", + "line": 4, + "column": 0, + "end_line": 4, + "end_column": 10 + } + ], + "value": { + "node": { + "type": "NumberLit", + "binary_suffix": null, + "value": { + "type": "Int", + "value": 0 + } + }, + "filename": "hello.k", + "line": 4, + "column": 13, + "end_line": 4, + "end_column": 14 + }, + "ty": null + }, + "filename": "hello.k", + "line": 4, + "column": 0, + "end_line": 4, + "end_column": 14 + }, + { + "node": { + "type": "If", + "body": [ + { + "node": { + "type": "Assign", + "targets": [ + { + "node": { + "name": { + "node": "_condition", + "filename": "hello.k", + "line": 5, + "column": 23, + "end_line": 5, + "end_column": 33 + }, + "paths": [], + "pkgpath": "" + }, + "filename": "hello.k", + "line": 5, + "column": 23, + "end_line": 5, + "end_column": 33 + } + ], + "value": { + "node": { + "type": "NumberLit", + "binary_suffix": null, + "value": { + "type": "Int", + "value": 1 + } + }, + "filename": "hello.k", + "line": 5, + "column": 36, + "end_line": 5, + "end_column": 37 + }, + "ty": null + }, + "filename": "hello.k", + "line": 5, + "column": 23, + "end_line": 5, + "end_column": 37 + } + ], + "cond": { + "node": { + "type": "Binary", + "left": { + "node": { + "type": "Compare", + "left": { + "node": { + "type": "Identifier", + "names": [ + { + "node": "a", + "filename": "hello.k", + "line": 5, + "column": 3, + "end_line": 5, + "end_column": 4 + } + ], + "pkgpath": "", + "ctx": "Load" + }, + "filename": "hello.k", + "line": 5, + "column": 3, + "end_line": 5, + "end_column": 4 + }, + "ops": [ + "Eq" + ], + "comparators": [ + { + "node": { + "type": "NumberLit", + "binary_suffix": null, + "value": { + "type": "Int", + "value": 11 + } + }, + "filename": "hello.k", + "line": 5, + "column": 8, + "end_line": 5, + "end_column": 10 + } + ] + }, + "filename": "hello.k", + "line": 5, + "column": 3, + "end_line": 5, + "end_column": 21 + }, + "op": "Or", + "right": { + "node": { + "type": "Compare", + "left": { + "node": { + "type": "Identifier", + "names": [ + { + "node": "b", + "filename": "hello.k", + "line": 5, + "column": 14, + "end_line": 5, + "end_column": 15 + } + ], + "pkgpath": "", + "ctx": "Load" + }, + "filename": "hello.k", + "line": 5, + "column": 14, + "end_line": 5, + "end_column": 15 + }, + "ops": [ + "Eq" + ], + "comparators": [ + { + "node": { + "type": "NumberLit", + "binary_suffix": null, + "value": { + "type": "Int", + "value": 13 + } + }, + "filename": "hello.k", + "line": 5, + "column": 19, + "end_line": 5, + "end_column": 21 + } + ] + }, + "filename": "hello.k", + "line": 5, + "column": 14, + "end_line": 5, + "end_column": 21 + } + }, + "filename": "hello.k", + "line": 5, + "column": 3, + "end_line": 5, + "end_column": 21 + }, + "orelse": [ + { + "node": { + "type": "If", + "body": [ + { + "node": { + "type": "Assign", + "targets": [ + { + "node": { + "name": { + "node": "_condition", + "filename": "hello.k", + "line": 6, + "column": 26, + "end_line": 6, + "end_column": 36 + }, + "paths": [], + "pkgpath": "" + }, + "filename": "hello.k", + "line": 6, + "column": 26, + "end_line": 6, + "end_column": 36 + } + ], + "value": { + "node": { + "type": "NumberLit", + "binary_suffix": null, + "value": { + "type": "Int", + "value": 2 + } + }, + "filename": "hello.k", + "line": 6, + "column": 39, + "end_line": 6, + "end_column": 40 + }, + "ty": null + }, + "filename": "hello.k", + "line": 6, + "column": 26, + "end_line": 6, + "end_column": 40 + } + ], + "cond": { + "node": { + "type": "Binary", + "left": { + "node": { + "type": "Compare", + "left": { + "node": { + "type": "Identifier", + "names": [ + { + "node": "a", + "filename": "hello.k", + "line": 6, + "column": 5, + "end_line": 6, + "end_column": 6 + } + ], + "pkgpath": "", + "ctx": "Load" + }, + "filename": "hello.k", + "line": 6, + "column": 5, + "end_line": 6, + "end_column": 6 + }, + "ops": [ + "Eq" + ], + "comparators": [ + { + "node": { + "type": "NumberLit", + "binary_suffix": null, + "value": { + "type": "Int", + "value": 10 + } + }, + "filename": "hello.k", + "line": 6, + "column": 10, + "end_line": 6, + "end_column": 12 + } + ] + }, + "filename": "hello.k", + "line": 6, + "column": 5, + "end_line": 6, + "end_column": 24 + }, + "op": "And", + "right": { + "node": { + "type": "Compare", + "left": { + "node": { + "type": "Identifier", + "names": [ + { + "node": "b", + "filename": "hello.k", + "line": 6, + "column": 17, + "end_line": 6, + "end_column": 18 + } + ], + "pkgpath": "", + "ctx": "Load" + }, + "filename": "hello.k", + "line": 6, + "column": 17, + "end_line": 6, + "end_column": 18 + }, + "ops": [ + "Eq" + ], + "comparators": [ + { + "node": { + "type": "NumberLit", + "binary_suffix": null, + "value": { + "type": "Int", + "value": 12 + } + }, + "filename": "hello.k", + "line": 6, + "column": 22, + "end_line": 6, + "end_column": 24 + } + ] + }, + "filename": "hello.k", + "line": 6, + "column": 17, + "end_line": 6, + "end_column": 24 + } + }, + "filename": "hello.k", + "line": 6, + "column": 5, + "end_line": 6, + "end_column": 24 + }, + "orelse": [] + }, + "filename": "hello.k", + "line": 6, + "column": 0, + "end_line": 7, + "end_column": 0 + } + ] + }, + "filename": "hello.k", + "line": 5, + "column": 0, + "end_line": 7, + "end_column": 0 + }, + { + "node": { + "type": "Assign", + "targets": [ + { + "node": { + "name": { + "node": "condition", + "filename": "hello.k", + "line": 7, + "column": 0, + "end_line": 7, + "end_column": 9 + }, + "paths": [], + "pkgpath": "" + }, + "filename": "hello.k", + "line": 7, + "column": 0, + "end_line": 7, + "end_column": 9 + } + ], + "value": { + "node": { + "type": "Identifier", + "names": [ + { + "node": "_condition", + "filename": "hello.k", + "line": 7, + "column": 12, + "end_line": 7, + "end_column": 22 + } + ], + "pkgpath": "", + "ctx": "Load" + }, + "filename": "hello.k", + "line": 7, + "column": 12, + "end_line": 7, + "end_column": 22 + }, + "ty": null + }, + "filename": "hello.k", + "line": 7, + "column": 0, + "end_line": 7, + "end_column": 22 + } + ], + "comments": [] +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__ast__if_stmt_1.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__ast__if_stmt_1.snap new file mode 100644 index 000000000..ebb01527c --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__ast__if_stmt_1.snap @@ -0,0 +1,320 @@ +--- +source: parser/src/tests/ast.rs +expression: "crate::tests::parsing_file_ast_json(\"hello.k\",\n r####\"\ndata2 = {\n **{key = \"value1\"}\n if a == 123: if b == 456: key = \"value2\"\n}\n \"####)" +--- +{ + "filename": "hello.k", + "doc": null, + "body": [ + { + "node": { + "type": "Assign", + "targets": [ + { + "node": { + "name": { + "node": "data2", + "filename": "hello.k", + "line": 2, + "column": 0, + "end_line": 2, + "end_column": 5 + }, + "paths": [], + "pkgpath": "" + }, + "filename": "hello.k", + "line": 2, + "column": 0, + "end_line": 2, + "end_column": 5 + } + ], + "value": { + "node": { + "type": "Config", + "items": [ + { + "node": { + "key": null, + "value": { + "node": { + "type": "Config", + "items": [ + { + "node": { + "key": { + "node": { + "type": "Identifier", + "names": [ + { + "node": "key", + "filename": "hello.k", + "line": 3, + "column": 7, + "end_line": 3, + "end_column": 10 + } + ], + "pkgpath": "", + "ctx": "Load" + }, + "filename": "hello.k", + "line": 3, + "column": 7, + "end_line": 3, + "end_column": 10 + }, + "value": { + "node": { + "type": "StringLit", + "is_long_string": false, + "raw_value": "\"value1\"", + "value": "value1" + }, + "filename": "hello.k", + "line": 3, + "column": 13, + "end_line": 3, + "end_column": 21 + }, + "operation": "Override" + }, + "filename": "hello.k", + "line": 3, + "column": 7, + "end_line": 3, + "end_column": 21 + } + ] + }, + "filename": "hello.k", + "line": 3, + "column": 6, + "end_line": 3, + "end_column": 22 + }, + "operation": "Union" + }, + "filename": "hello.k", + "line": 3, + "column": 4, + "end_line": 3, + "end_column": 22 + }, + { + "node": { + "key": null, + "value": { + "node": { + "type": "ConfigIfEntry", + "if_cond": { + "node": { + "type": "Compare", + "left": { + "node": { + "type": "Identifier", + "names": [ + { + "node": "a", + "filename": "hello.k", + "line": 4, + "column": 7, + "end_line": 4, + "end_column": 8 + } + ], + "pkgpath": "", + "ctx": "Load" + }, + "filename": "hello.k", + "line": 4, + "column": 7, + "end_line": 4, + "end_column": 8 + }, + "ops": [ + "Eq" + ], + "comparators": [ + { + "node": { + "type": "NumberLit", + "binary_suffix": null, + "value": { + "type": "Int", + "value": 123 + } + }, + "filename": "hello.k", + "line": 4, + "column": 12, + "end_line": 4, + "end_column": 15 + } + ] + }, + "filename": "hello.k", + "line": 4, + "column": 7, + "end_line": 4, + "end_column": 15 + }, + "items": [ + { + "node": { + "key": null, + "value": { + "node": { + "type": "ConfigIfEntry", + "if_cond": { + "node": { + "type": "Compare", + "left": { + "node": { + "type": "Identifier", + "names": [ + { + "node": "b", + "filename": "hello.k", + "line": 4, + "column": 20, + "end_line": 4, + "end_column": 21 + } + ], + "pkgpath": "", + "ctx": "Load" + }, + "filename": "hello.k", + "line": 4, + "column": 20, + "end_line": 4, + "end_column": 21 + }, + "ops": [ + "Eq" + ], + "comparators": [ + { + "node": { + "type": "NumberLit", + "binary_suffix": null, + "value": { + "type": "Int", + "value": 456 + } + }, + "filename": "hello.k", + "line": 4, + "column": 25, + "end_line": 4, + "end_column": 28 + } + ] + }, + "filename": "hello.k", + "line": 4, + "column": 20, + "end_line": 4, + "end_column": 28 + }, + "items": [ + { + "node": { + "key": { + "node": { + "type": "Identifier", + "names": [ + { + "node": "key", + "filename": "hello.k", + "line": 4, + "column": 30, + "end_line": 4, + "end_column": 33 + } + ], + "pkgpath": "", + "ctx": "Load" + }, + "filename": "hello.k", + "line": 4, + "column": 30, + "end_line": 4, + "end_column": 33 + }, + "value": { + "node": { + "type": "StringLit", + "is_long_string": false, + "raw_value": "\"value2\"", + "value": "value2" + }, + "filename": "hello.k", + "line": 4, + "column": 36, + "end_line": 4, + "end_column": 44 + }, + "operation": "Override" + }, + "filename": "hello.k", + "line": 4, + "column": 30, + "end_line": 4, + "end_column": 44 + } + ], + "orelse": null + }, + "filename": "hello.k", + "line": 4, + "column": 17, + "end_line": 5, + "end_column": 0 + }, + "operation": "Override" + }, + "filename": "hello.k", + "line": 4, + "column": 17, + "end_line": 5, + "end_column": 0 + } + ], + "orelse": null + }, + "filename": "hello.k", + "line": 4, + "column": 4, + "end_line": 5, + "end_column": 0 + }, + "operation": "Union" + }, + "filename": "hello.k", + "line": 4, + "column": 4, + "end_line": 5, + "end_column": 0 + } + ] + }, + "filename": "hello.k", + "line": 2, + "column": 8, + "end_line": 5, + "end_column": 1 + }, + "ty": null + }, + "filename": "hello.k", + "line": 2, + "column": 0, + "end_line": 5, + "end_column": 1 + } + ], + "comments": [] +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__ast__schema_stmt.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__ast__schema_stmt.snap new file mode 100644 index 000000000..c780457af --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__ast__schema_stmt.snap @@ -0,0 +1,913 @@ +--- +source: parser/src/tests/ast.rs +expression: "crate::tests::parsing_file_ast_json(\"hello.k\",\n r####\"\nschema TestBool:\n []\n [str ]: int\n [a: str]: int\n [a: ...str]: int\n [...str]: int\n a: int\n b?: str\n c: int = 0\n d?: str = \"\"\n\n [a]\n [a, b, c]\n [\n 1\n ]\n [\n a\n ]\n [a for a in [1, 2, 3]]\n [\n a for a in [1, 2, 3]\n ]\n\n check:\n a > 1, \"msg\"\n name not None, \"we fail here\"\n \"####)" +--- +{ + "filename": "hello.k", + "doc": null, + "body": [ + { + "node": { + "type": "Schema", + "doc": null, + "name": { + "node": "TestBool", + "filename": "hello.k", + "line": 2, + "column": 7, + "end_line": 2, + "end_column": 15 + }, + "parent_name": null, + "for_host_name": null, + "is_mixin": false, + "is_protocol": false, + "args": null, + "mixins": [], + "body": [ + { + "node": { + "type": "Expr", + "exprs": [ + { + "node": { + "type": "List", + "elts": [], + "ctx": "Load" + }, + "filename": "hello.k", + "line": 3, + "column": 4, + "end_line": 3, + "end_column": 6 + } + ] + }, + "filename": "hello.k", + "line": 3, + "column": 4, + "end_line": 3, + "end_column": 6 + }, + { + "node": { + "type": "SchemaAttr", + "doc": "", + "name": { + "node": "a", + "filename": "hello.k", + "line": 8, + "column": 4, + "end_line": 8, + "end_column": 5 + }, + "op": null, + "value": null, + "is_optional": false, + "decorators": [], + "ty": { + "node": { + "type": "Basic", + "value": "Int" + }, + "filename": "hello.k", + "line": 8, + "column": 7, + "end_line": 8, + "end_column": 10 + } + }, + "filename": "hello.k", + "line": 8, + "column": 4, + "end_line": 8, + "end_column": 10 + }, + { + "node": { + "type": "SchemaAttr", + "doc": "", + "name": { + "node": "b", + "filename": "hello.k", + "line": 9, + "column": 4, + "end_line": 9, + "end_column": 5 + }, + "op": null, + "value": null, + "is_optional": true, + "decorators": [], + "ty": { + "node": { + "type": "Basic", + "value": "Str" + }, + "filename": "hello.k", + "line": 9, + "column": 8, + "end_line": 9, + "end_column": 11 + } + }, + "filename": "hello.k", + "line": 9, + "column": 4, + "end_line": 10, + "end_column": 0 + }, + { + "node": { + "type": "SchemaAttr", + "doc": "", + "name": { + "node": "c", + "filename": "hello.k", + "line": 10, + "column": 4, + "end_line": 10, + "end_column": 5 + }, + "op": "Assign", + "value": { + "node": { + "type": "NumberLit", + "binary_suffix": null, + "value": { + "type": "Int", + "value": 0 + } + }, + "filename": "hello.k", + "line": 10, + "column": 13, + "end_line": 10, + "end_column": 14 + }, + "is_optional": false, + "decorators": [], + "ty": { + "node": { + "type": "Basic", + "value": "Int" + }, + "filename": "hello.k", + "line": 10, + "column": 7, + "end_line": 10, + "end_column": 10 + } + }, + "filename": "hello.k", + "line": 10, + "column": 4, + "end_line": 10, + "end_column": 14 + }, + { + "node": { + "type": "SchemaAttr", + "doc": "", + "name": { + "node": "d", + "filename": "hello.k", + "line": 11, + "column": 4, + "end_line": 11, + "end_column": 5 + }, + "op": "Assign", + "value": { + "node": { + "type": "StringLit", + "is_long_string": false, + "raw_value": "\"\"", + "value": "" + }, + "filename": "hello.k", + "line": 11, + "column": 14, + "end_line": 11, + "end_column": 16 + }, + "is_optional": true, + "decorators": [], + "ty": { + "node": { + "type": "Basic", + "value": "Str" + }, + "filename": "hello.k", + "line": 11, + "column": 8, + "end_line": 11, + "end_column": 11 + } + }, + "filename": "hello.k", + "line": 11, + "column": 4, + "end_line": 13, + "end_column": 0 + }, + { + "node": { + "type": "Expr", + "exprs": [ + { + "node": { + "type": "List", + "elts": [ + { + "node": { + "type": "Identifier", + "names": [ + { + "node": "a", + "filename": "hello.k", + "line": 13, + "column": 5, + "end_line": 13, + "end_column": 6 + } + ], + "pkgpath": "", + "ctx": "Load" + }, + "filename": "hello.k", + "line": 13, + "column": 5, + "end_line": 13, + "end_column": 6 + } + ], + "ctx": "Load" + }, + "filename": "hello.k", + "line": 13, + "column": 4, + "end_line": 13, + "end_column": 7 + } + ] + }, + "filename": "hello.k", + "line": 13, + "column": 4, + "end_line": 13, + "end_column": 7 + }, + { + "node": { + "type": "Expr", + "exprs": [ + { + "node": { + "type": "List", + "elts": [ + { + "node": { + "type": "Identifier", + "names": [ + { + "node": "a", + "filename": "hello.k", + "line": 14, + "column": 5, + "end_line": 14, + "end_column": 6 + } + ], + "pkgpath": "", + "ctx": "Load" + }, + "filename": "hello.k", + "line": 14, + "column": 5, + "end_line": 14, + "end_column": 6 + }, + { + "node": { + "type": "Identifier", + "names": [ + { + "node": "b", + "filename": "hello.k", + "line": 14, + "column": 8, + "end_line": 14, + "end_column": 9 + } + ], + "pkgpath": "", + "ctx": "Load" + }, + "filename": "hello.k", + "line": 14, + "column": 8, + "end_line": 14, + "end_column": 9 + }, + { + "node": { + "type": "Identifier", + "names": [ + { + "node": "c", + "filename": "hello.k", + "line": 14, + "column": 11, + "end_line": 14, + "end_column": 12 + } + ], + "pkgpath": "", + "ctx": "Load" + }, + "filename": "hello.k", + "line": 14, + "column": 11, + "end_line": 14, + "end_column": 12 + } + ], + "ctx": "Load" + }, + "filename": "hello.k", + "line": 14, + "column": 4, + "end_line": 14, + "end_column": 13 + } + ] + }, + "filename": "hello.k", + "line": 14, + "column": 4, + "end_line": 14, + "end_column": 13 + }, + { + "node": { + "type": "Expr", + "exprs": [ + { + "node": { + "type": "List", + "elts": [ + { + "node": { + "type": "NumberLit", + "binary_suffix": null, + "value": { + "type": "Int", + "value": 1 + } + }, + "filename": "hello.k", + "line": 16, + "column": 8, + "end_line": 16, + "end_column": 9 + } + ], + "ctx": "Load" + }, + "filename": "hello.k", + "line": 15, + "column": 4, + "end_line": 17, + "end_column": 5 + } + ] + }, + "filename": "hello.k", + "line": 15, + "column": 4, + "end_line": 17, + "end_column": 5 + }, + { + "node": { + "type": "Expr", + "exprs": [ + { + "node": { + "type": "List", + "elts": [ + { + "node": { + "type": "Identifier", + "names": [ + { + "node": "a", + "filename": "hello.k", + "line": 19, + "column": 8, + "end_line": 19, + "end_column": 9 + } + ], + "pkgpath": "", + "ctx": "Load" + }, + "filename": "hello.k", + "line": 19, + "column": 8, + "end_line": 19, + "end_column": 9 + } + ], + "ctx": "Load" + }, + "filename": "hello.k", + "line": 18, + "column": 4, + "end_line": 20, + "end_column": 5 + } + ] + }, + "filename": "hello.k", + "line": 18, + "column": 4, + "end_line": 20, + "end_column": 5 + }, + { + "node": { + "type": "Expr", + "exprs": [ + { + "node": { + "type": "ListComp", + "elt": { + "node": { + "type": "Identifier", + "names": [ + { + "node": "a", + "filename": "hello.k", + "line": 21, + "column": 5, + "end_line": 21, + "end_column": 6 + } + ], + "pkgpath": "", + "ctx": "Load" + }, + "filename": "hello.k", + "line": 21, + "column": 5, + "end_line": 21, + "end_column": 6 + }, + "generators": [ + { + "node": { + "targets": [ + { + "node": { + "names": [ + { + "node": "a", + "filename": "hello.k", + "line": 21, + "column": 11, + "end_line": 21, + "end_column": 12 + } + ], + "pkgpath": "", + "ctx": "Load" + }, + "filename": "hello.k", + "line": 21, + "column": 11, + "end_line": 21, + "end_column": 12 + } + ], + "iter": { + "node": { + "type": "List", + "elts": [ + { + "node": { + "type": "NumberLit", + "binary_suffix": null, + "value": { + "type": "Int", + "value": 1 + } + }, + "filename": "hello.k", + "line": 21, + "column": 17, + "end_line": 21, + "end_column": 18 + }, + { + "node": { + "type": "NumberLit", + "binary_suffix": null, + "value": { + "type": "Int", + "value": 2 + } + }, + "filename": "hello.k", + "line": 21, + "column": 20, + "end_line": 21, + "end_column": 21 + }, + { + "node": { + "type": "NumberLit", + "binary_suffix": null, + "value": { + "type": "Int", + "value": 3 + } + }, + "filename": "hello.k", + "line": 21, + "column": 23, + "end_line": 21, + "end_column": 24 + } + ], + "ctx": "Load" + }, + "filename": "hello.k", + "line": 21, + "column": 16, + "end_line": 21, + "end_column": 25 + }, + "ifs": [] + }, + "filename": "hello.k", + "line": 21, + "column": 7, + "end_line": 21, + "end_column": 25 + } + ] + }, + "filename": "hello.k", + "line": 21, + "column": 4, + "end_line": 21, + "end_column": 26 + } + ] + }, + "filename": "hello.k", + "line": 21, + "column": 4, + "end_line": 21, + "end_column": 26 + }, + { + "node": { + "type": "Expr", + "exprs": [ + { + "node": { + "type": "ListComp", + "elt": { + "node": { + "type": "Identifier", + "names": [ + { + "node": "a", + "filename": "hello.k", + "line": 23, + "column": 8, + "end_line": 23, + "end_column": 9 + } + ], + "pkgpath": "", + "ctx": "Load" + }, + "filename": "hello.k", + "line": 23, + "column": 8, + "end_line": 23, + "end_column": 9 + }, + "generators": [ + { + "node": { + "targets": [ + { + "node": { + "names": [ + { + "node": "a", + "filename": "hello.k", + "line": 23, + "column": 14, + "end_line": 23, + "end_column": 15 + } + ], + "pkgpath": "", + "ctx": "Load" + }, + "filename": "hello.k", + "line": 23, + "column": 14, + "end_line": 23, + "end_column": 15 + } + ], + "iter": { + "node": { + "type": "List", + "elts": [ + { + "node": { + "type": "NumberLit", + "binary_suffix": null, + "value": { + "type": "Int", + "value": 1 + } + }, + "filename": "hello.k", + "line": 23, + "column": 20, + "end_line": 23, + "end_column": 21 + }, + { + "node": { + "type": "NumberLit", + "binary_suffix": null, + "value": { + "type": "Int", + "value": 2 + } + }, + "filename": "hello.k", + "line": 23, + "column": 23, + "end_line": 23, + "end_column": 24 + }, + { + "node": { + "type": "NumberLit", + "binary_suffix": null, + "value": { + "type": "Int", + "value": 3 + } + }, + "filename": "hello.k", + "line": 23, + "column": 26, + "end_line": 23, + "end_column": 27 + } + ], + "ctx": "Load" + }, + "filename": "hello.k", + "line": 23, + "column": 19, + "end_line": 23, + "end_column": 28 + }, + "ifs": [] + }, + "filename": "hello.k", + "line": 23, + "column": 10, + "end_line": 24, + "end_column": 0 + } + ] + }, + "filename": "hello.k", + "line": 22, + "column": 4, + "end_line": 24, + "end_column": 5 + } + ] + }, + "filename": "hello.k", + "line": 22, + "column": 4, + "end_line": 24, + "end_column": 5 + } + ], + "decorators": [], + "checks": [ + { + "node": { + "test": { + "node": { + "type": "Compare", + "left": { + "node": { + "type": "Identifier", + "names": [ + { + "node": "a", + "filename": "hello.k", + "line": 27, + "column": 8, + "end_line": 27, + "end_column": 9 + } + ], + "pkgpath": "", + "ctx": "Load" + }, + "filename": "hello.k", + "line": 27, + "column": 8, + "end_line": 27, + "end_column": 9 + }, + "ops": [ + "Gt" + ], + "comparators": [ + { + "node": { + "type": "NumberLit", + "binary_suffix": null, + "value": { + "type": "Int", + "value": 1 + } + }, + "filename": "hello.k", + "line": 27, + "column": 12, + "end_line": 27, + "end_column": 13 + } + ] + }, + "filename": "hello.k", + "line": 27, + "column": 8, + "end_line": 27, + "end_column": 13 + }, + "if_cond": null, + "msg": { + "node": { + "type": "StringLit", + "is_long_string": false, + "raw_value": "\"msg\"", + "value": "msg" + }, + "filename": "hello.k", + "line": 27, + "column": 15, + "end_line": 27, + "end_column": 20 + } + }, + "filename": "hello.k", + "line": 27, + "column": 8, + "end_line": 27, + "end_column": 20 + }, + { + "node": { + "test": { + "node": { + "type": "Identifier", + "names": [ + { + "node": "name", + "filename": "hello.k", + "line": 28, + "column": 8, + "end_line": 28, + "end_column": 12 + } + ], + "pkgpath": "", + "ctx": "Load" + }, + "filename": "hello.k", + "line": 28, + "column": 8, + "end_line": 28, + "end_column": 12 + }, + "if_cond": null, + "msg": null + }, + "filename": "hello.k", + "line": 28, + "column": 8, + "end_line": 28, + "end_column": 12 + }, + { + "node": { + "test": { + "node": { + "type": "Unary", + "op": "Not", + "operand": { + "node": { + "type": "NameConstantLit", + "value": "None" + }, + "filename": "hello.k", + "line": 28, + "column": 17, + "end_line": 28, + "end_column": 21 + } + }, + "filename": "hello.k", + "line": 28, + "column": 13, + "end_line": 28, + "end_column": 21 + }, + "if_cond": null, + "msg": { + "node": { + "type": "StringLit", + "is_long_string": false, + "raw_value": "\"we fail here\"", + "value": "we fail here" + }, + "filename": "hello.k", + "line": 28, + "column": 23, + "end_line": 28, + "end_column": 37 + } + }, + "filename": "hello.k", + "line": 28, + "column": 13, + "end_line": 28, + "end_column": 37 + } + ], + "index_signature": { + "node": { + "key_name": null, + "value": null, + "any_other": true, + "key_ty": { + "node": { + "type": "Basic", + "value": "Str" + }, + "filename": "hello.k", + "line": 7, + "column": 8, + "end_line": 7, + "end_column": 11 + }, + "value_ty": { + "node": { + "type": "Basic", + "value": "Int" + }, + "filename": "hello.k", + "line": 7, + "column": 14, + "end_line": 7, + "end_column": 17 + } + }, + "filename": "hello.k", + "line": 7, + "column": 4, + "end_line": 8, + "end_column": 0 + } + }, + "filename": "hello.k", + "line": 2, + "column": 0, + "end_line": 29, + "end_column": 8 + } + ], + "comments": [] +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__assert_stmt_recovery_0.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__assert_stmt_recovery_0.snap new file mode 100644 index 000000000..9c09f887d --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__assert_stmt_recovery_0.snap @@ -0,0 +1,34 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\"assert\"#)" +--- +Module { + filename: "", + doc: None, + body: [ + Node { + node: Assert( + AssertStmt { + test: Node { + node: Missing( + MissingExpr, + ), + filename: "", + line: 1, + column: 6, + end_line: 1, + end_column: 6, + }, + if_cond: None, + msg: None, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 6, + }, + ], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__assert_stmt_recovery_1.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__assert_stmt_recovery_1.snap new file mode 100644 index 000000000..bc5b75397 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__assert_stmt_recovery_1.snap @@ -0,0 +1,55 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\"assert a.\"#)" +--- +Module { + filename: "", + doc: None, + body: [ + Node { + node: Assert( + AssertStmt { + test: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 7, + end_line: 1, + end_column: 8, + }, + Node { + node: "", + filename: "", + line: 1, + column: 9, + end_line: 1, + end_column: 9, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 7, + end_line: 1, + end_column: 9, + }, + if_cond: None, + msg: None, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 9, + }, + ], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__assert_stmt_recovery_2.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__assert_stmt_recovery_2.snap new file mode 100644 index 000000000..bbda939cc --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__assert_stmt_recovery_2.snap @@ -0,0 +1,74 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\"assert True,,, 'msg'\"#)" +--- +Module { + filename: "", + doc: None, + body: [ + Node { + node: Assert( + AssertStmt { + test: Node { + node: NameConstantLit( + NameConstantLit { + value: True, + }, + ), + filename: "", + line: 1, + column: 7, + end_line: 1, + end_column: 11, + }, + if_cond: None, + msg: Some( + Node { + node: Missing( + MissingExpr, + ), + filename: "", + line: 1, + column: 12, + end_line: 1, + end_column: 13, + }, + ), + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 12, + }, + Node { + node: Expr( + ExprStmt { + exprs: [ + Node { + node: StringLit( + StringLit { + is_long_string: false, + raw_value: "'msg'", + value: "msg", + }, + ), + filename: "", + line: 1, + column: 15, + end_line: 1, + end_column: 20, + }, + ], + }, + ), + filename: "", + line: 1, + column: 15, + end_line: 1, + end_column: 20, + }, + ], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__assert_stmt_recovery_3.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__assert_stmt_recovery_3.snap new file mode 100644 index 000000000..cd30623eb --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__assert_stmt_recovery_3.snap @@ -0,0 +1,123 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\"assert True if data else 'msg'\"#)" +--- +Module { + filename: "", + doc: None, + body: [ + Node { + node: Assert( + AssertStmt { + test: Node { + node: NameConstantLit( + NameConstantLit { + value: True, + }, + ), + filename: "", + line: 1, + column: 7, + end_line: 1, + end_column: 11, + }, + if_cond: Some( + Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "data", + filename: "", + line: 1, + column: 15, + end_line: 1, + end_column: 19, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 15, + end_line: 1, + end_column: 19, + }, + ), + msg: None, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 19, + }, + Node { + node: Expr( + ExprStmt { + exprs: [ + Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "else", + filename: "", + line: 1, + column: 20, + end_line: 1, + end_column: 24, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 20, + end_line: 1, + end_column: 24, + }, + ], + }, + ), + filename: "", + line: 1, + column: 20, + end_line: 1, + end_column: 24, + }, + Node { + node: Expr( + ExprStmt { + exprs: [ + Node { + node: StringLit( + StringLit { + is_long_string: false, + raw_value: "'msg'", + value: "msg", + }, + ), + filename: "", + line: 1, + column: 25, + end_line: 1, + end_column: 30, + }, + ], + }, + ), + filename: "", + line: 1, + column: 25, + end_line: 1, + end_column: 30, + }, + ], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__assign_stmt_recovery_0.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__assign_stmt_recovery_0.snap new file mode 100644 index 000000000..6951e9b94 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__assign_stmt_recovery_0.snap @@ -0,0 +1,54 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\"a = \"#)" +--- +Module { + filename: "", + doc: None, + body: [ + Node { + node: Assign( + AssignStmt { + targets: [ + Node { + node: Target { + name: Node { + node: "a", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + paths: [], + pkgpath: "", + }, + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + value: Node { + node: Missing( + MissingExpr, + ), + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 4, + }, + ty: None, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 3, + }, + ], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__assign_stmt_recovery_1.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__assign_stmt_recovery_1.snap new file mode 100644 index 000000000..5c468008e --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__assign_stmt_recovery_1.snap @@ -0,0 +1,39 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\" = 1\"#)" +--- +Module { + filename: "", + doc: None, + body: [ + Node { + node: Expr( + ExprStmt { + exprs: [ + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 1, + ), + }, + ), + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 4, + }, + ], + }, + ), + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 4, + }, + ], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__assign_stmt_recovery_10.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__assign_stmt_recovery_10.snap new file mode 100644 index 000000000..2f4e3439a --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__assign_stmt_recovery_10.snap @@ -0,0 +1,75 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\"a[0] -= 1\"#)" +--- +Module { + filename: "", + doc: None, + body: [ + Node { + node: AugAssign( + AugAssignStmt { + target: Node { + node: Target { + name: Node { + node: "a", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + paths: [ + Index( + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 0, + ), + }, + ), + filename: "", + line: 1, + column: 2, + end_line: 1, + end_column: 3, + }, + ), + ], + pkgpath: "", + }, + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 4, + }, + value: Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 1, + ), + }, + ), + filename: "", + line: 1, + column: 8, + end_line: 1, + end_column: 9, + }, + op: Sub, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 9, + }, + ], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__assign_stmt_recovery_11.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__assign_stmt_recovery_11.snap new file mode 100644 index 000000000..a645f9dcb --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__assign_stmt_recovery_11.snap @@ -0,0 +1,85 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\"a[0].b -= 1\"#)" +--- +Module { + filename: "", + doc: None, + body: [ + Node { + node: AugAssign( + AugAssignStmt { + target: Node { + node: Target { + name: Node { + node: "a", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + paths: [ + Index( + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 0, + ), + }, + ), + filename: "", + line: 1, + column: 2, + end_line: 1, + end_column: 3, + }, + ), + Member( + Node { + node: "b", + filename: "", + line: 1, + column: 5, + end_line: 1, + end_column: 6, + }, + ), + ], + pkgpath: "", + }, + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 6, + }, + value: Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 1, + ), + }, + ), + filename: "", + line: 1, + column: 10, + end_line: 1, + end_column: 11, + }, + op: Sub, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 11, + }, + ], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__assign_stmt_recovery_12.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__assign_stmt_recovery_12.snap new file mode 100644 index 000000000..5a184e372 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__assign_stmt_recovery_12.snap @@ -0,0 +1,87 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\"a.b[0] = 1\"#)" +--- +Module { + filename: "", + doc: None, + body: [ + Node { + node: Assign( + AssignStmt { + targets: [ + Node { + node: Target { + name: Node { + node: "a", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + paths: [ + Member( + Node { + node: "b", + filename: "", + line: 1, + column: 2, + end_line: 1, + end_column: 3, + }, + ), + Index( + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 0, + ), + }, + ), + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 5, + }, + ), + ], + pkgpath: "", + }, + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 6, + }, + ], + value: Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 1, + ), + }, + ), + filename: "", + line: 1, + column: 9, + end_line: 1, + end_column: 10, + }, + ty: None, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 10, + }, + ], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__assign_stmt_recovery_13.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__assign_stmt_recovery_13.snap new file mode 100644 index 000000000..edc868d44 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__assign_stmt_recovery_13.snap @@ -0,0 +1,39 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\"a().b = 1\"#)" +--- +Module { + filename: "", + doc: None, + body: [ + Node { + node: Assign( + AssignStmt { + targets: [], + value: Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 1, + ), + }, + ), + filename: "", + line: 1, + column: 8, + end_line: 1, + end_column: 9, + }, + ty: None, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 9, + }, + ], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__assign_stmt_recovery_14.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__assign_stmt_recovery_14.snap new file mode 100644 index 000000000..2f7c2a746 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__assign_stmt_recovery_14.snap @@ -0,0 +1,39 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\"a.b[1:2] = 1\"#)" +--- +Module { + filename: "", + doc: None, + body: [ + Node { + node: Assign( + AssignStmt { + targets: [], + value: Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 1, + ), + }, + ), + filename: "", + line: 1, + column: 11, + end_line: 1, + end_column: 12, + }, + ty: None, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 12, + }, + ], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__assign_stmt_recovery_15.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__assign_stmt_recovery_15.snap new file mode 100644 index 000000000..e078d719c --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__assign_stmt_recovery_15.snap @@ -0,0 +1,39 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\"a.b[1::2].c = 1\"#)" +--- +Module { + filename: "", + doc: None, + body: [ + Node { + node: Assign( + AssignStmt { + targets: [], + value: Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 1, + ), + }, + ), + filename: "", + line: 1, + column: 14, + end_line: 1, + end_column: 15, + }, + ty: None, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 15, + }, + ], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__assign_stmt_recovery_16.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__assign_stmt_recovery_16.snap new file mode 100644 index 000000000..194969bad --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__assign_stmt_recovery_16.snap @@ -0,0 +1,113 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\"a.b[c.d].e = 1\"#)" +--- +Module { + filename: "", + doc: None, + body: [ + Node { + node: Assign( + AssignStmt { + targets: [ + Node { + node: Target { + name: Node { + node: "a", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + paths: [ + Member( + Node { + node: "b", + filename: "", + line: 1, + column: 2, + end_line: 1, + end_column: 3, + }, + ), + Index( + Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "c", + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 5, + }, + Node { + node: "d", + filename: "", + line: 1, + column: 6, + end_line: 1, + end_column: 7, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 7, + }, + ), + Member( + Node { + node: "e", + filename: "", + line: 1, + column: 9, + end_line: 1, + end_column: 10, + }, + ), + ], + pkgpath: "", + }, + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 10, + }, + ], + value: Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 1, + ), + }, + ), + filename: "", + line: 1, + column: 13, + end_line: 1, + end_column: 14, + }, + ty: None, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 14, + }, + ], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__assign_stmt_recovery_17.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__assign_stmt_recovery_17.snap new file mode 100644 index 000000000..0e86e730d --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__assign_stmt_recovery_17.snap @@ -0,0 +1,124 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\"a.b[1 + 1].e = 1\"#)" +--- +Module { + filename: "", + doc: None, + body: [ + Node { + node: Assign( + AssignStmt { + targets: [ + Node { + node: Target { + name: Node { + node: "a", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + paths: [ + Member( + Node { + node: "b", + filename: "", + line: 1, + column: 2, + end_line: 1, + end_column: 3, + }, + ), + Index( + Node { + node: Binary( + BinaryExpr { + left: Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 1, + ), + }, + ), + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 5, + }, + op: Add, + right: Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 1, + ), + }, + ), + filename: "", + line: 1, + column: 8, + end_line: 1, + end_column: 9, + }, + }, + ), + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 9, + }, + ), + Member( + Node { + node: "e", + filename: "", + line: 1, + column: 11, + end_line: 1, + end_column: 12, + }, + ), + ], + pkgpath: "", + }, + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 12, + }, + ], + value: Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 1, + ), + }, + ), + filename: "", + line: 1, + column: 15, + end_line: 1, + end_column: 16, + }, + ty: None, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 16, + }, + ], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__assign_stmt_recovery_18.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__assign_stmt_recovery_18.snap new file mode 100644 index 000000000..357af11a9 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__assign_stmt_recovery_18.snap @@ -0,0 +1,118 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\"a.b[f()].e = 1\"#)" +--- +Module { + filename: "", + doc: None, + body: [ + Node { + node: Assign( + AssignStmt { + targets: [ + Node { + node: Target { + name: Node { + node: "a", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + paths: [ + Member( + Node { + node: "b", + filename: "", + line: 1, + column: 2, + end_line: 1, + end_column: 3, + }, + ), + Index( + Node { + node: Call( + CallExpr { + func: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "f", + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 5, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 5, + }, + args: [], + keywords: [], + }, + ), + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 7, + }, + ), + Member( + Node { + node: "e", + filename: "", + line: 1, + column: 9, + end_line: 1, + end_column: 10, + }, + ), + ], + pkgpath: "", + }, + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 10, + }, + ], + value: Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 1, + ), + }, + ), + filename: "", + line: 1, + column: 13, + end_line: 1, + end_column: 14, + }, + ty: None, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 14, + }, + ], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__assign_stmt_recovery_2.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__assign_stmt_recovery_2.snap new file mode 100644 index 000000000..53e11fbb5 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__assign_stmt_recovery_2.snap @@ -0,0 +1,65 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\"a: int =\"#)" +--- +Module { + filename: "", + doc: None, + body: [ + Node { + node: Assign( + AssignStmt { + targets: [ + Node { + node: Target { + name: Node { + node: "a", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + paths: [], + pkgpath: "", + }, + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + value: Node { + node: Missing( + MissingExpr, + ), + filename: "", + line: 1, + column: 8, + end_line: 1, + end_column: 8, + }, + ty: Some( + Node { + node: Basic( + Int, + ), + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 6, + }, + ), + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 8, + }, + ], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__assign_stmt_recovery_3.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__assign_stmt_recovery_3.snap new file mode 100644 index 000000000..07cdee130 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__assign_stmt_recovery_3.snap @@ -0,0 +1,83 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\"a: a = 1\"#)" +--- +Module { + filename: "", + doc: None, + body: [ + Node { + node: Assign( + AssignStmt { + targets: [ + Node { + node: Target { + name: Node { + node: "a", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + paths: [], + pkgpath: "", + }, + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + value: Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 1, + ), + }, + ), + filename: "", + line: 1, + column: 7, + end_line: 1, + end_column: 8, + }, + ty: Some( + Node { + node: Named( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 4, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 4, + }, + ), + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 8, + }, + ], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__assign_stmt_recovery_4.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__assign_stmt_recovery_4.snap new file mode 100644 index 000000000..a57200e48 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__assign_stmt_recovery_4.snap @@ -0,0 +1,63 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\"a:\"#)" +--- +Module { + filename: "", + doc: None, + body: [ + Node { + node: Assign( + AssignStmt { + targets: [ + Node { + node: Target { + name: Node { + node: "a", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + paths: [], + pkgpath: "", + }, + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + value: Node { + node: Missing( + MissingExpr, + ), + filename: "", + line: 1, + column: 2, + end_line: 1, + end_column: 2, + }, + ty: Some( + Node { + node: Any, + filename: "", + line: 1, + column: 2, + end_line: 1, + end_column: 2, + }, + ), + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__assign_stmt_recovery_5.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__assign_stmt_recovery_5.snap new file mode 100644 index 000000000..9086a33ef --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__assign_stmt_recovery_5.snap @@ -0,0 +1,73 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\"a = b = \"#)" +--- +Module { + filename: "", + doc: None, + body: [ + Node { + node: Assign( + AssignStmt { + targets: [ + Node { + node: Target { + name: Node { + node: "a", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + paths: [], + pkgpath: "", + }, + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + Node { + node: Target { + name: Node { + node: "b", + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 5, + }, + paths: [], + pkgpath: "", + }, + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 5, + }, + ], + value: Node { + node: Missing( + MissingExpr, + ), + filename: "", + line: 1, + column: 8, + end_line: 1, + end_column: 8, + }, + ty: None, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 7, + }, + ], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__assign_stmt_recovery_6.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__assign_stmt_recovery_6.snap new file mode 100644 index 000000000..edd7b68e7 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__assign_stmt_recovery_6.snap @@ -0,0 +1,78 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\"a() = b. = c\"#)" +--- +Module { + filename: "", + doc: None, + body: [ + Node { + node: Assign( + AssignStmt { + targets: [ + Node { + node: Target { + name: Node { + node: "b", + filename: "", + line: 1, + column: 6, + end_line: 1, + end_column: 7, + }, + paths: [ + Member( + Node { + node: "", + filename: "", + line: 1, + column: 9, + end_line: 1, + end_column: 9, + }, + ), + ], + pkgpath: "", + }, + filename: "", + line: 1, + column: 6, + end_line: 1, + end_column: 8, + }, + ], + value: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "c", + filename: "", + line: 1, + column: 11, + end_line: 1, + end_column: 12, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 11, + end_line: 1, + end_column: 12, + }, + ty: None, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 12, + }, + ], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__assign_stmt_recovery_7.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__assign_stmt_recovery_7.snap new file mode 100644 index 000000000..027ddcbd3 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__assign_stmt_recovery_7.snap @@ -0,0 +1,73 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\"a: () = 0\"#)" +--- +Module { + filename: "", + doc: None, + body: [ + Node { + node: Assign( + AssignStmt { + targets: [ + Node { + node: Target { + name: Node { + node: "a", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + paths: [], + pkgpath: "", + }, + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + value: Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 0, + ), + }, + ), + filename: "", + line: 1, + column: 8, + end_line: 1, + end_column: 9, + }, + ty: Some( + Node { + node: Function( + FunctionType { + params_ty: None, + ret_ty: None, + }, + ), + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 5, + }, + ), + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 9, + }, + ], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__assign_stmt_recovery_8.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__assign_stmt_recovery_8.snap new file mode 100644 index 000000000..027ddcbd3 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__assign_stmt_recovery_8.snap @@ -0,0 +1,73 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\"a: () = 0\"#)" +--- +Module { + filename: "", + doc: None, + body: [ + Node { + node: Assign( + AssignStmt { + targets: [ + Node { + node: Target { + name: Node { + node: "a", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + paths: [], + pkgpath: "", + }, + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + value: Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 0, + ), + }, + ), + filename: "", + line: 1, + column: 8, + end_line: 1, + end_column: 9, + }, + ty: Some( + Node { + node: Function( + FunctionType { + params_ty: None, + ret_ty: None, + }, + ), + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 5, + }, + ), + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 9, + }, + ], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__assign_stmt_recovery_9.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__assign_stmt_recovery_9.snap new file mode 100644 index 000000000..fdca2e151 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__assign_stmt_recovery_9.snap @@ -0,0 +1,10 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\"a ++= 1\"#)" +--- +Module { + filename: "", + doc: None, + body: [], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__binary_recovery_0.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__binary_recovery_0.snap new file mode 100644 index 000000000..bd7c6ee1d --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__binary_recovery_0.snap @@ -0,0 +1,28 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(r#\"a not is b\"#)" +--- +Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__binary_recovery_1.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__binary_recovery_1.snap new file mode 100644 index 000000000..c216df331 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__binary_recovery_1.snap @@ -0,0 +1,67 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(r#\"a is is not b\"#)" +--- +Node { + node: Compare( + Compare { + left: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ops: [ + Is, + ], + comparators: [ + Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "is", + filename: "", + line: 1, + column: 5, + end_line: 1, + end_column: 7, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 5, + end_line: 1, + end_column: 7, + }, + ], + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 7, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__binary_recovery_2.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__binary_recovery_2.snap new file mode 100644 index 000000000..977b93b43 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__binary_recovery_2.snap @@ -0,0 +1,28 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(r#\"a not b\"#)" +--- +Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__binary_recovery_3.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__binary_recovery_3.snap new file mode 100644 index 000000000..bf68b34e3 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__binary_recovery_3.snap @@ -0,0 +1,28 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(r#\"a not is in b\"#)" +--- +Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__binary_recovery_4.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__binary_recovery_4.snap new file mode 100644 index 000000000..d4b9948ff --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__binary_recovery_4.snap @@ -0,0 +1,67 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(r#\"a in in b\"#)" +--- +Node { + node: Compare( + Compare { + left: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ops: [ + In, + ], + comparators: [ + Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "in", + filename: "", + line: 1, + column: 5, + end_line: 1, + end_column: 7, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 5, + end_line: 1, + end_column: 7, + }, + ], + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 7, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__binary_recovery_5.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__binary_recovery_5.snap new file mode 100644 index 000000000..c597b6281 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__binary_recovery_5.snap @@ -0,0 +1,75 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(r#\"a ++ b\"#)" +--- +Node { + node: Binary( + BinaryExpr { + left: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + op: Add, + right: Node { + node: Unary( + UnaryExpr { + op: UAdd, + operand: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "b", + filename: "", + line: 1, + column: 5, + end_line: 1, + end_column: 6, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 5, + end_line: 1, + end_column: 6, + }, + }, + ), + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 6, + }, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 6, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__binary_recovery_6.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__binary_recovery_6.snap new file mode 100644 index 000000000..ad0ad2629 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__binary_recovery_6.snap @@ -0,0 +1,97 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(r#\"a -not- b\"#)" +--- +Node { + node: Binary( + BinaryExpr { + left: Node { + node: Binary( + BinaryExpr { + left: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + op: Sub, + right: Node { + node: Unary( + UnaryExpr { + op: Not, + operand: Node { + node: Missing( + MissingExpr, + ), + filename: "", + line: 1, + column: 6, + end_line: 1, + end_column: 7, + }, + }, + ), + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 6, + }, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 6, + }, + op: Sub, + right: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "b", + filename: "", + line: 1, + column: 8, + end_line: 1, + end_column: 9, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 8, + end_line: 1, + end_column: 9, + }, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 9, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__binary_recovery_7.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__binary_recovery_7.snap new file mode 100644 index 000000000..1f0594d49 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__binary_recovery_7.snap @@ -0,0 +1,63 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(r#\"a +is b\"#)" +--- +Node { + node: Binary( + BinaryExpr { + left: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + op: Add, + right: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "is", + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 5, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 5, + }, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 5, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__binary_recovery_8.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__binary_recovery_8.snap new file mode 100644 index 000000000..e76e3f815 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__binary_recovery_8.snap @@ -0,0 +1,28 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(r#\"a +=+ b\"#)" +--- +Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__call_recovery_0.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__call_recovery_0.snap new file mode 100644 index 000000000..dea4d3cfd --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__call_recovery_0.snap @@ -0,0 +1,40 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(r#\"a(\"#)" +--- +Node { + node: Call( + CallExpr { + func: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + args: [], + keywords: [], + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 2, +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__call_recovery_1.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__call_recovery_1.snap new file mode 100644 index 000000000..bdfd9fb5a --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__call_recovery_1.snap @@ -0,0 +1,41 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(r#\"a(]\"#)" +--- +Node { + node: Call( + CallExpr { + func: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + args: [], + keywords: [], + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 3, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__call_recovery_10.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__call_recovery_10.snap new file mode 100644 index 000000000..431ffacfc --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__call_recovery_10.snap @@ -0,0 +1,71 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(r#\"a(\n 1,\n 2\n)\"#)" +--- +Node { + node: Call( + CallExpr { + func: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + args: [ + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 1, + ), + }, + ), + filename: "", + line: 2, + column: 4, + end_line: 2, + end_column: 5, + }, + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 2, + ), + }, + ), + filename: "", + line: 3, + column: 4, + end_line: 3, + end_column: 5, + }, + ], + keywords: [], + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 4, + end_column: 1, +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__call_recovery_11.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__call_recovery_11.snap new file mode 100644 index 000000000..1cb2cce40 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__call_recovery_11.snap @@ -0,0 +1,71 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(r#\"a(\n 1,\n2,\n)\"#)" +--- +Node { + node: Call( + CallExpr { + func: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + args: [ + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 1, + ), + }, + ), + filename: "", + line: 2, + column: 4, + end_line: 2, + end_column: 5, + }, + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 2, + ), + }, + ), + filename: "", + line: 3, + column: 0, + end_line: 3, + end_column: 1, + }, + ], + keywords: [], + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 4, + end_column: 1, +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__call_recovery_12.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__call_recovery_12.snap new file mode 100644 index 000000000..1cb2cce40 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__call_recovery_12.snap @@ -0,0 +1,71 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(r#\"a(\n 1,\n2,\n)\"#)" +--- +Node { + node: Call( + CallExpr { + func: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + args: [ + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 1, + ), + }, + ), + filename: "", + line: 2, + column: 4, + end_line: 2, + end_column: 5, + }, + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 2, + ), + }, + ), + filename: "", + line: 3, + column: 0, + end_line: 3, + end_column: 1, + }, + ], + keywords: [], + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 4, + end_column: 1, +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__call_recovery_13.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__call_recovery_13.snap new file mode 100644 index 000000000..c3099f749 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__call_recovery_13.snap @@ -0,0 +1,71 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(r#\"a(\n 1,,\n2,\n)\"#)" +--- +Node { + node: Call( + CallExpr { + func: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + args: [ + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 1, + ), + }, + ), + filename: "", + line: 2, + column: 4, + end_line: 2, + end_column: 5, + }, + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 2, + ), + }, + ), + filename: "", + line: 3, + column: 0, + end_line: 3, + end_column: 1, + }, + ], + keywords: [], + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 4, + end_column: 1, +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__call_recovery_14.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__call_recovery_14.snap new file mode 100644 index 000000000..1e37e5050 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__call_recovery_14.snap @@ -0,0 +1,71 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(r#\"a(\n 1,\n 2,\n]\"#)" +--- +Node { + node: Call( + CallExpr { + func: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + args: [ + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 1, + ), + }, + ), + filename: "", + line: 2, + column: 4, + end_line: 2, + end_column: 5, + }, + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 2, + ), + }, + ), + filename: "", + line: 3, + column: 4, + end_line: 3, + end_column: 5, + }, + ], + keywords: [], + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 4, + end_column: 1, +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__call_recovery_2.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__call_recovery_2.snap new file mode 100644 index 000000000..80b7358cc --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__call_recovery_2.snap @@ -0,0 +1,64 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(r#\"a(a,,)\"#)" +--- +Node { + node: Call( + CallExpr { + func: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + args: [ + Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 2, + end_line: 1, + end_column: 3, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 2, + end_line: 1, + end_column: 3, + }, + ], + keywords: [], + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 6, +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__call_recovery_3.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__call_recovery_3.snap new file mode 100644 index 000000000..e853ca663 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__call_recovery_3.snap @@ -0,0 +1,113 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(r#\"a.b(a=1,2)\"#)" +--- +Node { + node: Call( + CallExpr { + func: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + Node { + node: "b", + filename: "", + line: 1, + column: 2, + end_line: 1, + end_column: 3, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 3, + }, + args: [ + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 2, + ), + }, + ), + filename: "", + line: 1, + column: 8, + end_line: 1, + end_column: 9, + }, + ], + keywords: [ + Node { + node: Keyword { + arg: Node { + node: Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 5, + }, + ], + pkgpath: "", + ctx: Load, + }, + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 5, + }, + value: Some( + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 1, + ), + }, + ), + filename: "", + line: 1, + column: 6, + end_line: 1, + end_column: 7, + }, + ), + }, + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 7, + }, + ], + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 10, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__call_recovery_4.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__call_recovery_4.snap new file mode 100644 index 000000000..174c24666 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__call_recovery_4.snap @@ -0,0 +1,113 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(r#\"a(a.ba=1,2)\"#)" +--- +Node { + node: Call( + CallExpr { + func: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + args: [ + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 2, + ), + }, + ), + filename: "", + line: 1, + column: 9, + end_line: 1, + end_column: 10, + }, + ], + keywords: [ + Node { + node: Keyword { + arg: Node { + node: Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 2, + end_line: 1, + end_column: 3, + }, + Node { + node: "ba", + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 6, + }, + ], + pkgpath: "", + ctx: Load, + }, + filename: "", + line: 1, + column: 2, + end_line: 1, + end_column: 6, + }, + value: Some( + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 1, + ), + }, + ), + filename: "", + line: 1, + column: 7, + end_line: 1, + end_column: 8, + }, + ), + }, + filename: "", + line: 1, + column: 2, + end_line: 1, + end_column: 8, + }, + ], + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 11, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__call_recovery_5.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__call_recovery_5.snap new file mode 100644 index 000000000..b279a496b --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__call_recovery_5.snap @@ -0,0 +1,96 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(r#\"a(a.b+a=1,2)\"#)" +--- +Node { + node: Call( + CallExpr { + func: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + args: [ + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 2, + ), + }, + ), + filename: "", + line: 1, + column: 10, + end_line: 1, + end_column: 11, + }, + ], + keywords: [ + Node { + node: Keyword { + arg: Node { + node: Identifier { + names: [], + pkgpath: "", + ctx: Load, + }, + filename: "", + line: 1, + column: 2, + end_line: 1, + end_column: 7, + }, + value: Some( + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 1, + ), + }, + ), + filename: "", + line: 1, + column: 8, + end_line: 1, + end_column: 9, + }, + ), + }, + filename: "", + line: 1, + column: 2, + end_line: 1, + end_column: 9, + }, + ], + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 12, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__call_recovery_6.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__call_recovery_6.snap new file mode 100644 index 000000000..0b7e629f4 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__call_recovery_6.snap @@ -0,0 +1,80 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(r#\"a(a-1.b=1)\"#)" +--- +Node { + node: Call( + CallExpr { + func: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + args: [], + keywords: [ + Node { + node: Keyword { + arg: Node { + node: Identifier { + names: [], + pkgpath: "", + ctx: Load, + }, + filename: "", + line: 1, + column: 2, + end_line: 1, + end_column: 7, + }, + value: Some( + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 1, + ), + }, + ), + filename: "", + line: 1, + column: 8, + end_line: 1, + end_column: 9, + }, + ), + }, + filename: "", + line: 1, + column: 2, + end_line: 1, + end_column: 9, + }, + ], + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 10, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__call_recovery_7.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__call_recovery_7.snap new file mode 100644 index 000000000..064b56799 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__call_recovery_7.snap @@ -0,0 +1,103 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(r#\"a(type=\"list\", \"key\")\"#)" +--- +Node { + node: Call( + CallExpr { + func: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + args: [ + Node { + node: StringLit( + StringLit { + is_long_string: false, + raw_value: "\"key\"", + value: "key", + }, + ), + filename: "", + line: 1, + column: 15, + end_line: 1, + end_column: 20, + }, + ], + keywords: [ + Node { + node: Keyword { + arg: Node { + node: Identifier { + names: [ + Node { + node: "type", + filename: "", + line: 1, + column: 2, + end_line: 1, + end_column: 6, + }, + ], + pkgpath: "", + ctx: Load, + }, + filename: "", + line: 1, + column: 2, + end_line: 1, + end_column: 6, + }, + value: Some( + Node { + node: StringLit( + StringLit { + is_long_string: false, + raw_value: "\"list\"", + value: "list", + }, + ), + filename: "", + line: 1, + column: 7, + end_line: 1, + end_column: 13, + }, + ), + }, + filename: "", + line: 1, + column: 2, + end_line: 1, + end_column: 13, + }, + ], + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 21, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__call_recovery_8.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__call_recovery_8.snap new file mode 100644 index 000000000..3451c9c7c --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__call_recovery_8.snap @@ -0,0 +1,71 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(r#\"a(\n 1,2\n)\"#)" +--- +Node { + node: Call( + CallExpr { + func: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + args: [ + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 1, + ), + }, + ), + filename: "", + line: 2, + column: 4, + end_line: 2, + end_column: 5, + }, + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 2, + ), + }, + ), + filename: "", + line: 2, + column: 6, + end_line: 2, + end_column: 7, + }, + ], + keywords: [], + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 3, + end_column: 1, +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__call_recovery_9.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__call_recovery_9.snap new file mode 100644 index 000000000..7610c0fe1 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__call_recovery_9.snap @@ -0,0 +1,71 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(r#\"a(1,2\n)\"#)" +--- +Node { + node: Call( + CallExpr { + func: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + args: [ + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 1, + ), + }, + ), + filename: "", + line: 1, + column: 2, + end_line: 1, + end_column: 3, + }, + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 2, + ), + }, + ), + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 5, + }, + ], + keywords: [], + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 5, +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__comp_clause_recovery_0.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__comp_clause_recovery_0.snap new file mode 100644 index 000000000..8a232b432 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__comp_clause_recovery_0.snap @@ -0,0 +1,133 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(\"[i for i in [1,2,3]]\")" +--- +Node { + node: ListComp( + ListComp { + elt: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "i", + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 2, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 2, + }, + generators: [ + Node { + node: CompClause { + targets: [ + Node { + node: Identifier { + names: [ + Node { + node: "i", + filename: "", + line: 1, + column: 7, + end_line: 1, + end_column: 8, + }, + ], + pkgpath: "", + ctx: Load, + }, + filename: "", + line: 1, + column: 7, + end_line: 1, + end_column: 8, + }, + ], + iter: Node { + node: List( + ListExpr { + elts: [ + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 1, + ), + }, + ), + filename: "", + line: 1, + column: 13, + end_line: 1, + end_column: 14, + }, + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 2, + ), + }, + ), + filename: "", + line: 1, + column: 15, + end_line: 1, + end_column: 16, + }, + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 3, + ), + }, + ), + filename: "", + line: 1, + column: 17, + end_line: 1, + end_column: 18, + }, + ], + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 12, + end_line: 1, + end_column: 19, + }, + ifs: [], + }, + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 19, + }, + ], + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 20, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__comp_clause_recovery_1.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__comp_clause_recovery_1.snap new file mode 100644 index 000000000..4d07d7700 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__comp_clause_recovery_1.snap @@ -0,0 +1,133 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(\"[i, j for i in [1,2,3]]\")" +--- +Node { + node: ListComp( + ListComp { + elt: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "i", + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 2, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 2, + }, + generators: [ + Node { + node: CompClause { + targets: [ + Node { + node: Identifier { + names: [ + Node { + node: "i", + filename: "", + line: 1, + column: 10, + end_line: 1, + end_column: 11, + }, + ], + pkgpath: "", + ctx: Load, + }, + filename: "", + line: 1, + column: 10, + end_line: 1, + end_column: 11, + }, + ], + iter: Node { + node: List( + ListExpr { + elts: [ + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 1, + ), + }, + ), + filename: "", + line: 1, + column: 16, + end_line: 1, + end_column: 17, + }, + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 2, + ), + }, + ), + filename: "", + line: 1, + column: 18, + end_line: 1, + end_column: 19, + }, + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 3, + ), + }, + ), + filename: "", + line: 1, + column: 20, + end_line: 1, + end_column: 21, + }, + ], + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 15, + end_line: 1, + end_column: 22, + }, + ifs: [], + }, + filename: "", + line: 1, + column: 6, + end_line: 1, + end_column: 22, + }, + ], + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 23, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__comp_clause_recovery_2.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__comp_clause_recovery_2.snap new file mode 100644 index 000000000..ff66fec1f --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__comp_clause_recovery_2.snap @@ -0,0 +1,19 @@ +--- +source: parser/src/tests/error_recovery.rs +assertion_line: 73 +expression: "crate::tests::parsing_expr_string(\"[for i in [1,2,3]]\")" +--- +Node { + node: List( + ListExpr { + elts: [], + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 18, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__comp_clause_recovery_3.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__comp_clause_recovery_3.snap new file mode 100644 index 000000000..37b66105d --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__comp_clause_recovery_3.snap @@ -0,0 +1,150 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(\"{i for i in [1,2,3]}\")" +--- +Node { + node: Config( + ConfigExpr { + items: [ + Node { + node: ConfigEntry { + key: Some( + Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "i", + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 2, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 2, + }, + ), + value: Node { + node: Compare( + Compare { + left: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "i", + filename: "", + line: 1, + column: 7, + end_line: 1, + end_column: 8, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 7, + end_line: 1, + end_column: 8, + }, + ops: [ + In, + ], + comparators: [ + Node { + node: List( + ListExpr { + elts: [ + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 1, + ), + }, + ), + filename: "", + line: 1, + column: 13, + end_line: 1, + end_column: 14, + }, + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 2, + ), + }, + ), + filename: "", + line: 1, + column: 15, + end_line: 1, + end_column: 16, + }, + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 3, + ), + }, + ), + filename: "", + line: 1, + column: 17, + end_line: 1, + end_column: 18, + }, + ], + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 12, + end_line: 1, + end_column: 19, + }, + ], + }, + ), + filename: "", + line: 1, + column: 7, + end_line: 1, + end_column: 19, + }, + operation: Override, + }, + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 19, + }, + ], + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 20, +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__comp_clause_recovery_4.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__comp_clause_recovery_4.snap new file mode 100644 index 000000000..d70188e8f --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__comp_clause_recovery_4.snap @@ -0,0 +1,195 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(\"{i: for i in [1,2,3]}\")" +--- +Node { + node: Config( + ConfigExpr { + items: [ + Node { + node: ConfigEntry { + key: Some( + Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "i", + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 2, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 2, + }, + ), + value: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "for", + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 7, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 7, + }, + operation: Union, + }, + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 7, + }, + Node { + node: ConfigEntry { + key: Some( + Node { + node: Compare( + Compare { + left: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "i", + filename: "", + line: 1, + column: 8, + end_line: 1, + end_column: 9, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 8, + end_line: 1, + end_column: 9, + }, + ops: [ + In, + ], + comparators: [ + Node { + node: List( + ListExpr { + elts: [ + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 1, + ), + }, + ), + filename: "", + line: 1, + column: 14, + end_line: 1, + end_column: 15, + }, + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 2, + ), + }, + ), + filename: "", + line: 1, + column: 16, + end_line: 1, + end_column: 17, + }, + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 3, + ), + }, + ), + filename: "", + line: 1, + column: 18, + end_line: 1, + end_column: 19, + }, + ], + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 13, + end_line: 1, + end_column: 20, + }, + ], + }, + ), + filename: "", + line: 1, + column: 8, + end_line: 1, + end_column: 20, + }, + ), + value: Node { + node: Missing( + MissingExpr, + ), + filename: "", + line: 1, + column: 21, + end_line: 1, + end_column: 21, + }, + operation: Override, + }, + filename: "", + line: 1, + column: 8, + end_line: 1, + end_column: 21, + }, + ], + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 21, +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__comp_clause_recovery_5.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__comp_clause_recovery_5.snap new file mode 100644 index 000000000..be499bccb --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__comp_clause_recovery_5.snap @@ -0,0 +1,200 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(\"{i: 1, j for i in [1,2,3]}\")" +--- +Node { + node: Config( + ConfigExpr { + items: [ + Node { + node: ConfigEntry { + key: Some( + Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "i", + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 2, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 2, + }, + ), + value: Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 1, + ), + }, + ), + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 5, + }, + operation: Union, + }, + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 5, + }, + Node { + node: ConfigEntry { + key: Some( + Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "j", + filename: "", + line: 1, + column: 7, + end_line: 1, + end_column: 8, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 7, + end_line: 1, + end_column: 8, + }, + ), + value: Node { + node: Compare( + Compare { + left: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "i", + filename: "", + line: 1, + column: 13, + end_line: 1, + end_column: 14, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 13, + end_line: 1, + end_column: 14, + }, + ops: [ + In, + ], + comparators: [ + Node { + node: List( + ListExpr { + elts: [ + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 1, + ), + }, + ), + filename: "", + line: 1, + column: 19, + end_line: 1, + end_column: 20, + }, + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 2, + ), + }, + ), + filename: "", + line: 1, + column: 21, + end_line: 1, + end_column: 22, + }, + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 3, + ), + }, + ), + filename: "", + line: 1, + column: 23, + end_line: 1, + end_column: 24, + }, + ], + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 18, + end_line: 1, + end_column: 25, + }, + ], + }, + ), + filename: "", + line: 1, + column: 13, + end_line: 1, + end_column: 25, + }, + operation: Override, + }, + filename: "", + line: 1, + column: 7, + end_line: 1, + end_column: 25, + }, + ], + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 26, +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__comp_clause_recovery_6.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__comp_clause_recovery_6.snap new file mode 100644 index 000000000..12c72821e --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__comp_clause_recovery_6.snap @@ -0,0 +1,18 @@ +--- +source: parser/src/tests/error_recovery.rs +assertion_line: 77 +expression: "crate::tests::parsing_expr_string(\"{for i in [1,2,3]}\")" +--- +Node { + node: Config( + ConfigExpr { + items: [], + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 18, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__compare_recovery_0.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__compare_recovery_0.snap new file mode 100644 index 000000000..a64d0b4e7 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__compare_recovery_0.snap @@ -0,0 +1,78 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(r#\"a <> b\"#)" +--- +Node { + node: Compare( + Compare { + left: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ops: [ + Lt, + Gt, + ], + comparators: [ + Node { + node: Missing( + MissingExpr, + ), + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 4, + }, + Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "b", + filename: "", + line: 1, + column: 5, + end_line: 1, + end_column: 6, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 5, + end_line: 1, + end_column: 6, + }, + ], + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 6, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__compare_recovery_1.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__compare_recovery_1.snap new file mode 100644 index 000000000..d75e31cfd --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__compare_recovery_1.snap @@ -0,0 +1,107 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(r#\"a < !b >!1\"#)" +--- +Node { + node: Compare( + Compare { + left: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ops: [ + Lt, + Gt, + ], + comparators: [ + Node { + node: Unary( + UnaryExpr { + op: Not, + operand: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "b", + filename: "", + line: 1, + column: 5, + end_line: 1, + end_column: 6, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 5, + end_line: 1, + end_column: 6, + }, + }, + ), + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 6, + }, + Node { + node: Unary( + UnaryExpr { + op: Not, + operand: Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 1, + ), + }, + ), + filename: "", + line: 1, + column: 9, + end_line: 1, + end_column: 10, + }, + }, + ), + filename: "", + line: 1, + column: 8, + end_line: 1, + end_column: 10, + }, + ], + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 10, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__compare_recovery_2.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__compare_recovery_2.snap new file mode 100644 index 000000000..d75e31cfd --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__compare_recovery_2.snap @@ -0,0 +1,107 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(r#\"a < !b >!1\"#)" +--- +Node { + node: Compare( + Compare { + left: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ops: [ + Lt, + Gt, + ], + comparators: [ + Node { + node: Unary( + UnaryExpr { + op: Not, + operand: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "b", + filename: "", + line: 1, + column: 5, + end_line: 1, + end_column: 6, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 5, + end_line: 1, + end_column: 6, + }, + }, + ), + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 6, + }, + Node { + node: Unary( + UnaryExpr { + op: Not, + operand: Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 1, + ), + }, + ), + filename: "", + line: 1, + column: 9, + end_line: 1, + end_column: 10, + }, + }, + ), + filename: "", + line: 1, + column: 8, + end_line: 1, + end_column: 10, + }, + ], + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 10, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__compare_recovery_3.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__compare_recovery_3.snap new file mode 100644 index 000000000..d7b4ce34f --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__compare_recovery_3.snap @@ -0,0 +1,89 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(r#\"a <<< b\"#)" +--- +Node { + node: Compare( + Compare { + left: Node { + node: Binary( + BinaryExpr { + left: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + op: LShift, + right: Node { + node: Missing( + MissingExpr, + ), + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 5, + }, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 4, + }, + ops: [ + Lt, + ], + comparators: [ + Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "b", + filename: "", + line: 1, + column: 6, + end_line: 1, + end_column: 7, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 6, + end_line: 1, + end_column: 7, + }, + ], + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 7, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__compare_recovery_4.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__compare_recovery_4.snap new file mode 100644 index 000000000..180757482 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__compare_recovery_4.snap @@ -0,0 +1,90 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(r#\"a <+< b\"#)" +--- +Node { + node: Compare( + Compare { + left: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ops: [ + Lt, + Lt, + ], + comparators: [ + Node { + node: Unary( + UnaryExpr { + op: UAdd, + operand: Node { + node: Missing( + MissingExpr, + ), + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 5, + }, + }, + ), + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 4, + }, + Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "b", + filename: "", + line: 1, + column: 6, + end_line: 1, + end_column: 7, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 6, + end_line: 1, + end_column: 7, + }, + ], + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 7, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__compare_recovery_5.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__compare_recovery_5.snap new file mode 100644 index 000000000..3b231aeec --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__compare_recovery_5.snap @@ -0,0 +1,79 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(r#\"a >+ b\"#)" +--- +Node { + node: Compare( + Compare { + left: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ops: [ + Gt, + ], + comparators: [ + Node { + node: Unary( + UnaryExpr { + op: UAdd, + operand: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "b", + filename: "", + line: 1, + column: 5, + end_line: 1, + end_column: 6, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 5, + end_line: 1, + end_column: 6, + }, + }, + ), + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 6, + }, + ], + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 6, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__compare_recovery_6.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__compare_recovery_6.snap new file mode 100644 index 000000000..d0df0d26a --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__compare_recovery_6.snap @@ -0,0 +1,90 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(r#\"+ b\"#)" +--- +Node { + node: Compare( + Compare { + left: Node { + node: Missing( + MissingExpr, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ops: [ + Lt, + Gt, + ], + comparators: [ + Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 2, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 2, + }, + Node { + node: Unary( + UnaryExpr { + op: UAdd, + operand: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "b", + filename: "", + line: 1, + column: 6, + end_line: 1, + end_column: 7, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 6, + end_line: 1, + end_column: 7, + }, + }, + ), + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 7, + }, + ], + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 7, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__config_recovery_0.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__config_recovery_0.snap new file mode 100644 index 000000000..cfe32a67b --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__config_recovery_0.snap @@ -0,0 +1,18 @@ +--- +source: parser/src/tests/error_recovery.rs +assertion_line: 14 +expression: "crate::tests::parsing_expr_string(\"{\")" +--- +Node { + node: Config( + ConfigExpr { + items: [], + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__config_recovery_1.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__config_recovery_1.snap new file mode 100644 index 000000000..df71197c7 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__config_recovery_1.snap @@ -0,0 +1,67 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(\"{a = 1\")" +--- +Node { + node: Config( + ConfigExpr { + items: [ + Node { + node: ConfigEntry { + key: Some( + Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 2, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 2, + }, + ), + value: Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 1, + ), + }, + ), + filename: "", + line: 1, + column: 5, + end_line: 1, + end_column: 6, + }, + operation: Override, + }, + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 6, + }, + ], + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 6, +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__config_recovery_10.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__config_recovery_10.snap new file mode 100644 index 000000000..3d0af9815 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__config_recovery_10.snap @@ -0,0 +1,118 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(\"{**a, *b}\")" +--- +Node { + node: Config( + ConfigExpr { + items: [ + Node { + node: ConfigEntry { + key: None, + value: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 4, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 4, + }, + operation: Union, + }, + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 4, + }, + Node { + node: ConfigEntry { + key: Some( + Node { + node: Binary( + BinaryExpr { + left: Node { + node: Missing( + MissingExpr, + ), + filename: "", + line: 1, + column: 6, + end_line: 1, + end_column: 7, + }, + op: Mul, + right: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "b", + filename: "", + line: 1, + column: 7, + end_line: 1, + end_column: 8, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 7, + end_line: 1, + end_column: 8, + }, + }, + ), + filename: "", + line: 1, + column: 6, + end_line: 1, + end_column: 8, + }, + ), + value: Node { + node: Missing( + MissingExpr, + ), + filename: "", + line: 1, + column: 9, + end_line: 1, + end_column: 9, + }, + operation: Override, + }, + filename: "", + line: 1, + column: 6, + end_line: 1, + end_column: 9, + }, + ], + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 9, +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__config_recovery_11.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__config_recovery_11.snap new file mode 100644 index 000000000..166a1b7b4 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__config_recovery_11.snap @@ -0,0 +1,149 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(\"{if True: a = , b = 2}\")" +--- +Node { + node: Config( + ConfigExpr { + items: [ + Node { + node: ConfigEntry { + key: None, + value: Node { + node: ConfigIfEntry( + ConfigIfEntryExpr { + if_cond: Node { + node: NameConstantLit( + NameConstantLit { + value: True, + }, + ), + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 8, + }, + items: [ + Node { + node: ConfigEntry { + key: Some( + Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 10, + end_line: 1, + end_column: 11, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 10, + end_line: 1, + end_column: 11, + }, + ), + value: Node { + node: Missing( + MissingExpr, + ), + filename: "", + line: 1, + column: 14, + end_line: 1, + end_column: 15, + }, + operation: Override, + }, + filename: "", + line: 1, + column: 10, + end_line: 1, + end_column: 15, + }, + ], + orelse: None, + }, + ), + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 15, + }, + operation: Union, + }, + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 15, + }, + Node { + node: ConfigEntry { + key: Some( + Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "b", + filename: "", + line: 1, + column: 16, + end_line: 1, + end_column: 17, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 16, + end_line: 1, + end_column: 17, + }, + ), + value: Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 2, + ), + }, + ), + filename: "", + line: 1, + column: 20, + end_line: 1, + end_column: 21, + }, + operation: Override, + }, + filename: "", + line: 1, + column: 16, + end_line: 1, + end_column: 21, + }, + ], + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 22, +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__config_recovery_12.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__config_recovery_12.snap new file mode 100644 index 000000000..8d7da0285 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__config_recovery_12.snap @@ -0,0 +1,171 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(\"{if True: *a, b = 2}\")" +--- +Node { + node: Config( + ConfigExpr { + items: [ + Node { + node: ConfigEntry { + key: None, + value: Node { + node: ConfigIfEntry( + ConfigIfEntryExpr { + if_cond: Node { + node: NameConstantLit( + NameConstantLit { + value: True, + }, + ), + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 8, + }, + items: [ + Node { + node: ConfigEntry { + key: Some( + Node { + node: Binary( + BinaryExpr { + left: Node { + node: Missing( + MissingExpr, + ), + filename: "", + line: 1, + column: 10, + end_line: 1, + end_column: 11, + }, + op: Mul, + right: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 11, + end_line: 1, + end_column: 12, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 11, + end_line: 1, + end_column: 12, + }, + }, + ), + filename: "", + line: 1, + column: 10, + end_line: 1, + end_column: 12, + }, + ), + value: Node { + node: Missing( + MissingExpr, + ), + filename: "", + line: 1, + column: 12, + end_line: 1, + end_column: 13, + }, + operation: Override, + }, + filename: "", + line: 1, + column: 10, + end_line: 1, + end_column: 13, + }, + ], + orelse: None, + }, + ), + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 13, + }, + operation: Union, + }, + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 13, + }, + Node { + node: ConfigEntry { + key: Some( + Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "b", + filename: "", + line: 1, + column: 14, + end_line: 1, + end_column: 15, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 14, + end_line: 1, + end_column: 15, + }, + ), + value: Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 2, + ), + }, + ), + filename: "", + line: 1, + column: 18, + end_line: 1, + end_column: 19, + }, + operation: Override, + }, + filename: "", + line: 1, + column: 14, + end_line: 1, + end_column: 19, + }, + ], + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 20, +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__config_recovery_13.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__config_recovery_13.snap new file mode 100644 index 000000000..4510d3d24 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__config_recovery_13.snap @@ -0,0 +1,101 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(\"{if True: key: {}}\")" +--- +Node { + node: Config( + ConfigExpr { + items: [ + Node { + node: ConfigEntry { + key: None, + value: Node { + node: ConfigIfEntry( + ConfigIfEntryExpr { + if_cond: Node { + node: NameConstantLit( + NameConstantLit { + value: True, + }, + ), + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 8, + }, + items: [ + Node { + node: ConfigEntry { + key: Some( + Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "key", + filename: "", + line: 1, + column: 10, + end_line: 1, + end_column: 13, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 10, + end_line: 1, + end_column: 13, + }, + ), + value: Node { + node: Config( + ConfigExpr { + items: [], + }, + ), + filename: "", + line: 1, + column: 15, + end_line: 1, + end_column: 17, + }, + operation: Union, + }, + filename: "", + line: 1, + column: 10, + end_line: 1, + end_column: 17, + }, + ], + orelse: None, + }, + ), + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 18, + }, + operation: Union, + }, + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 17, + }, + ], + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 18, +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__config_recovery_14.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__config_recovery_14.snap new file mode 100644 index 000000000..3a2992a34 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__config_recovery_14.snap @@ -0,0 +1,102 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(\"{if True: key: []}\")" +--- +Node { + node: Config( + ConfigExpr { + items: [ + Node { + node: ConfigEntry { + key: None, + value: Node { + node: ConfigIfEntry( + ConfigIfEntryExpr { + if_cond: Node { + node: NameConstantLit( + NameConstantLit { + value: True, + }, + ), + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 8, + }, + items: [ + Node { + node: ConfigEntry { + key: Some( + Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "key", + filename: "", + line: 1, + column: 10, + end_line: 1, + end_column: 13, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 10, + end_line: 1, + end_column: 13, + }, + ), + value: Node { + node: List( + ListExpr { + elts: [], + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 15, + end_line: 1, + end_column: 17, + }, + operation: Union, + }, + filename: "", + line: 1, + column: 10, + end_line: 1, + end_column: 17, + }, + ], + orelse: None, + }, + ), + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 18, + }, + operation: Union, + }, + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 17, + }, + ], + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 18, +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__config_recovery_15.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__config_recovery_15.snap new file mode 100644 index 000000000..e988ccd02 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__config_recovery_15.snap @@ -0,0 +1,62 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(\"{你好\")" +--- +Node { + node: Config( + ConfigExpr { + items: [ + Node { + node: ConfigEntry { + key: Some( + Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "你好", + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 3, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 3, + }, + ), + value: Node { + node: Missing( + MissingExpr, + ), + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 3, + }, + operation: Override, + }, + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 3, + }, + ], + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 3, +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__config_recovery_2.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__config_recovery_2.snap new file mode 100644 index 000000000..949af7663 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__config_recovery_2.snap @@ -0,0 +1,117 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(\"{a = 1, b = 2\")" +--- +Node { + node: Config( + ConfigExpr { + items: [ + Node { + node: ConfigEntry { + key: Some( + Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 2, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 2, + }, + ), + value: Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 1, + ), + }, + ), + filename: "", + line: 1, + column: 5, + end_line: 1, + end_column: 6, + }, + operation: Override, + }, + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 6, + }, + Node { + node: ConfigEntry { + key: Some( + Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "b", + filename: "", + line: 1, + column: 8, + end_line: 1, + end_column: 9, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 8, + end_line: 1, + end_column: 9, + }, + ), + value: Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 2, + ), + }, + ), + filename: "", + line: 1, + column: 12, + end_line: 1, + end_column: 13, + }, + operation: Override, + }, + filename: "", + line: 1, + column: 8, + end_line: 1, + end_column: 13, + }, + ], + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 13, +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__config_recovery_3.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__config_recovery_3.snap new file mode 100644 index 000000000..16b95f5ca --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__config_recovery_3.snap @@ -0,0 +1,115 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(\"{a = {a = 1}\")" +--- +Node { + node: Config( + ConfigExpr { + items: [ + Node { + node: ConfigEntry { + key: Some( + Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 2, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 2, + }, + ), + value: Node { + node: Config( + ConfigExpr { + items: [ + Node { + node: ConfigEntry { + key: Some( + Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 6, + end_line: 1, + end_column: 7, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 6, + end_line: 1, + end_column: 7, + }, + ), + value: Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 1, + ), + }, + ), + filename: "", + line: 1, + column: 10, + end_line: 1, + end_column: 11, + }, + operation: Override, + }, + filename: "", + line: 1, + column: 6, + end_line: 1, + end_column: 11, + }, + ], + }, + ), + filename: "", + line: 1, + column: 5, + end_line: 1, + end_column: 12, + }, + operation: Override, + }, + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 12, + }, + ], + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 12, +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__config_recovery_4.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__config_recovery_4.snap new file mode 100644 index 000000000..1e5f38fe7 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__config_recovery_4.snap @@ -0,0 +1,115 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(\"{a = {a = 1\")" +--- +Node { + node: Config( + ConfigExpr { + items: [ + Node { + node: ConfigEntry { + key: Some( + Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 2, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 2, + }, + ), + value: Node { + node: Config( + ConfigExpr { + items: [ + Node { + node: ConfigEntry { + key: Some( + Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 6, + end_line: 1, + end_column: 7, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 6, + end_line: 1, + end_column: 7, + }, + ), + value: Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 1, + ), + }, + ), + filename: "", + line: 1, + column: 10, + end_line: 1, + end_column: 11, + }, + operation: Override, + }, + filename: "", + line: 1, + column: 6, + end_line: 1, + end_column: 11, + }, + ], + }, + ), + filename: "", + line: 1, + column: 5, + end_line: 1, + end_column: 11, + }, + operation: Override, + }, + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 11, + }, + ], + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 11, +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__config_recovery_5.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__config_recovery_5.snap new file mode 100644 index 000000000..99f796475 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__config_recovery_5.snap @@ -0,0 +1,149 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(r#\"{\n a = 1\n b = 2\n \"#)" +--- +Node { + node: Config( + ConfigExpr { + items: [ + Node { + node: ConfigEntry { + key: Some( + Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 2, + column: 4, + end_line: 2, + end_column: 5, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 2, + column: 4, + end_line: 2, + end_column: 5, + }, + ), + value: Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 1, + ), + }, + ), + filename: "", + line: 2, + column: 8, + end_line: 2, + end_column: 9, + }, + operation: Override, + }, + filename: "", + line: 2, + column: 4, + end_line: 2, + end_column: 9, + }, + Node { + node: ConfigEntry { + key: Some( + Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "b", + filename: "", + line: 3, + column: 4, + end_line: 3, + end_column: 5, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 3, + column: 4, + end_line: 3, + end_column: 5, + }, + ), + value: Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 2, + ), + }, + ), + filename: "", + line: 3, + column: 8, + end_line: 3, + end_column: 9, + }, + operation: Override, + }, + filename: "", + line: 3, + column: 4, + end_line: 3, + end_column: 9, + }, + Node { + node: ConfigEntry { + key: Some( + Node { + node: Missing( + MissingExpr, + ), + filename: "", + line: 4, + column: 4, + end_line: 4, + end_column: 4, + }, + ), + value: Node { + node: Missing( + MissingExpr, + ), + filename: "", + line: 4, + column: 4, + end_line: 4, + end_column: 4, + }, + operation: Override, + }, + filename: "", + line: 4, + column: 4, + end_line: 4, + end_column: 4, + }, + ], + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 4, + end_column: 4, +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__config_recovery_6.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__config_recovery_6.snap new file mode 100644 index 000000000..25154a89d --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__config_recovery_6.snap @@ -0,0 +1,117 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(\"{a = 1 b = 2}\")" +--- +Node { + node: Config( + ConfigExpr { + items: [ + Node { + node: ConfigEntry { + key: Some( + Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 2, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 2, + }, + ), + value: Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 1, + ), + }, + ), + filename: "", + line: 1, + column: 5, + end_line: 1, + end_column: 6, + }, + operation: Override, + }, + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 6, + }, + Node { + node: ConfigEntry { + key: Some( + Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "b", + filename: "", + line: 1, + column: 7, + end_line: 1, + end_column: 8, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 7, + end_line: 1, + end_column: 8, + }, + ), + value: Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 2, + ), + }, + ), + filename: "", + line: 1, + column: 11, + end_line: 1, + end_column: 12, + }, + operation: Override, + }, + filename: "", + line: 1, + column: 7, + end_line: 1, + end_column: 12, + }, + ], + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 13, +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__config_recovery_7.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__config_recovery_7.snap new file mode 100644 index 000000000..7d94e620c --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__config_recovery_7.snap @@ -0,0 +1,149 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(\"{a = 1,, b = 2}\")" +--- +Node { + node: Config( + ConfigExpr { + items: [ + Node { + node: ConfigEntry { + key: Some( + Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 2, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 2, + }, + ), + value: Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 1, + ), + }, + ), + filename: "", + line: 1, + column: 5, + end_line: 1, + end_column: 6, + }, + operation: Override, + }, + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 6, + }, + Node { + node: ConfigEntry { + key: Some( + Node { + node: Missing( + MissingExpr, + ), + filename: "", + line: 1, + column: 7, + end_line: 1, + end_column: 8, + }, + ), + value: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "b", + filename: "", + line: 1, + column: 9, + end_line: 1, + end_column: 10, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 9, + end_line: 1, + end_column: 10, + }, + operation: Override, + }, + filename: "", + line: 1, + column: 7, + end_line: 1, + end_column: 10, + }, + Node { + node: ConfigEntry { + key: Some( + Node { + node: Missing( + MissingExpr, + ), + filename: "", + line: 1, + column: 11, + end_line: 1, + end_column: 12, + }, + ), + value: Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 2, + ), + }, + ), + filename: "", + line: 1, + column: 13, + end_line: 1, + end_column: 14, + }, + operation: Override, + }, + filename: "", + line: 1, + column: 11, + end_line: 1, + end_column: 14, + }, + ], + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 15, +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__config_recovery_8.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__config_recovery_8.snap new file mode 100644 index 000000000..c3412c7c5 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__config_recovery_8.snap @@ -0,0 +1,129 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(\"{a = 1 ~ b = 2}\")" +--- +Node { + node: Config( + ConfigExpr { + items: [ + Node { + node: ConfigEntry { + key: Some( + Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 2, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 2, + }, + ), + value: Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 1, + ), + }, + ), + filename: "", + line: 1, + column: 5, + end_line: 1, + end_column: 6, + }, + operation: Override, + }, + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 6, + }, + Node { + node: ConfigEntry { + key: Some( + Node { + node: Unary( + UnaryExpr { + op: Invert, + operand: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "b", + filename: "", + line: 1, + column: 9, + end_line: 1, + end_column: 10, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 9, + end_line: 1, + end_column: 10, + }, + }, + ), + filename: "", + line: 1, + column: 7, + end_line: 1, + end_column: 10, + }, + ), + value: Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 2, + ), + }, + ), + filename: "", + line: 1, + column: 13, + end_line: 1, + end_column: 14, + }, + operation: Override, + }, + filename: "", + line: 1, + column: 7, + end_line: 1, + end_column: 14, + }, + ], + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 15, +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__config_recovery_9.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__config_recovery_9.snap new file mode 100644 index 000000000..eadd2be4e --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__config_recovery_9.snap @@ -0,0 +1,119 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(\"{*a, **b}\")" +--- +Node { + node: Config( + ConfigExpr { + items: [ + Node { + node: ConfigEntry { + key: Some( + Node { + node: Binary( + BinaryExpr { + left: Node { + node: Missing( + MissingExpr, + ), + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 2, + }, + op: Mul, + right: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 2, + end_line: 1, + end_column: 3, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 2, + end_line: 1, + end_column: 3, + }, + }, + ), + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 3, + }, + ), + value: Node { + node: Binary( + BinaryExpr { + left: Node { + node: Missing( + MissingExpr, + ), + filename: "", + line: 1, + column: 5, + end_line: 1, + end_column: 7, + }, + op: Pow, + right: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "b", + filename: "", + line: 1, + column: 7, + end_line: 1, + end_column: 8, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 7, + end_line: 1, + end_column: 8, + }, + }, + ), + filename: "", + line: 1, + column: 5, + end_line: 1, + end_column: 8, + }, + operation: Override, + }, + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 8, + }, + ], + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 9, +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__fn_ty_annotation_recovery_0.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__fn_ty_annotation_recovery_0.snap new file mode 100644 index 000000000..289fe85e0 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__fn_ty_annotation_recovery_0.snap @@ -0,0 +1,79 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\"a:(\"#)" +--- +Module { + filename: "", + doc: None, + body: [ + Node { + node: Assign( + AssignStmt { + targets: [ + Node { + node: Target { + name: Node { + node: "a", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + paths: [], + pkgpath: "", + }, + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + value: Node { + node: Missing( + MissingExpr, + ), + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 3, + }, + ty: Some( + Node { + node: Function( + FunctionType { + params_ty: Some( + [ + Node { + node: Any, + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 3, + }, + ], + ), + ret_ty: None, + }, + ), + filename: "", + line: 1, + column: 2, + end_line: 1, + end_column: 3, + }, + ), + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__fn_ty_annotation_recovery_1.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__fn_ty_annotation_recovery_1.snap new file mode 100644 index 000000000..9890a5d4b --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__fn_ty_annotation_recovery_1.snap @@ -0,0 +1,102 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\"a:(i\"#)" +--- +Module { + filename: "", + doc: None, + body: [ + Node { + node: Assign( + AssignStmt { + targets: [ + Node { + node: Target { + name: Node { + node: "a", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + paths: [], + pkgpath: "", + }, + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + value: Node { + node: Missing( + MissingExpr, + ), + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 4, + }, + ty: Some( + Node { + node: Function( + FunctionType { + params_ty: Some( + [ + Node { + node: Named( + Identifier { + names: [ + Node { + node: "i", + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 4, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 4, + }, + Node { + node: Any, + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 4, + }, + ], + ), + ret_ty: None, + }, + ), + filename: "", + line: 1, + column: 2, + end_line: 1, + end_column: 4, + }, + ), + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__fn_ty_annotation_recovery_10.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__fn_ty_annotation_recovery_10.snap new file mode 100644 index 000000000..21f1b312e --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__fn_ty_annotation_recovery_10.snap @@ -0,0 +1,102 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\"a:({\"#)" +--- +Module { + filename: "", + doc: None, + body: [ + Node { + node: Assign( + AssignStmt { + targets: [ + Node { + node: Target { + name: Node { + node: "a", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + paths: [], + pkgpath: "", + }, + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + value: Node { + node: Missing( + MissingExpr, + ), + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 4, + }, + ty: Some( + Node { + node: Function( + FunctionType { + params_ty: Some( + [ + Node { + node: Dict( + DictType { + key_type: Some( + Node { + node: Any, + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 4, + }, + ), + value_type: Some( + Node { + node: Any, + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 4, + }, + ), + }, + ), + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 4, + }, + ], + ), + ret_ty: None, + }, + ), + filename: "", + line: 1, + column: 2, + end_line: 1, + end_column: 4, + }, + ), + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__fn_ty_annotation_recovery_11.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__fn_ty_annotation_recovery_11.snap new file mode 100644 index 000000000..646edab6d --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__fn_ty_annotation_recovery_11.snap @@ -0,0 +1,117 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\"a:({i\"#)" +--- +Module { + filename: "", + doc: None, + body: [ + Node { + node: Assign( + AssignStmt { + targets: [ + Node { + node: Target { + name: Node { + node: "a", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + paths: [], + pkgpath: "", + }, + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + value: Node { + node: Missing( + MissingExpr, + ), + filename: "", + line: 1, + column: 5, + end_line: 1, + end_column: 5, + }, + ty: Some( + Node { + node: Function( + FunctionType { + params_ty: Some( + [ + Node { + node: Dict( + DictType { + key_type: Some( + Node { + node: Named( + Identifier { + names: [ + Node { + node: "i", + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 5, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 5, + }, + ), + value_type: Some( + Node { + node: Any, + filename: "", + line: 1, + column: 5, + end_line: 1, + end_column: 5, + }, + ), + }, + ), + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 5, + }, + ], + ), + ret_ty: None, + }, + ), + filename: "", + line: 1, + column: 2, + end_line: 1, + end_column: 5, + }, + ), + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__fn_ty_annotation_recovery_12.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__fn_ty_annotation_recovery_12.snap new file mode 100644 index 000000000..3ae60363b --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__fn_ty_annotation_recovery_12.snap @@ -0,0 +1,117 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\"a:({i:\"#)" +--- +Module { + filename: "", + doc: None, + body: [ + Node { + node: Assign( + AssignStmt { + targets: [ + Node { + node: Target { + name: Node { + node: "a", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + paths: [], + pkgpath: "", + }, + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + value: Node { + node: Missing( + MissingExpr, + ), + filename: "", + line: 1, + column: 6, + end_line: 1, + end_column: 6, + }, + ty: Some( + Node { + node: Function( + FunctionType { + params_ty: Some( + [ + Node { + node: Dict( + DictType { + key_type: Some( + Node { + node: Named( + Identifier { + names: [ + Node { + node: "i", + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 5, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 5, + }, + ), + value_type: Some( + Node { + node: Any, + filename: "", + line: 1, + column: 6, + end_line: 1, + end_column: 6, + }, + ), + }, + ), + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 6, + }, + ], + ), + ret_ty: None, + }, + ), + filename: "", + line: 1, + column: 2, + end_line: 1, + end_column: 6, + }, + ), + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__fn_ty_annotation_recovery_13.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__fn_ty_annotation_recovery_13.snap new file mode 100644 index 000000000..60c402b80 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__fn_ty_annotation_recovery_13.snap @@ -0,0 +1,132 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\"a:({i:i\"#)" +--- +Module { + filename: "", + doc: None, + body: [ + Node { + node: Assign( + AssignStmt { + targets: [ + Node { + node: Target { + name: Node { + node: "a", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + paths: [], + pkgpath: "", + }, + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + value: Node { + node: Missing( + MissingExpr, + ), + filename: "", + line: 1, + column: 7, + end_line: 1, + end_column: 7, + }, + ty: Some( + Node { + node: Function( + FunctionType { + params_ty: Some( + [ + Node { + node: Dict( + DictType { + key_type: Some( + Node { + node: Named( + Identifier { + names: [ + Node { + node: "i", + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 5, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 5, + }, + ), + value_type: Some( + Node { + node: Named( + Identifier { + names: [ + Node { + node: "i", + filename: "", + line: 1, + column: 6, + end_line: 1, + end_column: 7, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 6, + end_line: 1, + end_column: 7, + }, + ), + }, + ), + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 7, + }, + ], + ), + ret_ty: None, + }, + ), + filename: "", + line: 1, + column: 2, + end_line: 1, + end_column: 7, + }, + ), + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__fn_ty_annotation_recovery_14.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__fn_ty_annotation_recovery_14.snap new file mode 100644 index 000000000..a1900d5b1 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__fn_ty_annotation_recovery_14.snap @@ -0,0 +1,119 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\"a:({i:int\"#)" +--- +Module { + filename: "", + doc: None, + body: [ + Node { + node: Assign( + AssignStmt { + targets: [ + Node { + node: Target { + name: Node { + node: "a", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + paths: [], + pkgpath: "", + }, + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + value: Node { + node: Missing( + MissingExpr, + ), + filename: "", + line: 1, + column: 9, + end_line: 1, + end_column: 9, + }, + ty: Some( + Node { + node: Function( + FunctionType { + params_ty: Some( + [ + Node { + node: Dict( + DictType { + key_type: Some( + Node { + node: Named( + Identifier { + names: [ + Node { + node: "i", + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 5, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 5, + }, + ), + value_type: Some( + Node { + node: Basic( + Int, + ), + filename: "", + line: 1, + column: 6, + end_line: 1, + end_column: 9, + }, + ), + }, + ), + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 9, + }, + ], + ), + ret_ty: None, + }, + ), + filename: "", + line: 1, + column: 2, + end_line: 1, + end_column: 9, + }, + ), + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__fn_ty_annotation_recovery_15.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__fn_ty_annotation_recovery_15.snap new file mode 100644 index 000000000..f259cc0be --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__fn_ty_annotation_recovery_15.snap @@ -0,0 +1,127 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\"a:({i:int]\"#)" +--- +Module { + filename: "", + doc: None, + body: [ + Node { + node: Assign( + AssignStmt { + targets: [ + Node { + node: Target { + name: Node { + node: "a", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + paths: [], + pkgpath: "", + }, + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + value: Node { + node: Missing( + MissingExpr, + ), + filename: "", + line: 1, + column: 10, + end_line: 1, + end_column: 10, + }, + ty: Some( + Node { + node: Function( + FunctionType { + params_ty: Some( + [ + Node { + node: Dict( + DictType { + key_type: Some( + Node { + node: Named( + Identifier { + names: [ + Node { + node: "i", + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 5, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 5, + }, + ), + value_type: Some( + Node { + node: Basic( + Int, + ), + filename: "", + line: 1, + column: 6, + end_line: 1, + end_column: 9, + }, + ), + }, + ), + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 10, + }, + Node { + node: Any, + filename: "", + line: 1, + column: 10, + end_line: 1, + end_column: 10, + }, + ], + ), + ret_ty: None, + }, + ), + filename: "", + line: 1, + column: 2, + end_line: 1, + end_column: 10, + }, + ), + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__fn_ty_annotation_recovery_16.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__fn_ty_annotation_recovery_16.snap new file mode 100644 index 000000000..d4f7e0baf --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__fn_ty_annotation_recovery_16.snap @@ -0,0 +1,114 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\"a:({str:int]\"#)" +--- +Module { + filename: "", + doc: None, + body: [ + Node { + node: Assign( + AssignStmt { + targets: [ + Node { + node: Target { + name: Node { + node: "a", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + paths: [], + pkgpath: "", + }, + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + value: Node { + node: Missing( + MissingExpr, + ), + filename: "", + line: 1, + column: 12, + end_line: 1, + end_column: 12, + }, + ty: Some( + Node { + node: Function( + FunctionType { + params_ty: Some( + [ + Node { + node: Dict( + DictType { + key_type: Some( + Node { + node: Basic( + Str, + ), + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 7, + }, + ), + value_type: Some( + Node { + node: Basic( + Int, + ), + filename: "", + line: 1, + column: 8, + end_line: 1, + end_column: 11, + }, + ), + }, + ), + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 12, + }, + Node { + node: Any, + filename: "", + line: 1, + column: 12, + end_line: 1, + end_column: 12, + }, + ], + ), + ret_ty: None, + }, + ), + filename: "", + line: 1, + column: 2, + end_line: 1, + end_column: 12, + }, + ), + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__fn_ty_annotation_recovery_17.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__fn_ty_annotation_recovery_17.snap new file mode 100644 index 000000000..3f62171eb --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__fn_ty_annotation_recovery_17.snap @@ -0,0 +1,114 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\"a:({str:int}\"#)" +--- +Module { + filename: "", + doc: None, + body: [ + Node { + node: Assign( + AssignStmt { + targets: [ + Node { + node: Target { + name: Node { + node: "a", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + paths: [], + pkgpath: "", + }, + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + value: Node { + node: Missing( + MissingExpr, + ), + filename: "", + line: 1, + column: 12, + end_line: 1, + end_column: 12, + }, + ty: Some( + Node { + node: Function( + FunctionType { + params_ty: Some( + [ + Node { + node: Dict( + DictType { + key_type: Some( + Node { + node: Basic( + Str, + ), + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 7, + }, + ), + value_type: Some( + Node { + node: Basic( + Int, + ), + filename: "", + line: 1, + column: 8, + end_line: 1, + end_column: 11, + }, + ), + }, + ), + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 12, + }, + Node { + node: Any, + filename: "", + line: 1, + column: 12, + end_line: 1, + end_column: 12, + }, + ], + ), + ret_ty: None, + }, + ), + filename: "", + line: 1, + column: 2, + end_line: 1, + end_column: 12, + }, + ), + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__fn_ty_annotation_recovery_18.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__fn_ty_annotation_recovery_18.snap new file mode 100644 index 000000000..55d4ac98e --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__fn_ty_annotation_recovery_18.snap @@ -0,0 +1,122 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\"a:({str:int} ->\"#)" +--- +Module { + filename: "", + doc: None, + body: [ + Node { + node: Assign( + AssignStmt { + targets: [ + Node { + node: Target { + name: Node { + node: "a", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + paths: [], + pkgpath: "", + }, + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + value: Node { + node: Missing( + MissingExpr, + ), + filename: "", + line: 1, + column: 15, + end_line: 1, + end_column: 15, + }, + ty: Some( + Node { + node: Function( + FunctionType { + params_ty: Some( + [ + Node { + node: Dict( + DictType { + key_type: Some( + Node { + node: Basic( + Str, + ), + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 7, + }, + ), + value_type: Some( + Node { + node: Basic( + Int, + ), + filename: "", + line: 1, + column: 8, + end_line: 1, + end_column: 11, + }, + ), + }, + ), + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 12, + }, + Node { + node: Any, + filename: "", + line: 1, + column: 13, + end_line: 1, + end_column: 15, + }, + Node { + node: Any, + filename: "", + line: 1, + column: 15, + end_line: 1, + end_column: 15, + }, + ], + ), + ret_ty: None, + }, + ), + filename: "", + line: 1, + column: 2, + end_line: 1, + end_column: 15, + }, + ), + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__fn_ty_annotation_recovery_19.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__fn_ty_annotation_recovery_19.snap new file mode 100644 index 000000000..c12213574 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__fn_ty_annotation_recovery_19.snap @@ -0,0 +1,130 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\"a:({str:int}) -> i\"#)" +--- +Module { + filename: "", + doc: None, + body: [ + Node { + node: Assign( + AssignStmt { + targets: [ + Node { + node: Target { + name: Node { + node: "a", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + paths: [], + pkgpath: "", + }, + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + value: Node { + node: Missing( + MissingExpr, + ), + filename: "", + line: 1, + column: 18, + end_line: 1, + end_column: 18, + }, + ty: Some( + Node { + node: Function( + FunctionType { + params_ty: Some( + [ + Node { + node: Dict( + DictType { + key_type: Some( + Node { + node: Basic( + Str, + ), + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 7, + }, + ), + value_type: Some( + Node { + node: Basic( + Int, + ), + filename: "", + line: 1, + column: 8, + end_line: 1, + end_column: 11, + }, + ), + }, + ), + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 12, + }, + ], + ), + ret_ty: Some( + Node { + node: Named( + Identifier { + names: [ + Node { + node: "i", + filename: "", + line: 1, + column: 17, + end_line: 1, + end_column: 18, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 17, + end_line: 1, + end_column: 18, + }, + ), + }, + ), + filename: "", + line: 1, + column: 2, + end_line: 1, + end_column: 18, + }, + ), + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__fn_ty_annotation_recovery_2.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__fn_ty_annotation_recovery_2.snap new file mode 100644 index 000000000..0623e3c2f --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__fn_ty_annotation_recovery_2.snap @@ -0,0 +1,89 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\"a:(int\"#)" +--- +Module { + filename: "", + doc: None, + body: [ + Node { + node: Assign( + AssignStmt { + targets: [ + Node { + node: Target { + name: Node { + node: "a", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + paths: [], + pkgpath: "", + }, + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + value: Node { + node: Missing( + MissingExpr, + ), + filename: "", + line: 1, + column: 6, + end_line: 1, + end_column: 6, + }, + ty: Some( + Node { + node: Function( + FunctionType { + params_ty: Some( + [ + Node { + node: Basic( + Int, + ), + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 6, + }, + Node { + node: Any, + filename: "", + line: 1, + column: 6, + end_line: 1, + end_column: 6, + }, + ], + ), + ret_ty: None, + }, + ), + filename: "", + line: 1, + column: 2, + end_line: 1, + end_column: 6, + }, + ), + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__fn_ty_annotation_recovery_20.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__fn_ty_annotation_recovery_20.snap new file mode 100644 index 000000000..4a9bd1289 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__fn_ty_annotation_recovery_20.snap @@ -0,0 +1,128 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\"a:(str|int) -> i\"#)" +--- +Module { + filename: "", + doc: None, + body: [ + Node { + node: Assign( + AssignStmt { + targets: [ + Node { + node: Target { + name: Node { + node: "a", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + paths: [], + pkgpath: "", + }, + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + value: Node { + node: Missing( + MissingExpr, + ), + filename: "", + line: 1, + column: 16, + end_line: 1, + end_column: 16, + }, + ty: Some( + Node { + node: Function( + FunctionType { + params_ty: Some( + [ + Node { + node: Union( + UnionType { + type_elements: [ + Node { + node: Basic( + Str, + ), + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 6, + }, + Node { + node: Basic( + Int, + ), + filename: "", + line: 1, + column: 7, + end_line: 1, + end_column: 10, + }, + ], + }, + ), + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 10, + }, + ], + ), + ret_ty: Some( + Node { + node: Named( + Identifier { + names: [ + Node { + node: "i", + filename: "", + line: 1, + column: 15, + end_line: 1, + end_column: 16, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 15, + end_line: 1, + end_column: 16, + }, + ), + }, + ), + filename: "", + line: 1, + column: 2, + end_line: 1, + end_column: 16, + }, + ), + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__fn_ty_annotation_recovery_21.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__fn_ty_annotation_recovery_21.snap new file mode 100644 index 000000000..9443f5d0c --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__fn_ty_annotation_recovery_21.snap @@ -0,0 +1,138 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\"a:(str|int, int) -> i\"#)" +--- +Module { + filename: "", + doc: None, + body: [ + Node { + node: Assign( + AssignStmt { + targets: [ + Node { + node: Target { + name: Node { + node: "a", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + paths: [], + pkgpath: "", + }, + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + value: Node { + node: Missing( + MissingExpr, + ), + filename: "", + line: 1, + column: 21, + end_line: 1, + end_column: 21, + }, + ty: Some( + Node { + node: Function( + FunctionType { + params_ty: Some( + [ + Node { + node: Union( + UnionType { + type_elements: [ + Node { + node: Basic( + Str, + ), + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 6, + }, + Node { + node: Basic( + Int, + ), + filename: "", + line: 1, + column: 7, + end_line: 1, + end_column: 10, + }, + ], + }, + ), + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 10, + }, + Node { + node: Basic( + Int, + ), + filename: "", + line: 1, + column: 12, + end_line: 1, + end_column: 15, + }, + ], + ), + ret_ty: Some( + Node { + node: Named( + Identifier { + names: [ + Node { + node: "i", + filename: "", + line: 1, + column: 20, + end_line: 1, + end_column: 21, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 20, + end_line: 1, + end_column: 21, + }, + ), + }, + ), + filename: "", + line: 1, + column: 2, + end_line: 1, + end_column: 21, + }, + ), + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__fn_ty_annotation_recovery_22.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__fn_ty_annotation_recovery_22.snap new file mode 100644 index 000000000..4e0f08952 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__fn_ty_annotation_recovery_22.snap @@ -0,0 +1,135 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\"a:(str|int, int|\"#)" +--- +Module { + filename: "", + doc: None, + body: [ + Node { + node: Assign( + AssignStmt { + targets: [ + Node { + node: Target { + name: Node { + node: "a", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + paths: [], + pkgpath: "", + }, + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + value: Node { + node: Missing( + MissingExpr, + ), + filename: "", + line: 1, + column: 16, + end_line: 1, + end_column: 16, + }, + ty: Some( + Node { + node: Function( + FunctionType { + params_ty: Some( + [ + Node { + node: Union( + UnionType { + type_elements: [ + Node { + node: Basic( + Str, + ), + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 6, + }, + Node { + node: Basic( + Int, + ), + filename: "", + line: 1, + column: 7, + end_line: 1, + end_column: 10, + }, + ], + }, + ), + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 10, + }, + Node { + node: Union( + UnionType { + type_elements: [ + Node { + node: Basic( + Int, + ), + filename: "", + line: 1, + column: 12, + end_line: 1, + end_column: 15, + }, + Node { + node: Any, + filename: "", + line: 1, + column: 16, + end_line: 1, + end_column: 16, + }, + ], + }, + ), + filename: "", + line: 1, + column: 12, + end_line: 1, + end_column: 16, + }, + ], + ), + ret_ty: None, + }, + ), + filename: "", + line: 1, + column: 2, + end_line: 1, + end_column: 16, + }, + ), + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__fn_ty_annotation_recovery_23.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__fn_ty_annotation_recovery_23.snap new file mode 100644 index 000000000..a04ea182f --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__fn_ty_annotation_recovery_23.snap @@ -0,0 +1,151 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\"a:(str|int, int|) ->\"#)" +--- +Module { + filename: "", + doc: None, + body: [ + Node { + node: Assign( + AssignStmt { + targets: [ + Node { + node: Target { + name: Node { + node: "a", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + paths: [], + pkgpath: "", + }, + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + value: Node { + node: Missing( + MissingExpr, + ), + filename: "", + line: 1, + column: 20, + end_line: 1, + end_column: 20, + }, + ty: Some( + Node { + node: Function( + FunctionType { + params_ty: Some( + [ + Node { + node: Union( + UnionType { + type_elements: [ + Node { + node: Basic( + Str, + ), + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 6, + }, + Node { + node: Basic( + Int, + ), + filename: "", + line: 1, + column: 7, + end_line: 1, + end_column: 10, + }, + ], + }, + ), + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 10, + }, + Node { + node: Union( + UnionType { + type_elements: [ + Node { + node: Basic( + Int, + ), + filename: "", + line: 1, + column: 12, + end_line: 1, + end_column: 15, + }, + Node { + node: Any, + filename: "", + line: 1, + column: 16, + end_line: 1, + end_column: 17, + }, + ], + }, + ), + filename: "", + line: 1, + column: 12, + end_line: 1, + end_column: 17, + }, + Node { + node: Any, + filename: "", + line: 1, + column: 18, + end_line: 1, + end_column: 20, + }, + Node { + node: Any, + filename: "", + line: 1, + column: 20, + end_line: 1, + end_column: 20, + }, + ], + ), + ret_ty: None, + }, + ), + filename: "", + line: 1, + column: 2, + end_line: 1, + end_column: 20, + }, + ), + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__fn_ty_annotation_recovery_3.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__fn_ty_annotation_recovery_3.snap new file mode 100644 index 000000000..4abeae807 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__fn_ty_annotation_recovery_3.snap @@ -0,0 +1,78 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\"a:i)\"#)" +--- +Module { + filename: "", + doc: None, + body: [ + Node { + node: Assign( + AssignStmt { + targets: [ + Node { + node: Target { + name: Node { + node: "a", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + paths: [], + pkgpath: "", + }, + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + value: Node { + node: Missing( + MissingExpr, + ), + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 4, + }, + ty: Some( + Node { + node: Named( + Identifier { + names: [ + Node { + node: "i", + filename: "", + line: 1, + column: 2, + end_line: 1, + end_column: 3, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 2, + end_line: 1, + end_column: 3, + }, + ), + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__fn_ty_annotation_recovery_4.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__fn_ty_annotation_recovery_4.snap new file mode 100644 index 000000000..d14d5c78c --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__fn_ty_annotation_recovery_4.snap @@ -0,0 +1,107 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\"a:([i\"#)" +--- +Module { + filename: "", + doc: None, + body: [ + Node { + node: Assign( + AssignStmt { + targets: [ + Node { + node: Target { + name: Node { + node: "a", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + paths: [], + pkgpath: "", + }, + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + value: Node { + node: Missing( + MissingExpr, + ), + filename: "", + line: 1, + column: 5, + end_line: 1, + end_column: 5, + }, + ty: Some( + Node { + node: Function( + FunctionType { + params_ty: Some( + [ + Node { + node: List( + ListType { + inner_type: Some( + Node { + node: Named( + Identifier { + names: [ + Node { + node: "i", + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 5, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 5, + }, + ), + }, + ), + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 5, + }, + ], + ), + ret_ty: None, + }, + ), + filename: "", + line: 1, + column: 2, + end_line: 1, + end_column: 5, + }, + ), + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__fn_ty_annotation_recovery_5.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__fn_ty_annotation_recovery_5.snap new file mode 100644 index 000000000..ce5eb974f --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__fn_ty_annotation_recovery_5.snap @@ -0,0 +1,115 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\"a:([i:\"#)" +--- +Module { + filename: "", + doc: None, + body: [ + Node { + node: Assign( + AssignStmt { + targets: [ + Node { + node: Target { + name: Node { + node: "a", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + paths: [], + pkgpath: "", + }, + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + value: Node { + node: Missing( + MissingExpr, + ), + filename: "", + line: 1, + column: 6, + end_line: 1, + end_column: 6, + }, + ty: Some( + Node { + node: Function( + FunctionType { + params_ty: Some( + [ + Node { + node: List( + ListType { + inner_type: Some( + Node { + node: Named( + Identifier { + names: [ + Node { + node: "i", + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 5, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 5, + }, + ), + }, + ), + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 6, + }, + Node { + node: Any, + filename: "", + line: 1, + column: 6, + end_line: 1, + end_column: 6, + }, + ], + ), + ret_ty: None, + }, + ), + filename: "", + line: 1, + column: 2, + end_line: 1, + end_column: 6, + }, + ), + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__fn_ty_annotation_recovery_6.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__fn_ty_annotation_recovery_6.snap new file mode 100644 index 000000000..8cfed4657 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__fn_ty_annotation_recovery_6.snap @@ -0,0 +1,115 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\"a:([i]\"#)" +--- +Module { + filename: "", + doc: None, + body: [ + Node { + node: Assign( + AssignStmt { + targets: [ + Node { + node: Target { + name: Node { + node: "a", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + paths: [], + pkgpath: "", + }, + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + value: Node { + node: Missing( + MissingExpr, + ), + filename: "", + line: 1, + column: 6, + end_line: 1, + end_column: 6, + }, + ty: Some( + Node { + node: Function( + FunctionType { + params_ty: Some( + [ + Node { + node: List( + ListType { + inner_type: Some( + Node { + node: Named( + Identifier { + names: [ + Node { + node: "i", + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 5, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 5, + }, + ), + }, + ), + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 6, + }, + Node { + node: Any, + filename: "", + line: 1, + column: 6, + end_line: 1, + end_column: 6, + }, + ], + ), + ret_ty: None, + }, + ), + filename: "", + line: 1, + column: 2, + end_line: 1, + end_column: 6, + }, + ), + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__fn_ty_annotation_recovery_7.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__fn_ty_annotation_recovery_7.snap new file mode 100644 index 000000000..fe51302d7 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__fn_ty_annotation_recovery_7.snap @@ -0,0 +1,102 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\"a:([int]\"#)" +--- +Module { + filename: "", + doc: None, + body: [ + Node { + node: Assign( + AssignStmt { + targets: [ + Node { + node: Target { + name: Node { + node: "a", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + paths: [], + pkgpath: "", + }, + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + value: Node { + node: Missing( + MissingExpr, + ), + filename: "", + line: 1, + column: 8, + end_line: 1, + end_column: 8, + }, + ty: Some( + Node { + node: Function( + FunctionType { + params_ty: Some( + [ + Node { + node: List( + ListType { + inner_type: Some( + Node { + node: Basic( + Int, + ), + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 7, + }, + ), + }, + ), + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 8, + }, + Node { + node: Any, + filename: "", + line: 1, + column: 8, + end_line: 1, + end_column: 8, + }, + ], + ), + ret_ty: None, + }, + ), + filename: "", + line: 1, + column: 2, + end_line: 1, + end_column: 8, + }, + ), + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__fn_ty_annotation_recovery_8.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__fn_ty_annotation_recovery_8.snap new file mode 100644 index 000000000..b2a05a64a --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__fn_ty_annotation_recovery_8.snap @@ -0,0 +1,94 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\"a:([int\"#)" +--- +Module { + filename: "", + doc: None, + body: [ + Node { + node: Assign( + AssignStmt { + targets: [ + Node { + node: Target { + name: Node { + node: "a", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + paths: [], + pkgpath: "", + }, + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + value: Node { + node: Missing( + MissingExpr, + ), + filename: "", + line: 1, + column: 7, + end_line: 1, + end_column: 7, + }, + ty: Some( + Node { + node: Function( + FunctionType { + params_ty: Some( + [ + Node { + node: List( + ListType { + inner_type: Some( + Node { + node: Basic( + Int, + ), + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 7, + }, + ), + }, + ), + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 7, + }, + ], + ), + ret_ty: None, + }, + ), + filename: "", + line: 1, + column: 2, + end_line: 1, + end_column: 7, + }, + ), + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__fn_ty_annotation_recovery_9.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__fn_ty_annotation_recovery_9.snap new file mode 100644 index 000000000..f4d31fa19 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__fn_ty_annotation_recovery_9.snap @@ -0,0 +1,102 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\"a:({}\"#)" +--- +Module { + filename: "", + doc: None, + body: [ + Node { + node: Assign( + AssignStmt { + targets: [ + Node { + node: Target { + name: Node { + node: "a", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + paths: [], + pkgpath: "", + }, + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + value: Node { + node: Missing( + MissingExpr, + ), + filename: "", + line: 1, + column: 5, + end_line: 1, + end_column: 5, + }, + ty: Some( + Node { + node: Function( + FunctionType { + params_ty: Some( + [ + Node { + node: Dict( + DictType { + key_type: Some( + Node { + node: Any, + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 5, + }, + ), + value_type: Some( + Node { + node: Any, + filename: "", + line: 1, + column: 5, + end_line: 1, + end_column: 5, + }, + ), + }, + ), + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 5, + }, + ], + ), + ret_ty: None, + }, + ), + filename: "", + line: 1, + column: 2, + end_line: 1, + end_column: 5, + }, + ), + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__if_recovery_0.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__if_recovery_0.snap new file mode 100644 index 000000000..528d37531 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__if_recovery_0.snap @@ -0,0 +1,51 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(r#\"1 if\"#)" +--- +Node { + node: If( + IfExpr { + body: Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 1, + ), + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + cond: Node { + node: Missing( + MissingExpr, + ), + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 4, + }, + orelse: Node { + node: Missing( + MissingExpr, + ), + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 4, + }, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 4, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__if_recovery_1.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__if_recovery_1.snap new file mode 100644 index 000000000..528d37531 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__if_recovery_1.snap @@ -0,0 +1,51 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(r#\"1 if\"#)" +--- +Node { + node: If( + IfExpr { + body: Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 1, + ), + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + cond: Node { + node: Missing( + MissingExpr, + ), + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 4, + }, + orelse: Node { + node: Missing( + MissingExpr, + ), + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 4, + }, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 4, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__if_recovery_2.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__if_recovery_2.snap new file mode 100644 index 000000000..49690bc2f --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__if_recovery_2.snap @@ -0,0 +1,53 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(r#\"1 if True\"#)" +--- +Node { + node: If( + IfExpr { + body: Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 1, + ), + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + cond: Node { + node: NameConstantLit( + NameConstantLit { + value: True, + }, + ), + filename: "", + line: 1, + column: 5, + end_line: 1, + end_column: 9, + }, + orelse: Node { + node: Missing( + MissingExpr, + ), + filename: "", + line: 1, + column: 9, + end_line: 1, + end_column: 9, + }, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 9, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__if_recovery_3.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__if_recovery_3.snap new file mode 100644 index 000000000..db389259e --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__if_recovery_3.snap @@ -0,0 +1,53 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(r#\"1 if True else\"#)" +--- +Node { + node: If( + IfExpr { + body: Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 1, + ), + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + cond: Node { + node: NameConstantLit( + NameConstantLit { + value: True, + }, + ), + filename: "", + line: 1, + column: 5, + end_line: 1, + end_column: 9, + }, + orelse: Node { + node: Missing( + MissingExpr, + ), + filename: "", + line: 1, + column: 14, + end_line: 1, + end_column: 14, + }, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 14, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__if_recovery_4.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__if_recovery_4.snap new file mode 100644 index 000000000..ccc877766 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__if_recovery_4.snap @@ -0,0 +1,28 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(r#\"if True else\"#)" +--- +Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "if", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 2, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 2, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__if_stmt_recovery_0.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__if_stmt_recovery_0.snap new file mode 100644 index 000000000..2fa082d3d --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__if_stmt_recovery_0.snap @@ -0,0 +1,65 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\"if True a = 1\"#)" +--- +Module { + filename: "", + doc: None, + body: [ + Node { + node: If( + IfStmt { + body: [ + Node { + node: Assign( + AssignStmt { + targets: [], + value: Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 1, + ), + }, + ), + filename: "", + line: 1, + column: 12, + end_line: 1, + end_column: 13, + }, + ty: None, + }, + ), + filename: "", + line: 1, + column: 10, + end_line: 1, + end_column: 13, + }, + ], + cond: Node { + node: NameConstantLit( + NameConstantLit { + value: True, + }, + ), + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 7, + }, + orelse: [], + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 13, + }, + ], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__if_stmt_recovery_1.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__if_stmt_recovery_1.snap new file mode 100644 index 000000000..b39f4363f --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__if_stmt_recovery_1.snap @@ -0,0 +1,114 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\"if True: a = 1 else if b = 2\"#)" +--- +Module { + filename: "", + doc: None, + body: [ + Node { + node: If( + IfStmt { + body: [ + Node { + node: Assign( + AssignStmt { + targets: [ + Node { + node: Target { + name: Node { + node: "a", + filename: "", + line: 1, + column: 9, + end_line: 1, + end_column: 10, + }, + paths: [], + pkgpath: "", + }, + filename: "", + line: 1, + column: 9, + end_line: 1, + end_column: 10, + }, + ], + value: Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 1, + ), + }, + ), + filename: "", + line: 1, + column: 13, + end_line: 1, + end_column: 14, + }, + ty: None, + }, + ), + filename: "", + line: 1, + column: 9, + end_line: 1, + end_column: 14, + }, + ], + cond: Node { + node: NameConstantLit( + NameConstantLit { + value: True, + }, + ), + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 7, + }, + orelse: [ + Node { + node: Assign( + AssignStmt { + targets: [], + value: Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 2, + ), + }, + ), + filename: "", + line: 1, + column: 27, + end_line: 1, + end_column: 28, + }, + ty: None, + }, + ), + filename: "", + line: 1, + column: 25, + end_line: 1, + end_column: 28, + }, + ], + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 28, + }, + ], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__if_stmt_recovery_2.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__if_stmt_recovery_2.snap new file mode 100644 index 000000000..1396ed4fd --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__if_stmt_recovery_2.snap @@ -0,0 +1,83 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\"if : a = 1\"#)" +--- +Module { + filename: "", + doc: None, + body: [ + Node { + node: If( + IfStmt { + body: [ + Node { + node: Assign( + AssignStmt { + targets: [ + Node { + node: Target { + name: Node { + node: "a", + filename: "", + line: 1, + column: 5, + end_line: 1, + end_column: 6, + }, + paths: [], + pkgpath: "", + }, + filename: "", + line: 1, + column: 5, + end_line: 1, + end_column: 6, + }, + ], + value: Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 1, + ), + }, + ), + filename: "", + line: 1, + column: 9, + end_line: 1, + end_column: 10, + }, + ty: None, + }, + ), + filename: "", + line: 1, + column: 5, + end_line: 1, + end_column: 10, + }, + ], + cond: Node { + node: Missing( + MissingExpr, + ), + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 4, + }, + orelse: [], + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 10, + }, + ], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__if_stmt_recovery_3.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__if_stmt_recovery_3.snap new file mode 100644 index 000000000..e225daff1 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__if_stmt_recovery_3.snap @@ -0,0 +1,114 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\"if True: a = 1 else b = 2\"#)" +--- +Module { + filename: "", + doc: None, + body: [ + Node { + node: If( + IfStmt { + body: [ + Node { + node: Assign( + AssignStmt { + targets: [ + Node { + node: Target { + name: Node { + node: "a", + filename: "", + line: 1, + column: 9, + end_line: 1, + end_column: 10, + }, + paths: [], + pkgpath: "", + }, + filename: "", + line: 1, + column: 9, + end_line: 1, + end_column: 10, + }, + ], + value: Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 1, + ), + }, + ), + filename: "", + line: 1, + column: 13, + end_line: 1, + end_column: 14, + }, + ty: None, + }, + ), + filename: "", + line: 1, + column: 9, + end_line: 1, + end_column: 14, + }, + ], + cond: Node { + node: NameConstantLit( + NameConstantLit { + value: True, + }, + ), + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 7, + }, + orelse: [ + Node { + node: Assign( + AssignStmt { + targets: [], + value: Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 2, + ), + }, + ), + filename: "", + line: 1, + column: 24, + end_line: 1, + end_column: 25, + }, + ty: None, + }, + ), + filename: "", + line: 1, + column: 22, + end_line: 1, + end_column: 25, + }, + ], + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 25, + }, + ], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__if_stmt_recovery_4.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__if_stmt_recovery_4.snap new file mode 100644 index 000000000..4b5684a72 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__if_stmt_recovery_4.snap @@ -0,0 +1,109 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\"if True: else: b = 2\"#)" +--- +Module { + filename: "", + doc: None, + body: [ + Node { + node: If( + IfStmt { + body: [ + Node { + node: Assign( + AssignStmt { + targets: [ + Node { + node: Target { + name: Node { + node: "else", + filename: "", + line: 1, + column: 9, + end_line: 1, + end_column: 13, + }, + paths: [], + pkgpath: "", + }, + filename: "", + line: 1, + column: 9, + end_line: 1, + end_column: 13, + }, + ], + value: Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 2, + ), + }, + ), + filename: "", + line: 1, + column: 19, + end_line: 1, + end_column: 20, + }, + ty: Some( + Node { + node: Named( + Identifier { + names: [ + Node { + node: "b", + filename: "", + line: 1, + column: 15, + end_line: 1, + end_column: 16, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 15, + end_line: 1, + end_column: 16, + }, + ), + }, + ), + filename: "", + line: 1, + column: 9, + end_line: 1, + end_column: 20, + }, + ], + cond: Node { + node: NameConstantLit( + NameConstantLit { + value: True, + }, + ), + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 7, + }, + orelse: [], + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 20, + }, + ], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__if_stmt_recovery_5.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__if_stmt_recovery_5.snap new file mode 100644 index 000000000..206bf3133 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__if_stmt_recovery_5.snap @@ -0,0 +1,58 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\"if\"#)" +--- +Module { + filename: "", + doc: None, + body: [ + Node { + node: If( + IfStmt { + body: [ + Node { + node: Expr( + ExprStmt { + exprs: [ + Node { + node: Missing( + MissingExpr, + ), + filename: "", + line: 1, + column: 2, + end_line: 1, + end_column: 2, + }, + ], + }, + ), + filename: "", + line: 1, + column: 2, + end_line: 1, + end_column: 2, + }, + ], + cond: Node { + node: Missing( + MissingExpr, + ), + filename: "", + line: 1, + column: 2, + end_line: 1, + end_column: 2, + }, + orelse: [], + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 2, + }, + ], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__if_stmt_recovery_6.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__if_stmt_recovery_6.snap new file mode 100644 index 000000000..90c99d7cb --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__if_stmt_recovery_6.snap @@ -0,0 +1,71 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\"if else\"#)" +--- +Module { + filename: "", + doc: None, + body: [ + Node { + node: If( + IfStmt { + body: [ + Node { + node: Expr( + ExprStmt { + exprs: [ + Node { + node: Missing( + MissingExpr, + ), + filename: "", + line: 1, + column: 7, + end_line: 1, + end_column: 7, + }, + ], + }, + ), + filename: "", + line: 1, + column: 7, + end_line: 1, + end_column: 7, + }, + ], + cond: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "else", + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 7, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 7, + }, + orelse: [], + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 7, + }, + ], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__if_stmt_recovery_7.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__if_stmt_recovery_7.snap new file mode 100644 index 000000000..3435267c8 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__if_stmt_recovery_7.snap @@ -0,0 +1,36 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\"if True:\"#)" +--- +Module { + filename: "", + doc: None, + body: [ + Node { + node: If( + IfStmt { + body: [], + cond: Node { + node: NameConstantLit( + NameConstantLit { + value: True, + }, + ), + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 7, + }, + orelse: [], + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 8, + }, + ], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__if_stmt_recovery_8.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__if_stmt_recovery_8.snap new file mode 100644 index 000000000..64253742f --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__if_stmt_recovery_8.snap @@ -0,0 +1,138 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\"if True: a = 1\nelse if False: b = 1\"#)" +--- +Module { + filename: "", + doc: None, + body: [ + Node { + node: If( + IfStmt { + body: [ + Node { + node: Assign( + AssignStmt { + targets: [ + Node { + node: Target { + name: Node { + node: "a", + filename: "", + line: 1, + column: 9, + end_line: 1, + end_column: 10, + }, + paths: [], + pkgpath: "", + }, + filename: "", + line: 1, + column: 9, + end_line: 1, + end_column: 10, + }, + ], + value: Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 1, + ), + }, + ), + filename: "", + line: 1, + column: 13, + end_line: 1, + end_column: 14, + }, + ty: None, + }, + ), + filename: "", + line: 1, + column: 9, + end_line: 1, + end_column: 14, + }, + ], + cond: Node { + node: NameConstantLit( + NameConstantLit { + value: True, + }, + ), + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 7, + }, + orelse: [ + Node { + node: Assign( + AssignStmt { + targets: [], + value: Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 1, + ), + }, + ), + filename: "", + line: 2, + column: 19, + end_line: 2, + end_column: 20, + }, + ty: Some( + Node { + node: Named( + Identifier { + names: [ + Node { + node: "b", + filename: "", + line: 2, + column: 15, + end_line: 2, + end_column: 16, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 2, + column: 15, + end_line: 2, + end_column: 16, + }, + ), + }, + ), + filename: "", + line: 2, + column: 13, + end_line: 2, + end_column: 20, + }, + ], + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 2, + end_column: 20, + }, + ], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__if_stmt_recovery_9.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__if_stmt_recovery_9.snap new file mode 100644 index 000000000..045b89545 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__if_stmt_recovery_9.snap @@ -0,0 +1,138 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\"if True: a = 1\nelse False: b = 1\"#)" +--- +Module { + filename: "", + doc: None, + body: [ + Node { + node: If( + IfStmt { + body: [ + Node { + node: Assign( + AssignStmt { + targets: [ + Node { + node: Target { + name: Node { + node: "a", + filename: "", + line: 1, + column: 9, + end_line: 1, + end_column: 10, + }, + paths: [], + pkgpath: "", + }, + filename: "", + line: 1, + column: 9, + end_line: 1, + end_column: 10, + }, + ], + value: Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 1, + ), + }, + ), + filename: "", + line: 1, + column: 13, + end_line: 1, + end_column: 14, + }, + ty: None, + }, + ), + filename: "", + line: 1, + column: 9, + end_line: 1, + end_column: 14, + }, + ], + cond: Node { + node: NameConstantLit( + NameConstantLit { + value: True, + }, + ), + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 7, + }, + orelse: [ + Node { + node: Assign( + AssignStmt { + targets: [], + value: Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 1, + ), + }, + ), + filename: "", + line: 2, + column: 16, + end_line: 2, + end_column: 17, + }, + ty: Some( + Node { + node: Named( + Identifier { + names: [ + Node { + node: "b", + filename: "", + line: 2, + column: 12, + end_line: 2, + end_column: 13, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 2, + column: 12, + end_line: 2, + end_column: 13, + }, + ), + }, + ), + filename: "", + line: 2, + column: 10, + end_line: 2, + end_column: 17, + }, + ], + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 2, + end_column: 17, + }, + ], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__import_recovery_0.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__import_recovery_0.snap new file mode 100644 index 000000000..5b34ce992 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__import_recovery_0.snap @@ -0,0 +1,34 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\"import json as j.a\"#)" +--- +Module { + filename: "", + doc: None, + body: [ + Node { + node: Import( + ImportStmt { + path: Node { + node: "json", + filename: "", + line: 1, + column: 7, + end_line: 1, + end_column: 11, + }, + rawpath: "json", + name: "json", + asname: None, + pkg_name: "", + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 18, + }, + ], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__import_stmt_recovery_0.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__import_stmt_recovery_0.snap new file mode 100644 index 000000000..cb7f681b5 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__import_stmt_recovery_0.snap @@ -0,0 +1,34 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\"import\"#)" +--- +Module { + filename: "", + doc: None, + body: [ + Node { + node: Import( + ImportStmt { + path: Node { + node: "", + filename: "", + line: 1, + column: 6, + end_line: 1, + end_column: 6, + }, + rawpath: "", + name: "", + asname: None, + pkg_name: "", + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 6, + }, + ], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__import_stmt_recovery_1.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__import_stmt_recovery_1.snap new file mode 100644 index 000000000..a69bc5079 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__import_stmt_recovery_1.snap @@ -0,0 +1,61 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\"import 'pkg_path'\"#)" +--- +Module { + filename: "", + doc: None, + body: [ + Node { + node: Import( + ImportStmt { + path: Node { + node: "", + filename: "", + line: 1, + column: 7, + end_line: 1, + end_column: 6, + }, + rawpath: "", + name: "", + asname: None, + pkg_name: "", + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 6, + }, + Node { + node: Expr( + ExprStmt { + exprs: [ + Node { + node: StringLit( + StringLit { + is_long_string: false, + raw_value: "'pkg_path'", + value: "pkg_path", + }, + ), + filename: "", + line: 1, + column: 7, + end_line: 1, + end_column: 17, + }, + ], + }, + ), + filename: "", + line: 1, + column: 7, + end_line: 1, + end_column: 17, + }, + ], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__import_stmt_recovery_2.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__import_stmt_recovery_2.snap new file mode 100644 index 000000000..6b6986b97 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__import_stmt_recovery_2.snap @@ -0,0 +1,34 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\"import pkg_path.\"#)" +--- +Module { + filename: "", + doc: None, + body: [ + Node { + node: Import( + ImportStmt { + path: Node { + node: "pkg_path.", + filename: "", + line: 1, + column: 7, + end_line: 1, + end_column: 16, + }, + rawpath: "pkg_path.", + name: "", + asname: None, + pkg_name: "", + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 16, + }, + ], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__import_stmt_recovery_3.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__import_stmt_recovery_3.snap new file mode 100644 index 000000000..94512d4be --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__import_stmt_recovery_3.snap @@ -0,0 +1,76 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\"import pkg_path[0]\"#)" +--- +Module { + filename: "", + doc: None, + body: [ + Node { + node: Import( + ImportStmt { + path: Node { + node: "pkg_path", + filename: "", + line: 1, + column: 7, + end_line: 1, + end_column: 15, + }, + rawpath: "pkg_path", + name: "pkg_path", + asname: None, + pkg_name: "", + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 15, + }, + Node { + node: Expr( + ExprStmt { + exprs: [ + Node { + node: List( + ListExpr { + elts: [ + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 0, + ), + }, + ), + filename: "", + line: 1, + column: 16, + end_line: 1, + end_column: 17, + }, + ], + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 15, + end_line: 1, + end_column: 18, + }, + ], + }, + ), + filename: "", + line: 1, + column: 15, + end_line: 1, + end_column: 18, + }, + ], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__import_stmt_recovery_4.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__import_stmt_recovery_4.snap new file mode 100644 index 000000000..33fe9d47f --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__import_stmt_recovery_4.snap @@ -0,0 +1,34 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\"import .pkg_path.\"#)" +--- +Module { + filename: "", + doc: None, + body: [ + Node { + node: Import( + ImportStmt { + path: Node { + node: ".pkg_path.", + filename: "", + line: 1, + column: 7, + end_line: 1, + end_column: 17, + }, + rawpath: ".pkg_path.", + name: "", + asname: None, + pkg_name: "", + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 17, + }, + ], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__import_stmt_recovery_5.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__import_stmt_recovery_5.snap new file mode 100644 index 000000000..da09f18cc --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__import_stmt_recovery_5.snap @@ -0,0 +1,43 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\"import pkg_path as \"#)" +--- +Module { + filename: "", + doc: None, + body: [ + Node { + node: Import( + ImportStmt { + path: Node { + node: "pkg_path", + filename: "", + line: 1, + column: 7, + end_line: 1, + end_column: 15, + }, + rawpath: "pkg_path", + name: "", + asname: Some( + Node { + node: "", + filename: "", + line: 1, + column: 19, + end_line: 1, + end_column: 19, + }, + ), + pkg_name: "", + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 18, + }, + ], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__import_stmt_recovery_6.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__import_stmt_recovery_6.snap new file mode 100644 index 000000000..21ec43038 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__import_stmt_recovery_6.snap @@ -0,0 +1,70 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\"import pkg_path as 'data'\"#)" +--- +Module { + filename: "", + doc: None, + body: [ + Node { + node: Import( + ImportStmt { + path: Node { + node: "pkg_path", + filename: "", + line: 1, + column: 7, + end_line: 1, + end_column: 15, + }, + rawpath: "pkg_path", + name: "", + asname: Some( + Node { + node: "", + filename: "", + line: 1, + column: 19, + end_line: 1, + end_column: 19, + }, + ), + pkg_name: "", + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 18, + }, + Node { + node: Expr( + ExprStmt { + exprs: [ + Node { + node: StringLit( + StringLit { + is_long_string: false, + raw_value: "'data'", + value: "data", + }, + ), + filename: "", + line: 1, + column: 19, + end_line: 1, + end_column: 25, + }, + ], + }, + ), + filename: "", + line: 1, + column: 19, + end_line: 1, + end_column: 25, + }, + ], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__joined_string_recovery_0.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__joined_string_recovery_0.snap new file mode 100644 index 000000000..d65592149 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__joined_string_recovery_0.snap @@ -0,0 +1,44 @@ +--- +source: parser/src/tests/error_recovery.rs +assertion_line: 151 +expression: "crate::tests::parsing_expr_string(r#\"'${}'\"#)" +--- +Node { + node: JoinedString( + JoinedString { + is_long_string: false, + values: [ + Node { + node: FormattedValue( + FormattedValue { + is_long_string: false, + value: Node { + node: Missing( + MissingExpr, + ), + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 3, + }, + format_spec: None, + }, + ), + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 3, + }, + ], + raw_value: "'${}'", + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 5, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__joined_string_recovery_1.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__joined_string_recovery_1.snap new file mode 100644 index 000000000..9e1a8683e --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__joined_string_recovery_1.snap @@ -0,0 +1,78 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(r#\"'${a +}'\"#)" +--- +Node { + node: JoinedString( + JoinedString { + is_long_string: false, + values: [ + Node { + node: FormattedValue( + FormattedValue { + is_long_string: false, + value: Node { + node: Binary( + BinaryExpr { + left: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 4, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 4, + }, + op: Add, + right: Node { + node: Missing( + MissingExpr, + ), + filename: "", + line: 1, + column: 6, + end_line: 1, + end_column: 6, + }, + }, + ), + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 6, + }, + format_spec: None, + }, + ), + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 6, + }, + ], + raw_value: "'${a +}'", + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 8, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__joined_string_recovery_10.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__joined_string_recovery_10.snap new file mode 100644 index 000000000..3aca424a4 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__joined_string_recovery_10.snap @@ -0,0 +1,83 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(r#\"\"\"\"\n ${CC}\n\"\"\"\"#)" +--- +Node { + node: JoinedString( + JoinedString { + is_long_string: true, + values: [ + Node { + node: StringLit( + StringLit { + is_long_string: false, + raw_value: "\n ", + value: "\n ", + }, + ), + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 1, + }, + Node { + node: FormattedValue( + FormattedValue { + is_long_string: false, + value: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "CC", + filename: "", + line: 2, + column: 4, + end_line: 2, + end_column: 6, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 2, + column: 4, + end_line: 2, + end_column: 6, + }, + format_spec: None, + }, + ), + filename: "", + line: 2, + column: 4, + end_line: 2, + end_column: 6, + }, + Node { + node: StringLit( + StringLit { + is_long_string: false, + raw_value: "\n", + value: "\n", + }, + ), + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 1, + }, + ], + raw_value: "\"\"\"\n ${CC}\n\"\"\"", + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 3, + end_column: 3, +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__joined_string_recovery_11.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__joined_string_recovery_11.snap new file mode 100644 index 000000000..8343e4ae8 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__joined_string_recovery_11.snap @@ -0,0 +1,143 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(r#\"'\\\"false\\\" ${item.kind}: ${item.metadata.name}'\"#)" +--- +Node { + node: JoinedString( + JoinedString { + is_long_string: false, + values: [ + Node { + node: StringLit( + StringLit { + is_long_string: false, + raw_value: "\\\"false\\\" ", + value: "\"false\" ", + }, + ), + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 1, + }, + Node { + node: FormattedValue( + FormattedValue { + is_long_string: false, + value: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "item", + filename: "", + line: 1, + column: 13, + end_line: 1, + end_column: 17, + }, + Node { + node: "kind", + filename: "", + line: 1, + column: 18, + end_line: 1, + end_column: 22, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 13, + end_line: 1, + end_column: 22, + }, + format_spec: None, + }, + ), + filename: "", + line: 1, + column: 13, + end_line: 1, + end_column: 22, + }, + Node { + node: StringLit( + StringLit { + is_long_string: false, + raw_value: ": ", + value: ": ", + }, + ), + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 1, + }, + Node { + node: FormattedValue( + FormattedValue { + is_long_string: false, + value: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "item", + filename: "", + line: 1, + column: 27, + end_line: 1, + end_column: 31, + }, + Node { + node: "metadata", + filename: "", + line: 1, + column: 32, + end_line: 1, + end_column: 40, + }, + Node { + node: "name", + filename: "", + line: 1, + column: 41, + end_line: 1, + end_column: 45, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 27, + end_line: 1, + end_column: 45, + }, + format_spec: None, + }, + ), + filename: "", + line: 1, + column: 27, + end_line: 1, + end_column: 45, + }, + ], + raw_value: "'\\\"false\\\" ${item.kind}: ${item.metadata.name}'", + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 47, +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__joined_string_recovery_12.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__joined_string_recovery_12.snap new file mode 100644 index 000000000..235648fa5 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__joined_string_recovery_12.snap @@ -0,0 +1,207 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(r#\"'\\\"false\\\" ${item.kind}: ${item.metadata.name} \\\"true\\\" ${item} '\"#)" +--- +Node { + node: JoinedString( + JoinedString { + is_long_string: false, + values: [ + Node { + node: StringLit( + StringLit { + is_long_string: false, + raw_value: "\\\"false\\\" ", + value: "\"false\" ", + }, + ), + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 1, + }, + Node { + node: FormattedValue( + FormattedValue { + is_long_string: false, + value: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "item", + filename: "", + line: 1, + column: 13, + end_line: 1, + end_column: 17, + }, + Node { + node: "kind", + filename: "", + line: 1, + column: 18, + end_line: 1, + end_column: 22, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 13, + end_line: 1, + end_column: 22, + }, + format_spec: None, + }, + ), + filename: "", + line: 1, + column: 13, + end_line: 1, + end_column: 22, + }, + Node { + node: StringLit( + StringLit { + is_long_string: false, + raw_value: ": ", + value: ": ", + }, + ), + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 1, + }, + Node { + node: FormattedValue( + FormattedValue { + is_long_string: false, + value: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "item", + filename: "", + line: 1, + column: 27, + end_line: 1, + end_column: 31, + }, + Node { + node: "metadata", + filename: "", + line: 1, + column: 32, + end_line: 1, + end_column: 40, + }, + Node { + node: "name", + filename: "", + line: 1, + column: 41, + end_line: 1, + end_column: 45, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 27, + end_line: 1, + end_column: 45, + }, + format_spec: None, + }, + ), + filename: "", + line: 1, + column: 27, + end_line: 1, + end_column: 45, + }, + Node { + node: StringLit( + StringLit { + is_long_string: false, + raw_value: " \\\"true\\\" ", + value: " \"true\" ", + }, + ), + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 1, + }, + Node { + node: FormattedValue( + FormattedValue { + is_long_string: false, + value: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "item", + filename: "", + line: 1, + column: 58, + end_line: 1, + end_column: 62, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 58, + end_line: 1, + end_column: 62, + }, + format_spec: None, + }, + ), + filename: "", + line: 1, + column: 58, + end_line: 1, + end_column: 62, + }, + Node { + node: StringLit( + StringLit { + is_long_string: false, + raw_value: " ", + value: " ", + }, + ), + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 1, + }, + ], + raw_value: "'\\\"false\\\" ${item.kind}: ${item.metadata.name} \\\"true\\\" ${item} '", + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 65, +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__joined_string_recovery_13.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__joined_string_recovery_13.snap new file mode 100644 index 000000000..cb1becd17 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__joined_string_recovery_13.snap @@ -0,0 +1,127 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(r#\"'\\\"false\\\" \\${item.kind}: a${item.metadata.name} \\\"true\\\" \\${item} '\"#)" +--- +Node { + node: JoinedString( + JoinedString { + is_long_string: false, + values: [ + Node { + node: StringLit( + StringLit { + is_long_string: false, + raw_value: "\\\"false\\\" \\${item.kind}", + value: "\"false\" ${item.kind}", + }, + ), + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 1, + }, + Node { + node: StringLit( + StringLit { + is_long_string: false, + raw_value: ": a", + value: ": a", + }, + ), + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 1, + }, + Node { + node: FormattedValue( + FormattedValue { + is_long_string: false, + value: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "item", + filename: "", + line: 1, + column: 29, + end_line: 1, + end_column: 33, + }, + Node { + node: "metadata", + filename: "", + line: 1, + column: 34, + end_line: 1, + end_column: 42, + }, + Node { + node: "name", + filename: "", + line: 1, + column: 43, + end_line: 1, + end_column: 47, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 29, + end_line: 1, + end_column: 47, + }, + format_spec: None, + }, + ), + filename: "", + line: 1, + column: 29, + end_line: 1, + end_column: 47, + }, + Node { + node: StringLit( + StringLit { + is_long_string: false, + raw_value: " \\\"true\\\" \\${item}", + value: " \"true\" ${item}", + }, + ), + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 1, + }, + Node { + node: StringLit( + StringLit { + is_long_string: false, + raw_value: " ", + value: " ", + }, + ), + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 1, + }, + ], + raw_value: "'\\\"false\\\" \\${item.kind}: a${item.metadata.name} \\\"true\\\" \\${item} '", + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 68, +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__joined_string_recovery_2.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__joined_string_recovery_2.snap new file mode 100644 index 000000000..7bdb64047 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__joined_string_recovery_2.snap @@ -0,0 +1,89 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(r#\"'${(a +}'\"#)" +--- +Node { + node: JoinedString( + JoinedString { + is_long_string: false, + values: [ + Node { + node: FormattedValue( + FormattedValue { + is_long_string: false, + value: Node { + node: Paren( + ParenExpr { + expr: Node { + node: Binary( + BinaryExpr { + left: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 5, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 5, + }, + op: Add, + right: Node { + node: Missing( + MissingExpr, + ), + filename: "", + line: 1, + column: 7, + end_line: 1, + end_column: 7, + }, + }, + ), + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 7, + }, + }, + ), + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 7, + }, + format_spec: None, + }, + ), + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 7, + }, + ], + raw_value: "'${(a +}'", + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 9, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__joined_string_recovery_3.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__joined_string_recovery_3.snap new file mode 100644 index 000000000..fb84a2866 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__joined_string_recovery_3.snap @@ -0,0 +1,35 @@ +--- +source: parser/src/tests/error_recovery.rs +assertion_line: 129 +expression: "crate::tests::parsing_expr_string(r#\"'${a'\"#)" +--- +Node { + node: JoinedString( + JoinedString { + is_long_string: false, + values: [ + Node { + node: StringLit( + StringLit { + is_long_string: false, + raw_value: "${a", + value: "${a", + }, + ), + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 1, + }, + ], + raw_value: "'${a'", + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 5, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__joined_string_recovery_5.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__joined_string_recovery_5.snap new file mode 100644 index 000000000..c974dedbf --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__joined_string_recovery_5.snap @@ -0,0 +1,83 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(r#\"'${a + 1 = }'\"#)" +--- +Node { + node: JoinedString( + JoinedString { + is_long_string: false, + values: [ + Node { + node: FormattedValue( + FormattedValue { + is_long_string: false, + value: Node { + node: Binary( + BinaryExpr { + left: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 4, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 4, + }, + op: Add, + right: Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 1, + ), + }, + ), + filename: "", + line: 1, + column: 7, + end_line: 1, + end_column: 8, + }, + }, + ), + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 8, + }, + format_spec: None, + }, + ), + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 11, + }, + ], + raw_value: "'${a + 1 = }'", + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 13, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__joined_string_recovery_6.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__joined_string_recovery_6.snap new file mode 100644 index 000000000..466ccce34 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__joined_string_recovery_6.snap @@ -0,0 +1,56 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(r#\"'${a: json}'\"#)" +--- +Node { + node: JoinedString( + JoinedString { + is_long_string: false, + values: [ + Node { + node: FormattedValue( + FormattedValue { + is_long_string: false, + value: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 4, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 4, + }, + format_spec: None, + }, + ), + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 10, + }, + ], + raw_value: "'${a: json}'", + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 12, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__joined_string_recovery_7.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__joined_string_recovery_7.snap new file mode 100644 index 000000000..60205c006 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__joined_string_recovery_7.snap @@ -0,0 +1,71 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(r#\"'\\n${a: #json}'\"#)" +--- +Node { + node: JoinedString( + JoinedString { + is_long_string: false, + values: [ + Node { + node: StringLit( + StringLit { + is_long_string: false, + raw_value: "\\n", + value: "\n", + }, + ), + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 1, + }, + Node { + node: FormattedValue( + FormattedValue { + is_long_string: false, + value: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 5, + end_line: 1, + end_column: 6, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 5, + end_line: 1, + end_column: 6, + }, + format_spec: Some( + "#json", + ), + }, + ), + filename: "", + line: 1, + column: 5, + end_line: 1, + end_column: 13, + }, + ], + raw_value: "'\\n${a: #json}'", + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 15, +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__joined_string_recovery_8.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__joined_string_recovery_8.snap new file mode 100644 index 000000000..c679d1782 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__joined_string_recovery_8.snap @@ -0,0 +1,85 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(r#\"'a\\nb${a: #json}\\n'\"#)" +--- +Node { + node: JoinedString( + JoinedString { + is_long_string: false, + values: [ + Node { + node: StringLit( + StringLit { + is_long_string: false, + raw_value: "a\\nb", + value: "a\nb", + }, + ), + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 1, + }, + Node { + node: FormattedValue( + FormattedValue { + is_long_string: false, + value: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 7, + end_line: 1, + end_column: 8, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 7, + end_line: 1, + end_column: 8, + }, + format_spec: Some( + "#json", + ), + }, + ), + filename: "", + line: 1, + column: 7, + end_line: 1, + end_column: 15, + }, + Node { + node: StringLit( + StringLit { + is_long_string: false, + raw_value: "\\n", + value: "\n", + }, + ), + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 1, + }, + ], + raw_value: "'a\\nb${a: #json}\\n'", + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 19, +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__joined_string_recovery_9.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__joined_string_recovery_9.snap new file mode 100644 index 000000000..d93090334 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__joined_string_recovery_9.snap @@ -0,0 +1,83 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(r#\"'''\\\n ${CC}\n'''\"#)" +--- +Node { + node: JoinedString( + JoinedString { + is_long_string: true, + values: [ + Node { + node: StringLit( + StringLit { + is_long_string: false, + raw_value: "\\\n ", + value: " ", + }, + ), + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 1, + }, + Node { + node: FormattedValue( + FormattedValue { + is_long_string: false, + value: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "CC", + filename: "", + line: 2, + column: 4, + end_line: 2, + end_column: 6, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 2, + column: 4, + end_line: 2, + end_column: 6, + }, + format_spec: None, + }, + ), + filename: "", + line: 2, + column: 4, + end_line: 2, + end_column: 6, + }, + Node { + node: StringLit( + StringLit { + is_long_string: false, + raw_value: "\n", + value: "\n", + }, + ), + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 1, + }, + ], + raw_value: "'''\\\n ${CC}\n'''", + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 3, + end_column: 3, +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__lambda_recovery_0.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__lambda_recovery_0.snap new file mode 100644 index 000000000..72e7e6216 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__lambda_recovery_0.snap @@ -0,0 +1,33 @@ +--- +source: parser/src/tests/error_recovery.rs +assertion_line: 161 +expression: "crate::tests::parsing_expr_string(r#\"lambda\"#)" +--- +Node { + node: Lambda( + LambdaExpr { + args: Some( + Node { + node: Arguments { + args: [], + defaults: [], + ty_list: [], + }, + filename: "", + line: 1, + column: 6, + end_line: 1, + end_column: 6, + }, + ), + body: [], + return_ty: None, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 6, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__lambda_recovery_1.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__lambda_recovery_1.snap new file mode 100644 index 000000000..01fc43f47 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__lambda_recovery_1.snap @@ -0,0 +1,20 @@ +--- +source: parser/src/tests/error_recovery.rs +assertion_line: 162 +expression: "crate::tests::parsing_expr_string(r#\"lambda {\"#)" +--- +Node { + node: Lambda( + LambdaExpr { + args: None, + body: [], + return_ty: None, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 8, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__lambda_recovery_2.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__lambda_recovery_2.snap new file mode 100644 index 000000000..d591a8a1b --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__lambda_recovery_2.snap @@ -0,0 +1,20 @@ +--- +source: parser/src/tests/error_recovery.rs +assertion_line: 163 +expression: "crate::tests::parsing_expr_string(r#\"lambda {}\"#)" +--- +Node { + node: Lambda( + LambdaExpr { + args: None, + body: [], + return_ty: None, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 9, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__lambda_recovery_3.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__lambda_recovery_3.snap new file mode 100644 index 000000000..1f7ff3bbb --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__lambda_recovery_3.snap @@ -0,0 +1,92 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(r#\"{lambda}\"#)" +--- +Node { + node: Config( + ConfigExpr { + items: [ + Node { + node: ConfigEntry { + key: Some( + Node { + node: Lambda( + LambdaExpr { + args: Some( + Node { + node: Arguments { + args: [ + Node { + node: Identifier { + names: [ + Node { + node: "", + filename: "", + line: 1, + column: 7, + end_line: 1, + end_column: 7, + }, + ], + pkgpath: "", + ctx: Load, + }, + filename: "", + line: 1, + column: 7, + end_line: 1, + end_column: 7, + }, + ], + defaults: [ + None, + ], + ty_list: [ + None, + ], + }, + filename: "", + line: 1, + column: 7, + end_line: 1, + end_column: 8, + }, + ), + body: [], + return_ty: None, + }, + ), + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 8, + }, + ), + value: Node { + node: Missing( + MissingExpr, + ), + filename: "", + line: 1, + column: 8, + end_line: 1, + end_column: 8, + }, + operation: Override, + }, + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 8, + }, + ], + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 8, +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__lambda_recovery_4.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__lambda_recovery_4.snap new file mode 100644 index 000000000..52080bd08 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__lambda_recovery_4.snap @@ -0,0 +1,53 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(r#\"{lambda{}\"#)" +--- +Node { + node: Config( + ConfigExpr { + items: [ + Node { + node: ConfigEntry { + key: Some( + Node { + node: Lambda( + LambdaExpr { + args: None, + body: [], + return_ty: None, + }, + ), + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 9, + }, + ), + value: Node { + node: Missing( + MissingExpr, + ), + filename: "", + line: 1, + column: 9, + end_line: 1, + end_column: 9, + }, + operation: Override, + }, + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 9, + }, + ], + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 9, +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__lambda_recovery_5.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__lambda_recovery_5.snap new file mode 100644 index 000000000..9c6d1b83e --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__lambda_recovery_5.snap @@ -0,0 +1,92 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(r#\"{lambda a{}\"#)" +--- +Node { + node: Config( + ConfigExpr { + items: [ + Node { + node: ConfigEntry { + key: Some( + Node { + node: Lambda( + LambdaExpr { + args: Some( + Node { + node: Arguments { + args: [ + Node { + node: Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 8, + end_line: 1, + end_column: 9, + }, + ], + pkgpath: "", + ctx: Load, + }, + filename: "", + line: 1, + column: 8, + end_line: 1, + end_column: 9, + }, + ], + defaults: [ + None, + ], + ty_list: [ + None, + ], + }, + filename: "", + line: 1, + column: 8, + end_line: 1, + end_column: 9, + }, + ), + body: [], + return_ty: None, + }, + ), + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 11, + }, + ), + value: Node { + node: Missing( + MissingExpr, + ), + filename: "", + line: 1, + column: 11, + end_line: 1, + end_column: 11, + }, + operation: Override, + }, + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 11, + }, + ], + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 11, +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__line_continue_recovery_0.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__line_continue_recovery_0.snap new file mode 100644 index 000000000..c5759da50 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__line_continue_recovery_0.snap @@ -0,0 +1,21 @@ +--- +source: parser/src/tests/error_recovery.rs +assertion_line: 15 +expression: "crate::tests::parsing_expr_string(\"0x\\\\2\\n12\")" +--- +Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 0, + ), + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 2, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__line_continue_recovery_1.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__line_continue_recovery_1.snap new file mode 100644 index 000000000..6a188859e --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__line_continue_recovery_1.snap @@ -0,0 +1,20 @@ +--- +source: parser/src/tests/error_recovery.rs +assertion_line: 24 +expression: "crate::tests::parsing_expr_string(\"'abc\\\\ \\ndef\")" +--- +Node { + node: StringLit( + StringLit { + is_long_string: false, + raw_value: "'abc\\ ", + value: "abc\\ ", + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 6, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__line_continue_recovery_2.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__line_continue_recovery_2.snap new file mode 100644 index 000000000..90d980588 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__line_continue_recovery_2.snap @@ -0,0 +1,45 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(r#\"'a' + \\\n'b'\n\"#)" +--- +Node { + node: Binary( + BinaryExpr { + left: Node { + node: StringLit( + StringLit { + is_long_string: false, + raw_value: "'a'", + value: "a", + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 3, + }, + op: Add, + right: Node { + node: StringLit( + StringLit { + is_long_string: false, + raw_value: "'b'", + value: "b", + }, + ), + filename: "", + line: 2, + column: 0, + end_line: 2, + end_column: 3, + }, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 2, + end_column: 3, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__line_continue_recovery_3.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__line_continue_recovery_3.snap new file mode 100644 index 000000000..560f44c0f --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__line_continue_recovery_3.snap @@ -0,0 +1,46 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(r#\"'a' + \\1\n'b'\n\"#)" +--- +Node { + node: Binary( + BinaryExpr { + left: Node { + node: StringLit( + StringLit { + is_long_string: false, + raw_value: "'a'", + value: "a", + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 3, + }, + op: Add, + right: Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 1, + ), + }, + ), + filename: "", + line: 1, + column: 7, + end_line: 1, + end_column: 8, + }, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 8, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__list_recovery_0.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__list_recovery_0.snap new file mode 100644 index 000000000..b9f33adb6 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__list_recovery_0.snap @@ -0,0 +1,19 @@ +--- +source: parser/src/tests/error_recovery.rs +assertion_line: 5 +expression: "crate::tests::parsing_expr_string(\"[\")" +--- +Node { + node: List( + ListExpr { + elts: [], + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__list_recovery_1.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__list_recovery_1.snap new file mode 100644 index 000000000..620783e9c --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__list_recovery_1.snap @@ -0,0 +1,35 @@ +--- +source: parser/src/tests/error_recovery.rs +assertion_line: 6 +expression: "crate::tests::parsing_expr_string(\"[0\")" +--- +Node { + node: List( + ListExpr { + elts: [ + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 0, + ), + }, + ), + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 2, + }, + ], + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 2, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__list_recovery_10.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__list_recovery_10.snap new file mode 100644 index 000000000..47087d246 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__list_recovery_10.snap @@ -0,0 +1,99 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(\"[**a, *b\")" +--- +Node { + node: List( + ListExpr { + elts: [ + Node { + node: Binary( + BinaryExpr { + left: Node { + node: Missing( + MissingExpr, + ), + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 3, + }, + op: Pow, + right: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 4, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 4, + }, + }, + ), + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 4, + }, + Node { + node: Starred( + StarredExpr { + value: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "b", + filename: "", + line: 1, + column: 7, + end_line: 1, + end_column: 8, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 7, + end_line: 1, + end_column: 8, + }, + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 6, + end_line: 1, + end_column: 8, + }, + ], + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 8, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__list_recovery_11.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__list_recovery_11.snap new file mode 100644 index 000000000..637195280 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__list_recovery_11.snap @@ -0,0 +1,91 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(\"[if True: a, b]\")" +--- +Node { + node: List( + ListExpr { + elts: [ + Node { + node: ListIfItem( + ListIfItemExpr { + if_cond: Node { + node: NameConstantLit( + NameConstantLit { + value: True, + }, + ), + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 8, + }, + exprs: [ + Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 10, + end_line: 1, + end_column: 11, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 10, + end_line: 1, + end_column: 11, + }, + ], + orelse: None, + }, + ), + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 11, + }, + Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "b", + filename: "", + line: 1, + column: 13, + end_line: 1, + end_column: 14, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 13, + end_line: 1, + end_column: 14, + }, + ], + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 15, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__list_recovery_12.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__list_recovery_12.snap new file mode 100644 index 000000000..452d8d6fa --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__list_recovery_12.snap @@ -0,0 +1,113 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(\"[if True: **a, b]\")" +--- +Node { + node: List( + ListExpr { + elts: [ + Node { + node: ListIfItem( + ListIfItemExpr { + if_cond: Node { + node: NameConstantLit( + NameConstantLit { + value: True, + }, + ), + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 8, + }, + exprs: [ + Node { + node: Binary( + BinaryExpr { + left: Node { + node: Missing( + MissingExpr, + ), + filename: "", + line: 1, + column: 10, + end_line: 1, + end_column: 12, + }, + op: Pow, + right: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 12, + end_line: 1, + end_column: 13, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 12, + end_line: 1, + end_column: 13, + }, + }, + ), + filename: "", + line: 1, + column: 10, + end_line: 1, + end_column: 13, + }, + ], + orelse: None, + }, + ), + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 13, + }, + Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "b", + filename: "", + line: 1, + column: 15, + end_line: 1, + end_column: 16, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 15, + end_line: 1, + end_column: 16, + }, + ], + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 17, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__list_recovery_13.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__list_recovery_13.snap new file mode 100644 index 000000000..90b45fd76 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__list_recovery_13.snap @@ -0,0 +1,90 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(r#\"[\n if True:\n b = []\n]\n\"#)" +--- +Node { + node: List( + ListExpr { + elts: [ + Node { + node: ListIfItem( + ListIfItemExpr { + if_cond: Node { + node: NameConstantLit( + NameConstantLit { + value: True, + }, + ), + filename: "", + line: 2, + column: 7, + end_line: 2, + end_column: 11, + }, + exprs: [ + Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "b", + filename: "", + line: 3, + column: 8, + end_line: 3, + end_column: 9, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 3, + column: 8, + end_line: 3, + end_column: 9, + }, + Node { + node: Missing( + MissingExpr, + ), + filename: "", + line: 3, + column: 10, + end_line: 3, + end_column: 11, + }, + Node { + node: List( + ListExpr { + elts: [], + ctx: Load, + }, + ), + filename: "", + line: 3, + column: 12, + end_line: 3, + end_column: 14, + }, + ], + orelse: None, + }, + ), + filename: "", + line: 2, + column: 4, + end_line: 4, + end_column: 0, + }, + ], + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 4, + end_column: 1, +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__list_recovery_14.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__list_recovery_14.snap new file mode 100644 index 000000000..fe6b45e6d --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__list_recovery_14.snap @@ -0,0 +1,87 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(r#\"[\n if True:\n b = \n]\n\"#)" +--- +Node { + node: List( + ListExpr { + elts: [ + Node { + node: ListIfItem( + ListIfItemExpr { + if_cond: Node { + node: NameConstantLit( + NameConstantLit { + value: True, + }, + ), + filename: "", + line: 2, + column: 7, + end_line: 2, + end_column: 11, + }, + exprs: [ + Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "b", + filename: "", + line: 3, + column: 8, + end_line: 3, + end_column: 9, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 3, + column: 8, + end_line: 3, + end_column: 9, + }, + Node { + node: Missing( + MissingExpr, + ), + filename: "", + line: 3, + column: 10, + end_line: 3, + end_column: 11, + }, + Node { + node: Missing( + MissingExpr, + ), + filename: "", + line: 3, + column: 12, + end_line: 4, + end_column: 0, + }, + ], + orelse: None, + }, + ), + filename: "", + line: 2, + column: 4, + end_line: 4, + end_column: 0, + }, + ], + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 4, + end_column: 1, +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__list_recovery_15.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__list_recovery_15.snap new file mode 100644 index 000000000..4d35ef38b --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__list_recovery_15.snap @@ -0,0 +1,89 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(r#\"[\n if True:\n b -\n]\n\"#)" +--- +Node { + node: List( + ListExpr { + elts: [ + Node { + node: ListIfItem( + ListIfItemExpr { + if_cond: Node { + node: NameConstantLit( + NameConstantLit { + value: True, + }, + ), + filename: "", + line: 2, + column: 7, + end_line: 2, + end_column: 11, + }, + exprs: [ + Node { + node: Binary( + BinaryExpr { + left: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "b", + filename: "", + line: 3, + column: 8, + end_line: 3, + end_column: 9, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 3, + column: 8, + end_line: 3, + end_column: 9, + }, + op: Sub, + right: Node { + node: Missing( + MissingExpr, + ), + filename: "", + line: 3, + column: 11, + end_line: 4, + end_column: 0, + }, + }, + ), + filename: "", + line: 3, + column: 8, + end_line: 3, + end_column: 11, + }, + ], + orelse: None, + }, + ), + filename: "", + line: 2, + column: 4, + end_line: 4, + end_column: 0, + }, + ], + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 4, + end_column: 1, +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__list_recovery_16.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__list_recovery_16.snap new file mode 100644 index 000000000..6200e4a98 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__list_recovery_16.snap @@ -0,0 +1,137 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(r#\"{\n if True:\n b = [] = []\n}\n\"#)" +--- +Node { + node: Config( + ConfigExpr { + items: [ + Node { + node: ConfigEntry { + key: None, + value: Node { + node: ConfigIfEntry( + ConfigIfEntryExpr { + if_cond: Node { + node: NameConstantLit( + NameConstantLit { + value: True, + }, + ), + filename: "", + line: 2, + column: 7, + end_line: 2, + end_column: 11, + }, + items: [ + Node { + node: ConfigEntry { + key: Some( + Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "b", + filename: "", + line: 3, + column: 8, + end_line: 3, + end_column: 9, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 3, + column: 8, + end_line: 3, + end_column: 9, + }, + ), + value: Node { + node: List( + ListExpr { + elts: [], + ctx: Load, + }, + ), + filename: "", + line: 3, + column: 12, + end_line: 3, + end_column: 14, + }, + operation: Override, + }, + filename: "", + line: 3, + column: 8, + end_line: 3, + end_column: 14, + }, + Node { + node: ConfigEntry { + key: Some( + Node { + node: Missing( + MissingExpr, + ), + filename: "", + line: 3, + column: 15, + end_line: 3, + end_column: 16, + }, + ), + value: Node { + node: List( + ListExpr { + elts: [], + ctx: Load, + }, + ), + filename: "", + line: 3, + column: 17, + end_line: 3, + end_column: 19, + }, + operation: Override, + }, + filename: "", + line: 3, + column: 15, + end_line: 3, + end_column: 19, + }, + ], + orelse: None, + }, + ), + filename: "", + line: 2, + column: 4, + end_line: 4, + end_column: 0, + }, + operation: Union, + }, + filename: "", + line: 2, + column: 4, + end_line: 4, + end_column: 0, + }, + ], + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 4, + end_column: 1, +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__list_recovery_17.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__list_recovery_17.snap new file mode 100644 index 000000000..8af297076 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__list_recovery_17.snap @@ -0,0 +1,134 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(r#\"{\n if True:\n b = [] = \n}\n\"#)" +--- +Node { + node: Config( + ConfigExpr { + items: [ + Node { + node: ConfigEntry { + key: None, + value: Node { + node: ConfigIfEntry( + ConfigIfEntryExpr { + if_cond: Node { + node: NameConstantLit( + NameConstantLit { + value: True, + }, + ), + filename: "", + line: 2, + column: 7, + end_line: 2, + end_column: 11, + }, + items: [ + Node { + node: ConfigEntry { + key: Some( + Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "b", + filename: "", + line: 3, + column: 8, + end_line: 3, + end_column: 9, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 3, + column: 8, + end_line: 3, + end_column: 9, + }, + ), + value: Node { + node: List( + ListExpr { + elts: [], + ctx: Load, + }, + ), + filename: "", + line: 3, + column: 12, + end_line: 3, + end_column: 14, + }, + operation: Override, + }, + filename: "", + line: 3, + column: 8, + end_line: 3, + end_column: 14, + }, + Node { + node: ConfigEntry { + key: Some( + Node { + node: Missing( + MissingExpr, + ), + filename: "", + line: 3, + column: 15, + end_line: 3, + end_column: 16, + }, + ), + value: Node { + node: Missing( + MissingExpr, + ), + filename: "", + line: 3, + column: 17, + end_line: 4, + end_column: 0, + }, + operation: Override, + }, + filename: "", + line: 3, + column: 15, + end_line: 4, + end_column: 0, + }, + ], + orelse: None, + }, + ), + filename: "", + line: 2, + column: 4, + end_line: 4, + end_column: 0, + }, + operation: Union, + }, + filename: "", + line: 2, + column: 4, + end_line: 4, + end_column: 0, + }, + ], + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 4, + end_column: 1, +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__list_recovery_18.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__list_recovery_18.snap new file mode 100644 index 000000000..a4ff6c2ce --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__list_recovery_18.snap @@ -0,0 +1,124 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(r#\"{\n if True:\n b = [] -\n}\n\"#)" +--- +Node { + node: Config( + ConfigExpr { + items: [ + Node { + node: ConfigEntry { + key: None, + value: Node { + node: ConfigIfEntry( + ConfigIfEntryExpr { + if_cond: Node { + node: NameConstantLit( + NameConstantLit { + value: True, + }, + ), + filename: "", + line: 2, + column: 7, + end_line: 2, + end_column: 11, + }, + items: [ + Node { + node: ConfigEntry { + key: Some( + Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "b", + filename: "", + line: 3, + column: 8, + end_line: 3, + end_column: 9, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 3, + column: 8, + end_line: 3, + end_column: 9, + }, + ), + value: Node { + node: Binary( + BinaryExpr { + left: Node { + node: List( + ListExpr { + elts: [], + ctx: Load, + }, + ), + filename: "", + line: 3, + column: 12, + end_line: 3, + end_column: 14, + }, + op: Sub, + right: Node { + node: Missing( + MissingExpr, + ), + filename: "", + line: 3, + column: 16, + end_line: 4, + end_column: 0, + }, + }, + ), + filename: "", + line: 3, + column: 12, + end_line: 3, + end_column: 16, + }, + operation: Override, + }, + filename: "", + line: 3, + column: 8, + end_line: 3, + end_column: 16, + }, + ], + orelse: None, + }, + ), + filename: "", + line: 2, + column: 4, + end_line: 4, + end_column: 0, + }, + operation: Union, + }, + filename: "", + line: 2, + column: 4, + end_line: 4, + end_column: 0, + }, + ], + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 4, + end_column: 1, +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__list_recovery_2.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__list_recovery_2.snap new file mode 100644 index 000000000..aced507ef --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__list_recovery_2.snap @@ -0,0 +1,50 @@ +--- +source: parser/src/tests/error_recovery.rs +assertion_line: 7 +expression: "crate::tests::parsing_expr_string(\"[0,1\")" +--- +Node { + node: List( + ListExpr { + elts: [ + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 0, + ), + }, + ), + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 2, + }, + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 1, + ), + }, + ), + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 4, + }, + ], + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 4, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__list_recovery_3.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__list_recovery_3.snap new file mode 100644 index 000000000..e5badc30f --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__list_recovery_3.snap @@ -0,0 +1,64 @@ +--- +source: parser/src/tests/error_recovery.rs +assertion_line: 8 +expression: "crate::tests::parsing_expr_string(\"[[0,1]\")" +--- +Node { + node: List( + ListExpr { + elts: [ + Node { + node: List( + ListExpr { + elts: [ + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 0, + ), + }, + ), + filename: "", + line: 1, + column: 2, + end_line: 1, + end_column: 3, + }, + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 1, + ), + }, + ), + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 5, + }, + ], + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 6, + }, + ], + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 6, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__list_recovery_4.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__list_recovery_4.snap new file mode 100644 index 000000000..85ef6c261 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__list_recovery_4.snap @@ -0,0 +1,64 @@ +--- +source: parser/src/tests/error_recovery.rs +assertion_line: 9 +expression: "crate::tests::parsing_expr_string(\"[[0,1\")" +--- +Node { + node: List( + ListExpr { + elts: [ + Node { + node: List( + ListExpr { + elts: [ + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 0, + ), + }, + ), + filename: "", + line: 1, + column: 2, + end_line: 1, + end_column: 3, + }, + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 1, + ), + }, + ), + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 5, + }, + ], + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 5, + }, + ], + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 5, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__list_recovery_5.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__list_recovery_5.snap new file mode 100644 index 000000000..492a653ca --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__list_recovery_5.snap @@ -0,0 +1,50 @@ +--- +source: parser/src/tests/error_recovery.rs +assertion_line: 10 +expression: "crate::tests::parsing_expr_string(r#\"[\n 0,\n 1\n \"#)" +--- +Node { + node: List( + ListExpr { + elts: [ + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 0, + ), + }, + ), + filename: "", + line: 2, + column: 4, + end_line: 2, + end_column: 5, + }, + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 1, + ), + }, + ), + filename: "", + line: 3, + column: 4, + end_line: 3, + end_column: 5, + }, + ], + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 4, + end_column: 4, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__list_recovery_6.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__list_recovery_6.snap new file mode 100644 index 000000000..78c29602f --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__list_recovery_6.snap @@ -0,0 +1,50 @@ +--- +source: parser/src/tests/error_recovery.rs +assertion_line: 48 +expression: "crate::tests::parsing_expr_string(\"[0 1]\")" +--- +Node { + node: List( + ListExpr { + elts: [ + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 0, + ), + }, + ), + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 2, + }, + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 1, + ), + }, + ), + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 4, + }, + ], + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 5, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__list_recovery_7.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__list_recovery_7.snap new file mode 100644 index 000000000..e715c89bc --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__list_recovery_7.snap @@ -0,0 +1,50 @@ +--- +source: parser/src/tests/error_recovery.rs +assertion_line: 49 +expression: "crate::tests::parsing_expr_string(\"[0,, 1\")" +--- +Node { + node: List( + ListExpr { + elts: [ + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 0, + ), + }, + ), + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 2, + }, + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 1, + ), + }, + ), + filename: "", + line: 1, + column: 5, + end_line: 1, + end_column: 6, + }, + ], + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 6, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__list_recovery_8.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__list_recovery_8.snap new file mode 100644 index 000000000..4d10dee6f --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__list_recovery_8.snap @@ -0,0 +1,62 @@ +--- +source: parser/src/tests/error_recovery.rs +assertion_line: 50 +expression: "crate::tests::parsing_expr_string(\"[0 ~ 1\")" +--- +Node { + node: List( + ListExpr { + elts: [ + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 0, + ), + }, + ), + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 2, + }, + Node { + node: Unary( + UnaryExpr { + op: Invert, + operand: Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 1, + ), + }, + ), + filename: "", + line: 1, + column: 5, + end_line: 1, + end_column: 6, + }, + }, + ), + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 6, + }, + ], + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 6, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__list_recovery_9.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__list_recovery_9.snap new file mode 100644 index 000000000..9d6ba6afb --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__list_recovery_9.snap @@ -0,0 +1,99 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(\"[*a, **b]\")" +--- +Node { + node: List( + ListExpr { + elts: [ + Node { + node: Starred( + StarredExpr { + value: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 2, + end_line: 1, + end_column: 3, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 2, + end_line: 1, + end_column: 3, + }, + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 3, + }, + Node { + node: Binary( + BinaryExpr { + left: Node { + node: Missing( + MissingExpr, + ), + filename: "", + line: 1, + column: 5, + end_line: 1, + end_column: 7, + }, + op: Pow, + right: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "b", + filename: "", + line: 1, + column: 7, + end_line: 1, + end_column: 8, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 7, + end_line: 1, + end_column: 8, + }, + }, + ), + filename: "", + line: 1, + column: 5, + end_line: 1, + end_column: 8, + }, + ], + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 9, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__number_literal_recovery_0.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__number_literal_recovery_0.snap new file mode 100644 index 000000000..a1e546300 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__number_literal_recovery_0.snap @@ -0,0 +1,21 @@ +--- +source: parser/src/tests/error_recovery.rs +assertion_line: 8 +expression: "crate::tests::parsing_expr_string(\"00\")" +--- +Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 0, + ), + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 2, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__number_literal_recovery_1.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__number_literal_recovery_1.snap new file mode 100644 index 000000000..ac6b04397 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__number_literal_recovery_1.snap @@ -0,0 +1,21 @@ +--- +source: parser/src/tests/error_recovery.rs +assertion_line: 9 +expression: "crate::tests::parsing_expr_string(\"00a\")" +--- +Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 0, + ), + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 3, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__number_literal_recovery_10.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__number_literal_recovery_10.snap new file mode 100644 index 000000000..1fcdec63e --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__number_literal_recovery_10.snap @@ -0,0 +1,21 @@ +--- +source: parser/src/tests/error_recovery.rs +assertion_line: 20 +expression: "crate::tests::parsing_expr_string(\"100mm\")" +--- +Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 100, + ), + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 5, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__number_literal_recovery_2.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__number_literal_recovery_2.snap new file mode 100644 index 000000000..8e11e6460 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__number_literal_recovery_2.snap @@ -0,0 +1,21 @@ +--- +source: parser/src/tests/error_recovery.rs +assertion_line: 12 +expression: "crate::tests::parsing_expr_string(\"0x112.3\")" +--- +Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Float( + 0.0, + ), + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 7, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__number_literal_recovery_3.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__number_literal_recovery_3.snap new file mode 100644 index 000000000..a08c61788 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__number_literal_recovery_3.snap @@ -0,0 +1,21 @@ +--- +source: parser/src/tests/error_recovery.rs +assertion_line: 11 +expression: "crate::tests::parsing_expr_string(\"0o\")" +--- +Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 0, + ), + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 2, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__number_literal_recovery_4.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__number_literal_recovery_4.snap new file mode 100644 index 000000000..6db076205 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__number_literal_recovery_4.snap @@ -0,0 +1,21 @@ +--- +source: parser/src/tests/error_recovery.rs +assertion_line: 12 +expression: "crate::tests::parsing_expr_string(\"0oA\")" +--- +Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 0, + ), + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 3, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__number_literal_recovery_5.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__number_literal_recovery_5.snap new file mode 100644 index 000000000..9953c6cfd --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__number_literal_recovery_5.snap @@ -0,0 +1,21 @@ +--- +source: parser/src/tests/error_recovery.rs +assertion_line: 13 +expression: "crate::tests::parsing_expr_string(\"0x\")" +--- +Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 0, + ), + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 2, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__number_literal_recovery_6.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__number_literal_recovery_6.snap new file mode 100644 index 000000000..09b76ab4c --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__number_literal_recovery_6.snap @@ -0,0 +1,21 @@ +--- +source: parser/src/tests/error_recovery.rs +assertion_line: 14 +expression: "crate::tests::parsing_expr_string(\"0xH\")" +--- +Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 0, + ), + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 3, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__number_literal_recovery_7.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__number_literal_recovery_7.snap new file mode 100644 index 000000000..2eeebefbc --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__number_literal_recovery_7.snap @@ -0,0 +1,21 @@ +--- +source: parser/src/tests/error_recovery.rs +assertion_line: 17 +expression: "crate::tests::parsing_expr_string(\"0e0\")" +--- +Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Float( + 0.0, + ), + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 3, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__number_literal_recovery_8.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__number_literal_recovery_8.snap new file mode 100644 index 000000000..0c9228f75 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__number_literal_recovery_8.snap @@ -0,0 +1,21 @@ +--- +source: parser/src/tests/error_recovery.rs +assertion_line: 18 +expression: "crate::tests::parsing_expr_string(\"0b333\")" +--- +Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 0, + ), + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 5, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__number_literal_recovery_9.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__number_literal_recovery_9.snap new file mode 100644 index 000000000..df346b367 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__number_literal_recovery_9.snap @@ -0,0 +1,21 @@ +--- +source: parser/src/tests/error_recovery.rs +assertion_line: 19 +expression: "crate::tests::parsing_expr_string(\"10KI\")" +--- +Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 10, + ), + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 4, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__paren_recovery_0.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__paren_recovery_0.snap new file mode 100644 index 000000000..658e897e8 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__paren_recovery_0.snap @@ -0,0 +1,39 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(\"(a\")" +--- +Node { + node: Paren( + ParenExpr { + expr: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 2, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 2, + }, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 2, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__paren_recovery_1.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__paren_recovery_1.snap new file mode 100644 index 000000000..c5ab49249 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__paren_recovery_1.snap @@ -0,0 +1,66 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(\"(a + 1\")" +--- +Node { + node: Paren( + ParenExpr { + expr: Node { + node: Binary( + BinaryExpr { + left: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 2, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 2, + }, + op: Add, + right: Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 1, + ), + }, + ), + filename: "", + line: 1, + column: 5, + end_line: 1, + end_column: 6, + }, + }, + ), + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 6, + }, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 6, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__paren_recovery_2.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__paren_recovery_2.snap new file mode 100644 index 000000000..555d7f732 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__paren_recovery_2.snap @@ -0,0 +1,26 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(r#\"(\"#)" +--- +Node { + node: Paren( + ParenExpr { + expr: Node { + node: Missing( + MissingExpr, + ), + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 1, + }, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__paren_recovery_3.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__paren_recovery_3.snap new file mode 100644 index 000000000..891fafced --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__paren_recovery_3.snap @@ -0,0 +1,26 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(r#\"(]\"#)" +--- +Node { + node: Paren( + ParenExpr { + expr: Node { + node: Missing( + MissingExpr, + ), + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 2, + }, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 2, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__paren_recovery_4.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__paren_recovery_4.snap new file mode 100644 index 000000000..371a9181f --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__paren_recovery_4.snap @@ -0,0 +1,39 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(r#\"(a\"#)" +--- +Node { + node: Paren( + ParenExpr { + expr: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 2, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 2, + }, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 2, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__paren_recovery_5.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__paren_recovery_5.snap new file mode 100644 index 000000000..de670e6df --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__paren_recovery_5.snap @@ -0,0 +1,61 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(r#\"(a +\"#)" +--- +Node { + node: Paren( + ParenExpr { + expr: Node { + node: Binary( + BinaryExpr { + left: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 2, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 2, + }, + op: Add, + right: Node { + node: Missing( + MissingExpr, + ), + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 4, + }, + }, + ), + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 4, + }, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 4, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__rule_stmt_recovery_0.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__rule_stmt_recovery_0.snap new file mode 100644 index 000000000..72222a840 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__rule_stmt_recovery_0.snap @@ -0,0 +1,36 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\"rule\"#)" +--- +Module { + filename: "", + doc: None, + body: [ + Node { + node: Rule( + RuleStmt { + doc: None, + name: Node { + node: "", + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 4, + }, + parent_rules: [], + decorators: [], + checks: [], + args: None, + for_host_name: None, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 4, + }, + ], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__rule_stmt_recovery_1.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__rule_stmt_recovery_1.snap new file mode 100644 index 000000000..690ccd1b8 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__rule_stmt_recovery_1.snap @@ -0,0 +1,36 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\"rule A\"#)" +--- +Module { + filename: "", + doc: None, + body: [ + Node { + node: Rule( + RuleStmt { + doc: None, + name: Node { + node: "A", + filename: "", + line: 1, + column: 5, + end_line: 1, + end_column: 6, + }, + parent_rules: [], + decorators: [], + checks: [], + args: None, + for_host_name: None, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 6, + }, + ], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__rule_stmt_recovery_2.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__rule_stmt_recovery_2.snap new file mode 100644 index 000000000..25924f88f --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__rule_stmt_recovery_2.snap @@ -0,0 +1,49 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\"rule A[\"#)" +--- +Module { + filename: "", + doc: None, + body: [ + Node { + node: Rule( + RuleStmt { + doc: None, + name: Node { + node: "A", + filename: "", + line: 1, + column: 5, + end_line: 1, + end_column: 6, + }, + parent_rules: [], + decorators: [], + checks: [], + args: Some( + Node { + node: Arguments { + args: [], + defaults: [], + ty_list: [], + }, + filename: "", + line: 1, + column: 6, + end_line: 1, + end_column: 7, + }, + ), + for_host_name: None, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 7, + }, + ], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__rule_stmt_recovery_3.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__rule_stmt_recovery_3.snap new file mode 100644 index 000000000..4b30e85b0 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__rule_stmt_recovery_3.snap @@ -0,0 +1,58 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\"rule A::\"#)" +--- +Module { + filename: "", + doc: None, + body: [ + Node { + node: Rule( + RuleStmt { + doc: None, + name: Node { + node: "A", + filename: "", + line: 1, + column: 5, + end_line: 1, + end_column: 6, + }, + parent_rules: [], + decorators: [], + checks: [ + Node { + node: CheckExpr { + test: Node { + node: Missing( + MissingExpr, + ), + filename: "", + line: 1, + column: 8, + end_line: 1, + end_column: 8, + }, + if_cond: None, + msg: None, + }, + filename: "", + line: 1, + column: 8, + end_line: 1, + end_column: 8, + }, + ], + args: None, + for_host_name: None, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 8, + }, + ], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__rule_stmt_recovery_4.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__rule_stmt_recovery_4.snap new file mode 100644 index 000000000..d94506fa0 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__rule_stmt_recovery_4.snap @@ -0,0 +1,58 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\"rule A:B\"#)" +--- +Module { + filename: "", + doc: None, + body: [ + Node { + node: Rule( + RuleStmt { + doc: None, + name: Node { + node: "A", + filename: "", + line: 1, + column: 5, + end_line: 1, + end_column: 6, + }, + parent_rules: [], + decorators: [], + checks: [ + Node { + node: CheckExpr { + test: Node { + node: Missing( + MissingExpr, + ), + filename: "", + line: 1, + column: 8, + end_line: 1, + end_column: 8, + }, + if_cond: None, + msg: None, + }, + filename: "", + line: 1, + column: 8, + end_line: 1, + end_column: 8, + }, + ], + args: None, + for_host_name: None, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 8, + }, + ], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__rule_stmt_recovery_5.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__rule_stmt_recovery_5.snap new file mode 100644 index 000000000..cc4c1f167 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__rule_stmt_recovery_5.snap @@ -0,0 +1,49 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\"rule A(:\"#)" +--- +Module { + filename: "", + doc: None, + body: [ + Node { + node: Rule( + RuleStmt { + doc: None, + name: Node { + node: "A", + filename: "", + line: 1, + column: 5, + end_line: 1, + end_column: 6, + }, + parent_rules: [ + Node { + node: Identifier { + names: [], + pkgpath: "", + ctx: Load, + }, + filename: "", + line: 1, + column: 7, + end_line: 1, + end_column: 8, + }, + ], + decorators: [], + checks: [], + args: None, + for_host_name: None, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 8, + }, + ], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__rule_stmt_recovery_6.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__rule_stmt_recovery_6.snap new file mode 100644 index 000000000..6bf798b74 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__rule_stmt_recovery_6.snap @@ -0,0 +1,60 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\"\nrule A:\n True \"#)" +--- +Module { + filename: "", + doc: None, + body: [ + Node { + node: Rule( + RuleStmt { + doc: None, + name: Node { + node: "A", + filename: "", + line: 2, + column: 5, + end_line: 2, + end_column: 6, + }, + parent_rules: [], + decorators: [], + checks: [ + Node { + node: CheckExpr { + test: Node { + node: NameConstantLit( + NameConstantLit { + value: True, + }, + ), + filename: "", + line: 3, + column: 4, + end_line: 3, + end_column: 8, + }, + if_cond: None, + msg: None, + }, + filename: "", + line: 3, + column: 4, + end_line: 3, + end_column: 8, + }, + ], + args: None, + for_host_name: None, + }, + ), + filename: "", + line: 2, + column: 0, + end_line: 3, + end_column: 9, + }, + ], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__rule_stmt_recovery_7.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__rule_stmt_recovery_7.snap new file mode 100644 index 000000000..5b1f5dd0d --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__rule_stmt_recovery_7.snap @@ -0,0 +1,79 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\"\nrule A:\n @\n\"#)" +--- +Module { + filename: "", + doc: None, + body: [ + Node { + node: Rule( + RuleStmt { + doc: None, + name: Node { + node: "A", + filename: "", + line: 2, + column: 5, + end_line: 2, + end_column: 6, + }, + parent_rules: [], + decorators: [], + checks: [ + Node { + node: CheckExpr { + test: Node { + node: Missing( + MissingExpr, + ), + filename: "", + line: 3, + column: 4, + end_line: 3, + end_column: 5, + }, + if_cond: None, + msg: None, + }, + filename: "", + line: 3, + column: 4, + end_line: 3, + end_column: 4, + }, + Node { + node: CheckExpr { + test: Node { + node: Missing( + MissingExpr, + ), + filename: "", + line: 3, + column: 5, + end_line: 3, + end_column: 6, + }, + if_cond: None, + msg: None, + }, + filename: "", + line: 3, + column: 5, + end_line: 3, + end_column: 5, + }, + ], + args: None, + for_host_name: None, + }, + ), + filename: "", + line: 2, + column: 0, + end_line: 3, + end_column: 6, + }, + ], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_recovery_0.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_recovery_0.snap new file mode 100644 index 000000000..5f6e442ad --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_recovery_0.snap @@ -0,0 +1,51 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(r#\"s {\"#)" +--- +Node { + node: Schema( + SchemaExpr { + name: Node { + node: Identifier { + names: [ + Node { + node: "s", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + pkgpath: "", + ctx: Load, + }, + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + args: [], + kwargs: [], + config: Node { + node: Config( + ConfigExpr { + items: [], + }, + ), + filename: "", + line: 1, + column: 2, + end_line: 1, + end_column: 3, + }, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 3, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_recovery_1.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_recovery_1.snap new file mode 100644 index 000000000..89c8905aa --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_recovery_1.snap @@ -0,0 +1,101 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(r#\"s {a=1\"#)" +--- +Node { + node: Schema( + SchemaExpr { + name: Node { + node: Identifier { + names: [ + Node { + node: "s", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + pkgpath: "", + ctx: Load, + }, + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + args: [], + kwargs: [], + config: Node { + node: Config( + ConfigExpr { + items: [ + Node { + node: ConfigEntry { + key: Some( + Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 4, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 4, + }, + ), + value: Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 1, + ), + }, + ), + filename: "", + line: 1, + column: 5, + end_line: 1, + end_column: 6, + }, + operation: Override, + }, + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 6, + }, + ], + }, + ), + filename: "", + line: 1, + column: 2, + end_line: 1, + end_column: 6, + }, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 6, +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_recovery_2.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_recovery_2.snap new file mode 100644 index 000000000..d601fb18f --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_recovery_2.snap @@ -0,0 +1,36 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(r#\"s.0 {a=1}\"#)" +--- +Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "s", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + Node { + node: "", + filename: "", + line: 1, + column: 2, + end_line: 1, + end_column: 2, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 2, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_recovery_3.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_recovery_3.snap new file mode 100644 index 000000000..3e5dc5123 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_recovery_3.snap @@ -0,0 +1,62 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(r#\"s?.a {a=1}\"#)" +--- +Node { + node: Selector( + SelectorExpr { + value: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "s", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + attr: Node { + node: Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 4, + }, + ], + pkgpath: "", + ctx: Load, + }, + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 4, + }, + ctx: Load, + has_question: true, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 4, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_recovery_4.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_recovery_4.snap new file mode 100644 index 000000000..2a0aad990 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_recovery_4.snap @@ -0,0 +1,109 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(r#\"s. {a=1}\"#)" +--- +Node { + node: Schema( + SchemaExpr { + name: Node { + node: Identifier { + names: [ + Node { + node: "s", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + Node { + node: "", + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 3, + }, + ], + pkgpath: "", + ctx: Load, + }, + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 2, + }, + args: [], + kwargs: [], + config: Node { + node: Config( + ConfigExpr { + items: [ + Node { + node: ConfigEntry { + key: Some( + Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 5, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 5, + }, + ), + value: Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 1, + ), + }, + ), + filename: "", + line: 1, + column: 6, + end_line: 1, + end_column: 7, + }, + operation: Override, + }, + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 7, + }, + ], + }, + ), + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 8, + }, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 8, +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_recovery_5.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_recovery_5.snap new file mode 100644 index 000000000..2f3c3ba6f --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_recovery_5.snap @@ -0,0 +1,104 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(r#\"s( {a=1}\"#)" +--- +Node { + node: Call( + CallExpr { + func: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "s", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + args: [ + Node { + node: Config( + ConfigExpr { + items: [ + Node { + node: ConfigEntry { + key: Some( + Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 5, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 5, + }, + ), + value: Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 1, + ), + }, + ), + filename: "", + line: 1, + column: 6, + end_line: 1, + end_column: 7, + }, + operation: Override, + }, + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 7, + }, + ], + }, + ), + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 8, + }, + ], + keywords: [], + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 8, +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_recovery_6.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_recovery_6.snap new file mode 100644 index 000000000..d61635ea6 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_recovery_6.snap @@ -0,0 +1,101 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(r#\"s(] {a=1}\"#)" +--- +Node { + node: Schema( + SchemaExpr { + name: Node { + node: Identifier { + names: [ + Node { + node: "s", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + pkgpath: "", + ctx: Load, + }, + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + args: [], + kwargs: [], + config: Node { + node: Config( + ConfigExpr { + items: [ + Node { + node: ConfigEntry { + key: Some( + Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 5, + end_line: 1, + end_column: 6, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 5, + end_line: 1, + end_column: 6, + }, + ), + value: Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 1, + ), + }, + ), + filename: "", + line: 1, + column: 7, + end_line: 1, + end_column: 8, + }, + operation: Override, + }, + filename: "", + line: 1, + column: 5, + end_line: 1, + end_column: 8, + }, + ], + }, + ), + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 9, + }, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 9, +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_0.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_0.snap new file mode 100644 index 000000000..dfe7121ea --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_0.snap @@ -0,0 +1,41 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\"schema\"#)" +--- +Module { + filename: "", + doc: None, + body: [ + Node { + node: Schema( + SchemaStmt { + doc: None, + name: Node { + node: "", + filename: "", + line: 1, + column: 6, + end_line: 1, + end_column: 6, + }, + parent_name: None, + for_host_name: None, + is_mixin: false, + is_protocol: false, + args: None, + mixins: [], + body: [], + decorators: [], + checks: [], + index_signature: None, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 6, + }, + ], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_1.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_1.snap new file mode 100644 index 000000000..6f8bf3c3d --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_1.snap @@ -0,0 +1,41 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\"schema A\"#)" +--- +Module { + filename: "", + doc: None, + body: [ + Node { + node: Schema( + SchemaStmt { + doc: None, + name: Node { + node: "A", + filename: "", + line: 1, + column: 7, + end_line: 1, + end_column: 8, + }, + parent_name: None, + for_host_name: None, + is_mixin: false, + is_protocol: false, + args: None, + mixins: [], + body: [], + decorators: [], + checks: [], + index_signature: None, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 8, + }, + ], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_10.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_10.snap new file mode 100644 index 000000000..bc0fcc076 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_10.snap @@ -0,0 +1,77 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\"schema A:\n[str:]: []\"#)" +--- +Module { + filename: "", + doc: None, + body: [ + Node { + node: Schema( + SchemaStmt { + doc: None, + name: Node { + node: "A", + filename: "", + line: 1, + column: 7, + end_line: 1, + end_column: 8, + }, + parent_name: None, + for_host_name: None, + is_mixin: false, + is_protocol: false, + args: None, + mixins: [], + body: [], + decorators: [], + checks: [], + index_signature: None, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 2, + end_column: 0, + }, + Node { + node: Assign( + AssignStmt { + targets: [], + value: Node { + node: Missing( + MissingExpr, + ), + filename: "", + line: 2, + column: 10, + end_line: 2, + end_column: 10, + }, + ty: Some( + Node { + node: List( + ListType { + inner_type: None, + }, + ), + filename: "", + line: 2, + column: 8, + end_line: 2, + end_column: 10, + }, + ), + }, + ), + filename: "", + line: 2, + column: 0, + end_line: 2, + end_column: 6, + }, + ], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_11.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_11.snap new file mode 100644 index 000000000..97012da11 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_11.snap @@ -0,0 +1,75 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\"schema A:\n[str]: str = \"#)" +--- +Module { + filename: "", + doc: None, + body: [ + Node { + node: Schema( + SchemaStmt { + doc: None, + name: Node { + node: "A", + filename: "", + line: 1, + column: 7, + end_line: 1, + end_column: 8, + }, + parent_name: None, + for_host_name: None, + is_mixin: false, + is_protocol: false, + args: None, + mixins: [], + body: [], + decorators: [], + checks: [], + index_signature: None, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 2, + end_column: 0, + }, + Node { + node: Assign( + AssignStmt { + targets: [], + value: Node { + node: Missing( + MissingExpr, + ), + filename: "", + line: 2, + column: 13, + end_line: 2, + end_column: 13, + }, + ty: Some( + Node { + node: Basic( + Str, + ), + filename: "", + line: 2, + column: 7, + end_line: 2, + end_column: 10, + }, + ), + }, + ), + filename: "", + line: 2, + column: 0, + end_line: 2, + end_column: 12, + }, + ], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_12.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_12.snap new file mode 100644 index 000000000..c0d7f3461 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_12.snap @@ -0,0 +1,73 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\"schema A:\n[str]: = \"#)" +--- +Module { + filename: "", + doc: None, + body: [ + Node { + node: Schema( + SchemaStmt { + doc: None, + name: Node { + node: "A", + filename: "", + line: 1, + column: 7, + end_line: 1, + end_column: 8, + }, + parent_name: None, + for_host_name: None, + is_mixin: false, + is_protocol: false, + args: None, + mixins: [], + body: [], + decorators: [], + checks: [], + index_signature: None, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 2, + end_column: 0, + }, + Node { + node: Assign( + AssignStmt { + targets: [], + value: Node { + node: Missing( + MissingExpr, + ), + filename: "", + line: 2, + column: 9, + end_line: 2, + end_column: 9, + }, + ty: Some( + Node { + node: Any, + filename: "", + line: 2, + column: 7, + end_line: 2, + end_column: 8, + }, + ), + }, + ), + filename: "", + line: 2, + column: 0, + end_line: 2, + end_column: 5, + }, + ], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_13.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_13.snap new file mode 100644 index 000000000..e14c4f3f8 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_13.snap @@ -0,0 +1,77 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\"schema A:\n[str]: ''= \"#)" +--- +Module { + filename: "", + doc: None, + body: [ + Node { + node: Schema( + SchemaStmt { + doc: None, + name: Node { + node: "A", + filename: "", + line: 1, + column: 7, + end_line: 1, + end_column: 8, + }, + parent_name: None, + for_host_name: None, + is_mixin: false, + is_protocol: false, + args: None, + mixins: [], + body: [], + decorators: [], + checks: [], + index_signature: None, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 2, + end_column: 0, + }, + Node { + node: Assign( + AssignStmt { + targets: [], + value: Node { + node: Missing( + MissingExpr, + ), + filename: "", + line: 2, + column: 11, + end_line: 2, + end_column: 11, + }, + ty: Some( + Node { + node: Literal( + Str( + "", + ), + ), + filename: "", + line: 2, + column: 7, + end_line: 2, + end_column: 9, + }, + ), + }, + ), + filename: "", + line: 2, + column: 0, + end_line: 2, + end_column: 10, + }, + ], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_14.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_14.snap new file mode 100644 index 000000000..631651b7a --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_14.snap @@ -0,0 +1,113 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\"schema A:\na??: int \"#)" +--- +Module { + filename: "", + doc: None, + body: [ + Node { + node: Schema( + SchemaStmt { + doc: None, + name: Node { + node: "A", + filename: "", + line: 1, + column: 7, + end_line: 1, + end_column: 8, + }, + parent_name: None, + for_host_name: None, + is_mixin: false, + is_protocol: false, + args: None, + mixins: [], + body: [], + decorators: [], + checks: [], + index_signature: None, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 2, + end_column: 0, + }, + Node { + node: Expr( + ExprStmt { + exprs: [ + Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 2, + column: 0, + end_line: 2, + end_column: 1, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 2, + column: 0, + end_line: 2, + end_column: 1, + }, + ], + }, + ), + filename: "", + line: 2, + column: 0, + end_line: 2, + end_column: 1, + }, + Node { + node: Expr( + ExprStmt { + exprs: [ + Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "int", + filename: "", + line: 2, + column: 5, + end_line: 2, + end_column: 8, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 2, + column: 5, + end_line: 2, + end_column: 8, + }, + ], + }, + ), + filename: "", + line: 2, + column: 5, + end_line: 2, + end_column: 8, + }, + ], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_15.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_15.snap new file mode 100644 index 000000000..7aa335109 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_15.snap @@ -0,0 +1,148 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\"schema A:\na!: int \"#)" +--- +Module { + filename: "", + doc: None, + body: [ + Node { + node: Schema( + SchemaStmt { + doc: None, + name: Node { + node: "A", + filename: "", + line: 1, + column: 7, + end_line: 1, + end_column: 8, + }, + parent_name: None, + for_host_name: None, + is_mixin: false, + is_protocol: false, + args: None, + mixins: [], + body: [], + decorators: [], + checks: [], + index_signature: None, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 2, + end_column: 0, + }, + Node { + node: Expr( + ExprStmt { + exprs: [ + Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 2, + column: 0, + end_line: 2, + end_column: 1, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 2, + column: 0, + end_line: 2, + end_column: 1, + }, + ], + }, + ), + filename: "", + line: 2, + column: 0, + end_line: 2, + end_column: 1, + }, + Node { + node: Expr( + ExprStmt { + exprs: [ + Node { + node: Unary( + UnaryExpr { + op: Not, + operand: Node { + node: Missing( + MissingExpr, + ), + filename: "", + line: 2, + column: 2, + end_line: 2, + end_column: 3, + }, + }, + ), + filename: "", + line: 2, + column: 1, + end_line: 2, + end_column: 2, + }, + ], + }, + ), + filename: "", + line: 2, + column: 1, + end_line: 2, + end_column: 2, + }, + Node { + node: Expr( + ExprStmt { + exprs: [ + Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "int", + filename: "", + line: 2, + column: 4, + end_line: 2, + end_column: 7, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 2, + column: 4, + end_line: 2, + end_column: 7, + }, + ], + }, + ), + filename: "", + line: 2, + column: 4, + end_line: 2, + end_column: 7, + }, + ], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_16.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_16.snap new file mode 100644 index 000000000..6109806a8 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_16.snap @@ -0,0 +1,183 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\"schema A:\na!!: int \"#)" +--- +Module { + filename: "", + doc: None, + body: [ + Node { + node: Schema( + SchemaStmt { + doc: None, + name: Node { + node: "A", + filename: "", + line: 1, + column: 7, + end_line: 1, + end_column: 8, + }, + parent_name: None, + for_host_name: None, + is_mixin: false, + is_protocol: false, + args: None, + mixins: [], + body: [], + decorators: [], + checks: [], + index_signature: None, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 2, + end_column: 0, + }, + Node { + node: Expr( + ExprStmt { + exprs: [ + Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 2, + column: 0, + end_line: 2, + end_column: 1, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 2, + column: 0, + end_line: 2, + end_column: 1, + }, + ], + }, + ), + filename: "", + line: 2, + column: 0, + end_line: 2, + end_column: 1, + }, + Node { + node: Expr( + ExprStmt { + exprs: [ + Node { + node: Unary( + UnaryExpr { + op: Not, + operand: Node { + node: Missing( + MissingExpr, + ), + filename: "", + line: 2, + column: 2, + end_line: 2, + end_column: 3, + }, + }, + ), + filename: "", + line: 2, + column: 1, + end_line: 2, + end_column: 2, + }, + ], + }, + ), + filename: "", + line: 2, + column: 1, + end_line: 2, + end_column: 2, + }, + Node { + node: Expr( + ExprStmt { + exprs: [ + Node { + node: Unary( + UnaryExpr { + op: Not, + operand: Node { + node: Missing( + MissingExpr, + ), + filename: "", + line: 2, + column: 3, + end_line: 2, + end_column: 4, + }, + }, + ), + filename: "", + line: 2, + column: 2, + end_line: 2, + end_column: 3, + }, + ], + }, + ), + filename: "", + line: 2, + column: 2, + end_line: 2, + end_column: 3, + }, + Node { + node: Expr( + ExprStmt { + exprs: [ + Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "int", + filename: "", + line: 2, + column: 5, + end_line: 2, + end_column: 8, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 2, + column: 5, + end_line: 2, + end_column: 8, + }, + ], + }, + ), + filename: "", + line: 2, + column: 5, + end_line: 2, + end_column: 8, + }, + ], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_17.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_17.snap new file mode 100644 index 000000000..497f3d15e --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_17.snap @@ -0,0 +1,93 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\"schema A:\na: \"#)" +--- +Module { + filename: "", + doc: None, + body: [ + Node { + node: Schema( + SchemaStmt { + doc: None, + name: Node { + node: "A", + filename: "", + line: 1, + column: 7, + end_line: 1, + end_column: 8, + }, + parent_name: None, + for_host_name: None, + is_mixin: false, + is_protocol: false, + args: None, + mixins: [], + body: [], + decorators: [], + checks: [], + index_signature: None, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 2, + end_column: 0, + }, + Node { + node: Assign( + AssignStmt { + targets: [ + Node { + node: Target { + name: Node { + node: "a", + filename: "", + line: 2, + column: 0, + end_line: 2, + end_column: 1, + }, + paths: [], + pkgpath: "", + }, + filename: "", + line: 2, + column: 0, + end_line: 2, + end_column: 1, + }, + ], + value: Node { + node: Missing( + MissingExpr, + ), + filename: "", + line: 2, + column: 3, + end_line: 2, + end_column: 3, + }, + ty: Some( + Node { + node: Any, + filename: "", + line: 2, + column: 3, + end_line: 2, + end_column: 3, + }, + ), + }, + ), + filename: "", + line: 2, + column: 0, + end_line: 2, + end_column: 1, + }, + ], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_18.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_18.snap new file mode 100644 index 000000000..4b59b1b3c --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_18.snap @@ -0,0 +1,88 @@ +--- +source: parser/src/tests/error_recovery.rs +assertion_line: 210 +expression: "crate::tests::parsing_module_string(r#\"\nschema A:\n a: int\"#)" +--- +Module { + filename: "", + pkg: "", + doc: "", + name: "", + body: [ + Node { + node: Schema( + SchemaStmt { + doc: "", + name: Node { + node: "A", + filename: "", + line: 2, + column: 7, + end_line: 2, + end_column: 8, + }, + parent_name: None, + for_host_name: None, + is_mixin: false, + is_protocol: false, + args: None, + mixins: [], + body: [ + Node { + node: SchemaAttr( + SchemaAttr { + doc: "", + name: Node { + node: "a", + filename: "", + line: 3, + column: 4, + end_line: 3, + end_column: 5, + }, + type_str: Node { + node: "int", + filename: "", + line: 3, + column: 7, + end_line: 3, + end_column: 10, + }, + op: None, + value: None, + is_optional: false, + decorators: [], + ty: Node { + node: Basic( + Int, + ), + filename: "", + line: 3, + column: 7, + end_line: 3, + end_column: 10, + }, + }, + ), + filename: "", + line: 3, + column: 4, + end_line: 3, + end_column: 10, + }, + ], + decorators: [], + checks: [], + index_signature: None, + }, + ), + filename: "", + line: 2, + column: 0, + end_line: 3, + end_column: 10, + }, + ], + comments: [], +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_19.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_19.snap new file mode 100644 index 000000000..70c29f78e --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_19.snap @@ -0,0 +1,109 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\"@deprecated\nschema A:\n a: \"#)" +--- +Module { + filename: "", + doc: None, + body: [ + Node { + node: Schema( + SchemaStmt { + doc: None, + name: Node { + node: "A", + filename: "", + line: 2, + column: 7, + end_line: 2, + end_column: 8, + }, + parent_name: None, + for_host_name: None, + is_mixin: false, + is_protocol: false, + args: None, + mixins: [], + body: [ + Node { + node: SchemaAttr( + SchemaAttr { + doc: "", + name: Node { + node: "a", + filename: "", + line: 3, + column: 4, + end_line: 3, + end_column: 5, + }, + op: None, + value: None, + is_optional: false, + decorators: [], + ty: Node { + node: Any, + filename: "", + line: 3, + column: 7, + end_line: 3, + end_column: 7, + }, + }, + ), + filename: "", + line: 3, + column: 4, + end_line: 3, + end_column: 7, + }, + ], + decorators: [ + Node { + node: CallExpr { + func: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "deprecated", + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 11, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 11, + }, + args: [], + keywords: [], + }, + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 11, + }, + ], + checks: [], + index_signature: None, + }, + ), + filename: "", + line: 2, + column: 0, + end_line: 3, + end_column: 7, + }, + ], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_2.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_2.snap new file mode 100644 index 000000000..af0bbf8a4 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_2.snap @@ -0,0 +1,54 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\"schema A[\"#)" +--- +Module { + filename: "", + doc: None, + body: [ + Node { + node: Schema( + SchemaStmt { + doc: None, + name: Node { + node: "A", + filename: "", + line: 1, + column: 7, + end_line: 1, + end_column: 8, + }, + parent_name: None, + for_host_name: None, + is_mixin: false, + is_protocol: false, + args: Some( + Node { + node: Arguments { + args: [], + defaults: [], + ty_list: [], + }, + filename: "", + line: 1, + column: 8, + end_line: 1, + end_column: 9, + }, + ), + mixins: [], + body: [], + decorators: [], + checks: [], + index_signature: None, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 9, + }, + ], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_20.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_20.snap new file mode 100644 index 000000000..6889d2b02 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_20.snap @@ -0,0 +1,10 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\"@deprecated(\nschema A:\n a: \"#)" +--- +Module { + filename: "", + doc: None, + body: [], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_21.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_21.snap new file mode 100644 index 000000000..6889d2b02 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_21.snap @@ -0,0 +1,10 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\"@deprecated(\nschema A:\n a: \"#)" +--- +Module { + filename: "", + doc: None, + body: [], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_22.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_22.snap new file mode 100644 index 000000000..195cdc9c0 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_22.snap @@ -0,0 +1,133 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\"@deprecated(a\nschema A:\n a: \"#)" +--- +Module { + filename: "", + doc: None, + body: [ + Node { + node: Schema( + SchemaStmt { + doc: None, + name: Node { + node: "A", + filename: "", + line: 2, + column: 7, + end_line: 2, + end_column: 8, + }, + parent_name: None, + for_host_name: None, + is_mixin: false, + is_protocol: false, + args: None, + mixins: [], + body: [ + Node { + node: SchemaAttr( + SchemaAttr { + doc: "", + name: Node { + node: "a", + filename: "", + line: 3, + column: 4, + end_line: 3, + end_column: 5, + }, + op: None, + value: None, + is_optional: false, + decorators: [], + ty: Node { + node: Any, + filename: "", + line: 3, + column: 7, + end_line: 3, + end_column: 7, + }, + }, + ), + filename: "", + line: 3, + column: 4, + end_line: 3, + end_column: 7, + }, + ], + decorators: [ + Node { + node: CallExpr { + func: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "deprecated", + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 11, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 11, + }, + args: [ + Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 12, + end_line: 1, + end_column: 13, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 12, + end_line: 1, + end_column: 13, + }, + ], + keywords: [], + }, + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 13, + }, + ], + checks: [], + index_signature: None, + }, + ), + filename: "", + line: 2, + column: 0, + end_line: 3, + end_column: 7, + }, + ], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_23.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_23.snap new file mode 100644 index 000000000..d915512c1 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_23.snap @@ -0,0 +1,133 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\"@deprecated(a,\nschema A:\n a: \"#)" +--- +Module { + filename: "", + doc: None, + body: [ + Node { + node: Schema( + SchemaStmt { + doc: None, + name: Node { + node: "A", + filename: "", + line: 2, + column: 7, + end_line: 2, + end_column: 8, + }, + parent_name: None, + for_host_name: None, + is_mixin: false, + is_protocol: false, + args: None, + mixins: [], + body: [ + Node { + node: SchemaAttr( + SchemaAttr { + doc: "", + name: Node { + node: "a", + filename: "", + line: 3, + column: 4, + end_line: 3, + end_column: 5, + }, + op: None, + value: None, + is_optional: false, + decorators: [], + ty: Node { + node: Any, + filename: "", + line: 3, + column: 7, + end_line: 3, + end_column: 7, + }, + }, + ), + filename: "", + line: 3, + column: 4, + end_line: 3, + end_column: 7, + }, + ], + decorators: [ + Node { + node: CallExpr { + func: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "deprecated", + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 11, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 11, + }, + args: [ + Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 12, + end_line: 1, + end_column: 13, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 12, + end_line: 1, + end_column: 13, + }, + ], + keywords: [], + }, + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 14, + }, + ], + checks: [], + index_signature: None, + }, + ), + filename: "", + line: 2, + column: 0, + end_line: 3, + end_column: 7, + }, + ], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_24.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_24.snap new file mode 100644 index 000000000..6b4165f99 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_24.snap @@ -0,0 +1,131 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\"@deprecated((),\nschema A:\n a: \"#)" +--- +Module { + filename: "", + doc: None, + body: [ + Node { + node: Schema( + SchemaStmt { + doc: None, + name: Node { + node: "A", + filename: "", + line: 2, + column: 7, + end_line: 2, + end_column: 8, + }, + parent_name: None, + for_host_name: None, + is_mixin: false, + is_protocol: false, + args: None, + mixins: [], + body: [ + Node { + node: SchemaAttr( + SchemaAttr { + doc: "", + name: Node { + node: "a", + filename: "", + line: 3, + column: 4, + end_line: 3, + end_column: 5, + }, + op: None, + value: None, + is_optional: false, + decorators: [], + ty: Node { + node: Any, + filename: "", + line: 3, + column: 7, + end_line: 3, + end_column: 7, + }, + }, + ), + filename: "", + line: 3, + column: 4, + end_line: 3, + end_column: 7, + }, + ], + decorators: [ + Node { + node: CallExpr { + func: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "deprecated", + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 11, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 11, + }, + args: [ + Node { + node: Paren( + ParenExpr { + expr: Node { + node: Missing( + MissingExpr, + ), + filename: "", + line: 1, + column: 13, + end_line: 1, + end_column: 14, + }, + }, + ), + filename: "", + line: 1, + column: 12, + end_line: 1, + end_column: 14, + }, + ], + keywords: [], + }, + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 15, + }, + ], + checks: [], + index_signature: None, + }, + ), + filename: "", + line: 2, + column: 0, + end_line: 3, + end_column: 7, + }, + ], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_25.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_25.snap new file mode 100644 index 000000000..e857c6eef --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_25.snap @@ -0,0 +1,63 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\"\nschema A:\n check: \"#)" +--- +Module { + filename: "", + doc: None, + body: [ + Node { + node: Schema( + SchemaStmt { + doc: None, + name: Node { + node: "A", + filename: "", + line: 2, + column: 7, + end_line: 2, + end_column: 8, + }, + parent_name: None, + for_host_name: None, + is_mixin: false, + is_protocol: false, + args: None, + mixins: [], + body: [], + decorators: [], + checks: [ + Node { + node: CheckExpr { + test: Node { + node: Missing( + MissingExpr, + ), + filename: "", + line: 3, + column: 11, + end_line: 3, + end_column: 11, + }, + if_cond: None, + msg: None, + }, + filename: "", + line: 3, + column: 11, + end_line: 3, + end_column: 11, + }, + ], + index_signature: None, + }, + ), + filename: "", + line: 2, + column: 0, + end_line: 4, + end_column: 0, + }, + ], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_26.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_26.snap new file mode 100644 index 000000000..f95033e52 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_26.snap @@ -0,0 +1,84 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\"\nschema A:\n check: \n @\"#)" +--- +Module { + filename: "", + doc: None, + body: [ + Node { + node: Schema( + SchemaStmt { + doc: None, + name: Node { + node: "A", + filename: "", + line: 2, + column: 7, + end_line: 2, + end_column: 8, + }, + parent_name: None, + for_host_name: None, + is_mixin: false, + is_protocol: false, + args: None, + mixins: [], + body: [], + decorators: [], + checks: [ + Node { + node: CheckExpr { + test: Node { + node: Missing( + MissingExpr, + ), + filename: "", + line: 4, + column: 8, + end_line: 4, + end_column: 9, + }, + if_cond: None, + msg: None, + }, + filename: "", + line: 4, + column: 8, + end_line: 4, + end_column: 8, + }, + Node { + node: CheckExpr { + test: Node { + node: Missing( + MissingExpr, + ), + filename: "", + line: 4, + column: 9, + end_line: 4, + end_column: 9, + }, + if_cond: None, + msg: None, + }, + filename: "", + line: 4, + column: 9, + end_line: 4, + end_column: 9, + }, + ], + index_signature: None, + }, + ), + filename: "", + line: 2, + column: 0, + end_line: 4, + end_column: 9, + }, + ], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_27.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_27.snap new file mode 100644 index 000000000..76f1085d3 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_27.snap @@ -0,0 +1,145 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\"\nschema A:\n [.str]: str \"#)" +--- +Module { + filename: "", + doc: None, + body: [ + Node { + node: Schema( + SchemaStmt { + doc: None, + name: Node { + node: "A", + filename: "", + line: 2, + column: 7, + end_line: 2, + end_column: 8, + }, + parent_name: None, + for_host_name: None, + is_mixin: false, + is_protocol: false, + args: None, + mixins: [], + body: [ + Node { + node: Expr( + ExprStmt { + exprs: [ + Node { + node: Selector( + SelectorExpr { + value: Node { + node: Missing( + MissingExpr, + ), + filename: "", + line: 3, + column: 5, + end_line: 3, + end_column: 6, + }, + attr: Node { + node: Identifier { + names: [ + Node { + node: "str", + filename: "", + line: 3, + column: 6, + end_line: 3, + end_column: 9, + }, + ], + pkgpath: "", + ctx: Load, + }, + filename: "", + line: 3, + column: 6, + end_line: 3, + end_column: 9, + }, + ctx: Load, + has_question: false, + }, + ), + filename: "", + line: 3, + column: 5, + end_line: 3, + end_column: 9, + }, + ], + }, + ), + filename: "", + line: 3, + column: 5, + end_line: 3, + end_column: 9, + }, + Node { + node: Expr( + ExprStmt { + exprs: [ + Node { + node: Missing( + MissingExpr, + ), + filename: "", + line: 3, + column: 9, + end_line: 3, + end_column: 10, + }, + ], + }, + ), + filename: "", + line: 3, + column: 9, + end_line: 3, + end_column: 10, + }, + Node { + node: Expr( + ExprStmt { + exprs: [ + Node { + node: Missing( + MissingExpr, + ), + filename: "", + line: 3, + column: 16, + end_line: 3, + end_column: 16, + }, + ], + }, + ), + filename: "", + line: 3, + column: 16, + end_line: 3, + end_column: 16, + }, + ], + decorators: [], + checks: [], + index_signature: None, + }, + ), + filename: "", + line: 2, + column: 0, + end_line: 4, + end_column: 0, + }, + ], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_28.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_28.snap new file mode 100644 index 000000000..5f479243b --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_28.snap @@ -0,0 +1,168 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\"\nschema A:\n [....str]: str \"#)" +--- +Module { + filename: "", + doc: None, + body: [ + Node { + node: Schema( + SchemaStmt { + doc: None, + name: Node { + node: "A", + filename: "", + line: 2, + column: 7, + end_line: 2, + end_column: 8, + }, + parent_name: None, + for_host_name: None, + is_mixin: false, + is_protocol: false, + args: None, + mixins: [], + body: [ + Node { + node: Expr( + ExprStmt { + exprs: [ + Node { + node: Missing( + MissingExpr, + ), + filename: "", + line: 3, + column: 5, + end_line: 3, + end_column: 8, + }, + ], + }, + ), + filename: "", + line: 3, + column: 5, + end_line: 3, + end_column: 8, + }, + Node { + node: Expr( + ExprStmt { + exprs: [ + Node { + node: Selector( + SelectorExpr { + value: Node { + node: Missing( + MissingExpr, + ), + filename: "", + line: 3, + column: 8, + end_line: 3, + end_column: 9, + }, + attr: Node { + node: Identifier { + names: [ + Node { + node: "str", + filename: "", + line: 3, + column: 9, + end_line: 3, + end_column: 12, + }, + ], + pkgpath: "", + ctx: Load, + }, + filename: "", + line: 3, + column: 9, + end_line: 3, + end_column: 12, + }, + ctx: Load, + has_question: false, + }, + ), + filename: "", + line: 3, + column: 8, + end_line: 3, + end_column: 12, + }, + ], + }, + ), + filename: "", + line: 3, + column: 8, + end_line: 3, + end_column: 12, + }, + Node { + node: Expr( + ExprStmt { + exprs: [ + Node { + node: Missing( + MissingExpr, + ), + filename: "", + line: 3, + column: 12, + end_line: 3, + end_column: 13, + }, + ], + }, + ), + filename: "", + line: 3, + column: 12, + end_line: 3, + end_column: 13, + }, + Node { + node: Expr( + ExprStmt { + exprs: [ + Node { + node: Missing( + MissingExpr, + ), + filename: "", + line: 3, + column: 19, + end_line: 3, + end_column: 19, + }, + ], + }, + ), + filename: "", + line: 3, + column: 19, + end_line: 3, + end_column: 19, + }, + ], + decorators: [], + checks: [], + index_signature: None, + }, + ), + filename: "", + line: 2, + column: 0, + end_line: 4, + end_column: 0, + }, + ], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_29.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_29.snap new file mode 100644 index 000000000..62fc4f318 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_29.snap @@ -0,0 +1,74 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\"\nschema A:\n @\"#)" +--- +Module { + filename: "", + doc: None, + body: [ + Node { + node: Schema( + SchemaStmt { + doc: None, + name: Node { + node: "A", + filename: "", + line: 2, + column: 7, + end_line: 2, + end_column: 8, + }, + parent_name: None, + for_host_name: None, + is_mixin: false, + is_protocol: false, + args: None, + mixins: [], + body: [ + Node { + node: SchemaAttr( + SchemaAttr { + doc: "", + name: Node { + node: "", + filename: "", + line: 3, + column: 5, + end_line: 3, + end_column: 5, + }, + op: None, + value: None, + is_optional: false, + decorators: [], + ty: Node { + node: Any, + filename: "", + line: 3, + column: 5, + end_line: 3, + end_column: 5, + }, + }, + ), + filename: "", + line: 3, + column: 4, + end_line: 3, + end_column: 5, + }, + ], + decorators: [], + checks: [], + index_signature: None, + }, + ), + filename: "", + line: 2, + column: 0, + end_line: 4, + end_column: 0, + }, + ], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_3.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_3.snap new file mode 100644 index 000000000..81c47f096 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_3.snap @@ -0,0 +1,41 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\"schema A::\"#)" +--- +Module { + filename: "", + doc: None, + body: [ + Node { + node: Schema( + SchemaStmt { + doc: None, + name: Node { + node: "A", + filename: "", + line: 1, + column: 7, + end_line: 1, + end_column: 8, + }, + parent_name: None, + for_host_name: None, + is_mixin: false, + is_protocol: false, + args: None, + mixins: [], + body: [], + decorators: [], + checks: [], + index_signature: None, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 9, + }, + ], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_30.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_30.snap new file mode 100644 index 000000000..b16bcd28a --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_30.snap @@ -0,0 +1,99 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\"\nschema A:\n .\"#)" +--- +Module { + filename: "", + doc: None, + body: [ + Node { + node: Schema( + SchemaStmt { + doc: None, + name: Node { + node: "A", + filename: "", + line: 2, + column: 7, + end_line: 2, + end_column: 8, + }, + parent_name: None, + for_host_name: None, + is_mixin: false, + is_protocol: false, + args: None, + mixins: [], + body: [ + Node { + node: Expr( + ExprStmt { + exprs: [ + Node { + node: Selector( + SelectorExpr { + value: Node { + node: Missing( + MissingExpr, + ), + filename: "", + line: 3, + column: 4, + end_line: 3, + end_column: 5, + }, + attr: Node { + node: Identifier { + names: [ + Node { + node: "", + filename: "", + line: 3, + column: 5, + end_line: 3, + end_column: 5, + }, + ], + pkgpath: "", + ctx: Load, + }, + filename: "", + line: 3, + column: 5, + end_line: 3, + end_column: 5, + }, + ctx: Load, + has_question: false, + }, + ), + filename: "", + line: 3, + column: 4, + end_line: 3, + end_column: 5, + }, + ], + }, + ), + filename: "", + line: 3, + column: 4, + end_line: 3, + end_column: 5, + }, + ], + decorators: [], + checks: [], + index_signature: None, + }, + ), + filename: "", + line: 2, + column: 0, + end_line: 3, + end_column: 5, + }, + ], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_31.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_31.snap new file mode 100644 index 000000000..8b89cf890 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_31.snap @@ -0,0 +1,87 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\"\nschema A:\n [str]: str\n [str]: int\"#)" +--- +Module { + filename: "", + doc: None, + body: [ + Node { + node: Schema( + SchemaStmt { + doc: None, + name: Node { + node: "A", + filename: "", + line: 2, + column: 7, + end_line: 2, + end_column: 8, + }, + parent_name: None, + for_host_name: None, + is_mixin: false, + is_protocol: false, + args: None, + mixins: [], + body: [], + decorators: [], + checks: [], + index_signature: Some( + Node { + node: SchemaIndexSignature { + key_name: None, + value: None, + any_other: false, + key_ty: Node { + node: Named( + Identifier { + names: [ + Node { + node: "str", + filename: "", + line: 4, + column: 5, + end_line: 4, + end_column: 8, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 4, + column: 5, + end_line: 4, + end_column: 8, + }, + value_ty: Node { + node: Basic( + Int, + ), + filename: "", + line: 4, + column: 11, + end_line: 4, + end_column: 14, + }, + }, + filename: "", + line: 4, + column: 4, + end_line: 4, + end_column: 14, + }, + ), + }, + ), + filename: "", + line: 2, + column: 0, + end_line: 4, + end_column: 14, + }, + ], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_32.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_32.snap new file mode 100644 index 000000000..ecddecab0 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_32.snap @@ -0,0 +1,76 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\"\nschema A:\n \"attr\": str\"#)" +--- +Module { + filename: "", + doc: None, + body: [ + Node { + node: Schema( + SchemaStmt { + doc: None, + name: Node { + node: "A", + filename: "", + line: 2, + column: 7, + end_line: 2, + end_column: 8, + }, + parent_name: None, + for_host_name: None, + is_mixin: false, + is_protocol: false, + args: None, + mixins: [], + body: [ + Node { + node: SchemaAttr( + SchemaAttr { + doc: "", + name: Node { + node: "attr", + filename: "", + line: 3, + column: 4, + end_line: 3, + end_column: 10, + }, + op: None, + value: None, + is_optional: false, + decorators: [], + ty: Node { + node: Basic( + Str, + ), + filename: "", + line: 3, + column: 12, + end_line: 3, + end_column: 15, + }, + }, + ), + filename: "", + line: 3, + column: 4, + end_line: 3, + end_column: 15, + }, + ], + decorators: [], + checks: [], + index_signature: None, + }, + ), + filename: "", + line: 2, + column: 0, + end_line: 3, + end_column: 15, + }, + ], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_33.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_33.snap new file mode 100644 index 000000000..94699965b --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_33.snap @@ -0,0 +1,85 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\"\nschema A:\n \"\"\"Schema Doc\"\"\"\n \"attr\": str\"#)" +--- +Module { + filename: "", + doc: None, + body: [ + Node { + node: Schema( + SchemaStmt { + doc: Some( + Node { + node: "\"\"\"Schema Doc\"\"\"", + filename: "", + line: 3, + column: 4, + end_line: 3, + end_column: 20, + }, + ), + name: Node { + node: "A", + filename: "", + line: 2, + column: 7, + end_line: 2, + end_column: 8, + }, + parent_name: None, + for_host_name: None, + is_mixin: false, + is_protocol: false, + args: None, + mixins: [], + body: [ + Node { + node: SchemaAttr( + SchemaAttr { + doc: "", + name: Node { + node: "attr", + filename: "", + line: 4, + column: 4, + end_line: 4, + end_column: 10, + }, + op: None, + value: None, + is_optional: false, + decorators: [], + ty: Node { + node: Basic( + Str, + ), + filename: "", + line: 4, + column: 12, + end_line: 4, + end_column: 15, + }, + }, + ), + filename: "", + line: 4, + column: 4, + end_line: 4, + end_column: 15, + }, + ], + decorators: [], + checks: [], + index_signature: None, + }, + ), + filename: "", + line: 2, + column: 0, + end_line: 4, + end_column: 15, + }, + ], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_34.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_34.snap new file mode 100644 index 000000000..25d475bb9 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_34.snap @@ -0,0 +1,69 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\"\nschema A:\n \"attr: str\"#)" +--- +Module { + filename: "", + doc: None, + body: [ + Node { + node: Schema( + SchemaStmt { + doc: None, + name: Node { + node: "A", + filename: "", + line: 2, + column: 7, + end_line: 2, + end_column: 8, + }, + parent_name: None, + for_host_name: None, + is_mixin: false, + is_protocol: false, + args: None, + mixins: [], + body: [ + Node { + node: Expr( + ExprStmt { + exprs: [ + Node { + node: StringLit( + StringLit { + is_long_string: false, + raw_value: "\"attr: str", + value: "attr: str", + }, + ), + filename: "", + line: 3, + column: 4, + end_line: 3, + end_column: 14, + }, + ], + }, + ), + filename: "", + line: 3, + column: 4, + end_line: 3, + end_column: 14, + }, + ], + decorators: [], + checks: [], + index_signature: None, + }, + ), + filename: "", + line: 2, + column: 0, + end_line: 3, + end_column: 14, + }, + ], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_35.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_35.snap new file mode 100644 index 000000000..da25f67ba --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_35.snap @@ -0,0 +1,74 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\"\nschema A:\n \"attr\":\"#)" +--- +Module { + filename: "", + doc: None, + body: [ + Node { + node: Schema( + SchemaStmt { + doc: None, + name: Node { + node: "A", + filename: "", + line: 2, + column: 7, + end_line: 2, + end_column: 8, + }, + parent_name: None, + for_host_name: None, + is_mixin: false, + is_protocol: false, + args: None, + mixins: [], + body: [ + Node { + node: SchemaAttr( + SchemaAttr { + doc: "", + name: Node { + node: "attr", + filename: "", + line: 3, + column: 4, + end_line: 3, + end_column: 10, + }, + op: None, + value: None, + is_optional: false, + decorators: [], + ty: Node { + node: Any, + filename: "", + line: 3, + column: 11, + end_line: 3, + end_column: 11, + }, + }, + ), + filename: "", + line: 3, + column: 4, + end_line: 3, + end_column: 11, + }, + ], + decorators: [], + checks: [], + index_signature: None, + }, + ), + filename: "", + line: 2, + column: 0, + end_line: 3, + end_column: 11, + }, + ], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_36.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_36.snap new file mode 100644 index 000000000..f6a0910bb --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_36.snap @@ -0,0 +1,41 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\"\nschema A:\n mixin: \"#)" +--- +Module { + filename: "", + doc: None, + body: [ + Node { + node: Schema( + SchemaStmt { + doc: None, + name: Node { + node: "A", + filename: "", + line: 2, + column: 7, + end_line: 2, + end_column: 8, + }, + parent_name: None, + for_host_name: None, + is_mixin: false, + is_protocol: false, + args: None, + mixins: [], + body: [], + decorators: [], + checks: [], + index_signature: None, + }, + ), + filename: "", + line: 2, + column: 0, + end_line: 4, + end_column: 0, + }, + ], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_37.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_37.snap new file mode 100644 index 000000000..4d014d978 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_37.snap @@ -0,0 +1,84 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\"\nschema A:\n mixin: [\"#)" +--- +Module { + filename: "", + doc: None, + body: [ + Node { + node: Schema( + SchemaStmt { + doc: None, + name: Node { + node: "A", + filename: "", + line: 2, + column: 7, + end_line: 2, + end_column: 8, + }, + parent_name: None, + for_host_name: None, + is_mixin: false, + is_protocol: false, + args: None, + mixins: [ + Node { + node: Identifier { + names: [ + Node { + node: "", + filename: "", + line: 3, + column: 11, + end_line: 3, + end_column: 11, + }, + ], + pkgpath: "", + ctx: Load, + }, + filename: "", + line: 3, + column: 11, + end_line: 3, + end_column: 11, + }, + Node { + node: Identifier { + names: [ + Node { + node: "", + filename: "", + line: 3, + column: 12, + end_line: 3, + end_column: 12, + }, + ], + pkgpath: "", + ctx: Load, + }, + filename: "", + line: 3, + column: 12, + end_line: 3, + end_column: 12, + }, + ], + body: [], + decorators: [], + checks: [], + index_signature: None, + }, + ), + filename: "", + line: 2, + column: 0, + end_line: 4, + end_column: 0, + }, + ], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_38.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_38.snap new file mode 100644 index 000000000..a664c289e --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_38.snap @@ -0,0 +1,63 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\"\nschema A:\n mixin: []\"#)" +--- +Module { + filename: "", + doc: None, + body: [ + Node { + node: Schema( + SchemaStmt { + doc: None, + name: Node { + node: "A", + filename: "", + line: 2, + column: 7, + end_line: 2, + end_column: 8, + }, + parent_name: None, + for_host_name: None, + is_mixin: false, + is_protocol: false, + args: None, + mixins: [ + Node { + node: Identifier { + names: [ + Node { + node: "", + filename: "", + line: 3, + column: 11, + end_line: 3, + end_column: 11, + }, + ], + pkgpath: "", + ctx: Load, + }, + filename: "", + line: 3, + column: 11, + end_line: 3, + end_column: 11, + }, + ], + body: [], + decorators: [], + checks: [], + index_signature: None, + }, + ), + filename: "", + line: 2, + column: 0, + end_line: 3, + end_column: 13, + }, + ], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_39.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_39.snap new file mode 100644 index 000000000..d063f1e0f --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_39.snap @@ -0,0 +1,41 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\"\nschema A:\n mixin []\"#)" +--- +Module { + filename: "", + doc: None, + body: [ + Node { + node: Schema( + SchemaStmt { + doc: None, + name: Node { + node: "A", + filename: "", + line: 2, + column: 7, + end_line: 2, + end_column: 8, + }, + parent_name: None, + for_host_name: None, + is_mixin: false, + is_protocol: false, + args: None, + mixins: [], + body: [], + decorators: [], + checks: [], + index_signature: None, + }, + ), + filename: "", + line: 2, + column: 0, + end_line: 3, + end_column: 12, + }, + ], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_4.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_4.snap new file mode 100644 index 000000000..0d9173231 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_4.snap @@ -0,0 +1,77 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\"schema A:B\"#)" +--- +Module { + filename: "", + doc: None, + body: [ + Node { + node: Schema( + SchemaStmt { + doc: None, + name: Node { + node: "A", + filename: "", + line: 1, + column: 7, + end_line: 1, + end_column: 8, + }, + parent_name: None, + for_host_name: None, + is_mixin: false, + is_protocol: false, + args: None, + mixins: [], + body: [], + decorators: [], + checks: [], + index_signature: None, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 9, + }, + Node { + node: Expr( + ExprStmt { + exprs: [ + Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "B", + filename: "", + line: 1, + column: 9, + end_line: 1, + end_column: 10, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 9, + end_line: 1, + end_column: 10, + }, + ], + }, + ), + filename: "", + line: 1, + column: 9, + end_line: 1, + end_column: 10, + }, + ], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_40.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_40.snap new file mode 100644 index 000000000..76f050c8a --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_40.snap @@ -0,0 +1,41 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\"\nschema A:\n mixin [\"#)" +--- +Module { + filename: "", + doc: None, + body: [ + Node { + node: Schema( + SchemaStmt { + doc: None, + name: Node { + node: "A", + filename: "", + line: 2, + column: 7, + end_line: 2, + end_column: 8, + }, + parent_name: None, + for_host_name: None, + is_mixin: false, + is_protocol: false, + args: None, + mixins: [], + body: [], + decorators: [], + checks: [], + index_signature: None, + }, + ), + filename: "", + line: 2, + column: 0, + end_line: 4, + end_column: 0, + }, + ], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_5.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_5.snap new file mode 100644 index 000000000..c0f19a73e --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_5.snap @@ -0,0 +1,63 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\"schema A(:\"#)" +--- +Module { + filename: "", + doc: None, + body: [ + Node { + node: Schema( + SchemaStmt { + doc: None, + name: Node { + node: "A", + filename: "", + line: 1, + column: 7, + end_line: 1, + end_column: 8, + }, + parent_name: Some( + Node { + node: Identifier { + names: [ + Node { + node: "", + filename: "", + line: 1, + column: 9, + end_line: 1, + end_column: 9, + }, + ], + pkgpath: "", + ctx: Load, + }, + filename: "", + line: 1, + column: 9, + end_line: 1, + end_column: 9, + }, + ), + for_host_name: None, + is_mixin: false, + is_protocol: false, + args: None, + mixins: [], + body: [], + decorators: [], + checks: [], + index_signature: None, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 10, + }, + ], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_6.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_6.snap new file mode 100644 index 000000000..f7d1e7d10 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_6.snap @@ -0,0 +1,63 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\"schema A():\"#)" +--- +Module { + filename: "", + doc: None, + body: [ + Node { + node: Schema( + SchemaStmt { + doc: None, + name: Node { + node: "A", + filename: "", + line: 1, + column: 7, + end_line: 1, + end_column: 8, + }, + parent_name: Some( + Node { + node: Identifier { + names: [ + Node { + node: "", + filename: "", + line: 1, + column: 9, + end_line: 1, + end_column: 9, + }, + ], + pkgpath: "", + ctx: Load, + }, + filename: "", + line: 1, + column: 9, + end_line: 1, + end_column: 9, + }, + ), + for_host_name: None, + is_mixin: false, + is_protocol: false, + args: None, + mixins: [], + body: [], + decorators: [], + checks: [], + index_signature: None, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 11, + }, + ], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_7.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_7.snap new file mode 100644 index 000000000..b79287b21 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_7.snap @@ -0,0 +1,129 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\"schema A:\na:: int\"#)" +--- +Module { + filename: "", + doc: None, + body: [ + Node { + node: Schema( + SchemaStmt { + doc: None, + name: Node { + node: "A", + filename: "", + line: 1, + column: 7, + end_line: 1, + end_column: 8, + }, + parent_name: None, + for_host_name: None, + is_mixin: false, + is_protocol: false, + args: None, + mixins: [], + body: [], + decorators: [], + checks: [], + index_signature: None, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 2, + end_column: 0, + }, + Node { + node: Assign( + AssignStmt { + targets: [ + Node { + node: Target { + name: Node { + node: "a", + filename: "", + line: 2, + column: 0, + end_line: 2, + end_column: 1, + }, + paths: [], + pkgpath: "", + }, + filename: "", + line: 2, + column: 0, + end_line: 2, + end_column: 1, + }, + ], + value: Node { + node: Missing( + MissingExpr, + ), + filename: "", + line: 2, + column: 4, + end_line: 2, + end_column: 7, + }, + ty: Some( + Node { + node: Any, + filename: "", + line: 2, + column: 2, + end_line: 2, + end_column: 3, + }, + ), + }, + ), + filename: "", + line: 2, + column: 0, + end_line: 2, + end_column: 1, + }, + Node { + node: Expr( + ExprStmt { + exprs: [ + Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "int", + filename: "", + line: 2, + column: 4, + end_line: 2, + end_column: 7, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 2, + column: 4, + end_line: 2, + end_column: 7, + }, + ], + }, + ), + filename: "", + line: 2, + column: 4, + end_line: 2, + end_column: 7, + }, + ], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_8.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_8.snap new file mode 100644 index 000000000..696794612 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_8.snap @@ -0,0 +1,95 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\"schema A:\na: int =\"#)" +--- +Module { + filename: "", + doc: None, + body: [ + Node { + node: Schema( + SchemaStmt { + doc: None, + name: Node { + node: "A", + filename: "", + line: 1, + column: 7, + end_line: 1, + end_column: 8, + }, + parent_name: None, + for_host_name: None, + is_mixin: false, + is_protocol: false, + args: None, + mixins: [], + body: [], + decorators: [], + checks: [], + index_signature: None, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 2, + end_column: 0, + }, + Node { + node: Assign( + AssignStmt { + targets: [ + Node { + node: Target { + name: Node { + node: "a", + filename: "", + line: 2, + column: 0, + end_line: 2, + end_column: 1, + }, + paths: [], + pkgpath: "", + }, + filename: "", + line: 2, + column: 0, + end_line: 2, + end_column: 1, + }, + ], + value: Node { + node: Missing( + MissingExpr, + ), + filename: "", + line: 2, + column: 8, + end_line: 2, + end_column: 8, + }, + ty: Some( + Node { + node: Basic( + Int, + ), + filename: "", + line: 2, + column: 3, + end_line: 2, + end_column: 6, + }, + ), + }, + ), + filename: "", + line: 2, + column: 0, + end_line: 2, + end_column: 8, + }, + ], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_9.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_9.snap new file mode 100644 index 000000000..b6722c4e9 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_9.snap @@ -0,0 +1,77 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\"schema A:\n[]: []\"#)" +--- +Module { + filename: "", + doc: None, + body: [ + Node { + node: Schema( + SchemaStmt { + doc: None, + name: Node { + node: "A", + filename: "", + line: 1, + column: 7, + end_line: 1, + end_column: 8, + }, + parent_name: None, + for_host_name: None, + is_mixin: false, + is_protocol: false, + args: None, + mixins: [], + body: [], + decorators: [], + checks: [], + index_signature: None, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 2, + end_column: 0, + }, + Node { + node: Assign( + AssignStmt { + targets: [], + value: Node { + node: Missing( + MissingExpr, + ), + filename: "", + line: 2, + column: 6, + end_line: 2, + end_column: 6, + }, + ty: Some( + Node { + node: List( + ListType { + inner_type: None, + }, + ), + filename: "", + line: 2, + column: 4, + end_line: 2, + end_column: 6, + }, + ), + }, + ), + filename: "", + line: 2, + column: 0, + end_line: 2, + end_column: 2, + }, + ], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__select_recovery_0.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__select_recovery_0.snap new file mode 100644 index 000000000..bbe003c51 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__select_recovery_0.snap @@ -0,0 +1,36 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(r#\"a.\"#)" +--- +Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + Node { + node: "", + filename: "", + line: 1, + column: 2, + end_line: 1, + end_column: 2, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 2, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__select_recovery_1.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__select_recovery_1.snap new file mode 100644 index 000000000..97847cd0c --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__select_recovery_1.snap @@ -0,0 +1,44 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(r#\"a.b.\"#)" +--- +Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + Node { + node: "b", + filename: "", + line: 1, + column: 2, + end_line: 1, + end_column: 3, + }, + Node { + node: "", + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 4, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 4, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__select_recovery_10.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__select_recovery_10.snap new file mode 100644 index 000000000..35c0b2f28 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__select_recovery_10.snap @@ -0,0 +1,62 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(r#\"a?.b?\"#)" +--- +Node { + node: Selector( + SelectorExpr { + value: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + attr: Node { + node: Identifier { + names: [ + Node { + node: "b", + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 4, + }, + ], + pkgpath: "", + ctx: Load, + }, + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 4, + }, + ctx: Load, + has_question: true, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 4, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__select_recovery_11.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__select_recovery_11.snap new file mode 100644 index 000000000..615b8a3db --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__select_recovery_11.snap @@ -0,0 +1,96 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(r#\"a?.b?.c?\"#)" +--- +Node { + node: Selector( + SelectorExpr { + value: Node { + node: Selector( + SelectorExpr { + value: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + attr: Node { + node: Identifier { + names: [ + Node { + node: "b", + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 4, + }, + ], + pkgpath: "", + ctx: Load, + }, + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 4, + }, + ctx: Load, + has_question: true, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 4, + }, + attr: Node { + node: Identifier { + names: [ + Node { + node: "c", + filename: "", + line: 1, + column: 6, + end_line: 1, + end_column: 7, + }, + ], + pkgpath: "", + ctx: Load, + }, + filename: "", + line: 1, + column: 6, + end_line: 1, + end_column: 7, + }, + ctx: Load, + has_question: true, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 7, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__select_recovery_12.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__select_recovery_12.snap new file mode 100644 index 000000000..7deefffd2 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__select_recovery_12.snap @@ -0,0 +1,36 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(r#\"a.0\"#)" +--- +Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + Node { + node: "", + filename: "", + line: 1, + column: 2, + end_line: 1, + end_column: 2, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 2, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__select_recovery_13.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__select_recovery_13.snap new file mode 100644 index 000000000..0f7564c77 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__select_recovery_13.snap @@ -0,0 +1,44 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(r#\"a..0\"#)" +--- +Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + Node { + node: "", + filename: "", + line: 1, + column: 2, + end_line: 1, + end_column: 2, + }, + Node { + node: "", + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 3, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 3, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__select_recovery_14.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__select_recovery_14.snap new file mode 100644 index 000000000..9a683650f --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__select_recovery_14.snap @@ -0,0 +1,28 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(r#\"a...\"#)" +--- +Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__select_recovery_2.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__select_recovery_2.snap new file mode 100644 index 000000000..ad5c2dd8d --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__select_recovery_2.snap @@ -0,0 +1,52 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(r#\"a.b.c.\"#)" +--- +Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + Node { + node: "b", + filename: "", + line: 1, + column: 2, + end_line: 1, + end_column: 3, + }, + Node { + node: "c", + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 5, + }, + Node { + node: "", + filename: "", + line: 1, + column: 6, + end_line: 1, + end_column: 6, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 6, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__select_recovery_3.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__select_recovery_3.snap new file mode 100644 index 000000000..992848968 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__select_recovery_3.snap @@ -0,0 +1,53 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(r#\"''.\"#)" +--- +Node { + node: Selector( + SelectorExpr { + value: Node { + node: StringLit( + StringLit { + is_long_string: false, + raw_value: "''", + value: "", + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 2, + }, + attr: Node { + node: Identifier { + names: [ + Node { + node: "", + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 3, + }, + ], + pkgpath: "", + ctx: Load, + }, + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 3, + }, + ctx: Load, + has_question: false, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 3, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__select_recovery_4.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__select_recovery_4.snap new file mode 100644 index 000000000..45ff29d11 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__select_recovery_4.snap @@ -0,0 +1,53 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(r#\"''.lower\"#)" +--- +Node { + node: Selector( + SelectorExpr { + value: Node { + node: StringLit( + StringLit { + is_long_string: false, + raw_value: "''", + value: "", + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 2, + }, + attr: Node { + node: Identifier { + names: [ + Node { + node: "lower", + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 8, + }, + ], + pkgpath: "", + ctx: Load, + }, + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 8, + }, + ctx: Load, + has_question: false, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 8, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__select_recovery_5.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__select_recovery_5.snap new file mode 100644 index 000000000..484388876 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__select_recovery_5.snap @@ -0,0 +1,100 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(r#\"''.lower().\"#)" +--- +Node { + node: Selector( + SelectorExpr { + value: Node { + node: Call( + CallExpr { + func: Node { + node: Selector( + SelectorExpr { + value: Node { + node: StringLit( + StringLit { + is_long_string: false, + raw_value: "''", + value: "", + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 2, + }, + attr: Node { + node: Identifier { + names: [ + Node { + node: "lower", + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 8, + }, + ], + pkgpath: "", + ctx: Load, + }, + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 8, + }, + ctx: Load, + has_question: false, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 8, + }, + args: [], + keywords: [], + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 10, + }, + attr: Node { + node: Identifier { + names: [ + Node { + node: "", + filename: "", + line: 1, + column: 11, + end_line: 1, + end_column: 11, + }, + ], + pkgpath: "", + ctx: Load, + }, + filename: "", + line: 1, + column: 11, + end_line: 1, + end_column: 11, + }, + ctx: Load, + has_question: false, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 11, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__select_recovery_6.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__select_recovery_6.snap new file mode 100644 index 000000000..675b0e19b --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__select_recovery_6.snap @@ -0,0 +1,62 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(r#\"a?.\"#)" +--- +Node { + node: Selector( + SelectorExpr { + value: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + attr: Node { + node: Identifier { + names: [ + Node { + node: "", + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 3, + }, + ], + pkgpath: "", + ctx: Load, + }, + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 3, + }, + ctx: Load, + has_question: true, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 3, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__select_recovery_7.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__select_recovery_7.snap new file mode 100644 index 000000000..20d302127 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__select_recovery_7.snap @@ -0,0 +1,96 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(r#\"a?.b?.\"#)" +--- +Node { + node: Selector( + SelectorExpr { + value: Node { + node: Selector( + SelectorExpr { + value: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + attr: Node { + node: Identifier { + names: [ + Node { + node: "b", + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 4, + }, + ], + pkgpath: "", + ctx: Load, + }, + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 4, + }, + ctx: Load, + has_question: true, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 4, + }, + attr: Node { + node: Identifier { + names: [ + Node { + node: "", + filename: "", + line: 1, + column: 6, + end_line: 1, + end_column: 6, + }, + ], + pkgpath: "", + ctx: Load, + }, + filename: "", + line: 1, + column: 6, + end_line: 1, + end_column: 6, + }, + ctx: Load, + has_question: true, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 6, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__select_recovery_8.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__select_recovery_8.snap new file mode 100644 index 000000000..202dd5709 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__select_recovery_8.snap @@ -0,0 +1,130 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(r#\"a?.b?.c?.\"#)" +--- +Node { + node: Selector( + SelectorExpr { + value: Node { + node: Selector( + SelectorExpr { + value: Node { + node: Selector( + SelectorExpr { + value: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + attr: Node { + node: Identifier { + names: [ + Node { + node: "b", + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 4, + }, + ], + pkgpath: "", + ctx: Load, + }, + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 4, + }, + ctx: Load, + has_question: true, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 4, + }, + attr: Node { + node: Identifier { + names: [ + Node { + node: "c", + filename: "", + line: 1, + column: 6, + end_line: 1, + end_column: 7, + }, + ], + pkgpath: "", + ctx: Load, + }, + filename: "", + line: 1, + column: 6, + end_line: 1, + end_column: 7, + }, + ctx: Load, + has_question: true, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 7, + }, + attr: Node { + node: Identifier { + names: [ + Node { + node: "", + filename: "", + line: 1, + column: 9, + end_line: 1, + end_column: 9, + }, + ], + pkgpath: "", + ctx: Load, + }, + filename: "", + line: 1, + column: 9, + end_line: 1, + end_column: 9, + }, + ctx: Load, + has_question: true, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 9, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__select_recovery_9.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__select_recovery_9.snap new file mode 100644 index 000000000..25cc39e66 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__select_recovery_9.snap @@ -0,0 +1,28 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(r#\"a?\"#)" +--- +Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__string_literal_recovery_0.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__string_literal_recovery_0.snap new file mode 100644 index 000000000..25c936d5b --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__string_literal_recovery_0.snap @@ -0,0 +1,20 @@ +--- +source: parser/src/tests/error_recovery.rs +assertion_line: 3 +expression: "crate::tests::parsing_expr_string(\"'abc\")" +--- +Node { + node: StringLit( + StringLit { + is_long_string: false, + raw_value: "'abc", + value: "abc", + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 4, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__string_literal_recovery_1.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__string_literal_recovery_1.snap new file mode 100644 index 000000000..ce6535974 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__string_literal_recovery_1.snap @@ -0,0 +1,20 @@ +--- +source: parser/src/tests/error_recovery.rs +assertion_line: 4 +expression: "crate::tests::parsing_expr_string(\"r'abc\")" +--- +Node { + node: StringLit( + StringLit { + is_long_string: false, + raw_value: "r'abc", + value: "abc", + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 5, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__string_literal_recovery_2.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__string_literal_recovery_2.snap new file mode 100644 index 000000000..fce74020f --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__string_literal_recovery_2.snap @@ -0,0 +1,20 @@ +--- +source: parser/src/tests/error_recovery.rs +assertion_line: 5 +expression: "crate::tests::parsing_expr_string(\"'''abc\")" +--- +Node { + node: StringLit( + StringLit { + is_long_string: false, + raw_value: "'''abc", + value: "''abc", + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 6, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__string_literal_recovery_3.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__string_literal_recovery_3.snap new file mode 100644 index 000000000..03c0aa2e3 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__string_literal_recovery_3.snap @@ -0,0 +1,20 @@ +--- +source: parser/src/tests/error_recovery.rs +assertion_line: 6 +expression: "crate::tests::parsing_expr_string(\"r'''abc\")" +--- +Node { + node: StringLit( + StringLit { + is_long_string: false, + raw_value: "r'''abc", + value: "''abc", + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 7, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__string_literal_recovery_4.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__string_literal_recovery_4.snap new file mode 100644 index 000000000..55f2ad0c0 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__string_literal_recovery_4.snap @@ -0,0 +1,20 @@ +--- +source: parser/src/tests/error_recovery.rs +assertion_line: 7 +expression: "crate::tests::parsing_expr_string(\"r''abc'\")" +--- +Node { + node: StringLit( + StringLit { + is_long_string: false, + raw_value: "r''", + value: "", + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 3, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__string_literal_recovery_5.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__string_literal_recovery_5.snap new file mode 100644 index 000000000..83b1e9728 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__string_literal_recovery_5.snap @@ -0,0 +1,20 @@ +--- +source: parser/src/tests/error_recovery.rs +assertion_line: 8 +expression: "crate::tests::parsing_expr_string(\"'\")" +--- +Node { + node: StringLit( + StringLit { + is_long_string: false, + raw_value: "'", + value: "", + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__string_literal_recovery_6.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__string_literal_recovery_6.snap new file mode 100644 index 000000000..2d74a5ec0 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__string_literal_recovery_6.snap @@ -0,0 +1,20 @@ +--- +source: parser/src/tests/error_recovery.rs +assertion_line: 9 +expression: "crate::tests::parsing_expr_string(\"'''\")" +--- +Node { + node: StringLit( + StringLit { + is_long_string: false, + raw_value: "'''", + value: "''", + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 3, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__string_literal_recovery_7.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__string_literal_recovery_7.snap new file mode 100644 index 000000000..6f68ad175 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__string_literal_recovery_7.snap @@ -0,0 +1,20 @@ +--- +source: parser/src/tests/error_recovery.rs +assertion_line: 10 +expression: "crate::tests::parsing_expr_string(\"'\\n\")" +--- +Node { + node: StringLit( + StringLit { + is_long_string: false, + raw_value: "'\n", + value: "", + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 2, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__string_literal_recovery_8.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__string_literal_recovery_8.snap new file mode 100644 index 000000000..5f96fc52f --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__string_literal_recovery_8.snap @@ -0,0 +1,20 @@ +--- +source: parser/src/tests/error_recovery.rs +assertion_line: 11 +expression: "crate::tests::parsing_expr_string(\"r'abc\\n\")" +--- +Node { + node: StringLit( + StringLit { + is_long_string: false, + raw_value: "r'abc", + value: "abc", + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 5, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__subscript_recovery_0.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__subscript_recovery_0.snap new file mode 100644 index 000000000..7acd7bdf8 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__subscript_recovery_0.snap @@ -0,0 +1,61 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(r#\"a[b 1]\"#)" +--- +Node { + node: Subscript( + Subscript { + value: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + index: Some( + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 1, + ), + }, + ), + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 5, + }, + ), + lower: None, + upper: None, + step: None, + ctx: Load, + has_question: false, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 6, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__subscript_recovery_1.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__subscript_recovery_1.snap new file mode 100644 index 000000000..6877c8670 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__subscript_recovery_1.snap @@ -0,0 +1,56 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(r#\"a[1,b]\"#)" +--- +Node { + node: Subscript( + Subscript { + value: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + index: Some( + Node { + node: Missing( + MissingExpr, + ), + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 4, + }, + ), + lower: None, + upper: None, + step: None, + ctx: Load, + has_question: false, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 3, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__subscript_recovery_10.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__subscript_recovery_10.snap new file mode 100644 index 000000000..c0b5ac715 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__subscript_recovery_10.snap @@ -0,0 +1,101 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(r#\"[0]?.[0]\"#)" +--- +Node { + node: Subscript( + Subscript { + value: Node { + node: Selector( + SelectorExpr { + value: Node { + node: List( + ListExpr { + elts: [ + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 0, + ), + }, + ), + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 2, + }, + ], + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 3, + }, + attr: Node { + node: Identifier { + names: [ + Node { + node: "", + filename: "", + line: 1, + column: 5, + end_line: 1, + end_column: 5, + }, + ], + pkgpath: "", + ctx: Load, + }, + filename: "", + line: 1, + column: 5, + end_line: 1, + end_column: 5, + }, + ctx: Load, + has_question: true, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 5, + }, + index: Some( + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 0, + ), + }, + ), + filename: "", + line: 1, + column: 6, + end_line: 1, + end_column: 7, + }, + ), + lower: None, + upper: None, + step: None, + ctx: Load, + has_question: false, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 8, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__subscript_recovery_11.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__subscript_recovery_11.snap new file mode 100644 index 000000000..5ac61db4d --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__subscript_recovery_11.snap @@ -0,0 +1,35 @@ +--- +source: parser/src/tests/error_recovery.rs +assertion_line: 95 +expression: "crate::tests::parsing_expr_string(r#\"[0]??[0]\"#)" +--- +Node { + node: List( + ListExpr { + elts: [ + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 0, + ), + }, + ), + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 2, + }, + ], + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 3, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__subscript_recovery_12.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__subscript_recovery_12.snap new file mode 100644 index 000000000..d68841a4b --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__subscript_recovery_12.snap @@ -0,0 +1,101 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(r#\"[0].?[0]\"#)" +--- +Node { + node: Subscript( + Subscript { + value: Node { + node: Selector( + SelectorExpr { + value: Node { + node: List( + ListExpr { + elts: [ + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 0, + ), + }, + ), + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 2, + }, + ], + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 3, + }, + attr: Node { + node: Identifier { + names: [ + Node { + node: "", + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 4, + }, + ], + pkgpath: "", + ctx: Load, + }, + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 4, + }, + ctx: Load, + has_question: false, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 4, + }, + index: Some( + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 0, + ), + }, + ), + filename: "", + line: 1, + column: 6, + end_line: 1, + end_column: 7, + }, + ), + lower: None, + upper: None, + step: None, + ctx: Load, + has_question: true, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 8, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__subscript_recovery_2.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__subscript_recovery_2.snap new file mode 100644 index 000000000..034165107 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__subscript_recovery_2.snap @@ -0,0 +1,69 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(r#\"a[b;;b]\"#)" +--- +Node { + node: Subscript( + Subscript { + value: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + index: Some( + Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "b", + filename: "", + line: 1, + column: 5, + end_line: 1, + end_column: 6, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 5, + end_line: 1, + end_column: 6, + }, + ), + lower: None, + upper: None, + step: None, + ctx: Load, + has_question: false, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 7, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__subscript_recovery_3.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__subscript_recovery_3.snap new file mode 100644 index 000000000..6e6a2f491 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__subscript_recovery_3.snap @@ -0,0 +1,56 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(r#\"a[b[b]\"#)" +--- +Node { + node: Subscript( + Subscript { + value: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + index: Some( + Node { + node: Missing( + MissingExpr, + ), + filename: "", + line: 1, + column: 6, + end_line: 1, + end_column: 6, + }, + ), + lower: None, + upper: None, + step: None, + ctx: Load, + has_question: false, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 6, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__subscript_recovery_4.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__subscript_recovery_4.snap new file mode 100644 index 000000000..53b3104ed --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__subscript_recovery_4.snap @@ -0,0 +1,45 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(r#\"a[:::]\"#)" +--- +Node { + node: Subscript( + Subscript { + value: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + index: None, + lower: None, + upper: None, + step: None, + ctx: Load, + has_question: false, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 6, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__subscript_recovery_5.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__subscript_recovery_5.snap new file mode 100644 index 000000000..45d2cd7cc --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__subscript_recovery_5.snap @@ -0,0 +1,77 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(r#\"a[:1:2:]\"#)" +--- +Node { + node: Subscript( + Subscript { + value: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + index: None, + lower: None, + upper: Some( + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 1, + ), + }, + ), + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 4, + }, + ), + step: Some( + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 2, + ), + }, + ), + filename: "", + line: 1, + column: 5, + end_line: 1, + end_column: 6, + }, + ), + ctx: Load, + has_question: false, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 8, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__subscript_recovery_6.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__subscript_recovery_6.snap new file mode 100644 index 000000000..b250a5626 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__subscript_recovery_6.snap @@ -0,0 +1,107 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(r#\"[][a:b:c:d]\"#)" +--- +Node { + node: Subscript( + Subscript { + value: Node { + node: List( + ListExpr { + elts: [], + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 2, + }, + index: None, + lower: Some( + Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 4, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 4, + }, + ), + upper: Some( + Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "b", + filename: "", + line: 1, + column: 5, + end_line: 1, + end_column: 6, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 5, + end_line: 1, + end_column: 6, + }, + ), + step: Some( + Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "c", + filename: "", + line: 1, + column: 7, + end_line: 1, + end_column: 8, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 7, + end_line: 1, + end_column: 8, + }, + ), + ctx: Load, + has_question: false, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 8, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__subscript_recovery_7.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__subscript_recovery_7.snap new file mode 100644 index 000000000..f9a7d62fc --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__subscript_recovery_7.snap @@ -0,0 +1,36 @@ +--- +source: parser/src/tests/error_recovery.rs +assertion_line: 116 +expression: "crate::tests::parsing_expr_string(r#\"[][]\"#)" +--- +Node { + node: Subscript( + Subscript { + value: Node { + node: List( + ListExpr { + elts: [], + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 2, + }, + index: None, + lower: None, + upper: None, + step: None, + ctx: Load, + has_question: false, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 4, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__subscript_recovery_8.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__subscript_recovery_8.snap new file mode 100644 index 000000000..5959e1822 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__subscript_recovery_8.snap @@ -0,0 +1,53 @@ +--- +source: parser/src/tests/error_recovery.rs +assertion_line: 117 +expression: "crate::tests::parsing_expr_string(r#\"[][][]\"#)" +--- +Node { + node: Subscript( + Subscript { + value: Node { + node: Subscript( + Subscript { + value: Node { + node: List( + ListExpr { + elts: [], + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 2, + }, + index: None, + lower: None, + upper: None, + step: None, + ctx: Load, + has_question: false, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 4, + }, + index: None, + lower: None, + upper: None, + step: None, + ctx: Load, + has_question: false, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 6, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__subscript_recovery_9.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__subscript_recovery_9.snap new file mode 100644 index 000000000..bd84fee9d --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__subscript_recovery_9.snap @@ -0,0 +1,36 @@ +--- +source: parser/src/tests/error_recovery.rs +assertion_line: 118 +expression: "crate::tests::parsing_expr_string(r#\"[]?[]\"#)" +--- +Node { + node: Subscript( + Subscript { + value: Node { + node: List( + ListExpr { + elts: [], + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 2, + }, + index: None, + lower: None, + upper: None, + step: None, + ctx: Load, + has_question: true, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 5, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__type_alias_recovery_0.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__type_alias_recovery_0.snap new file mode 100644 index 000000000..47c1b7a74 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__type_alias_recovery_0.snap @@ -0,0 +1,50 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\"type\"#)" +--- +Module { + filename: "", + doc: None, + body: [ + Node { + node: TypeAlias( + TypeAliasStmt { + type_name: Node { + node: Identifier { + names: [], + pkgpath: "", + ctx: Load, + }, + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 4, + }, + type_value: Node { + node: "any", + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 4, + }, + ty: Node { + node: Any, + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 4, + }, + }, + ), + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 4, + }, + ], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__type_alias_recovery_1.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__type_alias_recovery_1.snap new file mode 100644 index 000000000..e7f6a3b7d --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__type_alias_recovery_1.snap @@ -0,0 +1,50 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\"type 'pkg_path'\"#)" +--- +Module { + filename: "", + doc: None, + body: [ + Node { + node: TypeAlias( + TypeAliasStmt { + type_name: Node { + node: Identifier { + names: [], + pkgpath: "", + ctx: Load, + }, + filename: "", + line: 1, + column: 5, + end_line: 1, + end_column: 15, + }, + type_value: Node { + node: "any", + filename: "", + line: 1, + column: 15, + end_line: 1, + end_column: 15, + }, + ty: Node { + node: Any, + filename: "", + line: 1, + column: 15, + end_line: 1, + end_column: 15, + }, + }, + ), + filename: "", + line: 1, + column: 5, + end_line: 1, + end_column: 15, + }, + ], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__type_alias_recovery_2.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__type_alias_recovery_2.snap new file mode 100644 index 000000000..df48fb9e0 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__type_alias_recovery_2.snap @@ -0,0 +1,67 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\"type pkg_path.\"#)" +--- +Module { + filename: "", + doc: None, + body: [ + Node { + node: TypeAlias( + TypeAliasStmt { + type_name: Node { + node: Identifier { + names: [ + Node { + node: "pkg_path", + filename: "", + line: 1, + column: 5, + end_line: 1, + end_column: 13, + }, + Node { + node: "", + filename: "", + line: 1, + column: 14, + end_line: 1, + end_column: 14, + }, + ], + pkgpath: "", + ctx: Load, + }, + filename: "", + line: 1, + column: 5, + end_line: 1, + end_column: 14, + }, + type_value: Node { + node: "any", + filename: "", + line: 1, + column: 14, + end_line: 1, + end_column: 14, + }, + ty: Node { + node: Any, + filename: "", + line: 1, + column: 14, + end_line: 1, + end_column: 14, + }, + }, + ), + filename: "", + line: 1, + column: 5, + end_line: 1, + end_column: 14, + }, + ], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__type_alias_recovery_3.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__type_alias_recovery_3.snap new file mode 100644 index 000000000..eec7060a9 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__type_alias_recovery_3.snap @@ -0,0 +1,50 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\"type pkg_path[0]\"#)" +--- +Module { + filename: "", + doc: None, + body: [ + Node { + node: TypeAlias( + TypeAliasStmt { + type_name: Node { + node: Identifier { + names: [], + pkgpath: "", + ctx: Load, + }, + filename: "", + line: 1, + column: 5, + end_line: 1, + end_column: 16, + }, + type_value: Node { + node: "any", + filename: "", + line: 1, + column: 16, + end_line: 1, + end_column: 16, + }, + ty: Node { + node: Any, + filename: "", + line: 1, + column: 16, + end_line: 1, + end_column: 16, + }, + }, + ), + filename: "", + line: 1, + column: 5, + end_line: 1, + end_column: 16, + }, + ], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__type_alias_recovery_4.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__type_alias_recovery_4.snap new file mode 100644 index 000000000..bfb604958 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__type_alias_recovery_4.snap @@ -0,0 +1,50 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\"type .pkg_path.\"#)" +--- +Module { + filename: "", + doc: None, + body: [ + Node { + node: TypeAlias( + TypeAliasStmt { + type_name: Node { + node: Identifier { + names: [], + pkgpath: "", + ctx: Load, + }, + filename: "", + line: 1, + column: 5, + end_line: 1, + end_column: 15, + }, + type_value: Node { + node: "any", + filename: "", + line: 1, + column: 15, + end_line: 1, + end_column: 15, + }, + ty: Node { + node: Any, + filename: "", + line: 1, + column: 15, + end_line: 1, + end_column: 15, + }, + }, + ), + filename: "", + line: 1, + column: 5, + end_line: 1, + end_column: 15, + }, + ], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__type_alias_recovery_5.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__type_alias_recovery_5.snap new file mode 100644 index 000000000..897aa29b2 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__type_alias_recovery_5.snap @@ -0,0 +1,59 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\"type pkg_path = \"#)" +--- +Module { + filename: "", + doc: None, + body: [ + Node { + node: TypeAlias( + TypeAliasStmt { + type_name: Node { + node: Identifier { + names: [ + Node { + node: "pkg_path", + filename: "", + line: 1, + column: 5, + end_line: 1, + end_column: 13, + }, + ], + pkgpath: "", + ctx: Load, + }, + filename: "", + line: 1, + column: 5, + end_line: 1, + end_column: 13, + }, + type_value: Node { + node: "any", + filename: "", + line: 1, + column: 16, + end_line: 1, + end_column: 16, + }, + ty: Node { + node: Any, + filename: "", + line: 1, + column: 16, + end_line: 1, + end_column: 16, + }, + }, + ), + filename: "", + line: 1, + column: 5, + end_line: 1, + end_column: 16, + }, + ], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__type_alias_recovery_6.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__type_alias_recovery_6.snap new file mode 100644 index 000000000..895de4613 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__type_alias_recovery_6.snap @@ -0,0 +1,63 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\"type pkg_path = 'data'\"#)" +--- +Module { + filename: "", + doc: None, + body: [ + Node { + node: TypeAlias( + TypeAliasStmt { + type_name: Node { + node: Identifier { + names: [ + Node { + node: "pkg_path", + filename: "", + line: 1, + column: 5, + end_line: 1, + end_column: 13, + }, + ], + pkgpath: "", + ctx: Load, + }, + filename: "", + line: 1, + column: 5, + end_line: 1, + end_column: 13, + }, + type_value: Node { + node: "\"data\"", + filename: "", + line: 1, + column: 16, + end_line: 1, + end_column: 22, + }, + ty: Node { + node: Literal( + Str( + "data", + ), + ), + filename: "", + line: 1, + column: 16, + end_line: 1, + end_column: 22, + }, + }, + ), + filename: "", + line: 1, + column: 5, + end_line: 1, + end_column: 22, + }, + ], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__unary_recovery_0.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__unary_recovery_0.snap new file mode 100644 index 000000000..82b3cdaa4 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__unary_recovery_0.snap @@ -0,0 +1,40 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(r#\"!a\"#)" +--- +Node { + node: Unary( + UnaryExpr { + op: Not, + operand: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 2, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 2, + }, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 2, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__unary_recovery_1.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__unary_recovery_1.snap new file mode 100644 index 000000000..16dc359a3 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__unary_recovery_1.snap @@ -0,0 +1,27 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(r#\"!!a\"#)" +--- +Node { + node: Unary( + UnaryExpr { + op: Not, + operand: Node { + node: Missing( + MissingExpr, + ), + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 2, + }, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__unary_recovery_2.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__unary_recovery_2.snap new file mode 100644 index 000000000..dbe5ca25a --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__unary_recovery_2.snap @@ -0,0 +1,63 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(r#\"not (!a)\"#)" +--- +Node { + node: Unary( + UnaryExpr { + op: Not, + operand: Node { + node: Paren( + ParenExpr { + expr: Node { + node: Unary( + UnaryExpr { + op: Not, + operand: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 6, + end_line: 1, + end_column: 7, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 6, + end_line: 1, + end_column: 7, + }, + }, + ), + filename: "", + line: 1, + column: 5, + end_line: 1, + end_column: 7, + }, + }, + ), + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 8, + }, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 8, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__unary_recovery_3.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__unary_recovery_3.snap new file mode 100644 index 000000000..c564377bc --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__unary_recovery_3.snap @@ -0,0 +1,63 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(r#\"! (not a)\"#)" +--- +Node { + node: Unary( + UnaryExpr { + op: Not, + operand: Node { + node: Paren( + ParenExpr { + expr: Node { + node: Unary( + UnaryExpr { + op: Not, + operand: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 7, + end_line: 1, + end_column: 8, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 7, + end_line: 1, + end_column: 8, + }, + }, + ), + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 8, + }, + }, + ), + filename: "", + line: 1, + column: 2, + end_line: 1, + end_column: 9, + }, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 9, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__unary_recovery_5.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__unary_recovery_5.snap new file mode 100644 index 000000000..b81c0b0e6 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__unary_recovery_5.snap @@ -0,0 +1,62 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(r#\"++i\"#)" +--- +Node { + node: Binary( + BinaryExpr { + left: Node { + node: Unary( + UnaryExpr { + op: UAdd, + operand: Node { + node: Missing( + MissingExpr, + ), + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 2, + }, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + op: Add, + right: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "i", + filename: "", + line: 1, + column: 2, + end_line: 1, + end_column: 3, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 2, + end_line: 1, + end_column: 3, + }, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 3, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__unary_recovery_6.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__unary_recovery_6.snap new file mode 100644 index 000000000..4d52ae56e --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__unary_recovery_6.snap @@ -0,0 +1,62 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(r#\"--i\"#)" +--- +Node { + node: Binary( + BinaryExpr { + left: Node { + node: Unary( + UnaryExpr { + op: USub, + operand: Node { + node: Missing( + MissingExpr, + ), + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 2, + }, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + op: Sub, + right: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "i", + filename: "", + line: 1, + column: 2, + end_line: 1, + end_column: 3, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 2, + end_line: 1, + end_column: 3, + }, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 3, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__unary_recovery_7.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__unary_recovery_7.snap new file mode 100644 index 000000000..986f87af6 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__unary_recovery_7.snap @@ -0,0 +1,62 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(r#\"-+i\"#)" +--- +Node { + node: Binary( + BinaryExpr { + left: Node { + node: Unary( + UnaryExpr { + op: USub, + operand: Node { + node: Missing( + MissingExpr, + ), + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 2, + }, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + op: Add, + right: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "i", + filename: "", + line: 1, + column: 2, + end_line: 1, + end_column: 3, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 2, + end_line: 1, + end_column: 3, + }, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 3, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__unary_recovery_8.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__unary_recovery_8.snap new file mode 100644 index 000000000..35ca71f65 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__unary_recovery_8.snap @@ -0,0 +1,27 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_expr_string(r#\"~~i\"#)" +--- +Node { + node: Unary( + UnaryExpr { + op: Invert, + operand: Node { + node: Missing( + MissingExpr, + ), + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 2, + }, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__unification_stmt_recovery_0.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__unification_stmt_recovery_0.snap new file mode 100644 index 000000000..14cf86ba4 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__unification_stmt_recovery_0.snap @@ -0,0 +1,87 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\"s: Server {\"#)" +--- +Module { + filename: "", + doc: None, + body: [ + Node { + node: Unification( + UnificationStmt { + target: Node { + node: Identifier { + names: [ + Node { + node: "s", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + pkgpath: "", + ctx: Store, + }, + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + value: Node { + node: SchemaExpr { + name: Node { + node: Identifier { + names: [ + Node { + node: "Server", + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 9, + }, + ], + pkgpath: "", + ctx: Load, + }, + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 9, + }, + args: [], + kwargs: [], + config: Node { + node: Config( + ConfigExpr { + items: [], + }, + ), + filename: "", + line: 1, + column: 10, + end_line: 1, + end_column: 11, + }, + }, + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 11, + }, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 11, + }, + ], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__unification_stmt_recovery_1.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__unification_stmt_recovery_1.snap new file mode 100644 index 000000000..0349210c7 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__unification_stmt_recovery_1.snap @@ -0,0 +1,87 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\"s: Server {}\"#)" +--- +Module { + filename: "", + doc: None, + body: [ + Node { + node: Unification( + UnificationStmt { + target: Node { + node: Identifier { + names: [ + Node { + node: "s", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + pkgpath: "", + ctx: Store, + }, + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + value: Node { + node: SchemaExpr { + name: Node { + node: Identifier { + names: [ + Node { + node: "Server", + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 9, + }, + ], + pkgpath: "", + ctx: Load, + }, + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 9, + }, + args: [], + kwargs: [], + config: Node { + node: Config( + ConfigExpr { + items: [], + }, + ), + filename: "", + line: 1, + column: 10, + end_line: 1, + end_column: 12, + }, + }, + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 12, + }, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 12, + }, + ], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__unification_stmt_recovery_2.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__unification_stmt_recovery_2.snap new file mode 100644 index 000000000..1e45fa860 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__unification_stmt_recovery_2.snap @@ -0,0 +1,87 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\"s: Server (\"#)" +--- +Module { + filename: "", + doc: None, + body: [ + Node { + node: Unification( + UnificationStmt { + target: Node { + node: Identifier { + names: [ + Node { + node: "s", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + pkgpath: "", + ctx: Store, + }, + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + value: Node { + node: SchemaExpr { + name: Node { + node: Identifier { + names: [ + Node { + node: "Server", + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 9, + }, + ], + pkgpath: "", + ctx: Load, + }, + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 9, + }, + args: [], + kwargs: [], + config: Node { + node: Config( + ConfigExpr { + items: [], + }, + ), + filename: "", + line: 1, + column: 11, + end_line: 1, + end_column: 11, + }, + }, + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 11, + }, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 11, + }, + ], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__unification_stmt_recovery_3.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__unification_stmt_recovery_3.snap new file mode 100644 index 000000000..a8c89921f --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__unification_stmt_recovery_3.snap @@ -0,0 +1,87 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\"s: Server ()\"#)" +--- +Module { + filename: "", + doc: None, + body: [ + Node { + node: Unification( + UnificationStmt { + target: Node { + node: Identifier { + names: [ + Node { + node: "s", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + pkgpath: "", + ctx: Store, + }, + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + value: Node { + node: SchemaExpr { + name: Node { + node: Identifier { + names: [ + Node { + node: "Server", + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 9, + }, + ], + pkgpath: "", + ctx: Load, + }, + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 9, + }, + args: [], + kwargs: [], + config: Node { + node: Config( + ConfigExpr { + items: [], + }, + ), + filename: "", + line: 1, + column: 12, + end_line: 1, + end_column: 12, + }, + }, + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 12, + }, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 12, + }, + ], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__unification_stmt_recovery_4.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__unification_stmt_recovery_4.snap new file mode 100644 index 000000000..dfa74cd5e --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__unification_stmt_recovery_4.snap @@ -0,0 +1,87 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\"s: Server () {\"#)" +--- +Module { + filename: "", + doc: None, + body: [ + Node { + node: Unification( + UnificationStmt { + target: Node { + node: Identifier { + names: [ + Node { + node: "s", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + pkgpath: "", + ctx: Store, + }, + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + value: Node { + node: SchemaExpr { + name: Node { + node: Identifier { + names: [ + Node { + node: "Server", + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 9, + }, + ], + pkgpath: "", + ctx: Load, + }, + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 9, + }, + args: [], + kwargs: [], + config: Node { + node: Config( + ConfigExpr { + items: [], + }, + ), + filename: "", + line: 1, + column: 13, + end_line: 1, + end_column: 14, + }, + }, + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 14, + }, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 14, + }, + ], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__unification_stmt_recovery_5.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__unification_stmt_recovery_5.snap new file mode 100644 index 000000000..1c71c2c1d --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__unification_stmt_recovery_5.snap @@ -0,0 +1,100 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\"s: Server ( {\"#)" +--- +Module { + filename: "", + doc: None, + body: [ + Node { + node: Unification( + UnificationStmt { + target: Node { + node: Identifier { + names: [ + Node { + node: "s", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + pkgpath: "", + ctx: Store, + }, + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + value: Node { + node: SchemaExpr { + name: Node { + node: Identifier { + names: [ + Node { + node: "Server", + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 9, + }, + ], + pkgpath: "", + ctx: Load, + }, + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 9, + }, + args: [ + Node { + node: Config( + ConfigExpr { + items: [], + }, + ), + filename: "", + line: 1, + column: 12, + end_line: 1, + end_column: 13, + }, + ], + kwargs: [], + config: Node { + node: Config( + ConfigExpr { + items: [], + }, + ), + filename: "", + line: 1, + column: 13, + end_line: 1, + end_column: 13, + }, + }, + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 13, + }, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 13, + }, + ], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__unification_stmt_recovery_6.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__unification_stmt_recovery_6.snap new file mode 100644 index 000000000..91d45bb2d --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__unification_stmt_recovery_6.snap @@ -0,0 +1,87 @@ +--- +source: parser/src/tests/error_recovery.rs +expression: "crate::tests::parsing_module_string(r#\"s: Server ( }\"#)" +--- +Module { + filename: "", + doc: None, + body: [ + Node { + node: Unification( + UnificationStmt { + target: Node { + node: Identifier { + names: [ + Node { + node: "s", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + pkgpath: "", + ctx: Store, + }, + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + value: Node { + node: SchemaExpr { + name: Node { + node: Identifier { + names: [ + Node { + node: "Server", + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 9, + }, + ], + pkgpath: "", + ctx: Load, + }, + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 9, + }, + args: [], + kwargs: [], + config: Node { + node: Config( + ConfigExpr { + items: [], + }, + ), + filename: "", + line: 1, + column: 13, + end_line: 1, + end_column: 13, + }, + }, + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 13, + }, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 13, + }, + ], + comments: [], +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__binary_expr_0.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__binary_expr_0.snap new file mode 100644 index 000000000..5eff3ea53 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__binary_expr_0.snap @@ -0,0 +1,74 @@ +--- +source: parser/src/tests/expr.rs +expression: "crate::tests::parsing_expr_string(r####\"1+2+3\"####)" +--- +Node { + node: Binary( + BinaryExpr { + left: Node { + node: Binary( + BinaryExpr { + left: Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 1, + ), + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + op: Add, + right: Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 2, + ), + }, + ), + filename: "", + line: 1, + column: 2, + end_line: 1, + end_column: 3, + }, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 3, + }, + op: Add, + right: Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 3, + ), + }, + ), + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 5, + }, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 5, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__binary_expr_1.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__binary_expr_1.snap new file mode 100644 index 000000000..332c5dcc2 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__binary_expr_1.snap @@ -0,0 +1,101 @@ +--- +source: parser/src/tests/expr.rs +expression: "crate::tests::parsing_expr_string(r####\"1+2*3-4\"####)" +--- +Node { + node: Binary( + BinaryExpr { + left: Node { + node: Binary( + BinaryExpr { + left: Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 1, + ), + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + op: Add, + right: Node { + node: Binary( + BinaryExpr { + left: Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 2, + ), + }, + ), + filename: "", + line: 1, + column: 2, + end_line: 1, + end_column: 3, + }, + op: Mul, + right: Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 3, + ), + }, + ), + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 5, + }, + }, + ), + filename: "", + line: 1, + column: 2, + end_line: 1, + end_column: 5, + }, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 5, + }, + op: Sub, + right: Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 4, + ), + }, + ), + filename: "", + line: 1, + column: 6, + end_line: 1, + end_column: 7, + }, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 7, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__binary_expr_10.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__binary_expr_10.snap new file mode 100644 index 000000000..97c2bc28e --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__binary_expr_10.snap @@ -0,0 +1,90 @@ +--- +source: parser/src/tests/expr.rs +expression: "crate::tests::parsing_expr_string(r####\"1 + a and b\"####)" +--- +Node { + node: Binary( + BinaryExpr { + left: Node { + node: Binary( + BinaryExpr { + left: Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 1, + ), + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + op: Add, + right: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 5, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 5, + }, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 5, + }, + op: And, + right: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "b", + filename: "", + line: 1, + column: 10, + end_line: 1, + end_column: 11, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 10, + end_line: 1, + end_column: 11, + }, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 11, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__binary_expr_2.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__binary_expr_2.snap new file mode 100644 index 000000000..d401b95d2 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__binary_expr_2.snap @@ -0,0 +1,101 @@ +--- +source: parser/src/tests/expr.rs +expression: "crate::tests::parsing_expr_string(r####\"1+2*3/4\"####)" +--- +Node { + node: Binary( + BinaryExpr { + left: Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 1, + ), + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + op: Add, + right: Node { + node: Binary( + BinaryExpr { + left: Node { + node: Binary( + BinaryExpr { + left: Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 2, + ), + }, + ), + filename: "", + line: 1, + column: 2, + end_line: 1, + end_column: 3, + }, + op: Mul, + right: Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 3, + ), + }, + ), + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 5, + }, + }, + ), + filename: "", + line: 1, + column: 2, + end_line: 1, + end_column: 5, + }, + op: Div, + right: Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 4, + ), + }, + ), + filename: "", + line: 1, + column: 6, + end_line: 1, + end_column: 7, + }, + }, + ), + filename: "", + line: 1, + column: 2, + end_line: 1, + end_column: 7, + }, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 7, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__binary_expr_3.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__binary_expr_3.snap new file mode 100644 index 000000000..90eafbf74 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__binary_expr_3.snap @@ -0,0 +1,63 @@ +--- +source: parser/src/tests/expr.rs +expression: "crate::tests::parsing_expr_string(r####\"a or b\"####)" +--- +Node { + node: Binary( + BinaryExpr { + left: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + op: Or, + right: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "b", + filename: "", + line: 1, + column: 5, + end_line: 1, + end_column: 6, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 5, + end_line: 1, + end_column: 6, + }, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 6, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__binary_expr_4.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__binary_expr_4.snap new file mode 100644 index 000000000..2f4355574 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__binary_expr_4.snap @@ -0,0 +1,102 @@ +--- +source: parser/src/tests/expr.rs +expression: "crate::tests::parsing_expr_string(r####\"x == a or b\"####)" +--- +Node { + node: Binary( + BinaryExpr { + left: Node { + node: Compare( + Compare { + left: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "x", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ops: [ + Eq, + ], + comparators: [ + Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 5, + end_line: 1, + end_column: 6, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 5, + end_line: 1, + end_column: 6, + }, + ], + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 11, + }, + op: Or, + right: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "b", + filename: "", + line: 1, + column: 10, + end_line: 1, + end_column: 11, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 10, + end_line: 1, + end_column: 11, + }, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 11, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__binary_expr_5.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__binary_expr_5.snap new file mode 100644 index 000000000..390202c20 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__binary_expr_5.snap @@ -0,0 +1,109 @@ +--- +source: parser/src/tests/expr.rs +expression: "crate::tests::parsing_expr_string(r####\"22 > 11 and 111 < 222\"####)" +--- +Node { + node: Binary( + BinaryExpr { + left: Node { + node: Compare( + Compare { + left: Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 22, + ), + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 2, + }, + ops: [ + Gt, + ], + comparators: [ + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 11, + ), + }, + ), + filename: "", + line: 1, + column: 5, + end_line: 1, + end_column: 7, + }, + ], + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 21, + }, + op: And, + right: Node { + node: Compare( + Compare { + left: Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 111, + ), + }, + ), + filename: "", + line: 1, + column: 12, + end_line: 1, + end_column: 15, + }, + ops: [ + Lt, + ], + comparators: [ + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 222, + ), + }, + ), + filename: "", + line: 1, + column: 18, + end_line: 1, + end_column: 21, + }, + ], + }, + ), + filename: "", + line: 1, + column: 12, + end_line: 1, + end_column: 21, + }, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 21, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__binary_expr_6.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__binary_expr_6.snap new file mode 100644 index 000000000..cd1469496 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__binary_expr_6.snap @@ -0,0 +1,170 @@ +--- +source: parser/src/tests/expr.rs +expression: "crate::tests::parsing_expr_string(r####\"int(e.value) > 1 and i == 0\"####)" +--- +Node { + node: Binary( + BinaryExpr { + left: Node { + node: Compare( + Compare { + left: Node { + node: Call( + CallExpr { + func: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "int", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 3, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 3, + }, + args: [ + Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "e", + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 5, + }, + Node { + node: "value", + filename: "", + line: 1, + column: 6, + end_line: 1, + end_column: 11, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 11, + }, + ], + keywords: [], + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 12, + }, + ops: [ + Gt, + ], + comparators: [ + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 1, + ), + }, + ), + filename: "", + line: 1, + column: 15, + end_line: 1, + end_column: 16, + }, + ], + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 27, + }, + op: And, + right: Node { + node: Compare( + Compare { + left: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "i", + filename: "", + line: 1, + column: 21, + end_line: 1, + end_column: 22, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 21, + end_line: 1, + end_column: 22, + }, + ops: [ + Eq, + ], + comparators: [ + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 0, + ), + }, + ), + filename: "", + line: 1, + column: 26, + end_line: 1, + end_column: 27, + }, + ], + }, + ), + filename: "", + line: 1, + column: 21, + end_line: 1, + end_column: 27, + }, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 27, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__binary_expr_7.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__binary_expr_7.snap new file mode 100644 index 000000000..7f48f3a65 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__binary_expr_7.snap @@ -0,0 +1,72 @@ +--- +source: parser/src/tests/expr.rs +expression: "crate::tests::parsing_expr_string(r####\"key in ['key']\"####)" +--- +Node { + node: Compare( + Compare { + left: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "key", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 3, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 3, + }, + ops: [ + In, + ], + comparators: [ + Node { + node: List( + ListExpr { + elts: [ + Node { + node: StringLit( + StringLit { + is_long_string: false, + raw_value: "'key'", + value: "key", + }, + ), + filename: "", + line: 1, + column: 8, + end_line: 1, + end_column: 13, + }, + ], + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 7, + end_line: 1, + end_column: 14, + }, + ], + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 14, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__binary_expr_8.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__binary_expr_8.snap new file mode 100644 index 000000000..1bb4f300a --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__binary_expr_8.snap @@ -0,0 +1,72 @@ +--- +source: parser/src/tests/expr.rs +expression: "crate::tests::parsing_expr_string(r####\"key not in ['key']\"####)" +--- +Node { + node: Compare( + Compare { + left: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "key", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 3, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 3, + }, + ops: [ + NotIn, + ], + comparators: [ + Node { + node: List( + ListExpr { + elts: [ + Node { + node: StringLit( + StringLit { + is_long_string: false, + raw_value: "'key'", + value: "key", + }, + ), + filename: "", + line: 1, + column: 12, + end_line: 1, + end_column: 17, + }, + ], + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 11, + end_line: 1, + end_column: 18, + }, + ], + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 18, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__binary_expr_9.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__binary_expr_9.snap new file mode 100644 index 000000000..416b34223 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__binary_expr_9.snap @@ -0,0 +1,109 @@ +--- +source: parser/src/tests/expr.rs +expression: "crate::tests::parsing_expr_string(r####\"1 is 1 and 11 is not 22\"####)" +--- +Node { + node: Binary( + BinaryExpr { + left: Node { + node: Compare( + Compare { + left: Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 1, + ), + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ops: [ + Is, + ], + comparators: [ + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 1, + ), + }, + ), + filename: "", + line: 1, + column: 5, + end_line: 1, + end_column: 6, + }, + ], + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 23, + }, + op: And, + right: Node { + node: Compare( + Compare { + left: Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 11, + ), + }, + ), + filename: "", + line: 1, + column: 11, + end_line: 1, + end_column: 13, + }, + ops: [ + IsNot, + ], + comparators: [ + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 22, + ), + }, + ), + filename: "", + line: 1, + column: 21, + end_line: 1, + end_column: 23, + }, + ], + }, + ), + filename: "", + line: 1, + column: 11, + end_line: 1, + end_column: 23, + }, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 23, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__binary_expr_with_paren.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__binary_expr_with_paren.snap new file mode 100644 index 000000000..b370c6def --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__binary_expr_with_paren.snap @@ -0,0 +1,112 @@ +--- +source: parser/src/tests/expr.rs +expression: "crate::tests::parsing_expr_string(r####\"1*(2+3)-4\"####)" +--- +Node { + node: Binary( + BinaryExpr { + left: Node { + node: Binary( + BinaryExpr { + left: Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 1, + ), + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + op: Mul, + right: Node { + node: Paren( + ParenExpr { + expr: Node { + node: Binary( + BinaryExpr { + left: Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 2, + ), + }, + ), + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 4, + }, + op: Add, + right: Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 3, + ), + }, + ), + filename: "", + line: 1, + column: 5, + end_line: 1, + end_column: 6, + }, + }, + ), + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 6, + }, + }, + ), + filename: "", + line: 1, + column: 2, + end_line: 1, + end_column: 7, + }, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 7, + }, + op: Sub, + right: Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 4, + ), + }, + ), + filename: "", + line: 1, + column: 8, + end_line: 1, + end_column: 9, + }, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 9, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__call_expr_0.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__call_expr_0.snap new file mode 100644 index 000000000..44b34d0df --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__call_expr_0.snap @@ -0,0 +1,41 @@ +--- +source: parser/src/tests/expr.rs +expression: "crate::tests::parsing_expr_string(r####\"func0()\"####)" +--- +Node { + node: Call( + CallExpr { + func: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "func0", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 5, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 5, + }, + args: [], + keywords: [], + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 7, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__call_expr_1.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__call_expr_1.snap new file mode 100644 index 000000000..7f53f5a9e --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__call_expr_1.snap @@ -0,0 +1,57 @@ +--- +source: parser/src/tests/expr.rs +expression: "crate::tests::parsing_expr_string(r####\"func1(1)\"####)" +--- +Node { + node: Call( + CallExpr { + func: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "func1", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 5, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 5, + }, + args: [ + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 1, + ), + }, + ), + filename: "", + line: 1, + column: 6, + end_line: 1, + end_column: 7, + }, + ], + keywords: [], + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 8, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__call_expr_2.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__call_expr_2.snap new file mode 100644 index 000000000..365a54fd2 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__call_expr_2.snap @@ -0,0 +1,89 @@ +--- +source: parser/src/tests/expr.rs +expression: "crate::tests::parsing_expr_string(r####\"func2(x=2)\"####)" +--- +Node { + node: Call( + CallExpr { + func: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "func2", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 5, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 5, + }, + args: [], + keywords: [ + Node { + node: Keyword { + arg: Node { + node: Identifier { + names: [ + Node { + node: "x", + filename: "", + line: 1, + column: 6, + end_line: 1, + end_column: 7, + }, + ], + pkgpath: "", + ctx: Load, + }, + filename: "", + line: 1, + column: 6, + end_line: 1, + end_column: 7, + }, + value: Some( + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 2, + ), + }, + ), + filename: "", + line: 1, + column: 8, + end_line: 1, + end_column: 9, + }, + ), + }, + filename: "", + line: 1, + column: 6, + end_line: 1, + end_column: 9, + }, + ], + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 10, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__call_expr_3.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__call_expr_3.snap new file mode 100644 index 000000000..abe42a4cb --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__call_expr_3.snap @@ -0,0 +1,105 @@ +--- +source: parser/src/tests/expr.rs +expression: "crate::tests::parsing_expr_string(r####\"func3(1,x=2)\"####)" +--- +Node { + node: Call( + CallExpr { + func: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "func3", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 5, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 5, + }, + args: [ + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 1, + ), + }, + ), + filename: "", + line: 1, + column: 6, + end_line: 1, + end_column: 7, + }, + ], + keywords: [ + Node { + node: Keyword { + arg: Node { + node: Identifier { + names: [ + Node { + node: "x", + filename: "", + line: 1, + column: 8, + end_line: 1, + end_column: 9, + }, + ], + pkgpath: "", + ctx: Load, + }, + filename: "", + line: 1, + column: 8, + end_line: 1, + end_column: 9, + }, + value: Some( + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 2, + ), + }, + ), + filename: "", + line: 1, + column: 10, + end_line: 1, + end_column: 11, + }, + ), + }, + filename: "", + line: 1, + column: 8, + end_line: 1, + end_column: 11, + }, + ], + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 12, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__config_expr_0.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__config_expr_0.snap new file mode 100644 index 000000000..1a31b93d9 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__config_expr_0.snap @@ -0,0 +1,136 @@ +--- +source: parser/src/tests/expr.rs +expression: "crate::tests::parsing_expr_string(r####\"{\n \"name\" = {\n \"name\": \"alice\"\n },\n \"gender\" = \"female\"\n}\"####)" +--- +Node { + node: Config( + ConfigExpr { + items: [ + Node { + node: ConfigEntry { + key: Some( + Node { + node: StringLit( + StringLit { + is_long_string: false, + raw_value: "\"name\"", + value: "name", + }, + ), + filename: "", + line: 2, + column: 4, + end_line: 2, + end_column: 10, + }, + ), + value: Node { + node: Config( + ConfigExpr { + items: [ + Node { + node: ConfigEntry { + key: Some( + Node { + node: StringLit( + StringLit { + is_long_string: false, + raw_value: "\"name\"", + value: "name", + }, + ), + filename: "", + line: 3, + column: 8, + end_line: 3, + end_column: 14, + }, + ), + value: Node { + node: StringLit( + StringLit { + is_long_string: false, + raw_value: "\"alice\"", + value: "alice", + }, + ), + filename: "", + line: 3, + column: 16, + end_line: 3, + end_column: 23, + }, + operation: Union, + }, + filename: "", + line: 3, + column: 8, + end_line: 3, + end_column: 23, + }, + ], + }, + ), + filename: "", + line: 2, + column: 13, + end_line: 4, + end_column: 5, + }, + operation: Override, + }, + filename: "", + line: 2, + column: 4, + end_line: 4, + end_column: 5, + }, + Node { + node: ConfigEntry { + key: Some( + Node { + node: StringLit( + StringLit { + is_long_string: false, + raw_value: "\"gender\"", + value: "gender", + }, + ), + filename: "", + line: 5, + column: 4, + end_line: 5, + end_column: 12, + }, + ), + value: Node { + node: StringLit( + StringLit { + is_long_string: false, + raw_value: "\"female\"", + value: "female", + }, + ), + filename: "", + line: 5, + column: 15, + end_line: 5, + end_column: 23, + }, + operation: Override, + }, + filename: "", + line: 5, + column: 4, + end_line: 5, + end_column: 23, + }, + ], + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 6, + end_column: 1, +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__config_expr_1.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__config_expr_1.snap new file mode 100644 index 000000000..20854a5cc --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__config_expr_1.snap @@ -0,0 +1,136 @@ +--- +source: parser/src/tests/expr.rs +expression: "crate::tests::parsing_expr_string(r####\"{\n \"name\" = {\n \"name\": \"alice\"\n }\n \"gender\" = \"female\",\n}\"####)" +--- +Node { + node: Config( + ConfigExpr { + items: [ + Node { + node: ConfigEntry { + key: Some( + Node { + node: StringLit( + StringLit { + is_long_string: false, + raw_value: "\"name\"", + value: "name", + }, + ), + filename: "", + line: 2, + column: 4, + end_line: 2, + end_column: 10, + }, + ), + value: Node { + node: Config( + ConfigExpr { + items: [ + Node { + node: ConfigEntry { + key: Some( + Node { + node: StringLit( + StringLit { + is_long_string: false, + raw_value: "\"name\"", + value: "name", + }, + ), + filename: "", + line: 3, + column: 8, + end_line: 3, + end_column: 14, + }, + ), + value: Node { + node: StringLit( + StringLit { + is_long_string: false, + raw_value: "\"alice\"", + value: "alice", + }, + ), + filename: "", + line: 3, + column: 16, + end_line: 3, + end_column: 23, + }, + operation: Union, + }, + filename: "", + line: 3, + column: 8, + end_line: 3, + end_column: 23, + }, + ], + }, + ), + filename: "", + line: 2, + column: 13, + end_line: 4, + end_column: 5, + }, + operation: Override, + }, + filename: "", + line: 2, + column: 4, + end_line: 4, + end_column: 5, + }, + Node { + node: ConfigEntry { + key: Some( + Node { + node: StringLit( + StringLit { + is_long_string: false, + raw_value: "\"gender\"", + value: "gender", + }, + ), + filename: "", + line: 5, + column: 4, + end_line: 5, + end_column: 12, + }, + ), + value: Node { + node: StringLit( + StringLit { + is_long_string: false, + raw_value: "\"female\"", + value: "female", + }, + ), + filename: "", + line: 5, + column: 15, + end_line: 5, + end_column: 23, + }, + operation: Override, + }, + filename: "", + line: 5, + column: 4, + end_line: 5, + end_column: 23, + }, + ], + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 6, + end_column: 1, +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__config_expr_2.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__config_expr_2.snap new file mode 100644 index 000000000..13be4b453 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__config_expr_2.snap @@ -0,0 +1,136 @@ +--- +source: parser/src/tests/expr.rs +expression: "crate::tests::parsing_expr_string(r####\"{\n \"name\" = {\n \"name\": \"alice\",\n }\n \"gender\" = \"female\"\n}\"####)" +--- +Node { + node: Config( + ConfigExpr { + items: [ + Node { + node: ConfigEntry { + key: Some( + Node { + node: StringLit( + StringLit { + is_long_string: false, + raw_value: "\"name\"", + value: "name", + }, + ), + filename: "", + line: 2, + column: 4, + end_line: 2, + end_column: 10, + }, + ), + value: Node { + node: Config( + ConfigExpr { + items: [ + Node { + node: ConfigEntry { + key: Some( + Node { + node: StringLit( + StringLit { + is_long_string: false, + raw_value: "\"name\"", + value: "name", + }, + ), + filename: "", + line: 3, + column: 8, + end_line: 3, + end_column: 14, + }, + ), + value: Node { + node: StringLit( + StringLit { + is_long_string: false, + raw_value: "\"alice\"", + value: "alice", + }, + ), + filename: "", + line: 3, + column: 16, + end_line: 3, + end_column: 23, + }, + operation: Union, + }, + filename: "", + line: 3, + column: 8, + end_line: 3, + end_column: 23, + }, + ], + }, + ), + filename: "", + line: 2, + column: 13, + end_line: 4, + end_column: 5, + }, + operation: Override, + }, + filename: "", + line: 2, + column: 4, + end_line: 4, + end_column: 5, + }, + Node { + node: ConfigEntry { + key: Some( + Node { + node: StringLit( + StringLit { + is_long_string: false, + raw_value: "\"gender\"", + value: "gender", + }, + ), + filename: "", + line: 5, + column: 4, + end_line: 5, + end_column: 12, + }, + ), + value: Node { + node: StringLit( + StringLit { + is_long_string: false, + raw_value: "\"female\"", + value: "female", + }, + ), + filename: "", + line: 5, + column: 15, + end_line: 5, + end_column: 23, + }, + operation: Override, + }, + filename: "", + line: 5, + column: 4, + end_line: 5, + end_column: 23, + }, + ], + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 6, + end_column: 1, +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__config_if_expr_0.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__config_if_expr_0.snap new file mode 100644 index 000000000..2d85fa3c0 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__config_if_expr_0.snap @@ -0,0 +1,104 @@ +--- +source: parser/src/tests/expr.rs +expression: "crate::tests::parsing_expr_string(r####\"{\n if True:\n a = 1\n}\"####)" +--- +Node { + node: Config( + ConfigExpr { + items: [ + Node { + node: ConfigEntry { + key: None, + value: Node { + node: ConfigIfEntry( + ConfigIfEntryExpr { + if_cond: Node { + node: NameConstantLit( + NameConstantLit { + value: True, + }, + ), + filename: "", + line: 2, + column: 7, + end_line: 2, + end_column: 11, + }, + items: [ + Node { + node: ConfigEntry { + key: Some( + Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 3, + column: 8, + end_line: 3, + end_column: 9, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 3, + column: 8, + end_line: 3, + end_column: 9, + }, + ), + value: Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 1, + ), + }, + ), + filename: "", + line: 3, + column: 12, + end_line: 3, + end_column: 13, + }, + operation: Override, + }, + filename: "", + line: 3, + column: 8, + end_line: 3, + end_column: 13, + }, + ], + orelse: None, + }, + ), + filename: "", + line: 2, + column: 4, + end_line: 4, + end_column: 0, + }, + operation: Union, + }, + filename: "", + line: 2, + column: 4, + end_line: 4, + end_column: 0, + }, + ], + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 4, + end_column: 1, +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__config_if_expr_1.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__config_if_expr_1.snap new file mode 100644 index 000000000..af1795665 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__config_if_expr_1.snap @@ -0,0 +1,168 @@ +--- +source: parser/src/tests/expr.rs +expression: "crate::tests::parsing_expr_string(r####\"{\n if True:\n a = 1\n else:\n a = 2\n}\"####)" +--- +Node { + node: Config( + ConfigExpr { + items: [ + Node { + node: ConfigEntry { + key: None, + value: Node { + node: ConfigIfEntry( + ConfigIfEntryExpr { + if_cond: Node { + node: NameConstantLit( + NameConstantLit { + value: True, + }, + ), + filename: "", + line: 2, + column: 7, + end_line: 2, + end_column: 11, + }, + items: [ + Node { + node: ConfigEntry { + key: Some( + Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 3, + column: 8, + end_line: 3, + end_column: 9, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 3, + column: 8, + end_line: 3, + end_column: 9, + }, + ), + value: Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 1, + ), + }, + ), + filename: "", + line: 3, + column: 12, + end_line: 3, + end_column: 13, + }, + operation: Override, + }, + filename: "", + line: 3, + column: 8, + end_line: 3, + end_column: 13, + }, + ], + orelse: Some( + Node { + node: Config( + ConfigExpr { + items: [ + Node { + node: ConfigEntry { + key: Some( + Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 5, + column: 8, + end_line: 5, + end_column: 9, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 5, + column: 8, + end_line: 5, + end_column: 9, + }, + ), + value: Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 2, + ), + }, + ), + filename: "", + line: 5, + column: 12, + end_line: 5, + end_column: 13, + }, + operation: Override, + }, + filename: "", + line: 5, + column: 8, + end_line: 5, + end_column: 13, + }, + ], + }, + ), + filename: "", + line: 4, + column: 4, + end_line: 6, + end_column: 0, + }, + ), + }, + ), + filename: "", + line: 2, + column: 4, + end_line: 6, + end_column: 0, + }, + operation: Union, + }, + filename: "", + line: 2, + column: 4, + end_line: 6, + end_column: 0, + }, + ], + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 6, + end_column: 1, +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__config_if_expr_2.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__config_if_expr_2.snap new file mode 100644 index 000000000..8931e97bc --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__config_if_expr_2.snap @@ -0,0 +1,287 @@ +--- +source: parser/src/tests/expr.rs +expression: "crate::tests::parsing_expr_string(r####\"{\n if True:\n a = 1\n elif x > 1:\n a = 2\n else:\n a = 3\n}\"####)" +--- +Node { + node: Config( + ConfigExpr { + items: [ + Node { + node: ConfigEntry { + key: None, + value: Node { + node: ConfigIfEntry( + ConfigIfEntryExpr { + if_cond: Node { + node: NameConstantLit( + NameConstantLit { + value: True, + }, + ), + filename: "", + line: 2, + column: 7, + end_line: 2, + end_column: 11, + }, + items: [ + Node { + node: ConfigEntry { + key: Some( + Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 3, + column: 8, + end_line: 3, + end_column: 9, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 3, + column: 8, + end_line: 3, + end_column: 9, + }, + ), + value: Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 1, + ), + }, + ), + filename: "", + line: 3, + column: 12, + end_line: 3, + end_column: 13, + }, + operation: Override, + }, + filename: "", + line: 3, + column: 8, + end_line: 3, + end_column: 13, + }, + ], + orelse: Some( + Node { + node: ConfigIfEntry( + ConfigIfEntryExpr { + if_cond: Node { + node: Compare( + Compare { + left: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "x", + filename: "", + line: 4, + column: 9, + end_line: 4, + end_column: 10, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 4, + column: 9, + end_line: 4, + end_column: 10, + }, + ops: [ + Gt, + ], + comparators: [ + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 1, + ), + }, + ), + filename: "", + line: 4, + column: 13, + end_line: 4, + end_column: 14, + }, + ], + }, + ), + filename: "", + line: 4, + column: 9, + end_line: 4, + end_column: 14, + }, + items: [ + Node { + node: ConfigEntry { + key: Some( + Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 5, + column: 8, + end_line: 5, + end_column: 9, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 5, + column: 8, + end_line: 5, + end_column: 9, + }, + ), + value: Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 2, + ), + }, + ), + filename: "", + line: 5, + column: 12, + end_line: 5, + end_column: 13, + }, + operation: Override, + }, + filename: "", + line: 5, + column: 8, + end_line: 5, + end_column: 13, + }, + ], + orelse: Some( + Node { + node: Config( + ConfigExpr { + items: [ + Node { + node: ConfigEntry { + key: Some( + Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 7, + column: 8, + end_line: 7, + end_column: 9, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 7, + column: 8, + end_line: 7, + end_column: 9, + }, + ), + value: Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 3, + ), + }, + ), + filename: "", + line: 7, + column: 12, + end_line: 7, + end_column: 13, + }, + operation: Override, + }, + filename: "", + line: 7, + column: 8, + end_line: 7, + end_column: 13, + }, + ], + }, + ), + filename: "", + line: 6, + column: 4, + end_line: 8, + end_column: 0, + }, + ), + }, + ), + filename: "", + line: 4, + column: 4, + end_line: 6, + end_column: 4, + }, + ), + }, + ), + filename: "", + line: 2, + column: 4, + end_line: 8, + end_column: 0, + }, + operation: Union, + }, + filename: "", + line: 2, + column: 4, + end_line: 8, + end_column: 0, + }, + ], + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 8, + end_column: 1, +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__config_if_expr_3.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__config_if_expr_3.snap new file mode 100644 index 000000000..c110d9ea1 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__config_if_expr_3.snap @@ -0,0 +1,141 @@ +--- +source: parser/src/tests/expr.rs +expression: "crate::tests::parsing_expr_string(r####\"{\n if True:\n if False:\n a = 1\n}\"####)" +--- +Node { + node: Config( + ConfigExpr { + items: [ + Node { + node: ConfigEntry { + key: None, + value: Node { + node: ConfigIfEntry( + ConfigIfEntryExpr { + if_cond: Node { + node: NameConstantLit( + NameConstantLit { + value: True, + }, + ), + filename: "", + line: 2, + column: 7, + end_line: 2, + end_column: 11, + }, + items: [ + Node { + node: ConfigEntry { + key: None, + value: Node { + node: ConfigIfEntry( + ConfigIfEntryExpr { + if_cond: Node { + node: NameConstantLit( + NameConstantLit { + value: False, + }, + ), + filename: "", + line: 3, + column: 11, + end_line: 3, + end_column: 16, + }, + items: [ + Node { + node: ConfigEntry { + key: Some( + Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 4, + column: 12, + end_line: 4, + end_column: 13, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 4, + column: 12, + end_line: 4, + end_column: 13, + }, + ), + value: Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 1, + ), + }, + ), + filename: "", + line: 4, + column: 16, + end_line: 4, + end_column: 17, + }, + operation: Override, + }, + filename: "", + line: 4, + column: 12, + end_line: 4, + end_column: 17, + }, + ], + orelse: None, + }, + ), + filename: "", + line: 3, + column: 8, + end_line: 5, + end_column: 0, + }, + operation: Override, + }, + filename: "", + line: 3, + column: 8, + end_line: 5, + end_column: 0, + }, + ], + orelse: None, + }, + ), + filename: "", + line: 2, + column: 4, + end_line: 5, + end_column: 0, + }, + operation: Union, + }, + filename: "", + line: 2, + column: 4, + end_line: 5, + end_column: 0, + }, + ], + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 5, + end_column: 1, +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__dict_comp_expr.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__dict_comp_expr.snap new file mode 100644 index 000000000..a240ca07e --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__dict_comp_expr.snap @@ -0,0 +1,262 @@ +--- +source: parser/src/tests/expr.rs +expression: "crate::tests::parsing_expr_string(r####\"{k: v + 1 for k, v in {k1 = 1, k2 = 2}}\"####)" +--- +Node { + node: DictComp( + DictComp { + entry: ConfigEntry { + key: Some( + Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "k", + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 2, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 2, + }, + ), + value: Node { + node: Binary( + BinaryExpr { + left: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "v", + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 5, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 5, + }, + op: Add, + right: Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 1, + ), + }, + ), + filename: "", + line: 1, + column: 8, + end_line: 1, + end_column: 9, + }, + }, + ), + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 9, + }, + operation: Union, + }, + generators: [ + Node { + node: CompClause { + targets: [ + Node { + node: Identifier { + names: [ + Node { + node: "k", + filename: "", + line: 1, + column: 14, + end_line: 1, + end_column: 15, + }, + ], + pkgpath: "", + ctx: Load, + }, + filename: "", + line: 1, + column: 14, + end_line: 1, + end_column: 15, + }, + Node { + node: Identifier { + names: [ + Node { + node: "v", + filename: "", + line: 1, + column: 17, + end_line: 1, + end_column: 18, + }, + ], + pkgpath: "", + ctx: Load, + }, + filename: "", + line: 1, + column: 17, + end_line: 1, + end_column: 18, + }, + ], + iter: Node { + node: Config( + ConfigExpr { + items: [ + Node { + node: ConfigEntry { + key: Some( + Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "k1", + filename: "", + line: 1, + column: 23, + end_line: 1, + end_column: 25, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 23, + end_line: 1, + end_column: 25, + }, + ), + value: Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 1, + ), + }, + ), + filename: "", + line: 1, + column: 28, + end_line: 1, + end_column: 29, + }, + operation: Override, + }, + filename: "", + line: 1, + column: 23, + end_line: 1, + end_column: 29, + }, + Node { + node: ConfigEntry { + key: Some( + Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "k2", + filename: "", + line: 1, + column: 31, + end_line: 1, + end_column: 33, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 31, + end_line: 1, + end_column: 33, + }, + ), + value: Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 2, + ), + }, + ), + filename: "", + line: 1, + column: 36, + end_line: 1, + end_column: 37, + }, + operation: Override, + }, + filename: "", + line: 1, + column: 31, + end_line: 1, + end_column: 37, + }, + ], + }, + ), + filename: "", + line: 1, + column: 22, + end_line: 1, + end_column: 38, + }, + ifs: [], + }, + filename: "", + line: 1, + column: 10, + end_line: 1, + end_column: 38, + }, + ], + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 39, +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__dict_expr.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__dict_expr.snap new file mode 100644 index 000000000..f94a0e658 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__dict_expr.snap @@ -0,0 +1,133 @@ +--- +source: parser/src/tests/expr.rs +expression: "crate::tests::parsing_expr_string(r####\"{k0=v0, k1=v1}\"####)" +--- +Node { + node: Config( + ConfigExpr { + items: [ + Node { + node: ConfigEntry { + key: Some( + Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "k0", + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 3, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 3, + }, + ), + value: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "v0", + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 6, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 6, + }, + operation: Override, + }, + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 6, + }, + Node { + node: ConfigEntry { + key: Some( + Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "k1", + filename: "", + line: 1, + column: 8, + end_line: 1, + end_column: 10, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 8, + end_line: 1, + end_column: 10, + }, + ), + value: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "v1", + filename: "", + line: 1, + column: 11, + end_line: 1, + end_column: 13, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 11, + end_line: 1, + end_column: 13, + }, + operation: Override, + }, + filename: "", + line: 1, + column: 8, + end_line: 1, + end_column: 13, + }, + ], + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 14, +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__expr_with_brace_0.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__expr_with_brace_0.snap new file mode 100644 index 000000000..487dd4827 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__expr_with_brace_0.snap @@ -0,0 +1,67 @@ +--- +source: parser/src/tests/expr.rs +expression: "crate::tests::parsing_expr_string(r####\"{a=2}\"####)" +--- +Node { + node: Config( + ConfigExpr { + items: [ + Node { + node: ConfigEntry { + key: Some( + Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 2, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 2, + }, + ), + value: Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 2, + ), + }, + ), + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 4, + }, + operation: Override, + }, + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 4, + }, + ], + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 5, +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__expr_with_brace_1.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__expr_with_brace_1.snap new file mode 100644 index 000000000..10ebd495e --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__expr_with_brace_1.snap @@ -0,0 +1,67 @@ +--- +source: parser/src/tests/expr.rs +expression: "crate::tests::parsing_expr_string(r####\"{a=2}}\"####)" +--- +Node { + node: Config( + ConfigExpr { + items: [ + Node { + node: ConfigEntry { + key: Some( + Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 2, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 2, + }, + ), + value: Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 2, + ), + }, + ), + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 4, + }, + operation: Override, + }, + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 4, + }, + ], + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 5, +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__expr_with_bracket_0.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__expr_with_bracket_0.snap new file mode 100644 index 000000000..5f61ac170 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__expr_with_bracket_0.snap @@ -0,0 +1,49 @@ +--- +source: parser/src/tests/expr.rs +expression: "crate::tests::parsing_expr_string(r####\"[2,3]\"####)" +--- +Node { + node: List( + ListExpr { + elts: [ + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 2, + ), + }, + ), + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 2, + }, + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 3, + ), + }, + ), + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 4, + }, + ], + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 5, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__expr_with_bracket_1.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__expr_with_bracket_1.snap new file mode 100644 index 000000000..8540a6417 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__expr_with_bracket_1.snap @@ -0,0 +1,63 @@ +--- +source: parser/src/tests/expr.rs +expression: "crate::tests::parsing_expr_string(r####\"[[2,3]\"####)" +--- +Node { + node: List( + ListExpr { + elts: [ + Node { + node: List( + ListExpr { + elts: [ + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 2, + ), + }, + ), + filename: "", + line: 1, + column: 2, + end_line: 1, + end_column: 3, + }, + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 3, + ), + }, + ), + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 5, + }, + ], + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 6, + }, + ], + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 6, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__expr_with_bracket_2.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__expr_with_bracket_2.snap new file mode 100644 index 000000000..974638b56 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__expr_with_bracket_2.snap @@ -0,0 +1,49 @@ +--- +source: parser/src/tests/expr.rs +expression: "crate::tests::parsing_expr_string(r####\"[2,3]]\"####)" +--- +Node { + node: List( + ListExpr { + elts: [ + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 2, + ), + }, + ), + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 2, + }, + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 3, + ), + }, + ), + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 4, + }, + ], + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 5, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__expr_with_bracket_3.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__expr_with_bracket_3.snap new file mode 100644 index 000000000..f00b8be1a --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__expr_with_bracket_3.snap @@ -0,0 +1,49 @@ +--- +source: parser/src/tests/expr.rs +expression: "crate::tests::parsing_expr_string(r####\"[2,3\"####)" +--- +Node { + node: List( + ListExpr { + elts: [ + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 2, + ), + }, + ), + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 2, + }, + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 3, + ), + }, + ), + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 4, + }, + ], + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 4, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__expr_with_bracket_4.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__expr_with_bracket_4.snap new file mode 100644 index 000000000..1caf60fff --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__expr_with_bracket_4.snap @@ -0,0 +1,18 @@ +--- +source: parser/src/tests/expr.rs +expression: "crate::tests::parsing_expr_string(r####\"[\"####)" +--- +Node { + node: List( + ListExpr { + elts: [], + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__expr_with_bracket_5.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__expr_with_bracket_5.snap new file mode 100644 index 000000000..aa4f7fe96 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__expr_with_bracket_5.snap @@ -0,0 +1,49 @@ +--- +source: parser/src/tests/expr.rs +expression: "crate::tests::parsing_expr_string(r####\"[\n 1\n 2,\n]\n \"####)" +--- +Node { + node: List( + ListExpr { + elts: [ + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 1, + ), + }, + ), + filename: "", + line: 2, + column: 4, + end_line: 2, + end_column: 5, + }, + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 2, + ), + }, + ), + filename: "", + line: 3, + column: 4, + end_line: 3, + end_column: 5, + }, + ], + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 4, + end_column: 1, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__expr_with_bracket_6.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__expr_with_bracket_6.snap new file mode 100644 index 000000000..ca20c1f26 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__expr_with_bracket_6.snap @@ -0,0 +1,49 @@ +--- +source: parser/src/tests/expr.rs +expression: "crate::tests::parsing_expr_string(r####\"[\n 1,2,\n]\n \"####)" +--- +Node { + node: List( + ListExpr { + elts: [ + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 1, + ), + }, + ), + filename: "", + line: 2, + column: 4, + end_line: 2, + end_column: 5, + }, + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 2, + ), + }, + ), + filename: "", + line: 2, + column: 6, + end_line: 2, + end_column: 7, + }, + ], + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 3, + end_column: 1, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__expr_with_bracket_7.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__expr_with_bracket_7.snap new file mode 100644 index 000000000..9ae683dfa --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__expr_with_bracket_7.snap @@ -0,0 +1,49 @@ +--- +source: parser/src/tests/expr.rs +expression: "crate::tests::parsing_expr_string(r####\"[\n 1,2,\n\n \"####)" +--- +Node { + node: List( + ListExpr { + elts: [ + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 1, + ), + }, + ), + filename: "", + line: 2, + column: 4, + end_line: 2, + end_column: 5, + }, + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 2, + ), + }, + ), + filename: "", + line: 2, + column: 6, + end_line: 2, + end_column: 7, + }, + ], + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 4, + end_column: 8, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__expr_with_delim_0.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__expr_with_delim_0.snap new file mode 100644 index 000000000..c854743c8 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__expr_with_delim_0.snap @@ -0,0 +1,78 @@ +--- +source: parser/src/tests/expr.rs +expression: "crate::tests::parsing_expr_string(r####\"({a=2}\"####)" +--- +Node { + node: Paren( + ParenExpr { + expr: Node { + node: Config( + ConfigExpr { + items: [ + Node { + node: ConfigEntry { + key: Some( + Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 2, + end_line: 1, + end_column: 3, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 2, + end_line: 1, + end_column: 3, + }, + ), + value: Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 2, + ), + }, + ), + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 5, + }, + operation: Override, + }, + filename: "", + line: 1, + column: 2, + end_line: 1, + end_column: 5, + }, + ], + }, + ), + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 6, + }, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 6, +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__expr_with_delim_1.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__expr_with_delim_1.snap new file mode 100644 index 000000000..a25037c77 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__expr_with_delim_1.snap @@ -0,0 +1,89 @@ +--- +source: parser/src/tests/expr.rs +expression: "crate::tests::parsing_expr_string(r####\"({a=(2}\"####)" +--- +Node { + node: Paren( + ParenExpr { + expr: Node { + node: Config( + ConfigExpr { + items: [ + Node { + node: ConfigEntry { + key: Some( + Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 2, + end_line: 1, + end_column: 3, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 2, + end_line: 1, + end_column: 3, + }, + ), + value: Node { + node: Paren( + ParenExpr { + expr: Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 2, + ), + }, + ), + filename: "", + line: 1, + column: 5, + end_line: 1, + end_column: 6, + }, + }, + ), + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 7, + }, + operation: Override, + }, + filename: "", + line: 1, + column: 2, + end_line: 1, + end_column: 7, + }, + ], + }, + ), + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 7, + }, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 7, +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__expr_with_delim_2.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__expr_with_delim_2.snap new file mode 100644 index 000000000..2f0a50261 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__expr_with_delim_2.snap @@ -0,0 +1,81 @@ +--- +source: parser/src/tests/expr.rs +expression: "crate::tests::parsing_expr_string(r####\"{a=[2]\"####)" +--- +Node { + node: Config( + ConfigExpr { + items: [ + Node { + node: ConfigEntry { + key: Some( + Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 2, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 2, + }, + ), + value: Node { + node: List( + ListExpr { + elts: [ + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 2, + ), + }, + ), + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 5, + }, + ], + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 6, + }, + operation: Override, + }, + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 6, + }, + ], + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 6, +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__expr_with_delim_3.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__expr_with_delim_3.snap new file mode 100644 index 000000000..9758f62a5 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__expr_with_delim_3.snap @@ -0,0 +1,81 @@ +--- +source: parser/src/tests/expr.rs +expression: "crate::tests::parsing_expr_string(r####\"[{a=2}\"####)" +--- +Node { + node: List( + ListExpr { + elts: [ + Node { + node: Config( + ConfigExpr { + items: [ + Node { + node: ConfigEntry { + key: Some( + Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 2, + end_line: 1, + end_column: 3, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 2, + end_line: 1, + end_column: 3, + }, + ), + value: Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 2, + ), + }, + ), + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 5, + }, + operation: Override, + }, + filename: "", + line: 1, + column: 2, + end_line: 1, + end_column: 5, + }, + ], + }, + ), + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 6, + }, + ], + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 6, +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__expr_with_delim_4.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__expr_with_delim_4.snap new file mode 100644 index 000000000..c9e7a9b93 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__expr_with_delim_4.snap @@ -0,0 +1,92 @@ +--- +source: parser/src/tests/expr.rs +expression: "crate::tests::parsing_expr_string(r####\"({a=[2}\"####)" +--- +Node { + node: Paren( + ParenExpr { + expr: Node { + node: Config( + ConfigExpr { + items: [ + Node { + node: ConfigEntry { + key: Some( + Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 2, + end_line: 1, + end_column: 3, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 2, + end_line: 1, + end_column: 3, + }, + ), + value: Node { + node: List( + ListExpr { + elts: [ + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 2, + ), + }, + ), + filename: "", + line: 1, + column: 5, + end_line: 1, + end_column: 6, + }, + ], + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 7, + }, + operation: Override, + }, + filename: "", + line: 1, + column: 2, + end_line: 1, + end_column: 7, + }, + ], + }, + ), + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 7, + }, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 7, +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__expr_with_delim_5.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__expr_with_delim_5.snap new file mode 100644 index 000000000..e69e0ea93 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__expr_with_delim_5.snap @@ -0,0 +1,17 @@ +--- +source: parser/src/tests/expr.rs +expression: "crate::tests::parsing_expr_string(r####\"{\"####)" +--- +Node { + node: Config( + ConfigExpr { + items: [], + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__expr_with_delim_6.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__expr_with_delim_6.snap new file mode 100644 index 000000000..bda623e7f --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__expr_with_delim_6.snap @@ -0,0 +1,67 @@ +--- +source: parser/src/tests/expr.rs +expression: "crate::tests::parsing_expr_string(r####\"{\n a = 1\n}\"####)" +--- +Node { + node: Config( + ConfigExpr { + items: [ + Node { + node: ConfigEntry { + key: Some( + Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 2, + column: 4, + end_line: 2, + end_column: 5, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 2, + column: 4, + end_line: 2, + end_column: 5, + }, + ), + value: Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 1, + ), + }, + ), + filename: "", + line: 2, + column: 8, + end_line: 2, + end_column: 9, + }, + operation: Override, + }, + filename: "", + line: 2, + column: 4, + end_line: 2, + end_column: 9, + }, + ], + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 3, + end_column: 1, +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__expr_with_delim_7.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__expr_with_delim_7.snap new file mode 100644 index 000000000..fa26c7489 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__expr_with_delim_7.snap @@ -0,0 +1,99 @@ +--- +source: parser/src/tests/expr.rs +expression: "crate::tests::parsing_expr_string(r####\"{\n a = 1\n\"####)" +--- +Node { + node: Config( + ConfigExpr { + items: [ + Node { + node: ConfigEntry { + key: Some( + Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 2, + column: 4, + end_line: 2, + end_column: 5, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 2, + column: 4, + end_line: 2, + end_column: 5, + }, + ), + value: Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 1, + ), + }, + ), + filename: "", + line: 2, + column: 8, + end_line: 2, + end_column: 9, + }, + operation: Override, + }, + filename: "", + line: 2, + column: 4, + end_line: 2, + end_column: 9, + }, + Node { + node: ConfigEntry { + key: Some( + Node { + node: Missing( + MissingExpr, + ), + filename: "", + line: 2, + column: 10, + end_line: 2, + end_column: 10, + }, + ), + value: Node { + node: Missing( + MissingExpr, + ), + filename: "", + line: 2, + column: 10, + end_line: 2, + end_column: 10, + }, + operation: Override, + }, + filename: "", + line: 2, + column: 10, + end_line: 2, + end_column: 10, + }, + ], + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 2, + end_column: 10, +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__expr_with_paren_0.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__expr_with_paren_0.snap new file mode 100644 index 000000000..6c6715bc5 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__expr_with_paren_0.snap @@ -0,0 +1,58 @@ +--- +source: parser/src/tests/expr.rs +expression: "crate::tests::parsing_expr_string(r####\"(2+3)\"####)" +--- +Node { + node: Paren( + ParenExpr { + expr: Node { + node: Binary( + BinaryExpr { + left: Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 2, + ), + }, + ), + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 2, + }, + op: Add, + right: Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 3, + ), + }, + ), + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 4, + }, + }, + ), + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 4, + }, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 5, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__expr_with_paren_1.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__expr_with_paren_1.snap new file mode 100644 index 000000000..5a29b6407 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__expr_with_paren_1.snap @@ -0,0 +1,69 @@ +--- +source: parser/src/tests/expr.rs +expression: "crate::tests::parsing_expr_string(r####\"((2+3)\"####)" +--- +Node { + node: Paren( + ParenExpr { + expr: Node { + node: Paren( + ParenExpr { + expr: Node { + node: Binary( + BinaryExpr { + left: Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 2, + ), + }, + ), + filename: "", + line: 1, + column: 2, + end_line: 1, + end_column: 3, + }, + op: Add, + right: Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 3, + ), + }, + ), + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 5, + }, + }, + ), + filename: "", + line: 1, + column: 2, + end_line: 1, + end_column: 5, + }, + }, + ), + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 6, + }, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 6, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__expr_with_paren_2.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__expr_with_paren_2.snap new file mode 100644 index 000000000..c353720ce --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__expr_with_paren_2.snap @@ -0,0 +1,58 @@ +--- +source: parser/src/tests/expr.rs +expression: "crate::tests::parsing_expr_string(r####\"(2+3))\"####)" +--- +Node { + node: Paren( + ParenExpr { + expr: Node { + node: Binary( + BinaryExpr { + left: Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 2, + ), + }, + ), + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 2, + }, + op: Add, + right: Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 3, + ), + }, + ), + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 4, + }, + }, + ), + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 4, + }, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 5, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__if_expr.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__if_expr.snap new file mode 100644 index 000000000..6d43c32c0 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__if_expr.snap @@ -0,0 +1,69 @@ +--- +source: parser/src/tests/expr.rs +expression: "crate::tests::parsing_expr_string(r####\"1 if true else 2\"####)" +--- +Node { + node: If( + IfExpr { + body: Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 1, + ), + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + cond: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "true", + filename: "", + line: 1, + column: 5, + end_line: 1, + end_column: 9, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 5, + end_line: 1, + end_column: 9, + }, + orelse: Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 2, + ), + }, + ), + filename: "", + line: 1, + column: 15, + end_line: 1, + end_column: 16, + }, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 16, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__lambda_expr_0.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__lambda_expr_0.snap new file mode 100644 index 000000000..0d919f9bc --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__lambda_expr_0.snap @@ -0,0 +1,20 @@ +--- +source: parser/src/tests/expr.rs +assertion_line: 79 +expression: "crate::tests::parsing_expr_string(r####\"lambda {}\"####)" +--- +Node { + node: Lambda( + LambdaExpr { + args: None, + body: [], + return_ty: None, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 9, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__lambda_expr_1.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__lambda_expr_1.snap new file mode 100644 index 000000000..f6415f382 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__lambda_expr_1.snap @@ -0,0 +1,59 @@ +--- +source: parser/src/tests/expr.rs +assertion_line: 80 +expression: "crate::tests::parsing_expr_string(r####\"lambda x {}\"####)" +--- +Node { + node: Lambda( + LambdaExpr { + args: Some( + Node { + node: Arguments { + args: [ + Node { + node: Identifier { + names: [ + Node { + node: "x", + filename: "", + line: 1, + column: 7, + end_line: 1, + end_column: 8, + }, + ], + pkgpath: "", + ctx: Load, + }, + filename: "", + line: 1, + column: 7, + end_line: 1, + end_column: 8, + }, + ], + defaults: [ + None, + ], + ty_list: [ + None, + ], + }, + filename: "", + line: 1, + column: 7, + end_line: 1, + end_column: 8, + }, + ), + body: [], + return_ty: None, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 11, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__lambda_expr_2.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__lambda_expr_2.snap new file mode 100644 index 000000000..0364c43ef --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__lambda_expr_2.snap @@ -0,0 +1,118 @@ +--- +source: parser/src/tests/expr.rs +assertion_line: 81 +expression: "crate::tests::parsing_expr_string(r####\"lambda x: int -> int {x}\"####)" +--- +Node { + node: Lambda( + LambdaExpr { + args: Some( + Node { + node: Arguments { + args: [ + Node { + node: Identifier { + names: [ + Node { + node: "x", + filename: "", + line: 1, + column: 7, + end_line: 1, + end_column: 8, + }, + ], + pkgpath: "", + ctx: Load, + }, + filename: "", + line: 1, + column: 7, + end_line: 1, + end_column: 8, + }, + ], + defaults: [ + None, + ], + ty_list: [ + Some( + Node { + node: Basic( + Int, + ), + filename: "", + line: 1, + column: 10, + end_line: 1, + end_column: 13, + }, + ), + ], + }, + filename: "", + line: 1, + column: 7, + end_line: 1, + end_column: 13, + }, + ), + body: [ + Node { + node: Expr( + ExprStmt { + exprs: [ + Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "x", + filename: "", + line: 1, + column: 22, + end_line: 1, + end_column: 23, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 22, + end_line: 1, + end_column: 23, + }, + ], + }, + ), + filename: "", + line: 1, + column: 22, + end_line: 1, + end_column: 23, + }, + ], + return_ty: Some( + Node { + node: Basic( + Int, + ), + filename: "", + line: 1, + column: 17, + end_line: 1, + end_column: 20, + }, + ), + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 24, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__lambda_expr_3.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__lambda_expr_3.snap new file mode 100644 index 000000000..e8f968626 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__lambda_expr_3.snap @@ -0,0 +1,178 @@ +--- +source: parser/src/tests/expr.rs +expression: "crate::tests::parsing_expr_string(r####\"lambda {\n if True:\n _a = 1\n else:\n _a = 2\n _a\n}\"####)" +--- +Node { + node: Lambda( + LambdaExpr { + args: None, + body: [ + Node { + node: If( + IfStmt { + body: [ + Node { + node: Assign( + AssignStmt { + targets: [ + Node { + node: Target { + name: Node { + node: "_a", + filename: "", + line: 3, + column: 8, + end_line: 3, + end_column: 10, + }, + paths: [], + pkgpath: "", + }, + filename: "", + line: 3, + column: 8, + end_line: 3, + end_column: 10, + }, + ], + value: Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 1, + ), + }, + ), + filename: "", + line: 3, + column: 13, + end_line: 3, + end_column: 14, + }, + ty: None, + }, + ), + filename: "", + line: 3, + column: 8, + end_line: 3, + end_column: 14, + }, + ], + cond: Node { + node: NameConstantLit( + NameConstantLit { + value: True, + }, + ), + filename: "", + line: 2, + column: 7, + end_line: 2, + end_column: 11, + }, + orelse: [ + Node { + node: Assign( + AssignStmt { + targets: [ + Node { + node: Target { + name: Node { + node: "_a", + filename: "", + line: 5, + column: 8, + end_line: 5, + end_column: 10, + }, + paths: [], + pkgpath: "", + }, + filename: "", + line: 5, + column: 8, + end_line: 5, + end_column: 10, + }, + ], + value: Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 2, + ), + }, + ), + filename: "", + line: 5, + column: 13, + end_line: 5, + end_column: 14, + }, + ty: None, + }, + ), + filename: "", + line: 5, + column: 8, + end_line: 5, + end_column: 14, + }, + ], + }, + ), + filename: "", + line: 2, + column: 4, + end_line: 6, + end_column: 4, + }, + Node { + node: Expr( + ExprStmt { + exprs: [ + Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "_a", + filename: "", + line: 6, + column: 4, + end_line: 6, + end_column: 6, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 6, + column: 4, + end_line: 6, + end_column: 6, + }, + ], + }, + ), + filename: "", + line: 6, + column: 4, + end_line: 6, + end_column: 6, + }, + ], + return_ty: None, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 7, + end_column: 1, +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__line_continue.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__line_continue.snap new file mode 100644 index 000000000..a563e4cd8 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__line_continue.snap @@ -0,0 +1,47 @@ +--- +source: parser/src/tests/expr.rs +expression: "crate::tests::parsing_expr_string(r####\"1 + \\\n2\n\"####)" +--- +Node { + node: Binary( + BinaryExpr { + left: Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 1, + ), + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + op: Add, + right: Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 2, + ), + }, + ), + filename: "", + line: 2, + column: 0, + end_line: 2, + end_column: 1, + }, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 2, + end_column: 1, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__list_comp_expr_0.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__list_comp_expr_0.snap new file mode 100644 index 000000000..c6f7cc855 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__list_comp_expr_0.snap @@ -0,0 +1,160 @@ +--- +source: parser/src/tests/expr.rs +expression: "crate::tests::parsing_expr_string(r####\"[x ** 2 for x in [1, 2, 3]]\"####)" +--- +Node { + node: ListComp( + ListComp { + elt: Node { + node: Binary( + BinaryExpr { + left: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "x", + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 2, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 2, + }, + op: Pow, + right: Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 2, + ), + }, + ), + filename: "", + line: 1, + column: 6, + end_line: 1, + end_column: 7, + }, + }, + ), + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 7, + }, + generators: [ + Node { + node: CompClause { + targets: [ + Node { + node: Identifier { + names: [ + Node { + node: "x", + filename: "", + line: 1, + column: 12, + end_line: 1, + end_column: 13, + }, + ], + pkgpath: "", + ctx: Load, + }, + filename: "", + line: 1, + column: 12, + end_line: 1, + end_column: 13, + }, + ], + iter: Node { + node: List( + ListExpr { + elts: [ + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 1, + ), + }, + ), + filename: "", + line: 1, + column: 18, + end_line: 1, + end_column: 19, + }, + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 2, + ), + }, + ), + filename: "", + line: 1, + column: 21, + end_line: 1, + end_column: 22, + }, + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 3, + ), + }, + ), + filename: "", + line: 1, + column: 24, + end_line: 1, + end_column: 25, + }, + ], + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 17, + end_line: 1, + end_column: 26, + }, + ifs: [], + }, + filename: "", + line: 1, + column: 8, + end_line: 1, + end_column: 26, + }, + ], + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 27, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__list_comp_expr_1.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__list_comp_expr_1.snap new file mode 100644 index 000000000..724c18610 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__list_comp_expr_1.snap @@ -0,0 +1,188 @@ +--- +source: parser/src/tests/expr.rs +expression: "crate::tests::parsing_expr_string(r####\"[i for i in [1, 2, 3] if i > 2]\"####)" +--- +Node { + node: ListComp( + ListComp { + elt: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "i", + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 2, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 2, + }, + generators: [ + Node { + node: CompClause { + targets: [ + Node { + node: Identifier { + names: [ + Node { + node: "i", + filename: "", + line: 1, + column: 7, + end_line: 1, + end_column: 8, + }, + ], + pkgpath: "", + ctx: Load, + }, + filename: "", + line: 1, + column: 7, + end_line: 1, + end_column: 8, + }, + ], + iter: Node { + node: List( + ListExpr { + elts: [ + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 1, + ), + }, + ), + filename: "", + line: 1, + column: 13, + end_line: 1, + end_column: 14, + }, + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 2, + ), + }, + ), + filename: "", + line: 1, + column: 16, + end_line: 1, + end_column: 17, + }, + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 3, + ), + }, + ), + filename: "", + line: 1, + column: 19, + end_line: 1, + end_column: 20, + }, + ], + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 12, + end_line: 1, + end_column: 21, + }, + ifs: [ + Node { + node: Compare( + Compare { + left: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "i", + filename: "", + line: 1, + column: 25, + end_line: 1, + end_column: 26, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 25, + end_line: 1, + end_column: 26, + }, + ops: [ + Gt, + ], + comparators: [ + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 2, + ), + }, + ), + filename: "", + line: 1, + column: 29, + end_line: 1, + end_column: 30, + }, + ], + }, + ), + filename: "", + line: 1, + column: 25, + end_line: 1, + end_column: 30, + }, + ], + }, + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 30, + }, + ], + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 31, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__list_expr_0.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__list_expr_0.snap new file mode 100644 index 000000000..356ee9454 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__list_expr_0.snap @@ -0,0 +1,64 @@ +--- +source: parser/src/tests/expr.rs +expression: "crate::tests::parsing_expr_string(r####\"[1, 2, 3]\"####)" +--- +Node { + node: List( + ListExpr { + elts: [ + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 1, + ), + }, + ), + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 2, + }, + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 2, + ), + }, + ), + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 5, + }, + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 3, + ), + }, + ), + filename: "", + line: 1, + column: 7, + end_line: 1, + end_column: 8, + }, + ], + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 9, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__list_expr_1.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__list_expr_1.snap new file mode 100644 index 000000000..3401d3c7f --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__list_expr_1.snap @@ -0,0 +1,90 @@ +--- +source: parser/src/tests/expr.rs +expression: "crate::tests::parsing_expr_string(r####\"[1, if True: 2, 3]\"####)" +--- +Node { + node: List( + ListExpr { + elts: [ + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 1, + ), + }, + ), + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 2, + }, + Node { + node: ListIfItem( + ListIfItemExpr { + if_cond: Node { + node: NameConstantLit( + NameConstantLit { + value: True, + }, + ), + filename: "", + line: 1, + column: 7, + end_line: 1, + end_column: 11, + }, + exprs: [ + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 2, + ), + }, + ), + filename: "", + line: 1, + column: 13, + end_line: 1, + end_column: 14, + }, + ], + orelse: None, + }, + ), + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 14, + }, + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 3, + ), + }, + ), + filename: "", + line: 1, + column: 16, + end_line: 1, + end_column: 17, + }, + ], + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 18, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__logic_expr_0.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__logic_expr_0.snap new file mode 100644 index 000000000..6f3ba2059 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__logic_expr_0.snap @@ -0,0 +1,75 @@ +--- +source: parser/src/tests/expr.rs +expression: "crate::tests::parsing_expr_string(r####\"0 < a < 100\"####)" +--- +Node { + node: Compare( + Compare { + left: Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 0, + ), + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ops: [ + Lt, + Lt, + ], + comparators: [ + Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 5, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 5, + }, + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 100, + ), + }, + ), + filename: "", + line: 1, + column: 8, + end_line: 1, + end_column: 11, + }, + ], + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 11, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__logic_expr_1.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__logic_expr_1.snap new file mode 100644 index 000000000..a5f7197a3 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__logic_expr_1.snap @@ -0,0 +1,110 @@ +--- +source: parser/src/tests/expr.rs +expression: "crate::tests::parsing_expr_string(r####\"0 < a < 100 + a\"####)" +--- +Node { + node: Compare( + Compare { + left: Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 0, + ), + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ops: [ + Lt, + Lt, + ], + comparators: [ + Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 5, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 5, + }, + Node { + node: Binary( + BinaryExpr { + left: Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 100, + ), + }, + ), + filename: "", + line: 1, + column: 8, + end_line: 1, + end_column: 11, + }, + op: Add, + right: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 14, + end_line: 1, + end_column: 15, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 14, + end_line: 1, + end_column: 15, + }, + }, + ), + filename: "", + line: 1, + column: 8, + end_line: 1, + end_column: 15, + }, + ], + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 15, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__logic_expr_2.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__logic_expr_2.snap new file mode 100644 index 000000000..b8df91bfb --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__logic_expr_2.snap @@ -0,0 +1,75 @@ +--- +source: parser/src/tests/expr.rs +expression: "crate::tests::parsing_expr_string(r####\"100 > a > 0\"####)" +--- +Node { + node: Compare( + Compare { + left: Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 100, + ), + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 3, + }, + ops: [ + Gt, + Gt, + ], + comparators: [ + Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 6, + end_line: 1, + end_column: 7, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 6, + end_line: 1, + end_column: 7, + }, + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 0, + ), + }, + ), + filename: "", + line: 1, + column: 10, + end_line: 1, + end_column: 11, + }, + ], + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 11, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__logic_expr_3.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__logic_expr_3.snap new file mode 100644 index 000000000..1116355bb --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__logic_expr_3.snap @@ -0,0 +1,110 @@ +--- +source: parser/src/tests/expr.rs +expression: "crate::tests::parsing_expr_string(r####\"100 + a > a > 0\"####)" +--- +Node { + node: Compare( + Compare { + left: Node { + node: Binary( + BinaryExpr { + left: Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 100, + ), + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 3, + }, + op: Add, + right: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 6, + end_line: 1, + end_column: 7, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 6, + end_line: 1, + end_column: 7, + }, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 7, + }, + ops: [ + Gt, + Gt, + ], + comparators: [ + Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 10, + end_line: 1, + end_column: 11, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 10, + end_line: 1, + end_column: 11, + }, + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 0, + ), + }, + ), + filename: "", + line: 1, + column: 14, + end_line: 1, + end_column: 15, + }, + ], + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 15, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__logic_expr_4.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__logic_expr_4.snap new file mode 100644 index 000000000..4d1179f19 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__logic_expr_4.snap @@ -0,0 +1,67 @@ +--- +source: parser/src/tests/expr.rs +expression: "crate::tests::parsing_expr_string(r####\"a is b\"####)" +--- +Node { + node: Compare( + Compare { + left: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ops: [ + Is, + ], + comparators: [ + Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "b", + filename: "", + line: 1, + column: 5, + end_line: 1, + end_column: 6, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 5, + end_line: 1, + end_column: 6, + }, + ], + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 6, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__logic_expr_5.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__logic_expr_5.snap new file mode 100644 index 000000000..45e278b7b --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__logic_expr_5.snap @@ -0,0 +1,56 @@ +--- +source: parser/src/tests/expr.rs +expression: "crate::tests::parsing_expr_string(r####\"a is not True\"####)" +--- +Node { + node: Compare( + Compare { + left: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ops: [ + IsNot, + ], + comparators: [ + Node { + node: NameConstantLit( + NameConstantLit { + value: True, + }, + ), + filename: "", + line: 1, + column: 9, + end_line: 1, + end_column: 13, + }, + ], + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 13, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__logic_expr_6.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__logic_expr_6.snap new file mode 100644 index 000000000..b848314b7 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__logic_expr_6.snap @@ -0,0 +1,158 @@ +--- +source: parser/src/tests/expr.rs +expression: "crate::tests::parsing_expr_string(r####\"not False or a > 0 and b is True\"####)" +--- +Node { + node: Binary( + BinaryExpr { + left: Node { + node: Unary( + UnaryExpr { + op: Not, + operand: Node { + node: NameConstantLit( + NameConstantLit { + value: False, + }, + ), + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 9, + }, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 9, + }, + op: Or, + right: Node { + node: Binary( + BinaryExpr { + left: Node { + node: Compare( + Compare { + left: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 13, + end_line: 1, + end_column: 14, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 13, + end_line: 1, + end_column: 14, + }, + ops: [ + Gt, + ], + comparators: [ + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 0, + ), + }, + ), + filename: "", + line: 1, + column: 17, + end_line: 1, + end_column: 18, + }, + ], + }, + ), + filename: "", + line: 1, + column: 13, + end_line: 1, + end_column: 32, + }, + op: And, + right: Node { + node: Compare( + Compare { + left: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "b", + filename: "", + line: 1, + column: 23, + end_line: 1, + end_column: 24, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 23, + end_line: 1, + end_column: 24, + }, + ops: [ + Is, + ], + comparators: [ + Node { + node: NameConstantLit( + NameConstantLit { + value: True, + }, + ), + filename: "", + line: 1, + column: 28, + end_line: 1, + end_column: 32, + }, + ], + }, + ), + filename: "", + line: 1, + column: 23, + end_line: 1, + end_column: 32, + }, + }, + ), + filename: "", + line: 1, + column: 13, + end_line: 1, + end_column: 32, + }, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 32, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__named_literal_expr_0.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__named_literal_expr_0.snap new file mode 100644 index 000000000..7de5ef740 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__named_literal_expr_0.snap @@ -0,0 +1,17 @@ +--- +source: parser/src/tests/expr.rs +expression: "crate::tests::parsing_expr_string(\"Undefined\")" +--- +Node { + node: NameConstantLit( + NameConstantLit { + value: Undefined, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 9, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__named_literal_expr_1.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__named_literal_expr_1.snap new file mode 100644 index 000000000..7f5c7ef9d --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__named_literal_expr_1.snap @@ -0,0 +1,17 @@ +--- +source: parser/src/tests/expr.rs +expression: "crate::tests::parsing_expr_string(\"None\")" +--- +Node { + node: NameConstantLit( + NameConstantLit { + value: None, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 4, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__named_literal_expr_2.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__named_literal_expr_2.snap new file mode 100644 index 000000000..2da8eaa4c --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__named_literal_expr_2.snap @@ -0,0 +1,17 @@ +--- +source: parser/src/tests/expr.rs +expression: "crate::tests::parsing_expr_string(\"True\")" +--- +Node { + node: NameConstantLit( + NameConstantLit { + value: True, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 4, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__named_literal_expr_3.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__named_literal_expr_3.snap new file mode 100644 index 000000000..2f6bf66cc --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__named_literal_expr_3.snap @@ -0,0 +1,17 @@ +--- +source: parser/src/tests/expr.rs +expression: "crate::tests::parsing_expr_string(\"False\")" +--- +Node { + node: NameConstantLit( + NameConstantLit { + value: False, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 5, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__nonstring_literal_expr.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__nonstring_literal_expr.snap new file mode 100644 index 000000000..565de3ff4 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__nonstring_literal_expr.snap @@ -0,0 +1,20 @@ +--- +source: parser/src/tests/expr.rs +expression: "crate::tests::parsing_expr_string(r####\"1234\"####)" +--- +Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 1234, + ), + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 4, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__number_bin_suffix_expr.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__number_bin_suffix_expr.snap new file mode 100644 index 000000000..5082423ff --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__number_bin_suffix_expr.snap @@ -0,0 +1,22 @@ +--- +source: parser/src/tests/expr.rs +expression: "crate::tests::parsing_expr_string(r####\"1234Ki\"####)" +--- +Node { + node: NumberLit( + NumberLit { + binary_suffix: Some( + Ki, + ), + value: Int( + 1234, + ), + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 6, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__parse_joined_string_0.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__parse_joined_string_0.snap new file mode 100644 index 000000000..9de6c12ec --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__parse_joined_string_0.snap @@ -0,0 +1,75 @@ +--- +source: parser/src/tests/expr.rs +expression: "crate::tests::parsing_expr_string(r####\"'${123+200}'\"####)" +--- +Node { + node: JoinedString( + JoinedString { + is_long_string: false, + values: [ + Node { + node: FormattedValue( + FormattedValue { + is_long_string: false, + value: Node { + node: Binary( + BinaryExpr { + left: Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 123, + ), + }, + ), + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 6, + }, + op: Add, + right: Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 200, + ), + }, + ), + filename: "", + line: 1, + column: 7, + end_line: 1, + end_column: 10, + }, + }, + ), + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 10, + }, + format_spec: None, + }, + ), + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 10, + }, + ], + raw_value: "'${123+200}'", + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 12, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__parse_joined_string_1.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__parse_joined_string_1.snap new file mode 100644 index 000000000..5fa01f670 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__parse_joined_string_1.snap @@ -0,0 +1,111 @@ +--- +source: parser/src/tests/expr.rs +expression: "crate::tests::parsing_expr_string(r####\"'abc${a+1}cde'\"####)" +--- +Node { + node: JoinedString( + JoinedString { + is_long_string: false, + values: [ + Node { + node: StringLit( + StringLit { + is_long_string: false, + raw_value: "abc", + value: "abc", + }, + ), + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 1, + }, + Node { + node: FormattedValue( + FormattedValue { + is_long_string: false, + value: Node { + node: Binary( + BinaryExpr { + left: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 6, + end_line: 1, + end_column: 7, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 6, + end_line: 1, + end_column: 7, + }, + op: Add, + right: Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 1, + ), + }, + ), + filename: "", + line: 1, + column: 8, + end_line: 1, + end_column: 9, + }, + }, + ), + filename: "", + line: 1, + column: 6, + end_line: 1, + end_column: 9, + }, + format_spec: None, + }, + ), + filename: "", + line: 1, + column: 6, + end_line: 1, + end_column: 9, + }, + Node { + node: StringLit( + StringLit { + is_long_string: false, + raw_value: "cde", + value: "cde", + }, + ), + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 1, + }, + ], + raw_value: "'abc${a+1}cde'", + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 14, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__primary_expr_0.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__primary_expr_0.snap new file mode 100644 index 000000000..a028192b6 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__primary_expr_0.snap @@ -0,0 +1,44 @@ +--- +source: parser/src/tests/expr.rs +expression: "crate::tests::parsing_expr_string(r####\"a.b.c\"####)" +--- +Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + Node { + node: "b", + filename: "", + line: 1, + column: 2, + end_line: 1, + end_column: 3, + }, + Node { + node: "c", + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 5, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 5, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__primary_expr_1.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__primary_expr_1.snap new file mode 100644 index 000000000..df2ad88f0 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__primary_expr_1.snap @@ -0,0 +1,82 @@ +--- +source: parser/src/tests/expr.rs +expression: "crate::tests::parsing_expr_string(r####\"'{}'.format(1)\"####)" +--- +Node { + node: Call( + CallExpr { + func: Node { + node: Selector( + SelectorExpr { + value: Node { + node: StringLit( + StringLit { + is_long_string: false, + raw_value: "'{}'", + value: "{}", + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 4, + }, + attr: Node { + node: Identifier { + names: [ + Node { + node: "format", + filename: "", + line: 1, + column: 5, + end_line: 1, + end_column: 11, + }, + ], + pkgpath: "", + ctx: Load, + }, + filename: "", + line: 1, + column: 5, + end_line: 1, + end_column: 11, + }, + ctx: Load, + has_question: false, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 11, + }, + args: [ + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 1, + ), + }, + ), + filename: "", + line: 1, + column: 12, + end_line: 1, + end_column: 13, + }, + ], + keywords: [], + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 14, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__primary_expr_2.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__primary_expr_2.snap new file mode 100644 index 000000000..45416f506 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__primary_expr_2.snap @@ -0,0 +1,104 @@ +--- +source: parser/src/tests/expr.rs +expression: "crate::tests::parsing_expr_string(r####\"str(1).isdigit()\"####)" +--- +Node { + node: Call( + CallExpr { + func: Node { + node: Selector( + SelectorExpr { + value: Node { + node: Call( + CallExpr { + func: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "str", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 3, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 3, + }, + args: [ + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 1, + ), + }, + ), + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 5, + }, + ], + keywords: [], + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 6, + }, + attr: Node { + node: Identifier { + names: [ + Node { + node: "isdigit", + filename: "", + line: 1, + column: 7, + end_line: 1, + end_column: 14, + }, + ], + pkgpath: "", + ctx: Load, + }, + filename: "", + line: 1, + column: 7, + end_line: 1, + end_column: 14, + }, + ctx: Load, + has_question: false, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 14, + }, + args: [], + keywords: [], + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 16, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__primary_expr_3.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__primary_expr_3.snap new file mode 100644 index 000000000..5485d0a48 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__primary_expr_3.snap @@ -0,0 +1,50 @@ +--- +source: parser/src/tests/expr.rs +expression: "crate::tests::parsing_expr_string(r####\"{}.a\"####)" +--- +Node { + node: Selector( + SelectorExpr { + value: Node { + node: Config( + ConfigExpr { + items: [], + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 2, + }, + attr: Node { + node: Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 4, + }, + ], + pkgpath: "", + ctx: Load, + }, + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 4, + }, + ctx: Load, + has_question: false, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 4, +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__primary_expr_4.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__primary_expr_4.snap new file mode 100644 index 000000000..70bc3af4b --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__primary_expr_4.snap @@ -0,0 +1,84 @@ +--- +source: parser/src/tests/expr.rs +expression: "crate::tests::parsing_expr_string(r####\"{}..a\"####)" +--- +Node { + node: Selector( + SelectorExpr { + value: Node { + node: Selector( + SelectorExpr { + value: Node { + node: Config( + ConfigExpr { + items: [], + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 2, + }, + attr: Node { + node: Identifier { + names: [ + Node { + node: "", + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 3, + }, + ], + pkgpath: "", + ctx: Load, + }, + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 3, + }, + ctx: Load, + has_question: false, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 3, + }, + attr: Node { + node: Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 5, + }, + ], + pkgpath: "", + ctx: Load, + }, + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 5, + }, + ctx: Load, + has_question: false, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 5, +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__primary_expr_5.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__primary_expr_5.snap new file mode 100644 index 000000000..c8ebf0ba3 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__primary_expr_5.snap @@ -0,0 +1,16 @@ +--- +source: parser/src/tests/expr.rs +expression: "crate::tests::parsing_expr_string(r####\"{}...a\"####)" +--- +Node { + node: Config( + ConfigExpr { + items: [], + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 2, +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__primary_expr_6.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__primary_expr_6.snap new file mode 100644 index 000000000..a560d73fc --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__primary_expr_6.snap @@ -0,0 +1,85 @@ +--- +source: parser/src/tests/expr.rs +expression: "crate::tests::parsing_expr_string(r####\"[]..a\"####)" +--- +Node { + node: Selector( + SelectorExpr { + value: Node { + node: Selector( + SelectorExpr { + value: Node { + node: List( + ListExpr { + elts: [], + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 2, + }, + attr: Node { + node: Identifier { + names: [ + Node { + node: "", + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 3, + }, + ], + pkgpath: "", + ctx: Load, + }, + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 3, + }, + ctx: Load, + has_question: false, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 3, + }, + attr: Node { + node: Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 5, + }, + ], + pkgpath: "", + ctx: Load, + }, + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 5, + }, + ctx: Load, + has_question: false, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 5, +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__primary_expr_7.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__primary_expr_7.snap new file mode 100644 index 000000000..c7674ed47 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__primary_expr_7.snap @@ -0,0 +1,44 @@ +--- +source: parser/src/tests/expr.rs +expression: "crate::tests::parsing_expr_string(r####\"{}[[]\"####)" +--- +Node { + node: Subscript( + Subscript { + value: Node { + node: Config( + ConfigExpr { + items: [], + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 2, + }, + index: Some( + Node { + node: Missing( + MissingExpr, + ), + filename: "", + line: 1, + column: 5, + end_line: 1, + end_column: 5, + }, + ), + lower: None, + upper: None, + step: None, + ctx: Load, + has_question: false, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 5, +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__quant_expr_0.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__quant_expr_0.snap new file mode 100644 index 000000000..2da80a01e --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__quant_expr_0.snap @@ -0,0 +1,119 @@ +--- +source: parser/src/tests/expr.rs +expression: "crate::tests::parsing_expr_string(r####\"all x in collection {x > 0}\"####)" +--- +Node { + node: Quant( + QuantExpr { + target: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "collection", + filename: "", + line: 1, + column: 9, + end_line: 1, + end_column: 19, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 9, + end_line: 1, + end_column: 19, + }, + variables: [ + Node { + node: Identifier { + names: [ + Node { + node: "x", + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 5, + }, + ], + pkgpath: "", + ctx: Load, + }, + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 5, + }, + ], + op: All, + test: Node { + node: Compare( + Compare { + left: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "x", + filename: "", + line: 1, + column: 21, + end_line: 1, + end_column: 22, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 21, + end_line: 1, + end_column: 22, + }, + ops: [ + Gt, + ], + comparators: [ + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 0, + ), + }, + ), + filename: "", + line: 1, + column: 25, + end_line: 1, + end_column: 26, + }, + ], + }, + ), + filename: "", + line: 1, + column: 21, + end_line: 1, + end_column: 26, + }, + if_cond: None, + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 27, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__quant_expr_1.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__quant_expr_1.snap new file mode 100644 index 000000000..2191519ad --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__quant_expr_1.snap @@ -0,0 +1,119 @@ +--- +source: parser/src/tests/expr.rs +expression: "crate::tests::parsing_expr_string(r####\"any y in collection {y < 0}\"####)" +--- +Node { + node: Quant( + QuantExpr { + target: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "collection", + filename: "", + line: 1, + column: 9, + end_line: 1, + end_column: 19, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 9, + end_line: 1, + end_column: 19, + }, + variables: [ + Node { + node: Identifier { + names: [ + Node { + node: "y", + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 5, + }, + ], + pkgpath: "", + ctx: Load, + }, + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 5, + }, + ], + op: Any, + test: Node { + node: Compare( + Compare { + left: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "y", + filename: "", + line: 1, + column: 21, + end_line: 1, + end_column: 22, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 21, + end_line: 1, + end_column: 22, + }, + ops: [ + Lt, + ], + comparators: [ + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 0, + ), + }, + ), + filename: "", + line: 1, + column: 25, + end_line: 1, + end_column: 26, + }, + ], + }, + ), + filename: "", + line: 1, + column: 21, + end_line: 1, + end_column: 26, + }, + if_cond: None, + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 27, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__quant_expr_2.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__quant_expr_2.snap new file mode 100644 index 000000000..e969f0cc3 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__quant_expr_2.snap @@ -0,0 +1,115 @@ +--- +source: parser/src/tests/expr.rs +expression: "crate::tests::parsing_expr_string(r####\"map x in collection {x + 1}\"####)" +--- +Node { + node: Quant( + QuantExpr { + target: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "collection", + filename: "", + line: 1, + column: 9, + end_line: 1, + end_column: 19, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 9, + end_line: 1, + end_column: 19, + }, + variables: [ + Node { + node: Identifier { + names: [ + Node { + node: "x", + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 5, + }, + ], + pkgpath: "", + ctx: Load, + }, + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 5, + }, + ], + op: Map, + test: Node { + node: Binary( + BinaryExpr { + left: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "x", + filename: "", + line: 1, + column: 21, + end_line: 1, + end_column: 22, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 21, + end_line: 1, + end_column: 22, + }, + op: Add, + right: Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 1, + ), + }, + ), + filename: "", + line: 1, + column: 25, + end_line: 1, + end_column: 26, + }, + }, + ), + filename: "", + line: 1, + column: 21, + end_line: 1, + end_column: 26, + }, + if_cond: None, + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 27, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__quant_expr_3.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__quant_expr_3.snap new file mode 100644 index 000000000..272131f54 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__quant_expr_3.snap @@ -0,0 +1,119 @@ +--- +source: parser/src/tests/expr.rs +expression: "crate::tests::parsing_expr_string(r####\"filter x in collection {x > 1}\"####)" +--- +Node { + node: Quant( + QuantExpr { + target: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "collection", + filename: "", + line: 1, + column: 12, + end_line: 1, + end_column: 22, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 12, + end_line: 1, + end_column: 22, + }, + variables: [ + Node { + node: Identifier { + names: [ + Node { + node: "x", + filename: "", + line: 1, + column: 7, + end_line: 1, + end_column: 8, + }, + ], + pkgpath: "", + ctx: Load, + }, + filename: "", + line: 1, + column: 7, + end_line: 1, + end_column: 8, + }, + ], + op: Filter, + test: Node { + node: Compare( + Compare { + left: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "x", + filename: "", + line: 1, + column: 24, + end_line: 1, + end_column: 25, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 24, + end_line: 1, + end_column: 25, + }, + ops: [ + Gt, + ], + comparators: [ + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 1, + ), + }, + ), + filename: "", + line: 1, + column: 28, + end_line: 1, + end_column: 29, + }, + ], + }, + ), + filename: "", + line: 1, + column: 24, + end_line: 1, + end_column: 29, + }, + if_cond: None, + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 30, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__quant_expr_4.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__quant_expr_4.snap new file mode 100644 index 000000000..272131f54 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__quant_expr_4.snap @@ -0,0 +1,119 @@ +--- +source: parser/src/tests/expr.rs +expression: "crate::tests::parsing_expr_string(r####\"filter x in collection {x > 1}\"####)" +--- +Node { + node: Quant( + QuantExpr { + target: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "collection", + filename: "", + line: 1, + column: 12, + end_line: 1, + end_column: 22, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 12, + end_line: 1, + end_column: 22, + }, + variables: [ + Node { + node: Identifier { + names: [ + Node { + node: "x", + filename: "", + line: 1, + column: 7, + end_line: 1, + end_column: 8, + }, + ], + pkgpath: "", + ctx: Load, + }, + filename: "", + line: 1, + column: 7, + end_line: 1, + end_column: 8, + }, + ], + op: Filter, + test: Node { + node: Compare( + Compare { + left: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "x", + filename: "", + line: 1, + column: 24, + end_line: 1, + end_column: 25, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 24, + end_line: 1, + end_column: 25, + }, + ops: [ + Gt, + ], + comparators: [ + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 1, + ), + }, + ), + filename: "", + line: 1, + column: 28, + end_line: 1, + end_column: 29, + }, + ], + }, + ), + filename: "", + line: 1, + column: 24, + end_line: 1, + end_column: 29, + }, + if_cond: None, + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 30, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__quant_expr_5.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__quant_expr_5.snap new file mode 100644 index 000000000..ee6e33686 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__quant_expr_5.snap @@ -0,0 +1,210 @@ +--- +source: parser/src/tests/expr.rs +expression: "crate::tests::parsing_expr_string(r####\"map i, e in [{k1 = \"v1\", k2 = \"v2\"}] { e }\"####)" +--- +Node { + node: Quant( + QuantExpr { + target: Node { + node: List( + ListExpr { + elts: [ + Node { + node: Config( + ConfigExpr { + items: [ + Node { + node: ConfigEntry { + key: Some( + Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "k1", + filename: "", + line: 1, + column: 14, + end_line: 1, + end_column: 16, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 14, + end_line: 1, + end_column: 16, + }, + ), + value: Node { + node: StringLit( + StringLit { + is_long_string: false, + raw_value: "\"v1\"", + value: "v1", + }, + ), + filename: "", + line: 1, + column: 19, + end_line: 1, + end_column: 23, + }, + operation: Override, + }, + filename: "", + line: 1, + column: 14, + end_line: 1, + end_column: 23, + }, + Node { + node: ConfigEntry { + key: Some( + Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "k2", + filename: "", + line: 1, + column: 25, + end_line: 1, + end_column: 27, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 25, + end_line: 1, + end_column: 27, + }, + ), + value: Node { + node: StringLit( + StringLit { + is_long_string: false, + raw_value: "\"v2\"", + value: "v2", + }, + ), + filename: "", + line: 1, + column: 30, + end_line: 1, + end_column: 34, + }, + operation: Override, + }, + filename: "", + line: 1, + column: 25, + end_line: 1, + end_column: 34, + }, + ], + }, + ), + filename: "", + line: 1, + column: 13, + end_line: 1, + end_column: 35, + }, + ], + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 12, + end_line: 1, + end_column: 36, + }, + variables: [ + Node { + node: Identifier { + names: [ + Node { + node: "i", + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 5, + }, + ], + pkgpath: "", + ctx: Load, + }, + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 5, + }, + Node { + node: Identifier { + names: [ + Node { + node: "e", + filename: "", + line: 1, + column: 7, + end_line: 1, + end_column: 8, + }, + ], + pkgpath: "", + ctx: Load, + }, + filename: "", + line: 1, + column: 7, + end_line: 1, + end_column: 8, + }, + ], + op: Map, + test: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "e", + filename: "", + line: 1, + column: 39, + end_line: 1, + end_column: 40, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 39, + end_line: 1, + end_column: 40, + }, + if_cond: None, + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 42, +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__quant_expr_6.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__quant_expr_6.snap new file mode 100644 index 000000000..39e61cef4 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__quant_expr_6.snap @@ -0,0 +1,265 @@ +--- +source: parser/src/tests/expr.rs +expression: "crate::tests::parsing_expr_string(r####\"map i, e in [{k1 = \"v1\", k2 = \"v2\"}] { e if i > 0 }\"####)" +--- +Node { + node: Quant( + QuantExpr { + target: Node { + node: List( + ListExpr { + elts: [ + Node { + node: Config( + ConfigExpr { + items: [ + Node { + node: ConfigEntry { + key: Some( + Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "k1", + filename: "", + line: 1, + column: 14, + end_line: 1, + end_column: 16, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 14, + end_line: 1, + end_column: 16, + }, + ), + value: Node { + node: StringLit( + StringLit { + is_long_string: false, + raw_value: "\"v1\"", + value: "v1", + }, + ), + filename: "", + line: 1, + column: 19, + end_line: 1, + end_column: 23, + }, + operation: Override, + }, + filename: "", + line: 1, + column: 14, + end_line: 1, + end_column: 23, + }, + Node { + node: ConfigEntry { + key: Some( + Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "k2", + filename: "", + line: 1, + column: 25, + end_line: 1, + end_column: 27, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 25, + end_line: 1, + end_column: 27, + }, + ), + value: Node { + node: StringLit( + StringLit { + is_long_string: false, + raw_value: "\"v2\"", + value: "v2", + }, + ), + filename: "", + line: 1, + column: 30, + end_line: 1, + end_column: 34, + }, + operation: Override, + }, + filename: "", + line: 1, + column: 25, + end_line: 1, + end_column: 34, + }, + ], + }, + ), + filename: "", + line: 1, + column: 13, + end_line: 1, + end_column: 35, + }, + ], + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 12, + end_line: 1, + end_column: 36, + }, + variables: [ + Node { + node: Identifier { + names: [ + Node { + node: "i", + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 5, + }, + ], + pkgpath: "", + ctx: Load, + }, + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 5, + }, + Node { + node: Identifier { + names: [ + Node { + node: "e", + filename: "", + line: 1, + column: 7, + end_line: 1, + end_column: 8, + }, + ], + pkgpath: "", + ctx: Load, + }, + filename: "", + line: 1, + column: 7, + end_line: 1, + end_column: 8, + }, + ], + op: Map, + test: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "e", + filename: "", + line: 1, + column: 39, + end_line: 1, + end_column: 40, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 39, + end_line: 1, + end_column: 40, + }, + if_cond: Some( + Node { + node: Compare( + Compare { + left: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "i", + filename: "", + line: 1, + column: 44, + end_line: 1, + end_column: 45, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 44, + end_line: 1, + end_column: 45, + }, + ops: [ + Gt, + ], + comparators: [ + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 0, + ), + }, + ), + filename: "", + line: 1, + column: 48, + end_line: 1, + end_column: 49, + }, + ], + }, + ), + filename: "", + line: 1, + column: 44, + end_line: 1, + end_column: 49, + }, + ), + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 51, +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__schema_expr_0.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__schema_expr_0.snap new file mode 100644 index 000000000..ca2d929a2 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__schema_expr_0.snap @@ -0,0 +1,51 @@ +--- +source: parser/src/tests/expr.rs +expression: "crate::tests::parsing_expr_string(r####\"Schema {}\"####)" +--- +Node { + node: Schema( + SchemaExpr { + name: Node { + node: Identifier { + names: [ + Node { + node: "Schema", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 6, + }, + ], + pkgpath: "", + ctx: Load, + }, + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 6, + }, + args: [], + kwargs: [], + config: Node { + node: Config( + ConfigExpr { + items: [], + }, + ), + filename: "", + line: 1, + column: 7, + end_line: 1, + end_column: 9, + }, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 9, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__schema_expr_1.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__schema_expr_1.snap new file mode 100644 index 000000000..553da53ed --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__schema_expr_1.snap @@ -0,0 +1,109 @@ +--- +source: parser/src/tests/expr.rs +expression: "crate::tests::parsing_expr_string(r####\"Schema {k=v}\"####)" +--- +Node { + node: Schema( + SchemaExpr { + name: Node { + node: Identifier { + names: [ + Node { + node: "Schema", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 6, + }, + ], + pkgpath: "", + ctx: Load, + }, + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 6, + }, + args: [], + kwargs: [], + config: Node { + node: Config( + ConfigExpr { + items: [ + Node { + node: ConfigEntry { + key: Some( + Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "k", + filename: "", + line: 1, + column: 8, + end_line: 1, + end_column: 9, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 8, + end_line: 1, + end_column: 9, + }, + ), + value: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "v", + filename: "", + line: 1, + column: 10, + end_line: 1, + end_column: 11, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 10, + end_line: 1, + end_column: 11, + }, + operation: Override, + }, + filename: "", + line: 1, + column: 8, + end_line: 1, + end_column: 11, + }, + ], + }, + ), + filename: "", + line: 1, + column: 7, + end_line: 1, + end_column: 12, + }, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 12, +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__schema_expr_2.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__schema_expr_2.snap new file mode 100644 index 000000000..92dffcfc6 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__schema_expr_2.snap @@ -0,0 +1,109 @@ +--- +source: parser/src/tests/expr.rs +expression: "crate::tests::parsing_expr_string(r####\"Schema () {k=v}\"####)" +--- +Node { + node: Schema( + SchemaExpr { + name: Node { + node: Identifier { + names: [ + Node { + node: "Schema", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 6, + }, + ], + pkgpath: "", + ctx: Load, + }, + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 6, + }, + args: [], + kwargs: [], + config: Node { + node: Config( + ConfigExpr { + items: [ + Node { + node: ConfigEntry { + key: Some( + Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "k", + filename: "", + line: 1, + column: 11, + end_line: 1, + end_column: 12, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 11, + end_line: 1, + end_column: 12, + }, + ), + value: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "v", + filename: "", + line: 1, + column: 13, + end_line: 1, + end_column: 14, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 13, + end_line: 1, + end_column: 14, + }, + operation: Override, + }, + filename: "", + line: 1, + column: 11, + end_line: 1, + end_column: 14, + }, + ], + }, + ), + filename: "", + line: 1, + column: 10, + end_line: 1, + end_column: 15, + }, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 15, +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__schema_expr_3.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__schema_expr_3.snap new file mode 100644 index 000000000..921ac0dd1 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__schema_expr_3.snap @@ -0,0 +1,140 @@ +--- +source: parser/src/tests/expr.rs +expression: "crate::tests::parsing_expr_string(r####\"Schema (1, 2) {k=v}\"####)" +--- +Node { + node: Schema( + SchemaExpr { + name: Node { + node: Identifier { + names: [ + Node { + node: "Schema", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 6, + }, + ], + pkgpath: "", + ctx: Load, + }, + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 6, + }, + args: [ + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 1, + ), + }, + ), + filename: "", + line: 1, + column: 8, + end_line: 1, + end_column: 9, + }, + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 2, + ), + }, + ), + filename: "", + line: 1, + column: 11, + end_line: 1, + end_column: 12, + }, + ], + kwargs: [], + config: Node { + node: Config( + ConfigExpr { + items: [ + Node { + node: ConfigEntry { + key: Some( + Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "k", + filename: "", + line: 1, + column: 15, + end_line: 1, + end_column: 16, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 15, + end_line: 1, + end_column: 16, + }, + ), + value: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "v", + filename: "", + line: 1, + column: 17, + end_line: 1, + end_column: 18, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 17, + end_line: 1, + end_column: 18, + }, + operation: Override, + }, + filename: "", + line: 1, + column: 15, + end_line: 1, + end_column: 18, + }, + ], + }, + ), + filename: "", + line: 1, + column: 14, + end_line: 1, + end_column: 19, + }, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 19, +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__schema_expr_4.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__schema_expr_4.snap new file mode 100644 index 000000000..b0d50f05b --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__schema_expr_4.snap @@ -0,0 +1,140 @@ +--- +source: parser/src/tests/expr.rs +expression: "crate::tests::parsing_expr_string(r####\"Schema (1, 2) {\n k=v\n}\"####)" +--- +Node { + node: Schema( + SchemaExpr { + name: Node { + node: Identifier { + names: [ + Node { + node: "Schema", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 6, + }, + ], + pkgpath: "", + ctx: Load, + }, + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 6, + }, + args: [ + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 1, + ), + }, + ), + filename: "", + line: 1, + column: 8, + end_line: 1, + end_column: 9, + }, + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 2, + ), + }, + ), + filename: "", + line: 1, + column: 11, + end_line: 1, + end_column: 12, + }, + ], + kwargs: [], + config: Node { + node: Config( + ConfigExpr { + items: [ + Node { + node: ConfigEntry { + key: Some( + Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "k", + filename: "", + line: 2, + column: 4, + end_line: 2, + end_column: 5, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 2, + column: 4, + end_line: 2, + end_column: 5, + }, + ), + value: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "v", + filename: "", + line: 2, + column: 6, + end_line: 2, + end_column: 7, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 2, + column: 6, + end_line: 2, + end_column: 7, + }, + operation: Override, + }, + filename: "", + line: 2, + column: 4, + end_line: 2, + end_column: 7, + }, + ], + }, + ), + filename: "", + line: 1, + column: 14, + end_line: 3, + end_column: 1, + }, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 3, + end_column: 1, +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__smoke_test_parsing_expr_0.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__smoke_test_parsing_expr_0.snap new file mode 100644 index 000000000..896509e1b --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__smoke_test_parsing_expr_0.snap @@ -0,0 +1,20 @@ +--- +source: parser/src/tests/expr.rs +expression: "crate::tests::parsing_expr_string(\"1\\n\")" +--- +Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 1, + ), + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__smoke_test_parsing_expr_1.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__smoke_test_parsing_expr_1.snap new file mode 100644 index 000000000..2e7abca86 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__smoke_test_parsing_expr_1.snap @@ -0,0 +1,19 @@ +--- +source: parser/src/tests/expr.rs +expression: "crate::tests::parsing_expr_string(\"\\\"1\\\"\\n\")" +--- +Node { + node: StringLit( + StringLit { + is_long_string: false, + raw_value: "\"1\"", + value: "1", + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 3, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__string_literal_expr_0.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__string_literal_expr_0.snap new file mode 100644 index 000000000..6c8c37538 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__string_literal_expr_0.snap @@ -0,0 +1,19 @@ +--- +source: parser/src/tests/expr.rs +expression: "crate::tests::parsing_expr_string(r####\"'1234'\"####)" +--- +Node { + node: StringLit( + StringLit { + is_long_string: false, + raw_value: "'1234'", + value: "1234", + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 6, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__string_literal_expr_1.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__string_literal_expr_1.snap new file mode 100644 index 000000000..1f108e406 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__string_literal_expr_1.snap @@ -0,0 +1,19 @@ +--- +source: parser/src/tests/expr.rs +expression: "crate::tests::parsing_expr_string(r####\"\"1234\"\"####)" +--- +Node { + node: StringLit( + StringLit { + is_long_string: false, + raw_value: "\"1234\"", + value: "1234", + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 6, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__string_literal_expr_2.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__string_literal_expr_2.snap new file mode 100644 index 000000000..a5f3e2e53 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__string_literal_expr_2.snap @@ -0,0 +1,19 @@ +--- +source: parser/src/tests/expr.rs +expression: "crate::tests::parsing_expr_string(r####\"\"1234\\n\"\"####)" +--- +Node { + node: StringLit( + StringLit { + is_long_string: false, + raw_value: "\"1234\\n\"", + value: "1234\n", + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 8, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__subscript_expr_0.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__subscript_expr_0.snap new file mode 100644 index 000000000..3752cbeac --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__subscript_expr_0.snap @@ -0,0 +1,61 @@ +--- +source: parser/src/tests/expr.rs +expression: "crate::tests::parsing_expr_string(r####\"a[0]\"####)" +--- +Node { + node: Subscript( + Subscript { + value: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + index: Some( + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 0, + ), + }, + ), + filename: "", + line: 1, + column: 2, + end_line: 1, + end_column: 3, + }, + ), + lower: None, + upper: None, + step: None, + ctx: Load, + has_question: false, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 4, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__subscript_expr_1.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__subscript_expr_1.snap new file mode 100644 index 000000000..9b32e231a --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__subscript_expr_1.snap @@ -0,0 +1,60 @@ +--- +source: parser/src/tests/expr.rs +expression: "crate::tests::parsing_expr_string(r####\"b[\"k\"]\"####)" +--- +Node { + node: Subscript( + Subscript { + value: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "b", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + index: Some( + Node { + node: StringLit( + StringLit { + is_long_string: false, + raw_value: "\"k\"", + value: "k", + }, + ), + filename: "", + line: 1, + column: 2, + end_line: 1, + end_column: 5, + }, + ), + lower: None, + upper: None, + step: None, + ctx: Load, + has_question: false, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 6, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__subscript_expr_10.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__subscript_expr_10.snap new file mode 100644 index 000000000..ce08b1682 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__subscript_expr_10.snap @@ -0,0 +1,73 @@ +--- +source: parser/src/tests/expr.rs +expression: "crate::tests::parsing_expr_string(r####\"a[::-1]\"####)" +--- +Node { + node: Subscript( + Subscript { + value: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + index: None, + lower: None, + upper: None, + step: Some( + Node { + node: Unary( + UnaryExpr { + op: USub, + operand: Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 1, + ), + }, + ), + filename: "", + line: 1, + column: 5, + end_line: 1, + end_column: 6, + }, + }, + ), + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 6, + }, + ), + ctx: Load, + has_question: false, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 7, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__subscript_expr_11.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__subscript_expr_11.snap new file mode 100644 index 000000000..a5cc8ab34 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__subscript_expr_11.snap @@ -0,0 +1,77 @@ +--- +source: parser/src/tests/expr.rs +expression: "crate::tests::parsing_expr_string(r####\"a[1::2]\"####)" +--- +Node { + node: Subscript( + Subscript { + value: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + index: None, + lower: Some( + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 1, + ), + }, + ), + filename: "", + line: 1, + column: 2, + end_line: 1, + end_column: 3, + }, + ), + upper: None, + step: Some( + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 2, + ), + }, + ), + filename: "", + line: 1, + column: 5, + end_line: 1, + end_column: 6, + }, + ), + ctx: Load, + has_question: false, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 7, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__subscript_expr_12.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__subscript_expr_12.snap new file mode 100644 index 000000000..f6cfe4beb --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__subscript_expr_12.snap @@ -0,0 +1,77 @@ +--- +source: parser/src/tests/expr.rs +expression: "crate::tests::parsing_expr_string(r####\"a[:2:1]\"####)" +--- +Node { + node: Subscript( + Subscript { + value: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + index: None, + lower: None, + upper: Some( + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 2, + ), + }, + ), + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 4, + }, + ), + step: Some( + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 1, + ), + }, + ), + filename: "", + line: 1, + column: 5, + end_line: 1, + end_column: 6, + }, + ), + ctx: Load, + has_question: false, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 7, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__subscript_expr_13.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__subscript_expr_13.snap new file mode 100644 index 000000000..61b668cca --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__subscript_expr_13.snap @@ -0,0 +1,77 @@ +--- +source: parser/src/tests/expr.rs +expression: "crate::tests::parsing_expr_string(r####\"a[1:2:]\"####)" +--- +Node { + node: Subscript( + Subscript { + value: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + index: None, + lower: Some( + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 1, + ), + }, + ), + filename: "", + line: 1, + column: 2, + end_line: 1, + end_column: 3, + }, + ), + upper: Some( + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 2, + ), + }, + ), + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 5, + }, + ), + step: None, + ctx: Load, + has_question: false, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 7, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__subscript_expr_14.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__subscript_expr_14.snap new file mode 100644 index 000000000..001416f3a --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__subscript_expr_14.snap @@ -0,0 +1,93 @@ +--- +source: parser/src/tests/expr.rs +expression: "crate::tests::parsing_expr_string(r####\"a[1:3:1]\"####)" +--- +Node { + node: Subscript( + Subscript { + value: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + index: None, + lower: Some( + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 1, + ), + }, + ), + filename: "", + line: 1, + column: 2, + end_line: 1, + end_column: 3, + }, + ), + upper: Some( + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 3, + ), + }, + ), + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 5, + }, + ), + step: Some( + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 1, + ), + }, + ), + filename: "", + line: 1, + column: 6, + end_line: 1, + end_column: 7, + }, + ), + ctx: Load, + has_question: false, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 8, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__subscript_expr_2.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__subscript_expr_2.snap new file mode 100644 index 000000000..1c4f15312 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__subscript_expr_2.snap @@ -0,0 +1,61 @@ +--- +source: parser/src/tests/expr.rs +expression: "crate::tests::parsing_expr_string(r####\"c?[1]\"####)" +--- +Node { + node: Subscript( + Subscript { + value: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "c", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + index: Some( + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 1, + ), + }, + ), + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 4, + }, + ), + lower: None, + upper: None, + step: None, + ctx: Load, + has_question: true, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 5, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__subscript_expr_3.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__subscript_expr_3.snap new file mode 100644 index 000000000..a288ead99 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__subscript_expr_3.snap @@ -0,0 +1,61 @@ +--- +source: parser/src/tests/expr.rs +expression: "crate::tests::parsing_expr_string(r####\"a[1:]\"####)" +--- +Node { + node: Subscript( + Subscript { + value: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + index: None, + lower: Some( + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 1, + ), + }, + ), + filename: "", + line: 1, + column: 2, + end_line: 1, + end_column: 3, + }, + ), + upper: None, + step: None, + ctx: Load, + has_question: false, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 5, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__subscript_expr_4.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__subscript_expr_4.snap new file mode 100644 index 000000000..d65b89649 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__subscript_expr_4.snap @@ -0,0 +1,73 @@ +--- +source: parser/src/tests/expr.rs +expression: "crate::tests::parsing_expr_string(r####\"a[:-1]\"####)" +--- +Node { + node: Subscript( + Subscript { + value: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + index: None, + lower: None, + upper: Some( + Node { + node: Unary( + UnaryExpr { + op: USub, + operand: Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 1, + ), + }, + ), + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 5, + }, + }, + ), + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 5, + }, + ), + step: None, + ctx: Load, + has_question: false, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 6, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__subscript_expr_5.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__subscript_expr_5.snap new file mode 100644 index 000000000..d095deb1f --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__subscript_expr_5.snap @@ -0,0 +1,85 @@ +--- +source: parser/src/tests/expr.rs +expression: "crate::tests::parsing_expr_string(r####\"a[1:len]\"####)" +--- +Node { + node: Subscript( + Subscript { + value: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + index: None, + lower: Some( + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 1, + ), + }, + ), + filename: "", + line: 1, + column: 2, + end_line: 1, + end_column: 3, + }, + ), + upper: Some( + Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "len", + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 7, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 7, + }, + ), + step: None, + ctx: Load, + has_question: false, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 8, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__subscript_expr_6.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__subscript_expr_6.snap new file mode 100644 index 000000000..16596547b --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__subscript_expr_6.snap @@ -0,0 +1,89 @@ +--- +source: parser/src/tests/expr.rs +expression: "crate::tests::parsing_expr_string(r####\"a[0:-1]\"####)" +--- +Node { + node: Subscript( + Subscript { + value: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + index: None, + lower: Some( + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 0, + ), + }, + ), + filename: "", + line: 1, + column: 2, + end_line: 1, + end_column: 3, + }, + ), + upper: Some( + Node { + node: Unary( + UnaryExpr { + op: USub, + operand: Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 1, + ), + }, + ), + filename: "", + line: 1, + column: 5, + end_line: 1, + end_column: 6, + }, + }, + ), + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 6, + }, + ), + step: None, + ctx: Load, + has_question: false, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 7, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__subscript_expr_7.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__subscript_expr_7.snap new file mode 100644 index 000000000..efdc7b695 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__subscript_expr_7.snap @@ -0,0 +1,45 @@ +--- +source: parser/src/tests/expr.rs +expression: "crate::tests::parsing_expr_string(r####\"a[::]\"####)" +--- +Node { + node: Subscript( + Subscript { + value: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + index: None, + lower: None, + upper: None, + step: None, + ctx: Load, + has_question: false, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 5, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__subscript_expr_8.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__subscript_expr_8.snap new file mode 100644 index 000000000..6a16c990c --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__subscript_expr_8.snap @@ -0,0 +1,61 @@ +--- +source: parser/src/tests/expr.rs +expression: "crate::tests::parsing_expr_string(r####\"a[1::]\"####)" +--- +Node { + node: Subscript( + Subscript { + value: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + index: None, + lower: Some( + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 1, + ), + }, + ), + filename: "", + line: 1, + column: 2, + end_line: 1, + end_column: 3, + }, + ), + upper: None, + step: None, + ctx: Load, + has_question: false, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 6, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__subscript_expr_9.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__subscript_expr_9.snap new file mode 100644 index 000000000..14164675c --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__subscript_expr_9.snap @@ -0,0 +1,61 @@ +--- +source: parser/src/tests/expr.rs +expression: "crate::tests::parsing_expr_string(r####\"a[:0:]\"####)" +--- +Node { + node: Subscript( + Subscript { + value: Node { + node: Identifier( + Identifier { + names: [ + Node { + node: "a", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 1, + }, + index: None, + lower: None, + upper: Some( + Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 0, + ), + }, + ), + filename: "", + line: 1, + column: 3, + end_line: 1, + end_column: 4, + }, + ), + step: None, + ctx: Load, + has_question: false, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 6, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__unary_expr.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__unary_expr.snap new file mode 100644 index 000000000..174b7eeec --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__expr__unary_expr.snap @@ -0,0 +1,32 @@ +--- +source: parser/src/tests/expr.rs +expression: "crate::tests::parsing_expr_string(r####\"+1\"####)" +--- +Node { + node: Unary( + UnaryExpr { + op: UAdd, + operand: Node { + node: NumberLit( + NumberLit { + binary_suffix: None, + value: Int( + 1, + ), + }, + ), + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 2, + }, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 2, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__file__assert_1.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__file__assert_1.snap new file mode 100644 index 000000000..48d0bf21e --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__file__assert_1.snap @@ -0,0 +1,100 @@ +--- +source: parser/src/tests/file.rs +expression: "crate::tests::parsing_file_string(\"testdata/assert-01.k\")" +--- +{ + "filename": "assert-01.k", + "doc": null, + "body": [ + { + "node": { + "type": "Assert", + "test": { + "node": { + "type": "NumberLit", + "binary_suffix": null, + "value": { + "type": "Int", + "value": 1 + } + }, + "filename": "assert-01.k", + "line": 1, + "column": 7, + "end_line": 1, + "end_column": 8 + }, + "if_cond": null, + "msg": null + }, + "filename": "assert-01.k", + "line": 1, + "column": 0, + "end_line": 1, + "end_column": 8 + }, + { + "node": { + "type": "Assert", + "test": { + "node": { + "type": "NumberLit", + "binary_suffix": null, + "value": { + "type": "Int", + "value": 2 + } + }, + "filename": "assert-01.k", + "line": 2, + "column": 7, + "end_line": 2, + "end_column": 8 + }, + "if_cond": null, + "msg": { + "node": { + "type": "StringLit", + "is_long_string": false, + "raw_value": "\"msg\"", + "value": "msg" + }, + "filename": "assert-01.k", + "line": 2, + "column": 10, + "end_line": 2, + "end_column": 15 + } + }, + "filename": "assert-01.k", + "line": 2, + "column": 0, + "end_line": 2, + "end_column": 15 + }, + { + "node": { + "type": "Assert", + "test": { + "node": { + "type": "NameConstantLit", + "value": "True" + }, + "filename": "assert-01.k", + "line": 3, + "column": 7, + "end_line": 3, + "end_column": 11 + }, + "if_cond": null, + "msg": null + }, + "filename": "assert-01.k", + "line": 3, + "column": 0, + "end_line": 3, + "end_column": 11 + } + ], + "comments": [] +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__file__assert_2.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__file__assert_2.snap new file mode 100644 index 000000000..499040813 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__file__assert_2.snap @@ -0,0 +1,198 @@ +--- +source: parser/src/tests/file.rs +expression: "crate::tests::parsing_file_string(\"testdata/assert-02.k\")" +--- +{ + "filename": "assert-02.k", + "doc": null, + "body": [ + { + "node": { + "type": "Assert", + "test": { + "node": { + "type": "NameConstantLit", + "value": "True" + }, + "filename": "assert-02.k", + "line": 1, + "column": 7, + "end_line": 1, + "end_column": 11 + }, + "if_cond": null, + "msg": null + }, + "filename": "assert-02.k", + "line": 1, + "column": 0, + "end_line": 1, + "end_column": 11 + }, + { + "node": { + "type": "Assert", + "test": { + "node": { + "type": "Compare", + "left": { + "node": { + "type": "NumberLit", + "binary_suffix": null, + "value": { + "type": "Int", + "value": 1 + } + }, + "filename": "assert-02.k", + "line": 2, + "column": 7, + "end_line": 2, + "end_column": 8 + }, + "ops": [ + "Eq" + ], + "comparators": [ + { + "node": { + "type": "NumberLit", + "binary_suffix": null, + "value": { + "type": "Int", + "value": 1 + } + }, + "filename": "assert-02.k", + "line": 2, + "column": 12, + "end_line": 2, + "end_column": 13 + } + ] + }, + "filename": "assert-02.k", + "line": 2, + "column": 7, + "end_line": 2, + "end_column": 13 + }, + "if_cond": null, + "msg": null + }, + "filename": "assert-02.k", + "line": 2, + "column": 0, + "end_line": 2, + "end_column": 13 + }, + { + "node": { + "type": "Assign", + "targets": [ + { + "node": { + "name": { + "node": "_x", + "filename": "assert-02.k", + "line": 3, + "column": 0, + "end_line": 3, + "end_column": 2 + }, + "paths": [], + "pkgpath": "" + }, + "filename": "assert-02.k", + "line": 3, + "column": 0, + "end_line": 3, + "end_column": 2 + } + ], + "value": { + "node": { + "type": "StringLit", + "is_long_string": false, + "raw_value": "\"good case\"", + "value": "good case" + }, + "filename": "assert-02.k", + "line": 3, + "column": 5, + "end_line": 3, + "end_column": 16 + }, + "ty": null + }, + "filename": "assert-02.k", + "line": 3, + "column": 0, + "end_line": 3, + "end_column": 16 + }, + { + "node": { + "type": "Assert", + "test": { + "node": { + "type": "Compare", + "left": { + "node": { + "type": "Identifier", + "names": [ + { + "node": "_x", + "filename": "assert-02.k", + "line": 4, + "column": 7, + "end_line": 4, + "end_column": 9 + } + ], + "pkgpath": "", + "ctx": "Load" + }, + "filename": "assert-02.k", + "line": 4, + "column": 7, + "end_line": 4, + "end_column": 9 + }, + "ops": [ + "Eq" + ], + "comparators": [ + { + "node": { + "type": "StringLit", + "is_long_string": false, + "raw_value": "\"good case\"", + "value": "good case" + }, + "filename": "assert-02.k", + "line": 4, + "column": 13, + "end_line": 4, + "end_column": 24 + } + ] + }, + "filename": "assert-02.k", + "line": 4, + "column": 7, + "end_line": 4, + "end_column": 24 + }, + "if_cond": null, + "msg": null + }, + "filename": "assert-02.k", + "line": 4, + "column": 0, + "end_line": 4, + "end_column": 24 + } + ], + "comments": [] +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__file__assert_3.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__file__assert_3.snap new file mode 100644 index 000000000..5f7883c36 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__file__assert_3.snap @@ -0,0 +1,270 @@ +--- +source: parser/src/tests/file.rs +expression: "crate::tests::parsing_file_string(\"testdata/assert-03.k\")" +--- +{ + "filename": "assert-03.k", + "doc": null, + "body": [ + { + "node": { + "type": "If", + "body": [ + { + "node": { + "type": "Assert", + "test": { + "node": { + "type": "NameConstantLit", + "value": "True" + }, + "filename": "assert-03.k", + "line": 2, + "column": 11, + "end_line": 2, + "end_column": 15 + }, + "if_cond": null, + "msg": { + "node": { + "type": "StringLit", + "is_long_string": false, + "raw_value": "\"Error messgae\"", + "value": "Error messgae" + }, + "filename": "assert-03.k", + "line": 2, + "column": 17, + "end_line": 2, + "end_column": 32 + } + }, + "filename": "assert-03.k", + "line": 2, + "column": 4, + "end_line": 2, + "end_column": 32 + }, + { + "node": { + "type": "Assert", + "test": { + "node": { + "type": "Compare", + "left": { + "node": { + "type": "NumberLit", + "binary_suffix": null, + "value": { + "type": "Int", + "value": 1 + } + }, + "filename": "assert-03.k", + "line": 3, + "column": 11, + "end_line": 3, + "end_column": 12 + }, + "ops": [ + "Eq" + ], + "comparators": [ + { + "node": { + "type": "NumberLit", + "binary_suffix": null, + "value": { + "type": "Int", + "value": 1 + } + }, + "filename": "assert-03.k", + "line": 3, + "column": 16, + "end_line": 3, + "end_column": 17 + } + ] + }, + "filename": "assert-03.k", + "line": 3, + "column": 11, + "end_line": 3, + "end_column": 17 + }, + "if_cond": null, + "msg": { + "node": { + "type": "StringLit", + "is_long_string": false, + "raw_value": "\"\"", + "value": "" + }, + "filename": "assert-03.k", + "line": 3, + "column": 19, + "end_line": 3, + "end_column": 21 + } + }, + "filename": "assert-03.k", + "line": 3, + "column": 4, + "end_line": 3, + "end_column": 21 + }, + { + "node": { + "type": "Assign", + "targets": [ + { + "node": { + "name": { + "node": "_x", + "filename": "assert-03.k", + "line": 4, + "column": 4, + "end_line": 4, + "end_column": 6 + }, + "paths": [], + "pkgpath": "" + }, + "filename": "assert-03.k", + "line": 4, + "column": 4, + "end_line": 4, + "end_column": 6 + } + ], + "value": { + "node": { + "type": "StringLit", + "is_long_string": false, + "raw_value": "\"good case\"", + "value": "good case" + }, + "filename": "assert-03.k", + "line": 4, + "column": 9, + "end_line": 4, + "end_column": 20 + }, + "ty": null + }, + "filename": "assert-03.k", + "line": 4, + "column": 4, + "end_line": 4, + "end_column": 20 + }, + { + "node": { + "type": "Assert", + "test": { + "node": { + "type": "Compare", + "left": { + "node": { + "type": "Identifier", + "names": [ + { + "node": "_x", + "filename": "assert-03.k", + "line": 5, + "column": 11, + "end_line": 5, + "end_column": 13 + } + ], + "pkgpath": "", + "ctx": "Load" + }, + "filename": "assert-03.k", + "line": 5, + "column": 11, + "end_line": 5, + "end_column": 13 + }, + "ops": [ + "Eq" + ], + "comparators": [ + { + "node": { + "type": "StringLit", + "is_long_string": false, + "raw_value": "\"good case\"", + "value": "good case" + }, + "filename": "assert-03.k", + "line": 5, + "column": 17, + "end_line": 5, + "end_column": 28 + } + ] + }, + "filename": "assert-03.k", + "line": 5, + "column": 11, + "end_line": 5, + "end_column": 28 + }, + "if_cond": null, + "msg": null + }, + "filename": "assert-03.k", + "line": 5, + "column": 4, + "end_line": 5, + "end_column": 28 + } + ], + "cond": { + "node": { + "type": "NameConstantLit", + "value": "True" + }, + "filename": "assert-03.k", + "line": 1, + "column": 3, + "end_line": 1, + "end_column": 7 + }, + "orelse": [ + { + "node": { + "type": "Assert", + "test": { + "node": { + "type": "NameConstantLit", + "value": "False" + }, + "filename": "assert-03.k", + "line": 7, + "column": 11, + "end_line": 7, + "end_column": 16 + }, + "if_cond": null, + "msg": null + }, + "filename": "assert-03.k", + "line": 7, + "column": 4, + "end_line": 7, + "end_column": 16 + } + ] + }, + "filename": "assert-03.k", + "line": 1, + "column": 0, + "end_line": 8, + "end_column": 1 + } + ], + "comments": [] +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__file__assert_if_0.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__file__assert_if_0.snap new file mode 100644 index 000000000..4362c79da --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__file__assert_if_0.snap @@ -0,0 +1,241 @@ +--- +source: parser/src/tests/file.rs +expression: "crate::tests::parsing_file_string(\"testdata/assert-if-0.k\")" +--- +{ + "filename": "assert-if-0.k", + "doc": null, + "body": [ + { + "node": { + "type": "Assert", + "test": { + "node": { + "type": "NameConstantLit", + "value": "True" + }, + "filename": "assert-if-0.k", + "line": 1, + "column": 7, + "end_line": 1, + "end_column": 11 + }, + "if_cond": null, + "msg": null + }, + "filename": "assert-if-0.k", + "line": 1, + "column": 0, + "end_line": 1, + "end_column": 11 + }, + { + "node": { + "type": "Assert", + "test": { + "node": { + "type": "Compare", + "left": { + "node": { + "type": "NumberLit", + "binary_suffix": null, + "value": { + "type": "Int", + "value": 1 + } + }, + "filename": "assert-if-0.k", + "line": 2, + "column": 7, + "end_line": 2, + "end_column": 8 + }, + "ops": [ + "Eq" + ], + "comparators": [ + { + "node": { + "type": "NumberLit", + "binary_suffix": null, + "value": { + "type": "Int", + "value": 1 + } + }, + "filename": "assert-if-0.k", + "line": 2, + "column": 12, + "end_line": 2, + "end_column": 13 + } + ] + }, + "filename": "assert-if-0.k", + "line": 2, + "column": 7, + "end_line": 2, + "end_column": 13 + }, + "if_cond": { + "node": { + "type": "NameConstantLit", + "value": "True" + }, + "filename": "assert-if-0.k", + "line": 2, + "column": 17, + "end_line": 2, + "end_column": 21 + }, + "msg": null + }, + "filename": "assert-if-0.k", + "line": 2, + "column": 0, + "end_line": 2, + "end_column": 21 + }, + { + "node": { + "type": "Assign", + "targets": [ + { + "node": { + "name": { + "node": "_x", + "filename": "assert-if-0.k", + "line": 3, + "column": 0, + "end_line": 3, + "end_column": 2 + }, + "paths": [], + "pkgpath": "" + }, + "filename": "assert-if-0.k", + "line": 3, + "column": 0, + "end_line": 3, + "end_column": 2 + } + ], + "value": { + "node": { + "type": "StringLit", + "is_long_string": false, + "raw_value": "\"good case\"", + "value": "good case" + }, + "filename": "assert-if-0.k", + "line": 3, + "column": 5, + "end_line": 3, + "end_column": 16 + }, + "ty": null + }, + "filename": "assert-if-0.k", + "line": 3, + "column": 0, + "end_line": 3, + "end_column": 16 + }, + { + "node": { + "type": "Assert", + "test": { + "node": { + "type": "Compare", + "left": { + "node": { + "type": "Identifier", + "names": [ + { + "node": "_x", + "filename": "assert-if-0.k", + "line": 4, + "column": 7, + "end_line": 4, + "end_column": 9 + } + ], + "pkgpath": "", + "ctx": "Load" + }, + "filename": "assert-if-0.k", + "line": 4, + "column": 7, + "end_line": 4, + "end_column": 9 + }, + "ops": [ + "Eq" + ], + "comparators": [ + { + "node": { + "type": "StringLit", + "is_long_string": false, + "raw_value": "\"good case\"", + "value": "good case" + }, + "filename": "assert-if-0.k", + "line": 4, + "column": 13, + "end_line": 4, + "end_column": 24 + } + ] + }, + "filename": "assert-if-0.k", + "line": 4, + "column": 7, + "end_line": 4, + "end_column": 24 + }, + "if_cond": { + "node": { + "type": "Identifier", + "names": [ + { + "node": "_x", + "filename": "assert-if-0.k", + "line": 4, + "column": 28, + "end_line": 4, + "end_column": 30 + } + ], + "pkgpath": "", + "ctx": "Load" + }, + "filename": "assert-if-0.k", + "line": 4, + "column": 28, + "end_line": 4, + "end_column": 30 + }, + "msg": { + "node": { + "type": "StringLit", + "is_long_string": false, + "raw_value": "\"_x need to be 'good case'\"", + "value": "_x need to be 'good case'" + }, + "filename": "assert-if-0.k", + "line": 4, + "column": 32, + "end_line": 4, + "end_column": 59 + } + }, + "filename": "assert-if-0.k", + "line": 4, + "column": 0, + "end_line": 4, + "end_column": 59 + } + ], + "comments": [] +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__file__assert_if_1.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__file__assert_if_1.snap new file mode 100644 index 000000000..ccdaa2edb --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__file__assert_if_1.snap @@ -0,0 +1,262 @@ +--- +source: parser/src/tests/file.rs +expression: "crate::tests::parsing_file_string(\"testdata/assert-if-1.k\")" +--- +{ + "filename": "assert-if-1.k", + "doc": null, + "body": [ + { + "node": { + "type": "Assert", + "test": { + "node": { + "type": "NameConstantLit", + "value": "True" + }, + "filename": "assert-if-1.k", + "line": 1, + "column": 7, + "end_line": 1, + "end_column": 11 + }, + "if_cond": { + "node": { + "type": "NameConstantLit", + "value": "False" + }, + "filename": "assert-if-1.k", + "line": 1, + "column": 15, + "end_line": 1, + "end_column": 20 + }, + "msg": null + }, + "filename": "assert-if-1.k", + "line": 1, + "column": 0, + "end_line": 1, + "end_column": 20 + }, + { + "node": { + "type": "Assert", + "test": { + "node": { + "type": "Compare", + "left": { + "node": { + "type": "NumberLit", + "binary_suffix": null, + "value": { + "type": "Int", + "value": 1 + } + }, + "filename": "assert-if-1.k", + "line": 2, + "column": 7, + "end_line": 2, + "end_column": 8 + }, + "ops": [ + "Eq" + ], + "comparators": [ + { + "node": { + "type": "NumberLit", + "binary_suffix": null, + "value": { + "type": "Int", + "value": 1 + } + }, + "filename": "assert-if-1.k", + "line": 2, + "column": 12, + "end_line": 2, + "end_column": 13 + } + ] + }, + "filename": "assert-if-1.k", + "line": 2, + "column": 7, + "end_line": 2, + "end_column": 13 + }, + "if_cond": { + "node": { + "type": "NameConstantLit", + "value": "False" + }, + "filename": "assert-if-1.k", + "line": 2, + "column": 17, + "end_line": 2, + "end_column": 22 + }, + "msg": null + }, + "filename": "assert-if-1.k", + "line": 2, + "column": 0, + "end_line": 2, + "end_column": 22 + }, + { + "node": { + "type": "Assign", + "targets": [ + { + "node": { + "name": { + "node": "_x", + "filename": "assert-if-1.k", + "line": 3, + "column": 0, + "end_line": 3, + "end_column": 2 + }, + "paths": [], + "pkgpath": "" + }, + "filename": "assert-if-1.k", + "line": 3, + "column": 0, + "end_line": 3, + "end_column": 2 + } + ], + "value": { + "node": { + "type": "StringLit", + "is_long_string": false, + "raw_value": "\"good case\"", + "value": "good case" + }, + "filename": "assert-if-1.k", + "line": 3, + "column": 5, + "end_line": 3, + "end_column": 16 + }, + "ty": null + }, + "filename": "assert-if-1.k", + "line": 3, + "column": 0, + "end_line": 3, + "end_column": 16 + }, + { + "node": { + "type": "Assert", + "test": { + "node": { + "type": "Compare", + "left": { + "node": { + "type": "Identifier", + "names": [ + { + "node": "_x", + "filename": "assert-if-1.k", + "line": 4, + "column": 7, + "end_line": 4, + "end_column": 9 + } + ], + "pkgpath": "", + "ctx": "Load" + }, + "filename": "assert-if-1.k", + "line": 4, + "column": 7, + "end_line": 4, + "end_column": 9 + }, + "ops": [ + "Eq" + ], + "comparators": [ + { + "node": { + "type": "StringLit", + "is_long_string": false, + "raw_value": "\"good case\"", + "value": "good case" + }, + "filename": "assert-if-1.k", + "line": 4, + "column": 13, + "end_line": 4, + "end_column": 24 + } + ] + }, + "filename": "assert-if-1.k", + "line": 4, + "column": 7, + "end_line": 4, + "end_column": 24 + }, + "if_cond": { + "node": { + "type": "Unary", + "op": "Not", + "operand": { + "node": { + "type": "Identifier", + "names": [ + { + "node": "_x", + "filename": "assert-if-1.k", + "line": 4, + "column": 32, + "end_line": 4, + "end_column": 34 + } + ], + "pkgpath": "", + "ctx": "Load" + }, + "filename": "assert-if-1.k", + "line": 4, + "column": 32, + "end_line": 4, + "end_column": 34 + } + }, + "filename": "assert-if-1.k", + "line": 4, + "column": 28, + "end_line": 4, + "end_column": 34 + }, + "msg": { + "node": { + "type": "StringLit", + "is_long_string": false, + "raw_value": "\"_x need to be 'good case'\"", + "value": "_x need to be 'good case'" + }, + "filename": "assert-if-1.k", + "line": 4, + "column": 36, + "end_line": 4, + "end_column": 63 + } + }, + "filename": "assert-if-1.k", + "line": 4, + "column": 0, + "end_line": 4, + "end_column": 63 + } + ], + "comments": [] +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__file__assert_if_2.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__file__assert_if_2.snap new file mode 100644 index 000000000..38a807578 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__file__assert_if_2.snap @@ -0,0 +1,368 @@ +--- +source: parser/src/tests/file.rs +expression: "crate::tests::parsing_file_string(\"testdata/assert-if-2.k\")" +--- +{ + "filename": "assert-if-2.k", + "doc": null, + "body": [ + { + "node": { + "type": "Schema", + "doc": null, + "name": { + "node": "Data", + "filename": "assert-if-2.k", + "line": 1, + "column": 7, + "end_line": 1, + "end_column": 11 + }, + "parent_name": null, + "for_host_name": null, + "is_mixin": false, + "is_protocol": false, + "args": null, + "mixins": [], + "body": [ + { + "node": { + "type": "Assert", + "test": { + "node": { + "type": "NameConstantLit", + "value": "True" + }, + "filename": "assert-if-2.k", + "line": 2, + "column": 11, + "end_line": 2, + "end_column": 15 + }, + "if_cond": { + "node": { + "type": "NameConstantLit", + "value": "False" + }, + "filename": "assert-if-2.k", + "line": 2, + "column": 19, + "end_line": 2, + "end_column": 24 + }, + "msg": null + }, + "filename": "assert-if-2.k", + "line": 2, + "column": 4, + "end_line": 2, + "end_column": 24 + }, + { + "node": { + "type": "Assert", + "test": { + "node": { + "type": "Compare", + "left": { + "node": { + "type": "NumberLit", + "binary_suffix": null, + "value": { + "type": "Int", + "value": 1 + } + }, + "filename": "assert-if-2.k", + "line": 3, + "column": 11, + "end_line": 3, + "end_column": 12 + }, + "ops": [ + "Eq" + ], + "comparators": [ + { + "node": { + "type": "NumberLit", + "binary_suffix": null, + "value": { + "type": "Int", + "value": 1 + } + }, + "filename": "assert-if-2.k", + "line": 3, + "column": 16, + "end_line": 3, + "end_column": 17 + } + ] + }, + "filename": "assert-if-2.k", + "line": 3, + "column": 11, + "end_line": 3, + "end_column": 17 + }, + "if_cond": { + "node": { + "type": "NameConstantLit", + "value": "False" + }, + "filename": "assert-if-2.k", + "line": 3, + "column": 21, + "end_line": 3, + "end_column": 26 + }, + "msg": null + }, + "filename": "assert-if-2.k", + "line": 3, + "column": 4, + "end_line": 3, + "end_column": 26 + }, + { + "node": { + "type": "Assign", + "targets": [ + { + "node": { + "name": { + "node": "_x", + "filename": "assert-if-2.k", + "line": 4, + "column": 4, + "end_line": 4, + "end_column": 6 + }, + "paths": [], + "pkgpath": "" + }, + "filename": "assert-if-2.k", + "line": 4, + "column": 4, + "end_line": 4, + "end_column": 6 + } + ], + "value": { + "node": { + "type": "StringLit", + "is_long_string": false, + "raw_value": "\"good case\"", + "value": "good case" + }, + "filename": "assert-if-2.k", + "line": 4, + "column": 9, + "end_line": 4, + "end_column": 20 + }, + "ty": null + }, + "filename": "assert-if-2.k", + "line": 4, + "column": 4, + "end_line": 4, + "end_column": 20 + }, + { + "node": { + "type": "Assert", + "test": { + "node": { + "type": "Compare", + "left": { + "node": { + "type": "Identifier", + "names": [ + { + "node": "_x", + "filename": "assert-if-2.k", + "line": 5, + "column": 11, + "end_line": 5, + "end_column": 13 + } + ], + "pkgpath": "", + "ctx": "Load" + }, + "filename": "assert-if-2.k", + "line": 5, + "column": 11, + "end_line": 5, + "end_column": 13 + }, + "ops": [ + "Eq" + ], + "comparators": [ + { + "node": { + "type": "StringLit", + "is_long_string": false, + "raw_value": "\"good case\"", + "value": "good case" + }, + "filename": "assert-if-2.k", + "line": 5, + "column": 17, + "end_line": 5, + "end_column": 28 + } + ] + }, + "filename": "assert-if-2.k", + "line": 5, + "column": 11, + "end_line": 5, + "end_column": 28 + }, + "if_cond": { + "node": { + "type": "Unary", + "op": "Not", + "operand": { + "node": { + "type": "Identifier", + "names": [ + { + "node": "_x", + "filename": "assert-if-2.k", + "line": 5, + "column": 36, + "end_line": 5, + "end_column": 38 + } + ], + "pkgpath": "", + "ctx": "Load" + }, + "filename": "assert-if-2.k", + "line": 5, + "column": 36, + "end_line": 5, + "end_column": 38 + } + }, + "filename": "assert-if-2.k", + "line": 5, + "column": 32, + "end_line": 5, + "end_column": 38 + }, + "msg": { + "node": { + "type": "StringLit", + "is_long_string": false, + "raw_value": "\"_x need to be 'good case'\"", + "value": "_x need to be 'good case'" + }, + "filename": "assert-if-2.k", + "line": 5, + "column": 40, + "end_line": 5, + "end_column": 67 + } + }, + "filename": "assert-if-2.k", + "line": 5, + "column": 4, + "end_line": 5, + "end_column": 67 + } + ], + "decorators": [], + "checks": [], + "index_signature": null + }, + "filename": "assert-if-2.k", + "line": 1, + "column": 0, + "end_line": 7, + "end_column": 0 + }, + { + "node": { + "type": "Assign", + "targets": [ + { + "node": { + "name": { + "node": "data", + "filename": "assert-if-2.k", + "line": 7, + "column": 0, + "end_line": 7, + "end_column": 4 + }, + "paths": [], + "pkgpath": "" + }, + "filename": "assert-if-2.k", + "line": 7, + "column": 0, + "end_line": 7, + "end_column": 4 + } + ], + "value": { + "node": { + "type": "Schema", + "name": { + "node": { + "names": [ + { + "node": "Data", + "filename": "assert-if-2.k", + "line": 7, + "column": 7, + "end_line": 7, + "end_column": 11 + } + ], + "pkgpath": "", + "ctx": "Load" + }, + "filename": "assert-if-2.k", + "line": 7, + "column": 7, + "end_line": 7, + "end_column": 11 + }, + "args": [], + "kwargs": [], + "config": { + "node": { + "type": "Config", + "items": [] + }, + "filename": "assert-if-2.k", + "line": 7, + "column": 12, + "end_line": 7, + "end_column": 14 + } + }, + "filename": "assert-if-2.k", + "line": 7, + "column": 7, + "end_line": 7, + "end_column": 14 + }, + "ty": null + }, + "filename": "assert-if-2.k", + "line": 7, + "column": 0, + "end_line": 7, + "end_column": 14 + } + ], + "comments": [] +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__file__assign_1.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__file__assign_1.snap new file mode 100644 index 000000000..de61728b9 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__file__assign_1.snap @@ -0,0 +1,230 @@ +--- +source: parser/src/tests/file.rs +expression: "crate::tests::parsing_file_string(\"testdata/assign-01.k\")" +--- +{ + "filename": "assign-01.k", + "doc": null, + "body": [ + { + "node": { + "type": "Assign", + "targets": [ + { + "node": { + "name": { + "node": "a", + "filename": "assign-01.k", + "line": 1, + "column": 0, + "end_line": 1, + "end_column": 1 + }, + "paths": [], + "pkgpath": "" + }, + "filename": "assign-01.k", + "line": 1, + "column": 0, + "end_line": 1, + "end_column": 1 + } + ], + "value": { + "node": { + "type": "NumberLit", + "binary_suffix": null, + "value": { + "type": "Int", + "value": 1 + } + }, + "filename": "assign-01.k", + "line": 1, + "column": 2, + "end_line": 1, + "end_column": 3 + }, + "ty": null + }, + "filename": "assign-01.k", + "line": 1, + "column": 0, + "end_line": 1, + "end_column": 3 + }, + { + "node": { + "type": "Assign", + "targets": [ + { + "node": { + "name": { + "node": "b", + "filename": "assign-01.k", + "line": 2, + "column": 0, + "end_line": 2, + "end_column": 1 + }, + "paths": [], + "pkgpath": "" + }, + "filename": "assign-01.k", + "line": 2, + "column": 0, + "end_line": 2, + "end_column": 1 + } + ], + "value": { + "node": { + "type": "Binary", + "left": { + "node": { + "type": "NumberLit", + "binary_suffix": null, + "value": { + "type": "Int", + "value": 1 + } + }, + "filename": "assign-01.k", + "line": 2, + "column": 4, + "end_line": 2, + "end_column": 5 + }, + "op": "Add", + "right": { + "node": { + "type": "NumberLit", + "binary_suffix": null, + "value": { + "type": "Int", + "value": 2 + } + }, + "filename": "assign-01.k", + "line": 2, + "column": 8, + "end_line": 2, + "end_column": 9 + } + }, + "filename": "assign-01.k", + "line": 2, + "column": 4, + "end_line": 2, + "end_column": 9 + }, + "ty": null + }, + "filename": "assign-01.k", + "line": 2, + "column": 0, + "end_line": 2, + "end_column": 9 + }, + { + "node": { + "type": "Assign", + "targets": [ + { + "node": { + "name": { + "node": "c", + "filename": "assign-01.k", + "line": 3, + "column": 0, + "end_line": 3, + "end_column": 1 + }, + "paths": [], + "pkgpath": "" + }, + "filename": "assign-01.k", + "line": 3, + "column": 0, + "end_line": 3, + "end_column": 1 + } + ], + "value": { + "node": { + "type": "Binary", + "left": { + "node": { + "type": "NumberLit", + "binary_suffix": null, + "value": { + "type": "Int", + "value": 2 + } + }, + "filename": "assign-01.k", + "line": 3, + "column": 4, + "end_line": 3, + "end_column": 5 + }, + "op": "Add", + "right": { + "node": { + "type": "Binary", + "left": { + "node": { + "type": "NumberLit", + "binary_suffix": null, + "value": { + "type": "Int", + "value": 2 + } + }, + "filename": "assign-01.k", + "line": 3, + "column": 8, + "end_line": 3, + "end_column": 9 + }, + "op": "Mul", + "right": { + "node": { + "type": "NumberLit", + "binary_suffix": null, + "value": { + "type": "Int", + "value": 3 + } + }, + "filename": "assign-01.k", + "line": 3, + "column": 10, + "end_line": 3, + "end_column": 11 + } + }, + "filename": "assign-01.k", + "line": 3, + "column": 8, + "end_line": 3, + "end_column": 11 + } + }, + "filename": "assign-01.k", + "line": 3, + "column": 4, + "end_line": 3, + "end_column": 11 + }, + "ty": null + }, + "filename": "assign-01.k", + "line": 3, + "column": 0, + "end_line": 3, + "end_column": 11 + } + ], + "comments": [] +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__file__config_expr_1.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__file__config_expr_1.snap new file mode 100644 index 000000000..f4162051e --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__file__config_expr_1.snap @@ -0,0 +1,54 @@ +--- +source: parser/src/tests/file.rs +expression: "crate::tests::parsing_file_string(\"testdata/config_expr-01.k\")" +--- +{ + "filename": "config_expr-01.k", + "doc": null, + "body": [ + { + "node": { + "type": "Assign", + "targets": [ + { + "node": { + "name": { + "node": "config", + "filename": "config_expr-01.k", + "line": 1, + "column": 0, + "end_line": 1, + "end_column": 6 + }, + "paths": [], + "pkgpath": "" + }, + "filename": "config_expr-01.k", + "line": 1, + "column": 0, + "end_line": 1, + "end_column": 6 + } + ], + "value": { + "node": { + "type": "Config", + "items": [] + }, + "filename": "config_expr-01.k", + "line": 1, + "column": 9, + "end_line": 2, + "end_column": 1 + }, + "ty": null + }, + "filename": "config_expr-01.k", + "line": 1, + "column": 0, + "end_line": 2, + "end_column": 1 + } + ], + "comments": [] +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__file__config_expr_2.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__file__config_expr_2.snap new file mode 100644 index 000000000..dd2937192 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__file__config_expr_2.snap @@ -0,0 +1,149 @@ +--- +source: parser/src/tests/file.rs +expression: "crate::tests::parsing_file_string(\"testdata/config_expr-02.k\")" +--- +{ + "filename": "config_expr-02.k", + "doc": null, + "body": [ + { + "node": { + "type": "Assign", + "targets": [ + { + "node": { + "name": { + "node": "config", + "filename": "config_expr-02.k", + "line": 1, + "column": 0, + "end_line": 1, + "end_column": 6 + }, + "paths": [], + "pkgpath": "" + }, + "filename": "config_expr-02.k", + "line": 1, + "column": 0, + "end_line": 1, + "end_column": 6 + } + ], + "value": { + "node": { + "type": "Config", + "items": [ + { + "node": { + "key": { + "node": { + "type": "Identifier", + "names": [ + { + "node": "k1", + "filename": "config_expr-02.k", + "line": 2, + "column": 4, + "end_line": 2, + "end_column": 6 + } + ], + "pkgpath": "", + "ctx": "Load" + }, + "filename": "config_expr-02.k", + "line": 2, + "column": 4, + "end_line": 2, + "end_column": 6 + }, + "value": { + "node": { + "type": "NumberLit", + "binary_suffix": null, + "value": { + "type": "Int", + "value": 111 + } + }, + "filename": "config_expr-02.k", + "line": 2, + "column": 9, + "end_line": 2, + "end_column": 12 + }, + "operation": "Override" + }, + "filename": "config_expr-02.k", + "line": 2, + "column": 4, + "end_line": 2, + "end_column": 12 + }, + { + "node": { + "key": { + "node": { + "type": "Identifier", + "names": [ + { + "node": "k2", + "filename": "config_expr-02.k", + "line": 3, + "column": 4, + "end_line": 3, + "end_column": 6 + } + ], + "pkgpath": "", + "ctx": "Load" + }, + "filename": "config_expr-02.k", + "line": 3, + "column": 4, + "end_line": 3, + "end_column": 6 + }, + "value": { + "node": { + "type": "NumberLit", + "binary_suffix": null, + "value": { + "type": "Int", + "value": 222 + } + }, + "filename": "config_expr-02.k", + "line": 3, + "column": 9, + "end_line": 3, + "end_column": 12 + }, + "operation": "Override" + }, + "filename": "config_expr-02.k", + "line": 3, + "column": 4, + "end_line": 3, + "end_column": 12 + } + ] + }, + "filename": "config_expr-02.k", + "line": 1, + "column": 9, + "end_line": 4, + "end_column": 1 + }, + "ty": null + }, + "filename": "config_expr-02.k", + "line": 1, + "column": 0, + "end_line": 4, + "end_column": 1 + } + ], + "comments": [] +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__file__config_expr_3.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__file__config_expr_3.snap new file mode 100644 index 000000000..5a893eaca --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__file__config_expr_3.snap @@ -0,0 +1,448 @@ +--- +source: parser/src/tests/file.rs +expression: "crate::tests::parsing_file_string(\"testdata/config_expr-03.k\")" +--- +{ + "filename": "config_expr-03.k", + "doc": null, + "body": [ + { + "node": { + "type": "Assign", + "targets": [ + { + "node": { + "name": { + "node": "config", + "filename": "config_expr-03.k", + "line": 3, + "column": 0, + "end_line": 3, + "end_column": 6 + }, + "paths": [], + "pkgpath": "" + }, + "filename": "config_expr-03.k", + "line": 3, + "column": 0, + "end_line": 3, + "end_column": 6 + } + ], + "value": { + "node": { + "type": "Config", + "items": [ + { + "node": { + "key": { + "node": { + "type": "Identifier", + "names": [ + { + "node": "main", + "filename": "config_expr-03.k", + "line": 4, + "column": 4, + "end_line": 4, + "end_column": 8 + } + ], + "pkgpath": "", + "ctx": "Load" + }, + "filename": "config_expr-03.k", + "line": 4, + "column": 4, + "end_line": 4, + "end_column": 8 + }, + "value": { + "node": { + "type": "Config", + "items": [ + { + "node": { + "key": { + "node": { + "type": "Identifier", + "names": [ + { + "node": "env", + "filename": "config_expr-03.k", + "line": 5, + "column": 8, + "end_line": 5, + "end_column": 11 + } + ], + "pkgpath": "", + "ctx": "Load" + }, + "filename": "config_expr-03.k", + "line": 5, + "column": 8, + "end_line": 5, + "end_column": 11 + }, + "value": { + "node": { + "type": "List", + "elts": [ + { + "node": { + "type": "Config", + "items": [ + { + "node": { + "key": { + "node": { + "type": "Identifier", + "names": [ + { + "node": "name", + "filename": "config_expr-03.k", + "line": 6, + "column": 13, + "end_line": 6, + "end_column": 17 + } + ], + "pkgpath": "", + "ctx": "Load" + }, + "filename": "config_expr-03.k", + "line": 6, + "column": 13, + "end_line": 6, + "end_column": 17 + }, + "value": { + "node": { + "type": "StringLit", + "is_long_string": false, + "raw_value": "\"ENV_1\"", + "value": "ENV_1" + }, + "filename": "config_expr-03.k", + "line": 6, + "column": 19, + "end_line": 6, + "end_column": 26 + }, + "operation": "Union" + }, + "filename": "config_expr-03.k", + "line": 6, + "column": 13, + "end_line": 6, + "end_column": 26 + }, + { + "node": { + "key": { + "node": { + "type": "Identifier", + "names": [ + { + "node": "value", + "filename": "config_expr-03.k", + "line": 6, + "column": 28, + "end_line": 6, + "end_column": 33 + } + ], + "pkgpath": "", + "ctx": "Load" + }, + "filename": "config_expr-03.k", + "line": 6, + "column": 28, + "end_line": 6, + "end_column": 33 + }, + "value": { + "node": { + "type": "StringLit", + "is_long_string": false, + "raw_value": "\"1\"", + "value": "1" + }, + "filename": "config_expr-03.k", + "line": 6, + "column": 35, + "end_line": 6, + "end_column": 38 + }, + "operation": "Union" + }, + "filename": "config_expr-03.k", + "line": 6, + "column": 28, + "end_line": 6, + "end_column": 38 + } + ] + }, + "filename": "config_expr-03.k", + "line": 6, + "column": 12, + "end_line": 6, + "end_column": 39 + } + ], + "ctx": "Load" + }, + "filename": "config_expr-03.k", + "line": 5, + "column": 13, + "end_line": 7, + "end_column": 9 + }, + "operation": "Union" + }, + "filename": "config_expr-03.k", + "line": 5, + "column": 8, + "end_line": 7, + "end_column": 9 + } + ] + }, + "filename": "config_expr-03.k", + "line": 4, + "column": 10, + "end_line": 8, + "end_column": 5 + }, + "operation": "Union" + }, + "filename": "config_expr-03.k", + "line": 4, + "column": 4, + "end_line": 8, + "end_column": 5 + }, + { + "node": { + "key": { + "node": { + "type": "Identifier", + "names": [ + { + "node": "main", + "filename": "config_expr-03.k", + "line": 9, + "column": 4, + "end_line": 9, + "end_column": 8 + } + ], + "pkgpath": "", + "ctx": "Load" + }, + "filename": "config_expr-03.k", + "line": 9, + "column": 4, + "end_line": 9, + "end_column": 8 + }, + "value": { + "node": { + "type": "Config", + "items": [ + { + "node": { + "key": { + "node": { + "type": "Identifier", + "names": [ + { + "node": "env", + "filename": "config_expr-03.k", + "line": 10, + "column": 8, + "end_line": 10, + "end_column": 11 + } + ], + "pkgpath": "", + "ctx": "Load" + }, + "filename": "config_expr-03.k", + "line": 10, + "column": 8, + "end_line": 10, + "end_column": 11 + }, + "value": { + "node": { + "type": "List", + "elts": [ + { + "node": { + "type": "Config", + "items": [ + { + "node": { + "key": { + "node": { + "type": "Identifier", + "names": [ + { + "node": "name", + "filename": "config_expr-03.k", + "line": 11, + "column": 13, + "end_line": 11, + "end_column": 17 + } + ], + "pkgpath": "", + "ctx": "Load" + }, + "filename": "config_expr-03.k", + "line": 11, + "column": 13, + "end_line": 11, + "end_column": 17 + }, + "value": { + "node": { + "type": "StringLit", + "is_long_string": false, + "raw_value": "\"ENV_2\"", + "value": "ENV_2" + }, + "filename": "config_expr-03.k", + "line": 11, + "column": 19, + "end_line": 11, + "end_column": 26 + }, + "operation": "Union" + }, + "filename": "config_expr-03.k", + "line": 11, + "column": 13, + "end_line": 11, + "end_column": 26 + }, + { + "node": { + "key": { + "node": { + "type": "Identifier", + "names": [ + { + "node": "value", + "filename": "config_expr-03.k", + "line": 11, + "column": 28, + "end_line": 11, + "end_column": 33 + } + ], + "pkgpath": "", + "ctx": "Load" + }, + "filename": "config_expr-03.k", + "line": 11, + "column": 28, + "end_line": 11, + "end_column": 33 + }, + "value": { + "node": { + "type": "StringLit", + "is_long_string": false, + "raw_value": "\"2\"", + "value": "2" + }, + "filename": "config_expr-03.k", + "line": 11, + "column": 35, + "end_line": 11, + "end_column": 38 + }, + "operation": "Union" + }, + "filename": "config_expr-03.k", + "line": 11, + "column": 28, + "end_line": 11, + "end_column": 38 + } + ] + }, + "filename": "config_expr-03.k", + "line": 11, + "column": 12, + "end_line": 11, + "end_column": 39 + } + ], + "ctx": "Load" + }, + "filename": "config_expr-03.k", + "line": 10, + "column": 15, + "end_line": 12, + "end_column": 9 + }, + "operation": "Insert" + }, + "filename": "config_expr-03.k", + "line": 10, + "column": 8, + "end_line": 12, + "end_column": 9 + } + ] + }, + "filename": "config_expr-03.k", + "line": 9, + "column": 10, + "end_line": 13, + "end_column": 5 + }, + "operation": "Union" + }, + "filename": "config_expr-03.k", + "line": 9, + "column": 4, + "end_line": 13, + "end_column": 5 + } + ] + }, + "filename": "config_expr-03.k", + "line": 3, + "column": 9, + "end_line": 14, + "end_column": 1 + }, + "ty": null + }, + "filename": "config_expr-03.k", + "line": 3, + "column": 0, + "end_line": 14, + "end_column": 1 + } + ], + "comments": [ + { + "node": { + "text": "# test/grammar/attr_operator/config_inside/insert/dict_0/main.k" + }, + "filename": "config_expr-03.k", + "line": 1, + "column": 0, + "end_line": 1, + "end_column": 63 + } + ] +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__file__config_expr_4.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__file__config_expr_4.snap new file mode 100644 index 000000000..03043661b --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__file__config_expr_4.snap @@ -0,0 +1,865 @@ +--- +source: parser/src/tests/file.rs +expression: "crate::tests::parsing_file_string(\"testdata/config_expr-04.k\")" +--- +{ + "filename": "config_expr-04.k", + "doc": null, + "body": [ + { + "node": { + "type": "Schema", + "doc": null, + "name": { + "node": "Env", + "filename": "config_expr-04.k", + "line": 3, + "column": 7, + "end_line": 3, + "end_column": 10 + }, + "parent_name": null, + "for_host_name": null, + "is_mixin": false, + "is_protocol": false, + "args": null, + "mixins": [], + "body": [ + { + "node": { + "type": "SchemaAttr", + "doc": "", + "name": { + "node": "name", + "filename": "config_expr-04.k", + "line": 4, + "column": 4, + "end_line": 4, + "end_column": 8 + }, + "op": null, + "value": null, + "is_optional": false, + "decorators": [], + "ty": { + "node": { + "type": "Basic", + "value": "Str" + }, + "filename": "config_expr-04.k", + "line": 4, + "column": 10, + "end_line": 4, + "end_column": 13 + } + }, + "filename": "config_expr-04.k", + "line": 4, + "column": 4, + "end_line": 4, + "end_column": 13 + }, + { + "node": { + "type": "SchemaAttr", + "doc": "", + "name": { + "node": "value", + "filename": "config_expr-04.k", + "line": 5, + "column": 4, + "end_line": 5, + "end_column": 9 + }, + "op": null, + "value": null, + "is_optional": false, + "decorators": [], + "ty": { + "node": { + "type": "Basic", + "value": "Str" + }, + "filename": "config_expr-04.k", + "line": 5, + "column": 11, + "end_line": 5, + "end_column": 14 + } + }, + "filename": "config_expr-04.k", + "line": 5, + "column": 4, + "end_line": 5, + "end_column": 14 + } + ], + "decorators": [], + "checks": [], + "index_signature": null + }, + "filename": "config_expr-04.k", + "line": 3, + "column": 0, + "end_line": 7, + "end_column": 0 + }, + { + "node": { + "type": "Schema", + "doc": null, + "name": { + "node": "Main", + "filename": "config_expr-04.k", + "line": 7, + "column": 7, + "end_line": 7, + "end_column": 11 + }, + "parent_name": null, + "for_host_name": null, + "is_mixin": false, + "is_protocol": false, + "args": null, + "mixins": [], + "body": [ + { + "node": { + "type": "SchemaAttr", + "doc": "", + "name": { + "node": "env", + "filename": "config_expr-04.k", + "line": 8, + "column": 4, + "end_line": 8, + "end_column": 7 + }, + "op": null, + "value": null, + "is_optional": false, + "decorators": [], + "ty": { + "node": { + "type": "List", + "value": { + "inner_type": { + "node": { + "type": "Named", + "value": { + "names": [ + { + "node": "Env", + "filename": "config_expr-04.k", + "line": 8, + "column": 10, + "end_line": 8, + "end_column": 13 + } + ], + "pkgpath": "", + "ctx": "Load" + } + }, + "filename": "config_expr-04.k", + "line": 8, + "column": 10, + "end_line": 8, + "end_column": 13 + } + } + }, + "filename": "config_expr-04.k", + "line": 8, + "column": 9, + "end_line": 8, + "end_column": 14 + } + }, + "filename": "config_expr-04.k", + "line": 8, + "column": 4, + "end_line": 8, + "end_column": 14 + } + ], + "decorators": [], + "checks": [], + "index_signature": null + }, + "filename": "config_expr-04.k", + "line": 7, + "column": 0, + "end_line": 10, + "end_column": 0 + }, + { + "node": { + "type": "Schema", + "doc": null, + "name": { + "node": "Config", + "filename": "config_expr-04.k", + "line": 10, + "column": 7, + "end_line": 10, + "end_column": 13 + }, + "parent_name": null, + "for_host_name": null, + "is_mixin": false, + "is_protocol": false, + "args": null, + "mixins": [], + "body": [ + { + "node": { + "type": "SchemaAttr", + "doc": "", + "name": { + "node": "main", + "filename": "config_expr-04.k", + "line": 11, + "column": 4, + "end_line": 11, + "end_column": 8 + }, + "op": null, + "value": null, + "is_optional": false, + "decorators": [], + "ty": { + "node": { + "type": "Named", + "value": { + "names": [ + { + "node": "Main", + "filename": "config_expr-04.k", + "line": 11, + "column": 10, + "end_line": 11, + "end_column": 14 + } + ], + "pkgpath": "", + "ctx": "Load" + } + }, + "filename": "config_expr-04.k", + "line": 11, + "column": 10, + "end_line": 11, + "end_column": 14 + } + }, + "filename": "config_expr-04.k", + "line": 11, + "column": 4, + "end_line": 11, + "end_column": 14 + } + ], + "decorators": [], + "checks": [], + "index_signature": null + }, + "filename": "config_expr-04.k", + "line": 10, + "column": 0, + "end_line": 13, + "end_column": 0 + }, + { + "node": { + "type": "Assign", + "targets": [ + { + "node": { + "name": { + "node": "_main", + "filename": "config_expr-04.k", + "line": 13, + "column": 0, + "end_line": 13, + "end_column": 5 + }, + "paths": [], + "pkgpath": "" + }, + "filename": "config_expr-04.k", + "line": 13, + "column": 0, + "end_line": 13, + "end_column": 5 + } + ], + "value": { + "node": { + "type": "Schema", + "name": { + "node": { + "names": [ + { + "node": "Main", + "filename": "config_expr-04.k", + "line": 13, + "column": 8, + "end_line": 13, + "end_column": 12 + } + ], + "pkgpath": "", + "ctx": "Load" + }, + "filename": "config_expr-04.k", + "line": 13, + "column": 8, + "end_line": 13, + "end_column": 12 + }, + "args": [], + "kwargs": [], + "config": { + "node": { + "type": "Config", + "items": [ + { + "node": { + "key": { + "node": { + "type": "Identifier", + "names": [ + { + "node": "env", + "filename": "config_expr-04.k", + "line": 14, + "column": 4, + "end_line": 14, + "end_column": 7 + } + ], + "pkgpath": "", + "ctx": "Load" + }, + "filename": "config_expr-04.k", + "line": 14, + "column": 4, + "end_line": 14, + "end_column": 7 + }, + "value": { + "node": { + "type": "List", + "elts": [ + { + "node": { + "type": "Config", + "items": [ + { + "node": { + "key": { + "node": { + "type": "Identifier", + "names": [ + { + "node": "name", + "filename": "config_expr-04.k", + "line": 15, + "column": 9, + "end_line": 15, + "end_column": 13 + } + ], + "pkgpath": "", + "ctx": "Load" + }, + "filename": "config_expr-04.k", + "line": 15, + "column": 9, + "end_line": 15, + "end_column": 13 + }, + "value": { + "node": { + "type": "StringLit", + "is_long_string": false, + "raw_value": "\"ENV_1\"", + "value": "ENV_1" + }, + "filename": "config_expr-04.k", + "line": 15, + "column": 15, + "end_line": 15, + "end_column": 22 + }, + "operation": "Union" + }, + "filename": "config_expr-04.k", + "line": 15, + "column": 9, + "end_line": 15, + "end_column": 22 + }, + { + "node": { + "key": { + "node": { + "type": "Identifier", + "names": [ + { + "node": "value", + "filename": "config_expr-04.k", + "line": 15, + "column": 24, + "end_line": 15, + "end_column": 29 + } + ], + "pkgpath": "", + "ctx": "Load" + }, + "filename": "config_expr-04.k", + "line": 15, + "column": 24, + "end_line": 15, + "end_column": 29 + }, + "value": { + "node": { + "type": "StringLit", + "is_long_string": false, + "raw_value": "\"1\"", + "value": "1" + }, + "filename": "config_expr-04.k", + "line": 15, + "column": 31, + "end_line": 15, + "end_column": 34 + }, + "operation": "Union" + }, + "filename": "config_expr-04.k", + "line": 15, + "column": 24, + "end_line": 15, + "end_column": 34 + } + ] + }, + "filename": "config_expr-04.k", + "line": 15, + "column": 8, + "end_line": 15, + "end_column": 35 + } + ], + "ctx": "Load" + }, + "filename": "config_expr-04.k", + "line": 14, + "column": 9, + "end_line": 16, + "end_column": 5 + }, + "operation": "Union" + }, + "filename": "config_expr-04.k", + "line": 14, + "column": 4, + "end_line": 16, + "end_column": 5 + } + ] + }, + "filename": "config_expr-04.k", + "line": 13, + "column": 13, + "end_line": 17, + "end_column": 1 + } + }, + "filename": "config_expr-04.k", + "line": 13, + "column": 8, + "end_line": 17, + "end_column": 1 + }, + "ty": null + }, + "filename": "config_expr-04.k", + "line": 13, + "column": 0, + "end_line": 17, + "end_column": 1 + }, + { + "node": { + "type": "Assign", + "targets": [ + { + "node": { + "name": { + "node": "config", + "filename": "config_expr-04.k", + "line": 19, + "column": 0, + "end_line": 19, + "end_column": 6 + }, + "paths": [], + "pkgpath": "" + }, + "filename": "config_expr-04.k", + "line": 19, + "column": 0, + "end_line": 19, + "end_column": 6 + } + ], + "value": { + "node": { + "type": "Schema", + "name": { + "node": { + "names": [ + { + "node": "Config", + "filename": "config_expr-04.k", + "line": 19, + "column": 9, + "end_line": 19, + "end_column": 15 + } + ], + "pkgpath": "", + "ctx": "Load" + }, + "filename": "config_expr-04.k", + "line": 19, + "column": 9, + "end_line": 19, + "end_column": 15 + }, + "args": [], + "kwargs": [], + "config": { + "node": { + "type": "Config", + "items": [ + { + "node": { + "key": { + "node": { + "type": "Identifier", + "names": [ + { + "node": "main", + "filename": "config_expr-04.k", + "line": 20, + "column": 4, + "end_line": 20, + "end_column": 8 + } + ], + "pkgpath": "", + "ctx": "Load" + }, + "filename": "config_expr-04.k", + "line": 20, + "column": 4, + "end_line": 20, + "end_column": 8 + }, + "value": { + "node": { + "type": "Identifier", + "names": [ + { + "node": "_main", + "filename": "config_expr-04.k", + "line": 20, + "column": 10, + "end_line": 20, + "end_column": 15 + } + ], + "pkgpath": "", + "ctx": "Load" + }, + "filename": "config_expr-04.k", + "line": 20, + "column": 10, + "end_line": 20, + "end_column": 15 + }, + "operation": "Union" + }, + "filename": "config_expr-04.k", + "line": 20, + "column": 4, + "end_line": 20, + "end_column": 15 + }, + { + "node": { + "key": { + "node": { + "type": "Identifier", + "names": [ + { + "node": "main", + "filename": "config_expr-04.k", + "line": 21, + "column": 4, + "end_line": 21, + "end_column": 8 + } + ], + "pkgpath": "", + "ctx": "Load" + }, + "filename": "config_expr-04.k", + "line": 21, + "column": 4, + "end_line": 21, + "end_column": 8 + }, + "value": { + "node": { + "type": "Schema", + "name": { + "node": { + "names": [ + { + "node": "Main", + "filename": "config_expr-04.k", + "line": 21, + "column": 10, + "end_line": 21, + "end_column": 14 + } + ], + "pkgpath": "", + "ctx": "Load" + }, + "filename": "config_expr-04.k", + "line": 21, + "column": 10, + "end_line": 21, + "end_column": 14 + }, + "args": [], + "kwargs": [], + "config": { + "node": { + "type": "Config", + "items": [ + { + "node": { + "key": { + "node": { + "type": "Identifier", + "names": [ + { + "node": "env", + "filename": "config_expr-04.k", + "line": 22, + "column": 8, + "end_line": 22, + "end_column": 11 + } + ], + "pkgpath": "", + "ctx": "Load" + }, + "filename": "config_expr-04.k", + "line": 22, + "column": 8, + "end_line": 22, + "end_column": 11 + }, + "value": { + "node": { + "type": "List", + "elts": [ + { + "node": { + "type": "Config", + "items": [ + { + "node": { + "key": { + "node": { + "type": "Identifier", + "names": [ + { + "node": "name", + "filename": "config_expr-04.k", + "line": 23, + "column": 13, + "end_line": 23, + "end_column": 17 + } + ], + "pkgpath": "", + "ctx": "Load" + }, + "filename": "config_expr-04.k", + "line": 23, + "column": 13, + "end_line": 23, + "end_column": 17 + }, + "value": { + "node": { + "type": "StringLit", + "is_long_string": false, + "raw_value": "\"ENV_2\"", + "value": "ENV_2" + }, + "filename": "config_expr-04.k", + "line": 23, + "column": 19, + "end_line": 23, + "end_column": 26 + }, + "operation": "Union" + }, + "filename": "config_expr-04.k", + "line": 23, + "column": 13, + "end_line": 23, + "end_column": 26 + }, + { + "node": { + "key": { + "node": { + "type": "Identifier", + "names": [ + { + "node": "value", + "filename": "config_expr-04.k", + "line": 23, + "column": 28, + "end_line": 23, + "end_column": 33 + } + ], + "pkgpath": "", + "ctx": "Load" + }, + "filename": "config_expr-04.k", + "line": 23, + "column": 28, + "end_line": 23, + "end_column": 33 + }, + "value": { + "node": { + "type": "StringLit", + "is_long_string": false, + "raw_value": "\"2\"", + "value": "2" + }, + "filename": "config_expr-04.k", + "line": 23, + "column": 35, + "end_line": 23, + "end_column": 38 + }, + "operation": "Union" + }, + "filename": "config_expr-04.k", + "line": 23, + "column": 28, + "end_line": 23, + "end_column": 38 + } + ] + }, + "filename": "config_expr-04.k", + "line": 23, + "column": 12, + "end_line": 23, + "end_column": 39 + } + ], + "ctx": "Load" + }, + "filename": "config_expr-04.k", + "line": 22, + "column": 15, + "end_line": 24, + "end_column": 9 + }, + "operation": "Insert" + }, + "filename": "config_expr-04.k", + "line": 22, + "column": 8, + "end_line": 24, + "end_column": 9 + } + ] + }, + "filename": "config_expr-04.k", + "line": 21, + "column": 15, + "end_line": 25, + "end_column": 5 + } + }, + "filename": "config_expr-04.k", + "line": 21, + "column": 10, + "end_line": 25, + "end_column": 5 + }, + "operation": "Union" + }, + "filename": "config_expr-04.k", + "line": 21, + "column": 4, + "end_line": 25, + "end_column": 5 + } + ] + }, + "filename": "config_expr-04.k", + "line": 19, + "column": 16, + "end_line": 26, + "end_column": 1 + } + }, + "filename": "config_expr-04.k", + "line": 19, + "column": 9, + "end_line": 26, + "end_column": 1 + }, + "ty": null + }, + "filename": "config_expr-04.k", + "line": 19, + "column": 0, + "end_line": 26, + "end_column": 1 + } + ], + "comments": [ + { + "node": { + "text": "# test/grammar/attr_operator/config_inside/insert/schema_0/main.k" + }, + "filename": "config_expr-04.k", + "line": 1, + "column": 0, + "end_line": 1, + "end_column": 65 + } + ] +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__file__hello_win.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__file__hello_win.snap new file mode 100644 index 000000000..f5ad82a8f --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__file__hello_win.snap @@ -0,0 +1,163 @@ +--- +source: parser/src/tests/file.rs +expression: "crate::tests::parsing_file_string(\"testdata/hello_win.k\")" +--- +{ + "filename": "hello_win.k", + "doc": null, + "body": [ + { + "node": { + "type": "Schema", + "doc": null, + "name": { + "node": "Person", + "filename": "hello_win.k", + "line": 2, + "column": 7, + "end_line": 2, + "end_column": 13 + }, + "parent_name": null, + "for_host_name": null, + "is_mixin": false, + "is_protocol": false, + "args": null, + "mixins": [], + "body": [ + { + "node": { + "type": "SchemaAttr", + "doc": "", + "name": { + "node": "name", + "filename": "hello_win.k", + "line": 3, + "column": 4, + "end_line": 3, + "end_column": 8 + }, + "op": "Assign", + "value": { + "node": { + "type": "StringLit", + "is_long_string": false, + "raw_value": "\"kcl\"", + "value": "kcl" + }, + "filename": "hello_win.k", + "line": 3, + "column": 16, + "end_line": 3, + "end_column": 21 + }, + "is_optional": false, + "decorators": [], + "ty": { + "node": { + "type": "Basic", + "value": "Str" + }, + "filename": "hello_win.k", + "line": 3, + "column": 10, + "end_line": 3, + "end_column": 13 + } + }, + "filename": "hello_win.k", + "line": 3, + "column": 4, + "end_line": 3, + "end_column": 21 + } + ], + "decorators": [], + "checks": [], + "index_signature": null + }, + "filename": "hello_win.k", + "line": 2, + "column": 0, + "end_line": 5, + "end_column": 0 + }, + { + "node": { + "type": "Assign", + "targets": [ + { + "node": { + "name": { + "node": "x0", + "filename": "hello_win.k", + "line": 5, + "column": 0, + "end_line": 5, + "end_column": 2 + }, + "paths": [], + "pkgpath": "" + }, + "filename": "hello_win.k", + "line": 5, + "column": 0, + "end_line": 5, + "end_column": 2 + } + ], + "value": { + "node": { + "type": "Schema", + "name": { + "node": { + "names": [ + { + "node": "Person", + "filename": "hello_win.k", + "line": 5, + "column": 5, + "end_line": 5, + "end_column": 11 + } + ], + "pkgpath": "", + "ctx": "Load" + }, + "filename": "hello_win.k", + "line": 5, + "column": 5, + "end_line": 5, + "end_column": 11 + }, + "args": [], + "kwargs": [], + "config": { + "node": { + "type": "Config", + "items": [] + }, + "filename": "hello_win.k", + "line": 5, + "column": 12, + "end_line": 5, + "end_column": 14 + } + }, + "filename": "hello_win.k", + "line": 5, + "column": 5, + "end_line": 5, + "end_column": 14 + }, + "ty": null + }, + "filename": "hello_win.k", + "line": 5, + "column": 0, + "end_line": 5, + "end_column": 14 + } + ], + "comments": [] +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__file__if_1.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__file__if_1.snap new file mode 100644 index 000000000..4621f8909 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__file__if_1.snap @@ -0,0 +1,140 @@ +--- +source: parser/src/tests/file.rs +expression: "crate::tests::parsing_file_string(\"testdata/if-01.k\")" +--- +{ + "filename": "if-01.k", + "doc": null, + "body": [ + { + "node": { + "type": "Assign", + "targets": [ + { + "node": { + "name": { + "node": "a", + "filename": "if-01.k", + "line": 1, + "column": 0, + "end_line": 1, + "end_column": 1 + }, + "paths": [], + "pkgpath": "" + }, + "filename": "if-01.k", + "line": 1, + "column": 0, + "end_line": 1, + "end_column": 1 + } + ], + "value": { + "node": { + "type": "NumberLit", + "binary_suffix": null, + "value": { + "type": "Int", + "value": 1 + } + }, + "filename": "if-01.k", + "line": 1, + "column": 4, + "end_line": 1, + "end_column": 5 + }, + "ty": null + }, + "filename": "if-01.k", + "line": 1, + "column": 0, + "end_line": 1, + "end_column": 5 + }, + { + "node": { + "type": "If", + "body": [ + { + "node": { + "type": "Assign", + "targets": [ + { + "node": { + "name": { + "node": "bbb", + "filename": "if-01.k", + "line": 4, + "column": 4, + "end_line": 4, + "end_column": 7 + }, + "paths": [], + "pkgpath": "" + }, + "filename": "if-01.k", + "line": 4, + "column": 4, + "end_line": 4, + "end_column": 7 + } + ], + "value": { + "node": { + "type": "NumberLit", + "binary_suffix": null, + "value": { + "type": "Int", + "value": 2 + } + }, + "filename": "if-01.k", + "line": 4, + "column": 10, + "end_line": 4, + "end_column": 11 + }, + "ty": null + }, + "filename": "if-01.k", + "line": 4, + "column": 4, + "end_line": 4, + "end_column": 11 + } + ], + "cond": { + "node": { + "type": "Identifier", + "names": [ + { + "node": "a", + "filename": "if-01.k", + "line": 3, + "column": 3, + "end_line": 3, + "end_column": 4 + } + ], + "pkgpath": "", + "ctx": "Load" + }, + "filename": "if-01.k", + "line": 3, + "column": 3, + "end_line": 3, + "end_column": 4 + }, + "orelse": [] + }, + "filename": "if-01.k", + "line": 3, + "column": 0, + "end_line": 4, + "end_column": 12 + } + ], + "comments": [] +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__file__if_2.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__file__if_2.snap new file mode 100644 index 000000000..fa0d10abb --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__file__if_2.snap @@ -0,0 +1,453 @@ +--- +source: parser/src/tests/file.rs +expression: "crate::tests::parsing_file_string(\"testdata/if-02.k\")" +--- +{ + "filename": "if-02.k", + "doc": null, + "body": [ + { + "node": { + "type": "Assign", + "targets": [ + { + "node": { + "name": { + "node": "a", + "filename": "if-02.k", + "line": 1, + "column": 0, + "end_line": 1, + "end_column": 1 + }, + "paths": [], + "pkgpath": "" + }, + "filename": "if-02.k", + "line": 1, + "column": 0, + "end_line": 1, + "end_column": 1 + } + ], + "value": { + "node": { + "type": "NumberLit", + "binary_suffix": null, + "value": { + "type": "Int", + "value": 1 + } + }, + "filename": "if-02.k", + "line": 1, + "column": 4, + "end_line": 1, + "end_column": 5 + }, + "ty": null + }, + "filename": "if-02.k", + "line": 1, + "column": 0, + "end_line": 1, + "end_column": 5 + }, + { + "node": { + "type": "If", + "body": [ + { + "node": { + "type": "Assign", + "targets": [ + { + "node": { + "name": { + "node": "bbb", + "filename": "if-02.k", + "line": 4, + "column": 4, + "end_line": 4, + "end_column": 7 + }, + "paths": [], + "pkgpath": "" + }, + "filename": "if-02.k", + "line": 4, + "column": 4, + "end_line": 4, + "end_column": 7 + } + ], + "value": { + "node": { + "type": "NumberLit", + "binary_suffix": null, + "value": { + "type": "Int", + "value": 2 + } + }, + "filename": "if-02.k", + "line": 4, + "column": 10, + "end_line": 4, + "end_column": 11 + }, + "ty": null + }, + "filename": "if-02.k", + "line": 4, + "column": 4, + "end_line": 4, + "end_column": 11 + } + ], + "cond": { + "node": { + "type": "Identifier", + "names": [ + { + "node": "a", + "filename": "if-02.k", + "line": 3, + "column": 3, + "end_line": 3, + "end_column": 4 + } + ], + "pkgpath": "", + "ctx": "Load" + }, + "filename": "if-02.k", + "line": 3, + "column": 3, + "end_line": 3, + "end_column": 4 + }, + "orelse": [ + { + "node": { + "type": "If", + "body": [ + { + "node": { + "type": "Assign", + "targets": [ + { + "node": { + "name": { + "node": "ccc", + "filename": "if-02.k", + "line": 6, + "column": 4, + "end_line": 6, + "end_column": 7 + }, + "paths": [], + "pkgpath": "" + }, + "filename": "if-02.k", + "line": 6, + "column": 4, + "end_line": 6, + "end_column": 7 + } + ], + "value": { + "node": { + "type": "NumberLit", + "binary_suffix": null, + "value": { + "type": "Int", + "value": 3 + } + }, + "filename": "if-02.k", + "line": 6, + "column": 10, + "end_line": 6, + "end_column": 11 + }, + "ty": null + }, + "filename": "if-02.k", + "line": 6, + "column": 4, + "end_line": 6, + "end_column": 11 + } + ], + "cond": { + "node": { + "type": "Binary", + "left": { + "node": { + "type": "Identifier", + "names": [ + { + "node": "a", + "filename": "if-02.k", + "line": 5, + "column": 5, + "end_line": 5, + "end_column": 6 + } + ], + "pkgpath": "", + "ctx": "Load" + }, + "filename": "if-02.k", + "line": 5, + "column": 5, + "end_line": 5, + "end_column": 6 + }, + "op": "Add", + "right": { + "node": { + "type": "NumberLit", + "binary_suffix": null, + "value": { + "type": "Int", + "value": 10 + } + }, + "filename": "if-02.k", + "line": 5, + "column": 9, + "end_line": 5, + "end_column": 11 + } + }, + "filename": "if-02.k", + "line": 5, + "column": 5, + "end_line": 5, + "end_column": 11 + }, + "orelse": [ + { + "node": { + "type": "If", + "body": [ + { + "node": { + "type": "Assign", + "targets": [ + { + "node": { + "name": { + "node": "ddd", + "filename": "if-02.k", + "line": 8, + "column": 4, + "end_line": 8, + "end_column": 7 + }, + "paths": [], + "pkgpath": "" + }, + "filename": "if-02.k", + "line": 8, + "column": 4, + "end_line": 8, + "end_column": 7 + } + ], + "value": { + "node": { + "type": "NumberLit", + "binary_suffix": null, + "value": { + "type": "Int", + "value": 4 + } + }, + "filename": "if-02.k", + "line": 8, + "column": 10, + "end_line": 8, + "end_column": 11 + }, + "ty": null + }, + "filename": "if-02.k", + "line": 8, + "column": 4, + "end_line": 8, + "end_column": 11 + } + ], + "cond": { + "node": { + "type": "Binary", + "left": { + "node": { + "type": "Identifier", + "names": [ + { + "node": "a", + "filename": "if-02.k", + "line": 7, + "column": 5, + "end_line": 7, + "end_column": 6 + } + ], + "pkgpath": "", + "ctx": "Load" + }, + "filename": "if-02.k", + "line": 7, + "column": 5, + "end_line": 7, + "end_column": 6 + }, + "op": "Add", + "right": { + "node": { + "type": "NumberLit", + "binary_suffix": null, + "value": { + "type": "Int", + "value": 100 + } + }, + "filename": "if-02.k", + "line": 7, + "column": 9, + "end_line": 7, + "end_column": 12 + } + }, + "filename": "if-02.k", + "line": 7, + "column": 5, + "end_line": 7, + "end_column": 12 + }, + "orelse": [ + { + "node": { + "type": "Assign", + "targets": [ + { + "node": { + "name": { + "node": "eee", + "filename": "if-02.k", + "line": 10, + "column": 4, + "end_line": 10, + "end_column": 7 + }, + "paths": [], + "pkgpath": "" + }, + "filename": "if-02.k", + "line": 10, + "column": 4, + "end_line": 10, + "end_column": 7 + } + ], + "value": { + "node": { + "type": "NumberLit", + "binary_suffix": null, + "value": { + "type": "Int", + "value": 5 + } + }, + "filename": "if-02.k", + "line": 10, + "column": 10, + "end_line": 10, + "end_column": 11 + }, + "ty": null + }, + "filename": "if-02.k", + "line": 10, + "column": 4, + "end_line": 10, + "end_column": 11 + }, + { + "node": { + "type": "Assign", + "targets": [ + { + "node": { + "name": { + "node": "fff", + "filename": "if-02.k", + "line": 11, + "column": 4, + "end_line": 11, + "end_column": 7 + }, + "paths": [], + "pkgpath": "" + }, + "filename": "if-02.k", + "line": 11, + "column": 4, + "end_line": 11, + "end_column": 7 + } + ], + "value": { + "node": { + "type": "NumberLit", + "binary_suffix": null, + "value": { + "type": "Int", + "value": 6 + } + }, + "filename": "if-02.k", + "line": 11, + "column": 10, + "end_line": 11, + "end_column": 11 + }, + "ty": null + }, + "filename": "if-02.k", + "line": 11, + "column": 4, + "end_line": 11, + "end_column": 11 + } + ] + }, + "filename": "if-02.k", + "line": 7, + "column": 0, + "end_line": 11, + "end_column": 11 + } + ] + }, + "filename": "if-02.k", + "line": 5, + "column": 0, + "end_line": 11, + "end_column": 11 + } + ] + }, + "filename": "if-02.k", + "line": 3, + "column": 0, + "end_line": 11, + "end_column": 12 + } + ], + "comments": [] +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__file__if_3.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__file__if_3.snap new file mode 100644 index 000000000..15b09c735 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__file__if_3.snap @@ -0,0 +1,82 @@ +--- +source: parser/src/tests/file.rs +expression: "crate::tests::parsing_file_string(\"testdata/if-03.k\")" +--- +{ + "filename": "if-03.k", + "doc": null, + "body": [ + { + "node": { + "type": "If", + "body": [ + { + "node": { + "type": "Assign", + "targets": [ + { + "node": { + "name": { + "node": "a", + "filename": "if-03.k", + "line": 1, + "column": 9, + "end_line": 1, + "end_column": 10 + }, + "paths": [], + "pkgpath": "" + }, + "filename": "if-03.k", + "line": 1, + "column": 9, + "end_line": 1, + "end_column": 10 + } + ], + "value": { + "node": { + "type": "NumberLit", + "binary_suffix": null, + "value": { + "type": "Int", + "value": 1 + } + }, + "filename": "if-03.k", + "line": 1, + "column": 13, + "end_line": 1, + "end_column": 14 + }, + "ty": null + }, + "filename": "if-03.k", + "line": 1, + "column": 9, + "end_line": 1, + "end_column": 14 + } + ], + "cond": { + "node": { + "type": "NameConstantLit", + "value": "True" + }, + "filename": "if-03.k", + "line": 1, + "column": 3, + "end_line": 1, + "end_column": 7 + }, + "orelse": [] + }, + "filename": "if-03.k", + "line": 1, + "column": 0, + "end_line": 1, + "end_column": 15 + } + ], + "comments": [] +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__file__import_1.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__file__import_1.snap new file mode 100644 index 000000000..3b95fac1a --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__file__import_1.snap @@ -0,0 +1,106 @@ +--- +source: parser/src/tests/file.rs +expression: "crate::tests::parsing_file_string(\"testdata/import-01.k\")" +--- +{ + "filename": "import-01.k", + "doc": null, + "body": [ + { + "node": { + "type": "Import", + "path": { + "node": "a1", + "filename": "import-01.k", + "line": 1, + "column": 7, + "end_line": 1, + "end_column": 9 + }, + "rawpath": "a1", + "name": "a1", + "asname": null, + "pkg_name": "__main__" + }, + "filename": "import-01.k", + "line": 1, + "column": 0, + "end_line": 1, + "end_column": 9 + }, + { + "node": { + "type": "Import", + "path": { + "node": "a2", + "filename": "import-01.k", + "line": 3, + "column": 7, + "end_line": 3, + "end_column": 9 + }, + "rawpath": "a2", + "name": "a2_pkg", + "asname": { + "node": "a2_pkg", + "filename": "import-01.k", + "line": 3, + "column": 13, + "end_line": 3, + "end_column": 19 + }, + "pkg_name": "__main__" + }, + "filename": "import-01.k", + "line": 3, + "column": 0, + "end_line": 3, + "end_column": 19 + }, + { + "node": { + "type": "Import", + "path": { + "node": "subpkg.b1.c1", + "filename": "import-01.k", + "line": 5, + "column": 7, + "end_line": 5, + "end_column": 19 + }, + "rawpath": "subpkg.b1.c1", + "name": "c1", + "asname": null, + "pkg_name": "__main__" + }, + "filename": "import-01.k", + "line": 5, + "column": 0, + "end_line": 5, + "end_column": 19 + }, + { + "node": { + "type": "Import", + "path": { + "node": "a3", + "filename": "import-01.k", + "line": 7, + "column": 7, + "end_line": 7, + "end_column": 10 + }, + "rawpath": ".a3", + "name": "a3", + "asname": null, + "pkg_name": "__main__" + }, + "filename": "import-01.k", + "line": 7, + "column": 0, + "end_line": 7, + "end_column": 10 + } + ], + "comments": [] +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__file__type_1.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__file__type_1.snap new file mode 100644 index 000000000..e696e92c9 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__file__type_1.snap @@ -0,0 +1,540 @@ +--- +source: parser/src/tests/file.rs +expression: "crate::tests::parsing_file_string(\"testdata/type-01.k\")" +--- +{ + "filename": "type-01.k", + "doc": null, + "body": [ + { + "node": { + "type": "TypeAlias", + "type_name": { + "node": { + "names": [ + { + "node": "a", + "filename": "type-01.k", + "line": 1, + "column": 5, + "end_line": 1, + "end_column": 6 + } + ], + "pkgpath": "", + "ctx": "Load" + }, + "filename": "type-01.k", + "line": 1, + "column": 5, + "end_line": 1, + "end_column": 6 + }, + "type_value": { + "node": "any", + "filename": "type-01.k", + "line": 1, + "column": 9, + "end_line": 1, + "end_column": 12 + }, + "ty": { + "node": { + "type": "Any" + }, + "filename": "type-01.k", + "line": 1, + "column": 9, + "end_line": 1, + "end_column": 12 + } + }, + "filename": "type-01.k", + "line": 1, + "column": 5, + "end_line": 1, + "end_column": 12 + }, + { + "node": { + "type": "TypeAlias", + "type_name": { + "node": { + "names": [ + { + "node": "b", + "filename": "type-01.k", + "line": 3, + "column": 5, + "end_line": 3, + "end_column": 6 + } + ], + "pkgpath": "", + "ctx": "Load" + }, + "filename": "type-01.k", + "line": 3, + "column": 5, + "end_line": 3, + "end_column": 6 + }, + "type_value": { + "node": "bool", + "filename": "type-01.k", + "line": 3, + "column": 9, + "end_line": 3, + "end_column": 13 + }, + "ty": { + "node": { + "type": "Basic", + "value": "Bool" + }, + "filename": "type-01.k", + "line": 3, + "column": 9, + "end_line": 3, + "end_column": 13 + } + }, + "filename": "type-01.k", + "line": 3, + "column": 5, + "end_line": 3, + "end_column": 13 + }, + { + "node": { + "type": "TypeAlias", + "type_name": { + "node": { + "names": [ + { + "node": "c", + "filename": "type-01.k", + "line": 4, + "column": 5, + "end_line": 4, + "end_column": 6 + } + ], + "pkgpath": "", + "ctx": "Load" + }, + "filename": "type-01.k", + "line": 4, + "column": 5, + "end_line": 4, + "end_column": 6 + }, + "type_value": { + "node": "int", + "filename": "type-01.k", + "line": 4, + "column": 9, + "end_line": 4, + "end_column": 12 + }, + "ty": { + "node": { + "type": "Basic", + "value": "Int" + }, + "filename": "type-01.k", + "line": 4, + "column": 9, + "end_line": 4, + "end_column": 12 + } + }, + "filename": "type-01.k", + "line": 4, + "column": 5, + "end_line": 4, + "end_column": 12 + }, + { + "node": { + "type": "TypeAlias", + "type_name": { + "node": { + "names": [ + { + "node": "d", + "filename": "type-01.k", + "line": 5, + "column": 5, + "end_line": 5, + "end_column": 6 + } + ], + "pkgpath": "", + "ctx": "Load" + }, + "filename": "type-01.k", + "line": 5, + "column": 5, + "end_line": 5, + "end_column": 6 + }, + "type_value": { + "node": "float", + "filename": "type-01.k", + "line": 5, + "column": 9, + "end_line": 5, + "end_column": 14 + }, + "ty": { + "node": { + "type": "Basic", + "value": "Float" + }, + "filename": "type-01.k", + "line": 5, + "column": 9, + "end_line": 5, + "end_column": 14 + } + }, + "filename": "type-01.k", + "line": 5, + "column": 5, + "end_line": 5, + "end_column": 14 + }, + { + "node": { + "type": "TypeAlias", + "type_name": { + "node": { + "names": [ + { + "node": "e", + "filename": "type-01.k", + "line": 6, + "column": 5, + "end_line": 6, + "end_column": 6 + } + ], + "pkgpath": "", + "ctx": "Load" + }, + "filename": "type-01.k", + "line": 6, + "column": 5, + "end_line": 6, + "end_column": 6 + }, + "type_value": { + "node": "str", + "filename": "type-01.k", + "line": 6, + "column": 9, + "end_line": 6, + "end_column": 12 + }, + "ty": { + "node": { + "type": "Basic", + "value": "Str" + }, + "filename": "type-01.k", + "line": 6, + "column": 9, + "end_line": 6, + "end_column": 12 + } + }, + "filename": "type-01.k", + "line": 6, + "column": 5, + "end_line": 6, + "end_column": 12 + }, + { + "node": { + "type": "TypeAlias", + "type_name": { + "node": { + "names": [ + { + "node": "type_list1", + "filename": "type-01.k", + "line": 8, + "column": 5, + "end_line": 8, + "end_column": 15 + } + ], + "pkgpath": "", + "ctx": "Load" + }, + "filename": "type-01.k", + "line": 8, + "column": 5, + "end_line": 8, + "end_column": 15 + }, + "type_value": { + "node": "[]", + "filename": "type-01.k", + "line": 8, + "column": 18, + "end_line": 8, + "end_column": 20 + }, + "ty": { + "node": { + "type": "List", + "value": { + "inner_type": null + } + }, + "filename": "type-01.k", + "line": 8, + "column": 18, + "end_line": 8, + "end_column": 20 + } + }, + "filename": "type-01.k", + "line": 8, + "column": 5, + "end_line": 8, + "end_column": 20 + }, + { + "node": { + "type": "TypeAlias", + "type_name": { + "node": { + "names": [ + { + "node": "type_list2", + "filename": "type-01.k", + "line": 9, + "column": 5, + "end_line": 9, + "end_column": 15 + } + ], + "pkgpath": "", + "ctx": "Load" + }, + "filename": "type-01.k", + "line": 9, + "column": 5, + "end_line": 9, + "end_column": 15 + }, + "type_value": { + "node": "[[]]", + "filename": "type-01.k", + "line": 9, + "column": 18, + "end_line": 9, + "end_column": 22 + }, + "ty": { + "node": { + "type": "List", + "value": { + "inner_type": { + "node": { + "type": "List", + "value": { + "inner_type": null + } + }, + "filename": "type-01.k", + "line": 9, + "column": 19, + "end_line": 9, + "end_column": 21 + } + } + }, + "filename": "type-01.k", + "line": 9, + "column": 18, + "end_line": 9, + "end_column": 22 + } + }, + "filename": "type-01.k", + "line": 9, + "column": 5, + "end_line": 9, + "end_column": 22 + }, + { + "node": { + "type": "TypeAlias", + "type_name": { + "node": { + "names": [ + { + "node": "type_list3", + "filename": "type-01.k", + "line": 10, + "column": 5, + "end_line": 10, + "end_column": 15 + } + ], + "pkgpath": "", + "ctx": "Load" + }, + "filename": "type-01.k", + "line": 10, + "column": 5, + "end_line": 10, + "end_column": 15 + }, + "type_value": { + "node": "[int]", + "filename": "type-01.k", + "line": 10, + "column": 18, + "end_line": 10, + "end_column": 23 + }, + "ty": { + "node": { + "type": "List", + "value": { + "inner_type": { + "node": { + "type": "Basic", + "value": "Int" + }, + "filename": "type-01.k", + "line": 10, + "column": 19, + "end_line": 10, + "end_column": 22 + } + } + }, + "filename": "type-01.k", + "line": 10, + "column": 18, + "end_line": 10, + "end_column": 23 + } + }, + "filename": "type-01.k", + "line": 10, + "column": 5, + "end_line": 10, + "end_column": 23 + }, + { + "node": { + "type": "TypeAlias", + "type_name": { + "node": { + "names": [ + { + "node": "b", + "filename": "type-01.k", + "line": 12, + "column": 5, + "end_line": 12, + "end_column": 6 + } + ], + "pkgpath": "", + "ctx": "Load" + }, + "filename": "type-01.k", + "line": 12, + "column": 5, + "end_line": 12, + "end_column": 6 + }, + "type_value": { + "node": "int | str | [] | {:}", + "filename": "type-01.k", + "line": 12, + "column": 9, + "end_line": 12, + "end_column": 29 + }, + "ty": { + "node": { + "type": "Union", + "value": { + "type_elements": [ + { + "node": { + "type": "Basic", + "value": "Int" + }, + "filename": "type-01.k", + "line": 12, + "column": 9, + "end_line": 12, + "end_column": 12 + }, + { + "node": { + "type": "Basic", + "value": "Str" + }, + "filename": "type-01.k", + "line": 12, + "column": 15, + "end_line": 12, + "end_column": 18 + }, + { + "node": { + "type": "List", + "value": { + "inner_type": null + } + }, + "filename": "type-01.k", + "line": 12, + "column": 21, + "end_line": 12, + "end_column": 23 + }, + { + "node": { + "type": "Dict", + "value": { + "key_type": null, + "value_type": null + } + }, + "filename": "type-01.k", + "line": 12, + "column": 26, + "end_line": 12, + "end_column": 29 + } + ] + } + }, + "filename": "type-01.k", + "line": 12, + "column": 9, + "end_line": 12, + "end_column": 29 + } + }, + "filename": "type-01.k", + "line": 12, + "column": 5, + "end_line": 12, + "end_column": 29 + } + ], + "comments": [] +} diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__types__any_type.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__types__any_type.snap new file mode 100644 index 000000000..5e3e41d28 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__types__any_type.snap @@ -0,0 +1,13 @@ +--- +source: parser/src/tests/types.rs +expression: "crate::tests::parsing_type_string(r####\"any\"####)" +--- +Node { + node: Any, + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 3, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__types__basic_type_0.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__types__basic_type_0.snap new file mode 100644 index 000000000..d7a243058 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__types__basic_type_0.snap @@ -0,0 +1,15 @@ +--- +source: parser/src/tests/types.rs +expression: "crate::tests::parsing_type_string(r####\"bool\"####)" +--- +Node { + node: Basic( + Bool, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 4, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__types__basic_type_1.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__types__basic_type_1.snap new file mode 100644 index 000000000..335b19217 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__types__basic_type_1.snap @@ -0,0 +1,15 @@ +--- +source: parser/src/tests/types.rs +expression: "crate::tests::parsing_type_string(r####\"int\"####)" +--- +Node { + node: Basic( + Int, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 3, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__types__basic_type_2.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__types__basic_type_2.snap new file mode 100644 index 000000000..7c6ee89d2 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__types__basic_type_2.snap @@ -0,0 +1,15 @@ +--- +source: parser/src/tests/types.rs +expression: "crate::tests::parsing_type_string(r####\"float\"####)" +--- +Node { + node: Basic( + Float, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 5, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__types__basic_type_3.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__types__basic_type_3.snap new file mode 100644 index 000000000..9d7b59a4b --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__types__basic_type_3.snap @@ -0,0 +1,15 @@ +--- +source: parser/src/tests/types.rs +expression: "crate::tests::parsing_type_string(r####\"str\"####)" +--- +Node { + node: Basic( + Str, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 3, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__types__dict_type_0.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__types__dict_type_0.snap new file mode 100644 index 000000000..7d0a2bf4b --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__types__dict_type_0.snap @@ -0,0 +1,18 @@ +--- +source: parser/src/tests/types.rs +expression: "crate::tests::parsing_type_string(r####\"{:}\"####)" +--- +Node { + node: Dict( + DictType { + key_type: None, + value_type: None, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 3, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__types__dict_type_1.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__types__dict_type_1.snap new file mode 100644 index 000000000..3b4667dcb --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__types__dict_type_1.snap @@ -0,0 +1,29 @@ +--- +source: parser/src/tests/types.rs +expression: "crate::tests::parsing_type_string(r####\"{str:}\"####)" +--- +Node { + node: Dict( + DictType { + key_type: Some( + Node { + node: Basic( + Str, + ), + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 4, + }, + ), + value_type: None, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 6, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__types__dict_type_2.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__types__dict_type_2.snap new file mode 100644 index 000000000..8165aaed5 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__types__dict_type_2.snap @@ -0,0 +1,31 @@ +--- +source: parser/src/tests/types.rs +expression: "crate::tests::parsing_type_string(r####\"{:[]}\"####)" +--- +Node { + node: Dict( + DictType { + key_type: None, + value_type: Some( + Node { + node: List( + ListType { + inner_type: None, + }, + ), + filename: "", + line: 1, + column: 2, + end_line: 1, + end_column: 4, + }, + ), + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 5, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__types__dict_type_3.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__types__dict_type_3.snap new file mode 100644 index 000000000..c35fb6168 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__types__dict_type_3.snap @@ -0,0 +1,54 @@ +--- +source: parser/src/tests/types.rs +expression: "crate::tests::parsing_type_string(r####\"{str:{:float}}\"####)" +--- +Node { + node: Dict( + DictType { + key_type: Some( + Node { + node: Basic( + Str, + ), + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 4, + }, + ), + value_type: Some( + Node { + node: Dict( + DictType { + key_type: None, + value_type: Some( + Node { + node: Basic( + Float, + ), + filename: "", + line: 1, + column: 7, + end_line: 1, + end_column: 12, + }, + ), + }, + ), + filename: "", + line: 1, + column: 5, + end_line: 1, + end_column: 13, + }, + ), + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 14, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__types__dict_type_4.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__types__dict_type_4.snap new file mode 100644 index 000000000..b98aafcde --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__types__dict_type_4.snap @@ -0,0 +1,54 @@ +--- +source: parser/src/tests/types.rs +expression: "crate::tests::parsing_type_string(r####\"{str:{:float}, int:[]}\"####)" +--- +Node { + node: Dict( + DictType { + key_type: Some( + Node { + node: Basic( + Str, + ), + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 4, + }, + ), + value_type: Some( + Node { + node: Dict( + DictType { + key_type: None, + value_type: Some( + Node { + node: Basic( + Float, + ), + filename: "", + line: 1, + column: 7, + end_line: 1, + end_column: 12, + }, + ), + }, + ), + filename: "", + line: 1, + column: 5, + end_line: 1, + end_column: 13, + }, + ), + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 14, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__types__list_type_0.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__types__list_type_0.snap new file mode 100644 index 000000000..c473941af --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__types__list_type_0.snap @@ -0,0 +1,17 @@ +--- +source: parser/src/tests/types.rs +expression: "crate::tests::parsing_type_string(r####\"[]\"####)" +--- +Node { + node: List( + ListType { + inner_type: None, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 2, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__types__list_type_1.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__types__list_type_1.snap new file mode 100644 index 000000000..fd9988b84 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__types__list_type_1.snap @@ -0,0 +1,28 @@ +--- +source: parser/src/tests/types.rs +expression: "crate::tests::parsing_type_string(r####\"[int]\"####)" +--- +Node { + node: List( + ListType { + inner_type: Some( + Node { + node: Basic( + Int, + ), + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 4, + }, + ), + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 5, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__types__list_type_2.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__types__list_type_2.snap new file mode 100644 index 000000000..73e992119 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__types__list_type_2.snap @@ -0,0 +1,26 @@ +--- +source: parser/src/tests/types.rs +expression: "crate::tests::parsing_type_string(r####\"[any]\"####)" +--- +Node { + node: List( + ListType { + inner_type: Some( + Node { + node: Any, + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 4, + }, + ), + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 5, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__types__list_type_3.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__types__list_type_3.snap new file mode 100644 index 000000000..a3b930896 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__types__list_type_3.snap @@ -0,0 +1,30 @@ +--- +source: parser/src/tests/types.rs +expression: "crate::tests::parsing_type_string(r####\"[[]]\"####)" +--- +Node { + node: List( + ListType { + inner_type: Some( + Node { + node: List( + ListType { + inner_type: None, + }, + ), + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 3, + }, + ), + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 4, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__types__list_type_4.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__types__list_type_4.snap new file mode 100644 index 000000000..518dd31b9 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__types__list_type_4.snap @@ -0,0 +1,41 @@ +--- +source: parser/src/tests/types.rs +expression: "crate::tests::parsing_type_string(r####\"[[str]]\"####)" +--- +Node { + node: List( + ListType { + inner_type: Some( + Node { + node: List( + ListType { + inner_type: Some( + Node { + node: Basic( + Str, + ), + filename: "", + line: 1, + column: 2, + end_line: 1, + end_column: 5, + }, + ), + }, + ), + filename: "", + line: 1, + column: 1, + end_line: 1, + end_column: 6, + }, + ), + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 7, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__types__literal_type_0.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__types__literal_type_0.snap new file mode 100644 index 000000000..d7ba0c795 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__types__literal_type_0.snap @@ -0,0 +1,17 @@ +--- +source: parser/src/tests/types.rs +expression: "crate::tests::parsing_type_string(r####\"True\"####)" +--- +Node { + node: Literal( + Bool( + true, + ), + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 4, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__types__literal_type_1.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__types__literal_type_1.snap new file mode 100644 index 000000000..79951d904 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__types__literal_type_1.snap @@ -0,0 +1,17 @@ +--- +source: parser/src/tests/types.rs +expression: "crate::tests::parsing_type_string(r####\"False\"####)" +--- +Node { + node: Literal( + Bool( + false, + ), + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 5, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__types__literal_type_2.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__types__literal_type_2.snap new file mode 100644 index 000000000..fe221ef16 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__types__literal_type_2.snap @@ -0,0 +1,20 @@ +--- +source: parser/src/tests/types.rs +expression: "crate::tests::parsing_type_string(r####\"123\"####)" +--- +Node { + node: Literal( + Int( + IntLiteralType { + value: 123, + suffix: None, + }, + ), + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 3, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__types__literal_type_3.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__types__literal_type_3.snap new file mode 100644 index 000000000..7db780a7d --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__types__literal_type_3.snap @@ -0,0 +1,17 @@ +--- +source: parser/src/tests/types.rs +expression: "crate::tests::parsing_type_string(r####\"123.0\"####)" +--- +Node { + node: Literal( + Float( + 123.0, + ), + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 5, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__types__literal_type_4.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__types__literal_type_4.snap new file mode 100644 index 000000000..9e368bc0d --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__types__literal_type_4.snap @@ -0,0 +1,17 @@ +--- +source: parser/src/tests/types.rs +expression: "crate::tests::parsing_type_string(r####\"\"abc\"\"####)" +--- +Node { + node: Literal( + Str( + "abc", + ), + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 5, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__types__literal_type_5.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__types__literal_type_5.snap new file mode 100644 index 000000000..886d9b0cb --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__types__literal_type_5.snap @@ -0,0 +1,17 @@ +--- +source: parser/src/tests/types.rs +expression: "crate::tests::parsing_type_string(r####\"''\"####)" +--- +Node { + node: Literal( + Str( + "", + ), + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 2, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__types__named_type_0.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__types__named_type_0.snap new file mode 100644 index 000000000..9c2a9e0a9 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__types__named_type_0.snap @@ -0,0 +1,28 @@ +--- +source: parser/src/tests/types.rs +expression: "crate::tests::parsing_type_string(r####\"Person\"####)" +--- +Node { + node: Named( + Identifier { + names: [ + Node { + node: "Person", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 6, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 6, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__types__named_type_1.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__types__named_type_1.snap new file mode 100644 index 000000000..ea918caae --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__types__named_type_1.snap @@ -0,0 +1,44 @@ +--- +source: parser/src/tests/types.rs +expression: "crate::tests::parsing_type_string(r####\"some.pkg.Person\"####)" +--- +Node { + node: Named( + Identifier { + names: [ + Node { + node: "some", + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 4, + }, + Node { + node: "pkg", + filename: "", + line: 1, + column: 5, + end_line: 1, + end_column: 8, + }, + Node { + node: "Person", + filename: "", + line: 1, + column: 9, + end_line: 1, + end_column: 15, + }, + ], + pkgpath: "", + ctx: Load, + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 15, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__types__type_str_0.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__types__type_str_0.snap new file mode 100644 index 000000000..fe487c4ab --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__types__type_str_0.snap @@ -0,0 +1,5 @@ +--- +source: parser/src/tests/types.rs +expression: "crate::tests::parsing_type_node_string(r####\"int\"####)" +--- +int diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__types__type_str_1.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__types__type_str_1.snap new file mode 100644 index 000000000..b5d050c86 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__types__type_str_1.snap @@ -0,0 +1,5 @@ +--- +source: parser/src/tests/types.rs +expression: "crate::tests::parsing_type_node_string(r####\" int \"####)" +--- +int diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__types__type_str_2.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__types__type_str_2.snap new file mode 100644 index 000000000..f6ceb4f04 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__types__type_str_2.snap @@ -0,0 +1,5 @@ +--- +source: parser/src/tests/types.rs +expression: "crate::tests::parsing_type_node_string(r####\"bool | True | int | str|str\"####)" +--- +bool | True | int | str | str diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__types__type_str_3.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__types__type_str_3.snap new file mode 100644 index 000000000..8d25e81de --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__types__type_str_3.snap @@ -0,0 +1,5 @@ +--- +source: parser/src/tests/types.rs +expression: "crate::tests::parsing_type_node_string(r####\"[ [{str: float}] | int]\"####)" +--- +[[{str:float}] | int] diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__types__union_type_0.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__types__union_type_0.snap new file mode 100644 index 000000000..d78b2e820 --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__types__union_type_0.snap @@ -0,0 +1,38 @@ +--- +source: parser/src/tests/types.rs +expression: "crate::tests::parsing_type_string(r####\"int|str\"####)" +--- +Node { + node: Union( + UnionType { + type_elements: [ + Node { + node: Basic( + Int, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 3, + }, + Node { + node: Basic( + Str, + ), + filename: "", + line: 1, + column: 4, + end_line: 1, + end_column: 7, + }, + ], + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 7, +} + diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__types__union_type_1.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__types__union_type_1.snap new file mode 100644 index 000000000..4a631d87f --- /dev/null +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__types__union_type_1.snap @@ -0,0 +1,63 @@ +--- +source: parser/src/tests/types.rs +expression: "crate::tests::parsing_type_string(r####\"int | str | [] | {:}\"####)" +--- +Node { + node: Union( + UnionType { + type_elements: [ + Node { + node: Basic( + Int, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 3, + }, + Node { + node: Basic( + Str, + ), + filename: "", + line: 1, + column: 6, + end_line: 1, + end_column: 9, + }, + Node { + node: List( + ListType { + inner_type: None, + }, + ), + filename: "", + line: 1, + column: 12, + end_line: 1, + end_column: 14, + }, + Node { + node: Dict( + DictType { + key_type: None, + value_type: None, + }, + ), + filename: "", + line: 1, + column: 17, + end_line: 1, + end_column: 20, + }, + ], + }, + ), + filename: "", + line: 1, + column: 0, + end_line: 1, + end_column: 20, +} + diff --git a/kclvm/parser/src/tests/types.rs b/kclvm/parser/src/tests/types.rs new file mode 100644 index 000000000..d1b2ab629 --- /dev/null +++ b/kclvm/parser/src/tests/types.rs @@ -0,0 +1,32 @@ +use crate::tests::{parse_type_node_snapshot, parse_type_snapshot}; + +parse_type_snapshot!(basic_type_0, r####"bool"####); +parse_type_snapshot!(basic_type_1, r####"int"####); +parse_type_snapshot!(basic_type_2, r####"float"####); +parse_type_snapshot!(basic_type_3, r####"str"####); +parse_type_snapshot!(any_type, r####"any"####); +parse_type_snapshot!(list_type_0, r####"[]"####); +parse_type_snapshot!(list_type_1, r####"[int]"####); +parse_type_snapshot!(list_type_2, r####"[any]"####); +parse_type_snapshot!(list_type_3, r####"[[]]"####); +parse_type_snapshot!(list_type_4, r####"[[str]]"####); +parse_type_snapshot!(dict_type_0, r####"{:}"####); +parse_type_snapshot!(dict_type_1, r####"{str:}"####); +parse_type_snapshot!(dict_type_2, r####"{:[]}"####); +parse_type_snapshot!(dict_type_3, r####"{str:{:float}}"####); +parse_type_snapshot!(dict_type_4, r####"{str:{:float}, int:[]}"####); +parse_type_snapshot!(union_type_0, r####"int|str"####); +parse_type_snapshot!(union_type_1, r####"int | str | [] | {:}"####); +parse_type_snapshot!(named_type_0, r####"Person"####); +parse_type_snapshot!(named_type_1, r####"some.pkg.Person"####); +parse_type_snapshot!(literal_type_0, r####"True"####); +parse_type_snapshot!(literal_type_1, r####"False"####); +parse_type_snapshot!(literal_type_2, r####"123"####); +parse_type_snapshot!(literal_type_3, r####"123.0"####); +parse_type_snapshot!(literal_type_4, r####""abc""####); +parse_type_snapshot!(literal_type_5, r####"''"####); + +parse_type_node_snapshot!(type_str_0, r####"int"####); +parse_type_node_snapshot!(type_str_1, r####" int "####); +parse_type_node_snapshot!(type_str_2, r####"bool | True | int | str|str"####); +parse_type_node_snapshot!(type_str_3, r####"[ [{str: float}] | int]"####); diff --git a/kclvm/parser/testdata/Makefile b/kclvm/parser/testdata/Makefile deleted file mode 100644 index ac278ac6b..000000000 --- a/kclvm/parser/testdata/Makefile +++ /dev/null @@ -1,13 +0,0 @@ - -K_FILES=$(wildcard ./*.k) -K_JSON_FILES=$(patsubst %.k,%.k.json,$(K_FILES)) - -default: clean $(K_JSON_FILES) $(K_FMT_JSON_FILES) - @echo "ok" - -clean: - -rm *.k.json - -%.k.json: %.k - cargo run --bin parse_file $< > $@ - diff --git a/kclvm/parser/testdata/a1.k.json b/kclvm/parser/testdata/a1.k.json deleted file mode 100644 index 3b4674ab1..000000000 --- a/kclvm/parser/testdata/a1.k.json +++ /dev/null @@ -1 +0,0 @@ -{"filename":"a1.k","pkg":"__main__","doc":"","name":"__main__","body":[],"comments":[]} diff --git a/kclvm/parser/testdata/a2.k.json b/kclvm/parser/testdata/a2.k.json deleted file mode 100644 index 9de81155a..000000000 --- a/kclvm/parser/testdata/a2.k.json +++ /dev/null @@ -1 +0,0 @@ -{"filename":"a2.k","pkg":"__main__","doc":"","name":"__main__","body":[],"comments":[]} diff --git a/kclvm/parser/testdata/a3.k.json b/kclvm/parser/testdata/a3.k.json deleted file mode 100644 index 70af70275..000000000 --- a/kclvm/parser/testdata/a3.k.json +++ /dev/null @@ -1 +0,0 @@ -{"filename":"a3.k","pkg":"__main__","doc":"","name":"__main__","body":[],"comments":[]} diff --git a/kclvm/parser/testdata/assert-01.k.json b/kclvm/parser/testdata/assert-01.k.json deleted file mode 100644 index 75b5a5f19..000000000 --- a/kclvm/parser/testdata/assert-01.k.json +++ /dev/null @@ -1 +0,0 @@ -{"filename":"assert-01.k","pkg":"__main__","doc":"","name":"__main__","body":[{"node":{"Assert":{"test":{"node":{"NumberLit":{"binary_suffix":null,"value":{"Int":1}}},"filename":"assert-01.k","line":1,"column":7,"end_line":1,"end_column":8},"if_cond":null,"msg":null}},"filename":"assert-01.k","line":1,"column":0,"end_line":1,"end_column":8},{"node":{"Assert":{"test":{"node":{"NumberLit":{"binary_suffix":null,"value":{"Int":2}}},"filename":"assert-01.k","line":2,"column":7,"end_line":2,"end_column":8},"if_cond":null,"msg":{"node":{"StringLit":{"is_long_string":false,"raw_value":"\"msg\"","value":"msg"}},"filename":"assert-01.k","line":2,"column":10,"end_line":2,"end_column":15}}},"filename":"assert-01.k","line":2,"column":0,"end_line":2,"end_column":15},{"node":{"Assert":{"test":{"node":{"NameConstantLit":{"value":"True"}},"filename":"assert-01.k","line":3,"column":7,"end_line":3,"end_column":11},"if_cond":null,"msg":null}},"filename":"assert-01.k","line":3,"column":0,"end_line":3,"end_column":11}],"comments":[]} diff --git a/kclvm/parser/testdata/assert-02.k.json b/kclvm/parser/testdata/assert-02.k.json deleted file mode 100644 index 4f792f2de..000000000 --- a/kclvm/parser/testdata/assert-02.k.json +++ /dev/null @@ -1 +0,0 @@ -{"filename":"assert-02.k","pkg":"__main__","doc":"","name":"__main__","body":[{"node":{"Assert":{"test":{"node":{"NameConstantLit":{"value":"True"}},"filename":"assert-02.k","line":1,"column":7,"end_line":1,"end_column":11},"if_cond":null,"msg":null}},"filename":"assert-02.k","line":1,"column":0,"end_line":1,"end_column":11},{"node":{"Assert":{"test":{"node":{"Compare":{"left":{"node":{"NumberLit":{"binary_suffix":null,"value":{"Int":1}}},"filename":"assert-02.k","line":2,"column":7,"end_line":2,"end_column":8},"ops":["Eq"],"comparators":[{"node":{"NumberLit":{"binary_suffix":null,"value":{"Int":1}}},"filename":"assert-02.k","line":2,"column":12,"end_line":2,"end_column":13}]}},"filename":"assert-02.k","line":2,"column":7,"end_line":2,"end_column":13},"if_cond":null,"msg":null}},"filename":"assert-02.k","line":2,"column":0,"end_line":2,"end_column":13},{"node":{"Assign":{"targets":[{"node":{"names":["_x"],"pkgpath":"","ctx":"Store"},"filename":"assert-02.k","line":3,"column":0,"end_line":3,"end_column":2}],"value":{"node":{"StringLit":{"is_long_string":false,"raw_value":"\"good case\"","value":"good case"}},"filename":"assert-02.k","line":3,"column":5,"end_line":3,"end_column":16},"type_annotation":null}},"filename":"assert-02.k","line":3,"column":0,"end_line":4,"end_column":0},{"node":{"Assert":{"test":{"node":{"Compare":{"left":{"node":{"Identifier":{"names":["_x"],"pkgpath":"","ctx":"Load"}},"filename":"assert-02.k","line":4,"column":7,"end_line":4,"end_column":9},"ops":["Eq"],"comparators":[{"node":{"StringLit":{"is_long_string":false,"raw_value":"\"good case\"","value":"good case"}},"filename":"assert-02.k","line":4,"column":13,"end_line":4,"end_column":24}]}},"filename":"assert-02.k","line":4,"column":7,"end_line":4,"end_column":24},"if_cond":null,"msg":null}},"filename":"assert-02.k","line":4,"column":0,"end_line":4,"end_column":24}],"comments":[]} diff --git a/kclvm/parser/testdata/assert-03.k.json b/kclvm/parser/testdata/assert-03.k.json deleted file mode 100644 index 454097999..000000000 --- a/kclvm/parser/testdata/assert-03.k.json +++ /dev/null @@ -1 +0,0 @@ -{"filename":"assert-03.k","pkg":"__main__","doc":"","name":"__main__","body":[{"node":{"If":{"body":[{"node":{"Assert":{"test":{"node":{"NameConstantLit":{"value":"True"}},"filename":"assert-03.k","line":2,"column":11,"end_line":2,"end_column":15},"if_cond":null,"msg":{"node":{"StringLit":{"is_long_string":false,"raw_value":"\"Error messgae\"","value":"Error messgae"}},"filename":"assert-03.k","line":2,"column":17,"end_line":2,"end_column":32}}},"filename":"assert-03.k","line":2,"column":4,"end_line":2,"end_column":32},{"node":{"Assert":{"test":{"node":{"Compare":{"left":{"node":{"NumberLit":{"binary_suffix":null,"value":{"Int":1}}},"filename":"assert-03.k","line":3,"column":11,"end_line":3,"end_column":12},"ops":["Eq"],"comparators":[{"node":{"NumberLit":{"binary_suffix":null,"value":{"Int":1}}},"filename":"assert-03.k","line":3,"column":16,"end_line":3,"end_column":17}]}},"filename":"assert-03.k","line":3,"column":11,"end_line":3,"end_column":17},"if_cond":null,"msg":{"node":{"StringLit":{"is_long_string":false,"raw_value":"\"\"","value":""}},"filename":"assert-03.k","line":3,"column":19,"end_line":3,"end_column":21}}},"filename":"assert-03.k","line":3,"column":4,"end_line":3,"end_column":21},{"node":{"Assign":{"targets":[{"node":{"names":["_x"],"pkgpath":"","ctx":"Store"},"filename":"assert-03.k","line":4,"column":4,"end_line":4,"end_column":6}],"value":{"node":{"StringLit":{"is_long_string":false,"raw_value":"\"good case\"","value":"good case"}},"filename":"assert-03.k","line":4,"column":9,"end_line":4,"end_column":20},"type_annotation":null}},"filename":"assert-03.k","line":4,"column":4,"end_line":5,"end_column":0},{"node":{"Assert":{"test":{"node":{"Compare":{"left":{"node":{"Identifier":{"names":["_x"],"pkgpath":"","ctx":"Load"}},"filename":"assert-03.k","line":5,"column":11,"end_line":5,"end_column":13},"ops":["Eq"],"comparators":[{"node":{"StringLit":{"is_long_string":false,"raw_value":"\"good case\"","value":"good case"}},"filename":"assert-03.k","line":5,"column":17,"end_line":5,"end_column":28}]}},"filename":"assert-03.k","line":5,"column":11,"end_line":5,"end_column":28},"if_cond":null,"msg":null}},"filename":"assert-03.k","line":5,"column":4,"end_line":5,"end_column":28}],"cond":{"node":{"NameConstantLit":{"value":"True"}},"filename":"assert-03.k","line":1,"column":3,"end_line":1,"end_column":7},"orelse":[{"node":{"Assert":{"test":{"node":{"NameConstantLit":{"value":"False"}},"filename":"assert-03.k","line":7,"column":11,"end_line":7,"end_column":16},"if_cond":null,"msg":null}},"filename":"assert-03.k","line":7,"column":4,"end_line":7,"end_column":16}]}},"filename":"assert-03.k","line":1,"column":0,"end_line":8,"end_column":1}],"comments":[]} diff --git a/kclvm/parser/testdata/assert-if-0.k.json b/kclvm/parser/testdata/assert-if-0.k.json deleted file mode 100644 index e539c0e4c..000000000 --- a/kclvm/parser/testdata/assert-if-0.k.json +++ /dev/null @@ -1 +0,0 @@ -{"filename":"assert-if-0.k","pkg":"__main__","doc":"","name":"__main__","body":[{"node":{"Assert":{"test":{"node":{"NameConstantLit":{"value":"True"}},"filename":"assert-if-0.k","line":1,"column":7,"end_line":1,"end_column":11},"if_cond":null,"msg":null}},"filename":"assert-if-0.k","line":1,"column":0,"end_line":1,"end_column":11},{"node":{"Assert":{"test":{"node":{"Compare":{"left":{"node":{"NumberLit":{"binary_suffix":null,"value":{"Int":1}}},"filename":"assert-if-0.k","line":2,"column":7,"end_line":2,"end_column":8},"ops":["Eq"],"comparators":[{"node":{"NumberLit":{"binary_suffix":null,"value":{"Int":1}}},"filename":"assert-if-0.k","line":2,"column":12,"end_line":2,"end_column":13}]}},"filename":"assert-if-0.k","line":2,"column":7,"end_line":2,"end_column":13},"if_cond":{"node":{"NameConstantLit":{"value":"True"}},"filename":"assert-if-0.k","line":2,"column":17,"end_line":2,"end_column":21},"msg":null}},"filename":"assert-if-0.k","line":2,"column":0,"end_line":2,"end_column":21},{"node":{"Assign":{"targets":[{"node":{"names":["_x"],"pkgpath":"","ctx":"Store"},"filename":"assert-if-0.k","line":3,"column":0,"end_line":3,"end_column":2}],"value":{"node":{"StringLit":{"is_long_string":false,"raw_value":"\"good case\"","value":"good case"}},"filename":"assert-if-0.k","line":3,"column":5,"end_line":3,"end_column":16},"type_annotation":null}},"filename":"assert-if-0.k","line":3,"column":0,"end_line":4,"end_column":0},{"node":{"Assert":{"test":{"node":{"Compare":{"left":{"node":{"Identifier":{"names":["_x"],"pkgpath":"","ctx":"Load"}},"filename":"assert-if-0.k","line":4,"column":7,"end_line":4,"end_column":9},"ops":["Eq"],"comparators":[{"node":{"StringLit":{"is_long_string":false,"raw_value":"\"good case\"","value":"good case"}},"filename":"assert-if-0.k","line":4,"column":13,"end_line":4,"end_column":24}]}},"filename":"assert-if-0.k","line":4,"column":7,"end_line":4,"end_column":24},"if_cond":{"node":{"Identifier":{"names":["_x"],"pkgpath":"","ctx":"Load"}},"filename":"assert-if-0.k","line":4,"column":28,"end_line":4,"end_column":30},"msg":{"node":{"StringLit":{"is_long_string":false,"raw_value":"\"_x need to be 'good case'\"","value":"_x need to be 'good case'"}},"filename":"assert-if-0.k","line":4,"column":32,"end_line":4,"end_column":59}}},"filename":"assert-if-0.k","line":4,"column":0,"end_line":4,"end_column":59}],"comments":[]} diff --git a/kclvm/parser/testdata/assert-if-1.k.json b/kclvm/parser/testdata/assert-if-1.k.json deleted file mode 100644 index a93760fdc..000000000 --- a/kclvm/parser/testdata/assert-if-1.k.json +++ /dev/null @@ -1 +0,0 @@ -{"filename":"assert-if-1.k","pkg":"__main__","doc":"","name":"__main__","body":[{"node":{"Assert":{"test":{"node":{"NameConstantLit":{"value":"True"}},"filename":"assert-if-1.k","line":1,"column":7,"end_line":1,"end_column":11},"if_cond":{"node":{"NameConstantLit":{"value":"False"}},"filename":"assert-if-1.k","line":1,"column":15,"end_line":1,"end_column":20},"msg":null}},"filename":"assert-if-1.k","line":1,"column":0,"end_line":1,"end_column":20},{"node":{"Assert":{"test":{"node":{"Compare":{"left":{"node":{"NumberLit":{"binary_suffix":null,"value":{"Int":1}}},"filename":"assert-if-1.k","line":2,"column":7,"end_line":2,"end_column":8},"ops":["Eq"],"comparators":[{"node":{"NumberLit":{"binary_suffix":null,"value":{"Int":1}}},"filename":"assert-if-1.k","line":2,"column":12,"end_line":2,"end_column":13}]}},"filename":"assert-if-1.k","line":2,"column":7,"end_line":2,"end_column":13},"if_cond":{"node":{"NameConstantLit":{"value":"False"}},"filename":"assert-if-1.k","line":2,"column":17,"end_line":2,"end_column":22},"msg":null}},"filename":"assert-if-1.k","line":2,"column":0,"end_line":2,"end_column":22},{"node":{"Assign":{"targets":[{"node":{"names":["_x"],"pkgpath":"","ctx":"Store"},"filename":"assert-if-1.k","line":3,"column":0,"end_line":3,"end_column":2}],"value":{"node":{"StringLit":{"is_long_string":false,"raw_value":"\"good case\"","value":"good case"}},"filename":"assert-if-1.k","line":3,"column":5,"end_line":3,"end_column":16},"type_annotation":null}},"filename":"assert-if-1.k","line":3,"column":0,"end_line":4,"end_column":0},{"node":{"Assert":{"test":{"node":{"Compare":{"left":{"node":{"Identifier":{"names":["_x"],"pkgpath":"","ctx":"Load"}},"filename":"assert-if-1.k","line":4,"column":7,"end_line":4,"end_column":9},"ops":["Eq"],"comparators":[{"node":{"StringLit":{"is_long_string":false,"raw_value":"\"good case\"","value":"good case"}},"filename":"assert-if-1.k","line":4,"column":13,"end_line":4,"end_column":24}]}},"filename":"assert-if-1.k","line":4,"column":7,"end_line":4,"end_column":24},"if_cond":{"node":{"Unary":{"op":"Not","operand":{"node":{"Identifier":{"names":["_x"],"pkgpath":"","ctx":"Load"}},"filename":"assert-if-1.k","line":4,"column":32,"end_line":4,"end_column":34}}},"filename":"assert-if-1.k","line":4,"column":28,"end_line":4,"end_column":34},"msg":{"node":{"StringLit":{"is_long_string":false,"raw_value":"\"_x need to be 'good case'\"","value":"_x need to be 'good case'"}},"filename":"assert-if-1.k","line":4,"column":36,"end_line":4,"end_column":63}}},"filename":"assert-if-1.k","line":4,"column":0,"end_line":4,"end_column":63}],"comments":[]} diff --git a/kclvm/parser/testdata/assert-if-2.k.json b/kclvm/parser/testdata/assert-if-2.k.json deleted file mode 100644 index 3a5c70faf..000000000 --- a/kclvm/parser/testdata/assert-if-2.k.json +++ /dev/null @@ -1 +0,0 @@ -{"filename":"assert-if-2.k","pkg":"__main__","doc":"","name":"__main__","body":[{"node":{"Schema":{"doc":"","name":{"node":"Data","filename":"assert-if-2.k","line":1,"column":7,"end_line":1,"end_column":11},"parent_name":null,"for_host_name":null,"is_mixin":false,"is_protocol":false,"args":null,"mixins":[],"body":[{"node":{"Assert":{"test":{"node":{"NameConstantLit":{"value":"True"}},"filename":"assert-if-2.k","line":2,"column":11,"end_line":2,"end_column":15},"if_cond":{"node":{"NameConstantLit":{"value":"False"}},"filename":"assert-if-2.k","line":2,"column":19,"end_line":2,"end_column":24},"msg":null}},"filename":"assert-if-2.k","line":2,"column":4,"end_line":2,"end_column":24},{"node":{"Assert":{"test":{"node":{"Compare":{"left":{"node":{"NumberLit":{"binary_suffix":null,"value":{"Int":1}}},"filename":"assert-if-2.k","line":3,"column":11,"end_line":3,"end_column":12},"ops":["Eq"],"comparators":[{"node":{"NumberLit":{"binary_suffix":null,"value":{"Int":1}}},"filename":"assert-if-2.k","line":3,"column":16,"end_line":3,"end_column":17}]}},"filename":"assert-if-2.k","line":3,"column":11,"end_line":3,"end_column":17},"if_cond":{"node":{"NameConstantLit":{"value":"False"}},"filename":"assert-if-2.k","line":3,"column":21,"end_line":3,"end_column":26},"msg":null}},"filename":"assert-if-2.k","line":3,"column":4,"end_line":3,"end_column":26},{"node":{"Assign":{"targets":[{"node":{"names":["_x"],"pkgpath":"","ctx":"Store"},"filename":"assert-if-2.k","line":4,"column":4,"end_line":4,"end_column":6}],"value":{"node":{"StringLit":{"is_long_string":false,"raw_value":"\"good case\"","value":"good case"}},"filename":"assert-if-2.k","line":4,"column":9,"end_line":4,"end_column":20},"type_annotation":null}},"filename":"assert-if-2.k","line":4,"column":4,"end_line":5,"end_column":0},{"node":{"Assert":{"test":{"node":{"Compare":{"left":{"node":{"Identifier":{"names":["_x"],"pkgpath":"","ctx":"Load"}},"filename":"assert-if-2.k","line":5,"column":11,"end_line":5,"end_column":13},"ops":["Eq"],"comparators":[{"node":{"StringLit":{"is_long_string":false,"raw_value":"\"good case\"","value":"good case"}},"filename":"assert-if-2.k","line":5,"column":17,"end_line":5,"end_column":28}]}},"filename":"assert-if-2.k","line":5,"column":11,"end_line":5,"end_column":28},"if_cond":{"node":{"Unary":{"op":"Not","operand":{"node":{"Identifier":{"names":["_x"],"pkgpath":"","ctx":"Load"}},"filename":"assert-if-2.k","line":5,"column":36,"end_line":5,"end_column":38}}},"filename":"assert-if-2.k","line":5,"column":32,"end_line":5,"end_column":38},"msg":{"node":{"StringLit":{"is_long_string":false,"raw_value":"\"_x need to be 'good case'\"","value":"_x need to be 'good case'"}},"filename":"assert-if-2.k","line":5,"column":40,"end_line":5,"end_column":67}}},"filename":"assert-if-2.k","line":5,"column":4,"end_line":5,"end_column":67}],"decorators":[],"checks":[],"index_signature":null}},"filename":"assert-if-2.k","line":1,"column":0,"end_line":7,"end_column":0},{"node":{"Assign":{"targets":[{"node":{"names":["data"],"pkgpath":"","ctx":"Store"},"filename":"assert-if-2.k","line":7,"column":0,"end_line":7,"end_column":4}],"value":{"node":{"Schema":{"name":{"node":{"names":["Data"],"pkgpath":"","ctx":"Load"},"filename":"assert-if-2.k","line":7,"column":7,"end_line":7,"end_column":11},"args":[],"kwargs":[],"config":{"node":{"Config":{"items":[]}},"filename":"assert-if-2.k","line":7,"column":12,"end_line":7,"end_column":14}}},"filename":"assert-if-2.k","line":7,"column":7,"end_line":7,"end_column":14},"type_annotation":null}},"filename":"assert-if-2.k","line":7,"column":0,"end_line":7,"end_column":15}],"comments":[]} diff --git a/kclvm/parser/testdata/assign-01.k.json b/kclvm/parser/testdata/assign-01.k.json deleted file mode 100644 index 5ba151537..000000000 --- a/kclvm/parser/testdata/assign-01.k.json +++ /dev/null @@ -1 +0,0 @@ -{"filename":"assign-01.k","pkg":"__main__","doc":"","name":"__main__","body":[{"node":{"Assign":{"targets":[{"node":{"names":["a"],"pkgpath":"","ctx":"Store"},"filename":"assign-01.k","line":1,"column":0,"end_line":1,"end_column":1}],"value":{"node":{"NumberLit":{"binary_suffix":null,"value":{"Int":1}}},"filename":"assign-01.k","line":1,"column":2,"end_line":1,"end_column":3},"type_annotation":null}},"filename":"assign-01.k","line":1,"column":0,"end_line":2,"end_column":0},{"node":{"Assign":{"targets":[{"node":{"names":["b"],"pkgpath":"","ctx":"Store"},"filename":"assign-01.k","line":2,"column":0,"end_line":2,"end_column":1}],"value":{"node":{"Binary":{"left":{"node":{"NumberLit":{"binary_suffix":null,"value":{"Int":1}}},"filename":"assign-01.k","line":2,"column":4,"end_line":2,"end_column":5},"op":{"Bin":"Add"},"right":{"node":{"NumberLit":{"binary_suffix":null,"value":{"Int":2}}},"filename":"assign-01.k","line":2,"column":8,"end_line":2,"end_column":9}}},"filename":"assign-01.k","line":2,"column":4,"end_line":2,"end_column":9},"type_annotation":null}},"filename":"assign-01.k","line":2,"column":0,"end_line":3,"end_column":0},{"node":{"Assign":{"targets":[{"node":{"names":["c"],"pkgpath":"","ctx":"Store"},"filename":"assign-01.k","line":3,"column":0,"end_line":3,"end_column":1}],"value":{"node":{"Binary":{"left":{"node":{"NumberLit":{"binary_suffix":null,"value":{"Int":2}}},"filename":"assign-01.k","line":3,"column":4,"end_line":3,"end_column":5},"op":{"Bin":"Add"},"right":{"node":{"Binary":{"left":{"node":{"NumberLit":{"binary_suffix":null,"value":{"Int":2}}},"filename":"assign-01.k","line":3,"column":8,"end_line":3,"end_column":9},"op":{"Bin":"Mul"},"right":{"node":{"NumberLit":{"binary_suffix":null,"value":{"Int":3}}},"filename":"assign-01.k","line":3,"column":10,"end_line":3,"end_column":11}}},"filename":"assign-01.k","line":3,"column":8,"end_line":3,"end_column":11}}},"filename":"assign-01.k","line":3,"column":4,"end_line":3,"end_column":11},"type_annotation":null}},"filename":"assign-01.k","line":3,"column":0,"end_line":3,"end_column":12}],"comments":[]} diff --git a/kclvm/parser/testdata/config_expr-01.k.json b/kclvm/parser/testdata/config_expr-01.k.json deleted file mode 100644 index 69b72efe8..000000000 --- a/kclvm/parser/testdata/config_expr-01.k.json +++ /dev/null @@ -1 +0,0 @@ -{"filename":"config_expr-01.k","pkg":"__main__","doc":"","name":"__main__","body":[{"node":{"Assign":{"targets":[{"node":{"names":["config"],"pkgpath":"","ctx":"Store"},"filename":"config_expr-01.k","line":1,"column":0,"end_line":1,"end_column":6}],"value":{"node":{"Config":{"items":[]}},"filename":"config_expr-01.k","line":1,"column":9,"end_line":2,"end_column":1},"type_annotation":null}},"filename":"config_expr-01.k","line":1,"column":0,"end_line":2,"end_column":2}],"comments":[]} diff --git a/kclvm/parser/testdata/config_expr-02.k.json b/kclvm/parser/testdata/config_expr-02.k.json deleted file mode 100644 index a53af3a1b..000000000 --- a/kclvm/parser/testdata/config_expr-02.k.json +++ /dev/null @@ -1 +0,0 @@ -{"filename":"config_expr-02.k","pkg":"__main__","doc":"","name":"__main__","body":[{"node":{"Assign":{"targets":[{"node":{"names":["config"],"pkgpath":"","ctx":"Store"},"filename":"config_expr-02.k","line":1,"column":0,"end_line":1,"end_column":6}],"value":{"node":{"Config":{"items":[{"node":{"key":{"node":{"Identifier":{"names":["k1"],"pkgpath":"","ctx":"Load"}},"filename":"config_expr-02.k","line":2,"column":4,"end_line":2,"end_column":6},"value":{"node":{"NumberLit":{"binary_suffix":null,"value":{"Int":111}}},"filename":"config_expr-02.k","line":2,"column":9,"end_line":2,"end_column":12},"operation":"Override","insert_index":-1},"filename":"config_expr-02.k","line":2,"column":4,"end_line":2,"end_column":12},{"node":{"key":{"node":{"Identifier":{"names":["k2"],"pkgpath":"","ctx":"Load"}},"filename":"config_expr-02.k","line":3,"column":4,"end_line":3,"end_column":6},"value":{"node":{"NumberLit":{"binary_suffix":null,"value":{"Int":222}}},"filename":"config_expr-02.k","line":3,"column":9,"end_line":3,"end_column":12},"operation":"Override","insert_index":-1},"filename":"config_expr-02.k","line":3,"column":4,"end_line":3,"end_column":12}]}},"filename":"config_expr-02.k","line":1,"column":9,"end_line":4,"end_column":1},"type_annotation":null}},"filename":"config_expr-02.k","line":1,"column":0,"end_line":4,"end_column":2}],"comments":[]} diff --git a/kclvm/parser/testdata/config_expr-03.k.json b/kclvm/parser/testdata/config_expr-03.k.json deleted file mode 100644 index ae716b613..000000000 --- a/kclvm/parser/testdata/config_expr-03.k.json +++ /dev/null @@ -1 +0,0 @@ -{"filename":"config_expr-03.k","pkg":"__main__","doc":"","name":"__main__","body":[{"node":{"Assign":{"targets":[{"node":{"names":["config"],"pkgpath":"","ctx":"Store"},"filename":"config_expr-03.k","line":3,"column":0,"end_line":3,"end_column":6}],"value":{"node":{"Config":{"items":[{"node":{"key":{"node":{"Identifier":{"names":["main"],"pkgpath":"","ctx":"Load"}},"filename":"config_expr-03.k","line":4,"column":4,"end_line":4,"end_column":8},"value":{"node":{"Config":{"items":[{"node":{"key":{"node":{"Identifier":{"names":["env"],"pkgpath":"","ctx":"Load"}},"filename":"config_expr-03.k","line":5,"column":8,"end_line":5,"end_column":11},"value":{"node":{"List":{"elts":[{"node":{"Config":{"items":[{"node":{"key":{"node":{"Identifier":{"names":["name"],"pkgpath":"","ctx":"Load"}},"filename":"config_expr-03.k","line":6,"column":13,"end_line":6,"end_column":17},"value":{"node":{"StringLit":{"is_long_string":false,"raw_value":"\"ENV_1\"","value":"ENV_1"}},"filename":"config_expr-03.k","line":6,"column":19,"end_line":6,"end_column":26},"operation":"Union","insert_index":-1},"filename":"config_expr-03.k","line":6,"column":13,"end_line":6,"end_column":26},{"node":{"key":{"node":{"Identifier":{"names":["value"],"pkgpath":"","ctx":"Load"}},"filename":"config_expr-03.k","line":6,"column":28,"end_line":6,"end_column":33},"value":{"node":{"StringLit":{"is_long_string":false,"raw_value":"\"1\"","value":"1"}},"filename":"config_expr-03.k","line":6,"column":35,"end_line":6,"end_column":38},"operation":"Union","insert_index":-1},"filename":"config_expr-03.k","line":6,"column":28,"end_line":6,"end_column":38}]}},"filename":"config_expr-03.k","line":6,"column":12,"end_line":6,"end_column":39}],"ctx":"Load"}},"filename":"config_expr-03.k","line":5,"column":13,"end_line":7,"end_column":9},"operation":"Union","insert_index":-1},"filename":"config_expr-03.k","line":5,"column":8,"end_line":7,"end_column":9}]}},"filename":"config_expr-03.k","line":4,"column":10,"end_line":8,"end_column":5},"operation":"Union","insert_index":-1},"filename":"config_expr-03.k","line":4,"column":4,"end_line":8,"end_column":5},{"node":{"key":{"node":{"Identifier":{"names":["main"],"pkgpath":"","ctx":"Load"}},"filename":"config_expr-03.k","line":9,"column":4,"end_line":9,"end_column":8},"value":{"node":{"Config":{"items":[{"node":{"key":{"node":{"Identifier":{"names":["env"],"pkgpath":"","ctx":"Load"}},"filename":"config_expr-03.k","line":10,"column":8,"end_line":10,"end_column":11},"value":{"node":{"List":{"elts":[{"node":{"Config":{"items":[{"node":{"key":{"node":{"Identifier":{"names":["name"],"pkgpath":"","ctx":"Load"}},"filename":"config_expr-03.k","line":11,"column":13,"end_line":11,"end_column":17},"value":{"node":{"StringLit":{"is_long_string":false,"raw_value":"\"ENV_2\"","value":"ENV_2"}},"filename":"config_expr-03.k","line":11,"column":19,"end_line":11,"end_column":26},"operation":"Union","insert_index":-1},"filename":"config_expr-03.k","line":11,"column":13,"end_line":11,"end_column":26},{"node":{"key":{"node":{"Identifier":{"names":["value"],"pkgpath":"","ctx":"Load"}},"filename":"config_expr-03.k","line":11,"column":28,"end_line":11,"end_column":33},"value":{"node":{"StringLit":{"is_long_string":false,"raw_value":"\"2\"","value":"2"}},"filename":"config_expr-03.k","line":11,"column":35,"end_line":11,"end_column":38},"operation":"Union","insert_index":-1},"filename":"config_expr-03.k","line":11,"column":28,"end_line":11,"end_column":38}]}},"filename":"config_expr-03.k","line":11,"column":12,"end_line":11,"end_column":39}],"ctx":"Load"}},"filename":"config_expr-03.k","line":10,"column":15,"end_line":12,"end_column":9},"operation":"Insert","insert_index":-1},"filename":"config_expr-03.k","line":10,"column":8,"end_line":12,"end_column":9}]}},"filename":"config_expr-03.k","line":9,"column":10,"end_line":13,"end_column":5},"operation":"Union","insert_index":-1},"filename":"config_expr-03.k","line":9,"column":4,"end_line":13,"end_column":5}]}},"filename":"config_expr-03.k","line":3,"column":9,"end_line":14,"end_column":1},"type_annotation":null}},"filename":"config_expr-03.k","line":3,"column":0,"end_line":14,"end_column":2}],"comments":[{"node":{"text":"# test/grammar/attr_operator/config_inside/insert/dict_0/main.k"},"filename":"config_expr-03.k","line":1,"column":0,"end_line":1,"end_column":63}]} diff --git a/kclvm/parser/testdata/config_expr-04.k.json b/kclvm/parser/testdata/config_expr-04.k.json deleted file mode 100644 index e4a711f5e..000000000 --- a/kclvm/parser/testdata/config_expr-04.k.json +++ /dev/null @@ -1 +0,0 @@ -{"filename":"config_expr-04.k","pkg":"__main__","doc":"","name":"__main__","body":[{"node":{"Schema":{"doc":"","name":{"node":"Env","filename":"config_expr-04.k","line":3,"column":7,"end_line":3,"end_column":10},"parent_name":null,"for_host_name":null,"is_mixin":false,"is_protocol":false,"args":null,"mixins":[],"body":[{"node":{"SchemaAttr":{"doc":"","name":{"node":"name","filename":"config_expr-04.k","line":4,"column":4,"end_line":4,"end_column":8},"type_str":{"node":"str","filename":"config_expr-04.k","line":4,"column":10,"end_line":4,"end_column":13},"op":null,"value":null,"is_optional":false,"decorators":[]}},"filename":"config_expr-04.k","line":4,"column":4,"end_line":5,"end_column":0},{"node":{"SchemaAttr":{"doc":"","name":{"node":"value","filename":"config_expr-04.k","line":5,"column":4,"end_line":5,"end_column":9},"type_str":{"node":"str","filename":"config_expr-04.k","line":5,"column":11,"end_line":5,"end_column":14},"op":null,"value":null,"is_optional":false,"decorators":[]}},"filename":"config_expr-04.k","line":5,"column":4,"end_line":7,"end_column":0}],"decorators":[],"checks":[],"index_signature":null}},"filename":"config_expr-04.k","line":3,"column":0,"end_line":7,"end_column":0},{"node":{"Schema":{"doc":"","name":{"node":"Main","filename":"config_expr-04.k","line":7,"column":7,"end_line":7,"end_column":11},"parent_name":null,"for_host_name":null,"is_mixin":false,"is_protocol":false,"args":null,"mixins":[],"body":[{"node":{"SchemaAttr":{"doc":"","name":{"node":"env","filename":"config_expr-04.k","line":8,"column":4,"end_line":8,"end_column":7},"type_str":{"node":"[Env]","filename":"config_expr-04.k","line":8,"column":9,"end_line":8,"end_column":14},"op":null,"value":null,"is_optional":false,"decorators":[]}},"filename":"config_expr-04.k","line":8,"column":4,"end_line":10,"end_column":0}],"decorators":[],"checks":[],"index_signature":null}},"filename":"config_expr-04.k","line":7,"column":0,"end_line":10,"end_column":0},{"node":{"Schema":{"doc":"","name":{"node":"Config","filename":"config_expr-04.k","line":10,"column":7,"end_line":10,"end_column":13},"parent_name":null,"for_host_name":null,"is_mixin":false,"is_protocol":false,"args":null,"mixins":[],"body":[{"node":{"SchemaAttr":{"doc":"","name":{"node":"main","filename":"config_expr-04.k","line":11,"column":4,"end_line":11,"end_column":8},"type_str":{"node":"Main","filename":"config_expr-04.k","line":11,"column":10,"end_line":11,"end_column":14},"op":null,"value":null,"is_optional":false,"decorators":[]}},"filename":"config_expr-04.k","line":11,"column":4,"end_line":13,"end_column":0}],"decorators":[],"checks":[],"index_signature":null}},"filename":"config_expr-04.k","line":10,"column":0,"end_line":13,"end_column":0},{"node":{"Assign":{"targets":[{"node":{"names":["_main"],"pkgpath":"","ctx":"Store"},"filename":"config_expr-04.k","line":13,"column":0,"end_line":13,"end_column":5}],"value":{"node":{"Schema":{"name":{"node":{"names":["Main"],"pkgpath":"","ctx":"Load"},"filename":"config_expr-04.k","line":13,"column":8,"end_line":13,"end_column":12},"args":[],"kwargs":[],"config":{"node":{"Config":{"items":[{"node":{"key":{"node":{"Identifier":{"names":["env"],"pkgpath":"","ctx":"Load"}},"filename":"config_expr-04.k","line":14,"column":4,"end_line":14,"end_column":7},"value":{"node":{"List":{"elts":[{"node":{"Config":{"items":[{"node":{"key":{"node":{"Identifier":{"names":["name"],"pkgpath":"","ctx":"Load"}},"filename":"config_expr-04.k","line":15,"column":9,"end_line":15,"end_column":13},"value":{"node":{"StringLit":{"is_long_string":false,"raw_value":"\"ENV_1\"","value":"ENV_1"}},"filename":"config_expr-04.k","line":15,"column":15,"end_line":15,"end_column":22},"operation":"Union","insert_index":-1},"filename":"config_expr-04.k","line":15,"column":9,"end_line":15,"end_column":22},{"node":{"key":{"node":{"Identifier":{"names":["value"],"pkgpath":"","ctx":"Load"}},"filename":"config_expr-04.k","line":15,"column":24,"end_line":15,"end_column":29},"value":{"node":{"StringLit":{"is_long_string":false,"raw_value":"\"1\"","value":"1"}},"filename":"config_expr-04.k","line":15,"column":31,"end_line":15,"end_column":34},"operation":"Union","insert_index":-1},"filename":"config_expr-04.k","line":15,"column":24,"end_line":15,"end_column":34}]}},"filename":"config_expr-04.k","line":15,"column":8,"end_line":15,"end_column":35}],"ctx":"Load"}},"filename":"config_expr-04.k","line":14,"column":9,"end_line":16,"end_column":5},"operation":"Union","insert_index":-1},"filename":"config_expr-04.k","line":14,"column":4,"end_line":16,"end_column":5}]}},"filename":"config_expr-04.k","line":13,"column":13,"end_line":17,"end_column":1}}},"filename":"config_expr-04.k","line":13,"column":8,"end_line":17,"end_column":1},"type_annotation":null}},"filename":"config_expr-04.k","line":13,"column":0,"end_line":19,"end_column":0},{"node":{"Assign":{"targets":[{"node":{"names":["config"],"pkgpath":"","ctx":"Store"},"filename":"config_expr-04.k","line":19,"column":0,"end_line":19,"end_column":6}],"value":{"node":{"Schema":{"name":{"node":{"names":["Config"],"pkgpath":"","ctx":"Load"},"filename":"config_expr-04.k","line":19,"column":9,"end_line":19,"end_column":15},"args":[],"kwargs":[],"config":{"node":{"Config":{"items":[{"node":{"key":{"node":{"Identifier":{"names":["main"],"pkgpath":"","ctx":"Load"}},"filename":"config_expr-04.k","line":20,"column":4,"end_line":20,"end_column":8},"value":{"node":{"Identifier":{"names":["_main"],"pkgpath":"","ctx":"Load"}},"filename":"config_expr-04.k","line":20,"column":10,"end_line":20,"end_column":15},"operation":"Union","insert_index":-1},"filename":"config_expr-04.k","line":20,"column":4,"end_line":20,"end_column":15},{"node":{"key":{"node":{"Identifier":{"names":["main"],"pkgpath":"","ctx":"Load"}},"filename":"config_expr-04.k","line":21,"column":4,"end_line":21,"end_column":8},"value":{"node":{"Schema":{"name":{"node":{"names":["Main"],"pkgpath":"","ctx":"Load"},"filename":"config_expr-04.k","line":21,"column":10,"end_line":21,"end_column":14},"args":[],"kwargs":[],"config":{"node":{"Config":{"items":[{"node":{"key":{"node":{"Identifier":{"names":["env"],"pkgpath":"","ctx":"Load"}},"filename":"config_expr-04.k","line":22,"column":8,"end_line":22,"end_column":11},"value":{"node":{"List":{"elts":[{"node":{"Config":{"items":[{"node":{"key":{"node":{"Identifier":{"names":["name"],"pkgpath":"","ctx":"Load"}},"filename":"config_expr-04.k","line":23,"column":13,"end_line":23,"end_column":17},"value":{"node":{"StringLit":{"is_long_string":false,"raw_value":"\"ENV_2\"","value":"ENV_2"}},"filename":"config_expr-04.k","line":23,"column":19,"end_line":23,"end_column":26},"operation":"Union","insert_index":-1},"filename":"config_expr-04.k","line":23,"column":13,"end_line":23,"end_column":26},{"node":{"key":{"node":{"Identifier":{"names":["value"],"pkgpath":"","ctx":"Load"}},"filename":"config_expr-04.k","line":23,"column":28,"end_line":23,"end_column":33},"value":{"node":{"StringLit":{"is_long_string":false,"raw_value":"\"2\"","value":"2"}},"filename":"config_expr-04.k","line":23,"column":35,"end_line":23,"end_column":38},"operation":"Union","insert_index":-1},"filename":"config_expr-04.k","line":23,"column":28,"end_line":23,"end_column":38}]}},"filename":"config_expr-04.k","line":23,"column":12,"end_line":23,"end_column":39}],"ctx":"Load"}},"filename":"config_expr-04.k","line":22,"column":15,"end_line":24,"end_column":9},"operation":"Insert","insert_index":-1},"filename":"config_expr-04.k","line":22,"column":8,"end_line":24,"end_column":9}]}},"filename":"config_expr-04.k","line":21,"column":15,"end_line":25,"end_column":5}}},"filename":"config_expr-04.k","line":21,"column":10,"end_line":25,"end_column":5},"operation":"Union","insert_index":-1},"filename":"config_expr-04.k","line":21,"column":4,"end_line":25,"end_column":5}]}},"filename":"config_expr-04.k","line":19,"column":16,"end_line":26,"end_column":1}}},"filename":"config_expr-04.k","line":19,"column":9,"end_line":26,"end_column":1},"type_annotation":null}},"filename":"config_expr-04.k","line":19,"column":0,"end_line":26,"end_column":2}],"comments":[{"node":{"text":"# test/grammar/attr_operator/config_inside/insert/schema_0/main.k"},"filename":"config_expr-04.k","line":1,"column":0,"end_line":1,"end_column":65}]} diff --git a/kclvm/parser/testdata/a1.k b/kclvm/parser/testdata/expand_file_pattern/KCL_MOD similarity index 100% rename from kclvm/parser/testdata/a1.k rename to kclvm/parser/testdata/expand_file_pattern/KCL_MOD diff --git a/kclvm/parser/testdata/expand_file_pattern/kcl.mod b/kclvm/parser/testdata/expand_file_pattern/kcl.mod new file mode 100644 index 000000000..f647ff5c5 --- /dev/null +++ b/kclvm/parser/testdata/expand_file_pattern/kcl.mod @@ -0,0 +1,5 @@ +[package] +name = "expand_file_pattern" +edition = "0.0.1" +version = "0.0.1" + diff --git a/kclvm/parser/testdata/expand_file_pattern/kcl1/kcl.mod b/kclvm/parser/testdata/expand_file_pattern/kcl1/kcl.mod new file mode 100644 index 000000000..ab572545d --- /dev/null +++ b/kclvm/parser/testdata/expand_file_pattern/kcl1/kcl.mod @@ -0,0 +1,5 @@ +[package] +name = "kcl1" +edition = "0.0.1" +version = "0.0.1" + diff --git a/kclvm/parser/testdata/expand_file_pattern/kcl1/kcl2/kcl.mod b/kclvm/parser/testdata/expand_file_pattern/kcl1/kcl2/kcl.mod new file mode 100644 index 000000000..5fb058acd --- /dev/null +++ b/kclvm/parser/testdata/expand_file_pattern/kcl1/kcl2/kcl.mod @@ -0,0 +1,5 @@ +[package] +name = "kcl2" +edition = "0.0.1" +version = "0.0.1" + diff --git a/kclvm/parser/testdata/expand_file_pattern/kcl1/kcl2/main.k b/kclvm/parser/testdata/expand_file_pattern/kcl1/kcl2/main.k new file mode 100644 index 000000000..fa7048e63 --- /dev/null +++ b/kclvm/parser/testdata/expand_file_pattern/kcl1/kcl2/main.k @@ -0,0 +1 @@ +The_first_kcl_program = 'Hello World!' \ No newline at end of file diff --git a/kclvm/parser/testdata/expand_file_pattern/kcl1/kcl4/kcl.mod b/kclvm/parser/testdata/expand_file_pattern/kcl1/kcl4/kcl.mod new file mode 100644 index 000000000..98f429002 --- /dev/null +++ b/kclvm/parser/testdata/expand_file_pattern/kcl1/kcl4/kcl.mod @@ -0,0 +1,5 @@ +[package] +name = "kcl4" +edition = "0.0.1" +version = "0.0.1" + diff --git a/kclvm/parser/testdata/expand_file_pattern/kcl1/kcl4/main.k b/kclvm/parser/testdata/expand_file_pattern/kcl1/kcl4/main.k new file mode 100644 index 000000000..fa7048e63 --- /dev/null +++ b/kclvm/parser/testdata/expand_file_pattern/kcl1/kcl4/main.k @@ -0,0 +1 @@ +The_first_kcl_program = 'Hello World!' \ No newline at end of file diff --git a/kclvm/parser/testdata/expand_file_pattern/kcl1/main.k b/kclvm/parser/testdata/expand_file_pattern/kcl1/main.k new file mode 100644 index 000000000..fa7048e63 --- /dev/null +++ b/kclvm/parser/testdata/expand_file_pattern/kcl1/main.k @@ -0,0 +1 @@ +The_first_kcl_program = 'Hello World!' \ No newline at end of file diff --git a/kclvm/parser/testdata/expand_file_pattern/kcl3/kcl.mod b/kclvm/parser/testdata/expand_file_pattern/kcl3/kcl.mod new file mode 100644 index 000000000..b99124970 --- /dev/null +++ b/kclvm/parser/testdata/expand_file_pattern/kcl3/kcl.mod @@ -0,0 +1,5 @@ +[package] +name = "kcl3" +edition = "0.0.1" +version = "0.0.1" + diff --git a/kclvm/parser/testdata/expand_file_pattern/kcl3/main.k b/kclvm/parser/testdata/expand_file_pattern/kcl3/main.k new file mode 100644 index 000000000..fa7048e63 --- /dev/null +++ b/kclvm/parser/testdata/expand_file_pattern/kcl3/main.k @@ -0,0 +1 @@ +The_first_kcl_program = 'Hello World!' \ No newline at end of file diff --git a/kclvm/parser/testdata/expand_file_pattern/main.k b/kclvm/parser/testdata/expand_file_pattern/main.k new file mode 100644 index 000000000..fa7048e63 --- /dev/null +++ b/kclvm/parser/testdata/expand_file_pattern/main.k @@ -0,0 +1 @@ +The_first_kcl_program = 'Hello World!' \ No newline at end of file diff --git a/kclvm/parser/testdata/hello_win.k b/kclvm/parser/testdata/hello_win.k new file mode 100644 index 000000000..d31f013fe --- /dev/null +++ b/kclvm/parser/testdata/hello_win.k @@ -0,0 +1,5 @@ + +schema Person: + name: str = "kcl" + +x0 = Person {} diff --git a/kclvm/parser/testdata/if-01.k.json b/kclvm/parser/testdata/if-01.k.json deleted file mode 100644 index ea4fa48cf..000000000 --- a/kclvm/parser/testdata/if-01.k.json +++ /dev/null @@ -1 +0,0 @@ -{"filename":"if-01.k","pkg":"__main__","doc":"","name":"__main__","body":[{"node":{"Assign":{"targets":[{"node":{"names":["a"],"pkgpath":"","ctx":"Store"},"filename":"if-01.k","line":1,"column":0,"end_line":1,"end_column":1}],"value":{"node":{"NumberLit":{"binary_suffix":null,"value":{"Int":1}}},"filename":"if-01.k","line":1,"column":4,"end_line":1,"end_column":5},"type_annotation":null}},"filename":"if-01.k","line":1,"column":0,"end_line":3,"end_column":0},{"node":{"If":{"body":[{"node":{"Assign":{"targets":[{"node":{"names":["bbb"],"pkgpath":"","ctx":"Store"},"filename":"if-01.k","line":4,"column":4,"end_line":4,"end_column":7}],"value":{"node":{"NumberLit":{"binary_suffix":null,"value":{"Int":2}}},"filename":"if-01.k","line":4,"column":10,"end_line":4,"end_column":11},"type_annotation":null}},"filename":"if-01.k","line":4,"column":4,"end_line":4,"end_column":12}],"cond":{"node":{"Identifier":{"names":["a"],"pkgpath":"","ctx":"Load"}},"filename":"if-01.k","line":3,"column":3,"end_line":3,"end_column":4},"orelse":[]}},"filename":"if-01.k","line":3,"column":0,"end_line":4,"end_column":12}],"comments":[]} diff --git a/kclvm/parser/testdata/if-02.k b/kclvm/parser/testdata/if-02.k index 5132d411e..e66aed39a 100644 --- a/kclvm/parser/testdata/if-02.k +++ b/kclvm/parser/testdata/if-02.k @@ -8,3 +8,4 @@ elif a + 100: ddd = 4 else: eee = 5 + fff = 6 diff --git a/kclvm/parser/testdata/if-02.k.json b/kclvm/parser/testdata/if-02.k.json deleted file mode 100644 index 7fdc9b69e..000000000 --- a/kclvm/parser/testdata/if-02.k.json +++ /dev/null @@ -1 +0,0 @@ -{"filename":"if-02.k","pkg":"__main__","doc":"","name":"__main__","body":[{"node":{"Assign":{"targets":[{"node":{"names":["a"],"pkgpath":"","ctx":"Store"},"filename":"if-02.k","line":1,"column":0,"end_line":1,"end_column":1}],"value":{"node":{"NumberLit":{"binary_suffix":null,"value":{"Int":1}}},"filename":"if-02.k","line":1,"column":4,"end_line":1,"end_column":5},"type_annotation":null}},"filename":"if-02.k","line":1,"column":0,"end_line":3,"end_column":0},{"node":{"If":{"body":[{"node":{"Assign":{"targets":[{"node":{"names":["bbb"],"pkgpath":"","ctx":"Store"},"filename":"if-02.k","line":4,"column":4,"end_line":4,"end_column":7}],"value":{"node":{"NumberLit":{"binary_suffix":null,"value":{"Int":2}}},"filename":"if-02.k","line":4,"column":10,"end_line":4,"end_column":11},"type_annotation":null}},"filename":"if-02.k","line":4,"column":4,"end_line":5,"end_column":0}],"cond":{"node":{"Identifier":{"names":["a"],"pkgpath":"","ctx":"Load"}},"filename":"if-02.k","line":3,"column":3,"end_line":3,"end_column":4},"orelse":[{"node":{"If":{"body":[{"node":{"Assign":{"targets":[{"node":{"names":["ccc"],"pkgpath":"","ctx":"Store"},"filename":"if-02.k","line":6,"column":4,"end_line":6,"end_column":7}],"value":{"node":{"NumberLit":{"binary_suffix":null,"value":{"Int":3}}},"filename":"if-02.k","line":6,"column":10,"end_line":6,"end_column":11},"type_annotation":null}},"filename":"if-02.k","line":6,"column":4,"end_line":7,"end_column":0}],"cond":{"node":{"Binary":{"left":{"node":{"Identifier":{"names":["a"],"pkgpath":"","ctx":"Load"}},"filename":"if-02.k","line":5,"column":5,"end_line":5,"end_column":6},"op":{"Bin":"Add"},"right":{"node":{"NumberLit":{"binary_suffix":null,"value":{"Int":10}}},"filename":"if-02.k","line":5,"column":9,"end_line":5,"end_column":11}}},"filename":"if-02.k","line":5,"column":5,"end_line":5,"end_column":11},"orelse":[{"node":{"If":{"body":[{"node":{"Assign":{"targets":[{"node":{"names":["ddd"],"pkgpath":"","ctx":"Store"},"filename":"if-02.k","line":8,"column":4,"end_line":8,"end_column":7}],"value":{"node":{"NumberLit":{"binary_suffix":null,"value":{"Int":4}}},"filename":"if-02.k","line":8,"column":10,"end_line":8,"end_column":11},"type_annotation":null}},"filename":"if-02.k","line":8,"column":4,"end_line":9,"end_column":0}],"cond":{"node":{"Binary":{"left":{"node":{"Identifier":{"names":["a"],"pkgpath":"","ctx":"Load"}},"filename":"if-02.k","line":7,"column":5,"end_line":7,"end_column":6},"op":{"Bin":"Add"},"right":{"node":{"NumberLit":{"binary_suffix":null,"value":{"Int":100}}},"filename":"if-02.k","line":7,"column":9,"end_line":7,"end_column":12}}},"filename":"if-02.k","line":7,"column":5,"end_line":7,"end_column":12},"orelse":[{"node":{"Assign":{"targets":[{"node":{"names":["eee"],"pkgpath":"","ctx":"Store"},"filename":"if-02.k","line":10,"column":4,"end_line":10,"end_column":7}],"value":{"node":{"NumberLit":{"binary_suffix":null,"value":{"Int":5}}},"filename":"if-02.k","line":10,"column":10,"end_line":10,"end_column":11},"type_annotation":null}},"filename":"if-02.k","line":10,"column":4,"end_line":10,"end_column":12}]}},"filename":"if-02.k","line":7,"column":0,"end_line":9,"end_column":0}]}},"filename":"if-02.k","line":5,"column":0,"end_line":7,"end_column":0}]}},"filename":"if-02.k","line":3,"column":0,"end_line":10,"end_column":12}],"comments":[]} diff --git a/kclvm/parser/testdata/if-03.k.json b/kclvm/parser/testdata/if-03.k.json deleted file mode 100644 index b0e7c0339..000000000 --- a/kclvm/parser/testdata/if-03.k.json +++ /dev/null @@ -1 +0,0 @@ -{"filename":"if-03.k","pkg":"__main__","doc":"","name":"__main__","body":[{"node":{"If":{"body":[{"node":{"Assign":{"targets":[{"node":{"names":["a"],"pkgpath":"","ctx":"Store"},"filename":"if-03.k","line":1,"column":9,"end_line":1,"end_column":10}],"value":{"node":{"NumberLit":{"binary_suffix":null,"value":{"Int":1}}},"filename":"if-03.k","line":1,"column":13,"end_line":1,"end_column":14},"type_annotation":null}},"filename":"if-03.k","line":1,"column":9,"end_line":1,"end_column":15}],"cond":{"node":{"NameConstantLit":{"value":"True"}},"filename":"if-03.k","line":1,"column":3,"end_line":1,"end_column":7},"orelse":[]}},"filename":"if-03.k","line":1,"column":0,"end_line":1,"end_column":15}],"comments":[]} diff --git a/kclvm/parser/testdata/import-01.k.json b/kclvm/parser/testdata/import-01.k.json deleted file mode 100644 index be1415934..000000000 --- a/kclvm/parser/testdata/import-01.k.json +++ /dev/null @@ -1 +0,0 @@ -{"filename":"import-01.k","pkg":"__main__","doc":"","name":"__main__","body":[{"node":{"Import":{"path":"a1","rawpath":"a1","name":"a1","asname":null}},"filename":"import-01.k","line":1,"column":0,"end_line":1,"end_column":9},{"node":{"Import":{"path":"a2","rawpath":"a2","name":"a2_pkg","asname":"a2_pkg"}},"filename":"import-01.k","line":3,"column":0,"end_line":3,"end_column":19},{"node":{"Import":{"path":"subpkg.b1.c1","rawpath":"subpkg.b1.c1","name":"c1","asname":null}},"filename":"import-01.k","line":5,"column":0,"end_line":5,"end_column":19},{"node":{"Import":{"path":".a3","rawpath":".a3","name":"a3","asname":null}},"filename":"import-01.k","line":7,"column":0,"end_line":7,"end_column":10}],"comments":[]} diff --git a/kclvm/parser/testdata/import_vendor/assign.k b/kclvm/parser/testdata/import_vendor/assign.k new file mode 100644 index 000000000..f15b076e4 --- /dev/null +++ b/kclvm/parser/testdata/import_vendor/assign.k @@ -0,0 +1,10 @@ +import assign as a +import assign.assign as aa + +a_a = a.a +a_b = a.b +a_c = a.c + +aa_a = aa.a +aa_b = aa.b +aa_c = aa.c \ No newline at end of file diff --git a/kclvm/parser/testdata/import_vendor/config_expr.k b/kclvm/parser/testdata/import_vendor/config_expr.k new file mode 100644 index 000000000..6772ce0b5 --- /dev/null +++ b/kclvm/parser/testdata/import_vendor/config_expr.k @@ -0,0 +1,5 @@ +import config_expr as ce +import config_expr.config_expr_02 as cece + +demo_ce = ce.config +demo_cece = cece.config \ No newline at end of file diff --git a/kclvm/parser/testdata/import_vendor/nested_vendor.k b/kclvm/parser/testdata/import_vendor/nested_vendor.k new file mode 100644 index 000000000..8aa3ab780 --- /dev/null +++ b/kclvm/parser/testdata/import_vendor/nested_vendor.k @@ -0,0 +1,14 @@ +import nested_vendor as nv +import nested_vendor.nested_vendor as nvnv + +nv_sub_in_subpkg = nv.sub_in_subpkg +nv_sub1_in_subpkg = nv.sub1_in_subpkg + +nv_sub_in_sub2_in_subpkg = nv.sub_in_sub2_in_subpkg +nv_sub1_in_sub2_in_subpkg = nv.sub1_in_sub2_in_subpkg + +nvnv_sub_in_subpkg = nvnv.sub_in_subpkg +nvnv_sub1_in_subpkg = nvnv.sub1_in_subpkg + +nvnv_sub_in_sub2_in_subpkg = nvnv.sub_in_sub2_in_subpkg +nvnv_sub1_in_sub2_in_subpkg = nvnv.sub1_in_sub2_in_subpkg \ No newline at end of file diff --git a/kclvm/parser/testdata/import_vendor/same_name.k b/kclvm/parser/testdata/import_vendor/same_name.k new file mode 100644 index 000000000..5da68daa3 --- /dev/null +++ b/kclvm/parser/testdata/import_vendor/same_name.k @@ -0,0 +1,3 @@ +import same_vendor as sv + +demo = sv.sv \ No newline at end of file diff --git a/kclvm/parser/testdata/import_vendor/subpkg.k b/kclvm/parser/testdata/import_vendor/subpkg.k new file mode 100644 index 000000000..88825f67f --- /dev/null +++ b/kclvm/parser/testdata/import_vendor/subpkg.k @@ -0,0 +1,7 @@ +import vendor_subpkg as sub + +sub_in_subpkg = sub.sub_in_subpkg +sub1_in_subpkg = sub.sub1_in_subpkg + +sub_in_sub2_in_subpkg = sub.sub_in_sub2_in_subpkg +sub1_in_sub2_in_subpkg = sub.sub1_in_sub2_in_subpkg \ No newline at end of file diff --git a/kclvm/parser/testdata/parse_all_modules/a/kcl.mod b/kclvm/parser/testdata/parse_all_modules/a/kcl.mod new file mode 100644 index 000000000..31e3a3003 --- /dev/null +++ b/kclvm/parser/testdata/parse_all_modules/a/kcl.mod @@ -0,0 +1,9 @@ +[package] +name = "a" +edition = "v0.9.0" +version = "0.0.1" + +[dependencies] +b = { path = "../b" } +helloworld = "0.0.1" + diff --git a/kclvm/parser/testdata/parse_all_modules/a/main.k b/kclvm/parser/testdata/parse_all_modules/a/main.k new file mode 100644 index 000000000..fa7048e63 --- /dev/null +++ b/kclvm/parser/testdata/parse_all_modules/a/main.k @@ -0,0 +1 @@ +The_first_kcl_program = 'Hello World!' \ No newline at end of file diff --git a/kclvm/parser/testdata/a2.k b/kclvm/parser/testdata/parse_all_modules/a/sub/sub.k similarity index 100% rename from kclvm/parser/testdata/a2.k rename to kclvm/parser/testdata/parse_all_modules/a/sub/sub.k diff --git a/kclvm/parser/testdata/parse_all_modules/b/kcl.mod b/kclvm/parser/testdata/parse_all_modules/b/kcl.mod new file mode 100644 index 000000000..f1a67ab29 --- /dev/null +++ b/kclvm/parser/testdata/parse_all_modules/b/kcl.mod @@ -0,0 +1,6 @@ +[package] +name = "b" +edition = "v0.9.0" +version = "0.0.1" + + diff --git a/kclvm/parser/testdata/parse_all_modules/b/main.k b/kclvm/parser/testdata/parse_all_modules/b/main.k new file mode 100644 index 000000000..fa7048e63 --- /dev/null +++ b/kclvm/parser/testdata/parse_all_modules/b/main.k @@ -0,0 +1 @@ +The_first_kcl_program = 'Hello World!' \ No newline at end of file diff --git a/kclvm/parser/testdata/parse_all_modules/helloworld_0.0.1/README.md b/kclvm/parser/testdata/parse_all_modules/helloworld_0.0.1/README.md new file mode 100644 index 000000000..4d63fef38 --- /dev/null +++ b/kclvm/parser/testdata/parse_all_modules/helloworld_0.0.1/README.md @@ -0,0 +1,2 @@ +## Introduction +This is a kcl package named helloworld. diff --git a/kclvm/parser/testdata/parse_all_modules/helloworld_0.0.1/kcl.mod b/kclvm/parser/testdata/parse_all_modules/helloworld_0.0.1/kcl.mod new file mode 100644 index 000000000..bef7e7f76 --- /dev/null +++ b/kclvm/parser/testdata/parse_all_modules/helloworld_0.0.1/kcl.mod @@ -0,0 +1,5 @@ +[package] +name = "helloworld" +edition = "0.0.1" +version = "0.0.1" + diff --git a/kclvm/parser/testdata/parse_all_modules/helloworld_0.0.1/main.k b/kclvm/parser/testdata/parse_all_modules/helloworld_0.0.1/main.k new file mode 100644 index 000000000..fa7048e63 --- /dev/null +++ b/kclvm/parser/testdata/parse_all_modules/helloworld_0.0.1/main.k @@ -0,0 +1 @@ +The_first_kcl_program = 'Hello World!' \ No newline at end of file diff --git a/test/grammar/path_selector/mod_root/kcl.mod b/kclvm/parser/testdata/same_vendor/kcl.mod similarity index 100% rename from test/grammar/path_selector/mod_root/kcl.mod rename to kclvm/parser/testdata/same_vendor/kcl.mod diff --git a/kclvm/parser/testdata/same_vendor/same_vendor.k b/kclvm/parser/testdata/same_vendor/same_vendor.k new file mode 100644 index 000000000..d445f2c1a --- /dev/null +++ b/kclvm/parser/testdata/same_vendor/same_vendor.k @@ -0,0 +1 @@ +sv = "same vendor pkg." \ No newline at end of file diff --git a/kclvm/parser/testdata/test_vendor/assign/assign.k b/kclvm/parser/testdata/test_vendor/assign/assign.k new file mode 100644 index 000000000..a044863e7 --- /dev/null +++ b/kclvm/parser/testdata/test_vendor/assign/assign.k @@ -0,0 +1,3 @@ +a=1 +b = 1 + 2 +c = 2 + 2*3 diff --git a/test/test_units/test_kclvm/test_api/test_object/path_selector_test_data/kcl.mod b/kclvm/parser/testdata/test_vendor/assign/kcl.mod similarity index 100% rename from test/test_units/test_kclvm/test_api/test_object/path_selector_test_data/kcl.mod rename to kclvm/parser/testdata/test_vendor/assign/kcl.mod diff --git a/kclvm/parser/testdata/test_vendor/config_expr/config_expr_02.k b/kclvm/parser/testdata/test_vendor/config_expr/config_expr_02.k new file mode 100644 index 000000000..f830e360a --- /dev/null +++ b/kclvm/parser/testdata/test_vendor/config_expr/config_expr_02.k @@ -0,0 +1,4 @@ +config = { + k1 = 111 + k2 = 222 +} diff --git a/test/test_units/test_kclvm/test_compiler/test_build/invalid_testdata/kcl.mod b/kclvm/parser/testdata/test_vendor/config_expr/kcl.mod similarity index 100% rename from test/test_units/test_kclvm/test_compiler/test_build/invalid_testdata/kcl.mod rename to kclvm/parser/testdata/test_vendor/config_expr/kcl.mod diff --git a/test/test_units/test_kclvm/test_compiler/test_build/invalid_testdata/nest_import/kcl.mod b/kclvm/parser/testdata/test_vendor/nested_vendor/kcl.mod similarity index 100% rename from test/test_units/test_kclvm/test_compiler/test_build/invalid_testdata/nest_import/kcl.mod rename to kclvm/parser/testdata/test_vendor/nested_vendor/kcl.mod diff --git a/kclvm/parser/testdata/test_vendor/nested_vendor/nested_vendor.k b/kclvm/parser/testdata/test_vendor/nested_vendor/nested_vendor.k new file mode 100644 index 000000000..010cf5e67 --- /dev/null +++ b/kclvm/parser/testdata/test_vendor/nested_vendor/nested_vendor.k @@ -0,0 +1,7 @@ +import vendor_subpkg as sub + +sub_in_subpkg = sub.sub_in_subpkg +sub1_in_subpkg = sub.sub1_in_subpkg + +sub_in_sub2_in_subpkg = sub.sub_in_sub2_in_subpkg +sub1_in_sub2_in_subpkg = sub.sub1_in_sub2_in_subpkg diff --git a/kclvm/parser/testdata/test_vendor/nested_vendor/sub/sub.k b/kclvm/parser/testdata/test_vendor/nested_vendor/sub/sub.k new file mode 100644 index 000000000..fd778d797 --- /dev/null +++ b/kclvm/parser/testdata/test_vendor/nested_vendor/sub/sub.k @@ -0,0 +1 @@ +sub = "sub" \ No newline at end of file diff --git a/kclvm/parser/testdata/test_vendor/nested_vendor/sub/sub1.k b/kclvm/parser/testdata/test_vendor/nested_vendor/sub/sub1.k new file mode 100644 index 000000000..7e2e764b4 --- /dev/null +++ b/kclvm/parser/testdata/test_vendor/nested_vendor/sub/sub1.k @@ -0,0 +1 @@ +sub1 = "sub1" \ No newline at end of file diff --git a/kclvm/parser/testdata/test_vendor/nested_vendor/sub/sub2/sub2.k b/kclvm/parser/testdata/test_vendor/nested_vendor/sub/sub2/sub2.k new file mode 100644 index 000000000..dc262a825 --- /dev/null +++ b/kclvm/parser/testdata/test_vendor/nested_vendor/sub/sub2/sub2.k @@ -0,0 +1,6 @@ +import ..sub as sub +import ..sub1 as sub1 + +sub2 = "sub2" +sub_in_sub2 = sub.sub +sub1_in_sub2 = sub1.sub1 \ No newline at end of file diff --git a/test/test_units/test_kclvm/test_compiler/test_build/scope_testdata/kcl.mod b/kclvm/parser/testdata/test_vendor/same_vendor/kcl.mod similarity index 100% rename from test/test_units/test_kclvm/test_compiler/test_build/scope_testdata/kcl.mod rename to kclvm/parser/testdata/test_vendor/same_vendor/kcl.mod diff --git a/kclvm/parser/testdata/test_vendor/same_vendor/same_vendor.k b/kclvm/parser/testdata/test_vendor/same_vendor/same_vendor.k new file mode 100644 index 000000000..d445f2c1a --- /dev/null +++ b/kclvm/parser/testdata/test_vendor/same_vendor/same_vendor.k @@ -0,0 +1 @@ +sv = "same vendor pkg." \ No newline at end of file diff --git a/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/kcl.mod b/kclvm/parser/testdata/test_vendor/vendor_subpkg/kcl.mod similarity index 100% rename from test/test_units/test_kclvm/test_compiler/test_eval/eval_data/kcl.mod rename to kclvm/parser/testdata/test_vendor/vendor_subpkg/kcl.mod diff --git a/kclvm/parser/testdata/test_vendor/vendor_subpkg/sub/sub.k b/kclvm/parser/testdata/test_vendor/vendor_subpkg/sub/sub.k new file mode 100644 index 000000000..fd778d797 --- /dev/null +++ b/kclvm/parser/testdata/test_vendor/vendor_subpkg/sub/sub.k @@ -0,0 +1 @@ +sub = "sub" \ No newline at end of file diff --git a/kclvm/parser/testdata/test_vendor/vendor_subpkg/sub/sub1.k b/kclvm/parser/testdata/test_vendor/vendor_subpkg/sub/sub1.k new file mode 100644 index 000000000..7e2e764b4 --- /dev/null +++ b/kclvm/parser/testdata/test_vendor/vendor_subpkg/sub/sub1.k @@ -0,0 +1 @@ +sub1 = "sub1" \ No newline at end of file diff --git a/kclvm/parser/testdata/test_vendor/vendor_subpkg/sub/sub2/sub2.k b/kclvm/parser/testdata/test_vendor/vendor_subpkg/sub/sub2/sub2.k new file mode 100644 index 000000000..dc262a825 --- /dev/null +++ b/kclvm/parser/testdata/test_vendor/vendor_subpkg/sub/sub2/sub2.k @@ -0,0 +1,6 @@ +import ..sub as sub +import ..sub1 as sub1 + +sub2 = "sub2" +sub_in_sub2 = sub.sub +sub1_in_sub2 = sub1.sub1 \ No newline at end of file diff --git a/kclvm/parser/testdata/test_vendor/vendor_subpkg/vendor_subpkg.k b/kclvm/parser/testdata/test_vendor/vendor_subpkg/vendor_subpkg.k new file mode 100644 index 000000000..f810e974f --- /dev/null +++ b/kclvm/parser/testdata/test_vendor/vendor_subpkg/vendor_subpkg.k @@ -0,0 +1,9 @@ +import sub.sub1 as sub1 +import sub as sub +import .sub.sub2 as sub2 + +sub_in_subpkg = sub.sub +sub1_in_subpkg = sub1.sub1 + +sub_in_sub2_in_subpkg = sub2.sub_in_sub2 +sub1_in_sub2_in_subpkg = sub2.sub1_in_sub2 diff --git a/kclvm/parser/testdata/type-01.k.json b/kclvm/parser/testdata/type-01.k.json deleted file mode 100644 index 5600554e2..000000000 --- a/kclvm/parser/testdata/type-01.k.json +++ /dev/null @@ -1 +0,0 @@ -{"filename":"type-01.k","pkg":"__main__","doc":"","name":"__main__","body":[{"node":{"TypeAlias":{"type_name":{"node":{"names":["a"],"pkgpath":"","ctx":"Load"},"filename":"type-01.k","line":1,"column":5,"end_line":1,"end_column":6},"type_value":{"node":"any","filename":"type-01.k","line":1,"column":9,"end_line":1,"end_column":12}}},"filename":"type-01.k","line":1,"column":5,"end_line":1,"end_column":12},{"node":{"TypeAlias":{"type_name":{"node":{"names":["b"],"pkgpath":"","ctx":"Load"},"filename":"type-01.k","line":3,"column":5,"end_line":3,"end_column":6},"type_value":{"node":"bool","filename":"type-01.k","line":3,"column":9,"end_line":3,"end_column":13}}},"filename":"type-01.k","line":3,"column":5,"end_line":3,"end_column":13},{"node":{"TypeAlias":{"type_name":{"node":{"names":["c"],"pkgpath":"","ctx":"Load"},"filename":"type-01.k","line":4,"column":5,"end_line":4,"end_column":6},"type_value":{"node":"int","filename":"type-01.k","line":4,"column":9,"end_line":4,"end_column":12}}},"filename":"type-01.k","line":4,"column":5,"end_line":4,"end_column":12},{"node":{"TypeAlias":{"type_name":{"node":{"names":["d"],"pkgpath":"","ctx":"Load"},"filename":"type-01.k","line":5,"column":5,"end_line":5,"end_column":6},"type_value":{"node":"float","filename":"type-01.k","line":5,"column":9,"end_line":5,"end_column":14}}},"filename":"type-01.k","line":5,"column":5,"end_line":5,"end_column":14},{"node":{"TypeAlias":{"type_name":{"node":{"names":["e"],"pkgpath":"","ctx":"Load"},"filename":"type-01.k","line":6,"column":5,"end_line":6,"end_column":6},"type_value":{"node":"str","filename":"type-01.k","line":6,"column":9,"end_line":6,"end_column":12}}},"filename":"type-01.k","line":6,"column":5,"end_line":6,"end_column":12},{"node":{"TypeAlias":{"type_name":{"node":{"names":["type_list1"],"pkgpath":"","ctx":"Load"},"filename":"type-01.k","line":8,"column":5,"end_line":8,"end_column":15},"type_value":{"node":"[]","filename":"type-01.k","line":8,"column":18,"end_line":8,"end_column":20}}},"filename":"type-01.k","line":8,"column":5,"end_line":8,"end_column":20},{"node":{"TypeAlias":{"type_name":{"node":{"names":["type_list2"],"pkgpath":"","ctx":"Load"},"filename":"type-01.k","line":9,"column":5,"end_line":9,"end_column":15},"type_value":{"node":"[[]]","filename":"type-01.k","line":9,"column":18,"end_line":9,"end_column":22}}},"filename":"type-01.k","line":9,"column":5,"end_line":9,"end_column":22},{"node":{"TypeAlias":{"type_name":{"node":{"names":["type_list3"],"pkgpath":"","ctx":"Load"},"filename":"type-01.k","line":10,"column":5,"end_line":10,"end_column":15},"type_value":{"node":"[int]","filename":"type-01.k","line":10,"column":18,"end_line":10,"end_column":23}}},"filename":"type-01.k","line":10,"column":5,"end_line":10,"end_column":23},{"node":{"TypeAlias":{"type_name":{"node":{"names":["b"],"pkgpath":"","ctx":"Load"},"filename":"type-01.k","line":12,"column":5,"end_line":12,"end_column":6},"type_value":{"node":"int|str|[]|{:}","filename":"type-01.k","line":12,"column":9,"end_line":12,"end_column":29}}},"filename":"type-01.k","line":12,"column":5,"end_line":12,"end_column":29}],"comments":[]} diff --git a/kclvm/parser/testdata_without_kclmod/import_by_external_assign.k b/kclvm/parser/testdata_without_kclmod/import_by_external_assign.k new file mode 100644 index 000000000..26a35b488 --- /dev/null +++ b/kclvm/parser/testdata_without_kclmod/import_by_external_assign.k @@ -0,0 +1,3 @@ +import assign as a + +t1 = a.a \ No newline at end of file diff --git a/kclvm/parser/testdata_without_kclmod/import_by_external_config_expr.k b/kclvm/parser/testdata_without_kclmod/import_by_external_config_expr.k new file mode 100644 index 000000000..66805c186 --- /dev/null +++ b/kclvm/parser/testdata_without_kclmod/import_by_external_config_expr.k @@ -0,0 +1,3 @@ +import config_expr as ce + +t = ce.config \ No newline at end of file diff --git a/kclvm/parser/testdata_without_kclmod/import_by_external_nested_vendor.k b/kclvm/parser/testdata_without_kclmod/import_by_external_nested_vendor.k new file mode 100644 index 000000000..94df0aed1 --- /dev/null +++ b/kclvm/parser/testdata_without_kclmod/import_by_external_nested_vendor.k @@ -0,0 +1,3 @@ +import nested_vendor as nv + +t = sv.ub_in_subpkg \ No newline at end of file diff --git a/kclvm/parser/testdata_without_kclmod/import_by_external_vendor_subpkg.k b/kclvm/parser/testdata_without_kclmod/import_by_external_vendor_subpkg.k new file mode 100644 index 000000000..3d1a29b76 --- /dev/null +++ b/kclvm/parser/testdata_without_kclmod/import_by_external_vendor_subpkg.k @@ -0,0 +1,3 @@ +import vendor_subpkg as vs + +t1 = vs.sub_in_subpkg \ No newline at end of file diff --git a/kclvm/parser/testdata_without_kclmod/import_vendor.k b/kclvm/parser/testdata_without_kclmod/import_vendor.k new file mode 100644 index 000000000..4b6a3e4e3 --- /dev/null +++ b/kclvm/parser/testdata_without_kclmod/import_vendor.k @@ -0,0 +1,5 @@ +import assign.assign as aa + +aa_a = aa.a +aa_b = aa.b +aa_c = aa.c \ No newline at end of file diff --git a/kclvm/parser/testdata_without_kclmod/same_name/assign.k b/kclvm/parser/testdata_without_kclmod/same_name/assign.k new file mode 100644 index 000000000..06e1a517b --- /dev/null +++ b/kclvm/parser/testdata_without_kclmod/same_name/assign.k @@ -0,0 +1,5 @@ +import assign as a + +a_a = a.a +a_b = a.b +a_c = a.c \ No newline at end of file diff --git a/kclvm/plugin/.gitignore b/kclvm/plugin/.gitignore deleted file mode 100644 index a4045b0f4..000000000 --- a/kclvm/plugin/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -build -*.so -*.dll -target diff --git a/kclvm/plugin/Makefile b/kclvm/plugin/Makefile deleted file mode 100644 index 728058188..000000000 --- a/kclvm/plugin/Makefile +++ /dev/null @@ -1,19 +0,0 @@ -# Copyright 2021 The KCL Authors. All rights reserved. - -default: - swig -c++ -python kclvm_plugin.i - python3 -m black . - - cd ../runtime && cargo fmt && cargo build --release - - kclvm setup.py build_ext --inplace - kclvm setup.py install_lib - - @echo ------------------ - cd demo && kclvm hello.py - -swig: - swig -c++ -python kclvm_plugin.i - -clean: - -rm -rf build *.so *.dll diff --git a/kclvm/plugin/kclvm_plugin.cpp b/kclvm/plugin/kclvm_plugin.cpp deleted file mode 100644 index 001d49651..000000000 --- a/kclvm/plugin/kclvm_plugin.cpp +++ /dev/null @@ -1,148 +0,0 @@ -// Copyright 2021 The KCL Authors. All rights reserved. - -#include "kclvm_plugin.h" - -#include -#include - -static const int32_t kDefaultBufferSize = 1024*1024*10; - -static _kclvm_plugin_AppContextBase* g_self_ = NULL; -static uint64_t g_rust_invoke_json_ptr_ = 0; - -static const char* _invoke_json_proxy( - const char* method, - const char* args_json, - const char* kwargs_json -) { - if(g_self_ == NULL) { return ""; } - - static std::string jsonResult; - jsonResult = g_self_->_call_py_method(method, args_json, kwargs_json); - return jsonResult.c_str(); -} - -_kclvm_plugin_AppContextBase::_kclvm_plugin_AppContextBase(uint64_t rust_invoke_json_ptr) { - g_rust_invoke_json_ptr_ = rust_invoke_json_ptr; - assert(g_self_ == NULL); - g_self_ = this; -} -_kclvm_plugin_AppContextBase::~_kclvm_plugin_AppContextBase() { - g_rust_invoke_json_ptr_ = 0; - g_self_ = NULL; -} - -void _kclvm_plugin_AppContextBase::_clear_options() { - this->option_keys_.clear(); - this->option_values_.clear(); -} -void _kclvm_plugin_AppContextBase::_add_option(const std::string& key, const std::string& value) { - this->option_keys_.push_back(key); - this->option_values_.push_back(value); -} - -std::string _kclvm_plugin_AppContextBase::_run_app( - uint64_t _start_fn_ptr, - uint64_t _kclvm_main_ptr, // main.k => kclvm_main - int32_t strict_range_check, - int32_t disable_none, - int32_t disable_schema_check, - int32_t list_option_mode, - int32_t debug_mode, - int32_t buffer_size -) { - typedef int32_t (*kcl_run_t)( - uint64_t _kclvm_main_ptr, // main.k => kclvm_main - int32_t option_len, - const char** option_keys, - const char** option_values, - int32_t strict_range_check, - int32_t disable_none, - int32_t disable_schema_check, - int32_t list_option_mode, - int32_t debug_mode, - int32_t result_buffer_len, - char* result_buffer, - int32_t warn_buffer_len, - char* warn_buffer - ); - - int32_t _option_len = this->option_keys_.size(); - std::vector _option_keys(_option_len); - std::vector _option_values(_option_len); - - for(size_t i = 0; i < this->option_keys_.size(); i++) { - _option_keys[i] = (char*)this->option_keys_[i].c_str(); - _option_values[i] = (char*)this->option_values_[i].c_str(); - } - - this->buffer_.clear(); - this->warn_buffer_.clear(); - - if(buffer_size > 0) { - this->buffer_.resize(buffer_size, '\0'); - } else { - this->buffer_.resize(kDefaultBufferSize, '\0'); - } - - this->warn_buffer_.resize(10*1024*1924, '\0'); - - kcl_run_t _kcl_run = (kcl_run_t)(_start_fn_ptr); - int32_t result_len = _kcl_run( - _kclvm_main_ptr, - _option_len, - (const char**)(_option_keys.data()), - (const char**)(_option_values.data()), - strict_range_check, - disable_none, - disable_schema_check, - list_option_mode, - debug_mode, - this->buffer_.size()-1, - &this->buffer_[0], - this->warn_buffer_.size()-1, - &this->warn_buffer_[0] - ); - - if(result_len > 0) { - this->buffer_.resize(result_len); - } else if (result_len == 0) { - this->buffer_ = "{}"; - } else { - this->buffer_ = "{\"error\": \"buffer size limit\"}"; - } - - this->warn_buffer_.resize(strlen(&this->warn_buffer_[0])); - - return this->buffer_; -} - -std::string _kclvm_plugin_AppContextBase::_get_warn() { - return this->warn_buffer_; -} - -uint64_t _kclvm_plugin_AppContextBase::_get_cxx_invoke_proxy_ptr() { - return uint64_t(_invoke_json_proxy); -} - -std::string _kclvm_plugin_AppContextBase::_call_rust_method( - const std::string& name, - const std::string& args_json, - const std::string& kwargs_json -) { - typedef const char* (*invoke_fn_t)( - const char* method, - const char* args_json, - const char* kwargs_json - ); - invoke_fn_t fn = (invoke_fn_t)(g_rust_invoke_json_ptr_); - return fn(name.c_str(), args_json.c_str(), kwargs_json.c_str()); -} - -std::string _kclvm_plugin_AppContextBase::_call_py_method( - const std::string& name, - const std::string& args_json, - const std::string& kwargs_json -) { - return "implemented in Python!!!"; -} diff --git a/kclvm/plugin/kclvm_plugin.h b/kclvm/plugin/kclvm_plugin.h deleted file mode 100644 index bc0e19df5..000000000 --- a/kclvm/plugin/kclvm_plugin.h +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright 2021 The KCL Authors. All rights reserved. - -#pragma once - -#ifndef __cplusplus -#error "please use C++" -#endif - -#include -#include -#include -#include - -#include -#include - -// ---------------------------------------------------------------------------- - -class _kclvm_plugin_AppContextBase { - std::string buffer_; - std::string warn_buffer_; - std::vector option_keys_; - std::vector option_values_; - -public: - _kclvm_plugin_AppContextBase(uint64_t rust_invoke_json_ptr); - virtual ~_kclvm_plugin_AppContextBase(); - - void _clear_options(); - void _add_option(const std::string& key, const std::string& value); - - std::string _run_app( - uint64_t _start_fn_ptr, - uint64_t _kclvm_main_ptr, // main.k => kclvm_main - int32_t strict_range_check, - int32_t disable_none, - int32_t disable_schema_check, - int32_t list_option_mode, - int32_t debug_mode, - int32_t buffer_size - ); - - std::string _get_warn(); - - uint64_t _get_cxx_invoke_proxy_ptr(); - - std::string _call_rust_method( - const std::string& name, - const std::string& args_json, - const std::string& kwargs_json - ); - - virtual std::string _call_py_method( - const std::string& name, - const std::string& args_json, - const std::string& kwargs_json - ); -}; - -// ---------------------------------------------------------------------------- -// END -// ---------------------------------------------------------------------------- diff --git a/kclvm/plugin/kclvm_plugin.i b/kclvm/plugin/kclvm_plugin.i deleted file mode 100644 index 20f56ee48..000000000 --- a/kclvm/plugin/kclvm_plugin.i +++ /dev/null @@ -1,266 +0,0 @@ -// Copyright 2021 The KCL Authors. All rights reserved. - -// http://www.swig.org/Doc3.0/Python.html#Python_directors - -%module(directors="1") kclvm_plugin - -%{ -#define SWIG_FILE_WITH_INIT -#include "kclvm_plugin.h" -%} - -// ---------------------------------------------------------------------------- -// C/C++ code -// ---------------------------------------------------------------------------- - -%include "stdint.i" -%include "std_string.i" - -%feature("director") _kclvm_plugin_AppContextBase; -class _kclvm_plugin_AppContextBase { -public: - _kclvm_plugin_AppContextBase(uint64_t rust_invoke_json_ptr); - virtual ~_kclvm_plugin_AppContextBase(); - - void _clear_options(); - void _add_option(const std::string& key, const std::string& value); - - std::string _run_app( - uint64_t _start_fn_ptr, - uint64_t _kclvm_main_ptr, // main.k => kclvm_main - int32_t strict_range_check, - int32_t disable_none, - int32_t disable_schema_check, - int32_t list_option_mode, - int32_t debug_mode, - int32_t buffer_size - ); - - std::string _get_warn(); - - uint64_t _get_cxx_invoke_proxy_ptr(); - - std::string _call_rust_method( - const std::string& name, - const std::string& args_json, - const std::string& kwargs_json - ); - - virtual std::string _call_py_method( - const std::string& name, - const std::string& args_json, - const std::string& kwargs_json - ); -}; - -// ---------------------------------------------------------------------------- -// Python code -// ---------------------------------------------------------------------------- - -%pythonbegin %{ -import sys -import typing -import ctypes -import os -import importlib -import json -import inspect - -import kclvm.kcl.info as kcl_info -import kclvm.compiler.extension.plugin.plugin as kcl_plugin -import kclvm.api.object.internal.option as option -import kclvm.api.object as objpkg -%} - -%pythoncode %{ -class AppContext(_kclvm_plugin_AppContextBase): - def __init__(self, app_dll_name: str): - self._is_windows: bool = os.name == "nt" - - self._start_func_name: str = "" - self._app_dll_name = app_dll_name - self._plugin_dict: typing.Dict[str, any] = {} - - if self._is_windows: - _executable_root = os.path.dirname(sys.executable) - self._kclvm_runtime = ctypes.CDLL(f"{_executable_root}\\kclvm.dll") - self._app_lib = ctypes.CDLL(app_dll_name) - else: - self._kclvm_runtime = ctypes.CDLL(app_dll_name) - self._app_lib = ctypes.CDLL(app_dll_name) - - self._kclvm_runtime.kclvm_plugin_init.restype = None - self._kclvm_runtime.kclvm_plugin_init.argtypes = [ctypes.c_longlong] - - self._kclvm_runtime.kclvm_plugin_invoke_json.restype = ctypes.c_char_p - self._kclvm_runtime.kclvm_plugin_invoke_json.argtypes = [ - ctypes.c_char_p, - ctypes.c_char_p, - ctypes.c_char_p - ] - - rust_invoke_json_ptr = ctypes.cast(self._kclvm_runtime.kclvm_plugin_invoke_json, ctypes.c_void_p).value - super().__init__(rust_invoke_json_ptr) - - self._kclvm_runtime.kclvm_plugin_init(self._get_cxx_invoke_proxy_ptr()) - - def InitOptions(self, arguments): - self._clear_options() - for kv in arguments or []: - key, value = kv - if isinstance(value, (bool, list, dict)): - value = json.dumps(value) - elif isinstance(value, str): - value = '"{}"'.format(value.replace('"', '\\"')) - else: - value = str(value) - self._add_option(key, value) - - def RunApp(self, *, - start_func_name='_kcl_run', - strict_range_check=None, - disable_none=None, - disable_schema_check=None, - list_option_mode=None, - debug_mode=None, - buffer_size=0 - ) -> str: - self._start_func_name = start_func_name - - _start = getattr(self._kclvm_runtime, start_func_name) - _start_ptr = ctypes.cast(_start, ctypes.c_void_p).value - - if hasattr(self._app_lib, 'kclvm_main'): - _kclvm_main = getattr(self._app_lib, 'kclvm_main') - _kclvm_main_ptr = ctypes.cast(_kclvm_main, ctypes.c_void_p).value - elif hasattr(self._app_lib, 'kclvm_main_win'): - _kclvm_main = getattr(self._app_lib, 'kclvm_main_win') - _kclvm_main_ptr = ctypes.cast(_kclvm_main, ctypes.c_void_p).value - else: - _kclvm_main_ptr = 0 - - if disable_none: - disable_none = 1 - else: - disable_none = 0 - - if strict_range_check: - strict_range_check = 1 - else: - strict_range_check = 0 - - if disable_schema_check: - disable_schema_check = 1 - else: - disable_schema_check = 0 - - if list_option_mode: - list_option_mode = 1 - else: - list_option_mode = 0 - - if debug_mode: - debug_mode = 1 - else: - debug_mode = 0 - - json_result = self._run_app(_start_ptr, _kclvm_main_ptr, - strict_range_check, - disable_none, - disable_schema_check, - list_option_mode, - debug_mode, - buffer_size - ) - return json_result - - def GetWarn(self) -> str: - json_warn_result = self._get_warn() - return json_warn_result - - def CallMethod(self, name:str, args_json:str, kwargs_json:str) -> str: - return self._call_rust_method(name, args_json, kwargs_json) - - def _call_py_method(self, name:str, args_json:str, kwargs_json:str) -> str: - try: - return self._call_py_method_unsafe(name, args_json, kwargs_json) - except Exception as e: - return json.dumps({ "__kcl_PanicInfo__": f"{e}" }) - - def _get_plugin(self, plugin_name:str) -> typing.Optional[any]: - if plugin_name in self._plugin_dict: - return self._plugin_dict[plugin_name] - - module = kcl_plugin.get_plugin(plugin_name) - self._plugin_dict[plugin_name] = module - return module - - def _call_py_method_unsafe(self, name:str, args_json:str, kwargs_json:str) -> str: - dotIdx = name.rfind(".") - if dotIdx < 0: - return "" - - modulePath = name[:dotIdx] - mathodName = name[dotIdx+1:] - - plugin_name = modulePath[modulePath.rfind('.')+1:] - - module = self._get_plugin(plugin_name) - mathodFunc = None - - for func_name, func in inspect.getmembers(module): - if func_name == kcl_info.demangle(mathodName): - mathodFunc = func - break - - args = [] - kwargs = {} - - if args_json: - args = json.loads(args_json) - if not isinstance(args, list): - return "" - if kwargs_json: - kwargs = json.loads(kwargs_json) - if not isinstance(kwargs, dict): - return "" - - result = mathodFunc(*args, **kwargs) - return json.dumps(result) - - def __del__(self): - self._free_library() - - def _free_library(self): - if os.name == 'nt': - import ctypes.wintypes - kernel32 = ctypes.WinDLL('kernel32', use_last_error=True) - kernel32.FreeLibrary.argtypes = [ctypes.wintypes.HMODULE] - kernel32.FreeLibrary(self._app_lib._handle) - self._app_lib = None - # kernel32 = ctypes.WinDLL('kernel32', use_last_error=True) - # kernel32.FreeLibrary.argtypes = [ctypes.wintypes.HMODULE] - # kernel32.FreeLibrary(self._app_dll._handle) - pass - else: - # libdl = ctypes.CDLL("libdl.so") - # libdl.dlclose(self._app_dll._handle) - pass - - -def main(args: typing.List[str]): - if len(args) < 2: - print("usage: kclvm_plugin app.[dll|dylib|so]") - sys._exit(1) - - ctx = AppContext(args[1]) - ctx.RunApp(args[2:]) - - -if __name__ == "__main__": - main(sys.argv) -%} - -// ---------------------------------------------------------------------------- -// END -// ---------------------------------------------------------------------------- diff --git a/kclvm/plugin/kclvm_plugin.py b/kclvm/plugin/kclvm_plugin.py deleted file mode 100644 index 059d6fb76..000000000 --- a/kclvm/plugin/kclvm_plugin.py +++ /dev/null @@ -1,423 +0,0 @@ -# This file was automatically generated by SWIG (http://www.swig.org). -# Version 3.0.12 -# -# Do not make changes to this file unless you know what you are doing--modify -# the SWIG interface file instead. - - -import sys -import typing -import ctypes -import os -import importlib -import json -import inspect - -import kclvm.kcl.info as kcl_info -import kclvm.compiler.extension.plugin.plugin as kcl_plugin -import kclvm.api.object.internal.option as option -import kclvm.api.object as objpkg - - -from sys import version_info as _swig_python_version_info - -if _swig_python_version_info >= (2, 7, 0): - - def swig_import_helper(): - import importlib - - pkg = __name__.rpartition(".")[0] - mname = ".".join((pkg, "_kclvm_plugin")).lstrip(".") - try: - return importlib.import_module(mname) - except ImportError: - return importlib.import_module("_kclvm_plugin") - - _kclvm_plugin = swig_import_helper() - del swig_import_helper -elif _swig_python_version_info >= (2, 6, 0): - - def swig_import_helper(): - from os.path import dirname - import imp - - fp = None - try: - fp, pathname, description = imp.find_module( - "_kclvm_plugin", [dirname(__file__)] - ) - except ImportError: - import _kclvm_plugin - - return _kclvm_plugin - try: - _mod = imp.load_module("_kclvm_plugin", fp, pathname, description) - finally: - if fp is not None: - fp.close() - return _mod - - _kclvm_plugin = swig_import_helper() - del swig_import_helper -else: - import _kclvm_plugin -del _swig_python_version_info - -try: - _swig_property = property -except NameError: - pass # Python < 2.2 doesn't have 'property'. - -try: - import builtins as __builtin__ -except ImportError: - import __builtin__ - - -def _swig_setattr_nondynamic(self, class_type, name, value, static=1): - if name == "thisown": - return self.this.own(value) - if name == "this": - if type(value).__name__ == "SwigPyObject": - self.__dict__[name] = value - return - method = class_type.__swig_setmethods__.get(name, None) - if method: - return method(self, value) - if not static: - if _newclass: - object.__setattr__(self, name, value) - else: - self.__dict__[name] = value - else: - raise AttributeError("You cannot add attributes to %s" % self) - - -def _swig_setattr(self, class_type, name, value): - return _swig_setattr_nondynamic(self, class_type, name, value, 0) - - -def _swig_getattr(self, class_type, name): - if name == "thisown": - return self.this.own() - method = class_type.__swig_getmethods__.get(name, None) - if method: - return method(self) - raise AttributeError( - "'%s' object has no attribute '%s'" % (class_type.__name__, name) - ) - - -def _swig_repr(self): - try: - strthis = "proxy of " + self.this.__repr__() - except __builtin__.Exception: - strthis = "" - return "<%s.%s; %s >" % ( - self.__class__.__module__, - self.__class__.__name__, - strthis, - ) - - -try: - _object = object - _newclass = 1 -except __builtin__.Exception: - - class _object: - pass - - _newclass = 0 - -try: - import weakref - - weakref_proxy = weakref.proxy -except __builtin__.Exception: - weakref_proxy = lambda x: x - - -class _kclvm_plugin_AppContextBase(_object): - __swig_setmethods__ = {} - __setattr__ = lambda self, name, value: _swig_setattr( - self, _kclvm_plugin_AppContextBase, name, value - ) - __swig_getmethods__ = {} - __getattr__ = lambda self, name: _swig_getattr( - self, _kclvm_plugin_AppContextBase, name - ) - __repr__ = _swig_repr - - def __init__(self, rust_invoke_json_ptr): - if self.__class__ == _kclvm_plugin_AppContextBase: - _self = None - else: - _self = self - this = _kclvm_plugin.new__kclvm_plugin_AppContextBase( - _self, rust_invoke_json_ptr - ) - try: - self.this.append(this) - except __builtin__.Exception: - self.this = this - - __swig_destroy__ = _kclvm_plugin.delete__kclvm_plugin_AppContextBase - __del__ = lambda self: None - - def _clear_options(self): - return _kclvm_plugin._kclvm_plugin_AppContextBase__clear_options(self) - - def _add_option(self, key, value): - return _kclvm_plugin._kclvm_plugin_AppContextBase__add_option(self, key, value) - - def _run_app( - self, - _start_fn_ptr, - _kclvm_main_ptr, - strict_range_check, - disable_none, - disable_schema_check, - list_option_mode, - debug_mode, - buffer_size, - ): - return _kclvm_plugin._kclvm_plugin_AppContextBase__run_app( - self, - _start_fn_ptr, - _kclvm_main_ptr, - strict_range_check, - disable_none, - disable_schema_check, - list_option_mode, - debug_mode, - buffer_size, - ) - - def _get_warn(self): - return _kclvm_plugin._kclvm_plugin_AppContextBase__get_warn(self) - - def _get_cxx_invoke_proxy_ptr(self): - return _kclvm_plugin._kclvm_plugin_AppContextBase__get_cxx_invoke_proxy_ptr( - self - ) - - def _call_rust_method(self, name, args_json, kwargs_json): - return _kclvm_plugin._kclvm_plugin_AppContextBase__call_rust_method( - self, name, args_json, kwargs_json - ) - - def _call_py_method(self, name, args_json, kwargs_json): - return _kclvm_plugin._kclvm_plugin_AppContextBase__call_py_method( - self, name, args_json, kwargs_json - ) - - def __disown__(self): - self.this.disown() - _kclvm_plugin.disown__kclvm_plugin_AppContextBase(self) - return weakref_proxy(self) - - -_kclvm_plugin_AppContextBase_swigregister = ( - _kclvm_plugin._kclvm_plugin_AppContextBase_swigregister -) -_kclvm_plugin_AppContextBase_swigregister(_kclvm_plugin_AppContextBase) - - -class AppContext(_kclvm_plugin_AppContextBase): - def __init__(self, app_dll_name: str): - self._is_windows: bool = os.name == "nt" - - self._start_func_name: str = "" - self._app_dll_name = app_dll_name - self._plugin_dict: typing.Dict[str, any] = {} - - if self._is_windows: - _executable_root = os.path.dirname(sys.executable) - self._kclvm_runtime = ctypes.CDLL(f"{_executable_root}\\kclvm.dll") - self._app_lib = ctypes.CDLL(app_dll_name) - else: - self._kclvm_runtime = ctypes.CDLL(app_dll_name) - self._app_lib = ctypes.CDLL(app_dll_name) - - self._kclvm_runtime.kclvm_plugin_init.restype = None - self._kclvm_runtime.kclvm_plugin_init.argtypes = [ctypes.c_longlong] - - self._kclvm_runtime.kclvm_plugin_invoke_json.restype = ctypes.c_char_p - self._kclvm_runtime.kclvm_plugin_invoke_json.argtypes = [ - ctypes.c_char_p, - ctypes.c_char_p, - ctypes.c_char_p, - ] - - rust_invoke_json_ptr = ctypes.cast( - self._kclvm_runtime.kclvm_plugin_invoke_json, ctypes.c_void_p - ).value - super().__init__(rust_invoke_json_ptr) - - self._kclvm_runtime.kclvm_plugin_init(self._get_cxx_invoke_proxy_ptr()) - - def InitOptions(self, arguments): - self._clear_options() - for kv in arguments or []: - key, value = kv - if isinstance(value, (bool, list, dict)): - value = json.dumps(value) - elif isinstance(value, str): - value = '"{}"'.format(value.replace('"', '\\"')) - else: - value = str(value) - self._add_option(key, value) - - def RunApp( - self, - *, - start_func_name="_kcl_run", - strict_range_check=None, - disable_none=None, - disable_schema_check=None, - list_option_mode=None, - debug_mode=None, - buffer_size=0, - ) -> str: - self._start_func_name = start_func_name - - _start = getattr(self._kclvm_runtime, start_func_name) - _start_ptr = ctypes.cast(_start, ctypes.c_void_p).value - - if hasattr(self._app_lib, "kclvm_main"): - _kclvm_main = getattr(self._app_lib, "kclvm_main") - _kclvm_main_ptr = ctypes.cast(_kclvm_main, ctypes.c_void_p).value - elif hasattr(self._app_lib, "kclvm_main_win"): - _kclvm_main = getattr(self._app_lib, "kclvm_main_win") - _kclvm_main_ptr = ctypes.cast(_kclvm_main, ctypes.c_void_p).value - else: - _kclvm_main_ptr = 0 - - if disable_none: - disable_none = 1 - else: - disable_none = 0 - - if strict_range_check: - strict_range_check = 1 - else: - strict_range_check = 0 - - if disable_schema_check: - disable_schema_check = 1 - else: - disable_schema_check = 0 - - if list_option_mode: - list_option_mode = 1 - else: - list_option_mode = 0 - - if debug_mode: - debug_mode = 1 - else: - debug_mode = 0 - - json_result = self._run_app( - _start_ptr, - _kclvm_main_ptr, - strict_range_check, - disable_none, - disable_schema_check, - list_option_mode, - debug_mode, - buffer_size, - ) - return json_result - - def GetWarn(self) -> str: - json_warn_result = self._get_warn() - return json_warn_result - - def CallMethod(self, name: str, args_json: str, kwargs_json: str) -> str: - return self._call_rust_method(name, args_json, kwargs_json) - - def _call_py_method(self, name: str, args_json: str, kwargs_json: str) -> str: - try: - return self._call_py_method_unsafe(name, args_json, kwargs_json) - except Exception as e: - return json.dumps({"__kcl_PanicInfo__": f"{e}"}) - - def _get_plugin(self, plugin_name: str) -> typing.Optional[any]: - if plugin_name in self._plugin_dict: - return self._plugin_dict[plugin_name] - - module = kcl_plugin.get_plugin(plugin_name) - self._plugin_dict[plugin_name] = module - return module - - def _call_py_method_unsafe( - self, name: str, args_json: str, kwargs_json: str - ) -> str: - dotIdx = name.rfind(".") - if dotIdx < 0: - return "" - - modulePath = name[:dotIdx] - mathodName = name[dotIdx + 1 :] - - plugin_name = modulePath[modulePath.rfind(".") + 1 :] - - module = self._get_plugin(plugin_name) - mathodFunc = None - - for func_name, func in inspect.getmembers(module): - if func_name == kcl_info.demangle(mathodName): - mathodFunc = func - break - - args = [] - kwargs = {} - - if args_json: - args = json.loads(args_json) - if not isinstance(args, list): - return "" - if kwargs_json: - kwargs = json.loads(kwargs_json) - if not isinstance(kwargs, dict): - return "" - - result = mathodFunc(*args, **kwargs) - return json.dumps(result) - - def __del__(self): - self._free_library() - - def _free_library(self): - if os.name == "nt": - import ctypes.wintypes - - kernel32 = ctypes.WinDLL("kernel32", use_last_error=True) - kernel32.FreeLibrary.argtypes = [ctypes.wintypes.HMODULE] - kernel32.FreeLibrary(self._app_lib._handle) - self._app_lib = None - # kernel32 = ctypes.WinDLL('kernel32', use_last_error=True) - # kernel32.FreeLibrary.argtypes = [ctypes.wintypes.HMODULE] - # kernel32.FreeLibrary(self._app_dll._handle) - pass - else: - # libdl = ctypes.CDLL("libdl.so") - # libdl.dlclose(self._app_dll._handle) - pass - - -def main(args: typing.List[str]): - if len(args) < 2: - print("usage: kclvm_plugin app.[dll|dylib|so]") - sys._exit(1) - - ctx = AppContext(args[1]) - ctx.RunApp(args[2:]) - - -if __name__ == "__main__": - main(sys.argv) - -# This file is compatible with both classic and new-style classes. diff --git a/kclvm/plugin/kclvm_plugin_wrap.cxx b/kclvm/plugin/kclvm_plugin_wrap.cxx deleted file mode 100644 index 1b98fdf40..000000000 --- a/kclvm/plugin/kclvm_plugin_wrap.cxx +++ /dev/null @@ -1,5290 +0,0 @@ -/* ---------------------------------------------------------------------------- - * This file was automatically generated by SWIG (http://www.swig.org). - * Version 3.0.12 - * - * This file is not intended to be easily readable and contains a number of - * coding conventions designed to improve portability and efficiency. Do not make - * changes to this file unless you know what you are doing--modify the SWIG - * interface file instead. - * ----------------------------------------------------------------------------- */ - - -#ifndef SWIGPYTHON -#define SWIGPYTHON -#endif - -#define SWIG_DIRECTORS -#define SWIG_PYTHON_DIRECTOR_NO_VTABLE - - -#ifdef __cplusplus -/* SwigValueWrapper is described in swig.swg */ -template class SwigValueWrapper { - struct SwigMovePointer { - T *ptr; - SwigMovePointer(T *p) : ptr(p) { } - ~SwigMovePointer() { delete ptr; } - SwigMovePointer& operator=(SwigMovePointer& rhs) { T* oldptr = ptr; ptr = 0; delete oldptr; ptr = rhs.ptr; rhs.ptr = 0; return *this; } - } pointer; - SwigValueWrapper& operator=(const SwigValueWrapper& rhs); - SwigValueWrapper(const SwigValueWrapper& rhs); -public: - SwigValueWrapper() : pointer(0) { } - SwigValueWrapper& operator=(const T& t) { SwigMovePointer tmp(new T(t)); pointer = tmp; return *this; } - operator T&() const { return *pointer.ptr; } - T *operator&() { return pointer.ptr; } -}; - -template T SwigValueInit() { - return T(); -} -#endif - -/* ----------------------------------------------------------------------------- - * This section contains generic SWIG labels for method/variable - * declarations/attributes, and other compiler dependent labels. - * ----------------------------------------------------------------------------- */ - -/* template workaround for compilers that cannot correctly implement the C++ standard */ -#ifndef SWIGTEMPLATEDISAMBIGUATOR -# if defined(__SUNPRO_CC) && (__SUNPRO_CC <= 0x560) -# define SWIGTEMPLATEDISAMBIGUATOR template -# elif defined(__HP_aCC) -/* Needed even with `aCC -AA' when `aCC -V' reports HP ANSI C++ B3910B A.03.55 */ -/* If we find a maximum version that requires this, the test would be __HP_aCC <= 35500 for A.03.55 */ -# define SWIGTEMPLATEDISAMBIGUATOR template -# else -# define SWIGTEMPLATEDISAMBIGUATOR -# endif -#endif - -/* inline attribute */ -#ifndef SWIGINLINE -# if defined(__cplusplus) || (defined(__GNUC__) && !defined(__STRICT_ANSI__)) -# define SWIGINLINE inline -# else -# define SWIGINLINE -# endif -#endif - -/* attribute recognised by some compilers to avoid 'unused' warnings */ -#ifndef SWIGUNUSED -# if defined(__GNUC__) -# if !(defined(__cplusplus)) || (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)) -# define SWIGUNUSED __attribute__ ((__unused__)) -# else -# define SWIGUNUSED -# endif -# elif defined(__ICC) -# define SWIGUNUSED __attribute__ ((__unused__)) -# else -# define SWIGUNUSED -# endif -#endif - -#ifndef SWIG_MSC_UNSUPPRESS_4505 -# if defined(_MSC_VER) -# pragma warning(disable : 4505) /* unreferenced local function has been removed */ -# endif -#endif - -#ifndef SWIGUNUSEDPARM -# ifdef __cplusplus -# define SWIGUNUSEDPARM(p) -# else -# define SWIGUNUSEDPARM(p) p SWIGUNUSED -# endif -#endif - -/* internal SWIG method */ -#ifndef SWIGINTERN -# define SWIGINTERN static SWIGUNUSED -#endif - -/* internal inline SWIG method */ -#ifndef SWIGINTERNINLINE -# define SWIGINTERNINLINE SWIGINTERN SWIGINLINE -#endif - -/* exporting methods */ -#if defined(__GNUC__) -# if (__GNUC__ >= 4) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) -# ifndef GCC_HASCLASSVISIBILITY -# define GCC_HASCLASSVISIBILITY -# endif -# endif -#endif - -#ifndef SWIGEXPORT -# if defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__) -# if defined(STATIC_LINKED) -# define SWIGEXPORT -# else -# define SWIGEXPORT __declspec(dllexport) -# endif -# else -# if defined(__GNUC__) && defined(GCC_HASCLASSVISIBILITY) -# define SWIGEXPORT __attribute__ ((visibility("default"))) -# else -# define SWIGEXPORT -# endif -# endif -#endif - -/* calling conventions for Windows */ -#ifndef SWIGSTDCALL -# if defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__) -# define SWIGSTDCALL __stdcall -# else -# define SWIGSTDCALL -# endif -#endif - -/* Deal with Microsoft's attempt at deprecating C standard runtime functions */ -#if !defined(SWIG_NO_CRT_SECURE_NO_DEPRECATE) && defined(_MSC_VER) && !defined(_CRT_SECURE_NO_DEPRECATE) -# define _CRT_SECURE_NO_DEPRECATE -#endif - -/* Deal with Microsoft's attempt at deprecating methods in the standard C++ library */ -#if !defined(SWIG_NO_SCL_SECURE_NO_DEPRECATE) && defined(_MSC_VER) && !defined(_SCL_SECURE_NO_DEPRECATE) -# define _SCL_SECURE_NO_DEPRECATE -#endif - -/* Deal with Apple's deprecated 'AssertMacros.h' from Carbon-framework */ -#if defined(__APPLE__) && !defined(__ASSERT_MACROS_DEFINE_VERSIONS_WITHOUT_UNDERSCORES) -# define __ASSERT_MACROS_DEFINE_VERSIONS_WITHOUT_UNDERSCORES 0 -#endif - -/* Intel's compiler complains if a variable which was never initialised is - * cast to void, which is a common idiom which we use to indicate that we - * are aware a variable isn't used. So we just silence that warning. - * See: https://github.com/swig/swig/issues/192 for more discussion. - */ -#ifdef __INTEL_COMPILER -# pragma warning disable 592 -#endif - - -#if defined(_DEBUG) && defined(SWIG_PYTHON_INTERPRETER_NO_DEBUG) -/* Use debug wrappers with the Python release dll */ -# undef _DEBUG -# include -# define _DEBUG -#else -# include -#endif - -/* ----------------------------------------------------------------------------- - * swigrun.swg - * - * This file contains generic C API SWIG runtime support for pointer - * type checking. - * ----------------------------------------------------------------------------- */ - -/* This should only be incremented when either the layout of swig_type_info changes, - or for whatever reason, the runtime changes incompatibly */ -#define SWIG_RUNTIME_VERSION "4" - -/* define SWIG_TYPE_TABLE_NAME as "SWIG_TYPE_TABLE" */ -#ifdef SWIG_TYPE_TABLE -# define SWIG_QUOTE_STRING(x) #x -# define SWIG_EXPAND_AND_QUOTE_STRING(x) SWIG_QUOTE_STRING(x) -# define SWIG_TYPE_TABLE_NAME SWIG_EXPAND_AND_QUOTE_STRING(SWIG_TYPE_TABLE) -#else -# define SWIG_TYPE_TABLE_NAME -#endif - -/* - You can use the SWIGRUNTIME and SWIGRUNTIMEINLINE macros for - creating a static or dynamic library from the SWIG runtime code. - In 99.9% of the cases, SWIG just needs to declare them as 'static'. - - But only do this if strictly necessary, ie, if you have problems - with your compiler or suchlike. -*/ - -#ifndef SWIGRUNTIME -# define SWIGRUNTIME SWIGINTERN -#endif - -#ifndef SWIGRUNTIMEINLINE -# define SWIGRUNTIMEINLINE SWIGRUNTIME SWIGINLINE -#endif - -/* Generic buffer size */ -#ifndef SWIG_BUFFER_SIZE -# define SWIG_BUFFER_SIZE 1024 -#endif - -/* Flags for pointer conversions */ -#define SWIG_POINTER_DISOWN 0x1 -#define SWIG_CAST_NEW_MEMORY 0x2 - -/* Flags for new pointer objects */ -#define SWIG_POINTER_OWN 0x1 - - -/* - Flags/methods for returning states. - - The SWIG conversion methods, as ConvertPtr, return an integer - that tells if the conversion was successful or not. And if not, - an error code can be returned (see swigerrors.swg for the codes). - - Use the following macros/flags to set or process the returning - states. - - In old versions of SWIG, code such as the following was usually written: - - if (SWIG_ConvertPtr(obj,vptr,ty.flags) != -1) { - // success code - } else { - //fail code - } - - Now you can be more explicit: - - int res = SWIG_ConvertPtr(obj,vptr,ty.flags); - if (SWIG_IsOK(res)) { - // success code - } else { - // fail code - } - - which is the same really, but now you can also do - - Type *ptr; - int res = SWIG_ConvertPtr(obj,(void **)(&ptr),ty.flags); - if (SWIG_IsOK(res)) { - // success code - if (SWIG_IsNewObj(res) { - ... - delete *ptr; - } else { - ... - } - } else { - // fail code - } - - I.e., now SWIG_ConvertPtr can return new objects and you can - identify the case and take care of the deallocation. Of course that - also requires SWIG_ConvertPtr to return new result values, such as - - int SWIG_ConvertPtr(obj, ptr,...) { - if () { - if () { - *ptr = ; - return SWIG_NEWOBJ; - } else { - *ptr = ; - return SWIG_OLDOBJ; - } - } else { - return SWIG_BADOBJ; - } - } - - Of course, returning the plain '0(success)/-1(fail)' still works, but you can be - more explicit by returning SWIG_BADOBJ, SWIG_ERROR or any of the - SWIG errors code. - - Finally, if the SWIG_CASTRANK_MODE is enabled, the result code - allows to return the 'cast rank', for example, if you have this - - int food(double) - int fooi(int); - - and you call - - food(1) // cast rank '1' (1 -> 1.0) - fooi(1) // cast rank '0' - - just use the SWIG_AddCast()/SWIG_CheckState() -*/ - -#define SWIG_OK (0) -#define SWIG_ERROR (-1) -#define SWIG_IsOK(r) (r >= 0) -#define SWIG_ArgError(r) ((r != SWIG_ERROR) ? r : SWIG_TypeError) - -/* The CastRankLimit says how many bits are used for the cast rank */ -#define SWIG_CASTRANKLIMIT (1 << 8) -/* The NewMask denotes the object was created (using new/malloc) */ -#define SWIG_NEWOBJMASK (SWIG_CASTRANKLIMIT << 1) -/* The TmpMask is for in/out typemaps that use temporal objects */ -#define SWIG_TMPOBJMASK (SWIG_NEWOBJMASK << 1) -/* Simple returning values */ -#define SWIG_BADOBJ (SWIG_ERROR) -#define SWIG_OLDOBJ (SWIG_OK) -#define SWIG_NEWOBJ (SWIG_OK | SWIG_NEWOBJMASK) -#define SWIG_TMPOBJ (SWIG_OK | SWIG_TMPOBJMASK) -/* Check, add and del mask methods */ -#define SWIG_AddNewMask(r) (SWIG_IsOK(r) ? (r | SWIG_NEWOBJMASK) : r) -#define SWIG_DelNewMask(r) (SWIG_IsOK(r) ? (r & ~SWIG_NEWOBJMASK) : r) -#define SWIG_IsNewObj(r) (SWIG_IsOK(r) && (r & SWIG_NEWOBJMASK)) -#define SWIG_AddTmpMask(r) (SWIG_IsOK(r) ? (r | SWIG_TMPOBJMASK) : r) -#define SWIG_DelTmpMask(r) (SWIG_IsOK(r) ? (r & ~SWIG_TMPOBJMASK) : r) -#define SWIG_IsTmpObj(r) (SWIG_IsOK(r) && (r & SWIG_TMPOBJMASK)) - -/* Cast-Rank Mode */ -#if defined(SWIG_CASTRANK_MODE) -# ifndef SWIG_TypeRank -# define SWIG_TypeRank unsigned long -# endif -# ifndef SWIG_MAXCASTRANK /* Default cast allowed */ -# define SWIG_MAXCASTRANK (2) -# endif -# define SWIG_CASTRANKMASK ((SWIG_CASTRANKLIMIT) -1) -# define SWIG_CastRank(r) (r & SWIG_CASTRANKMASK) -SWIGINTERNINLINE int SWIG_AddCast(int r) { - return SWIG_IsOK(r) ? ((SWIG_CastRank(r) < SWIG_MAXCASTRANK) ? (r + 1) : SWIG_ERROR) : r; -} -SWIGINTERNINLINE int SWIG_CheckState(int r) { - return SWIG_IsOK(r) ? SWIG_CastRank(r) + 1 : 0; -} -#else /* no cast-rank mode */ -# define SWIG_AddCast(r) (r) -# define SWIG_CheckState(r) (SWIG_IsOK(r) ? 1 : 0) -#endif - - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -typedef void *(*swig_converter_func)(void *, int *); -typedef struct swig_type_info *(*swig_dycast_func)(void **); - -/* Structure to store information on one type */ -typedef struct swig_type_info { - const char *name; /* mangled name of this type */ - const char *str; /* human readable name of this type */ - swig_dycast_func dcast; /* dynamic cast function down a hierarchy */ - struct swig_cast_info *cast; /* linked list of types that can cast into this type */ - void *clientdata; /* language specific type data */ - int owndata; /* flag if the structure owns the clientdata */ -} swig_type_info; - -/* Structure to store a type and conversion function used for casting */ -typedef struct swig_cast_info { - swig_type_info *type; /* pointer to type that is equivalent to this type */ - swig_converter_func converter; /* function to cast the void pointers */ - struct swig_cast_info *next; /* pointer to next cast in linked list */ - struct swig_cast_info *prev; /* pointer to the previous cast */ -} swig_cast_info; - -/* Structure used to store module information - * Each module generates one structure like this, and the runtime collects - * all of these structures and stores them in a circularly linked list.*/ -typedef struct swig_module_info { - swig_type_info **types; /* Array of pointers to swig_type_info structures that are in this module */ - size_t size; /* Number of types in this module */ - struct swig_module_info *next; /* Pointer to next element in circularly linked list */ - swig_type_info **type_initial; /* Array of initially generated type structures */ - swig_cast_info **cast_initial; /* Array of initially generated casting structures */ - void *clientdata; /* Language specific module data */ -} swig_module_info; - -/* - Compare two type names skipping the space characters, therefore - "char*" == "char *" and "Class" == "Class", etc. - - Return 0 when the two name types are equivalent, as in - strncmp, but skipping ' '. -*/ -SWIGRUNTIME int -SWIG_TypeNameComp(const char *f1, const char *l1, - const char *f2, const char *l2) { - for (;(f1 != l1) && (f2 != l2); ++f1, ++f2) { - while ((*f1 == ' ') && (f1 != l1)) ++f1; - while ((*f2 == ' ') && (f2 != l2)) ++f2; - if (*f1 != *f2) return (*f1 > *f2) ? 1 : -1; - } - return (int)((l1 - f1) - (l2 - f2)); -} - -/* - Check type equivalence in a name list like ||... - Return 0 if equal, -1 if nb < tb, 1 if nb > tb -*/ -SWIGRUNTIME int -SWIG_TypeCmp(const char *nb, const char *tb) { - int equiv = 1; - const char* te = tb + strlen(tb); - const char* ne = nb; - while (equiv != 0 && *ne) { - for (nb = ne; *ne; ++ne) { - if (*ne == '|') break; - } - equiv = SWIG_TypeNameComp(nb, ne, tb, te); - if (*ne) ++ne; - } - return equiv; -} - -/* - Check type equivalence in a name list like ||... - Return 0 if not equal, 1 if equal -*/ -SWIGRUNTIME int -SWIG_TypeEquiv(const char *nb, const char *tb) { - return SWIG_TypeCmp(nb, tb) == 0 ? 1 : 0; -} - -/* - Check the typename -*/ -SWIGRUNTIME swig_cast_info * -SWIG_TypeCheck(const char *c, swig_type_info *ty) { - if (ty) { - swig_cast_info *iter = ty->cast; - while (iter) { - if (strcmp(iter->type->name, c) == 0) { - if (iter == ty->cast) - return iter; - /* Move iter to the top of the linked list */ - iter->prev->next = iter->next; - if (iter->next) - iter->next->prev = iter->prev; - iter->next = ty->cast; - iter->prev = 0; - if (ty->cast) ty->cast->prev = iter; - ty->cast = iter; - return iter; - } - iter = iter->next; - } - } - return 0; -} - -/* - Identical to SWIG_TypeCheck, except strcmp is replaced with a pointer comparison -*/ -SWIGRUNTIME swig_cast_info * -SWIG_TypeCheckStruct(swig_type_info *from, swig_type_info *ty) { - if (ty) { - swig_cast_info *iter = ty->cast; - while (iter) { - if (iter->type == from) { - if (iter == ty->cast) - return iter; - /* Move iter to the top of the linked list */ - iter->prev->next = iter->next; - if (iter->next) - iter->next->prev = iter->prev; - iter->next = ty->cast; - iter->prev = 0; - if (ty->cast) ty->cast->prev = iter; - ty->cast = iter; - return iter; - } - iter = iter->next; - } - } - return 0; -} - -/* - Cast a pointer up an inheritance hierarchy -*/ -SWIGRUNTIMEINLINE void * -SWIG_TypeCast(swig_cast_info *ty, void *ptr, int *newmemory) { - return ((!ty) || (!ty->converter)) ? ptr : (*ty->converter)(ptr, newmemory); -} - -/* - Dynamic pointer casting. Down an inheritance hierarchy -*/ -SWIGRUNTIME swig_type_info * -SWIG_TypeDynamicCast(swig_type_info *ty, void **ptr) { - swig_type_info *lastty = ty; - if (!ty || !ty->dcast) return ty; - while (ty && (ty->dcast)) { - ty = (*ty->dcast)(ptr); - if (ty) lastty = ty; - } - return lastty; -} - -/* - Return the name associated with this type -*/ -SWIGRUNTIMEINLINE const char * -SWIG_TypeName(const swig_type_info *ty) { - return ty->name; -} - -/* - Return the pretty name associated with this type, - that is an unmangled type name in a form presentable to the user. -*/ -SWIGRUNTIME const char * -SWIG_TypePrettyName(const swig_type_info *type) { - /* The "str" field contains the equivalent pretty names of the - type, separated by vertical-bar characters. We choose - to print the last name, as it is often (?) the most - specific. */ - if (!type) return NULL; - if (type->str != NULL) { - const char *last_name = type->str; - const char *s; - for (s = type->str; *s; s++) - if (*s == '|') last_name = s+1; - return last_name; - } - else - return type->name; -} - -/* - Set the clientdata field for a type -*/ -SWIGRUNTIME void -SWIG_TypeClientData(swig_type_info *ti, void *clientdata) { - swig_cast_info *cast = ti->cast; - /* if (ti->clientdata == clientdata) return; */ - ti->clientdata = clientdata; - - while (cast) { - if (!cast->converter) { - swig_type_info *tc = cast->type; - if (!tc->clientdata) { - SWIG_TypeClientData(tc, clientdata); - } - } - cast = cast->next; - } -} -SWIGRUNTIME void -SWIG_TypeNewClientData(swig_type_info *ti, void *clientdata) { - SWIG_TypeClientData(ti, clientdata); - ti->owndata = 1; -} - -/* - Search for a swig_type_info structure only by mangled name - Search is a O(log #types) - - We start searching at module start, and finish searching when start == end. - Note: if start == end at the beginning of the function, we go all the way around - the circular list. -*/ -SWIGRUNTIME swig_type_info * -SWIG_MangledTypeQueryModule(swig_module_info *start, - swig_module_info *end, - const char *name) { - swig_module_info *iter = start; - do { - if (iter->size) { - size_t l = 0; - size_t r = iter->size - 1; - do { - /* since l+r >= 0, we can (>> 1) instead (/ 2) */ - size_t i = (l + r) >> 1; - const char *iname = iter->types[i]->name; - if (iname) { - int compare = strcmp(name, iname); - if (compare == 0) { - return iter->types[i]; - } else if (compare < 0) { - if (i) { - r = i - 1; - } else { - break; - } - } else if (compare > 0) { - l = i + 1; - } - } else { - break; /* should never happen */ - } - } while (l <= r); - } - iter = iter->next; - } while (iter != end); - return 0; -} - -/* - Search for a swig_type_info structure for either a mangled name or a human readable name. - It first searches the mangled names of the types, which is a O(log #types) - If a type is not found it then searches the human readable names, which is O(#types). - - We start searching at module start, and finish searching when start == end. - Note: if start == end at the beginning of the function, we go all the way around - the circular list. -*/ -SWIGRUNTIME swig_type_info * -SWIG_TypeQueryModule(swig_module_info *start, - swig_module_info *end, - const char *name) { - /* STEP 1: Search the name field using binary search */ - swig_type_info *ret = SWIG_MangledTypeQueryModule(start, end, name); - if (ret) { - return ret; - } else { - /* STEP 2: If the type hasn't been found, do a complete search - of the str field (the human readable name) */ - swig_module_info *iter = start; - do { - size_t i = 0; - for (; i < iter->size; ++i) { - if (iter->types[i]->str && (SWIG_TypeEquiv(iter->types[i]->str, name))) - return iter->types[i]; - } - iter = iter->next; - } while (iter != end); - } - - /* neither found a match */ - return 0; -} - -/* - Pack binary data into a string -*/ -SWIGRUNTIME char * -SWIG_PackData(char *c, void *ptr, size_t sz) { - static const char hex[17] = "0123456789abcdef"; - const unsigned char *u = (unsigned char *) ptr; - const unsigned char *eu = u + sz; - for (; u != eu; ++u) { - unsigned char uu = *u; - *(c++) = hex[(uu & 0xf0) >> 4]; - *(c++) = hex[uu & 0xf]; - } - return c; -} - -/* - Unpack binary data from a string -*/ -SWIGRUNTIME const char * -SWIG_UnpackData(const char *c, void *ptr, size_t sz) { - unsigned char *u = (unsigned char *) ptr; - const unsigned char *eu = u + sz; - for (; u != eu; ++u) { - char d = *(c++); - unsigned char uu; - if ((d >= '0') && (d <= '9')) - uu = (unsigned char)((d - '0') << 4); - else if ((d >= 'a') && (d <= 'f')) - uu = (unsigned char)((d - ('a'-10)) << 4); - else - return (char *) 0; - d = *(c++); - if ((d >= '0') && (d <= '9')) - uu |= (unsigned char)(d - '0'); - else if ((d >= 'a') && (d <= 'f')) - uu |= (unsigned char)(d - ('a'-10)); - else - return (char *) 0; - *u = uu; - } - return c; -} - -/* - Pack 'void *' into a string buffer. -*/ -SWIGRUNTIME char * -SWIG_PackVoidPtr(char *buff, void *ptr, const char *name, size_t bsz) { - char *r = buff; - if ((2*sizeof(void *) + 2) > bsz) return 0; - *(r++) = '_'; - r = SWIG_PackData(r,&ptr,sizeof(void *)); - if (strlen(name) + 1 > (bsz - (r - buff))) return 0; - strcpy(r,name); - return buff; -} - -SWIGRUNTIME const char * -SWIG_UnpackVoidPtr(const char *c, void **ptr, const char *name) { - if (*c != '_') { - if (strcmp(c,"NULL") == 0) { - *ptr = (void *) 0; - return name; - } else { - return 0; - } - } - return SWIG_UnpackData(++c,ptr,sizeof(void *)); -} - -SWIGRUNTIME char * -SWIG_PackDataName(char *buff, void *ptr, size_t sz, const char *name, size_t bsz) { - char *r = buff; - size_t lname = (name ? strlen(name) : 0); - if ((2*sz + 2 + lname) > bsz) return 0; - *(r++) = '_'; - r = SWIG_PackData(r,ptr,sz); - if (lname) { - strncpy(r,name,lname+1); - } else { - *r = 0; - } - return buff; -} - -SWIGRUNTIME const char * -SWIG_UnpackDataName(const char *c, void *ptr, size_t sz, const char *name) { - if (*c != '_') { - if (strcmp(c,"NULL") == 0) { - memset(ptr,0,sz); - return name; - } else { - return 0; - } - } - return SWIG_UnpackData(++c,ptr,sz); -} - -#ifdef __cplusplus -} -#endif - -/* Errors in SWIG */ -#define SWIG_UnknownError -1 -#define SWIG_IOError -2 -#define SWIG_RuntimeError -3 -#define SWIG_IndexError -4 -#define SWIG_TypeError -5 -#define SWIG_DivisionByZero -6 -#define SWIG_OverflowError -7 -#define SWIG_SyntaxError -8 -#define SWIG_ValueError -9 -#define SWIG_SystemError -10 -#define SWIG_AttributeError -11 -#define SWIG_MemoryError -12 -#define SWIG_NullReferenceError -13 - - - -/* Compatibility macros for Python 3 */ -#if PY_VERSION_HEX >= 0x03000000 - -#define PyClass_Check(obj) PyObject_IsInstance(obj, (PyObject *)&PyType_Type) -#define PyInt_Check(x) PyLong_Check(x) -#define PyInt_AsLong(x) PyLong_AsLong(x) -#define PyInt_FromLong(x) PyLong_FromLong(x) -#define PyInt_FromSize_t(x) PyLong_FromSize_t(x) -#define PyString_Check(name) PyBytes_Check(name) -#define PyString_FromString(x) PyUnicode_FromString(x) -#define PyString_Format(fmt, args) PyUnicode_Format(fmt, args) -#define PyString_AsString(str) PyBytes_AsString(str) -#define PyString_Size(str) PyBytes_Size(str) -#define PyString_InternFromString(key) PyUnicode_InternFromString(key) -#define Py_TPFLAGS_HAVE_CLASS Py_TPFLAGS_BASETYPE -#define PyString_AS_STRING(x) PyUnicode_AS_STRING(x) -#define _PyLong_FromSsize_t(x) PyLong_FromSsize_t(x) - -#endif - -#ifndef Py_TYPE -# define Py_TYPE(op) ((op)->ob_type) -#endif - -/* SWIG APIs for compatibility of both Python 2 & 3 */ - -#if PY_VERSION_HEX >= 0x03000000 -# define SWIG_Python_str_FromFormat PyUnicode_FromFormat -#else -# define SWIG_Python_str_FromFormat PyString_FromFormat -#endif - - -/* Warning: This function will allocate a new string in Python 3, - * so please call SWIG_Python_str_DelForPy3(x) to free the space. - */ -SWIGINTERN char* -SWIG_Python_str_AsChar(PyObject *str) -{ -#if PY_VERSION_HEX >= 0x03000000 - char *cstr; - char *newstr; - Py_ssize_t len; - str = PyUnicode_AsUTF8String(str); - PyBytes_AsStringAndSize(str, &cstr, &len); - newstr = (char *) malloc(len+1); - memcpy(newstr, cstr, len+1); - Py_XDECREF(str); - return newstr; -#else - return PyString_AsString(str); -#endif -} - -#if PY_VERSION_HEX >= 0x03000000 -# define SWIG_Python_str_DelForPy3(x) free( (void*) (x) ) -#else -# define SWIG_Python_str_DelForPy3(x) -#endif - - -SWIGINTERN PyObject* -SWIG_Python_str_FromChar(const char *c) -{ -#if PY_VERSION_HEX >= 0x03000000 - return PyUnicode_FromString(c); -#else - return PyString_FromString(c); -#endif -} - -/* Add PyOS_snprintf for old Pythons */ -#if PY_VERSION_HEX < 0x02020000 -# if defined(_MSC_VER) || defined(__BORLANDC__) || defined(_WATCOM) -# define PyOS_snprintf _snprintf -# else -# define PyOS_snprintf snprintf -# endif -#endif - -/* A crude PyString_FromFormat implementation for old Pythons */ -#if PY_VERSION_HEX < 0x02020000 - -#ifndef SWIG_PYBUFFER_SIZE -# define SWIG_PYBUFFER_SIZE 1024 -#endif - -static PyObject * -PyString_FromFormat(const char *fmt, ...) { - va_list ap; - char buf[SWIG_PYBUFFER_SIZE * 2]; - int res; - va_start(ap, fmt); - res = vsnprintf(buf, sizeof(buf), fmt, ap); - va_end(ap); - return (res < 0 || res >= (int)sizeof(buf)) ? 0 : PyString_FromString(buf); -} -#endif - -#ifndef PyObject_DEL -# define PyObject_DEL PyObject_Del -#endif - -/* A crude PyExc_StopIteration exception for old Pythons */ -#if PY_VERSION_HEX < 0x02020000 -# ifndef PyExc_StopIteration -# define PyExc_StopIteration PyExc_RuntimeError -# endif -# ifndef PyObject_GenericGetAttr -# define PyObject_GenericGetAttr 0 -# endif -#endif - -/* Py_NotImplemented is defined in 2.1 and up. */ -#if PY_VERSION_HEX < 0x02010000 -# ifndef Py_NotImplemented -# define Py_NotImplemented PyExc_RuntimeError -# endif -#endif - -/* A crude PyString_AsStringAndSize implementation for old Pythons */ -#if PY_VERSION_HEX < 0x02010000 -# ifndef PyString_AsStringAndSize -# define PyString_AsStringAndSize(obj, s, len) {*s = PyString_AsString(obj); *len = *s ? strlen(*s) : 0;} -# endif -#endif - -/* PySequence_Size for old Pythons */ -#if PY_VERSION_HEX < 0x02000000 -# ifndef PySequence_Size -# define PySequence_Size PySequence_Length -# endif -#endif - -/* PyBool_FromLong for old Pythons */ -#if PY_VERSION_HEX < 0x02030000 -static -PyObject *PyBool_FromLong(long ok) -{ - PyObject *result = ok ? Py_True : Py_False; - Py_INCREF(result); - return result; -} -#endif - -/* Py_ssize_t for old Pythons */ -/* This code is as recommended by: */ -/* http://www.python.org/dev/peps/pep-0353/#conversion-guidelines */ -#if PY_VERSION_HEX < 0x02050000 && !defined(PY_SSIZE_T_MIN) -typedef int Py_ssize_t; -# define PY_SSIZE_T_MAX INT_MAX -# define PY_SSIZE_T_MIN INT_MIN -typedef inquiry lenfunc; -typedef intargfunc ssizeargfunc; -typedef intintargfunc ssizessizeargfunc; -typedef intobjargproc ssizeobjargproc; -typedef intintobjargproc ssizessizeobjargproc; -typedef getreadbufferproc readbufferproc; -typedef getwritebufferproc writebufferproc; -typedef getsegcountproc segcountproc; -typedef getcharbufferproc charbufferproc; -static long PyNumber_AsSsize_t (PyObject *x, void *SWIGUNUSEDPARM(exc)) -{ - long result = 0; - PyObject *i = PyNumber_Int(x); - if (i) { - result = PyInt_AsLong(i); - Py_DECREF(i); - } - return result; -} -#endif - -#if PY_VERSION_HEX < 0x02050000 -#define PyInt_FromSize_t(x) PyInt_FromLong((long)x) -#endif - -#if PY_VERSION_HEX < 0x02040000 -#define Py_VISIT(op) \ - do { \ - if (op) { \ - int vret = visit((op), arg); \ - if (vret) \ - return vret; \ - } \ - } while (0) -#endif - -#if PY_VERSION_HEX < 0x02030000 -typedef struct { - PyTypeObject type; - PyNumberMethods as_number; - PyMappingMethods as_mapping; - PySequenceMethods as_sequence; - PyBufferProcs as_buffer; - PyObject *name, *slots; -} PyHeapTypeObject; -#endif - -#if PY_VERSION_HEX < 0x02030000 -typedef destructor freefunc; -#endif - -#if ((PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION > 6) || \ - (PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION > 0) || \ - (PY_MAJOR_VERSION > 3)) -# define SWIGPY_USE_CAPSULE -# define SWIGPY_CAPSULE_NAME ((char*)"swig_runtime_data" SWIG_RUNTIME_VERSION ".type_pointer_capsule" SWIG_TYPE_TABLE_NAME) -#endif - -#if PY_VERSION_HEX < 0x03020000 -#define PyDescr_TYPE(x) (((PyDescrObject *)(x))->d_type) -#define PyDescr_NAME(x) (((PyDescrObject *)(x))->d_name) -#define Py_hash_t long -#endif - -/* ----------------------------------------------------------------------------- - * error manipulation - * ----------------------------------------------------------------------------- */ - -SWIGRUNTIME PyObject* -SWIG_Python_ErrorType(int code) { - PyObject* type = 0; - switch(code) { - case SWIG_MemoryError: - type = PyExc_MemoryError; - break; - case SWIG_IOError: - type = PyExc_IOError; - break; - case SWIG_RuntimeError: - type = PyExc_RuntimeError; - break; - case SWIG_IndexError: - type = PyExc_IndexError; - break; - case SWIG_TypeError: - type = PyExc_TypeError; - break; - case SWIG_DivisionByZero: - type = PyExc_ZeroDivisionError; - break; - case SWIG_OverflowError: - type = PyExc_OverflowError; - break; - case SWIG_SyntaxError: - type = PyExc_SyntaxError; - break; - case SWIG_ValueError: - type = PyExc_ValueError; - break; - case SWIG_SystemError: - type = PyExc_SystemError; - break; - case SWIG_AttributeError: - type = PyExc_AttributeError; - break; - default: - type = PyExc_RuntimeError; - } - return type; -} - - -SWIGRUNTIME void -SWIG_Python_AddErrorMsg(const char* mesg) -{ - PyObject *type = 0; - PyObject *value = 0; - PyObject *traceback = 0; - - if (PyErr_Occurred()) PyErr_Fetch(&type, &value, &traceback); - if (value) { - char *tmp; - PyObject *old_str = PyObject_Str(value); - PyErr_Clear(); - Py_XINCREF(type); - - PyErr_Format(type, "%s %s", tmp = SWIG_Python_str_AsChar(old_str), mesg); - SWIG_Python_str_DelForPy3(tmp); - Py_DECREF(old_str); - Py_DECREF(value); - } else { - PyErr_SetString(PyExc_RuntimeError, mesg); - } -} - -#if defined(SWIG_PYTHON_NO_THREADS) -# if defined(SWIG_PYTHON_THREADS) -# undef SWIG_PYTHON_THREADS -# endif -#endif -#if defined(SWIG_PYTHON_THREADS) /* Threading support is enabled */ -# if !defined(SWIG_PYTHON_USE_GIL) && !defined(SWIG_PYTHON_NO_USE_GIL) -# if (PY_VERSION_HEX >= 0x02030000) /* For 2.3 or later, use the PyGILState calls */ -# define SWIG_PYTHON_USE_GIL -# endif -# endif -# if defined(SWIG_PYTHON_USE_GIL) /* Use PyGILState threads calls */ -# ifndef SWIG_PYTHON_INITIALIZE_THREADS -# define SWIG_PYTHON_INITIALIZE_THREADS PyEval_InitThreads() -# endif -# ifdef __cplusplus /* C++ code */ - class SWIG_Python_Thread_Block { - bool status; - PyGILState_STATE state; - public: - void end() { if (status) { PyGILState_Release(state); status = false;} } - SWIG_Python_Thread_Block() : status(true), state(PyGILState_Ensure()) {} - ~SWIG_Python_Thread_Block() { end(); } - }; - class SWIG_Python_Thread_Allow { - bool status; - PyThreadState *save; - public: - void end() { if (status) { PyEval_RestoreThread(save); status = false; }} - SWIG_Python_Thread_Allow() : status(true), save(PyEval_SaveThread()) {} - ~SWIG_Python_Thread_Allow() { end(); } - }; -# define SWIG_PYTHON_THREAD_BEGIN_BLOCK SWIG_Python_Thread_Block _swig_thread_block -# define SWIG_PYTHON_THREAD_END_BLOCK _swig_thread_block.end() -# define SWIG_PYTHON_THREAD_BEGIN_ALLOW SWIG_Python_Thread_Allow _swig_thread_allow -# define SWIG_PYTHON_THREAD_END_ALLOW _swig_thread_allow.end() -# else /* C code */ -# define SWIG_PYTHON_THREAD_BEGIN_BLOCK PyGILState_STATE _swig_thread_block = PyGILState_Ensure() -# define SWIG_PYTHON_THREAD_END_BLOCK PyGILState_Release(_swig_thread_block) -# define SWIG_PYTHON_THREAD_BEGIN_ALLOW PyThreadState *_swig_thread_allow = PyEval_SaveThread() -# define SWIG_PYTHON_THREAD_END_ALLOW PyEval_RestoreThread(_swig_thread_allow) -# endif -# else /* Old thread way, not implemented, user must provide it */ -# if !defined(SWIG_PYTHON_INITIALIZE_THREADS) -# define SWIG_PYTHON_INITIALIZE_THREADS -# endif -# if !defined(SWIG_PYTHON_THREAD_BEGIN_BLOCK) -# define SWIG_PYTHON_THREAD_BEGIN_BLOCK -# endif -# if !defined(SWIG_PYTHON_THREAD_END_BLOCK) -# define SWIG_PYTHON_THREAD_END_BLOCK -# endif -# if !defined(SWIG_PYTHON_THREAD_BEGIN_ALLOW) -# define SWIG_PYTHON_THREAD_BEGIN_ALLOW -# endif -# if !defined(SWIG_PYTHON_THREAD_END_ALLOW) -# define SWIG_PYTHON_THREAD_END_ALLOW -# endif -# endif -#else /* No thread support */ -# define SWIG_PYTHON_INITIALIZE_THREADS -# define SWIG_PYTHON_THREAD_BEGIN_BLOCK -# define SWIG_PYTHON_THREAD_END_BLOCK -# define SWIG_PYTHON_THREAD_BEGIN_ALLOW -# define SWIG_PYTHON_THREAD_END_ALLOW -#endif - -/* ----------------------------------------------------------------------------- - * Python API portion that goes into the runtime - * ----------------------------------------------------------------------------- */ - -#ifdef __cplusplus -extern "C" { -#endif - -/* ----------------------------------------------------------------------------- - * Constant declarations - * ----------------------------------------------------------------------------- */ - -/* Constant Types */ -#define SWIG_PY_POINTER 4 -#define SWIG_PY_BINARY 5 - -/* Constant information structure */ -typedef struct swig_const_info { - int type; - char *name; - long lvalue; - double dvalue; - void *pvalue; - swig_type_info **ptype; -} swig_const_info; - - -/* ----------------------------------------------------------------------------- - * Wrapper of PyInstanceMethod_New() used in Python 3 - * It is exported to the generated module, used for -fastproxy - * ----------------------------------------------------------------------------- */ -#if PY_VERSION_HEX >= 0x03000000 -SWIGRUNTIME PyObject* SWIG_PyInstanceMethod_New(PyObject *SWIGUNUSEDPARM(self), PyObject *func) -{ - return PyInstanceMethod_New(func); -} -#else -SWIGRUNTIME PyObject* SWIG_PyInstanceMethod_New(PyObject *SWIGUNUSEDPARM(self), PyObject *SWIGUNUSEDPARM(func)) -{ - return NULL; -} -#endif - -#ifdef __cplusplus -} -#endif - - -/* ----------------------------------------------------------------------------- - * pyrun.swg - * - * This file contains the runtime support for Python modules - * and includes code for managing global variables and pointer - * type checking. - * - * ----------------------------------------------------------------------------- */ - -/* Common SWIG API */ - -/* for raw pointers */ -#define SWIG_Python_ConvertPtr(obj, pptr, type, flags) SWIG_Python_ConvertPtrAndOwn(obj, pptr, type, flags, 0) -#define SWIG_ConvertPtr(obj, pptr, type, flags) SWIG_Python_ConvertPtr(obj, pptr, type, flags) -#define SWIG_ConvertPtrAndOwn(obj,pptr,type,flags,own) SWIG_Python_ConvertPtrAndOwn(obj, pptr, type, flags, own) - -#ifdef SWIGPYTHON_BUILTIN -#define SWIG_NewPointerObj(ptr, type, flags) SWIG_Python_NewPointerObj(self, ptr, type, flags) -#else -#define SWIG_NewPointerObj(ptr, type, flags) SWIG_Python_NewPointerObj(NULL, ptr, type, flags) -#endif - -#define SWIG_InternalNewPointerObj(ptr, type, flags) SWIG_Python_NewPointerObj(NULL, ptr, type, flags) - -#define SWIG_CheckImplicit(ty) SWIG_Python_CheckImplicit(ty) -#define SWIG_AcquirePtr(ptr, src) SWIG_Python_AcquirePtr(ptr, src) -#define swig_owntype int - -/* for raw packed data */ -#define SWIG_ConvertPacked(obj, ptr, sz, ty) SWIG_Python_ConvertPacked(obj, ptr, sz, ty) -#define SWIG_NewPackedObj(ptr, sz, type) SWIG_Python_NewPackedObj(ptr, sz, type) - -/* for class or struct pointers */ -#define SWIG_ConvertInstance(obj, pptr, type, flags) SWIG_ConvertPtr(obj, pptr, type, flags) -#define SWIG_NewInstanceObj(ptr, type, flags) SWIG_NewPointerObj(ptr, type, flags) - -/* for C or C++ function pointers */ -#define SWIG_ConvertFunctionPtr(obj, pptr, type) SWIG_Python_ConvertFunctionPtr(obj, pptr, type) -#define SWIG_NewFunctionPtrObj(ptr, type) SWIG_Python_NewPointerObj(NULL, ptr, type, 0) - -/* for C++ member pointers, ie, member methods */ -#define SWIG_ConvertMember(obj, ptr, sz, ty) SWIG_Python_ConvertPacked(obj, ptr, sz, ty) -#define SWIG_NewMemberObj(ptr, sz, type) SWIG_Python_NewPackedObj(ptr, sz, type) - - -/* Runtime API */ - -#define SWIG_GetModule(clientdata) SWIG_Python_GetModule(clientdata) -#define SWIG_SetModule(clientdata, pointer) SWIG_Python_SetModule(pointer) -#define SWIG_NewClientData(obj) SwigPyClientData_New(obj) - -#define SWIG_SetErrorObj SWIG_Python_SetErrorObj -#define SWIG_SetErrorMsg SWIG_Python_SetErrorMsg -#define SWIG_ErrorType(code) SWIG_Python_ErrorType(code) -#define SWIG_Error(code, msg) SWIG_Python_SetErrorMsg(SWIG_ErrorType(code), msg) -#define SWIG_fail goto fail - - -/* Runtime API implementation */ - -/* Error manipulation */ - -SWIGINTERN void -SWIG_Python_SetErrorObj(PyObject *errtype, PyObject *obj) { - SWIG_PYTHON_THREAD_BEGIN_BLOCK; - PyErr_SetObject(errtype, obj); - Py_DECREF(obj); - SWIG_PYTHON_THREAD_END_BLOCK; -} - -SWIGINTERN void -SWIG_Python_SetErrorMsg(PyObject *errtype, const char *msg) { - SWIG_PYTHON_THREAD_BEGIN_BLOCK; - PyErr_SetString(errtype, msg); - SWIG_PYTHON_THREAD_END_BLOCK; -} - -#define SWIG_Python_Raise(obj, type, desc) SWIG_Python_SetErrorObj(SWIG_Python_ExceptionType(desc), obj) - -/* Set a constant value */ - -#if defined(SWIGPYTHON_BUILTIN) - -SWIGINTERN void -SwigPyBuiltin_AddPublicSymbol(PyObject *seq, const char *key) { - PyObject *s = PyString_InternFromString(key); - PyList_Append(seq, s); - Py_DECREF(s); -} - -SWIGINTERN void -SWIG_Python_SetConstant(PyObject *d, PyObject *public_interface, const char *name, PyObject *obj) { -#if PY_VERSION_HEX < 0x02030000 - PyDict_SetItemString(d, (char *)name, obj); -#else - PyDict_SetItemString(d, name, obj); -#endif - Py_DECREF(obj); - if (public_interface) - SwigPyBuiltin_AddPublicSymbol(public_interface, name); -} - -#else - -SWIGINTERN void -SWIG_Python_SetConstant(PyObject *d, const char *name, PyObject *obj) { -#if PY_VERSION_HEX < 0x02030000 - PyDict_SetItemString(d, (char *)name, obj); -#else - PyDict_SetItemString(d, name, obj); -#endif - Py_DECREF(obj); -} - -#endif - -/* Append a value to the result obj */ - -SWIGINTERN PyObject* -SWIG_Python_AppendOutput(PyObject* result, PyObject* obj) { -#if !defined(SWIG_PYTHON_OUTPUT_TUPLE) - if (!result) { - result = obj; - } else if (result == Py_None) { - Py_DECREF(result); - result = obj; - } else { - if (!PyList_Check(result)) { - PyObject *o2 = result; - result = PyList_New(1); - PyList_SetItem(result, 0, o2); - } - PyList_Append(result,obj); - Py_DECREF(obj); - } - return result; -#else - PyObject* o2; - PyObject* o3; - if (!result) { - result = obj; - } else if (result == Py_None) { - Py_DECREF(result); - result = obj; - } else { - if (!PyTuple_Check(result)) { - o2 = result; - result = PyTuple_New(1); - PyTuple_SET_ITEM(result, 0, o2); - } - o3 = PyTuple_New(1); - PyTuple_SET_ITEM(o3, 0, obj); - o2 = result; - result = PySequence_Concat(o2, o3); - Py_DECREF(o2); - Py_DECREF(o3); - } - return result; -#endif -} - -/* Unpack the argument tuple */ - -SWIGINTERN Py_ssize_t -SWIG_Python_UnpackTuple(PyObject *args, const char *name, Py_ssize_t min, Py_ssize_t max, PyObject **objs) -{ - if (!args) { - if (!min && !max) { - return 1; - } else { - PyErr_Format(PyExc_TypeError, "%s expected %s%d arguments, got none", - name, (min == max ? "" : "at least "), (int)min); - return 0; - } - } - if (!PyTuple_Check(args)) { - if (min <= 1 && max >= 1) { - Py_ssize_t i; - objs[0] = args; - for (i = 1; i < max; ++i) { - objs[i] = 0; - } - return 2; - } - PyErr_SetString(PyExc_SystemError, "UnpackTuple() argument list is not a tuple"); - return 0; - } else { - Py_ssize_t l = PyTuple_GET_SIZE(args); - if (l < min) { - PyErr_Format(PyExc_TypeError, "%s expected %s%d arguments, got %d", - name, (min == max ? "" : "at least "), (int)min, (int)l); - return 0; - } else if (l > max) { - PyErr_Format(PyExc_TypeError, "%s expected %s%d arguments, got %d", - name, (min == max ? "" : "at most "), (int)max, (int)l); - return 0; - } else { - Py_ssize_t i; - for (i = 0; i < l; ++i) { - objs[i] = PyTuple_GET_ITEM(args, i); - } - for (; l < max; ++l) { - objs[l] = 0; - } - return i + 1; - } - } -} - -/* A functor is a function object with one single object argument */ -#if PY_VERSION_HEX >= 0x02020000 -#define SWIG_Python_CallFunctor(functor, obj) PyObject_CallFunctionObjArgs(functor, obj, NULL); -#else -#define SWIG_Python_CallFunctor(functor, obj) PyObject_CallFunction(functor, "O", obj); -#endif - -/* - Helper for static pointer initialization for both C and C++ code, for example - static PyObject *SWIG_STATIC_POINTER(MyVar) = NewSomething(...); -*/ -#ifdef __cplusplus -#define SWIG_STATIC_POINTER(var) var -#else -#define SWIG_STATIC_POINTER(var) var = 0; if (!var) var -#endif - -/* ----------------------------------------------------------------------------- - * Pointer declarations - * ----------------------------------------------------------------------------- */ - -/* Flags for new pointer objects */ -#define SWIG_POINTER_NOSHADOW (SWIG_POINTER_OWN << 1) -#define SWIG_POINTER_NEW (SWIG_POINTER_NOSHADOW | SWIG_POINTER_OWN) - -#define SWIG_POINTER_IMPLICIT_CONV (SWIG_POINTER_DISOWN << 1) - -#define SWIG_BUILTIN_TP_INIT (SWIG_POINTER_OWN << 2) -#define SWIG_BUILTIN_INIT (SWIG_BUILTIN_TP_INIT | SWIG_POINTER_OWN) - -#ifdef __cplusplus -extern "C" { -#endif - -/* How to access Py_None */ -#if defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__) -# ifndef SWIG_PYTHON_NO_BUILD_NONE -# ifndef SWIG_PYTHON_BUILD_NONE -# define SWIG_PYTHON_BUILD_NONE -# endif -# endif -#endif - -#ifdef SWIG_PYTHON_BUILD_NONE -# ifdef Py_None -# undef Py_None -# define Py_None SWIG_Py_None() -# endif -SWIGRUNTIMEINLINE PyObject * -_SWIG_Py_None(void) -{ - PyObject *none = Py_BuildValue((char*)""); - Py_DECREF(none); - return none; -} -SWIGRUNTIME PyObject * -SWIG_Py_None(void) -{ - static PyObject *SWIG_STATIC_POINTER(none) = _SWIG_Py_None(); - return none; -} -#endif - -/* The python void return value */ - -SWIGRUNTIMEINLINE PyObject * -SWIG_Py_Void(void) -{ - PyObject *none = Py_None; - Py_INCREF(none); - return none; -} - -/* SwigPyClientData */ - -typedef struct { - PyObject *klass; - PyObject *newraw; - PyObject *newargs; - PyObject *destroy; - int delargs; - int implicitconv; - PyTypeObject *pytype; -} SwigPyClientData; - -SWIGRUNTIMEINLINE int -SWIG_Python_CheckImplicit(swig_type_info *ty) -{ - SwigPyClientData *data = (SwigPyClientData *)ty->clientdata; - return data ? data->implicitconv : 0; -} - -SWIGRUNTIMEINLINE PyObject * -SWIG_Python_ExceptionType(swig_type_info *desc) { - SwigPyClientData *data = desc ? (SwigPyClientData *) desc->clientdata : 0; - PyObject *klass = data ? data->klass : 0; - return (klass ? klass : PyExc_RuntimeError); -} - - -SWIGRUNTIME SwigPyClientData * -SwigPyClientData_New(PyObject* obj) -{ - if (!obj) { - return 0; - } else { - SwigPyClientData *data = (SwigPyClientData *)malloc(sizeof(SwigPyClientData)); - /* the klass element */ - data->klass = obj; - Py_INCREF(data->klass); - /* the newraw method and newargs arguments used to create a new raw instance */ - if (PyClass_Check(obj)) { - data->newraw = 0; - data->newargs = obj; - Py_INCREF(obj); - } else { -#if (PY_VERSION_HEX < 0x02020000) - data->newraw = 0; -#else - data->newraw = PyObject_GetAttrString(data->klass, (char *)"__new__"); -#endif - if (data->newraw) { - Py_INCREF(data->newraw); - data->newargs = PyTuple_New(1); - PyTuple_SetItem(data->newargs, 0, obj); - } else { - data->newargs = obj; - } - Py_INCREF(data->newargs); - } - /* the destroy method, aka as the C++ delete method */ - data->destroy = PyObject_GetAttrString(data->klass, (char *)"__swig_destroy__"); - if (PyErr_Occurred()) { - PyErr_Clear(); - data->destroy = 0; - } - if (data->destroy) { - int flags; - Py_INCREF(data->destroy); - flags = PyCFunction_GET_FLAGS(data->destroy); -#ifdef METH_O - data->delargs = !(flags & (METH_O)); -#else - data->delargs = 0; -#endif - } else { - data->delargs = 0; - } - data->implicitconv = 0; - data->pytype = 0; - return data; - } -} - -SWIGRUNTIME void -SwigPyClientData_Del(SwigPyClientData *data) { - Py_XDECREF(data->newraw); - Py_XDECREF(data->newargs); - Py_XDECREF(data->destroy); -} - -/* =============== SwigPyObject =====================*/ - -typedef struct { - PyObject_HEAD - void *ptr; - swig_type_info *ty; - int own; - PyObject *next; -#ifdef SWIGPYTHON_BUILTIN - PyObject *dict; -#endif -} SwigPyObject; - - -#ifdef SWIGPYTHON_BUILTIN - -SWIGRUNTIME PyObject * -SwigPyObject_get___dict__(PyObject *v, PyObject *SWIGUNUSEDPARM(args)) -{ - SwigPyObject *sobj = (SwigPyObject *)v; - - if (!sobj->dict) - sobj->dict = PyDict_New(); - - Py_INCREF(sobj->dict); - return sobj->dict; -} - -#endif - -SWIGRUNTIME PyObject * -SwigPyObject_long(SwigPyObject *v) -{ - return PyLong_FromVoidPtr(v->ptr); -} - -SWIGRUNTIME PyObject * -SwigPyObject_format(const char* fmt, SwigPyObject *v) -{ - PyObject *res = NULL; - PyObject *args = PyTuple_New(1); - if (args) { - if (PyTuple_SetItem(args, 0, SwigPyObject_long(v)) == 0) { - PyObject *ofmt = SWIG_Python_str_FromChar(fmt); - if (ofmt) { -#if PY_VERSION_HEX >= 0x03000000 - res = PyUnicode_Format(ofmt,args); -#else - res = PyString_Format(ofmt,args); -#endif - Py_DECREF(ofmt); - } - Py_DECREF(args); - } - } - return res; -} - -SWIGRUNTIME PyObject * -SwigPyObject_oct(SwigPyObject *v) -{ - return SwigPyObject_format("%o",v); -} - -SWIGRUNTIME PyObject * -SwigPyObject_hex(SwigPyObject *v) -{ - return SwigPyObject_format("%x",v); -} - -SWIGRUNTIME PyObject * -#ifdef METH_NOARGS -SwigPyObject_repr(SwigPyObject *v) -#else -SwigPyObject_repr(SwigPyObject *v, PyObject *args) -#endif -{ - const char *name = SWIG_TypePrettyName(v->ty); - PyObject *repr = SWIG_Python_str_FromFormat("", (name ? name : "unknown"), (void *)v); - if (v->next) { -# ifdef METH_NOARGS - PyObject *nrep = SwigPyObject_repr((SwigPyObject *)v->next); -# else - PyObject *nrep = SwigPyObject_repr((SwigPyObject *)v->next, args); -# endif -# if PY_VERSION_HEX >= 0x03000000 - PyObject *joined = PyUnicode_Concat(repr, nrep); - Py_DecRef(repr); - Py_DecRef(nrep); - repr = joined; -# else - PyString_ConcatAndDel(&repr,nrep); -# endif - } - return repr; -} - -SWIGRUNTIME int -SwigPyObject_compare(SwigPyObject *v, SwigPyObject *w) -{ - void *i = v->ptr; - void *j = w->ptr; - return (i < j) ? -1 : ((i > j) ? 1 : 0); -} - -/* Added for Python 3.x, would it also be useful for Python 2.x? */ -SWIGRUNTIME PyObject* -SwigPyObject_richcompare(SwigPyObject *v, SwigPyObject *w, int op) -{ - PyObject* res; - if( op != Py_EQ && op != Py_NE ) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - res = PyBool_FromLong( (SwigPyObject_compare(v, w)==0) == (op == Py_EQ) ? 1 : 0); - return res; -} - - -SWIGRUNTIME PyTypeObject* SwigPyObject_TypeOnce(void); - -#ifdef SWIGPYTHON_BUILTIN -static swig_type_info *SwigPyObject_stype = 0; -SWIGRUNTIME PyTypeObject* -SwigPyObject_type(void) { - SwigPyClientData *cd; - assert(SwigPyObject_stype); - cd = (SwigPyClientData*) SwigPyObject_stype->clientdata; - assert(cd); - assert(cd->pytype); - return cd->pytype; -} -#else -SWIGRUNTIME PyTypeObject* -SwigPyObject_type(void) { - static PyTypeObject *SWIG_STATIC_POINTER(type) = SwigPyObject_TypeOnce(); - return type; -} -#endif - -SWIGRUNTIMEINLINE int -SwigPyObject_Check(PyObject *op) { -#ifdef SWIGPYTHON_BUILTIN - PyTypeObject *target_tp = SwigPyObject_type(); - if (PyType_IsSubtype(op->ob_type, target_tp)) - return 1; - return (strcmp(op->ob_type->tp_name, "SwigPyObject") == 0); -#else - return (Py_TYPE(op) == SwigPyObject_type()) - || (strcmp(Py_TYPE(op)->tp_name,"SwigPyObject") == 0); -#endif -} - -SWIGRUNTIME PyObject * -SwigPyObject_New(void *ptr, swig_type_info *ty, int own); - -SWIGRUNTIME void -SwigPyObject_dealloc(PyObject *v) -{ - SwigPyObject *sobj = (SwigPyObject *) v; - PyObject *next = sobj->next; - if (sobj->own == SWIG_POINTER_OWN) { - swig_type_info *ty = sobj->ty; - SwigPyClientData *data = ty ? (SwigPyClientData *) ty->clientdata : 0; - PyObject *destroy = data ? data->destroy : 0; - if (destroy) { - /* destroy is always a VARARGS method */ - PyObject *res; - - /* PyObject_CallFunction() has the potential to silently drop - the active active exception. In cases of unnamed temporary - variable or where we just finished iterating over a generator - StopIteration will be active right now, and this needs to - remain true upon return from SwigPyObject_dealloc. So save - and restore. */ - - PyObject *val = NULL, *type = NULL, *tb = NULL; - PyErr_Fetch(&val, &type, &tb); - - if (data->delargs) { - /* we need to create a temporary object to carry the destroy operation */ - PyObject *tmp = SwigPyObject_New(sobj->ptr, ty, 0); - res = SWIG_Python_CallFunctor(destroy, tmp); - Py_DECREF(tmp); - } else { - PyCFunction meth = PyCFunction_GET_FUNCTION(destroy); - PyObject *mself = PyCFunction_GET_SELF(destroy); - res = ((*meth)(mself, v)); - } - if (!res) - PyErr_WriteUnraisable(destroy); - - PyErr_Restore(val, type, tb); - - Py_XDECREF(res); - } -#if !defined(SWIG_PYTHON_SILENT_MEMLEAK) - else { - const char *name = SWIG_TypePrettyName(ty); - printf("swig/python detected a memory leak of type '%s', no destructor found.\n", (name ? name : "unknown")); - } -#endif - } - Py_XDECREF(next); - PyObject_DEL(v); -} - -SWIGRUNTIME PyObject* -SwigPyObject_append(PyObject* v, PyObject* next) -{ - SwigPyObject *sobj = (SwigPyObject *) v; -#ifndef METH_O - PyObject *tmp = 0; - if (!PyArg_ParseTuple(next,(char *)"O:append", &tmp)) return NULL; - next = tmp; -#endif - if (!SwigPyObject_Check(next)) { - PyErr_SetString(PyExc_TypeError, "Attempt to append a non SwigPyObject"); - return NULL; - } - sobj->next = next; - Py_INCREF(next); - return SWIG_Py_Void(); -} - -SWIGRUNTIME PyObject* -#ifdef METH_NOARGS -SwigPyObject_next(PyObject* v) -#else -SwigPyObject_next(PyObject* v, PyObject *SWIGUNUSEDPARM(args)) -#endif -{ - SwigPyObject *sobj = (SwigPyObject *) v; - if (sobj->next) { - Py_INCREF(sobj->next); - return sobj->next; - } else { - return SWIG_Py_Void(); - } -} - -SWIGINTERN PyObject* -#ifdef METH_NOARGS -SwigPyObject_disown(PyObject *v) -#else -SwigPyObject_disown(PyObject* v, PyObject *SWIGUNUSEDPARM(args)) -#endif -{ - SwigPyObject *sobj = (SwigPyObject *)v; - sobj->own = 0; - return SWIG_Py_Void(); -} - -SWIGINTERN PyObject* -#ifdef METH_NOARGS -SwigPyObject_acquire(PyObject *v) -#else -SwigPyObject_acquire(PyObject* v, PyObject *SWIGUNUSEDPARM(args)) -#endif -{ - SwigPyObject *sobj = (SwigPyObject *)v; - sobj->own = SWIG_POINTER_OWN; - return SWIG_Py_Void(); -} - -SWIGINTERN PyObject* -SwigPyObject_own(PyObject *v, PyObject *args) -{ - PyObject *val = 0; -#if (PY_VERSION_HEX < 0x02020000) - if (!PyArg_ParseTuple(args,(char *)"|O:own",&val)) -#elif (PY_VERSION_HEX < 0x02050000) - if (!PyArg_UnpackTuple(args, (char *)"own", 0, 1, &val)) -#else - if (!PyArg_UnpackTuple(args, "own", 0, 1, &val)) -#endif - { - return NULL; - } - else - { - SwigPyObject *sobj = (SwigPyObject *)v; - PyObject *obj = PyBool_FromLong(sobj->own); - if (val) { -#ifdef METH_NOARGS - if (PyObject_IsTrue(val)) { - SwigPyObject_acquire(v); - } else { - SwigPyObject_disown(v); - } -#else - if (PyObject_IsTrue(val)) { - SwigPyObject_acquire(v,args); - } else { - SwigPyObject_disown(v,args); - } -#endif - } - return obj; - } -} - -#ifdef METH_O -static PyMethodDef -swigobject_methods[] = { - {(char *)"disown", (PyCFunction)SwigPyObject_disown, METH_NOARGS, (char *)"releases ownership of the pointer"}, - {(char *)"acquire", (PyCFunction)SwigPyObject_acquire, METH_NOARGS, (char *)"acquires ownership of the pointer"}, - {(char *)"own", (PyCFunction)SwigPyObject_own, METH_VARARGS, (char *)"returns/sets ownership of the pointer"}, - {(char *)"append", (PyCFunction)SwigPyObject_append, METH_O, (char *)"appends another 'this' object"}, - {(char *)"next", (PyCFunction)SwigPyObject_next, METH_NOARGS, (char *)"returns the next 'this' object"}, - {(char *)"__repr__",(PyCFunction)SwigPyObject_repr, METH_NOARGS, (char *)"returns object representation"}, - {0, 0, 0, 0} -}; -#else -static PyMethodDef -swigobject_methods[] = { - {(char *)"disown", (PyCFunction)SwigPyObject_disown, METH_VARARGS, (char *)"releases ownership of the pointer"}, - {(char *)"acquire", (PyCFunction)SwigPyObject_acquire, METH_VARARGS, (char *)"acquires ownership of the pointer"}, - {(char *)"own", (PyCFunction)SwigPyObject_own, METH_VARARGS, (char *)"returns/sets ownership of the pointer"}, - {(char *)"append", (PyCFunction)SwigPyObject_append, METH_VARARGS, (char *)"appends another 'this' object"}, - {(char *)"next", (PyCFunction)SwigPyObject_next, METH_VARARGS, (char *)"returns the next 'this' object"}, - {(char *)"__repr__",(PyCFunction)SwigPyObject_repr, METH_VARARGS, (char *)"returns object representation"}, - {0, 0, 0, 0} -}; -#endif - -#if PY_VERSION_HEX < 0x02020000 -SWIGINTERN PyObject * -SwigPyObject_getattr(SwigPyObject *sobj,char *name) -{ - return Py_FindMethod(swigobject_methods, (PyObject *)sobj, name); -} -#endif - -SWIGRUNTIME PyTypeObject* -SwigPyObject_TypeOnce(void) { - static char swigobject_doc[] = "Swig object carries a C/C++ instance pointer"; - - static PyNumberMethods SwigPyObject_as_number = { - (binaryfunc)0, /*nb_add*/ - (binaryfunc)0, /*nb_subtract*/ - (binaryfunc)0, /*nb_multiply*/ - /* nb_divide removed in Python 3 */ -#if PY_VERSION_HEX < 0x03000000 - (binaryfunc)0, /*nb_divide*/ -#endif - (binaryfunc)0, /*nb_remainder*/ - (binaryfunc)0, /*nb_divmod*/ - (ternaryfunc)0,/*nb_power*/ - (unaryfunc)0, /*nb_negative*/ - (unaryfunc)0, /*nb_positive*/ - (unaryfunc)0, /*nb_absolute*/ - (inquiry)0, /*nb_nonzero*/ - 0, /*nb_invert*/ - 0, /*nb_lshift*/ - 0, /*nb_rshift*/ - 0, /*nb_and*/ - 0, /*nb_xor*/ - 0, /*nb_or*/ -#if PY_VERSION_HEX < 0x03000000 - 0, /*nb_coerce*/ -#endif - (unaryfunc)SwigPyObject_long, /*nb_int*/ -#if PY_VERSION_HEX < 0x03000000 - (unaryfunc)SwigPyObject_long, /*nb_long*/ -#else - 0, /*nb_reserved*/ -#endif - (unaryfunc)0, /*nb_float*/ -#if PY_VERSION_HEX < 0x03000000 - (unaryfunc)SwigPyObject_oct, /*nb_oct*/ - (unaryfunc)SwigPyObject_hex, /*nb_hex*/ -#endif -#if PY_VERSION_HEX >= 0x03050000 /* 3.5 */ - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 /* nb_inplace_add -> nb_inplace_matrix_multiply */ -#elif PY_VERSION_HEX >= 0x03000000 /* 3.0 */ - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 /* nb_inplace_add -> nb_index, nb_inplace_divide removed */ -#elif PY_VERSION_HEX >= 0x02050000 /* 2.5.0 */ - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 /* nb_inplace_add -> nb_index */ -#elif PY_VERSION_HEX >= 0x02020000 /* 2.2.0 */ - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 /* nb_inplace_add -> nb_inplace_true_divide */ -#elif PY_VERSION_HEX >= 0x02000000 /* 2.0.0 */ - 0,0,0,0,0,0,0,0,0,0,0 /* nb_inplace_add -> nb_inplace_or */ -#endif - }; - - static PyTypeObject swigpyobject_type; - static int type_init = 0; - if (!type_init) { - const PyTypeObject tmp = { -#if PY_VERSION_HEX >= 0x03000000 - PyVarObject_HEAD_INIT(NULL, 0) -#else - PyObject_HEAD_INIT(NULL) - 0, /* ob_size */ -#endif - (char *)"SwigPyObject", /* tp_name */ - sizeof(SwigPyObject), /* tp_basicsize */ - 0, /* tp_itemsize */ - (destructor)SwigPyObject_dealloc, /* tp_dealloc */ - 0, /* tp_print */ -#if PY_VERSION_HEX < 0x02020000 - (getattrfunc)SwigPyObject_getattr, /* tp_getattr */ -#else - (getattrfunc)0, /* tp_getattr */ -#endif - (setattrfunc)0, /* tp_setattr */ -#if PY_VERSION_HEX >= 0x03000000 - 0, /* tp_reserved in 3.0.1, tp_compare in 3.0.0 but not used */ -#else - (cmpfunc)SwigPyObject_compare, /* tp_compare */ -#endif - (reprfunc)SwigPyObject_repr, /* tp_repr */ - &SwigPyObject_as_number, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - (hashfunc)0, /* tp_hash */ - (ternaryfunc)0, /* tp_call */ - 0, /* tp_str */ - PyObject_GenericGetAttr, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT, /* tp_flags */ - swigobject_doc, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - (richcmpfunc)SwigPyObject_richcompare,/* tp_richcompare */ - 0, /* tp_weaklistoffset */ -#if PY_VERSION_HEX >= 0x02020000 - 0, /* tp_iter */ - 0, /* tp_iternext */ - swigobject_methods, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - 0, /* tp_init */ - 0, /* tp_alloc */ - 0, /* tp_new */ - 0, /* tp_free */ - 0, /* tp_is_gc */ - 0, /* tp_bases */ - 0, /* tp_mro */ - 0, /* tp_cache */ - 0, /* tp_subclasses */ - 0, /* tp_weaklist */ -#endif -#if PY_VERSION_HEX >= 0x02030000 - 0, /* tp_del */ -#endif -#if PY_VERSION_HEX >= 0x02060000 - 0, /* tp_version_tag */ -#endif -#if PY_VERSION_HEX >= 0x03040000 - 0, /* tp_finalize */ -#endif -#ifdef COUNT_ALLOCS - 0, /* tp_allocs */ - 0, /* tp_frees */ - 0, /* tp_maxalloc */ -#if PY_VERSION_HEX >= 0x02050000 - 0, /* tp_prev */ -#endif - 0 /* tp_next */ -#endif - }; - swigpyobject_type = tmp; - type_init = 1; -#if PY_VERSION_HEX < 0x02020000 - swigpyobject_type.ob_type = &PyType_Type; -#else - if (PyType_Ready(&swigpyobject_type) < 0) - return NULL; -#endif - } - return &swigpyobject_type; -} - -SWIGRUNTIME PyObject * -SwigPyObject_New(void *ptr, swig_type_info *ty, int own) -{ - SwigPyObject *sobj = PyObject_NEW(SwigPyObject, SwigPyObject_type()); - if (sobj) { - sobj->ptr = ptr; - sobj->ty = ty; - sobj->own = own; - sobj->next = 0; - } - return (PyObject *)sobj; -} - -/* ----------------------------------------------------------------------------- - * Implements a simple Swig Packed type, and use it instead of string - * ----------------------------------------------------------------------------- */ - -typedef struct { - PyObject_HEAD - void *pack; - swig_type_info *ty; - size_t size; -} SwigPyPacked; - -SWIGRUNTIME int -SwigPyPacked_print(SwigPyPacked *v, FILE *fp, int SWIGUNUSEDPARM(flags)) -{ - char result[SWIG_BUFFER_SIZE]; - fputs("pack, v->size, 0, sizeof(result))) { - fputs("at ", fp); - fputs(result, fp); - } - fputs(v->ty->name,fp); - fputs(">", fp); - return 0; -} - -SWIGRUNTIME PyObject * -SwigPyPacked_repr(SwigPyPacked *v) -{ - char result[SWIG_BUFFER_SIZE]; - if (SWIG_PackDataName(result, v->pack, v->size, 0, sizeof(result))) { - return SWIG_Python_str_FromFormat("", result, v->ty->name); - } else { - return SWIG_Python_str_FromFormat("", v->ty->name); - } -} - -SWIGRUNTIME PyObject * -SwigPyPacked_str(SwigPyPacked *v) -{ - char result[SWIG_BUFFER_SIZE]; - if (SWIG_PackDataName(result, v->pack, v->size, 0, sizeof(result))){ - return SWIG_Python_str_FromFormat("%s%s", result, v->ty->name); - } else { - return SWIG_Python_str_FromChar(v->ty->name); - } -} - -SWIGRUNTIME int -SwigPyPacked_compare(SwigPyPacked *v, SwigPyPacked *w) -{ - size_t i = v->size; - size_t j = w->size; - int s = (i < j) ? -1 : ((i > j) ? 1 : 0); - return s ? s : strncmp((char *)v->pack, (char *)w->pack, 2*v->size); -} - -SWIGRUNTIME PyTypeObject* SwigPyPacked_TypeOnce(void); - -SWIGRUNTIME PyTypeObject* -SwigPyPacked_type(void) { - static PyTypeObject *SWIG_STATIC_POINTER(type) = SwigPyPacked_TypeOnce(); - return type; -} - -SWIGRUNTIMEINLINE int -SwigPyPacked_Check(PyObject *op) { - return ((op)->ob_type == SwigPyPacked_TypeOnce()) - || (strcmp((op)->ob_type->tp_name,"SwigPyPacked") == 0); -} - -SWIGRUNTIME void -SwigPyPacked_dealloc(PyObject *v) -{ - if (SwigPyPacked_Check(v)) { - SwigPyPacked *sobj = (SwigPyPacked *) v; - free(sobj->pack); - } - PyObject_DEL(v); -} - -SWIGRUNTIME PyTypeObject* -SwigPyPacked_TypeOnce(void) { - static char swigpacked_doc[] = "Swig object carries a C/C++ instance pointer"; - static PyTypeObject swigpypacked_type; - static int type_init = 0; - if (!type_init) { - const PyTypeObject tmp = { -#if PY_VERSION_HEX>=0x03000000 - PyVarObject_HEAD_INIT(NULL, 0) -#else - PyObject_HEAD_INIT(NULL) - 0, /* ob_size */ -#endif - (char *)"SwigPyPacked", /* tp_name */ - sizeof(SwigPyPacked), /* tp_basicsize */ - 0, /* tp_itemsize */ - (destructor)SwigPyPacked_dealloc, /* tp_dealloc */ - (printfunc)SwigPyPacked_print, /* tp_print */ - (getattrfunc)0, /* tp_getattr */ - (setattrfunc)0, /* tp_setattr */ -#if PY_VERSION_HEX>=0x03000000 - 0, /* tp_reserved in 3.0.1 */ -#else - (cmpfunc)SwigPyPacked_compare, /* tp_compare */ -#endif - (reprfunc)SwigPyPacked_repr, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - (hashfunc)0, /* tp_hash */ - (ternaryfunc)0, /* tp_call */ - (reprfunc)SwigPyPacked_str, /* tp_str */ - PyObject_GenericGetAttr, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT, /* tp_flags */ - swigpacked_doc, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ -#if PY_VERSION_HEX >= 0x02020000 - 0, /* tp_iter */ - 0, /* tp_iternext */ - 0, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - 0, /* tp_init */ - 0, /* tp_alloc */ - 0, /* tp_new */ - 0, /* tp_free */ - 0, /* tp_is_gc */ - 0, /* tp_bases */ - 0, /* tp_mro */ - 0, /* tp_cache */ - 0, /* tp_subclasses */ - 0, /* tp_weaklist */ -#endif -#if PY_VERSION_HEX >= 0x02030000 - 0, /* tp_del */ -#endif -#if PY_VERSION_HEX >= 0x02060000 - 0, /* tp_version_tag */ -#endif -#if PY_VERSION_HEX >= 0x03040000 - 0, /* tp_finalize */ -#endif -#ifdef COUNT_ALLOCS - 0, /* tp_allocs */ - 0, /* tp_frees */ - 0, /* tp_maxalloc */ -#if PY_VERSION_HEX >= 0x02050000 - 0, /* tp_prev */ -#endif - 0 /* tp_next */ -#endif - }; - swigpypacked_type = tmp; - type_init = 1; -#if PY_VERSION_HEX < 0x02020000 - swigpypacked_type.ob_type = &PyType_Type; -#else - if (PyType_Ready(&swigpypacked_type) < 0) - return NULL; -#endif - } - return &swigpypacked_type; -} - -SWIGRUNTIME PyObject * -SwigPyPacked_New(void *ptr, size_t size, swig_type_info *ty) -{ - SwigPyPacked *sobj = PyObject_NEW(SwigPyPacked, SwigPyPacked_type()); - if (sobj) { - void *pack = malloc(size); - if (pack) { - memcpy(pack, ptr, size); - sobj->pack = pack; - sobj->ty = ty; - sobj->size = size; - } else { - PyObject_DEL((PyObject *) sobj); - sobj = 0; - } - } - return (PyObject *) sobj; -} - -SWIGRUNTIME swig_type_info * -SwigPyPacked_UnpackData(PyObject *obj, void *ptr, size_t size) -{ - if (SwigPyPacked_Check(obj)) { - SwigPyPacked *sobj = (SwigPyPacked *)obj; - if (sobj->size != size) return 0; - memcpy(ptr, sobj->pack, size); - return sobj->ty; - } else { - return 0; - } -} - -/* ----------------------------------------------------------------------------- - * pointers/data manipulation - * ----------------------------------------------------------------------------- */ - -SWIGRUNTIMEINLINE PyObject * -_SWIG_This(void) -{ - return SWIG_Python_str_FromChar("this"); -} - -static PyObject *swig_this = NULL; - -SWIGRUNTIME PyObject * -SWIG_This(void) -{ - if (swig_this == NULL) - swig_this = _SWIG_This(); - return swig_this; -} - -/* #define SWIG_PYTHON_SLOW_GETSET_THIS */ - -/* TODO: I don't know how to implement the fast getset in Python 3 right now */ -#if PY_VERSION_HEX>=0x03000000 -#define SWIG_PYTHON_SLOW_GETSET_THIS -#endif - -SWIGRUNTIME SwigPyObject * -SWIG_Python_GetSwigThis(PyObject *pyobj) -{ - PyObject *obj; - - if (SwigPyObject_Check(pyobj)) - return (SwigPyObject *) pyobj; - -#ifdef SWIGPYTHON_BUILTIN - (void)obj; -# ifdef PyWeakref_CheckProxy - if (PyWeakref_CheckProxy(pyobj)) { - pyobj = PyWeakref_GET_OBJECT(pyobj); - if (pyobj && SwigPyObject_Check(pyobj)) - return (SwigPyObject*) pyobj; - } -# endif - return NULL; -#else - - obj = 0; - -#if (!defined(SWIG_PYTHON_SLOW_GETSET_THIS) && (PY_VERSION_HEX >= 0x02030000)) - if (PyInstance_Check(pyobj)) { - obj = _PyInstance_Lookup(pyobj, SWIG_This()); - } else { - PyObject **dictptr = _PyObject_GetDictPtr(pyobj); - if (dictptr != NULL) { - PyObject *dict = *dictptr; - obj = dict ? PyDict_GetItem(dict, SWIG_This()) : 0; - } else { -#ifdef PyWeakref_CheckProxy - if (PyWeakref_CheckProxy(pyobj)) { - PyObject *wobj = PyWeakref_GET_OBJECT(pyobj); - return wobj ? SWIG_Python_GetSwigThis(wobj) : 0; - } -#endif - obj = PyObject_GetAttr(pyobj,SWIG_This()); - if (obj) { - Py_DECREF(obj); - } else { - if (PyErr_Occurred()) PyErr_Clear(); - return 0; - } - } - } -#else - obj = PyObject_GetAttr(pyobj,SWIG_This()); - if (obj) { - Py_DECREF(obj); - } else { - if (PyErr_Occurred()) PyErr_Clear(); - return 0; - } -#endif - if (obj && !SwigPyObject_Check(obj)) { - /* a PyObject is called 'this', try to get the 'real this' - SwigPyObject from it */ - return SWIG_Python_GetSwigThis(obj); - } - return (SwigPyObject *)obj; -#endif -} - -/* Acquire a pointer value */ - -SWIGRUNTIME int -SWIG_Python_AcquirePtr(PyObject *obj, int own) { - if (own == SWIG_POINTER_OWN) { - SwigPyObject *sobj = SWIG_Python_GetSwigThis(obj); - if (sobj) { - int oldown = sobj->own; - sobj->own = own; - return oldown; - } - } - return 0; -} - -/* Convert a pointer value */ - -SWIGRUNTIME int -SWIG_Python_ConvertPtrAndOwn(PyObject *obj, void **ptr, swig_type_info *ty, int flags, int *own) { - int res; - SwigPyObject *sobj; - int implicit_conv = (flags & SWIG_POINTER_IMPLICIT_CONV) != 0; - - if (!obj) - return SWIG_ERROR; - if (obj == Py_None && !implicit_conv) { - if (ptr) - *ptr = 0; - return SWIG_OK; - } - - res = SWIG_ERROR; - - sobj = SWIG_Python_GetSwigThis(obj); - if (own) - *own = 0; - while (sobj) { - void *vptr = sobj->ptr; - if (ty) { - swig_type_info *to = sobj->ty; - if (to == ty) { - /* no type cast needed */ - if (ptr) *ptr = vptr; - break; - } else { - swig_cast_info *tc = SWIG_TypeCheck(to->name,ty); - if (!tc) { - sobj = (SwigPyObject *)sobj->next; - } else { - if (ptr) { - int newmemory = 0; - *ptr = SWIG_TypeCast(tc,vptr,&newmemory); - if (newmemory == SWIG_CAST_NEW_MEMORY) { - assert(own); /* badly formed typemap which will lead to a memory leak - it must set and use own to delete *ptr */ - if (own) - *own = *own | SWIG_CAST_NEW_MEMORY; - } - } - break; - } - } - } else { - if (ptr) *ptr = vptr; - break; - } - } - if (sobj) { - if (own) - *own = *own | sobj->own; - if (flags & SWIG_POINTER_DISOWN) { - sobj->own = 0; - } - res = SWIG_OK; - } else { - if (implicit_conv) { - SwigPyClientData *data = ty ? (SwigPyClientData *) ty->clientdata : 0; - if (data && !data->implicitconv) { - PyObject *klass = data->klass; - if (klass) { - PyObject *impconv; - data->implicitconv = 1; /* avoid recursion and call 'explicit' constructors*/ - impconv = SWIG_Python_CallFunctor(klass, obj); - data->implicitconv = 0; - if (PyErr_Occurred()) { - PyErr_Clear(); - impconv = 0; - } - if (impconv) { - SwigPyObject *iobj = SWIG_Python_GetSwigThis(impconv); - if (iobj) { - void *vptr; - res = SWIG_Python_ConvertPtrAndOwn((PyObject*)iobj, &vptr, ty, 0, 0); - if (SWIG_IsOK(res)) { - if (ptr) { - *ptr = vptr; - /* transfer the ownership to 'ptr' */ - iobj->own = 0; - res = SWIG_AddCast(res); - res = SWIG_AddNewMask(res); - } else { - res = SWIG_AddCast(res); - } - } - } - Py_DECREF(impconv); - } - } - } - } - if (!SWIG_IsOK(res) && obj == Py_None) { - if (ptr) - *ptr = 0; - if (PyErr_Occurred()) - PyErr_Clear(); - res = SWIG_OK; - } - } - return res; -} - -/* Convert a function ptr value */ - -SWIGRUNTIME int -SWIG_Python_ConvertFunctionPtr(PyObject *obj, void **ptr, swig_type_info *ty) { - if (!PyCFunction_Check(obj)) { - return SWIG_ConvertPtr(obj, ptr, ty, 0); - } else { - void *vptr = 0; - - /* here we get the method pointer for callbacks */ - const char *doc = (((PyCFunctionObject *)obj) -> m_ml -> ml_doc); - const char *desc = doc ? strstr(doc, "swig_ptr: ") : 0; - if (desc) - desc = ty ? SWIG_UnpackVoidPtr(desc + 10, &vptr, ty->name) : 0; - if (!desc) - return SWIG_ERROR; - if (ty) { - swig_cast_info *tc = SWIG_TypeCheck(desc,ty); - if (tc) { - int newmemory = 0; - *ptr = SWIG_TypeCast(tc,vptr,&newmemory); - assert(!newmemory); /* newmemory handling not yet implemented */ - } else { - return SWIG_ERROR; - } - } else { - *ptr = vptr; - } - return SWIG_OK; - } -} - -/* Convert a packed value value */ - -SWIGRUNTIME int -SWIG_Python_ConvertPacked(PyObject *obj, void *ptr, size_t sz, swig_type_info *ty) { - swig_type_info *to = SwigPyPacked_UnpackData(obj, ptr, sz); - if (!to) return SWIG_ERROR; - if (ty) { - if (to != ty) { - /* check type cast? */ - swig_cast_info *tc = SWIG_TypeCheck(to->name,ty); - if (!tc) return SWIG_ERROR; - } - } - return SWIG_OK; -} - -/* ----------------------------------------------------------------------------- - * Create a new pointer object - * ----------------------------------------------------------------------------- */ - -/* - Create a new instance object, without calling __init__, and set the - 'this' attribute. -*/ - -SWIGRUNTIME PyObject* -SWIG_Python_NewShadowInstance(SwigPyClientData *data, PyObject *swig_this) -{ -#if (PY_VERSION_HEX >= 0x02020000) - PyObject *inst = 0; - PyObject *newraw = data->newraw; - if (newraw) { - inst = PyObject_Call(newraw, data->newargs, NULL); - if (inst) { -#if !defined(SWIG_PYTHON_SLOW_GETSET_THIS) - PyObject **dictptr = _PyObject_GetDictPtr(inst); - if (dictptr != NULL) { - PyObject *dict = *dictptr; - if (dict == NULL) { - dict = PyDict_New(); - *dictptr = dict; - PyDict_SetItem(dict, SWIG_This(), swig_this); - } - } -#else - PyObject *key = SWIG_This(); - PyObject_SetAttr(inst, key, swig_this); -#endif - } - } else { -#if PY_VERSION_HEX >= 0x03000000 - inst = ((PyTypeObject*) data->newargs)->tp_new((PyTypeObject*) data->newargs, Py_None, Py_None); - if (inst) { - PyObject_SetAttr(inst, SWIG_This(), swig_this); - Py_TYPE(inst)->tp_flags &= ~Py_TPFLAGS_VALID_VERSION_TAG; - } -#else - PyObject *dict = PyDict_New(); - if (dict) { - PyDict_SetItem(dict, SWIG_This(), swig_this); - inst = PyInstance_NewRaw(data->newargs, dict); - Py_DECREF(dict); - } -#endif - } - return inst; -#else -#if (PY_VERSION_HEX >= 0x02010000) - PyObject *inst = 0; - PyObject *dict = PyDict_New(); - if (dict) { - PyDict_SetItem(dict, SWIG_This(), swig_this); - inst = PyInstance_NewRaw(data->newargs, dict); - Py_DECREF(dict); - } - return (PyObject *) inst; -#else - PyInstanceObject *inst = PyObject_NEW(PyInstanceObject, &PyInstance_Type); - if (inst == NULL) { - return NULL; - } - inst->in_class = (PyClassObject *)data->newargs; - Py_INCREF(inst->in_class); - inst->in_dict = PyDict_New(); - if (inst->in_dict == NULL) { - Py_DECREF(inst); - return NULL; - } -#ifdef Py_TPFLAGS_HAVE_WEAKREFS - inst->in_weakreflist = NULL; -#endif -#ifdef Py_TPFLAGS_GC - PyObject_GC_Init(inst); -#endif - PyDict_SetItem(inst->in_dict, SWIG_This(), swig_this); - return (PyObject *) inst; -#endif -#endif -} - -SWIGRUNTIME void -SWIG_Python_SetSwigThis(PyObject *inst, PyObject *swig_this) -{ - PyObject *dict; -#if (PY_VERSION_HEX >= 0x02020000) && !defined(SWIG_PYTHON_SLOW_GETSET_THIS) - PyObject **dictptr = _PyObject_GetDictPtr(inst); - if (dictptr != NULL) { - dict = *dictptr; - if (dict == NULL) { - dict = PyDict_New(); - *dictptr = dict; - } - PyDict_SetItem(dict, SWIG_This(), swig_this); - return; - } -#endif - dict = PyObject_GetAttrString(inst, (char*)"__dict__"); - PyDict_SetItem(dict, SWIG_This(), swig_this); - Py_DECREF(dict); -} - - -SWIGINTERN PyObject * -SWIG_Python_InitShadowInstance(PyObject *args) { - PyObject *obj[2]; - if (!SWIG_Python_UnpackTuple(args, "swiginit", 2, 2, obj)) { - return NULL; - } else { - SwigPyObject *sthis = SWIG_Python_GetSwigThis(obj[0]); - if (sthis) { - SwigPyObject_append((PyObject*) sthis, obj[1]); - } else { - SWIG_Python_SetSwigThis(obj[0], obj[1]); - } - return SWIG_Py_Void(); - } -} - -/* Create a new pointer object */ - -SWIGRUNTIME PyObject * -SWIG_Python_NewPointerObj(PyObject *self, void *ptr, swig_type_info *type, int flags) { - SwigPyClientData *clientdata; - PyObject * robj; - int own; - - if (!ptr) - return SWIG_Py_Void(); - - clientdata = type ? (SwigPyClientData *)(type->clientdata) : 0; - own = (flags & SWIG_POINTER_OWN) ? SWIG_POINTER_OWN : 0; - if (clientdata && clientdata->pytype) { - SwigPyObject *newobj; - if (flags & SWIG_BUILTIN_TP_INIT) { - newobj = (SwigPyObject*) self; - if (newobj->ptr) { - PyObject *next_self = clientdata->pytype->tp_alloc(clientdata->pytype, 0); - while (newobj->next) - newobj = (SwigPyObject *) newobj->next; - newobj->next = next_self; - newobj = (SwigPyObject *)next_self; -#ifdef SWIGPYTHON_BUILTIN - newobj->dict = 0; -#endif - } - } else { - newobj = PyObject_New(SwigPyObject, clientdata->pytype); -#ifdef SWIGPYTHON_BUILTIN - newobj->dict = 0; -#endif - } - if (newobj) { - newobj->ptr = ptr; - newobj->ty = type; - newobj->own = own; - newobj->next = 0; - return (PyObject*) newobj; - } - return SWIG_Py_Void(); - } - - assert(!(flags & SWIG_BUILTIN_TP_INIT)); - - robj = SwigPyObject_New(ptr, type, own); - if (robj && clientdata && !(flags & SWIG_POINTER_NOSHADOW)) { - PyObject *inst = SWIG_Python_NewShadowInstance(clientdata, robj); - Py_DECREF(robj); - robj = inst; - } - return robj; -} - -/* Create a new packed object */ - -SWIGRUNTIMEINLINE PyObject * -SWIG_Python_NewPackedObj(void *ptr, size_t sz, swig_type_info *type) { - return ptr ? SwigPyPacked_New((void *) ptr, sz, type) : SWIG_Py_Void(); -} - -/* -----------------------------------------------------------------------------* - * Get type list - * -----------------------------------------------------------------------------*/ - -#ifdef SWIG_LINK_RUNTIME -void *SWIG_ReturnGlobalTypeList(void *); -#endif - -SWIGRUNTIME swig_module_info * -SWIG_Python_GetModule(void *SWIGUNUSEDPARM(clientdata)) { - static void *type_pointer = (void *)0; - /* first check if module already created */ - if (!type_pointer) { -#ifdef SWIG_LINK_RUNTIME - type_pointer = SWIG_ReturnGlobalTypeList((void *)0); -#else -# ifdef SWIGPY_USE_CAPSULE - type_pointer = PyCapsule_Import(SWIGPY_CAPSULE_NAME, 0); -# else - type_pointer = PyCObject_Import((char*)"swig_runtime_data" SWIG_RUNTIME_VERSION, - (char*)"type_pointer" SWIG_TYPE_TABLE_NAME); -# endif - if (PyErr_Occurred()) { - PyErr_Clear(); - type_pointer = (void *)0; - } -#endif - } - return (swig_module_info *) type_pointer; -} - -#if PY_MAJOR_VERSION < 2 -/* PyModule_AddObject function was introduced in Python 2.0. The following function - is copied out of Python/modsupport.c in python version 2.3.4 */ -SWIGINTERN int -PyModule_AddObject(PyObject *m, char *name, PyObject *o) -{ - PyObject *dict; - if (!PyModule_Check(m)) { - PyErr_SetString(PyExc_TypeError, "PyModule_AddObject() needs module as first arg"); - return SWIG_ERROR; - } - if (!o) { - PyErr_SetString(PyExc_TypeError, "PyModule_AddObject() needs non-NULL value"); - return SWIG_ERROR; - } - - dict = PyModule_GetDict(m); - if (dict == NULL) { - /* Internal error -- modules must have a dict! */ - PyErr_Format(PyExc_SystemError, "module '%s' has no __dict__", - PyModule_GetName(m)); - return SWIG_ERROR; - } - if (PyDict_SetItemString(dict, name, o)) - return SWIG_ERROR; - Py_DECREF(o); - return SWIG_OK; -} -#endif - -SWIGRUNTIME void -#ifdef SWIGPY_USE_CAPSULE -SWIG_Python_DestroyModule(PyObject *obj) -#else -SWIG_Python_DestroyModule(void *vptr) -#endif -{ -#ifdef SWIGPY_USE_CAPSULE - swig_module_info *swig_module = (swig_module_info *) PyCapsule_GetPointer(obj, SWIGPY_CAPSULE_NAME); -#else - swig_module_info *swig_module = (swig_module_info *) vptr; -#endif - swig_type_info **types = swig_module->types; - size_t i; - for (i =0; i < swig_module->size; ++i) { - swig_type_info *ty = types[i]; - if (ty->owndata) { - SwigPyClientData *data = (SwigPyClientData *) ty->clientdata; - if (data) SwigPyClientData_Del(data); - } - } - Py_DECREF(SWIG_This()); - swig_this = NULL; -} - -SWIGRUNTIME void -SWIG_Python_SetModule(swig_module_info *swig_module) { -#if PY_VERSION_HEX >= 0x03000000 - /* Add a dummy module object into sys.modules */ - PyObject *module = PyImport_AddModule((char*)"swig_runtime_data" SWIG_RUNTIME_VERSION); -#else - static PyMethodDef swig_empty_runtime_method_table[] = { {NULL, NULL, 0, NULL} }; /* Sentinel */ - PyObject *module = Py_InitModule((char*)"swig_runtime_data" SWIG_RUNTIME_VERSION, swig_empty_runtime_method_table); -#endif -#ifdef SWIGPY_USE_CAPSULE - PyObject *pointer = PyCapsule_New((void *) swig_module, SWIGPY_CAPSULE_NAME, SWIG_Python_DestroyModule); - if (pointer && module) { - PyModule_AddObject(module, (char*)"type_pointer_capsule" SWIG_TYPE_TABLE_NAME, pointer); - } else { - Py_XDECREF(pointer); - } -#else - PyObject *pointer = PyCObject_FromVoidPtr((void *) swig_module, SWIG_Python_DestroyModule); - if (pointer && module) { - PyModule_AddObject(module, (char*)"type_pointer" SWIG_TYPE_TABLE_NAME, pointer); - } else { - Py_XDECREF(pointer); - } -#endif -} - -/* The python cached type query */ -SWIGRUNTIME PyObject * -SWIG_Python_TypeCache(void) { - static PyObject *SWIG_STATIC_POINTER(cache) = PyDict_New(); - return cache; -} - -SWIGRUNTIME swig_type_info * -SWIG_Python_TypeQuery(const char *type) -{ - PyObject *cache = SWIG_Python_TypeCache(); - PyObject *key = SWIG_Python_str_FromChar(type); - PyObject *obj = PyDict_GetItem(cache, key); - swig_type_info *descriptor; - if (obj) { -#ifdef SWIGPY_USE_CAPSULE - descriptor = (swig_type_info *) PyCapsule_GetPointer(obj, NULL); -#else - descriptor = (swig_type_info *) PyCObject_AsVoidPtr(obj); -#endif - } else { - swig_module_info *swig_module = SWIG_GetModule(0); - descriptor = SWIG_TypeQueryModule(swig_module, swig_module, type); - if (descriptor) { -#ifdef SWIGPY_USE_CAPSULE - obj = PyCapsule_New((void*) descriptor, NULL, NULL); -#else - obj = PyCObject_FromVoidPtr(descriptor, NULL); -#endif - PyDict_SetItem(cache, key, obj); - Py_DECREF(obj); - } - } - Py_DECREF(key); - return descriptor; -} - -/* - For backward compatibility only -*/ -#define SWIG_POINTER_EXCEPTION 0 -#define SWIG_arg_fail(arg) SWIG_Python_ArgFail(arg) -#define SWIG_MustGetPtr(p, type, argnum, flags) SWIG_Python_MustGetPtr(p, type, argnum, flags) - -SWIGRUNTIME int -SWIG_Python_AddErrMesg(const char* mesg, int infront) -{ - if (PyErr_Occurred()) { - PyObject *type = 0; - PyObject *value = 0; - PyObject *traceback = 0; - PyErr_Fetch(&type, &value, &traceback); - if (value) { - char *tmp; - PyObject *old_str = PyObject_Str(value); - Py_XINCREF(type); - PyErr_Clear(); - if (infront) { - PyErr_Format(type, "%s %s", mesg, tmp = SWIG_Python_str_AsChar(old_str)); - } else { - PyErr_Format(type, "%s %s", tmp = SWIG_Python_str_AsChar(old_str), mesg); - } - SWIG_Python_str_DelForPy3(tmp); - Py_DECREF(old_str); - } - return 1; - } else { - return 0; - } -} - -SWIGRUNTIME int -SWIG_Python_ArgFail(int argnum) -{ - if (PyErr_Occurred()) { - /* add information about failing argument */ - char mesg[256]; - PyOS_snprintf(mesg, sizeof(mesg), "argument number %d:", argnum); - return SWIG_Python_AddErrMesg(mesg, 1); - } else { - return 0; - } -} - -SWIGRUNTIMEINLINE const char * -SwigPyObject_GetDesc(PyObject *self) -{ - SwigPyObject *v = (SwigPyObject *)self; - swig_type_info *ty = v ? v->ty : 0; - return ty ? ty->str : ""; -} - -SWIGRUNTIME void -SWIG_Python_TypeError(const char *type, PyObject *obj) -{ - if (type) { -#if defined(SWIG_COBJECT_TYPES) - if (obj && SwigPyObject_Check(obj)) { - const char *otype = (const char *) SwigPyObject_GetDesc(obj); - if (otype) { - PyErr_Format(PyExc_TypeError, "a '%s' is expected, 'SwigPyObject(%s)' is received", - type, otype); - return; - } - } else -#endif - { - const char *otype = (obj ? obj->ob_type->tp_name : 0); - if (otype) { - PyObject *str = PyObject_Str(obj); - const char *cstr = str ? SWIG_Python_str_AsChar(str) : 0; - if (cstr) { - PyErr_Format(PyExc_TypeError, "a '%s' is expected, '%s(%s)' is received", - type, otype, cstr); - SWIG_Python_str_DelForPy3(cstr); - } else { - PyErr_Format(PyExc_TypeError, "a '%s' is expected, '%s' is received", - type, otype); - } - Py_XDECREF(str); - return; - } - } - PyErr_Format(PyExc_TypeError, "a '%s' is expected", type); - } else { - PyErr_Format(PyExc_TypeError, "unexpected type is received"); - } -} - - -/* Convert a pointer value, signal an exception on a type mismatch */ -SWIGRUNTIME void * -SWIG_Python_MustGetPtr(PyObject *obj, swig_type_info *ty, int SWIGUNUSEDPARM(argnum), int flags) { - void *result; - if (SWIG_Python_ConvertPtr(obj, &result, ty, flags) == -1) { - PyErr_Clear(); -#if SWIG_POINTER_EXCEPTION - if (flags) { - SWIG_Python_TypeError(SWIG_TypePrettyName(ty), obj); - SWIG_Python_ArgFail(argnum); - } -#endif - } - return result; -} - -#ifdef SWIGPYTHON_BUILTIN -SWIGRUNTIME int -SWIG_Python_NonDynamicSetAttr(PyObject *obj, PyObject *name, PyObject *value) { - PyTypeObject *tp = obj->ob_type; - PyObject *descr; - PyObject *encoded_name; - descrsetfunc f; - int res = -1; - -# ifdef Py_USING_UNICODE - if (PyString_Check(name)) { - name = PyUnicode_Decode(PyString_AsString(name), PyString_Size(name), NULL, NULL); - if (!name) - return -1; - } else if (!PyUnicode_Check(name)) -# else - if (!PyString_Check(name)) -# endif - { - PyErr_Format(PyExc_TypeError, "attribute name must be string, not '%.200s'", name->ob_type->tp_name); - return -1; - } else { - Py_INCREF(name); - } - - if (!tp->tp_dict) { - if (PyType_Ready(tp) < 0) - goto done; - } - - descr = _PyType_Lookup(tp, name); - f = NULL; - if (descr != NULL) - f = descr->ob_type->tp_descr_set; - if (!f) { - if (PyString_Check(name)) { - encoded_name = name; - Py_INCREF(name); - } else { - encoded_name = PyUnicode_AsUTF8String(name); - } - PyErr_Format(PyExc_AttributeError, "'%.100s' object has no attribute '%.200s'", tp->tp_name, PyString_AsString(encoded_name)); - Py_DECREF(encoded_name); - } else { - res = f(descr, obj, value); - } - - done: - Py_DECREF(name); - return res; -} -#endif - - -#ifdef __cplusplus -} -#endif - - - -#define SWIG_exception_fail(code, msg) do { SWIG_Error(code, msg); SWIG_fail; } while(0) - -#define SWIG_contract_assert(expr, msg) if (!(expr)) { SWIG_Error(SWIG_RuntimeError, msg); SWIG_fail; } else - - -/* ----------------------------------------------------------------------------- - * director_common.swg - * - * This file contains support for director classes which is common between - * languages. - * ----------------------------------------------------------------------------- */ - -/* - Use -DSWIG_DIRECTOR_STATIC if you prefer to avoid the use of the - 'Swig' namespace. This could be useful for multi-modules projects. -*/ -#ifdef SWIG_DIRECTOR_STATIC -/* Force anonymous (static) namespace */ -#define Swig -#endif -/* ----------------------------------------------------------------------------- - * director.swg - * - * This file contains support for director classes so that Python proxy - * methods can be called from C++. - * ----------------------------------------------------------------------------- */ - -#ifndef SWIG_DIRECTOR_PYTHON_HEADER_ -#define SWIG_DIRECTOR_PYTHON_HEADER_ - -#include -#include -#include -#include -#include - - -/* - Use -DSWIG_PYTHON_DIRECTOR_NO_VTABLE if you don't want to generate a 'virtual - table', and avoid multiple GetAttr calls to retrieve the python - methods. -*/ - -#ifndef SWIG_PYTHON_DIRECTOR_NO_VTABLE -#ifndef SWIG_PYTHON_DIRECTOR_VTABLE -#define SWIG_PYTHON_DIRECTOR_VTABLE -#endif -#endif - - - -/* - Use -DSWIG_DIRECTOR_NO_UEH if you prefer to avoid the use of the - Undefined Exception Handler provided by swig. -*/ -#ifndef SWIG_DIRECTOR_NO_UEH -#ifndef SWIG_DIRECTOR_UEH -#define SWIG_DIRECTOR_UEH -#endif -#endif - - -/* - Use -DSWIG_DIRECTOR_NORTTI if you prefer to avoid the use of the - native C++ RTTI and dynamic_cast<>. But be aware that directors - could stop working when using this option. -*/ -#ifdef SWIG_DIRECTOR_NORTTI -/* - When we don't use the native C++ RTTI, we implement a minimal one - only for Directors. -*/ -# ifndef SWIG_DIRECTOR_RTDIR -# define SWIG_DIRECTOR_RTDIR - -namespace Swig { - class Director; - SWIGINTERN std::map& get_rtdir_map() { - static std::map rtdir_map; - return rtdir_map; - } - - SWIGINTERNINLINE void set_rtdir(void *vptr, Director *rtdir) { - get_rtdir_map()[vptr] = rtdir; - } - - SWIGINTERNINLINE Director *get_rtdir(void *vptr) { - std::map::const_iterator pos = get_rtdir_map().find(vptr); - Director *rtdir = (pos != get_rtdir_map().end()) ? pos->second : 0; - return rtdir; - } -} -# endif /* SWIG_DIRECTOR_RTDIR */ - -# define SWIG_DIRECTOR_CAST(ARG) Swig::get_rtdir(static_cast(ARG)) -# define SWIG_DIRECTOR_RGTR(ARG1, ARG2) Swig::set_rtdir(static_cast(ARG1), ARG2) - -#else - -# define SWIG_DIRECTOR_CAST(ARG) dynamic_cast(ARG) -# define SWIG_DIRECTOR_RGTR(ARG1, ARG2) - -#endif /* SWIG_DIRECTOR_NORTTI */ - -extern "C" { - struct swig_type_info; -} - -namespace Swig { - - /* memory handler */ - struct GCItem { - virtual ~GCItem() {} - - virtual int get_own() const { - return 0; - } - }; - - struct GCItem_var { - GCItem_var(GCItem *item = 0) : _item(item) { - } - - GCItem_var& operator=(GCItem *item) { - GCItem *tmp = _item; - _item = item; - delete tmp; - return *this; - } - - ~GCItem_var() { - delete _item; - } - - GCItem * operator->() const { - return _item; - } - - private: - GCItem *_item; - }; - - struct GCItem_Object : GCItem { - GCItem_Object(int own) : _own(own) { - } - - virtual ~GCItem_Object() { - } - - int get_own() const { - return _own; - } - - private: - int _own; - }; - - template - struct GCItem_T : GCItem { - GCItem_T(Type *ptr) : _ptr(ptr) { - } - - virtual ~GCItem_T() { - delete _ptr; - } - - private: - Type *_ptr; - }; - - template - struct GCArray_T : GCItem { - GCArray_T(Type *ptr) : _ptr(ptr) { - } - - virtual ~GCArray_T() { - delete[] _ptr; - } - - private: - Type *_ptr; - }; - - /* base class for director exceptions */ - class DirectorException : public std::exception { - protected: - std::string swig_msg; - public: - DirectorException(PyObject *error, const char *hdr ="", const char *msg ="") : swig_msg(hdr) { - SWIG_PYTHON_THREAD_BEGIN_BLOCK; - if (msg[0]) { - swig_msg += " "; - swig_msg += msg; - } - if (!PyErr_Occurred()) { - PyErr_SetString(error, what()); - } - SWIG_PYTHON_THREAD_END_BLOCK; - } - - virtual ~DirectorException() throw() { - } - - /* Deprecated, use what() instead */ - const char *getMessage() const { - return what(); - } - - const char *what() const throw() { - return swig_msg.c_str(); - } - - static void raise(PyObject *error, const char *msg) { - throw DirectorException(error, msg); - } - - static void raise(const char *msg) { - raise(PyExc_RuntimeError, msg); - } - }; - - /* unknown exception handler */ - class UnknownExceptionHandler { -#ifdef SWIG_DIRECTOR_UEH - static void handler() { - try { - throw; - } catch (DirectorException& e) { - std::cerr << "SWIG Director exception caught:" << std::endl - << e.what() << std::endl; - } catch (std::exception& e) { - std::cerr << "std::exception caught: "<< e.what() << std::endl; - } catch (...) { - std::cerr << "Unknown exception caught." << std::endl; - } - - std::cerr << std::endl - << "Python interpreter traceback:" << std::endl; - PyErr_Print(); - std::cerr << std::endl; - - std::cerr << "This exception was caught by the SWIG unexpected exception handler." << std::endl - << "Try using %feature(\"director:except\") to avoid reaching this point." << std::endl - << std::endl - << "Exception is being re-thrown, program will likely abort/terminate." << std::endl; - throw; - } - - public: - - std::unexpected_handler old; - UnknownExceptionHandler(std::unexpected_handler nh = handler) { - old = std::set_unexpected(nh); - } - - ~UnknownExceptionHandler() { - std::set_unexpected(old); - } -#endif - }; - - /* type mismatch in the return value from a python method call */ - class DirectorTypeMismatchException : public DirectorException { - public: - DirectorTypeMismatchException(PyObject *error, const char *msg="") - : DirectorException(error, "SWIG director type mismatch", msg) { - } - - DirectorTypeMismatchException(const char *msg="") - : DirectorException(PyExc_TypeError, "SWIG director type mismatch", msg) { - } - - static void raise(PyObject *error, const char *msg) { - throw DirectorTypeMismatchException(error, msg); - } - - static void raise(const char *msg) { - throw DirectorTypeMismatchException(msg); - } - }; - - /* any python exception that occurs during a director method call */ - class DirectorMethodException : public DirectorException { - public: - DirectorMethodException(const char *msg = "") - : DirectorException(PyExc_RuntimeError, "SWIG director method error.", msg) { - } - - static void raise(const char *msg) { - throw DirectorMethodException(msg); - } - }; - - /* attempt to call a pure virtual method via a director method */ - class DirectorPureVirtualException : public DirectorException { - public: - DirectorPureVirtualException(const char *msg = "") - : DirectorException(PyExc_RuntimeError, "SWIG director pure virtual method called", msg) { - } - - static void raise(const char *msg) { - throw DirectorPureVirtualException(msg); - } - }; - - -#if defined(SWIG_PYTHON_THREADS) -/* __THREAD__ is the old macro to activate some thread support */ -# if !defined(__THREAD__) -# define __THREAD__ 1 -# endif -#endif - -#ifdef __THREAD__ -# include "pythread.h" - class Guard { - PyThread_type_lock &mutex_; - - public: - Guard(PyThread_type_lock & mutex) : mutex_(mutex) { - PyThread_acquire_lock(mutex_, WAIT_LOCK); - } - - ~Guard() { - PyThread_release_lock(mutex_); - } - }; -# define SWIG_GUARD(mutex) Guard _guard(mutex) -#else -# define SWIG_GUARD(mutex) -#endif - - /* director base class */ - class Director { - private: - /* pointer to the wrapped python object */ - PyObject *swig_self; - /* flag indicating whether the object is owned by python or c++ */ - mutable bool swig_disown_flag; - - /* decrement the reference count of the wrapped python object */ - void swig_decref() const { - if (swig_disown_flag) { - SWIG_PYTHON_THREAD_BEGIN_BLOCK; - Py_DECREF(swig_self); - SWIG_PYTHON_THREAD_END_BLOCK; - } - } - - public: - /* wrap a python object. */ - Director(PyObject *self) : swig_self(self), swig_disown_flag(false) { - } - - /* discard our reference at destruction */ - virtual ~Director() { - swig_decref(); - } - - /* return a pointer to the wrapped python object */ - PyObject *swig_get_self() const { - return swig_self; - } - - /* acquire ownership of the wrapped python object (the sense of "disown" is from python) */ - void swig_disown() const { - if (!swig_disown_flag) { - swig_disown_flag=true; - swig_incref(); - } - } - - /* increase the reference count of the wrapped python object */ - void swig_incref() const { - if (swig_disown_flag) { - Py_INCREF(swig_self); - } - } - - /* methods to implement pseudo protected director members */ - virtual bool swig_get_inner(const char * /* swig_protected_method_name */) const { - return true; - } - - virtual void swig_set_inner(const char * /* swig_protected_method_name */, bool /* swig_val */) const { - } - - /* ownership management */ - private: - typedef std::map swig_ownership_map; - mutable swig_ownership_map swig_owner; -#ifdef __THREAD__ - static PyThread_type_lock swig_mutex_own; -#endif - - public: - template - void swig_acquire_ownership_array(Type *vptr) const { - if (vptr) { - SWIG_GUARD(swig_mutex_own); - swig_owner[vptr] = new GCArray_T(vptr); - } - } - - template - void swig_acquire_ownership(Type *vptr) const { - if (vptr) { - SWIG_GUARD(swig_mutex_own); - swig_owner[vptr] = new GCItem_T(vptr); - } - } - - void swig_acquire_ownership_obj(void *vptr, int own) const { - if (vptr && own) { - SWIG_GUARD(swig_mutex_own); - swig_owner[vptr] = new GCItem_Object(own); - } - } - - int swig_release_ownership(void *vptr) const { - int own = 0; - if (vptr) { - SWIG_GUARD(swig_mutex_own); - swig_ownership_map::iterator iter = swig_owner.find(vptr); - if (iter != swig_owner.end()) { - own = iter->second->get_own(); - swig_owner.erase(iter); - } - } - return own; - } - - template - static PyObject *swig_pyobj_disown(PyObject *pyobj, PyObject *SWIGUNUSEDPARM(args)) { - SwigPyObject *sobj = (SwigPyObject *)pyobj; - sobj->own = 0; - Director *d = SWIG_DIRECTOR_CAST(reinterpret_cast(sobj->ptr)); - if (d) - d->swig_disown(); - return PyWeakref_NewProxy(pyobj, NULL); - } - }; - -#ifdef __THREAD__ - PyThread_type_lock Director::swig_mutex_own = PyThread_allocate_lock(); -#endif -} - -#endif - -/* -------- TYPES TABLE (BEGIN) -------- */ - -#define SWIGTYPE_p__kclvm_plugin_AppContextBase swig_types[0] -#define SWIGTYPE_p_char swig_types[1] -#define SWIGTYPE_p_int swig_types[2] -#define SWIGTYPE_p_long_long swig_types[3] -#define SWIGTYPE_p_short swig_types[4] -#define SWIGTYPE_p_signed_char swig_types[5] -#define SWIGTYPE_p_unsigned_char swig_types[6] -#define SWIGTYPE_p_unsigned_int swig_types[7] -#define SWIGTYPE_p_unsigned_long_long swig_types[8] -#define SWIGTYPE_p_unsigned_short swig_types[9] -static swig_type_info *swig_types[11]; -static swig_module_info swig_module = {swig_types, 10, 0, 0, 0, 0}; -#define SWIG_TypeQuery(name) SWIG_TypeQueryModule(&swig_module, &swig_module, name) -#define SWIG_MangledTypeQuery(name) SWIG_MangledTypeQueryModule(&swig_module, &swig_module, name) - -/* -------- TYPES TABLE (END) -------- */ - -#if (PY_VERSION_HEX <= 0x02000000) -# if !defined(SWIG_PYTHON_CLASSIC) -# error "This python version requires swig to be run with the '-classic' option" -# endif -#endif - -/*----------------------------------------------- - @(target):= _kclvm_plugin.so - ------------------------------------------------*/ -#if PY_VERSION_HEX >= 0x03000000 -# define SWIG_init PyInit__kclvm_plugin - -#else -# define SWIG_init init_kclvm_plugin - -#endif -#define SWIG_name "_kclvm_plugin" - -#define SWIGVERSION 0x030012 -#define SWIG_VERSION SWIGVERSION - - -#define SWIG_as_voidptr(a) const_cast< void * >(static_cast< const void * >(a)) -#define SWIG_as_voidptrptr(a) ((void)SWIG_as_voidptr(*a),reinterpret_cast< void** >(a)) - - -#include - - -namespace swig { - class SwigPtr_PyObject { - protected: - PyObject *_obj; - - public: - SwigPtr_PyObject() :_obj(0) - { - } - - SwigPtr_PyObject(const SwigPtr_PyObject& item) : _obj(item._obj) - { - SWIG_PYTHON_THREAD_BEGIN_BLOCK; - Py_XINCREF(_obj); - SWIG_PYTHON_THREAD_END_BLOCK; - } - - SwigPtr_PyObject(PyObject *obj, bool initial_ref = true) :_obj(obj) - { - if (initial_ref) { - SWIG_PYTHON_THREAD_BEGIN_BLOCK; - Py_XINCREF(_obj); - SWIG_PYTHON_THREAD_END_BLOCK; - } - } - - SwigPtr_PyObject & operator=(const SwigPtr_PyObject& item) - { - SWIG_PYTHON_THREAD_BEGIN_BLOCK; - Py_XINCREF(item._obj); - Py_XDECREF(_obj); - _obj = item._obj; - SWIG_PYTHON_THREAD_END_BLOCK; - return *this; - } - - ~SwigPtr_PyObject() - { - SWIG_PYTHON_THREAD_BEGIN_BLOCK; - Py_XDECREF(_obj); - SWIG_PYTHON_THREAD_END_BLOCK; - } - - operator PyObject *() const - { - return _obj; - } - - PyObject *operator->() const - { - return _obj; - } - }; -} - - -namespace swig { - struct SwigVar_PyObject : SwigPtr_PyObject { - SwigVar_PyObject(PyObject* obj = 0) : SwigPtr_PyObject(obj, false) { } - - SwigVar_PyObject & operator = (PyObject* obj) - { - Py_XDECREF(_obj); - _obj = obj; - return *this; - } - }; -} - - -#define SWIG_FILE_WITH_INIT -#include "kclvm_plugin.h" - - -#include // Use the C99 official header - - -#include - - -SWIGINTERN swig_type_info* -SWIG_pchar_descriptor(void) -{ - static int init = 0; - static swig_type_info* info = 0; - if (!init) { - info = SWIG_TypeQuery("_p_char"); - init = 1; - } - return info; -} - - -SWIGINTERN int -SWIG_AsCharPtrAndSize(PyObject *obj, char** cptr, size_t* psize, int *alloc) -{ -#if PY_VERSION_HEX>=0x03000000 -#if defined(SWIG_PYTHON_STRICT_BYTE_CHAR) - if (PyBytes_Check(obj)) -#else - if (PyUnicode_Check(obj)) -#endif -#else - if (PyString_Check(obj)) -#endif - { - char *cstr; Py_ssize_t len; -#if PY_VERSION_HEX>=0x03000000 -#if !defined(SWIG_PYTHON_STRICT_BYTE_CHAR) - if (!alloc && cptr) { - /* We can't allow converting without allocation, since the internal - representation of string in Python 3 is UCS-2/UCS-4 but we require - a UTF-8 representation. - TODO(bhy) More detailed explanation */ - return SWIG_RuntimeError; - } - obj = PyUnicode_AsUTF8String(obj); - if(alloc) *alloc = SWIG_NEWOBJ; -#endif - PyBytes_AsStringAndSize(obj, &cstr, &len); -#else - PyString_AsStringAndSize(obj, &cstr, &len); -#endif - if (cptr) { - if (alloc) { - /* - In python the user should not be able to modify the inner - string representation. To warranty that, if you define - SWIG_PYTHON_SAFE_CSTRINGS, a new/copy of the python string - buffer is always returned. - - The default behavior is just to return the pointer value, - so, be careful. - */ -#if defined(SWIG_PYTHON_SAFE_CSTRINGS) - if (*alloc != SWIG_OLDOBJ) -#else - if (*alloc == SWIG_NEWOBJ) -#endif - { - *cptr = reinterpret_cast< char* >(memcpy(new char[len + 1], cstr, sizeof(char)*(len + 1))); - *alloc = SWIG_NEWOBJ; - } else { - *cptr = cstr; - *alloc = SWIG_OLDOBJ; - } - } else { -#if PY_VERSION_HEX>=0x03000000 -#if defined(SWIG_PYTHON_STRICT_BYTE_CHAR) - *cptr = PyBytes_AsString(obj); -#else - assert(0); /* Should never reach here with Unicode strings in Python 3 */ -#endif -#else - *cptr = SWIG_Python_str_AsChar(obj); -#endif - } - } - if (psize) *psize = len + 1; -#if PY_VERSION_HEX>=0x03000000 && !defined(SWIG_PYTHON_STRICT_BYTE_CHAR) - Py_XDECREF(obj); -#endif - return SWIG_OK; - } else { -#if defined(SWIG_PYTHON_2_UNICODE) -#if defined(SWIG_PYTHON_STRICT_BYTE_CHAR) -#error "Cannot use both SWIG_PYTHON_2_UNICODE and SWIG_PYTHON_STRICT_BYTE_CHAR at once" -#endif -#if PY_VERSION_HEX<0x03000000 - if (PyUnicode_Check(obj)) { - char *cstr; Py_ssize_t len; - if (!alloc && cptr) { - return SWIG_RuntimeError; - } - obj = PyUnicode_AsUTF8String(obj); - if (PyString_AsStringAndSize(obj, &cstr, &len) != -1) { - if (cptr) { - if (alloc) *alloc = SWIG_NEWOBJ; - *cptr = reinterpret_cast< char* >(memcpy(new char[len + 1], cstr, sizeof(char)*(len + 1))); - } - if (psize) *psize = len + 1; - - Py_XDECREF(obj); - return SWIG_OK; - } else { - Py_XDECREF(obj); - } - } -#endif -#endif - - swig_type_info* pchar_descriptor = SWIG_pchar_descriptor(); - if (pchar_descriptor) { - void* vptr = 0; - if (SWIG_ConvertPtr(obj, &vptr, pchar_descriptor, 0) == SWIG_OK) { - if (cptr) *cptr = (char *) vptr; - if (psize) *psize = vptr ? (strlen((char *)vptr) + 1) : 0; - if (alloc) *alloc = SWIG_OLDOBJ; - return SWIG_OK; - } - } - } - return SWIG_TypeError; -} - - -SWIGINTERN int -SWIG_AsPtr_std_string (PyObject * obj, std::string **val) -{ - char* buf = 0 ; size_t size = 0; int alloc = SWIG_OLDOBJ; - if (SWIG_IsOK((SWIG_AsCharPtrAndSize(obj, &buf, &size, &alloc)))) { - if (buf) { - if (val) *val = new std::string(buf, size - 1); - if (alloc == SWIG_NEWOBJ) delete[] buf; - return SWIG_NEWOBJ; - } else { - if (val) *val = 0; - return SWIG_OLDOBJ; - } - } else { - static int init = 0; - static swig_type_info* descriptor = 0; - if (!init) { - descriptor = SWIG_TypeQuery("std::string" " *"); - init = 1; - } - if (descriptor) { - std::string *vptr; - int res = SWIG_ConvertPtr(obj, (void**)&vptr, descriptor, 0); - if (SWIG_IsOK(res) && val) *val = vptr; - return res; - } - } - return SWIG_ERROR; -} - - -SWIGINTERNINLINE PyObject * -SWIG_FromCharPtrAndSize(const char* carray, size_t size) -{ - if (carray) { - if (size > INT_MAX) { - swig_type_info* pchar_descriptor = SWIG_pchar_descriptor(); - return pchar_descriptor ? - SWIG_InternalNewPointerObj(const_cast< char * >(carray), pchar_descriptor, 0) : SWIG_Py_Void(); - } else { -#if PY_VERSION_HEX >= 0x03000000 -#if defined(SWIG_PYTHON_STRICT_BYTE_CHAR) - return PyBytes_FromStringAndSize(carray, static_cast< Py_ssize_t >(size)); -#else -#if PY_VERSION_HEX >= 0x03010000 - return PyUnicode_DecodeUTF8(carray, static_cast< Py_ssize_t >(size), "surrogateescape"); -#else - return PyUnicode_FromStringAndSize(carray, static_cast< Py_ssize_t >(size)); -#endif -#endif -#else - return PyString_FromStringAndSize(carray, static_cast< Py_ssize_t >(size)); -#endif - } - } else { - return SWIG_Py_Void(); - } -} - - -SWIGINTERNINLINE PyObject * -SWIG_From_std_string (const std::string& s) -{ - return SWIG_FromCharPtrAndSize(s.data(), s.size()); -} - - -SWIGINTERN int -SWIG_AsVal_double (PyObject *obj, double *val) -{ - int res = SWIG_TypeError; - if (PyFloat_Check(obj)) { - if (val) *val = PyFloat_AsDouble(obj); - return SWIG_OK; -#if PY_VERSION_HEX < 0x03000000 - } else if (PyInt_Check(obj)) { - if (val) *val = (double) PyInt_AsLong(obj); - return SWIG_OK; -#endif - } else if (PyLong_Check(obj)) { - double v = PyLong_AsDouble(obj); - if (!PyErr_Occurred()) { - if (val) *val = v; - return SWIG_OK; - } else { - PyErr_Clear(); - } - } -#ifdef SWIG_PYTHON_CAST_MODE - { - int dispatch = 0; - double d = PyFloat_AsDouble(obj); - if (!PyErr_Occurred()) { - if (val) *val = d; - return SWIG_AddCast(SWIG_OK); - } else { - PyErr_Clear(); - } - if (!dispatch) { - long v = PyLong_AsLong(obj); - if (!PyErr_Occurred()) { - if (val) *val = v; - return SWIG_AddCast(SWIG_AddCast(SWIG_OK)); - } else { - PyErr_Clear(); - } - } - } -#endif - return res; -} - - -#include - - -#include - - -SWIGINTERNINLINE int -SWIG_CanCastAsInteger(double *d, double min, double max) { - double x = *d; - if ((min <= x && x <= max)) { - double fx = floor(x); - double cx = ceil(x); - double rd = ((x - fx) < 0.5) ? fx : cx; /* simple rint */ - if ((errno == EDOM) || (errno == ERANGE)) { - errno = 0; - } else { - double summ, reps, diff; - if (rd < x) { - diff = x - rd; - } else if (rd > x) { - diff = rd - x; - } else { - return 1; - } - summ = rd + x; - reps = diff/summ; - if (reps < 8*DBL_EPSILON) { - *d = rd; - return 1; - } - } - } - return 0; -} - - -SWIGINTERN int -SWIG_AsVal_unsigned_SS_long (PyObject *obj, unsigned long *val) -{ -#if PY_VERSION_HEX < 0x03000000 - if (PyInt_Check(obj)) { - long v = PyInt_AsLong(obj); - if (v >= 0) { - if (val) *val = v; - return SWIG_OK; - } else { - return SWIG_OverflowError; - } - } else -#endif - if (PyLong_Check(obj)) { - unsigned long v = PyLong_AsUnsignedLong(obj); - if (!PyErr_Occurred()) { - if (val) *val = v; - return SWIG_OK; - } else { - PyErr_Clear(); - return SWIG_OverflowError; - } - } -#ifdef SWIG_PYTHON_CAST_MODE - { - int dispatch = 0; - unsigned long v = PyLong_AsUnsignedLong(obj); - if (!PyErr_Occurred()) { - if (val) *val = v; - return SWIG_AddCast(SWIG_OK); - } else { - PyErr_Clear(); - } - if (!dispatch) { - double d; - int res = SWIG_AddCast(SWIG_AsVal_double (obj,&d)); - if (SWIG_IsOK(res) && SWIG_CanCastAsInteger(&d, 0, ULONG_MAX)) { - if (val) *val = (unsigned long)(d); - return res; - } - } - } -#endif - return SWIG_TypeError; -} - - -#include -#if !defined(SWIG_NO_LLONG_MAX) -# if !defined(LLONG_MAX) && defined(__GNUC__) && defined (__LONG_LONG_MAX__) -# define LLONG_MAX __LONG_LONG_MAX__ -# define LLONG_MIN (-LLONG_MAX - 1LL) -# define ULLONG_MAX (LLONG_MAX * 2ULL + 1ULL) -# endif -#endif - - -#if defined(LLONG_MAX) && !defined(SWIG_LONG_LONG_AVAILABLE) -# define SWIG_LONG_LONG_AVAILABLE -#endif - - -#ifdef SWIG_LONG_LONG_AVAILABLE -SWIGINTERN int -SWIG_AsVal_unsigned_SS_long_SS_long (PyObject *obj, unsigned long long *val) -{ - int res = SWIG_TypeError; - if (PyLong_Check(obj)) { - unsigned long long v = PyLong_AsUnsignedLongLong(obj); - if (!PyErr_Occurred()) { - if (val) *val = v; - return SWIG_OK; - } else { - PyErr_Clear(); - res = SWIG_OverflowError; - } - } else { - unsigned long v; - res = SWIG_AsVal_unsigned_SS_long (obj,&v); - if (SWIG_IsOK(res)) { - if (val) *val = v; - return res; - } - } -#ifdef SWIG_PYTHON_CAST_MODE - { - const double mant_max = 1LL << DBL_MANT_DIG; - double d; - res = SWIG_AsVal_double (obj,&d); - if (SWIG_IsOK(res) && !SWIG_CanCastAsInteger(&d, 0, mant_max)) - return SWIG_OverflowError; - if (SWIG_IsOK(res) && SWIG_CanCastAsInteger(&d, 0, mant_max)) { - if (val) *val = (unsigned long long)(d); - return SWIG_AddCast(res); - } - res = SWIG_TypeError; - } -#endif - return res; -} -#endif - - -SWIGINTERN int -SWIG_AsVal_long (PyObject *obj, long* val) -{ -#if PY_VERSION_HEX < 0x03000000 - if (PyInt_Check(obj)) { - if (val) *val = PyInt_AsLong(obj); - return SWIG_OK; - } else -#endif - if (PyLong_Check(obj)) { - long v = PyLong_AsLong(obj); - if (!PyErr_Occurred()) { - if (val) *val = v; - return SWIG_OK; - } else { - PyErr_Clear(); - return SWIG_OverflowError; - } - } -#ifdef SWIG_PYTHON_CAST_MODE - { - int dispatch = 0; - long v = PyInt_AsLong(obj); - if (!PyErr_Occurred()) { - if (val) *val = v; - return SWIG_AddCast(SWIG_OK); - } else { - PyErr_Clear(); - } - if (!dispatch) { - double d; - int res = SWIG_AddCast(SWIG_AsVal_double (obj,&d)); - if (SWIG_IsOK(res) && SWIG_CanCastAsInteger(&d, LONG_MIN, LONG_MAX)) { - if (val) *val = (long)(d); - return res; - } - } - } -#endif - return SWIG_TypeError; -} - - -SWIGINTERN int -SWIG_AsVal_int (PyObject * obj, int *val) -{ - long v; - int res = SWIG_AsVal_long (obj, &v); - if (SWIG_IsOK(res)) { - if ((v < INT_MIN || v > INT_MAX)) { - return SWIG_OverflowError; - } else { - if (val) *val = static_cast< int >(v); - } - } - return res; -} - - -#ifdef SWIG_LONG_LONG_AVAILABLE -SWIGINTERNINLINE PyObject* -SWIG_From_unsigned_SS_long_SS_long (unsigned long long value) -{ - return (value > LONG_MAX) ? - PyLong_FromUnsignedLongLong(value) : PyInt_FromLong(static_cast< long >(value)); -} -#endif - - - -/* --------------------------------------------------- - * C++ director class methods - * --------------------------------------------------- */ - -#include "kclvm_plugin_wrap.h" - -SwigDirector__kclvm_plugin_AppContextBase::SwigDirector__kclvm_plugin_AppContextBase(PyObject *self, uint64_t rust_invoke_json_ptr): _kclvm_plugin_AppContextBase(rust_invoke_json_ptr), Swig::Director(self) { - SWIG_DIRECTOR_RGTR((_kclvm_plugin_AppContextBase *)this, this); -} - - - - -SwigDirector__kclvm_plugin_AppContextBase::~SwigDirector__kclvm_plugin_AppContextBase() { -} - -std::string SwigDirector__kclvm_plugin_AppContextBase::_call_py_method(std::string const &name, std::string const &args_json, std::string const &kwargs_json) { - std::string c_result; - swig::SwigVar_PyObject obj0; - obj0 = SWIG_From_std_string(static_cast< std::string >(name)); - swig::SwigVar_PyObject obj1; - obj1 = SWIG_From_std_string(static_cast< std::string >(args_json)); - swig::SwigVar_PyObject obj2; - obj2 = SWIG_From_std_string(static_cast< std::string >(kwargs_json)); - if (!swig_get_self()) { - Swig::DirectorException::raise("'self' uninitialized, maybe you forgot to call _kclvm_plugin_AppContextBase.__init__."); - } -#if defined(SWIG_PYTHON_DIRECTOR_VTABLE) - const size_t swig_method_index = 0; - const char *const swig_method_name = "_call_py_method"; - PyObject *method = swig_get_method(swig_method_index, swig_method_name); - swig::SwigVar_PyObject result = PyObject_CallFunction(method, (char *)"(OOO)" ,(PyObject *)obj0,(PyObject *)obj1,(PyObject *)obj2); -#else - swig::SwigVar_PyObject result = PyObject_CallMethod(swig_get_self(), (char *)"_call_py_method", (char *)"(OOO)" ,(PyObject *)obj0,(PyObject *)obj1,(PyObject *)obj2); -#endif - if (!result) { - PyObject *error = PyErr_Occurred(); - if (error) { - Swig::DirectorMethodException::raise("Error detected when calling '_kclvm_plugin_AppContextBase._call_py_method'"); - } - } - std::string *swig_optr = 0; - int swig_ores = SWIG_AsPtr_std_string(result, &swig_optr); - if (!SWIG_IsOK(swig_ores) || !swig_optr) { - Swig::DirectorTypeMismatchException::raise(SWIG_ErrorType(SWIG_ArgError((swig_optr ? swig_ores : SWIG_TypeError))), "in output value of type '""std::string""'"); - } - c_result = *swig_optr; - if (SWIG_IsNewObj(swig_ores)) delete swig_optr; - return (std::string) c_result; -} - - -#ifdef __cplusplus -extern "C" { -#endif -SWIGINTERN PyObject *_wrap_new__kclvm_plugin_AppContextBase(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { - PyObject *resultobj = 0; - PyObject *arg1 = (PyObject *) 0 ; - uint64_t arg2 ; - unsigned long long val2 ; - int ecode2 = 0 ; - PyObject * obj0 = 0 ; - PyObject * obj1 = 0 ; - _kclvm_plugin_AppContextBase *result = 0 ; - - if (!PyArg_ParseTuple(args,(char *)"OO:new__kclvm_plugin_AppContextBase",&obj0,&obj1)) SWIG_fail; - arg1 = obj0; - ecode2 = SWIG_AsVal_unsigned_SS_long_SS_long(obj1, &val2); - if (!SWIG_IsOK(ecode2)) { - SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "new__kclvm_plugin_AppContextBase" "', argument " "2"" of type '" "uint64_t""'"); - } - arg2 = static_cast< uint64_t >(val2); - if ( arg1 != Py_None ) { - /* subclassed */ - result = (_kclvm_plugin_AppContextBase *)new SwigDirector__kclvm_plugin_AppContextBase(arg1,arg2); - } else { - result = (_kclvm_plugin_AppContextBase *)new _kclvm_plugin_AppContextBase(arg2); - } - - resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p__kclvm_plugin_AppContextBase, SWIG_POINTER_NEW | 0 ); - return resultobj; -fail: - return NULL; -} - - -SWIGINTERN PyObject *_wrap_delete__kclvm_plugin_AppContextBase(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { - PyObject *resultobj = 0; - _kclvm_plugin_AppContextBase *arg1 = (_kclvm_plugin_AppContextBase *) 0 ; - void *argp1 = 0 ; - int res1 = 0 ; - PyObject * obj0 = 0 ; - - if (!PyArg_ParseTuple(args,(char *)"O:delete__kclvm_plugin_AppContextBase",&obj0)) SWIG_fail; - res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p__kclvm_plugin_AppContextBase, SWIG_POINTER_DISOWN | 0 ); - if (!SWIG_IsOK(res1)) { - SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "delete__kclvm_plugin_AppContextBase" "', argument " "1"" of type '" "_kclvm_plugin_AppContextBase *""'"); - } - arg1 = reinterpret_cast< _kclvm_plugin_AppContextBase * >(argp1); - delete arg1; - resultobj = SWIG_Py_Void(); - return resultobj; -fail: - return NULL; -} - - -SWIGINTERN PyObject *_wrap__kclvm_plugin_AppContextBase__clear_options(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { - PyObject *resultobj = 0; - _kclvm_plugin_AppContextBase *arg1 = (_kclvm_plugin_AppContextBase *) 0 ; - void *argp1 = 0 ; - int res1 = 0 ; - PyObject * obj0 = 0 ; - - if (!PyArg_ParseTuple(args,(char *)"O:_kclvm_plugin_AppContextBase__clear_options",&obj0)) SWIG_fail; - res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p__kclvm_plugin_AppContextBase, 0 | 0 ); - if (!SWIG_IsOK(res1)) { - SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "_kclvm_plugin_AppContextBase__clear_options" "', argument " "1"" of type '" "_kclvm_plugin_AppContextBase *""'"); - } - arg1 = reinterpret_cast< _kclvm_plugin_AppContextBase * >(argp1); - (arg1)->_clear_options(); - resultobj = SWIG_Py_Void(); - return resultobj; -fail: - return NULL; -} - - -SWIGINTERN PyObject *_wrap__kclvm_plugin_AppContextBase__add_option(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { - PyObject *resultobj = 0; - _kclvm_plugin_AppContextBase *arg1 = (_kclvm_plugin_AppContextBase *) 0 ; - std::string *arg2 = 0 ; - std::string *arg3 = 0 ; - void *argp1 = 0 ; - int res1 = 0 ; - int res2 = SWIG_OLDOBJ ; - int res3 = SWIG_OLDOBJ ; - PyObject * obj0 = 0 ; - PyObject * obj1 = 0 ; - PyObject * obj2 = 0 ; - - if (!PyArg_ParseTuple(args,(char *)"OOO:_kclvm_plugin_AppContextBase__add_option",&obj0,&obj1,&obj2)) SWIG_fail; - res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p__kclvm_plugin_AppContextBase, 0 | 0 ); - if (!SWIG_IsOK(res1)) { - SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "_kclvm_plugin_AppContextBase__add_option" "', argument " "1"" of type '" "_kclvm_plugin_AppContextBase *""'"); - } - arg1 = reinterpret_cast< _kclvm_plugin_AppContextBase * >(argp1); - { - std::string *ptr = (std::string *)0; - res2 = SWIG_AsPtr_std_string(obj1, &ptr); - if (!SWIG_IsOK(res2)) { - SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "_kclvm_plugin_AppContextBase__add_option" "', argument " "2"" of type '" "std::string const &""'"); - } - if (!ptr) { - SWIG_exception_fail(SWIG_ValueError, "invalid null reference " "in method '" "_kclvm_plugin_AppContextBase__add_option" "', argument " "2"" of type '" "std::string const &""'"); - } - arg2 = ptr; - } - { - std::string *ptr = (std::string *)0; - res3 = SWIG_AsPtr_std_string(obj2, &ptr); - if (!SWIG_IsOK(res3)) { - SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "_kclvm_plugin_AppContextBase__add_option" "', argument " "3"" of type '" "std::string const &""'"); - } - if (!ptr) { - SWIG_exception_fail(SWIG_ValueError, "invalid null reference " "in method '" "_kclvm_plugin_AppContextBase__add_option" "', argument " "3"" of type '" "std::string const &""'"); - } - arg3 = ptr; - } - (arg1)->_add_option((std::string const &)*arg2,(std::string const &)*arg3); - resultobj = SWIG_Py_Void(); - if (SWIG_IsNewObj(res2)) delete arg2; - if (SWIG_IsNewObj(res3)) delete arg3; - return resultobj; -fail: - if (SWIG_IsNewObj(res2)) delete arg2; - if (SWIG_IsNewObj(res3)) delete arg3; - return NULL; -} - - -SWIGINTERN PyObject *_wrap__kclvm_plugin_AppContextBase__run_app(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { - PyObject *resultobj = 0; - _kclvm_plugin_AppContextBase *arg1 = (_kclvm_plugin_AppContextBase *) 0 ; - uint64_t arg2 ; - uint64_t arg3 ; - int32_t arg4 ; - int32_t arg5 ; - int32_t arg6 ; - int32_t arg7 ; - int32_t arg8 ; - int32_t arg9 ; - void *argp1 = 0 ; - int res1 = 0 ; - unsigned long long val2 ; - int ecode2 = 0 ; - unsigned long long val3 ; - int ecode3 = 0 ; - int val4 ; - int ecode4 = 0 ; - int val5 ; - int ecode5 = 0 ; - int val6 ; - int ecode6 = 0 ; - int val7 ; - int ecode7 = 0 ; - int val8 ; - int ecode8 = 0 ; - int val9 ; - int ecode9 = 0 ; - PyObject * obj0 = 0 ; - PyObject * obj1 = 0 ; - PyObject * obj2 = 0 ; - PyObject * obj3 = 0 ; - PyObject * obj4 = 0 ; - PyObject * obj5 = 0 ; - PyObject * obj6 = 0 ; - PyObject * obj7 = 0 ; - PyObject * obj8 = 0 ; - std::string result; - - if (!PyArg_ParseTuple(args,(char *)"OOOOOOOOO:_kclvm_plugin_AppContextBase__run_app",&obj0,&obj1,&obj2,&obj3,&obj4,&obj5,&obj6,&obj7,&obj8)) SWIG_fail; - res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p__kclvm_plugin_AppContextBase, 0 | 0 ); - if (!SWIG_IsOK(res1)) { - SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "_kclvm_plugin_AppContextBase__run_app" "', argument " "1"" of type '" "_kclvm_plugin_AppContextBase *""'"); - } - arg1 = reinterpret_cast< _kclvm_plugin_AppContextBase * >(argp1); - ecode2 = SWIG_AsVal_unsigned_SS_long_SS_long(obj1, &val2); - if (!SWIG_IsOK(ecode2)) { - SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "_kclvm_plugin_AppContextBase__run_app" "', argument " "2"" of type '" "uint64_t""'"); - } - arg2 = static_cast< uint64_t >(val2); - ecode3 = SWIG_AsVal_unsigned_SS_long_SS_long(obj2, &val3); - if (!SWIG_IsOK(ecode3)) { - SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "_kclvm_plugin_AppContextBase__run_app" "', argument " "3"" of type '" "uint64_t""'"); - } - arg3 = static_cast< uint64_t >(val3); - ecode4 = SWIG_AsVal_int(obj3, &val4); - if (!SWIG_IsOK(ecode4)) { - SWIG_exception_fail(SWIG_ArgError(ecode4), "in method '" "_kclvm_plugin_AppContextBase__run_app" "', argument " "4"" of type '" "int32_t""'"); - } - arg4 = static_cast< int32_t >(val4); - ecode5 = SWIG_AsVal_int(obj4, &val5); - if (!SWIG_IsOK(ecode5)) { - SWIG_exception_fail(SWIG_ArgError(ecode5), "in method '" "_kclvm_plugin_AppContextBase__run_app" "', argument " "5"" of type '" "int32_t""'"); - } - arg5 = static_cast< int32_t >(val5); - ecode6 = SWIG_AsVal_int(obj5, &val6); - if (!SWIG_IsOK(ecode6)) { - SWIG_exception_fail(SWIG_ArgError(ecode6), "in method '" "_kclvm_plugin_AppContextBase__run_app" "', argument " "6"" of type '" "int32_t""'"); - } - arg6 = static_cast< int32_t >(val6); - ecode7 = SWIG_AsVal_int(obj6, &val7); - if (!SWIG_IsOK(ecode7)) { - SWIG_exception_fail(SWIG_ArgError(ecode7), "in method '" "_kclvm_plugin_AppContextBase__run_app" "', argument " "7"" of type '" "int32_t""'"); - } - arg7 = static_cast< int32_t >(val7); - ecode8 = SWIG_AsVal_int(obj7, &val8); - if (!SWIG_IsOK(ecode8)) { - SWIG_exception_fail(SWIG_ArgError(ecode8), "in method '" "_kclvm_plugin_AppContextBase__run_app" "', argument " "8"" of type '" "int32_t""'"); - } - arg8 = static_cast< int32_t >(val8); - ecode9 = SWIG_AsVal_int(obj8, &val9); - if (!SWIG_IsOK(ecode9)) { - SWIG_exception_fail(SWIG_ArgError(ecode9), "in method '" "_kclvm_plugin_AppContextBase__run_app" "', argument " "9"" of type '" "int32_t""'"); - } - arg9 = static_cast< int32_t >(val9); - result = (arg1)->_run_app(arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9); - resultobj = SWIG_From_std_string(static_cast< std::string >(result)); - return resultobj; -fail: - return NULL; -} - - -SWIGINTERN PyObject *_wrap__kclvm_plugin_AppContextBase__get_warn(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { - PyObject *resultobj = 0; - _kclvm_plugin_AppContextBase *arg1 = (_kclvm_plugin_AppContextBase *) 0 ; - void *argp1 = 0 ; - int res1 = 0 ; - PyObject * obj0 = 0 ; - std::string result; - - if (!PyArg_ParseTuple(args,(char *)"O:_kclvm_plugin_AppContextBase__get_warn",&obj0)) SWIG_fail; - res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p__kclvm_plugin_AppContextBase, 0 | 0 ); - if (!SWIG_IsOK(res1)) { - SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "_kclvm_plugin_AppContextBase__get_warn" "', argument " "1"" of type '" "_kclvm_plugin_AppContextBase *""'"); - } - arg1 = reinterpret_cast< _kclvm_plugin_AppContextBase * >(argp1); - result = (arg1)->_get_warn(); - resultobj = SWIG_From_std_string(static_cast< std::string >(result)); - return resultobj; -fail: - return NULL; -} - - -SWIGINTERN PyObject *_wrap__kclvm_plugin_AppContextBase__get_cxx_invoke_proxy_ptr(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { - PyObject *resultobj = 0; - _kclvm_plugin_AppContextBase *arg1 = (_kclvm_plugin_AppContextBase *) 0 ; - void *argp1 = 0 ; - int res1 = 0 ; - PyObject * obj0 = 0 ; - uint64_t result; - - if (!PyArg_ParseTuple(args,(char *)"O:_kclvm_plugin_AppContextBase__get_cxx_invoke_proxy_ptr",&obj0)) SWIG_fail; - res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p__kclvm_plugin_AppContextBase, 0 | 0 ); - if (!SWIG_IsOK(res1)) { - SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "_kclvm_plugin_AppContextBase__get_cxx_invoke_proxy_ptr" "', argument " "1"" of type '" "_kclvm_plugin_AppContextBase *""'"); - } - arg1 = reinterpret_cast< _kclvm_plugin_AppContextBase * >(argp1); - result = (uint64_t)(arg1)->_get_cxx_invoke_proxy_ptr(); - resultobj = SWIG_From_unsigned_SS_long_SS_long(static_cast< unsigned long long >(result)); - return resultobj; -fail: - return NULL; -} - - -SWIGINTERN PyObject *_wrap__kclvm_plugin_AppContextBase__call_rust_method(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { - PyObject *resultobj = 0; - _kclvm_plugin_AppContextBase *arg1 = (_kclvm_plugin_AppContextBase *) 0 ; - std::string *arg2 = 0 ; - std::string *arg3 = 0 ; - std::string *arg4 = 0 ; - void *argp1 = 0 ; - int res1 = 0 ; - int res2 = SWIG_OLDOBJ ; - int res3 = SWIG_OLDOBJ ; - int res4 = SWIG_OLDOBJ ; - PyObject * obj0 = 0 ; - PyObject * obj1 = 0 ; - PyObject * obj2 = 0 ; - PyObject * obj3 = 0 ; - std::string result; - - if (!PyArg_ParseTuple(args,(char *)"OOOO:_kclvm_plugin_AppContextBase__call_rust_method",&obj0,&obj1,&obj2,&obj3)) SWIG_fail; - res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p__kclvm_plugin_AppContextBase, 0 | 0 ); - if (!SWIG_IsOK(res1)) { - SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "_kclvm_plugin_AppContextBase__call_rust_method" "', argument " "1"" of type '" "_kclvm_plugin_AppContextBase *""'"); - } - arg1 = reinterpret_cast< _kclvm_plugin_AppContextBase * >(argp1); - { - std::string *ptr = (std::string *)0; - res2 = SWIG_AsPtr_std_string(obj1, &ptr); - if (!SWIG_IsOK(res2)) { - SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "_kclvm_plugin_AppContextBase__call_rust_method" "', argument " "2"" of type '" "std::string const &""'"); - } - if (!ptr) { - SWIG_exception_fail(SWIG_ValueError, "invalid null reference " "in method '" "_kclvm_plugin_AppContextBase__call_rust_method" "', argument " "2"" of type '" "std::string const &""'"); - } - arg2 = ptr; - } - { - std::string *ptr = (std::string *)0; - res3 = SWIG_AsPtr_std_string(obj2, &ptr); - if (!SWIG_IsOK(res3)) { - SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "_kclvm_plugin_AppContextBase__call_rust_method" "', argument " "3"" of type '" "std::string const &""'"); - } - if (!ptr) { - SWIG_exception_fail(SWIG_ValueError, "invalid null reference " "in method '" "_kclvm_plugin_AppContextBase__call_rust_method" "', argument " "3"" of type '" "std::string const &""'"); - } - arg3 = ptr; - } - { - std::string *ptr = (std::string *)0; - res4 = SWIG_AsPtr_std_string(obj3, &ptr); - if (!SWIG_IsOK(res4)) { - SWIG_exception_fail(SWIG_ArgError(res4), "in method '" "_kclvm_plugin_AppContextBase__call_rust_method" "', argument " "4"" of type '" "std::string const &""'"); - } - if (!ptr) { - SWIG_exception_fail(SWIG_ValueError, "invalid null reference " "in method '" "_kclvm_plugin_AppContextBase__call_rust_method" "', argument " "4"" of type '" "std::string const &""'"); - } - arg4 = ptr; - } - result = (arg1)->_call_rust_method((std::string const &)*arg2,(std::string const &)*arg3,(std::string const &)*arg4); - resultobj = SWIG_From_std_string(static_cast< std::string >(result)); - if (SWIG_IsNewObj(res2)) delete arg2; - if (SWIG_IsNewObj(res3)) delete arg3; - if (SWIG_IsNewObj(res4)) delete arg4; - return resultobj; -fail: - if (SWIG_IsNewObj(res2)) delete arg2; - if (SWIG_IsNewObj(res3)) delete arg3; - if (SWIG_IsNewObj(res4)) delete arg4; - return NULL; -} - - -SWIGINTERN PyObject *_wrap__kclvm_plugin_AppContextBase__call_py_method(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { - PyObject *resultobj = 0; - _kclvm_plugin_AppContextBase *arg1 = (_kclvm_plugin_AppContextBase *) 0 ; - std::string *arg2 = 0 ; - std::string *arg3 = 0 ; - std::string *arg4 = 0 ; - void *argp1 = 0 ; - int res1 = 0 ; - int res2 = SWIG_OLDOBJ ; - int res3 = SWIG_OLDOBJ ; - int res4 = SWIG_OLDOBJ ; - PyObject * obj0 = 0 ; - PyObject * obj1 = 0 ; - PyObject * obj2 = 0 ; - PyObject * obj3 = 0 ; - Swig::Director *director = 0; - bool upcall = false; - std::string result; - - if (!PyArg_ParseTuple(args,(char *)"OOOO:_kclvm_plugin_AppContextBase__call_py_method",&obj0,&obj1,&obj2,&obj3)) SWIG_fail; - res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p__kclvm_plugin_AppContextBase, 0 | 0 ); - if (!SWIG_IsOK(res1)) { - SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "_kclvm_plugin_AppContextBase__call_py_method" "', argument " "1"" of type '" "_kclvm_plugin_AppContextBase *""'"); - } - arg1 = reinterpret_cast< _kclvm_plugin_AppContextBase * >(argp1); - { - std::string *ptr = (std::string *)0; - res2 = SWIG_AsPtr_std_string(obj1, &ptr); - if (!SWIG_IsOK(res2)) { - SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "_kclvm_plugin_AppContextBase__call_py_method" "', argument " "2"" of type '" "std::string const &""'"); - } - if (!ptr) { - SWIG_exception_fail(SWIG_ValueError, "invalid null reference " "in method '" "_kclvm_plugin_AppContextBase__call_py_method" "', argument " "2"" of type '" "std::string const &""'"); - } - arg2 = ptr; - } - { - std::string *ptr = (std::string *)0; - res3 = SWIG_AsPtr_std_string(obj2, &ptr); - if (!SWIG_IsOK(res3)) { - SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "_kclvm_plugin_AppContextBase__call_py_method" "', argument " "3"" of type '" "std::string const &""'"); - } - if (!ptr) { - SWIG_exception_fail(SWIG_ValueError, "invalid null reference " "in method '" "_kclvm_plugin_AppContextBase__call_py_method" "', argument " "3"" of type '" "std::string const &""'"); - } - arg3 = ptr; - } - { - std::string *ptr = (std::string *)0; - res4 = SWIG_AsPtr_std_string(obj3, &ptr); - if (!SWIG_IsOK(res4)) { - SWIG_exception_fail(SWIG_ArgError(res4), "in method '" "_kclvm_plugin_AppContextBase__call_py_method" "', argument " "4"" of type '" "std::string const &""'"); - } - if (!ptr) { - SWIG_exception_fail(SWIG_ValueError, "invalid null reference " "in method '" "_kclvm_plugin_AppContextBase__call_py_method" "', argument " "4"" of type '" "std::string const &""'"); - } - arg4 = ptr; - } - director = SWIG_DIRECTOR_CAST(arg1); - upcall = (director && (director->swig_get_self()==obj0)); - try { - if (upcall) { - result = (arg1)->_kclvm_plugin_AppContextBase::_call_py_method((std::string const &)*arg2,(std::string const &)*arg3,(std::string const &)*arg4); - } else { - result = (arg1)->_call_py_method((std::string const &)*arg2,(std::string const &)*arg3,(std::string const &)*arg4); - } - } catch (Swig::DirectorException&) { - SWIG_fail; - } - resultobj = SWIG_From_std_string(static_cast< std::string >(result)); - if (SWIG_IsNewObj(res2)) delete arg2; - if (SWIG_IsNewObj(res3)) delete arg3; - if (SWIG_IsNewObj(res4)) delete arg4; - return resultobj; -fail: - if (SWIG_IsNewObj(res2)) delete arg2; - if (SWIG_IsNewObj(res3)) delete arg3; - if (SWIG_IsNewObj(res4)) delete arg4; - return NULL; -} - - -SWIGINTERN PyObject *_wrap_disown__kclvm_plugin_AppContextBase(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { - PyObject *resultobj = 0; - _kclvm_plugin_AppContextBase *arg1 = (_kclvm_plugin_AppContextBase *) 0 ; - void *argp1 = 0 ; - int res1 = 0 ; - PyObject * obj0 = 0 ; - - if (!PyArg_ParseTuple(args,(char *)"O:disown__kclvm_plugin_AppContextBase",&obj0)) SWIG_fail; - res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p__kclvm_plugin_AppContextBase, 0 | 0 ); - if (!SWIG_IsOK(res1)) { - SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "disown__kclvm_plugin_AppContextBase" "', argument " "1"" of type '" "_kclvm_plugin_AppContextBase *""'"); - } - arg1 = reinterpret_cast< _kclvm_plugin_AppContextBase * >(argp1); - { - Swig::Director *director = SWIG_DIRECTOR_CAST(arg1); - if (director) director->swig_disown(); - } - - resultobj = SWIG_Py_Void(); - return resultobj; -fail: - return NULL; -} - - -SWIGINTERN PyObject *_kclvm_plugin_AppContextBase_swigregister(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { - PyObject *obj; - if (!PyArg_ParseTuple(args,(char *)"O:swigregister", &obj)) return NULL; - SWIG_TypeNewClientData(SWIGTYPE_p__kclvm_plugin_AppContextBase, SWIG_NewClientData(obj)); - return SWIG_Py_Void(); -} - -static PyMethodDef SwigMethods[] = { - { (char *)"SWIG_PyInstanceMethod_New", (PyCFunction)SWIG_PyInstanceMethod_New, METH_O, NULL}, - { (char *)"new__kclvm_plugin_AppContextBase", _wrap_new__kclvm_plugin_AppContextBase, METH_VARARGS, NULL}, - { (char *)"delete__kclvm_plugin_AppContextBase", _wrap_delete__kclvm_plugin_AppContextBase, METH_VARARGS, NULL}, - { (char *)"_kclvm_plugin_AppContextBase__clear_options", _wrap__kclvm_plugin_AppContextBase__clear_options, METH_VARARGS, NULL}, - { (char *)"_kclvm_plugin_AppContextBase__add_option", _wrap__kclvm_plugin_AppContextBase__add_option, METH_VARARGS, NULL}, - { (char *)"_kclvm_plugin_AppContextBase__run_app", _wrap__kclvm_plugin_AppContextBase__run_app, METH_VARARGS, NULL}, - { (char *)"_kclvm_plugin_AppContextBase__get_warn", _wrap__kclvm_plugin_AppContextBase__get_warn, METH_VARARGS, NULL}, - { (char *)"_kclvm_plugin_AppContextBase__get_cxx_invoke_proxy_ptr", _wrap__kclvm_plugin_AppContextBase__get_cxx_invoke_proxy_ptr, METH_VARARGS, NULL}, - { (char *)"_kclvm_plugin_AppContextBase__call_rust_method", _wrap__kclvm_plugin_AppContextBase__call_rust_method, METH_VARARGS, NULL}, - { (char *)"_kclvm_plugin_AppContextBase__call_py_method", _wrap__kclvm_plugin_AppContextBase__call_py_method, METH_VARARGS, NULL}, - { (char *)"disown__kclvm_plugin_AppContextBase", _wrap_disown__kclvm_plugin_AppContextBase, METH_VARARGS, NULL}, - { (char *)"_kclvm_plugin_AppContextBase_swigregister", _kclvm_plugin_AppContextBase_swigregister, METH_VARARGS, NULL}, - { NULL, NULL, 0, NULL } -}; - - -/* -------- TYPE CONVERSION AND EQUIVALENCE RULES (BEGIN) -------- */ - -static swig_type_info _swigt__p__kclvm_plugin_AppContextBase = {"_p__kclvm_plugin_AppContextBase", "_kclvm_plugin_AppContextBase *", 0, 0, (void*)0, 0}; -static swig_type_info _swigt__p_char = {"_p_char", "char *", 0, 0, (void*)0, 0}; -static swig_type_info _swigt__p_int = {"_p_int", "intptr_t *|int *|int_least32_t *|int_fast32_t *|int32_t *|int_fast16_t *", 0, 0, (void*)0, 0}; -static swig_type_info _swigt__p_long_long = {"_p_long_long", "int_least64_t *|int_fast64_t *|int64_t *|long long *|intmax_t *", 0, 0, (void*)0, 0}; -static swig_type_info _swigt__p_short = {"_p_short", "short *|int_least16_t *|int16_t *", 0, 0, (void*)0, 0}; -static swig_type_info _swigt__p_signed_char = {"_p_signed_char", "signed char *|int_least8_t *|int_fast8_t *|int8_t *", 0, 0, (void*)0, 0}; -static swig_type_info _swigt__p_unsigned_char = {"_p_unsigned_char", "unsigned char *|uint_least8_t *|uint_fast8_t *|uint8_t *", 0, 0, (void*)0, 0}; -static swig_type_info _swigt__p_unsigned_int = {"_p_unsigned_int", "uintptr_t *|uint_least32_t *|uint_fast32_t *|uint32_t *|unsigned int *|uint_fast16_t *", 0, 0, (void*)0, 0}; -static swig_type_info _swigt__p_unsigned_long_long = {"_p_unsigned_long_long", "uint_least64_t *|uint_fast64_t *|uint64_t *|unsigned long long *|uintmax_t *", 0, 0, (void*)0, 0}; -static swig_type_info _swigt__p_unsigned_short = {"_p_unsigned_short", "unsigned short *|uint_least16_t *|uint16_t *", 0, 0, (void*)0, 0}; - -static swig_type_info *swig_type_initial[] = { - &_swigt__p__kclvm_plugin_AppContextBase, - &_swigt__p_char, - &_swigt__p_int, - &_swigt__p_long_long, - &_swigt__p_short, - &_swigt__p_signed_char, - &_swigt__p_unsigned_char, - &_swigt__p_unsigned_int, - &_swigt__p_unsigned_long_long, - &_swigt__p_unsigned_short, -}; - -static swig_cast_info _swigc__p__kclvm_plugin_AppContextBase[] = { {&_swigt__p__kclvm_plugin_AppContextBase, 0, 0, 0},{0, 0, 0, 0}}; -static swig_cast_info _swigc__p_char[] = { {&_swigt__p_char, 0, 0, 0},{0, 0, 0, 0}}; -static swig_cast_info _swigc__p_int[] = { {&_swigt__p_int, 0, 0, 0},{0, 0, 0, 0}}; -static swig_cast_info _swigc__p_long_long[] = { {&_swigt__p_long_long, 0, 0, 0},{0, 0, 0, 0}}; -static swig_cast_info _swigc__p_short[] = { {&_swigt__p_short, 0, 0, 0},{0, 0, 0, 0}}; -static swig_cast_info _swigc__p_signed_char[] = { {&_swigt__p_signed_char, 0, 0, 0},{0, 0, 0, 0}}; -static swig_cast_info _swigc__p_unsigned_char[] = { {&_swigt__p_unsigned_char, 0, 0, 0},{0, 0, 0, 0}}; -static swig_cast_info _swigc__p_unsigned_int[] = { {&_swigt__p_unsigned_int, 0, 0, 0},{0, 0, 0, 0}}; -static swig_cast_info _swigc__p_unsigned_long_long[] = { {&_swigt__p_unsigned_long_long, 0, 0, 0},{0, 0, 0, 0}}; -static swig_cast_info _swigc__p_unsigned_short[] = { {&_swigt__p_unsigned_short, 0, 0, 0},{0, 0, 0, 0}}; - -static swig_cast_info *swig_cast_initial[] = { - _swigc__p__kclvm_plugin_AppContextBase, - _swigc__p_char, - _swigc__p_int, - _swigc__p_long_long, - _swigc__p_short, - _swigc__p_signed_char, - _swigc__p_unsigned_char, - _swigc__p_unsigned_int, - _swigc__p_unsigned_long_long, - _swigc__p_unsigned_short, -}; - - -/* -------- TYPE CONVERSION AND EQUIVALENCE RULES (END) -------- */ - -static swig_const_info swig_const_table[] = { -{0, 0, 0, 0.0, 0, 0}}; - -#ifdef __cplusplus -} -#endif -/* ----------------------------------------------------------------------------- - * Type initialization: - * This problem is tough by the requirement that no dynamic - * memory is used. Also, since swig_type_info structures store pointers to - * swig_cast_info structures and swig_cast_info structures store pointers back - * to swig_type_info structures, we need some lookup code at initialization. - * The idea is that swig generates all the structures that are needed. - * The runtime then collects these partially filled structures. - * The SWIG_InitializeModule function takes these initial arrays out of - * swig_module, and does all the lookup, filling in the swig_module.types - * array with the correct data and linking the correct swig_cast_info - * structures together. - * - * The generated swig_type_info structures are assigned statically to an initial - * array. We just loop through that array, and handle each type individually. - * First we lookup if this type has been already loaded, and if so, use the - * loaded structure instead of the generated one. Then we have to fill in the - * cast linked list. The cast data is initially stored in something like a - * two-dimensional array. Each row corresponds to a type (there are the same - * number of rows as there are in the swig_type_initial array). Each entry in - * a column is one of the swig_cast_info structures for that type. - * The cast_initial array is actually an array of arrays, because each row has - * a variable number of columns. So to actually build the cast linked list, - * we find the array of casts associated with the type, and loop through it - * adding the casts to the list. The one last trick we need to do is making - * sure the type pointer in the swig_cast_info struct is correct. - * - * First off, we lookup the cast->type name to see if it is already loaded. - * There are three cases to handle: - * 1) If the cast->type has already been loaded AND the type we are adding - * casting info to has not been loaded (it is in this module), THEN we - * replace the cast->type pointer with the type pointer that has already - * been loaded. - * 2) If BOTH types (the one we are adding casting info to, and the - * cast->type) are loaded, THEN the cast info has already been loaded by - * the previous module so we just ignore it. - * 3) Finally, if cast->type has not already been loaded, then we add that - * swig_cast_info to the linked list (because the cast->type) pointer will - * be correct. - * ----------------------------------------------------------------------------- */ - -#ifdef __cplusplus -extern "C" { -#if 0 -} /* c-mode */ -#endif -#endif - -#if 0 -#define SWIGRUNTIME_DEBUG -#endif - - -SWIGRUNTIME void -SWIG_InitializeModule(void *clientdata) { - size_t i; - swig_module_info *module_head, *iter; - int init; - - /* check to see if the circular list has been setup, if not, set it up */ - if (swig_module.next==0) { - /* Initialize the swig_module */ - swig_module.type_initial = swig_type_initial; - swig_module.cast_initial = swig_cast_initial; - swig_module.next = &swig_module; - init = 1; - } else { - init = 0; - } - - /* Try and load any already created modules */ - module_head = SWIG_GetModule(clientdata); - if (!module_head) { - /* This is the first module loaded for this interpreter */ - /* so set the swig module into the interpreter */ - SWIG_SetModule(clientdata, &swig_module); - } else { - /* the interpreter has loaded a SWIG module, but has it loaded this one? */ - iter=module_head; - do { - if (iter==&swig_module) { - /* Our module is already in the list, so there's nothing more to do. */ - return; - } - iter=iter->next; - } while (iter!= module_head); - - /* otherwise we must add our module into the list */ - swig_module.next = module_head->next; - module_head->next = &swig_module; - } - - /* When multiple interpreters are used, a module could have already been initialized in - a different interpreter, but not yet have a pointer in this interpreter. - In this case, we do not want to continue adding types... everything should be - set up already */ - if (init == 0) return; - - /* Now work on filling in swig_module.types */ -#ifdef SWIGRUNTIME_DEBUG - printf("SWIG_InitializeModule: size %d\n", swig_module.size); -#endif - for (i = 0; i < swig_module.size; ++i) { - swig_type_info *type = 0; - swig_type_info *ret; - swig_cast_info *cast; - -#ifdef SWIGRUNTIME_DEBUG - printf("SWIG_InitializeModule: type %d %s\n", i, swig_module.type_initial[i]->name); -#endif - - /* if there is another module already loaded */ - if (swig_module.next != &swig_module) { - type = SWIG_MangledTypeQueryModule(swig_module.next, &swig_module, swig_module.type_initial[i]->name); - } - if (type) { - /* Overwrite clientdata field */ -#ifdef SWIGRUNTIME_DEBUG - printf("SWIG_InitializeModule: found type %s\n", type->name); -#endif - if (swig_module.type_initial[i]->clientdata) { - type->clientdata = swig_module.type_initial[i]->clientdata; -#ifdef SWIGRUNTIME_DEBUG - printf("SWIG_InitializeModule: found and overwrite type %s \n", type->name); -#endif - } - } else { - type = swig_module.type_initial[i]; - } - - /* Insert casting types */ - cast = swig_module.cast_initial[i]; - while (cast->type) { - /* Don't need to add information already in the list */ - ret = 0; -#ifdef SWIGRUNTIME_DEBUG - printf("SWIG_InitializeModule: look cast %s\n", cast->type->name); -#endif - if (swig_module.next != &swig_module) { - ret = SWIG_MangledTypeQueryModule(swig_module.next, &swig_module, cast->type->name); -#ifdef SWIGRUNTIME_DEBUG - if (ret) printf("SWIG_InitializeModule: found cast %s\n", ret->name); -#endif - } - if (ret) { - if (type == swig_module.type_initial[i]) { -#ifdef SWIGRUNTIME_DEBUG - printf("SWIG_InitializeModule: skip old type %s\n", ret->name); -#endif - cast->type = ret; - ret = 0; - } else { - /* Check for casting already in the list */ - swig_cast_info *ocast = SWIG_TypeCheck(ret->name, type); -#ifdef SWIGRUNTIME_DEBUG - if (ocast) printf("SWIG_InitializeModule: skip old cast %s\n", ret->name); -#endif - if (!ocast) ret = 0; - } - } - - if (!ret) { -#ifdef SWIGRUNTIME_DEBUG - printf("SWIG_InitializeModule: adding cast %s\n", cast->type->name); -#endif - if (type->cast) { - type->cast->prev = cast; - cast->next = type->cast; - } - type->cast = cast; - } - cast++; - } - /* Set entry in modules->types array equal to the type */ - swig_module.types[i] = type; - } - swig_module.types[i] = 0; - -#ifdef SWIGRUNTIME_DEBUG - printf("**** SWIG_InitializeModule: Cast List ******\n"); - for (i = 0; i < swig_module.size; ++i) { - int j = 0; - swig_cast_info *cast = swig_module.cast_initial[i]; - printf("SWIG_InitializeModule: type %d %s\n", i, swig_module.type_initial[i]->name); - while (cast->type) { - printf("SWIG_InitializeModule: cast type %s\n", cast->type->name); - cast++; - ++j; - } - printf("---- Total casts: %d\n",j); - } - printf("**** SWIG_InitializeModule: Cast List ******\n"); -#endif -} - -/* This function will propagate the clientdata field of type to -* any new swig_type_info structures that have been added into the list -* of equivalent types. It is like calling -* SWIG_TypeClientData(type, clientdata) a second time. -*/ -SWIGRUNTIME void -SWIG_PropagateClientData(void) { - size_t i; - swig_cast_info *equiv; - static int init_run = 0; - - if (init_run) return; - init_run = 1; - - for (i = 0; i < swig_module.size; i++) { - if (swig_module.types[i]->clientdata) { - equiv = swig_module.types[i]->cast; - while (equiv) { - if (!equiv->converter) { - if (equiv->type && !equiv->type->clientdata) - SWIG_TypeClientData(equiv->type, swig_module.types[i]->clientdata); - } - equiv = equiv->next; - } - } - } -} - -#ifdef __cplusplus -#if 0 -{ - /* c-mode */ -#endif -} -#endif - - - -#ifdef __cplusplus -extern "C" { -#endif - - /* Python-specific SWIG API */ -#define SWIG_newvarlink() SWIG_Python_newvarlink() -#define SWIG_addvarlink(p, name, get_attr, set_attr) SWIG_Python_addvarlink(p, name, get_attr, set_attr) -#define SWIG_InstallConstants(d, constants) SWIG_Python_InstallConstants(d, constants) - - /* ----------------------------------------------------------------------------- - * global variable support code. - * ----------------------------------------------------------------------------- */ - - typedef struct swig_globalvar { - char *name; /* Name of global variable */ - PyObject *(*get_attr)(void); /* Return the current value */ - int (*set_attr)(PyObject *); /* Set the value */ - struct swig_globalvar *next; - } swig_globalvar; - - typedef struct swig_varlinkobject { - PyObject_HEAD - swig_globalvar *vars; - } swig_varlinkobject; - - SWIGINTERN PyObject * - swig_varlink_repr(swig_varlinkobject *SWIGUNUSEDPARM(v)) { -#if PY_VERSION_HEX >= 0x03000000 - return PyUnicode_InternFromString(""); -#else - return PyString_FromString(""); -#endif - } - - SWIGINTERN PyObject * - swig_varlink_str(swig_varlinkobject *v) { -#if PY_VERSION_HEX >= 0x03000000 - PyObject *str = PyUnicode_InternFromString("("); - PyObject *tail; - PyObject *joined; - swig_globalvar *var; - for (var = v->vars; var; var=var->next) { - tail = PyUnicode_FromString(var->name); - joined = PyUnicode_Concat(str, tail); - Py_DecRef(str); - Py_DecRef(tail); - str = joined; - if (var->next) { - tail = PyUnicode_InternFromString(", "); - joined = PyUnicode_Concat(str, tail); - Py_DecRef(str); - Py_DecRef(tail); - str = joined; - } - } - tail = PyUnicode_InternFromString(")"); - joined = PyUnicode_Concat(str, tail); - Py_DecRef(str); - Py_DecRef(tail); - str = joined; -#else - PyObject *str = PyString_FromString("("); - swig_globalvar *var; - for (var = v->vars; var; var=var->next) { - PyString_ConcatAndDel(&str,PyString_FromString(var->name)); - if (var->next) PyString_ConcatAndDel(&str,PyString_FromString(", ")); - } - PyString_ConcatAndDel(&str,PyString_FromString(")")); -#endif - return str; - } - - SWIGINTERN int - swig_varlink_print(swig_varlinkobject *v, FILE *fp, int SWIGUNUSEDPARM(flags)) { - char *tmp; - PyObject *str = swig_varlink_str(v); - fprintf(fp,"Swig global variables "); - fprintf(fp,"%s\n", tmp = SWIG_Python_str_AsChar(str)); - SWIG_Python_str_DelForPy3(tmp); - Py_DECREF(str); - return 0; - } - - SWIGINTERN void - swig_varlink_dealloc(swig_varlinkobject *v) { - swig_globalvar *var = v->vars; - while (var) { - swig_globalvar *n = var->next; - free(var->name); - free(var); - var = n; - } - } - - SWIGINTERN PyObject * - swig_varlink_getattr(swig_varlinkobject *v, char *n) { - PyObject *res = NULL; - swig_globalvar *var = v->vars; - while (var) { - if (strcmp(var->name,n) == 0) { - res = (*var->get_attr)(); - break; - } - var = var->next; - } - if (res == NULL && !PyErr_Occurred()) { - PyErr_Format(PyExc_AttributeError, "Unknown C global variable '%s'", n); - } - return res; - } - - SWIGINTERN int - swig_varlink_setattr(swig_varlinkobject *v, char *n, PyObject *p) { - int res = 1; - swig_globalvar *var = v->vars; - while (var) { - if (strcmp(var->name,n) == 0) { - res = (*var->set_attr)(p); - break; - } - var = var->next; - } - if (res == 1 && !PyErr_Occurred()) { - PyErr_Format(PyExc_AttributeError, "Unknown C global variable '%s'", n); - } - return res; - } - - SWIGINTERN PyTypeObject* - swig_varlink_type(void) { - static char varlink__doc__[] = "Swig var link object"; - static PyTypeObject varlink_type; - static int type_init = 0; - if (!type_init) { - const PyTypeObject tmp = { -#if PY_VERSION_HEX >= 0x03000000 - PyVarObject_HEAD_INIT(NULL, 0) -#else - PyObject_HEAD_INIT(NULL) - 0, /* ob_size */ -#endif - (char *)"swigvarlink", /* tp_name */ - sizeof(swig_varlinkobject), /* tp_basicsize */ - 0, /* tp_itemsize */ - (destructor) swig_varlink_dealloc, /* tp_dealloc */ - (printfunc) swig_varlink_print, /* tp_print */ - (getattrfunc) swig_varlink_getattr, /* tp_getattr */ - (setattrfunc) swig_varlink_setattr, /* tp_setattr */ - 0, /* tp_compare */ - (reprfunc) swig_varlink_repr, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - (reprfunc) swig_varlink_str, /* tp_str */ - 0, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - 0, /* tp_flags */ - varlink__doc__, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ -#if PY_VERSION_HEX >= 0x02020000 - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* tp_iter -> tp_weaklist */ -#endif -#if PY_VERSION_HEX >= 0x02030000 - 0, /* tp_del */ -#endif -#if PY_VERSION_HEX >= 0x02060000 - 0, /* tp_version_tag */ -#endif -#if PY_VERSION_HEX >= 0x03040000 - 0, /* tp_finalize */ -#endif -#ifdef COUNT_ALLOCS - 0, /* tp_allocs */ - 0, /* tp_frees */ - 0, /* tp_maxalloc */ -#if PY_VERSION_HEX >= 0x02050000 - 0, /* tp_prev */ -#endif - 0 /* tp_next */ -#endif - }; - varlink_type = tmp; - type_init = 1; -#if PY_VERSION_HEX < 0x02020000 - varlink_type.ob_type = &PyType_Type; -#else - if (PyType_Ready(&varlink_type) < 0) - return NULL; -#endif - } - return &varlink_type; - } - - /* Create a variable linking object for use later */ - SWIGINTERN PyObject * - SWIG_Python_newvarlink(void) { - swig_varlinkobject *result = PyObject_NEW(swig_varlinkobject, swig_varlink_type()); - if (result) { - result->vars = 0; - } - return ((PyObject*) result); - } - - SWIGINTERN void - SWIG_Python_addvarlink(PyObject *p, char *name, PyObject *(*get_attr)(void), int (*set_attr)(PyObject *p)) { - swig_varlinkobject *v = (swig_varlinkobject *) p; - swig_globalvar *gv = (swig_globalvar *) malloc(sizeof(swig_globalvar)); - if (gv) { - size_t size = strlen(name)+1; - gv->name = (char *)malloc(size); - if (gv->name) { - strncpy(gv->name,name,size); - gv->get_attr = get_attr; - gv->set_attr = set_attr; - gv->next = v->vars; - } - } - v->vars = gv; - } - - SWIGINTERN PyObject * - SWIG_globals(void) { - static PyObject *_SWIG_globals = 0; - if (!_SWIG_globals) _SWIG_globals = SWIG_newvarlink(); - return _SWIG_globals; - } - - /* ----------------------------------------------------------------------------- - * constants/methods manipulation - * ----------------------------------------------------------------------------- */ - - /* Install Constants */ - SWIGINTERN void - SWIG_Python_InstallConstants(PyObject *d, swig_const_info constants[]) { - PyObject *obj = 0; - size_t i; - for (i = 0; constants[i].type; ++i) { - switch(constants[i].type) { - case SWIG_PY_POINTER: - obj = SWIG_InternalNewPointerObj(constants[i].pvalue, *(constants[i]).ptype,0); - break; - case SWIG_PY_BINARY: - obj = SWIG_NewPackedObj(constants[i].pvalue, constants[i].lvalue, *(constants[i].ptype)); - break; - default: - obj = 0; - break; - } - if (obj) { - PyDict_SetItemString(d, constants[i].name, obj); - Py_DECREF(obj); - } - } - } - - /* -----------------------------------------------------------------------------*/ - /* Fix SwigMethods to carry the callback ptrs when needed */ - /* -----------------------------------------------------------------------------*/ - - SWIGINTERN void - SWIG_Python_FixMethods(PyMethodDef *methods, - swig_const_info *const_table, - swig_type_info **types, - swig_type_info **types_initial) { - size_t i; - for (i = 0; methods[i].ml_name; ++i) { - const char *c = methods[i].ml_doc; - if (!c) continue; - c = strstr(c, "swig_ptr: "); - if (c) { - int j; - swig_const_info *ci = 0; - const char *name = c + 10; - for (j = 0; const_table[j].type; ++j) { - if (strncmp(const_table[j].name, name, - strlen(const_table[j].name)) == 0) { - ci = &(const_table[j]); - break; - } - } - if (ci) { - void *ptr = (ci->type == SWIG_PY_POINTER) ? ci->pvalue : 0; - if (ptr) { - size_t shift = (ci->ptype) - types; - swig_type_info *ty = types_initial[shift]; - size_t ldoc = (c - methods[i].ml_doc); - size_t lptr = strlen(ty->name)+2*sizeof(void*)+2; - char *ndoc = (char*)malloc(ldoc + lptr + 10); - if (ndoc) { - char *buff = ndoc; - strncpy(buff, methods[i].ml_doc, ldoc); - buff += ldoc; - strncpy(buff, "swig_ptr: ", 10); - buff += 10; - SWIG_PackVoidPtr(buff, ptr, ty->name, lptr); - methods[i].ml_doc = ndoc; - } - } - } - } - } - } - -#ifdef __cplusplus -} -#endif - -/* -----------------------------------------------------------------------------* - * Partial Init method - * -----------------------------------------------------------------------------*/ - -#ifdef __cplusplus -extern "C" -#endif - -SWIGEXPORT -#if PY_VERSION_HEX >= 0x03000000 -PyObject* -#else -void -#endif -SWIG_init(void) { - PyObject *m, *d, *md; -#if PY_VERSION_HEX >= 0x03000000 - static struct PyModuleDef SWIG_module = { -# if PY_VERSION_HEX >= 0x03020000 - PyModuleDef_HEAD_INIT, -# else - { - PyObject_HEAD_INIT(NULL) - NULL, /* m_init */ - 0, /* m_index */ - NULL, /* m_copy */ - }, -# endif - (char *) SWIG_name, - NULL, - -1, - SwigMethods, - NULL, - NULL, - NULL, - NULL - }; -#endif - -#if defined(SWIGPYTHON_BUILTIN) - static SwigPyClientData SwigPyObject_clientdata = { - 0, 0, 0, 0, 0, 0, 0 - }; - static PyGetSetDef this_getset_def = { - (char *)"this", &SwigPyBuiltin_ThisClosure, NULL, NULL, NULL - }; - static SwigPyGetSet thisown_getset_closure = { - (PyCFunction) SwigPyObject_own, - (PyCFunction) SwigPyObject_own - }; - static PyGetSetDef thisown_getset_def = { - (char *)"thisown", SwigPyBuiltin_GetterClosure, SwigPyBuiltin_SetterClosure, NULL, &thisown_getset_closure - }; - PyTypeObject *builtin_pytype; - int builtin_base_count; - swig_type_info *builtin_basetype; - PyObject *tuple; - PyGetSetDescrObject *static_getset; - PyTypeObject *metatype; - PyTypeObject *swigpyobject; - SwigPyClientData *cd; - PyObject *public_interface, *public_symbol; - PyObject *this_descr; - PyObject *thisown_descr; - PyObject *self = 0; - int i; - - (void)builtin_pytype; - (void)builtin_base_count; - (void)builtin_basetype; - (void)tuple; - (void)static_getset; - (void)self; - - /* Metaclass is used to implement static member variables */ - metatype = SwigPyObjectType(); - assert(metatype); -#endif - - /* Fix SwigMethods to carry the callback ptrs when needed */ - SWIG_Python_FixMethods(SwigMethods, swig_const_table, swig_types, swig_type_initial); - -#if PY_VERSION_HEX >= 0x03000000 - m = PyModule_Create(&SWIG_module); -#else - m = Py_InitModule((char *) SWIG_name, SwigMethods); -#endif - - md = d = PyModule_GetDict(m); - (void)md; - - SWIG_InitializeModule(0); - -#ifdef SWIGPYTHON_BUILTIN - swigpyobject = SwigPyObject_TypeOnce(); - - SwigPyObject_stype = SWIG_MangledTypeQuery("_p_SwigPyObject"); - assert(SwigPyObject_stype); - cd = (SwigPyClientData*) SwigPyObject_stype->clientdata; - if (!cd) { - SwigPyObject_stype->clientdata = &SwigPyObject_clientdata; - SwigPyObject_clientdata.pytype = swigpyobject; - } else if (swigpyobject->tp_basicsize != cd->pytype->tp_basicsize) { - PyErr_SetString(PyExc_RuntimeError, "Import error: attempted to load two incompatible swig-generated modules."); -# if PY_VERSION_HEX >= 0x03000000 - return NULL; -# else - return; -# endif - } - - /* All objects have a 'this' attribute */ - this_descr = PyDescr_NewGetSet(SwigPyObject_type(), &this_getset_def); - (void)this_descr; - - /* All objects have a 'thisown' attribute */ - thisown_descr = PyDescr_NewGetSet(SwigPyObject_type(), &thisown_getset_def); - (void)thisown_descr; - - public_interface = PyList_New(0); - public_symbol = 0; - (void)public_symbol; - - PyDict_SetItemString(md, "__all__", public_interface); - Py_DECREF(public_interface); - for (i = 0; SwigMethods[i].ml_name != NULL; ++i) - SwigPyBuiltin_AddPublicSymbol(public_interface, SwigMethods[i].ml_name); - for (i = 0; swig_const_table[i].name != 0; ++i) - SwigPyBuiltin_AddPublicSymbol(public_interface, swig_const_table[i].name); -#endif - - SWIG_InstallConstants(d,swig_const_table); - -#if PY_VERSION_HEX >= 0x03000000 - return m; -#else - return; -#endif -} - diff --git a/kclvm/plugin/kclvm_plugin_wrap.h b/kclvm/plugin/kclvm_plugin_wrap.h deleted file mode 100644 index 0548c7e4c..000000000 --- a/kclvm/plugin/kclvm_plugin_wrap.h +++ /dev/null @@ -1,60 +0,0 @@ -/* ---------------------------------------------------------------------------- - * This file was automatically generated by SWIG (http://www.swig.org). - * Version 3.0.12 - * - * This file is not intended to be easily readable and contains a number of - * coding conventions designed to improve portability and efficiency. Do not make - * changes to this file unless you know what you are doing--modify the SWIG - * interface file instead. - * ----------------------------------------------------------------------------- */ - -#ifndef SWIG_kclvm_plugin_WRAP_H_ -#define SWIG_kclvm_plugin_WRAP_H_ - -#include -#include - - -class SwigDirector__kclvm_plugin_AppContextBase : public _kclvm_plugin_AppContextBase, public Swig::Director { - -public: - SwigDirector__kclvm_plugin_AppContextBase(PyObject *self, uint64_t rust_invoke_json_ptr); - virtual ~SwigDirector__kclvm_plugin_AppContextBase(); - virtual std::string _call_py_method(std::string const &name, std::string const &args_json, std::string const &kwargs_json); - -/* Internal director utilities */ -public: - bool swig_get_inner(const char *swig_protected_method_name) const { - std::map::const_iterator iv = swig_inner.find(swig_protected_method_name); - return (iv != swig_inner.end() ? iv->second : false); - } - void swig_set_inner(const char *swig_protected_method_name, bool swig_val) const { - swig_inner[swig_protected_method_name] = swig_val; - } -private: - mutable std::map swig_inner; - -#if defined(SWIG_PYTHON_DIRECTOR_VTABLE) -/* VTable implementation */ - PyObject *swig_get_method(size_t method_index, const char *method_name) const { - PyObject *method = vtable[method_index]; - if (!method) { - swig::SwigVar_PyObject name = SWIG_Python_str_FromChar(method_name); - method = PyObject_GetAttr(swig_get_self(), name); - if (!method) { - std::string msg = "Method in class _kclvm_plugin_AppContextBase doesn't exist, undefined "; - msg += method_name; - Swig::DirectorMethodException::raise(msg.c_str()); - } - vtable[method_index] = method; - } - return method; - } -private: - mutable swig::SwigVar_PyObject vtable[1]; -#endif - -}; - - -#endif diff --git a/kclvm/plugin/kclvm_runtime.py b/kclvm/plugin/kclvm_runtime.py deleted file mode 100644 index 3bd464a7c..000000000 --- a/kclvm/plugin/kclvm_runtime.py +++ /dev/null @@ -1,97 +0,0 @@ -# Copyright 2021 The KCL Authors. All rights reserved. - -import ctypes -import json -import os -import sys - - -def _find_default_dylib_path() -> str: - _executable_root = os.path.dirname(os.path.dirname(sys.executable)) - - pathList = [ - f"{_executable_root}/lib/libkclvm.dylib", - f"{_executable_root}/lib/libkclvm.so", - f"{_executable_root}/lib/kclvm.dll", - f"{os.path.dirname(__file__)}/../runtime/target/release/libkclvm.dylib", - f"{os.path.dirname(__file__)}/../runtime/target/release/libkclvm.so", - f"{os.path.dirname(__file__)}/../runtime/target/release/kclvm.dll", - f"{os.path.dirname(__file__)}/../runtime/target/debug/libkclvm.dylib", - f"{os.path.dirname(__file__)}/../runtime/target/debug/libkclvm.so", - f"{os.path.dirname(__file__)}/../runtime/target/debug/kclvm.dll", - ] - - for s in pathList: - if os.path.exists(s): - return s - return "" - - -class KclvmRuntimeDylib: - def __init__(self, dllpath: str = None): - if dllpath is None: - dllpath = _find_default_dylib_path() - if not dllpath: - raise f"kclvm runtime lib not found" - - self.dllpath = dllpath - self._app_dll = ctypes.cdll.LoadLibrary(dllpath) - self._app_lib = ctypes.CDLL(dllpath) - self.ctx = None - - # kclvm_context_t* kclvm_context_new(); - self._app_lib.kclvm_context_new.restype = ctypes.c_void_p - - # void kclvm_context_delete(kclvm_context_t* p); - self._app_lib.kclvm_context_delete.argtypes = [ - ctypes.c_void_p, - ] - - # const char* kclvm_context_invoke(kclvm_context_t* p, const char* method, const char* args, const char* kwargs); - self._app_lib.kclvm_context_invoke.restype = ctypes.c_char_p - self._app_lib.kclvm_context_invoke.argtypes = [ - ctypes.c_void_p, - ctypes.c_char_p, - ctypes.c_char_p, - ctypes.c_char_p, - ] - - def _kclvm_context_new(self) -> ctypes.c_void_p: - return self._app_lib.kclvm_context_new() - - def kclvm_context_delete(self, ctx: ctypes.c_void_p): - self._app_lib.kclvm_context_delete(ctx) - - def _kclvm_context_invoke( - self, ctx: ctypes.c_void_p, method: str, args: str, kwargs: str - ) -> any: - jsonValue = self._app_lib.kclvm_context_invoke( - ctx, method.encode(), args.encode(), kwargs.encode() - ) - return json.loads(jsonValue) - - def Path(self) -> str: - return self.dllpath - - def Invoke(self, method: str, *args, **kwargs) -> any: - if self.ctx is None: - self.ctx = self._kclvm_context_new() - - if not method.startswith("kclvm_"): - if method.startswith("str."): - # str.startswith => kclvm_builtin_str_startswith - method = f'kclvm_builtin_{method.replace(".", "_")}' - elif "." in method: - # regex.match => kclvm_regex_match - method = f'kclvm_{method.replace(".", "_")}' # json.encode => kclvm_json_encode - else: - method = f"kclvm_builtin_{method}" # print => kclvm_builtin_print - - return self._kclvm_context_invoke( - self.ctx, method, json.dumps(args), json.dumps(kwargs) - ) - - -if __name__ == "__main__": - dylib = KclvmRuntimeDylib() - dylib.Invoke(f"print", "hello kclvm") diff --git a/kclvm/plugin/readme.md b/kclvm/plugin/readme.md deleted file mode 100644 index 3132958d4..000000000 --- a/kclvm/plugin/readme.md +++ /dev/null @@ -1 +0,0 @@ -# KCLVM Plugin diff --git a/kclvm/plugin/setup.py b/kclvm/plugin/setup.py deleted file mode 100644 index 93daf026c..000000000 --- a/kclvm/plugin/setup.py +++ /dev/null @@ -1,20 +0,0 @@ -# Copyright 2021 The KCL Authors. All rights reserved. - -import os -import distutils.core - -PWD = os.path.abspath(os.path.dirname(__file__)) -kclvm_ROOT = os.path.abspath(f"{PWD}/..") - -distutils.core.setup( - name="kclvm-plugin", - version="1.0", - py_modules=["kclvm_plugin", "kclvm_runtime"], - ext_modules=[ - distutils.core.Extension( - "_kclvm_plugin", - [f"{PWD}/kclvm_plugin.cpp", f"{PWD}/kclvm_plugin_wrap.cxx"], - include_dirs=[f"{kclvm_ROOT}/runtime/src"], - ) - ], -) diff --git a/kclvm/query/Cargo.toml b/kclvm/query/Cargo.toml new file mode 100644 index 000000000..eb5bc552c --- /dev/null +++ b/kclvm/query/Cargo.toml @@ -0,0 +1,27 @@ +[package] +name = "kclvm-query" +version = "0.11.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +anyhow = "1.0" +compiler_base_session = "0.1.3" +compiler_base_macros = "0.1.1" +indexmap = "1.0" + +kclvm-ast = {path = "../ast"} +kclvm-ast-pretty = {path = "../ast_pretty"} +kclvm-parser = {path = "../parser"} +kclvm-sema = {path = "../sema"} +kclvm-error = {path = "../error"} +kclvm-utils ={ path = "../utils"} +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" +fancy-regex = "0.7.1" +maplit = "1.0.2" + +[dev-dependencies] +pretty_assertions = "1.2.1" +insta = "1.8.0" diff --git a/kclvm/query/src/lib.rs b/kclvm/query/src/lib.rs new file mode 100644 index 000000000..88d25b3a8 --- /dev/null +++ b/kclvm/query/src/lib.rs @@ -0,0 +1,113 @@ +//! This package is mainly the implementation of the KCL query tool, mainly including +//! KCL code modification `override` and other implementations. We can call the `override_file` +//! function to modify the file. The main principle is to parse the AST according to the +//! input file name, and according to the ast::OverrideSpec transforms the nodes in the +//! AST, recursively modifying or deleting the values of the nodes in the AST. +pub mod node; +pub mod r#override; +pub mod path; +pub mod query; +pub mod selector; + +#[cfg(test)] +mod tests; +mod util; + +use anyhow::{anyhow, Result}; +use kclvm_ast_pretty::print_ast_module; +use kclvm_error::diagnostic::Errors; +use kclvm_parser::parse_single_file; + +use kclvm_sema::pre_process::fix_config_expr_nest_attr; +pub use query::{get_schema_type, GetSchemaOption}; +pub use r#override::{apply_override_on_module, apply_overrides}; + +/// Override and rewrite a file with override specifications. Please note that this is an external user API, +/// and it can directly modify the KCL file in place. +/// +/// # Parameters +/// +/// `file`: [&str] +/// The File that need to be overridden +/// +/// `specs`: &\[[String]\] +/// List of specs that need to be overridden. +/// Each spec string satisfies the form: := or :- +/// When the pkgpath is '__main__', `:` can be omitted. +/// +/// `import_paths`: &\[[String]\] +/// List of import paths that are need to be added. +/// +/// # Returns +/// +/// result: [Result] +/// Whether the file has been modified. +/// +/// # Examples +/// +/// ```no_run +/// use kclvm_query::override_file; +/// +/// let result = override_file( +/// "test.k", +/// &["alice.age=18".to_string()], +/// &[] +/// ).unwrap(); +/// ``` +/// +/// - test.k (before override) +/// +/// ```kcl +/// schema Person: +/// age: int +/// +/// alice = Person { +/// age = 10 +/// } +/// ``` +/// +/// - test.k (after override) +/// +/// ```kcl +/// schema Person: +/// age: int +/// +/// alice = Person { +/// age = 18 +/// } +/// ``` +pub fn override_file( + file: &str, + specs: &[String], + import_paths: &[String], +) -> Result { + // Parse file to AST module. + let mut parse_result = match parse_single_file(file, None) { + Ok(module) => module, + Err(msg) => return Err(anyhow!("{}", msg)), + }; + let mut result = false; + // Override AST module. + for s in specs { + if apply_override_on_module(&mut parse_result.module, s, import_paths)? { + result = true; + } + } + + // Transform config expr to simplify the config path query and override. + fix_config_expr_nest_attr(&mut parse_result.module); + // Print AST module. + if result { + let code_str = print_ast_module(&parse_result.module); + std::fs::write(file, code_str)? + } + Ok(OverrideFileResult { + result, + parse_errors: parse_result.errors, + }) +} + +pub struct OverrideFileResult { + pub result: bool, + pub parse_errors: Errors, +} diff --git a/kclvm/query/src/main.k b/kclvm/query/src/main.k new file mode 100644 index 000000000..c18ce614d --- /dev/null +++ b/kclvm/query/src/main.k @@ -0,0 +1,18 @@ +a = [1, 2, 3, 4] +b = { + "c": "d", +} + +_part1 = { + a = "b" +} + +_part2 = { + c = "d" +} + +_list0 = [1, 2, 3] +_list1 = [4, 5, 6] +union_list = [*_list0, *_list1] + +a_dict = {**_part1, **_part2} # {"a: "b", "c": "d"} diff --git a/kclvm/query/src/node.rs b/kclvm/query/src/node.rs new file mode 100644 index 000000000..3439db732 --- /dev/null +++ b/kclvm/query/src/node.rs @@ -0,0 +1,765 @@ +use kclvm_ast::{ + ast::{self}, + walker::MutSelfMutWalker, +}; + +use kclvm_ast::walk_if_mut; +use kclvm_ast::walk_list_mut; + +/// `AstNodeMover` will move the AST node by offset +pub struct AstNodeMover { + pub line_offset: usize, +} + +impl<'ctx> MutSelfMutWalker<'ctx> for AstNodeMover { + fn walk_expr_stmt(&mut self, expr_stmt: &'ctx mut ast::ExprStmt) { + for expr in expr_stmt.exprs.iter_mut() { + expr.line += self.line_offset as u64; + expr.end_line += self.line_offset as u64; + } + + for expr in expr_stmt.exprs.iter_mut() { + self.walk_expr(&mut expr.node) + } + } + fn walk_type_alias_stmt(&mut self, type_alias_stmt: &'ctx mut ast::TypeAliasStmt) { + type_alias_stmt.type_name.line += self.line_offset as u64; + type_alias_stmt.type_name.end_line += self.line_offset as u64; + + type_alias_stmt.ty.line += self.line_offset as u64; + type_alias_stmt.ty.end_line += self.line_offset as u64; + + self.walk_identifier(&mut type_alias_stmt.type_name.node); + self.walk_type(&mut type_alias_stmt.ty.node); + } + fn walk_unification_stmt(&mut self, unification_stmt: &'ctx mut ast::UnificationStmt) { + unification_stmt.target.line += self.line_offset as u64; + unification_stmt.target.end_line += self.line_offset as u64; + + unification_stmt.value.line += self.line_offset as u64; + unification_stmt.value.end_line += self.line_offset as u64; + + self.walk_identifier(&mut unification_stmt.target.node); + self.walk_schema_expr(&mut unification_stmt.value.node); + } + fn walk_assign_stmt(&mut self, assign_stmt: &'ctx mut ast::AssignStmt) { + for target in assign_stmt.targets.iter_mut() { + target.line += self.line_offset as u64; + target.end_line += self.line_offset as u64; + } + + assign_stmt.value.line += self.line_offset as u64; + assign_stmt.value.end_line += self.line_offset as u64; + + match assign_stmt.ty.as_deref_mut() { + Some(v) => { + v.line += self.line_offset as u64; + v.end_line += self.line_offset as u64; + } + None => (), + } + + for target in assign_stmt.targets.iter_mut() { + self.walk_target(&mut target.node) + } + self.walk_expr(&mut assign_stmt.value.node); + walk_if_mut!(self, walk_type, assign_stmt.ty) + } + fn walk_aug_assign_stmt(&mut self, aug_assign_stmt: &'ctx mut ast::AugAssignStmt) { + aug_assign_stmt.target.line += self.line_offset as u64; + aug_assign_stmt.target.end_line += self.line_offset as u64; + + aug_assign_stmt.value.line += self.line_offset as u64; + aug_assign_stmt.value.end_line += self.line_offset as u64; + + self.walk_target(&mut aug_assign_stmt.target.node); + self.walk_expr(&mut aug_assign_stmt.value.node); + } + fn walk_assert_stmt(&mut self, assert_stmt: &'ctx mut ast::AssertStmt) { + assert_stmt.test.line += self.line_offset as u64; + assert_stmt.test.end_line += self.line_offset as u64; + + match assert_stmt.if_cond.as_deref_mut() { + Some(v) => { + v.line += self.line_offset as u64; + v.end_line += self.line_offset as u64; + } + None => (), + } + + match assert_stmt.msg.as_deref_mut() { + Some(v) => { + v.line += self.line_offset as u64; + v.end_line += self.line_offset as u64; + } + None => (), + } + + self.walk_expr(&mut assert_stmt.test.node); + walk_if_mut!(self, walk_expr, assert_stmt.if_cond); + walk_if_mut!(self, walk_expr, assert_stmt.msg); + } + fn walk_if_stmt(&mut self, if_stmt: &'ctx mut ast::IfStmt) { + if_stmt.cond.line += self.line_offset as u64; + if_stmt.cond.end_line += self.line_offset as u64; + + for stmt in if_stmt.body.iter_mut() { + stmt.line += self.line_offset as u64; + stmt.end_line += self.line_offset as u64; + } + + for stmt in if_stmt.orelse.iter_mut() { + stmt.line += self.line_offset as u64; + stmt.end_line += self.line_offset as u64; + } + + self.walk_expr(&mut if_stmt.cond.node); + walk_list_mut!(self, walk_stmt, if_stmt.body); + walk_list_mut!(self, walk_stmt, if_stmt.orelse); + } + fn walk_import_stmt(&mut self, _import_stmt: &'ctx mut ast::ImportStmt) { + // Nothing to do + } + fn walk_schema_attr(&mut self, schema_attr: &'ctx mut ast::SchemaAttr) { + schema_attr.name.line += self.line_offset as u64; + schema_attr.name.end_line += self.line_offset as u64; + + match schema_attr.value.as_deref_mut() { + Some(v) => { + v.line += self.line_offset as u64; + v.end_line += self.line_offset as u64; + } + None => (), + } + + schema_attr.decorators.iter_mut().for_each(|d| { + d.line += self.line_offset as u64; + d.end_line += self.line_offset as u64; + }); + + schema_attr.ty.line += self.line_offset as u64; + schema_attr.ty.end_line += self.line_offset as u64; + + walk_list_mut!(self, walk_call_expr, schema_attr.decorators); + walk_if_mut!(self, walk_expr, schema_attr.value); + self.walk_type(&mut schema_attr.ty.node); + } + + fn walk_type(&mut self, ty: &'ctx mut ast::Type) { + match ty { + ast::Type::Named(id) => self.walk_identifier(id), + ast::Type::List(list_ty) => { + if let Some(ty) = &mut list_ty.inner_type { + ty.line += self.line_offset as u64; + ty.end_line += self.line_offset as u64; + self.walk_type(&mut ty.node) + } + } + ast::Type::Dict(dict_ty) => { + if let Some(ty) = &mut dict_ty.key_type { + ty.line += self.line_offset as u64; + ty.end_line += self.line_offset as u64; + self.walk_type(&mut ty.node) + } + if let Some(ty) = &mut dict_ty.value_type { + ty.line += self.line_offset as u64; + ty.end_line += self.line_offset as u64; + self.walk_type(&mut ty.node) + } + } + ast::Type::Union(union_ty) => { + union_ty.type_elements.iter_mut().for_each(|ty| { + ty.line += self.line_offset as u64; + ty.end_line += self.line_offset as u64; + self.walk_type(&mut ty.node) + }); + } + _ => {} + } + } + fn walk_schema_stmt(&mut self, schema_stmt: &'ctx mut ast::SchemaStmt) { + schema_stmt.name.line += self.line_offset as u64; + schema_stmt.name.end_line += self.line_offset as u64; + + match schema_stmt.parent_name.as_deref_mut() { + Some(v) => { + v.line += self.line_offset as u64; + v.end_line += self.line_offset as u64; + } + None => (), + } + + match schema_stmt.for_host_name.as_deref_mut() { + Some(v) => { + v.line += self.line_offset as u64; + v.end_line += self.line_offset as u64; + } + None => (), + } + + for arg in schema_stmt.args.iter_mut() { + arg.line += self.line_offset as u64; + arg.end_line += self.line_offset as u64; + } + + if let Some(schema_index_signature) = schema_stmt.index_signature.as_deref_mut() { + let value = &mut schema_index_signature.node.value; + match value.as_deref_mut() { + Some(v) => { + v.line += self.line_offset as u64; + v.end_line += self.line_offset as u64; + } + None => (), + } + } + + schema_stmt.mixins.iter_mut().for_each(|m| { + m.line += self.line_offset as u64; + m.end_line += self.line_offset as u64; + }); + + schema_stmt.decorators.iter_mut().for_each(|d| { + d.line += self.line_offset as u64; + d.end_line += self.line_offset as u64; + }); + + schema_stmt.checks.iter_mut().for_each(|c| { + c.line += self.line_offset as u64; + c.end_line += self.line_offset as u64; + }); + + schema_stmt.body.iter_mut().for_each(|s| { + s.line += self.line_offset as u64; + s.end_line += self.line_offset as u64; + }); + + walk_if_mut!(self, walk_identifier, schema_stmt.parent_name); + walk_if_mut!(self, walk_identifier, schema_stmt.for_host_name); + walk_if_mut!(self, walk_arguments, schema_stmt.args); + if let Some(schema_index_signature) = schema_stmt.index_signature.as_deref_mut() { + let value = &mut schema_index_signature.node.value; + walk_if_mut!(self, walk_expr, value); + } + walk_list_mut!(self, walk_identifier, schema_stmt.mixins); + walk_list_mut!(self, walk_call_expr, schema_stmt.decorators); + walk_list_mut!(self, walk_check_expr, schema_stmt.checks); + walk_list_mut!(self, walk_stmt, schema_stmt.body); + } + fn walk_rule_stmt(&mut self, rule_stmt: &'ctx mut ast::RuleStmt) { + rule_stmt.name.line += self.line_offset as u64; + rule_stmt.name.end_line += self.line_offset as u64; + + rule_stmt.parent_rules.iter_mut().for_each(|p| { + p.line += self.line_offset as u64; + p.end_line += self.line_offset as u64; + }); + + rule_stmt.decorators.iter_mut().for_each(|d| { + d.line += self.line_offset as u64; + d.end_line += self.line_offset as u64; + }); + + rule_stmt.checks.iter_mut().for_each(|c| { + c.line += self.line_offset as u64; + c.end_line += self.line_offset as u64; + }); + + rule_stmt.args.iter_mut().for_each(|a| { + a.line += self.line_offset as u64; + a.end_line += self.line_offset as u64; + }); + + match rule_stmt.for_host_name.as_deref_mut() { + Some(v) => { + v.line += self.line_offset as u64; + v.end_line += self.line_offset as u64; + } + None => (), + } + + walk_list_mut!(self, walk_identifier, rule_stmt.parent_rules); + walk_list_mut!(self, walk_call_expr, rule_stmt.decorators); + walk_list_mut!(self, walk_check_expr, rule_stmt.checks); + walk_if_mut!(self, walk_arguments, rule_stmt.args); + walk_if_mut!(self, walk_identifier, rule_stmt.for_host_name); + } + fn walk_quant_expr(&mut self, quant_expr: &'ctx mut ast::QuantExpr) { + quant_expr.target.line += self.line_offset as u64; + quant_expr.target.end_line += self.line_offset as u64; + + quant_expr.variables.iter_mut().for_each(|v| { + v.line += self.line_offset as u64; + v.end_line += self.line_offset as u64; + }); + + quant_expr.test.line += self.line_offset as u64; + quant_expr.test.end_line += self.line_offset as u64; + + match quant_expr.if_cond.as_deref_mut() { + Some(v) => { + v.line += self.line_offset as u64; + v.end_line += self.line_offset as u64; + } + None => (), + } + + self.walk_expr(&mut quant_expr.target.node); + walk_list_mut!(self, walk_identifier, quant_expr.variables); + self.walk_expr(&mut quant_expr.test.node); + walk_if_mut!(self, walk_expr, quant_expr.if_cond); + } + fn walk_if_expr(&mut self, if_expr: &'ctx mut ast::IfExpr) { + if_expr.cond.line += self.line_offset as u64; + if_expr.cond.end_line += self.line_offset as u64; + + if_expr.body.line += self.line_offset as u64; + if_expr.body.end_line += self.line_offset as u64; + + if_expr.orelse.line += self.line_offset as u64; + if_expr.orelse.end_line += self.line_offset as u64; + + self.walk_expr(&mut if_expr.cond.node); + self.walk_expr(&mut if_expr.body.node); + self.walk_expr(&mut if_expr.orelse.node); + } + fn walk_unary_expr(&mut self, unary_expr: &'ctx mut ast::UnaryExpr) { + unary_expr.operand.line += self.line_offset as u64; + unary_expr.operand.end_line += self.line_offset as u64; + + self.walk_expr(&mut unary_expr.operand.node); + } + fn walk_binary_expr(&mut self, binary_expr: &'ctx mut ast::BinaryExpr) { + binary_expr.left.line += self.line_offset as u64; + binary_expr.left.end_line += self.line_offset as u64; + + self.walk_expr(&mut binary_expr.left.node); + self.walk_expr(&mut binary_expr.right.node); + } + fn walk_selector_expr(&mut self, selector_expr: &'ctx mut ast::SelectorExpr) { + selector_expr.value.line += self.line_offset as u64; + selector_expr.value.end_line += self.line_offset as u64; + + self.walk_expr(&mut selector_expr.value.node); + self.walk_identifier(&mut selector_expr.attr.node); + } + fn walk_call_expr(&mut self, call_expr: &'ctx mut ast::CallExpr) { + call_expr.func.line += self.line_offset as u64; + call_expr.func.end_line += self.line_offset as u64; + + call_expr.args.iter_mut().for_each(|a| { + a.line += self.line_offset as u64; + a.end_line += self.line_offset as u64; + }); + + call_expr.keywords.iter_mut().for_each(|k| { + k.line += self.line_offset as u64; + k.end_line += self.line_offset as u64; + }); + + self.walk_expr(&mut call_expr.func.node); + walk_list_mut!(self, walk_expr, call_expr.args); + walk_list_mut!(self, walk_keyword, call_expr.keywords); + } + fn walk_subscript(&mut self, subscript: &'ctx mut ast::Subscript) { + subscript.value.line += self.line_offset as u64; + subscript.value.end_line += self.line_offset as u64; + + match subscript.index.as_deref_mut() { + Some(v) => { + v.line += self.line_offset as u64; + v.end_line += self.line_offset as u64; + } + None => (), + } + + match subscript.lower.as_deref_mut() { + Some(v) => { + v.line += self.line_offset as u64; + v.end_line += self.line_offset as u64; + } + None => (), + } + + match subscript.upper.as_deref_mut() { + Some(v) => { + v.line += self.line_offset as u64; + v.end_line += self.line_offset as u64; + } + None => (), + } + + match subscript.step.as_deref_mut() { + Some(v) => { + v.line += self.line_offset as u64; + v.end_line += self.line_offset as u64; + } + None => (), + } + + self.walk_expr(&mut subscript.value.node); + walk_if_mut!(self, walk_expr, subscript.index); + walk_if_mut!(self, walk_expr, subscript.lower); + walk_if_mut!(self, walk_expr, subscript.upper); + walk_if_mut!(self, walk_expr, subscript.step); + } + fn walk_paren_expr(&mut self, paren_expr: &'ctx mut ast::ParenExpr) { + paren_expr.expr.line += self.line_offset as u64; + paren_expr.expr.end_line += self.line_offset as u64; + + self.walk_expr(&mut paren_expr.expr.node); + } + fn walk_list_expr(&mut self, list_expr: &'ctx mut ast::ListExpr) { + list_expr.elts.iter_mut().for_each(|e| { + e.line += self.line_offset as u64; + e.end_line += self.line_offset as u64; + }); + walk_list_mut!(self, walk_expr, list_expr.elts); + } + fn walk_list_comp(&mut self, list_comp: &'ctx mut ast::ListComp) { + list_comp.elt.line += self.line_offset as u64; + list_comp.elt.end_line += self.line_offset as u64; + + list_comp.generators.iter_mut().for_each(|g| { + g.line += self.line_offset as u64; + g.end_line += self.line_offset as u64; + }); + + self.walk_expr(&mut list_comp.elt.node); + walk_list_mut!(self, walk_comp_clause, list_comp.generators); + } + fn walk_list_if_item_expr(&mut self, list_if_item_expr: &'ctx mut ast::ListIfItemExpr) { + list_if_item_expr.if_cond.line += self.line_offset as u64; + list_if_item_expr.if_cond.end_line += self.line_offset as u64; + + list_if_item_expr.exprs.iter_mut().for_each(|e| { + e.line += self.line_offset as u64; + e.end_line += self.line_offset as u64; + }); + + match list_if_item_expr.orelse.as_deref_mut() { + Some(v) => { + v.line += self.line_offset as u64; + v.end_line += self.line_offset as u64; + } + None => (), + } + + self.walk_expr(&mut list_if_item_expr.if_cond.node); + walk_list_mut!(self, walk_expr, list_if_item_expr.exprs); + walk_if_mut!(self, walk_expr, list_if_item_expr.orelse); + } + fn walk_starred_expr(&mut self, starred_expr: &'ctx mut ast::StarredExpr) { + starred_expr.value.line += self.line_offset as u64; + starred_expr.value.end_line += self.line_offset as u64; + self.walk_expr(&mut starred_expr.value.node); + } + fn walk_dict_comp(&mut self, dict_comp: &'ctx mut ast::DictComp) { + if let Some(key) = &mut dict_comp.entry.key { + key.line += self.line_offset as u64; + key.end_line += self.line_offset as u64; + } + + dict_comp.entry.value.line += self.line_offset as u64; + dict_comp.entry.value.end_line += self.line_offset as u64; + + dict_comp.generators.iter_mut().for_each(|g| { + g.line += self.line_offset as u64; + g.end_line += self.line_offset as u64; + }); + + if let Some(key) = &mut dict_comp.entry.key { + self.walk_expr(&mut key.node); + } + self.walk_expr(&mut dict_comp.entry.value.node); + walk_list_mut!(self, walk_comp_clause, dict_comp.generators); + } + fn walk_config_if_entry_expr( + &mut self, + config_if_entry_expr: &'ctx mut ast::ConfigIfEntryExpr, + ) { + config_if_entry_expr.if_cond.line += self.line_offset as u64; + config_if_entry_expr.if_cond.end_line += self.line_offset as u64; + + for config_entry in config_if_entry_expr.items.iter_mut() { + match config_entry.node.key.as_deref_mut() { + Some(k) => { + k.line += self.line_offset as u64; + k.end_line += self.line_offset as u64; + } + None => (), + } + + config_entry.node.value.line += self.line_offset as u64; + } + + match config_if_entry_expr.orelse.as_deref_mut() { + Some(v) => { + v.line += self.line_offset as u64; + v.end_line += self.line_offset as u64; + } + None => (), + } + + self.walk_expr(&mut config_if_entry_expr.if_cond.node); + for config_entry in config_if_entry_expr.items.iter_mut() { + walk_if_mut!(self, walk_expr, config_entry.node.key); + self.walk_expr(&mut config_entry.node.value.node); + } + walk_if_mut!(self, walk_expr, config_if_entry_expr.orelse); + } + fn walk_comp_clause(&mut self, comp_clause: &'ctx mut ast::CompClause) { + comp_clause.iter.line += self.line_offset as u64; + comp_clause.iter.end_line += self.line_offset as u64; + + comp_clause.targets.iter_mut().for_each(|t| { + t.line += self.line_offset as u64; + t.end_line += self.line_offset as u64; + }); + + comp_clause.ifs.iter_mut().for_each(|i| { + i.line += self.line_offset as u64; + i.end_line += self.line_offset as u64; + }); + + walk_list_mut!(self, walk_identifier, comp_clause.targets); + self.walk_expr(&mut comp_clause.iter.node); + walk_list_mut!(self, walk_expr, comp_clause.ifs); + } + fn walk_schema_expr(&mut self, schema_expr: &'ctx mut ast::SchemaExpr) { + schema_expr.name.line += self.line_offset as u64; + schema_expr.name.end_line += self.line_offset as u64; + + schema_expr.args.iter_mut().for_each(|a| { + a.line += self.line_offset as u64; + a.end_line += self.line_offset as u64; + }); + + schema_expr.kwargs.iter_mut().for_each(|k| { + k.line += self.line_offset as u64; + k.end_line += self.line_offset as u64; + }); + + schema_expr.config.line += self.line_offset as u64; + schema_expr.config.end_line += self.line_offset as u64; + + self.walk_identifier(&mut schema_expr.name.node); + walk_list_mut!(self, walk_expr, schema_expr.args); + walk_list_mut!(self, walk_keyword, schema_expr.kwargs); + self.walk_expr(&mut schema_expr.config.node); + } + fn walk_config_expr(&mut self, config_expr: &'ctx mut ast::ConfigExpr) { + for config_entry in config_expr.items.iter_mut() { + match config_entry.node.key.as_deref_mut() { + Some(k) => { + k.line += self.line_offset as u64; + k.end_line += self.line_offset as u64; + } + None => (), + } + + config_entry.node.value.line += self.line_offset as u64; + } + + for config_entry in config_expr.items.iter_mut() { + walk_if_mut!(self, walk_expr, config_entry.node.key); + self.walk_expr(&mut config_entry.node.value.node); + } + } + fn walk_check_expr(&mut self, check_expr: &'ctx mut ast::CheckExpr) { + check_expr.test.line += self.line_offset as u64; + check_expr.test.end_line += self.line_offset as u64; + + match check_expr.if_cond.as_deref_mut() { + Some(v) => { + v.line += self.line_offset as u64; + v.end_line += self.line_offset as u64; + } + None => (), + } + + match check_expr.msg.as_deref_mut() { + Some(v) => { + v.line += self.line_offset as u64; + v.end_line += self.line_offset as u64; + } + None => (), + } + + self.walk_expr(&mut check_expr.test.node); + walk_if_mut!(self, walk_expr, check_expr.if_cond); + walk_if_mut!(self, walk_expr, check_expr.msg); + } + fn walk_lambda_expr(&mut self, lambda_expr: &'ctx mut ast::LambdaExpr) { + match lambda_expr.args.as_deref_mut() { + Some(v) => { + v.line += self.line_offset as u64; + v.end_line += self.line_offset as u64; + } + None => (), + } + + for stmt in lambda_expr.body.iter_mut() { + stmt.line += self.line_offset as u64; + stmt.end_line += self.line_offset as u64; + } + + match lambda_expr.return_ty.as_deref_mut() { + Some(v) => { + v.line += self.line_offset as u64; + v.end_line += self.line_offset as u64; + } + None => (), + } + + walk_if_mut!(self, walk_arguments, lambda_expr.args); + walk_list_mut!(self, walk_stmt, lambda_expr.body); + walk_if_mut!(self, walk_type, lambda_expr.return_ty); + } + fn walk_keyword(&mut self, keyword: &'ctx mut ast::Keyword) { + keyword.arg.line += self.line_offset as u64; + keyword.arg.end_line += self.line_offset as u64; + + if let Some(v) = keyword.value.as_deref_mut() { + v.line += self.line_offset as u64; + v.end_line += self.line_offset as u64; + } + + self.walk_identifier(&mut keyword.arg.node); + if let Some(v) = keyword.value.as_deref_mut() { + self.walk_expr(&mut v.node) + } + } + fn walk_arguments(&mut self, arguments: &'ctx mut ast::Arguments) { + arguments.args.iter_mut().for_each(|a| { + a.line += self.line_offset as u64; + a.end_line += self.line_offset as u64; + }); + + for default in arguments.defaults.iter_mut() { + if let Some(d) = default.as_deref_mut() { + d.line += self.line_offset as u64; + d.end_line += self.line_offset as u64; + } + } + for ty in arguments.ty_list.iter_mut() { + if let Some(ty) = ty.as_deref_mut() { + ty.line += self.line_offset as u64; + ty.end_line += self.line_offset as u64; + } + } + + walk_list_mut!(self, walk_identifier, arguments.args); + for default in arguments.defaults.iter_mut() { + if let Some(d) = default.as_deref_mut() { + self.walk_expr(&mut d.node) + } + } + for ty in arguments.ty_list.iter_mut() { + if let Some(ty) = ty.as_deref_mut() { + self.walk_type(&mut ty.node); + } + } + } + fn walk_compare(&mut self, compare: &'ctx mut ast::Compare) { + compare.left.line += self.line_offset as u64; + compare.left.end_line += self.line_offset as u64; + + for comparator in compare.comparators.iter_mut() { + comparator.line += self.line_offset as u64; + comparator.end_line += self.line_offset as u64; + } + + self.walk_expr(&mut compare.left.node); + walk_list_mut!(self, walk_expr, compare.comparators); + } + fn walk_joined_string(&mut self, joined_string: &'ctx mut ast::JoinedString) { + joined_string.values.iter_mut().for_each(|v| { + v.line += self.line_offset as u64; + v.end_line += self.line_offset as u64; + }); + + walk_list_mut!(self, walk_expr, joined_string.values); + } + fn walk_formatted_value(&mut self, formatted_value: &'ctx mut ast::FormattedValue) { + formatted_value.value.line += self.line_offset as u64; + formatted_value.value.end_line += self.line_offset as u64; + + self.walk_expr(&mut formatted_value.value.node); + } + fn walk_module(&mut self, module: &'ctx mut ast::Module) { + module.comments.iter_mut().for_each(|c| { + c.line += self.line_offset as u64; + c.end_line += self.line_offset as u64; + }); + + for stmt in module.body.iter_mut() { + if let ast::Stmt::Import(_) = stmt.node { + continue; + } + + stmt.line += self.line_offset as u64; + stmt.end_line += self.line_offset as u64; + + self.walk_stmt(&mut stmt.node) + } + } + fn walk_stmt(&mut self, stmt: &'ctx mut ast::Stmt) { + match stmt { + ast::Stmt::TypeAlias(type_alias) => self.walk_type_alias_stmt(type_alias), + ast::Stmt::Expr(expr_stmt) => self.walk_expr_stmt(expr_stmt), + ast::Stmt::Unification(unification_stmt) => { + self.walk_unification_stmt(unification_stmt) + } + ast::Stmt::Assign(assign_stmt) => self.walk_assign_stmt(assign_stmt), + ast::Stmt::AugAssign(aug_assign_stmt) => self.walk_aug_assign_stmt(aug_assign_stmt), + ast::Stmt::Assert(assert_stmt) => self.walk_assert_stmt(assert_stmt), + ast::Stmt::If(if_stmt) => self.walk_if_stmt(if_stmt), + ast::Stmt::Import(import_stmt) => self.walk_import_stmt(import_stmt), + ast::Stmt::SchemaAttr(schema_attr) => self.walk_schema_attr(schema_attr), + ast::Stmt::Schema(schema_stmt) => self.walk_schema_stmt(schema_stmt), + ast::Stmt::Rule(rule_stmt) => self.walk_rule_stmt(rule_stmt), + } + } + fn walk_expr(&mut self, expr: &'ctx mut ast::Expr) { + match expr { + ast::Expr::Target(target) => self.walk_target(target), + ast::Expr::Identifier(identifier) => self.walk_identifier(identifier), + ast::Expr::Unary(unary_expr) => self.walk_unary_expr(unary_expr), + ast::Expr::Binary(binary_expr) => self.walk_binary_expr(binary_expr), + ast::Expr::If(if_expr) => self.walk_if_expr(if_expr), + ast::Expr::Selector(selector_expr) => self.walk_selector_expr(selector_expr), + ast::Expr::Call(call_expr) => self.walk_call_expr(call_expr), + ast::Expr::Paren(paren_expr) => self.walk_paren_expr(paren_expr), + ast::Expr::Quant(quant_expr) => self.walk_quant_expr(quant_expr), + ast::Expr::List(list_expr) => self.walk_list_expr(list_expr), + ast::Expr::ListIfItem(list_if_item_expr) => { + self.walk_list_if_item_expr(list_if_item_expr) + } + ast::Expr::ListComp(list_comp) => self.walk_list_comp(list_comp), + ast::Expr::Starred(starred_expr) => self.walk_starred_expr(starred_expr), + ast::Expr::DictComp(dict_comp) => self.walk_dict_comp(dict_comp), + ast::Expr::ConfigIfEntry(config_if_entry_expr) => { + self.walk_config_if_entry_expr(config_if_entry_expr) + } + ast::Expr::CompClause(comp_clause) => self.walk_comp_clause(comp_clause), + ast::Expr::Schema(schema_expr) => self.walk_schema_expr(schema_expr), + ast::Expr::Config(config_expr) => self.walk_config_expr(config_expr), + ast::Expr::Check(check) => self.walk_check_expr(check), + ast::Expr::Lambda(lambda) => self.walk_lambda_expr(lambda), + ast::Expr::Subscript(subscript) => self.walk_subscript(subscript), + ast::Expr::Keyword(keyword) => self.walk_keyword(keyword), + ast::Expr::Arguments(arguments) => self.walk_arguments(arguments), + ast::Expr::Compare(compare) => self.walk_compare(compare), + ast::Expr::NumberLit(number_lit) => self.walk_number_lit(number_lit), + ast::Expr::StringLit(string_lit) => self.walk_string_lit(string_lit), + ast::Expr::NameConstantLit(name_constant_lit) => { + self.walk_name_constant_lit(name_constant_lit) + } + ast::Expr::JoinedString(joined_string) => self.walk_joined_string(joined_string), + ast::Expr::FormattedValue(formatted_value) => { + self.walk_formatted_value(formatted_value) + } + ast::Expr::Missing(missing_expr) => self.walk_missing_expr(missing_expr), + } + } +} diff --git a/kclvm/query/src/override.rs b/kclvm/query/src/override.rs new file mode 100644 index 000000000..68cc7f47d --- /dev/null +++ b/kclvm/query/src/override.rs @@ -0,0 +1,947 @@ +use std::collections::HashSet; + +use anyhow::{anyhow, Result}; + +use compiler_base_macros::bug; +use kclvm_ast::config::try_get_config_expr_mut; +use kclvm_ast::path::{get_key_parts, get_key_path}; +use kclvm_ast::walk_list_mut; +use kclvm_ast::walker::MutSelfMutWalker; +use kclvm_ast::MAIN_PKG; +use kclvm_ast::{ast, path::get_target_path}; +use kclvm_ast_pretty::print_ast_module; +use kclvm_parser::parse_expr; +use kclvm_sema::pre_process::{fix_config_expr_nest_attr, transform_multi_assign}; + +use crate::{node::AstNodeMover, path::parse_attribute_path}; + +use super::util::invalid_spec_error; + +/// Import statement column offset always start with 1. +/// todo: The (1-based) column offset needs to be constrained by specifications. +const IMPORT_STMT_COLUMN_OFFSET: u64 = 1; + +/// Apply overrides on the AST program with the override specifications. +/// +/// Please note that this a low level internal API used by compiler itself, +/// The parameters of the method are all compiler internal concepts such as +/// AST, etc. +/// +/// # Examples +/// +/// ```no_check +/// use kclvm_parser::load_program; +/// use kclvm_tools::query::r#override::apply_overrides; +/// +/// let mut prog = load_program(&["config.k"], None, None).unwrap(); +/// let overrides = vec![parse_override_spec("config.id=1").unwrap()]; +/// let import_paths = vec!["path.to.pkg".to_string()]; +/// let result = apply_overrides(&mut prog, &overrides, &import_paths, true).unwrap(); +/// ``` +pub fn apply_overrides( + prog: &mut ast::Program, + overrides: &[String], + import_paths: &[String], + print_ast: bool, +) -> Result<()> { + for o in overrides { + if let Some(modules) = prog.pkgs.get(MAIN_PKG) { + for m in modules.iter() { + let mut m = prog + .get_module_mut(m) + .expect("Failed to acquire module lock") + .expect(&format!("module {:?} not found in program", m)); + if apply_override_on_module(&mut m, o, import_paths)? && print_ast { + let code_str = print_ast_module(&m); + std::fs::write(&m.filename, &code_str)? + } + } + } + } + Ok(()) +} + +/// Build a expression from string. +pub fn build_expr_from_string(value: &str) -> Option> { + let expr: Option> = parse_expr(value); + match &expr { + Some(e) => match &e.node { + // fix attr=value to attr="value" + ast::Expr::Unary(_) | ast::Expr::Binary(_) => { + Some(ast::NodeRef::new(ast::Node::node_with_pos( + ast::Expr::StringLit(ast::StringLit { + is_long_string: false, + raw_value: format!("{value:?}"), + value: value.to_string(), + }), + e.pos(), + ))) + } + _ => expr, + }, + None => None, + } +} + +/// Apply overrides on the AST module with the override specifications. +/// +/// Please note that this a low level internal API used by compiler itself, +/// The parameters of the method are all compiler internal concepts such as +/// AST, etc. +/// +/// # Examples +/// +/// ```no_check +/// use kclvm_parser::parse_file_force_errors; +/// use kclvm_tools::query::apply_override_on_module; +/// +/// let mut module = parse_file_force_errors("", None).unwrap(); +/// let override_spec = parse_override_spec("config.id=1").unwrap(); +/// let import_paths = vec!["path.to.pkg".to_string()]; +/// let result = apply_override_on_module(&mut module, override_spec, &import_paths).unwrap(); +/// ``` +pub fn apply_override_on_module( + m: &mut ast::Module, + o: &str, + import_paths: &[String], +) -> Result { + // Apply import paths on AST module. + apply_import_paths_on_module(m, import_paths)?; + let o = parse_override_spec(o)?; + let ss = parse_attribute_path(&o.field_path)?; + let default = String::default(); + let target_id = ss.get(0).unwrap_or(&default); + let value = &o.field_value; + let key = ast::Identifier { + names: ss[1..] + .iter() + .map(|s| ast::Node::dummy_node(s.to_string())) + .collect(), + ctx: ast::ExprContext::Store, + pkgpath: "".to_string(), + }; + // Transform config expr to simplify the config path query and override. + fix_config_expr_nest_attr(m); + // When there is a multi-target assignment statement of the form `a = b = Config {}`, + // it needs to be transformed into the following form first to prevent the configuration + // from being incorrectly modified. + // ```kcl + // a = Config {} + // b = Config {} + // ``` + transform_multi_assign(m); + let mut transformer = OverrideTransformer { + target_id: target_id.to_string(), + field_paths: ss[1..].to_vec(), + override_key: key, + override_value: build_expr_from_string(value), + override_target_count: 0, + has_override: false, + action: o.action, + operation: o.operation, + }; + transformer.walk_module(m); + Ok(transformer.has_override) +} + +/// Parse override spec string to override structure. +/// +/// parse_override_spec("alice.age=10") -> ast::OverrideSpec { +/// pkgpath: "".to_string(), +/// field_path: "alice.age".to_string(), +/// field_value: "10".to_string(), +/// action: ast::OverrideAction::CreateOrUpdate, +/// } +pub fn parse_override_spec(spec: &str) -> Result { + if let Some((path, value, operation)) = split_override_spec_op(spec) { + // Create or update the override value. + let field_path = path.trim().to_string(); + let field_value = value.trim().to_string(); + if field_path.is_empty() || field_value.is_empty() { + Err(invalid_spec_error(spec)) + } else { + Ok(ast::OverrideSpec { + field_path, + field_value, + action: ast::OverrideAction::CreateOrUpdate, + operation, + }) + } + } else if let Some(stripped_spec) = spec.strip_suffix('-') { + // Delete the override value. + let field_path = stripped_spec.trim().to_string(); + if field_path.is_empty() { + Err(invalid_spec_error(spec)) + } else { + Ok(ast::OverrideSpec { + field_path: stripped_spec.trim().to_string(), + field_value: "".to_string(), + action: ast::OverrideAction::Delete, + operation: ast::ConfigEntryOperation::Override, + }) + } + } else { + Err(invalid_spec_error(spec)) + } +} + +/// split_override_spec_op split the override_spec and do not split the override_op in list +/// expr, dict expr and string e.g., "a.b=1" -> (a.b, 1, =), "a["a=1"]=1" -> (a["a=1"], =, 1) +pub fn split_override_spec_op(spec: &str) -> Option<(String, String, ast::ConfigEntryOperation)> { + let mut i = 0; + let mut stack = String::new(); + while i < spec.chars().count() { + let (c_idx, c) = spec.char_indices().nth(i).unwrap(); + if c == '=' && stack.is_empty() { + return Some(( + spec[..c_idx].to_string(), + spec[c_idx + 1..].to_string(), + ast::ConfigEntryOperation::Override, + )); + } else if c == ':' && stack.is_empty() { + return Some(( + spec[..c_idx].to_string(), + spec[c_idx + 1..].to_string(), + ast::ConfigEntryOperation::Union, + )); + } else if c == '+' && stack.is_empty() { + if let Some((c_next_idx, c_next)) = spec.char_indices().nth(i + 1) { + if c_next == '=' { + return Some(( + spec[..c_idx].to_string(), + spec[c_next_idx + 1..].to_string(), + ast::ConfigEntryOperation::Insert, + )); + } + } + } + // List/Dict type + else if c == '[' || c == '{' { + stack.push(c); + } + // List/Dict type + else if c == ']' || c == '}' { + stack.pop(); + } + // String literal type + else if c == '\"' { + let t: String = spec.chars().skip(i).collect(); + let re = fancy_regex::Regex::new(r#""(?!"").*?(? Result<()> { + if import_paths.is_empty() { + return Ok(()); + } + let mut exist_import_set: HashSet = HashSet::new(); + for stmt in &m.body { + if let ast::Stmt::Import(import_stmt) = &stmt.node { + if let Some(asname) = &import_stmt.asname { + exist_import_set.insert(format!("{} as {}", import_stmt.path.node, asname.node)); + } else { + exist_import_set.insert(import_stmt.rawpath.to_string()); + } + } + } + + let mut new_imports_count = 0; + + for (i, path) in import_paths.iter().enumerate() { + let line: u64 = i as u64 + 1; + if exist_import_set.contains(path) { + continue; + } + let name = path + .split('.') + .last() + .ok_or_else(|| anyhow!("Invalid import path {}", path))?; + let import_node = ast::ImportStmt { + path: ast::Node::dummy_node(path.to_string()), + rawpath: path.to_string(), + name: name.to_string(), + asname: None, + pkg_name: String::new(), + }; + let import_stmt = Box::new(ast::Node::new( + ast::Stmt::Import(import_node), + m.filename.clone(), + line, + IMPORT_STMT_COLUMN_OFFSET, + line, + // i denotes the space len between the `import` keyword and the path. + ("import".len() + path.len() + 1) as u64, + )); + new_imports_count += 1; + m.body.insert((line - 1) as usize, import_stmt) + } + + // Walk the AST module to update the line number of the all the nodes except the import statement. + let mut nlw = AstNodeMover { + line_offset: new_imports_count, + }; + + nlw.walk_module(m); + + Ok(()) +} + +macro_rules! override_top_level_stmt { + ($self:expr, $stmt: expr) => { + let item = $stmt.value.clone(); + let mut value = $self.clone_override_value(); + // Use position information that needs to override the expression. + value.set_pos(item.pos()); + match &$self.operation { + ast::ConfigEntryOperation::Union => { + if let ast::Expr::Config(merged_config_expr) = &value.node { + match &mut $stmt.value.node { + ast::Expr::Schema(schema_expr) => { + if let ast::Expr::Config(config_expr) = &mut schema_expr.config.node { + $self.has_override = merge_config_expr( + config_expr, + merged_config_expr, + &$self.action, + ); + } + } + ast::Expr::Config(config_expr) => { + $self.has_override = + merge_config_expr(config_expr, merged_config_expr, &$self.action); + } + _ => {} + } + } else if let ast::Expr::Schema(merged_schema_expr) = &value.node { + if let ast::Expr::Schema(schema_expr) = &mut $stmt.value.node { + if schema_expr.name.node.get_name() + == merged_schema_expr.name.node.get_name() + { + if let ( + ast::Expr::Config(merged_config_expr), + ast::Expr::Config(config_expr), + ) = ( + &merged_schema_expr.config.node, + &mut schema_expr.config.node, + ) { + $self.has_override = merge_config_expr( + config_expr, + merged_config_expr, + &$self.action, + ); + } + } + } + } else { + // Override the node value. + $stmt.value = value; + $self.has_override = true; + } + } + ast::ConfigEntryOperation::Insert => { + if let ast::Expr::List(insert_list_expr) = &value.node { + if let ast::Expr::List(list_expr) = &mut $stmt.value.node { + for value in &insert_list_expr.elts { + list_expr.elts.push(value.clone()); + } + $self.has_override = true; + } + } + } + ast::ConfigEntryOperation::Override => { + // Override the node value. + $stmt.value = value; + $self.has_override = true; + } + } + }; +} + +/// OverrideTransformer is used to walk AST and transform it with the override values. +struct OverrideTransformer { + pub target_id: String, + pub field_paths: Vec, + pub override_key: ast::Identifier, + pub override_value: Option>, + pub override_target_count: usize, + pub has_override: bool, + pub action: ast::OverrideAction, + pub operation: ast::ConfigEntryOperation, +} + +impl<'ctx> MutSelfMutWalker<'ctx> for OverrideTransformer { + // When override the global variable, it should be updated in the module level. + // Because the delete action may delete the global variable. + // TODO: combine the code of walk_module, walk_assign_stmt and walk_unification_stmt + fn walk_module(&mut self, module: &'ctx mut ast::Module) { + if self.has_override { + return; + } + match self.action { + // Walk the module body to find the target and override it. + ast::OverrideAction::CreateOrUpdate => { + module.body.iter_mut().for_each(|stmt| { + if let ast::Stmt::Assign(assign_stmt) = &mut stmt.node { + if assign_stmt.targets.len() == 1 && self.field_paths.len() == 0 { + let target = assign_stmt.targets.get(0).unwrap().node.clone(); + let target = get_target_path(&target); + if target == self.target_id { + override_top_level_stmt!(self, assign_stmt); + } + } + } else if let ast::Stmt::AugAssign(aug_assign_stmt) = &mut stmt.node { + if self.field_paths.len() == 0 { + let target = aug_assign_stmt.target.node.clone(); + let target = get_target_path(&target); + if target == self.target_id { + override_top_level_stmt!(self, aug_assign_stmt); + } + } + } else if let ast::Stmt::Unification(unification_stmt) = &mut stmt.node { + if self.field_paths.len() == 0 { + let target = match unification_stmt.target.node.names.get(0) { + Some(name) => name, + None => bug!( + "Invalid AST unification target names {:?}", + unification_stmt.target.node.names + ), + }; + if target.node == self.target_id { + let item = unification_stmt.value.clone(); + let mut value = self.clone_override_value(); + // Use position information that needs to override the expression. + value.set_pos(item.pos()); + let schema_expr = &mut unification_stmt.value.node; + match &self.operation { + ast::ConfigEntryOperation::Union => { + if let ast::Expr::Config(merged_config_expr) = &value.node { + if let ast::Expr::Config(config_expr) = + &mut schema_expr.config.node + { + self.has_override = merge_config_expr( + config_expr, + merged_config_expr, + &self.action, + ); + } + } else if let ast::Expr::Schema(merged_schema_expr) = + &value.node + { + if schema_expr.name.node.get_name() + == merged_schema_expr.name.node.get_name() + { + if let ( + ast::Expr::Config(merged_config_expr), + ast::Expr::Config(config_expr), + ) = ( + &merged_schema_expr.config.node, + &mut schema_expr.config.node, + ) { + self.has_override = merge_config_expr( + config_expr, + merged_config_expr, + &self.action, + ); + } + } + } else { + // Unification is only support to override the schema expression. + if let ast::Expr::Schema(schema_expr) = value.node { + if self.field_paths.len() == 0 { + unification_stmt.value = Box::new( + ast::Node::dummy_node(schema_expr), + ); + self.has_override = true; + } + } + } + } + ast::ConfigEntryOperation::Insert + | ast::ConfigEntryOperation::Override => { + // Unification is only support to override the schema expression. + if let ast::Expr::Schema(schema_expr) = value.node { + if self.field_paths.len() == 0 { + unification_stmt.value = + Box::new(ast::Node::dummy_node(schema_expr)); + self.has_override = true; + } + } + } + } + } + } + } + }); + } + ast::OverrideAction::Delete => { + // Delete the override target when the action is DELETE. + module.body.retain(|stmt| { + if let ast::Stmt::Assign(assign_stmt) = &stmt.node { + if assign_stmt.targets.len() == 1 && self.field_paths.len() == 0 { + let target = get_target_path(&assign_stmt.targets.get(0).unwrap().node); + if target == self.target_id { + self.has_override = true; + return false; + } + } + } + if let ast::Stmt::Unification(unification_stmt) = &stmt.node { + let target = match unification_stmt.target.node.names.get(0) { + Some(name) => name, + None => bug!( + "Invalid AST unification target names {:?}", + unification_stmt.target.node.names + ), + }; + if target.node == self.target_id && self.field_paths.len() == 0 { + self.has_override = true; + return false; + } + } + true + }); + } + } + + walk_list_mut!(self, walk_stmt, module.body); + + // If the variable is not found, add a new variable with the override value. + if !self.has_override { + match self.action { + // Walk the module body to find the target and override it. + ast::OverrideAction::CreateOrUpdate => { + let value = if self.field_paths.len() == 0 { + self.clone_override_value() + } else { + // if the spec is b.c.d=1 and the b is not found, add config b: {c: {d: 1}} + Box::new(ast::Node::dummy_node(ast::Expr::Config(ast::ConfigExpr { + items: vec![Box::new(ast::Node::dummy_node(ast::ConfigEntry { + key: Some(Box::new(ast::Node::dummy_node(ast::Expr::Identifier( + ast::Identifier { + names: self + .field_paths + .iter() + .map(|s| ast::Node::dummy_node(s.to_string())) + .collect(), + ctx: ast::ExprContext::Store, + pkgpath: "".to_string(), + }, + )))), + value: self.clone_override_value(), + operation: self.operation.clone(), + }))], + }))) + }; + match &self.operation { + ast::ConfigEntryOperation::Override => { + let assign = ast::AssignStmt { + targets: vec![Box::new(ast::Node::dummy_node(ast::Target { + name: ast::Node::dummy_node(self.target_id.clone()), + paths: vec![], + pkgpath: "".to_string(), + }))], + ty: None, + value, + }; + module + .body + .push(Box::new(ast::Node::dummy_node(ast::Stmt::Assign(assign)))); + } + ast::ConfigEntryOperation::Union => { + let schema_expr: Result, _> = + value.as_ref().clone().try_into(); + match schema_expr { + Ok(schema_expr) => { + let stmt = ast::UnificationStmt { + target: Box::new(ast::Node::dummy_node(ast::Identifier { + names: vec![ast::Node::dummy_node( + self.target_id.clone(), + )], + ctx: ast::ExprContext::Store, + pkgpath: "".to_string(), + })), + value: Box::new(schema_expr), + }; + module.body.push(Box::new(ast::Node::dummy_node( + ast::Stmt::Unification(stmt), + ))); + } + Err(_) => { + let stmt = ast::AssignStmt { + targets: vec![Box::new(ast::Node::dummy_node( + ast::Target { + name: ast::Node::dummy_node(self.target_id.clone()), + paths: vec![], + pkgpath: "".to_string(), + }, + ))], + ty: None, + value, + }; + module.body.push(Box::new(ast::Node::dummy_node( + ast::Stmt::Assign(stmt), + ))); + } + } + } + ast::ConfigEntryOperation::Insert => { + let stmt = ast::AugAssignStmt { + target: Box::new(ast::Node::dummy_node(ast::Target { + name: ast::Node::dummy_node(self.target_id.clone()), + paths: vec![], + pkgpath: "".to_string(), + })), + op: ast::AugOp::Add, + value, + }; + module + .body + .push(Box::new(ast::Node::dummy_node(ast::Stmt::AugAssign(stmt)))); + } + } + + self.has_override = true; + } + ast::OverrideAction::Delete => { + return; + } + } + } + } + + fn walk_unification_stmt(&mut self, unification_stmt: &'ctx mut ast::UnificationStmt) { + if self.has_override { + return; + } + let name = match unification_stmt.target.node.names.get(0) { + Some(name) => name, + None => bug!( + "Invalid AST unification target names {:?}", + unification_stmt.target.node.names + ), + }; + if name.node != self.target_id || self.field_paths.len() == 0 { + return; + } + self.override_target_count = 1; + self.walk_schema_expr(&mut unification_stmt.value.node); + } + + fn walk_assign_stmt(&mut self, assign_stmt: &'ctx mut ast::AssignStmt) { + if self.has_override { + return; + } + if let ast::Expr::Schema(_) | ast::Expr::Config(_) = &assign_stmt.value.node { + self.override_target_count = 0; + for target in &assign_stmt.targets { + if !target.node.paths.is_empty() { + continue; + } + if target.node.name.node != self.target_id { + continue; + } + self.override_target_count += 1; + } + if self.override_target_count == 0 { + return; + } + self.walk_expr(&mut assign_stmt.value.node); + } + } + + fn walk_schema_expr(&mut self, schema_expr: &'ctx mut ast::SchemaExpr) { + if self.has_override { + return; + } + if self.override_target_count == 0 { + return; + } + if let ast::Expr::Config(config_expr) = &mut schema_expr.config.node { + if !self.lookup_config_and_replace(config_expr) { + // Not exist and append an override value when the action is CREATE_OR_UPDATE + if let ast::OverrideAction::CreateOrUpdate = self.action { + if let ast::Expr::Config(config_expr) = &mut schema_expr.config.node { + config_expr + .items + .push(Box::new(ast::Node::dummy_node(ast::ConfigEntry { + key: Some(Box::new(ast::Node::dummy_node(ast::Expr::Identifier( + self.override_key.clone(), + )))), + value: self.clone_override_value(), + operation: self.operation.clone(), + }))); + self.has_override = true; + } + } + } else { + self.has_override = true; + } + } + self.override_target_count = 0; + } + + fn walk_config_expr(&mut self, config_expr: &'ctx mut ast::ConfigExpr) { + if self.has_override { + return; + } + // Lookup config all fields and replace if it is matched with the override spec. + if !self.lookup_config_and_replace(config_expr) { + return; + } + self.has_override = true; + self.override_target_count = 0; + } + + fn walk_if_stmt(&mut self, _: &'ctx mut ast::IfStmt) { + // Do not override AssignStmt in IfStmt + } + fn walk_schema_stmt(&mut self, _: &'ctx mut ast::SchemaStmt) { + // Do not override AssignStmt in SchemaStmt + } + fn walk_lambda_expr(&mut self, _: &'ctx mut ast::LambdaExpr) { + // Do not override AssignStmt in LambdaExpr + } +} + +impl OverrideTransformer { + /// Lookup schema config all fields and replace if it is matched with the override spec, + /// return whether is found a replaced one. + fn lookup_config_and_replace(&self, config_expr: &mut ast::ConfigExpr) -> bool { + // Split a path into multiple parts. `a.b.c` -> ["a", "b", "c"] + let parts = self + .field_paths + .iter() + .map(|s| s.as_str()) + .collect::>(); + replace_config_with_path_parts( + config_expr, + &parts, + &self.action, + &self.operation, + &self.override_value, + ) + } + + /// Clone a override value + #[inline] + fn clone_override_value(&self) -> ast::NodeRef { + match &self.override_value { + Some(v) => v.clone(), + None => bug!("Override value is None"), + } + } +} + +fn merge_config_expr( + config_expr: &mut ast::ConfigExpr, + merged_config_expr: &ast::ConfigExpr, + action: &ast::OverrideAction, +) -> bool { + let mut changed = false; + for item in &merged_config_expr.items { + let parts = get_key_parts(&item.node.key); + // Deal double star and config if expr + if parts.is_empty() { + config_expr.items.push(item.clone()); + changed = true; + } else { + if replace_config_with_path_parts( + config_expr, + &parts, + action, + &item.node.operation, + &Some(item.node.value.clone()), + ) { + changed = true; + } + } + } + changed +} + +/// Replace AST config expr with one part of path. The implementation of this function +/// uses recursive matching to find the config entry need to be modified. +fn replace_config_with_path_parts( + config_expr: &mut ast::ConfigExpr, + parts: &[&str], + action: &ast::OverrideAction, + operation: &ast::ConfigEntryOperation, + value: &Option>, +) -> bool { + // Do not replace empty path parts and out of index parts on the config expression. + if parts.is_empty() { + return false; + } + // Always take the first part to match, because recursive search is required. + let part = parts[0]; + let mut delete_index_set = HashSet::new(); + let mut changed = false; + // Loop all entries in the config expression and replace, because there may be duplicate + // configuration items in config. + for (i, item) in config_expr.items.iter_mut().enumerate() { + // Compare each field of the config structure one by one. + // - `part` denotes the path entered by the user to be modified. + // - `get_path_key` returns the real config key name. + // For example, the real config node is `a: {b: c: {}}`. The path + // that needs to be modified is `a.b.c`, and its parts are ["a", "b", "c"]. + if part == get_key_path(&item.node.key) { + // When the last part of the path is successfully recursively matched, + // it indicates that the original value that needs to be overwritten + // is successfully found, and the new value is used to overwrite it. + // - `parts.len() == 1` denotes the path matches exactly. + if parts.len() == 1 { + match action { + ast::OverrideAction::CreateOrUpdate => { + if let Some(value) = value { + let mut value = value.clone(); + // Use position information that needs to override the expression. + value.set_pos(item.pos()); + match operation { + ast::ConfigEntryOperation::Union => { + if let ast::Expr::Config(merged_config_expr) = &value.node { + match &mut item.node.value.node { + ast::Expr::Schema(schema_expr) => { + if let ast::Expr::Config(config_expr) = + &mut schema_expr.config.node + { + changed = merge_config_expr( + config_expr, + merged_config_expr, + action, + ); + } + } + ast::Expr::Config(config_expr) => { + changed = merge_config_expr( + config_expr, + merged_config_expr, + action, + ); + } + _ => {} + } + } else if let ast::Expr::Schema(merged_schema_expr) = + &value.node + { + if let ast::Expr::Schema(schema_expr) = + &mut item.node.value.node + { + if schema_expr.name.node.get_name() + == merged_schema_expr.name.node.get_name() + { + if let ( + ast::Expr::Config(merged_config_expr), + ast::Expr::Config(config_expr), + ) = ( + &merged_schema_expr.config.node, + &mut schema_expr.config.node, + ) { + changed = merge_config_expr( + config_expr, + merged_config_expr, + action, + ); + } + } + } + } else { + // Override the node value. + item.node.value = value; + changed = true; + } + } + ast::ConfigEntryOperation::Insert => { + if let ast::Expr::List(insert_list_expr) = &value.node { + if let ast::Expr::List(list_expr) = + &mut item.node.value.node + { + for value in &insert_list_expr.elts { + list_expr.elts.push(value.clone()); + } + changed = true; + } + } + } + ast::ConfigEntryOperation::Override => { + // Override the node value. + item.node.value = value; + changed = true; + } + } + } + } + ast::OverrideAction::Delete => { + // Store the config entry delete index into the delete index set. + // Because we can't delete the entry directly in the loop + delete_index_set.insert(i); + changed = true; + } + } + } + // Replace value recursively using the path composed by subsequent parts. + // + // The reason for using recursion instead of looping for path matching + // is that rust cannot directly hold shared references to AST nodes + // (ast::NodeRef is a Box), so recursive search is performed + // directly on AST nodes. + else if let Some(config_expr) = try_get_config_expr_mut(&mut item.node.value.node) { + changed = replace_config_with_path_parts( + config_expr, + &parts[1..], + action, + operation, + value, + ); + } + } + } + // Delete entries according delete index set. + if !delete_index_set.is_empty() { + let items: Vec<(usize, &ast::NodeRef)> = config_expr + .items + .iter() + .enumerate() + .filter(|(i, _)| !delete_index_set.contains(i)) + .collect(); + config_expr.items = items + .iter() + .map(|(_, item)| <&ast::NodeRef>::clone(item).clone()) + .collect(); + } else if let ast::OverrideAction::CreateOrUpdate = action { + if !changed { + if let Some(value) = value { + let key = ast::Identifier { + names: parts + .iter() + .map(|s| ast::Node::dummy_node(s.to_string())) + .collect(), + ctx: ast::ExprContext::Store, + pkgpath: "".to_string(), + }; + config_expr + .items + .push(Box::new(ast::Node::dummy_node(ast::ConfigEntry { + key: Some(Box::new(ast::Node::dummy_node(ast::Expr::Identifier(key)))), + value: value.clone(), + operation: operation.clone(), + }))); + changed = true; + } + } + } + return changed; +} diff --git a/kclvm/query/src/path.rs b/kclvm/query/src/path.rs new file mode 100644 index 000000000..c75cf427e --- /dev/null +++ b/kclvm/query/src/path.rs @@ -0,0 +1,60 @@ +use anyhow::Result; + +/// Parse attribute path which returns either a vector of strings or an error. e.g. +/// `a.b.c`, `a['b'].c`, `a["b"].c`, `a.['b'].c` and `a.["b"].c` both return `["a", "b", "c"]` +pub fn parse_attribute_path(path: &str) -> Result> { + let mut parts: Vec = Vec::new(); + let mut current = String::new(); + let mut chars = path.chars().peekable(); + let mut in_brackets = false; + + while let Some(ch) = chars.next() { + if in_brackets { + if ch == '"' || ch == '\'' { + // Expecting the closing quote, skip if found + if chars.peek() == Some(&']') { + chars.next(); // Consume the closing bracket + in_brackets = false; + continue; + } + return Err(anyhow::anyhow!("Expected closing bracket")); + } else { + current.push(ch); + } + } else { + match ch { + '.' => { + if !current.is_empty() { + parts.push(current.clone()); + current.clear(); + } + } + '[' => { + if !current.is_empty() { + parts.push(current.clone()); + current.clear(); + } + in_brackets = true; + // Skip the opening quote + if let Some(next_char) = chars.next() { + if next_char != '"' && next_char != '\'' { + return Err(anyhow::anyhow!("Expected opening quote after '['")); + } + } + } + ']' => { + return Err(anyhow::anyhow!("Unmatched closing bracket")); + } + _ => { + current.push(ch); + } + } + } + } + + if !current.is_empty() { + parts.push(current); + } + + Ok(parts) +} diff --git a/kclvm/query/src/query.rs b/kclvm/query/src/query.rs new file mode 100644 index 000000000..ece300208 --- /dev/null +++ b/kclvm/query/src/query.rs @@ -0,0 +1,332 @@ +use std::{cell::RefCell, rc::Rc, sync::Arc}; + +use anyhow::Result; +use indexmap::IndexMap; +use kclvm_parser::{load_all_files_under_paths, load_program, LoadProgramOptions, ParseSession}; +use kclvm_sema::{ + resolver::{ + resolve_program_with_opts, + scope::{ProgramScope, Scope}, + Options, + }, + ty::SchemaType, +}; + +/// Get schema type kind. +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum GetSchemaOption { + /// Get schema instances. + Instances, + /// Get schema definitions. + Definitions, + /// Get schema instances and definitions + All, +} + +impl Default for GetSchemaOption { + fn default() -> Self { + GetSchemaOption::All + } +} + +/// Get schema types from a kcl file or code. +/// +/// # Parameters +/// file: [&str]. The kcl filename. +/// +/// code: [Option<&str>]. The kcl code string +/// +/// schema_name: [Option<&str>]. The schema name, when the schema name is empty, all schemas are returned. +/// +/// # Examples +/// +/// ``` +/// use kclvm_query::query::{get_schema_type, GetSchemaOption}; +/// +/// let file = "schema.k"; +/// let code = r#" +/// import units +/// +/// schema Person: +/// name: str +/// age: int +/// size?: units.NumberMultiplier = 1Mi +/// +/// person = Person { +/// name = "Alice" +/// age = 18 +/// } +/// "#; +/// // Get all schema +/// let types = get_schema_type(file, Some(code), None, GetSchemaOption::All).unwrap(); +/// assert_eq!(types.len(), 2); +/// assert_eq!(types[0].name, "Person"); +/// assert_eq!(types[1].name, "Person"); +/// assert_eq!(types["Person"].name, "Person"); +/// assert_eq!(types["person"].name, "Person"); +/// +/// let types = get_schema_type(file, Some(code), None, GetSchemaOption::Instances).unwrap(); +/// assert_eq!(types.len(), 1); +/// assert_eq!(types[0].name, "Person"); +/// assert_eq!(types["person"].name, "Person"); +/// +/// let types = get_schema_type(file, Some(code), None, GetSchemaOption::Definitions).unwrap(); +/// assert_eq!(types.len(), 1); +/// assert_eq!(types[0].name, "Person"); +/// assert_eq!(types["Person"].name, "Person"); +/// assert_eq!(types["Person"].attrs["name"].ty.ty_str(), "str"); +/// assert_eq!(types["Person"].attrs["age"].ty.ty_str(), "int"); +/// assert_eq!(types["Person"].attrs["size"].ty.ty_str(), "number_multiplier"); +/// ``` +pub fn get_schema_type( + file: &str, + code: Option<&str>, + schema_name: Option<&str>, + opt: GetSchemaOption, +) -> Result> { + let mut result = IndexMap::new(); + let scope = resolve_file(&CompilationOptions { + paths: vec![file.to_string()], + loader_opts: code.map(|c| LoadProgramOptions { + k_code_list: vec![c.to_string()], + ..Default::default() + }), + resolve_opts: Options { + resolve_val: true, + ..Default::default() + }, + get_schema_opts: opt.clone(), + })?; + for (name, o) in &scope.borrow().elems { + if o.borrow().ty.is_schema() { + let schema_ty = o.borrow().ty.into_schema_type(); + if opt == GetSchemaOption::All + || (opt == GetSchemaOption::Definitions && !schema_ty.is_instance) + || (opt == GetSchemaOption::Instances && schema_ty.is_instance) + { + // Schema name filter + match schema_name { + Some(schema_name) => { + if schema_name == name { + result.insert(name.to_string(), schema_ty); + } + } + None => { + result.insert(name.to_string(), schema_ty); + } + } + } + } + } + Ok(result) +} + +#[derive(Debug, Clone, Default)] +pub struct CompilationOptions { + pub paths: Vec, + pub loader_opts: Option, + pub resolve_opts: Options, + pub get_schema_opts: GetSchemaOption, +} + +/// Service for getting the full schema type list. +/// +/// # Examples +/// +/// ``` +/// use kclvm_parser::LoadProgramOptions; +/// use kclvm_query::query::CompilationOptions; +/// use kclvm_query::query::get_full_schema_type; +/// use std::path::Path; +/// use maplit::hashmap; +/// +/// let work_dir_parent = Path::new(".").join("src").join("test_data").join("get_schema_ty"); +/// +/// let result = get_full_schema_type( +/// Some("a"), +/// CompilationOptions { +/// paths: vec![ +/// work_dir_parent.join("aaa").join("main.k").canonicalize().unwrap().display().to_string() +/// ], +/// loader_opts: Some(LoadProgramOptions { +/// work_dir: work_dir_parent.join("aaa").canonicalize().unwrap().display().to_string(), +/// package_maps: hashmap!{ +/// "bbb".to_string() => work_dir_parent.join("bbb").canonicalize().unwrap().display().to_string(), +/// }, +/// ..Default::default() +/// }), +/// ..Default::default() +/// } +/// ).unwrap(); +/// assert_eq!(result.len(), 1); +/// ``` +pub fn get_full_schema_type( + schema_name: Option<&str>, + opts: CompilationOptions, +) -> Result> { + let mut result = IndexMap::new(); + let scope = resolve_file(&opts)?; + for (name, o) in &scope.borrow().elems { + if o.borrow().ty.is_schema() { + let mut schema_ty = o.borrow().ty.into_schema_type(); + if let Some(base) = &schema_ty.base { + schema_ty.base = Some(Box::new(get_full_schema_type_recursive(*base.clone())?)); + } + if opts.get_schema_opts == GetSchemaOption::All + || (opts.get_schema_opts == GetSchemaOption::Definitions && !schema_ty.is_instance) + || (opts.get_schema_opts == GetSchemaOption::Instances && schema_ty.is_instance) + { + // Schema name filter + match schema_name { + Some(schema_name) => { + if schema_name.is_empty() || schema_name == name { + result.insert(name.to_string(), schema_ty); + } + } + None => { + result.insert(name.to_string(), schema_ty); + } + } + } + } + } + Ok(result) +} + +/// Service for getting the full schema type list under paths. +/// Different from `get_full_schema_type`, this function will compile files that are not imported +/// And key of result is pka name, not schema name. +/// +/// # Examples +/// +/// ``` +/// use kclvm_parser::LoadProgramOptions; +/// use kclvm_query::query::CompilationOptions; +/// use kclvm_query::query::get_full_schema_type_under_path; +/// use std::path::Path; +/// use maplit::hashmap; +/// use kclvm_ast::MAIN_PKG; +/// +/// let work_dir_parent = Path::new(env!("CARGO_MANIFEST_DIR")).join("src").join("test_data").join("get_schema_ty_under_path"); +/// +/// let result = get_full_schema_type_under_path( +/// None, +/// CompilationOptions { +/// paths: vec![ +/// work_dir_parent.join("aaa").canonicalize().unwrap().display().to_string() +/// ], +/// loader_opts: Some(LoadProgramOptions { +/// work_dir: work_dir_parent.join("aaa").canonicalize().unwrap().display().to_string(), +/// package_maps: hashmap!{ +/// "bbb".to_string() => work_dir_parent.join("bbb").canonicalize().unwrap().display().to_string(), +/// "helloworld".to_string() => work_dir_parent.join("helloworld_0.0.1").canonicalize().unwrap().display().to_string(), +/// }, +/// ..Default::default() +/// }), +/// ..Default::default() +/// } +/// ).unwrap(); +/// assert_eq!(result.len(), 4); +/// assert_eq!(result.get(MAIN_PKG).unwrap().len(), 1); +/// assert_eq!(result.get("bbb").unwrap().len(), 2); +/// assert_eq!(result.get("helloworld").unwrap().len(), 1); +/// assert_eq!(result.get("sub").unwrap().len(), 1); +/// ``` +pub fn get_full_schema_type_under_path( + schema_name: Option<&str>, + opts: CompilationOptions, +) -> Result>> { + let program_scope = resolve_paths(&opts)?; + Ok(filter_pkg_schemas(&program_scope, schema_name, Some(opts))) +} + +fn get_full_schema_type_recursive(schema_ty: SchemaType) -> Result { + let mut result = schema_ty; + if let Some(base) = result.base { + result.base = Some(Box::new(get_full_schema_type_recursive(*base)?)); + } + Ok(result) +} + +fn resolve_file(opts: &CompilationOptions) -> Result>> { + let sess = Arc::new(ParseSession::default()); + let mut program = match load_program( + sess, + &opts.paths.iter().map(AsRef::as_ref).collect::>(), + opts.loader_opts.clone(), + None, + ) { + Ok(p) => p.program, + Err(err) => { + return Err(anyhow::anyhow!("{err}")); + } + }; + let scope = resolve_program_with_opts(&mut program, opts.resolve_opts.clone(), None); + match scope.main_scope() { + Some(scope) => Ok(scope.clone()), + None => Err(anyhow::anyhow!("main scope is not found")), + } +} + +fn resolve_paths(opts: &CompilationOptions) -> Result { + let sess = Arc::new(ParseSession::default()); + let mut program = load_all_files_under_paths( + sess, + &opts.paths.iter().map(AsRef::as_ref).collect::>(), + opts.loader_opts.clone(), + None, + )? + .program; + Ok(resolve_program_with_opts( + &mut program, + opts.resolve_opts.clone(), + None, + )) +} + +pub fn filter_pkg_schemas( + program_scope: &ProgramScope, + schema_name: Option<&str>, + opts: Option, +) -> IndexMap> { + let mut result = IndexMap::new(); + for (pkg, scope) in &program_scope.scope_map { + for (name, o) in &scope.borrow().elems { + if o.borrow().ty.is_schema() { + let schema_ty = o.borrow().ty.into_schema_type(); + if let Some(opts) = &opts { + if opts.get_schema_opts == GetSchemaOption::All + || (opts.get_schema_opts == GetSchemaOption::Definitions + && !schema_ty.is_instance) + || (opts.get_schema_opts == GetSchemaOption::Instances + && schema_ty.is_instance) + { + // Schema name filter + match schema_name { + Some(schema_name) => { + if schema_name.is_empty() || schema_name == name { + result.entry(pkg.clone()).or_insert(vec![]).push(schema_ty); + } + } + None => { + result.entry(pkg.clone()).or_insert(vec![]).push(schema_ty); + } + } + } + } else { + match schema_name { + Some(schema_name) => { + if schema_name.is_empty() || schema_name == name { + result.entry(pkg.clone()).or_insert(vec![]).push(schema_ty); + } + } + None => { + result.entry(pkg.clone()).or_insert(vec![]).push(schema_ty); + } + } + } + } + } + } + result +} diff --git a/kclvm/query/src/selector.rs b/kclvm/query/src/selector.rs new file mode 100644 index 000000000..420142d98 --- /dev/null +++ b/kclvm/query/src/selector.rs @@ -0,0 +1,778 @@ +use crate::r#override::build_expr_from_string; + +use super::util::{invalid_symbol_selector_spec_error, split_field_path}; +use anyhow::Result; +use kclvm_ast::{ast, path::get_target_path}; +use kclvm_error::diagnostic::Errors; +use kclvm_parser::ParseSession; +use serde::{Deserialize, Serialize}; + +use std::{ + collections::{BTreeMap, HashMap, VecDeque}, + fmt, + sync::Arc, + vec, +}; + +use kclvm_ast::path::get_key_path; + +use kclvm_ast::walker::MutSelfWalker; +use kclvm_ast_pretty::{print_ast_node, ASTNode}; +use kclvm_parser::load_program; + +use kclvm_sema::pre_process::pre_process_program; +use kclvm_sema::resolver::Options; +#[derive(Debug, Default)] +/// UnsupportedSelectee is used to store the unsupported selectee, such as if, for, etc. +pub struct UnsupportedSelectee { + pub code: String, +} + +#[derive(Debug)] +/// Selector is used to select the target variable from the kcl program. +pub struct Selector { + select_specs: Vec, + select_result: BTreeMap>, + unsupported: Vec, + inner: SelectorInner, +} + +#[derive(Debug)] +struct SelectorInner { + current_spec: String, + current_spec_items: VecDeque, + spec_store: Vec>, + var_store: VecDeque, + has_err: bool, +} + +impl SelectorInner { + fn default() -> Self { + Self { + current_spec: String::new(), + current_spec_items: VecDeque::new(), + spec_store: vec![vec![]], + var_store: VecDeque::new(), + has_err: false, + } + } + + fn pop_front(&mut self) -> Option { + let selector = self.current_spec_items.pop_front(); + if let Some(selector) = &selector { + if let Some(store) = self.spec_store.last_mut() { + store.push(selector.to_string()); + } else { + return None; + } + } + return selector; + } + + fn init(&mut self) { + self.spec_store.push(vec![]); + } + + fn restore(&mut self) { + let store_items = self.spec_store.pop(); + + if let Some(store_items) = store_items { + for item in store_items.iter().rev() { + self.current_spec_items.push_front(item.to_string()); + } + } + } +} + +impl Selector { + fn new(select_specs: Vec) -> Result { + Ok(Self { + select_specs, + select_result: BTreeMap::new(), + unsupported: vec![], + inner: SelectorInner::default(), + }) + } + + // check_node_supported is used to check if the node is supported. + fn check_node_supported(&mut self, expr: &ast::Expr) -> bool { + self.inner.has_err = false; + match expr { + ast::Expr::If(if_expr) => self.walk_if_expr(if_expr), + ast::Expr::ListIfItem(list_if_item_expr) => { + self.walk_list_if_item_expr(list_if_item_expr) + } + ast::Expr::ListComp(list_comp) => self.walk_list_comp(list_comp), + ast::Expr::DictComp(dict_comp) => self.walk_dict_comp(dict_comp), + ast::Expr::ConfigIfEntry(config_if_entry_expr) => { + self.walk_config_if_entry_expr(config_if_entry_expr) + } + ast::Expr::CompClause(comp_clause) => self.walk_comp_clause(comp_clause), + ast::Expr::Lambda(lambda) => self.walk_lambda_expr(lambda), + _ => {} + } + + return self.inner.has_err; + } + + fn switch_top_variable(&mut self, variable: Variable) { + let mut binding = Variable::default(); + + let var = self.inner.var_store.back_mut().unwrap_or(&mut binding); + + var.dict_entries.push(DictEntry { + key: variable.name.clone(), + value: variable.clone(), + }); + } + + fn push_variable(&mut self, variable: Variable) { + self.inner.var_store.push_back(variable); + } + + fn pop_n_variables(&mut self, n: usize) -> Vec { + let mut variables = Vec::new(); + for _ in 0..n { + if let Some(top) = self.inner.var_store.pop_back() { + variables.push(top); + } + } + variables + } + + fn store_variable(&mut self, key: String) { + if let Some(popped) = self.inner.var_store.front() { + self.select_result + .entry(key.clone()) + .or_insert_with(Vec::new) + .push(popped.clone()); + } + } + + pub fn select_varibales( + &mut self, + spec: String, + variable: Variable, + ) -> HashMap> { + let mut res = HashMap::new(); + + // split the spec with '.' + // put the spec into a queue to select the target + self.inner.current_spec = spec.clone(); + self.inner.current_spec_items = spec + .split('.') + .map(|s| s.to_string()) + .collect::>(); + + res.insert(spec.to_string(), self.find_variables(variable.clone())); + return res; + } + + fn find_variables(&mut self, variable: Variable) -> Vec { + self.inner.init(); + let mut variables = Vec::new(); + if self.inner.current_spec_items.is_empty() { + variables.push(variable.clone()); + } else { + if let Some(selector) = self.inner.pop_front() { + if variable.name == selector { + if self.inner.current_spec_items.is_empty() { + variables.push(variable.clone()); + } else { + if variable.is_dict() { + for entry in &variable.dict_entries { + variables.append(&mut self.find_variables(entry.value.clone())); + } + } + + if variable.is_list() { + for item in &variable.list_items { + variables.append(&mut self.find_variables(item.clone())); + } + } + } + } + } + } + + self.inner.restore(); + return variables; + } + + // The value of Variable includes the three types: String, List, Dict. + fn fill_variable_value(&mut self, variable: &mut Variable, value_expr: &ast::Expr) { + let k_code = print_ast_node(ASTNode::Expr(&Box::new(ast::Node::dummy_node( + value_expr.clone(), + )))); + + variable.value = k_code; + + self.inner.has_err = false; + match value_expr { + ast::Expr::List(list) => { + let mut variables = vec![]; + for item in &list.elts { + let mut variable = Variable::default(); + self.fill_variable_value(&mut variable, &item.node); + variables.push(variable); + } + variable.list_items = variables; + } + ast::Expr::Config(dict) => { + let mut variables = Vec::new(); + for item in &dict.items { + let key = get_key_path(&item.node.key); + + let mut variable = Variable::default(); + variable.name = key.to_string(); + variable.op_sym = item.node.operation.symbol().to_string(); + self.fill_variable_value(&mut variable, &item.node.value.node); + variables.push(DictEntry { + key, + value: variable, + }); + } + variable.dict_entries = variables; + } + ast::Expr::Schema(schema_expr) => { + let mut variables = Vec::new(); + if let ast::Expr::Config(config_expr) = &schema_expr.config.node { + for item in &config_expr.items { + let key = get_key_path(&item.node.key); + + let mut variable = Variable::default(); + variable.name = key.to_string(); + variable.op_sym = item.node.operation.symbol().to_string(); + self.fill_variable_value(&mut variable, &item.node.value.node); + variables.push(DictEntry { + key, + value: variable, + }); + } + variable.dict_entries = variables; + } + } + _ => return, + } + } +} + +impl<'ctx> MutSelfWalker for Selector { + fn walk_module(&mut self, module: &ast::Module) { + let select_paths = self.select_specs.clone(); + // If there is no select path, walk the entire module + // And return all the variables in the top level. + if select_paths.is_empty() { + for stmt in &module.body { + self.walk_stmt(&stmt.node); + } + } + + for path in &select_paths { + // split the spec with '.' + // put the spec into a queue to select the target + self.inner.current_spec = path.clone(); + self.inner.current_spec_items = path + .split('.') + .map(|s| s.to_string()) + .collect::>(); + self.inner.var_store.clear(); + + // walk the module to find the target + for stmt in &module.body { + self.walk_stmt(&stmt.node); + } + } + } + + fn walk_unification_stmt(&mut self, unification_stmt: &ast::UnificationStmt) { + self.inner.init(); + let mut stack_size = 0; + let target = &unification_stmt.target; + let target = &Some(Box::new(ast::Node::dummy_node(ast::Expr::Identifier( + target.node.clone(), + )))); + let target = get_key_path(&target); + let mut variable = Variable::default(); + // If the spec is empty, all the top level variables are returned. + if self.inner.current_spec.is_empty() { + self.fill_variable_value( + &mut variable, + &ast::Expr::Schema(unification_stmt.value.node.clone()), + ); + variable.name = target.to_string(); + variable.type_name = unification_stmt.value.node.name.node.get_name(); + variable.op_sym = ast::ConfigEntryOperation::Union.symbol().to_string(); + self.switch_top_variable(variable.clone()); + self.push_variable(variable); + stack_size += 1; + self.store_variable(target.to_string()); + } else { + // if length of spec is largr or equal to target + let selector = self.inner.pop_front(); + if let Some(selector) = selector { + if selector == target.to_string() { + variable.name = target.to_string(); + variable.type_name = unification_stmt.value.node.name.node.get_name(); + variable.op_sym = ast::ConfigEntryOperation::Union.symbol().to_string(); + if self.inner.current_spec_items.is_empty() { + self.fill_variable_value( + &mut variable, + &ast::Expr::Schema(unification_stmt.value.node.clone()), + ); + self.switch_top_variable(variable.clone()); + self.push_variable(variable); + stack_size += 1; + self.store_variable(target.to_string()); + } else { + self.switch_top_variable(variable.clone()); + self.push_variable(variable); + stack_size += 1; + // walk ahead + self.walk_schema_expr(&unification_stmt.value.node); + } + } + } + } + // the spec is still used up + // Unmatched, return + self.inner.restore(); + self.pop_n_variables(stack_size); + } + + fn walk_assign_stmt(&mut self, assign_stmt: &ast::AssignStmt) { + self.inner.init(); + let mut stack_size = 0; + let mut variable = Variable::default(); + // If the spec is empty, all the top level variables are returned. + if self.inner.current_spec.is_empty() { + // check the value of the assign statement is supported + if self.check_node_supported(&assign_stmt.value.node) { + return; + } + // get the value source code of the assign statement + self.fill_variable_value(&mut variable, &assign_stmt.value.node); + + let type_name = if let ast::Expr::Schema(schema) = &assign_stmt.value.node { + schema.name.node.get_name() + } else { + "".to_string() + }; + // The length of name for variable in top level is 1 + for target in &assign_stmt.targets { + let key = get_target_path(&target.node); + let mut variable = variable.clone(); + variable.name = key.to_string(); + variable.type_name = type_name.clone(); + variable.op_sym = ast::ConfigEntryOperation::Override.symbol().to_string(); + self.switch_top_variable(variable.clone()); + self.push_variable(variable); + stack_size += 1; + self.store_variable(key.to_string()); + } + } else { + // Compare the target with the spec + for target in &assign_stmt.targets { + let target = get_target_path(&target.node); + let selector = self.inner.pop_front(); + if let Some(selector) = selector { + if selector == target { + let type_name = if let ast::Expr::Schema(schema) = &assign_stmt.value.node { + schema.name.node.get_name() + } else { + "".to_string() + }; + let mut variable = variable.clone(); + variable.name = selector.to_string(); + variable.type_name = type_name; + variable.op_sym = ast::ConfigEntryOperation::Override.symbol().to_string(); + if self.inner.current_spec_items.is_empty() { + // matched + self.fill_variable_value(&mut variable, &assign_stmt.value.node); + + self.switch_top_variable(variable.clone()); + self.push_variable(variable); + stack_size += 1; + // check the value of the assign statement is supported + if self.check_node_supported(&assign_stmt.value.node) { + self.inner.restore(); + return; + } + self.store_variable(target.to_string()); + } else { + self.switch_top_variable(variable.clone()); + self.push_variable(variable); + stack_size += 1; + // walk ahead + self.walk_expr(&assign_stmt.value.node) + } + } + } + } + } + self.inner.restore(); + self.pop_n_variables(stack_size); + } + + fn walk_config_expr(&mut self, config_expr: &ast::ConfigExpr) { + self.inner.init(); + let mut stack_size = 0; + let selector = self.inner.pop_front(); + + if let Some(selector) = selector { + for item in &config_expr.items { + let mut variable = Variable::default(); + let key = get_key_path(&item.node.key); + // key is empty, the value of the config entry may be supported action. e.g. if, for + if key.is_empty() { + // chack the value of the config entry is supported + if self.check_node_supported(&item.node.value.node) { + continue; + } + } + let type_name = if let ast::Expr::Schema(schema) = &item.node.value.node { + schema.name.node.get_name() + } else { + "".to_string() + }; + variable.name = key.to_string(); + variable.type_name = type_name; + variable.op_sym = item.node.operation.symbol().to_string(); + // match the key with the selector + if key == selector { + self.fill_variable_value(&mut variable, &item.node.value.node); + + if self.inner.current_spec_items.is_empty() { + // If all the spec items are matched + // check and return + if self.check_node_supported(&item.node.value.node) { + continue; + } + self.switch_top_variable(variable); + self.store_variable(self.inner.current_spec.to_string()); + } else { + // the spec is still not used up + // walk ahead + self.switch_top_variable(variable.clone()); + self.push_variable(variable); + stack_size += 1; + self.walk_expr(&item.node.value.node); + } + } + } + self.inner.restore(); + self.pop_n_variables(stack_size); + } + } + + fn walk_if_expr(&mut self, if_expr: &ast::IfExpr) { + self.unsupported.push(UnsupportedSelectee::default()); + let mut un_supported_selectee = UnsupportedSelectee::default(); + un_supported_selectee.code = print_ast_node(ASTNode::Expr(&Box::new( + ast::Node::dummy_node(ast::Expr::If(if_expr.clone())), + ))); + self.unsupported.push(un_supported_selectee); + self.inner.has_err = true; + } + + fn walk_list_if_item_expr(&mut self, list_if_item_expr: &ast::ListIfItemExpr) { + let mut un_supported_selectee = UnsupportedSelectee::default(); + un_supported_selectee.code = print_ast_node(ASTNode::Expr(&Box::new( + ast::Node::dummy_node(ast::Expr::ListIfItem(list_if_item_expr.clone())), + ))); + self.unsupported.push(un_supported_selectee); + + self.inner.has_err = true; + } + + fn walk_list_comp(&mut self, list_comp: &ast::ListComp) { + let mut un_supported_selectee = UnsupportedSelectee::default(); + un_supported_selectee.code = print_ast_node(ASTNode::Expr(&Box::new( + ast::Node::dummy_node(ast::Expr::ListComp(list_comp.clone())), + ))); + self.unsupported.push(un_supported_selectee); + + self.inner.has_err = true; + } + + fn walk_dict_comp(&mut self, dict_comp: &ast::DictComp) { + let mut un_supported_selectee = UnsupportedSelectee::default(); + un_supported_selectee.code = print_ast_node(ASTNode::Expr(&Box::new( + ast::Node::dummy_node(ast::Expr::DictComp(dict_comp.clone())), + ))); + self.unsupported.push(un_supported_selectee); + + self.inner.has_err = true; + } + + fn walk_config_if_entry_expr(&mut self, config_if_entry_expr: &ast::ConfigIfEntryExpr) { + let mut un_supported_selectee = UnsupportedSelectee::default(); + un_supported_selectee.code = print_ast_node(ASTNode::Expr(&Box::new( + ast::Node::dummy_node(ast::Expr::ConfigIfEntry(config_if_entry_expr.clone())), + ))); + self.unsupported.push(un_supported_selectee); + + self.inner.has_err = true; + } + + fn walk_comp_clause(&mut self, comp_clause: &ast::CompClause) { + let mut un_supported_selectee = UnsupportedSelectee::default(); + un_supported_selectee.code = print_ast_node(ASTNode::Expr(&Box::new( + ast::Node::dummy_node(ast::Expr::CompClause(comp_clause.clone())), + ))); + self.unsupported.push(un_supported_selectee); + + self.inner.has_err = true; + } + + fn walk_lambda_expr(&mut self, lambda_expr: &ast::LambdaExpr) { + let mut un_supported_selectee = UnsupportedSelectee::default(); + un_supported_selectee.code = print_ast_node(ASTNode::Expr(&Box::new( + ast::Node::dummy_node(ast::Expr::Lambda(lambda_expr.clone())), + ))); + self.unsupported.push(un_supported_selectee); + self.inner.has_err = true; + } +} + +pub struct ListVariablesResult { + pub variables: BTreeMap>, + pub unsupported: Vec, + pub parse_errors: Errors, +} + +#[derive(Debug, PartialEq, Default, Serialize, Deserialize, Clone)] +pub struct Variable { + pub name: String, + pub type_name: String, + pub op_sym: String, + pub value: String, + pub list_items: Vec, + pub dict_entries: Vec, +} + +impl fmt::Display for Variable { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + if self.is_base_type() { + return write!(f, "{}", self.value); + } else if self.is_list() { + write!(f, "[")?; + for (i, item) in self.list_items.iter().enumerate() { + if i != 0 { + write!(f, ", ")?; + } + write!(f, "{}", item)?; + } + write!(f, "]")?; + } else if self.is_dict() { + write!(f, "{} {{ ", self.type_name)?; + for (i, entry) in self.dict_entries.iter().enumerate() { + if i != 0 { + write!(f, ", ")?; + } + write!(f, "{} {} {}", entry.key, entry.value.op_sym, entry.value)?; + } + write!(f, " }}")?; + } + Ok(()) + } +} + +#[derive(Debug, PartialEq, Default, Serialize, Deserialize, Clone)] +pub struct DictEntry { + pub key: String, + pub value: Variable, +} + +impl Variable { + pub fn new( + name: String, + type_name: String, + op_sym: String, + value: String, + list_items: Vec, + dict_entries: Vec, + ) -> Self { + Self { + name, + type_name, + op_sym, + value, + list_items, + dict_entries, + } + } + + pub fn is_base_type(&self) -> bool { + self.list_items.is_empty() && self.dict_entries.is_empty() && self.type_name.is_empty() + } + + pub fn is_union(&self) -> bool { + self.op_sym == ast::ConfigEntryOperation::Union.symbol().to_string() + } + + pub fn is_override(&self) -> bool { + self.op_sym == ast::ConfigEntryOperation::Override.symbol().to_string() + } + + pub fn is_dict(&self) -> bool { + !self.dict_entries.is_empty() + } + + pub fn is_list(&self) -> bool { + !self.list_items.is_empty() + } + + pub fn merge(&mut self, var: &Variable) -> &mut Self { + if var.is_override() { + self.value = var.value.clone(); + self.list_items = var.list_items.clone(); + self.dict_entries = var.dict_entries.clone(); + } + + if var.is_union() { + // For int, float, str and bool types, when their values are different, they are considered as conflicts. + if self.is_base_type() && self.is_base_type() && self.value == self.value { + return self; + } else { + if self.is_dict() && var.is_dict() { + let mut dict = BTreeMap::new(); + for entry in self.dict_entries.iter() { + dict.insert(entry.key.clone(), entry.value.clone()); + } + + for entry in var.dict_entries.iter() { + if let Some(v) = dict.get_mut(&entry.key) { + v.merge(&entry.value); + } else { + dict.insert(entry.key.clone(), entry.value.clone()); + } + } + + self.dict_entries = dict + .iter() + .map(|(k, v)| DictEntry { + key: k.clone(), + value: v.clone(), + }) + .collect(); + + let expr: Option>> = + build_expr_from_string(&self.to_string()); + if let Some(expr) = expr { + self.value = print_ast_node(ASTNode::Expr(&expr)); + } else { + self.value = self.to_string(); + } + } + } + } + + return self; + } +} + +pub struct ListOptions { + pub merge_program: bool, +} + +/// list_options provides users with the ability to parse kcl program and get all option +/// calling information. +pub fn list_variables( + files: Vec, + specs: Vec, + list_opts: Option<&ListOptions>, +) -> Result { + let mut selector = Selector::new(specs)?; + let mut load_result = load_program( + Arc::new(ParseSession::default()), + &files.iter().map(AsRef::as_ref).collect::>(), + None, + None, + )?; + + let mut opts = Options::default(); + opts.merge_program = true; + pre_process_program(&mut load_result.program, &opts); + + for (_, modules) in load_result.program.pkgs.iter() { + for module in modules.iter() { + let module = load_result + .program + .get_module(module) + .expect("Failed to acquire module lock") + .expect(&format!("module {:?} not found in program", module)); + selector.walk_module(&module); + } + } + + if let Some(list_opts) = list_opts { + if list_opts.merge_program { + let keys_and_vars: Vec<_> = selector + .select_result + .iter() + .map(|(k, v)| (k.clone(), v.clone())) + .collect(); + for (key, mut vars) in keys_and_vars { + let mut tmp_var = vars.get(0).unwrap().clone(); + for var in vars.iter_mut().skip(1) { + tmp_var.merge(var); + } + let res = selector.select_varibales(key, tmp_var); + selector.select_result.extend(res); + } + } + } else { + let keys_and_vars: Vec<_> = selector + .select_result + .iter() + .map(|(k, v)| (k.clone(), v.clone())) + .collect(); + for (key, vars) in keys_and_vars { + for var in vars.iter() { + let res = selector.select_varibales(key.clone(), var.clone()); + selector.select_result.extend(res); + } + } + } + + Ok(ListVariablesResult { + variables: selector.select_result, + unsupported: selector.unsupported, + parse_errors: load_result.errors, + }) +} + +/// Parse symbol selector string to symbol selector spec +/// +/// # Examples +/// +/// ``` +/// use kclvm_query::selector::parse_symbol_selector_spec; +/// +/// if let Ok(spec) = parse_symbol_selector_spec("", "alice.age") { +/// assert_eq!(spec.pkgpath, "".to_string()); +/// assert_eq!(spec.field_path, "alice.age".to_string()); +/// } +/// ``` +pub fn parse_symbol_selector_spec( + pkg_root: &str, + symbol_path: &str, +) -> Result { + if let Ok((pkgpath, field_path)) = split_field_path(symbol_path) { + Ok(ast::SymbolSelectorSpec { + pkg_root: pkg_root.to_string(), + pkgpath, + field_path, + }) + } else { + Err(invalid_symbol_selector_spec_error(symbol_path)) + } +} + +#[test] +fn test_symbol_path_selector() { + let spec = parse_symbol_selector_spec("", "pkg_name:alice.age").unwrap(); + assert_eq!(spec.pkgpath, "pkg_name".to_string()); + assert_eq!(spec.field_path, "alice.age".to_string()); +} diff --git a/kclvm/query/src/snapshots/kclvm_query__tests__list_all_variables-10.snap b/kclvm/query/src/snapshots/kclvm_query__tests__list_all_variables-10.snap new file mode 100644 index 000000000..05312712c --- /dev/null +++ b/kclvm/query/src/snapshots/kclvm_query__tests__list_all_variables-10.snap @@ -0,0 +1,734 @@ +--- +source: query/src/tests.rs +expression: got_json +--- +{ + "_list0": [ + { + "name": "_list0", + "type_name": "", + "op_sym": "=", + "value": "[\n 1\n 2\n 3\n]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "1", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "2", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "3", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + ], + "_list1": [ + { + "name": "_list1", + "type_name": "", + "op_sym": "=", + "value": "[\n 4\n 5\n 6\n]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "4", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "5", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "6", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + ], + "_part1": [ + { + "name": "_part1", + "type_name": "", + "op_sym": "=", + "value": "{\n a = \"b\"\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": "=", + "value": "\"b\"", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "_part2": [ + { + "name": "_part2", + "type_name": "", + "op_sym": "=", + "value": "{\n c = \"d\"\n}", + "list_items": [], + "dict_entries": [ + { + "key": "c", + "value": { + "name": "c", + "type_name": "", + "op_sym": "=", + "value": "\"d\"", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "a": [ + { + "name": "a", + "type_name": "", + "op_sym": "=", + "value": "1", + "list_items": [], + "dict_entries": [] + } + ], + "a1": [ + { + "name": "a1", + "type_name": "", + "op_sym": "=", + "value": "2", + "list_items": [], + "dict_entries": [] + } + ], + "a3": [ + { + "name": "a3", + "type_name": "", + "op_sym": "=", + "value": "3m", + "list_items": [], + "dict_entries": [] + } + ], + "a_dict": [ + { + "name": "a_dict", + "type_name": "", + "op_sym": "=", + "value": "{\n **_part1\n **_part2\n}", + "list_items": [], + "dict_entries": [ + { + "key": "", + "value": { + "name": "", + "type_name": "", + "op_sym": ":", + "value": "_part1", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "", + "value": { + "name": "", + "type_name": "", + "op_sym": ":", + "value": "_part2", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "array1": [ + { + "name": "array1", + "type_name": "", + "op_sym": "=", + "value": "[\n 1\n 2\n 3\n]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "1", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "2", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "3", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + ], + "b1": [ + { + "name": "b1", + "type_name": "", + "op_sym": "=", + "value": "True", + "list_items": [], + "dict_entries": [] + } + ], + "b2": [ + { + "name": "b2", + "type_name": "", + "op_sym": "=", + "value": "False", + "list_items": [], + "dict_entries": [] + } + ], + "c": [ + { + "name": "c", + "type_name": "C", + "op_sym": "=", + "value": "C {\n a: {name: \"Hello\"}\n a: {ids: [7, 8, 9]}\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{\n name: \"Hello\"\n}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": ":", + "value": "\"Hello\"", + "list_items": [], + "dict_entries": [] + } + } + ] + } + }, + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{\n ids: [7, 8, 9]\n}", + "list_items": [], + "dict_entries": [ + { + "key": "ids", + "value": { + "name": "ids", + "type_name": "", + "op_sym": ":", + "value": "[\n 7\n 8\n 9\n]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "7", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "8", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "9", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + } + ] + } + } + ] + } + ], + "dict1": [ + { + "name": "dict1", + "type_name": "", + "op_sym": "=", + "value": "{\n \"a\": 1\n \"b\": 2\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "1", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "b", + "value": { + "name": "b", + "type_name": "", + "op_sym": ":", + "value": "2", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "dict2": [ + { + "name": "dict2", + "type_name": "", + "op_sym": "=", + "value": "{\n \"a\": 1\n \"b\": {\n \"c\": 2\n \"d\": 3\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "1", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "b", + "value": { + "name": "b", + "type_name": "", + "op_sym": ":", + "value": "{\n \"c\": 2\n \"d\": 3\n}", + "list_items": [], + "dict_entries": [ + { + "key": "c", + "value": { + "name": "c", + "type_name": "", + "op_sym": ":", + "value": "2", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "d", + "value": { + "name": "d", + "type_name": "", + "op_sym": ":", + "value": "3", + "list_items": [], + "dict_entries": [] + } + } + ] + } + } + ] + } + ], + "job": [ + { + "name": "job", + "type_name": "Job", + "op_sym": "=", + "value": "Job {\n name = \"{}-{}\".format(\"app\", \"test\").lower()\n}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": "=", + "value": "\"{}-{}\".format(\"app\", \"test\").lower()", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "s1": [ + { + "name": "s1", + "type_name": "", + "op_sym": "=", + "value": "\"Hello\"", + "list_items": [], + "dict_entries": [] + } + ], + "select": [ + { + "name": "select", + "type_name": "a.b.c", + "op_sym": "=", + "value": "a.b.c {\n a: 1\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "1", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "sha": [ + { + "name": "sha", + "type_name": "A", + "op_sym": "=", + "value": "A {\n name: \"Hello\"\n ids: [1, 2, 3]\n data: {\n \"a\": {\n \"b\": {\n \"c\": 2\n }\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": ":", + "value": "\"Hello\"", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "ids", + "value": { + "name": "ids", + "type_name": "", + "op_sym": ":", + "value": "[\n 1\n 2\n 3\n]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "1", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "2", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "3", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + }, + { + "key": "data", + "value": { + "name": "data", + "type_name": "", + "op_sym": ":", + "value": "{\n \"a\": {\n \"b\": {\n \"c\": 2\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{\n \"b\": {\n \"c\": 2\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "b", + "value": { + "name": "b", + "type_name": "", + "op_sym": ":", + "value": "{\n \"c\": 2\n}", + "list_items": [], + "dict_entries": [ + { + "key": "c", + "value": { + "name": "c", + "type_name": "", + "op_sym": ":", + "value": "2", + "list_items": [], + "dict_entries": [] + } + } + ] + } + } + ] + } + } + ] + } + } + ] + } + ], + "shb": [ + { + "name": "shb", + "type_name": "B", + "op_sym": "=", + "value": "B {\n a: {\n name: \"HelloB\"\n ids: [4, 5, 6]\n data: {\n \"d\": {\n \"e\": {\n \"f\": 3\n }\n }\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{\n name: \"HelloB\"\n ids: [4, 5, 6]\n data: {\n \"d\": {\n \"e\": {\n \"f\": 3\n }\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": ":", + "value": "\"HelloB\"", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "ids", + "value": { + "name": "ids", + "type_name": "", + "op_sym": ":", + "value": "[\n 4\n 5\n 6\n]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "4", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "5", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "6", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + }, + { + "key": "data", + "value": { + "name": "data", + "type_name": "", + "op_sym": ":", + "value": "{\n \"d\": {\n \"e\": {\n \"f\": 3\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "d", + "value": { + "name": "d", + "type_name": "", + "op_sym": ":", + "value": "{\n \"e\": {\n \"f\": 3\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "e", + "value": { + "name": "e", + "type_name": "", + "op_sym": ":", + "value": "{\n \"f\": 3\n}", + "list_items": [], + "dict_entries": [ + { + "key": "f", + "value": { + "name": "f", + "type_name": "", + "op_sym": ":", + "value": "3", + "list_items": [], + "dict_entries": [] + } + } + ] + } + } + ] + } + } + ] + } + } + ] + } + } + ] + } + ], + "uconfa": [ + { + "name": "uconfa", + "type_name": "UnificationConf", + "op_sym": ":", + "value": "UnificationConf {\n name = \"b\"\n}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": "=", + "value": "\"b\"", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "union_list": [ + { + "name": "union_list", + "type_name": "", + "op_sym": "=", + "value": "[\n *_list0\n *_list1\n]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "*_list0", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "*_list1", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + ] +} diff --git a/kclvm/query/src/snapshots/kclvm_query__tests__list_all_variables-11.snap b/kclvm/query/src/snapshots/kclvm_query__tests__list_all_variables-11.snap new file mode 100644 index 000000000..05312712c --- /dev/null +++ b/kclvm/query/src/snapshots/kclvm_query__tests__list_all_variables-11.snap @@ -0,0 +1,734 @@ +--- +source: query/src/tests.rs +expression: got_json +--- +{ + "_list0": [ + { + "name": "_list0", + "type_name": "", + "op_sym": "=", + "value": "[\n 1\n 2\n 3\n]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "1", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "2", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "3", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + ], + "_list1": [ + { + "name": "_list1", + "type_name": "", + "op_sym": "=", + "value": "[\n 4\n 5\n 6\n]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "4", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "5", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "6", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + ], + "_part1": [ + { + "name": "_part1", + "type_name": "", + "op_sym": "=", + "value": "{\n a = \"b\"\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": "=", + "value": "\"b\"", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "_part2": [ + { + "name": "_part2", + "type_name": "", + "op_sym": "=", + "value": "{\n c = \"d\"\n}", + "list_items": [], + "dict_entries": [ + { + "key": "c", + "value": { + "name": "c", + "type_name": "", + "op_sym": "=", + "value": "\"d\"", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "a": [ + { + "name": "a", + "type_name": "", + "op_sym": "=", + "value": "1", + "list_items": [], + "dict_entries": [] + } + ], + "a1": [ + { + "name": "a1", + "type_name": "", + "op_sym": "=", + "value": "2", + "list_items": [], + "dict_entries": [] + } + ], + "a3": [ + { + "name": "a3", + "type_name": "", + "op_sym": "=", + "value": "3m", + "list_items": [], + "dict_entries": [] + } + ], + "a_dict": [ + { + "name": "a_dict", + "type_name": "", + "op_sym": "=", + "value": "{\n **_part1\n **_part2\n}", + "list_items": [], + "dict_entries": [ + { + "key": "", + "value": { + "name": "", + "type_name": "", + "op_sym": ":", + "value": "_part1", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "", + "value": { + "name": "", + "type_name": "", + "op_sym": ":", + "value": "_part2", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "array1": [ + { + "name": "array1", + "type_name": "", + "op_sym": "=", + "value": "[\n 1\n 2\n 3\n]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "1", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "2", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "3", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + ], + "b1": [ + { + "name": "b1", + "type_name": "", + "op_sym": "=", + "value": "True", + "list_items": [], + "dict_entries": [] + } + ], + "b2": [ + { + "name": "b2", + "type_name": "", + "op_sym": "=", + "value": "False", + "list_items": [], + "dict_entries": [] + } + ], + "c": [ + { + "name": "c", + "type_name": "C", + "op_sym": "=", + "value": "C {\n a: {name: \"Hello\"}\n a: {ids: [7, 8, 9]}\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{\n name: \"Hello\"\n}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": ":", + "value": "\"Hello\"", + "list_items": [], + "dict_entries": [] + } + } + ] + } + }, + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{\n ids: [7, 8, 9]\n}", + "list_items": [], + "dict_entries": [ + { + "key": "ids", + "value": { + "name": "ids", + "type_name": "", + "op_sym": ":", + "value": "[\n 7\n 8\n 9\n]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "7", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "8", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "9", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + } + ] + } + } + ] + } + ], + "dict1": [ + { + "name": "dict1", + "type_name": "", + "op_sym": "=", + "value": "{\n \"a\": 1\n \"b\": 2\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "1", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "b", + "value": { + "name": "b", + "type_name": "", + "op_sym": ":", + "value": "2", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "dict2": [ + { + "name": "dict2", + "type_name": "", + "op_sym": "=", + "value": "{\n \"a\": 1\n \"b\": {\n \"c\": 2\n \"d\": 3\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "1", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "b", + "value": { + "name": "b", + "type_name": "", + "op_sym": ":", + "value": "{\n \"c\": 2\n \"d\": 3\n}", + "list_items": [], + "dict_entries": [ + { + "key": "c", + "value": { + "name": "c", + "type_name": "", + "op_sym": ":", + "value": "2", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "d", + "value": { + "name": "d", + "type_name": "", + "op_sym": ":", + "value": "3", + "list_items": [], + "dict_entries": [] + } + } + ] + } + } + ] + } + ], + "job": [ + { + "name": "job", + "type_name": "Job", + "op_sym": "=", + "value": "Job {\n name = \"{}-{}\".format(\"app\", \"test\").lower()\n}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": "=", + "value": "\"{}-{}\".format(\"app\", \"test\").lower()", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "s1": [ + { + "name": "s1", + "type_name": "", + "op_sym": "=", + "value": "\"Hello\"", + "list_items": [], + "dict_entries": [] + } + ], + "select": [ + { + "name": "select", + "type_name": "a.b.c", + "op_sym": "=", + "value": "a.b.c {\n a: 1\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "1", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "sha": [ + { + "name": "sha", + "type_name": "A", + "op_sym": "=", + "value": "A {\n name: \"Hello\"\n ids: [1, 2, 3]\n data: {\n \"a\": {\n \"b\": {\n \"c\": 2\n }\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": ":", + "value": "\"Hello\"", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "ids", + "value": { + "name": "ids", + "type_name": "", + "op_sym": ":", + "value": "[\n 1\n 2\n 3\n]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "1", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "2", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "3", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + }, + { + "key": "data", + "value": { + "name": "data", + "type_name": "", + "op_sym": ":", + "value": "{\n \"a\": {\n \"b\": {\n \"c\": 2\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{\n \"b\": {\n \"c\": 2\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "b", + "value": { + "name": "b", + "type_name": "", + "op_sym": ":", + "value": "{\n \"c\": 2\n}", + "list_items": [], + "dict_entries": [ + { + "key": "c", + "value": { + "name": "c", + "type_name": "", + "op_sym": ":", + "value": "2", + "list_items": [], + "dict_entries": [] + } + } + ] + } + } + ] + } + } + ] + } + } + ] + } + ], + "shb": [ + { + "name": "shb", + "type_name": "B", + "op_sym": "=", + "value": "B {\n a: {\n name: \"HelloB\"\n ids: [4, 5, 6]\n data: {\n \"d\": {\n \"e\": {\n \"f\": 3\n }\n }\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{\n name: \"HelloB\"\n ids: [4, 5, 6]\n data: {\n \"d\": {\n \"e\": {\n \"f\": 3\n }\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": ":", + "value": "\"HelloB\"", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "ids", + "value": { + "name": "ids", + "type_name": "", + "op_sym": ":", + "value": "[\n 4\n 5\n 6\n]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "4", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "5", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "6", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + }, + { + "key": "data", + "value": { + "name": "data", + "type_name": "", + "op_sym": ":", + "value": "{\n \"d\": {\n \"e\": {\n \"f\": 3\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "d", + "value": { + "name": "d", + "type_name": "", + "op_sym": ":", + "value": "{\n \"e\": {\n \"f\": 3\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "e", + "value": { + "name": "e", + "type_name": "", + "op_sym": ":", + "value": "{\n \"f\": 3\n}", + "list_items": [], + "dict_entries": [ + { + "key": "f", + "value": { + "name": "f", + "type_name": "", + "op_sym": ":", + "value": "3", + "list_items": [], + "dict_entries": [] + } + } + ] + } + } + ] + } + } + ] + } + } + ] + } + } + ] + } + ], + "uconfa": [ + { + "name": "uconfa", + "type_name": "UnificationConf", + "op_sym": ":", + "value": "UnificationConf {\n name = \"b\"\n}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": "=", + "value": "\"b\"", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "union_list": [ + { + "name": "union_list", + "type_name": "", + "op_sym": "=", + "value": "[\n *_list0\n *_list1\n]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "*_list0", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "*_list1", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + ] +} diff --git a/kclvm/query/src/snapshots/kclvm_query__tests__list_all_variables-12.snap b/kclvm/query/src/snapshots/kclvm_query__tests__list_all_variables-12.snap new file mode 100644 index 000000000..05312712c --- /dev/null +++ b/kclvm/query/src/snapshots/kclvm_query__tests__list_all_variables-12.snap @@ -0,0 +1,734 @@ +--- +source: query/src/tests.rs +expression: got_json +--- +{ + "_list0": [ + { + "name": "_list0", + "type_name": "", + "op_sym": "=", + "value": "[\n 1\n 2\n 3\n]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "1", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "2", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "3", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + ], + "_list1": [ + { + "name": "_list1", + "type_name": "", + "op_sym": "=", + "value": "[\n 4\n 5\n 6\n]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "4", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "5", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "6", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + ], + "_part1": [ + { + "name": "_part1", + "type_name": "", + "op_sym": "=", + "value": "{\n a = \"b\"\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": "=", + "value": "\"b\"", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "_part2": [ + { + "name": "_part2", + "type_name": "", + "op_sym": "=", + "value": "{\n c = \"d\"\n}", + "list_items": [], + "dict_entries": [ + { + "key": "c", + "value": { + "name": "c", + "type_name": "", + "op_sym": "=", + "value": "\"d\"", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "a": [ + { + "name": "a", + "type_name": "", + "op_sym": "=", + "value": "1", + "list_items": [], + "dict_entries": [] + } + ], + "a1": [ + { + "name": "a1", + "type_name": "", + "op_sym": "=", + "value": "2", + "list_items": [], + "dict_entries": [] + } + ], + "a3": [ + { + "name": "a3", + "type_name": "", + "op_sym": "=", + "value": "3m", + "list_items": [], + "dict_entries": [] + } + ], + "a_dict": [ + { + "name": "a_dict", + "type_name": "", + "op_sym": "=", + "value": "{\n **_part1\n **_part2\n}", + "list_items": [], + "dict_entries": [ + { + "key": "", + "value": { + "name": "", + "type_name": "", + "op_sym": ":", + "value": "_part1", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "", + "value": { + "name": "", + "type_name": "", + "op_sym": ":", + "value": "_part2", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "array1": [ + { + "name": "array1", + "type_name": "", + "op_sym": "=", + "value": "[\n 1\n 2\n 3\n]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "1", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "2", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "3", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + ], + "b1": [ + { + "name": "b1", + "type_name": "", + "op_sym": "=", + "value": "True", + "list_items": [], + "dict_entries": [] + } + ], + "b2": [ + { + "name": "b2", + "type_name": "", + "op_sym": "=", + "value": "False", + "list_items": [], + "dict_entries": [] + } + ], + "c": [ + { + "name": "c", + "type_name": "C", + "op_sym": "=", + "value": "C {\n a: {name: \"Hello\"}\n a: {ids: [7, 8, 9]}\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{\n name: \"Hello\"\n}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": ":", + "value": "\"Hello\"", + "list_items": [], + "dict_entries": [] + } + } + ] + } + }, + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{\n ids: [7, 8, 9]\n}", + "list_items": [], + "dict_entries": [ + { + "key": "ids", + "value": { + "name": "ids", + "type_name": "", + "op_sym": ":", + "value": "[\n 7\n 8\n 9\n]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "7", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "8", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "9", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + } + ] + } + } + ] + } + ], + "dict1": [ + { + "name": "dict1", + "type_name": "", + "op_sym": "=", + "value": "{\n \"a\": 1\n \"b\": 2\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "1", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "b", + "value": { + "name": "b", + "type_name": "", + "op_sym": ":", + "value": "2", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "dict2": [ + { + "name": "dict2", + "type_name": "", + "op_sym": "=", + "value": "{\n \"a\": 1\n \"b\": {\n \"c\": 2\n \"d\": 3\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "1", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "b", + "value": { + "name": "b", + "type_name": "", + "op_sym": ":", + "value": "{\n \"c\": 2\n \"d\": 3\n}", + "list_items": [], + "dict_entries": [ + { + "key": "c", + "value": { + "name": "c", + "type_name": "", + "op_sym": ":", + "value": "2", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "d", + "value": { + "name": "d", + "type_name": "", + "op_sym": ":", + "value": "3", + "list_items": [], + "dict_entries": [] + } + } + ] + } + } + ] + } + ], + "job": [ + { + "name": "job", + "type_name": "Job", + "op_sym": "=", + "value": "Job {\n name = \"{}-{}\".format(\"app\", \"test\").lower()\n}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": "=", + "value": "\"{}-{}\".format(\"app\", \"test\").lower()", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "s1": [ + { + "name": "s1", + "type_name": "", + "op_sym": "=", + "value": "\"Hello\"", + "list_items": [], + "dict_entries": [] + } + ], + "select": [ + { + "name": "select", + "type_name": "a.b.c", + "op_sym": "=", + "value": "a.b.c {\n a: 1\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "1", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "sha": [ + { + "name": "sha", + "type_name": "A", + "op_sym": "=", + "value": "A {\n name: \"Hello\"\n ids: [1, 2, 3]\n data: {\n \"a\": {\n \"b\": {\n \"c\": 2\n }\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": ":", + "value": "\"Hello\"", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "ids", + "value": { + "name": "ids", + "type_name": "", + "op_sym": ":", + "value": "[\n 1\n 2\n 3\n]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "1", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "2", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "3", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + }, + { + "key": "data", + "value": { + "name": "data", + "type_name": "", + "op_sym": ":", + "value": "{\n \"a\": {\n \"b\": {\n \"c\": 2\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{\n \"b\": {\n \"c\": 2\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "b", + "value": { + "name": "b", + "type_name": "", + "op_sym": ":", + "value": "{\n \"c\": 2\n}", + "list_items": [], + "dict_entries": [ + { + "key": "c", + "value": { + "name": "c", + "type_name": "", + "op_sym": ":", + "value": "2", + "list_items": [], + "dict_entries": [] + } + } + ] + } + } + ] + } + } + ] + } + } + ] + } + ], + "shb": [ + { + "name": "shb", + "type_name": "B", + "op_sym": "=", + "value": "B {\n a: {\n name: \"HelloB\"\n ids: [4, 5, 6]\n data: {\n \"d\": {\n \"e\": {\n \"f\": 3\n }\n }\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{\n name: \"HelloB\"\n ids: [4, 5, 6]\n data: {\n \"d\": {\n \"e\": {\n \"f\": 3\n }\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": ":", + "value": "\"HelloB\"", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "ids", + "value": { + "name": "ids", + "type_name": "", + "op_sym": ":", + "value": "[\n 4\n 5\n 6\n]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "4", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "5", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "6", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + }, + { + "key": "data", + "value": { + "name": "data", + "type_name": "", + "op_sym": ":", + "value": "{\n \"d\": {\n \"e\": {\n \"f\": 3\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "d", + "value": { + "name": "d", + "type_name": "", + "op_sym": ":", + "value": "{\n \"e\": {\n \"f\": 3\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "e", + "value": { + "name": "e", + "type_name": "", + "op_sym": ":", + "value": "{\n \"f\": 3\n}", + "list_items": [], + "dict_entries": [ + { + "key": "f", + "value": { + "name": "f", + "type_name": "", + "op_sym": ":", + "value": "3", + "list_items": [], + "dict_entries": [] + } + } + ] + } + } + ] + } + } + ] + } + } + ] + } + } + ] + } + ], + "uconfa": [ + { + "name": "uconfa", + "type_name": "UnificationConf", + "op_sym": ":", + "value": "UnificationConf {\n name = \"b\"\n}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": "=", + "value": "\"b\"", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "union_list": [ + { + "name": "union_list", + "type_name": "", + "op_sym": "=", + "value": "[\n *_list0\n *_list1\n]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "*_list0", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "*_list1", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + ] +} diff --git a/kclvm/query/src/snapshots/kclvm_query__tests__list_all_variables-13.snap b/kclvm/query/src/snapshots/kclvm_query__tests__list_all_variables-13.snap new file mode 100644 index 000000000..05312712c --- /dev/null +++ b/kclvm/query/src/snapshots/kclvm_query__tests__list_all_variables-13.snap @@ -0,0 +1,734 @@ +--- +source: query/src/tests.rs +expression: got_json +--- +{ + "_list0": [ + { + "name": "_list0", + "type_name": "", + "op_sym": "=", + "value": "[\n 1\n 2\n 3\n]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "1", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "2", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "3", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + ], + "_list1": [ + { + "name": "_list1", + "type_name": "", + "op_sym": "=", + "value": "[\n 4\n 5\n 6\n]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "4", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "5", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "6", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + ], + "_part1": [ + { + "name": "_part1", + "type_name": "", + "op_sym": "=", + "value": "{\n a = \"b\"\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": "=", + "value": "\"b\"", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "_part2": [ + { + "name": "_part2", + "type_name": "", + "op_sym": "=", + "value": "{\n c = \"d\"\n}", + "list_items": [], + "dict_entries": [ + { + "key": "c", + "value": { + "name": "c", + "type_name": "", + "op_sym": "=", + "value": "\"d\"", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "a": [ + { + "name": "a", + "type_name": "", + "op_sym": "=", + "value": "1", + "list_items": [], + "dict_entries": [] + } + ], + "a1": [ + { + "name": "a1", + "type_name": "", + "op_sym": "=", + "value": "2", + "list_items": [], + "dict_entries": [] + } + ], + "a3": [ + { + "name": "a3", + "type_name": "", + "op_sym": "=", + "value": "3m", + "list_items": [], + "dict_entries": [] + } + ], + "a_dict": [ + { + "name": "a_dict", + "type_name": "", + "op_sym": "=", + "value": "{\n **_part1\n **_part2\n}", + "list_items": [], + "dict_entries": [ + { + "key": "", + "value": { + "name": "", + "type_name": "", + "op_sym": ":", + "value": "_part1", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "", + "value": { + "name": "", + "type_name": "", + "op_sym": ":", + "value": "_part2", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "array1": [ + { + "name": "array1", + "type_name": "", + "op_sym": "=", + "value": "[\n 1\n 2\n 3\n]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "1", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "2", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "3", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + ], + "b1": [ + { + "name": "b1", + "type_name": "", + "op_sym": "=", + "value": "True", + "list_items": [], + "dict_entries": [] + } + ], + "b2": [ + { + "name": "b2", + "type_name": "", + "op_sym": "=", + "value": "False", + "list_items": [], + "dict_entries": [] + } + ], + "c": [ + { + "name": "c", + "type_name": "C", + "op_sym": "=", + "value": "C {\n a: {name: \"Hello\"}\n a: {ids: [7, 8, 9]}\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{\n name: \"Hello\"\n}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": ":", + "value": "\"Hello\"", + "list_items": [], + "dict_entries": [] + } + } + ] + } + }, + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{\n ids: [7, 8, 9]\n}", + "list_items": [], + "dict_entries": [ + { + "key": "ids", + "value": { + "name": "ids", + "type_name": "", + "op_sym": ":", + "value": "[\n 7\n 8\n 9\n]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "7", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "8", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "9", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + } + ] + } + } + ] + } + ], + "dict1": [ + { + "name": "dict1", + "type_name": "", + "op_sym": "=", + "value": "{\n \"a\": 1\n \"b\": 2\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "1", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "b", + "value": { + "name": "b", + "type_name": "", + "op_sym": ":", + "value": "2", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "dict2": [ + { + "name": "dict2", + "type_name": "", + "op_sym": "=", + "value": "{\n \"a\": 1\n \"b\": {\n \"c\": 2\n \"d\": 3\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "1", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "b", + "value": { + "name": "b", + "type_name": "", + "op_sym": ":", + "value": "{\n \"c\": 2\n \"d\": 3\n}", + "list_items": [], + "dict_entries": [ + { + "key": "c", + "value": { + "name": "c", + "type_name": "", + "op_sym": ":", + "value": "2", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "d", + "value": { + "name": "d", + "type_name": "", + "op_sym": ":", + "value": "3", + "list_items": [], + "dict_entries": [] + } + } + ] + } + } + ] + } + ], + "job": [ + { + "name": "job", + "type_name": "Job", + "op_sym": "=", + "value": "Job {\n name = \"{}-{}\".format(\"app\", \"test\").lower()\n}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": "=", + "value": "\"{}-{}\".format(\"app\", \"test\").lower()", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "s1": [ + { + "name": "s1", + "type_name": "", + "op_sym": "=", + "value": "\"Hello\"", + "list_items": [], + "dict_entries": [] + } + ], + "select": [ + { + "name": "select", + "type_name": "a.b.c", + "op_sym": "=", + "value": "a.b.c {\n a: 1\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "1", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "sha": [ + { + "name": "sha", + "type_name": "A", + "op_sym": "=", + "value": "A {\n name: \"Hello\"\n ids: [1, 2, 3]\n data: {\n \"a\": {\n \"b\": {\n \"c\": 2\n }\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": ":", + "value": "\"Hello\"", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "ids", + "value": { + "name": "ids", + "type_name": "", + "op_sym": ":", + "value": "[\n 1\n 2\n 3\n]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "1", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "2", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "3", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + }, + { + "key": "data", + "value": { + "name": "data", + "type_name": "", + "op_sym": ":", + "value": "{\n \"a\": {\n \"b\": {\n \"c\": 2\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{\n \"b\": {\n \"c\": 2\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "b", + "value": { + "name": "b", + "type_name": "", + "op_sym": ":", + "value": "{\n \"c\": 2\n}", + "list_items": [], + "dict_entries": [ + { + "key": "c", + "value": { + "name": "c", + "type_name": "", + "op_sym": ":", + "value": "2", + "list_items": [], + "dict_entries": [] + } + } + ] + } + } + ] + } + } + ] + } + } + ] + } + ], + "shb": [ + { + "name": "shb", + "type_name": "B", + "op_sym": "=", + "value": "B {\n a: {\n name: \"HelloB\"\n ids: [4, 5, 6]\n data: {\n \"d\": {\n \"e\": {\n \"f\": 3\n }\n }\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{\n name: \"HelloB\"\n ids: [4, 5, 6]\n data: {\n \"d\": {\n \"e\": {\n \"f\": 3\n }\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": ":", + "value": "\"HelloB\"", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "ids", + "value": { + "name": "ids", + "type_name": "", + "op_sym": ":", + "value": "[\n 4\n 5\n 6\n]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "4", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "5", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "6", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + }, + { + "key": "data", + "value": { + "name": "data", + "type_name": "", + "op_sym": ":", + "value": "{\n \"d\": {\n \"e\": {\n \"f\": 3\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "d", + "value": { + "name": "d", + "type_name": "", + "op_sym": ":", + "value": "{\n \"e\": {\n \"f\": 3\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "e", + "value": { + "name": "e", + "type_name": "", + "op_sym": ":", + "value": "{\n \"f\": 3\n}", + "list_items": [], + "dict_entries": [ + { + "key": "f", + "value": { + "name": "f", + "type_name": "", + "op_sym": ":", + "value": "3", + "list_items": [], + "dict_entries": [] + } + } + ] + } + } + ] + } + } + ] + } + } + ] + } + } + ] + } + ], + "uconfa": [ + { + "name": "uconfa", + "type_name": "UnificationConf", + "op_sym": ":", + "value": "UnificationConf {\n name = \"b\"\n}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": "=", + "value": "\"b\"", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "union_list": [ + { + "name": "union_list", + "type_name": "", + "op_sym": "=", + "value": "[\n *_list0\n *_list1\n]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "*_list0", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "*_list1", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + ] +} diff --git a/kclvm/query/src/snapshots/kclvm_query__tests__list_all_variables-14.snap b/kclvm/query/src/snapshots/kclvm_query__tests__list_all_variables-14.snap new file mode 100644 index 000000000..05312712c --- /dev/null +++ b/kclvm/query/src/snapshots/kclvm_query__tests__list_all_variables-14.snap @@ -0,0 +1,734 @@ +--- +source: query/src/tests.rs +expression: got_json +--- +{ + "_list0": [ + { + "name": "_list0", + "type_name": "", + "op_sym": "=", + "value": "[\n 1\n 2\n 3\n]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "1", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "2", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "3", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + ], + "_list1": [ + { + "name": "_list1", + "type_name": "", + "op_sym": "=", + "value": "[\n 4\n 5\n 6\n]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "4", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "5", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "6", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + ], + "_part1": [ + { + "name": "_part1", + "type_name": "", + "op_sym": "=", + "value": "{\n a = \"b\"\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": "=", + "value": "\"b\"", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "_part2": [ + { + "name": "_part2", + "type_name": "", + "op_sym": "=", + "value": "{\n c = \"d\"\n}", + "list_items": [], + "dict_entries": [ + { + "key": "c", + "value": { + "name": "c", + "type_name": "", + "op_sym": "=", + "value": "\"d\"", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "a": [ + { + "name": "a", + "type_name": "", + "op_sym": "=", + "value": "1", + "list_items": [], + "dict_entries": [] + } + ], + "a1": [ + { + "name": "a1", + "type_name": "", + "op_sym": "=", + "value": "2", + "list_items": [], + "dict_entries": [] + } + ], + "a3": [ + { + "name": "a3", + "type_name": "", + "op_sym": "=", + "value": "3m", + "list_items": [], + "dict_entries": [] + } + ], + "a_dict": [ + { + "name": "a_dict", + "type_name": "", + "op_sym": "=", + "value": "{\n **_part1\n **_part2\n}", + "list_items": [], + "dict_entries": [ + { + "key": "", + "value": { + "name": "", + "type_name": "", + "op_sym": ":", + "value": "_part1", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "", + "value": { + "name": "", + "type_name": "", + "op_sym": ":", + "value": "_part2", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "array1": [ + { + "name": "array1", + "type_name": "", + "op_sym": "=", + "value": "[\n 1\n 2\n 3\n]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "1", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "2", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "3", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + ], + "b1": [ + { + "name": "b1", + "type_name": "", + "op_sym": "=", + "value": "True", + "list_items": [], + "dict_entries": [] + } + ], + "b2": [ + { + "name": "b2", + "type_name": "", + "op_sym": "=", + "value": "False", + "list_items": [], + "dict_entries": [] + } + ], + "c": [ + { + "name": "c", + "type_name": "C", + "op_sym": "=", + "value": "C {\n a: {name: \"Hello\"}\n a: {ids: [7, 8, 9]}\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{\n name: \"Hello\"\n}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": ":", + "value": "\"Hello\"", + "list_items": [], + "dict_entries": [] + } + } + ] + } + }, + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{\n ids: [7, 8, 9]\n}", + "list_items": [], + "dict_entries": [ + { + "key": "ids", + "value": { + "name": "ids", + "type_name": "", + "op_sym": ":", + "value": "[\n 7\n 8\n 9\n]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "7", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "8", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "9", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + } + ] + } + } + ] + } + ], + "dict1": [ + { + "name": "dict1", + "type_name": "", + "op_sym": "=", + "value": "{\n \"a\": 1\n \"b\": 2\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "1", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "b", + "value": { + "name": "b", + "type_name": "", + "op_sym": ":", + "value": "2", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "dict2": [ + { + "name": "dict2", + "type_name": "", + "op_sym": "=", + "value": "{\n \"a\": 1\n \"b\": {\n \"c\": 2\n \"d\": 3\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "1", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "b", + "value": { + "name": "b", + "type_name": "", + "op_sym": ":", + "value": "{\n \"c\": 2\n \"d\": 3\n}", + "list_items": [], + "dict_entries": [ + { + "key": "c", + "value": { + "name": "c", + "type_name": "", + "op_sym": ":", + "value": "2", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "d", + "value": { + "name": "d", + "type_name": "", + "op_sym": ":", + "value": "3", + "list_items": [], + "dict_entries": [] + } + } + ] + } + } + ] + } + ], + "job": [ + { + "name": "job", + "type_name": "Job", + "op_sym": "=", + "value": "Job {\n name = \"{}-{}\".format(\"app\", \"test\").lower()\n}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": "=", + "value": "\"{}-{}\".format(\"app\", \"test\").lower()", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "s1": [ + { + "name": "s1", + "type_name": "", + "op_sym": "=", + "value": "\"Hello\"", + "list_items": [], + "dict_entries": [] + } + ], + "select": [ + { + "name": "select", + "type_name": "a.b.c", + "op_sym": "=", + "value": "a.b.c {\n a: 1\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "1", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "sha": [ + { + "name": "sha", + "type_name": "A", + "op_sym": "=", + "value": "A {\n name: \"Hello\"\n ids: [1, 2, 3]\n data: {\n \"a\": {\n \"b\": {\n \"c\": 2\n }\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": ":", + "value": "\"Hello\"", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "ids", + "value": { + "name": "ids", + "type_name": "", + "op_sym": ":", + "value": "[\n 1\n 2\n 3\n]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "1", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "2", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "3", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + }, + { + "key": "data", + "value": { + "name": "data", + "type_name": "", + "op_sym": ":", + "value": "{\n \"a\": {\n \"b\": {\n \"c\": 2\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{\n \"b\": {\n \"c\": 2\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "b", + "value": { + "name": "b", + "type_name": "", + "op_sym": ":", + "value": "{\n \"c\": 2\n}", + "list_items": [], + "dict_entries": [ + { + "key": "c", + "value": { + "name": "c", + "type_name": "", + "op_sym": ":", + "value": "2", + "list_items": [], + "dict_entries": [] + } + } + ] + } + } + ] + } + } + ] + } + } + ] + } + ], + "shb": [ + { + "name": "shb", + "type_name": "B", + "op_sym": "=", + "value": "B {\n a: {\n name: \"HelloB\"\n ids: [4, 5, 6]\n data: {\n \"d\": {\n \"e\": {\n \"f\": 3\n }\n }\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{\n name: \"HelloB\"\n ids: [4, 5, 6]\n data: {\n \"d\": {\n \"e\": {\n \"f\": 3\n }\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": ":", + "value": "\"HelloB\"", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "ids", + "value": { + "name": "ids", + "type_name": "", + "op_sym": ":", + "value": "[\n 4\n 5\n 6\n]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "4", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "5", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "6", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + }, + { + "key": "data", + "value": { + "name": "data", + "type_name": "", + "op_sym": ":", + "value": "{\n \"d\": {\n \"e\": {\n \"f\": 3\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "d", + "value": { + "name": "d", + "type_name": "", + "op_sym": ":", + "value": "{\n \"e\": {\n \"f\": 3\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "e", + "value": { + "name": "e", + "type_name": "", + "op_sym": ":", + "value": "{\n \"f\": 3\n}", + "list_items": [], + "dict_entries": [ + { + "key": "f", + "value": { + "name": "f", + "type_name": "", + "op_sym": ":", + "value": "3", + "list_items": [], + "dict_entries": [] + } + } + ] + } + } + ] + } + } + ] + } + } + ] + } + } + ] + } + ], + "uconfa": [ + { + "name": "uconfa", + "type_name": "UnificationConf", + "op_sym": ":", + "value": "UnificationConf {\n name = \"b\"\n}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": "=", + "value": "\"b\"", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "union_list": [ + { + "name": "union_list", + "type_name": "", + "op_sym": "=", + "value": "[\n *_list0\n *_list1\n]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "*_list0", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "*_list1", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + ] +} diff --git a/kclvm/query/src/snapshots/kclvm_query__tests__list_all_variables-15.snap b/kclvm/query/src/snapshots/kclvm_query__tests__list_all_variables-15.snap new file mode 100644 index 000000000..05312712c --- /dev/null +++ b/kclvm/query/src/snapshots/kclvm_query__tests__list_all_variables-15.snap @@ -0,0 +1,734 @@ +--- +source: query/src/tests.rs +expression: got_json +--- +{ + "_list0": [ + { + "name": "_list0", + "type_name": "", + "op_sym": "=", + "value": "[\n 1\n 2\n 3\n]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "1", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "2", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "3", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + ], + "_list1": [ + { + "name": "_list1", + "type_name": "", + "op_sym": "=", + "value": "[\n 4\n 5\n 6\n]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "4", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "5", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "6", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + ], + "_part1": [ + { + "name": "_part1", + "type_name": "", + "op_sym": "=", + "value": "{\n a = \"b\"\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": "=", + "value": "\"b\"", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "_part2": [ + { + "name": "_part2", + "type_name": "", + "op_sym": "=", + "value": "{\n c = \"d\"\n}", + "list_items": [], + "dict_entries": [ + { + "key": "c", + "value": { + "name": "c", + "type_name": "", + "op_sym": "=", + "value": "\"d\"", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "a": [ + { + "name": "a", + "type_name": "", + "op_sym": "=", + "value": "1", + "list_items": [], + "dict_entries": [] + } + ], + "a1": [ + { + "name": "a1", + "type_name": "", + "op_sym": "=", + "value": "2", + "list_items": [], + "dict_entries": [] + } + ], + "a3": [ + { + "name": "a3", + "type_name": "", + "op_sym": "=", + "value": "3m", + "list_items": [], + "dict_entries": [] + } + ], + "a_dict": [ + { + "name": "a_dict", + "type_name": "", + "op_sym": "=", + "value": "{\n **_part1\n **_part2\n}", + "list_items": [], + "dict_entries": [ + { + "key": "", + "value": { + "name": "", + "type_name": "", + "op_sym": ":", + "value": "_part1", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "", + "value": { + "name": "", + "type_name": "", + "op_sym": ":", + "value": "_part2", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "array1": [ + { + "name": "array1", + "type_name": "", + "op_sym": "=", + "value": "[\n 1\n 2\n 3\n]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "1", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "2", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "3", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + ], + "b1": [ + { + "name": "b1", + "type_name": "", + "op_sym": "=", + "value": "True", + "list_items": [], + "dict_entries": [] + } + ], + "b2": [ + { + "name": "b2", + "type_name": "", + "op_sym": "=", + "value": "False", + "list_items": [], + "dict_entries": [] + } + ], + "c": [ + { + "name": "c", + "type_name": "C", + "op_sym": "=", + "value": "C {\n a: {name: \"Hello\"}\n a: {ids: [7, 8, 9]}\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{\n name: \"Hello\"\n}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": ":", + "value": "\"Hello\"", + "list_items": [], + "dict_entries": [] + } + } + ] + } + }, + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{\n ids: [7, 8, 9]\n}", + "list_items": [], + "dict_entries": [ + { + "key": "ids", + "value": { + "name": "ids", + "type_name": "", + "op_sym": ":", + "value": "[\n 7\n 8\n 9\n]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "7", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "8", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "9", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + } + ] + } + } + ] + } + ], + "dict1": [ + { + "name": "dict1", + "type_name": "", + "op_sym": "=", + "value": "{\n \"a\": 1\n \"b\": 2\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "1", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "b", + "value": { + "name": "b", + "type_name": "", + "op_sym": ":", + "value": "2", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "dict2": [ + { + "name": "dict2", + "type_name": "", + "op_sym": "=", + "value": "{\n \"a\": 1\n \"b\": {\n \"c\": 2\n \"d\": 3\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "1", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "b", + "value": { + "name": "b", + "type_name": "", + "op_sym": ":", + "value": "{\n \"c\": 2\n \"d\": 3\n}", + "list_items": [], + "dict_entries": [ + { + "key": "c", + "value": { + "name": "c", + "type_name": "", + "op_sym": ":", + "value": "2", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "d", + "value": { + "name": "d", + "type_name": "", + "op_sym": ":", + "value": "3", + "list_items": [], + "dict_entries": [] + } + } + ] + } + } + ] + } + ], + "job": [ + { + "name": "job", + "type_name": "Job", + "op_sym": "=", + "value": "Job {\n name = \"{}-{}\".format(\"app\", \"test\").lower()\n}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": "=", + "value": "\"{}-{}\".format(\"app\", \"test\").lower()", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "s1": [ + { + "name": "s1", + "type_name": "", + "op_sym": "=", + "value": "\"Hello\"", + "list_items": [], + "dict_entries": [] + } + ], + "select": [ + { + "name": "select", + "type_name": "a.b.c", + "op_sym": "=", + "value": "a.b.c {\n a: 1\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "1", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "sha": [ + { + "name": "sha", + "type_name": "A", + "op_sym": "=", + "value": "A {\n name: \"Hello\"\n ids: [1, 2, 3]\n data: {\n \"a\": {\n \"b\": {\n \"c\": 2\n }\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": ":", + "value": "\"Hello\"", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "ids", + "value": { + "name": "ids", + "type_name": "", + "op_sym": ":", + "value": "[\n 1\n 2\n 3\n]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "1", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "2", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "3", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + }, + { + "key": "data", + "value": { + "name": "data", + "type_name": "", + "op_sym": ":", + "value": "{\n \"a\": {\n \"b\": {\n \"c\": 2\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{\n \"b\": {\n \"c\": 2\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "b", + "value": { + "name": "b", + "type_name": "", + "op_sym": ":", + "value": "{\n \"c\": 2\n}", + "list_items": [], + "dict_entries": [ + { + "key": "c", + "value": { + "name": "c", + "type_name": "", + "op_sym": ":", + "value": "2", + "list_items": [], + "dict_entries": [] + } + } + ] + } + } + ] + } + } + ] + } + } + ] + } + ], + "shb": [ + { + "name": "shb", + "type_name": "B", + "op_sym": "=", + "value": "B {\n a: {\n name: \"HelloB\"\n ids: [4, 5, 6]\n data: {\n \"d\": {\n \"e\": {\n \"f\": 3\n }\n }\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{\n name: \"HelloB\"\n ids: [4, 5, 6]\n data: {\n \"d\": {\n \"e\": {\n \"f\": 3\n }\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": ":", + "value": "\"HelloB\"", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "ids", + "value": { + "name": "ids", + "type_name": "", + "op_sym": ":", + "value": "[\n 4\n 5\n 6\n]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "4", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "5", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "6", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + }, + { + "key": "data", + "value": { + "name": "data", + "type_name": "", + "op_sym": ":", + "value": "{\n \"d\": {\n \"e\": {\n \"f\": 3\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "d", + "value": { + "name": "d", + "type_name": "", + "op_sym": ":", + "value": "{\n \"e\": {\n \"f\": 3\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "e", + "value": { + "name": "e", + "type_name": "", + "op_sym": ":", + "value": "{\n \"f\": 3\n}", + "list_items": [], + "dict_entries": [ + { + "key": "f", + "value": { + "name": "f", + "type_name": "", + "op_sym": ":", + "value": "3", + "list_items": [], + "dict_entries": [] + } + } + ] + } + } + ] + } + } + ] + } + } + ] + } + } + ] + } + ], + "uconfa": [ + { + "name": "uconfa", + "type_name": "UnificationConf", + "op_sym": ":", + "value": "UnificationConf {\n name = \"b\"\n}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": "=", + "value": "\"b\"", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "union_list": [ + { + "name": "union_list", + "type_name": "", + "op_sym": "=", + "value": "[\n *_list0\n *_list1\n]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "*_list0", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "*_list1", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + ] +} diff --git a/kclvm/query/src/snapshots/kclvm_query__tests__list_all_variables-2.snap b/kclvm/query/src/snapshots/kclvm_query__tests__list_all_variables-2.snap new file mode 100644 index 000000000..05312712c --- /dev/null +++ b/kclvm/query/src/snapshots/kclvm_query__tests__list_all_variables-2.snap @@ -0,0 +1,734 @@ +--- +source: query/src/tests.rs +expression: got_json +--- +{ + "_list0": [ + { + "name": "_list0", + "type_name": "", + "op_sym": "=", + "value": "[\n 1\n 2\n 3\n]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "1", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "2", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "3", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + ], + "_list1": [ + { + "name": "_list1", + "type_name": "", + "op_sym": "=", + "value": "[\n 4\n 5\n 6\n]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "4", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "5", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "6", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + ], + "_part1": [ + { + "name": "_part1", + "type_name": "", + "op_sym": "=", + "value": "{\n a = \"b\"\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": "=", + "value": "\"b\"", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "_part2": [ + { + "name": "_part2", + "type_name": "", + "op_sym": "=", + "value": "{\n c = \"d\"\n}", + "list_items": [], + "dict_entries": [ + { + "key": "c", + "value": { + "name": "c", + "type_name": "", + "op_sym": "=", + "value": "\"d\"", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "a": [ + { + "name": "a", + "type_name": "", + "op_sym": "=", + "value": "1", + "list_items": [], + "dict_entries": [] + } + ], + "a1": [ + { + "name": "a1", + "type_name": "", + "op_sym": "=", + "value": "2", + "list_items": [], + "dict_entries": [] + } + ], + "a3": [ + { + "name": "a3", + "type_name": "", + "op_sym": "=", + "value": "3m", + "list_items": [], + "dict_entries": [] + } + ], + "a_dict": [ + { + "name": "a_dict", + "type_name": "", + "op_sym": "=", + "value": "{\n **_part1\n **_part2\n}", + "list_items": [], + "dict_entries": [ + { + "key": "", + "value": { + "name": "", + "type_name": "", + "op_sym": ":", + "value": "_part1", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "", + "value": { + "name": "", + "type_name": "", + "op_sym": ":", + "value": "_part2", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "array1": [ + { + "name": "array1", + "type_name": "", + "op_sym": "=", + "value": "[\n 1\n 2\n 3\n]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "1", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "2", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "3", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + ], + "b1": [ + { + "name": "b1", + "type_name": "", + "op_sym": "=", + "value": "True", + "list_items": [], + "dict_entries": [] + } + ], + "b2": [ + { + "name": "b2", + "type_name": "", + "op_sym": "=", + "value": "False", + "list_items": [], + "dict_entries": [] + } + ], + "c": [ + { + "name": "c", + "type_name": "C", + "op_sym": "=", + "value": "C {\n a: {name: \"Hello\"}\n a: {ids: [7, 8, 9]}\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{\n name: \"Hello\"\n}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": ":", + "value": "\"Hello\"", + "list_items": [], + "dict_entries": [] + } + } + ] + } + }, + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{\n ids: [7, 8, 9]\n}", + "list_items": [], + "dict_entries": [ + { + "key": "ids", + "value": { + "name": "ids", + "type_name": "", + "op_sym": ":", + "value": "[\n 7\n 8\n 9\n]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "7", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "8", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "9", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + } + ] + } + } + ] + } + ], + "dict1": [ + { + "name": "dict1", + "type_name": "", + "op_sym": "=", + "value": "{\n \"a\": 1\n \"b\": 2\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "1", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "b", + "value": { + "name": "b", + "type_name": "", + "op_sym": ":", + "value": "2", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "dict2": [ + { + "name": "dict2", + "type_name": "", + "op_sym": "=", + "value": "{\n \"a\": 1\n \"b\": {\n \"c\": 2\n \"d\": 3\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "1", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "b", + "value": { + "name": "b", + "type_name": "", + "op_sym": ":", + "value": "{\n \"c\": 2\n \"d\": 3\n}", + "list_items": [], + "dict_entries": [ + { + "key": "c", + "value": { + "name": "c", + "type_name": "", + "op_sym": ":", + "value": "2", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "d", + "value": { + "name": "d", + "type_name": "", + "op_sym": ":", + "value": "3", + "list_items": [], + "dict_entries": [] + } + } + ] + } + } + ] + } + ], + "job": [ + { + "name": "job", + "type_name": "Job", + "op_sym": "=", + "value": "Job {\n name = \"{}-{}\".format(\"app\", \"test\").lower()\n}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": "=", + "value": "\"{}-{}\".format(\"app\", \"test\").lower()", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "s1": [ + { + "name": "s1", + "type_name": "", + "op_sym": "=", + "value": "\"Hello\"", + "list_items": [], + "dict_entries": [] + } + ], + "select": [ + { + "name": "select", + "type_name": "a.b.c", + "op_sym": "=", + "value": "a.b.c {\n a: 1\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "1", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "sha": [ + { + "name": "sha", + "type_name": "A", + "op_sym": "=", + "value": "A {\n name: \"Hello\"\n ids: [1, 2, 3]\n data: {\n \"a\": {\n \"b\": {\n \"c\": 2\n }\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": ":", + "value": "\"Hello\"", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "ids", + "value": { + "name": "ids", + "type_name": "", + "op_sym": ":", + "value": "[\n 1\n 2\n 3\n]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "1", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "2", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "3", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + }, + { + "key": "data", + "value": { + "name": "data", + "type_name": "", + "op_sym": ":", + "value": "{\n \"a\": {\n \"b\": {\n \"c\": 2\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{\n \"b\": {\n \"c\": 2\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "b", + "value": { + "name": "b", + "type_name": "", + "op_sym": ":", + "value": "{\n \"c\": 2\n}", + "list_items": [], + "dict_entries": [ + { + "key": "c", + "value": { + "name": "c", + "type_name": "", + "op_sym": ":", + "value": "2", + "list_items": [], + "dict_entries": [] + } + } + ] + } + } + ] + } + } + ] + } + } + ] + } + ], + "shb": [ + { + "name": "shb", + "type_name": "B", + "op_sym": "=", + "value": "B {\n a: {\n name: \"HelloB\"\n ids: [4, 5, 6]\n data: {\n \"d\": {\n \"e\": {\n \"f\": 3\n }\n }\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{\n name: \"HelloB\"\n ids: [4, 5, 6]\n data: {\n \"d\": {\n \"e\": {\n \"f\": 3\n }\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": ":", + "value": "\"HelloB\"", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "ids", + "value": { + "name": "ids", + "type_name": "", + "op_sym": ":", + "value": "[\n 4\n 5\n 6\n]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "4", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "5", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "6", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + }, + { + "key": "data", + "value": { + "name": "data", + "type_name": "", + "op_sym": ":", + "value": "{\n \"d\": {\n \"e\": {\n \"f\": 3\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "d", + "value": { + "name": "d", + "type_name": "", + "op_sym": ":", + "value": "{\n \"e\": {\n \"f\": 3\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "e", + "value": { + "name": "e", + "type_name": "", + "op_sym": ":", + "value": "{\n \"f\": 3\n}", + "list_items": [], + "dict_entries": [ + { + "key": "f", + "value": { + "name": "f", + "type_name": "", + "op_sym": ":", + "value": "3", + "list_items": [], + "dict_entries": [] + } + } + ] + } + } + ] + } + } + ] + } + } + ] + } + } + ] + } + ], + "uconfa": [ + { + "name": "uconfa", + "type_name": "UnificationConf", + "op_sym": ":", + "value": "UnificationConf {\n name = \"b\"\n}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": "=", + "value": "\"b\"", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "union_list": [ + { + "name": "union_list", + "type_name": "", + "op_sym": "=", + "value": "[\n *_list0\n *_list1\n]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "*_list0", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "*_list1", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + ] +} diff --git a/kclvm/query/src/snapshots/kclvm_query__tests__list_all_variables-3.snap b/kclvm/query/src/snapshots/kclvm_query__tests__list_all_variables-3.snap new file mode 100644 index 000000000..05312712c --- /dev/null +++ b/kclvm/query/src/snapshots/kclvm_query__tests__list_all_variables-3.snap @@ -0,0 +1,734 @@ +--- +source: query/src/tests.rs +expression: got_json +--- +{ + "_list0": [ + { + "name": "_list0", + "type_name": "", + "op_sym": "=", + "value": "[\n 1\n 2\n 3\n]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "1", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "2", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "3", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + ], + "_list1": [ + { + "name": "_list1", + "type_name": "", + "op_sym": "=", + "value": "[\n 4\n 5\n 6\n]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "4", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "5", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "6", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + ], + "_part1": [ + { + "name": "_part1", + "type_name": "", + "op_sym": "=", + "value": "{\n a = \"b\"\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": "=", + "value": "\"b\"", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "_part2": [ + { + "name": "_part2", + "type_name": "", + "op_sym": "=", + "value": "{\n c = \"d\"\n}", + "list_items": [], + "dict_entries": [ + { + "key": "c", + "value": { + "name": "c", + "type_name": "", + "op_sym": "=", + "value": "\"d\"", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "a": [ + { + "name": "a", + "type_name": "", + "op_sym": "=", + "value": "1", + "list_items": [], + "dict_entries": [] + } + ], + "a1": [ + { + "name": "a1", + "type_name": "", + "op_sym": "=", + "value": "2", + "list_items": [], + "dict_entries": [] + } + ], + "a3": [ + { + "name": "a3", + "type_name": "", + "op_sym": "=", + "value": "3m", + "list_items": [], + "dict_entries": [] + } + ], + "a_dict": [ + { + "name": "a_dict", + "type_name": "", + "op_sym": "=", + "value": "{\n **_part1\n **_part2\n}", + "list_items": [], + "dict_entries": [ + { + "key": "", + "value": { + "name": "", + "type_name": "", + "op_sym": ":", + "value": "_part1", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "", + "value": { + "name": "", + "type_name": "", + "op_sym": ":", + "value": "_part2", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "array1": [ + { + "name": "array1", + "type_name": "", + "op_sym": "=", + "value": "[\n 1\n 2\n 3\n]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "1", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "2", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "3", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + ], + "b1": [ + { + "name": "b1", + "type_name": "", + "op_sym": "=", + "value": "True", + "list_items": [], + "dict_entries": [] + } + ], + "b2": [ + { + "name": "b2", + "type_name": "", + "op_sym": "=", + "value": "False", + "list_items": [], + "dict_entries": [] + } + ], + "c": [ + { + "name": "c", + "type_name": "C", + "op_sym": "=", + "value": "C {\n a: {name: \"Hello\"}\n a: {ids: [7, 8, 9]}\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{\n name: \"Hello\"\n}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": ":", + "value": "\"Hello\"", + "list_items": [], + "dict_entries": [] + } + } + ] + } + }, + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{\n ids: [7, 8, 9]\n}", + "list_items": [], + "dict_entries": [ + { + "key": "ids", + "value": { + "name": "ids", + "type_name": "", + "op_sym": ":", + "value": "[\n 7\n 8\n 9\n]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "7", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "8", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "9", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + } + ] + } + } + ] + } + ], + "dict1": [ + { + "name": "dict1", + "type_name": "", + "op_sym": "=", + "value": "{\n \"a\": 1\n \"b\": 2\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "1", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "b", + "value": { + "name": "b", + "type_name": "", + "op_sym": ":", + "value": "2", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "dict2": [ + { + "name": "dict2", + "type_name": "", + "op_sym": "=", + "value": "{\n \"a\": 1\n \"b\": {\n \"c\": 2\n \"d\": 3\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "1", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "b", + "value": { + "name": "b", + "type_name": "", + "op_sym": ":", + "value": "{\n \"c\": 2\n \"d\": 3\n}", + "list_items": [], + "dict_entries": [ + { + "key": "c", + "value": { + "name": "c", + "type_name": "", + "op_sym": ":", + "value": "2", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "d", + "value": { + "name": "d", + "type_name": "", + "op_sym": ":", + "value": "3", + "list_items": [], + "dict_entries": [] + } + } + ] + } + } + ] + } + ], + "job": [ + { + "name": "job", + "type_name": "Job", + "op_sym": "=", + "value": "Job {\n name = \"{}-{}\".format(\"app\", \"test\").lower()\n}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": "=", + "value": "\"{}-{}\".format(\"app\", \"test\").lower()", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "s1": [ + { + "name": "s1", + "type_name": "", + "op_sym": "=", + "value": "\"Hello\"", + "list_items": [], + "dict_entries": [] + } + ], + "select": [ + { + "name": "select", + "type_name": "a.b.c", + "op_sym": "=", + "value": "a.b.c {\n a: 1\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "1", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "sha": [ + { + "name": "sha", + "type_name": "A", + "op_sym": "=", + "value": "A {\n name: \"Hello\"\n ids: [1, 2, 3]\n data: {\n \"a\": {\n \"b\": {\n \"c\": 2\n }\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": ":", + "value": "\"Hello\"", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "ids", + "value": { + "name": "ids", + "type_name": "", + "op_sym": ":", + "value": "[\n 1\n 2\n 3\n]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "1", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "2", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "3", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + }, + { + "key": "data", + "value": { + "name": "data", + "type_name": "", + "op_sym": ":", + "value": "{\n \"a\": {\n \"b\": {\n \"c\": 2\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{\n \"b\": {\n \"c\": 2\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "b", + "value": { + "name": "b", + "type_name": "", + "op_sym": ":", + "value": "{\n \"c\": 2\n}", + "list_items": [], + "dict_entries": [ + { + "key": "c", + "value": { + "name": "c", + "type_name": "", + "op_sym": ":", + "value": "2", + "list_items": [], + "dict_entries": [] + } + } + ] + } + } + ] + } + } + ] + } + } + ] + } + ], + "shb": [ + { + "name": "shb", + "type_name": "B", + "op_sym": "=", + "value": "B {\n a: {\n name: \"HelloB\"\n ids: [4, 5, 6]\n data: {\n \"d\": {\n \"e\": {\n \"f\": 3\n }\n }\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{\n name: \"HelloB\"\n ids: [4, 5, 6]\n data: {\n \"d\": {\n \"e\": {\n \"f\": 3\n }\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": ":", + "value": "\"HelloB\"", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "ids", + "value": { + "name": "ids", + "type_name": "", + "op_sym": ":", + "value": "[\n 4\n 5\n 6\n]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "4", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "5", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "6", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + }, + { + "key": "data", + "value": { + "name": "data", + "type_name": "", + "op_sym": ":", + "value": "{\n \"d\": {\n \"e\": {\n \"f\": 3\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "d", + "value": { + "name": "d", + "type_name": "", + "op_sym": ":", + "value": "{\n \"e\": {\n \"f\": 3\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "e", + "value": { + "name": "e", + "type_name": "", + "op_sym": ":", + "value": "{\n \"f\": 3\n}", + "list_items": [], + "dict_entries": [ + { + "key": "f", + "value": { + "name": "f", + "type_name": "", + "op_sym": ":", + "value": "3", + "list_items": [], + "dict_entries": [] + } + } + ] + } + } + ] + } + } + ] + } + } + ] + } + } + ] + } + ], + "uconfa": [ + { + "name": "uconfa", + "type_name": "UnificationConf", + "op_sym": ":", + "value": "UnificationConf {\n name = \"b\"\n}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": "=", + "value": "\"b\"", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "union_list": [ + { + "name": "union_list", + "type_name": "", + "op_sym": "=", + "value": "[\n *_list0\n *_list1\n]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "*_list0", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "*_list1", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + ] +} diff --git a/kclvm/query/src/snapshots/kclvm_query__tests__list_all_variables-4.snap b/kclvm/query/src/snapshots/kclvm_query__tests__list_all_variables-4.snap new file mode 100644 index 000000000..05312712c --- /dev/null +++ b/kclvm/query/src/snapshots/kclvm_query__tests__list_all_variables-4.snap @@ -0,0 +1,734 @@ +--- +source: query/src/tests.rs +expression: got_json +--- +{ + "_list0": [ + { + "name": "_list0", + "type_name": "", + "op_sym": "=", + "value": "[\n 1\n 2\n 3\n]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "1", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "2", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "3", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + ], + "_list1": [ + { + "name": "_list1", + "type_name": "", + "op_sym": "=", + "value": "[\n 4\n 5\n 6\n]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "4", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "5", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "6", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + ], + "_part1": [ + { + "name": "_part1", + "type_name": "", + "op_sym": "=", + "value": "{\n a = \"b\"\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": "=", + "value": "\"b\"", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "_part2": [ + { + "name": "_part2", + "type_name": "", + "op_sym": "=", + "value": "{\n c = \"d\"\n}", + "list_items": [], + "dict_entries": [ + { + "key": "c", + "value": { + "name": "c", + "type_name": "", + "op_sym": "=", + "value": "\"d\"", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "a": [ + { + "name": "a", + "type_name": "", + "op_sym": "=", + "value": "1", + "list_items": [], + "dict_entries": [] + } + ], + "a1": [ + { + "name": "a1", + "type_name": "", + "op_sym": "=", + "value": "2", + "list_items": [], + "dict_entries": [] + } + ], + "a3": [ + { + "name": "a3", + "type_name": "", + "op_sym": "=", + "value": "3m", + "list_items": [], + "dict_entries": [] + } + ], + "a_dict": [ + { + "name": "a_dict", + "type_name": "", + "op_sym": "=", + "value": "{\n **_part1\n **_part2\n}", + "list_items": [], + "dict_entries": [ + { + "key": "", + "value": { + "name": "", + "type_name": "", + "op_sym": ":", + "value": "_part1", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "", + "value": { + "name": "", + "type_name": "", + "op_sym": ":", + "value": "_part2", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "array1": [ + { + "name": "array1", + "type_name": "", + "op_sym": "=", + "value": "[\n 1\n 2\n 3\n]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "1", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "2", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "3", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + ], + "b1": [ + { + "name": "b1", + "type_name": "", + "op_sym": "=", + "value": "True", + "list_items": [], + "dict_entries": [] + } + ], + "b2": [ + { + "name": "b2", + "type_name": "", + "op_sym": "=", + "value": "False", + "list_items": [], + "dict_entries": [] + } + ], + "c": [ + { + "name": "c", + "type_name": "C", + "op_sym": "=", + "value": "C {\n a: {name: \"Hello\"}\n a: {ids: [7, 8, 9]}\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{\n name: \"Hello\"\n}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": ":", + "value": "\"Hello\"", + "list_items": [], + "dict_entries": [] + } + } + ] + } + }, + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{\n ids: [7, 8, 9]\n}", + "list_items": [], + "dict_entries": [ + { + "key": "ids", + "value": { + "name": "ids", + "type_name": "", + "op_sym": ":", + "value": "[\n 7\n 8\n 9\n]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "7", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "8", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "9", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + } + ] + } + } + ] + } + ], + "dict1": [ + { + "name": "dict1", + "type_name": "", + "op_sym": "=", + "value": "{\n \"a\": 1\n \"b\": 2\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "1", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "b", + "value": { + "name": "b", + "type_name": "", + "op_sym": ":", + "value": "2", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "dict2": [ + { + "name": "dict2", + "type_name": "", + "op_sym": "=", + "value": "{\n \"a\": 1\n \"b\": {\n \"c\": 2\n \"d\": 3\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "1", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "b", + "value": { + "name": "b", + "type_name": "", + "op_sym": ":", + "value": "{\n \"c\": 2\n \"d\": 3\n}", + "list_items": [], + "dict_entries": [ + { + "key": "c", + "value": { + "name": "c", + "type_name": "", + "op_sym": ":", + "value": "2", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "d", + "value": { + "name": "d", + "type_name": "", + "op_sym": ":", + "value": "3", + "list_items": [], + "dict_entries": [] + } + } + ] + } + } + ] + } + ], + "job": [ + { + "name": "job", + "type_name": "Job", + "op_sym": "=", + "value": "Job {\n name = \"{}-{}\".format(\"app\", \"test\").lower()\n}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": "=", + "value": "\"{}-{}\".format(\"app\", \"test\").lower()", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "s1": [ + { + "name": "s1", + "type_name": "", + "op_sym": "=", + "value": "\"Hello\"", + "list_items": [], + "dict_entries": [] + } + ], + "select": [ + { + "name": "select", + "type_name": "a.b.c", + "op_sym": "=", + "value": "a.b.c {\n a: 1\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "1", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "sha": [ + { + "name": "sha", + "type_name": "A", + "op_sym": "=", + "value": "A {\n name: \"Hello\"\n ids: [1, 2, 3]\n data: {\n \"a\": {\n \"b\": {\n \"c\": 2\n }\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": ":", + "value": "\"Hello\"", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "ids", + "value": { + "name": "ids", + "type_name": "", + "op_sym": ":", + "value": "[\n 1\n 2\n 3\n]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "1", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "2", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "3", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + }, + { + "key": "data", + "value": { + "name": "data", + "type_name": "", + "op_sym": ":", + "value": "{\n \"a\": {\n \"b\": {\n \"c\": 2\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{\n \"b\": {\n \"c\": 2\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "b", + "value": { + "name": "b", + "type_name": "", + "op_sym": ":", + "value": "{\n \"c\": 2\n}", + "list_items": [], + "dict_entries": [ + { + "key": "c", + "value": { + "name": "c", + "type_name": "", + "op_sym": ":", + "value": "2", + "list_items": [], + "dict_entries": [] + } + } + ] + } + } + ] + } + } + ] + } + } + ] + } + ], + "shb": [ + { + "name": "shb", + "type_name": "B", + "op_sym": "=", + "value": "B {\n a: {\n name: \"HelloB\"\n ids: [4, 5, 6]\n data: {\n \"d\": {\n \"e\": {\n \"f\": 3\n }\n }\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{\n name: \"HelloB\"\n ids: [4, 5, 6]\n data: {\n \"d\": {\n \"e\": {\n \"f\": 3\n }\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": ":", + "value": "\"HelloB\"", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "ids", + "value": { + "name": "ids", + "type_name": "", + "op_sym": ":", + "value": "[\n 4\n 5\n 6\n]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "4", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "5", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "6", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + }, + { + "key": "data", + "value": { + "name": "data", + "type_name": "", + "op_sym": ":", + "value": "{\n \"d\": {\n \"e\": {\n \"f\": 3\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "d", + "value": { + "name": "d", + "type_name": "", + "op_sym": ":", + "value": "{\n \"e\": {\n \"f\": 3\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "e", + "value": { + "name": "e", + "type_name": "", + "op_sym": ":", + "value": "{\n \"f\": 3\n}", + "list_items": [], + "dict_entries": [ + { + "key": "f", + "value": { + "name": "f", + "type_name": "", + "op_sym": ":", + "value": "3", + "list_items": [], + "dict_entries": [] + } + } + ] + } + } + ] + } + } + ] + } + } + ] + } + } + ] + } + ], + "uconfa": [ + { + "name": "uconfa", + "type_name": "UnificationConf", + "op_sym": ":", + "value": "UnificationConf {\n name = \"b\"\n}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": "=", + "value": "\"b\"", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "union_list": [ + { + "name": "union_list", + "type_name": "", + "op_sym": "=", + "value": "[\n *_list0\n *_list1\n]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "*_list0", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "*_list1", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + ] +} diff --git a/kclvm/query/src/snapshots/kclvm_query__tests__list_all_variables-5.snap b/kclvm/query/src/snapshots/kclvm_query__tests__list_all_variables-5.snap new file mode 100644 index 000000000..05312712c --- /dev/null +++ b/kclvm/query/src/snapshots/kclvm_query__tests__list_all_variables-5.snap @@ -0,0 +1,734 @@ +--- +source: query/src/tests.rs +expression: got_json +--- +{ + "_list0": [ + { + "name": "_list0", + "type_name": "", + "op_sym": "=", + "value": "[\n 1\n 2\n 3\n]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "1", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "2", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "3", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + ], + "_list1": [ + { + "name": "_list1", + "type_name": "", + "op_sym": "=", + "value": "[\n 4\n 5\n 6\n]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "4", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "5", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "6", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + ], + "_part1": [ + { + "name": "_part1", + "type_name": "", + "op_sym": "=", + "value": "{\n a = \"b\"\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": "=", + "value": "\"b\"", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "_part2": [ + { + "name": "_part2", + "type_name": "", + "op_sym": "=", + "value": "{\n c = \"d\"\n}", + "list_items": [], + "dict_entries": [ + { + "key": "c", + "value": { + "name": "c", + "type_name": "", + "op_sym": "=", + "value": "\"d\"", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "a": [ + { + "name": "a", + "type_name": "", + "op_sym": "=", + "value": "1", + "list_items": [], + "dict_entries": [] + } + ], + "a1": [ + { + "name": "a1", + "type_name": "", + "op_sym": "=", + "value": "2", + "list_items": [], + "dict_entries": [] + } + ], + "a3": [ + { + "name": "a3", + "type_name": "", + "op_sym": "=", + "value": "3m", + "list_items": [], + "dict_entries": [] + } + ], + "a_dict": [ + { + "name": "a_dict", + "type_name": "", + "op_sym": "=", + "value": "{\n **_part1\n **_part2\n}", + "list_items": [], + "dict_entries": [ + { + "key": "", + "value": { + "name": "", + "type_name": "", + "op_sym": ":", + "value": "_part1", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "", + "value": { + "name": "", + "type_name": "", + "op_sym": ":", + "value": "_part2", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "array1": [ + { + "name": "array1", + "type_name": "", + "op_sym": "=", + "value": "[\n 1\n 2\n 3\n]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "1", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "2", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "3", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + ], + "b1": [ + { + "name": "b1", + "type_name": "", + "op_sym": "=", + "value": "True", + "list_items": [], + "dict_entries": [] + } + ], + "b2": [ + { + "name": "b2", + "type_name": "", + "op_sym": "=", + "value": "False", + "list_items": [], + "dict_entries": [] + } + ], + "c": [ + { + "name": "c", + "type_name": "C", + "op_sym": "=", + "value": "C {\n a: {name: \"Hello\"}\n a: {ids: [7, 8, 9]}\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{\n name: \"Hello\"\n}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": ":", + "value": "\"Hello\"", + "list_items": [], + "dict_entries": [] + } + } + ] + } + }, + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{\n ids: [7, 8, 9]\n}", + "list_items": [], + "dict_entries": [ + { + "key": "ids", + "value": { + "name": "ids", + "type_name": "", + "op_sym": ":", + "value": "[\n 7\n 8\n 9\n]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "7", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "8", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "9", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + } + ] + } + } + ] + } + ], + "dict1": [ + { + "name": "dict1", + "type_name": "", + "op_sym": "=", + "value": "{\n \"a\": 1\n \"b\": 2\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "1", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "b", + "value": { + "name": "b", + "type_name": "", + "op_sym": ":", + "value": "2", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "dict2": [ + { + "name": "dict2", + "type_name": "", + "op_sym": "=", + "value": "{\n \"a\": 1\n \"b\": {\n \"c\": 2\n \"d\": 3\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "1", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "b", + "value": { + "name": "b", + "type_name": "", + "op_sym": ":", + "value": "{\n \"c\": 2\n \"d\": 3\n}", + "list_items": [], + "dict_entries": [ + { + "key": "c", + "value": { + "name": "c", + "type_name": "", + "op_sym": ":", + "value": "2", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "d", + "value": { + "name": "d", + "type_name": "", + "op_sym": ":", + "value": "3", + "list_items": [], + "dict_entries": [] + } + } + ] + } + } + ] + } + ], + "job": [ + { + "name": "job", + "type_name": "Job", + "op_sym": "=", + "value": "Job {\n name = \"{}-{}\".format(\"app\", \"test\").lower()\n}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": "=", + "value": "\"{}-{}\".format(\"app\", \"test\").lower()", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "s1": [ + { + "name": "s1", + "type_name": "", + "op_sym": "=", + "value": "\"Hello\"", + "list_items": [], + "dict_entries": [] + } + ], + "select": [ + { + "name": "select", + "type_name": "a.b.c", + "op_sym": "=", + "value": "a.b.c {\n a: 1\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "1", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "sha": [ + { + "name": "sha", + "type_name": "A", + "op_sym": "=", + "value": "A {\n name: \"Hello\"\n ids: [1, 2, 3]\n data: {\n \"a\": {\n \"b\": {\n \"c\": 2\n }\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": ":", + "value": "\"Hello\"", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "ids", + "value": { + "name": "ids", + "type_name": "", + "op_sym": ":", + "value": "[\n 1\n 2\n 3\n]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "1", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "2", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "3", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + }, + { + "key": "data", + "value": { + "name": "data", + "type_name": "", + "op_sym": ":", + "value": "{\n \"a\": {\n \"b\": {\n \"c\": 2\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{\n \"b\": {\n \"c\": 2\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "b", + "value": { + "name": "b", + "type_name": "", + "op_sym": ":", + "value": "{\n \"c\": 2\n}", + "list_items": [], + "dict_entries": [ + { + "key": "c", + "value": { + "name": "c", + "type_name": "", + "op_sym": ":", + "value": "2", + "list_items": [], + "dict_entries": [] + } + } + ] + } + } + ] + } + } + ] + } + } + ] + } + ], + "shb": [ + { + "name": "shb", + "type_name": "B", + "op_sym": "=", + "value": "B {\n a: {\n name: \"HelloB\"\n ids: [4, 5, 6]\n data: {\n \"d\": {\n \"e\": {\n \"f\": 3\n }\n }\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{\n name: \"HelloB\"\n ids: [4, 5, 6]\n data: {\n \"d\": {\n \"e\": {\n \"f\": 3\n }\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": ":", + "value": "\"HelloB\"", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "ids", + "value": { + "name": "ids", + "type_name": "", + "op_sym": ":", + "value": "[\n 4\n 5\n 6\n]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "4", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "5", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "6", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + }, + { + "key": "data", + "value": { + "name": "data", + "type_name": "", + "op_sym": ":", + "value": "{\n \"d\": {\n \"e\": {\n \"f\": 3\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "d", + "value": { + "name": "d", + "type_name": "", + "op_sym": ":", + "value": "{\n \"e\": {\n \"f\": 3\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "e", + "value": { + "name": "e", + "type_name": "", + "op_sym": ":", + "value": "{\n \"f\": 3\n}", + "list_items": [], + "dict_entries": [ + { + "key": "f", + "value": { + "name": "f", + "type_name": "", + "op_sym": ":", + "value": "3", + "list_items": [], + "dict_entries": [] + } + } + ] + } + } + ] + } + } + ] + } + } + ] + } + } + ] + } + ], + "uconfa": [ + { + "name": "uconfa", + "type_name": "UnificationConf", + "op_sym": ":", + "value": "UnificationConf {\n name = \"b\"\n}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": "=", + "value": "\"b\"", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "union_list": [ + { + "name": "union_list", + "type_name": "", + "op_sym": "=", + "value": "[\n *_list0\n *_list1\n]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "*_list0", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "*_list1", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + ] +} diff --git a/kclvm/query/src/snapshots/kclvm_query__tests__list_all_variables-6.snap b/kclvm/query/src/snapshots/kclvm_query__tests__list_all_variables-6.snap new file mode 100644 index 000000000..05312712c --- /dev/null +++ b/kclvm/query/src/snapshots/kclvm_query__tests__list_all_variables-6.snap @@ -0,0 +1,734 @@ +--- +source: query/src/tests.rs +expression: got_json +--- +{ + "_list0": [ + { + "name": "_list0", + "type_name": "", + "op_sym": "=", + "value": "[\n 1\n 2\n 3\n]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "1", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "2", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "3", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + ], + "_list1": [ + { + "name": "_list1", + "type_name": "", + "op_sym": "=", + "value": "[\n 4\n 5\n 6\n]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "4", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "5", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "6", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + ], + "_part1": [ + { + "name": "_part1", + "type_name": "", + "op_sym": "=", + "value": "{\n a = \"b\"\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": "=", + "value": "\"b\"", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "_part2": [ + { + "name": "_part2", + "type_name": "", + "op_sym": "=", + "value": "{\n c = \"d\"\n}", + "list_items": [], + "dict_entries": [ + { + "key": "c", + "value": { + "name": "c", + "type_name": "", + "op_sym": "=", + "value": "\"d\"", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "a": [ + { + "name": "a", + "type_name": "", + "op_sym": "=", + "value": "1", + "list_items": [], + "dict_entries": [] + } + ], + "a1": [ + { + "name": "a1", + "type_name": "", + "op_sym": "=", + "value": "2", + "list_items": [], + "dict_entries": [] + } + ], + "a3": [ + { + "name": "a3", + "type_name": "", + "op_sym": "=", + "value": "3m", + "list_items": [], + "dict_entries": [] + } + ], + "a_dict": [ + { + "name": "a_dict", + "type_name": "", + "op_sym": "=", + "value": "{\n **_part1\n **_part2\n}", + "list_items": [], + "dict_entries": [ + { + "key": "", + "value": { + "name": "", + "type_name": "", + "op_sym": ":", + "value": "_part1", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "", + "value": { + "name": "", + "type_name": "", + "op_sym": ":", + "value": "_part2", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "array1": [ + { + "name": "array1", + "type_name": "", + "op_sym": "=", + "value": "[\n 1\n 2\n 3\n]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "1", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "2", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "3", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + ], + "b1": [ + { + "name": "b1", + "type_name": "", + "op_sym": "=", + "value": "True", + "list_items": [], + "dict_entries": [] + } + ], + "b2": [ + { + "name": "b2", + "type_name": "", + "op_sym": "=", + "value": "False", + "list_items": [], + "dict_entries": [] + } + ], + "c": [ + { + "name": "c", + "type_name": "C", + "op_sym": "=", + "value": "C {\n a: {name: \"Hello\"}\n a: {ids: [7, 8, 9]}\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{\n name: \"Hello\"\n}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": ":", + "value": "\"Hello\"", + "list_items": [], + "dict_entries": [] + } + } + ] + } + }, + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{\n ids: [7, 8, 9]\n}", + "list_items": [], + "dict_entries": [ + { + "key": "ids", + "value": { + "name": "ids", + "type_name": "", + "op_sym": ":", + "value": "[\n 7\n 8\n 9\n]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "7", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "8", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "9", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + } + ] + } + } + ] + } + ], + "dict1": [ + { + "name": "dict1", + "type_name": "", + "op_sym": "=", + "value": "{\n \"a\": 1\n \"b\": 2\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "1", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "b", + "value": { + "name": "b", + "type_name": "", + "op_sym": ":", + "value": "2", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "dict2": [ + { + "name": "dict2", + "type_name": "", + "op_sym": "=", + "value": "{\n \"a\": 1\n \"b\": {\n \"c\": 2\n \"d\": 3\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "1", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "b", + "value": { + "name": "b", + "type_name": "", + "op_sym": ":", + "value": "{\n \"c\": 2\n \"d\": 3\n}", + "list_items": [], + "dict_entries": [ + { + "key": "c", + "value": { + "name": "c", + "type_name": "", + "op_sym": ":", + "value": "2", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "d", + "value": { + "name": "d", + "type_name": "", + "op_sym": ":", + "value": "3", + "list_items": [], + "dict_entries": [] + } + } + ] + } + } + ] + } + ], + "job": [ + { + "name": "job", + "type_name": "Job", + "op_sym": "=", + "value": "Job {\n name = \"{}-{}\".format(\"app\", \"test\").lower()\n}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": "=", + "value": "\"{}-{}\".format(\"app\", \"test\").lower()", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "s1": [ + { + "name": "s1", + "type_name": "", + "op_sym": "=", + "value": "\"Hello\"", + "list_items": [], + "dict_entries": [] + } + ], + "select": [ + { + "name": "select", + "type_name": "a.b.c", + "op_sym": "=", + "value": "a.b.c {\n a: 1\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "1", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "sha": [ + { + "name": "sha", + "type_name": "A", + "op_sym": "=", + "value": "A {\n name: \"Hello\"\n ids: [1, 2, 3]\n data: {\n \"a\": {\n \"b\": {\n \"c\": 2\n }\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": ":", + "value": "\"Hello\"", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "ids", + "value": { + "name": "ids", + "type_name": "", + "op_sym": ":", + "value": "[\n 1\n 2\n 3\n]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "1", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "2", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "3", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + }, + { + "key": "data", + "value": { + "name": "data", + "type_name": "", + "op_sym": ":", + "value": "{\n \"a\": {\n \"b\": {\n \"c\": 2\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{\n \"b\": {\n \"c\": 2\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "b", + "value": { + "name": "b", + "type_name": "", + "op_sym": ":", + "value": "{\n \"c\": 2\n}", + "list_items": [], + "dict_entries": [ + { + "key": "c", + "value": { + "name": "c", + "type_name": "", + "op_sym": ":", + "value": "2", + "list_items": [], + "dict_entries": [] + } + } + ] + } + } + ] + } + } + ] + } + } + ] + } + ], + "shb": [ + { + "name": "shb", + "type_name": "B", + "op_sym": "=", + "value": "B {\n a: {\n name: \"HelloB\"\n ids: [4, 5, 6]\n data: {\n \"d\": {\n \"e\": {\n \"f\": 3\n }\n }\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{\n name: \"HelloB\"\n ids: [4, 5, 6]\n data: {\n \"d\": {\n \"e\": {\n \"f\": 3\n }\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": ":", + "value": "\"HelloB\"", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "ids", + "value": { + "name": "ids", + "type_name": "", + "op_sym": ":", + "value": "[\n 4\n 5\n 6\n]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "4", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "5", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "6", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + }, + { + "key": "data", + "value": { + "name": "data", + "type_name": "", + "op_sym": ":", + "value": "{\n \"d\": {\n \"e\": {\n \"f\": 3\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "d", + "value": { + "name": "d", + "type_name": "", + "op_sym": ":", + "value": "{\n \"e\": {\n \"f\": 3\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "e", + "value": { + "name": "e", + "type_name": "", + "op_sym": ":", + "value": "{\n \"f\": 3\n}", + "list_items": [], + "dict_entries": [ + { + "key": "f", + "value": { + "name": "f", + "type_name": "", + "op_sym": ":", + "value": "3", + "list_items": [], + "dict_entries": [] + } + } + ] + } + } + ] + } + } + ] + } + } + ] + } + } + ] + } + ], + "uconfa": [ + { + "name": "uconfa", + "type_name": "UnificationConf", + "op_sym": ":", + "value": "UnificationConf {\n name = \"b\"\n}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": "=", + "value": "\"b\"", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "union_list": [ + { + "name": "union_list", + "type_name": "", + "op_sym": "=", + "value": "[\n *_list0\n *_list1\n]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "*_list0", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "*_list1", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + ] +} diff --git a/kclvm/query/src/snapshots/kclvm_query__tests__list_all_variables-7.snap b/kclvm/query/src/snapshots/kclvm_query__tests__list_all_variables-7.snap new file mode 100644 index 000000000..05312712c --- /dev/null +++ b/kclvm/query/src/snapshots/kclvm_query__tests__list_all_variables-7.snap @@ -0,0 +1,734 @@ +--- +source: query/src/tests.rs +expression: got_json +--- +{ + "_list0": [ + { + "name": "_list0", + "type_name": "", + "op_sym": "=", + "value": "[\n 1\n 2\n 3\n]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "1", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "2", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "3", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + ], + "_list1": [ + { + "name": "_list1", + "type_name": "", + "op_sym": "=", + "value": "[\n 4\n 5\n 6\n]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "4", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "5", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "6", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + ], + "_part1": [ + { + "name": "_part1", + "type_name": "", + "op_sym": "=", + "value": "{\n a = \"b\"\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": "=", + "value": "\"b\"", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "_part2": [ + { + "name": "_part2", + "type_name": "", + "op_sym": "=", + "value": "{\n c = \"d\"\n}", + "list_items": [], + "dict_entries": [ + { + "key": "c", + "value": { + "name": "c", + "type_name": "", + "op_sym": "=", + "value": "\"d\"", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "a": [ + { + "name": "a", + "type_name": "", + "op_sym": "=", + "value": "1", + "list_items": [], + "dict_entries": [] + } + ], + "a1": [ + { + "name": "a1", + "type_name": "", + "op_sym": "=", + "value": "2", + "list_items": [], + "dict_entries": [] + } + ], + "a3": [ + { + "name": "a3", + "type_name": "", + "op_sym": "=", + "value": "3m", + "list_items": [], + "dict_entries": [] + } + ], + "a_dict": [ + { + "name": "a_dict", + "type_name": "", + "op_sym": "=", + "value": "{\n **_part1\n **_part2\n}", + "list_items": [], + "dict_entries": [ + { + "key": "", + "value": { + "name": "", + "type_name": "", + "op_sym": ":", + "value": "_part1", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "", + "value": { + "name": "", + "type_name": "", + "op_sym": ":", + "value": "_part2", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "array1": [ + { + "name": "array1", + "type_name": "", + "op_sym": "=", + "value": "[\n 1\n 2\n 3\n]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "1", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "2", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "3", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + ], + "b1": [ + { + "name": "b1", + "type_name": "", + "op_sym": "=", + "value": "True", + "list_items": [], + "dict_entries": [] + } + ], + "b2": [ + { + "name": "b2", + "type_name": "", + "op_sym": "=", + "value": "False", + "list_items": [], + "dict_entries": [] + } + ], + "c": [ + { + "name": "c", + "type_name": "C", + "op_sym": "=", + "value": "C {\n a: {name: \"Hello\"}\n a: {ids: [7, 8, 9]}\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{\n name: \"Hello\"\n}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": ":", + "value": "\"Hello\"", + "list_items": [], + "dict_entries": [] + } + } + ] + } + }, + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{\n ids: [7, 8, 9]\n}", + "list_items": [], + "dict_entries": [ + { + "key": "ids", + "value": { + "name": "ids", + "type_name": "", + "op_sym": ":", + "value": "[\n 7\n 8\n 9\n]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "7", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "8", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "9", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + } + ] + } + } + ] + } + ], + "dict1": [ + { + "name": "dict1", + "type_name": "", + "op_sym": "=", + "value": "{\n \"a\": 1\n \"b\": 2\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "1", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "b", + "value": { + "name": "b", + "type_name": "", + "op_sym": ":", + "value": "2", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "dict2": [ + { + "name": "dict2", + "type_name": "", + "op_sym": "=", + "value": "{\n \"a\": 1\n \"b\": {\n \"c\": 2\n \"d\": 3\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "1", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "b", + "value": { + "name": "b", + "type_name": "", + "op_sym": ":", + "value": "{\n \"c\": 2\n \"d\": 3\n}", + "list_items": [], + "dict_entries": [ + { + "key": "c", + "value": { + "name": "c", + "type_name": "", + "op_sym": ":", + "value": "2", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "d", + "value": { + "name": "d", + "type_name": "", + "op_sym": ":", + "value": "3", + "list_items": [], + "dict_entries": [] + } + } + ] + } + } + ] + } + ], + "job": [ + { + "name": "job", + "type_name": "Job", + "op_sym": "=", + "value": "Job {\n name = \"{}-{}\".format(\"app\", \"test\").lower()\n}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": "=", + "value": "\"{}-{}\".format(\"app\", \"test\").lower()", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "s1": [ + { + "name": "s1", + "type_name": "", + "op_sym": "=", + "value": "\"Hello\"", + "list_items": [], + "dict_entries": [] + } + ], + "select": [ + { + "name": "select", + "type_name": "a.b.c", + "op_sym": "=", + "value": "a.b.c {\n a: 1\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "1", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "sha": [ + { + "name": "sha", + "type_name": "A", + "op_sym": "=", + "value": "A {\n name: \"Hello\"\n ids: [1, 2, 3]\n data: {\n \"a\": {\n \"b\": {\n \"c\": 2\n }\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": ":", + "value": "\"Hello\"", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "ids", + "value": { + "name": "ids", + "type_name": "", + "op_sym": ":", + "value": "[\n 1\n 2\n 3\n]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "1", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "2", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "3", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + }, + { + "key": "data", + "value": { + "name": "data", + "type_name": "", + "op_sym": ":", + "value": "{\n \"a\": {\n \"b\": {\n \"c\": 2\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{\n \"b\": {\n \"c\": 2\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "b", + "value": { + "name": "b", + "type_name": "", + "op_sym": ":", + "value": "{\n \"c\": 2\n}", + "list_items": [], + "dict_entries": [ + { + "key": "c", + "value": { + "name": "c", + "type_name": "", + "op_sym": ":", + "value": "2", + "list_items": [], + "dict_entries": [] + } + } + ] + } + } + ] + } + } + ] + } + } + ] + } + ], + "shb": [ + { + "name": "shb", + "type_name": "B", + "op_sym": "=", + "value": "B {\n a: {\n name: \"HelloB\"\n ids: [4, 5, 6]\n data: {\n \"d\": {\n \"e\": {\n \"f\": 3\n }\n }\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{\n name: \"HelloB\"\n ids: [4, 5, 6]\n data: {\n \"d\": {\n \"e\": {\n \"f\": 3\n }\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": ":", + "value": "\"HelloB\"", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "ids", + "value": { + "name": "ids", + "type_name": "", + "op_sym": ":", + "value": "[\n 4\n 5\n 6\n]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "4", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "5", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "6", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + }, + { + "key": "data", + "value": { + "name": "data", + "type_name": "", + "op_sym": ":", + "value": "{\n \"d\": {\n \"e\": {\n \"f\": 3\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "d", + "value": { + "name": "d", + "type_name": "", + "op_sym": ":", + "value": "{\n \"e\": {\n \"f\": 3\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "e", + "value": { + "name": "e", + "type_name": "", + "op_sym": ":", + "value": "{\n \"f\": 3\n}", + "list_items": [], + "dict_entries": [ + { + "key": "f", + "value": { + "name": "f", + "type_name": "", + "op_sym": ":", + "value": "3", + "list_items": [], + "dict_entries": [] + } + } + ] + } + } + ] + } + } + ] + } + } + ] + } + } + ] + } + ], + "uconfa": [ + { + "name": "uconfa", + "type_name": "UnificationConf", + "op_sym": ":", + "value": "UnificationConf {\n name = \"b\"\n}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": "=", + "value": "\"b\"", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "union_list": [ + { + "name": "union_list", + "type_name": "", + "op_sym": "=", + "value": "[\n *_list0\n *_list1\n]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "*_list0", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "*_list1", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + ] +} diff --git a/kclvm/query/src/snapshots/kclvm_query__tests__list_all_variables-8.snap b/kclvm/query/src/snapshots/kclvm_query__tests__list_all_variables-8.snap new file mode 100644 index 000000000..05312712c --- /dev/null +++ b/kclvm/query/src/snapshots/kclvm_query__tests__list_all_variables-8.snap @@ -0,0 +1,734 @@ +--- +source: query/src/tests.rs +expression: got_json +--- +{ + "_list0": [ + { + "name": "_list0", + "type_name": "", + "op_sym": "=", + "value": "[\n 1\n 2\n 3\n]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "1", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "2", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "3", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + ], + "_list1": [ + { + "name": "_list1", + "type_name": "", + "op_sym": "=", + "value": "[\n 4\n 5\n 6\n]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "4", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "5", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "6", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + ], + "_part1": [ + { + "name": "_part1", + "type_name": "", + "op_sym": "=", + "value": "{\n a = \"b\"\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": "=", + "value": "\"b\"", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "_part2": [ + { + "name": "_part2", + "type_name": "", + "op_sym": "=", + "value": "{\n c = \"d\"\n}", + "list_items": [], + "dict_entries": [ + { + "key": "c", + "value": { + "name": "c", + "type_name": "", + "op_sym": "=", + "value": "\"d\"", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "a": [ + { + "name": "a", + "type_name": "", + "op_sym": "=", + "value": "1", + "list_items": [], + "dict_entries": [] + } + ], + "a1": [ + { + "name": "a1", + "type_name": "", + "op_sym": "=", + "value": "2", + "list_items": [], + "dict_entries": [] + } + ], + "a3": [ + { + "name": "a3", + "type_name": "", + "op_sym": "=", + "value": "3m", + "list_items": [], + "dict_entries": [] + } + ], + "a_dict": [ + { + "name": "a_dict", + "type_name": "", + "op_sym": "=", + "value": "{\n **_part1\n **_part2\n}", + "list_items": [], + "dict_entries": [ + { + "key": "", + "value": { + "name": "", + "type_name": "", + "op_sym": ":", + "value": "_part1", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "", + "value": { + "name": "", + "type_name": "", + "op_sym": ":", + "value": "_part2", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "array1": [ + { + "name": "array1", + "type_name": "", + "op_sym": "=", + "value": "[\n 1\n 2\n 3\n]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "1", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "2", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "3", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + ], + "b1": [ + { + "name": "b1", + "type_name": "", + "op_sym": "=", + "value": "True", + "list_items": [], + "dict_entries": [] + } + ], + "b2": [ + { + "name": "b2", + "type_name": "", + "op_sym": "=", + "value": "False", + "list_items": [], + "dict_entries": [] + } + ], + "c": [ + { + "name": "c", + "type_name": "C", + "op_sym": "=", + "value": "C {\n a: {name: \"Hello\"}\n a: {ids: [7, 8, 9]}\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{\n name: \"Hello\"\n}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": ":", + "value": "\"Hello\"", + "list_items": [], + "dict_entries": [] + } + } + ] + } + }, + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{\n ids: [7, 8, 9]\n}", + "list_items": [], + "dict_entries": [ + { + "key": "ids", + "value": { + "name": "ids", + "type_name": "", + "op_sym": ":", + "value": "[\n 7\n 8\n 9\n]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "7", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "8", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "9", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + } + ] + } + } + ] + } + ], + "dict1": [ + { + "name": "dict1", + "type_name": "", + "op_sym": "=", + "value": "{\n \"a\": 1\n \"b\": 2\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "1", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "b", + "value": { + "name": "b", + "type_name": "", + "op_sym": ":", + "value": "2", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "dict2": [ + { + "name": "dict2", + "type_name": "", + "op_sym": "=", + "value": "{\n \"a\": 1\n \"b\": {\n \"c\": 2\n \"d\": 3\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "1", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "b", + "value": { + "name": "b", + "type_name": "", + "op_sym": ":", + "value": "{\n \"c\": 2\n \"d\": 3\n}", + "list_items": [], + "dict_entries": [ + { + "key": "c", + "value": { + "name": "c", + "type_name": "", + "op_sym": ":", + "value": "2", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "d", + "value": { + "name": "d", + "type_name": "", + "op_sym": ":", + "value": "3", + "list_items": [], + "dict_entries": [] + } + } + ] + } + } + ] + } + ], + "job": [ + { + "name": "job", + "type_name": "Job", + "op_sym": "=", + "value": "Job {\n name = \"{}-{}\".format(\"app\", \"test\").lower()\n}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": "=", + "value": "\"{}-{}\".format(\"app\", \"test\").lower()", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "s1": [ + { + "name": "s1", + "type_name": "", + "op_sym": "=", + "value": "\"Hello\"", + "list_items": [], + "dict_entries": [] + } + ], + "select": [ + { + "name": "select", + "type_name": "a.b.c", + "op_sym": "=", + "value": "a.b.c {\n a: 1\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "1", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "sha": [ + { + "name": "sha", + "type_name": "A", + "op_sym": "=", + "value": "A {\n name: \"Hello\"\n ids: [1, 2, 3]\n data: {\n \"a\": {\n \"b\": {\n \"c\": 2\n }\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": ":", + "value": "\"Hello\"", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "ids", + "value": { + "name": "ids", + "type_name": "", + "op_sym": ":", + "value": "[\n 1\n 2\n 3\n]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "1", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "2", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "3", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + }, + { + "key": "data", + "value": { + "name": "data", + "type_name": "", + "op_sym": ":", + "value": "{\n \"a\": {\n \"b\": {\n \"c\": 2\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{\n \"b\": {\n \"c\": 2\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "b", + "value": { + "name": "b", + "type_name": "", + "op_sym": ":", + "value": "{\n \"c\": 2\n}", + "list_items": [], + "dict_entries": [ + { + "key": "c", + "value": { + "name": "c", + "type_name": "", + "op_sym": ":", + "value": "2", + "list_items": [], + "dict_entries": [] + } + } + ] + } + } + ] + } + } + ] + } + } + ] + } + ], + "shb": [ + { + "name": "shb", + "type_name": "B", + "op_sym": "=", + "value": "B {\n a: {\n name: \"HelloB\"\n ids: [4, 5, 6]\n data: {\n \"d\": {\n \"e\": {\n \"f\": 3\n }\n }\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{\n name: \"HelloB\"\n ids: [4, 5, 6]\n data: {\n \"d\": {\n \"e\": {\n \"f\": 3\n }\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": ":", + "value": "\"HelloB\"", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "ids", + "value": { + "name": "ids", + "type_name": "", + "op_sym": ":", + "value": "[\n 4\n 5\n 6\n]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "4", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "5", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "6", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + }, + { + "key": "data", + "value": { + "name": "data", + "type_name": "", + "op_sym": ":", + "value": "{\n \"d\": {\n \"e\": {\n \"f\": 3\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "d", + "value": { + "name": "d", + "type_name": "", + "op_sym": ":", + "value": "{\n \"e\": {\n \"f\": 3\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "e", + "value": { + "name": "e", + "type_name": "", + "op_sym": ":", + "value": "{\n \"f\": 3\n}", + "list_items": [], + "dict_entries": [ + { + "key": "f", + "value": { + "name": "f", + "type_name": "", + "op_sym": ":", + "value": "3", + "list_items": [], + "dict_entries": [] + } + } + ] + } + } + ] + } + } + ] + } + } + ] + } + } + ] + } + ], + "uconfa": [ + { + "name": "uconfa", + "type_name": "UnificationConf", + "op_sym": ":", + "value": "UnificationConf {\n name = \"b\"\n}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": "=", + "value": "\"b\"", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "union_list": [ + { + "name": "union_list", + "type_name": "", + "op_sym": "=", + "value": "[\n *_list0\n *_list1\n]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "*_list0", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "*_list1", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + ] +} diff --git a/kclvm/query/src/snapshots/kclvm_query__tests__list_all_variables-9.snap b/kclvm/query/src/snapshots/kclvm_query__tests__list_all_variables-9.snap new file mode 100644 index 000000000..05312712c --- /dev/null +++ b/kclvm/query/src/snapshots/kclvm_query__tests__list_all_variables-9.snap @@ -0,0 +1,734 @@ +--- +source: query/src/tests.rs +expression: got_json +--- +{ + "_list0": [ + { + "name": "_list0", + "type_name": "", + "op_sym": "=", + "value": "[\n 1\n 2\n 3\n]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "1", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "2", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "3", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + ], + "_list1": [ + { + "name": "_list1", + "type_name": "", + "op_sym": "=", + "value": "[\n 4\n 5\n 6\n]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "4", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "5", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "6", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + ], + "_part1": [ + { + "name": "_part1", + "type_name": "", + "op_sym": "=", + "value": "{\n a = \"b\"\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": "=", + "value": "\"b\"", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "_part2": [ + { + "name": "_part2", + "type_name": "", + "op_sym": "=", + "value": "{\n c = \"d\"\n}", + "list_items": [], + "dict_entries": [ + { + "key": "c", + "value": { + "name": "c", + "type_name": "", + "op_sym": "=", + "value": "\"d\"", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "a": [ + { + "name": "a", + "type_name": "", + "op_sym": "=", + "value": "1", + "list_items": [], + "dict_entries": [] + } + ], + "a1": [ + { + "name": "a1", + "type_name": "", + "op_sym": "=", + "value": "2", + "list_items": [], + "dict_entries": [] + } + ], + "a3": [ + { + "name": "a3", + "type_name": "", + "op_sym": "=", + "value": "3m", + "list_items": [], + "dict_entries": [] + } + ], + "a_dict": [ + { + "name": "a_dict", + "type_name": "", + "op_sym": "=", + "value": "{\n **_part1\n **_part2\n}", + "list_items": [], + "dict_entries": [ + { + "key": "", + "value": { + "name": "", + "type_name": "", + "op_sym": ":", + "value": "_part1", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "", + "value": { + "name": "", + "type_name": "", + "op_sym": ":", + "value": "_part2", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "array1": [ + { + "name": "array1", + "type_name": "", + "op_sym": "=", + "value": "[\n 1\n 2\n 3\n]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "1", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "2", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "3", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + ], + "b1": [ + { + "name": "b1", + "type_name": "", + "op_sym": "=", + "value": "True", + "list_items": [], + "dict_entries": [] + } + ], + "b2": [ + { + "name": "b2", + "type_name": "", + "op_sym": "=", + "value": "False", + "list_items": [], + "dict_entries": [] + } + ], + "c": [ + { + "name": "c", + "type_name": "C", + "op_sym": "=", + "value": "C {\n a: {name: \"Hello\"}\n a: {ids: [7, 8, 9]}\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{\n name: \"Hello\"\n}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": ":", + "value": "\"Hello\"", + "list_items": [], + "dict_entries": [] + } + } + ] + } + }, + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{\n ids: [7, 8, 9]\n}", + "list_items": [], + "dict_entries": [ + { + "key": "ids", + "value": { + "name": "ids", + "type_name": "", + "op_sym": ":", + "value": "[\n 7\n 8\n 9\n]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "7", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "8", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "9", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + } + ] + } + } + ] + } + ], + "dict1": [ + { + "name": "dict1", + "type_name": "", + "op_sym": "=", + "value": "{\n \"a\": 1\n \"b\": 2\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "1", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "b", + "value": { + "name": "b", + "type_name": "", + "op_sym": ":", + "value": "2", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "dict2": [ + { + "name": "dict2", + "type_name": "", + "op_sym": "=", + "value": "{\n \"a\": 1\n \"b\": {\n \"c\": 2\n \"d\": 3\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "1", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "b", + "value": { + "name": "b", + "type_name": "", + "op_sym": ":", + "value": "{\n \"c\": 2\n \"d\": 3\n}", + "list_items": [], + "dict_entries": [ + { + "key": "c", + "value": { + "name": "c", + "type_name": "", + "op_sym": ":", + "value": "2", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "d", + "value": { + "name": "d", + "type_name": "", + "op_sym": ":", + "value": "3", + "list_items": [], + "dict_entries": [] + } + } + ] + } + } + ] + } + ], + "job": [ + { + "name": "job", + "type_name": "Job", + "op_sym": "=", + "value": "Job {\n name = \"{}-{}\".format(\"app\", \"test\").lower()\n}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": "=", + "value": "\"{}-{}\".format(\"app\", \"test\").lower()", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "s1": [ + { + "name": "s1", + "type_name": "", + "op_sym": "=", + "value": "\"Hello\"", + "list_items": [], + "dict_entries": [] + } + ], + "select": [ + { + "name": "select", + "type_name": "a.b.c", + "op_sym": "=", + "value": "a.b.c {\n a: 1\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "1", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "sha": [ + { + "name": "sha", + "type_name": "A", + "op_sym": "=", + "value": "A {\n name: \"Hello\"\n ids: [1, 2, 3]\n data: {\n \"a\": {\n \"b\": {\n \"c\": 2\n }\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": ":", + "value": "\"Hello\"", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "ids", + "value": { + "name": "ids", + "type_name": "", + "op_sym": ":", + "value": "[\n 1\n 2\n 3\n]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "1", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "2", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "3", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + }, + { + "key": "data", + "value": { + "name": "data", + "type_name": "", + "op_sym": ":", + "value": "{\n \"a\": {\n \"b\": {\n \"c\": 2\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{\n \"b\": {\n \"c\": 2\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "b", + "value": { + "name": "b", + "type_name": "", + "op_sym": ":", + "value": "{\n \"c\": 2\n}", + "list_items": [], + "dict_entries": [ + { + "key": "c", + "value": { + "name": "c", + "type_name": "", + "op_sym": ":", + "value": "2", + "list_items": [], + "dict_entries": [] + } + } + ] + } + } + ] + } + } + ] + } + } + ] + } + ], + "shb": [ + { + "name": "shb", + "type_name": "B", + "op_sym": "=", + "value": "B {\n a: {\n name: \"HelloB\"\n ids: [4, 5, 6]\n data: {\n \"d\": {\n \"e\": {\n \"f\": 3\n }\n }\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{\n name: \"HelloB\"\n ids: [4, 5, 6]\n data: {\n \"d\": {\n \"e\": {\n \"f\": 3\n }\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": ":", + "value": "\"HelloB\"", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "ids", + "value": { + "name": "ids", + "type_name": "", + "op_sym": ":", + "value": "[\n 4\n 5\n 6\n]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "4", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "5", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "6", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + }, + { + "key": "data", + "value": { + "name": "data", + "type_name": "", + "op_sym": ":", + "value": "{\n \"d\": {\n \"e\": {\n \"f\": 3\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "d", + "value": { + "name": "d", + "type_name": "", + "op_sym": ":", + "value": "{\n \"e\": {\n \"f\": 3\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "e", + "value": { + "name": "e", + "type_name": "", + "op_sym": ":", + "value": "{\n \"f\": 3\n}", + "list_items": [], + "dict_entries": [ + { + "key": "f", + "value": { + "name": "f", + "type_name": "", + "op_sym": ":", + "value": "3", + "list_items": [], + "dict_entries": [] + } + } + ] + } + } + ] + } + } + ] + } + } + ] + } + } + ] + } + ], + "uconfa": [ + { + "name": "uconfa", + "type_name": "UnificationConf", + "op_sym": ":", + "value": "UnificationConf {\n name = \"b\"\n}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": "=", + "value": "\"b\"", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "union_list": [ + { + "name": "union_list", + "type_name": "", + "op_sym": "=", + "value": "[\n *_list0\n *_list1\n]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "*_list0", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "*_list1", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + ] +} diff --git a/kclvm/query/src/snapshots/kclvm_query__tests__list_all_variables.snap b/kclvm/query/src/snapshots/kclvm_query__tests__list_all_variables.snap new file mode 100644 index 000000000..05312712c --- /dev/null +++ b/kclvm/query/src/snapshots/kclvm_query__tests__list_all_variables.snap @@ -0,0 +1,734 @@ +--- +source: query/src/tests.rs +expression: got_json +--- +{ + "_list0": [ + { + "name": "_list0", + "type_name": "", + "op_sym": "=", + "value": "[\n 1\n 2\n 3\n]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "1", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "2", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "3", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + ], + "_list1": [ + { + "name": "_list1", + "type_name": "", + "op_sym": "=", + "value": "[\n 4\n 5\n 6\n]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "4", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "5", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "6", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + ], + "_part1": [ + { + "name": "_part1", + "type_name": "", + "op_sym": "=", + "value": "{\n a = \"b\"\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": "=", + "value": "\"b\"", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "_part2": [ + { + "name": "_part2", + "type_name": "", + "op_sym": "=", + "value": "{\n c = \"d\"\n}", + "list_items": [], + "dict_entries": [ + { + "key": "c", + "value": { + "name": "c", + "type_name": "", + "op_sym": "=", + "value": "\"d\"", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "a": [ + { + "name": "a", + "type_name": "", + "op_sym": "=", + "value": "1", + "list_items": [], + "dict_entries": [] + } + ], + "a1": [ + { + "name": "a1", + "type_name": "", + "op_sym": "=", + "value": "2", + "list_items": [], + "dict_entries": [] + } + ], + "a3": [ + { + "name": "a3", + "type_name": "", + "op_sym": "=", + "value": "3m", + "list_items": [], + "dict_entries": [] + } + ], + "a_dict": [ + { + "name": "a_dict", + "type_name": "", + "op_sym": "=", + "value": "{\n **_part1\n **_part2\n}", + "list_items": [], + "dict_entries": [ + { + "key": "", + "value": { + "name": "", + "type_name": "", + "op_sym": ":", + "value": "_part1", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "", + "value": { + "name": "", + "type_name": "", + "op_sym": ":", + "value": "_part2", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "array1": [ + { + "name": "array1", + "type_name": "", + "op_sym": "=", + "value": "[\n 1\n 2\n 3\n]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "1", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "2", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "3", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + ], + "b1": [ + { + "name": "b1", + "type_name": "", + "op_sym": "=", + "value": "True", + "list_items": [], + "dict_entries": [] + } + ], + "b2": [ + { + "name": "b2", + "type_name": "", + "op_sym": "=", + "value": "False", + "list_items": [], + "dict_entries": [] + } + ], + "c": [ + { + "name": "c", + "type_name": "C", + "op_sym": "=", + "value": "C {\n a: {name: \"Hello\"}\n a: {ids: [7, 8, 9]}\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{\n name: \"Hello\"\n}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": ":", + "value": "\"Hello\"", + "list_items": [], + "dict_entries": [] + } + } + ] + } + }, + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{\n ids: [7, 8, 9]\n}", + "list_items": [], + "dict_entries": [ + { + "key": "ids", + "value": { + "name": "ids", + "type_name": "", + "op_sym": ":", + "value": "[\n 7\n 8\n 9\n]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "7", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "8", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "9", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + } + ] + } + } + ] + } + ], + "dict1": [ + { + "name": "dict1", + "type_name": "", + "op_sym": "=", + "value": "{\n \"a\": 1\n \"b\": 2\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "1", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "b", + "value": { + "name": "b", + "type_name": "", + "op_sym": ":", + "value": "2", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "dict2": [ + { + "name": "dict2", + "type_name": "", + "op_sym": "=", + "value": "{\n \"a\": 1\n \"b\": {\n \"c\": 2\n \"d\": 3\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "1", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "b", + "value": { + "name": "b", + "type_name": "", + "op_sym": ":", + "value": "{\n \"c\": 2\n \"d\": 3\n}", + "list_items": [], + "dict_entries": [ + { + "key": "c", + "value": { + "name": "c", + "type_name": "", + "op_sym": ":", + "value": "2", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "d", + "value": { + "name": "d", + "type_name": "", + "op_sym": ":", + "value": "3", + "list_items": [], + "dict_entries": [] + } + } + ] + } + } + ] + } + ], + "job": [ + { + "name": "job", + "type_name": "Job", + "op_sym": "=", + "value": "Job {\n name = \"{}-{}\".format(\"app\", \"test\").lower()\n}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": "=", + "value": "\"{}-{}\".format(\"app\", \"test\").lower()", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "s1": [ + { + "name": "s1", + "type_name": "", + "op_sym": "=", + "value": "\"Hello\"", + "list_items": [], + "dict_entries": [] + } + ], + "select": [ + { + "name": "select", + "type_name": "a.b.c", + "op_sym": "=", + "value": "a.b.c {\n a: 1\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "1", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "sha": [ + { + "name": "sha", + "type_name": "A", + "op_sym": "=", + "value": "A {\n name: \"Hello\"\n ids: [1, 2, 3]\n data: {\n \"a\": {\n \"b\": {\n \"c\": 2\n }\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": ":", + "value": "\"Hello\"", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "ids", + "value": { + "name": "ids", + "type_name": "", + "op_sym": ":", + "value": "[\n 1\n 2\n 3\n]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "1", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "2", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "3", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + }, + { + "key": "data", + "value": { + "name": "data", + "type_name": "", + "op_sym": ":", + "value": "{\n \"a\": {\n \"b\": {\n \"c\": 2\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{\n \"b\": {\n \"c\": 2\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "b", + "value": { + "name": "b", + "type_name": "", + "op_sym": ":", + "value": "{\n \"c\": 2\n}", + "list_items": [], + "dict_entries": [ + { + "key": "c", + "value": { + "name": "c", + "type_name": "", + "op_sym": ":", + "value": "2", + "list_items": [], + "dict_entries": [] + } + } + ] + } + } + ] + } + } + ] + } + } + ] + } + ], + "shb": [ + { + "name": "shb", + "type_name": "B", + "op_sym": "=", + "value": "B {\n a: {\n name: \"HelloB\"\n ids: [4, 5, 6]\n data: {\n \"d\": {\n \"e\": {\n \"f\": 3\n }\n }\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{\n name: \"HelloB\"\n ids: [4, 5, 6]\n data: {\n \"d\": {\n \"e\": {\n \"f\": 3\n }\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": ":", + "value": "\"HelloB\"", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "ids", + "value": { + "name": "ids", + "type_name": "", + "op_sym": ":", + "value": "[\n 4\n 5\n 6\n]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "4", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "5", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "6", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + }, + { + "key": "data", + "value": { + "name": "data", + "type_name": "", + "op_sym": ":", + "value": "{\n \"d\": {\n \"e\": {\n \"f\": 3\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "d", + "value": { + "name": "d", + "type_name": "", + "op_sym": ":", + "value": "{\n \"e\": {\n \"f\": 3\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "e", + "value": { + "name": "e", + "type_name": "", + "op_sym": ":", + "value": "{\n \"f\": 3\n}", + "list_items": [], + "dict_entries": [ + { + "key": "f", + "value": { + "name": "f", + "type_name": "", + "op_sym": ":", + "value": "3", + "list_items": [], + "dict_entries": [] + } + } + ] + } + } + ] + } + } + ] + } + } + ] + } + } + ] + } + ], + "uconfa": [ + { + "name": "uconfa", + "type_name": "UnificationConf", + "op_sym": ":", + "value": "UnificationConf {\n name = \"b\"\n}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": "=", + "value": "\"b\"", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "union_list": [ + { + "name": "union_list", + "type_name": "", + "op_sym": "=", + "value": "[\n *_list0\n *_list1\n]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "*_list0", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "*_list1", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + ] +} diff --git a/kclvm/query/src/snapshots/kclvm_query__tests__list_variables-10.snap b/kclvm/query/src/snapshots/kclvm_query__tests__list_variables-10.snap new file mode 100644 index 000000000..6ff706a78 --- /dev/null +++ b/kclvm/query/src/snapshots/kclvm_query__tests__list_variables-10.snap @@ -0,0 +1,16 @@ +--- +source: query/src/tests.rs +expression: got_json +--- +{ + "dict1.b": [ + { + "name": "b", + "type_name": "", + "op_sym": ":", + "value": "2", + "list_items": [], + "dict_entries": [] + } + ] +} diff --git a/kclvm/query/src/snapshots/kclvm_query__tests__list_variables-11.snap b/kclvm/query/src/snapshots/kclvm_query__tests__list_variables-11.snap new file mode 100644 index 000000000..048543d0d --- /dev/null +++ b/kclvm/query/src/snapshots/kclvm_query__tests__list_variables-11.snap @@ -0,0 +1,62 @@ +--- +source: query/src/tests.rs +expression: got_json +--- +{ + "dict2": [ + { + "name": "dict2", + "type_name": "", + "op_sym": "=", + "value": "{\n \"a\": 1\n \"b\": {\n \"c\": 2\n \"d\": 3\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "1", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "b", + "value": { + "name": "b", + "type_name": "", + "op_sym": ":", + "value": "{\n \"c\": 2\n \"d\": 3\n}", + "list_items": [], + "dict_entries": [ + { + "key": "c", + "value": { + "name": "c", + "type_name": "", + "op_sym": ":", + "value": "2", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "d", + "value": { + "name": "d", + "type_name": "", + "op_sym": ":", + "value": "3", + "list_items": [], + "dict_entries": [] + } + } + ] + } + } + ] + } + ] +} diff --git a/kclvm/query/src/snapshots/kclvm_query__tests__list_variables-12.snap b/kclvm/query/src/snapshots/kclvm_query__tests__list_variables-12.snap new file mode 100644 index 000000000..463f534c6 --- /dev/null +++ b/kclvm/query/src/snapshots/kclvm_query__tests__list_variables-12.snap @@ -0,0 +1,16 @@ +--- +source: query/src/tests.rs +expression: got_json +--- +{ + "dict2.a": [ + { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "1", + "list_items": [], + "dict_entries": [] + } + ] +} diff --git a/kclvm/query/src/snapshots/kclvm_query__tests__list_variables-13.snap b/kclvm/query/src/snapshots/kclvm_query__tests__list_variables-13.snap new file mode 100644 index 000000000..c805efc89 --- /dev/null +++ b/kclvm/query/src/snapshots/kclvm_query__tests__list_variables-13.snap @@ -0,0 +1,39 @@ +--- +source: query/src/tests.rs +expression: got_json +--- +{ + "dict2.b": [ + { + "name": "b", + "type_name": "", + "op_sym": ":", + "value": "{\n \"c\": 2\n \"d\": 3\n}", + "list_items": [], + "dict_entries": [ + { + "key": "c", + "value": { + "name": "c", + "type_name": "", + "op_sym": ":", + "value": "2", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "d", + "value": { + "name": "d", + "type_name": "", + "op_sym": ":", + "value": "3", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ] +} diff --git a/kclvm/query/src/snapshots/kclvm_query__tests__list_variables-14.snap b/kclvm/query/src/snapshots/kclvm_query__tests__list_variables-14.snap new file mode 100644 index 000000000..4e097554a --- /dev/null +++ b/kclvm/query/src/snapshots/kclvm_query__tests__list_variables-14.snap @@ -0,0 +1,16 @@ +--- +source: query/src/tests.rs +expression: got_json +--- +{ + "dict2.b.c": [ + { + "name": "c", + "type_name": "", + "op_sym": ":", + "value": "2", + "list_items": [], + "dict_entries": [] + } + ] +} diff --git a/kclvm/query/src/snapshots/kclvm_query__tests__list_variables-15.snap b/kclvm/query/src/snapshots/kclvm_query__tests__list_variables-15.snap new file mode 100644 index 000000000..8e9e5cc3f --- /dev/null +++ b/kclvm/query/src/snapshots/kclvm_query__tests__list_variables-15.snap @@ -0,0 +1,16 @@ +--- +source: query/src/tests.rs +expression: got_json +--- +{ + "dict2.b.d": [ + { + "name": "d", + "type_name": "", + "op_sym": ":", + "value": "3", + "list_items": [], + "dict_entries": [] + } + ] +} diff --git a/kclvm/query/src/snapshots/kclvm_query__tests__list_variables-16.snap b/kclvm/query/src/snapshots/kclvm_query__tests__list_variables-16.snap new file mode 100644 index 000000000..3619bf40f --- /dev/null +++ b/kclvm/query/src/snapshots/kclvm_query__tests__list_variables-16.snap @@ -0,0 +1,111 @@ +--- +source: query/src/tests.rs +expression: got_json +--- +{ + "sha": [ + { + "name": "sha", + "type_name": "A", + "op_sym": "=", + "value": "A {\n name: \"Hello\"\n ids: [1, 2, 3]\n data: {\n \"a\": {\n \"b\": {\n \"c\": 2\n }\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": ":", + "value": "\"Hello\"", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "ids", + "value": { + "name": "ids", + "type_name": "", + "op_sym": ":", + "value": "[\n 1\n 2\n 3\n]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "1", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "2", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "3", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + }, + { + "key": "data", + "value": { + "name": "data", + "type_name": "", + "op_sym": ":", + "value": "{\n \"a\": {\n \"b\": {\n \"c\": 2\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{\n \"b\": {\n \"c\": 2\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "b", + "value": { + "name": "b", + "type_name": "", + "op_sym": ":", + "value": "{\n \"c\": 2\n}", + "list_items": [], + "dict_entries": [ + { + "key": "c", + "value": { + "name": "c", + "type_name": "", + "op_sym": ":", + "value": "2", + "list_items": [], + "dict_entries": [] + } + } + ] + } + } + ] + } + } + ] + } + } + ] + } + ] +} diff --git a/kclvm/query/src/snapshots/kclvm_query__tests__list_variables-17.snap b/kclvm/query/src/snapshots/kclvm_query__tests__list_variables-17.snap new file mode 100644 index 000000000..cdd2fea38 --- /dev/null +++ b/kclvm/query/src/snapshots/kclvm_query__tests__list_variables-17.snap @@ -0,0 +1,16 @@ +--- +source: query/src/tests.rs +expression: got_json +--- +{ + "sha.name": [ + { + "name": "name", + "type_name": "", + "op_sym": ":", + "value": "\"Hello\"", + "list_items": [], + "dict_entries": [] + } + ] +} diff --git a/kclvm/query/src/snapshots/kclvm_query__tests__list_variables-18.snap b/kclvm/query/src/snapshots/kclvm_query__tests__list_variables-18.snap new file mode 100644 index 000000000..e52d3b673 --- /dev/null +++ b/kclvm/query/src/snapshots/kclvm_query__tests__list_variables-18.snap @@ -0,0 +1,41 @@ +--- +source: query/src/tests.rs +expression: got_json +--- +{ + "sha.ids": [ + { + "name": "ids", + "type_name": "", + "op_sym": ":", + "value": "[\n 1\n 2\n 3\n]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "1", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "2", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "3", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + ] +} diff --git a/kclvm/query/src/snapshots/kclvm_query__tests__list_variables-19.snap b/kclvm/query/src/snapshots/kclvm_query__tests__list_variables-19.snap new file mode 100644 index 000000000..80f490cc6 --- /dev/null +++ b/kclvm/query/src/snapshots/kclvm_query__tests__list_variables-19.snap @@ -0,0 +1,52 @@ +--- +source: query/src/tests.rs +expression: got_json +--- +{ + "sha.data": [ + { + "name": "data", + "type_name": "", + "op_sym": ":", + "value": "{\n \"a\": {\n \"b\": {\n \"c\": 2\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{\n \"b\": {\n \"c\": 2\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "b", + "value": { + "name": "b", + "type_name": "", + "op_sym": ":", + "value": "{\n \"c\": 2\n}", + "list_items": [], + "dict_entries": [ + { + "key": "c", + "value": { + "name": "c", + "type_name": "", + "op_sym": ":", + "value": "2", + "list_items": [], + "dict_entries": [] + } + } + ] + } + } + ] + } + } + ] + } + ] +} diff --git a/kclvm/query/src/snapshots/kclvm_query__tests__list_variables-2.snap b/kclvm/query/src/snapshots/kclvm_query__tests__list_variables-2.snap new file mode 100644 index 000000000..fd89b8a39 --- /dev/null +++ b/kclvm/query/src/snapshots/kclvm_query__tests__list_variables-2.snap @@ -0,0 +1,16 @@ +--- +source: query/src/tests.rs +expression: got_json +--- +{ + "a1": [ + { + "name": "a1", + "type_name": "", + "op_sym": "=", + "value": "2", + "list_items": [], + "dict_entries": [] + } + ] +} diff --git a/kclvm/query/src/snapshots/kclvm_query__tests__list_variables-20.snap b/kclvm/query/src/snapshots/kclvm_query__tests__list_variables-20.snap new file mode 100644 index 000000000..738ea1425 --- /dev/null +++ b/kclvm/query/src/snapshots/kclvm_query__tests__list_variables-20.snap @@ -0,0 +1,40 @@ +--- +source: query/src/tests.rs +expression: got_json +--- +{ + "sha.data.a": [ + { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{\n \"b\": {\n \"c\": 2\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "b", + "value": { + "name": "b", + "type_name": "", + "op_sym": ":", + "value": "{\n \"c\": 2\n}", + "list_items": [], + "dict_entries": [ + { + "key": "c", + "value": { + "name": "c", + "type_name": "", + "op_sym": ":", + "value": "2", + "list_items": [], + "dict_entries": [] + } + } + ] + } + } + ] + } + ] +} diff --git a/kclvm/query/src/snapshots/kclvm_query__tests__list_variables-21.snap b/kclvm/query/src/snapshots/kclvm_query__tests__list_variables-21.snap new file mode 100644 index 000000000..46979358e --- /dev/null +++ b/kclvm/query/src/snapshots/kclvm_query__tests__list_variables-21.snap @@ -0,0 +1,28 @@ +--- +source: query/src/tests.rs +expression: got_json +--- +{ + "sha.data.a.b": [ + { + "name": "b", + "type_name": "", + "op_sym": ":", + "value": "{\n \"c\": 2\n}", + "list_items": [], + "dict_entries": [ + { + "key": "c", + "value": { + "name": "c", + "type_name": "", + "op_sym": ":", + "value": "2", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ] +} diff --git a/kclvm/query/src/snapshots/kclvm_query__tests__list_variables-22.snap b/kclvm/query/src/snapshots/kclvm_query__tests__list_variables-22.snap new file mode 100644 index 000000000..18d4fa819 --- /dev/null +++ b/kclvm/query/src/snapshots/kclvm_query__tests__list_variables-22.snap @@ -0,0 +1,16 @@ +--- +source: query/src/tests.rs +expression: got_json +--- +{ + "sha.data.a.b.c": [ + { + "name": "c", + "type_name": "", + "op_sym": ":", + "value": "2", + "list_items": [], + "dict_entries": [] + } + ] +} diff --git a/kclvm/query/src/snapshots/kclvm_query__tests__list_variables-23.snap b/kclvm/query/src/snapshots/kclvm_query__tests__list_variables-23.snap new file mode 100644 index 000000000..7be559c7c --- /dev/null +++ b/kclvm/query/src/snapshots/kclvm_query__tests__list_variables-23.snap @@ -0,0 +1,123 @@ +--- +source: query/src/tests.rs +expression: got_json +--- +{ + "shb": [ + { + "name": "shb", + "type_name": "B", + "op_sym": "=", + "value": "B {\n a: {\n name: \"HelloB\"\n ids: [4, 5, 6]\n data: {\n \"d\": {\n \"e\": {\n \"f\": 3\n }\n }\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{\n name: \"HelloB\"\n ids: [4, 5, 6]\n data: {\n \"d\": {\n \"e\": {\n \"f\": 3\n }\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": ":", + "value": "\"HelloB\"", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "ids", + "value": { + "name": "ids", + "type_name": "", + "op_sym": ":", + "value": "[\n 4\n 5\n 6\n]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "4", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "5", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "6", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + }, + { + "key": "data", + "value": { + "name": "data", + "type_name": "", + "op_sym": ":", + "value": "{\n \"d\": {\n \"e\": {\n \"f\": 3\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "d", + "value": { + "name": "d", + "type_name": "", + "op_sym": ":", + "value": "{\n \"e\": {\n \"f\": 3\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "e", + "value": { + "name": "e", + "type_name": "", + "op_sym": ":", + "value": "{\n \"f\": 3\n}", + "list_items": [], + "dict_entries": [ + { + "key": "f", + "value": { + "name": "f", + "type_name": "", + "op_sym": ":", + "value": "3", + "list_items": [], + "dict_entries": [] + } + } + ] + } + } + ] + } + } + ] + } + } + ] + } + } + ] + } + ] +} diff --git a/kclvm/query/src/snapshots/kclvm_query__tests__list_variables-24.snap b/kclvm/query/src/snapshots/kclvm_query__tests__list_variables-24.snap new file mode 100644 index 000000000..adc4b5bf6 --- /dev/null +++ b/kclvm/query/src/snapshots/kclvm_query__tests__list_variables-24.snap @@ -0,0 +1,111 @@ +--- +source: query/src/tests.rs +expression: got_json +--- +{ + "shb.a": [ + { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{\n name: \"HelloB\"\n ids: [4, 5, 6]\n data: {\n \"d\": {\n \"e\": {\n \"f\": 3\n }\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": ":", + "value": "\"HelloB\"", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "ids", + "value": { + "name": "ids", + "type_name": "", + "op_sym": ":", + "value": "[\n 4\n 5\n 6\n]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "4", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "5", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "6", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + }, + { + "key": "data", + "value": { + "name": "data", + "type_name": "", + "op_sym": ":", + "value": "{\n \"d\": {\n \"e\": {\n \"f\": 3\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "d", + "value": { + "name": "d", + "type_name": "", + "op_sym": ":", + "value": "{\n \"e\": {\n \"f\": 3\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "e", + "value": { + "name": "e", + "type_name": "", + "op_sym": ":", + "value": "{\n \"f\": 3\n}", + "list_items": [], + "dict_entries": [ + { + "key": "f", + "value": { + "name": "f", + "type_name": "", + "op_sym": ":", + "value": "3", + "list_items": [], + "dict_entries": [] + } + } + ] + } + } + ] + } + } + ] + } + } + ] + } + ] +} diff --git a/kclvm/query/src/snapshots/kclvm_query__tests__list_variables-25.snap b/kclvm/query/src/snapshots/kclvm_query__tests__list_variables-25.snap new file mode 100644 index 000000000..07d17738c --- /dev/null +++ b/kclvm/query/src/snapshots/kclvm_query__tests__list_variables-25.snap @@ -0,0 +1,16 @@ +--- +source: query/src/tests.rs +expression: got_json +--- +{ + "shb.a.name": [ + { + "name": "name", + "type_name": "", + "op_sym": ":", + "value": "\"HelloB\"", + "list_items": [], + "dict_entries": [] + } + ] +} diff --git a/kclvm/query/src/snapshots/kclvm_query__tests__list_variables-26.snap b/kclvm/query/src/snapshots/kclvm_query__tests__list_variables-26.snap new file mode 100644 index 000000000..e53fb1fa9 --- /dev/null +++ b/kclvm/query/src/snapshots/kclvm_query__tests__list_variables-26.snap @@ -0,0 +1,41 @@ +--- +source: query/src/tests.rs +expression: got_json +--- +{ + "shb.a.ids": [ + { + "name": "ids", + "type_name": "", + "op_sym": ":", + "value": "[\n 4\n 5\n 6\n]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "4", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "5", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "6", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + ] +} diff --git a/kclvm/query/src/snapshots/kclvm_query__tests__list_variables-27.snap b/kclvm/query/src/snapshots/kclvm_query__tests__list_variables-27.snap new file mode 100644 index 000000000..69664521c --- /dev/null +++ b/kclvm/query/src/snapshots/kclvm_query__tests__list_variables-27.snap @@ -0,0 +1,52 @@ +--- +source: query/src/tests.rs +expression: got_json +--- +{ + "shb.a.data": [ + { + "name": "data", + "type_name": "", + "op_sym": ":", + "value": "{\n \"d\": {\n \"e\": {\n \"f\": 3\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "d", + "value": { + "name": "d", + "type_name": "", + "op_sym": ":", + "value": "{\n \"e\": {\n \"f\": 3\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "e", + "value": { + "name": "e", + "type_name": "", + "op_sym": ":", + "value": "{\n \"f\": 3\n}", + "list_items": [], + "dict_entries": [ + { + "key": "f", + "value": { + "name": "f", + "type_name": "", + "op_sym": ":", + "value": "3", + "list_items": [], + "dict_entries": [] + } + } + ] + } + } + ] + } + } + ] + } + ] +} diff --git a/kclvm/query/src/snapshots/kclvm_query__tests__list_variables-28.snap b/kclvm/query/src/snapshots/kclvm_query__tests__list_variables-28.snap new file mode 100644 index 000000000..01349d3d6 --- /dev/null +++ b/kclvm/query/src/snapshots/kclvm_query__tests__list_variables-28.snap @@ -0,0 +1,40 @@ +--- +source: query/src/tests.rs +expression: got_json +--- +{ + "shb.a.data.d": [ + { + "name": "d", + "type_name": "", + "op_sym": ":", + "value": "{\n \"e\": {\n \"f\": 3\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "e", + "value": { + "name": "e", + "type_name": "", + "op_sym": ":", + "value": "{\n \"f\": 3\n}", + "list_items": [], + "dict_entries": [ + { + "key": "f", + "value": { + "name": "f", + "type_name": "", + "op_sym": ":", + "value": "3", + "list_items": [], + "dict_entries": [] + } + } + ] + } + } + ] + } + ] +} diff --git a/kclvm/query/src/snapshots/kclvm_query__tests__list_variables-29.snap b/kclvm/query/src/snapshots/kclvm_query__tests__list_variables-29.snap new file mode 100644 index 000000000..cdf811de6 --- /dev/null +++ b/kclvm/query/src/snapshots/kclvm_query__tests__list_variables-29.snap @@ -0,0 +1,28 @@ +--- +source: query/src/tests.rs +expression: got_json +--- +{ + "shb.a.data.d.e": [ + { + "name": "e", + "type_name": "", + "op_sym": ":", + "value": "{\n \"f\": 3\n}", + "list_items": [], + "dict_entries": [ + { + "key": "f", + "value": { + "name": "f", + "type_name": "", + "op_sym": ":", + "value": "3", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ] +} diff --git a/kclvm/query/src/snapshots/kclvm_query__tests__list_variables-3.snap b/kclvm/query/src/snapshots/kclvm_query__tests__list_variables-3.snap new file mode 100644 index 000000000..1ee7ad1bc --- /dev/null +++ b/kclvm/query/src/snapshots/kclvm_query__tests__list_variables-3.snap @@ -0,0 +1,16 @@ +--- +source: query/src/tests.rs +expression: got_json +--- +{ + "a3": [ + { + "name": "a3", + "type_name": "", + "op_sym": "=", + "value": "3m", + "list_items": [], + "dict_entries": [] + } + ] +} diff --git a/kclvm/query/src/snapshots/kclvm_query__tests__list_variables-30.snap b/kclvm/query/src/snapshots/kclvm_query__tests__list_variables-30.snap new file mode 100644 index 000000000..ef96f3dce --- /dev/null +++ b/kclvm/query/src/snapshots/kclvm_query__tests__list_variables-30.snap @@ -0,0 +1,16 @@ +--- +source: query/src/tests.rs +expression: got_json +--- +{ + "uconfa.name": [ + { + "name": "name", + "type_name": "", + "op_sym": "=", + "value": "\"b\"", + "list_items": [], + "dict_entries": [] + } + ] +} diff --git a/kclvm/query/src/snapshots/kclvm_query__tests__list_variables-31.snap b/kclvm/query/src/snapshots/kclvm_query__tests__list_variables-31.snap new file mode 100644 index 000000000..300f02879 --- /dev/null +++ b/kclvm/query/src/snapshots/kclvm_query__tests__list_variables-31.snap @@ -0,0 +1,73 @@ +--- +source: query/src/tests.rs +expression: got_json +--- +{ + "c.a": [ + { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{\n name: \"Hello\"\n}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": ":", + "value": "\"Hello\"", + "list_items": [], + "dict_entries": [] + } + } + ] + }, + { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{\n ids: [7, 8, 9]\n}", + "list_items": [], + "dict_entries": [ + { + "key": "ids", + "value": { + "name": "ids", + "type_name": "", + "op_sym": ":", + "value": "[\n 7\n 8\n 9\n]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "7", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "8", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "9", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + } + ] + } + ] +} diff --git a/kclvm/query/src/snapshots/kclvm_query__tests__list_variables-32.snap b/kclvm/query/src/snapshots/kclvm_query__tests__list_variables-32.snap new file mode 100644 index 000000000..8ff53eded --- /dev/null +++ b/kclvm/query/src/snapshots/kclvm_query__tests__list_variables-32.snap @@ -0,0 +1,16 @@ +--- +source: query/src/tests.rs +expression: got_json +--- +{ + "job.name": [ + { + "name": "name", + "type_name": "", + "op_sym": "=", + "value": "\"{}-{}\".format(\"app\", \"test\").lower()", + "list_items": [], + "dict_entries": [] + } + ] +} diff --git a/kclvm/query/src/snapshots/kclvm_query__tests__list_variables-33.snap b/kclvm/query/src/snapshots/kclvm_query__tests__list_variables-33.snap new file mode 100644 index 000000000..d89b02b12 --- /dev/null +++ b/kclvm/query/src/snapshots/kclvm_query__tests__list_variables-33.snap @@ -0,0 +1,33 @@ +--- +source: query/src/tests.rs +expression: got_json +--- +{ + "union_list": [ + { + "name": "union_list", + "type_name": "", + "op_sym": "=", + "value": "[\n *_list0\n *_list1\n]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "*_list0", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "*_list1", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + ] +} diff --git a/kclvm/query/src/snapshots/kclvm_query__tests__list_variables-34.snap b/kclvm/query/src/snapshots/kclvm_query__tests__list_variables-34.snap new file mode 100644 index 000000000..f5e8f07ac --- /dev/null +++ b/kclvm/query/src/snapshots/kclvm_query__tests__list_variables-34.snap @@ -0,0 +1,39 @@ +--- +source: query/src/tests.rs +expression: got_json +--- +{ + "a_dict": [ + { + "name": "a_dict", + "type_name": "", + "op_sym": "=", + "value": "{\n **_part1\n **_part2\n}", + "list_items": [], + "dict_entries": [ + { + "key": "", + "value": { + "name": "", + "type_name": "", + "op_sym": ":", + "value": "_part1", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "", + "value": { + "name": "", + "type_name": "", + "op_sym": ":", + "value": "_part2", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ] +} diff --git a/kclvm/query/src/snapshots/kclvm_query__tests__list_variables-4.snap b/kclvm/query/src/snapshots/kclvm_query__tests__list_variables-4.snap new file mode 100644 index 000000000..b8f33a1f4 --- /dev/null +++ b/kclvm/query/src/snapshots/kclvm_query__tests__list_variables-4.snap @@ -0,0 +1,16 @@ +--- +source: query/src/tests.rs +expression: got_json +--- +{ + "b1": [ + { + "name": "b1", + "type_name": "", + "op_sym": "=", + "value": "True", + "list_items": [], + "dict_entries": [] + } + ] +} diff --git a/kclvm/query/src/snapshots/kclvm_query__tests__list_variables-5.snap b/kclvm/query/src/snapshots/kclvm_query__tests__list_variables-5.snap new file mode 100644 index 000000000..0ad8ec0d3 --- /dev/null +++ b/kclvm/query/src/snapshots/kclvm_query__tests__list_variables-5.snap @@ -0,0 +1,16 @@ +--- +source: query/src/tests.rs +expression: got_json +--- +{ + "b2": [ + { + "name": "b2", + "type_name": "", + "op_sym": "=", + "value": "False", + "list_items": [], + "dict_entries": [] + } + ] +} diff --git a/kclvm/query/src/snapshots/kclvm_query__tests__list_variables-6.snap b/kclvm/query/src/snapshots/kclvm_query__tests__list_variables-6.snap new file mode 100644 index 000000000..289741857 --- /dev/null +++ b/kclvm/query/src/snapshots/kclvm_query__tests__list_variables-6.snap @@ -0,0 +1,16 @@ +--- +source: query/src/tests.rs +expression: got_json +--- +{ + "s1": [ + { + "name": "s1", + "type_name": "", + "op_sym": "=", + "value": "\"Hello\"", + "list_items": [], + "dict_entries": [] + } + ] +} diff --git a/kclvm/query/src/snapshots/kclvm_query__tests__list_variables-7.snap b/kclvm/query/src/snapshots/kclvm_query__tests__list_variables-7.snap new file mode 100644 index 000000000..588a63886 --- /dev/null +++ b/kclvm/query/src/snapshots/kclvm_query__tests__list_variables-7.snap @@ -0,0 +1,41 @@ +--- +source: query/src/tests.rs +expression: got_json +--- +{ + "array1": [ + { + "name": "array1", + "type_name": "", + "op_sym": "=", + "value": "[\n 1\n 2\n 3\n]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "1", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "2", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "3", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + ] +} diff --git a/kclvm/query/src/snapshots/kclvm_query__tests__list_variables-8.snap b/kclvm/query/src/snapshots/kclvm_query__tests__list_variables-8.snap new file mode 100644 index 000000000..3c3a55dc0 --- /dev/null +++ b/kclvm/query/src/snapshots/kclvm_query__tests__list_variables-8.snap @@ -0,0 +1,39 @@ +--- +source: query/src/tests.rs +expression: got_json +--- +{ + "dict1": [ + { + "name": "dict1", + "type_name": "", + "op_sym": "=", + "value": "{\n \"a\": 1\n \"b\": 2\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "1", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "b", + "value": { + "name": "b", + "type_name": "", + "op_sym": ":", + "value": "2", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ] +} diff --git a/kclvm/query/src/snapshots/kclvm_query__tests__list_variables-9.snap b/kclvm/query/src/snapshots/kclvm_query__tests__list_variables-9.snap new file mode 100644 index 000000000..1a0eecc18 --- /dev/null +++ b/kclvm/query/src/snapshots/kclvm_query__tests__list_variables-9.snap @@ -0,0 +1,16 @@ +--- +source: query/src/tests.rs +expression: got_json +--- +{ + "dict1.a": [ + { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "1", + "list_items": [], + "dict_entries": [] + } + ] +} diff --git a/kclvm/query/src/snapshots/kclvm_query__tests__list_variables.snap b/kclvm/query/src/snapshots/kclvm_query__tests__list_variables.snap new file mode 100644 index 000000000..f8f69e330 --- /dev/null +++ b/kclvm/query/src/snapshots/kclvm_query__tests__list_variables.snap @@ -0,0 +1,16 @@ +--- +source: query/src/tests.rs +expression: got_json +--- +{ + "a": [ + { + "name": "a", + "type_name": "", + "op_sym": "=", + "value": "1", + "list_items": [], + "dict_entries": [] + } + ] +} diff --git a/kclvm/query/src/test_data/config.k b/kclvm/query/src/test_data/config.k new file mode 100644 index 000000000..a29c47a19 --- /dev/null +++ b/kclvm/query/src/test_data/config.k @@ -0,0 +1,59 @@ +schema Main: + name?: str + env?: [{str:}] + +schema Probe: + initialDelaySeconds?: int + timeoutSeconds?: int + periodSeconds?: int = 10 + successThreshold?: int + failureThreshold?: int + +schema AppConfiguration: + appName: str + image: str + overQuota: bool = False + resource: {str:} + mainContainer?: Main + labels: {str:} + probe?: Probe + +appConfiguration = AppConfiguration { + appName: "kclvm" + image: "kclvm/kclvm:v0.1.0" + resource: { + cpu: "4" + disk: "50Gi" + memory: "12Gi" + } + labels: { + key: { + key: "value" + } + } + mainContainer: Main { + name: "kclvm" + } + overQuota = True + overQuota = True + probe: Probe {} +} + +appConfigurationUnification: AppConfiguration { + appName: "kclvm" + image: "kclvm/kclvm:v0.1.0" + resource: { + cpu: "4" + disk: "50Gi" + memory: "12Gi" + } + labels: { + key: { + key: "value" + } + } + mainContainer: Main { + name: "kclvm" + } + overQuota: True +} diff --git a/kclvm/query/src/test_data/expect.k b/kclvm/query/src/test_data/expect.k new file mode 100644 index 000000000..90ca23838 --- /dev/null +++ b/kclvm/query/src/test_data/expect.k @@ -0,0 +1,68 @@ +schema Data: + id?: int = 0 + value?: str = "value" + +schema Config: + image: str + data?: Data + +if True: + configOther = Config {image = "image/other:v1"} + +config = Config { + image = "image/image:v1" + data = { + id = 1 + value = "override_value" + } +} + +config: Config { + image = "image/image:v3" +} +dict_config = { + "image": "image/image:v2" + "data": { + "id": 2 + "value2": "override_value2" + } +} +envs = [ + { + key = "key1" + value = "value1" + } + { + key = "key2" + value = "value2" + } +] + +isfilter = False + +count = 2 + +msg = "Hi World" + +dict_delete = { + "data": { + "id": 1 + "value": "override_value" + } +} + +insert_config = { + key = 1 +} + +uni_config = { + labels: {key1: 1} +} + +config_unification: Config { + "image": "image/image:v4" + env: { + "aaa": "aaa" + bbb: "bbb" + } +} diff --git a/kclvm/query/src/test_data/get_schema_ty/aaa/kcl.mod b/kclvm/query/src/test_data/get_schema_ty/aaa/kcl.mod new file mode 100644 index 000000000..1e29d9eb2 --- /dev/null +++ b/kclvm/query/src/test_data/get_schema_ty/aaa/kcl.mod @@ -0,0 +1,5 @@ +[package] +name = "aaa" +edition = "0.0.1" +version = "0.0.1" + diff --git a/kclvm/query/src/test_data/get_schema_ty/aaa/main.k b/kclvm/query/src/test_data/get_schema_ty/aaa/main.k new file mode 100644 index 000000000..e2c858985 --- /dev/null +++ b/kclvm/query/src/test_data/get_schema_ty/aaa/main.k @@ -0,0 +1,5 @@ +import bbb as b + +a = b.B { + name: "b instance in a" +} \ No newline at end of file diff --git a/kclvm/query/src/test_data/get_schema_ty/bbb/kcl.mod b/kclvm/query/src/test_data/get_schema_ty/bbb/kcl.mod new file mode 100644 index 000000000..e9ea10a52 --- /dev/null +++ b/kclvm/query/src/test_data/get_schema_ty/bbb/kcl.mod @@ -0,0 +1,5 @@ +[package] +name = "bbb" +edition = "0.0.1" +version = "0.0.1" + diff --git a/kclvm/query/src/test_data/get_schema_ty/bbb/main.k b/kclvm/query/src/test_data/get_schema_ty/bbb/main.k new file mode 100644 index 000000000..21dad4f9e --- /dev/null +++ b/kclvm/query/src/test_data/get_schema_ty/bbb/main.k @@ -0,0 +1,2 @@ +schema B: + name: str \ No newline at end of file diff --git a/kclvm/query/src/test_data/get_schema_ty_under_path/aaa/kcl.mod b/kclvm/query/src/test_data/get_schema_ty_under_path/aaa/kcl.mod new file mode 100644 index 000000000..062218adb --- /dev/null +++ b/kclvm/query/src/test_data/get_schema_ty_under_path/aaa/kcl.mod @@ -0,0 +1,8 @@ +[package] +name = "aaa" +edition = "0.0.1" +version = "0.0.1" + +[dependencies] +bbb = { path = "../bbb" } +helloworld = "0.0.1" \ No newline at end of file diff --git a/kclvm/query/src/test_data/get_schema_ty_under_path/aaa/main.k b/kclvm/query/src/test_data/get_schema_ty_under_path/aaa/main.k new file mode 100644 index 000000000..5c48776d5 --- /dev/null +++ b/kclvm/query/src/test_data/get_schema_ty_under_path/aaa/main.k @@ -0,0 +1,5 @@ +import bbb + +a = bbb.B { + name: "b instance in a" +} \ No newline at end of file diff --git a/kclvm/query/src/test_data/get_schema_ty_under_path/aaa/sub/sub.k b/kclvm/query/src/test_data/get_schema_ty_under_path/aaa/sub/sub.k new file mode 100644 index 000000000..8000c5ff0 --- /dev/null +++ b/kclvm/query/src/test_data/get_schema_ty_under_path/aaa/sub/sub.k @@ -0,0 +1,3 @@ +schema Sub: + name: str + \ No newline at end of file diff --git a/kclvm/query/src/test_data/get_schema_ty_under_path/bbb/kcl.mod b/kclvm/query/src/test_data/get_schema_ty_under_path/bbb/kcl.mod new file mode 100644 index 000000000..e9ea10a52 --- /dev/null +++ b/kclvm/query/src/test_data/get_schema_ty_under_path/bbb/kcl.mod @@ -0,0 +1,5 @@ +[package] +name = "bbb" +edition = "0.0.1" +version = "0.0.1" + diff --git a/kclvm/query/src/test_data/get_schema_ty_under_path/bbb/main.k b/kclvm/query/src/test_data/get_schema_ty_under_path/bbb/main.k new file mode 100644 index 000000000..15b434862 --- /dev/null +++ b/kclvm/query/src/test_data/get_schema_ty_under_path/bbb/main.k @@ -0,0 +1,4 @@ +schema Base: + n: str +schema B(Base): + name: str \ No newline at end of file diff --git a/kclvm/query/src/test_data/get_schema_ty_under_path/helloworld_0.0.1/README.md b/kclvm/query/src/test_data/get_schema_ty_under_path/helloworld_0.0.1/README.md new file mode 100644 index 000000000..4d63fef38 --- /dev/null +++ b/kclvm/query/src/test_data/get_schema_ty_under_path/helloworld_0.0.1/README.md @@ -0,0 +1,2 @@ +## Introduction +This is a kcl package named helloworld. diff --git a/kclvm/query/src/test_data/get_schema_ty_under_path/helloworld_0.0.1/kcl.mod b/kclvm/query/src/test_data/get_schema_ty_under_path/helloworld_0.0.1/kcl.mod new file mode 100644 index 000000000..bef7e7f76 --- /dev/null +++ b/kclvm/query/src/test_data/get_schema_ty_under_path/helloworld_0.0.1/kcl.mod @@ -0,0 +1,5 @@ +[package] +name = "helloworld" +edition = "0.0.1" +version = "0.0.1" + diff --git a/kclvm/query/src/test_data/get_schema_ty_under_path/helloworld_0.0.1/main.k b/kclvm/query/src/test_data/get_schema_ty_under_path/helloworld_0.0.1/main.k new file mode 100644 index 000000000..571977787 --- /dev/null +++ b/kclvm/query/src/test_data/get_schema_ty_under_path/helloworld_0.0.1/main.k @@ -0,0 +1,3 @@ +The_first_kcl_program = 'Hello World!' +schema Hello: + name: str \ No newline at end of file diff --git a/kclvm/query/src/test_data/import_paths.k b/kclvm/query/src/test_data/import_paths.k new file mode 100644 index 000000000..6520cdc6f --- /dev/null +++ b/kclvm/query/src/test_data/import_paths.k @@ -0,0 +1,11 @@ +import pkg +import pkg.pkg +import pkg.pkg as alias_pkg1 +import pkg.pkg as alias_pkg2 +import relative_pkg + +schema Data: + id?: int = 0 + value?: str = "value" + +data = Data {value = "override_value"} diff --git a/kclvm/query/src/test_data/invalid.bk.k b/kclvm/query/src/test_data/invalid.bk.k new file mode 100644 index 000000000..9495fd5e5 --- /dev/null +++ b/kclvm/query/src/test_data/invalid.bk.k @@ -0,0 +1 @@ +"a": "b" \ No newline at end of file diff --git a/kclvm/query/src/test_data/kcl.mod b/kclvm/query/src/test_data/kcl.mod new file mode 100644 index 000000000..c51d42cae --- /dev/null +++ b/kclvm/query/src/test_data/kcl.mod @@ -0,0 +1,2 @@ +[package] + diff --git a/kclvm/query/src/test_data/simple.bk.k b/kclvm/query/src/test_data/simple.bk.k new file mode 100644 index 000000000..9d348f617 --- /dev/null +++ b/kclvm/query/src/test_data/simple.bk.k @@ -0,0 +1,77 @@ +schema Data: + id?: int = 0 + value?: str = "value" + +schema Config: + image: str + data?: Data + +if True: + configOther = Config {image = "image/other:v1"} + + +config = Config { + image = "image/image:v1" +} + +config : Config { + image = "image/image:v3" +} + +dict_config = { + "image": "image/image:v1" + "data": { + "id": 1 + "value": "override_value" + } +} +envs = [ + { + "name": "ENV1" + "value": "value1" + } + { + "name": "ENV2" + "value": "value2" + } +] + +isfilter = True + +count = 1 + +msg = "Hello World" + +delete = "Delete" + +dict_delete = { + "image": "image/image:v1" + "data": { + "id": 1 + "value": "override_value" + } +} + +dict_delete_whole = { + "image": "image/image:v1" + "data": { + "id": 1 + "value": "override_value" + } +} + +insert_config = {} + +uni_config = { + labels: {key1: "value1"} +} + +config_unification: Config { + image = "image/image:v1" + data = {id = 1, value = "override_value"} +} + +config_unification_delete: Config { + image = "image/image:v1" + data = {id = 1, value = "override_value"} +} \ No newline at end of file diff --git a/kclvm/query/src/test_data/simple.k b/kclvm/query/src/test_data/simple.k new file mode 100644 index 000000000..9d348f617 --- /dev/null +++ b/kclvm/query/src/test_data/simple.k @@ -0,0 +1,77 @@ +schema Data: + id?: int = 0 + value?: str = "value" + +schema Config: + image: str + data?: Data + +if True: + configOther = Config {image = "image/other:v1"} + + +config = Config { + image = "image/image:v1" +} + +config : Config { + image = "image/image:v3" +} + +dict_config = { + "image": "image/image:v1" + "data": { + "id": 1 + "value": "override_value" + } +} +envs = [ + { + "name": "ENV1" + "value": "value1" + } + { + "name": "ENV2" + "value": "value2" + } +] + +isfilter = True + +count = 1 + +msg = "Hello World" + +delete = "Delete" + +dict_delete = { + "image": "image/image:v1" + "data": { + "id": 1 + "value": "override_value" + } +} + +dict_delete_whole = { + "image": "image/image:v1" + "data": { + "id": 1 + "value": "override_value" + } +} + +insert_config = {} + +uni_config = { + labels: {key1: "value1"} +} + +config_unification: Config { + image = "image/image:v1" + data = {id = 1, value = "override_value"} +} + +config_unification_delete: Config { + image = "image/image:v1" + data = {id = 1, value = "override_value"} +} \ No newline at end of file diff --git a/kclvm/query/src/test_data/test_list_variables/invalid.k b/kclvm/query/src/test_data/test_list_variables/invalid.k new file mode 100644 index 000000000..9495fd5e5 --- /dev/null +++ b/kclvm/query/src/test_data/test_list_variables/invalid.k @@ -0,0 +1 @@ +"a": "b" \ No newline at end of file diff --git a/kclvm/query/src/test_data/test_list_variables/supported.k b/kclvm/query/src/test_data/test_list_variables/supported.k new file mode 100644 index 000000000..8ed77c079 --- /dev/null +++ b/kclvm/query/src/test_data/test_list_variables/supported.k @@ -0,0 +1,97 @@ +a = 1 +a1 = 2 +a3 = 3m + +b1 = True +b2 = False + +s1 = "Hello" + +array1 = [1, 2, 3] + +dict1 = {"a": 1, "b": 2} +dict2 = { + "a": 1 + "b": { + "c": 2 + "d": 3 + } +} + +schema A: + name: str + ids: [int] + data?: {str: {str: {str: int}}} + +sha = A { + name: "Hello" + ids: [1, 2, 3] + data: { + "a": { + "b": { + "c": 2 + } + } + } +} + +schema B: + a: A + +shb = B { + a: { + name: "HelloB" + ids: [4, 5, 6] + data: { + "d": { + "e": { + "f": 3 + } + } + } + } +} + +schema UnificationConf: + name: str + +uconfa = UnificationConf{ + name = "a" +} + +uconfa : UnificationConf { + name = "b" +} + +schema C: + a: A + +c = C { + a: {name: "Hello"} + a: {ids: [7, 8, 9]} +} + +schema Job: + name: str + +job = Job { + name = "{}-{}".format("app", "test").lower() +} + +select = a.b.c { + a: 1 +} + +_part1 = { + a = "b" +} + +_part2 = { + c = "d" +} + +_list0 = [1, 2, 3] +_list1 = [4, 5, 6] +union_list = [*_list0, *_list1] + +a_dict = {**_part1, **_part2} # {"a: "b", "c": "d"} \ No newline at end of file diff --git a/kclvm/query/src/test_data/test_list_variables/test_list_all_variables/a.json b/kclvm/query/src/test_data/test_list_variables/test_list_all_variables/a.json new file mode 100644 index 000000000..ce82e99a9 --- /dev/null +++ b/kclvm/query/src/test_data/test_list_variables/test_list_all_variables/a.json @@ -0,0 +1,730 @@ +{ + "_list0": [ + { + "name": "_list0", + "type_name": "", + "op_sym": "=", + "value": "[1, 2, 3]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "1", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "2", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "3", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + ], + "_list1": [ + { + "name": "_list1", + "type_name": "", + "op_sym": "=", + "value": "[4, 5, 6]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "4", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "5", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "6", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + ], + "_part1": [ + { + "name": "_part1", + "type_name": "", + "op_sym": "=", + "value": "{a = \"b\"}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": "=", + "value": "\"b\"", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "_part2": [ + { + "name": "_part2", + "type_name": "", + "op_sym": "=", + "value": "{c = \"d\"}", + "list_items": [], + "dict_entries": [ + { + "key": "c", + "value": { + "name": "c", + "type_name": "", + "op_sym": "=", + "value": "\"d\"", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "a": [ + { + "name": "a", + "type_name": "", + "op_sym": "=", + "value": "1", + "list_items": [], + "dict_entries": [] + } + ], + "a1": [ + { + "name": "a1", + "type_name": "", + "op_sym": "=", + "value": "2", + "list_items": [], + "dict_entries": [] + } + ], + "a3": [ + { + "name": "a3", + "type_name": "", + "op_sym": "=", + "value": "3m", + "list_items": [], + "dict_entries": [] + } + ], + "a_dict": [ + { + "name": "a_dict", + "type_name": "", + "op_sym": "=", + "value": "{**_part1, **_part2}", + "list_items": [], + "dict_entries": [ + { + "key": "", + "value": { + "name": "", + "type_name": "", + "op_sym": ":", + "value": "_part1", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "", + "value": { + "name": "", + "type_name": "", + "op_sym": ":", + "value": "_part2", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "array1": [ + { + "name": "array1", + "type_name": "", + "op_sym": "=", + "value": "[1, 2, 3]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "1", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "2", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "3", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + ], + "b1": [ + { + "name": "b1", + "type_name": "", + "op_sym": "=", + "value": "True", + "list_items": [], + "dict_entries": [] + } + ], + "b2": [ + { + "name": "b2", + "type_name": "", + "op_sym": "=", + "value": "False", + "list_items": [], + "dict_entries": [] + } + ], + "c": [ + { + "name": "c", + "type_name": "C", + "op_sym": "=", + "value": "C {\n a: {name: \"Hello\"}\n a: {ids: [7, 8, 9]}\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{name: \"Hello\"}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": ":", + "value": "\"Hello\"", + "list_items": [], + "dict_entries": [] + } + } + ] + } + }, + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{ids: [7, 8, 9]}", + "list_items": [], + "dict_entries": [ + { + "key": "ids", + "value": { + "name": "ids", + "type_name": "", + "op_sym": ":", + "value": "[7, 8, 9]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "7", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "8", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "9", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + } + ] + } + } + ] + } + ], + "dict1": [ + { + "name": "dict1", + "type_name": "", + "op_sym": "=", + "value": "{\"a\": 1, \"b\": 2}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "1", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "b", + "value": { + "name": "b", + "type_name": "", + "op_sym": ":", + "value": "2", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "dict2": [ + { + "name": "dict2", + "type_name": "", + "op_sym": "=", + "value": "{\n \"a\": 1\n \"b\": {\n \"c\": 2\n \"d\": 3\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "1", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "b", + "value": { + "name": "b", + "type_name": "", + "op_sym": ":", + "value": "{\n \"c\": 2\n \"d\": 3\n}", + "list_items": [], + "dict_entries": [ + { + "key": "c", + "value": { + "name": "c", + "type_name": "", + "op_sym": ":", + "value": "2", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "d", + "value": { + "name": "d", + "type_name": "", + "op_sym": ":", + "value": "3", + "list_items": [], + "dict_entries": [] + } + } + ] + } + } + ] + } + ], + "job": [ + { + "name": "job", + "type_name": "Job", + "op_sym": "=", + "value": "Job {name = \"{}-{}\".format(\"app\", \"test\").lower()}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": "=", + "value": "\"{}-{}\".format(\"app\", \"test\").lower()", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "s1": [ + { + "name": "s1", + "type_name": "", + "op_sym": "=", + "value": "\"Hello\"", + "list_items": [], + "dict_entries": [] + } + ], + "select": [ + { + "name": "select", + "type_name": "a.b.c", + "op_sym": "=", + "value": "a.b.c {a: 1}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "1", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "sha": [ + { + "name": "sha", + "type_name": "A", + "op_sym": "=", + "value": "A {\n name: \"Hello\"\n ids: [1, 2, 3]\n data: {\n \"a\": {\n \"b\": {\"c\": 2}\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": ":", + "value": "\"Hello\"", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "ids", + "value": { + "name": "ids", + "type_name": "", + "op_sym": ":", + "value": "[1, 2, 3]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "1", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "2", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "3", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + }, + { + "key": "data", + "value": { + "name": "data", + "type_name": "", + "op_sym": ":", + "value": "{\n \"a\": {\n \"b\": {\"c\": 2}\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{\n \"b\": {\"c\": 2}\n}", + "list_items": [], + "dict_entries": [ + { + "key": "b", + "value": { + "name": "b", + "type_name": "", + "op_sym": ":", + "value": "{\"c\": 2}", + "list_items": [], + "dict_entries": [ + { + "key": "c", + "value": { + "name": "c", + "type_name": "", + "op_sym": ":", + "value": "2", + "list_items": [], + "dict_entries": [] + } + } + ] + } + } + ] + } + } + ] + } + } + ] + } + ], + "shb": [ + { + "name": "shb", + "type_name": "B", + "op_sym": "=", + "value": "B {\n a: {\n name: \"HelloB\"\n ids: [4, 5, 6]\n data: {\n \"d\": {\n \"e\": {\"f\": 3}\n }\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{\n name: \"HelloB\"\n ids: [4, 5, 6]\n data: {\n \"d\": {\n \"e\": {\"f\": 3}\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": ":", + "value": "\"HelloB\"", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "ids", + "value": { + "name": "ids", + "type_name": "", + "op_sym": ":", + "value": "[4, 5, 6]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "4", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "5", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "6", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + }, + { + "key": "data", + "value": { + "name": "data", + "type_name": "", + "op_sym": ":", + "value": "{\n \"d\": {\n \"e\": {\"f\": 3}\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "d", + "value": { + "name": "d", + "type_name": "", + "op_sym": ":", + "value": "{\n \"e\": {\"f\": 3}\n}", + "list_items": [], + "dict_entries": [ + { + "key": "e", + "value": { + "name": "e", + "type_name": "", + "op_sym": ":", + "value": "{\"f\": 3}", + "list_items": [], + "dict_entries": [ + { + "key": "f", + "value": { + "name": "f", + "type_name": "", + "op_sym": ":", + "value": "3", + "list_items": [], + "dict_entries": [] + } + } + ] + } + } + ] + } + } + ] + } + } + ] + } + } + ] + } + ], + "uconfa": [ + { + "name": "uconfa", + "type_name": "UnificationConf", + "op_sym": ":", + "value": "UnificationConf {name = \"b\"}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": "=", + "value": "\"b\"", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "union_list": [ + { + "name": "union_list", + "type_name": "", + "op_sym": "=", + "value": "[*_list0, *_list1]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "*_list0", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "*_list1", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + ] +} \ No newline at end of file diff --git a/kclvm/query/src/test_data/test_list_variables/test_list_all_variables/a1.json b/kclvm/query/src/test_data/test_list_variables/test_list_all_variables/a1.json new file mode 100644 index 000000000..ce82e99a9 --- /dev/null +++ b/kclvm/query/src/test_data/test_list_variables/test_list_all_variables/a1.json @@ -0,0 +1,730 @@ +{ + "_list0": [ + { + "name": "_list0", + "type_name": "", + "op_sym": "=", + "value": "[1, 2, 3]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "1", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "2", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "3", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + ], + "_list1": [ + { + "name": "_list1", + "type_name": "", + "op_sym": "=", + "value": "[4, 5, 6]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "4", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "5", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "6", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + ], + "_part1": [ + { + "name": "_part1", + "type_name": "", + "op_sym": "=", + "value": "{a = \"b\"}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": "=", + "value": "\"b\"", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "_part2": [ + { + "name": "_part2", + "type_name": "", + "op_sym": "=", + "value": "{c = \"d\"}", + "list_items": [], + "dict_entries": [ + { + "key": "c", + "value": { + "name": "c", + "type_name": "", + "op_sym": "=", + "value": "\"d\"", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "a": [ + { + "name": "a", + "type_name": "", + "op_sym": "=", + "value": "1", + "list_items": [], + "dict_entries": [] + } + ], + "a1": [ + { + "name": "a1", + "type_name": "", + "op_sym": "=", + "value": "2", + "list_items": [], + "dict_entries": [] + } + ], + "a3": [ + { + "name": "a3", + "type_name": "", + "op_sym": "=", + "value": "3m", + "list_items": [], + "dict_entries": [] + } + ], + "a_dict": [ + { + "name": "a_dict", + "type_name": "", + "op_sym": "=", + "value": "{**_part1, **_part2}", + "list_items": [], + "dict_entries": [ + { + "key": "", + "value": { + "name": "", + "type_name": "", + "op_sym": ":", + "value": "_part1", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "", + "value": { + "name": "", + "type_name": "", + "op_sym": ":", + "value": "_part2", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "array1": [ + { + "name": "array1", + "type_name": "", + "op_sym": "=", + "value": "[1, 2, 3]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "1", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "2", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "3", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + ], + "b1": [ + { + "name": "b1", + "type_name": "", + "op_sym": "=", + "value": "True", + "list_items": [], + "dict_entries": [] + } + ], + "b2": [ + { + "name": "b2", + "type_name": "", + "op_sym": "=", + "value": "False", + "list_items": [], + "dict_entries": [] + } + ], + "c": [ + { + "name": "c", + "type_name": "C", + "op_sym": "=", + "value": "C {\n a: {name: \"Hello\"}\n a: {ids: [7, 8, 9]}\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{name: \"Hello\"}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": ":", + "value": "\"Hello\"", + "list_items": [], + "dict_entries": [] + } + } + ] + } + }, + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{ids: [7, 8, 9]}", + "list_items": [], + "dict_entries": [ + { + "key": "ids", + "value": { + "name": "ids", + "type_name": "", + "op_sym": ":", + "value": "[7, 8, 9]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "7", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "8", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "9", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + } + ] + } + } + ] + } + ], + "dict1": [ + { + "name": "dict1", + "type_name": "", + "op_sym": "=", + "value": "{\"a\": 1, \"b\": 2}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "1", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "b", + "value": { + "name": "b", + "type_name": "", + "op_sym": ":", + "value": "2", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "dict2": [ + { + "name": "dict2", + "type_name": "", + "op_sym": "=", + "value": "{\n \"a\": 1\n \"b\": {\n \"c\": 2\n \"d\": 3\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "1", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "b", + "value": { + "name": "b", + "type_name": "", + "op_sym": ":", + "value": "{\n \"c\": 2\n \"d\": 3\n}", + "list_items": [], + "dict_entries": [ + { + "key": "c", + "value": { + "name": "c", + "type_name": "", + "op_sym": ":", + "value": "2", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "d", + "value": { + "name": "d", + "type_name": "", + "op_sym": ":", + "value": "3", + "list_items": [], + "dict_entries": [] + } + } + ] + } + } + ] + } + ], + "job": [ + { + "name": "job", + "type_name": "Job", + "op_sym": "=", + "value": "Job {name = \"{}-{}\".format(\"app\", \"test\").lower()}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": "=", + "value": "\"{}-{}\".format(\"app\", \"test\").lower()", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "s1": [ + { + "name": "s1", + "type_name": "", + "op_sym": "=", + "value": "\"Hello\"", + "list_items": [], + "dict_entries": [] + } + ], + "select": [ + { + "name": "select", + "type_name": "a.b.c", + "op_sym": "=", + "value": "a.b.c {a: 1}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "1", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "sha": [ + { + "name": "sha", + "type_name": "A", + "op_sym": "=", + "value": "A {\n name: \"Hello\"\n ids: [1, 2, 3]\n data: {\n \"a\": {\n \"b\": {\"c\": 2}\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": ":", + "value": "\"Hello\"", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "ids", + "value": { + "name": "ids", + "type_name": "", + "op_sym": ":", + "value": "[1, 2, 3]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "1", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "2", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "3", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + }, + { + "key": "data", + "value": { + "name": "data", + "type_name": "", + "op_sym": ":", + "value": "{\n \"a\": {\n \"b\": {\"c\": 2}\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{\n \"b\": {\"c\": 2}\n}", + "list_items": [], + "dict_entries": [ + { + "key": "b", + "value": { + "name": "b", + "type_name": "", + "op_sym": ":", + "value": "{\"c\": 2}", + "list_items": [], + "dict_entries": [ + { + "key": "c", + "value": { + "name": "c", + "type_name": "", + "op_sym": ":", + "value": "2", + "list_items": [], + "dict_entries": [] + } + } + ] + } + } + ] + } + } + ] + } + } + ] + } + ], + "shb": [ + { + "name": "shb", + "type_name": "B", + "op_sym": "=", + "value": "B {\n a: {\n name: \"HelloB\"\n ids: [4, 5, 6]\n data: {\n \"d\": {\n \"e\": {\"f\": 3}\n }\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{\n name: \"HelloB\"\n ids: [4, 5, 6]\n data: {\n \"d\": {\n \"e\": {\"f\": 3}\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": ":", + "value": "\"HelloB\"", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "ids", + "value": { + "name": "ids", + "type_name": "", + "op_sym": ":", + "value": "[4, 5, 6]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "4", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "5", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "6", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + }, + { + "key": "data", + "value": { + "name": "data", + "type_name": "", + "op_sym": ":", + "value": "{\n \"d\": {\n \"e\": {\"f\": 3}\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "d", + "value": { + "name": "d", + "type_name": "", + "op_sym": ":", + "value": "{\n \"e\": {\"f\": 3}\n}", + "list_items": [], + "dict_entries": [ + { + "key": "e", + "value": { + "name": "e", + "type_name": "", + "op_sym": ":", + "value": "{\"f\": 3}", + "list_items": [], + "dict_entries": [ + { + "key": "f", + "value": { + "name": "f", + "type_name": "", + "op_sym": ":", + "value": "3", + "list_items": [], + "dict_entries": [] + } + } + ] + } + } + ] + } + } + ] + } + } + ] + } + } + ] + } + ], + "uconfa": [ + { + "name": "uconfa", + "type_name": "UnificationConf", + "op_sym": ":", + "value": "UnificationConf {name = \"b\"}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": "=", + "value": "\"b\"", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "union_list": [ + { + "name": "union_list", + "type_name": "", + "op_sym": "=", + "value": "[*_list0, *_list1]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "*_list0", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "*_list1", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + ] +} \ No newline at end of file diff --git a/kclvm/query/src/test_data/test_list_variables/test_list_all_variables/a3.json b/kclvm/query/src/test_data/test_list_variables/test_list_all_variables/a3.json new file mode 100644 index 000000000..ce82e99a9 --- /dev/null +++ b/kclvm/query/src/test_data/test_list_variables/test_list_all_variables/a3.json @@ -0,0 +1,730 @@ +{ + "_list0": [ + { + "name": "_list0", + "type_name": "", + "op_sym": "=", + "value": "[1, 2, 3]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "1", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "2", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "3", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + ], + "_list1": [ + { + "name": "_list1", + "type_name": "", + "op_sym": "=", + "value": "[4, 5, 6]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "4", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "5", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "6", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + ], + "_part1": [ + { + "name": "_part1", + "type_name": "", + "op_sym": "=", + "value": "{a = \"b\"}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": "=", + "value": "\"b\"", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "_part2": [ + { + "name": "_part2", + "type_name": "", + "op_sym": "=", + "value": "{c = \"d\"}", + "list_items": [], + "dict_entries": [ + { + "key": "c", + "value": { + "name": "c", + "type_name": "", + "op_sym": "=", + "value": "\"d\"", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "a": [ + { + "name": "a", + "type_name": "", + "op_sym": "=", + "value": "1", + "list_items": [], + "dict_entries": [] + } + ], + "a1": [ + { + "name": "a1", + "type_name": "", + "op_sym": "=", + "value": "2", + "list_items": [], + "dict_entries": [] + } + ], + "a3": [ + { + "name": "a3", + "type_name": "", + "op_sym": "=", + "value": "3m", + "list_items": [], + "dict_entries": [] + } + ], + "a_dict": [ + { + "name": "a_dict", + "type_name": "", + "op_sym": "=", + "value": "{**_part1, **_part2}", + "list_items": [], + "dict_entries": [ + { + "key": "", + "value": { + "name": "", + "type_name": "", + "op_sym": ":", + "value": "_part1", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "", + "value": { + "name": "", + "type_name": "", + "op_sym": ":", + "value": "_part2", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "array1": [ + { + "name": "array1", + "type_name": "", + "op_sym": "=", + "value": "[1, 2, 3]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "1", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "2", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "3", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + ], + "b1": [ + { + "name": "b1", + "type_name": "", + "op_sym": "=", + "value": "True", + "list_items": [], + "dict_entries": [] + } + ], + "b2": [ + { + "name": "b2", + "type_name": "", + "op_sym": "=", + "value": "False", + "list_items": [], + "dict_entries": [] + } + ], + "c": [ + { + "name": "c", + "type_name": "C", + "op_sym": "=", + "value": "C {\n a: {name: \"Hello\"}\n a: {ids: [7, 8, 9]}\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{name: \"Hello\"}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": ":", + "value": "\"Hello\"", + "list_items": [], + "dict_entries": [] + } + } + ] + } + }, + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{ids: [7, 8, 9]}", + "list_items": [], + "dict_entries": [ + { + "key": "ids", + "value": { + "name": "ids", + "type_name": "", + "op_sym": ":", + "value": "[7, 8, 9]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "7", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "8", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "9", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + } + ] + } + } + ] + } + ], + "dict1": [ + { + "name": "dict1", + "type_name": "", + "op_sym": "=", + "value": "{\"a\": 1, \"b\": 2}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "1", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "b", + "value": { + "name": "b", + "type_name": "", + "op_sym": ":", + "value": "2", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "dict2": [ + { + "name": "dict2", + "type_name": "", + "op_sym": "=", + "value": "{\n \"a\": 1\n \"b\": {\n \"c\": 2\n \"d\": 3\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "1", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "b", + "value": { + "name": "b", + "type_name": "", + "op_sym": ":", + "value": "{\n \"c\": 2\n \"d\": 3\n}", + "list_items": [], + "dict_entries": [ + { + "key": "c", + "value": { + "name": "c", + "type_name": "", + "op_sym": ":", + "value": "2", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "d", + "value": { + "name": "d", + "type_name": "", + "op_sym": ":", + "value": "3", + "list_items": [], + "dict_entries": [] + } + } + ] + } + } + ] + } + ], + "job": [ + { + "name": "job", + "type_name": "Job", + "op_sym": "=", + "value": "Job {name = \"{}-{}\".format(\"app\", \"test\").lower()}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": "=", + "value": "\"{}-{}\".format(\"app\", \"test\").lower()", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "s1": [ + { + "name": "s1", + "type_name": "", + "op_sym": "=", + "value": "\"Hello\"", + "list_items": [], + "dict_entries": [] + } + ], + "select": [ + { + "name": "select", + "type_name": "a.b.c", + "op_sym": "=", + "value": "a.b.c {a: 1}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "1", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "sha": [ + { + "name": "sha", + "type_name": "A", + "op_sym": "=", + "value": "A {\n name: \"Hello\"\n ids: [1, 2, 3]\n data: {\n \"a\": {\n \"b\": {\"c\": 2}\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": ":", + "value": "\"Hello\"", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "ids", + "value": { + "name": "ids", + "type_name": "", + "op_sym": ":", + "value": "[1, 2, 3]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "1", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "2", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "3", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + }, + { + "key": "data", + "value": { + "name": "data", + "type_name": "", + "op_sym": ":", + "value": "{\n \"a\": {\n \"b\": {\"c\": 2}\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{\n \"b\": {\"c\": 2}\n}", + "list_items": [], + "dict_entries": [ + { + "key": "b", + "value": { + "name": "b", + "type_name": "", + "op_sym": ":", + "value": "{\"c\": 2}", + "list_items": [], + "dict_entries": [ + { + "key": "c", + "value": { + "name": "c", + "type_name": "", + "op_sym": ":", + "value": "2", + "list_items": [], + "dict_entries": [] + } + } + ] + } + } + ] + } + } + ] + } + } + ] + } + ], + "shb": [ + { + "name": "shb", + "type_name": "B", + "op_sym": "=", + "value": "B {\n a: {\n name: \"HelloB\"\n ids: [4, 5, 6]\n data: {\n \"d\": {\n \"e\": {\"f\": 3}\n }\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{\n name: \"HelloB\"\n ids: [4, 5, 6]\n data: {\n \"d\": {\n \"e\": {\"f\": 3}\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": ":", + "value": "\"HelloB\"", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "ids", + "value": { + "name": "ids", + "type_name": "", + "op_sym": ":", + "value": "[4, 5, 6]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "4", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "5", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "6", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + }, + { + "key": "data", + "value": { + "name": "data", + "type_name": "", + "op_sym": ":", + "value": "{\n \"d\": {\n \"e\": {\"f\": 3}\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "d", + "value": { + "name": "d", + "type_name": "", + "op_sym": ":", + "value": "{\n \"e\": {\"f\": 3}\n}", + "list_items": [], + "dict_entries": [ + { + "key": "e", + "value": { + "name": "e", + "type_name": "", + "op_sym": ":", + "value": "{\"f\": 3}", + "list_items": [], + "dict_entries": [ + { + "key": "f", + "value": { + "name": "f", + "type_name": "", + "op_sym": ":", + "value": "3", + "list_items": [], + "dict_entries": [] + } + } + ] + } + } + ] + } + } + ] + } + } + ] + } + } + ] + } + ], + "uconfa": [ + { + "name": "uconfa", + "type_name": "UnificationConf", + "op_sym": ":", + "value": "UnificationConf {name = \"b\"}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": "=", + "value": "\"b\"", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "union_list": [ + { + "name": "union_list", + "type_name": "", + "op_sym": "=", + "value": "[*_list0, *_list1]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "*_list0", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "*_list1", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + ] +} \ No newline at end of file diff --git a/kclvm/query/src/test_data/test_list_variables/test_list_all_variables/a_dict.json b/kclvm/query/src/test_data/test_list_variables/test_list_all_variables/a_dict.json new file mode 100644 index 000000000..ce82e99a9 --- /dev/null +++ b/kclvm/query/src/test_data/test_list_variables/test_list_all_variables/a_dict.json @@ -0,0 +1,730 @@ +{ + "_list0": [ + { + "name": "_list0", + "type_name": "", + "op_sym": "=", + "value": "[1, 2, 3]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "1", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "2", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "3", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + ], + "_list1": [ + { + "name": "_list1", + "type_name": "", + "op_sym": "=", + "value": "[4, 5, 6]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "4", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "5", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "6", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + ], + "_part1": [ + { + "name": "_part1", + "type_name": "", + "op_sym": "=", + "value": "{a = \"b\"}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": "=", + "value": "\"b\"", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "_part2": [ + { + "name": "_part2", + "type_name": "", + "op_sym": "=", + "value": "{c = \"d\"}", + "list_items": [], + "dict_entries": [ + { + "key": "c", + "value": { + "name": "c", + "type_name": "", + "op_sym": "=", + "value": "\"d\"", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "a": [ + { + "name": "a", + "type_name": "", + "op_sym": "=", + "value": "1", + "list_items": [], + "dict_entries": [] + } + ], + "a1": [ + { + "name": "a1", + "type_name": "", + "op_sym": "=", + "value": "2", + "list_items": [], + "dict_entries": [] + } + ], + "a3": [ + { + "name": "a3", + "type_name": "", + "op_sym": "=", + "value": "3m", + "list_items": [], + "dict_entries": [] + } + ], + "a_dict": [ + { + "name": "a_dict", + "type_name": "", + "op_sym": "=", + "value": "{**_part1, **_part2}", + "list_items": [], + "dict_entries": [ + { + "key": "", + "value": { + "name": "", + "type_name": "", + "op_sym": ":", + "value": "_part1", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "", + "value": { + "name": "", + "type_name": "", + "op_sym": ":", + "value": "_part2", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "array1": [ + { + "name": "array1", + "type_name": "", + "op_sym": "=", + "value": "[1, 2, 3]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "1", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "2", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "3", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + ], + "b1": [ + { + "name": "b1", + "type_name": "", + "op_sym": "=", + "value": "True", + "list_items": [], + "dict_entries": [] + } + ], + "b2": [ + { + "name": "b2", + "type_name": "", + "op_sym": "=", + "value": "False", + "list_items": [], + "dict_entries": [] + } + ], + "c": [ + { + "name": "c", + "type_name": "C", + "op_sym": "=", + "value": "C {\n a: {name: \"Hello\"}\n a: {ids: [7, 8, 9]}\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{name: \"Hello\"}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": ":", + "value": "\"Hello\"", + "list_items": [], + "dict_entries": [] + } + } + ] + } + }, + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{ids: [7, 8, 9]}", + "list_items": [], + "dict_entries": [ + { + "key": "ids", + "value": { + "name": "ids", + "type_name": "", + "op_sym": ":", + "value": "[7, 8, 9]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "7", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "8", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "9", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + } + ] + } + } + ] + } + ], + "dict1": [ + { + "name": "dict1", + "type_name": "", + "op_sym": "=", + "value": "{\"a\": 1, \"b\": 2}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "1", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "b", + "value": { + "name": "b", + "type_name": "", + "op_sym": ":", + "value": "2", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "dict2": [ + { + "name": "dict2", + "type_name": "", + "op_sym": "=", + "value": "{\n \"a\": 1\n \"b\": {\n \"c\": 2\n \"d\": 3\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "1", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "b", + "value": { + "name": "b", + "type_name": "", + "op_sym": ":", + "value": "{\n \"c\": 2\n \"d\": 3\n}", + "list_items": [], + "dict_entries": [ + { + "key": "c", + "value": { + "name": "c", + "type_name": "", + "op_sym": ":", + "value": "2", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "d", + "value": { + "name": "d", + "type_name": "", + "op_sym": ":", + "value": "3", + "list_items": [], + "dict_entries": [] + } + } + ] + } + } + ] + } + ], + "job": [ + { + "name": "job", + "type_name": "Job", + "op_sym": "=", + "value": "Job {name = \"{}-{}\".format(\"app\", \"test\").lower()}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": "=", + "value": "\"{}-{}\".format(\"app\", \"test\").lower()", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "s1": [ + { + "name": "s1", + "type_name": "", + "op_sym": "=", + "value": "\"Hello\"", + "list_items": [], + "dict_entries": [] + } + ], + "select": [ + { + "name": "select", + "type_name": "a.b.c", + "op_sym": "=", + "value": "a.b.c {a: 1}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "1", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "sha": [ + { + "name": "sha", + "type_name": "A", + "op_sym": "=", + "value": "A {\n name: \"Hello\"\n ids: [1, 2, 3]\n data: {\n \"a\": {\n \"b\": {\"c\": 2}\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": ":", + "value": "\"Hello\"", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "ids", + "value": { + "name": "ids", + "type_name": "", + "op_sym": ":", + "value": "[1, 2, 3]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "1", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "2", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "3", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + }, + { + "key": "data", + "value": { + "name": "data", + "type_name": "", + "op_sym": ":", + "value": "{\n \"a\": {\n \"b\": {\"c\": 2}\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{\n \"b\": {\"c\": 2}\n}", + "list_items": [], + "dict_entries": [ + { + "key": "b", + "value": { + "name": "b", + "type_name": "", + "op_sym": ":", + "value": "{\"c\": 2}", + "list_items": [], + "dict_entries": [ + { + "key": "c", + "value": { + "name": "c", + "type_name": "", + "op_sym": ":", + "value": "2", + "list_items": [], + "dict_entries": [] + } + } + ] + } + } + ] + } + } + ] + } + } + ] + } + ], + "shb": [ + { + "name": "shb", + "type_name": "B", + "op_sym": "=", + "value": "B {\n a: {\n name: \"HelloB\"\n ids: [4, 5, 6]\n data: {\n \"d\": {\n \"e\": {\"f\": 3}\n }\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{\n name: \"HelloB\"\n ids: [4, 5, 6]\n data: {\n \"d\": {\n \"e\": {\"f\": 3}\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": ":", + "value": "\"HelloB\"", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "ids", + "value": { + "name": "ids", + "type_name": "", + "op_sym": ":", + "value": "[4, 5, 6]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "4", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "5", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "6", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + }, + { + "key": "data", + "value": { + "name": "data", + "type_name": "", + "op_sym": ":", + "value": "{\n \"d\": {\n \"e\": {\"f\": 3}\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "d", + "value": { + "name": "d", + "type_name": "", + "op_sym": ":", + "value": "{\n \"e\": {\"f\": 3}\n}", + "list_items": [], + "dict_entries": [ + { + "key": "e", + "value": { + "name": "e", + "type_name": "", + "op_sym": ":", + "value": "{\"f\": 3}", + "list_items": [], + "dict_entries": [ + { + "key": "f", + "value": { + "name": "f", + "type_name": "", + "op_sym": ":", + "value": "3", + "list_items": [], + "dict_entries": [] + } + } + ] + } + } + ] + } + } + ] + } + } + ] + } + } + ] + } + ], + "uconfa": [ + { + "name": "uconfa", + "type_name": "UnificationConf", + "op_sym": ":", + "value": "UnificationConf {name = \"b\"}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": "=", + "value": "\"b\"", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "union_list": [ + { + "name": "union_list", + "type_name": "", + "op_sym": "=", + "value": "[*_list0, *_list1]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "*_list0", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "*_list1", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + ] +} \ No newline at end of file diff --git a/kclvm/query/src/test_data/test_list_variables/test_list_all_variables/array1.json b/kclvm/query/src/test_data/test_list_variables/test_list_all_variables/array1.json new file mode 100644 index 000000000..ce82e99a9 --- /dev/null +++ b/kclvm/query/src/test_data/test_list_variables/test_list_all_variables/array1.json @@ -0,0 +1,730 @@ +{ + "_list0": [ + { + "name": "_list0", + "type_name": "", + "op_sym": "=", + "value": "[1, 2, 3]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "1", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "2", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "3", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + ], + "_list1": [ + { + "name": "_list1", + "type_name": "", + "op_sym": "=", + "value": "[4, 5, 6]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "4", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "5", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "6", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + ], + "_part1": [ + { + "name": "_part1", + "type_name": "", + "op_sym": "=", + "value": "{a = \"b\"}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": "=", + "value": "\"b\"", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "_part2": [ + { + "name": "_part2", + "type_name": "", + "op_sym": "=", + "value": "{c = \"d\"}", + "list_items": [], + "dict_entries": [ + { + "key": "c", + "value": { + "name": "c", + "type_name": "", + "op_sym": "=", + "value": "\"d\"", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "a": [ + { + "name": "a", + "type_name": "", + "op_sym": "=", + "value": "1", + "list_items": [], + "dict_entries": [] + } + ], + "a1": [ + { + "name": "a1", + "type_name": "", + "op_sym": "=", + "value": "2", + "list_items": [], + "dict_entries": [] + } + ], + "a3": [ + { + "name": "a3", + "type_name": "", + "op_sym": "=", + "value": "3m", + "list_items": [], + "dict_entries": [] + } + ], + "a_dict": [ + { + "name": "a_dict", + "type_name": "", + "op_sym": "=", + "value": "{**_part1, **_part2}", + "list_items": [], + "dict_entries": [ + { + "key": "", + "value": { + "name": "", + "type_name": "", + "op_sym": ":", + "value": "_part1", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "", + "value": { + "name": "", + "type_name": "", + "op_sym": ":", + "value": "_part2", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "array1": [ + { + "name": "array1", + "type_name": "", + "op_sym": "=", + "value": "[1, 2, 3]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "1", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "2", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "3", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + ], + "b1": [ + { + "name": "b1", + "type_name": "", + "op_sym": "=", + "value": "True", + "list_items": [], + "dict_entries": [] + } + ], + "b2": [ + { + "name": "b2", + "type_name": "", + "op_sym": "=", + "value": "False", + "list_items": [], + "dict_entries": [] + } + ], + "c": [ + { + "name": "c", + "type_name": "C", + "op_sym": "=", + "value": "C {\n a: {name: \"Hello\"}\n a: {ids: [7, 8, 9]}\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{name: \"Hello\"}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": ":", + "value": "\"Hello\"", + "list_items": [], + "dict_entries": [] + } + } + ] + } + }, + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{ids: [7, 8, 9]}", + "list_items": [], + "dict_entries": [ + { + "key": "ids", + "value": { + "name": "ids", + "type_name": "", + "op_sym": ":", + "value": "[7, 8, 9]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "7", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "8", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "9", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + } + ] + } + } + ] + } + ], + "dict1": [ + { + "name": "dict1", + "type_name": "", + "op_sym": "=", + "value": "{\"a\": 1, \"b\": 2}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "1", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "b", + "value": { + "name": "b", + "type_name": "", + "op_sym": ":", + "value": "2", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "dict2": [ + { + "name": "dict2", + "type_name": "", + "op_sym": "=", + "value": "{\n \"a\": 1\n \"b\": {\n \"c\": 2\n \"d\": 3\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "1", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "b", + "value": { + "name": "b", + "type_name": "", + "op_sym": ":", + "value": "{\n \"c\": 2\n \"d\": 3\n}", + "list_items": [], + "dict_entries": [ + { + "key": "c", + "value": { + "name": "c", + "type_name": "", + "op_sym": ":", + "value": "2", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "d", + "value": { + "name": "d", + "type_name": "", + "op_sym": ":", + "value": "3", + "list_items": [], + "dict_entries": [] + } + } + ] + } + } + ] + } + ], + "job": [ + { + "name": "job", + "type_name": "Job", + "op_sym": "=", + "value": "Job {name = \"{}-{}\".format(\"app\", \"test\").lower()}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": "=", + "value": "\"{}-{}\".format(\"app\", \"test\").lower()", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "s1": [ + { + "name": "s1", + "type_name": "", + "op_sym": "=", + "value": "\"Hello\"", + "list_items": [], + "dict_entries": [] + } + ], + "select": [ + { + "name": "select", + "type_name": "a.b.c", + "op_sym": "=", + "value": "a.b.c {a: 1}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "1", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "sha": [ + { + "name": "sha", + "type_name": "A", + "op_sym": "=", + "value": "A {\n name: \"Hello\"\n ids: [1, 2, 3]\n data: {\n \"a\": {\n \"b\": {\"c\": 2}\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": ":", + "value": "\"Hello\"", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "ids", + "value": { + "name": "ids", + "type_name": "", + "op_sym": ":", + "value": "[1, 2, 3]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "1", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "2", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "3", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + }, + { + "key": "data", + "value": { + "name": "data", + "type_name": "", + "op_sym": ":", + "value": "{\n \"a\": {\n \"b\": {\"c\": 2}\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{\n \"b\": {\"c\": 2}\n}", + "list_items": [], + "dict_entries": [ + { + "key": "b", + "value": { + "name": "b", + "type_name": "", + "op_sym": ":", + "value": "{\"c\": 2}", + "list_items": [], + "dict_entries": [ + { + "key": "c", + "value": { + "name": "c", + "type_name": "", + "op_sym": ":", + "value": "2", + "list_items": [], + "dict_entries": [] + } + } + ] + } + } + ] + } + } + ] + } + } + ] + } + ], + "shb": [ + { + "name": "shb", + "type_name": "B", + "op_sym": "=", + "value": "B {\n a: {\n name: \"HelloB\"\n ids: [4, 5, 6]\n data: {\n \"d\": {\n \"e\": {\"f\": 3}\n }\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{\n name: \"HelloB\"\n ids: [4, 5, 6]\n data: {\n \"d\": {\n \"e\": {\"f\": 3}\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": ":", + "value": "\"HelloB\"", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "ids", + "value": { + "name": "ids", + "type_name": "", + "op_sym": ":", + "value": "[4, 5, 6]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "4", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "5", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "6", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + }, + { + "key": "data", + "value": { + "name": "data", + "type_name": "", + "op_sym": ":", + "value": "{\n \"d\": {\n \"e\": {\"f\": 3}\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "d", + "value": { + "name": "d", + "type_name": "", + "op_sym": ":", + "value": "{\n \"e\": {\"f\": 3}\n}", + "list_items": [], + "dict_entries": [ + { + "key": "e", + "value": { + "name": "e", + "type_name": "", + "op_sym": ":", + "value": "{\"f\": 3}", + "list_items": [], + "dict_entries": [ + { + "key": "f", + "value": { + "name": "f", + "type_name": "", + "op_sym": ":", + "value": "3", + "list_items": [], + "dict_entries": [] + } + } + ] + } + } + ] + } + } + ] + } + } + ] + } + } + ] + } + ], + "uconfa": [ + { + "name": "uconfa", + "type_name": "UnificationConf", + "op_sym": ":", + "value": "UnificationConf {name = \"b\"}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": "=", + "value": "\"b\"", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "union_list": [ + { + "name": "union_list", + "type_name": "", + "op_sym": "=", + "value": "[*_list0, *_list1]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "*_list0", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "*_list1", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + ] +} \ No newline at end of file diff --git a/kclvm/query/src/test_data/test_list_variables/test_list_all_variables/b1.json b/kclvm/query/src/test_data/test_list_variables/test_list_all_variables/b1.json new file mode 100644 index 000000000..ce82e99a9 --- /dev/null +++ b/kclvm/query/src/test_data/test_list_variables/test_list_all_variables/b1.json @@ -0,0 +1,730 @@ +{ + "_list0": [ + { + "name": "_list0", + "type_name": "", + "op_sym": "=", + "value": "[1, 2, 3]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "1", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "2", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "3", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + ], + "_list1": [ + { + "name": "_list1", + "type_name": "", + "op_sym": "=", + "value": "[4, 5, 6]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "4", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "5", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "6", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + ], + "_part1": [ + { + "name": "_part1", + "type_name": "", + "op_sym": "=", + "value": "{a = \"b\"}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": "=", + "value": "\"b\"", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "_part2": [ + { + "name": "_part2", + "type_name": "", + "op_sym": "=", + "value": "{c = \"d\"}", + "list_items": [], + "dict_entries": [ + { + "key": "c", + "value": { + "name": "c", + "type_name": "", + "op_sym": "=", + "value": "\"d\"", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "a": [ + { + "name": "a", + "type_name": "", + "op_sym": "=", + "value": "1", + "list_items": [], + "dict_entries": [] + } + ], + "a1": [ + { + "name": "a1", + "type_name": "", + "op_sym": "=", + "value": "2", + "list_items": [], + "dict_entries": [] + } + ], + "a3": [ + { + "name": "a3", + "type_name": "", + "op_sym": "=", + "value": "3m", + "list_items": [], + "dict_entries": [] + } + ], + "a_dict": [ + { + "name": "a_dict", + "type_name": "", + "op_sym": "=", + "value": "{**_part1, **_part2}", + "list_items": [], + "dict_entries": [ + { + "key": "", + "value": { + "name": "", + "type_name": "", + "op_sym": ":", + "value": "_part1", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "", + "value": { + "name": "", + "type_name": "", + "op_sym": ":", + "value": "_part2", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "array1": [ + { + "name": "array1", + "type_name": "", + "op_sym": "=", + "value": "[1, 2, 3]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "1", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "2", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "3", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + ], + "b1": [ + { + "name": "b1", + "type_name": "", + "op_sym": "=", + "value": "True", + "list_items": [], + "dict_entries": [] + } + ], + "b2": [ + { + "name": "b2", + "type_name": "", + "op_sym": "=", + "value": "False", + "list_items": [], + "dict_entries": [] + } + ], + "c": [ + { + "name": "c", + "type_name": "C", + "op_sym": "=", + "value": "C {\n a: {name: \"Hello\"}\n a: {ids: [7, 8, 9]}\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{name: \"Hello\"}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": ":", + "value": "\"Hello\"", + "list_items": [], + "dict_entries": [] + } + } + ] + } + }, + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{ids: [7, 8, 9]}", + "list_items": [], + "dict_entries": [ + { + "key": "ids", + "value": { + "name": "ids", + "type_name": "", + "op_sym": ":", + "value": "[7, 8, 9]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "7", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "8", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "9", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + } + ] + } + } + ] + } + ], + "dict1": [ + { + "name": "dict1", + "type_name": "", + "op_sym": "=", + "value": "{\"a\": 1, \"b\": 2}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "1", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "b", + "value": { + "name": "b", + "type_name": "", + "op_sym": ":", + "value": "2", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "dict2": [ + { + "name": "dict2", + "type_name": "", + "op_sym": "=", + "value": "{\n \"a\": 1\n \"b\": {\n \"c\": 2\n \"d\": 3\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "1", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "b", + "value": { + "name": "b", + "type_name": "", + "op_sym": ":", + "value": "{\n \"c\": 2\n \"d\": 3\n}", + "list_items": [], + "dict_entries": [ + { + "key": "c", + "value": { + "name": "c", + "type_name": "", + "op_sym": ":", + "value": "2", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "d", + "value": { + "name": "d", + "type_name": "", + "op_sym": ":", + "value": "3", + "list_items": [], + "dict_entries": [] + } + } + ] + } + } + ] + } + ], + "job": [ + { + "name": "job", + "type_name": "Job", + "op_sym": "=", + "value": "Job {name = \"{}-{}\".format(\"app\", \"test\").lower()}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": "=", + "value": "\"{}-{}\".format(\"app\", \"test\").lower()", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "s1": [ + { + "name": "s1", + "type_name": "", + "op_sym": "=", + "value": "\"Hello\"", + "list_items": [], + "dict_entries": [] + } + ], + "select": [ + { + "name": "select", + "type_name": "a.b.c", + "op_sym": "=", + "value": "a.b.c {a: 1}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "1", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "sha": [ + { + "name": "sha", + "type_name": "A", + "op_sym": "=", + "value": "A {\n name: \"Hello\"\n ids: [1, 2, 3]\n data: {\n \"a\": {\n \"b\": {\"c\": 2}\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": ":", + "value": "\"Hello\"", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "ids", + "value": { + "name": "ids", + "type_name": "", + "op_sym": ":", + "value": "[1, 2, 3]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "1", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "2", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "3", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + }, + { + "key": "data", + "value": { + "name": "data", + "type_name": "", + "op_sym": ":", + "value": "{\n \"a\": {\n \"b\": {\"c\": 2}\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{\n \"b\": {\"c\": 2}\n}", + "list_items": [], + "dict_entries": [ + { + "key": "b", + "value": { + "name": "b", + "type_name": "", + "op_sym": ":", + "value": "{\"c\": 2}", + "list_items": [], + "dict_entries": [ + { + "key": "c", + "value": { + "name": "c", + "type_name": "", + "op_sym": ":", + "value": "2", + "list_items": [], + "dict_entries": [] + } + } + ] + } + } + ] + } + } + ] + } + } + ] + } + ], + "shb": [ + { + "name": "shb", + "type_name": "B", + "op_sym": "=", + "value": "B {\n a: {\n name: \"HelloB\"\n ids: [4, 5, 6]\n data: {\n \"d\": {\n \"e\": {\"f\": 3}\n }\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{\n name: \"HelloB\"\n ids: [4, 5, 6]\n data: {\n \"d\": {\n \"e\": {\"f\": 3}\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": ":", + "value": "\"HelloB\"", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "ids", + "value": { + "name": "ids", + "type_name": "", + "op_sym": ":", + "value": "[4, 5, 6]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "4", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "5", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "6", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + }, + { + "key": "data", + "value": { + "name": "data", + "type_name": "", + "op_sym": ":", + "value": "{\n \"d\": {\n \"e\": {\"f\": 3}\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "d", + "value": { + "name": "d", + "type_name": "", + "op_sym": ":", + "value": "{\n \"e\": {\"f\": 3}\n}", + "list_items": [], + "dict_entries": [ + { + "key": "e", + "value": { + "name": "e", + "type_name": "", + "op_sym": ":", + "value": "{\"f\": 3}", + "list_items": [], + "dict_entries": [ + { + "key": "f", + "value": { + "name": "f", + "type_name": "", + "op_sym": ":", + "value": "3", + "list_items": [], + "dict_entries": [] + } + } + ] + } + } + ] + } + } + ] + } + } + ] + } + } + ] + } + ], + "uconfa": [ + { + "name": "uconfa", + "type_name": "UnificationConf", + "op_sym": ":", + "value": "UnificationConf {name = \"b\"}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": "=", + "value": "\"b\"", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "union_list": [ + { + "name": "union_list", + "type_name": "", + "op_sym": "=", + "value": "[*_list0, *_list1]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "*_list0", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "*_list1", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + ] +} \ No newline at end of file diff --git a/kclvm/query/src/test_data/test_list_variables/test_list_all_variables/b2.json b/kclvm/query/src/test_data/test_list_variables/test_list_all_variables/b2.json new file mode 100644 index 000000000..ce82e99a9 --- /dev/null +++ b/kclvm/query/src/test_data/test_list_variables/test_list_all_variables/b2.json @@ -0,0 +1,730 @@ +{ + "_list0": [ + { + "name": "_list0", + "type_name": "", + "op_sym": "=", + "value": "[1, 2, 3]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "1", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "2", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "3", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + ], + "_list1": [ + { + "name": "_list1", + "type_name": "", + "op_sym": "=", + "value": "[4, 5, 6]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "4", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "5", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "6", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + ], + "_part1": [ + { + "name": "_part1", + "type_name": "", + "op_sym": "=", + "value": "{a = \"b\"}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": "=", + "value": "\"b\"", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "_part2": [ + { + "name": "_part2", + "type_name": "", + "op_sym": "=", + "value": "{c = \"d\"}", + "list_items": [], + "dict_entries": [ + { + "key": "c", + "value": { + "name": "c", + "type_name": "", + "op_sym": "=", + "value": "\"d\"", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "a": [ + { + "name": "a", + "type_name": "", + "op_sym": "=", + "value": "1", + "list_items": [], + "dict_entries": [] + } + ], + "a1": [ + { + "name": "a1", + "type_name": "", + "op_sym": "=", + "value": "2", + "list_items": [], + "dict_entries": [] + } + ], + "a3": [ + { + "name": "a3", + "type_name": "", + "op_sym": "=", + "value": "3m", + "list_items": [], + "dict_entries": [] + } + ], + "a_dict": [ + { + "name": "a_dict", + "type_name": "", + "op_sym": "=", + "value": "{**_part1, **_part2}", + "list_items": [], + "dict_entries": [ + { + "key": "", + "value": { + "name": "", + "type_name": "", + "op_sym": ":", + "value": "_part1", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "", + "value": { + "name": "", + "type_name": "", + "op_sym": ":", + "value": "_part2", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "array1": [ + { + "name": "array1", + "type_name": "", + "op_sym": "=", + "value": "[1, 2, 3]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "1", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "2", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "3", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + ], + "b1": [ + { + "name": "b1", + "type_name": "", + "op_sym": "=", + "value": "True", + "list_items": [], + "dict_entries": [] + } + ], + "b2": [ + { + "name": "b2", + "type_name": "", + "op_sym": "=", + "value": "False", + "list_items": [], + "dict_entries": [] + } + ], + "c": [ + { + "name": "c", + "type_name": "C", + "op_sym": "=", + "value": "C {\n a: {name: \"Hello\"}\n a: {ids: [7, 8, 9]}\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{name: \"Hello\"}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": ":", + "value": "\"Hello\"", + "list_items": [], + "dict_entries": [] + } + } + ] + } + }, + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{ids: [7, 8, 9]}", + "list_items": [], + "dict_entries": [ + { + "key": "ids", + "value": { + "name": "ids", + "type_name": "", + "op_sym": ":", + "value": "[7, 8, 9]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "7", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "8", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "9", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + } + ] + } + } + ] + } + ], + "dict1": [ + { + "name": "dict1", + "type_name": "", + "op_sym": "=", + "value": "{\"a\": 1, \"b\": 2}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "1", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "b", + "value": { + "name": "b", + "type_name": "", + "op_sym": ":", + "value": "2", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "dict2": [ + { + "name": "dict2", + "type_name": "", + "op_sym": "=", + "value": "{\n \"a\": 1\n \"b\": {\n \"c\": 2\n \"d\": 3\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "1", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "b", + "value": { + "name": "b", + "type_name": "", + "op_sym": ":", + "value": "{\n \"c\": 2\n \"d\": 3\n}", + "list_items": [], + "dict_entries": [ + { + "key": "c", + "value": { + "name": "c", + "type_name": "", + "op_sym": ":", + "value": "2", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "d", + "value": { + "name": "d", + "type_name": "", + "op_sym": ":", + "value": "3", + "list_items": [], + "dict_entries": [] + } + } + ] + } + } + ] + } + ], + "job": [ + { + "name": "job", + "type_name": "Job", + "op_sym": "=", + "value": "Job {name = \"{}-{}\".format(\"app\", \"test\").lower()}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": "=", + "value": "\"{}-{}\".format(\"app\", \"test\").lower()", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "s1": [ + { + "name": "s1", + "type_name": "", + "op_sym": "=", + "value": "\"Hello\"", + "list_items": [], + "dict_entries": [] + } + ], + "select": [ + { + "name": "select", + "type_name": "a.b.c", + "op_sym": "=", + "value": "a.b.c {a: 1}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "1", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "sha": [ + { + "name": "sha", + "type_name": "A", + "op_sym": "=", + "value": "A {\n name: \"Hello\"\n ids: [1, 2, 3]\n data: {\n \"a\": {\n \"b\": {\"c\": 2}\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": ":", + "value": "\"Hello\"", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "ids", + "value": { + "name": "ids", + "type_name": "", + "op_sym": ":", + "value": "[1, 2, 3]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "1", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "2", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "3", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + }, + { + "key": "data", + "value": { + "name": "data", + "type_name": "", + "op_sym": ":", + "value": "{\n \"a\": {\n \"b\": {\"c\": 2}\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{\n \"b\": {\"c\": 2}\n}", + "list_items": [], + "dict_entries": [ + { + "key": "b", + "value": { + "name": "b", + "type_name": "", + "op_sym": ":", + "value": "{\"c\": 2}", + "list_items": [], + "dict_entries": [ + { + "key": "c", + "value": { + "name": "c", + "type_name": "", + "op_sym": ":", + "value": "2", + "list_items": [], + "dict_entries": [] + } + } + ] + } + } + ] + } + } + ] + } + } + ] + } + ], + "shb": [ + { + "name": "shb", + "type_name": "B", + "op_sym": "=", + "value": "B {\n a: {\n name: \"HelloB\"\n ids: [4, 5, 6]\n data: {\n \"d\": {\n \"e\": {\"f\": 3}\n }\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{\n name: \"HelloB\"\n ids: [4, 5, 6]\n data: {\n \"d\": {\n \"e\": {\"f\": 3}\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": ":", + "value": "\"HelloB\"", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "ids", + "value": { + "name": "ids", + "type_name": "", + "op_sym": ":", + "value": "[4, 5, 6]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "4", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "5", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "6", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + }, + { + "key": "data", + "value": { + "name": "data", + "type_name": "", + "op_sym": ":", + "value": "{\n \"d\": {\n \"e\": {\"f\": 3}\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "d", + "value": { + "name": "d", + "type_name": "", + "op_sym": ":", + "value": "{\n \"e\": {\"f\": 3}\n}", + "list_items": [], + "dict_entries": [ + { + "key": "e", + "value": { + "name": "e", + "type_name": "", + "op_sym": ":", + "value": "{\"f\": 3}", + "list_items": [], + "dict_entries": [ + { + "key": "f", + "value": { + "name": "f", + "type_name": "", + "op_sym": ":", + "value": "3", + "list_items": [], + "dict_entries": [] + } + } + ] + } + } + ] + } + } + ] + } + } + ] + } + } + ] + } + ], + "uconfa": [ + { + "name": "uconfa", + "type_name": "UnificationConf", + "op_sym": ":", + "value": "UnificationConf {name = \"b\"}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": "=", + "value": "\"b\"", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "union_list": [ + { + "name": "union_list", + "type_name": "", + "op_sym": "=", + "value": "[*_list0, *_list1]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "*_list0", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "*_list1", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + ] +} \ No newline at end of file diff --git a/kclvm/query/src/test_data/test_list_variables/test_list_all_variables/dict1.json b/kclvm/query/src/test_data/test_list_variables/test_list_all_variables/dict1.json new file mode 100644 index 000000000..ce82e99a9 --- /dev/null +++ b/kclvm/query/src/test_data/test_list_variables/test_list_all_variables/dict1.json @@ -0,0 +1,730 @@ +{ + "_list0": [ + { + "name": "_list0", + "type_name": "", + "op_sym": "=", + "value": "[1, 2, 3]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "1", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "2", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "3", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + ], + "_list1": [ + { + "name": "_list1", + "type_name": "", + "op_sym": "=", + "value": "[4, 5, 6]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "4", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "5", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "6", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + ], + "_part1": [ + { + "name": "_part1", + "type_name": "", + "op_sym": "=", + "value": "{a = \"b\"}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": "=", + "value": "\"b\"", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "_part2": [ + { + "name": "_part2", + "type_name": "", + "op_sym": "=", + "value": "{c = \"d\"}", + "list_items": [], + "dict_entries": [ + { + "key": "c", + "value": { + "name": "c", + "type_name": "", + "op_sym": "=", + "value": "\"d\"", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "a": [ + { + "name": "a", + "type_name": "", + "op_sym": "=", + "value": "1", + "list_items": [], + "dict_entries": [] + } + ], + "a1": [ + { + "name": "a1", + "type_name": "", + "op_sym": "=", + "value": "2", + "list_items": [], + "dict_entries": [] + } + ], + "a3": [ + { + "name": "a3", + "type_name": "", + "op_sym": "=", + "value": "3m", + "list_items": [], + "dict_entries": [] + } + ], + "a_dict": [ + { + "name": "a_dict", + "type_name": "", + "op_sym": "=", + "value": "{**_part1, **_part2}", + "list_items": [], + "dict_entries": [ + { + "key": "", + "value": { + "name": "", + "type_name": "", + "op_sym": ":", + "value": "_part1", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "", + "value": { + "name": "", + "type_name": "", + "op_sym": ":", + "value": "_part2", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "array1": [ + { + "name": "array1", + "type_name": "", + "op_sym": "=", + "value": "[1, 2, 3]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "1", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "2", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "3", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + ], + "b1": [ + { + "name": "b1", + "type_name": "", + "op_sym": "=", + "value": "True", + "list_items": [], + "dict_entries": [] + } + ], + "b2": [ + { + "name": "b2", + "type_name": "", + "op_sym": "=", + "value": "False", + "list_items": [], + "dict_entries": [] + } + ], + "c": [ + { + "name": "c", + "type_name": "C", + "op_sym": "=", + "value": "C {\n a: {name: \"Hello\"}\n a: {ids: [7, 8, 9]}\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{name: \"Hello\"}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": ":", + "value": "\"Hello\"", + "list_items": [], + "dict_entries": [] + } + } + ] + } + }, + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{ids: [7, 8, 9]}", + "list_items": [], + "dict_entries": [ + { + "key": "ids", + "value": { + "name": "ids", + "type_name": "", + "op_sym": ":", + "value": "[7, 8, 9]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "7", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "8", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "9", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + } + ] + } + } + ] + } + ], + "dict1": [ + { + "name": "dict1", + "type_name": "", + "op_sym": "=", + "value": "{\"a\": 1, \"b\": 2}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "1", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "b", + "value": { + "name": "b", + "type_name": "", + "op_sym": ":", + "value": "2", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "dict2": [ + { + "name": "dict2", + "type_name": "", + "op_sym": "=", + "value": "{\n \"a\": 1\n \"b\": {\n \"c\": 2\n \"d\": 3\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "1", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "b", + "value": { + "name": "b", + "type_name": "", + "op_sym": ":", + "value": "{\n \"c\": 2\n \"d\": 3\n}", + "list_items": [], + "dict_entries": [ + { + "key": "c", + "value": { + "name": "c", + "type_name": "", + "op_sym": ":", + "value": "2", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "d", + "value": { + "name": "d", + "type_name": "", + "op_sym": ":", + "value": "3", + "list_items": [], + "dict_entries": [] + } + } + ] + } + } + ] + } + ], + "job": [ + { + "name": "job", + "type_name": "Job", + "op_sym": "=", + "value": "Job {name = \"{}-{}\".format(\"app\", \"test\").lower()}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": "=", + "value": "\"{}-{}\".format(\"app\", \"test\").lower()", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "s1": [ + { + "name": "s1", + "type_name": "", + "op_sym": "=", + "value": "\"Hello\"", + "list_items": [], + "dict_entries": [] + } + ], + "select": [ + { + "name": "select", + "type_name": "a.b.c", + "op_sym": "=", + "value": "a.b.c {a: 1}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "1", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "sha": [ + { + "name": "sha", + "type_name": "A", + "op_sym": "=", + "value": "A {\n name: \"Hello\"\n ids: [1, 2, 3]\n data: {\n \"a\": {\n \"b\": {\"c\": 2}\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": ":", + "value": "\"Hello\"", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "ids", + "value": { + "name": "ids", + "type_name": "", + "op_sym": ":", + "value": "[1, 2, 3]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "1", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "2", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "3", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + }, + { + "key": "data", + "value": { + "name": "data", + "type_name": "", + "op_sym": ":", + "value": "{\n \"a\": {\n \"b\": {\"c\": 2}\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{\n \"b\": {\"c\": 2}\n}", + "list_items": [], + "dict_entries": [ + { + "key": "b", + "value": { + "name": "b", + "type_name": "", + "op_sym": ":", + "value": "{\"c\": 2}", + "list_items": [], + "dict_entries": [ + { + "key": "c", + "value": { + "name": "c", + "type_name": "", + "op_sym": ":", + "value": "2", + "list_items": [], + "dict_entries": [] + } + } + ] + } + } + ] + } + } + ] + } + } + ] + } + ], + "shb": [ + { + "name": "shb", + "type_name": "B", + "op_sym": "=", + "value": "B {\n a: {\n name: \"HelloB\"\n ids: [4, 5, 6]\n data: {\n \"d\": {\n \"e\": {\"f\": 3}\n }\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{\n name: \"HelloB\"\n ids: [4, 5, 6]\n data: {\n \"d\": {\n \"e\": {\"f\": 3}\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": ":", + "value": "\"HelloB\"", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "ids", + "value": { + "name": "ids", + "type_name": "", + "op_sym": ":", + "value": "[4, 5, 6]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "4", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "5", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "6", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + }, + { + "key": "data", + "value": { + "name": "data", + "type_name": "", + "op_sym": ":", + "value": "{\n \"d\": {\n \"e\": {\"f\": 3}\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "d", + "value": { + "name": "d", + "type_name": "", + "op_sym": ":", + "value": "{\n \"e\": {\"f\": 3}\n}", + "list_items": [], + "dict_entries": [ + { + "key": "e", + "value": { + "name": "e", + "type_name": "", + "op_sym": ":", + "value": "{\"f\": 3}", + "list_items": [], + "dict_entries": [ + { + "key": "f", + "value": { + "name": "f", + "type_name": "", + "op_sym": ":", + "value": "3", + "list_items": [], + "dict_entries": [] + } + } + ] + } + } + ] + } + } + ] + } + } + ] + } + } + ] + } + ], + "uconfa": [ + { + "name": "uconfa", + "type_name": "UnificationConf", + "op_sym": ":", + "value": "UnificationConf {name = \"b\"}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": "=", + "value": "\"b\"", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "union_list": [ + { + "name": "union_list", + "type_name": "", + "op_sym": "=", + "value": "[*_list0, *_list1]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "*_list0", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "*_list1", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + ] +} \ No newline at end of file diff --git a/kclvm/query/src/test_data/test_list_variables/test_list_all_variables/dict2.json b/kclvm/query/src/test_data/test_list_variables/test_list_all_variables/dict2.json new file mode 100644 index 000000000..ce82e99a9 --- /dev/null +++ b/kclvm/query/src/test_data/test_list_variables/test_list_all_variables/dict2.json @@ -0,0 +1,730 @@ +{ + "_list0": [ + { + "name": "_list0", + "type_name": "", + "op_sym": "=", + "value": "[1, 2, 3]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "1", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "2", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "3", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + ], + "_list1": [ + { + "name": "_list1", + "type_name": "", + "op_sym": "=", + "value": "[4, 5, 6]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "4", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "5", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "6", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + ], + "_part1": [ + { + "name": "_part1", + "type_name": "", + "op_sym": "=", + "value": "{a = \"b\"}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": "=", + "value": "\"b\"", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "_part2": [ + { + "name": "_part2", + "type_name": "", + "op_sym": "=", + "value": "{c = \"d\"}", + "list_items": [], + "dict_entries": [ + { + "key": "c", + "value": { + "name": "c", + "type_name": "", + "op_sym": "=", + "value": "\"d\"", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "a": [ + { + "name": "a", + "type_name": "", + "op_sym": "=", + "value": "1", + "list_items": [], + "dict_entries": [] + } + ], + "a1": [ + { + "name": "a1", + "type_name": "", + "op_sym": "=", + "value": "2", + "list_items": [], + "dict_entries": [] + } + ], + "a3": [ + { + "name": "a3", + "type_name": "", + "op_sym": "=", + "value": "3m", + "list_items": [], + "dict_entries": [] + } + ], + "a_dict": [ + { + "name": "a_dict", + "type_name": "", + "op_sym": "=", + "value": "{**_part1, **_part2}", + "list_items": [], + "dict_entries": [ + { + "key": "", + "value": { + "name": "", + "type_name": "", + "op_sym": ":", + "value": "_part1", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "", + "value": { + "name": "", + "type_name": "", + "op_sym": ":", + "value": "_part2", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "array1": [ + { + "name": "array1", + "type_name": "", + "op_sym": "=", + "value": "[1, 2, 3]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "1", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "2", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "3", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + ], + "b1": [ + { + "name": "b1", + "type_name": "", + "op_sym": "=", + "value": "True", + "list_items": [], + "dict_entries": [] + } + ], + "b2": [ + { + "name": "b2", + "type_name": "", + "op_sym": "=", + "value": "False", + "list_items": [], + "dict_entries": [] + } + ], + "c": [ + { + "name": "c", + "type_name": "C", + "op_sym": "=", + "value": "C {\n a: {name: \"Hello\"}\n a: {ids: [7, 8, 9]}\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{name: \"Hello\"}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": ":", + "value": "\"Hello\"", + "list_items": [], + "dict_entries": [] + } + } + ] + } + }, + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{ids: [7, 8, 9]}", + "list_items": [], + "dict_entries": [ + { + "key": "ids", + "value": { + "name": "ids", + "type_name": "", + "op_sym": ":", + "value": "[7, 8, 9]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "7", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "8", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "9", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + } + ] + } + } + ] + } + ], + "dict1": [ + { + "name": "dict1", + "type_name": "", + "op_sym": "=", + "value": "{\"a\": 1, \"b\": 2}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "1", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "b", + "value": { + "name": "b", + "type_name": "", + "op_sym": ":", + "value": "2", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "dict2": [ + { + "name": "dict2", + "type_name": "", + "op_sym": "=", + "value": "{\n \"a\": 1\n \"b\": {\n \"c\": 2\n \"d\": 3\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "1", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "b", + "value": { + "name": "b", + "type_name": "", + "op_sym": ":", + "value": "{\n \"c\": 2\n \"d\": 3\n}", + "list_items": [], + "dict_entries": [ + { + "key": "c", + "value": { + "name": "c", + "type_name": "", + "op_sym": ":", + "value": "2", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "d", + "value": { + "name": "d", + "type_name": "", + "op_sym": ":", + "value": "3", + "list_items": [], + "dict_entries": [] + } + } + ] + } + } + ] + } + ], + "job": [ + { + "name": "job", + "type_name": "Job", + "op_sym": "=", + "value": "Job {name = \"{}-{}\".format(\"app\", \"test\").lower()}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": "=", + "value": "\"{}-{}\".format(\"app\", \"test\").lower()", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "s1": [ + { + "name": "s1", + "type_name": "", + "op_sym": "=", + "value": "\"Hello\"", + "list_items": [], + "dict_entries": [] + } + ], + "select": [ + { + "name": "select", + "type_name": "a.b.c", + "op_sym": "=", + "value": "a.b.c {a: 1}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "1", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "sha": [ + { + "name": "sha", + "type_name": "A", + "op_sym": "=", + "value": "A {\n name: \"Hello\"\n ids: [1, 2, 3]\n data: {\n \"a\": {\n \"b\": {\"c\": 2}\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": ":", + "value": "\"Hello\"", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "ids", + "value": { + "name": "ids", + "type_name": "", + "op_sym": ":", + "value": "[1, 2, 3]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "1", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "2", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "3", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + }, + { + "key": "data", + "value": { + "name": "data", + "type_name": "", + "op_sym": ":", + "value": "{\n \"a\": {\n \"b\": {\"c\": 2}\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{\n \"b\": {\"c\": 2}\n}", + "list_items": [], + "dict_entries": [ + { + "key": "b", + "value": { + "name": "b", + "type_name": "", + "op_sym": ":", + "value": "{\"c\": 2}", + "list_items": [], + "dict_entries": [ + { + "key": "c", + "value": { + "name": "c", + "type_name": "", + "op_sym": ":", + "value": "2", + "list_items": [], + "dict_entries": [] + } + } + ] + } + } + ] + } + } + ] + } + } + ] + } + ], + "shb": [ + { + "name": "shb", + "type_name": "B", + "op_sym": "=", + "value": "B {\n a: {\n name: \"HelloB\"\n ids: [4, 5, 6]\n data: {\n \"d\": {\n \"e\": {\"f\": 3}\n }\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{\n name: \"HelloB\"\n ids: [4, 5, 6]\n data: {\n \"d\": {\n \"e\": {\"f\": 3}\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": ":", + "value": "\"HelloB\"", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "ids", + "value": { + "name": "ids", + "type_name": "", + "op_sym": ":", + "value": "[4, 5, 6]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "4", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "5", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "6", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + }, + { + "key": "data", + "value": { + "name": "data", + "type_name": "", + "op_sym": ":", + "value": "{\n \"d\": {\n \"e\": {\"f\": 3}\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "d", + "value": { + "name": "d", + "type_name": "", + "op_sym": ":", + "value": "{\n \"e\": {\"f\": 3}\n}", + "list_items": [], + "dict_entries": [ + { + "key": "e", + "value": { + "name": "e", + "type_name": "", + "op_sym": ":", + "value": "{\"f\": 3}", + "list_items": [], + "dict_entries": [ + { + "key": "f", + "value": { + "name": "f", + "type_name": "", + "op_sym": ":", + "value": "3", + "list_items": [], + "dict_entries": [] + } + } + ] + } + } + ] + } + } + ] + } + } + ] + } + } + ] + } + ], + "uconfa": [ + { + "name": "uconfa", + "type_name": "UnificationConf", + "op_sym": ":", + "value": "UnificationConf {name = \"b\"}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": "=", + "value": "\"b\"", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "union_list": [ + { + "name": "union_list", + "type_name": "", + "op_sym": "=", + "value": "[*_list0, *_list1]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "*_list0", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "*_list1", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + ] +} \ No newline at end of file diff --git a/kclvm/query/src/test_data/test_list_variables/test_list_all_variables/job.json b/kclvm/query/src/test_data/test_list_variables/test_list_all_variables/job.json new file mode 100644 index 000000000..ce82e99a9 --- /dev/null +++ b/kclvm/query/src/test_data/test_list_variables/test_list_all_variables/job.json @@ -0,0 +1,730 @@ +{ + "_list0": [ + { + "name": "_list0", + "type_name": "", + "op_sym": "=", + "value": "[1, 2, 3]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "1", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "2", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "3", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + ], + "_list1": [ + { + "name": "_list1", + "type_name": "", + "op_sym": "=", + "value": "[4, 5, 6]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "4", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "5", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "6", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + ], + "_part1": [ + { + "name": "_part1", + "type_name": "", + "op_sym": "=", + "value": "{a = \"b\"}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": "=", + "value": "\"b\"", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "_part2": [ + { + "name": "_part2", + "type_name": "", + "op_sym": "=", + "value": "{c = \"d\"}", + "list_items": [], + "dict_entries": [ + { + "key": "c", + "value": { + "name": "c", + "type_name": "", + "op_sym": "=", + "value": "\"d\"", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "a": [ + { + "name": "a", + "type_name": "", + "op_sym": "=", + "value": "1", + "list_items": [], + "dict_entries": [] + } + ], + "a1": [ + { + "name": "a1", + "type_name": "", + "op_sym": "=", + "value": "2", + "list_items": [], + "dict_entries": [] + } + ], + "a3": [ + { + "name": "a3", + "type_name": "", + "op_sym": "=", + "value": "3m", + "list_items": [], + "dict_entries": [] + } + ], + "a_dict": [ + { + "name": "a_dict", + "type_name": "", + "op_sym": "=", + "value": "{**_part1, **_part2}", + "list_items": [], + "dict_entries": [ + { + "key": "", + "value": { + "name": "", + "type_name": "", + "op_sym": ":", + "value": "_part1", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "", + "value": { + "name": "", + "type_name": "", + "op_sym": ":", + "value": "_part2", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "array1": [ + { + "name": "array1", + "type_name": "", + "op_sym": "=", + "value": "[1, 2, 3]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "1", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "2", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "3", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + ], + "b1": [ + { + "name": "b1", + "type_name": "", + "op_sym": "=", + "value": "True", + "list_items": [], + "dict_entries": [] + } + ], + "b2": [ + { + "name": "b2", + "type_name": "", + "op_sym": "=", + "value": "False", + "list_items": [], + "dict_entries": [] + } + ], + "c": [ + { + "name": "c", + "type_name": "C", + "op_sym": "=", + "value": "C {\n a: {name: \"Hello\"}\n a: {ids: [7, 8, 9]}\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{name: \"Hello\"}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": ":", + "value": "\"Hello\"", + "list_items": [], + "dict_entries": [] + } + } + ] + } + }, + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{ids: [7, 8, 9]}", + "list_items": [], + "dict_entries": [ + { + "key": "ids", + "value": { + "name": "ids", + "type_name": "", + "op_sym": ":", + "value": "[7, 8, 9]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "7", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "8", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "9", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + } + ] + } + } + ] + } + ], + "dict1": [ + { + "name": "dict1", + "type_name": "", + "op_sym": "=", + "value": "{\"a\": 1, \"b\": 2}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "1", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "b", + "value": { + "name": "b", + "type_name": "", + "op_sym": ":", + "value": "2", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "dict2": [ + { + "name": "dict2", + "type_name": "", + "op_sym": "=", + "value": "{\n \"a\": 1\n \"b\": {\n \"c\": 2\n \"d\": 3\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "1", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "b", + "value": { + "name": "b", + "type_name": "", + "op_sym": ":", + "value": "{\n \"c\": 2\n \"d\": 3\n}", + "list_items": [], + "dict_entries": [ + { + "key": "c", + "value": { + "name": "c", + "type_name": "", + "op_sym": ":", + "value": "2", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "d", + "value": { + "name": "d", + "type_name": "", + "op_sym": ":", + "value": "3", + "list_items": [], + "dict_entries": [] + } + } + ] + } + } + ] + } + ], + "job": [ + { + "name": "job", + "type_name": "Job", + "op_sym": "=", + "value": "Job {name = \"{}-{}\".format(\"app\", \"test\").lower()}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": "=", + "value": "\"{}-{}\".format(\"app\", \"test\").lower()", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "s1": [ + { + "name": "s1", + "type_name": "", + "op_sym": "=", + "value": "\"Hello\"", + "list_items": [], + "dict_entries": [] + } + ], + "select": [ + { + "name": "select", + "type_name": "a.b.c", + "op_sym": "=", + "value": "a.b.c {a: 1}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "1", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "sha": [ + { + "name": "sha", + "type_name": "A", + "op_sym": "=", + "value": "A {\n name: \"Hello\"\n ids: [1, 2, 3]\n data: {\n \"a\": {\n \"b\": {\"c\": 2}\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": ":", + "value": "\"Hello\"", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "ids", + "value": { + "name": "ids", + "type_name": "", + "op_sym": ":", + "value": "[1, 2, 3]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "1", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "2", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "3", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + }, + { + "key": "data", + "value": { + "name": "data", + "type_name": "", + "op_sym": ":", + "value": "{\n \"a\": {\n \"b\": {\"c\": 2}\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{\n \"b\": {\"c\": 2}\n}", + "list_items": [], + "dict_entries": [ + { + "key": "b", + "value": { + "name": "b", + "type_name": "", + "op_sym": ":", + "value": "{\"c\": 2}", + "list_items": [], + "dict_entries": [ + { + "key": "c", + "value": { + "name": "c", + "type_name": "", + "op_sym": ":", + "value": "2", + "list_items": [], + "dict_entries": [] + } + } + ] + } + } + ] + } + } + ] + } + } + ] + } + ], + "shb": [ + { + "name": "shb", + "type_name": "B", + "op_sym": "=", + "value": "B {\n a: {\n name: \"HelloB\"\n ids: [4, 5, 6]\n data: {\n \"d\": {\n \"e\": {\"f\": 3}\n }\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{\n name: \"HelloB\"\n ids: [4, 5, 6]\n data: {\n \"d\": {\n \"e\": {\"f\": 3}\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": ":", + "value": "\"HelloB\"", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "ids", + "value": { + "name": "ids", + "type_name": "", + "op_sym": ":", + "value": "[4, 5, 6]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "4", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "5", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "6", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + }, + { + "key": "data", + "value": { + "name": "data", + "type_name": "", + "op_sym": ":", + "value": "{\n \"d\": {\n \"e\": {\"f\": 3}\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "d", + "value": { + "name": "d", + "type_name": "", + "op_sym": ":", + "value": "{\n \"e\": {\"f\": 3}\n}", + "list_items": [], + "dict_entries": [ + { + "key": "e", + "value": { + "name": "e", + "type_name": "", + "op_sym": ":", + "value": "{\"f\": 3}", + "list_items": [], + "dict_entries": [ + { + "key": "f", + "value": { + "name": "f", + "type_name": "", + "op_sym": ":", + "value": "3", + "list_items": [], + "dict_entries": [] + } + } + ] + } + } + ] + } + } + ] + } + } + ] + } + } + ] + } + ], + "uconfa": [ + { + "name": "uconfa", + "type_name": "UnificationConf", + "op_sym": ":", + "value": "UnificationConf {name = \"b\"}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": "=", + "value": "\"b\"", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "union_list": [ + { + "name": "union_list", + "type_name": "", + "op_sym": "=", + "value": "[*_list0, *_list1]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "*_list0", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "*_list1", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + ] +} \ No newline at end of file diff --git a/kclvm/query/src/test_data/test_list_variables/test_list_all_variables/s1.json b/kclvm/query/src/test_data/test_list_variables/test_list_all_variables/s1.json new file mode 100644 index 000000000..ce82e99a9 --- /dev/null +++ b/kclvm/query/src/test_data/test_list_variables/test_list_all_variables/s1.json @@ -0,0 +1,730 @@ +{ + "_list0": [ + { + "name": "_list0", + "type_name": "", + "op_sym": "=", + "value": "[1, 2, 3]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "1", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "2", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "3", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + ], + "_list1": [ + { + "name": "_list1", + "type_name": "", + "op_sym": "=", + "value": "[4, 5, 6]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "4", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "5", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "6", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + ], + "_part1": [ + { + "name": "_part1", + "type_name": "", + "op_sym": "=", + "value": "{a = \"b\"}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": "=", + "value": "\"b\"", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "_part2": [ + { + "name": "_part2", + "type_name": "", + "op_sym": "=", + "value": "{c = \"d\"}", + "list_items": [], + "dict_entries": [ + { + "key": "c", + "value": { + "name": "c", + "type_name": "", + "op_sym": "=", + "value": "\"d\"", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "a": [ + { + "name": "a", + "type_name": "", + "op_sym": "=", + "value": "1", + "list_items": [], + "dict_entries": [] + } + ], + "a1": [ + { + "name": "a1", + "type_name": "", + "op_sym": "=", + "value": "2", + "list_items": [], + "dict_entries": [] + } + ], + "a3": [ + { + "name": "a3", + "type_name": "", + "op_sym": "=", + "value": "3m", + "list_items": [], + "dict_entries": [] + } + ], + "a_dict": [ + { + "name": "a_dict", + "type_name": "", + "op_sym": "=", + "value": "{**_part1, **_part2}", + "list_items": [], + "dict_entries": [ + { + "key": "", + "value": { + "name": "", + "type_name": "", + "op_sym": ":", + "value": "_part1", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "", + "value": { + "name": "", + "type_name": "", + "op_sym": ":", + "value": "_part2", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "array1": [ + { + "name": "array1", + "type_name": "", + "op_sym": "=", + "value": "[1, 2, 3]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "1", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "2", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "3", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + ], + "b1": [ + { + "name": "b1", + "type_name": "", + "op_sym": "=", + "value": "True", + "list_items": [], + "dict_entries": [] + } + ], + "b2": [ + { + "name": "b2", + "type_name": "", + "op_sym": "=", + "value": "False", + "list_items": [], + "dict_entries": [] + } + ], + "c": [ + { + "name": "c", + "type_name": "C", + "op_sym": "=", + "value": "C {\n a: {name: \"Hello\"}\n a: {ids: [7, 8, 9]}\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{name: \"Hello\"}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": ":", + "value": "\"Hello\"", + "list_items": [], + "dict_entries": [] + } + } + ] + } + }, + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{ids: [7, 8, 9]}", + "list_items": [], + "dict_entries": [ + { + "key": "ids", + "value": { + "name": "ids", + "type_name": "", + "op_sym": ":", + "value": "[7, 8, 9]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "7", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "8", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "9", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + } + ] + } + } + ] + } + ], + "dict1": [ + { + "name": "dict1", + "type_name": "", + "op_sym": "=", + "value": "{\"a\": 1, \"b\": 2}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "1", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "b", + "value": { + "name": "b", + "type_name": "", + "op_sym": ":", + "value": "2", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "dict2": [ + { + "name": "dict2", + "type_name": "", + "op_sym": "=", + "value": "{\n \"a\": 1\n \"b\": {\n \"c\": 2\n \"d\": 3\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "1", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "b", + "value": { + "name": "b", + "type_name": "", + "op_sym": ":", + "value": "{\n \"c\": 2\n \"d\": 3\n}", + "list_items": [], + "dict_entries": [ + { + "key": "c", + "value": { + "name": "c", + "type_name": "", + "op_sym": ":", + "value": "2", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "d", + "value": { + "name": "d", + "type_name": "", + "op_sym": ":", + "value": "3", + "list_items": [], + "dict_entries": [] + } + } + ] + } + } + ] + } + ], + "job": [ + { + "name": "job", + "type_name": "Job", + "op_sym": "=", + "value": "Job {name = \"{}-{}\".format(\"app\", \"test\").lower()}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": "=", + "value": "\"{}-{}\".format(\"app\", \"test\").lower()", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "s1": [ + { + "name": "s1", + "type_name": "", + "op_sym": "=", + "value": "\"Hello\"", + "list_items": [], + "dict_entries": [] + } + ], + "select": [ + { + "name": "select", + "type_name": "a.b.c", + "op_sym": "=", + "value": "a.b.c {a: 1}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "1", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "sha": [ + { + "name": "sha", + "type_name": "A", + "op_sym": "=", + "value": "A {\n name: \"Hello\"\n ids: [1, 2, 3]\n data: {\n \"a\": {\n \"b\": {\"c\": 2}\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": ":", + "value": "\"Hello\"", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "ids", + "value": { + "name": "ids", + "type_name": "", + "op_sym": ":", + "value": "[1, 2, 3]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "1", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "2", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "3", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + }, + { + "key": "data", + "value": { + "name": "data", + "type_name": "", + "op_sym": ":", + "value": "{\n \"a\": {\n \"b\": {\"c\": 2}\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{\n \"b\": {\"c\": 2}\n}", + "list_items": [], + "dict_entries": [ + { + "key": "b", + "value": { + "name": "b", + "type_name": "", + "op_sym": ":", + "value": "{\"c\": 2}", + "list_items": [], + "dict_entries": [ + { + "key": "c", + "value": { + "name": "c", + "type_name": "", + "op_sym": ":", + "value": "2", + "list_items": [], + "dict_entries": [] + } + } + ] + } + } + ] + } + } + ] + } + } + ] + } + ], + "shb": [ + { + "name": "shb", + "type_name": "B", + "op_sym": "=", + "value": "B {\n a: {\n name: \"HelloB\"\n ids: [4, 5, 6]\n data: {\n \"d\": {\n \"e\": {\"f\": 3}\n }\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{\n name: \"HelloB\"\n ids: [4, 5, 6]\n data: {\n \"d\": {\n \"e\": {\"f\": 3}\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": ":", + "value": "\"HelloB\"", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "ids", + "value": { + "name": "ids", + "type_name": "", + "op_sym": ":", + "value": "[4, 5, 6]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "4", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "5", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "6", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + }, + { + "key": "data", + "value": { + "name": "data", + "type_name": "", + "op_sym": ":", + "value": "{\n \"d\": {\n \"e\": {\"f\": 3}\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "d", + "value": { + "name": "d", + "type_name": "", + "op_sym": ":", + "value": "{\n \"e\": {\"f\": 3}\n}", + "list_items": [], + "dict_entries": [ + { + "key": "e", + "value": { + "name": "e", + "type_name": "", + "op_sym": ":", + "value": "{\"f\": 3}", + "list_items": [], + "dict_entries": [ + { + "key": "f", + "value": { + "name": "f", + "type_name": "", + "op_sym": ":", + "value": "3", + "list_items": [], + "dict_entries": [] + } + } + ] + } + } + ] + } + } + ] + } + } + ] + } + } + ] + } + ], + "uconfa": [ + { + "name": "uconfa", + "type_name": "UnificationConf", + "op_sym": ":", + "value": "UnificationConf {name = \"b\"}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": "=", + "value": "\"b\"", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "union_list": [ + { + "name": "union_list", + "type_name": "", + "op_sym": "=", + "value": "[*_list0, *_list1]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "*_list0", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "*_list1", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + ] +} \ No newline at end of file diff --git a/kclvm/query/src/test_data/test_list_variables/test_list_all_variables/select.json b/kclvm/query/src/test_data/test_list_variables/test_list_all_variables/select.json new file mode 100644 index 000000000..ce82e99a9 --- /dev/null +++ b/kclvm/query/src/test_data/test_list_variables/test_list_all_variables/select.json @@ -0,0 +1,730 @@ +{ + "_list0": [ + { + "name": "_list0", + "type_name": "", + "op_sym": "=", + "value": "[1, 2, 3]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "1", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "2", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "3", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + ], + "_list1": [ + { + "name": "_list1", + "type_name": "", + "op_sym": "=", + "value": "[4, 5, 6]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "4", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "5", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "6", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + ], + "_part1": [ + { + "name": "_part1", + "type_name": "", + "op_sym": "=", + "value": "{a = \"b\"}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": "=", + "value": "\"b\"", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "_part2": [ + { + "name": "_part2", + "type_name": "", + "op_sym": "=", + "value": "{c = \"d\"}", + "list_items": [], + "dict_entries": [ + { + "key": "c", + "value": { + "name": "c", + "type_name": "", + "op_sym": "=", + "value": "\"d\"", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "a": [ + { + "name": "a", + "type_name": "", + "op_sym": "=", + "value": "1", + "list_items": [], + "dict_entries": [] + } + ], + "a1": [ + { + "name": "a1", + "type_name": "", + "op_sym": "=", + "value": "2", + "list_items": [], + "dict_entries": [] + } + ], + "a3": [ + { + "name": "a3", + "type_name": "", + "op_sym": "=", + "value": "3m", + "list_items": [], + "dict_entries": [] + } + ], + "a_dict": [ + { + "name": "a_dict", + "type_name": "", + "op_sym": "=", + "value": "{**_part1, **_part2}", + "list_items": [], + "dict_entries": [ + { + "key": "", + "value": { + "name": "", + "type_name": "", + "op_sym": ":", + "value": "_part1", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "", + "value": { + "name": "", + "type_name": "", + "op_sym": ":", + "value": "_part2", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "array1": [ + { + "name": "array1", + "type_name": "", + "op_sym": "=", + "value": "[1, 2, 3]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "1", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "2", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "3", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + ], + "b1": [ + { + "name": "b1", + "type_name": "", + "op_sym": "=", + "value": "True", + "list_items": [], + "dict_entries": [] + } + ], + "b2": [ + { + "name": "b2", + "type_name": "", + "op_sym": "=", + "value": "False", + "list_items": [], + "dict_entries": [] + } + ], + "c": [ + { + "name": "c", + "type_name": "C", + "op_sym": "=", + "value": "C {\n a: {name: \"Hello\"}\n a: {ids: [7, 8, 9]}\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{name: \"Hello\"}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": ":", + "value": "\"Hello\"", + "list_items": [], + "dict_entries": [] + } + } + ] + } + }, + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{ids: [7, 8, 9]}", + "list_items": [], + "dict_entries": [ + { + "key": "ids", + "value": { + "name": "ids", + "type_name": "", + "op_sym": ":", + "value": "[7, 8, 9]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "7", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "8", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "9", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + } + ] + } + } + ] + } + ], + "dict1": [ + { + "name": "dict1", + "type_name": "", + "op_sym": "=", + "value": "{\"a\": 1, \"b\": 2}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "1", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "b", + "value": { + "name": "b", + "type_name": "", + "op_sym": ":", + "value": "2", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "dict2": [ + { + "name": "dict2", + "type_name": "", + "op_sym": "=", + "value": "{\n \"a\": 1\n \"b\": {\n \"c\": 2\n \"d\": 3\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "1", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "b", + "value": { + "name": "b", + "type_name": "", + "op_sym": ":", + "value": "{\n \"c\": 2\n \"d\": 3\n}", + "list_items": [], + "dict_entries": [ + { + "key": "c", + "value": { + "name": "c", + "type_name": "", + "op_sym": ":", + "value": "2", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "d", + "value": { + "name": "d", + "type_name": "", + "op_sym": ":", + "value": "3", + "list_items": [], + "dict_entries": [] + } + } + ] + } + } + ] + } + ], + "job": [ + { + "name": "job", + "type_name": "Job", + "op_sym": "=", + "value": "Job {name = \"{}-{}\".format(\"app\", \"test\").lower()}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": "=", + "value": "\"{}-{}\".format(\"app\", \"test\").lower()", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "s1": [ + { + "name": "s1", + "type_name": "", + "op_sym": "=", + "value": "\"Hello\"", + "list_items": [], + "dict_entries": [] + } + ], + "select": [ + { + "name": "select", + "type_name": "a.b.c", + "op_sym": "=", + "value": "a.b.c {a: 1}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "1", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "sha": [ + { + "name": "sha", + "type_name": "A", + "op_sym": "=", + "value": "A {\n name: \"Hello\"\n ids: [1, 2, 3]\n data: {\n \"a\": {\n \"b\": {\"c\": 2}\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": ":", + "value": "\"Hello\"", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "ids", + "value": { + "name": "ids", + "type_name": "", + "op_sym": ":", + "value": "[1, 2, 3]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "1", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "2", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "3", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + }, + { + "key": "data", + "value": { + "name": "data", + "type_name": "", + "op_sym": ":", + "value": "{\n \"a\": {\n \"b\": {\"c\": 2}\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{\n \"b\": {\"c\": 2}\n}", + "list_items": [], + "dict_entries": [ + { + "key": "b", + "value": { + "name": "b", + "type_name": "", + "op_sym": ":", + "value": "{\"c\": 2}", + "list_items": [], + "dict_entries": [ + { + "key": "c", + "value": { + "name": "c", + "type_name": "", + "op_sym": ":", + "value": "2", + "list_items": [], + "dict_entries": [] + } + } + ] + } + } + ] + } + } + ] + } + } + ] + } + ], + "shb": [ + { + "name": "shb", + "type_name": "B", + "op_sym": "=", + "value": "B {\n a: {\n name: \"HelloB\"\n ids: [4, 5, 6]\n data: {\n \"d\": {\n \"e\": {\"f\": 3}\n }\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{\n name: \"HelloB\"\n ids: [4, 5, 6]\n data: {\n \"d\": {\n \"e\": {\"f\": 3}\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": ":", + "value": "\"HelloB\"", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "ids", + "value": { + "name": "ids", + "type_name": "", + "op_sym": ":", + "value": "[4, 5, 6]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "4", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "5", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "6", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + }, + { + "key": "data", + "value": { + "name": "data", + "type_name": "", + "op_sym": ":", + "value": "{\n \"d\": {\n \"e\": {\"f\": 3}\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "d", + "value": { + "name": "d", + "type_name": "", + "op_sym": ":", + "value": "{\n \"e\": {\"f\": 3}\n}", + "list_items": [], + "dict_entries": [ + { + "key": "e", + "value": { + "name": "e", + "type_name": "", + "op_sym": ":", + "value": "{\"f\": 3}", + "list_items": [], + "dict_entries": [ + { + "key": "f", + "value": { + "name": "f", + "type_name": "", + "op_sym": ":", + "value": "3", + "list_items": [], + "dict_entries": [] + } + } + ] + } + } + ] + } + } + ] + } + } + ] + } + } + ] + } + ], + "uconfa": [ + { + "name": "uconfa", + "type_name": "UnificationConf", + "op_sym": ":", + "value": "UnificationConf {name = \"b\"}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": "=", + "value": "\"b\"", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "union_list": [ + { + "name": "union_list", + "type_name": "", + "op_sym": "=", + "value": "[*_list0, *_list1]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "*_list0", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "*_list1", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + ] +} \ No newline at end of file diff --git a/kclvm/query/src/test_data/test_list_variables/test_list_all_variables/sha.json b/kclvm/query/src/test_data/test_list_variables/test_list_all_variables/sha.json new file mode 100644 index 000000000..ce82e99a9 --- /dev/null +++ b/kclvm/query/src/test_data/test_list_variables/test_list_all_variables/sha.json @@ -0,0 +1,730 @@ +{ + "_list0": [ + { + "name": "_list0", + "type_name": "", + "op_sym": "=", + "value": "[1, 2, 3]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "1", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "2", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "3", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + ], + "_list1": [ + { + "name": "_list1", + "type_name": "", + "op_sym": "=", + "value": "[4, 5, 6]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "4", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "5", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "6", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + ], + "_part1": [ + { + "name": "_part1", + "type_name": "", + "op_sym": "=", + "value": "{a = \"b\"}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": "=", + "value": "\"b\"", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "_part2": [ + { + "name": "_part2", + "type_name": "", + "op_sym": "=", + "value": "{c = \"d\"}", + "list_items": [], + "dict_entries": [ + { + "key": "c", + "value": { + "name": "c", + "type_name": "", + "op_sym": "=", + "value": "\"d\"", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "a": [ + { + "name": "a", + "type_name": "", + "op_sym": "=", + "value": "1", + "list_items": [], + "dict_entries": [] + } + ], + "a1": [ + { + "name": "a1", + "type_name": "", + "op_sym": "=", + "value": "2", + "list_items": [], + "dict_entries": [] + } + ], + "a3": [ + { + "name": "a3", + "type_name": "", + "op_sym": "=", + "value": "3m", + "list_items": [], + "dict_entries": [] + } + ], + "a_dict": [ + { + "name": "a_dict", + "type_name": "", + "op_sym": "=", + "value": "{**_part1, **_part2}", + "list_items": [], + "dict_entries": [ + { + "key": "", + "value": { + "name": "", + "type_name": "", + "op_sym": ":", + "value": "_part1", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "", + "value": { + "name": "", + "type_name": "", + "op_sym": ":", + "value": "_part2", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "array1": [ + { + "name": "array1", + "type_name": "", + "op_sym": "=", + "value": "[1, 2, 3]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "1", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "2", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "3", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + ], + "b1": [ + { + "name": "b1", + "type_name": "", + "op_sym": "=", + "value": "True", + "list_items": [], + "dict_entries": [] + } + ], + "b2": [ + { + "name": "b2", + "type_name": "", + "op_sym": "=", + "value": "False", + "list_items": [], + "dict_entries": [] + } + ], + "c": [ + { + "name": "c", + "type_name": "C", + "op_sym": "=", + "value": "C {\n a: {name: \"Hello\"}\n a: {ids: [7, 8, 9]}\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{name: \"Hello\"}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": ":", + "value": "\"Hello\"", + "list_items": [], + "dict_entries": [] + } + } + ] + } + }, + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{ids: [7, 8, 9]}", + "list_items": [], + "dict_entries": [ + { + "key": "ids", + "value": { + "name": "ids", + "type_name": "", + "op_sym": ":", + "value": "[7, 8, 9]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "7", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "8", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "9", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + } + ] + } + } + ] + } + ], + "dict1": [ + { + "name": "dict1", + "type_name": "", + "op_sym": "=", + "value": "{\"a\": 1, \"b\": 2}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "1", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "b", + "value": { + "name": "b", + "type_name": "", + "op_sym": ":", + "value": "2", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "dict2": [ + { + "name": "dict2", + "type_name": "", + "op_sym": "=", + "value": "{\n \"a\": 1\n \"b\": {\n \"c\": 2\n \"d\": 3\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "1", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "b", + "value": { + "name": "b", + "type_name": "", + "op_sym": ":", + "value": "{\n \"c\": 2\n \"d\": 3\n}", + "list_items": [], + "dict_entries": [ + { + "key": "c", + "value": { + "name": "c", + "type_name": "", + "op_sym": ":", + "value": "2", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "d", + "value": { + "name": "d", + "type_name": "", + "op_sym": ":", + "value": "3", + "list_items": [], + "dict_entries": [] + } + } + ] + } + } + ] + } + ], + "job": [ + { + "name": "job", + "type_name": "Job", + "op_sym": "=", + "value": "Job {name = \"{}-{}\".format(\"app\", \"test\").lower()}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": "=", + "value": "\"{}-{}\".format(\"app\", \"test\").lower()", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "s1": [ + { + "name": "s1", + "type_name": "", + "op_sym": "=", + "value": "\"Hello\"", + "list_items": [], + "dict_entries": [] + } + ], + "select": [ + { + "name": "select", + "type_name": "a.b.c", + "op_sym": "=", + "value": "a.b.c {a: 1}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "1", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "sha": [ + { + "name": "sha", + "type_name": "A", + "op_sym": "=", + "value": "A {\n name: \"Hello\"\n ids: [1, 2, 3]\n data: {\n \"a\": {\n \"b\": {\"c\": 2}\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": ":", + "value": "\"Hello\"", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "ids", + "value": { + "name": "ids", + "type_name": "", + "op_sym": ":", + "value": "[1, 2, 3]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "1", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "2", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "3", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + }, + { + "key": "data", + "value": { + "name": "data", + "type_name": "", + "op_sym": ":", + "value": "{\n \"a\": {\n \"b\": {\"c\": 2}\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{\n \"b\": {\"c\": 2}\n}", + "list_items": [], + "dict_entries": [ + { + "key": "b", + "value": { + "name": "b", + "type_name": "", + "op_sym": ":", + "value": "{\"c\": 2}", + "list_items": [], + "dict_entries": [ + { + "key": "c", + "value": { + "name": "c", + "type_name": "", + "op_sym": ":", + "value": "2", + "list_items": [], + "dict_entries": [] + } + } + ] + } + } + ] + } + } + ] + } + } + ] + } + ], + "shb": [ + { + "name": "shb", + "type_name": "B", + "op_sym": "=", + "value": "B {\n a: {\n name: \"HelloB\"\n ids: [4, 5, 6]\n data: {\n \"d\": {\n \"e\": {\"f\": 3}\n }\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{\n name: \"HelloB\"\n ids: [4, 5, 6]\n data: {\n \"d\": {\n \"e\": {\"f\": 3}\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": ":", + "value": "\"HelloB\"", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "ids", + "value": { + "name": "ids", + "type_name": "", + "op_sym": ":", + "value": "[4, 5, 6]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "4", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "5", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "6", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + }, + { + "key": "data", + "value": { + "name": "data", + "type_name": "", + "op_sym": ":", + "value": "{\n \"d\": {\n \"e\": {\"f\": 3}\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "d", + "value": { + "name": "d", + "type_name": "", + "op_sym": ":", + "value": "{\n \"e\": {\"f\": 3}\n}", + "list_items": [], + "dict_entries": [ + { + "key": "e", + "value": { + "name": "e", + "type_name": "", + "op_sym": ":", + "value": "{\"f\": 3}", + "list_items": [], + "dict_entries": [ + { + "key": "f", + "value": { + "name": "f", + "type_name": "", + "op_sym": ":", + "value": "3", + "list_items": [], + "dict_entries": [] + } + } + ] + } + } + ] + } + } + ] + } + } + ] + } + } + ] + } + ], + "uconfa": [ + { + "name": "uconfa", + "type_name": "UnificationConf", + "op_sym": ":", + "value": "UnificationConf {name = \"b\"}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": "=", + "value": "\"b\"", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "union_list": [ + { + "name": "union_list", + "type_name": "", + "op_sym": "=", + "value": "[*_list0, *_list1]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "*_list0", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "*_list1", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + ] +} \ No newline at end of file diff --git a/kclvm/query/src/test_data/test_list_variables/test_list_all_variables/shb.json b/kclvm/query/src/test_data/test_list_variables/test_list_all_variables/shb.json new file mode 100644 index 000000000..ce82e99a9 --- /dev/null +++ b/kclvm/query/src/test_data/test_list_variables/test_list_all_variables/shb.json @@ -0,0 +1,730 @@ +{ + "_list0": [ + { + "name": "_list0", + "type_name": "", + "op_sym": "=", + "value": "[1, 2, 3]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "1", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "2", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "3", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + ], + "_list1": [ + { + "name": "_list1", + "type_name": "", + "op_sym": "=", + "value": "[4, 5, 6]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "4", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "5", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "6", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + ], + "_part1": [ + { + "name": "_part1", + "type_name": "", + "op_sym": "=", + "value": "{a = \"b\"}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": "=", + "value": "\"b\"", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "_part2": [ + { + "name": "_part2", + "type_name": "", + "op_sym": "=", + "value": "{c = \"d\"}", + "list_items": [], + "dict_entries": [ + { + "key": "c", + "value": { + "name": "c", + "type_name": "", + "op_sym": "=", + "value": "\"d\"", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "a": [ + { + "name": "a", + "type_name": "", + "op_sym": "=", + "value": "1", + "list_items": [], + "dict_entries": [] + } + ], + "a1": [ + { + "name": "a1", + "type_name": "", + "op_sym": "=", + "value": "2", + "list_items": [], + "dict_entries": [] + } + ], + "a3": [ + { + "name": "a3", + "type_name": "", + "op_sym": "=", + "value": "3m", + "list_items": [], + "dict_entries": [] + } + ], + "a_dict": [ + { + "name": "a_dict", + "type_name": "", + "op_sym": "=", + "value": "{**_part1, **_part2}", + "list_items": [], + "dict_entries": [ + { + "key": "", + "value": { + "name": "", + "type_name": "", + "op_sym": ":", + "value": "_part1", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "", + "value": { + "name": "", + "type_name": "", + "op_sym": ":", + "value": "_part2", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "array1": [ + { + "name": "array1", + "type_name": "", + "op_sym": "=", + "value": "[1, 2, 3]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "1", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "2", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "3", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + ], + "b1": [ + { + "name": "b1", + "type_name": "", + "op_sym": "=", + "value": "True", + "list_items": [], + "dict_entries": [] + } + ], + "b2": [ + { + "name": "b2", + "type_name": "", + "op_sym": "=", + "value": "False", + "list_items": [], + "dict_entries": [] + } + ], + "c": [ + { + "name": "c", + "type_name": "C", + "op_sym": "=", + "value": "C {\n a: {name: \"Hello\"}\n a: {ids: [7, 8, 9]}\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{name: \"Hello\"}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": ":", + "value": "\"Hello\"", + "list_items": [], + "dict_entries": [] + } + } + ] + } + }, + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{ids: [7, 8, 9]}", + "list_items": [], + "dict_entries": [ + { + "key": "ids", + "value": { + "name": "ids", + "type_name": "", + "op_sym": ":", + "value": "[7, 8, 9]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "7", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "8", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "9", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + } + ] + } + } + ] + } + ], + "dict1": [ + { + "name": "dict1", + "type_name": "", + "op_sym": "=", + "value": "{\"a\": 1, \"b\": 2}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "1", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "b", + "value": { + "name": "b", + "type_name": "", + "op_sym": ":", + "value": "2", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "dict2": [ + { + "name": "dict2", + "type_name": "", + "op_sym": "=", + "value": "{\n \"a\": 1\n \"b\": {\n \"c\": 2\n \"d\": 3\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "1", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "b", + "value": { + "name": "b", + "type_name": "", + "op_sym": ":", + "value": "{\n \"c\": 2\n \"d\": 3\n}", + "list_items": [], + "dict_entries": [ + { + "key": "c", + "value": { + "name": "c", + "type_name": "", + "op_sym": ":", + "value": "2", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "d", + "value": { + "name": "d", + "type_name": "", + "op_sym": ":", + "value": "3", + "list_items": [], + "dict_entries": [] + } + } + ] + } + } + ] + } + ], + "job": [ + { + "name": "job", + "type_name": "Job", + "op_sym": "=", + "value": "Job {name = \"{}-{}\".format(\"app\", \"test\").lower()}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": "=", + "value": "\"{}-{}\".format(\"app\", \"test\").lower()", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "s1": [ + { + "name": "s1", + "type_name": "", + "op_sym": "=", + "value": "\"Hello\"", + "list_items": [], + "dict_entries": [] + } + ], + "select": [ + { + "name": "select", + "type_name": "a.b.c", + "op_sym": "=", + "value": "a.b.c {a: 1}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "1", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "sha": [ + { + "name": "sha", + "type_name": "A", + "op_sym": "=", + "value": "A {\n name: \"Hello\"\n ids: [1, 2, 3]\n data: {\n \"a\": {\n \"b\": {\"c\": 2}\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": ":", + "value": "\"Hello\"", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "ids", + "value": { + "name": "ids", + "type_name": "", + "op_sym": ":", + "value": "[1, 2, 3]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "1", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "2", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "3", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + }, + { + "key": "data", + "value": { + "name": "data", + "type_name": "", + "op_sym": ":", + "value": "{\n \"a\": {\n \"b\": {\"c\": 2}\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{\n \"b\": {\"c\": 2}\n}", + "list_items": [], + "dict_entries": [ + { + "key": "b", + "value": { + "name": "b", + "type_name": "", + "op_sym": ":", + "value": "{\"c\": 2}", + "list_items": [], + "dict_entries": [ + { + "key": "c", + "value": { + "name": "c", + "type_name": "", + "op_sym": ":", + "value": "2", + "list_items": [], + "dict_entries": [] + } + } + ] + } + } + ] + } + } + ] + } + } + ] + } + ], + "shb": [ + { + "name": "shb", + "type_name": "B", + "op_sym": "=", + "value": "B {\n a: {\n name: \"HelloB\"\n ids: [4, 5, 6]\n data: {\n \"d\": {\n \"e\": {\"f\": 3}\n }\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{\n name: \"HelloB\"\n ids: [4, 5, 6]\n data: {\n \"d\": {\n \"e\": {\"f\": 3}\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": ":", + "value": "\"HelloB\"", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "ids", + "value": { + "name": "ids", + "type_name": "", + "op_sym": ":", + "value": "[4, 5, 6]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "4", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "5", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "6", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + }, + { + "key": "data", + "value": { + "name": "data", + "type_name": "", + "op_sym": ":", + "value": "{\n \"d\": {\n \"e\": {\"f\": 3}\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "d", + "value": { + "name": "d", + "type_name": "", + "op_sym": ":", + "value": "{\n \"e\": {\"f\": 3}\n}", + "list_items": [], + "dict_entries": [ + { + "key": "e", + "value": { + "name": "e", + "type_name": "", + "op_sym": ":", + "value": "{\"f\": 3}", + "list_items": [], + "dict_entries": [ + { + "key": "f", + "value": { + "name": "f", + "type_name": "", + "op_sym": ":", + "value": "3", + "list_items": [], + "dict_entries": [] + } + } + ] + } + } + ] + } + } + ] + } + } + ] + } + } + ] + } + ], + "uconfa": [ + { + "name": "uconfa", + "type_name": "UnificationConf", + "op_sym": ":", + "value": "UnificationConf {name = \"b\"}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": "=", + "value": "\"b\"", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "union_list": [ + { + "name": "union_list", + "type_name": "", + "op_sym": "=", + "value": "[*_list0, *_list1]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "*_list0", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "*_list1", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + ] +} \ No newline at end of file diff --git a/kclvm/query/src/test_data/test_list_variables/test_list_all_variables/union_list.json b/kclvm/query/src/test_data/test_list_variables/test_list_all_variables/union_list.json new file mode 100644 index 000000000..ce82e99a9 --- /dev/null +++ b/kclvm/query/src/test_data/test_list_variables/test_list_all_variables/union_list.json @@ -0,0 +1,730 @@ +{ + "_list0": [ + { + "name": "_list0", + "type_name": "", + "op_sym": "=", + "value": "[1, 2, 3]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "1", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "2", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "3", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + ], + "_list1": [ + { + "name": "_list1", + "type_name": "", + "op_sym": "=", + "value": "[4, 5, 6]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "4", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "5", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "6", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + ], + "_part1": [ + { + "name": "_part1", + "type_name": "", + "op_sym": "=", + "value": "{a = \"b\"}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": "=", + "value": "\"b\"", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "_part2": [ + { + "name": "_part2", + "type_name": "", + "op_sym": "=", + "value": "{c = \"d\"}", + "list_items": [], + "dict_entries": [ + { + "key": "c", + "value": { + "name": "c", + "type_name": "", + "op_sym": "=", + "value": "\"d\"", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "a": [ + { + "name": "a", + "type_name": "", + "op_sym": "=", + "value": "1", + "list_items": [], + "dict_entries": [] + } + ], + "a1": [ + { + "name": "a1", + "type_name": "", + "op_sym": "=", + "value": "2", + "list_items": [], + "dict_entries": [] + } + ], + "a3": [ + { + "name": "a3", + "type_name": "", + "op_sym": "=", + "value": "3m", + "list_items": [], + "dict_entries": [] + } + ], + "a_dict": [ + { + "name": "a_dict", + "type_name": "", + "op_sym": "=", + "value": "{**_part1, **_part2}", + "list_items": [], + "dict_entries": [ + { + "key": "", + "value": { + "name": "", + "type_name": "", + "op_sym": ":", + "value": "_part1", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "", + "value": { + "name": "", + "type_name": "", + "op_sym": ":", + "value": "_part2", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "array1": [ + { + "name": "array1", + "type_name": "", + "op_sym": "=", + "value": "[1, 2, 3]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "1", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "2", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "3", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + ], + "b1": [ + { + "name": "b1", + "type_name": "", + "op_sym": "=", + "value": "True", + "list_items": [], + "dict_entries": [] + } + ], + "b2": [ + { + "name": "b2", + "type_name": "", + "op_sym": "=", + "value": "False", + "list_items": [], + "dict_entries": [] + } + ], + "c": [ + { + "name": "c", + "type_name": "C", + "op_sym": "=", + "value": "C {\n a: {name: \"Hello\"}\n a: {ids: [7, 8, 9]}\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{name: \"Hello\"}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": ":", + "value": "\"Hello\"", + "list_items": [], + "dict_entries": [] + } + } + ] + } + }, + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{ids: [7, 8, 9]}", + "list_items": [], + "dict_entries": [ + { + "key": "ids", + "value": { + "name": "ids", + "type_name": "", + "op_sym": ":", + "value": "[7, 8, 9]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "7", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "8", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "9", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + } + ] + } + } + ] + } + ], + "dict1": [ + { + "name": "dict1", + "type_name": "", + "op_sym": "=", + "value": "{\"a\": 1, \"b\": 2}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "1", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "b", + "value": { + "name": "b", + "type_name": "", + "op_sym": ":", + "value": "2", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "dict2": [ + { + "name": "dict2", + "type_name": "", + "op_sym": "=", + "value": "{\n \"a\": 1\n \"b\": {\n \"c\": 2\n \"d\": 3\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "1", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "b", + "value": { + "name": "b", + "type_name": "", + "op_sym": ":", + "value": "{\n \"c\": 2\n \"d\": 3\n}", + "list_items": [], + "dict_entries": [ + { + "key": "c", + "value": { + "name": "c", + "type_name": "", + "op_sym": ":", + "value": "2", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "d", + "value": { + "name": "d", + "type_name": "", + "op_sym": ":", + "value": "3", + "list_items": [], + "dict_entries": [] + } + } + ] + } + } + ] + } + ], + "job": [ + { + "name": "job", + "type_name": "Job", + "op_sym": "=", + "value": "Job {name = \"{}-{}\".format(\"app\", \"test\").lower()}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": "=", + "value": "\"{}-{}\".format(\"app\", \"test\").lower()", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "s1": [ + { + "name": "s1", + "type_name": "", + "op_sym": "=", + "value": "\"Hello\"", + "list_items": [], + "dict_entries": [] + } + ], + "select": [ + { + "name": "select", + "type_name": "a.b.c", + "op_sym": "=", + "value": "a.b.c {a: 1}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "1", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "sha": [ + { + "name": "sha", + "type_name": "A", + "op_sym": "=", + "value": "A {\n name: \"Hello\"\n ids: [1, 2, 3]\n data: {\n \"a\": {\n \"b\": {\"c\": 2}\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": ":", + "value": "\"Hello\"", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "ids", + "value": { + "name": "ids", + "type_name": "", + "op_sym": ":", + "value": "[1, 2, 3]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "1", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "2", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "3", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + }, + { + "key": "data", + "value": { + "name": "data", + "type_name": "", + "op_sym": ":", + "value": "{\n \"a\": {\n \"b\": {\"c\": 2}\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{\n \"b\": {\"c\": 2}\n}", + "list_items": [], + "dict_entries": [ + { + "key": "b", + "value": { + "name": "b", + "type_name": "", + "op_sym": ":", + "value": "{\"c\": 2}", + "list_items": [], + "dict_entries": [ + { + "key": "c", + "value": { + "name": "c", + "type_name": "", + "op_sym": ":", + "value": "2", + "list_items": [], + "dict_entries": [] + } + } + ] + } + } + ] + } + } + ] + } + } + ] + } + ], + "shb": [ + { + "name": "shb", + "type_name": "B", + "op_sym": "=", + "value": "B {\n a: {\n name: \"HelloB\"\n ids: [4, 5, 6]\n data: {\n \"d\": {\n \"e\": {\"f\": 3}\n }\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "a", + "value": { + "name": "a", + "type_name": "", + "op_sym": ":", + "value": "{\n name: \"HelloB\"\n ids: [4, 5, 6]\n data: {\n \"d\": {\n \"e\": {\"f\": 3}\n }\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": ":", + "value": "\"HelloB\"", + "list_items": [], + "dict_entries": [] + } + }, + { + "key": "ids", + "value": { + "name": "ids", + "type_name": "", + "op_sym": ":", + "value": "[4, 5, 6]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "4", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "5", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "6", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + }, + { + "key": "data", + "value": { + "name": "data", + "type_name": "", + "op_sym": ":", + "value": "{\n \"d\": {\n \"e\": {\"f\": 3}\n }\n}", + "list_items": [], + "dict_entries": [ + { + "key": "d", + "value": { + "name": "d", + "type_name": "", + "op_sym": ":", + "value": "{\n \"e\": {\"f\": 3}\n}", + "list_items": [], + "dict_entries": [ + { + "key": "e", + "value": { + "name": "e", + "type_name": "", + "op_sym": ":", + "value": "{\"f\": 3}", + "list_items": [], + "dict_entries": [ + { + "key": "f", + "value": { + "name": "f", + "type_name": "", + "op_sym": ":", + "value": "3", + "list_items": [], + "dict_entries": [] + } + } + ] + } + } + ] + } + } + ] + } + } + ] + } + } + ] + } + ], + "uconfa": [ + { + "name": "uconfa", + "type_name": "UnificationConf", + "op_sym": ":", + "value": "UnificationConf {name = \"b\"}", + "list_items": [], + "dict_entries": [ + { + "key": "name", + "value": { + "name": "name", + "type_name": "", + "op_sym": "=", + "value": "\"b\"", + "list_items": [], + "dict_entries": [] + } + } + ] + } + ], + "union_list": [ + { + "name": "union_list", + "type_name": "", + "op_sym": "=", + "value": "[*_list0, *_list1]", + "list_items": [ + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "*_list0", + "list_items": [], + "dict_entries": [] + }, + { + "name": "", + "type_name": "", + "op_sym": "", + "value": "*_list1", + "list_items": [], + "dict_entries": [] + } + ], + "dict_entries": [] + } + ] +} \ No newline at end of file diff --git a/kclvm/query/src/test_data/test_list_variables/test_list_merged_variables/kcl.mod b/kclvm/query/src/test_data/test_list_variables/test_list_merged_variables/kcl.mod new file mode 100644 index 000000000..f893ac172 --- /dev/null +++ b/kclvm/query/src/test_data/test_list_variables/test_list_merged_variables/kcl.mod @@ -0,0 +1,5 @@ +[package] +name = "test_list_merged_variables" +edition = "v0.9.0" +version = "0.0.1" + diff --git a/kclvm/query/src/test_data/test_list_variables/test_list_merged_variables/main.k b/kclvm/query/src/test_data/test_list_variables/test_list_merged_variables/main.k new file mode 100644 index 000000000..42a2438ab --- /dev/null +++ b/kclvm/query/src/test_data/test_list_variables/test_list_merged_variables/main.k @@ -0,0 +1,2 @@ +a = res.Resource {cpu = "2", disk = "35Gi", memory = "4Gi"} + diff --git a/kclvm/query/src/test_data/test_list_variables/test_list_merged_variables/merge_1/base.k b/kclvm/query/src/test_data/test_list_variables/test_list_merged_variables/merge_1/base.k new file mode 100644 index 000000000..396c0b326 --- /dev/null +++ b/kclvm/query/src/test_data/test_list_variables/test_list_merged_variables/merge_1/base.k @@ -0,0 +1,19 @@ +appConfiguration: AppConfiguration { + releaseStrategy: "Manual" + replicas: 3 + mainContainer: container.Main { + env = [ + { + name: "key1" + value: "v1" + } + { + name: "key2" + value: "v2" + } + ] + } + resource: res.Resource { + disk = "35Gi" + } +} \ No newline at end of file diff --git a/kclvm/query/src/test_data/test_list_variables/test_list_merged_variables/merge_1/main.k b/kclvm/query/src/test_data/test_list_variables/test_list_merged_variables/merge_1/main.k new file mode 100644 index 000000000..4ed792d1f --- /dev/null +++ b/kclvm/query/src/test_data/test_list_variables/test_list_merged_variables/merge_1/main.k @@ -0,0 +1,18 @@ +appConfiguration: AppConfiguration { + atsValues = values._v + resource: res.Resource { + cpu = "2" + memory = "4Gi" + } + mainContainer: container.Main {env = [ + { + name: "key1" + value: "v1" + } + { + name: "key2" + value: "v2" + } + ]} + replicas = 3 +} \ No newline at end of file diff --git a/kclvm/query/src/test_data/test_list_variables/test_list_merged_variables/merge_10/main.k b/kclvm/query/src/test_data/test_list_variables/test_list_merged_variables/merge_10/main.k new file mode 100644 index 000000000..3b4757f06 --- /dev/null +++ b/kclvm/query/src/test_data/test_list_variables/test_list_merged_variables/merge_10/main.k @@ -0,0 +1,14 @@ +schema Person: + name: str + age: int + hc: [int] + +alice: Person { + name: "Alice" + hc: [1, 2] +} + +alice: Person { + age: 18 + hc = [2] +} diff --git a/kclvm/query/src/test_data/test_list_variables/test_list_merged_variables/merge_11/main.k b/kclvm/query/src/test_data/test_list_variables/test_list_merged_variables/merge_11/main.k new file mode 100644 index 000000000..1fd19c60a --- /dev/null +++ b/kclvm/query/src/test_data/test_list_variables/test_list_merged_variables/merge_11/main.k @@ -0,0 +1,24 @@ +schema Main: + env: [str] + args: [str] + +schema Config: + name?: str + age?: int + hc?: [int] + main: Main + +config: Config { + name: "Alice" + main: Main { + env: ["123", "456"] + args: ["1"] + } +} +config: Config { + age: 18 + main: Main { + env = ["789", "456"] + args = ["1"] + } +} diff --git a/kclvm/query/src/test_data/test_list_variables/test_list_merged_variables/merge_2/base.k b/kclvm/query/src/test_data/test_list_variables/test_list_merged_variables/merge_2/base.k new file mode 100644 index 000000000..34d8dcf7f --- /dev/null +++ b/kclvm/query/src/test_data/test_list_variables/test_list_merged_variables/merge_2/base.k @@ -0,0 +1,19 @@ +appConfiguration = AppConfiguration { + releaseStrategy: "Manual" + replicas: 3 + mainContainer: container.Main { + env = [ + { + name: "key1" + value: "v1" + } + { + name: "key2" + value: "v2" + } + ] + } + resource: res.Resource { + disk = "35Gi" + } +} \ No newline at end of file diff --git a/kclvm/query/src/test_data/test_list_variables/test_list_merged_variables/merge_2/main.k b/kclvm/query/src/test_data/test_list_variables/test_list_merged_variables/merge_2/main.k new file mode 100644 index 000000000..df922ad76 --- /dev/null +++ b/kclvm/query/src/test_data/test_list_variables/test_list_merged_variables/merge_2/main.k @@ -0,0 +1,18 @@ +appConfiguration = AppConfiguration { + atsValues = values._v + resource: res.Resource { + cpu = "2" + memory = "4Gi" + } + mainContainer: container.Main {env = [ + { + name: "key1" + value: "v1" + } + { + name: "key2" + value: "v2" + } + ]} + replicas = 3 +} \ No newline at end of file diff --git a/kclvm/query/src/test_data/test_list_variables/test_list_merged_variables/merge_3/base.k b/kclvm/query/src/test_data/test_list_variables/test_list_merged_variables/merge_3/base.k new file mode 100644 index 000000000..34d8dcf7f --- /dev/null +++ b/kclvm/query/src/test_data/test_list_variables/test_list_merged_variables/merge_3/base.k @@ -0,0 +1,19 @@ +appConfiguration = AppConfiguration { + releaseStrategy: "Manual" + replicas: 3 + mainContainer: container.Main { + env = [ + { + name: "key1" + value: "v1" + } + { + name: "key2" + value: "v2" + } + ] + } + resource: res.Resource { + disk = "35Gi" + } +} \ No newline at end of file diff --git a/kclvm/query/src/test_data/test_list_variables/test_list_merged_variables/merge_3/main.k b/kclvm/query/src/test_data/test_list_variables/test_list_merged_variables/merge_3/main.k new file mode 100644 index 000000000..5388d3413 --- /dev/null +++ b/kclvm/query/src/test_data/test_list_variables/test_list_merged_variables/merge_3/main.k @@ -0,0 +1,18 @@ +appConfiguration : AppConfiguration { + atsValues = values._v + resource: res.Resource { + cpu = "2" + memory = "4Gi" + } + mainContainer: container.Main {env = [ + { + name: "key1" + value: "v1" + } + { + name: "key2" + value: "v2" + } + ]} + replicas = 3 +} \ No newline at end of file diff --git a/kclvm/query/src/test_data/test_list_variables/test_list_merged_variables/merge_4/base.k b/kclvm/query/src/test_data/test_list_variables/test_list_merged_variables/merge_4/base.k new file mode 100644 index 000000000..4b3095663 --- /dev/null +++ b/kclvm/query/src/test_data/test_list_variables/test_list_merged_variables/merge_4/base.k @@ -0,0 +1,19 @@ +appConfiguration : AppConfiguration { + releaseStrategy: "Manual" + replicas: 3 + mainContainer: container.Main { + env = [ + { + name: "key1" + value: "v1" + } + { + name: "key2" + value: "v2" + } + ] + } + resource: res.Resource { + disk = "35Gi" + } +} \ No newline at end of file diff --git a/kclvm/query/src/test_data/test_list_variables/test_list_merged_variables/merge_4/main.k b/kclvm/query/src/test_data/test_list_variables/test_list_merged_variables/merge_4/main.k new file mode 100644 index 000000000..df922ad76 --- /dev/null +++ b/kclvm/query/src/test_data/test_list_variables/test_list_merged_variables/merge_4/main.k @@ -0,0 +1,18 @@ +appConfiguration = AppConfiguration { + atsValues = values._v + resource: res.Resource { + cpu = "2" + memory = "4Gi" + } + mainContainer: container.Main {env = [ + { + name: "key1" + value: "v1" + } + { + name: "key2" + value: "v2" + } + ]} + replicas = 3 +} \ No newline at end of file diff --git a/kclvm/query/src/test_data/test_list_variables/test_list_merged_variables/merge_5/base.k b/kclvm/query/src/test_data/test_list_variables/test_list_merged_variables/merge_5/base.k new file mode 100644 index 000000000..fcdc64f31 --- /dev/null +++ b/kclvm/query/src/test_data/test_list_variables/test_list_merged_variables/merge_5/base.k @@ -0,0 +1,23 @@ +appConfiguration : AppConfiguration { + releaseStrategy: "Manual" + replicas: 3 + mainContainer: container.Main { + env = [ + { + name: "key1" + value: "v1" + } + { + name: "key2" + value: "v2" + } + ] + } + resource: res.Resource { + disk = "35Gi" + cpu = { + request: "100m" + limit: "200m" + } + } +} \ No newline at end of file diff --git a/kclvm/query/src/test_data/test_list_variables/test_list_merged_variables/merge_5/main.k b/kclvm/query/src/test_data/test_list_variables/test_list_merged_variables/merge_5/main.k new file mode 100644 index 000000000..31dcde6c8 --- /dev/null +++ b/kclvm/query/src/test_data/test_list_variables/test_list_merged_variables/merge_5/main.k @@ -0,0 +1,21 @@ +appConfiguration : AppConfiguration { + atsValues = values._v + resource: res.Resource { + cpu : { + request: "100m" + limit_plus: "20000m" + } + memory = "4Gi" + } + mainContainer: container.Main {env = [ + { + name: "key1" + value: "v1" + } + { + name: "key2" + value: "v2" + } + ]} + replicas = 3 +} \ No newline at end of file diff --git a/kclvm/query/src/test_data/test_list_variables/test_list_merged_variables/merge_6/base.k b/kclvm/query/src/test_data/test_list_variables/test_list_merged_variables/merge_6/base.k new file mode 100644 index 000000000..bbd76df47 --- /dev/null +++ b/kclvm/query/src/test_data/test_list_variables/test_list_merged_variables/merge_6/base.k @@ -0,0 +1,3 @@ +config: Config { + name = "config2" +} diff --git a/kclvm/query/src/test_data/test_list_variables/test_list_merged_variables/merge_6/main.k b/kclvm/query/src/test_data/test_list_variables/test_list_merged_variables/merge_6/main.k new file mode 100644 index 000000000..d917345da --- /dev/null +++ b/kclvm/query/src/test_data/test_list_variables/test_list_merged_variables/merge_6/main.k @@ -0,0 +1,10 @@ +schema Config: + name?: str + args: [str] + labels: {str:} + +config: Config { + name: "config1" + args: ["kcl", "main.k"] + labels.key1: "value1" +} diff --git a/kclvm/query/src/test_data/test_list_variables/test_list_merged_variables/merge_7/base.k b/kclvm/query/src/test_data/test_list_variables/test_list_merged_variables/merge_7/base.k new file mode 100644 index 000000000..45dbcba0e --- /dev/null +++ b/kclvm/query/src/test_data/test_list_variables/test_list_merged_variables/merge_7/base.k @@ -0,0 +1,4 @@ +_NAME = "config2" +config: Config { + name = _NAME +} diff --git a/kclvm/query/src/test_data/test_list_variables/test_list_merged_variables/merge_7/main.k b/kclvm/query/src/test_data/test_list_variables/test_list_merged_variables/merge_7/main.k new file mode 100644 index 000000000..d917345da --- /dev/null +++ b/kclvm/query/src/test_data/test_list_variables/test_list_merged_variables/merge_7/main.k @@ -0,0 +1,10 @@ +schema Config: + name?: str + args: [str] + labels: {str:} + +config: Config { + name: "config1" + args: ["kcl", "main.k"] + labels.key1: "value1" +} diff --git a/kclvm/query/src/test_data/test_list_variables/test_list_merged_variables/merge_8/main.k b/kclvm/query/src/test_data/test_list_variables/test_list_merged_variables/merge_8/main.k new file mode 100644 index 000000000..717e291a6 --- /dev/null +++ b/kclvm/query/src/test_data/test_list_variables/test_list_merged_variables/merge_8/main.k @@ -0,0 +1,20 @@ +schema Config: + args: [str] + labels: {str:} + +config: Config { + args: ["kcl", "main.k"] + labels.key1: "value1" +} + +config: Config { + labels: { + key2: "value2" + } +} + +config: Config { + "labels": { + "key3": "value3" + } +} diff --git a/kclvm/query/src/test_data/test_list_variables/test_list_merged_variables/merge_9/main.k b/kclvm/query/src/test_data/test_list_variables/test_list_merged_variables/merge_9/main.k new file mode 100644 index 000000000..cfc72eff2 --- /dev/null +++ b/kclvm/query/src/test_data/test_list_variables/test_list_merged_variables/merge_9/main.k @@ -0,0 +1,24 @@ +schema Name0: + name?: str + data?: int + +schema Name: + name?: Name0 + +schema Config: + args?: [str] + labels: {str:} + name: Name + +config: Config { + args: ["kcl", "main.k"] + labels.key1: "value1" + name.name.name: "name" +} + +config: Config { + labels: { + key2: "value2" + } + name.name: Name0 {data: 1} +} diff --git a/kclvm/query/src/test_data/test_list_variables/test_list_merged_variables/override/base.k b/kclvm/query/src/test_data/test_list_variables/test_list_merged_variables/override/base.k new file mode 100644 index 000000000..cc4c5914b --- /dev/null +++ b/kclvm/query/src/test_data/test_list_variables/test_list_merged_variables/override/base.k @@ -0,0 +1,11 @@ + +import test + +_tests = test.Test { + pots: [ + test.Pot { + name: "http" + number: 90 + } + ] +} \ No newline at end of file diff --git a/kclvm/query/src/test_data/test_list_variables/test_list_merged_variables/override/main.k b/kclvm/query/src/test_data/test_list_variables/test_list_merged_variables/override/main.k new file mode 100644 index 000000000..074e18a18 --- /dev/null +++ b/kclvm/query/src/test_data/test_list_variables/test_list_merged_variables/override/main.k @@ -0,0 +1,6 @@ + +import test + +_tests = test.Test { + aType: "Internet" +} diff --git a/kclvm/query/src/test_data/test_list_variables/test_list_merged_variables/test.k b/kclvm/query/src/test_data/test_list_variables/test_list_merged_variables/test.k new file mode 100644 index 000000000..a484f7f47 --- /dev/null +++ b/kclvm/query/src/test_data/test_list_variables/test_list_merged_variables/test.k @@ -0,0 +1,7 @@ +schema Pot: + name: str + number: int + +schema Test: + aType?: str + pots?: [Pot] diff --git a/kclvm/query/src/test_data/test_list_variables/unsupported.k b/kclvm/query/src/test_data/test_list_variables/unsupported.k new file mode 100644 index 000000000..115cd8501 --- /dev/null +++ b/kclvm/query/src/test_data/test_list_variables/unsupported.k @@ -0,0 +1,52 @@ +list = [ _x for _x in range(20) if _x % 2 == 0] +list1 = [i if i > 2 else i + 1 for i in [1,2,3]] + + +dict = {str(i): 2 * i for i in range(3)} + +func = lambda x: int, y: int -> int { x + y } + +schema IfSchemaInner: + innerValue: int + +schema IfSchema: + trueValue?: int + falseValue?: int + name: str + age: int + inner: IfSchemaInner + inner2: IfSchemaInner + +if_schema = IfSchema { + if True : + trueValue: 1 + else : + falseValue: 2 + + name: "name" + age: 1 + inner: IfSchemaInner { + innerValue: 1 + } + + inner2: { + innerValue: 2 + } +} + +if_schema1 = { + if True : + trueValue: 1 + else : + falseValue: 2 + + name: "name" + age: 1 + inner: IfSchemaInner { + innerValue: 1 + } + + inner2: { + innerValue: 2 + } +} \ No newline at end of file diff --git a/kclvm/query/src/test_data/test_override_file/expect.k b/kclvm/query/src/test_data/test_override_file/expect.k new file mode 100644 index 000000000..06d281e00 --- /dev/null +++ b/kclvm/query/src/test_data/test_override_file/expect.k @@ -0,0 +1,76 @@ +import base.pkg.kusion_models.app +import base.pkg.kusion_models.app.vip as vip +import base.pkg.kusion_models.app.container +import base.pkg.kusion_models.app.resource as res +import base.pkg.kusion_models.app.sidecar +import base.pkg.models.app +import base.pkg.models.app.resource as res +import .values + +# Note: This is a sample configuration file. Please modify it according to your needs. +# Note: +# 1. This file is used to configure the application. +# 2. The configuration file is written in KCL. +c = { + "a": 1 + b = { + "a": "b" + } +} + +_access = test.ServiceAccess { + iType = "kkkkkkk" + sType = dsType + TestStr = ["${test_str}"] + ports = [80, 443] + booltest = True + mergedattr = 1 + a: { + b: { + c = 2 + } + c: { + b = 3 + } + } +} + +_access3 = test.ServiceAccess { + iType = "kkkkkkk" + sType = dsType + TestStr = [ + "${test_str}" + ] + ports = [ + 80 + 443 + ] + booltest = True +} +b = { + "c": 2 +} +d = { + e: { + f: { + g = 3 + } + } +} +_access4 = test.ServiceAccess { + iType = "kkkkkkk" + sType = dsType + TestStr = [ + "${test_str}" + ] + ports = [ + 80 + 443 + ] + booltest = True +} +_access5 = { + iType = "dddddd" +} +a = b +_access6 = "a6" diff --git a/kclvm/query/src/test_data/test_override_file/invalid.k b/kclvm/query/src/test_data/test_override_file/invalid.k new file mode 100644 index 000000000..9495fd5e5 --- /dev/null +++ b/kclvm/query/src/test_data/test_override_file/invalid.k @@ -0,0 +1 @@ +"a": "b" \ No newline at end of file diff --git a/kclvm/query/src/test_data/test_override_file/main.bk.k b/kclvm/query/src/test_data/test_override_file/main.bk.k new file mode 100644 index 000000000..8d8ddcdd4 --- /dev/null +++ b/kclvm/query/src/test_data/test_override_file/main.bk.k @@ -0,0 +1,28 @@ +import base.pkg.models.app +import base.pkg.models.app.resource as res +import .values + +# Note: This is a sample configuration file. Please modify it according to your needs. +# Note: +# 1. This file is used to configure the application. +# 2. The configuration file is written in KCL. + +c = { + "a": 1 +} + +_access = test.ServiceAccess { + iType = "kkkkkkk" + sType = dsType + TestStr = ["${test_str}"] + ports = [80, 443] + booltest = True +} + +_access3 = test.ServiceAccess { + iType = "kkkkkkk" + sType = dsType + TestStr = ["${test_str}"] + ports = [80, 443] + booltest = True +} \ No newline at end of file diff --git a/kclvm/query/src/test_data/test_override_file/main.k b/kclvm/query/src/test_data/test_override_file/main.k new file mode 100644 index 000000000..8d8ddcdd4 --- /dev/null +++ b/kclvm/query/src/test_data/test_override_file/main.k @@ -0,0 +1,28 @@ +import base.pkg.models.app +import base.pkg.models.app.resource as res +import .values + +# Note: This is a sample configuration file. Please modify it according to your needs. +# Note: +# 1. This file is used to configure the application. +# 2. The configuration file is written in KCL. + +c = { + "a": 1 +} + +_access = test.ServiceAccess { + iType = "kkkkkkk" + sType = dsType + TestStr = ["${test_str}"] + ports = [80, 443] + booltest = True +} + +_access3 = test.ServiceAccess { + iType = "kkkkkkk" + sType = dsType + TestStr = ["${test_str}"] + ports = [80, 443] + booltest = True +} \ No newline at end of file diff --git a/kclvm/query/src/tests.rs b/kclvm/query/src/tests.rs new file mode 100644 index 000000000..2f63850e9 --- /dev/null +++ b/kclvm/query/src/tests.rs @@ -0,0 +1,1099 @@ +use std::{fs, path::PathBuf}; + +use super::{r#override::apply_override_on_module, *}; +use crate::{ + path::parse_attribute_path, r#override::parse_override_spec, selector::list_variables, +}; +use kclvm_error::{DiagnosticId, ErrorKind, Level}; +use kclvm_parser::parse_file_force_errors; +use kclvm_utils::path::PathPrefix; +use pretty_assertions::assert_eq; +use selector::ListOptions; + +const CARGO_FILE_PATH: &str = env!("CARGO_MANIFEST_DIR"); + +fn get_test_dir(sub: String) -> PathBuf { + let mut cargo_file_path = PathBuf::from(CARGO_FILE_PATH); + cargo_file_path.push("src"); + cargo_file_path.push("test_data"); + // Split unix and windows path + for part in sub.split("/") { + for p in part.split("\\") { + cargo_file_path.push(p); + } + } + cargo_file_path +} + +/// Test override_file result. +#[test] +fn test_override_file_simple() { + let specs = vec![ + "config.image=image/image".to_string(), + "config.image=\"image/image:v1\"".to_string(), + "config.data={id=1,value=\"override_value\"}".to_string(), + "dict_config={\"image\": \"image/image:v2\" \"data\":{\"id\":2 \"value2\": \"override_value2\"}}".to_string(), + "envs=[{key=\"key1\" value=\"value1\"} {key=\"key2\" value=\"value2\"}]".to_string(), + "isfilter=False".to_string(), + "count=2".to_string(), + "msg=\"Hi World\"".to_string(), + "delete-".to_string(), + "dict_delete.image-".to_string(), + "dict_delete_whole-".to_string(), + "insert_config.key=1".to_string(), + "uni_config.labels.key1=1".to_string(), + "config_unification=Config {\"image\": \"image/image:v4\"}".to_string(), + "config_unification:Config {\"env\": {\"aaa\": \"aaa\"}}".to_string(), + "config_unification.env: {\"bbb\": \"bbb\"}}".to_string(), + "config_unification_delete-".to_string() + ]; + + let simple_path = get_test_dir("simple.k".to_string()); + let simple_bk_path = get_test_dir("simple.bk.k".to_string()); + let expect_path = get_test_dir("expect.k".to_string()); + fs::copy(simple_bk_path.clone(), simple_path.clone()).unwrap(); + if simple_path.exists() { + fs::remove_file(simple_path.clone()).unwrap(); + } + + fs::copy(simple_bk_path.clone(), simple_path.clone()).unwrap(); + + let import_paths = vec![]; + assert_eq!( + override_file(simple_path.clone().to_str().unwrap(), &specs, &import_paths) + .unwrap() + .result, + true + ); + + let simple_content = fs::read_to_string(simple_path.clone()).unwrap(); + let expect_content = fs::read_to_string(expect_path).unwrap(); + + let simple_content = simple_content.replace("\r\n", "\n"); + let expect_content = expect_content.replace("\r\n", "\n"); + + assert_eq!(simple_content, expect_content); + + fs::copy(simple_bk_path.clone(), simple_path.clone()).unwrap(); +} +/// Test override_file result. +#[test] +fn test_override_file_import_paths() { + let specs = vec!["data.value=\"override_value\"".to_string()]; + let import_paths = vec![ + "pkg".to_string(), + "pkg.pkg".to_string(), + "pkg.pkg as alias_pkg1".to_string(), + "pkg.pkg as alias_pkg2".to_string(), + ]; + + let mut cargo_file_path = PathBuf::from(CARGO_FILE_PATH); + cargo_file_path.push("src/test_data/import_paths.k"); + let abs_path = cargo_file_path.to_str().unwrap(); + + assert_eq!( + override_file(abs_path, &specs, &import_paths) + .unwrap() + .result, + true + ) +} + +/// Test override_file result with the expected modified AST. +#[test] +fn test_override_file_config() { + let specs = vec![ + "appConfiguration.image=\"kcl/kcl:{}\".format(version)".to_string(), + r#"appConfiguration.mainContainer.name="override_name""#.to_string(), + "appConfiguration.labels.key.key=\"override_value\"".to_string(), + "appConfiguration.labels.key.str-key=\"override_value\"".to_string(), + "appConfiguration.labels.key['dot.key']=\"override_value\"".to_string(), + "appConfiguration.overQuota=False".to_string(), + "appConfiguration.probe={periodSeconds=20}".to_string(), + "appConfiguration.resource-".to_string(), + "appConfiguration.svc=s.Service {}".to_string(), + "appConfigurationUnification.image=\"kcl/kcl:v0.1\"".to_string(), + r#"appConfigurationUnification.mainContainer.name="override_name""#.to_string(), + "appConfigurationUnification.labels.key.key=\"override_value\"".to_string(), + "appConfigurationUnification.overQuota=False".to_string(), + "appConfigurationUnification.resource.cpu-".to_string(), + "appConfigurationUnification.svc=s.Service {}".to_string(), + "appConfigurationUnification:{name=\"name\"}".to_string(), + "config.x:{a:1}".to_string(), + "config.x:{b:2}".to_string(), + "config.x:{b:3}".to_string(), + "config.x:{c.d:4}".to_string(), + "config.y=1".to_string(), + "config.z+=[1,2,3]".to_string(), + "config.z+=[4,5,6]".to_string(), + "var1:1".to_string(), + "var2=1".to_string(), + "var3+=[1,2,3]".to_string(), + "var3+=[4,5,6]".to_string(), + "var4:AppConfiguration {image:'image'}".to_string(), + ]; + let import_paths = vec!["service as s".to_string()]; + + let mut cargo_file_path = PathBuf::from(CARGO_FILE_PATH); + cargo_file_path.push("src/test_data/config.k"); + let abs_path = cargo_file_path.to_str().unwrap(); + + let mut module = parse_file_force_errors(abs_path, None).unwrap(); + for s in &specs { + apply_override_on_module(&mut module, s, &import_paths).unwrap(); + } + let expected_code = print_ast_module(&module); + assert_eq!( + expected_code, + r#"import service as s + +schema Main: + name?: str + env?: [{str:}] + +schema Probe: + initialDelaySeconds?: int + timeoutSeconds?: int + periodSeconds?: int = 10 + successThreshold?: int + failureThreshold?: int + +schema AppConfiguration: + appName: str + image: str + overQuota: bool = False + resource: {str:} + mainContainer?: Main + labels: {str:} + probe?: Probe + +appConfiguration = AppConfiguration { + appName: "kclvm" + image: "kcl/kcl:{}".format(version) + labels: { + key: { + key: "override_value" + "str-key" = "override_value" + "dot.key" = "override_value" + } + } + mainContainer: Main {name: "override_name"} + overQuota = False + overQuota = False + probe: { + periodSeconds = 20 + } + svc = s.Service {} +} + +appConfigurationUnification: AppConfiguration { + appName: "kclvm" + image: "kcl/kcl:v0.1" + resource: { + disk: "50Gi" + memory: "12Gi" + } + labels: { + key: {key: "override_value"} + } + mainContainer: Main {name: "override_name"} + overQuota: False + svc = s.Service {} + name = "name" +} +config = { + x: { + a: 1 + b: 3 + c: { + d: 4 + } + } + y = 1 + z += [ + 1 + 2 + 3 + 4 + 5 + 6 + ] +} +var1 = 1 +var2 = 1 +var3 += [ + 1 + 2 + 3 + 4 + 5 + 6 +] +var4: AppConfiguration { + image: 'image' +} +"# + ); +} + +/// Test override spec parser. +#[test] +fn test_parse_override_spec_invalid() { + let specs = vec![":a:", "=a=", ":a", "a-1"]; + for spec in specs { + assert!(parse_override_spec(spec).is_err(), "{spec} test failed"); + } +} + +#[test] +fn test_parse_property_path() { + assert_eq!(parse_attribute_path("a.b.c").unwrap(), vec!["a", "b", "c"]); + assert_eq!( + parse_attribute_path(r#"a["b"].c"#).unwrap(), + vec!["a", "b", "c"] + ); + assert_eq!( + parse_attribute_path(r#"a.["b"].c"#).unwrap(), + vec!["a", "b", "c"] + ); + assert_eq!( + parse_attribute_path(r#"a['b'].c"#).unwrap(), + vec!["a", "b", "c"] + ); + assert_eq!( + parse_attribute_path(r#"a.b['c.d']"#).unwrap(), + vec!["a", "b", "c.d"] + ); + assert_eq!( + parse_attribute_path(r#"a.b.['c.d']"#).unwrap(), + vec!["a", "b", "c.d"] + ); + assert_eq!( + parse_attribute_path(r#"a.b['c.d'].e"#).unwrap(), + vec!["a", "b", "c.d", "e"] + ); + assert_eq!( + parse_attribute_path(r#"a.b.['c.d'].e"#).unwrap(), + vec!["a", "b", "c.d", "e"] + ); + assert_eq!( + parse_attribute_path(r#"a.b.c-d.e"#).unwrap(), + vec!["a", "b", "c-d", "e"] + ); + assert!(parse_attribute_path(r#"a.[b.c-d.e"#).is_err(),); + assert!(parse_attribute_path(r#"a.[b.c]-d.e"#).is_err(),); +} + +#[test] +fn test_list_variables() { + let file = PathBuf::from("./src/test_data/test_list_variables/supported.k") + .canonicalize() + .unwrap() + .display() + .to_string(); + let test_cases = vec![ + ("a", "1", "", "="), + ("a1", "2", "", "="), + ("a3", "3m", "", "="), + ("b1", "True", "", "="), + ("b2", "False", "", "="), + ("s1", "\"Hello\"", "", "="), + ( + "array1", + r#"[ + 1 + 2 + 3 +]"#, + "", + "=", + ), + ( + "dict1", + r#"{ + "a": 1 + "b": 2 +}"#, + "", + "=", + ), + ("dict1.a", "1", "", ":"), + ("dict1.b", "2", "", ":"), + ( + "dict2", + r#"{ + "a": 1 + "b": { + "c": 2 + "d": 3 + } +}"#, + "", + "=", + ), + ("dict2.a", "1", "", ":"), + ( + "dict2.b", + r#"{ + "c": 2 + "d": 3 +}"#, + "", + ":", + ), + ("dict2.b.c", "2", "", ":"), + ("dict2.b.d", "3", "", ":"), + ( + "sha", + r#"A { + name: "Hello" + ids: [1, 2, 3] + data: { + "a": { + "b": { + "c": 2 + } + } + } +}"#, + "A", + "=", + ), + ("sha.name", "\"Hello\"", "", ":"), + ( + "sha.ids", + r#"[ + 1 + 2 + 3 +]"#, + "", + ":", + ), + ( + "sha.data", + r#"{ + "a": { + "b": { + "c": 2 + } + } +}"#, + "", + ":", + ), + ( + "sha.data.a", + r#"{ + "b": { + "c": 2 + } +}"#, + "", + ":", + ), + ( + "sha.data.a.b", + r#"{ + "c": 2 +}"#, + "", + ":", + ), + ("sha.data.a.b.c", "2", "", ":"), + ( + "shb", + r#"B { + a: { + name: "HelloB" + ids: [4, 5, 6] + data: { + "d": { + "e": { + "f": 3 + } + } + } + } +}"#, + "B", + "=", + ), + ( + "shb.a", + r#"{ + name: "HelloB" + ids: [4, 5, 6] + data: { + "d": { + "e": { + "f": 3 + } + } + } +}"#, + "", + ":", + ), + ("shb.a.name", "\"HelloB\"", "", ":"), + ( + "shb.a.ids", + r#"[ + 4 + 5 + 6 +]"#, + "", + ":", + ), + ( + "shb.a.data", + r#"{ + "d": { + "e": { + "f": 3 + } + } +}"#, + "", + ":", + ), + ( + "shb.a.data.d", + r#"{ + "e": { + "f": 3 + } +}"#, + "", + ":", + ), + ( + "shb.a.data.d.e", + r#"{ + "f": 3 +}"#, + "", + ":", + ), + ("uconfa.name", "\"b\"", "", "="), + ( + "c.a", + r#"{ + name: "Hello" +}"#, + "", + ":", + ), + ( + "job.name", + r#""{}-{}".format("app", "test").lower()"#, + "", + "=", + ), + ( + "union_list", + r#"[ + *_list0 + *_list1 +]"#, + "", + "=", + ), + ( + "a_dict", + r#"{ + **_part1 + **_part2 +}"#, + "", + "=", + ), + ]; + + for (spec, expected, expected_name, op_sym) in test_cases { + let specs = vec![spec.to_string()]; + let result = list_variables(vec![file.clone()], specs, None).unwrap(); + assert_eq!( + result.variables.get(spec).unwrap().get(0).unwrap().value, + expected, + "{spec}" + ); + assert_eq!( + result + .variables + .get(spec) + .unwrap() + .get(0) + .unwrap() + .type_name, + expected_name, + "{spec}" + ); + assert_eq!( + result.variables.get(spec).unwrap().get(0).unwrap().op_sym, + op_sym, + "{spec}" + ); + + let got_json = serde_json::to_string_pretty(&result.variables).unwrap(); + insta::assert_snapshot!(got_json); + } +} + +#[test] +fn test_list_all_variables() { + let file = PathBuf::from("./src/test_data/test_list_variables/supported.k") + .canonicalize() + .unwrap() + .display() + .to_string(); + let test_cases = vec![ + ("a", "1", "", "="), + ("a1", "2", "", "="), + ("a3", "3m", "", "="), + ("b1", "True", "", "="), + ("b2", "False", "", "="), + ("s1", "\"Hello\"", "", "="), + ( + "array1", + r#"[ + 1 + 2 + 3 +]"#, + "", + "=", + ), + ( + "dict1", + r#"{ + "a": 1 + "b": 2 +}"#, + "", + "=", + ), + ( + "dict2", + r#"{ + "a": 1 + "b": { + "c": 2 + "d": 3 + } +}"#, + "", + "=", + ), + ( + "sha", + r#"A { + name: "Hello" + ids: [1, 2, 3] + data: { + "a": { + "b": { + "c": 2 + } + } + } +}"#, + "A", + "=", + ), + ( + "shb", + r#"B { + a: { + name: "HelloB" + ids: [4, 5, 6] + data: { + "d": { + "e": { + "f": 3 + } + } + } + } +}"#, + "B", + "=", + ), + ( + "job", + r#"Job { + name = "{}-{}".format("app", "test").lower() +}"#, + "Job", + "=", + ), + ( + "select", + r#"a.b.c { + a: 1 +}"#, + "a.b.c", + "=", + ), + ( + "union_list", + r#"[ + *_list0 + *_list1 +]"#, + "", + "=", + ), + ( + "a_dict", + r#"{ + **_part1 + **_part2 +}"#, + "", + "=", + ), + ]; + + for (spec, expected, expected_name, op_sym) in test_cases { + println!("{:?}", spec); + let result = list_variables(vec![file.clone()], vec![], None).unwrap(); + assert_eq!( + result.variables.get(spec).unwrap().get(0).unwrap().value, + expected, + "{spec}" + ); + assert_eq!( + result + .variables + .get(spec) + .unwrap() + .get(0) + .unwrap() + .type_name, + expected_name, + "{spec}" + ); + assert_eq!( + result.variables.get(spec).unwrap().get(0).unwrap().op_sym, + op_sym, + "{spec}" + ); + assert_eq!(result.parse_errors.len(), 0); + + let got_json = serde_json::to_string_pretty(&result.variables).unwrap(); + insta::assert_snapshot!(got_json); + } +} + +#[test] +fn test_list_unsupported_variables() { + let file = PathBuf::from("./src/test_data/test_list_variables/unsupported.k") + .canonicalize() + .unwrap() + .display() + .to_string(); + + // test unsupport code + let test_cases = vec![ + ("list", "[_x for _x in range(20) if _x % 2 == 0]"), + ("list1", "[i if i > 2 else i + 1 for i in [1, 2, 3]]"), + ("dict", "{str(i): 2 * i for i in range(3)}"), + ( + "func", + r#"lambda x: int, y: int -> int { + x + y +}"#, + ), + ( + "if_schema.falseValue", + "if True:\n trueValue: 1\nelse:\n falseValue: 2", + ), + ( + "if_schema.trueValue", + "if True:\n trueValue: 1\nelse:\n falseValue: 2", + ), + ]; + + for (spec, expected_code) in test_cases { + let specs = vec![spec.to_string()]; + let result = list_variables(vec![file.clone()], specs, None).unwrap(); + assert_eq!(result.variables.get(spec), None); + assert_eq!(result.unsupported[0].code, expected_code); + assert_eq!(result.parse_errors.len(), 0); + } + + // test list variables from unsupported code + let test_cases = vec![ + ("if_schema.name", r#""name""#), + ("if_schema.age", "1"), + ( + "if_schema.inner", + r#"IfSchemaInner { + innerValue: 1 +}"#, + ), + ("if_schema.inner.innerValue", "1"), + ( + "if_schema.inner2", + r#"{ + innerValue: 2 +}"#, + ), + ("if_schema.inner2.innerValue", "2"), + ("if_schema1.name", r#""name""#), + ("if_schema1.age", "1"), + ( + "if_schema1.inner", + r#"IfSchemaInner { + innerValue: 1 +}"#, + ), + ("if_schema1.inner.innerValue", "1"), + ( + "if_schema1.inner2", + r#"{ + innerValue: 2 +}"#, + ), + ("if_schema1.inner2.innerValue", "2"), + ]; + + for (spec, expected_code) in test_cases { + let specs = vec![spec.to_string()]; + let result = list_variables(vec![file.clone()], specs, None).unwrap(); + assert_eq!( + result.variables.get(spec).unwrap().get(0).unwrap().value, + expected_code, + "{spec}", + ); + } +} + +#[test] +fn test_override_file_insert() { + let specs = vec![ + r#"b={ + "c": 2 + }"# + .to_string(), + r#"c.b={"a": "b"}"#.to_string(), + r#"d.e.f.g=3"#.to_string(), + r#"_access3=test.ServiceAccess { + iType = "kkkkkkk" + sType = dsType + TestStr = ["${test_str}"] + ports = [80, 443] + booltest = True +}"# + .to_string(), + r#"_access4=test.ServiceAccess { + iType = "kkkkkkk" + sType = dsType + TestStr = ["${test_str}"] + ports = [80, 443] + booltest = True +}"# + .to_string(), + r#"_access.iType="kkkkkkk""#.to_string(), + r#"_access5.iType="dddddd""#.to_string(), + r#"a=b"#.to_string(), + r#"_access6 ="a6""#.to_string(), + r#"_access.mergedattr=1"#.to_string(), + r#"_access.a.b.c=2"#.to_string(), + r#"_access.a.c.b=3"#.to_string(), + ]; + + let simple_path = get_test_dir("test_override_file/main.k".to_string()); + let simple_bk_path = get_test_dir("test_override_file/main.bk.k".to_string()); + let expect_path = get_test_dir("test_override_file/expect.k".to_string()); + fs::copy(simple_bk_path.clone(), simple_path.clone()).unwrap(); + let import_paths = vec![ + "base.pkg.kusion_models.app".to_string(), + "base.pkg.kusion_models.app.vip as vip".to_string(), + "base.pkg.kusion_models.app.container".to_string(), + "base.pkg.kusion_models.app.resource as res".to_string(), + "base.pkg.kusion_models.app.sidecar".to_string(), + ".values".to_string(), + ]; + + // test insert multiple times + for _ in 1..=5 { + assert_eq!( + override_file(&simple_path.display().to_string(), &specs, &import_paths) + .unwrap() + .result, + true + ); + + let simple_content = fs::read_to_string(simple_path.clone()).unwrap(); + let expect_content = fs::read_to_string(expect_path.clone()).unwrap(); + + let simple_content = simple_content.replace("\r\n", "\n"); + let expect_content = expect_content.replace("\r\n", "\n"); + + assert_eq!(simple_content, expect_content); + } + + fs::copy(simple_bk_path.clone(), simple_path.clone()).unwrap(); +} + +#[test] +fn test_list_variable_with_invalid_kcl() { + let file = PathBuf::from("./src/test_data/test_list_variables/invalid.k") + .canonicalize() + .unwrap() + .display() + .to_string(); + let specs = vec!["a".to_string()]; + let result = list_variables(vec![file.clone()], specs, None).unwrap(); + assert_eq!(result.variables.get("a"), None); + assert_eq!(result.parse_errors.len(), 2); + assert_eq!(result.parse_errors[0].level, Level::Error); + assert_eq!( + result.parse_errors[0].code, + Some(DiagnosticId::Error(ErrorKind::InvalidSyntax)) + ); + assert_eq!( + result.parse_errors[0].messages[0].message, + "expected one of [\"=\"] got eof", + ); + assert_eq!( + result.parse_errors[0].messages[0].range.0.filename, + file.adjust_canonicalization() + ); + assert_eq!(result.parse_errors[0].messages[0].range.0.line, 1); + assert_eq!(result.parse_errors[0].messages[0].range.0.column, Some(8)); +} + +#[test] +fn test_overridefile_with_invalid_kcl() { + let simple_path = get_test_dir("test_override_file/invalid.k".to_string()); + let simple_bk_path = get_test_dir("invalid.bk.k".to_string()); + fs::copy(simple_bk_path.clone(), simple_path.clone()).unwrap(); + + let result = override_file( + &simple_path.display().to_string(), + &vec!["a=b".to_string()], + &vec![], + ) + .unwrap(); + + fs::copy(simple_bk_path.clone(), simple_path.clone()).unwrap(); + assert_eq!(result.result, true); + assert_eq!(result.parse_errors.len(), 2); + assert_eq!(result.parse_errors[0].level, Level::Error); + assert_eq!( + result.parse_errors[0].code, + Some(DiagnosticId::Error(ErrorKind::InvalidSyntax)) + ); + assert_eq!( + result.parse_errors[0].messages[0].message, + "expected one of [\"=\"] got eof" + ); + assert_eq!( + result.parse_errors[0].messages[0] + .range + .0 + .filename + .adjust_canonicalization(), + simple_path.display().to_string().adjust_canonicalization() + ); + assert_eq!(result.parse_errors[0].messages[0].range.0.line, 1); + assert_eq!(result.parse_errors[0].messages[0].range.0.column, Some(8)); +} + +#[test] +fn test_list_variables_with_file_noexist() { + let file = PathBuf::from("./src/test_data/test_list_variables/noexist.k") + .display() + .to_string(); + let specs = vec!["a".to_string()]; + let result = list_variables(vec![file.clone()], specs, None); + assert!(result.is_err()); + let err = result.err().unwrap(); + assert_eq!(err.to_string(), "Cannot find the kcl file, please check the file path ./src/test_data/test_list_variables/noexist.k"); +} + +#[test] +fn test_override_file_with_invalid_spec() { + let specs = vec!["....".to_string()]; + let import_paths = vec![]; + let file = PathBuf::from("./src/test_data/test_override_file/main.k") + .canonicalize() + .unwrap() + .display() + .to_string(); + let result = override_file(&file, &specs, &import_paths); + assert!(result.is_err()); + let err = result.err().unwrap(); + assert_eq!(err.to_string(), "Invalid spec format '....', expected =filed_value>, :filed_value>, +=filed_value> or -"); +} + +#[test] +fn test_list_merged_variables() { + let file = PathBuf::from("./src/test_data/test_list_variables/test_list_merged_variables") + .canonicalize() + .unwrap(); + + file.join("path").display().to_string(); + + let test_cases = vec![ + ( + vec![ + file.join("merge_1/base.k").display().to_string(), + file.join("merge_1/main.k").display().to_string(), + ], + vec!["appConfiguration.resource".to_string()], + vec![r#"res.Resource {cpu = "2", disk = "35Gi", memory = "4Gi"}"#.to_string()], + ), + ( + vec![ + file.join("merge_2/base.k").display().to_string(), + file.join("merge_2/main.k").display().to_string(), + ], + vec!["appConfiguration.resource".to_string()], + vec![r#"res.Resource { + cpu = "2" + memory = "4Gi" +}"#.to_string()], + ), + ( + vec![ + file.join("merge_3/base.k").display().to_string(), + file.join("merge_3/main.k").display().to_string(), + ], + vec!["appConfiguration.resource".to_string()], + vec![r#"res.Resource {cpu = "2", disk = "35Gi", memory = "4Gi"}"#.to_string()], + ), + ( + vec![ + file.join("merge_4/base.k").display().to_string(), + file.join("merge_4/main.k").display().to_string(), + ], + vec!["appConfiguration.resource".to_string()], + vec![r#"res.Resource { + cpu = "2" + memory = "4Gi" +}"#.to_string()], + ), + ( + vec![ + file.join("merge_5/base.k").display().to_string(), + file.join("merge_5/main.k").display().to_string(), + ], + vec!["appConfiguration.resource".to_string()], + vec![r#"res.Resource {cpu = {limit: "200m", limit_plus: "20000m", request: "100m"}, disk = "35Gi", memory = "4Gi"}"#.to_string()], + ), + ( + vec![ + file.join("merge_6/main.k").display().to_string(), + file.join("merge_6/base.k").display().to_string(), + ], + vec!["config".to_string()], + vec![r#"Config { + name = "config2" + args: ["kcl", "main.k"] + labels: {key1: "value1"} +}"#.to_string()], + ), + ( + vec![ + file.join("merge_7/main.k").display().to_string(), + file.join("merge_7/base.k").display().to_string(), + ], + vec!["config".to_string()], + vec![r#"Config { + name = _NAME + args: ["kcl", "main.k"] + labels: {key1: "value1"} +}"#.to_string()], + ), + ( + vec![ + file.join("merge_8/main.k").display().to_string(), + ], + vec!["config".to_string()], + vec![r#"Config { + args: [ + "kcl" + "main.k" + ] + labels: { + key1: "value1" + } + labels: { + key2: "value2" + } + "labels": { + "key3": "value3" + } +}"#.to_string()], + ), + ( + vec![ + file.join("merge_9/main.k").display().to_string(), + ], + vec!["config".to_string()], + vec![r#"Config { + args: [ + "kcl" + "main.k" + ] + labels: { + key1: "value1" + } + labels: { + key2: "value2" + } + name: { + name: { + name: "name" + } + } + name: { + name: Name0 {data: 1} + } +}"#.to_string()], + ), + ( + vec![ + file.join("merge_10/main.k").display().to_string(), + ], + vec!["alice.hc".to_string()], + vec![r#"[ + 2 +]"#.to_string()], + ), + ( + vec![ + file.join("merge_11/main.k").display().to_string(), + ], + vec!["config.main".to_string()], + vec![r#"Main {args: ["1"], env: ["789", "456"]}"#.to_string()], + ), + ]; + + for (files, specs, expected_values) in test_cases { + println!("{:?}", files); + let result = list_variables( + files, + specs.clone(), + Some(&ListOptions { + merge_program: true, + }), + ) + .unwrap(); + for (i, expected_value) in expected_values.iter().enumerate() { + let variables = result + .variables + .get(&specs.get(i).unwrap().to_string()) + .unwrap(); + assert_eq!(variables.len(), 1); + for variable in variables { + assert_eq!(variable.value.to_string(), expected_value.to_string()); + } + } + } +} diff --git a/kclvm/query/src/util.rs b/kclvm/query/src/util.rs new file mode 100644 index 000000000..9c3ffffb4 --- /dev/null +++ b/kclvm/query/src/util.rs @@ -0,0 +1,38 @@ +use anyhow::{anyhow, Result}; + +/// Get field package path and identifier name from the path. +/// (TODO: Needs to be a package related to the language specification +/// and move this function into it.) +/// +/// split_field_path("pkg.to.path:field") -> ("pkg.to.path", "field") +pub(crate) fn split_field_path(path: &str) -> Result<(String, String)> { + let err = Err(anyhow!("Invalid field path {:?}", path)); + let paths = path.splitn(2, ':').collect::>(); + let (pkgpath, field_path) = if paths.len() == 1 { + ("".to_string(), paths[0].to_string()) + } else if paths.len() == 2 { + (paths[0].to_string(), paths[1].to_string()) + } else { + return err; + }; + if field_path.is_empty() { + err + } else { + Ok((pkgpath, field_path)) + } +} + +/// Get the invalid spec error message. +#[inline] +pub(crate) fn invalid_spec_error(spec: &str) -> anyhow::Error { + anyhow!("Invalid spec format '{}', expected =filed_value>, :filed_value>, +=filed_value> or -", spec) +} + +/// Get the invalid symbol selector spec error message. +#[inline] +pub(crate) fn invalid_symbol_selector_spec_error(spec: &str) -> anyhow::Error { + anyhow!( + "Invalid spec format '{}', expected :", + spec + ) +} diff --git a/kclvm/runner/Cargo.lock b/kclvm/runner/Cargo.lock deleted file mode 100644 index b90f4cf39..000000000 --- a/kclvm/runner/Cargo.lock +++ /dev/null @@ -1,1658 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "ahash" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" -dependencies = [ - "getrandom", - "once_cell", - "version_check", -] - -[[package]] -name = "aho-corasick" -version = "0.7.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" -dependencies = [ - "memchr", -] - -[[package]] -name = "annotate-snippets" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d78ea013094e5ea606b1c05fe35f1dd7ea1eb1ea259908d040b25bd5ec677ee5" - -[[package]] -name = "ansi_term" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" -dependencies = [ - "winapi", -] - -[[package]] -name = "arrayvec" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6" - -[[package]] -name = "atty" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" -dependencies = [ - "hermit-abi", - "libc", - "winapi", -] - -[[package]] -name = "autocfg" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" - -[[package]] -name = "base64" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" - -[[package]] -name = "bit-set" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e11e16035ea35e4e5997b393eacbf6f63983188f7a2ad25bfb13465f5ad59de" -dependencies = [ - "bit-vec", -] - -[[package]] -name = "bit-vec" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "block-buffer" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" -dependencies = [ - "generic-array", -] - -[[package]] -name = "block-buffer" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bf7fe51849ea569fd452f37822f606a5cabb684dc918707a0193fd4664ff324" -dependencies = [ - "generic-array", -] - -[[package]] -name = "bstr" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223" -dependencies = [ - "lazy_static", - "memchr", - "regex-automata", -] - -[[package]] -name = "cc" -version = "1.0.73" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" - -[[package]] -name = "cfg-if" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "chrono" -version = "0.4.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73" -dependencies = [ - "libc", - "num-integer", - "num-traits", - "time", - "winapi", -] - -[[package]] -name = "clap" -version = "2.34.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" -dependencies = [ - "ansi_term", - "atty", - "bitflags", - "strsim", - "textwrap", - "unicode-width", - "vec_map", -] - -[[package]] -name = "cpufeatures" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59a6001667ab124aebae2a495118e11d30984c3a653e99d86d58971708cf5e4b" -dependencies = [ - "libc", -] - -[[package]] -name = "crossbeam-deque" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e" -dependencies = [ - "cfg-if 1.0.0", - "crossbeam-epoch", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-epoch" -version = "0.9.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1145cf131a2c6ba0615079ab6a638f7e1973ac9c2634fcbeaaad6114246efe8c" -dependencies = [ - "autocfg", - "cfg-if 1.0.0", - "crossbeam-utils", - "lazy_static", - "memoffset", - "scopeguard", -] - -[[package]] -name = "crossbeam-utils" -version = "0.8.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bf124c720b7686e3c2663cf54062ab0f68a88af2fb6a030e87e30bf721fcb38" -dependencies = [ - "cfg-if 1.0.0", - "lazy_static", -] - -[[package]] -name = "crypto-common" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57952ca27b5e3606ff4dd79b0020231aaf9d6aa76dc05fd30137538c50bd3ce8" -dependencies = [ - "generic-array", - "typenum", -] - -[[package]] -name = "digest" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" -dependencies = [ - "generic-array", -] - -[[package]] -name = "digest" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2fb860ca6fafa5552fb6d0e816a69c8e49f0908bf524e30a90d97c85892d506" -dependencies = [ - "block-buffer 0.10.2", - "crypto-common", -] - -[[package]] -name = "either" -version = "1.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" - -[[package]] -name = "ena" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7402b94a93c24e742487327a7cd839dc9d36fec9de9fb25b09f2dae459f36c3" -dependencies = [ - "log", -] - -[[package]] -name = "enquote" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06c36cb11dbde389f4096111698d8b567c0720e3452fd5ac3e6b4e47e1939932" -dependencies = [ - "thiserror", -] - -[[package]] -name = "fancy-regex" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d6b8560a05112eb52f04b00e5d3790c0dd75d9d980eb8a122fb23b92a623ccf" -dependencies = [ - "bit-set", - "regex", -] - -[[package]] -name = "fastrand" -version = "1.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3fcf0cee53519c866c09b5de1f6c56ff9d647101f81c1964fa632e148896cdf" -dependencies = [ - "instant", -] - -[[package]] -name = "fixedbitset" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "279fb028e20b3c4c320317955b77c5e0c9701f05a1d309905d6fc702cdc5053e" - -[[package]] -name = "fslock" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04412b8935272e3a9bae6f48c7bfff74c2911f60525404edfdd28e49884c3bfb" -dependencies = [ - "libc", - "winapi", -] - -[[package]] -name = "fuchsia-cprng" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" - -[[package]] -name = "gcc" -version = "0.3.55" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f5f3913fa0bfe7ee1fd8248b6b9f42a5af4b9d65ec2dd2c3c26132b950ecfc2" - -[[package]] -name = "generic-array" -version = "0.14.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd48d33ec7f05fbfa152300fdad764757cbded343c1aa1cff2fbaf4134851803" -dependencies = [ - "typenum", - "version_check", -] - -[[package]] -name = "getrandom" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9be70c98951c83b8d2f8f60d7065fa6d5146873094452a1008da8c2f1e4205ad" -dependencies = [ - "cfg-if 1.0.0", - "libc", - "wasi", -] - -[[package]] -name = "glob" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" - -[[package]] -name = "hashbrown" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" - -[[package]] -name = "hermit-abi" -version = "0.1.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" -dependencies = [ - "libc", -] - -[[package]] -name = "indexmap" -version = "1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f647032dfaa1f8b6dc29bd3edb7bbef4861b8b8007ebb118d6db284fd59f6ee" -dependencies = [ - "autocfg", - "hashbrown", - "rustc-rayon", -] - -[[package]] -name = "inkwell" -version = "0.1.0" -source = "git+https://github.com/TheDan64/inkwell?branch=master#bff378bee02bcbb5bed35f47e9ed69e6642e9188" -dependencies = [ - "either", - "inkwell_internals", - "libc", - "llvm-sys", - "once_cell", - "parking_lot", -] - -[[package]] -name = "inkwell_internals" -version = "0.5.0" -source = "git+https://github.com/TheDan64/inkwell?branch=master#bff378bee02bcbb5bed35f47e9ed69e6642e9188" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "instant" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" -dependencies = [ - "cfg-if 1.0.0", -] - -[[package]] -name = "itertools" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3" -dependencies = [ - "either", -] - -[[package]] -name = "itoa" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35" - -[[package]] -name = "jobserver" -version = "0.1.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af25a77299a7f711a01975c35a6a424eb6862092cc2d6c72c4ed6cbc56dfc1fa" -dependencies = [ - "libc", -] - -[[package]] -name = "json_minimal" -version = "0.1.3" - -[[package]] -name = "kclvm-ast" -version = "0.1.0" -dependencies = [ - "kclvm-span", - "rustc_span", - "serde", - "serde_json", -] - -[[package]] -name = "kclvm-compiler" -version = "0.1.0" -dependencies = [ - "ahash", - "bit-set", - "bitflags", - "fancy-regex", - "indexmap", - "inkwell", - "kclvm-ast", - "kclvm-error", - "kclvm-runtime", - "kclvm-sema", - "once_cell", - "phf", - "time", - "unicode_names2", -] - -[[package]] -name = "kclvm-config" -version = "0.1.0" -dependencies = [ - "ahash", - "chrono", - "fslock", - "glob", - "indexmap", - "kclvm-version", - "pathdiff", - "ron", - "rust-crypto", - "serde", - "serde_yaml", - "toml", -] - -[[package]] -name = "kclvm-error" -version = "0.1.0" -dependencies = [ - "annotate-snippets", - "atty", - "indexmap", - "kclvm-runtime", - "kclvm-span", - "rustc_span", - "termcolor", - "termize", - "tracing", -] - -[[package]] -name = "kclvm-lexer" -version = "0.1.0" -dependencies = [ - "kclvm-error", - "rustc_lexer", - "unic-emoji-char", -] - -[[package]] -name = "kclvm-macros" -version = "0.1.0" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "synstructure", -] - -[[package]] -name = "kclvm-parser" -version = "0.1.0" -dependencies = [ - "bstr", - "either", - "enquote", - "kclvm-ast", - "kclvm-config", - "kclvm-error", - "kclvm-lexer", - "kclvm-runtime", - "kclvm-sema", - "kclvm-span", - "num-bigint", - "rustc_data_structures", - "rustc_lexer", - "rustc_span", - "serde", - "serde_json", - "tracing", - "unicode_names2", -] - -[[package]] -name = "kclvm-runner" -version = "0.1.0" -dependencies = [ - "clap", - "fslock", - "glob", - "indexmap", - "kclvm-ast", - "kclvm-compiler", - "kclvm-config", - "kclvm-parser", - "kclvm-runtime", - "kclvm-sema", - "kclvm-version", - "libc", - "libloading", - "serde", - "serde_json", - "walkdir", -] - -[[package]] -name = "kclvm-runtime" -version = "0.1.0" -dependencies = [ - "ahash", - "base64", - "bstr", - "chrono", - "fancy-regex", - "indexmap", - "itertools", - "json_minimal", - "kclvm_runtime_internal_macros", - "libc", - "md5", - "num-integer", - "phf", - "regex", - "serde", - "serde_json", - "serde_yaml", - "sha1", - "sha2 0.9.9", - "unic-ucd-bidi", - "unic-ucd-category", - "unicode-casing", -] - -[[package]] -name = "kclvm-sema" -version = "0.1.0" -dependencies = [ - "ahash", - "bit-set", - "bitflags", - "fancy-regex", - "indexmap", - "kclvm-ast", - "kclvm-error", - "kclvm-runtime", - "kclvm-span", - "once_cell", - "petgraph", - "phf", - "unicode_names2", -] - -[[package]] -name = "kclvm-span" -version = "0.1.0" -dependencies = [ - "kclvm-macros", - "rustc_span", - "scoped-tls", -] - -[[package]] -name = "kclvm-version" -version = "0.1.0" - -[[package]] -name = "kclvm_runtime_internal_macros" -version = "0.1.0" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "lazy_static" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" - -[[package]] -name = "libc" -version = "0.2.125" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5916d2ae698f6de9bfb891ad7a8d65c09d232dc58cc4ac433c7da3b2fd84bc2b" - -[[package]] -name = "libloading" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efbc0f03f9a775e9f6aed295c6a1ba2253c5757a9e03d55c6caa46a681abcddd" -dependencies = [ - "cfg-if 1.0.0", - "winapi", -] - -[[package]] -name = "linked-hash-map" -version = "0.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fb9b38af92608140b86b693604b9ffcc5824240a484d1ecd4795bacb2fe88f3" - -[[package]] -name = "llvm-sys" -version = "120.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09b716322964966a62377cf86e64f00ca7043505fdf27bd2ec7d41ae6682d1e7" -dependencies = [ - "cc", - "lazy_static", - "libc", - "regex", - "semver", -] - -[[package]] -name = "lock_api" -version = "0.4.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "327fa5b6a6940e4699ec49a9beae1ea4845c6bab9314e4f84ac68742139d8c53" -dependencies = [ - "autocfg", - "scopeguard", -] - -[[package]] -name = "log" -version = "0.4.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" -dependencies = [ - "cfg-if 1.0.0", -] - -[[package]] -name = "matches" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" - -[[package]] -name = "md-5" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "658646b21e0b72f7866c7038ab086d3d5e1cd6271f060fd37defb241949d0582" -dependencies = [ - "digest 0.10.3", -] - -[[package]] -name = "md5" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "490cc448043f947bae3cbee9c203358d62dbee0db12107a74be5c30ccfd09771" - -[[package]] -name = "memchr" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" - -[[package]] -name = "memmap2" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "723e3ebdcdc5c023db1df315364573789f8857c11b631a2fdfad7c00f5c046b4" -dependencies = [ - "libc", -] - -[[package]] -name = "memoffset" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" -dependencies = [ - "autocfg", -] - -[[package]] -name = "num-bigint" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f" -dependencies = [ - "autocfg", - "num-integer", - "num-traits", -] - -[[package]] -name = "num-integer" -version = "0.1.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" -dependencies = [ - "autocfg", - "num-traits", -] - -[[package]] -name = "num-traits" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" -dependencies = [ - "autocfg", -] - -[[package]] -name = "num_cpus" -version = "1.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" -dependencies = [ - "hermit-abi", - "libc", -] - -[[package]] -name = "once_cell" -version = "1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87f3e037eac156d1775da914196f0f37741a274155e34a0b7e427c35d2a2ecb9" - -[[package]] -name = "opaque-debug" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" - -[[package]] -name = "parking_lot" -version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87f5ec2493a61ac0506c0f4199f99070cbe83857b0337006a30f3e6719b8ef58" -dependencies = [ - "lock_api", - "parking_lot_core", -] - -[[package]] -name = "parking_lot_core" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09a279cbf25cb0757810394fbc1e359949b59e348145c643a939a525692e6929" -dependencies = [ - "cfg-if 1.0.0", - "libc", - "redox_syscall", - "smallvec", - "windows-sys", -] - -[[package]] -name = "pathdiff" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd" - -[[package]] -name = "pest" -version = "2.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10f4872ae94d7b90ae48754df22fd42ad52ce740b8f370b03da4835417403e53" -dependencies = [ - "ucd-trie", -] - -[[package]] -name = "petgraph" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a13a2fa9d0b63e5f22328828741e523766fff0ee9e779316902290dff3f824f" -dependencies = [ - "fixedbitset", - "indexmap", -] - -[[package]] -name = "phf" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2ac8b67553a7ca9457ce0e526948cad581819238f4a9d1ea74545851fa24f37" -dependencies = [ - "phf_macros", - "phf_shared", - "proc-macro-hack", -] - -[[package]] -name = "phf_generator" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d43f3220d96e0080cc9ea234978ccd80d904eafb17be31bb0f76daaea6493082" -dependencies = [ - "phf_shared", - "rand 0.8.5", -] - -[[package]] -name = "phf_macros" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b706f5936eb50ed880ae3009395b43ed19db5bff2ebd459c95e7bf013a89ab86" -dependencies = [ - "phf_generator", - "phf_shared", - "proc-macro-hack", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "phf_shared" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a68318426de33640f02be62b4ae8eb1261be2efbc337b60c54d845bf4484e0d9" -dependencies = [ - "siphasher", -] - -[[package]] -name = "pin-project-lite" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" - -[[package]] -name = "ppv-lite86" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" - -[[package]] -name = "proc-macro-hack" -version = "0.5.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" - -[[package]] -name = "proc-macro2" -version = "1.0.38" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9027b48e9d4c9175fa2218adf3557f91c1137021739951d4932f5f8268ac48aa" -dependencies = [ - "unicode-xid", -] - -[[package]] -name = "psm" -version = "0.1.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "871372391786ccec00d3c5d3d6608905b3d4db263639cfe075d3b60a736d115a" -dependencies = [ - "cc", -] - -[[package]] -name = "quote" -version = "1.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "rand" -version = "0.3.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64ac302d8f83c0c1974bf758f6b041c6c8ada916fbb44a609158ca8b064cc76c" -dependencies = [ - "libc", - "rand 0.4.6", -] - -[[package]] -name = "rand" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" -dependencies = [ - "fuchsia-cprng", - "libc", - "rand_core 0.3.1", - "rdrand", - "winapi", -] - -[[package]] -name = "rand" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" -dependencies = [ - "libc", - "rand_chacha", - "rand_core 0.6.3", -] - -[[package]] -name = "rand_chacha" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" -dependencies = [ - "ppv-lite86", - "rand_core 0.6.3", -] - -[[package]] -name = "rand_core" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" -dependencies = [ - "rand_core 0.4.2", -] - -[[package]] -name = "rand_core" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" - -[[package]] -name = "rand_core" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" -dependencies = [ - "getrandom", -] - -[[package]] -name = "rdrand" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" -dependencies = [ - "rand_core 0.3.1", -] - -[[package]] -name = "redox_syscall" -version = "0.2.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42" -dependencies = [ - "bitflags", -] - -[[package]] -name = "regex" -version = "1.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a11647b6b25ff05a515cb92c365cec08801e83423a235b51e231e1808747286" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] - -[[package]] -name = "regex-automata" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" - -[[package]] -name = "regex-syntax" -version = "0.6.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" - -[[package]] -name = "remove_dir_all" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" -dependencies = [ - "winapi", -] - -[[package]] -name = "ron" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b861ecaade43ac97886a512b360d01d66be9f41f3c61088b42cedf92e03d678" -dependencies = [ - "base64", - "bitflags", - "serde", -] - -[[package]] -name = "rust-crypto" -version = "0.2.36" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f76d05d3993fd5f4af9434e8e436db163a12a9d40e1a58a726f27a01dfd12a2a" -dependencies = [ - "gcc", - "libc", - "rand 0.3.23", - "rustc-serialize", - "time", -] - -[[package]] -name = "rustc-hash" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" - -[[package]] -name = "rustc-rayon" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9974ab223660e61c1b4e7b43b827379df286736ca988308ce7e16f59f2d89246" -dependencies = [ - "crossbeam-deque", - "either", - "rustc-rayon-core", -] - -[[package]] -name = "rustc-rayon-core" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "564bfd27be8db888d0fa76aa4335e7851aaed0c2c11ad1e93aeb9349f6b88500" -dependencies = [ - "crossbeam-deque", - "crossbeam-utils", - "lazy_static", - "num_cpus", -] - -[[package]] -name = "rustc-serialize" -version = "0.3.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda" - -[[package]] -name = "rustc_data_structures" -version = "0.0.0" -dependencies = [ - "arrayvec", - "bitflags", - "cfg-if 0.1.10", - "ena", - "indexmap", - "jobserver", - "libc", - "memmap2", - "parking_lot", - "rustc-hash", - "rustc-rayon", - "rustc-rayon-core", - "stable_deref_trait", - "stacker", - "tempfile", - "tracing", - "winapi", -] - -[[package]] -name = "rustc_lexer" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c86aae0c77166108c01305ee1a36a1e77289d7dc6ca0a3cd91ff4992de2d16a5" -dependencies = [ - "unicode-xid", -] - -[[package]] -name = "rustc_span" -version = "0.0.0" -dependencies = [ - "cfg-if 0.1.10", - "md-5", - "rustc_data_structures", - "scoped-tls", - "sha-1", - "sha2 0.10.2", - "tracing", - "unicode-width", -] - -[[package]] -name = "ryu" -version = "1.0.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f" - -[[package]] -name = "same-file" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" -dependencies = [ - "winapi-util", -] - -[[package]] -name = "scoped-tls" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2" - -[[package]] -name = "scopeguard" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" - -[[package]] -name = "semver" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6" -dependencies = [ - "semver-parser", -] - -[[package]] -name = "semver-parser" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0bef5b7f9e0df16536d3961cfb6e84331c065b4066afb39768d0e319411f7" -dependencies = [ - "pest", -] - -[[package]] -name = "serde" -version = "1.0.137" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61ea8d54c77f8315140a05f4c7237403bf38b72704d031543aa1d16abbf517d1" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.137" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f26faba0c3959972377d3b2d306ee9f71faee9714294e41bb777f83f88578be" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "serde_json" -version = "1.0.81" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b7ce2b32a1aed03c558dc61a5cd328f15aff2dbc17daad8fb8af04d2100e15c" -dependencies = [ - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "serde_yaml" -version = "0.8.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "707d15895415db6628332b737c838b88c598522e4dc70647e59b72312924aebc" -dependencies = [ - "indexmap", - "ryu", - "serde", - "yaml-rust", -] - -[[package]] -name = "sha-1" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "028f48d513f9678cda28f6e4064755b3fbb2af6acd672f2c209b62323f7aea0f" -dependencies = [ - "cfg-if 1.0.0", - "cpufeatures", - "digest 0.10.3", -] - -[[package]] -name = "sha1" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1da05c97445caa12d05e848c4a4fcbbea29e748ac28f7e80e9b010392063770" -dependencies = [ - "sha1_smol", -] - -[[package]] -name = "sha1_smol" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae1a47186c03a32177042e55dbc5fd5aee900b8e0069a8d70fba96a9375cd012" - -[[package]] -name = "sha2" -version = "0.9.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" -dependencies = [ - "block-buffer 0.9.0", - "cfg-if 1.0.0", - "cpufeatures", - "digest 0.9.0", - "opaque-debug", -] - -[[package]] -name = "sha2" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55deaec60f81eefe3cce0dc50bda92d6d8e88f2a27df7c5033b42afeb1ed2676" -dependencies = [ - "cfg-if 1.0.0", - "cpufeatures", - "digest 0.10.3", -] - -[[package]] -name = "siphasher" -version = "0.3.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7bd3e3206899af3f8b12af284fafc038cc1dc2b41d1b89dd17297221c5d225de" - -[[package]] -name = "smallvec" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83" - -[[package]] -name = "stable_deref_trait" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" - -[[package]] -name = "stacker" -version = "0.1.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90939d5171a4420b3ff5fbc8954d641e7377335454c259dcb80786f3f21dc9b4" -dependencies = [ - "cc", - "cfg-if 1.0.0", - "libc", - "psm", - "winapi", -] - -[[package]] -name = "strsim" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" - -[[package]] -name = "syn" -version = "1.0.92" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ff7c592601f11445996a06f8ad0c27f094a58857c2f89e97974ab9235b92c52" -dependencies = [ - "proc-macro2", - "quote", - "unicode-xid", -] - -[[package]] -name = "synstructure" -version = "0.12.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "unicode-xid", -] - -[[package]] -name = "tempfile" -version = "3.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" -dependencies = [ - "cfg-if 1.0.0", - "fastrand", - "libc", - "redox_syscall", - "remove_dir_all", - "winapi", -] - -[[package]] -name = "termcolor" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" -dependencies = [ - "winapi-util", -] - -[[package]] -name = "termize" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1706be6b564323ce7092f5f7e6b118a14c8ef7ed0e69c8c5329c914a9f101295" -dependencies = [ - "libc", - "winapi", -] - -[[package]] -name = "textwrap" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" -dependencies = [ - "unicode-width", -] - -[[package]] -name = "thiserror" -version = "1.0.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd829fe32373d27f76265620b5309d0340cb8550f523c1dda251d6298069069a" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0396bc89e626244658bef819e22d0cc459e795a5ebe878e6ec336d1674a8d79a" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "time" -version = "0.1.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255" -dependencies = [ - "libc", - "wasi", - "winapi", -] - -[[package]] -name = "toml" -version = "0.5.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d82e1a7758622a465f8cee077614c73484dac5b836c02ff6a40d5d1010324d7" -dependencies = [ - "serde", -] - -[[package]] -name = "tracing" -version = "0.1.34" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d0ecdcb44a79f0fe9844f0c4f33a342cbcbb5117de8001e6ba0dc2351327d09" -dependencies = [ - "cfg-if 1.0.0", - "pin-project-lite", - "tracing-attributes", - "tracing-core", -] - -[[package]] -name = "tracing-attributes" -version = "0.1.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc6b8ad3567499f98a1db7a752b07a7c8c7c7c34c332ec00effb2b0027974b7c" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "tracing-core" -version = "0.1.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f54c8ca710e81886d498c2fd3331b56c93aa248d49de2222ad2742247c60072f" -dependencies = [ - "lazy_static", -] - -[[package]] -name = "typenum" -version = "1.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" - -[[package]] -name = "ucd-trie" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c" - -[[package]] -name = "unic-char-property" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8c57a407d9b6fa02b4795eb81c5b6652060a15a7903ea981f3d723e6c0be221" -dependencies = [ - "unic-char-range", -] - -[[package]] -name = "unic-char-range" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0398022d5f700414f6b899e10b8348231abf9173fa93144cbc1a43b9793c1fbc" - -[[package]] -name = "unic-common" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80d7ff825a6a654ee85a63e80f92f054f904f21e7d12da4e22f9834a4aaa35bc" - -[[package]] -name = "unic-emoji-char" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b07221e68897210270a38bde4babb655869637af0f69407f96053a34f76494d" -dependencies = [ - "unic-char-property", - "unic-char-range", - "unic-ucd-version", -] - -[[package]] -name = "unic-ucd-bidi" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1d568b51222484e1f8209ce48caa6b430bf352962b877d592c29ab31fb53d8c" -dependencies = [ - "unic-char-property", - "unic-char-range", - "unic-ucd-version", -] - -[[package]] -name = "unic-ucd-category" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b8d4591f5fcfe1bd4453baaf803c40e1b1e69ff8455c47620440b46efef91c0" -dependencies = [ - "matches", - "unic-char-property", - "unic-char-range", - "unic-ucd-version", -] - -[[package]] -name = "unic-ucd-version" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96bd2f2237fe450fcd0a1d2f5f4e91711124f7857ba2e964247776ebeeb7b0c4" -dependencies = [ - "unic-common", -] - -[[package]] -name = "unicode-casing" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "623f59e6af2a98bdafeb93fa277ac8e1e40440973001ca15cf4ae1541cd16d56" - -[[package]] -name = "unicode-width" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" - -[[package]] -name = "unicode-xid" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "957e51f3646910546462e67d5f7599b9e4fb8acdd304b087a6494730f9eebf04" - -[[package]] -name = "unicode_names2" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87d6678d7916394abad0d4b19df4d3802e1fd84abd7d701f39b75ee71b9e8cf1" - -[[package]] -name = "vec_map" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" - -[[package]] -name = "version_check" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" - -[[package]] -name = "walkdir" -version = "2.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" -dependencies = [ - "same-file", - "winapi", - "winapi-util", -] - -[[package]] -name = "wasi" -version = "0.10.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-util" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" -dependencies = [ - "winapi", -] - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "windows-sys" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2" -dependencies = [ - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_msvc", -] - -[[package]] -name = "windows_aarch64_msvc" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" - -[[package]] -name = "windows_i686_gnu" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" - -[[package]] -name = "windows_i686_msvc" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" - -[[package]] -name = "yaml-rust" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85" -dependencies = [ - "linked-hash-map", -] diff --git a/kclvm/runner/Cargo.toml b/kclvm/runner/Cargo.toml index 27190b8ab..9cfe718ab 100644 --- a/kclvm/runner/Cargo.toml +++ b/kclvm/runner/Cargo.toml @@ -1,25 +1,51 @@ [package] name = "kclvm-runner" -version = "0.1.0" +version = "0.11.0" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +[build-dependencies] +cc = "1.0" + [dependencies] -clap = "2.33.3" serde_json = "1.0" serde = { version = "1", features = ["derive"] } glob = "0.3.0" walkdir = "2" libc = "0.2.112" indexmap = "1.0" -fslock = "0.2.1" libloading = "0.7.3" +threadpool = "1.0" +chrono = "0.4.19" +tempfile = "3.5.0" +anyhow = "1.0" +once_cell = "1.10" +cc = "1.0" +uuid = "1.7.0" +compiler_base_session = "0.1.3" +compiler_base_macros = "0.1.1" + +kclvm-ast = {path = "../ast"} +kclvm-parser = {path = "../parser"} +kclvm-compiler = {path = "../compiler"} +kclvm-config = {path = "../config"} +kclvm-runtime = {path = "../runtime"} +kclvm-sema = {path = "../sema"} +kclvm-version = {path = "../version"} +kclvm-error = {path = "../error"} +kclvm-query = {path = "../query"} +kclvm-utils = {path = "../utils"} +kclvm-driver = {path = "../driver"} +kclvm-evaluator = {path = "../evaluator"} + +[dev-dependencies] +kclvm-parser = {path = "../parser"} +criterion = "0.5" + +[[bench]] +name = "bench_runner" +harness = false -kclvm-ast = {path = "../ast", version = "0.1.0"} -kclvm-parser = {path = "../parser", version = "0.1.0"} -kclvm-compiler = {path = "../compiler", version = "0.1.0"} -kclvm-config = {path = "../config", version = "0.1.0"} -kclvm-runtime = {path = "../runtime", version = "0.1.0"} -kclvm-sema = {path = "../sema", version = "0.1.0"} -kclvm-version = {path = "../version", version = "0.1.0"} +[features] +llvm = ["kclvm-compiler/llvm"] diff --git a/kclvm/runner/benches/bench_runner.rs b/kclvm/runner/benches/bench_runner.rs new file mode 100644 index 000000000..399033d4b --- /dev/null +++ b/kclvm/runner/benches/bench_runner.rs @@ -0,0 +1,67 @@ +use anyhow::Result; +use std::path::Path; +use std::sync::Arc; + +use criterion::{criterion_group, criterion_main, Criterion}; +use walkdir::WalkDir; + +use kclvm_parser::{load_program, ParseSession}; +use kclvm_runner::{execute, runner::ExecProgramArgs}; + +const EXEC_DATA_PATH: &str = "./src/exec_data/"; + +pub fn criterion_benchmark(c: &mut Criterion) { + c.bench_function("refactor kclvm-runner", |b| { + b.iter(|| { + let prev_hook = std::panic::take_hook(); + // disable print panic info + std::panic::set_hook(Box::new(|_| {})); + let result = std::panic::catch_unwind(|| { + for file in get_files(EXEC_DATA_PATH, false, true, ".k") { + exec(&file).unwrap(); + } + }); + assert!(result.is_ok()); + std::panic::set_hook(prev_hook); + }) + }); +} + +criterion_group!(benches, criterion_benchmark); +criterion_main!(benches); + +fn exec(file: &str) -> Result { + let mut args = ExecProgramArgs::default(); + args.k_filename_list.push(file.to_string()); + let opts = args.get_load_program_options(); + let sess = Arc::new(ParseSession::default()); + // Load AST program + let program = load_program(sess.clone(), &[file], Some(opts), None) + .unwrap() + .program; + // Resolve ATS, generate libs, link libs and execute. + execute(sess, program, &args).map(|r| r.yaml_result) +} + +/// Get kcl files from path. +fn get_files>( + path: P, + recursively: bool, + sorted: bool, + suffix: &str, +) -> Vec { + let mut files = vec![]; + for entry in WalkDir::new(path).into_iter().filter_map(|e| e.ok()) { + let path = entry.path(); + if path.is_file() { + let file = path.to_str().unwrap(); + if file.ends_with(suffix) && (recursively || entry.depth() == 1) { + files.push(file.to_string()) + } + } + } + if sorted { + files.sort(); + } + files +} diff --git a/kclvm/runner/build.rs b/kclvm/runner/build.rs new file mode 100644 index 000000000..6e02103ba --- /dev/null +++ b/kclvm/runner/build.rs @@ -0,0 +1,11 @@ +fn main() { + setup_target(); +} + +/// Set rustc TARGET to KCLVM_DEFAULT_TARGET +fn setup_target() { + println!( + "cargo:rustc-env=KCLVM_DEFAULT_TARGET={}", + std::env::var("TARGET").unwrap() + ); +} diff --git a/kclvm/runner/src/assembler.rs b/kclvm/runner/src/assembler.rs new file mode 100644 index 000000000..5915fca8e --- /dev/null +++ b/kclvm/runner/src/assembler.rs @@ -0,0 +1,420 @@ +use anyhow::Result; +use compiler_base_macros::bug; +use indexmap::IndexMap; +use kclvm_ast::ast::{self, Program}; +use kclvm_compiler::codegen::{emit_code, EmitOptions, OBJECT_FILE_SUFFIX}; +use kclvm_config::cache::{load_pkg_cache, save_pkg_cache, CacheOption, KCL_CACHE_PATH_ENV_VAR}; +use kclvm_sema::resolver::scope::ProgramScope; +use kclvm_utils::fslock::open_lock_file; +use std::{ + collections::HashMap, + env, + path::{Path, PathBuf}, +}; + +use crate::ExecProgramArgs; + +/// IR code file suffix. +const DEFAULT_IR_FILE: &str = "_a.out"; + +/// LibAssembler trait is used to indicate the general interface +/// that must be implemented when different intermediate codes are assembled +/// into dynamic link libraries. +/// +/// Note: LibAssembler is only for single file kcl program. For multi-file kcl programs, +/// KclvmAssembler is provided to support for multi-file parallel compilation to improve +/// the performance of the compiler. +pub(crate) trait LibAssembler { + /// Add a suffix to the file name according to the file suffix of different intermediate code files. + /// e.g. LLVM IR -> code_file : "/test_dir/test_code_file" -> return : "/test_dir/test_code_file.o" + fn add_code_file_suffix(&self, code_file: &str) -> String; + + /// Return the file suffix of different intermediate code files. + /// e.g. LLVM IR -> return : ".o" + fn get_code_file_suffix(&self) -> String; + + /// Assemble different intermediate codes into object files for single file kcl program. + /// Returns the path of the object file. + /// + /// Inputs: + /// compile_prog: Reference of kcl program ast. + /// + /// "import_names" is import pkgpath and name of kcl program. + /// Type of import_names is "IndexMap>". + /// + /// "kcl_file_name" is the kcl file name string. + /// "import_name" is the name string of import stmt. + /// "import_path" is the path string of import stmt. + /// + /// e.g. "import test/main_pkg as main", "main" is an "import_name". + /// e.g. "import test/main_pkg as main", "test/main_pkg" is an import_path. + /// + /// "code_file" is the filename of the generated intermediate code file. + /// e.g. code_file : "/test_dir/test_code_file" + /// + /// "object_file_path" is the full filename of the generated intermediate code file with suffix. + /// e.g. code_file_path : "/test_dir/test_code_file.o" + /// + /// "arg" is the arguments of the kclvm runtime. + fn assemble( + &self, + compile_prog: &Program, + import_names: IndexMap>, + code_file: &str, + code_file_path: &str, + arg: &ExecProgramArgs, + ) -> Result; + + /// Clean cache lock files. + #[inline] + fn clean_lock_file(&self, path: &str) -> Result<()> { + let lock_path = &format!("{}.lock", self.add_code_file_suffix(path)); + clean_path(lock_path) + } +} + +/// This enum lists all the intermediate code assemblers currently supported by kclvm. +/// Currently only supports assemble llvm intermediate code into dynamic link library. +#[derive(Clone)] +pub(crate) enum KclvmLibAssembler { + LLVM, +} + +/// KclvmLibAssembler is a dispatcher, responsible for calling corresponding methods +/// according to different types of intermediate codes. +/// +/// KclvmLibAssembler implements the LibAssembler trait, +/// and calls the corresponding method according to different assembler. +impl LibAssembler for KclvmLibAssembler { + #[inline] + fn assemble( + &self, + compile_prog: &Program, + import_names: IndexMap>, + code_file: &str, + object_file_path: &str, + args: &ExecProgramArgs, + ) -> Result { + match &self { + KclvmLibAssembler::LLVM => LlvmLibAssembler.assemble( + compile_prog, + import_names, + code_file, + object_file_path, + args, + ), + } + } + + #[inline] + fn add_code_file_suffix(&self, code_file: &str) -> String { + match &self { + KclvmLibAssembler::LLVM => LlvmLibAssembler.add_code_file_suffix(code_file), + } + } + + #[inline] + fn get_code_file_suffix(&self) -> String { + match &self { + KclvmLibAssembler::LLVM => LlvmLibAssembler.get_code_file_suffix(), + } + } +} + +/// LlvmLibAssembler is mainly responsible for assembling the generated LLVM IR into a dynamic link library. +#[derive(Clone)] +pub(crate) struct LlvmLibAssembler; + +impl LlvmLibAssembler { + #[inline] + fn new() -> Self { + Self {} + } +} + +impl Default for LlvmLibAssembler { + #[inline] + fn default() -> Self { + Self::new() + } +} + +/// KclvmLibAssembler implements the LibAssembler trait, +impl LibAssembler for LlvmLibAssembler { + /// "assemble_lib" will call the [kclvm_compiler::codegen::emit_code] + /// to generate the `.o` object file. + #[inline] + fn assemble( + &self, + compile_prog: &Program, + import_names: IndexMap>, + code_file: &str, + object_file_path: &str, + arg: &ExecProgramArgs, + ) -> Result { + // Clean the existed "*.o" object file. + clean_path(object_file_path)?; + + // Compile KCL code into ".o" object file. + emit_code( + compile_prog, + arg.work_dir.clone().unwrap_or("".to_string()), + import_names, + &EmitOptions { + from_path: None, + emit_path: Some(code_file), + no_link: true, + }, + ) + .map_err(|e| { + anyhow::anyhow!( + "Internal error: compile KCL to LLVM error {}", + e.to_string() + ) + })?; + + Ok(object_file_path.to_string()) + } + + #[inline] + fn add_code_file_suffix(&self, code_file: &str) -> String { + format!("{}{}", code_file, OBJECT_FILE_SUFFIX) + } + + #[inline] + fn get_code_file_suffix(&self) -> String { + OBJECT_FILE_SUFFIX.to_string() + } +} + +/// KclvmAssembler is mainly responsible for assembling the generated bytecode +/// LLVM IR or other IR code into dynamic link libraries, for multi-file kcl programs, +/// and take the result of kclvm-parser, kclvm-sema and kclvm-compiler as input. +/// +/// KclvmAssembler improves the performance of kclvm by concurrently compiling kcl multi-file programs. +/// The member "thread_count" of KclvmAssembler is the number of threads in multi-file compilation. +/// +/// KclvmAssembler provides an atomic operation for generating a dynamic link library for a single file +/// through KclvmLibAssembler for each thread. +pub(crate) struct KclvmAssembler { + program: ast::Program, + scope: ProgramScope, + entry_file: String, + single_file_assembler: KclvmLibAssembler, + target: String, + external_pkgs: HashMap, +} + +impl KclvmAssembler { + /// Constructs an KclvmAssembler instance with a default value 4 + /// for the number of threads in multi-file compilation. + #[inline] + pub(crate) fn new( + program: ast::Program, + scope: ProgramScope, + entry_file: String, + single_file_assembler: KclvmLibAssembler, + external_pkgs: HashMap, + ) -> Self { + Self { + program, + scope, + entry_file, + single_file_assembler, + target: env!("KCLVM_DEFAULT_TARGET").to_string(), + external_pkgs, + } + } + + /// Clean up the path of the dynamic link libraries generated. + /// It will remove the file in "file_path" and all the files in file_path end with ir code file suffix. + #[inline] + pub(crate) fn clean_path_for_genlibs(&self, file_path: &str, suffix: &str) -> Result<()> { + let path = std::path::Path::new(file_path); + if path.exists() { + std::fs::remove_file(path)?; + } + for entry in glob::glob(&format!("{}*{}", file_path, suffix))? { + match entry { + Ok(path) => { + if path.exists() { + std::fs::remove_file(path)?; + } + } + Err(e) => bug!("{:?}", e), + }; + } + Ok(()) + } + + /// Generate cache dir from the program root path. + /// Create cache dir if it doesn't exist. + #[inline] + pub(crate) fn load_cache_dir(&self, root: &str) -> Result { + let cache_dir = self.construct_cache_dir(root); + if !cache_dir.exists() { + std::fs::create_dir_all(&cache_dir)?; + } + Ok(cache_dir) + } + + #[inline] + pub(crate) fn construct_cache_dir(&self, root: &str) -> PathBuf { + let root = std::env::var(KCL_CACHE_PATH_ENV_VAR).unwrap_or(root.to_string()); + Path::new(&root) + .join(".kclvm") + .join("cache") + .join(kclvm_version::get_version_string()) + .join(&self.target) + } + + /// Generate the dynamic link libraries and return file paths. + /// + /// In the method, multiple threads will be created to concurrently generate dynamic link libraries + /// under different package paths. + /// + /// This method will generate dynamic link library files (such as "*.dylib", "*.dll.lib", "*.so") + /// and ir code files, and return the file paths of the dynamic link library files in [Vec]. + /// + /// `gen_libs` will create multiple threads and call the method provided by [KclvmLibAssembler] in each thread + /// to generate the dynamic link library in parallel. + pub(crate) fn gen_libs(self, args: &ExecProgramArgs) -> Result> { + self.clean_path_for_genlibs( + DEFAULT_IR_FILE, + &self.single_file_assembler.get_code_file_suffix(), + )?; + let cache_dir = self.load_cache_dir(&self.program.root)?; + let mut compile_progs: IndexMap< + String, + ( + ast::Program, + IndexMap>, + PathBuf, + ), + > = IndexMap::default(); + for (pkgpath, modules) in self.program.pkgs { + let mut pkgs = HashMap::new(); + pkgs.insert(pkgpath.clone(), modules); + let compile_prog = ast::Program { + root: self.program.root.clone(), + pkgs, + modules: self.program.modules.clone(), + pkgs_not_imported: HashMap::new(), + modules_not_imported: HashMap::new(), + }; + compile_progs.insert( + pkgpath, + ( + compile_prog, + self.scope.import_names.clone(), + cache_dir.clone(), + ), + ); + } + let mut lib_paths = vec![]; + for (pkgpath, (compile_prog, import_names, cache_dir)) in compile_progs { + // Clone a single file assembler for one thread. + let assembler = self.single_file_assembler.clone(); + // Generate paths for some intermediate files (*.o, *.lock). + let entry_file = self.entry_file.clone(); + let is_main_pkg = pkgpath == kclvm_ast::MAIN_PKG; + let file = if is_main_pkg { + // The path to the generated files(*.o or *.lock) when the main package is compiled. + PathBuf::from(entry_file) + } else { + // The path to the generated files(*.o or *.lock) when the non-main package is compiled. + cache_dir.join(&pkgpath) + }; + let code_file = file + .to_str() + .ok_or(anyhow::anyhow!("Internal error: get cache file failed"))? + .to_string(); + let code_file_path = assembler.add_code_file_suffix(&code_file); + let lock_file_path = format!("{}.lock", code_file_path); + let target = self.target.clone(); + { + // Locking file for parallel code generation. + let mut file_lock = open_lock_file(&lock_file_path)?; + file_lock.lock()?; + + let root = &compile_prog.root; + // The main package does not perform cache reading and writing, + // and other packages perform read and write caching. Because + // KCL supports multi-file compilation, it is impossible to + // specify a standard entry for these multi-files and cannot + // be shared, so the cache of the main package is not read and + // written. + let file_path = if is_main_pkg { + // generate dynamic link library for single file kcl program + assembler.assemble( + &compile_prog, + import_names, + &code_file, + &code_file_path, + args, + )? + } else { + // Read the lib path cache + let file_relative_path: Option = load_pkg_cache( + root, + &target, + &pkgpath, + CacheOption::default(), + &self.external_pkgs, + ); + let file_abs_path = match file_relative_path { + Some(file_relative_path) => { + let path = if file_relative_path.starts_with('.') { + file_relative_path.replacen('.', root, 1) + } else { + file_relative_path + }; + if Path::new(&path).exists() { + Some(path) + } else { + None + } + } + None => None, + }; + match file_abs_path { + Some(path) => path, + None => { + // Generate the object file for single file kcl program. + let file_path = assembler.assemble( + &compile_prog, + import_names, + &code_file, + &code_file_path, + args, + )?; + let lib_relative_path = file_path.replacen(root, ".", 1); + let _ = save_pkg_cache( + root, + &target, + &pkgpath, + lib_relative_path, + CacheOption::default(), + &self.external_pkgs, + ); + file_path + } + } + }; + file_lock.unlock()?; + lib_paths.push(file_path); + }; + } + self.single_file_assembler + .clean_lock_file(&self.entry_file)?; + Ok(lib_paths) + } +} + +#[inline] +pub(crate) fn clean_path(path: &str) -> Result<()> { + if Path::new(path).exists() { + std::fs::remove_file(path)?; + } + Ok(()) +} diff --git a/kclvm/runner/src/command.rs b/kclvm/runner/src/command.rs deleted file mode 100644 index ac18d6fe4..000000000 --- a/kclvm/runner/src/command.rs +++ /dev/null @@ -1,479 +0,0 @@ -use std::{env, path::PathBuf}; - -use super::runner::*; -use kclvm::ValueRef; -use kclvm_config::settings::SettingsFile; - -#[derive(Debug)] -pub struct Command { - clang_path: String, - rust_libstd_dylib: String, - executable_root: String, - plugin_method_ptr: u64, -} - -impl Command { - pub fn new(plugin_method_ptr: u64) -> Self { - let executable_root = Self::get_executable_root(); - let rust_libstd_dylib = Self::get_rust_libstd_dylib(executable_root.as_str()); - let clang_path = Self::get_clang_path(); - - Self { - clang_path, - rust_libstd_dylib, - executable_root, - plugin_method_ptr, - } - } - - pub fn run_dylib(&self, dylib_path: &str) -> Result { - unsafe { - let lib = libloading::Library::new(dylib_path).unwrap(); - - // get kclvm_plugin_init - let kclvm_plugin_init: libloading::Symbol< - unsafe extern "C" fn( - fn_ptr: extern "C" fn( - method: *const i8, - args_json: *const i8, - kwargs_json: *const i8, - ) -> *const i8, - ), - > = lib.get(b"kclvm_plugin_init").unwrap(); - - // get _kcl_run - let kcl_run: libloading::Symbol< - unsafe extern "C" fn( - kclvm_main_ptr: u64, // main.k => kclvm_main - option_len: kclvm_size_t, - option_keys: *const *const kclvm_char_t, - option_values: *const *const kclvm_char_t, - strict_range_check: i32, - disable_none: i32, - disable_schema_check: i32, - list_option_mode: i32, - debug_mode: i32, - result_buffer_len: kclvm_size_t, - result_buffer: *mut kclvm_char_t, - warn_buffer_len: kclvm_size_t, - warn_buffer: *mut kclvm_char_t, - ) -> kclvm_size_t, - > = lib.get(b"_kcl_run").unwrap(); - - // get kclvm_main - let kclvm_main: libloading::Symbol = lib.get(b"kclvm_main").unwrap(); - let kclvm_main_ptr = kclvm_main.into_raw().into_raw() as u64; - - // get plugin_method - let plugin_method_ptr = self.plugin_method_ptr; - let plugin_method_ptr = (plugin_method_ptr as *const u64) as *const () - as *const extern "C" fn( - method: *const i8, - args: *const i8, - kwargs: *const i8, - ) -> *const i8; - let plugin_method: extern "C" fn( - method: *const i8, - args: *const i8, - kwargs: *const i8, - ) -> *const i8 = std::mem::transmute(plugin_method_ptr); - - // register plugin agent - kclvm_plugin_init(plugin_method); - - let option_len = 0; - let option_keys = std::ptr::null(); - let option_values = std::ptr::null(); - let strict_range_check = 0; - let disable_none = 0; - let disable_schema_check = 0; - let list_option_mode = 0; - let debug_mode = 0; - - let mut result = vec![0u8; 1024 * 1024]; - let result_buffer_len = result.len() as i32 - 1; - let result_buffer = result.as_mut_ptr() as *mut i8; - - let mut warn_buffer = vec![0u8; 1024 * 1024]; - let warn_buffer_len = warn_buffer.len() as i32 - 1; - let warn_buffer = warn_buffer.as_mut_ptr() as *mut i8; - - let n = kcl_run( - kclvm_main_ptr, - option_len, - option_keys, - option_values, - strict_range_check, - disable_none, - disable_schema_check, - list_option_mode, - debug_mode, - result_buffer_len, - result_buffer, - warn_buffer_len, - warn_buffer, - ); - - let s = std::str::from_utf8(&result[0..n as usize]).unwrap(); - Ok(s.to_string()) - } - } - - pub fn run_dylib_with_settings( - &self, - dylib_path: &str, - settings: SettingsFile, - ) -> Result { - unsafe { - let lib = libloading::Library::new(dylib_path).unwrap(); - - let kcl_run: libloading::Symbol< - unsafe extern "C" fn( - kclvm_main_ptr: u64, // main.k => kclvm_main - option_len: kclvm_size_t, - option_keys: *const *const kclvm_char_t, - option_values: *const *const kclvm_char_t, - strict_range_check: i32, - disable_none: i32, - disable_schema_check: i32, - list_option_mode: i32, - debug_mode: i32, - result_buffer_len: kclvm_size_t, - result_buffer: *mut kclvm_char_t, - warn_buffer_len: kclvm_size_t, - warn_buffer: *mut kclvm_char_t, - ) -> kclvm_size_t, - > = lib.get(b"_kcl_run").unwrap(); - - let kclvm_main: libloading::Symbol = lib.get(b"kclvm_main").unwrap(); - let kclvm_main_ptr = kclvm_main.into_raw().into_raw() as u64; - - let option_len = 0; - let option_keys = std::ptr::null(); - let option_values = std::ptr::null(); - let strict_range_check = 0; - let disable_none = settings - .kcl_cli_configs - .as_ref() - .map_or(0, |c| c.disable_none.map_or(0, |v| v as i32)); - let disable_schema_check = 0; - let list_option_mode = 0; - let debug_mode = settings - .kcl_cli_configs - .as_ref() - .map_or(0, |c| c.debug.map_or(0, |v| v as i32)); - - let mut result = vec![0u8; 1024 * 1024]; - let result_buffer_len = result.len() as i32 - 1; - let result_buffer = result.as_mut_ptr() as *mut i8; - - let mut warn_buffer = vec![0u8; 1024 * 1024]; - let warn_buffer_len = warn_buffer.len() as i32 - 1; - let warn_buffer = warn_buffer.as_mut_ptr() as *mut i8; - - let n = kcl_run( - kclvm_main_ptr, - option_len, - option_keys, - option_values, - strict_range_check, - disable_none, - disable_schema_check, - list_option_mode, - debug_mode, - result_buffer_len, - result_buffer, - warn_buffer_len, - warn_buffer, - ); - - let ctx = kclvm::Context::current_context_mut(); - ctx.cfg.debug_mode = debug_mode > 0; - ctx.cfg.disable_none = disable_none > 0; - let s = std::str::from_utf8(&result[0..n as usize]).unwrap(); - if s.is_empty() { - println!() - } else { - println!("{}", ValueRef::from_json(s).unwrap().plan_to_yaml_string()); - } - } - - Ok("".to_string()) - } - - pub fn link_dylibs(&mut self, dylibs: &[String], dylib_path: &str) -> String { - let mut dylib_path = dylib_path.to_string(); - - if dylib_path.is_empty() { - dylib_path = format!("{}{}", "_a.out", Self::get_lib_suffix()); - } - - let mut args: Vec = vec![ - "-Wno-override-module".to_string(), - "-Wno-error=unused-command-line-argument".to_string(), - "-Wno-unused-command-line-argument".to_string(), - "-shared".to_string(), - "-undefined".to_string(), - "dynamic_lookup".to_string(), - format!("-Wl,-rpath,{}/lib", self.executable_root), - format!("-L{}/lib", self.executable_root), - "-lkclvm_native_shared".to_string(), - format!("-I{}/include", self.executable_root), - ]; - let mut bc_files = dylibs.to_owned(); - args.append(&mut bc_files); - let mut more_args = vec![ - self.rust_libstd_dylib.clone(), - "-fPIC".to_string(), - "-o".to_string(), - dylib_path.to_string(), - ]; - args.append(&mut more_args); - - std::process::Command::new(self.clang_path.clone()) - .stdout(std::process::Stdio::inherit()) - .stderr(std::process::Stdio::inherit()) - .args(&args) - .output() - .expect("clang failed"); - - dylib_path - } - - pub fn run_clang(&mut self, bc_path: &str, dylib_path: &str) -> String { - let mut bc_path = bc_path.to_string(); - let mut dylib_path = dylib_path.to_string(); - - let mut bc_files = vec![]; - - for entry in glob::glob(&format!("{}*.ll", bc_path)).unwrap() { - match entry { - Ok(path) => { - if path.exists() { - bc_files.push(path); - } - } - Err(e) => println!("{:?}", e), - }; - } - let mut bc_files = bc_files - .iter() - .map(|f| f.to_str().unwrap().to_string()) - .collect::>(); - - if !Self::path_exist(bc_path.as_str()) { - let s = format!("{}.ll", bc_path); - if Self::path_exist(s.as_str()) { - bc_path = s; - } else { - let s = format!("{}.ll", bc_path); - if Self::path_exist(s.as_str()) { - bc_path = s; - } - } - } - - if dylib_path.is_empty() { - dylib_path = format!("{}{}", bc_path, Self::get_lib_suffix()); - } - - let mut args: Vec = vec![ - "-Wno-override-module".to_string(), - "-Wno-error=unused-command-line-argument".to_string(), - "-Wno-unused-command-line-argument".to_string(), - "-shared".to_string(), - "-undefined".to_string(), - "dynamic_lookup".to_string(), - format!("-Wl,-rpath,{}/lib", self.executable_root), - format!("-L{}/lib", self.executable_root), - "-lkclvm_native_shared".to_string(), - format!("-I{}/include", self.executable_root), - ]; - args.append(&mut bc_files); - let mut more_args = vec![ - self.rust_libstd_dylib.clone(), - "-fPIC".to_string(), - "-o".to_string(), - dylib_path.to_string(), - ]; - args.append(&mut more_args); - - std::process::Command::new(self.clang_path.clone()) - .stdout(std::process::Stdio::inherit()) - .stderr(std::process::Stdio::inherit()) - .args(&args) - .output() - .expect("clang failed"); - - dylib_path - } - - pub fn run_clang_single(&mut self, bc_path: &str, dylib_path: &str) -> String { - let mut bc_path = bc_path.to_string(); - let mut dylib_path = dylib_path.to_string(); - - if !Self::path_exist(bc_path.as_str()) { - let s = format!("{}.ll", bc_path); - if Self::path_exist(s.as_str()) { - bc_path = s; - } else { - let s = format!("{}.ll", bc_path); - if Self::path_exist(s.as_str()) { - bc_path = s; - } - } - } - - if dylib_path.is_empty() { - dylib_path = format!("{}{}", bc_path, Self::get_lib_suffix()); - } - - let mut args: Vec = vec![ - "-Wno-override-module".to_string(), - "-Wno-error=unused-command-line-argument".to_string(), - "-Wno-unused-command-line-argument".to_string(), - "-shared".to_string(), - "-undefined".to_string(), - "dynamic_lookup".to_string(), - format!("-Wl,-rpath,{}/lib", self.executable_root), - format!("-L{}/lib", self.executable_root), - "-lkclvm_native_shared".to_string(), - format!("-I{}/include", self.executable_root), - ]; - let mut bc_files = vec![bc_path]; - args.append(&mut bc_files); - let mut more_args = vec![ - self.rust_libstd_dylib.clone(), - "-fPIC".to_string(), - "-o".to_string(), - dylib_path.to_string(), - ]; - args.append(&mut more_args); - - std::process::Command::new(self.clang_path.clone()) - .stdout(std::process::Stdio::inherit()) - .stderr(std::process::Stdio::inherit()) - .args(&args) - .output() - .expect("clang failed"); - // Use absolute path. - let path = PathBuf::from(&dylib_path).canonicalize().unwrap(); - path.to_str().unwrap().to_string() - } - - fn get_executable_root() -> String { - if Self::is_windows() { - todo!(); - } - - let kclvm_exe = if Self::is_windows() { - "kclvm.exe" - } else { - "kclvm" - }; - let p = if let Some(x) = Self::find_it(kclvm_exe) { - x - } else { - std::env::current_exe().unwrap() - }; - - let p = p.parent().unwrap().parent().unwrap(); - p.to_str().unwrap().to_string() - } - - fn get_rust_libstd_dylib(executable_root: &str) -> String { - let txt_path = std::path::Path::new(&executable_root) - .join(if Self::is_windows() { "libs" } else { "lib" }) - .join("rust-libstd-name.txt"); - let rust_libstd_name = std::fs::read_to_string(txt_path).unwrap(); - let rust_libstd_name = rust_libstd_name.trim(); - format!("{}/lib/{}", executable_root, rust_libstd_name) - } - - fn get_clang_path() -> String { - // ${KCLVM_CLANG} - let env_kclvm_clang = env::var("KCLVM_CLANG"); - if let Ok(clang_path) = env_kclvm_clang { - if !clang_path.is_empty() { - if Self::is_windows() { - return format!("{}.exe", clang_path); - } else { - return clang_path; - } - } - } - - // {root}/tools/clang/bin/clang - let executable_root = Self::get_executable_root(); - let clang_path = std::path::Path::new(&executable_root) - .join("tools") - .join("clang") - .join("bin") - .join(if Self::is_windows() { - "clang.exe" - } else { - "clang" - }); - if clang_path.exists() { - return clang_path.to_str().unwrap().to_string(); - } - - let clang_exe = if Self::is_windows() { - "clang.exe" - } else { - "clang" - }; - - - if let Some(s) = Self::find_it(clang_exe) { - return s.to_str().unwrap().to_string(); - } - - panic!("get_clang_path failed") - } - - pub fn get_lib_suffix() -> String { - if Self::is_windows() { - return ".dll.lib".to_string(); - } - if Self::is_macos() { - return ".dylib".to_string(); - } - if Self::is_linux() { - return ".so".to_string(); - } - panic!("unsupport os") - } - - fn is_windows() -> bool { - cfg!(target_os = "windows") - } - fn is_macos() -> bool { - cfg!(target_os = "macos") - } - fn is_linux() -> bool { - cfg!(target_os = "linux") - } - - fn path_exist(path: &str) -> bool { - std::path::Path::new(path).exists() - } - - fn find_it

(exe_name: P) -> Option - where - P: AsRef, - { - std::env::var_os("PATH").and_then(|paths| { - std::env::split_paths(&paths) - .filter_map(|dir| { - let full_path = dir.join(&exe_name); - if full_path.is_file() { - Some(full_path) - } else { - None - } - }) - .next() - }) - } -} diff --git a/kclvm/runner/src/custom_manifests_data/dict.k b/kclvm/runner/src/custom_manifests_data/dict.k new file mode 100644 index 000000000..332dc066a --- /dev/null +++ b/kclvm/runner/src/custom_manifests_data/dict.k @@ -0,0 +1,7 @@ +import manifests + +manifests.yaml_stream([{ + name = "kcl" +}, { + age = 10 +}]) diff --git a/kclvm/runner/src/custom_manifests_data/dict.stdout.golden b/kclvm/runner/src/custom_manifests_data/dict.stdout.golden new file mode 100644 index 000000000..e6baa8fee --- /dev/null +++ b/kclvm/runner/src/custom_manifests_data/dict.stdout.golden @@ -0,0 +1,3 @@ +name: kcl +--- +age: 10 diff --git a/kclvm/runner/src/custom_manifests_data/dict_ignore_none.k b/kclvm/runner/src/custom_manifests_data/dict_ignore_none.k new file mode 100644 index 000000000..961add477 --- /dev/null +++ b/kclvm/runner/src/custom_manifests_data/dict_ignore_none.k @@ -0,0 +1,11 @@ +import manifests + +manifests.yaml_stream([{ + name = "Alice" + age = 10 +}, { + name = "Bob" + age = None +}], opts = { + ignore_none = True +}) diff --git a/kclvm/runner/src/custom_manifests_data/dict_ignore_none.stdout.golden b/kclvm/runner/src/custom_manifests_data/dict_ignore_none.stdout.golden new file mode 100644 index 000000000..e88d48de7 --- /dev/null +++ b/kclvm/runner/src/custom_manifests_data/dict_ignore_none.stdout.golden @@ -0,0 +1,4 @@ +name: Alice +age: 10 +--- +name: Bob diff --git a/kclvm/runner/src/custom_manifests_data/dict_sort_key.k b/kclvm/runner/src/custom_manifests_data/dict_sort_key.k new file mode 100644 index 000000000..72c6df0ec --- /dev/null +++ b/kclvm/runner/src/custom_manifests_data/dict_sort_key.k @@ -0,0 +1,9 @@ +import manifests + +manifests.yaml_stream([{ + name = "kcl" + age = 10 +}, { + age = 10 + name = "kcl" +}], opts = {sort_keys = True}) diff --git a/kclvm/runner/src/custom_manifests_data/dict_sort_key.stdout.golden b/kclvm/runner/src/custom_manifests_data/dict_sort_key.stdout.golden new file mode 100644 index 000000000..38101c958 --- /dev/null +++ b/kclvm/runner/src/custom_manifests_data/dict_sort_key.stdout.golden @@ -0,0 +1,5 @@ +age: 10 +name: kcl +--- +age: 10 +name: kcl diff --git a/kclvm/runner/src/custom_manifests_data/list.k b/kclvm/runner/src/custom_manifests_data/list.k new file mode 100644 index 000000000..f23e06233 --- /dev/null +++ b/kclvm/runner/src/custom_manifests_data/list.k @@ -0,0 +1,3 @@ +import manifests + +manifests.yaml_stream([{k1 = [1, 2], k2 = [3, 4]}, {k3 = [5, 6], k4 = [7, 8]}, {k5 = [9, 10]}]) diff --git a/kclvm/runner/src/custom_manifests_data/list.stdout.golden b/kclvm/runner/src/custom_manifests_data/list.stdout.golden new file mode 100644 index 000000000..cf081cf3d --- /dev/null +++ b/kclvm/runner/src/custom_manifests_data/list.stdout.golden @@ -0,0 +1,17 @@ +k1: +- 1 +- 2 +k2: +- 3 +- 4 +--- +k3: +- 5 +- 6 +k4: +- 7 +- 8 +--- +k5: +- 9 +- 10 diff --git a/kclvm/runner/src/custom_manifests_data/schema.k b/kclvm/runner/src/custom_manifests_data/schema.k new file mode 100644 index 000000000..95d777dd7 --- /dev/null +++ b/kclvm/runner/src/custom_manifests_data/schema.k @@ -0,0 +1,11 @@ +import manifests + +schema Person: + name: str = "kcl" + age: int = 1 + +x0 = Person {} +x1 = Person { + age = 101 +} +manifests.yaml_stream([x0, x1]) diff --git a/kclvm/runner/src/custom_manifests_data/schema.stdout.golden b/kclvm/runner/src/custom_manifests_data/schema.stdout.golden new file mode 100644 index 000000000..c3eb922d7 --- /dev/null +++ b/kclvm/runner/src/custom_manifests_data/schema.stdout.golden @@ -0,0 +1,5 @@ +name: kcl +age: 1 +--- +name: kcl +age: 101 diff --git a/kclvm/runner/src/custom_manifests_data/schema_ignore_none.k b/kclvm/runner/src/custom_manifests_data/schema_ignore_none.k new file mode 100644 index 000000000..bb632ddf2 --- /dev/null +++ b/kclvm/runner/src/custom_manifests_data/schema_ignore_none.k @@ -0,0 +1,11 @@ +import manifests + +schema Person: + name: str = "kcl" + age?: int = 1 + +x0 = Person {} +x1 = Person { + age = None +} +manifests.yaml_stream([x0, x1], opts = {ignore_none = True}) diff --git a/kclvm/runner/src/custom_manifests_data/schema_ignore_none.stdout.golden b/kclvm/runner/src/custom_manifests_data/schema_ignore_none.stdout.golden new file mode 100644 index 000000000..30fcca92f --- /dev/null +++ b/kclvm/runner/src/custom_manifests_data/schema_ignore_none.stdout.golden @@ -0,0 +1,4 @@ +name: kcl +age: 1 +--- +name: kcl diff --git a/kclvm/runner/src/custom_manifests_data/schema_sort_key.k b/kclvm/runner/src/custom_manifests_data/schema_sort_key.k new file mode 100644 index 000000000..1421735c6 --- /dev/null +++ b/kclvm/runner/src/custom_manifests_data/schema_sort_key.k @@ -0,0 +1,11 @@ +import manifests + +schema Person: + name: str = "kcl" + age: int = 1 + +x0 = Person {} +x1 = Person { + age = 101 +} +manifests.yaml_stream([x0, x1], opts = {sort_keys = True}) diff --git a/kclvm/runner/src/custom_manifests_data/schema_sort_key.stdout.golden b/kclvm/runner/src/custom_manifests_data/schema_sort_key.stdout.golden new file mode 100644 index 000000000..e80c18631 --- /dev/null +++ b/kclvm/runner/src/custom_manifests_data/schema_sort_key.stdout.golden @@ -0,0 +1,5 @@ +age: 1 +name: kcl +--- +age: 101 +name: kcl diff --git a/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/assert.k b/kclvm/runner/src/exec_data/assert.k similarity index 100% rename from test/test_units/test_kclvm/test_compiler/test_eval/eval_data/assert.k rename to kclvm/runner/src/exec_data/assert.k diff --git a/kclvm/runner/src/exec_data/aug_assign.k b/kclvm/runner/src/exec_data/aug_assign.k new file mode 100644 index 000000000..6353279e6 --- /dev/null +++ b/kclvm/runner/src/exec_data/aug_assign.k @@ -0,0 +1,29 @@ +schema Name: + first: str + last?: str + age?: int + +schema A: + name: Name + +schema Data: + _alice = A { + name: { + first: "aa" + age: 1 + } + } + + _alice.name.age += 1 + alice = _alice + +data = Data {} +_alice = A { + name: { + first: "aa" + age: 1 + } +} + +_alice.name.age += 1 +alice = _alice diff --git a/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/calculation.k b/kclvm/runner/src/exec_data/calculation.k similarity index 100% rename from test/test_units/test_kclvm/test_compiler/test_eval/eval_data/calculation.k rename to kclvm/runner/src/exec_data/calculation.k diff --git a/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/collection_if.k b/kclvm/runner/src/exec_data/collection_if.k similarity index 100% rename from test/test_units/test_kclvm/test_compiler/test_eval/eval_data/collection_if.k rename to kclvm/runner/src/exec_data/collection_if.k diff --git a/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/compare.k b/kclvm/runner/src/exec_data/compare.k similarity index 100% rename from test/test_units/test_kclvm/test_compiler/test_eval/eval_data/compare.k rename to kclvm/runner/src/exec_data/compare.k diff --git a/kclvm/runner/src/exec_data/complex.k b/kclvm/runner/src/exec_data/complex.k new file mode 100644 index 000000000..db48c8b53 --- /dev/null +++ b/kclvm/runner/src/exec_data/complex.k @@ -0,0 +1,42 @@ +import math + +name = "Alice" +schema Base: + hc: int = 3 + key: str = name + +schema Person(Base): + name: str = "Alice" + age: int = 18 + labels: {str:str} = {"key": "value", "ageLabel": "ageVal " + str(age)} + info: [int|str] = [name, age] + +person1 = Person { + "name" = "Bob" + "age" = 16 +} +ceil_val = math.ceil(1.1) +a = 1.1 + 1.1 + 6.6 + 3.2 + abs(-1.2) +b = {"key1": "value1", "key2": "value2"} +attr = b.key1 + person1.name +c = 3 - 2 * 3 / 4 +d = a + 2 +e = a + 2 +f = "ABC" + "234{}" +p = "ABC"[::-1] +ff = f.format("123") +fff = ff.lower() +q = "1" * 12 +g = True +l = [1, 2, 3, attr + "value1"] +ll = [*l, 1] +_e = 1 + 1 +aug1 = aug2 = 4 + 3 +data = [1, 2, 3, 4] +lcomp = [_d * 2 for _d in data for _d in data] +dcomp = {str(dd): dd * 2 for dd in data} +data0 = data[0] +data12 = data[::-1] +pk = "ABC"[::-1] +qk = [1, 2, 3][::-1] +dict_data = {**person1, **{"key" = "value"}, "key2": "value2"} diff --git a/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/convert_collection_value.k b/kclvm/runner/src/exec_data/convert_collection_value.k similarity index 100% rename from test/test_units/test_kclvm/test_compiler/test_eval/eval_data/convert_collection_value.k rename to kclvm/runner/src/exec_data/convert_collection_value.k diff --git a/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/for.k b/kclvm/runner/src/exec_data/for.k similarity index 100% rename from test/test_units/test_kclvm/test_compiler/test_eval/eval_data/for.k rename to kclvm/runner/src/exec_data/for.k diff --git a/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/if.k b/kclvm/runner/src/exec_data/if.k similarity index 100% rename from test/test_units/test_kclvm/test_compiler/test_eval/eval_data/if.k rename to kclvm/runner/src/exec_data/if.k diff --git a/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/index_signature.k b/kclvm/runner/src/exec_data/index_signature.k similarity index 100% rename from test/test_units/test_kclvm/test_compiler/test_eval/eval_data/index_signature.k rename to kclvm/runner/src/exec_data/index_signature.k diff --git a/test/test_units/test_kclvm/test_compiler/test_vfs/test_get_pkg_root/kcl.mod b/kclvm/runner/src/exec_data/kcl.mod similarity index 100% rename from test/test_units/test_kclvm/test_compiler/test_vfs/test_get_pkg_root/kcl.mod rename to kclvm/runner/src/exec_data/kcl.mod diff --git a/kclvm/runner/src/exec_data/lambda.k.fixme b/kclvm/runner/src/exec_data/lambda.k.fixme new file mode 100644 index 000000000..ddcd3e35e --- /dev/null +++ b/kclvm/runner/src/exec_data/lambda.k.fixme @@ -0,0 +1,37 @@ +# TOFIX(zong-zhe): issue https://github.com/kcl-lang/kcl/issues/241 +sumFunc1 = lambda x, y { + x + y +} +sumFunc2 = lambda x, y = 1 { + x + y +} +sumFunc3 = lambda x = 1, y: int = 1 { + x + y +} +sumFunc4 = lambda x: int = 1, y: int = 1 -> int { + x + y +} +x0 = sumFunc1(1, 2) +x1 = sumFunc1(2, 3) +x2 = sumFunc1(3, 4) +x3 = sumFunc1(4, 5) + +schema Data: + var: int = 1 + _func = lambda x: int | str, y: int | str { + (lambda x, y { + int(x) + int(y) + var + })(x, y) + } + + a = _func(1, 1) + b = _func("123", "456") + +data = Data() + +result = (lambda x: int, y: int -> int { + a = 1 + (lambda { + x + y + a + 1 + })() +})(1, 1) diff --git a/kclvm/runner/src/exec_data/lambda_return_undefined.k b/kclvm/runner/src/exec_data/lambda_return_undefined.k new file mode 100644 index 000000000..4acd2f4f1 --- /dev/null +++ b/kclvm/runner/src/exec_data/lambda_return_undefined.k @@ -0,0 +1,6 @@ +a = lambda { + if False: + v = 1 + v +}() +b = 1 diff --git a/kclvm/runner/src/exec_data/list.k b/kclvm/runner/src/exec_data/list.k new file mode 100644 index 000000000..5f7d77e43 --- /dev/null +++ b/kclvm/runner/src/exec_data/list.k @@ -0,0 +1,9 @@ +schema Data: + id?: int + name: str + +x0 = [[{a: 1, b: Undefined}]] +x1 = [[[{a: 1, b: Undefined}]]] +x2 = [[{a: 1, b: None}]] +x3 = [[[{a: 1, b: None}]]] +x4 = [[[1, Data { name = "data" }]]] diff --git a/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/member_ship.k b/kclvm/runner/src/exec_data/member_ship.k similarity index 100% rename from test/test_units/test_kclvm/test_compiler/test_eval/eval_data/member_ship.k rename to kclvm/runner/src/exec_data/member_ship.k diff --git a/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/nest_var.k b/kclvm/runner/src/exec_data/nest_var.k similarity index 100% rename from test/test_units/test_kclvm/test_compiler/test_eval/eval_data/nest_var.k rename to kclvm/runner/src/exec_data/nest_var.k diff --git a/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/plus.k b/kclvm/runner/src/exec_data/plus.k similarity index 100% rename from test/test_units/test_kclvm/test_compiler/test_eval/eval_data/plus.k rename to kclvm/runner/src/exec_data/plus.k diff --git a/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/quant_expr.k b/kclvm/runner/src/exec_data/quant_expr.k similarity index 100% rename from test/test_units/test_kclvm/test_compiler/test_eval/eval_data/quant_expr.k rename to kclvm/runner/src/exec_data/quant_expr.k diff --git a/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/regex.k b/kclvm/runner/src/exec_data/regex.k similarity index 100% rename from test/test_units/test_kclvm/test_compiler/test_eval/eval_data/regex.k rename to kclvm/runner/src/exec_data/regex.k diff --git a/kclvm/runner/src/exec_data/rule.k b/kclvm/runner/src/exec_data/rule.k new file mode 100644 index 000000000..eb9150d2a --- /dev/null +++ b/kclvm/runner/src/exec_data/rule.k @@ -0,0 +1,13 @@ +age = 1 + +@deprecated +rule DeprecatedRule: + age == 0 + +schema RuleProtocol: + age?: int + +rule Main for RuleProtocol: + True + +Main {} diff --git a/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/schema.k b/kclvm/runner/src/exec_data/schema.k similarity index 100% rename from test/test_units/test_kclvm/test_compiler/test_eval/eval_data/schema.k rename to kclvm/runner/src/exec_data/schema.k diff --git a/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/schema_args.k b/kclvm/runner/src/exec_data/schema_args.k similarity index 100% rename from test/test_units/test_kclvm/test_compiler/test_eval/eval_data/schema_args.k rename to kclvm/runner/src/exec_data/schema_args.k diff --git a/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/str.k b/kclvm/runner/src/exec_data/str.k similarity index 100% rename from test/test_units/test_kclvm/test_compiler/test_eval/eval_data/str.k rename to kclvm/runner/src/exec_data/str.k diff --git a/test/test_units/test_kclvm/test_tools/test_printer/test_data/type_alias.input b/kclvm/runner/src/exec_data/type_alias.k similarity index 100% rename from test/test_units/test_kclvm/test_tools/test_printer/test_data/type_alias.input rename to kclvm/runner/src/exec_data/type_alias.k diff --git a/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/type_as.k b/kclvm/runner/src/exec_data/type_as.k similarity index 100% rename from test/test_units/test_kclvm/test_compiler/test_eval/eval_data/type_as.k rename to kclvm/runner/src/exec_data/type_as.k diff --git a/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/types.k b/kclvm/runner/src/exec_data/types.k similarity index 100% rename from test/test_units/test_kclvm/test_compiler/test_eval/eval_data/types.k rename to kclvm/runner/src/exec_data/types.k diff --git a/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/unary.k b/kclvm/runner/src/exec_data/unary.k similarity index 100% rename from test/test_units/test_kclvm/test_compiler/test_eval/eval_data/unary.k rename to kclvm/runner/src/exec_data/unary.k diff --git a/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/unification.k b/kclvm/runner/src/exec_data/unification.k similarity index 100% rename from test/test_units/test_kclvm/test_compiler/test_eval/eval_data/unification.k rename to kclvm/runner/src/exec_data/unification.k diff --git a/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/unification_with_mixin.k b/kclvm/runner/src/exec_data/unification_with_mixin.k similarity index 100% rename from test/test_units/test_kclvm/test_compiler/test_eval/eval_data/unification_with_mixin.k rename to kclvm/runner/src/exec_data/unification_with_mixin.k diff --git a/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/units.k b/kclvm/runner/src/exec_data/units.k similarity index 100% rename from test/test_units/test_kclvm/test_compiler/test_eval/eval_data/units.k rename to kclvm/runner/src/exec_data/units.k diff --git a/kclvm/runner/src/exec_err_data/attr_not_found.k b/kclvm/runner/src/exec_err_data/attr_not_found.k new file mode 100644 index 000000000..9bbd0b61b --- /dev/null +++ b/kclvm/runner/src/exec_err_data/attr_not_found.k @@ -0,0 +1,8 @@ +schema Data: + resource?: str | {str:str} + +schema Config[inputData]: + data: Data = inputData + template: str = data?.resource?.template + +c = Config({resource = "100Gi"}) diff --git a/kclvm/runner/src/exec_err_data/attr_not_found.stderr.json b/kclvm/runner/src/exec_err_data/attr_not_found.stderr.json new file mode 100644 index 000000000..1ee53f64c --- /dev/null +++ b/kclvm/runner/src/exec_err_data/attr_not_found.stderr.json @@ -0,0 +1,5 @@ +{ + "line": 6, + "col": 0, + "message": "str object attr 'template' not found" +} diff --git a/kclvm/runner/src/lib.rs b/kclvm/runner/src/lib.rs index e7a51a61d..934438146 100644 --- a/kclvm/runner/src/lib.rs +++ b/kclvm/runner/src/lib.rs @@ -1,2 +1,415 @@ -pub mod command; +use std::{ + collections::HashMap, + ffi::OsStr, + path::Path, + sync::{Arc, RwLock}, +}; + +use anyhow::{anyhow, bail, Result}; +use assembler::KclvmLibAssembler; +use kclvm_ast::{ + ast::{Module, Program}, + MAIN_PKG, +}; +use kclvm_config::cache::KCL_CACHE_PATH_ENV_VAR; +use kclvm_parser::{load_program, KCLModuleCache, ParseSessionRef}; +use kclvm_query::apply_overrides; +use kclvm_sema::resolver::{ + resolve_program, resolve_program_with_opts, scope::ProgramScope, Options, +}; +use kclvm_utils::fslock::open_lock_file; +use linker::Command; +pub use runner::{Artifact, ExecProgramArgs, ExecProgramResult, MapErrorResult}; +use runner::{FastRunner, RunnerOptions}; +#[cfg(feature = "llvm")] +use runner::{LibRunner, ProgramRunner}; +use tempfile::tempdir; + +pub mod assembler; +pub mod linker; pub mod runner; + +#[cfg(test)] +pub mod tests; + +pub const KCL_FAST_EVAL_ENV_VAR: &str = "KCL_FAST_EVAL"; + +/// After the kcl program passed through kclvm-parser in the compiler frontend, +/// KCL needs to resolve ast, generate corresponding LLVM IR, dynamic link library or +/// executable file for kcl program in the compiler backend. +/// +/// Method “execute” is the entry point for the compiler backend. +/// +/// It returns the KCL program executing result as Result, +/// and mainly takes "program" (ast.Program returned by kclvm-parser) as input. +/// +/// "args" is the items selected by the user in the KCL CLI. +/// +/// This method will first resolve “program” (ast.Program) and save the result to the "scope" (ProgramScope). +/// +/// Then, dynamic link libraries is generated by KclvmAssembler, and method "KclvmAssembler::gen_libs" +/// will return dynamic link library paths in a "Vec"; +/// +/// KclvmAssembler is mainly responsible for concurrent compilation of multiple files. +/// Single-file compilation in each thread in concurrent compilation is the responsibility of KclvmLibAssembler. +/// In the future, it may support the dynamic link library generation of multiple intermediate language. +/// KclvmLibAssembler currently only supports LLVM IR. +/// +/// After linking all dynamic link libraries by KclvmLinker, method "KclvmLinker::link_all_libs" will return a path +/// for dynamic link library after linking. +/// +/// At last, KclLibRunner will be constructed and call method "run" to execute the kcl program. +/// +/// **Note that it is not thread safe.** +/// +/// # Examples +/// +/// ``` +/// use kclvm_runner::{exec_program, ExecProgramArgs}; +/// use kclvm_parser::ParseSession; +/// use std::sync::Arc; +/// +/// // Create sessions +/// let sess = Arc::new(ParseSession::default()); +/// // Get default args +/// let mut args = ExecProgramArgs::default(); +/// args.k_filename_list = vec!["./src/test_datas/init_check_order_0/main.k".to_string()]; +/// +/// // Resolve ast, generate libs, link libs and execute. +/// // Result is the kcl in json format. +/// let result = exec_program(sess, &args).unwrap(); +/// ``` +pub fn exec_program(sess: ParseSessionRef, args: &ExecProgramArgs) -> Result { + // parse args from json string + let opts = args.get_load_program_options(); + let kcl_paths_str = args + .k_filename_list + .iter() + .map(|s| s.as_str()) + .collect::>(); + let module_cache = KCLModuleCache::default(); + let mut program = load_program( + sess.clone(), + kcl_paths_str.as_slice(), + Some(opts), + Some(module_cache), + )? + .program; + apply_overrides( + &mut program, + &args.overrides, + &[], + args.print_override_ast || args.debug > 0, + )?; + execute(sess, program, args) +} + +/// Execute the KCL artifact with args. +pub fn exec_artifact>( + path: P, + args: &ExecProgramArgs, +) -> Result { + #[cfg(feature = "llvm")] + { + Artifact::from_path(path)?.run(args) + } + #[cfg(not(feature = "llvm"))] + { + let _ = path; + let _ = args; + Err(anyhow::anyhow!("error: llvm feature is not enabled. Note: Set KCL_FAST_EVAL=1 or rebuild the crate with the llvm feature.")) + } +} + +/// After the kcl program passed through kclvm-parser in the compiler frontend, +/// KCL needs to resolve ast, generate corresponding LLVM IR, dynamic link library or +/// executable file for kcl program in the compiler backend. +/// +/// Method “execute” is the entry point for the compiler backend. +/// +/// It returns the KCL program executing result as Result, +/// and mainly takes "program" (ast.Program returned by kclvm-parser) as input. +/// +/// "args" is the items selected by the user in the KCL CLI. +/// +/// This method will first resolve “program” (ast.Program) and save the result to the "scope" (ProgramScope). +/// +/// Then, dynamic link libraries is generated by KclvmAssembler, and method "KclvmAssembler::gen_libs" +/// will return dynamic link library paths in a "Vec"; +/// +/// KclvmAssembler is mainly responsible for concurrent compilation of multiple files. +/// Single-file compilation in each thread in concurrent compilation is the responsibility of KclvmLibAssembler. +/// In the future, it may support the dynamic link library generation of multiple intermediate language. +/// KclvmLibAssembler currently only supports LLVM IR. +/// +/// After linking all dynamic link libraries by KclvmLinker, method "KclvmLinker::link_all_libs" will return a path +/// for dynamic link library after linking. +/// +/// At last, KclLibRunner will be constructed and call method "run" to execute the kcl program. +/// +/// **Note that it is not thread safe.** +/// +/// # Examples +/// +/// ``` +/// use kclvm_runner::{execute, runner::ExecProgramArgs}; +/// use kclvm_parser::{load_program, ParseSession}; +/// use kclvm_ast::ast::Program; +/// use std::sync::Arc; +/// +/// // Create sessions +/// let sess = Arc::new(ParseSession::default()); +/// // Get default args +/// let args = ExecProgramArgs::default(); +/// let opts = args.get_load_program_options(); +/// +/// // Parse kcl file +/// let kcl_path = "./src/test_datas/init_check_order_0/main.k"; +/// let prog = load_program(sess.clone(), &[kcl_path], Some(opts), None).unwrap().program; +/// +/// // Resolve ast, generate libs, link libs and execute. +/// // Result is the kcl in json format. +/// let result = execute(sess, prog, &args).unwrap(); +/// ``` +pub fn execute( + sess: ParseSessionRef, + mut program: Program, + args: &ExecProgramArgs, +) -> Result { + // If the user only wants to compile the kcl program, the following code will only resolve ast. + if args.compile_only { + let mut resolve_opts = Options::default(); + resolve_opts.merge_program = false; + // Resolve ast + let scope = resolve_program_with_opts(&mut program, resolve_opts, None); + emit_compile_diag_to_string(sess, &scope, args.compile_only)?; + return Ok(ExecProgramResult::default()); + } + // Resolve ast + let scope = resolve_program(&mut program); + // Emit parse and resolve errors if exists. + emit_compile_diag_to_string(sess, &scope, false)?; + Ok( + // Use the fast evaluator to run the kcl program. + if args.fast_eval || std::env::var(KCL_FAST_EVAL_ENV_VAR).is_ok() { + FastRunner::new(Some(RunnerOptions { + plugin_agent_ptr: args.plugin_agent, + })) + .run(&program, args)? + } else { + // Compile the kcl program to native lib and run it. + #[cfg(feature = "llvm")] + { + // Create a temp entry file and the temp dir will be delete automatically + let temp_dir = tempdir()?; + let temp_dir_path = temp_dir.path().to_str().ok_or(anyhow!( + "Internal error: {}: No such file or directory", + temp_dir.path().display() + ))?; + let temp_entry_file = temp_file(temp_dir_path)?; + + // Generate libs + let lib_paths = assembler::KclvmAssembler::new( + program, + scope, + temp_entry_file.clone(), + KclvmLibAssembler::LLVM, + args.get_package_maps_from_external_pkg(), + ) + .gen_libs(args)?; + + // Link libs into one library + let lib_suffix = Command::get_lib_suffix(); + let temp_out_lib_file = format!("{}{}", temp_entry_file, lib_suffix); + let lib_path = linker::KclvmLinker::link_all_libs(lib_paths, temp_out_lib_file)?; + + // Run the library + let runner = LibRunner::new(Some(RunnerOptions { + plugin_agent_ptr: args.plugin_agent, + })); + let result = runner.run(&lib_path, args)?; + + remove_file(&lib_path)?; + clean_tmp_files(&temp_entry_file, &lib_suffix)?; + result + } + // If we don't enable llvm feature, the default running path is through the evaluator. + #[cfg(not(feature = "llvm"))] + { + FastRunner::new(Some(RunnerOptions { + plugin_agent_ptr: args.plugin_agent, + })) + .run(&program, args)? + } + }, + ) +} + +/// `execute_module` can directly execute the ast `Module`. +/// `execute_module` constructs `Program` with default pkg name `MAIN_PKG`, +/// and calls method `execute` with default `plugin_agent` and `ExecProgramArgs`. +/// For more information, see doc above method `execute`. +/// +/// **Note that it is not thread safe.** +pub fn execute_module(m: Module) -> Result { + let mut pkgs = HashMap::new(); + let mut modules = HashMap::new(); + pkgs.insert(MAIN_PKG.to_string(), vec![m.filename.clone()]); + modules.insert(m.filename.clone(), Arc::new(RwLock::new(m))); + + let prog = Program { + root: MAIN_PKG.to_string(), + pkgs, + modules, + pkgs_not_imported: HashMap::new(), + modules_not_imported: HashMap::new(), + }; + + execute( + ParseSessionRef::default(), + prog, + &ExecProgramArgs::default(), + ) +} + +/// Build a KCL program and generate a library artifact. +pub fn build_program>( + sess: ParseSessionRef, + args: &ExecProgramArgs, + output: Option

, +) -> Result { + // Parse program. + let opts = args.get_load_program_options(); + let kcl_paths_str = args + .k_filename_list + .iter() + .map(|s| s.as_str()) + .collect::>(); + let mut program = + load_program(sess.clone(), kcl_paths_str.as_slice(), Some(opts), None)?.program; + // Resolve program. + let scope = resolve_program(&mut program); + // Emit parse and resolve errors if exists. + emit_compile_diag_to_string(sess, &scope, false)?; + // When set the common package cache path, lock the package to prevent the + // data competition during compilation of different modules. + if let Ok(cache_path) = std::env::var(KCL_CACHE_PATH_ENV_VAR) { + build_with_lock(args, program, scope, &cache_path, output) + } else { + let temp_dir = std::env::temp_dir(); + build_with_lock(args, program, scope, &temp_dir.to_string_lossy(), output) + } +} + +fn build_with_lock>( + args: &ExecProgramArgs, + program: Program, + scope: ProgramScope, + cache_path: &str, + output: Option

, +) -> Result { + let lock_file = Path::new(&cache_path) + .join(format!("pkg.lock")) + .display() + .to_string(); + let mut lock_file = open_lock_file(&lock_file)?; + lock_file.lock()?; + let artifact = build(args, program, scope, output); + lock_file.unlock()?; + artifact +} + +fn build>( + args: &ExecProgramArgs, + program: Program, + scope: ProgramScope, + output: Option

, +) -> Result { + // Create a temp entry file and the temp dir will be delete automatically. + let temp_dir = tempdir()?; + let temp_dir_path = temp_dir.path().to_str().ok_or(anyhow!( + "Internal error: {}: No such file or directory", + temp_dir.path().display() + ))?; + let temp_entry_file = temp_file(temp_dir_path)?; + + // Link libs into one library. + let lib_suffix = Command::get_lib_suffix(); + // Temporary output of linker + let temp_out_lib_file = if let Some(output) = output { + output + .as_ref() + .to_str() + .ok_or(anyhow!("build output path is not found"))? + .to_string() + } else { + format!("{}{}", temp_entry_file, lib_suffix) + }; + // Generate native libs. + let lib_paths = assembler::KclvmAssembler::new( + program, + scope, + temp_entry_file.clone(), + KclvmLibAssembler::LLVM, + args.get_package_maps_from_external_pkg(), + ) + .gen_libs(args)?; + let lib_path = linker::KclvmLinker::link_all_libs(lib_paths, temp_out_lib_file)?; + + // Return the library artifact. + Artifact::from_path(lib_path) +} + +/// Clean all the tmp files generated during lib generating and linking. +#[inline] +#[cfg(feature = "llvm")] +fn clean_tmp_files(temp_entry_file: &String, lib_suffix: &String) -> Result<()> { + let temp_entry_lib_file = format!("{}{}", temp_entry_file, lib_suffix); + remove_file(&temp_entry_lib_file) +} + +#[inline] +#[cfg(feature = "llvm")] +fn remove_file(file: &str) -> Result<()> { + if Path::new(&file).exists() { + std::fs::remove_file(file)?; + } + Ok(()) +} + +/// Returns a temporary file name consisting of timestamp and process id. +fn temp_file(dir: &str) -> Result { + let timestamp = chrono::Local::now() + .timestamp_nanos_opt() + .unwrap_or_default(); + let id = std::process::id(); + let file = format!("{}_{}", id, timestamp); + std::fs::create_dir_all(dir)?; + Ok(Path::new(dir) + .join(file) + .to_str() + .ok_or(anyhow::anyhow!("{dir} not found"))? + .to_string()) +} + +// [`emit_compile_diag_to_string`] will emit compile diagnostics to string, including parsing and resolving diagnostics. +fn emit_compile_diag_to_string( + sess: ParseSessionRef, + scope: &ProgramScope, + include_warnings: bool, +) -> Result<()> { + let mut res_str = sess.1.write().emit_to_string()?; + let sema_err = scope.emit_diagnostics_to_string(sess.0.clone(), include_warnings); + if let Err(err) = &sema_err { + #[cfg(not(target_os = "windows"))] + res_str.push('\n'); + #[cfg(target_os = "windows")] + res_str.push_str("\r\n"); + res_str.push_str(err); + } + + res_str + .is_empty() + .then(|| Ok(())) + .unwrap_or_else(|| bail!(res_str)) +} diff --git a/kclvm/runner/src/linker.rs b/kclvm/runner/src/linker.rs new file mode 100644 index 000000000..81d1b661b --- /dev/null +++ b/kclvm/runner/src/linker.rs @@ -0,0 +1,236 @@ +use anyhow::Result; +use kclvm_utils::path::PathPrefix; +use std::env::consts::DLL_SUFFIX; +use std::path::PathBuf; + +const KCLVM_CLI_BIN_PATH_ENV_VAR: &str = "KCLVM_CLI_BIN_PATH"; +const KCLVM_LIB_LINK_PATH_ENV_VAR: &str = "KCLVM_LIB_LINK_PATH"; +const KCLVM_LIB_SHORT_NAME: &str = "kclvm_cli_cdylib"; +const EXEC_ROOT_NOT_FOUND_MSG: &str = "Internal error: the executable root is not found"; + +/// KclvmLinker is mainly responsible for linking the libs generated by KclvmAssembler. +pub struct KclvmLinker; +impl KclvmLinker { + /// Link the libs generated by method "gen_bc_or_ll_file". + pub fn link_all_libs(lib_paths: Vec, lib_path: String) -> Result { + // In the final stage of link, we can't ignore any undefined symbols and do + // not allow external mounting of the implementation. + Command::new()?.link_libs_with_cc(&lib_paths, &lib_path) + } +} + +#[derive(Debug)] +pub struct Command { + executable_root: String, +} + +impl Command { + pub fn new() -> Result { + let executable_root = Self::get_executable_root()?; + + Ok(Self { executable_root }) + } + + /// Link dynamic libraries into one library using cc-rs lib. + pub(crate) fn link_libs_with_cc(&mut self, libs: &[String], lib_path: &str) -> Result { + let lib_suffix = Self::get_lib_suffix(); + let lib_path = if lib_path.is_empty() { + format!("{}{}", "_a.out", lib_suffix) + } else if !lib_path.ends_with(&lib_suffix) { + format!("{}{}", lib_path, lib_suffix) + } else { + lib_path.to_string() + }; + + #[cfg(not(target_os = "windows"))] + let target = format!("{}-{}", std::env::consts::ARCH, std::env::consts::OS); + + #[cfg(target_os = "windows")] + let target = format!("{}-{}", std::env::consts::ARCH, Self::cc_env_windows()); + + let mut build = cc::Build::new(); + + build + .cargo_metadata(false) + .no_default_flags(false) + .pic(true) + .shared_flag(true) + .opt_level(0) + .target(&target) + .host(&target) + .flag("-o") + .flag(&lib_path); + + build.files(libs); + + // Run command with cc. + let mut cmd = build.try_get_compiler()?.to_command(); + self.add_args(libs, lib_path.to_string(), &mut cmd)?; + let result = cmd.output()?; + if !result.status.success() { + anyhow::bail!( + "run linker failed: stdout {}, stderr: {}", + String::from_utf8_lossy(&result.stdout), + String::from_utf8_lossy(&result.stderr) + ); + } + // Use absolute path. + let path = PathBuf::from(&lib_path).canonicalize()?; + Ok(path.adjust_canonicalization()) + } + + /// Add args for cc. + pub(crate) fn add_args( + &self, + libs: &[String], + lib_path: String, + cmd: &mut std::process::Command, + ) -> Result<()> { + #[cfg(not(target_os = "windows"))] + self.unix_args(libs, lib_path, cmd)?; + + #[cfg(target_os = "windows")] + self.msvc_win_args(libs, lib_path, cmd)?; + + Ok(()) + } + + /// Add args for cc on unix os. + #[cfg(not(target_os = "windows"))] + pub(crate) fn unix_args( + &self, + libs: &[String], + _lib_path: String, + cmd: &mut std::process::Command, + ) -> Result<()> { + let path = self.get_lib_link_path()?; + cmd.args(libs) + .arg(&format!("-Wl,-rpath,{}", &path)) + .arg(&format!("-L{}", &path)) + .arg(&format!("-I{}/include", self.executable_root)) + .arg(&format!("-l{KCLVM_LIB_SHORT_NAME}")); + Ok(()) + } + + // Add args for cc on windows os. + #[cfg(target_os = "windows")] + pub(crate) fn msvc_win_args( + &self, + libs: &[String], + lib_path: String, + cmd: &mut std::process::Command, + ) -> Result<()> { + cmd.args(libs) + .arg(&format!("{KCLVM_LIB_SHORT_NAME}.lib")) + .arg("/link") + .arg("/NOENTRY") + .arg("/NOLOGO") + .arg(format!(r#"/LIBPATH:"{}""#, self.get_lib_link_path()?)) + .arg("/DEFAULTLIB:msvcrt.lib") + .arg("/DEFAULTLIB:libcmt.lib") + .arg("/DLL") + .arg(format!("/OUT:{}", lib_path)) + .arg("/EXPORT:_kcl_run") + .arg("/EXPORT:kclvm_main") + .arg("/EXPORT:kclvm_plugin_init"); + Ok(()) + } + + /// Get the executable root. + fn get_executable_root() -> Result { + if let Ok(path) = std::env::var(KCLVM_CLI_BIN_PATH_ENV_VAR) { + return Ok(path); + } + let bin_name = if Self::is_windows() { + "kclvm_cli.exe" + } else { + "kclvm_cli" + }; + let p = if let Some(x) = Self::find_it(bin_name) { + x + } else { + std::env::current_exe()? + } + .canonicalize()?; + + let err = EXEC_ROOT_NOT_FOUND_MSG; + let p = p + .parent() + .ok_or(anyhow::anyhow!(err))? + .parent() + .ok_or(anyhow::anyhow!(err))?; + Ok(p.to_str().ok_or(anyhow::anyhow!(err))?.to_string()) + } + + /// Get KCLVM lib link path + pub(crate) fn get_lib_link_path(&self) -> Result { + let mut default_path = None; + for folder in ["lib", "bin"] { + let path = std::path::Path::new(&self.executable_root) + .join(folder) + .join(&Self::get_lib_name()); + if path.exists() { + default_path = Some( + path.parent() + .ok_or(anyhow::anyhow!("{} not found", path.display()))? + .to_string_lossy() + .to_string(), + ); + break; + } + } + Ok(std::env::var(KCLVM_LIB_LINK_PATH_ENV_VAR) + .ok() + .or(default_path) + .unwrap_or(self.executable_root.clone())) + } + + /// Get KCLVM lib name + pub(crate) fn get_lib_name() -> String { + let suffix = Self::get_lib_suffix(); + if Self::is_windows() { + format!("{KCLVM_LIB_SHORT_NAME}{suffix}") + } else { + format!("lib{KCLVM_LIB_SHORT_NAME}{suffix}") + } + } + + /// Specifies the filename suffix used for shared libraries on this + /// platform. Example value is `.so`. + /// + /// Some possible values: + /// + /// - .so + /// - .dylib + /// - .dll + pub(crate) fn get_lib_suffix() -> String { + DLL_SUFFIX.to_string() + } + + fn is_windows() -> bool { + cfg!(target_os = "windows") + } + + #[cfg(target_os = "windows")] + fn cc_env_windows() -> String { + "msvc".to_string() + } + + fn find_it

(exe_name: P) -> Option + where + P: AsRef, + { + std::env::var_os("PATH").and_then(|paths| { + std::env::split_paths(&paths) + .filter_map(|dir| { + let full_path = dir.join(&exe_name); + if full_path.is_file() { + Some(full_path) + } else { + None + } + }) + .next() + }) + } +} diff --git a/kclvm/runner/src/runner.rs b/kclvm/runner/src/runner.rs index f38efe6fe..b22825e77 100644 --- a/kclvm/runner/src/runner.rs +++ b/kclvm/runner/src/runner.rs @@ -1,9 +1,30 @@ -use serde::{Deserialize, Serialize}; +use anyhow::{anyhow, Result}; +use kclvm_evaluator::Evaluator; +use std::collections::HashMap; +use std::{cell::RefCell, rc::Rc}; use kclvm_ast::ast; +use kclvm_config::{ + modfile::get_vendor_home, + settings::{SettingsFile, SettingsPathBuf}, +}; +use kclvm_error::{Diagnostic, Handler}; +#[cfg(not(target_arch = "wasm32"))] +use kclvm_runtime::kclvm_plugin_init; +#[cfg(feature = "llvm")] +use kclvm_runtime::FFIRunOptions; +use kclvm_runtime::{Context, PanicInfo, RuntimePanicRecord}; +#[cfg(target_arch = "wasm32")] +use once_cell::sync::Lazy; +use serde::{Deserialize, Serialize}; +use std::ffi::OsStr; +use std::os::raw::c_char; + +const RESULT_SIZE: usize = 2048 * 2048; +const KCL_DEBUG_ERROR_ENV_VAR: &str = "KCL_DEBUG_ERROR"; #[allow(non_camel_case_types)] -pub type kclvm_char_t = i8; +pub type kclvm_char_t = c_char; #[allow(non_camel_case_types)] pub type kclvm_size_t = i32; #[allow(non_camel_case_types)] @@ -11,225 +32,609 @@ pub type kclvm_context_t = std::ffi::c_void; #[allow(non_camel_case_types)] pub type kclvm_value_ref_t = std::ffi::c_void; +/// ExecProgramArgs denotes the configuration required to execute the KCL program. #[derive(Serialize, Deserialize, Debug, Default, Clone)] pub struct ExecProgramArgs { pub work_dir: Option, pub k_filename_list: Vec, + /// -E key=value + pub external_pkgs: Vec, pub k_code_list: Vec, - - pub args: Vec, - pub overrides: Vec, - + /// -D key=value + pub args: Vec, + /// -O override_spec + pub overrides: Vec, + /// -S path_selector + pub path_selector: Vec, pub disable_yaml_result: bool, + /// Whether to apply overrides on the source code. pub print_override_ast: bool, - - // -r --strict-range-check + /// -r --strict-range-check pub strict_range_check: bool, - - // -n --disable-none + /// -n --disable-none pub disable_none: bool, - // -v --verbose + /// -v --verbose pub verbose: i32, - - // -d --debug + /// -d --debug pub debug: i32, - - // yaml/json: sort keys + /// yaml/json: sort keys pub sort_keys: bool, - // include schema type path in JSON/YAML result + /// Show hidden attributes + pub show_hidden: bool, + /// Whether including schema type in JSON/YAML result pub include_schema_type_path: bool, + /// Whether to compile only. + pub compile_only: bool, + /// plugin_agent is the address of plugin. + #[serde(skip)] + pub plugin_agent: u64, + /// fast_eval denotes directly executing at the AST level to obtain + /// the result without any form of compilation. + #[serde(skip)] + pub fast_eval: bool, } +impl ExecProgramArgs { + /// [`get_package_maps_from_external_pkg`] gets the package name to package path mapping. + pub fn get_package_maps_from_external_pkg(&self) -> HashMap { + let mut package_maps = HashMap::new(); + for external_pkg in &self.external_pkgs { + package_maps.insert(external_pkg.pkg_name.clone(), external_pkg.pkg_path.clone()); + } + package_maps + } + + /// [`set_external_pkg_from_package_maps`] sets the package name to package path mapping. + pub fn set_external_pkg_from_package_maps(&mut self, package_maps: HashMap) { + self.external_pkgs = package_maps + .iter() + .map(|(pkg_name, pkg_path)| ast::ExternalPkg { + pkg_name: pkg_name.clone(), + pkg_path: pkg_path.clone(), + }) + .collect(); + } +} + +/// ExecProgramResult denotes the running result of the KCL program. #[derive(Serialize, Deserialize, Debug, Default, Clone)] pub struct ExecProgramResult { pub json_result: String, pub yaml_result: String, + pub log_message: String, + pub err_message: String, +} + +pub trait MapErrorResult { + /// Map execute error message into the [`Result::Err`] + fn map_err_to_result(self) -> Result + where + Self: Sized; +} - pub escaped_time: String, +impl MapErrorResult for ExecProgramResult { + /// Map execute error message into the [`Result::Err`] + fn map_err_to_result(self) -> Result + where + Self: Sized, + { + if self.err_message.is_empty() { + Ok(self) + } else { + Err(anyhow!(self.err_message)) + } + } +} + +impl MapErrorResult for Result { + /// Map execute error message into the [`Result::Err`] + fn map_err_to_result(self) -> Result + where + Self: Sized, + { + match self { + Ok(result) => result.map_err_to_result(), + Err(err) => Err(err), + } + } } impl ExecProgramArgs { + /// Deserialize an instance of type [ExecProgramArgs] from a string of JSON text. pub fn from_str(s: &str) -> Self { if s.trim().is_empty() { return Default::default(); } serde_json::from_str::(s).expect(s) } + + /// Serialize the [ExecProgramArgs] structure as a String of JSON. pub fn to_json(&self) -> String { serde_json::ser::to_string(self).unwrap() } + /// Get the input file list. pub fn get_files(&self) -> Vec<&str> { self.k_filename_list.iter().map(|s| s.as_str()).collect() } + /// Get the [`kclvm_parser::LoadProgramOptions`] from the [`kclvm_runner::ExecProgramArgs`] pub fn get_load_program_options(&self) -> kclvm_parser::LoadProgramOptions { kclvm_parser::LoadProgramOptions { - work_dir: self.work_dir.clone().unwrap_or("".to_string()).clone(), + work_dir: self.work_dir.clone().unwrap_or_default(), + vendor_dirs: vec![get_vendor_home()], + package_maps: self.get_package_maps_from_external_pkg(), k_code_list: self.k_code_list.clone(), - cmd_args: self.args.clone(), - cmd_overrides: self.overrides.clone(), + load_plugins: self.plugin_agent > 0, ..Default::default() } } } +impl TryFrom for ExecProgramArgs { + type Error = anyhow::Error; + fn try_from(settings: SettingsFile) -> Result { + let mut args = Self::default(); + if let Some(cli_configs) = settings.kcl_cli_configs { + args.k_filename_list = cli_configs.files.unwrap_or_default(); + if args.k_filename_list.is_empty() { + args.k_filename_list = cli_configs.file.unwrap_or_default(); + } + args.strict_range_check = cli_configs.strict_range_check.unwrap_or_default(); + args.disable_none = cli_configs.disable_none.unwrap_or_default(); + args.verbose = cli_configs.verbose.unwrap_or_default() as i32; + args.debug = cli_configs.debug.unwrap_or_default() as i32; + args.sort_keys = cli_configs.sort_keys.unwrap_or_default(); + args.show_hidden = cli_configs.show_hidden.unwrap_or_default(); + args.fast_eval = cli_configs.fast_eval.unwrap_or_default(); + args.include_schema_type_path = + cli_configs.include_schema_type_path.unwrap_or_default(); + for override_str in cli_configs.overrides.unwrap_or_default() { + args.overrides.push(override_str); + } + args.path_selector = cli_configs.path_selector.unwrap_or_default(); + args.set_external_pkg_from_package_maps( + cli_configs.package_maps.unwrap_or(HashMap::default()), + ) + } + if let Some(options) = settings.kcl_options { + args.args = options + .iter() + .map(|o| ast::Argument { + name: o.key.to_string(), + value: o.value.to_string(), + }) + .collect(); + } + Ok(args) + } +} + +impl TryFrom for ExecProgramArgs { + type Error = anyhow::Error; + fn try_from(s: SettingsPathBuf) -> Result { + let mut args: ExecProgramArgs = s.settings().clone().try_into()?; + args.work_dir = s.path().clone().map(|p| p.to_string_lossy().to_string()); + Ok(args) + } +} + #[derive(Debug, Default)] -pub struct KclvmRunnerOptions { +pub struct RunnerOptions { pub plugin_agent_ptr: u64, } -pub struct KclvmRunner { - opts: KclvmRunnerOptions, - lib: libloading::Library, +#[cfg(feature = "llvm")] +/// A public struct named [Artifact] which wraps around the native library [libloading::Library]. +pub struct Artifact(libloading::Library, String); +#[cfg(not(feature = "llvm"))] +pub struct Artifact(String); + +pub trait ProgramRunner { + /// Run with the arguments [ExecProgramArgs] and return the program execute result that + /// contains the planning result and the evaluation errors if any. + fn run(&self, args: &ExecProgramArgs) -> Result; } -impl KclvmRunner { - pub fn new(dylib_path: &str, opts: Option) -> Self { - let lib = unsafe { - libloading::Library::new(std::path::PathBuf::from(dylib_path).canonicalize().unwrap()) - .unwrap() - }; +impl ProgramRunner for Artifact { + fn run(&self, args: &ExecProgramArgs) -> Result { + #[cfg(feature = "llvm")] + unsafe { + LibRunner::lib_kclvm_plugin_init(&self.0, args.plugin_agent)?; + LibRunner::lib_kcl_run(&self.0, args) + } + #[cfg(not(feature = "llvm"))] + { + let _ = args; + Err(anyhow::anyhow!("error: llvm feature is not enabled. Note: Set KCL_FAST_EVAL=1 or rebuild the crate with the llvm feature.")) + } + } +} + +#[cfg(feature = "llvm")] +impl Artifact { + #[inline] + pub fn from_path>(path: P) -> Result { + let path = path.as_ref().to_str().unwrap().to_string(); + let lib = unsafe { libloading::Library::new(&path)? }; + Ok(Self(lib, path)) + } + + #[inline] + pub fn get_path(&self) -> &String { + &self.1 + } +} + +#[cfg(not(feature = "llvm"))] +impl Artifact { + #[inline] + pub fn from_path>(path: P) -> Result { + let path = path.as_ref().to_str().unwrap().to_string(); + Ok(Self(path)) + } + + #[inline] + pub fn get_path(&self) -> &String { + &self.0 + } +} + +#[cfg(feature = "llvm")] +pub struct LibRunner { + opts: RunnerOptions, +} + +#[cfg(feature = "llvm")] +impl LibRunner { + /// New a runner using the lib path and options. + pub fn new(opts: Option) -> Self { Self { opts: opts.unwrap_or_default(), - lib, } } - pub fn run(&self, args: &ExecProgramArgs) -> Result { + /// Run kcl library with exec arguments. + pub fn run(&self, lib_path: &str, args: &ExecProgramArgs) -> Result { unsafe { - Self::dylib_kclvm_plugin_init(&self.lib, self.opts.plugin_agent_ptr); - Self::dylib_kcl_run(&self.lib, &args) + let lib = libloading::Library::new(std::path::PathBuf::from(lib_path).canonicalize()?)?; + Self::lib_kclvm_plugin_init(&lib, self.opts.plugin_agent_ptr)?; + Self::lib_kcl_run(&lib, args) } } } -impl KclvmRunner { - unsafe fn dylib_kclvm_plugin_init(lib: &libloading::Library, plugin_method_ptr: u64) { +#[cfg(feature = "llvm")] +impl LibRunner { + unsafe fn lib_kclvm_plugin_init( + lib: &libloading::Library, + plugin_method_ptr: u64, + ) -> Result<()> { // get kclvm_plugin_init let kclvm_plugin_init: libloading::Symbol< unsafe extern "C" fn( fn_ptr: extern "C" fn( - method: *const i8, - args_json: *const i8, - kwargs_json: *const i8, - ) -> *const i8, + method: *const c_char, + args_json: *const c_char, + kwargs_json: *const c_char, + ) -> *const c_char, ), - > = lib.get(b"kclvm_plugin_init").unwrap(); + > = lib.get(b"kclvm_plugin_init")?; // get plugin_method let plugin_method_ptr = plugin_method_ptr; let plugin_method_ptr = (plugin_method_ptr as *const u64) as *const () as *const extern "C" fn( - method: *const i8, - args: *const i8, - kwargs: *const i8, - ) -> *const i8; + method: *const c_char, + args: *const c_char, + kwargs: *const c_char, + ) -> *const c_char; let plugin_method: extern "C" fn( - method: *const i8, - args: *const i8, - kwargs: *const i8, - ) -> *const i8 = std::mem::transmute(plugin_method_ptr); + method: *const c_char, + args: *const c_char, + kwargs: *const c_char, + ) -> *const c_char = std::mem::transmute(plugin_method_ptr); // register plugin agent kclvm_plugin_init(plugin_method); + Ok(()) } - unsafe fn dylib_kcl_run( + unsafe fn lib_kcl_run( lib: &libloading::Library, args: &ExecProgramArgs, - ) -> Result { + ) -> Result { let kcl_run: libloading::Symbol< unsafe extern "C" fn( kclvm_main_ptr: u64, // main.k => kclvm_main option_len: kclvm_size_t, option_keys: *const *const kclvm_char_t, option_values: *const *const kclvm_char_t, - strict_range_check: i32, - disable_none: i32, - disable_schema_check: i32, - list_option_mode: i32, - debug_mode: i32, - result_buffer_len: kclvm_size_t, - result_buffer: *mut kclvm_char_t, - warn_buffer_len: kclvm_size_t, - warn_buffer: *mut kclvm_char_t, + opts: FFIRunOptions, + path_selector: *const *const kclvm_char_t, + json_result_buffer_len: *mut kclvm_size_t, + json_result_buffer: *mut kclvm_char_t, + yaml_result_buffer_len: *mut kclvm_size_t, + yaml_result_buffer: *mut kclvm_char_t, + err_buffer_len: *mut kclvm_size_t, + err_buffer: *mut kclvm_char_t, + log_buffer_len: *mut kclvm_size_t, + log_buffer: *mut kclvm_char_t, ) -> kclvm_size_t, - > = lib.get(b"_kcl_run").unwrap(); + > = lib.get(b"_kcl_run")?; - let kclvm_main: libloading::Symbol = lib.get(b"kclvm_main").unwrap(); + // The lib main function + let kclvm_main: libloading::Symbol = lib.get(b"kclvm_main")?; let kclvm_main_ptr = kclvm_main.into_raw().into_raw() as u64; + // CLI configs option len let option_len = args.args.len() as kclvm_size_t; - + // CLI configs option keys let cstr_argv: Vec<_> = args .args .iter() .map(|arg| std::ffi::CString::new(arg.name.as_str()).unwrap()) .collect(); - let mut p_argv: Vec<_> = cstr_argv .iter() // do NOT into_iter() .map(|arg| arg.as_ptr()) .collect(); p_argv.push(std::ptr::null()); - - let p: *const *const kclvm_char_t = p_argv.as_ptr(); - let option_keys = p; - + let option_keys = p_argv.as_ptr(); + // CLI configs option values let cstr_argv: Vec<_> = args .args .iter() .map(|arg| std::ffi::CString::new(arg.value.as_str()).unwrap()) .collect(); - let mut p_argv: Vec<_> = cstr_argv .iter() // do NOT into_iter() .map(|arg| arg.as_ptr()) .collect(); p_argv.push(std::ptr::null()); - - let p: *const *const kclvm_char_t = p_argv.as_ptr(); - let option_values = p; - - let strict_range_check = args.strict_range_check as i32; - let disable_none = args.disable_none as i32; - let disable_schema_check = 0; // todo - let list_option_mode = 0; // todo - let debug_mode = args.debug as i32; - - let mut result = vec![0u8; 1024 * 1024]; - let result_buffer_len = result.len() as i32 - 1; - let result_buffer = result.as_mut_ptr() as *mut i8; - - let mut warn_data = vec![0u8; 1024 * 1024]; - let warn_buffer_len = warn_data.len() as i32 - 1; - let warn_buffer = warn_data.as_mut_ptr() as *mut i8; - - let n = kcl_run( + let option_values = p_argv.as_ptr(); + // path selectors + let cstr_argv: Vec<_> = args + .path_selector + .iter() + .map(|arg| std::ffi::CString::new(arg.as_str()).unwrap()) + .collect(); + let mut p_argv: Vec<_> = cstr_argv + .iter() // do NOT into_iter() + .map(|arg| arg.as_ptr()) + .collect(); + p_argv.push(std::ptr::null()); + let path_selector = p_argv.as_ptr(); + + let opts = FFIRunOptions { + strict_range_check: args.strict_range_check as i32, + disable_none: args.disable_none as i32, + disable_schema_check: 0, + disable_empty_list: 0, + sort_keys: args.sort_keys as i32, + show_hidden: args.show_hidden as i32, + debug_mode: args.debug, + include_schema_type_path: args.include_schema_type_path as i32, + }; + let mut json_buffer = Buffer::make(); + let mut yaml_buffer = Buffer::make(); + let mut log_buffer = Buffer::make(); + let mut err_buffer = Buffer::make(); + // Input the main function, options and return the exec result + // including JSON and YAML result, log message and error message. + kcl_run( kclvm_main_ptr, option_len, option_keys, option_values, - strict_range_check, - disable_none, - disable_schema_check, - list_option_mode, - debug_mode, - result_buffer_len, - result_buffer, - warn_buffer_len, - warn_buffer, + opts, + path_selector, + json_buffer.mut_len(), + json_buffer.mut_ptr(), + yaml_buffer.mut_len(), + yaml_buffer.mut_ptr(), + err_buffer.mut_len(), + err_buffer.mut_ptr(), + log_buffer.mut_len(), + log_buffer.mut_ptr(), ); + // Convert runtime result to ExecProgramResult + let mut result = ExecProgramResult { + yaml_result: yaml_buffer.to_string()?, + json_result: json_buffer.to_string()?, + log_message: log_buffer.to_string()?, + err_message: err_buffer.to_string()?, + }; + // Wrap runtime JSON Panic error string into diagnostic style string. + if !result.err_message.is_empty() && std::env::var(KCL_DEBUG_ERROR_ENV_VAR).is_err() { + result.err_message = match Handler::default() + .add_diagnostic(>::into(PanicInfo::from( + result.err_message.as_str(), + ))) + .emit_to_string() + { + Ok(msg) => msg, + Err(err) => err.to_string(), + }; + } + Ok(result) + } +} - if n > 0 { - let return_len = n; - let s = std::str::from_utf8(&result[0..return_len as usize]).unwrap(); - Ok(s.to_string()) - } else { - let return_len = 0 - n; - let s = std::str::from_utf8(&warn_data[0..return_len as usize]).unwrap(); - Err(s.to_string()) +thread_local! { + pub static KCL_RUNTIME_PANIC_RECORD: RefCell = RefCell::new(RuntimePanicRecord::default()) +} + +#[cfg(target_arch = "wasm32")] +static ONCE_PANIC_HOOK: Lazy<()> = Lazy::new(|| { + std::panic::set_hook(Box::new(|info: &std::panic::PanicInfo| { + KCL_RUNTIME_PANIC_RECORD.with(|record| { + let mut record = record.borrow_mut(); + record.kcl_panic_info = true; + record.message = if let Some(s) = info.payload().downcast_ref::<&str>() { + s.to_string() + } else if let Some(s) = info.payload().downcast_ref::<&String>() { + (*s).clone() + } else if let Some(s) = info.payload().downcast_ref::() { + (*s).clone() + } else { + "unknown runtime error".to_string() + }; + if let Some(location) = info.location() { + record.rust_file = location.file().to_string(); + record.rust_line = location.line() as i32; + record.rust_col = location.column() as i32; + } + }) + })); +}); + +pub struct FastRunner { + opts: RunnerOptions, +} + +impl FastRunner { + /// New a runner using the lib path and options. + pub fn new(opts: Option) -> Self { + Self { + opts: opts.unwrap_or_default(), + } + } + + /// Run kcl library with exec arguments. + pub fn run(&self, program: &ast::Program, args: &ExecProgramArgs) -> Result { + let ctx = Rc::new(RefCell::new(args_to_ctx(program, args))); + let evaluator = Evaluator::new_with_runtime_ctx(program, ctx.clone()); + #[cfg(target_arch = "wasm32")] + // Ensure the panic hook is set (this will only happen once) for the WASM target, + // because it is single threaded. + Lazy::force(&ONCE_PANIC_HOOK); + #[cfg(not(target_arch = "wasm32"))] + let prev_hook = std::panic::take_hook(); + #[cfg(not(target_arch = "wasm32"))] + std::panic::set_hook(Box::new(|info: &std::panic::PanicInfo| { + KCL_RUNTIME_PANIC_RECORD.with(|record| { + let mut record = record.borrow_mut(); + record.kcl_panic_info = true; + record.message = if let Some(s) = info.payload().downcast_ref::<&str>() { + s.to_string() + } else if let Some(s) = info.payload().downcast_ref::<&String>() { + (*s).clone() + } else if let Some(s) = info.payload().downcast_ref::() { + (*s).clone() + } else { + "unknown runtime error".to_string() + }; + if let Some(location) = info.location() { + record.rust_file = location.file().to_string(); + record.rust_line = location.line() as i32; + record.rust_col = location.column() as i32; + } + }) + })); + let evaluator_result = std::panic::catch_unwind(|| { + if self.opts.plugin_agent_ptr > 0 { + #[cfg(not(target_arch = "wasm32"))] + unsafe { + let plugin_method: extern "C" fn( + method: *const c_char, + args: *const c_char, + kwargs: *const c_char, + ) -> *const c_char = std::mem::transmute(self.opts.plugin_agent_ptr); + kclvm_plugin_init(plugin_method); + } + } + evaluator.run() + }); + #[cfg(not(target_arch = "wasm32"))] + std::panic::set_hook(prev_hook); + KCL_RUNTIME_PANIC_RECORD.with(|record| { + let record = record.borrow(); + ctx.borrow_mut().set_panic_info(&record); + }); + let mut result = ExecProgramResult { + log_message: ctx.borrow().log_message.clone(), + ..Default::default() + }; + let is_err = evaluator_result.is_err(); + match evaluator_result { + Ok(r) => match r { + Ok((json, yaml)) => { + result.json_result = json; + result.yaml_result = yaml; + } + Err(err) => { + result.err_message = err.to_string(); + } + }, + Err(err) => { + result.err_message = if is_err { + ctx.borrow() + .get_panic_info_json_string() + .unwrap_or_default() + } else { + kclvm_error::err_to_str(err) + }; + } + } + // Wrap runtime JSON Panic error string into diagnostic style string. + if !result.err_message.is_empty() && std::env::var(KCL_DEBUG_ERROR_ENV_VAR).is_err() { + result.err_message = match Handler::default() + .add_diagnostic(>::into(PanicInfo::from( + result.err_message.as_str(), + ))) + .emit_to_string() + { + Ok(msg) => msg, + Err(err) => err.to_string(), + }; } + // Free all value references at runtime. This is because the runtime context marks + // all KCL objects and holds their copies, so it is necessary to actively GC them. + ctx.borrow().gc(); + Ok(result) + } +} + +pub(crate) fn args_to_ctx(program: &ast::Program, args: &ExecProgramArgs) -> Context { + let mut ctx = Context::new(); + ctx.cfg.strict_range_check = args.strict_range_check; + ctx.cfg.debug_mode = args.debug != 0; + ctx.plan_opts.disable_none = args.disable_none; + ctx.plan_opts.show_hidden = args.show_hidden; + ctx.plan_opts.sort_keys = args.sort_keys; + ctx.plan_opts.include_schema_type_path = args.include_schema_type_path; + ctx.plan_opts.query_paths = args.path_selector.clone(); + for arg in &args.args { + ctx.builtin_option_init(&arg.name, &arg.value); + } + ctx.set_kcl_workdir(&args.work_dir.clone().unwrap_or_default()); + ctx.set_kcl_module_path(&program.root); + ctx +} + +#[repr(C)] +pub struct Buffer(Vec, i32); + +impl Buffer { + #[inline] + pub fn make() -> Self { + let buffer = vec![0u8; RESULT_SIZE]; + Self(buffer, RESULT_SIZE as i32 - 1) + } + + #[inline] + pub fn to_string(&self) -> anyhow::Result { + Ok(String::from_utf8(self.0[0..self.1 as usize].to_vec())?) + } + + #[inline] + pub fn mut_ptr(&mut self) -> *mut c_char { + self.0.as_mut_ptr() as *mut c_char + } + + #[inline] + pub fn mut_len(&mut self) -> &mut i32 { + &mut self.1 } } diff --git a/kclvm/runner/src/test_datas/compile_recursive/kcl1/main.k b/kclvm/runner/src/test_datas/compile_recursive/kcl1/main.k new file mode 100644 index 000000000..23d3c668c --- /dev/null +++ b/kclvm/runner/src/test_datas/compile_recursive/kcl1/main.k @@ -0,0 +1 @@ +k1 = 'Hello k1!' \ No newline at end of file diff --git a/kclvm/runner/src/test_datas/compile_recursive/kcl2/main.k b/kclvm/runner/src/test_datas/compile_recursive/kcl2/main.k new file mode 100644 index 000000000..0cc5f31c5 --- /dev/null +++ b/kclvm/runner/src/test_datas/compile_recursive/kcl2/main.k @@ -0,0 +1 @@ +k2 = 'Hello k2!' \ No newline at end of file diff --git a/kclvm/runner/src/test_datas/compile_recursive/main.k b/kclvm/runner/src/test_datas/compile_recursive/main.k new file mode 100644 index 000000000..fa7048e63 --- /dev/null +++ b/kclvm/runner/src/test_datas/compile_recursive/main.k @@ -0,0 +1 @@ +The_first_kcl_program = 'Hello World!' \ No newline at end of file diff --git a/kclvm/runner/src/test_datas/exec_prog_args/default.json b/kclvm/runner/src/test_datas/exec_prog_args/default.json new file mode 100644 index 000000000..0ccfdb556 --- /dev/null +++ b/kclvm/runner/src/test_datas/exec_prog_args/default.json @@ -0,0 +1 @@ +{"work_dir":null,"k_filename_list":[],"external_pkgs":[],"k_code_list":[],"args":[],"overrides":[],"path_selector":[],"disable_yaml_result":false,"print_override_ast":false,"strict_range_check":false,"disable_none":false,"verbose":0,"debug":0,"sort_keys":false,"show_hidden":false,"include_schema_type_path":false,"compile_only":false} \ No newline at end of file diff --git a/kclvm/runner/src/test_datas/init_check_order_0/main.k b/kclvm/runner/src/test_datas/init_check_order_0/main.k new file mode 100644 index 000000000..a76f90c8b --- /dev/null +++ b/kclvm/runner/src/test_datas/init_check_order_0/main.k @@ -0,0 +1,11 @@ +schema Person: + name: str + age: int + gender: str + info: str = "{}, {}, {} years old".format(name, gender, age) + +alice = Person { + "name": "alice", + "age": 10, + "gender": "female" +} diff --git a/kclvm/runner/src/test_datas/init_check_order_0/stdout.golden.json b/kclvm/runner/src/test_datas/init_check_order_0/stdout.golden.json new file mode 100644 index 000000000..a80a0c009 --- /dev/null +++ b/kclvm/runner/src/test_datas/init_check_order_0/stdout.golden.json @@ -0,0 +1 @@ +{"alice": {"name": "alice", "age": 10, "gender": "female", "info": "alice, female, 10 years old"}} \ No newline at end of file diff --git a/kclvm/runner/src/test_datas/init_check_order_1/main.k b/kclvm/runner/src/test_datas/init_check_order_1/main.k new file mode 100644 index 000000000..2711ed87e --- /dev/null +++ b/kclvm/runner/src/test_datas/init_check_order_1/main.k @@ -0,0 +1,61 @@ +schema Name: + mixin [UpperMixin] + firstName: str + lastName: str + upper: str + + # print("init name") + +schema Person(Name): + gender: str + title: str + info: str + + # print("init person") + +schema Girl(Person): + mixin [TitleMixin, InfoMixin] + gender: str = "female" + added: str = "some girl attr" + + # print("init girl") + + check: + gender == "female", "gender should be female in Girl" + +schema Boy(Person): + mixin [TitleMixin, InfoMixin] + gender: str = "male" + added: str = "some boy attr" + + # print("init boy") + + check: + gender == "male", "gender should be male in Boy" + +schema UpperMixin: + # print("init upperMixin") + upper: str = lastName.upper() + +schema TitleMixin: + # print("init title mixin") + if gender == "female": + title = "Ms.{}".format(lastName) + else: + title = "Mr.{}".format(lastName) + +schema InfoMixin: + # print("init info mixin") + info = "{}, {}".format(title, gender) + +alice = Girl { + "firstName": "Alice", + "lastName": "Smith" +} + +# print(" ===") + +bob = Boy { + "firstName": "Bob", + "lastName": "Green" +} diff --git a/kclvm/runner/src/test_datas/init_check_order_1/stdout.golden.json b/kclvm/runner/src/test_datas/init_check_order_1/stdout.golden.json new file mode 100644 index 000000000..c56067a6c --- /dev/null +++ b/kclvm/runner/src/test_datas/init_check_order_1/stdout.golden.json @@ -0,0 +1 @@ +{"alice": {"firstName": "Alice", "lastName": "Smith", "upper": "SMITH", "gender": "female", "title": "Ms.Smith", "info": "Ms.Smith, female", "added": "some girl attr"}, "bob": {"firstName": "Bob", "lastName": "Green", "upper": "GREEN", "gender": "male", "title": "Mr.Green", "info": "Mr.Green, male", "added": "some boy attr"}} \ No newline at end of file diff --git a/kclvm/runner/src/test_datas/multi_file_compilation/import_abs_path/app-main/main.k b/kclvm/runner/src/test_datas/multi_file_compilation/import_abs_path/app-main/main.k new file mode 100644 index 000000000..912eb0857 --- /dev/null +++ b/kclvm/runner/src/test_datas/multi_file_compilation/import_abs_path/app-main/main.k @@ -0,0 +1,7 @@ +import some0.pkg1 as some00 +import some1.pkg1 as some10 +import ..some1.pkg1 as some11 + +Name1 = some00.Name # some0.pkg1.name +Name2 = some10.Name # some1.pkg1.name +Name3 = some11.Name # some1.pkg1.name diff --git a/kclvm/runner/src/test_datas/multi_file_compilation/import_abs_path/app-main/some1/pkg1/pkg1.k b/kclvm/runner/src/test_datas/multi_file_compilation/import_abs_path/app-main/some1/pkg1/pkg1.k new file mode 100644 index 000000000..3fcc664c9 --- /dev/null +++ b/kclvm/runner/src/test_datas/multi_file_compilation/import_abs_path/app-main/some1/pkg1/pkg1.k @@ -0,0 +1 @@ +Name = '.some1.pkg1.name' diff --git a/test/test_units/test_kclvm/test_config/test_data/kcl.mod b/kclvm/runner/src/test_datas/multi_file_compilation/import_abs_path/kcl.mod similarity index 100% rename from test/test_units/test_kclvm/test_config/test_data/kcl.mod rename to kclvm/runner/src/test_datas/multi_file_compilation/import_abs_path/kcl.mod diff --git a/kclvm/runner/src/test_datas/multi_file_compilation/import_abs_path/some0/pkg1/pkg1.k b/kclvm/runner/src/test_datas/multi_file_compilation/import_abs_path/some0/pkg1/pkg1.k new file mode 100644 index 000000000..6ddf6bada --- /dev/null +++ b/kclvm/runner/src/test_datas/multi_file_compilation/import_abs_path/some0/pkg1/pkg1.k @@ -0,0 +1 @@ +Name = 'some0.pkg1.name' diff --git a/kclvm/runner/src/test_datas/multi_file_compilation/import_abs_path/some1/pkg1/pkg1.k b/kclvm/runner/src/test_datas/multi_file_compilation/import_abs_path/some1/pkg1/pkg1.k new file mode 100644 index 000000000..6e08e1de8 --- /dev/null +++ b/kclvm/runner/src/test_datas/multi_file_compilation/import_abs_path/some1/pkg1/pkg1.k @@ -0,0 +1 @@ +Name = 'some1.pkg1.name' diff --git a/test/test_units/test_kclvm/test_program/test_exec/testdata/schema_infer/kcl.mod b/kclvm/runner/src/test_datas/multi_file_compilation/import_regular_module/kcl.mod similarity index 100% rename from test/test_units/test_kclvm/test_program/test_exec/testdata/schema_infer/kcl.mod rename to kclvm/runner/src/test_datas/multi_file_compilation/import_regular_module/kcl.mod diff --git a/kclvm/runner/src/test_datas/multi_file_compilation/import_regular_module/main.k b/kclvm/runner/src/test_datas/multi_file_compilation/import_regular_module/main.k new file mode 100644 index 000000000..a12cf1ce8 --- /dev/null +++ b/kclvm/runner/src/test_datas/multi_file_compilation/import_regular_module/main.k @@ -0,0 +1,3 @@ +import mymodule + +result = mymodule.data.num diff --git a/test/test_units/test_kclvm/test_compiler/test_build/invalid_testdata/nest_import/module.k b/kclvm/runner/src/test_datas/multi_file_compilation/import_regular_module/mymodule.k similarity index 100% rename from test/test_units/test_kclvm/test_compiler/test_build/invalid_testdata/nest_import/module.k rename to kclvm/runner/src/test_datas/multi_file_compilation/import_regular_module/mymodule.k diff --git a/test/test_units/test_kclvm/test_rpc_server/testdata/kcl-module/kcl.mod b/kclvm/runner/src/test_datas/multi_file_compilation/import_regular_module_as/kcl.mod similarity index 100% rename from test/test_units/test_kclvm/test_rpc_server/testdata/kcl-module/kcl.mod rename to kclvm/runner/src/test_datas/multi_file_compilation/import_regular_module_as/kcl.mod diff --git a/kclvm/runner/src/test_datas/multi_file_compilation/import_regular_module_as/main.k b/kclvm/runner/src/test_datas/multi_file_compilation/import_regular_module_as/main.k new file mode 100644 index 000000000..c6ff5e75a --- /dev/null +++ b/kclvm/runner/src/test_datas/multi_file_compilation/import_regular_module_as/main.k @@ -0,0 +1,3 @@ +import mymodule as mm + +result = mm.data.num diff --git a/kclvm/runner/src/test_datas/multi_file_compilation/import_regular_module_as/mymodule.k b/kclvm/runner/src/test_datas/multi_file_compilation/import_regular_module_as/mymodule.k new file mode 100644 index 000000000..db9135a5f --- /dev/null +++ b/kclvm/runner/src/test_datas/multi_file_compilation/import_regular_module_as/mymodule.k @@ -0,0 +1,6 @@ +schema Data: + num: int = 1 + +data = Data { + "num" = 100 +} diff --git a/kclvm/runner/src/test_datas/multi_file_compilation/no_kcl_mod_file/main.k b/kclvm/runner/src/test_datas/multi_file_compilation/no_kcl_mod_file/main.k new file mode 100644 index 000000000..cd9eda3dd --- /dev/null +++ b/kclvm/runner/src/test_datas/multi_file_compilation/no_kcl_mod_file/main.k @@ -0,0 +1,7 @@ +import pkg1 +import pkg2 + +# no kcl.mod, use dirname(main.k) as root + +Path1 = pkg1.Path +Path2 = pkg2.Path diff --git a/kclvm/runner/src/test_datas/multi_file_compilation/no_kcl_mod_file/pkg1/pkg.k b/kclvm/runner/src/test_datas/multi_file_compilation/no_kcl_mod_file/pkg1/pkg.k new file mode 100644 index 000000000..b6ec63378 --- /dev/null +++ b/kclvm/runner/src/test_datas/multi_file_compilation/no_kcl_mod_file/pkg1/pkg.k @@ -0,0 +1 @@ +Path = "pkg1" \ No newline at end of file diff --git a/kclvm/runner/src/test_datas/multi_file_compilation/no_kcl_mod_file/pkg2.k b/kclvm/runner/src/test_datas/multi_file_compilation/no_kcl_mod_file/pkg2.k new file mode 100644 index 000000000..d296fe1ab --- /dev/null +++ b/kclvm/runner/src/test_datas/multi_file_compilation/no_kcl_mod_file/pkg2.k @@ -0,0 +1 @@ +Path = "pkg2" \ No newline at end of file diff --git a/kclvm/runner/src/test_datas/multi_file_compilation/no_kcl_mod_file/stdout.golden b/kclvm/runner/src/test_datas/multi_file_compilation/no_kcl_mod_file/stdout.golden new file mode 100644 index 000000000..87b7c93f3 --- /dev/null +++ b/kclvm/runner/src/test_datas/multi_file_compilation/no_kcl_mod_file/stdout.golden @@ -0,0 +1,2 @@ +Path1: pkg1 +Path2: pkg2 diff --git a/kclvm/runner/src/test_datas/multi_file_compilation/relative_import/main.k b/kclvm/runner/src/test_datas/multi_file_compilation/relative_import/main.k new file mode 100644 index 000000000..346d8034b --- /dev/null +++ b/kclvm/runner/src/test_datas/multi_file_compilation/relative_import/main.k @@ -0,0 +1,4 @@ +import .mydir.mymodule +import .mydir.mydir2.mymodule2 + +result = mymodule2.data1.num \ No newline at end of file diff --git a/kclvm/runner/src/test_datas/multi_file_compilation/relative_import/mydir/mydir2/mymodule2.k b/kclvm/runner/src/test_datas/multi_file_compilation/relative_import/mydir/mydir2/mymodule2.k new file mode 100644 index 000000000..efa3e35aa --- /dev/null +++ b/kclvm/runner/src/test_datas/multi_file_compilation/relative_import/mydir/mydir2/mymodule2.k @@ -0,0 +1,6 @@ +schema data: + num : int = 1 + +data1 = data { + "num" = 10 +} diff --git a/kclvm/runner/src/test_datas/multi_file_compilation/relative_import/mydir/mymodule.k b/kclvm/runner/src/test_datas/multi_file_compilation/relative_import/mydir/mymodule.k new file mode 100644 index 000000000..72367c5c3 --- /dev/null +++ b/kclvm/runner/src/test_datas/multi_file_compilation/relative_import/mydir/mymodule.k @@ -0,0 +1,6 @@ +schema data: + num : int = 1 + +data0 = data { + "num" = 100 +} diff --git a/kclvm/runner/src/test_datas/multi_file_compilation/relative_import_as/main.k b/kclvm/runner/src/test_datas/multi_file_compilation/relative_import_as/main.k new file mode 100644 index 000000000..5ba0e0e4f --- /dev/null +++ b/kclvm/runner/src/test_datas/multi_file_compilation/relative_import_as/main.k @@ -0,0 +1,4 @@ +import .mydir.mymodule as m1 +import .mydir.mydir2.mymodule2 as m2 + +result = m2.data1.num diff --git a/kclvm/runner/src/test_datas/multi_file_compilation/relative_import_as/mydir/mydir2/mymodule2.k b/kclvm/runner/src/test_datas/multi_file_compilation/relative_import_as/mydir/mydir2/mymodule2.k new file mode 100644 index 000000000..7fc22a7b6 --- /dev/null +++ b/kclvm/runner/src/test_datas/multi_file_compilation/relative_import_as/mydir/mydir2/mymodule2.k @@ -0,0 +1,6 @@ +schema data: + num: int = 1 + +data1 = data { + "num" = 10 +} diff --git a/kclvm/runner/src/test_datas/multi_file_compilation/relative_import_as/mydir/mymodule.k b/kclvm/runner/src/test_datas/multi_file_compilation/relative_import_as/mydir/mymodule.k new file mode 100644 index 000000000..5832188b9 --- /dev/null +++ b/kclvm/runner/src/test_datas/multi_file_compilation/relative_import_as/mydir/mymodule.k @@ -0,0 +1,6 @@ +schema data: + num: int = 1 + +data0 = data { + "num" = 100 +} diff --git a/kclvm/runner/src/test_datas/multi_vars_0/main.k b/kclvm/runner/src/test_datas/multi_vars_0/main.k new file mode 100644 index 000000000..6263c0633 --- /dev/null +++ b/kclvm/runner/src/test_datas/multi_vars_0/main.k @@ -0,0 +1,5 @@ +data = [1, 2, 3] +dataLoop1 = [i for i, v in data] # [0, 1, 2] +dataLoop2 = [i * 2 for i in data] # [2, 4, 6] +dataLoop3 = [i for i in data if i == 2] # [2] +dataLoop4 = [i if i > 2 else i + 1 for i in data] # [2, 3, 3] diff --git a/kclvm/runner/src/test_datas/multi_vars_0/stdout.golden.json b/kclvm/runner/src/test_datas/multi_vars_0/stdout.golden.json new file mode 100644 index 000000000..563723179 --- /dev/null +++ b/kclvm/runner/src/test_datas/multi_vars_0/stdout.golden.json @@ -0,0 +1 @@ +{"data":[1,2,3],"dataLoop1":[0,1,2],"dataLoop2":[2,4,6],"dataLoop3":[2],"dataLoop4":[2,3,3]} \ No newline at end of file diff --git a/kclvm/runner/src/test_datas/normal_2/main.k b/kclvm/runner/src/test_datas/normal_2/main.k new file mode 100644 index 000000000..2a7b43467 --- /dev/null +++ b/kclvm/runner/src/test_datas/normal_2/main.k @@ -0,0 +1,11 @@ + +schema NumberMap: + [num: str]: int + + check: + int(num) % 2 == 0 + +numMap = NumberMap { + str(0): 0 + str(2): 2 +} diff --git a/kclvm/runner/src/test_datas/normal_2/stdout.golden.json b/kclvm/runner/src/test_datas/normal_2/stdout.golden.json new file mode 100644 index 000000000..c9f63ad19 --- /dev/null +++ b/kclvm/runner/src/test_datas/normal_2/stdout.golden.json @@ -0,0 +1 @@ +{"numMap":{"0":0,"2":2}} \ No newline at end of file diff --git a/kclvm/runner/src/test_datas/settings_file/settings.json b/kclvm/runner/src/test_datas/settings_file/settings.json new file mode 100644 index 000000000..b3567f2ea --- /dev/null +++ b/kclvm/runner/src/test_datas/settings_file/settings.json @@ -0,0 +1 @@ +{"work_dir":null,"k_filename_list":["../main.k","./before/base.k","./main.k","./sub/sub.k"],"external_pkgs":[],"k_code_list":[],"args":[{"name":"app-name","value":"\"kclvm\""},{"name":"image","value":"\"kclvm:v0.0.1\""}],"overrides":[],"path_selector":[],"disable_yaml_result":false,"print_override_ast":false,"strict_range_check":false,"disable_none":false,"verbose":0,"debug":0,"sort_keys":false,"show_hidden":false,"include_schema_type_path":false,"compile_only":false} \ No newline at end of file diff --git a/kclvm/runner/src/test_datas/settings_file/settings.yaml b/kclvm/runner/src/test_datas/settings_file/settings.yaml new file mode 100644 index 000000000..8b7a8a399 --- /dev/null +++ b/kclvm/runner/src/test_datas/settings_file/settings.yaml @@ -0,0 +1,14 @@ +kcl_cli_configs: + files: + - ../main.k + - ./before/base.k + - ./main.k + - ./sub/sub.k + disable_none: false + strict_range_check: false + debug: false +kcl_options: + - key: app-name + value: kclvm + - key: image + value: kclvm:v0.0.1 diff --git a/kclvm/runner/src/test_datas/type_annotation_not_full_2/main.k b/kclvm/runner/src/test_datas/type_annotation_not_full_2/main.k new file mode 100644 index 000000000..5d277e7f0 --- /dev/null +++ b/kclvm/runner/src/test_datas/type_annotation_not_full_2/main.k @@ -0,0 +1,6 @@ +schema A[arg=1]: + a: int = arg + +a1 = A() +a2 = A(2) +a3 = A(arg=3) diff --git a/kclvm/runner/src/test_datas/type_annotation_not_full_2/stdout.golden.json b/kclvm/runner/src/test_datas/type_annotation_not_full_2/stdout.golden.json new file mode 100644 index 000000000..c200367c8 --- /dev/null +++ b/kclvm/runner/src/test_datas/type_annotation_not_full_2/stdout.golden.json @@ -0,0 +1 @@ +{"a1":{"a":1},"a2":{"a":2},"a3":{"a":3}} \ No newline at end of file diff --git a/kclvm/runner/src/test_file_pattern/kcl1/kcl.mod b/kclvm/runner/src/test_file_pattern/kcl1/kcl.mod new file mode 100644 index 000000000..ab572545d --- /dev/null +++ b/kclvm/runner/src/test_file_pattern/kcl1/kcl.mod @@ -0,0 +1,5 @@ +[package] +name = "kcl1" +edition = "0.0.1" +version = "0.0.1" + diff --git a/kclvm/runner/src/test_file_pattern/kcl1/kcl3/kcl.mod b/kclvm/runner/src/test_file_pattern/kcl1/kcl3/kcl.mod new file mode 100644 index 000000000..b99124970 --- /dev/null +++ b/kclvm/runner/src/test_file_pattern/kcl1/kcl3/kcl.mod @@ -0,0 +1,5 @@ +[package] +name = "kcl3" +edition = "0.0.1" +version = "0.0.1" + diff --git a/kclvm/runner/src/test_file_pattern/kcl1/kcl3/main.k b/kclvm/runner/src/test_file_pattern/kcl1/kcl3/main.k new file mode 100644 index 000000000..0acce2f52 --- /dev/null +++ b/kclvm/runner/src/test_file_pattern/kcl1/kcl3/main.k @@ -0,0 +1 @@ +k3 = 'Hello World!' \ No newline at end of file diff --git a/kclvm/runner/src/test_file_pattern/kcl1/main.k b/kclvm/runner/src/test_file_pattern/kcl1/main.k new file mode 100644 index 000000000..ac6689514 --- /dev/null +++ b/kclvm/runner/src/test_file_pattern/kcl1/main.k @@ -0,0 +1 @@ +k1 = 'Hello World!' \ No newline at end of file diff --git a/kclvm/runner/src/test_file_pattern/kcl2/kcl.mod b/kclvm/runner/src/test_file_pattern/kcl2/kcl.mod new file mode 100644 index 000000000..5fb058acd --- /dev/null +++ b/kclvm/runner/src/test_file_pattern/kcl2/kcl.mod @@ -0,0 +1,5 @@ +[package] +name = "kcl2" +edition = "0.0.1" +version = "0.0.1" + diff --git a/kclvm/runner/src/test_file_pattern/kcl2/main.k b/kclvm/runner/src/test_file_pattern/kcl2/main.k new file mode 100644 index 000000000..fe6900bb4 --- /dev/null +++ b/kclvm/runner/src/test_file_pattern/kcl2/main.k @@ -0,0 +1 @@ +k2 = 'Hello World!' \ No newline at end of file diff --git a/kclvm/runner/src/test_indent_error/if_indent_err.k b/kclvm/runner/src/test_indent_error/if_indent_err.k new file mode 100644 index 000000000..04c753795 --- /dev/null +++ b/kclvm/runner/src/test_indent_error/if_indent_err.k @@ -0,0 +1,4 @@ +_a = True +if _a : + a = 1 + b = 1 \ No newline at end of file diff --git a/kclvm/runner/src/test_indent_error/if_indent_err.stderr b/kclvm/runner/src/test_indent_error/if_indent_err.stderr new file mode 100644 index 000000000..9e60cd8c5 --- /dev/null +++ b/kclvm/runner/src/test_indent_error/if_indent_err.stderr @@ -0,0 +1 @@ +invalid indentation with 1 space, try to align indents by adding or removing spaces \ No newline at end of file diff --git a/kclvm/runner/src/test_indent_error/schema_indent_err.k b/kclvm/runner/src/test_indent_error/schema_indent_err.k new file mode 100644 index 000000000..2bd207d0d --- /dev/null +++ b/kclvm/runner/src/test_indent_error/schema_indent_err.k @@ -0,0 +1,11 @@ +schema MySchema: + metadata: {str:} = {} + metadata1: {str:} = {} + +metadata.environment = "dev" + + +output = MySchema { + metadata.environment = "qa" + metadata.name = "config" +} diff --git a/kclvm/runner/src/test_indent_error/schema_indent_err.stderr b/kclvm/runner/src/test_indent_error/schema_indent_err.stderr new file mode 100644 index 000000000..9e60cd8c5 --- /dev/null +++ b/kclvm/runner/src/test_indent_error/schema_indent_err.stderr @@ -0,0 +1 @@ +invalid indentation with 1 space, try to align indents by adding or removing spaces \ No newline at end of file diff --git a/kclvm/runner/src/test_symbolic_link/test_pkg/aaa/kcl.mod b/kclvm/runner/src/test_symbolic_link/test_pkg/aaa/kcl.mod new file mode 100644 index 000000000..045e4aa1f --- /dev/null +++ b/kclvm/runner/src/test_symbolic_link/test_pkg/aaa/kcl.mod @@ -0,0 +1,4 @@ +[package] +name = "aaa" +edition = "v0.10.0" +version = "0.0.1" diff --git a/kclvm/runner/src/test_symbolic_link/test_pkg/aaa/sub/main.k b/kclvm/runner/src/test_symbolic_link/test_pkg/aaa/sub/main.k new file mode 100644 index 000000000..d3131dde9 --- /dev/null +++ b/kclvm/runner/src/test_symbolic_link/test_pkg/aaa/sub/main.k @@ -0,0 +1,4 @@ +import .sub as s + +The_first_kcl_program = 'Hello World!' +b = s.sub \ No newline at end of file diff --git a/kclvm/runner/src/test_symbolic_link/test_pkg/aaa/sub/sub.k b/kclvm/runner/src/test_symbolic_link/test_pkg/aaa/sub/sub.k new file mode 100644 index 000000000..3fe1abe00 --- /dev/null +++ b/kclvm/runner/src/test_symbolic_link/test_pkg/aaa/sub/sub.k @@ -0,0 +1 @@ +sub = 1 \ No newline at end of file diff --git a/kclvm/runner/src/test_symbolic_link/test_pkg/bbb/kcl.mod b/kclvm/runner/src/test_symbolic_link/test_pkg/bbb/kcl.mod new file mode 100644 index 000000000..5815c866b --- /dev/null +++ b/kclvm/runner/src/test_symbolic_link/test_pkg/bbb/kcl.mod @@ -0,0 +1,4 @@ +[package] +name = "bbb" +edition = "v0.10.0" +version = "0.0.1" diff --git a/kclvm/runner/src/test_symbolic_link/test_pkg/bbb/main.k b/kclvm/runner/src/test_symbolic_link/test_pkg/bbb/main.k new file mode 120000 index 000000000..6bb0681f8 --- /dev/null +++ b/kclvm/runner/src/test_symbolic_link/test_pkg/bbb/main.k @@ -0,0 +1 @@ +../aaa/sub/main.k \ No newline at end of file diff --git a/kclvm/runner/src/test_symbolic_link/test_pkg/bbb/sub.k b/kclvm/runner/src/test_symbolic_link/test_pkg/bbb/sub.k new file mode 120000 index 000000000..5103975d1 --- /dev/null +++ b/kclvm/runner/src/test_symbolic_link/test_pkg/bbb/sub.k @@ -0,0 +1 @@ +../aaa/sub/sub.k \ No newline at end of file diff --git a/kclvm/runner/src/test_uuid/main.k b/kclvm/runner/src/test_uuid/main.k new file mode 100644 index 000000000..caec6bd4f --- /dev/null +++ b/kclvm/runner/src/test_uuid/main.k @@ -0,0 +1,3 @@ +import crypto + +a = crypto.uuid() \ No newline at end of file diff --git a/kclvm/runner/src/tests.rs b/kclvm/runner/src/tests.rs new file mode 100644 index 000000000..8e0f172e2 --- /dev/null +++ b/kclvm/runner/src/tests.rs @@ -0,0 +1,713 @@ +#[cfg(feature = "llvm")] +use crate::assembler::clean_path; +#[cfg(feature = "llvm")] +use crate::assembler::KclvmAssembler; +#[cfg(feature = "llvm")] +use crate::assembler::KclvmLibAssembler; +#[cfg(feature = "llvm")] +use crate::assembler::LibAssembler; +use crate::exec_program; +#[cfg(feature = "llvm")] +use crate::temp_file; +use crate::{execute, runner::ExecProgramArgs}; +#[cfg(feature = "llvm")] +use anyhow::Context; +use anyhow::Result; +use kclvm_ast::ast::{Module, Program}; +#[cfg(feature = "llvm")] +use kclvm_compiler::codegen::OBJECT_FILE_SUFFIX; +use kclvm_config::settings::load_file; +use kclvm_parser::load_program; +use kclvm_parser::ParseSession; +#[cfg(feature = "llvm")] +use kclvm_sema::resolver::resolve_program; +use serde_json::Value; +#[cfg(feature = "llvm")] +use std::fs::create_dir_all; +use std::path::{Path, PathBuf}; +use std::sync::Arc; +use std::sync::RwLock; +use std::{ + collections::HashMap, + fs::{self, File}, +}; +#[cfg(feature = "llvm")] +use tempfile::tempdir; +use uuid::Uuid; +use walkdir::WalkDir; + +#[cfg(feature = "llvm")] +const MULTI_FILE_TEST_CASES: &[&str; 5] = &[ + "no_kcl_mod_file", + "relative_import", + "relative_import_as", + "import_regular_module", + "import_regular_module_as", +]; + +const TEST_CASES: &[&str; 5] = &[ + "init_check_order_0", + "init_check_order_1", + "normal_2", + "type_annotation_not_full_2", + "multi_vars_0", +]; + +fn exec_data_path() -> String { + Path::new("src").join("exec_data").display().to_string() +} + +fn exec_err_data_path() -> String { + Path::new("src").join("exec_err_data").display().to_string() +} + +fn custom_manifests_data_path() -> String { + Path::new("src") + .join("custom_manifests_data") + .display() + .to_string() +} + +#[cfg(feature = "llvm")] +fn multi_file_test_cases() -> Vec { + let mut test_cases: Vec = MULTI_FILE_TEST_CASES + .iter() + .map(|case| { + Path::new("multi_file_compilation") + .join(case) + .display() + .to_string() + }) + .collect(); + + test_cases.push( + Path::new("multi_file_compilation") + .join("import_abs_path") + .join("app-main") + .display() + .to_string(), + ); + test_cases.push( + Path::new("..") + .join("..") + .join("..") + .join("..") + .join("test") + .join("integration") + .join("konfig") + .join("base") + .join("examples") + .join("job-example") + .join("dev") + .display() + .to_string(), + ); + + test_cases +} + +fn exec_prog_args_test_case() -> Vec { + vec![Path::new("exec_prog_args") + .join("default.json") + .display() + .to_string()] +} + +fn settings_file_test_case() -> Vec<(String, String)> { + vec![( + Path::new("settings_file") + .join("settings.yaml") + .display() + .to_string(), + Path::new("settings_file") + .join("settings.json") + .display() + .to_string(), + )] +} + +const EXPECTED_JSON_FILE_NAME: &str = "stdout.golden.json"; + +fn test_case_path() -> String { + Path::new("src").join("test_datas").display().to_string() +} + +const KCL_FILE_NAME: &str = "main.k"; +const MAIN_PKG_NAME: &str = "__main__"; +#[cfg(feature = "llvm")] +const CARGO_PATH: &str = env!("CARGO_MANIFEST_DIR"); + +#[derive(serde::Deserialize, serde::Serialize)] +struct SimplePanicInfo { + line: i32, + col: i32, + message: String, +} + +#[cfg(feature = "llvm")] +fn gen_full_path(rel_path: String) -> Result { + let mut cargo_file_path = PathBuf::from(CARGO_PATH); + cargo_file_path.push(&rel_path); + let full_path = cargo_file_path + .to_str() + .with_context(|| format!("No such file or directory '{}'", rel_path))?; + Ok(full_path.to_string()) +} + +/// Load test kcl file to ast.Program +fn load_test_program(filename: String) -> Program { + let module = kclvm_parser::parse_file_force_errors(&filename, None).unwrap(); + construct_program(module) +} + +#[cfg(feature = "llvm")] +fn parse_program(test_kcl_case_path: &str) -> Program { + let args = ExecProgramArgs::default(); + let opts = args.get_load_program_options(); + load_program( + Arc::new(ParseSession::default()), + &[test_kcl_case_path], + Some(opts), + None, + ) + .unwrap() + .program +} + +/// Construct ast.Program by ast.Module and default configuration. +/// Default configuration: +/// module.pkg = "__main__" +/// Program.root = "__main__" +fn construct_program(module: Module) -> Program { + let mut pkgs_ast = HashMap::new(); + pkgs_ast.insert(MAIN_PKG_NAME.to_string(), vec![module.filename.clone()]); + let mut modules = HashMap::new(); + modules.insert(module.filename.clone(), Arc::new(RwLock::new(module))); + Program { + root: MAIN_PKG_NAME.to_string(), + pkgs: pkgs_ast, + modules, + pkgs_not_imported: HashMap::new(), + modules_not_imported: HashMap::new(), + } +} + +#[cfg(feature = "llvm")] +fn construct_pkg_lib_path( + prog: &Program, + assembler: &KclvmAssembler, + main_path: &str, + suffix: String, +) -> Vec { + let cache_dir = assembler.construct_cache_dir(&prog.root); + let mut result = vec![]; + for (pkgpath, _) in &prog.pkgs { + if pkgpath == "__main__" { + result.push(PathBuf::from(format!("{}{}", main_path, suffix))); + } else { + result.push(cache_dir.join(format!("{}{}", pkgpath.clone(), suffix))); + } + } + result +} + +/// Load the expect result from stdout.golden.json +fn load_expect_file(filename: String) -> String { + let f = File::open(filename).unwrap(); + let v: serde_json::Value = serde_json::from_reader(f).unwrap(); + v.to_string() +} + +/// Format str by json str +fn format_str_by_json(str: String) -> String { + let v: serde_json::Value = serde_json::from_str(&str).unwrap(); + v.to_string() +} + +fn execute_for_test(kcl_path: &String) -> String { + let args = ExecProgramArgs::default(); + // Parse kcl file + let program = load_test_program(kcl_path.to_string()); + // Generate libs, link libs and execute. + execute(Arc::new(ParseSession::default()), program, &args) + .unwrap() + .json_result +} + +#[cfg(feature = "llvm")] +fn gen_assembler(entry_file: &str, test_kcl_case_path: &str) -> KclvmAssembler { + let mut prog = parse_program(test_kcl_case_path); + let scope = resolve_program(&mut prog); + KclvmAssembler::new( + prog.clone(), + scope, + entry_file.to_string(), + KclvmLibAssembler::LLVM, + HashMap::new(), + ) +} + +#[cfg(feature = "llvm")] +fn gen_libs_for_test(entry_file: &str, test_kcl_case_path: &str) { + let assembler = gen_assembler(entry_file, test_kcl_case_path); + + let expected_pkg_paths = construct_pkg_lib_path( + &parse_program(test_kcl_case_path), + &assembler, + PathBuf::from(entry_file).to_str().unwrap(), + OBJECT_FILE_SUFFIX.to_string(), + ); + + let lib_paths = assembler.gen_libs(&ExecProgramArgs::default()).unwrap(); + + assert_eq!(lib_paths.len(), expected_pkg_paths.len()); + + for pkg_path in &expected_pkg_paths { + assert_eq!(pkg_path.exists(), true); + } + + let tmp_main_lib_path = + fs::canonicalize(format!("{}{}", entry_file, OBJECT_FILE_SUFFIX)).unwrap(); + assert_eq!(tmp_main_lib_path.exists(), true); + + clean_path(tmp_main_lib_path.to_str().unwrap()).unwrap(); + assert_eq!(tmp_main_lib_path.exists(), false); +} + +#[cfg(feature = "llvm")] +fn assemble_lib_for_test( + entry_file: &str, + test_kcl_case_path: &str, + assembler: &KclvmLibAssembler, +) -> String { + // default args and configuration + let mut args = ExecProgramArgs::default(); + + args.k_filename_list.push(test_kcl_case_path.to_string()); + let files = args.get_files(); + let opts = args.get_load_program_options(); + let sess = Arc::new(ParseSession::default()); + // parse and resolve kcl + let mut program = load_program(sess, &files, Some(opts), None) + .unwrap() + .program; + + let scope = resolve_program(&mut program); + + // tmp file + let temp_entry_file_path = &format!("{}{}", entry_file, OBJECT_FILE_SUFFIX); + + // Assemble object files + assembler + .assemble( + &program, + scope.import_names, + entry_file, + temp_entry_file_path, + &ExecProgramArgs::default(), + ) + .unwrap() +} + +fn test_kclvm_runner_execute() { + for case in TEST_CASES { + let kcl_path = &Path::new(&test_case_path()) + .join(case) + .join(KCL_FILE_NAME) + .display() + .to_string(); + let expected_path = &Path::new(&test_case_path()) + .join(case) + .join(EXPECTED_JSON_FILE_NAME) + .display() + .to_string(); + let result = execute_for_test(kcl_path); + let expected_result = load_expect_file(expected_path.to_string()); + assert_eq!(expected_result, format_str_by_json(result)); + } +} + +#[test] +#[cfg(feature = "llvm")] +fn test_assemble_lib_llvm() { + for case in TEST_CASES { + let temp_dir = tempdir().unwrap(); + let temp_dir_path = temp_dir.path().to_str().unwrap(); + let temp_entry_file = temp_file(temp_dir_path).unwrap(); + let kcl_path = &Path::new(&test_case_path()) + .join(case) + .join(KCL_FILE_NAME) + .display() + .to_string(); + let assembler = &KclvmLibAssembler::LLVM; + + let lib_file = assemble_lib_for_test( + &format!("{}{}", temp_entry_file, "4assemble_lib"), + kcl_path, + assembler, + ); + + let lib_path = std::path::Path::new(&lib_file); + assert_eq!(lib_path.exists(), true); + clean_path(&lib_file).unwrap(); + assert_eq!(lib_path.exists(), false); + } +} + +#[test] +#[cfg(feature = "llvm")] +fn test_gen_libs() { + for case in multi_file_test_cases() { + let temp_dir = tempdir().unwrap(); + let temp_dir_path = temp_dir.path().to_str().unwrap(); + let temp_entry_file = temp_file(temp_dir_path).unwrap(); + + let kcl_path = gen_full_path( + Path::new(&test_case_path()) + .join(case) + .join(KCL_FILE_NAME) + .display() + .to_string(), + ) + .unwrap(); + gen_libs_for_test(&format!("{}{}", temp_entry_file, "4gen_libs"), &kcl_path); + } +} + +#[test] +#[cfg(feature = "llvm")] +fn test_clean_path_for_genlibs() { + let mut prog = parse_program( + &Path::new(".") + .join("src") + .join("test_datas") + .join("multi_file_compilation") + .join("import_abs_path") + .join("app-main") + .join("main.k") + .display() + .to_string(), + ); + let scope = resolve_program(&mut prog); + let assembler = KclvmAssembler::new( + prog, + scope, + String::new(), + KclvmLibAssembler::LLVM, + HashMap::new(), + ); + + let temp_dir = tempdir().unwrap(); + let temp_dir_path = temp_dir.path().to_str().unwrap(); + let tmp_file_path = &temp_file(temp_dir_path).unwrap(); + + create_dir_all(tmp_file_path).unwrap(); + + let file_name = &Path::new(tmp_file_path).join("test").display().to_string(); + let file_suffix = ".o"; + + File::create(file_name).unwrap(); + let path = std::path::Path::new(file_name); + assert_eq!(path.exists(), true); + + assembler + .clean_path_for_genlibs(file_name, file_suffix) + .unwrap(); + assert_eq!(path.exists(), false); + + let test1 = &format!("{}{}", file_name, ".test1.o"); + let test2 = &format!("{}{}", file_name, ".test2.o"); + File::create(test1).unwrap(); + File::create(test2).unwrap(); + let path1 = std::path::Path::new(test1); + + let path2 = std::path::Path::new(test2); + assert_eq!(path1.exists(), true); + assert_eq!(path2.exists(), true); + + assembler + .clean_path_for_genlibs(file_name, file_suffix) + .unwrap(); + assert_eq!(path1.exists(), false); + assert_eq!(path2.exists(), false); +} + +#[test] +fn test_to_json_program_arg() { + for case in exec_prog_args_test_case() { + let test_case_json_file = &Path::new(&test_case_path()) + .join(case) + .display() + .to_string(); + let expected_json_str = fs::read_to_string(test_case_json_file).unwrap(); + let exec_prog_args = ExecProgramArgs::default(); + assert_eq!(expected_json_str.trim(), exec_prog_args.to_json().trim()); + } +} + +#[test] +fn test_from_str_program_arg() { + for case in exec_prog_args_test_case() { + let test_case_json_file = &Path::new(&test_case_path()) + .join(case) + .display() + .to_string(); + let expected_json_str = fs::read_to_string(test_case_json_file).unwrap(); + let exec_prog_args = ExecProgramArgs::from_str(&expected_json_str); + assert_eq!(expected_json_str.trim(), exec_prog_args.to_json().trim()); + } +} + +#[test] +fn test_from_setting_file_program_arg() { + for (case_yaml, case_json) in settings_file_test_case() { + let test_case_yaml_file = &Path::new(&test_case_path()) + .join(case_yaml) + .display() + .to_string(); + let settings_file = load_file(test_case_yaml_file).unwrap(); + + let test_case_json_file = &Path::new(&test_case_path()) + .join(case_json) + .display() + .to_string(); + let expected_json_str = fs::read_to_string(test_case_json_file).unwrap(); + + let exec_prog_args = ExecProgramArgs::try_from(settings_file).unwrap(); + assert_eq!(expected_json_str.trim(), exec_prog_args.to_json().trim()); + } +} + +fn test_exec_file() { + let result = std::panic::catch_unwind(|| { + for file in get_files(exec_data_path(), false, true, ".k") { + exec(&file).unwrap(); + println!("{} - PASS", file); + } + }); + assert!(result.is_ok()); +} + +fn test_custom_manifests_output() { + exec_with_result_at(&custom_manifests_data_path()); +} + +fn test_exec_with_err_result() { + exec_with_err_result_at(&exec_err_data_path()); +} + +fn clean_dir(path: String) { + if let Ok(_) = fs::remove_dir_all(path) {} +} + +#[test] +fn test_exec() { + clean_dir( + Path::new(".") + .join("src") + .join("exec_data") + .join(".kclvm") + .display() + .to_string(), + ); + + clean_dir( + Path::new(".") + .join("src") + .join("exec_err_data") + .join(".kclvm") + .display() + .to_string(), + ); + + test_exec_file(); + println!("test_exec_file - PASS"); + + test_kclvm_runner_execute(); + println!("test_kclvm_runner_execute - PASS"); + + test_custom_manifests_output(); + println!("test_custom_manifests_output - PASS"); + + test_exec_with_err_result(); + println!("test_exec_with_err_result - PASS"); + + test_indent_error(); + println!("test_indent_error - PASS"); + + test_compile_with_file_pattern(); + println!("test_compile_with_file_pattern - PASS"); + + test_uuid(); + println!("test_uuid - PASS"); +} + +fn test_indent_error() { + let test_path = PathBuf::from("./src/test_indent_error"); + let kcl_files = get_files(test_path.clone(), false, true, ".k"); + let output_files = get_files(test_path, false, true, ".stderr"); + + for (kcl_file, err_file) in kcl_files.iter().zip(&output_files) { + let mut args = ExecProgramArgs::default(); + args.k_filename_list.push(kcl_file.to_string()); + let res = exec_program(Arc::new(ParseSession::default()), &args); + assert!(res.is_err()); + if let Err(err_msg) = res { + let expect_err = fs::read_to_string(err_file).expect("Failed to read file"); + assert!(err_msg.to_string().contains(&expect_err)); + } + } +} + +fn exec(file: &str) -> Result { + let mut args = ExecProgramArgs::default(); + args.k_filename_list.push(file.to_string()); + let opts = args.get_load_program_options(); + let sess = Arc::new(ParseSession::default()); + // Load AST program + let program = load_program(sess.clone(), &[file], Some(opts), None) + .unwrap() + .program; + // Resolve ATS, generate libs, link libs and execute. + match execute(sess, program, &args) { + Ok(result) => { + if result.err_message.is_empty() { + Ok(result.json_result) + } else { + Err(result.err_message) + } + } + Err(err) => Err(err.to_string()), + } +} + +/// Run all kcl files at path and compare the exec result with the expect output. +fn exec_with_result_at(path: &str) { + let kcl_files = get_files(path, false, true, ".k"); + let output_files = get_files(path, false, true, ".stdout.golden"); + for (kcl_file, output_file) in kcl_files.iter().zip(&output_files) { + let mut args = ExecProgramArgs::default(); + args.k_filename_list.push(kcl_file.to_string()); + let result = exec_program(Arc::new(ParseSession::default()), &args).unwrap(); + + #[cfg(not(target_os = "windows"))] + let newline = "\n"; + #[cfg(target_os = "windows")] + let newline = "\r\n"; + + let expected = std::fs::read_to_string(output_file) + .unwrap() + .strip_suffix(newline) + .unwrap() + .to_string(); + + #[cfg(target_os = "windows")] + let expected = expected.replace("\r\n", "\n"); + + assert_eq!( + result.yaml_result, expected, + "test case {} {} failed", + path, kcl_file + ); + } +} + +/// Run all kcl files at path and compare the exec error result with the expect error output. +fn exec_with_err_result_at(path: &str) { + let kcl_files = get_files(path, false, true, ".k"); + let output_files = get_files(path, false, true, ".stderr.json"); + + let prev_hook = std::panic::take_hook(); + // disable print panic info + std::panic::set_hook(Box::new(|_| {})); + let result = std::panic::catch_unwind(|| { + for (kcl_file, _) in kcl_files.iter().zip(&output_files) { + let mut args = ExecProgramArgs::default(); + args.k_filename_list.push(kcl_file.to_string()); + let result = exec_program(Arc::new(ParseSession::default()), &args); + if let Ok(result) = result { + assert!(!result.err_message.is_empty(), "{}", result.err_message); + } else { + assert!(result.is_err()); + } + } + }); + assert!(result.is_ok()); + std::panic::set_hook(prev_hook); +} + +/// Get kcl files from path. +fn get_files>( + path: P, + recursively: bool, + sorted: bool, + suffix: &str, +) -> Vec { + let mut files = vec![]; + for entry in WalkDir::new(path).into_iter().filter_map(|e| e.ok()) { + let path = entry.path(); + if path.is_file() { + let file = path.to_str().unwrap(); + if file.ends_with(suffix) && (recursively || entry.depth() == 1) { + files.push(file.to_string()) + } + } + } + if sorted { + files.sort(); + } + files +} + +fn test_compile_with_file_pattern() { + let test_path = PathBuf::from("./src/test_file_pattern/**/main.k"); + let mut args = ExecProgramArgs::default(); + args.k_filename_list.push(test_path.display().to_string()); + let res = exec_program(Arc::new(ParseSession::default()), &args); + assert!(res.is_ok()); + assert_eq!( + res.as_ref().unwrap().yaml_result, + "k3: Hello World!\nk1: Hello World!\nk2: Hello World!" + ); + assert_eq!( + res.as_ref().unwrap().json_result, + "{\"k3\": \"Hello World!\", \"k1\": \"Hello World!\", \"k2\": \"Hello World!\"}" + ); +} + +fn test_uuid() { + let res = exec( + &PathBuf::from(".") + .join("src") + .join("test_uuid") + .join("main.k") + .canonicalize() + .unwrap() + .display() + .to_string(), + ); + + let v: Value = serde_json::from_str(res.clone().unwrap().as_str()).unwrap(); + assert!(v["a"].as_str().is_some()); + if let Some(uuid_str) = v["a"].as_str() { + assert!(Uuid::parse_str(uuid_str).is_ok()); + } +} + +#[test] +fn test_compile_with_symbolic_link() { + let main_test_path = PathBuf::from("./src/test_symbolic_link/test_pkg/bbb/main.k"); + let mut args = ExecProgramArgs::default(); + args.k_filename_list + .push(main_test_path.display().to_string()); + let res = exec_program(Arc::new(ParseSession::default()), &args); + assert!(res.is_ok()); + assert_eq!( + res.as_ref().unwrap().yaml_result, + "The_first_kcl_program: Hello World!\nb: 1" + ); + assert_eq!( + res.as_ref().unwrap().json_result, + "{\"The_first_kcl_program\": \"Hello World!\", \"b\": 1}" + ); +} diff --git a/kclvm/runtime/Cargo.lock b/kclvm/runtime/Cargo.lock index 968c9976d..05641b334 100644 --- a/kclvm/runtime/Cargo.lock +++ b/kclvm/runtime/Cargo.lock @@ -398,9 +398,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.5.4" +version = "1.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461" +checksum = "d83f127d94bdbcda4c8cc2e50f6f84f4b611f69c902699ca385a39c3a75f9ff1" dependencies = [ "aho-corasick", "memchr", @@ -415,9 +415,9 @@ checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" [[package]] name = "regex-syntax" -version = "0.6.25" +version = "0.6.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" +checksum = "49b3de9ec5dc0a3417da371aab17d729997c15010e7fd24ff707773a33bddb64" [[package]] name = "ryu" diff --git a/kclvm/runtime/Cargo.toml b/kclvm/runtime/Cargo.toml index e6db54848..f0e4d1024 100644 --- a/kclvm/runtime/Cargo.toml +++ b/kclvm/runtime/Cargo.toml @@ -1,34 +1,23 @@ [package] name = "kclvm-runtime" -version = "0.1.0" +version = "0.11.0" edition = "2021" -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[lib] -crate-type = [ - "staticlib", - "cdylib", - "rlib" -] -name = "kclvm" -path = "src/lib.rs" - [dependencies] kclvm_runtime_internal_macros = { path = "./internal_macros" } -json_minimal = {path = "./src/3rdparty/json_minimal", version = "0.1.0"} +serde_json = {package = "serde_json", version = "= 1.0.115"} serde = { version = "1", features = ["derive"] } -serde_yaml = "0.8.23" - +serde_yaml = {path = "../third-party/serde_yaml"} +lazy_static = "1.4.0" +generational-arena = "0.2.9" base64 = "0.13.0" -serde_json = "1.0.69" libc = "0.2.112" itertools = "0.10.3" unic-ucd-bidi = "0.9" unic-ucd-category = "0.9" unicode-casing = "0.1" bstr = "0.2.16" -regex = "1.5" +regex = "1.5.5" md5 = "0.7.0" sha2 = "0.9.8" sha1 = "0.6.0" @@ -38,11 +27,18 @@ indexmap = "1.0" phf = { version = "0.9", features = ["macros"] } fancy-regex = "0.7.1" num-integer = "0.1.44" +glob = "0.3.0" +uuid = { version = "1.7.0", features = ["serde", "v4"] } +handlebars = "5.1.2" +walkdir = "2.5.0" +anyhow = "1" +blake3 = "1.5.4" +encoding = "0.2.33" -#pprof = { version = "0.4", features = ["flamegraph"] } +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +hostname = "0.4.0" +dns-lookup = "2.0.4" -[profile.release] -rpath = true -panic = "unwind" -opt-level = "z" # Optimize for size. -lto = true +[[bin]] +name = "gen-api-spec" +path = "scripts/gen-api-spec.rs" diff --git a/kclvm/runtime/Makefile b/kclvm/runtime/Makefile index d1453760d..c1c27b8be 100644 --- a/kclvm/runtime/Makefile +++ b/kclvm/runtime/Makefile @@ -1,78 +1,16 @@ default: make gen-api-spec - cargo test gen-api-spec: mkdir -p target cargo clean -q - kclvm_RUNTIME_GEN_API_SPEC= cargo build > ./src/_kclvm_api_spec.rs.tmp + KCLVM_RUNTIME_GEN_API_SPEC= cargo build -r > ./src/_kclvm_api_spec.rs.tmp - echo "// Copyright 2022 The KCL Authors. All rights reserved.\n" > ./src/_kclvm_api_spec.rs + echo "// Copyright The KCL Authors. All rights reserved.\n" > ./src/_kclvm_api_spec.rs echo "// Auto generated by command, DONOT EDIT!!!\n" >> ./src/_kclvm_api_spec.rs cat ./src/_kclvm_api_spec.rs.tmp >> ./src/_kclvm_api_spec.rs rm ./src/_kclvm_api_spec.rs.tmp - make -C ./tools/kclvm-runtime-gen-api - -dev: - cargo build - cargo run --bin hello-llvm - llvm-dis a.out.bc - - # Rust can't re-export from a linked C library (unless you rename) when compiled as a cdylib. - # https://marcopolo.io/code/from-c-to-rust-to-c/ - # https://github.com/rust-lang/rfcs/issues/2771 - - clang++ -stdlib=libc++ -std=c++14 -Wno-override-module -o a.out.exe a.out.bc ./target/debug/libkclvm.a - #clang++ -Wno-override-module -o a.out.exe a.out.bc ./target/debug/libkclvm.dylib - ./a.out.exe - -lib: - cargo build - #nm -gU ./target/debug/libkclvm.dylib - nm -gU ./target/debug/libkclvm.a - -ll: - # target/debug/deps/kclvm.ll - - # cargo build - # cargo rustc --lib -- --emit=llvm-ir - # cargo rustc --lib -- --emit=llvm-bc - # cp target/debug/deps/kclvm.ll target/kclvm-debug.ll - # cp target/debug/deps/kclvm.bc target/kclvm-debug.bc - - # https://stackoverflow.com/questions/69042049/rust-including-dependenies-in-llvm-bitcode - - RUSTFLAGS="--emit=llvm-bc" cargo build - llvm-link target/debug/deps/*.bc > target/kclvm-debug.bc - llvm-dis target/kclvm-debug.bc - -ll-release: - RUSTFLAGS="--emit=llvm-bc" cargo build --release - llvm-link target/release/deps/*.bc > target/kclvm-release.bc - llvm-dis target/kclvm-release.bc - -ll-wasm: - RUSTFLAGS="--emit=llvm-bc" cargo build --release --target wasm32-unknown-unknown - llvm-link target/wasm32-unknown-unknown/release/deps/*.bc > target/kclvm-wasm.bc - llvm-dis target/kclvm-wasm.bc - -fmt: - cargo fmt - -test: - cargo test - -# Only for linux, run it in docker -coverage: - cargo install cargo-tarpaulin - cargo tarpaulin -v - -lint: - cargo clippy - -clean: - -rm -rf target - -rm a.out + cargo run -r --bin gen-api-spec diff --git a/kclvm/runtime/internal_macros/Cargo.toml b/kclvm/runtime/internal_macros/Cargo.toml index 2b9db5b8b..3db5e19ac 100644 --- a/kclvm/runtime/internal_macros/Cargo.toml +++ b/kclvm/runtime/internal_macros/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "kclvm_runtime_internal_macros" -version = "0.1.0" +version = "0.5.0" edition = "2021" [dependencies] diff --git a/kclvm/runtime/internal_macros/src/lib.rs b/kclvm/runtime/internal_macros/src/lib.rs index 94ee77c2f..2a7ea763b 100644 --- a/kclvm/runtime/internal_macros/src/lib.rs +++ b/kclvm/runtime/internal_macros/src/lib.rs @@ -8,18 +8,18 @@ use syn::{parse_macro_input, FnArg}; pub fn runtime_fn(_attr: TokenStream, item: TokenStream) -> TokenStream { let parsed_fn = parse_macro_input!(item as syn::ItemFn); - if let Ok(_) = std::env::var("kclvm_RUNTIME_GEN_API_SPEC") { + if std::env::var("KCLVM_RUNTIME_GEN_API_SPEC").is_ok() { print_api_spec(&parsed_fn); } let x = quote! { #parsed_fn }; - return x.into(); + x.into() } // ---------------------------------------------------------------------------- - +#[allow(clippy::upper_case_acronyms)] #[derive(Debug)] enum TargetName { C, @@ -32,7 +32,7 @@ fn print_api_spec(fn_item: &syn::ItemFn) { let fn_llvm_sig = get_fn_sig(fn_item, &TargetName::LLVM); // skip _fn_name() - if !fn_name.starts_with("_") { + if !fn_name.starts_with('_') { println!("// api-spec: {}", fn_name); println!("// api-spec(c): {};", fn_c_sig); println!("// api-spec(llvm): {};", fn_llvm_sig); @@ -101,27 +101,29 @@ fn get_fn_args_type(fn_item: &syn::ItemFn, target: &TargetName) -> String { fn get_fn_arg_name(arg: &FnArg, target: &TargetName) -> String { match arg { - syn::FnArg::Typed(ty) => match ty { - syn::PatType { pat, .. } => match &**pat { + syn::FnArg::Typed(ty) => { + let syn::PatType { pat, .. } = ty; + match &**pat { syn::Pat::Ident(x) => match target { TargetName::C => x.ident.to_string(), TargetName::LLVM => format!("%{}", x.ident), }, _ => panic!("unsupported type: {}", quote!(#ty)), - }, - }, + } + } _ => panic!("unsupported arg: {}", quote!(#arg)), } } fn get_fn_arg_type(arg: &FnArg, target: &TargetName) -> String { match arg { - syn::FnArg::Typed(ty) => match ty { - syn::PatType { ty, .. } => match target { + syn::FnArg::Typed(ty) => { + let syn::PatType { ty, .. } = ty; + match target { TargetName::C => build_c_type(ty), TargetName::LLVM => build_llvm_type(ty), - }, - }, + } + } _ => panic!("unsupported fn arg: {}", quote!(#arg)), } } @@ -160,13 +162,13 @@ fn build_c_type(ty: &syn::Type) -> String { } syn::Type::Ptr(ty_ptr) => { let base_ty = &ty_ptr.elem; - let base_constr = build_c_type(&base_ty); - format!("{}*", base_constr).to_string() + let base_constr = build_c_type(base_ty); + format!("{}*", base_constr) } syn::Type::Reference(ty_ref) => { let base_ty = &ty_ref.elem; - let base_constr = build_c_type(&base_ty); - format!("{}*", base_constr).to_string() + let base_constr = build_c_type(base_ty); + format!("{}*", base_constr) } syn::Type::BareFn(_) => "void*".to_string(), syn::Type::Never(_) => "void".to_string(), @@ -199,13 +201,13 @@ fn build_llvm_type(ty: &syn::Type) -> String { } syn::Type::Ptr(ty_ptr) => { let base_ty = &ty_ptr.elem; - let base_constr = build_llvm_type(&base_ty); - format!("{}*", base_constr).to_string() + let base_constr = build_llvm_type(base_ty); + format!("{}*", base_constr) } syn::Type::Reference(ty_ref) => { let base_ty = &ty_ref.elem; - let base_constr = build_llvm_type(&base_ty); - format!("{}*", base_constr).to_string() + let base_constr = build_llvm_type(base_ty); + format!("{}*", base_constr) } syn::Type::BareFn(_) => "i8*".to_string(), syn::Type::Never(_) => "void".to_string(), diff --git a/kclvm/runtime/readme.md b/kclvm/runtime/readme.md deleted file mode 100644 index 1ff43103d..000000000 --- a/kclvm/runtime/readme.md +++ /dev/null @@ -1,7 +0,0 @@ -# KCLVM - runtime - -KCLVM runtime library. - -- run test: `make` -- regenerate llvm-ir file: `make gen-api-spec` -- lint code: `cargo clippy` diff --git a/kclvm/runtime/scripts/gen-api-spec.rs b/kclvm/runtime/scripts/gen-api-spec.rs new file mode 100644 index 000000000..28513805b --- /dev/null +++ b/kclvm/runtime/scripts/gen-api-spec.rs @@ -0,0 +1,307 @@ +use std::collections::HashMap; +use std::error::Error; +use std::fs; +use std::process; +use std::process::Command; +use std::process::ExitStatus; +use walkdir::WalkDir; + +const ROOT: &str = "./src"; +const C_API_FILE: &str = "./src/_kclvm.h"; +const LL_API_FILE: &str = "./src/_kclvm.ll"; +const RUST_API_ENUM: &str = "./src/_kclvm.rs"; +const RUST_API_ADDR: &str = "./src/_kclvm_addr.rs"; + +#[derive(Debug, Default)] +struct ApiSpec { + file: String, + line: usize, + name: String, + spec_c: String, + spec_ll: String, + is_type: bool, +} + +fn main() -> Result<(), Box> { + std::env::set_var("KCLVM_RUNTIME_GEN_API_SPEC", "1"); + let specs = load_all_api_spec(ROOT); + let src = gen_c_api(&specs); + fs::write(C_API_FILE, src).unwrap_or_else(|err| { + eprintln!("Failed to write C API file: {}", err); + process::exit(1); + }); + + let src = gen_ll_api(&specs); + fs::write(LL_API_FILE, src).unwrap_or_else(|err| { + eprintln!("Failed to write LLVM API file: {}", err); + process::exit(1); + }); + + let src = gen_rust_api_enum(&specs); + fs::write(RUST_API_ENUM, src).unwrap_or_else(|err| { + eprintln!("Failed to write Rust API Enum file: {}", err); + process::exit(1); + }); + + let src = gen_rust_api_addr(&specs); + fs::write(RUST_API_ADDR, src).unwrap_or_else(|err| { + eprintln!("Failed to write Rust API Addr file: {}", err); + process::exit(1); + }); + + run_llvm_as(LL_API_FILE)?; + run_cargo_fmt()?; + Ok(()) +} + +fn load_all_api_spec(root: &str) -> Vec { + let mut specs: HashMap = HashMap::new(); + let api_spec_prefix_name = "// api-spec:"; + let api_spec_prefix_c = "// api-spec(c):"; + let api_spec_prefix_ll = "// api-spec(llvm):"; + + for entry in WalkDir::new(root).into_iter().filter_map(|e| e.ok()) { + let path = entry.path(); + if path.is_dir() + || !path + .to_str() + .expect(&format!("{path:?} not found")) + .ends_with(".rs") + { + continue; + } + let data = fs::read_to_string(path).expect(&format!("{path:?} not found")); + let mut spec = ApiSpec::default(); + + for (i, line) in data.lines().enumerate() { + let line = line.trim(); + + if line.starts_with(api_spec_prefix_name) { + spec.file = path.display().to_string(); + spec.line = i + 1; + spec.name = line + .trim_start_matches(api_spec_prefix_name) + .trim() + .to_string(); + spec.is_type = spec.name.ends_with("_t"); + } else if line.starts_with(api_spec_prefix_c) { + if !spec.spec_c.is_empty() { + spec.spec_c.push(' '); + } + spec.spec_c + .push_str(line.trim_start_matches(api_spec_prefix_c).trim()); + } else if line.starts_with(api_spec_prefix_ll) { + if !spec.spec_ll.is_empty() { + spec.spec_ll.push(' '); + } + spec.spec_ll + .push_str(line.trim_start_matches(api_spec_prefix_ll).trim()); + } else { + if !spec.name.is_empty() { + if let Some(existing) = specs.get(&spec.name) { + eprintln!( + "WARN: {}:{} {} api-spec exists ({}:{})", + path.display(), + i + 1, + spec.name, + existing.file, + existing.line + ); + } + specs.insert(spec.name.clone(), spec); + } + spec = ApiSpec::default(); + } + } + } + + let mut spec_list: Vec = specs.into_values().collect(); + spec_list.sort_by(|a, b| a.name.cmp(&b.name)); + spec_list +} + +fn gen_c_api(specs: &[ApiSpec]) -> String { + let mut buf = String::new(); + + buf.push_str("// Copyright The KCL Authors. All rights reserved.\n\n"); + buf.push_str("// Auto generated, DONOT EDIT!!!\n\n"); + buf.push_str("#pragma once\n\n"); + buf.push_str("#ifndef _kclvm_h_\n#define _kclvm_h_\n\n"); + buf.push_str("#include \n#include \n#include \n\n"); + buf.push_str("#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n"); + + buf.push_str("// please keep same as 'kclvm/runtime/src/kind/mod.rs#Kind'\n\n"); + buf.push_str("enum kclvm_kind_t {\n"); + buf.push_str(" Invalid = 0,\n"); + buf.push_str(" Undefined = 1,\n"); + buf.push_str(" None = 2,\n"); + buf.push_str(" Bool = 3,\n"); + buf.push_str(" Int = 4,\n"); + buf.push_str(" Float = 5,\n"); + buf.push_str(" Str = 6,\n"); + buf.push_str(" List = 7,\n"); + buf.push_str(" Dict = 8,\n"); + buf.push_str(" Schema = 9,\n"); + buf.push_str(" Error = 10,\n"); + buf.push_str(" Any = 11,\n"); + buf.push_str(" Union = 12,\n"); + buf.push_str(" BoolLit = 13,\n"); + buf.push_str(" IntLit = 14,\n"); + buf.push_str(" FloatLit = 15,\n"); + buf.push_str(" StrLit = 16,\n"); + buf.push_str(" Func = 17,\n"); + buf.push_str(" Max = 18,\n"); + buf.push_str("};\n\n"); + + for spec in specs { + if spec.is_type { + buf.push_str(&spec.spec_c); + buf.push_str("\n\n"); + } + } + + for spec in specs { + if !spec.is_type { + buf.push_str(&spec.spec_c); + buf.push_str("\n\n"); + } + } + + buf.push_str("#ifdef __cplusplus\n} // extern \"C\"\n#endif\n\n"); + buf.push_str("#endif // _kclvm_h_\n"); + + fmt_code(&buf) +} + +fn gen_ll_api(specs: &[ApiSpec]) -> String { + let mut buf = String::new(); + + buf.push_str("; Copyright The KCL Authors. All rights reserved.\n\n"); + buf.push_str("; Auto generated, DONOT EDIT!!!\n\n"); + + for spec in specs { + if spec.is_type { + buf.push_str(&spec.spec_ll); + buf.push_str("\n\n"); + } + } + + for spec in specs { + if !spec.is_type { + buf.push_str(&spec.spec_ll); + buf.push_str("\n\n"); + } + } + + buf.push_str( + "define void @__kcl_keep_link_runtime(%kclvm_value_ref_t* %_a, %kclvm_context_t* %_b) {\n", + ); + buf.push_str(" call %kclvm_value_ref_t* @kclvm_value_None(%kclvm_context_t* %_b)\n"); + buf.push_str(" ret void\n"); + buf.push_str("}\n"); + + fmt_code(&buf) +} + +fn gen_rust_api_enum(specs: &[ApiSpec]) -> String { + let mut buf = String::new(); + + buf.push_str("// Copyright The KCL Authors. All rights reserved.\n\n"); + buf.push_str("// Auto generated, DONOT EDIT!!!\n\n"); + + // Enum ApiType + buf.push_str("#[allow(dead_code, non_camel_case_types)]\n"); + buf.push_str("#[derive(Clone, PartialEq, Eq, Debug, Hash)]\n"); + buf.push_str("pub enum ApiType {\n"); + buf.push_str(" Value,\n"); + buf.push_str("}\n"); + buf.push('\n'); + buf.push_str("impl std::fmt::Display for ApiType {\n"); + buf.push_str(" fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {\n"); + buf.push_str(" match self {\n"); + buf.push_str(" ApiType::Value => write!(f, \"{:?}\", \"api::kclvm::Value\"),\n"); + buf.push_str(" }\n"); + buf.push_str(" }\n"); + buf.push_str("}\n"); + buf.push('\n'); + buf.push_str("impl ApiType {\n"); + buf.push_str(" #[allow(dead_code)]\n"); + buf.push_str(" pub fn name(&self) -> String {\n"); + buf.push_str(" format!(\"{self:?}\")\n"); + buf.push_str(" }\n"); + buf.push_str("}\n"); + buf.push('\n'); + // Enum ApiFunc + buf.push_str("#[allow(dead_code, non_camel_case_types)]\n"); + buf.push_str("#[derive(Clone, PartialEq, Eq, Debug, Hash)]\n"); + buf.push_str("pub enum ApiFunc {\n"); + + for spec in specs { + if !spec.is_type { + buf.push_str(" "); + buf.push_str(&spec.name); + buf.push_str(",\n"); + } + } + + buf.push_str("}\n"); + buf.push('\n'); + buf.push_str("impl std::fmt::Display for ApiFunc {\n"); + buf.push_str(" fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {\n"); + buf.push_str(" write!(f, \"{self:?}\")\n"); + buf.push_str(" }\n"); + buf.push_str("}\n"); + buf.push('\n'); + buf.push_str("impl ApiFunc {\n"); + buf.push_str(" #[allow(dead_code)]\n"); + buf.push_str(" pub fn name(&self) -> String {\n"); + buf.push_str(" format!(\"{self:?}\")\n"); + buf.push_str(" }\n"); + buf.push_str("}\n"); + + fmt_code(&buf) +} + +fn gen_rust_api_addr(specs: &[ApiSpec]) -> String { + let mut buf = String::new(); + + buf.push_str("// Copyright The KCL Authors. All rights reserved.\n\n"); + buf.push_str("// Auto generated, DONOT EDIT!!!\n\n"); + + buf.push_str("#[allow(dead_code)]\n"); + buf.push_str("pub fn _kclvm_get_fn_ptr_by_name(name: &str) -> u64 {\n"); + buf.push_str(" match name {\n"); + + for spec in specs { + if !spec.is_type { + buf.push_str(" \""); + buf.push_str(&spec.name); + buf.push_str("\" => crate::"); + buf.push_str(&spec.name); + buf.push_str(" as *const () as u64,\n"); + } + } + + buf.push_str(" _ => panic!(\"unknown {name}\"),\n"); + buf.push_str(" }\n"); + buf.push_str("}\n"); + + fmt_code(&buf) +} + +fn fmt_code(s: &str) -> String { + s.split("\n\n\n") + .collect::>() + .join("\n\n") + .trim() + .to_string() + + "\n" +} + +fn run_llvm_as(file_path: &str) -> Result { + Command::new("llvm-as").arg(file_path).status() +} + +fn run_cargo_fmt() -> Result { + Command::new("cargo").arg("fmt").status() +} diff --git a/kclvm/runtime/src/3rdparty/json_minimal/Cargo.toml b/kclvm/runtime/src/3rdparty/json_minimal/Cargo.toml deleted file mode 100644 index 5fb678c94..000000000 --- a/kclvm/runtime/src/3rdparty/json_minimal/Cargo.toml +++ /dev/null @@ -1,13 +0,0 @@ -[package] -name = "json_minimal" -version = "0.1.3" -authors = ["36den"] -edition = "2021" -description = "A minimal json crate." -license = "MIT OR Apache-2.0" -keywords = ["json","minimal"] -categories = ["encoding"] -repository = "https://github.com/36den/json_minimal-rust" -readme = "README.md" - -[dependencies] diff --git a/kclvm/runtime/src/3rdparty/json_minimal/LICENSE.md b/kclvm/runtime/src/3rdparty/json_minimal/LICENSE.md deleted file mode 100644 index 5147935e1..000000000 --- a/kclvm/runtime/src/3rdparty/json_minimal/LICENSE.md +++ /dev/null @@ -1,19 +0,0 @@ -# APACHE - -Copyright 2020 36den - -Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at - -`http://www.apache.org/licenses/LICENSE-2.0` - -Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. - -# MIT - -Copyright 2020 36den - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/kclvm/runtime/src/3rdparty/json_minimal/README.md b/kclvm/runtime/src/3rdparty/json_minimal/README.md deleted file mode 100644 index f5869899a..000000000 --- a/kclvm/runtime/src/3rdparty/json_minimal/README.md +++ /dev/null @@ -1,316 +0,0 @@ -# json_minimal - -A minimal json crate conforming to https://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf . - -## Tutorial (creating jsons) - -In order to create a valid (i.e. generally accepted) json you should always start with: -```rust - use json_minimal::*; - - let mut json = Json::new(); - // which is equivalent to - let mut json = Json::JSON(Vec::new()); - // ... -``` - -To add an object, simply do this: -```rust - // ... - let greeting = - Json::OBJECT { - name: String::from("Greeting"), - - value: Box::new( - Json::STRING( String::from("Hello, world!") ) - ) - } - ; - - json.add(greeting); - // ... -``` -or alternatively: -```rust - // ... - json.add( - Json::OBJECT { - name: String::from("Greeting"), - - value: Box::new( - Json::STRING( String::from("Hello, world!") ) - ) - } - ); - // ... -``` - -As you can see, whilst the crate is minimal (in my opinion) it may not be the quickest to work with. This becomes clearer when adding an array to an object: -```rust - // ... - - let mut days_in_the_week = - Json::OBJECT { - name: String::from("Days of the week"), - - value: Box::new( - Json::JSON(Vec::new()) - ) - } - ; - - let mut days = Json::ARRAY(Vec::new()); - - days - .add( - Json::STRING( String::from("Monday") ) - ) - .add( - Json::STRING( String::from("Tuesday") ) - ) - .add( - Json::STRING( String::from("Wednesday") ) - ) - .add( - Json::STRING( String::from("Thursday") ) - ) - .add( - Json::STRING( String::from("Friday") ) - ) - .add( - Json::STRING( String::from("Saturday") ) - ) - .add( - Json::STRING( String::from("Sunday") ) - ) - ; - - days_in_the_week - .add( - Json::OBJECT { - name: String::from("Total number of days"), - - value: Box::new( - Json::NUMBER(7.0) // Accepts `f64` - ) - } - ) - .add( - Json::OBJECT { - name: String::from("They are called"), - - value: Box::new( - days - ) - } - ) - ; - - json.add(days_in_the_week); - // ... -``` - -In conclusion: -```rust - // ... - - let mut conclusion = - Json::OBJECT { - name: String::from("Conclusion"), - - value: Box::new( - Json::JSON(Vec::new()) - ) - } - ; - - conclusion - .add( - Json::OBJECT { - name: String::from("Minimal in my opinion"), - - value: Box::new( - Json::BOOL(true) - ) - } - ) - .add( - Json::OBJECT { - name: String::from("How much I care about your opinion"), - - value: Box::new( - Json::NULL - ) - } - ) - .add( - Json::OBJECT { - name: String::from("Comment"), - - value: Box::new( - Json::STRING( String::from(";)") ) - ) - } - ) - ; - - json.add(conclusion); - // ... -``` - -Calling: -```rust - // ... - let resulting_json = json.print(); -``` -will result in a `String` containing: -`{"Greeting":"Hello, world!","Days of the week":{"Total number of days":7,"They are called":["Monday","Tuesday","Wednesday","Thursday","Friday","Saturday","Sunday"]},"Conclusion":{"Minimal in my opinion":true,"How much I care about your opinion":null,"Comment":";)"}}` - -If you would like the json string in a different format you can easily make your own 'print' function. - -## Tutorial (parsing and working with jsons) - -Parsing a json value from bytes is even more minimal - at the cost of being more cumbersome. Let's see how we can parse the json we generated above: -```rust - use json_minimal::*; - - let json = match Json::parse(b"{\"Greeting\":\"Hello, world!\",\"Days of the week\":{\"Total number of days\":7,\"They are called\":[\"Monday\",\"Tuesday\",\"Wednesday\",\"Thursday\",\"Friday\",\"Saturday\",\"Sunday\"]},\"Conclusion\":{\"Minimal in my opinion\":true,\"How much I care about your opinion\":null,\"Comment\":\";)\"}}") { - Ok(json) => { - json - }, - Err( (position,message) ) => { - panic!("`{}` at position `{}`!!!"); - } - } - // ... -``` - -Let's first talk about what information is given for a parsing error. As you might expect it is minimal. `position` above is the position were everything went wrong and the `message` will be something like`"Error parsing array."` if, for example, a closing `]` is missing somewhere. Continuing where we left off: -```rust - // ... - match json.get("Greeting") { - Some(json) => { - match json { - Json::OBJECT { name: _, value } => { - match value.unbox() { - Json::STRING(val) => { - assert_eq!("Hello, world!",val); - }, - json => { - panic!("Expected Json::STRING but found {:?}",json); - } - } - }, - json => { - panic!("Expected Json::JSON but found {:?}!!!",json) - } - } - }, - None => { - panic!("Couln't find Greeting. How rude!"); - } - } - // ... -``` -Unfortunately all of this was necessary because, even though we were able to confirm that `"Greeting"` exists, we had no way of knowing what it really is. It's not over: -```rust - // ... - match json.get("Days of the week") { // Hint: You can also use `get_mut` to aid in editing/creating jsons... - Some(json) => { - match json { - Json::OBJECT { name: _, value } => { - match value.unbox() { - Json::JSON(values) => { - assert_eq!(values.len(),2); - - match &values[0] { - Json::OBJECT { name, value: _ } => { - assert_eq!("Total number of days",name); - }, - json => { - panic!("Expected Json::OBJECT but found {:?}!!!",json); - } - } - - match &values[1] { - Json::OBJECT { name, value: _ } => { - assert_eq!("They are called",name); - }, - json => { - panic!("Expected Json::OBJECT but found {:?}!!!",json); - } - } - - }, - json => { - panic!("Expected Json::JSON but found {:?}!!!",json); - } - } - }, - json => { - panic!("Expected Json::OBJECT but found {:?}!!!",json); - } - } - }, - None => { - panic!("Days of the week not found!"); - } - } - // You get the idea. -``` -The function `Json::parse(...)` can also parse 'standalone values'. Example: - -```rust - match Json::parse("\"What's up?\"") { - Ok(json) => { - match json { - Json::STRING(val) => { - assert_eq!("What's up?",val); - }, - json => { - panic!("Expected Json::STRING but found {:?}!!!",json); - } - } - }, - Err( (position,message) ) => { - panic!("`{}` at position `{}`."); - } - } - - // Another example: - - match Json::parse("[1,2,3,\"four\"]") { - Ok(json) => { - match json { - Json::ARRAY(val) => { - assert_eq!(val.len(),4); - }, - json => { - panic!("Expected Json::ARRAY but found {:?}!!!",json); - } - } - }, - Err( (position,message) ) => { - panic!("`{}` at position `{}`."); - } - } -``` -## Changes & Improvements - -* Lonami (github) has made improvements: - 1. `json_minimal` can now parse non-ASCII strings and escape sequences. (I overlooked this, I admit.) - 2. The code is cleaner thanks to the question-mark operator and using rustfmt. - 3. Some parsing stuff that didn't work now works. - - A thousand thanks to Lonami !!! - -* `json_minimal` can now also parse 'pretty' json like this (as long as only `\r`, `\n`, `\t` and whitespace were used for formatting): -``` -{ - "Array": [ "Hello" , "World" , "!" ] -} -``` -This should also have worked from the start but I did not include because it of my aversion to energy inefficiency (although it is, perhaps, unfounded). - ---- -Please let me know if something doesn't work. I can't promise i'll react immediately, though. \ No newline at end of file diff --git a/kclvm/runtime/src/3rdparty/json_minimal/src/lib.rs b/kclvm/runtime/src/3rdparty/json_minimal/src/lib.rs deleted file mode 100644 index 86dbdcd92..000000000 --- a/kclvm/runtime/src/3rdparty/json_minimal/src/lib.rs +++ /dev/null @@ -1,1070 +0,0 @@ -#[derive(Debug)] -pub enum Json { - OBJECT { name: String, value: Box }, - JSON(Vec), - ARRAY(Vec), - STRING(String), - NUMBER(f64), - INT(i64), - FLOAT(f64), - BOOL(bool), - NULL, -} - -#[derive(PartialEq, Clone, Default, Debug)] -pub struct PrintOption { - pub sort_keys: bool, - pub indent: i32, - pub sep_space: bool, - pub py_style_f64: bool, - pub append_null: bool, -} - -#[derive(PartialEq, Clone, Default, Debug)] -pub struct ParseOption { - pub support_int: bool, -} - -impl Json { - /// Construct a new `Json::JSON` - /// ## Example - /// ``` - /// use json_minimal::*; - /// - /// let mut json = Json::new(); - /// ``` - pub fn new() -> Json { - Json::JSON(Vec::new()) - } - - /// Add any `Json` variant to a `Json` variant of type `Json::JSON`, `Json::ARRAY` - /// or a `Json::OBJECT` (holding a `Json::JSON`,`Json::ARRAY`,`Json::OBJECT` (holding a `Json::JSON`,`Json::`...)). - /// ## Panics! - /// Will panic if the conditions stated above are not met OR if an attempt is made to add a `Json::JSON` to a `Json::JSON` - /// without wrapping it in a `Json::OBJECT` first. - /// ## Example - /// ``` - /// use json_minimal::*; - /// - /// let mut json = Json::new(); - /// - /// json - /// .add( - /// Json::OBJECT { - /// name: String::from("Greeting"), - /// - /// value: Box::new( - /// Json::STRING( String::from("Hello, world!") ) - /// ) - /// } - /// ) - /// ; - /// ``` - /// See the tutorial on github for more. - pub fn add(&mut self, value: Json) -> &mut Json { - match self { - Json::JSON(values) => match value { - Json::OBJECT { name, value } => { - values.push(Json::OBJECT { name, value }); - } - Json::JSON(_) => { - panic!("A `Json::JSON` may not be added to a `Json::JSON` if it is not within a `Json::OBJECT`."); - } - Json::ARRAY(vals) => { - values.push(Json::ARRAY(vals)); - } - Json::STRING(val) => { - values.push(Json::STRING(val)); - } - Json::NUMBER(val) => { - values.push(Json::NUMBER(val)); - } - Json::INT(val) => { - values.push(Json::INT(val)); - } - Json::FLOAT(val) => { - values.push(Json::FLOAT(val)); - } - Json::BOOL(val) => { - values.push(Json::BOOL(val)); - } - Json::NULL => { - values.push(Json::NULL); - } - }, - Json::OBJECT { - name: _, - value: obj_val, - } => match obj_val.unbox_mut() { - Json::JSON(values) => match value { - Json::OBJECT { name, value } => { - values.push(Json::OBJECT { name, value }); - } - Json::JSON(_) => { - panic!("A `Json::JSON` may not be added to a `Json::JSON` if it is not within a `Json::OBJECT`."); - } - Json::ARRAY(vals) => { - values.push(Json::ARRAY(vals)); - } - Json::STRING(val) => { - values.push(Json::STRING(val)); - } - Json::NUMBER(val) => { - values.push(Json::NUMBER(val)); - } - Json::INT(val) => { - values.push(Json::INT(val)); - } - Json::FLOAT(val) => { - values.push(Json::FLOAT(val)); - } - Json::BOOL(val) => { - values.push(Json::BOOL(val)); - } - Json::NULL => { - values.push(Json::NULL); - } - }, - Json::ARRAY(values) => match value { - Json::OBJECT { name, value } => { - values.push(Json::OBJECT { name, value }); - } - Json::JSON(vals) => { - values.push(Json::JSON(vals)); - } - Json::ARRAY(vals) => { - values.push(Json::ARRAY(vals)); - } - Json::STRING(val) => { - values.push(Json::STRING(val)); - } - Json::NUMBER(val) => { - values.push(Json::NUMBER(val)); - } - Json::INT(val) => { - values.push(Json::INT(val)); - } - Json::FLOAT(val) => { - values.push(Json::FLOAT(val)); - } - Json::BOOL(val) => { - values.push(Json::BOOL(val)); - } - Json::NULL => { - values.push(Json::NULL); - } - }, - json => { - panic!("The function `add(`&mut self`,`name: String`,`value: Json`)` may only be called on a `Json::JSON`, `Json::ARRAY` or `Json::OBJECT` holding a `Json::JSON` or `Json::ARRAY`. It was called on: {:?}",json); - } - }, - Json::ARRAY(values) => match value { - Json::OBJECT { name, value } => { - values.push(Json::OBJECT { name, value }); - } - Json::JSON(vals) => { - values.push(Json::JSON(vals)); - } - Json::ARRAY(vals) => { - values.push(Json::ARRAY(vals)); - } - Json::STRING(val) => { - values.push(Json::STRING(val)); - } - Json::NUMBER(val) => { - values.push(Json::NUMBER(val)); - } - Json::INT(val) => { - values.push(Json::INT(val)); - } - Json::FLOAT(val) => { - values.push(Json::FLOAT(val)); - } - Json::BOOL(val) => { - values.push(Json::BOOL(val)); - } - Json::NULL => { - values.push(Json::NULL); - } - }, - json => { - panic!("The function `add(`&mut self`,`name: String`,`value: Json`)` may only be called on a `Json::JSON`, `Json::ARRAY` or `Json::OBJECT` holding a `Json::JSON` or `Json::ARRAY`. It was called on: {:?}",json); - } - } - - self - } - - /// Get the `Json` with the requested name if it exists. - /// ## Panics - /// This function will panic if called on a `Json` variant other than `Json::JSON` or `Json::OBJECT`, - /// as only these two variants may hold `Json::OBJECT` (which has a `name` field). - /// ## Example - /// ``` - /// use json_minimal::*; - /// - /// let mut json = Json::new(); - /// - /// json - /// .add( - /// Json::OBJECT { - /// name: String::from("Greeting"), - /// - /// value: Box::new( - /// Json::STRING( String::from("Hello, world!") ) - /// ) - /// } - /// ) - /// ; - /// - /// match json.get("Greeting") { - /// Some(json) => { - /// match json { - /// Json::OBJECT { name, value } => { - /// match value.unbox() { // See `unbox()` below - /// Json::STRING(val) => { - /// assert_eq!("Hello, world!",val); - /// }, - /// _ => { - /// panic!("I expected this to be a `Json::STRING`!!!"); - /// } - /// } - /// }, - /// _ => { - /// panic!("This shouldn't happen!!!"); - /// } - /// } - /// }, - /// None => { - /// panic!("Not found!!!"); - /// } - /// } - /// ``` - pub fn get(&self, search: &str) -> Option<&Json> { - match self { - Json::JSON(values) => { - for n in 0..values.len() { - match &values[n] { - Json::OBJECT { name, value: _ } => { - if name == search { - return Some(&values[n]); - } - } - _ => {} - } - } - - return None; - } - Json::OBJECT { name: _, value } => match value.unbox() { - Json::JSON(values) => { - for n in 0..values.len() { - match &values[n] { - Json::OBJECT { name, value: _ } => { - if name == search { - return Some(&values[n]); - } - } - _ => {} - } - } - - return None; - } - json => { - panic!("The function `get(`&self`,`search: &str`)` may only be called on a `Json::JSON` or a `Json::OBJECT` holding a `Json::JSON`. I was called on: {:?}",json); - } - }, - json => { - panic!("The function `get(`&self`,`search: &str`)` may only be called on a `Json::JSON`. I was called on: {:?}",json); - } - } - } - - /// Same as `get` above, but the references are mutable. Use `unbox_mut()` (see below) with this one. - /// ## Panics - /// This function will panic if called on a `Json` variant other than `Json::JSON` or `Json::OBJECT`, - /// as only these two variants may hold `Json::OBJECT` which has a `name` field. - pub fn get_mut(&mut self, search: &str) -> Option<&mut Json> { - match self { - Json::JSON(values) => { - for n in 0..values.len() { - match &values[n] { - Json::OBJECT { name, value: _ } => { - if name == search { - return Some(&mut values[n]); - } - } - _ => {} - } - } - } - Json::OBJECT { name: _, value } => match value.unbox_mut() { - Json::JSON(values) => { - for n in 0..values.len() { - match &values[n] { - Json::OBJECT { name, value: _ } => { - if name == search { - return Some(&mut values[n]); - } - } - _ => {} - } - } - } - json => { - panic!("The function `get_mut(`&self`,`search: &str`)` may only be called on a `Json::JSON` or a `Json::OBJECT` holding a `Json::JSON`. I was called on: {:?}",json); - } - }, - json => { - panic!("The function `get_mut(`&self`,`search: &str`)` may only be called on a `Json::JSON` or a `Json::OBJECT` holding a `Json::JSON`. I was called on: {:?}",json); - } - } - - None - } - - /// Enables matching the contents of a `Box`. - pub fn unbox(&self) -> &Json { - self - } - - /// Idem. - pub fn unbox_mut(&mut self) -> &mut Json { - self - } - - /// Returns a `String` of the form: `{"Json":"Value",...}` but can also be called on 'standalone objects' - /// which could result in `"Object":{"Stuff":...}` or `"Json":true`. - pub fn print(&self) -> String { - return self._print(&Default::default(), 0); - } - - pub fn print_with_option(&self, opt: &PrintOption) -> String { - let s = self._print(opt, 0); - if !opt.append_null { - return s; - } - - let mut result = s.clone(); - result.push('\0'); - return result; - } - - fn _print_indent(&self, result: &mut String, opt: &PrintOption, level: i32) { - if opt.indent == 0 || level == 0 { - return; - } - for _i in 0..level { - for _j in 0..opt.indent { - result.push(' '); - } - } - } - fn _print_sep_space(&self, result: &mut String, opt: &PrintOption, is_tail: bool) { - if opt.indent > 0 { - result.push('\n'); - return; - } - if opt.sep_space && !is_tail { - result.push(' '); - return; - } - } - - fn _print(&self, opt: &PrintOption, level: i32) -> String { - let mut result = String::new(); - - match self { - Json::OBJECT { name, value } => { - if opt.sep_space || opt.indent > 0 { - result.push_str(&format!("\"{}\": {}", name, value._print(opt, level))); - } else { - result.push_str(&format!("\"{}\":{}", name, value._print(opt, level))); - } - } - Json::JSON(values) => { - if values.len() == 0 { - return "{}".to_string(); - } - - result.push('{'); - if opt.indent > 0 { - result.push('\n'); - } - - if opt.sort_keys { - panic!("todo"); - } - - for n in 0..values.len() { - self._print_indent(&mut result, opt, level + 1); - result.push_str(&values[n]._print(opt, level + 1)); - if n < values.len() - 1 { - result.push(','); - self._print_sep_space(&mut result, opt, false); - } else { - self._print_sep_space(&mut result, opt, true); - } - } - - self._print_indent(&mut result, opt, level); - result.push('}'); - } - Json::ARRAY(values) => { - if values.len() == 0 { - return "[]".to_string(); - } - - result.push('['); - if opt.indent > 0 { - result.push('\n'); - } - - for n in 0..values.len() { - self._print_indent(&mut result, opt, level + 1); - result.push_str(&values[n]._print(opt, level + 1)); - if n < values.len() - 1 { - result.push(','); - self._print_sep_space(&mut result, opt, false); - } else { - self._print_sep_space(&mut result, opt, true); - } - } - - self._print_indent(&mut result, opt, level); - result.push(']'); - } - Json::STRING(val) => { - let s = Json::encode_string_escape(val); - result.push_str(&format!("\"{}\"", s)); - } - Json::NUMBER(val) => { - if opt.py_style_f64 { - result.push_str(&float_to_string(*val)); - } else { - result.push_str(&format!("{}", val)); - } - } - Json::INT(val) => { - result.push_str(&format!("{}", val)); - } - Json::FLOAT(val) => { - if ((*val as i64) as f64) == *val { - result.push_str(&format!("{}.0", val)); - } else { - result.push_str(&float_to_string(*val)); - } - } - Json::BOOL(val) => { - if *val { - result.push_str("true"); - } else { - result.push_str("false") - } - } - Json::NULL => { - result.push_str("null"); - } - } - - result - } - - fn encode_string_escape(s: &str) -> String { - let mut result = String::new(); - - for x in s.to_string().chars() { - if x == '\\' { - result.push_str("\\\\"); - continue; - } - if x == '\"' { - result.push_str("\\\""); - continue; - } - if x == 0x08 as char { - result.push_str("\\b"); - continue; - } - if x == 0x0c as char { - result.push_str("\\f"); - continue; - } - if x == '\n' { - result.push_str("\\n"); - continue; - } - if x == '\r' { - result.push_str("\\r"); - continue; - } - if x == '\t' { - result.push_str("\\t"); - continue; - } - if is_control(x as i32) { - // \uxxxx - let s = format!("\\u{:04x}", x as i32); - result.push_str(s.as_str()); - continue; - } - result.push(x); - } - return result; - } - - /// Parses the given bytes if a json structure is found. It even works with `\"Hello\":\"World\"` - /// (doesn't have to be like `{...}`), i.e. it can return any of the variants in the `Json` enum. - /// The error is returned in the form `(last position, what went wrong)`. Unfortunately the error - /// description are minimal (basically "Error parsing ...type..."). - /// ## Example - /// ``` - /// use json_minimal::*; - /// - /// match Json::parse(b"{\"Greeting\":\"Hello, world!\"}") { - /// Ok(json) => { - /// - /// match json.get("Greeting") { - /// Some(json) => { - /// match json { - /// Json::OBJECT { name, value } => { - /// match value.unbox() { - /// Json::STRING(val) => { - /// assert_eq!(val,"Hello, world!"); - /// }, - /// json => { - /// panic!("Expected Json::STRING but found {:?}!!!",json); - /// } - /// } - /// } - /// json => { - /// panic!("Expected Json::OBJECT but found {:?}!!!",json); - /// } - /// } - /// }, - /// None => { - /// panic!("Greeting was not found!!!"); - /// } - /// } - /// }, - /// Err( (pos,msg) ) => { - /// panic!("`{}` at position `{}`!!!",msg,pos); - /// } - /// } - /// ``` - /// See the tutorial on github for more. - pub fn parse(input: &[u8]) -> Result { - return Json::parse_with_option(input, &ParseOption { support_int: false }); - } - - pub fn parse_with_option( - input: &[u8], - opt: &ParseOption, - ) -> Result { - let mut incr: usize = 0; - - match input[incr] as char { - '{' => Self::parse_json(input, &mut incr, opt), - '\"' => Self::parse_string(input, &mut incr, opt), - '[' => Self::parse_array(input, &mut incr, opt), - 't' | 'f' => Self::parse_bool(input, &mut incr, opt), - 'n' => Self::parse_null(input, &mut incr, opt), - - // NaN, Infinity, -Infinity - '-' | '0'..='9' | 'N' | 'I' => Self::parse_number(input, &mut incr, opt), - _ => Err((incr, "Not a valid json format")), - } - } - - // This must exclusively be used by `parse_string` to make any sense. - fn parse_object( - input: &[u8], - incr: &mut usize, - name: String, - opt: &ParseOption, - ) -> Result { - // if input[*incr] as char != ':' { - // return Err((*incr, "Error parsing object.")); - // } - - *incr += 1; - - if *incr >= input.len() { - return Err((*incr, "Error parsing object.")); - } - - loop { - match input[*incr] as char { - '\r' | '\n' | '\t' | ' ' => { - *incr += 1; - - if *incr >= input.len() { - return Err((*incr, "Error parsing object.")); - } - } - _ => { - break; - } - } - } - - let value = match input[*incr] as char { - '{' => Self::parse_json(input, incr, opt)?, - '[' => Self::parse_array(input, incr, opt)?, - '\"' => Self::parse_string(input, incr, opt)?, - 't' | 'f' => Self::parse_bool(input, incr, opt)?, - 'n' => Self::parse_null(input, incr, opt)?, - - // NaN, Infinity, -Infinity - '-' | '0'..='9' | 'N' | 'I' => Self::parse_number(input, incr, opt)?, - _ => { - return Err((*incr, "Error parsing object.")); - } - }; - - Ok(Json::OBJECT { - name, - - value: Box::new(value), - }) - } - - // Parse if you thik it's something like `{...}` - fn parse_json( - input: &[u8], - incr: &mut usize, - opt: &ParseOption, - ) -> Result { - let mut result: Vec = Vec::new(); - - // if input[*incr] as char != '{' { - // return Err((*incr, "Error parsing json.")); - // } - - *incr += 1; - - if *incr >= input.len() { - return Err((*incr, "Error parsing json.")); - } - - loop { - let json = match input[*incr] as char { - ',' => { - *incr += 1; - continue; - } - '\"' => Self::parse_string(input, incr, opt)?, - '[' => Self::parse_array(input, incr, opt)?, - 't' | 'f' => Self::parse_bool(input, incr, opt)?, - 'n' => Self::parse_null(input, incr, opt)?, - - // NaN, Infinity, -Infinity - '-' | '0'..='9' | 'N' | 'I' => Self::parse_number(input, incr, opt)?, - '}' => { - *incr += 1; - - return Ok(Json::JSON(result)); - } - '{' => Self::parse_json(input, incr, opt)?, - // '\x0c' => '\f' - '\r' | '\n' | '\t' | '\x0c' | ' ' => { - *incr += 1; - - if *incr >= input.len() { - return Err((*incr, "Error parsing json.")); - } - - continue; - } - _ => { - return Err((*incr, "Error parsing json.")); - } - }; - - result.push(json); - } - } - - // Parse a &str if you're sure it resembles `[...` - fn parse_array( - input: &[u8], - incr: &mut usize, - opt: &ParseOption, - ) -> Result { - let mut result: Vec = Vec::new(); - - // if input[*incr] as char != '[' { - // return Err((*incr, "Error parsing array.")); - // } - - *incr += 1; - - if *incr >= input.len() { - return Err((*incr, "Error parsing array.")); - } - - loop { - let json = match input[*incr] as char { - ',' => { - *incr += 1; - continue; - } - '\"' => Self::parse_string(input, incr, opt)?, - '[' => Self::parse_array(input, incr, opt)?, - '{' => Self::parse_json(input, incr, opt)?, - 't' | 'f' => Self::parse_bool(input, incr, opt)?, - 'n' => Self::parse_null(input, incr, opt)?, - - // NaN, Infinity, -Infinity - '-' | '0'..='9' | 'N' | 'I' => Self::parse_number(input, incr, opt)?, - ']' => { - *incr += 1; - - return Ok(Json::ARRAY(result)); - } - // '\x0c' => '\f' - '\r' | '\n' | '\t' | '\x0c' | ' ' => { - *incr += 1; - - if *incr >= input.len() { - return Err((*incr, "Error parsing array.")); - } - - continue; - } - _ => { - return Err((*incr, "Error parsing array.")); - } - }; - - result.push(json); - } - } - - // Parse a &str if you know that it corresponds to/starts with a json String. - fn parse_string( - input: &[u8], - incr: &mut usize, - opt: &ParseOption, - ) -> Result { - let mut result: Vec = Vec::new(); - - // if input[*incr] as char != '\"' { - // return Err((*incr, "Error parsing string.")); - // } - - *incr += 1; - - if *incr >= input.len() { - return Err((*incr, "Error parsing string.")); - } - - loop { - match input[*incr] { - b'\"' => { - *incr += 1; - - let result = String::from_utf8(result) - .map_err(|_| (*incr, "Error parsing non-utf8 string."))?; - - if *incr < input.len() { - if input[*incr] as char == ':' { - return Self::parse_object(input, incr, result, opt); - } else { - return Ok(Json::STRING(result)); - } - } else { - return Ok(Json::STRING(result)); - } - } - b'\\' => { - Self::parse_string_escape_sequence(input, incr, &mut result, opt)?; - } - c => { - result.push(c); - - *incr += 1; - - if *incr >= input.len() { - return Err((*incr, "Error parsing string.")); - } - } - } - } - } - - // Parse an escape sequence inside a string - fn parse_string_escape_sequence( - input: &[u8], - incr: &mut usize, - result: &mut Vec, - _opt: &ParseOption, - ) -> Result<(), (usize, &'static str)> { - // if input[*incr] as char != '\\' { - // return Err((*incr, "Error parsing string escape sequence.")); - // } - - *incr += 1; - - if *incr >= input.len() { - return Err((*incr, "Error parsing string escape sequence.")); - } - match input[*incr] as char { - '\"' | '\\' | '/' => { - result.push(input[*incr]); - } - 'b' => { - result.push(b'\x08'); - } - // '\x0c' => '\f' - 'f' => { - result.push(b'\x0c'); - } - 'n' => { - result.push(b'\n'); - } - 'r' => { - result.push(b'\r'); - } - 't' => { - result.push(b'\t'); - } - 'u' => { - const BAD_UNICODE: &str = "Error parsing unicode string escape sequence."; - - if *incr + 4 >= input.len() { - return Err((*incr, BAD_UNICODE)); - } - - let hex = (&input[*incr + 1..*incr + 5]).to_vec(); - let hex = String::from_utf8(hex).map_err(|_| (*incr, BAD_UNICODE))?; - let mut value = u32::from_str_radix(&hex, 16).map_err(|_| (*incr, BAD_UNICODE))?; - - //high surrogate - if value >= 0xD800 && value <= 0xDBFF { - // /u xxxx /u xxx x - // 1234 56 789 10 - if *incr + 10 >= input.len() { - return Err((*incr, BAD_UNICODE)); - } - // /u xxxx /uxxxx - // 1234 56 - if &input[*incr + 5..*incr + 7] != "\\u".as_bytes() { - return Err((*incr, BAD_UNICODE)); - } - *incr += 6; - let low_hex = (&input[*incr + 1..*incr + 5]).to_vec(); - let low_hex = String::from_utf8(low_hex).map_err(|_| (*incr, BAD_UNICODE))?; - let low_value = - u32::from_str_radix(&low_hex, 16).map_err(|_| (*incr, BAD_UNICODE))?; - //low surrogate - if low_value >= 0xDC00 && low_value <= 0xDFFF { - value = ((value - 0xD800) << 10) + (low_value - 0xDC00) + 0x10000; - } else { - return Err((*incr, "Error parsing invalid string escape sequence.")); - } - } - let value = std::char::from_u32(value).ok_or((*incr, BAD_UNICODE))?; - - let mut buffer = [0; 4]; - result.extend(value.encode_utf8(&mut buffer).as_bytes()); - *incr += 4; - } - _ => { - return Err((*incr, "Error parsing invalid string escape sequence.")); - } - } - - *incr += 1; - - if *incr >= input.len() { - return Err((*incr, "Error parsing string escape sequence.")); - } - - Ok(()) - } - - fn parse_number( - input: &[u8], - incr: &mut usize, - opt: &ParseOption, - ) -> Result { - let mut result = String::new(); - - loop { - match input[*incr] as char { - // '\x0c' => '\f' - ',' | ']' | '}' | '\r' | '\n' | '\t' | '\x0c' | ' ' => { - break; - } - c => { - result.push(c); - - *incr += 1; - - if *incr >= input.len() { - match result.parse::() { - Ok(num) => { - if opt.support_int { - if result.contains(".") { - return Ok(Json::NUMBER(num)); - } else { - return Ok(Json::INT(num as i64)); - } - } else { - return Ok(Json::NUMBER(num)); - } - } - Err(_) => { - return Err((*incr, "Error parsing number.")); - } - } - } - } - } - } - - match result.parse::() { - Ok(num) => { - if opt.support_int { - if result.contains(".") { - return Ok(Json::NUMBER(num)); - } else if (num as i64) as f64 == num { - return Ok(Json::INT(num as i64)); - } else { - return Ok(Json::NUMBER(num)); - } - } else { - return Ok(Json::NUMBER(num)); - } - } - Err(_) => { - return Err((*incr, "Error parsing number.")); - } - } - } - - fn parse_bool( - input: &[u8], - incr: &mut usize, - _opt: &ParseOption, - ) -> Result { - let mut result = String::new(); - - loop { - match input[*incr] as char { - // '\x0c' => '\f' - ',' | ']' | '}' | '\r' | '\n' | '\t' | '\x0c' | ' ' => { - break; - } - c => { - result.push(c); - - *incr += 1; - - if *incr >= input.len() { - if result == "true" { - return Ok(Json::BOOL(true)); - } - - if result == "false" { - return Ok(Json::BOOL(false)); - } - - return Err((*incr, "Error parsing bool.")); - } - } - } - } - - if result == "true" { - return Ok(Json::BOOL(true)); - } - - if result == "false" { - return Ok(Json::BOOL(false)); - } - - return Err((*incr, "Error parsing bool.")); - } - - fn parse_null( - input: &[u8], - incr: &mut usize, - _opt: &ParseOption, - ) -> Result { - let mut result = String::new(); - - loop { - match input[*incr] as char { - // '\x0c' => '\f' - ',' | ']' | '}' | '\r' | '\n' | '\t' | '\x0c' | ' ' => { - break; - } - c => { - result.push(c); - - *incr += 1; - - if *incr >= input.len() { - if result == "null" { - return Ok(Json::NULL); - } else { - return Err((*incr, "Error parsing null.")); - } - } - } - } - } - - if result == "null" { - return Ok(Json::NULL); - } else { - return Err((*incr, "Error parsing null.")); - } - } -} - -pub fn float_to_string(value: f64) -> String { - if value.is_nan() { - return "NaN".to_string(); - } - if value.is_infinite() { - if value.is_sign_negative() { - return "-Infinity".to_string(); - } else { - return "Infinity".to_string(); - } - } - - let lit = format!("{:e}", value); - if let Some(position) = lit.find('e') { - let significand = &lit[..position]; - let exponent = &lit[position + 1..]; - let exponent = exponent.parse::().unwrap(); - if exponent < 16 && exponent > -5 { - if is_integer(value) { - format!("{:.1?}", value) - } else { - value.to_string() - } - } else { - format!("{}e{:+#03}", significand, exponent) - } - } else { - value.to_string() - } -} - -pub fn is_integer(v: f64) -> bool { - (v - v.round()).abs() < std::f64::EPSILON -} - -fn is_control(b: i32) -> bool { - const DEL: i32 = 127; - b < 32 || b == DEL -} - -#[cfg(test)] -mod tests; diff --git a/kclvm/runtime/src/3rdparty/json_minimal/src/tests.rs b/kclvm/runtime/src/3rdparty/json_minimal/src/tests.rs deleted file mode 100644 index 311f1513a..000000000 --- a/kclvm/runtime/src/3rdparty/json_minimal/src/tests.rs +++ /dev/null @@ -1,651 +0,0 @@ -use super::*; - -#[test] -fn test_make_json() { - let mut json = Json::new(); - - let greeting = Json::OBJECT { - name: String::from("Greeting"), - - value: Box::new(Json::STRING(String::from("Hello, world!"))), - }; - - json.add(greeting); - - let mut days_in_the_week = Json::OBJECT { - name: String::from("Days in the week"), - - value: Box::new(Json::JSON(Vec::new())), - }; - - let mut days = Json::ARRAY(Vec::new()); - - days.add(Json::STRING(String::from("Monday"))) - .add(Json::STRING(String::from("Tuesday"))) - .add(Json::STRING(String::from("Wednesday"))) - .add(Json::STRING(String::from("Thursday"))) - .add(Json::STRING(String::from("Friday"))) - .add(Json::STRING(String::from("Saturday"))) - .add(Json::STRING(String::from("Sunday"))); - - days_in_the_week - .add(Json::OBJECT { - name: String::from("Total number of days"), - - value: Box::new(Json::NUMBER(7.0)), - }) - .add(Json::OBJECT { - name: String::from("They are called"), - - value: Box::new(days), - }); - - json.add(days_in_the_week); - - let mut conclusion = Json::OBJECT { - name: String::from("Conclusion"), - - value: Box::new(Json::JSON(Vec::new())), - }; - - conclusion - .add(Json::OBJECT { - name: String::from("Minimal in my opinion"), - - value: Box::new(Json::BOOL(true)), - }) - .add(Json::OBJECT { - name: String::from("How much I care about your opinion"), - - value: Box::new(Json::NULL), - }) - .add(Json::OBJECT { - name: String::from("Comment"), - - value: Box::new(Json::STRING(String::from(";)"))), - }); - - json.add(conclusion); - - assert_eq!( - "{\"Greeting\":\"Hello, world!\",\"Days in the week\":{\"Total number of days\":7,\"They are called\":[\"Monday\",\"Tuesday\",\"Wednesday\",\"Thursday\",\"Friday\",\"Saturday\",\"Sunday\"]},\"Conclusion\":{\"Minimal in my opinion\":true,\"How much I care about your opinion\":null,\"Comment\":\";)\"}}", - &json.print() - ) -} - -#[test] -fn test_get_mut() { - let mut json = Json::new(); - - json.add(Json::OBJECT { - name: String::from("Greeting"), - - value: Box::new(Json::STRING(String::from("Hello, world!"))), - }); - - match json.get_mut("Greeting") { - Some(json) => match json { - Json::OBJECT { name: _, value } => match value.unbox_mut() { - Json::STRING(val) => { - assert_eq!("Hello, world!", val); - - val.push_str(" How are you?"); - - assert_eq!("Hello, world! How are you?", val); - } - _ => { - panic!("Expected `Json::STRING`!!!"); - } - }, - _ => { - panic!("Expected `Json::OBJECT`!!!"); - } - }, - None => { - panic!("Not found!!!"); - } - } -} - -#[test] -fn test_parse_number() { - let mut incr: usize = 0; - - match Json::parse_number(b"36.36", &mut incr, &ParseOption::default()) { - Ok(json) => match json { - Json::NUMBER(val) => { - assert_eq!(val, 36.36); - } - json => { - panic!("Expected Json::NUMBER but found {:?}", json); - } - }, - Err(e) => { - parse_error(e); - } - } -} - -#[test] -fn test_parse_bool() { - let mut incr: usize = 0; - - match Json::parse_bool(b"true", &mut incr, &ParseOption::default()) { - Ok(json) => match json { - Json::BOOL(val) => { - assert_eq!(val, true); - } - json => { - panic!("Expected Json::BOOL but found {:?}", json); - } - }, - Err(e) => { - parse_error(e); - } - } - - incr = 0; - - match Json::parse_bool(b"false", &mut incr, &ParseOption::default()) { - Ok(json) => match json { - Json::BOOL(val) => { - assert_eq!(val, false); - } - json => { - panic!("Expected Json::BOOL but found {:?}", json); - } - }, - Err(e) => { - parse_error(e); - } - } -} - -#[test] -fn test_parse_null() { - let mut incr: usize = 0; - - match Json::parse_null(b"null", &mut incr, &ParseOption::default()) { - Ok(json) => match json { - Json::NULL => {} - json => { - panic!("Expected Json::NULL but found {:?}", json); - } - }, - Err(e) => { - parse_error(e); - } - } -} - -#[test] -fn test_parse_array() { - let mut incr: usize = 0; - - match Json::parse_array( - b"[1,\"two\",true,[\"array\",[\"another one\",[\"another one\",1.5]]]]", - &mut incr, - &ParseOption::default(), - ) { - Ok(json) => match json { - Json::ARRAY(vals) => { - assert_eq!(vals.len(), 4); - } - json => { - panic!("Expected Json::ARRAY but found {:?}", json); - } - }, - Err(e) => { - parse_error(e); - } - } -} - -#[test] -fn test_parse_json() { - let mut incr: usize = 0; - - match Json::parse_json(b"{\"on\",\"off\"}", &mut incr, &ParseOption::default()) { - Ok(json) => match json { - Json::JSON(vals) => { - assert_eq!(vals.len(), 2); - } - json => { - panic!("Expected Json::ARRAY but found {:?}", json); - } - }, - Err(e) => { - parse_error(e); - } - } -} - -#[test] -fn test_parse_json_2() { - let mut incr: usize = 0; - - match Json::parse_json( - b"{\"on\",\"off\",\"OBJECT\":{\"ARRAY\":[\"on\",\"off\"]},\"on or off?\"}", - &mut incr, - &ParseOption::default(), - ) { - Ok(json) => match json { - Json::JSON(vals) => { - assert_eq!(vals.len(), 4); - } - json => { - panic!("Expected Json::ARRAY but found {:?}", json); - } - }, - Err(e) => { - parse_error(e); - } - } -} - -#[test] -fn test_parse_object() { - let mut incr: usize = 0; - - match Json::parse_string(b"\"String\":\"Value\"", &mut incr, &ParseOption::default()) { - Ok(json) => match json { - Json::OBJECT { name, value } => { - assert_eq!(name, "String"); - - match value.unbox() { - Json::STRING(val) => { - assert_eq!(val, "Value"); - } - json => { - panic!("Expected Json::STRING but found {:?}", json); - } - } - } - json => { - panic!("Expected Json::OBJECT but found {:?}", json); - } - }, - Err(e) => { - parse_error(e); - } - } -} - -#[test] -fn test_parse() { - match Json::parse(b"{\"Greeting\":\"Hello, world!\",\"Days in the week\":{\"Total number of days\":7,\"They are called\":[\"Monday\",\"Tuesday\",\"Wednesday\",\"Thursday\",\"Friday\",\"Saturday\",\"Sunday\"]},\"Minimal in my opinion\":true,\"How much I care about your opinion\":null}") { - Ok(json) => { - match json { - Json::JSON(values) => { - assert_eq!(values.len(),4); - - match &values[0] { - Json::OBJECT { name, value } => { - assert_eq!("Greeting",name); - - match value.unbox() { - Json::STRING(val) => { - assert_eq!("Hello, world!",val); - }, - json => { - panic!("Expected Json::STRING but found {:?}",json); - } - } - }, - json => { - panic!("Expected Json::OBJECT but found {:?}",json); - } - } - - match &values[1] { - Json::OBJECT { name, value } => { - assert_eq!("Days in the week",name); - - match value.unbox() { - Json::JSON(values) => { - assert_eq!(values.len(),2); - - match &values[0] { - Json::OBJECT { name, value } => { - assert_eq!("Total number of days",name); - - match value.unbox() { - Json::NUMBER(num) => { - assert_eq!(*num,7.0); - }, - json => { - panic!("Expected Json::NUMBER but found {:?}",json); - } - } - }, - json => { - panic!("Expected Json::OBJECT but found {:?}",json); - } - } - - match &values[1] { - Json::OBJECT { name, value } => { - assert_eq!("They are called",name); - - match value.unbox() { - Json::ARRAY(vals) => { - assert_eq!(vals.len(),7); - - for n in 0..7 { - match &vals[n] { - Json::STRING(val) => { - match val.as_bytes() { - b"Monday" => { - - }, - b"Tuesday" => { - - }, - b"Wednesday" => { - - }, - b"Thursday" => { - - }, - b"Friday" => { - - }, - b"Saturday" => { - - }, - b"Sunday" => { - - }, - d => { - panic!("\"{:?}\" is not a day of the week!!",d); - } - } - }, - json => { - panic!("Expected Json::STRING but found {:?}",json); - } - } - } - }, - json => { - panic!("Expected Json::ARRAY but found {:?}",json); - } - } - }, - json => { - panic!("Expected Json::OBJECT but found {:?}",json); - } - } - }, - json => { - panic!("Expected Json::JSON but found {:?}",json); - } - } - }, - json => { - panic!("Expected Json::OBJECT but found {:?}",json); - } - } - }, - json => { - panic!("Expected Json::JSON but found {:?}",json); - } - } - }, - Err(e) => { - parse_error(e); - } - } -} - -#[test] -fn test_parse_2() { - #[allow(unused_assignments)] - - let json = match Json::parse(b"{\"Greeting\":\"Hello, world!\",\"Days of the week\":{\"Total number of days\":7,\"They are called\":[\"Monday\",\"Tuesday\",\"Wednesday\",\"Thursday\",\"Friday\",\"Saturday\",\"Sunday\"]},\"Conclusion\":{\"Minimal in my opinion\":true,\"How much I care about your opinion\":null,\"Comment\":\";)\"}}") { - Ok(json) => { - json - }, - Err( (position,message) ) => { - panic!("`{}` at position `{}`!!!",message,position); - } - }; - - match json.get("Greeting") { - Some(json) => match json { - Json::OBJECT { name: _, value } => match value.unbox() { - Json::STRING(val) => { - assert_eq!("Hello, world!", val); - } - json => { - panic!("Expected Json::STRING but found {:?}", json); - } - }, - json => panic!("Expected Json::JSON but found {:?}!!!", json), - }, - None => { - panic!("Couln't find Greeting. How rude!"); - } - } - - match json.get("Days of the week") { - // Hint: You can also use `get_mut` to aid in editing/creating jsons... - Some(json) => match json { - Json::OBJECT { name: _, value } => match value.unbox() { - Json::JSON(values) => { - assert_eq!(values.len(), 2); - - match &values[0] { - Json::OBJECT { name, value: _ } => { - assert_eq!("Total number of days", name); - } - json => { - panic!("Expected Json::OBJECT but found {:?}!!!", json); - } - } - - match &values[1] { - Json::OBJECT { name, value: _ } => { - assert_eq!("They are called", name); - } - json => { - panic!("Expected Json::OBJECT but found {:?}!!!", json); - } - } - } - json => { - panic!("Expected Json::JSON but found {:?}!!!", json); - } - }, - json => { - panic!("Expected Json::OBJECT but found {:?}!!!", json); - } - }, - None => { - panic!("Days of the week not found!"); - } - } -} - -#[test] -fn parse_strange() { - let json = match Json::parse(b"[0,{\"hello\":\"world\",\"what's\":\"up?\"}]") { - Ok(json) => json, - Err((pos, msg)) => { - panic!("`{}` at position {}", msg, pos); - } - }; - - match json { - Json::ARRAY(vals) => { - assert_eq!(vals.len(), 2); - - match &vals[0] { - Json::NUMBER(n) => { - assert_eq!(*n, 0.0); - } - json => { - panic!("Expected Json::NUMBER but found {:?}!!!", json); - } - } - - match &vals[1] { - Json::JSON(vals) => { - assert_eq!(2, vals.len()); - - match &vals[0] { - Json::OBJECT { name, value: _ } => { - assert_eq!("hello", name); - } - json => { - panic!("Expected Json::ARRAY but found {:?}!!!", json); - } - } - - match &vals[1] { - Json::OBJECT { name, value: _ } => { - assert_eq!("what's", name); - } - json => { - panic!("Expected Json::ARRAY but found {:?}!!!", json); - } - } - } - json => { - panic!("Expected Json::JSON but found {:?}!!!", json); - } - } - } - json => { - panic!("Expected Json::ARRAY but found {:?}!!!", json); - } - } -} - -#[test] -fn parse_escape_sequence() { - let json = match Json::parse(br#""a \" \/ \b \f \n \r \t \u2764 z""#) { - Ok(json) => json, - Err((pos, msg)) => { - panic!("`{}` at position {}", msg, pos); - } - }; - - match json { - Json::STRING(string) => { - assert_eq!(string, "a \" / \u{8} \u{c} \n \r \t ❤ z"); - } - json => { - panic!("Expected Json::STRING but found {:?}!!!", json); - } - } -} - -#[test] -fn parse_escape_sequence_in_array() { - let json = match Json::parse(br#"["\"foo"]"#) { - Ok(json) => json, - Err((pos, msg)) => { - panic!("`{}` at position {}", msg, pos); - } - }; - - match json { - Json::ARRAY(vals) => { - assert_eq!(vals.len(), 1); - - match &vals[0] { - Json::STRING(n) => { - assert_eq!(*n, "\"foo"); - } - json => { - panic!("Expected Json::STRING but found {:?}!!!", json); - } - } - } - json => { - panic!("Expected Json::ARRAY but found {:?}!!!", json); - } - } -} - -#[test] -fn parse_non_ascii() { - let json = match Json::parse(r#""a ❤ z""#.as_bytes()) { - Ok(json) => json, - Err((pos, msg)) => { - panic!("`{}` at position {}", msg, pos); - } - }; - - match json { - Json::STRING(string) => { - assert_eq!(string, "a ❤ z"); - } - json => { - panic!("Expected Json::STRING but found {:?}!!!", json); - } - } -} - -#[test] -fn parse_pretty() { - let json = match Json::parse(b"{\r\n\t\"Array\": [\r\n\t\t\"First\" ,\r\n\r\n\t\t2 ,\r\n\r\n\t\t[\"Three\"] ,\r\n\r\n\t\t3.6\r\n\t],\r\n\t{\r\n\r\n\t\t\"Sub-Object\": \"Hello, world!\"\r\n\t}\r\n}") { - Ok(json) => json, - Err((pos, msg)) => { - panic!("`{}` at position {}", msg, pos); - } - }; - - match json { - Json::JSON(values) => { - match values[0].unbox() { - Json::OBJECT { name, value } => { - assert_eq!(name, "Array"); - - match value.unbox() { - Json::ARRAY(values) => { - assert_eq!(values.len(), 4); - } - json => { - panic!("Expected Json::ARRAY but found {:?}!!!", json); - } - } - } - json => { - panic!("Expected Json::OBJECT but found {:?}!!!", json); - } - } - - match values[1].unbox() { - Json::JSON(values) => match values[0].unbox() { - Json::OBJECT { name, value } => { - assert_eq!(name, "Sub-Object"); - - match value.unbox() { - Json::STRING(value) => { - assert_eq!(value, "Hello, world!"); - } - json => { - panic!("Expected Json::STRING but found {:?}!!!", json); - } - } - } - json => { - panic!("Expected Json::OBJECT but found {:?}!!!", json); - } - }, - json => { - panic!("Expected Json::Json but found {:?}!!!", json); - } - } - } - json => { - panic!("Expected Json::JSON but found {:?}!!!", json); - } - } -} - -fn parse_error((pos, msg): (usize, &str)) { - panic!("`{}` at position `{}`!!!", msg, pos); -} diff --git a/kclvm/runtime/src/_kcl_run.rs b/kclvm/runtime/src/_kcl_run.rs index d6a1c656f..a9ab2cbb0 100644 --- a/kclvm/runtime/src/_kcl_run.rs +++ b/kclvm/runtime/src/_kcl_run.rs @@ -1,177 +1,186 @@ -// Copyright 2021 The KCL Authors. All rights reserved. +//! Copyright The KCL Authors. All rights reserved. +#![allow(clippy::missing_safety_doc)] + +use std::os::raw::c_char; use crate::*; +use self::eval::LazyEvalScope; + #[allow(dead_code, non_camel_case_types)] -pub type kclvm_buffer_t = Buffer; +type kclvm_context_t = Context; #[allow(dead_code, non_camel_case_types)] -pub type kclvm_context_t = Context; +type kclvm_eval_scope_t = LazyEvalScope; #[allow(dead_code, non_camel_case_types)] -pub type kclvm_kind_t = Kind; +type kclvm_kind_t = Kind; #[allow(dead_code, non_camel_case_types)] -pub type kclvm_type_t = Type; +type kclvm_type_t = Type; #[allow(dead_code, non_camel_case_types)] -pub type kclvm_value_ref_t = ValueRef; +type kclvm_value_ref_t = ValueRef; #[allow(dead_code, non_camel_case_types)] -pub type kclvm_iterator_t = ValueIterator; +type kclvm_iterator_t = ValueIterator; #[allow(dead_code, non_camel_case_types)] -pub type kclvm_char_t = i8; +type kclvm_char_t = c_char; #[allow(dead_code, non_camel_case_types)] -pub type kclvm_size_t = i32; +type kclvm_size_t = i32; #[allow(dead_code, non_camel_case_types)] type kclvm_bool_t = i8; #[allow(dead_code, non_camel_case_types)] -pub type kclvm_int_t = i64; +type kclvm_int_t = i64; #[allow(dead_code, non_camel_case_types)] -pub type kclvm_float_t = f64; +type kclvm_float_t = f64; + +#[derive(Debug, Default)] +pub struct RuntimePanicRecord { + pub kcl_panic_info: bool, + pub message: String, + pub rust_file: String, + pub rust_line: i32, + pub rust_col: i32, +} -// const SHOULD_PROFILE: bool = false; +#[derive(Debug, Default, Clone, Copy)] +#[repr(C)] +pub struct FFIRunOptions { + pub strict_range_check: i32, + pub disable_none: i32, + pub disable_schema_check: i32, + pub debug_mode: i32, + pub show_hidden: i32, + pub sort_keys: i32, + pub include_schema_type_path: i32, + pub disable_empty_list: i32, +} + +thread_local! { + static KCL_RUNTIME_PANIC_RECORD: std::cell::RefCell = std::cell::RefCell::new(RuntimePanicRecord::default()) +} + +fn new_ctx_with_opts(opts: FFIRunOptions, path_selector: &[String]) -> Context { + let mut ctx = Context::new(); + // Config + ctx.cfg.strict_range_check = opts.strict_range_check != 0; + ctx.cfg.disable_schema_check = opts.disable_schema_check != 0; + ctx.cfg.debug_mode = opts.debug_mode != 0; + // Plan options + ctx.plan_opts.disable_none = opts.disable_none != 0; + ctx.plan_opts.show_hidden = opts.show_hidden != 0; + ctx.plan_opts.sort_keys = opts.sort_keys != 0; + ctx.plan_opts.include_schema_type_path = opts.include_schema_type_path != 0; + ctx.plan_opts.disable_empty_list = opts.disable_empty_list != 0; + ctx.plan_opts.query_paths = path_selector.to_vec(); + ctx +} #[no_mangle] #[runtime_fn] -pub extern "C" fn _kcl_run( +#[allow(clippy::too_many_arguments)] +pub unsafe extern "C" fn _kcl_run( kclvm_main_ptr: u64, // main.k => kclvm_main option_len: kclvm_size_t, option_keys: *const *const kclvm_char_t, option_values: *const *const kclvm_char_t, - strict_range_check: i32, - disable_none: i32, - disable_schema_check: i32, - list_option_mode: i32, - debug_mode: i32, - result_buffer_len: kclvm_size_t, - result_buffer: *mut kclvm_char_t, - warn_buffer_len: kclvm_size_t, - warn_buffer: *mut kclvm_char_t, + opts: FFIRunOptions, + path_selector: *const *const kclvm_char_t, + json_result_buffer_len: *mut kclvm_size_t, + json_result_buffer: *mut kclvm_char_t, + yaml_result_buffer_len: *mut kclvm_size_t, + yaml_result_buffer: *mut kclvm_char_t, + err_buffer_len: *mut kclvm_size_t, + err_buffer: *mut kclvm_char_t, + log_buffer_len: *mut kclvm_size_t, + log_buffer: *mut kclvm_char_t, ) -> kclvm_size_t { - let ctx = kclvm_context_new(); - + // Init runtime context with options + let ctx = Box::new(new_ctx_with_opts(opts, &c2str_vec(path_selector))).into_raw(); + let scope = kclvm_scope_new(); + let option_keys = std::slice::from_raw_parts(option_keys, option_len as usize); + let option_values = std::slice::from_raw_parts(option_values, option_len as usize); + for i in 0..(option_len as usize) { + kclvm_builtin_option_init(ctx, option_keys[i], option_values[i]); + } let prev_hook = std::panic::take_hook(); std::panic::set_hook(Box::new(|info: &std::panic::PanicInfo| { - let ctx = Context::current_context_mut(); - ctx.set_panic_info(info); - let _ = ctx; + KCL_RUNTIME_PANIC_RECORD.with(|record| { + let mut record = record.borrow_mut(); + record.kcl_panic_info = true; + + record.message = if let Some(s) = info.payload().downcast_ref::<&str>() { + s.to_string() + } else if let Some(s) = info.payload().downcast_ref::<&String>() { + (*s).clone() + } else if let Some(s) = info.payload().downcast_ref::() { + (*s).clone() + } else { + "".to_string() + }; + if let Some(location) = info.location() { + record.rust_file = location.file().to_string(); + record.rust_line = location.line() as i32; + record.rust_col = location.column() as i32; + } + }) })); - - let result = std::panic::catch_unwind(|| { - _kcl_run_in_closure( - kclvm_main_ptr, - option_len, - option_keys, - option_values, - strict_range_check, - disable_none, - disable_schema_check, - list_option_mode, - debug_mode, - result_buffer_len, - result_buffer, - ) - }); + let result = std::panic::catch_unwind(|| _kcl_run_in_closure(ctx, scope, kclvm_main_ptr)); std::panic::set_hook(prev_hook); - match result { - Ok(n) => { - let json_panic_info = Context::current_context().get_panic_info_json_string(); - - let c_str_ptr = json_panic_info.as_ptr() as *const i8; - let c_str_len = json_panic_info.len() as i32; - - unsafe { - if c_str_len <= warn_buffer_len { - std::ptr::copy(c_str_ptr, warn_buffer, c_str_len as usize); - } - } - - kclvm_context_delete(ctx); - n - } - Err(_) => { - let json_panic_info = Context::current_context().get_panic_info_json_string(); - - let c_str_ptr = json_panic_info.as_ptr() as *const i8; - let c_str_len = json_panic_info.len() as i32; - - let mut return_len = c_str_len; - - unsafe { - if return_len <= result_buffer_len { - std::ptr::copy(c_str_ptr, result_buffer, return_len as usize); - } else { - *result_buffer = '\0' as kclvm_char_t; - return_len = 0 - return_len; - } - } - - kclvm_context_delete(ctx); - return_len - } - } + KCL_RUNTIME_PANIC_RECORD.with(|record| { + let record = record.borrow(); + let ctx = mut_ptr_as_ref(ctx); + ctx.set_panic_info(&record); + }); + // Get the runtime context. + let ctx_ref = ptr_as_ref(ctx); + // Copy planned result and log message + copy_str_to( + &ctx_ref.json_result, + json_result_buffer, + json_result_buffer_len, + ); + copy_str_to( + &ctx_ref.yaml_result, + yaml_result_buffer, + yaml_result_buffer_len, + ); + copy_str_to(&ctx_ref.log_message, log_buffer, log_buffer_len); + // Copy JSON panic info message pointer + let json_panic_info = if result.is_err() { + ctx_ref.get_panic_info_json_string().unwrap_or_default() + } else { + "".to_string() + }; + copy_str_to(&json_panic_info, err_buffer, err_buffer_len); + // Delete the context + kclvm_context_delete(ctx); + // Delete the scope + kclvm_scope_delete(scope); + result.is_err() as kclvm_size_t } -#[allow(clippy::too_many_arguments)] -fn _kcl_run_in_closure( +unsafe fn _kcl_run_in_closure( + ctx: *mut Context, + scope: *mut LazyEvalScope, kclvm_main_ptr: u64, // main.k => kclvm_main - option_len: kclvm_size_t, - option_keys: *const *const kclvm_char_t, - option_values: *const *const kclvm_char_t, - strict_range_check: i32, - disable_none: i32, - disable_schema_check: i32, - list_option_mode: i32, - debug_mode: i32, - result_buffer_len: kclvm_size_t, - result_buffer: *mut kclvm_char_t, -) -> kclvm_size_t { - let ctx = kclvm_context_current(); - +) { let kclvm_main = (&kclvm_main_ptr as *const u64) as *const () - as *const extern "C" fn(ctx: *mut kclvm_context_t) -> *mut kclvm_value_ref_t; - - kclvm_context_set_strict_range_check(ctx, strict_range_check as kclvm_bool_t); - kclvm_context_set_disable_none(ctx, disable_none as kclvm_bool_t); - kclvm_context_set_disable_schema_check(ctx, disable_schema_check as kclvm_bool_t); - kclvm_context_set_list_option_mode(ctx, list_option_mode as kclvm_bool_t); - kclvm_context_set_debug_mode(ctx, debug_mode as kclvm_bool_t); + as *const extern "C" fn( + ctx: *mut kclvm_context_t, + scope: *mut kclvm_eval_scope_t, + ) -> *mut kclvm_value_ref_t; unsafe { - let option_keys = std::slice::from_raw_parts(option_keys, option_len as usize); - let option_values = std::slice::from_raw_parts(option_values, option_len as usize); - - for i in 0..(option_len as usize) { - kclvm_builtin_option_init(ctx, option_keys[i], option_values[i]); - } - - let value = if kclvm_main.is_null() { - kclvm_value_Str(b"{}\0" as *const u8 as *const kclvm_char_t) - } else { - kclvm_context_main_begin_hook(ctx); - let x = (*kclvm_main)(ctx); - kclvm_context_main_end_hook(ctx, x) - }; - - let c_str_ptr = kclvm_value_Str_ptr(value); - let c_str_len = kclvm_value_len(value); - - let mut return_len = c_str_len; - - if return_len <= result_buffer_len { - std::ptr::copy(c_str_ptr, result_buffer, return_len as usize); - } else { - *result_buffer = '\0' as kclvm_char_t; - return_len = 0 - return_len; + if kclvm_main.is_null() { + panic!("kcl program main function not found"); } - - kclvm_value_delete(value); - return_len + (*kclvm_main)(ctx, scope); } } diff --git a/kclvm/runtime/src/_kclvm.bc b/kclvm/runtime/src/_kclvm.bc index 79fb3cbd2..b604c8633 100644 Binary files a/kclvm/runtime/src/_kclvm.bc and b/kclvm/runtime/src/_kclvm.bc differ diff --git a/kclvm/runtime/src/_kclvm.h b/kclvm/runtime/src/_kclvm.h index 17611eef6..ed60c6297 100644 --- a/kclvm/runtime/src/_kclvm.h +++ b/kclvm/runtime/src/_kclvm.h @@ -1,4 +1,4 @@ -// Copyright 2021 The KCL Authors. All rights reserved. +// Copyright The KCL Authors. All rights reserved. // Auto generated, DONOT EDIT!!! @@ -19,38 +19,23 @@ extern "C" { enum kclvm_kind_t { Invalid = 0, - - // only for value - - Undefined = 1, + Undefined = 1, None = 2, - - // for value & type - Bool = 3, Int = 4, Float = 5, Str = 6, List = 7, Dict = 8, - Schema = 9, Error = 10, - - // only for type - Any = 11, Union = 12, - BoolLit = 13, IntLit = 14, FloatLit = 15, StrLit = 16, - Func = 17, - - // max num - Max = 18, }; @@ -64,6 +49,8 @@ typedef struct kclvm_context_t kclvm_context_t; typedef struct kclvm_decorator_value_t kclvm_decorator_value_t; +typedef struct kclvm_eval_scope_t kclvm_eval_scope_t; + typedef double kclvm_float_t; typedef int64_t kclvm_int_t; @@ -80,19 +67,11 @@ typedef struct kclvm_value_ref_t kclvm_value_ref_t; typedef struct kclvm_value_t kclvm_value_t; -void kclvm_assert(kclvm_value_ref_t* value, kclvm_value_ref_t* msg); +void kclvm_assert(kclvm_context_t* ctx, kclvm_value_ref_t* value, kclvm_value_ref_t* msg); -kclvm_value_ref_t* kclvm_base64_decode(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); +kclvm_value_ref_t* kclvm_base64_decode(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); -kclvm_value_ref_t* kclvm_base64_encode(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); - -kclvm_char_t* kclvm_buffer_data(kclvm_buffer_t* p); - -void kclvm_buffer_delete(kclvm_buffer_t* p); - -kclvm_buffer_t* kclvm_buffer_new(kclvm_size_t size); - -kclvm_size_t kclvm_buffer_size(kclvm_buffer_t* p); +kclvm_value_ref_t* kclvm_base64_encode(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); kclvm_value_ref_t* kclvm_builtin_abs(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); @@ -102,7 +81,7 @@ kclvm_value_ref_t* kclvm_builtin_any_true(kclvm_context_t* ctx, kclvm_value_ref_ kclvm_value_ref_t* kclvm_builtin_bin(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); -kclvm_value_ref_t* kclvm_builtin_bool(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); +kclvm_value_ref_t* kclvm_builtin_bool(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); kclvm_value_ref_t* kclvm_builtin_dict(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); @@ -112,15 +91,17 @@ kclvm_value_ref_t* kclvm_builtin_hex(kclvm_context_t* ctx, kclvm_value_ref_t* ar kclvm_value_ref_t* kclvm_builtin_int(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); +kclvm_value_ref_t* kclvm_builtin_isnullish(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); + kclvm_value_ref_t* kclvm_builtin_isunique(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); -kclvm_value_ref_t* kclvm_builtin_len(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); +kclvm_value_ref_t* kclvm_builtin_len(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); kclvm_value_ref_t* kclvm_builtin_list(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); -kclvm_value_ref_t* kclvm_builtin_max(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); +kclvm_value_ref_t* kclvm_builtin_max(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); -kclvm_value_ref_t* kclvm_builtin_min(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); +kclvm_value_ref_t* kclvm_builtin_min(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); kclvm_value_ref_t* kclvm_builtin_multiplyof(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); @@ -128,7 +109,7 @@ kclvm_value_ref_t* kclvm_builtin_oct(kclvm_context_t* ctx, kclvm_value_ref_t* ar kclvm_value_ref_t* kclvm_builtin_option(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); -void kclvm_builtin_option_init(kclvm_context_t* ctx, int8_t* key, int8_t* value); +void kclvm_builtin_option_init(kclvm_context_t* ctx, char* key, char* value); kclvm_value_ref_t* kclvm_builtin_option_reset(kclvm_context_t* ctx, kclvm_value_ref_t* _args, kclvm_value_ref_t* _kwargs); @@ -144,93 +125,83 @@ kclvm_value_ref_t* kclvm_builtin_round(kclvm_context_t* ctx, kclvm_value_ref_t* kclvm_value_ref_t* kclvm_builtin_sorted(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); -kclvm_value_ref_t* kclvm_builtin_str(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); - -kclvm_value_ref_t* kclvm_builtin_str_capitalize(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); +kclvm_value_ref_t* kclvm_builtin_str(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); -kclvm_value_ref_t* kclvm_builtin_str_count(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); +kclvm_value_ref_t* kclvm_builtin_str_capitalize(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); -kclvm_value_ref_t* kclvm_builtin_str_endswith(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); +kclvm_value_ref_t* kclvm_builtin_str_chars(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); -kclvm_value_ref_t* kclvm_builtin_str_find(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); +kclvm_value_ref_t* kclvm_builtin_str_count(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); -kclvm_value_ref_t* kclvm_builtin_str_format(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); +kclvm_value_ref_t* kclvm_builtin_str_endswith(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); -kclvm_value_ref_t* kclvm_builtin_str_index(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); +kclvm_value_ref_t* kclvm_builtin_str_find(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); -kclvm_value_ref_t* kclvm_builtin_str_isalnum(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); +kclvm_value_ref_t* kclvm_builtin_str_format(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); -kclvm_value_ref_t* kclvm_builtin_str_isalpha(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); +kclvm_value_ref_t* kclvm_builtin_str_index(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); -kclvm_value_ref_t* kclvm_builtin_str_isdigit(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); +kclvm_value_ref_t* kclvm_builtin_str_isalnum(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); -kclvm_value_ref_t* kclvm_builtin_str_islower(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); +kclvm_value_ref_t* kclvm_builtin_str_isalpha(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); -kclvm_value_ref_t* kclvm_builtin_str_isspace(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); +kclvm_value_ref_t* kclvm_builtin_str_isdigit(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); -kclvm_value_ref_t* kclvm_builtin_str_istitle(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); +kclvm_value_ref_t* kclvm_builtin_str_islower(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); -kclvm_value_ref_t* kclvm_builtin_str_isupper(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); +kclvm_value_ref_t* kclvm_builtin_str_isspace(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); -kclvm_value_ref_t* kclvm_builtin_str_join(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); +kclvm_value_ref_t* kclvm_builtin_str_istitle(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); -kclvm_value_ref_t* kclvm_builtin_str_lower(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); +kclvm_value_ref_t* kclvm_builtin_str_isupper(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); -kclvm_value_ref_t* kclvm_builtin_str_lstrip(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); +kclvm_value_ref_t* kclvm_builtin_str_join(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); -kclvm_value_ref_t* kclvm_builtin_str_replace(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); +kclvm_value_ref_t* kclvm_builtin_str_lower(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); -kclvm_value_ref_t* kclvm_builtin_str_rfind(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); +kclvm_value_ref_t* kclvm_builtin_str_lstrip(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); -kclvm_value_ref_t* kclvm_builtin_str_rindex(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); +kclvm_value_ref_t* kclvm_builtin_str_removeprefix(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); -kclvm_value_ref_t* kclvm_builtin_str_rsplit(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); +kclvm_value_ref_t* kclvm_builtin_str_removesuffix(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); -kclvm_value_ref_t* kclvm_builtin_str_rstrip(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); +kclvm_value_ref_t* kclvm_builtin_str_replace(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); -kclvm_value_ref_t* kclvm_builtin_str_split(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); +kclvm_value_ref_t* kclvm_builtin_str_rfind(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); -kclvm_value_ref_t* kclvm_builtin_str_splitlines(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); +kclvm_value_ref_t* kclvm_builtin_str_rindex(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); -kclvm_value_ref_t* kclvm_builtin_str_startswith(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); +kclvm_value_ref_t* kclvm_builtin_str_rsplit(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); -kclvm_value_ref_t* kclvm_builtin_str_strip(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); +kclvm_value_ref_t* kclvm_builtin_str_rstrip(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); -kclvm_value_ref_t* kclvm_builtin_str_title(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); +kclvm_value_ref_t* kclvm_builtin_str_split(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); -kclvm_value_ref_t* kclvm_builtin_str_upper(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); +kclvm_value_ref_t* kclvm_builtin_str_splitlines(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); -kclvm_value_ref_t* kclvm_builtin_sum(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); - -kclvm_value_ref_t* kclvm_builtin_typeof(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); +kclvm_value_ref_t* kclvm_builtin_str_startswith(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); -kclvm_value_ref_t* kclvm_builtin_zip(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); +kclvm_value_ref_t* kclvm_builtin_str_strip(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); -void kclvm_config_attr_map(kclvm_value_ref_t* value, kclvm_char_t* name, kclvm_char_t* type_str); +kclvm_value_ref_t* kclvm_builtin_str_title(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); -void kclvm_context_args_clear(kclvm_context_t* p); +kclvm_value_ref_t* kclvm_builtin_str_upper(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); -kclvm_char_t* kclvm_context_args_get(kclvm_context_t* _p, kclvm_char_t* _key); +kclvm_value_ref_t* kclvm_builtin_sum(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); -void kclvm_context_args_set(kclvm_context_t* _p, kclvm_char_t* _key, kclvm_char_t* _value); +kclvm_value_ref_t* kclvm_builtin_typeof(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); -void kclvm_context_clear_all_types(kclvm_context_t* p); +kclvm_value_ref_t* kclvm_builtin_zip(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); -kclvm_context_t* kclvm_context_current(); +void kclvm_config_attr_map(kclvm_value_ref_t* value, kclvm_char_t* name, kclvm_char_t* type_str); void kclvm_context_delete(kclvm_context_t* p); char* kclvm_context_invoke(kclvm_context_t* p, char* method, char* args, char* kwargs); -void kclvm_context_main_begin_hook(kclvm_context_t* p); - -kclvm_value_ref_t* kclvm_context_main_end_hook(kclvm_context_t* p, kclvm_value_ref_t* return_value); - kclvm_context_t* kclvm_context_new(); -kclvm_bool_t kclvm_context_pkgpath_is_imported(kclvm_char_t* pkgpath); - -void kclvm_context_put_type(kclvm_context_t* p, kclvm_type_t* typ); +kclvm_bool_t kclvm_context_pkgpath_is_imported(kclvm_context_t* ctx, kclvm_char_t* pkgpath); void kclvm_context_set_debug_mode(kclvm_context_t* p, kclvm_bool_t v); @@ -240,61 +211,53 @@ void kclvm_context_set_disable_schema_check(kclvm_context_t* p, kclvm_bool_t v); void kclvm_context_set_import_names(kclvm_context_t* p, kclvm_value_ref_t* import_names); -void kclvm_context_set_kcl_filename(int8_t* filename); - -void kclvm_context_set_kcl_line_col(int32_t line, int32_t col); - -void kclvm_context_set_kcl_location(kclvm_context_t* p, int8_t* filename, int32_t line, int32_t col); +void kclvm_context_set_kcl_filename(kclvm_context_t* ctx, char* filename); -void kclvm_context_set_kcl_pkgpath(kclvm_context_t* p, int8_t* pkgpath); +void kclvm_context_set_kcl_line_col(kclvm_context_t* ctx, int32_t line, int32_t col); -void kclvm_context_set_list_option_mode(kclvm_context_t* p, kclvm_bool_t v); +void kclvm_context_set_kcl_location(kclvm_context_t* p, char* filename, int32_t line, int32_t col); -void kclvm_context_set_strict_range_check(kclvm_context_t* p, kclvm_bool_t v); - -void kclvm_context_symbol_init(kclvm_context_t* p, kclvm_size_t n, kclvm_char_t** symbol_names); - -kclvm_char_t* kclvm_context_symbol_name(kclvm_context_t* p, kclvm_size_t i); +void kclvm_context_set_kcl_modpath(kclvm_context_t* p, char* module_path); -kclvm_size_t kclvm_context_symbol_num(kclvm_context_t* p); +void kclvm_context_set_kcl_pkgpath(kclvm_context_t* p, char* pkgpath); -kclvm_value_t* kclvm_context_symbol_value(kclvm_context_t* p, kclvm_size_t i); +void kclvm_context_set_kcl_workdir(kclvm_context_t* p, char* workdir); -kclvm_value_ref_t* kclvm_convert_collection_value(kclvm_value_ref_t* value, kclvm_char_t* tpe); +void kclvm_context_set_strict_range_check(kclvm_context_t* p, kclvm_bool_t v); -kclvm_value_ref_t* kclvm_crypto_md5(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); +kclvm_value_ref_t* kclvm_convert_collection_value(kclvm_context_t* ctx, kclvm_value_ref_t* value, kclvm_char_t* tpe, kclvm_value_ref_t* is_in_schema); -kclvm_value_ref_t* kclvm_crypto_sha1(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); +kclvm_value_ref_t* kclvm_crypto_blake3(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); -kclvm_value_ref_t* kclvm_crypto_sha224(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); +kclvm_value_ref_t* kclvm_crypto_fileblake3(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); -kclvm_value_ref_t* kclvm_crypto_sha256(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); +kclvm_value_ref_t* kclvm_crypto_filesha256(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); -kclvm_value_ref_t* kclvm_crypto_sha384(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); +kclvm_value_ref_t* kclvm_crypto_filesha512(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); -kclvm_value_ref_t* kclvm_crypto_sha512(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); +kclvm_value_ref_t* kclvm_crypto_md5(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); -kclvm_value_ref_t* kclvm_datetime_date(kclvm_context_t* _ctx, kclvm_value_ref_t* _args, kclvm_value_ref_t* _kwargs); +kclvm_value_ref_t* kclvm_crypto_sha1(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); -kclvm_value_ref_t* kclvm_datetime_now(kclvm_context_t* _ctx, kclvm_value_ref_t* _args, kclvm_value_ref_t* _kwargs); +kclvm_value_ref_t* kclvm_crypto_sha224(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); -kclvm_value_ref_t* kclvm_datetime_ticks(kclvm_context_t* _ctx, kclvm_value_ref_t* _args, kclvm_value_ref_t* _kwargs); +kclvm_value_ref_t* kclvm_crypto_sha256(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); -kclvm_value_ref_t* kclvm_datetime_today(kclvm_context_t* _ctx, kclvm_value_ref_t* _args, kclvm_value_ref_t* _kwargs); +kclvm_value_ref_t* kclvm_crypto_sha384(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); -void kclvm_debug_hello(); +kclvm_value_ref_t* kclvm_crypto_sha512(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); -void kclvm_debug_invoke_func(void* fn_ptr); +kclvm_value_ref_t* kclvm_crypto_uuid(kclvm_context_t* ctx, kclvm_value_ref_t* _args, kclvm_value_ref_t* _kwargs); -void kclvm_debug_print(int8_t* cs); +kclvm_value_ref_t* kclvm_datetime_date(kclvm_context_t* ctx, kclvm_value_ref_t* _args, kclvm_value_ref_t* _kwargs); -void kclvm_debug_print_str_list(int32_t len, int8_t** ss); +kclvm_value_ref_t* kclvm_datetime_now(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); -void kclvm_debug_print_type(kclvm_type_t* p); +kclvm_value_ref_t* kclvm_datetime_ticks(kclvm_context_t* ctx, kclvm_value_ref_t* _args, kclvm_value_ref_t* _kwargs); -void kclvm_debug_print_value(kclvm_value_ref_t* p); +kclvm_value_ref_t* kclvm_datetime_today(kclvm_context_t* ctx, kclvm_value_ref_t* _args, kclvm_value_ref_t* _kwargs); -void kclvm_debug_print_value_json_string(kclvm_value_ref_t* p); +kclvm_value_ref_t* kclvm_datetime_validate(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); void kclvm_default_collection_insert_int_pointer(kclvm_value_ref_t* p, kclvm_char_t* key, uint64_t* ptr); @@ -302,41 +265,71 @@ void kclvm_default_collection_insert_value(kclvm_value_ref_t* p, kclvm_char_t* k void kclvm_dict_clear(kclvm_value_ref_t* p); -kclvm_value_ref_t* kclvm_dict_get(kclvm_value_ref_t* p, kclvm_value_ref_t* key); +kclvm_value_ref_t* kclvm_dict_get(kclvm_context_t* ctx, kclvm_value_ref_t* p, kclvm_value_ref_t* key); -kclvm_value_ref_t* kclvm_dict_get_entry(kclvm_value_ref_t* p, kclvm_char_t* key); +kclvm_value_ref_t* kclvm_dict_get_entry(kclvm_context_t* ctx, kclvm_value_ref_t* p, kclvm_char_t* key); -kclvm_value_ref_t* kclvm_dict_get_value(kclvm_value_ref_t* p, kclvm_char_t* key); +kclvm_value_ref_t* kclvm_dict_get_value(kclvm_context_t* ctx, kclvm_value_ref_t* p, kclvm_char_t* key); -kclvm_value_ref_t* kclvm_dict_get_value_by_path(kclvm_value_ref_t* p, kclvm_char_t* path); +kclvm_value_ref_t* kclvm_dict_get_value_by_path(kclvm_context_t* ctx, kclvm_value_ref_t* p, kclvm_char_t* path); kclvm_bool_t kclvm_dict_has_value(kclvm_value_ref_t* p, kclvm_char_t* key); -void kclvm_dict_insert(kclvm_value_ref_t* p, kclvm_char_t* key, kclvm_value_ref_t* v, kclvm_size_t op, kclvm_size_t insert_index); +void kclvm_dict_insert(kclvm_context_t* ctx, kclvm_value_ref_t* p, kclvm_char_t* key, kclvm_value_ref_t* v, kclvm_size_t op, kclvm_size_t insert_index, kclvm_bool_t has_insert_index); + +void kclvm_dict_insert_unpack(kclvm_context_t* ctx, kclvm_value_ref_t* p, kclvm_value_ref_t* v); -void kclvm_dict_insert_unpack(kclvm_value_ref_t* p, kclvm_value_ref_t* v); +void kclvm_dict_insert_value(kclvm_context_t* ctx, kclvm_value_ref_t* p, kclvm_value_ref_t* key, kclvm_value_ref_t* v, kclvm_size_t op, kclvm_size_t insert_index, kclvm_bool_t has_insert_index); -void kclvm_dict_insert_value(kclvm_value_ref_t* p, kclvm_value_ref_t* key, kclvm_value_ref_t* v, kclvm_size_t op, kclvm_size_t insert_index); +kclvm_bool_t kclvm_dict_is_override_attr(kclvm_value_ref_t* p, kclvm_char_t* key); -kclvm_value_ref_t* kclvm_dict_keys(kclvm_value_ref_t* p); +kclvm_value_ref_t* kclvm_dict_keys(kclvm_context_t* ctx, kclvm_value_ref_t* p); kclvm_size_t kclvm_dict_len(kclvm_value_ref_t* p); -void kclvm_dict_merge(kclvm_value_ref_t* p, kclvm_char_t* key, kclvm_value_ref_t* v, kclvm_size_t op, kclvm_size_t insert_index); +void kclvm_dict_merge(kclvm_context_t* ctx, kclvm_value_ref_t* p, kclvm_char_t* key, kclvm_value_ref_t* v, kclvm_size_t op, kclvm_size_t insert_index, kclvm_bool_t has_insert_index); void kclvm_dict_remove(kclvm_value_ref_t* p, kclvm_char_t* key); -void kclvm_dict_safe_insert(kclvm_value_ref_t* p, kclvm_char_t* key, kclvm_value_ref_t* v, kclvm_size_t op, kclvm_size_t insert_index); +void kclvm_dict_safe_insert(kclvm_context_t* ctx, kclvm_value_ref_t* p, kclvm_char_t* key, kclvm_value_ref_t* v, kclvm_size_t op, kclvm_size_t insert_index, kclvm_bool_t has_insert_index); -void kclvm_dict_set_value(kclvm_value_ref_t* p, kclvm_char_t* key, kclvm_value_ref_t* val); +void kclvm_dict_set_value(kclvm_context_t* ctx, kclvm_value_ref_t* p, kclvm_char_t* key, kclvm_value_ref_t* val); void kclvm_dict_update(kclvm_value_ref_t* p, kclvm_value_ref_t* v); void kclvm_dict_update_key_value(kclvm_value_ref_t* p, kclvm_value_ref_t* key, kclvm_value_ref_t* v); -kclvm_value_ref_t* kclvm_dict_values(kclvm_value_ref_t* p); +kclvm_value_ref_t* kclvm_dict_values(kclvm_context_t* ctx, kclvm_value_ref_t* p); + +kclvm_value_ref_t* kclvm_file_abs(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); + +kclvm_value_ref_t* kclvm_file_append(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); + +kclvm_value_ref_t* kclvm_file_cp(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); + +kclvm_value_ref_t* kclvm_file_current(kclvm_context_t* ctx, kclvm_value_ref_t* _args, kclvm_value_ref_t* _kwargs); + +kclvm_value_ref_t* kclvm_file_delete(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); + +kclvm_value_ref_t* kclvm_file_exists(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); + +kclvm_value_ref_t* kclvm_file_glob(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); + +kclvm_value_ref_t* kclvm_file_mkdir(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); + +kclvm_value_ref_t* kclvm_file_modpath(kclvm_context_t* ctx, kclvm_value_ref_t* _args, kclvm_value_ref_t* _kwargs); + +kclvm_value_ref_t* kclvm_file_mv(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); + +kclvm_value_ref_t* kclvm_file_read(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); + +kclvm_value_ref_t* kclvm_file_read_env(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); -void kclvm_free(uint8_t* ptr); +kclvm_value_ref_t* kclvm_file_size(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); + +kclvm_value_ref_t* kclvm_file_workdir(kclvm_context_t* ctx, kclvm_value_ref_t* _args, kclvm_value_ref_t* _kwargs); + +kclvm_value_ref_t* kclvm_file_write(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); kclvm_value_ref_t* kclvm_iterator_cur_key(kclvm_iterator_t* p); @@ -348,11 +341,13 @@ kclvm_bool_t kclvm_iterator_is_end(kclvm_iterator_t* p); kclvm_value_ref_t* kclvm_iterator_next_value(kclvm_iterator_t* p, kclvm_value_ref_t* host); -kclvm_value_ref_t* kclvm_json_decode(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); +kclvm_value_ref_t* kclvm_json_decode(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); + +kclvm_value_ref_t* kclvm_json_dump_to_file(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); -kclvm_value_ref_t* kclvm_json_dump_to_file(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); +kclvm_value_ref_t* kclvm_json_encode(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); -kclvm_value_ref_t* kclvm_json_encode(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); +kclvm_value_ref_t* kclvm_json_validate(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); void kclvm_list_append(kclvm_value_ref_t* p, kclvm_value_ref_t* v); @@ -368,21 +363,21 @@ void kclvm_list_append_unpack(kclvm_value_ref_t* p, kclvm_value_ref_t* v); void kclvm_list_clear(kclvm_value_ref_t* p); -kclvm_value_ref_t* kclvm_list_count(kclvm_value_ref_t* p, kclvm_value_ref_t* item); +kclvm_value_ref_t* kclvm_list_count(kclvm_context_t* ctx, kclvm_value_ref_t* p, kclvm_value_ref_t* item); -kclvm_value_ref_t* kclvm_list_find(kclvm_value_ref_t* p, kclvm_value_ref_t* item); +kclvm_value_ref_t* kclvm_list_find(kclvm_context_t* ctx, kclvm_value_ref_t* p, kclvm_value_ref_t* item); -kclvm_value_ref_t* kclvm_list_get(kclvm_value_ref_t* p, kclvm_size_t i); +kclvm_value_ref_t* kclvm_list_get(kclvm_context_t* ctx, kclvm_value_ref_t* p, kclvm_size_t i); -kclvm_value_ref_t* kclvm_list_get_option(kclvm_value_ref_t* p, kclvm_size_t i); +kclvm_value_ref_t* kclvm_list_get_option(kclvm_context_t* ctx, kclvm_value_ref_t* p, kclvm_size_t i); void kclvm_list_insert(kclvm_value_ref_t* p, kclvm_value_ref_t* index, kclvm_value_ref_t* value); kclvm_size_t kclvm_list_len(kclvm_value_ref_t* p); -kclvm_value_ref_t* kclvm_list_pop(kclvm_value_ref_t* p); +kclvm_value_ref_t* kclvm_list_pop(kclvm_context_t* ctx, kclvm_value_ref_t* p); -kclvm_value_ref_t* kclvm_list_pop_first(kclvm_value_ref_t* p); +kclvm_value_ref_t* kclvm_list_pop_first(kclvm_context_t* ctx, kclvm_value_ref_t* p); void kclvm_list_remove_at(kclvm_value_ref_t* p, kclvm_size_t i); @@ -390,67 +385,67 @@ void kclvm_list_resize(kclvm_value_ref_t* p, kclvm_size_t newsize); void kclvm_list_set(kclvm_value_ref_t* p, kclvm_size_t i, kclvm_value_ref_t* v); -uint8_t* kclvm_malloc(int32_t n); +kclvm_value_ref_t* kclvm_manifests_yaml_stream(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); -kclvm_value_ref_t* kclvm_math_ceil(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); +kclvm_value_ref_t* kclvm_math_ceil(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); -kclvm_value_ref_t* kclvm_math_exp(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); +kclvm_value_ref_t* kclvm_math_exp(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); -kclvm_value_ref_t* kclvm_math_expm1(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); +kclvm_value_ref_t* kclvm_math_expm1(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); -kclvm_value_ref_t* kclvm_math_factorial(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); +kclvm_value_ref_t* kclvm_math_factorial(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); -kclvm_value_ref_t* kclvm_math_floor(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); +kclvm_value_ref_t* kclvm_math_floor(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); -kclvm_value_ref_t* kclvm_math_gcd(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); +kclvm_value_ref_t* kclvm_math_gcd(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); -kclvm_value_ref_t* kclvm_math_isfinite(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); +kclvm_value_ref_t* kclvm_math_isfinite(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); -kclvm_value_ref_t* kclvm_math_isinf(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); +kclvm_value_ref_t* kclvm_math_isinf(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); -kclvm_value_ref_t* kclvm_math_isnan(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); +kclvm_value_ref_t* kclvm_math_isnan(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); -kclvm_value_ref_t* kclvm_math_log(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); +kclvm_value_ref_t* kclvm_math_log(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); -kclvm_value_ref_t* kclvm_math_log10(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); +kclvm_value_ref_t* kclvm_math_log10(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); -kclvm_value_ref_t* kclvm_math_log1p(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); +kclvm_value_ref_t* kclvm_math_log1p(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); -kclvm_value_ref_t* kclvm_math_log2(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); +kclvm_value_ref_t* kclvm_math_log2(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); -kclvm_value_ref_t* kclvm_math_modf(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); +kclvm_value_ref_t* kclvm_math_modf(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); -kclvm_value_ref_t* kclvm_math_pow(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); +kclvm_value_ref_t* kclvm_math_pow(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); -kclvm_value_ref_t* kclvm_math_sqrt(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); +kclvm_value_ref_t* kclvm_math_sqrt(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); -kclvm_value_ref_t* kclvm_net_IP_string(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); +kclvm_value_ref_t* kclvm_net_IP_string(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); -kclvm_value_ref_t* kclvm_net_fqdn(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); +kclvm_value_ref_t* kclvm_net_fqdn(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); -kclvm_value_ref_t* kclvm_net_is_IP(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); +kclvm_value_ref_t* kclvm_net_is_IP(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); -kclvm_value_ref_t* kclvm_net_is_IPv4(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); +kclvm_value_ref_t* kclvm_net_is_IPv4(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); -kclvm_value_ref_t* kclvm_net_is_global_unicast_IP(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); +kclvm_value_ref_t* kclvm_net_is_global_unicast_IP(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); -kclvm_value_ref_t* kclvm_net_is_interface_local_multicast_IP(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); +kclvm_value_ref_t* kclvm_net_is_interface_local_multicast_IP(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); -kclvm_value_ref_t* kclvm_net_is_link_local_multicast_IP(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); +kclvm_value_ref_t* kclvm_net_is_link_local_multicast_IP(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); kclvm_value_ref_t* kclvm_net_is_link_local_unicast_IP(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); -kclvm_value_ref_t* kclvm_net_is_loopback_IP(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); +kclvm_value_ref_t* kclvm_net_is_loopback_IP(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); -kclvm_value_ref_t* kclvm_net_is_multicast_IP(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); +kclvm_value_ref_t* kclvm_net_is_multicast_IP(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); -kclvm_value_ref_t* kclvm_net_is_unspecified_IP(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); +kclvm_value_ref_t* kclvm_net_is_unspecified_IP(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); -kclvm_value_ref_t* kclvm_net_join_host_port(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); +kclvm_value_ref_t* kclvm_net_join_host_port(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); kclvm_value_ref_t* kclvm_net_parse_IP(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); -kclvm_value_ref_t* kclvm_net_split_host_port(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); +kclvm_value_ref_t* kclvm_net_split_host_port(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); kclvm_value_ref_t* kclvm_net_to_IP16(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); @@ -458,109 +453,55 @@ kclvm_value_ref_t* kclvm_net_to_IP4(kclvm_context_t* ctx, kclvm_value_ref_t* arg void kclvm_plugin_init(void* fn_ptr); -kclvm_value_ref_t* kclvm_plugin_invoke(int8_t* method, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); +kclvm_value_ref_t* kclvm_plugin_invoke(kclvm_context_t* ctx, char* method, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); -char* kclvm_plugin_invoke_json(int8_t* method, char* args, char* kwargs); +char* kclvm_plugin_invoke_json(char* method, char* args, char* kwargs); -kclvm_value_ref_t* kclvm_regex_compile(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); +kclvm_value_ref_t* kclvm_regex_compile(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); -kclvm_value_ref_t* kclvm_regex_findall(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); +kclvm_value_ref_t* kclvm_regex_findall(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); -kclvm_value_ref_t* kclvm_regex_match(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); +kclvm_value_ref_t* kclvm_regex_match(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); -kclvm_value_ref_t* kclvm_regex_replace(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); +kclvm_value_ref_t* kclvm_regex_replace(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); -kclvm_value_ref_t* kclvm_regex_search(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); +kclvm_value_ref_t* kclvm_regex_search(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); -kclvm_value_ref_t* kclvm_regex_split(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); +kclvm_value_ref_t* kclvm_regex_split(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); -void kclvm_schema_assert(kclvm_value_ref_t* value, kclvm_value_ref_t* msg, kclvm_value_ref_t* config_meta); +kclvm_value_ref_t* kclvm_runtime_catch(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); -void kclvm_schema_backtrack_cache(kclvm_value_ref_t* schema, kclvm_value_ref_t* cache, kclvm_value_ref_t* cal_map, kclvm_char_t* name, kclvm_value_ref_t* runtime_type); +void kclvm_schema_assert(kclvm_context_t* ctx, kclvm_value_ref_t* value, kclvm_value_ref_t* msg, kclvm_value_ref_t* config_meta); -void kclvm_schema_default_settings(kclvm_value_ref_t* schema_value, kclvm_value_ref_t* config_value, kclvm_char_t* runtime_type); +void kclvm_schema_backtrack_cache(kclvm_context_t* ctx, kclvm_value_ref_t* schema, kclvm_value_ref_t* cache, kclvm_value_ref_t* cal_map, kclvm_char_t* name, kclvm_value_ref_t* runtime_type); + +void kclvm_schema_default_settings(kclvm_value_ref_t* schema_value, kclvm_value_ref_t* _config_value, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs, kclvm_char_t* runtime_type); void kclvm_schema_do_check_with_index_sign_attr(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs, uint64_t* check_fn_ptr, kclvm_char_t* attr_name); -kclvm_value_ref_t* kclvm_schema_get_value(kclvm_value_ref_t* p, kclvm_char_t* key, kclvm_value_ref_t* config, kclvm_value_ref_t* config_meta, kclvm_value_ref_t* cal_map, kclvm_char_t* target_attr, kclvm_value_ref_t* backtrack_level_map, kclvm_value_ref_t* backtrack_cache, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); +kclvm_value_ref_t* kclvm_schema_get_value(kclvm_context_t* ctx, kclvm_value_ref_t* p, kclvm_char_t* key, kclvm_value_ref_t* config, kclvm_value_ref_t* config_meta, kclvm_value_ref_t* cal_map, kclvm_char_t* target_attr, kclvm_value_ref_t* backtrack_level_map, kclvm_value_ref_t* backtrack_cache, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); kclvm_value_ref_t* kclvm_schema_instances(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); -kclvm_value_ref_t* kclvm_schema_optional_check(kclvm_value_ref_t* p, kclvm_value_ref_t* v, kclvm_char_t* schema_name, kclvm_value_ref_t* config_meta); +void kclvm_schema_optional_check(kclvm_context_t* ctx, kclvm_value_ref_t* p); -void kclvm_schema_value_check(kclvm_value_ref_t* schema_value, kclvm_value_ref_t* schema_config, kclvm_value_ref_t* _config_meta, kclvm_char_t* schema_name, kclvm_value_ref_t* index_sign_value, kclvm_char_t* _key_name, kclvm_char_t* key_type, kclvm_char_t* _value_type, kclvm_bool_t _any_other, kclvm_bool_t is_relaxed); +void kclvm_schema_value_check(kclvm_context_t* ctx, kclvm_value_ref_t* schema_value, kclvm_value_ref_t* schema_config, kclvm_value_ref_t* _config_meta, kclvm_char_t* schema_name, kclvm_value_ref_t* index_sign_value, kclvm_char_t* key_name, kclvm_char_t* key_type, kclvm_char_t* value_type, kclvm_bool_t _any_other); kclvm_value_ref_t* kclvm_schema_value_new(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs, kclvm_value_ref_t* schema_value_or_func, kclvm_value_ref_t* config, kclvm_value_ref_t* config_meta, kclvm_char_t* pkgpath); -kclvm_size_t kclvm_strlen(uint8_t* ptr); - -void kclvm_testing_arguments(kclvm_context_t* _ctx, kclvm_value_ref_t* _args, kclvm_value_ref_t* _kwargs); - -void kclvm_testing_setting_file(kclvm_context_t* _ctx, kclvm_value_ref_t* _args, kclvm_value_ref_t* _kwargs); - -kclvm_type_t* kclvm_type_Any(); - -kclvm_type_t* kclvm_type_Bool(); - -kclvm_type_t* kclvm_type_BoolLit(kclvm_bool_t v); - -kclvm_bool_t kclvm_type_BoolLit_value(kclvm_type_t* p); - -kclvm_type_t* kclvm_type_Dict(kclvm_type_t* key_type, kclvm_type_t* elem_type); - -kclvm_type_t* kclvm_type_Float(); - -kclvm_type_t* kclvm_type_FloatLit(double v); - -double kclvm_type_FloatLit_value(kclvm_type_t* p); - -kclvm_type_t* kclvm_type_Func(kclvm_size_t args_len, kclvm_type_t** args_types, kclvm_type_t* return_type); - -kclvm_type_t* kclvm_type_Int(); - -kclvm_type_t* kclvm_type_IntLit(int64_t v); - -int64_t kclvm_type_IntLit_value(kclvm_type_t* p); - -kclvm_type_t* kclvm_type_List(kclvm_type_t* elem_type); - -kclvm_type_t* kclvm_type_Schema(kclvm_char_t* name, kclvm_char_t* parent_name, kclvm_bool_t _is_relaxed, kclvm_size_t field_num, kclvm_char_t** field_names, kclvm_type_t** field_types); - -kclvm_type_t* kclvm_type_Str(); - -kclvm_type_t* kclvm_type_StrLit(kclvm_char_t* s); - -kclvm_char_t* kclvm_type_StrLit_value(kclvm_type_t* p); +void kclvm_scope_add_setter(kclvm_context_t* _ctx, kclvm_eval_scope_t* scope, char* pkg, char* name, uint64_t* setter); -kclvm_type_t* kclvm_type_Union(kclvm_size_t n, kclvm_type_t** elem_types); +void kclvm_scope_delete(kclvm_eval_scope_t* scope); -kclvm_size_t kclvm_type_arg_num(kclvm_type_t* p); +kclvm_value_ref_t* kclvm_scope_get(kclvm_context_t* ctx, kclvm_eval_scope_t* scope, char* pkg, char* name, char* target, kclvm_value_ref_t* default); -kclvm_type_t* kclvm_type_arg_type(kclvm_type_t* p, kclvm_size_t i); +kclvm_eval_scope_t* kclvm_scope_new(); -void kclvm_type_delete(kclvm_type_t* p); +void kclvm_scope_set(kclvm_context_t* _ctx, kclvm_eval_scope_t* scope, char* pkg, char* name, kclvm_value_ref_t* value); -kclvm_type_t* kclvm_type_elem_type(kclvm_type_t* p); +kclvm_value_ref_t* kclvm_template_execute(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); -kclvm_type_t* kclvm_type_key_type(kclvm_type_t* p); - -kclvm_kind_t kclvm_type_kind(kclvm_type_t* p); - -kclvm_type_t* kclvm_type_return_type(kclvm_type_t* p); - -kclvm_char_t* kclvm_type_schema_field_name(kclvm_type_t* p, kclvm_size_t i); - -kclvm_size_t kclvm_type_schema_field_num(kclvm_type_t* p); - -kclvm_type_t* kclvm_type_schema_field_type(kclvm_type_t* p, kclvm_size_t i); - -kclvm_char_t* kclvm_type_schema_name(kclvm_type_t* p); - -kclvm_char_t* kclvm_type_schema_parent_name(kclvm_type_t* p); - -kclvm_bool_t kclvm_type_schema_relaxed(kclvm_type_t* p); - -kclvm_kind_t kclvm_type_str(kclvm_type_t* p); +kclvm_value_ref_t* kclvm_template_html_escape(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); kclvm_value_ref_t* kclvm_units_to_G(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); @@ -588,203 +529,191 @@ kclvm_value_ref_t* kclvm_units_to_n(kclvm_context_t* ctx, kclvm_value_ref_t* arg kclvm_value_ref_t* kclvm_units_to_u(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); -kclvm_value_ref_t* kclvm_value_Bool(kclvm_bool_t v); - -kclvm_bool_t* kclvm_value_Bool_ptr(kclvm_value_ref_t* p); - -kclvm_decorator_value_t* kclvm_value_Decorator(kclvm_char_t* name, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs, kclvm_value_ref_t* config_meta, kclvm_char_t* attr_name, kclvm_value_ref_t* config_value, kclvm_value_ref_t* is_schema_target); - -kclvm_value_ref_t* kclvm_value_Dict(); +kclvm_value_ref_t* kclvm_value_Bool(kclvm_context_t* ctx, kclvm_bool_t v); -kclvm_value_ref_t* kclvm_value_False(); +kclvm_decorator_value_t* kclvm_value_Decorator(kclvm_context_t* ctx, kclvm_char_t* name, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs, kclvm_value_ref_t* config_meta, kclvm_char_t* attr_name, kclvm_value_ref_t* config_value, kclvm_value_ref_t* is_schema_target); -kclvm_value_ref_t* kclvm_value_Float(kclvm_float_t v); +kclvm_value_ref_t* kclvm_value_Dict(kclvm_context_t* ctx); -kclvm_float_t* kclvm_value_Float_ptr(kclvm_value_ref_t* p); +kclvm_value_ref_t* kclvm_value_False(kclvm_context_t* ctx); -kclvm_value_ref_t* kclvm_value_Function(uint64_t* fn_ptr, kclvm_value_ref_t* closure, kclvm_char_t* external_name); +kclvm_value_ref_t* kclvm_value_Float(kclvm_context_t* ctx, kclvm_float_t v); -kclvm_value_ref_t* kclvm_value_Function_using_ptr(uint64_t* fn_ptr); +kclvm_value_ref_t* kclvm_value_Function(kclvm_context_t* ctx, uint64_t* fn_ptr, kclvm_value_ref_t* closure, kclvm_char_t* name, kclvm_bool_t is_external); -kclvm_value_ref_t* kclvm_value_Int(kclvm_int_t v); +kclvm_value_ref_t* kclvm_value_Function_using_ptr(kclvm_context_t* ctx, uint64_t* fn_ptr, kclvm_char_t* name); -kclvm_int_t* kclvm_value_Int_ptr(kclvm_value_ref_t* p); +kclvm_value_ref_t* kclvm_value_Int(kclvm_context_t* ctx, kclvm_int_t v); -kclvm_value_ref_t* kclvm_value_List(); +kclvm_value_ref_t* kclvm_value_List(kclvm_context_t* ctx); -kclvm_value_ref_t* kclvm_value_List10(kclvm_value_ref_t* v1, kclvm_value_ref_t* v2, kclvm_value_ref_t* v3, kclvm_value_ref_t* v4, kclvm_value_ref_t* v5, kclvm_value_ref_t* v6, kclvm_value_ref_t* v7, kclvm_value_ref_t* v8, kclvm_value_ref_t* v9, kclvm_value_ref_t* v10); +kclvm_value_ref_t* kclvm_value_List10(kclvm_context_t* ctx, kclvm_value_ref_t* v1, kclvm_value_ref_t* v2, kclvm_value_ref_t* v3, kclvm_value_ref_t* v4, kclvm_value_ref_t* v5, kclvm_value_ref_t* v6, kclvm_value_ref_t* v7, kclvm_value_ref_t* v8, kclvm_value_ref_t* v9, kclvm_value_ref_t* v10); -kclvm_value_ref_t* kclvm_value_List6(kclvm_value_ref_t* v1, kclvm_value_ref_t* v2, kclvm_value_ref_t* v3, kclvm_value_ref_t* v4, kclvm_value_ref_t* v5, kclvm_value_ref_t* v6); +kclvm_value_ref_t* kclvm_value_List6(kclvm_context_t* ctx, kclvm_value_ref_t* v1, kclvm_value_ref_t* v2, kclvm_value_ref_t* v3, kclvm_value_ref_t* v4, kclvm_value_ref_t* v5, kclvm_value_ref_t* v6); -kclvm_value_ref_t* kclvm_value_ListN(kclvm_int_t n, kclvm_value_ref_t** elem_values); +kclvm_value_ref_t* kclvm_value_None(kclvm_context_t* ctx); -kclvm_value_ref_t* kclvm_value_None(); +kclvm_value_ref_t* kclvm_value_Schema(kclvm_context_t* ctx); -kclvm_value_ref_t* kclvm_value_Schema(); - -kclvm_value_ref_t* kclvm_value_Str(kclvm_char_t* v); - -kclvm_size_t kclvm_value_Str_len(kclvm_value_ref_t* p); +kclvm_value_ref_t* kclvm_value_Str(kclvm_context_t* ctx, kclvm_char_t* v); kclvm_char_t* kclvm_value_Str_ptr(kclvm_value_ref_t* p); -void kclvm_value_Str_resize(kclvm_value_ref_t* p, kclvm_size_t n); - -kclvm_value_ref_t* kclvm_value_True(); +kclvm_value_ref_t* kclvm_value_True(kclvm_context_t* ctx); -kclvm_value_ref_t* kclvm_value_Undefined(); +kclvm_value_ref_t* kclvm_value_Undefined(kclvm_context_t* ctx); -kclvm_value_ref_t* kclvm_value_Unit(kclvm_float_t v, kclvm_int_t raw, kclvm_char_t* unit); +kclvm_value_ref_t* kclvm_value_Unit(kclvm_context_t* ctx, kclvm_float_t v, kclvm_int_t raw, kclvm_char_t* unit); -kclvm_value_ref_t* kclvm_value_as(kclvm_value_ref_t* a, kclvm_value_ref_t* b); +kclvm_value_ref_t* kclvm_value_as(kclvm_context_t* ctx, kclvm_value_ref_t* a, kclvm_value_ref_t* b); uint64_t* kclvm_value_check_function_ptr(kclvm_value_ref_t* p); -kclvm_value_ref_t* kclvm_value_cmp_equal_to(kclvm_value_ref_t* a, kclvm_value_ref_t* b); +kclvm_value_ref_t* kclvm_value_cmp_equal_to(kclvm_context_t* ctx, kclvm_value_ref_t* a, kclvm_value_ref_t* b); -kclvm_value_ref_t* kclvm_value_cmp_greater_than(kclvm_value_ref_t* a, kclvm_value_ref_t* b); +kclvm_value_ref_t* kclvm_value_cmp_greater_than(kclvm_context_t* ctx, kclvm_value_ref_t* a, kclvm_value_ref_t* b); -kclvm_value_ref_t* kclvm_value_cmp_greater_than_or_equal(kclvm_value_ref_t* a, kclvm_value_ref_t* b); +kclvm_value_ref_t* kclvm_value_cmp_greater_than_or_equal(kclvm_context_t* ctx, kclvm_value_ref_t* a, kclvm_value_ref_t* b); -kclvm_value_ref_t* kclvm_value_cmp_less_than(kclvm_value_ref_t* a, kclvm_value_ref_t* b); +kclvm_value_ref_t* kclvm_value_cmp_less_than(kclvm_context_t* ctx, kclvm_value_ref_t* a, kclvm_value_ref_t* b); -kclvm_value_ref_t* kclvm_value_cmp_less_than_or_equal(kclvm_value_ref_t* a, kclvm_value_ref_t* b); +kclvm_value_ref_t* kclvm_value_cmp_less_than_or_equal(kclvm_context_t* ctx, kclvm_value_ref_t* a, kclvm_value_ref_t* b); -kclvm_value_ref_t* kclvm_value_cmp_not_equal_to(kclvm_value_ref_t* a, kclvm_value_ref_t* b); +kclvm_value_ref_t* kclvm_value_cmp_not_equal_to(kclvm_context_t* ctx, kclvm_value_ref_t* a, kclvm_value_ref_t* b); -kclvm_value_ref_t* kclvm_value_deep_copy(kclvm_value_ref_t* p); +kclvm_value_ref_t* kclvm_value_deep_copy(kclvm_context_t* ctx, kclvm_value_ref_t* p); void kclvm_value_delete(kclvm_value_ref_t* p); -kclvm_value_ref_t* kclvm_value_from_json(kclvm_char_t* s); - -kclvm_value_ref_t* kclvm_value_function_external_invoke(kclvm_value_ref_t* p, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); - -kclvm_value_ref_t* kclvm_value_function_get_closure(kclvm_value_ref_t* p); - -kclvm_value_ref_t* kclvm_value_function_invoke(kclvm_value_ref_t* p, kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs, kclvm_char_t* pkgpath); +kclvm_value_ref_t* kclvm_value_from_json(kclvm_context_t* ctx, kclvm_char_t* s); -kclvm_bool_t kclvm_value_function_is_external(kclvm_value_ref_t* p); +kclvm_value_ref_t* kclvm_value_function_invoke(kclvm_value_ref_t* p, kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs, kclvm_char_t* pkgpath, kclvm_value_ref_t* is_in_schema); uint64_t* kclvm_value_function_ptr(kclvm_value_ref_t* p); -kclvm_value_ref_t* kclvm_value_in(kclvm_value_ref_t* a, kclvm_value_ref_t* b); +kclvm_value_ref_t* kclvm_value_in(kclvm_context_t* ctx, kclvm_value_ref_t* a, kclvm_value_ref_t* b); -kclvm_value_ref_t* kclvm_value_is(kclvm_value_ref_t* a, kclvm_value_ref_t* b); +kclvm_value_ref_t* kclvm_value_is(kclvm_context_t* ctx, kclvm_value_ref_t* a, kclvm_value_ref_t* b); -kclvm_value_ref_t* kclvm_value_is_not(kclvm_value_ref_t* a, kclvm_value_ref_t* b); +kclvm_value_ref_t* kclvm_value_is_not(kclvm_context_t* ctx, kclvm_value_ref_t* a, kclvm_value_ref_t* b); kclvm_bool_t kclvm_value_is_truthy(kclvm_value_ref_t* p); kclvm_iterator_t* kclvm_value_iter(kclvm_value_ref_t* p); -kclvm_kind_t kclvm_value_kind(kclvm_value_ref_t* p); - kclvm_size_t kclvm_value_len(kclvm_value_ref_t* p); -kclvm_value_ref_t* kclvm_value_load_attr(kclvm_value_ref_t* obj, kclvm_char_t* key); +kclvm_value_ref_t* kclvm_value_load_attr(kclvm_context_t* ctx, kclvm_value_ref_t* obj, kclvm_char_t* key); -kclvm_value_ref_t* kclvm_value_load_attr_option(kclvm_value_ref_t* p, kclvm_char_t* key); +kclvm_value_ref_t* kclvm_value_load_attr_option(kclvm_context_t* ctx, kclvm_value_ref_t* p, kclvm_char_t* key); -kclvm_value_ref_t* kclvm_value_logic_and(kclvm_value_ref_t* a, kclvm_value_ref_t* b); +kclvm_value_ref_t* kclvm_value_logic_and(kclvm_context_t* ctx, kclvm_value_ref_t* a, kclvm_value_ref_t* b); -kclvm_value_ref_t* kclvm_value_logic_or(kclvm_value_ref_t* a, kclvm_value_ref_t* b); +kclvm_value_ref_t* kclvm_value_logic_or(kclvm_context_t* ctx, kclvm_value_ref_t* a, kclvm_value_ref_t* b); -kclvm_value_ref_t* kclvm_value_not_in(kclvm_value_ref_t* a, kclvm_value_ref_t* b); +kclvm_value_ref_t* kclvm_value_not_in(kclvm_context_t* ctx, kclvm_value_ref_t* a, kclvm_value_ref_t* b); -kclvm_value_ref_t* kclvm_value_op_add(kclvm_value_ref_t* a, kclvm_value_ref_t* b); +kclvm_value_ref_t* kclvm_value_op_add(kclvm_context_t* ctx, kclvm_value_ref_t* a, kclvm_value_ref_t* b); -kclvm_value_ref_t* kclvm_value_op_aug_add(kclvm_value_ref_t* a, kclvm_value_ref_t* b); +kclvm_value_ref_t* kclvm_value_op_aug_add(kclvm_context_t* ctx, kclvm_value_ref_t* a, kclvm_value_ref_t* b); -kclvm_value_ref_t* kclvm_value_op_aug_bit_and(kclvm_value_ref_t* a, kclvm_value_ref_t* b); +kclvm_value_ref_t* kclvm_value_op_aug_bit_and(kclvm_context_t* _ctx, kclvm_value_ref_t* a, kclvm_value_ref_t* b); -kclvm_value_ref_t* kclvm_value_op_aug_bit_lshift(kclvm_value_ref_t* a, kclvm_value_ref_t* b); +kclvm_value_ref_t* kclvm_value_op_aug_bit_lshift(kclvm_context_t* ctx, kclvm_value_ref_t* a, kclvm_value_ref_t* b); -kclvm_value_ref_t* kclvm_value_op_aug_bit_or(kclvm_value_ref_t* a, kclvm_value_ref_t* b); +kclvm_value_ref_t* kclvm_value_op_aug_bit_or(kclvm_context_t* ctx, kclvm_value_ref_t* a, kclvm_value_ref_t* b); -kclvm_value_ref_t* kclvm_value_op_aug_bit_rshift(kclvm_value_ref_t* a, kclvm_value_ref_t* b); +kclvm_value_ref_t* kclvm_value_op_aug_bit_rshift(kclvm_context_t* ctx, kclvm_value_ref_t* a, kclvm_value_ref_t* b); -kclvm_value_ref_t* kclvm_value_op_aug_bit_xor(kclvm_value_ref_t* a, kclvm_value_ref_t* b); +kclvm_value_ref_t* kclvm_value_op_aug_bit_xor(kclvm_context_t* _ctx, kclvm_value_ref_t* a, kclvm_value_ref_t* b); -kclvm_value_ref_t* kclvm_value_op_aug_div(kclvm_value_ref_t* a, kclvm_value_ref_t* b); +kclvm_value_ref_t* kclvm_value_op_aug_div(kclvm_context_t* _ctx, kclvm_value_ref_t* a, kclvm_value_ref_t* b); -kclvm_value_ref_t* kclvm_value_op_aug_floor_div(kclvm_value_ref_t* a, kclvm_value_ref_t* b); +kclvm_value_ref_t* kclvm_value_op_aug_floor_div(kclvm_context_t* _ctx, kclvm_value_ref_t* a, kclvm_value_ref_t* b); -kclvm_value_ref_t* kclvm_value_op_aug_mod(kclvm_value_ref_t* a, kclvm_value_ref_t* b); +kclvm_value_ref_t* kclvm_value_op_aug_mod(kclvm_context_t* _ctx, kclvm_value_ref_t* a, kclvm_value_ref_t* b); -kclvm_value_ref_t* kclvm_value_op_aug_mul(kclvm_value_ref_t* a, kclvm_value_ref_t* b); +kclvm_value_ref_t* kclvm_value_op_aug_mul(kclvm_context_t* ctx, kclvm_value_ref_t* a, kclvm_value_ref_t* b); -kclvm_value_ref_t* kclvm_value_op_aug_pow(kclvm_value_ref_t* a, kclvm_value_ref_t* b); +kclvm_value_ref_t* kclvm_value_op_aug_pow(kclvm_context_t* ctx, kclvm_value_ref_t* a, kclvm_value_ref_t* b); -kclvm_value_ref_t* kclvm_value_op_aug_sub(kclvm_value_ref_t* a, kclvm_value_ref_t* b); +kclvm_value_ref_t* kclvm_value_op_aug_sub(kclvm_context_t* ctx, kclvm_value_ref_t* a, kclvm_value_ref_t* b); -kclvm_value_ref_t* kclvm_value_op_bit_and(kclvm_value_ref_t* a, kclvm_value_ref_t* b); +kclvm_value_ref_t* kclvm_value_op_bit_and(kclvm_context_t* ctx, kclvm_value_ref_t* a, kclvm_value_ref_t* b); -kclvm_value_ref_t* kclvm_value_op_bit_lshift(kclvm_value_ref_t* a, kclvm_value_ref_t* b); +kclvm_value_ref_t* kclvm_value_op_bit_lshift(kclvm_context_t* ctx, kclvm_value_ref_t* a, kclvm_value_ref_t* b); -kclvm_value_ref_t* kclvm_value_op_bit_or(kclvm_value_ref_t* a, kclvm_value_ref_t* b); +kclvm_value_ref_t* kclvm_value_op_bit_or(kclvm_context_t* ctx, kclvm_value_ref_t* a, kclvm_value_ref_t* b); -kclvm_value_ref_t* kclvm_value_op_bit_rshift(kclvm_value_ref_t* a, kclvm_value_ref_t* b); +kclvm_value_ref_t* kclvm_value_op_bit_rshift(kclvm_context_t* ctx, kclvm_value_ref_t* a, kclvm_value_ref_t* b); -kclvm_value_ref_t* kclvm_value_op_bit_xor(kclvm_value_ref_t* a, kclvm_value_ref_t* b); +kclvm_value_ref_t* kclvm_value_op_bit_xor(kclvm_context_t* ctx, kclvm_value_ref_t* a, kclvm_value_ref_t* b); -kclvm_value_ref_t* kclvm_value_op_div(kclvm_value_ref_t* a, kclvm_value_ref_t* b); +kclvm_value_ref_t* kclvm_value_op_div(kclvm_context_t* ctx, kclvm_value_ref_t* a, kclvm_value_ref_t* b); -kclvm_value_ref_t* kclvm_value_op_floor_div(kclvm_value_ref_t* a, kclvm_value_ref_t* b); +kclvm_value_ref_t* kclvm_value_op_floor_div(kclvm_context_t* ctx, kclvm_value_ref_t* a, kclvm_value_ref_t* b); -kclvm_value_ref_t* kclvm_value_op_mod(kclvm_value_ref_t* a, kclvm_value_ref_t* b); +kclvm_value_ref_t* kclvm_value_op_mod(kclvm_context_t* ctx, kclvm_value_ref_t* a, kclvm_value_ref_t* b); -kclvm_value_ref_t* kclvm_value_op_mul(kclvm_value_ref_t* a, kclvm_value_ref_t* b); +kclvm_value_ref_t* kclvm_value_op_mul(kclvm_context_t* ctx, kclvm_value_ref_t* a, kclvm_value_ref_t* b); -kclvm_value_ref_t* kclvm_value_op_pow(kclvm_value_ref_t* a, kclvm_value_ref_t* b); +kclvm_value_ref_t* kclvm_value_op_pow(kclvm_context_t* ctx, kclvm_value_ref_t* a, kclvm_value_ref_t* b); -kclvm_value_ref_t* kclvm_value_op_sub(kclvm_value_ref_t* a, kclvm_value_ref_t* b); +kclvm_value_ref_t* kclvm_value_op_sub(kclvm_context_t* ctx, kclvm_value_ref_t* a, kclvm_value_ref_t* b); -kclvm_value_ref_t* kclvm_value_plan_to_json(kclvm_value_ref_t* p); +kclvm_value_ref_t* kclvm_value_plan_to_json(kclvm_context_t* ctx, kclvm_value_ref_t* p); -kclvm_value_ref_t* kclvm_value_plan_to_yaml(kclvm_value_ref_t* p); +kclvm_value_ref_t* kclvm_value_plan_to_yaml(kclvm_context_t* ctx, kclvm_value_ref_t* p); void kclvm_value_remove_item(kclvm_value_ref_t* a, kclvm_value_ref_t* b); -kclvm_value_ref_t* kclvm_value_schema_function(uint64_t* fn_ptr, uint64_t* check_fn_ptr, kclvm_char_t* tpe); +kclvm_value_ref_t* kclvm_value_schema_function(kclvm_context_t* ctx, uint64_t* fn_ptr, uint64_t* check_fn_ptr, kclvm_value_ref_t* attr_map, kclvm_char_t* tpe); + +kclvm_value_ref_t* kclvm_value_schema_with_config(kclvm_context_t* ctx, kclvm_value_ref_t* schema_dict, kclvm_value_ref_t* config, kclvm_value_ref_t* config_meta, kclvm_char_t* name, kclvm_char_t* pkgpath, kclvm_value_ref_t* is_sub_schema, kclvm_value_ref_t* record_instance, kclvm_value_ref_t* instance_pkgpath, kclvm_value_ref_t* optional_mapping, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); + +kclvm_value_ref_t* kclvm_value_slice(kclvm_context_t* ctx, kclvm_value_ref_t* x, kclvm_value_ref_t* a, kclvm_value_ref_t* b, kclvm_value_ref_t* step); + +kclvm_value_ref_t* kclvm_value_slice_option(kclvm_context_t* ctx, kclvm_value_ref_t* x, kclvm_value_ref_t* a, kclvm_value_ref_t* b, kclvm_value_ref_t* step); + +kclvm_value_ref_t* kclvm_value_subscr(kclvm_context_t* ctx, kclvm_value_ref_t* a, kclvm_value_ref_t* b); -kclvm_value_ref_t* kclvm_value_schema_with_config(kclvm_value_ref_t* schema_dict, kclvm_value_ref_t* config, kclvm_char_t* name, kclvm_char_t* pkgpath, kclvm_value_ref_t* is_sub_schema, kclvm_value_ref_t* record_instance, kclvm_value_ref_t* instance_pkgpath); +kclvm_value_ref_t* kclvm_value_subscr_option(kclvm_context_t* ctx, kclvm_value_ref_t* a, kclvm_value_ref_t* b); -kclvm_value_ref_t* kclvm_value_slice(kclvm_value_ref_t* x, kclvm_value_ref_t* a, kclvm_value_ref_t* b, kclvm_value_ref_t* step); +void kclvm_value_subscr_set(kclvm_context_t* ctx, kclvm_value_ref_t* p, kclvm_value_ref_t* index, kclvm_value_ref_t* val); -kclvm_value_ref_t* kclvm_value_slice_option(kclvm_value_ref_t* x, kclvm_value_ref_t* a, kclvm_value_ref_t* b, kclvm_value_ref_t* step); +kclvm_value_ref_t* kclvm_value_to_json_value(kclvm_context_t* ctx, kclvm_value_ref_t* p); -kclvm_value_ref_t* kclvm_value_subscr(kclvm_value_ref_t* a, kclvm_value_ref_t* b); +kclvm_value_ref_t* kclvm_value_to_json_value_with_null(kclvm_context_t* ctx, kclvm_value_ref_t* p); -kclvm_value_ref_t* kclvm_value_subscr_option(kclvm_value_ref_t* a, kclvm_value_ref_t* b); +kclvm_value_ref_t* kclvm_value_to_str_value(kclvm_context_t* ctx, kclvm_value_ref_t* p); -kclvm_buffer_t* kclvm_value_to_json(kclvm_value_ref_t* p); +kclvm_value_ref_t* kclvm_value_to_yaml_value(kclvm_context_t* ctx, kclvm_value_ref_t* p); -kclvm_value_ref_t* kclvm_value_to_json_value(kclvm_value_ref_t* p); +kclvm_value_ref_t* kclvm_value_unary_l_not(kclvm_context_t* ctx, kclvm_value_ref_t* a); -kclvm_value_ref_t* kclvm_value_to_json_value_with_null(kclvm_value_ref_t* p); +kclvm_value_ref_t* kclvm_value_unary_minus(kclvm_context_t* ctx, kclvm_value_ref_t* a); -kclvm_value_ref_t* kclvm_value_to_str_value(kclvm_value_ref_t* p); +kclvm_value_ref_t* kclvm_value_unary_not(kclvm_context_t* ctx, kclvm_value_ref_t* a); -kclvm_value_ref_t* kclvm_value_to_yaml_value(kclvm_value_ref_t* p); +kclvm_value_ref_t* kclvm_value_unary_plus(kclvm_context_t* ctx, kclvm_value_ref_t* a); -kclvm_value_ref_t* kclvm_value_unary_l_not(kclvm_value_ref_t* a); +kclvm_value_ref_t* kclvm_value_union(kclvm_context_t* ctx, kclvm_value_ref_t* schema, kclvm_value_ref_t* b); -kclvm_value_ref_t* kclvm_value_unary_minus(kclvm_value_ref_t* a); +kclvm_value_ref_t* kclvm_value_union_all(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); -kclvm_value_ref_t* kclvm_value_unary_not(kclvm_value_ref_t* a); +kclvm_value_ref_t* kclvm_yaml_decode(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); -kclvm_value_ref_t* kclvm_value_unary_plus(kclvm_value_ref_t* a); +kclvm_value_ref_t* kclvm_yaml_decode_all(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); -kclvm_value_ref_t* kclvm_value_union(kclvm_value_ref_t* schema, kclvm_value_ref_t* b); +kclvm_value_ref_t* kclvm_yaml_dump_all_to_file(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); -kclvm_value_ref_t* kclvm_value_union_all(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); +kclvm_value_ref_t* kclvm_yaml_dump_to_file(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); -kclvm_value_ref_t* kclvm_yaml_decode(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); +kclvm_value_ref_t* kclvm_yaml_encode(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); -kclvm_value_ref_t* kclvm_yaml_dump_to_file(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); +kclvm_value_ref_t* kclvm_yaml_encode_all(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); -kclvm_value_ref_t* kclvm_yaml_encode(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); +kclvm_value_ref_t* kclvm_yaml_validate(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); #ifdef __cplusplus } // extern "C" diff --git a/kclvm/runtime/src/_kclvm.ll b/kclvm/runtime/src/_kclvm.ll index d1a22957b..c07eaeb6f 100644 --- a/kclvm/runtime/src/_kclvm.ll +++ b/kclvm/runtime/src/_kclvm.ll @@ -1,4 +1,4 @@ -; Copyright 2021 The KCL Authors. All rights reserved. +; Copyright The KCL Authors. All rights reserved. ; Auto generated, DONOT EDIT!!! @@ -12,6 +12,8 @@ %"kclvm_decorator_value_t" = type opaque +%"kclvm_eval_scope_t" = type { i8* } + %"kclvm_float_t" = type double %"kclvm_int_t" = type i64 @@ -28,19 +30,11 @@ %"kclvm_value_t" = type { i8* } -declare void @kclvm_assert(%kclvm_value_ref_t* %value, %kclvm_value_ref_t* %msg); - -declare %kclvm_value_ref_t* @kclvm_base64_decode(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); - -declare %kclvm_value_ref_t* @kclvm_base64_encode(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +declare void @kclvm_assert(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %value, %kclvm_value_ref_t* %msg); -declare %kclvm_char_t* @kclvm_buffer_data(%kclvm_buffer_t* %p); +declare %kclvm_value_ref_t* @kclvm_base64_decode(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); -declare void @kclvm_buffer_delete(%kclvm_buffer_t* %p); - -declare %kclvm_buffer_t* @kclvm_buffer_new(%kclvm_size_t %size); - -declare %kclvm_size_t @kclvm_buffer_size(%kclvm_buffer_t* %p); +declare %kclvm_value_ref_t* @kclvm_base64_encode(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); declare %kclvm_value_ref_t* @kclvm_builtin_abs(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); @@ -50,7 +44,7 @@ declare %kclvm_value_ref_t* @kclvm_builtin_any_true(%kclvm_context_t* %ctx, %kcl declare %kclvm_value_ref_t* @kclvm_builtin_bin(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); -declare %kclvm_value_ref_t* @kclvm_builtin_bool(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +declare %kclvm_value_ref_t* @kclvm_builtin_bool(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); declare %kclvm_value_ref_t* @kclvm_builtin_dict(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); @@ -60,15 +54,17 @@ declare %kclvm_value_ref_t* @kclvm_builtin_hex(%kclvm_context_t* %ctx, %kclvm_va declare %kclvm_value_ref_t* @kclvm_builtin_int(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); +declare %kclvm_value_ref_t* @kclvm_builtin_isnullish(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); + declare %kclvm_value_ref_t* @kclvm_builtin_isunique(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); -declare %kclvm_value_ref_t* @kclvm_builtin_len(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +declare %kclvm_value_ref_t* @kclvm_builtin_len(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); declare %kclvm_value_ref_t* @kclvm_builtin_list(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); -declare %kclvm_value_ref_t* @kclvm_builtin_max(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); +declare %kclvm_value_ref_t* @kclvm_builtin_max(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); -declare %kclvm_value_ref_t* @kclvm_builtin_min(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); +declare %kclvm_value_ref_t* @kclvm_builtin_min(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); declare %kclvm_value_ref_t* @kclvm_builtin_multiplyof(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); @@ -92,93 +88,83 @@ declare %kclvm_value_ref_t* @kclvm_builtin_round(%kclvm_context_t* %ctx, %kclvm_ declare %kclvm_value_ref_t* @kclvm_builtin_sorted(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); -declare %kclvm_value_ref_t* @kclvm_builtin_str(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +declare %kclvm_value_ref_t* @kclvm_builtin_str(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); -declare %kclvm_value_ref_t* @kclvm_builtin_str_capitalize(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +declare %kclvm_value_ref_t* @kclvm_builtin_str_capitalize(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); -declare %kclvm_value_ref_t* @kclvm_builtin_str_count(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +declare %kclvm_value_ref_t* @kclvm_builtin_str_chars(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); -declare %kclvm_value_ref_t* @kclvm_builtin_str_endswith(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +declare %kclvm_value_ref_t* @kclvm_builtin_str_count(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); -declare %kclvm_value_ref_t* @kclvm_builtin_str_find(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +declare %kclvm_value_ref_t* @kclvm_builtin_str_endswith(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); -declare %kclvm_value_ref_t* @kclvm_builtin_str_format(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); +declare %kclvm_value_ref_t* @kclvm_builtin_str_find(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); -declare %kclvm_value_ref_t* @kclvm_builtin_str_index(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +declare %kclvm_value_ref_t* @kclvm_builtin_str_format(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); -declare %kclvm_value_ref_t* @kclvm_builtin_str_isalnum(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +declare %kclvm_value_ref_t* @kclvm_builtin_str_index(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); -declare %kclvm_value_ref_t* @kclvm_builtin_str_isalpha(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +declare %kclvm_value_ref_t* @kclvm_builtin_str_isalnum(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); -declare %kclvm_value_ref_t* @kclvm_builtin_str_isdigit(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +declare %kclvm_value_ref_t* @kclvm_builtin_str_isalpha(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); -declare %kclvm_value_ref_t* @kclvm_builtin_str_islower(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +declare %kclvm_value_ref_t* @kclvm_builtin_str_isdigit(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); -declare %kclvm_value_ref_t* @kclvm_builtin_str_isspace(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +declare %kclvm_value_ref_t* @kclvm_builtin_str_islower(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); -declare %kclvm_value_ref_t* @kclvm_builtin_str_istitle(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +declare %kclvm_value_ref_t* @kclvm_builtin_str_isspace(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); -declare %kclvm_value_ref_t* @kclvm_builtin_str_isupper(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +declare %kclvm_value_ref_t* @kclvm_builtin_str_istitle(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); -declare %kclvm_value_ref_t* @kclvm_builtin_str_join(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +declare %kclvm_value_ref_t* @kclvm_builtin_str_isupper(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); -declare %kclvm_value_ref_t* @kclvm_builtin_str_lower(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +declare %kclvm_value_ref_t* @kclvm_builtin_str_join(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); -declare %kclvm_value_ref_t* @kclvm_builtin_str_lstrip(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +declare %kclvm_value_ref_t* @kclvm_builtin_str_lower(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); -declare %kclvm_value_ref_t* @kclvm_builtin_str_replace(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +declare %kclvm_value_ref_t* @kclvm_builtin_str_lstrip(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); -declare %kclvm_value_ref_t* @kclvm_builtin_str_rfind(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +declare %kclvm_value_ref_t* @kclvm_builtin_str_removeprefix(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); -declare %kclvm_value_ref_t* @kclvm_builtin_str_rindex(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +declare %kclvm_value_ref_t* @kclvm_builtin_str_removesuffix(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); -declare %kclvm_value_ref_t* @kclvm_builtin_str_rsplit(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); +declare %kclvm_value_ref_t* @kclvm_builtin_str_replace(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); -declare %kclvm_value_ref_t* @kclvm_builtin_str_rstrip(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +declare %kclvm_value_ref_t* @kclvm_builtin_str_rfind(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); -declare %kclvm_value_ref_t* @kclvm_builtin_str_split(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); +declare %kclvm_value_ref_t* @kclvm_builtin_str_rindex(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); -declare %kclvm_value_ref_t* @kclvm_builtin_str_splitlines(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); +declare %kclvm_value_ref_t* @kclvm_builtin_str_rsplit(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); -declare %kclvm_value_ref_t* @kclvm_builtin_str_startswith(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +declare %kclvm_value_ref_t* @kclvm_builtin_str_rstrip(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); -declare %kclvm_value_ref_t* @kclvm_builtin_str_strip(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +declare %kclvm_value_ref_t* @kclvm_builtin_str_split(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); -declare %kclvm_value_ref_t* @kclvm_builtin_str_title(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +declare %kclvm_value_ref_t* @kclvm_builtin_str_splitlines(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); -declare %kclvm_value_ref_t* @kclvm_builtin_str_upper(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +declare %kclvm_value_ref_t* @kclvm_builtin_str_startswith(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); -declare %kclvm_value_ref_t* @kclvm_builtin_sum(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); - -declare %kclvm_value_ref_t* @kclvm_builtin_typeof(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); +declare %kclvm_value_ref_t* @kclvm_builtin_str_strip(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); -declare %kclvm_value_ref_t* @kclvm_builtin_zip(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); - -declare void @kclvm_config_attr_map(%kclvm_value_ref_t* %value, %kclvm_char_t* %name, %kclvm_char_t* %type_str); +declare %kclvm_value_ref_t* @kclvm_builtin_str_title(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); -declare void @kclvm_context_args_clear(%kclvm_context_t* %p); +declare %kclvm_value_ref_t* @kclvm_builtin_str_upper(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); -declare %kclvm_char_t* @kclvm_context_args_get(%kclvm_context_t* %_p, %kclvm_char_t* %_key); +declare %kclvm_value_ref_t* @kclvm_builtin_sum(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); -declare void @kclvm_context_args_set(%kclvm_context_t* %_p, %kclvm_char_t* %_key, %kclvm_char_t* %_value); +declare %kclvm_value_ref_t* @kclvm_builtin_typeof(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); -declare void @kclvm_context_clear_all_types(%kclvm_context_t* %p); +declare %kclvm_value_ref_t* @kclvm_builtin_zip(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); -declare %kclvm_context_t* @kclvm_context_current(); +declare void @kclvm_config_attr_map(%kclvm_value_ref_t* %value, %kclvm_char_t* %name, %kclvm_char_t* %type_str); declare void @kclvm_context_delete(%kclvm_context_t* %p); declare i8* @kclvm_context_invoke(%kclvm_context_t* %p, i8* %method, i8* %args, i8* %kwargs); -declare void @kclvm_context_main_begin_hook(%kclvm_context_t* %p); - -declare %kclvm_value_ref_t* @kclvm_context_main_end_hook(%kclvm_context_t* %p, %kclvm_value_ref_t* %return_value); - declare %kclvm_context_t* @kclvm_context_new(); -declare %kclvm_bool_t @kclvm_context_pkgpath_is_imported(%kclvm_char_t* %pkgpath); - -declare void @kclvm_context_put_type(%kclvm_context_t* %p, %kclvm_type_t* %typ); +declare %kclvm_bool_t @kclvm_context_pkgpath_is_imported(%kclvm_context_t* %ctx, %kclvm_char_t* %pkgpath); declare void @kclvm_context_set_debug_mode(%kclvm_context_t* %p, %kclvm_bool_t %v); @@ -188,61 +174,53 @@ declare void @kclvm_context_set_disable_schema_check(%kclvm_context_t* %p, %kclv declare void @kclvm_context_set_import_names(%kclvm_context_t* %p, %kclvm_value_ref_t* %import_names); -declare void @kclvm_context_set_kcl_filename(i8* %filename); +declare void @kclvm_context_set_kcl_filename(%kclvm_context_t* %ctx, i8* %filename); -declare void @kclvm_context_set_kcl_line_col(i32 %line, i32 %col); +declare void @kclvm_context_set_kcl_line_col(%kclvm_context_t* %ctx, i32 %line, i32 %col); declare void @kclvm_context_set_kcl_location(%kclvm_context_t* %p, i8* %filename, i32 %line, i32 %col); +declare void @kclvm_context_set_kcl_modpath(%kclvm_context_t* %p, i8* %module_path); + declare void @kclvm_context_set_kcl_pkgpath(%kclvm_context_t* %p, i8* %pkgpath); -declare void @kclvm_context_set_list_option_mode(%kclvm_context_t* %p, %kclvm_bool_t %v); +declare void @kclvm_context_set_kcl_workdir(%kclvm_context_t* %p, i8* %workdir); declare void @kclvm_context_set_strict_range_check(%kclvm_context_t* %p, %kclvm_bool_t %v); -declare void @kclvm_context_symbol_init(%kclvm_context_t* %p, %kclvm_size_t %n, %kclvm_char_t** %symbol_names); - -declare %kclvm_char_t* @kclvm_context_symbol_name(%kclvm_context_t* %p, %kclvm_size_t %i); - -declare %kclvm_size_t @kclvm_context_symbol_num(%kclvm_context_t* %p); - -declare %kclvm_value_t* @kclvm_context_symbol_value(%kclvm_context_t* %p, %kclvm_size_t %i); +declare %kclvm_value_ref_t* @kclvm_convert_collection_value(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %value, %kclvm_char_t* %tpe, %kclvm_value_ref_t* %is_in_schema); -declare %kclvm_value_ref_t* @kclvm_convert_collection_value(%kclvm_value_ref_t* %value, %kclvm_char_t* %tpe); +declare %kclvm_value_ref_t* @kclvm_crypto_blake3(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); -declare %kclvm_value_ref_t* @kclvm_crypto_md5(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +declare %kclvm_value_ref_t* @kclvm_crypto_fileblake3(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); -declare %kclvm_value_ref_t* @kclvm_crypto_sha1(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +declare %kclvm_value_ref_t* @kclvm_crypto_filesha256(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); -declare %kclvm_value_ref_t* @kclvm_crypto_sha224(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +declare %kclvm_value_ref_t* @kclvm_crypto_filesha512(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); -declare %kclvm_value_ref_t* @kclvm_crypto_sha256(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +declare %kclvm_value_ref_t* @kclvm_crypto_md5(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); -declare %kclvm_value_ref_t* @kclvm_crypto_sha384(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +declare %kclvm_value_ref_t* @kclvm_crypto_sha1(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); -declare %kclvm_value_ref_t* @kclvm_crypto_sha512(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +declare %kclvm_value_ref_t* @kclvm_crypto_sha224(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); -declare %kclvm_value_ref_t* @kclvm_datetime_date(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %_args, %kclvm_value_ref_t* %_kwargs); +declare %kclvm_value_ref_t* @kclvm_crypto_sha256(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); -declare %kclvm_value_ref_t* @kclvm_datetime_now(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %_args, %kclvm_value_ref_t* %_kwargs); +declare %kclvm_value_ref_t* @kclvm_crypto_sha384(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); -declare %kclvm_value_ref_t* @kclvm_datetime_ticks(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %_args, %kclvm_value_ref_t* %_kwargs); +declare %kclvm_value_ref_t* @kclvm_crypto_sha512(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); -declare %kclvm_value_ref_t* @kclvm_datetime_today(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %_args, %kclvm_value_ref_t* %_kwargs); +declare %kclvm_value_ref_t* @kclvm_crypto_uuid(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %_args, %kclvm_value_ref_t* %_kwargs); -declare void @kclvm_debug_hello(); +declare %kclvm_value_ref_t* @kclvm_datetime_date(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %_args, %kclvm_value_ref_t* %_kwargs); -declare void @kclvm_debug_invoke_func(i8* %fn_ptr); +declare %kclvm_value_ref_t* @kclvm_datetime_now(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); -declare void @kclvm_debug_print(i8* %cs); +declare %kclvm_value_ref_t* @kclvm_datetime_ticks(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %_args, %kclvm_value_ref_t* %_kwargs); -declare void @kclvm_debug_print_str_list(i32 %len, i8** %ss); +declare %kclvm_value_ref_t* @kclvm_datetime_today(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %_args, %kclvm_value_ref_t* %_kwargs); -declare void @kclvm_debug_print_type(%kclvm_type_t* %p); - -declare void @kclvm_debug_print_value(%kclvm_value_ref_t* %p); - -declare void @kclvm_debug_print_value_json_string(%kclvm_value_ref_t* %p); +declare %kclvm_value_ref_t* @kclvm_datetime_validate(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); declare void @kclvm_default_collection_insert_int_pointer(%kclvm_value_ref_t* %p, %kclvm_char_t* %key, i64* %ptr); @@ -250,41 +228,71 @@ declare void @kclvm_default_collection_insert_value(%kclvm_value_ref_t* %p, %kcl declare void @kclvm_dict_clear(%kclvm_value_ref_t* %p); -declare %kclvm_value_ref_t* @kclvm_dict_get(%kclvm_value_ref_t* %p, %kclvm_value_ref_t* %key); +declare %kclvm_value_ref_t* @kclvm_dict_get(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %p, %kclvm_value_ref_t* %key); -declare %kclvm_value_ref_t* @kclvm_dict_get_entry(%kclvm_value_ref_t* %p, %kclvm_char_t* %key); +declare %kclvm_value_ref_t* @kclvm_dict_get_entry(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %p, %kclvm_char_t* %key); -declare %kclvm_value_ref_t* @kclvm_dict_get_value(%kclvm_value_ref_t* %p, %kclvm_char_t* %key); +declare %kclvm_value_ref_t* @kclvm_dict_get_value(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %p, %kclvm_char_t* %key); -declare %kclvm_value_ref_t* @kclvm_dict_get_value_by_path(%kclvm_value_ref_t* %p, %kclvm_char_t* %path); +declare %kclvm_value_ref_t* @kclvm_dict_get_value_by_path(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %p, %kclvm_char_t* %path); declare %kclvm_bool_t @kclvm_dict_has_value(%kclvm_value_ref_t* %p, %kclvm_char_t* %key); -declare void @kclvm_dict_insert(%kclvm_value_ref_t* %p, %kclvm_char_t* %key, %kclvm_value_ref_t* %v, %kclvm_size_t %op, %kclvm_size_t %insert_index); +declare void @kclvm_dict_insert(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %p, %kclvm_char_t* %key, %kclvm_value_ref_t* %v, %kclvm_size_t %op, %kclvm_size_t %insert_index, %kclvm_bool_t %has_insert_index); + +declare void @kclvm_dict_insert_unpack(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %p, %kclvm_value_ref_t* %v); -declare void @kclvm_dict_insert_unpack(%kclvm_value_ref_t* %p, %kclvm_value_ref_t* %v); +declare void @kclvm_dict_insert_value(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %p, %kclvm_value_ref_t* %key, %kclvm_value_ref_t* %v, %kclvm_size_t %op, %kclvm_size_t %insert_index, %kclvm_bool_t %has_insert_index); -declare void @kclvm_dict_insert_value(%kclvm_value_ref_t* %p, %kclvm_value_ref_t* %key, %kclvm_value_ref_t* %v, %kclvm_size_t %op, %kclvm_size_t %insert_index); +declare %kclvm_bool_t @kclvm_dict_is_override_attr(%kclvm_value_ref_t* %p, %kclvm_char_t* %key); -declare %kclvm_value_ref_t* @kclvm_dict_keys(%kclvm_value_ref_t* %p); +declare %kclvm_value_ref_t* @kclvm_dict_keys(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %p); declare %kclvm_size_t @kclvm_dict_len(%kclvm_value_ref_t* %p); -declare void @kclvm_dict_merge(%kclvm_value_ref_t* %p, %kclvm_char_t* %key, %kclvm_value_ref_t* %v, %kclvm_size_t %op, %kclvm_size_t %insert_index); +declare void @kclvm_dict_merge(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %p, %kclvm_char_t* %key, %kclvm_value_ref_t* %v, %kclvm_size_t %op, %kclvm_size_t %insert_index, %kclvm_bool_t %has_insert_index); declare void @kclvm_dict_remove(%kclvm_value_ref_t* %p, %kclvm_char_t* %key); -declare void @kclvm_dict_safe_insert(%kclvm_value_ref_t* %p, %kclvm_char_t* %key, %kclvm_value_ref_t* %v, %kclvm_size_t %op, %kclvm_size_t %insert_index); +declare void @kclvm_dict_safe_insert(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %p, %kclvm_char_t* %key, %kclvm_value_ref_t* %v, %kclvm_size_t %op, %kclvm_size_t %insert_index, %kclvm_bool_t %has_insert_index); -declare void @kclvm_dict_set_value(%kclvm_value_ref_t* %p, %kclvm_char_t* %key, %kclvm_value_ref_t* %val); +declare void @kclvm_dict_set_value(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %p, %kclvm_char_t* %key, %kclvm_value_ref_t* %val); declare void @kclvm_dict_update(%kclvm_value_ref_t* %p, %kclvm_value_ref_t* %v); declare void @kclvm_dict_update_key_value(%kclvm_value_ref_t* %p, %kclvm_value_ref_t* %key, %kclvm_value_ref_t* %v); -declare %kclvm_value_ref_t* @kclvm_dict_values(%kclvm_value_ref_t* %p); +declare %kclvm_value_ref_t* @kclvm_dict_values(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %p); + +declare %kclvm_value_ref_t* @kclvm_file_abs(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); + +declare %kclvm_value_ref_t* @kclvm_file_append(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); + +declare %kclvm_value_ref_t* @kclvm_file_cp(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); + +declare %kclvm_value_ref_t* @kclvm_file_current(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %_args, %kclvm_value_ref_t* %_kwargs); + +declare %kclvm_value_ref_t* @kclvm_file_delete(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); + +declare %kclvm_value_ref_t* @kclvm_file_exists(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); + +declare %kclvm_value_ref_t* @kclvm_file_glob(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); -declare void @kclvm_free(i8* %ptr); +declare %kclvm_value_ref_t* @kclvm_file_mkdir(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); + +declare %kclvm_value_ref_t* @kclvm_file_modpath(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %_args, %kclvm_value_ref_t* %_kwargs); + +declare %kclvm_value_ref_t* @kclvm_file_mv(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); + +declare %kclvm_value_ref_t* @kclvm_file_read(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); + +declare %kclvm_value_ref_t* @kclvm_file_read_env(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); + +declare %kclvm_value_ref_t* @kclvm_file_size(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); + +declare %kclvm_value_ref_t* @kclvm_file_workdir(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %_args, %kclvm_value_ref_t* %_kwargs); + +declare %kclvm_value_ref_t* @kclvm_file_write(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); declare %kclvm_value_ref_t* @kclvm_iterator_cur_key(%kclvm_iterator_t* %p); @@ -296,11 +304,13 @@ declare %kclvm_bool_t @kclvm_iterator_is_end(%kclvm_iterator_t* %p); declare %kclvm_value_ref_t* @kclvm_iterator_next_value(%kclvm_iterator_t* %p, %kclvm_value_ref_t* %host); -declare %kclvm_value_ref_t* @kclvm_json_decode(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +declare %kclvm_value_ref_t* @kclvm_json_decode(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); + +declare %kclvm_value_ref_t* @kclvm_json_dump_to_file(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); -declare %kclvm_value_ref_t* @kclvm_json_dump_to_file(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +declare %kclvm_value_ref_t* @kclvm_json_encode(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); -declare %kclvm_value_ref_t* @kclvm_json_encode(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); +declare %kclvm_value_ref_t* @kclvm_json_validate(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); declare void @kclvm_list_append(%kclvm_value_ref_t* %p, %kclvm_value_ref_t* %v); @@ -316,21 +326,21 @@ declare void @kclvm_list_append_unpack(%kclvm_value_ref_t* %p, %kclvm_value_ref_ declare void @kclvm_list_clear(%kclvm_value_ref_t* %p); -declare %kclvm_value_ref_t* @kclvm_list_count(%kclvm_value_ref_t* %p, %kclvm_value_ref_t* %item); +declare %kclvm_value_ref_t* @kclvm_list_count(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %p, %kclvm_value_ref_t* %item); -declare %kclvm_value_ref_t* @kclvm_list_find(%kclvm_value_ref_t* %p, %kclvm_value_ref_t* %item); +declare %kclvm_value_ref_t* @kclvm_list_find(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %p, %kclvm_value_ref_t* %item); -declare %kclvm_value_ref_t* @kclvm_list_get(%kclvm_value_ref_t* %p, %kclvm_size_t %i); +declare %kclvm_value_ref_t* @kclvm_list_get(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %p, %kclvm_size_t %i); -declare %kclvm_value_ref_t* @kclvm_list_get_option(%kclvm_value_ref_t* %p, %kclvm_size_t %i); +declare %kclvm_value_ref_t* @kclvm_list_get_option(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %p, %kclvm_size_t %i); declare void @kclvm_list_insert(%kclvm_value_ref_t* %p, %kclvm_value_ref_t* %index, %kclvm_value_ref_t* %value); declare %kclvm_size_t @kclvm_list_len(%kclvm_value_ref_t* %p); -declare %kclvm_value_ref_t* @kclvm_list_pop(%kclvm_value_ref_t* %p); +declare %kclvm_value_ref_t* @kclvm_list_pop(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %p); -declare %kclvm_value_ref_t* @kclvm_list_pop_first(%kclvm_value_ref_t* %p); +declare %kclvm_value_ref_t* @kclvm_list_pop_first(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %p); declare void @kclvm_list_remove_at(%kclvm_value_ref_t* %p, %kclvm_size_t %i); @@ -338,67 +348,67 @@ declare void @kclvm_list_resize(%kclvm_value_ref_t* %p, %kclvm_size_t %newsize); declare void @kclvm_list_set(%kclvm_value_ref_t* %p, %kclvm_size_t %i, %kclvm_value_ref_t* %v); -declare i8* @kclvm_malloc(i32 %n); +declare %kclvm_value_ref_t* @kclvm_manifests_yaml_stream(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); -declare %kclvm_value_ref_t* @kclvm_math_ceil(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +declare %kclvm_value_ref_t* @kclvm_math_ceil(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); -declare %kclvm_value_ref_t* @kclvm_math_exp(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +declare %kclvm_value_ref_t* @kclvm_math_exp(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); -declare %kclvm_value_ref_t* @kclvm_math_expm1(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +declare %kclvm_value_ref_t* @kclvm_math_expm1(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); -declare %kclvm_value_ref_t* @kclvm_math_factorial(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +declare %kclvm_value_ref_t* @kclvm_math_factorial(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); -declare %kclvm_value_ref_t* @kclvm_math_floor(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +declare %kclvm_value_ref_t* @kclvm_math_floor(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); -declare %kclvm_value_ref_t* @kclvm_math_gcd(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +declare %kclvm_value_ref_t* @kclvm_math_gcd(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); -declare %kclvm_value_ref_t* @kclvm_math_isfinite(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +declare %kclvm_value_ref_t* @kclvm_math_isfinite(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); -declare %kclvm_value_ref_t* @kclvm_math_isinf(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +declare %kclvm_value_ref_t* @kclvm_math_isinf(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); -declare %kclvm_value_ref_t* @kclvm_math_isnan(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +declare %kclvm_value_ref_t* @kclvm_math_isnan(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); -declare %kclvm_value_ref_t* @kclvm_math_log(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +declare %kclvm_value_ref_t* @kclvm_math_log(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); -declare %kclvm_value_ref_t* @kclvm_math_log10(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +declare %kclvm_value_ref_t* @kclvm_math_log10(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); -declare %kclvm_value_ref_t* @kclvm_math_log1p(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +declare %kclvm_value_ref_t* @kclvm_math_log1p(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); -declare %kclvm_value_ref_t* @kclvm_math_log2(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +declare %kclvm_value_ref_t* @kclvm_math_log2(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); -declare %kclvm_value_ref_t* @kclvm_math_modf(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +declare %kclvm_value_ref_t* @kclvm_math_modf(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); -declare %kclvm_value_ref_t* @kclvm_math_pow(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +declare %kclvm_value_ref_t* @kclvm_math_pow(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); -declare %kclvm_value_ref_t* @kclvm_math_sqrt(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +declare %kclvm_value_ref_t* @kclvm_math_sqrt(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); -declare %kclvm_value_ref_t* @kclvm_net_IP_string(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +declare %kclvm_value_ref_t* @kclvm_net_IP_string(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); -declare %kclvm_value_ref_t* @kclvm_net_fqdn(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +declare %kclvm_value_ref_t* @kclvm_net_fqdn(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); -declare %kclvm_value_ref_t* @kclvm_net_is_IP(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +declare %kclvm_value_ref_t* @kclvm_net_is_IP(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); -declare %kclvm_value_ref_t* @kclvm_net_is_IPv4(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +declare %kclvm_value_ref_t* @kclvm_net_is_IPv4(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); -declare %kclvm_value_ref_t* @kclvm_net_is_global_unicast_IP(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +declare %kclvm_value_ref_t* @kclvm_net_is_global_unicast_IP(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); -declare %kclvm_value_ref_t* @kclvm_net_is_interface_local_multicast_IP(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +declare %kclvm_value_ref_t* @kclvm_net_is_interface_local_multicast_IP(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); -declare %kclvm_value_ref_t* @kclvm_net_is_link_local_multicast_IP(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +declare %kclvm_value_ref_t* @kclvm_net_is_link_local_multicast_IP(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); declare %kclvm_value_ref_t* @kclvm_net_is_link_local_unicast_IP(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); -declare %kclvm_value_ref_t* @kclvm_net_is_loopback_IP(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +declare %kclvm_value_ref_t* @kclvm_net_is_loopback_IP(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); -declare %kclvm_value_ref_t* @kclvm_net_is_multicast_IP(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +declare %kclvm_value_ref_t* @kclvm_net_is_multicast_IP(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); -declare %kclvm_value_ref_t* @kclvm_net_is_unspecified_IP(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +declare %kclvm_value_ref_t* @kclvm_net_is_unspecified_IP(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); -declare %kclvm_value_ref_t* @kclvm_net_join_host_port(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +declare %kclvm_value_ref_t* @kclvm_net_join_host_port(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); declare %kclvm_value_ref_t* @kclvm_net_parse_IP(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); -declare %kclvm_value_ref_t* @kclvm_net_split_host_port(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +declare %kclvm_value_ref_t* @kclvm_net_split_host_port(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); declare %kclvm_value_ref_t* @kclvm_net_to_IP16(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); @@ -406,109 +416,55 @@ declare %kclvm_value_ref_t* @kclvm_net_to_IP4(%kclvm_context_t* %ctx, %kclvm_val declare void @kclvm_plugin_init(i8* %fn_ptr); -declare %kclvm_value_ref_t* @kclvm_plugin_invoke(i8* %method, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); +declare %kclvm_value_ref_t* @kclvm_plugin_invoke(%kclvm_context_t* %ctx, i8* %method, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); declare i8* @kclvm_plugin_invoke_json(i8* %method, i8* %args, i8* %kwargs); -declare %kclvm_value_ref_t* @kclvm_regex_compile(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +declare %kclvm_value_ref_t* @kclvm_regex_compile(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); -declare %kclvm_value_ref_t* @kclvm_regex_findall(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +declare %kclvm_value_ref_t* @kclvm_regex_findall(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); -declare %kclvm_value_ref_t* @kclvm_regex_match(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +declare %kclvm_value_ref_t* @kclvm_regex_match(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); -declare %kclvm_value_ref_t* @kclvm_regex_replace(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +declare %kclvm_value_ref_t* @kclvm_regex_replace(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); -declare %kclvm_value_ref_t* @kclvm_regex_search(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +declare %kclvm_value_ref_t* @kclvm_regex_search(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); -declare %kclvm_value_ref_t* @kclvm_regex_split(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +declare %kclvm_value_ref_t* @kclvm_regex_split(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); -declare void @kclvm_schema_assert(%kclvm_value_ref_t* %value, %kclvm_value_ref_t* %msg, %kclvm_value_ref_t* %config_meta); +declare %kclvm_value_ref_t* @kclvm_runtime_catch(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); -declare void @kclvm_schema_backtrack_cache(%kclvm_value_ref_t* %schema, %kclvm_value_ref_t* %cache, %kclvm_value_ref_t* %cal_map, %kclvm_char_t* %name, %kclvm_value_ref_t* %runtime_type); +declare void @kclvm_schema_assert(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %value, %kclvm_value_ref_t* %msg, %kclvm_value_ref_t* %config_meta); -declare void @kclvm_schema_default_settings(%kclvm_value_ref_t* %schema_value, %kclvm_value_ref_t* %config_value, %kclvm_char_t* %runtime_type); +declare void @kclvm_schema_backtrack_cache(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %schema, %kclvm_value_ref_t* %cache, %kclvm_value_ref_t* %cal_map, %kclvm_char_t* %name, %kclvm_value_ref_t* %runtime_type); + +declare void @kclvm_schema_default_settings(%kclvm_value_ref_t* %schema_value, %kclvm_value_ref_t* %_config_value, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs, %kclvm_char_t* %runtime_type); declare void @kclvm_schema_do_check_with_index_sign_attr(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs, i64* %check_fn_ptr, %kclvm_char_t* %attr_name); -declare %kclvm_value_ref_t* @kclvm_schema_get_value(%kclvm_value_ref_t* %p, %kclvm_char_t* %key, %kclvm_value_ref_t* %config, %kclvm_value_ref_t* %config_meta, %kclvm_value_ref_t* %cal_map, %kclvm_char_t* %target_attr, %kclvm_value_ref_t* %backtrack_level_map, %kclvm_value_ref_t* %backtrack_cache, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); +declare %kclvm_value_ref_t* @kclvm_schema_get_value(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %p, %kclvm_char_t* %key, %kclvm_value_ref_t* %config, %kclvm_value_ref_t* %config_meta, %kclvm_value_ref_t* %cal_map, %kclvm_char_t* %target_attr, %kclvm_value_ref_t* %backtrack_level_map, %kclvm_value_ref_t* %backtrack_cache, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); declare %kclvm_value_ref_t* @kclvm_schema_instances(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); -declare %kclvm_value_ref_t* @kclvm_schema_optional_check(%kclvm_value_ref_t* %p, %kclvm_value_ref_t* %v, %kclvm_char_t* %schema_name, %kclvm_value_ref_t* %config_meta); +declare void @kclvm_schema_optional_check(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %p); -declare void @kclvm_schema_value_check(%kclvm_value_ref_t* %schema_value, %kclvm_value_ref_t* %schema_config, %kclvm_value_ref_t* %_config_meta, %kclvm_char_t* %schema_name, %kclvm_value_ref_t* %index_sign_value, %kclvm_char_t* %_key_name, %kclvm_char_t* %key_type, %kclvm_char_t* %_value_type, %kclvm_bool_t %_any_other, %kclvm_bool_t %is_relaxed); +declare void @kclvm_schema_value_check(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %schema_value, %kclvm_value_ref_t* %schema_config, %kclvm_value_ref_t* %_config_meta, %kclvm_char_t* %schema_name, %kclvm_value_ref_t* %index_sign_value, %kclvm_char_t* %key_name, %kclvm_char_t* %key_type, %kclvm_char_t* %value_type, %kclvm_bool_t %_any_other); declare %kclvm_value_ref_t* @kclvm_schema_value_new(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs, %kclvm_value_ref_t* %schema_value_or_func, %kclvm_value_ref_t* %config, %kclvm_value_ref_t* %config_meta, %kclvm_char_t* %pkgpath); -declare %kclvm_size_t @kclvm_strlen(i8* %ptr); - -declare void @kclvm_testing_arguments(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %_args, %kclvm_value_ref_t* %_kwargs); +declare void @kclvm_scope_add_setter(%kclvm_context_t* %_ctx, %kclvm_eval_scope_t* %scope, i8* %pkg, i8* %name, i64* %setter); -declare void @kclvm_testing_setting_file(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %_args, %kclvm_value_ref_t* %_kwargs); +declare void @kclvm_scope_delete(%kclvm_eval_scope_t* %scope); -declare %kclvm_type_t* @kclvm_type_Any(); +declare %kclvm_value_ref_t* @kclvm_scope_get(%kclvm_context_t* %ctx, %kclvm_eval_scope_t* %scope, i8* %pkg, i8* %name, i8* %target, %kclvm_value_ref_t* %default); -declare %kclvm_type_t* @kclvm_type_Bool(); +declare %kclvm_eval_scope_t* @kclvm_scope_new(); -declare %kclvm_type_t* @kclvm_type_BoolLit(%kclvm_bool_t %v); +declare void @kclvm_scope_set(%kclvm_context_t* %_ctx, %kclvm_eval_scope_t* %scope, i8* %pkg, i8* %name, %kclvm_value_ref_t* %value); -declare %kclvm_bool_t @kclvm_type_BoolLit_value(%kclvm_type_t* %p); +declare %kclvm_value_ref_t* @kclvm_template_execute(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); -declare %kclvm_type_t* @kclvm_type_Dict(%kclvm_type_t* %key_type, %kclvm_type_t* %elem_type); - -declare %kclvm_type_t* @kclvm_type_Float(); - -declare %kclvm_type_t* @kclvm_type_FloatLit(double %v); - -declare double @kclvm_type_FloatLit_value(%kclvm_type_t* %p); - -declare %kclvm_type_t* @kclvm_type_Func(%kclvm_size_t %args_len, %kclvm_type_t** %args_types, %kclvm_type_t* %return_type); - -declare %kclvm_type_t* @kclvm_type_Int(); - -declare %kclvm_type_t* @kclvm_type_IntLit(i64 %v); - -declare i64 @kclvm_type_IntLit_value(%kclvm_type_t* %p); - -declare %kclvm_type_t* @kclvm_type_List(%kclvm_type_t* %elem_type); - -declare %kclvm_type_t* @kclvm_type_Schema(%kclvm_char_t* %name, %kclvm_char_t* %parent_name, %kclvm_bool_t %_is_relaxed, %kclvm_size_t %field_num, %kclvm_char_t** %field_names, %kclvm_type_t** %field_types); - -declare %kclvm_type_t* @kclvm_type_Str(); - -declare %kclvm_type_t* @kclvm_type_StrLit(%kclvm_char_t* %s); - -declare %kclvm_char_t* @kclvm_type_StrLit_value(%kclvm_type_t* %p); - -declare %kclvm_type_t* @kclvm_type_Union(%kclvm_size_t %n, %kclvm_type_t** %elem_types); - -declare %kclvm_size_t @kclvm_type_arg_num(%kclvm_type_t* %p); - -declare %kclvm_type_t* @kclvm_type_arg_type(%kclvm_type_t* %p, %kclvm_size_t %i); - -declare void @kclvm_type_delete(%kclvm_type_t* %p); - -declare %kclvm_type_t* @kclvm_type_elem_type(%kclvm_type_t* %p); - -declare %kclvm_type_t* @kclvm_type_key_type(%kclvm_type_t* %p); - -declare %kclvm_kind_t @kclvm_type_kind(%kclvm_type_t* %p); - -declare %kclvm_type_t* @kclvm_type_return_type(%kclvm_type_t* %p); - -declare %kclvm_char_t* @kclvm_type_schema_field_name(%kclvm_type_t* %p, %kclvm_size_t %i); - -declare %kclvm_size_t @kclvm_type_schema_field_num(%kclvm_type_t* %p); - -declare %kclvm_type_t* @kclvm_type_schema_field_type(%kclvm_type_t* %p, %kclvm_size_t %i); - -declare %kclvm_char_t* @kclvm_type_schema_name(%kclvm_type_t* %p); - -declare %kclvm_char_t* @kclvm_type_schema_parent_name(%kclvm_type_t* %p); - -declare %kclvm_bool_t @kclvm_type_schema_relaxed(%kclvm_type_t* %p); - -declare %kclvm_kind_t @kclvm_type_str(%kclvm_type_t* %p); +declare %kclvm_value_ref_t* @kclvm_template_html_escape(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); declare %kclvm_value_ref_t* @kclvm_units_to_G(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); @@ -536,205 +492,193 @@ declare %kclvm_value_ref_t* @kclvm_units_to_n(%kclvm_context_t* %ctx, %kclvm_val declare %kclvm_value_ref_t* @kclvm_units_to_u(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); -declare %kclvm_value_ref_t* @kclvm_value_Bool(%kclvm_bool_t %v); - -declare %kclvm_bool_t* @kclvm_value_Bool_ptr(%kclvm_value_ref_t* %p); - -declare %kclvm_decorator_value_t* @kclvm_value_Decorator(%kclvm_char_t* %name, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs, %kclvm_value_ref_t* %config_meta, %kclvm_char_t* %attr_name, %kclvm_value_ref_t* %config_value, %kclvm_value_ref_t* %is_schema_target); - -declare %kclvm_value_ref_t* @kclvm_value_Dict(); - -declare %kclvm_value_ref_t* @kclvm_value_False(); +declare %kclvm_value_ref_t* @kclvm_value_Bool(%kclvm_context_t* %ctx, %kclvm_bool_t %v); -declare %kclvm_value_ref_t* @kclvm_value_Float(%kclvm_float_t %v); +declare %kclvm_decorator_value_t* @kclvm_value_Decorator(%kclvm_context_t* %ctx, %kclvm_char_t* %name, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs, %kclvm_value_ref_t* %config_meta, %kclvm_char_t* %attr_name, %kclvm_value_ref_t* %config_value, %kclvm_value_ref_t* %is_schema_target); -declare %kclvm_float_t* @kclvm_value_Float_ptr(%kclvm_value_ref_t* %p); +declare %kclvm_value_ref_t* @kclvm_value_Dict(%kclvm_context_t* %ctx); -declare %kclvm_value_ref_t* @kclvm_value_Function(i64* %fn_ptr, %kclvm_value_ref_t* %closure, %kclvm_char_t* %external_name); +declare %kclvm_value_ref_t* @kclvm_value_False(%kclvm_context_t* %ctx); -declare %kclvm_value_ref_t* @kclvm_value_Function_using_ptr(i64* %fn_ptr); +declare %kclvm_value_ref_t* @kclvm_value_Float(%kclvm_context_t* %ctx, %kclvm_float_t %v); -declare %kclvm_value_ref_t* @kclvm_value_Int(%kclvm_int_t %v); +declare %kclvm_value_ref_t* @kclvm_value_Function(%kclvm_context_t* %ctx, i64* %fn_ptr, %kclvm_value_ref_t* %closure, %kclvm_char_t* %name, %kclvm_bool_t %is_external); -declare %kclvm_int_t* @kclvm_value_Int_ptr(%kclvm_value_ref_t* %p); +declare %kclvm_value_ref_t* @kclvm_value_Function_using_ptr(%kclvm_context_t* %ctx, i64* %fn_ptr, %kclvm_char_t* %name); -declare %kclvm_value_ref_t* @kclvm_value_List(); +declare %kclvm_value_ref_t* @kclvm_value_Int(%kclvm_context_t* %ctx, %kclvm_int_t %v); -declare %kclvm_value_ref_t* @kclvm_value_List10(%kclvm_value_ref_t* %v1, %kclvm_value_ref_t* %v2, %kclvm_value_ref_t* %v3, %kclvm_value_ref_t* %v4, %kclvm_value_ref_t* %v5, %kclvm_value_ref_t* %v6, %kclvm_value_ref_t* %v7, %kclvm_value_ref_t* %v8, %kclvm_value_ref_t* %v9, %kclvm_value_ref_t* %v10); +declare %kclvm_value_ref_t* @kclvm_value_List(%kclvm_context_t* %ctx); -declare %kclvm_value_ref_t* @kclvm_value_List6(%kclvm_value_ref_t* %v1, %kclvm_value_ref_t* %v2, %kclvm_value_ref_t* %v3, %kclvm_value_ref_t* %v4, %kclvm_value_ref_t* %v5, %kclvm_value_ref_t* %v6); +declare %kclvm_value_ref_t* @kclvm_value_List10(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %v1, %kclvm_value_ref_t* %v2, %kclvm_value_ref_t* %v3, %kclvm_value_ref_t* %v4, %kclvm_value_ref_t* %v5, %kclvm_value_ref_t* %v6, %kclvm_value_ref_t* %v7, %kclvm_value_ref_t* %v8, %kclvm_value_ref_t* %v9, %kclvm_value_ref_t* %v10); -declare %kclvm_value_ref_t* @kclvm_value_ListN(%kclvm_int_t %n, %kclvm_value_ref_t** %elem_values); +declare %kclvm_value_ref_t* @kclvm_value_List6(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %v1, %kclvm_value_ref_t* %v2, %kclvm_value_ref_t* %v3, %kclvm_value_ref_t* %v4, %kclvm_value_ref_t* %v5, %kclvm_value_ref_t* %v6); -declare %kclvm_value_ref_t* @kclvm_value_None(); +declare %kclvm_value_ref_t* @kclvm_value_None(%kclvm_context_t* %ctx); -declare %kclvm_value_ref_t* @kclvm_value_Schema(); +declare %kclvm_value_ref_t* @kclvm_value_Schema(%kclvm_context_t* %ctx); -declare %kclvm_value_ref_t* @kclvm_value_Str(%kclvm_char_t* %v); - -declare %kclvm_size_t @kclvm_value_Str_len(%kclvm_value_ref_t* %p); +declare %kclvm_value_ref_t* @kclvm_value_Str(%kclvm_context_t* %ctx, %kclvm_char_t* %v); declare %kclvm_char_t* @kclvm_value_Str_ptr(%kclvm_value_ref_t* %p); -declare void @kclvm_value_Str_resize(%kclvm_value_ref_t* %p, %kclvm_size_t %n); - -declare %kclvm_value_ref_t* @kclvm_value_True(); +declare %kclvm_value_ref_t* @kclvm_value_True(%kclvm_context_t* %ctx); -declare %kclvm_value_ref_t* @kclvm_value_Undefined(); +declare %kclvm_value_ref_t* @kclvm_value_Undefined(%kclvm_context_t* %ctx); -declare %kclvm_value_ref_t* @kclvm_value_Unit(%kclvm_float_t %v, %kclvm_int_t %raw, %kclvm_char_t* %unit); +declare %kclvm_value_ref_t* @kclvm_value_Unit(%kclvm_context_t* %ctx, %kclvm_float_t %v, %kclvm_int_t %raw, %kclvm_char_t* %unit); -declare %kclvm_value_ref_t* @kclvm_value_as(%kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); +declare %kclvm_value_ref_t* @kclvm_value_as(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); declare i64* @kclvm_value_check_function_ptr(%kclvm_value_ref_t* %p); -declare %kclvm_value_ref_t* @kclvm_value_cmp_equal_to(%kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); +declare %kclvm_value_ref_t* @kclvm_value_cmp_equal_to(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); -declare %kclvm_value_ref_t* @kclvm_value_cmp_greater_than(%kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); +declare %kclvm_value_ref_t* @kclvm_value_cmp_greater_than(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); -declare %kclvm_value_ref_t* @kclvm_value_cmp_greater_than_or_equal(%kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); +declare %kclvm_value_ref_t* @kclvm_value_cmp_greater_than_or_equal(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); -declare %kclvm_value_ref_t* @kclvm_value_cmp_less_than(%kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); +declare %kclvm_value_ref_t* @kclvm_value_cmp_less_than(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); -declare %kclvm_value_ref_t* @kclvm_value_cmp_less_than_or_equal(%kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); +declare %kclvm_value_ref_t* @kclvm_value_cmp_less_than_or_equal(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); -declare %kclvm_value_ref_t* @kclvm_value_cmp_not_equal_to(%kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); +declare %kclvm_value_ref_t* @kclvm_value_cmp_not_equal_to(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); -declare %kclvm_value_ref_t* @kclvm_value_deep_copy(%kclvm_value_ref_t* %p); +declare %kclvm_value_ref_t* @kclvm_value_deep_copy(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %p); declare void @kclvm_value_delete(%kclvm_value_ref_t* %p); -declare %kclvm_value_ref_t* @kclvm_value_from_json(%kclvm_char_t* %s); - -declare %kclvm_value_ref_t* @kclvm_value_function_external_invoke(%kclvm_value_ref_t* %p, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); - -declare %kclvm_value_ref_t* @kclvm_value_function_get_closure(%kclvm_value_ref_t* %p); - -declare %kclvm_value_ref_t* @kclvm_value_function_invoke(%kclvm_value_ref_t* %p, %kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs, %kclvm_char_t* %pkgpath); +declare %kclvm_value_ref_t* @kclvm_value_from_json(%kclvm_context_t* %ctx, %kclvm_char_t* %s); -declare %kclvm_bool_t @kclvm_value_function_is_external(%kclvm_value_ref_t* %p); +declare %kclvm_value_ref_t* @kclvm_value_function_invoke(%kclvm_value_ref_t* %p, %kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs, %kclvm_char_t* %pkgpath, %kclvm_value_ref_t* %is_in_schema); declare i64* @kclvm_value_function_ptr(%kclvm_value_ref_t* %p); -declare %kclvm_value_ref_t* @kclvm_value_in(%kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); +declare %kclvm_value_ref_t* @kclvm_value_in(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); -declare %kclvm_value_ref_t* @kclvm_value_is(%kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); +declare %kclvm_value_ref_t* @kclvm_value_is(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); -declare %kclvm_value_ref_t* @kclvm_value_is_not(%kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); +declare %kclvm_value_ref_t* @kclvm_value_is_not(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); declare %kclvm_bool_t @kclvm_value_is_truthy(%kclvm_value_ref_t* %p); declare %kclvm_iterator_t* @kclvm_value_iter(%kclvm_value_ref_t* %p); -declare %kclvm_kind_t @kclvm_value_kind(%kclvm_value_ref_t* %p); - declare %kclvm_size_t @kclvm_value_len(%kclvm_value_ref_t* %p); -declare %kclvm_value_ref_t* @kclvm_value_load_attr(%kclvm_value_ref_t* %obj, %kclvm_char_t* %key); +declare %kclvm_value_ref_t* @kclvm_value_load_attr(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %obj, %kclvm_char_t* %key); -declare %kclvm_value_ref_t* @kclvm_value_load_attr_option(%kclvm_value_ref_t* %p, %kclvm_char_t* %key); +declare %kclvm_value_ref_t* @kclvm_value_load_attr_option(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %p, %kclvm_char_t* %key); -declare %kclvm_value_ref_t* @kclvm_value_logic_and(%kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); +declare %kclvm_value_ref_t* @kclvm_value_logic_and(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); -declare %kclvm_value_ref_t* @kclvm_value_logic_or(%kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); +declare %kclvm_value_ref_t* @kclvm_value_logic_or(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); -declare %kclvm_value_ref_t* @kclvm_value_not_in(%kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); +declare %kclvm_value_ref_t* @kclvm_value_not_in(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); -declare %kclvm_value_ref_t* @kclvm_value_op_add(%kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); +declare %kclvm_value_ref_t* @kclvm_value_op_add(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); -declare %kclvm_value_ref_t* @kclvm_value_op_aug_add(%kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); +declare %kclvm_value_ref_t* @kclvm_value_op_aug_add(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); -declare %kclvm_value_ref_t* @kclvm_value_op_aug_bit_and(%kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); +declare %kclvm_value_ref_t* @kclvm_value_op_aug_bit_and(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); -declare %kclvm_value_ref_t* @kclvm_value_op_aug_bit_lshift(%kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); +declare %kclvm_value_ref_t* @kclvm_value_op_aug_bit_lshift(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); -declare %kclvm_value_ref_t* @kclvm_value_op_aug_bit_or(%kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); +declare %kclvm_value_ref_t* @kclvm_value_op_aug_bit_or(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); -declare %kclvm_value_ref_t* @kclvm_value_op_aug_bit_rshift(%kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); +declare %kclvm_value_ref_t* @kclvm_value_op_aug_bit_rshift(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); -declare %kclvm_value_ref_t* @kclvm_value_op_aug_bit_xor(%kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); +declare %kclvm_value_ref_t* @kclvm_value_op_aug_bit_xor(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); -declare %kclvm_value_ref_t* @kclvm_value_op_aug_div(%kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); +declare %kclvm_value_ref_t* @kclvm_value_op_aug_div(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); -declare %kclvm_value_ref_t* @kclvm_value_op_aug_floor_div(%kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); +declare %kclvm_value_ref_t* @kclvm_value_op_aug_floor_div(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); -declare %kclvm_value_ref_t* @kclvm_value_op_aug_mod(%kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); +declare %kclvm_value_ref_t* @kclvm_value_op_aug_mod(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); -declare %kclvm_value_ref_t* @kclvm_value_op_aug_mul(%kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); +declare %kclvm_value_ref_t* @kclvm_value_op_aug_mul(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); -declare %kclvm_value_ref_t* @kclvm_value_op_aug_pow(%kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); +declare %kclvm_value_ref_t* @kclvm_value_op_aug_pow(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); -declare %kclvm_value_ref_t* @kclvm_value_op_aug_sub(%kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); +declare %kclvm_value_ref_t* @kclvm_value_op_aug_sub(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); -declare %kclvm_value_ref_t* @kclvm_value_op_bit_and(%kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); +declare %kclvm_value_ref_t* @kclvm_value_op_bit_and(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); -declare %kclvm_value_ref_t* @kclvm_value_op_bit_lshift(%kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); +declare %kclvm_value_ref_t* @kclvm_value_op_bit_lshift(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); -declare %kclvm_value_ref_t* @kclvm_value_op_bit_or(%kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); +declare %kclvm_value_ref_t* @kclvm_value_op_bit_or(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); -declare %kclvm_value_ref_t* @kclvm_value_op_bit_rshift(%kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); +declare %kclvm_value_ref_t* @kclvm_value_op_bit_rshift(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); -declare %kclvm_value_ref_t* @kclvm_value_op_bit_xor(%kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); +declare %kclvm_value_ref_t* @kclvm_value_op_bit_xor(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); -declare %kclvm_value_ref_t* @kclvm_value_op_div(%kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); +declare %kclvm_value_ref_t* @kclvm_value_op_div(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); -declare %kclvm_value_ref_t* @kclvm_value_op_floor_div(%kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); +declare %kclvm_value_ref_t* @kclvm_value_op_floor_div(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); -declare %kclvm_value_ref_t* @kclvm_value_op_mod(%kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); +declare %kclvm_value_ref_t* @kclvm_value_op_mod(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); -declare %kclvm_value_ref_t* @kclvm_value_op_mul(%kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); +declare %kclvm_value_ref_t* @kclvm_value_op_mul(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); -declare %kclvm_value_ref_t* @kclvm_value_op_pow(%kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); +declare %kclvm_value_ref_t* @kclvm_value_op_pow(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); -declare %kclvm_value_ref_t* @kclvm_value_op_sub(%kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); +declare %kclvm_value_ref_t* @kclvm_value_op_sub(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); -declare %kclvm_value_ref_t* @kclvm_value_plan_to_json(%kclvm_value_ref_t* %p); +declare %kclvm_value_ref_t* @kclvm_value_plan_to_json(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %p); -declare %kclvm_value_ref_t* @kclvm_value_plan_to_yaml(%kclvm_value_ref_t* %p); +declare %kclvm_value_ref_t* @kclvm_value_plan_to_yaml(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %p); declare void @kclvm_value_remove_item(%kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); -declare %kclvm_value_ref_t* @kclvm_value_schema_function(i64* %fn_ptr, i64* %check_fn_ptr, %kclvm_char_t* %tpe); +declare %kclvm_value_ref_t* @kclvm_value_schema_function(%kclvm_context_t* %ctx, i64* %fn_ptr, i64* %check_fn_ptr, %kclvm_value_ref_t* %attr_map, %kclvm_char_t* %tpe); + +declare %kclvm_value_ref_t* @kclvm_value_schema_with_config(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %schema_dict, %kclvm_value_ref_t* %config, %kclvm_value_ref_t* %config_meta, %kclvm_char_t* %name, %kclvm_char_t* %pkgpath, %kclvm_value_ref_t* %is_sub_schema, %kclvm_value_ref_t* %record_instance, %kclvm_value_ref_t* %instance_pkgpath, %kclvm_value_ref_t* %optional_mapping, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); + +declare %kclvm_value_ref_t* @kclvm_value_slice(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %x, %kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b, %kclvm_value_ref_t* %step); + +declare %kclvm_value_ref_t* @kclvm_value_slice_option(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %x, %kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b, %kclvm_value_ref_t* %step); + +declare %kclvm_value_ref_t* @kclvm_value_subscr(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); -declare %kclvm_value_ref_t* @kclvm_value_schema_with_config(%kclvm_value_ref_t* %schema_dict, %kclvm_value_ref_t* %config, %kclvm_char_t* %name, %kclvm_char_t* %pkgpath, %kclvm_value_ref_t* %is_sub_schema, %kclvm_value_ref_t* %record_instance, %kclvm_value_ref_t* %instance_pkgpath); +declare %kclvm_value_ref_t* @kclvm_value_subscr_option(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); -declare %kclvm_value_ref_t* @kclvm_value_slice(%kclvm_value_ref_t* %x, %kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b, %kclvm_value_ref_t* %step); +declare void @kclvm_value_subscr_set(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %p, %kclvm_value_ref_t* %index, %kclvm_value_ref_t* %val); -declare %kclvm_value_ref_t* @kclvm_value_slice_option(%kclvm_value_ref_t* %x, %kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b, %kclvm_value_ref_t* %step); +declare %kclvm_value_ref_t* @kclvm_value_to_json_value(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %p); -declare %kclvm_value_ref_t* @kclvm_value_subscr(%kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); +declare %kclvm_value_ref_t* @kclvm_value_to_json_value_with_null(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %p); -declare %kclvm_value_ref_t* @kclvm_value_subscr_option(%kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); +declare %kclvm_value_ref_t* @kclvm_value_to_str_value(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %p); -declare %kclvm_buffer_t* @kclvm_value_to_json(%kclvm_value_ref_t* %p); +declare %kclvm_value_ref_t* @kclvm_value_to_yaml_value(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %p); -declare %kclvm_value_ref_t* @kclvm_value_to_json_value(%kclvm_value_ref_t* %p); +declare %kclvm_value_ref_t* @kclvm_value_unary_l_not(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %a); -declare %kclvm_value_ref_t* @kclvm_value_to_json_value_with_null(%kclvm_value_ref_t* %p); +declare %kclvm_value_ref_t* @kclvm_value_unary_minus(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %a); -declare %kclvm_value_ref_t* @kclvm_value_to_str_value(%kclvm_value_ref_t* %p); +declare %kclvm_value_ref_t* @kclvm_value_unary_not(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %a); -declare %kclvm_value_ref_t* @kclvm_value_to_yaml_value(%kclvm_value_ref_t* %p); +declare %kclvm_value_ref_t* @kclvm_value_unary_plus(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %a); -declare %kclvm_value_ref_t* @kclvm_value_unary_l_not(%kclvm_value_ref_t* %a); +declare %kclvm_value_ref_t* @kclvm_value_union(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %schema, %kclvm_value_ref_t* %b); -declare %kclvm_value_ref_t* @kclvm_value_unary_minus(%kclvm_value_ref_t* %a); +declare %kclvm_value_ref_t* @kclvm_value_union_all(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); -declare %kclvm_value_ref_t* @kclvm_value_unary_not(%kclvm_value_ref_t* %a); +declare %kclvm_value_ref_t* @kclvm_yaml_decode(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); -declare %kclvm_value_ref_t* @kclvm_value_unary_plus(%kclvm_value_ref_t* %a); +declare %kclvm_value_ref_t* @kclvm_yaml_decode_all(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); -declare %kclvm_value_ref_t* @kclvm_value_union(%kclvm_value_ref_t* %schema, %kclvm_value_ref_t* %b); +declare %kclvm_value_ref_t* @kclvm_yaml_dump_all_to_file(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); -declare %kclvm_value_ref_t* @kclvm_value_union_all(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +declare %kclvm_value_ref_t* @kclvm_yaml_dump_to_file(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); -declare %kclvm_value_ref_t* @kclvm_yaml_decode(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +declare %kclvm_value_ref_t* @kclvm_yaml_encode(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); -declare %kclvm_value_ref_t* @kclvm_yaml_dump_to_file(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +declare %kclvm_value_ref_t* @kclvm_yaml_encode_all(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); -declare %kclvm_value_ref_t* @kclvm_yaml_encode(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); +declare %kclvm_value_ref_t* @kclvm_yaml_validate(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); define void @__kcl_keep_link_runtime(%kclvm_value_ref_t* %_a, %kclvm_context_t* %_b) { - call %kclvm_value_ref_t*() @kclvm_value_None() - ret void + call %kclvm_value_ref_t* @kclvm_value_None(%kclvm_context_t* %_b) + ret void } diff --git a/kclvm/runtime/src/_kclvm.rs b/kclvm/runtime/src/_kclvm.rs index 17da328eb..983d44a48 100644 --- a/kclvm/runtime/src/_kclvm.rs +++ b/kclvm/runtime/src/_kclvm.rs @@ -1,4 +1,4 @@ -// Copyright 2021 The KCL Authors. All rights reserved. +// Copyright The KCL Authors. All rights reserved. // Auto generated, DONOT EDIT!!! @@ -19,7 +19,7 @@ impl std::fmt::Display for ApiType { impl ApiType { #[allow(dead_code)] pub fn name(&self) -> String { - return format!("{:?}", self); + format!("{self:?}") } } @@ -29,10 +29,6 @@ pub enum ApiFunc { kclvm_assert, kclvm_base64_decode, kclvm_base64_encode, - kclvm_buffer_data, - kclvm_buffer_delete, - kclvm_buffer_new, - kclvm_buffer_size, kclvm_builtin_abs, kclvm_builtin_all_true, kclvm_builtin_any_true, @@ -42,6 +38,7 @@ pub enum ApiFunc { kclvm_builtin_float, kclvm_builtin_hex, kclvm_builtin_int, + kclvm_builtin_isnullish, kclvm_builtin_isunique, kclvm_builtin_len, kclvm_builtin_list, @@ -60,6 +57,7 @@ pub enum ApiFunc { kclvm_builtin_sorted, kclvm_builtin_str, kclvm_builtin_str_capitalize, + kclvm_builtin_str_chars, kclvm_builtin_str_count, kclvm_builtin_str_endswith, kclvm_builtin_str_find, @@ -75,6 +73,8 @@ pub enum ApiFunc { kclvm_builtin_str_join, kclvm_builtin_str_lower, kclvm_builtin_str_lstrip, + kclvm_builtin_str_removeprefix, + kclvm_builtin_str_removesuffix, kclvm_builtin_str_replace, kclvm_builtin_str_rfind, kclvm_builtin_str_rindex, @@ -90,18 +90,10 @@ pub enum ApiFunc { kclvm_builtin_typeof, kclvm_builtin_zip, kclvm_config_attr_map, - kclvm_context_args_clear, - kclvm_context_args_get, - kclvm_context_args_set, - kclvm_context_clear_all_types, - kclvm_context_current, kclvm_context_delete, kclvm_context_invoke, - kclvm_context_main_begin_hook, - kclvm_context_main_end_hook, kclvm_context_new, kclvm_context_pkgpath_is_imported, - kclvm_context_put_type, kclvm_context_set_debug_mode, kclvm_context_set_disable_none, kclvm_context_set_disable_schema_check, @@ -109,31 +101,27 @@ pub enum ApiFunc { kclvm_context_set_kcl_filename, kclvm_context_set_kcl_line_col, kclvm_context_set_kcl_location, + kclvm_context_set_kcl_modpath, kclvm_context_set_kcl_pkgpath, - kclvm_context_set_list_option_mode, + kclvm_context_set_kcl_workdir, kclvm_context_set_strict_range_check, - kclvm_context_symbol_init, - kclvm_context_symbol_name, - kclvm_context_symbol_num, - kclvm_context_symbol_value, kclvm_convert_collection_value, + kclvm_crypto_blake3, + kclvm_crypto_fileblake3, + kclvm_crypto_filesha256, + kclvm_crypto_filesha512, kclvm_crypto_md5, kclvm_crypto_sha1, kclvm_crypto_sha224, kclvm_crypto_sha256, kclvm_crypto_sha384, kclvm_crypto_sha512, + kclvm_crypto_uuid, kclvm_datetime_date, kclvm_datetime_now, kclvm_datetime_ticks, kclvm_datetime_today, - kclvm_debug_hello, - kclvm_debug_invoke_func, - kclvm_debug_print, - kclvm_debug_print_str_list, - kclvm_debug_print_type, - kclvm_debug_print_value, - kclvm_debug_print_value_json_string, + kclvm_datetime_validate, kclvm_default_collection_insert_int_pointer, kclvm_default_collection_insert_value, kclvm_dict_clear, @@ -145,6 +133,7 @@ pub enum ApiFunc { kclvm_dict_insert, kclvm_dict_insert_unpack, kclvm_dict_insert_value, + kclvm_dict_is_override_attr, kclvm_dict_keys, kclvm_dict_len, kclvm_dict_merge, @@ -154,7 +143,21 @@ pub enum ApiFunc { kclvm_dict_update, kclvm_dict_update_key_value, kclvm_dict_values, - kclvm_free, + kclvm_file_abs, + kclvm_file_append, + kclvm_file_cp, + kclvm_file_current, + kclvm_file_delete, + kclvm_file_exists, + kclvm_file_glob, + kclvm_file_mkdir, + kclvm_file_modpath, + kclvm_file_mv, + kclvm_file_read, + kclvm_file_read_env, + kclvm_file_size, + kclvm_file_workdir, + kclvm_file_write, kclvm_iterator_cur_key, kclvm_iterator_cur_value, kclvm_iterator_delete, @@ -163,6 +166,7 @@ pub enum ApiFunc { kclvm_json_decode, kclvm_json_dump_to_file, kclvm_json_encode, + kclvm_json_validate, kclvm_list_append, kclvm_list_append_bool, kclvm_list_append_float, @@ -181,7 +185,7 @@ pub enum ApiFunc { kclvm_list_remove_at, kclvm_list_resize, kclvm_list_set, - kclvm_malloc, + kclvm_manifests_yaml_stream, kclvm_math_ceil, kclvm_math_exp, kclvm_math_expm1, @@ -223,6 +227,7 @@ pub enum ApiFunc { kclvm_regex_replace, kclvm_regex_search, kclvm_regex_split, + kclvm_runtime_catch, kclvm_schema_assert, kclvm_schema_backtrack_cache, kclvm_schema_default_settings, @@ -232,41 +237,13 @@ pub enum ApiFunc { kclvm_schema_optional_check, kclvm_schema_value_check, kclvm_schema_value_new, - kclvm_strlen, - kclvm_testing_arguments, - kclvm_testing_setting_file, - kclvm_type_Any, - kclvm_type_Bool, - kclvm_type_BoolLit, - kclvm_type_BoolLit_value, - kclvm_type_Dict, - kclvm_type_Float, - kclvm_type_FloatLit, - kclvm_type_FloatLit_value, - kclvm_type_Func, - kclvm_type_Int, - kclvm_type_IntLit, - kclvm_type_IntLit_value, - kclvm_type_List, - kclvm_type_Schema, - kclvm_type_Str, - kclvm_type_StrLit, - kclvm_type_StrLit_value, - kclvm_type_Union, - kclvm_type_arg_num, - kclvm_type_arg_type, - kclvm_type_delete, - kclvm_type_elem_type, - kclvm_type_key_type, - kclvm_type_kind, - kclvm_type_return_type, - kclvm_type_schema_field_name, - kclvm_type_schema_field_num, - kclvm_type_schema_field_type, - kclvm_type_schema_name, - kclvm_type_schema_parent_name, - kclvm_type_schema_relaxed, - kclvm_type_str, + kclvm_scope_add_setter, + kclvm_scope_delete, + kclvm_scope_get, + kclvm_scope_new, + kclvm_scope_set, + kclvm_template_execute, + kclvm_template_html_escape, kclvm_units_to_G, kclvm_units_to_Gi, kclvm_units_to_K, @@ -281,26 +258,20 @@ pub enum ApiFunc { kclvm_units_to_n, kclvm_units_to_u, kclvm_value_Bool, - kclvm_value_Bool_ptr, kclvm_value_Decorator, kclvm_value_Dict, kclvm_value_False, kclvm_value_Float, - kclvm_value_Float_ptr, kclvm_value_Function, kclvm_value_Function_using_ptr, kclvm_value_Int, - kclvm_value_Int_ptr, kclvm_value_List, kclvm_value_List10, kclvm_value_List6, - kclvm_value_ListN, kclvm_value_None, kclvm_value_Schema, kclvm_value_Str, - kclvm_value_Str_len, kclvm_value_Str_ptr, - kclvm_value_Str_resize, kclvm_value_True, kclvm_value_Undefined, kclvm_value_Unit, @@ -315,17 +286,13 @@ pub enum ApiFunc { kclvm_value_deep_copy, kclvm_value_delete, kclvm_value_from_json, - kclvm_value_function_external_invoke, - kclvm_value_function_get_closure, kclvm_value_function_invoke, - kclvm_value_function_is_external, kclvm_value_function_ptr, kclvm_value_in, kclvm_value_is, kclvm_value_is_not, kclvm_value_is_truthy, kclvm_value_iter, - kclvm_value_kind, kclvm_value_len, kclvm_value_load_attr, kclvm_value_load_attr_option, @@ -365,7 +332,7 @@ pub enum ApiFunc { kclvm_value_slice_option, kclvm_value_subscr, kclvm_value_subscr_option, - kclvm_value_to_json, + kclvm_value_subscr_set, kclvm_value_to_json_value, kclvm_value_to_json_value_with_null, kclvm_value_to_str_value, @@ -377,19 +344,23 @@ pub enum ApiFunc { kclvm_value_union, kclvm_value_union_all, kclvm_yaml_decode, + kclvm_yaml_decode_all, + kclvm_yaml_dump_all_to_file, kclvm_yaml_dump_to_file, kclvm_yaml_encode, + kclvm_yaml_encode_all, + kclvm_yaml_validate, } impl std::fmt::Display for ApiFunc { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - write!(f, "{:?}", self) + write!(f, "{self:?}") } } impl ApiFunc { #[allow(dead_code)] pub fn name(&self) -> String { - return format!("{:?}", self); + format!("{self:?}") } } diff --git a/kclvm/runtime/src/_kclvm_addr.rs b/kclvm/runtime/src/_kclvm_addr.rs index b0687ed84..5824c87ad 100644 --- a/kclvm/runtime/src/_kclvm_addr.rs +++ b/kclvm/runtime/src/_kclvm_addr.rs @@ -1,4 +1,4 @@ -// Copyright 2021 The KCL Authors. All rights reserved. +// Copyright The KCL Authors. All rights reserved. // Auto generated, DONOT EDIT!!! @@ -8,10 +8,6 @@ pub fn _kclvm_get_fn_ptr_by_name(name: &str) -> u64 { "kclvm_assert" => crate::kclvm_assert as *const () as u64, "kclvm_base64_decode" => crate::kclvm_base64_decode as *const () as u64, "kclvm_base64_encode" => crate::kclvm_base64_encode as *const () as u64, - "kclvm_buffer_data" => crate::kclvm_buffer_data as *const () as u64, - "kclvm_buffer_delete" => crate::kclvm_buffer_delete as *const () as u64, - "kclvm_buffer_new" => crate::kclvm_buffer_new as *const () as u64, - "kclvm_buffer_size" => crate::kclvm_buffer_size as *const () as u64, "kclvm_builtin_abs" => crate::kclvm_builtin_abs as *const () as u64, "kclvm_builtin_all_true" => crate::kclvm_builtin_all_true as *const () as u64, "kclvm_builtin_any_true" => crate::kclvm_builtin_any_true as *const () as u64, @@ -21,6 +17,7 @@ pub fn _kclvm_get_fn_ptr_by_name(name: &str) -> u64 { "kclvm_builtin_float" => crate::kclvm_builtin_float as *const () as u64, "kclvm_builtin_hex" => crate::kclvm_builtin_hex as *const () as u64, "kclvm_builtin_int" => crate::kclvm_builtin_int as *const () as u64, + "kclvm_builtin_isnullish" => crate::kclvm_builtin_isnullish as *const () as u64, "kclvm_builtin_isunique" => crate::kclvm_builtin_isunique as *const () as u64, "kclvm_builtin_len" => crate::kclvm_builtin_len as *const () as u64, "kclvm_builtin_list" => crate::kclvm_builtin_list as *const () as u64, @@ -39,6 +36,7 @@ pub fn _kclvm_get_fn_ptr_by_name(name: &str) -> u64 { "kclvm_builtin_sorted" => crate::kclvm_builtin_sorted as *const () as u64, "kclvm_builtin_str" => crate::kclvm_builtin_str as *const () as u64, "kclvm_builtin_str_capitalize" => crate::kclvm_builtin_str_capitalize as *const () as u64, + "kclvm_builtin_str_chars" => crate::kclvm_builtin_str_chars as *const () as u64, "kclvm_builtin_str_count" => crate::kclvm_builtin_str_count as *const () as u64, "kclvm_builtin_str_endswith" => crate::kclvm_builtin_str_endswith as *const () as u64, "kclvm_builtin_str_find" => crate::kclvm_builtin_str_find as *const () as u64, @@ -54,6 +52,12 @@ pub fn _kclvm_get_fn_ptr_by_name(name: &str) -> u64 { "kclvm_builtin_str_join" => crate::kclvm_builtin_str_join as *const () as u64, "kclvm_builtin_str_lower" => crate::kclvm_builtin_str_lower as *const () as u64, "kclvm_builtin_str_lstrip" => crate::kclvm_builtin_str_lstrip as *const () as u64, + "kclvm_builtin_str_removeprefix" => { + crate::kclvm_builtin_str_removeprefix as *const () as u64 + } + "kclvm_builtin_str_removesuffix" => { + crate::kclvm_builtin_str_removesuffix as *const () as u64 + } "kclvm_builtin_str_replace" => crate::kclvm_builtin_str_replace as *const () as u64, "kclvm_builtin_str_rfind" => crate::kclvm_builtin_str_rfind as *const () as u64, "kclvm_builtin_str_rindex" => crate::kclvm_builtin_str_rindex as *const () as u64, @@ -69,20 +73,12 @@ pub fn _kclvm_get_fn_ptr_by_name(name: &str) -> u64 { "kclvm_builtin_typeof" => crate::kclvm_builtin_typeof as *const () as u64, "kclvm_builtin_zip" => crate::kclvm_builtin_zip as *const () as u64, "kclvm_config_attr_map" => crate::kclvm_config_attr_map as *const () as u64, - "kclvm_context_args_clear" => crate::kclvm_context_args_clear as *const () as u64, - "kclvm_context_args_get" => crate::kclvm_context_args_get as *const () as u64, - "kclvm_context_args_set" => crate::kclvm_context_args_set as *const () as u64, - "kclvm_context_clear_all_types" => crate::kclvm_context_clear_all_types as *const () as u64, - "kclvm_context_current" => crate::kclvm_context_current as *const () as u64, "kclvm_context_delete" => crate::kclvm_context_delete as *const () as u64, "kclvm_context_invoke" => crate::kclvm_context_invoke as *const () as u64, - "kclvm_context_main_begin_hook" => crate::kclvm_context_main_begin_hook as *const () as u64, - "kclvm_context_main_end_hook" => crate::kclvm_context_main_end_hook as *const () as u64, "kclvm_context_new" => crate::kclvm_context_new as *const () as u64, "kclvm_context_pkgpath_is_imported" => { crate::kclvm_context_pkgpath_is_imported as *const () as u64 } - "kclvm_context_put_type" => crate::kclvm_context_put_type as *const () as u64, "kclvm_context_set_debug_mode" => crate::kclvm_context_set_debug_mode as *const () as u64, "kclvm_context_set_disable_none" => { crate::kclvm_context_set_disable_none as *const () as u64 @@ -102,39 +98,31 @@ pub fn _kclvm_get_fn_ptr_by_name(name: &str) -> u64 { "kclvm_context_set_kcl_location" => { crate::kclvm_context_set_kcl_location as *const () as u64 } + "kclvm_context_set_kcl_modpath" => crate::kclvm_context_set_kcl_modpath as *const () as u64, "kclvm_context_set_kcl_pkgpath" => crate::kclvm_context_set_kcl_pkgpath as *const () as u64, - "kclvm_context_set_list_option_mode" => { - crate::kclvm_context_set_list_option_mode as *const () as u64 - } + "kclvm_context_set_kcl_workdir" => crate::kclvm_context_set_kcl_workdir as *const () as u64, "kclvm_context_set_strict_range_check" => { crate::kclvm_context_set_strict_range_check as *const () as u64 } - "kclvm_context_symbol_init" => crate::kclvm_context_symbol_init as *const () as u64, - "kclvm_context_symbol_name" => crate::kclvm_context_symbol_name as *const () as u64, - "kclvm_context_symbol_num" => crate::kclvm_context_symbol_num as *const () as u64, - "kclvm_context_symbol_value" => crate::kclvm_context_symbol_value as *const () as u64, "kclvm_convert_collection_value" => { crate::kclvm_convert_collection_value as *const () as u64 } + "kclvm_crypto_blake3" => crate::kclvm_crypto_blake3 as *const () as u64, + "kclvm_crypto_fileblake3" => crate::kclvm_crypto_fileblake3 as *const () as u64, + "kclvm_crypto_filesha256" => crate::kclvm_crypto_filesha256 as *const () as u64, + "kclvm_crypto_filesha512" => crate::kclvm_crypto_filesha512 as *const () as u64, "kclvm_crypto_md5" => crate::kclvm_crypto_md5 as *const () as u64, "kclvm_crypto_sha1" => crate::kclvm_crypto_sha1 as *const () as u64, "kclvm_crypto_sha224" => crate::kclvm_crypto_sha224 as *const () as u64, "kclvm_crypto_sha256" => crate::kclvm_crypto_sha256 as *const () as u64, "kclvm_crypto_sha384" => crate::kclvm_crypto_sha384 as *const () as u64, "kclvm_crypto_sha512" => crate::kclvm_crypto_sha512 as *const () as u64, + "kclvm_crypto_uuid" => crate::kclvm_crypto_uuid as *const () as u64, "kclvm_datetime_date" => crate::kclvm_datetime_date as *const () as u64, "kclvm_datetime_now" => crate::kclvm_datetime_now as *const () as u64, "kclvm_datetime_ticks" => crate::kclvm_datetime_ticks as *const () as u64, "kclvm_datetime_today" => crate::kclvm_datetime_today as *const () as u64, - "kclvm_debug_hello" => crate::kclvm_debug_hello as *const () as u64, - "kclvm_debug_invoke_func" => crate::kclvm_debug_invoke_func as *const () as u64, - "kclvm_debug_print" => crate::kclvm_debug_print as *const () as u64, - "kclvm_debug_print_str_list" => crate::kclvm_debug_print_str_list as *const () as u64, - "kclvm_debug_print_type" => crate::kclvm_debug_print_type as *const () as u64, - "kclvm_debug_print_value" => crate::kclvm_debug_print_value as *const () as u64, - "kclvm_debug_print_value_json_string" => { - crate::kclvm_debug_print_value_json_string as *const () as u64 - } + "kclvm_datetime_validate" => crate::kclvm_datetime_validate as *const () as u64, "kclvm_default_collection_insert_int_pointer" => { crate::kclvm_default_collection_insert_int_pointer as *const () as u64 } @@ -150,6 +138,7 @@ pub fn _kclvm_get_fn_ptr_by_name(name: &str) -> u64 { "kclvm_dict_insert" => crate::kclvm_dict_insert as *const () as u64, "kclvm_dict_insert_unpack" => crate::kclvm_dict_insert_unpack as *const () as u64, "kclvm_dict_insert_value" => crate::kclvm_dict_insert_value as *const () as u64, + "kclvm_dict_is_override_attr" => crate::kclvm_dict_is_override_attr as *const () as u64, "kclvm_dict_keys" => crate::kclvm_dict_keys as *const () as u64, "kclvm_dict_len" => crate::kclvm_dict_len as *const () as u64, "kclvm_dict_merge" => crate::kclvm_dict_merge as *const () as u64, @@ -159,7 +148,21 @@ pub fn _kclvm_get_fn_ptr_by_name(name: &str) -> u64 { "kclvm_dict_update" => crate::kclvm_dict_update as *const () as u64, "kclvm_dict_update_key_value" => crate::kclvm_dict_update_key_value as *const () as u64, "kclvm_dict_values" => crate::kclvm_dict_values as *const () as u64, - "kclvm_free" => crate::kclvm_free as *const () as u64, + "kclvm_file_abs" => crate::kclvm_file_abs as *const () as u64, + "kclvm_file_append" => crate::kclvm_file_append as *const () as u64, + "kclvm_file_cp" => crate::kclvm_file_cp as *const () as u64, + "kclvm_file_current" => crate::kclvm_file_current as *const () as u64, + "kclvm_file_delete" => crate::kclvm_file_delete as *const () as u64, + "kclvm_file_exists" => crate::kclvm_file_exists as *const () as u64, + "kclvm_file_glob" => crate::kclvm_file_glob as *const () as u64, + "kclvm_file_mkdir" => crate::kclvm_file_mkdir as *const () as u64, + "kclvm_file_modpath" => crate::kclvm_file_modpath as *const () as u64, + "kclvm_file_mv" => crate::kclvm_file_mv as *const () as u64, + "kclvm_file_read" => crate::kclvm_file_read as *const () as u64, + "kclvm_file_read_env" => crate::kclvm_file_read_env as *const () as u64, + "kclvm_file_size" => crate::kclvm_file_size as *const () as u64, + "kclvm_file_workdir" => crate::kclvm_file_workdir as *const () as u64, + "kclvm_file_write" => crate::kclvm_file_write as *const () as u64, "kclvm_iterator_cur_key" => crate::kclvm_iterator_cur_key as *const () as u64, "kclvm_iterator_cur_value" => crate::kclvm_iterator_cur_value as *const () as u64, "kclvm_iterator_delete" => crate::kclvm_iterator_delete as *const () as u64, @@ -168,6 +171,7 @@ pub fn _kclvm_get_fn_ptr_by_name(name: &str) -> u64 { "kclvm_json_decode" => crate::kclvm_json_decode as *const () as u64, "kclvm_json_dump_to_file" => crate::kclvm_json_dump_to_file as *const () as u64, "kclvm_json_encode" => crate::kclvm_json_encode as *const () as u64, + "kclvm_json_validate" => crate::kclvm_json_validate as *const () as u64, "kclvm_list_append" => crate::kclvm_list_append as *const () as u64, "kclvm_list_append_bool" => crate::kclvm_list_append_bool as *const () as u64, "kclvm_list_append_float" => crate::kclvm_list_append_float as *const () as u64, @@ -186,7 +190,7 @@ pub fn _kclvm_get_fn_ptr_by_name(name: &str) -> u64 { "kclvm_list_remove_at" => crate::kclvm_list_remove_at as *const () as u64, "kclvm_list_resize" => crate::kclvm_list_resize as *const () as u64, "kclvm_list_set" => crate::kclvm_list_set as *const () as u64, - "kclvm_malloc" => crate::kclvm_malloc as *const () as u64, + "kclvm_manifests_yaml_stream" => crate::kclvm_manifests_yaml_stream as *const () as u64, "kclvm_math_ceil" => crate::kclvm_math_ceil as *const () as u64, "kclvm_math_exp" => crate::kclvm_math_exp as *const () as u64, "kclvm_math_expm1" => crate::kclvm_math_expm1 as *const () as u64, @@ -236,6 +240,7 @@ pub fn _kclvm_get_fn_ptr_by_name(name: &str) -> u64 { "kclvm_regex_replace" => crate::kclvm_regex_replace as *const () as u64, "kclvm_regex_search" => crate::kclvm_regex_search as *const () as u64, "kclvm_regex_split" => crate::kclvm_regex_split as *const () as u64, + "kclvm_runtime_catch" => crate::kclvm_runtime_catch as *const () as u64, "kclvm_schema_assert" => crate::kclvm_schema_assert as *const () as u64, "kclvm_schema_backtrack_cache" => crate::kclvm_schema_backtrack_cache as *const () as u64, "kclvm_schema_default_settings" => crate::kclvm_schema_default_settings as *const () as u64, @@ -247,41 +252,13 @@ pub fn _kclvm_get_fn_ptr_by_name(name: &str) -> u64 { "kclvm_schema_optional_check" => crate::kclvm_schema_optional_check as *const () as u64, "kclvm_schema_value_check" => crate::kclvm_schema_value_check as *const () as u64, "kclvm_schema_value_new" => crate::kclvm_schema_value_new as *const () as u64, - "kclvm_strlen" => crate::kclvm_strlen as *const () as u64, - "kclvm_testing_arguments" => crate::kclvm_testing_arguments as *const () as u64, - "kclvm_testing_setting_file" => crate::kclvm_testing_setting_file as *const () as u64, - "kclvm_type_Any" => crate::kclvm_type_Any as *const () as u64, - "kclvm_type_Bool" => crate::kclvm_type_Bool as *const () as u64, - "kclvm_type_BoolLit" => crate::kclvm_type_BoolLit as *const () as u64, - "kclvm_type_BoolLit_value" => crate::kclvm_type_BoolLit_value as *const () as u64, - "kclvm_type_Dict" => crate::kclvm_type_Dict as *const () as u64, - "kclvm_type_Float" => crate::kclvm_type_Float as *const () as u64, - "kclvm_type_FloatLit" => crate::kclvm_type_FloatLit as *const () as u64, - "kclvm_type_FloatLit_value" => crate::kclvm_type_FloatLit_value as *const () as u64, - "kclvm_type_Func" => crate::kclvm_type_Func as *const () as u64, - "kclvm_type_Int" => crate::kclvm_type_Int as *const () as u64, - "kclvm_type_IntLit" => crate::kclvm_type_IntLit as *const () as u64, - "kclvm_type_IntLit_value" => crate::kclvm_type_IntLit_value as *const () as u64, - "kclvm_type_List" => crate::kclvm_type_List as *const () as u64, - "kclvm_type_Schema" => crate::kclvm_type_Schema as *const () as u64, - "kclvm_type_Str" => crate::kclvm_type_Str as *const () as u64, - "kclvm_type_StrLit" => crate::kclvm_type_StrLit as *const () as u64, - "kclvm_type_StrLit_value" => crate::kclvm_type_StrLit_value as *const () as u64, - "kclvm_type_Union" => crate::kclvm_type_Union as *const () as u64, - "kclvm_type_arg_num" => crate::kclvm_type_arg_num as *const () as u64, - "kclvm_type_arg_type" => crate::kclvm_type_arg_type as *const () as u64, - "kclvm_type_delete" => crate::kclvm_type_delete as *const () as u64, - "kclvm_type_elem_type" => crate::kclvm_type_elem_type as *const () as u64, - "kclvm_type_key_type" => crate::kclvm_type_key_type as *const () as u64, - "kclvm_type_kind" => crate::kclvm_type_kind as *const () as u64, - "kclvm_type_return_type" => crate::kclvm_type_return_type as *const () as u64, - "kclvm_type_schema_field_name" => crate::kclvm_type_schema_field_name as *const () as u64, - "kclvm_type_schema_field_num" => crate::kclvm_type_schema_field_num as *const () as u64, - "kclvm_type_schema_field_type" => crate::kclvm_type_schema_field_type as *const () as u64, - "kclvm_type_schema_name" => crate::kclvm_type_schema_name as *const () as u64, - "kclvm_type_schema_parent_name" => crate::kclvm_type_schema_parent_name as *const () as u64, - "kclvm_type_schema_relaxed" => crate::kclvm_type_schema_relaxed as *const () as u64, - "kclvm_type_str" => crate::kclvm_type_str as *const () as u64, + "kclvm_scope_add_setter" => crate::kclvm_scope_add_setter as *const () as u64, + "kclvm_scope_delete" => crate::kclvm_scope_delete as *const () as u64, + "kclvm_scope_get" => crate::kclvm_scope_get as *const () as u64, + "kclvm_scope_new" => crate::kclvm_scope_new as *const () as u64, + "kclvm_scope_set" => crate::kclvm_scope_set as *const () as u64, + "kclvm_template_execute" => crate::kclvm_template_execute as *const () as u64, + "kclvm_template_html_escape" => crate::kclvm_template_html_escape as *const () as u64, "kclvm_units_to_G" => crate::kclvm_units_to_G as *const () as u64, "kclvm_units_to_Gi" => crate::kclvm_units_to_Gi as *const () as u64, "kclvm_units_to_K" => crate::kclvm_units_to_K as *const () as u64, @@ -296,28 +273,22 @@ pub fn _kclvm_get_fn_ptr_by_name(name: &str) -> u64 { "kclvm_units_to_n" => crate::kclvm_units_to_n as *const () as u64, "kclvm_units_to_u" => crate::kclvm_units_to_u as *const () as u64, "kclvm_value_Bool" => crate::kclvm_value_Bool as *const () as u64, - "kclvm_value_Bool_ptr" => crate::kclvm_value_Bool_ptr as *const () as u64, "kclvm_value_Decorator" => crate::kclvm_value_Decorator as *const () as u64, "kclvm_value_Dict" => crate::kclvm_value_Dict as *const () as u64, "kclvm_value_False" => crate::kclvm_value_False as *const () as u64, "kclvm_value_Float" => crate::kclvm_value_Float as *const () as u64, - "kclvm_value_Float_ptr" => crate::kclvm_value_Float_ptr as *const () as u64, "kclvm_value_Function" => crate::kclvm_value_Function as *const () as u64, "kclvm_value_Function_using_ptr" => { crate::kclvm_value_Function_using_ptr as *const () as u64 } "kclvm_value_Int" => crate::kclvm_value_Int as *const () as u64, - "kclvm_value_Int_ptr" => crate::kclvm_value_Int_ptr as *const () as u64, "kclvm_value_List" => crate::kclvm_value_List as *const () as u64, "kclvm_value_List10" => crate::kclvm_value_List10 as *const () as u64, "kclvm_value_List6" => crate::kclvm_value_List6 as *const () as u64, - "kclvm_value_ListN" => crate::kclvm_value_ListN as *const () as u64, "kclvm_value_None" => crate::kclvm_value_None as *const () as u64, "kclvm_value_Schema" => crate::kclvm_value_Schema as *const () as u64, "kclvm_value_Str" => crate::kclvm_value_Str as *const () as u64, - "kclvm_value_Str_len" => crate::kclvm_value_Str_len as *const () as u64, "kclvm_value_Str_ptr" => crate::kclvm_value_Str_ptr as *const () as u64, - "kclvm_value_Str_resize" => crate::kclvm_value_Str_resize as *const () as u64, "kclvm_value_True" => crate::kclvm_value_True as *const () as u64, "kclvm_value_Undefined" => crate::kclvm_value_Undefined as *const () as u64, "kclvm_value_Unit" => crate::kclvm_value_Unit as *const () as u64, @@ -338,23 +309,13 @@ pub fn _kclvm_get_fn_ptr_by_name(name: &str) -> u64 { "kclvm_value_deep_copy" => crate::kclvm_value_deep_copy as *const () as u64, "kclvm_value_delete" => crate::kclvm_value_delete as *const () as u64, "kclvm_value_from_json" => crate::kclvm_value_from_json as *const () as u64, - "kclvm_value_function_external_invoke" => { - crate::kclvm_value_function_external_invoke as *const () as u64 - } - "kclvm_value_function_get_closure" => { - crate::kclvm_value_function_get_closure as *const () as u64 - } "kclvm_value_function_invoke" => crate::kclvm_value_function_invoke as *const () as u64, - "kclvm_value_function_is_external" => { - crate::kclvm_value_function_is_external as *const () as u64 - } "kclvm_value_function_ptr" => crate::kclvm_value_function_ptr as *const () as u64, "kclvm_value_in" => crate::kclvm_value_in as *const () as u64, "kclvm_value_is" => crate::kclvm_value_is as *const () as u64, "kclvm_value_is_not" => crate::kclvm_value_is_not as *const () as u64, "kclvm_value_is_truthy" => crate::kclvm_value_is_truthy as *const () as u64, "kclvm_value_iter" => crate::kclvm_value_iter as *const () as u64, - "kclvm_value_kind" => crate::kclvm_value_kind as *const () as u64, "kclvm_value_len" => crate::kclvm_value_len as *const () as u64, "kclvm_value_load_attr" => crate::kclvm_value_load_attr as *const () as u64, "kclvm_value_load_attr_option" => crate::kclvm_value_load_attr_option as *const () as u64, @@ -396,7 +357,7 @@ pub fn _kclvm_get_fn_ptr_by_name(name: &str) -> u64 { "kclvm_value_slice_option" => crate::kclvm_value_slice_option as *const () as u64, "kclvm_value_subscr" => crate::kclvm_value_subscr as *const () as u64, "kclvm_value_subscr_option" => crate::kclvm_value_subscr_option as *const () as u64, - "kclvm_value_to_json" => crate::kclvm_value_to_json as *const () as u64, + "kclvm_value_subscr_set" => crate::kclvm_value_subscr_set as *const () as u64, "kclvm_value_to_json_value" => crate::kclvm_value_to_json_value as *const () as u64, "kclvm_value_to_json_value_with_null" => { crate::kclvm_value_to_json_value_with_null as *const () as u64 @@ -410,8 +371,12 @@ pub fn _kclvm_get_fn_ptr_by_name(name: &str) -> u64 { "kclvm_value_union" => crate::kclvm_value_union as *const () as u64, "kclvm_value_union_all" => crate::kclvm_value_union_all as *const () as u64, "kclvm_yaml_decode" => crate::kclvm_yaml_decode as *const () as u64, + "kclvm_yaml_decode_all" => crate::kclvm_yaml_decode_all as *const () as u64, + "kclvm_yaml_dump_all_to_file" => crate::kclvm_yaml_dump_all_to_file as *const () as u64, "kclvm_yaml_dump_to_file" => crate::kclvm_yaml_dump_to_file as *const () as u64, "kclvm_yaml_encode" => crate::kclvm_yaml_encode as *const () as u64, - _ => panic!("unknown {}", name), + "kclvm_yaml_encode_all" => crate::kclvm_yaml_encode_all as *const () as u64, + "kclvm_yaml_validate" => crate::kclvm_yaml_validate as *const () as u64, + _ => panic!("unknown {name}"), } } diff --git a/kclvm/runtime/src/_kclvm_api_spec.rs b/kclvm/runtime/src/_kclvm_api_spec.rs index 87f041ab9..129a06398 100644 --- a/kclvm/runtime/src/_kclvm_api_spec.rs +++ b/kclvm/runtime/src/_kclvm_api_spec.rs @@ -1,39 +1,7 @@ -// Copyright 2022 The KCL Authors. All rights reserved. +// Copyright The KCL Authors. All rights reserved. // Auto generated by command, DONOT EDIT!!! -// api-spec: kclvm_buffer_new -// api-spec(c): kclvm_buffer_t* kclvm_buffer_new(kclvm_size_t size); -// api-spec(llvm): declare %kclvm_buffer_t* @kclvm_buffer_new(%kclvm_size_t %size); - -// api-spec: kclvm_buffer_delete -// api-spec(c): void kclvm_buffer_delete(kclvm_buffer_t* p); -// api-spec(llvm): declare void @kclvm_buffer_delete(%kclvm_buffer_t* %p); - -// api-spec: kclvm_buffer_size -// api-spec(c): kclvm_size_t kclvm_buffer_size(kclvm_buffer_t* p); -// api-spec(llvm): declare %kclvm_size_t @kclvm_buffer_size(%kclvm_buffer_t* %p); - -// api-spec: kclvm_buffer_data -// api-spec(c): kclvm_char_t* kclvm_buffer_data(kclvm_buffer_t* p); -// api-spec(llvm): declare %kclvm_char_t* @kclvm_buffer_data(%kclvm_buffer_t* %p); - -// api-spec: kclvm_malloc -// api-spec(c): uint8_t* kclvm_malloc(int32_t n); -// api-spec(llvm): declare i8* @kclvm_malloc(i32 %n); - -// api-spec: kclvm_free -// api-spec(c): void kclvm_free(uint8_t* ptr); -// api-spec(llvm): declare void @kclvm_free(i8* %ptr); - -// api-spec: kclvm_strlen -// api-spec(c): kclvm_size_t kclvm_strlen(uint8_t* ptr); -// api-spec(llvm): declare %kclvm_size_t @kclvm_strlen(i8* %ptr); - -// api-spec: kclvm_context_current -// api-spec(c): kclvm_context_t* kclvm_context_current(); -// api-spec(llvm): declare %kclvm_context_t* @kclvm_context_current(); - // api-spec: kclvm_context_new // api-spec(c): kclvm_context_t* kclvm_context_new(); // api-spec(llvm): declare %kclvm_context_t* @kclvm_context_new(); @@ -42,65 +10,49 @@ // api-spec(c): void kclvm_context_delete(kclvm_context_t* p); // api-spec(llvm): declare void @kclvm_context_delete(%kclvm_context_t* %p); -// api-spec: kclvm_context_main_begin_hook -// api-spec(c): void kclvm_context_main_begin_hook(kclvm_context_t* p); -// api-spec(llvm): declare void @kclvm_context_main_begin_hook(%kclvm_context_t* %p); - -// api-spec: kclvm_context_main_end_hook -// api-spec(c): kclvm_value_ref_t* kclvm_context_main_end_hook(kclvm_context_t* p, kclvm_value_ref_t* return_value); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_context_main_end_hook(%kclvm_context_t* %p, %kclvm_value_ref_t* %return_value); - // api-spec: kclvm_context_set_kcl_location -// api-spec(c): void kclvm_context_set_kcl_location(kclvm_context_t* p, int8_t* filename, int32_t line, int32_t col); +// api-spec(c): void kclvm_context_set_kcl_location(kclvm_context_t* p, char* filename, int32_t line, int32_t col); // api-spec(llvm): declare void @kclvm_context_set_kcl_location(%kclvm_context_t* %p, i8* %filename, i32 %line, i32 %col); // api-spec: kclvm_context_set_kcl_pkgpath -// api-spec(c): void kclvm_context_set_kcl_pkgpath(kclvm_context_t* p, int8_t* pkgpath); +// api-spec(c): void kclvm_context_set_kcl_pkgpath(kclvm_context_t* p, char* pkgpath); // api-spec(llvm): declare void @kclvm_context_set_kcl_pkgpath(%kclvm_context_t* %p, i8* %pkgpath); -// api-spec: kclvm_context_set_kcl_filename -// api-spec(c): void kclvm_context_set_kcl_filename(int8_t* filename); -// api-spec(llvm): declare void @kclvm_context_set_kcl_filename(i8* %filename); - -// api-spec: kclvm_context_set_kcl_line_col -// api-spec(c): void kclvm_context_set_kcl_line_col(int32_t line, int32_t col); -// api-spec(llvm): declare void @kclvm_context_set_kcl_line_col(i32 %line, i32 %col); - -// api-spec: kclvm_context_put_type -// api-spec(c): void kclvm_context_put_type(kclvm_context_t* p, kclvm_type_t* typ); -// api-spec(llvm): declare void @kclvm_context_put_type(%kclvm_context_t* %p, %kclvm_type_t* %typ); +// api-spec: kclvm_context_set_kcl_modpath +// api-spec(c): void kclvm_context_set_kcl_modpath(kclvm_context_t* p, char* module_path); +// api-spec(llvm): declare void @kclvm_context_set_kcl_modpath(%kclvm_context_t* %p, i8* %module_path); -// api-spec: kclvm_context_clear_all_types -// api-spec(c): void kclvm_context_clear_all_types(kclvm_context_t* p); -// api-spec(llvm): declare void @kclvm_context_clear_all_types(%kclvm_context_t* %p); +// api-spec: kclvm_context_set_kcl_workdir +// api-spec(c): void kclvm_context_set_kcl_workdir(kclvm_context_t* p, char* workdir); +// api-spec(llvm): declare void @kclvm_context_set_kcl_workdir(%kclvm_context_t* %p, i8* %workdir); -// api-spec: kclvm_context_symbol_init -// api-spec(c): void kclvm_context_symbol_init(kclvm_context_t* p, kclvm_size_t n, kclvm_char_t** symbol_names); -// api-spec(llvm): declare void @kclvm_context_symbol_init(%kclvm_context_t* %p, %kclvm_size_t %n, %kclvm_char_t** %symbol_names); +// api-spec: kclvm_context_set_kcl_filename +// api-spec(c): void kclvm_context_set_kcl_filename(kclvm_context_t* ctx, char* filename); +// api-spec(llvm): declare void @kclvm_context_set_kcl_filename(%kclvm_context_t* %ctx, i8* %filename); -// api-spec: kclvm_context_symbol_num -// api-spec(c): kclvm_size_t kclvm_context_symbol_num(kclvm_context_t* p); -// api-spec(llvm): declare %kclvm_size_t @kclvm_context_symbol_num(%kclvm_context_t* %p); +// api-spec: kclvm_context_set_kcl_line_col +// api-spec(c): void kclvm_context_set_kcl_line_col(kclvm_context_t* ctx, int32_t line, int32_t col); +// api-spec(llvm): declare void @kclvm_context_set_kcl_line_col(%kclvm_context_t* %ctx, i32 %line, i32 %col); -// api-spec: kclvm_context_symbol_name -// api-spec(c): kclvm_char_t* kclvm_context_symbol_name(kclvm_context_t* p, kclvm_size_t i); -// api-spec(llvm): declare %kclvm_char_t* @kclvm_context_symbol_name(%kclvm_context_t* %p, %kclvm_size_t %i); +// api-spec: kclvm_scope_new +// api-spec(c): kclvm_eval_scope_t* kclvm_scope_new(); +// api-spec(llvm): declare %kclvm_eval_scope_t* @kclvm_scope_new(); -// api-spec: kclvm_context_symbol_value -// api-spec(c): kclvm_value_t* kclvm_context_symbol_value(kclvm_context_t* p, kclvm_size_t i); -// api-spec(llvm): declare %kclvm_value_t* @kclvm_context_symbol_value(%kclvm_context_t* %p, %kclvm_size_t %i); +// api-spec: kclvm_scope_delete +// api-spec(c): void kclvm_scope_delete(kclvm_eval_scope_t* scope); +// api-spec(llvm): declare void @kclvm_scope_delete(%kclvm_eval_scope_t* %scope); -// api-spec: kclvm_context_args_get -// api-spec(c): kclvm_char_t* kclvm_context_args_get(kclvm_context_t* _p, kclvm_char_t* _key); -// api-spec(llvm): declare %kclvm_char_t* @kclvm_context_args_get(%kclvm_context_t* %_p, %kclvm_char_t* %_key); +// api-spec: kclvm_scope_add_setter +// api-spec(c): void kclvm_scope_add_setter(kclvm_context_t* _ctx, kclvm_eval_scope_t* scope, char* pkg, char* name, uint64_t* setter); +// api-spec(llvm): declare void @kclvm_scope_add_setter(%kclvm_context_t* %_ctx, %kclvm_eval_scope_t* %scope, i8* %pkg, i8* %name, i64* %setter); -// api-spec: kclvm_context_args_set -// api-spec(c): void kclvm_context_args_set(kclvm_context_t* _p, kclvm_char_t* _key, kclvm_char_t* _value); -// api-spec(llvm): declare void @kclvm_context_args_set(%kclvm_context_t* %_p, %kclvm_char_t* %_key, %kclvm_char_t* %_value); +// api-spec: kclvm_scope_set +// api-spec(c): void kclvm_scope_set(kclvm_context_t* _ctx, kclvm_eval_scope_t* scope, char* pkg, char* name, kclvm_value_ref_t* value); +// api-spec(llvm): declare void @kclvm_scope_set(%kclvm_context_t* %_ctx, %kclvm_eval_scope_t* %scope, i8* %pkg, i8* %name, %kclvm_value_ref_t* %value); -// api-spec: kclvm_context_args_clear -// api-spec(c): void kclvm_context_args_clear(kclvm_context_t* p); -// api-spec(llvm): declare void @kclvm_context_args_clear(%kclvm_context_t* %p); +// api-spec: kclvm_scope_get +// api-spec(c): kclvm_value_ref_t* kclvm_scope_get(kclvm_context_t* ctx, kclvm_eval_scope_t* scope, char* pkg, char* name, char* target, kclvm_value_ref_t* default); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_scope_get(%kclvm_context_t* %ctx, %kclvm_eval_scope_t* %scope, i8* %pkg, i8* %name, i8* %target, %kclvm_value_ref_t* %default); // api-spec: kclvm_context_set_debug_mode // api-spec(c): void kclvm_context_set_debug_mode(kclvm_context_t* p, kclvm_bool_t v); @@ -118,282 +70,122 @@ // api-spec(c): void kclvm_context_set_disable_schema_check(kclvm_context_t* p, kclvm_bool_t v); // api-spec(llvm): declare void @kclvm_context_set_disable_schema_check(%kclvm_context_t* %p, %kclvm_bool_t %v); -// api-spec: kclvm_context_set_list_option_mode -// api-spec(c): void kclvm_context_set_list_option_mode(kclvm_context_t* p, kclvm_bool_t v); -// api-spec(llvm): declare void @kclvm_context_set_list_option_mode(%kclvm_context_t* %p, %kclvm_bool_t %v); - // api-spec: kclvm_context_invoke // api-spec(c): char* kclvm_context_invoke(kclvm_context_t* p, char* method, char* args, char* kwargs); // api-spec(llvm): declare i8* @kclvm_context_invoke(%kclvm_context_t* %p, i8* %method, i8* %args, i8* %kwargs); // api-spec: kclvm_context_pkgpath_is_imported -// api-spec(c): kclvm_bool_t kclvm_context_pkgpath_is_imported(kclvm_char_t* pkgpath); -// api-spec(llvm): declare %kclvm_bool_t @kclvm_context_pkgpath_is_imported(%kclvm_char_t* %pkgpath); - -// api-spec: kclvm_type_Any -// api-spec(c): kclvm_type_t* kclvm_type_Any(); -// api-spec(llvm): declare %kclvm_type_t* @kclvm_type_Any(); - -// api-spec: kclvm_type_Bool -// api-spec(c): kclvm_type_t* kclvm_type_Bool(); -// api-spec(llvm): declare %kclvm_type_t* @kclvm_type_Bool(); - -// api-spec: kclvm_type_BoolLit -// api-spec(c): kclvm_type_t* kclvm_type_BoolLit(kclvm_bool_t v); -// api-spec(llvm): declare %kclvm_type_t* @kclvm_type_BoolLit(%kclvm_bool_t %v); - -// api-spec: kclvm_type_Int -// api-spec(c): kclvm_type_t* kclvm_type_Int(); -// api-spec(llvm): declare %kclvm_type_t* @kclvm_type_Int(); - -// api-spec: kclvm_type_IntLit -// api-spec(c): kclvm_type_t* kclvm_type_IntLit(int64_t v); -// api-spec(llvm): declare %kclvm_type_t* @kclvm_type_IntLit(i64 %v); - -// api-spec: kclvm_type_Float -// api-spec(c): kclvm_type_t* kclvm_type_Float(); -// api-spec(llvm): declare %kclvm_type_t* @kclvm_type_Float(); - -// api-spec: kclvm_type_FloatLit -// api-spec(c): kclvm_type_t* kclvm_type_FloatLit(double v); -// api-spec(llvm): declare %kclvm_type_t* @kclvm_type_FloatLit(double %v); - -// api-spec: kclvm_type_Str -// api-spec(c): kclvm_type_t* kclvm_type_Str(); -// api-spec(llvm): declare %kclvm_type_t* @kclvm_type_Str(); - -// api-spec: kclvm_type_StrLit -// api-spec(c): kclvm_type_t* kclvm_type_StrLit(kclvm_char_t* s); -// api-spec(llvm): declare %kclvm_type_t* @kclvm_type_StrLit(%kclvm_char_t* %s); - -// api-spec: kclvm_type_List -// api-spec(c): kclvm_type_t* kclvm_type_List(kclvm_type_t* elem_type); -// api-spec(llvm): declare %kclvm_type_t* @kclvm_type_List(%kclvm_type_t* %elem_type); - -// api-spec: kclvm_type_Dict -// api-spec(c): kclvm_type_t* kclvm_type_Dict(kclvm_type_t* key_type, kclvm_type_t* elem_type); -// api-spec(llvm): declare %kclvm_type_t* @kclvm_type_Dict(%kclvm_type_t* %key_type, %kclvm_type_t* %elem_type); - -// api-spec: kclvm_type_Union -// api-spec(c): kclvm_type_t* kclvm_type_Union(kclvm_size_t n, kclvm_type_t** elem_types); -// api-spec(llvm): declare %kclvm_type_t* @kclvm_type_Union(%kclvm_size_t %n, %kclvm_type_t** %elem_types); - -// api-spec: kclvm_type_Schema -// api-spec(c): kclvm_type_t* kclvm_type_Schema(kclvm_char_t* name, kclvm_char_t* parent_name, kclvm_bool_t _is_relaxed, kclvm_size_t field_num, kclvm_char_t** field_names, kclvm_type_t** field_types); -// api-spec(llvm): declare %kclvm_type_t* @kclvm_type_Schema(%kclvm_char_t* %name, %kclvm_char_t* %parent_name, %kclvm_bool_t %_is_relaxed, %kclvm_size_t %field_num, %kclvm_char_t** %field_names, %kclvm_type_t** %field_types); - -// api-spec: kclvm_type_Func -// api-spec(c): kclvm_type_t* kclvm_type_Func(kclvm_size_t args_len, kclvm_type_t** args_types, kclvm_type_t* return_type); -// api-spec(llvm): declare %kclvm_type_t* @kclvm_type_Func(%kclvm_size_t %args_len, %kclvm_type_t** %args_types, %kclvm_type_t* %return_type); - -// api-spec: kclvm_type_delete -// api-spec(c): void kclvm_type_delete(kclvm_type_t* p); -// api-spec(llvm): declare void @kclvm_type_delete(%kclvm_type_t* %p); - -// api-spec: kclvm_type_kind -// api-spec(c): kclvm_kind_t kclvm_type_kind(kclvm_type_t* p); -// api-spec(llvm): declare %kclvm_kind_t @kclvm_type_kind(%kclvm_type_t* %p); - -// api-spec: kclvm_type_str -// api-spec(c): kclvm_kind_t kclvm_type_str(kclvm_type_t* p); -// api-spec(llvm): declare %kclvm_kind_t @kclvm_type_str(%kclvm_type_t* %p); - -// api-spec: kclvm_type_BoolLit_value -// api-spec(c): kclvm_bool_t kclvm_type_BoolLit_value(kclvm_type_t* p); -// api-spec(llvm): declare %kclvm_bool_t @kclvm_type_BoolLit_value(%kclvm_type_t* %p); - -// api-spec: kclvm_type_IntLit_value -// api-spec(c): int64_t kclvm_type_IntLit_value(kclvm_type_t* p); -// api-spec(llvm): declare i64 @kclvm_type_IntLit_value(%kclvm_type_t* %p); - -// api-spec: kclvm_type_FloatLit_value -// api-spec(c): double kclvm_type_FloatLit_value(kclvm_type_t* p); -// api-spec(llvm): declare double @kclvm_type_FloatLit_value(%kclvm_type_t* %p); - -// api-spec: kclvm_type_StrLit_value -// api-spec(c): kclvm_char_t* kclvm_type_StrLit_value(kclvm_type_t* p); -// api-spec(llvm): declare %kclvm_char_t* @kclvm_type_StrLit_value(%kclvm_type_t* %p); - -// api-spec: kclvm_type_key_type -// api-spec(c): kclvm_type_t* kclvm_type_key_type(kclvm_type_t* p); -// api-spec(llvm): declare %kclvm_type_t* @kclvm_type_key_type(%kclvm_type_t* %p); - -// api-spec: kclvm_type_elem_type -// api-spec(c): kclvm_type_t* kclvm_type_elem_type(kclvm_type_t* p); -// api-spec(llvm): declare %kclvm_type_t* @kclvm_type_elem_type(%kclvm_type_t* %p); - -// api-spec: kclvm_type_schema_name -// api-spec(c): kclvm_char_t* kclvm_type_schema_name(kclvm_type_t* p); -// api-spec(llvm): declare %kclvm_char_t* @kclvm_type_schema_name(%kclvm_type_t* %p); - -// api-spec: kclvm_type_schema_parent_name -// api-spec(c): kclvm_char_t* kclvm_type_schema_parent_name(kclvm_type_t* p); -// api-spec(llvm): declare %kclvm_char_t* @kclvm_type_schema_parent_name(%kclvm_type_t* %p); - -// api-spec: kclvm_type_schema_relaxed -// api-spec(c): kclvm_bool_t kclvm_type_schema_relaxed(kclvm_type_t* p); -// api-spec(llvm): declare %kclvm_bool_t @kclvm_type_schema_relaxed(%kclvm_type_t* %p); - -// api-spec: kclvm_type_schema_field_num -// api-spec(c): kclvm_size_t kclvm_type_schema_field_num(kclvm_type_t* p); -// api-spec(llvm): declare %kclvm_size_t @kclvm_type_schema_field_num(%kclvm_type_t* %p); - -// api-spec: kclvm_type_schema_field_name -// api-spec(c): kclvm_char_t* kclvm_type_schema_field_name(kclvm_type_t* p, kclvm_size_t i); -// api-spec(llvm): declare %kclvm_char_t* @kclvm_type_schema_field_name(%kclvm_type_t* %p, %kclvm_size_t %i); - -// api-spec: kclvm_type_schema_field_type -// api-spec(c): kclvm_type_t* kclvm_type_schema_field_type(kclvm_type_t* p, kclvm_size_t i); -// api-spec(llvm): declare %kclvm_type_t* @kclvm_type_schema_field_type(%kclvm_type_t* %p, %kclvm_size_t %i); - -// api-spec: kclvm_type_arg_num -// api-spec(c): kclvm_size_t kclvm_type_arg_num(kclvm_type_t* p); -// api-spec(llvm): declare %kclvm_size_t @kclvm_type_arg_num(%kclvm_type_t* %p); - -// api-spec: kclvm_type_arg_type -// api-spec(c): kclvm_type_t* kclvm_type_arg_type(kclvm_type_t* p, kclvm_size_t i); -// api-spec(llvm): declare %kclvm_type_t* @kclvm_type_arg_type(%kclvm_type_t* %p, %kclvm_size_t %i); - -// api-spec: kclvm_type_return_type -// api-spec(c): kclvm_type_t* kclvm_type_return_type(kclvm_type_t* p); -// api-spec(llvm): declare %kclvm_type_t* @kclvm_type_return_type(%kclvm_type_t* %p); +// api-spec(c): kclvm_bool_t kclvm_context_pkgpath_is_imported(kclvm_context_t* ctx, kclvm_char_t* pkgpath); +// api-spec(llvm): declare %kclvm_bool_t @kclvm_context_pkgpath_is_imported(%kclvm_context_t* %ctx, %kclvm_char_t* %pkgpath); // api-spec: kclvm_context_set_import_names // api-spec(c): void kclvm_context_set_import_names(kclvm_context_t* p, kclvm_value_ref_t* import_names); // api-spec(llvm): declare void @kclvm_context_set_import_names(%kclvm_context_t* %p, %kclvm_value_ref_t* %import_names); // api-spec: kclvm_value_Undefined -// api-spec(c): kclvm_value_ref_t* kclvm_value_Undefined(); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_Undefined(); +// api-spec(c): kclvm_value_ref_t* kclvm_value_Undefined(kclvm_context_t* ctx); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_Undefined(%kclvm_context_t* %ctx); // api-spec: kclvm_value_None -// api-spec(c): kclvm_value_ref_t* kclvm_value_None(); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_None(); +// api-spec(c): kclvm_value_ref_t* kclvm_value_None(kclvm_context_t* ctx); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_None(%kclvm_context_t* %ctx); // api-spec: kclvm_value_True -// api-spec(c): kclvm_value_ref_t* kclvm_value_True(); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_True(); +// api-spec(c): kclvm_value_ref_t* kclvm_value_True(kclvm_context_t* ctx); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_True(%kclvm_context_t* %ctx); // api-spec: kclvm_value_False -// api-spec(c): kclvm_value_ref_t* kclvm_value_False(); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_False(); +// api-spec(c): kclvm_value_ref_t* kclvm_value_False(kclvm_context_t* ctx); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_False(%kclvm_context_t* %ctx); // api-spec: kclvm_value_Bool -// api-spec(c): kclvm_value_ref_t* kclvm_value_Bool(kclvm_bool_t v); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_Bool(%kclvm_bool_t %v); +// api-spec(c): kclvm_value_ref_t* kclvm_value_Bool(kclvm_context_t* ctx, kclvm_bool_t v); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_Bool(%kclvm_context_t* %ctx, %kclvm_bool_t %v); // api-spec: kclvm_value_Int -// api-spec(c): kclvm_value_ref_t* kclvm_value_Int(kclvm_int_t v); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_Int(%kclvm_int_t %v); +// api-spec(c): kclvm_value_ref_t* kclvm_value_Int(kclvm_context_t* ctx, kclvm_int_t v); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_Int(%kclvm_context_t* %ctx, %kclvm_int_t %v); // api-spec: kclvm_value_Float -// api-spec(c): kclvm_value_ref_t* kclvm_value_Float(kclvm_float_t v); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_Float(%kclvm_float_t %v); +// api-spec(c): kclvm_value_ref_t* kclvm_value_Float(kclvm_context_t* ctx, kclvm_float_t v); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_Float(%kclvm_context_t* %ctx, %kclvm_float_t %v); // api-spec: kclvm_value_Unit -// api-spec(c): kclvm_value_ref_t* kclvm_value_Unit(kclvm_float_t v, kclvm_int_t raw, kclvm_char_t* unit); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_Unit(%kclvm_float_t %v, %kclvm_int_t %raw, %kclvm_char_t* %unit); +// api-spec(c): kclvm_value_ref_t* kclvm_value_Unit(kclvm_context_t* ctx, kclvm_float_t v, kclvm_int_t raw, kclvm_char_t* unit); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_Unit(%kclvm_context_t* %ctx, %kclvm_float_t %v, %kclvm_int_t %raw, %kclvm_char_t* %unit); // api-spec: kclvm_value_Str -// api-spec(c): kclvm_value_ref_t* kclvm_value_Str(kclvm_char_t* v); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_Str(%kclvm_char_t* %v); +// api-spec(c): kclvm_value_ref_t* kclvm_value_Str(kclvm_context_t* ctx, kclvm_char_t* v); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_Str(%kclvm_context_t* %ctx, %kclvm_char_t* %v); // api-spec: kclvm_value_List -// api-spec(c): kclvm_value_ref_t* kclvm_value_List(); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_List(); +// api-spec(c): kclvm_value_ref_t* kclvm_value_List(kclvm_context_t* ctx); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_List(%kclvm_context_t* %ctx); // api-spec: kclvm_value_List6 -// api-spec(c): kclvm_value_ref_t* kclvm_value_List6(kclvm_value_ref_t* v1, kclvm_value_ref_t* v2, kclvm_value_ref_t* v3, kclvm_value_ref_t* v4, kclvm_value_ref_t* v5, kclvm_value_ref_t* v6); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_List6(%kclvm_value_ref_t* %v1, %kclvm_value_ref_t* %v2, %kclvm_value_ref_t* %v3, %kclvm_value_ref_t* %v4, %kclvm_value_ref_t* %v5, %kclvm_value_ref_t* %v6); +// api-spec(c): kclvm_value_ref_t* kclvm_value_List6(kclvm_context_t* ctx, kclvm_value_ref_t* v1, kclvm_value_ref_t* v2, kclvm_value_ref_t* v3, kclvm_value_ref_t* v4, kclvm_value_ref_t* v5, kclvm_value_ref_t* v6); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_List6(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %v1, %kclvm_value_ref_t* %v2, %kclvm_value_ref_t* %v3, %kclvm_value_ref_t* %v4, %kclvm_value_ref_t* %v5, %kclvm_value_ref_t* %v6); // api-spec: kclvm_value_List10 -// api-spec(c): kclvm_value_ref_t* kclvm_value_List10(kclvm_value_ref_t* v1, kclvm_value_ref_t* v2, kclvm_value_ref_t* v3, kclvm_value_ref_t* v4, kclvm_value_ref_t* v5, kclvm_value_ref_t* v6, kclvm_value_ref_t* v7, kclvm_value_ref_t* v8, kclvm_value_ref_t* v9, kclvm_value_ref_t* v10); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_List10(%kclvm_value_ref_t* %v1, %kclvm_value_ref_t* %v2, %kclvm_value_ref_t* %v3, %kclvm_value_ref_t* %v4, %kclvm_value_ref_t* %v5, %kclvm_value_ref_t* %v6, %kclvm_value_ref_t* %v7, %kclvm_value_ref_t* %v8, %kclvm_value_ref_t* %v9, %kclvm_value_ref_t* %v10); - -// api-spec: kclvm_value_ListN -// api-spec(c): kclvm_value_ref_t* kclvm_value_ListN(kclvm_int_t n, kclvm_value_ref_t** elem_values); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_ListN(%kclvm_int_t %n, %kclvm_value_ref_t** %elem_values); +// api-spec(c): kclvm_value_ref_t* kclvm_value_List10(kclvm_context_t* ctx, kclvm_value_ref_t* v1, kclvm_value_ref_t* v2, kclvm_value_ref_t* v3, kclvm_value_ref_t* v4, kclvm_value_ref_t* v5, kclvm_value_ref_t* v6, kclvm_value_ref_t* v7, kclvm_value_ref_t* v8, kclvm_value_ref_t* v9, kclvm_value_ref_t* v10); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_List10(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %v1, %kclvm_value_ref_t* %v2, %kclvm_value_ref_t* %v3, %kclvm_value_ref_t* %v4, %kclvm_value_ref_t* %v5, %kclvm_value_ref_t* %v6, %kclvm_value_ref_t* %v7, %kclvm_value_ref_t* %v8, %kclvm_value_ref_t* %v9, %kclvm_value_ref_t* %v10); // api-spec: kclvm_value_Dict -// api-spec(c): kclvm_value_ref_t* kclvm_value_Dict(); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_Dict(); +// api-spec(c): kclvm_value_ref_t* kclvm_value_Dict(kclvm_context_t* ctx); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_Dict(%kclvm_context_t* %ctx); // api-spec: kclvm_value_Schema -// api-spec(c): kclvm_value_ref_t* kclvm_value_Schema(); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_Schema(); +// api-spec(c): kclvm_value_ref_t* kclvm_value_Schema(kclvm_context_t* ctx); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_Schema(%kclvm_context_t* %ctx); // api-spec: kclvm_value_schema_with_config -// api-spec(c): kclvm_value_ref_t* kclvm_value_schema_with_config(kclvm_value_ref_t* schema_dict, kclvm_value_ref_t* config, kclvm_char_t* name, kclvm_char_t* pkgpath, kclvm_value_ref_t* is_sub_schema, kclvm_value_ref_t* record_instance, kclvm_value_ref_t* instance_pkgpath); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_schema_with_config(%kclvm_value_ref_t* %schema_dict, %kclvm_value_ref_t* %config, %kclvm_char_t* %name, %kclvm_char_t* %pkgpath, %kclvm_value_ref_t* %is_sub_schema, %kclvm_value_ref_t* %record_instance, %kclvm_value_ref_t* %instance_pkgpath); +// api-spec(c): kclvm_value_ref_t* kclvm_value_schema_with_config(kclvm_context_t* ctx, kclvm_value_ref_t* schema_dict, kclvm_value_ref_t* config, kclvm_value_ref_t* config_meta, kclvm_char_t* name, kclvm_char_t* pkgpath, kclvm_value_ref_t* is_sub_schema, kclvm_value_ref_t* record_instance, kclvm_value_ref_t* instance_pkgpath, kclvm_value_ref_t* optional_mapping, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_schema_with_config(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %schema_dict, %kclvm_value_ref_t* %config, %kclvm_value_ref_t* %config_meta, %kclvm_char_t* %name, %kclvm_char_t* %pkgpath, %kclvm_value_ref_t* %is_sub_schema, %kclvm_value_ref_t* %record_instance, %kclvm_value_ref_t* %instance_pkgpath, %kclvm_value_ref_t* %optional_mapping, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); // api-spec: kclvm_value_Function -// api-spec(c): kclvm_value_ref_t* kclvm_value_Function(uint64_t* fn_ptr, kclvm_value_ref_t* closure, kclvm_char_t* external_name); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_Function(i64* %fn_ptr, %kclvm_value_ref_t* %closure, %kclvm_char_t* %external_name); +// api-spec(c): kclvm_value_ref_t* kclvm_value_Function(kclvm_context_t* ctx, uint64_t* fn_ptr, kclvm_value_ref_t* closure, kclvm_char_t* name, kclvm_bool_t is_external); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_Function(%kclvm_context_t* %ctx, i64* %fn_ptr, %kclvm_value_ref_t* %closure, %kclvm_char_t* %name, %kclvm_bool_t %is_external); // api-spec: kclvm_value_Function_using_ptr -// api-spec(c): kclvm_value_ref_t* kclvm_value_Function_using_ptr(uint64_t* fn_ptr); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_Function_using_ptr(i64* %fn_ptr); +// api-spec(c): kclvm_value_ref_t* kclvm_value_Function_using_ptr(kclvm_context_t* ctx, uint64_t* fn_ptr, kclvm_char_t* name); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_Function_using_ptr(%kclvm_context_t* %ctx, i64* %fn_ptr, %kclvm_char_t* %name); // api-spec: kclvm_value_schema_function -// api-spec(c): kclvm_value_ref_t* kclvm_value_schema_function(uint64_t* fn_ptr, uint64_t* check_fn_ptr, kclvm_char_t* tpe); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_schema_function(i64* %fn_ptr, i64* %check_fn_ptr, %kclvm_char_t* %tpe); +// api-spec(c): kclvm_value_ref_t* kclvm_value_schema_function(kclvm_context_t* ctx, uint64_t* fn_ptr, uint64_t* check_fn_ptr, kclvm_value_ref_t* attr_map, kclvm_char_t* tpe); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_schema_function(%kclvm_context_t* %ctx, i64* %fn_ptr, i64* %check_fn_ptr, %kclvm_value_ref_t* %attr_map, %kclvm_char_t* %tpe); // api-spec: kclvm_value_from_json -// api-spec(c): kclvm_value_ref_t* kclvm_value_from_json(kclvm_char_t* s); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_from_json(%kclvm_char_t* %s); - -// api-spec: kclvm_value_to_json -// api-spec(c): kclvm_buffer_t* kclvm_value_to_json(kclvm_value_ref_t* p); -// api-spec(llvm): declare %kclvm_buffer_t* @kclvm_value_to_json(%kclvm_value_ref_t* %p); +// api-spec(c): kclvm_value_ref_t* kclvm_value_from_json(kclvm_context_t* ctx, kclvm_char_t* s); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_from_json(%kclvm_context_t* %ctx, %kclvm_char_t* %s); // api-spec: kclvm_value_to_json_value -// api-spec(c): kclvm_value_ref_t* kclvm_value_to_json_value(kclvm_value_ref_t* p); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_to_json_value(%kclvm_value_ref_t* %p); +// api-spec(c): kclvm_value_ref_t* kclvm_value_to_json_value(kclvm_context_t* ctx, kclvm_value_ref_t* p); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_to_json_value(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %p); // api-spec: kclvm_value_to_json_value_with_null -// api-spec(c): kclvm_value_ref_t* kclvm_value_to_json_value_with_null(kclvm_value_ref_t* p); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_to_json_value_with_null(%kclvm_value_ref_t* %p); +// api-spec(c): kclvm_value_ref_t* kclvm_value_to_json_value_with_null(kclvm_context_t* ctx, kclvm_value_ref_t* p); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_to_json_value_with_null(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %p); // api-spec: kclvm_value_plan_to_json -// api-spec(c): kclvm_value_ref_t* kclvm_value_plan_to_json(kclvm_value_ref_t* p); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_plan_to_json(%kclvm_value_ref_t* %p); +// api-spec(c): kclvm_value_ref_t* kclvm_value_plan_to_json(kclvm_context_t* ctx, kclvm_value_ref_t* p); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_plan_to_json(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %p); // api-spec: kclvm_value_plan_to_yaml -// api-spec(c): kclvm_value_ref_t* kclvm_value_plan_to_yaml(kclvm_value_ref_t* p); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_plan_to_yaml(%kclvm_value_ref_t* %p); +// api-spec(c): kclvm_value_ref_t* kclvm_value_plan_to_yaml(kclvm_context_t* ctx, kclvm_value_ref_t* p); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_plan_to_yaml(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %p); // api-spec: kclvm_value_to_yaml_value -// api-spec(c): kclvm_value_ref_t* kclvm_value_to_yaml_value(kclvm_value_ref_t* p); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_to_yaml_value(%kclvm_value_ref_t* %p); +// api-spec(c): kclvm_value_ref_t* kclvm_value_to_yaml_value(kclvm_context_t* ctx, kclvm_value_ref_t* p); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_to_yaml_value(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %p); // api-spec: kclvm_value_to_str_value -// api-spec(c): kclvm_value_ref_t* kclvm_value_to_str_value(kclvm_value_ref_t* p); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_to_str_value(%kclvm_value_ref_t* %p); - -// api-spec: kclvm_value_Bool_ptr -// api-spec(c): kclvm_bool_t* kclvm_value_Bool_ptr(kclvm_value_ref_t* p); -// api-spec(llvm): declare %kclvm_bool_t* @kclvm_value_Bool_ptr(%kclvm_value_ref_t* %p); - -// api-spec: kclvm_value_Int_ptr -// api-spec(c): kclvm_int_t* kclvm_value_Int_ptr(kclvm_value_ref_t* p); -// api-spec(llvm): declare %kclvm_int_t* @kclvm_value_Int_ptr(%kclvm_value_ref_t* %p); - -// api-spec: kclvm_value_Float_ptr -// api-spec(c): kclvm_float_t* kclvm_value_Float_ptr(kclvm_value_ref_t* p); -// api-spec(llvm): declare %kclvm_float_t* @kclvm_value_Float_ptr(%kclvm_value_ref_t* %p); +// api-spec(c): kclvm_value_ref_t* kclvm_value_to_str_value(kclvm_context_t* ctx, kclvm_value_ref_t* p); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_to_str_value(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %p); // api-spec: kclvm_value_Str_ptr // api-spec(c): kclvm_char_t* kclvm_value_Str_ptr(kclvm_value_ref_t* p); // api-spec(llvm): declare %kclvm_char_t* @kclvm_value_Str_ptr(%kclvm_value_ref_t* %p); -// api-spec: kclvm_value_Str_len -// api-spec(c): kclvm_size_t kclvm_value_Str_len(kclvm_value_ref_t* p); -// api-spec(llvm): declare %kclvm_size_t @kclvm_value_Str_len(%kclvm_value_ref_t* %p); - -// api-spec: kclvm_value_Str_resize -// api-spec(c): void kclvm_value_Str_resize(kclvm_value_ref_t* p, kclvm_size_t n); -// api-spec(llvm): declare void @kclvm_value_Str_resize(%kclvm_value_ref_t* %p, %kclvm_size_t %n); - // api-spec: kclvm_value_function_ptr // api-spec(c): uint64_t* kclvm_value_function_ptr(kclvm_value_ref_t* p); // api-spec(llvm): declare i64* @kclvm_value_function_ptr(%kclvm_value_ref_t* %p); @@ -402,29 +194,13 @@ // api-spec(c): uint64_t* kclvm_value_check_function_ptr(kclvm_value_ref_t* p); // api-spec(llvm): declare i64* @kclvm_value_check_function_ptr(%kclvm_value_ref_t* %p); -// api-spec: kclvm_value_function_is_external -// api-spec(c): kclvm_bool_t kclvm_value_function_is_external(kclvm_value_ref_t* p); -// api-spec(llvm): declare %kclvm_bool_t @kclvm_value_function_is_external(%kclvm_value_ref_t* %p); - -// api-spec: kclvm_value_function_external_invoke -// api-spec(c): kclvm_value_ref_t* kclvm_value_function_external_invoke(kclvm_value_ref_t* p, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_function_external_invoke(%kclvm_value_ref_t* %p, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); - // api-spec: kclvm_value_function_invoke -// api-spec(c): kclvm_value_ref_t* kclvm_value_function_invoke(kclvm_value_ref_t* p, kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs, kclvm_char_t* pkgpath); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_function_invoke(%kclvm_value_ref_t* %p, %kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs, %kclvm_char_t* %pkgpath); - -// api-spec: kclvm_value_function_get_closure -// api-spec(c): kclvm_value_ref_t* kclvm_value_function_get_closure(kclvm_value_ref_t* p); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_function_get_closure(%kclvm_value_ref_t* %p); - -// api-spec: kclvm_value_kind -// api-spec(c): kclvm_kind_t kclvm_value_kind(kclvm_value_ref_t* p); -// api-spec(llvm): declare %kclvm_kind_t @kclvm_value_kind(%kclvm_value_ref_t* %p); +// api-spec(c): kclvm_value_ref_t* kclvm_value_function_invoke(kclvm_value_ref_t* p, kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs, kclvm_char_t* pkgpath, kclvm_value_ref_t* is_in_schema); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_function_invoke(%kclvm_value_ref_t* %p, %kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs, %kclvm_char_t* %pkgpath, %kclvm_value_ref_t* %is_in_schema); // api-spec: kclvm_value_deep_copy -// api-spec(c): kclvm_value_ref_t* kclvm_value_deep_copy(kclvm_value_ref_t* p); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_deep_copy(%kclvm_value_ref_t* %p); +// api-spec(c): kclvm_value_ref_t* kclvm_value_deep_copy(kclvm_context_t* ctx, kclvm_value_ref_t* p); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_deep_copy(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %p); // api-spec: kclvm_value_delete // api-spec(c): void kclvm_value_delete(kclvm_value_ref_t* p); @@ -467,36 +243,36 @@ // api-spec(llvm): declare void @kclvm_list_clear(%kclvm_value_ref_t* %p); // api-spec: kclvm_list_count -// api-spec(c): kclvm_value_ref_t* kclvm_list_count(kclvm_value_ref_t* p, kclvm_value_ref_t* item); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_list_count(%kclvm_value_ref_t* %p, %kclvm_value_ref_t* %item); +// api-spec(c): kclvm_value_ref_t* kclvm_list_count(kclvm_context_t* ctx, kclvm_value_ref_t* p, kclvm_value_ref_t* item); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_list_count(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %p, %kclvm_value_ref_t* %item); // api-spec: kclvm_list_find -// api-spec(c): kclvm_value_ref_t* kclvm_list_find(kclvm_value_ref_t* p, kclvm_value_ref_t* item); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_list_find(%kclvm_value_ref_t* %p, %kclvm_value_ref_t* %item); +// api-spec(c): kclvm_value_ref_t* kclvm_list_find(kclvm_context_t* ctx, kclvm_value_ref_t* p, kclvm_value_ref_t* item); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_list_find(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %p, %kclvm_value_ref_t* %item); // api-spec: kclvm_list_insert // api-spec(c): void kclvm_list_insert(kclvm_value_ref_t* p, kclvm_value_ref_t* index, kclvm_value_ref_t* value); // api-spec(llvm): declare void @kclvm_list_insert(%kclvm_value_ref_t* %p, %kclvm_value_ref_t* %index, %kclvm_value_ref_t* %value); // api-spec: kclvm_list_get -// api-spec(c): kclvm_value_ref_t* kclvm_list_get(kclvm_value_ref_t* p, kclvm_size_t i); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_list_get(%kclvm_value_ref_t* %p, %kclvm_size_t %i); +// api-spec(c): kclvm_value_ref_t* kclvm_list_get(kclvm_context_t* ctx, kclvm_value_ref_t* p, kclvm_size_t i); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_list_get(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %p, %kclvm_size_t %i); // api-spec: kclvm_list_get_option -// api-spec(c): kclvm_value_ref_t* kclvm_list_get_option(kclvm_value_ref_t* p, kclvm_size_t i); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_list_get_option(%kclvm_value_ref_t* %p, %kclvm_size_t %i); +// api-spec(c): kclvm_value_ref_t* kclvm_list_get_option(kclvm_context_t* ctx, kclvm_value_ref_t* p, kclvm_size_t i); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_list_get_option(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %p, %kclvm_size_t %i); // api-spec: kclvm_list_set // api-spec(c): void kclvm_list_set(kclvm_value_ref_t* p, kclvm_size_t i, kclvm_value_ref_t* v); // api-spec(llvm): declare void @kclvm_list_set(%kclvm_value_ref_t* %p, %kclvm_size_t %i, %kclvm_value_ref_t* %v); // api-spec: kclvm_list_pop -// api-spec(c): kclvm_value_ref_t* kclvm_list_pop(kclvm_value_ref_t* p); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_list_pop(%kclvm_value_ref_t* %p); +// api-spec(c): kclvm_value_ref_t* kclvm_list_pop(kclvm_context_t* ctx, kclvm_value_ref_t* p); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_list_pop(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %p); // api-spec: kclvm_list_pop_first -// api-spec(c): kclvm_value_ref_t* kclvm_list_pop_first(kclvm_value_ref_t* p); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_list_pop_first(%kclvm_value_ref_t* %p); +// api-spec(c): kclvm_value_ref_t* kclvm_list_pop_first(kclvm_context_t* ctx, kclvm_value_ref_t* p); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_list_pop_first(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %p); // api-spec: kclvm_list_append // api-spec(c): void kclvm_list_append(kclvm_value_ref_t* p, kclvm_value_ref_t* v); @@ -534,61 +310,65 @@ // api-spec(c): void kclvm_dict_clear(kclvm_value_ref_t* p); // api-spec(llvm): declare void @kclvm_dict_clear(%kclvm_value_ref_t* %p); +// api-spec: kclvm_dict_is_override_attr +// api-spec(c): kclvm_bool_t kclvm_dict_is_override_attr(kclvm_value_ref_t* p, kclvm_char_t* key); +// api-spec(llvm): declare %kclvm_bool_t @kclvm_dict_is_override_attr(%kclvm_value_ref_t* %p, %kclvm_char_t* %key); + // api-spec: kclvm_dict_get -// api-spec(c): kclvm_value_ref_t* kclvm_dict_get(kclvm_value_ref_t* p, kclvm_value_ref_t* key); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_dict_get(%kclvm_value_ref_t* %p, %kclvm_value_ref_t* %key); +// api-spec(c): kclvm_value_ref_t* kclvm_dict_get(kclvm_context_t* ctx, kclvm_value_ref_t* p, kclvm_value_ref_t* key); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_dict_get(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %p, %kclvm_value_ref_t* %key); // api-spec: kclvm_dict_has_value // api-spec(c): kclvm_bool_t kclvm_dict_has_value(kclvm_value_ref_t* p, kclvm_char_t* key); // api-spec(llvm): declare %kclvm_bool_t @kclvm_dict_has_value(%kclvm_value_ref_t* %p, %kclvm_char_t* %key); // api-spec: kclvm_dict_get_value -// api-spec(c): kclvm_value_ref_t* kclvm_dict_get_value(kclvm_value_ref_t* p, kclvm_char_t* key); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_dict_get_value(%kclvm_value_ref_t* %p, %kclvm_char_t* %key); +// api-spec(c): kclvm_value_ref_t* kclvm_dict_get_value(kclvm_context_t* ctx, kclvm_value_ref_t* p, kclvm_char_t* key); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_dict_get_value(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %p, %kclvm_char_t* %key); // api-spec: kclvm_dict_get_entry -// api-spec(c): kclvm_value_ref_t* kclvm_dict_get_entry(kclvm_value_ref_t* p, kclvm_char_t* key); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_dict_get_entry(%kclvm_value_ref_t* %p, %kclvm_char_t* %key); +// api-spec(c): kclvm_value_ref_t* kclvm_dict_get_entry(kclvm_context_t* ctx, kclvm_value_ref_t* p, kclvm_char_t* key); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_dict_get_entry(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %p, %kclvm_char_t* %key); // api-spec: kclvm_dict_get_value_by_path -// api-spec(c): kclvm_value_ref_t* kclvm_dict_get_value_by_path(kclvm_value_ref_t* p, kclvm_char_t* path); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_dict_get_value_by_path(%kclvm_value_ref_t* %p, %kclvm_char_t* %path); +// api-spec(c): kclvm_value_ref_t* kclvm_dict_get_value_by_path(kclvm_context_t* ctx, kclvm_value_ref_t* p, kclvm_char_t* path); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_dict_get_value_by_path(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %p, %kclvm_char_t* %path); // api-spec: kclvm_dict_set_value -// api-spec(c): void kclvm_dict_set_value(kclvm_value_ref_t* p, kclvm_char_t* key, kclvm_value_ref_t* val); -// api-spec(llvm): declare void @kclvm_dict_set_value(%kclvm_value_ref_t* %p, %kclvm_char_t* %key, %kclvm_value_ref_t* %val); +// api-spec(c): void kclvm_dict_set_value(kclvm_context_t* ctx, kclvm_value_ref_t* p, kclvm_char_t* key, kclvm_value_ref_t* val); +// api-spec(llvm): declare void @kclvm_dict_set_value(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %p, %kclvm_char_t* %key, %kclvm_value_ref_t* %val); // api-spec: kclvm_dict_keys -// api-spec(c): kclvm_value_ref_t* kclvm_dict_keys(kclvm_value_ref_t* p); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_dict_keys(%kclvm_value_ref_t* %p); +// api-spec(c): kclvm_value_ref_t* kclvm_dict_keys(kclvm_context_t* ctx, kclvm_value_ref_t* p); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_dict_keys(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %p); // api-spec: kclvm_dict_values -// api-spec(c): kclvm_value_ref_t* kclvm_dict_values(kclvm_value_ref_t* p); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_dict_values(%kclvm_value_ref_t* %p); +// api-spec(c): kclvm_value_ref_t* kclvm_dict_values(kclvm_context_t* ctx, kclvm_value_ref_t* p); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_dict_values(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %p); // api-spec: kclvm_dict_insert -// api-spec(c): void kclvm_dict_insert(kclvm_value_ref_t* p, kclvm_char_t* key, kclvm_value_ref_t* v, kclvm_size_t op, kclvm_size_t insert_index); -// api-spec(llvm): declare void @kclvm_dict_insert(%kclvm_value_ref_t* %p, %kclvm_char_t* %key, %kclvm_value_ref_t* %v, %kclvm_size_t %op, %kclvm_size_t %insert_index); +// api-spec(c): void kclvm_dict_insert(kclvm_context_t* ctx, kclvm_value_ref_t* p, kclvm_char_t* key, kclvm_value_ref_t* v, kclvm_size_t op, kclvm_size_t insert_index, kclvm_bool_t has_insert_index); +// api-spec(llvm): declare void @kclvm_dict_insert(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %p, %kclvm_char_t* %key, %kclvm_value_ref_t* %v, %kclvm_size_t %op, %kclvm_size_t %insert_index, %kclvm_bool_t %has_insert_index); // api-spec: kclvm_dict_merge -// api-spec(c): void kclvm_dict_merge(kclvm_value_ref_t* p, kclvm_char_t* key, kclvm_value_ref_t* v, kclvm_size_t op, kclvm_size_t insert_index); -// api-spec(llvm): declare void @kclvm_dict_merge(%kclvm_value_ref_t* %p, %kclvm_char_t* %key, %kclvm_value_ref_t* %v, %kclvm_size_t %op, %kclvm_size_t %insert_index); +// api-spec(c): void kclvm_dict_merge(kclvm_context_t* ctx, kclvm_value_ref_t* p, kclvm_char_t* key, kclvm_value_ref_t* v, kclvm_size_t op, kclvm_size_t insert_index, kclvm_bool_t has_insert_index); +// api-spec(llvm): declare void @kclvm_dict_merge(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %p, %kclvm_char_t* %key, %kclvm_value_ref_t* %v, %kclvm_size_t %op, %kclvm_size_t %insert_index, %kclvm_bool_t %has_insert_index); // api-spec: kclvm_dict_insert_value -// api-spec(c): void kclvm_dict_insert_value(kclvm_value_ref_t* p, kclvm_value_ref_t* key, kclvm_value_ref_t* v, kclvm_size_t op, kclvm_size_t insert_index); -// api-spec(llvm): declare void @kclvm_dict_insert_value(%kclvm_value_ref_t* %p, %kclvm_value_ref_t* %key, %kclvm_value_ref_t* %v, %kclvm_size_t %op, %kclvm_size_t %insert_index); +// api-spec(c): void kclvm_dict_insert_value(kclvm_context_t* ctx, kclvm_value_ref_t* p, kclvm_value_ref_t* key, kclvm_value_ref_t* v, kclvm_size_t op, kclvm_size_t insert_index, kclvm_bool_t has_insert_index); +// api-spec(llvm): declare void @kclvm_dict_insert_value(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %p, %kclvm_value_ref_t* %key, %kclvm_value_ref_t* %v, %kclvm_size_t %op, %kclvm_size_t %insert_index, %kclvm_bool_t %has_insert_index); // api-spec: kclvm_dict_update_key_value // api-spec(c): void kclvm_dict_update_key_value(kclvm_value_ref_t* p, kclvm_value_ref_t* key, kclvm_value_ref_t* v); // api-spec(llvm): declare void @kclvm_dict_update_key_value(%kclvm_value_ref_t* %p, %kclvm_value_ref_t* %key, %kclvm_value_ref_t* %v); // api-spec: kclvm_dict_safe_insert -// api-spec(c): void kclvm_dict_safe_insert(kclvm_value_ref_t* p, kclvm_char_t* key, kclvm_value_ref_t* v, kclvm_size_t op, kclvm_size_t insert_index); -// api-spec(llvm): declare void @kclvm_dict_safe_insert(%kclvm_value_ref_t* %p, %kclvm_char_t* %key, %kclvm_value_ref_t* %v, %kclvm_size_t %op, %kclvm_size_t %insert_index); +// api-spec(c): void kclvm_dict_safe_insert(kclvm_context_t* ctx, kclvm_value_ref_t* p, kclvm_char_t* key, kclvm_value_ref_t* v, kclvm_size_t op, kclvm_size_t insert_index, kclvm_bool_t has_insert_index); +// api-spec(llvm): declare void @kclvm_dict_safe_insert(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %p, %kclvm_char_t* %key, %kclvm_value_ref_t* %v, %kclvm_size_t %op, %kclvm_size_t %insert_index, %kclvm_bool_t %has_insert_index); // api-spec: kclvm_dict_insert_unpack -// api-spec(c): void kclvm_dict_insert_unpack(kclvm_value_ref_t* p, kclvm_value_ref_t* v); -// api-spec(llvm): declare void @kclvm_dict_insert_unpack(%kclvm_value_ref_t* %p, %kclvm_value_ref_t* %v); +// api-spec(c): void kclvm_dict_insert_unpack(kclvm_context_t* ctx, kclvm_value_ref_t* p, kclvm_value_ref_t* v); +// api-spec(llvm): declare void @kclvm_dict_insert_unpack(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %p, %kclvm_value_ref_t* %v); // api-spec: kclvm_default_collection_insert_int_pointer // api-spec(c): void kclvm_default_collection_insert_int_pointer(kclvm_value_ref_t* p, kclvm_char_t* key, uint64_t* ptr); @@ -615,496 +395,544 @@ // api-spec(llvm): declare %kclvm_size_t @kclvm_value_len(%kclvm_value_ref_t* %p); // api-spec: kclvm_value_cmp_equal_to -// api-spec(c): kclvm_value_ref_t* kclvm_value_cmp_equal_to(kclvm_value_ref_t* a, kclvm_value_ref_t* b); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_cmp_equal_to(%kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); +// api-spec(c): kclvm_value_ref_t* kclvm_value_cmp_equal_to(kclvm_context_t* ctx, kclvm_value_ref_t* a, kclvm_value_ref_t* b); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_cmp_equal_to(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); // api-spec: kclvm_value_cmp_not_equal_to -// api-spec(c): kclvm_value_ref_t* kclvm_value_cmp_not_equal_to(kclvm_value_ref_t* a, kclvm_value_ref_t* b); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_cmp_not_equal_to(%kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); +// api-spec(c): kclvm_value_ref_t* kclvm_value_cmp_not_equal_to(kclvm_context_t* ctx, kclvm_value_ref_t* a, kclvm_value_ref_t* b); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_cmp_not_equal_to(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); // api-spec: kclvm_value_cmp_less_than -// api-spec(c): kclvm_value_ref_t* kclvm_value_cmp_less_than(kclvm_value_ref_t* a, kclvm_value_ref_t* b); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_cmp_less_than(%kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); +// api-spec(c): kclvm_value_ref_t* kclvm_value_cmp_less_than(kclvm_context_t* ctx, kclvm_value_ref_t* a, kclvm_value_ref_t* b); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_cmp_less_than(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); // api-spec: kclvm_value_cmp_less_than_or_equal -// api-spec(c): kclvm_value_ref_t* kclvm_value_cmp_less_than_or_equal(kclvm_value_ref_t* a, kclvm_value_ref_t* b); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_cmp_less_than_or_equal(%kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); +// api-spec(c): kclvm_value_ref_t* kclvm_value_cmp_less_than_or_equal(kclvm_context_t* ctx, kclvm_value_ref_t* a, kclvm_value_ref_t* b); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_cmp_less_than_or_equal(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); // api-spec: kclvm_value_cmp_greater_than -// api-spec(c): kclvm_value_ref_t* kclvm_value_cmp_greater_than(kclvm_value_ref_t* a, kclvm_value_ref_t* b); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_cmp_greater_than(%kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); +// api-spec(c): kclvm_value_ref_t* kclvm_value_cmp_greater_than(kclvm_context_t* ctx, kclvm_value_ref_t* a, kclvm_value_ref_t* b); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_cmp_greater_than(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); // api-spec: kclvm_value_cmp_greater_than_or_equal -// api-spec(c): kclvm_value_ref_t* kclvm_value_cmp_greater_than_or_equal(kclvm_value_ref_t* a, kclvm_value_ref_t* b); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_cmp_greater_than_or_equal(%kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); +// api-spec(c): kclvm_value_ref_t* kclvm_value_cmp_greater_than_or_equal(kclvm_context_t* ctx, kclvm_value_ref_t* a, kclvm_value_ref_t* b); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_cmp_greater_than_or_equal(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); // api-spec: kclvm_value_is -// api-spec(c): kclvm_value_ref_t* kclvm_value_is(kclvm_value_ref_t* a, kclvm_value_ref_t* b); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_is(%kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); +// api-spec(c): kclvm_value_ref_t* kclvm_value_is(kclvm_context_t* ctx, kclvm_value_ref_t* a, kclvm_value_ref_t* b); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_is(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); // api-spec: kclvm_value_is_not -// api-spec(c): kclvm_value_ref_t* kclvm_value_is_not(kclvm_value_ref_t* a, kclvm_value_ref_t* b); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_is_not(%kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); +// api-spec(c): kclvm_value_ref_t* kclvm_value_is_not(kclvm_context_t* ctx, kclvm_value_ref_t* a, kclvm_value_ref_t* b); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_is_not(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); // api-spec: kclvm_value_in -// api-spec(c): kclvm_value_ref_t* kclvm_value_in(kclvm_value_ref_t* a, kclvm_value_ref_t* b); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_in(%kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); +// api-spec(c): kclvm_value_ref_t* kclvm_value_in(kclvm_context_t* ctx, kclvm_value_ref_t* a, kclvm_value_ref_t* b); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_in(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); // api-spec: kclvm_value_not_in -// api-spec(c): kclvm_value_ref_t* kclvm_value_not_in(kclvm_value_ref_t* a, kclvm_value_ref_t* b); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_not_in(%kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); +// api-spec(c): kclvm_value_ref_t* kclvm_value_not_in(kclvm_context_t* ctx, kclvm_value_ref_t* a, kclvm_value_ref_t* b); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_not_in(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); // api-spec: kclvm_value_as -// api-spec(c): kclvm_value_ref_t* kclvm_value_as(kclvm_value_ref_t* a, kclvm_value_ref_t* b); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_as(%kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); +// api-spec(c): kclvm_value_ref_t* kclvm_value_as(kclvm_context_t* ctx, kclvm_value_ref_t* a, kclvm_value_ref_t* b); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_as(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); // api-spec: kclvm_value_unary_plus -// api-spec(c): kclvm_value_ref_t* kclvm_value_unary_plus(kclvm_value_ref_t* a); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_unary_plus(%kclvm_value_ref_t* %a); +// api-spec(c): kclvm_value_ref_t* kclvm_value_unary_plus(kclvm_context_t* ctx, kclvm_value_ref_t* a); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_unary_plus(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %a); // api-spec: kclvm_value_unary_minus -// api-spec(c): kclvm_value_ref_t* kclvm_value_unary_minus(kclvm_value_ref_t* a); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_unary_minus(%kclvm_value_ref_t* %a); +// api-spec(c): kclvm_value_ref_t* kclvm_value_unary_minus(kclvm_context_t* ctx, kclvm_value_ref_t* a); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_unary_minus(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %a); // api-spec: kclvm_value_unary_not -// api-spec(c): kclvm_value_ref_t* kclvm_value_unary_not(kclvm_value_ref_t* a); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_unary_not(%kclvm_value_ref_t* %a); +// api-spec(c): kclvm_value_ref_t* kclvm_value_unary_not(kclvm_context_t* ctx, kclvm_value_ref_t* a); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_unary_not(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %a); // api-spec: kclvm_value_unary_l_not -// api-spec(c): kclvm_value_ref_t* kclvm_value_unary_l_not(kclvm_value_ref_t* a); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_unary_l_not(%kclvm_value_ref_t* %a); +// api-spec(c): kclvm_value_ref_t* kclvm_value_unary_l_not(kclvm_context_t* ctx, kclvm_value_ref_t* a); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_unary_l_not(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %a); // api-spec: kclvm_value_op_add -// api-spec(c): kclvm_value_ref_t* kclvm_value_op_add(kclvm_value_ref_t* a, kclvm_value_ref_t* b); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_op_add(%kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); +// api-spec(c): kclvm_value_ref_t* kclvm_value_op_add(kclvm_context_t* ctx, kclvm_value_ref_t* a, kclvm_value_ref_t* b); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_op_add(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); // api-spec: kclvm_value_op_sub -// api-spec(c): kclvm_value_ref_t* kclvm_value_op_sub(kclvm_value_ref_t* a, kclvm_value_ref_t* b); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_op_sub(%kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); +// api-spec(c): kclvm_value_ref_t* kclvm_value_op_sub(kclvm_context_t* ctx, kclvm_value_ref_t* a, kclvm_value_ref_t* b); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_op_sub(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); // api-spec: kclvm_value_op_mul -// api-spec(c): kclvm_value_ref_t* kclvm_value_op_mul(kclvm_value_ref_t* a, kclvm_value_ref_t* b); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_op_mul(%kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); +// api-spec(c): kclvm_value_ref_t* kclvm_value_op_mul(kclvm_context_t* ctx, kclvm_value_ref_t* a, kclvm_value_ref_t* b); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_op_mul(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); // api-spec: kclvm_value_op_div -// api-spec(c): kclvm_value_ref_t* kclvm_value_op_div(kclvm_value_ref_t* a, kclvm_value_ref_t* b); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_op_div(%kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); +// api-spec(c): kclvm_value_ref_t* kclvm_value_op_div(kclvm_context_t* ctx, kclvm_value_ref_t* a, kclvm_value_ref_t* b); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_op_div(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); // api-spec: kclvm_value_op_mod -// api-spec(c): kclvm_value_ref_t* kclvm_value_op_mod(kclvm_value_ref_t* a, kclvm_value_ref_t* b); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_op_mod(%kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); +// api-spec(c): kclvm_value_ref_t* kclvm_value_op_mod(kclvm_context_t* ctx, kclvm_value_ref_t* a, kclvm_value_ref_t* b); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_op_mod(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); // api-spec: kclvm_value_op_pow -// api-spec(c): kclvm_value_ref_t* kclvm_value_op_pow(kclvm_value_ref_t* a, kclvm_value_ref_t* b); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_op_pow(%kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); +// api-spec(c): kclvm_value_ref_t* kclvm_value_op_pow(kclvm_context_t* ctx, kclvm_value_ref_t* a, kclvm_value_ref_t* b); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_op_pow(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); // api-spec: kclvm_value_op_floor_div -// api-spec(c): kclvm_value_ref_t* kclvm_value_op_floor_div(kclvm_value_ref_t* a, kclvm_value_ref_t* b); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_op_floor_div(%kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); +// api-spec(c): kclvm_value_ref_t* kclvm_value_op_floor_div(kclvm_context_t* ctx, kclvm_value_ref_t* a, kclvm_value_ref_t* b); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_op_floor_div(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); // api-spec: kclvm_value_op_bit_lshift -// api-spec(c): kclvm_value_ref_t* kclvm_value_op_bit_lshift(kclvm_value_ref_t* a, kclvm_value_ref_t* b); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_op_bit_lshift(%kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); +// api-spec(c): kclvm_value_ref_t* kclvm_value_op_bit_lshift(kclvm_context_t* ctx, kclvm_value_ref_t* a, kclvm_value_ref_t* b); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_op_bit_lshift(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); // api-spec: kclvm_value_op_bit_rshift -// api-spec(c): kclvm_value_ref_t* kclvm_value_op_bit_rshift(kclvm_value_ref_t* a, kclvm_value_ref_t* b); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_op_bit_rshift(%kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); +// api-spec(c): kclvm_value_ref_t* kclvm_value_op_bit_rshift(kclvm_context_t* ctx, kclvm_value_ref_t* a, kclvm_value_ref_t* b); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_op_bit_rshift(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); // api-spec: kclvm_value_op_bit_and -// api-spec(c): kclvm_value_ref_t* kclvm_value_op_bit_and(kclvm_value_ref_t* a, kclvm_value_ref_t* b); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_op_bit_and(%kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); +// api-spec(c): kclvm_value_ref_t* kclvm_value_op_bit_and(kclvm_context_t* ctx, kclvm_value_ref_t* a, kclvm_value_ref_t* b); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_op_bit_and(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); // api-spec: kclvm_value_op_bit_xor -// api-spec(c): kclvm_value_ref_t* kclvm_value_op_bit_xor(kclvm_value_ref_t* a, kclvm_value_ref_t* b); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_op_bit_xor(%kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); +// api-spec(c): kclvm_value_ref_t* kclvm_value_op_bit_xor(kclvm_context_t* ctx, kclvm_value_ref_t* a, kclvm_value_ref_t* b); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_op_bit_xor(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); // api-spec: kclvm_value_op_bit_or -// api-spec(c): kclvm_value_ref_t* kclvm_value_op_bit_or(kclvm_value_ref_t* a, kclvm_value_ref_t* b); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_op_bit_or(%kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); +// api-spec(c): kclvm_value_ref_t* kclvm_value_op_bit_or(kclvm_context_t* ctx, kclvm_value_ref_t* a, kclvm_value_ref_t* b); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_op_bit_or(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); // api-spec: kclvm_value_op_aug_add -// api-spec(c): kclvm_value_ref_t* kclvm_value_op_aug_add(kclvm_value_ref_t* a, kclvm_value_ref_t* b); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_op_aug_add(%kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); +// api-spec(c): kclvm_value_ref_t* kclvm_value_op_aug_add(kclvm_context_t* ctx, kclvm_value_ref_t* a, kclvm_value_ref_t* b); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_op_aug_add(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); // api-spec: kclvm_value_op_aug_sub -// api-spec(c): kclvm_value_ref_t* kclvm_value_op_aug_sub(kclvm_value_ref_t* a, kclvm_value_ref_t* b); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_op_aug_sub(%kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); +// api-spec(c): kclvm_value_ref_t* kclvm_value_op_aug_sub(kclvm_context_t* ctx, kclvm_value_ref_t* a, kclvm_value_ref_t* b); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_op_aug_sub(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); // api-spec: kclvm_value_op_aug_mul -// api-spec(c): kclvm_value_ref_t* kclvm_value_op_aug_mul(kclvm_value_ref_t* a, kclvm_value_ref_t* b); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_op_aug_mul(%kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); +// api-spec(c): kclvm_value_ref_t* kclvm_value_op_aug_mul(kclvm_context_t* ctx, kclvm_value_ref_t* a, kclvm_value_ref_t* b); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_op_aug_mul(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); // api-spec: kclvm_value_op_aug_div -// api-spec(c): kclvm_value_ref_t* kclvm_value_op_aug_div(kclvm_value_ref_t* a, kclvm_value_ref_t* b); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_op_aug_div(%kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); +// api-spec(c): kclvm_value_ref_t* kclvm_value_op_aug_div(kclvm_context_t* _ctx, kclvm_value_ref_t* a, kclvm_value_ref_t* b); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_op_aug_div(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); // api-spec: kclvm_value_op_aug_mod -// api-spec(c): kclvm_value_ref_t* kclvm_value_op_aug_mod(kclvm_value_ref_t* a, kclvm_value_ref_t* b); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_op_aug_mod(%kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); +// api-spec(c): kclvm_value_ref_t* kclvm_value_op_aug_mod(kclvm_context_t* _ctx, kclvm_value_ref_t* a, kclvm_value_ref_t* b); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_op_aug_mod(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); // api-spec: kclvm_value_op_aug_pow -// api-spec(c): kclvm_value_ref_t* kclvm_value_op_aug_pow(kclvm_value_ref_t* a, kclvm_value_ref_t* b); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_op_aug_pow(%kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); +// api-spec(c): kclvm_value_ref_t* kclvm_value_op_aug_pow(kclvm_context_t* ctx, kclvm_value_ref_t* a, kclvm_value_ref_t* b); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_op_aug_pow(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); // api-spec: kclvm_value_op_aug_floor_div -// api-spec(c): kclvm_value_ref_t* kclvm_value_op_aug_floor_div(kclvm_value_ref_t* a, kclvm_value_ref_t* b); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_op_aug_floor_div(%kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); +// api-spec(c): kclvm_value_ref_t* kclvm_value_op_aug_floor_div(kclvm_context_t* _ctx, kclvm_value_ref_t* a, kclvm_value_ref_t* b); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_op_aug_floor_div(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); // api-spec: kclvm_value_op_aug_bit_lshift -// api-spec(c): kclvm_value_ref_t* kclvm_value_op_aug_bit_lshift(kclvm_value_ref_t* a, kclvm_value_ref_t* b); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_op_aug_bit_lshift(%kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); +// api-spec(c): kclvm_value_ref_t* kclvm_value_op_aug_bit_lshift(kclvm_context_t* ctx, kclvm_value_ref_t* a, kclvm_value_ref_t* b); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_op_aug_bit_lshift(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); // api-spec: kclvm_value_op_aug_bit_rshift -// api-spec(c): kclvm_value_ref_t* kclvm_value_op_aug_bit_rshift(kclvm_value_ref_t* a, kclvm_value_ref_t* b); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_op_aug_bit_rshift(%kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); +// api-spec(c): kclvm_value_ref_t* kclvm_value_op_aug_bit_rshift(kclvm_context_t* ctx, kclvm_value_ref_t* a, kclvm_value_ref_t* b); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_op_aug_bit_rshift(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); // api-spec: kclvm_value_op_aug_bit_and -// api-spec(c): kclvm_value_ref_t* kclvm_value_op_aug_bit_and(kclvm_value_ref_t* a, kclvm_value_ref_t* b); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_op_aug_bit_and(%kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); +// api-spec(c): kclvm_value_ref_t* kclvm_value_op_aug_bit_and(kclvm_context_t* _ctx, kclvm_value_ref_t* a, kclvm_value_ref_t* b); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_op_aug_bit_and(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); // api-spec: kclvm_value_op_aug_bit_xor -// api-spec(c): kclvm_value_ref_t* kclvm_value_op_aug_bit_xor(kclvm_value_ref_t* a, kclvm_value_ref_t* b); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_op_aug_bit_xor(%kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); +// api-spec(c): kclvm_value_ref_t* kclvm_value_op_aug_bit_xor(kclvm_context_t* _ctx, kclvm_value_ref_t* a, kclvm_value_ref_t* b); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_op_aug_bit_xor(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); // api-spec: kclvm_value_op_aug_bit_or -// api-spec(c): kclvm_value_ref_t* kclvm_value_op_aug_bit_or(kclvm_value_ref_t* a, kclvm_value_ref_t* b); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_op_aug_bit_or(%kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); +// api-spec(c): kclvm_value_ref_t* kclvm_value_op_aug_bit_or(kclvm_context_t* ctx, kclvm_value_ref_t* a, kclvm_value_ref_t* b); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_op_aug_bit_or(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); // api-spec: kclvm_value_union -// api-spec(c): kclvm_value_ref_t* kclvm_value_union(kclvm_value_ref_t* schema, kclvm_value_ref_t* b); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_union(%kclvm_value_ref_t* %schema, %kclvm_value_ref_t* %b); +// api-spec(c): kclvm_value_ref_t* kclvm_value_union(kclvm_context_t* ctx, kclvm_value_ref_t* schema, kclvm_value_ref_t* b); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_union(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %schema, %kclvm_value_ref_t* %b); // api-spec: kclvm_value_logic_and -// api-spec(c): kclvm_value_ref_t* kclvm_value_logic_and(kclvm_value_ref_t* a, kclvm_value_ref_t* b); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_logic_and(%kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); +// api-spec(c): kclvm_value_ref_t* kclvm_value_logic_and(kclvm_context_t* ctx, kclvm_value_ref_t* a, kclvm_value_ref_t* b); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_logic_and(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); // api-spec: kclvm_value_logic_or -// api-spec(c): kclvm_value_ref_t* kclvm_value_logic_or(kclvm_value_ref_t* a, kclvm_value_ref_t* b); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_logic_or(%kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); +// api-spec(c): kclvm_value_ref_t* kclvm_value_logic_or(kclvm_context_t* ctx, kclvm_value_ref_t* a, kclvm_value_ref_t* b); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_logic_or(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); // api-spec: kclvm_value_subscr -// api-spec(c): kclvm_value_ref_t* kclvm_value_subscr(kclvm_value_ref_t* a, kclvm_value_ref_t* b); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_subscr(%kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); +// api-spec(c): kclvm_value_ref_t* kclvm_value_subscr(kclvm_context_t* ctx, kclvm_value_ref_t* a, kclvm_value_ref_t* b); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_subscr(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); + +// api-spec: kclvm_value_subscr_set +// api-spec(c): void kclvm_value_subscr_set(kclvm_context_t* ctx, kclvm_value_ref_t* p, kclvm_value_ref_t* index, kclvm_value_ref_t* val); +// api-spec(llvm): declare void @kclvm_value_subscr_set(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %p, %kclvm_value_ref_t* %index, %kclvm_value_ref_t* %val); // api-spec: kclvm_value_subscr_option -// api-spec(c): kclvm_value_ref_t* kclvm_value_subscr_option(kclvm_value_ref_t* a, kclvm_value_ref_t* b); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_subscr_option(%kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); +// api-spec(c): kclvm_value_ref_t* kclvm_value_subscr_option(kclvm_context_t* ctx, kclvm_value_ref_t* a, kclvm_value_ref_t* b); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_subscr_option(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); // api-spec: kclvm_value_load_attr -// api-spec(c): kclvm_value_ref_t* kclvm_value_load_attr(kclvm_value_ref_t* obj, kclvm_char_t* key); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_load_attr(%kclvm_value_ref_t* %obj, %kclvm_char_t* %key); +// api-spec(c): kclvm_value_ref_t* kclvm_value_load_attr(kclvm_context_t* ctx, kclvm_value_ref_t* obj, kclvm_char_t* key); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_load_attr(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %obj, %kclvm_char_t* %key); // api-spec: kclvm_value_load_attr_option -// api-spec(c): kclvm_value_ref_t* kclvm_value_load_attr_option(kclvm_value_ref_t* p, kclvm_char_t* key); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_load_attr_option(%kclvm_value_ref_t* %p, %kclvm_char_t* %key); +// api-spec(c): kclvm_value_ref_t* kclvm_value_load_attr_option(kclvm_context_t* ctx, kclvm_value_ref_t* p, kclvm_char_t* key); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_load_attr_option(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %p, %kclvm_char_t* %key); // api-spec: kclvm_value_remove_item // api-spec(c): void kclvm_value_remove_item(kclvm_value_ref_t* a, kclvm_value_ref_t* b); // api-spec(llvm): declare void @kclvm_value_remove_item(%kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b); // api-spec: kclvm_value_slice -// api-spec(c): kclvm_value_ref_t* kclvm_value_slice(kclvm_value_ref_t* x, kclvm_value_ref_t* a, kclvm_value_ref_t* b, kclvm_value_ref_t* step); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_slice(%kclvm_value_ref_t* %x, %kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b, %kclvm_value_ref_t* %step); +// api-spec(c): kclvm_value_ref_t* kclvm_value_slice(kclvm_context_t* ctx, kclvm_value_ref_t* x, kclvm_value_ref_t* a, kclvm_value_ref_t* b, kclvm_value_ref_t* step); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_slice(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %x, %kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b, %kclvm_value_ref_t* %step); // api-spec: kclvm_value_slice_option -// api-spec(c): kclvm_value_ref_t* kclvm_value_slice_option(kclvm_value_ref_t* x, kclvm_value_ref_t* a, kclvm_value_ref_t* b, kclvm_value_ref_t* step); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_slice_option(%kclvm_value_ref_t* %x, %kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b, %kclvm_value_ref_t* %step); +// api-spec(c): kclvm_value_ref_t* kclvm_value_slice_option(kclvm_context_t* ctx, kclvm_value_ref_t* x, kclvm_value_ref_t* a, kclvm_value_ref_t* b, kclvm_value_ref_t* step); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_slice_option(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %x, %kclvm_value_ref_t* %a, %kclvm_value_ref_t* %b, %kclvm_value_ref_t* %step); // api-spec: kclvm_schema_backtrack_cache -// api-spec(c): void kclvm_schema_backtrack_cache(kclvm_value_ref_t* schema, kclvm_value_ref_t* cache, kclvm_value_ref_t* cal_map, kclvm_char_t* name, kclvm_value_ref_t* runtime_type); -// api-spec(llvm): declare void @kclvm_schema_backtrack_cache(%kclvm_value_ref_t* %schema, %kclvm_value_ref_t* %cache, %kclvm_value_ref_t* %cal_map, %kclvm_char_t* %name, %kclvm_value_ref_t* %runtime_type); +// api-spec(c): void kclvm_schema_backtrack_cache(kclvm_context_t* ctx, kclvm_value_ref_t* schema, kclvm_value_ref_t* cache, kclvm_value_ref_t* cal_map, kclvm_char_t* name, kclvm_value_ref_t* runtime_type); +// api-spec(llvm): declare void @kclvm_schema_backtrack_cache(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %schema, %kclvm_value_ref_t* %cache, %kclvm_value_ref_t* %cal_map, %kclvm_char_t* %name, %kclvm_value_ref_t* %runtime_type); // api-spec: kclvm_schema_instances // api-spec(c): kclvm_value_ref_t* kclvm_schema_instances(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); // api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_schema_instances(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); // api-spec: kclvm_schema_value_check -// api-spec(c): void kclvm_schema_value_check(kclvm_value_ref_t* schema_value, kclvm_value_ref_t* schema_config, kclvm_value_ref_t* _config_meta, kclvm_char_t* schema_name, kclvm_value_ref_t* index_sign_value, kclvm_char_t* _key_name, kclvm_char_t* key_type, kclvm_char_t* _value_type, kclvm_bool_t _any_other, kclvm_bool_t is_relaxed); -// api-spec(llvm): declare void @kclvm_schema_value_check(%kclvm_value_ref_t* %schema_value, %kclvm_value_ref_t* %schema_config, %kclvm_value_ref_t* %_config_meta, %kclvm_char_t* %schema_name, %kclvm_value_ref_t* %index_sign_value, %kclvm_char_t* %_key_name, %kclvm_char_t* %key_type, %kclvm_char_t* %_value_type, %kclvm_bool_t %_any_other, %kclvm_bool_t %is_relaxed); +// api-spec(c): void kclvm_schema_value_check(kclvm_context_t* ctx, kclvm_value_ref_t* schema_value, kclvm_value_ref_t* schema_config, kclvm_value_ref_t* _config_meta, kclvm_char_t* schema_name, kclvm_value_ref_t* index_sign_value, kclvm_char_t* key_name, kclvm_char_t* key_type, kclvm_char_t* value_type, kclvm_bool_t _any_other); +// api-spec(llvm): declare void @kclvm_schema_value_check(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %schema_value, %kclvm_value_ref_t* %schema_config, %kclvm_value_ref_t* %_config_meta, %kclvm_char_t* %schema_name, %kclvm_value_ref_t* %index_sign_value, %kclvm_char_t* %key_name, %kclvm_char_t* %key_type, %kclvm_char_t* %value_type, %kclvm_bool_t %_any_other); // api-spec: kclvm_schema_do_check_with_index_sign_attr // api-spec(c): void kclvm_schema_do_check_with_index_sign_attr(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs, uint64_t* check_fn_ptr, kclvm_char_t* attr_name); // api-spec(llvm): declare void @kclvm_schema_do_check_with_index_sign_attr(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs, i64* %check_fn_ptr, %kclvm_char_t* %attr_name); // api-spec: kclvm_schema_optional_check -// api-spec(c): kclvm_value_ref_t* kclvm_schema_optional_check(kclvm_value_ref_t* p, kclvm_value_ref_t* v, kclvm_char_t* schema_name, kclvm_value_ref_t* config_meta); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_schema_optional_check(%kclvm_value_ref_t* %p, %kclvm_value_ref_t* %v, %kclvm_char_t* %schema_name, %kclvm_value_ref_t* %config_meta); +// api-spec(c): void kclvm_schema_optional_check(kclvm_context_t* ctx, kclvm_value_ref_t* p); +// api-spec(llvm): declare void @kclvm_schema_optional_check(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %p); // api-spec: kclvm_schema_default_settings -// api-spec(c): void kclvm_schema_default_settings(kclvm_value_ref_t* schema_value, kclvm_value_ref_t* config_value, kclvm_char_t* runtime_type); -// api-spec(llvm): declare void @kclvm_schema_default_settings(%kclvm_value_ref_t* %schema_value, %kclvm_value_ref_t* %config_value, %kclvm_char_t* %runtime_type); +// api-spec(c): void kclvm_schema_default_settings(kclvm_value_ref_t* schema_value, kclvm_value_ref_t* _config_value, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs, kclvm_char_t* runtime_type); +// api-spec(llvm): declare void @kclvm_schema_default_settings(%kclvm_value_ref_t* %schema_value, %kclvm_value_ref_t* %_config_value, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs, %kclvm_char_t* %runtime_type); // api-spec: kclvm_schema_assert -// api-spec(c): void kclvm_schema_assert(kclvm_value_ref_t* value, kclvm_value_ref_t* msg, kclvm_value_ref_t* config_meta); -// api-spec(llvm): declare void @kclvm_schema_assert(%kclvm_value_ref_t* %value, %kclvm_value_ref_t* %msg, %kclvm_value_ref_t* %config_meta); +// api-spec(c): void kclvm_schema_assert(kclvm_context_t* ctx, kclvm_value_ref_t* value, kclvm_value_ref_t* msg, kclvm_value_ref_t* config_meta); +// api-spec(llvm): declare void @kclvm_schema_assert(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %value, %kclvm_value_ref_t* %msg, %kclvm_value_ref_t* %config_meta); // api-spec: kclvm_schema_value_new // api-spec(c): kclvm_value_ref_t* kclvm_schema_value_new(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs, kclvm_value_ref_t* schema_value_or_func, kclvm_value_ref_t* config, kclvm_value_ref_t* config_meta, kclvm_char_t* pkgpath); // api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_schema_value_new(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs, %kclvm_value_ref_t* %schema_value_or_func, %kclvm_value_ref_t* %config, %kclvm_value_ref_t* %config_meta, %kclvm_char_t* %pkgpath); // api-spec: kclvm_convert_collection_value -// api-spec(c): kclvm_value_ref_t* kclvm_convert_collection_value(kclvm_value_ref_t* value, kclvm_char_t* tpe); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_convert_collection_value(%kclvm_value_ref_t* %value, %kclvm_char_t* %tpe); +// api-spec(c): kclvm_value_ref_t* kclvm_convert_collection_value(kclvm_context_t* ctx, kclvm_value_ref_t* value, kclvm_char_t* tpe, kclvm_value_ref_t* is_in_schema); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_convert_collection_value(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %value, %kclvm_char_t* %tpe, %kclvm_value_ref_t* %is_in_schema); // api-spec: kclvm_schema_get_value -// api-spec(c): kclvm_value_ref_t* kclvm_schema_get_value(kclvm_value_ref_t* p, kclvm_char_t* key, kclvm_value_ref_t* config, kclvm_value_ref_t* config_meta, kclvm_value_ref_t* cal_map, kclvm_char_t* target_attr, kclvm_value_ref_t* backtrack_level_map, kclvm_value_ref_t* backtrack_cache, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_schema_get_value(%kclvm_value_ref_t* %p, %kclvm_char_t* %key, %kclvm_value_ref_t* %config, %kclvm_value_ref_t* %config_meta, %kclvm_value_ref_t* %cal_map, %kclvm_char_t* %target_attr, %kclvm_value_ref_t* %backtrack_level_map, %kclvm_value_ref_t* %backtrack_cache, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); +// api-spec(c): kclvm_value_ref_t* kclvm_schema_get_value(kclvm_context_t* ctx, kclvm_value_ref_t* p, kclvm_char_t* key, kclvm_value_ref_t* config, kclvm_value_ref_t* config_meta, kclvm_value_ref_t* cal_map, kclvm_char_t* target_attr, kclvm_value_ref_t* backtrack_level_map, kclvm_value_ref_t* backtrack_cache, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_schema_get_value(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %p, %kclvm_char_t* %key, %kclvm_value_ref_t* %config, %kclvm_value_ref_t* %config_meta, %kclvm_value_ref_t* %cal_map, %kclvm_char_t* %target_attr, %kclvm_value_ref_t* %backtrack_level_map, %kclvm_value_ref_t* %backtrack_cache, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); // api-spec: kclvm_config_attr_map // api-spec(c): void kclvm_config_attr_map(kclvm_value_ref_t* value, kclvm_char_t* name, kclvm_char_t* type_str); // api-spec(llvm): declare void @kclvm_config_attr_map(%kclvm_value_ref_t* %value, %kclvm_char_t* %name, %kclvm_char_t* %type_str); // api-spec: kclvm_value_Decorator -// api-spec(c): kclvm_decorator_value_t* kclvm_value_Decorator(kclvm_char_t* name, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs, kclvm_value_ref_t* config_meta, kclvm_char_t* attr_name, kclvm_value_ref_t* config_value, kclvm_value_ref_t* is_schema_target); -// api-spec(llvm): declare %kclvm_decorator_value_t* @kclvm_value_Decorator(%kclvm_char_t* %name, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs, %kclvm_value_ref_t* %config_meta, %kclvm_char_t* %attr_name, %kclvm_value_ref_t* %config_value, %kclvm_value_ref_t* %is_schema_target); +// api-spec(c): kclvm_decorator_value_t* kclvm_value_Decorator(kclvm_context_t* ctx, kclvm_char_t* name, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs, kclvm_value_ref_t* config_meta, kclvm_char_t* attr_name, kclvm_value_ref_t* config_value, kclvm_value_ref_t* is_schema_target); +// api-spec(llvm): declare %kclvm_decorator_value_t* @kclvm_value_Decorator(%kclvm_context_t* %ctx, %kclvm_char_t* %name, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs, %kclvm_value_ref_t* %config_meta, %kclvm_char_t* %attr_name, %kclvm_value_ref_t* %config_value, %kclvm_value_ref_t* %is_schema_target); // api-spec: kclvm_builtin_str_lower -// api-spec(c): kclvm_value_ref_t* kclvm_builtin_str_lower(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_builtin_str_lower(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +// api-spec(c): kclvm_value_ref_t* kclvm_builtin_str_lower(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_builtin_str_lower(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); // api-spec: kclvm_builtin_str_upper -// api-spec(c): kclvm_value_ref_t* kclvm_builtin_str_upper(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_builtin_str_upper(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +// api-spec(c): kclvm_value_ref_t* kclvm_builtin_str_upper(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_builtin_str_upper(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); // api-spec: kclvm_builtin_str_capitalize -// api-spec(c): kclvm_value_ref_t* kclvm_builtin_str_capitalize(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_builtin_str_capitalize(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +// api-spec(c): kclvm_value_ref_t* kclvm_builtin_str_capitalize(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_builtin_str_capitalize(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); + +// api-spec: kclvm_builtin_str_chars +// api-spec(c): kclvm_value_ref_t* kclvm_builtin_str_chars(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_builtin_str_chars(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); // api-spec: kclvm_builtin_str_count -// api-spec(c): kclvm_value_ref_t* kclvm_builtin_str_count(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_builtin_str_count(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +// api-spec(c): kclvm_value_ref_t* kclvm_builtin_str_count(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_builtin_str_count(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); // api-spec: kclvm_builtin_str_endswith -// api-spec(c): kclvm_value_ref_t* kclvm_builtin_str_endswith(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_builtin_str_endswith(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +// api-spec(c): kclvm_value_ref_t* kclvm_builtin_str_endswith(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_builtin_str_endswith(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); // api-spec: kclvm_builtin_str_find -// api-spec(c): kclvm_value_ref_t* kclvm_builtin_str_find(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_builtin_str_find(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +// api-spec(c): kclvm_value_ref_t* kclvm_builtin_str_find(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_builtin_str_find(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); // api-spec: kclvm_builtin_str_format -// api-spec(c): kclvm_value_ref_t* kclvm_builtin_str_format(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_builtin_str_format(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); +// api-spec(c): kclvm_value_ref_t* kclvm_builtin_str_format(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_builtin_str_format(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); // api-spec: kclvm_builtin_str_index -// api-spec(c): kclvm_value_ref_t* kclvm_builtin_str_index(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_builtin_str_index(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +// api-spec(c): kclvm_value_ref_t* kclvm_builtin_str_index(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_builtin_str_index(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); // api-spec: kclvm_builtin_str_isalnum -// api-spec(c): kclvm_value_ref_t* kclvm_builtin_str_isalnum(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_builtin_str_isalnum(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +// api-spec(c): kclvm_value_ref_t* kclvm_builtin_str_isalnum(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_builtin_str_isalnum(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); // api-spec: kclvm_builtin_str_isalpha -// api-spec(c): kclvm_value_ref_t* kclvm_builtin_str_isalpha(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_builtin_str_isalpha(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +// api-spec(c): kclvm_value_ref_t* kclvm_builtin_str_isalpha(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_builtin_str_isalpha(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); // api-spec: kclvm_builtin_str_isdigit -// api-spec(c): kclvm_value_ref_t* kclvm_builtin_str_isdigit(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_builtin_str_isdigit(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +// api-spec(c): kclvm_value_ref_t* kclvm_builtin_str_isdigit(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_builtin_str_isdigit(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); // api-spec: kclvm_builtin_str_islower -// api-spec(c): kclvm_value_ref_t* kclvm_builtin_str_islower(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_builtin_str_islower(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +// api-spec(c): kclvm_value_ref_t* kclvm_builtin_str_islower(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_builtin_str_islower(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); // api-spec: kclvm_builtin_str_isspace -// api-spec(c): kclvm_value_ref_t* kclvm_builtin_str_isspace(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_builtin_str_isspace(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +// api-spec(c): kclvm_value_ref_t* kclvm_builtin_str_isspace(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_builtin_str_isspace(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); // api-spec: kclvm_builtin_str_istitle -// api-spec(c): kclvm_value_ref_t* kclvm_builtin_str_istitle(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_builtin_str_istitle(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +// api-spec(c): kclvm_value_ref_t* kclvm_builtin_str_istitle(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_builtin_str_istitle(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); // api-spec: kclvm_builtin_str_isupper -// api-spec(c): kclvm_value_ref_t* kclvm_builtin_str_isupper(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_builtin_str_isupper(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +// api-spec(c): kclvm_value_ref_t* kclvm_builtin_str_isupper(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_builtin_str_isupper(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); // api-spec: kclvm_builtin_str_join -// api-spec(c): kclvm_value_ref_t* kclvm_builtin_str_join(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_builtin_str_join(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +// api-spec(c): kclvm_value_ref_t* kclvm_builtin_str_join(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_builtin_str_join(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); // api-spec: kclvm_builtin_str_lstrip -// api-spec(c): kclvm_value_ref_t* kclvm_builtin_str_lstrip(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_builtin_str_lstrip(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +// api-spec(c): kclvm_value_ref_t* kclvm_builtin_str_lstrip(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_builtin_str_lstrip(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); // api-spec: kclvm_builtin_str_rstrip -// api-spec(c): kclvm_value_ref_t* kclvm_builtin_str_rstrip(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_builtin_str_rstrip(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +// api-spec(c): kclvm_value_ref_t* kclvm_builtin_str_rstrip(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_builtin_str_rstrip(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); // api-spec: kclvm_builtin_str_replace -// api-spec(c): kclvm_value_ref_t* kclvm_builtin_str_replace(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_builtin_str_replace(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +// api-spec(c): kclvm_value_ref_t* kclvm_builtin_str_replace(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_builtin_str_replace(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); + +// api-spec: kclvm_builtin_str_removeprefix +// api-spec(c): kclvm_value_ref_t* kclvm_builtin_str_removeprefix(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_builtin_str_removeprefix(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); + +// api-spec: kclvm_builtin_str_removesuffix +// api-spec(c): kclvm_value_ref_t* kclvm_builtin_str_removesuffix(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_builtin_str_removesuffix(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); // api-spec: kclvm_builtin_str_rfind -// api-spec(c): kclvm_value_ref_t* kclvm_builtin_str_rfind(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_builtin_str_rfind(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +// api-spec(c): kclvm_value_ref_t* kclvm_builtin_str_rfind(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_builtin_str_rfind(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); // api-spec: kclvm_builtin_str_rindex -// api-spec(c): kclvm_value_ref_t* kclvm_builtin_str_rindex(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_builtin_str_rindex(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +// api-spec(c): kclvm_value_ref_t* kclvm_builtin_str_rindex(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_builtin_str_rindex(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); // api-spec: kclvm_builtin_str_rsplit -// api-spec(c): kclvm_value_ref_t* kclvm_builtin_str_rsplit(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_builtin_str_rsplit(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); +// api-spec(c): kclvm_value_ref_t* kclvm_builtin_str_rsplit(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_builtin_str_rsplit(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); // api-spec: kclvm_builtin_str_split -// api-spec(c): kclvm_value_ref_t* kclvm_builtin_str_split(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_builtin_str_split(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); +// api-spec(c): kclvm_value_ref_t* kclvm_builtin_str_split(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_builtin_str_split(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); // api-spec: kclvm_builtin_str_splitlines -// api-spec(c): kclvm_value_ref_t* kclvm_builtin_str_splitlines(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_builtin_str_splitlines(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); +// api-spec(c): kclvm_value_ref_t* kclvm_builtin_str_splitlines(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_builtin_str_splitlines(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); // api-spec: kclvm_builtin_str_startswith -// api-spec(c): kclvm_value_ref_t* kclvm_builtin_str_startswith(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_builtin_str_startswith(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +// api-spec(c): kclvm_value_ref_t* kclvm_builtin_str_startswith(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_builtin_str_startswith(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); // api-spec: kclvm_builtin_str_strip -// api-spec(c): kclvm_value_ref_t* kclvm_builtin_str_strip(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_builtin_str_strip(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +// api-spec(c): kclvm_value_ref_t* kclvm_builtin_str_strip(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_builtin_str_strip(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); // api-spec: kclvm_builtin_str_title -// api-spec(c): kclvm_value_ref_t* kclvm_builtin_str_title(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_builtin_str_title(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +// api-spec(c): kclvm_value_ref_t* kclvm_builtin_str_title(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_builtin_str_title(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); // api-spec: kclvm_base64_encode -// api-spec(c): kclvm_value_ref_t* kclvm_base64_encode(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_base64_encode(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +// api-spec(c): kclvm_value_ref_t* kclvm_base64_encode(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_base64_encode(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); // api-spec: kclvm_base64_decode -// api-spec(c): kclvm_value_ref_t* kclvm_base64_decode(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_base64_decode(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +// api-spec(c): kclvm_value_ref_t* kclvm_base64_decode(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_base64_decode(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); // api-spec: kclvm_value_union_all -// api-spec(c): kclvm_value_ref_t* kclvm_value_union_all(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_union_all(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +// api-spec(c): kclvm_value_ref_t* kclvm_value_union_all(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_union_all(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); // api-spec: kclvm_crypto_md5 -// api-spec(c): kclvm_value_ref_t* kclvm_crypto_md5(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_crypto_md5(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +// api-spec(c): kclvm_value_ref_t* kclvm_crypto_md5(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_crypto_md5(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); // api-spec: kclvm_crypto_sha1 -// api-spec(c): kclvm_value_ref_t* kclvm_crypto_sha1(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_crypto_sha1(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +// api-spec(c): kclvm_value_ref_t* kclvm_crypto_sha1(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_crypto_sha1(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); // api-spec: kclvm_crypto_sha224 -// api-spec(c): kclvm_value_ref_t* kclvm_crypto_sha224(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_crypto_sha224(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +// api-spec(c): kclvm_value_ref_t* kclvm_crypto_sha224(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_crypto_sha224(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); // api-spec: kclvm_crypto_sha256 -// api-spec(c): kclvm_value_ref_t* kclvm_crypto_sha256(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_crypto_sha256(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +// api-spec(c): kclvm_value_ref_t* kclvm_crypto_sha256(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_crypto_sha256(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); // api-spec: kclvm_crypto_sha384 -// api-spec(c): kclvm_value_ref_t* kclvm_crypto_sha384(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_crypto_sha384(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +// api-spec(c): kclvm_value_ref_t* kclvm_crypto_sha384(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_crypto_sha384(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); // api-spec: kclvm_crypto_sha512 -// api-spec(c): kclvm_value_ref_t* kclvm_crypto_sha512(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_crypto_sha512(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +// api-spec(c): kclvm_value_ref_t* kclvm_crypto_sha512(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_crypto_sha512(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); + +// api-spec: kclvm_crypto_blake3 +// api-spec(c): kclvm_value_ref_t* kclvm_crypto_blake3(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_crypto_blake3(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); + +// api-spec: kclvm_crypto_uuid +// api-spec(c): kclvm_value_ref_t* kclvm_crypto_uuid(kclvm_context_t* ctx, kclvm_value_ref_t* _args, kclvm_value_ref_t* _kwargs); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_crypto_uuid(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %_args, %kclvm_value_ref_t* %_kwargs); + +// api-spec: kclvm_crypto_filesha256 +// api-spec(c): kclvm_value_ref_t* kclvm_crypto_filesha256(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_crypto_filesha256(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); + +// api-spec: kclvm_crypto_filesha512 +// api-spec(c): kclvm_value_ref_t* kclvm_crypto_filesha512(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_crypto_filesha512(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); + +// api-spec: kclvm_crypto_fileblake3 +// api-spec(c): kclvm_value_ref_t* kclvm_crypto_fileblake3(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_crypto_fileblake3(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); // api-spec: kclvm_datetime_today -// api-spec(c): kclvm_value_ref_t* kclvm_datetime_today(kclvm_context_t* _ctx, kclvm_value_ref_t* _args, kclvm_value_ref_t* _kwargs); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_datetime_today(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %_args, %kclvm_value_ref_t* %_kwargs); +// api-spec(c): kclvm_value_ref_t* kclvm_datetime_today(kclvm_context_t* ctx, kclvm_value_ref_t* _args, kclvm_value_ref_t* _kwargs); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_datetime_today(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %_args, %kclvm_value_ref_t* %_kwargs); // api-spec: kclvm_datetime_now -// api-spec(c): kclvm_value_ref_t* kclvm_datetime_now(kclvm_context_t* _ctx, kclvm_value_ref_t* _args, kclvm_value_ref_t* _kwargs); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_datetime_now(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %_args, %kclvm_value_ref_t* %_kwargs); +// api-spec(c): kclvm_value_ref_t* kclvm_datetime_now(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_datetime_now(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); // api-spec: kclvm_datetime_ticks -// api-spec(c): kclvm_value_ref_t* kclvm_datetime_ticks(kclvm_context_t* _ctx, kclvm_value_ref_t* _args, kclvm_value_ref_t* _kwargs); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_datetime_ticks(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %_args, %kclvm_value_ref_t* %_kwargs); +// api-spec(c): kclvm_value_ref_t* kclvm_datetime_ticks(kclvm_context_t* ctx, kclvm_value_ref_t* _args, kclvm_value_ref_t* _kwargs); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_datetime_ticks(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %_args, %kclvm_value_ref_t* %_kwargs); // api-spec: kclvm_datetime_date -// api-spec(c): kclvm_value_ref_t* kclvm_datetime_date(kclvm_context_t* _ctx, kclvm_value_ref_t* _args, kclvm_value_ref_t* _kwargs); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_datetime_date(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %_args, %kclvm_value_ref_t* %_kwargs); +// api-spec(c): kclvm_value_ref_t* kclvm_datetime_date(kclvm_context_t* ctx, kclvm_value_ref_t* _args, kclvm_value_ref_t* _kwargs); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_datetime_date(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %_args, %kclvm_value_ref_t* %_kwargs); + +// api-spec: kclvm_datetime_validate +// api-spec(c): kclvm_value_ref_t* kclvm_datetime_validate(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_datetime_validate(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); // api-spec: kclvm_json_encode -// api-spec(c): kclvm_value_ref_t* kclvm_json_encode(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_json_encode(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); +// api-spec(c): kclvm_value_ref_t* kclvm_json_encode(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_json_encode(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); // api-spec: kclvm_json_decode -// api-spec(c): kclvm_value_ref_t* kclvm_json_decode(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_json_decode(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +// api-spec(c): kclvm_value_ref_t* kclvm_json_decode(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_json_decode(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); + +// api-spec: kclvm_json_validate +// api-spec(c): kclvm_value_ref_t* kclvm_json_validate(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_json_validate(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); // api-spec: kclvm_json_dump_to_file -// api-spec(c): kclvm_value_ref_t* kclvm_json_dump_to_file(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_json_dump_to_file(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +// api-spec(c): kclvm_value_ref_t* kclvm_json_dump_to_file(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_json_dump_to_file(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); + +// api-spec: kclvm_manifests_yaml_stream +// api-spec(c): kclvm_value_ref_t* kclvm_manifests_yaml_stream(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_manifests_yaml_stream(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); // api-spec: kclvm_math_ceil -// api-spec(c): kclvm_value_ref_t* kclvm_math_ceil(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_math_ceil(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +// api-spec(c): kclvm_value_ref_t* kclvm_math_ceil(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_math_ceil(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); // api-spec: kclvm_math_factorial -// api-spec(c): kclvm_value_ref_t* kclvm_math_factorial(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_math_factorial(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +// api-spec(c): kclvm_value_ref_t* kclvm_math_factorial(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_math_factorial(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); // api-spec: kclvm_math_floor -// api-spec(c): kclvm_value_ref_t* kclvm_math_floor(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_math_floor(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +// api-spec(c): kclvm_value_ref_t* kclvm_math_floor(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_math_floor(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); // api-spec: kclvm_math_gcd -// api-spec(c): kclvm_value_ref_t* kclvm_math_gcd(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_math_gcd(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +// api-spec(c): kclvm_value_ref_t* kclvm_math_gcd(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_math_gcd(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); // api-spec: kclvm_math_isfinite -// api-spec(c): kclvm_value_ref_t* kclvm_math_isfinite(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_math_isfinite(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +// api-spec(c): kclvm_value_ref_t* kclvm_math_isfinite(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_math_isfinite(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); // api-spec: kclvm_math_isinf -// api-spec(c): kclvm_value_ref_t* kclvm_math_isinf(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_math_isinf(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +// api-spec(c): kclvm_value_ref_t* kclvm_math_isinf(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_math_isinf(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); // api-spec: kclvm_math_isnan -// api-spec(c): kclvm_value_ref_t* kclvm_math_isnan(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_math_isnan(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +// api-spec(c): kclvm_value_ref_t* kclvm_math_isnan(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_math_isnan(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); // api-spec: kclvm_math_modf -// api-spec(c): kclvm_value_ref_t* kclvm_math_modf(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_math_modf(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +// api-spec(c): kclvm_value_ref_t* kclvm_math_modf(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_math_modf(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); // api-spec: kclvm_math_exp -// api-spec(c): kclvm_value_ref_t* kclvm_math_exp(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_math_exp(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +// api-spec(c): kclvm_value_ref_t* kclvm_math_exp(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_math_exp(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); // api-spec: kclvm_math_expm1 -// api-spec(c): kclvm_value_ref_t* kclvm_math_expm1(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_math_expm1(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +// api-spec(c): kclvm_value_ref_t* kclvm_math_expm1(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_math_expm1(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); // api-spec: kclvm_math_log -// api-spec(c): kclvm_value_ref_t* kclvm_math_log(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_math_log(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +// api-spec(c): kclvm_value_ref_t* kclvm_math_log(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_math_log(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); // api-spec: kclvm_math_log1p -// api-spec(c): kclvm_value_ref_t* kclvm_math_log1p(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_math_log1p(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +// api-spec(c): kclvm_value_ref_t* kclvm_math_log1p(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_math_log1p(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); // api-spec: kclvm_math_log2 -// api-spec(c): kclvm_value_ref_t* kclvm_math_log2(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_math_log2(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +// api-spec(c): kclvm_value_ref_t* kclvm_math_log2(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_math_log2(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); // api-spec: kclvm_math_log10 -// api-spec(c): kclvm_value_ref_t* kclvm_math_log10(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_math_log10(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +// api-spec(c): kclvm_value_ref_t* kclvm_math_log10(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_math_log10(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); // api-spec: kclvm_math_pow -// api-spec(c): kclvm_value_ref_t* kclvm_math_pow(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_math_pow(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +// api-spec(c): kclvm_value_ref_t* kclvm_math_pow(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_math_pow(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); // api-spec: kclvm_math_sqrt -// api-spec(c): kclvm_value_ref_t* kclvm_math_sqrt(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_math_sqrt(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +// api-spec(c): kclvm_value_ref_t* kclvm_math_sqrt(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_math_sqrt(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); // api-spec: kclvm_net_split_host_port -// api-spec(c): kclvm_value_ref_t* kclvm_net_split_host_port(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_net_split_host_port(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +// api-spec(c): kclvm_value_ref_t* kclvm_net_split_host_port(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_net_split_host_port(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); // api-spec: kclvm_net_join_host_port -// api-spec(c): kclvm_value_ref_t* kclvm_net_join_host_port(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_net_join_host_port(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +// api-spec(c): kclvm_value_ref_t* kclvm_net_join_host_port(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_net_join_host_port(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); // api-spec: kclvm_net_fqdn -// api-spec(c): kclvm_value_ref_t* kclvm_net_fqdn(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_net_fqdn(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +// api-spec(c): kclvm_value_ref_t* kclvm_net_fqdn(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_net_fqdn(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); // api-spec: kclvm_net_parse_IP // api-spec(c): kclvm_value_ref_t* kclvm_net_parse_IP(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); @@ -1119,103 +947,75 @@ // api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_net_to_IP16(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); // api-spec: kclvm_net_IP_string -// api-spec(c): kclvm_value_ref_t* kclvm_net_IP_string(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_net_IP_string(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +// api-spec(c): kclvm_value_ref_t* kclvm_net_IP_string(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_net_IP_string(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); // api-spec: kclvm_net_is_IPv4 -// api-spec(c): kclvm_value_ref_t* kclvm_net_is_IPv4(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_net_is_IPv4(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +// api-spec(c): kclvm_value_ref_t* kclvm_net_is_IPv4(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_net_is_IPv4(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); // api-spec: kclvm_net_is_IP -// api-spec(c): kclvm_value_ref_t* kclvm_net_is_IP(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_net_is_IP(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +// api-spec(c): kclvm_value_ref_t* kclvm_net_is_IP(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_net_is_IP(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); // api-spec: kclvm_net_is_loopback_IP -// api-spec(c): kclvm_value_ref_t* kclvm_net_is_loopback_IP(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_net_is_loopback_IP(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +// api-spec(c): kclvm_value_ref_t* kclvm_net_is_loopback_IP(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_net_is_loopback_IP(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); // api-spec: kclvm_net_is_multicast_IP -// api-spec(c): kclvm_value_ref_t* kclvm_net_is_multicast_IP(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_net_is_multicast_IP(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +// api-spec(c): kclvm_value_ref_t* kclvm_net_is_multicast_IP(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_net_is_multicast_IP(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); // api-spec: kclvm_net_is_interface_local_multicast_IP -// api-spec(c): kclvm_value_ref_t* kclvm_net_is_interface_local_multicast_IP(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_net_is_interface_local_multicast_IP(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +// api-spec(c): kclvm_value_ref_t* kclvm_net_is_interface_local_multicast_IP(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_net_is_interface_local_multicast_IP(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); // api-spec: kclvm_net_is_link_local_multicast_IP -// api-spec(c): kclvm_value_ref_t* kclvm_net_is_link_local_multicast_IP(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_net_is_link_local_multicast_IP(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +// api-spec(c): kclvm_value_ref_t* kclvm_net_is_link_local_multicast_IP(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_net_is_link_local_multicast_IP(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); // api-spec: kclvm_net_is_link_local_unicast_IP // api-spec(c): kclvm_value_ref_t* kclvm_net_is_link_local_unicast_IP(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); // api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_net_is_link_local_unicast_IP(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); // api-spec: kclvm_net_is_global_unicast_IP -// api-spec(c): kclvm_value_ref_t* kclvm_net_is_global_unicast_IP(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_net_is_global_unicast_IP(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +// api-spec(c): kclvm_value_ref_t* kclvm_net_is_global_unicast_IP(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_net_is_global_unicast_IP(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); // api-spec: kclvm_net_is_unspecified_IP -// api-spec(c): kclvm_value_ref_t* kclvm_net_is_unspecified_IP(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_net_is_unspecified_IP(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +// api-spec(c): kclvm_value_ref_t* kclvm_net_is_unspecified_IP(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_net_is_unspecified_IP(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); // api-spec: kclvm_regex_match -// api-spec(c): kclvm_value_ref_t* kclvm_regex_match(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_regex_match(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +// api-spec(c): kclvm_value_ref_t* kclvm_regex_match(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_regex_match(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); // api-spec: kclvm_regex_replace -// api-spec(c): kclvm_value_ref_t* kclvm_regex_replace(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_regex_replace(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +// api-spec(c): kclvm_value_ref_t* kclvm_regex_replace(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_regex_replace(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); // api-spec: kclvm_regex_compile -// api-spec(c): kclvm_value_ref_t* kclvm_regex_compile(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_regex_compile(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +// api-spec(c): kclvm_value_ref_t* kclvm_regex_compile(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_regex_compile(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); // api-spec: kclvm_regex_findall -// api-spec(c): kclvm_value_ref_t* kclvm_regex_findall(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_regex_findall(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +// api-spec(c): kclvm_value_ref_t* kclvm_regex_findall(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_regex_findall(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); // api-spec: kclvm_regex_search -// api-spec(c): kclvm_value_ref_t* kclvm_regex_search(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_regex_search(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +// api-spec(c): kclvm_value_ref_t* kclvm_regex_search(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_regex_search(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); // api-spec: kclvm_regex_split -// api-spec(c): kclvm_value_ref_t* kclvm_regex_split(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_regex_split(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +// api-spec(c): kclvm_value_ref_t* kclvm_regex_split(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_regex_split(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); // api-spec: kclvm_assert -// api-spec(c): void kclvm_assert(kclvm_value_ref_t* value, kclvm_value_ref_t* msg); -// api-spec(llvm): declare void @kclvm_assert(%kclvm_value_ref_t* %value, %kclvm_value_ref_t* %msg); - -// api-spec: kclvm_debug_hello -// api-spec(c): void kclvm_debug_hello(); -// api-spec(llvm): declare void @kclvm_debug_hello(); - -// api-spec: kclvm_debug_print -// api-spec(c): void kclvm_debug_print(int8_t* cs); -// api-spec(llvm): declare void @kclvm_debug_print(i8* %cs); - -// api-spec: kclvm_debug_print_str_list -// api-spec(c): void kclvm_debug_print_str_list(int32_t len, int8_t** ss); -// api-spec(llvm): declare void @kclvm_debug_print_str_list(i32 %len, i8** %ss); - -// api-spec: kclvm_debug_print_type -// api-spec(c): void kclvm_debug_print_type(kclvm_type_t* p); -// api-spec(llvm): declare void @kclvm_debug_print_type(%kclvm_type_t* %p); - -// api-spec: kclvm_debug_print_value -// api-spec(c): void kclvm_debug_print_value(kclvm_value_ref_t* p); -// api-spec(llvm): declare void @kclvm_debug_print_value(%kclvm_value_ref_t* %p); - -// api-spec: kclvm_debug_print_value_json_string -// api-spec(c): void kclvm_debug_print_value_json_string(kclvm_value_ref_t* p); -// api-spec(llvm): declare void @kclvm_debug_print_value_json_string(%kclvm_value_ref_t* %p); - -// api-spec: kclvm_debug_invoke_func -// api-spec(c): void kclvm_debug_invoke_func(void* fn_ptr); -// api-spec(llvm): declare void @kclvm_debug_invoke_func(i8* %fn_ptr); +// api-spec(c): void kclvm_assert(kclvm_context_t* ctx, kclvm_value_ref_t* value, kclvm_value_ref_t* msg); +// api-spec(llvm): declare void @kclvm_assert(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %value, %kclvm_value_ref_t* %msg); // api-spec: kclvm_builtin_option_init -// api-spec(c): void kclvm_builtin_option_init(kclvm_context_t* ctx, int8_t* key, int8_t* value); +// api-spec(c): void kclvm_builtin_option_init(kclvm_context_t* ctx, char* key, char* value); // api-spec(llvm): declare void @kclvm_builtin_option_init(%kclvm_context_t* %ctx, i8* %key, i8* %value); // api-spec: kclvm_builtin_option_reset @@ -1231,8 +1031,8 @@ // api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_builtin_print(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); // api-spec: kclvm_builtin_len -// api-spec(c): kclvm_value_ref_t* kclvm_builtin_len(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_builtin_len(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +// api-spec(c): kclvm_value_ref_t* kclvm_builtin_len(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_builtin_len(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); // api-spec: kclvm_builtin_any_true // api-spec(c): kclvm_value_ref_t* kclvm_builtin_any_true(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); @@ -1255,20 +1055,20 @@ // api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_builtin_float(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); // api-spec: kclvm_builtin_bool -// api-spec(c): kclvm_value_ref_t* kclvm_builtin_bool(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_builtin_bool(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +// api-spec(c): kclvm_value_ref_t* kclvm_builtin_bool(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_builtin_bool(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); // api-spec: kclvm_builtin_str -// api-spec(c): kclvm_value_ref_t* kclvm_builtin_str(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_builtin_str(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +// api-spec(c): kclvm_value_ref_t* kclvm_builtin_str(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_builtin_str(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); // api-spec: kclvm_builtin_max -// api-spec(c): kclvm_value_ref_t* kclvm_builtin_max(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_builtin_max(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); +// api-spec(c): kclvm_value_ref_t* kclvm_builtin_max(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_builtin_max(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); // api-spec: kclvm_builtin_min -// api-spec(c): kclvm_value_ref_t* kclvm_builtin_min(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_builtin_min(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); +// api-spec(c): kclvm_value_ref_t* kclvm_builtin_min(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_builtin_min(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); // api-spec: kclvm_builtin_multiplyof // api-spec(c): kclvm_value_ref_t* kclvm_builtin_multiplyof(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); @@ -1299,8 +1099,8 @@ // api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_builtin_round(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); // api-spec: kclvm_builtin_zip -// api-spec(c): kclvm_value_ref_t* kclvm_builtin_zip(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_builtin_zip(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); +// api-spec(c): kclvm_value_ref_t* kclvm_builtin_zip(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_builtin_zip(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); // api-spec: kclvm_builtin_list // api-spec(c): kclvm_value_ref_t* kclvm_builtin_list(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); @@ -1330,26 +1130,22 @@ // api-spec(c): kclvm_value_ref_t* kclvm_builtin_range(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); // api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_builtin_range(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); +// api-spec: kclvm_builtin_isnullish +// api-spec(c): kclvm_value_ref_t* kclvm_builtin_isnullish(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_builtin_isnullish(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); + // api-spec: kclvm_plugin_init // api-spec(c): void kclvm_plugin_init(void* fn_ptr); // api-spec(llvm): declare void @kclvm_plugin_init(i8* %fn_ptr); // api-spec: kclvm_plugin_invoke -// api-spec(c): kclvm_value_ref_t* kclvm_plugin_invoke(int8_t* method, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_plugin_invoke(i8* %method, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); +// api-spec(c): kclvm_value_ref_t* kclvm_plugin_invoke(kclvm_context_t* ctx, char* method, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_plugin_invoke(%kclvm_context_t* %ctx, i8* %method, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); // api-spec: kclvm_plugin_invoke_json -// api-spec(c): char* kclvm_plugin_invoke_json(int8_t* method, char* args, char* kwargs); +// api-spec(c): char* kclvm_plugin_invoke_json(char* method, char* args, char* kwargs); // api-spec(llvm): declare i8* @kclvm_plugin_invoke_json(i8* %method, i8* %args, i8* %kwargs); -// api-spec: kclvm_testing_arguments -// api-spec(c): void kclvm_testing_arguments(kclvm_context_t* _ctx, kclvm_value_ref_t* _args, kclvm_value_ref_t* _kwargs); -// api-spec(llvm): declare void @kclvm_testing_arguments(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %_args, %kclvm_value_ref_t* %_kwargs); - -// api-spec: kclvm_testing_setting_file -// api-spec(c): void kclvm_testing_setting_file(kclvm_context_t* _ctx, kclvm_value_ref_t* _args, kclvm_value_ref_t* _kwargs); -// api-spec(llvm): declare void @kclvm_testing_setting_file(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %_args, %kclvm_value_ref_t* %_kwargs); - // api-spec: kclvm_units_to_n // api-spec(c): kclvm_value_ref_t* kclvm_units_to_n(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); // api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_units_to_n(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); @@ -1403,14 +1199,102 @@ // api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_units_to_Pi(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); // api-spec: kclvm_yaml_encode -// api-spec(c): kclvm_value_ref_t* kclvm_yaml_encode(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_yaml_encode(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); +// api-spec(c): kclvm_value_ref_t* kclvm_yaml_encode(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_yaml_encode(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); + +// api-spec: kclvm_yaml_encode_all +// api-spec(c): kclvm_value_ref_t* kclvm_yaml_encode_all(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_yaml_encode_all(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); // api-spec: kclvm_yaml_decode -// api-spec(c): kclvm_value_ref_t* kclvm_yaml_decode(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_yaml_decode(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +// api-spec(c): kclvm_value_ref_t* kclvm_yaml_decode(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_yaml_decode(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); + +// api-spec: kclvm_yaml_decode_all +// api-spec(c): kclvm_value_ref_t* kclvm_yaml_decode_all(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_yaml_decode_all(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); // api-spec: kclvm_yaml_dump_to_file -// api-spec(c): kclvm_value_ref_t* kclvm_yaml_dump_to_file(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); -// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_yaml_dump_to_file(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +// api-spec(c): kclvm_value_ref_t* kclvm_yaml_dump_to_file(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_yaml_dump_to_file(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); + +// api-spec: kclvm_yaml_dump_all_to_file +// api-spec(c): kclvm_value_ref_t* kclvm_yaml_dump_all_to_file(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_yaml_dump_all_to_file(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); + +// api-spec: kclvm_yaml_validate +// api-spec(c): kclvm_value_ref_t* kclvm_yaml_validate(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_yaml_validate(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); + +// api-spec: kclvm_file_read +// api-spec(c): kclvm_value_ref_t* kclvm_file_read(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_file_read(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); + +// api-spec: kclvm_file_glob +// api-spec(c): kclvm_value_ref_t* kclvm_file_glob(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_file_glob(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); + +// api-spec: kclvm_file_modpath +// api-spec(c): kclvm_value_ref_t* kclvm_file_modpath(kclvm_context_t* ctx, kclvm_value_ref_t* _args, kclvm_value_ref_t* _kwargs); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_file_modpath(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %_args, %kclvm_value_ref_t* %_kwargs); + +// api-spec: kclvm_file_workdir +// api-spec(c): kclvm_value_ref_t* kclvm_file_workdir(kclvm_context_t* ctx, kclvm_value_ref_t* _args, kclvm_value_ref_t* _kwargs); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_file_workdir(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %_args, %kclvm_value_ref_t* %_kwargs); + +// api-spec: kclvm_file_current +// api-spec(c): kclvm_value_ref_t* kclvm_file_current(kclvm_context_t* ctx, kclvm_value_ref_t* _args, kclvm_value_ref_t* _kwargs); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_file_current(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %_args, %kclvm_value_ref_t* %_kwargs); + +// api-spec: kclvm_file_exists +// api-spec(c): kclvm_value_ref_t* kclvm_file_exists(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_file_exists(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); + +// api-spec: kclvm_file_abs +// api-spec(c): kclvm_value_ref_t* kclvm_file_abs(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_file_abs(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); + +// api-spec: kclvm_file_mkdir +// api-spec(c): kclvm_value_ref_t* kclvm_file_mkdir(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_file_mkdir(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); + +// api-spec: kclvm_file_delete +// api-spec(c): kclvm_value_ref_t* kclvm_file_delete(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_file_delete(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); + +// api-spec: kclvm_file_cp +// api-spec(c): kclvm_value_ref_t* kclvm_file_cp(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_file_cp(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); + +// api-spec: kclvm_file_mv +// api-spec(c): kclvm_value_ref_t* kclvm_file_mv(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_file_mv(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); + +// api-spec: kclvm_file_size +// api-spec(c): kclvm_value_ref_t* kclvm_file_size(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_file_size(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); + +// api-spec: kclvm_file_write +// api-spec(c): kclvm_value_ref_t* kclvm_file_write(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_file_write(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); + +// api-spec: kclvm_file_append +// api-spec(c): kclvm_value_ref_t* kclvm_file_append(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_file_append(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); + +// api-spec: kclvm_file_read_env +// api-spec(c): kclvm_value_ref_t* kclvm_file_read_env(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_file_read_env(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); + +// api-spec: kclvm_template_execute +// api-spec(c): kclvm_value_ref_t* kclvm_template_execute(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_template_execute(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); + +// api-spec: kclvm_template_html_escape +// api-spec(c): kclvm_value_ref_t* kclvm_template_html_escape(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_template_html_escape(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); + +// api-spec: kclvm_runtime_catch +// api-spec(c): kclvm_value_ref_t* kclvm_runtime_catch(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_runtime_catch(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); diff --git a/kclvm/runtime/src/_kclvm_main_win.c b/kclvm/runtime/src/_kclvm_main_win.c deleted file mode 100644 index 917efac53..000000000 --- a/kclvm/runtime/src/_kclvm_main_win.c +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2021 The KCL Authors. All rights reserved. - -extern void* kclvm_main(void* ctx); - -extern void kclvm_debug_hello(); -extern void kclvm_debug_print(const char* s); - -__declspec(dllexport) void* kclvm_main_win(void* ctx) { - return kclvm_main(ctx); -} - -__declspec(dllexport) void kclvm_debug_hello_win() { - kclvm_debug_hello(); -} - -__declspec(dllexport) void kclvm_debug_print_win(const char* s) { - kclvm_debug_print(s); -} diff --git a/kclvm/runtime/src/api/buf.rs b/kclvm/runtime/src/api/buf.rs deleted file mode 100644 index 110a9a220..000000000 --- a/kclvm/runtime/src/api/buf.rs +++ /dev/null @@ -1,95 +0,0 @@ -// Copyright 2021 The KCL Authors. All rights reserved. - -use crate::*; - -#[allow(dead_code, non_camel_case_types)] -type kclvm_bool_t = i8; - -#[allow(dead_code, non_camel_case_types)] -type kclvm_char_t = i8; - -#[allow(dead_code, non_camel_case_types)] -type kclvm_size_t = i32; - -#[allow(dead_code, non_camel_case_types)] -type kclvm_buffer_t = Buffer; - -#[allow(dead_code, non_camel_case_types)] -pub type kclvm_value_t = Value; - -#[repr(C)] -#[derive(Debug, Clone, Default)] -pub struct Buffer { - buf: Vec, -} - -impl Buffer { - #[allow(dead_code)] - pub fn new_with_buf(buf: &[u8]) -> Self { - Buffer { buf: buf.to_vec() } - } - - #[allow(dead_code)] - pub fn into_raw(self) -> *mut Self { - Box::into_raw(Box::new(self)) - } - - #[allow(dead_code)] - pub fn malloc(size: usize) -> *mut u8 { - let p = Box::into_raw(Box::new(Buffer { - buf: vec![0u8; size + 8], - })); - - unsafe { - let data_ptr = (*p).buf.as_ptr() as *mut u8; - let u64bytes = (p as u64).to_le_bytes(); - (*p).buf[..8].clone_from_slice(&u64bytes[..8]); - data_ptr.add(8) - } - } - - #[allow(dead_code)] - pub fn free(_data_ptr: *mut u8) { - unsafe { - let p = u64::from_le_bytes( - std::slice::from_raw_parts(((_data_ptr as u64) - 8) as *const u8, 8) - .try_into() - .unwrap(), - ) as *mut Self; - - Box::from_raw(p); - } - } -} - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_buffer_new(size: kclvm_size_t) -> *mut kclvm_buffer_t { - let mut p = Buffer { buf: Vec::new() }; - p.buf.resize(size as usize, 0); - new_mut_ptr(p) -} - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_buffer_delete(p: *mut kclvm_buffer_t) { - free_mut_ptr(p) -} - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_buffer_size(p: *const kclvm_buffer_t) -> kclvm_size_t { - let p = ptr_as_ref(p); - p.buf.len() as kclvm_size_t -} - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_buffer_data(p: *const kclvm_buffer_t) -> *const kclvm_char_t { - let p = ptr_as_ref(p); - if !p.buf.is_empty() { - p.buf.as_ptr() as *const kclvm_char_t - } else { - std::ptr::null() - } -} diff --git a/kclvm/runtime/src/api/err_type.rs b/kclvm/runtime/src/api/err_type.rs deleted file mode 100644 index b36faf3e0..000000000 --- a/kclvm/runtime/src/api/err_type.rs +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright 2021 The KCL Authors. All rights reserved. - -// Auto generated, DONOT EDIT!!! - -// python: kclvm.kcl.error.ErrType - -#[derive(Copy, Clone)] -#[allow(non_camel_case_types)] -pub enum ErrType { - InvalidSyntax_TYPE = 0, - TabError_TYPE = 1, - IndentationError_TYPE = 2, - CannotFindModule_TYPE = 3, - FailedLoadModule_TYPE = 4, - CompileError_TYPE = 5, - EvaluationError_TYPE = 6, - RecursiveLoad_TYPE = 7, - FloatOverflow_TYPE = 8, - FloatUnderflow_TYPE = 9, - IntOverflow_TYPE = 10, - InvalidDocstring_TYPE = 11, - Deprecated_TYPE = 12, - UnKnownDecorator_TYPE = 13, - InvalidDecoratorTarget_TYPE = 14, - InvalidFormatSpec_TYPE = 15, - SelectorError_TYPE = 16, - SchemaCheckFailure_TYPE = 17, - MixinNamingError_TYPE = 18, - MixinStructureIllegal_TYPE = 19, - IndexSignatureError_TYPE = 20, - TypeError_Runtime_TYPE = 21, - TypeError_Compile_TYPE = 22, - NameError_TYPE = 23, - ValueError_TYPE = 24, - KeyError_TYPE = 25, - UniqueKeyError_TYPE = 26, - AttributeError_TYPE = 27, - AttributeError_Runtime_TYPE = 28, - AssertionError_TYPE = 29, - ImmutableCompileError_TYPE = 30, - ImmutableRuntimeError_TYPE = 31, - MultiInheritError_TYPE = 32, - CycleInheritError_TYPE = 33, - IllegalInheritError_TYPE = 34, - IllegalAttributeError_TYPE = 35, - IllegalArgumentError_TYPE = 36, - IllegalArgumentError_Complie_TYPE = 37, - IllegalArgumentError_Syntax_TYPE = 38, - RecursionError_TYPE = 39, - PlanError_TYPE = 40, - Deprecated_Warning_TYPE = 41, - CannotAddMembers_TYPE = 42, - CannotAddMembers_Runtime_TYPE = 43, -} diff --git a/kclvm/runtime/src/api/error.rs b/kclvm/runtime/src/api/error.rs new file mode 100644 index 000000000..5a5578493 --- /dev/null +++ b/kclvm/runtime/src/api/error.rs @@ -0,0 +1,16 @@ +//! Copyright The KCL Authors. All rights reserved. + +#[derive(Copy, Clone)] +#[allow(non_camel_case_types)] +pub enum RuntimeErrorType { + EvaluationError = 1, + RecursiveLoad = 2, + FloatOverflow = 3, + FloatUnderflow = 4, + IntOverflow = 5, + TypeError = 6, + AssertionError = 7, + Deprecated = 8, + DeprecatedWarning = 9, + SchemaCheckFailure = 10, +} diff --git a/kclvm/runtime/src/api/kclvm.rs b/kclvm/runtime/src/api/kclvm.rs index 4fe021320..7c101948f 100644 --- a/kclvm/runtime/src/api/kclvm.rs +++ b/kclvm/runtime/src/api/kclvm.rs @@ -1,69 +1,52 @@ -// Copyright 2021 The KCL Authors. All rights reserved. +//! Copyright The KCL Authors. All rights reserved. -#[allow(non_camel_case_types)] -type kclvm_value_ref_t = crate::ValueRef; -use crate::IndexMap; +use crate::{new_mut_ptr, val_plan::PlanOptions, IndexMap}; +use generational_arena::Index; +use indexmap::IndexSet; use serde::{Deserialize, Serialize}; use std::collections::{HashMap, HashSet}; +use std::panic::{RefUnwindSafe, UnwindSafe}; +use std::rc::Rc; +use std::sync::Arc; use std::{ cell::RefCell, cmp::Ordering, hash::{Hash, Hasher}, - rc::Rc, }; +/* + * Single instance name constants Undefined, None, True, False + */ #[allow(non_upper_case_globals)] pub const UNDEFINED: Value = Value::undefined; - #[allow(non_upper_case_globals)] pub const NONE: Value = Value::none; - #[allow(non_upper_case_globals)] pub const TRUE: Value = Value::bool_value(true); - #[allow(non_upper_case_globals)] pub const FALSE: Value = Value::bool_value(false); -#[derive(PartialEq, Clone, Default, Debug)] -pub struct KclError { - pub err_code: i32, - pub err_text: String, - pub filename: String, - pub source_code: String, - pub line: i32, - pub column: i32, -} +/* + * Runtime types + */ -#[allow(non_camel_case_types)] -#[derive(Clone, PartialEq, Debug)] +#[derive(Clone, PartialEq, Debug, Default)] pub enum Type { - any_type, - bool_type, - bool_lit_type(bool), - int_type, - int_lit_type(i64), - float_type, - float_lit_type(f64), - str_type, - str_lit_type(String), - list_type(ListType), - dict_type(DictType), - union_type(UnionType), - schema_type(SchemaType), - func_type(FuncType), -} - -impl Default for Type { - fn default() -> Self { - Type::any_type - } -} - -impl Type { - #[allow(dead_code)] - pub fn into_raw(self) -> *mut Self { - Box::into_raw(Box::new(self)) - } + #[default] + Any, + Bool, + BoolLit(bool), + Int, + IntLit(i64), + Float, + FloatLit(f64), + Str, + StrLit(String), + List(ListType), + Dict(DictType), + Union(UnionType), + Schema(SchemaType), + Func(FuncType), } #[derive(PartialEq, Clone, Default, Debug)] @@ -82,12 +65,17 @@ pub struct UnionType { pub elem_types: Vec, } +/// The runtime schema type. #[derive(PartialEq, Clone, Default, Debug)] pub struct SchemaType { + /// The schema runtime type name. pub name: String, - pub parent_name: String, - pub field_names: Vec, - pub field_types: Vec, + /// Schema attributes. + pub attrs: IndexMap, + /// Schema index signature. + pub has_index_signature: bool, + /// Schema runtime function value. + pub func: ValueRef, } #[derive(PartialEq, Clone, Default, Debug)] @@ -100,7 +88,7 @@ pub struct FuncType { #[allow(non_camel_case_types)] #[derive(Clone, Debug)] pub struct ValueRef { - pub rc: Rc, + pub rc: Rc>, } impl Eq for ValueRef {} @@ -113,18 +101,18 @@ impl PartialEq for ValueRef { impl Ord for ValueRef { fn cmp(&self, other: &ValueRef) -> Ordering { - let ord = match *self.rc { - Value::int_value(a) => match *other.rc { + let ord = match *self.rc.borrow() { + Value::int_value(a) => match *other.rc.borrow() { Value::int_value(b) => a.partial_cmp(&b), Value::float_value(b) => (a as f64).partial_cmp(&b), _ => None, }, - Value::float_value(a) => match *other.rc { + Value::float_value(a) => match *other.rc.borrow() { Value::int_value(b) => a.partial_cmp(&(b as f64)), Value::float_value(b) => a.partial_cmp(&b), _ => None, }, - Value::str_value(ref a) => match &*other.rc { + Value::str_value(ref a) => match &*other.rc.borrow() { Value::str_value(ref b) => a.partial_cmp(b), _ => None, }, @@ -149,9 +137,9 @@ impl PartialOrd for ValueRef { impl Hash for ValueRef { fn hash(&self, state: &mut H) { - match &*self.rc { - Value::undefined => panic!("unsupport hash for undefined"), - Value::none => panic!("unsupport hash for none"), + match &*self.rc.borrow() { + Value::undefined => 0.hash(state), + Value::none => 0.hash(state), Value::int_value(v) => (*v as f64).to_bits().hash(state), Value::unit_value(_real, raw, unit) => { raw.hash(state); @@ -187,14 +175,26 @@ impl Hash for ValueRef { impl Default for ValueRef { fn default() -> Self { Self { - rc: Rc::new(Value::undefined), + rc: Rc::new(RefCell::new(Value::undefined)), } } } impl ValueRef { - pub fn into_raw(self) -> *mut Self { - Box::into_raw(Box::new(self)) + // Returns whether self and x refer to the same Value + pub fn is_same_ref(&self, x: &Self) -> bool { + std::ptr::eq(&*self.rc.borrow(), &*x.rc.borrow()) + } + + pub fn into_raw(self, ctx: &mut Context) -> *mut Self { + new_mut_ptr(ctx, self) + } + + pub fn from_raw(&self) { + // If value is a func, clear the captured ValueRef to break circular reference. + if let Value::func_value(val) = &mut *self.rc.borrow_mut() { + val.closure = ValueRef::none(); + } } } @@ -207,10 +207,10 @@ pub enum Value { int_value(i64), float_value(f64), str_value(String), - list_value(ListValue), - dict_value(DictValue), - schema_value(SchemaValue), - func_value(FuncValue), + list_value(Box), + dict_value(Box), + schema_value(Box), + func_value(Box), unit_value(f64, i64, String), // (Real value, raw value, unit string) } @@ -220,62 +220,70 @@ impl Default for Value { } } -#[derive(PartialEq, Clone, Default, Debug)] +#[derive(PartialEq, Eq, Clone, Default, Debug)] pub struct ListValue { pub values: Vec, } -#[derive(PartialEq, Clone, Default, Debug)] +#[derive(PartialEq, Eq, Clone, Default, Debug)] pub struct DictValue { pub values: IndexMap, pub ops: IndexMap, pub insert_indexs: IndexMap, + /// Attribute type annotation string mapping. pub attr_map: IndexMap, + /// The runtime dict to schema reflect type string. + pub potential_schema: Option, } #[derive(PartialEq, Clone, Default, Debug)] pub struct SchemaValue { + /// Schema name without the package path prefix. pub name: String, + /// Schema instance package path, note is it not the schema definition package path. pub pkgpath: String, - pub config: Rc, + /// Schema values. + pub config: Box, + /// Schema instance config keys e.g., "a" in `MySchema {a = "foo"}` pub config_keys: Vec, + /// schema config meta information including filename, line and column. + pub config_meta: ValueRef, + /// This map stores which attributes of the schema are optional and which are required. + pub optional_mapping: ValueRef, + /// Schema instance argument values + pub args: ValueRef, + /// Schema instance keyword argument values + pub kwargs: ValueRef, } -#[derive(PartialEq, Clone, Default, Debug)] +#[derive(PartialEq, Eq, Clone, Default, Debug)] pub struct DecoratorValue { pub name: String, pub args: ValueRef, pub kwargs: ValueRef, } -#[derive(PartialEq, Clone, Default, Debug)] +#[derive(PartialEq, Eq, Clone, Default, Debug)] pub struct FuncValue { - // TODO (refactor): SchemaFuncValue pub fn_ptr: u64, pub check_fn_ptr: u64, pub closure: ValueRef, - pub external_name: String, - pub runtime_type: String, -} - -#[derive(PartialEq, Clone, Default, Debug)] -pub struct ErrorValue { - pub errors: Vec, -} - -#[derive(PartialEq, Clone, Default, Debug)] -pub struct OptionHelp { pub name: String, - pub typ: String, - pub required: bool, - pub default_value: Option, - pub help: String, + pub runtime_type: String, + pub is_external: bool, + /// Proxy functions represent the saved functions of the runtime itself, + /// rather than executing KCL defined functions or plugin functions. + pub proxy: Option, } #[allow(non_snake_case)] -#[derive(PartialEq, Clone, Default, Debug, Serialize, Deserialize)] +#[derive(PartialEq, Eq, Clone, Default, Debug, Serialize, Deserialize)] pub struct PanicInfo { - pub __kcl_PanicInfo__: bool, // "__kcl_PanicInfo__" + // Used to distinguish whether it is an error + // message JSON or a program run result. + #[serde(rename = "__kcl_PanicInfo__")] + pub __kcl_PanicInfo__: bool, + pub backtrace: Vec, pub rust_file: String, pub rust_line: i32, @@ -283,11 +291,12 @@ pub struct PanicInfo { pub kcl_pkgpath: String, pub kcl_file: String, + pub kcl_func: String, pub kcl_line: i32, pub kcl_col: i32, pub kcl_arg_msg: String, - // only for schema check + // Only for schema check failed error message pub kcl_config_meta_file: String, pub kcl_config_meta_line: i32, pub kcl_config_meta_col: i32, @@ -298,86 +307,117 @@ pub struct PanicInfo { pub is_warning: bool, } -#[derive(PartialEq, Clone, Default, Debug)] +#[derive(PartialEq, Eq, Clone, Default, Debug)] pub struct ContextConfig { pub debug_mode: bool, - pub strict_range_check: bool, - pub disable_none: bool, pub disable_schema_check: bool, - - pub list_option_mode: bool, } -#[derive(PartialEq, Clone, Debug)] +#[derive(PartialEq, Eq, Clone, Debug)] pub struct ContextBuffer { pub kclvm_context_invoke_result: String, + /// Custom manifest output string. + pub custom_manifests_output: Option, } impl Default for ContextBuffer { fn default() -> Self { Self { kclvm_context_invoke_result: "\0".to_string(), + custom_manifests_output: None, } } } -#[derive(PartialEq, Clone, Debug)] -pub struct ContextOutput { - pub stdout: String, - pub stderr: String, +/// Plugin functions +pub type PluginFunction = + Arc anyhow::Result + Send + Sync>; - pub return_value: *mut kclvm_value_ref_t, // *mut kclvm_value_ref_t +#[derive(Clone, Default)] +pub struct Context { + /// Runtime evaluation config. + pub cfg: ContextConfig, + /// kcl.mod path or the pwd path + pub module_path: String, + /// Program work directory + pub workdir: String, + /// Runtime backtrace frame for the debugger. + pub backtrace: Vec, + /// Imported package path to check the cyclic import process. + pub imported_pkgpath: HashSet, + /// Runtime arguments for the option function. + pub option_values: HashMap, + /// All schema instances, the first key is the schema runtime type and + /// the second key is the schema instance package path + pub instances: IndexMap>>, + /// All schema types + pub all_schemas: HashMap, + /// Import graph + pub import_names: IndexMap>, + /// A buffer to store plugin or hooks function calling results. + pub buffer: ContextBuffer, + /// Objects is to store all KCL object pointers at runtime for GC. + pub objects: IndexSet, + /// Log message used to store print results. + pub log_message: String, + /// Planned JSON result + pub json_result: String, + /// Planned YAML result + pub yaml_result: String, + /// Panic information at runtime + pub panic_info: PanicInfo, + /// Planning options + pub plan_opts: PlanOptions, + /// Builtin plugin functions, the key of the map is the form . e.g., `hello.say_hello` + pub plugin_functions: IndexMap, } -impl Default for ContextOutput { +impl UnwindSafe for Context {} +impl RefUnwindSafe for Context {} + +#[derive(PartialEq, Eq, Clone, Debug, Serialize, Deserialize)] +pub struct BacktraceFrame { + pub file: String, + pub func: String, + pub col: i32, + pub line: i32, +} +impl Default for BacktraceFrame { fn default() -> Self { Self { - stdout: "".to_string(), - stderr: "".to_string(), - return_value: std::ptr::null_mut(), + file: Default::default(), + func: "_kclvm_main".to_string(), + col: Default::default(), + line: Default::default(), } } } -#[derive(PartialEq, Clone, Default, Debug)] -pub struct Context { - pub cfg: ContextConfig, - pub output: ContextOutput, - pub panic_info: PanicInfo, - - pub main_pkg_path: String, - pub main_pkg_files: Vec, - - pub imported_pkgpath: HashSet, - pub app_args: HashMap, - pub instances: RefCell>>, - pub all_types: Vec, - pub all_schemas: RefCell>, - pub import_names: IndexMap>, - pub symbol_names: Vec, - pub symbol_values: Vec, - pub func_handlers: Vec, - - pub option_helps: Vec, - pub buffer: ContextBuffer, +impl BacktraceFrame { + pub fn from_panic_info(info: &PanicInfo) -> Self { + Self { + file: info.kcl_file.clone(), + func: info.kcl_func.clone(), + col: info.kcl_col, + line: info.kcl_line, + } + } } impl Context { pub fn new() -> Self { Context { - instances: RefCell::new(HashMap::new()), + instances: IndexMap::default(), + panic_info: PanicInfo { + kcl_func: "kclvm_main".to_string(), + ..Default::default() + }, ..Default::default() } } } -#[derive(PartialEq, Clone, Default, Debug)] -pub struct FuncHandler { - pub namespace: String, - pub fn_pointer: u64, -} - #[repr(C)] #[derive(Clone, PartialEq, Eq, Debug, Hash)] pub enum Kind { @@ -402,19 +442,14 @@ pub enum Kind { Func = 18, } -#[derive(Clone, PartialEq, Eq, Debug, Hash)] +#[derive(Clone, PartialEq, Eq, Debug, Hash, Default)] pub enum ConfigEntryOperationKind { + #[default] Union = 0, Override = 1, Insert = 2, } -impl Default for ConfigEntryOperationKind { - fn default() -> Self { - ConfigEntryOperationKind::Union - } -} - impl ConfigEntryOperationKind { pub fn from_i32(v: i32) -> Self { match v { @@ -423,7 +458,7 @@ impl ConfigEntryOperationKind { ConfigEntryOperationKind::Override } x if x == ConfigEntryOperationKind::Insert as i32 => ConfigEntryOperationKind::Insert, - _ => panic!("Invalid AttrOpKind integer {}, expected 0, 1 or 2", v), + _ => panic!("Invalid AttrOpKind integer {v}, expected 0, 1 or 2"), } } } diff --git a/kclvm/runtime/src/api/malloc.rs b/kclvm/runtime/src/api/malloc.rs deleted file mode 100644 index 958d97777..000000000 --- a/kclvm/runtime/src/api/malloc.rs +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright 2021 The KCL Authors. All rights reserved. - -use crate::*; - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_malloc(n: i32) -> *mut u8 { - Buffer::malloc(n as usize) -} - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_free(ptr: *mut u8) { - Buffer::free(ptr); -} - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_strlen(ptr: *mut u8) -> kclvm_size_t { - unsafe { - let mut p = ptr; - while *p != b'\0' { - p = p.add(1); - } - (p as i32) - (ptr as i32) - } -} diff --git a/kclvm/runtime/src/api/mod.rs b/kclvm/runtime/src/api/mod.rs index 45eacd222..d9ceae469 100644 --- a/kclvm/runtime/src/api/mod.rs +++ b/kclvm/runtime/src/api/mod.rs @@ -1,16 +1,10 @@ -// Copyright 2021 The KCL Authors. All rights reserved. +//! Copyright The KCL Authors. All rights reserved. pub mod kclvm; pub use self::kclvm::*; -pub mod buf; -pub use self::buf::*; - -pub mod malloc; -pub use self::malloc::*; - pub mod utils; pub use self::utils::*; -pub mod err_type; -pub use self::err_type::*; +pub mod error; +pub use self::error::*; diff --git a/kclvm/runtime/src/api/utils.rs b/kclvm/runtime/src/api/utils.rs index 0d4a5ea08..cfdf2bf34 100644 --- a/kclvm/runtime/src/api/utils.rs +++ b/kclvm/runtime/src/api/utils.rs @@ -1,73 +1,105 @@ -// Copyright 2021 The KCL Authors. All rights reserved. +//! Copyright The KCL Authors. All rights reserved. + +use std::os::raw::c_char; + +use crate::{kclvm_size_t, Context, ValueRef}; /// New a mutable raw pointer. -pub fn new_mut_ptr(x: T) -> *mut T { - Box::into_raw(Box::new(x)) +/// Safety: The caller must ensure that `ctx` lives longer than the returned pointer +/// and that the pointer is properly deallocated by calling `free_mut_ptr`. +pub fn new_mut_ptr(ctx: &mut Context, x: ValueRef) -> *mut ValueRef { + let ptr = Box::into_raw(Box::new(x)); + // Store the object pointer address to + // drop it it after execution is complete + ctx.objects.insert(ptr as usize); + ptr } /// Free a mutable raw pointer. +/// Safety: The caller must ensure `p` is a valid pointer obtained from `new_mut_ptr`. pub fn free_mut_ptr(p: *mut T) { if !p.is_null() { unsafe { - Box::from_raw(p); + drop(Box::from_raw(p)); } } } /// Convert a const raw pointer to a immutable borrow. +/// Safety: The caller must ensure that `p` is valid for the lifetime `'a`. pub fn ptr_as_ref<'a, T>(p: *const T) -> &'a T { assert!(!p.is_null()); unsafe { &*p } } /// Convert a mutable raw pointer to a mutable borrow. +/// Safety: The caller must ensure that `p` is valid for the lifetime `'a`. pub fn mut_ptr_as_ref<'a, T>(p: *mut T) -> &'a mut T { assert!(!p.is_null()); + unsafe { &mut *p } } +/// Copy str to mutable pointer with length +pub(crate) fn copy_str_to(v: &str, p: *mut c_char, size: *mut kclvm_size_t) { + assert!(!p.is_null() || !size.is_null()); + + unsafe { + let c_str_ptr = v.as_ptr() as *const c_char; + let c_str_len = v.len() as i32; + if c_str_len <= *size { + std::ptr::copy(c_str_ptr, p, c_str_len as usize); + *size = c_str_len + } + } +} + /// Convert a C str pointer to a Rust &str. -pub fn c2str<'a>(s: *const i8) -> &'a str { - let s = unsafe { std::ffi::CStr::from_ptr(s) }.to_str().unwrap(); +/// Safety: The caller must ensure that `s` is a valid null-terminated C string. +pub fn c2str<'a>(p: *const c_char) -> &'a str { + assert!(!p.is_null()); + + let s = unsafe { std::ffi::CStr::from_ptr(p) }.to_str().unwrap(); s } -/// Convert a immutable borrow to a mutable borrow unsafely to enable rapid data changes. -/// Please use it with caution. -#[inline] -pub fn get_ref_mut(val: &T) -> &mut T { - unsafe { &mut *(val as *const T as *mut T) } -} +/// Convert a C str pointer pointer to a Rust Vec. +pub fn c2str_vec(ptr_array: *const *const c_char) -> Vec { + assert!(!ptr_array.is_null()); + + let mut result = Vec::new(); + let mut index = 0; -/// Convert a raw double pinter to a Rust Vec. -pub fn convert_double_pointer_to_vec(data: &mut &mut i8, len: usize) -> Vec { unsafe { - match std::slice::from_raw_parts(data, len) - .iter() - .map(|arg| { - std::ffi::CStr::from_ptr(*arg) - .to_str() - .map(ToString::to_string) - }) - .collect() - { - Err(_error) => Vec::::new(), - Ok(x) => x, + loop { + let current_ptr = *ptr_array.offset(index); + if current_ptr.is_null() { + break; + } + let c_str = std::ffi::CStr::from_ptr(current_ptr); + let rust_string = c_str.to_string_lossy().to_string(); + result.push(rust_string); + index += 1; } } + + result } -pub fn assert_panic () + std::panic::UnwindSafe>(msg: &str, func: F) { +pub fn assert_panic(msg: &str, func: F) { match std::panic::catch_unwind(func) { Ok(_v) => { - panic!("not panic, expect={}", msg); + panic!("not panic, expect={msg}"); } Err(e) => match e.downcast::() { - Ok(_v) => panic!("unreachable"), + Ok(v) => { + let got = v.to_string(); + assert!(got.contains(msg), "expect={msg}, got={got}"); + } Err(e) => match e.downcast::<&str>() { Ok(v) => { let got = v.to_string(); - assert!(got.contains(msg), "expect={}, got={}", msg, got); + assert!(got.contains(msg), "expect={msg}, got={got}"); } _ => unreachable!(), }, diff --git a/kclvm/runtime/src/base64/base64.rs b/kclvm/runtime/src/base64/base64.rs deleted file mode 100644 index 8329aaac0..000000000 --- a/kclvm/runtime/src/base64/base64.rs +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright 2021 The KCL Authors. All rights reserved. -extern crate base64; -use base64::{decode, encode}; - -use crate::*; - -#[allow(non_camel_case_types)] -type kclvm_value_ref_t = ValueRef; - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_base64_encode( - _ctx: *mut kclvm_context_t, - args: *const kclvm_value_ref_t, - _kwargs: *const kclvm_value_ref_t, -) -> *const kclvm_value_ref_t { - let args = ptr_as_ref(args); - let p = args.arg_0().unwrap(); - match &*p.rc { - Value::str_value(x) => { - let s = encode(x.clone()); - return ValueRef::str(s.as_str()).into_raw(); - } - _ => { - let ctx = Context::current_context_mut(); - ctx.set_err_type(&ErrType::TypeError_Runtime_TYPE); - - panic!("a bytes-like object is required, not '{}'", p.as_str()); - } - } -} - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_base64_decode( - _ctx: *mut kclvm_context_t, - args: *const kclvm_value_ref_t, - _kwargs: *const kclvm_value_ref_t, -) -> *mut kclvm_value_ref_t { - let args = ptr_as_ref(args); - let p = args.arg_0().unwrap(); - match &*p.rc { - Value::str_value(x) => { - let de_str = decode(x.clone()).unwrap(); - return ValueRef::str(std::str::from_utf8(&de_str).unwrap()).into_raw(); - } - _ => { - let ctx = Context::current_context_mut(); - ctx.set_err_type(&ErrType::TypeError_Runtime_TYPE); - - panic!( - "argument should be a bytes-like object or ASCII string, not '{}'", - p.as_str() - ); - } - } -} diff --git a/kclvm/runtime/src/base64/mod.rs b/kclvm/runtime/src/base64/mod.rs index e56a77ea1..5ed481346 100644 --- a/kclvm/runtime/src/base64/mod.rs +++ b/kclvm/runtime/src/base64/mod.rs @@ -1,4 +1,40 @@ -// Copyright 2021 The KCL Authors. All rights reserved. +//! Copyright The KCL Authors. All rights reserved. -pub mod base64; -pub use self::base64::*; +extern crate base64; +use base64::{decode, encode}; + +use crate::*; + +#[no_mangle] +#[runtime_fn] +pub extern "C" fn kclvm_base64_encode( + ctx: *mut kclvm_context_t, + args: *const kclvm_value_ref_t, + kwargs: *const kclvm_value_ref_t, +) -> *const kclvm_value_ref_t { + let args = ptr_as_ref(args); + let kwargs = ptr_as_ref(kwargs); + let ctx = mut_ptr_as_ref(ctx); + if let Some(s) = get_call_arg_str(args, kwargs, 0, Some("value")) { + let s = encode(s); + return ValueRef::str(s.as_str()).into_raw(ctx); + } + panic!("encode() missing 1 required positional argument: 'value'"); +} + +#[no_mangle] +#[runtime_fn] +pub extern "C" fn kclvm_base64_decode( + ctx: *mut kclvm_context_t, + args: *const kclvm_value_ref_t, + kwargs: *const kclvm_value_ref_t, +) -> *mut kclvm_value_ref_t { + let args = ptr_as_ref(args); + let kwargs = ptr_as_ref(kwargs); + let ctx = mut_ptr_as_ref(ctx); + if let Some(s) = get_call_arg_str(args, kwargs, 0, Some("value")) { + let de_str = decode(s).unwrap(); + return ValueRef::str(std::str::from_utf8(&de_str).unwrap()).into_raw(ctx); + } + panic!("decode() missing 1 required positional argument: 'value'"); +} diff --git a/kclvm/runtime/src/collection/collection.rs b/kclvm/runtime/src/collection/collection.rs deleted file mode 100644 index b7e1dad98..000000000 --- a/kclvm/runtime/src/collection/collection.rs +++ /dev/null @@ -1,35 +0,0 @@ -//! KCL collection system module -//! -//! Copyright 2021 The KCL Authors. All rights reserved. - -use crate::*; - -#[allow(non_camel_case_types)] -type kclvm_value_ref_t = ValueRef; - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_value_union_all( - _ctx: *mut kclvm_context_t, - args: *const kclvm_value_ref_t, - _kwargs: *const kclvm_value_ref_t, -) -> *const kclvm_value_ref_t { - let args = ptr_as_ref(args); - if let Some(arg) = args.arg_0() { - if !arg.is_truthy() || !arg.is_list() { - return ValueRef::dict(None).into_raw(); - } - let value = arg.as_list_ref(); - if value.values.is_empty() { - return ValueRef::dict(None).into_raw(); - } - let mut result = value.values[0].deep_copy(); - for (i, v) in value.values.iter().enumerate() { - if i > 0 { - result.bin_aug_union_with(v); - } - } - return result.into_raw(); - } - panic!("union_all() takes at least 1 argument (0 given)") -} diff --git a/kclvm/runtime/src/collection/mod.rs b/kclvm/runtime/src/collection/mod.rs index 552ad5847..7f4a02aa1 100644 --- a/kclvm/runtime/src/collection/mod.rs +++ b/kclvm/runtime/src/collection/mod.rs @@ -1,4 +1,31 @@ -// Copyright 2021 The KCL Authors. All rights reserved. +//! Copyright The KCL Authors. All rights reserved. -pub mod collection; -pub use self::collection::*; +use crate::*; + +#[no_mangle] +#[runtime_fn] +pub extern "C" fn kclvm_value_union_all( + ctx: *mut kclvm_context_t, + args: *const kclvm_value_ref_t, + _kwargs: *const kclvm_value_ref_t, +) -> *const kclvm_value_ref_t { + let args = ptr_as_ref(args); + let ctx = mut_ptr_as_ref(ctx); + if let Some(arg) = args.arg_0() { + if !arg.is_truthy() || !arg.is_list() { + return ValueRef::dict(None).into_raw(ctx); + } + let value = arg.as_list_ref(); + if value.values.is_empty() { + return ValueRef::dict(None).into_raw(ctx); + } + let mut result = value.values[0].deep_copy(); + for (i, v) in value.values.iter().enumerate() { + if i > 0 { + result.bin_aug_union_with(ctx, v); + } + } + return result.into_raw(ctx); + } + panic!("union_all() takes at least 1 argument (0 given)") +} diff --git a/kclvm/runtime/src/context/api.rs b/kclvm/runtime/src/context/api.rs index 398065010..aaeb77687 100644 --- a/kclvm/runtime/src/context/api.rs +++ b/kclvm/runtime/src/context/api.rs @@ -1,13 +1,16 @@ -// Copyright 2021 The KCL Authors. All rights reserved. +//! Copyright The KCL Authors. All rights reserved. +#![allow(clippy::missing_safety_doc)] use crate::*; use std::os::raw::c_char; +use self::eval::LazyEvalScope; + #[allow(dead_code, non_camel_case_types)] type kclvm_context_t = Context; #[allow(dead_code, non_camel_case_types)] -type kclvm_error_t = KclError; +type kclvm_eval_scope_t = LazyEvalScope; #[allow(dead_code, non_camel_case_types)] type kclvm_kind_t = Kind; @@ -19,7 +22,7 @@ type kclvm_type_t = Type; type kclvm_value_t = Value; #[allow(dead_code, non_camel_case_types)] -type kclvm_char_t = i8; +type kclvm_char_t = c_char; #[allow(dead_code, non_camel_case_types)] type kclvm_size_t = i32; @@ -37,57 +40,21 @@ type kclvm_float_t = f64; // new/delete // ---------------------------------------------------------------------------- -// singleton - -#[allow(non_camel_case_types, non_upper_case_globals)] -static mut _kclvm_context_current: u64 = 0; - #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_context_current() -> *mut kclvm_context_t { - unsafe { - if _kclvm_context_current == 0 { - _kclvm_context_current = kclvm_context_new() as u64; - } - _kclvm_context_current as *mut kclvm_context_t - } +pub unsafe extern "C" fn kclvm_context_new() -> *mut kclvm_context_t { + Box::into_raw(Box::new(Context::new())) } #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_context_new() -> *mut kclvm_context_t { - let p = new_mut_ptr(Context::new()); - unsafe { - _kclvm_context_current = p as u64; +pub unsafe extern "C" fn kclvm_context_delete(p: *mut kclvm_context_t) { + let ctx = mut_ptr_as_ref(p); + for o in &ctx.objects { + let ptr = (*o) as *mut kclvm_value_ref_t; + kclvm_value_delete(ptr); } - p -} - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_context_delete(p: *mut kclvm_context_t) { - free_mut_ptr(p) -} - -// ---------------------------------------------------------------------------- -// main begin/end -// ---------------------------------------------------------------------------- - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_context_main_begin_hook(p: *mut kclvm_context_t) { - let p = mut_ptr_as_ref(p); - p.main_begin_hook(); -} - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_context_main_end_hook( - p: *mut kclvm_context_t, - return_value: *mut kclvm_value_ref_t, -) -> *mut kclvm_value_ref_t { - let p = mut_ptr_as_ref(p); - p.main_end_hook(return_value) + free_mut_ptr(p); } // ---------------------------------------------------------------------------- @@ -96,9 +63,9 @@ pub extern "C" fn kclvm_context_main_end_hook( #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_context_set_kcl_location( +pub unsafe extern "C" fn kclvm_context_set_kcl_location( p: *mut kclvm_context_t, - filename: *const i8, + filename: *const c_char, line: i32, col: i32, ) { @@ -112,7 +79,10 @@ pub extern "C" fn kclvm_context_set_kcl_location( #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_context_set_kcl_pkgpath(p: *mut kclvm_context_t, pkgpath: *const i8) { +pub unsafe extern "C" fn kclvm_context_set_kcl_pkgpath( + p: *mut kclvm_context_t, + pkgpath: *const c_char, +) { let p = mut_ptr_as_ref(p); if !pkgpath.is_null() { p.set_kcl_pkgpath(c2str(pkgpath)); @@ -121,135 +91,127 @@ pub extern "C" fn kclvm_context_set_kcl_pkgpath(p: *mut kclvm_context_t, pkgpath #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_context_set_kcl_filename(filename: *const i8) { - let p = Context::current_context_mut(); - if !filename.is_null() { - p.set_kcl_filename(c2str(filename)); +pub unsafe extern "C" fn kclvm_context_set_kcl_modpath( + p: *mut kclvm_context_t, + module_path: *const c_char, +) { + let p = mut_ptr_as_ref(p); + if !module_path.is_null() { + p.set_kcl_module_path(c2str(module_path)); } } #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_context_set_kcl_line_col(line: i32, col: i32) { - let p = Context::current_context_mut(); - p.set_kcl_line_col(line, col); +pub unsafe extern "C" fn kclvm_context_set_kcl_workdir( + p: *mut kclvm_context_t, + workdir: *const c_char, +) { + let p = mut_ptr_as_ref(p); + if !workdir.is_null() { + p.set_kcl_workdir(c2str(workdir)); + } } -// ---------------------------------------------------------------------------- -// manage types -// ---------------------------------------------------------------------------- - #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_context_put_type(p: *mut kclvm_context_t, typ: *const kclvm_type_t) { - let p = mut_ptr_as_ref(p); - let typ = ptr_as_ref(typ); - - p.all_types.push(typ.clone()); +pub unsafe extern "C" fn kclvm_context_set_kcl_filename( + ctx: *mut kclvm_context_t, + filename: *const c_char, +) { + let ctx = mut_ptr_as_ref(ctx); + if !filename.is_null() { + ctx.set_kcl_filename(c2str(filename)); + } } #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_context_clear_all_types(p: *mut kclvm_context_t) { - let p = mut_ptr_as_ref(p); - p.all_types.clear(); +pub unsafe extern "C" fn kclvm_context_set_kcl_line_col( + ctx: *mut kclvm_context_t, + line: i32, + col: i32, +) { + let ctx = mut_ptr_as_ref(ctx); + ctx.set_kcl_line_col(line, col); } // ---------------------------------------------------------------------------- -// symbol +// Global values and evaluation scope. // ---------------------------------------------------------------------------- #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_context_symbol_init( - p: *mut kclvm_context_t, - n: kclvm_size_t, - symbol_names: *const *const kclvm_char_t, -) { - let p = mut_ptr_as_ref(p); - - unsafe { - p.symbol_names.clear(); - p.symbol_values.clear(); - - let _ = std::slice::from_raw_parts(symbol_names, n as usize) - .iter() - .map(|arg| { - p.symbol_names.push(c2str(*arg).to_string()); - p.symbol_values.push(Value::default()); - }); - } -} - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_context_symbol_num(p: *const kclvm_context_t) -> kclvm_size_t { - let p = ptr_as_ref(p); - - p.symbol_names.len() as kclvm_size_t +pub unsafe extern "C" fn kclvm_scope_new() -> *mut kclvm_eval_scope_t { + Box::into_raw(Box::default()) } #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_context_symbol_name( - p: *const kclvm_context_t, - i: kclvm_size_t, -) -> *const kclvm_char_t { - let p = ptr_as_ref(p); - return match p.symbol_names.get(i as usize) { - Some(value) => value.as_bytes().as_ptr() as *const kclvm_char_t, - None => std::ptr::null(), - }; +pub unsafe extern "C" fn kclvm_scope_delete(scope: *mut kclvm_eval_scope_t) { + drop(Box::from_raw(scope)); } #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_context_symbol_value( - p: *const kclvm_context_t, - i: kclvm_size_t, -) -> *const kclvm_value_t { - let p = ptr_as_ref(p); - match p.symbol_values.get(i as usize) { - Some(v) => v as *const kclvm_value_t, - None => std::ptr::null(), +pub unsafe extern "C" fn kclvm_scope_add_setter( + _ctx: *mut kclvm_context_t, + scope: *mut kclvm_eval_scope_t, + pkg: *const c_char, + name: *const c_char, + setter: *const u64, +) { + let scope = mut_ptr_as_ref(scope); + let pkg = c2str(pkg); + let name = c2str(name); + let key = format!("{}.{}", pkg, name); + if !scope.setters.contains_key(&key) { + scope.setters.insert(key.clone(), vec![]); + } + if let Some(setters) = scope.setters.get_mut(&key) { + setters.push(setter as u64); } -} - -// ---------------------------------------------------------------------------- -// args -// ---------------------------------------------------------------------------- - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_context_args_get( - _p: *const kclvm_context_t, - _key: *const kclvm_char_t, -) -> *const kclvm_char_t { - //let p = ptr_as_ref(p); - //match p.app_args.get(c2str(key)) { - // Some(value) => (*value).as_bytes().as_ptr() as *const kclvm_char_t, - // None => std::ptr::null(), - //}; - std::ptr::null() } #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_context_args_set( - _p: *mut kclvm_context_t, - _key: *const kclvm_char_t, - _value: *const kclvm_char_t, +pub unsafe extern "C" fn kclvm_scope_set( + _ctx: *mut kclvm_context_t, + scope: *mut kclvm_eval_scope_t, + pkg: *const c_char, + name: *const c_char, + value: *const kclvm_value_ref_t, ) { - //let p = mut_ptr_as_ref(p); - //p.app_args - // .insert(c2str(key).to_string(), c2str(value).to_string()); + let scope = mut_ptr_as_ref(scope); + let value = ptr_as_ref(value); + let pkg = c2str(pkg); + let name = c2str(name); + let key = format!("{}.{}", pkg, name); + scope.set_value(&key, value); } #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_context_args_clear(p: *mut kclvm_context_t) { - let p = mut_ptr_as_ref(p); - p.app_args.clear(); +pub unsafe extern "C" fn kclvm_scope_get( + ctx: *mut kclvm_context_t, + scope: *mut kclvm_eval_scope_t, + pkg: *const c_char, + name: *const c_char, + target: *const c_char, + default: *const kclvm_value_ref_t, +) -> *const kclvm_value_ref_t { + let ctx = mut_ptr_as_ref(ctx); + let scope = mut_ptr_as_ref(scope); + let pkg = c2str(pkg); + let name = c2str(name); + let target = format!("{}.{}", pkg, c2str(target)); + let key = format!("{}.{}", pkg, name); + // Existing values or existing but not yet calculated values. + if scope.contains_key(&key) || scope.setters.contains_key(&key) { + scope.get_value(ctx, &key, &target).into_raw(ctx) + } else { + default + } } // ---------------------------------------------------------------------------- @@ -258,46 +220,45 @@ pub extern "C" fn kclvm_context_args_clear(p: *mut kclvm_context_t) { #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_context_set_debug_mode(p: *mut kclvm_context_t, v: kclvm_bool_t) { +pub unsafe extern "C" fn kclvm_context_set_debug_mode(p: *mut kclvm_context_t, v: kclvm_bool_t) { let p = mut_ptr_as_ref(p); p.cfg.debug_mode = v != 0; } #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_context_set_strict_range_check(p: *mut kclvm_context_t, v: kclvm_bool_t) { +pub unsafe extern "C" fn kclvm_context_set_strict_range_check( + p: *mut kclvm_context_t, + v: kclvm_bool_t, +) { let p = mut_ptr_as_ref(p); p.cfg.strict_range_check = v != 0; } #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_context_set_disable_none(p: *mut kclvm_context_t, v: kclvm_bool_t) { +pub unsafe extern "C" fn kclvm_context_set_disable_none(p: *mut kclvm_context_t, v: kclvm_bool_t) { let p = mut_ptr_as_ref(p); - p.cfg.disable_none = v != 0; + p.plan_opts.disable_none = v != 0; } #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_context_set_disable_schema_check(p: *mut kclvm_context_t, v: kclvm_bool_t) { +pub unsafe extern "C" fn kclvm_context_set_disable_schema_check( + p: *mut kclvm_context_t, + v: kclvm_bool_t, +) { let p = mut_ptr_as_ref(p); p.cfg.disable_schema_check = v != 0; } -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_context_set_list_option_mode(p: *mut kclvm_context_t, v: kclvm_bool_t) { - let p = mut_ptr_as_ref(p); - p.cfg.list_option_mode = v != 0; -} - // ---------------------------------------------------------------------------- // invoke // ---------------------------------------------------------------------------- #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_context_invoke( +pub unsafe extern "C" fn kclvm_context_invoke( p: *mut kclvm_context_t, method: *const c_char, args: *const c_char, @@ -306,12 +267,12 @@ pub extern "C" fn kclvm_context_invoke( let p = mut_ptr_as_ref(p); let method = c2str(method); - let args = kclvm_value_from_json(args); - let kwargs = kclvm_value_from_json(kwargs); + let args = kclvm_value_from_json(p, args); + let kwargs = kclvm_value_from_json(p, kwargs); let result = _kclvm_context_invoke(p, method, args, kwargs); p.buffer.kclvm_context_invoke_result = ptr_as_ref(result).to_json_string_with_null(); - let result_json = p.buffer.kclvm_context_invoke_result.as_ptr() as *const i8; + let result_json = p.buffer.kclvm_context_invoke_result.as_ptr() as *const c_char; kclvm_value_delete(args); kclvm_value_delete(kwargs); @@ -320,7 +281,7 @@ pub extern "C" fn kclvm_context_invoke( result_json } -fn _kclvm_context_invoke( +unsafe fn _kclvm_context_invoke( ctx: *mut kclvm_context_t, method: &str, args: *const kclvm_value_ref_t, @@ -345,9 +306,12 @@ fn _kclvm_context_invoke( #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_context_pkgpath_is_imported(pkgpath: *const kclvm_char_t) -> kclvm_bool_t { +pub unsafe extern "C" fn kclvm_context_pkgpath_is_imported( + ctx: *mut kclvm_context_t, + pkgpath: *const kclvm_char_t, +) -> kclvm_bool_t { let pkgpath = c2str(pkgpath); - let ctx = Context::current_context_mut(); + let ctx = mut_ptr_as_ref(ctx); let result = ctx.imported_pkgpath.contains(pkgpath); ctx.imported_pkgpath.insert(pkgpath.to_string()); result as kclvm_bool_t diff --git a/kclvm/runtime/src/context/mod.rs b/kclvm/runtime/src/context/mod.rs index 704fe730c..ec24cc733 100644 --- a/kclvm/runtime/src/context/mod.rs +++ b/kclvm/runtime/src/context/mod.rs @@ -1,16 +1,18 @@ -// Copyright 2021 The KCL Authors. All rights reserved. +//! Copyright The KCL Authors. All rights reserved. pub mod api; pub use api::*; +use std::fmt; -#[allow(non_camel_case_types)] -type kclvm_value_ref_t = crate::ValueRef; +use crate::{kclvm_value_delete, kclvm_value_ref_t, BacktraceFrame, PanicInfo, RuntimePanicRecord}; -impl crate::PanicInfo { - pub fn to_string(&self) -> String { - return format!("{:?}", self); +impl fmt::Display for PanicInfo { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{self:?}") } +} +impl PanicInfo { pub fn to_json_string(&self) -> String { let result = serde_json::to_string(&self); match result { @@ -20,53 +22,81 @@ impl crate::PanicInfo { } } } -} - -impl crate::Context { - pub fn into_raw(self) -> *mut Self { - Box::into_raw(Box::new(self)) - } - pub fn current_context() -> &'static crate::Context { - unsafe { - let ctx = kclvm_context_current(); - &*ctx + /// Parse a json string to a PanicInfo. + pub fn from_json_string(s: &str) -> Self { + let result = serde_json::from_str(s); + match result { + Ok(res) => res, + _ => { + panic!("PanicInfo Deserialize Failed") + } } } - pub fn current_context_mut() -> &'static mut crate::Context { - unsafe { - let ctx = kclvm_context_current(); - &mut *ctx + /// Parse a string or json string to a PanicInfo. + pub fn from_string(s: &str) -> Self { + let result = serde_json::from_str(s); + match result { + Ok(res) => res, + Err(_) => PanicInfo { + __kcl_PanicInfo__: true, + message: s.to_string(), + err_type_code: crate::RuntimeErrorType::EvaluationError as i32, + ..Default::default() + }, } } +} - pub fn main_begin_hook(&mut self) { - // Nothing to do +impl From for PanicInfo { + fn from(value: String) -> Self { + Self::from_string(&value) } +} - pub fn main_end_hook( - &mut self, - return_value: *mut kclvm_value_ref_t, - ) -> *mut kclvm_value_ref_t { - self.output.return_value = return_value; +impl PanicInfo { + /// New a [`PanicInfo`] from error message [`value`] and the position that error occur. + pub fn from_ast_pos(value: String, pos: (String, u64, u64, u64, u64)) -> Self { + let mut panic_info = Self::from_string(&value); + panic_info.kcl_file = pos.0; + panic_info.kcl_line = pos.1 as i32; + panic_info.kcl_col = pos.2 as i32; + panic_info + } +} - if self.cfg.list_option_mode { - self.output.return_value = - crate::ValueRef::str(self.list_option_help().as_str()).into_raw(); - } +impl From<&str> for PanicInfo { + fn from(value: &str) -> Self { + Self::from_string(value) + } +} - self.output.return_value +impl crate::Context { + pub fn into_raw(self) -> *mut Self { + Box::into_raw(Box::new(self)) } - pub fn get_panic_info_json_string(&self) -> String { - self.panic_info.to_json_string() + pub fn get_panic_info_json_string(&self) -> Option { + if self.panic_info.__kcl_PanicInfo__ { + Some(self.panic_info.to_json_string()) + } else { + None + } } pub fn set_kcl_pkgpath(&mut self, pkgpath: &str) { self.panic_info.kcl_pkgpath = pkgpath.to_string(); } + pub fn set_kcl_module_path(&mut self, module_path: &str) { + self.module_path = module_path.to_string(); + } + + pub fn set_kcl_workdir(&mut self, workdir: &str) { + self.workdir = workdir.to_string(); + } + pub fn set_kcl_filename(&mut self, file: &str) { if !file.is_empty() { self.panic_info.kcl_file = file.to_string(); @@ -120,129 +150,42 @@ impl crate::Context { } } - pub fn set_err_type(&mut self, err_type: &crate::ErrType) { + pub fn set_err_type(&mut self, err_type: &crate::RuntimeErrorType) { self.panic_info.__kcl_PanicInfo__ = true; self.panic_info.err_type_code = *err_type as i32; } - pub fn set_warnning_message(&mut self, msg: &str) { + + pub fn set_warning_message(&mut self, msg: &str) { self.panic_info.__kcl_PanicInfo__ = true; self.panic_info.message = msg.to_string(); self.panic_info.is_warning = true; } - pub fn set_panic_info(&mut self, info: &std::panic::PanicInfo) { + pub fn set_panic_info(&mut self, record: &RuntimePanicRecord) { self.panic_info.__kcl_PanicInfo__ = true; - if let Some(s) = info.payload().downcast_ref::<&str>() { - self.panic_info.message = s.to_string(); - } else if let Some(s) = info.payload().downcast_ref::<&String>() { - self.panic_info.message = (*s).clone(); - } else if let Some(s) = info.payload().downcast_ref::() { - self.panic_info.message = (*s).clone(); - } else { - self.panic_info.message = "".to_string(); - } - - if let Some(location) = info.location() { - self.panic_info.rust_file = location.file().to_string(); - self.panic_info.rust_line = location.line() as i32; - self.panic_info.rust_col = location.column() as i32; - } else { - self.panic_info.rust_file = "".to_string(); - self.panic_info.rust_line = 0; - self.panic_info.rust_col = 0; - } - } -} - -impl crate::Context { - pub fn define_option( - &mut self, - name: &str, - typ: &str, - required: bool, - default_value: Option, - help: &str, - ) { - // check dup - for i in 0..self.option_helps.len() { - if self.option_helps[i].name == name { - if typ.is_empty() && !required && default_value == None && help.is_empty() { - return; - } - - if self.option_helps[i].typ.is_empty() { - self.option_helps[i].typ = typ.to_string(); - } - - if !self.option_helps[i].required { - self.option_helps[i].required = required; - } - if self.option_helps[i].default_value == None { - self.option_helps[i].default_value = default_value; - } - if self.option_helps[i].help.is_empty() { - self.option_helps[i].help = help.to_string(); - } - - return; - } + self.panic_info.message = record.message.clone(); + if self.cfg.debug_mode { + self.panic_info.backtrace = self.backtrace.clone(); + self.panic_info.backtrace.push(BacktraceFrame { + file: self.panic_info.kcl_file.clone(), + func: self.panic_info.kcl_func.clone(), + col: self.panic_info.kcl_col, + line: self.panic_info.kcl_line, + }); } - self.option_helps.push(crate::OptionHelp { - name: name.to_string(), - typ: typ.to_string(), - required, - default_value, - help: help.to_string(), - }); + self.panic_info.rust_file = record.rust_file.clone(); + self.panic_info.rust_line = record.rust_line; + self.panic_info.rust_col = record.rust_col; } - pub fn list_option_help(&self) -> String { - let mut msg: String = "".to_string(); - - // name=? (required) set name value - // name=? (str,required) set name value - // a=42 set a value - // b=? set b value - // obj=? - // obj2=? - - msg.push_str("option list:\n"); - for opt in &self.option_helps { - let name = opt.name.clone(); - - let mut default_value: String = "?".to_string(); - if let Some(ref v) = opt.default_value { - default_value = (*v).clone(); - } - - let s = format!(" -D {}={}", name, default_value); - msg.push_str(s.as_str()); - - // (required) - // (str,required) - if !opt.typ.is_empty() || opt.required { - if opt.required && !opt.typ.is_empty() { - let s = format!(" ({},{})", opt.typ, "required"); - msg.push_str(s.as_str()); - } else if !opt.typ.is_empty() { - let s = format!(" ({})", opt.typ); - msg.push_str(s.as_str()); - } else { - msg.push_str(" (required)"); - } - } - - if !opt.help.is_empty() { - msg.push(' '); - msg.push_str(opt.help.as_str()); + pub fn gc(&self) { + unsafe { + for o in &self.objects { + let ptr = (*o) as *mut kclvm_value_ref_t; + kclvm_value_delete(ptr); } - - msg.push('\n'); } - - msg = msg.as_str().trim_end_matches('\n').to_string(); - msg } } diff --git a/kclvm/runtime/src/crypto/crypto.rs b/kclvm/runtime/src/crypto/crypto.rs deleted file mode 100644 index 9c6341555..000000000 --- a/kclvm/runtime/src/crypto/crypto.rs +++ /dev/null @@ -1,162 +0,0 @@ -//! KCL crypto system module -//! -//! Copyright 2021 The KCL Authors. All rights reserved. - -extern crate md5; -extern crate sha1; -extern crate sha2; - -use sha2::{Digest, Sha224, Sha256, Sha384, Sha512}; - -use crate::*; - -#[allow(non_camel_case_types)] -type kclvm_value_ref_t = ValueRef; - -// md5(value: str, encoding: str = "utf-8") -> str - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_crypto_md5( - _ctx: *mut kclvm_context_t, - args: *const kclvm_value_ref_t, - _kwargs: *const kclvm_value_ref_t, -) -> *const kclvm_value_ref_t { - let args = ptr_as_ref(args); - - if let Some(s) = args.arg_i_str(0, None) { - let hex = format!("{:x}", md5::compute(&s)); - return ValueRef::str(hex.as_ref()).into_raw(); - } - panic!("md5() missing 1 required positional argument: 'value'"); -} - -// sha1(value: str, encoding: str = "utf-8") -> str - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_crypto_sha1( - _ctx: *mut kclvm_context_t, - args: *const kclvm_value_ref_t, - _kwargs: *const kclvm_value_ref_t, -) -> *const kclvm_value_ref_t { - let args = ptr_as_ref(args); - - if let Some(s) = args.arg_i_str(0, None) { - let hex = sha1::Sha1::from(s).digest().to_string(); - return ValueRef::str(hex.as_ref()).into_raw(); - } - panic!("sha1() missing 1 required positional argument: 'value'"); -} - -// sha224(value: str, encoding: str = "utf-8") -> str - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_crypto_sha224( - _ctx: *mut kclvm_context_t, - args: *const kclvm_value_ref_t, - _kwargs: *const kclvm_value_ref_t, -) -> *const kclvm_value_ref_t { - let args = ptr_as_ref(args); - - if let Some(s) = args.arg_i_str(0, None) { - let mut hasher = Sha224::new(); - hasher.update(&s); - let result = hasher.finalize(); - - let mut hex = String::with_capacity(2 * Sha256::output_size()); - use std::fmt::Write; - - for byte in result { - let _ = write!(&mut hex, "{:02x}", byte); - } - - return ValueRef::str(hex.as_ref()).into_raw(); - } - panic!("sha224() missing 1 required positional argument: 'value'"); -} - -// sha256(value: str, encoding: str = "utf-8") -> str - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_crypto_sha256( - _ctx: *mut kclvm_context_t, - args: *const kclvm_value_ref_t, - _kwargs: *const kclvm_value_ref_t, -) -> *const kclvm_value_ref_t { - let args = ptr_as_ref(args); - - if let Some(s) = args.arg_i_str(0, None) { - let mut hasher = Sha256::new(); - hasher.update(&s); - let result = hasher.finalize(); - - let mut hex = String::with_capacity(2 * Sha256::output_size()); - use std::fmt::Write; - - for byte in result { - let _ = write!(&mut hex, "{:02x}", byte); - } - - return ValueRef::str(hex.as_ref()).into_raw(); - } - panic!("sha256() missing 1 required positional argument: 'value'"); -} - -// sha384(value: str, encoding: str = "utf-8") -> str - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_crypto_sha384( - _ctx: *mut kclvm_context_t, - args: *const kclvm_value_ref_t, - _kwargs: *const kclvm_value_ref_t, -) -> *const kclvm_value_ref_t { - let args = ptr_as_ref(args); - - if let Some(s) = args.arg_i_str(0, None) { - let mut hasher = Sha384::new(); - hasher.update(&s); - let result = hasher.finalize(); - - let mut hex = String::with_capacity(2 * Sha256::output_size()); - use std::fmt::Write; - - for byte in result { - let _ = write!(&mut hex, "{:02x}", byte); - } - - return ValueRef::str(hex.as_ref()).into_raw(); - } - panic!("sha384() missing 1 required positional argument: 'value'"); -} - -// sha512(value: str, encoding: str = "utf-8") -> str - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_crypto_sha512( - _ctx: *mut kclvm_context_t, - args: *const kclvm_value_ref_t, - _kwargs: *const kclvm_value_ref_t, -) -> *const kclvm_value_ref_t { - let args = ptr_as_ref(args); - - if let Some(s) = args.arg_i_str(0, None) { - let mut hasher = Sha512::new(); - hasher.update(&s); - let result = hasher.finalize(); - - let mut hex = String::with_capacity(2 * Sha256::output_size()); - use std::fmt::Write; - - for byte in result { - let _ = write!(&mut hex, "{:02x}", byte); - } - - return ValueRef::str(hex.as_ref()).into_raw(); - } - panic!("sha512() missing 1 required positional argument: 'value'"); -} diff --git a/kclvm/runtime/src/crypto/mod.rs b/kclvm/runtime/src/crypto/mod.rs index 4105751af..6d54ab1ff 100644 --- a/kclvm/runtime/src/crypto/mod.rs +++ b/kclvm/runtime/src/crypto/mod.rs @@ -1,4 +1,342 @@ -// Copyright 2021 The KCL Authors. All rights reserved. +//! Copyright The KCL Authors. All rights reserved. -pub mod crypto; -pub use self::crypto::*; +extern crate blake3; +extern crate md5; +extern crate sha1; +extern crate sha2; + +use core::panic; +use std::{fs::File, io::Read}; + +use crate::encoding::encode_text; +use sha2::{Digest, Sha224, Sha256, Sha384, Sha512}; + +use crate::*; +use uuid::Uuid; + +#[allow(non_camel_case_types)] +type kclvm_value_ref_t = ValueRef; + +// md5(value: str, encoding: str = "utf-8") -> str + +#[no_mangle] +#[runtime_fn] +pub extern "C" fn kclvm_crypto_md5( + ctx: *mut kclvm_context_t, + args: *const kclvm_value_ref_t, + kwargs: *const kclvm_value_ref_t, +) -> *const kclvm_value_ref_t { + let args = ptr_as_ref(args); + let kwargs = ptr_as_ref(kwargs); + let ctx = mut_ptr_as_ref(ctx); + + if let Some(s) = get_call_arg_str(args, kwargs, 0, Some("value")) { + let encoding = get_call_arg_str(args, kwargs, 1, Some("encoding")); + let bytes = encode_text(&s, encoding).unwrap(); + let hex = format!("{:x}", md5::compute(bytes)); + return ValueRef::str(hex.as_ref()).into_raw(ctx); + } + panic!("md5() missing 1 required positional argument: 'value'"); +} + +// sha1(value: str, encoding: str = "utf-8") -> str + +#[no_mangle] +#[runtime_fn] +pub extern "C" fn kclvm_crypto_sha1( + ctx: *mut kclvm_context_t, + args: *const kclvm_value_ref_t, + kwargs: *const kclvm_value_ref_t, +) -> *const kclvm_value_ref_t { + let args = ptr_as_ref(args); + let kwargs = ptr_as_ref(kwargs); + let ctx = mut_ptr_as_ref(ctx); + + if let Some(s) = get_call_arg_str(args, kwargs, 0, Some("value")) { + let encoding = get_call_arg_str(args, kwargs, 1, Some("encoding")); + let bytes = encode_text(&s, encoding).unwrap(); + let hex = sha1::Sha1::from(bytes).digest().to_string(); + return ValueRef::str(hex.as_ref()).into_raw(ctx); + } + panic!("sha1() missing 1 required positional argument: 'value'"); +} + +// sha224(value: str, encoding: str = "utf-8") -> str + +#[no_mangle] +#[runtime_fn] +pub extern "C" fn kclvm_crypto_sha224( + ctx: *mut kclvm_context_t, + args: *const kclvm_value_ref_t, + kwargs: *const kclvm_value_ref_t, +) -> *const kclvm_value_ref_t { + let args = ptr_as_ref(args); + let kwargs = ptr_as_ref(kwargs); + let ctx = mut_ptr_as_ref(ctx); + + if let Some(s) = get_call_arg_str(args, kwargs, 0, Some("value")) { + let encoding = get_call_arg_str(args, kwargs, 1, Some("encoding")); + let bytes = encode_text(&s, encoding).unwrap(); + let mut hasher = Sha224::new(); + hasher.update(bytes); + let result = hasher.finalize(); + + let mut hex = String::with_capacity(2 * Sha256::output_size()); + use std::fmt::Write; + + for byte in result { + let _ = write!(&mut hex, "{byte:02x}"); + } + + return ValueRef::str(hex.as_ref()).into_raw(ctx); + } + panic!("sha224() missing 1 required positional argument: 'value'"); +} + +// sha256(value: str, encoding: str = "utf-8") -> str + +#[no_mangle] +#[runtime_fn] +pub extern "C" fn kclvm_crypto_sha256( + ctx: *mut kclvm_context_t, + args: *const kclvm_value_ref_t, + kwargs: *const kclvm_value_ref_t, +) -> *const kclvm_value_ref_t { + let args = ptr_as_ref(args); + let kwargs = ptr_as_ref(kwargs); + let ctx = mut_ptr_as_ref(ctx); + + if let Some(s) = get_call_arg_str(args, kwargs, 0, Some("value")) { + let encoding = get_call_arg_str(args, kwargs, 1, Some("encoding")); + let bytes = encode_text(&s, encoding).unwrap(); + let mut hasher = Sha256::new(); + hasher.update(bytes); + let result = hasher.finalize(); + + let mut hex = String::with_capacity(2 * Sha256::output_size()); + use std::fmt::Write; + + for byte in result { + let _ = write!(&mut hex, "{byte:02x}"); + } + + return ValueRef::str(hex.as_ref()).into_raw(ctx); + } + panic!("sha256() missing 1 required positional argument: 'value'"); +} + +// sha384(value: str, encoding: str = "utf-8") -> str + +#[no_mangle] +#[runtime_fn] +pub extern "C" fn kclvm_crypto_sha384( + ctx: *mut kclvm_context_t, + args: *const kclvm_value_ref_t, + kwargs: *const kclvm_value_ref_t, +) -> *const kclvm_value_ref_t { + let args = ptr_as_ref(args); + let kwargs = ptr_as_ref(kwargs); + let ctx = mut_ptr_as_ref(ctx); + + if let Some(s) = get_call_arg_str(args, kwargs, 0, Some("value")) { + let encoding = get_call_arg_str(args, kwargs, 1, Some("encoding")); + let bytes = encode_text(&s, encoding).unwrap(); + let mut hasher = Sha384::new(); + hasher.update(bytes); + let result = hasher.finalize(); + + let mut hex = String::with_capacity(2 * Sha256::output_size()); + use std::fmt::Write; + + for byte in result { + let _ = write!(&mut hex, "{byte:02x}"); + } + + return ValueRef::str(hex.as_ref()).into_raw(ctx); + } + panic!("sha384() missing 1 required positional argument: 'value'"); +} + +// sha512(value: str, encoding: str = "utf-8") -> str + +#[no_mangle] +#[runtime_fn] +pub extern "C" fn kclvm_crypto_sha512( + ctx: *mut kclvm_context_t, + args: *const kclvm_value_ref_t, + kwargs: *const kclvm_value_ref_t, +) -> *const kclvm_value_ref_t { + let args = ptr_as_ref(args); + let kwargs = ptr_as_ref(kwargs); + let ctx = mut_ptr_as_ref(ctx); + + if let Some(s) = get_call_arg_str(args, kwargs, 0, Some("value")) { + let encoding = get_call_arg_str(args, kwargs, 1, Some("encoding")); + let bytes = encode_text(&s, encoding).unwrap(); + let mut hasher = Sha512::new(); + hasher.update(bytes); + let result = hasher.finalize(); + + let mut hex = String::with_capacity(2 * Sha256::output_size()); + use std::fmt::Write; + + for byte in result { + let _ = write!(&mut hex, "{byte:02x}"); + } + + return ValueRef::str(hex.as_ref()).into_raw(ctx); + } + panic!("sha512() missing 1 required positional argument: 'value'"); +} + +// blake3(value: str, encoding: str = "utf-8") -> str + +#[no_mangle] +#[runtime_fn] +pub extern "C" fn kclvm_crypto_blake3( + ctx: *mut kclvm_context_t, + args: *const kclvm_value_ref_t, + kwargs: *const kclvm_value_ref_t, +) -> *const kclvm_value_ref_t { + let args = ptr_as_ref(args); + let kwargs = ptr_as_ref(kwargs); + let ctx = mut_ptr_as_ref(ctx); + + if let Some(s) = get_call_arg_str(args, kwargs, 0, Some("value")) { + let encoding = get_call_arg_str(args, kwargs, 1, Some("encoding")); + let bytes = encode_text(&s, encoding).unwrap(); + let hasher = blake3::hash(&bytes); + + let mut hex = String::with_capacity(2 * blake3::OUT_LEN); + use std::fmt::Write; + + for byte in hasher.as_bytes() { + let _ = write!(&mut hex, "{byte:02x}"); + } + + return ValueRef::str(hex.as_ref()).into_raw(ctx); + } + panic!("blake3() missing 1 required positional argument: 'value'"); +} + +#[no_mangle] +#[runtime_fn] +pub extern "C" fn kclvm_crypto_uuid( + ctx: *mut kclvm_context_t, + _args: *const kclvm_value_ref_t, + _kwargs: *const kclvm_value_ref_t, +) -> *const kclvm_value_ref_t { + let ctx = mut_ptr_as_ref(ctx); + return ValueRef::str(Uuid::new_v4().to_string().as_ref()).into_raw(ctx); +} + +#[no_mangle] +#[runtime_fn] +pub extern "C" fn kclvm_crypto_filesha256( + ctx: *mut kclvm_context_t, + args: *const kclvm_value_ref_t, + kwargs: *const kclvm_value_ref_t, +) -> *const kclvm_value_ref_t { + let args = ptr_as_ref(args); + let kwargs = ptr_as_ref(kwargs); + let ctx = mut_ptr_as_ref(ctx); + + if let Some(filepath) = get_call_arg_str(args, kwargs, 0, Some("filepath")) { + // Open the file + let mut file = File::open(&filepath) + .unwrap_or_else(|e| panic!("failed to access file '{}': {}", filepath, e)); + + // Create a SHA256 hasher instance + let mut hasher = Sha256::new(); + + // Read the file content and update the hasher + let mut buffer = Vec::new(); + file.read_to_end(&mut buffer) + .unwrap_or_else(|e| panic!("failed to read file '{}': {}", filepath, e)); + hasher.update(&buffer); + + // Compute the SHA256 hash + let hash_result = hasher.finalize(); + + let mut hex = String::with_capacity(2 * Sha256::output_size()); + use std::fmt::Write; + + for byte in hash_result { + let _ = write!(&mut hex, "{byte:02x}"); + } + + return ValueRef::str(hex.as_str()).into_raw(ctx); + } + panic!("filesha256() missing 1 required positional argument: 'filepath'"); +} + +#[no_mangle] +#[runtime_fn] +pub extern "C" fn kclvm_crypto_filesha512( + ctx: *mut kclvm_context_t, + args: *const kclvm_value_ref_t, + kwargs: *const kclvm_value_ref_t, +) -> *const kclvm_value_ref_t { + let args = ptr_as_ref(args); + let kwargs = ptr_as_ref(kwargs); + let ctx = mut_ptr_as_ref(ctx); + + if let Some(filepath) = get_call_arg_str(args, kwargs, 0, Some("filepath")) { + let mut file = File::open(&filepath) + .unwrap_or_else(|e| panic!("failed to access file '{}': {}", filepath, e)); + + let mut hasher = Sha512::new(); + + let mut buffer = [0; 4096]; + while let Ok(bytes_read) = file.read(&mut buffer) { + if bytes_read == 0 { + break; // End of file + } + hasher.update(&buffer[..bytes_read]); + } + + let hash_result = hasher.finalize(); + + let hex = hash_result + .iter() + .map(|byte| format!("{byte:02x}")) + .collect::(); + + return ValueRef::str(&hex).into_raw(ctx); + } + panic!("filesha512() missing 1 required positional argument: 'filepath'"); +} + +// fileblake3 +#[no_mangle] +#[runtime_fn] +pub extern "C" fn kclvm_crypto_fileblake3( + ctx: *mut kclvm_context_t, + args: *const kclvm_value_ref_t, + kwargs: *const kclvm_value_ref_t, +) -> *const kclvm_value_ref_t { + let args = ptr_as_ref(args); + let kwargs = ptr_as_ref(kwargs); + let ctx = mut_ptr_as_ref(ctx); + + if let Some(filepath) = get_call_arg_str(args, kwargs, 0, Some("filepath")) { + let mut file = File::open(&filepath) + .unwrap_or_else(|e| panic!("failed to access file '{}': {}", filepath, e)); + + let mut buffer = Vec::new(); + file.read_to_end(&mut buffer) + .unwrap_or_else(|e| panic!("failed to read file '{}': {}", filepath, e)); + + let hasher = blake3::hash(&buffer); + + let mut hex = String::with_capacity(2 * blake3::OUT_LEN); + use std::fmt::Write; + + for byte in hasher.as_bytes() { + let _ = write!(&mut hex, "{byte:02x}"); + } + + return ValueRef::str(hex.as_str()).into_raw(ctx); + } + panic!("fileblake3() missing 1 required positional argument: 'filepath'"); +} diff --git a/kclvm/runtime/src/datetime/datetime.rs b/kclvm/runtime/src/datetime/datetime.rs deleted file mode 100644 index 79161b43d..000000000 --- a/kclvm/runtime/src/datetime/datetime.rs +++ /dev/null @@ -1,64 +0,0 @@ -//! KCL datetime system module -//! -//! Copyright 2021 The KCL Authors. All rights reserved. - -extern crate chrono; - -use chrono::prelude::Local; - -use crate::*; - -#[allow(non_camel_case_types)] -type kclvm_value_ref_t = ValueRef; - -// def KMANGLED_today() -> str: - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_datetime_today( - _ctx: *mut kclvm_context_t, - _args: *const kclvm_value_ref_t, - _kwargs: *const kclvm_value_ref_t, -) -> *const kclvm_value_ref_t { - let s = Local::today().to_string(); - return ValueRef::str(s.as_ref()).into_raw(); -} - -// def KMANGLED_now() -> str: - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_datetime_now( - _ctx: *mut kclvm_context_t, - _args: *const kclvm_value_ref_t, - _kwargs: *const kclvm_value_ref_t, -) -> *const kclvm_value_ref_t { - let s = Local::now().to_string(); - return ValueRef::str(s.as_ref()).into_raw(); -} - -// def KMANGLED_ticks() -> float: - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_datetime_ticks( - _ctx: *mut kclvm_context_t, - _args: *const kclvm_value_ref_t, - _kwargs: *const kclvm_value_ref_t, -) -> *const kclvm_value_ref_t { - let x = Local::now().timestamp(); - ValueRef::float(x as f64).into_raw() -} - -// def KMANGLED_date() -> str: - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_datetime_date( - _ctx: *mut kclvm_context_t, - _args: *const kclvm_value_ref_t, - _kwargs: *const kclvm_value_ref_t, -) -> *const kclvm_value_ref_t { - let s = Local::today().to_string(); - return ValueRef::str(s.as_ref()).into_raw(); -} diff --git a/kclvm/runtime/src/datetime/mod.rs b/kclvm/runtime/src/datetime/mod.rs index 6aa3369cc..5c8873fee 100644 --- a/kclvm/runtime/src/datetime/mod.rs +++ b/kclvm/runtime/src/datetime/mod.rs @@ -1,4 +1,109 @@ -// Copyright 2021 The KCL Authors. All rights reserved. +//! Copyright The KCL Authors. All rights reserved. -pub mod datetime; -pub use self::datetime::*; +extern crate chrono; + +use chrono::{prelude::Local, NaiveDate, NaiveDateTime, NaiveTime}; + +use crate::*; + +/// Return the "%Y-%m-%d %H:%M:%S.%{ticks}" format date. +/// `today() -> str` +#[no_mangle] +#[runtime_fn] +pub extern "C" fn kclvm_datetime_today( + ctx: *mut kclvm_context_t, + _args: *const kclvm_value_ref_t, + _kwargs: *const kclvm_value_ref_t, +) -> *const kclvm_value_ref_t { + let s = Local::now(); + let ctx = mut_ptr_as_ref(ctx); + ValueRef::str(&(s.format("%Y-%m-%d %H:%M:%S").to_string() + "." + &s.timestamp().to_string())) + .into_raw(ctx) +} + +/// Return the local time format. e.g. 'Sat Jun 06 16:26:11 1998' or format the combined date and time per the specified format string, +/// and the default date format is "%a %b %d %H:%M:%S %Y". +/// `now() -> str` +#[no_mangle] +#[runtime_fn] +pub extern "C" fn kclvm_datetime_now( + ctx: *mut kclvm_context_t, + args: *const kclvm_value_ref_t, + kwargs: *const kclvm_value_ref_t, +) -> *const kclvm_value_ref_t { + let s = Local::now(); + let ctx = mut_ptr_as_ref(ctx); + let args = ptr_as_ref(args); + let kwargs = ptr_as_ref(kwargs); + let format = get_call_arg_str(args, kwargs, 0, Some("format")) + .unwrap_or_else(|| "%a %b %d %H:%M:%S %Y".to_string()); + ValueRef::str(&s.format(&format).to_string()).into_raw(ctx) +} + +/// Return the current time in seconds since the Epoch. Fractions of a second may be present if the system clock provides them. +/// `ticks() -> float` +#[no_mangle] +#[runtime_fn] +pub extern "C" fn kclvm_datetime_ticks( + ctx: *mut kclvm_context_t, + _args: *const kclvm_value_ref_t, + _kwargs: *const kclvm_value_ref_t, +) -> *const kclvm_value_ref_t { + let ctx = mut_ptr_as_ref(ctx); + let x = Local::now().timestamp(); + ValueRef::float(x as f64).into_raw(ctx) +} + +/// Return the %Y-%m-%d %H:%M:%S format date. +/// `date() -> str` +#[no_mangle] +#[runtime_fn] +pub extern "C" fn kclvm_datetime_date( + ctx: *mut kclvm_context_t, + _args: *const kclvm_value_ref_t, + _kwargs: *const kclvm_value_ref_t, +) -> *const kclvm_value_ref_t { + let s = Local::now(); + let ctx = mut_ptr_as_ref(ctx); + ValueRef::str(&s.format("%Y-%m-%d %H:%M:%S").to_string()).into_raw(ctx) +} + +/// Validates whether the provided date string matches the specified format. +/// `validate(str, str) -> bool` +#[no_mangle] +#[runtime_fn] +pub extern "C" fn kclvm_datetime_validate( + ctx: *mut kclvm_context_t, + args: *const kclvm_value_ref_t, + kwargs: *const kclvm_value_ref_t, +) -> *const kclvm_value_ref_t { + let ctx = mut_ptr_as_ref(ctx); + let args = ptr_as_ref(args); + let kwargs = ptr_as_ref(kwargs); + if let Some(date) = get_call_arg_str(args, kwargs, 0, Some("date")) { + if let Some(format) = get_call_arg_str(args, kwargs, 1, Some("format")) { + let result = validate_date(&date, &format); + return ValueRef::bool(result).into_raw(ctx); + } + panic!("validate() takes 2 positional arguments (1 given)"); + } + panic!("validate() takes 2 positional arguments (0 given)"); +} + +/// Validates whether the provided date string matches the specified format. +/// +/// # Parameters +/// - `date`: A string slice representing the date to be validated. +/// - `format`: A string slice representing the expected format for the date. +/// +/// # Returns +/// - Returns `true` if the date string successfully parses according to the specified format, +/// otherwise, returns `false`. +#[inline] +fn validate_date(date: &str, format: &str) -> bool { + NaiveDateTime::parse_from_str(date, format) + .map(|_| true) + .or_else(|_| NaiveDate::parse_from_str(date, format).map(|_| true)) + .or_else(|_| NaiveTime::parse_from_str(date, format).map(|_| true)) + .is_ok() +} diff --git a/kclvm/runtime/src/encoding/mod.rs b/kclvm/runtime/src/encoding/mod.rs new file mode 100644 index 000000000..31555ed11 --- /dev/null +++ b/kclvm/runtime/src/encoding/mod.rs @@ -0,0 +1,36 @@ +use anyhow::{bail, Result}; +use encoding::{all::encodings, EncoderTrap}; + +/// Encoding string value to bytes with specific encoding format. +pub fn encode_text(value: &str, encoding: Option) -> Result> { + if let Some(encoding) = encoding { + let encoding = normalize_encoding_name(&encoding)?; + let valid_encodings = encodings(); + for valid_encoding in valid_encodings { + if valid_encoding.name() == encoding { + return valid_encoding + .encode(value, EncoderTrap::Strict) + .map_err(|e| anyhow::anyhow!(e)); + } + } + bail!("unknown encoding {encoding}") + } else { + Ok(value.as_bytes().to_vec()) + } +} + +fn normalize_encoding_name(encoding: &str) -> Result { + if let Some(i) = encoding.find(|c: char| c == ' ' || c.is_ascii_uppercase()) { + let mut out = encoding.as_bytes().to_owned(); + for byte in &mut out[i..] { + if *byte == b' ' { + *byte = b'-'; + } else { + byte.make_ascii_lowercase(); + } + } + String::from_utf8(out).map_err(|e| anyhow::anyhow!(e)) + } else { + Ok(encoding.into()) + } +} diff --git a/kclvm/runtime/src/eval/mod.rs b/kclvm/runtime/src/eval/mod.rs new file mode 100644 index 000000000..5b31a834d --- /dev/null +++ b/kclvm/runtime/src/eval/mod.rs @@ -0,0 +1,122 @@ +use std::{ + mem::transmute_copy, + panic::{RefUnwindSafe, UnwindSafe}, +}; + +use crate::{ + kclvm_context_t, kclvm_eval_scope_t, kclvm_value_ref_t, mut_ptr_as_ref, Context, IndexMap, + ValueRef, +}; + +/// Variable setter function type. fn(ctx: &mut Context, scope: &mut ScopeEval, args: ValueRef, kwargs: ValueRef) -> ValueRef. +pub type SetterFuncType = + unsafe extern "C" fn(*mut kclvm_context_t, *mut kclvm_eval_scope_t) -> *const kclvm_value_ref_t; + +/// LazyEvalScope represents a scope of sequentially independent calculations, where +/// the calculation of values is lazy and only recursively performed through +/// backtracking when needed. +#[derive(PartialEq, Clone, Default, Debug)] +pub struct LazyEvalScope { + /// Temp variable values. + pub vars: IndexMap, + /// Variable value cache. + pub cache: IndexMap, + /// Backtrack levels. + pub levels: IndexMap, + /// Variable setter function pointers. + pub setters: IndexMap>, + /// Calculate times without backtracking. + pub cal_times: IndexMap, +} + +impl LazyEvalScope { + #[inline] + pub fn is_backtracking(&self, key: &str) -> bool { + let level = self.levels.get(key).unwrap_or(&0); + *level > 0 + } + + #[inline] + pub fn setter_len(&self, key: &str) -> usize { + self.setters.get(key).unwrap_or(&vec![]).len() + } + + #[inline] + pub fn cal_increment(&mut self, key: &str) -> bool { + if self.is_backtracking(key) { + false + } else { + let cal_time = *self.cal_times.get(key).unwrap_or(&0); + let next_cal_time = cal_time + 1; + self.cal_times.insert(key.to_string(), next_cal_time); + next_cal_time >= self.setter_len(key) + } + } + + #[inline] + pub fn contains_key(&self, key: &str) -> bool { + self.vars.contains_key(key) + } + + /// Get the value from the context. + pub fn get_value(&mut self, ctx: &mut Context, key: &str, target: &str) -> ValueRef { + let value = match self.vars.get(key) { + Some(value) => value.clone(), + None => ValueRef::undefined(), + }; + // Deal in-place modify and return it self immediately. + if key == target && (!self.is_backtracking(key) || self.setter_len(key) <= 1) { + value + } else { + match self.cache.get(key) { + Some(value) => value.clone(), + None => { + match &self.setters.get(key) { + Some(setters) if !setters.is_empty() => { + // Call all setters function to calculate the value recursively. + let level = *self.levels.get(key).unwrap_or(&0); + let next_level = level + 1; + self.levels.insert(key.to_string(), next_level); + let n = setters.len(); + let index = n - next_level; + if index >= n { + value + } else { + let fn_ptr = setters[index]; + unsafe { + let ctx_ref = mut_ptr_as_ref(ctx); + let panic_info = ctx_ref.panic_info.clone(); + let setter_fn: SetterFuncType = transmute_copy(&fn_ptr); + // Restore the panic info of current schema attribute. + ctx_ref.panic_info = panic_info; + // Call setter functions + setter_fn(ctx, self) + }; + self.levels.insert(key.to_string(), level); + let value = match self.vars.get(key) { + Some(value) => value.clone(), + None => ValueRef::undefined(), + }; + self.cache.insert(key.to_string(), value.clone()); + value + } + } + _ => value, + } + } + } + } + } + + /// Set value to the context. + #[inline] + pub fn set_value(&mut self, key: &str, value: &ValueRef) { + self.vars.insert(key.to_string(), value.clone()); + if self.cal_increment(key) && self.cache.get(key).is_none() { + self.cache.insert(key.to_string(), value.clone()); + } + } +} + +impl UnwindSafe for LazyEvalScope {} +impl RefUnwindSafe for LazyEvalScope {} diff --git a/kclvm/runtime/src/file/mod.rs b/kclvm/runtime/src/file/mod.rs new file mode 100644 index 000000000..311f6981a --- /dev/null +++ b/kclvm/runtime/src/file/mod.rs @@ -0,0 +1,369 @@ +mod utils; + +use std::{fs, io::ErrorKind}; + +use crate::*; +use glob::glob; +use std::io::Write; +use std::path::Path; + +#[no_mangle] +#[runtime_fn] +pub extern "C" fn kclvm_file_read( + ctx: *mut kclvm_context_t, + args: *const kclvm_value_ref_t, + kwargs: *const kclvm_value_ref_t, +) -> *const kclvm_value_ref_t { + let args = ptr_as_ref(args); + let kwargs = ptr_as_ref(kwargs); + let ctx = mut_ptr_as_ref(ctx); + + if let Some(x) = get_call_arg_str(args, kwargs, 0, Some("filepath")) { + let contents = fs::read_to_string(&x) + .unwrap_or_else(|e| panic!("failed to access the file '{}': {}", x, e)); + + let s = ValueRef::str(contents.as_ref()); + return s.into_raw(ctx); + } + + panic!("read() takes exactly one argument (0 given)"); +} + +#[no_mangle] +#[runtime_fn] +pub extern "C" fn kclvm_file_glob( + ctx: *mut kclvm_context_t, + args: *const kclvm_value_ref_t, + kwargs: *const kclvm_value_ref_t, +) -> *const kclvm_value_ref_t { + let args = ptr_as_ref(args); + let kwargs = ptr_as_ref(kwargs); + let ctx = mut_ptr_as_ref(ctx); + + let pattern = get_call_arg_str(args, kwargs, 0, Some("pattern")) + .expect("glob() takes exactly one argument (0 given)"); + + let mut matched_paths = vec![]; + for entry in glob(&pattern).unwrap_or_else(|e| panic!("Failed to read glob pattern: {}", e)) { + match entry { + Ok(path) => matched_paths.push(path.display().to_string()), + Err(e) => panic!("failed to access the file matching '{}': {}", pattern, e), + } + } + + ValueRef::list_str(matched_paths.as_slice()).into_raw(ctx) +} + +#[no_mangle] +#[runtime_fn] +pub extern "C" fn kclvm_file_modpath( + ctx: *mut kclvm_context_t, + _args: *const kclvm_value_ref_t, + _kwargs: *const kclvm_value_ref_t, +) -> *const kclvm_value_ref_t { + let ctx = mut_ptr_as_ref(ctx); + let s = ValueRef::str(ctx.module_path.as_ref()); + s.into_raw(ctx) +} + +#[no_mangle] +#[runtime_fn] +pub extern "C" fn kclvm_file_workdir( + ctx: *mut kclvm_context_t, + _args: *const kclvm_value_ref_t, + _kwargs: *const kclvm_value_ref_t, +) -> *const kclvm_value_ref_t { + let ctx = mut_ptr_as_ref(ctx); + let s = ValueRef::str(ctx.workdir.as_ref()); + s.into_raw(ctx) +} + +/// Read the path of the current script or module that is being executed +#[no_mangle] +#[runtime_fn] +pub extern "C" fn kclvm_file_current( + ctx: *mut kclvm_context_t, + _args: *const kclvm_value_ref_t, + _kwargs: *const kclvm_value_ref_t, +) -> *const kclvm_value_ref_t { + let ctx = mut_ptr_as_ref(ctx); + let s = ValueRef::str(ctx.panic_info.kcl_file.as_ref()); + s.into_raw(ctx) +} + +/// Whether this file path exists. Returns true if the path points at +/// an existing entity. This function will traverse symbolic links to +/// query information about the destination file. +#[no_mangle] +#[runtime_fn] +pub extern "C" fn kclvm_file_exists( + ctx: *mut kclvm_context_t, + args: *const kclvm_value_ref_t, + kwargs: *const kclvm_value_ref_t, +) -> *const kclvm_value_ref_t { + let args = ptr_as_ref(args); + let kwargs = ptr_as_ref(kwargs); + let ctx = mut_ptr_as_ref(ctx); + + if let Some(path) = get_call_arg_str(args, kwargs, 0, Some("filepath")) { + let exist = Path::new(&path).exists(); + return ValueRef::bool(exist).into_raw(ctx); + } + + panic!("read() takes exactly one argument (0 given)"); +} + +/// Returns the canonical, absolute form of the path with all intermediate +/// components normalized and symbolic links resolved. +#[no_mangle] +#[runtime_fn] +pub extern "C" fn kclvm_file_abs( + ctx: *mut kclvm_context_t, + args: *const kclvm_value_ref_t, + kwargs: *const kclvm_value_ref_t, +) -> *const kclvm_value_ref_t { + let args = ptr_as_ref(args); + let kwargs = ptr_as_ref(kwargs); + let ctx = mut_ptr_as_ref(ctx); + + if let Some(path) = get_call_arg_str(args, kwargs, 0, Some("filepath")) { + if let Ok(abs_path) = Path::new(&path).canonicalize() { + return ValueRef::str(abs_path.to_str().unwrap()).into_raw(ctx); + } else { + panic!("Could not get the absolute path of {path}"); + } + } + + panic!("read() takes exactly one argument (0 given)"); +} + +#[no_mangle] +#[runtime_fn] +pub extern "C" fn kclvm_file_mkdir( + ctx: *mut kclvm_context_t, + args: *const kclvm_value_ref_t, + kwargs: *const kclvm_value_ref_t, +) -> *const kclvm_value_ref_t { + let args = ptr_as_ref(args); + let kwargs = ptr_as_ref(kwargs); + let ctx = mut_ptr_as_ref(ctx); + + if let Some(path) = get_call_arg_str(args, kwargs, 0, Some("directory")) { + let exists = get_call_arg_bool(args, kwargs, 1, Some("exists")).unwrap_or_default(); + if let Err(e) = fs::create_dir_all(&path) { + // Ignore the file exists error. + if exists && matches!(e.kind(), ErrorKind::AlreadyExists) { + return ValueRef::none().into_raw(ctx); + } + panic!("Failed to create directory '{}': {}", path, e); + } + return ValueRef::none().into_raw(ctx); + } + + panic!("mkdir() takes exactly one argument (0 given)"); +} + +#[no_mangle] +#[runtime_fn] +pub extern "C" fn kclvm_file_delete( + ctx: *mut kclvm_context_t, + args: *const kclvm_value_ref_t, + kwargs: *const kclvm_value_ref_t, +) -> *const kclvm_value_ref_t { + let args = ptr_as_ref(args); + let kwargs = ptr_as_ref(kwargs); + let ctx = mut_ptr_as_ref(ctx); + + if let Some(path) = get_call_arg_str(args, kwargs, 0, Some("filepath")) { + if let Err(e) = fs::remove_file(&path) { + match e.kind() { + std::io::ErrorKind::NotFound => { + // if file not found, try to remove it as a directory + if let Err(e) = fs::remove_dir(&path) { + panic!("failed to delete '{}': {}", path, e); + } + } + _ => { + panic!("failed to delete '{}': {}", path, e); + } + } + } + return ValueRef::none().into_raw(ctx); + } + + panic!("delete() takes exactly one argument (0 given)"); +} + +#[no_mangle] +#[runtime_fn] +pub extern "C" fn kclvm_file_cp( + ctx: *mut kclvm_context_t, + args: *const kclvm_value_ref_t, + kwargs: *const kclvm_value_ref_t, +) -> *const kclvm_value_ref_t { + let args = ptr_as_ref(args); + let kwargs = ptr_as_ref(kwargs); + let ctx = mut_ptr_as_ref(ctx); + + if let Some(src_path) = get_call_arg_str(args, kwargs, 0, Some("src")) { + if let Some(dest_path) = get_call_arg_str(args, kwargs, 1, Some("dest")) { + let src_path = Path::new(&src_path); + let dest_path = Path::new(&dest_path); + let result = if src_path.is_dir() { + utils::copy_directory(&src_path, &dest_path) + } else { + fs::copy(&src_path, &dest_path).map(|_| ()) + }; + if let Err(e) = result { + panic!( + "Failed to copy from '{}' to '{}': {}", + src_path.display(), + dest_path.display(), + e + ); + } + return ValueRef::none().into_raw(ctx); + } else { + panic!("cp() missing 'dest_path' argument"); + } + } else { + panic!("cp() missing 'src_path' argument"); + } +} + +#[no_mangle] +#[runtime_fn] +pub extern "C" fn kclvm_file_mv( + ctx: *mut kclvm_context_t, + args: *const kclvm_value_ref_t, + kwargs: *const kclvm_value_ref_t, +) -> *const kclvm_value_ref_t { + let args = ptr_as_ref(args); + let kwargs = ptr_as_ref(kwargs); + let ctx = mut_ptr_as_ref(ctx); + + if let Some(src_path) = get_call_arg_str(args, kwargs, 0, Some("src")) { + if let Some(dest_path) = get_call_arg_str(args, kwargs, 1, Some("dest")) { + if let Err(e) = fs::rename(&src_path, &dest_path) { + panic!("Failed to move '{}' to '{}': {}", src_path, dest_path, e); + } + return ValueRef::none().into_raw(ctx); + } else { + panic!("mv() missing 'dest_path' argument"); + } + } else { + panic!("mv() missing 'src_path' argument"); + } +} + +#[no_mangle] +#[runtime_fn] +pub extern "C" fn kclvm_file_size( + ctx: *mut kclvm_context_t, + args: *const kclvm_value_ref_t, + kwargs: *const kclvm_value_ref_t, +) -> *const kclvm_value_ref_t { + let args = ptr_as_ref(args); + let kwargs = ptr_as_ref(kwargs); + let ctx = mut_ptr_as_ref(ctx); + + if let Some(path) = get_call_arg_str(args, kwargs, 0, Some("filepath")) { + let metadata = fs::metadata(&path); + match metadata { + Ok(metadata) => { + let size = metadata.len(); + let value = kclvm::ValueRef::int(size as i64); + return value.into_raw(ctx); + } + Err(e) => { + panic!("failed to get size of '{}': {}", path, e); + } + } + } + + panic!("size() takes exactly one argument (0 given)"); +} + +#[no_mangle] +#[runtime_fn] +pub extern "C" fn kclvm_file_write( + ctx: *mut kclvm_context_t, + args: *const kclvm_value_ref_t, + kwargs: *const kclvm_value_ref_t, +) -> *const kclvm_value_ref_t { + let args = ptr_as_ref(args); + let kwargs = ptr_as_ref(kwargs); + let ctx = mut_ptr_as_ref(ctx); + + if let Some(path) = get_call_arg_str(args, kwargs, 0, Some("filepath")) { + if let Some(content) = get_call_arg_str(args, kwargs, 1, Some("content")) { + match fs::File::create(&path) { + Ok(mut file) => { + if let Err(e) = file.write_all(content.as_bytes()) { + panic!("Failed to write to '{}': {}", path, e); + } + return ValueRef::none().into_raw(ctx); + } + Err(e) => panic!("Failed to create file '{}': {}", path, e), + } + } else { + panic!("write() missing 'content' argument"); + } + } else { + panic!("write() missing 'filepath' argument"); + } +} + +#[no_mangle] +#[runtime_fn] +pub extern "C" fn kclvm_file_append( + ctx: *mut kclvm_context_t, + args: *const kclvm_value_ref_t, + kwargs: *const kclvm_value_ref_t, +) -> *const kclvm_value_ref_t { + let args = ptr_as_ref(args); + let kwargs = ptr_as_ref(kwargs); + let ctx = mut_ptr_as_ref(ctx); + + if let Some(path) = get_call_arg_str(args, kwargs, 0, Some("filepath")) { + if let Some(content) = get_call_arg_str(args, kwargs, 1, Some("content")) { + // Open the file in append mode, creating it if it doesn't exist + match fs::OpenOptions::new().append(true).create(true).open(&path) { + Ok(mut file) => { + if let Err(e) = file.write_all(content.as_bytes()) { + panic!("Failed to append to file '{}': {}", path, e); + } + return ValueRef::none().into_raw(ctx); + } + Err(e) => { + panic!("Failed to open or create file '{}': {}", path, e); + } + } + } else { + panic!("append() requires 'content' argument"); + } + } else { + panic!("append() requires 'filepath' argument"); + } +} + +#[no_mangle] +#[runtime_fn] +pub extern "C" fn kclvm_file_read_env( + ctx: *mut kclvm_context_t, + args: *const kclvm_value_ref_t, + kwargs: *const kclvm_value_ref_t, +) -> *const kclvm_value_ref_t { + let args = ptr_as_ref(args); + let kwargs = ptr_as_ref(kwargs); + let ctx = mut_ptr_as_ref(ctx); + + if let Some(key) = get_call_arg_str(args, kwargs, 0, Some("key")) { + match std::env::var(key) { + Ok(v) => ValueRef::str(&v).into_raw(ctx), + Err(_) => ValueRef::undefined().into_raw(ctx), + } + } else { + panic!("read_env() requires 'key' argument"); + } +} diff --git a/kclvm/runtime/src/file/utils.rs b/kclvm/runtime/src/file/utils.rs new file mode 100644 index 000000000..761e89f4c --- /dev/null +++ b/kclvm/runtime/src/file/utils.rs @@ -0,0 +1,19 @@ +use std::{fs, path::Path}; + +pub(crate) fn copy_directory(src: &Path, dst: &Path) -> std::io::Result<()> { + if !dst.exists() { + fs::create_dir_all(&dst)?; + } + for entry in fs::read_dir(src)? { + let entry = entry?; + let file_type = entry.file_type()?; + let new_src = entry.path(); + let new_dst = dst.join(entry.file_name()); + if file_type.is_dir() { + copy_directory(&new_src, &new_dst)?; + } else if file_type.is_file() { + fs::copy(&new_src, &new_dst)?; + } + } + Ok(()) +} diff --git a/kclvm/runtime/src/json/json.rs b/kclvm/runtime/src/json/json.rs deleted file mode 100644 index b8c5e6fa0..000000000 --- a/kclvm/runtime/src/json/json.rs +++ /dev/null @@ -1,78 +0,0 @@ -//! KCL json system module -//! -//! Copyright 2021 The KCL Authors. All rights reserved. - -use crate::*; - -#[allow(non_camel_case_types)] -type kclvm_value_ref_t = ValueRef; - -// data, sort_keys=False, indent=None, ignore_private=False, ignore_none=False - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_json_encode( - _ctx: *mut kclvm_context_t, - args: *const kclvm_value_ref_t, - kwargs: *const kclvm_value_ref_t, -) -> *const kclvm_value_ref_t { - let args = ptr_as_ref(args); - let kwargs = ptr_as_ref(kwargs); - - let mut opt = JsonEncodeOptions::default(); - if let Some(sort_keys) = kwargs.kwarg_bool("sort_keys", None) { - opt.sort_keys = sort_keys; - } - if let Some(indent) = kwargs.kwarg_int("indent", None) { - opt.indent = indent; - } - if let Some(ignore_private) = kwargs.kwarg_bool("ignore_private", None) { - opt.ignore_private = ignore_private; - } - if let Some(ignore_none) = kwargs.kwarg_bool("ignore_none", None) { - opt.ignore_none = ignore_none; - } - - if let Some(arg0) = args.arg_i(0) { - let s = ValueRef::str(arg0.to_json_string_with_option(&opt).as_ref()); - return s.into_raw(); - } - panic!("encode() missing 1 required positional argument: 'value'") -} - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_json_decode( - _ctx: *mut kclvm_context_t, - args: *const kclvm_value_ref_t, - _kwargs: *const kclvm_value_ref_t, -) -> *const kclvm_value_ref_t { - let args = ptr_as_ref(args); - - if let Some(arg0) = args.arg_i(0) { - if let Some(x) = ValueRef::from_json(arg0.as_str().as_ref()) { - return x.into_raw(); - } - } - panic!("decode() missing 1 required positional argument: 'value'") -} - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_json_dump_to_file( - _ctx: *mut kclvm_context_t, - args: *const kclvm_value_ref_t, - _kwargs: *const kclvm_value_ref_t, -) -> *const kclvm_value_ref_t { - let args = ptr_as_ref(args); - - if let Some(data) = args.arg_i(0) { - if let Some(filename) = args.arg_i(0) { - let yaml = data.to_json_string(); - let filename = filename.as_str(); - - std::fs::write(filename, yaml).expect("Unable to write file"); - } - } - panic!("dump_to_file() missing 2 required positional arguments: 'data' and 'filename'") -} diff --git a/kclvm/runtime/src/json/mod.rs b/kclvm/runtime/src/json/mod.rs index 4859bd9cb..24d9230c7 100644 --- a/kclvm/runtime/src/json/mod.rs +++ b/kclvm/runtime/src/json/mod.rs @@ -1,4 +1,109 @@ -// Copyright 2021 The KCL Authors. All rights reserved. +//! Copyright The KCL Authors. All rights reserved. -pub mod json; -pub use self::json::*; +use crate::*; + +// data, sort_keys=False, indent=None, ignore_private=False, ignore_none=False + +#[no_mangle] +#[runtime_fn] +pub extern "C" fn kclvm_json_encode( + ctx: *mut kclvm_context_t, + args: *const kclvm_value_ref_t, + kwargs: *const kclvm_value_ref_t, +) -> *const kclvm_value_ref_t { + let args = ptr_as_ref(args); + let ctx = mut_ptr_as_ref(ctx); + let kwargs = ptr_as_ref(kwargs); + + if let Some(arg0) = get_call_arg(args, kwargs, 0, Some("data")) { + let s = ValueRef::str( + arg0.to_json_string_with_options(&args_to_opts(args, kwargs, 1)) + .as_ref(), + ); + return s.into_raw(ctx); + } + panic!("encode() missing 1 required positional argument: 'value'") +} + +#[no_mangle] +#[runtime_fn] +pub extern "C" fn kclvm_json_decode( + ctx: *mut kclvm_context_t, + args: *const kclvm_value_ref_t, + kwargs: *const kclvm_value_ref_t, +) -> *const kclvm_value_ref_t { + let args = ptr_as_ref(args); + let kwargs = ptr_as_ref(kwargs); + let ctx = mut_ptr_as_ref(ctx); + + if let Some(arg0) = get_call_arg(args, kwargs, 0, Some("value")) { + match ValueRef::from_json(ctx, arg0.as_str().as_ref()) { + Ok(x) => return x.into_raw(ctx), + Err(err) => panic!("{}", err), + } + } + panic!("decode() missing 1 required positional argument: 'value'") +} + +#[no_mangle] +#[runtime_fn] +pub extern "C" fn kclvm_json_validate( + ctx: *mut kclvm_context_t, + args: *const kclvm_value_ref_t, + kwargs: *const kclvm_value_ref_t, +) -> *const kclvm_value_ref_t { + let args = ptr_as_ref(args); + let kwargs = ptr_as_ref(kwargs); + let ctx = mut_ptr_as_ref(ctx); + + if let Some(arg0) = get_call_arg(args, kwargs, 0, Some("value")) { + match ValueRef::from_json(ctx, arg0.as_str().as_ref()) { + Ok(_) => return kclvm_value_True(ctx), + Err(_) => return kclvm_value_False(ctx), + } + } + panic!("validate() missing 1 required positional argument: 'value'") +} + +#[no_mangle] +#[runtime_fn] +pub extern "C" fn kclvm_json_dump_to_file( + ctx: *mut kclvm_context_t, + args: *const kclvm_value_ref_t, + kwargs: *const kclvm_value_ref_t, +) -> *const kclvm_value_ref_t { + let args = ptr_as_ref(args); + let kwargs = ptr_as_ref(kwargs); + let data = args.arg_i(0).or(kwargs.get_by_key("data")); + let filename = args.arg_i(1).or(kwargs.get_by_key("filename")); + match (data, filename) { + (Some(data), Some(filename)) => { + let filename = filename.as_str(); + let json = data.to_json_string_with_options(&args_to_opts(args, kwargs, 2)); + std::fs::write(&filename, json) + .unwrap_or_else(|e| panic!("Unable to write file '{}': {}", filename, e)); + kclvm_value_Undefined(ctx) + } + _ => { + panic!("dump_to_file() missing 2 required positional arguments: 'data' and 'filename'") + } + } +} + +fn args_to_opts(args: &ValueRef, kwargs: &ValueRef, index: usize) -> JsonEncodeOptions { + let mut opts = JsonEncodeOptions::default(); + if let Some(sort_keys) = get_call_arg_bool(args, kwargs, index, Some("sort_keys")) { + opts.sort_keys = sort_keys; + } + if let Some(indent) = get_call_arg_int(args, kwargs, index + 1, Some("indent")) { + opts.indent = indent; + } + if let Some(ignore_private) = get_call_arg_bool(args, kwargs, index + 2, Some("ignore_private")) + { + opts.ignore_private = ignore_private; + } + if let Some(ignore_none) = get_call_arg_bool(args, kwargs, index + 3, Some("ignore_none")) { + opts.ignore_none = ignore_none; + } + opts +} diff --git a/kclvm/runtime/src/lib.rs b/kclvm/runtime/src/lib.rs index fad7f33eb..d3c630e80 100644 --- a/kclvm/runtime/src/lib.rs +++ b/kclvm/runtime/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2021 The KCL Authors. All rights reserved. +//! Copyright The KCL Authors. All rights reserved. use kclvm_runtime_internal_macros::runtime_fn; @@ -6,6 +6,10 @@ use kclvm_runtime_internal_macros::runtime_fn; // api-spec(c): typedef struct kclvm_context_t kclvm_context_t; // api-spec(llvm): %"kclvm_context_t" = type { i8* } +// api-spec: kclvm_eval_scope_t +// api-spec(c): typedef struct kclvm_eval_scope_t kclvm_eval_scope_t; +// api-spec(llvm): %"kclvm_eval_scope_t" = type { i8* } + // api-spec: kclvm_type_t // api-spec(c): typedef struct kclvm_type_t kclvm_type_t; // api-spec(llvm): %"kclvm_type_t" = type { i8* } @@ -77,12 +81,19 @@ pub use self::collection::*; pub mod crypto; pub use self::crypto::*; +mod eval; + pub mod datetime; pub use self::datetime::*; +pub mod encoding; + pub mod json; pub use self::json::*; +pub mod manifests; +pub use self::manifests::*; + pub mod math; pub use self::math::*; @@ -95,15 +106,21 @@ pub use self::regex::*; pub mod stdlib; pub use self::stdlib::*; -pub mod testing; -pub use self::testing::*; - pub mod units; pub use self::units::*; pub mod yaml; pub use self::yaml::*; +pub mod file; +pub use self::file::*; + +pub mod template; +pub use self::template::*; + +pub mod panic; +pub use self::panic::*; + pub mod _kcl_run; pub use self::_kcl_run::*; @@ -113,4 +130,4 @@ pub use self::_kclvm::*; pub mod _kclvm_addr; pub use self::_kclvm_addr::*; -type IndexMap = indexmap::IndexMap; +pub type IndexMap = indexmap::IndexMap; diff --git a/kclvm/runtime/src/manifests/mod.rs b/kclvm/runtime/src/manifests/mod.rs new file mode 100644 index 000000000..092f602f4 --- /dev/null +++ b/kclvm/runtime/src/manifests/mod.rs @@ -0,0 +1,102 @@ +//! KCL manifests system module +//! +//! Copyright The KCL Authors. All rights reserved. + +use crate::*; + +#[cfg(test)] +mod tests; +mod yaml; + +#[allow(non_camel_case_types)] +type kclvm_value_ref_t = ValueRef; + +/// The function is to serialize a list of KCL objects to YAML and output using the style with +/// the `---\n` separator, and put it to the custom manifest output in the context. +/// +/// ManifestsYamlStreamOptions contain these options +/// - sort_keys: Sort the encode result by keys (defaults to false). +/// - ignore_private: Whether to ignore the attribute whose name starts with +/// a character `_` (defaults to false). +/// - ignore_none: Whether to ignore the attribute whose value is `None` (defaults to false). +/// - sep: Which separator to use between YAML documents (defaults to "---"). +/// More information: https://github.com/kcl-lang/kcl/issues/94 +/// +/// - Function signature. +/// +/// ```kcl, no run +/// schema ManifestsYamlStreamOptions: +/// sort_keys: bool = False +/// ignore_private: bool = True +/// ignore_none: bool = False +/// separator: str = "---\n" +/// +/// manifests.yaml_stream(values: [any], * , opts: ManifestsYamlStreamOptions = ManifestsYamlStreamOptions {}) +/// ``` +/// +/// - Usage +/// +/// ```kcl, no run +/// import manifests +/// +/// config1 = {k1 = "v1"} +/// config2 = {k2 = "v2"} +/// +/// manifests.yaml_stream([config1, config2]) +/// manifests.yaml_stream([config1, config2], opts = { +/// sort_keys = True +/// ignore_none = True +/// }) +/// ``` +/// TODO: more options on the function `yaml_stream`. +#[no_mangle] +#[runtime_fn] +pub extern "C" fn kclvm_manifests_yaml_stream( + ctx: *mut kclvm_context_t, + args: *const kclvm_value_ref_t, + kwargs: *const kclvm_value_ref_t, +) -> *const kclvm_value_ref_t { + let args = ptr_as_ref(args); + let kwargs = ptr_as_ref(kwargs); + let ctx = mut_ptr_as_ref(ctx); + + // Get the YAML encode options from the second keyword argument `opts`. + let opts = match kwargs.kwarg("opts").or_else(|| args.arg_i(1)) { + Some(opts) => { + if opts.is_config() { + // Get options or default. + YamlEncodeOptions { + sort_keys: opts + .get_by_key("sort_keys") + .unwrap_or_else(|| ValueRef::bool(false)) + .as_bool(), + ignore_private: opts + .get_by_key("ignore_private") + .unwrap_or_else(|| ValueRef::bool(true)) + .as_bool(), + ignore_none: opts + .get_by_key("ignore_none") + .unwrap_or_else(|| ValueRef::bool(false)) + .as_bool(), + sep: opts + .get_by_key("sep") + .unwrap_or_else(|| ValueRef::str("---")) + .as_str(), + } + } else { + panic!( + "Invalid options arguments in yaml_stream(): expect config, got {}", + opts.type_str() + ) + } + } + None => YamlEncodeOptions::default(), + }; + + if let Some(value) = get_call_arg(args, kwargs, 0, Some("values")) { + self::yaml::encode_yaml_stream_to_manifests(ctx, &value, opts); + } else { + panic!("yaml_stream() missing 1 required positional argument: 'values'"); + } + ValueRef::undefined().into_raw(ctx) +} diff --git a/kclvm/runtime/src/manifests/tests.rs b/kclvm/runtime/src/manifests/tests.rs new file mode 100644 index 000000000..5c38c539d --- /dev/null +++ b/kclvm/runtime/src/manifests/tests.rs @@ -0,0 +1,121 @@ +use crate::*; + +#[test] +fn test_kclvm_manifests_yaml_stream() { + let cases = [ + ( + "a: 1\n", + ValueRef::list(Some(&[&ValueRef::dict(Some(&[("a", &ValueRef::int(1))]))])), + YamlEncodeOptions::default(), + ), + ( + "a: 1\nb: 2\n", + ValueRef::list(Some(&[&ValueRef::dict(Some(&[ + ("a", &ValueRef::int(1)), + ("b", &ValueRef::int(2)), + ]))])), + YamlEncodeOptions::default(), + ), + ( + "a:\n- 1\n- 2\n- 3\nb: s\n", + ValueRef::list(Some(&[&ValueRef::dict(Some(&[ + ("a", &ValueRef::list_int(&[1, 2, 3])), + ("b", &ValueRef::str("s")), + ]))])), + YamlEncodeOptions::default(), + ), + ( + "a: 1\n", + ValueRef::list(Some(&[&ValueRef::dict(Some(&[ + ("a", &ValueRef::int(1)), + ("_b", &ValueRef::none()), + ]))])), + YamlEncodeOptions { + ignore_private: true, + ..Default::default() + }, + ), + ( + "a: 1\nb: null\n", + ValueRef::list(Some(&[&ValueRef::dict(Some(&[ + ("a", &ValueRef::int(1)), + ("b", &ValueRef::none()), + ]))])), + YamlEncodeOptions::default(), + ), + ( + "a: 1\n", + ValueRef::list(Some(&[&ValueRef::dict(Some(&[ + ("a", &ValueRef::int(1)), + ("_b", &ValueRef::int(2)), + ("c", &ValueRef::none()), + ("d", &ValueRef::undefined()), + ]))])), + YamlEncodeOptions { + ignore_private: true, + ignore_none: true, + ..Default::default() + }, + ), + ]; + for (yaml_str, value, opts) in cases { + let mut ctx = Context::default(); + let opts = ValueRef::dict(Some(&[ + ("sort_keys", &ValueRef::bool(opts.sort_keys)), + ("ignore_private", &ValueRef::bool(opts.ignore_private)), + ("ignore_none", &ValueRef::bool(opts.ignore_none)), + ("sep", &ValueRef::str(&opts.sep)), + ])); + let mut args = ValueRef::list(None); + args.list_append(&value); + let mut kwargs = ValueRef::dict(None); + kwargs.dict_insert( + &mut ctx, + "opts", + &opts, + ConfigEntryOperationKind::Override, + None, + ); + kclvm_manifests_yaml_stream(&mut ctx, &args, &kwargs); + assert_eq!( + Some(yaml_str.to_string()), + ctx.buffer.custom_manifests_output + ); + } +} + +#[test] +fn test_kclvm_manifests_yaml_stream_invalid() { + let prev_hook = std::panic::take_hook(); + // Disable print panic info in stderr. + std::panic::set_hook(Box::new(|_| {})); + assert_panic( + "yaml_stream() missing 1 required positional argument: 'values'", + || { + let mut ctx = Context::new(); + let args = ValueRef::list(None).into_raw(&mut ctx); + let kwargs = ValueRef::dict(None).into_raw(&mut ctx); + kclvm_manifests_yaml_stream(ctx.into_raw(), args, kwargs); + }, + ); + assert_panic( + "Invalid options arguments in yaml_stream(): expect config, got str", + || { + let mut ctx = Context::new(); + let args = ValueRef::list(None).into_raw(&mut ctx); + let kwargs = ValueRef::dict(Some(&[("opts", &ValueRef::str("invalid_kwarg"))])) + .into_raw(&mut ctx); + kclvm_manifests_yaml_stream(ctx.into_raw(), args, kwargs); + }, + ); + assert_panic( + "Invalid options arguments in yaml_stream(): expect config, got NoneType", + || { + let mut ctx = Context::new(); + let args = ValueRef::list(None).into_raw(&mut ctx); + let kwargs = ValueRef::dict(Some(&[("opts", &ValueRef::none())])).into_raw(&mut ctx); + kclvm_manifests_yaml_stream(ctx.into_raw(), args, kwargs); + }, + ); + std::panic::set_hook(prev_hook); +} diff --git a/kclvm/runtime/src/manifests/yaml.rs b/kclvm/runtime/src/manifests/yaml.rs new file mode 100644 index 000000000..7565742b8 --- /dev/null +++ b/kclvm/runtime/src/manifests/yaml.rs @@ -0,0 +1,112 @@ +use crate::{Context, ValueRef, YamlEncodeOptions}; + +/// Encode the list value to the yaml stream format. +#[inline] +pub(crate) fn encode_yaml_stream_to_manifests( + ctx: &mut Context, + values: &ValueRef, + opts: YamlEncodeOptions, +) { + // Update custom plan manifests output. + ctx.buffer.custom_manifests_output = Some( + values + .as_list_ref() + .values + .iter() + .map(|v| v.to_yaml_string_with_options(&opts)) + .collect::>() + .join(&format!("\n{}\n", opts.sep)), + ); + // Update plan options. + ctx.plan_opts.disable_none = opts.ignore_none; + ctx.plan_opts.sort_keys = opts.sort_keys; + ctx.plan_opts.show_hidden = !opts.ignore_private; + ctx.plan_opts.sep = Some(opts.sep.clone()) +} + +#[cfg(test)] +mod test_manifests_yaml { + use crate::{manifests::yaml::encode_yaml_stream_to_manifests, *}; + + #[test] + fn test_encode_yaml_stream_to_manifests() { + let cases = [ + ( + "a: 1\n", + ValueRef::list(Some(&[&ValueRef::dict(Some(&[("a", &ValueRef::int(1))]))])), + YamlEncodeOptions::default(), + ), + ( + "a: 1\nb: 2\n", + ValueRef::list(Some(&[&ValueRef::dict(Some(&[ + ("a", &ValueRef::int(1)), + ("b", &ValueRef::int(2)), + ]))])), + YamlEncodeOptions::default(), + ), + ( + "a:\n- 1\n- 2\n- 3\nb: s\n", + ValueRef::list(Some(&[&ValueRef::dict(Some(&[ + ("a", &ValueRef::list_int(&[1, 2, 3])), + ("b", &ValueRef::str("s")), + ]))])), + YamlEncodeOptions::default(), + ), + ( + "a: 1\n", + ValueRef::list(Some(&[&ValueRef::dict(Some(&[ + ("a", &ValueRef::int(1)), + ("_b", &ValueRef::none()), + ]))])), + YamlEncodeOptions { + ignore_private: true, + ..Default::default() + }, + ), + ( + "a: 1\nb: null\n", + ValueRef::list(Some(&[&ValueRef::dict(Some(&[ + ("a", &ValueRef::int(1)), + ("b", &ValueRef::none()), + ]))])), + YamlEncodeOptions::default(), + ), + ( + "a: 1\n", + ValueRef::list(Some(&[&ValueRef::dict(Some(&[ + ("a", &ValueRef::int(1)), + ("_b", &ValueRef::int(2)), + ("c", &ValueRef::none()), + ("d", &ValueRef::undefined()), + ]))])), + YamlEncodeOptions { + ignore_private: true, + ignore_none: true, + ..Default::default() + }, + ), + ]; + let mut ctx = Context::default(); + for (yaml_str, value, opts) in cases { + encode_yaml_stream_to_manifests(&mut ctx, &value, opts); + assert_eq!( + Some(yaml_str.to_string()), + ctx.buffer.custom_manifests_output + ); + } + } + + #[test] + fn test_encode_yaml_stream_to_manifests_failure() { + let prev_hook = std::panic::take_hook(); + // Disable print panic info in stderr. + std::panic::set_hook(Box::new(|_| {})); + assert_panic("invalid list value", || { + let mut ctx = Context::default(); + let value = ValueRef::dict(Some(&[("a", &ValueRef::int(1))])); + let opts = YamlEncodeOptions::default(); + encode_yaml_stream_to_manifests(&mut ctx, &value, opts); + }); + std::panic::set_hook(prev_hook); + } +} diff --git a/kclvm/runtime/src/math/math.rs b/kclvm/runtime/src/math/math.rs deleted file mode 100644 index 93f667066..000000000 --- a/kclvm/runtime/src/math/math.rs +++ /dev/null @@ -1,360 +0,0 @@ -//! KCL math system module -//! -//! Copyright 2021 The KCL Authors. All rights reserved. - -extern crate num_integer; - -use crate::*; - -#[allow(non_camel_case_types)] -type kclvm_value_ref_t = ValueRef; - -// https://docs.python.org/3/library/math.html -// https://doc.rust-lang.org/std/primitive.f64.html -// https://github.com/RustPython/RustPython/blob/main/stdlib/src/math.rs - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_math_ceil( - _ctx: *mut kclvm_context_t, - args: *const kclvm_value_ref_t, - _kwargs: *const kclvm_value_ref_t, -) -> *const kclvm_value_ref_t { - let args = ptr_as_ref(args); - - if let Some(x) = args.arg_i_int(0, None) { - return kclvm_value_Int(x); - } - if let Some(x) = args.arg_i_float(0, None) { - return kclvm_value_Int(x.ceil() as i64); - } - - panic!("ceil() takes exactly one argument (0 given)"); -} - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_math_factorial( - _ctx: *mut kclvm_context_t, - args: *const kclvm_value_ref_t, - _kwargs: *const kclvm_value_ref_t, -) -> *const kclvm_value_ref_t { - fn factorial(num: i64) -> i64 { - if num >= 21 { - // overflow: 21! = 51090942171709440000 - // MaxInt64: 9223372036854775807 - panic!("factorial() result overflow"); - } - match num { - 0 => 1, - 1 => 1, - _ => factorial(num - 1) * num, - } - } - - let args = ptr_as_ref(args); - - if let Some(x) = args.arg_i_int(0, None) { - if x >= 0 { - return kclvm_value_Int(factorial(x)); - } - } - if let Some(x) = args.arg_i_float(0, None) { - if x >= 0.0 && (x as i64 as f64) == x { - return kclvm_value_Float(factorial(x as i64) as f64); - } - } - if args.args_len() > 0 { - panic!("factorial() only accepts integral values") - } - panic!("factorial() takes exactly one argument (0 given)"); -} - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_math_floor( - _ctx: *mut kclvm_context_t, - args: *const kclvm_value_ref_t, - _kwargs: *const kclvm_value_ref_t, -) -> *const kclvm_value_ref_t { - let args = ptr_as_ref(args); - - if let Some(x) = args.arg_i_int(0, None) { - return kclvm_value_Int(x); - } - if let Some(x) = args.arg_i_float(0, None) { - return kclvm_value_Float(x.floor()); - } - - panic!("floor() takes exactly one argument (0 given)"); -} - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_math_gcd( - _ctx: *mut kclvm_context_t, - args: *const kclvm_value_ref_t, - _kwargs: *const kclvm_value_ref_t, -) -> *const kclvm_value_ref_t { - let args = ptr_as_ref(args); - - if let Some(a) = args.arg_i_int(0, None) { - if let Some(b) = args.arg_i_int(1, None) { - return kclvm_value_Int(num_integer::gcd(a, b)); - } - } - - panic!( - "gcd() takes exactly two arguments ({} given)", - args.args_len() - ); -} - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_math_isfinite( - _ctx: *mut kclvm_context_t, - args: *const kclvm_value_ref_t, - _kwargs: *const kclvm_value_ref_t, -) -> *const kclvm_value_ref_t { - let args = ptr_as_ref(args); - - if let Some(_x) = args.arg_i_int(0, None) { - return kclvm_value_Bool(true as i8); - } - if let Some(x) = args.arg_i_float(0, None) { - return kclvm_value_Bool(x.is_finite() as i8); - } - - panic!("isfinite() takes exactly one argument (0 given)"); -} - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_math_isinf( - _ctx: *mut kclvm_context_t, - args: *const kclvm_value_ref_t, - _kwargs: *const kclvm_value_ref_t, -) -> *const kclvm_value_ref_t { - let args = ptr_as_ref(args); - - if let Some(_x) = args.arg_i_int(0, None) { - return kclvm_value_Bool(false as i8); - } - if let Some(x) = args.arg_i_float(0, None) { - return kclvm_value_Bool(x.is_infinite() as i8); - } - - panic!("isinf() takes exactly one argument (0 given)"); -} - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_math_isnan( - _ctx: *mut kclvm_context_t, - args: *const kclvm_value_ref_t, - _kwargs: *const kclvm_value_ref_t, -) -> *const kclvm_value_ref_t { - let args = ptr_as_ref(args); - - if let Some(_x) = args.arg_i_int(0, None) { - return kclvm_value_Bool(false as i8); - } - if let Some(x) = args.arg_i_float(0, None) { - return kclvm_value_Bool(x.is_nan() as i8); - } - - panic!("isnan() takes exactly one argument (0 given)"); -} - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_math_modf( - _ctx: *mut kclvm_context_t, - args: *const kclvm_value_ref_t, - _kwargs: *const kclvm_value_ref_t, -) -> *const kclvm_value_ref_t { - let args = ptr_as_ref(args); - - if let Some(x) = args.arg_i_int(0, None) { - let list = ValueRef::list_float(&[0.0, x as f64]); - return list.into_raw(); - } - if let Some(x) = args.arg_i_float(0, None) { - if !x.is_finite() { - if x.is_infinite() { - let list = ValueRef::list_float(&[0.0_f64.copysign(x), x]); - return list.into_raw(); - } else if x.is_nan() { - let list = ValueRef::list_float(&[x, x]); - return list.into_raw(); - } - } - let list = ValueRef::list_float(&[x.fract(), x.trunc()]); - return list.into_raw(); - } - - panic!("modf() takes exactly one argument (0 given)"); -} - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_math_exp( - _ctx: *mut kclvm_context_t, - args: *const kclvm_value_ref_t, - _kwargs: *const kclvm_value_ref_t, -) -> *const kclvm_value_ref_t { - let args = ptr_as_ref(args); - - if let Some(x) = args.arg_i_int(0, None) { - return kclvm_value_Float((x as f64).exp()); - } - if let Some(x) = args.arg_i_float(0, None) { - return kclvm_value_Float(x.exp()); - } - panic!("exp() takes exactly one argument (0 given)"); -} - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_math_expm1( - _ctx: *mut kclvm_context_t, - args: *const kclvm_value_ref_t, - _kwargs: *const kclvm_value_ref_t, -) -> *const kclvm_value_ref_t { - let args = ptr_as_ref(args); - - if let Some(x) = args.arg_i_int(0, None) { - return kclvm_value_Float((x as f64).exp_m1()); - } - if let Some(x) = args.arg_i_float(0, None) { - return kclvm_value_Float(x.exp_m1()); - } - panic!("expm1() takes exactly one argument (0 given)"); -} - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_math_log( - _ctx: *mut kclvm_context_t, - args: *const kclvm_value_ref_t, - _kwargs: *const kclvm_value_ref_t, -) -> *const kclvm_value_ref_t { - let args = ptr_as_ref(args); - - if let Some(x) = args.arg_i_int(0, None) { - if let Some(base) = args.arg_i_float(1, Some(std::f64::consts::E)) { - return kclvm_value_Int((x as f64).log(base) as i64); - } - } - if let Some(x) = args.arg_i_float(0, None) { - if let Some(base) = args.arg_i_float(1, Some(std::f64::consts::E)) { - return kclvm_value_Float(x.log(base)); - } - } - panic!("log() takes exactly one argument (0 given)"); -} - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_math_log1p( - _ctx: *mut kclvm_context_t, - args: *const kclvm_value_ref_t, - _kwargs: *const kclvm_value_ref_t, -) -> *const kclvm_value_ref_t { - let args = ptr_as_ref(args); - - if let Some(x) = args.arg_i_int(0, None) { - return kclvm_value_Float(((x + 1) as f64).ln_1p()); - } - if let Some(x) = args.arg_i_float(0, None) { - return kclvm_value_Float((x + 1.0).ln_1p()); - } - panic!("log1p() takes exactly one argument (0 given)"); -} - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_math_log2( - _ctx: *mut kclvm_context_t, - args: *const kclvm_value_ref_t, - _kwargs: *const kclvm_value_ref_t, -) -> *const kclvm_value_ref_t { - let args = ptr_as_ref(args); - - if let Some(x) = args.arg_i_int(0, None) { - return kclvm_value_Int((x as f64).log2() as i64); - } - if let Some(x) = args.arg_i_float(0, None) { - return kclvm_value_Float(x.log2()); - } - panic!("log2() takes exactly one argument (0 given)"); -} - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_math_log10( - _ctx: *mut kclvm_context_t, - args: *const kclvm_value_ref_t, - _kwargs: *const kclvm_value_ref_t, -) -> *const kclvm_value_ref_t { - let args = ptr_as_ref(args); - - if let Some(x) = args.arg_i_int(0, None) { - return kclvm_value_Float((x as f64).log10()); - } - if let Some(x) = args.arg_i_float(0, None) { - return kclvm_value_Float(x.log10()); - } - panic!("log10() takes exactly one argument (0 given)"); -} - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_math_pow( - _ctx: *mut kclvm_context_t, - args: *const kclvm_value_ref_t, - _kwargs: *const kclvm_value_ref_t, -) -> *const kclvm_value_ref_t { - let args = ptr_as_ref(args); - - if let Some(x) = args.arg_i_int(0, None) { - if let Some(n) = args.arg_i_int(1, None) { - if n < 0 { - return kclvm_value_Float((x as f64).powf(n as f64)); - } else { - return kclvm_value_Int(x.pow(n as u32)); - } - } - if let Some(n) = args.arg_i_float(1, None) { - return kclvm_value_Float((x as f64).powf(n)); - } - } - if let Some(x) = args.arg_i_float(0, None) { - if let Some(n) = args.arg_i_int(1, None) { - return kclvm_value_Float(x.powi(n as i32)); - } - if let Some(n) = args.arg_i_float(1, None) { - return kclvm_value_Float(x.powf(n)); - } - } - panic!("pow() takes exactly one argument (0 given)"); -} - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_math_sqrt( - _ctx: *mut kclvm_context_t, - args: *const kclvm_value_ref_t, - _kwargs: *const kclvm_value_ref_t, -) -> *const kclvm_value_ref_t { - let args = ptr_as_ref(args); - - if let Some(x) = args.arg_i_int(0, None) { - return kclvm_value_Float((x as f64).sqrt()); - } - if let Some(x) = args.arg_i_float(0, None) { - return kclvm_value_Float(x.sqrt()); - } - panic!("sqrt() takes exactly one argument (0 given)"); -} diff --git a/kclvm/runtime/src/math/mod.rs b/kclvm/runtime/src/math/mod.rs index fb00f12d7..ec3913704 100644 --- a/kclvm/runtime/src/math/mod.rs +++ b/kclvm/runtime/src/math/mod.rs @@ -1,4 +1,394 @@ -// Copyright 2021 The KCL Authors. All rights reserved. +//! Copyright The KCL Authors. All rights reserved. -pub mod math; -pub use self::math::*; +extern crate num_integer; + +use crate::*; + +// https://docs.python.org/3/library/math.html +// https://doc.rust-lang.org/std/primitive.f64.html +// https://github.com/RustPython/RustPython/blob/main/stdlib/src/math.rs + +#[no_mangle] +#[runtime_fn] +pub extern "C" fn kclvm_math_ceil( + ctx: *mut kclvm_context_t, + args: *const kclvm_value_ref_t, + kwargs: *const kclvm_value_ref_t, +) -> *const kclvm_value_ref_t { + let args = ptr_as_ref(args); + let kwargs = ptr_as_ref(kwargs); + + if let Some(x) = args.arg_i_int(0, None).or(kwargs.kwarg_int("x", None)) { + return kclvm_value_Int(ctx, x); + } + if let Some(x) = args.arg_i_float(0, None).or(kwargs.kwarg_float("x", None)) { + return kclvm_value_Int(ctx, x.ceil() as i64); + } + + panic!("ceil() takes exactly one argument (0 given)"); +} + +#[no_mangle] +#[runtime_fn] +pub extern "C" fn kclvm_math_factorial( + ctx: *mut kclvm_context_t, + args: *const kclvm_value_ref_t, + kwargs: *const kclvm_value_ref_t, +) -> *const kclvm_value_ref_t { + fn factorial(num: i64) -> i64 { + if num >= 21 { + // overflow: 21! = 51090942171709440000 + // MaxInt64: 9223372036854775807 + panic!("factorial() result overflow"); + } + match num { + 0 => 1, + 1 => 1, + _ => factorial(num - 1) * num, + } + } + + let args = ptr_as_ref(args); + let kwargs = ptr_as_ref(kwargs); + + if let Some(x) = args.arg_i_int(0, None).or(kwargs.kwarg_int("x", None)) { + if x >= 0 { + return kclvm_value_Int(ctx, factorial(x)); + } + } + if let Some(x) = args.arg_i_float(0, None).or(kwargs.kwarg_float("x", None)) { + if x >= 0.0 && (x as i64 as f64) == x { + return kclvm_value_Float(ctx, factorial(x as i64) as f64); + } + } + + if args.args_len() > 0 { + panic!("factorial() only accepts integral values") + } + panic!("factorial() takes exactly one argument (0 given)"); +} + +#[no_mangle] +#[runtime_fn] +pub extern "C" fn kclvm_math_floor( + ctx: *mut kclvm_context_t, + args: *const kclvm_value_ref_t, + kwargs: *const kclvm_value_ref_t, +) -> *const kclvm_value_ref_t { + let args = ptr_as_ref(args); + let kwargs = ptr_as_ref(kwargs); + + if let Some(x) = args.arg_i_int(0, None).or(kwargs.kwarg_int("x", None)) { + return kclvm_value_Int(ctx, x); + } + if let Some(x) = args.arg_i_float(0, None).or(kwargs.kwarg_float("x", None)) { + return kclvm_value_Float(ctx, x.floor()); + } + + panic!("floor() takes exactly one argument (0 given)"); +} + +#[no_mangle] +#[runtime_fn] +pub extern "C" fn kclvm_math_gcd( + ctx: *mut kclvm_context_t, + args: *const kclvm_value_ref_t, + kwargs: *const kclvm_value_ref_t, +) -> *const kclvm_value_ref_t { + let args = ptr_as_ref(args); + let kwargs = ptr_as_ref(kwargs); + + if let Some(a) = args.arg_i_int(0, None).or(kwargs.kwarg_int("a", None)) { + if let Some(b) = args.arg_i_int(1, None).or(kwargs.kwarg_int("b", None)) { + return kclvm_value_Int(ctx, num_integer::gcd(a, b)); + } + } + + panic!( + "gcd() takes exactly two arguments ({} given)", + args.args_len() + ); +} + +#[no_mangle] +#[runtime_fn] +pub extern "C" fn kclvm_math_isfinite( + ctx: *mut kclvm_context_t, + args: *const kclvm_value_ref_t, + kwargs: *const kclvm_value_ref_t, +) -> *const kclvm_value_ref_t { + let args = ptr_as_ref(args); + let kwargs = ptr_as_ref(kwargs); + + if args + .arg_i_int(0, None) + .or(kwargs.kwarg_int("x", None)) + .is_some() + { + return kclvm_value_Bool(ctx, true as i8); + } + if let Some(x) = args.arg_i_float(0, None).or(kwargs.kwarg_float("x", None)) { + return kclvm_value_Bool(ctx, x.is_finite() as i8); + } + + panic!("isfinite() takes exactly one argument (0 given)"); +} + +#[no_mangle] +#[runtime_fn] +pub extern "C" fn kclvm_math_isinf( + ctx: *mut kclvm_context_t, + args: *const kclvm_value_ref_t, + kwargs: *const kclvm_value_ref_t, +) -> *const kclvm_value_ref_t { + let args = ptr_as_ref(args); + let kwargs = ptr_as_ref(kwargs); + + if args + .arg_i_int(0, None) + .or(kwargs.kwarg_int("x", None)) + .is_some() + { + return kclvm_value_Bool(ctx, false as i8); + } + if let Some(x) = args.arg_i_float(0, None).or(kwargs.kwarg_float("x", None)) { + return kclvm_value_Bool(ctx, x.is_infinite() as i8); + } + if args.arg_i_bool(0, None).is_some() { + return kclvm_value_Bool(ctx, false as i8); + } + + panic!("isinf() takes exactly one argument (0 given)"); +} + +#[no_mangle] +#[runtime_fn] +pub extern "C" fn kclvm_math_isnan( + ctx: *mut kclvm_context_t, + args: *const kclvm_value_ref_t, + kwargs: *const kclvm_value_ref_t, +) -> *const kclvm_value_ref_t { + let args = ptr_as_ref(args); + let kwargs = ptr_as_ref(kwargs); + + if args + .arg_i_int(0, None) + .or(kwargs.kwarg_int("x", None)) + .is_some() + { + return kclvm_value_Bool(ctx, false as i8); + } + if let Some(x) = args.arg_i_float(0, None).or(kwargs.kwarg_float("x", None)) { + return kclvm_value_Bool(ctx, x.is_nan() as i8); + } + + panic!("isnan() takes exactly one argument (0 given)"); +} + +#[no_mangle] +#[runtime_fn] +pub extern "C" fn kclvm_math_modf( + ctx: *mut kclvm_context_t, + args: *const kclvm_value_ref_t, + kwargs: *const kclvm_value_ref_t, +) -> *const kclvm_value_ref_t { + let args = ptr_as_ref(args); + let ctx = mut_ptr_as_ref(ctx); + let kwargs = ptr_as_ref(kwargs); + + if let Some(x) = args.arg_i_int(0, None).or(kwargs.kwarg_int("x", None)) { + let list = ValueRef::list_float(&[0.0, x as f64]); + return list.into_raw(ctx); + } + if let Some(x) = args.arg_i_float(0, None).or(kwargs.kwarg_float("x", None)) { + if !x.is_finite() { + if x.is_infinite() { + let list = ValueRef::list_float(&[0.0_f64.copysign(x), x]); + return list.into_raw(ctx); + } else if x.is_nan() { + let list = ValueRef::list_float(&[x, x]); + return list.into_raw(ctx); + } + } + let list = ValueRef::list_float(&[x.fract(), x.trunc()]); + return list.into_raw(ctx); + } + + panic!("modf() takes exactly one argument (0 given)"); +} + +#[no_mangle] +#[runtime_fn] +pub extern "C" fn kclvm_math_exp( + ctx: *mut kclvm_context_t, + args: *const kclvm_value_ref_t, + kwargs: *const kclvm_value_ref_t, +) -> *const kclvm_value_ref_t { + let args = ptr_as_ref(args); + let kwargs = ptr_as_ref(kwargs); + + if let Some(x) = args.arg_i_int(0, None).or(kwargs.kwarg_int("x", None)) { + return kclvm_value_Float(ctx, (x as f64).exp()); + } + if let Some(x) = args.arg_i_float(0, None).or(kwargs.kwarg_float("x", None)) { + return kclvm_value_Float(ctx, x.exp()); + } + panic!("exp() takes exactly one argument (0 given)"); +} + +#[no_mangle] +#[runtime_fn] +pub extern "C" fn kclvm_math_expm1( + ctx: *mut kclvm_context_t, + args: *const kclvm_value_ref_t, + kwargs: *const kclvm_value_ref_t, +) -> *const kclvm_value_ref_t { + let args = ptr_as_ref(args); + let kwargs = ptr_as_ref(kwargs); + + if let Some(x) = args.arg_i_int(0, None).or(kwargs.kwarg_int("x", None)) { + return kclvm_value_Float(ctx, (x as f64).exp_m1()); + } + if let Some(x) = args.arg_i_float(0, None).or(kwargs.kwarg_float("x", None)) { + return kclvm_value_Float(ctx, x.exp_m1()); + } + panic!("expm1() takes exactly one argument (0 given)"); +} + +#[no_mangle] +#[runtime_fn] +pub extern "C" fn kclvm_math_log( + ctx: *mut kclvm_context_t, + args: *const kclvm_value_ref_t, + kwargs: *const kclvm_value_ref_t, +) -> *const kclvm_value_ref_t { + let args = ptr_as_ref(args); + let kwargs = ptr_as_ref(kwargs); + + if let Some(x) = args.arg_i_int(0, None).or(kwargs.kwarg_int("x", None)) { + if let Some(base) = args + .arg_i_float(1, Some(std::f64::consts::E)) + .or_else(|| kwargs.kwarg_float("e", Some(std::f64::consts::E))) + { + return kclvm_value_Int(ctx, (x as f64).log(base) as i64); + } + } + if let Some(x) = args.arg_i_float(0, None).or(kwargs.kwarg_float("x", None)) { + if let Some(base) = args + .arg_i_float(1, Some(std::f64::consts::E)) + .or_else(|| kwargs.kwarg_float("e", Some(std::f64::consts::E))) + { + return kclvm_value_Float(ctx, x.log(base)); + } + } + panic!("log() takes exactly one argument (0 given)"); +} + +#[no_mangle] +#[runtime_fn] +pub extern "C" fn kclvm_math_log1p( + ctx: *mut kclvm_context_t, + args: *const kclvm_value_ref_t, + kwargs: *const kclvm_value_ref_t, +) -> *const kclvm_value_ref_t { + let args = ptr_as_ref(args); + let kwargs = ptr_as_ref(kwargs); + + if let Some(x) = args.arg_i_int(0, None).or(kwargs.kwarg_int("x", None)) { + return kclvm_value_Float(ctx, ((x + 1) as f64).ln_1p()); + } + if let Some(x) = args.arg_i_float(0, None).or(kwargs.kwarg_float("x", None)) { + return kclvm_value_Float(ctx, (x + 1.0).ln_1p()); + } + panic!("log1p() takes exactly one argument (0 given)"); +} + +#[no_mangle] +#[runtime_fn] +pub extern "C" fn kclvm_math_log2( + ctx: *mut kclvm_context_t, + args: *const kclvm_value_ref_t, + kwargs: *const kclvm_value_ref_t, +) -> *const kclvm_value_ref_t { + let args = ptr_as_ref(args); + let kwargs = ptr_as_ref(kwargs); + + if let Some(x) = args.arg_i_int(0, None).or(kwargs.kwarg_int("x", None)) { + return kclvm_value_Int(ctx, (x as f64).log2() as i64); + } + if let Some(x) = args.arg_i_float(0, None).or(kwargs.kwarg_float("x", None)) { + return kclvm_value_Float(ctx, x.log2()); + } + panic!("log2() takes exactly one argument (0 given)"); +} + +#[no_mangle] +#[runtime_fn] +pub extern "C" fn kclvm_math_log10( + ctx: *mut kclvm_context_t, + args: *const kclvm_value_ref_t, + kwargs: *const kclvm_value_ref_t, +) -> *const kclvm_value_ref_t { + let args = ptr_as_ref(args); + let kwargs = ptr_as_ref(kwargs); + + if let Some(x) = args.arg_i_int(0, None).or(kwargs.kwarg_int("x", None)) { + return kclvm_value_Float(ctx, (x as f64).log10()); + } + if let Some(x) = args.arg_i_float(0, None).or(kwargs.kwarg_float("x", None)) { + return kclvm_value_Float(ctx, x.log10()); + } + panic!("log10() takes exactly one argument (0 given)"); +} + +#[no_mangle] +#[runtime_fn] +pub extern "C" fn kclvm_math_pow( + ctx: *mut kclvm_context_t, + args: *const kclvm_value_ref_t, + kwargs: *const kclvm_value_ref_t, +) -> *const kclvm_value_ref_t { + let args = ptr_as_ref(args); + let kwargs = ptr_as_ref(kwargs); + + if let Some(x) = args.arg_i_int(0, None).or(kwargs.kwarg_int("x", None)) { + if let Some(n) = args.arg_i_int(1, None).or(kwargs.kwarg_int("n", None)) { + if n < 0 { + return kclvm_value_Float(ctx, (x as f64).powf(n as f64)); + } else { + return kclvm_value_Int(ctx, x.pow(n as u32)); + } + } + if let Some(n) = args.arg_i_float(1, None).or(kwargs.kwarg_float("n", None)) { + return kclvm_value_Float(ctx, (x as f64).powf(n)); + } + } + if let Some(x) = args.arg_i_float(0, None).or(kwargs.kwarg_float("x", None)) { + if let Some(n) = args.arg_i_int(1, None).or(kwargs.kwarg_int("n", None)) { + return kclvm_value_Float(ctx, x.powi(n as i32)); + } + if let Some(n) = args.arg_i_float(1, None).or(kwargs.kwarg_float("n", None)) { + return kclvm_value_Float(ctx, x.powf(n)); + } + } + panic!("pow() takes exactly one argument (0 given)"); +} + +#[no_mangle] +#[runtime_fn] +pub extern "C" fn kclvm_math_sqrt( + ctx: *mut kclvm_context_t, + args: *const kclvm_value_ref_t, + kwargs: *const kclvm_value_ref_t, +) -> *const kclvm_value_ref_t { + let args = ptr_as_ref(args); + let kwargs = ptr_as_ref(kwargs); + + if let Some(x) = args.arg_i_int(0, None).or(kwargs.kwarg_int("x", None)) { + return kclvm_value_Float(ctx, (x as f64).sqrt()); + } + if let Some(x) = args.arg_i_float(0, None).or(kwargs.kwarg_float("x", None)) { + return kclvm_value_Float(ctx, x.sqrt()); + } + panic!("sqrt() takes exactly one argument (0 given)"); +} diff --git a/kclvm/runtime/src/net/mod.rs b/kclvm/runtime/src/net/mod.rs index 84dc29eb9..5446d1bab 100644 --- a/kclvm/runtime/src/net/mod.rs +++ b/kclvm/runtime/src/net/mod.rs @@ -1,4 +1,460 @@ -// Copyright 2021 The KCL Authors. All rights reserved. +//! Copyright The KCL Authors. All rights reserved. -pub mod net; -pub use self::net::*; +use std::net::Ipv4Addr; +use std::net::Ipv6Addr; +use std::str::FromStr; + +use crate::*; + +// split_host_port(ip_end_point: str) -> List[str] + +#[no_mangle] +#[runtime_fn] +pub extern "C" fn kclvm_net_split_host_port( + ctx: *mut kclvm_context_t, + args: *const kclvm_value_ref_t, + kwargs: *const kclvm_value_ref_t, +) -> *const kclvm_value_ref_t { + let args = ptr_as_ref(args); + let kwargs = ptr_as_ref(kwargs); + let ctx = mut_ptr_as_ref(ctx); + + if let Some(string) = get_call_arg_str(args, kwargs, 0, Some("ip_end_point")) { + let mut list = ValueRef::list(None); + for s in string.split(':') { + list.list_append(&ValueRef::str(s)); + } + return list.into_raw(ctx); + } + + panic!("split_host_port() missing 1 required positional argument: 'ip_end_point'"); +} + +// join_host_port(host, port) -> str + +#[no_mangle] +#[runtime_fn] +pub extern "C" fn kclvm_net_join_host_port( + ctx: *mut kclvm_context_t, + args: *const kclvm_value_ref_t, + kwargs: *const kclvm_value_ref_t, +) -> *const kclvm_value_ref_t { + let args = ptr_as_ref(args); + let kwargs = ptr_as_ref(kwargs); + let ctx = mut_ptr_as_ref(ctx); + + if let Some(host) = get_call_arg_str(args, kwargs, 0, Some("host")) { + if let Some(port) = args.arg_i_int(1, None).or(kwargs.kwarg_int("port", None)) { + let s = format!("{host}:{port}"); + return ValueRef::str(s.as_ref()).into_raw(ctx); + } + if let Some(port) = args.arg_i_str(1, None).or(kwargs.kwarg_str("port", None)) { + let s = format!("{host}:{port}"); + return ValueRef::str(s.as_ref()).into_raw(ctx); + } + } + panic!("join_host_port() missing 2 required positional arguments: 'host' and 'port'"); +} + +// fqdn(name: str = '') -> str + +#[cfg(not(target_arch = "wasm32"))] +#[no_mangle] +#[runtime_fn] +pub extern "C" fn kclvm_net_fqdn( + ctx: *mut kclvm_context_t, + args: *const kclvm_value_ref_t, + kwargs: *const kclvm_value_ref_t, +) -> *const kclvm_value_ref_t { + use std::net::ToSocketAddrs; + let ctx = mut_ptr_as_ref(ctx); + let args = ptr_as_ref(args); + let kwargs = ptr_as_ref(kwargs); + let name = get_call_arg_str(args, kwargs, 0, Some("name")).unwrap_or_default(); + let hostname = if name.is_empty() { + match hostname::get() { + Ok(name) => name.to_string_lossy().into_owned(), + Err(_) => return ValueRef::str("").into_raw(ctx), + } + } else { + name + }; + match (hostname.as_str(), 0).to_socket_addrs() { + Ok(mut addrs) => { + if let Some(addr) = addrs.next() { + match dns_lookup::lookup_addr(&addr.ip()) { + Ok(fqdn) => ValueRef::str(&fqdn), + Err(_) => ValueRef::str(&hostname), + } + } else { + ValueRef::str(&hostname) + } + } + Err(_) => ValueRef::str(&hostname), + } + .into_raw(ctx) +} + +#[cfg(target_arch = "wasm32")] +#[no_mangle] +#[runtime_fn] +pub extern "C" fn kclvm_net_fqdn( + _ctx: *mut kclvm_context_t, + _args: *const kclvm_value_ref_t, + _kwargs: *const kclvm_value_ref_t, +) -> *const kclvm_value_ref_t { + panic!("fqdn() do not support the WASM target"); +} + +// parse_IP(ip) -> str + +#[no_mangle] +#[runtime_fn] +pub extern "C" fn kclvm_net_parse_IP( + ctx: *mut kclvm_context_t, + args: *const kclvm_value_ref_t, + kwargs: *const kclvm_value_ref_t, +) -> *const kclvm_value_ref_t { + kclvm_net_IP_string(ctx, args, kwargs) +} + +// to_IP4(ip) -> str + +#[no_mangle] +#[runtime_fn] +pub extern "C" fn kclvm_net_to_IP4( + ctx: *mut kclvm_context_t, + args: *const kclvm_value_ref_t, + kwargs: *const kclvm_value_ref_t, +) -> *const kclvm_value_ref_t { + kclvm_net_IP_string(ctx, args, kwargs) +} + +// to_IP16(ip) -> int + +#[no_mangle] +#[runtime_fn] +pub extern "C" fn kclvm_net_to_IP16( + ctx: *mut kclvm_context_t, + args: *const kclvm_value_ref_t, + kwargs: *const kclvm_value_ref_t, +) -> *const kclvm_value_ref_t { + kclvm_net_IP_string(ctx, args, kwargs) +} + +// IP_string(ip: str) -> str + +#[no_mangle] +#[runtime_fn] +pub extern "C" fn kclvm_net_IP_string( + ctx: *mut kclvm_context_t, + args: *const kclvm_value_ref_t, + kwargs: *const kclvm_value_ref_t, +) -> *const kclvm_value_ref_t { + let args = ptr_as_ref(args); + let kwargs = ptr_as_ref(kwargs); + let ctx = mut_ptr_as_ref(ctx); + if let Some(ip) = get_call_arg_str(args, kwargs, 0, Some("ip")) { + if let Ok(addr) = Ipv4Addr::from_str(ip.as_ref()) { + let s = format!("{addr}"); + return ValueRef::str(s.as_ref()).into_raw(ctx); + } + if let Ok(addr) = Ipv6Addr::from_str(ip.as_ref()) { + let s = format!("{addr}"); + return ValueRef::str(s.as_ref()).into_raw(ctx); + } + + return ValueRef::str("").into_raw(ctx); + } + + panic!("IP_string() missing 1 required positional argument: 'ip'"); +} + +// is_IPv4(ip: str) -> bool + +#[no_mangle] +#[runtime_fn] +pub extern "C" fn kclvm_net_is_IPv4( + ctx: *mut kclvm_context_t, + args: *const kclvm_value_ref_t, + kwargs: *const kclvm_value_ref_t, +) -> *const kclvm_value_ref_t { + let args = ptr_as_ref(args); + let kwargs = ptr_as_ref(kwargs); + + if let Some(ip) = get_call_arg_str(args, kwargs, 0, Some("ip")) { + if let Ok(_addr) = Ipv4Addr::from_str(ip.as_ref()) { + return kclvm_value_True(ctx); + } + if let Ok(_addr) = Ipv6Addr::from_str(ip.as_ref()) { + return kclvm_value_False(ctx); + } + + return kclvm_value_False(ctx); + } + + panic!("is_IPv4() missing 1 required positional argument: 'ip'"); +} + +// is_IP(ip: str) -> bool + +#[no_mangle] +#[runtime_fn] +pub extern "C" fn kclvm_net_is_IP( + ctx: *mut kclvm_context_t, + args: *const kclvm_value_ref_t, + kwargs: *const kclvm_value_ref_t, +) -> *const kclvm_value_ref_t { + let args = ptr_as_ref(args); + let kwargs = ptr_as_ref(kwargs); + + if let Some(ip) = get_call_arg_str(args, kwargs, 0, Some("ip")) { + if Ipv4Addr::from_str(ip.as_ref()).is_ok() || Ipv6Addr::from_str(ip.as_ref()).is_ok() { + kclvm_value_True(ctx) + } else { + kclvm_value_False(ctx) + } + } else { + panic!("is_IP() missing 1 required positional argument: 'ip'"); + } +} + +// is_loopback_IP(ip: str) -> bool + +#[no_mangle] +#[runtime_fn] +pub extern "C" fn kclvm_net_is_loopback_IP( + ctx: *mut kclvm_context_t, + args: *const kclvm_value_ref_t, + kwargs: *const kclvm_value_ref_t, +) -> *const kclvm_value_ref_t { + let args = ptr_as_ref(args); + let kwargs = ptr_as_ref(kwargs); + + if let Some(ip) = get_call_arg_str(args, kwargs, 0, Some("ip")) { + if let Ok(addr) = Ipv4Addr::from_str(ip.as_ref()) { + let x = addr.is_loopback(); + return kclvm_value_Bool(ctx, x as i8); + } + if let Ok(addr) = Ipv6Addr::from_str(ip.as_ref()) { + let x = addr.is_loopback(); + return kclvm_value_Bool(ctx, x as i8); + } + + return kclvm_value_False(ctx); + } + + panic!("is_loopback_IP() missing 1 required positional argument: 'ip'"); +} + +// is_multicast_IP(ip: str) -> bool + +#[no_mangle] +#[runtime_fn] +pub extern "C" fn kclvm_net_is_multicast_IP( + ctx: *mut kclvm_context_t, + args: *const kclvm_value_ref_t, + kwargs: *const kclvm_value_ref_t, +) -> *const kclvm_value_ref_t { + let args = ptr_as_ref(args); + let kwargs = ptr_as_ref(kwargs); + + if let Some(ip) = get_call_arg_str(args, kwargs, 0, Some("ip")) { + if let Ok(addr) = Ipv4Addr::from_str(ip.as_ref()) { + let x = addr.is_multicast(); + return kclvm_value_Bool(ctx, x as i8); + } + if let Ok(addr) = Ipv6Addr::from_str(ip.as_ref()) { + let x = addr.is_multicast(); + return kclvm_value_Bool(ctx, x as i8); + } + + return kclvm_value_False(ctx); + } + + panic!("kclvm_net_is_multicast_IP() missing 1 required positional argument: 'ip'"); +} + +// is_interface_local_multicast_IP(ip: str) -> bool + +#[no_mangle] +#[runtime_fn] +pub extern "C" fn kclvm_net_is_interface_local_multicast_IP( + ctx: *mut kclvm_context_t, + args: *const kclvm_value_ref_t, + kwargs: *const kclvm_value_ref_t, +) -> *const kclvm_value_ref_t { + let args = ptr_as_ref(args); + let kwargs = ptr_as_ref(kwargs); + if let Some(ip) = get_call_arg_str(args, kwargs, 0, Some("ip")) { + if let Ok(addr) = Ipv4Addr::from_str(ip.as_ref()) { + // For IPv4, interface-local multicast addresses are in the range 224.0.0.0/24 + let is_interface_local = + addr.octets()[0] == 224 && addr.octets()[1] == 0 && addr.octets()[2] == 0; + let x = is_interface_local && addr.is_multicast(); + return kclvm_value_Bool(ctx, x as i8); + } + if let Ok(addr) = Ipv6Addr::from_str(ip.as_ref()) { + // For IPv6, interface-local multicast addresses start with ff01::/16 + let is_interface_local = addr.segments()[0] == 0xff01; + let x = is_interface_local && addr.is_multicast(); + return kclvm_value_Bool(ctx, x as i8); + } + return kclvm_value_Bool(ctx, 0); // False for invalid IP addresses + } + panic!("is_interface_local_multicast_IP() missing 1 required positional argument: 'ip'"); +} + +// is_link_local_multicast_IP(ip: str) -> bool + +#[no_mangle] +#[runtime_fn] +pub extern "C" fn kclvm_net_is_link_local_multicast_IP( + ctx: *mut kclvm_context_t, + args: *const kclvm_value_ref_t, + kwargs: *const kclvm_value_ref_t, +) -> *const kclvm_value_ref_t { + let args = ptr_as_ref(args); + let kwargs = ptr_as_ref(kwargs); + + if let Some(ip) = get_call_arg_str(args, kwargs, 0, Some("ip")) { + if let Ok(addr) = Ipv4Addr::from_str(ip.as_ref()) { + // For IPv4, link-local multicast addresses are in the range 224.0.0.0/24 + let is_link_local_multicast = + addr.octets()[0] == 224 && addr.octets()[1] == 0 && addr.octets()[2] == 0; + let x = is_link_local_multicast && addr.is_multicast(); + return kclvm_value_Bool(ctx, x as i8); + } + if let Ok(addr) = Ipv6Addr::from_str(ip.as_ref()) { + // For IPv6, link-local multicast addresses start with ff02::/16 + let is_link_local_multicast = addr.segments()[0] == 0xff02; + let x = is_link_local_multicast && addr.is_multicast(); + return kclvm_value_Bool(ctx, x as i8); + } + return kclvm_value_Bool(ctx, 0); // False for invalid IP addresses + } + + panic!("is_link_local_multicast_IP() missing 1 required positional argument: 'ip'"); +} + +// is_link_local_unicast_IP(ip: str) -> bool + +#[no_mangle] +#[runtime_fn] +pub extern "C" fn kclvm_net_is_link_local_unicast_IP( + ctx: *mut kclvm_context_t, + args: *const kclvm_value_ref_t, + kwargs: *const kclvm_value_ref_t, +) -> *const kclvm_value_ref_t { + let args = ptr_as_ref(args); + let kwargs = ptr_as_ref(kwargs); + + if let Some(ip) = get_call_arg_str(args, kwargs, 0, Some("ip")) { + if let Ok(addr) = Ipv4Addr::from_str(ip.as_ref()) { + let x = addr.is_link_local() && (!addr.is_multicast()); + return kclvm_value_Bool(ctx, x as i8); + } + if let Ok(_addr) = Ipv6Addr::from_str(ip.as_ref()) { + let x = Ipv6Addr_is_unicast_link_local(&_addr) && (!_addr.is_multicast()); + return kclvm_value_Bool(ctx, x as i8); + } + return kclvm_value_False(ctx); + } + + panic!("is_link_local_unicast_IP() missing 1 required positional argument: 'ip'"); +} + +#[allow(non_camel_case_types, non_snake_case)] +pub const fn Ipv6Addr_is_unicast_link_local(_self: &Ipv6Addr) -> bool { + (_self.segments()[0] & 0xffc0) == 0xfe80 +} + +// is_global_unicast_IP(ip: str) -> bool + +#[no_mangle] +#[runtime_fn] +pub extern "C" fn kclvm_net_is_global_unicast_IP( + ctx: *mut kclvm_context_t, + args: *const kclvm_value_ref_t, + kwargs: *const kclvm_value_ref_t, +) -> *const kclvm_value_ref_t { + let args = ptr_as_ref(args); + let kwargs = ptr_as_ref(kwargs); + + if let Some(ip) = get_call_arg_str(args, kwargs, 0, Some("ip")) { + if let Ok(addr) = Ipv4Addr::from_str(ip.as_ref()) { + let x = Ipv4Addr_is_global(&addr) && (!addr.is_multicast()); + return kclvm_value_Bool(ctx, x as i8); + } + if let Ok(addr) = Ipv6Addr::from_str(ip.as_ref()) { + return kclvm_value_Bool(ctx, addr.is_multicast() as i8); + } + + return kclvm_value_False(ctx); + } + + panic!("is_global_unicast_IP() missing 1 required positional argument: 'ip'"); +} + +#[allow(non_camel_case_types, non_snake_case)] +fn Ipv4Addr_is_global(_self: &std::net::Ipv4Addr) -> bool { + // check if this address is 192.0.0.9 or 192.0.0.10. These addresses are the only two + // globally routable addresses in the 192.0.0.0/24 range. + if u32::from_be_bytes(_self.octets()) == 0xc0000009 + || u32::from_be_bytes(_self.octets()) == 0xc000000a + { + return true; + } + !_self.is_private() + && !_self.is_loopback() + && !_self.is_link_local() + && !_self.is_broadcast() + && !_self.is_documentation() + && !Ipv4Addr_is_shared(_self) // _self.is_shared() + && !Ipv4Addr_is_ietf_protocol_assignment(_self) // _self.is_ietf_protocol_assignment() + && !Ipv4Addr_is_reserved(_self) // _self.is_reserved() + && !Ipv4Addr_is_benchmarking(_self) // _self.is_benchmarking() + // Make sure the address is not in 0.0.0.0/8 + && _self.octets()[0] != 0 +} + +#[allow(non_camel_case_types, non_snake_case)] +const fn Ipv4Addr_is_shared(_self: &std::net::Ipv4Addr) -> bool { + _self.octets()[0] == 100 && (_self.octets()[1] & 0b1100_0000 == 0b0100_0000) +} +#[allow(non_camel_case_types, non_snake_case)] +const fn Ipv4Addr_is_ietf_protocol_assignment(_self: &std::net::Ipv4Addr) -> bool { + _self.octets()[0] == 192 && _self.octets()[1] == 0 && _self.octets()[2] == 0 +} +#[allow(non_camel_case_types, non_snake_case)] +const fn Ipv4Addr_is_reserved(_self: &std::net::Ipv4Addr) -> bool { + _self.octets()[0] & 240 == 240 && !_self.is_broadcast() +} +#[allow(non_camel_case_types, non_snake_case)] +const fn Ipv4Addr_is_benchmarking(_self: &std::net::Ipv4Addr) -> bool { + _self.octets()[0] == 198 && (_self.octets()[1] & 0xfe) == 18 +} + +// is_unspecified_IP(ip: str) -> bool + +#[no_mangle] +#[runtime_fn] +pub extern "C" fn kclvm_net_is_unspecified_IP( + ctx: *mut kclvm_context_t, + args: *const kclvm_value_ref_t, + kwargs: *const kclvm_value_ref_t, +) -> *const kclvm_value_ref_t { + let args = ptr_as_ref(args); + let kwargs = ptr_as_ref(kwargs); + + if let Some(ip) = get_call_arg_str(args, kwargs, 0, Some("ip")) { + if let Ok(addr) = Ipv4Addr::from_str(ip.as_ref()) { + return kclvm_value_Bool(ctx, addr.is_unspecified() as i8); + } + if let Ok(addr) = Ipv6Addr::from_str(ip.as_ref()) { + return kclvm_value_Bool(ctx, addr.is_unspecified() as i8); + } + return kclvm_value_False(ctx); + } + panic!("is_unspecified_IP() missing 1 required positional argument: 'ip'"); +} diff --git a/kclvm/runtime/src/net/net.rs b/kclvm/runtime/src/net/net.rs deleted file mode 100644 index 6c6da329e..000000000 --- a/kclvm/runtime/src/net/net.rs +++ /dev/null @@ -1,418 +0,0 @@ -//! KCL net system module -//! -//! Copyright 2021 The KCL Authors. All rights reserved. - -use std::net::Ipv4Addr; -use std::net::Ipv6Addr; -use std::str::FromStr; - -use crate::*; - -#[allow(non_camel_case_types)] -type kclvm_value_ref_t = ValueRef; - -// split_host_port(ip_end_point: str) -> List[str] - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_net_split_host_port( - _ctx: *mut kclvm_context_t, - args: *const kclvm_value_ref_t, - _kwargs: *const kclvm_value_ref_t, -) -> *const kclvm_value_ref_t { - let args = ptr_as_ref(args); - - if let Some(string) = args.arg_i_str(0, None) { - let mut list = ValueRef::list(None); - for s in string.split(':') { - list.list_append(&ValueRef::str(s)); - } - return list.into_raw(); - } - - panic!("split_host_port() missing 1 required positional argument: 'ip_end_point'"); -} - -// join_host_port(host, port) -> str - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_net_join_host_port( - _ctx: *mut kclvm_context_t, - args: *const kclvm_value_ref_t, - _kwargs: *const kclvm_value_ref_t, -) -> *const kclvm_value_ref_t { - let args = ptr_as_ref(args); - - if let Some(host) = args.arg_i_str(0, None) { - if let Some(port) = args.arg_i_int(1, None) { - let s = format!("{}:{}", host, port); - return ValueRef::str(s.as_ref()).into_raw(); - } - if let Some(port) = args.arg_i_str(1, None) { - let s = format!("{}:{}", host, port); - return ValueRef::str(s.as_ref()).into_raw(); - } - } - panic!("join_host_port() missing 2 required positional arguments: 'host' and 'port'"); -} - -// fqdn(name: str = '') -> str - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_net_fqdn( - _ctx: *mut kclvm_context_t, - args: *const kclvm_value_ref_t, - _kwargs: *const kclvm_value_ref_t, -) -> *const kclvm_value_ref_t { - let args = ptr_as_ref(args); - - if let Some(_name) = args.arg_i_str(0, Some("".to_string())) { - todo!("todo"); - } - panic!("fqdn() missing 1 required positional argument: 'name'"); -} - -// parse_IP(ip) -> str - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_net_parse_IP( - ctx: *mut kclvm_context_t, - args: *const kclvm_value_ref_t, - kwargs: *const kclvm_value_ref_t, -) -> *const kclvm_value_ref_t { - kclvm_net_IP_string(ctx, args, kwargs) -} - -// to_IP4(ip) -> str - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_net_to_IP4( - ctx: *mut kclvm_context_t, - args: *const kclvm_value_ref_t, - kwargs: *const kclvm_value_ref_t, -) -> *const kclvm_value_ref_t { - kclvm_net_IP_string(ctx, args, kwargs) -} - -// to_IP16(ip) -> int - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_net_to_IP16( - ctx: *mut kclvm_context_t, - args: *const kclvm_value_ref_t, - kwargs: *const kclvm_value_ref_t, -) -> *const kclvm_value_ref_t { - kclvm_net_IP_string(ctx, args, kwargs) -} - -// IP_string(ip: str) -> str - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_net_IP_string( - _ctx: *mut kclvm_context_t, - args: *const kclvm_value_ref_t, - _kwargs: *const kclvm_value_ref_t, -) -> *const kclvm_value_ref_t { - let args = ptr_as_ref(args); - - if let Some(ip) = args.arg_i_str(0, None) { - if let Ok(addr) = Ipv4Addr::from_str(ip.as_ref()) { - let s = format!("{}", addr); - return ValueRef::str(s.as_ref()).into_raw(); - } - if let Ok(addr) = Ipv6Addr::from_str(ip.as_ref()) { - let s = format!("{}", addr); - return ValueRef::str(s.as_ref()).into_raw(); - } - - return kclvm_value_False(); - } - - panic!("IP_string() missing 1 required positional argument: 'ip'"); -} - -// is_IPv4(ip: str) -> bool - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_net_is_IPv4( - _ctx: *mut kclvm_context_t, - args: *const kclvm_value_ref_t, - _kwargs: *const kclvm_value_ref_t, -) -> *const kclvm_value_ref_t { - let args = ptr_as_ref(args); - - if let Some(ip) = args.arg_i_str(0, None) { - if let Ok(_addr) = Ipv4Addr::from_str(ip.as_ref()) { - return kclvm_value_True(); - } - if let Ok(_addr) = Ipv6Addr::from_str(ip.as_ref()) { - return kclvm_value_False(); - } - - return kclvm_value_False(); - } - - panic!("is_IPv4() missing 1 required positional argument: 'ip'"); -} - -// is_IP(ip: str) -> bool - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_net_is_IP( - _ctx: *mut kclvm_context_t, - args: *const kclvm_value_ref_t, - _kwargs: *const kclvm_value_ref_t, -) -> *const kclvm_value_ref_t { - let args = ptr_as_ref(args); - - if let Some(ip) = args.arg_i_str(0, None) { - if let Ok(..) = Ipv4Addr::from_str(ip.as_ref()) { - return kclvm_value_True(); - } - if let Ok(..) = Ipv6Addr::from_str(ip.as_ref()) { - return kclvm_value_True(); - } - - return kclvm_value_False(); - } - - panic!("is_IP() missing 1 required positional argument: 'ip'"); -} - -// is_loopback_IP(ip: str) -> bool - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_net_is_loopback_IP( - _ctx: *mut kclvm_context_t, - args: *const kclvm_value_ref_t, - _kwargs: *const kclvm_value_ref_t, -) -> *const kclvm_value_ref_t { - let args = ptr_as_ref(args); - - if let Some(ip) = args.arg_i_str(0, None) { - if let Ok(addr) = Ipv4Addr::from_str(ip.as_ref()) { - let x = addr.is_loopback(); - return kclvm_value_Bool(x as i8); - } - if let Ok(addr) = Ipv6Addr::from_str(ip.as_ref()) { - let x = addr.is_loopback(); - return kclvm_value_Bool(x as i8); - } - - return kclvm_value_False(); - } - - panic!("is_loopback_IP() missing 1 required positional argument: 'ip'"); -} - -// is_multicast_IP(ip: str) -> bool - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_net_is_multicast_IP( - _ctx: *mut kclvm_context_t, - args: *const kclvm_value_ref_t, - _kwargs: *const kclvm_value_ref_t, -) -> *const kclvm_value_ref_t { - let args = ptr_as_ref(args); - - if let Some(ip) = args.arg_i_str(0, None) { - if let Ok(addr) = Ipv4Addr::from_str(ip.as_ref()) { - let x = addr.is_multicast(); - return kclvm_value_Bool(x as i8); - } - if let Ok(addr) = Ipv6Addr::from_str(ip.as_ref()) { - let x = addr.is_multicast(); - return kclvm_value_Bool(x as i8); - } - - return kclvm_value_False(); - } - - panic!("kclvm_net_is_multicast_IP() missing 1 required positional argument: 'ip'"); -} - -// is_interface_local_multicast_IP(ip: str) -> bool - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_net_is_interface_local_multicast_IP( - _ctx: *mut kclvm_context_t, - args: *const kclvm_value_ref_t, - _kwargs: *const kclvm_value_ref_t, -) -> *const kclvm_value_ref_t { - let args = ptr_as_ref(args); - - if let Some(ip) = args.arg_i_str(0, None) { - if let Ok(addr) = Ipv4Addr::from_str(ip.as_ref()) { - let is_site_local = false; // TODO - let x = is_site_local && addr.is_multicast(); - return kclvm_value_Bool(x as i8); - } - if let Ok(_addr) = Ipv6Addr::from_str(ip.as_ref()) { - todo!("todo"); - } - - return kclvm_value_False(); - } - - panic!("is_interface_local_multicast_IP() missing 1 required positional argument: 'ip'"); -} - -// is_link_local_multicast_IP(ip: str) -> bool - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_net_is_link_local_multicast_IP( - _ctx: *mut kclvm_context_t, - args: *const kclvm_value_ref_t, - _kwargs: *const kclvm_value_ref_t, -) -> *const kclvm_value_ref_t { - let args = ptr_as_ref(args); - - if let Some(ip) = args.arg_i_str(0, None) { - if let Ok(addr) = Ipv4Addr::from_str(ip.as_ref()) { - let x = addr.is_link_local() && addr.is_multicast(); - return kclvm_value_Bool(x as i8); - } - if let Ok(addr) = Ipv6Addr::from_str(ip.as_ref()) { - let is_link_local = false; // TODO - let x = is_link_local && addr.is_multicast(); - return kclvm_value_Bool(x as i8); - } - - return kclvm_value_False(); - } - - panic!("is_link_local_multicast_IP() missing 1 required positional argument: 'ip'"); -} - -// is_link_local_unicast_IP(ip: str) -> bool - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_net_is_link_local_unicast_IP( - ctx: *mut kclvm_context_t, - args: *const kclvm_value_ref_t, - kwargs: *const kclvm_value_ref_t, -) -> *const kclvm_value_ref_t { - let _ctx = mut_ptr_as_ref(ctx); - let args = ptr_as_ref(args); - let _kwargs = ptr_as_ref(kwargs); - - if let Some(ip) = args.arg_i_str(0, None) { - if let Ok(addr) = Ipv4Addr::from_str(ip.as_ref()) { - let x = addr.is_link_local() && (!addr.is_multicast()); - return kclvm_value_Bool(x as i8); - } - if let Ok(_addr) = Ipv6Addr::from_str(ip.as_ref()) { - let x = Ipv6Addr_is_unicast_link_local(&_addr) && (!_addr.is_multicast()); - return kclvm_value_Bool(x as i8); - } - return kclvm_value_False(); - } - - panic!("is_link_local_unicast_IP() missing 1 required positional argument: 'ip'"); -} - -#[allow(non_camel_case_types, non_snake_case)] -pub const fn Ipv6Addr_is_unicast_link_local(_self: &Ipv6Addr) -> bool { - (_self.segments()[0] & 0xffc0) == 0xfe80 -} - -// is_global_unicast_IP(ip: str) -> bool - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_net_is_global_unicast_IP( - _ctx: *mut kclvm_context_t, - args: *const kclvm_value_ref_t, - _kwargs: *const kclvm_value_ref_t, -) -> *const kclvm_value_ref_t { - let args = ptr_as_ref(args); - - if let Some(ip) = args.arg_i_str(0, None) { - if let Ok(addr) = Ipv4Addr::from_str(ip.as_ref()) { - let x = Ipv4Addr_is_global(&addr) && (!addr.is_multicast()); - return kclvm_value_Bool(x as i8); - } - if let Ok(addr) = Ipv6Addr::from_str(ip.as_ref()) { - return kclvm_value_Bool(addr.is_multicast() as i8); - } - - return kclvm_value_False(); - } - - panic!("is_global_unicast_IP() missing 1 required positional argument: 'ip'"); -} - -#[allow(non_camel_case_types, non_snake_case)] -fn Ipv4Addr_is_global(_self: &std::net::Ipv4Addr) -> bool { - // check if this address is 192.0.0.9 or 192.0.0.10. These addresses are the only two - // globally routable addresses in the 192.0.0.0/24 range. - if u32::from_be_bytes(_self.octets()) == 0xc0000009 - || u32::from_be_bytes(_self.octets()) == 0xc000000a - { - return true; - } - !_self.is_private() - && !_self.is_loopback() - && !_self.is_link_local() - && !_self.is_broadcast() - && !_self.is_documentation() - && !Ipv4Addr_is_shared(_self) // _self.is_shared() - && !Ipv4Addr_is_ietf_protocol_assignment(_self) // _self.is_ietf_protocol_assignment() - && !Ipv4Addr_is_reserved(_self) // _self.is_reserved() - && !Ipv4Addr_is_benchmarking(_self) // _self.is_benchmarking() - // Make sure the address is not in 0.0.0.0/8 - && _self.octets()[0] != 0 -} - -#[allow(non_camel_case_types, non_snake_case)] -const fn Ipv4Addr_is_shared(_self: &std::net::Ipv4Addr) -> bool { - _self.octets()[0] == 100 && (_self.octets()[1] & 0b1100_0000 == 0b0100_0000) -} -#[allow(non_camel_case_types, non_snake_case)] -const fn Ipv4Addr_is_ietf_protocol_assignment(_self: &std::net::Ipv4Addr) -> bool { - _self.octets()[0] == 192 && _self.octets()[1] == 0 && _self.octets()[2] == 0 -} -#[allow(non_camel_case_types, non_snake_case)] -const fn Ipv4Addr_is_reserved(_self: &std::net::Ipv4Addr) -> bool { - _self.octets()[0] & 240 == 240 && !_self.is_broadcast() -} -#[allow(non_camel_case_types, non_snake_case)] -const fn Ipv4Addr_is_benchmarking(_self: &std::net::Ipv4Addr) -> bool { - _self.octets()[0] == 198 && (_self.octets()[1] & 0xfe) == 18 -} - -// is_unspecified_IP(ip: str) -> bool - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_net_is_unspecified_IP( - _ctx: *mut kclvm_context_t, - args: *const kclvm_value_ref_t, - _kwargs: *const kclvm_value_ref_t, -) -> *const kclvm_value_ref_t { - let args = ptr_as_ref(args); - - if let Some(ip) = args.arg_i_str(0, None) { - if let Ok(addr) = Ipv4Addr::from_str(ip.as_ref()) { - return kclvm_value_Bool(addr.is_unspecified() as i8); - } - if let Ok(addr) = Ipv6Addr::from_str(ip.as_ref()) { - return kclvm_value_Bool(addr.is_unspecified() as i8); - } - return kclvm_value_False(); - } - panic!("is_unspecified_IP() missing 1 required positional argument: 'ip'"); -} diff --git a/kclvm/runtime/src/panic/mod.rs b/kclvm/runtime/src/panic/mod.rs new file mode 100644 index 000000000..d5ee2ffea --- /dev/null +++ b/kclvm/runtime/src/panic/mod.rs @@ -0,0 +1,123 @@ +use std::{any::Any, mem::transmute_copy, os::raw::c_char}; + +use std::cell::UnsafeCell; +use std::panic::catch_unwind; +use std::panic::AssertUnwindSafe; +use std::panic::RefUnwindSafe; +use std::panic::UnwindSafe; + +use crate::*; + +/// Executes the provided function and catches any potential runtime errors. +/// Returns undefined if execution is successful, otherwise returns an error +/// message in case of a runtime panic. +#[no_mangle] +#[runtime_fn] +pub extern "C" fn kclvm_runtime_catch( + ctx: *mut kclvm_context_t, + args: *const kclvm_value_ref_t, + kwargs: *const kclvm_value_ref_t, +) -> *const kclvm_value_ref_t { + let args = ptr_as_ref(args); + let kwargs = ptr_as_ref(kwargs); + let ctx = mut_ptr_as_ref(ctx); + + if let Some(func) = get_call_arg(args, kwargs, 0, Some("func")) { + let func = func.as_function(); + if ctx.cfg.debug_mode { + ctx.backtrace + .push(BacktraceFrame::from_panic_info(&ctx.panic_info)); + ctx.panic_info.kcl_func = func.name.clone(); + } + let now_meta_info = ctx.panic_info.clone(); + let fn_ptr = func.fn_ptr; + let wrapper = UnsafeWrapper::new(|| { + let args = ValueRef::list(None).into_raw(ctx); + let kwargs = ValueRef::dict(None).into_raw(ctx); + unsafe { + let call_fn: SchemaTypeFunc = transmute_copy(&fn_ptr); + // Call schema constructor twice + if func.is_external { + let name = format!("{}\0", func.name); + kclvm_plugin_invoke(ctx, name.as_ptr() as *const c_char, args, kwargs) + } else { + call_fn(ctx, args, kwargs) + }; + }; + }); + let result = catch_unwind(AssertUnwindSafe(|| unsafe { + (wrapper.get())(); + })); + if ctx.cfg.debug_mode { + ctx.backtrace.pop(); + } + ctx.panic_info = now_meta_info; + return match result { + Ok(_) => ValueRef::undefined(), + Err(err) => ValueRef::str(&err_to_str(err)), + } + .into_raw(ctx); + } + panic!("catch() takes exactly one argument (0 given)"); +} + +#[inline] +pub fn is_runtime_catch_function(ptr: u64) -> bool { + ptr == kclvm_runtime_catch as *const () as u64 +} + +/// Convert an error to string. +pub fn err_to_str(err: Box) -> String { + if let Some(s) = err.downcast_ref::<&str>() { + s.to_string() + } else if let Some(s) = err.downcast_ref::<&String>() { + (*s).clone() + } else if let Some(s) = err.downcast_ref::() { + (*s).clone() + } else { + "".to_string() + } +} + +/// A wrapper struct that holds a value of type T inside an UnsafeCell. +/// UnsafeCell is the core primitive for interior mutability in Rust. +pub struct UnsafeWrapper { + value: UnsafeCell, +} + +impl UnsafeWrapper { + /// Creates a new instance of UnsafeWrapper with the provided value. + /// + /// # Arguments + /// + /// * `value` - The value to be wrapped inside an UnsafeCell. + /// + /// # Returns + /// + /// A new instance of UnsafeWrapper containing the provided value. + pub fn new(value: T) -> Self { + UnsafeWrapper { + value: UnsafeCell::new(value), + } + } + + /// Provides a mutable reference to the inner value. + /// + /// # Safety + /// + /// This is an unsafe function because obtaining multiple mutable references + /// can lead to undefined behavior. The caller must ensure that the returned + /// reference does not violate Rust's borrowing rules. + /// + /// # Returns + /// + /// A mutable reference to the inner value of type T. + pub unsafe fn get(&self) -> &mut T { + &mut *self.value.get() + } +} + +// Implementing the UnwindSafe and RefUnwindSafe traits for UnsafeWrapper +// to ensure it can be safely used across panic boundaries. +impl UnwindSafe for UnsafeWrapper {} +impl RefUnwindSafe for UnsafeWrapper {} diff --git a/kclvm/runtime/src/regex/mod.rs b/kclvm/runtime/src/regex/mod.rs index 71be7d77c..5d5a4b996 100644 --- a/kclvm/runtime/src/regex/mod.rs +++ b/kclvm/runtime/src/regex/mod.rs @@ -1,4 +1,197 @@ -// Copyright 2021 The KCL Authors. All rights reserved. +//! Copyright The KCL Authors. All rights reserved. -pub mod regex; -pub use self::regex::*; +extern crate fancy_regex; + +use crate::*; + +// match(string: str, pattern: str) -> bool: + +#[no_mangle] +#[runtime_fn] +pub extern "C" fn kclvm_regex_match( + ctx: *mut kclvm_context_t, + args: *const kclvm_value_ref_t, + kwargs: *const kclvm_value_ref_t, +) -> *const kclvm_value_ref_t { + let args = ptr_as_ref(args); + let kwargs = ptr_as_ref(kwargs); + + if let Some(string) = get_call_arg_str(args, kwargs, 0, Some("string")) { + if let Some(pattern) = get_call_arg_str(args, kwargs, 1, Some("pattern")) { + let re = fancy_regex::Regex::new(pattern.as_ref()).unwrap(); + match re.is_match(string.as_ref()) { + Ok(ok) => { + if ok { + return kclvm_value_Bool(ctx, 1); + } else { + return kclvm_value_Bool(ctx, 0); + } + } + _ => return kclvm_value_Bool(ctx, 0), + } + } + } + + panic!("match() missing 2 required positional arguments: 'string' and 'pattern'") +} + +// replace(string: str, pattern: str, replace: str, count: int = 0): + +#[no_mangle] +#[runtime_fn] +pub extern "C" fn kclvm_regex_replace( + ctx: *mut kclvm_context_t, + args: *const kclvm_value_ref_t, + kwargs: *const kclvm_value_ref_t, +) -> *mut kclvm_value_ref_t { + let args = ptr_as_ref(args); + let kwargs = ptr_as_ref(kwargs); + let ctx = mut_ptr_as_ref(ctx); + if let Some(string) = get_call_arg_str(args, kwargs, 0, Some("string")) { + if let Some(pattern) = get_call_arg_str(args, kwargs, 1, Some("pattern")) { + if let Some(replace) = get_call_arg_str(args, kwargs, 2, Some("replace")) { + let count = get_call_arg_int(args, kwargs, 3, Some("count")).unwrap_or_else(|| 0); + let re = fancy_regex::Regex::new(pattern.as_ref()).unwrap(); + let s = re.replacen(string.as_ref(), count as usize, replace.as_ref() as &str); + return ValueRef::str(&s).into_raw(ctx); + } + panic!("replace() missing the required positional argument: 'replace'"); + } + panic!("replace() missing the required positional argument: 'pattern'"); + } + panic!("replace() missing 3 required positional arguments: 'string', 'pattern', and 'replace"); +} + +// compile(pattern: str) -> bool: + +#[no_mangle] +#[runtime_fn] +pub extern "C" fn kclvm_regex_compile( + ctx: *mut kclvm_context_t, + args: *const kclvm_value_ref_t, + kwargs: *const kclvm_value_ref_t, +) -> *mut kclvm_value_ref_t { + let args = ptr_as_ref(args); + let kwargs = ptr_as_ref(kwargs); + + if let Some(pattern) = get_call_arg_str(args, kwargs, 0, Some("pattern")) { + match fancy_regex::Regex::new(pattern.as_ref()) { + Ok(_) => return kclvm_value_Bool(ctx, 1), + _ => return kclvm_value_Bool(ctx, 0), + } + } + panic!("compile() missing the required positional argument: 'pattern'") +} + +// findall(string: str, pattern: str) -> [str]: + +#[no_mangle] +#[runtime_fn] +pub extern "C" fn kclvm_regex_findall( + ctx: *mut kclvm_context_t, + args: *const kclvm_value_ref_t, + kwargs: *const kclvm_value_ref_t, +) -> *mut kclvm_value_ref_t { + let args = ptr_as_ref(args); + let kwargs = ptr_as_ref(kwargs); + let ctx = mut_ptr_as_ref(ctx); + if let Some(string) = get_call_arg_str(args, kwargs, 0, Some("string")) { + if let Some(pattern) = get_call_arg_str(args, kwargs, 1, Some("pattern")) { + let mut list = ValueRef::list(None); + + for x in fancy_regex::Regex::new(pattern.as_ref()) + .unwrap() + .captures_iter(string.as_ref()) + .flatten() + { + let len = x.len(); + if len < 3 { + list.list_append(&ValueRef::str(x.get(0).unwrap().as_str())); + } else { + let mut sub_list = ValueRef::list(None); + for i in 1..len { + sub_list.list_append(&ValueRef::str(x.get(i).unwrap().as_str())); + } + list.list_append(&sub_list) + } + } + + return list.into_raw(ctx); + } + panic!("findall() missing the required positional argument: 'pattern'") + } + panic!("findall() missing 2 required positional arguments: 'string' and 'pattern'") +} + +// search(string: str, pattern: str): + +#[no_mangle] +#[runtime_fn] +pub extern "C" fn kclvm_regex_search( + ctx: *mut kclvm_context_t, + args: *const kclvm_value_ref_t, + kwargs: *const kclvm_value_ref_t, +) -> *mut kclvm_value_ref_t { + let args = ptr_as_ref(args); + let kwargs = ptr_as_ref(kwargs); + + if let Some(string) = get_call_arg_str(args, kwargs, 0, Some("string")) { + if let Some(pattern) = get_call_arg_str(args, kwargs, 1, Some("pattern")) { + let re = fancy_regex::Regex::new(pattern.as_ref()).unwrap(); + + if let Ok(Some(..)) = re.find(string.as_ref()) { + return kclvm_value_Bool(ctx, 1); + } + return kclvm_value_Bool(ctx, 0); + } + panic!("search() missing the required positional argument: 'pattern'"); + } + panic!("search() missing 2 required positional arguments: 'string' and 'pattern'"); +} + +// split(string: str, pattern: str, maxsplit: int = 0): + +#[no_mangle] +#[runtime_fn] +pub extern "C" fn kclvm_regex_split( + ctx: *mut kclvm_context_t, + args: *const kclvm_value_ref_t, + kwargs: *const kclvm_value_ref_t, +) -> *mut kclvm_value_ref_t { + let args = ptr_as_ref(args); + let kwargs = ptr_as_ref(kwargs); + let ctx = mut_ptr_as_ref(ctx); + if let Some(string) = get_call_arg_str(args, kwargs, 0, Some("string")) { + if let Some(pattern) = get_call_arg_str(args, kwargs, 1, Some("pattern")) { + let maxsplit = get_call_arg_int(args, kwargs, 2, Some("maxsplit")).unwrap_or_else(|| 0); + let mut list = ValueRef::list(None); + + let re = fancy_regex::Regex::new(pattern.as_ref()).unwrap(); + + let mut fields: Vec = Vec::new(); + let mut current_pos = 0; + loop { + let capture = re + .captures_from_pos(string.as_ref(), current_pos) + .map_or(None, |c| c); + if let Some(Some(cap)) = capture.map(|c| c.get(0)) { + fields.push(string[current_pos..cap.start()].to_string()); + if maxsplit > 0 && fields.len() >= (maxsplit as usize) { + break; + } + current_pos = cap.end(); + } else { + fields.push(string[current_pos..].to_string()); + break; + } + } + + for s in fields { + list.list_append(&ValueRef::str(s.as_ref())); + } + return list.into_raw(ctx); + } + panic!("split() missing the required positional argument: 'pattern'"); + } + panic!("split() missing 2 required positional arguments: 'string' and 'pattern'"); +} diff --git a/kclvm/runtime/src/regex/regex.rs b/kclvm/runtime/src/regex/regex.rs deleted file mode 100644 index 766005f9b..000000000 --- a/kclvm/runtime/src/regex/regex.rs +++ /dev/null @@ -1,200 +0,0 @@ -//! KCL regex system module -//! regex.match(string: str, pattern: str) -> bool -//! regex.replace(string: str, pattern: str, replace: str, count: int = 0) -> str -//! regex.compile(pattern: str) -> bool -//! regex.findall(string: str, pattern: str) -> [str] -//! regex.search(string: str, pattern: str) -> bool -//! regex.split(string: str, pattern: str, maxsplit: int = 0) -> [str] -//! -//! Copyright 2021 The KCL Authors. All rights reserved. - -extern crate fancy_regex; - -use crate::*; - -#[allow(non_camel_case_types)] -type kclvm_value_ref_t = ValueRef; - -// def KMANGLED_match(string: str, pattern: str) -> bool: - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_regex_match( - _ctx: *mut kclvm_context_t, - args: *const kclvm_value_ref_t, - _kwargs: *const kclvm_value_ref_t, -) -> *const kclvm_value_ref_t { - let args = ptr_as_ref(args); - - if let Some(string) = args.arg_i_str(0, None) { - if let Some(pattern) = args.arg_i_str(1, None) { - let re = fancy_regex::Regex::new(pattern.as_ref()).unwrap(); - match re.is_match(string.as_ref()) { - Ok(ok) => { - if ok { - return kclvm_value_Bool(1); - } else { - return kclvm_value_Bool(0); - } - } - _ => return kclvm_value_Bool(0), - } - } - } - - panic!("match() missing 2 required positional arguments: 'string' and 'pattern'") -} - -// def KMANGLED_replace(string: str, pattern: str, replace: str, count: int = 0): - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_regex_replace( - _ctx: *mut kclvm_context_t, - args: *const kclvm_value_ref_t, - _kwargs: *const kclvm_value_ref_t, -) -> *mut kclvm_value_ref_t { - let args = ptr_as_ref(args); - - if let Some(string) = args.arg_i_str(0, None) { - if let Some(pattern) = args.arg_i_str(1, None) { - if let Some(replace) = args.arg_i_str(2, None) { - if let Some(count) = args.arg_i_int(3, Some(0)) { - let re = fancy_regex::Regex::new(pattern.as_ref()).unwrap(); - let s = re.replacen(string.as_ref(), count as usize, replace.as_ref() as &str); - return ValueRef::str(&s).into_raw(); - } - } - } - } - panic!("replace() missing 3 required positional arguments: 'string', 'pattern', and 'replace"); -} - -// def KMANGLED_compile(pattern: str) -> bool: - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_regex_compile( - _ctx: *mut kclvm_context_t, - args: *const kclvm_value_ref_t, - _kwargs: *const kclvm_value_ref_t, -) -> *mut kclvm_value_ref_t { - let args = ptr_as_ref(args); - - if let Some(pattern) = args.arg_i_str(0, None) { - match fancy_regex::Regex::new(pattern.as_ref()) { - Ok(_) => return kclvm_value_Bool(1), - _ => return kclvm_value_Bool(0), - } - } - panic!("compile() missing 2 required positional arguments: 'string' and 'pattern'") -} - -// def KMANGLED_findall(string: str, pattern: str) -> [str]: - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_regex_findall( - _ctx: *mut kclvm_context_t, - args: *const kclvm_value_ref_t, - _kwargs: *const kclvm_value_ref_t, -) -> *mut kclvm_value_ref_t { - let args = ptr_as_ref(args); - - if let Some(string) = args.arg_i_str(0, None) { - if let Some(pattern) = args.arg_i_str(1, None) { - let mut list = ValueRef::list(None); - - for x in fancy_regex::Regex::new(pattern.as_ref()) - .unwrap() - .captures_iter(string.as_ref()) - .flatten() - { - let len = x.len(); - if len < 3 { - list.list_append(&ValueRef::str(x.get(0).unwrap().as_str())); - } else { - let mut sub_list = ValueRef::list(None); - for i in 1..len { - sub_list.list_append(&ValueRef::str(x.get(i).unwrap().as_str())); - } - list.list_append(&sub_list) - } - } - - return list.into_raw(); - } - } - - panic!("findall() missing 2 required positional arguments: 'string' and 'pattern'") -} - -// def KMANGLED_search(string: str, pattern: str): - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_regex_search( - _ctx: *mut kclvm_context_t, - args: *const kclvm_value_ref_t, - _kwargs: *const kclvm_value_ref_t, -) -> *mut kclvm_value_ref_t { - let args = ptr_as_ref(args); - - if let Some(string) = args.arg_i_str(0, None) { - if let Some(pattern) = args.arg_i_str(1, None) { - let re = fancy_regex::Regex::new(pattern.as_ref()).unwrap(); - - if let Ok(Some(..)) = re.find(string.as_ref()) { - return kclvm_value_Bool(1); - } - return kclvm_value_Bool(0); - } - } - panic!("search() missing 2 required positional arguments: 'string' and 'pattern'"); -} - -// def KMANGLED_split(string: str, pattern: str, maxsplit: int = 0): - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_regex_split( - _ctx: *mut kclvm_context_t, - args: *const kclvm_value_ref_t, - _kwargs: *const kclvm_value_ref_t, -) -> *mut kclvm_value_ref_t { - let args = ptr_as_ref(args); - - if let Some(string) = args.arg_i_str(0, None) { - if let Some(pattern) = args.arg_i_str(1, None) { - if let Some(maxsplit) = args.arg_i_int(2, Some(0)) { - let mut list = ValueRef::list(None); - - let re = fancy_regex::Regex::new(pattern.as_ref()).unwrap(); - - let mut fields: Vec = Vec::new(); - let mut current_pos = 0; - loop { - let capture = re - .captures_from_pos(string.as_ref(), current_pos) - .map_or(None, |c| c); - if let Some(Some(cap)) = capture.map(|c| c.get(0)) { - fields.push(string[current_pos..cap.start()].to_string()); - if maxsplit > 0 && fields.len() >= (maxsplit as usize) { - break; - } - current_pos = cap.end(); - } else { - fields.push(string[current_pos..].to_string()); - break; - } - } - - for s in fields { - list.list_append(&ValueRef::str(s.as_ref())); - } - return list.into_raw(); - } - } - } - panic!("split() missing 2 required positional arguments: 'string' and 'pattern'"); -} diff --git a/kclvm/runtime/src/stdlib/assert_api.rs b/kclvm/runtime/src/stdlib/assert_api.rs index 478a3a254..34c6cb007 100644 --- a/kclvm/runtime/src/stdlib/assert_api.rs +++ b/kclvm/runtime/src/stdlib/assert_api.rs @@ -1,4 +1,4 @@ -// Copyright 2021 The KCL Authors. All rights reserved. +//! Copyright The KCL Authors. All rights reserved. use crate::*; @@ -7,13 +7,17 @@ type kclvm_value_ref_t = ValueRef; #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_assert(value: *const kclvm_value_ref_t, msg: *const kclvm_value_ref_t) { +pub extern "C" fn kclvm_assert( + ctx: *mut kclvm_context_t, + value: *const kclvm_value_ref_t, + msg: *const kclvm_value_ref_t, +) { let value = ptr_as_ref(value); let msg = ptr_as_ref(msg); if !value.is_truthy() { - let ctx = Context::current_context_mut(); - ctx.set_err_type(&ErrType::AssertionError_TYPE); + let ctx = mut_ptr_as_ref(ctx); + ctx.set_err_type(&RuntimeErrorType::AssertionError); let msg = msg.as_str(); panic!("{}", msg); diff --git a/kclvm/runtime/src/stdlib/builtin.rs b/kclvm/runtime/src/stdlib/builtin.rs index be3464dea..8ecf6506e 100644 --- a/kclvm/runtime/src/stdlib/builtin.rs +++ b/kclvm/runtime/src/stdlib/builtin.rs @@ -1,4 +1,4 @@ -// Copyright 2021 The KCL Authors. All rights reserved. +//! Copyright The KCL Authors. All rights reserved. use std::{collections::HashSet, ops::Index}; @@ -6,27 +6,22 @@ use crate::*; impl Context { pub fn builtin_option_init(&mut self, key: &str, value: &str) { - if let Some(x) = ValueRef::from_json(value) { - self.app_args.insert(key.to_string(), x.into_raw() as u64); + if let Ok(x) = ValueRef::from_json(self, value) { + self.option_values.insert(key.to_string(), x); return; } - self.app_args - .insert(key.to_string(), ValueRef::str(value).into_raw() as u64); + self.option_values + .insert(key.to_string(), ValueRef::str(value)); } pub fn builtin_option_reset(&mut self) { - for (_, x) in self.app_args.iter() { - if (*x) != 0 { - kclvm_value_delete((*x) as *mut ValueRef); - } - } - self.app_args.clear(); + self.option_values.clear(); } } impl ValueRef { pub fn any_true(&self) -> bool { - match &*self.rc { + match &*self.rc.borrow() { Value::list_value(ref list) => { for x in list.values.iter() { if x.is_truthy() { @@ -56,7 +51,7 @@ impl ValueRef { } pub fn all_true(&self) -> bool { - match &*self.rc { + match &*self.rc.borrow() { Value::list_value(ref list) => { for x in list.values.iter() { if !x.is_truthy() { @@ -86,7 +81,7 @@ impl ValueRef { } pub fn isunique(&self) -> bool { - match &*self.rc { + match &*self.rc.borrow() { Value::list_value(ref list) => { let mut set: HashSet<&ValueRef> = HashSet::new(); for x in list.values.iter() { @@ -107,7 +102,7 @@ impl ValueRef { } else { false }; - match &*self.rc { + match &*self.rc.borrow() { Value::str_value(s) => { let mut list = ListValue::default(); for c in s.chars() { @@ -120,16 +115,18 @@ impl ValueRef { } else { values.sort(); } - Self::from(Value::list_value(list)) + Self::from(Value::list_value(Box::new(list))) } Value::list_value(_) => { let mut list = self.deep_copy(); - let list_ref = list.as_list_mut_ref(); - let values = &mut list_ref.values; - if reverse { - values.sort_by(|a, b| b.partial_cmp(a).unwrap()); - } else { - values.sort(); + { + let mut list_ref = list.as_list_mut_ref(); + let values = &mut list_ref.values; + if reverse { + values.sort_by(|a, b| b.partial_cmp(a).unwrap()); + } else { + values.sort(); + } } list } @@ -145,18 +142,17 @@ impl ValueRef { } else { values.sort(); } - Self::from(Value::list_value(list)) + Self::from(Value::list_value(Box::new(list))) } _ => panic!("sorted only for str|list|dict type"), } } - pub fn convert_to_int(&self, base: Option<&ValueRef>) -> ValueRef { - let ctx = crate::Context::current_context_mut(); + pub fn convert_to_int(&self, ctx: &mut Context, base: Option<&ValueRef>) -> ValueRef { let strict_range_check_i32 = ctx.cfg.strict_range_check; let strict_range_check_i64 = ctx.cfg.debug_mode || !ctx.cfg.strict_range_check; - match &*self.rc { + match &*self.rc.borrow() { Value::int_value(ref v) => ValueRef::int(*v), Value::float_value(ref v) => ValueRef::int(*v as i64), Value::unit_value(ref v, raw, unit) => { @@ -166,16 +162,14 @@ impl ValueRef { if ctx.cfg.debug_mode { if int_32_overflow { - let ctx = Context::current_context_mut(); - ctx.set_err_type(&ErrType::IntOverflow_TYPE); + ctx.set_err_type(&RuntimeErrorType::IntOverflow); - panic!("{}: A 32 bit integer overflow", v_i128); + panic!("{v_i128}: A 32 bit integer overflow"); } if int_64_overflow { - let ctx = Context::current_context_mut(); - ctx.set_err_type(&ErrType::IntOverflow_TYPE); + ctx.set_err_type(&RuntimeErrorType::IntOverflow); - panic!("{}: A 64 bit integer overflow", v_i128); + panic!("{v_i128}: A 64 bit integer overflow"); } } @@ -187,39 +181,34 @@ impl ValueRef { let number_str = to_quantity(v.as_str()).to_string(); let v: i64 = i64::from_str_radix(number_str.as_str(), base as u32).unwrap_or_else(|_| { - panic!( - "invalid literal for int() with base {}: '{}'", - base, - self.to_string() - ) + panic!("invalid literal for int() with base {base}: '{self}'") }); ValueRef::int(v) } _ => panic!( - "int() argument must be a string, a bytes-like object or a number, not '{}'", + "int() argument must be a string or a number, not '{}'", self.type_str() ), } } - pub fn convert_to_float(&self) -> ValueRef { - let ctx = crate::Context::current_context_mut(); + pub fn convert_to_float(&self, ctx: &mut Context) -> ValueRef { let strict_range_check_i32 = ctx.cfg.strict_range_check; let strict_range_check_i64 = ctx.cfg.debug_mode || !ctx.cfg.strict_range_check; - match &*self.rc { + match &*self.rc.borrow() { Value::int_value(ref v) => ValueRef::float(*v as f64), Value::float_value(ref v) => { let float32_overflow = strict_range_check_i32 && (*v as f32).is_infinite(); let float64_overflow = strict_range_check_i64 && (*v).is_infinite(); if float32_overflow { - ctx.set_err_type(&ErrType::FloatOverflow_TYPE); + ctx.set_err_type(&RuntimeErrorType::FloatOverflow); panic!("inf: A 32-bit floating point number overflow"); } if float64_overflow { - ctx.set_err_type(&ErrType::FloatOverflow_TYPE); + ctx.set_err_type(&RuntimeErrorType::FloatOverflow); panic!("inf: A 64-bit floating point number overflow"); } @@ -229,29 +218,23 @@ impl ValueRef { Value::bool_value(ref v) => ValueRef::float((*v as i64) as f64), Value::str_value(ref v) => { let v: f64 = v.parse().unwrap_or_else(|_| { - panic!( - "invalid literal for float() with base 10: '{}'", - self.to_string() - ) + panic!("invalid literal for float() with base 10: '{self}'") }); let float32_overflow = strict_range_check_i32 && (v as f32).is_infinite(); let float64_overflow = strict_range_check_i64 && (v).is_infinite(); if float32_overflow { - ctx.set_err_type(&ErrType::FloatOverflow_TYPE); + ctx.set_err_type(&RuntimeErrorType::FloatOverflow); panic!("inf: A 32-bit floating point number overflow"); } if float64_overflow { - ctx.set_err_type(&ErrType::FloatOverflow_TYPE); + ctx.set_err_type(&RuntimeErrorType::FloatOverflow); panic!("inf: A 64-bit floating point number overflow"); } ValueRef::float(v) } - _ => panic!( - "invalid literal for float() with base 10: '{}'", - self.to_string() - ), + _ => panic!("invalid literal for float() with base 10: '{self}'"), } } @@ -264,7 +247,7 @@ impl ValueRef { } pub fn filter(&self, filter: fn(&ValueRef, &ValueRef) -> bool) -> ValueRef { - match &*self.rc { + match &*self.rc.borrow() { Value::str_value(ref s) => { if s.is_empty() { panic!("arg is an empty str"); @@ -299,14 +282,11 @@ impl ValueRef { let keys: Vec = dict.values.keys().map(|s| (*s).clone()).collect(); let mut result = keys.first().unwrap(); for key in keys.iter() { - if filter( - &ValueRef::str(&key.to_string()), - &ValueRef::str(&result.to_string()), - ) { + if filter(&ValueRef::str(key), &ValueRef::str(result)) { result = key; } } - ValueRef::str(&result.to_string()) + ValueRef::str(result) } Value::schema_value(ref schema) => { if schema.config.values.is_empty() { @@ -315,21 +295,18 @@ impl ValueRef { let keys: Vec = schema.config.values.keys().map(|s| (*s).clone()).collect(); let mut result = keys.first().unwrap(); for key in keys.iter() { - if filter( - &ValueRef::str(&key.to_string()), - &ValueRef::str(&result.to_string()), - ) { + if filter(&ValueRef::str(key), &ValueRef::str(result)) { result = key; } } - ValueRef::str(&result.to_string()) + ValueRef::str(result) } _ => panic!("{} object is not iterable", self.type_str()), } } pub fn hex(&self) -> ValueRef { - match &*self.rc { + match &*self.rc.borrow() { Value::int_value(val) => { if *val == i64::MIN { ValueRef::str("-0x8000000000000000") @@ -344,7 +321,7 @@ impl ValueRef { } pub fn oct(&self) -> ValueRef { - match &*self.rc { + match &*self.rc.borrow() { Value::int_value(val) => { if *val == i64::MIN { ValueRef::str("-01000000000000000000000") @@ -359,7 +336,7 @@ impl ValueRef { } pub fn bin(&self) -> ValueRef { - match &*self.rc { + match &*self.rc.borrow() { Value::int_value(val) => { if *val == i64::MIN { ValueRef::str( @@ -375,16 +352,16 @@ impl ValueRef { } } - pub fn sum(&self, init_value: &ValueRef) -> ValueRef { - match &*self.rc { + pub fn sum(&self, ctx: &mut Context, init_value: &ValueRef) -> ValueRef { + match &*self.rc.borrow() { Value::list_value(list) => { - let mut result = match &*init_value.rc { + let mut result = match &*init_value.rc.borrow() { Value::str_value(_str) => panic!("sum() can't sum strings"), _ => init_value.clone(), }; for val in list.values.iter() { //xx_bin_aug_add() might modify the value of init_value - result = result.bin_add(val) + result = result.bin_add(ctx, val) } result } @@ -393,7 +370,7 @@ impl ValueRef { } pub fn abs(&self) -> ValueRef { - match &*self.rc { + match &*self.rc.borrow() { Value::int_value(val) => ValueRef::int(val.abs()), Value::float_value(val) => ValueRef::float(val.abs()), _ => ValueRef::undefined(), @@ -401,7 +378,7 @@ impl ValueRef { } pub fn ord(&self) -> ValueRef { - match &*self.rc { + match &*self.rc.borrow() { Value::str_value(str) => { let string_len = str.chars().count(); if string_len != 1 { @@ -418,7 +395,7 @@ impl ValueRef { } pub fn zip(&self) -> ValueRef { - match &*self.rc { + match &*self.rc.borrow() { Value::list_value(list) => { let mut iters = Vec::new(); for val in list.values.iter() { @@ -465,18 +442,18 @@ pub fn list(iterable: Option<&ValueRef>) -> ValueRef { } } -pub fn dict(iterable: Option<&ValueRef>) -> ValueRef { +pub fn dict(ctx: &mut Context, iterable: Option<&ValueRef>) -> ValueRef { match iterable { Some(val) => { let mut iter = val.iter(); let mut result = ValueRef::dict(None); while !iter.is_end() { iter.next(val); - let elem = &iter.cur_val.clone(); - let k = &iter.cur_key.clone(); - match &*k.rc { + let elem = iter.cur_val.clone(); + let k = iter.cur_key.clone(); + match &*k.rc.borrow() { Value::str_value(str) => { - result.dict_insert(str.as_str(), elem, Default::default(), 0); + result.dict_insert(ctx, str.as_str(), &elem, Default::default(), None); } _ => { let mut elem_iter = elem.iter(); @@ -485,9 +462,9 @@ pub fn dict(iterable: Option<&ValueRef>) -> ValueRef { } let k = elem_iter.next(val).unwrap().to_string(); let v = elem_iter.next(val).unwrap(); - result.dict_insert(k.as_str(), v, Default::default(), 0); + result.dict_insert(ctx, k.as_str(), v, Default::default(), None); } - } + }; } result } @@ -496,7 +473,7 @@ pub fn dict(iterable: Option<&ValueRef>) -> ValueRef { } pub fn range(start: &ValueRef, stop: &ValueRef, step: &ValueRef) -> ValueRef { - match (&*start.rc, &*stop.rc, &*step.rc) { + match (&*start.rc.borrow(), &*stop.rc.borrow(), &*step.rc.borrow()) { (Value::int_value(start), Value::int_value(stop), Value::int_value(step)) => { if *step == 0 { panic!("range() step argument must not be zero"); @@ -520,19 +497,19 @@ pub fn range(start: &ValueRef, stop: &ValueRef, step: &ValueRef) -> ValueRef { /// Check if the modular result of a and b is 0 pub fn multiplyof(a: &ValueRef, b: &ValueRef) -> ValueRef { - match (&*a.rc, &*b.rc) { + match (&*a.rc.borrow(), &*b.rc.borrow()) { (Value::int_value(a), Value::int_value(b)) => ValueRef::bool(a % b == 0), _ => ValueRef::undefined(), } } pub fn pow(x: &ValueRef, y: &ValueRef, z: &ValueRef) -> ValueRef { - match &*z.rc { + match &*z.rc.borrow() { Value::int_value(z) => { if *z == 0 { panic!("pow() 3rd argument cannot be 0") } - match (&*x.rc, &*y.rc) { + match (&*x.rc.borrow(), &*y.rc.borrow()) { (Value::int_value(x), Value::int_value(y)) => match (*y).cmp(&0) { std::cmp::Ordering::Equal => ValueRef::int(1), std::cmp::Ordering::Greater => { @@ -556,7 +533,7 @@ pub fn pow(x: &ValueRef, y: &ValueRef, z: &ValueRef) -> ValueRef { _ => panic!("pow() 3rd argument not allowed unless all arguments are integers"), } } - _ => match (&*x.rc, &*y.rc) { + _ => match (&*x.rc.borrow(), &*y.rc.borrow()) { (Value::int_value(x), Value::int_value(y)) => { if *y >= 0 { ValueRef::int((*x as f64).powf(*y as f64) as i64) @@ -573,8 +550,8 @@ pub fn pow(x: &ValueRef, y: &ValueRef, z: &ValueRef) -> ValueRef { } pub fn round(number: &ValueRef, ndigits: &ValueRef) -> ValueRef { - match &*ndigits.rc { - Value::int_value(ndigits) => match &*number.rc { + match &*ndigits.rc.borrow() { + Value::int_value(ndigits) => match &*number.rc.borrow() { Value::int_value(number) => ValueRef::float(*number as f64), Value::float_value(number) => { if *ndigits == 0 { @@ -620,7 +597,7 @@ pub fn round(number: &ValueRef, ndigits: &ValueRef) -> ValueRef { } _ => ValueRef::undefined(), }, - _ => match &*number.rc { + _ => match &*number.rc.borrow() { Value::int_value(number) => ValueRef::int(*number), Value::float_value(number) => ValueRef::int(number.round() as i64), _ => ValueRef::undefined(), @@ -639,10 +616,10 @@ pub fn type_of(x: &ValueRef, full_name: &ValueRef) -> ValueRef { }; let mut result = String::new(); if full_type_str != MAIN_PKG_PATH { - result += &full_type_str.to_string(); + result += full_type_str; result += "."; } - result += &x.type_str(); + result += &schema.name; return ValueRef::str(result.as_str()); } } else if x.is_none() { @@ -674,7 +651,7 @@ mod test_builtin { builtin::pow(&ValueRef::int(2), &ValueRef::int(3), &ValueRef::int(5)).as_int() ); assert_eq!( - (2.0 as f64).powf(0.5), + (2.0_f64).powf(0.5), builtin::pow(&ValueRef::int(2), &ValueRef::float(0.5), &ValueRef::none()).as_float() ); assert_eq!( diff --git a/kclvm/runtime/src/stdlib/builtin_api.rs b/kclvm/runtime/src/stdlib/builtin_api.rs index 212c415e2..d7c4dae60 100644 --- a/kclvm/runtime/src/stdlib/builtin_api.rs +++ b/kclvm/runtime/src/stdlib/builtin_api.rs @@ -1,4 +1,7 @@ -// Copyright 2021 The KCL Authors. All rights reserved. +//! Copyright The KCL Authors. All rights reserved. +#![allow(clippy::missing_safety_doc)] + +use std::os::raw::c_char; use crate::*; @@ -7,10 +10,10 @@ type kclvm_value_ref_t = ValueRef; #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_builtin_option_init( +pub unsafe extern "C" fn kclvm_builtin_option_init( ctx: *mut kclvm_context_t, - key: *const i8, - value: *const i8, + key: *const c_char, + value: *const c_char, ) { let ctx = mut_ptr_as_ref(ctx); ctx.builtin_option_init(c2str(key), c2str(value)); @@ -18,22 +21,22 @@ pub extern "C" fn kclvm_builtin_option_init( #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_builtin_option_reset( +pub unsafe extern "C" fn kclvm_builtin_option_reset( ctx: *mut kclvm_context_t, _args: *const kclvm_value_ref_t, _kwargs: *const kclvm_value_ref_t, ) -> *mut kclvm_value_ref_t { - let ctx = mut_ptr_as_ref(ctx); + let ctx_ref = mut_ptr_as_ref(ctx); - ctx.builtin_option_reset(); - kclvm_value_Undefined() + ctx_ref.builtin_option_reset(); + kclvm_value_Undefined(ctx) } // def kcl_option(name: str, *, type="", required=False, default=None, help="", file="", line=0) -> typing.Any: #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_builtin_option( +pub unsafe extern "C" fn kclvm_builtin_option( ctx: *mut kclvm_context_t, args: *const kclvm_value_ref_t, kwargs: *const kclvm_value_ref_t, @@ -42,36 +45,12 @@ pub extern "C" fn kclvm_builtin_option( let args = ptr_as_ref(args); let kwargs = ptr_as_ref(kwargs); - let mut list_option_mode = false; - - if ctx.cfg.list_option_mode { - list_option_mode = true; - - let name = args.arg_i_str(0, Some("?".to_string())).unwrap(); - let typ = kwargs.kwarg_str("type", Some("".to_string())).unwrap(); - let required = kwargs.kwarg_bool("required", Some(false)).unwrap(); - let help = kwargs.kwarg_str("help", Some("".to_string())).unwrap(); - - let mut default_value: Option = None; - if let Some(x) = kwargs.kwarg("default") { - default_value = Some(x.to_string()); - } - - ctx.define_option( - name.as_str(), - typ.as_str(), - required, - default_value, - help.as_str(), - ); - } - - fn _value_to_type(this: &ValueRef, typ: String, list_option_mode: bool) -> ValueRef { + fn _value_to_type(this: &ValueRef, typ: String) -> ValueRef { if typ.is_empty() { return this.clone(); } if typ == "bool" { - match *this.rc { + match *this.rc.borrow() { Value::bool_value(ref v) => { return ValueRef::bool(*v); } @@ -90,7 +69,7 @@ pub extern "C" fn kclvm_builtin_option( } } if typ == "int" { - match *this.rc { + match *this.rc.borrow() { Value::bool_value(ref v) => { if *v { return ValueRef::int(1); @@ -107,20 +86,17 @@ pub extern "C" fn kclvm_builtin_option( Value::str_value(ref v) => { match v.parse::() { Ok(n) => return ValueRef::int(n), - _ => panic!("cannot use '{}' as type '{}'", v, typ), + _ => panic!("cannot use '{v}' as type '{typ}'"), }; } _ => { - if list_option_mode { - return ValueRef::none(); - } - let err_msg = format!("cannot use '{}' as type '{}'", this.to_string(), typ); + let err_msg = format!("cannot use '{this}' as type '{typ}'"); panic!("{}", err_msg); } } } if typ == "float" { - match *this.rc { + match *this.rc.borrow() { Value::bool_value(ref v) => { if *v { return ValueRef::float(1.0); @@ -141,16 +117,13 @@ pub extern "C" fn kclvm_builtin_option( }; } _ => { - if list_option_mode { - return ValueRef::none(); - } - let err_msg = format!("cannot use '{}' as type '{}'", this.to_string(), typ); + let err_msg = format!("cannot use '{this}' as type '{typ}'"); panic!("{}", err_msg); } } } if typ == "str" { - match *this.rc { + match *this.rc.borrow() { Value::bool_value(ref v) => { let s = format!("{}", *v); return ValueRef::str(s.as_ref()); @@ -167,297 +140,270 @@ pub extern "C" fn kclvm_builtin_option( return ValueRef::str(v.as_ref()); } _ => { - if list_option_mode { - return ValueRef::none(); - } - let err_msg = format!("cannot use '{}' as type '{}'", this.to_string(), typ); + let err_msg = format!("cannot use '{this}' as type '{typ}'"); panic!("{}", err_msg); } } } if typ == "list" { - match *this.rc { + match *this.rc.borrow() { Value::list_value(_) => { return this.clone(); } _ => { - if list_option_mode { - return ValueRef::none(); - } - let err_msg = format!("cannot use '{}' as type '{}'", this.to_string(), typ); + let err_msg = format!("cannot use '{this}' as type '{typ}'"); panic!("{}", err_msg); } } } if typ == "dict" { - match *this.rc { + match *this.rc.borrow() { Value::dict_value(_) => { return this.clone(); } _ => { - if list_option_mode { - return ValueRef::none(); - } - let err_msg = format!("cannot use '{}' as type '{}'", this.to_string(), typ); + let err_msg = format!("cannot use '{this}' as type '{typ}'"); panic!("{}", err_msg); } } } - if list_option_mode { - return ValueRef::none(); - } - - panic!("unknonwn type '{}'", typ); + panic!("unknown type '{typ}'"); } - if let Some(arg0) = args.arg_0() { - if let Some(x) = ctx.app_args.get(&arg0.as_str()) { - if *x == 0 { - return kclvm_value_Undefined(); - } - - let opt_value = mut_ptr_as_ref((*x) as *mut kclvm_value_ref_t); - - if let Some(kwarg_type) = kwargs.kwarg_str("type", None) { - return _value_to_type(opt_value, kwarg_type, ctx.cfg.list_option_mode).into_raw(); + if let Some(arg0) = get_call_arg_str(args, kwargs, 0, Some("key")) { + if let Some(x) = ctx.option_values.get(&arg0) { + if let Some(kwarg_type) = get_call_arg_str(args, kwargs, 1, Some("type")) { + return _value_to_type(x, kwarg_type).into_raw(ctx); } - - return (*x) as *mut kclvm_value_ref_t; - } else if let Some(kwarg_default) = kwargs.kwarg("default") { - if let Some(kwarg_type) = kwargs.kwarg_str("type", None) { - return _value_to_type(kwarg_default, kwarg_type, ctx.cfg.list_option_mode) - .into_raw(); + return x.clone().into_raw(ctx); + } else if let Some(kwarg_default) = get_call_arg(args, kwargs, 3, Some("default")) { + if let Some(kwarg_type) = get_call_arg_str(args, kwargs, 1, Some("type")) { + return _value_to_type(&kwarg_default, kwarg_type).into_raw(ctx); } - - return kwarg_default.clone().into_raw(); + return kwarg_default.into_raw(ctx); } } - - if list_option_mode { - return kclvm_value_None(); - } - - let required = kwargs.kwarg_bool("required", Some(false)).unwrap(); + let required = get_call_arg_bool(args, kwargs, 2, Some("required")).unwrap_or_default(); if required { - let name = args.arg_i_str(0, Some("?".to_string())).unwrap(); - panic!( - "option('{}') must be initialized, try '-D {}=?' argument", - name, name - ); + let name = + get_call_arg_str(args, kwargs, 0, Some("key")).unwrap_or_else(|| "?".to_string()); + panic!("option('{name}') must be initialized, try '-D {name}=?' argument"); } - - kclvm_value_None() + ValueRef::none().into_raw(ctx) } #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_builtin_print( +pub unsafe extern "C" fn kclvm_builtin_print( ctx: *mut kclvm_context_t, args: *const kclvm_value_ref_t, kwargs: *const kclvm_value_ref_t, ) -> *mut kclvm_value_ref_t { - let _ctx = mut_ptr_as_ref(ctx); let args = ptr_as_ref(args); let kwargs = ptr_as_ref(kwargs); + let ctx_ref = mut_ptr_as_ref(ctx); // args let list = args.as_list_ref(); let values: Vec = list.values.iter().map(|v| v.to_string()).collect(); - print!("{}", values.join(" ")); + ctx_ref.log_message.push_str(&values.join(" ")); let dict = kwargs.as_dict_ref(); // kwargs: end if let Some(c) = dict.values.get("end") { - print!("{}", c.to_string()); - use std::io::Write; - let _ = std::io::stdout().flush(); + ctx_ref.log_message.push_str(&format!("{c}")); } else { - println!(); + ctx_ref.log_message.push('\n'); } - kclvm_value_None() + kclvm_value_None(ctx) } #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_builtin_len( - _ctx: *mut kclvm_context_t, +pub unsafe extern "C" fn kclvm_builtin_len( + ctx: *mut kclvm_context_t, args: *const kclvm_value_ref_t, - _kwargs: *const kclvm_value_ref_t, + kwargs: *const kclvm_value_ref_t, ) -> *mut kclvm_value_ref_t { let args = ptr_as_ref(args); + let kwargs = ptr_as_ref(kwargs); - if let Some(arg) = args.arg_0() { - return kclvm_value_Int(arg.len() as i64); + if let Some(arg) = get_call_arg(args, kwargs, 0, Some("inval")) { + return kclvm_value_Int(ctx, arg.len() as i64); } panic!("len() takes exactly one argument (0 given)"); } #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_builtin_any_true( +pub unsafe extern "C" fn kclvm_builtin_any_true( ctx: *mut kclvm_context_t, args: *const kclvm_value_ref_t, kwargs: *const kclvm_value_ref_t, ) -> *mut kclvm_value_ref_t { - let _ctx = mut_ptr_as_ref(ctx); let args = ptr_as_ref(args); - let _kwargs = ptr_as_ref(kwargs); + let kwargs = ptr_as_ref(kwargs); - if let Some(arg0) = args.arg_0() { - return kclvm_value_Bool(arg0.any_true() as i8); + if let Some(arg0) = get_call_arg(args, kwargs, 0, Some("inval")) { + return kclvm_value_Bool(ctx, arg0.any_true() as i8); } - kclvm_value_Bool(0) + kclvm_value_Bool(ctx, 0) } #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_builtin_isunique( +pub unsafe extern "C" fn kclvm_builtin_isunique( ctx: *mut kclvm_context_t, args: *const kclvm_value_ref_t, kwargs: *const kclvm_value_ref_t, ) -> *mut kclvm_value_ref_t { - let _ctx = mut_ptr_as_ref(ctx); let args = ptr_as_ref(args); - let _kwargs = ptr_as_ref(kwargs); + let kwargs = ptr_as_ref(kwargs); - if let Some(arg0) = args.arg_0() { - return kclvm_value_Bool(arg0.isunique() as i8); + if let Some(arg0) = get_call_arg(args, kwargs, 0, Some("inval")) { + return kclvm_value_Bool(ctx, arg0.isunique() as i8); } - kclvm_value_Bool(0) + kclvm_value_Bool(ctx, 0) } #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_builtin_sorted( +pub unsafe extern "C" fn kclvm_builtin_sorted( ctx: *mut kclvm_context_t, args: *const kclvm_value_ref_t, kwargs: *const kclvm_value_ref_t, ) -> *mut kclvm_value_ref_t { - let _ctx = mut_ptr_as_ref(ctx); + let ctx = mut_ptr_as_ref(ctx); let args = ptr_as_ref(args); let kwargs = ptr_as_ref(kwargs); - if let Some(arg0) = args.arg_0() { - let reverse = kwargs.kwarg("reverse"); - return arg0.sorted(reverse).into_raw(); + if let Some(arg0) = get_call_arg(args, kwargs, 0, Some("inval")) { + let reverse = get_call_arg(args, kwargs, 1, Some("reverse")); + return arg0.sorted(reverse.as_ref()).into_raw(ctx); } panic!("sorted() takes exactly one argument (0 given)"); } #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_builtin_int( +pub unsafe extern "C" fn kclvm_builtin_int( ctx: *mut kclvm_context_t, args: *const kclvm_value_ref_t, kwargs: *const kclvm_value_ref_t, ) -> *mut kclvm_value_ref_t { - let _ctx = mut_ptr_as_ref(ctx); + let ctx = mut_ptr_as_ref(ctx); let args = ptr_as_ref(args); let kwargs = ptr_as_ref(kwargs); - if let Some(arg0) = args.arg_0() { - let base = args.arg_i(1).or_else(|| kwargs.kwarg("base")); - return arg0.convert_to_int(base).into_raw(); + if let Some(arg0) = get_call_arg(args, kwargs, 0, Some("number")) { + let base = get_call_arg(args, kwargs, 1, Some("base")); + return arg0.convert_to_int(ctx, base.as_ref()).into_raw(ctx); } panic!("int() takes exactly one argument (0 given)"); } #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_builtin_float( +pub unsafe extern "C" fn kclvm_builtin_float( ctx: *mut kclvm_context_t, args: *const kclvm_value_ref_t, kwargs: *const kclvm_value_ref_t, ) -> *mut kclvm_value_ref_t { - let _ctx = mut_ptr_as_ref(ctx); + let ctx = mut_ptr_as_ref(ctx); let args = ptr_as_ref(args); - let _kwargs = ptr_as_ref(kwargs); + let kwargs = ptr_as_ref(kwargs); - if let Some(arg0) = args.arg_0() { - return arg0.convert_to_float().into_raw(); + if let Some(arg0) = get_call_arg(args, kwargs, 0, Some("number")) { + return arg0.convert_to_float(ctx).into_raw(ctx); } panic!("float() takes exactly one argument (0 given)"); } #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_builtin_bool( - _ctx: *mut kclvm_context_t, +pub unsafe extern "C" fn kclvm_builtin_bool( + ctx: *mut kclvm_context_t, args: *const kclvm_value_ref_t, - _kwargs: *const kclvm_value_ref_t, + kwargs: *const kclvm_value_ref_t, ) -> *const kclvm_value_ref_t { + let ctx = mut_ptr_as_ref(ctx); let args = ptr_as_ref(args); + let kwargs = ptr_as_ref(kwargs); - if let Some(arg0) = args.arg_0() { - return ValueRef::bool(arg0.is_truthy()).into_raw(); + if let Some(arg0) = get_call_arg(args, kwargs, 0, Some("x")) { + return ValueRef::bool(arg0.is_truthy()).into_raw(ctx); } panic!("bool() takes exactly one argument (0 given)"); } #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_builtin_str( - _ctx: *mut kclvm_context_t, +pub unsafe extern "C" fn kclvm_builtin_str( + ctx: *mut kclvm_context_t, args: *const kclvm_value_ref_t, - _kwargs: *const kclvm_value_ref_t, + kwargs: *const kclvm_value_ref_t, ) -> *const kclvm_value_ref_t { + let ctx = mut_ptr_as_ref(ctx); let args = ptr_as_ref(args); + let kwargs = ptr_as_ref(kwargs); - if let Some(arg0) = args.arg_0() { - return ValueRef::str(&arg0.to_string()).into_raw(); + if let Some(arg0) = get_call_arg(args, kwargs, 0, Some("x")) { + return ValueRef::str(&arg0.to_string()).into_raw(ctx); } - ValueRef::str("").into_raw() + ValueRef::str("").into_raw(ctx) } #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_builtin_max( +pub unsafe extern "C" fn kclvm_builtin_max( ctx: *mut kclvm_context_t, args: *const kclvm_value_ref_t, - kwargs: *const kclvm_value_ref_t, + _kwargs: *const kclvm_value_ref_t, ) -> *mut kclvm_value_ref_t { - let _ctx = mut_ptr_as_ref(ctx); + let ctx = mut_ptr_as_ref(ctx); let args = ptr_as_ref(args); - let _kwargs = ptr_as_ref(kwargs); if args.args_len() > 1 { - return args.max_value().into_raw(); + return args.max_value().into_raw(ctx); } if let Some(arg0) = args.arg_0() { - return arg0.max_value().into_raw(); + return arg0.max_value().into_raw(ctx); } panic!("max() takes exactly one argument (0 given)"); } #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_builtin_min( +pub unsafe extern "C" fn kclvm_builtin_min( ctx: *mut kclvm_context_t, args: *const kclvm_value_ref_t, - kwargs: *const kclvm_value_ref_t, + _kwargs: *const kclvm_value_ref_t, ) -> *mut kclvm_value_ref_t { - let _ctx = mut_ptr_as_ref(ctx); + let ctx = mut_ptr_as_ref(ctx); let args = ptr_as_ref(args); - let _kwargs = ptr_as_ref(kwargs); if args.args_len() > 1 { - return args.min_value().into_raw(); + return args.min_value().into_raw(ctx); } if let Some(arg0) = args.arg_0() { - return arg0.min_value().into_raw(); + return arg0.min_value().into_raw(ctx); } panic!("min() takes exactly one argument (0 given)"); } #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_builtin_multiplyof( +pub unsafe extern "C" fn kclvm_builtin_multiplyof( ctx: *mut kclvm_context_t, args: *const kclvm_value_ref_t, kwargs: *const kclvm_value_ref_t, ) -> *const kclvm_value_ref_t { - let _ctx = mut_ptr_as_ref(ctx); + let ctx = mut_ptr_as_ref(ctx); let args = ptr_as_ref(args); - let _kwargs = ptr_as_ref(kwargs); - if let (Some(arg0), Some(arg1)) = (args.arg_i(0), args.arg_i(1)) { - return builtin::multiplyof(arg0, arg1).into_raw(); + let kwargs = ptr_as_ref(kwargs); + + if let (Some(arg0), Some(arg1)) = ( + get_call_arg(args, kwargs, 0, Some("a")), + get_call_arg(args, kwargs, 1, Some("b")), + ) { + return builtin::multiplyof(&arg0, &arg1).into_raw(ctx); } panic!( "multiplyof() takes exactly two argument ({} given)", @@ -467,175 +413,186 @@ pub extern "C" fn kclvm_builtin_multiplyof( #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_builtin_abs( +pub unsafe extern "C" fn kclvm_builtin_abs( ctx: *mut kclvm_context_t, args: *const kclvm_value_ref_t, kwargs: *const kclvm_value_ref_t, ) -> *const kclvm_value_ref_t { - let _ctx = mut_ptr_as_ref(ctx); + let ctx = mut_ptr_as_ref(ctx); let args = ptr_as_ref(args); - let _kwargs = ptr_as_ref(kwargs); - if let Some(arg0) = args.arg_0() { - return arg0.abs().into_raw(); + let kwargs = ptr_as_ref(kwargs); + + if let Some(arg0) = get_call_arg(args, kwargs, 0, Some("inval")) { + return arg0.abs().into_raw(ctx); } panic!("abs() takes exactly one argument (0 given)"); } #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_builtin_all_true( +pub unsafe extern "C" fn kclvm_builtin_all_true( ctx: *mut kclvm_context_t, args: *const kclvm_value_ref_t, kwargs: *const kclvm_value_ref_t, ) -> *const kclvm_value_ref_t { - let _ctx = mut_ptr_as_ref(ctx); let args = ptr_as_ref(args); - let _kwargs = ptr_as_ref(kwargs); - if let Some(arg0) = args.arg_0() { - return kclvm_value_Bool(arg0.all_true() as i8); + let kwargs = ptr_as_ref(kwargs); + + if let Some(arg0) = get_call_arg(args, kwargs, 0, Some("inval")) { + return kclvm_value_Bool(ctx, arg0.all_true() as i8); } - kclvm_value_Bool(0) + kclvm_value_Bool(ctx, 0) } #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_builtin_hex( +pub unsafe extern "C" fn kclvm_builtin_hex( ctx: *mut kclvm_context_t, args: *const kclvm_value_ref_t, kwargs: *const kclvm_value_ref_t, ) -> *const kclvm_value_ref_t { - let _ctx = mut_ptr_as_ref(ctx); + let ctx = mut_ptr_as_ref(ctx); let args = ptr_as_ref(args); - let _kwargs = ptr_as_ref(kwargs); - if let Some(arg0) = args.arg_0() { - return arg0.hex().into_raw(); + let kwargs = ptr_as_ref(kwargs); + + if let Some(arg0) = get_call_arg(args, kwargs, 0, Some("number")) { + return arg0.hex().into_raw(ctx); } panic!("hex() takes exactly one argument (0 given)"); } #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_builtin_sum( +pub unsafe extern "C" fn kclvm_builtin_sum( ctx: *mut kclvm_context_t, args: *const kclvm_value_ref_t, kwargs: *const kclvm_value_ref_t, ) -> *const kclvm_value_ref_t { - let _ctx = mut_ptr_as_ref(ctx); + let ctx_ref = mut_ptr_as_ref(ctx); let args = ptr_as_ref(args); - let _kwargs = ptr_as_ref(kwargs); - match args.arg_i(0) { - Some(arg0) => match args.arg_i(1) { - Some(arg1) => arg0.sum(arg1).into_raw(), - _ => arg0.sum(&ValueRef::int(0)).into_raw(), + let kwargs = ptr_as_ref(kwargs); + + match get_call_arg(args, kwargs, 0, Some("iterable")) { + Some(arg0) => match get_call_arg(args, kwargs, 1, Some("start")) { + Some(arg1) => arg0.sum(ctx_ref, &arg1).into_raw(ctx_ref), + _ => arg0.sum(ctx_ref, &ValueRef::int(0)).into_raw(ctx_ref), }, - _ => kclvm_value_Undefined(), + _ => kclvm_value_Undefined(ctx), } } #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_builtin_pow( +pub unsafe extern "C" fn kclvm_builtin_pow( ctx: *mut kclvm_context_t, args: *const kclvm_value_ref_t, kwargs: *const kclvm_value_ref_t, ) -> *const kclvm_value_ref_t { - let _ctx = mut_ptr_as_ref(ctx); + let ctx_ref = mut_ptr_as_ref(ctx); let args = ptr_as_ref(args); - let _kwargs = ptr_as_ref(kwargs); - match (args.arg_i(0), args.arg_i(1)) { - (Some(arg0), Some(arg1)) => match args.arg_i(2) { - Some(arg2) => builtin::pow(arg0, arg1, arg2).into_raw(), - _ => builtin::pow(arg0, arg1, &ValueRef::none()).into_raw(), + let kwargs = ptr_as_ref(kwargs); + + match ( + get_call_arg(args, kwargs, 0, Some("x")), + get_call_arg(args, kwargs, 1, Some("y")), + ) { + (Some(arg0), Some(arg1)) => match get_call_arg(args, kwargs, 2, Some("z")) { + Some(arg2) => builtin::pow(&arg0, &arg1, &arg2).into_raw(ctx_ref), + _ => builtin::pow(&arg0, &arg1, &ValueRef::none()).into_raw(ctx_ref), }, - _ => kclvm_value_Undefined(), + _ => kclvm_value_Undefined(ctx), } } #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_builtin_round( +pub unsafe extern "C" fn kclvm_builtin_round( ctx: *mut kclvm_context_t, args: *const kclvm_value_ref_t, kwargs: *const kclvm_value_ref_t, ) -> *const kclvm_value_ref_t { - let _ctx = mut_ptr_as_ref(ctx); + let ctx_ref = mut_ptr_as_ref(ctx); let args = ptr_as_ref(args); - let _kwargs = ptr_as_ref(kwargs); - match args.arg_i(0) { - Some(arg0) => match args.arg_i(1) { - Some(arg1) => builtin::round(arg0, arg1).into_raw(), - _ => builtin::round(arg0, &ValueRef::none()).into_raw(), + let kwargs = ptr_as_ref(kwargs); + + match get_call_arg(args, kwargs, 0, Some("number")) { + Some(arg0) => match get_call_arg(args, kwargs, 1, Some("ndigits")) { + Some(arg1) => builtin::round(&arg0, &arg1).into_raw(ctx_ref), + _ => builtin::round(&arg0, &ValueRef::none()).into_raw(ctx_ref), }, - _ => kclvm_value_Undefined(), + _ => kclvm_value_Undefined(ctx), } } #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_builtin_zip( +pub unsafe extern "C" fn kclvm_builtin_zip( ctx: *mut kclvm_context_t, args: *const kclvm_value_ref_t, - kwargs: *const kclvm_value_ref_t, + _kwargs: *const kclvm_value_ref_t, ) -> *const kclvm_value_ref_t { - let _ctx = mut_ptr_as_ref(ctx); + let ctx = mut_ptr_as_ref(ctx); let args = ptr_as_ref(args); - let _kwargs = ptr_as_ref(kwargs); - args.zip().into_raw() + args.zip().into_raw(ctx) } #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_builtin_list( +pub unsafe extern "C" fn kclvm_builtin_list( ctx: *mut kclvm_context_t, args: *const kclvm_value_ref_t, kwargs: *const kclvm_value_ref_t, ) -> *const kclvm_value_ref_t { - let _ctx = mut_ptr_as_ref(ctx); + let ctx = mut_ptr_as_ref(ctx); let args = ptr_as_ref(args); - let _kwargs = ptr_as_ref(kwargs); + let kwargs = ptr_as_ref(kwargs); + if args.args_len() > 0 { - if let Some(arg0) = args.arg_0() { - return builtin::list(Some(arg0)).into_raw(); + if let Some(arg0) = get_call_arg(args, kwargs, 0, Some("x")) { + return builtin::list(Some(&arg0)).into_raw(ctx); } panic!("invalid arguments in list() function"); } else { - builtin::list(None).into_raw() + builtin::list(None).into_raw(ctx) } } #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_builtin_dict( +pub unsafe extern "C" fn kclvm_builtin_dict( ctx: *mut kclvm_context_t, args: *const kclvm_value_ref_t, kwargs: *const kclvm_value_ref_t, ) -> *const kclvm_value_ref_t { - let _ctx = mut_ptr_as_ref(ctx); + let ctx = mut_ptr_as_ref(ctx); let args = ptr_as_ref(args); let kwargs = ptr_as_ref(kwargs); let mut dict = ValueRef::dict(None); - if let Some(arg0) = args.arg_0() { - dict.dict_insert_unpack(&builtin::dict(Some(arg0))); + if let Some(arg0) = get_call_arg(args, kwargs, 0, Some("x")) { + let v = builtin::dict(ctx, Some(&arg0)); + dict.dict_insert_unpack(ctx, &v); } - dict.dict_insert_unpack(&builtin::dict(Some(kwargs))); - dict.into_raw() + let v = builtin::dict(ctx, Some(kwargs)); + dict.dict_insert_unpack(ctx, &v); + dict.into_raw(ctx) } #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_builtin_typeof( +pub unsafe extern "C" fn kclvm_builtin_typeof( ctx: *mut kclvm_context_t, args: *const kclvm_value_ref_t, kwargs: *const kclvm_value_ref_t, ) -> *const kclvm_value_ref_t { - let _ctx = mut_ptr_as_ref(ctx); + let ctx = mut_ptr_as_ref(ctx); let args = ptr_as_ref(args); let kwargs = ptr_as_ref(kwargs); - if let Some(arg0) = args.arg_0() { - if let Some(full_name) = kwargs.kwarg("full_name") { - return builtin::type_of(arg0, full_name).into_raw(); + + if let Some(arg0) = get_call_arg(args, kwargs, 0, Some("x")) { + if let Some(full_name) = get_call_arg(args, kwargs, 1, Some("full_name")) { + return builtin::type_of(&arg0, &full_name).into_raw(ctx); } - return builtin::type_of(arg0, &ValueRef::bool(false)).into_raw(); + return builtin::type_of(&arg0, &ValueRef::bool(false)).into_raw(ctx); } panic!("typeof() missing 1 required positional argument: 'x'"); @@ -643,73 +600,92 @@ pub extern "C" fn kclvm_builtin_typeof( #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_builtin_bin( +pub unsafe extern "C" fn kclvm_builtin_bin( ctx: *mut kclvm_context_t, args: *const kclvm_value_ref_t, kwargs: *const kclvm_value_ref_t, ) -> *const kclvm_value_ref_t { - let _ctx = mut_ptr_as_ref(ctx); + let ctx = mut_ptr_as_ref(ctx); let args = ptr_as_ref(args); - let _kwargs = ptr_as_ref(kwargs); - if let Some(arg0) = args.arg_0() { - return arg0.bin().into_raw(); + let kwargs = ptr_as_ref(kwargs); + + if let Some(arg0) = get_call_arg(args, kwargs, 0, Some("number")) { + return arg0.bin().into_raw(ctx); } panic!("bin() takes exactly one argument (0 given)"); } #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_builtin_oct( +pub unsafe extern "C" fn kclvm_builtin_oct( ctx: *mut kclvm_context_t, args: *const kclvm_value_ref_t, kwargs: *const kclvm_value_ref_t, ) -> *const kclvm_value_ref_t { - let _ctx = mut_ptr_as_ref(ctx); + let ctx = mut_ptr_as_ref(ctx); let args = ptr_as_ref(args); - let _kwargs = ptr_as_ref(kwargs); - if let Some(arg0) = args.arg_0() { - return arg0.oct().into_raw(); + let kwargs = ptr_as_ref(kwargs); + + if let Some(arg0) = get_call_arg(args, kwargs, 0, Some("number")) { + return arg0.oct().into_raw(ctx); } panic!("oct() takes exactly one argument (0 given)"); } #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_builtin_ord( +pub unsafe extern "C" fn kclvm_builtin_ord( ctx: *mut kclvm_context_t, args: *const kclvm_value_ref_t, kwargs: *const kclvm_value_ref_t, ) -> *const kclvm_value_ref_t { - let _ctx = mut_ptr_as_ref(ctx); - let args = ptr_as_ref(args); - let _kwargs = ptr_as_ref(kwargs); - let _ctx = mut_ptr_as_ref(ctx); + let ctx = mut_ptr_as_ref(ctx); let args = ptr_as_ref(args); - let _kwargs = ptr_as_ref(kwargs); - if let Some(arg0) = args.arg_0() { - return arg0.ord().into_raw(); + let kwargs = ptr_as_ref(kwargs); + + if let Some(arg0) = get_call_arg(args, kwargs, 0, Some("c")) { + return arg0.ord().into_raw(ctx); } panic!("ord() takes exactly one argument (0 given)"); } #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_builtin_range( +pub unsafe extern "C" fn kclvm_builtin_range( ctx: *mut kclvm_context_t, args: *const kclvm_value_ref_t, kwargs: *const kclvm_value_ref_t, ) -> *mut kclvm_value_ref_t { - let _ctx = mut_ptr_as_ref(ctx); + let ctx_ref = mut_ptr_as_ref(ctx); let args = ptr_as_ref(args); - let _kwargs = ptr_as_ref(kwargs); - match args.arg_i(0) { - Some(arg0) => match args.arg_i(1) { - Some(arg1) => match args.arg_i(2) { - Some(arg2) => builtin::range(arg0, arg1, arg2).into_raw(), - _ => builtin::range(arg0, arg1, &ValueRef::int(1)).into_raw(), + let kwargs = ptr_as_ref(kwargs); + + match get_call_arg(args, kwargs, 0, Some("start")) { + Some(arg0) => match get_call_arg(args, kwargs, 1, Some("stop")) { + Some(arg1) => match get_call_arg(args, kwargs, 2, Some("step")) { + Some(arg2) => builtin::range(&arg0, &arg1, &arg2).into_raw(ctx_ref), + _ => builtin::range(&arg0, &arg1, &ValueRef::int(1)).into_raw(ctx_ref), }, - _ => builtin::range(&ValueRef::int(0), arg0, &ValueRef::int(1)).into_raw(), + _ => builtin::range(&ValueRef::int(0), &arg0, &ValueRef::int(1)).into_raw(ctx_ref), }, - _ => kclvm_value_Undefined(), + _ => kclvm_value_Undefined(ctx), + } +} + +/// Return `True` if the input value is `None` or `Undefined`, and `False` otherwise. +#[no_mangle] +#[runtime_fn] +pub unsafe extern "C" fn kclvm_builtin_isnullish( + ctx: *mut kclvm_context_t, + args: *const kclvm_value_ref_t, + kwargs: *const kclvm_value_ref_t, +) -> *mut kclvm_value_ref_t { + let ctx = mut_ptr_as_ref(ctx); + let args = ptr_as_ref(args); + let kwargs = ptr_as_ref(kwargs); + + if let Some(arg0) = get_call_arg(args, kwargs, 0, Some("inval")) { + return ValueRef::bool(arg0.is_none_or_undefined()).into_raw(ctx); } + panic!("is_nullable() takes exactly one argument (0 given)"); } diff --git a/kclvm/runtime/src/stdlib/debug_api.rs b/kclvm/runtime/src/stdlib/debug_api.rs deleted file mode 100644 index 3ff5dc36c..000000000 --- a/kclvm/runtime/src/stdlib/debug_api.rs +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright 2021 The KCL Authors. All rights reserved. - -use crate::*; - -#[allow(non_camel_case_types)] -type kclvm_type_t = Type; - -#[allow(non_camel_case_types)] -type kclvm_value_ref_t = ValueRef; - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_debug_hello() { - println!("kclvm_debug_hello: hello kclvm") -} - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_debug_print(cs: *const i8) { - let msg = unsafe { std::ffi::CStr::from_ptr(cs) }.to_str().unwrap(); - println!("kclvm_debug_print: {}", msg) -} - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_debug_print_str_list(len: i32, ss: &mut &mut i8) { - let x = crate::convert_double_pointer_to_vec(ss, len as usize); - println!("kclvm_debug_print_str_list: {:?}", x); -} - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_debug_print_type(p: *const kclvm_type_t) { - let p = ptr_as_ref(p); - println!("kclvm_debug_print_type: {:?}", p) -} - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_debug_print_value(p: *const kclvm_value_ref_t) { - let p = ptr_as_ref(p); - println!("kclvm_debug_print_value: {:?}", p); -} - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_debug_print_value_json_string(p: *const kclvm_value_ref_t) { - let p = ptr_as_ref(p); - println!("kclvm_debug_print_value: {}", p.to_json_string()); -} - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_debug_invoke_func(fn_ptr: extern "C" fn()) { - println!("kclvm_debug_invoke_func begin"); - fn_ptr(); - println!("kclvm_debug_invoke_func end"); -} diff --git a/kclvm/runtime/src/stdlib/mod.rs b/kclvm/runtime/src/stdlib/mod.rs index 6a1f5ba42..1b30846d6 100644 --- a/kclvm/runtime/src/stdlib/mod.rs +++ b/kclvm/runtime/src/stdlib/mod.rs @@ -1,11 +1,8 @@ -// Copyright 2021 The KCL Authors. All rights reserved. +//! Copyright The KCL Authors. All rights reserved. pub mod assert_api; pub use assert_api::*; -pub mod debug_api; -pub use debug_api::*; - pub mod builtin_api; pub use builtin_api::*; diff --git a/kclvm/runtime/src/stdlib/plugin.rs b/kclvm/runtime/src/stdlib/plugin.rs index 90ae9afb3..081e4962d 100644 --- a/kclvm/runtime/src/stdlib/plugin.rs +++ b/kclvm/runtime/src/stdlib/plugin.rs @@ -1,54 +1,83 @@ -// Copyright 2021 The KCL Authors. All rights reserved. +//! Copyright The KCL Authors. All rights reserved. + +#![allow(clippy::missing_safety_doc)] use crate::*; +use lazy_static::lazy_static; use std::os::raw::c_char; +use std::sync::Mutex; + +lazy_static! { + static ref PLUGIN_HANDLER_FN_PTR: Mutex< + Option< + extern "C" fn( + method: *const c_char, + args_json: *const c_char, + kwargs_json: *const c_char, + ) -> *const c_char, + >, + > = Mutex::new(None); +} -#[allow(non_upper_case_globals)] -static mut _plugin_handler_fn_ptr: u64 = 0; +/// KCL plugin module prefix +pub const PLUGIN_MODULE_PREFIX: &str = "kcl_plugin."; #[no_mangle] #[runtime_fn] pub extern "C" fn kclvm_plugin_init( fn_ptr: extern "C" fn( - method: *const i8, + method: *const c_char, args_json: *const c_char, kwargs_json: *const c_char, ) -> *const c_char, ) { - unsafe { - _plugin_handler_fn_ptr = fn_ptr as usize as u64; - } + let mut fn_ptr_guard = PLUGIN_HANDLER_FN_PTR.lock().unwrap(); + *fn_ptr_guard = Some(fn_ptr); } // import kcl_plugin.hello -// hello.SayHello() +// hello.say_hello() // -// => return kclvm_plugin_invoke("kcl_plugin.hello.SayHello", args, kwarge) +// => return kclvm_plugin_invoke("kcl_plugin.hello.say_hello", args, kwargs) #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_plugin_invoke( - method: *const i8, +pub unsafe extern "C" fn kclvm_plugin_invoke( + ctx: *mut kclvm_context_t, + method: *const c_char, args: *const kclvm_value_ref_t, kwargs: *const kclvm_value_ref_t, ) -> *const kclvm_value_ref_t { - let args_s = kclvm_value_to_json_value_with_null(args); - let kwargs_s = kclvm_value_to_json_value_with_null(kwargs); + let ctx_ref = mut_ptr_as_ref(ctx); + let method_ref = c2str(method); + let plugin_short_method = match method_ref.strip_prefix(PLUGIN_MODULE_PREFIX) { + Some(s) => s, + None => method_ref, + }; + if let Some(func) = ctx_ref.plugin_functions.get(plugin_short_method) { + let args = ptr_as_ref(args); + let kwargs = ptr_as_ref(kwargs); + let result = func(ctx_ref, args, kwargs); + return result.unwrap().into_raw(ctx_ref); + } + let args_s = kclvm_value_to_json_value_with_null(ctx, args); + let kwargs_s = kclvm_value_to_json_value_with_null(ctx, kwargs); let args_json = kclvm_value_Str_ptr(args_s); let kwargs_json = kclvm_value_Str_ptr(kwargs_s); let result_json = kclvm_plugin_invoke_json(method, args_json, kwargs_json); - kclvm_value_delete(args_s); - kclvm_value_delete(kwargs_s); + // Value delete by context. + // kclvm_value_delete(args_s); + // kclvm_value_delete(kwargs_s); - let ptr = kclvm_value_from_json(result_json); + let ptr = kclvm_value_from_json(ctx, result_json); { if let Some(msg) = ptr_as_ref(ptr).dict_get_value("__kcl_PanicInfo__") { - let ctx = Context::current_context_mut(); - ctx.set_err_type(&ErrType::EvaluationError_TYPE); + let ctx = mut_ptr_as_ref(ctx); + ctx.set_err_type(&RuntimeErrorType::EvaluationError); panic!("{}", msg.as_str()); } @@ -61,23 +90,15 @@ pub extern "C" fn kclvm_plugin_invoke( #[no_mangle] #[runtime_fn] pub extern "C" fn kclvm_plugin_invoke_json( - method: *const i8, + method: *const c_char, args: *const c_char, kwargs: *const c_char, ) -> *const c_char { - unsafe { - if _plugin_handler_fn_ptr == 0 { - panic!("plugin is nil, should call kclvm_plugin_init at first"); - } - - let ptr = (&_plugin_handler_fn_ptr as *const u64) as *const () - as *const extern "C" fn( - method: *const i8, - args: *const c_char, - kwargs: *const c_char, - ) -> *const c_char; - - (*ptr)(method, args, kwargs) + let fn_ptr_guard = PLUGIN_HANDLER_FN_PTR.lock().unwrap(); + if let Some(fn_ptr) = *fn_ptr_guard { + fn_ptr(method, args, kwargs) + } else { + panic!("plugin handler is nil, should call kclvm_plugin_init at first"); } } @@ -85,7 +106,7 @@ pub extern "C" fn kclvm_plugin_invoke_json( #[no_mangle] #[runtime_fn] pub extern "C" fn kclvm_plugin_invoke_json( - method: *const i8, + method: *const c_char, args: *const c_char, kwargs: *const c_char, ) -> *const c_char { @@ -97,7 +118,7 @@ pub extern "C" fn kclvm_plugin_invoke_json( #[cfg(target_arch = "wasm32")] extern "C" { pub fn kclvm_plugin_invoke_json_wasm( - method: *const i8, + method: *const c_char, args: *const c_char, kwargs: *const c_char, ) -> *const c_char; diff --git a/kclvm/runtime/src/template/mod.rs b/kclvm/runtime/src/template/mod.rs new file mode 100644 index 000000000..bb7004933 --- /dev/null +++ b/kclvm/runtime/src/template/mod.rs @@ -0,0 +1,55 @@ +use std::collections::HashMap; + +use crate::*; +use handlebars::{html_escape, Handlebars}; + +/// Applies a parsed template to the specified data object and +/// returns the string output. +#[no_mangle] +#[runtime_fn] +pub extern "C" fn kclvm_template_execute( + ctx: *mut kclvm_context_t, + args: *const kclvm_value_ref_t, + kwargs: *const kclvm_value_ref_t, +) -> *const kclvm_value_ref_t { + let args = ptr_as_ref(args); + let kwargs = ptr_as_ref(kwargs); + let ctx = mut_ptr_as_ref(ctx); + + if let Some(template) = get_call_arg_str(args, kwargs, 0, Some("template")) { + let mut handlebars = Handlebars::new(); + handlebars + .register_template_string("template", template) + .expect("register template failed"); + let data = get_call_arg(args, kwargs, 1, Some("data")).unwrap_or(ValueRef::dict(None)); + let data: HashMap = HashMap::from_iter( + data.as_dict_ref() + .values + .iter() + .map(|(k, v)| (k.to_string(), v.build_json(&Default::default()))), + ); + let result = handlebars + .render("template", &data) + .expect("render template failed"); + return ValueRef::str(&result).into_raw(ctx); + } + panic!("execute() takes exactly one argument (0 given)"); +} + +/// Replaces the characters `&"<>` with the equivalent html / xml entities. +#[no_mangle] +#[runtime_fn] +pub extern "C" fn kclvm_template_html_escape( + ctx: *mut kclvm_context_t, + args: *const kclvm_value_ref_t, + kwargs: *const kclvm_value_ref_t, +) -> *const kclvm_value_ref_t { + let args = ptr_as_ref(args); + let kwargs = ptr_as_ref(kwargs); + let ctx = mut_ptr_as_ref(ctx); + + if let Some(data) = get_call_arg_str(args, kwargs, 0, Some("data")) { + return ValueRef::str(&html_escape(&data)).into_raw(ctx); + } + panic!("html_escape() takes exactly one argument (0 given)"); +} diff --git a/kclvm/runtime/src/testing/mod.rs b/kclvm/runtime/src/testing/mod.rs deleted file mode 100644 index c4034afa8..000000000 --- a/kclvm/runtime/src/testing/mod.rs +++ /dev/null @@ -1,4 +0,0 @@ -// Copyright 2021 The KCL Authors. All rights reserved. - -pub mod testing; -pub use self::testing::*; diff --git a/kclvm/runtime/src/testing/testing.rs b/kclvm/runtime/src/testing/testing.rs deleted file mode 100644 index 3a16ad538..000000000 --- a/kclvm/runtime/src/testing/testing.rs +++ /dev/null @@ -1,28 +0,0 @@ -//! KCL testing system module -//! -//! Copyright 2021 The KCL Authors. All rights reserved. - -use crate::*; - -#[allow(non_camel_case_types)] -type kclvm_value_ref_t = ValueRef; - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_testing_arguments( - _ctx: *mut kclvm_context_t, - _args: *const kclvm_value_ref_t, - _kwargs: *const kclvm_value_ref_t, -) { - // Nothing to do -} - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_testing_setting_file( - _ctx: *mut kclvm_context_t, - _args: *const kclvm_value_ref_t, - _kwargs: *const kclvm_value_ref_t, -) { - // Nothing to do -} diff --git a/kclvm/runtime/src/types/api.rs b/kclvm/runtime/src/types/api.rs deleted file mode 100644 index 1359dccc0..000000000 --- a/kclvm/runtime/src/types/api.rs +++ /dev/null @@ -1,387 +0,0 @@ -// Copyright 2021 The KCL Authors. All rights reserved. - -use crate::*; - -#[allow(dead_code, non_camel_case_types)] -type kclvm_context_t = Context; - -#[allow(dead_code, non_camel_case_types)] -type kclvm_kind_t = Kind; - -#[allow(dead_code, non_camel_case_types)] -type kclvm_type_t = Type; - -#[allow(dead_code, non_camel_case_types)] -type kclvm_value_t = Value; - -#[allow(dead_code, non_camel_case_types)] -type kclvm_char_t = i8; - -#[allow(dead_code, non_camel_case_types)] -type kclvm_size_t = i32; - -#[allow(dead_code, non_camel_case_types)] -type kclvm_bool_t = i8; - -#[allow(dead_code, non_camel_case_types)] -type kclvm_int_t = i64; - -#[allow(dead_code, non_camel_case_types)] -type kclvm_float_t = f64; - -// ---------------------------------------------------------------------------- -// new -// ---------------------------------------------------------------------------- - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_type_Any() -> *mut kclvm_type_t { - new_mut_ptr(Type::any()) -} - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_type_Bool() -> *mut kclvm_type_t { - new_mut_ptr(Type::bool()) -} - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_type_BoolLit(v: kclvm_bool_t) -> *mut kclvm_type_t { - new_mut_ptr(Type::bool_lit(v != 0)) -} - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_type_Int() -> *mut kclvm_type_t { - new_mut_ptr(Type::int()) -} - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_type_IntLit(v: i64) -> *mut kclvm_type_t { - new_mut_ptr(Type::int_lit(v)) -} - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_type_Float() -> *mut kclvm_type_t { - new_mut_ptr(Type::float()) -} - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_type_FloatLit(v: f64) -> *mut kclvm_type_t { - new_mut_ptr(Type::float_lit(v)) -} - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_type_Str() -> *mut kclvm_type_t { - new_mut_ptr(Type::str()) -} - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_type_StrLit(s: *const kclvm_char_t) -> *mut kclvm_type_t { - return new_mut_ptr(Type::str_lit(c2str(s))); -} - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_type_List(elem_type: *const kclvm_type_t) -> *mut kclvm_type_t { - return new_mut_ptr(Type::list(ptr_as_ref(elem_type))); -} - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_type_Dict( - key_type: *const kclvm_type_t, - elem_type: *const kclvm_type_t, -) -> *mut kclvm_type_t { - return new_mut_ptr(Type::dict(ptr_as_ref(key_type), ptr_as_ref(elem_type))); -} - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_type_Union( - n: kclvm_size_t, - elem_types: *const *const kclvm_type_t, -) -> *mut kclvm_type_t { - unsafe { - let mut ut: UnionType = Default::default(); - - let _ = std::slice::from_raw_parts(elem_types, n as usize) - .iter() - .map(|arg| ut.elem_types.push(ptr_as_ref(*arg).clone())); - - new_mut_ptr(Type::union_type(ut)) - } -} - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_type_Schema( - name: *const kclvm_char_t, - parent_name: *const kclvm_char_t, - _is_relaxed: kclvm_bool_t, - field_num: kclvm_size_t, - field_names: *const *const kclvm_char_t, - field_types: *const *const kclvm_type_t, -) -> *mut kclvm_type_t { - unsafe { - let mut st: SchemaType = SchemaType { - name: c2str(name).to_string(), - parent_name: c2str(parent_name).to_string(), - ..Default::default() - }; - - let _ = std::slice::from_raw_parts(field_names, field_num as usize) - .iter() - .map(|arg| st.field_names.push(c2str(*arg).to_string())); - let _ = std::slice::from_raw_parts(field_types, field_num as usize) - .iter() - .map(|arg| st.field_types.push(ptr_as_ref(*arg).clone())); - - new_mut_ptr(Type::schema_type(st)) - } -} - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_type_Func( - args_len: kclvm_size_t, - args_types: *const *const kclvm_type_t, - return_type: *const kclvm_type_t, -) -> *mut kclvm_type_t { - unsafe { - let mut ft: FuncType = FuncType { - return_type: Box::new(ptr_as_ref(return_type).clone()), - ..Default::default() - }; - let _ = std::slice::from_raw_parts(args_types, args_len as usize) - .iter() - .map(|arg| ft.args_types.push(ptr_as_ref(*arg).clone())); - - new_mut_ptr(Type::func_type(ft)) - } -} - -// ---------------------------------------------------------------------------- -// delete -// ---------------------------------------------------------------------------- - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_type_delete(p: *mut kclvm_type_t) { - free_mut_ptr(p); -} - -// ---------------------------------------------------------------------------- -// kind -// ---------------------------------------------------------------------------- - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_type_kind(p: *const kclvm_type_t) -> kclvm_kind_t { - let p = ptr_as_ref(p); - - p.kind() -} - -// ---------------------------------------------------------------------------- -// type_str -// ---------------------------------------------------------------------------- - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_type_str(p: *const kclvm_type_t) -> kclvm_kind_t { - let p = ptr_as_ref(p); - - p.kind() -} - -// ---------------------------------------------------------------------------- -// lit value -// ---------------------------------------------------------------------------- - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_type_BoolLit_value(p: *const kclvm_type_t) -> kclvm_bool_t { - match ptr_as_ref(p) { - Type::bool_lit_type(ref v) => *v as kclvm_bool_t, - _ => 0, - } -} - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_type_IntLit_value(p: *const kclvm_type_t) -> i64 { - let p = ptr_as_ref(p); - match p { - Type::int_lit_type(ref v) => *v, - _ => 0, - } -} - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_type_FloatLit_value(p: *const kclvm_type_t) -> f64 { - let p = ptr_as_ref(p); - match p { - Type::float_lit_type(ref v) => *v, - _ => 0.0, - } -} - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_type_StrLit_value(p: *const kclvm_type_t) -> *const kclvm_char_t { - let p = ptr_as_ref(p); - match p { - Type::str_lit_type(ref v) => v.as_ptr() as *const kclvm_char_t, - _ => std::ptr::null(), - } -} - -// ---------------------------------------------------------------------------- -// list/dict type -// ---------------------------------------------------------------------------- - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_type_key_type(p: *const kclvm_type_t) -> *const kclvm_type_t { - let p = ptr_as_ref(p); - match p { - Type::dict_type(ref v) => { - return v.key_type.as_ref() as *const Type; - } - _ => std::ptr::null(), - } -} - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_type_elem_type(p: *const kclvm_type_t) -> *const kclvm_type_t { - let p = ptr_as_ref(p); - match p { - Type::list_type(ref v) => { - return v.elem_type.as_ref() as *const Type; - } - Type::dict_type(ref v) => { - return v.elem_type.as_ref() as *const Type; - } - _ => std::ptr::null(), - } -} - -// ---------------------------------------------------------------------------- -// schema -// ---------------------------------------------------------------------------- - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_type_schema_name(p: *const kclvm_type_t) -> *const kclvm_char_t { - let p = ptr_as_ref(p); - match p { - Type::schema_type(ref v) => v.name.as_ptr() as *const kclvm_char_t, - _ => std::ptr::null(), - } -} - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_type_schema_parent_name(p: *const kclvm_type_t) -> *const kclvm_char_t { - let p = ptr_as_ref(p); - match p { - Type::schema_type(ref v) => v.parent_name.as_ptr() as *const kclvm_char_t, - _ => std::ptr::null(), - } -} - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_type_schema_relaxed(p: *const kclvm_type_t) -> kclvm_bool_t { - let p = ptr_as_ref(p); - match p { - Type::schema_type(..) => false as kclvm_bool_t, - _ => 0, - } -} - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_type_schema_field_num(p: *const kclvm_type_t) -> kclvm_size_t { - let p = ptr_as_ref(p); - match p { - Type::schema_type(ref v) => v.field_names.len() as kclvm_size_t, - _ => 0, - } -} - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_type_schema_field_name( - p: *const kclvm_type_t, - i: kclvm_size_t, -) -> *const kclvm_char_t { - let p = ptr_as_ref(p); - match p { - Type::schema_type(ref v) => v.field_names[i as usize].as_ptr() as *const kclvm_char_t, - _ => std::ptr::null(), - } -} - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_type_schema_field_type( - p: *const kclvm_type_t, - i: kclvm_size_t, -) -> *const kclvm_type_t { - let p = ptr_as_ref(p); - match p { - Type::schema_type(ref v) => &v.field_types[i as usize] as *const kclvm_type_t, - _ => std::ptr::null(), - } -} - -// ---------------------------------------------------------------------------- -// func (for plugin) -// ---------------------------------------------------------------------------- - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_type_arg_num(p: *const kclvm_type_t) -> kclvm_size_t { - let p = ptr_as_ref(p); - match p { - Type::func_type(ref v) => v.args_types.len() as kclvm_size_t, - _ => 0, - } -} - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_type_arg_type( - p: *const kclvm_type_t, - i: kclvm_size_t, -) -> *const kclvm_type_t { - let p = ptr_as_ref(p); - match p { - Type::func_type(ref v) => &v.args_types[i as usize] as *const kclvm_type_t, - _ => std::ptr::null(), - } -} - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_type_return_type(p: *const kclvm_type_t) -> *const kclvm_type_t { - let p = ptr_as_ref(p); - match p { - Type::func_type(ref v) => v.return_type.as_ref() as *const kclvm_type_t, - _ => std::ptr::null(), - } -} - -// ---------------------------------------------------------------------------- -// END -// ---------------------------------------------------------------------------- diff --git a/kclvm/runtime/src/types/constructor.rs b/kclvm/runtime/src/types/constructor.rs new file mode 100644 index 000000000..47b73921b --- /dev/null +++ b/kclvm/runtime/src/types/constructor.rs @@ -0,0 +1,94 @@ +//! Copyright The KCL Authors. All rights reserved. + +use crate::*; + +impl Type { + #[inline] + pub fn any() -> Self { + Type::Any + } + + #[inline] + pub fn func() -> Self { + Type::Func(Default::default()) + } + + #[inline] + pub fn bool() -> Self { + Type::Bool + } + + #[inline] + pub fn bool_lit(v: bool) -> Self { + Type::BoolLit(v) + } + + #[inline] + pub fn int() -> Self { + Type::Int + } + + #[inline] + pub fn int_lit(v: i64) -> Self { + Type::IntLit(v) + } + + #[inline] + pub fn float() -> Self { + Type::Float + } + + #[inline] + pub fn float_lit(v: f64) -> Self { + Type::FloatLit(v) + } + + #[inline] + pub fn str() -> Self { + Type::Str + } + + #[inline] + pub fn str_lit(s: &str) -> Self { + Type::StrLit(s.to_string()) + } + + #[inline] + pub fn list(elem_type: &Self) -> Self { + Type::List(ListType { + elem_type: Box::new(elem_type.clone()), + }) + } + + #[inline] + pub fn dict(key_type: &Self, elem_type: &Self) -> Self { + Type::Dict(DictType { + key_type: Box::new(key_type.clone()), + elem_type: Box::new(elem_type.clone()), + }) + } + + #[inline] + pub fn union(elem_types: &[&Self]) -> Self { + let mut ut: UnionType = Default::default(); + for typ in elem_types { + ut.elem_types.push((*typ).clone()); + } + Type::Union(ut) + } + + #[inline] + pub fn schema( + name: String, + attrs: IndexMap, + has_index_signature: bool, + func: ValueRef, + ) -> Self { + Type::Schema(SchemaType { + name, + attrs, + has_index_signature, + func, + }) + } +} diff --git a/kclvm/runtime/src/types/kind.rs b/kclvm/runtime/src/types/kind.rs new file mode 100644 index 000000000..6526a624e --- /dev/null +++ b/kclvm/runtime/src/types/kind.rs @@ -0,0 +1,24 @@ +//! Copyright The KCL Authors. All rights reserved. + +use crate::*; + +impl Type { + pub fn kind(&self) -> Kind { + match self { + Type::Any => Kind::Any, + Type::Bool => Kind::Bool, + Type::BoolLit(..) => Kind::BoolLit, + Type::Int => Kind::Int, + Type::IntLit(..) => Kind::IntLit, + Type::Float => Kind::Float, + Type::FloatLit(..) => Kind::FloatLit, + Type::Str => Kind::Str, + Type::StrLit(..) => Kind::StrLit, + Type::List(..) => Kind::List, + Type::Dict(..) => Kind::Dict, + Type::Union(..) => Kind::Union, + Type::Schema(..) => Kind::Schema, + Type::Func(..) => Kind::Func, + } + } +} diff --git a/kclvm/runtime/src/types/mod.rs b/kclvm/runtime/src/types/mod.rs index 7f1db4c8b..851a5e286 100644 --- a/kclvm/runtime/src/types/mod.rs +++ b/kclvm/runtime/src/types/mod.rs @@ -1,13 +1,5 @@ -// Copyright 2021 The KCL Authors. All rights reserved. +//! Copyright The KCL Authors. All rights reserved. -pub mod api; -pub use api::*; - -pub mod typ_kind; -pub use typ_kind::*; - -pub mod typ_new; -pub use typ_new::*; - -pub mod typ_type_str; -pub use typ_type_str::*; +pub mod constructor; +pub mod kind; +pub mod str; diff --git a/kclvm/runtime/src/types/str.rs b/kclvm/runtime/src/types/str.rs new file mode 100644 index 000000000..cbfd7f0b6 --- /dev/null +++ b/kclvm/runtime/src/types/str.rs @@ -0,0 +1,34 @@ +//! Copyright The KCL Authors. All rights reserved. + +use crate::*; + +impl Type { + pub fn type_str(&self) -> String { + match self { + Type::Any => KCL_TYPE_ANY.to_string(), + Type::Bool => BUILTIN_TYPE_BOOL.to_string(), + Type::BoolLit(ref v) => format!("{BUILTIN_TYPE_BOOL}({v})"), + Type::Int => BUILTIN_TYPE_INT.to_string(), + Type::IntLit(ref v) => format!("{BUILTIN_TYPE_INT}({v})"), + Type::Float => BUILTIN_TYPE_FLOAT.to_string(), + Type::FloatLit(ref v) => format!("{BUILTIN_TYPE_FLOAT}({v})"), + Type::Str => BUILTIN_TYPE_STR.to_string(), + Type::StrLit(ref v) => format!("{BUILTIN_TYPE_STR}({v})"), + Type::List(ref v) => format!("[{}]", v.elem_type.type_str()), + Type::Dict(ref v) => { + format!("{{{}:{}}}", v.key_type.type_str(), v.elem_type.type_str()) + } + Type::Union(ref v) => match v.elem_types.len() { + 0 => String::new(), + 1 => v.elem_types[0].type_str(), + _ => { + let mut types = Vec::new(); + let _ = v.elem_types.iter().map(|e| types.push(e.type_str())); + types.join(" | ") + } + }, + Type::Schema(ref v) => v.name.to_string(), + Type::Func(ref _v) => "func".to_string(), + } + } +} diff --git a/kclvm/runtime/src/types/typ_kind.rs b/kclvm/runtime/src/types/typ_kind.rs deleted file mode 100644 index 3c11d8fa2..000000000 --- a/kclvm/runtime/src/types/typ_kind.rs +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright 2021 The KCL Authors. All rights reserved. - -use crate::*; - -impl Type { - pub fn kind(&self) -> Kind { - match self { - Type::any_type => Kind::Any, - Type::bool_type => Kind::Bool, - Type::bool_lit_type(..) => Kind::BoolLit, - Type::int_type => Kind::Int, - Type::int_lit_type(..) => Kind::IntLit, - Type::float_type => Kind::Float, - Type::float_lit_type(..) => Kind::FloatLit, - Type::str_type => Kind::Str, - Type::str_lit_type(..) => Kind::StrLit, - Type::list_type(..) => Kind::List, - Type::dict_type(..) => Kind::Dict, - Type::union_type(..) => Kind::Union, - Type::schema_type(..) => Kind::Schema, - Type::func_type(..) => Kind::Func, - } - } -} diff --git a/kclvm/runtime/src/types/typ_new.rs b/kclvm/runtime/src/types/typ_new.rs deleted file mode 100644 index d679698b2..000000000 --- a/kclvm/runtime/src/types/typ_new.rs +++ /dev/null @@ -1,88 +0,0 @@ -// Copyright 2021 The KCL Authors. All rights reserved. - -use crate::*; - -impl Type { - pub fn any() -> Self { - Type::any_type - } - - pub fn func() -> Self { - Type::func_type(Default::default()) - } - - pub fn bool() -> Self { - Type::bool_type - } - - pub fn bool_lit(v: bool) -> Self { - Type::bool_lit_type(v) - } - - pub fn int() -> Self { - Type::int_type - } - - pub fn int_lit(v: i64) -> Self { - Type::int_lit_type(v) - } - - pub fn float() -> Self { - Type::float_type - } - - pub fn float_lit(v: f64) -> Self { - Type::float_lit_type(v) - } - - pub fn str() -> Self { - Type::str_type - } - - pub fn str_lit(s: &str) -> Self { - Type::str_lit_type(s.to_string()) - } - - pub fn list(elem_type: &Self) -> Self { - Type::list_type(ListType { - elem_type: Box::new(elem_type.clone()), - }) - } - - pub fn dict(key_type: &Self, elem_type: &Self) -> Self { - Type::dict_type(DictType { - key_type: Box::new(key_type.clone()), - elem_type: Box::new(elem_type.clone()), - }) - } - - pub fn union(elem_types: &[&Self]) -> Self { - let mut ut: UnionType = Default::default(); - for typ in elem_types { - ut.elem_types.push((*typ).clone()); - } - Type::union_type(ut) - } - - pub fn schema( - name: &str, - parent_name: &str, - field_names: &[&str], - field_types: &[&Self], - ) -> Self { - let mut st = SchemaType { - name: name.to_string(), - parent_name: parent_name.to_string(), - ..Default::default() - }; - - for name in field_names { - st.field_names.push((*name).to_string()); - } - for typ in field_types { - st.field_types.push((*typ).clone()); - } - - Type::schema_type(st) - } -} diff --git a/kclvm/runtime/src/types/typ_type_str.rs b/kclvm/runtime/src/types/typ_type_str.rs deleted file mode 100644 index 50fa8756b..000000000 --- a/kclvm/runtime/src/types/typ_type_str.rs +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2021 The KCL Authors. All rights reserved. - -use crate::*; - -impl Type { - pub fn type_str(&self) -> String { - match self { - Type::any_type => KCL_TYPE_ANY.to_string(), - Type::bool_type => BUILTIN_TYPE_BOOL.to_string(), - Type::bool_lit_type(ref v) => format!("{}({})", BUILTIN_TYPE_BOOL, v), - Type::int_type => BUILTIN_TYPE_INT.to_string(), - Type::int_lit_type(ref v) => format!("{}({})", BUILTIN_TYPE_INT, v), - Type::float_type => BUILTIN_TYPE_FLOAT.to_string(), - Type::float_lit_type(ref v) => format!("{}({})", BUILTIN_TYPE_FLOAT, v), - Type::str_type => BUILTIN_TYPE_STR.to_string(), - Type::str_lit_type(ref v) => format!("{}({})", BUILTIN_TYPE_STR, v), - Type::list_type(ref v) => format!("[{}]", v.elem_type.type_str()), - Type::dict_type(ref v) => { - format!("{{{}:{}}}", v.key_type.type_str(), v.elem_type.type_str()) - } - Type::union_type(ref v) => match v.elem_types.len() { - 0 => String::new(), - 1 => v.elem_types[0].type_str(), - _ => { - let mut types = Vec::new(); - let _ = v.elem_types.iter().map(|e| types.push(e.type_str())); - types.join("|") - } - }, - Type::schema_type(ref v) => v.name.to_string(), - Type::func_type(ref _v) => "func".to_string(), - } - } -} diff --git a/kclvm/runtime/src/unification/mod.rs b/kclvm/runtime/src/unification/mod.rs index ff06983fc..55d8d4141 100644 --- a/kclvm/runtime/src/unification/mod.rs +++ b/kclvm/runtime/src/unification/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2021 The KCL Authors. All rights reserved. +//! Copyright The KCL Authors. All rights reserved. pub mod subsume; pub use subsume::*; diff --git a/kclvm/runtime/src/unification/subsume.rs b/kclvm/runtime/src/unification/subsume.rs index 5f4295d2c..25140be6c 100644 --- a/kclvm/runtime/src/unification/subsume.rs +++ b/kclvm/runtime/src/unification/subsume.rs @@ -1,4 +1,4 @@ -// Copyright 2021 The KCL Authors. All rights reserved. +//! Copyright The KCL Authors. All rights reserved. use crate::*; @@ -28,7 +28,7 @@ pub fn value_subsume(value1: &ValueRef, value2: &ValueRef, should_recursive_chec if value1.is_str() && value2.is_str() { return value1.as_str() == value2.as_str(); } - match (&*value1.rc, &*value2.rc) { + match (&*value1.rc.borrow(), &*value2.rc.borrow()) { (Value::list_value(value1), Value::list_value(value2)) => { return value1.values.len() == value2.values.len() && value1 diff --git a/kclvm/runtime/src/units/mod.rs b/kclvm/runtime/src/units/mod.rs index c0a05d119..b71115a4f 100644 --- a/kclvm/runtime/src/units/mod.rs +++ b/kclvm/runtime/src/units/mod.rs @@ -1,4 +1,443 @@ -// Copyright 2021 The KCL Authors. All rights reserved. +//! Copyright The KCL Authors. All rights reserved. -pub mod units; -pub use self::units::*; +use crate::*; + +#[derive(Debug)] +#[allow(non_camel_case_types, dead_code)] +enum to_unit_suffix { + n, + u, + m, + k, + K, + M, + G, + T, + P, + Ki, + Mi, + Gi, + Ti, + Pi, +} + +use phf::{phf_map, Map}; + +pub const IEC_SUFFIX: &str = "i"; +pub const EXPONENTS: Map<&str, i8> = phf_map! { + "n" => -3, + "u" => -2, + "m" => -1, + "k" => 1, + "K" => 1, + "M" => 2, + "G" => 3, + "T" => 4, + "P" => 5, +}; +pub const INVALID_UNITS: [&str; 4] = ["ni", "ui", "mi", "ki"]; + +// to_n(num: int) -> str + +#[no_mangle] +#[runtime_fn] +pub extern "C" fn kclvm_units_to_n( + ctx: *mut kclvm_context_t, + args: *const kclvm_value_ref_t, + kwargs: *const kclvm_value_ref_t, +) -> *const kclvm_value_ref_t { + let ctx = mut_ptr_as_ref(ctx); + let args = ptr_as_ref(args); + let kwargs = ptr_as_ref(kwargs); + + if let Some(num) = get_call_arg(args, kwargs, 0, Some("num")) { + let num = num.convert_to_float(ctx).as_float(); + let s = to_unit(num, to_unit_suffix::n); + return ValueRef::str(s.as_ref()).into_raw(ctx); + } + panic!("to_n() missing 1 required positional argument: 'num'"); +} + +// to_u(num: int) -> str + +#[no_mangle] +#[runtime_fn] +pub extern "C" fn kclvm_units_to_u( + ctx: *mut kclvm_context_t, + args: *const kclvm_value_ref_t, + kwargs: *const kclvm_value_ref_t, +) -> *const kclvm_value_ref_t { + let ctx = mut_ptr_as_ref(ctx); + let args = ptr_as_ref(args); + let kwargs = ptr_as_ref(kwargs); + + if let Some(num) = get_call_arg(args, kwargs, 0, Some("num")) { + let num = num.convert_to_float(ctx).as_float(); + let s = to_unit(num, to_unit_suffix::u); + return ValueRef::str(s.as_ref()).into_raw(ctx); + } + panic!("to_u() missing 1 required positional argument: 'num'"); +} + +// to_m(num: int) -> str + +#[no_mangle] +#[runtime_fn] +pub extern "C" fn kclvm_units_to_m( + ctx: *mut kclvm_context_t, + args: *const kclvm_value_ref_t, + kwargs: *const kclvm_value_ref_t, +) -> *const kclvm_value_ref_t { + let ctx = mut_ptr_as_ref(ctx); + let args = ptr_as_ref(args); + let kwargs = ptr_as_ref(kwargs); + + if let Some(num) = get_call_arg(args, kwargs, 0, Some("num")) { + let num = num.convert_to_float(ctx).as_float(); + let s = to_unit(num, to_unit_suffix::m); + return ValueRef::str(s.as_ref()).into_raw(ctx); + } + panic!("to_m() missing 1 required positional argument: 'num'"); +} + +// to_K(num: int) -> str + +#[no_mangle] +#[runtime_fn] +pub extern "C" fn kclvm_units_to_K( + ctx: *mut kclvm_context_t, + args: *const kclvm_value_ref_t, + kwargs: *const kclvm_value_ref_t, +) -> *const kclvm_value_ref_t { + let ctx = mut_ptr_as_ref(ctx); + let args = ptr_as_ref(args); + let kwargs = ptr_as_ref(kwargs); + + if let Some(num) = get_call_arg_num(args, kwargs, 0, Some("num")) { + let s = to_unit(num, to_unit_suffix::K); + return ValueRef::str(s.as_ref()).into_raw(ctx); + } + panic!("to_K() missing 1 required positional argument: 'num'"); +} + +// to_M(num: int) -> str + +#[no_mangle] +#[runtime_fn] +pub extern "C" fn kclvm_units_to_M( + ctx: *mut kclvm_context_t, + args: *const kclvm_value_ref_t, + kwargs: *const kclvm_value_ref_t, +) -> *const kclvm_value_ref_t { + let ctx = mut_ptr_as_ref(ctx); + let args = ptr_as_ref(args); + let kwargs = ptr_as_ref(kwargs); + + if let Some(num) = get_call_arg_num(args, kwargs, 0, Some("num")) { + let s = to_unit(num, to_unit_suffix::M); + return ValueRef::str(s.as_ref()).into_raw(ctx); + } + panic!("to_M() missing 1 required positional argument: 'num'"); +} + +// to_G(num: int) -> str + +#[no_mangle] +#[runtime_fn] +pub extern "C" fn kclvm_units_to_G( + ctx: *mut kclvm_context_t, + args: *const kclvm_value_ref_t, + kwargs: *const kclvm_value_ref_t, +) -> *const kclvm_value_ref_t { + let ctx = mut_ptr_as_ref(ctx); + let args = ptr_as_ref(args); + let kwargs = ptr_as_ref(kwargs); + + if let Some(num) = get_call_arg_num(args, kwargs, 0, Some("num")) { + let s = to_unit(num, to_unit_suffix::G); + return ValueRef::str(s.as_ref()).into_raw(ctx); + } + panic!("to_G() missing 1 required positional argument: 'num'"); +} + +// to_T(num: int) -> str + +#[no_mangle] +#[runtime_fn] +pub extern "C" fn kclvm_units_to_T( + ctx: *mut kclvm_context_t, + args: *const kclvm_value_ref_t, + kwargs: *const kclvm_value_ref_t, +) -> *const kclvm_value_ref_t { + let ctx = mut_ptr_as_ref(ctx); + let args = ptr_as_ref(args); + let kwargs = ptr_as_ref(kwargs); + + if let Some(num) = get_call_arg_num(args, kwargs, 0, Some("num")) { + let s = to_unit(num, to_unit_suffix::T); + return ValueRef::str(s.as_ref()).into_raw(ctx); + } + panic!("to_T() missing 1 required positional argument: 'num'"); +} + +// to_P(num: int) -> str + +#[no_mangle] +#[runtime_fn] +pub extern "C" fn kclvm_units_to_P( + ctx: *mut kclvm_context_t, + args: *const kclvm_value_ref_t, + kwargs: *const kclvm_value_ref_t, +) -> *const kclvm_value_ref_t { + let ctx = mut_ptr_as_ref(ctx); + let args = ptr_as_ref(args); + let kwargs = ptr_as_ref(kwargs); + + if let Some(num) = get_call_arg_num(args, kwargs, 0, Some("num")) { + let s = to_unit(num, to_unit_suffix::P); + return ValueRef::str(s.as_ref()).into_raw(ctx); + } + panic!("to_P() missing 1 required positional argument: 'num'"); +} + +// to_Ki(num: int) -> str + +#[no_mangle] +#[runtime_fn] +pub extern "C" fn kclvm_units_to_Ki( + ctx: *mut kclvm_context_t, + args: *const kclvm_value_ref_t, + kwargs: *const kclvm_value_ref_t, +) -> *const kclvm_value_ref_t { + let ctx = mut_ptr_as_ref(ctx); + let args = ptr_as_ref(args); + let kwargs = ptr_as_ref(kwargs); + + if let Some(num) = get_call_arg_num(args, kwargs, 0, Some("num")) { + let s = to_unit(num, to_unit_suffix::Ki); + return ValueRef::str(s.as_ref()).into_raw(ctx); + } + panic!("to_Ki() missing 1 required positional argument: 'num'"); +} + +// to_Mi(num: int) -> str + +#[no_mangle] +#[runtime_fn] +pub extern "C" fn kclvm_units_to_Mi( + ctx: *mut kclvm_context_t, + args: *const kclvm_value_ref_t, + kwargs: *const kclvm_value_ref_t, +) -> *const kclvm_value_ref_t { + let ctx = mut_ptr_as_ref(ctx); + let args = ptr_as_ref(args); + let kwargs = ptr_as_ref(kwargs); + + if let Some(num) = get_call_arg_num(args, kwargs, 0, Some("num")) { + let s = to_unit(num, to_unit_suffix::Mi); + return ValueRef::str(s.as_ref()).into_raw(ctx); + } + panic!("to_Mi() missing 1 required positional argument: 'num'"); +} + +// to_Gi(num: int) -> str + +#[no_mangle] +#[runtime_fn] +pub extern "C" fn kclvm_units_to_Gi( + ctx: *mut kclvm_context_t, + args: *const kclvm_value_ref_t, + kwargs: *const kclvm_value_ref_t, +) -> *const kclvm_value_ref_t { + let ctx = mut_ptr_as_ref(ctx); + let args = ptr_as_ref(args); + let kwargs = ptr_as_ref(kwargs); + + if let Some(num) = get_call_arg_num(args, kwargs, 0, Some("num")) { + let s = to_unit(num, to_unit_suffix::Gi); + return ValueRef::str(s.as_ref()).into_raw(ctx); + } + panic!("to_Gi() missing 1 required positional argument: 'num'"); +} + +// to_Ti(num: int) -> str + +#[no_mangle] +#[runtime_fn] +pub extern "C" fn kclvm_units_to_Ti( + ctx: *mut kclvm_context_t, + args: *const kclvm_value_ref_t, + kwargs: *const kclvm_value_ref_t, +) -> *const kclvm_value_ref_t { + let ctx = mut_ptr_as_ref(ctx); + let args = ptr_as_ref(args); + let kwargs = ptr_as_ref(kwargs); + + if let Some(num) = get_call_arg_num(args, kwargs, 0, Some("num")) { + let s = to_unit(num, to_unit_suffix::Ti); + return ValueRef::str(s.as_ref()).into_raw(ctx); + } + panic!("to_Ti() missing 1 required positional argument: 'num'"); +} + +// to_Pi(num: int) -> str + +#[no_mangle] +#[runtime_fn] +pub extern "C" fn kclvm_units_to_Pi( + ctx: *mut kclvm_context_t, + args: *const kclvm_value_ref_t, + kwargs: *const kclvm_value_ref_t, +) -> *const kclvm_value_ref_t { + let ctx = mut_ptr_as_ref(ctx); + let args = ptr_as_ref(args); + let kwargs = ptr_as_ref(kwargs); + + if let Some(num) = get_call_arg_num(args, kwargs, 0, Some("num")) { + let s = to_unit(num, to_unit_suffix::Pi); + return ValueRef::str(s.as_ref()).into_raw(ctx); + } + panic!("to_Pi() missing 1 required positional argument: 'num'"); +} + +fn to_unit(num: f64, suffix: to_unit_suffix) -> String { + match suffix { + to_unit_suffix::n => format!("{}{:?}", (num / 1e-09) as i64, suffix), + to_unit_suffix::u => format!("{}{:?}", (num / 1e-06) as i64, suffix), + to_unit_suffix::m => format!("{}{:?}", (num / 0.001) as i64, suffix), + to_unit_suffix::k => format!("{}{:?}", (num / 1_000.0) as i64, suffix), + to_unit_suffix::K => format!("{}{:?}", (num / 1_000.0) as i64, suffix), + to_unit_suffix::M => format!("{}{:?}", (num / 1_000_000.0) as i64, suffix), + to_unit_suffix::G => format!("{}{:?}", (num / 1_000_000_000.0) as i64, suffix), + to_unit_suffix::T => format!("{}{:?}", (num / 1_000_000_000_000.0) as i64, suffix), + to_unit_suffix::P => format!("{}{:?}", (num / 1_000_000_000_000_000.0) as i64, suffix), + to_unit_suffix::Ki => format!("{}{:?}", (num / 1024.0) as i64, suffix), + to_unit_suffix::Mi => format!("{}{:?}", (num / (1024.0 * 1024.0)) as i64, suffix), + to_unit_suffix::Gi => format!("{}{:?}", (num / (1024.0 * 1024.0 * 1024.0)) as i64, suffix), + to_unit_suffix::Ti => format!( + "{}{:?}", + (num / (1024.0 * 1024.0 * 1024.0 * 1024.0)) as i64, + suffix + ), + to_unit_suffix::Pi => format!( + "{}{:?}", + (num / (1024.0 * 1024.0 * 1024.0 * 1024.0 * 1024.0)) as i64, + suffix + ), + } +} + +/// Parse and return number based on input quantity. +/// +/// Supported suffixes: +/// SI: n | u | m | k | K | M | G | T | P +/// IEC: Ki | Mi | Gi | Ti | Pi +/// +/// Input: +/// quantity: &str. +/// +/// Returns: +/// result: i64 +pub fn to_quantity(quantity: &str) -> i64 { + let quantity_len = quantity.len(); + let mut number = quantity; + let mut suffix: Option<&str> = None; + if quantity_len >= 2 && &quantity[quantity_len - 1..] == IEC_SUFFIX { + if EXPONENTS.contains_key(&quantity[quantity_len - 2..quantity_len - 1]) { + number = &quantity[..quantity_len - 2]; + suffix = Some(&quantity[quantity_len - 2..]); + } + } else if quantity_len >= 1 && EXPONENTS.contains_key(&quantity[quantity_len - 1..]) { + number = &quantity[..quantity_len - 1]; + suffix = Some(&quantity[quantity_len - 1..]); + } + if number.is_empty() { + panic!("number can't be empty") + } + let number: i64 = number.parse().unwrap(); + if suffix.is_none() { + return number; + } + let suffix = suffix.unwrap(); + validate_unit(&suffix[0..1]); + let base: i64 = if suffix.ends_with(IEC_SUFFIX) { + 1024 + } else { + 1000 + }; + let exponent = EXPONENTS.get(&suffix[0..1]).unwrap(); + number * (base.pow(*exponent as u32)) +} + +/// Calculate number based on value and binary suffix. +/// +/// Supported suffixes: +/// SI: n | u | m | k | K | M | G | T | P +/// IEC: Ki | Mi | Gi | Ti | Pi +/// +/// Input: +/// value: int. +/// suffix: str. +/// +/// Returns: +/// int +/// +/// Raises: +/// ValueError on invalid or unknown suffix +pub fn cal_num(value: i64, unit: &str) -> f64 { + validate_unit(unit); + let mut base: f64 = 1000.0; + let mut unit = unit; + if unit.len() > 1 && &unit[1..2] == IEC_SUFFIX { + base = 1024.0; + unit = &unit[0..1]; + } + let exponent = EXPONENTS + .get(unit) + .unwrap_or_else(|| panic!("invalid unit {unit}")); + value as f64 * base.powf(*exponent as f64) +} + +#[inline] +pub fn real_uint_value(raw: i64, unit: &str) -> i128 { + (raw as i128) * (u64_unit_value(unit) as i128) +} + +/// Validate the unit is valid +pub fn validate_unit(unit: &str) { + if unit.is_empty() || unit.len() > 2 { + panic!("Invalid suffix {unit}"); + } + if INVALID_UNITS.contains(&unit) { + panic!("Invalid suffix {unit}"); + } + if !EXPONENTS.contains_key(&unit[..1]) { + panic!("Invalid suffix {unit}"); + } +} + +pub fn f64_unit_value(unit: &str) -> f64 { + match unit { + "n" => 1e-09, + "u" => 1e-06, + "m" => 0.001, + _ => 1_f64, + } +} + +pub fn u64_unit_value(unit: &str) -> u64 { + match unit { + "k" => 1_000, + "K" => 1_000, + "M" => 1_000_000, + "G" => 1_000_000_000, + "T" => 1_000_000_000_000, + "P" => 1_000_000_000_000_000, + "Ki" => 1024, + "Mi" => 1048576, + "Gi" => 1073741824, + "Ti" => 1099511627776, + "Pi" => 1125899906842624, + _ => 1_u64, + } +} diff --git a/kclvm/runtime/src/units/units.rs b/kclvm/runtime/src/units/units.rs deleted file mode 100644 index 856b97a5e..000000000 --- a/kclvm/runtime/src/units/units.rs +++ /dev/null @@ -1,439 +0,0 @@ -//! KCL units system module -//! -//! Copyright 2021 The KCL Authors. All rights reserved. - -use crate::*; - -#[allow(non_camel_case_types)] -type kclvm_value_ref_t = ValueRef; - -#[derive(Debug)] -#[allow(dead_code, non_camel_case_types)] -enum to_unit_suffix { - n, - u, - m, - k, - K, - M, - G, - T, - P, - Ki, - Mi, - Gi, - Ti, - Pi, -} - -use phf::{phf_map, Map}; - -pub const IEC_SUFFIX: &str = "i"; -pub const EXPONENTS: Map<&str, i8> = phf_map! { - "n" => -3, - "u" => -2, - "m" => -1, - "k" => 1, - "K" => 1, - "M" => 2, - "G" => 3, - "T" => 4, - "P" => 5, -}; -pub const INVALID_UNITS: [&str; 4] = ["ni", "ui", "mi", "ki"]; - -// to_n(num: int) -> str - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_units_to_n( - ctx: *mut kclvm_context_t, - args: *const kclvm_value_ref_t, - kwargs: *const kclvm_value_ref_t, -) -> *const kclvm_value_ref_t { - let _ctx = mut_ptr_as_ref(ctx); - let args = ptr_as_ref(args); - let _kwargs = ptr_as_ref(kwargs); - - let num = args.arg_0().unwrap().convert_to_float().as_float(); - let s = to_unit(num, to_unit_suffix::n); - return ValueRef::str(s.as_ref()).into_raw(); -} - -// to_u(num: int) -> str - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_units_to_u( - ctx: *mut kclvm_context_t, - args: *const kclvm_value_ref_t, - kwargs: *const kclvm_value_ref_t, -) -> *const kclvm_value_ref_t { - let _ctx = mut_ptr_as_ref(ctx); - let args = ptr_as_ref(args); - let _kwargs = ptr_as_ref(kwargs); - - let num = args.arg_0().unwrap().convert_to_float().as_float(); - let s = to_unit(num, to_unit_suffix::u); - return ValueRef::str(s.as_ref()).into_raw(); -} - -// to_m(num: int) -> str - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_units_to_m( - ctx: *mut kclvm_context_t, - args: *const kclvm_value_ref_t, - kwargs: *const kclvm_value_ref_t, -) -> *const kclvm_value_ref_t { - let _ctx = mut_ptr_as_ref(ctx); - let args = ptr_as_ref(args); - let _kwargs = ptr_as_ref(kwargs); - - let num = args.arg_0().unwrap().convert_to_float().as_float(); - let s = to_unit(num, to_unit_suffix::m); - return ValueRef::str(s.as_ref()).into_raw(); -} - -// to_K(num: int) -> str - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_units_to_K( - ctx: *mut kclvm_context_t, - args: *const kclvm_value_ref_t, - kwargs: *const kclvm_value_ref_t, -) -> *const kclvm_value_ref_t { - let _ctx = mut_ptr_as_ref(ctx); - let args = ptr_as_ref(args); - let _kwargs = ptr_as_ref(kwargs); - - if let Some(num) = args.arg_i_num(0, None) { - let s = to_unit(num, to_unit_suffix::K); - return ValueRef::str(s.as_ref()).into_raw(); - } - panic!("to_K() missing 1 required positional argument: 'num'"); -} - -// to_M(num: int) -> str - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_units_to_M( - ctx: *mut kclvm_context_t, - args: *const kclvm_value_ref_t, - kwargs: *const kclvm_value_ref_t, -) -> *const kclvm_value_ref_t { - let _ctx = mut_ptr_as_ref(ctx); - let args = ptr_as_ref(args); - let _kwargs = ptr_as_ref(kwargs); - - if let Some(num) = args.arg_i_num(0, None) { - let s = to_unit(num, to_unit_suffix::M); - return ValueRef::str(s.as_ref()).into_raw(); - } - panic!("to_M() missing 1 required positional argument: 'num'"); -} - -// to_G(num: int) -> str - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_units_to_G( - ctx: *mut kclvm_context_t, - args: *const kclvm_value_ref_t, - kwargs: *const kclvm_value_ref_t, -) -> *const kclvm_value_ref_t { - let _ctx = mut_ptr_as_ref(ctx); - let args = ptr_as_ref(args); - let _kwargs = ptr_as_ref(kwargs); - - if let Some(num) = args.arg_i_num(0, None) { - let s = to_unit(num, to_unit_suffix::G); - return ValueRef::str(s.as_ref()).into_raw(); - } - panic!("to_G() missing 1 required positional argument: 'num'"); -} - -// to_T(num: int) -> str - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_units_to_T( - ctx: *mut kclvm_context_t, - args: *const kclvm_value_ref_t, - kwargs: *const kclvm_value_ref_t, -) -> *const kclvm_value_ref_t { - let _ctx = mut_ptr_as_ref(ctx); - let args = ptr_as_ref(args); - let _kwargs = ptr_as_ref(kwargs); - - if let Some(num) = args.arg_i_num(0, None) { - let s = to_unit(num, to_unit_suffix::T); - return ValueRef::str(s.as_ref()).into_raw(); - } - panic!("to_T() missing 1 required positional argument: 'num'"); -} - -// to_P(num: int) -> str - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_units_to_P( - ctx: *mut kclvm_context_t, - args: *const kclvm_value_ref_t, - kwargs: *const kclvm_value_ref_t, -) -> *const kclvm_value_ref_t { - let _ctx = mut_ptr_as_ref(ctx); - let args = ptr_as_ref(args); - let _kwargs = ptr_as_ref(kwargs); - - if let Some(num) = args.arg_i_num(0, None) { - let s = to_unit(num, to_unit_suffix::P); - return ValueRef::str(s.as_ref()).into_raw(); - } - panic!("to_P() missing 1 required positional argument: 'num'"); -} - -// to_Ki(num: int) -> str - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_units_to_Ki( - ctx: *mut kclvm_context_t, - args: *const kclvm_value_ref_t, - kwargs: *const kclvm_value_ref_t, -) -> *const kclvm_value_ref_t { - let _ctx = mut_ptr_as_ref(ctx); - let args = ptr_as_ref(args); - let _kwargs = ptr_as_ref(kwargs); - - if let Some(num) = args.arg_i_num(0, None) { - let s = to_unit(num, to_unit_suffix::Ki); - return ValueRef::str(s.as_ref()).into_raw(); - } - panic!("to_Ki() missing 1 required positional argument: 'num'"); -} - -// to_Mi(num: int) -> str - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_units_to_Mi( - ctx: *mut kclvm_context_t, - args: *const kclvm_value_ref_t, - kwargs: *const kclvm_value_ref_t, -) -> *const kclvm_value_ref_t { - let _ctx = mut_ptr_as_ref(ctx); - let args = ptr_as_ref(args); - let _kwargs = ptr_as_ref(kwargs); - - if let Some(num) = args.arg_i_num(0, None) { - let s = to_unit(num, to_unit_suffix::Mi); - return ValueRef::str(s.as_ref()).into_raw(); - } - panic!("to_Mi() missing 1 required positional argument: 'num'"); -} - -// to_Gi(num: int) -> str - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_units_to_Gi( - ctx: *mut kclvm_context_t, - args: *const kclvm_value_ref_t, - kwargs: *const kclvm_value_ref_t, -) -> *const kclvm_value_ref_t { - let _ctx = mut_ptr_as_ref(ctx); - let args = ptr_as_ref(args); - let _kwargs = ptr_as_ref(kwargs); - - if let Some(num) = args.arg_i_num(0, None) { - let s = to_unit(num, to_unit_suffix::Gi); - return ValueRef::str(s.as_ref()).into_raw(); - } - panic!("to_Gi() missing 1 required positional argument: 'num'"); -} - -// to_Ti(num: int) -> str - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_units_to_Ti( - ctx: *mut kclvm_context_t, - args: *const kclvm_value_ref_t, - kwargs: *const kclvm_value_ref_t, -) -> *const kclvm_value_ref_t { - let _ctx = mut_ptr_as_ref(ctx); - let args = ptr_as_ref(args); - let _kwargs = ptr_as_ref(kwargs); - - if let Some(num) = args.arg_i_num(0, None) { - let s = to_unit(num, to_unit_suffix::Ti); - return ValueRef::str(s.as_ref()).into_raw(); - } - panic!("to_Ti() missing 1 required positional argument: 'num'"); -} - -// to_Pi(num: int) -> str - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_units_to_Pi( - ctx: *mut kclvm_context_t, - args: *const kclvm_value_ref_t, - kwargs: *const kclvm_value_ref_t, -) -> *const kclvm_value_ref_t { - let _ctx = mut_ptr_as_ref(ctx); - let args = ptr_as_ref(args); - let _kwargs = ptr_as_ref(kwargs); - - if let Some(num) = args.arg_i_num(0, None) { - let s = to_unit(num, to_unit_suffix::Pi); - return ValueRef::str(s.as_ref()).into_raw(); - } - panic!("to_Pi() missing 1 required positional argument: 'num'"); -} - -fn to_unit(num: f64, suffix: to_unit_suffix) -> String { - match suffix { - to_unit_suffix::n => format!("{}{:?}", (num / 1e-09) as i64, suffix), - to_unit_suffix::u => format!("{}{:?}", (num / 1e-06) as i64, suffix), - to_unit_suffix::m => format!("{}{:?}", (num / 0.001) as i64, suffix), - to_unit_suffix::k => format!("{}{:?}", (num / 1_000.0) as i64, suffix), - to_unit_suffix::K => format!("{}{:?}", (num / 1_000.0) as i64, suffix), - to_unit_suffix::M => format!("{}{:?}", (num / 1_000_000.0) as i64, suffix), - to_unit_suffix::G => format!("{}{:?}", (num / 1_000_000_000.0) as i64, suffix), - to_unit_suffix::T => format!("{}{:?}", (num / 1_000_000_000_000.0) as i64, suffix), - to_unit_suffix::P => format!("{}{:?}", (num / 1_000_000_000_000_000.0) as i64, suffix), - to_unit_suffix::Ki => format!("{}{:?}", (num / 1024.0) as i64, suffix), - to_unit_suffix::Mi => format!("{}{:?}", (num / (1024.0 * 1024.0)) as i64, suffix), - to_unit_suffix::Gi => format!("{}{:?}", (num / (1024.0 * 1024.0 * 1024.0)) as i64, suffix), - to_unit_suffix::Ti => format!( - "{}{:?}", - (num / (1024.0 * 1024.0 * 1024.0 * 1024.0)) as i64, - suffix - ), - to_unit_suffix::Pi => format!( - "{}{:?}", - (num / (1024.0 * 1024.0 * 1024.0 * 1024.0 * 1024.0)) as i64, - suffix - ), - } -} - -/// Parse and return number based on input quantity. -/// -/// Supported suffixes: -/// SI: n | u | m | k | K | M | G | T | P -/// IEC: Ki | Mi | Gi | Ti | Pi -/// -/// Input: -/// quantity: &str. -/// -/// Returns: -/// result: i64 -pub fn to_quantity(quantity: &str) -> i64 { - let quantity_len = quantity.len(); - let mut number = quantity; - let mut suffix: Option<&str> = None; - if quantity_len >= 2 && &quantity[quantity_len - 1..] == IEC_SUFFIX { - if EXPONENTS.contains_key(&quantity[quantity_len - 2..quantity_len - 1]) { - number = &quantity[..quantity_len - 2]; - suffix = Some(&quantity[quantity_len - 2..]); - } - } else if quantity_len >= 1 && EXPONENTS.contains_key(&quantity[quantity_len - 1..]) { - number = &quantity[..quantity_len - 1]; - suffix = Some(&quantity[quantity_len - 1..]); - } - if number.is_empty() { - panic!("number can't be empty") - } - let number: i64 = number.parse().unwrap(); - if suffix.is_none() { - return number; - } - let suffix = suffix.unwrap(); - validate_unit(&suffix[0..1]); - let base: i64 = if suffix.ends_with(IEC_SUFFIX) { - 1024 - } else { - 1000 - }; - let exponent = EXPONENTS.get(&suffix[0..1]).unwrap(); - number * (base.pow(*exponent as u32)) as i64 -} - -/// Calculate number based on value and binary suffix. -/// -/// Supported suffixes: -/// SI: n | u | m | k | K | M | G | T | P -/// IEC: Ki | Mi | Gi | Ti | Pi -/// -/// Input: -/// value: int. -/// suffix: str. -/// -/// Returns: -/// int -/// -/// Raises: -/// ValueError on invalid or unknown suffix -pub fn cal_num(value: i64, unit: &str) -> f64 { - validate_unit(unit); - let mut base: f64 = 1000.0; - let mut unit = unit; - if unit.len() > 1 && &unit[1..2] == IEC_SUFFIX { - base = 1024.0; - unit = &unit[0..1]; - } - let exponent = EXPONENTS - .get(unit) - .unwrap_or_else(|| panic!("invalid unit {}", unit)); - value as f64 * base.powf(*exponent as f64) -} - -#[inline] -pub fn real_uint_value(raw: i64, unit: &str) -> i128 { - (raw as i128) * (u64_unit_value(unit) as i128) -} - -/// Validate the unit is valid -pub fn validate_unit(unit: &str) { - if unit.is_empty() || unit.len() > 2 { - panic!("Invalid suffix {}", unit); - } - if INVALID_UNITS.contains(&unit) { - panic!("Invalid suffix {}", unit); - } - if !EXPONENTS.contains_key(&unit[..1]) { - panic!("Invalid suffix {}", unit); - } -} - -pub fn f64_unit_value(unit: &str) -> f64 { - match unit { - "n" => 1e-09, - "u" => 1e-06, - "m" => 0.001, - _ => 1_f64, - } -} - -pub fn u64_unit_value(unit: &str) -> u64 { - match unit { - "k" => 1_000, - "K" => 1_000, - "M" => 1_000_000, - "G" => 1_000_000_000, - "T" => 1_000_000_000_000, - "P" => 1_000_000_000_000_000, - "Ki" => 1024, - "Mi" => 1048576, - "Gi" => 1073741824, - "Ti" => 1099511627776, - "Pi" => 1125899906842624, - _ => 1_u64, - } -} diff --git a/kclvm/runtime/src/value/api.rs b/kclvm/runtime/src/value/api.rs index 95f45f335..dd94018f8 100644 --- a/kclvm/runtime/src/value/api.rs +++ b/kclvm/runtime/src/value/api.rs @@ -1,15 +1,18 @@ -// Copyright 2021 The KCL Authors. All rights reserved. +//! Copyright The KCL Authors. All rights reserved. +#![allow(clippy::missing_safety_doc)] -use std::mem::transmute_copy; +use std::{mem::transmute_copy, os::raw::c_char}; use crate::*; -#[allow(non_camel_case_types)] -pub type kclvm_buffer_t = Buffer; +use self::{eval::LazyEvalScope, walker::walk_value_mut}; #[allow(non_camel_case_types)] pub type kclvm_context_t = Context; +#[allow(non_camel_case_types)] +pub type kclvm_eval_scope_t = LazyEvalScope; + #[allow(non_camel_case_types)] pub type kclvm_decorator_value_t = DecoratorValue; @@ -26,7 +29,7 @@ pub type kclvm_value_ref_t = ValueRef; pub type kclvm_iterator_t = ValueIterator; #[allow(non_camel_case_types)] -pub type kclvm_char_t = i8; +pub type kclvm_char_t = c_char; #[allow(non_camel_case_types)] pub type kclvm_size_t = i32; @@ -42,7 +45,7 @@ pub type kclvm_float_t = f64; #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_context_set_import_names( +pub unsafe extern "C" fn kclvm_context_set_import_names( p: *mut kclvm_context_t, import_names: *const kclvm_value_ref_t, ) { @@ -64,133 +67,111 @@ pub extern "C" fn kclvm_context_set_import_names( // values: new // ---------------------------------------------------------------------------- -// singleton - -#[allow(non_camel_case_types, non_upper_case_globals)] -static mut kclvm_value_Undefined_obj: usize = 0; - -#[allow(non_camel_case_types, non_upper_case_globals)] -static mut kclvm_value_None_obj: usize = 0; - -#[allow(non_camel_case_types, non_upper_case_globals)] -static mut kclvm_value_Bool_true_obj: usize = 0; - -#[allow(non_camel_case_types, non_upper_case_globals)] -static mut kclvm_value_Bool_false_obj: usize = 0; - -#[allow(non_camel_case_types, non_upper_case_globals)] -static mut kclvm_value_Int_0_obj: usize = 0; - -#[allow(non_camel_case_types, non_upper_case_globals)] -static mut kclvm_value_Float_0_obj: usize = 0; - -// Undefine/None - #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_value_Undefined() -> *mut kclvm_value_ref_t { - ValueRef::undefined().into_raw() +pub extern "C" fn kclvm_value_Undefined(ctx: *mut kclvm_context_t) -> *mut kclvm_value_ref_t { + let ctx = mut_ptr_as_ref(ctx); + new_mut_ptr(ctx, ValueRef::undefined()) } #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_value_None() -> *mut kclvm_value_ref_t { - ValueRef::none().into_raw() +pub extern "C" fn kclvm_value_None(ctx: *mut kclvm_context_t) -> *mut kclvm_value_ref_t { + let ctx = mut_ptr_as_ref(ctx); + new_mut_ptr(ctx, ValueRef::none()) } // bool/int/float/str #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_value_True() -> *mut kclvm_value_ref_t { - kclvm_value_Bool(1) +pub extern "C" fn kclvm_value_True(ctx: *mut kclvm_context_t) -> *mut kclvm_value_ref_t { + let ctx = mut_ptr_as_ref(ctx); + kclvm_value_Bool(ctx, 1) } #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_value_False() -> *mut kclvm_value_ref_t { - kclvm_value_Bool(0) +pub extern "C" fn kclvm_value_False(ctx: *mut kclvm_context_t) -> *mut kclvm_value_ref_t { + let ctx = mut_ptr_as_ref(ctx); + kclvm_value_Bool(ctx, 0) } #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_value_Bool(v: kclvm_bool_t) -> *mut kclvm_value_ref_t { - unsafe { - if v != 0 { - if kclvm_value_Bool_true_obj == 0 { - kclvm_value_Bool_true_obj = new_mut_ptr(ValueRef::bool(true)) as usize; - } - kclvm_value_Bool_true_obj as *mut kclvm_value_ref_t - } else { - if kclvm_value_Bool_false_obj == 0 { - kclvm_value_Bool_false_obj = new_mut_ptr(ValueRef::bool(false)) as usize; - } - kclvm_value_Bool_false_obj as *mut kclvm_value_ref_t - } +pub extern "C" fn kclvm_value_Bool( + ctx: *mut kclvm_context_t, + v: kclvm_bool_t, +) -> *mut kclvm_value_ref_t { + let ctx = mut_ptr_as_ref(ctx); + if v != 0 { + ValueRef::bool(true).into_raw(ctx) + } else { + ValueRef::bool(false).into_raw(ctx) } } #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_value_Int(v: kclvm_int_t) -> *mut kclvm_value_ref_t { - if v == 0 { - unsafe { - if kclvm_value_Int_0_obj == 0 { - kclvm_value_Int_0_obj = new_mut_ptr(ValueRef::int(0)) as usize; - } - return kclvm_value_Int_0_obj as *mut kclvm_value_ref_t; - } - } - new_mut_ptr(ValueRef::int(v)) +pub extern "C" fn kclvm_value_Int( + ctx: *mut kclvm_context_t, + v: kclvm_int_t, +) -> *mut kclvm_value_ref_t { + let ctx = mut_ptr_as_ref(ctx); + new_mut_ptr(ctx, ValueRef::int(v)) } #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_value_Float(v: kclvm_float_t) -> *mut kclvm_value_ref_t { - if v == 0.0 { - unsafe { - if kclvm_value_Float_0_obj == 0 { - kclvm_value_Float_0_obj = new_mut_ptr(ValueRef::float(0.0)) as usize; - } - return kclvm_value_Float_0_obj as *mut kclvm_value_ref_t; - } - } - new_mut_ptr(ValueRef::float(v)) +pub extern "C" fn kclvm_value_Float( + ctx: *mut kclvm_context_t, + v: kclvm_float_t, +) -> *mut kclvm_value_ref_t { + let ctx = mut_ptr_as_ref(ctx); + new_mut_ptr(ctx, ValueRef::float(v)) } #[no_mangle] #[runtime_fn] pub extern "C" fn kclvm_value_Unit( + ctx: *mut kclvm_context_t, v: kclvm_float_t, raw: kclvm_int_t, unit: *const kclvm_char_t, ) -> *mut kclvm_value_ref_t { + let ctx = mut_ptr_as_ref(ctx); let unit = c2str(unit); - new_mut_ptr(ValueRef::unit(v, raw, unit)) + new_mut_ptr(ctx, ValueRef::unit(v, raw, unit)) } #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_value_Str(v: *const kclvm_char_t) -> *mut kclvm_value_ref_t { +pub unsafe extern "C" fn kclvm_value_Str( + ctx: *mut kclvm_context_t, + v: *const kclvm_char_t, +) -> *mut kclvm_value_ref_t { + let ctx = mut_ptr_as_ref(ctx); unsafe { - if v.is_null() || *v == '\0' as i8 { - return new_mut_ptr(ValueRef::str("")); + if v.is_null() || *v == '\0' as c_char { + return new_mut_ptr(ctx, ValueRef::str("")); } } - return new_mut_ptr(ValueRef::str(c2str(v))); + return new_mut_ptr(ctx, ValueRef::str(c2str(v))); } // list/dict/schema #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_value_List() -> *mut kclvm_value_ref_t { - new_mut_ptr(ValueRef::list(None)) +pub extern "C" fn kclvm_value_List(ctx: *mut kclvm_context_t) -> *mut kclvm_value_ref_t { + let ctx = mut_ptr_as_ref(ctx); + new_mut_ptr(ctx, ValueRef::list(None)) } #[no_mangle] #[runtime_fn] pub extern "C" fn kclvm_value_List6( + ctx: *mut kclvm_context_t, v1: *const kclvm_value_ref_t, v2: *const kclvm_value_ref_t, v3: *const kclvm_value_ref_t, @@ -198,16 +179,18 @@ pub extern "C" fn kclvm_value_List6( v5: *const kclvm_value_ref_t, v6: *const kclvm_value_ref_t, ) -> *mut kclvm_value_ref_t { + let ctx = mut_ptr_as_ref(ctx); let values: Vec<&ValueRef> = vec![v1, v2, v3, v4, v5, v6] .into_iter() .map(ptr_as_ref) .collect(); - new_mut_ptr(ValueRef::list(Some(values.as_slice()))) + new_mut_ptr(ctx, ValueRef::list(Some(values.as_slice()))) } #[no_mangle] #[runtime_fn] pub extern "C" fn kclvm_value_List10( + ctx: *mut kclvm_context_t, v1: *const kclvm_value_ref_t, v2: *const kclvm_value_ref_t, v3: *const kclvm_value_ref_t, @@ -219,64 +202,50 @@ pub extern "C" fn kclvm_value_List10( v9: *const kclvm_value_ref_t, v10: *const kclvm_value_ref_t, ) -> *mut kclvm_value_ref_t { + let ctx = mut_ptr_as_ref(ctx); let values: Vec<&ValueRef> = vec![v1, v2, v3, v4, v5, v6, v7, v8, v9, v10] .into_iter() .map(ptr_as_ref) .collect(); - new_mut_ptr(ValueRef::list(Some(values.as_slice()))) + new_mut_ptr(ctx, ValueRef::list(Some(values.as_slice()))) } #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_value_ListN( - n: kclvm_int_t, - elem_values: *const *const kclvm_value_ref_t, -) -> *mut kclvm_value_ref_t { - let mut list = ListValue::default(); - - unsafe { - for xi in std::slice::from_raw_parts(elem_values, n as usize).iter() { - let v: &ValueRef = ptr_as_ref(*xi); - list.values.push(v.clone()); - } - - ValueRef::from(Value::list_value(list)).into_raw() - } +pub extern "C" fn kclvm_value_Dict(ctx: *mut kclvm_context_t) -> *mut kclvm_value_ref_t { + let ctx = mut_ptr_as_ref(ctx); + new_mut_ptr(ctx, ValueRef::dict(None)) } #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_value_Dict() -> *mut kclvm_value_ref_t { - new_mut_ptr(ValueRef::dict(None)) +pub extern "C" fn kclvm_value_Schema(ctx: *mut kclvm_context_t) -> *mut kclvm_value_ref_t { + let ctx = mut_ptr_as_ref(ctx); + new_mut_ptr(ctx, ValueRef::schema()) } #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_value_Schema() -> *mut kclvm_value_ref_t { - new_mut_ptr(ValueRef::schema()) -} - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_value_schema_with_config( +pub unsafe extern "C" fn kclvm_value_schema_with_config( + ctx: *mut kclvm_context_t, schema_dict: *const kclvm_value_ref_t, config: *const kclvm_value_ref_t, + config_meta: *const kclvm_value_ref_t, name: *const kclvm_char_t, pkgpath: *const kclvm_char_t, is_sub_schema: *const kclvm_value_ref_t, record_instance: *const kclvm_value_ref_t, instance_pkgpath: *const kclvm_value_ref_t, + optional_mapping: *const kclvm_value_ref_t, + args: *const kclvm_value_ref_t, + kwargs: *const kclvm_value_ref_t, ) -> *mut kclvm_value_ref_t { + let ctx = mut_ptr_as_ref(ctx); let schema_dict = ptr_as_ref(schema_dict); // Config dict let config = ptr_as_ref(config); - let config_keys: Vec = config - .as_dict_ref() - .values - .keys() - .into_iter() - .cloned() - .collect(); + let config_meta = ptr_as_ref(config_meta); + let config_keys: Vec = config.as_dict_ref().values.keys().cloned().collect(); // Schema meta let name = c2str(name); let pkgpath = c2str(pkgpath); @@ -285,56 +254,92 @@ pub extern "C" fn kclvm_value_schema_with_config( let record_instance = ptr_as_ref(record_instance); let instance_pkgpath = ptr_as_ref(instance_pkgpath); let instance_pkgpath = instance_pkgpath.as_str(); - let schema = schema_dict.dict_to_schema(name, pkgpath, &config_keys); - // Runtime context - let ctx = Context::current_context(); - if record_instance.is_truthy() - && (instance_pkgpath.is_empty() || instance_pkgpath == MAIN_PKG_PATH) - { + let optional_mapping = ptr_as_ref(optional_mapping); + let args = ptr_as_ref(args); + let kwargs = ptr_as_ref(kwargs); + if record_instance.is_truthy() { // Record schema instance in the context - let mut instance_map = ctx.instances.borrow_mut(); - if !instance_map.contains_key(&runtime_type) { - instance_map.insert(runtime_type.clone(), vec![]); + if !ctx.instances.contains_key(&runtime_type) { + ctx.instances + .insert(runtime_type.clone(), IndexMap::default()); + } + let pkg_instance_map = ctx.instances.get_mut(&runtime_type).unwrap(); + if !pkg_instance_map.contains_key(&instance_pkgpath) { + pkg_instance_map.insert(instance_pkgpath.clone(), vec![]); } - instance_map - .get_mut(&runtime_type) + pkg_instance_map + .get_mut(&instance_pkgpath) .unwrap() .push(schema_dict.clone()); } // Dict to schema if is_sub_schema.is_truthy() { - schema.into_raw() + let schema = schema_dict.dict_to_schema( + name, + pkgpath, + &config_keys, + config_meta, + optional_mapping, + Some(args.clone()), + Some(kwargs.clone()), + ); + schema.into_raw(ctx) } else { - schema_dict.clone().into_raw() + schema_dict.clone().into_raw(ctx) } } #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_value_Function( +pub unsafe extern "C" fn kclvm_value_Function( + ctx: *mut kclvm_context_t, fn_ptr: *const u64, closure: *const kclvm_value_ref_t, - external_name: *const kclvm_char_t, + name: *const kclvm_char_t, + is_external: kclvm_bool_t, ) -> *mut kclvm_value_ref_t { + let ctx = mut_ptr_as_ref(ctx); let closure = ptr_as_ref(closure); - let name = c2str(external_name); - new_mut_ptr(ValueRef::func(fn_ptr as u64, 0, closure.clone(), name, "")) + let name = c2str(name); + new_mut_ptr( + ctx, + ValueRef::func( + fn_ptr as u64, + 0, + closure.clone(), + name, + "", + is_external != 0, + ), + ) } #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_value_Function_using_ptr(fn_ptr: *const u64) -> *mut kclvm_value_ref_t { - new_mut_ptr(ValueRef::func(fn_ptr as u64, 0, ValueRef::none(), "", "")) +pub unsafe extern "C" fn kclvm_value_Function_using_ptr( + ctx: *mut kclvm_context_t, + fn_ptr: *const u64, + name: *const kclvm_char_t, +) -> *mut kclvm_value_ref_t { + let name = c2str(name); + let ctx = mut_ptr_as_ref(ctx); + new_mut_ptr( + ctx, + ValueRef::func(fn_ptr as u64, 0, ValueRef::none(), name, "", false), + ) } #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_value_schema_function( +pub unsafe extern "C" fn kclvm_value_schema_function( + ctx: *mut kclvm_context_t, fn_ptr: *const u64, check_fn_ptr: *const u64, + attr_map: *const kclvm_value_ref_t, tpe: *const kclvm_char_t, ) -> *mut kclvm_value_ref_t { // Schema function closures + let ctx = mut_ptr_as_ref(ctx); let is_sub_schema = ValueRef::bool(false); let config_meta = ValueRef::dict(None); let config = ValueRef::dict(None); @@ -347,18 +352,19 @@ pub extern "C" fn kclvm_value_schema_function( let instance_pkgpath = ValueRef::str(MAIN_PKG_PATH); let mut schema_args = ValueRef::list(None); - let schema_args_ref = schema_args.as_list_mut_ref(); - schema_args_ref.values.push(is_sub_schema); - schema_args_ref.values.push(config_meta); - schema_args_ref.values.push(config); - schema_args_ref.values.push(schema); - schema_args_ref.values.push(optional_mapping); - schema_args_ref.values.push(cal_map); - schema_args_ref.values.push(backtrack_level_map); - schema_args_ref.values.push(backtrack_cache); - schema_args_ref.values.push(record_instance); - schema_args_ref.values.push(instance_pkgpath); - + { + let mut schema_args_ref = schema_args.as_list_mut_ref(); + schema_args_ref.values.push(is_sub_schema); + schema_args_ref.values.push(config_meta); + schema_args_ref.values.push(config); + schema_args_ref.values.push(schema); + schema_args_ref.values.push(optional_mapping); + schema_args_ref.values.push(cal_map); + schema_args_ref.values.push(backtrack_level_map); + schema_args_ref.values.push(backtrack_cache); + schema_args_ref.values.push(record_instance); + schema_args_ref.values.push(instance_pkgpath); + } let runtime_type = c2str(tpe); let schema_func = ValueRef::func( fn_ptr as u64, @@ -366,11 +372,22 @@ pub extern "C" fn kclvm_value_schema_function( schema_args, "", runtime_type, + false, ); - let ctx = Context::current_context_mut(); - let mut all_schemas = ctx.all_schemas.borrow_mut(); - all_schemas.insert(runtime_type.to_string(), schema_func.clone()); - new_mut_ptr(schema_func) + let attr_map = ptr_as_ref(attr_map); + let attr_dict = attr_map.as_dict_ref(); + let schema_ty = SchemaType { + name: runtime_type.to_string(), + attrs: attr_dict + .values + .iter() + .map(|(k, _)| (k.to_string(), Type::any())) // TODO: store schema attr type in the runtime. + .collect(), + has_index_signature: attr_dict.attr_map.contains_key(CAL_MAP_INDEX_SIGNATURE), + func: schema_func.clone(), + }; + ctx.all_schemas.insert(runtime_type.to_string(), schema_ty); + new_mut_ptr(ctx, schema_func) } // ---------------------------------------------------------------------------- @@ -379,95 +396,119 @@ pub extern "C" fn kclvm_value_schema_function( #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_value_from_json(s: *const kclvm_char_t) -> *mut kclvm_value_ref_t { +pub unsafe extern "C" fn kclvm_value_from_json( + ctx: *mut kclvm_context_t, + s: *const kclvm_char_t, +) -> *mut kclvm_value_ref_t { + let ctx_ref = mut_ptr_as_ref(ctx); if s.is_null() { - return kclvm_value_Undefined(); + return kclvm_value_Undefined(ctx); } - match ValueRef::from_json(c2str(s)) { - Some(x) => x.into_raw(), - _ => kclvm_value_Undefined(), + match ValueRef::from_json(ctx_ref, c2str(s)) { + Ok(x) => x.into_raw(ctx_ref), + _ => kclvm_value_Undefined(ctx), } } #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_value_to_json(p: *const kclvm_value_ref_t) -> *mut kclvm_buffer_t { - let p = ptr_as_ref(p); - let x = p.to_json(); - let buf = Buffer::new_with_buf(&x); - buf.into_raw() -} - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_value_to_json_value(p: *const kclvm_value_ref_t) -> *mut kclvm_value_ref_t { +pub unsafe extern "C" fn kclvm_value_to_json_value( + ctx: *mut kclvm_context_t, + p: *const kclvm_value_ref_t, +) -> *mut kclvm_value_ref_t { if p.is_null() { - return kclvm_value_Str(std::ptr::null()); + return kclvm_value_Str(ctx, std::ptr::null()); } let p = ptr_as_ref(p); let s = p.to_json_string(); - - return new_mut_ptr(ValueRef::str(s.as_ref())); + let ctx = mut_ptr_as_ref(ctx); + new_mut_ptr(ctx, ValueRef::str(s.as_ref())) } #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_value_to_json_value_with_null( +pub unsafe extern "C" fn kclvm_value_to_json_value_with_null( + ctx: *mut kclvm_context_t, p: *const kclvm_value_ref_t, ) -> *mut kclvm_value_ref_t { if p.is_null() { - return kclvm_value_Str(std::ptr::null()); + return kclvm_value_Str(ctx, std::ptr::null()); } let p = ptr_as_ref(p); let s = p.to_json_string_with_null(); - - return new_mut_ptr(ValueRef::str(s.as_ref())); + let ctx = mut_ptr_as_ref(ctx); + new_mut_ptr(ctx, ValueRef::str(s.as_ref())) } #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_value_plan_to_json(p: *const kclvm_value_ref_t) -> *mut kclvm_value_ref_t { +pub unsafe extern "C" fn kclvm_value_plan_to_json( + ctx: *mut kclvm_context_t, + p: *const kclvm_value_ref_t, +) -> *mut kclvm_value_ref_t { let p = ptr_as_ref(p); - let s = p.plan_to_json_string(); - - return new_mut_ptr(ValueRef::str(s.as_ref())); + let ctx: &mut Context = mut_ptr_as_ref(ctx); + let value = match ctx.buffer.custom_manifests_output.clone() { + Some(output) => ValueRef::from_yaml_stream(ctx, &output).unwrap(), + None => p.clone(), + }; + let (json_string, yaml_string) = value.plan(ctx); + ctx.json_result = json_string.clone(); + ctx.yaml_result = yaml_string.clone(); + new_mut_ptr(ctx, ValueRef::str(&json_string)) } #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_value_plan_to_yaml(p: *const kclvm_value_ref_t) -> *mut kclvm_value_ref_t { +pub unsafe extern "C" fn kclvm_value_plan_to_yaml( + ctx: *mut kclvm_context_t, + p: *const kclvm_value_ref_t, +) -> *mut kclvm_value_ref_t { let p = ptr_as_ref(p); - let s = p.plan_to_yaml_string(); - - return new_mut_ptr(ValueRef::str(s.as_ref())); + let ctx = mut_ptr_as_ref(ctx); + let value = match ctx.buffer.custom_manifests_output.clone() { + Some(output) => ValueRef::from_yaml_stream(ctx, &output).unwrap(), + None => p.clone(), + }; + let (json_string, yaml_string) = value.plan(ctx); + ctx.json_result = json_string.clone(); + ctx.yaml_result = yaml_string.clone(); + new_mut_ptr(ctx, ValueRef::str(&yaml_string)) } #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_value_to_yaml_value(p: *const kclvm_value_ref_t) -> *mut kclvm_value_ref_t { +pub unsafe extern "C" fn kclvm_value_to_yaml_value( + ctx: *mut kclvm_context_t, + p: *const kclvm_value_ref_t, +) -> *mut kclvm_value_ref_t { if p.is_null() { - return kclvm_value_Str(std::ptr::null()); + return kclvm_value_Str(ctx, std::ptr::null()); } - + let ctx = mut_ptr_as_ref(ctx); let p = ptr_as_ref(p); let s = p.to_yaml_string(); - return new_mut_ptr(ValueRef::str(s.as_ref())); + new_mut_ptr(ctx, ValueRef::str(s.as_ref())) } #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_value_to_str_value(p: *const kclvm_value_ref_t) -> *mut kclvm_value_ref_t { +pub unsafe extern "C" fn kclvm_value_to_str_value( + ctx: *mut kclvm_context_t, + p: *const kclvm_value_ref_t, +) -> *mut kclvm_value_ref_t { if p.is_null() { - return kclvm_value_Str(std::ptr::null()); + return kclvm_value_Str(ctx, std::ptr::null()); } + let ctx = mut_ptr_as_ref(ctx); let p = ptr_as_ref(p); let s = p.to_string(); - return new_mut_ptr(ValueRef::str(s.as_ref())); + new_mut_ptr(ctx, ValueRef::str(s.as_ref())) } // ---------------------------------------------------------------------------- @@ -476,63 +517,19 @@ pub extern "C" fn kclvm_value_to_str_value(p: *const kclvm_value_ref_t) -> *mut #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_value_Bool_ptr(p: *const kclvm_value_ref_t) -> *const kclvm_bool_t { - let p = ptr_as_ref(p); - match &*p.rc { - Value::bool_value(ref v) => v as *const bool as *const kclvm_bool_t, // sizeof(bool) == sizeof(i8) - _ => std::ptr::null(), - } -} - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_value_Int_ptr(p: *const kclvm_value_ref_t) -> *const kclvm_int_t { - let p = ptr_as_ref(p); - match &*p.rc { - Value::int_value(ref v) => v as *const kclvm_int_t, - _ => std::ptr::null(), - } -} - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_value_Float_ptr(p: *const kclvm_value_ref_t) -> *const kclvm_float_t { +pub unsafe extern "C" fn kclvm_value_Str_ptr(p: *const kclvm_value_ref_t) -> *const kclvm_char_t { let p = ptr_as_ref(p); - match &*p.rc { - Value::float_value(ref v) => v as *const kclvm_float_t, + match &*p.rc.borrow() { + Value::str_value(ref v) => v.as_ptr() as *const c_char, _ => std::ptr::null(), } } #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_value_Str_ptr(p: *const kclvm_value_ref_t) -> *const kclvm_char_t { +pub unsafe extern "C" fn kclvm_value_function_ptr(p: *const kclvm_value_ref_t) -> *const u64 { let p = ptr_as_ref(p); - match &*p.rc { - Value::str_value(ref v) => v.as_ptr() as *const i8, - _ => std::ptr::null(), - } -} - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_value_Str_len(p: *const kclvm_value_ref_t) -> kclvm_size_t { - let p = ptr_as_ref(p); - p.str_len() as kclvm_size_t -} - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_value_Str_resize(p: *mut kclvm_value_ref_t, n: kclvm_size_t) { - let p = mut_ptr_as_ref(p); - p.str_resize(n as usize) -} - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_value_function_ptr(p: *const kclvm_value_ref_t) -> *const u64 { - let p = ptr_as_ref(p); - match &*p.rc { + match &*p.rc.borrow() { Value::func_value(ref v) => v.fn_ptr as *const u64, _ => std::ptr::null::(), } @@ -540,9 +537,9 @@ pub extern "C" fn kclvm_value_function_ptr(p: *const kclvm_value_ref_t) -> *cons #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_value_check_function_ptr(p: *const kclvm_value_ref_t) -> *const u64 { +pub unsafe extern "C" fn kclvm_value_check_function_ptr(p: *const kclvm_value_ref_t) -> *const u64 { let p = ptr_as_ref(p); - match &*p.rc { + match &*p.rc.borrow() { Value::func_value(ref v) => v.check_fn_ptr as *const u64, _ => std::ptr::null::(), } @@ -550,39 +547,13 @@ pub extern "C" fn kclvm_value_check_function_ptr(p: *const kclvm_value_ref_t) -> #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_value_function_is_external(p: *const kclvm_value_ref_t) -> kclvm_bool_t { - let p = ptr_as_ref(p); - match &*p.rc { - Value::func_value(ref v) => !v.external_name.is_empty() as kclvm_bool_t, - _ => false as kclvm_bool_t, - } -} - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_value_function_external_invoke( - p: *const kclvm_value_ref_t, - args: *const kclvm_value_ref_t, - kwargs: *const kclvm_value_ref_t, -) -> *const kclvm_value_ref_t { - let p = ptr_as_ref(p); - match &*p.rc { - Value::func_value(ref v) => { - let name = format!("{}\0", v.external_name); - kclvm_plugin_invoke(name.as_ptr() as *const i8, args, kwargs) - } - _ => kclvm_value_None(), - } -} - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_value_function_invoke( +pub unsafe extern "C" fn kclvm_value_function_invoke( p: *const kclvm_value_ref_t, ctx: *mut kclvm_context_t, args: *mut kclvm_value_ref_t, kwargs: *const kclvm_value_ref_t, pkgpath: *const kclvm_char_t, + is_in_schema: *const kclvm_value_ref_t, ) -> *const kclvm_value_ref_t { let func = ptr_as_ref(p); let args_ref = mut_ptr_as_ref(args); @@ -591,8 +562,13 @@ pub extern "C" fn kclvm_value_function_invoke( let fn_ptr = func.fn_ptr; let closure = &func.closure; let is_schema = !func.runtime_type.is_empty(); - let is_external = !func.external_name.is_empty(); let ctx_ref = mut_ptr_as_ref(ctx); + if ctx_ref.cfg.debug_mode { + ctx_ref + .backtrace + .push(BacktraceFrame::from_panic_info(&ctx_ref.panic_info)); + ctx_ref.panic_info.kcl_func = func.name.clone(); + } let now_meta_info = ctx_ref.panic_info.clone(); unsafe { let call_fn: SchemaTypeFunc = transmute_copy(&fn_ptr); @@ -607,7 +583,7 @@ pub extern "C" fn kclvm_value_function_invoke( let record_instance_index = closure.len() - 2; let instance_pkgpath_index = closure.len() - 1; args_ref.list_append_unpack(closure); - let args = args_ref.clone().into_raw(); + let args = args_ref.clone().into_raw(ctx_ref); call_fn(ctx, args, kwargs); let cal_map = closure.list_get(cal_map_index).unwrap(); // is sub schema @@ -617,7 +593,7 @@ pub extern "C" fn kclvm_value_function_invoke( // instance pkgpath closure_new.list_set(instance_pkgpath_index, &ValueRef::str(pkgpath)); // cal map - closure_new.list_set(cal_map_index as usize, cal_map); + closure_new.list_set(cal_map_index as usize, &cal_map); // config meta let config_meta = schema_config_meta( &ctx_ref.panic_info.kcl_file, @@ -626,87 +602,58 @@ pub extern "C" fn kclvm_value_function_invoke( ); closure_new.list_set(config_meta_index as usize, &config_meta); args_new.list_append_unpack(&closure_new); - call_fn(ctx, args_new.into_raw(), kwargs) + call_fn(ctx, args_new.into_raw(ctx_ref), kwargs) // Normal kcl function, call directly - } else if is_external { - let name = format!("{}\0", func.external_name); - kclvm_plugin_invoke(name.as_ptr() as *const i8, args, kwargs) + } else if func.is_external { + let name = format!("{}\0", func.name); + kclvm_plugin_invoke(ctx, name.as_ptr() as *const c_char, args, kwargs) } else { args_ref.list_append_unpack_first(closure); - let args = args_ref.clone().into_raw(); + let args = args_ref.clone().into_raw(ctx_ref); call_fn(ctx, args, kwargs) }; + let is_in_schema = ptr_as_ref(is_in_schema); + if is_schema && !is_in_schema.is_truthy() { + let schema_value = ptr_as_ref(value); + schema_value.schema_check_attr_optional(ctx_ref, true); + } + if ctx_ref.cfg.debug_mode { + ctx_ref.backtrace.pop(); + } ctx_ref.panic_info = now_meta_info; return value; }; } - kclvm_value_None() -} - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_value_function_get_closure( - p: *const kclvm_value_ref_t, -) -> *mut kclvm_value_ref_t { - let p = ptr_as_ref(p); - match &*p.rc { - Value::func_value(ref v) => v.closure.deep_copy().into_raw(), - Value::none | Value::undefined => kclvm_value_None(), - _ => panic!("invalid value of function self value function"), - } + kclvm_value_Undefined(ctx) } // ---------------------------------------------------------------------------- // values: method // ---------------------------------------------------------------------------- -// kind - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_value_kind(p: *const kclvm_value_ref_t) -> kclvm_kind_t { - let p = ptr_as_ref(p); - p.kind() -} - // clone #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_value_deep_copy(p: *const kclvm_value_ref_t) -> *mut kclvm_value_ref_t { +pub unsafe extern "C" fn kclvm_value_deep_copy( + ctx: *mut kclvm_context_t, + p: *const kclvm_value_ref_t, +) -> *mut kclvm_value_ref_t { let p = ptr_as_ref(p); - p.deep_copy().into_raw() + let ctx = mut_ptr_as_ref(ctx); + p.deep_copy().into_raw(ctx) } // delete #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_value_delete(p: *mut kclvm_value_ref_t) { +pub unsafe extern "C" fn kclvm_value_delete(p: *mut kclvm_value_ref_t) { if p.is_null() { return; } - unsafe { - if p as usize == kclvm_value_Undefined_obj { - return; - } - if p as usize == kclvm_value_None_obj { - return; - } - if p as usize == kclvm_value_Bool_true_obj { - return; - } - if p as usize == kclvm_value_Bool_false_obj { - return; - } - - if p as usize == kclvm_value_Int_0_obj { - return; - } - if p as usize == kclvm_value_Float_0_obj { - return; - } - } + let val = ptr_as_ref(p); + val.from_raw(); free_mut_ptr(p); } @@ -716,28 +663,30 @@ pub extern "C" fn kclvm_value_delete(p: *mut kclvm_value_ref_t) { #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_value_iter(p: *const kclvm_value_ref_t) -> *mut kclvm_iterator_t { +pub unsafe extern "C" fn kclvm_value_iter(p: *const kclvm_value_ref_t) -> *mut kclvm_iterator_t { let p = ptr_as_ref(p); let iter = ValueIterator::from_value(p); - new_mut_ptr(iter) + Box::into_raw(Box::new(iter)) } #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_iterator_delete(p: *mut kclvm_iterator_t) { +pub unsafe extern "C" fn kclvm_iterator_delete(p: *mut kclvm_iterator_t) { free_mut_ptr(p); } #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_iterator_is_end(p: *mut kclvm_iterator_t) -> kclvm_bool_t { +pub unsafe extern "C" fn kclvm_iterator_is_end(p: *mut kclvm_iterator_t) -> kclvm_bool_t { let p = ptr_as_ref(p); p.is_end() as kclvm_bool_t } #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_iterator_cur_key(p: *mut kclvm_iterator_t) -> *const kclvm_value_ref_t { +pub unsafe extern "C" fn kclvm_iterator_cur_key( + p: *mut kclvm_iterator_t, +) -> *const kclvm_value_ref_t { let p = ptr_as_ref(p); match p.key() { Some(x) => x, @@ -747,7 +696,9 @@ pub extern "C" fn kclvm_iterator_cur_key(p: *mut kclvm_iterator_t) -> *const kcl #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_iterator_cur_value(p: *mut kclvm_iterator_t) -> *const kclvm_value_ref_t { +pub unsafe extern "C" fn kclvm_iterator_cur_value( + p: *mut kclvm_iterator_t, +) -> *const kclvm_value_ref_t { let p = mut_ptr_as_ref(p); match p.value() { Some(x) => x, @@ -757,7 +708,7 @@ pub extern "C" fn kclvm_iterator_cur_value(p: *mut kclvm_iterator_t) -> *const k #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_iterator_next_value( +pub unsafe extern "C" fn kclvm_iterator_next_value( p: *mut kclvm_iterator_t, host: *const kclvm_value_ref_t, ) -> *const kclvm_value_ref_t { @@ -776,21 +727,21 @@ pub extern "C" fn kclvm_iterator_next_value( #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_list_len(p: *const kclvm_value_ref_t) -> kclvm_size_t { +pub unsafe extern "C" fn kclvm_list_len(p: *const kclvm_value_ref_t) -> kclvm_size_t { let p = ptr_as_ref(p); p.len() as kclvm_size_t } #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_list_resize(p: *mut kclvm_value_ref_t, newsize: kclvm_size_t) { +pub unsafe extern "C" fn kclvm_list_resize(p: *mut kclvm_value_ref_t, newsize: kclvm_size_t) { let p = mut_ptr_as_ref(p); p.list_resize(newsize as usize); } #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_list_clear(p: *mut kclvm_value_ref_t) { +pub unsafe extern "C" fn kclvm_list_clear(p: *mut kclvm_value_ref_t) { let p = mut_ptr_as_ref(p); p.list_clear(); } @@ -798,21 +749,24 @@ pub extern "C" fn kclvm_list_clear(p: *mut kclvm_value_ref_t) { /// Return number of occurrences of the list value. #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_list_count( +pub unsafe extern "C" fn kclvm_list_count( + ctx: *mut kclvm_context_t, p: *const kclvm_value_ref_t, item: *const kclvm_value_ref_t, ) -> *const kclvm_value_ref_t { let p = ptr_as_ref(p); let item = ptr_as_ref(item); let count = p.list_count(item); + let ctx = mut_ptr_as_ref(ctx); let count_value = ValueRef::int(count as i64); - count_value.into_raw() + count_value.into_raw(ctx) } /// Return first index of the list value. Panic if the value is not present. #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_list_find( +pub unsafe extern "C" fn kclvm_list_find( + ctx: *mut kclvm_context_t, p: *const kclvm_value_ref_t, item: *const kclvm_value_ref_t, ) -> *const kclvm_value_ref_t { @@ -820,13 +774,14 @@ pub extern "C" fn kclvm_list_find( let item = ptr_as_ref(item); let index = p.list_find(item); let index_value = ValueRef::int(index as i64); - index_value.into_raw() + let ctx = mut_ptr_as_ref(ctx); + index_value.into_raw(ctx) } /// Insert object before index of the list value. #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_list_insert( +pub unsafe extern "C" fn kclvm_list_insert( p: *mut kclvm_value_ref_t, index: *const kclvm_value_ref_t, value: *const kclvm_value_ref_t, @@ -839,33 +794,37 @@ pub extern "C" fn kclvm_list_insert( #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_list_get( +pub unsafe extern "C" fn kclvm_list_get( + ctx: *mut kclvm_context_t, p: *const kclvm_value_ref_t, i: kclvm_size_t, ) -> *const kclvm_value_ref_t { let p = ptr_as_ref(p); + let ctx = mut_ptr_as_ref(ctx); match p.list_get(i as isize) { - Some(x) => x, + Some(x) => x.into_raw(ctx), _ => panic!("list index out of range"), } } #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_list_get_option( +pub unsafe extern "C" fn kclvm_list_get_option( + ctx: *mut kclvm_context_t, p: *const kclvm_value_ref_t, i: kclvm_size_t, ) -> *const kclvm_value_ref_t { let p = ptr_as_ref(p); + match p.list_get_option(i as isize) { - Some(x) => x.clone().into_raw(), - _ => kclvm_value_Undefined(), + Some(x) => x.into_raw(mut_ptr_as_ref(ctx)), + _ => kclvm_value_Undefined(ctx), } } #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_list_set( +pub unsafe extern "C" fn kclvm_list_set( p: *mut kclvm_value_ref_t, i: kclvm_size_t, v: *const kclvm_value_ref_t, @@ -877,27 +836,34 @@ pub extern "C" fn kclvm_list_set( #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_list_pop(p: *mut kclvm_value_ref_t) -> *const kclvm_value_ref_t { +pub unsafe extern "C" fn kclvm_list_pop( + ctx: *mut kclvm_context_t, + p: *mut kclvm_value_ref_t, +) -> *const kclvm_value_ref_t { let p = mut_ptr_as_ref(p); + match p.list_pop() { - Some(x) => x, - _ => kclvm_value_Undefined(), + Some(x) => x.into_raw(mut_ptr_as_ref(ctx)), + _ => kclvm_value_Undefined(ctx), } } #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_list_pop_first(p: *mut kclvm_value_ref_t) -> *const kclvm_value_ref_t { +pub unsafe extern "C" fn kclvm_list_pop_first( + ctx: *mut kclvm_context_t, + p: *mut kclvm_value_ref_t, +) -> *const kclvm_value_ref_t { let p = mut_ptr_as_ref(p); match p.list_pop_first() { - Some(x) => x.into_raw(), - _ => kclvm_value_Undefined(), + Some(x) => x.into_raw(mut_ptr_as_ref(ctx)), + _ => kclvm_value_Undefined(ctx), } } #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_list_append(p: *mut kclvm_value_ref_t, v: *const kclvm_value_ref_t) { +pub unsafe extern "C" fn kclvm_list_append(p: *mut kclvm_value_ref_t, v: *const kclvm_value_ref_t) { let p = mut_ptr_as_ref(p); let v = ptr_as_ref(v); p.list_append(v); @@ -905,46 +871,49 @@ pub extern "C" fn kclvm_list_append(p: *mut kclvm_value_ref_t, v: *const kclvm_v #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_list_append_bool(p: *mut kclvm_value_ref_t, v: kclvm_bool_t) { +pub unsafe extern "C" fn kclvm_list_append_bool(p: *mut kclvm_value_ref_t, v: kclvm_bool_t) { let p = mut_ptr_as_ref(p); p.list_append(&ValueRef::bool(v != 0)); } #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_list_append_int(p: *mut kclvm_value_ref_t, v: kclvm_int_t) { +pub unsafe extern "C" fn kclvm_list_append_int(p: *mut kclvm_value_ref_t, v: kclvm_int_t) { let p = mut_ptr_as_ref(p); p.list_append(&ValueRef::int(v)); } #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_list_append_float(p: *mut kclvm_value_ref_t, v: kclvm_float_t) { +pub unsafe extern "C" fn kclvm_list_append_float(p: *mut kclvm_value_ref_t, v: kclvm_float_t) { let p = mut_ptr_as_ref(p); p.list_append(&ValueRef::float(v)); } #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_list_append_str(p: *mut kclvm_value_ref_t, v: *const kclvm_char_t) { +pub unsafe extern "C" fn kclvm_list_append_str(p: *mut kclvm_value_ref_t, v: *const kclvm_char_t) { let p = mut_ptr_as_ref(p); p.list_append(&ValueRef::str(c2str(v))); } #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_list_append_unpack(p: *mut kclvm_value_ref_t, v: *const kclvm_value_ref_t) { +pub unsafe extern "C" fn kclvm_list_append_unpack( + p: *mut kclvm_value_ref_t, + v: *const kclvm_value_ref_t, +) { let p = mut_ptr_as_ref(p); let v = ptr_as_ref(v); - if let Value::list_value(ref _list) = &*p.rc { + if p.is_list() { p.list_append_unpack(v); } } #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_list_remove_at(p: *mut kclvm_value_ref_t, i: kclvm_size_t) { +pub unsafe extern "C" fn kclvm_list_remove_at(p: *mut kclvm_value_ref_t, i: kclvm_size_t) { let p = mut_ptr_as_ref(p); p.list_remove_at(i as usize); } @@ -955,9 +924,9 @@ pub extern "C" fn kclvm_list_remove_at(p: *mut kclvm_value_ref_t, i: kclvm_size_ #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_dict_len(p: *const kclvm_value_ref_t) -> kclvm_size_t { +pub unsafe extern "C" fn kclvm_dict_len(p: *const kclvm_value_ref_t) -> kclvm_size_t { let p = ptr_as_ref(p); - match &*p.rc { + match &*p.rc.borrow() { Value::dict_value(ref dict) => dict.values.len() as kclvm_size_t, _ => 0, } @@ -965,14 +934,31 @@ pub extern "C" fn kclvm_dict_len(p: *const kclvm_value_ref_t) -> kclvm_size_t { #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_dict_clear(p: *mut kclvm_value_ref_t) { +pub unsafe extern "C" fn kclvm_dict_clear(p: *mut kclvm_value_ref_t) { let p = mut_ptr_as_ref(p); p.dict_clear(); } #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_dict_get( +pub unsafe extern "C" fn kclvm_dict_is_override_attr( + p: *const kclvm_value_ref_t, + key: *const kclvm_char_t, +) -> kclvm_bool_t { + let p = ptr_as_ref(p); + let key = c2str(key); + let is_override_op = matches!( + p.dict_get_attr_operator(key), + Some(ConfigEntryOperationKind::Override) + ); + let without_index = matches!(p.dict_get_insert_index(key), Some(-1) | None); + (is_override_op && without_index) as kclvm_bool_t +} + +#[no_mangle] +#[runtime_fn] +pub unsafe extern "C" fn kclvm_dict_get( + ctx: *mut kclvm_context_t, p: *const kclvm_value_ref_t, key: *const kclvm_value_ref_t, ) -> *const kclvm_value_ref_t { @@ -980,14 +966,14 @@ pub extern "C" fn kclvm_dict_get( let key = ptr_as_ref(key); match p.dict_get(key) { - Some(x) => x.clone().into_raw(), - None => kclvm_value_Undefined(), + Some(x) => x.into_raw(mut_ptr_as_ref(ctx)), + None => kclvm_value_Undefined(ctx), } } #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_dict_has_value( +pub unsafe extern "C" fn kclvm_dict_has_value( p: *const kclvm_value_ref_t, key: *const kclvm_char_t, ) -> kclvm_bool_t { @@ -1001,49 +987,53 @@ pub extern "C" fn kclvm_dict_has_value( #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_dict_get_value( +pub unsafe extern "C" fn kclvm_dict_get_value( + ctx: *mut kclvm_context_t, p: *const kclvm_value_ref_t, key: *const kclvm_char_t, ) -> *const kclvm_value_ref_t { let p = ptr_as_ref(p); let key = c2str(key); match p.dict_get_value(key) { - Some(x) => x.clone().into_raw(), - None => kclvm_value_Undefined(), + Some(x) => x.into_raw(mut_ptr_as_ref(ctx)), + None => kclvm_value_Undefined(ctx), } } #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_dict_get_entry( +pub unsafe extern "C" fn kclvm_dict_get_entry( + ctx: *mut kclvm_context_t, p: *const kclvm_value_ref_t, key: *const kclvm_char_t, ) -> *const kclvm_value_ref_t { let p = ptr_as_ref(p); let key = c2str(key); match p.dict_get_entry(key) { - Some(x) => x.into_raw(), - None => kclvm_value_Undefined(), + Some(x) => x.into_raw(mut_ptr_as_ref(ctx)), + None => kclvm_value_Undefined(ctx), } } #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_dict_get_value_by_path( +pub unsafe extern "C" fn kclvm_dict_get_value_by_path( + ctx: *mut kclvm_context_t, p: *const kclvm_value_ref_t, path: *const kclvm_char_t, ) -> *const kclvm_value_ref_t { let p = ptr_as_ref(p); let path = c2str(path); match p.get_by_path(path) { - Some(x) => x.clone().into_raw(), - None => kclvm_value_Undefined(), + Some(x) => x.into_raw(mut_ptr_as_ref(ctx)), + None => kclvm_value_Undefined(ctx), } } #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_dict_set_value( +pub unsafe extern "C" fn kclvm_dict_set_value( + ctx: *mut kclvm_context_t, p: *mut kclvm_value_ref_t, key: *const kclvm_char_t, val: *const kclvm_value_ref_t, @@ -1053,110 +1043,156 @@ pub extern "C" fn kclvm_dict_set_value( let val = ptr_as_ref(val); if p.is_config() { p.dict_update_key_value(key, val.clone()); + if p.is_schema() { + let schema: ValueRef; + { + let schema_value = p.as_schema(); + let mut config_keys = schema_value.config_keys.clone(); + config_keys.push(key.to_string()); + schema = resolve_schema(mut_ptr_as_ref(ctx), p, &config_keys); + } + p.schema_update_with_schema(&schema); + } + } else { + panic!( + "failed to update the dict. An iterable of key-value pairs was expected, but got {}. Check if the syntax for updating the dictionary with the attribute '{}' is correct", + p.type_str(), + key + ); } - if p.is_schema() { - let schema_value = p.as_schema(); - let mut config_keys = schema_value.config_keys.clone(); - config_keys.push(key.to_string()); - let schema = resolve_schema(p, &config_keys); - p.schema_update_with_schema(&schema); - } - /*panic*/ } #[no_mangle] #[runtime_fn] /// Return all dict keys. -pub extern "C" fn kclvm_dict_keys(p: *const kclvm_value_ref_t) -> *const kclvm_value_ref_t { +pub unsafe extern "C" fn kclvm_dict_keys( + ctx: *mut kclvm_context_t, + p: *const kclvm_value_ref_t, +) -> *const kclvm_value_ref_t { let p = ptr_as_ref(p); let r = p.dict_keys(); - r.into_raw() + r.into_raw(mut_ptr_as_ref(ctx)) } #[no_mangle] #[runtime_fn] /// Return all dict values. -pub extern "C" fn kclvm_dict_values(p: *const kclvm_value_ref_t) -> *const kclvm_value_ref_t { +pub unsafe extern "C" fn kclvm_dict_values( + ctx: *mut kclvm_context_t, + p: *const kclvm_value_ref_t, +) -> *const kclvm_value_ref_t { let p = ptr_as_ref(p); let r = p.dict_values(); - r.into_raw() + r.into_raw(mut_ptr_as_ref(ctx)) } #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_dict_insert( +pub unsafe extern "C" fn kclvm_dict_insert( + ctx: *mut kclvm_context_t, p: *mut kclvm_value_ref_t, key: *const kclvm_char_t, v: *const kclvm_value_ref_t, op: kclvm_size_t, insert_index: kclvm_size_t, + has_insert_index: kclvm_bool_t, ) { let p = mut_ptr_as_ref(p); let v = ptr_as_ref(v); p.dict_insert( + mut_ptr_as_ref(ctx), c2str(key), v, ConfigEntryOperationKind::from_i32(op), - insert_index, + if has_insert_index != 0 { + Some(insert_index) + } else { + None + }, ); } #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_dict_merge( +pub unsafe extern "C" fn kclvm_dict_merge( + ctx: *mut kclvm_context_t, p: *mut kclvm_value_ref_t, key: *const kclvm_char_t, v: *const kclvm_value_ref_t, op: kclvm_size_t, insert_index: kclvm_size_t, + has_insert_index: kclvm_bool_t, ) { let p = mut_ptr_as_ref(p); let v = ptr_as_ref(v); let key = c2str(key); + let ctx = mut_ptr_as_ref(ctx); let attr_map = { - match &*p.rc { - Value::dict_value(dict) => &dict.attr_map, - Value::schema_value(schema) => &schema.config.attr_map, + match &*p.rc.borrow() { + Value::dict_value(dict) => dict.attr_map.clone(), + Value::schema_value(schema) => schema.config.attr_map.clone(), _ => panic!("invalid object '{}' in attr_map", p.type_str()), } }; if attr_map.contains_key(key) { - let v = type_pack_and_check(v, vec![attr_map.get(key).unwrap()]); + let v = type_pack_and_check(ctx, v, vec![attr_map.get(key).unwrap()], false); p.dict_merge( + ctx, key, &v, ConfigEntryOperationKind::from_i32(op), - insert_index, + if has_insert_index != 0 { + Some(insert_index) + } else { + None + }, ); } else { - p.dict_merge(key, v, ConfigEntryOperationKind::from_i32(op), insert_index); + p.dict_merge( + ctx, + key, + v, + ConfigEntryOperationKind::from_i32(op), + if has_insert_index != 0 { + Some(insert_index) + } else { + None + }, + ); } } #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_dict_insert_value( +pub unsafe extern "C" fn kclvm_dict_insert_value( + ctx: *mut kclvm_context_t, p: *mut kclvm_value_ref_t, key: *const kclvm_value_ref_t, v: *const kclvm_value_ref_t, op: kclvm_size_t, insert_index: kclvm_size_t, + has_insert_index: kclvm_bool_t, ) { let p = mut_ptr_as_ref(p); let v = ptr_as_ref(v); let key = ptr_as_ref(key); let key = key.attr_str(); p.dict_insert( + mut_ptr_as_ref(ctx), key.as_str(), v, ConfigEntryOperationKind::from_i32(op), - insert_index, + if has_insert_index != 0 { + Some(insert_index) + } else { + None + }, ); } #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_dict_update_key_value( +pub unsafe extern "C" fn kclvm_dict_update_key_value( p: *mut kclvm_value_ref_t, key: *const kclvm_value_ref_t, v: *const kclvm_value_ref_t, @@ -1170,30 +1206,37 @@ pub extern "C" fn kclvm_dict_update_key_value( #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_dict_safe_insert( +pub unsafe extern "C" fn kclvm_dict_safe_insert( + ctx: *mut kclvm_context_t, p: *mut kclvm_value_ref_t, key: *const kclvm_char_t, v: *const kclvm_value_ref_t, op: kclvm_size_t, insert_index: kclvm_size_t, + has_insert_index: kclvm_bool_t, ) { if p.is_null() || key.is_null() || v.is_null() { return; } - kclvm_dict_insert(p, key, v, op, insert_index); + kclvm_dict_insert(ctx, p, key, v, op, insert_index, has_insert_index); } #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_dict_insert_unpack(p: *mut kclvm_value_ref_t, v: *const kclvm_value_ref_t) { +pub unsafe extern "C" fn kclvm_dict_insert_unpack( + ctx: *mut kclvm_context_t, + p: *mut kclvm_value_ref_t, + v: *const kclvm_value_ref_t, +) { let p = mut_ptr_as_ref(p); + let ctx = mut_ptr_as_ref(ctx); let v = ptr_as_ref(v); - p.dict_insert_unpack(v); + p.dict_insert_unpack(ctx, v); } #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_default_collection_insert_int_pointer( +pub unsafe extern "C" fn kclvm_default_collection_insert_int_pointer( p: *mut kclvm_value_ref_t, key: *const kclvm_char_t, ptr: *const u64, @@ -1202,7 +1245,7 @@ pub extern "C" fn kclvm_default_collection_insert_int_pointer( let key = c2str(key); let ptr = ptr as i64; if p.is_dict() { - let dict_ref_mut = p.as_dict_mut_ref(); + let mut dict_ref_mut = p.as_dict_mut_ref(); if !dict_ref_mut.values.contains_key(key) { let value = ValueRef::list(None); dict_ref_mut.values.insert(key.to_string(), value); @@ -1217,7 +1260,7 @@ pub extern "C" fn kclvm_default_collection_insert_int_pointer( #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_default_collection_insert_value( +pub unsafe extern "C" fn kclvm_default_collection_insert_value( p: *mut kclvm_value_ref_t, key: *const kclvm_char_t, value: *const kclvm_value_ref_t, @@ -1226,7 +1269,7 @@ pub extern "C" fn kclvm_default_collection_insert_value( let key = c2str(key); let value = ptr_as_ref(value); if p.is_dict() { - let dict_ref_mut = p.as_dict_mut_ref(); + let mut dict_ref_mut = p.as_dict_mut_ref(); if !dict_ref_mut.values.contains_key(key) { let value = ValueRef::list(None); dict_ref_mut.values.insert(key.to_string(), value); @@ -1240,14 +1283,14 @@ pub extern "C" fn kclvm_default_collection_insert_value( #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_dict_remove(p: *mut kclvm_value_ref_t, key: *const kclvm_char_t) { +pub unsafe extern "C" fn kclvm_dict_remove(p: *mut kclvm_value_ref_t, key: *const kclvm_char_t) { let p = mut_ptr_as_ref(p); p.dict_remove(c2str(key)); } #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_dict_update(p: *mut kclvm_value_ref_t, v: *const kclvm_value_ref_t) { +pub unsafe extern "C" fn kclvm_dict_update(p: *mut kclvm_value_ref_t, v: *const kclvm_value_ref_t) { let p = mut_ptr_as_ref(p); let v = ptr_as_ref(v); p.dict_update(v); @@ -1261,7 +1304,7 @@ pub extern "C" fn kclvm_dict_update(p: *mut kclvm_value_ref_t, v: *const kclvm_v #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_value_is_truthy(p: *const kclvm_value_ref_t) -> kclvm_bool_t { +pub unsafe extern "C" fn kclvm_value_is_truthy(p: *const kclvm_value_ref_t) -> kclvm_bool_t { let p = ptr_as_ref(p); p.is_truthy() as kclvm_bool_t } @@ -1270,7 +1313,7 @@ pub extern "C" fn kclvm_value_is_truthy(p: *const kclvm_value_ref_t) -> kclvm_bo #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_value_len(p: *const kclvm_value_ref_t) -> kclvm_size_t { +pub unsafe extern "C" fn kclvm_value_len(p: *const kclvm_value_ref_t) -> kclvm_size_t { let p = ptr_as_ref(p); p.len() as kclvm_size_t } @@ -1279,349 +1322,399 @@ pub extern "C" fn kclvm_value_len(p: *const kclvm_value_ref_t) -> kclvm_size_t { #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_value_cmp_equal_to( +pub unsafe extern "C" fn kclvm_value_cmp_equal_to( + ctx: *mut kclvm_context_t, a: *const kclvm_value_ref_t, b: *const kclvm_value_ref_t, ) -> *mut kclvm_value_ref_t { if a == b { - return kclvm_value_Bool(1); + return kclvm_value_Bool(ctx, 1); } let a = ptr_as_ref(a); let b = ptr_as_ref(b); - ValueRef::bool(a.cmp_equal(b)).into_raw() + ValueRef::bool(a.cmp_equal(b)).into_raw(mut_ptr_as_ref(ctx)) } #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_value_cmp_not_equal_to( +pub unsafe extern "C" fn kclvm_value_cmp_not_equal_to( + ctx: *mut kclvm_context_t, a: *const kclvm_value_ref_t, b: *const kclvm_value_ref_t, ) -> *mut kclvm_value_ref_t { if a == b { - return kclvm_value_Bool(0); + return kclvm_value_Bool(ctx, 0); } let a = ptr_as_ref(a); let b = ptr_as_ref(b); - ValueRef::bool(!a.cmp_equal(b)).into_raw() + ValueRef::bool(!a.cmp_equal(b)).into_raw(mut_ptr_as_ref(ctx)) } #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_value_cmp_less_than( +pub unsafe extern "C" fn kclvm_value_cmp_less_than( + ctx: *mut kclvm_context_t, a: *const kclvm_value_ref_t, b: *const kclvm_value_ref_t, ) -> *mut kclvm_value_ref_t { if a == b { - return kclvm_value_Bool(0); + return kclvm_value_Bool(ctx, 0); } let a = ptr_as_ref(a); let b = ptr_as_ref(b); - ValueRef::bool(a.cmp_less_than(b)).into_raw() + ValueRef::bool(a.cmp_less_than(b)).into_raw(mut_ptr_as_ref(ctx)) } #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_value_cmp_less_than_or_equal( +pub unsafe extern "C" fn kclvm_value_cmp_less_than_or_equal( + ctx: *mut kclvm_context_t, a: *const kclvm_value_ref_t, b: *const kclvm_value_ref_t, ) -> *mut kclvm_value_ref_t { let a = ptr_as_ref(a); let b = ptr_as_ref(b); - ValueRef::bool(a.cmp_less_than_or_equal(b)).into_raw() + ValueRef::bool(a.cmp_less_than_or_equal(b)).into_raw(mut_ptr_as_ref(ctx)) } #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_value_cmp_greater_than( +pub unsafe extern "C" fn kclvm_value_cmp_greater_than( + ctx: *mut kclvm_context_t, a: *const kclvm_value_ref_t, b: *const kclvm_value_ref_t, ) -> *mut kclvm_value_ref_t { if a == b { - return kclvm_value_Bool(0); + return kclvm_value_Bool(ctx, 0); } let a = ptr_as_ref(a); let b = ptr_as_ref(b); - ValueRef::bool(a.cmp_greater_than(b)).into_raw() + ValueRef::bool(a.cmp_greater_than(b)).into_raw(mut_ptr_as_ref(ctx)) } #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_value_cmp_greater_than_or_equal( +pub unsafe extern "C" fn kclvm_value_cmp_greater_than_or_equal( + ctx: *mut kclvm_context_t, a: *const kclvm_value_ref_t, b: *const kclvm_value_ref_t, ) -> *mut kclvm_value_ref_t { let a = ptr_as_ref(a); let b = ptr_as_ref(b); - ValueRef::bool(a.cmp_greater_than_or_equal(b)).into_raw() + ValueRef::bool(a.cmp_greater_than_or_equal(b)).into_raw(mut_ptr_as_ref(ctx)) } // is/in #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_value_is( +pub unsafe extern "C" fn kclvm_value_is( + ctx: *mut kclvm_context_t, a: *const kclvm_value_ref_t, b: *const kclvm_value_ref_t, ) -> *mut kclvm_value_ref_t { let a = ptr_as_ref(a); let b = ptr_as_ref(b); if a == b { - return kclvm_value_Bool(1); + return kclvm_value_Bool(ctx, 1); } - kclvm_value_Bool(0) + kclvm_value_Bool(ctx, 0) } #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_value_is_not( +pub unsafe extern "C" fn kclvm_value_is_not( + ctx: *mut kclvm_context_t, a: *const kclvm_value_ref_t, b: *const kclvm_value_ref_t, ) -> *mut kclvm_value_ref_t { let a = ptr_as_ref(a); let b = ptr_as_ref(b); if a == b { - return kclvm_value_Bool(0); + return kclvm_value_Bool(ctx, 0); } - kclvm_value_Bool(1) + kclvm_value_Bool(ctx, 1) } #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_value_in( +pub unsafe extern "C" fn kclvm_value_in( + ctx: *mut kclvm_context_t, a: *const kclvm_value_ref_t, b: *const kclvm_value_ref_t, ) -> *mut kclvm_value_ref_t { let a = ptr_as_ref(a); let b = ptr_as_ref(b); - ValueRef::bool(a.r#in(b)).into_raw() + ValueRef::bool(a.r#in(b)).into_raw(mut_ptr_as_ref(ctx)) } #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_value_not_in( +pub unsafe extern "C" fn kclvm_value_not_in( + ctx: *mut kclvm_context_t, a: *const kclvm_value_ref_t, b: *const kclvm_value_ref_t, ) -> *mut kclvm_value_ref_t { let a = ptr_as_ref(a); let b = ptr_as_ref(b); - ValueRef::bool(a.not_in(b)).into_raw() + ValueRef::bool(a.not_in(b)).into_raw(mut_ptr_as_ref(ctx)) } #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_value_as( +pub unsafe extern "C" fn kclvm_value_as( + ctx: *mut kclvm_context_t, a: *const kclvm_value_ref_t, b: *const kclvm_value_ref_t, ) -> *mut kclvm_value_ref_t { let a = ptr_as_ref(a); let b = ptr_as_ref(b); let ty_str = b.as_str(); - let value = type_pack_and_check(a, vec![ty_str.as_str()]); - value.into_raw() + let ctx = mut_ptr_as_ref(ctx); + let value = type_pack_and_check(ctx, a, vec![ty_str.as_str()], true); + value.into_raw(ctx) } // unary-xxx #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_value_unary_plus(a: *const kclvm_value_ref_t) -> *mut kclvm_value_ref_t { +pub unsafe extern "C" fn kclvm_value_unary_plus( + ctx: *mut kclvm_context_t, + a: *const kclvm_value_ref_t, +) -> *mut kclvm_value_ref_t { let a = ptr_as_ref(a); - a.unary_plus().into_raw() + a.unary_plus().into_raw(mut_ptr_as_ref(ctx)) } #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_value_unary_minus(a: *const kclvm_value_ref_t) -> *mut kclvm_value_ref_t { +pub unsafe extern "C" fn kclvm_value_unary_minus( + ctx: *mut kclvm_context_t, + a: *const kclvm_value_ref_t, +) -> *mut kclvm_value_ref_t { let a = ptr_as_ref(a); - a.unary_minus().into_raw() + a.unary_minus().into_raw(mut_ptr_as_ref(ctx)) } #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_value_unary_not(a: *const kclvm_value_ref_t) -> *mut kclvm_value_ref_t { +pub unsafe extern "C" fn kclvm_value_unary_not( + ctx: *mut kclvm_context_t, + a: *const kclvm_value_ref_t, +) -> *mut kclvm_value_ref_t { let a = ptr_as_ref(a); - a.unary_not().into_raw() + a.unary_not().into_raw(mut_ptr_as_ref(ctx)) } #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_value_unary_l_not(a: *const kclvm_value_ref_t) -> *mut kclvm_value_ref_t { +pub unsafe extern "C" fn kclvm_value_unary_l_not( + ctx: *mut kclvm_context_t, + a: *const kclvm_value_ref_t, +) -> *mut kclvm_value_ref_t { let a = ptr_as_ref(a); - a.unary_l_not().into_raw() + a.unary_l_not().into_raw(mut_ptr_as_ref(ctx)) } // op-xxx #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_value_op_add( +pub unsafe extern "C" fn kclvm_value_op_add( + ctx: *mut kclvm_context_t, a: *const kclvm_value_ref_t, b: *const kclvm_value_ref_t, ) -> *mut kclvm_value_ref_t { let a = ptr_as_ref(a); let b = ptr_as_ref(b); - a.bin_add(b).into_raw() + let ctx = mut_ptr_as_ref(ctx); + a.bin_add(ctx, b).into_raw(ctx) } #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_value_op_sub( +pub unsafe extern "C" fn kclvm_value_op_sub( + ctx: *mut kclvm_context_t, a: *const kclvm_value_ref_t, b: *const kclvm_value_ref_t, ) -> *mut kclvm_value_ref_t { let a = ptr_as_ref(a); let b = ptr_as_ref(b); - a.bin_sub(b).into_raw() + let ctx = mut_ptr_as_ref(ctx); + a.bin_sub(ctx, b).into_raw(ctx) } #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_value_op_mul( +pub unsafe extern "C" fn kclvm_value_op_mul( + ctx: *mut kclvm_context_t, a: *const kclvm_value_ref_t, b: *const kclvm_value_ref_t, ) -> *mut kclvm_value_ref_t { let a = ptr_as_ref(a); let b = ptr_as_ref(b); - a.bin_mul(b).into_raw() + let ctx = mut_ptr_as_ref(ctx); + a.bin_mul(ctx, b).into_raw(ctx) } #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_value_op_div( +pub unsafe extern "C" fn kclvm_value_op_div( + ctx: *mut kclvm_context_t, a: *const kclvm_value_ref_t, b: *const kclvm_value_ref_t, ) -> *mut kclvm_value_ref_t { let a = ptr_as_ref(a); let b = ptr_as_ref(b); - a.bin_div(b).into_raw() + a.bin_div(b).into_raw(mut_ptr_as_ref(ctx)) } #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_value_op_mod( +pub unsafe extern "C" fn kclvm_value_op_mod( + ctx: *mut kclvm_context_t, a: *const kclvm_value_ref_t, b: *const kclvm_value_ref_t, ) -> *mut kclvm_value_ref_t { let a = ptr_as_ref(a); let b = ptr_as_ref(b); - a.bin_mod(b).into_raw() + a.bin_mod(b).into_raw(mut_ptr_as_ref(ctx)) } #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_value_op_pow( +pub unsafe extern "C" fn kclvm_value_op_pow( + ctx: *mut kclvm_context_t, a: *const kclvm_value_ref_t, b: *const kclvm_value_ref_t, ) -> *mut kclvm_value_ref_t { let a = ptr_as_ref(a); let b = ptr_as_ref(b); - a.bin_pow(b).into_raw() + let ctx = mut_ptr_as_ref(ctx); + a.bin_pow(ctx, b).into_raw(ctx) } #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_value_op_floor_div( +pub unsafe extern "C" fn kclvm_value_op_floor_div( + ctx: *mut kclvm_context_t, a: *const kclvm_value_ref_t, b: *const kclvm_value_ref_t, ) -> *mut kclvm_value_ref_t { let a = ptr_as_ref(a); let b = ptr_as_ref(b); - a.bin_floor_div(b).into_raw() + a.bin_floor_div(b).into_raw(mut_ptr_as_ref(ctx)) } #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_value_op_bit_lshift( +pub unsafe extern "C" fn kclvm_value_op_bit_lshift( + ctx: *mut kclvm_context_t, a: *const kclvm_value_ref_t, b: *const kclvm_value_ref_t, ) -> *mut kclvm_value_ref_t { let a = ptr_as_ref(a); let b = ptr_as_ref(b); - a.bin_bit_lshift(b).into_raw() + let ctx = mut_ptr_as_ref(ctx); + a.bin_bit_lshift(ctx, b).into_raw(ctx) } #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_value_op_bit_rshift( +pub unsafe extern "C" fn kclvm_value_op_bit_rshift( + ctx: *mut kclvm_context_t, a: *const kclvm_value_ref_t, b: *const kclvm_value_ref_t, ) -> *mut kclvm_value_ref_t { let a = ptr_as_ref(a); let b = ptr_as_ref(b); - a.bin_bit_rshift(b).into_raw() + let ctx = mut_ptr_as_ref(ctx); + a.bin_bit_rshift(ctx, b).into_raw(ctx) } #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_value_op_bit_and( +pub unsafe extern "C" fn kclvm_value_op_bit_and( + ctx: *mut kclvm_context_t, a: *const kclvm_value_ref_t, b: *const kclvm_value_ref_t, ) -> *mut kclvm_value_ref_t { let a = ptr_as_ref(a); let b = ptr_as_ref(b); - a.bin_bit_and(b).into_raw() + a.bin_bit_and(b).into_raw(mut_ptr_as_ref(ctx)) } #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_value_op_bit_xor( +pub unsafe extern "C" fn kclvm_value_op_bit_xor( + ctx: *mut kclvm_context_t, a: *const kclvm_value_ref_t, b: *const kclvm_value_ref_t, ) -> *mut kclvm_value_ref_t { let a = ptr_as_ref(a); let b = ptr_as_ref(b); - a.bin_bit_xor(b).into_raw() + a.bin_bit_xor(b).into_raw(mut_ptr_as_ref(ctx)) } #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_value_op_bit_or( +pub unsafe extern "C" fn kclvm_value_op_bit_or( + ctx: *mut kclvm_context_t, a: *const kclvm_value_ref_t, b: *const kclvm_value_ref_t, ) -> *mut kclvm_value_ref_t { let a = ptr_as_ref(a); let b = ptr_as_ref(b); - a.bin_bit_or(b).into_raw() + let ctx = mut_ptr_as_ref(ctx); + a.bin_bit_or(ctx, b).into_raw(ctx) } // op-aug-xxx #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_value_op_aug_add( +pub unsafe extern "C" fn kclvm_value_op_aug_add( + ctx: *mut kclvm_context_t, a: *mut kclvm_value_ref_t, b: *const kclvm_value_ref_t, ) -> *const kclvm_value_ref_t { let a = mut_ptr_as_ref(a); let b = ptr_as_ref(b); - return a.bin_aug_add(b) as *const kclvm_value_ref_t; + let ctx = mut_ptr_as_ref(ctx); + return a.bin_aug_add(ctx, b) as *const kclvm_value_ref_t; } #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_value_op_aug_sub( +pub unsafe extern "C" fn kclvm_value_op_aug_sub( + ctx: *mut kclvm_context_t, a: *mut kclvm_value_ref_t, b: *const kclvm_value_ref_t, ) -> *const kclvm_value_ref_t { let a = mut_ptr_as_ref(a); let b = ptr_as_ref(b); - return a.bin_aug_sub(b) as *const kclvm_value_ref_t; + let ctx = mut_ptr_as_ref(ctx); + return a.bin_aug_sub(ctx, b) as *const kclvm_value_ref_t; } #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_value_op_aug_mul( +pub unsafe extern "C" fn kclvm_value_op_aug_mul( + ctx: *mut kclvm_context_t, a: *mut kclvm_value_ref_t, b: *const kclvm_value_ref_t, ) -> *const kclvm_value_ref_t { let a = mut_ptr_as_ref(a); let b = ptr_as_ref(b); - return a.bin_aug_mul(b) as *const kclvm_value_ref_t; + let ctx = mut_ptr_as_ref(ctx); + return a.bin_aug_mul(ctx, b); } #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_value_op_aug_div( +pub unsafe extern "C" fn kclvm_value_op_aug_div( + _ctx: *mut kclvm_context_t, a: *mut kclvm_value_ref_t, b: *const kclvm_value_ref_t, ) -> *const kclvm_value_ref_t { @@ -1632,7 +1725,8 @@ pub extern "C" fn kclvm_value_op_aug_div( #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_value_op_aug_mod( +pub unsafe extern "C" fn kclvm_value_op_aug_mod( + _ctx: *mut kclvm_context_t, a: *mut kclvm_value_ref_t, b: *const kclvm_value_ref_t, ) -> *const kclvm_value_ref_t { @@ -1643,18 +1737,21 @@ pub extern "C" fn kclvm_value_op_aug_mod( #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_value_op_aug_pow( +pub unsafe extern "C" fn kclvm_value_op_aug_pow( + ctx: *mut kclvm_context_t, a: *mut kclvm_value_ref_t, b: *const kclvm_value_ref_t, ) -> *const kclvm_value_ref_t { let a = mut_ptr_as_ref(a); let b = ptr_as_ref(b); - return a.bin_aug_pow(b) as *const kclvm_value_ref_t; + let ctx = mut_ptr_as_ref(ctx); + return a.bin_aug_pow(ctx, b) as *const kclvm_value_ref_t; } #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_value_op_aug_floor_div( +pub unsafe extern "C" fn kclvm_value_op_aug_floor_div( + _ctx: *mut kclvm_context_t, a: *mut kclvm_value_ref_t, b: *const kclvm_value_ref_t, ) -> *const kclvm_value_ref_t { @@ -1665,29 +1762,34 @@ pub extern "C" fn kclvm_value_op_aug_floor_div( #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_value_op_aug_bit_lshift( +pub unsafe extern "C" fn kclvm_value_op_aug_bit_lshift( + ctx: *mut kclvm_context_t, a: *mut kclvm_value_ref_t, b: *const kclvm_value_ref_t, ) -> *const kclvm_value_ref_t { let a = mut_ptr_as_ref(a); let b = ptr_as_ref(b); - a.bin_aug_bit_lshift(b) as *const kclvm_value_ref_t + let ctx = mut_ptr_as_ref(ctx); + a.bin_aug_bit_lshift(ctx, b) as *const kclvm_value_ref_t } #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_value_op_aug_bit_rshift( +pub unsafe extern "C" fn kclvm_value_op_aug_bit_rshift( + ctx: *mut kclvm_context_t, a: *mut kclvm_value_ref_t, b: *const kclvm_value_ref_t, ) -> *const kclvm_value_ref_t { let a = mut_ptr_as_ref(a); let b = ptr_as_ref(b); - a.bin_aug_bit_rshift(b) as *const kclvm_value_ref_t + let ctx = mut_ptr_as_ref(ctx); + a.bin_aug_bit_rshift(ctx, b) as *const kclvm_value_ref_t } #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_value_op_aug_bit_and( +pub unsafe extern "C" fn kclvm_value_op_aug_bit_and( + _ctx: *mut kclvm_context_t, a: *mut kclvm_value_ref_t, b: *const kclvm_value_ref_t, ) -> *const kclvm_value_ref_t { @@ -1698,7 +1800,8 @@ pub extern "C" fn kclvm_value_op_aug_bit_and( #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_value_op_aug_bit_xor( +pub unsafe extern "C" fn kclvm_value_op_aug_bit_xor( + _ctx: *mut kclvm_context_t, a: *mut kclvm_value_ref_t, b: *const kclvm_value_ref_t, ) -> *const kclvm_value_ref_t { @@ -1709,53 +1812,51 @@ pub extern "C" fn kclvm_value_op_aug_bit_xor( #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_value_op_aug_bit_or( +pub unsafe extern "C" fn kclvm_value_op_aug_bit_or( + ctx: *mut kclvm_context_t, a: *mut kclvm_value_ref_t, b: *const kclvm_value_ref_t, ) -> *const kclvm_value_ref_t { let a = mut_ptr_as_ref(a); let b = ptr_as_ref(b); - a.bin_aug_bit_or(b) as *const kclvm_value_ref_t + let ctx = mut_ptr_as_ref(ctx); + a.bin_aug_bit_or(ctx, b) as *const kclvm_value_ref_t } #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_value_union( +pub unsafe extern "C" fn kclvm_value_union( + ctx: *mut kclvm_context_t, schema: *mut kclvm_value_ref_t, b: *const kclvm_value_ref_t, ) -> *const kclvm_value_ref_t { let a = mut_ptr_as_ref(schema); let b = ptr_as_ref(b); - let attr_map = { - match &*a.rc { - Value::dict_value(dict) => &dict.attr_map, - Value::schema_value(schema) => &schema.config.attr_map, - _ => panic!("invalid object '{}' in attr_map", a.type_str()), - } + let ctx = mut_ptr_as_ref(ctx); + let attr_map = match &*a.rc.borrow() { + Value::dict_value(dict) => dict.attr_map.clone(), + Value::schema_value(schema) => schema.config.attr_map.clone(), + _ => panic!("invalid object '{}' in attr_map", a.type_str()), + }; + let opts = UnionOptions { + list_override: false, + idempotent_check: false, + config_resolve: true, }; if b.is_config() { let dict = b.as_dict_ref(); - let mut result = schema; - for (k, v) in &dict.values { - if attr_map.contains_key(k) { - let v = type_pack_and_check(v, vec![attr_map.get(k).unwrap()]); - let mut entry = b.dict_get_entry(k).unwrap().deep_copy(); - entry.dict_update_key_value(k, v); - result = a - .union(&entry, true, false, false, false) - .clone() - .into_raw(); - } else { - let entry = b.dict_get_entry(k).unwrap(); - result = a - .union(&entry, true, false, false, false) - .clone() - .into_raw(); + for k in dict.values.keys() { + let entry = b.dict_get_entry(k).unwrap(); + a.union_entry(ctx, &entry, true, &opts); + // Has type annotation + if let Some(ty) = attr_map.get(k) { + let value = a.dict_get_value(k).unwrap(); + a.dict_update_key_value(k, type_pack_and_check(ctx, &value, vec![ty], false)); } } - result + a.clone().into_raw(ctx) } else { - a.union(b, true, false, false, false).into_raw() + a.union_entry(ctx, b, true, &opts).into_raw(ctx) } } @@ -1763,141 +1864,101 @@ pub extern "C" fn kclvm_value_union( #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_value_logic_and( +pub unsafe extern "C" fn kclvm_value_logic_and( + ctx: *mut kclvm_context_t, a: *const kclvm_value_ref_t, b: *const kclvm_value_ref_t, ) -> *mut kclvm_value_ref_t { let a = ptr_as_ref(a); let b = ptr_as_ref(b); - ValueRef::bool(a.logic_and(b)).into_raw() + ValueRef::bool(a.logic_and(b)).into_raw(mut_ptr_as_ref(ctx)) } #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_value_logic_or( +pub unsafe extern "C" fn kclvm_value_logic_or( + ctx: *mut kclvm_context_t, a: *const kclvm_value_ref_t, b: *const kclvm_value_ref_t, ) -> *mut kclvm_value_ref_t { let a = ptr_as_ref(a); let b = ptr_as_ref(b); - ValueRef::bool(a.logic_or(b)).into_raw() + ValueRef::bool(a.logic_or(b)).into_raw(mut_ptr_as_ref(ctx)) } #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_value_subscr( +pub unsafe extern "C" fn kclvm_value_subscr( + ctx: *mut kclvm_context_t, a: *const kclvm_value_ref_t, b: *const kclvm_value_ref_t, ) -> *mut kclvm_value_ref_t { let a = ptr_as_ref(a); let b = ptr_as_ref(b); - a.bin_subscr(b).into_raw() + a.bin_subscr(b).into_raw(mut_ptr_as_ref(ctx)) } #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_value_subscr_option( +pub unsafe extern "C" fn kclvm_value_subscr_set( + ctx: *mut kclvm_context_t, + p: *mut kclvm_value_ref_t, + index: *const kclvm_value_ref_t, + val: *const kclvm_value_ref_t, +) { + let ctx = mut_ptr_as_ref(ctx); + let p = mut_ptr_as_ref(p); + let index = ptr_as_ref(index); + let val = ptr_as_ref(val); + p.bin_subscr_set(ctx, index, val); +} + +#[no_mangle] +#[runtime_fn] +pub unsafe extern "C" fn kclvm_value_subscr_option( + ctx: *mut kclvm_context_t, a: *const kclvm_value_ref_t, b: *const kclvm_value_ref_t, ) -> *mut kclvm_value_ref_t { let a = ptr_as_ref(a); let b = ptr_as_ref(b); - a.bin_subscr_option(b).into_raw() + a.bin_subscr_option(b).into_raw(mut_ptr_as_ref(ctx)) } #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_value_load_attr( +pub unsafe extern "C" fn kclvm_value_load_attr( + ctx: *mut kclvm_context_t, obj: *const kclvm_value_ref_t, key: *const kclvm_char_t, ) -> *const kclvm_value_ref_t { let p = ptr_as_ref(obj); let key = c2str(key); - // load_attr including str/dict/schema. - if p.is_dict() { - match p.dict_get_value(key) { - Some(x) => { - return x.clone().into_raw(); - } - None => { - return kclvm_value_Undefined(); - } - } - } else if p.is_schema() { - let dict = p.schema_to_dict(); - match dict.dict_get_value(key) { - Some(x) => { - return x.clone().into_raw(); - } - None => panic!("schema '{}' attribute '{}' not found", p.type_str(), key), - } - } else if p.is_str() { - let function = match key { - "lower" => kclvm_builtin_str_lower, - "upper" => kclvm_builtin_str_upper, - "capitalize" => kclvm_builtin_str_capitalize, - "count" => kclvm_builtin_str_count, - "endswith" => kclvm_builtin_str_endswith, - "find" => kclvm_builtin_str_find, - "format" => kclvm_builtin_str_format, - "index" => kclvm_builtin_str_index, - "isalnum" => kclvm_builtin_str_isalnum, - "isalpha" => kclvm_builtin_str_isalpha, - "isdigit" => kclvm_builtin_str_isdigit, - "islower" => kclvm_builtin_str_islower, - "isspace" => kclvm_builtin_str_isspace, - "istitle" => kclvm_builtin_str_istitle, - "isupper" => kclvm_builtin_str_isupper, - "join" => kclvm_builtin_str_join, - "lstrip" => kclvm_builtin_str_lstrip, - "rstrip" => kclvm_builtin_str_rstrip, - "replace" => kclvm_builtin_str_replace, - "rfind" => kclvm_builtin_str_rfind, - "rindex" => kclvm_builtin_str_rindex, - "rsplit" => kclvm_builtin_str_rsplit, - "split" => kclvm_builtin_str_split, - "splitlines" => kclvm_builtin_str_splitlines, - "startswith" => kclvm_builtin_str_startswith, - "strip" => kclvm_builtin_str_strip, - "title" => kclvm_builtin_str_title, - _ => panic!("str object attr '{}' not found", key), - }; - let closure = ValueRef::list(Some(&[p])); - return new_mut_ptr(ValueRef::func(function as usize as u64, 0, closure, "", "")); - } - // schema instance - else if p.is_func() { - let function = match key { - "instances" => kclvm_schema_instances, - _ => panic!("schema object attr '{}' not found", key), - }; - let closure = ValueRef::list(Some(&[p])); - return new_mut_ptr(ValueRef::func(function as usize as u64, 0, closure, "", "")); - } - panic!( - "invalid value '{}' to load attribute '{}'", - p.type_str(), - key - ); + let ctx = mut_ptr_as_ref(ctx); + p.load_attr(key).into_raw(ctx) } #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_value_load_attr_option( +pub unsafe extern "C" fn kclvm_value_load_attr_option( + ctx: *mut kclvm_context_t, p: *const kclvm_value_ref_t, key: *const kclvm_char_t, ) -> *const kclvm_value_ref_t { let p_ref = ptr_as_ref(p); if p_ref.is_truthy() { - kclvm_value_load_attr(p, key) + kclvm_value_load_attr(ctx, p, key) } else { - kclvm_value_None() + kclvm_value_None(ctx) } } #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_value_remove_item(a: *mut kclvm_value_ref_t, b: *const kclvm_value_ref_t) { +pub unsafe extern "C" fn kclvm_value_remove_item( + a: *mut kclvm_value_ref_t, + b: *const kclvm_value_ref_t, +) { let a = mut_ptr_as_ref(a); let b = ptr_as_ref(b); if a.is_dict() { @@ -1911,7 +1972,8 @@ pub extern "C" fn kclvm_value_remove_item(a: *mut kclvm_value_ref_t, b: *const k #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_value_slice( +pub unsafe extern "C" fn kclvm_value_slice( + ctx: *mut kclvm_context_t, x: *const kclvm_value_ref_t, a: *const kclvm_value_ref_t, b: *const kclvm_value_ref_t, @@ -1921,12 +1983,13 @@ pub extern "C" fn kclvm_value_slice( let a = ptr_as_ref(a); let b = ptr_as_ref(b); let step = ptr_as_ref(step); - x.list_slice(a, b, step).into_raw() + x.list_slice(a, b, step).into_raw(mut_ptr_as_ref(ctx)) } #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_value_slice_option( +pub unsafe extern "C" fn kclvm_value_slice_option( + ctx: *mut kclvm_context_t, x: *const kclvm_value_ref_t, a: *const kclvm_value_ref_t, b: *const kclvm_value_ref_t, @@ -1934,9 +1997,9 @@ pub extern "C" fn kclvm_value_slice_option( ) -> *const kclvm_value_ref_t { let value = ptr_as_ref(x); if value.is_truthy() { - kclvm_value_slice(x, a, b, step) + kclvm_value_slice(ctx, x, a, b, step) } else { - kclvm_value_None() + kclvm_value_None(ctx) } } @@ -1946,7 +2009,8 @@ pub extern "C" fn kclvm_value_slice_option( #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_schema_backtrack_cache( +pub unsafe extern "C" fn kclvm_schema_backtrack_cache( + ctx: *mut kclvm_context_t, schema: *const kclvm_value_ref_t, cache: *mut kclvm_value_ref_t, cal_map: *const kclvm_value_ref_t, @@ -1960,32 +2024,25 @@ pub extern "C" fn kclvm_schema_backtrack_cache( if let Some(v) = cal_map.dict_get_value(name) { if v.len() == 1 { if let Some(value) = schema.dict_get_value(name) { - cache.dict_update_key_value(name, value.clone()); + cache.dict_update_key_value(name, value); } - } else { - match ( - cal_map.dict_get_value(&format!("{}_{}", name, CAL_MAP_RUNTIME_TYPE)), - cal_map.dict_get_value(&format!("{}_{}", name, CAL_MAP_META_LINE)), + } else if let (Some(cal_map_runtime_type_list), Some(cal_map_meta_line_list)) = ( + cal_map.dict_get_value(&format!("{name}_{CAL_MAP_RUNTIME_TYPE}")), + cal_map.dict_get_value(&format!("{name}_{CAL_MAP_META_LINE}")), + ) { + if let (Some(cal_map_runtime_type), Some(cal_map_meta_line)) = ( + cal_map_runtime_type_list.list_get(-1), + cal_map_meta_line_list.list_get(-1), ) { - (Some(cal_map_runtime_type_list), Some(cal_map_meta_line_list)) => { - match ( - cal_map_runtime_type_list.list_get(-1), - cal_map_meta_line_list.list_get(-1), - ) { - (Some(cal_map_runtime_type), Some(cal_map_meta_line)) => { - let runtime_type = ptr_as_ref(runtime_type); - let line = Context::current_context().panic_info.kcl_line as i64; - let cal_map_meta_line = cal_map_meta_line.as_int(); - if runtime_type == cal_map_runtime_type && line >= cal_map_meta_line { - if let Some(value) = schema.dict_get_value(name) { - cache.dict_update_key_value(name, value.clone()); - } - } - } - _ => {} + let runtime_type = ptr_as_ref(runtime_type); + let ctx = mut_ptr_as_ref(ctx); + let line = ctx.panic_info.kcl_line as i64; + let cal_map_meta_line = cal_map_meta_line.as_int(); + if runtime_type == &cal_map_runtime_type && line >= cal_map_meta_line { + if let Some(value) = schema.dict_get_value(name) { + cache.dict_update_key_value(name, value); } } - _ => {} } } } @@ -1993,110 +2050,139 @@ pub extern "C" fn kclvm_schema_backtrack_cache( #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_schema_instances( +pub unsafe extern "C" fn kclvm_schema_instances( ctx: *mut kclvm_context_t, args: *const kclvm_value_ref_t, kwargs: *const kclvm_value_ref_t, ) -> *const kclvm_value_ref_t { - let ctx = ptr_as_ref(ctx); + let ctx_ref = mut_ptr_as_ref(ctx); let args = ptr_as_ref(args); let kwargs = ptr_as_ref(kwargs); if let Some(val) = args.pop_arg_first() { let function = val.as_function(); - let main_pkg = args.arg_0().or_else(|| kwargs.kwarg("main_pkg")); - let main_pkg = if let Some(v) = main_pkg { + let full_pkg = args.arg_0().or_else(|| kwargs.kwarg("full_pkg")); + let full_pkg = if let Some(v) = full_pkg { v.is_truthy() } else { - true + false }; let runtime_type = &function.runtime_type; - let instance_map = ctx.instances.borrow_mut(); - if instance_map.contains_key(runtime_type) { + if ctx_ref.instances.contains_key(runtime_type) { let mut list = ValueRef::list(None); - for v in instance_map.get(runtime_type).unwrap() { - if v.is_schema() { - let schema = v.as_schema(); - if main_pkg { - if schema.pkgpath == MAIN_PKG_PATH { - list.list_append(v) - } - } else { - list.list_append(v) - } - } else if v.is_dict() { - let runtime_type_attr_path = - format!("{}.{}", SCHEMA_SETTINGS_ATTR_NAME, SETTINGS_SCHEMA_TYPE_KEY); - let runtime_type = - if let Some(runtime_type) = v.get_by_path(&runtime_type_attr_path) { - runtime_type.as_str() - } else { - runtime_type.to_string() - }; - let names: Vec<&str> = runtime_type.rsplit('.').collect(); - let name = names[0]; - let pkgpath = names[1]; - let v = v.dict_to_schema(name, pkgpath, &[]); - list.list_append(&v); + let instance_map = ctx_ref.instances.get(runtime_type).unwrap(); + if full_pkg { + for (_, v_list) in instance_map { + collect_schema_instances(&mut list, &v_list, runtime_type) } - } - list.into_raw() + } else { + // Get the schema instances only located at the main package. + if let Some(v_list) = instance_map.get(MAIN_PKG_PATH) { + collect_schema_instances(&mut list, &v_list, runtime_type) + } + if let Some(v_list) = instance_map.get("") { + collect_schema_instances(&mut list, &v_list, runtime_type) + } + }; + list.into_raw(ctx_ref) } else { - kclvm_value_List() + kclvm_value_List(ctx) } } else { - kclvm_value_None() + kclvm_value_None(ctx) + } +} + +fn collect_schema_instances(list: &mut ValueRef, v_list: &[ValueRef], runtime_type: &str) { + for v in v_list { + if v.is_schema() { + list.list_append(v) + } else if v.is_dict() { + let runtime_type = v + .get_potential_schema_type() + .unwrap_or(runtime_type.to_string()); + let names: Vec<&str> = runtime_type.rsplit('.').collect(); + let name = names[0]; + let pkgpath = names[1]; + let v = v.dict_to_schema( + name, + pkgpath, + &[], + &ValueRef::dict(None), + &ValueRef::dict(None), + None, + None, + ); + list.list_append(&v); + } } } #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_schema_value_check( +pub unsafe extern "C" fn kclvm_schema_value_check( + ctx: *mut kclvm_context_t, schema_value: *mut kclvm_value_ref_t, schema_config: *const kclvm_value_ref_t, _config_meta: *const kclvm_value_ref_t, schema_name: *const kclvm_char_t, index_sign_value: *const kclvm_value_ref_t, - _key_name: *const kclvm_char_t, + key_name: *const kclvm_char_t, key_type: *const kclvm_char_t, - _value_type: *const kclvm_char_t, + value_type: *const kclvm_char_t, _any_other: kclvm_bool_t, - is_relaxed: kclvm_bool_t, ) { let schema_value = mut_ptr_as_ref(schema_value); let schema_config = ptr_as_ref(schema_config); let index_sign_value = ptr_as_ref(index_sign_value); let key_type = c2str(key_type); + let value_type = c2str(value_type); + let index_key_name = c2str(key_name); let has_index_signature = !key_type.is_empty(); - let should_add_attr = is_relaxed != 0 || has_index_signature; - let ctx = Context::current_context_mut(); + let ctx = mut_ptr_as_ref(ctx); if ctx.cfg.disable_schema_check { return; } - let config = schema_config.as_dict_ref(); for (key, value) in &config.values { - let is_not_in_schema = schema_value.dict_get_value(key).is_none(); - if should_add_attr && is_not_in_schema { - let value = index_sign_value - .deep_copy() - .union(value, true, false, false, true); - let op = config - .ops - .get(key) - .or_else(|| Some(&ConfigEntryOperationKind::Union)) - .unwrap(); - schema_value.dict_update_entry(key.as_str(), &value.clone(), op, &-1); - } else if !should_add_attr && is_not_in_schema { + let no_such_attr = schema_value.dict_get_value(key).is_none(); + if has_index_signature && no_such_attr { + // Allow index signature value has different values + // related to the index signature key name. + let should_update = + if let Some(index_key_value) = schema_value.dict_get_value(index_key_name) { + index_key_value.is_str() && key == &index_key_value.as_str() + } else { + true + }; + if should_update { + let op = config + .ops + .get(key) + .unwrap_or(&ConfigEntryOperationKind::Union); + schema_value.dict_update_entry( + key.as_str(), + &index_sign_value.deep_copy(), + &ConfigEntryOperationKind::Override, + None, + ); + schema_value.dict_insert(ctx, key.as_str(), value, op.clone(), None); + let value = schema_value.dict_get_value(key).unwrap(); + schema_value.dict_update_key_value( + key.as_str(), + type_pack_and_check(ctx, &value, vec![value_type], false), + ); + } + } else if !has_index_signature && no_such_attr { let schema_name = c2str(schema_name); - panic!("{}: No such member in the schema '{}'", key, schema_name); + panic!("No attribute named '{key}' in the schema '{schema_name}'"); } } } #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_schema_do_check_with_index_sign_attr( +pub unsafe extern "C" fn kclvm_schema_do_check_with_index_sign_attr( ctx: *mut kclvm_context_t, args: *const kclvm_value_ref_t, kwargs: *const kclvm_value_ref_t, @@ -2112,11 +2198,10 @@ pub extern "C" fn kclvm_schema_do_check_with_index_sign_attr( // Schema check function closure let config_meta = args_value.arg_i(0).unwrap(); let config = args_value.arg_i(1).unwrap(); - let schema = args_value.arg_i(2).unwrap(); + let mut schema = args_value.arg_i(2).unwrap(); let cal_map = args_value.arg_i(3).unwrap(); let backtrack_level_map = args_value.arg_i(4).unwrap(); let backtrack_cache = args_value.arg_i(5).unwrap(); - let schema = get_ref_mut(schema); for (k, _) in &config.as_dict_ref().values { // relaxed keys if schema.attr_map_get(k).is_none() { @@ -2124,13 +2209,13 @@ pub extern "C" fn kclvm_schema_do_check_with_index_sign_attr( schema.dict_update_key_value(attr_name, value); let args = &mut ValueRef::list(None); // Schema check function closure - args.list_append(config_meta); - args.list_append(config); - args.list_append(schema); - args.list_append(cal_map); - args.list_append(backtrack_level_map); - args.list_append(backtrack_cache); - let args = args.clone().into_raw(); + args.list_append(&config_meta); + args.list_append(&config); + args.list_append(&schema); + args.list_append(&cal_map); + args.list_append(&backtrack_level_map); + args.list_append(&backtrack_cache); + let args = args.clone().into_raw(mut_ptr_as_ref(ctx)); check_fn(ctx, args, kwargs); } } @@ -2140,42 +2225,38 @@ pub extern "C" fn kclvm_schema_do_check_with_index_sign_attr( #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_schema_optional_check( +pub unsafe extern "C" fn kclvm_schema_optional_check( + ctx: *mut kclvm_context_t, p: *const kclvm_value_ref_t, - v: *const kclvm_value_ref_t, - schema_name: *const kclvm_char_t, - config_meta: *const kclvm_value_ref_t, -) -> *const kclvm_value_ref_t { +) { let p = ptr_as_ref(p); - let v = ptr_as_ref(v); - let schema_name = c2str(schema_name); - let config_meta = ptr_as_ref(config_meta); - - let ctx = Context::current_context_mut(); - if ctx.cfg.disable_schema_check { - return kclvm_value_None(); + let ctx = mut_ptr_as_ref(ctx); + if !ctx.cfg.disable_schema_check { + p.schema_check_attr_optional(ctx, true); } - - p.schema_check_attr_optional(v, schema_name, config_meta); - kclvm_value_None() } #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_schema_default_settings( +pub unsafe extern "C" fn kclvm_schema_default_settings( schema_value: *mut kclvm_value_ref_t, - config_value: *const kclvm_value_ref_t, + _config_value: *const kclvm_value_ref_t, + args: *const kclvm_value_ref_t, + kwargs: *const kclvm_value_ref_t, runtime_type: *const kclvm_char_t, ) { let schema_value = mut_ptr_as_ref(schema_value); - let config_value = ptr_as_ref(config_value); + let args = ptr_as_ref(args); + let kwargs = ptr_as_ref(kwargs); let runtime_type = c2str(runtime_type); - schema_value.schema_default_settings(config_value, runtime_type); + schema_value.set_potential_schema_type(runtime_type); + schema_value.set_schema_args(args, kwargs); } #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_schema_assert( +pub unsafe extern "C" fn kclvm_schema_assert( + ctx: *mut kclvm_context_t, value: *const kclvm_value_ref_t, msg: *const kclvm_value_ref_t, config_meta: *const kclvm_value_ref_t, @@ -2184,8 +2265,8 @@ pub extern "C" fn kclvm_schema_assert( let msg = ptr_as_ref(msg); let config_meta = ptr_as_ref(config_meta); if !value.is_truthy() { - let ctx = Context::current_context_mut(); - ctx.set_err_type(&ErrType::SchemaCheckFailure_TYPE); + let ctx = mut_ptr_as_ref(ctx); + ctx.set_err_type(&RuntimeErrorType::SchemaCheckFailure); if let Some(config_meta_file) = config_meta.get_by_key(CONFIG_META_FILENAME) { let config_meta_line = config_meta.get_by_key(CONFIG_META_LINE).unwrap(); let config_meta_column = config_meta.get_by_key(CONFIG_META_COLUMN).unwrap(); @@ -2197,7 +2278,15 @@ pub extern "C" fn kclvm_schema_assert( ); } - ctx.set_kcl_location_info(Some("Check failed on the condition"), None, None, None); + let arg_msg = format!( + "Check failed on the condition{}", + if msg.is_empty() { + "".to_string() + } else { + format!(": {msg}") + } + ); + ctx.set_kcl_location_info(Some(arg_msg.as_str()), None, None, None); panic!("{}", msg.as_str()); } @@ -2205,7 +2294,7 @@ pub extern "C" fn kclvm_schema_assert( #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_schema_value_new( +pub unsafe extern "C" fn kclvm_schema_value_new( ctx: *mut kclvm_context_t, args: *mut kclvm_value_ref_t, kwargs: *const kclvm_value_ref_t, @@ -2218,31 +2307,39 @@ pub extern "C" fn kclvm_schema_value_new( if schema_value_or_func.is_func() { let schema_func = schema_value_or_func.as_function(); let schema_fn_ptr = schema_func.fn_ptr; + let ctx_ref = mut_ptr_as_ref(ctx); + let now_meta_info = ctx_ref.panic_info.clone(); + if ctx_ref.cfg.debug_mode { + ctx_ref + .backtrace + .push(BacktraceFrame::from_panic_info(&ctx_ref.panic_info)); + ctx_ref.panic_info.kcl_func = schema_func.runtime_type.clone(); + } let value = unsafe { let org_args = ptr_as_ref(args).deep_copy(); let schema_fn: SchemaTypeFunc = transmute_copy(&schema_fn_ptr); - let cal_map = kclvm_value_Dict(); - let instance_pkgpath = kclvm_value_Str(pkgpath); + let cal_map = kclvm_value_Dict(ctx); + let instance_pkgpath = kclvm_value_Str(ctx, pkgpath); // Schema function closures let values = [ // is_sub_schema - kclvm_value_Bool(0), + kclvm_value_Bool(ctx, 0), // Config meta config_meta, // Config value config, // Schema value - kclvm_value_Dict(), + kclvm_value_Dict(ctx), // optional_mapping - kclvm_value_Dict(), + kclvm_value_Dict(ctx), // cal order map cal_map, // backtrack level map - kclvm_value_Dict(), + kclvm_value_Dict(ctx), // backtrack cache - kclvm_value_Dict(), + kclvm_value_Dict(ctx), // record instance - kclvm_value_Bool(0), + kclvm_value_Bool(ctx, 0), // instance pkgpath instance_pkgpath, ]; @@ -2251,26 +2348,26 @@ pub extern "C" fn kclvm_schema_value_new( } schema_fn(ctx, args, kwargs); // schema args - let args = org_args.into_raw(); + let args = org_args.into_raw(ctx_ref); let values = [ // is_sub_schema - kclvm_value_Bool(1), + kclvm_value_Bool(ctx, 1), // Config meta config_meta, // Config value config, // Schema value - kclvm_value_Dict(), + kclvm_value_Dict(ctx), // optional_mapping - kclvm_value_Dict(), + kclvm_value_Dict(ctx), // cal order map cal_map, // backtrack level map - kclvm_value_Dict(), + kclvm_value_Dict(ctx), // backtrack cache - kclvm_value_Dict(), + kclvm_value_Dict(ctx), // record instance - kclvm_value_Bool(1), + kclvm_value_Bool(ctx, 1), // instance pkgpath instance_pkgpath, ]; @@ -2279,31 +2376,51 @@ pub extern "C" fn kclvm_schema_value_new( } schema_fn(ctx, args, kwargs) }; + ctx_ref.panic_info = now_meta_info; + if ctx_ref.cfg.debug_mode { + ctx_ref.backtrace.pop(); + } value } else { let config = ptr_as_ref(config); - let result = schema_value_or_func - .deep_copy() - .union(config, true, false, true, true); - result.into_raw() + let result = schema_value_or_func.deep_copy().union_entry( + mut_ptr_as_ref(ctx), + config, + true, + &UnionOptions::default(), + ); + result.into_raw(mut_ptr_as_ref(ctx)) } } #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_convert_collection_value( +pub unsafe extern "C" fn kclvm_convert_collection_value( + ctx: *mut kclvm_context_t, value: *const kclvm_value_ref_t, tpe: *const kclvm_char_t, + is_in_schema: *const kclvm_value_ref_t, ) -> *const kclvm_value_ref_t { let value = ptr_as_ref(value); + let ctx = mut_ptr_as_ref(ctx); let tpe = c2str(tpe); - let value = convert_collection_value(value, tpe); - value.into_raw() + let value = type_pack_and_check(ctx, value, vec![tpe], false); + let is_in_schema = ptr_as_ref(is_in_schema); + // Schema required attribute validating. + if !is_in_schema.is_truthy() { + walk_value_mut(&value, &mut |value: &ValueRef| { + if value.is_schema() { + value.schema_check_attr_optional(ctx, true); + } + }) + } + value.into_raw(ctx) } #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_schema_get_value( +pub unsafe extern "C" fn kclvm_schema_get_value( + ctx: *mut kclvm_context_t, p: *const kclvm_value_ref_t, key: *const kclvm_char_t, config: *const kclvm_value_ref_t, @@ -2326,19 +2443,18 @@ pub extern "C" fn kclvm_schema_get_value( let default_level = ValueRef::int(0); let level = backtrack_level_map .dict_get_value(key) - .or(Some(&default_level)) - .unwrap(); + .unwrap_or(default_level); let level = level.as_int(); let is_backtracking = level > 0; // Deal in-place modify and return it self immediately if key == target_attr && !is_backtracking { match schema.dict_get_value(key) { - Some(x) => return x.clone().into_raw(), - None => return kclvm_value_Undefined(), + Some(x) => return x.into_raw(mut_ptr_as_ref(ctx)), + None => return kclvm_value_Undefined(ctx), } } if let Some(v) = backtrack_cache.dict_get_value(key) { - return v.clone().into_raw(); + return v.into_raw(mut_ptr_as_ref(ctx)); } if let Some(attr_code) = cal_map.dict_get_value(key) { let now_level = level + 1; @@ -2348,19 +2464,22 @@ pub extern "C" fn kclvm_schema_get_value( let index = n - now_level as usize; if index >= n { let value = match schema.dict_get_value(key) { - Some(x) => x.clone(), + Some(x) => x, None => ValueRef::undefined(), }; - return value.into_raw(); + return value.into_raw(mut_ptr_as_ref(ctx)); } let fn_ptr = &attr_code.values[index]; let fn_ptr = fn_ptr.as_int(); + // When we calculate other schema attribute values, we retain + // the row and column number information of the current schema attribute. + let ctx_ref = mut_ptr_as_ref(ctx); + let panic_info = ctx_ref.panic_info.clone(); unsafe { let attr_fn: SchemaTypeFunc = transmute_copy(&fn_ptr); // args_0: config_meta, args_1: config, args_2: schema, args_3: cal_map let config_meta = ptr_as_ref(config_meta); let config = ptr_as_ref(config); - let schema = get_ref_mut(schema); let mut args = ValueRef::list(None); let args_org = args_org.as_list_ref(); for value in &args_org.values { @@ -2373,27 +2492,28 @@ pub extern "C" fn kclvm_schema_get_value( args.list_append(cal_map); args.list_append(backtrack_level_map); args.list_append(backtrack_cache); - let args = args.into_raw(); - let kwargs = kwargs.clone().into_raw(); - let ctx = kclvm_context_current(); + let args = args.into_raw(ctx_ref); + let kwargs = kwargs.clone().into_raw(ctx_ref); attr_fn(ctx, args, kwargs); }; + // Restore the panic info of current schema attribute. + ctx_ref.panic_info = panic_info; backtrack_level_map.dict_update_key_value(key, ValueRef::int(level)); let value = match schema.dict_get_value(key) { - Some(x) => x.clone(), + Some(x) => x, None => ValueRef::undefined(), }; backtrack_cache.dict_update_key_value(key, value); } match schema.dict_get_value(key) { - Some(x) => x.clone().into_raw(), - None => kclvm_value_Undefined(), + Some(x) => x.into_raw(mut_ptr_as_ref(ctx)), + None => kclvm_value_Undefined(ctx), } } #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_config_attr_map( +pub unsafe extern "C" fn kclvm_config_attr_map( value: *mut kclvm_value_ref_t, name: *const kclvm_char_t, type_str: *const kclvm_char_t, @@ -2410,7 +2530,8 @@ pub extern "C" fn kclvm_config_attr_map( #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_value_Decorator( +pub unsafe extern "C" fn kclvm_value_Decorator( + ctx: *mut kclvm_context_t, name: *const kclvm_char_t, args: *const kclvm_value_ref_t, kwargs: *const kclvm_value_ref_t, @@ -2428,6 +2549,7 @@ pub extern "C" fn kclvm_value_Decorator( let is_schema_target = ptr_as_ref(is_schema_target); let decorator = DecoratorValue::new(name, args, kwargs); decorator.run( + mut_ptr_as_ref(ctx), attr_name, is_schema_target.as_bool(), config_value, @@ -2442,14 +2564,14 @@ pub extern "C" fn kclvm_value_Decorator( #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_builtin_str_lower( - _ctx: *mut kclvm_context_t, +pub unsafe extern "C" fn kclvm_builtin_str_lower( + ctx: *mut kclvm_context_t, args: *const kclvm_value_ref_t, _kwargs: *const kclvm_value_ref_t, ) -> *const kclvm_value_ref_t { let args = ptr_as_ref(args); if let Some(val) = args.pop_arg_first() { - val.str_lower().into_raw() + val.str_lower().into_raw(mut_ptr_as_ref(ctx)) } else { panic!("invalid self value in str_lower"); } @@ -2457,14 +2579,14 @@ pub extern "C" fn kclvm_builtin_str_lower( #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_builtin_str_upper( - _ctx: *mut kclvm_context_t, +pub unsafe extern "C" fn kclvm_builtin_str_upper( + ctx: *mut kclvm_context_t, args: *const kclvm_value_ref_t, _kwargs: *const kclvm_value_ref_t, ) -> *const kclvm_value_ref_t { let args = ptr_as_ref(args); if let Some(val) = args.pop_arg_first() { - val.str_upper().into_raw() + val.str_upper().into_raw(mut_ptr_as_ref(ctx)) } else { panic!("invalid self value in str_upper"); } @@ -2472,14 +2594,14 @@ pub extern "C" fn kclvm_builtin_str_upper( #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_builtin_str_capitalize( - _ctx: *mut kclvm_context_t, +pub unsafe extern "C" fn kclvm_builtin_str_capitalize( + ctx: *mut kclvm_context_t, args: *const kclvm_value_ref_t, _kwargs: *const kclvm_value_ref_t, ) -> *const kclvm_value_ref_t { let args = ptr_as_ref(args); if let Some(val) = args.pop_arg_first() { - val.str_capitalize().into_raw() + val.str_capitalize().into_raw(mut_ptr_as_ref(ctx)) } else { panic!("invalid self value in str_capitalize"); } @@ -2487,8 +2609,23 @@ pub extern "C" fn kclvm_builtin_str_capitalize( #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_builtin_str_count( - _ctx: *mut kclvm_context_t, +pub unsafe extern "C" fn kclvm_builtin_str_chars( + ctx: *mut kclvm_context_t, + args: *const kclvm_value_ref_t, + _kwargs: *const kclvm_value_ref_t, +) -> *const kclvm_value_ref_t { + let args = ptr_as_ref(args); + if let Some(val) = args.pop_arg_first() { + val.str_chars().into_raw(mut_ptr_as_ref(ctx)) + } else { + panic!("invalid self value in str_chars"); + } +} + +#[no_mangle] +#[runtime_fn] +pub unsafe extern "C" fn kclvm_builtin_str_count( + ctx: *mut kclvm_context_t, args: *const kclvm_value_ref_t, _kwargs: *const kclvm_value_ref_t, ) -> *const kclvm_value_ref_t { @@ -2497,7 +2634,8 @@ pub extern "C" fn kclvm_builtin_str_count( if let Some(sub) = args.arg_0() { let start = args.arg_i(1); let end = args.arg_i(2); - val.str_count(sub, start, end).into_raw() + val.str_count(&sub, start.as_ref(), end.as_ref()) + .into_raw(mut_ptr_as_ref(ctx)) } else { panic!("count() takes at least 1 argument (0 given)"); } @@ -2508,8 +2646,8 @@ pub extern "C" fn kclvm_builtin_str_count( #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_builtin_str_endswith( - _ctx: *mut kclvm_context_t, +pub unsafe extern "C" fn kclvm_builtin_str_endswith( + ctx: *mut kclvm_context_t, args: *const kclvm_value_ref_t, _kwargs: *const kclvm_value_ref_t, ) -> *const kclvm_value_ref_t { @@ -2518,7 +2656,8 @@ pub extern "C" fn kclvm_builtin_str_endswith( if let Some(suffix) = args.arg_0() { let start = args.arg_i(1); let end = args.arg_i(2); - val.str_endswith(suffix, start, end).into_raw() + val.str_endswith(&suffix, start.as_ref(), end.as_ref()) + .into_raw(mut_ptr_as_ref(ctx)) } else { panic!("endswith() takes at least 1 argument (0 given)"); } @@ -2529,8 +2668,8 @@ pub extern "C" fn kclvm_builtin_str_endswith( #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_builtin_str_find( - _ctx: *mut kclvm_context_t, +pub unsafe extern "C" fn kclvm_builtin_str_find( + ctx: *mut kclvm_context_t, args: *const kclvm_value_ref_t, _kwargs: *const kclvm_value_ref_t, ) -> *const kclvm_value_ref_t { @@ -2539,7 +2678,8 @@ pub extern "C" fn kclvm_builtin_str_find( if let Some(sub) = args.arg_0() { let start = args.arg_i(1); let end = args.arg_i(2); - val.str_find(sub, start, end).into_raw() + val.str_find(&sub, start.as_ref(), end.as_ref()) + .into_raw(mut_ptr_as_ref(ctx)) } else { panic!("find() takes at least 1 argument (0 given)"); } @@ -2550,15 +2690,15 @@ pub extern "C" fn kclvm_builtin_str_find( #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_builtin_str_format( - _ctx: *mut kclvm_context_t, +pub unsafe extern "C" fn kclvm_builtin_str_format( + ctx: *mut kclvm_context_t, args: *const kclvm_value_ref_t, kwargs: *const kclvm_value_ref_t, ) -> *const kclvm_value_ref_t { let args = ptr_as_ref(args); let kwargs = ptr_as_ref(kwargs); if let Some(val) = args.pop_arg_first() { - val.str_format(args, kwargs).into_raw() + val.str_format(args, kwargs).into_raw(mut_ptr_as_ref(ctx)) } else { panic!("invalid self value in str_format"); } @@ -2566,8 +2706,8 @@ pub extern "C" fn kclvm_builtin_str_format( #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_builtin_str_index( - _ctx: *mut kclvm_context_t, +pub unsafe extern "C" fn kclvm_builtin_str_index( + ctx: *mut kclvm_context_t, args: *const kclvm_value_ref_t, _kwargs: *const kclvm_value_ref_t, ) -> *const kclvm_value_ref_t { @@ -2576,7 +2716,8 @@ pub extern "C" fn kclvm_builtin_str_index( if let Some(sub) = args.arg_0() { let start = args.arg_i(1); let end = args.arg_i(2); - val.str_index(sub, start, end).into_raw() + val.str_index(&sub, start.as_ref(), end.as_ref()) + .into_raw(mut_ptr_as_ref(ctx)) } else { panic!("index() takes at least 1 argument (0 given)"); } @@ -2587,14 +2728,14 @@ pub extern "C" fn kclvm_builtin_str_index( #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_builtin_str_isalnum( - _ctx: *mut kclvm_context_t, +pub unsafe extern "C" fn kclvm_builtin_str_isalnum( + ctx: *mut kclvm_context_t, args: *const kclvm_value_ref_t, _kwargs: *const kclvm_value_ref_t, ) -> *const kclvm_value_ref_t { let args = ptr_as_ref(args); if let Some(val) = args.pop_arg_first() { - val.str_isalnum().into_raw() + val.str_isalnum().into_raw(mut_ptr_as_ref(ctx)) } else { panic!("invalid self value in str_isalnum"); } @@ -2602,14 +2743,14 @@ pub extern "C" fn kclvm_builtin_str_isalnum( #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_builtin_str_isalpha( - _ctx: *mut kclvm_context_t, +pub unsafe extern "C" fn kclvm_builtin_str_isalpha( + ctx: *mut kclvm_context_t, args: *const kclvm_value_ref_t, _kwargs: *const kclvm_value_ref_t, ) -> *const kclvm_value_ref_t { let args = ptr_as_ref(args); if let Some(val) = args.pop_arg_first() { - val.str_isalpha().into_raw() + val.str_isalpha().into_raw(mut_ptr_as_ref(ctx)) } else { panic!("invalid self value in str_isalpha"); } @@ -2617,14 +2758,14 @@ pub extern "C" fn kclvm_builtin_str_isalpha( #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_builtin_str_isdigit( - _ctx: *mut kclvm_context_t, +pub unsafe extern "C" fn kclvm_builtin_str_isdigit( + ctx: *mut kclvm_context_t, args: *const kclvm_value_ref_t, _kwargs: *const kclvm_value_ref_t, ) -> *const kclvm_value_ref_t { let args = ptr_as_ref(args); if let Some(val) = args.pop_arg_first() { - val.str_isdigit().into_raw() + val.str_isdigit().into_raw(mut_ptr_as_ref(ctx)) } else { panic!("invalid self value in str_isdigit"); } @@ -2632,14 +2773,14 @@ pub extern "C" fn kclvm_builtin_str_isdigit( #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_builtin_str_islower( - _ctx: *mut kclvm_context_t, +pub unsafe extern "C" fn kclvm_builtin_str_islower( + ctx: *mut kclvm_context_t, args: *const kclvm_value_ref_t, _kwargs: *const kclvm_value_ref_t, ) -> *const kclvm_value_ref_t { let args = ptr_as_ref(args); if let Some(val) = args.pop_arg_first() { - val.str_islower().into_raw() + val.str_islower().into_raw(mut_ptr_as_ref(ctx)) } else { panic!("invalid self value in str_islower"); } @@ -2647,14 +2788,14 @@ pub extern "C" fn kclvm_builtin_str_islower( #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_builtin_str_isspace( - _ctx: *mut kclvm_context_t, +pub unsafe extern "C" fn kclvm_builtin_str_isspace( + ctx: *mut kclvm_context_t, args: *const kclvm_value_ref_t, _kwargs: *const kclvm_value_ref_t, ) -> *const kclvm_value_ref_t { let args = ptr_as_ref(args); if let Some(val) = args.pop_arg_first() { - val.str_isspace().into_raw() + val.str_isspace().into_raw(mut_ptr_as_ref(ctx)) } else { panic!("invalid self value in str_isspace"); } @@ -2662,14 +2803,14 @@ pub extern "C" fn kclvm_builtin_str_isspace( #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_builtin_str_istitle( - _ctx: *mut kclvm_context_t, +pub unsafe extern "C" fn kclvm_builtin_str_istitle( + ctx: *mut kclvm_context_t, args: *const kclvm_value_ref_t, _kwargs: *const kclvm_value_ref_t, ) -> *const kclvm_value_ref_t { let args = ptr_as_ref(args); if let Some(val) = args.pop_arg_first() { - val.str_istitle().into_raw() + val.str_istitle().into_raw(mut_ptr_as_ref(ctx)) } else { panic!("invalid self value in str_istitle"); } @@ -2677,14 +2818,14 @@ pub extern "C" fn kclvm_builtin_str_istitle( #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_builtin_str_isupper( - _ctx: *mut kclvm_context_t, +pub unsafe extern "C" fn kclvm_builtin_str_isupper( + ctx: *mut kclvm_context_t, args: *const kclvm_value_ref_t, _kwargs: *const kclvm_value_ref_t, ) -> *const kclvm_value_ref_t { let args = ptr_as_ref(args); if let Some(val) = args.pop_arg_first() { - val.str_isupper().into_raw() + val.str_isupper().into_raw(mut_ptr_as_ref(ctx)) } else { panic!("invalid self value in str_isupper"); } @@ -2692,15 +2833,15 @@ pub extern "C" fn kclvm_builtin_str_isupper( #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_builtin_str_join( - _ctx: *mut kclvm_context_t, +pub unsafe extern "C" fn kclvm_builtin_str_join( + ctx: *mut kclvm_context_t, args: *const kclvm_value_ref_t, _kwargs: *const kclvm_value_ref_t, ) -> *const kclvm_value_ref_t { let args = ptr_as_ref(args); if let Some(val) = args.pop_arg_first() { let iter = args.arg_i(0).unwrap(); - val.str_join(iter).into_raw() + val.str_join(&iter).into_raw(mut_ptr_as_ref(ctx)) } else { panic!("invalid self value in str_join"); } @@ -2708,15 +2849,15 @@ pub extern "C" fn kclvm_builtin_str_join( #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_builtin_str_lstrip( - _ctx: *mut kclvm_context_t, +pub unsafe extern "C" fn kclvm_builtin_str_lstrip( + ctx: *mut kclvm_context_t, args: *const kclvm_value_ref_t, _kwargs: *const kclvm_value_ref_t, ) -> *const kclvm_value_ref_t { let args = ptr_as_ref(args); if let Some(val) = args.pop_arg_first() { let chars = args.arg_i(0); - val.str_lstrip(chars).into_raw() + val.str_lstrip(chars.as_ref()).into_raw(mut_ptr_as_ref(ctx)) } else { panic!("invalid self value in str_lstrip"); } @@ -2724,15 +2865,15 @@ pub extern "C" fn kclvm_builtin_str_lstrip( #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_builtin_str_rstrip( - _ctx: *mut kclvm_context_t, +pub unsafe extern "C" fn kclvm_builtin_str_rstrip( + ctx: *mut kclvm_context_t, args: *const kclvm_value_ref_t, _kwargs: *const kclvm_value_ref_t, ) -> *const kclvm_value_ref_t { let args = ptr_as_ref(args); if let Some(val) = args.pop_arg_first() { let chars = args.arg_i(0); - val.str_rstrip(chars).into_raw() + val.str_rstrip(chars.as_ref()).into_raw(mut_ptr_as_ref(ctx)) } else { panic!("invalid self value in str_rstrip"); } @@ -2740,26 +2881,63 @@ pub extern "C" fn kclvm_builtin_str_rstrip( #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_builtin_str_replace( - _ctx: *mut kclvm_context_t, +pub unsafe extern "C" fn kclvm_builtin_str_replace( + ctx: *mut kclvm_context_t, args: *const kclvm_value_ref_t, _kwargs: *const kclvm_value_ref_t, ) -> *const kclvm_value_ref_t { let args = ptr_as_ref(args); if let Some(val) = args.pop_arg_first() { - let old = args.arg_i(0).unwrap(); - let new = args.arg_i(1).unwrap(); + let old = args.arg_i(0).expect("expect 1 argument, found 0"); + let new = args.arg_i(1).expect("expect 2 arguments, found 1"); let count = args.arg_i(2); - val.str_replace(old, new, count).into_raw() + val.str_replace(&old, &new, count.as_ref()) + .into_raw(mut_ptr_as_ref(ctx)) } else { panic!("invalid self value in str_replace"); } } +/// If the string starts with the prefix string, return string[len(prefix):]. +/// Otherwise, return a copy of the original string. #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_builtin_str_rfind( - _ctx: *mut kclvm_context_t, +pub unsafe extern "C" fn kclvm_builtin_str_removeprefix( + ctx: *mut kclvm_context_t, + args: *const kclvm_value_ref_t, + _kwargs: *const kclvm_value_ref_t, +) -> *const kclvm_value_ref_t { + let args = ptr_as_ref(args); + if let Some(val) = args.pop_arg_first() { + let prefix = args.arg_i(0).expect("expect 1 argument, found 0"); + val.str_removeprefix(&prefix).into_raw(mut_ptr_as_ref(ctx)) + } else { + panic!("invalid self value in str_removeprefix"); + } +} + +/// If the string ends with the suffix string and that suffix is not empty, return string[:-len(suffix)]. +/// Otherwise, return a copy of the original string. +#[no_mangle] +#[runtime_fn] +pub unsafe extern "C" fn kclvm_builtin_str_removesuffix( + ctx: *mut kclvm_context_t, + args: *const kclvm_value_ref_t, + _kwargs: *const kclvm_value_ref_t, +) -> *const kclvm_value_ref_t { + let args = ptr_as_ref(args); + if let Some(val) = args.pop_arg_first() { + let suffix = args.arg_i(0).expect("expect 1 argument, found 0"); + val.str_removesuffix(&suffix).into_raw(mut_ptr_as_ref(ctx)) + } else { + panic!("invalid self value in str_removesuffix"); + } +} + +#[no_mangle] +#[runtime_fn] +pub unsafe extern "C" fn kclvm_builtin_str_rfind( + ctx: *mut kclvm_context_t, args: *const kclvm_value_ref_t, _kwargs: *const kclvm_value_ref_t, ) -> *const kclvm_value_ref_t { @@ -2768,7 +2946,8 @@ pub extern "C" fn kclvm_builtin_str_rfind( if let Some(sub) = args.arg_0() { let start = args.arg_i(1); let end = args.arg_i(2); - val.str_rfind(sub, start, end).into_raw() + val.str_rfind(&sub, start.as_ref(), end.as_ref()) + .into_raw(mut_ptr_as_ref(ctx)) } else { panic!("rfind() takes at least 1 argument (0 given)"); } @@ -2779,8 +2958,8 @@ pub extern "C" fn kclvm_builtin_str_rfind( #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_builtin_str_rindex( - _ctx: *mut kclvm_context_t, +pub unsafe extern "C" fn kclvm_builtin_str_rindex( + ctx: *mut kclvm_context_t, args: *const kclvm_value_ref_t, _kwargs: *const kclvm_value_ref_t, ) -> *const kclvm_value_ref_t { @@ -2789,7 +2968,8 @@ pub extern "C" fn kclvm_builtin_str_rindex( if let Some(sub) = args.arg_0() { let start = args.arg_i(1); let end = args.arg_i(2); - val.str_rindex(sub, start, end).into_raw() + val.str_rindex(&sub, start.as_ref(), end.as_ref()) + .into_raw(mut_ptr_as_ref(ctx)) } else { panic!("rindex() takes at least 1 argument (0 given)"); } @@ -2800,8 +2980,8 @@ pub extern "C" fn kclvm_builtin_str_rindex( #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_builtin_str_rsplit( - _ctx: *mut kclvm_context_t, +pub unsafe extern "C" fn kclvm_builtin_str_rsplit( + ctx: *mut kclvm_context_t, args: *const kclvm_value_ref_t, kwargs: *const kclvm_value_ref_t, ) -> *const kclvm_value_ref_t { @@ -2818,7 +2998,8 @@ pub extern "C" fn kclvm_builtin_str_rsplit( } else { kwargs.kwarg("maxsplit") }; - val.str_rsplit(sep, maxsplit).into_raw() + val.str_rsplit(sep.as_ref(), maxsplit.as_ref()) + .into_raw(mut_ptr_as_ref(ctx)) } else { panic!("invalid self value in str_rsplit"); } @@ -2826,8 +3007,8 @@ pub extern "C" fn kclvm_builtin_str_rsplit( #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_builtin_str_split( - _ctx: *mut kclvm_context_t, +pub unsafe extern "C" fn kclvm_builtin_str_split( + ctx: *mut kclvm_context_t, args: *const kclvm_value_ref_t, kwargs: *const kclvm_value_ref_t, ) -> *const kclvm_value_ref_t { @@ -2844,8 +3025,8 @@ pub extern "C" fn kclvm_builtin_str_split( } else { kwargs.kwarg("maxsplit") }; - let x = val.str_split(sep, maxsplit); - x.into_raw() + let x = val.str_split(sep.as_ref(), maxsplit.as_ref()); + x.into_raw(mut_ptr_as_ref(ctx)) } else { panic!("invalid self value in str_split"); } @@ -2853,8 +3034,8 @@ pub extern "C" fn kclvm_builtin_str_split( #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_builtin_str_splitlines( - _ctx: *mut kclvm_context_t, +pub unsafe extern "C" fn kclvm_builtin_str_splitlines( + ctx: *mut kclvm_context_t, args: *const kclvm_value_ref_t, kwargs: *const kclvm_value_ref_t, ) -> *const kclvm_value_ref_t { @@ -2862,11 +3043,13 @@ pub extern "C" fn kclvm_builtin_str_splitlines( let kwargs = ptr_as_ref(kwargs); if let Some(val) = args.pop_arg_first() { if let Some(keepends) = args.arg_i(0) { - val.str_splitlines(Some(keepends)).into_raw() + val.str_splitlines(Some(&keepends)) + .into_raw(mut_ptr_as_ref(ctx)) } else if let Some(keepends) = kwargs.kwarg("keepends") { - val.str_splitlines(Some(keepends)).into_raw() + val.str_splitlines(Some(&keepends)) + .into_raw(mut_ptr_as_ref(ctx)) } else { - val.str_splitlines(None).into_raw() + val.str_splitlines(None).into_raw(mut_ptr_as_ref(ctx)) } } else { panic!("invalid self value in str_splitlines"); @@ -2875,8 +3058,8 @@ pub extern "C" fn kclvm_builtin_str_splitlines( #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_builtin_str_startswith( - _ctx: *mut kclvm_context_t, +pub unsafe extern "C" fn kclvm_builtin_str_startswith( + ctx: *mut kclvm_context_t, args: *const kclvm_value_ref_t, _kwargs: *const kclvm_value_ref_t, ) -> *const kclvm_value_ref_t { @@ -2885,7 +3068,8 @@ pub extern "C" fn kclvm_builtin_str_startswith( if let Some(suffix) = args.arg_0() { let start = args.arg_i(1); let end = args.arg_i(2); - val.str_startswith(suffix, start, end).into_raw() + val.str_startswith(&suffix, start.as_ref(), end.as_ref()) + .into_raw(mut_ptr_as_ref(ctx)) } else { panic!("startswith() takes at least 1 argument (0 given)"); } @@ -2896,15 +3080,15 @@ pub extern "C" fn kclvm_builtin_str_startswith( #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_builtin_str_strip( - _ctx: *mut kclvm_context_t, +pub unsafe extern "C" fn kclvm_builtin_str_strip( + ctx: *mut kclvm_context_t, args: *const kclvm_value_ref_t, _kwargs: *const kclvm_value_ref_t, ) -> *const kclvm_value_ref_t { let args = ptr_as_ref(args); if let Some(val) = args.pop_arg_first() { let chars = args.arg_i(0); - val.str_strip(chars).into_raw() + val.str_strip(chars.as_ref()).into_raw(mut_ptr_as_ref(ctx)) } else { panic!("invalid self value in str_strip"); } @@ -2912,14 +3096,14 @@ pub extern "C" fn kclvm_builtin_str_strip( #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_builtin_str_title( - _ctx: *mut kclvm_context_t, +pub unsafe extern "C" fn kclvm_builtin_str_title( + ctx: *mut kclvm_context_t, args: *const kclvm_value_ref_t, _kwargs: *const kclvm_value_ref_t, ) -> *const kclvm_value_ref_t { let args = ptr_as_ref(args); if let Some(val) = args.pop_arg_first() { - val.str_title().into_raw() + val.str_title().into_raw(mut_ptr_as_ref(ctx)) } else { panic!("invalid self value in str_title"); } diff --git a/kclvm/runtime/src/value/iter.rs b/kclvm/runtime/src/value/iter.rs index 87bf5eba4..29acdd537 100644 --- a/kclvm/runtime/src/value/iter.rs +++ b/kclvm/runtime/src/value/iter.rs @@ -1,4 +1,4 @@ -// Copyright 2021 The KCL Authors. All rights reserved. +//! Copyright The KCL Authors. All rights reserved. use crate::*; @@ -8,7 +8,6 @@ pub struct ValueIterator { pub len: usize, pub cur_key: ValueRef, pub cur_val: ValueRef, - pub end_val: *const ValueRef, pub keys: Vec, pub pos: i32, } @@ -19,7 +18,6 @@ impl Default for ValueIterator { len: 0, cur_key: Default::default(), cur_val: Default::default(), - end_val: std::ptr::null(), keys: Vec::new(), pos: 0, } @@ -31,37 +29,30 @@ impl ValueIterator { if !p.is_str() && !p.is_list() && !p.is_config() { panic!("'{}' object is not iterable", p.type_str()); } - if p.len() == 0 { + if p.is_empty() { return Default::default(); } - match *p.rc { - Value::str_value(ref s) => { - ValueIterator { - len: s.len(), - cur_key: Default::default(), - cur_val: Default::default(), - end_val: 1 as *const ValueRef, // just as bool flag - keys: Vec::new(), - pos: 0, - } - } - Value::list_value(ref list) => { - ValueIterator { - len: list.values.len(), - cur_key: Default::default(), - cur_val: Default::default(), - end_val: 1 as *const ValueRef, // just as bool flag - keys: Vec::new(), - pos: 0, - } - } + match *p.rc.borrow() { + Value::str_value(ref s) => ValueIterator { + len: s.len(), + cur_key: Default::default(), + cur_val: Default::default(), + keys: Vec::new(), + pos: 0, + }, + Value::list_value(ref list) => ValueIterator { + len: list.values.len(), + cur_key: Default::default(), + cur_val: Default::default(), + keys: Vec::new(), + pos: 0, + }, Value::dict_value(ref dict) => { let keys: Vec = dict.values.keys().map(|s| (*s).clone()).collect(); ValueIterator { len: dict.values.len(), cur_key: Default::default(), cur_val: Default::default(), - end_val: 1 as *const ValueRef, // just as bool flag keys, pos: 0, } @@ -73,7 +64,6 @@ impl ValueIterator { len: schema.config.values.len(), cur_key: Default::default(), cur_val: Default::default(), - end_val: 1 as *const ValueRef, // just as bool flag keys, pos: 0, } @@ -91,45 +81,50 @@ impl ValueIterator { if self.pos == 0 || self.pos > self.len as i32 { return Option::None; } - if !self.end_val.is_null() { - Some(&self.cur_key) - } else { - Option::None - } + Some(&self.cur_key) } - pub fn value<'a>(&'a mut self) -> Option<&'a ValueRef> { + pub fn value(&mut self) -> Option<&ValueRef> { if self.pos == 0 { return Option::None; } - if !self.end_val.is_null() { - Some(&self.cur_val) - } else { - Option::None + Some(&self.cur_val) + } + + /// Get the next value, iterate key and value of the iterator. + pub fn next_with_key_value<'a>( + &'a mut self, + host: &'a ValueRef, + ) -> Option<(ValueRef, ValueRef, ValueRef)> { + let next_value = self.next(host); + match next_value { + Some(v) => Some((v.clone(), self.cur_key.clone(), self.cur_val.clone())), + None => None, } } + /// Get the next value reference of the iterator. pub fn next<'a>(&'a mut self, host: &'a ValueRef) -> Option<&'a ValueRef> { - if host.len() == 0 { + if host.is_empty() { return None; } if self.pos >= host.len() as i32 { - self.end_val = std::ptr::null(); return None; } - match *host.rc { + match *host.rc.borrow() { Value::str_value(ref s) => { + if self.pos >= s.chars().count() as i32 { + return None; + } let ch = s.chars().nth(self.pos as usize).unwrap(); self.cur_key = ValueRef::int(self.pos as i64); self.cur_val = ValueRef::str(&ch.to_string()); - self.end_val = &self.cur_val; self.pos += 1; Some(&self.cur_val) } Value::list_value(ref list) => { self.cur_key = ValueRef::int(self.pos as i64); self.cur_val = list.values[self.pos as usize].clone(); - self.end_val = &self.cur_val; self.pos += 1; Some(&self.cur_val) } @@ -137,7 +132,6 @@ impl ValueIterator { let key = &self.keys[self.pos as usize]; self.cur_key = ValueRef::str(key); self.cur_val = dict.values[key].clone(); - self.end_val = &self.cur_val; self.pos += 1; Some(&self.cur_key) } @@ -145,7 +139,6 @@ impl ValueIterator { let key = &self.keys[self.pos as usize]; self.cur_key = ValueRef::str(key); self.cur_val = schema.config.values[key].clone(); - self.end_val = &self.cur_val; self.pos += 1; Some(&self.cur_key) } @@ -170,14 +163,14 @@ mod test_value_iter { let s = ValueRef::str("abc"); let mut it = s.iter(); - assert_eq!(it.is_end(), false); + assert!(!it.is_end()); let _ = it.next(&s); assert_eq!(it.key().unwrap().as_int(), 0); assert_eq!(it.value().unwrap().as_str(), "a"); let _ = it.next(&s); - assert_eq!(it.is_end(), false); + assert!(!it.is_end()); assert_eq!(it.key().unwrap().as_int(), 1); assert_eq!(it.value().unwrap().as_str(), "b"); @@ -185,10 +178,10 @@ mod test_value_iter { assert_eq!(v.unwrap().as_str(), "c"); assert_eq!(it.key().unwrap().as_int(), 2); assert_eq!(it.value().unwrap().as_str(), "c"); - assert_eq!(it.is_end(), true); + assert!(it.is_end()); let _ = it.next(&s); - assert_eq!(it.is_end(), true); + assert!(it.is_end()); } #[test] @@ -196,24 +189,24 @@ mod test_value_iter { let value = ValueRef::list_int(&[1, 2, 3]); let mut it = value.iter(); - assert_eq!(it.is_end(), false); + assert!(!it.is_end()); let _ = it.next(&value); assert_eq!(it.key().unwrap().as_int(), 0); assert_eq!(it.value().unwrap().as_int(), 1); let _ = it.next(&value); - assert_eq!(it.is_end(), false); + assert!(!it.is_end()); assert_eq!(it.key().unwrap().as_int(), 1); assert_eq!(it.value().unwrap().as_int(), 2); let _ = it.next(&value); assert_eq!(it.key().unwrap().as_int(), 2); assert_eq!(it.value().unwrap().as_int(), 3); - assert_eq!(it.is_end(), true); + assert!(it.is_end()); let _ = it.next(&value); - assert_eq!(it.is_end(), true); + assert!(it.is_end()); } #[test] @@ -221,23 +214,23 @@ mod test_value_iter { let value = ValueRef::dict_int(&[("a", 1), ("b", 2), ("c", 3)]); let mut it = value.iter(); - assert_eq!(it.is_end(), false); + assert!(!it.is_end()); let _ = it.next(&value); assert_eq!(it.key().unwrap().as_str(), "a"); assert_eq!(it.value().unwrap().as_int(), 1); let _ = it.next(&value); - assert_eq!(it.is_end(), false); + assert!(!it.is_end()); assert_eq!(it.key().unwrap().as_str(), "b"); assert_eq!(it.value().unwrap().as_int(), 2); let _ = it.next(&value); assert_eq!(it.key().unwrap().as_str(), "c"); assert_eq!(it.value().unwrap().as_int(), 3); - assert_eq!(it.is_end(), true); + assert!(it.is_end()); let _ = it.next(&value); - assert_eq!(it.is_end(), true); + assert!(it.is_end()); } } diff --git a/kclvm/runtime/src/value/mod.rs b/kclvm/runtime/src/value/mod.rs index 3ff12728d..41ab89858 100644 --- a/kclvm/runtime/src/value/mod.rs +++ b/kclvm/runtime/src/value/mod.rs @@ -1,7 +1,6 @@ -// Copyright 2021 The KCL Authors. All rights reserved. +//! Copyright The KCL Authors. All rights reserved. pub mod val_panic; -pub use val_panic::*; pub mod val_overflow; pub use val_overflow::*; @@ -13,49 +12,38 @@ pub mod iter; pub use iter::*; pub mod val; -pub use val::*; pub mod val_len; -pub use val_len::*; pub mod val_args; pub use val_args::*; pub mod val_logic; -pub use val_logic::*; pub mod val_as_val; -pub use val_as_val::*; pub mod val_kind; -pub use val_kind::*; pub mod val_clone; -pub use val_clone::*; pub mod val_cmp; -pub use val_cmp::*; pub mod val_decorator; pub use val_decorator::*; pub mod val_is_in; -pub use val_is_in::*; pub mod val_list; -pub use val_list::*; pub mod val_dict; -pub use val_dict::*; pub mod val_fmt; pub use val_fmt::*; pub mod val_from; -pub use val_from::*; +pub mod val_func; pub mod val_get_set; -pub use val_get_set::*; pub mod val_schema; pub use val_schema::*; @@ -64,19 +52,16 @@ pub mod val_json; pub use val_json::*; pub mod val_bin_aug; -pub use val_bin_aug::*; pub mod val_unary; -pub use val_unary::*; pub mod val_bin; -pub use val_bin::*; pub mod val_plan; -pub use val_plan::*; pub mod val_str; -pub use val_str::*; + +pub mod val_attr; pub mod val_type; pub use val_type::*; @@ -86,3 +71,5 @@ pub use val_union::*; pub mod val_yaml; pub use val_yaml::*; + +pub mod walker; diff --git a/kclvm/runtime/src/value/val.rs b/kclvm/runtime/src/value/val.rs index 215466f50..efc9f986d 100644 --- a/kclvm/runtime/src/value/val.rs +++ b/kclvm/runtime/src/value/val.rs @@ -1,4 +1,6 @@ -// Copyright 2021 The KCL Authors. All rights reserved. +//! Copyright The KCL Authors. All rights reserved. + +use generational_arena::Index; use crate::*; @@ -38,7 +40,7 @@ impl ValueRef { list.values.push((**x).clone()); } } - Self::from(Value::list_value(list)) + Self::from(Value::list_value(Box::new(list))) } pub fn list_value(values: Option<&[Self]>) -> Self { @@ -48,7 +50,7 @@ impl ValueRef { list.values.push((*x).clone()); } } - Self::from(Value::list_value(list)) + Self::from(Value::list_value(Box::new(list))) } pub fn dict(values: Option<&[(&str, &Self)]>) -> Self { @@ -58,12 +60,12 @@ impl ValueRef { dict.values.insert(x.0.to_string(), (*x.1).clone()); } } - Self::from(Value::dict_value(dict)) + Self::from(Value::dict_value(Box::new(dict))) } pub fn schema() -> Self { let s: SchemaValue = Default::default(); - Self::from(Value::schema_value(s)) + Self::from(Value::schema_value(Box::new(s))) } pub fn func( @@ -72,13 +74,42 @@ impl ValueRef { closure: ValueRef, name: &str, runtime_type: &str, + is_external: bool, ) -> Self { - Self::from(Value::func_value(FuncValue { + Self::from(Value::func_value(Box::new(FuncValue { fn_ptr, check_fn_ptr, closure, - external_name: name.to_string(), + name: name.to_string(), + runtime_type: runtime_type.to_string(), + is_external, + proxy: None, + }))) + } + + /// New a proxy function with function index in the function list. + pub fn proxy_func(proxy: Index) -> Self { + Self::from(Value::func_value(Box::new(FuncValue { + fn_ptr: 0, + check_fn_ptr: 0, + closure: ValueRef::undefined(), + name: "".to_string(), + runtime_type: "".to_string(), + is_external: false, + proxy: Some(proxy), + }))) + } + + /// New a proxy function with function index and the runtime type in the function list. + pub fn proxy_func_with_type(proxy: Index, runtime_type: &str) -> Self { + Self::from(Value::func_value(Box::new(FuncValue { + fn_ptr: 0, + check_fn_ptr: 0, + closure: ValueRef::undefined(), + name: "".to_string(), runtime_type: runtime_type.to_string(), - })) + is_external: false, + proxy: Some(proxy), + }))) } } diff --git a/kclvm/runtime/src/value/val_args.rs b/kclvm/runtime/src/value/val_args.rs index 905e309e7..c32810775 100644 --- a/kclvm/runtime/src/value/val_args.rs +++ b/kclvm/runtime/src/value/val_args.rs @@ -1,4 +1,4 @@ -// Copyright 2021 The KCL Authors. All rights reserved. +//! Copyright The KCL Authors. All rights reserved. use crate::*; @@ -17,31 +17,27 @@ pub fn adjust_parameter(value: Option<&ValueRef>) -> Option<&ValueRef> { } impl ValueRef { - pub fn arg_0(&self) -> Option<&Self> { + pub fn arg_0(&self) -> Option { self.arg_i(0) } - pub fn arg_last(&self) -> Option<&Self> { - match *self.rc { - Value::list_value(ref list) => Some(&list.values[list.values.len() - 1]), + pub fn arg_last(&self) -> Option { + match *self.rc.borrow() { + Value::list_value(ref list) => Some(list.values[list.values.len() - 1].clone()), _ => None, } } pub fn pop_arg_last(&self) -> Option { - match *self.rc { - Value::list_value(ref list) => { - let list = get_ref_mut(list); - list.values.pop() - } + match *self.rc.borrow_mut() { + Value::list_value(ref mut list) => list.values.pop(), _ => None, } } pub fn pop_arg_first(&self) -> Option { - match *self.rc { - Value::list_value(ref list) => { - let list = get_ref_mut(list); + match *self.rc.borrow_mut() { + Value::list_value(ref mut list) => { if !list.values.is_empty() { Some(list.values.remove(0)) } else { @@ -53,17 +49,17 @@ impl ValueRef { } pub fn args_len(&self) -> usize { - match *self.rc { + match *self.rc.borrow() { Value::list_value(ref list) => list.values.len(), _ => 1, } } - pub fn arg_i(&self, i: usize) -> Option<&Self> { - match *self.rc { + pub fn arg_i(&self, i: usize) -> Option { + match *self.rc.borrow() { Value::list_value(ref list) => { if i < list.values.len() { - return Some(&list.values[i]); + return Some(list.values[i].clone()); } None } @@ -73,9 +69,9 @@ impl ValueRef { pub fn arg_i_bool(&self, i: usize, default: Option) -> Option { if let Some(x) = self.arg_i(i) { - match *x.rc { + match *x.rc.borrow() { Value::bool_value(v) => return Some(v), - Value::none => return default, + Value::none | Value::undefined => return default, _ => return None, } } @@ -84,9 +80,21 @@ impl ValueRef { pub fn arg_i_int(&self, i: usize, default: Option) -> Option { if let Some(x) = self.arg_i(i) { - match *x.rc { + match *x.rc.borrow() { + Value::int_value(v) => return Some(v), + Value::none | Value::undefined => return default, + _ => return None, + } + } + default + } + + pub fn arg_i_int_or_bool(&self, i: usize, default: Option) -> Option { + if let Some(x) = self.arg_i(i) { + match *x.rc.borrow() { + Value::bool_value(v) => return Some(v as i64), Value::int_value(v) => return Some(v), - Value::none => return default, + Value::none | Value::undefined => return default, _ => return None, } } @@ -95,9 +103,9 @@ impl ValueRef { pub fn arg_i_float(&self, i: usize, default: Option) -> Option { if let Some(x) = self.arg_i(i) { - match *x.rc { + match *x.rc.borrow() { Value::float_value(v) => return Some(v), - Value::none => return default, + Value::none | Value::undefined => return default, _ => return None, } } @@ -106,10 +114,10 @@ impl ValueRef { pub fn arg_i_num(&self, i: usize, default: Option) -> Option { if let Some(x) = self.arg_i(i) { - match *x.rc { + match *x.rc.borrow() { Value::float_value(v) => return Some(v), Value::int_value(v) => return Some(v as f64), - Value::none => return default, + Value::none | Value::undefined => return default, _ => return None, } } @@ -118,47 +126,41 @@ impl ValueRef { pub fn arg_i_str(&self, i: usize, default: Option) -> Option { if let Some(x) = self.arg_i(i) { - match &*x.rc { + match &*x.rc.borrow() { Value::str_value(s) => return Some(s.to_string()), - Value::none => return default, + Value::none | Value::undefined => return default, _ => return None, } } default } - pub fn arg_i_list(&self, i: usize) -> Option<&Self> { + pub fn arg_i_list(&self, i: usize) -> Option { if let Some(x) = self.arg_i(i) { - match *x.rc { - Value::list_value(_) => return Some(x), - _ => return None, - } + return if x.is_list() { Some(x) } else { None }; } None } - pub fn arg_i_dict(&self, i: usize) -> Option<&Self> { + pub fn arg_i_dict(&self, i: usize) -> Option { if let Some(x) = self.arg_i(i) { - match *x.rc { - Value::dict_value(_) => return Some(x), - _ => return None, - } + return if x.is_dict() { Some(x) } else { None }; } None } - pub fn kwarg(&self, name: &str) -> Option<&Self> { - match *self.rc { - Value::dict_value(ref dict) => dict.values.get(&name.to_string()), + pub fn kwarg(&self, name: &str) -> Option { + match *self.rc.borrow() { + Value::dict_value(ref dict) => dict.values.get(&name.to_string()).cloned(), _ => None, } } pub fn kwarg_bool(&self, name: &str, default: Option) -> Option { if let Some(x) = self.kwarg(name) { - match *x.rc { + match *x.rc.borrow() { Value::bool_value(v) => return Some(v), - Value::none => return default, + Value::none | Value::undefined => return default, _ => return None, } } @@ -167,9 +169,9 @@ impl ValueRef { pub fn kwarg_int(&self, name: &str, default: Option) -> Option { if let Some(x) = self.kwarg(name) { - match *x.rc { + match *x.rc.borrow() { Value::int_value(v) => return Some(v), - Value::none => return default, + Value::none | Value::undefined => return default, _ => return None, } } @@ -178,9 +180,9 @@ impl ValueRef { pub fn kwarg_float(&self, name: &str, default: Option) -> Option { if let Some(x) = self.kwarg(name) { - match *x.rc { + match *x.rc.borrow() { Value::float_value(v) => return Some(v), - Value::none => return default, + Value::none | Value::undefined => return default, _ => return None, } } @@ -189,36 +191,88 @@ impl ValueRef { pub fn kwarg_str(&self, name: &str, default: Option) -> Option { if let Some(x) = self.kwarg(name) { - match &*x.rc { + match &*x.rc.borrow() { Value::str_value(s) => return Some(s.to_string()), - Value::none => return default, + Value::none | Value::undefined => return default, _ => return None, } } default } - pub fn kwarg_list(&self, name: &str) -> Option<&Self> { + pub fn kwarg_list(&self, name: &str) -> Option { if let Some(x) = self.kwarg(name) { - match *x.rc { - Value::list_value(_) => return Some(x), - _ => return None, - } + return if x.is_list() { Some(x) } else { None }; } None } - pub fn kwarg_dict(&self, name: &str) -> Option<&Self> { + pub fn kwarg_dict(&self, name: &str) -> Option { if let Some(x) = self.kwarg(name) { - match *x.rc { - Value::dict_value(_) => return Some(x), - _ => return None, - } + return if x.is_dict() { Some(x) } else { None }; } None } } +/// Get value from arguments and keyword arguments. +pub fn get_call_arg( + args: &ValueRef, + kwargs: &ValueRef, + index: usize, + key: Option<&str>, +) -> Option { + if let Some(key) = key { + if let Some(val) = kwargs.get_by_key(key) { + return Some(val); + } + } + if index < args.len() { + return Some(args.list_get(index as isize).unwrap()); + } + None +} + +#[inline] +pub fn get_call_arg_str( + args: &ValueRef, + kwargs: &ValueRef, + index: usize, + key: Option<&str>, +) -> Option { + get_call_arg(args, kwargs, index, key).map(|v| v.as_str()) +} + +#[inline] +pub fn get_call_arg_bool( + args: &ValueRef, + kwargs: &ValueRef, + index: usize, + key: Option<&str>, +) -> Option { + get_call_arg(args, kwargs, index, key).map(|v| v.as_bool()) +} + +#[inline] +pub fn get_call_arg_int( + args: &ValueRef, + kwargs: &ValueRef, + index: usize, + key: Option<&str>, +) -> Option { + get_call_arg(args, kwargs, index, key).map(|v| v.must_as_strict_int()) +} + +#[inline] +pub fn get_call_arg_num( + args: &ValueRef, + kwargs: &ValueRef, + index: usize, + key: Option<&str>, +) -> Option { + get_call_arg(args, kwargs, index, key).map(|v| v.as_num()) +} + #[cfg(test)] mod test_value_args { use crate::*; diff --git a/kclvm/runtime/src/value/val_as_val.rs b/kclvm/runtime/src/value/val_as_val.rs index e870cd720..7e79f566c 100644 --- a/kclvm/runtime/src/value/val_as_val.rs +++ b/kclvm/runtime/src/value/val_as_val.rs @@ -1,7 +1,8 @@ -// Copyright 2021 The KCL Authors. All rights reserved. +//! Copyright The KCL Authors. All rights reserved. use crate::*; - +use std::cell::Ref; +use std::cell::RefMut; impl ValueRef { #[inline] pub fn as_bool(&self) -> bool { @@ -10,7 +11,7 @@ impl ValueRef { #[inline] pub fn as_int(&self) -> i64 { - match *self.rc { + match *self.rc.borrow() { Value::int_value(ref v) => *v, Value::float_value(ref v) => *v as i64, Value::unit_value(ref v, _, _) => *v as i64, @@ -18,9 +19,17 @@ impl ValueRef { } } + #[inline] + pub fn must_as_strict_int(&self) -> i64 { + match *self.rc.borrow() { + Value::int_value(ref v) => *v, + _ => panic!("invalid int value"), + } + } + #[inline] pub fn as_float(&self) -> f64 { - match *self.rc { + match *self.rc.borrow() { Value::int_value(ref v) => *v as f64, Value::float_value(ref v) => *v, Value::unit_value(ref v, _, _) => *v, @@ -28,67 +37,76 @@ impl ValueRef { } } + #[inline] + pub fn as_num(&self) -> f64 { + match *self.rc.borrow() { + Value::float_value(v) => v, + Value::int_value(v) => v as f64, + _ => return 0.0, + } + } + #[inline] pub fn as_str(&self) -> String { - match *self.rc { + match *self.rc.borrow() { Value::str_value(ref v) => v.clone(), _ => "".to_string(), } } #[inline] - pub fn as_list_ref(&self) -> &ListValue { - match *self.rc { - Value::list_value(ref v) => v, + pub fn as_list_ref(&self) -> Ref { + Ref::map(self.rc.borrow(), |val| match val { + Value::list_value(ref v) => v.as_ref(), _ => panic!("invalid list value"), - } + }) } #[inline] - pub fn as_list_mut_ref(&mut self) -> &mut ListValue { - match *self.rc { - Value::list_value(ref v) => get_ref_mut(v), + pub fn as_list_mut_ref(&mut self) -> RefMut { + RefMut::map(self.rc.borrow_mut(), |val| match val { + Value::list_value(ref mut v) => v.as_mut(), _ => panic!("invalid list value"), - } + }) } #[inline] - pub fn as_dict_ref(&self) -> &DictValue { - match *self.rc { - Value::dict_value(ref v) => v, + pub fn as_dict_ref(&self) -> Ref { + Ref::map(self.rc.borrow(), |val| match val { + Value::dict_value(ref v) => v.as_ref(), Value::schema_value(ref v) => v.config.as_ref(), _ => panic!("invalid dict value"), - } + }) } #[inline] - pub fn as_dict_mut_ref(&mut self) -> &mut DictValue { - match *self.rc { - Value::dict_value(ref v) => get_ref_mut(v), - Value::schema_value(ref v) => get_ref_mut(v.config.as_ref()), + pub fn as_dict_mut_ref(&mut self) -> RefMut { + RefMut::map(self.rc.borrow_mut(), |val| match val { + Value::dict_value(ref mut v) => v.as_mut(), + Value::schema_value(ref mut v) => v.config.as_mut(), _ => panic!("invalid dict value"), - } + }) } #[inline] - pub fn as_schema(&self) -> &SchemaValue { - match *self.rc { - Value::schema_value(ref v) => v, + pub fn as_schema(&self) -> Ref { + Ref::map(self.rc.borrow(), |val| match val { + Value::schema_value(ref v) => v.as_ref(), _ => panic!("invalid schema value"), - } + }) } #[inline] - pub fn as_function(&self) -> &FuncValue { - match *self.rc { - Value::func_value(ref v) => v, - _ => panic!("invalid function value"), - } + pub fn as_function(&self) -> Ref { + Ref::map(self.rc.borrow(), |val| match val { + Value::func_value(ref v) => v.as_ref(), + _ => panic!("invalid func value"), + }) } #[inline] pub fn as_unit(&self) -> (f64, i64, String) { - match &*self.rc { + match &*self.rc.borrow() { Value::unit_value(v, raw, unit) => (*v, *raw, unit.clone()), _ => panic!("invalid unit value"), } diff --git a/kclvm/runtime/src/value/val_attr.rs b/kclvm/runtime/src/value/val_attr.rs new file mode 100644 index 000000000..8b08dd678 --- /dev/null +++ b/kclvm/runtime/src/value/val_attr.rs @@ -0,0 +1,75 @@ +//! Copyright The KCL Authors. All rights reserved. + +use crate::*; + +impl ValueRef { + /// Load attribute named `key` from the self value, the attribute maybe a + /// member function or a builtin value. + pub fn load_attr(&self, key: &str) -> Self { + let p: &ValueRef = self; + // load_attr including str/dict/schema. + if p.is_dict() { + match p.dict_get_value(key) { + Some(x) => x, + None => ValueRef::undefined(), + } + } else if p.is_schema() { + let dict = p.schema_to_dict(); + match dict.dict_get_value(key) { + Some(x) => x, + None => panic!("schema '{}' attribute '{}' not found", p.type_str(), key), + } + } else if p.is_str() { + let function = match key { + "lower" => kclvm_builtin_str_lower, + "upper" => kclvm_builtin_str_upper, + "capitalize" => kclvm_builtin_str_capitalize, + "chars" => kclvm_builtin_str_chars, + "count" => kclvm_builtin_str_count, + "endswith" => kclvm_builtin_str_endswith, + "find" => kclvm_builtin_str_find, + "format" => kclvm_builtin_str_format, + "index" => kclvm_builtin_str_index, + "isalnum" => kclvm_builtin_str_isalnum, + "isalpha" => kclvm_builtin_str_isalpha, + "isdigit" => kclvm_builtin_str_isdigit, + "islower" => kclvm_builtin_str_islower, + "isspace" => kclvm_builtin_str_isspace, + "istitle" => kclvm_builtin_str_istitle, + "isupper" => kclvm_builtin_str_isupper, + "join" => kclvm_builtin_str_join, + "lstrip" => kclvm_builtin_str_lstrip, + "rstrip" => kclvm_builtin_str_rstrip, + "replace" => kclvm_builtin_str_replace, + "removeprefix" => kclvm_builtin_str_removeprefix, + "removesuffix" => kclvm_builtin_str_removesuffix, + "rfind" => kclvm_builtin_str_rfind, + "rindex" => kclvm_builtin_str_rindex, + "rsplit" => kclvm_builtin_str_rsplit, + "split" => kclvm_builtin_str_split, + "splitlines" => kclvm_builtin_str_splitlines, + "startswith" => kclvm_builtin_str_startswith, + "strip" => kclvm_builtin_str_strip, + "title" => kclvm_builtin_str_title, + _ => panic!("str object attr '{key}' not found"), + }; + let closure = ValueRef::list(Some(&[p])); + ValueRef::func(function as usize as u64, 0, closure, "", "", false) + } + // schema instance + else if p.is_func() { + let function = match key { + "instances" => kclvm_schema_instances, + _ => panic!("schema object attr '{key}' not found"), + }; + let closure = ValueRef::list(Some(&[p])); + ValueRef::func(function as usize as u64, 0, closure, "", "", false) + } else { + panic!( + "invalid value '{}' to load attribute '{}'", + p.type_str(), + key + ); + } + } +} diff --git a/kclvm/runtime/src/value/val_bin.rs b/kclvm/runtime/src/value/val_bin.rs index 75e2b0bb5..38fb862ad 100644 --- a/kclvm/runtime/src/value/val_bin.rs +++ b/kclvm/runtime/src/value/val_bin.rs @@ -1,45 +1,38 @@ -// Copyright 2021 The KCL Authors. All rights reserved. +//! Copyright The KCL Authors. All rights reserved. use crate::*; impl ValueRef { - pub fn bin_add(&self, x: &Self) -> Self { - let ctx = crate::Context::current_context_mut(); + pub fn bin_add(&self, ctx: &mut Context, x: &Self) -> Self { let strict_range_check_32 = ctx.cfg.strict_range_check; let strict_range_check_64 = ctx.cfg.debug_mode || !ctx.cfg.strict_range_check; - match (&*self.rc, &*x.rc) { + match (&*self.rc.borrow(), &*x.rc.borrow()) { (Value::int_value(a), Value::int_value(b)) => { - if strict_range_check_32 { - if is_i32_overflow_add(*a, *b) { - panic_i32_overflow!(*a as i128 + *b as i128); - } + if strict_range_check_32 && is_i32_overflow_add(*a, *b) { + panic_i32_overflow!(ctx, *a as i128 + *b as i128); } - if strict_range_check_64 { - if is_i64_overflow_add(*a, *b) { - panic_i64_overflow!(*a as i128 + *b as i128); - } + if strict_range_check_64 && is_i64_overflow_add(*a, *b) { + panic_i64_overflow!(ctx, *a as i128 + *b as i128); } Self::int(*a + *b) } (Value::float_value(a), Value::float_value(b)) => { - if strict_range_check_32 { - if is_f32_overflow_add(*a, *b) { - panic_f32_overflow!(*a + *b); - } + if strict_range_check_32 && is_f32_overflow_add(*a, *b) { + panic_f32_overflow!(ctx, *a + *b); } Self::float(*a + *b) } (Value::int_value(a), Value::float_value(b)) => { if is_f32_overflow_add(*a as f64, *b) { - panic_f32_overflow!(*a as f64 + *b); + panic_f32_overflow!(ctx, *a as f64 + *b); } Self::float(*a as f64 + *b) } (Value::float_value(a), Value::int_value(b)) => { if is_f32_overflow_add(*a, *b as f64) { - panic_f32_overflow!(*a + *b as f64); + panic_f32_overflow!(ctx, *a + *b as f64); } Self::float(*a + *b as f64) } @@ -67,46 +60,35 @@ impl ValueRef { } } - pub fn bin_sub(&self, x: &Self) -> Self { - let ctx = crate::Context::current_context_mut(); + pub fn bin_sub(&self, ctx: &mut Context, x: &Self) -> Self { let strict_range_check_32 = ctx.cfg.strict_range_check; let strict_range_check_64 = ctx.cfg.debug_mode || !ctx.cfg.strict_range_check; - match (&*self.rc, &*x.rc) { + match (&*self.rc.borrow(), &*x.rc.borrow()) { (Value::int_value(a), Value::int_value(b)) => { - if strict_range_check_32 { - if is_i32_overflow_sub(*a, *b) { - panic_i32_overflow!(*a as i128 - *b as i128); - } + if strict_range_check_32 && is_i32_overflow_sub(*a, *b) { + panic_i32_overflow!(ctx, *a as i128 - *b as i128); } - if strict_range_check_64 { - if is_i64_overflow_sub(*a, *b) { - panic_i32_overflow!(*a as i128 - *b as i128); - } + if strict_range_check_64 && is_i64_overflow_sub(*a, *b) { + panic_i32_overflow!(ctx, *a as i128 - *b as i128); } Self::int(*a - *b) } (Value::float_value(a), Value::float_value(b)) => { - if strict_range_check_32 { - if is_f32_overflow_sub(*a, *b) { - panic_f32_overflow!(*a - *b); - } + if strict_range_check_32 && is_f32_overflow_sub(*a, *b) { + panic_f32_overflow!(ctx, *a - *b); } Self::float(*a - *b) } (Value::int_value(a), Value::float_value(b)) => { - if strict_range_check_32 { - if is_f32_overflow_sub(*a as f64, *b) { - panic_f32_overflow!(*a as f64 - *b); - } + if strict_range_check_32 && is_f32_overflow_sub(*a as f64, *b) { + panic_f32_overflow!(ctx, *a as f64 - *b); } Self::float(*a as f64 - *b) } (Value::float_value(a), Value::int_value(b)) => { - if strict_range_check_32 { - if is_f32_overflow_sub(*a, *b as f64) { - panic_f32_overflow!(*a - *b as f64); - } + if strict_range_check_32 && is_f32_overflow_sub(*a, *b as f64) { + panic_f32_overflow!(ctx, *a - *b as f64); } Self::float(*a - *b as f64) } @@ -114,46 +96,35 @@ impl ValueRef { } } - pub fn bin_mul(&self, x: &Self) -> Self { - let ctx = crate::Context::current_context_mut(); + pub fn bin_mul(&self, ctx: &mut Context, x: &Self) -> Self { let strict_range_check_32 = ctx.cfg.strict_range_check; let strict_range_check_64 = ctx.cfg.debug_mode || !ctx.cfg.strict_range_check; - match (&*self.rc, &*x.rc) { + match (&*self.rc.borrow(), &*x.rc.borrow()) { (Value::int_value(a), Value::int_value(b)) => { - if strict_range_check_32 { - if is_i32_overflow_mul(*a, *b) { - panic_i32_overflow!(*a as i128 * *b as i128); - } + if strict_range_check_32 && is_i32_overflow_mul(*a, *b) { + panic_i32_overflow!(ctx, *a as i128 * *b as i128); } - if strict_range_check_64 { - if is_i64_overflow_mul(*a, *b) { - panic_i64_overflow!(*a as i128 * *b as i128); - } + if strict_range_check_64 && is_i64_overflow_mul(*a, *b) { + panic_i64_overflow!(ctx, *a as i128 * *b as i128); } Self::int(*a * *b) } (Value::float_value(a), Value::float_value(b)) => { - if strict_range_check_32 { - if is_f32_overflow_mul(*a, *b) { - panic_f32_overflow!(*a * *b); - } + if strict_range_check_32 && is_f32_overflow_mul(*a, *b) { + panic_f32_overflow!(ctx, *a * *b); } Self::float(*a * *b) } (Value::int_value(a), Value::float_value(b)) => { - if strict_range_check_32 { - if is_f32_overflow_mul(*a as f64, *b) { - panic_f32_overflow!(*a as f64 * *b); - } + if strict_range_check_32 && is_f32_overflow_mul(*a as f64, *b) { + panic_f32_overflow!(ctx, *a as f64 * *b); } Self::float(*a as f64 * *b) } (Value::float_value(a), Value::int_value(b)) => { - if strict_range_check_32 { - if is_f32_overflow_mul(*a, *b as f64) { - panic_f32_overflow!(*a * *b as f64); - } + if strict_range_check_32 && is_f32_overflow_mul(*a, *b as f64) { + panic_f32_overflow!(ctx, *a * *b as f64); } Self::float(*a * *b as f64) } @@ -164,26 +135,26 @@ impl ValueRef { let mut list = ListValue::default(); for _ in 0..(*b as usize) { for x in a.values.iter() { - list.values.push(x.clone()); + list.values.push(x.deep_copy()); } } - Self::from(Value::list_value(list)) + Self::from(Value::list_value(Box::new(list))) } (Value::int_value(b), Value::list_value(a)) => { let mut list = ListValue::default(); for _ in 0..(*b as usize) { for x in a.values.iter() { - list.values.push(x.clone()); + list.values.push(x.deep_copy()); } } - Self::from(Value::list_value(list)) + Self::from(Value::list_value(Box::new(list))) } _ => panic_unsupported_bin_op!("*", self.type_str(), x.type_str()), } } pub fn bin_div(&self, x: &Self) -> Self { - match (&*self.rc, &*x.rc) { + match (&*self.rc.borrow(), &*x.rc.borrow()) { (Value::int_value(a), Value::int_value(b)) => Self::float((*a as f64) / (*b as f64)), (Value::float_value(a), Value::float_value(b)) => Self::float(*a / *b), (Value::int_value(a), Value::float_value(b)) => Self::float(*a as f64 / *b), @@ -193,11 +164,11 @@ impl ValueRef { } pub fn bin_mod(&self, x: &Self) -> Self { - match (&*self.rc, &*x.rc) { + match (&*self.rc.borrow(), &*x.rc.borrow()) { (Value::int_value(a), Value::int_value(b)) => { let x = *a; let y = *b; - if -13 / 5 == -2 && (x < 0) != (y < 0) && x % y != 0 { + if (x < 0) != (y < 0) && x % y != 0 { Self::int(x % y + y) } else { Self::int(x % y) @@ -210,46 +181,35 @@ impl ValueRef { } } - pub fn bin_pow(&self, x: &Self) -> Self { - let ctx = crate::Context::current_context_mut(); + pub fn bin_pow(&self, ctx: &mut Context, x: &Self) -> Self { let strict_range_check_32 = ctx.cfg.strict_range_check; let strict_range_check_64 = ctx.cfg.debug_mode || !ctx.cfg.strict_range_check; - match (&*self.rc, &*x.rc) { + match (&*self.rc.borrow(), &*x.rc.borrow()) { (Value::int_value(ref a), Value::int_value(b)) => { - if strict_range_check_32 { - if is_i32_overflow_pow(*a, *b) { - panic_i32_overflow!((*a as i128).pow(*b as u32)); - } + if strict_range_check_32 && is_i32_overflow_pow(*a, *b) { + panic_i32_overflow!(ctx, (*a as i128).pow(*b as u32)); } - if strict_range_check_64 { - if is_i64_overflow_pow(*a, *b) { - panic_i64_overflow!((*a as i128).pow(*b as u32)); - } + if strict_range_check_64 && is_i64_overflow_pow(*a, *b) { + panic_i64_overflow!(ctx, (*a as i128).pow(*b as u32)); } Self::int(a.pow(*b as u32)) } (Value::float_value(a), Value::float_value(b)) => { - if strict_range_check_32 { - if is_f32_overflow_pow(*a, *b) { - panic_f32_overflow!(a.powf(*b)); - } + if strict_range_check_32 && is_f32_overflow_pow(*a, *b) { + panic_f32_overflow!(ctx, a.powf(*b)); } Self::float(a.powf(*b)) } (Value::int_value(a), Value::float_value(b)) => { - if strict_range_check_32 { - if is_f32_overflow_pow(*a as f64, *b) { - panic_f32_overflow!((*a as f64).powf(*b)); - } + if strict_range_check_32 && is_f32_overflow_pow(*a as f64, *b) { + panic_f32_overflow!(ctx, (*a as f64).powf(*b)); } Self::float((*a as f64).powf(*b)) } (Value::float_value(a), Value::int_value(b)) => { - if strict_range_check_32 { - if is_f32_overflow_pow(*a, *b as f64) { - panic_f32_overflow!(a.powf(*b as f64)); - } + if strict_range_check_32 && is_f32_overflow_pow(*a, *b as f64) { + panic_f32_overflow!(ctx, a.powf(*b as f64)); } Self::float(a.powf(*b as f64)) } @@ -258,11 +218,11 @@ impl ValueRef { } pub fn bin_floor_div(&self, x: &Self) -> Self { - match (&*self.rc, &*x.rc) { + match (&*self.rc.borrow(), &*x.rc.borrow()) { (Value::int_value(a), Value::int_value(b)) => { let x = *a; let y = *b; - if -13 / 5 == -2 && (x < 0) != (y < 0) && x % y != 0 { + if (x < 0) != (y < 0) && x % y != 0 { Self::int(x / y - 1) } else { Self::int(x / y) @@ -275,22 +235,17 @@ impl ValueRef { } } - pub fn bin_bit_lshift(&self, x: &Self) -> Self { - let ctx = crate::Context::current_context_mut(); + pub fn bin_bit_lshift(&self, ctx: &mut Context, x: &Self) -> Self { let strict_range_check_32 = ctx.cfg.strict_range_check; let strict_range_check_64 = ctx.cfg.debug_mode || !ctx.cfg.strict_range_check; - match (&*self.rc, &*x.rc) { + match (&*self.rc.borrow(), &*x.rc.borrow()) { (Value::int_value(a), Value::int_value(b)) => { - if strict_range_check_32 { - if is_i32_overflow_shl(*a, *b) { - panic_i32_overflow!((*a as i128) << (*b as u32)); - } + if strict_range_check_32 && is_i32_overflow_shl(*a, *b) { + panic_i32_overflow!(ctx, (*a as i128) << (*b as u32)); } - if strict_range_check_64 { - if is_i64_overflow_shl(*a, *b) { - panic_i64_overflow!((*a as i128) << (*b as u32)); - } + if strict_range_check_64 && is_i64_overflow_shl(*a, *b) { + panic_i64_overflow!(ctx, (*a as i128) << (*b as u32)); } Self::int(*a << *b) } @@ -298,22 +253,17 @@ impl ValueRef { } } - pub fn bin_bit_rshift(&self, x: &Self) -> Self { - let ctx = crate::Context::current_context_mut(); + pub fn bin_bit_rshift(&self, ctx: &mut Context, x: &Self) -> Self { let strict_range_check_32 = ctx.cfg.strict_range_check; let strict_range_check_64 = ctx.cfg.debug_mode || !ctx.cfg.strict_range_check; - match (&*self.rc, &*x.rc) { + match (&*self.rc.borrow(), &*x.rc.borrow()) { (Value::int_value(a), Value::int_value(b)) => { - if strict_range_check_32 { - if is_i32_overflow_shr(*a, *b) { - panic_i32_overflow!((*a as i128) >> (*b as u32)); - } + if strict_range_check_32 && is_i32_overflow_shr(*a, *b) { + panic_i32_overflow!(ctx, (*a as i128) >> (*b as u32)); } - if strict_range_check_64 { - if is_i64_overflow_shr(*a, *b) { - panic_i64_overflow!((*a as i128) >> (*b as u32)); - } + if strict_range_check_64 && is_i64_overflow_shr(*a, *b) { + panic_i64_overflow!(ctx, (*a as i128) >> (*b as u32)); } Self::int(*a >> *b) } @@ -322,54 +272,47 @@ impl ValueRef { } pub fn bin_bit_and(&self, x: &Self) -> Self { - match (&*self.rc, &*x.rc) { + match (&*self.rc.borrow(), &*x.rc.borrow()) { (Value::int_value(a), Value::int_value(b)) => Self::int(*a & *b), _ => panic_unsupported_bin_op!("&", self.type_str(), x.type_str()), } } pub fn bin_bit_xor(&self, x: &Self) -> Self { - match (&*self.rc, &*x.rc) { + match (&*self.rc.borrow(), &*x.rc.borrow()) { (Value::int_value(a), Value::int_value(b)) => Self::int(*a ^ *b), _ => panic_unsupported_bin_op!("^", self.type_str(), x.type_str()), } } - pub fn bin_bit_or(&self, x: &Self) -> Self { - match (&*self.rc, &*x.rc) { - (Value::int_value(a), Value::int_value(b)) => Self::int(*a | *b), - _ => self.deep_copy().union(x, true, false, true, true), - } + pub fn bin_bit_or(&self, ctx: &mut Context, x: &Self) -> Self { + if let (Value::int_value(a), Value::int_value(b)) = (&*self.rc.borrow(), &*x.rc.borrow()) { + return Self::int(*a | *b); + }; + self.deep_copy() + .union_entry(ctx, x, true, &UnionOptions::default()) } pub fn bin_subscr(&self, x: &Self) -> Self { - match (&*self.rc, &*x.rc) { + match (&*self.rc.borrow(), &*x.rc.borrow()) { (Value::str_value(a), Value::int_value(b)) => { let str_len = a.chars().count(); let index = *b; - let index = if index < 0 { - (index + str_len as i64) as usize - } else { - index as usize - }; + let index = must_normalize_index(index as i32, str_len); if index < a.len() { let ch = a.chars().nth(index).unwrap(); Self::str(ch.to_string().as_ref()) } else { - panic!("string index out of range: {}", b.to_string()); + panic!("string index out of range: {b}"); } } (Value::list_value(a), Value::int_value(b)) => { let index = *b; - let index = if index < 0 { - (index + a.values.len() as i64) as usize - } else { - index as usize - }; + let index = must_normalize_index(index as i32, a.values.len()); if index < a.values.len() { a.values[index].clone() } else { - panic!("list index out of range: {}", b.to_string()); + panic!("list index out of range: {b}"); } } (Value::dict_value(a), Value::str_value(b)) => match a.values.get(b) { @@ -396,6 +339,21 @@ impl ValueRef { Self::none() } } + + pub fn bin_subscr_set(&mut self, ctx: &mut Context, x: &Self, v: &Self) { + if self.is_list() && x.is_int() { + self.list_set_value(x, v); + } else if self.is_config() && x.is_str() { + let key = x.as_str(); + self.dict_set_value(ctx, &key, v); + } else { + panic!( + "'{}' object is not subscriptable with '{}'", + self.type_str(), + x.type_str() + ); + } + } } #[cfg(test)] @@ -405,6 +363,7 @@ mod test_value_bin { #[test] fn test_int_bin() { + let mut ctx = Context::new(); let cases = [ (0, 0, "+", 0), (1, 1, "-", 0), @@ -423,17 +382,17 @@ mod test_value_bin { let left = ValueRef::int(left); let right = ValueRef::int(right); let result = match op { - "+" => left.bin_add(&right), - "-" => left.bin_sub(&right), - "*" => left.bin_mul(&right), + "+" => left.bin_add(&mut ctx, &right), + "-" => left.bin_sub(&mut ctx, &right), + "*" => left.bin_mul(&mut ctx, &right), "/" => left.bin_div(&right), "//" => left.bin_floor_div(&right), "%" => left.bin_mod(&right), - "**" => left.bin_pow(&right), - "<<" => left.bin_bit_lshift(&right), - ">>" => left.bin_bit_rshift(&right), + "**" => left.bin_pow(&mut ctx, &right), + "<<" => left.bin_bit_lshift(&mut ctx, &right), + ">>" => left.bin_bit_rshift(&mut ctx, &right), "&" => left.bin_bit_and(&right), - "|" => left.bin_bit_or(&right), + "|" => left.bin_bit_or(&mut ctx, &right), "^" => left.bin_bit_xor(&right), _ => panic!("invalid op {}", op), }; diff --git a/kclvm/runtime/src/value/val_bin_aug.rs b/kclvm/runtime/src/value/val_bin_aug.rs index b3682ff6e..d5e2c4543 100644 --- a/kclvm/runtime/src/value/val_bin_aug.rs +++ b/kclvm/runtime/src/value/val_bin_aug.rs @@ -1,439 +1,400 @@ -// Copyright 2021 The KCL Authors. All rights reserved. +//! Copyright The KCL Authors. All rights reserved. use crate::*; impl ValueRef { - pub fn bin_aug_add(&mut self, x: &Self) -> &mut Self { - let ctx = crate::Context::current_context_mut(); + pub fn bin_aug_add(&mut self, ctx: &mut Context, x: &Self) -> &mut Self { let strict_range_check_32 = ctx.cfg.strict_range_check; let strict_range_check_64 = ctx.cfg.debug_mode || !ctx.cfg.strict_range_check; - match (&*self.rc, &*x.rc) { + let valid = match (&mut *self.rc.borrow_mut(), &*x.rc.borrow()) { (Value::int_value(a), Value::int_value(b)) => { - if strict_range_check_32 { - if is_i32_overflow_add(*a, *b) { - panic_i32_overflow!(*a as i128 + *b as i128); - } + if strict_range_check_32 && is_i32_overflow_add(*a, *b) { + panic_i32_overflow!(ctx, *a as i128 + *b as i128); } - if strict_range_check_64 { - if is_i64_overflow_add(*a, *b) { - panic_i64_overflow!(*a as i128 + *b as i128); - } + if strict_range_check_64 && is_i64_overflow_add(*a, *b) { + panic_i64_overflow!(ctx, *a as i128 + *b as i128); } - let a: &mut i64 = get_ref_mut(a); *a += *b; - self + true } (Value::float_value(a), Value::float_value(b)) => { - if strict_range_check_32 { - if is_f32_overflow_add(*a, *b) { - panic_f32_overflow!(*a + *b); - } + if strict_range_check_32 && is_f32_overflow_add(*a, *b) { + panic_f32_overflow!(ctx, *a + *b); } - let a: &mut f64 = get_ref_mut(a); *a += *b; - self + true } (Value::int_value(a), Value::float_value(b)) => { if is_f32_overflow_add(*a as f64, *b) { - panic_f32_overflow!(*a as f64 + *b); + panic_f32_overflow!(ctx, *a as f64 + *b); } - let a: &mut i64 = get_ref_mut(a); *a += *b as i64; - self + true } (Value::float_value(a), Value::int_value(b)) => { if is_f32_overflow_add(*a, *b as f64) { - panic_f32_overflow!(*a + *b as f64); + panic_f32_overflow!(ctx, *a + *b as f64); } - let a: &mut f64 = get_ref_mut(a); *a += *b as f64; - self + true } (Value::str_value(a), Value::str_value(b)) => { - let a: &mut String = get_ref_mut(a); *a = format!("{}{}", *a, *b); - self + true } - (Value::list_value(a), _) => match &*x.rc { + (Value::list_value(a), _) => match &*x.rc.borrow() { Value::list_value(ref b) => { - let list: &mut ListValue = get_ref_mut(a); for x in b.values.iter() { - list.values.push(x.clone()); + a.values.push(x.clone()); } - self + true } - _ => panic_unsupported_bin_op!("+", self.type_str(), x.type_str()), + _ => false, }, - _ => panic_unsupported_bin_op!("+", self.type_str(), x.type_str()), + _ => false, + }; + if !valid { + panic_unsupported_bin_op!("+", self.type_str(), x.type_str()) } + self } - pub fn bin_aug_sub(&mut self, x: &Self) -> &mut Self { - let ctx = crate::Context::current_context_mut(); + pub fn bin_aug_sub(&mut self, ctx: &mut Context, x: &Self) -> &mut Self { let strict_range_check_32 = ctx.cfg.strict_range_check; let strict_range_check_64 = ctx.cfg.debug_mode || !ctx.cfg.strict_range_check; - match (&*self.rc, &*x.rc) { + let valid = match (&mut *self.rc.borrow_mut(), &*x.rc.borrow()) { (Value::int_value(a), Value::int_value(b)) => { - if strict_range_check_32 { - if is_i32_overflow_sub(*a, *b) { - panic_i32_overflow!(*a as i128 - *b as i128); - } + if strict_range_check_32 && is_i32_overflow_sub(*a, *b) { + panic_i32_overflow!(ctx, *a as i128 - *b as i128); } - if strict_range_check_64 { - if is_i64_overflow_sub(*a, *b) { - panic_i32_overflow!(*a as i128 - *b as i128); + if strict_range_check_64 && is_i64_overflow_sub(*a, *b) { + { + panic_i32_overflow!(ctx, *a as i128 - *b as i128); } } - let a: &mut i64 = get_ref_mut(a); *a -= *b; - self + true } (Value::float_value(a), Value::float_value(b)) => { - if strict_range_check_32 { - if is_f32_overflow_sub(*a, *b) { - panic_f32_overflow!(*a - *b); - } + if strict_range_check_32 && is_f32_overflow_sub(*a, *b) { + panic_f32_overflow!(ctx, *a - *b); } - let a: &mut f64 = get_ref_mut(a); *a -= *b; - self + true } (Value::int_value(a), Value::float_value(b)) => { - if strict_range_check_32 { - if is_f32_overflow_sub(*a as f64, *b) { - panic_f32_overflow!(*a as f64 - *b); - } + if strict_range_check_32 && is_f32_overflow_sub(*a as f64, *b) { + panic_f32_overflow!(ctx, *a as f64 - *b); } - let a: &mut i64 = get_ref_mut(a); *a -= *b as i64; - self + true } (Value::float_value(a), Value::int_value(b)) => { - if strict_range_check_32 { - if is_f32_overflow_sub(*a, *b as f64) { - panic_f32_overflow!(*a - *b as f64); - } + if strict_range_check_32 && is_f32_overflow_sub(*a, *b as f64) { + panic_f32_overflow!(ctx, *a - *b as f64); } - let a: &mut f64 = get_ref_mut(a); *a -= *b as f64; - self + true } - _ => panic_unsupported_bin_op!("-", self.type_str(), x.type_str()), + _ => false, + }; + if !valid { + panic_unsupported_bin_op!("-", self.type_str(), x.type_str()) } + self } - pub fn bin_aug_mul(&mut self, x: &Self) -> &mut Self { - let ctx = crate::Context::current_context_mut(); + pub fn bin_aug_mul(&mut self, ctx: &mut Context, x: &Self) -> &mut Self { let strict_range_check_32 = ctx.cfg.strict_range_check; let strict_range_check_64 = ctx.cfg.debug_mode || !ctx.cfg.strict_range_check; - match (&*self.rc, &*x.rc) { + let valid = match (&mut *self.rc.borrow_mut(), &*x.rc.borrow()) { (Value::int_value(a), Value::int_value(b)) => { - if strict_range_check_32 { - if is_i32_overflow_mul(*a, *b) { - panic_i32_overflow!(*a as i128 * *b as i128); - } + if strict_range_check_32 && is_i32_overflow_mul(*a, *b) { + panic_i32_overflow!(ctx, *a as i128 * *b as i128); } - if strict_range_check_64 { - if is_i64_overflow_mul(*a, *b) { - panic_i64_overflow!(*a as i128 * *b as i128); - } + if strict_range_check_64 && is_i64_overflow_mul(*a, *b) { + panic_i64_overflow!(ctx, *a as i128 * *b as i128); } - let a: &mut i64 = get_ref_mut(a); *a *= *b; - self + true } (Value::float_value(a), Value::float_value(b)) => { - if strict_range_check_32 { - if is_f32_overflow_mul(*a, *b) { - panic_f32_overflow!(*a * *b); - } + if strict_range_check_32 && is_f32_overflow_mul(*a, *b) { + panic_f32_overflow!(ctx, *a * *b); } - let a: &mut f64 = get_ref_mut(a); *a *= *b; - self + true } (Value::int_value(a), Value::float_value(b)) => { - if strict_range_check_32 { - if is_f32_overflow_mul(*a as f64, *b) { - panic_f32_overflow!(*a as f64 * *b); - } + if strict_range_check_32 && is_f32_overflow_mul(*a as f64, *b) { + panic_f32_overflow!(ctx, *a as f64 * *b); } - let a: &mut i64 = get_ref_mut(a); *a *= *b as i64; - self + true } (Value::float_value(a), Value::int_value(b)) => { - if strict_range_check_32 { - if is_f32_overflow_mul(*a, *b as f64) { - panic_f32_overflow!(*a * *b as f64); - } + if strict_range_check_32 && is_f32_overflow_mul(*a, *b as f64) { + panic_f32_overflow!(ctx, *a * *b as f64); } - let a: &mut f64 = get_ref_mut(a); *a *= *b as f64; - self + true } (Value::str_value(a), Value::int_value(b)) => { - let a: &mut String = get_ref_mut(a); *a = a.repeat(*b as usize); - self + true } - (Value::list_value(ref list), _) => match &*x.rc { + (Value::list_value(list), _) => match &*x.rc.borrow() { Value::int_value(ref b) => { - let list: &mut ListValue = get_ref_mut(list); let n = list.values.len(); for _ in 1..(*b as usize) { for i in 0..n { list.values.push(list.values[i].clone()); } } - self + true } - _ => panic_unsupported_bin_op!("*", self.type_str(), x.type_str()), + _ => false, }, - _ => panic_unsupported_bin_op!("*", self.type_str(), x.type_str()), + _ => false, + }; + if !valid { + panic_unsupported_bin_op!("*", self.type_str(), x.type_str()) } + self } pub fn bin_aug_div(&mut self, x: &Self) -> &mut Self { - match (&*self.rc, &*x.rc) { + let valid = match (&mut *self.rc.borrow_mut(), &*x.rc.borrow()) { (Value::int_value(a), Value::int_value(b)) => { - let a: &mut i64 = get_ref_mut(a); *a /= *b; - self + true } (Value::int_value(a), Value::float_value(b)) => { - let a: &mut i64 = get_ref_mut(a); *a /= *b as i64; - self + true } (Value::float_value(a), Value::int_value(b)) => { - let a: &mut f64 = get_ref_mut(a); *a /= *b as f64; - self + true } (Value::float_value(a), Value::float_value(b)) => { - let a: &mut f64 = get_ref_mut(a); *a /= *b; - self + true } - _ => panic_unsupported_bin_op!("/", self.type_str(), x.type_str()), + _ => false, + }; + if !valid { + panic_unsupported_bin_op!("/", self.type_str(), x.type_str()) } + self } pub fn bin_aug_mod(&mut self, x: &Self) -> &mut Self { - match (&*self.rc, &*x.rc) { + let valid = match (&mut *self.rc.borrow_mut(), &*x.rc.borrow()) { (Value::int_value(a), Value::int_value(b)) => { - let a: &mut i64 = get_ref_mut(a); let x = *a; let y = *b; - if -13 / 5 == -2 && (x < 0) != (y < 0) && x % y != 0 { + if (x < 0) != (y < 0) && x % y != 0 { *a = *a % *b + *b; } else { - *a = *a % *b + *a %= *b } - self + true } (Value::int_value(a), Value::float_value(b)) => { - let a: &mut i64 = get_ref_mut(a); *a %= *b as i64; - self + true } (Value::float_value(a), Value::int_value(b)) => { - let a: &mut f64 = get_ref_mut(a); *a %= *b as f64; - self + true } (Value::float_value(a), Value::float_value(b)) => { - let a: &mut f64 = get_ref_mut(a); *a %= *b; - self + true } - _ => panic_unsupported_bin_op!("%", self.type_str(), x.type_str()), + _ => false, + }; + if !valid { + panic_unsupported_bin_op!("%", self.type_str(), x.type_str()) } + self } - pub fn bin_aug_pow(&mut self, x: &Self) -> &mut Self { - let ctx = crate::Context::current_context_mut(); + pub fn bin_aug_pow(&mut self, ctx: &mut Context, x: &Self) -> &mut Self { let strict_range_check_32 = ctx.cfg.strict_range_check; let strict_range_check_64 = ctx.cfg.debug_mode || !ctx.cfg.strict_range_check; - match (&*self.rc, &*x.rc) { - (Value::int_value(ref a), Value::int_value(b)) => { - if strict_range_check_32 { - if is_i32_overflow_pow(*a, *b) { - panic_i32_overflow!((*a as i128).pow(*b as u32)); - } + let valid = match (&mut *self.rc.borrow_mut(), &*x.rc.borrow()) { + (Value::int_value(a), Value::int_value(b)) => { + if strict_range_check_32 && is_i32_overflow_pow(*a, *b) { + panic_i32_overflow!(ctx, (*a as i128).pow(*b as u32)); } - if strict_range_check_64 { - if is_i64_overflow_pow(*a, *b) { - panic_i64_overflow!((*a as i128).pow(*b as u32)); - } + if strict_range_check_64 && is_i64_overflow_pow(*a, *b) { + panic_i64_overflow!(ctx, (*a as i128).pow(*b as u32)); } - let a: &mut i64 = get_ref_mut(a); *a = a.pow(*b as u32); - self + true } - (Value::float_value(ref a), Value::float_value(b)) => { - if strict_range_check_32 { - if is_f32_overflow_pow(*a, *b) { - panic_f32_overflow!(a.powf(*b)); - } + (Value::float_value(a), Value::float_value(b)) => { + if strict_range_check_32 && is_f32_overflow_pow(*a, *b) { + panic_f32_overflow!(ctx, a.powf(*b)); } - let a: &mut f64 = get_ref_mut(a); - *a = a.powf(*b as f64); - self + *a = a.powf(*b); + true } - (Value::int_value(ref a), Value::float_value(b)) => { - if strict_range_check_32 { - if is_f32_overflow_pow(*a as f64, *b) { - panic_f32_overflow!((*a as f64).powf(*b)); - } + (Value::int_value(a), Value::float_value(b)) => { + if strict_range_check_32 && is_f32_overflow_pow(*a as f64, *b) { + panic_f32_overflow!(ctx, (*a as f64).powf(*b)); } - let a: &mut i64 = get_ref_mut(a); *a = a.pow(*b as u32); - self + true } - (Value::float_value(ref a), Value::int_value(b)) => { - if strict_range_check_32 { - if is_f32_overflow_pow(*a, *b as f64) { - panic_f32_overflow!(a.powf(*b as f64)); - } + (Value::float_value(a), Value::int_value(b)) => { + if strict_range_check_32 && is_f32_overflow_pow(*a, *b as f64) { + panic_f32_overflow!(ctx, a.powf(*b as f64)); } - let a: &mut f64 = get_ref_mut(a); *a = a.powf(*b as f64); - self + true } - _ => panic_unsupported_bin_op!("**", self.type_str(), x.type_str()), + _ => false, + }; + if !valid { + panic_unsupported_bin_op!("**", self.type_str(), x.type_str()) } + self } pub fn bin_aug_floor_div(&mut self, x: &Self) -> &mut Self { - match (&*self.rc, &*x.rc) { + let valid = match (&mut *self.rc.borrow_mut(), &*x.rc.borrow()) { (Value::int_value(a), Value::int_value(b)) => { - let a: &mut i64 = get_ref_mut(a); let x = *a; let y = *b; - if -13 / 5 == -2 && (x < 0) != (y < 0) && x % y != 0 { + if (x < 0) != (y < 0) && x % y != 0 { *a = *a / *b - 1 } else { *a /= *b } - self + true } (Value::int_value(a), Value::float_value(b)) => { - let a: &mut i64 = get_ref_mut(a); *a = (*a as f64 / *b) as i64; - self + true } (Value::float_value(a), Value::int_value(b)) => { - let a: &mut f64 = get_ref_mut(a); *a /= *b as f64; - self + true } (Value::float_value(a), Value::float_value(b)) => { - let a: &mut f64 = get_ref_mut(a); *a /= *b; - self + true } - _ => panic_unsupported_bin_op!("//", self.type_str(), x.type_str()), + _ => false, + }; + if !valid { + panic_unsupported_bin_op!("//", self.type_str(), x.type_str()) } + self } - pub fn bin_aug_bit_lshift(&mut self, x: &Self) -> &mut Self { - let ctx = crate::Context::current_context_mut(); + pub fn bin_aug_bit_lshift(&mut self, ctx: &mut Context, x: &Self) -> &mut Self { let strict_range_check_32 = ctx.cfg.strict_range_check; let strict_range_check_64 = ctx.cfg.debug_mode || !ctx.cfg.strict_range_check; - match (&*self.rc, &*x.rc) { + let valid = match (&mut *self.rc.borrow_mut(), &*x.rc.borrow()) { (Value::int_value(a), Value::int_value(b)) => { - if strict_range_check_32 { - if is_i32_overflow_shl(*a, *b) { - panic_i32_overflow!((*a as i128) << (*b as u32)); - } + if strict_range_check_32 && is_i32_overflow_shl(*a, *b) { + panic_i32_overflow!(ctx, (*a as i128) << (*b as u32)); } - if strict_range_check_64 { - if is_i64_overflow_shl(*a, *b) { - panic_i64_overflow!((*a as i128) << (*b as u32)); - } + if strict_range_check_64 && is_i64_overflow_shl(*a, *b) { + panic_i64_overflow!(ctx, (*a as i128) << (*b as u32)); } - let a: &mut i64 = get_ref_mut(a); *a <<= *b as usize; - self + true } - _ => panic_unsupported_bin_op!("<<", self.type_str(), x.type_str()), + _ => false, + }; + if !valid { + panic_unsupported_bin_op!("<<", self.type_str(), x.type_str()) } + self } - pub fn bin_aug_bit_rshift(&mut self, x: &Self) -> &mut Self { - let ctx = crate::Context::current_context_mut(); + pub fn bin_aug_bit_rshift(&mut self, ctx: &mut Context, x: &Self) -> &mut Self { let strict_range_check_32 = ctx.cfg.strict_range_check; let strict_range_check_64 = ctx.cfg.debug_mode || !ctx.cfg.strict_range_check; - match (&*self.rc, &*x.rc) { + let valid = match (&mut *self.rc.borrow_mut(), &*x.rc.borrow()) { (Value::int_value(a), Value::int_value(b)) => { - if strict_range_check_32 { - if is_i32_overflow_shr(*a, *b) { - panic_i32_overflow!((*a as i128) >> (*b as u32)); - } + if strict_range_check_32 && is_i32_overflow_shr(*a, *b) { + panic_i32_overflow!(ctx, (*a as i128) >> (*b as u32)); } - if strict_range_check_64 { - if is_i64_overflow_shr(*a, *b) { - panic_i64_overflow!((*a as i128) >> (*b as u32)); - } + if strict_range_check_64 && is_i64_overflow_shr(*a, *b) { + panic_i64_overflow!(ctx, (*a as i128) >> (*b as u32)); } - let a: &mut i64 = get_ref_mut(a); *a >>= *b as usize; - self + true } - _ => panic_unsupported_bin_op!(">>", self.type_str(), x.type_str()), + _ => false, + }; + if !valid { + panic_unsupported_bin_op!(">>", self.type_str(), x.type_str()) } + self } pub fn bin_aug_bit_and(&mut self, x: &Self) -> &mut Self { - match (&*self.rc, &*x.rc) { + let valid = match (&mut *self.rc.borrow_mut(), &*x.rc.borrow()) { (Value::int_value(a), Value::int_value(b)) => { - let a: &mut i64 = get_ref_mut(a); - *a &= *b as i64; - self + *a &= *b; + true } - _ => panic_unsupported_bin_op!("&", self.type_str(), x.type_str()), + _ => false, + }; + if !valid { + panic_unsupported_bin_op!("^", self.type_str(), x.type_str()) } + self } pub fn bin_aug_bit_xor(&mut self, x: &Self) -> &mut Self { - match (&*self.rc, &*x.rc) { + let valid = match (&mut *self.rc.borrow_mut(), &*x.rc.borrow()) { (Value::int_value(a), Value::int_value(b)) => { - let a: &mut i64 = get_ref_mut(a); - *a ^= *b as i64; - self + *a ^= *b; + true } - _ => panic_unsupported_bin_op!("^", self.type_str(), x.type_str()), + _ => false, + }; + if !valid { + panic_unsupported_bin_op!("^", self.type_str(), x.type_str()) } + self } - pub fn bin_aug_bit_or(&mut self, x: &Self) -> &mut Self { - match (&*self.rc, &*x.rc) { + pub fn bin_aug_bit_or(&mut self, ctx: &mut Context, x: &Self) -> &mut Self { + let valid = match (&mut *self.rc.borrow_mut(), &*x.rc.borrow()) { (Value::int_value(a), Value::int_value(b)) => { - let a: &mut i64 = get_ref_mut(a); - *a |= *b as i64; - self - } - _ => { - if self.is_list_or_config() || x.is_list_or_config() { - self.union(x, true, false, true, true); - return self; - } + *a |= *b; + true + } + _ => false, + }; + if !valid { + if self.is_list_or_config() || x.is_list_or_config() { + self.union_entry(ctx, x, true, &UnionOptions::default()); + } else { panic_unsupported_bin_op!("|", self.type_str(), x.type_str()); } } + self } /// Binary aug union a | b - pub fn bin_aug_union_with(&mut self, x: &Self) -> &mut Self { - self.bin_aug_bit_or(x) + pub fn bin_aug_union_with(&mut self, ctx: &mut Context, x: &Self) -> &mut Self { + self.bin_aug_bit_or(ctx, x) } } @@ -457,21 +418,22 @@ mod test_value_bin_aug { (5, 10, "|", 15), (7, 11, "^", 12), ]; + let mut ctx = Context::new(); for (left, right, op, expected) in cases { let mut left = ValueRef::int(left); let right = ValueRef::int(right); let result = match op { - "+" => left.bin_aug_add(&right), - "-" => left.bin_aug_sub(&right), - "*" => left.bin_aug_mul(&right), + "+" => left.bin_aug_add(&mut ctx, &right), + "-" => left.bin_aug_sub(&mut ctx, &right), + "*" => left.bin_aug_mul(&mut ctx, &right), "/" => left.bin_aug_div(&right), "//" => left.bin_aug_floor_div(&right), "%" => left.bin_aug_mod(&right), - "**" => left.bin_aug_pow(&right), - "<<" => left.bin_aug_bit_lshift(&right), - ">>" => left.bin_aug_bit_rshift(&right), + "**" => left.bin_aug_pow(&mut ctx, &right), + "<<" => left.bin_aug_bit_lshift(&mut ctx, &right), + ">>" => left.bin_aug_bit_rshift(&mut ctx, &right), "&" => left.bin_aug_bit_and(&right), - "|" => left.bin_aug_bit_or(&right), + "|" => left.bin_aug_bit_or(&mut ctx, &right), "^" => left.bin_aug_bit_xor(&right), _ => panic!("invalid op {}", op), }; @@ -481,16 +443,19 @@ mod test_value_bin_aug { #[test] fn test_aug_add() { + let mut ctx = Context::new(); // int assert_eq!( - ValueRef::int(1).bin_aug_add(&ValueRef::int(2)).as_int(), + ValueRef::int(1) + .bin_aug_add(&mut ctx, &ValueRef::int(2)) + .as_int(), 1 + 2 ); // float assert_eq!( ValueRef::float(1.5) - .bin_aug_add(&ValueRef::float(2.0)) + .bin_aug_add(&mut ctx, &ValueRef::float(2.0)) .as_float(), 3.5 ); @@ -501,14 +466,16 @@ mod test_value_bin_aug { // int + float => int assert_eq!( - ValueRef::int(1).bin_aug_add(&ValueRef::float(2.5)).as_int(), + ValueRef::int(1) + .bin_aug_add(&mut ctx, &ValueRef::float(2.5)) + .as_int(), 1 + 2 ); // float + int => float assert_eq!( ValueRef::float(1.5) - .bin_aug_add(&ValueRef::int(2)) + .bin_aug_add(&mut ctx, &ValueRef::int(2)) .as_float(), 1.5 + 2.0 ); diff --git a/kclvm/runtime/src/value/val_clone.rs b/kclvm/runtime/src/value/val_clone.rs index 538dfd4da..5ba0494b4 100644 --- a/kclvm/runtime/src/value/val_clone.rs +++ b/kclvm/runtime/src/value/val_clone.rs @@ -1,93 +1,98 @@ -// Copyright 2021 The KCL Authors. All rights reserved. +//! Copyright The KCL Authors. All rights reserved. +use std::boxed::Box; +use std::cell::RefCell; use std::rc::Rc; use crate::*; impl ValueRef { pub fn deep_copy(&self) -> ValueRef { - match &*self.rc { + match &*self.rc.borrow() { Value::undefined => ValueRef { - rc: Rc::new(Value::undefined), + rc: Rc::new(RefCell::new(Value::undefined)), }, Value::none => ValueRef { - rc: Rc::new(Value::none), + rc: Rc::new(RefCell::new(Value::none)), }, Value::func_value(ref v) => ValueRef { - rc: Rc::new(Value::func_value(FuncValue { + rc: Rc::new(RefCell::new(Value::func_value(Box::new(FuncValue { fn_ptr: v.fn_ptr, check_fn_ptr: v.check_fn_ptr, - closure: v.closure.deep_copy(), - external_name: v.external_name.clone(), + // In KCL, functions are all pure, so we only need a shallow + // copy of the closure of the function. + // In addition, this can avoid stack overflow issues caused + // by deep copies of references to schema `self` held by functions + // within the schema. Because schema also holds a reference to + // the function. + closure: v.closure.clone(), + name: v.name.clone(), runtime_type: v.runtime_type.clone(), - })), + is_external: v.is_external, + proxy: v.proxy, + })))), }, Value::bool_value(ref v) => ValueRef { - rc: Rc::new(Value::bool_value(*v)), + rc: Rc::new(RefCell::new(Value::bool_value(*v))), }, Value::int_value(ref v) => ValueRef { - rc: Rc::new(Value::int_value(*v)), + rc: Rc::new(RefCell::new(Value::int_value(*v))), }, Value::float_value(ref v) => ValueRef { - rc: Rc::new(Value::float_value(*v)), + rc: Rc::new(RefCell::new(Value::float_value(*v))), }, Value::unit_value(ref v, ref raw, ref unit) => ValueRef { - rc: Rc::new(Value::unit_value(*v, *raw, unit.clone())), + rc: Rc::new(RefCell::new(Value::unit_value(*v, *raw, unit.clone()))), }, Value::str_value(ref v) => ValueRef { - rc: Rc::new(Value::str_value(v.to_string())), + rc: Rc::new(RefCell::new(Value::str_value(v.to_string()))), }, Value::list_value(ref v) => ValueRef { - rc: Rc::new(Value::list_value(ListValue { + rc: Rc::new(RefCell::new(Value::list_value(Box::new(ListValue { values: v.values.iter().map(|x| x.deep_copy()).collect(), - })), + })))), }, Value::dict_value(ref v) => { - let mut dict = DictValue::new(&[]); + let mut dict = ValueRef::from(Value::dict_value(Box::new(DictValue::new(&[])))); for (key, val) in &v.values { - let op = v - .ops - .get(key) - .or(Some(&ConfigEntryOperationKind::Union)) - .unwrap(); - let index = v.insert_indexs.get(key).or(Some(&-1)).unwrap(); - dict.dict_update_entry( - key.as_str(), - &val.deep_copy(), - &op.clone(), - &index.clone(), - ); + let op = v.ops.get(key).unwrap_or(&ConfigEntryOperationKind::Union); + let index = v.insert_indexs.get(key); + dict.dict_update_entry(key.as_str(), &val.deep_copy(), &op.clone(), index); } + dict.set_potential_schema_type(&v.potential_schema.clone().unwrap_or_default()); dict } Value::schema_value(ref v) => { - let mut dict = DictValue::new(&[]); + let mut dict = ValueRef::from(Value::dict_value(Box::new(DictValue::new(&[])))); + dict.set_potential_schema_type( + &v.config.potential_schema.clone().unwrap_or_default(), + ); for (key, val) in &v.config.values { let op = v .config .ops .get(key) - .or(Some(&ConfigEntryOperationKind::Union)) - .unwrap(); - let index = v.config.insert_indexs.get(key).or(Some(&-1)).unwrap(); - dict.dict_update_entry( - key.as_str(), - &val.deep_copy(), - &op.clone(), - &index.clone(), - ); + .unwrap_or(&ConfigEntryOperationKind::Union); + let index = v.config.insert_indexs.get(key); + dict.dict_update_entry(key.as_str(), &val.deep_copy(), &op.clone(), index); if let Some(type_str) = v.config.attr_map.get(key) { dict.update_attr_map(key, type_str); } } - ValueRef { - rc: Rc::new(Value::schema_value(SchemaValue { + return ValueRef { + rc: Rc::new(RefCell::new(Value::schema_value(Box::new(SchemaValue { name: v.name.clone(), pkgpath: v.pkgpath.clone(), - config: Rc::new(dict.as_dict_ref().clone()), + config: Box::new(dict.as_dict_ref().clone()), config_keys: v.config_keys.clone(), - })), - } + config_meta: v.config_meta.clone(), + optional_mapping: v.optional_mapping.clone(), + // For KCL, args and kwargs are both immutable within the schema scope, + // so here we only need to clone the references. + args: v.args.clone(), + kwargs: v.kwargs.clone(), + })))), + }; } } } diff --git a/kclvm/runtime/src/value/val_cmp.rs b/kclvm/runtime/src/value/val_cmp.rs index c2dde9fa6..b4126552d 100644 --- a/kclvm/runtime/src/value/val_cmp.rs +++ b/kclvm/runtime/src/value/val_cmp.rs @@ -1,22 +1,22 @@ -// Copyright 2021 The KCL Authors. All rights reserved. +//! Copyright The KCL Authors. All rights reserved. use crate::*; // cmp impl ValueRef { pub fn cmp_equal(&self, x: &Self) -> bool { - match *self.rc { - Value::int_value(a) => match *x.rc { + match *self.rc.borrow() { + Value::int_value(a) => match *x.rc.borrow() { Value::int_value(b) => a == b, Value::float_value(b) => a as f64 == b, _ => false, }, - Value::float_value(a) => match *x.rc { + Value::float_value(a) => match *x.rc.borrow() { Value::int_value(b) => a == b as f64, Value::float_value(b) => a == b, _ => false, }, - _ => match (&*self.rc, &*x.rc) { + _ => match (&*self.rc.borrow(), &*x.rc.borrow()) { (Value::undefined, Value::undefined) => true, (Value::none, Value::none) => true, (Value::bool_value(a), Value::bool_value(b)) => *a == *b, @@ -71,8 +71,8 @@ impl ValueRef { } pub fn cmp_less_than(&self, x: &Self) -> bool { - match &*self.rc { - Value::int_value(a) => match &*x.rc { + match &*self.rc.borrow() { + Value::int_value(a) => match &*x.rc.borrow() { Value::int_value(b) => *a < *b, Value::float_value(b) => (*a as f64) < *b, Value::bool_value(b) => *a < (*b as i64), @@ -82,7 +82,7 @@ impl ValueRef { x.type_str() ), }, - Value::float_value(a) => match &*x.rc { + Value::float_value(a) => match &*x.rc.borrow() { Value::int_value(b) => *a < *b as f64, Value::float_value(b) => *a < *b, Value::bool_value(b) => *a < ((*b as i64) as f64), @@ -92,7 +92,7 @@ impl ValueRef { x.type_str() ), }, - Value::bool_value(a) => match &*x.rc { + Value::bool_value(a) => match &*x.rc.borrow() { Value::int_value(b) => (*a as i64) < *b, Value::float_value(b) => ((*a as i64) as f64) < *b, Value::bool_value(b) => !(*a) & *b, @@ -102,7 +102,7 @@ impl ValueRef { x.type_str() ), }, - Value::str_value(a) => match &*x.rc { + Value::str_value(a) => match &*x.rc.borrow() { Value::str_value(b) => *a < *b, _ => panic!( "'<' not supported between instances of '{}' and '{}'", @@ -110,7 +110,7 @@ impl ValueRef { x.type_str() ), }, - Value::list_value(a) => match &*x.rc { + Value::list_value(a) => match &*x.rc.borrow() { Value::list_value(b) => { let len_a = a.values.len(); let len_b = b.values.len(); @@ -139,8 +139,8 @@ impl ValueRef { } pub fn cmp_less_than_or_equal(&self, x: &Self) -> bool { - match &*self.rc { - Value::int_value(a) => match &*x.rc { + match &*self.rc.borrow() { + Value::int_value(a) => match &*x.rc.borrow() { Value::int_value(b) => *a <= *b, Value::float_value(b) => (*a as f64) <= *b, Value::bool_value(b) => *a <= (*b as i64), @@ -150,7 +150,7 @@ impl ValueRef { x.type_str() ), }, - Value::float_value(a) => match &*x.rc { + Value::float_value(a) => match &*x.rc.borrow() { Value::int_value(b) => *a <= *b as f64, Value::float_value(b) => *a <= *b, Value::bool_value(b) => *a <= ((*b as i64) as f64), @@ -160,7 +160,7 @@ impl ValueRef { x.type_str() ), }, - Value::bool_value(a) => match &*x.rc { + Value::bool_value(a) => match &*x.rc.borrow() { Value::int_value(b) => (*a as i64) <= *b, Value::float_value(b) => ((*a as i64) as f64) <= *b, Value::bool_value(b) => *a <= *b, @@ -170,7 +170,7 @@ impl ValueRef { x.type_str() ), }, - Value::str_value(a) => match &*x.rc { + Value::str_value(a) => match &*x.rc.borrow() { Value::str_value(b) => *a <= *b, _ => panic!( "'<=' not supported between instances of '{}' and '{}'", @@ -178,7 +178,7 @@ impl ValueRef { x.type_str() ), }, - Value::list_value(a) => match &*x.rc { + Value::list_value(a) => match &*x.rc.borrow() { Value::list_value(b) => { let len_a = a.values.len(); let len_b = b.values.len(); @@ -207,8 +207,8 @@ impl ValueRef { } pub fn cmp_greater_than(&self, x: &Self) -> bool { - match &*self.rc { - Value::int_value(a) => match &*x.rc { + match &*self.rc.borrow() { + Value::int_value(a) => match &*x.rc.borrow() { Value::int_value(b) => *a > *b, Value::float_value(b) => (*a as f64) > *b, Value::bool_value(b) => *a > (*b as i64), @@ -218,7 +218,7 @@ impl ValueRef { x.type_str() ), }, - Value::float_value(a) => match &*x.rc { + Value::float_value(a) => match &*x.rc.borrow() { Value::int_value(b) => *a > *b as f64, Value::float_value(b) => *a > *b, Value::bool_value(b) => *a > ((*b as i64) as f64), @@ -228,7 +228,7 @@ impl ValueRef { x.type_str() ), }, - Value::bool_value(a) => match &*x.rc { + Value::bool_value(a) => match &*x.rc.borrow() { Value::int_value(b) => (*a as i64) > *b, Value::float_value(b) => ((*a as i64) as f64) > *b, Value::bool_value(b) => *a & !(*b), @@ -238,7 +238,7 @@ impl ValueRef { x.type_str() ), }, - Value::str_value(a) => match &*x.rc { + Value::str_value(a) => match &*x.rc.borrow() { Value::str_value(b) => *a > *b, _ => panic!( "'>' not supported between instances of '{}' and '{}'", @@ -246,7 +246,7 @@ impl ValueRef { x.type_str() ), }, - Value::list_value(a) => match &*x.rc { + Value::list_value(a) => match &*x.rc.borrow() { Value::list_value(b) => { let len_a = a.values.len(); let len_b = b.values.len(); @@ -275,8 +275,8 @@ impl ValueRef { } pub fn cmp_greater_than_or_equal(&self, x: &Self) -> bool { - match &*self.rc { - Value::int_value(a) => match &*x.rc { + match &*self.rc.borrow() { + Value::int_value(a) => match &*x.rc.borrow() { Value::int_value(b) => *a >= *b, Value::float_value(b) => (*a as f64) >= *b, Value::bool_value(b) => *a >= (*b as i64), @@ -286,7 +286,7 @@ impl ValueRef { x.type_str() ), }, - Value::float_value(a) => match &*x.rc { + Value::float_value(a) => match &*x.rc.borrow() { Value::int_value(b) => *a >= *b as f64, Value::float_value(b) => *a >= *b, Value::bool_value(b) => *a >= ((*b as i64) as f64), @@ -296,7 +296,7 @@ impl ValueRef { x.type_str() ), }, - Value::bool_value(a) => match &*x.rc { + Value::bool_value(a) => match &*x.rc.borrow() { Value::int_value(b) => (*a as i64) >= *b, Value::float_value(b) => ((*a as i64) as f64) >= *b, Value::bool_value(b) => *a >= *b, @@ -306,7 +306,7 @@ impl ValueRef { x.type_str() ), }, - Value::str_value(a) => match &*x.rc { + Value::str_value(a) => match &*x.rc.borrow() { Value::str_value(b) => *a >= *b, _ => panic!( "'>=' not supported between instances of '{}' and '{}'", @@ -314,7 +314,7 @@ impl ValueRef { x.type_str() ), }, - Value::list_value(a) => match &*x.rc { + Value::list_value(a) => match &*x.rc.borrow() { Value::list_value(b) => { let len_a = a.values.len(); let len_b = b.values.len(); diff --git a/kclvm/runtime/src/value/val_decorator.rs b/kclvm/runtime/src/value/val_decorator.rs index 69bc026bd..069621d1c 100644 --- a/kclvm/runtime/src/value/val_decorator.rs +++ b/kclvm/runtime/src/value/val_decorator.rs @@ -1,4 +1,4 @@ -// Copyright 2021 The KCL Authors. All rights reserved. +//! Copyright The KCL Authors. All rights reserved. use crate::*; @@ -16,6 +16,7 @@ impl DecoratorValue { pub fn run( &self, + ctx: &mut Context, attr_name: &str, is_schema_target: bool, config_value: &ValueRef, @@ -45,43 +46,38 @@ impl DecoratorValue { }; let mut msg = String::new(); if !version.is_empty() { - let version = format!("since version {}", version); + let version = format!("since version {version}"); msg.push_str(&version); } if !reason.is_empty() { - let reason = format!(", {}", reason); + let reason = format!(", {reason}"); msg.push_str(&reason); } if strict { if is_schema_target || config_value.get_by_key(attr_name).is_some() { - let mut err_msg = format!("{} was deprecated ", attr_name); + let mut err_msg = format!("{attr_name} was deprecated "); if !msg.is_empty() { err_msg.push_str(&msg); } - let ctx = Context::current_context_mut(); if let (Some(filename), Some(line)) = (filename, line) { ctx.set_kcl_filename(&filename.as_str()); ctx.panic_info.kcl_line = line.as_int() as i32; } - ctx.set_err_type(&ErrType::Deprecated_TYPE); + ctx.set_err_type(&RuntimeErrorType::Deprecated); panic!("{}", err_msg) } } else if is_schema_target || config_value.get_by_key(attr_name).is_some() { - let mut err_msg = format!("{} was deprecated ", attr_name); + let mut err_msg = format!("{attr_name} was deprecated "); if !msg.is_empty() { err_msg.push_str(&msg); } - - let ctx = Context::current_context_mut(); - ctx.set_err_type(&ErrType::Deprecated_Warning_TYPE); - - ctx.set_warnning_message(err_msg.as_str()); + ctx.set_err_type(&RuntimeErrorType::DeprecatedWarning); + ctx.set_warning_message(err_msg.as_str()); } else { - let ctx = Context::current_context_mut(); - let err_msg = format!("{} was deprecated ", attr_name); - ctx.set_err_type(&ErrType::Deprecated_Warning_TYPE); - ctx.set_warnning_message(err_msg.as_str()); + let err_msg = format!("{attr_name} was deprecated "); + ctx.set_err_type(&RuntimeErrorType::DeprecatedWarning); + ctx.set_warning_message(err_msg.as_str()); } } DEPRECATED_INFO => { /* Nothing to do on Info decorator */ } @@ -101,13 +97,14 @@ impl DecoratorValue { mod test_value_decorator { use crate::*; - fn assert_panic () + std::panic::UnwindSafe>(func: F) { + fn assert_panic(func: F) { let result = std::panic::catch_unwind(func); assert!(result.is_err()) } #[test] fn test_decorator() { + let mut ctx = Context::new(); let args = ValueRef::list(None); let mut kwargs = ValueRef::dict(None); let test_deprecated_decorator = DecoratorValue::new(DEPRECATED_DECORATOR, &args, &kwargs); @@ -115,12 +112,13 @@ mod test_value_decorator { let schema_name = "Data"; let config_meta = ValueRef::dict(None); let config_value = ValueRef::dict_str(&[("key1", "value1")]); - test_deprecated_decorator.run(schema_name, true, &config_value, &config_meta); + test_deprecated_decorator.run(&mut ctx, schema_name, true, &config_value, &config_meta); } #[test] fn test_decorator_invalid() { assert_panic(|| { + let mut ctx = Context::new(); let args = ValueRef::list(None); let kwargs = ValueRef::dict(None); let test_deprecated_decorator = @@ -128,7 +126,7 @@ mod test_value_decorator { let schema_name = "Data"; let config_meta = ValueRef::dict(None); let config_value = ValueRef::dict_str(&[("key1", "value1")]); - test_deprecated_decorator.run(schema_name, true, &config_value, &config_meta); + test_deprecated_decorator.run(&mut ctx, schema_name, true, &config_value, &config_meta); }); } } diff --git a/kclvm/runtime/src/value/val_dict.rs b/kclvm/runtime/src/value/val_dict.rs index 80c65544c..9d45ae8f2 100644 --- a/kclvm/runtime/src/value/val_dict.rs +++ b/kclvm/runtime/src/value/val_dict.rs @@ -1,31 +1,31 @@ -// Copyright 2021 The KCL Authors. All rights reserved. +//! Copyright The KCL Authors. All rights reserved. use crate::*; - +use std::cell::Ref; impl DictValue { - pub fn new(values: &[(&str, &ValueRef)]) -> ValueRef { + pub fn new(values: &[(&str, &ValueRef)]) -> DictValue { let mut dict = DictValue::default(); for x in values { dict.values.insert(x.0.to_string(), x.1.clone()); } - ValueRef::from(Value::dict_value(dict)) + dict } - pub fn get(&self, key: &ValueRef) -> Option<&ValueRef> { - match &*key.rc { - Value::str_value(ref s) => self.values.get(s), + pub fn get(&self, key: &ValueRef) -> Option { + match &*key.rc.borrow() { + Value::str_value(ref s) => self.values.get(s).cloned(), _ => None, } } pub fn insert(&mut self, key: &ValueRef, value: &ValueRef) { - if let Value::str_value(ref s) = &*key.rc { + if let Value::str_value(ref s) = &*key.rc.borrow() { self.values.insert(s.to_string(), value.clone()); } } pub fn insert_unpack(&mut self, v: &ValueRef) { - if let Value::dict_value(ref b) = &*v.rc { + if let Value::dict_value(ref b) = &*v.rc.borrow() { for (k, v) in b.values.iter() { self.values.insert(k.clone(), v.clone()); } @@ -34,19 +34,19 @@ impl DictValue { } impl ValueRef { - fn dict_config(&self) -> &DictValue { - match &*self.rc { - Value::dict_value(ref dict) => dict, + fn dict_config(&self) -> Ref { + Ref::map(self.rc.borrow(), |val| match val { + Value::dict_value(ref dict) => dict.as_ref(), Value::schema_value(ref schema) => schema.config.as_ref(), _ => panic!("invalid dict config value type {}", self.type_str()), - } + }) } pub fn dict_int(values: &[(&str, i64)]) -> Self { let mut dict = DictValue::default(); for x in values { dict.values.insert(x.0.to_string(), Self::int(x.1)); } - Self::from(Value::dict_value(dict)) + Self::from(Value::dict_value(Box::new(dict))) } pub fn dict_float(values: &[(&str, f64)]) -> Self { @@ -54,7 +54,7 @@ impl ValueRef { for x in values { dict.values.insert(x.0.to_string(), Self::float(x.1)); } - Self::from(Value::dict_value(dict)) + Self::from(Value::dict_value(Box::new(dict))) } pub fn dict_bool(values: &[(&str, bool)]) -> Self { @@ -62,7 +62,7 @@ impl ValueRef { for x in values { dict.values.insert(x.0.to_string(), Self::bool(x.1)); } - Self::from(Value::dict_value(dict)) + Self::from(Value::dict_value(Box::new(dict))) } pub fn dict_str(values: &[(&str, &str)]) -> Self { @@ -70,14 +70,15 @@ impl ValueRef { for x in values { dict.values.insert(x.0.to_string(), Self::str(x.1)); } - Self::from(Value::dict_value(dict)) + Self::from(Value::dict_value(Box::new(dict))) } /// Dict clear pub fn dict_clear(&mut self) { - let dict = match &*self.rc { - Value::dict_value(ref dict) => get_ref_mut(dict), - Value::schema_value(ref schema) => get_ref_mut(schema.config.as_ref()), + let mut binding = self.rc.borrow_mut(); + let dict = match &mut *binding { + Value::dict_value(dict) => dict.as_mut(), + Value::schema_value(schema) => schema.config.as_mut(), _ => panic!("invalid config value in dict_clear"), }; dict.values.clear() @@ -93,13 +94,13 @@ impl ValueRef { /// Dict get values pub fn dict_values(&self) -> ValueRef { let dict = self.dict_config(); - let values: Vec<&ValueRef> = dict.values.values().map(|k| k).collect(); + let values: Vec<&ValueRef> = dict.values.values().collect(); ValueRef::list(Some(&values)) } /// Dict get e.g., {k1: v1, k2, v2}.get(ValueRef::str(k1)) == v1 - pub fn dict_get(&self, key: &ValueRef) -> Option<&ValueRef> { - match &*self.rc { + pub fn dict_get(&self, key: &ValueRef) -> Option { + match &*self.rc.borrow() { Value::dict_value(ref dict) => dict.get(key), Value::schema_value(ref schema) => schema.config.get(key), _ => panic!("invalid config value in dict_get"), @@ -107,17 +108,35 @@ impl ValueRef { } /// Dict get value e.g., {k1: v1, k2, v2}.get_value(k1) == v1 - pub fn dict_get_value(&self, key: &str) -> Option<&ValueRef> { - match &*self.rc { - Value::dict_value(ref dict) => dict.values.get(key), - Value::schema_value(ref schema) => schema.config.values.get(key), + pub fn dict_get_value(&self, key: &str) -> Option { + match &*self.rc.borrow() { + Value::dict_value(ref dict) => dict.values.get(key).cloned(), + Value::schema_value(ref schema) => schema.config.values.get(key).cloned(), + _ => None, + } + } + + /// Dict get value e.g., {k1 = v1, k2 = v2}.get_attr_operator(k1) == Some(ConfigEntryOperationKind::Override) + pub fn dict_get_attr_operator(&self, key: &str) -> Option { + match &*self.rc.borrow() { + Value::dict_value(ref dict) => dict.ops.get(key).cloned(), + Value::schema_value(ref schema) => schema.config.ops.get(key).cloned(), + _ => None, + } + } + + /// Dict get value e.g., {k1 = v1, k2 = v2}.get_attr_operator(k1) == Some(ConfigEntryOperationKind::Override) + pub fn dict_get_insert_index(&self, key: &str) -> Option { + match &*self.rc.borrow() { + Value::dict_value(ref dict) => dict.insert_indexs.get(key).cloned(), + Value::schema_value(ref schema) => schema.config.insert_indexs.get(key).cloned(), _ => None, } } /// Dict get entry e.g., {k1: v1, k2, v2}.get_entry(k1) == {k1: v1} pub fn dict_get_entry(&self, key: &str) -> Option { - match &*self.rc { + match &*self.rc.borrow() { Value::dict_value(ref dict) => { if dict.values.contains_key(key) { let mut d = ValueRef::dict(None); @@ -127,12 +146,9 @@ impl ValueRef { } else { &ConfigEntryOperationKind::Union }; - let index = if let Some(idx) = dict.insert_indexs.get(key) { - *idx - } else { - -1 - }; - d.dict_update_entry(key, value, op, &index); + let index = dict.insert_indexs.get(key); + d.dict_update_entry(key, value, op, index); + d.set_potential_schema_type(&dict.potential_schema.clone().unwrap_or_default()); Some(d) } else { None @@ -147,12 +163,11 @@ impl ValueRef { } else { &ConfigEntryOperationKind::Union }; - let index = if let Some(idx) = schema.config.insert_indexs.get(key) { - *idx - } else { - -1 - }; - d.dict_update_entry(key, value, op, &index); + let index = schema.config.insert_indexs.get(key); + d.dict_update_entry(key, value, op, index); + d.set_potential_schema_type( + &schema.config.potential_schema.clone().unwrap_or_default(), + ); Some(d) } else { None @@ -165,7 +180,7 @@ impl ValueRef { /// Dict get entries e.g., {k1: v1, k2, v2}.get_entries([k1, k2]) == {k1: v1, k1: v2} pub fn dict_get_entries(&self, keys: Vec<&str>) -> ValueRef { - match &*self.rc { + match &*self.rc.borrow() { Value::dict_value(ref dict) => { let mut d = ValueRef::dict(None); for key in keys { @@ -174,12 +189,12 @@ impl ValueRef { let op = dict .ops .get(key) - .or(Some(&ConfigEntryOperationKind::Union)) - .unwrap(); - let index = dict.insert_indexs.get(key).or(Some(&-1)).unwrap(); + .unwrap_or(&ConfigEntryOperationKind::Union); + let index = dict.insert_indexs.get(key); d.dict_update_entry(key, value, op, index); } } + d.set_potential_schema_type(&dict.potential_schema.clone().unwrap_or_default()); d } Value::schema_value(ref schema) => { @@ -191,12 +206,62 @@ impl ValueRef { .config .ops .get(key) - .or(Some(&ConfigEntryOperationKind::Union)) - .unwrap(); - let index = schema.config.insert_indexs.get(key).or(Some(&-1)).unwrap(); + .unwrap_or(&ConfigEntryOperationKind::Union); + let index = schema.config.insert_indexs.get(key); d.dict_update_entry(key, value, op, index); } } + d.set_potential_schema_type( + &schema + .config + .potential_schema + .as_ref() + .map(|v| v.to_string()) + .unwrap_or_default(), + ); + d + } + // Panic + _ => panic!("invalid config value in dict_get_entries"), + } + } + + /// Dict get entries e.g., {k1: v1, k2, v2}.get_entries([k1, k2]) == {k1: v1, k1: v2} + pub fn dict_get_entries_with_op( + &self, + keys: Vec<&str>, + op: &ConfigEntryOperationKind, + ) -> ValueRef { + match &*self.rc.borrow() { + Value::dict_value(ref dict) => { + let mut d = ValueRef::dict(None); + for key in keys { + if dict.values.contains_key(key) { + let value = dict.values.get(key).unwrap(); + let index = dict.insert_indexs.get(key); + d.dict_update_entry(key, value, op, index); + } + } + d.set_potential_schema_type(&dict.potential_schema.clone().unwrap_or_default()); + d + } + Value::schema_value(ref schema) => { + let mut d = ValueRef::dict(None); + for key in keys { + if schema.config.values.contains_key(key) { + let value = schema.config.values.get(key).unwrap(); + let index = schema.config.insert_indexs.get(key); + d.dict_update_entry(key, value, op, index); + } + } + d.set_potential_schema_type( + &schema + .config + .potential_schema + .as_ref() + .map(|v| v.to_string()) + .unwrap_or_default(), + ); d } // Panic @@ -206,16 +271,15 @@ impl ValueRef { /// Update dict value without attribute operator check, only update pub fn dict_update(&mut self, v: &ValueRef) { - let dict = match &*self.rc { - Value::dict_value(ref v) => get_ref_mut(v), - Value::schema_value(ref v) => { - let schema = get_ref_mut(v); - get_ref_mut(schema.config.as_ref()) - } + let mut binding = self.rc.borrow_mut(); + let dict = match &mut *binding { + Value::dict_value(v) => v.as_mut(), + Value::schema_value(v) => v.config.as_mut(), _ => panic!("invalid dict update value: {}", self.type_str()), }; if v.is_config() { let v = v.as_dict_ref(); + dict.potential_schema = v.potential_schema.clone(); for (k, v) in v.values.iter() { dict.values.insert(k.clone(), v.clone()); } @@ -224,17 +288,18 @@ impl ValueRef { /// Update key value pair without attribute operator check, only update pub fn dict_update_key_value(&mut self, key: &str, val: ValueRef) { - match &*self.rc { - Value::dict_value(ref v) => { - let dict = get_ref_mut(v); + match &mut *self.rc.borrow_mut() { + Value::dict_value(dict) => { dict.values.insert(key.to_string(), val); } - Value::schema_value(ref v) => { - let schema = get_ref_mut(v); - let dict = get_ref_mut(schema.config.as_ref()); - dict.values.insert(key.to_string(), val); + Value::schema_value(schema) => { + schema.config.values.insert(key.to_string(), val); } - _ => panic!("invalid dict update value: {}", self.type_str()), + _ => panic!( + "failed to update the dict. An iterable of key-value pairs was expected, but got {}. Check if the syntax for updating the dictionary with the attribute '{}' is correct", + self.type_str(), + key + ), } } @@ -244,125 +309,155 @@ impl ValueRef { key: &str, val: &ValueRef, op: &ConfigEntryOperationKind, - index: &i32, + index: Option<&i32>, ) { - let dict = match &*self.rc { - Value::dict_value(ref v) => get_ref_mut(v), - Value::schema_value(ref v) => { - let schema = get_ref_mut(v); - get_ref_mut(schema.config.as_ref()) - } + let mut binding = self.rc.borrow_mut(); + let dict = match &mut *binding { + Value::dict_value(v) => v.as_mut(), + Value::schema_value(v) => v.config.as_mut(), _ => panic!("invalid dict update value: {}", self.type_str()), }; dict.values.insert(key.to_string(), val.clone()); dict.ops.insert(key.to_string(), op.clone()); - dict.insert_indexs.insert(key.to_string(), *index); + if let Some(index) = index { + dict.insert_indexs.insert(key.to_string(), *index); + } } - /// Insert key value pair with the idempotent check + /// Insert key value pair with the idempotent check. + #[inline] pub fn dict_insert( &mut self, + ctx: &mut Context, key: &str, v: &ValueRef, op: ConfigEntryOperationKind, - insert_index: i32, + insert_index: Option, ) { - self.dict_merge_key_value_pair(key, v, op, insert_index, true); + self.dict_merge_key_value_pair(ctx, key, v, op, insert_index, true); } /// Merge key value pair without the idempotent check pub fn dict_merge( &mut self, + ctx: &mut Context, key: &str, v: &ValueRef, op: ConfigEntryOperationKind, - insert_index: i32, + insert_index: Option, ) { - self.dict_merge_key_value_pair(key, v, op, insert_index, false); + self.dict_merge_key_value_pair(ctx, key, v, op, insert_index, false); } /// Private dict merge key value pair with the idempotent check option fn dict_merge_key_value_pair( &mut self, + ctx: &mut Context, key: &str, v: &ValueRef, op: ConfigEntryOperationKind, - insert_index: i32, - should_idempotent_check: bool, + insert_index: Option, + idempotent_check: bool, ) { - let ctx = crate::Context::current_context_mut(); - if ctx.cfg.debug_mode { - if let Value::int_value(ref x) = *v.rc { + if let Value::int_value(ref x) = *v.rc.borrow() { let strict_range_check_i32 = ctx.cfg.strict_range_check; let strict_range_check_i64 = ctx.cfg.debug_mode || !ctx.cfg.strict_range_check; let v_i128 = *x as i128; if strict_range_check_i32 { if v_i128 != ((v_i128 as i32) as i128) { - let ctx = Context::current_context_mut(); - ctx.set_err_type(&ErrType::IntOverflow_TYPE); + ctx.set_err_type(&RuntimeErrorType::IntOverflow); - panic!("{}: A 32 bit integer overflow", v_i128); + panic!("{v_i128}: A 32 bit integer overflow"); } } else if strict_range_check_i64 && v_i128 != ((v_i128 as i64) as i128) { - let ctx = Context::current_context_mut(); - ctx.set_err_type(&ErrType::IntOverflow_TYPE); + ctx.set_err_type(&RuntimeErrorType::IntOverflow); - panic!("{}: A 64 bit integer overflow", v_i128); + panic!("{v_i128}: A 64 bit integer overflow"); } } } - match &*self.rc { - Value::dict_value(_) | Value::schema_value(_) => { - let mut dict: DictValue = Default::default(); - dict.values.insert(key.to_string(), v.clone()); - dict.ops.insert(key.to_string(), op); + if self.is_config() { + let mut dict: DictValue = Default::default(); + dict.values.insert(key.to_string(), v.clone()); + dict.ops.insert(key.to_string(), op); + if let Some(insert_index) = insert_index { dict.insert_indexs.insert(key.to_string(), insert_index); - self.union( - &ValueRef::from(Value::dict_value(dict)), - true, - false, - should_idempotent_check, - false, - ); } - _ => panic!("invalid dict insert value: {}", self.type_str()), + self.union_entry( + ctx, + &ValueRef::from(Value::dict_value(Box::new(dict))), + true, + &UnionOptions { + config_resolve: false, + idempotent_check, + ..Default::default() + }, + ); + } else { + panic!("invalid dict insert value: {}", self.type_str()) } } /// Dict insert unpack value e.g., data = {**v} - pub fn dict_insert_unpack(&mut self, v: &ValueRef) { - match (&*self.rc, &*v.rc) { + pub fn dict_insert_unpack(&mut self, ctx: &mut Context, v: &ValueRef) { + let mut union = false; + match (&*self.rc.borrow(), &*v.rc.borrow()) { ( Value::dict_value(_) | Value::schema_value(_), Value::dict_value(_) | Value::schema_value(_), ) => { - self.bin_aug_bit_or(&v.schema_to_dict().deep_copy()); + union = true; } (Value::dict_value(_) | Value::schema_value(_), Value::none) => { /*Do nothing on unpacking None/Undefined*/ } (Value::dict_value(_) | Value::schema_value(_), Value::undefined) => { /*Do nothing on unpacking None/Undefined*/ } - _ => panic!("only list, dict and schema object can be used with unpack operators * and **, got {}", v.to_string()), + _ => panic!("only list, dict and schema object can be used with unpack operators * and **, got {v}"), + } + if union { + self.bin_aug_bit_or(ctx, &v.schema_to_dict().deep_copy()); } } /// Dict remove the key-value pair equivalent to key pub fn dict_remove(&mut self, key: &str) { - match &*self.rc { - Value::dict_value(ref dict) => { - let dict: &mut DictValue = get_ref_mut(dict); + match &mut *self.rc.borrow_mut() { + Value::dict_value(dict) => { dict.values.remove(key); } - Value::schema_value(ref schema) => { - let dict: &mut DictValue = get_ref_mut(schema.config.as_ref()); - dict.values.remove(key); + Value::schema_value(schema) => { + schema.config.values.remove(key); } _ => panic!("invalid dict remove value: {}", self.type_str()), } } + + /// Set dict key with the value. When the dict is a schema and resolve schema validations. + pub fn dict_set_value(&mut self, ctx: &mut Context, key: &str, val: &ValueRef) { + let p = self; + if p.is_config() { + p.dict_update_key_value(key, val.clone()); + if p.is_schema() { + let schema: ValueRef; + { + let schema_value = p.as_schema(); + let mut config_keys = schema_value.config_keys.clone(); + config_keys.push(key.to_string()); + schema = resolve_schema(ctx, p, &config_keys); + } + p.schema_update_with_schema(&schema); + } + } else { + panic!( + "failed to update the dict. An iterable of key-value pairs was expected, but got {}. Check if the syntax for updating the dictionary with the attribute '{}' is correct", + p.type_str(), + key + ); + } + } } #[cfg(test)] @@ -420,7 +515,7 @@ mod test_value_dict { key, &ValueRef::str(val), &ConfigEntryOperationKind::Union, - &-1, + None, ); } for (key, val) in update_entries { diff --git a/kclvm/runtime/src/value/val_fmt.rs b/kclvm/runtime/src/value/val_fmt.rs index 220e8f3d6..30e3a1e1a 100644 --- a/kclvm/runtime/src/value/val_fmt.rs +++ b/kclvm/runtime/src/value/val_fmt.rs @@ -1,9 +1,10 @@ //! Ref: https://github.com/RustPython/RustPython/blob/main/vm/src/format.rs //! -//! Copyright 2021 The KCL Authors. All rights reserved. +//! Copyright The KCL Authors. All rights reserved. use itertools::{Itertools, PeekingNext}; use std::cmp; +use std::fmt; use std::str::FromStr; use crate::*; @@ -63,7 +64,7 @@ fn format_inf(case: Case) -> String { pub fn format_fixed(precision: usize, magnitude: f64, case: Case) -> String { match magnitude { - magnitude if magnitude.is_finite() => format!("{:.*}", precision, magnitude), + magnitude if magnitude.is_finite() => format!("{magnitude:.precision$}"), magnitude if magnitude.is_nan() => format_nan(case), magnitude if magnitude.is_infinite() => format_inf(case), _ => "".to_string(), @@ -75,19 +76,19 @@ pub fn is_integer(v: f64) -> bool { } pub fn float_to_string(value: f64) -> String { - let lit = format!("{:e}", value); + let lit = format!("{value:e}"); if let Some(position) = lit.find('e') { let significand = &lit[..position]; let exponent = &lit[position + 1..]; let exponent = exponent.parse::().unwrap(); if exponent < 16 && exponent > -5 { if is_integer(value) { - format!("{:.1?}", value) + format!("{value:.1?}") } else { value.to_string() } } else { - format!("{}e{:+#03}", significand, exponent) + format!("{significand}e{exponent:+#03}") } } else { value.to_string() @@ -108,11 +109,11 @@ pub fn format_general(precision: usize, magnitude: f64, case: Case) -> String { }; let base = remove_trailing_redundant_chars(format!("{:.*}", precision + 1, base)); - format!("{}{}{:+#03}", base, e, exponent) + format!("{base}{e}{exponent:+#03}") } else { let precision = (precision as i64) - 1 - exponent; let precision = precision as usize; - remove_trailing_redundant_chars(format!("{:.*}", precision, magnitude)) + remove_trailing_redundant_chars(format!("{magnitude:.precision$}")) } } magnitude if magnitude.is_nan() => format_nan(case), @@ -126,7 +127,7 @@ pub fn format_general(precision: usize, magnitude: f64, case: Case) -> String { pub fn format_exponent(precision: usize, magnitude: f64, case: Case) -> String { match magnitude { magnitude if magnitude.is_finite() => { - let r_exp = format!("{:.*e}", precision, magnitude); + let r_exp = format!("{magnitude:.precision$e}"); let mut parts = r_exp.splitn(2, 'e'); let base = parts.next().unwrap(); let exponent = parts.next().unwrap().parse::().unwrap(); @@ -134,7 +135,7 @@ pub fn format_exponent(precision: usize, magnitude: f64, case: Case) -> String { Case::Lower => 'e', Case::Upper => 'E', }; - format!("{}{}{:+#03}", base, e, exponent) + format!("{base}{e}{exponent:+#03}") } magnitude if magnitude.is_nan() => format_nan(case), magnitude if magnitude.is_infinite() => format_inf(case), @@ -251,7 +252,7 @@ pub(crate) struct FormatSpec { pub(crate) fn get_num_digits(text: &str) -> usize { for (index, character) in text.char_indices() { - if !character.is_digit(10) { + if !character.is_ascii_digit() { return index; } } @@ -419,7 +420,6 @@ impl FormatSpec { .collect::() } - #[allow(dead_code)] fn add_magnitude_separators_for_char( magnitude_string: String, interval: usize, @@ -445,7 +445,6 @@ impl FormatSpec { result } - #[allow(dead_code)] fn get_separator_interval(&self) -> usize { match self.format_type { Some(FormatType::Binary) => 4, @@ -460,7 +459,6 @@ impl FormatSpec { } } - #[allow(dead_code)] fn add_magnitude_separators(&self, magnitude_string: String) -> String { match self.grouping_option { Some(FormatGrouping::Comma) => FormatSpec::add_magnitude_separators_for_char( @@ -525,11 +523,8 @@ impl FormatSpec { }, }; - if raw_magnitude_string_result.is_err() { - return raw_magnitude_string_result; - } - - let magnitude_string = self.add_magnitude_separators(raw_magnitude_string_result.unwrap()); + let raw_magnitude_string = raw_magnitude_string_result?; + let magnitude_string = self.add_magnitude_separators(raw_magnitude_string); let format_sign = self.sign.unwrap_or(FormatSign::Minus); let sign_str = if num.is_sign_negative() && !num.is_nan() { "-" @@ -558,16 +553,16 @@ impl FormatSpec { "" }; let raw_magnitude_string_result: Result = match self.format_type { - Some(FormatType::Binary) => Ok(format!("{:b}", magnitude)), - Some(FormatType::Decimal) => Ok(format!("{}", magnitude)), - Some(FormatType::Octal) => Ok(format!("{:o}", magnitude)), - Some(FormatType::HexLower) => Ok(format!("{:x}", magnitude)), + Some(FormatType::Binary) => Ok(format!("{magnitude:b}")), + Some(FormatType::Decimal) => Ok(format!("{magnitude}")), + Some(FormatType::Octal) => Ok(format!("{magnitude:o}")), + Some(FormatType::HexLower) => Ok(format!("{magnitude:x}")), Some(FormatType::HexUpper) => { - let mut result = format!("{:x}", magnitude); + let mut result = format!("{magnitude:x}"); result.make_ascii_uppercase(); Ok(result) } - Some(FormatType::Number) => Ok(format!("{}", magnitude)), + Some(FormatType::Number) => Ok(format!("{magnitude}")), Some(FormatType::String) => Err("Unknown format code 's' for object of type 'int'"), Some(FormatType::Character) => Err("Unknown format code 'c' for object of type 'int'"), Some(FormatType::GeneralFormatUpper) => { @@ -583,13 +578,11 @@ impl FormatSpec { | Some(FormatType::Percentage) => self.format_float(*num as f64), None => Ok(magnitude.to_string()), }; - if raw_magnitude_string_result.is_err() { - return raw_magnitude_string_result; - } + let raw_magnitude_string = raw_magnitude_string_result?; let magnitude_string = format!( "{}{}", prefix, - self.add_magnitude_separators(raw_magnitude_string_result.unwrap()) + self.add_magnitude_separators(raw_magnitude_string) ); let format_sign = self.sign.unwrap_or(FormatSign::Minus); @@ -605,15 +598,6 @@ impl FormatSpec { self.format_sign_and_align(&magnitude_string, sign_str) } - #[allow(dead_code)] - pub(crate) fn format_string(&self, s: &str) -> Result { - match self.format_type { - Some(FormatType::String) | None => self.format_sign_and_align(s, ""), - _ => Err("Unknown format code for object of type 'str'"), - } - } - - #[allow(dead_code)] fn format_sign_and_align( &self, magnitude_string: &str, @@ -653,10 +637,7 @@ impl FormatSpec { FormatSpec::compute_fill_string(fill_char, left_fill_chars_needed); let right_fill_string = FormatSpec::compute_fill_string(fill_char, right_fill_chars_needed); - format!( - "{}{}{}{}", - left_fill_string, sign_str, magnitude_string, right_fill_string - ) + format!("{left_fill_string}{sign_str}{magnitude_string}{right_fill_string}") } }) } @@ -908,21 +889,22 @@ impl FormatString { } FieldType::Keyword(keyword) => kwargs .dict_get_value(keyword.as_str()) - .expect("keyword argument not found"), + .unwrap_or_else(|| panic!("keyword argument '{keyword}' not found")) + .clone(), }; for name_part in parts { match name_part { // Load attr FieldNamePart::Attribute(attr) => { - argument = args.dict_get_value(attr.as_str()).unwrap(); + argument = argument.dict_get_value(attr.as_str()).unwrap().clone(); } // List subscript FieldNamePart::Index(index) => { - argument = args.list_get(index as isize).unwrap(); + argument = argument.list_get(index as isize).unwrap().clone(); } // Dict subscript FieldNamePart::StringIndex(value) => { - argument = args.dict_get_value(value.as_str()).unwrap(); + argument = argument.dict_get_value(value.as_str()).unwrap().clone(); } } } @@ -982,61 +964,41 @@ pub fn quoted_string(value: &str) -> String { let has_double_quote = value.contains('\''); let has_single_quote = value.contains('\"'); if !has_single_quote { - format!("'{}'", value) + format!("'{value}'") } else if !has_double_quote { - format!("\"{}\"", value) + format!("\"{value}\"") } else { - format!("\"{}\"", value.replace("\"", "\\\"")) + format!("\"{}\"", value.replace('\"', "\\\"")) } } -impl ValueRef { - /// to_string_with_spec e.g., "{:.0f}".format(1.0) - pub fn to_string_with_spec(&self, spec: &str) -> String { - match &*self.rc { - Value::int_value(ref v) => { - match FormatSpec::parse(spec).and_then(|format_spec| format_spec.format_int(v)) { - Ok(string) => string, - Err(err) => panic!("{}", err), - } - } - Value::float_value(ref v) => { - match FormatSpec::parse(spec).and_then(|format_spec| format_spec.format_float(*v)) { - Ok(string) => string, - Err(err) => panic!("{}", err), - } - } - _ => self.to_string(), - } - } - - /// to_string e.g., "{}".format(1.0) - pub fn to_string(&self) -> String { - match &*self.rc { - Value::undefined => String::from("Undefined"), - Value::none => String::from("None"), +impl fmt::Display for ValueRef { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match &*self.rc.borrow() { + Value::undefined => write!(f, "Undefined"), + Value::none => write!(f, "None"), Value::bool_value(ref v) => { if *v { - String::from("True") + write!(f, "True") } else { - String::from("False") + write!(f, "False") } } - Value::int_value(ref v) => v.to_string(), + Value::int_value(ref v) => write!(f, "{v}"), Value::float_value(ref v) => { let mut float_str = v.to_string(); if !float_str.contains('.') { float_str.push_str(".0"); } - float_str + write!(f, "{float_str}") } Value::unit_value(_, raw, unit) => { - format!("{}{}", raw, unit) + write!(f, "{raw}{unit}") } - Value::str_value(ref v) => v.clone(), + Value::str_value(ref v) => write!(f, "{v}"), Value::list_value(ref v) => { let values: Vec = v.values.iter().map(|v| v.to_string()).collect(); - format!("[{}]", values.join(", ")) + write!(f, "[{}]", values.join(", ")) } Value::dict_value(ref v) => { let values: Vec = v @@ -1044,7 +1006,7 @@ impl ValueRef { .iter() .map(|(k, v)| format!("{}: {}", quoted_string(k), value_to_quoted_string(v))) .collect(); - format!("{{{}}}", values.join(", ")) + write!(f, "{{{}}}", values.join(", ")) } Value::schema_value(ref v) => { let values: Vec = v @@ -1053,9 +1015,57 @@ impl ValueRef { .iter() .map(|(k, v)| format!("{}: {}", quoted_string(k), value_to_quoted_string(v))) .collect(); - format!("{{{}}}", values.join(", ")) + write!(f, "{{{}}}", values.join(", ")) } - Value::func_value(_) => String::from("function"), + Value::func_value(_) => write!(f, "function"), + } + } +} + +impl ValueRef { + /// to_string_with_spec e.g., "{:.0f}".format(1.0) + pub fn to_string_with_spec(&self, spec: &str) -> String { + match &*self.rc.borrow() { + Value::int_value(ref v) => { + match FormatSpec::parse(spec).and_then(|format_spec| format_spec.format_int(v)) { + Ok(string) => string, + Err(err) => panic!("{}", err), + } + } + Value::float_value(ref v) => { + match FormatSpec::parse(spec).and_then(|format_spec| format_spec.format_float(*v)) { + Ok(string) => string, + Err(err) => panic!("{}", err), + } + } + _ => self.to_string(), + } + } +} + +#[cfg(test)] +mod test_value_fmt { + use crate::*; + + #[test] + fn test_string_format() { + let mut ctx = Context::new(); + let cases = [ + (r#""{} {}""#, r#"["Hello","World"]"#, "\"Hello World\""), + (r#""{:.0f}""#, r#"[1.0]"#, "\"1\""), + (r#""{:.1f} {:.0f}""#, r#"[1.0,2.0]"#, "\"1.0 2\""), + ( + r#""0{0[0]}, 1{0[1]}, Hello{1[Hello]}""#, + r#"[["0","1"],{ "Hello": "World" }]"#, + "\"00, 11, HelloWorld\"", + ), + ]; + for (format_string, args, expected) in cases { + let format_string = FormatString::from_str(format_string).unwrap(); + let args = ValueRef::from_json(&mut ctx, args).unwrap(); + let kwargs = ValueRef::dict(None); + let result = format_string.format(&args, &kwargs); + assert_eq!(&result, expected) } } } diff --git a/kclvm/runtime/src/value/val_from.rs b/kclvm/runtime/src/value/val_from.rs index 5bad2c568..992db5b89 100644 --- a/kclvm/runtime/src/value/val_from.rs +++ b/kclvm/runtime/src/value/val_from.rs @@ -1,6 +1,7 @@ -// Copyright 2022 The KCL Authors. All rights reserved. +// Copyright The KCL Authors. All rights reserved. use crate::*; +use std::cell::RefCell; use std::convert::{From, TryFrom}; use std::iter::FromIterator; use std::rc::Rc; @@ -24,24 +25,24 @@ macro_rules! define_value_from_trait { } macro_rules! define_value_try_from_trait { - ($for_type: ty, $kcl_type_value :ident) => { + ($for_type: ty, $kcl_type_value :ident, $for_type_name :expr) => { impl TryFrom for $for_type { - type Error = (); + type Error = String; fn try_from(v: ValueRef) -> Result { - match &*v.rc { + match &*v.rc.borrow() { Value::$kcl_type_value(v) => Ok(v.clone()), - _ => Err(()), + _ => Err(format!("can't convert {} to {}", v, $for_type_name)), } } } impl TryFrom<&ValueRef> for $for_type { - type Error = (); + type Error = String; fn try_from(v: &ValueRef) -> Result { - match &*v.rc { + match &*v.rc.borrow() { Value::$kcl_type_value(v) => Ok(v.clone()), - _ => Err(()), + _ => Err(format!("can't convert {} to {}", v, $for_type_name)), } } } @@ -51,7 +52,7 @@ macro_rules! define_value_try_from_trait { macro_rules! define_value_try_into_method { ($try_into_type: ident, $type: ty) => { impl ValueRef { - pub fn $try_into_type(&self) -> Result<$type, ()> { + pub fn $try_into_type(&self) -> Result<$type, String> { use std::convert::TryInto; self.try_into() } @@ -69,16 +70,18 @@ define_value_try_into_method!(try_into_int, i64); define_value_try_into_method!(try_into_float, f64); define_value_try_into_method!(try_into_str, String); -define_value_try_from_trait!(bool, bool_value); -define_value_try_from_trait!(i64, int_value); -define_value_try_from_trait!(f64, float_value); -define_value_try_from_trait!(String, str_value); +define_value_try_from_trait!(bool, bool_value, "bool"); +define_value_try_from_trait!(i64, int_value, "i64"); +define_value_try_from_trait!(f64, float_value, "f64"); +define_value_try_from_trait!(String, str_value, "String"); // value impl From for ValueRef { fn from(v: Value) -> Self { - Self { rc: Rc::new(v) } + Self { + rc: Rc::new(RefCell::new(v)), + } } } @@ -92,7 +95,7 @@ macro_rules! define_value_list_from_iter_trait { for i in iter { list.values.push(i.into()); } - Self::from(Value::list_value(list)) + Self::from(Value::list_value(Box::new(list))) } } }; @@ -103,7 +106,7 @@ macro_rules! define_value_list_from_iter_trait { for i in iter { list.values.push(i.into()); } - Self::from(Value::list_value(list)) + Self::from(Value::list_value(Box::new(list))) } } }; @@ -116,9 +119,9 @@ define_value_list_from_iter_trait!(f64); define_value_list_from_iter_trait!(ref, str); define_value_list_from_iter_trait!(ref, ValueRef); -define_value_try_from_trait!(ListValue, list_value); +define_value_try_from_trait!(Box, list_value, "ListValue"); -define_value_try_into_method!(try_into_list, ListValue); +define_value_try_into_method!(try_into_list, Box); // dict @@ -130,7 +133,7 @@ macro_rules! define_value_dict_from_iter_trait { for (k, v) in iter { dict.values.insert(k.to_string(), v.into()); } - Self::from(Value::dict_value(dict)) + Self::from(Value::dict_value(Box::new(dict))) } } }; @@ -141,7 +144,7 @@ macro_rules! define_value_dict_from_iter_trait { for (k, v) in iter { dict.values.insert(k.to_string(), v.into()); } - Self::from(Value::dict_value(dict)) + Self::from(Value::dict_value(Box::new(dict))) } } }; @@ -153,13 +156,13 @@ define_value_dict_from_iter_trait!(f64); define_value_dict_from_iter_trait!(ref, str); define_value_dict_from_iter_trait!(ref, ValueRef); -define_value_try_from_trait!(DictValue, dict_value); +define_value_try_from_trait!(Box, dict_value, "DictValue"); -define_value_try_into_method!(try_into_dict, DictValue); +define_value_try_into_method!(try_into_dict, Box); // schema -define_value_try_from_trait!(SchemaValue, schema_value); +define_value_try_from_trait!(Box, schema_value, "SchemaValue"); #[cfg(test)] mod tests_from { @@ -175,12 +178,12 @@ mod tests_from { assert_eq!(ValueRef::bool(true), ValueRef::from(TRUE)); assert_eq!(ValueRef::bool(false), ValueRef::from(FALSE)); - assert_eq!(true, ValueRef::from(true).try_into_bool().unwrap()); + assert!(ValueRef::from(true).try_into_bool().unwrap()); assert_eq!(123, ValueRef::from(123).try_into_int().unwrap()); assert_eq!(1.5, ValueRef::from(1.5).try_into_float().unwrap()); assert_eq!("abc", ValueRef::from("abc").try_into_str().unwrap()); - assert_eq!(true, bool::try_from(ValueRef::from(true)).unwrap()); + assert!(bool::try_from(ValueRef::from(true)).unwrap()); assert_eq!(123, i64::try_from(ValueRef::from(123)).unwrap()); assert_eq!(1.5, f64::try_from(ValueRef::from(1.5)).unwrap()); assert_eq!("abc", String::try_from(ValueRef::from("abc")).unwrap()); @@ -201,11 +204,11 @@ mod tests_from { } test_x_type!(test_bool, bool, vec![true, false]); - test_x_type!(test_int, int, vec![-1 as i64, 0, 1, 123, 0xFFFFFFFF + 1]); + test_x_type!(test_int, int, vec![-1, 0, 1, 123, 0xFFFFFFFF + 1]); test_x_type!( test_float, float, - vec![0.0 as f64, 1.5, 123.0, 0xFFFFFFFFi64 as f64 + 1.0] + vec![0.0, 1.5, 123.0, 0xFFFFFFFFi64 as f64 + 1.0] ); test_x_type!(test_str, str, vec!["", "abc", "123"]); @@ -214,7 +217,7 @@ mod tests_from { fn test_list() { let list = vec![true, false]; - let list_value: ValueRef = ValueRef::from_iter(list.clone().into_iter()); + let list_value: ValueRef = ValueRef::from_iter(list.clone()); assert_eq!(list.len(), list_value.len()); for (i, v) in list.iter().enumerate() { @@ -223,11 +226,12 @@ mod tests_from { } } + #[test] fn test_list2() { let list = vec![1, 2, 4, 3]; - let list_value: ValueRef = ValueRef::from_iter(list.clone().into_iter()); - let list_value: ListValue = list_value.try_into().unwrap(); + let list_value: ValueRef = ValueRef::from_iter(list.clone()); + let list_value: Box = list_value.try_into().unwrap(); assert_eq!( list_value @@ -241,6 +245,7 @@ mod tests_from { macro_rules! test_try_into { ($test_fn_name: ident, $type: ty, $tests: expr) => { + #[test] fn $test_fn_name() { for v in $tests { let v0 = v; @@ -252,8 +257,8 @@ mod tests_from { }; } - test_try_into!(test_try_into_bool, bool, vec![true, false, true, true]); - test_try_into!(test_try_into_i64, i64, vec![1, 2, 3, -1]); - test_try_into!(test_try_into_f64, f64, vec![1.5, 2.0]); - test_try_into!(test_try_into_str, String, vec!["", "abc"]); + test_try_into!(test_try_into_bool, bool, [true, false, true, true]); + test_try_into!(test_try_into_i64, i64, [1, 2, 3, -1]); + test_try_into!(test_try_into_f64, f64, [1.5, 2.0]); + test_try_into!(test_try_into_str, String, ["", "abc"]); } diff --git a/kclvm/runtime/src/value/val_func.rs b/kclvm/runtime/src/value/val_func.rs new file mode 100644 index 000000000..5adfe2cef --- /dev/null +++ b/kclvm/runtime/src/value/val_func.rs @@ -0,0 +1,13 @@ +use generational_arena::Index; + +use crate::ValueRef; + +impl ValueRef { + /// Try get the proxy function index + pub fn try_get_proxy(&self) -> Option { + match &*self.rc.borrow() { + crate::Value::func_value(func) => func.proxy, + _ => None, + } + } +} diff --git a/kclvm/runtime/src/value/val_get_set.rs b/kclvm/runtime/src/value/val_get_set.rs index 4c8da5e19..ceecb7a75 100644 --- a/kclvm/runtime/src/value/val_get_set.rs +++ b/kclvm/runtime/src/value/val_get_set.rs @@ -1,61 +1,24 @@ -// Copyright 2021 The KCL Authors. All rights reserved. +//! Copyright The KCL Authors. All rights reserved. use crate::*; impl ValueRef { - pub fn get_by_key(&self, key: &str) -> Option<&Self> { - match &*self.rc { + pub fn get_by_key(&self, key: &str) -> Option { + match &*self.rc.borrow() { Value::list_value(ref list) => match key.parse::() { - Ok(i) => list.values.as_slice().get(i), + Ok(i) => list.values.as_slice().get(i).cloned(), Err(_) => None, }, - Value::dict_value(ref dict) => dict.values.get(key), - Value::schema_value(ref schema) => schema.config.values.get(key), + Value::dict_value(ref dict) => dict.values.get(key).cloned(), + Value::schema_value(ref schema) => schema.config.values.get(key).cloned(), _ => None, } } - pub fn get_mut_by_key(&mut self, key: &str) -> Option<&mut Self> { - match &*self.rc { - Value::list_value(ref list) => match key.parse::() { - Ok(i) => { - let list: &mut ListValue = get_ref_mut(list); - return list.values.as_mut_slice().get_mut(i); - } - Err(_) => None, - }, - Value::dict_value(ref dict) => { - let dict: &mut DictValue = get_ref_mut(dict); - dict.values.get_mut(key) - } - Value::schema_value(ref schema) => { - let schema: &mut SchemaValue = get_ref_mut(schema); - let dict: &mut DictValue = get_ref_mut(schema.config.as_ref()); - dict.values.get_mut(key) - } - _ => None, - } - } - - pub fn get_by_path(&self, path: &str) -> Option<&Self> { - let mut val: &Self = self; + pub fn get_by_path(&self, path: &str) -> Option { + let mut val: Self = self.clone(); for key in path.split('.') { match val.get_by_key(key) { - Some(x) => { - val = x; - } - None => { - return None; - } - } - } - Some(val) - } - - pub fn get_mut(&mut self, path: &str) -> Option<&Self> { - let mut val: &mut Self = self; - for key in path.split('.') { - match val.get_mut_by_key(key) { Some(x) => { val = x; } @@ -72,27 +35,39 @@ mod test_value_get { #[test] fn test_get() { - let mut list_int = ValueRef::list_int(&vec![10 as i64, 20, 30]); - + let mut list_int = ValueRef::list_int(&[10_i64, 20, 30]); + let mut ctx = Context::new(); let mut dict = ValueRef::dict(None); - dict.dict_insert("a", &ValueRef::str("a-value"), Default::default(), 0); - dict.dict_insert("b", &ValueRef::str("b-value"), Default::default(), 0); + dict.dict_insert( + &mut ctx, + "a", + &ValueRef::str("a-value"), + Default::default(), + None, + ); + dict.dict_insert( + &mut ctx, + "b", + &ValueRef::str("b-value"), + Default::default(), + None, + ); list_int.list_set(1, &dict); - list_int.list_set(2, &ValueRef::list_int(&vec![100 as i64, 200, 300])); + list_int.list_set(2, &ValueRef::list_int(&[100_i64, 200, 300])); assert_eq!(list_int.get_by_path("1.a").unwrap().as_str(), "a-value"); assert_eq!(list_int.get_by_path("2.2").unwrap().as_int(), 300); - let dict = ValueRef::dict(Some(&vec![ + let dict = ValueRef::dict(Some(&[ ("aaa", &ValueRef::int(111)), ( "bbb", - &ValueRef::list(Some(&vec![ + &ValueRef::list(Some(&[ &ValueRef::str("a"), &ValueRef::str("b"), - &ValueRef::dict(Some(&vec![("key0", &ValueRef::int(12345))])), + &ValueRef::dict(Some(&[("key0", &ValueRef::int(12345))])), ])), ), ])); diff --git a/kclvm/runtime/src/value/val_is_in.rs b/kclvm/runtime/src/value/val_is_in.rs index 2bebdd95e..e93ee9d08 100644 --- a/kclvm/runtime/src/value/val_is_in.rs +++ b/kclvm/runtime/src/value/val_is_in.rs @@ -1,4 +1,4 @@ -// Copyright 2021 The KCL Authors. All rights reserved. +//! Copyright The KCL Authors. All rights reserved. use crate::*; @@ -7,12 +7,12 @@ use crate::*; impl ValueRef { #[inline] pub fn is_undefined(&self) -> bool { - matches!(&*self.rc, Value::undefined) + matches!(&*self.rc.borrow(), Value::undefined) } #[inline] pub fn is_none(&self) -> bool { - matches!(&*self.rc, Value::none) + matches!(&*self.rc.borrow(), Value::none) } #[inline] @@ -52,18 +52,35 @@ impl ValueRef { #[inline] pub fn is_number(&self) -> bool { - matches!(&*self.rc, Value::int_value(_) | Value::float_value(_)) + matches!( + &*self.rc.borrow(), + Value::int_value(_) | Value::float_value(_) + ) + } + + #[inline] + pub fn is_builtin(&self) -> bool { + matches!( + &*self.rc.borrow(), + Value::int_value(_) + | Value::float_value(_) + | Value::bool_value(_) + | Value::str_value(_) + ) } #[inline] pub fn is_config(&self) -> bool { - matches!(&*self.rc, Value::schema_value(_) | Value::dict_value(_)) + matches!( + &*self.rc.borrow(), + Value::schema_value(_) | Value::dict_value(_) + ) } #[inline] pub fn is_list_or_config(&self) -> bool { matches!( - &*self.rc, + &*self.rc.borrow(), Value::list_value(_) | Value::schema_value(_) | Value::dict_value(_) ) } @@ -75,12 +92,25 @@ impl ValueRef { #[inline] pub fn is_none_or_undefined(&self) -> bool { - matches!(&*self.rc, Value::none | Value::undefined) + matches!(&*self.rc.borrow(), Value::none | Value::undefined) } #[inline] pub fn is_unit(&self) -> bool { - matches!(&*self.rc, Value::unit_value(..)) + matches!(&*self.rc.borrow(), Value::unit_value(..)) + } + + #[inline] + pub fn is_scalar(&self) -> bool { + matches!( + &*self.rc.borrow(), + Value::none + | Value::bool_value(_) + | Value::int_value(_) + | Value::float_value(_) + | Value::str_value(_) + | Value::unit_value(..) + ) } } @@ -88,9 +118,9 @@ impl ValueRef { impl ValueRef { pub fn r#in(&self, x: &Self) -> bool { - match &*x.rc { + match &*x.rc.borrow() { // "a" in "abc" - Value::str_value(ref b) => match &*self.rc { + Value::str_value(ref b) => match &*self.rc.borrow() { Value::str_value(ref a) => b.contains(a), _ => false, }, @@ -130,7 +160,7 @@ impl ValueRef { impl ValueRef { pub fn has_key(&self, key: &str) -> bool { - match &*self.rc { + match &*self.rc.borrow() { Value::dict_value(ref dict) => dict.values.contains_key(key), Value::schema_value(ref schema) => schema.config.values.contains_key(key), _ => false, @@ -148,39 +178,27 @@ mod test_value_in { #[test] fn test_in() { - assert_eq!(ValueRef::str("a").r#in(&ValueRef::str("abc")), true); - assert_eq!(ValueRef::str("ab").r#in(&ValueRef::str("abc")), true); - assert_eq!(ValueRef::str("abcd").r#in(&ValueRef::str("abc")), false); - - assert_eq!( - ValueRef::str("a").r#in(&ValueRef::list_str(&[ - "a".to_string(), - "b".to_string(), - "c".to_string() - ])), - true - ); - assert_eq!( - ValueRef::str("d").r#in(&ValueRef::list_str(&[ - "a".to_string(), - "b".to_string(), - "c".to_string() - ])), - false - ); - assert_eq!( - ValueRef::str("key1").r#in(&ValueRef::dict_str(&[ - ("key1", "value1"), - ("key2", "value1"), - ])), - true - ); - assert_eq!( - ValueRef::str("err_key").r#in(&ValueRef::dict_str(&[ - ("key1", "value1"), - ("key2", "value1"), - ])), - false - ); + assert!(ValueRef::str("a").r#in(&ValueRef::str("abc"))); + assert!(ValueRef::str("ab").r#in(&ValueRef::str("abc"))); + assert!(!ValueRef::str("abcd").r#in(&ValueRef::str("abc"))); + + assert!(ValueRef::str("a").r#in(&ValueRef::list_str(&[ + "a".to_string(), + "b".to_string(), + "c".to_string() + ]))); + assert!(!ValueRef::str("d").r#in(&ValueRef::list_str(&[ + "a".to_string(), + "b".to_string(), + "c".to_string() + ]))); + assert!(ValueRef::str("key1").r#in(&ValueRef::dict_str(&[ + ("key1", "value1"), + ("key2", "value1"), + ]))); + assert!(!ValueRef::str("err_key").r#in(&ValueRef::dict_str(&[ + ("key1", "value1"), + ("key2", "value1"), + ]))); } } diff --git a/kclvm/runtime/src/value/val_json.rs b/kclvm/runtime/src/value/val_json.rs index 10f77ea15..6d291f393 100644 --- a/kclvm/runtime/src/value/val_json.rs +++ b/kclvm/runtime/src/value/val_json.rs @@ -1,9 +1,24 @@ -// Copyright 2021 The KCL Authors. All rights reserved. +//! Copyright The KCL Authors. All rights reserved. -use crate::*; -use json_minimal::*; +use bstr::ByteSlice; +use indexmap::IndexMap; +use serde::{ + de::{DeserializeSeed, MapAccess, SeqAccess, Visitor}, + Deserialize, Serialize, +}; -#[derive(Debug, Default)] +use crate::{val_plan::KCL_PRIVATE_VAR_PREFIX, ConfigEntryOperationKind, Context, ValueRef}; + +macro_rules! tri { + ($e:expr $(,)?) => { + match $e { + core::result::Result::Ok(val) => val, + core::result::Result::Err(err) => return core::result::Result::Err(err), + } + }; +} + +#[derive(Debug, Clone, Default)] pub struct JsonEncodeOptions { pub sort_keys: bool, pub indent: i64, @@ -11,202 +26,527 @@ pub struct JsonEncodeOptions { pub ignore_none: bool, } +struct JsonFormatter { + current_indent: usize, + has_value: bool, + indent: String, +} + +#[derive(Clone, Eq, PartialEq)] +pub(crate) enum JsonValue { + Null, + + Bool(bool), + + Number(serde_json::Number), + + String(String), + + Array(Vec), + + Object(IndexMap), +} + +struct MapKeyClass; +impl<'de> DeserializeSeed<'de> for MapKeyClass { + type Value = String; + + fn deserialize(self, deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + deserializer.deserialize_str(self) + } +} + +impl<'de> Visitor<'de> for MapKeyClass { + type Value = String; + + fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { + formatter.write_str("a string key") + } + + fn visit_str(self, s: &str) -> Result + where + E: serde::de::Error, + { + Ok(s.to_owned()) + } + + fn visit_string(self, s: String) -> Result + where + E: serde::de::Error, + { + Ok(s) + } +} + +impl<'de> Deserialize<'de> for JsonValue { + #[inline] + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + struct ValueVisitor; + + impl<'de> Visitor<'de> for ValueVisitor { + type Value = JsonValue; + + fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { + formatter.write_str("any valid JSON value") + } + + #[inline] + fn visit_bool(self, value: bool) -> Result { + Ok(Self::Value::Bool(value)) + } + + #[inline] + fn visit_i64(self, value: i64) -> Result { + Ok(Self::Value::Number(value.into())) + } + + #[inline] + fn visit_u64(self, value: u64) -> Result { + Ok(Self::Value::Number(value.into())) + } + + #[inline] + fn visit_f64(self, value: f64) -> Result { + Ok(serde_json::Number::from_f64(value) + .map_or(Self::Value::Null, Self::Value::Number)) + } + + #[inline] + fn visit_str(self, value: &str) -> Result + where + E: serde::de::Error, + { + self.visit_string(String::from(value)) + } + + #[inline] + fn visit_string(self, value: String) -> Result { + Ok(Self::Value::String(value)) + } + + #[inline] + fn visit_none(self) -> Result { + Ok(Self::Value::Null) + } + + #[inline] + fn visit_some(self, deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + Deserialize::deserialize(deserializer) + } + + #[inline] + fn visit_unit(self) -> Result { + Ok(Self::Value::Null) + } + + #[inline] + fn visit_seq(self, mut visitor: V) -> Result + where + V: SeqAccess<'de>, + { + let mut vec = Vec::new(); + + while let Some(elem) = tri!(visitor.next_element()) { + vec.push(elem); + } + + Ok(Self::Value::Array(vec)) + } + + fn visit_map(self, mut visitor: V) -> Result + where + V: MapAccess<'de>, + { + match visitor.next_key_seed(MapKeyClass)? { + Some(first_key) => { + let mut values = IndexMap::new(); + + values.insert(first_key, tri!(visitor.next_value())); + while let Some((key, value)) = tri!(visitor.next_entry()) { + values.insert(key, value); + } + + Ok(Self::Value::Object(values)) + } + None => Ok(Self::Value::Object(IndexMap::new())), + } + } + } + + deserializer.deserialize_any(ValueVisitor) + } +} + +impl Serialize for JsonValue { + #[inline] + fn serialize(&self, serializer: S) -> Result + where + S: ::serde::Serializer, + { + match self { + JsonValue::Null => serializer.serialize_unit(), + JsonValue::Bool(b) => serializer.serialize_bool(*b), + JsonValue::Number(n) => n.serialize(serializer), + JsonValue::String(s) => serializer.serialize_str(s), + JsonValue::Array(v) => v.serialize(serializer), + JsonValue::Object(m) => { + use serde::ser::SerializeMap; + let mut map = tri!(serializer.serialize_map(Some(m.len()))); + for (k, v) in m { + tri!(map.serialize_entry(k, v)); + } + map.end() + } + } + } +} + +impl JsonFormatter { + /// Construct a pretty printer formatter that defaults to using two spaces for indentation. + pub fn new() -> Self { + JsonFormatter::with_indent(0) + } + + /// Construct a pretty printer formatter that uses the `indent` string for indentation. + pub fn with_indent(indent: i64) -> Self { + let indent = if indent < 0 { 0 } else { indent as usize }; + JsonFormatter { + current_indent: 0, + has_value: false, + indent: String::from_utf8(vec![b' '; indent]).unwrap(), + } + } +} + +impl Default for JsonFormatter { + fn default() -> Self { + JsonFormatter::new() + } +} + +impl serde_json::ser::Formatter for JsonFormatter { + #[inline] + fn begin_array(&mut self, writer: &mut W) -> std::io::Result<()> + where + W: ?Sized + std::io::Write, + { + self.current_indent += 1; + self.has_value = false; + writer.write_all(b"[") + } + + #[inline] + fn end_array(&mut self, writer: &mut W) -> std::io::Result<()> + where + W: ?Sized + std::io::Write, + { + self.current_indent -= 1; + + if self.has_value && !self.indent.is_empty() { + tri!(writer.write_all(b"\n")); + tri!(indent(writer, self.current_indent, self.indent.as_bytes())); + } + + writer.write_all(b"]") + } + + #[inline] + fn begin_array_value(&mut self, writer: &mut W, first: bool) -> std::io::Result<()> + where + W: ?Sized + std::io::Write, + { + if !first { + tri!(writer.write_all(b",")); + } + if !self.indent.is_empty() { + tri!(writer.write_all(b"\n")); + } else if !first { + tri!(writer.write_all(b" ")); + } + tri!(indent(writer, self.current_indent, self.indent.as_bytes())); + Ok(()) + } + + #[inline] + fn end_array_value(&mut self, _writer: &mut W) -> std::io::Result<()> + where + W: ?Sized + std::io::Write, + { + self.has_value = true; + Ok(()) + } + + #[inline] + fn begin_object(&mut self, writer: &mut W) -> std::io::Result<()> + where + W: ?Sized + std::io::Write, + { + self.current_indent += 1; + self.has_value = false; + writer.write_all(b"{") + } + + #[inline] + fn end_object(&mut self, writer: &mut W) -> std::io::Result<()> + where + W: ?Sized + std::io::Write, + { + self.current_indent -= 1; + + if self.has_value && !self.indent.is_empty() { + tri!(writer.write_all(b"\n")); + tri!(indent(writer, self.current_indent, self.indent.as_bytes())); + } + + writer.write_all(b"}") + } + + #[inline] + fn begin_object_key(&mut self, writer: &mut W, first: bool) -> std::io::Result<()> + where + W: ?Sized + std::io::Write, + { + if !first { + tri!(writer.write_all(b",")); + } + if !self.indent.is_empty() { + tri!(writer.write_all(b"\n")); + } else if !first { + tri!(writer.write_all(b" ")); + } + indent(writer, self.current_indent, self.indent.as_bytes()) + } + + #[inline] + fn begin_object_value(&mut self, writer: &mut W) -> std::io::Result<()> + where + W: ?Sized + std::io::Write, + { + writer.write_all(b": ") + } + + #[inline] + fn end_object_value(&mut self, _writer: &mut W) -> std::io::Result<()> + where + W: ?Sized + std::io::Write, + { + self.has_value = true; + Ok(()) + } +} + +fn indent(wr: &mut W, n: usize, s: &[u8]) -> std::io::Result<()> +where + W: ?Sized + std::io::Write, +{ + for _ in 0..n { + tri!(wr.write_all(s)); + } + + Ok(()) +} + impl ValueRef { - pub fn from_json(s: &str) -> Option { - match Json::parse_with_option( - s.as_bytes(), - &json_minimal::ParseOption { support_int: true }, - ) { - Ok(json) => Some(Self::parse_json(&json)), - _ => None, + pub fn from_json(ctx: &mut Context, s: &str) -> Result { + match serde_json::de::from_str::(s) { + Ok(json) => Ok(Self::parse_json(ctx, &json)), + Err(err) => Err(err), } } - fn parse_json(json: &Json) -> Self { + pub(crate) fn parse_json(ctx: &mut Context, json: &JsonValue) -> Self { match json { - Json::OBJECT { name, value } => { - let _ = name; - let _ = value; - panic!("unreachable"); - } - Json::JSON(values) => { + JsonValue::Object(values) => { let mut dict = Self::dict(None); - for value in values { - match value { - Json::OBJECT { name, value } => dict.dict_insert( - name.as_ref(), - &Self::parse_json(value), - ConfigEntryOperationKind::Union, - 0, - ), - _ => panic!("unreachable"), - } + for (name, value) in values { + let v = Self::parse_json(ctx, value); + dict.dict_insert( + ctx, + name.as_ref(), + &v, + ConfigEntryOperationKind::Union, + None, + ); } dict } - Json::ARRAY(values) => { + JsonValue::Array(values) => { let mut list = Self::list(None); for value in values { - list.list_append(&Self::parse_json(value)); + list.list_append(&Self::parse_json(ctx, value)); } list } - Json::STRING(val) => Self::str((*val).as_ref()), - Json::NUMBER(val) => Self::float(*val), - Json::INT(val) => Self::int(*val), - Json::FLOAT(val) => Self::float(*val), - Json::BOOL(val) => Self::bool(*val), - Json::NULL => Self::none(), + JsonValue::String(val) => Self::str((*val).as_ref()), + JsonValue::Number(val) => { + if val.is_i64() { + Self::int(val.as_i64().unwrap()) + } else if val.is_u64() { + let n = val.as_u64().unwrap(); + if n <= i64::max_value() as u64 { + Self::int(n as i64) + } else { + Self::float(n as f64) + } + } else { + Self::float(val.as_f64().unwrap()) + } + } + JsonValue::Bool(val) => Self::bool(*val), + JsonValue::Null => Self::none(), } } pub fn to_json(&self) -> Vec { let json = self.build_json(&Default::default()); - let opt = json_minimal::PrintOption { - sep_space: true, - py_style_f64: true, - ..Default::default() - }; - - json.print_with_option(&opt).into_bytes() + let formatter = JsonFormatter::new(); + let mut writer = Vec::with_capacity(128); + let mut serializer = serde_json::Serializer::with_formatter(&mut writer, formatter); + json.serialize(&mut serializer).unwrap(); + writer } pub fn to_json_string(&self) -> String { let json = self.build_json(&Default::default()); - let opt = json_minimal::PrintOption { - sep_space: true, - py_style_f64: true, - ..Default::default() - }; - - json.print_with_option(&opt) + let formatter = JsonFormatter::new(); + let mut writer = Vec::with_capacity(128); + let mut serializer = serde_json::Serializer::with_formatter(&mut writer, formatter); + json.serialize(&mut serializer).unwrap(); + writer.to_str().unwrap().to_string() } - pub fn to_json_string_with_option(&self, opt: &JsonEncodeOptions) -> String { - let json = self.build_json(opt); - - let opt = json_minimal::PrintOption { - sort_keys: opt.sort_keys, - indent: opt.indent as i32, - sep_space: true, - py_style_f64: true, - ..Default::default() - }; - - json.print_with_option(&opt) + pub fn to_json_string_with_options(&self, opts: &JsonEncodeOptions) -> String { + let json = self.build_json(opts); + let formatter = JsonFormatter::with_indent(opts.indent); + let mut writer = Vec::with_capacity(128); + let mut serializer = serde_json::Serializer::with_formatter(&mut writer, formatter); + json.serialize(&mut serializer).unwrap(); + writer.to_str().unwrap().to_string() } pub fn to_json_string_with_null(&self) -> String { let json = self.build_json(&Default::default()); - - let opt = json_minimal::PrintOption { - sep_space: true, - py_style_f64: true, - append_null: true, - ..Default::default() - }; - - json.print_with_option(&opt) + let formatter = JsonFormatter::new(); + let mut writer = Vec::with_capacity(128); + let mut serializer = serde_json::Serializer::with_formatter(&mut writer, formatter); + json.serialize(&mut serializer).unwrap(); + writer.push(0); + writer.to_str().unwrap().to_string() } - fn build_json(&self, opt: &JsonEncodeOptions) -> Json { - match &*self.rc { - Value::undefined => Json::NULL, - Value::none => Json::NULL, + pub(crate) fn build_json(&self, opts: &JsonEncodeOptions) -> JsonValue { + match &*self.rc.borrow() { + crate::Value::undefined => JsonValue::Null, + crate::Value::none => JsonValue::Null, - Value::bool_value(ref v) => Json::BOOL(*v), - Value::int_value(ref v) => Json::INT(*v), - Value::float_value(ref v) => Json::FLOAT(*v), - Value::unit_value(..) => Json::STRING(self.to_string()), - Value::str_value(ref v) => Json::STRING(v.clone()), + crate::Value::bool_value(ref v) => JsonValue::Bool(*v), + crate::Value::int_value(ref v) => JsonValue::Number(serde_json::Number::from(*v)), + crate::Value::float_value(ref v) => match serde_json::Number::from_f64(*v) { + Some(n) => JsonValue::Number(n), + None => JsonValue::Null, + }, + // The number_multiplier is still a number, if we want to get the string form, we can + // use the `str` function e.g. `str(1Mi)` + crate::Value::unit_value(ref v, ..) => match serde_json::Number::from_f64(*v) { + Some(n) => JsonValue::Number(n), + None => JsonValue::Null, + }, + crate::Value::str_value(ref v) => JsonValue::String(v.clone()), - Value::list_value(ref v) => { - let mut list = Json::ARRAY(Vec::new()); + crate::Value::list_value(ref v) => { + let mut val_array = Vec::new(); for x in v.values.iter() { - match *x.rc { - Value::undefined => { + match *x.rc.borrow() { + crate::Value::undefined => { continue; } - Value::none => { - if !opt.ignore_none { - list.add(x.build_json(opt)); + crate::Value::none => { + if !opts.ignore_none { + val_array.push(x.build_json(opts)); } } - Value::func_value(_) => { + crate::Value::func_value(_) => { // ignore func } _ => { - list.add(x.build_json(opt)); + val_array.push(x.build_json(opts)); } } } - list + JsonValue::Array(val_array) } - Value::dict_value(ref v) => { - let mut json = Json::new(); - for (key, val) in v.values.iter() { - if opt.ignore_private && (*key).starts_with(KCL_PRIVATE_VAR_PREFIX) { + crate::Value::dict_value(ref v) => { + let mut val_map = IndexMap::new(); + let mut vals = v.values.clone(); + if opts.sort_keys { + vals.sort_keys(); + } + for (key, val) in vals.iter() { + if opts.ignore_private && (*key).starts_with(KCL_PRIVATE_VAR_PREFIX) { continue; } - match *val.rc { - Value::undefined => { + match *val.rc.borrow() { + crate::Value::undefined => { continue; } - Value::none => { - if !opt.ignore_none { - json.add(Json::OBJECT { - name: key.clone(), - value: Box::new(val.build_json(opt)), - }); + crate::Value::none => { + if !opts.ignore_none { + val_map.insert(key.clone(), val.build_json(opts)); } } - Value::func_value(_) => { + crate::Value::func_value(_) => { // ignore func } _ => { - json.add(Json::OBJECT { - name: key.clone(), - value: Box::new(val.build_json(opt)), - }); + val_map.insert(key.clone(), val.build_json(opts)); } } } - json + JsonValue::Object(val_map) } - Value::schema_value(ref v) => { - let mut json = Json::new(); - for (key, val) in v.config.values.iter() { - if opt.ignore_private && (*key).starts_with(KCL_PRIVATE_VAR_PREFIX) { + crate::Value::schema_value(ref v) => { + let mut val_map = IndexMap::new(); + let mut vals = v.config.values.clone(); + if opts.sort_keys { + vals.sort_keys(); + } + for (key, val) in vals.iter() { + if opts.ignore_private && (*key).starts_with(KCL_PRIVATE_VAR_PREFIX) { continue; } - match *val.rc { - Value::undefined => { + match *val.rc.borrow() { + crate::Value::undefined => { continue; } - Value::none => { - if !opt.ignore_none { - json.add(Json::OBJECT { - name: key.clone(), - value: Box::new(val.build_json(opt)), - }); + crate::Value::none => { + if !opts.ignore_none { + val_map.insert(key.clone(), val.build_json(opts)); } } - Value::func_value(_) => { + crate::Value::func_value(_) => { // ignore func } _ => { - json.add(Json::OBJECT { - name: key.clone(), - value: Box::new(val.build_json(opt)), - }); + val_map.insert(key.clone(), val.build_json(opts)); } } } - json + JsonValue::Object(val_map) + } + crate::Value::func_value(ref v) => { + JsonValue::Number(serde_json::Number::from(v.fn_ptr)) } - Value::func_value(ref v) => Json::NUMBER(v.fn_ptr as f64), } } } @@ -216,7 +556,8 @@ mod test_value_json { use crate::*; #[test] - fn test_value_from_json() { + fn test_value_from_correct_json() { + let mut ctx = Context::new(); let cases = [ ( "{\"a\": 1}\n", @@ -233,10 +574,26 @@ mod test_value_json { ("b", &ValueRef::str("s")), ])), ), + ("\n{}", ValueRef::dict(Some(&[]))), + ]; + for (json_str, expected) in cases { + let result = ValueRef::from_json(&mut ctx, json_str).unwrap(); + assert_eq!(result, expected); + } + } + + #[test] + fn test_value_from_err_json() { + let mut ctx = Context::new(); + let cases = [ + ("{", "EOF while parsing an object at line 1 column 1"), + ("{\"a\": 1,}", "trailing comma at line 1 column 9"), + ("{\"a\": ]}", "expected value at line 1 column 7"), + ("[}", "expected value at line 1 column 2"), ]; for (json_str, expected) in cases { - let result = ValueRef::from_json(json_str); - assert_eq!(result, Some(expected)); + let result = ValueRef::from_json(&mut ctx, json_str); + assert_eq!(result.err().unwrap().to_string(), expected); } } diff --git a/kclvm/runtime/src/value/val_kind.rs b/kclvm/runtime/src/value/val_kind.rs index 73ce8fb94..3e36e83d6 100644 --- a/kclvm/runtime/src/value/val_kind.rs +++ b/kclvm/runtime/src/value/val_kind.rs @@ -1,11 +1,11 @@ -// Copyright 2021 The KCL Authors. All rights reserved. +//! Copyright The KCL Authors. All rights reserved. use crate::*; // common impl ValueRef { pub fn kind(&self) -> Kind { - match *self.rc { + match *self.rc.borrow() { Value::undefined => Kind::Undefined, Value::none => Kind::None, Value::bool_value(_) => Kind::Bool, diff --git a/kclvm/runtime/src/value/val_len.rs b/kclvm/runtime/src/value/val_len.rs index 047c3e420..602dc81a4 100644 --- a/kclvm/runtime/src/value/val_len.rs +++ b/kclvm/runtime/src/value/val_len.rs @@ -1,10 +1,10 @@ -// Copyright 2021 The KCL Authors. All rights reserved. +//! Copyright The KCL Authors. All rights reserved. use crate::*; impl ValueRef { pub fn len(&self) -> usize { - match *self.rc { + match *self.rc.borrow() { Value::str_value(ref s) => s.len(), Value::list_value(ref v) => v.values.len(), Value::dict_value(ref v) => v.values.len(), @@ -12,26 +12,33 @@ impl ValueRef { _ => panic!("object of type '{}' has no len()", self.type_str()), } } + + pub fn is_empty(&self) -> bool { + self.len() == 0_usize + } } #[cfg(test)] mod test_value_len { use crate::*; - fn assert_panic () + std::panic::UnwindSafe>(func: F) { + fn assert_panic(func: F) { let result = std::panic::catch_unwind(func); assert!(result.is_err()) } #[test] fn test_len() { + let mut ctx = Context::new(); assert_eq!(ValueRef::str("abc").len(), 3); assert_eq!( - ValueRef::str("abc").bin_aug_mul(&ValueRef::int(10)).len(), + ValueRef::str("abc") + .bin_aug_mul(&mut ctx, &ValueRef::int(10)) + .len(), 3 * 10 ); assert_eq!(ValueRef::list_n(10, &ValueRef::undefined()).len(), 10); - assert_eq!(ValueRef::list_int(&vec![1 as i64, 2, 3]).len(), 3); + assert_eq!(ValueRef::list_int(&[1_i64, 2, 3]).len(), 3); } #[test] diff --git a/kclvm/runtime/src/value/val_list.rs b/kclvm/runtime/src/value/val_list.rs index 6fc5fa23a..9b9f11238 100644 --- a/kclvm/runtime/src/value/val_list.rs +++ b/kclvm/runtime/src/value/val_list.rs @@ -1,4 +1,4 @@ -// Copyright 2021 The KCL Authors. All rights reserved. +//! Copyright The KCL Authors. All rights reserved. use crate::*; @@ -8,7 +8,7 @@ impl ValueRef { for _i in 0..size { list.values.push(val.clone()); } - Self::from(Value::list_value(list)) + Self::from(Value::list_value(Box::new(list))) } pub fn list_bool(x: &[bool]) -> Self { @@ -16,7 +16,7 @@ impl ValueRef { for x in x.iter() { list.values.push(Self::bool(*x)); } - Self::from(Value::list_value(list)) + Self::from(Value::list_value(Box::new(list))) } pub fn list_int(x: &[i64]) -> Self { @@ -24,7 +24,7 @@ impl ValueRef { for x in x.iter() { list.values.push(Self::int(*x)); } - Self::from(Value::list_value(list)) + Self::from(Value::list_value(Box::new(list))) } pub fn list_float(x: &[f64]) -> Self { @@ -32,7 +32,7 @@ impl ValueRef { for x in x.iter() { list.values.push(Self::float(*x)); } - Self::from(Value::list_value(list)) + Self::from(Value::list_value(Box::new(list))) } pub fn list_str(x: &[String]) -> Self { @@ -40,13 +40,12 @@ impl ValueRef { for x in x.iter() { list.values.push(Self::str((*x).as_ref())); } - Self::from(Value::list_value(list)) + Self::from(Value::list_value(Box::new(list))) } pub fn list_resize(&mut self, newsize: usize) { - match &*self.rc { - Value::list_value(ref list) => { - let list: &mut ListValue = get_ref_mut(list); + match &mut *self.rc.borrow_mut() { + Value::list_value(list) => { if list.values.len() > newsize { list.values.truncate(newsize); } else { @@ -60,17 +59,16 @@ impl ValueRef { } pub fn list_clear(&mut self) { - match &*self.rc { - Value::list_value(ref list) => { - let list: &mut ListValue = get_ref_mut(list); + match &mut *self.rc.borrow_mut() { + Value::list_value(list) => { list.values.clear(); } _ => panic!("Invalid list object in list_clear"), } } - pub fn list_get(&self, i: isize) -> Option<&Self> { - match &*self.rc { + pub fn list_get(&self, i: isize) -> Option { + match &*self.rc.borrow() { Value::list_value(ref list) => { let index = if i < 0 { (i + list.values.len() as isize) as usize @@ -78,7 +76,7 @@ impl ValueRef { i as usize }; if !list.values.is_empty() { - Some(&list.values.as_slice()[index]) + Some(list.values.as_slice()[index].clone()) } else { None } @@ -87,8 +85,8 @@ impl ValueRef { } } - pub fn list_get_option(&self, i: isize) -> Option<&Self> { - match &*self.rc { + pub fn list_get_option(&self, i: isize) -> Option { + match &*self.rc.borrow() { Value::list_value(ref list) => { let index = if i < 0 { (i + list.values.len() as isize) as usize @@ -96,7 +94,7 @@ impl ValueRef { i as usize }; if !list.values.is_empty() && index < list.values.len() { - Some(&list.values.as_slice()[index]) + Some(list.values.as_slice()[index].clone()) } else { None } @@ -105,10 +103,16 @@ impl ValueRef { } } + /// Set list element value `v` with the index `i`. + pub fn list_set_value(&mut self, i: &Self, v: &Self) { + let index = i.must_as_strict_int(); + let index = must_normalize_index(index as i32, self.len()); + self.list_must_set(index, v); + } + pub fn list_set(&mut self, i: usize, v: &Self) { - match &*self.rc { - Value::list_value(ref list) => { - let list: &mut ListValue = get_ref_mut(list); + match &mut *self.rc.borrow_mut() { + Value::list_value(list) => { if i < list.values.len() { list.values.as_mut_slice()[i] = v.clone(); } @@ -117,22 +121,25 @@ impl ValueRef { } } - pub fn list_pop(&mut self) -> Option<&Self> { - match &*self.rc { - Value::list_value(ref list) => { - let list: &mut ListValue = get_ref_mut(list); - let last_value = self.list_get((list.values.len() - 1) as isize); - list.values.pop(); - last_value + pub fn list_must_set(&mut self, i: usize, v: &Self) { + match &mut *self.rc.borrow_mut() { + Value::list_value(list) => { + list.values.as_mut_slice()[i] = v.clone(); } + _ => panic!("Invalid list object in list_set"), + } + } + + pub fn list_pop(&mut self) -> Option { + match &mut *self.rc.borrow_mut() { + Value::list_value(list) => list.values.pop(), _ => panic!("Invalid list object in list_pop"), } } pub fn list_pop_first(&mut self) -> Option { - match &*self.rc { - Value::list_value(ref list) => { - let list: &mut ListValue = get_ref_mut(list); + match &mut *self.rc.borrow_mut() { + Value::list_value(list) => { if !list.values.is_empty() { Some(list.values.remove(0)) } else { @@ -144,9 +151,8 @@ impl ValueRef { } pub fn list_append(&mut self, v: &Self) { - match &*self.rc { - Value::list_value(ref list) => { - let list: &mut ListValue = get_ref_mut(list); + match &mut *self.rc.borrow_mut() { + Value::list_value(list) => { list.values.push(v.clone()); } _ => panic!( @@ -158,58 +164,50 @@ impl ValueRef { } pub fn list_append_unpack(&mut self, x_or_list: &Self) { - match &*self.rc { - Value::list_value(ref list) => match &*x_or_list.rc { + match &mut*self.rc.borrow_mut() { + Value::list_value(list) => match &*x_or_list.rc.borrow() { Value::list_value(ref list_b) => { - let list: &mut ListValue = get_ref_mut(list); for x in list_b.values.iter() { list.values.push(x.clone()); } } Value::dict_value(ref dict_b) => { - let list: &mut ListValue = get_ref_mut(list); for (x, _) in dict_b.values.iter() { list.values.push(Self::str(x.as_str())); } } Value::schema_value(ref schema_b) => { - let list: &mut ListValue = get_ref_mut(list); for (x, _) in schema_b.config.values.iter() { list.values.push(Self::str(x.as_str())); } } Value::none | Value::undefined => { /*Do nothing on unpacking None/Undefined*/ } - _ => panic!("only list, dict and schema object can be used with unpack operators * and **, got {}", x_or_list.to_string()), + _ => panic!("only list, dict and schema object can be used with unpack operators * and **, got {x_or_list}"), }, _ => panic!("Invalid list object in list_append_unpack"), } } pub fn list_append_unpack_first(&mut self, x_or_list: &Self) { - match &*self.rc { - Value::list_value(ref list) => match &*x_or_list.rc { + match &mut *self.rc.borrow_mut() { + Value::list_value(list) => match &*x_or_list.rc.borrow() { Value::list_value(ref list_b) => { - let list: &mut ListValue = get_ref_mut(list); for (i, x) in list_b.values.iter().enumerate() { list.values.insert(i, x.clone()); } } Value::dict_value(ref dict_b) => { - let list: &mut ListValue = get_ref_mut(list); for (i, x) in dict_b.values.iter().enumerate() { list.values.insert(i, Self::str(x.0.as_str())); } } Value::schema_value(ref schema_b) => { - let list: &mut ListValue = get_ref_mut(list); for (i, x) in schema_b.config.values.iter().enumerate() { list.values.insert(i, Self::str(x.0.as_str())); } } Value::none | Value::undefined => { /*Do nothing on unpacking None/Undefined*/ } _ => { - let list: &mut ListValue = get_ref_mut(list); - // Panic list.values.insert(0, x_or_list.clone()); } @@ -220,7 +218,7 @@ impl ValueRef { pub fn list_count(&self, item: &Self) -> usize { let mut count: usize = 0; - match &*self.rc { + match &*self.rc.borrow() { Value::list_value(ref list) => { for v in &list.values { if v == item { @@ -230,11 +228,11 @@ impl ValueRef { } _ => panic!("Invalid list object in list_find"), } - return count; + count } pub fn list_find(&self, item: &Self) -> isize { - match &*self.rc { + match &*self.rc.borrow() { Value::list_value(ref list) => { for (i, v) in list.values.iter().enumerate() { if v == item { @@ -244,13 +242,12 @@ impl ValueRef { } _ => panic!("Invalid list object in list_find"), } - return -1; + -1 } pub fn list_insert_at(&mut self, i: usize, v: &Self) { - match &*self.rc { - Value::list_value(ref list) => { - let list: &mut ListValue = get_ref_mut(list); + match &mut *self.rc.borrow_mut() { + Value::list_value(list) => { list.values.insert(i, v.clone()); } _ => panic!("Invalid list object in list_insert_at"), @@ -258,9 +255,8 @@ impl ValueRef { } pub fn list_remove_at(&mut self, i: usize) { - match &*self.rc { - Value::list_value(ref list) => { - let list: &mut ListValue = get_ref_mut(list); + match &mut *self.rc.borrow_mut() { + Value::list_value(list) => { list.values.remove(i); } _ => panic!("Invalid list object in list_remove_at"), @@ -268,9 +264,8 @@ impl ValueRef { } pub fn list_remove(&mut self, item: &ValueRef) { - match &*self.rc { - Value::list_value(ref list) => { - let list: &mut ListValue = get_ref_mut(list); + match &mut *self.rc.borrow_mut() { + Value::list_value(list) => { let mut index: Option = None; for (i, v) in list.values.iter().enumerate() { if v == item { @@ -289,7 +284,7 @@ impl ValueRef { let start_val; let step_val; let stop_val; - match &*step.rc { + match &*step.rc.borrow() { Value::int_value(ref step) => { step_val = *step; if step_val == 0 { @@ -300,7 +295,7 @@ impl ValueRef { step_val = 1; } } - match &*start.rc { + match &*start.rc.borrow() { Value::int_value(ref start) => start_val = *start, _ => { if step_val < 0 { @@ -310,7 +305,7 @@ impl ValueRef { } } } - match &*stop.rc { + match &*stop.rc.borrow() { Value::int_value(ref stop) => stop_val = *stop, _ => { if step_val < 0 { @@ -377,7 +372,7 @@ impl ValueRef { } pub fn list_slice(&self, start: &ValueRef, stop: &ValueRef, step: &ValueRef) -> ValueRef { - match &*self.rc { + match &*self.rc.borrow() { Value::list_value(ref list) => { let (start, stop, step) = ValueRef::slice_unpack(start, stop, step); let (start, _stop, slice_len) = diff --git a/kclvm/runtime/src/value/val_logic.rs b/kclvm/runtime/src/value/val_logic.rs index 9c3f87717..bb9a2179e 100644 --- a/kclvm/runtime/src/value/val_logic.rs +++ b/kclvm/runtime/src/value/val_logic.rs @@ -1,11 +1,11 @@ -// Copyright 2021 The KCL Authors. All rights reserved. +//! Copyright The KCL Authors. All rights reserved. use crate::*; impl ValueRef { #[inline] pub fn is_truthy(&self) -> bool { - match *self.rc { + match *self.rc.borrow() { Value::undefined => false, Value::none => false, Value::bool_value(ref v) => *v, diff --git a/kclvm/runtime/src/value/val_overflow.rs b/kclvm/runtime/src/value/val_overflow.rs index bb391f122..9d584c978 100644 --- a/kclvm/runtime/src/value/val_overflow.rs +++ b/kclvm/runtime/src/value/val_overflow.rs @@ -1,4 +1,4 @@ -// Copyright 2021 The KCL Authors. All rights reserved. +//! Copyright The KCL Authors. All rights reserved. pub fn is_i32_overflow(v: i64) -> bool { v > i32::MAX as i64 || v < i32::MIN as i64 @@ -80,8 +80,8 @@ mod test_is_int_overflow { #[test] fn test_is_i32_overflow() { - assert_eq!(is_i32_overflow(2147483647), false); - assert_eq!(is_i32_overflow(2147483647 + 1), true); + assert!(!is_i32_overflow(2147483647)); + assert!(is_i32_overflow(2147483647 + 1)); assert!(is_i32_overflow2(i32::MAX as i64 + 1, i32::MAX as i64 + 2)); } diff --git a/kclvm/runtime/src/value/val_panic.rs b/kclvm/runtime/src/value/val_panic.rs index 468a57aba..541a37ccd 100644 --- a/kclvm/runtime/src/value/val_panic.rs +++ b/kclvm/runtime/src/value/val_panic.rs @@ -1,31 +1,28 @@ -// Copyright 2021 The KCL Authors. All rights reserved. +//! Copyright The KCL Authors. All rights reserved. #[macro_export] macro_rules! panic_i32_overflow { - ($v: expr) => { + ($ctx: expr,$v: expr) => { let v = $v as i128; - let ctx = crate::Context::current_context_mut(); - ctx.set_err_type(&ErrType::IntOverflow_TYPE); + $ctx.set_err_type(&RuntimeErrorType::IntOverflow); panic!("{}: A 32 bit integer overflow", v) }; } #[macro_export] macro_rules! panic_i64_overflow { - ($v: expr) => { + ($ctx: expr,$v: expr) => { let v = $v as i128; - let ctx = crate::Context::current_context_mut(); - ctx.set_err_type(&ErrType::IntOverflow_TYPE); + $ctx.set_err_type(&RuntimeErrorType::IntOverflow); panic!("{}: A 64 bit integer overflow", v) }; } #[macro_export] macro_rules! panic_f32_overflow { - ($v: expr) => { + ($ctx: expr,$v: expr) => { let v = $v as f64; - let ctx = crate::Context::current_context_mut(); - ctx.set_err_type(&ErrType::FloatOverflow_TYPE); + $ctx.set_err_type(&RuntimeErrorType::FloatOverflow); let mut s = format!("{:e}: A 32-bit floating point number overflow", v); if !s.contains("e-") { diff --git a/kclvm/runtime/src/value/val_plan.rs b/kclvm/runtime/src/value/val_plan.rs index b02f0e355..3fb041202 100644 --- a/kclvm/runtime/src/value/val_plan.rs +++ b/kclvm/runtime/src/value/val_plan.rs @@ -1,39 +1,65 @@ -// Copyright 2021 The KCL Authors. All rights reserved. - -use std::rc::Rc; +//! Copyright The KCL Authors. All rights reserved. use crate::*; pub const KCL_PRIVATE_VAR_PREFIX: &str = "_"; const LIST_DICT_TEMP_KEY: &str = "$"; +const SCHEMA_TYPE_META_ATTR: &str = "_type"; + +/// PlanOptions denotes the configuration required to execute the KCL +/// program and the JSON/YAML planning. +#[derive(PartialEq, Clone, Default, Debug)] +pub struct PlanOptions { + /// Sorts the key order in the config. + pub sort_keys: bool, + /// Emit the `_type` attribute in the schema instance. + pub include_schema_type_path: bool, + /// Whether to emit hidden attributes that start with `_` + pub show_hidden: bool, + /// Whether to emit none value in the plan process. + pub disable_none: bool, + /// Whether to emit empty list in the plan process. + pub disable_empty_list: bool, + /// Filter planned value with the path selector. + pub query_paths: Vec, + /// YAML plan separator string, default is `---`. + pub sep: Option, +} -#[allow(dead_code)] -fn filter_results(key_values: &ValueRef) -> Vec { +/// Filter list or config results with context options. +fn filter_results(ctx: &Context, key_values: &ValueRef) -> Vec { let mut results: Vec = vec![]; - if !key_values.is_config() { - return results; - } - let ctx = Context::current_context(); - // index 0 for in-line keyvalues output, index 1: for standalone keyvalues outputs - let result = ValueRef::dict(None); - results.push(result); - let key_values = key_values.as_dict_ref(); - for (key, value) in &key_values.values { - if value.is_none() && ctx.cfg.disable_none { - continue; + // Plan list value with the yaml stream format. + if key_values.is_list() { + let key_values_list = &key_values.as_list_ref().values; + for key_values in key_values_list { + if key_values.is_list_or_config() { + results.append(&mut filter_results(ctx, key_values)); + } else if key_values.is_scalar() { + results.push(key_values.clone()); + } } - if key.starts_with(KCL_PRIVATE_VAR_PREFIX) || value.is_undefined() || value.is_func() { - continue; - } else if value.is_schema() { - let (filtered, standalone) = handle_schema(value); - if !filtered.is_empty() { - if standalone { - // if the instance is marked as 'STANDALONE', treat it as a separate one and - // extend it and derived STANDALONE instances to results. - for v in filtered { - results.push(v); - } - } else { + results + } + // Plan dict value + else if key_values.is_config() { + let key_values = key_values.as_dict_ref(); + // index 0 for in-line keyvalues output, index 1: for standalone keyvalues outputs + let mut result = ValueRef::dict(None); + result.set_potential_schema_type(&key_values.potential_schema.clone().unwrap_or_default()); + results.push(result); + for (key, value) in &key_values.values { + if value.is_none() && ctx.plan_opts.disable_none { + continue; + } + if key.starts_with(KCL_PRIVATE_VAR_PREFIX) && !ctx.plan_opts.show_hidden { + continue; + } + if value.is_undefined() || value.is_func() { + continue; + } else if value.is_schema() || value.has_potential_schema_type() { + let filtered = handle_schema(ctx, value); + if !filtered.is_empty() { // else put it as the value of the key of results let result = results.get_mut(0).unwrap(); result.dict_update_key_value(key.as_str(), filtered[0].clone()); @@ -44,213 +70,377 @@ fn filter_results(key_values: &ValueRef) -> Vec { } } } - } - } else if value.is_dict() { - let filtered = filter_results(value); - let result = results.get_mut(0).unwrap(); - result.dict_update_key_value(key.as_str(), filtered[0].clone()); - // if the value has derived 'STANDALONE' instances, extend them - if filtered.len() > 1 { - for v in &filtered[1..] { - results.push(v.clone()); + } else if value.is_dict() { + let filtered = filter_results(ctx, value); + if !results.is_empty() { + let result = results.get_mut(0).unwrap(); + if !filtered.is_empty() { + result.dict_update_key_value(key.as_str(), filtered[0].clone()); + } + // if the value has derived 'STANDALONE' instances, extend them + if filtered.len() > 1 { + for v in &filtered[1..] { + results.push(v.clone()); + } + } } - } - } else if value.is_list() { - let mut filtered_list: Vec = vec![]; - let mut standalone_list: Vec = vec![]; - let mut ignore_schema_count = 0; - let list_value = value.as_list_ref(); - for v in &list_value.values { - if v.is_schema() { - let (filtered, standalone) = handle_schema(value); - if filtered.is_empty() { - ignore_schema_count += 1; - continue; - } else if standalone { - for v in filtered { - standalone_list.push(v); + } else if value.is_list() { + let mut filtered_list: Vec = vec![]; + let mut ignore_schema_count = 0; + let list_value = value.as_list_ref(); + for v in &list_value.values { + if v.is_schema() || v.has_potential_schema_type() { + let filtered = handle_schema(ctx, v); + if filtered.is_empty() { + ignore_schema_count += 1; + continue; + } else { + for v in filtered { + filtered_list.push(v); + } } - } else { + } else if v.is_dict() { + let filtered = filter_results(ctx, v); for v in filtered { filtered_list.push(v); } - } - } else if v.is_dict() { - let filtered = filter_results(v); - for v in filtered { - filtered_list.push(v); - } - } else if v.is_none() && ctx.cfg.disable_none { - continue; - } else if !v.is_undefined() { - let list_dict = ValueRef::dict(Some(&[(LIST_DICT_TEMP_KEY, v)])); - let filtered = filter_results(&list_dict); - if !filtered.is_empty() { - if let Some(v) = filtered[0].get_by_key(key) { - filtered_list.push(v.clone()); + } else if v.is_none() && ctx.plan_opts.disable_none { + continue; + } else if !v.is_undefined() { + let list_dict = ValueRef::dict(Some(&[(LIST_DICT_TEMP_KEY, v)])); + let filtered = filter_results(ctx, &list_dict); + if !filtered.is_empty() { + if let Some(v) = filtered[0].get_by_key(LIST_DICT_TEMP_KEY) { + filtered_list.push(v.clone()); + } } - } - if filtered.len() > 1 { - for v in &filtered[1..] { - results.push(v.clone()); + if filtered.len() > 1 { + for v in &filtered[1..] { + results.push(v.clone()); + } } } } - } - let schema_in_list_count = ignore_schema_count + standalone_list.len(); - let value = &value.as_list_ref().values; - if schema_in_list_count < value.len() { + let schema_in_list_count = ignore_schema_count; + let value = &value.as_list_ref().values; + // Plan empty list to values. + if value.is_empty() && !ctx.plan_opts.disable_empty_list { + let result = results.get_mut(0).unwrap(); + result.dict_update_key_value(key.as_str(), ValueRef::list(None)); + } + if schema_in_list_count < value.len() { + let result = results.get_mut(0).unwrap(); + let filtered_list: Vec<&ValueRef> = filtered_list.iter().collect(); + let filtered_list = filtered_list.as_slice(); + let filtered_list = ValueRef::list(Some(filtered_list)); + result.dict_update_key_value(key.as_str(), filtered_list); + } + } else { let result = results.get_mut(0).unwrap(); - let filtered_list: Vec<&ValueRef> = filtered_list.iter().collect(); - let filtered_list = filtered_list.as_slice(); - let filtered_list = ValueRef::list(Some(filtered_list)); - result.dict_update_key_value(key.as_str(), filtered_list); - } - for v in standalone_list { - results.push(v); + result.dict_update_key_value(key.as_str(), value.clone()); } - } else { - let result = results.get_mut(0).unwrap(); - result.dict_update_key_value(key.as_str(), value.clone()); } + results.iter().enumerate().map(|v| v.1).cloned().collect() + } else { + results } - results } -#[allow(dead_code)] -fn handle_schema(value: &ValueRef) -> (Vec, bool) { - let filtered = filter_results(value); +fn handle_schema(ctx: &Context, value: &ValueRef) -> Vec { + let mut filtered = filter_results(ctx, value); if filtered.is_empty() { - return (filtered, false); + return filtered; } - let settings = SCHEMA_SETTINGS_ATTR_NAME; - let output_type = SETTINGS_OUTPUT_KEY; - let path = format!("{}.{}", settings, output_type); - let output_type_option = value.get_by_path(&path); - if let Some(output_type) = output_type_option { - if output_type.str_equal(SETTINGS_OUTPUT_IGNORE) { - if filtered.is_empty() { - return (filtered, false); - } else { - return (filtered[1..].to_vec(), true); + // Deal schema type meta attribute and add the attribute with the type string value + // into the planned object. + if ctx.plan_opts.include_schema_type_path { + if let Some(v) = filtered.get_mut(0) { + if v.is_config() { + v.dict_update_key_value( + SCHEMA_TYPE_META_ATTR, + ValueRef::str(&value_type_path(value, true)), + ); } } } - let mut standalone = false; - if let Some(output_type) = output_type_option { - if output_type.str_equal(SETTINGS_OUTPUT_STANDALONE) { - standalone = true; + filtered +} + +/// Returns the type path of the runtime value `v`. +pub(crate) fn value_type_path(v: &ValueRef, full_name: bool) -> String { + if v.is_schema() { + type_of(v, full_name) + } else { + match v.get_potential_schema_type() { + Some(ty_str) => { + let ty = if full_name { + match ty_str.strip_prefix('@') { + Some(ty_str) => ty_str.to_string(), + None => ty_str.to_string(), + } + } else { + let parts: Vec<&str> = ty_str.rsplit('.').collect(); + match parts.first() { + Some(v) => v.to_string(), + None => type_of(v, full_name), + } + }; + match ty.strip_prefix(&format!("{MAIN_PKG_PATH}.")) { + Some(ty) => ty.to_string(), + None => ty, + } + } + None => type_of(v, full_name), } } - (filtered, standalone) +} + +/// Returns the type path of the runtime value `v`. +#[inline] +pub fn type_of(v: &ValueRef, full_name: bool) -> String { + builtin::type_of(v, &ValueRef::bool(full_name)).as_str() } impl ValueRef { - fn is_planned_empty(&self) -> bool { - self.is_dict() && !self.is_truthy() + /// Plan the value to JSON and YAML strings. + pub fn plan(&self, ctx: &Context) -> (String, String) { + // Encoding options + let json_opts = JsonEncodeOptions { + sort_keys: ctx.plan_opts.sort_keys, + ..Default::default() + }; + let yaml_opts = YamlEncodeOptions { + sort_keys: ctx.plan_opts.sort_keys, + ..Default::default() + }; + // Filter values with query paths + let value = if ctx.plan_opts.query_paths.is_empty() { + self.clone() + } else { + self.filter_by_path(&ctx.plan_opts.query_paths) + .unwrap_or_else(|e| panic!("{e}")) + }; + if value.is_list_or_config() { + let results = filter_results(ctx, &value); + let sep = ctx + .plan_opts + .sep + .clone() + .unwrap_or_else(|| "---".to_string()); + // Plan YAML result + let yaml_result = results + .iter() + .map(|r| { + r.to_yaml_string_with_options(&yaml_opts) + .strip_suffix('\n') + .unwrap() + .to_string() + }) + .collect::>() + .join(&format!("\n{}\n", sep)); + // Plan JSON result + let json_result = results + .iter() + .map(|r| r.to_json_string_with_options(&json_opts)) + .collect::>() + .join(JSON_STREAM_SEP); + (json_result, yaml_result) + } else { + ( + value.to_json_string_with_options(&json_opts), + value.to_yaml_string_with_options(&yaml_opts), + ) + } } - pub fn plan_to_json_string(&self) -> String { - let result = self.filter_results(); - if result.is_planned_empty() { - return "".to_string(); + /// Filter values using path selectors. + pub fn filter_by_path(&self, path_selector: &[String]) -> Result { + if self.is_config() && !path_selector.is_empty() { + if path_selector.len() == 1 { + let path = &path_selector[0]; + match self.get_by_path(path) { + Some(value) => Ok(value), + None => Err(format!( + "invalid path select operand {path}, value not found" + )), + } + } else { + let mut values = ValueRef::list(None); + for path in path_selector { + let value = match self.get_by_path(path) { + Some(value) => value, + None => { + return Err(format!( + "invalid path select operand {path}, value not found" + )) + } + }; + values.list_append(&value); + } + Ok(values) + } + } else { + Ok(self.clone()) } - result.to_json_string() } +} + +#[cfg(test)] +mod test_value_plan { + use crate::{schema_runtime_type, val_plan::PlanOptions, Context, ValueRef, MAIN_PKG_PATH}; - pub fn plan_to_yaml_string(&self) -> String { - let result = self.filter_results(); - result.to_yaml_string() + use super::filter_results; + + const TEST_SCHEMA_NAME: &str = "Data"; + + fn get_test_schema_value() -> ValueRef { + let mut schema = ValueRef::dict(None).dict_to_schema( + TEST_SCHEMA_NAME, + MAIN_PKG_PATH, + &[], + &ValueRef::dict(None), + &ValueRef::dict(None), + None, + None, + ); + schema.set_potential_schema_type(&schema_runtime_type(TEST_SCHEMA_NAME, MAIN_PKG_PATH)); + schema } - fn filter_results(&self) -> ValueRef { - let ctx = Context::current_context(); - match &*self.rc { - Value::undefined => ValueRef { - rc: Rc::new(Value::undefined), - }, - Value::none => ValueRef { - rc: Rc::new(Value::none), - }, - Value::func_value(ref v) => ValueRef { - rc: Rc::new(Value::func_value(v.clone())), - }, - Value::bool_value(ref v) => ValueRef { - rc: Rc::new(Value::bool_value(*v)), - }, - Value::int_value(ref v) => ValueRef { - rc: Rc::new(Value::int_value(*v)), - }, - Value::float_value(ref v) => ValueRef { - rc: Rc::new(Value::float_value(*v)), - }, - Value::unit_value(ref v, _, _) => ValueRef { - rc: Rc::new(Value::float_value(*v)), - }, - Value::str_value(ref v) => ValueRef { - rc: Rc::new(Value::str_value(v.to_string())), - }, - Value::list_value(ref v) => { - let mut list = ValueRef { - rc: Rc::new(Value::list_value(ListValue { values: vec![] })), - }; - for x in v.values.iter() { - if !(x.is_undefined() || x.is_func() || ctx.cfg.disable_none && x.is_none()) { - list.list_append(&x.filter_results()); - } - } - list - } - Value::dict_value(ref v) => { - let mut dict = ValueRef { - rc: Rc::new(Value::dict_value(DictValue { - values: IndexMap::default(), - ops: IndexMap::default(), - insert_indexs: IndexMap::default(), - attr_map: IndexMap::default(), - })), - }; - for (key, val) in v.values.iter() { - if !(val.is_undefined() - || val.is_func() - || ctx.cfg.disable_none && val.is_none()) - { - dict.dict_insert( - key, - &val.filter_results(), - ConfigEntryOperationKind::Override, - 0, - ); - } - } - dict - } - Value::schema_value(ref v) => { - let mut schema = ValueRef { - rc: Rc::new(Value::schema_value(SchemaValue { - name: v.name.clone(), - pkgpath: v.pkgpath.clone(), - config: Rc::new(DictValue { - values: IndexMap::default(), - ops: IndexMap::default(), - insert_indexs: IndexMap::default(), - attr_map: IndexMap::default(), - }), - config_keys: vec![], - })), - }; - for (key, val) in v.config.values.iter() { - if !val.is_undefined() && !val.is_func() { - schema.dict_insert( - key, - &val.filter_results(), - ConfigEntryOperationKind::Union, - 0, - ); - } - } - schema - } + fn get_test_schema_value_with_pkg() -> ValueRef { + let mut schema = ValueRef::dict(None).dict_to_schema( + TEST_SCHEMA_NAME, + "pkg", + &[], + &ValueRef::dict(None), + &ValueRef::dict(None), + None, + None, + ); + schema.set_potential_schema_type(&schema_runtime_type(TEST_SCHEMA_NAME, MAIN_PKG_PATH)); + schema + } + + #[test] + fn test_filter_results() { + let ctx = Context::new(); + let dict1 = ValueRef::dict_int(&[("k1", 1)]); + let dict2 = ValueRef::dict_int(&[("k2", 2)]); + let dict3 = ValueRef::dict_int(&[("k3", 3)]); + let dict_list = vec![&dict1, &dict2, &dict3]; + let list_data = ValueRef::list(Some(&dict_list)); + assert_eq!( + filter_results(&ctx, &list_data), + dict_list + .iter() + .map(|v| v.deep_copy()) + .collect::>() + ); + for dict in dict_list { + assert_eq!(filter_results(&ctx, dict), vec![dict.deep_copy()]); } } + + #[test] + fn test_filter_by_path() { + let dict = ValueRef::dict_int(&[("k1", 1)]); + assert_eq!( + dict.filter_by_path(&[]).unwrap(), + ValueRef::dict_int(&[("k1", 1)]), + ); + assert_eq!( + dict.filter_by_path(&["k1".to_string()]).unwrap(), + ValueRef::int(1) + ); + assert_eq!( + dict.filter_by_path(&["k1".to_string(), "k1".to_string()]) + .unwrap(), + ValueRef::list_int(&[1, 1]) + ); + assert_eq!( + dict.filter_by_path(&["err_path".to_string()]) + .err() + .unwrap(), + "invalid path select operand err_path, value not found" + ); + assert_eq!( + dict.filter_by_path(&["err_path.to".to_string()]) + .err() + .unwrap(), + "invalid path select operand err_path.to, value not found" + ); + } + + #[test] + fn test_value_plan_with_options() { + let mut ctx = Context::new(); + ctx.plan_opts = PlanOptions::default(); + let mut config = ValueRef::dict(None); + config.dict_update_key_value("data", get_test_schema_value()); + config.dict_update_key_value("_hidden", ValueRef::int(1)); + config.dict_update_key_value("vec", ValueRef::list(None)); + config.dict_update_key_value("empty", ValueRef::none()); + let (json_string, yaml_string) = config.plan(&ctx); + assert_eq!(json_string, "{\"data\": {}, \"vec\": [], \"empty\": null}"); + assert_eq!(yaml_string, "data: {}\nvec: []\nempty: null"); + + ctx.plan_opts.include_schema_type_path = true; + let (json_string, yaml_string) = config.plan(&ctx); + assert_eq!( + json_string, + "{\"data\": {\"_type\": \"Data\"}, \"vec\": [], \"empty\": null}" + ); + assert_eq!(yaml_string, "data:\n _type: Data\nvec: []\nempty: null"); + + ctx.plan_opts.show_hidden = true; + let (json_string, yaml_string) = config.plan(&ctx); + assert_eq!( + json_string, + "{\"data\": {\"_type\": \"Data\"}, \"_hidden\": 1, \"vec\": [], \"empty\": null}" + ); + assert_eq!( + yaml_string, + "data:\n _type: Data\n_hidden: 1\nvec: []\nempty: null" + ); + + ctx.plan_opts.sort_keys = true; + let (json_string, yaml_string) = config.plan(&ctx); + assert_eq!( + json_string, + "{\"_hidden\": 1, \"data\": {\"_type\": \"Data\"}, \"empty\": null, \"vec\": []}" + ); + assert_eq!( + yaml_string, + "_hidden: 1\ndata:\n _type: Data\nempty: null\nvec: []" + ); + + ctx.plan_opts.disable_none = true; + let (json_string, yaml_string) = config.plan(&ctx); + assert_eq!( + json_string, + "{\"_hidden\": 1, \"data\": {\"_type\": \"Data\"}, \"vec\": []}" + ); + assert_eq!(yaml_string, "_hidden: 1\ndata:\n _type: Data\nvec: []"); + + ctx.plan_opts.disable_empty_list = true; + let (json_string, yaml_string) = config.plan(&ctx); + assert_eq!( + json_string, + "{\"_hidden\": 1, \"data\": {\"_type\": \"Data\"}}" + ); + assert_eq!(yaml_string, "_hidden: 1\ndata:\n _type: Data"); + + config.dict_update_key_value("data_with_pkg", get_test_schema_value_with_pkg()); + let (json_string, yaml_string) = config.plan(&ctx); + assert_eq!(json_string, "{\"_hidden\": 1, \"data\": {\"_type\": \"Data\"}, \"data_with_pkg\": {\"_type\": \"pkg.Data\"}}"); + assert_eq!( + yaml_string, + "_hidden: 1\ndata:\n _type: Data\ndata_with_pkg:\n _type: pkg.Data" + ); + + ctx.plan_opts.query_paths = vec!["data".to_string()]; + let (json_string, yaml_string) = config.plan(&ctx); + assert_eq!(json_string, "{}"); + assert_eq!(yaml_string, "{}"); + } } diff --git a/kclvm/runtime/src/value/val_schema.rs b/kclvm/runtime/src/value/val_schema.rs index c1aec1492..6a6b337e0 100644 --- a/kclvm/runtime/src/value/val_schema.rs +++ b/kclvm/runtime/src/value/val_schema.rs @@ -1,15 +1,11 @@ -// Copyright 2021 The KCL Authors. All rights reserved. +//! Copyright The KCL Authors. All rights reserved. -use std::rc::Rc; +use indexmap::IndexSet; use crate::*; -pub const SETTINGS_OUTPUT_KEY: &str = "output_type"; -pub const SETTINGS_SCHEMA_TYPE_KEY: &str = "__schema_type__"; -pub const SETTINGS_OUTPUT_STANDALONE: &str = "STANDALONE"; -pub const SETTINGS_OUTPUT_INLINE: &str = "INLINE"; -pub const SETTINGS_OUTPUT_IGNORE: &str = "IGNORE"; -pub const SCHEMA_SETTINGS_ATTR_NAME: &str = "__settings__"; +use self::walker::walk_value_mut; + pub const CONFIG_META_FILENAME: &str = "$filename"; pub const CONFIG_META_LINE: &str = "$lineno"; pub const CONFIG_META_COLUMN: &str = "$columnno"; @@ -21,10 +17,12 @@ pub const MAIN_PKG_PATH: &str = "__main__"; pub const PKG_PATH_PREFIX: char = '@'; pub const CAL_MAP_RUNTIME_TYPE: &str = "cal_map_runtime_type"; pub const CAL_MAP_META_LINE: &str = "cal_map_meta_line"; +pub const CAL_MAP_INDEX_SIGNATURE: &str = "$cal_map_index_signature"; -/// Get the schema runtime type use the schema name and pkgpath +/// Get the schema runtime type use the schema name and pkgpath. +#[inline] pub fn schema_runtime_type(name: &str, pkgpath: &str) -> String { - format!("{}.{}", pkgpath, name) + format!("{pkgpath}.{name}") } /// Construct a schema config meta dict using filename, line and column @@ -37,15 +35,56 @@ pub fn schema_config_meta(filename: &str, line: u64, column: u64) -> ValueRef { ])) } +pub fn schema_assert(ctx: &mut Context, value: &ValueRef, msg: &str, config_meta: &ValueRef) { + if !value.is_truthy() { + ctx.set_err_type(&RuntimeErrorType::SchemaCheckFailure); + if let Some(config_meta_file) = config_meta.get_by_key(CONFIG_META_FILENAME) { + let config_meta_line = config_meta.get_by_key(CONFIG_META_LINE).unwrap(); + let config_meta_column = config_meta.get_by_key(CONFIG_META_COLUMN).unwrap(); + ctx.set_kcl_config_meta_location_info( + Some("Instance check failed"), + Some(config_meta_file.as_str().as_str()), + Some(config_meta_line.as_int() as i32), + Some(config_meta_column.as_int() as i32), + ); + } + + let arg_msg = format!( + "Check failed on the condition{}", + if msg.is_empty() { + "".to_string() + } else { + format!(": {msg}") + } + ); + ctx.set_kcl_location_info(Some(arg_msg.as_str()), None, None, None); + + panic!("{}", msg); + } +} + impl ValueRef { - pub fn dict_to_schema(&self, name: &str, pkgpath: &str, config_keys: &[String]) -> Self { + pub fn dict_to_schema( + &self, + name: &str, + pkgpath: &str, + config_keys: &[String], + config_meta: &ValueRef, + optional_mapping: &ValueRef, + args: Option, + kwargs: Option, + ) -> Self { if self.is_dict() { - Self::from(Value::schema_value(SchemaValue { + Self::from(Value::schema_value(Box::new(SchemaValue { name: name.to_string(), pkgpath: pkgpath.to_string(), - config: Rc::new(self.as_dict_ref().clone()), + config: Box::new(self.as_dict_ref().clone()), config_keys: config_keys.to_owned(), - })) + config_meta: config_meta.clone(), + optional_mapping: optional_mapping.clone(), + args: args.unwrap_or(ValueRef::list(None)), + kwargs: kwargs.unwrap_or(ValueRef::dict(None)), + }))) } else if self.is_schema() { self.clone() } else { @@ -54,44 +93,90 @@ impl ValueRef { } pub fn schema_to_dict(&self) -> Self { - match &*self.rc { + match &*self.rc.borrow() { Value::schema_value(ref schema) => { - Self::from(Value::dict_value(schema.config.as_ref().clone())) + Self::from(Value::dict_value(Box::new(schema.config.as_ref().clone()))) } Value::dict_value(_) => self.clone(), _ => panic!("invalid schema object to dict"), } } - pub fn schema_check_attr_optional( - &self, - optional_mapping: &ValueRef, - schema_name: &str, - config_meta: &ValueRef, - ) { - let attr_map = match &*self.rc { - Value::schema_value(ref schema) => { - let schema: &mut SchemaValue = get_ref_mut(schema); - let schema = get_ref_mut(schema); - &schema.config.values - } - Value::dict_value(ref schema) => { - let schema: &mut DictValue = get_ref_mut(schema); - &schema.values + /// Get the schema attribute optional mapping. + #[inline] + pub fn schema_name(&self) -> String { + if let Value::schema_value(schema) = &*self.rc.borrow() { + schema.name.clone() + } else { + "".to_string() + } + } + + /// Get the schema name + #[inline] + pub fn schema_optional_mapping(&self) -> ValueRef { + if let Value::schema_value(schema) = &*self.rc.borrow() { + schema.optional_mapping.clone() + } else { + ValueRef::dict(None) + } + } + + /// Get the schema config meta information including filename, line and column. + #[inline] + pub fn schema_config_meta(&self) -> ValueRef { + if let Value::schema_value(schema) = &*self.rc.borrow() { + schema.config_meta.clone() + } else { + ValueRef::dict(None) + } + } + + /// Set of keys not in the schema. + pub fn keys_not_in_schema(&self, ty: &SchemaType, cal_order: &ValueRef) -> IndexSet { + let mut keys = IndexSet::new(); + if self.is_config() { + let config = self.as_dict_ref(); + for (key, _) in &config.values { + let no_such_attr = ty.attrs.get(key).is_none() + && cal_order.dict_get_value(key).is_none() + && !key.starts_with('_'); + let has_index_signature = ty.has_index_signature + || cal_order.dict_get_value(CAL_MAP_INDEX_SIGNATURE).is_some(); + if !has_index_signature && no_such_attr { + keys.insert(key.to_string()); + } } - _ => panic!("Invalid schema/dict value, got {}", self.type_str()), + } + keys + } + + /// Check whether the config fits into the schema type. + #[inline] + pub fn is_fit_schema(&self, ty: &SchemaType, cal_order: &ValueRef) -> bool { + self.keys_not_in_schema(ty, cal_order).is_empty() + } + + /// Check schema optional attributes. + pub fn schema_check_attr_optional(&self, ctx: &mut Context, recursive: bool) { + let binding = self.rc.borrow(); + let attr_map = match &*binding { + Value::schema_value(schema) => &schema.config.values, + Value::dict_value(schema) => &schema.values, + _ => panic!("invalid schema or dict value, got {}", self.type_str()), }; - match &*optional_mapping.rc { - Value::dict_value(ref optional_mapping) => { - let optional_mapping = get_ref_mut(optional_mapping); + let optional_mapping = self.schema_optional_mapping(); + let optional_mapping_ref = optional_mapping.rc.borrow(); + let config_meta = self.schema_config_meta(); + match &*optional_mapping_ref { + Value::dict_value(optional_mapping) => { for (attr, is_optional) in &optional_mapping.values { let is_required = !is_optional.as_bool(); let undefined = ValueRef::undefined(); - let value = attr_map.get(attr).or(Some(&undefined)).unwrap(); + let value = attr_map.get(attr).unwrap_or(&undefined); if is_required && value.is_none_or_undefined() { let filename = config_meta.get_by_key(CONFIG_META_FILENAME); let line = config_meta.get_by_key(CONFIG_META_LINE); - let ctx = Context::current_context_mut(); if let Some(filename) = filename { ctx.set_kcl_filename(&filename.as_str()); } @@ -100,10 +185,22 @@ impl ValueRef { } panic!( "attribute '{}' of {} is required and can't be None or Undefined", - attr, schema_name + attr, + self.schema_name() ); } } + // Recursive check schema values for every attributes. + if recursive { + for value in attr_map.values() { + // For composite type structures, we recursively check the schema within them. + walk_value_mut(value, &mut |value: &ValueRef| { + if value.is_schema() { + value.schema_check_attr_optional(ctx, true); + } + }) + } + } } _ => panic!( "Invalid optional mapping, got {}", @@ -112,26 +209,46 @@ impl ValueRef { } } - pub fn schema_default_settings(&mut self, config: &ValueRef, runtime_type: &str) { - let settings = self.dict_get_value(SCHEMA_SETTINGS_ATTR_NAME); - if settings.is_none() || (settings.is_some() && !settings.unwrap().is_config()) { - let mut default_settings = ValueRef::dict(None); - default_settings - .dict_update_key_value(SETTINGS_OUTPUT_KEY, ValueRef::str(SETTINGS_OUTPUT_INLINE)); - default_settings - .dict_update_key_value(SETTINGS_SCHEMA_TYPE_KEY, ValueRef::str(runtime_type)); - self.dict_update_key_value(SCHEMA_SETTINGS_ATTR_NAME, default_settings); - } else { - let settings = get_ref_mut(settings.unwrap()); - settings.dict_update_key_value(SETTINGS_SCHEMA_TYPE_KEY, ValueRef::str(runtime_type)); + /// Set the schema instance value with arguments and keyword arguments. + pub fn set_schema_args(&mut self, args: &ValueRef, kwargs: &ValueRef) { + if let Value::schema_value(ref mut schema) = &mut *self.rc.borrow_mut() { + schema.args = args.clone(); + schema.kwargs = kwargs.clone(); + } + } + + pub fn get_potential_schema_type(&self) -> Option { + match &*self.rc.borrow() { + Value::dict_value(ref dict) => dict.potential_schema.clone(), + Value::schema_value(ref schema) => schema.config.potential_schema.clone(), + _ => None, + } + } + + pub fn set_potential_schema_type(&mut self, runtime_type: &str) { + if !runtime_type.is_empty() { + match &mut *self.rc.borrow_mut() { + Value::dict_value(ref mut dict) => { + dict.potential_schema = Some(runtime_type.to_string()) + } + Value::schema_value(ref mut schema) => { + schema.config.potential_schema = Some(runtime_type.to_string()) + } + _ => {} + } } - if let Some(v) = config.dict_get_value(SCHEMA_SETTINGS_ATTR_NAME) { - self.dict_update_key_value(SCHEMA_SETTINGS_ATTR_NAME, v.clone()); + } + + pub fn has_potential_schema_type(&self) -> bool { + match &*self.rc.borrow() { + Value::dict_value(ref dict) => dict.potential_schema.is_some(), + Value::schema_value(ref schema) => schema.config.potential_schema.is_some(), + _ => false, } } pub fn attr_str(&self) -> String { - match &*self.rc { + match &*self.rc.borrow() { Value::int_value(v) => v.to_string(), Value::float_value(v) => v.to_string(), Value::str_value(v) => v.clone(), @@ -140,49 +257,50 @@ impl ValueRef { } pub fn update_attr_map(&mut self, name: &str, type_str: &str) { - match &*self.rc { + match &mut *self.rc.borrow_mut() { Value::dict_value(dict) => { - let attr_map = get_ref_mut(&dict.attr_map); - attr_map.insert(name.to_string(), type_str.to_string()); + dict.attr_map.insert(name.to_string(), type_str.to_string()); } Value::schema_value(schema) => { - let attr_map = get_ref_mut(&schema.config.attr_map); - attr_map.insert(name.to_string(), type_str.to_string()); + schema + .config + .attr_map + .insert(name.to_string(), type_str.to_string()); } _ => panic!("invalid object '{}' in update_attr_map", self.type_str()), } } - pub fn attr_map_get(&mut self, name: &str) -> Option<&String> { - match &*self.rc { - Value::dict_value(dict) => { - let attr_map = get_ref_mut(&dict.attr_map); - attr_map.get(name) - } - Value::schema_value(schema) => { - let attr_map = get_ref_mut(&schema.config.attr_map); - attr_map.get(name) - } + pub fn attr_map_get(&self, name: &str) -> Option { + match &*self.rc.borrow() { + Value::dict_value(dict) => dict.attr_map.get(name).cloned(), + Value::schema_value(schema) => schema.config.attr_map.get(name).cloned(), _ => panic!("invalid object '{}' in attr_map_get", self.type_str()), } } pub fn schema_update_with_schema(&mut self, value: &ValueRef) { - if let (Value::schema_value(schema), Value::schema_value(value)) = (&*self.rc, &*value.rc) { - let values = get_ref_mut(&schema.config.values); - let ops = get_ref_mut(&schema.config.ops); - let insert_indexs = get_ref_mut(&schema.config.insert_indexs); + if let (Value::schema_value(schema), Value::schema_value(value)) = + (&mut *self.rc.borrow_mut(), &*value.rc.borrow()) + { + let values = &mut schema.config.values; + let ops = &mut schema.config.ops; + let insert_indexs = &mut schema.config.insert_indexs; + // Reserve config keys for the schema update process. Issue: #785 + schema.config_keys = value.config_keys.clone(); + schema.config.potential_schema = value.config.potential_schema.clone(); for (k, v) in &value.config.values { let op = value .config .ops .get(k) - .or(Some(&ConfigEntryOperationKind::Union)) - .unwrap(); - let index = value.config.insert_indexs.get(k).or(Some(&-1)).unwrap(); + .unwrap_or(&ConfigEntryOperationKind::Union); + let index = value.config.insert_indexs.get(k); values.insert(k.clone(), v.clone()); ops.insert(k.clone(), op.clone()); - insert_indexs.insert(k.clone(), *index); + if let Some(index) = index { + insert_indexs.insert(k.clone(), *index); + } } } } @@ -195,12 +313,16 @@ mod test_value_schema { const TEST_SCHEMA_NAME: &str = "Data"; fn get_test_schema_value() -> ValueRef { - let config = ValueRef::dict(None); - let mut schema = ValueRef::dict(None).dict_to_schema(TEST_SCHEMA_NAME, MAIN_PKG_PATH, &[]); - schema.schema_default_settings( - &config, - &schema_runtime_type(TEST_SCHEMA_NAME, MAIN_PKG_PATH), + let mut schema = ValueRef::dict(None).dict_to_schema( + TEST_SCHEMA_NAME, + MAIN_PKG_PATH, + &[], + &ValueRef::dict(None), + &ValueRef::dict(None), + None, + None, ); + schema.set_potential_schema_type(&schema_runtime_type(TEST_SCHEMA_NAME, MAIN_PKG_PATH)); schema } @@ -208,51 +330,71 @@ mod test_value_schema { fn test_dict_schema_convention() { let dict = ValueRef::dict(None); let dict = dict.schema_to_dict(); - assert_eq!(dict.is_dict(), true); - let schema = dict.dict_to_schema(TEST_SCHEMA_NAME, MAIN_PKG_PATH, &[]); - assert_eq!(schema.is_schema(), true); - let schema = schema.dict_to_schema(TEST_SCHEMA_NAME, MAIN_PKG_PATH, &[]); - assert_eq!(schema.is_schema(), true); + assert!(dict.is_dict()); + let schema = dict.dict_to_schema( + TEST_SCHEMA_NAME, + MAIN_PKG_PATH, + &[], + &ValueRef::dict(None), + &ValueRef::dict(None), + None, + None, + ); + assert!(schema.is_schema()); + let schema = schema.dict_to_schema( + TEST_SCHEMA_NAME, + MAIN_PKG_PATH, + &[], + &ValueRef::dict(None), + &ValueRef::dict(None), + None, + None, + ); + assert!(schema.is_schema()); let dict = schema.schema_to_dict(); - assert_eq!(dict.is_dict(), true); + assert!(dict.is_dict()); } #[test] fn test_schema_check_attr_optional() { + let mut ctx = Context::new(); let dict = ValueRef::dict_str(&[("key", "value")]); - let schema = dict.dict_to_schema(TEST_SCHEMA_NAME, MAIN_PKG_PATH, &[]); let config_meta = ValueRef::dict(None); let optional_mapping = ValueRef::dict_bool(&[("key", true)]); - schema.schema_check_attr_optional(&optional_mapping, TEST_SCHEMA_NAME, &config_meta); - let optional_mapping = ValueRef::dict_bool(&[("key", false)]); - schema.schema_check_attr_optional(&optional_mapping, TEST_SCHEMA_NAME, &config_meta); - let optional_mapping = ValueRef::dict_bool(&[("another_key", true)]); - schema.schema_check_attr_optional(&optional_mapping, TEST_SCHEMA_NAME, &config_meta); + let schema = dict.dict_to_schema( + TEST_SCHEMA_NAME, + MAIN_PKG_PATH, + &[], + &config_meta, + &optional_mapping, + None, + None, + ); + schema.schema_check_attr_optional(&mut ctx, true); + schema.schema_check_attr_optional(&mut ctx, false); } #[test] fn test_schema_check_attr_optional_invalid() { let err = std::panic::catch_unwind(|| { + let mut ctx = Context::new(); let dict = ValueRef::dict_str(&[("key", "value")]); - let schema = dict.dict_to_schema(TEST_SCHEMA_NAME, MAIN_PKG_PATH, &[]); let config_meta = ValueRef::dict(None); let optional_mapping = ValueRef::dict_bool(&[("another_key", false)]); - schema.schema_check_attr_optional(&optional_mapping, TEST_SCHEMA_NAME, &config_meta); + let schema = dict.dict_to_schema( + TEST_SCHEMA_NAME, + MAIN_PKG_PATH, + &[], + &config_meta, + &optional_mapping, + None, + None, + ); + schema.schema_check_attr_optional(&mut ctx, true); }); assert!(err.is_err()) } - #[test] - fn test_schema_default_settings() { - let schema = get_test_schema_value(); - let schema_settings = schema.get_by_key(SCHEMA_SETTINGS_ATTR_NAME).unwrap(); - let output_type = schema_settings - .get_by_key(SETTINGS_OUTPUT_KEY) - .unwrap() - .as_str(); - assert_eq!(output_type, SETTINGS_OUTPUT_INLINE); - } - #[test] fn test_schema_attr_map() { let mut schema = get_test_schema_value(); @@ -276,7 +418,7 @@ mod test_value_schema { key, &ValueRef::str(val), &ConfigEntryOperationKind::Union, - &-1, + None, ); } assert_ne!(schema1, schema2); diff --git a/kclvm/runtime/src/value/val_str.rs b/kclvm/runtime/src/value/val_str.rs index 517ef5cb8..32f104cc4 100644 --- a/kclvm/runtime/src/value/val_str.rs +++ b/kclvm/runtime/src/value/val_str.rs @@ -1,4 +1,4 @@ -// Copyright 2021 The KCL Authors. All rights reserved. +//! Copyright The KCL Authors. All rights reserved. use crate::*; use bstr::ByteSlice; @@ -72,36 +72,28 @@ impl RangeNormal for std::ops::Range { impl ValueRef { pub fn str_len(&self) -> usize { - match &*self.rc { + match &*self.rc.borrow() { Value::str_value(ref v) => v.len(), _ => panic!("Invalid str object in str len"), } } - pub fn str_resize(&mut self, n: usize) { - match &*self.rc { - Value::str_value(_) => { - self.rc = std::rc::Rc::new(Value::str_value("?".repeat(n))); - } - _ => panic!("Invalid str object in str resize"), - } - } pub fn str_lower(&self) -> ValueRef { - match &*self.rc { + match &*self.rc.borrow() { Value::str_value(ref v) => ValueRef::str(&v.to_lowercase()), _ => panic!("Invalid str object in lower"), } } pub fn str_upper(&self) -> ValueRef { - match &*self.rc { + match &*self.rc.borrow() { Value::str_value(ref v) => ValueRef::str(&v.to_uppercase()), _ => panic!("Invalid str object in upper"), } } pub fn str_capitalize(&self) -> ValueRef { - match &*self.rc { + match &*self.rc.borrow() { Value::str_value(ref v) => { let mut chars = v.chars(); let value = if let Some(first_char) = chars.next() { @@ -119,6 +111,16 @@ impl ValueRef { } } + pub fn str_chars(&self) -> ValueRef { + match &*self.rc.borrow() { + Value::str_value(ref v) => { + let chars: Vec = v.chars().map(|c| c.to_string()).collect(); + ValueRef::list_str(&chars) + } + _ => panic!("Invalid str object in str_chars"), + } + } + pub fn str_count( &self, sub: &ValueRef, @@ -128,7 +130,7 @@ impl ValueRef { let start = adjust_parameter(start); let end = adjust_parameter(end); - match (&*self.rc, &*sub.rc) { + match (&*self.rc.borrow(), &*sub.rc.borrow()) { (Value::str_value(ref v), Value::str_value(ref sub_str)) => { let range = adjust_indices(start, end, v.len()); let count = if range.is_normal() { @@ -151,7 +153,7 @@ impl ValueRef { let start = adjust_parameter(start); let end = adjust_parameter(end); - match (&*self.rc, &*prefix.rc) { + match (&*self.rc.borrow(), &*prefix.rc.borrow()) { (Value::str_value(ref v), Value::str_value(ref prefix)) => { let range = adjust_indices(start, end, v.len()); let result = if range.is_normal() { @@ -174,7 +176,7 @@ impl ValueRef { let start = adjust_parameter(start); let end = adjust_parameter(end); - match (&*self.rc, &*suffix.rc) { + match (&*self.rc.borrow(), &*suffix.rc.borrow()) { (Value::str_value(ref v), Value::str_value(ref suffix)) => { let range = adjust_indices(start, end, v.len()); let result = if range.is_normal() { @@ -189,7 +191,7 @@ impl ValueRef { } pub fn str_format(&self, args: &ValueRef, kwargs: &ValueRef) -> ValueRef { - match (&*self.rc, &*args.rc) { + match (&*self.rc.borrow(), &*args.rc.borrow()) { (Value::str_value(ref v), Value::list_value(_)) => { match FormatString::from_str(v.as_str()) { Ok(format_string) => { @@ -212,7 +214,7 @@ impl ValueRef { let start = adjust_parameter(start); let end = adjust_parameter(end); - match (&*self.rc, &*sub.rc) { + match (&*self.rc.borrow(), &*sub.rc.borrow()) { (Value::str_value(ref v), Value::str_value(ref sub)) => { let range = adjust_indices(start, end, v.len()); let range_start = range.start; @@ -239,7 +241,7 @@ impl ValueRef { let start = adjust_parameter(start); let end = adjust_parameter(end); - match (&*self.rc, &*sub.rc) { + match (&*self.rc.borrow(), &*sub.rc.borrow()) { (Value::str_value(ref v), Value::str_value(ref sub)) => { let range = adjust_indices(start, end, v.len()); let range_start = range.start; @@ -266,7 +268,7 @@ impl ValueRef { let start = adjust_parameter(start); let end = adjust_parameter(end); - match (&*self.rc, &*sub.rc) { + match (&*self.rc.borrow(), &*sub.rc.borrow()) { (Value::str_value(ref v), Value::str_value(ref sub)) => { let range = adjust_indices(start, end, v.len()); let range_start = range.start; @@ -293,7 +295,7 @@ impl ValueRef { let start = adjust_parameter(start); let end = adjust_parameter(end); - match (&*self.rc, &*sub.rc) { + match (&*self.rc.borrow(), &*sub.rc.borrow()) { (Value::str_value(ref v), Value::str_value(ref sub)) => { let range = adjust_indices(start, end, v.len()); let range_start = range.start; @@ -312,7 +314,7 @@ impl ValueRef { } pub fn str_isalnum(&self) -> ValueRef { - match &*self.rc { + match &*self.rc.borrow() { Value::str_value(ref v) => { let result = !v.is_empty() && v.chars().all(char::is_alphanumeric); ValueRef::bool(result) @@ -322,7 +324,7 @@ impl ValueRef { } pub fn str_isalpha(&self) -> ValueRef { - match &*self.rc { + match &*self.rc.borrow() { Value::str_value(ref v) => { let result = !v.is_empty() && v.chars().all(char::is_alphabetic); ValueRef::bool(result) @@ -332,7 +334,7 @@ impl ValueRef { } pub fn str_isdigit(&self) -> ValueRef { - match &*self.rc { + match &*self.rc.borrow() { Value::str_value(ref v) => { let valid_unicodes: [u16; 10] = [ 0x2070, 0x00B9, 0x00B2, 0x00B3, 0x2074, 0x2075, 0x2076, 0x2077, 0x2078, 0x2079, @@ -340,7 +342,7 @@ impl ValueRef { let result = !v.is_empty() && v.chars() - .filter(|c| !c.is_digit(10)) + .filter(|c| !c.is_ascii_digit()) .all(|c| valid_unicodes.contains(&(c as u16))); ValueRef::bool(result) } @@ -349,7 +351,7 @@ impl ValueRef { } pub fn str_islower(&self) -> ValueRef { - match &*self.rc { + match &*self.rc.borrow() { Value::str_value(ref v) => { let result = is_case(v, char::is_lowercase, char::is_uppercase); ValueRef::bool(result) @@ -359,7 +361,7 @@ impl ValueRef { } pub fn str_isspace(&self) -> ValueRef { - match &*self.rc { + match &*self.rc.borrow() { Value::str_value(ref v) => { if v.is_empty() { return ValueRef::bool(false); @@ -376,7 +378,7 @@ impl ValueRef { } pub fn str_istitle(&self) -> ValueRef { - match &*self.rc { + match &*self.rc.borrow() { Value::str_value(ref v) => { if v.is_empty() { return ValueRef::bool(false); @@ -408,7 +410,7 @@ impl ValueRef { } pub fn str_isupper(&self) -> ValueRef { - match &*self.rc { + match &*self.rc.borrow() { Value::str_value(ref v) => { let result = is_case(v, char::is_uppercase, char::is_lowercase); ValueRef::bool(result) @@ -418,7 +420,7 @@ impl ValueRef { } pub fn str_isnumeric(&self) -> ValueRef { - match &*self.rc { + match &*self.rc.borrow() { Value::str_value(ref v) => { let result = !v.is_empty() && v.chars().all(char::is_numeric); ValueRef::bool(result) @@ -428,7 +430,7 @@ impl ValueRef { } pub fn str_join(&self, value: &ValueRef) -> ValueRef { - match &*self.rc { + match &*self.rc.borrow() { Value::str_value(ref v) => { let mut joined = String::new(); let mut iter = value.iter(); @@ -448,7 +450,7 @@ impl ValueRef { pub fn str_lstrip(&self, value: Option<&ValueRef>) -> ValueRef { let value = adjust_parameter(value); - match &*self.rc { + match &*self.rc.borrow() { Value::str_value(ref v) => { let value = match value { Some(chars) => { @@ -467,7 +469,7 @@ impl ValueRef { pub fn str_rstrip(&self, value: Option<&ValueRef>) -> ValueRef { let value = adjust_parameter(value); - match &*self.rc { + match &*self.rc.borrow() { Value::str_value(ref v) => { let value = match value { Some(chars) => { @@ -491,7 +493,7 @@ impl ValueRef { ) -> ValueRef { let count = adjust_parameter(count); - match &*self.rc { + match &*self.rc.borrow() { Value::str_value(ref v) => { let old = old.as_str(); let new = new.as_str(); @@ -512,11 +514,41 @@ impl ValueRef { } } + /// If the string starts with the prefix string, return string[len(prefix):]. + /// Otherwise, return a copy of the original string. + pub fn str_removeprefix(&self, prefix: &ValueRef) -> ValueRef { + match &*self.rc.borrow() { + Value::str_value(ref v) => { + let prefix = prefix.as_str(); + match v.strip_prefix(&prefix) { + Some(r) => ValueRef::str(r), + None => ValueRef::str(v), + } + } + _ => panic!("Invalid str object in str_rstrip"), + } + } + + /// If the string ends with the suffix string and that suffix is not empty, return string[:-len(suffix)]. + /// Otherwise, return a copy of the original string. + pub fn str_removesuffix(&self, suffix: &ValueRef) -> ValueRef { + match &*self.rc.borrow() { + Value::str_value(ref v) => { + let suffix = suffix.as_str(); + match v.strip_suffix(&suffix) { + Some(r) => ValueRef::str(r), + None => ValueRef::str(v), + } + } + _ => panic!("Invalid str object in str_removesuffix"), + } + } + pub fn str_split(&self, sep: Option<&ValueRef>, maxsplit: Option<&ValueRef>) -> ValueRef { let sep = adjust_parameter(sep); let maxsplit = adjust_parameter(maxsplit); - match &*self.rc { + match &*self.rc.borrow() { Value::str_value(ref v) => { let convert = ValueRef::str; let maxsplit = match maxsplit { @@ -566,7 +598,7 @@ impl ValueRef { let sep = adjust_parameter(sep); let maxsplit = adjust_parameter(maxsplit); - match &*self.rc { + match &*self.rc.borrow() { Value::str_value(ref v) => { let convert = ValueRef::str; let maxsplit = match maxsplit { @@ -614,7 +646,7 @@ impl ValueRef { pub fn str_splitlines(&self, keepends: Option<&ValueRef>) -> ValueRef { let keepends = adjust_parameter(keepends); - match &*self.rc { + match &*self.rc.borrow() { Value::str_value(ref v) => { let convert = ValueRef::str; let keepends = match keepends { @@ -657,7 +689,7 @@ impl ValueRef { pub fn str_strip(&self, value: Option<&ValueRef>) -> ValueRef { let value = adjust_parameter(value); - match &*self.rc { + match &*self.rc.borrow() { Value::str_value(ref v) => { let value = match value { Some(chars) => { @@ -674,7 +706,7 @@ impl ValueRef { } pub fn str_title(&self) -> ValueRef { - match &*self.rc { + match &*self.rc.borrow() { Value::str_value(ref v) => { let mut title = String::with_capacity(v.len()); let mut previous_is_cased = false; @@ -705,7 +737,7 @@ impl ValueRef { } pub fn str_equal(&self, value: &str) -> bool { - match &*self.rc { + match &*self.rc.borrow() { Value::str_value(ref v) => *v == *value, _ => false, } diff --git a/kclvm/runtime/src/value/val_type.rs b/kclvm/runtime/src/value/val_type.rs index 5a6156424..8b19a2d1d 100644 --- a/kclvm/runtime/src/value/val_type.rs +++ b/kclvm/runtime/src/value/val_type.rs @@ -1,4 +1,4 @@ -// Copyright 2021 The KCL Authors. All rights reserved. +//! Copyright The KCL Authors. All rights reserved. extern crate fancy_regex; @@ -21,6 +21,7 @@ pub const KCL_TYPE_ANY: &str = "any"; pub const KCL_TYPE_LIST: &str = "list"; pub const KCL_TYPE_DICT: &str = "dict"; pub const KCL_TYPE_FUNCTION: &str = "function"; +pub const KCL_TYPE_TYPE: &str = "type"; pub const KCL_TYPE_NUMBER_MULTIPLY: &str = "number_multiplier"; pub const KCL_NAME_CONSTANT_NONE: &str = "None"; pub const KCL_NAME_CONSTANT_UNDEFINED: &str = "Undefined"; @@ -45,46 +46,45 @@ pub type SchemaTypeFunc = unsafe extern "C" fn( // common impl ValueRef { pub fn type_str(&self) -> String { - match &*self.rc { + match &*self.rc.borrow() { Value::undefined => String::from(KCL_TYPE_UNDEFINED), Value::none => String::from(KCL_TYPE_NONE), Value::bool_value(..) => String::from(BUILTIN_TYPE_BOOL), Value::int_value(..) => String::from(BUILTIN_TYPE_INT), Value::float_value(..) => String::from(BUILTIN_TYPE_FLOAT), Value::unit_value(_, raw, suffix) => { - format!("{}({}{})", KCL_TYPE_NUMBER_MULTIPLY, raw, suffix) + format!("{KCL_TYPE_NUMBER_MULTIPLY}({raw}{suffix})") } Value::str_value(..) => String::from(BUILTIN_TYPE_STR), Value::list_value(..) => String::from(KCL_TYPE_LIST), Value::dict_value(..) => String::from(KCL_TYPE_DICT), Value::schema_value(ref v) => v.name.clone(), - Value::func_value(..) => String::from(KCL_TYPE_FUNCTION), + Value::func_value(func) => { + if func.runtime_type.is_empty() { + String::from(KCL_TYPE_FUNCTION) + } else { + String::from(KCL_TYPE_TYPE) + } + } } } } /// Use the schema instance to build a new schema instance using the schema construct function -pub fn resolve_schema(schema: &ValueRef, keys: &[String]) -> ValueRef { +pub fn resolve_schema(ctx: &mut Context, schema: &ValueRef, keys: &[String]) -> ValueRef { if !schema.is_schema() { return schema.clone(); } let schema_value = schema.as_schema(); let schema_type_name = schema_runtime_type(&schema_value.name, &schema_value.pkgpath); - let ctx = Context::current_context_mut(); let now_meta_info = ctx.panic_info.clone(); - let has_schema_type = { - let all_schemas = ctx.all_schemas.borrow_mut(); - all_schemas.contains_key(&schema_type_name) - }; + let has_schema_type = { ctx.all_schemas.contains_key(&schema_type_name) }; if has_schema_type { - let schema_type = { - let all_schemas = ctx.all_schemas.borrow_mut(); - all_schemas.get(&schema_type_name).unwrap().clone() - }; - let schema_type = schema_type.as_function(); + let schema_type = { ctx.all_schemas.get(&schema_type_name).unwrap().clone() }; + let schema_type = schema_type.func.as_function(); let schema_fn_ptr = schema_type.fn_ptr; let keys = keys.iter().map(|v| v.as_str()).collect(); - let config = schema.dict_get_entries(keys); + let config = schema.dict_get_entries_with_op(keys, &ConfigEntryOperationKind::Override); let config_new = config.clone(); let config_meta = schema_config_meta( &ctx.panic_info.kcl_file, @@ -94,54 +94,59 @@ pub fn resolve_schema(schema: &ValueRef, keys: &[String]) -> ValueRef { let config_meta_new = config_meta.clone(); let value = unsafe { let schema_fn: SchemaTypeFunc = transmute_copy(&schema_fn_ptr); - let ctx = kclvm_context_current(); - let cal_map = kclvm_value_Dict(); - let list = kclvm_value_List(); + let cal_map = kclvm_value_Dict(ctx as *mut Context); + let list = schema_value.args.clone().into_raw(ctx); // Schema function closures // is sub schema - kclvm_list_append(list, ValueRef::bool(false).into_raw()); + kclvm_list_append(list, ValueRef::bool(false).into_raw(ctx)); // config meta - kclvm_list_append(list, config_meta.into_raw()); + kclvm_list_append(list, config_meta.into_raw(ctx)); // schema - kclvm_list_append(list, config.into_raw()); + kclvm_list_append(list, config.into_raw(ctx)); // config - kclvm_list_append(list, kclvm_value_Dict()); + kclvm_list_append(list, kclvm_value_Dict(ctx as *mut Context)); // optional mapping - kclvm_list_append(list, kclvm_value_Dict()); + kclvm_list_append(list, kclvm_value_Dict(ctx as *mut Context)); // cal order map kclvm_list_append(list, cal_map); // backtrack level map - kclvm_list_append(list, kclvm_value_Dict()); + kclvm_list_append(list, kclvm_value_Dict(ctx as *mut Context)); // backtrack cache - kclvm_list_append(list, kclvm_value_Dict()); + kclvm_list_append(list, kclvm_value_Dict(ctx as *mut Context)); // record instance - kclvm_list_append(list, ValueRef::bool(false).into_raw()); + kclvm_list_append(list, ValueRef::bool(false).into_raw(ctx)); // instance pkgpath - kclvm_list_append(list, ValueRef::str(&now_meta_info.kcl_pkgpath).into_raw()); - let dict = kclvm_value_Dict(); + kclvm_list_append( + list, + ValueRef::str(&now_meta_info.kcl_pkgpath).into_raw(ctx), + ); + let dict = schema_value.kwargs.clone().into_raw(ctx); schema_fn(ctx, list, dict); - let list = kclvm_value_List(); + let list = schema_value.args.clone().into_raw(ctx); // Schema function closures // is sub schema - kclvm_list_append(list, ValueRef::bool(true).into_raw()); + kclvm_list_append(list, ValueRef::bool(true).into_raw(ctx)); // config meta - kclvm_list_append(list, config_meta_new.into_raw()); + kclvm_list_append(list, config_meta_new.into_raw(ctx)); // schema - kclvm_list_append(list, config_new.into_raw()); + kclvm_list_append(list, config_new.into_raw(ctx)); // config - kclvm_list_append(list, kclvm_value_Dict()); + kclvm_list_append(list, kclvm_value_Dict(ctx as *mut Context)); // optional mapping - kclvm_list_append(list, kclvm_value_Dict()); + kclvm_list_append(list, kclvm_value_Dict(ctx as *mut Context)); // cal order map kclvm_list_append(list, cal_map); // backtrack level map - kclvm_list_append(list, kclvm_value_Dict()); + kclvm_list_append(list, kclvm_value_Dict(ctx as *mut Context)); // backtrack cache - kclvm_list_append(list, kclvm_value_Dict()); + kclvm_list_append(list, kclvm_value_Dict(ctx as *mut Context)); // record instance - kclvm_list_append(list, ValueRef::bool(true).into_raw()); + kclvm_list_append(list, ValueRef::bool(true).into_raw(ctx)); // instance pkgpath - kclvm_list_append(list, ValueRef::str(&now_meta_info.kcl_pkgpath).into_raw()); + kclvm_list_append( + list, + ValueRef::str(&now_meta_info.kcl_pkgpath).into_raw(ctx), + ); let value = schema_fn(ctx, list, dict); ptr_as_ref(value) }; @@ -153,91 +158,102 @@ pub fn resolve_schema(schema: &ValueRef, keys: &[String]) -> ValueRef { } /// Type pack and check ValueRef with the expected type vector -pub fn type_pack_and_check(value: &ValueRef, expected_types: Vec<&str>) -> ValueRef { +pub fn type_pack_and_check( + ctx: &mut Context, + value: &ValueRef, + expected_types: Vec<&str>, + strict: bool, +) -> ValueRef { if value.is_none_or_undefined() || expected_types.is_empty() { return value.clone(); } let is_schema = value.is_schema(); - let value_tpe = value.type_str(); let mut checked = false; - let mut convertted_value = value.clone(); - let expected_type = &expected_types.join(" | ").replace("@", ""); + let mut converted_value = value.clone(); + let expected_type = &expected_types.join(" | ").replace('@', ""); for tpe in expected_types { let tpe = if !tpe.contains('.') { - let ctx = Context::current_context_mut(); match ctx.import_names.get(tpe) { Some(mapping) => mapping.keys().next().unwrap(), None => tpe, } } else { tpe - }; + } + .to_string(); if !is_schema { - convertted_value = convert_collection_value(value, tpe); + converted_value = convert_collection_value(ctx, value, &tpe); } // Runtime type check - checked = check_type(&convertted_value, tpe); + checked = check_type(&converted_value, &ctx.panic_info.kcl_pkgpath, &tpe, strict); if checked { break; } } if !checked { - panic!("expect {}, got {}", expected_type, value_tpe); + panic!( + "expect {expected_type}, got {}", + val_plan::type_of(value, true) + ); } - convertted_value + converted_value } /// Convert collection value including dict/list to the potential schema -pub fn convert_collection_value(value: &ValueRef, tpe: &str) -> ValueRef { +pub fn convert_collection_value(ctx: &mut Context, value: &ValueRef, tpe: &str) -> ValueRef { // May be a type alias. let tpe = if !tpe.contains('.') { - let ctx = Context::current_context_mut(); match ctx.import_names.get(tpe) { Some(mapping) => mapping.keys().next().unwrap(), None => tpe, } } else { tpe - }; + } + .to_string(); if tpe.is_empty() || tpe == KCL_TYPE_ANY { return value.clone(); } let is_collection = value.is_list() || value.is_dict(); - let invalid_match_dict = is_dict_type(tpe) && !value.is_dict(); - let invalid_match_list = is_list_type(tpe) && !value.is_list(); + let invalid_match_dict = is_dict_type(&tpe) && !value.is_dict(); + let invalid_match_list = is_list_type(&tpe) && !value.is_list(); let invalid_match = invalid_match_dict || invalid_match_list; - if !is_collection || invalid_match || is_type_union(tpe) { + if !is_collection || invalid_match { return value.clone(); } - if is_dict_type(tpe) { + // Convert a value to union types e.g., {a: 1} => A | B + if is_type_union(&tpe) { + let types = split_type_union(&tpe); + convert_collection_value_with_union_types(ctx, value, &types) + } else if is_dict_type(&tpe) { //let (key_tpe, value_tpe) = separate_kv(tpe); - let (_, value_tpe) = separate_kv(&dereference_type(tpe)); + let (_, value_tpe) = separate_kv(&dereference_type(&tpe)); let mut expected_dict = ValueRef::dict(None); let dict_ref = value.as_dict_ref(); + expected_dict + .set_potential_schema_type(&dict_ref.potential_schema.clone().unwrap_or_default()); for (k, v) in &dict_ref.values { - let expected_value = convert_collection_value(v, &value_tpe); + let expected_value = convert_collection_value(ctx, v, &value_tpe); let op = dict_ref .ops .get(k) - .or(Some(&ConfigEntryOperationKind::Union)) - .unwrap(); - let index = dict_ref.insert_indexs.get(k).or(Some(&-1)).unwrap(); + .unwrap_or(&ConfigEntryOperationKind::Union); + let index = dict_ref.insert_indexs.get(k); expected_dict.dict_update_entry(k, &expected_value, op, index) } expected_dict - } else if is_list_type(tpe) { - let expected_type = dereference_type(tpe); + } else if is_list_type(&tpe) { + let expected_type = dereference_type(&tpe); let mut expected_list = ValueRef::list(None); let list_ref = value.as_list_ref(); for v in &list_ref.values { - let expected_value = convert_collection_value(v, &expected_type); + let expected_value = convert_collection_value(ctx, v, &expected_type); expected_list.list_append(&expected_value) } expected_list - } else if BUILTIN_TYPES.contains(&tpe) { + } else if BUILTIN_TYPES.contains(&tpe.as_str()) { value.clone() } else { - let ctx = Context::current_context_mut(); let now_meta_info = ctx.panic_info.clone(); let mut schema_type_name = if tpe.contains('.') { tpe.to_string() @@ -258,86 +274,87 @@ pub fn convert_collection_value(value: &ValueRef, tpe: &str) -> ValueRef { let pkgname = splits[1]; let name = splits[0]; match ctx.import_names.get(&now_meta_info.kcl_file) { - Some(mapping) => match mapping.get(pkgname) { - Some(pkgpath) => { - schema_type_name = format!("{}.{}", pkgpath, name); + Some(mapping) => { + if let Some(pkgpath) = mapping.get(pkgname) { + schema_type_name = format!("{pkgpath}.{name}"); } - None => {} - }, + } None => { for (_, mapping) in &ctx.import_names { - match mapping.get(pkgname) { - Some(pkgpath) => { - schema_type_name = format!("{}.{}", pkgpath, name); - break; - } - None => {} + if let Some(pkgpath) = mapping.get(pkgname) { + schema_type_name = format!("{pkgpath}.{name}"); + break; } } } } } - let has_schema_type = { - let all_schemas = ctx.all_schemas.borrow_mut(); - all_schemas.contains_key(&schema_type_name) - }; + let has_schema_type = { ctx.all_schemas.contains_key(&schema_type_name) }; if has_schema_type { - let schema_type = { - let all_schemas = ctx.all_schemas.borrow_mut(); - all_schemas.get(&schema_type_name).unwrap().clone() - }; - let schema_type = schema_type.as_function(); - let schema_fn_ptr = schema_type.fn_ptr; + let schema_type = { ctx.all_schemas.get(&schema_type_name).unwrap().clone() }; + let schema_fn = schema_type.func.as_function(); + let schema_fn_ptr = schema_fn.fn_ptr; let value = unsafe { let schema_fn: SchemaTypeFunc = transmute_copy(&schema_fn_ptr); - let ctx = kclvm_context_current(); - let cal_order = kclvm_value_Dict(); - let list = kclvm_value_List(); + let cal_order = kclvm_value_Dict(ctx as *mut Context); + let list = kclvm_value_List(ctx as *mut Context); // Schema function closures // is_sub_schema - kclvm_list_append(list, ValueRef::bool(false).into_raw()); + kclvm_list_append(list, ValueRef::bool(false).into_raw(ctx)); // config meta - kclvm_list_append(list, kclvm_value_Dict()); + kclvm_list_append(list, kclvm_value_Dict(ctx as *mut Context)); // config - kclvm_list_append(list, value.clone().into_raw()); + kclvm_list_append(list, value.clone().into_raw(ctx)); // schema - kclvm_list_append(list, kclvm_value_Dict()); + kclvm_list_append(list, kclvm_value_Dict(ctx as *mut Context)); // optional mapping - kclvm_list_append(list, kclvm_value_Dict()); + kclvm_list_append(list, kclvm_value_Dict(ctx as *mut Context)); // cal order map kclvm_list_append(list, cal_order); // backtrack level map - kclvm_list_append(list, kclvm_value_Dict()); + kclvm_list_append(list, kclvm_value_Dict(ctx as *mut Context)); // backtrack cache - kclvm_list_append(list, kclvm_value_Dict()); + kclvm_list_append(list, kclvm_value_Dict(ctx as *mut Context)); // record instance - kclvm_list_append(list, ValueRef::bool(false).into_raw()); + kclvm_list_append(list, ValueRef::bool(false).into_raw(ctx)); // instance pkgpath - kclvm_list_append(list, ValueRef::str(&now_meta_info.kcl_pkgpath).into_raw()); - let dict = kclvm_value_Dict(); + kclvm_list_append( + list, + ValueRef::str(&now_meta_info.kcl_pkgpath).into_raw(ctx), + ); + let dict = kclvm_value_Dict(ctx as *mut Context); schema_fn(ctx, list, dict); - let list = kclvm_value_List(); + let list = kclvm_value_List(ctx as *mut Context); + + // Try convert the config to schema, if failed, return the config + if !value.is_fit_schema(&schema_type, ptr_as_ref(cal_order)) { + return value.clone(); + } + // Schema function closures // is_sub_schema - kclvm_list_append(list, ValueRef::bool(true).into_raw()); + kclvm_list_append(list, ValueRef::bool(true).into_raw(ctx)); // config meta - kclvm_list_append(list, kclvm_value_Dict()); + kclvm_list_append(list, kclvm_value_Dict(ctx as *mut Context)); // config - kclvm_list_append(list, value.clone().into_raw()); + kclvm_list_append(list, value.clone().into_raw(ctx)); // schema - kclvm_list_append(list, kclvm_value_Dict()); + kclvm_list_append(list, kclvm_value_Dict(ctx as *mut Context)); // optional mapping - kclvm_list_append(list, kclvm_value_Dict()); + kclvm_list_append(list, kclvm_value_Dict(ctx as *mut Context)); // cal order map kclvm_list_append(list, cal_order); // backtrack level map - kclvm_list_append(list, kclvm_value_Dict()); + kclvm_list_append(list, kclvm_value_Dict(ctx as *mut Context)); // backtrack cache - kclvm_list_append(list, kclvm_value_Dict()); + kclvm_list_append(list, kclvm_value_Dict(ctx as *mut Context)); // record instance - kclvm_list_append(list, ValueRef::bool(true).into_raw()); + kclvm_list_append(list, ValueRef::bool(true).into_raw(ctx)); // instance pkgpath - kclvm_list_append(list, ValueRef::str(&now_meta_info.kcl_pkgpath).into_raw()); + kclvm_list_append( + list, + ValueRef::str(&now_meta_info.kcl_pkgpath).into_raw(ctx), + ); let value = schema_fn(ctx, list, dict); ptr_as_ref(value) }; @@ -349,8 +366,28 @@ pub fn convert_collection_value(value: &ValueRef, tpe: &str) -> ValueRef { } } +/// Convert collection value including dict/list to the potential schema and return errors. +pub fn convert_collection_value_with_union_types( + ctx: &mut Context, + value: &ValueRef, + types: &[&str], +) -> ValueRef { + if value.is_schema() { + value.clone() + } else { + for tpe in types { + // Try match every type and convert the value, if matched, return the value. + let value = convert_collection_value(ctx, value, tpe); + if check_type(&value, &ctx.panic_info.kcl_pkgpath, tpe, false) { + return value; + } + } + value.clone() + } +} + /// check_type returns the value wether match the given the type string -pub fn check_type(value: &ValueRef, tpe: &str) -> bool { +pub fn check_type(value: &ValueRef, pkgpath: &str, tpe: &str, strict: bool) -> bool { if tpe.is_empty() || tpe == KCL_TYPE_ANY { return true; } @@ -358,28 +395,48 @@ pub fn check_type(value: &ValueRef, tpe: &str) -> bool { return true; } if is_type_union(tpe) { - return check_type_union(value, tpe); - } else if check_type_literal(value, tpe) { + return check_type_union(value, pkgpath, tpe); + } + + if check_type_literal(value, tpe) { return true; - } else if check_number_multiplier_type(value, tpe) { + } + + if check_number_multiplier_type(value, tpe) { return true; } // if value type is a dict type e.g. {"k": "v"} else if value.is_dict() { - return check_type_dict(value, tpe); + return check_type_dict(value, pkgpath, tpe); } // if value type is a list type e.g. [1, 2, 3] else if value.is_list() { - return check_type_list(value, tpe); + return check_type_list(value, pkgpath, tpe); } else if !value.is_none_or_undefined() { // if value type is a built-in type e.g. str, int, float, bool if match_builtin_type(value, tpe) { return true; + } else if match_function_type(value, tpe) { + return true; } if value.is_schema() { - // not list/dict, not built-in type, treat as user defined schema, - // do not check user schema type because it has been checked at compile time - return is_schema_type(tpe); + if strict { + let value_ty = crate::val_plan::value_type_path(value, true); + let tpe = if pkgpath != "" && pkgpath != MAIN_PKG_PATH && !tpe.contains(".") { + format!("{pkgpath}.{tpe}") + } else { + tpe.to_string() + }; + let tpe = match tpe.strip_prefix('@') { + Some(ty_str) => ty_str.to_string(), + None => tpe.to_string(), + }; + return value_ty == tpe; + } else { + // not list/dict, not built-in type, treat as user defined schema, + // do not check user schema type because it has been checked at compile time + return is_schema_type(tpe); + } } // Type error return false; @@ -389,12 +446,15 @@ pub fn check_type(value: &ValueRef, tpe: &str) -> bool { } /// check_type_union returns the value wether match the given the union type string -pub fn check_type_union(value: &ValueRef, tpe: &str) -> bool { +pub fn check_type_union(value: &ValueRef, pkgpath: &str, tpe: &str) -> bool { let expected_types = split_type_union(tpe); if expected_types.len() <= 1 { - return false; + false + } else { + expected_types + .iter() + .any(|tpe| check_type(value, pkgpath, tpe, false)) } - return expected_types.iter().any(|tpe| check_type(value, tpe)); } /// check_type_literal returns the value wether match the given the literal type string @@ -432,7 +492,7 @@ pub fn check_number_multiplier_type(value: &ValueRef, tpe: &str) -> bool { if value.is_unit() { if is_number_multiplier_literal_type(tpe) { let (_, raw, suffix) = value.as_unit(); - return format!("{}{}", raw, suffix) == tpe; + return format!("{raw}{suffix}") == tpe; } return tpe == NUMBER_MULTIPLIER_TYPE; } @@ -440,7 +500,7 @@ pub fn check_number_multiplier_type(value: &ValueRef, tpe: &str) -> bool { } /// check_type_dict returns the value wether match the given the dict type string -pub fn check_type_dict(value: &ValueRef, tpe: &str) -> bool { +pub fn check_type_dict(value: &ValueRef, pkgpath: &str, tpe: &str) -> bool { if tpe.is_empty() { return true; } @@ -451,7 +511,7 @@ pub fn check_type_dict(value: &ValueRef, tpe: &str) -> bool { let (_, expected_value_type) = separate_kv(&expected_type); let dict_ref = value.as_dict_ref(); for (_, v) in &dict_ref.values { - if !check_type(v, &expected_value_type) { + if !check_type(v, pkgpath, &expected_value_type, false) { return false; } } @@ -459,7 +519,7 @@ pub fn check_type_dict(value: &ValueRef, tpe: &str) -> bool { } /// check_type_list returns the value wether match the given the list type string -pub fn check_type_list(value: &ValueRef, tpe: &str) -> bool { +pub fn check_type_list(value: &ValueRef, pkgpath: &str, tpe: &str) -> bool { if tpe.is_empty() { return true; } @@ -469,17 +529,26 @@ pub fn check_type_list(value: &ValueRef, tpe: &str) -> bool { let expected_type = dereference_type(tpe); let list_ref = value.as_list_ref(); for v in &list_ref.values { - if !check_type(v, &expected_type) { + if !check_type(v, pkgpath, &expected_type, false) { return false; } } true } -/// match_builtin_type returns the value wether match the given the type string +/// match_builtin_type returns the value wether match the given the type string. #[inline] pub fn match_builtin_type(value: &ValueRef, tpe: &str) -> bool { - value.type_str() == *tpe || (value.type_str() == BUILTIN_TYPE_INT && tpe == BUILTIN_TYPE_FLOAT) + (value.is_builtin() && value.type_str() == *tpe) + || (value.type_str() == BUILTIN_TYPE_INT && tpe == BUILTIN_TYPE_FLOAT) +} + +/// match_function_type returns the value wether match the given the function type string. +#[inline] +pub fn match_function_type(value: &ValueRef, tpe: &str) -> bool { + value.type_str() == KCL_TYPE_FUNCTION + && (tpe == KCL_TYPE_FUNCTION + || (tpe.contains("(") && tpe.contains(")") && tpe.contains("->"))) } /// is_literal_type returns the type string whether is a literal type @@ -496,7 +565,7 @@ pub fn is_literal_type(tpe: &str) -> bool { if ValueRef::str(tpe).str_isdigit().is_truthy() { return true; } - if ValueRef::str(tpe.replacen(".", "", 1).as_str()) + if ValueRef::str(tpe.replacen('.', "", 1).as_str()) .str_isdigit() .is_truthy() && tpe.matches('.').count() < 2 @@ -509,13 +578,19 @@ pub fn is_literal_type(tpe: &str) -> bool { /// is_dict_type returns the type string whether is a dict type #[inline] pub fn is_dict_type(tpe: &str) -> bool { - tpe.len() >= 2 && &tpe[0..1] == "{" && &tpe[tpe.len() - 1..] == "}" + let count = tpe.chars().count(); + count >= 2 + && matches!(tpe.chars().next(), Some('{')) + && matches!(tpe.chars().nth(count - 1), Some('}')) } /// is_list_type returns the type string whether is a list type #[inline] pub fn is_list_type(tpe: &str) -> bool { - tpe.len() >= 2 && &tpe[0..1] == "[" && &tpe[tpe.len() - 1..] == "]" + let count = tpe.chars().count(); + count >= 2 + && matches!(tpe.chars().next(), Some('[')) + && matches!(tpe.chars().nth(count - 1), Some(']')) } #[inline] @@ -547,16 +622,16 @@ pub fn is_type_union(tpe: &str) -> bool { } else if c == ']' || c == '}' { stack.pop(); } else if c == '\"' { - let t = &tpe[i..]; + let t: String = tpe.chars().skip(i).collect(); let re = fancy_regex::Regex::new(r#""(?!"").*?(? bool { } } +#[inline] +fn ty_str_strip(ty_str: &str) -> &str { + // Empty and tab chars. + let chars = " \t"; + ty_str.trim_matches(|c| chars.contains(c)) +} + /// separate_kv split the union type and do not split '|' in dict and list -/// e.g., "int|str" -> vec!["int", "str"] +/// e.g., "int|str" -> vec!["int", "str"], "int | str" -> vec!["int", "str"] pub fn split_type_union(tpe: &str) -> Vec<&str> { let mut i = 0; let mut s_index = 0; let mut stack = String::new(); let mut types: Vec<&str> = vec![]; while i < tpe.chars().count() { - let c = tpe.chars().nth(i).unwrap(); + let (c_idx, c) = tpe.char_indices().nth(i).unwrap(); if c == '|' && stack.is_empty() { - types.push(&tpe[s_index..i]); - s_index = i + 1; + types.push(&tpe[s_index..c_idx]); + s_index = c_idx + 1; } // List/Dict type else if c == '[' || c == '{' { @@ -596,24 +678,25 @@ pub fn split_type_union(tpe: &str) -> Vec<&str> { } // String literal type else if c == '\"' { - let t = &tpe[i..]; + let t: String = tpe.chars().skip(i).collect(); let re = fancy_regex::Regex::new(r#""(?!"").*?(? (String, String) { stack.push(c) } else if c == ']' { if &stack[stack.len() - 1..] != "[" { - panic!("invalid type string {}", expected_type); + panic!("invalid type string {expected_type}"); } stack.pop(); } else if c == '}' { if &stack[stack.len() - 1..] != "{" { - panic!("invalid type string {}", expected_type); + panic!("invalid type string {expected_type}"); } stack.pop(); } else if c == ':' { if !stack.is_empty() { - panic!("invalid type string {}", expected_type); + panic!("invalid type string {expected_type}"); } return ( expected_type[..n].to_string(), @@ -678,7 +761,7 @@ mod test_value_type { (ValueRef::str("0"), "int", false), ]; for (value, tpe, expected) in cases { - assert_eq!(check_type(&value, tpe), expected); + assert_eq!(check_type(&value, "", tpe, false), expected,); } } @@ -699,7 +782,7 @@ mod test_value_type { (ValueRef::bool(true), "int|str", false), ]; for (value, tpe, expected) in cases { - assert_eq!(check_type_union(&value, tpe), expected); + assert_eq!(check_type_union(&value, "", tpe), expected); } } @@ -751,7 +834,7 @@ mod test_value_type { (ValueRef::dict_int(&[("key", 1)]), "{str:str}", false), ]; for (value, tpe, expected) in cases { - assert_eq!(check_type_dict(&value, tpe), expected); + assert_eq!(check_type_dict(&value, "", tpe), expected); } } @@ -790,7 +873,7 @@ mod test_value_type { (ValueRef::list_int(&[1, 2, 3]), "[bool]", false), ]; for (value, tpe, expected) in cases { - assert_eq!(check_type_list(&value, tpe), expected); + assert_eq!(check_type_list(&value, "", tpe), expected); } } @@ -922,7 +1005,9 @@ mod test_value_type { let cases = [ ("", vec![""]), ("str|int", vec!["str", "int"]), + ("str | int", vec!["str", "int"]), ("str|int|bool", vec!["str", "int", "bool"]), + ("str | int | bool", vec!["str", "int", "bool"]), ("str|[str]", vec!["str", "[str]"]), ("str|{str:int}", vec!["str", "{str:int}"]), ("A|B|C", vec!["A", "B", "C"]), diff --git a/kclvm/runtime/src/value/val_unary.rs b/kclvm/runtime/src/value/val_unary.rs index 06bf047a0..4d964e5c7 100644 --- a/kclvm/runtime/src/value/val_unary.rs +++ b/kclvm/runtime/src/value/val_unary.rs @@ -1,11 +1,11 @@ -// Copyright 2021 The KCL Authors. All rights reserved. +//! Copyright The KCL Authors. All rights reserved. use crate::*; impl ValueRef { // +x pub fn unary_plus(&self) -> Self { - match &*self.rc { + match &*self.rc.borrow() { Value::int_value(ref a) => Self::int(*a), Value::float_value(ref a) => Self::float(*a), _ => panic!("bad operand type for unary +: '{}'", self.type_str()), @@ -14,7 +14,7 @@ impl ValueRef { // -x pub fn unary_minus(&self) -> Self { - match &*self.rc { + match &*self.rc.borrow() { Value::int_value(ref a) => Self::int(0 - *a), Value::float_value(ref a) => Self::float(0.0 - *a), _ => panic!("bad operand type for unary -: '{}'", self.type_str()), diff --git a/kclvm/runtime/src/value/val_union.rs b/kclvm/runtime/src/value/val_union.rs index ffd8ce145..5cc74c610 100644 --- a/kclvm/runtime/src/value/val_union.rs +++ b/kclvm/runtime/src/value/val_union.rs @@ -1,241 +1,430 @@ -// Copyright 2021 The KCL Authors. All rights reserved. +//! Copyright The KCL Authors. All rights reserved. use crate::unification::value_subsume; use crate::*; +/// UnionContext records some information during the value merging process, +/// including the merging path and whether there are conflicts. +#[derive(Default, Debug)] +pub struct UnionContext { + pub path_backtrace: Vec, + pub conflict: bool, + pub obj_json: String, + pub delta_json: String, +} + +/// UnionOptions denotes the union options between runtime values. +#[derive(Debug, Clone)] +pub struct UnionOptions { + /// Whether to override list values. + pub list_override: bool, + /// Whether to do the idempotent check. + pub idempotent_check: bool, + /// Whether to resolve config including optional attributes, etc. + pub config_resolve: bool, +} + +impl Default for UnionOptions { + fn default() -> Self { + Self { + list_override: false, + idempotent_check: true, + config_resolve: true, + } + } +} + +/// Normalize negative index into positive index with the length. +pub fn must_normalize_index(index: i32, len: usize) -> usize { + if index < 0 { + let pos_index = index + len as i32; + if pos_index >= 0 { + pos_index as usize + } else { + panic!( + "index out of bounds: the len is {} but the index is {}", + len, index + ) + } + } else { + index as usize + } +} + impl ValueRef { fn do_union( - &self, + &mut self, + ctx: &mut Context, x: &Self, - should_list_override: bool, - should_idempotent_check: bool, - should_config_resolve: bool, + opts: &UnionOptions, + union_context: &mut UnionContext, ) -> Self { - let union_fn = |obj: &DictValue, delta: &DictValue| { - let result_dict = get_ref_mut(obj); + if self.is_same_ref(x) { + return self.clone(); + } + + let mut union_fn = |obj: &mut DictValue, delta: &DictValue| { + // Update potential schema type + obj.potential_schema = delta.potential_schema.clone(); // Update attribute map for (k, v) in &delta.ops { - result_dict.ops.insert(k.clone(), v.clone()); + obj.ops.insert(k.clone(), v.clone()); } // Update index map for (k, v) in &delta.insert_indexs { - result_dict.insert_indexs.insert(k.clone(), *v); + obj.insert_indexs.insert(k.clone(), *v); } + // Update values for (k, v) in &delta.values { let operation = if let Some(op) = delta.ops.get(k) { op } else { &ConfigEntryOperationKind::Union }; - let index = if let Some(idx) = delta.insert_indexs.get(k) { - *idx - } else { - -1 - }; - if !result_dict.values.contains_key(k) { - result_dict.values.insert(k.clone(), v.clone()); + let index = delta.insert_indexs.get(k); + if !obj.values.contains_key(k) && index.is_none() { + obj.values.insert(k.clone(), v.clone()); } else { match operation { - ConfigEntryOperationKind::Union => { - if should_idempotent_check - && obj.values.contains_key(k) - && !value_subsume(v, obj.values.get(k).unwrap(), false) - { - panic!("conflicting values on the attribute '{}' between {:?} and {:?}", k, self.to_string(), x.to_string()); + ConfigEntryOperationKind::Union => match index { + Some(index) => { + let index = *index; + if let Some(origin_value) = obj.values.get_mut(k) { + if !origin_value.is_list() { + panic!( + "only list attribute can be union value with the index {}", + index + ); + } + let value = origin_value.list_get(index as isize); + if let Some(mut value) = value { + if opts.idempotent_check && !value_subsume(v, &value, false) + { + union_context.conflict = true; + union_context + .path_backtrace + .push(format!("{}[{}]", k, index)); + union_context.obj_json = if value.is_config() { + "{...}".to_string() + } else if value.is_list() { + "[...]".to_string() + } else { + value.to_json_string() + }; + + union_context.delta_json = if v.is_config() { + "{...}".to_string() + } else if v.is_list() { + "[...]".to_string() + } else { + v.to_json_string() + }; + return; + } + let union_value = + value.union(ctx, v, false, opts, union_context); + if union_context.conflict { + union_context.path_backtrace.push(k.clone()); + return; + } + let index = must_normalize_index(index, origin_value.len()); + origin_value.list_set(index, &union_value); + } else { + panic!("only non-empty list attribute can be union value with the index {}", index); + } + } else { + panic!("only non-empty list attribute can be union value with the index {}", index); + } } - let value = obj.values.get(k).unwrap().union( - v, - false, - should_list_override, - should_idempotent_check, - should_config_resolve, - ); - result_dict.values.insert(k.clone(), value); - } - ConfigEntryOperationKind::Override => { - if index < 0 { - result_dict.values.insert(k.clone(), v.clone()); - } else { - let origin_value = result_dict.values.get_mut(k).unwrap(); - if !origin_value.is_list() { - panic!("only list attribute can be inserted value"); + None => { + if let Some(obj_value) = obj.values.get_mut(k) { + if opts.idempotent_check && !value_subsume(v, obj_value, false) + { + union_context.conflict = true; + union_context.path_backtrace.push(k.clone()); + union_context.obj_json = if obj_value.is_config() { + "{...}".to_string() + } else if obj_value.is_list() { + "[...]".to_string() + } else { + obj_value.to_json_string() + }; + + union_context.delta_json = if v.is_config() { + "{...}".to_string() + } else if v.is_list() { + "[...]".to_string() + } else { + v.to_json_string() + }; + return; + } + obj_value.union(ctx, v, false, opts, union_context); + if union_context.conflict { + union_context.path_backtrace.push(k.clone()); + return; + } + } else { + obj.values.insert(k.clone(), v.clone()); } - if v.is_none_or_undefined() { - origin_value.list_remove_at(index as usize); + } + }, + ConfigEntryOperationKind::Override => match index { + Some(index) => { + let index = *index; + let origin_value = obj.values.get_mut(k); + if let Some(origin_value) = origin_value { + if !origin_value.is_list() { + panic!("only list attribute can be override value with the index {}", index); + } + let index = must_normalize_index(index, origin_value.len()); + if v.is_undefined() { + origin_value.list_remove_at(index as usize); + } else { + origin_value.list_must_set(index as usize, v); + } } else { - origin_value.list_set(index as usize, v); + panic!("only list attribute can be override value with the index {}", index); } } - } + None => { + obj.values.insert(k.clone(), v.clone()); + } + }, ConfigEntryOperationKind::Insert => { - let value = v.deep_copy(); - let origin_value = result_dict.values.get_mut(k).unwrap(); - if origin_value.is_none_or_undefined() { + let origin_value = obj.values.get_mut(k); + if origin_value.is_none() + || origin_value.unwrap().is_none_or_undefined() + { let list = ValueRef::list(None); - result_dict.values.insert(k.to_string(), list); + obj.values.insert(k.to_string(), list); + } + let origin_value = obj.values.get_mut(k).unwrap(); + if origin_value.is_same_ref(v) { + continue; } - let origin_value = result_dict.values.get_mut(k).unwrap(); - match (&*origin_value.rc, &*value.rc) { + match (&mut *origin_value.rc.borrow_mut(), &*v.rc.borrow()) { (Value::list_value(origin_value), Value::list_value(value)) => { - // As RefMut - let origin_value: &mut ListValue = unsafe { - &mut *(origin_value as *const ListValue as *mut ListValue) - }; - // As RefMut - let value: &mut ListValue = unsafe { - &mut *(value as *const ListValue as *mut ListValue) - }; - if index == -1 { - origin_value.values.append(&mut value.clone().values); - } else if index >= 0 { - let mut insert_index = index; - for v in &value.values { - origin_value - .values - .insert(insert_index as usize, v.clone()); - insert_index += 1; + match index { + Some(index) => { + let index = *index; + let mut insert_index = + must_normalize_index(index, origin_value.values.len()); + for v in &value.values { + origin_value.values.insert(insert_index, v.clone()); + insert_index += 1; + } + } + None => { + for elem in value.values.iter() { + origin_value.values.push(elem.clone()); + } } } } - _ => panic!("only list attribute can be inserted value"), - } + _ => panic!( + "only list attribute can be inserted value, the origin value type is {} and got value type is {}", + origin_value.type_str(), v.type_str() + ), + }; } } } } - self.clone() }; - match (&*self.rc, &*x.rc) { + + // Whether to union schema vars and resolve it and do the check of schema. + let mut union_schema = false; + let mut pkgpath: String = "".to_string(); + let mut name: String = "".to_string(); + let mut common_keys: Vec = vec![]; + let mut args = None; + let mut kwargs = None; + let mut valid = true; + match (&mut *self.rc.borrow_mut(), &*x.rc.borrow()) { (Value::list_value(obj), Value::list_value(delta)) => { - // Clone reference - let mut result_list = self.clone(); - if should_list_override { - return result_list; - } - let length = if obj.values.len() > delta.values.len() { - obj.values.len() - } else { - delta.values.len() - }; - let obj_len = obj.values.len(); - let delta_len = delta.values.len(); - for idx in 0..length { - if idx >= obj_len { - result_list.list_append(&delta.values[idx]); - } else if idx < delta_len { - let value = obj.values[idx].union( - &delta.values[idx], - false, - should_list_override, - should_idempotent_check, - should_config_resolve, - ); - result_list.list_set(idx, &value); + if !opts.list_override { + let length = if obj.values.len() > delta.values.len() { + obj.values.len() + } else { + delta.values.len() + }; + let obj_len = obj.values.len(); + let delta_len = delta.values.len(); + for idx in 0..length { + if idx >= obj_len { + obj.values.push(delta.values[idx].clone()); + } else if idx < delta_len { + obj.values[idx].union( + ctx, + &delta.values[idx], + false, + opts, + union_context, + ); + if union_context.conflict { + union_context.path_backtrace.push(format!("list[{idx}]")); + } + } } } - result_list } (Value::dict_value(obj), Value::dict_value(delta)) => union_fn(obj, delta), (Value::schema_value(obj), Value::dict_value(delta)) => { - let name = &obj.name; - let pkgpath = &obj.pkgpath; - let obj_value = obj.config.as_ref(); - let result = union_fn(obj_value, delta); - let mut common_keys = obj.config_keys.clone(); + name = obj.name.clone(); + pkgpath = obj.pkgpath.clone(); + let obj_value = obj.config.as_mut(); + union_fn(obj_value, delta); + common_keys = obj.config_keys.clone(); let mut other_keys: Vec = delta.values.keys().cloned().collect(); common_keys.append(&mut other_keys); - let schema = result.dict_to_schema(name.as_str(), pkgpath.as_str(), &common_keys); - if should_config_resolve { - resolve_schema(&schema, &common_keys) - } else { - schema - } + args = Some(obj.args.clone()); + kwargs = Some(obj.kwargs.clone()); + union_schema = true; } (Value::schema_value(obj), Value::schema_value(delta)) => { - let name = &obj.name; - let pkgpath = &obj.pkgpath; - let obj_value = obj.config.as_ref(); + name = obj.name.clone(); + pkgpath = obj.pkgpath.clone(); + let obj_value = obj.config.as_mut(); let delta_value = delta.config.as_ref(); - let result = union_fn(obj_value, delta_value); - let mut common_keys = obj.config_keys.clone(); - let mut other_keys = delta.config_keys.clone(); + union_fn(obj_value, delta_value); + common_keys = obj.config_keys.clone(); + let mut other_keys: Vec = delta.config_keys.clone(); common_keys.append(&mut other_keys); - let schema = result.dict_to_schema(name.as_str(), pkgpath.as_str(), &common_keys); - if should_config_resolve { - resolve_schema(&schema, &common_keys) - } else { - schema - } + args = Some(delta.args.clone()); + kwargs = Some(delta.kwargs.clone()); + union_schema = true; } (Value::dict_value(obj), Value::schema_value(delta)) => { - let name = &delta.name; - let pkgpath = &delta.pkgpath; + name = delta.name.clone(); + pkgpath = delta.pkgpath.clone(); let delta_value = delta.config.as_ref(); - let result = union_fn(obj, delta_value); - let mut common_keys = delta.config_keys.clone(); + union_fn(obj, delta_value); + common_keys = delta.config_keys.clone(); let mut other_keys: Vec = obj.values.keys().cloned().collect(); common_keys.append(&mut other_keys); - let schema = - result.dict_to_schema(name.as_str(), pkgpath.as_str(), &delta.config_keys); - if should_config_resolve { - resolve_schema(&schema, &common_keys) - } else { - schema - } + args = Some(delta.args.clone()); + kwargs = Some(delta.kwargs.clone()); + union_schema = true; } - _ => { - panic!( - "union failure, expect {:?}, got {:?}", - self.type_str(), - x.type_str() - ); + _ => valid = false, + } + if !valid { + panic!( + "union failure, expect {:?}, got {:?}", + self.type_str(), + x.type_str() + ) + } + if union_context.conflict { + return self.clone(); + } + if union_schema { + // Override schema arguments and keyword arguments. + let mut result = self.clone(); + if let (Some(args), Some(kwargs)) = (&args, &kwargs) { + result.set_schema_args(args, kwargs); + } + let optional_mapping = if self.is_schema() { + self.schema_optional_mapping() + } else { + x.schema_optional_mapping() + }; + let schema = result.dict_to_schema( + name.as_str(), + pkgpath.as_str(), + &common_keys, + &x.schema_config_meta(), + &optional_mapping, + args, + kwargs, + ); + if opts.config_resolve { + *self = resolve_schema(ctx, &schema, &common_keys); + } else { + *self = schema; } } + self.clone() } - - pub fn union( - &self, + fn union( + &mut self, + ctx: &mut Context, x: &Self, or_mode: bool, - should_list_override: bool, - should_idempotent_check: bool, - should_config_resolve: bool, + opts: &UnionOptions, + union_context: &mut UnionContext, ) -> Self { if self.is_none_or_undefined() { - return x.clone(); + *self = x.clone(); + return self.clone(); } if x.is_none_or_undefined() { return self.clone(); } - match (&*self.rc, &*x.rc) { - ( - Value::list_value(_) | Value::dict_value(_) | Value::schema_value(_), - Value::list_value(_) | Value::dict_value(_) | Value::schema_value(_), - ) => self.do_union( - x, - should_list_override, - should_idempotent_check, - should_config_resolve, - ), - _ => { - if or_mode { - match (&*self.rc, &*x.rc) { - (Value::int_value(a), Value::int_value(b)) => Self::int(*a | *b), - _ => { - panic!( - "unsupported operand type(s) for |: '{:?}' and '{:?}'", - self.type_str(), - x.type_str() - ); - } - } - } else if x.is_none_or_undefined() { - self.clone() - } else { - x.clone() - } + if self.is_list_or_config() && x.is_list_or_config() { + self.do_union(ctx, x, opts, union_context); + } else if or_mode { + if let (Value::int_value(a), Value::int_value(b)) = + (&mut *self.rc.borrow_mut(), &*x.rc.borrow()) + { + *a |= *b; + return self.clone(); + }; + panic!( + "unsupported operand type(s) for |: '{:?}' and '{:?}'", + self.type_str(), + x.type_str() + ) + } else { + *self = x.clone(); + } + self.clone() + } + + pub fn union_entry( + &mut self, + ctx: &mut Context, + x: &Self, + or_mode: bool, + opts: &UnionOptions, + ) -> Self { + let mut union_context = UnionContext::default(); + let ret = self.union(ctx, x, or_mode, opts, &mut union_context); + if union_context.conflict { + union_context.path_backtrace.reverse(); + let conflict_key = union_context.path_backtrace.last().unwrap(); + let path_string = union_context.path_backtrace.join("."); + + // build note + // it will be like: + // {...} | { + // ... + // b = {...} + // ... + // } + + let note = format!( + " {{...}} | {{\n ...\n {} = {}\n ...\n }}", + conflict_key, union_context.delta_json + ); + if conflict_key.is_empty() { + panic!( + "conflicting values between {} and {}", + union_context.delta_json, union_context.obj_json + ); + } else { + panic!( + "conflicting values on the attribute '{}' between :\n {}\nand\n {}\nwith union path :\n {}\ntry operator '=' to override the attribute, like:\n{}", + conflict_key, + union_context.obj_json, + union_context.delta_json, + path_string, + note, + ); } } + ret } } @@ -246,54 +435,56 @@ mod test_value_union { #[test] fn test_list_union() { + let mut ctx = Context::new(); let cases = [ ("[0]", "[1, 2]", "[1, 2]"), ("[1, 2]", "[2]", "[2, 2]"), ("[0, 0]", "[1, 2]", "[1, 2]"), ]; for (left, right, expected) in cases { - let left_value = ValueRef::from_json(left).unwrap(); - let right_value = ValueRef::from_json(right).unwrap(); - let value = left_value.bin_bit_or(&right_value); + let left_value = ValueRef::from_json(&mut ctx, left).unwrap(); + let right_value = ValueRef::from_json(&mut ctx, right).unwrap(); + let value = left_value.bin_bit_or(&mut ctx, &right_value); assert_eq!(value.to_json_string(), expected); } } #[test] fn test_dict_union() { + let mut ctx = Context::new(); let cases = [ ( - vec![("key", "value", ConfigEntryOperationKind::Union, -1)], - vec![("key", "value", ConfigEntryOperationKind::Union, -1)], - vec![("key", "value", ConfigEntryOperationKind::Union, -1)], + vec![("key", "value", ConfigEntryOperationKind::Union, None)], + vec![("key", "value", ConfigEntryOperationKind::Union, None)], + vec![("key", "value", ConfigEntryOperationKind::Union, None)], ), ( - vec![("key", "value", ConfigEntryOperationKind::Override, -1)], - vec![("key", "value", ConfigEntryOperationKind::Override, -1)], - vec![("key", "value", ConfigEntryOperationKind::Override, -1)], + vec![("key", "value", ConfigEntryOperationKind::Override, None)], + vec![("key", "value", ConfigEntryOperationKind::Override, None)], + vec![("key", "value", ConfigEntryOperationKind::Override, None)], ), ( - vec![("key", "value1", ConfigEntryOperationKind::Union, -1)], - vec![("key", "value2", ConfigEntryOperationKind::Override, -1)], - vec![("key", "value2", ConfigEntryOperationKind::Override, -1)], + vec![("key", "value1", ConfigEntryOperationKind::Union, None)], + vec![("key", "value2", ConfigEntryOperationKind::Override, None)], + vec![("key", "value2", ConfigEntryOperationKind::Override, None)], ), ( vec![ - ("key1", "value1", ConfigEntryOperationKind::Union, -1), - ("key2", "value2", ConfigEntryOperationKind::Union, -1), + ("key1", "value1", ConfigEntryOperationKind::Union, None), + ("key2", "value2", ConfigEntryOperationKind::Union, None), ], vec![ ( "key1", "override_value1", ConfigEntryOperationKind::Override, - -1, + None, ), ( "key2", "override_value2", ConfigEntryOperationKind::Override, - -1, + None, ), ], vec![ @@ -301,13 +492,13 @@ mod test_value_union { "key1", "override_value1", ConfigEntryOperationKind::Override, - -1, + None, ), ( "key2", "override_value2", ConfigEntryOperationKind::Override, - -1, + None, ), ], ), @@ -316,71 +507,274 @@ mod test_value_union { let mut left_value = ValueRef::dict(None); let mut right_value = ValueRef::dict(None); for (key, val, op, index) in left_entries { - left_value.dict_update_entry(key, &ValueRef::str(val), &op, &index); + left_value.dict_update_entry(key, &ValueRef::str(val), &op, index); } for (key, val, op, index) in right_entries { - right_value.dict_update_entry(key, &ValueRef::str(val), &op, &index); + right_value.dict_update_entry(key, &ValueRef::str(val), &op, index); } - let result = left_value.bin_bit_or(&right_value); + let result = left_value.bin_bit_or(&mut ctx, &right_value); for (key, val, op, index) in expected { let result_dict = result.as_dict_ref(); let result_val = result_dict.values.get(key).unwrap().as_str(); let result_op = result_dict.ops.get(key).unwrap(); - let result_index = result_dict.insert_indexs.get(key).unwrap(); + let result_index = result_dict.insert_indexs.get(key); assert_eq!(result_val, val); assert_eq!(*result_op, op); - assert_eq!(*result_index, index); + assert_eq!(result_index.cloned(), index); } } } #[test] fn test_dict_union_insert() { + let mut ctx = Context::new(); let cases = [ ( - vec![("key", vec![0, 1], ConfigEntryOperationKind::Override, -1)], - vec![("key", vec![2, 3], ConfigEntryOperationKind::Insert, -1)], + vec![("key", vec![0, 1], ConfigEntryOperationKind::Override, None)], + vec![("key", vec![2, 3], ConfigEntryOperationKind::Insert, None)], vec![( "key", vec![0, 1, 2, 3], ConfigEntryOperationKind::Insert, - -1, + None, )], ), ( - vec![("key", vec![0, 1], ConfigEntryOperationKind::Override, -1)], - vec![("key", vec![2, 3], ConfigEntryOperationKind::Insert, 0)], - vec![("key", vec![2, 3, 0, 1], ConfigEntryOperationKind::Insert, 0)], + vec![("key", vec![0, 1], ConfigEntryOperationKind::Override, None)], + vec![("key", vec![2, 3], ConfigEntryOperationKind::Insert, Some(0))], + vec![( + "key", + vec![2, 3, 0, 1], + ConfigEntryOperationKind::Insert, + Some(0), + )], ), ( - vec![("key", vec![0, 1], ConfigEntryOperationKind::Override, -1)], - vec![("key", vec![2, 3], ConfigEntryOperationKind::Insert, 1)], - vec![("key", vec![0, 2, 3, 1], ConfigEntryOperationKind::Insert, 1)], + vec![("key", vec![0, 1], ConfigEntryOperationKind::Override, None)], + vec![("key", vec![2, 3], ConfigEntryOperationKind::Insert, Some(1))], + vec![( + "key", + vec![0, 2, 3, 1], + ConfigEntryOperationKind::Insert, + Some(1), + )], ), ]; for (left_entries, right_entries, expected) in cases { let mut left_value = ValueRef::dict(None); let mut right_value = ValueRef::dict(None); for (key, val, op, index) in left_entries { - left_value.dict_update_entry(key, &ValueRef::list_int(val.as_slice()), &op, &index); + left_value.dict_update_entry(key, &ValueRef::list_int(val.as_slice()), &op, index); } for (key, val, op, index) in right_entries { right_value.dict_update_entry( key, &ValueRef::list_int(val.as_slice()), &op, - &index, + index.as_ref(), ); } - let result = left_value.bin_bit_or(&right_value); + let result = left_value.bin_bit_or(&mut ctx, &right_value); for (key, val, op, index) in expected { let result_dict = result.as_dict_ref(); let result_val = result_dict.values.get(key).unwrap(); let result_op = result_dict.ops.get(key).unwrap(); - let result_index = result_dict.insert_indexs.get(key).unwrap(); + let result_index = result_dict.insert_indexs.get(key); assert_eq!(result_val.clone(), ValueRef::list_int(val.as_slice())); assert_eq!(*result_op, op); - assert_eq!(*result_index, index); + assert_eq!(result_index.cloned(), index); + } + } + } + + #[test] + fn test_dict_union_same_ref() { + let mut ctx = Context::new(); + let cases = [ + ( + vec![("key1", "value", ConfigEntryOperationKind::Union, None)], + vec![("key1", "value", ConfigEntryOperationKind::Union, None)], + vec![("key2", "value", ConfigEntryOperationKind::Union, None)], + vec![ + ("key1", "value", ConfigEntryOperationKind::Union, None), + ("key2", "value", ConfigEntryOperationKind::Union, None), + ], + ), + ( + vec![("key1", "value1", ConfigEntryOperationKind::Override, None)], + vec![("key1", "value2", ConfigEntryOperationKind::Override, None)], + vec![("key2", "value", ConfigEntryOperationKind::Override, None)], + vec![ + ("key1", "value2", ConfigEntryOperationKind::Override, None), + ("key2", "value", ConfigEntryOperationKind::Override, None), + ], + ), + ( + vec![("key1", "value1", ConfigEntryOperationKind::Union, None)], + vec![("key1", "value2", ConfigEntryOperationKind::Override, None)], + vec![("key2", "value", ConfigEntryOperationKind::Override, None)], + vec![ + ("key1", "value2", ConfigEntryOperationKind::Override, None), + ("key2", "value", ConfigEntryOperationKind::Override, None), + ], + ), + ( + vec![ + ("key1", "value1", ConfigEntryOperationKind::Union, None), + ("key2", "value2", ConfigEntryOperationKind::Union, None), + ], + vec![ + ( + "key1", + "override_value1", + ConfigEntryOperationKind::Override, + None, + ), + ( + "key2", + "override_value2", + ConfigEntryOperationKind::Override, + None, + ), + ], + vec![("key3", "value", ConfigEntryOperationKind::Union, None)], + vec![ + ( + "key1", + "override_value1", + ConfigEntryOperationKind::Override, + None, + ), + ( + "key2", + "override_value2", + ConfigEntryOperationKind::Override, + None, + ), + ("key3", "value", ConfigEntryOperationKind::Union, None), + ], + ), + ]; + for (left_entries, right_entries, both_entries, expected) in cases { + let mut left_value = ValueRef::dict(None); + let mut right_value = ValueRef::dict(None); + for (key, val, op, index) in left_entries { + left_value.dict_update_entry(key, &ValueRef::str(val), &op, index); + } + for (key, val, op, index) in right_entries { + right_value.dict_update_entry(key, &ValueRef::str(val), &op, index); + } + for (key, val, op, index) in both_entries { + let both_val = ValueRef::str(val); + left_value.dict_update_entry(key, &both_val, &op, index); + left_value.dict_update_entry(key, &both_val, &op, index); + } + let result = left_value.bin_bit_or(&mut ctx, &right_value); + for (key, val, op, index) in expected { + let result_dict = result.as_dict_ref(); + let result_val = result_dict.values.get(key).unwrap().as_str(); + let result_op = result_dict.ops.get(key).unwrap(); + let result_index = result_dict.insert_indexs.get(key); + assert_eq!(result_val, val); + assert_eq!(*result_op, op); + assert_eq!(result_index, index); } } } + + #[test] + fn test_dict_union_conflict_attr() { + let pre_hook = std::panic::take_hook(); + std::panic::set_hook(Box::new(|_| {})); + let cases = [ + ( + r#"{"key" : "value"}"#, + r#"{"key" : "value1"}"#, + r#"conflicting values on the attribute 'key' between : + "value" +and + "value1" +with union path : + key +try operator '=' to override the attribute, like: + {...} | { + ... + key = "value1" + ... + }"#, + ), + ( + r#"[{"key" : "value"}]"#, + r#"[{"key" : "value1"}]"#, + r#"conflicting values on the attribute 'key' between : + "value" +and + "value1" +with union path : + list[0].key +try operator '=' to override the attribute, like: + {...} | { + ... + key = "value1" + ... + }"#, + ), + ( + r#"{"key1" : { "key2" : 3 }}"#, + r#"{"key1" : { "key2" : 4 }}"#, + r#"conflicting values on the attribute 'key2' between : + 3 +and + 4 +with union path : + key1.key2 +try operator '=' to override the attribute, like: + {...} | { + ... + key2 = 4 + ... + }"#, + ), + ( + r#"{"key1" : { "key2" : 3 }}"#, + r#"{"key1" : [1,2,3]}"#, + r#"conflicting values on the attribute 'key1' between : + {...} +and + [...] +with union path : + key1 +try operator '=' to override the attribute, like: + {...} | { + ... + key1 = [...] + ... + }"#, + ), + ( + r#"{"key1" : [1,2,3]}"#, + r#"{"key1" : { "key2" : 3 }}"#, + r#"conflicting values on the attribute 'key1' between : + [...] +and + {...} +with union path : + key1 +try operator '=' to override the attribute, like: + {...} | { + ... + key1 = {...} + ... + }"#, + ), + ]; + for (left, right, expected) in cases { + assert_panic(expected, || { + let mut ctx = Context::new(); + let left_value = ValueRef::from_json(&mut ctx, left).unwrap(); + let right_value = ValueRef::from_json(&mut ctx, right).unwrap(); + left_value.bin_bit_or(&mut ctx, &right_value); + }); + } + std::panic::set_hook(pre_hook); + } } diff --git a/kclvm/runtime/src/value/val_yaml.rs b/kclvm/runtime/src/value/val_yaml.rs index eaca4e9fc..2b2d8e80d 100644 --- a/kclvm/runtime/src/value/val_yaml.rs +++ b/kclvm/runtime/src/value/val_yaml.rs @@ -1,24 +1,85 @@ -// Copyright 2021 The KCL Authors. All rights reserved. +//! Copyright The KCL Authors. All rights reserved. extern crate serde_json; extern crate serde_yaml; use crate::*; -#[derive(Debug, Default)] +use serde::{Deserialize, Serialize}; + +/// YAML encode options. +/// - sort_keys: Sort the encode result by keys (defaults to false). +/// - ignore_private: Whether to ignore the attribute whose name starts with +/// a character `_` (defaults to false). +/// - ignore_none: Whether to ignore the attribute whose value is `None` (defaults to false). +/// - sep: Which separator to use between YAML documents (defaults to "---"). +/// +/// TODO: We have not yet supported the following options because serde_yaml +/// does not support these capabilities yet. +/// Ref: https://github.com/dtolnay/serde-yaml/issues/337 +/// - indent: Which kind of indentation to use when emitting (defaults to 2). +/// - width: The character width to use when folding text (defaults to 80). +/// - use_fold: Force folding of text when emitting (defaults to false). +/// - use_block: Force all text to be literal when emitting (defaults to false). +/// - use_version: Display the YAML version when emitting (defaults to false). +/// - use_header: Display the YAML header when emitting (defaults to false). +#[derive(Debug, Serialize, Deserialize)] pub struct YamlEncodeOptions { pub sort_keys: bool, pub ignore_private: bool, pub ignore_none: bool, + pub sep: String, +} + +impl Default for YamlEncodeOptions { + fn default() -> Self { + Self { + sort_keys: false, + ignore_private: false, + ignore_none: false, + sep: "---".to_string(), + } + } } impl ValueRef { - pub fn from_yaml(s: &str) -> Option { - let json_value: serde_json::Value = serde_yaml::from_str(s).unwrap(); - match serde_json::to_string(&json_value) { - Ok(s) => Self::from_json(s.as_ref()), - _ => None, + /// Decode a yaml single document string to a ValueRef. + /// Returns [serde_yaml::Error] when decoding fails. + pub fn from_yaml(ctx: &mut Context, s: &str) -> Result { + // We use JsonValue to implement the KCL universal serialization object. + let json_value: JsonValue = serde_yaml::from_str(s)?; + Ok(Self::from_json(ctx, serde_json::to_string(&json_value).unwrap().as_ref()).unwrap()) + } + + /// Decode yaml stream string that contains `---` to a ValueRef. + /// Returns [serde_yaml::Error] when decoding fails. + pub fn from_yaml_stream(ctx: &mut Context, s: &str) -> Result { + let documents = serde_yaml::Deserializer::from_str(s); + let mut result = ValueRef::list_value(None); + for document in documents { + let json_value: JsonValue = JsonValue::deserialize(document)?; + result.list_append(&ValueRef::parse_json(ctx, &json_value)) + } + if result.is_empty() { + // Empty result returns a empty dict. + Ok(ValueRef::dict(None)) + } else if result.len() == 1 { + Ok(result.list_get(0).unwrap()) + } else { + Ok(result) + } + } + + /// Decode yaml stream string that contains `---` to a ValueRef. + /// Returns [serde_yaml::Error] when decoding fails. + pub fn list_from_yaml_stream(ctx: &mut Context, s: &str) -> Result { + let documents = serde_yaml::Deserializer::from_str(s); + let mut result = ValueRef::list_value(None); + for document in documents { + let json_value: JsonValue = JsonValue::deserialize(document)?; + result.list_append(&ValueRef::parse_json(ctx, &json_value)) } + Ok(result) } pub fn to_yaml(&self) -> Vec { @@ -42,115 +103,23 @@ impl ValueRef { } } - pub fn to_yaml_string_with_options(&self, opt: &YamlEncodeOptions) -> String { - let x = self.yaml_clone_with_filter(opt); - x.to_yaml_string() - } - - fn yaml_clone_with_filter(&self, opt: &YamlEncodeOptions) -> Self { - match &*self.rc { - Value::undefined => ValueRef::undefined(), - Value::none => ValueRef::none(), - - Value::bool_value(ref v) => ValueRef::bool(*v), - Value::int_value(ref v) => ValueRef::int(*v), - Value::float_value(ref v) => ValueRef::float(*v), - Value::str_value(ref v) => ValueRef::str(v.as_ref()), - Value::unit_value(ref v, ref raw, ref unit) => ValueRef::unit(*v, *raw, unit), - Value::list_value(ref v) => { - let mut list = ValueRef::list(None); - for x in v.values.iter() { - match *x.rc { - Value::undefined => { - continue; - } - Value::none => { - if !opt.ignore_none { - list.list_append(&x.yaml_clone_with_filter(opt)); - } - } - Value::func_value(_) => { - // ignore func - } - _ => { - list.list_append(&x.yaml_clone_with_filter(opt)); - } - } - } - list - } - Value::dict_value(ref v) => { - let mut dict = ValueRef::dict(None); - for (key, val) in v.values.iter() { - if opt.ignore_private && (*key).starts_with(KCL_PRIVATE_VAR_PREFIX) { - continue; - } - match *val.rc { - Value::undefined => { - continue; - } - Value::none => { - if !opt.ignore_none { - dict.dict_insert( - key, - &val.yaml_clone_with_filter(opt), - Default::default(), - 0, - ); - } - } - Value::func_value(_) => { - // ignore func - } - _ => { - dict.dict_insert( - key, - &val.yaml_clone_with_filter(opt), - Default::default(), - 0, - ); - } - } - } - dict - } - - Value::schema_value(ref v) => { - let mut dict = ValueRef::dict(None); - for (key, val) in v.config.values.iter() { - if opt.ignore_private && (*key).starts_with(KCL_PRIVATE_VAR_PREFIX) { - continue; - } - match *val.rc { - Value::undefined => { - continue; - } - Value::none => { - if !opt.ignore_none { - dict.dict_insert( - key, - &val.yaml_clone_with_filter(opt), - Default::default(), - 0, - ); - } - } - Value::func_value(_) => { - // ignore func - } - _ => { - dict.dict_insert( - key, - &val.yaml_clone_with_filter(opt), - Default::default(), - 0, - ); - } - } - } - dict + pub fn to_yaml_string_with_options(&self, opts: &YamlEncodeOptions) -> String { + // convert Value to json in order to reuse + // "crate::val_json::JsonValue" to customize the serialized results + let json_opts = JsonEncodeOptions { + sort_keys: opts.sort_keys, + indent: 0, + ignore_private: opts.ignore_private, + ignore_none: opts.ignore_none, + }; + let json = self.to_json_string_with_options(&json_opts); + let yaml_value: serde_yaml::Value = serde_json::from_str(json.as_ref()).unwrap(); + match serde_yaml::to_string(&yaml_value) { + Ok(s) => { + let s = s.strip_prefix("---\n").unwrap_or_else(|| s.as_ref()); + s.to_string() } - Value::func_value(_) => ValueRef::undefined(), + Err(err) => panic!("{}", err), } } } @@ -159,8 +128,15 @@ impl ValueRef { mod test_value_yaml { use crate::*; + #[test] + fn test_serde_yaml_on_str() { + let on_str = serde_yaml::to_string("on").unwrap(); + assert_eq!(on_str, "'on'\n"); + } + #[test] fn test_value_from_yaml() { + let mut ctx = Context::new(); let cases = [ ("a: 1\n", ValueRef::dict(Some(&[("a", &ValueRef::int(1))]))), ( @@ -174,10 +150,76 @@ mod test_value_yaml { ("b", &ValueRef::str("s")), ])), ), + // This case is to test that the `from_yaml` function does not change + // the order of dictionary keys. + ( + "b: [1, 2, 3]\na: \"s\"\n", + ValueRef::dict(Some(&[ + ("b", &ValueRef::list_int(&[1, 2, 3])), + ("a", &ValueRef::str("s")), + ])), + ), + ]; + for (yaml_str, expected) in cases { + let result = ValueRef::from_yaml(&mut ctx, yaml_str); + assert_eq!(result.unwrap(), expected); + } + } + + #[test] + fn test_value_from_yaml_fail() { + let mut ctx = Context::new(); + let cases = [ + ( + "a: 1\n b: 2\nc: 3", + "mapping values are not allowed in this context at line 2 column 4", + ), + ( + "a:\n- 1\n -2\n-3", + "could not find expected ':' at line 5 column 1, while scanning a simple key at line 4 column 1", + ), + ]; + for (yaml_str, expected) in cases { + let result = ValueRef::from_yaml(&mut ctx, yaml_str); + assert_eq!(result.err().unwrap().to_string(), expected); + } + } + + #[test] + fn test_value_from_yaml_stream() { + let mut ctx = Context::new(); + let cases = [ + ("a: 1\n", ValueRef::dict(Some(&[("a", &ValueRef::int(1))]))), + ( + "a: 1\nb: 2\n---\nb: 1\na: 2\n", + ValueRef::list_value(Some(&[ + ValueRef::dict(Some(&[("a", &ValueRef::int(1)), ("b", &ValueRef::int(2))])), + ValueRef::dict(Some(&[("b", &ValueRef::int(1)), ("a", &ValueRef::int(2))])), + ])), + ), + ]; + for (yaml_str, expected) in cases { + let result = ValueRef::from_yaml_stream(&mut ctx, yaml_str); + assert_eq!(result.unwrap(), expected); + } + } + + #[test] + fn test_value_from_yaml_stream_fail() { + let mut ctx = Context::new(); + let cases = [ + ( + "a: 1\n---\na: 1\n b: 2\nc: 3", + "mapping values are not allowed in this context at line 4 column 4", + ), + ( + "b:3\n---\na:\n- 1\n -2\n-3", + "could not find expected ':' at line 7 column 1, while scanning a simple key at line 6 column 1", + ), ]; for (yaml_str, expected) in cases { - let result = ValueRef::from_yaml(yaml_str); - assert_eq!(result, Some(expected)); + let result = ValueRef::from_yaml_stream(&mut ctx, yaml_str); + assert_eq!(result.err().unwrap().to_string(), expected); } } @@ -194,7 +236,7 @@ mod test_value_yaml { ("a", &ValueRef::list_int(&[1, 2, 3])), ("b", &ValueRef::str("s")), ])), - "a:\n - 1\n - 2\n - 3\nb: s\n", + "a:\n- 1\n- 2\n- 3\nb: s\n", ), ]; for (value, expected) in cases { @@ -202,4 +244,67 @@ mod test_value_yaml { assert_eq!(result, expected); } } + + #[test] + fn test_value_to_yaml_string_with_opts() { + let cases = [ + ( + ValueRef::dict(Some(&[("b", &ValueRef::int(2)), ("a", &ValueRef::int(1))])), + "a: 1\nb: 2\n", + YamlEncodeOptions { + sort_keys: true, + ignore_private: false, + ignore_none: false, + sep: "---".to_string(), + }, + ), + ( + ValueRef::dict(Some(&[("b", &ValueRef::int(2)), ("a", &ValueRef::int(1))])), + "b: 2\na: 1\n", + YamlEncodeOptions { + sort_keys: false, + ignore_private: false, + ignore_none: false, + sep: "---".to_string(), + }, + ), + ( + ValueRef::dict(Some(&[("_b", &ValueRef::int(2)), ("a", &ValueRef::int(1))])), + "a: 1\n", + YamlEncodeOptions { + sort_keys: false, + ignore_private: true, + ignore_none: false, + sep: "---".to_string(), + }, + ), + ( + ValueRef::dict(Some(&[("b", &ValueRef::none()), ("a", &ValueRef::int(1))])), + "a: 1\n", + YamlEncodeOptions { + sort_keys: false, + ignore_private: true, + ignore_none: true, + sep: "---".to_string(), + }, + ), + ( + ValueRef::dict(Some(&[ + ("b", &ValueRef::list_int(&[1, 2, 3])), + ("a", &ValueRef::str("s")), + ])), + "a: s\nb:\n- 1\n- 2\n- 3\n", + YamlEncodeOptions { + sort_keys: true, + ignore_private: false, + ignore_none: false, + sep: "---".to_string(), + }, + ), + ]; + for (value, expected, opts) in cases { + let result = ValueRef::to_yaml_string_with_options(&value, &opts); + assert_eq!(result, expected); + } + } } diff --git a/kclvm/runtime/src/value/walker.rs b/kclvm/runtime/src/value/walker.rs new file mode 100644 index 000000000..f3f233580 --- /dev/null +++ b/kclvm/runtime/src/value/walker.rs @@ -0,0 +1,47 @@ +use crate::{Value, ValueRef}; + +/// Walk the value recursively and deal the type using the `walk_fn` +pub fn walk_value(val: &ValueRef, walk_fn: &impl Fn(&ValueRef)) { + walk_fn(val); + match &*val.rc.borrow() { + Value::list_value(list_value) => { + for v in &list_value.values { + walk_value(v, walk_fn); + } + } + Value::dict_value(dict_value) => { + for (_, v) in &dict_value.values { + walk_value(v, walk_fn); + } + } + Value::schema_value(schema_value) => { + for (_, v) in &schema_value.config.values { + walk_value(v, walk_fn); + } + } + _ => {} + } +} + +/// Walk the value recursively and mutably and deal the type using the `walk_fn` +pub fn walk_value_mut(val: &ValueRef, walk_fn: &mut impl FnMut(&ValueRef)) { + walk_fn(val); + match &*val.rc.borrow() { + Value::list_value(list_value) => { + for v in &list_value.values { + walk_value_mut(v, walk_fn); + } + } + Value::dict_value(dict_value) => { + for (_, v) in &dict_value.values { + walk_value_mut(v, walk_fn); + } + } + Value::schema_value(schema_value) => { + for (_, v) in &schema_value.config.values { + walk_value_mut(v, walk_fn); + } + } + _ => {} + } +} diff --git a/kclvm/runtime/src/yaml/mod.rs b/kclvm/runtime/src/yaml/mod.rs index a6dcac071..edcfdf0c2 100644 --- a/kclvm/runtime/src/yaml/mod.rs +++ b/kclvm/runtime/src/yaml/mod.rs @@ -1,4 +1,191 @@ -// Copyright 2021 The KCL Authors. All rights reserved. +//! Copyright The KCL Authors. All rights reserved. +use crate::*; -pub mod yaml; -pub use self::yaml::*; +pub const YAML_STREAM_SEP: &str = "\n---\n"; +pub const JSON_STREAM_SEP: &str = "\n"; + +/// encode(data, sort_keys=False, ignore_private=False, ignore_none=False) +#[no_mangle] +#[runtime_fn] +pub extern "C" fn kclvm_yaml_encode( + ctx: *mut kclvm_context_t, + args: *const kclvm_value_ref_t, + kwargs: *const kclvm_value_ref_t, +) -> *const kclvm_value_ref_t { + let args = ptr_as_ref(args); + let kwargs = ptr_as_ref(kwargs); + + if let Some(arg0) = get_call_arg(args, kwargs, 0, Some("data")) { + let s = ValueRef::str( + arg0.to_yaml_string_with_options(&args_to_opts(args, kwargs, 1)) + .as_ref(), + ); + return s.into_raw(mut_ptr_as_ref(ctx)); + } + panic!("encode_all() missing 1 required positional argument: 'data'") +} + +/// encode_all(data, sort_keys=False, ignore_private=False, ignore_none=False) +#[no_mangle] +#[runtime_fn] +pub extern "C" fn kclvm_yaml_encode_all( + ctx: *mut kclvm_context_t, + args: *const kclvm_value_ref_t, + kwargs: *const kclvm_value_ref_t, +) -> *const kclvm_value_ref_t { + let args = ptr_as_ref(args); + let kwargs = ptr_as_ref(kwargs); + + if let Some(arg0) = get_call_arg(args, kwargs, 0, Some("data")) { + let opts = args_to_opts(args, kwargs, 1); + let results = arg0 + .as_list_ref() + .values + .iter() + .map(|r| r.to_yaml_string_with_options(&opts)) + .collect::>(); + let s = ValueRef::str(&results.join(YAML_STREAM_SEP)); + return s.into_raw(mut_ptr_as_ref(ctx)); + } + panic!("encode() missing 1 required positional argument: 'data'") +} + +/// decode(value) +#[no_mangle] +#[runtime_fn] +pub extern "C" fn kclvm_yaml_decode( + ctx: *mut kclvm_context_t, + args: *const kclvm_value_ref_t, + kwargs: *const kclvm_value_ref_t, +) -> *const kclvm_value_ref_t { + let args = ptr_as_ref(args); + let kwargs = ptr_as_ref(kwargs); + let ctx = mut_ptr_as_ref(ctx); + + if let Some(arg0) = get_call_arg(args, kwargs, 0, Some("value")) { + match ValueRef::from_yaml(ctx, arg0.as_str().as_ref()) { + Ok(x) => return x.into_raw(ctx), + Err(err) => panic!("{}", err), + } + } + panic!("decode() missing 1 required positional argument: 'value'") +} + +/// decode_all(value) +#[no_mangle] +#[runtime_fn] +pub extern "C" fn kclvm_yaml_decode_all( + ctx: *mut kclvm_context_t, + args: *const kclvm_value_ref_t, + kwargs: *const kclvm_value_ref_t, +) -> *const kclvm_value_ref_t { + let args = ptr_as_ref(args); + let kwargs = ptr_as_ref(kwargs); + let ctx = mut_ptr_as_ref(ctx); + + if let Some(arg0) = get_call_arg(args, kwargs, 0, Some("value")) { + match ValueRef::list_from_yaml_stream(ctx, arg0.as_str().as_ref()) { + Ok(x) => return x.into_raw(ctx), + Err(err) => panic!("{}", err), + } + } + panic!("decode_all() missing 1 required positional argument: 'value'") +} + +/// dump_to_file(data, sort_keys=False, ignore_private=False, ignore_none=False) +#[no_mangle] +#[runtime_fn] +pub extern "C" fn kclvm_yaml_dump_to_file( + ctx: *mut kclvm_context_t, + args: *const kclvm_value_ref_t, + kwargs: *const kclvm_value_ref_t, +) -> *const kclvm_value_ref_t { + let args = ptr_as_ref(args); + let kwargs = ptr_as_ref(kwargs); + let data = args.arg_i(0).or(kwargs.get_by_key("data")); + let filename = args.arg_i(1).or(kwargs.get_by_key("filename")); + match (data, filename) { + (Some(data), Some(filename)) => { + let filename = filename.as_str(); + + let yaml = data.to_yaml_string_with_options(&args_to_opts(args, kwargs, 2)); + std::fs::write(&filename, yaml) + .unwrap_or_else(|e| panic!("Unable to write file '{}': {}", filename, e)); + kclvm_value_Undefined(ctx) + } + _ => { + panic!("dump_to_file() missing 2 required positional arguments: 'data' and 'filename'") + } + } +} + +/// dump_all_to_file(data, sort_keys=False, ignore_private=False, ignore_none=False) +#[no_mangle] +#[runtime_fn] +pub extern "C" fn kclvm_yaml_dump_all_to_file( + ctx: *mut kclvm_context_t, + args: *const kclvm_value_ref_t, + kwargs: *const kclvm_value_ref_t, +) -> *const kclvm_value_ref_t { + let args = ptr_as_ref(args); + let kwargs = ptr_as_ref(kwargs); + + let data = args.arg_i(0).or(kwargs.get_by_key("data")); + let filename = args.arg_i(1).or(kwargs.get_by_key("filename")); + match (data, filename) { + (Some(data), Some(filename)) => { + let filename = filename.as_str(); + let opts = args_to_opts(args, kwargs, 2); + let results = data + .as_list_ref() + .values + .iter() + .map(|r| r.to_yaml_string_with_options(&opts)) + .collect::>(); + + std::fs::write(filename, results.join(YAML_STREAM_SEP)).expect("Unable to write file"); + kclvm_value_Undefined(ctx) + } + _ => { + panic!( + "dump_all_to_file() missing 2 required positional arguments: 'data' and 'filename'" + ) + } + } +} + +/// validate(value: str) -> bool +#[no_mangle] +#[runtime_fn] +pub extern "C" fn kclvm_yaml_validate( + ctx: *mut kclvm_context_t, + args: *const kclvm_value_ref_t, + kwargs: *const kclvm_value_ref_t, +) -> *const kclvm_value_ref_t { + let args = ptr_as_ref(args); + let kwargs = ptr_as_ref(kwargs); + let ctx = mut_ptr_as_ref(ctx); + + if let Some(arg0) = get_call_arg(args, kwargs, 0, Some("value")) { + match ValueRef::from_yaml_stream(ctx, arg0.as_str().as_ref()) { + Ok(_) => return kclvm_value_True(ctx), + Err(_) => return kclvm_value_False(ctx), + } + } + panic!("validate() missing 1 required positional argument: 'value'") +} + +fn args_to_opts(args: &ValueRef, kwargs: &ValueRef, index: usize) -> YamlEncodeOptions { + let mut opts = YamlEncodeOptions::default(); + if let Some(sort_keys) = get_call_arg_bool(args, kwargs, index, Some("sort_keys")) { + opts.sort_keys = sort_keys; + } + if let Some(ignore_private) = get_call_arg_bool(args, kwargs, index + 1, Some("ignore_private")) + { + opts.ignore_private = ignore_private; + } + if let Some(ignore_none) = get_call_arg_bool(args, kwargs, index + 2, Some("ignore_none")) { + opts.ignore_none = ignore_none; + } + opts +} diff --git a/kclvm/runtime/src/yaml/yaml.rs b/kclvm/runtime/src/yaml/yaml.rs deleted file mode 100644 index 435fed98f..000000000 --- a/kclvm/runtime/src/yaml/yaml.rs +++ /dev/null @@ -1,75 +0,0 @@ -//! KCL yaml system module -//! -//! Copyright 2021 The KCL Authors. All rights reserved. - -use crate::*; - -#[allow(non_camel_case_types)] -type kclvm_value_ref_t = ValueRef; - -// def KMANGLED_encode(data, sort_keys=False, ignore_private=False, ignore_none=False): - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_yaml_encode( - _ctx: *mut kclvm_context_t, - args: *const kclvm_value_ref_t, - kwargs: *const kclvm_value_ref_t, -) -> *const kclvm_value_ref_t { - let args = ptr_as_ref(args); - let kwargs = ptr_as_ref(kwargs); - - let mut opt = YamlEncodeOptions::default(); - if let Some(sort_keys) = kwargs.kwarg_bool("sort_keys", None) { - opt.sort_keys = sort_keys; - } - if let Some(ignore_private) = kwargs.kwarg_bool("ignore_private", None) { - opt.ignore_private = ignore_private; - } - if let Some(ignore_none) = kwargs.kwarg_bool("ignore_none", None) { - opt.ignore_none = ignore_none; - } - - if let Some(arg0) = args.arg_i(0) { - let s = ValueRef::str(arg0.to_yaml_string_with_options(&opt).as_ref()); - return s.into_raw(); - } - panic!("encode() missing 1 required positional argument: 'value'") -} - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_yaml_decode( - _ctx: *mut kclvm_context_t, - args: *const kclvm_value_ref_t, - _kwargs: *const kclvm_value_ref_t, -) -> *const kclvm_value_ref_t { - let args = ptr_as_ref(args); - - if let Some(arg0) = args.arg_i(0) { - if let Some(x) = ValueRef::from_yaml(arg0.as_str().as_ref()) { - return x.into_raw(); - } - } - panic!("decode() missing 1 required positional argument: 'value'") -} - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_yaml_dump_to_file( - _ctx: *mut kclvm_context_t, - args: *const kclvm_value_ref_t, - _kwargs: *const kclvm_value_ref_t, -) -> *const kclvm_value_ref_t { - let args = ptr_as_ref(args); - - if let Some(data) = args.arg_i(0) { - if let Some(filename) = args.arg_i(0) { - let yaml = data.to_yaml_string(); - let filename = filename.as_str(); - - std::fs::write(filename, yaml).expect("Unable to write file"); - } - } - panic!("dump_to_file() missing 2 required positional arguments: 'data' and 'filename'") -} diff --git a/kclvm/runtime/tools/kclvm-runtime-gen-api/Makefile b/kclvm/runtime/tools/kclvm-runtime-gen-api/Makefile deleted file mode 100644 index e5dd18fe0..000000000 --- a/kclvm/runtime/tools/kclvm-runtime-gen-api/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -default: - go run main.go \ - -root=../../src \ - -c-api=../../src/_kclvm.h \ - -ll-api=../../src/_kclvm.ll \ - -rust-api-enum=../../src/_kclvm.rs \ - -rust-api-addr=../../src/_kclvm_addr.rs - - cargo fmt - - llvm-as ../../src/_kclvm.ll diff --git a/kclvm/runtime/tools/kclvm-runtime-gen-api/main.go b/kclvm/runtime/tools/kclvm-runtime-gen-api/main.go deleted file mode 100644 index 34f1e221c..000000000 --- a/kclvm/runtime/tools/kclvm-runtime-gen-api/main.go +++ /dev/null @@ -1,374 +0,0 @@ -// Copyright 2021 The KCL Authors. All rights reserved. - -package main - -import ( - "bytes" - "flag" - "fmt" - "os" - "path/filepath" - "regexp" - "sort" - "strings" - "text/template" -) - -var ( - flagRoot = flag.String("root", ".", "set kclvm-runtime root") - flagGenCApi = flag.String("c-api", "", "set c header file") - flagGenLLApi = flag.String("ll-api", "", "set llvm-ll file") - flagGenRustApiEnum = flag.String("rust-api-enum", "", "set rust-api-enum file") - flagGenRustApiAddr = flag.String("rust-api-addr", "", "set rust-api-addr file") -) - -func main() { - flag.Parse() - - specList := LoadAllApiSpec(*flagRoot) - if filename := *flagGenCApi; filename != "" { - src := genCApi(specList) - if err := os.WriteFile(filename, []byte(src), 0666); err != nil { - panic(err) - } - } - if filename := *flagGenLLApi; filename != "" { - src := genLLApi(specList) - if err := os.WriteFile(filename, []byte(src), 0666); err != nil { - panic(err) - } - } - if filename := *flagGenRustApiEnum; filename != "" { - src := genRustApiEnum(specList) - if err := os.WriteFile(filename, []byte(src), 0666); err != nil { - panic(err) - } - } - if filename := *flagGenRustApiAddr; filename != "" { - src := genRustApiAddr(specList) - if err := os.WriteFile(filename, []byte(src), 0666); err != nil { - panic(err) - } - } -} - -func genCApi(specs []ApiSpec) string { - tmpl, err := template.New("c-api").Parse(tmplCApi) - if err != nil { - panic(err) - } - - var buf bytes.Buffer - err = tmpl.Execute(&buf, specs) - if err != nil { - panic(err) - } - return fmtCode(buf.String()) -} - -func genLLApi(specs []ApiSpec) string { - tmpl, err := template.New("ll-api").Parse(tmplLLApi) - if err != nil { - panic(err) - } - - var buf bytes.Buffer - err = tmpl.Execute(&buf, specs) - if err != nil { - panic(err) - } - return fmtCode(buf.String()) -} - -func genRustApiEnum(specs []ApiSpec) string { - tmpl, err := template.New("rust-api-enum").Parse(tmplRustEnum) - if err != nil { - panic(err) - } - - var buf bytes.Buffer - err = tmpl.Execute(&buf, specs) - if err != nil { - panic(err) - } - return fmtCode(buf.String()) -} - -func genRustApiAddr(specs []ApiSpec) string { - tmpl, err := template.New("rust-api-addr").Parse(tmplRustAddr) - if err != nil { - panic(err) - } - - var buf bytes.Buffer - err = tmpl.Execute(&buf, specs) - if err != nil { - panic(err) - } - return fmtCode(buf.String()) -} - -func fmtCode(s string) string { - for { - if !strings.Contains(s, "\n\n\n") { - s = strings.TrimSpace(s) + "\n" - return s - } - s = strings.ReplaceAll(s, "\n\n\n", "\n\n") - } -} - -// ---------------------------------------------------------------------------- - -const ( - apiSpecPrefix_Name = "// api-spec:" - apiSpecPrefix_CApi = "// api-spec(c):" - apiSpecPrefix_LLApi = "// api-spec(llvm):" -) - -type ApiSpec struct { - File string - Line int - Name string // api-spec: kclvm_context_new - SpecC string // api-spec(c): i32 kclvm_context_new(); - SpecLL string // api-spec(llvm): declare i32* @kclvm_context_new() - IsType bool -} - -func LoadAllApiSpec(root string) []ApiSpec { - m := make(map[string]ApiSpec) - filepath.Walk(root, func(path string, info os.FileInfo, err error) error { - if err != nil { - panic(err) - } - if info.IsDir() { - return nil - } - - if !strings.HasSuffix(path, ".rs") { - return nil - } - - data, err := os.ReadFile(path) - if err != nil { - panic(err) - } - - var spec ApiSpec - for i, line := range strings.Split(string(data), "\n") { - line := strings.TrimSpace(line) - switch { - case strings.HasPrefix(line, apiSpecPrefix_Name): - spec.File = path - spec.Line = i + 1 - spec.Name = strings.TrimSpace(strings.TrimPrefix(line, apiSpecPrefix_Name)) - spec.IsType = strings.HasSuffix(spec.Name, "_t") - case strings.HasPrefix(line, apiSpecPrefix_CApi): - if spec.SpecC != "" { - spec.SpecC += " " - } - spec.SpecC += strings.TrimSpace(strings.TrimPrefix(line, apiSpecPrefix_CApi)) - case strings.HasPrefix(line, apiSpecPrefix_LLApi): - if spec.SpecLL != "" { - spec.SpecLL += " " - } - spec.SpecLL += strings.TrimSpace(strings.TrimPrefix(line, apiSpecPrefix_LLApi)) - default: - if matched, _ := regexp.MatchString(`//\s*api-spec`, line); matched { - panic(fmt.Errorf("%s:%d invalid 'api-spec'", path, i+1)) - } - if spec.Name != "" { - if x, ok := m[spec.Name]; ok { - fmt.Printf("WARN: %s:%d %s api-spec exits (%s:%d)\n", path, i+1, spec.Name, x.File, x.Line) - } - m[spec.Name] = spec - } - spec = ApiSpec{} - } - } - - return nil - }) - - var specs []ApiSpec - for _, x := range m { - specs = append(specs, x) - } - sort.Slice(specs, func(i, j int) bool { - return specs[i].Name < specs[j].Name - }) - return specs -} - -// ---------------------------------------------------------------------------- - -const tmplCApi = ` -{{$specList := .}} - -// Copyright 2021 The KCL Authors. All rights reserved. - -// Auto generated, DONOT EDIT!!! - -#pragma once - -#ifndef _kclvm_h_ -#define _kclvm_h_ - -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -// please keep same as 'kclvm/runtime/src/kind/mod.rs#Kind' - -enum kclvm_kind_t { - Invalid = 0, - - // only for value - - Undefined = 1, - None = 2, - - // for value & type - - Bool = 3, - Int = 4, - Float = 5, - Str = 6, - List = 7, - Dict = 8, - - Schema = 9, - Error = 10, - - // only for type - - Any = 11, - Union = 12, - - BoolLit = 13, - IntLit = 14, - FloatLit = 15, - StrLit = 16, - - Func = 17, - - // max num - - Max = 18, -}; - -{{range $_, $spec := $specList}} -{{if ($spec.IsType)}}{{$spec.SpecC}}{{end}} -{{end}} - -{{range $_, $spec := $specList}} -{{if (not $spec.IsType)}}{{$spec.SpecC}}{{end}} -{{end}} - -#ifdef __cplusplus -} // extern "C" -#endif - -#endif // _kclvm_h_ -` - -// ---------------------------------------------------------------------------- - -const tmplLLApi = ` -{{$specList := .}} - -; Copyright 2021 The KCL Authors. All rights reserved. - -; Auto generated, DONOT EDIT!!! - -{{range $_, $spec := $specList}} -{{if ($spec.IsType)}}{{$spec.SpecLL}}{{end}} -{{end}} - -{{range $_, $spec := $specList}} -{{if (not $spec.IsType)}}{{$spec.SpecLL}}{{end}} -{{end}} - -define void @__kcl_keep_link_runtime(%kclvm_value_ref_t* %_a, %kclvm_context_t* %_b) { - call %kclvm_value_ref_t*() @kclvm_value_None() - ret void -} -` - -// ---------------------------------------------------------------------------- - -const tmplRustEnum = ` -{{$specList := .}} - -// Copyright 2021 The KCL Authors. All rights reserved. - -// Auto generated, DONOT EDIT!!! - -#[allow(dead_code, non_camel_case_types)] -#[derive(Clone, PartialEq, Eq, Debug, Hash)] -pub enum ApiType { - Value, -} - -impl std::fmt::Display for ApiType { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - match self { - ApiType::Value => write!(f, "{:?}", "api::kclvm::Value"), - } - } -} - -impl ApiType { - #[allow(dead_code)] - pub fn name(&self) -> String { - return format!("{:?}", self); - } -} - -#[allow(dead_code, non_camel_case_types)] -#[derive(Clone, PartialEq, Eq, Debug, Hash)] -pub enum ApiFunc { - {{range $_, $spec := $specList}}{{if (not $spec.IsType)}} - {{- $spec.Name}}, - {{end}}{{end}} -} - -impl std::fmt::Display for ApiFunc { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - write!(f, "{:?}", self) - } -} - -impl ApiFunc { - #[allow(dead_code)] - pub fn name(&self) -> String { - return format!("{:?}", self); - } -} -` - -// ---------------------------------------------------------------------------- - -const tmplRustAddr = ` -{{$specList := .}} - -// Copyright 2021 The KCL Authors. All rights reserved. - -// Auto generated, DONOT EDIT!!! - -#[allow(dead_code)] -pub fn _kclvm_get_fn_ptr_by_name(name: &str) -> u64 { - match name { - {{- range $_, $spec := $specList -}}{{if (not $spec.IsType)}} - "{{$spec.Name}}" => crate::{{$spec.Name}} as *const () as u64, - {{- end}}{{end}} - _ => panic!("unknown {}", name), - } -} -` - -// ---------------------------------------------------------------------------- diff --git a/kclvm/runtime/tools/kclvm-runtime-gen-err-type/Makefile b/kclvm/runtime/tools/kclvm-runtime-gen-err-type/Makefile deleted file mode 100644 index 84bc7fbe3..000000000 --- a/kclvm/runtime/tools/kclvm-runtime-gen-err-type/Makefile +++ /dev/null @@ -1,6 +0,0 @@ -# Copyright 2021 The KCL Authors. All rights reserved. - -default: - kclvm ./main.py > ../../src/api/err_type.rs - -clean: diff --git a/kclvm/runtime/tools/kclvm-runtime-gen-err-type/main.py b/kclvm/runtime/tools/kclvm-runtime-gen-err-type/main.py deleted file mode 100644 index c527cdbf0..000000000 --- a/kclvm/runtime/tools/kclvm-runtime-gen-err-type/main.py +++ /dev/null @@ -1,24 +0,0 @@ -# Copyright 2021 The KCL Authors. All rights reserved. - -import kclvm.kcl.error as kcl_error - -# enum -> code -# kcl_error.ErrType.EvaluationError_TYPE.value[0] - -# code -> type -# x = kcl_error.ErrType((6,)) - -print( - """// Copyright 2021 The KCL Authors. All rights reserved. - -// Auto generated, DONOT EDIT!!! - -// python: kclvm.kcl.error.ErrType - -#[derive(Copy, Clone)] -#[allow(non_camel_case_types)] -pub enum ErrType {""" -) -for x in kcl_error.ErrType: - print(f" {x.name} = {x.value[0]},") -print("}") diff --git a/kclvm/rustfmt.toml b/kclvm/rustfmt.toml new file mode 100644 index 000000000..2fe8665e9 --- /dev/null +++ b/kclvm/rustfmt.toml @@ -0,0 +1,3 @@ +newline_style = "Unix" +use_field_init_shorthand = true +use_try_shorthand = true diff --git a/kclvm/sema/Cargo.lock b/kclvm/sema/Cargo.lock index 1c73922e3..14fd9529f 100644 --- a/kclvm/sema/Cargo.lock +++ b/kclvm/sema/Cargo.lock @@ -28,6 +28,12 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d78ea013094e5ea606b1c05fe35f1dd7ea1eb1ea259908d040b25bd5ec677ee5" +[[package]] +name = "anyhow" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "224afbd727c3d6e4b90103ece64b8d1b67fbb1973b1046c2281eed3f3803f800" + [[package]] name = "arrayvec" version = "0.7.2" @@ -110,9 +116,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.9.1" +version = "3.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a45a46ab1f2412e53d3a0ade76ffad2025804294569aae387231a0cd6e0899" +checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535" [[package]] name = "cast" @@ -484,13 +490,9 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "json_minimal" -version = "0.1.3" - [[package]] name = "kclvm-ast" -version = "0.1.0" +version = "0.4.5" dependencies = [ "kclvm-span", "rustc_span", @@ -500,9 +502,10 @@ dependencies = [ [[package]] name = "kclvm-config" -version = "0.1.0" +version = "0.4.5" dependencies = [ "ahash", + "anyhow", "chrono", "fslock", "glob", @@ -518,7 +521,7 @@ dependencies = [ [[package]] name = "kclvm-error" -version = "0.1.0" +version = "0.4.5" dependencies = [ "annotate-snippets", "atty", @@ -533,7 +536,7 @@ dependencies = [ [[package]] name = "kclvm-lexer" -version = "0.1.0" +version = "0.4.5" dependencies = [ "kclvm-error", "rustc_lexer", @@ -542,7 +545,7 @@ dependencies = [ [[package]] name = "kclvm-macros" -version = "0.1.0" +version = "0.4.5" dependencies = [ "proc-macro2", "quote", @@ -552,7 +555,7 @@ dependencies = [ [[package]] name = "kclvm-parser" -version = "0.1.0" +version = "0.4.5" dependencies = [ "bstr", "either", @@ -576,7 +579,7 @@ dependencies = [ [[package]] name = "kclvm-runtime" -version = "0.1.0" +version = "0.4.5" dependencies = [ "ahash", "base64", @@ -585,7 +588,6 @@ dependencies = [ "fancy-regex", "indexmap", "itertools", - "json_minimal", "kclvm_runtime_internal_macros", "libc", "md5", @@ -604,7 +606,7 @@ dependencies = [ [[package]] name = "kclvm-sema" -version = "0.1.0" +version = "0.4.5" dependencies = [ "ahash", "bit-set", @@ -625,7 +627,7 @@ dependencies = [ [[package]] name = "kclvm-span" -version = "0.1.0" +version = "0.4.5" dependencies = [ "kclvm-macros", "rustc_span", @@ -634,11 +636,11 @@ dependencies = [ [[package]] name = "kclvm-version" -version = "0.1.0" +version = "0.4.5" [[package]] name = "kclvm_runtime_internal_macros" -version = "0.1.0" +version = "0.4.5" dependencies = [ "proc-macro2", "quote", @@ -1262,9 +1264,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.79" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e8d9fa5c3b304765ce1fd9c4c8a3de2c8db365a5b91be52f186efc675681d95" +checksum = "41feea4228a6f1cd09ec7a3593a682276702cd67b5273544757dae23c096f074" dependencies = [ "itoa 1.0.1", "ryu", diff --git a/kclvm/sema/Cargo.toml b/kclvm/sema/Cargo.toml index 4eb251eba..966215911 100644 --- a/kclvm/sema/Cargo.toml +++ b/kclvm/sema/Cargo.toml @@ -1,11 +1,14 @@ [package] name = "kclvm-sema" -version = "0.1.0" +version = "0.11.0" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +serde_json = "1.0" +serde = { version = "1", features = ["derive"] } +generational-arena = "0.2.9" phf = { version = "0.9", features = ["macros"] } ahash = "0.7.2" indexmap = "1.0" @@ -15,16 +18,27 @@ once_cell = "1.5.2" fancy-regex = "0.7.1" unicode_names2 = "0.4" petgraph = "0.6.0" -kclvm-ast = {path = "../ast", version = "0.1.0"} -kclvm-runtime = {path = "../runtime", version = "0.1.0"} -kclvm-error = {path = "../error", version = "0.1.0"} -kclvm-span = {path = "../span", version = "0.1.0"} +anyhow = "1.0" +regex = "1.7.0" +lazy_static = "1.4.0" + +kclvm-ast = { path = "../ast" } +kclvm-ast-pretty = { path = "../ast_pretty" } +kclvm-runtime = { path = "../runtime" } +kclvm-error = { path = "../error" } +kclvm-span = { path = "../span" } +kclvm-utils = { path = "../utils" } +compiler_base_span = "0.1.2" +compiler_base_session = "0.1.3" +compiler_base_macros = "0.1.1" +compiler_base_error = "0.1.6" +suggestions = "0.1.1" +parking_lot = { version = "0.12.0", default-features = false } [dev-dependencies] -kclvm-parser = {path = "../parser", version = "0.1.0"} -criterion = "0.3" +kclvm-parser = { path = "../parser" } +criterion = "0.5" [[bench]] name = "my_benchmark" harness = false - diff --git a/kclvm/sema/benches/my_benchmark.rs b/kclvm/sema/benches/my_benchmark.rs index 5b0bc6fbf..309d22094 100644 --- a/kclvm/sema/benches/my_benchmark.rs +++ b/kclvm/sema/benches/my_benchmark.rs @@ -1,14 +1,19 @@ -use criterion::{black_box, criterion_group, criterion_main, Criterion}; +use criterion::{criterion_group, criterion_main, Criterion}; use kclvm_sema::ty::*; +use std::sync::Arc; + pub fn criterion_benchmark(c: &mut Criterion) { c.bench_function("sup", |b| { b.iter(|| { let types = vec![ - Type::int_lit(1), - Type::INT, - Type::union(&[Type::STR, Type::dict(Type::STR, Type::STR)]), - Type::dict(Type::ANY, Type::ANY), + Arc::new(Type::int_lit(1)), + Arc::new(Type::INT), + Arc::new(Type::union(&[ + Arc::new(Type::STR), + Arc::new(Type::dict(Arc::new(Type::STR), Arc::new(Type::STR))), + ])), + Arc::new(Type::dict(Arc::new(Type::ANY), Arc::new(Type::ANY))), ]; sup(&types); }) diff --git a/kclvm/sema/src/advanced_resolver/mod.rs b/kclvm/sema/src/advanced_resolver/mod.rs new file mode 100644 index 000000000..b10039cff --- /dev/null +++ b/kclvm/sema/src/advanced_resolver/mod.rs @@ -0,0 +1,1557 @@ +/* + + core::Namer basic_resolver + │ │ + ▼ ▼ + ┌─────────────────────┐ ┌─────────────────────┐ + │ core::GlobalState │ │ ast_node_type_map │ + └─────────────────────┘ └─────────────────────┘ + │ │ + ▼ ▼ + ┌──────────────────────────────────────────────────────────────────────────────┐ + │ advanced_resolver │ + ├──────────────────────────────────────────────────────────────────────────────┤ + │ ┌─────────────────┐ │ + │ │ ast::Expression │ │ + │ └─────────────────┘ │ + │ │ │ + │ │ resolve_local_value │ + │ ▼ │ + │ ┌─────────────────┐ │ + │ │ ast::Expression │ │ + │ └─────────────────┘ │ + │ │ │ + │ │ resolve_symbol_ref (map Expression to DefinitionSymbols) | + │ ▼ │ + │ ┌─────────────────┐ │ + │ │ ast::Expression │ │ + │ └─────────────────┘ │ + └──────────────────────────────────────────────────────────────────────────────┘ + │ + ▼ build_sema_db (collect symbol locs and analyse scope) + ┌─────────────────────┐ + │ core::GlobalState │ + └─────────────────────┘ +*/ + +use std::{cell::RefCell, rc::Rc}; + +use indexmap::IndexSet; +use kclvm_error::Position; + +use crate::{ + core::{ + global_state::GlobalState, + package::ModuleInfo, + scope::{LocalSymbolScope, LocalSymbolScopeKind, RootSymbolScope, ScopeKind, ScopeRef}, + symbol::SymbolRef, + }, + resolver::scope::{NodeKey, NodeTyMap}, +}; + +use kclvm_ast::ast::AstIndex; +use kclvm_ast::ast::Program; +use kclvm_ast::walker::MutSelfTypedResultWalker; +mod node; + +/// AdvancedResolver mainly does two tasks: +/// 1: Traverse AST to parse LocalSymbol and store it in GlobalState, while storing the parsed type in Symbol +/// 2: Establish a mapping between expressions and SymbolRef, specifically injecting symbol information into AST +/// +/// After the work of the advanced resolver is completed, the GlobalState will build the whole semantic database, +/// so that toolchain can query semantic information about the AST +pub struct AdvancedResolver<'ctx> { + pub(crate) ctx: Context<'ctx>, + pub(crate) gs: &'ctx mut GlobalState, +} + +pub struct Context<'ctx> { + pub program: &'ctx Program, + node_ty_map: Rc>, + scopes: Vec, + current_pkgpath: Option, + current_filename: Option, + schema_symbol_stack: Vec>, + start_pos: Position, + end_pos: Position, + cur_node: AstIndex, + + // whether the identifier currently being visited may be a definition + // it will only be true when visiting a l-value or parameter, + // which means advanced resolver will will create the corresponding + // ValueSymbol instead of an UnresolvedSymbol + maybe_def: bool, + // whether in schema config right value, affect lookup def + in_config_r_value: bool, + + is_type_expr: bool, +} + +impl<'ctx> Context<'ctx> { + pub fn get_node_key(&self, id: &AstIndex) -> NodeKey { + NodeKey { + pkgpath: self.current_pkgpath.clone().unwrap(), + id: id.clone(), + } + } +} + +impl<'ctx> AdvancedResolver<'ctx> { + pub fn resolve_program( + program: &'ctx Program, + gs: &'ctx mut GlobalState, + node_ty_map: Rc>, + ) -> anyhow::Result<()> { + let mut advanced_resolver = Self { + gs, + ctx: Context { + program, + node_ty_map, + scopes: vec![], + current_filename: None, + current_pkgpath: None, + schema_symbol_stack: vec![], + start_pos: Position::dummy_pos(), + end_pos: Position::dummy_pos(), + cur_node: AstIndex::default(), + maybe_def: false, + in_config_r_value: false, + is_type_expr: false, + }, + }; + // Scan all scehma symbol + for (name, modules) in advanced_resolver.ctx.program.pkgs.iter() { + advanced_resolver.scan_schemas(name, modules)?; + } + + for (name, modules) in advanced_resolver.ctx.program.pkgs.iter() { + advanced_resolver.walk_pkg(name, modules)?; + } + + advanced_resolver.gs.build_sema_db(); + advanced_resolver.gs.new_or_invalidate_pkgs.clear(); + Ok(()) + } + + fn scan_schemas(&mut self, name: &String, modules: &Vec) -> anyhow::Result<()> { + if !self.gs.new_or_invalidate_pkgs.contains(name) { + return Ok(()); + } + self.ctx.current_pkgpath = Some(name.clone()); + if let Some(pkg_info) = self.gs.get_packages().get_package_info(name) { + if modules.is_empty() { + return Ok(()); + } + if !self.ctx.scopes.is_empty() { + self.ctx.scopes.clear(); + } + + self.enter_root_scope( + name.clone(), + pkg_info.pkg_filepath.clone(), + pkg_info.kfile_paths.clone(), + ); + + let modules = self.ctx.program.get_modules_for_pkg(name); + for module in modules.iter() { + let module = module.read().expect("Failed to acquire module lock"); + self.ctx.current_filename = Some(module.filename.clone()); + self.walk_module_schemas(&module)?; + } + self.leave_scope() + } + Ok(()) + } + + fn walk_pkg(&mut self, name: &String, modules: &Vec) -> anyhow::Result<()> { + if !self.gs.new_or_invalidate_pkgs.contains(name) { + return Ok(()); + } + self.ctx.current_pkgpath = Some(name.clone()); + if let Some(_) = self.gs.get_packages().get_package_info(name) { + if modules.is_empty() { + return Ok(()); + } + if !self.ctx.scopes.is_empty() { + self.ctx.scopes.clear(); + } + + let scope_ref = self + .gs + .get_scopes_mut() + .get_root_scope(name.to_string()) + .unwrap(); + + self.ctx.scopes.push(scope_ref); + let modules = self.ctx.program.get_modules_for_pkg(name); + for module in modules.iter() { + let module = module.read().expect("Failed to acquire module lock"); + self.ctx.current_filename = Some(module.filename.clone()); + self.walk_module(&module)?; + } + self.leave_scope() + } + Ok(()) + } + + fn enter_root_scope( + &mut self, + pkgpath: String, + filename: String, + kfile_paths: IndexSet, + ) { + let package_ref = self + .gs + .get_symbols_mut() + .get_symbol_by_fully_qualified_name(&pkgpath) + .unwrap(); + + let root_scope = RootSymbolScope::new(pkgpath, filename, package_ref, kfile_paths); + let scope_ref = self.gs.get_scopes_mut().alloc_root_scope(root_scope); + self.ctx.scopes.push(scope_ref); + } + + fn enter_local_scope( + &mut self, + filepath: &str, + start: Position, + end: Position, + kind: LocalSymbolScopeKind, + ) { + let parent = *self.ctx.scopes.last().unwrap(); + let local_scope = LocalSymbolScope::new(parent, start, end, kind); + let scope_ref = self.gs.get_scopes_mut().alloc_local_scope(local_scope); + + match parent.get_kind() { + ScopeKind::Root => { + self.gs + .get_scopes_mut() + .roots + .get_mut(parent.get_id()) + .unwrap() + .add_child(filepath, scope_ref); + } + ScopeKind::Local => { + self.gs + .get_scopes_mut() + .locals + .get_mut(parent.get_id()) + .unwrap() + .add_child(scope_ref); + } + } + self.ctx.scopes.push(scope_ref); + } + + fn enter_schema_def_scope( + &mut self, + name: &str, + filepath: &str, + start: Position, + end: Position, + kind: LocalSymbolScopeKind, + ) { + let parent = *self.ctx.scopes.last().unwrap(); + let local_scope = LocalSymbolScope::new(parent, start, end, kind); + let pkg_path = self.ctx.current_pkgpath.clone().unwrap(); + let fqn_name = format!("{pkg_path}.{filepath}.{name}"); + let scope_ref = match self.gs.get_scopes().schema_scope_map.get(&fqn_name) { + Some(scope_ref) => scope_ref.clone(), + None => { + let scope_ref = self.gs.get_scopes_mut().alloc_local_scope(local_scope); + self.gs + .get_scopes_mut() + .schema_scope_map + .insert(fqn_name, scope_ref); + + match parent.get_kind() { + ScopeKind::Root => { + self.gs + .get_scopes_mut() + .roots + .get_mut(parent.get_id()) + .unwrap() + .add_child(filepath, scope_ref); + } + ScopeKind::Local => { + self.gs + .get_scopes_mut() + .locals + .get_mut(parent.get_id()) + .unwrap() + .add_child(scope_ref); + } + } + scope_ref + } + }; + self.ctx.scopes.push(scope_ref); + } + + fn leave_scope(&mut self) { + self.ctx.scopes.pop(); + } + + fn get_current_module_info(&self) -> Option<&ModuleInfo> { + self.gs + .get_packages() + .get_module_info(self.ctx.current_filename.as_ref()?) + } +} + +#[cfg(test)] +mod tests { + use crate::advanced_resolver::AdvancedResolver; + use crate::core::global_state::GlobalState; + use crate::core::symbol::SymbolKind; + use crate::namer::Namer; + use crate::resolver; + + use kclvm_ast::MAIN_PKG; + use kclvm_error::Position; + use kclvm_parser::load_program; + use kclvm_parser::ParseSession; + use std::path::Path; + use std::sync::Arc; + + #[cfg(not(target_os = "windows"))] + fn adjust_canonicalization>(p: P) -> String { + p.as_ref().display().to_string() + } + + #[cfg(target_os = "windows")] + fn adjust_canonicalization>(p: P) -> String { + const VERBATIM_PREFIX: &str = r#"\\?\"#; + let p = p.as_ref().display().to_string(); + if p.starts_with(VERBATIM_PREFIX) { + p[VERBATIM_PREFIX.len()..].to_string() + } else { + p + } + } + + #[allow(unused)] + fn print_symbols_info(gs: &GlobalState) { + let base_path = Path::new(".").canonicalize().unwrap(); + let symbols = gs.get_symbols(); + println!("vec!["); + for (key, val) in gs.sema_db.file_sema_map.iter() { + let key_path = Path::new(key) + .strip_prefix(base_path.clone()) + .unwrap_or_else(|_| Path::new(key)) + .to_str() + .unwrap() + .to_string(); + println!(" (\n \"{}\".to_string().replace(\"/\", &std::path::MAIN_SEPARATOR.to_string()),", key_path); + println!(" vec!["); + for symbol_ref in val.symbols.iter() { + let symbol = symbols.get_symbol(*symbol_ref).unwrap(); + let (start, end) = symbol.get_range(); + println!( + " ({},{},{},{},\"{}\".to_string(),SymbolKind::{:?}),", + start.line, + start.column.unwrap_or(0), + end.line, + end.column.unwrap_or(0), + symbol.get_name(), + symbol_ref.get_kind(), + ); + if let SymbolKind::Unresolved = symbol_ref.get_kind() { + let def_symbol_ref = symbol.get_definition().unwrap(); + let def_symbol = symbols.get_symbol(def_symbol_ref).unwrap(); + let (def_start, def_end) = def_symbol.get_range(); + let def_path = Path::new(&def_start.filename) + .strip_prefix(base_path.clone()) + .unwrap_or_else(|_| Path::new(&def_start.filename)) + .to_str() + .unwrap() + .to_string(); + println!( + " ({},{},{},{},\"{}\".to_string().replace(\"/\", &std::path::MAIN_SEPARATOR.to_string()),SymbolKind::{:?}),", + def_start.line, + def_start.column.unwrap_or(0), + def_end.line, + def_end.column.unwrap_or(0), + def_path, + def_symbol_ref.get_kind(), + ); + } + } + println!(" ],\n ),") + } + println!("]"); + } + + #[test] + fn test_look_up_exact_symbol() { + let sess = Arc::new(ParseSession::default()); + + let path = "src/advanced_resolver/test_data/schema_symbols.k" + .to_string() + .replace("/", &std::path::MAIN_SEPARATOR.to_string()); + let mut program = load_program(sess.clone(), &[&path], None, None) + .unwrap() + .program; + let mut gs = GlobalState::default(); + Namer::find_symbols(&program, &mut gs); + + let node_ty_map = resolver::resolve_program_with_opts( + &mut program, + resolver::Options { + merge_program: false, + type_erasure: false, + ..Default::default() + }, + None, + ) + .node_ty_map; + AdvancedResolver::resolve_program(&program, &mut gs, node_ty_map).unwrap(); + let base_path = Path::new(".").canonicalize().unwrap(); + // print_symbols_info(&gs); + let except_symbols = vec![ + ( + "src/advanced_resolver/test_data/import_test/e.k" + .to_string() + .replace("/", &std::path::MAIN_SEPARATOR.to_string()), + vec![ + (1, 7, 1, 16, "UnionType".to_string(), SymbolKind::Schema), + (2, 4, 2, 5, "a".to_string(), SymbolKind::Attribute), + ], + ), + ( + "src/advanced_resolver/test_data/import_test/a.k" + .to_string() + .replace("/", &std::path::MAIN_SEPARATOR.to_string()), + vec![ + (1, 0, 1, 2, "_a".to_string(), SymbolKind::Value), + (2, 7, 2, 11, "Name".to_string(), SymbolKind::Schema), + (3, 4, 3, 13, "firstName".to_string(), SymbolKind::Attribute), + (4, 4, 4, 12, "lastName".to_string(), SymbolKind::Attribute), + (6, 7, 6, 13, "Person".to_string(), SymbolKind::Schema), + (7, 4, 7, 8, "name".to_string(), SymbolKind::Attribute), + (7, 10, 7, 14, "Name".to_string(), SymbolKind::Unresolved), + ( + 2, + 7, + 2, + 11, + "src/advanced_resolver/test_data/import_test/a.k" + .to_string() + .replace("/", &std::path::MAIN_SEPARATOR.to_string()), + SymbolKind::Schema, + ), + (8, 4, 8, 7, "age".to_string(), SymbolKind::Attribute), + (10, 0, 10, 7, "_person".to_string(), SymbolKind::Value), + (10, 10, 10, 16, "Person".to_string(), SymbolKind::Unresolved), + ( + 6, + 7, + 6, + 13, + "src/advanced_resolver/test_data/import_test/a.k" + .to_string() + .replace("/", &std::path::MAIN_SEPARATOR.to_string()), + SymbolKind::Schema, + ), + (11, 4, 11, 8, "name".to_string(), SymbolKind::Unresolved), + ( + 7, + 4, + 7, + 8, + "src/advanced_resolver/test_data/import_test/a.k" + .to_string() + .replace("/", &std::path::MAIN_SEPARATOR.to_string()), + SymbolKind::Attribute, + ), + (11, 11, 11, 15, "Name".to_string(), SymbolKind::Unresolved), + ( + 2, + 7, + 2, + 11, + "src/advanced_resolver/test_data/import_test/a.k" + .to_string() + .replace("/", &std::path::MAIN_SEPARATOR.to_string()), + SymbolKind::Schema, + ), + ( + 12, + 8, + 12, + 17, + "firstName".to_string(), + SymbolKind::Unresolved, + ), + ( + 3, + 4, + 3, + 13, + "src/advanced_resolver/test_data/import_test/a.k" + .to_string() + .replace("/", &std::path::MAIN_SEPARATOR.to_string()), + SymbolKind::Attribute, + ), + ( + 13, + 8, + 13, + 16, + "lastName".to_string(), + SymbolKind::Unresolved, + ), + ( + 4, + 4, + 4, + 12, + "src/advanced_resolver/test_data/import_test/a.k" + .to_string() + .replace("/", &std::path::MAIN_SEPARATOR.to_string()), + SymbolKind::Attribute, + ), + (15, 4, 15, 7, "age".to_string(), SymbolKind::Unresolved), + ( + 8, + 4, + 8, + 7, + "src/advanced_resolver/test_data/import_test/a.k" + .to_string() + .replace("/", &std::path::MAIN_SEPARATOR.to_string()), + SymbolKind::Attribute, + ), + ], + ), + ( + "src/advanced_resolver/test_data/import_test/d.k" + .to_string() + .replace("/", &std::path::MAIN_SEPARATOR.to_string()), + vec![ + (1, 7, 1, 13, "Parent".to_string(), SymbolKind::Schema), + (2, 4, 2, 8, "age1".to_string(), SymbolKind::Attribute), + ], + ), + ( + "src/advanced_resolver/test_data/schema_symbols.k" + .to_string() + .replace("/", &std::path::MAIN_SEPARATOR.to_string()), + vec![ + ( + 1, + 7, + 1, + 20, + "import_test.a".to_string(), + SymbolKind::Unresolved, + ), + ( + 0, + 0, + 0, + 0, + "src/advanced_resolver/test_data/import_test/a" + .to_string() + .replace("/", &std::path::MAIN_SEPARATOR.to_string()), + SymbolKind::Package, + ), + ( + 2, + 7, + 2, + 20, + "import_test.b".to_string(), + SymbolKind::Unresolved, + ), + ( + 0, + 0, + 0, + 0, + "src/advanced_resolver/test_data/import_test/b" + .to_string() + .replace("/", &std::path::MAIN_SEPARATOR.to_string()), + SymbolKind::Package, + ), + ( + 3, + 7, + 3, + 20, + "import_test.c".to_string(), + SymbolKind::Unresolved, + ), + ( + 0, + 0, + 0, + 0, + "src/advanced_resolver/test_data/import_test/c" + .to_string() + .replace("/", &std::path::MAIN_SEPARATOR.to_string()), + SymbolKind::Package, + ), + ( + 4, + 7, + 4, + 20, + "import_test.d".to_string(), + SymbolKind::Unresolved, + ), + ( + 0, + 0, + 0, + 0, + "src/advanced_resolver/test_data/import_test/d" + .to_string() + .replace("/", &std::path::MAIN_SEPARATOR.to_string()), + SymbolKind::Package, + ), + ( + 5, + 7, + 5, + 20, + "import_test.e".to_string(), + SymbolKind::Unresolved, + ), + ( + 0, + 0, + 0, + 0, + "src/advanced_resolver/test_data/import_test/e" + .to_string() + .replace("/", &std::path::MAIN_SEPARATOR.to_string()), + SymbolKind::Package, + ), + ( + 6, + 24, + 6, + 25, + "import_test.f".to_string(), + SymbolKind::Unresolved, + ), + ( + 0, + 0, + 0, + 0, + "src/advanced_resolver/test_data/import_test/f" + .to_string() + .replace("/", &std::path::MAIN_SEPARATOR.to_string()), + SymbolKind::Package, + ), + (7, 7, 7, 10, "pkg".to_string(), SymbolKind::Unresolved), + ( + 0, + 0, + 0, + 0, + "src/advanced_resolver/test_data/pkg" + .to_string() + .replace("/", &std::path::MAIN_SEPARATOR.to_string()), + SymbolKind::Package, + ), + (8, 7, 8, 12, "regex".to_string(), SymbolKind::Unresolved), + ( + 1, + 0, + 1, + 0, + "".to_string() + .replace("/", &std::path::MAIN_SEPARATOR.to_string()), + SymbolKind::Package, + ), + (10, 7, 10, 11, "Main".to_string(), SymbolKind::Schema), + (10, 12, 10, 13, "d".to_string(), SymbolKind::Unresolved), + ( + 0, + 0, + 0, + 0, + "src/advanced_resolver/test_data/import_test/d" + .to_string() + .replace("/", &std::path::MAIN_SEPARATOR.to_string()), + SymbolKind::Package, + ), + (10, 14, 10, 20, "Parent".to_string(), SymbolKind::Unresolved), + ( + 1, + 7, + 1, + 13, + "src/advanced_resolver/test_data/import_test/d.k" + .to_string() + .replace("/", &std::path::MAIN_SEPARATOR.to_string()), + SymbolKind::Schema, + ), + (11, 11, 11, 12, "c".to_string(), SymbolKind::Unresolved), + ( + 0, + 0, + 0, + 0, + "src/advanced_resolver/test_data/import_test/c" + .to_string() + .replace("/", &std::path::MAIN_SEPARATOR.to_string()), + SymbolKind::Package, + ), + ( + 11, + 13, + 11, + 24, + "TestOfMixin".to_string(), + SymbolKind::Unresolved, + ), + ( + 1, + 7, + 1, + 18, + "src/advanced_resolver/test_data/import_test/c.k" + .to_string() + .replace("/", &std::path::MAIN_SEPARATOR.to_string()), + SymbolKind::Schema, + ), + (12, 4, 12, 8, "name".to_string(), SymbolKind::Attribute), + (13, 4, 13, 7, "age".to_string(), SymbolKind::Attribute), + (14, 4, 14, 10, "person".to_string(), SymbolKind::Attribute), + (14, 13, 14, 14, "a".to_string(), SymbolKind::Unresolved), + ( + 0, + 0, + 0, + 0, + "src/advanced_resolver/test_data/import_test/a" + .to_string() + .replace("/", &std::path::MAIN_SEPARATOR.to_string()), + SymbolKind::Package, + ), + (14, 15, 14, 21, "Person".to_string(), SymbolKind::Unresolved), + ( + 6, + 7, + 6, + 13, + "src/advanced_resolver/test_data/import_test/a.k" + .to_string() + .replace("/", &std::path::MAIN_SEPARATOR.to_string()), + SymbolKind::Schema, + ), + ( + 15, + 4, + 15, + 19, + "list_union_type".to_string(), + SymbolKind::Attribute, + ), + (15, 23, 15, 24, "e".to_string(), SymbolKind::Unresolved), + ( + 0, + 0, + 0, + 0, + "src/advanced_resolver/test_data/import_test/e" + .to_string() + .replace("/", &std::path::MAIN_SEPARATOR.to_string()), + SymbolKind::Package, + ), + ( + 15, + 25, + 15, + 34, + "UnionType".to_string(), + SymbolKind::Unresolved, + ), + ( + 1, + 7, + 1, + 16, + "src/advanced_resolver/test_data/import_test/e.k" + .to_string() + .replace("/", &std::path::MAIN_SEPARATOR.to_string()), + SymbolKind::Schema, + ), + ( + 16, + 4, + 16, + 19, + "dict_union_type".to_string(), + SymbolKind::Attribute, + ), + (16, 23, 16, 24, "g".to_string(), SymbolKind::Unresolved), + ( + 0, + 0, + 0, + 0, + "src/advanced_resolver/test_data/import_test/f" + .to_string() + .replace("/", &std::path::MAIN_SEPARATOR.to_string()), + SymbolKind::Package, + ), + ( + 16, + 25, + 16, + 34, + "UnionType".to_string(), + SymbolKind::Unresolved, + ), + ( + 1, + 7, + 1, + 16, + "src/advanced_resolver/test_data/import_test/f.k" + .to_string() + .replace("/", &std::path::MAIN_SEPARATOR.to_string()), + SymbolKind::Schema, + ), + (19, 8, 19, 13, "regex".to_string(), SymbolKind::Unresolved), + ( + 1, + 0, + 1, + 0, + "".to_string() + .replace("/", &std::path::MAIN_SEPARATOR.to_string()), + SymbolKind::Package, + ), + (19, 14, 19, 19, "match".to_string(), SymbolKind::Unresolved), + ( + 1, + 0, + 1, + 0, + "".to_string() + .replace("/", &std::path::MAIN_SEPARATOR.to_string()), + SymbolKind::Function, + ), + (19, 20, 19, 24, "name".to_string(), SymbolKind::Unresolved), + ( + 12, + 4, + 12, + 8, + "src/advanced_resolver/test_data/schema_symbols.k" + .to_string() + .replace("/", &std::path::MAIN_SEPARATOR.to_string()), + SymbolKind::Attribute, + ), + (19, 97, 19, 101, "name".to_string(), SymbolKind::Unresolved), + ( + 12, + 4, + 12, + 8, + "src/advanced_resolver/test_data/schema_symbols.k" + .to_string() + .replace("/", &std::path::MAIN_SEPARATOR.to_string()), + SymbolKind::Attribute, + ), + (21, 3, 21, 4, "a".to_string(), SymbolKind::Unresolved), + ( + 0, + 0, + 0, + 0, + "src/advanced_resolver/test_data/import_test/a" + .to_string() + .replace("/", &std::path::MAIN_SEPARATOR.to_string()), + SymbolKind::Package, + ), + (21, 5, 21, 7, "_a".to_string(), SymbolKind::Unresolved), + ( + 1, + 0, + 1, + 2, + "src/advanced_resolver/test_data/import_test/a.k" + .to_string() + .replace("/", &std::path::MAIN_SEPARATOR.to_string()), + SymbolKind::Value, + ), + (22, 4, 22, 6, "_c".to_string(), SymbolKind::Value), + (23, 5, 23, 6, "a".to_string(), SymbolKind::Unresolved), + ( + 0, + 0, + 0, + 0, + "src/advanced_resolver/test_data/import_test/a" + .to_string() + .replace("/", &std::path::MAIN_SEPARATOR.to_string()), + SymbolKind::Package, + ), + (23, 7, 23, 9, "_a".to_string(), SymbolKind::Unresolved), + ( + 1, + 0, + 1, + 2, + "src/advanced_resolver/test_data/import_test/a.k" + .to_string() + .replace("/", &std::path::MAIN_SEPARATOR.to_string()), + SymbolKind::Value, + ), + (24, 4, 24, 6, "_c".to_string(), SymbolKind::Unresolved), + ( + 22, + 4, + 22, + 6, + "src/advanced_resolver/test_data/schema_symbols.k" + .to_string() + .replace("/", &std::path::MAIN_SEPARATOR.to_string()), + SymbolKind::Value, + ), + (26, 4, 26, 6, "_c".to_string(), SymbolKind::Unresolved), + ( + 22, + 4, + 22, + 6, + "src/advanced_resolver/test_data/schema_symbols.k" + .to_string() + .replace("/", &std::path::MAIN_SEPARATOR.to_string()), + SymbolKind::Value, + ), + (28, 0, 28, 1, "p".to_string(), SymbolKind::Value), + (28, 4, 28, 8, "Main".to_string(), SymbolKind::Unresolved), + ( + 10, + 7, + 10, + 11, + "src/advanced_resolver/test_data/schema_symbols.k" + .to_string() + .replace("/", &std::path::MAIN_SEPARATOR.to_string()), + SymbolKind::Schema, + ), + (29, 4, 29, 8, "name".to_string(), SymbolKind::Unresolved), + ( + 12, + 4, + 12, + 8, + "src/advanced_resolver/test_data/schema_symbols.k" + .to_string() + .replace("/", &std::path::MAIN_SEPARATOR.to_string()), + SymbolKind::Attribute, + ), + (29, 11, 29, 12, "a".to_string(), SymbolKind::Unresolved), + ( + 0, + 0, + 0, + 0, + "src/advanced_resolver/test_data/import_test/a" + .to_string() + .replace("/", &std::path::MAIN_SEPARATOR.to_string()), + SymbolKind::Package, + ), + ( + 29, + 13, + 29, + 20, + "_person".to_string(), + SymbolKind::Unresolved, + ), + ( + 10, + 0, + 10, + 7, + "src/advanced_resolver/test_data/import_test/a.k" + .to_string() + .replace("/", &std::path::MAIN_SEPARATOR.to_string()), + SymbolKind::Value, + ), + (29, 21, 29, 25, "name".to_string(), SymbolKind::Unresolved), + ( + 7, + 4, + 7, + 8, + "src/advanced_resolver/test_data/import_test/a.k" + .to_string() + .replace("/", &std::path::MAIN_SEPARATOR.to_string()), + SymbolKind::Attribute, + ), + ( + 29, + 26, + 29, + 35, + "firstName".to_string(), + SymbolKind::Unresolved, + ), + ( + 3, + 4, + 3, + 13, + "src/advanced_resolver/test_data/import_test/a.k" + .to_string() + .replace("/", &std::path::MAIN_SEPARATOR.to_string()), + SymbolKind::Attribute, + ), + (29, 45, 29, 46, "a".to_string(), SymbolKind::Unresolved), + ( + 0, + 0, + 0, + 0, + "src/advanced_resolver/test_data/import_test/a" + .to_string() + .replace("/", &std::path::MAIN_SEPARATOR.to_string()), + SymbolKind::Package, + ), + ( + 29, + 47, + 29, + 54, + "_person".to_string(), + SymbolKind::Unresolved, + ), + ( + 10, + 0, + 10, + 7, + "src/advanced_resolver/test_data/import_test/a.k" + .to_string() + .replace("/", &std::path::MAIN_SEPARATOR.to_string()), + SymbolKind::Value, + ), + (29, 56, 29, 60, "name".to_string(), SymbolKind::Unresolved), + ( + 7, + 4, + 7, + 8, + "src/advanced_resolver/test_data/import_test/a.k" + .to_string() + .replace("/", &std::path::MAIN_SEPARATOR.to_string()), + SymbolKind::Attribute, + ), + ( + 29, + 61, + 29, + 69, + "lastName".to_string(), + SymbolKind::Unresolved, + ), + ( + 4, + 4, + 4, + 12, + "src/advanced_resolver/test_data/import_test/a.k" + .to_string() + .replace("/", &std::path::MAIN_SEPARATOR.to_string()), + SymbolKind::Attribute, + ), + (30, 4, 30, 7, "age".to_string(), SymbolKind::Unresolved), + ( + 13, + 4, + 13, + 7, + "src/advanced_resolver/test_data/schema_symbols.k" + .to_string() + .replace("/", &std::path::MAIN_SEPARATOR.to_string()), + SymbolKind::Attribute, + ), + (30, 10, 30, 11, "b".to_string(), SymbolKind::Unresolved), + ( + 0, + 0, + 0, + 0, + "src/advanced_resolver/test_data/import_test/b" + .to_string() + .replace("/", &std::path::MAIN_SEPARATOR.to_string()), + SymbolKind::Package, + ), + (30, 12, 30, 14, "_b".to_string(), SymbolKind::Unresolved), + ( + 1, + 0, + 1, + 2, + "src/advanced_resolver/test_data/import_test/b.k" + .to_string() + .replace("/", &std::path::MAIN_SEPARATOR.to_string()), + SymbolKind::Value, + ), + (30, 17, 30, 18, "a".to_string(), SymbolKind::Unresolved), + ( + 0, + 0, + 0, + 0, + "src/advanced_resolver/test_data/import_test/a" + .to_string() + .replace("/", &std::path::MAIN_SEPARATOR.to_string()), + SymbolKind::Package, + ), + ( + 30, + 19, + 30, + 26, + "_person".to_string(), + SymbolKind::Unresolved, + ), + ( + 10, + 0, + 10, + 7, + "src/advanced_resolver/test_data/import_test/a.k" + .to_string() + .replace("/", &std::path::MAIN_SEPARATOR.to_string()), + SymbolKind::Value, + ), + (30, 28, 30, 31, "age".to_string(), SymbolKind::Unresolved), + ( + 8, + 4, + 8, + 7, + "src/advanced_resolver/test_data/import_test/a.k" + .to_string() + .replace("/", &std::path::MAIN_SEPARATOR.to_string()), + SymbolKind::Attribute, + ), + (33, 0, 33, 6, "person".to_string(), SymbolKind::Value), + (33, 9, 33, 12, "pkg".to_string(), SymbolKind::Unresolved), + ( + 0, + 0, + 0, + 0, + "src/advanced_resolver/test_data/pkg" + .to_string() + .replace("/", &std::path::MAIN_SEPARATOR.to_string()), + SymbolKind::Package, + ), + (33, 13, 33, 19, "Person".to_string(), SymbolKind::Unresolved), + ( + 4, + 7, + 4, + 13, + "src/advanced_resolver/test_data/pkg/pkg.k" + .to_string() + .replace("/", &std::path::MAIN_SEPARATOR.to_string()), + SymbolKind::Schema, + ), + (34, 4, 34, 8, "name".to_string(), SymbolKind::Unresolved), + ( + 5, + 4, + 5, + 8, + "src/advanced_resolver/test_data/pkg/pkg.k" + .to_string() + .replace("/", &std::path::MAIN_SEPARATOR.to_string()), + SymbolKind::Attribute, + ), + (34, 9, 34, 13, "name".to_string(), SymbolKind::Unresolved), + ( + 2, + 4, + 2, + 8, + "src/advanced_resolver/test_data/pkg/pkg.k" + .to_string() + .replace("/", &std::path::MAIN_SEPARATOR.to_string()), + SymbolKind::Attribute, + ), + (37, 0, 37, 1, "x".to_string(), SymbolKind::Value), + (38, 16, 38, 17, "x".to_string(), SymbolKind::Unresolved), + ( + 37, + 0, + 37, + 1, + "src/advanced_resolver/test_data/schema_symbols.k" + .to_string() + .replace("/", &std::path::MAIN_SEPARATOR.to_string()), + SymbolKind::Value, + ), + ], + ), + ( + "src/advanced_resolver/test_data/import_test/f.k" + .to_string() + .replace("/", &std::path::MAIN_SEPARATOR.to_string()), + vec![ + (1, 7, 1, 16, "UnionType".to_string(), SymbolKind::Schema), + (2, 4, 2, 5, "b".to_string(), SymbolKind::Attribute), + ], + ), + ( + "src/advanced_resolver/test_data/import_test/c.k" + .to_string() + .replace("/", &std::path::MAIN_SEPARATOR.to_string()), + vec![ + (1, 7, 1, 18, "TestOfMixin".to_string(), SymbolKind::Schema), + (2, 4, 2, 7, "age".to_string(), SymbolKind::Attribute), + ], + ), + ( + "src/advanced_resolver/test_data/pkg/pkg.k" + .to_string() + .replace("/", &std::path::MAIN_SEPARATOR.to_string()), + vec![ + (1, 7, 1, 11, "Name".to_string(), SymbolKind::Schema), + (2, 4, 2, 8, "name".to_string(), SymbolKind::Attribute), + (4, 7, 4, 13, "Person".to_string(), SymbolKind::Schema), + (5, 4, 5, 8, "name".to_string(), SymbolKind::Attribute), + (5, 10, 5, 14, "Name".to_string(), SymbolKind::Unresolved), + ( + 1, + 7, + 1, + 11, + "src/advanced_resolver/test_data/pkg/pkg.k" + .to_string() + .replace("/", &std::path::MAIN_SEPARATOR.to_string()), + SymbolKind::Schema, + ), + (5, 17, 5, 21, "Name".to_string(), SymbolKind::Unresolved), + ( + 1, + 7, + 1, + 11, + "src/advanced_resolver/test_data/pkg/pkg.k" + .to_string() + .replace("/", &std::path::MAIN_SEPARATOR.to_string()), + SymbolKind::Schema, + ), + (5, 23, 5, 27, "name".to_string(), SymbolKind::Unresolved), + ( + 2, + 4, + 2, + 8, + "src/advanced_resolver/test_data/pkg/pkg.k" + .to_string() + .replace("/", &std::path::MAIN_SEPARATOR.to_string()), + SymbolKind::Attribute, + ), + ], + ), + ( + "src/advanced_resolver/test_data/import_test/b.k" + .to_string() + .replace("/", &std::path::MAIN_SEPARATOR.to_string()), + vec![(1, 0, 1, 2, "_b".to_string(), SymbolKind::Value)], + ), + ]; + let mut skip_def_info = false; + for (filepath, symbols) in except_symbols.iter() { + let abs_filepath = adjust_canonicalization(base_path.join(filepath)); + // symbols will be sorted according to their position in the file + // now we check all symbols + for (index, symbol_info) in symbols.iter().enumerate() { + if skip_def_info { + skip_def_info = false; + continue; + } + let (start_line, start_col, end_line, end_col, name, kind) = symbol_info; + if abs_filepath.is_empty() { + continue; + } + // test look up symbols + let inner_pos = Position { + filename: abs_filepath.clone(), + line: (start_line + end_line) / 2, + column: Some((start_col + end_col) / 2), + }; + let looked_symbol_ref = gs.look_up_exact_symbol(&inner_pos).unwrap(); + let looked_symbol = gs.get_symbols().get_symbol(looked_symbol_ref).unwrap(); + let (start, end) = looked_symbol.get_range(); + // test symbol basic infomation + assert_eq!(start.filename, abs_filepath); + assert_eq!(start.line, *start_line); + assert_eq!(start.column.unwrap_or(0), *start_col); + assert_eq!(end.line, *end_line); + assert_eq!(end.column.unwrap_or(0), *end_col); + assert_eq!(*name, looked_symbol.get_name()); + assert_eq!(looked_symbol_ref.get_kind(), *kind); + + // test find def + if SymbolKind::Unresolved == looked_symbol_ref.get_kind() { + let (start_line, start_col, end_line, end_col, path, kind) = + symbols.get(index + 1).unwrap(); + let def_ref = looked_symbol.get_definition().unwrap(); + let def = gs.get_symbols().get_symbol(def_ref).unwrap(); + let (start, end) = def.get_range(); + let def_filepath = adjust_canonicalization(base_path.join(path)); + assert_eq!(start.line, *start_line); + assert_eq!(start.column.unwrap_or(0), *start_col); + assert_eq!(end.line, *end_line); + assert_eq!(end.column.unwrap_or(0), *end_col); + if !path.is_empty() { + assert_eq!(start.filename, def_filepath); + } + assert_eq!(def_ref.get_kind(), *kind); + skip_def_info = true; + } + } + } + } + + #[test] + fn test_look_up_cloest_symbol() { + let sess = Arc::new(ParseSession::default()); + + let path = "src/advanced_resolver/test_data/schema_symbols.k" + .to_string() + .replace("/", &std::path::MAIN_SEPARATOR.to_string()); + let mut program = load_program(sess.clone(), &[&path], None, None) + .unwrap() + .program; + let mut gs = GlobalState::default(); + Namer::find_symbols(&program, &mut gs); + let node_ty_map = resolver::resolve_program(&mut program).node_ty_map; + AdvancedResolver::resolve_program(&program, &mut gs, node_ty_map).unwrap(); + let base_path = Path::new(".").canonicalize().unwrap(); + + let test_cases = vec![ + ( + "src/advanced_resolver/test_data/schema_symbols.k" + .to_string() + .replace("/", &std::path::MAIN_SEPARATOR.to_string()), + 19_u64, + 25_u64, + Some((19, 20, 19, 24, "name".to_string(), SymbolKind::Unresolved)), + ), + ( + "src/advanced_resolver/test_data/schema_symbols.k" + .to_string() + .replace("/", &std::path::MAIN_SEPARATOR.to_string()), + 32_u64, + 7_u64, + Some((28, 4, 28, 8, "Main".to_string(), SymbolKind::Unresolved)), + ), + ( + "src/advanced_resolver/test_data/schema_symbols.k" + .to_string() + .replace("/", &std::path::MAIN_SEPARATOR.to_string()), + 35_u64, + 5_u64, + Some((33, 13, 33, 19, "Person".to_string(), SymbolKind::Unresolved)), + ), + ( + "src/advanced_resolver/test_data/schema_symbols.k" + .to_string() + .replace("/", &std::path::MAIN_SEPARATOR.to_string()), + 28_u64, + 30_u64, + None, + ), + ]; + + for (filepath, line, col, symbol_info) in test_cases.iter() { + let abs_scope_file_path = adjust_canonicalization(base_path.join(filepath)); + let symbol_ref = gs.look_up_closest_symbol(&Position { + filename: abs_scope_file_path.clone(), + line: *line, + column: Some(*col), + }); + + match symbol_info { + Some((start_line, start_col, end_line, end_col, name, kind)) => { + let symbol_ref = symbol_ref.unwrap(); + let symbol = gs.get_symbols().get_symbol(symbol_ref).unwrap(); + + let (start, end) = symbol.get_range(); + assert_eq!(start.line, *start_line); + assert_eq!(start.column.unwrap_or(0), *start_col); + assert_eq!(end.line, *end_line); + assert_eq!(end.column.unwrap_or(0), *end_col); + assert_eq!(*name, symbol.get_name()); + assert_eq!(symbol_ref.get_kind(), *kind); + } + None => assert!(symbol_ref.is_none()), + } + } + } + + #[test] + fn test_look_up_scope() { + let sess = Arc::new(ParseSession::default()); + + let path = "src/advanced_resolver/test_data/schema_symbols.k" + .to_string() + .replace("/", &std::path::MAIN_SEPARATOR.to_string()); + let mut program = load_program(sess.clone(), &[&path], None, None) + .unwrap() + .program; + let mut gs = GlobalState::default(); + Namer::find_symbols(&program, &mut gs); + let node_ty_map = resolver::resolve_program(&mut program).node_ty_map; + AdvancedResolver::resolve_program(&program, &mut gs, node_ty_map).unwrap(); + let base_path = Path::new(".").canonicalize().unwrap(); + + let scope_test_cases = vec![ + // __main__.Main schema stmt scope + ( + "src/advanced_resolver/test_data/schema_symbols.k" + .to_string() + .replace("/", &std::path::MAIN_SEPARATOR.to_string()), + 17_u64, + 26_u64, + 10_usize, + ), + // __main__.Main schema expr scope + ( + "src/advanced_resolver/test_data/schema_symbols.k" + .to_string() + .replace("/", &std::path::MAIN_SEPARATOR.to_string()), + 30, + 6, + 6, + ), + // __main__.Main schema config entry value scope + ( + "src/advanced_resolver/test_data/schema_symbols.k" + .to_string() + .replace("/", &std::path::MAIN_SEPARATOR.to_string()), + 30, + 20, + 7, + ), + // pkg.Person schema expr scope + ( + "src/advanced_resolver/test_data/schema_symbols.k" + .to_string() + .replace("/", &std::path::MAIN_SEPARATOR.to_string()), + 33, + 21, + 1, + ), + // pkg.Person schema config entry value scope + ( + "src/advanced_resolver/test_data/schema_symbols.k" + .to_string() + .replace("/", &std::path::MAIN_SEPARATOR.to_string()), + 34, + 17, + 6, + ), + // __main__ package scope + ( + "src/advanced_resolver/test_data/schema_symbols.k" + .to_string() + .replace("/", &std::path::MAIN_SEPARATOR.to_string()), + 36, + 31, + 5, + ), + // import_test.a.Person expr scope + ( + "src/advanced_resolver/test_data/import_test/a.k" + .to_string() + .replace("/", &std::path::MAIN_SEPARATOR.to_string()), + 15, + 11, + 6, + ), + // import_test.a.Name expr scope + ( + "src/advanced_resolver/test_data/import_test/a.k" + .to_string() + .replace("/", &std::path::MAIN_SEPARATOR.to_string()), + 12, + 5, + 2, + ), + // import_test.a.Name config entry value scope + ( + "src/advanced_resolver/test_data/import_test/a.k" + .to_string() + .replace("/", &std::path::MAIN_SEPARATOR.to_string()), + 12, + 21, + 8, + ), + ]; + + for (filepath, line, col, def_num) in scope_test_cases.iter() { + let abs_scope_file_path = adjust_canonicalization(base_path.join(filepath)); + let pos = Position { + filename: abs_scope_file_path.clone(), + line: *line, + column: Some(*col), + }; + let scope_ref = gs.look_up_scope(&pos).unwrap(); + let all_defs = gs.get_all_defs_in_scope(scope_ref, &pos).unwrap(); + assert_eq!(all_defs.len(), *def_num) + } + } + + #[test] + fn test_schema_def_scope() { + let sess = Arc::new(ParseSession::default()); + + let path = "src/advanced_resolver/test_data/schema_def_scope.k" + .to_string() + .replace("/", &std::path::MAIN_SEPARATOR.to_string()); + let mut program = load_program(sess.clone(), &[&path], None, None) + .unwrap() + .program; + let mut gs = GlobalState::default(); + Namer::find_symbols(&program, &mut gs); + let node_ty_map = resolver::resolve_program(&mut program).node_ty_map; + AdvancedResolver::resolve_program(&program, &mut gs, node_ty_map).unwrap(); + let main_pkg_root_scope = gs + .get_scopes() + .get_root_scope(MAIN_PKG.to_string()) + .unwrap(); + assert_eq!( + gs.get_scopes() + .get_scope(&main_pkg_root_scope) + .unwrap() + .get_children() + .len(), + 2 + ); + } + + #[test] + fn test_schema_circle_dep() { + let sess = Arc::new(ParseSession::default()); + + let path = "src/advanced_resolver/test_data/circle_dep/circle_dep.k" + .to_string() + .replace("/", &std::path::MAIN_SEPARATOR.to_string()); + let mut program = load_program(sess.clone(), &[&path], None, None) + .unwrap() + .program; + let mut gs = GlobalState::default(); + Namer::find_symbols(&program, &mut gs); + let node_ty_map = resolver::resolve_program(&mut program).node_ty_map; + AdvancedResolver::resolve_program(&program, &mut gs, node_ty_map).unwrap(); + } +} diff --git a/kclvm/sema/src/advanced_resolver/node.rs b/kclvm/sema/src/advanced_resolver/node.rs new file mode 100644 index 000000000..0d7faf4cc --- /dev/null +++ b/kclvm/sema/src/advanced_resolver/node.rs @@ -0,0 +1,2044 @@ +use anyhow::anyhow; +use std::sync::Arc; + +use indexmap::IndexMap; +use kclvm_ast::ast::{self, Stmt}; +use kclvm_ast::pos::GetPos; +use kclvm_ast::walker::MutSelfTypedResultWalker; +use kclvm_error::{diagnostic::Range, Position}; + +use crate::core::symbol::Symbol; +use crate::{ + core::{ + scope::{ConfigScopeContext, LocalSymbolScopeKind}, + symbol::{ + CommentOrDocSymbol, DecoratorSymbol, ExpressionSymbol, SymbolHint, SymbolHintKind, + SymbolRef, SymbolSemanticInfo, UnresolvedSymbol, ValueSymbol, + }, + }, + ty::{Parameter, Type, TypeKind, ANY_TYPE_STR, SCHEMA_MEMBER_FUNCTIONS}, +}; + +use super::AdvancedResolver; + +type ResolvedResult = anyhow::Result>; + +impl<'ctx> MutSelfTypedResultWalker<'ctx> for AdvancedResolver<'_> { + type Result = anyhow::Result>; + + fn walk_module(&mut self, module: &'ctx ast::Module) -> Self::Result { + for stmt in module.body.iter() { + self.stmt(&stmt)?; + } + for comment in module.comments.iter() { + let (start, end) = comment.get_span_pos(); + self.ctx.start_pos = start; + self.ctx.end_pos = end; + self.ctx.cur_node = comment.id.clone(); + self.walk_comment(&comment.node)?; + } + Ok(None) + } + + fn walk_expr_stmt(&mut self, expr_stmt: &'ctx ast::ExprStmt) -> Self::Result { + for expr in expr_stmt.exprs.iter() { + self.expr(&expr)?; + } + Ok(None) + } + + fn walk_unification_stmt( + &mut self, + unification_stmt: &'ctx ast::UnificationStmt, + ) -> Self::Result { + self.ctx.maybe_def = true; + self.walk_identifier_expr(&unification_stmt.target)?; + // Set schema attribute if it is in the schema stmt. + if let Some(parent_scope) = self.ctx.scopes.last() { + if let Some(parent_scope) = self.gs.get_scopes().get_scope(&parent_scope) { + let mut doc = None; + if let Some(schema_symbol) = parent_scope.get_owner() { + let schema_symbol = self + .gs + .get_symbols() + .get_symbol(schema_symbol) + .ok_or(anyhow!("schema_symbol not found1"))?; + if let Some(schema_ty) = schema_symbol.get_sema_info().ty.clone() { + if !unification_stmt.target.node.names.is_empty() { + let schema_ty = schema_ty.into_schema_type(); + if let Some(attr) = schema_ty + .attrs + .get(&unification_stmt.target.node.names[0].node) + { + doc = attr.doc.clone() + } + let attr_symbol = self + .gs + .get_symbols() + .symbols_info + .node_symbol_map + .get( + &self + .ctx + .get_node_key(&unification_stmt.target.node.names[0].id), + ) + .cloned(); + if let Some(attr_symbol) = attr_symbol { + if let Some(symbol) = self + .gs + .get_symbols_mut() + .attributes + .get_mut(attr_symbol.get_id()) + { + symbol.sema_info = SymbolSemanticInfo { + ty: self + .ctx + .node_ty_map + .borrow() + .get(&self.ctx.get_node_key( + &unification_stmt.target.node.names[0].id, + )) + .map(|ty| ty.clone()), + doc, + }; + } + } + } + } + }; + } + } + self.ctx.maybe_def = false; + self.walk_schema_expr(&unification_stmt.value.node)?; + Ok(None) + } + + fn walk_type_alias_stmt(&mut self, type_alias_stmt: &'ctx ast::TypeAliasStmt) -> Self::Result { + let alias_symbol = self + .gs + .get_symbols() + .get_symbol_by_fully_qualified_name( + &(self.ctx.current_pkgpath.as_ref().unwrap().clone() + + "." + + &type_alias_stmt.type_name.node.get_name()), + ) + .ok_or(anyhow!("alias_symbol not found"))?; + if let Some(symbol) = self + .gs + .get_symbols_mut() + .type_aliases + .get_mut(alias_symbol.get_id()) + { + symbol.sema_info = SymbolSemanticInfo { + ty: self + .ctx + .node_ty_map + .borrow() + .get(&self.ctx.get_node_key(&type_alias_stmt.type_name.id)) + .map(|ty| ty.clone()), + doc: None, + }; + } + self.walk_type_expr(Some(&type_alias_stmt.ty))?; + Ok(None) + } + + fn walk_assign_stmt(&mut self, assign_stmt: &'ctx ast::AssignStmt) -> Self::Result { + for target in &assign_stmt.targets { + self.ctx.maybe_def = true; + self.walk_target_expr_with_hint(target, assign_stmt.ty.is_none())?; + self.ctx.maybe_def = false; + } + self.walk_type_expr(assign_stmt.ty.as_ref().map(|ty| ty.as_ref()))?; + self.expr(&assign_stmt.value)?; + Ok(None) + } + + fn walk_aug_assign_stmt(&mut self, aug_assign_stmt: &'ctx ast::AugAssignStmt) -> Self::Result { + self.walk_target_expr(&aug_assign_stmt.target)?; + self.expr(&aug_assign_stmt.value)?; + Ok(None) + } + + fn walk_assert_stmt(&mut self, assert_stmt: &'ctx ast::AssertStmt) -> Self::Result { + self.expr(&assert_stmt.test)?; + if let Some(if_cond) = &assert_stmt.if_cond { + self.expr(if_cond)?; + } + if let Some(msg) = &assert_stmt.msg { + self.expr(msg)?; + } + Ok(None) + } + + fn walk_if_stmt(&mut self, if_stmt: &'ctx ast::IfStmt) -> Self::Result { + self.expr(&if_stmt.cond)?; + for stmt in if_stmt.body.iter() { + self.stmt(stmt)?; + } + for stmt in if_stmt.orelse.iter() { + self.stmt(stmt)?; + } + Ok(None) + } + + fn walk_import_stmt(&mut self, import_stmt: &'ctx ast::ImportStmt) -> Self::Result { + let ast_id = self.ctx.cur_node.clone(); + let (start_pos, end_pos) = import_stmt + .asname + .clone() + .unwrap_or(import_stmt.path.clone()) + .get_span_pos(); + + let unresolved = UnresolvedSymbol::new( + import_stmt.path.node.clone(), + start_pos, + end_pos, + None, + self.ctx.is_type_expr, + ); + let package_symbol = match self + .gs + .get_symbols() + .get_symbol_by_fully_qualified_name(&import_stmt.path.node) + { + Some(symbol) => symbol, + None => return Ok(None), + }; + let unresolved_ref = self.gs.get_symbols_mut().alloc_unresolved_symbol( + unresolved, + self.ctx.get_node_key(&ast_id), + self.ctx.current_pkgpath.clone().unwrap(), + ); + self.gs + .get_symbols_mut() + .set_def_and_ref(package_symbol, unresolved_ref); + self.gs + .get_symbols_mut() + .symbols_info + .node_symbol_map + .insert(self.ctx.get_node_key(&ast_id), unresolved_ref); + let cur_scope = *self.ctx.scopes.last().unwrap(); + self.gs + .get_scopes_mut() + .add_ref_to_scope(cur_scope, unresolved_ref); + Ok(Some(unresolved_ref)) + } + + fn walk_schema_stmt(&mut self, schema_stmt: &'ctx ast::SchemaStmt) -> Self::Result { + let (start, end) = (self.ctx.start_pos.clone(), self.ctx.end_pos.clone()); + let schema_ty = self + .ctx + .node_ty_map + .borrow() + .get(&self.ctx.get_node_key(&schema_stmt.name.id)) + .ok_or(anyhow!( + "schema_ty not found when walk schema stmt {:?}", + schema_stmt + ))? + .clone(); + let schema_symbol = self + .gs + .get_symbols() + .get_type_symbol(&schema_ty, self.get_current_module_info()) + .ok_or(anyhow!("schema_symbol not found"))?; + if self + .gs + .get_symbols() + .schemas + .contains(schema_symbol.get_id()) + { + let mut schema_builtin_member = IndexMap::new(); + for name in SCHEMA_MEMBER_FUNCTIONS.iter() { + let func_ty = Arc::new(Type::function( + Some(schema_ty.clone()), + Type::list_ref(Type::any_ref()), + &[], + "", + false, + None, + )); + let mut func_value = ValueSymbol::new( + name.to_string(), + Position::dummy_pos(), + Position::dummy_pos(), + Some(schema_symbol), + false, + ); + func_value.sema_info.ty = Some(func_ty); + let func_symbol_ref = self.gs.get_symbols_mut().alloc_value_symbol( + func_value, + self.ctx.get_node_key(&ast::AstIndex::default()), + self.ctx.current_pkgpath.clone().unwrap(), + ); + schema_builtin_member.insert(name.to_string(), func_symbol_ref); + } + self.gs + .get_symbols_mut() + .symbols_info + .schema_builtin_symbols + .insert(schema_symbol, schema_builtin_member); + self.gs + .get_symbols_mut() + .schemas + .get_mut(schema_symbol.get_id()) + .ok_or(anyhow!("schema_symbol not found"))? + .sema_info = SymbolSemanticInfo { + ty: Some(schema_ty.clone()), + doc: schema_stmt.doc.as_ref().map(|doc| doc.node.clone()), + }; + } + + self.resolve_decorator(&schema_stmt.decorators); + + let mut last_end_pos = start.clone(); + + self.enter_schema_def_scope( + &schema_ty.into_schema_type().name, + &self.ctx.current_filename.clone().unwrap(), + start, + end.clone(), + LocalSymbolScopeKind::SchemaDef, + ); + let cur_scope = *self.ctx.scopes.last().unwrap(); + self.gs + .get_scopes_mut() + .set_owner_to_scope(cur_scope, schema_symbol); + if let Some(parent) = &schema_stmt.parent_name { + self.gs + .get_symbols_mut() + .schemas + .get_mut(schema_symbol.get_id()) + .ok_or(anyhow!("schema_symbol not found"))? + .parent_schema = self.walk_identifier_expr(parent)?; + } + if let Some(for_host) = &schema_stmt.for_host_name { + self.gs + .get_symbols_mut() + .schemas + .get_mut(schema_symbol.get_id()) + .ok_or(anyhow!("schema_symbol not found"))? + .for_host = self.walk_identifier_expr(for_host)?; + } + let mut mixins = vec![]; + for mixin in schema_stmt.mixins.iter() { + if let Some(mixin) = self.walk_identifier_expr(mixin)? { + mixins.push(mixin); + } + last_end_pos = mixin.get_end_pos(); + } + self.gs + .get_symbols_mut() + .schemas + .get_mut(schema_symbol.get_id()) + .ok_or(anyhow!("schema_symbol not found"))? + .mixins = mixins; + + if let Some(args) = &schema_stmt.args { + self.walk_arguments(&args.node)?; + last_end_pos = args.get_end_pos(); + } + if let Some(index_signature) = &schema_stmt.index_signature { + if let Some(key_name) = &index_signature.node.key_name { + let (start, end) = key_name.get_span_pos(); + let value = self.gs.get_symbols_mut().alloc_value_symbol( + ValueSymbol::new( + key_name.node.clone(), + start, + end, + Some(schema_symbol), + false, + ), + self.ctx.get_node_key(&index_signature.id), + self.ctx.current_pkgpath.clone().unwrap(), + ); + if let Some(symbol) = self.gs.get_symbols_mut().values.get_mut(value.get_id()) { + symbol.sema_info = SymbolSemanticInfo { + ty: self + .ctx + .node_ty_map + .borrow() + .get(&self.ctx.get_node_key(&index_signature.id)) + .map(|ty| ty.clone()), + doc: None, + }; + } + + self.gs + .get_scopes_mut() + .add_def_to_scope(cur_scope, key_name.node.clone(), value); + } + self.walk_type_expr(Some(&index_signature.node.value_ty))?; + if let Some(value) = &index_signature.node.value { + self.expr(value)?; + }; + last_end_pos = index_signature.get_end_pos(); + } + + if let Some(doc) = &schema_stmt.doc { + let (start, end) = doc.get_span_pos(); + let comment_symbol = CommentOrDocSymbol::new(start, end, doc.node.clone()); + self.gs.get_symbols_mut().alloc_comment_symbol( + comment_symbol, + self.ctx.get_node_key(&self.ctx.cur_node), + self.ctx.current_pkgpath.clone().unwrap(), + ); + } + + for stmt in schema_stmt.body.iter() { + if let Some(attribute_symbol) = self.stmt(&stmt)? { + let name = self + .gs + .get_symbols() + .get_symbol(attribute_symbol) + .ok_or(anyhow!("attribute_symbol not found"))? + .get_name(); + self.gs + .get_symbols_mut() + .schemas + .get_mut(schema_symbol.get_id()) + .ok_or(anyhow!("schema_symbol not found"))? + .attributes + .insert(name, attribute_symbol); + } + last_end_pos = stmt.get_end_pos(); + } + + let has_check = !schema_stmt.checks.is_empty(); + if has_check { + self.enter_local_scope( + &self.ctx.current_filename.clone().unwrap(), + last_end_pos, + end, + LocalSymbolScopeKind::Check, + ); + } + + for check_expr in schema_stmt.checks.iter() { + self.walk_check_expr(&check_expr.node)?; + } + + if has_check { + self.leave_scope(); + } + self.leave_scope(); + + Ok(Some(schema_symbol)) + } + + fn walk_rule_stmt(&mut self, rule_stmt: &'ctx ast::RuleStmt) -> Self::Result { + let rule_ty = self + .ctx + .node_ty_map + .borrow() + .get(&self.ctx.get_node_key(&rule_stmt.name.id)) + .ok_or(anyhow!("rule_ty not found"))? + .clone(); + let rule_symbol = self + .gs + .get_symbols() + .get_type_symbol(&rule_ty, self.get_current_module_info()) + .ok_or(anyhow!("rule_symbol not found"))?; + if let Some(symbol) = self + .gs + .get_symbols_mut() + .rules + .get_mut(rule_symbol.get_id()) + { + symbol.sema_info = SymbolSemanticInfo { + ty: self + .ctx + .node_ty_map + .borrow() + .get(&self.ctx.get_node_key(&rule_stmt.name.id)) + .map(|ty| ty.clone()), + doc: rule_stmt.doc.as_ref().map(|doc| doc.node.clone()), + }; + } + + if let Some(for_host) = &rule_stmt.for_host_name { + self.gs + .get_symbols_mut() + .rules + .get_mut(rule_symbol.get_id()) + .ok_or(anyhow!("rule_symbol not found"))? + .for_host = self.walk_identifier_expr(for_host)?; + } + let mut parent_rules = vec![]; + for parent_rule in rule_stmt.parent_rules.iter() { + parent_rules.push( + self.walk_identifier_expr(parent_rule)? + .ok_or(anyhow!("parent_rule not found"))?, + ); + } + self.gs + .get_symbols_mut() + .rules + .get_mut(rule_symbol.get_id()) + .ok_or(anyhow!("rule_symbol not found"))? + .parent_rules = parent_rules; + self.resolve_decorator(&rule_stmt.decorators); + Ok(Some(rule_symbol)) + } + + fn walk_quant_expr(&mut self, quant_expr: &'ctx ast::QuantExpr) -> Self::Result { + let (start, end) = (self.ctx.start_pos.clone(), self.ctx.end_pos.clone()); + self.expr(&quant_expr.target)?; + self.enter_local_scope( + &self.ctx.current_filename.as_ref().unwrap().clone(), + start, + end, + LocalSymbolScopeKind::Quant, + ); + let cur_scope = *self.ctx.scopes.last().unwrap(); + for target in quant_expr.variables.iter() { + if target.node.names.is_empty() { + continue; + } + let name = target.node.get_name(); + let (start_pos, end_pos): Range = target.get_span_pos(); + let ast_id = if target.node.names.is_empty() { + &target.id + } else { + &target.node.names.last().unwrap().id + }; + let value = self.gs.get_symbols_mut().alloc_value_symbol( + ValueSymbol::new(name.clone(), start_pos, end_pos.clone(), None, false), + self.ctx.get_node_key(&ast_id), + self.ctx.current_pkgpath.clone().unwrap(), + ); + self.gs + .get_scopes_mut() + .add_def_to_scope(cur_scope, name, value); + let symbols = self.gs.get_symbols_mut(); + let ty = match symbols.values.get_mut(value.get_id()) { + Some(symbol) => { + let ty = self + .ctx + .node_ty_map + .borrow() + .get(&self.ctx.get_node_key(ast_id)) + .map(|ty| ty.clone()); + symbol.sema_info = SymbolSemanticInfo { + ty: ty.clone(), + doc: None, + }; + ty + } + None => None, + }; + if let Some(ty) = ty { + symbols.alloc_hint( + SymbolHint { + kind: SymbolHintKind::TypeHint(ty.ty_hint()), + pos: end_pos, + }, + self.ctx.current_pkgpath.clone().unwrap(), + ); + } + } + + if let Some(if_cond) = &quant_expr.if_cond { + self.expr(&if_cond)?; + } + self.expr(&quant_expr.test)?; + self.leave_scope(); + Ok(None) + } + + fn walk_schema_attr(&mut self, schema_attr: &'ctx ast::SchemaAttr) -> Self::Result { + let attr_symbol = *self + .gs + .get_symbols() + .symbols_info + .node_symbol_map + .get(&self.ctx.get_node_key(&schema_attr.name.id)) + .ok_or(anyhow!("attr_symbol not found"))?; + let parent_scope = *self.ctx.scopes.last().unwrap(); + let parent_scope = self.gs.get_scopes().get_scope(&parent_scope).unwrap(); + let mut doc = None; + if let Some(schema_symbol) = parent_scope.get_owner() { + let schema_symbol = self + .gs + .get_symbols() + .get_symbol(schema_symbol) + .ok_or(anyhow!("schema_symbol not found"))?; + if let Some(schema_ty) = schema_symbol.get_sema_info().ty.clone() { + let schema_ty = schema_ty.into_schema_type(); + if let Some(attr) = schema_ty.attrs.get(&schema_attr.name.node) { + doc = attr.doc.clone() + } + } + }; + + if let Some(symbol) = self + .gs + .get_symbols_mut() + .attributes + .get_mut(attr_symbol.get_id()) + { + symbol.sema_info = SymbolSemanticInfo { + ty: self + .ctx + .node_ty_map + .borrow() + .get(&self.ctx.get_node_key(&schema_attr.name.id)) + .map(|ty| ty.clone()), + doc, + }; + }; + + self.walk_type_expr(Some(&schema_attr.ty))?; + if let Some(value) = &schema_attr.value { + self.expr(value)?; + } + + self.resolve_decorator(&schema_attr.decorators); + let cur_scope = *self.ctx.scopes.last().unwrap(); + let name = self + .gs + .get_symbols() + .get_symbol(attr_symbol) + .ok_or(anyhow!("attribute_symbol not found"))? + .get_name(); + self.gs + .get_scopes_mut() + .add_def_to_scope(cur_scope, name, attr_symbol); + Ok(Some(attr_symbol)) + } + + /// if else -> sup([body, orelse]) + fn walk_if_expr(&mut self, if_expr: &'ctx ast::IfExpr) -> Self::Result { + self.expr(&if_expr.cond)?; + self.expr(&if_expr.body)?; + self.expr(&if_expr.orelse)?; + Ok(None) + } + + fn walk_unary_expr(&mut self, unary_expr: &'ctx ast::UnaryExpr) -> Self::Result { + self.expr(&unary_expr.operand)?; + Ok(None) + } + + fn walk_binary_expr(&mut self, binary_expr: &'ctx ast::BinaryExpr) -> Self::Result { + self.expr(&binary_expr.left)?; + self.expr(&binary_expr.right)?; + Ok(None) + } + + fn walk_selector_expr(&mut self, selector_expr: &'ctx ast::SelectorExpr) -> Self::Result { + self.expr(&selector_expr.value)?; + let mut parent_ty = match self + .ctx + .node_ty_map + .borrow() + .get(&self.ctx.get_node_key(&selector_expr.value.id)) + { + Some(ty) => ty.clone(), + None => return Ok(None), + }; + for name in &selector_expr.attr.node.names { + let def_symbol_ref = match self.gs.get_symbols().get_type_attribute( + &parent_ty, + &name.node, + self.get_current_module_info(), + ) { + Some(symbol) => symbol, + None => return Ok(None), + }; + + let (start_pos, end_pos): Range = name.get_span_pos(); + let ast_id = name.id.clone(); + let unresolved = UnresolvedSymbol::new( + name.node.clone(), + start_pos, + end_pos, + None, + self.ctx.is_type_expr, + ); + let unresolved_ref = self.gs.get_symbols_mut().alloc_unresolved_symbol( + unresolved, + self.ctx.get_node_key(&ast_id), + self.ctx.current_pkgpath.clone().unwrap(), + ); + + self.gs + .get_symbols_mut() + .set_def_and_ref(def_symbol_ref, unresolved_ref); + + let cur_scope = *self.ctx.scopes.last().unwrap(); + self.gs + .get_scopes_mut() + .add_ref_to_scope(cur_scope, unresolved_ref); + + parent_ty = match self + .ctx + .node_ty_map + .borrow() + .get(&self.ctx.get_node_key(&name.id)) + { + Some(ty) => ty.clone(), + None => return Ok(None), + }; + } + Ok(None) + } + + fn walk_call_expr(&mut self, call_expr: &'ctx ast::CallExpr) -> Self::Result { + let start = call_expr.func.get_end_pos(); + let end = self.ctx.end_pos.clone(); + let func_symbol = self.expr(&call_expr.func)?; + let call_ty = self + .ctx + .node_ty_map + .borrow() + .get(&self.ctx.get_node_key(&call_expr.func.id)) + .map(|ty| ty.clone()); + + if let Some(ty) = call_ty { + match &ty.kind { + TypeKind::Schema(schema_ty) => { + if !schema_ty.is_instance { + self.enter_local_scope( + &self.ctx.current_filename.as_ref().unwrap().clone(), + start, + end, + LocalSymbolScopeKind::Config, + ); + + if let Some(owner) = func_symbol { + let cur_scope = self.ctx.scopes.last().unwrap(); + self.gs + .get_scopes_mut() + .set_owner_to_scope(*cur_scope, owner); + } + self.do_arguments_symbol_resolve_with_hint( + &call_expr.args, + &call_expr.keywords, + &schema_ty.func.params, + true, + )?; + + self.leave_scope(); + } + } + TypeKind::Function(func_ty) => { + self.enter_local_scope( + &self.ctx.current_filename.as_ref().unwrap().clone(), + start, + end, + LocalSymbolScopeKind::Callable, + ); + + if let Some(owner) = func_symbol { + let cur_scope = self.ctx.scopes.last().unwrap(); + self.gs + .get_scopes_mut() + .set_owner_to_scope(*cur_scope, owner); + } + + self.do_arguments_symbol_resolve_with_hint( + &call_expr.args, + &call_expr.keywords, + &func_ty.params, + true, + )?; + self.leave_scope(); + } + _ => {} + } + } + + Ok(None) + } + + fn walk_subscript(&mut self, subscript: &'ctx ast::Subscript) -> Self::Result { + self.expr(&subscript.value)?; + if let Some(index) = &subscript.index { + self.expr(index)?; + } else { + for expr in [&subscript.lower, &subscript.upper, &subscript.step] + .iter() + .copied() + .flatten() + { + self.expr(expr)?; + } + } + Ok(None) + } + + fn walk_paren_expr(&mut self, paren_expr: &'ctx ast::ParenExpr) -> Self::Result { + self.expr(&paren_expr.expr)?; + Ok(None) + } + + fn walk_list_expr(&mut self, list_expr: &'ctx ast::ListExpr) -> Self::Result { + for expr in list_expr.elts.iter() { + self.expr(expr)?; + } + Ok(None) + } + + fn walk_list_comp(&mut self, list_comp: &'ctx ast::ListComp) -> Self::Result { + let start = list_comp.elt.get_pos(); + let end = match list_comp.generators.last() { + Some(last) => last.get_end_pos(), + None => list_comp.elt.get_end_pos(), + }; + self.enter_local_scope( + &self.ctx.current_filename.clone().unwrap(), + start, + end, + LocalSymbolScopeKind::List, + ); + for comp_clause in &list_comp.generators { + self.walk_comp_clause(&comp_clause.node)?; + } + self.expr(&list_comp.elt)?; + self.leave_scope(); + Ok(None) + } + + fn walk_dict_comp(&mut self, dict_comp: &'ctx ast::DictComp) -> Self::Result { + let (start, key) = match dict_comp.entry.key.as_ref() { + Some(key) => (key.get_pos(), Some(key)), + None => (dict_comp.entry.value.get_pos(), None), + }; + + let end = match dict_comp.generators.last() { + Some(last) => last.get_end_pos(), + None => dict_comp.entry.value.get_end_pos(), + }; + self.enter_local_scope( + &self.ctx.current_filename.clone().unwrap(), + start, + end, + LocalSymbolScopeKind::Dict, + ); + for comp_clause in &dict_comp.generators { + self.walk_comp_clause(&comp_clause.node)?; + } + if let Some(key) = key { + self.expr(key)?; + } + self.expr(&dict_comp.entry.value)?; + self.leave_scope(); + Ok(None) + } + + fn walk_list_if_item_expr( + &mut self, + list_if_item_expr: &'ctx ast::ListIfItemExpr, + ) -> Self::Result { + self.expr(&list_if_item_expr.if_cond)?; + if let Some(orelse) = &list_if_item_expr.orelse { + self.expr(orelse)?; + } + for expr in list_if_item_expr.exprs.iter() { + self.expr(expr)?; + } + Ok(None) + } + + fn walk_starred_expr(&mut self, starred_expr: &'ctx ast::StarredExpr) -> Self::Result { + self.expr(&starred_expr.value)?; + Ok(None) + } + + fn walk_config_if_entry_expr( + &mut self, + config_if_entry_expr: &'ctx ast::ConfigIfEntryExpr, + ) -> Self::Result { + self.expr(&config_if_entry_expr.if_cond)?; + self.walk_config_entries(&config_if_entry_expr.items)?; + if let Some(expr) = config_if_entry_expr.orelse.as_ref() { + self.expr(expr)?; + } + Ok(None) + } + + fn walk_comp_clause(&mut self, comp_clause: &'ctx ast::CompClause) -> Self::Result { + self.expr(&comp_clause.iter)?; + for target in comp_clause.targets.iter() { + self.ctx.maybe_def = true; + self.walk_identifier_expr_with_hint(target, true)?; + self.ctx.maybe_def = false; + } + for if_expr in comp_clause.ifs.iter() { + self.expr(if_expr)?; + } + Ok(None) + } + + fn walk_schema_expr(&mut self, schema_expr: &'ctx ast::SchemaExpr) -> Self::Result { + self.walk_identifier_expr(&schema_expr.name)?; + let schema_ty = self + .ctx + .node_ty_map + .borrow() + .get(&self.ctx.get_node_key(&schema_expr.name.id)) + .ok_or(anyhow!( + "schema_ty not found when walk schema expr {:?}", + schema_expr + ))? + .clone(); + match schema_ty.kind { + TypeKind::Schema(_) => { + self.expr(&schema_expr.config)?; + self.do_arguments_symbol_resolve(&schema_expr.args, &schema_expr.kwargs)?; + } + _ => { + // Invalid schema type, nothing todo + } + } + Ok(None) + } + + fn walk_config_expr(&mut self, config_expr: &'ctx ast::ConfigExpr) -> Self::Result { + self.walk_config_entries(&config_expr.items)?; + Ok(None) + } + + fn walk_check_expr(&mut self, check_expr: &'ctx ast::CheckExpr) -> Self::Result { + if let Some(msg) = &check_expr.msg { + self.expr(msg)?; + } + if let Some(if_cond) = &check_expr.if_cond { + self.expr(if_cond)?; + } + self.expr(&check_expr.test)?; + Ok(None) + } + + fn walk_lambda_expr(&mut self, lambda_expr: &'ctx ast::LambdaExpr) -> Self::Result { + let (start, end) = (self.ctx.start_pos.clone(), self.ctx.end_pos.clone()); + self.enter_local_scope( + &self.ctx.current_filename.clone().unwrap(), + start, + end, + LocalSymbolScopeKind::Lambda, + ); + if let Some(args) = &lambda_expr.args { + self.walk_arguments(&args.node)?; + } + if let Some(ret_annotation_ty) = &lambda_expr.return_ty { + self.walk_type_expr(Some(&ret_annotation_ty))?; + } + for stmt in lambda_expr.body.iter() { + self.stmt(&stmt)?; + } + self.leave_scope(); + Ok(None) + } + + fn walk_keyword(&mut self, keyword: &'ctx ast::Keyword) -> Self::Result { + self.ctx.maybe_def = true; + self.walk_identifier_expr(&keyword.arg)?; + self.ctx.maybe_def = false; + if let Some(value) = &keyword.value { + self.expr(&value)?; + } + Ok(None) + } + + fn walk_arguments(&mut self, arguments: &'ctx ast::Arguments) -> Self::Result { + for (i, arg) in arguments.args.iter().enumerate() { + let ty = arguments.get_arg_type_node(i); + self.walk_type_expr(ty)?; + self.ctx.maybe_def = true; + self.walk_identifier_expr(arg)?; + self.ctx.maybe_def = false; + + if let Some(val) = &arguments.defaults[i] { + self.expr(val)?; + } + } + Ok(None) + } + + fn walk_compare(&mut self, compare: &'ctx ast::Compare) -> Self::Result { + self.expr(&compare.left)?; + for comparator in compare.comparators.iter() { + self.expr(&comparator)?; + } + Ok(None) + } + + fn walk_identifier(&mut self, identifier: &'ctx ast::Identifier) -> Self::Result { + let symbol_ref = self.resolve_names(&identifier.names, self.ctx.maybe_def)?; + Ok(symbol_ref) + } + + fn walk_target(&mut self, target: &'ctx ast::Target) -> Self::Result { + let symbol_ref = self.resolve_target(&target, self.ctx.maybe_def)?; + Ok(symbol_ref) + } + + fn walk_number_lit(&mut self, _number_lit: &'ctx ast::NumberLit) -> Self::Result { + Ok(None) + } + + fn walk_string_lit(&mut self, _string_lit: &'ctx ast::StringLit) -> Self::Result { + Ok(None) + } + + fn walk_name_constant_lit( + &mut self, + _name_constant_lit: &'ctx ast::NameConstantLit, + ) -> Self::Result { + Ok(None) + } + + fn walk_joined_string(&mut self, joined_string: &'ctx ast::JoinedString) -> Self::Result { + self.ctx.maybe_def = false; + for expr in joined_string.values.iter() { + self.expr(expr)?; + } + Ok(None) + } + + fn walk_formatted_value(&mut self, formatted_value: &'ctx ast::FormattedValue) -> Self::Result { + self.expr(&formatted_value.value)?; + Ok(None) + } + + fn walk_comment(&mut self, comment: &'ctx ast::Comment) -> Self::Result { + let (start, end) = (self.ctx.start_pos.clone(), self.ctx.end_pos.clone()); + let comment_symbol = CommentOrDocSymbol::new(start, end, comment.text.clone()); + Ok(self.gs.get_symbols_mut().alloc_comment_symbol( + comment_symbol, + self.ctx.get_node_key(&self.ctx.cur_node), + self.ctx.current_pkgpath.clone().unwrap(), + )) + } + + fn walk_missing_expr(&mut self, _missing_expr: &'ctx ast::MissingExpr) -> Self::Result { + Ok(None) + } +} + +impl<'ctx> AdvancedResolver<'_> { + #[inline] + pub fn expr(&mut self, expr: &'ctx ast::NodeRef) -> ResolvedResult { + if matches!( + &expr.node, + ast::Expr::Identifier(_) + | ast::Expr::Config(_) + | ast::Expr::Schema(_) + | ast::Expr::ConfigIfEntry(_) + | ast::Expr::Quant(_) + | ast::Expr::Lambda(_) + | ast::Expr::Call(_) + ) { + let (start, end) = expr.get_span_pos(); + self.ctx.start_pos = start; + self.ctx.end_pos = end; + } + self.ctx.cur_node = expr.id.clone(); + + if let Some(expr_ty) = self + .ctx + .node_ty_map + .borrow() + .get(&self.ctx.get_node_key(&expr.id)) + { + match &expr_ty.kind { + TypeKind::Schema(_) => { + let schema_symbol = self + .gs + .get_symbols() + .get_type_symbol(&expr_ty, self.get_current_module_info()) + .ok_or(anyhow!("schema_symbol not found"))?; + self.ctx.schema_symbol_stack.push(Some(schema_symbol)); + } + _ => { + self.ctx.schema_symbol_stack.push(None); + } + } + } + + let expr_symbol = self.walk_expr(&expr.node); + self.ctx.schema_symbol_stack.pop(); + + match expr_symbol { + Ok(None) => match self + .ctx + .node_ty_map + .borrow() + .get(&self.ctx.get_node_key(&expr.id)) + { + Some(ty) => match expr.node { + ast::Expr::Missing(_) + | ast::Expr::Binary(_) + | ast::Expr::CompClause(_) + | ast::Expr::Keyword(_) + | ast::Expr::Arguments(_) + | ast::Expr::Compare(_) => return Ok(None), + _ => { + let (_, end) = expr.get_span_pos(); + let mut expr_symbol = ExpressionSymbol::new( + format!("@{}", expr.node.get_expr_name()), + end.clone(), + end, + None, + ); + expr_symbol.sema_info.ty = if matches!(&expr.node, | ast::Expr::Call(_)) { + if let TypeKind::Function(func_ty) = &ty.kind { + Some(func_ty.return_ty.clone()) + } else { + Some(ty.clone()) + } + } else { + Some(ty.clone()) + }; + + Ok(self.gs.get_symbols_mut().alloc_expression_symbol( + expr_symbol, + self.ctx.get_node_key(&expr.id), + self.ctx.current_pkgpath.clone().unwrap(), + )) + } + }, + None => Ok(None), + }, + res => res, + } + } + + #[inline] + pub fn stmt(&mut self, stmt: &'ctx ast::NodeRef) -> ResolvedResult { + let (start, end) = stmt.get_span_pos(); + self.ctx.start_pos = start; + self.ctx.end_pos = end; + self.ctx.cur_node = stmt.id.clone(); + let result = self.walk_stmt(&stmt.node); + result + } + + fn resolve_names(&mut self, names: &[ast::Node], maybe_def: bool) -> ResolvedResult { + let first_name = names.get(0).unwrap(); + let cur_scope = *self.ctx.scopes.last().unwrap(); + + let mut first_symbol = self.gs.look_up_symbol( + &first_name.node, + cur_scope, + self.get_current_module_info(), + maybe_def, + !self.ctx.in_config_r_value, + ); + if first_symbol.is_none() { + // Maybe import package symbol + let module_info = self.get_current_module_info().unwrap(); + + let import_info = module_info.get_import_info(&first_name.node); + if import_info.is_some() { + first_symbol = self + .gs + .get_symbols() + .get_symbol_by_fully_qualified_name(&import_info.unwrap().fully_qualified_name); + } + + if let Some(first_symbol) = first_symbol { + if self + .gs + .get_symbols() + .get_symbol(first_symbol) + .ok_or(anyhow!("first name symbol not found"))? + .get_sema_info() + .ty + .is_none() + { + if let Some(ty) = self + .ctx + .node_ty_map + .borrow() + .get(&self.ctx.get_node_key(&first_name.id)) + { + self.gs + .get_symbols_mut() + .set_symbol_type(first_symbol, ty.clone()); + } + } + } + } + match first_symbol { + Some(symbol_ref) => { + let mut ret_symbol = symbol_ref.clone(); + let (start_pos, end_pos): Range = first_name.get_span_pos(); + let def_symbol = self + .gs + .get_symbols() + .get_symbol(symbol_ref) + .ok_or(anyhow!("first name symbol not found"))?; + let (def_start_pos, def_end_pos) = def_symbol.get_range(); + + let cur_scope = *self.ctx.scopes.last().unwrap(); + let ast_id = first_name.id.clone(); + let mut first_unresolved = UnresolvedSymbol::new( + first_name.node.clone(), + start_pos.clone(), + end_pos.clone(), + None, + self.ctx.is_type_expr, + ); + let name = def_symbol.get_name(); + first_unresolved.def = Some(symbol_ref); + let first_unresolved_ref = self.gs.get_symbols_mut().alloc_unresolved_symbol( + first_unresolved, + self.ctx.get_node_key(&ast_id), + self.ctx.current_pkgpath.clone().unwrap(), + ); + + match cur_scope.get_kind() { + crate::core::scope::ScopeKind::Local => { + let local_scope = self + .gs + .get_scopes() + .try_get_local_scope(&cur_scope) + .unwrap(); + match local_scope.get_kind() { + LocalSymbolScopeKind::Config => { + if let crate::core::symbol::SymbolKind::Attribute = + symbol_ref.get_kind() + { + if maybe_def { + self.gs.get_scopes_mut().add_def_to_scope( + cur_scope, + name, + first_unresolved_ref, + ); + ret_symbol = first_unresolved_ref; + } + } + } + _ => {} + } + } + _ => {} + } + + if def_start_pos != start_pos || def_end_pos != end_pos { + self.gs + .get_symbols_mut() + .set_def_and_ref(symbol_ref, first_unresolved_ref); + + let cur_scope = *self.ctx.scopes.last().unwrap(); + self.gs + .get_scopes_mut() + .add_ref_to_scope(cur_scope, first_unresolved_ref); + } + + if names.len() > 1 { + let mut parent_ty = match self + .ctx + .node_ty_map + .borrow() + .get(&self.ctx.get_node_key(&first_name.id)) + { + Some(ty) => ty.clone(), + None => return Ok(None), + }; + + for index in 1..names.len() { + let name = names.get(index).unwrap(); + let def_symbol_ref = match self.gs.get_symbols().get_type_attribute( + &parent_ty, + &name.node, + self.get_current_module_info(), + ) { + Some(symbol) => symbol, + None => return Ok(None), + }; + + let (start_pos, end_pos): Range = name.get_span_pos(); + let ast_id = name.id.clone(); + let mut unresolved = UnresolvedSymbol::new( + name.node.clone(), + start_pos, + end_pos, + None, + self.ctx.is_type_expr, + ); + + unresolved.sema_info = SymbolSemanticInfo { + ty: self + .ctx + .node_ty_map + .borrow() + .get(&self.ctx.get_node_key(&name.id)) + .map(|ty| ty.clone()), + doc: None, + }; + + let unresolved_ref = self.gs.get_symbols_mut().alloc_unresolved_symbol( + unresolved, + self.ctx.get_node_key(&ast_id), + self.ctx.current_pkgpath.clone().unwrap(), + ); + + self.gs + .get_symbols_mut() + .set_def_and_ref(def_symbol_ref, unresolved_ref); + + let cur_scope = *self.ctx.scopes.last().unwrap(); + self.gs + .get_scopes_mut() + .add_ref_to_scope(cur_scope, unresolved_ref); + + parent_ty = match self + .ctx + .node_ty_map + .borrow() + .get(&self.ctx.get_node_key(&name.id)) + { + Some(ty) => ty.clone(), + None => return Ok(None), + }; + if index == names.len() - 1 { + return Ok(Some(unresolved_ref)); + } + } + } + Ok(Some(ret_symbol)) + } + None => { + if maybe_def { + let (start_pos, end_pos): Range = first_name.get_span_pos(); + let ast_id = first_name.id.clone(); + let first_value = self.gs.get_symbols_mut().alloc_value_symbol( + ValueSymbol::new(first_name.node.clone(), start_pos, end_pos, None, false), + self.ctx.get_node_key(&ast_id), + self.ctx.current_pkgpath.clone().unwrap(), + ); + self.gs.get_scopes_mut().add_def_to_scope( + cur_scope, + first_name.node.clone(), + first_value, + ); + + if let Some(symbol) = self + .gs + .get_symbols_mut() + .values + .get_mut(first_value.get_id()) + { + symbol.sema_info = SymbolSemanticInfo { + ty: self + .ctx + .node_ty_map + .borrow() + .get(&self.ctx.get_node_key(&first_name.id)) + .map(|ty| ty.clone()), + doc: None, + }; + } + + for index in 1..names.len() { + let name = names.get(index).unwrap(); + let (start_pos, end_pos): Range = name.get_span_pos(); + let ast_id = name.id.clone(); + let value = self.gs.get_symbols_mut().alloc_value_symbol( + ValueSymbol::new(name.node.clone(), start_pos, end_pos, None, false), + self.ctx.get_node_key(&ast_id), + self.ctx.current_pkgpath.clone().unwrap(), + ); + + self.gs.get_scopes_mut().add_def_to_scope( + cur_scope, + name.node.clone(), + value, + ); + + if let Some(symbol) = + self.gs.get_symbols_mut().values.get_mut(value.get_id()) + { + symbol.sema_info = SymbolSemanticInfo { + ty: self + .ctx + .node_ty_map + .borrow() + .get(&self.ctx.get_node_key(&name.id)) + .map(|ty| ty.clone()), + doc: None, + }; + } + if index == names.len() - 1 { + return Ok(Some(value)); + } + } + } + Ok(None) + } + } + } + + fn resolve_target(&mut self, target: &'ctx ast::Target, maybe_def: bool) -> ResolvedResult { + let first_name = &target.name; + let cur_scope = *self.ctx.scopes.last().unwrap(); + + let first_symbol = self.gs.look_up_symbol( + &first_name.node, + cur_scope, + self.get_current_module_info(), + true, + !self.ctx.in_config_r_value, + ); + match first_symbol { + Some(symbol_ref) => { + let (start_pos, end_pos): Range = first_name.get_span_pos(); + let (def_start_pos, def_end_pos) = self + .gs + .get_symbols() + .get_symbol(symbol_ref) + .ok_or(anyhow!("first name symbol not found"))? + .get_range(); + + // Get an unresolved symbol + if def_start_pos != start_pos || def_end_pos != end_pos { + let ast_id = first_name.id.clone(); + let mut first_unresolved = UnresolvedSymbol::new( + first_name.node.clone(), + start_pos, + end_pos, + None, + self.ctx.is_type_expr, + ); + first_unresolved.def = Some(symbol_ref); + let first_unresolved_ref = self.gs.get_symbols_mut().alloc_unresolved_symbol( + first_unresolved, + self.ctx.get_node_key(&ast_id), + self.ctx.current_pkgpath.clone().unwrap(), + ); + let cur_scope = *self.ctx.scopes.last().unwrap(); + self.gs + .get_scopes_mut() + .add_ref_to_scope(cur_scope, first_unresolved_ref); + } + if !target.paths.is_empty() { + let mut parent_ty = match self + .ctx + .node_ty_map + .borrow() + .get(&self.ctx.get_node_key(&first_name.id)) + { + Some(ty) => ty.clone(), + None => return Ok(None), + }; + + for (index, path) in target.paths.iter().enumerate() { + match path { + ast::MemberOrIndex::Member(member) => { + let name = member; + let def_symbol_ref = match self.gs.get_symbols().get_type_attribute( + &parent_ty, + &name.node, + self.get_current_module_info(), + ) { + Some(symbol) => symbol, + None => return Ok(None), + }; + + let (start_pos, end_pos): Range = name.get_span_pos(); + let ast_id = name.id.clone(); + let mut unresolved = UnresolvedSymbol::new( + name.node.clone(), + start_pos, + end_pos, + None, + self.ctx.is_type_expr, + ); + unresolved.def = Some(def_symbol_ref); + unresolved.sema_info = SymbolSemanticInfo { + ty: self + .ctx + .node_ty_map + .borrow() + .get(&self.ctx.get_node_key(&name.id)) + .map(|ty| ty.clone()), + doc: None, + }; + + let unresolved_ref = + self.gs.get_symbols_mut().alloc_unresolved_symbol( + unresolved, + self.ctx.get_node_key(&ast_id), + self.ctx.current_pkgpath.clone().unwrap(), + ); + + let cur_scope = *self.ctx.scopes.last().unwrap(); + self.gs + .get_scopes_mut() + .add_ref_to_scope(cur_scope, unresolved_ref); + + parent_ty = match self + .ctx + .node_ty_map + .borrow() + .get(&self.ctx.get_node_key(&name.id)) + { + Some(ty) => ty.clone(), + None => return Ok(None), + }; + if index == target.paths.len() - 1 { + return Ok(Some(unresolved_ref)); + } + } + ast::MemberOrIndex::Index(index_expr) => { + let last_maybe_def = self.ctx.maybe_def; + self.ctx.maybe_def = false; + let symbol = self.expr(index_expr); + parent_ty = match self + .ctx + .node_ty_map + .borrow() + .get(&self.ctx.get_node_key(&index_expr.id)) + { + Some(ty) => ty.clone(), + None => return Ok(None), + }; + self.ctx.maybe_def = last_maybe_def; + if index == target.paths.len() { + return symbol; + } + } + } + } + } + Ok(Some(symbol_ref)) + } + None => { + if maybe_def { + let (start_pos, end_pos): Range = first_name.get_span_pos(); + let ast_id = first_name.id.clone(); + let first_value = self.gs.get_symbols_mut().alloc_value_symbol( + ValueSymbol::new(first_name.node.clone(), start_pos, end_pos, None, false), + self.ctx.get_node_key(&ast_id), + self.ctx.current_pkgpath.clone().unwrap(), + ); + self.gs.get_scopes_mut().add_def_to_scope( + cur_scope, + first_name.node.clone(), + first_value, + ); + + if let Some(symbol) = self + .gs + .get_symbols_mut() + .values + .get_mut(first_value.get_id()) + { + symbol.sema_info = SymbolSemanticInfo { + ty: self + .ctx + .node_ty_map + .borrow() + .get(&self.ctx.get_node_key(&first_name.id)) + .map(|ty| ty.clone()), + doc: None, + }; + } + + for (index, path) in target.paths.iter().enumerate() { + match path { + ast::MemberOrIndex::Member(member) => { + let name = member; + let (start_pos, end_pos): Range = name.get_span_pos(); + let ast_id = name.id.clone(); + let value = self.gs.get_symbols_mut().alloc_value_symbol( + ValueSymbol::new( + name.node.clone(), + start_pos, + end_pos, + None, + false, + ), + self.ctx.get_node_key(&ast_id), + self.ctx.current_pkgpath.clone().unwrap(), + ); + + self.gs.get_scopes_mut().add_def_to_scope( + cur_scope, + name.node.clone(), + value, + ); + + if let Some(symbol) = + self.gs.get_symbols_mut().values.get_mut(value.get_id()) + { + symbol.sema_info = SymbolSemanticInfo { + ty: self + .ctx + .node_ty_map + .borrow() + .get(&self.ctx.get_node_key(&name.id)) + .map(|ty| ty.clone()), + doc: None, + }; + } + if index == target.paths.len() { + return Ok(Some(value)); + } + } + ast::MemberOrIndex::Index(index_expr) => { + let last_maybe_def = self.ctx.maybe_def; + self.ctx.maybe_def = false; + let symbol = self.expr(index_expr); + self.ctx.maybe_def = last_maybe_def; + if index == target.paths.len() { + return symbol; + } + } + } + } + } + Ok(None) + } + } + } + + #[inline] + pub fn walk_target_expr(&mut self, target: &'ctx ast::NodeRef) -> ResolvedResult { + self.walk_target_expr_with_hint(target, false) + } + + pub fn walk_target_expr_with_hint( + &mut self, + target: &'ctx ast::NodeRef, + with_hint: bool, + ) -> ResolvedResult { + let symbol_ref = if let Some(identifier_symbol) = self + .gs + .get_symbols() + .symbols_info + .node_symbol_map + .get(&self.ctx.get_node_key(&&target.id)) + .map(|symbol_ref| *symbol_ref) + { + let symbols = self.gs.get_symbols_mut(); + + if let Some(symbol) = symbols.values.get_mut(identifier_symbol.get_id()) { + let id = if let Some(last) = target.node.paths.last() { + last.id() + } else { + target.node.name.id.clone() + }; + let ty = self + .ctx + .node_ty_map + .borrow() + .get(&self.ctx.get_node_key(&id)) + .map(|ty| ty.clone()); + + symbol.sema_info = SymbolSemanticInfo { + ty: ty.clone(), + doc: None, + }; + if with_hint & ty.is_some() { + symbols.alloc_hint( + SymbolHint { + kind: SymbolHintKind::TypeHint(ty.unwrap().ty_hint()), + pos: target.get_end_pos(), + }, + self.ctx.current_pkgpath.clone().unwrap(), + ); + } + } + + let cur_scope = *self.ctx.scopes.last().unwrap(); + match cur_scope.kind { + crate::core::scope::ScopeKind::Local => { + self.gs.get_scopes_mut().add_def_to_scope( + cur_scope, + target.node.get_name().to_string(), + identifier_symbol, + ); + } + crate::core::scope::ScopeKind::Root => {} + } + identifier_symbol + } else { + match self.resolve_target(&target.node, self.ctx.maybe_def)? { + Some(symbol) => symbol, + None => return Ok(None), + } + }; + + Ok(Some(symbol_ref)) + } + + #[inline] + pub fn walk_identifier_expr( + &mut self, + identifier: &'ctx ast::NodeRef, + ) -> ResolvedResult { + self.walk_identifier_expr_with_hint(identifier, false) + } + + pub fn walk_identifier_expr_with_hint( + &mut self, + identifier: &'ctx ast::NodeRef, + with_hint: bool, + ) -> ResolvedResult { + let symbol_ref = if let Some(identifier_symbol) = self + .gs + .get_symbols() + .symbols_info + .node_symbol_map + .get(&self.ctx.get_node_key(&&identifier.id)) + .map(|symbol_ref| *symbol_ref) + { + let symbols = self.gs.get_symbols_mut(); + + if let Some(symbol) = symbols.values.get_mut(identifier_symbol.get_id()) { + let id = if identifier.node.names.is_empty() { + &identifier.id + } else { + &identifier.node.names.last().unwrap().id + }; + let ty = self + .ctx + .node_ty_map + .borrow() + .get(&self.ctx.get_node_key(&id)) + .map(|ty| ty.clone()); + + symbol.sema_info = SymbolSemanticInfo { + ty: ty.clone(), + doc: None, + }; + if with_hint & ty.is_some() { + symbols.alloc_hint( + SymbolHint { + kind: SymbolHintKind::TypeHint(ty.unwrap().ty_hint()), + pos: identifier.get_end_pos(), + }, + self.ctx.current_pkgpath.clone().unwrap(), + ); + } + } + + if self.ctx.maybe_def && identifier.node.names.len() > 0 { + let cur_scope = *self.ctx.scopes.last().unwrap(); + match cur_scope.kind { + crate::core::scope::ScopeKind::Local => { + self.gs.get_scopes_mut().add_def_to_scope( + cur_scope, + identifier.node.names.last().unwrap().node.clone(), + identifier_symbol, + ); + } + crate::core::scope::ScopeKind::Root => {} + } + } + identifier_symbol + } else { + match self.resolve_names(&identifier.node.names, self.ctx.maybe_def)? { + Some(symbol) => symbol, + None => return Ok(None), + } + }; + + Ok(Some(symbol_ref)) + } + + pub fn walk_type_expr( + &mut self, + ty_node: Option<&'ctx ast::Node>, + ) -> ResolvedResult { + self.ctx.is_type_expr = true; + if let Some(ty_node) = ty_node { + match &ty_node.node { + ast::Type::Any => { + let (start, end) = ty_node.get_span_pos(); + let mut type_symbol = + UnresolvedSymbol::new(ANY_TYPE_STR.to_owned(), start, end, None, true); + + type_symbol.sema_info.ty = Some(Arc::new(Type::ANY)); + self.gs.get_symbols_mut().alloc_unresolved_symbol( + type_symbol, + self.ctx.get_node_key(&ty_node.id), + self.ctx.current_pkgpath.clone().unwrap(), + ); + } + ast::Type::Named(identifier) => { + self.walk_identifier(identifier)?; + } + ast::Type::Basic(_) => {} + ast::Type::List(list_type) => { + self.walk_type_expr(list_type.inner_type.as_ref().map(|ty| ty.as_ref()))?; + } + ast::Type::Dict(dict_type) => { + self.walk_type_expr(dict_type.key_type.as_ref().map(|ty| ty.as_ref()))?; + self.walk_type_expr(dict_type.value_type.as_ref().map(|ty| ty.as_ref()))?; + } + ast::Type::Union(union_type) => { + for elem_ty in union_type.type_elements.iter() { + self.walk_type_expr(Some(elem_ty))?; + } + } + ast::Type::Literal(_) => {} + ast::Type::Function(func_type) => { + if let Some(params_ty) = &func_type.params_ty { + for param_ty in params_ty.iter() { + self.walk_type_expr(Some(param_ty))?; + } + } + if let Some(ret_ty) = &func_type.ret_ty { + self.walk_type_expr(Some(&ret_ty))?; + } + } + } + } + + if let Some(ty_node) = ty_node { + match self + .ctx + .node_ty_map + .borrow() + .get(&self.ctx.get_node_key(&ty_node.id)) + { + Some(ty) => { + let (_, end) = ty_node.get_span_pos(); + let mut expr_symbol = + ExpressionSymbol::new(format!("@{}", ty.ty_hint()), end.clone(), end, None); + + expr_symbol.sema_info.ty = Some(ty.clone()); + self.gs.get_symbols_mut().alloc_expression_symbol( + expr_symbol, + self.ctx.get_node_key(&ty_node.id), + self.ctx.current_pkgpath.clone().unwrap(), + ); + } + None => {} + } + } + self.ctx.is_type_expr = false; + Ok(None) + } + + pub fn do_arguments_symbol_resolve( + &mut self, + args: &'ctx [ast::NodeRef], + kwargs: &'ctx [ast::NodeRef], + ) -> anyhow::Result<()> { + for arg in args.iter() { + self.expr(arg)?; + } + for kw in kwargs.iter() { + if let Some(value) = &kw.node.value { + self.expr(value)?; + } + let (start_pos, end_pos): Range = kw.node.arg.get_span_pos(); + let value = self.gs.get_symbols_mut().alloc_value_symbol( + ValueSymbol::new(kw.node.arg.node.get_name(), start_pos, end_pos, None, false), + self.ctx.get_node_key(&kw.id), + self.ctx.current_pkgpath.clone().unwrap(), + ); + + if let Some(value) = self.gs.get_symbols_mut().values.get_mut(value.get_id()) { + value.sema_info = SymbolSemanticInfo { + ty: self + .ctx + .node_ty_map + .borrow() + .get(&self.ctx.get_node_key(&kw.id)) + .map(|ty| ty.clone()), + doc: None, + }; + } + } + Ok(()) + } + + pub fn do_arguments_symbol_resolve_with_hint( + &mut self, + args: &'ctx [ast::NodeRef], + kwargs: &'ctx [ast::NodeRef], + params: &[Parameter], + with_hint: bool, + ) -> anyhow::Result<()> { + if params.is_empty() { + self.do_arguments_symbol_resolve(args, kwargs)?; + } else { + for (arg, param) in args.iter().zip(params.iter()) { + self.expr(arg)?; + + if with_hint { + let symbol_data = self.gs.get_symbols_mut(); + let id = match &arg.node { + ast::Expr::Identifier(id) => id.names.last().unwrap().id.clone(), + _ => arg.id.clone(), + }; + match symbol_data + .symbols_info + .node_symbol_map + .get(&self.ctx.get_node_key(&id)) + { + Some(arg_ref) => match arg_ref.get_kind() { + crate::core::symbol::SymbolKind::Unresolved => { + let mut has_hint = false; + if let Some(unresolved) = + symbol_data.unresolved.get(arg_ref.get_id()) + { + if let Some(def) = unresolved.def { + if let Some(def) = symbol_data.get_symbol(def) { + if def.get_name() != param.name { + has_hint = true; + } + } + } + } + if has_hint { + symbol_data.alloc_hint( + SymbolHint { + kind: SymbolHintKind::VarHint(param.name.clone()), + pos: arg.get_pos(), + }, + self.ctx.current_pkgpath.clone().unwrap(), + ); + } + } + _ => { + symbol_data.alloc_hint( + SymbolHint { + kind: SymbolHintKind::VarHint(param.name.clone()), + pos: arg.get_pos(), + }, + self.ctx.current_pkgpath.clone().unwrap(), + ); + } + }, + None => { + symbol_data.alloc_hint( + SymbolHint { + kind: SymbolHintKind::VarHint(param.name.clone()), + pos: arg.get_pos(), + }, + self.ctx.current_pkgpath.clone().unwrap(), + ); + } + } + } + } + + for kw in kwargs.iter() { + if let Some(value) = &kw.node.value { + self.expr(value)?; + } + let (start_pos, end_pos): Range = kw.node.arg.get_span_pos(); + let value = self.gs.get_symbols_mut().alloc_value_symbol( + ValueSymbol::new(kw.node.arg.node.get_name(), start_pos, end_pos, None, false), + self.ctx.get_node_key(&kw.id), + self.ctx.current_pkgpath.clone().unwrap(), + ); + + if let Some(value) = self.gs.get_symbols_mut().values.get_mut(value.get_id()) { + value.sema_info = SymbolSemanticInfo { + ty: self + .ctx + .node_ty_map + .borrow() + .get(&self.ctx.get_node_key(&kw.id)) + .map(|ty| ty.clone()), + doc: None, + }; + } + } + } + Ok(()) + } + + pub(crate) fn walk_config_entries( + &mut self, + entries: &'ctx [ast::NodeRef], + ) -> anyhow::Result<()> { + let (start, end) = (self.ctx.start_pos.clone(), self.ctx.end_pos.clone()); + + let schema_symbol = self.ctx.schema_symbol_stack.last().unwrap_or(&None).clone(); + let kind = LocalSymbolScopeKind::Config; + + self.enter_local_scope( + &self.ctx.current_filename.as_ref().unwrap().clone(), + start, + end, + kind, + ); + + if let Some(owner) = schema_symbol { + let cur_scope = self.ctx.scopes.last().unwrap(); + self.gs + .get_scopes_mut() + .set_owner_to_scope(*cur_scope, owner); + } + + let mut entries_range = vec![]; + for entry in entries.iter() { + entries_range.push(( + entry.node.key.clone().map(|k| k.get_span_pos()), + entry.node.value.get_span_pos(), + )); + self.ctx.in_config_r_value = true; + self.expr(&entry.node.value)?; + self.ctx.in_config_r_value = false; + + if let Some(key) = &entry.node.key { + self.ctx.maybe_def = true; + if let Some(symbol_ref) = self.expr(key)? { + if let Some(config_key_symbol) = + self.gs.get_symbols().unresolved.get(symbol_ref.get_id()) + { + if let Some(def_ref) = config_key_symbol.get_definition() { + if let Some(def_symbol) = self.gs.get_symbols().get_symbol(def_ref) { + let ty = def_symbol.get_sema_info().ty.clone(); + let symbols = self.gs.get_symbols_mut(); + if let Some(ty) = ty { + symbols.alloc_hint( + SymbolHint { + kind: SymbolHintKind::KeyTypeHint(ty.ty_hint()), + pos: key.get_end_pos(), + }, + self.ctx.current_pkgpath.clone().unwrap(), + ); + } + } + } + } + } + self.ctx.maybe_def = false; + } + } + + let cur_scope = self.ctx.scopes.last().unwrap(); + self.gs + .get_scopes_mut() + .config_scope_context + .insert(cur_scope.get_id(), ConfigScopeContext { entries_range }); + self.leave_scope(); + Ok(()) + } + + pub(crate) fn resolve_decorator(&mut self, decorators: &'ctx [ast::NodeRef]) { + for decorator in decorators { + let func_ident = &decorator.node.func; + let (start, end) = func_ident.get_span_pos(); + if let kclvm_ast::ast::Expr::Identifier(id) = &func_ident.node { + let decorator_symbol = DecoratorSymbol::new(start, end, id.get_name()); + self.gs.get_symbols_mut().alloc_decorator_symbol( + decorator_symbol, + self.ctx.get_node_key(&self.ctx.cur_node), + self.ctx.current_pkgpath.clone().unwrap(), + ); + } + } + } + + pub(crate) fn walk_module_schemas(&mut self, module: &'ctx ast::Module) -> anyhow::Result<()> { + for stmt in module.body.iter() { + if matches!(stmt.node, Stmt::Schema(_)) { + self.stmt(stmt)?; + } + } + Ok(()) + } +} diff --git a/kclvm/sema/src/advanced_resolver/test_data/circle_dep/circle_dep.k b/kclvm/sema/src/advanced_resolver/test_data/circle_dep/circle_dep.k new file mode 100644 index 000000000..b2dd28836 --- /dev/null +++ b/kclvm/sema/src/advanced_resolver/test_data/circle_dep/circle_dep.k @@ -0,0 +1,14 @@ +schema A(A): + name: str + +schema B(C): + name: str + +schema C(B): + name: str + + +schema D: + mixin [D] + +mixin D for D \ No newline at end of file diff --git a/kclvm/sema/src/advanced_resolver/test_data/import_test/a.k b/kclvm/sema/src/advanced_resolver/test_data/import_test/a.k new file mode 100644 index 000000000..b4938a73c --- /dev/null +++ b/kclvm/sema/src/advanced_resolver/test_data/import_test/a.k @@ -0,0 +1,16 @@ +_a = 1 +schema Name: + firstName: str + lastName: str + +schema Person: + name: Name + age: int + +_person = Person { + name = Name { + firstName = "a" + lastName = "b" + } + age = 20 +} \ No newline at end of file diff --git a/kclvm/sema/src/advanced_resolver/test_data/import_test/b.k b/kclvm/sema/src/advanced_resolver/test_data/import_test/b.k new file mode 100644 index 000000000..79fa8ccc7 --- /dev/null +++ b/kclvm/sema/src/advanced_resolver/test_data/import_test/b.k @@ -0,0 +1 @@ +_b = 1 diff --git a/test/test_units/test_kclvm/test_tools/test_lint/test_checker/test_data/c.k b/kclvm/sema/src/advanced_resolver/test_data/import_test/c.k similarity index 100% rename from test/test_units/test_kclvm/test_tools/test_lint/test_checker/test_data/c.k rename to kclvm/sema/src/advanced_resolver/test_data/import_test/c.k diff --git a/kclvm/sema/src/advanced_resolver/test_data/import_test/d.k b/kclvm/sema/src/advanced_resolver/test_data/import_test/d.k new file mode 100644 index 000000000..78dcd8b21 --- /dev/null +++ b/kclvm/sema/src/advanced_resolver/test_data/import_test/d.k @@ -0,0 +1,2 @@ +schema Parent: + age1?: int diff --git a/kclvm/sema/src/advanced_resolver/test_data/import_test/e.k b/kclvm/sema/src/advanced_resolver/test_data/import_test/e.k new file mode 100644 index 000000000..98fabf8f4 --- /dev/null +++ b/kclvm/sema/src/advanced_resolver/test_data/import_test/e.k @@ -0,0 +1,2 @@ +schema UnionType: + a?: int diff --git a/kclvm/sema/src/advanced_resolver/test_data/import_test/f.k b/kclvm/sema/src/advanced_resolver/test_data/import_test/f.k new file mode 100644 index 000000000..65a0fa043 --- /dev/null +++ b/kclvm/sema/src/advanced_resolver/test_data/import_test/f.k @@ -0,0 +1,2 @@ +schema UnionType: + b?: int diff --git a/test/test_units/test_kclvm/test_tools/test_doc/doc_data/source_files/kcl.mod b/kclvm/sema/src/advanced_resolver/test_data/kcl.mod similarity index 100% rename from test/test_units/test_kclvm/test_tools/test_doc/doc_data/source_files/kcl.mod rename to kclvm/sema/src/advanced_resolver/test_data/kcl.mod diff --git a/kclvm/sema/src/advanced_resolver/test_data/pkg/pkg.k b/kclvm/sema/src/advanced_resolver/test_data/pkg/pkg.k new file mode 100644 index 000000000..f8c946eff --- /dev/null +++ b/kclvm/sema/src/advanced_resolver/test_data/pkg/pkg.k @@ -0,0 +1,5 @@ +schema Name: + name?: str + +schema Person: + name: Name = Name {name = "Alice"} diff --git a/kclvm/sema/src/advanced_resolver/test_data/schema_def_scope.k b/kclvm/sema/src/advanced_resolver/test_data/schema_def_scope.k new file mode 100644 index 000000000..40ead160c --- /dev/null +++ b/kclvm/sema/src/advanced_resolver/test_data/schema_def_scope.k @@ -0,0 +1,8 @@ +schema Person: + name: str + age: int + +p1 = Person { + name: "Alice" + age: 18 +} \ No newline at end of file diff --git a/kclvm/sema/src/advanced_resolver/test_data/schema_symbols.k b/kclvm/sema/src/advanced_resolver/test_data/schema_symbols.k new file mode 100644 index 000000000..2a2139846 --- /dev/null +++ b/kclvm/sema/src/advanced_resolver/test_data/schema_symbols.k @@ -0,0 +1,38 @@ +import import_test.a +import import_test.b +import import_test.c +import import_test.d +import import_test.e +import import_test.f as g +import pkg +import regex + +schema Main(d.Parent): + mixin [c.TestOfMixin] + name?: str + age?: int = 18 + person?: a.Person + list_union_type?: [e.UnionType|int] + dict_union_type?: {g.UnionType|int:float} + + check: + regex.match(name, r"[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*") if name + +if a._a > 1: + _c = 1 +elif a._a == 1: + _c = 2 +else: + _c = 3 + +p = Main{ + name = a._person.name.firstName + " " + a._person?.name.lastName + age = b._b + a._person?.age +} + +person = pkg.Person { + name.name = "" +} + +x = "123" +assert True, "${x}456" diff --git a/kclvm/sema/src/builtin/decorator.rs b/kclvm/sema/src/builtin/decorator.rs index 446c36e4e..955620c12 100644 --- a/kclvm/sema/src/builtin/decorator.rs +++ b/kclvm/sema/src/builtin/decorator.rs @@ -1,6 +1,7 @@ -use std::rc::Rc; +use std::sync::Arc; use indexmap::IndexMap; +use kclvm_error::diagnostic::dummy_range; use once_cell::sync::Lazy; use crate::ty::{Parameter, Type}; @@ -22,49 +23,39 @@ macro_rules! register_decorator { register_decorator! { deprecated => Type::function( None, - Rc::new(Type::ANY), + Arc::new(Type::ANY), &[ Parameter { name: "version".to_string(), - ty: Rc::new(Type::STR), + ty: Arc::new(Type::STR), has_default: true, + default_value: None, + range: dummy_range(), }, Parameter { name: "reason".to_string(), - ty: Rc::new(Type::STR), + ty: Arc::new(Type::STR), has_default: true, + default_value: None, + range: dummy_range(), }, Parameter { name: "strict".to_string(), - ty: Rc::new(Type::BOOL), + ty: Arc::new(Type::BOOL), has_default: true, + default_value: None, + range: dummy_range(), }, ], - r#"This decorator is used to get the deprecation message according to the wrapped key-value pair. - - Examples - -------- - @deprecated(version="v1.16", reason="The age attribute was deprecated", strict=True) - schema Person: - name: str - age: int - "#, + r#"This decorator is used to get the deprecation message according to the wrapped key-value pair."#, false, None, ) info => Type::function( None, - Rc::new(Type::ANY), + Arc::new(Type::ANY), &[], - r#"Info decorator is used to mark some compile-time information for external API queries - - Examples - -------- - @info(message="User message") - schema Person: - name: str - age: int - "#, + r#"Info decorator is used to mark some compile-time information for external API queries"#, true, Some(0), ) diff --git a/kclvm/sema/src/builtin/mod.rs b/kclvm/sema/src/builtin/mod.rs index f932c4fa5..2154eb710 100644 --- a/kclvm/sema/src/builtin/mod.rs +++ b/kclvm/sema/src/builtin/mod.rs @@ -1,12 +1,14 @@ //! This package mainly contains the type definitions of built-in system libraries, //! functions, decorators and member methods. pub mod decorator; +pub mod option; pub mod string; pub mod system_module; -use std::rc::Rc; +use std::sync::Arc; use indexmap::IndexMap; +use kclvm_error::diagnostic::dummy_range; use once_cell::sync::Lazy; use crate::ty::{Parameter, Type}; @@ -35,42 +37,42 @@ macro_rules! register_builtin { register_builtin! { option => Type::function( None, - Rc::new(Type::ANY), + Arc::new(Type::ANY), &[ Parameter { name: "key".to_string(), - ty: Rc::new(Type::STR), + ty: Arc::new(Type::STR), has_default: false, + default_value: None, + range: dummy_range(), }, Parameter { name: "type".to_string(), - ty: Rc::new(Type::STR), + ty: Arc::new(Type::STR), has_default: true, + default_value: None, + range: dummy_range(), }, Parameter { name: "required".to_string(), - ty: Rc::new(Type::BOOL), + ty: Arc::new(Type::BOOL), has_default: true, + default_value: None, + range: dummy_range(), }, Parameter { name: "default".to_string(), - ty: Rc::new(Type::ANY), + ty: Arc::new(Type::ANY), has_default: true, + default_value: None, + range: dummy_range(), }, Parameter { name: "help".to_string(), - ty: Rc::new(Type::STR), - has_default: true, - }, - Parameter { - name: "file".to_string(), - ty: Rc::new(Type::STR), - has_default: true, - }, - Parameter { - name: "line".to_string(), - ty: Rc::new(Type::INT), + ty: Arc::new(Type::STR), has_default: true, + default_value: None, + range: dummy_range(), }, ], "Return the top level argument by the key", @@ -79,57 +81,79 @@ register_builtin! { ) print => Type::function( None, - Rc::new(Type::ANY), + Arc::new(Type::NONE), &[], - r#"Prints the values to a stream, or to sys.stdout by default. - Optional keyword arguments: - sep: string inserted between values, default a space. - end: string appended after the last value, default a newline. - "#, + r#"Prints the values to a stream, or to the system stdout by default. +Optional keyword arguments: +sep: string inserted between values, default a space. +end: string appended after the last value, default a newline."#, true, - Some(0), + None, ) multiplyof => Type::function( None, - Rc::new(Type::BOOL), + Arc::new(Type::BOOL), &[ Parameter { name: "a".to_string(), - ty: Rc::new(Type::INT), + ty: Arc::new(Type::INT), has_default: false, + default_value: None, + range: dummy_range(), }, Parameter { name: "b".to_string(), - ty: Rc::new(Type::INT), + ty: Arc::new(Type::INT), has_default: false, + default_value: None, + range: dummy_range(), }, ], "Check if the modular result of a and b is 0.", - true, - Some(0), + false, + None, ) isunique => Type::function( None, - Rc::new(Type::BOOL), + Arc::new(Type::BOOL), &[ Parameter { name: "inval".to_string(), - ty: Type::list_ref(Rc::new(Type::ANY)), + ty: Type::list_ref(Arc::new(Type::ANY)), has_default: false, + default_value: None, + range: dummy_range(), }, ], "Check if a list has duplicated elements", false, None, ) + isnullish => Type::function( + None, + Arc::new(Type::BOOL), + &[ + Parameter { + name: "inval".to_string(), + ty: Type::any_ref(), + has_default: false, + default_value: None, + range: dummy_range(), + }, + ], + "Return `True` if the input value is `None` or `Undefined`, and `False` otherwise.", + false, + None, + ) len => Type::function( None, - Rc::new(Type::INT), + Arc::new(Type::INT), &[ Parameter { name: "inval".to_string(), ty: Type::iterable(), - has_default: false, + has_default: false,default_value: None, + range: dummy_range(), }, ], "Return the length of a value.", @@ -138,12 +162,14 @@ register_builtin! { ) abs => Type::function( None, - Rc::new(Type::ANY), + Arc::new(Type::ANY), &[ Parameter { name: "inval".to_string(), - ty: Rc::new(Type::ANY), + ty: Arc::new(Type::ANY), has_default: false, + default_value: None, + range: dummy_range(), }, ], "Return the absolute value of the argument.", @@ -152,44 +178,50 @@ register_builtin! { ) all_true => Type::function( None, - Rc::new(Type::BOOL), + Arc::new(Type::BOOL), &[ Parameter { name: "inval".to_string(), - ty: Type::list_ref(Rc::new(Type::ANY)), + ty: Type::list_ref(Arc::new(Type::ANY)), has_default: false, + default_value: None, + range: dummy_range(), }, ], r#"Return True if bool(x) is True for all values x in the iterable. - If the iterable is empty, return True."#, +If the iterable is empty, return True."#, false, None, ) any_true => Type::function( None, - Rc::new(Type::BOOL), + Arc::new(Type::BOOL), &[ Parameter { name: "inval".to_string(), - ty: Type::list_ref(Rc::new(Type::ANY)), + ty: Type::list_ref(Arc::new(Type::ANY)), has_default: false, + default_value: None, + range: dummy_range(), }, ], r#"Return True if bool(x) is True for any x in the iterable. - If the iterable is empty, return False."#, +If the iterable is empty, return False."#, false, None, ) hex => Type::function( None, - Rc::new(Type::STR), + Arc::new(Type::STR), &[ Parameter { name: "number".to_string(), - ty: Rc::new(Type::INT), + ty: Arc::new(Type::INT), has_default: false, + default_value: None, + range: dummy_range(), }, ], "Return the hexadecimal representation of an integer.", @@ -198,12 +230,14 @@ register_builtin! { ) bin => Type::function( None, - Rc::new(Type::STR), + Arc::new(Type::STR), &[ Parameter { name: "number".to_string(), - ty: Rc::new(Type::INT), + ty: Arc::new(Type::INT), has_default: false, + default_value: None, + range: dummy_range(), }, ], "Return the binary representation of an integer.", @@ -212,12 +246,14 @@ register_builtin! { ) oct => Type::function( None, - Rc::new(Type::STR), + Arc::new(Type::STR), &[ Parameter { name: "number".to_string(), - ty: Rc::new(Type::INT), + ty: Arc::new(Type::INT), has_default: false, + default_value: None, + range: dummy_range(), }, ], "Return the octal representation of an integer.", @@ -226,12 +262,14 @@ register_builtin! { ) ord => Type::function( None, - Rc::new(Type::INT), + Arc::new(Type::INT), &[ Parameter { name: "c".to_string(), - ty: Rc::new(Type::STR), + ty: Arc::new(Type::STR), has_default: false, + default_value: None, + range: dummy_range(), }, ], "Return the Unicode code point for a one-character string.", @@ -240,44 +278,53 @@ register_builtin! { ) sorted => Type::function( None, - Type::list_ref(Rc::new(Type::ANY)), + Type::list_ref(Arc::new(Type::ANY)), &[ Parameter { name: "inval".to_string(), ty: Type::iterable(), has_default: false, + default_value: None, + range: dummy_range(), }, Parameter { name: "reverse".to_string(), - ty: Rc::new(Type::BOOL), - has_default: true, + ty: Arc::new(Type::BOOL), + has_default: true,default_value: None, + range: dummy_range(), }, ], r#"Return a new list containing all items from the iterable in ascending order. - A custom key function can be supplied to customize the sort order, and the reverse - flag can be set to request the result in descending order."#, +A custom key function can be supplied to customize the sort order, and the reverse +flag can be set to request the result in descending order."#, false, Some(1), ) range => Type::function( None, - Type::list_ref(Rc::new(Type::INT)), + Type::list_ref(Arc::new(Type::INT)), &[ Parameter { name: "start".to_string(), - ty: Rc::new(Type::INT), + ty: Arc::new(Type::INT), has_default: true, + default_value: None, + range: dummy_range(), }, Parameter { name: "stop".to_string(), - ty: Rc::new(Type::INT), + ty: Arc::new(Type::INT), has_default: true, + default_value: None, + range: dummy_range(), }, Parameter { name: "step".to_string(), - ty: Rc::new(Type::INT), + ty: Arc::new(Type::INT), has_default: true, + default_value: None, + range: dummy_range(), }, ], r#"Return the range of a value."#, @@ -286,44 +333,48 @@ register_builtin! { ) max => Type::function( None, - Rc::new(Type::ANY), + Arc::new(Type::ANY), &[], r#"With a single iterable argument, return its biggest item. - The default keyword-only argument specifies an object to return - if the provided iterable is empty. With two or more arguments, - return the largest argument."#, +The default keyword-only argument specifies an object to return +if the provided iterable is empty. With two or more arguments, +return the largest argument."#, true, None, ) min => Type::function( None, - Rc::new(Type::ANY), + Arc::new(Type::ANY), &[], r#"With a single iterable argument, return its smallest item. - The default keyword-only argument specifies an object to return - if the provided iterable is empty. With two or more arguments, - return the smallest argument."#, +The default keyword-only argument specifies an object to return +if the provided iterable is empty. With two or more arguments, +return the smallest argument."#, true, None, ) sum => Type::function( None, - Rc::new(Type::ANY), + Arc::new(Type::ANY), &[ Parameter { name: "iterable".to_string(), - ty: Type::list_ref(Rc::new(Type::ANY)), + ty: Type::list_ref(Arc::new(Type::ANY)), has_default: false, + default_value: None, + range: dummy_range(), }, Parameter { name: "start".to_string(), - ty: Rc::new(Type::ANY), + ty: Arc::new(Type::ANY), has_default: true, + default_value: None, + range: dummy_range(), }, ], r#"When the iterable is empty, return the start value. This function is - intended specifically for use with numeric values and may reject - non-numeric types."#, +intended specifically for use with numeric values and may reject +non-numeric types."#, false, None, ) @@ -335,22 +386,28 @@ register_builtin! { name: "x".to_string(), ty: Type::number(), has_default: false, + default_value: None, + range: dummy_range(), }, Parameter { name: "y".to_string(), ty: Type::number(), has_default: false, + default_value: None, + range: dummy_range(), }, Parameter { name: "z".to_string(), ty: Type::number(), has_default: true, + default_value: None, + range: dummy_range(), }, ], - r#"Equivalent to x**y (with two arguments) or x**y % z (with three arguments) + r#"Equivalent to `x ** y` (with two arguments) or `x ** y % z` (with three arguments) - Some types, such as ints, are able to use a more efficient algorithm when - invoked using the three argument form."#, +Some types, such as ints, are able to use a more efficient algorithm when +invoked using the three argument form."#, false, None, ) @@ -362,59 +419,69 @@ register_builtin! { name: "number".to_string(), ty: Type::number(), has_default: false, + default_value: None, + range: dummy_range(), }, Parameter { name: "ndigits".to_string(), - ty: Rc::new(Type::INT), + ty: Arc::new(Type::INT), has_default: true, + default_value: None, + range: dummy_range(), }, ], r#"Round a number to a given precision in decimal digits. - The return value is an integer if ndigits is omitted or None. - Otherwise the return value has the same type as the number. - ndigits may be negative."#, +The return value is an integer if ndigits is omitted or None. +Otherwise the return value has the same type as the number. +ndigits may be negative."#, false, None, ) zip => Type::function( None, - Type::list_ref(Rc::new(Type::ANY)), + Type::list_ref(Arc::new(Type::ANY)), &[], r#"Return a zip object whose next method returns - a tuple where the i-th element comes from the i-th iterable - argument."#, +a tuple where the i-th element comes from the i-th iterable +argument."#, true, None, ) int => Type::function( None, - Rc::new(Type::INT), + Arc::new(Type::INT), &[ Parameter { name: "number".to_string(), - ty: Rc::new(Type::ANY), + ty: Arc::new(Type::ANY), has_default: false, + default_value: None, + range: dummy_range(), }, Parameter { name: "base".to_string(), - ty: Rc::new(Type::INT), + ty: Arc::new(Type::INT), has_default: true, + default_value: None, + range: dummy_range(), }, ], r#"Convert a number or string to an integer, or return 0 if no arguments - are given. For floating point numbers, this truncates towards zero."#, +are given. For floating point numbers, this truncates towards zero."#, false, None, ) float => Type::function( None, - Rc::new(Type::FLOAT), + Arc::new(Type::FLOAT), &[ Parameter { name: "number".to_string(), - ty: Rc::new(Type::ANY), + ty: Arc::new(Type::ANY), has_default: false, + default_value: None, + range: dummy_range(), }, ], r#"Convert a string or number to a floating point number, if possible."#, @@ -423,85 +490,99 @@ register_builtin! { ) bool => Type::function( None, - Rc::new(Type::ANY), + Arc::new(Type::BOOL), &[ Parameter { name: "x".to_string(), - ty: Rc::new(Type::ANY), + ty: Arc::new(Type::ANY), has_default: true, + default_value: None, + range: dummy_range(), }, ], r#"Returns True when the argument x is true, False otherwise. - The builtins True and False are the only two instances of the class bool. - The class bool is a subclass of the class int, and cannot be subclassed."#, +The builtin `True` and `False` are the only two instances of the class bool. +The class bool is a subclass of the class int, and cannot be subclassed."#, false, None, ) str => Type::function( None, - Rc::new(Type::ANY), + Arc::new(Type::STR), &[ Parameter { name: "x".to_string(), - ty: Rc::new(Type::ANY), + ty: Arc::new(Type::ANY), has_default: true, + default_value: None, + range: dummy_range(), }, ], r#"Create a new string object from the given object. - If encoding or errors is specified, then the object must - expose a data buffer that will be decoded using the - given encoding and error handler."#, +If encoding or errors is specified, then the object must +expose a data buffer that will be decoded using the +given encoding and error handler."#, false, None, ) list => Type::function( None, - Type::list_ref(Rc::new(Type::ANY)), + Type::list_ref(Arc::new(Type::ANY)), &[ Parameter { name: "x".to_string(), - ty: Rc::new(Type::ANY), + ty: Arc::new(Type::ANY), has_default: true, + default_value: None, + range: dummy_range(), }, ], - r#"Built-in mutable sequence. + r#"Built-in list function, which can convert other data types or construct a list. - If no argument is given, the constructor creates a new empty list. - The argument must be an iterable if specified."#, +If no argument is given, the constructor creates a new empty list. +The argument must be an iterable if specified."#, false, None, ) dict => Type::function( None, - Type::dict_ref(Rc::new(Type::ANY), Rc::new(Type::ANY)), + Type::dict_ref(Arc::new(Type::ANY), Arc::new(Type::ANY)), &[ Parameter { name: "x".to_string(), - ty: Rc::new(Type::ANY), + ty: Arc::new(Type::ANY), has_default: true, + default_value: None, + range: dummy_range(), }, ], - r#"Built-in mutable dict."#, + r#"Built-in dict function. + +If no argument is given, the constructor creates a new empty dict."#, true, None, ) typeof => Type::function( None, - Rc::new(Type::STR), + Arc::new(Type::STR), &[ Parameter { name: "x".to_string(), - ty: Rc::new(Type::ANY), + ty: Arc::new(Type::ANY), has_default: false, + default_value: None, + range: dummy_range(), }, Parameter { name: "full_name".to_string(), - ty: Rc::new(Type::BOOL), + ty: Arc::new(Type::BOOL), has_default: true, + default_value: None, + range: dummy_range(), }, ], r#"Return the type of the object"#, - true, + false, None, ) } diff --git a/kclvm/sema/src/builtin/option.rs b/kclvm/sema/src/builtin/option.rs new file mode 100644 index 000000000..d59afde6b --- /dev/null +++ b/kclvm/sema/src/builtin/option.rs @@ -0,0 +1,59 @@ +/// OptionHelp denotes all the option function calling usage. +#[derive(PartialEq, Eq, Clone, Default, Debug)] +pub struct OptionHelp { + pub name: String, + pub ty: String, + pub required: bool, + pub default_value: String, + pub help: String, +} + +/// Print option helps to string +pub fn print_option_help(option_helps: &[OptionHelp]) -> String { + let mut msg: String = "".to_string(); + + // name=? (required) set name value + // name=? (str,required) set name value + // a=42 set a value + // b=? set b value + // obj=? + // obj2=? + + msg.push_str("option list:\n"); + for opt in option_helps { + let name = opt.name.clone(); + + let default_value = if !opt.default_value.is_empty() { + &opt.default_value + } else { + "?" + }; + + let s = format!(" -D {name}={default_value}"); + msg.push_str(s.as_str()); + + // (required) + // (str,required) + if !opt.ty.is_empty() || opt.required { + if opt.required && !opt.ty.is_empty() { + let s = format!(" ({},{})", opt.ty, "required"); + msg.push_str(s.as_str()); + } else if !opt.ty.is_empty() { + let s = format!(" ({})", opt.ty); + msg.push_str(s.as_str()); + } else { + msg.push_str(" (required)"); + } + } + + if !opt.help.is_empty() { + msg.push(' '); + msg.push_str(opt.help.as_str()); + } + + msg.push('\n'); + } + + msg = msg.as_str().trim_end_matches('\n').to_string(); + msg +} diff --git a/kclvm/sema/src/builtin/string.rs b/kclvm/sema/src/builtin/string.rs index 448b540bc..1d68c9f4c 100644 --- a/kclvm/sema/src/builtin/string.rs +++ b/kclvm/sema/src/builtin/string.rs @@ -1,8 +1,10 @@ +use std::sync::Arc; + use indexmap::IndexMap; +use kclvm_error::diagnostic::dummy_range; use once_cell::sync::Lazy; -use std::rc::Rc; -use crate::ty::Type; +use crate::ty::{Parameter, Type}; macro_rules! register_string_member { ($($name:ident => $ty:expr)*) => ( @@ -17,218 +19,504 @@ macro_rules! register_string_member { register_string_member! { capitalize => Type::function( - Some(Rc::new(Type::STR)), - Rc::new(Type::ANY), + Some(Arc::new(Type::STR)), + Arc::new(Type::STR), &[], - r#""#, + r#"Return a copy of the string with its first character capitalized and the rest lowercased."#, false, None, ) - count => Type::function( - Some(Rc::new(Type::STR)), - Rc::new(Type::INT), + chars => Type::function( + Some(Arc::new(Type::STR)), + Type::list_ref(Arc::new(Type::STR)), &[], - r#""#, + r#"Return a list of the characters in the string."#, + false, + None, + ) + count => Type::function( + Some(Arc::new(Type::STR)), + Arc::new(Type::INT), + &[ + Parameter { + name: "sub".to_string(), + ty: Type::str_ref(), + has_default: false, + default_value: None, + range: dummy_range(), + }, + Parameter { + name: "start".to_string(), + ty: Type::int_ref(), + has_default: true, + default_value: None, + range: dummy_range(), + }, + Parameter { + name: "end".to_string(), + ty: Type::int_ref(), + has_default: true, + default_value: None, + range: dummy_range(), + }, + ], + r#"Return the number of non-overlapping occurrences of substring sub in the range [start, end]. Optional arguments start and end are interpreted as in slice notation."#, false, None, ) endswith => Type::function( - Some(Rc::new(Type::STR)), - Rc::new(Type::BOOL), - &[], - r#""#, + Some(Arc::new(Type::STR)), + Arc::new(Type::BOOL), + &[ + Parameter { + name: "val".to_string(), + ty: Type::str_ref(), + has_default: false, + default_value: None, + range: dummy_range(), + }, + Parameter { + name: "start".to_string(), + ty: Type::int_ref(), + has_default: true, + default_value: None, + range: dummy_range(), + }, + Parameter { + name: "end".to_string(), + ty: Type::int_ref(), + has_default: true, + default_value: None, + range: dummy_range(), + }, + ], + r#"Return True if the string ends with the specified suffix, otherwise return False. suffix can also be a tuple of suffixes to look for. With optional start, test beginning at that position. With optional end, stop comparing at that position."#, false, None, ) find => Type::function( - Some(Rc::new(Type::STR)), - Rc::new(Type::INT), - &[], - r#""#, + Some(Arc::new(Type::STR)), + Arc::new(Type::INT), + &[ + Parameter { + name: "sub".to_string(), + ty: Type::str_ref(), + has_default: false, + default_value: None, + range: dummy_range(), + }, + Parameter { + name: "start".to_string(), + ty: Type::int_ref(), + has_default: true, + default_value: None, + range: dummy_range(), + }, + Parameter { + name: "end".to_string(), + ty: Type::int_ref(), + has_default: true, + default_value: None, + range: dummy_range(), + }, + ], + r#"Return the lowest index in the string where substring sub is found within the slice s[start:end]. Optional arguments start and end are interpreted as in slice notation. Return -1 if sub is not found."#, false, None, ) format => Type::function( - Some(Rc::new(Type::STR)), - Rc::new(Type::STR), + Some(Arc::new(Type::STR)), + Arc::new(Type::STR), &[], - r#""#, + r#"Perform a string formatting operation. The string on which this method is called can contain literal text or replacement fields delimited by braces {}. Each replacement field contains either the numeric index of a positional argument, or the name of a keyword argument. Returns a copy of the string where each replacement field is replaced with the string value of the corresponding argument."#, true, None, ) index => Type::function( - Some(Rc::new(Type::STR)), - Rc::new(Type::INT), - &[], - r#""#, + Some(Arc::new(Type::STR)), + Arc::new(Type::INT), + &[ + Parameter { + name: "sub".to_string(), + ty: Type::str_ref(), + has_default: false, + default_value: None, + range: dummy_range(), + }, + Parameter { + name: "start".to_string(), + ty: Type::int_ref(), + has_default: true, + default_value: None, + range: dummy_range(), + }, + Parameter { + name: "end".to_string(), + ty: Type::int_ref(), + has_default: true, + default_value: None, + range: dummy_range(), + }, + ], + r#"Like str.find(), but raise an error when the substring is not found."#, false, None, ) isalpha => Type::function( - Some(Rc::new(Type::STR)), - Rc::new(Type::BOOL), + Some(Arc::new(Type::STR)), + Arc::new(Type::BOOL), &[], - r#""#, + r#"Return True if all characters in the string are alphabetic and there is at least one character, False otherwise. Alphabetic characters are those characters defined in the Unicode character database as “Letter”, i.e., those with general category property being one of “Lm”, “Lt”, “Lu”, “Ll”, or “Lo”. Note that this is different from the “Alphabetic” property defined in the Unicode Standard."#, false, None, ) isalnum => Type::function( - Some(Rc::new(Type::STR)), - Rc::new(Type::BOOL), + Some(Arc::new(Type::STR)), + Arc::new(Type::BOOL), &[], - r#""#, + r#"Return True if all characters in the string are alphanumeric and there is at least one character, False otherwise. A character c is alphanumeric if one of the following returns True: c.isalpha(), c.isdecimal(), c.isdigit(), or c.isnumeric()."#, false, None, ) isdigit => Type::function( - Some(Rc::new(Type::STR)), - Rc::new(Type::BOOL), + Some(Arc::new(Type::STR)), + Arc::new(Type::BOOL), &[], - r#""#, + r#"Return True if all characters in the string are digits and there is at least one character, False otherwise. Digits include decimal characters and digits that need special handling, such as the compatibility superscript digits. This covers digits which cannot be used to form numbers in base 10, like the Kharosthi numbers. Formally, a digit is a character that has the property value Numeric_Type=Digit or Numeric_Type=Decimal."#, false, None, ) islower => Type::function( - Some(Rc::new(Type::STR)), - Rc::new(Type::BOOL), + Some(Arc::new(Type::STR)), + Arc::new(Type::BOOL), &[], - r#""#, + r#"Return True if all cased characters in the string are lowercase and there is at least one cased character, False otherwise."#, false, None, ) isspace => Type::function( - Some(Rc::new(Type::STR)), - Rc::new(Type::BOOL), + Some(Arc::new(Type::STR)), + Arc::new(Type::BOOL), &[], - r#""#, + r#"Return True if there are only whitespace characters in the string and there is at least one character, False otherwise."#, false, None, ) istitle => Type::function( - Some(Rc::new(Type::STR)), - Rc::new(Type::BOOL), + Some(Arc::new(Type::STR)), + Arc::new(Type::BOOL), &[], - r#""#, + r#"Return True if the string is a titlecased string and there is at least one character, for example uppercase characters may only follow uncased characters and lowercase characters only cased ones. Return False otherwise."#, false, None, ) isupper => Type::function( - Some(Rc::new(Type::STR)), - Rc::new(Type::BOOL), + Some(Arc::new(Type::STR)), + Arc::new(Type::BOOL), &[], - r#""#, + r#"Return True if all cased characters in the string are uppercase and there is at least one cased character, False otherwise."#, false, None, ) join => Type::function( - Some(Rc::new(Type::STR)), - Rc::new(Type::STR), - &[], - r#""#, - true, + Some(Arc::new(Type::STR)), + Arc::new(Type::STR), + &[ + Parameter { + name: "iter".to_string(), + ty: Type::list_ref(Type::any_ref()), + has_default: false, + default_value: None, + range: dummy_range(), + }, + ], + r#"Return a string which is the concatenation of the strings in iterable. An error will be raised if there are any non-string values in iterable. The separator between elements is the string providing this method."#, + false, None, ) lower => Type::function( - Some(Rc::new(Type::STR)), - Rc::new(Type::STR), + Some(Arc::new(Type::STR)), + Arc::new(Type::STR), &[], - r#""#, - true, + r#"Return a copy of the string with all the cased characters converted to lowercase."#, + false, None, ) upper => Type::function( - Some(Rc::new(Type::STR)), - Rc::new(Type::STR), + Some(Arc::new(Type::STR)), + Arc::new(Type::STR), &[], - r#""#, - true, + r#"Return a copy of the string with all the cased characters converted to uppercase."#, + false, None, ) lstrip => Type::function( - Some(Rc::new(Type::STR)), - Rc::new(Type::STR), - &[], - r#""#, - true, + Some(Arc::new(Type::STR)), + Arc::new(Type::STR), + &[ + Parameter { + name: "chars".to_string(), + ty: Type::str_ref(), + has_default: true, + default_value: None, + range: dummy_range(), + }, + ], + r#"Return a copy of the string with leading characters removed. The chars argument is a string specifying the set of characters to be removed. If omitted or None, the chars argument defaults to removing whitespace. The chars argument is not a prefix; rather, all combinations of its values are stripped:"#, + false, None, ) rstrip => Type::function( - Some(Rc::new(Type::STR)), - Rc::new(Type::STR), - &[], - r#""#, - true, + Some(Arc::new(Type::STR)), + Arc::new(Type::STR), + &[ + Parameter { + name: "chars".to_string(), + ty: Type::str_ref(), + has_default: true, + default_value: None, + range: dummy_range(), + }, + ], + r#"Return a copy of the string with trailing characters removed. The chars argument is a string specifying the set of characters to be removed. If omitted or None, the chars argument defaults to removing whitespace. The chars argument is not a suffix; rather, all combinations of its values are stripped:"#, + false, None, ) replace => Type::function( - Some(Rc::new(Type::STR)), - Rc::new(Type::STR), - &[], - r#""#, - true, + Some(Arc::new(Type::STR)), + Arc::new(Type::STR), + &[ + Parameter { + name: "old".to_string(), + ty: Type::str_ref(), + has_default: false, + default_value: None, + range: dummy_range(), + }, + Parameter { + name: "new".to_string(), + ty: Type::str_ref(), + has_default: false, + default_value: None, + range: dummy_range(), + }, + Parameter { + name: "count".to_string(), + ty: Type::int_ref(), + has_default: true, + default_value: None, + range: dummy_range(), + }, + ], + r#"Return a copy of the string with all occurrences of substring old replaced by new. If the optional argument count is given, only the first count occurrences are replaced.Return a copy of the string with all occurrences of substring old replaced by new. If the optional argument count is given, only the first count occurrences are replaced."#, + false, + None, + ) + removeprefix => Type::function( + Some(Arc::new(Type::STR)), + Arc::new(Type::STR), + &[ + Parameter { + name: "prefix".to_string(), + ty: Type::str_ref(), + has_default: false, + default_value: None, + range: dummy_range(), + }, + ], + r#"If the string starts with the prefix string, return string[len(prefix):]. Otherwise, return a copy of the original string."#, + false, + None, + ) + removesuffix => Type::function( + Some(Arc::new(Type::STR)), + Arc::new(Type::STR), + &[ + Parameter { + name: "suffix".to_string(), + ty: Type::str_ref(), + has_default: false, + default_value: None, + range: dummy_range(), + }, + ], + r#"If the string ends with the suffix string and that suffix is not empty, return string[:-len(suffix)]. Otherwise, return a copy of the original string."#, + false, None, ) rfind => Type::function( - Some(Rc::new(Type::STR)), - Rc::new(Type::INT), - &[], - r#""#, - true, + Some(Arc::new(Type::STR)), + Arc::new(Type::INT), + &[ + Parameter { + name: "sub".to_string(), + ty: Type::str_ref(), + has_default: false, + default_value: None, + range: dummy_range(), + }, + Parameter { + name: "start".to_string(), + ty: Type::int_ref(), + has_default: true, + default_value: None, + range: dummy_range(), + }, + Parameter { + name: "end".to_string(), + ty: Type::int_ref(), + has_default: true, + default_value: None, + range: dummy_range(), + }, + ], + r#"Return the highest index in the string where substring sub is found, such that sub is contained within s[start:end]. Optional arguments start and end are interpreted as in slice notation. Return -1 on failure."#, + false, None, ) rindex => Type::function( - Some(Rc::new(Type::STR)), - Rc::new(Type::INT), - &[], - r#""#, - true, + Some(Arc::new(Type::STR)), + Arc::new(Type::INT), + &[ + Parameter { + name: "sub".to_string(), + ty: Type::str_ref(), + has_default: false, + default_value: None, + range: dummy_range(), + }, + Parameter { + name: "start".to_string(), + ty: Type::int_ref(), + has_default: true, + default_value: None, + range: dummy_range(), + }, + Parameter { + name: "end".to_string(), + ty: Type::int_ref(), + has_default: true, + default_value: None, + range: dummy_range(), + }, + ], + r#"Like rfind() but raises ValueError when the substring sub is not found."#, + false, None, ) rsplit => Type::function( - Some(Rc::new(Type::STR)), - Type::list_ref(Rc::new(Type::STR)), - &[], - r#""#, - true, + Some(Arc::new(Type::STR)), + Type::list_ref(Arc::new(Type::STR)), + &[ + Parameter { + name: "sep".to_string(), + ty: Type::str_ref(), + has_default: true, + default_value: None, + range: dummy_range(), + }, + Parameter { + name: "maxsplit".to_string(), + ty: Type::int_ref(), + has_default: true, + default_value: None, + range: dummy_range(), + }, + ], + r#"Return a list of the words in the string, using sep as the delimiter string. If maxsplit is given, at most maxsplit splits are done, the rightmost ones. If sep is not specified or None, any whitespace string is a separator. Except for splitting from the right, rsplit() behaves like split() which is described in detail below."#, + false, None, ) split => Type::function( - Some(Rc::new(Type::STR)), - Type::list_ref(Rc::new(Type::STR)), - &[], - r#""#, - true, + Some(Arc::new(Type::STR)), + Type::list_ref(Arc::new(Type::STR)), + &[ + Parameter { + name: "sep".to_string(), + ty: Type::str_ref(), + has_default: true, + default_value: None, + range: dummy_range(), + }, + Parameter { + name: "maxsplit".to_string(), + ty: Type::int_ref(), + has_default: true, + default_value: None, + range: dummy_range(), + }, + ], + r#"Return a list of the words in the string, using sep as the delimiter string. If maxsplit is given, at most maxsplit splits are done (thus, the list will have at most maxsplit+1 elements). If maxsplit is not specified or -1, then there is no limit on the number of splits (all possible splits are made)."#, + false, None, ) splitlines => Type::function( - Some(Rc::new(Type::STR)), - Type::list_ref(Rc::new(Type::STR)), - &[], - r#""#, - true, + Some(Arc::new(Type::STR)), + Type::list_ref(Arc::new(Type::STR)), + &[ + Parameter { + name: "keepends".to_string(), + ty: Type::bool_ref(), + has_default: true, + default_value: None, + range: dummy_range(), + }, + ], + r#"Return a list of the lines in the string, breaking at line boundaries. Line breaks are not included in the resulting list unless keepends is given and true."#, + false, None, ) startswith => Type::function( - Some(Rc::new(Type::STR)), - Rc::new(Type::BOOL), - &[], - r#""#, + Some(Arc::new(Type::STR)), + Arc::new(Type::BOOL), + &[ + Parameter { + name: "val".to_string(), + ty: Type::str_ref(), + has_default: false, + default_value: None, + range: dummy_range(), + }, + Parameter { + name: "start".to_string(), + ty: Type::int_ref(), + has_default: true, + default_value: None, + range: dummy_range(), + }, + Parameter { + name: "end".to_string(), + ty: Type::int_ref(), + has_default: true, + default_value: None, + range: dummy_range(), + }, + ], + r#"Return True if string starts with the prefix, otherwise return False. prefix can also be a tuple of prefixes to look for. With optional start, test string beginning at that position. With optional end, stop comparing string at that position."#, false, None, ) strip => Type::function( - Some(Rc::new(Type::STR)), - Rc::new(Type::STR), - &[], - r#""#, + Some(Arc::new(Type::STR)), + Arc::new(Type::STR), + &[ + Parameter { + name: "chars".to_string(), + ty: Type::str_ref(), + has_default: true, + default_value: None, + range: dummy_range(), + }, + ], + r#"Return a copy of the string with the leading and trailing characters removed. The chars argument is a string specifying the set of characters to be removed. If omitted or None, the chars argument defaults to removing whitespace. The chars argument is not a prefix or suffix; rather, all combinations of its values are stripped:"#, false, None, ) title => Type::function( - Some(Rc::new(Type::STR)), - Rc::new(Type::STR), + Some(Arc::new(Type::STR)), + Arc::new(Type::STR), &[], - r#""#, + r#"Return a titlecased version of the string where words start with an uppercase character and the remaining characters are lowercase."#, false, None, ) diff --git a/kclvm/sema/src/builtin/system_module.rs b/kclvm/sema/src/builtin/system_module.rs index ed49c8df5..af2e3bc62 100644 --- a/kclvm/sema/src/builtin/system_module.rs +++ b/kclvm/sema/src/builtin/system_module.rs @@ -1,75 +1,1547 @@ -// Copyright 2021 The KCL Authors. All rights reserved. +//! Copyright The KCL Authors. All rights reserved. + +use std::sync::Arc; + +use crate::ty::{Parameter, Type, TypeRef}; +use indexmap::IndexMap; +use kclvm_error::diagnostic::dummy_range; +use once_cell::sync::Lazy; + +// ------------------------------ +// base64 system package +// ------------------------------ pub const BASE64: &str = "base64"; -pub const BASE64_FUNCTION_NAMES: [&str; 2] = ["encode", "decode"]; +macro_rules! register_base64_member { + ($($name:ident => $ty:expr)*) => ( + pub const BASE64_FUNCTION_TYPES: Lazy> = Lazy::new(|| { + let mut builtin_mapping = IndexMap::default(); + $( builtin_mapping.insert(stringify!($name).to_string(), $ty); )* + builtin_mapping + }); + pub const BASE64_FUNCTION_NAMES: &[&str] = &[ + $( stringify!($name), )* + ]; + ) +} +register_base64_member! { + encode => Type::function( + None, + Type::str_ref(), + &[ + Parameter { + name: "value".to_string(), + ty: Type::str_ref(), + has_default: false, + default_value: None, + range: dummy_range(), + }, + Parameter { + name: "encoding".to_string(), + ty: Type::str_ref(), + has_default: true, + default_value: None, + range: dummy_range(), + }, + ], + r#"Encode the string `value` using the codec registered for encoding."#, + false, + None, + ) + decode => Type::function( + None, + Type::str_ref(), + &[ + Parameter { + name: "value".to_string(), + ty: Type::str_ref(), + has_default: false,default_value: None, + range: dummy_range(), + }, + ], + r#"Decode the string `value` using the codec registered for encoding."#, + false, + None, + ) +} + +// ------------------------------ +// net system package +// ------------------------------ pub const NET: &str = "net"; -pub const NET_FUNCTION_NAMES: [&str; 16] = [ - "split_host_port", - "join_host_port", - "fqdn", - "parse_IP", - "to_IP4", - "to_IP16", - "IP_string", - "is_IPv4", - "is_IP", - "is_loopback_IP", - "is_multicast_IP", - "is_interface_local_multicast_IP", - "is_link_local_multicast_IP", - "is_link_local_unicast_IP", - "is_global_unicast_IP", - "is_unspecified_IP", -]; +macro_rules! register_net_member { + ($($name:ident => $ty:expr)*) => ( + pub const NET_FUNCTION_TYPES: Lazy> = Lazy::new(|| { + let mut builtin_mapping = IndexMap::default(); + $( builtin_mapping.insert(stringify!($name).to_string(), $ty); )* + builtin_mapping + }); + pub const NET_FUNCTION_NAMES: &[&str] = &[ + $( stringify!($name), )* + ]; + ) +} +register_net_member! { + split_host_port => Type::function( + None, + Type::list_ref(Type::str_ref()), + &[ + Parameter { + name: "ip_end_point".to_string(), + ty: Type::str_ref(), + has_default: false,default_value: None, + range: dummy_range(), + }, + ], + r#"Split the `host` and `port` from the `ip_end_point`."#, + false, + None, + ) + join_host_port => Type::function( + None, + Type::str_ref(), + &[ + Parameter { + name: "host".to_string(), + ty: Type::str_ref(), + has_default: false, + default_value: None, + range: dummy_range(), + }, + Parameter { + name: "port".to_string(), + ty: Type::union_ref(&[Type::int_ref(), Type::str_ref()]), + has_default: false, + default_value: None, + range: dummy_range(), + }, + ], + r#"Merge the `host` and `port`."#, + false, + None, + ) + fqdn => Type::function( + None, + Type::str_ref(), + &[ + Parameter { + name: "name".to_string(), + ty: Type::str_ref(), + has_default: true, + default_value: None, + range: dummy_range(), + }, + ], + r#"Return Fully Qualified Domain Name (FQDN)."#, + false, + None, + ) + parse_IP => Type::function( + None, + Type::str_ref(), + &[ + Parameter { + name: "ip".to_string(), + ty: Type::str_ref(), + has_default: false, + default_value: None, + range: dummy_range(), + }, + ], + r#"Parse ip to a real IP address."#, + false, + None, + ) + IP_string => Type::function( + None, + Type::str_ref(), + &[ + Parameter { + name: "ip".to_string(), + ty: Type::str_ref(), + has_default: false, + default_value: None, + range: dummy_range(), + }, + ], + r#"Get the IP string."#, + false, + None, + ) + to_IP4 => Type::function( + None, + Type::str_ref(), + &[ + Parameter { + name: "ip".to_string(), + ty: Type::str_ref(), + has_default: false, + default_value: None, + range: dummy_range(), + }, + ], + r#"Get the IP4 form of ip."#, + false, + None, + ) + to_IP16 => Type::function( + None, + Type::str_ref(), + &[ + Parameter { + name: "ip".to_string(), + ty: Type::str_ref(), + has_default: false, + default_value: None, + range: dummy_range(), + }, + ], + r#"Get the IP16 form of ip."#, + false, + None, + ) + is_IPv4 => Type::function( + None, + Type::bool_ref(), + &[ + Parameter { + name: "ip".to_string(), + ty: Type::str_ref(), + has_default: false, + default_value: None, + range: dummy_range(), + }, + ], + r#"Whether ip is a IPv4 one."#, + false, + None, + ) + is_IP =>Type::function( + None, + Type::bool_ref(), + &[ + Parameter { + name: "ip".to_string(), + ty: Type::str_ref(), + has_default: false, + default_value: None, + range: dummy_range(), + }, + ], + r#"Whether ip is a valid ip address."#, + false, + None, + ) + is_loopback_IP =>Type::function( + None, + Type::bool_ref(), + &[ + Parameter { + name: "ip".to_string(), + ty: Type::str_ref(), + has_default: false, + default_value: None, + range: dummy_range(), + }, + ], + r#"Whether ip is a loopback one."#, + false, + None, + ) + is_multicast_IP =>Type::function( + None, + Type::bool_ref(), + &[ + Parameter { + name: "ip".to_string(), + ty: Type::str_ref(), + has_default: false, + default_value: None, + range: dummy_range(), + }, + ], + r#"Whether ip is a multicast one."#, + false, + None, + ) + is_interface_local_multicast_IP => Type::function( + None, + Type::bool_ref(), + &[ + Parameter { + name: "ip".to_string(), + ty: Type::str_ref(), + has_default: false, + default_value: None, + range: dummy_range(), + }, + ], + r#"Whether ip is a interface, local and multicast one."#, + false, + None, + ) + is_link_local_multicast_IP =>Type::function( + None, + Type::bool_ref(), + &[ + Parameter { + name: "ip".to_string(), + ty: Type::str_ref(), + has_default: false, + default_value: None, + range: dummy_range(), + }, + ], + r#"Whether ip is a link local and multicast one."#, + false, + None, + ) + is_link_local_unicast_IP =>Type::function( + None, + Type::bool_ref(), + &[ + Parameter { + name: "ip".to_string(), + ty: Type::str_ref(), + has_default: false, + default_value: None, + range: dummy_range(), + }, + ], + r#"Whether ip is a link local and unicast one."#, + false, + None, + ) + is_global_unicast_IP =>Type::function( + None, + Type::bool_ref(), + &[ + Parameter { + name: "ip".to_string(), + ty: Type::str_ref(), + has_default: false, + default_value: None, + range: dummy_range(), + }, + ], + r#"Whether ip is a global and unicast one."#, + false, + None, + ) + is_unspecified_IP => Type::function( + None, + Type::bool_ref(), + &[ + Parameter { + name: "ip".to_string(), + ty: Type::str_ref(), + has_default: false, + default_value: None, + range: dummy_range(), + }, + ], + r#"Whether ip is a unspecified one."#, + false, + None, + ) +} + +// ------------------------------ +// manifests system package +// ------------------------------ + +pub const MANIFESTS: &str = "manifests"; +macro_rules! register_manifests_member { + ($($name:ident => $ty:expr)*) => ( + pub const MANIFESTS_FUNCTION_TYPES: Lazy> = Lazy::new(|| { + let mut builtin_mapping = IndexMap::default(); + $( builtin_mapping.insert(stringify!($name).to_string(), $ty); )* + builtin_mapping + }); + pub const MANIFESTS_FUNCTION_NAMES: &[&str] = &[ + $( stringify!($name), )* + ]; + ) +} +register_manifests_member! { + yaml_stream => Type::function( + None, + Type::any_ref(), + &[ + Parameter { + name: "values".to_string(), + ty: Type::any_ref(), + has_default: false, + default_value: None, + range: dummy_range(), + }, + Parameter { + name: "opts".to_string(), + ty: Type::dict_ref(Type::str_ref(), Type::any_ref()), + has_default: true, + default_value: None, + range: dummy_range(), + }, + ], + r#"This function is used to serialize the KCL object list into YAML output with the --- separator. It has two parameters: +values - A list of KCL objects +opts - The YAML serialization options + + sort_keys: Whether to sort the serialized results in the dictionary order of attribute names (the default is False). + + ignore_private: Whether to ignore the attribute output whose name starts with the character _ (the default value is True). + + ignore_none: Whether to ignore the attribute with the value of' None '(the default value is False). + + sep: Set the separator between multiple YAML documents (the default value is "---"). +"#, + false, + None, + ) +} + +// ------------------------------ +// math system package +// ------------------------------ pub const MATH: &str = "math"; -pub const MATH_FUNCTION_NAMES: [&str; 16] = [ - "ceil", - "factorial", - "floor", - "gcd", - "isfinite", - "isinf", - "isnan", - "modf", - "exp", - "expm1", - "log", - "log1p", - "log2", - "log10", - "pow", - "sqrt", -]; +macro_rules! register_math_member { + ($($name:ident => $ty:expr)*) => ( + pub const MATH_FUNCTION_TYPES: Lazy> = Lazy::new(|| { + let mut builtin_mapping = IndexMap::default(); + $( builtin_mapping.insert(stringify!($name).to_string(), $ty); )* + builtin_mapping + }); + pub const MATH_FUNCTION_NAMES: &[&str] = &[ + $( stringify!($name), )* + ]; + ) +} +register_math_member! { + ceil => Type::function( + None, + Type::int_ref(), + &[ + Parameter { + name: "x".to_string(), + ty: Type::number(), + has_default: false, + default_value: None, + range: dummy_range(), + }, + ], + r#"Return the ceiling of `x` as an Integral. This is the smallest integer >= `x`."#, + false, + None, + ) + factorial => Type::function( + None, + Type::int_ref(), + &[ + Parameter { + name: "x".to_string(), + ty: Type::number(), + has_default: false, + default_value: None, + range: dummy_range(), + }, + ], + r#"Return `x`!. Raise a error if `x` is negative or non-integral."#, + false, + None, + ) + floor => Type::function( + None, + Type::int_ref(), + &[ + Parameter { + name: "x".to_string(), + ty: Type::number(), + has_default: false, + default_value: None, + range: dummy_range(), + }, + ], + r#"Return the floor of `x` as an Integral. This is the largest integer <= `x`."#, + false, + None, + ) + gcd => Type::function( + None, + Type::int_ref(), + &[ + Parameter { + name: "a".to_string(), + ty: Type::int_ref(), + has_default: false, + default_value: None, + range: dummy_range(), + }, + Parameter { + name: "b".to_string(), + ty: Type::int_ref(), + has_default: false, + default_value: None, + range: dummy_range(), + }, + ], + r#"Return the greatest common divisor of `x` and `y`."#, + false, + None, + ) + isfinite => Type::function( + None, + Type::bool_ref(), + &[ + Parameter { + name: "x".to_string(), + ty: Type::number(), + has_default: false, + default_value: None, + range: dummy_range(), + }, + ], + r#"Return `True` if `x` is neither an infinity nor a NaN, and `False` otherwise."#, + false, + None, + ) + isinf => Type::function( + None, + Type::bool_ref(), + &[ + Parameter { + name: "x".to_string(), + ty: Type::number(), + has_default: false, + default_value: None, + range: dummy_range(), + }, + ], + r#"Return `True` if `x` is a positive or negative infinity, and `False` otherwise."#, + false, + None, + ) + isnan => Type::function( + None, + Type::bool_ref(), + &[ + Parameter { + name: "x".to_string(), + ty: Type::number(), + has_default: false, + default_value: None, + range: dummy_range(), + }, + ], + r#"Return `True` if `x` is a NaN (not a number), and `False` otherwise."#, + false, + None, + ) + modf => Type::function( + None, + Type::list_ref(Type::float_ref()), + &[ + Parameter { + name: "x".to_string(), + ty: Type::number(), + has_default: false, + default_value: None, + range: dummy_range(), + }, + ], + r#"Return the fractional and integer parts of `x`. Both results carry the sign of `x` and are floats."#, + false, + None, + ) + exp => Type::function( + None, + Type::float_ref(), + &[ + Parameter { + name: "x".to_string(), + ty: Type::number(), + has_default: false, + default_value: None, + range: dummy_range(), + }, + ], + r#"Return `e` raised to the power of `x`."#, + false, + None, + ) + expm1 => Type::function( + None, + Type::float_ref(), + &[ + Parameter { + name: "x".to_string(), + ty: Type::number(), + has_default: false, + default_value: None, + range: dummy_range(), + }, + ], + r#"Return `exp(x) - 1`. This function avoids the loss of precision involved in the direct evaluation of `exp(x) - 1` for small `x`."#, + false, + None, + ) + log => Type::function( + None, + Type::float_ref(), + &[ + Parameter { + name: "x".to_string(), + ty: Type::number(), + has_default: false, + default_value: None, + range: dummy_range(), + }, + Parameter { + name: "e".to_string(), + ty: Type::float_ref(), + has_default: true, + default_value: None, + range: dummy_range(), + }, + ], + r#"Return the logarithm of `x` to the base `e`."#, + false, + None, + ) + log1p => Type::function( + None, + Type::float_ref(), + &[ + Parameter { + name: "x".to_string(), + ty: Type::number(), + has_default: false, + default_value: None, + range: dummy_range(), + }, + ], + r#"Return the natural logarithm of `1+x` (base `e`). The result is computed in a way which is accurate for `x` near zero."#, + false, + None, + ) + log2 => Type::function( + None, + Type::float_ref(), + &[ + Parameter { + name: "x".to_string(), + ty: Type::number(), + has_default: false, + default_value: None, + range: dummy_range(), + }, + ], + r#"Return the base 2 logarithm of x."#, + false, + None, + ) + log10 => Type::function( + None, + Type::float_ref(), + &[ + Parameter { + name: "x".to_string(), + ty: Type::number(), + has_default: false, + default_value: None, + range: dummy_range(), + }, + ], + r#"Return the base 10 logarithm of `x`."#, + false, + None, + ) + pow => Type::function( + None, + Type::float_ref(), + &[ + Parameter { + name: "x".to_string(), + ty: Type::number(), + has_default: false, + default_value: None, + range: dummy_range(), + }, + Parameter { + name: "y".to_string(), + ty: Type::number(), + has_default: false, + default_value: None, + range: dummy_range(), + }, + ], + r#"Return `x**y` (`x` to the power of `y`)."#, + false, + None, + ) + sqrt => Type::function( + None, + Type::float_ref(), + &[ + Parameter { + name: "x".to_string(), + ty: Type::number(), + has_default: false, + default_value: None, + range: dummy_range(), + }, + ], + r#"Return the square root of `x`."#, + false, + None, + ) +} + +// ------------------------------ +// datetime system package +// ------------------------------ pub const DATETIME: &str = "datetime"; -pub const DATETIME_FUNCTION_NAMES: [&str; 4] = ["today", "now", "ticks", "date"]; +macro_rules! register_datetime_member { + ($($name:ident => $ty:expr)*) => ( + pub const DATETIME_FUNCTION_TYPES: Lazy> = Lazy::new(|| { + let mut builtin_mapping = IndexMap::default(); + $( builtin_mapping.insert(stringify!($name).to_string(), $ty); )* + builtin_mapping + }); + pub const DATETIME_FUNCTION_NAMES: &[&str] = &[ + $( stringify!($name), )* + ]; + ) +} +register_datetime_member! { + ticks => Type::function( + None, + Type::float_ref(), + &[], + r#"Return the current time in seconds since the Epoch. Fractions of a second may be present if the system clock provides them."#, + false, + None, + ) + date => Type::function( + None, + Type::str_ref(), + &[], + r#"Return the `%Y-%m-%d %H:%M:%S` format date."#, + false, + None, + ) + now => Type::function( + None, + Type::str_ref(), + &[ + Parameter { + name: "format".to_string(), + ty: Type::str_ref(), + has_default: true, + default_value: None, + range: dummy_range(), + }, + ], + r#"Return the local time format. e.g. 'Sat Jun 06 16:26:11 1998' or format the combined date and time per the specified format string, and the default date format is "%a %b %d %H:%M:%S %Y"."#, + false, + None, + ) + today => Type::function( + None, + Type::str_ref(), + &[], + r#"Return the `%Y-%m-%d %H:%M:%S.%{ticks}` format date."#, + false, + None, + ) + validate => Type::function( + None, + Type::bool_ref(), + &[ + Parameter { + name: "date".to_string(), + ty: Type::str_ref(), + has_default: false, + default_value: None, + range: dummy_range(), + }, + Parameter { + name: "format".to_string(), + ty: Type::str_ref(), + has_default: false, + default_value: None, + range: dummy_range(), + }, + ], + r#"Validate whether the provided date string matches the specified format."#, + false, + None, + ) +} + +// ------------------------------ +// regex system package +// ------------------------------ pub const REGEX: &str = "regex"; -pub const REGEX_FUNCTION_NAMES: [&str; 6] = - ["replace", "match", "compile", "findall", "search", "split"]; +macro_rules! register_regex_member { + ($($name:ident => $ty:expr)*) => ( + pub const REGEX_FUNCTION_TYPES: Lazy> = Lazy::new(|| { + let mut builtin_mapping = IndexMap::default(); + $( builtin_mapping.insert(stringify!($name).to_string(), $ty); )* + builtin_mapping + }); + pub const REGEX_FUNCTION_NAMES: &[&str] = &[ + $( stringify!($name), )* + ]; + ) +} +register_regex_member! { + replace => Type::function( + None, + Type::str_ref(), + &[ + Parameter { + name: "string".to_string(), + ty: Type::str_ref(), + has_default: false, + default_value: None, + range: dummy_range(), + }, + Parameter { + name: "pattern".to_string(), + ty: Type::str_ref(), + has_default: false, + default_value: None, + range: dummy_range(), + }, + Parameter { + name: "replace".to_string(), + ty: Type::str_ref(), + has_default: false, + default_value: None, + range: dummy_range(), + }, + Parameter { + name: "count".to_string(), + ty: Type::int_ref(), + has_default: true, + default_value: None, + range: dummy_range(), + }, + ], + r#"Return the string obtained by replacing the leftmost non-overlapping occurrences of the pattern in string by the replacement."#, + false, + None, + ) + match => Type::function( + None, + Type::bool_ref(), + &[ + Parameter { + name: "string".to_string(), + ty: Type::str_ref(), + has_default: false, + default_value: None, + range: dummy_range(), + }, + Parameter { + name: "pattern".to_string(), + ty: Type::str_ref(), + has_default: false, + default_value: None, + range: dummy_range(), + }, + ], + r#"Try to apply the pattern at the start of the string, returning a bool value `True` if any match was found, or `False` if no match was found."#, + false, + None, + ) + compile => Type::function( + None, + Type::bool_ref(), + &[ + Parameter { + name: "pattern".to_string(), + ty: Type::str_ref(), + has_default: false, + default_value: None, + range: dummy_range(), + }, + ], + r#"Compile a regular expression pattern, returning a bool value denoting whether the pattern is valid."#, + false, + None, + ) + findall => Type::function( + None, + Type::list_ref(Type::str_ref()), + &[ + Parameter { + name: "string".to_string(), + ty: Type::str_ref(), + has_default: false, + default_value: None, + range: dummy_range(), + }, + Parameter { + name: "pattern".to_string(), + ty: Type::str_ref(), + has_default: false, + default_value: None, + range: dummy_range(), + }, + ], + r#"Return a list of all non-overlapping matches in the string."#, + false, + None, + ) + search => Type::function( + None, + Type::bool_ref(), + &[ + Parameter { + name: "string".to_string(), + ty: Type::str_ref(), + has_default: false, + default_value: None, + range: dummy_range(), + }, + Parameter { + name: "pattern".to_string(), + ty: Type::str_ref(), + has_default: false, + default_value: None, + range: dummy_range(), + }, + ], + r#"Scan through string looking for a match to the pattern, returning a bool value `True` if any match was found, or `False` if no match was found."#, + false, + None, + ) + split => Type::function( + None, + Type::list_ref(Type::str_ref()), + &[ + Parameter { + name: "string".to_string(), + ty: Type::str_ref(), + has_default: false, + default_value: None, + range: dummy_range(), + }, + Parameter { + name: "pattern".to_string(), + ty: Type::str_ref(), + has_default: false, + default_value: None, + range: dummy_range(), + }, + Parameter { + name: "maxsplit".to_string(), + ty: Type::int_ref(), + has_default: true, + default_value: None, + range: dummy_range(), + }, + ], + r#"Return a list composed of words from the string, splitting up to a maximum of `maxsplit` times using `pattern` as the separator."#, + false, + None, + ) +} + +// ------------------------------ +// yaml system package +// ------------------------------ pub const YAML: &str = "yaml"; -pub const YAML_FUNCTION_NAMES: [&str; 3] = ["encode", "decode", "dump_to_file"]; +macro_rules! register_yaml_member { + ($($name:ident => $ty:expr)*) => ( + pub const YAML_FUNCTION_TYPES: Lazy> = Lazy::new(|| { + let mut builtin_mapping = IndexMap::default(); + $( builtin_mapping.insert(stringify!($name).to_string(), $ty); )* + builtin_mapping + }); + pub const YAML_FUNCTION_NAMES: &[&str] = &[ + $( stringify!($name), )* + ]; + ) +} +register_yaml_member! { + encode => Type::function( + None, + Type::str_ref(), + &[ + Parameter { + name: "data".to_string(), + ty: Type::any_ref(), + has_default: false, + default_value: None, + range: dummy_range(), + }, + Parameter { + name: "sort_keys".to_string(), + ty: Type::bool_ref(), + has_default: true, + default_value: None, + range: dummy_range(), + }, + Parameter { + name: "ignore_private".to_string(), + ty: Type::bool_ref(), + has_default: true, + default_value: None, + range: dummy_range(), + }, + Parameter { + name: "ignore_none".to_string(), + ty: Type::bool_ref(), + has_default: true, + default_value: None, + range: dummy_range(), + }, + ], + r#"Serialize a KCL object `data` to a YAML formatted str."#, + false, + Some(1), + ) + encode_all => Type::function( + None, + Type::str_ref(), + &[ + Parameter { + name: "data".to_string(), + ty: Type::list_ref(Type::any_ref()), + has_default: false, + default_value: None, + range: dummy_range(), + }, + Parameter { + name: "sort_keys".to_string(), + ty: Type::bool_ref(), + has_default: true, + default_value: None, + range: dummy_range(), + }, + Parameter { + name: "ignore_private".to_string(), + ty: Type::bool_ref(), + has_default: true, + default_value: None, + range: dummy_range(), + }, + Parameter { + name: "ignore_none".to_string(), + ty: Type::bool_ref(), + has_default: true, + default_value: None, + range: dummy_range(), + }, + ], + r#"Serialize a sequence of KCL objects into a YAML stream str."#, + false, + Some(1), + ) + decode => Type::function( + None, + Type::any_ref(), + &[ + Parameter { + name: "value".to_string(), + ty: Type::str_ref(), + has_default: false, + default_value: None, + range: dummy_range(), + }, + ], + r#"Deserialize `value` (a string instance containing a YAML document) to a KCL object."#, + false, + None, + ) + decode_all => Type::function( + None, + Type::list_ref(Type::any_ref()), + &[ + Parameter { + name: "value".to_string(), + ty: Type::str_ref(), + has_default: false, + default_value: None, + range: dummy_range(), + }, + ], + r#"Parse all YAML documents in a stream and produce corresponding KCL objects."#, + false, + None, + ) + dump_to_file => Type::function( + None, + Type::str_ref(), + &[ + Parameter { + name: "data".to_string(), + ty: Type::any_ref(), + has_default: false, + default_value: None, + range: dummy_range(), + }, + Parameter { + name: "filename".to_string(), + ty: Type::str_ref(), + has_default: false, + default_value: None, + range: dummy_range(), + }, + Parameter { + name: "sort_keys".to_string(), + ty: Type::bool_ref(), + has_default: true, + default_value: None, + range: dummy_range(), + }, + Parameter { + name: "ignore_private".to_string(), + ty: Type::bool_ref(), + has_default: true, + default_value: None, + range: dummy_range(), + }, + Parameter { + name: "ignore_none".to_string(), + ty: Type::bool_ref(), + has_default: true, + default_value: None, + range: dummy_range(), + }, + ], + r#"Serialize a KCL object `data` to a YAML formatted str and write it into the file `filename`."#, + false, + Some(2), + ) + dump_all_to_file => Type::function( + None, + Type::str_ref(), + &[ + Parameter { + name: "data".to_string(), + ty: Type::list_ref(Type::any_ref()), + has_default: false, + default_value: None, + range: dummy_range(), + }, + Parameter { + name: "filename".to_string(), + ty: Type::str_ref(), + has_default: false, + default_value: None, + range: dummy_range(), + }, + Parameter { + name: "sort_keys".to_string(), + ty: Type::bool_ref(), + has_default: true, + default_value: None, + range: dummy_range(), + }, + Parameter { + name: "ignore_private".to_string(), + ty: Type::bool_ref(), + has_default: true, + default_value: None, + range: dummy_range(), + }, + Parameter { + name: "ignore_none".to_string(), + ty: Type::bool_ref(), + has_default: true, + default_value: None, + range: dummy_range(), + }, + ], + r#"Serialize a sequence of KCL objects into a YAML stream str and write it into the file `filename`."#, + false, + Some(2), + ) + validate => Type::function( + None, + Type::bool_ref(), + &[ + Parameter { + name: "value".to_string(), + ty: Type::str_ref(), + has_default: false, + default_value: None, + range: dummy_range(), + }, + ], + r#"Validate whether the given string is a valid YAML or YAML stream document."#, + false, + None, + ) +} + +// ------------------------------ +// json system package +// ------------------------------ pub const JSON: &str = "json"; -pub const JSON_FUNCTION_NAMES: [&str; 3] = ["encode", "decode", "dump_to_file"]; +macro_rules! register_json_member { + ($($name:ident => $ty:expr)*) => ( + pub const JSON_FUNCTION_TYPES: Lazy> = Lazy::new(|| { + let mut builtin_mapping = IndexMap::default(); + $( builtin_mapping.insert(stringify!($name).to_string(), $ty); )* + builtin_mapping + }); + pub const JSON_FUNCTION_NAMES: &[&str] = &[ + $( stringify!($name), )* + ]; + ) +} +register_json_member! { + encode => Type::function( + None, + Type::str_ref(), + &[ + Parameter { + name: "data".to_string(), + ty: Type::any_ref(), + has_default: false, + default_value: None, + range: dummy_range(), + }, + Parameter { + name: "sort_keys".to_string(), + ty: Type::bool_ref(), + has_default: true, + default_value: None, + range: dummy_range(), + }, + Parameter { + name: "indent".to_string(), + ty: Type::int_ref(), + has_default: true, + default_value: None, + range: dummy_range(), + }, + Parameter { + name: "ignore_private".to_string(), + ty: Type::bool_ref(), + has_default: true, + default_value: None, + range: dummy_range(), + }, + Parameter { + name: "ignore_none".to_string(), + ty: Type::bool_ref(), + has_default: true, + default_value: None, + range: dummy_range(), + }, + ], + r#"Serialize a KCL object `data` to a JSON formatted str."#, + false, + Some(1), + ) + decode => Type::function( + None, + Type::any_ref(), + &[ + Parameter { + name: "value".to_string(), + ty: Type::str_ref(), + has_default: false, + default_value: None, + range: dummy_range(), + }, + ], + r#"Deserialize `value` (a string instance containing a JSON document) to a KCL object."#, + false, + None, + ) + dump_to_file => Type::function( + None, + Type::str_ref(), + &[ + Parameter { + name: "data".to_string(), + ty: Type::any_ref(), + has_default: false, + default_value: None, + range: dummy_range(), + }, + Parameter { + name: "filename".to_string(), + ty: Type::str_ref(), + has_default: false, + default_value: None, + range: dummy_range(), + }, + Parameter { + name: "sort_keys".to_string(), + ty: Type::bool_ref(), + has_default: true, + default_value: None, + range: dummy_range(), + }, + Parameter { + name: "indent".to_string(), + ty: Type::int_ref(), + has_default: true, + default_value: None, + range: dummy_range(), + }, + Parameter { + name: "ignore_private".to_string(), + ty: Type::bool_ref(), + has_default: true, + default_value: None, + range: dummy_range(), + }, + Parameter { + name: "ignore_none".to_string(), + ty: Type::bool_ref(), + has_default: true, + default_value: None, + range: dummy_range(), + }, + ], + r#"Serialize a KCL object `data` to a YAML formatted str and write it into the file `filename`."#, + false, + Some(2), + ) + validate => Type::function( + None, + Type::bool_ref(), + &[ + Parameter { + name: "value".to_string(), + ty: Type::str_ref(), + has_default: false, + default_value: None, + range: dummy_range(), + }, + ], + r#"Validate whether the given string is a valid JSON"#, + false, + None, + ) +} + +// ------------------------------ +// crypto system package +// ------------------------------ pub const CRYPTO: &str = "crypto"; -pub const CRYPTO_FUNCTION_NAMES: [&str; 6] = - ["md5", "sha1", "sha224", "sha256", "sha384", "sha512"]; +macro_rules! register_crypto_member { + ($($name:ident => $ty:expr)*) => ( + pub const CRYPTO_FUNCTION_TYPES: Lazy> = Lazy::new(|| { + let mut builtin_mapping = IndexMap::default(); + $( builtin_mapping.insert(stringify!($name).to_string(), $ty); )* + builtin_mapping + }); + pub const CRYPTO_FUNCTION_NAMES: &[&str] = &[ + $( stringify!($name), )* + ]; + ) +} +register_crypto_member! { + md5 => Type::function( + None, + Type::str_ref(), + &[ + Parameter { + name: "value".to_string(), + ty: Type::str_ref(), + has_default: false, + default_value: None, + range: dummy_range(), + }, + Parameter { + name: "encoding".to_string(), + ty: Type::str_ref(), + has_default: true, + default_value: None, + range: dummy_range(), + }, + ], + r#"Encrypt the string `value` using `MD5` and the codec registered for encoding."#, + false, + None, + ) + sha1 => Type::function( + None, + Type::str_ref(), + &[ + Parameter { + name: "value".to_string(), + ty: Type::str_ref(), + has_default: false, + default_value: None, + range: dummy_range(), + }, + Parameter { + name: "encoding".to_string(), + ty: Type::str_ref(), + has_default: true, + default_value: None, + range: dummy_range(), + }, + ], + r#"Encrypt the string `value` using `SHA1` and the codec registered for encoding."#, + false, + None, + ) + sha224 => Type::function( + None, + Type::str_ref(), + &[ + Parameter { + name: "value".to_string(), + ty: Type::str_ref(), + has_default: false, + default_value: None, + range: dummy_range(), + }, + Parameter { + name: "encoding".to_string(), + ty: Type::str_ref(), + has_default: true, + default_value: None, + range: dummy_range(), + }, + ], + r#"Encrypt the string `value` using `SHA224` and the codec registered for encoding."#, + false, + None, + ) + sha256 => Type::function( + None, + Type::str_ref(), + &[ + Parameter { + name: "value".to_string(), + ty: Type::str_ref(), + has_default: false, + default_value: None, + range: dummy_range(), + }, + Parameter { + name: "encoding".to_string(), + ty: Type::str_ref(), + has_default: true, + default_value: None, + range: dummy_range(), + }, + ], + r#"Encrypt the string `value` using `SHA256` and the codec registered for encoding."#, + false, + None, + ) + sha384 => Type::function( + None, + Type::str_ref(), + &[ + Parameter { + name: "value".to_string(), + ty: Type::str_ref(), + has_default: false, + default_value: None, + range: dummy_range(), + }, + Parameter { + name: "encoding".to_string(), + ty: Type::str_ref(), + has_default: true, + default_value: None, + range: dummy_range(), + }, + ], + r#"Encrypt the string `value` using `SHA384` and the codec registered for encoding."#, + false, + None, + ) + sha512 => Type::function( + None, + Type::str_ref(), + &[ + Parameter { + name: "value".to_string(), + ty: Type::str_ref(), + has_default: false, + default_value: None, + range: dummy_range(), + }, + Parameter { + name: "encoding".to_string(), + ty: Type::str_ref(), + has_default: true, + default_value: None, + range: dummy_range(), + }, + ], + r#"Encrypt the string `value` using `SHA512` and the codec registered for encoding."#, + false, + None, + ) + blake3 => Type::function( + None, + Type::str_ref(), + &[ + Parameter { + name: "value".to_string(), + ty: Type::str_ref(), + has_default: false, + default_value: None, + range: dummy_range(), + }, + Parameter { + name: "encoding".to_string(), + ty: Type::str_ref(), + has_default: true, + default_value: None, + range: dummy_range(), + }, + ], + r#"Encrypt the string `value` using `BLAKE3` and the codec registered for encoding."#, + false, + None, + ) + uuid => Type::function( + None, + Type::str_ref(), + &[], + r#"Generate a random UUID."#, + false, + None, + ) + filesha256 => Type::function( + None, + Type::str_ref(), + &[ + Parameter { + name: "filepath".to_string(), + ty: Type::str_ref(), + has_default: false, + default_value: None, + range: dummy_range(), + }, + ], + r#"Calculate the SHA256 hash of the file `filepath`."#, + false, + None, + ) +} -pub const TESTING: &str = "testing"; -pub const TESTING_FUNCTION_NAMES: [&str; 2] = ["arguments", "setting_file"]; +// ------------------------------ +// units system package +// ------------------------------ pub const UNITS: &str = "units"; -pub const UNITS_FUNCTION_NAMES: [&str; 13] = [ +pub const UNITS_FUNCTION_NAMES: &[&str] = &[ "to_n", "to_u", "to_m", "to_K", "to_M", "to_G", "to_T", "to_P", "to_Ki", "to_Mi", "to_Gi", "to_Ti", "to_Pi", ]; pub const UNITS_NUMBER_MULTIPLIER: &str = "NumberMultiplier"; -pub const UNITS_FIELD_NAMES: [&str; 15] = [ +pub const UNITS_FIELD_NAMES: &[&str] = &[ "n", "u", "m", @@ -86,17 +1558,651 @@ pub const UNITS_FIELD_NAMES: [&str; 15] = [ "Pi", UNITS_NUMBER_MULTIPLIER, ]; +macro_rules! register_units_member { + ($($name:ident => $ty:expr)*) => ( + pub const UNITS_FUNCTION_TYPES: Lazy> = Lazy::new(|| { + let mut builtin_mapping = IndexMap::default(); + $( builtin_mapping.insert(stringify!($name).to_string(), $ty); )* + builtin_mapping + }); + ) +} +register_units_member! { + n => Type::INT + u => Type::INT + m => Type::INT + k => Type::INT + K => Type::INT + M => Type::INT + G => Type::INT + T => Type::INT + P => Type::INT + Ki => Type::INT + Mi => Type::INT + Gi => Type::INT + Ti => Type::INT + Pi => Type::INT + to_n => Type::function( + None, + Type::str_ref(), + &[ + Parameter { + name: "num".to_string(), + ty: Type::number(), + has_default: false, + default_value: None, + range: dummy_range(), + }, + ], + r#"Int literal to string with `n` suffix."#, + false, + None, + ) + to_u => Type::function( + None, + Type::str_ref(), + &[ + Parameter { + name: "num".to_string(), + ty: Type::number(), + has_default: false, + default_value: None, + range: dummy_range(), + }, + ], + r#"Int literal to string with `u` suffix."#, + false, + None, + ) + to_m => Type::function( + None, + Type::str_ref(), + &[ + Parameter { + name: "num".to_string(), + ty: Type::number(), + has_default: false, + default_value: None, + range: dummy_range(), + }, + ], + r#"Int literal to string with `m` suffix."#, + false, + None, + ) + to_K => Type::function( + None, + Type::str_ref(), + &[ + Parameter { + name: "num".to_string(), + ty: Type::number(), + has_default: false, + default_value: None, + range: dummy_range(), + }, + ], + r#"Int literal to string with `K` suffix."#, + false, + None, + ) + to_M => Type::function( + None, + Type::str_ref(), + &[ + Parameter { + name: "num".to_string(), + ty: Type::number(), + has_default: false, + default_value: None, + range: dummy_range(), + }, + ], + r#"Int literal to string with `M` suffix."#, + false, + None, + ) + to_G => Type::function( + None, + Type::str_ref(), + &[ + Parameter { + name: "num".to_string(), + ty: Type::number(), + has_default: false, + default_value: None, + range: dummy_range(), + }, + ], + r#"Int literal to string with `G` suffix."#, + false, + None, + ) + to_T => Type::function( + None, + Type::str_ref(), + &[ + Parameter { + name: "num".to_string(), + ty: Type::number(), + has_default: false, + default_value: None, + range: dummy_range(), + }, + ], + r#"Int literal to string with `T` suffix."#, + false, + None, + ) + to_P => Type::function( + None, + Type::str_ref(), + &[ + Parameter { + name: "num".to_string(), + ty: Type::number(), + has_default: false, + default_value: None, + range: dummy_range(), + }, + ], + r#"Int literal to string with `P` suffix."#, + false, + None, + ) + to_Ki => Type::function( + None, + Type::str_ref(), + &[ + Parameter { + name: "num".to_string(), + ty: Type::number(), + has_default: false, + default_value: None, + range: dummy_range(), + }, + ], + r#"Int literal to string with `Ki` suffix."#, + false, + None, + ) + to_Mi => Type::function( + None, + Type::str_ref(), + &[ + Parameter { + name: "num".to_string(), + ty: Type::number(), + has_default: false, + default_value: None, + range: dummy_range(), + }, + ], + r#"Int literal to string with `Mi` suffix."#, + false, + None, + ) + to_Gi => Type::function( + None, + Type::str_ref(), + &[ + Parameter { + name: "num".to_string(), + ty: Type::number(), + has_default: false, + default_value: None, + range: dummy_range(), + }, + ], + r#"Int literal to string with `Gi` suffix."#, + false, + None, + ) + to_Ti => Type::function( + None, + Type::str_ref(), + &[ + Parameter { + name: "num".to_string(), + ty: Type::number(), + has_default: false, + default_value: None, + range: dummy_range(), + }, + ], + r#"Int literal to string with `Ti` suffix."#, + false, + None, + ) + to_Pi => Type::function( + None, + Type::str_ref(), + &[ + Parameter { + name: "num".to_string(), + ty: Type::number(), + has_default: false, + default_value: None, + range: dummy_range(), + }, + ], + r#"Int literal to string with `Pi` suffix."#, + false, + None, + ) +} + +// ------------------------------ +// collection system package +// ------------------------------ pub const COLLECTION: &str = "collection"; -pub const COLLECTION_FUNCTION_NAMES: [&str; 1] = ["union_all"]; +macro_rules! register_collection_member { + ($($name:ident => $ty:expr)*) => ( + pub const COLLECTION_FUNCTION_TYPES: Lazy> = Lazy::new(|| { + let mut builtin_mapping = IndexMap::default(); + $( builtin_mapping.insert(stringify!($name).to_string(), $ty); )* + builtin_mapping + }); + pub const COLLECTION_FUNCTION_NAMES: &[&str] = &[ + $( stringify!($name), )* + ]; + ) +} +register_collection_member! { + union_all => Type::function( + None, + Type::any_ref(), + &[ + Parameter { + name: "num".to_string(), + ty: Type::list_ref(Type::any_ref()), + has_default: false, + default_value: None, + range: dummy_range(), + }, + ], + r#"Union all object to one object."#, + false, + None, + ) +} + +// ------------------------------ +// file system package +// ------------------------------ + +pub const FILE: &str = "file"; +macro_rules! register_file_member { + ($($name:ident => $ty:expr)*) => ( + pub const FILE_FUNCTION_TYPES: Lazy> = Lazy::new(|| { + let mut builtin_mapping = IndexMap::default(); + $( builtin_mapping.insert(stringify!($name).to_string(), $ty); )* + builtin_mapping + }); + pub const FILE_FUNCTION_NAMES: &[&str] = &[ + $( stringify!($name), )* + ]; + ) +} +register_file_member! { + read => Type::function( + None, + Type::str_ref(), + &[ + Parameter { + name: "filepath".to_string(), + ty: Type::str_ref(), + has_default: false, + default_value: None, + range: dummy_range(), + }, + ], + r#"Read the file content from path"#, + false, + None, + ) + glob => Type::function( + None, + Type::list_ref(Type::str_ref()), + &[ + Parameter { + name: "pattern".to_string(), + ty: Type::str_ref(), + has_default: false, + default_value: None, + range: dummy_range(), + }, + ], + r#"Find all paths that match a pattern"#, + false, + None, + ) + modpath => Type::function( + None, + Type::str_ref(), + &[], + r#"Read the module root path (kcl.mod file path or a single *.k file path)"#, + false, + None, + ) + workdir => Type::function( + None, + Type::str_ref(), + &[], + r#"Read the workdir"#, + false, + None, + ) + current => Type::function( + None, + Type::str_ref(), + &[], + r#"Read the path of the current script or module that is being executed"#, + false, + None, + ) + exists => Type::function( + None, + Type::bool_ref(), + &[ + Parameter { + name: "filepath".to_string(), + ty: Type::str_ref(), + has_default: false, + default_value: None, + range: dummy_range(), + }, + ], + r#"Whether this file path exists. Returns true if the path points at an existing entity. This function will traverse symbolic links to query information about the destination file."#, + false, + None, + ) + abs => Type::function( + None, + Type::str_ref(), + &[ + Parameter { + name: "filepath".to_string(), + ty: Type::str_ref(), + has_default: false, + default_value: None, + range: dummy_range(), + }, + ], + r#"Returns the canonical, absolute form of the path with all intermediate components normalized and symbolic links resolved."#, + false, + None, + ) + append => Type::function( + None, + Type::any_ref(), + &[ + Parameter { + name: "filepath".to_string(), + ty: Type::str_ref(), + has_default: false, + default_value: None, + range: dummy_range(), + }, + Parameter { + name: "content".to_string(), + ty: Type::str_ref(), + has_default: false, + default_value: None, + range: dummy_range(), + }, + ], + r#"Append content to a file at the specified path. If the file doesn't exist, it will be created."#, + false, + None, + ) + mkdir => Type::function( + None, + Type::any_ref(), + &[ + Parameter { + name: "directory".to_string(), + ty: Type::str_ref(), + has_default: false, + default_value: None, + range: dummy_range(), + }, + Parameter { + name: "exists".to_string(), + ty: Type::bool_ref(), + has_default: true, + default_value: None, + range: dummy_range(), + }, + ], + r#"Create a new directory at the specified path if it doesn't already exist."#, + false, + None, + ) + delete => Type::function( + None, + Type::any_ref(), + &[ + Parameter { + name: "filepath".to_string(), + ty: Type::str_ref(), + has_default: false, + default_value: None, + range: dummy_range(), + }, + ], + r#"Delete a file or an empty directory at the specified path."#, + false, + None, + ) + cp => Type::function( + None, + Type::any_ref(), + &[ + Parameter { + name: "src".to_string(), + ty: Type::str_ref(), + has_default: false, + default_value: None, + range: dummy_range(), + }, + Parameter { + name: "dest".to_string(), + ty: Type::str_ref(), + has_default: false, + default_value: None, + range: dummy_range(), + }, + ], + r#"Copy a file or directory from the source path to the destination path."#, + false, + None, + ) + mv => Type::function( + None, + Type::any_ref(), + &[ + Parameter { + name: "src".to_string(), + ty: Type::str_ref(), + has_default: false, + default_value: None, + range: dummy_range(), + }, + Parameter { + name: "dest".to_string(), + ty: Type::str_ref(), + has_default: false, + default_value: None, + range: dummy_range(), + }, + ], + r#"Move a file or directory from the source path to the destination path."#, + false, + None, + ) + size => Type::function( + None, + Type::int_ref(), + &[ + Parameter { + name: "filepath".to_string(), + ty: Type::str_ref(), + has_default: false, + default_value: None, + range: dummy_range(), + }, + ], + r#"Get the size of a file at the specified path."#, + false, + None, + ) + write => Type::function( + None, + Type::any_ref(), + &[ + Parameter { + name: "filepath".to_string(), + ty: Type::str_ref(), + has_default: false, + default_value: None, + range: dummy_range(), + }, + Parameter { + name: "content".to_string(), + ty: Type::str_ref(), + has_default: false, + default_value: None, + range: dummy_range(), + }, + ], + r#"Write content to a file at the specified path. If the file doesn't exist, it will be created. If it does exist, its content will be replaced."#, + false, + None, + ) + read_env => Type::function( + None, + Type::str_ref(), + &[ + Parameter { + name: "key".to_string(), + ty: Type::str_ref(), + has_default: false, + default_value: None, + range: dummy_range(), + }, + ], + r#"Read the environment variable key from the current process."#, + false, + None, + ) +} + +// ------------------------------ +// template system package +// ------------------------------ -pub const STANDARD_SYSTEM_MODULES: [&str; 11] = [ - COLLECTION, NET, MATH, DATETIME, REGEX, YAML, JSON, CRYPTO, BASE64, TESTING, UNITS, +pub const TEMPLATE: &str = "template"; +macro_rules! register_template_member { + ($($name:ident => $ty:expr)*) => ( + pub const TEMPLATE_FUNCTION_TYPES: Lazy> = Lazy::new(|| { + let mut builtin_mapping = IndexMap::default(); + $( builtin_mapping.insert(stringify!($name).to_string(), $ty); )* + builtin_mapping + }); + pub const TEMPLATE_FUNCTION_NAMES: &[&str] = &[ + $( stringify!($name), )* + ]; + ) +} +register_template_member! { + execute => Type::function( + None, + Type::str_ref(), + &[ + Parameter { + name: "template".to_string(), + ty: Type::str_ref(), + has_default: false, + default_value: None, + range: dummy_range(), + }, + Parameter { + name: "data".to_string(), + ty: Type::dict_ref(Type::str_ref(), Type::any_ref()), + has_default: true, + default_value: None, + range: dummy_range(), + }, + ], + r#"Applies a parsed template to the specified data object and returns the string output. See https://handlebarsjs.com/ for more documents and examples."#, + false, + None, + ) + html_escape => Type::function( + None, + Type::str_ref(), + &[ + Parameter { + name: "data".to_string(), + ty: Type::str_ref(), + has_default: false, + default_value: None, + range: dummy_range(), + }, + ], + r#"Replaces the characters `&"<>` with the equivalent html / xml entities."#, + false, + None, + ) +} + +// ------------------------------ +// runtime system package +// ------------------------------ + +pub const RUNTIME: &str = "runtime"; +macro_rules! register_runtime_member { + ($($name:ident => $ty:expr)*) => ( + pub const RUNTIME_FUNCTION_TYPES: Lazy> = Lazy::new(|| { + let mut builtin_mapping = IndexMap::default(); + $( builtin_mapping.insert(stringify!($name).to_string(), $ty); )* + builtin_mapping + }); + pub const RUNTIME_FUNCTION_NAMES: &[&str] = &[ + $( stringify!($name), )* + ]; + ) +} +register_runtime_member! { + catch => Type::function( + None, + Type::str_ref(), + &[ + Parameter { + name: "func".to_string(), + ty: Arc::new(Type::function(None, Type::any_ref(), &[], "", false, None)), + has_default: false, + default_value: None, + range: dummy_range(), + }, + ], + r#"Executes the provided function and catches any potential runtime errors. Returns undefined if execution is successful, otherwise returns an error message in case of a runtime panic."#, + false, + None, + ) +} + +pub const STANDARD_SYSTEM_MODULES: &[&str] = &[ + COLLECTION, NET, MANIFESTS, MATH, DATETIME, REGEX, YAML, JSON, CRYPTO, BASE64, UNITS, FILE, + TEMPLATE, RUNTIME, ]; -pub const STANDARD_SYSTEM_MODULE_NAMES_WITH_AT: [&str; 11] = [ +pub const STANDARD_SYSTEM_MODULE_NAMES_WITH_AT: &[&str] = &[ "@collection", "@net", + "@manifests", "@math", "@datetime", "@regex", @@ -104,8 +2210,10 @@ pub const STANDARD_SYSTEM_MODULE_NAMES_WITH_AT: [&str; 11] = [ "@json", "@crypto", "@base64", - "@testing", "@units", + "@file", + "@template", + "@runtime", ]; /// Get the system module members @@ -113,19 +2221,88 @@ pub fn get_system_module_members(name: &str) -> Vec<&str> { match name { BASE64 => BASE64_FUNCTION_NAMES.to_vec(), NET => NET_FUNCTION_NAMES.to_vec(), + MANIFESTS => MANIFESTS_FUNCTION_NAMES.to_vec(), MATH => MATH_FUNCTION_NAMES.to_vec(), DATETIME => DATETIME_FUNCTION_NAMES.to_vec(), REGEX => REGEX_FUNCTION_NAMES.to_vec(), YAML => YAML_FUNCTION_NAMES.to_vec(), JSON => JSON_FUNCTION_NAMES.to_vec(), CRYPTO => CRYPTO_FUNCTION_NAMES.to_vec(), - TESTING => TESTING_FUNCTION_NAMES.to_vec(), UNITS => { let mut members = UNITS_FUNCTION_NAMES.to_vec(); members.append(&mut UNITS_FIELD_NAMES.to_vec()); members } COLLECTION => COLLECTION_FUNCTION_NAMES.to_vec(), + FILE => FILE_FUNCTION_NAMES.to_vec(), + TEMPLATE => TEMPLATE_FUNCTION_NAMES.to_vec(), + RUNTIME => RUNTIME_FUNCTION_NAMES.to_vec(), _ => bug!("invalid system module name '{}'", name), } } + +/// Get the system package member function type, if not found, return the any type. +pub fn get_system_member_function_ty(name: &str, func: &str) -> TypeRef { + let optional_ty = match name { + BASE64 => { + let types = BASE64_FUNCTION_TYPES; + types.get(func).cloned() + } + NET => { + let types = NET_FUNCTION_TYPES; + types.get(func).cloned() + } + MANIFESTS => { + let types = MANIFESTS_FUNCTION_TYPES; + types.get(func).cloned() + } + MATH => { + let types = MATH_FUNCTION_TYPES; + types.get(func).cloned() + } + DATETIME => { + let types = DATETIME_FUNCTION_TYPES; + types.get(func).cloned() + } + REGEX => { + let types = REGEX_FUNCTION_TYPES; + types.get(func).cloned() + } + YAML => { + let types = YAML_FUNCTION_TYPES; + types.get(func).cloned() + } + JSON => { + let types = JSON_FUNCTION_TYPES; + types.get(func).cloned() + } + CRYPTO => { + let types = CRYPTO_FUNCTION_TYPES; + types.get(func).cloned() + } + UNITS => { + let types = UNITS_FUNCTION_TYPES; + types.get(func).cloned() + } + COLLECTION => { + let types = COLLECTION_FUNCTION_TYPES; + types.get(func).cloned() + } + FILE => { + let types = FILE_FUNCTION_TYPES; + types.get(func).cloned() + } + TEMPLATE => { + let types = TEMPLATE_FUNCTION_TYPES; + types.get(func).cloned() + } + RUNTIME => { + let types = RUNTIME_FUNCTION_TYPES; + types.get(func).cloned() + } + _ => None, + }; + optional_ty + .map(|ty| Arc::new(ty)) + .unwrap_or(Type::any_ref()) +} diff --git a/kclvm/sema/src/core/global_state.rs b/kclvm/sema/src/core/global_state.rs new file mode 100644 index 000000000..66f6b4736 --- /dev/null +++ b/kclvm/sema/src/core/global_state.rs @@ -0,0 +1,748 @@ +use std::collections::HashSet; + +use indexmap::{IndexMap, IndexSet}; +use kclvm_error::Position; + +use super::{ + package::{ModuleInfo, PackageDB}, + scope::{ScopeData, ScopeKind, ScopeRef}, + semantic_information::{CachedLocation, CachedRange, FileSemanticInfo, SemanticDB}, + symbol::{SymbolData, SymbolKind, SymbolRef}, +}; + +/// GlobalState is used to store semantic information of KCL source code +#[derive(Default, Debug, Clone)] +pub struct GlobalState { + // store all allocated symbols + symbols: SymbolData, + // store all allocated scopes + scopes: ScopeData, + // store package information for name mapping + packages: PackageDB, + // store semantic information after analysis + pub(crate) sema_db: SemanticDB, + // new and invalidate(changed and affected by changed) pkg from CachedScope::update() + pub new_or_invalidate_pkgs: HashSet, +} + +impl GlobalState { + pub fn get_symbols(&self) -> &SymbolData { + &self.symbols + } + + pub fn get_symbols_mut(&mut self) -> &mut SymbolData { + &mut self.symbols + } + + pub fn get_scopes(&self) -> &ScopeData { + &self.scopes + } + + pub fn get_scopes_mut(&mut self) -> &mut ScopeData { + &mut self.scopes + } + + pub fn get_packages(&self) -> &PackageDB { + &self.packages + } + + pub fn get_packages_mut(&mut self) -> &mut PackageDB { + &mut self.packages + } + + pub fn get_sema_db(&self) -> &SemanticDB { + &self.sema_db + } + + pub fn get_sema_db_mut(&mut self) -> &mut SemanticDB { + &mut self.sema_db + } +} + +impl GlobalState { + /// look up symbol by name within specific scope + /// + /// # Parameters + /// + /// + /// `name`: [&str] + /// The name of symbol + /// + /// `scope_ref`: [ScopeRef] + /// the reference of scope which was allocated by [ScopeData] + /// + /// `module_info`: [Option<&ModuleInfo>] + /// the module import information + /// `local`: [bool] + /// look up in current scope + /// + /// # Returns + /// + /// result: [Option] + /// the matched symbol + pub fn look_up_symbol( + &self, + name: &str, + scope_ref: ScopeRef, + module_info: Option<&ModuleInfo>, + local: bool, + get_def_from_owner: bool, + ) -> Option { + let scope = self.scopes.get_scope(&scope_ref)?; + match scope.look_up_def( + name, + &self.scopes, + &self.symbols, + module_info, + local, + get_def_from_owner, + ) { + None => self + .symbols + .symbols_info + .global_builtin_symbols + .get(name) + .cloned(), + some => some, + } + } + + /// look up scope by specific position + /// + /// # Parameters + /// + /// `pos`: [&Position] + /// The pos within the scope + /// + /// + /// # Returns + /// + /// result: [Option] + /// the matched scope + pub fn look_up_scope(&self, pos: &Position) -> Option { + let scopes = &self.scopes; + for root_ref in scopes.root_map.values() { + if let Some(root) = scopes.get_scope(root_ref) { + if root.contains_pos(pos) { + if let Some(inner_ref) = self.look_up_into_scope(*root_ref, pos) { + return Some(inner_ref); + } else { + return Some(*root_ref); + } + } + } + } + None + } + + fn look_up_closest_sub_scope(&self, parent: ScopeRef, pos: &Position) -> Option { + let file_sema_info = self.sema_db.file_sema_map.get(&pos.filename)?; + let loc = CachedLocation { + line: pos.line, + column: pos.column.unwrap_or(0), + }; + let children = match parent.kind { + ScopeKind::Local => &self.scopes.locals.get(parent.id)?.children, + ScopeKind::Root => &self + .scopes + .roots + .get(parent.id)? + .children + .get(&pos.filename)?, + }; + + match children.binary_search_by(|scope_ref| { + file_sema_info + .local_scope_locs + .get(scope_ref) + .unwrap() + .start + .cmp(&loc) + }) { + Ok(symbol_index) => Some(children[symbol_index]), + Err(symbol_index) => { + if symbol_index > 0 { + Some(children[symbol_index - 1]) + } else { + None + } + } + } + } + + /// get all definition symbols within specific scope and parent scope + /// + /// # Parameters + /// + /// `scope`: [ScopeRef] + /// the reference of scope which was allocated by [ScopeData] + /// + /// + /// # Returns + /// + /// result: [Option>] + /// all definition symbols in the scope + pub fn get_all_defs_in_scope( + &self, + scope_ref: ScopeRef, + pos: &Position, + ) -> Option> { + let scopes = &self.scopes; + let scope = scopes.get_scope(&scope_ref)?; + let mut maybe_in_key = false; + let get_def_from_owner = match scope_ref.kind { + ScopeKind::Local => match scopes.try_get_local_scope(&scope_ref) { + Some(local) => match local.kind { + super::scope::LocalSymbolScopeKind::Config => { + maybe_in_key = scopes.get_config_scope_ctx(scope_ref)?.maybe_in_key(pos); + maybe_in_key + } + _ => true, + }, + None => true, + }, + ScopeKind::Root => true, + }; + + let all_defs: Vec = scope + .get_all_defs( + scopes, + &self.symbols, + self.packages.get_module_info(scope.get_filename()), + maybe_in_key, + get_def_from_owner, + ) + .values() + .into_iter() + .cloned() + .collect(); + Some(all_defs) + } + + /// get all definition symbols within specific scope + /// + /// # Parameters + /// + /// `scope`: [ScopeRef] + /// the reference of scope which was allocated by [ScopeData] + /// + /// + /// # Returns + /// + /// result: [Option>] + /// all definition symbols in the scope + pub fn get_defs_within_scope( + &self, + scope_ref: ScopeRef, + pos: &Position, + ) -> Option> { + let scopes = &self.scopes; + let mut maybe_in_key = false; + let get_def_from_owner = match scope_ref.kind { + ScopeKind::Local => match scopes.try_get_local_scope(&scope_ref) { + Some(local) => match local.kind { + super::scope::LocalSymbolScopeKind::Config => { + maybe_in_key = scopes.get_config_scope_ctx(scope_ref)?.maybe_in_key(pos); + maybe_in_key + } + _ => true, + }, + None => true, + }, + ScopeKind::Root => true, + }; + + let scope = scopes.get_scope(&scope_ref)?; + let all_defs: Vec = scope + .get_defs_within_scope( + scopes, + &self.symbols, + self.packages.get_module_info(scope.get_filename()), + maybe_in_key, + get_def_from_owner, + ) + .values() + .into_iter() + .cloned() + .collect(); + Some(all_defs) + } + + /// look up closest symbol by specific position, which means + /// the specified position is located after the starting position of the returned symbol + /// and before the starting position of the next symbol + /// + /// # Parameters + /// + /// `pos`: [&Position] + /// The target pos + /// + /// + /// # Returns + /// + /// result: [Option] + /// the closest symbol to the target pos + pub fn look_up_closest_symbol(&self, pos: &Position) -> Option { + let file_sema_info = self.sema_db.file_sema_map.get(&pos.filename)?; + let candidate = file_sema_info.look_up_closest_symbol(&CachedLocation { + line: pos.line, + column: pos.column.unwrap_or(0), + }); + match self.look_up_scope(pos) { + Some(parent_scope_ref) => { + let candidate_symbol = self.symbols.get_symbol(candidate?)?; + let (start, _) = candidate_symbol.get_range(); + let parent_scope = self.scopes.get_scope(&parent_scope_ref)?; + if parent_scope.contains_pos(&start) { + let barrier_scope = self.look_up_closest_sub_scope(parent_scope_ref, pos); + match barrier_scope { + Some(barrier_scope) => { + let barrier_scope = self.scopes.locals.get(barrier_scope.id)?; + // there is no local scope between the candidate and the specified position + // the candidate is the answer + if barrier_scope.end.less(&candidate_symbol.get_range().0) { + candidate + } + // otherwise, it indicates that the found symbol is shadowed by the local scope. + // we just skip the scope and directly look up its start pos + else { + file_sema_info.look_up_closest_symbol(&CachedLocation { + line: barrier_scope.start.line, + column: barrier_scope.start.column.unwrap_or(0), + }) + } + } + None => candidate, + } + } else { + None + } + } + None => None, + } + } + + /// look up exact symbol by specific position, which means + /// the specified position is within the range of the returned symbol + /// + /// # Parameters + /// + /// `pos`: [&Position] + /// The target pos + /// + /// + /// # Returns + /// + /// result: [Option] + /// the exact symbol to the target pos + pub fn look_up_exact_symbol(&self, pos: &Position) -> Option { + let candidate = self + .sema_db + .file_sema_map + .get(&pos.filename)? + .look_up_closest_symbol(&CachedLocation { + line: pos.line, + column: pos.column.unwrap_or(0), + }); + let (start, end) = self.symbols.get_symbol(candidate?)?.get_range(); + if start.less_equal(pos) && pos.less_equal(&end) { + candidate + } else { + None + } + } + + fn look_up_into_scope(&self, parent: ScopeRef, pos: &Position) -> Option { + let candidate_ref = self.look_up_closest_sub_scope(parent, pos)?; + + let candidate = self.scopes.get_scope(&candidate_ref)?; + if candidate.contains_pos(pos) { + if let Some(inner_ref) = self.look_up_into_scope(candidate_ref, pos) { + return Some(inner_ref); + } else { + return Some(candidate_ref); + } + } + None + } + + pub fn get_scope_symbols(&self, scope: ScopeRef) -> Option> { + let scope = self.get_scopes().get_scope(&scope)?; + let filename = scope.get_filename(); + let packeage = self.get_sema_db().get_file_sema(filename)?; + + let pkg_symbols = packeage.get_symbols(); + + let symbols: Vec = pkg_symbols + .iter() + .filter(|symbol| { + let symbol = self.get_symbols().get_symbol(**symbol).unwrap(); + scope.contains_pos(&symbol.get_range().0) + && scope.contains_pos(&symbol.get_range().1) + }) + .map(|s| s.clone()) + .collect(); + Some(symbols) + } +} + +impl GlobalState { + fn build_sema_db_with_symbols( + &self, + file_sema_map_cache: &mut IndexMap, + ) { + // put symbols + let mut file_sema_map: IndexMap = IndexMap::new(); + + for (index, symbol) in self.symbols.schemas.iter() { + if file_sema_map_cache.contains_key(&symbol.start.filename) { + continue; + } + let symbol_ref = SymbolRef { + kind: SymbolKind::Schema, + id: index, + }; + let filename = &symbol.start.filename; + if !file_sema_map.contains_key(filename) { + file_sema_map.insert(filename.clone(), FileSemanticInfo::new(filename.clone())); + } + let file_sema_info = file_sema_map.get_mut(filename).unwrap(); + file_sema_info.symbols.push(symbol_ref); + file_sema_info.symbol_locs.insert( + symbol_ref, + CachedLocation { + line: symbol.start.line, + column: symbol.start.column.unwrap_or(0), + }, + ); + } + for (index, symbol) in self.symbols.type_aliases.iter() { + if file_sema_map_cache.contains_key(&symbol.start.filename) { + continue; + } + let symbol_ref = SymbolRef { + kind: SymbolKind::TypeAlias, + id: index, + }; + let filename = &symbol.start.filename; + if !file_sema_map.contains_key(filename) { + file_sema_map.insert(filename.clone(), FileSemanticInfo::new(filename.clone())); + } + let file_sema_info = file_sema_map.get_mut(filename).unwrap(); + file_sema_info.symbols.push(symbol_ref); + file_sema_info.symbol_locs.insert( + symbol_ref, + CachedLocation { + line: symbol.start.line, + column: symbol.start.column.unwrap_or(0), + }, + ); + } + for (index, symbol) in self.symbols.attributes.iter() { + if file_sema_map_cache.contains_key(&symbol.start.filename) { + continue; + } + let symbol_ref = SymbolRef { + kind: SymbolKind::Attribute, + id: index, + }; + let filename = &symbol.start.filename; + if !file_sema_map.contains_key(filename) { + file_sema_map.insert(filename.clone(), FileSemanticInfo::new(filename.clone())); + } + let file_sema_info = file_sema_map.get_mut(filename).unwrap(); + file_sema_info.symbols.push(symbol_ref); + file_sema_info.symbol_locs.insert( + symbol_ref, + CachedLocation { + line: symbol.start.line, + column: symbol.start.column.unwrap_or(0), + }, + ); + } + for (index, symbol) in self.symbols.rules.iter() { + if file_sema_map_cache.contains_key(&symbol.start.filename) { + continue; + } + let symbol_ref = SymbolRef { + kind: SymbolKind::Rule, + id: index, + }; + let filename = &symbol.start.filename; + if !file_sema_map.contains_key(filename) { + file_sema_map.insert(filename.clone(), FileSemanticInfo::new(filename.clone())); + } + let file_sema_info = file_sema_map.get_mut(filename).unwrap(); + file_sema_info.symbols.push(symbol_ref); + file_sema_info.symbol_locs.insert( + symbol_ref, + CachedLocation { + line: symbol.start.line, + column: symbol.start.column.unwrap_or(0), + }, + ); + } + for (index, symbol) in self.symbols.values.iter() { + if file_sema_map_cache.contains_key(&symbol.start.filename) { + continue; + } + let symbol_ref = SymbolRef { + kind: SymbolKind::Value, + id: index, + }; + let filename = &symbol.start.filename; + if !file_sema_map.contains_key(filename) { + file_sema_map.insert(filename.clone(), FileSemanticInfo::new(filename.clone())); + } + let file_sema_info = file_sema_map.get_mut(filename).unwrap(); + file_sema_info.symbols.push(symbol_ref); + file_sema_info.symbol_locs.insert( + symbol_ref, + CachedLocation { + line: symbol.start.line, + column: symbol.start.column.unwrap_or(0), + }, + ); + } + for (index, symbol) in self.symbols.unresolved.iter() { + if file_sema_map_cache.contains_key(&symbol.start.filename) { + continue; + } + let symbol_ref = SymbolRef { + kind: SymbolKind::Unresolved, + id: index, + }; + let filename = &symbol.start.filename; + if !file_sema_map.contains_key(filename) { + file_sema_map.insert(filename.clone(), FileSemanticInfo::new(filename.clone())); + } + let file_sema_info = file_sema_map.get_mut(filename).unwrap(); + file_sema_info.symbols.push(symbol_ref); + file_sema_info.symbol_locs.insert( + symbol_ref, + CachedLocation { + line: symbol.start.line, + column: symbol.start.column.unwrap_or(0), + }, + ); + } + + for (index, symbol) in self.symbols.exprs.iter() { + if file_sema_map_cache.contains_key(&symbol.start.filename) { + continue; + } + + let symbol_ref = SymbolRef { + kind: SymbolKind::Expression, + id: index, + }; + let filename = &symbol.start.filename; + if !file_sema_map.contains_key(filename) { + file_sema_map.insert(filename.clone(), FileSemanticInfo::new(filename.clone())); + } + let file_sema_info = file_sema_map.get_mut(filename).unwrap(); + file_sema_info.symbols.push(symbol_ref); + file_sema_info.symbol_locs.insert( + symbol_ref, + CachedLocation { + line: symbol.start.line, + column: symbol.start.column.unwrap_or(0), + }, + ); + } + + for (index, symbol) in self.symbols.comments.iter() { + if file_sema_map_cache.contains_key(&symbol.start.filename) { + continue; + } + let symbol_ref = SymbolRef { + kind: SymbolKind::Comment, + id: index, + }; + let filename = &symbol.start.filename; + if !file_sema_map.contains_key(filename) { + file_sema_map.insert(filename.clone(), FileSemanticInfo::new(filename.clone())); + } + let file_sema_info = file_sema_map.get_mut(filename).unwrap(); + file_sema_info.symbols.push(symbol_ref); + file_sema_info.symbol_locs.insert( + symbol_ref, + CachedLocation { + line: symbol.start.line, + column: symbol.start.column.unwrap_or(0), + }, + ); + } + + for (index, symbol) in self.symbols.decorators.iter() { + if file_sema_map_cache.contains_key(&symbol.start.filename) { + continue; + } + let symbol_ref = SymbolRef { + kind: SymbolKind::Decorator, + id: index, + }; + let filename = &symbol.start.filename; + if !file_sema_map.contains_key(filename) { + file_sema_map.insert(filename.clone(), FileSemanticInfo::new(filename.clone())); + } + let file_sema_info = file_sema_map.get_mut(filename).unwrap(); + file_sema_info.symbols.push(symbol_ref); + file_sema_info.symbol_locs.insert( + symbol_ref, + CachedLocation { + line: symbol.start.line, + column: symbol.start.column.unwrap_or(0), + }, + ); + } + + for (index, symbol) in self.symbols.functions.iter() { + if file_sema_map_cache.contains_key(&symbol.start.filename) { + continue; + } + let symbol_ref = SymbolRef { + kind: SymbolKind::Function, + id: index, + }; + let filename = &symbol.start.filename; + if !file_sema_map.contains_key(filename) { + file_sema_map.insert(filename.clone(), FileSemanticInfo::new(filename.clone())); + } + let file_sema_info = file_sema_map.get_mut(filename).unwrap(); + file_sema_info.symbols.push(symbol_ref); + file_sema_info.symbol_locs.insert( + symbol_ref, + CachedLocation { + line: symbol.start.line, + column: symbol.start.column.unwrap_or(0), + }, + ); + } + + for (_, hints) in &self.symbols.hints { + for hint in hints { + if file_sema_map_cache.contains_key(&hint.pos.filename) { + continue; + } + let filename = &hint.pos.filename; + if !file_sema_map.contains_key(filename) { + file_sema_map.insert(filename.clone(), FileSemanticInfo::new(filename.clone())); + } + let file_sema_info = file_sema_map.get_mut(filename).unwrap(); + file_sema_info.hints.push(hint.clone()); + } + } + + // remove dummy file + file_sema_map.remove(""); + + for (_, sema_info) in file_sema_map.iter_mut() { + sema_info + .symbols + .sort_by_key(|symbol_ref| sema_info.symbol_locs.get(symbol_ref).unwrap()) + } + + file_sema_map_cache.extend(file_sema_map); + } + fn build_sema_db_with_scopes(&self, file_sema_map: &mut IndexMap) { + // put scope + for (index, scope) in self.scopes.locals.iter() { + let scope_ref = ScopeRef { + kind: ScopeKind::Local, + id: index, + }; + let filename = &scope.start.filename; + if !file_sema_map.contains_key(filename) { + file_sema_map.insert(filename.clone(), FileSemanticInfo::new(filename.clone())); + } + let file_sema_info = file_sema_map.get_mut(filename).unwrap(); + file_sema_info.local_scope_locs.insert( + scope_ref, + CachedRange { + start: CachedLocation { + line: scope.start.line, + column: scope.start.column.unwrap_or(0), + }, + end: CachedLocation { + line: scope.end.line, + column: scope.end.column.unwrap_or(0), + }, + }, + ); + file_sema_map + .get_mut(filename) + .unwrap() + .scopes + .push(scope_ref); + } + } + + fn sort_local_scopes(&mut self, file_sema_map: &IndexMap) { + // Direct sub scopes do not overlap, so we can directly sort them by start loc + for (_, root) in self.scopes.roots.iter_mut() { + for (filename, scopes) in root.children.iter_mut() { + let file_sema_info = file_sema_map.get(filename).unwrap(); + scopes.sort_by_key(|scope_ref| { + &file_sema_info + .local_scope_locs + .get(scope_ref) + .unwrap() + .start + }) + } + } + // Direct sub scopes do not overlap, so we can directly sort them by start loc + for (_, scope) in self.scopes.locals.iter_mut() { + let file_sema_info = file_sema_map.get(&scope.start.filename).unwrap(); + scope.children.sort_by_key(|scope_ref| { + &file_sema_info + .local_scope_locs + .get(scope_ref) + .unwrap() + .start + }) + } + } + + pub(crate) fn build_sema_db(&mut self) { + let mut file_sema_map_cache = self.get_sema_db_mut().file_sema_map.clone(); + + self.build_sema_db_with_symbols(&mut file_sema_map_cache); + self.build_sema_db_with_scopes(&mut file_sema_map_cache); + self.sort_local_scopes(&mut file_sema_map_cache); + + self.sema_db.file_sema_map = file_sema_map_cache; + } + + pub fn clear_cache(&mut self) { + let invalidate_pkgs = self.new_or_invalidate_pkgs.clone(); + self.clear_sema_db_cache(&invalidate_pkgs); + self.get_scopes_mut().clear_cache(&invalidate_pkgs); + self.get_packages_mut().clear_cache(&invalidate_pkgs); + self.get_symbols_mut().clear_cache(&invalidate_pkgs); + } + + fn clear_sema_db_cache(&mut self, invalidate_pkgs: &HashSet) { + let mut to_remove: Vec = Vec::new(); + let mut files: IndexSet = IndexSet::new(); + for invalidate_pkg in invalidate_pkgs { + if let Some(symbols) = self + .get_symbols() + .symbols_info + .pkg_symbol_map + .get(invalidate_pkg) + { + to_remove.extend(symbols.iter().cloned()); + } + } + for symbol in to_remove { + if let Some(s) = self.get_symbols().get_symbol(symbol) { + files.insert(s.get_range().0.filename); + } + } + for file in files { + self.sema_db.file_sema_map.remove(&file); + } + } +} diff --git a/kclvm/sema/src/core/mod.rs b/kclvm/sema/src/core/mod.rs new file mode 100644 index 000000000..14b98ccce --- /dev/null +++ b/kclvm/sema/src/core/mod.rs @@ -0,0 +1,5 @@ +pub mod global_state; +pub mod package; +pub mod scope; +pub mod semantic_information; +pub mod symbol; diff --git a/kclvm/sema/src/core/package.rs b/kclvm/sema/src/core/package.rs new file mode 100644 index 000000000..a8488767c --- /dev/null +++ b/kclvm/sema/src/core/package.rs @@ -0,0 +1,132 @@ +use std::collections::HashSet; + +use indexmap::{IndexMap, IndexSet}; + +#[derive(Default, Debug, Clone)] +pub struct PackageDB { + pub(crate) package_info: IndexMap, + pub(crate) module_info: IndexMap, +} + +impl PackageDB { + pub fn add_package(&mut self, info: PackageInfo) { + self.package_info + .insert(info.fully_qualified_name.clone(), info); + } + + pub fn remove_package_info(&mut self, name: &str) { + self.package_info.remove(name); + } + + pub fn get_package_info(&self, name: &str) -> Option<&PackageInfo> { + self.package_info.get(name) + } + + pub fn get_package_info_mut(&mut self, name: &str) -> Option<&mut PackageInfo> { + self.package_info.get_mut(name) + } + + pub fn add_module_info(&mut self, info: ModuleInfo) { + self.module_info.insert(info.filename.clone(), info); + } + + pub fn remove_module_info(&mut self, name: &str) { + self.module_info.remove(name); + } + + pub fn get_module_info_mut(&mut self, name: &str) -> Option<&mut ModuleInfo> { + self.module_info.get_mut(name) + } + + pub fn get_module_info(&self, name: &str) -> Option<&ModuleInfo> { + self.module_info.get(name) + } + + pub fn clear_cache(&mut self, invalidate_pkgs: &HashSet) { + for invalidate_pkg in invalidate_pkgs { + self.package_info.remove(invalidate_pkg); + } + } +} +#[derive(Debug, Clone)] +pub struct PackageInfo { + pub(crate) fully_qualified_name: String, + pub(crate) pkg_filepath: String, + pub(crate) kfile_paths: IndexSet, + pub(crate) is_system: bool, +} + +impl PackageInfo { + pub fn new(fully_qualified_name: String, pkg_filepath: String, is_system: bool) -> Self { + Self { + fully_qualified_name, + pkg_filepath, + kfile_paths: IndexSet::default(), + is_system, + } + } + + pub fn get_kfile_paths(&self) -> &IndexSet { + &self.kfile_paths + } + + pub fn get_pkg_filepath(&self) -> &String { + &self.pkg_filepath + } + + pub fn is_system(&self) -> bool { + self.is_system + } +} +#[allow(unused)] +#[derive(Debug, Clone)] +pub struct ImportInfo { + pub(crate) unqualified_name: String, + pub(crate) fully_qualified_name: String, +} + +impl ImportInfo { + pub fn new(unqualified_name: String, fully_qualified_name: String) -> Self { + Self { + unqualified_name, + fully_qualified_name, + } + } + + pub fn get_fully_qualified_name(&self) -> String { + self.fully_qualified_name.clone() + } +} +#[allow(unused)] +#[derive(Debug, Clone)] +pub struct ModuleInfo { + pub(crate) filename: String, + pub(crate) pkgpath: String, + pub(crate) imports: IndexMap, +} + +impl ModuleInfo { + pub fn new(filename: String, pkgpath: String) -> Self { + Self { + filename, + pkgpath, + imports: IndexMap::default(), + } + } + + pub fn add_import_info(&mut self, info: ImportInfo) { + self.imports.insert(info.unqualified_name.clone(), info); + } + + pub fn remove_import_info(&mut self, name: &str) { + self.imports.remove(name); + } + + pub fn get_import_info(&self, name: &str) -> Option<&ImportInfo> { + self.imports.get(name) + } + + pub fn get_imports(&self) -> IndexMap { + self.imports.clone() + } +} diff --git a/kclvm/sema/src/core/scope.rs b/kclvm/sema/src/core/scope.rs new file mode 100644 index 000000000..51d19c4f5 --- /dev/null +++ b/kclvm/sema/src/core/scope.rs @@ -0,0 +1,745 @@ +use std::collections::{HashMap, HashSet}; + +use indexmap::{IndexMap, IndexSet}; +use kclvm_ast::pos::ContainsPos; +use kclvm_error::{diagnostic::Range, Position}; +use serde::Serialize; + +use crate::core::symbol::SymbolRef; + +use super::{package::ModuleInfo, symbol::SymbolData}; + +pub trait Scope { + type SymbolData; + fn get_filename(&self) -> &str; + fn get_parent(&self) -> Option; + fn get_children(&self) -> Vec; + + fn contains_pos(&self, pos: &Position) -> bool; + fn get_range(&self) -> Option<(Position, Position)>; + + fn get_owner(&self) -> Option; + fn look_up_def( + &self, + name: &str, + scope_data: &ScopeData, + symbol_data: &Self::SymbolData, + module_info: Option<&ModuleInfo>, + // lookup in local scope + local: bool, + // lookup in scope owner + get_def_from_owner: bool, + ) -> Option; + + /// Get all defs within current scope and parent scope + fn get_all_defs( + &self, + scope_data: &ScopeData, + symbol_data: &Self::SymbolData, + module_info: Option<&ModuleInfo>, + maybe_in_key: bool, + get_def_from_owner: bool, + ) -> HashMap; + + /// Get all defs within current scope + fn get_defs_within_scope( + &self, + scope_data: &ScopeData, + symbol_data: &Self::SymbolData, + module_info: Option<&ModuleInfo>, + maybe_in_key: bool, + get_def_from_owner: bool, + ) -> HashMap; + + fn dump(&self, scope_data: &ScopeData, symbol_data: &Self::SymbolData) -> Option; +} + +#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, Serialize)] +pub enum ScopeKind { + Local, + Root, +} + +#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)] +pub struct ScopeRef { + pub(crate) id: generational_arena::Index, + pub(crate) kind: ScopeKind, +} + +impl Serialize for ScopeRef { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + let (index, generation) = self.id.into_raw_parts(); + let data = SerializableScopeRef { + i: index as u64, + g: generation, + kind: self.kind.clone(), + }; + data.serialize(serializer) + } +} + +#[derive(Debug, Clone, Serialize)] + +struct SerializableScopeRef { + i: u64, + g: u64, + kind: ScopeKind, +} + +impl ScopeRef { + pub fn get_id(&self) -> generational_arena::Index { + self.id + } + + pub fn get_kind(&self) -> ScopeKind { + self.kind + } +} + +#[derive(Default, Debug, Clone)] +pub struct ScopeData { + /// map pkgpath to root_scope + pub(crate) root_map: IndexMap, + /// map schema fully qualified name to schema local scope + pub(crate) schema_scope_map: IndexMap, + pub(crate) locals: generational_arena::Arena, + pub(crate) roots: generational_arena::Arena, + pub(crate) config_scope_context: IndexMap, +} + +/// Determine the position of pos in the config scope for completion in lsp. +/// Refer to gopls `compLitInfo`: https://github.com/golang/tools/blob/28ba9914c6b79f6cf3a56cc477398f7fd686c84d/gopls/internal/golang/completion/completion.go#L298 +/// But the semantics are different. Complete item in: +/// Go: left = keys + right right = all def in scope and parent scope +/// kcl: left = keys if in schema, right = all def in left and parent scope +#[derive(Default, Debug, Clone)] +pub struct ConfigScopeContext { + pub entries_range: Vec<(Option, Range)>, +} + +impl ConfigScopeContext { + pub fn in_entry(&self, pos: &Position) -> bool { + self.entries_range.iter().any(|(key, value)| { + let start = if key.is_some() { + key.clone().unwrap().0 + } else { + value.0.clone() + }; + start.less_equal(pos) && pos.less_equal(&value.1) + }) + } + + pub fn maybe_in_key(&self, pos: &Position) -> bool { + !self.in_right_value(pos) + } + + pub fn in_right_value(&self, pos: &Position) -> bool { + self.entries_range + .iter() + .any(|(_, value)| value.contains_pos(pos)) + } +} + +impl ScopeData { + #[inline] + pub fn get_root_scope_map(&self) -> &IndexMap { + &self.root_map + } + + pub fn get_scope(&self, scope: &ScopeRef) -> Option<&dyn Scope> { + match scope.get_kind() { + ScopeKind::Local => { + Some(self.locals.get(scope.get_id())? as &dyn Scope) + } + ScopeKind::Root => { + Some(self.roots.get(scope.get_id())? as &dyn Scope) + } + } + } + + pub fn remove_scope(&mut self, scope: &ScopeRef) { + match scope.get_kind() { + ScopeKind::Local => { + self.locals.remove(scope.get_id()); + } + ScopeKind::Root => { + self.roots.remove(scope.get_id()); + } + } + } + + pub fn try_get_local_scope(&self, scope: &ScopeRef) -> Option<&LocalSymbolScope> { + match scope.get_kind() { + ScopeKind::Local => Some(self.locals.get(scope.get_id())?), + ScopeKind::Root => None, + } + } + + pub fn get_root_scope(&self, name: String) -> Option { + self.root_map.get(&name).copied() + } + + pub fn add_def_to_scope(&mut self, scope: ScopeRef, name: String, symbol: SymbolRef) { + match scope.get_kind() { + ScopeKind::Local => { + if let Some(local) = self.locals.get_mut(scope.get_id()) { + local.defs.insert(name, symbol); + } + } + ScopeKind::Root => { + unreachable!("never add symbol to root scope after namer pass") + } + } + } + + pub fn add_ref_to_scope(&mut self, scope: ScopeRef, symbol: SymbolRef) { + match scope.get_kind() { + ScopeKind::Local => { + if let Some(local) = self.locals.get_mut(scope.get_id()) { + local.refs.push(symbol); + } + } + ScopeKind::Root => { + if let Some(root) = self.roots.get_mut(scope.get_id()) { + root.refs.push(symbol); + } + } + } + } + + pub fn set_owner_to_scope(&mut self, scope: ScopeRef, owner: SymbolRef) { + match scope.get_kind() { + ScopeKind::Local => { + if let Some(local) = self.locals.get_mut(scope.get_id()) { + local.owner = Some(owner); + } + } + ScopeKind::Root => { + if let Some(root) = self.roots.get_mut(scope.get_id()) { + root.owner = owner; + } + } + } + } + + pub fn alloc_root_scope(&mut self, root: RootSymbolScope) -> ScopeRef { + let filepath = root.pkgpath.clone(); + let id = self.roots.insert(root); + let scope_ref = ScopeRef { + id, + kind: ScopeKind::Root, + }; + self.root_map.insert(filepath, scope_ref); + scope_ref + } + + pub fn alloc_local_scope(&mut self, local: LocalSymbolScope) -> ScopeRef { + let id = self.locals.insert(local); + ScopeRef { + id, + kind: ScopeKind::Local, + } + } + + pub fn clear_cache(&mut self, invalidate_pkgs: &HashSet) { + for invalidate_pkg in invalidate_pkgs { + if let Some(scope_ref) = self.root_map.remove(invalidate_pkg) { + self.clear_scope_and_child(scope_ref); + self.roots.remove(scope_ref.get_id()); + } + self.schema_scope_map + .retain(|key, _| !key.starts_with(invalidate_pkg)); + } + } + + pub fn clear_scope_and_child(&mut self, scope_ref: ScopeRef) { + if let Some(scope) = self.get_scope(&scope_ref) { + for c in scope.get_children() { + self.clear_scope_and_child(c) + } + } + self.remove_scope(&scope_ref) + } + + pub fn set_config_scope_ctx(&mut self, scope: ScopeRef, ctx: ConfigScopeContext) { + self.config_scope_context.insert(scope.get_id(), ctx); + } + + pub fn get_config_scope_ctx(&self, scope: ScopeRef) -> Option { + self.config_scope_context.get(&scope.get_id()).cloned() + } +} + +#[derive(Debug, Clone)] +pub struct RootSymbolScope { + pub(crate) pkgpath: String, + + pub(crate) filename: String, + + pub(crate) kfile_path: IndexSet, + + /// PackageSymbol of this scope + pub(crate) owner: SymbolRef, + + /// map filepath to children + pub(crate) children: IndexMap>, + + pub(crate) refs: Vec, +} + +impl Scope for RootSymbolScope { + type SymbolData = SymbolData; + fn get_filename(&self) -> &str { + &self.filename + } + + fn get_children(&self) -> Vec { + let mut children = vec![]; + for scopes in self.children.values() { + children.append(&mut scopes.clone()) + } + children + } + + fn get_parent(&self) -> Option { + None + } + + fn contains_pos(&self, pos: &Position) -> bool { + self.kfile_path.contains(&pos.filename) + } + fn get_owner(&self) -> Option { + Some(self.owner) + } + + fn look_up_def( + &self, + name: &str, + _scope_data: &ScopeData, + symbol_data: &Self::SymbolData, + module_info: Option<&ModuleInfo>, + _local: bool, + _owner: bool, + ) -> Option { + let package_symbol = symbol_data.get_symbol(self.owner)?; + + package_symbol.get_attribute(name, symbol_data, module_info) + } + + fn get_all_defs( + &self, + _scope_data: &ScopeData, + symbol_data: &Self::SymbolData, + module_info: Option<&ModuleInfo>, + _maybe_in_key: bool, + _owner: bool, + ) -> HashMap { + let mut all_defs_map = HashMap::new(); + if let Some(owner) = symbol_data.get_symbol(self.owner) { + let all_defs = owner.get_all_attributes(symbol_data, module_info); + + for def_ref in all_defs { + if let Some(def) = symbol_data.get_symbol(def_ref) { + all_defs_map.insert(def.get_name(), def_ref); + } + } + } + all_defs_map + } + + fn dump(&self, scope_data: &ScopeData, symbol_data: &Self::SymbolData) -> Option { + let mut output = String::from(""); + output.push_str("{\n\"scope_kind\": \"Root\",\n"); + output.push_str(&format!("\n\"pkgpath\": \"{}\",\n", self.pkgpath)); + let owner_symbol = symbol_data.get_symbol(self.owner)?; + output.push_str(&format!( + "\"owner\": {},\n", + owner_symbol.full_dump(symbol_data)? + )); + output.push_str("\"refs\": [\n"); + for (index, symbol) in self.refs.iter().enumerate() { + let symbol = symbol_data.get_symbol(*symbol)?; + output.push_str(&format!("{}", symbol.full_dump(symbol_data)?)); + if index + 1 < self.refs.len() { + output.push_str(",\n") + } + } + output.push_str("\n],\n"); + output.push_str("\"children\": {\n"); + for (index, (key, scopes)) in self.children.iter().enumerate() { + output.push_str(&format!("\"{}\": [\n", key)); + for (index, scope) in scopes.iter().enumerate() { + let scope = scope_data.get_scope(scope)?; + output.push_str(&format!("{}", scope.dump(scope_data, symbol_data)?)); + if index + 1 < scopes.len() { + output.push_str(",\n"); + } + } + output.push_str("\n]"); + if index + 1 < self.children.len() { + output.push_str(",\n"); + } + } + output.push_str("\n}\n}"); + + let val: serde_json::Value = serde_json::from_str(&output).unwrap(); + Some(serde_json::to_string_pretty(&val).ok()?) + } + + fn get_range(&self) -> Option<(Position, Position)> { + None + } + + fn get_defs_within_scope( + &self, + scope_data: &ScopeData, + symbol_data: &Self::SymbolData, + module_info: Option<&ModuleInfo>, + maybe_in_key: bool, + owner: bool, + ) -> HashMap { + // get defs within root scope equal to get all defs + self.get_all_defs(scope_data, symbol_data, module_info, maybe_in_key, owner) + } +} + +impl RootSymbolScope { + pub fn new( + pkgpath: String, + filename: String, + owner: SymbolRef, + kfile_path: IndexSet, + ) -> Self { + Self { + pkgpath, + kfile_path, + filename, + owner, + children: IndexMap::default(), + refs: vec![], + } + } + + pub fn add_child(&mut self, filepath: &str, child: ScopeRef) { + if self.children.contains_key(filepath) { + self.children.get_mut(filepath).unwrap().push(child); + } else { + self.children.insert(filepath.to_string(), vec![child]); + } + } +} + +#[derive(Debug, Clone)] +pub struct LocalSymbolScope { + pub(crate) parent: ScopeRef, + pub(crate) owner: Option, + pub(crate) children: Vec, + pub(crate) defs: IndexMap, + pub(crate) refs: Vec, + + pub(crate) start: Position, + pub(crate) end: Position, + pub(crate) kind: LocalSymbolScopeKind, +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum LocalSymbolScopeKind { + List, + Dict, + Quant, + Lambda, + SchemaDef, + Config, + Check, + Callable, +} + +impl Scope for LocalSymbolScope { + type SymbolData = SymbolData; + + fn get_filename(&self) -> &str { + &self.start.filename + } + + fn get_children(&self) -> Vec { + self.children.clone() + } + + fn get_parent(&self) -> Option { + Some(self.parent) + } + + fn contains_pos(&self, pos: &Position) -> bool { + self.start.filename == pos.filename + && self.start.less_equal(pos) + && pos.less_equal(&self.end) + } + + fn get_owner(&self) -> Option { + self.owner.clone() + } + + fn look_up_def( + &self, + name: &str, + scope_data: &ScopeData, + symbol_data: &Self::SymbolData, + module_info: Option<&ModuleInfo>, + local: bool, + get_def_from_owner: bool, + ) -> Option { + match self.defs.get(name) { + Some(symbol_ref) => return Some(*symbol_ref), + None => { + // Try to get the attributes in the schema's protocol and mixin, and get the schema attr by `get_def_from_owner` + if let LocalSymbolScopeKind::SchemaDef = self.kind { + if let Some(owner) = self.owner.as_ref() { + if let Some(owner_schema) = symbol_data.get_schema_symbol(*owner) { + let attrs = + owner_schema.get_protocol_and_mixin_attrs(symbol_data, module_info); + for attr in attrs { + if let Some(symbol) = symbol_data.get_symbol(attr) { + if symbol.get_name() == name { + return Some(attr); + } + } + } + } + } + } + + match (local, get_def_from_owner) { + // Search in the current scope and owner + (true, true) => { + if let Some(owner) = self.owner.as_ref() { + let owner_symbol = symbol_data.get_symbol(*owner)?; + if let Some(symbol_ref) = + owner_symbol.get_attribute(name, symbol_data, module_info) + { + return Some(symbol_ref); + } + } + None + } + // Search only in the current scope + (true, false) => None, + // Search in the current scope, parent scope and owner + (false, true) => { + if let Some(owner) = self.owner.as_ref() { + let owner_symbol = symbol_data.get_symbol(*owner)?; + if let Some(symbol_ref) = + owner_symbol.get_attribute(name, symbol_data, module_info) + { + return Some(symbol_ref); + } + }; + + let parent = scope_data.get_scope(&self.parent)?; + return parent.look_up_def( + name, + scope_data, + symbol_data, + module_info, + local, + get_def_from_owner, + ); + } + // Search in the current and parent scope + (false, false) => { + let parent = scope_data.get_scope(&self.parent)?; + return parent.look_up_def( + name, + scope_data, + symbol_data, + module_info, + local, + get_def_from_owner, + ); + } + } + } + } + } + + fn get_all_defs( + &self, + scope_data: &ScopeData, + symbol_data: &Self::SymbolData, + module_info: Option<&ModuleInfo>, + maybe_in_key: bool, + owner: bool, + ) -> HashMap { + let mut all_defs_map = HashMap::new(); + if owner { + if let Some(owner) = self.owner { + if let Some(owner) = symbol_data.get_symbol(owner) { + for def_ref in owner.get_all_attributes(symbol_data, module_info) { + if let Some(def) = symbol_data.get_symbol(def_ref) { + let name = def.get_name(); + if !all_defs_map.contains_key(&name) { + all_defs_map.insert(name, def_ref); + } + } + } + } + } + } + // In Config, available definitions only contain keys of schema attr,i.e., `left` values in schema expr. + // but right value in schema expr, available definitions contain all def in left parent definitions. + // ``` + // b = "bar" + // foo = Foo{ + // bar: b + // } + // ```` + // At position of `bar`, only get def from keys of Foo + // At position of seconde `b`, get def from left([bar]) and parent scope + if maybe_in_key { + return all_defs_map; + } + + for def_ref in self.defs.values() { + if let Some(def) = symbol_data.get_symbol(*def_ref) { + all_defs_map.insert(def.get_name(), *def_ref); + } + } + + if let Some(parent) = scope_data.get_scope(&self.parent) { + for (name, def_ref) in + parent.get_all_defs(scope_data, symbol_data, module_info, false, owner) + { + if !all_defs_map.contains_key(&name) { + all_defs_map.insert(name, def_ref); + } + } + } + all_defs_map + } + + fn dump(&self, scope_data: &ScopeData, symbol_data: &Self::SymbolData) -> Option { + let mut output = String::from(""); + output.push_str("{\n\"scope_kind\": \"Local\",\n"); + output.push_str(&format!( + "\"range\": \"{}:{}", + self.start.filename, self.start.line + )); + if let Some(start_col) = self.start.column { + output.push_str(&format!(":{}", start_col)); + } + + output.push_str(&format!(" to {}", self.end.line)); + if let Some(end_col) = self.end.column { + output.push_str(&format!(":{}", end_col)); + } + output.push_str("\",\n"); + if let Some(owner) = self.owner.as_ref() { + let owner_symbol = symbol_data.get_symbol(*owner)?; + output.push_str(&format!( + "\"owner\": {},\n", + owner_symbol.full_dump(symbol_data)? + )); + } + output.push_str("\"defs\": {\n"); + for (index, (key, symbol)) in self.defs.iter().enumerate() { + let symbol = symbol_data.get_symbol(*symbol)?; + output.push_str(&format!("\"{}\": {}", key, symbol.full_dump(symbol_data)?)); + if index + 1 < self.defs.len() { + output.push_str(",\n") + } + } + output.push_str("\n},\n"); + output.push_str("\"refs\": [\n"); + for (index, symbol) in self.refs.iter().enumerate() { + let symbol = symbol_data.get_symbol(*symbol)?; + output.push_str(&format!("{}", symbol.full_dump(symbol_data)?)); + if index + 1 < self.refs.len() { + output.push_str(",\n") + } + } + output.push_str("\n],"); + output.push_str("\n\"children\": [\n"); + for (index, scope) in self.children.iter().enumerate() { + let scope = scope_data.get_scope(scope)?; + output.push_str(&format!("{}", scope.dump(scope_data, symbol_data)?)); + if index + 1 < self.children.len() { + output.push_str(",\n") + } + } + output.push_str("\n]\n}"); + Some(output) + } + + fn get_range(&self) -> Option<(Position, Position)> { + Some((self.start.clone(), self.end.clone())) + } + + fn get_defs_within_scope( + &self, + _scope_data: &ScopeData, + symbol_data: &Self::SymbolData, + module_info: Option<&ModuleInfo>, + _maybe_in_key: bool, + owner: bool, + ) -> HashMap { + let mut all_defs_map = HashMap::new(); + if owner { + if let Some(owner) = self.owner { + if let Some(owner) = symbol_data.get_symbol(owner) { + for def_ref in owner.get_all_attributes(symbol_data, module_info) { + if let Some(def) = symbol_data.get_symbol(def_ref) { + let name = def.get_name(); + if !all_defs_map.contains_key(&name) { + all_defs_map.insert(name, def_ref); + } + } + } + } + } + } + + for def_ref in self.defs.values() { + if let Some(def) = symbol_data.get_symbol(*def_ref) { + all_defs_map.insert(def.get_name(), *def_ref); + } + } + all_defs_map + } +} + +impl LocalSymbolScope { + pub fn new( + parent: ScopeRef, + start: Position, + end: Position, + kind: LocalSymbolScopeKind, + ) -> Self { + Self { + parent, + owner: None, + children: vec![], + defs: IndexMap::default(), + refs: vec![], + start, + end, + kind, + } + } + + #[inline] + pub fn get_kind(&self) -> &LocalSymbolScopeKind { + &self.kind + } + + #[inline] + pub fn add_child(&mut self, child: ScopeRef) { + self.children.push(child) + } + + #[inline] + pub fn set_owner(&mut self, owner: SymbolRef) { + self.owner = Some(owner) + } +} diff --git a/kclvm/sema/src/core/semantic_information.rs b/kclvm/sema/src/core/semantic_information.rs new file mode 100644 index 000000000..a1720f2da --- /dev/null +++ b/kclvm/sema/src/core/semantic_information.rs @@ -0,0 +1,99 @@ +use indexmap::IndexMap; +use kclvm_ast::ast::AstIndex; +use std::sync::Arc; + +use super::{ + scope::ScopeRef, + symbol::{SymbolHint, SymbolRef}, +}; +use crate::ty::Type; +#[allow(unused)] +#[derive(Debug, Default, Clone)] +pub struct SemanticDB { + pub(crate) tys: IndexMap>, + pub(crate) file_sema_map: IndexMap, +} + +impl SemanticDB { + pub fn get_file_sema(&self, file: &str) -> Option<&FileSemanticInfo> { + self.file_sema_map.get(file) + } +} + +#[allow(unused)] +#[derive(Debug, Clone)] +pub struct FileSemanticInfo { + pub(crate) filename: String, + pub(crate) symbols: Vec, + pub(crate) scopes: Vec, + pub(crate) symbol_locs: IndexMap, + pub(crate) local_scope_locs: IndexMap, + pub(crate) hints: Vec, +} + +impl FileSemanticInfo { + pub fn new(filename: String) -> Self { + Self { + filename, + symbols: vec![], + scopes: vec![], + symbol_locs: IndexMap::default(), + local_scope_locs: IndexMap::default(), + hints: vec![], + } + } + + pub fn look_up_closest_symbol(&self, loc: &CachedLocation) -> Option { + match self + .symbols + .binary_search_by(|symbol_ref| self.symbol_locs.get(symbol_ref).unwrap().cmp(loc)) + { + Ok(symbol_index) => Some(self.symbols[symbol_index]), + Err(symbol_index) => { + if symbol_index > 0 { + Some(self.symbols[symbol_index - 1]) + } else { + None + } + } + } + } + + pub fn get_symbols(&self) -> &Vec { + &self.symbols + } + + pub fn get_hints(&self) -> &Vec { + &self.hints + } +} + +#[derive(Debug, Eq, PartialEq, Clone)] +pub struct CachedLocation { + pub(crate) line: u64, + pub(crate) column: u64, +} + +#[derive(Debug, Eq, PartialEq, Clone)] +pub struct CachedRange { + pub(crate) start: CachedLocation, + pub(crate) end: CachedLocation, +} + +impl Ord for CachedLocation { + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + match self.line.cmp(&other.line) { + core::cmp::Ordering::Equal => self.column.cmp(&other.column), + ord => return ord, + } + } +} + +impl PartialOrd for CachedLocation { + fn partial_cmp(&self, other: &Self) -> Option { + match self.line.partial_cmp(&other.line) { + Some(core::cmp::Ordering::Equal) => self.column.partial_cmp(&other.column), + ord => return ord, + } + } +} diff --git a/kclvm/sema/src/core/symbol.rs b/kclvm/sema/src/core/symbol.rs new file mode 100644 index 000000000..0b81521fe --- /dev/null +++ b/kclvm/sema/src/core/symbol.rs @@ -0,0 +1,2637 @@ +use std::{ + collections::{HashMap, HashSet}, + sync::Arc, +}; + +use generational_arena::Arena; +use indexmap::{IndexMap, IndexSet}; + +use kclvm_error::{diagnostic::Range, Position}; +use serde::Serialize; + +use super::package::ModuleInfo; +use crate::{ + resolver::scope::NodeKey, + ty::{Type, TypeKind, TypeRef}, +}; + +pub trait Symbol { + type SymbolData; + type SemanticInfo; + type SymbolHint; + + fn get_sema_info(&self) -> &Self::SemanticInfo; + fn is_global(&self) -> bool; + fn get_range(&self) -> Range; + fn get_owner(&self) -> Option; + fn get_definition(&self) -> Option; + fn get_references(&self) -> HashSet; + fn get_name(&self) -> String; + fn get_id(&self) -> Option; + fn get_attribute( + &self, + name: &str, + data: &Self::SymbolData, + module_info: Option<&ModuleInfo>, + ) -> Option; + fn has_attribute( + &self, + name: &str, + data: &Self::SymbolData, + module_info: Option<&ModuleInfo>, + ) -> bool; + + fn get_all_attributes( + &self, + data: &Self::SymbolData, + module_info: Option<&ModuleInfo>, + ) -> Vec; + + fn simple_dump(&self) -> String; + + fn full_dump(&self, data: &Self::SymbolData) -> Option; +} + +pub type KCLSymbol = + dyn Symbol; +#[derive(Debug, Clone, Default)] +pub struct SymbolSemanticInfo { + pub ty: Option>, + pub doc: Option, +} + +pub(crate) const BUILTIN_STR_PACKAGE: &'static str = "@str"; +pub(crate) const BUILTIN_FUNCTION_PACKAGE: &'static str = "@builtin"; + +#[derive(Default, Debug, Clone)] +pub struct SymbolData { + pub(crate) values: Arena, + pub(crate) packages: Arena, + pub(crate) attributes: Arena, + pub(crate) schemas: Arena, + pub(crate) type_aliases: Arena, + pub(crate) unresolved: Arena, + pub(crate) rules: Arena, + pub(crate) exprs: Arena, + pub(crate) comments: Arena, + pub(crate) decorators: Arena, + pub(crate) functions: Arena, + pub(crate) hints: HashMap>, + + pub(crate) symbols_info: SymbolDB, +} + +#[derive(Default, Debug, Clone)] +pub struct SymbolDB { + pub(crate) symbol_pos_set: IndexSet, + pub(crate) global_builtin_symbols: IndexMap, + pub(crate) fully_qualified_name_map: IndexMap, + pub(crate) schema_builtin_symbols: IndexMap>, + pub(crate) node_symbol_map: IndexMap, + pub(crate) symbol_node_map: IndexMap, + pub(crate) pkg_symbol_map: IndexMap>, +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct SymbolHint { + pub kind: SymbolHintKind, + pub pos: Position, +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub enum SymbolHintKind { + TypeHint(String), + VarHint(String), + KeyTypeHint(String), +} + +impl SymbolData { + pub fn get_all_schemas(&self) -> &Arena { + &self.schemas + } + + pub fn get_package_symbol(&self, id: SymbolRef) -> Option<&PackageSymbol> { + if matches!(id.get_kind(), SymbolKind::Package) { + self.packages.get(id.get_id()) + } else { + None + } + } + + pub fn get_value_symbol(&self, id: SymbolRef) -> Option<&ValueSymbol> { + if matches!(id.get_kind(), SymbolKind::Value) { + self.values.get(id.get_id()) + } else { + None + } + } + + pub fn get_attribute_symbol(&self, id: SymbolRef) -> Option<&AttributeSymbol> { + if matches!(id.get_kind(), SymbolKind::Attribute) { + self.attributes.get(id.get_id()) + } else { + None + } + } + + pub fn get_type_alias_symbol(&self, id: SymbolRef) -> Option<&TypeAliasSymbol> { + if matches!(id.get_kind(), SymbolKind::TypeAlias) { + self.type_aliases.get(id.get_id()) + } else { + None + } + } + + pub fn get_schema_symbol(&self, id: SymbolRef) -> Option<&SchemaSymbol> { + if matches!(id.get_kind(), SymbolKind::Schema) { + self.schemas.get(id.get_id()) + } else { + None + } + } + + pub fn get_rule_symbol(&self, id: SymbolRef) -> Option<&RuleSymbol> { + if matches!(id.get_kind(), SymbolKind::Rule) { + self.rules.get(id.get_id()) + } else { + None + } + } + + pub fn get_attr_symbol(&self, id: SymbolRef) -> Option<&AttributeSymbol> { + if matches!(id.get_kind(), SymbolKind::Attribute) { + self.attributes.get(id.get_id()) + } else { + None + } + } + + pub fn get_function_symbol(&self, id: SymbolRef) -> Option<&FunctionSymbol> { + if matches!(id.get_kind(), SymbolKind::Function) { + self.functions.get(id.get_id()) + } else { + None + } + } + + pub fn get_unresolved_symbol(&self, id: SymbolRef) -> Option<&UnresolvedSymbol> { + if matches!(id.get_kind(), SymbolKind::Unresolved) { + self.unresolved.get(id.get_id()) + } else { + None + } + } + + pub fn get_symbol(&self, id: SymbolRef) -> Option<&KCLSymbol> { + match id.get_kind() { + SymbolKind::Schema => self + .schemas + .get(id.get_id()) + .map(|symbol| symbol as &KCLSymbol), + SymbolKind::Attribute => self + .attributes + .get(id.get_id()) + .map(|symbol| symbol as &KCLSymbol), + SymbolKind::Value => self + .values + .get(id.get_id()) + .map(|symbol| symbol as &KCLSymbol), + SymbolKind::Package => self + .packages + .get(id.get_id()) + .map(|symbol| symbol as &KCLSymbol), + SymbolKind::TypeAlias => self + .type_aliases + .get(id.get_id()) + .map(|symbol| symbol as &KCLSymbol), + SymbolKind::Unresolved => self + .unresolved + .get(id.get_id()) + .map(|symbol| symbol as &KCLSymbol), + SymbolKind::Rule => self + .rules + .get(id.get_id()) + .map(|symbol| symbol as &KCLSymbol), + SymbolKind::Expression => self + .exprs + .get(id.get_id()) + .map(|symbol| symbol as &KCLSymbol), + SymbolKind::Comment => self + .comments + .get(id.get_id()) + .map(|symbol| symbol as &KCLSymbol), + SymbolKind::Decorator => self + .decorators + .get(id.get_id()) + .map(|symbol| symbol as &KCLSymbol), + SymbolKind::Function => self + .functions + .get(id.get_id()) + .map(|symbol| symbol as &KCLSymbol), + } + } + + pub fn remove_symbol(&mut self, id: &SymbolRef) { + if let Some(symbol) = self.get_symbol(id.clone()) { + self.symbols_info + .symbol_pos_set + .remove(&symbol.get_range().1); + } + match id.get_kind() { + SymbolKind::Schema => { + self.schemas.remove(id.get_id()); + } + SymbolKind::Attribute => { + self.attributes.remove(id.get_id()); + } + SymbolKind::Value => { + self.values.remove(id.get_id()); + } + SymbolKind::Package => { + self.packages.remove(id.get_id()); + } + SymbolKind::TypeAlias => { + self.type_aliases.remove(id.get_id()); + } + SymbolKind::Unresolved => { + self.unresolved.remove(id.get_id()); + } + SymbolKind::Rule => { + self.rules.remove(id.get_id()); + } + SymbolKind::Expression => { + self.exprs.remove(id.get_id()); + } + SymbolKind::Comment => { + self.comments.remove(id.get_id()); + } + SymbolKind::Decorator => { + self.decorators.remove(id.get_id()); + } + SymbolKind::Function => { + self.functions.remove(id.get_id()); + } + } + } + + pub fn set_symbol_type(&mut self, id: SymbolRef, ty: TypeRef) { + match id.get_kind() { + SymbolKind::Schema => { + self.schemas.get_mut(id.get_id()).map(|symbol| { + symbol.sema_info.ty = Some(ty); + symbol + }); + } + SymbolKind::Attribute => { + self.attributes.get_mut(id.get_id()).map(|symbol| { + symbol.sema_info.ty = Some(ty); + symbol + }); + } + SymbolKind::Value => { + self.values.get_mut(id.get_id()).map(|symbol| { + symbol.sema_info.ty = Some(ty); + symbol + }); + } + SymbolKind::Package => { + self.packages.get_mut(id.get_id()).map(|symbol| { + symbol.sema_info.ty = Some(ty); + symbol + }); + } + SymbolKind::TypeAlias => { + self.type_aliases.get_mut(id.get_id()).map(|symbol| { + symbol.sema_info.ty = Some(ty); + symbol + }); + } + SymbolKind::Unresolved => { + self.unresolved.get_mut(id.get_id()).map(|symbol| { + symbol.sema_info.ty = Some(ty); + symbol + }); + } + SymbolKind::Rule => { + self.rules.get_mut(id.get_id()).map(|symbol| { + symbol.sema_info.ty = Some(ty); + symbol + }); + } + SymbolKind::Expression => { + self.exprs.get_mut(id.get_id()).map(|symbol| { + symbol.sema_info.ty = Some(ty); + symbol + }); + } + SymbolKind::Comment => { + self.comments.get_mut(id.get_id()).map(|symbol| { + symbol.sema_info.ty = Some(ty); + symbol + }); + } + SymbolKind::Decorator => { + self.decorators.get_mut(id.get_id()).map(|symbol| { + symbol.sema_info.ty = Some(ty); + symbol + }); + } + SymbolKind::Function => { + self.functions.get_mut(id.get_id()).map(|symbol| { + symbol.sema_info.ty = Some(ty); + symbol + }); + } + } + } + + pub fn get_type_symbol( + &self, + ty: &Type, + module_info: Option<&ModuleInfo>, + ) -> Option { + match &ty.kind { + //TODO: builtin ty symbol,now we just return none + TypeKind::None => None, + TypeKind::Any => None, + TypeKind::Void => None, + TypeKind::Bool => None, + TypeKind::BoolLit(_) => None, + TypeKind::Int => None, + TypeKind::IntLit(_) => None, + TypeKind::Float => None, + TypeKind::FloatLit(_) => None, + TypeKind::Str => self.get_symbol_by_fully_qualified_name(BUILTIN_STR_PACKAGE), + TypeKind::StrLit(_) => self.get_symbol_by_fully_qualified_name(BUILTIN_STR_PACKAGE), + TypeKind::List(_) => None, + TypeKind::Dict(_) => None, + TypeKind::NumberMultiplier(_) => None, + TypeKind::Function(_) => None, + TypeKind::Union(types) => { + if types + .iter() + .all(|ut| matches!(&ut.kind, TypeKind::StrLit(_) | TypeKind::Str)) + { + self.get_symbol_by_fully_qualified_name(BUILTIN_STR_PACKAGE) + } else { + None + } + } + TypeKind::Schema(schema_ty) => { + let fully_qualified_ty_name = schema_ty.pkgpath.clone() + "." + &schema_ty.name; + + self.get_symbol_by_fully_qualified_name(&fully_qualified_ty_name) + } + TypeKind::Module(module_ty) => { + self.get_symbol_by_fully_qualified_name(&module_ty.pkgpath) + } + TypeKind::Named(name) => { + let splits: Vec<&str> = name.rsplitn(2, '.').collect(); + let len = splits.len(); + let pkgname = splits[len - 1]; + + let pkgpath: &String = &module_info?.get_import_info(pkgname)?.fully_qualified_name; + let fully_qualified_ty_name = if name.contains('.') { + name.replacen(&pkgname, pkgpath, 1) + } else { + kclvm_ast::MAIN_PKG.to_string() + name + }; + + self.get_symbol_by_fully_qualified_name(&fully_qualified_ty_name) + } + } + } + + pub fn get_type_all_attribute( + &self, + ty: &Type, + name: &str, + module_info: Option<&ModuleInfo>, + ) -> Vec { + match &ty.kind { + //TODO: builtin ty symbol,now we just return none + TypeKind::None => vec![], + TypeKind::Any => vec![], + TypeKind::Void => vec![], + TypeKind::Bool => vec![], + TypeKind::BoolLit(_) => vec![], + TypeKind::Int => vec![], + TypeKind::IntLit(_) => vec![], + TypeKind::Float => vec![], + TypeKind::FloatLit(_) => vec![], + TypeKind::Str | TypeKind::StrLit(_) => { + let mut result = vec![]; + if let Some(symbol_ref) = self.get_type_symbol(ty, module_info) { + if let Some(symbol) = self.get_symbol(symbol_ref) { + result = symbol.get_all_attributes(self, module_info); + } + } + result + } + TypeKind::List(_) => vec![], + TypeKind::Dict(_) => vec![], + TypeKind::NumberMultiplier(_) => vec![], + TypeKind::Function(_) => vec![], + TypeKind::Union(tys) => { + let mut result = vec![]; + for ty in tys.iter() { + result.append(&mut self.get_type_all_attribute(ty, name, module_info)); + } + result + } + TypeKind::Schema(_) => { + let mut result = vec![]; + if let Some(symbol_ref) = self.get_type_symbol(ty, module_info) { + if let Some(symbol) = self.get_symbol(symbol_ref) { + result = symbol.get_all_attributes(self, module_info); + } + } + result + } + TypeKind::Module(_) => { + let mut result = vec![]; + if let Some(symbol_ref) = self.get_type_symbol(ty, module_info) { + if let Some(symbol) = self.get_symbol(symbol_ref) { + result = symbol.get_all_attributes(self, module_info); + } + } + result + } + TypeKind::Named(_) => { + let mut result = vec![]; + if let Some(symbol_ref) = self.get_type_symbol(ty, module_info) { + if let Some(symbol) = self.get_symbol(symbol_ref) { + result = symbol.get_all_attributes(self, module_info); + } + } + result + } + } + } + + pub fn get_type_attribute( + &self, + ty: &Type, + name: &str, + module_info: Option<&ModuleInfo>, + ) -> Option { + match &ty.kind { + TypeKind::None => None, + TypeKind::Any => None, + TypeKind::Void => None, + TypeKind::Bool => None, + TypeKind::BoolLit(_) => None, + TypeKind::Int => None, + TypeKind::IntLit(_) => None, + TypeKind::Float => None, + TypeKind::FloatLit(_) => None, + TypeKind::Str => self + .get_symbol(self.get_type_symbol(ty, module_info)?)? + .get_attribute(name, self, module_info), + TypeKind::StrLit(_) => self + .get_symbol(self.get_type_symbol(ty, module_info)?)? + .get_attribute(name, self, module_info), + TypeKind::List(_) => None, + TypeKind::Dict(_) => None, + TypeKind::NumberMultiplier(_) => None, + TypeKind::Function(_) => None, + TypeKind::Union(tys) => { + for ty in tys.iter() { + if let Some(symbol_ref) = self.get_type_attribute(ty, name, module_info) { + return Some(symbol_ref); + } + } + None + } + TypeKind::Schema(_) => self + .get_symbol(self.get_type_symbol(ty, module_info)?)? + .get_attribute(name, self, module_info), + TypeKind::Module(_) => self + .get_symbol(self.get_type_symbol(ty, module_info)?)? + .get_attribute(name, self, module_info), + TypeKind::Named(_) => self + .get_symbol(self.get_type_symbol(ty, module_info)?)? + .get_attribute(name, self, module_info), + } + } + + pub fn get_symbol_by_fully_qualified_name(&self, fqn: &str) -> Option { + self.symbols_info.fully_qualified_name_map.get(fqn).cloned() + } + + pub fn get_fully_qualified_name(&self, symbol_ref: SymbolRef) -> Option { + match symbol_ref.get_kind() { + SymbolKind::Unresolved => None, + _ => { + let symbol = self.get_symbol(symbol_ref)?; + let owner = symbol.get_owner(); + if let Some(owner) = owner { + Some(self.get_fully_qualified_name(owner)? + "." + &symbol.get_name()) + } else { + Some(symbol.get_name()) + } + } + } + } + + pub fn build_fully_qualified_name_map(&mut self) { + for (id, _) in self.packages.iter() { + let symbol_ref = SymbolRef { + id, + kind: SymbolKind::Package, + }; + self.symbols_info.fully_qualified_name_map.insert( + self.get_fully_qualified_name(symbol_ref).unwrap(), + symbol_ref, + ); + } + + for (id, _) in self.schemas.iter() { + let symbol_ref = SymbolRef { + id, + kind: SymbolKind::Schema, + }; + self.symbols_info.fully_qualified_name_map.insert( + self.get_fully_qualified_name(symbol_ref).unwrap(), + symbol_ref, + ); + } + + for (id, _) in self.type_aliases.iter() { + let symbol_ref = SymbolRef { + id, + kind: SymbolKind::TypeAlias, + }; + self.symbols_info.fully_qualified_name_map.insert( + self.get_fully_qualified_name(symbol_ref).unwrap(), + symbol_ref, + ); + } + + for (id, _) in self.attributes.iter() { + let symbol_ref = SymbolRef { + id, + kind: SymbolKind::Attribute, + }; + self.symbols_info.fully_qualified_name_map.insert( + self.get_fully_qualified_name(symbol_ref).unwrap(), + symbol_ref, + ); + } + + for (id, _) in self.rules.iter() { + let symbol_ref = SymbolRef { + id, + kind: SymbolKind::Rule, + }; + self.symbols_info.fully_qualified_name_map.insert( + self.get_fully_qualified_name(symbol_ref).unwrap(), + symbol_ref, + ); + } + + for (id, _) in self.values.iter() { + let symbol_ref = SymbolRef { + id, + kind: SymbolKind::Value, + }; + self.symbols_info.fully_qualified_name_map.insert( + self.get_fully_qualified_name(symbol_ref).unwrap(), + symbol_ref, + ); + } + + for (id, _) in self.functions.iter() { + let symbol_ref = SymbolRef { + id, + kind: SymbolKind::Function, + }; + self.symbols_info.fully_qualified_name_map.insert( + self.get_fully_qualified_name(symbol_ref).unwrap(), + symbol_ref, + ); + } + } + + pub fn insert_package_symbol(&mut self, symbol_ref: SymbolRef, pkg_name: String) { + if !self.symbols_info.pkg_symbol_map.contains_key(&pkg_name) { + self.symbols_info + .pkg_symbol_map + .insert(pkg_name.clone(), IndexSet::default()); + } + + self.symbols_info + .pkg_symbol_map + .get_mut(&pkg_name) + .unwrap() + .insert(symbol_ref); + } + + pub fn alloc_package_symbol(&mut self, pkg: PackageSymbol, pkg_name: String) -> SymbolRef { + let symbol_id = self.packages.insert(pkg); + let symbol_ref = SymbolRef { + id: symbol_id, + kind: SymbolKind::Package, + }; + self.packages.get_mut(symbol_id).unwrap().id = Some(symbol_ref); + self.insert_package_symbol(symbol_ref, pkg_name); + symbol_ref + } + + pub fn alloc_schema_symbol( + &mut self, + schema: SchemaSymbol, + node_key: NodeKey, + pkg_name: String, + ) -> SymbolRef { + self.symbols_info.symbol_pos_set.insert(schema.end.clone()); + let symbol_id = self.schemas.insert(schema); + let symbol_ref = SymbolRef { + id: symbol_id, + kind: SymbolKind::Schema, + }; + self.symbols_info + .node_symbol_map + .insert(node_key.clone(), symbol_ref); + self.symbols_info + .symbol_node_map + .insert(symbol_ref, node_key); + self.schemas.get_mut(symbol_id).unwrap().id = Some(symbol_ref); + self.insert_package_symbol(symbol_ref, pkg_name); + symbol_ref + } + + pub fn alloc_unresolved_symbol( + &mut self, + unresolved: UnresolvedSymbol, + node_key: NodeKey, + pkg_name: String, + ) -> SymbolRef { + self.symbols_info + .symbol_pos_set + .insert(unresolved.end.clone()); + let symbol_id = self.unresolved.insert(unresolved); + let symbol_ref = SymbolRef { + id: symbol_id, + kind: SymbolKind::Unresolved, + }; + self.symbols_info + .node_symbol_map + .insert(node_key.clone(), symbol_ref); + self.symbols_info + .symbol_node_map + .insert(symbol_ref, node_key); + self.unresolved.get_mut(symbol_id).unwrap().id = Some(symbol_ref); + self.insert_package_symbol(symbol_ref, pkg_name); + symbol_ref + } + + pub fn alloc_type_alias_symbol( + &mut self, + alias: TypeAliasSymbol, + node_key: NodeKey, + pkg_name: String, + ) -> SymbolRef { + self.symbols_info.symbol_pos_set.insert(alias.end.clone()); + let symbol_id = self.type_aliases.insert(alias); + let symbol_ref = SymbolRef { + id: symbol_id, + kind: SymbolKind::TypeAlias, + }; + self.symbols_info + .node_symbol_map + .insert(node_key.clone(), symbol_ref); + self.symbols_info + .symbol_node_map + .insert(symbol_ref, node_key); + self.type_aliases.get_mut(symbol_id).unwrap().id = Some(symbol_ref); + self.insert_package_symbol(symbol_ref, pkg_name); + symbol_ref + } + + pub fn alloc_rule_symbol( + &mut self, + rule: RuleSymbol, + node_key: NodeKey, + pkg_name: String, + ) -> SymbolRef { + self.symbols_info.symbol_pos_set.insert(rule.end.clone()); + let symbol_id = self.rules.insert(rule); + let symbol_ref = SymbolRef { + id: symbol_id, + kind: SymbolKind::Rule, + }; + self.symbols_info + .node_symbol_map + .insert(node_key.clone(), symbol_ref); + self.symbols_info + .symbol_node_map + .insert(symbol_ref, node_key); + self.rules.get_mut(symbol_id).unwrap().id = Some(symbol_ref); + self.insert_package_symbol(symbol_ref, pkg_name); + symbol_ref + } + + pub fn alloc_attribute_symbol( + &mut self, + attribute: AttributeSymbol, + node_key: NodeKey, + pkg_name: String, + ) -> SymbolRef { + self.symbols_info + .symbol_pos_set + .insert(attribute.end.clone()); + let symbol_id = self.attributes.insert(attribute); + let symbol_ref = SymbolRef { + id: symbol_id, + kind: SymbolKind::Attribute, + }; + self.symbols_info + .node_symbol_map + .insert(node_key.clone(), symbol_ref); + self.symbols_info + .symbol_node_map + .insert(symbol_ref, node_key); + self.attributes.get_mut(symbol_id).unwrap().id = Some(symbol_ref); + self.insert_package_symbol(symbol_ref, pkg_name); + symbol_ref + } + + pub fn alloc_value_symbol( + &mut self, + value: ValueSymbol, + node_key: NodeKey, + pkg_name: String, + ) -> SymbolRef { + self.symbols_info.symbol_pos_set.insert(value.end.clone()); + let symbol_id = self.values.insert(value); + let symbol_ref = SymbolRef { + id: symbol_id, + kind: SymbolKind::Value, + }; + self.symbols_info + .node_symbol_map + .insert(node_key.clone(), symbol_ref); + self.symbols_info + .symbol_node_map + .insert(symbol_ref, node_key); + self.values.get_mut(symbol_id).unwrap().id = Some(symbol_ref); + self.insert_package_symbol(symbol_ref, pkg_name); + symbol_ref + } + + pub fn alloc_expression_symbol( + &mut self, + expr: ExpressionSymbol, + node_key: NodeKey, + pkg_name: String, + ) -> Option { + if self.symbols_info.symbol_pos_set.contains(&expr.end) { + return None; + } + self.symbols_info.symbol_pos_set.insert(expr.end.clone()); + let symbol_id = self.exprs.insert(expr); + let symbol_ref = SymbolRef { + id: symbol_id, + kind: SymbolKind::Expression, + }; + self.symbols_info + .node_symbol_map + .insert(node_key.clone(), symbol_ref); + self.symbols_info + .symbol_node_map + .insert(symbol_ref, node_key); + self.exprs.get_mut(symbol_id).unwrap().id = Some(symbol_ref); + self.insert_package_symbol(symbol_ref, pkg_name); + Some(symbol_ref) + } + + pub fn alloc_comment_symbol( + &mut self, + comment: CommentOrDocSymbol, + node_key: NodeKey, + pkg_name: String, + ) -> Option { + let symbol_id = self.comments.insert(comment); + let symbol_ref = SymbolRef { + id: symbol_id, + kind: SymbolKind::Comment, + }; + self.symbols_info + .node_symbol_map + .insert(node_key.clone(), symbol_ref); + self.symbols_info + .symbol_node_map + .insert(symbol_ref, node_key); + self.comments.get_mut(symbol_id).unwrap().id = Some(symbol_ref); + self.insert_package_symbol(symbol_ref, pkg_name); + Some(symbol_ref) + } + + pub fn alloc_decorator_symbol( + &mut self, + decorator: DecoratorSymbol, + node_key: NodeKey, + pkg_name: String, + ) -> Option { + let symbol_id = self.decorators.insert(decorator); + let symbol_ref = SymbolRef { + id: symbol_id, + kind: SymbolKind::Decorator, + }; + self.symbols_info + .node_symbol_map + .insert(node_key.clone(), symbol_ref); + self.symbols_info + .symbol_node_map + .insert(symbol_ref, node_key); + self.decorators.get_mut(symbol_id).unwrap().id = Some(symbol_ref); + self.insert_package_symbol(symbol_ref, pkg_name); + Some(symbol_ref) + } + + pub fn alloc_function_symbol( + &mut self, + func: FunctionSymbol, + node_key: NodeKey, + pkg_name: String, + ) -> SymbolRef { + self.symbols_info.symbol_pos_set.insert(func.end.clone()); + let symbol_id = self.functions.insert(func); + let symbol_ref = SymbolRef { + id: symbol_id, + kind: SymbolKind::Function, + }; + self.symbols_info + .node_symbol_map + .insert(node_key.clone(), symbol_ref); + self.symbols_info + .symbol_node_map + .insert(symbol_ref, node_key); + self.functions.get_mut(symbol_id).unwrap().id = Some(symbol_ref); + self.insert_package_symbol(symbol_ref, pkg_name); + symbol_ref + } + + pub fn alloc_hint(&mut self, hint: SymbolHint, pkg_name: String) { + match self.hints.get_mut(&pkg_name) { + Some(hints) => hints.push(hint), + None => { + self.hints.insert(pkg_name, vec![hint]); + } + } + } + + #[inline] + pub fn get_node_symbol_map(&self) -> &IndexMap { + &self.symbols_info.node_symbol_map + } + + #[inline] + pub fn get_symbol_node_map(&self) -> &IndexMap { + &self.symbols_info.symbol_node_map + } + + #[inline] + pub fn get_fully_qualified_name_map(&self) -> &IndexMap { + &self.symbols_info.fully_qualified_name_map + } + + #[inline] + pub fn get_builtin_symbols(&self) -> &IndexMap { + &self.symbols_info.global_builtin_symbols + } + + pub fn clear_cache(&mut self, invalidate_pkgs: &HashSet) { + let mut to_remove: Vec = Vec::new(); + + for invalidate_pkg in invalidate_pkgs { + if let Some(symbols) = self.symbols_info.pkg_symbol_map.get(invalidate_pkg) { + to_remove.extend(symbols.iter().cloned()); + } + self.hints.remove(invalidate_pkg); + } + for symbol in to_remove { + self.remove_symbol(&symbol); + } + } + + pub fn set_def_and_ref(&mut self, def: SymbolRef, r#ref: SymbolRef) { + self.set_def(def, r#ref); + self.set_ref(def, r#ref); + } + + pub fn set_def(&mut self, def: SymbolRef, r#ref: SymbolRef) { + match r#ref.get_kind() { + SymbolKind::Unresolved => { + self.unresolved.get_mut(r#ref.get_id()).unwrap().def = Some(def) + } + _ => {} + } + } + + pub fn set_ref(&mut self, def: SymbolRef, r#ref: SymbolRef) { + match def.get_kind() { + SymbolKind::Schema => { + self.schemas + .get_mut(def.get_id()) + .unwrap() + .r#ref + .insert(r#ref); + } + + SymbolKind::Attribute => { + self.attributes + .get_mut(def.get_id()) + .unwrap() + .r#ref + .insert(r#ref); + } + SymbolKind::Value => { + self.values + .get_mut(def.get_id()) + .unwrap() + .r#ref + .insert(r#ref); + } + SymbolKind::Function => { + self.functions + .get_mut(def.get_id()) + .unwrap() + .r#ref + .insert(r#ref); + } + SymbolKind::Package => { + self.packages + .get_mut(def.get_id()) + .unwrap() + .r#ref + .insert(r#ref); + } + SymbolKind::TypeAlias => { + self.type_aliases + .get_mut(def.get_id()) + .unwrap() + .r#ref + .insert(r#ref); + } + SymbolKind::Rule => { + self.rules + .get_mut(def.get_id()) + .unwrap() + .r#ref + .insert(r#ref); + } + _ => {} + }; + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize)] +pub enum SymbolKind { + Schema, + Attribute, + Value, + Function, + Package, + TypeAlias, + Unresolved, + Rule, + Expression, + Comment, + Decorator, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct SymbolRef { + pub(crate) id: generational_arena::Index, + pub(crate) kind: SymbolKind, +} + +impl Serialize for SymbolRef { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + let (index, generation) = self.id.into_raw_parts(); + let data = SerializableSymbolRef { + i: index as u64, + g: generation, + kind: self.kind.clone(), + }; + data.serialize(serializer) + } +} + +#[derive(Debug, Clone, Serialize)] + +struct SerializableSymbolRef { + i: u64, + g: u64, + kind: SymbolKind, +} + +impl SymbolRef { + #[inline] + pub fn get_kind(&self) -> SymbolKind { + self.kind + } + #[inline] + pub fn get_id(&self) -> generational_arena::Index { + self.id + } +} +#[allow(unused)] +#[derive(Debug, Clone)] +pub struct SchemaSymbol { + pub(crate) id: Option, + pub(crate) name: String, + pub(crate) start: Position, + pub(crate) end: Position, + pub(crate) owner: SymbolRef, + pub(crate) sema_info: SymbolSemanticInfo, + pub(crate) r#ref: HashSet, + + pub(crate) parent_schema: Option, + pub(crate) for_host: Option, + pub(crate) mixins: Vec, + pub(crate) attributes: IndexMap, +} + +impl Symbol for SchemaSymbol { + type SymbolData = SymbolData; + type SemanticInfo = SymbolSemanticInfo; + type SymbolHint = SymbolHint; + + fn is_global(&self) -> bool { + true + } + fn get_range(&self) -> Range { + (self.start.clone(), self.end.clone()) + } + + fn get_owner(&self) -> Option { + Some(self.owner) + } + + fn get_definition(&self) -> Option { + self.id.clone() + } + + fn get_name(&self) -> String { + self.name.clone() + } + + fn get_id(&self) -> Option { + self.id.clone() + } + + fn get_attribute( + &self, + name: &str, + data: &Self::SymbolData, + module_info: Option<&ModuleInfo>, + ) -> Option { + match self.attributes.get(name) { + Some(attribute) => Some(*attribute), + None => { + if let Some(for_host) = self.for_host { + if let Some(attribute) = + data.get_symbol(for_host)? + .get_attribute(name, data, module_info) + { + return Some(attribute); + } + } + + for mixin in self.mixins.iter() { + if let Some(attribute) = + data.get_symbol(*mixin)? + .get_attribute(name, data, module_info) + { + return Some(attribute); + } + } + + if let Some(_) = self.parent_schema { + let mut parents = vec![]; + parents.push(self.id.unwrap()); + self.get_parents(data, &mut parents); + if parents.len() > 1 { + for parent_schema in &parents[1..] { + if let Some(parent_schema) = data.get_schema_symbol(*parent_schema) { + let parent_attr = parent_schema.get_self_attr(data, module_info); + for attr in parent_attr { + if let Some(attribute) = data.get_symbol(attr) { + if attribute.get_name() == name { + return Some(attr); + } + } + } + } + } + } + } + None + } + } + } + + fn get_all_attributes( + &self, + data: &Self::SymbolData, + module_info: Option<&ModuleInfo>, + ) -> Vec { + let mut result = self.get_self_attr(data, module_info); + if let Some(_) = self.parent_schema { + let mut parents = vec![]; + parents.push(self.id.unwrap()); + self.get_parents(data, &mut parents); + if parents.len() > 1 { + for parent in &parents[1..] { + if let Some(schema_symbol) = data.get_schema_symbol(*parent) { + result.append(&mut schema_symbol.get_self_attr(data, module_info)) + } + } + } + } + result + } + + fn has_attribute( + &self, + name: &str, + data: &Self::SymbolData, + module_info: Option<&ModuleInfo>, + ) -> bool { + self.get_attribute(name, data, module_info).is_some() + } + + fn simple_dump(&self) -> String { + let mut output = "{\n".to_string(); + output.push_str("\"kind\": \"SchemaSymbol\",\n"); + output.push_str(&format!("\"name\":\"{}\",\n", self.name)); + output.push_str(&format!( + "\"range\": \"{}:{}", + self.start.filename, self.start.line + )); + if let Some(start_col) = self.start.column { + output.push_str(&format!(":{}", start_col)); + } + + output.push_str(&format!(" to {}", self.end.line)); + if let Some(end_col) = self.end.column { + output.push_str(&format!(":{}", end_col)); + } + output.push_str("\"\n}"); + output + } + + fn full_dump(&self, data: &Self::SymbolData) -> Option { + let mut output = format!("{{\n\"simple_info\": {},\n", self.simple_dump()); + output.push_str("\"additional_info\": {\n"); + let owner_symbol = data.get_symbol(self.owner)?; + output.push_str(&format!("\"owner\": {},\n", owner_symbol.simple_dump())); + if let Some(parent_schema) = self.parent_schema.as_ref() { + let parent_schema_symbol = data.get_symbol(*parent_schema)?; + output.push_str(&format!( + "\"parent_schema\": {},\n", + parent_schema_symbol.simple_dump() + )); + } + if let Some(parent_schema) = self.for_host.as_ref() { + let host_symbol = data.get_symbol(*parent_schema)?; + output.push_str(&format!("\"for_host\": {},\n", host_symbol.simple_dump())); + } + output.push_str("\"mixins\": [\n"); + for (index, mixin) in self.mixins.iter().enumerate() { + let mixin_symbol = data.get_symbol(*mixin)?; + output.push_str(&format!("{}", mixin_symbol.simple_dump())); + if index + 1 < self.mixins.len() { + output.push_str(",\n") + } + } + output.push_str("\n],\n"); + output.push_str("\"attributes\": {\n"); + for (index, (key, attribute)) in self.attributes.iter().enumerate() { + let attribute_symbol = data.get_symbol(*attribute)?; + output.push_str(&format!("\"{}\": {}", key, attribute_symbol.simple_dump())); + if index + 1 < self.attributes.len() { + output.push_str(",\n") + } + } + output.push_str("\n}\n}\n}"); + Some(output) + } + + fn get_sema_info(&self) -> &Self::SemanticInfo { + &self.sema_info + } + + fn get_references(&self) -> HashSet { + self.r#ref.clone() + } +} + +impl SchemaSymbol { + pub fn new(name: String, start: Position, end: Position, owner: SymbolRef) -> Self { + Self { + id: None, + name, + start, + end, + owner, + parent_schema: None, + for_host: None, + sema_info: SymbolSemanticInfo::default(), + mixins: Vec::default(), + attributes: IndexMap::default(), + r#ref: HashSet::default(), + } + } + + pub fn get_parents(&self, data: &SymbolData, parents: &mut Vec) { + if let Some(parent_schema_ref) = self.parent_schema { + if let Some(parent_schema) = data.get_symbol(parent_schema_ref) { + if let Some(schema_def) = parent_schema.get_definition() { + if let Some(parent_schema) = data.get_schema_symbol(schema_def) { + // circular reference + if !parents.contains(&schema_def) { + parents.push(schema_def); + parent_schema.get_parents(data, parents); + } + } + } + } + } + } + + pub fn get_protocol_and_mixin_attrs( + &self, + data: &SymbolData, + module_info: Option<&ModuleInfo>, + ) -> Vec { + let mut result = vec![]; + if let Some(for_host) = self.for_host { + if let Some(for_host) = data.get_symbol(for_host) { + result.append(&mut for_host.get_all_attributes(data, module_info)) + } + } + for mixin in self.mixins.iter() { + if let Some(mixin) = data.get_symbol(*mixin) { + result.append(&mut mixin.get_all_attributes(data, module_info)) + } + } + + result + } + + pub fn get_self_attr( + &self, + data: &SymbolData, + module_info: Option<&ModuleInfo>, + ) -> Vec { + let mut result = vec![]; + for attribute in self.attributes.values() { + result.push(*attribute); + } + result.extend(self.get_protocol_and_mixin_attrs(data, module_info)); + result + } +} + +#[allow(unused)] +#[derive(Debug, Clone)] +pub struct ValueSymbol { + pub(crate) id: Option, + pub(crate) name: String, + pub(crate) start: Position, + pub(crate) end: Position, + pub(crate) owner: Option, + pub(crate) sema_info: SymbolSemanticInfo, + pub(crate) r#ref: HashSet, + pub(crate) is_global: bool, +} + +impl Symbol for ValueSymbol { + type SymbolData = SymbolData; + type SemanticInfo = SymbolSemanticInfo; + type SymbolHint = SymbolHint; + + fn is_global(&self) -> bool { + self.is_global + } + + fn get_range(&self) -> Range { + (self.start.clone(), self.end.clone()) + } + + fn get_owner(&self) -> Option { + self.owner.clone() + } + + fn get_definition(&self) -> Option { + self.id.clone() + } + + fn get_name(&self) -> String { + self.name.clone() + } + + fn get_id(&self) -> Option { + self.id.clone() + } + + fn get_attribute( + &self, + name: &str, + data: &Self::SymbolData, + module_info: Option<&ModuleInfo>, + ) -> Option { + data.get_type_attribute(self.sema_info.ty.as_ref()?, name, module_info) + } + + fn get_all_attributes( + &self, + data: &Self::SymbolData, + module_info: Option<&ModuleInfo>, + ) -> Vec { + let mut result = vec![]; + if let Some(ty) = self.sema_info.ty.as_ref() { + if let Some(symbol_ref) = data.get_type_symbol(ty, module_info) { + if let Some(symbol) = data.get_symbol(symbol_ref) { + result.append(&mut symbol.get_all_attributes(data, module_info)) + } + } + } + + result + } + + fn has_attribute( + &self, + name: &str, + data: &Self::SymbolData, + module_info: Option<&ModuleInfo>, + ) -> bool { + self.get_attribute(name, data, module_info).is_some() + } + + fn simple_dump(&self) -> String { + let mut output = "{\n".to_string(); + output.push_str("\"kind\": \"ValueSymbol\",\n"); + output.push_str(&format!("\"name\":\"{}\",\n", self.name)); + output.push_str(&format!( + "\"range\": \"{}:{}", + self.start.filename, self.start.line + )); + if let Some(start_col) = self.start.column { + output.push_str(&format!(":{}", start_col)); + } + + output.push_str(&format!(" to {}", self.end.line)); + if let Some(end_col) = self.end.column { + output.push_str(&format!(":{}", end_col)); + } + output.push_str("\"\n}"); + output + } + + fn full_dump(&self, data: &Self::SymbolData) -> Option { + let mut output = format!("{{\n\"simple_info\": {},\n", self.simple_dump()); + output.push_str("\"additional_info\": {\n"); + if let Some(owner) = self.owner.as_ref() { + let owner_symbol = data.get_symbol(*owner)?; + output.push_str(&format!("\"owner\": {}\n", owner_symbol.simple_dump())); + } + output.push_str("\n}\n}"); + Some(output) + } + + fn get_sema_info(&self) -> &Self::SemanticInfo { + &self.sema_info + } + + fn get_references(&self) -> HashSet { + self.r#ref.clone() + } +} + +impl ValueSymbol { + pub fn new( + name: String, + start: Position, + end: Position, + owner: Option, + is_global: bool, + ) -> Self { + Self { + id: None, + name, + start, + end, + owner, + sema_info: SymbolSemanticInfo::default(), + is_global, + r#ref: HashSet::default(), + } + } +} + +#[allow(unused)] +#[derive(Debug, Clone)] +pub struct AttributeSymbol { + pub(crate) id: Option, + pub(crate) name: String, + pub(crate) start: Position, + pub(crate) end: Position, + pub(crate) owner: SymbolRef, + pub(crate) sema_info: SymbolSemanticInfo, + pub(crate) is_optional: bool, + pub(crate) r#ref: HashSet, + pub(crate) default_value: Option, +} + +impl Symbol for AttributeSymbol { + type SymbolData = SymbolData; + type SemanticInfo = SymbolSemanticInfo; + type SymbolHint = SymbolHint; + + fn is_global(&self) -> bool { + true + } + fn get_range(&self) -> Range { + (self.start.clone(), self.end.clone()) + } + + fn get_owner(&self) -> Option { + Some(self.owner) + } + + fn get_definition(&self) -> Option { + self.id.clone() + } + + fn get_name(&self) -> String { + self.name.clone() + } + + fn get_id(&self) -> Option { + self.id.clone() + } + + fn get_attribute( + &self, + name: &str, + data: &Self::SymbolData, + module_info: Option<&ModuleInfo>, + ) -> Option { + let ty = self.sema_info.ty.as_ref()?; + data.get_type_attribute(ty, name, module_info) + } + + fn get_all_attributes( + &self, + data: &Self::SymbolData, + module_info: Option<&ModuleInfo>, + ) -> Vec { + let mut result = vec![]; + if module_info.is_none() { + return result; + } + if let Some(ty) = self.sema_info.ty.as_ref() { + if let Some(symbol_ref) = data.get_type_symbol(ty, module_info) { + if let Some(symbol) = data.get_symbol(symbol_ref) { + result.append(&mut symbol.get_all_attributes(data, module_info)) + } + } + } + + result + } + + fn has_attribute( + &self, + name: &str, + data: &Self::SymbolData, + module_info: Option<&ModuleInfo>, + ) -> bool { + self.get_attribute(name, data, module_info).is_some() + } + + fn simple_dump(&self) -> String { + let mut output = "{\n".to_string(); + output.push_str("\"kind\": \"AttributeSymbol\",\n"); + output.push_str(&format!("\"name\":\"{}\",\n", self.name)); + output.push_str(&format!( + "\"range\": \"{}:{}", + self.start.filename, self.start.line + )); + if let Some(start_col) = self.start.column { + output.push_str(&format!(":{}", start_col)); + } + + output.push_str(&format!(" to {}", self.end.line)); + if let Some(end_col) = self.end.column { + output.push_str(&format!(":{}", end_col)); + } + output.push_str("\"\n}"); + output + } + + fn full_dump(&self, data: &Self::SymbolData) -> Option { + let mut output = format!("{{\n\"simple_info\": {},\n", self.simple_dump()); + output.push_str("\"additional_info\": {\n"); + let owner_symbol = data.get_symbol(self.owner)?; + output.push_str(&format!("\"owner\": {}\n", owner_symbol.simple_dump())); + output.push_str("\n}\n}"); + Some(output) + } + + fn get_sema_info(&self) -> &Self::SemanticInfo { + &self.sema_info + } + + fn get_references(&self) -> HashSet { + self.r#ref.clone() + } +} + +impl AttributeSymbol { + pub fn new( + name: String, + start: Position, + end: Position, + owner: SymbolRef, + is_optional: bool, + default_value: Option, + ) -> Self { + Self { + id: None, + name, + start, + end, + sema_info: SymbolSemanticInfo::default(), + owner, + is_optional, + r#ref: HashSet::default(), + default_value, + } + } + + pub fn is_optional(&self) -> bool { + self.is_optional + } + + pub fn get_default_value(&self) -> Option { + self.default_value.clone() + } +} +#[allow(unused)] +#[derive(Debug, Clone)] +pub struct PackageSymbol { + pub(crate) id: Option, + pub(crate) name: String, + pub(crate) members: IndexMap, + pub(crate) start: Position, + pub(crate) end: Position, + pub(crate) sema_info: SymbolSemanticInfo, + pub(crate) r#ref: HashSet, +} + +impl Symbol for PackageSymbol { + type SymbolData = SymbolData; + type SemanticInfo = SymbolSemanticInfo; + type SymbolHint = SymbolHint; + + fn is_global(&self) -> bool { + true + } + fn get_range(&self) -> Range { + (self.start.clone(), self.end.clone()) + } + + fn get_owner(&self) -> Option { + None + } + + fn get_definition(&self) -> Option { + self.id.clone() + } + + fn get_name(&self) -> String { + self.name.clone() + } + + fn get_id(&self) -> Option { + self.id.clone() + } + + fn get_attribute( + &self, + name: &str, + _data: &Self::SymbolData, + _module_info: Option<&ModuleInfo>, + ) -> Option { + self.members.get(name).cloned() + } + + fn get_all_attributes( + &self, + _data: &Self::SymbolData, + _module_info: Option<&ModuleInfo>, + ) -> Vec { + let mut result = vec![]; + for member in self.members.values() { + result.push(*member); + } + result + } + + fn has_attribute( + &self, + name: &str, + _data: &Self::SymbolData, + _module_info: Option<&ModuleInfo>, + ) -> bool { + self.members.contains_key(name) + } + + fn simple_dump(&self) -> String { + let mut output = "{\n".to_string(); + output.push_str("\"kind\": \"PackageSymbol\",\n"); + output.push_str(&format!("\"name\":\"{}\",\n", self.name)); + output.push_str(&format!( + "\"range\": \"{}:{}", + self.start.filename, self.start.line + )); + if let Some(start_col) = self.start.column { + output.push_str(&format!(":{}", start_col)); + } + + output.push_str(&format!(" to {}", self.end.line)); + if let Some(end_col) = self.end.column { + output.push_str(&format!(":{}", end_col)); + } + output.push_str("\"\n}"); + output + } + + fn full_dump(&self, data: &Self::SymbolData) -> Option { + let mut output = format!("{{\n\"simple_info\": {},\n", self.simple_dump()); + output.push_str("\"additional_info\": {\n"); + output.push_str("\"members\": {\n"); + for (index, (key, member)) in self.members.iter().enumerate() { + let member_symbol = data.get_symbol(*member)?; + output.push_str(&format!("\"{}\": {}", key, member_symbol.simple_dump())); + if index + 1 < self.members.len() { + output.push_str(",\n"); + } + } + output.push_str("\n}\n}\n}"); + Some(output) + } + + fn get_sema_info(&self) -> &Self::SemanticInfo { + &self.sema_info + } + + fn get_references(&self) -> HashSet { + self.r#ref.clone() + } +} + +impl PackageSymbol { + pub fn new(name: String, start: Position, end: Position) -> Self { + Self { + id: None, + name, + start, + end, + sema_info: SymbolSemanticInfo::default(), + members: IndexMap::default(), + r#ref: HashSet::default(), + } + } +} +#[allow(unused)] +#[derive(Debug, Clone)] +pub struct TypeAliasSymbol { + pub(crate) id: Option, + pub(crate) name: String, + pub(crate) start: Position, + pub(crate) end: Position, + pub(crate) owner: SymbolRef, + pub(crate) sema_info: SymbolSemanticInfo, + pub(crate) r#ref: HashSet, +} + +impl Symbol for TypeAliasSymbol { + type SymbolData = SymbolData; + type SemanticInfo = SymbolSemanticInfo; + type SymbolHint = SymbolHint; + + fn is_global(&self) -> bool { + true + } + fn get_range(&self) -> Range { + (self.start.clone(), self.end.clone()) + } + + fn get_owner(&self) -> Option { + Some(self.owner) + } + + fn get_definition(&self) -> Option { + self.id.clone() + } + + fn get_name(&self) -> String { + self.name.clone() + } + + fn get_id(&self) -> Option { + self.id.clone() + } + + fn get_attribute( + &self, + name: &str, + data: &Self::SymbolData, + module_info: Option<&ModuleInfo>, + ) -> Option { + let ty = self.sema_info.ty.as_ref()?; + data.get_type_attribute(ty, name, module_info) + } + + fn get_all_attributes( + &self, + data: &Self::SymbolData, + module_info: Option<&ModuleInfo>, + ) -> Vec { + let mut result = vec![]; + if let Some(ty) = self.sema_info.ty.as_ref() { + if let Some(symbol_ref) = data.get_type_symbol(ty, module_info) { + if let Some(symbol) = data.get_symbol(symbol_ref) { + result.append(&mut symbol.get_all_attributes(data, module_info)) + } + } + } + result + } + + fn has_attribute( + &self, + name: &str, + data: &Self::SymbolData, + module_info: Option<&ModuleInfo>, + ) -> bool { + self.get_attribute(name, data, module_info).is_some() + } + + fn simple_dump(&self) -> String { + let mut output = "{\n".to_string(); + output.push_str("\"kind\": \"TypeAliasSymbol\",\n"); + output.push_str(&format!("\"name\":\"{}\",\n", self.name)); + output.push_str(&format!( + "\"range\": \"{}:{}", + self.start.filename, self.start.line + )); + if let Some(start_col) = self.start.column { + output.push_str(&format!(":{}", start_col)); + } + + output.push_str(&format!(" to {}", self.end.line)); + if let Some(end_col) = self.end.column { + output.push_str(&format!(":{}", end_col)); + } + output.push_str("\"\n}"); + output + } + + fn full_dump(&self, data: &Self::SymbolData) -> Option { + let mut output = format!("{{\n\"simple_info\": {},\n", self.simple_dump()); + output.push_str("\"additional_info\": {\n"); + let owner_symbol = data.get_symbol(self.owner)?; + output.push_str(&format!( + "\"owner\": {}\n}}\n}}", + owner_symbol.simple_dump() + )); + Some(output) + } + + fn get_sema_info(&self) -> &Self::SemanticInfo { + &self.sema_info + } + + fn get_references(&self) -> HashSet { + self.r#ref.clone() + } +} + +impl TypeAliasSymbol { + pub fn new(name: String, start: Position, end: Position, owner: SymbolRef) -> Self { + Self { + id: None, + name, + start, + end, + sema_info: SymbolSemanticInfo::default(), + owner, + r#ref: HashSet::default(), + } + } +} +#[allow(unused)] +#[derive(Debug, Clone)] +pub struct RuleSymbol { + pub(crate) id: Option, + pub(crate) name: String, + pub(crate) start: Position, + pub(crate) end: Position, + pub(crate) owner: SymbolRef, + pub(crate) sema_info: SymbolSemanticInfo, + + pub(crate) parent_rules: Vec, + pub(crate) for_host: Option, + pub(crate) r#ref: HashSet, +} + +impl Symbol for RuleSymbol { + type SymbolData = SymbolData; + type SemanticInfo = SymbolSemanticInfo; + type SymbolHint = SymbolHint; + + fn is_global(&self) -> bool { + true + } + fn get_range(&self) -> Range { + (self.start.clone(), self.end.clone()) + } + + fn get_owner(&self) -> Option { + Some(self.owner) + } + + fn get_definition(&self) -> Option { + self.id.clone() + } + + fn get_name(&self) -> String { + self.name.clone() + } + + fn get_id(&self) -> Option { + self.id.clone() + } + + fn get_attribute( + &self, + _name: &str, + _data: &Self::SymbolData, + _module_info: Option<&ModuleInfo>, + ) -> Option { + None + } + + fn get_all_attributes( + &self, + _data: &Self::SymbolData, + _module_info: Option<&ModuleInfo>, + ) -> Vec { + vec![] + } + + fn has_attribute( + &self, + _name: &str, + _data: &Self::SymbolData, + _module_info: Option<&ModuleInfo>, + ) -> bool { + false + } + + fn simple_dump(&self) -> String { + let mut output = "{\n".to_string(); + output.push_str("\"kind\": \"RuleSymbol\",\n"); + output.push_str(&format!("\"name\":\"{}\",\n", self.name)); + output.push_str(&format!( + "\"range\": \"{}:{}", + self.start.filename, self.start.line + )); + if let Some(start_col) = self.start.column { + output.push_str(&format!(":{}", start_col)); + } + + output.push_str(&format!(" to {}", self.end.line)); + if let Some(end_col) = self.end.column { + output.push_str(&format!(":{}", end_col)); + } + output.push_str("\"\n}"); + output + } + + fn full_dump(&self, data: &Self::SymbolData) -> Option { + let mut output = format!("{{\n\"simple_info\": {},\n", self.simple_dump()); + output.push_str("\"additional_info\": {\n"); + let owner_symbol = data.get_symbol(self.owner)?; + output.push_str(&format!("\"owner\": {},\n", owner_symbol.simple_dump())); + + if let Some(parent_schema) = self.for_host.as_ref() { + let host_symbol = data.get_symbol(*parent_schema)?; + output.push_str(&format!("\"for_host\": {},\n", host_symbol.simple_dump())); + } + output.push_str("\"parent_rules\": [\n"); + for (index, parent_rule) in self.parent_rules.iter().enumerate() { + let parent_symbol = data.get_symbol(*parent_rule)?; + output.push_str(&format!("{}", parent_symbol.simple_dump())); + if index + 1 < self.parent_rules.len() { + output.push_str(",\n") + } + } + output.push_str("\n]\n}\n}"); + + Some(output) + } + + fn get_sema_info(&self) -> &Self::SemanticInfo { + &self.sema_info + } + + fn get_references(&self) -> HashSet { + self.r#ref.clone() + } +} + +impl RuleSymbol { + pub fn new(name: String, start: Position, end: Position, owner: SymbolRef) -> Self { + Self { + id: None, + name, + start, + end, + owner, + sema_info: SymbolSemanticInfo::default(), + parent_rules: vec![], + for_host: None, + r#ref: HashSet::default(), + } + } +} +#[allow(unused)] +#[derive(Debug, Clone)] +pub struct UnresolvedSymbol { + pub(crate) id: Option, + pub(crate) def: Option, + pub(crate) name: String, + pub(crate) start: Position, + pub(crate) end: Position, + pub(crate) owner: Option, + pub(crate) sema_info: SymbolSemanticInfo, + pub(crate) is_type: bool, + pub(crate) r#ref: HashSet, +} + +impl Symbol for UnresolvedSymbol { + type SymbolData = SymbolData; + type SemanticInfo = SymbolSemanticInfo; + type SymbolHint = SymbolHint; + + fn is_global(&self) -> bool { + false + } + fn get_range(&self) -> Range { + (self.start.clone(), self.end.clone()) + } + + fn get_owner(&self) -> Option { + self.owner.clone() + } + + fn get_definition(&self) -> Option { + self.def.clone() + } + + fn get_name(&self) -> String { + self.name.clone() + } + + fn get_id(&self) -> Option { + self.id.clone() + } + + fn get_attribute( + &self, + name: &str, + data: &Self::SymbolData, + module_info: Option<&ModuleInfo>, + ) -> Option { + if self.is_type() { + None + } else { + data.get_symbol(self.def?)? + .get_attribute(name, data, module_info) + } + } + + fn get_all_attributes( + &self, + data: &Self::SymbolData, + module_info: Option<&ModuleInfo>, + ) -> Vec { + if !self.is_type() { + if let Some(def) = self.def { + if let Some(def_symbol) = data.get_symbol(def) { + return def_symbol.get_all_attributes(data, module_info); + } + } + } + + vec![] + } + + fn has_attribute( + &self, + name: &str, + data: &Self::SymbolData, + module_info: Option<&ModuleInfo>, + ) -> bool { + self.get_attribute(name, data, module_info).is_some() + } + + fn get_sema_info(&self) -> &Self::SemanticInfo { + &self.sema_info + } + + fn simple_dump(&self) -> String { + let mut output = "{\n".to_string(); + output.push_str("\"kind\": \"UnresolvedSymbol\",\n"); + output.push_str(&format!("\"name\":\"{}\",\n", self.name)); + output.push_str(&format!( + "\"range\": \"{}:{}", + self.start.filename, self.start.line + )); + if let Some(start_col) = self.start.column { + output.push_str(&format!(":{}", start_col)); + } + + output.push_str(&format!(" to {}", self.end.line)); + if let Some(end_col) = self.end.column { + output.push_str(&format!(":{}", end_col)); + } + output.push_str("\"\n}"); + output + } + + fn full_dump(&self, data: &Self::SymbolData) -> Option { + let mut output = format!("{{\n\"simple_info\": {},\n", self.simple_dump()); + output.push_str("\"additional_info\": {\n"); + if let Some(def) = self.def.as_ref() { + let def_symbol = data.get_symbol(*def)?; + output.push_str(&format!("\"def\": {}\n", def_symbol.simple_dump())); + } + output.push_str("\n}\n}"); + Some(output) + } + + fn get_references(&self) -> HashSet { + self.r#ref.clone() + } +} + +impl UnresolvedSymbol { + pub fn new( + name: String, + start: Position, + end: Position, + owner: Option, + is_type: bool, + ) -> Self { + Self { + id: None, + def: None, + name, + start, + end, + sema_info: SymbolSemanticInfo::default(), + owner, + is_type, + r#ref: HashSet::default(), + } + } + + pub fn get_fully_qualified_name(&self, module_info: &ModuleInfo) -> String { + let names: Vec<_> = self.name.split('.').collect(); + let pkg_path = if names.len() == 1 { + kclvm_ast::MAIN_PKG.to_string() + } else { + let pkg_alias = names.first().unwrap(); + let import_info = module_info.get_import_info(*pkg_alias); + match import_info { + Some(info) => info.fully_qualified_name.clone(), + None => kclvm_ast::MAIN_PKG.to_string(), + } + }; + + pkg_path + "." + names.last().unwrap() + } + + pub fn is_type(&self) -> bool { + self.is_type + } +} + +#[derive(Debug, Clone)] +pub struct ExpressionSymbol { + pub(crate) id: Option, + pub(crate) start: Position, + pub(crate) end: Position, + pub(crate) owner: Option, + pub(crate) name: String, + + pub(crate) sema_info: SymbolSemanticInfo, + pub(crate) r#ref: HashSet, +} + +impl Symbol for ExpressionSymbol { + type SymbolData = SymbolData; + type SemanticInfo = SymbolSemanticInfo; + type SymbolHint = SymbolHint; + + fn is_global(&self) -> bool { + false + } + fn get_range(&self) -> Range { + (self.start.clone(), self.end.clone()) + } + + fn get_owner(&self) -> Option { + self.owner.clone() + } + + fn get_definition(&self) -> Option { + self.id + } + + fn get_name(&self) -> String { + self.name.clone() + } + + fn get_id(&self) -> Option { + self.id.clone() + } + + fn get_attribute( + &self, + name: &str, + data: &Self::SymbolData, + module_info: Option<&ModuleInfo>, + ) -> Option { + data.get_type_attribute(self.sema_info.ty.as_ref()?, name, module_info) + } + + fn get_all_attributes( + &self, + data: &Self::SymbolData, + module_info: Option<&ModuleInfo>, + ) -> Vec { + let mut result = vec![]; + if let Some(ty) = self.sema_info.ty.as_ref() { + if let Some(symbol_ref) = data.get_type_symbol(ty, module_info) { + if let Some(symbol) = data.get_symbol(symbol_ref) { + result.append(&mut symbol.get_all_attributes(data, module_info)) + } + } + } + + result + } + + fn has_attribute( + &self, + name: &str, + data: &Self::SymbolData, + module_info: Option<&ModuleInfo>, + ) -> bool { + self.get_attribute(name, data, module_info).is_some() + } + + fn get_sema_info(&self) -> &Self::SemanticInfo { + &self.sema_info + } + + fn simple_dump(&self) -> String { + let mut output = "{\n".to_string(); + output.push_str("\"kind\": \"ExpressionSymbol\",\n"); + output.push_str(&format!( + "\"range\": \"{}:{}", + self.start.filename, self.start.line + )); + if let Some(start_col) = self.start.column { + output.push_str(&format!(":{}", start_col)); + } + + output.push_str(&format!(" to {}", self.end.line)); + if let Some(end_col) = self.end.column { + output.push_str(&format!(":{}", end_col)); + } + output.push_str("\"\n}"); + output + } + + fn full_dump(&self, data: &Self::SymbolData) -> Option { + let mut output = format!("{{\n\"simple_info\": {},\n", self.simple_dump()); + output.push_str("\"additional_info\": {\n"); + if let Some(owner) = self.owner.as_ref() { + let owner_symbol = data.get_symbol(*owner)?; + output.push_str(&format!("\"owner\": {}\n", owner_symbol.simple_dump())); + } + output.push_str("\n}\n}"); + Some(output) + } + + fn get_references(&self) -> HashSet { + self.r#ref.clone() + } +} + +impl ExpressionSymbol { + pub fn new(name: String, start: Position, end: Position, owner: Option) -> Self { + Self { + id: None, + name, + start, + end, + sema_info: SymbolSemanticInfo::default(), + owner, + r#ref: HashSet::default(), + } + } +} + +#[derive(Debug, Clone)] +pub struct CommentOrDocSymbol { + pub(crate) id: Option, + pub(crate) start: Position, + pub(crate) end: Position, + pub(crate) content: String, + pub(crate) sema_info: SymbolSemanticInfo, + pub(crate) r#ref: HashSet, +} + +impl Symbol for CommentOrDocSymbol { + type SymbolData = SymbolData; + type SemanticInfo = SymbolSemanticInfo; + type SymbolHint = SymbolHint; + + fn get_sema_info(&self) -> &Self::SemanticInfo { + &self.sema_info + } + + fn is_global(&self) -> bool { + true + } + + fn get_range(&self) -> Range { + (self.start.clone(), self.end.clone()) + } + + fn get_owner(&self) -> Option { + None + } + + fn get_definition(&self) -> Option { + self.id + } + + fn get_name(&self) -> String { + self.name() + } + + fn get_id(&self) -> Option { + self.id.clone() + } + + fn get_attribute( + &self, + _name: &str, + _data: &Self::SymbolData, + _module_info: Option<&ModuleInfo>, + ) -> Option { + None + } + + fn has_attribute( + &self, + _name: &str, + _data: &Self::SymbolData, + _module_info: Option<&ModuleInfo>, + ) -> bool { + false + } + + fn get_all_attributes( + &self, + _data: &Self::SymbolData, + _module_info: Option<&ModuleInfo>, + ) -> Vec { + vec![] + } + + fn simple_dump(&self) -> String { + let mut output = "{\n".to_string(); + output.push_str("\"kind\": \"CommentSymbol\",\n"); + output.push_str(&format!( + "\"range\": \"{}:{}", + self.start.filename, self.start.line + )); + if let Some(start_col) = self.start.column { + output.push_str(&format!(":{}", start_col)); + } + + output.push_str(&format!(" to {}", self.end.line)); + if let Some(end_col) = self.end.column { + output.push_str(&format!(":{}", end_col)); + } + output.push_str(&format!("content :{}", self.name())); + output.push_str("\"\n}"); + output + } + + fn full_dump(&self, _data: &Self::SymbolData) -> Option { + Some(self.simple_dump()) + } + + fn get_references(&self) -> HashSet { + self.r#ref.clone() + } +} + +impl CommentOrDocSymbol { + pub fn new(start: Position, end: Position, content: String) -> Self { + Self { + id: None, + start, + end, + content, + sema_info: SymbolSemanticInfo::default(), + r#ref: HashSet::default(), + } + } + + pub fn name(&self) -> String { + format!("# {}", self.content) + } +} + +#[derive(Debug, Clone)] +pub struct DecoratorSymbol { + pub(crate) id: Option, + pub(crate) start: Position, + pub(crate) end: Position, + pub(crate) name: String, + pub(crate) sema_info: SymbolSemanticInfo, + pub(crate) r#ref: HashSet, +} + +impl Symbol for DecoratorSymbol { + type SymbolData = SymbolData; + type SemanticInfo = SymbolSemanticInfo; + type SymbolHint = SymbolHint; + + fn get_sema_info(&self) -> &Self::SemanticInfo { + &self.sema_info + } + + fn is_global(&self) -> bool { + true + } + + fn get_range(&self) -> Range { + (self.start.clone(), self.end.clone()) + } + + fn get_owner(&self) -> Option { + None + } + + fn get_definition(&self) -> Option { + self.id + } + + fn get_name(&self) -> String { + self.name() + } + + fn get_id(&self) -> Option { + self.id.clone() + } + + fn get_attribute( + &self, + _name: &str, + _data: &Self::SymbolData, + _module_info: Option<&ModuleInfo>, + ) -> Option { + None + } + + fn has_attribute( + &self, + _name: &str, + _data: &Self::SymbolData, + _module_info: Option<&ModuleInfo>, + ) -> bool { + false + } + + fn get_all_attributes( + &self, + _data: &Self::SymbolData, + _module_info: Option<&ModuleInfo>, + ) -> Vec { + vec![] + } + + fn simple_dump(&self) -> String { + let mut output = "{\n".to_string(); + output.push_str("\"kind\": \"CommentSymbol\",\n"); + output.push_str(&format!( + "\"range\": \"{}:{}", + self.start.filename, self.start.line + )); + if let Some(start_col) = self.start.column { + output.push_str(&format!(":{}", start_col)); + } + + output.push_str(&format!(" to {}", self.end.line)); + if let Some(end_col) = self.end.column { + output.push_str(&format!(":{}", end_col)); + } + output.push_str(&format!("name :{}", self.name())); + output.push_str("\"\n}"); + output + } + + fn full_dump(&self, _data: &Self::SymbolData) -> Option { + Some(self.simple_dump()) + } + + fn get_references(&self) -> HashSet { + self.r#ref.clone() + } +} + +impl DecoratorSymbol { + pub fn new(start: Position, end: Position, name: String) -> Self { + Self { + id: None, + start, + end, + name, + sema_info: SymbolSemanticInfo::default(), + r#ref: HashSet::default(), + } + } + + pub fn name(&self) -> String { + self.name.clone() + } +} + +#[derive(Debug, Clone)] +pub struct FunctionSymbol { + pub(crate) id: Option, + pub(crate) name: String, + pub(crate) start: Position, + pub(crate) end: Position, + pub(crate) owner: Option, + pub(crate) sema_info: SymbolSemanticInfo, + pub(crate) is_global: bool, + pub(crate) r#ref: HashSet, +} + +impl Symbol for FunctionSymbol { + type SymbolData = SymbolData; + type SemanticInfo = SymbolSemanticInfo; + type SymbolHint = SymbolHint; + + fn is_global(&self) -> bool { + self.is_global + } + + fn get_range(&self) -> Range { + (self.start.clone(), self.end.clone()) + } + + fn get_owner(&self) -> Option { + self.owner.clone() + } + + fn get_definition(&self) -> Option { + self.id.clone() + } + + fn get_name(&self) -> String { + self.name.clone() + } + + fn get_id(&self) -> Option { + self.id.clone() + } + + fn get_attribute( + &self, + name: &str, + data: &Self::SymbolData, + module_info: Option<&ModuleInfo>, + ) -> Option { + data.get_type_attribute(self.sema_info.ty.as_ref()?, name, module_info) + } + + fn get_all_attributes( + &self, + data: &Self::SymbolData, + module_info: Option<&ModuleInfo>, + ) -> Vec { + let mut result = vec![]; + if let Some(ty) = self.sema_info.ty.as_ref() { + if let Some(symbol_ref) = data.get_type_symbol(ty, module_info) { + if let Some(symbol) = data.get_symbol(symbol_ref) { + result.append(&mut symbol.get_all_attributes(data, module_info)) + } + } + } + + result + } + + fn has_attribute( + &self, + name: &str, + data: &Self::SymbolData, + module_info: Option<&ModuleInfo>, + ) -> bool { + self.get_attribute(name, data, module_info).is_some() + } + + fn get_sema_info(&self) -> &Self::SemanticInfo { + &self.sema_info + } + + fn simple_dump(&self) -> String { + let mut output = "{\n".to_string(); + output.push_str("\"kind\": \"FunctionSymbol\",\n"); + output.push_str(&format!("\"name\":\"{}\",\n", self.name)); + output.push_str(&format!( + "\"range\": \"{}:{}", + self.start.filename, self.start.line + )); + if let Some(start_col) = self.start.column { + output.push_str(&format!(":{}", start_col)); + } + + output.push_str(&format!(" to {}", self.end.line)); + if let Some(end_col) = self.end.column { + output.push_str(&format!(":{}", end_col)); + } + output.push_str("\"\n}"); + output + } + + fn full_dump(&self, data: &Self::SymbolData) -> Option { + let mut output = format!("{{\n\"simple_info\": {},\n", self.simple_dump()); + output.push_str("\"additional_info\": {\n"); + if let Some(owner) = self.owner.as_ref() { + let owner_symbol = data.get_symbol(*owner)?; + output.push_str(&format!("\"owner\": {}\n", owner_symbol.simple_dump())); + } + output.push_str("\n}\n}"); + Some(output) + } + + fn get_references(&self) -> HashSet { + self.r#ref.clone() + } +} + +impl FunctionSymbol { + pub fn new( + name: String, + start: Position, + end: Position, + owner: Option, + is_global: bool, + ) -> Self { + Self { + id: None, + name, + start, + end, + owner, + sema_info: SymbolSemanticInfo::default(), + is_global, + r#ref: HashSet::default(), + } + } +} diff --git a/kclvm/sema/src/info/mod.rs b/kclvm/sema/src/info/mod.rs index f025de680..c57844717 100644 --- a/kclvm/sema/src/info/mod.rs +++ b/kclvm/sema/src/info/mod.rs @@ -1,4 +1,12 @@ +use regex::Regex; + #[inline] pub fn is_private_field(name: &str) -> bool { name.starts_with('_') } + +#[inline] +pub fn is_valid_kcl_name(name: &str) -> bool { + let re = Regex::new(r#"^[a-zA-Z_][a-zA-Z0-9_]*$"#).unwrap(); + re.is_match(name) +} diff --git a/kclvm/sema/src/lib.rs b/kclvm/sema/src/lib.rs index 35120ecc4..3f119adbf 100644 --- a/kclvm/sema/src/lib.rs +++ b/kclvm/sema/src/lib.rs @@ -1,10 +1,17 @@ +pub mod advanced_resolver; pub mod builtin; +pub mod core; pub mod eval; pub mod info; +pub mod lint; +pub mod namer; pub mod plugin; pub mod pre_process; pub mod resolver; pub mod ty; #[macro_use] -extern crate kclvm_error; +mod macros; + +#[macro_use] +extern crate compiler_base_macros; diff --git a/kclvm/sema/src/lint/LICENSE b/kclvm/sema/src/lint/LICENSE new file mode 100644 index 000000000..989e2c59e --- /dev/null +++ b/kclvm/sema/src/lint/LICENSE @@ -0,0 +1,201 @@ +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. \ No newline at end of file diff --git a/kclvm/sema/src/lint/combinedlintpass.rs b/kclvm/sema/src/lint/combinedlintpass.rs new file mode 100644 index 000000000..9e1c82041 --- /dev/null +++ b/kclvm/sema/src/lint/combinedlintpass.rs @@ -0,0 +1,127 @@ +use crate::lint::lint::{LintArray, LintContext}; +use crate::lint::lintpass::LintPass; +use crate::lint::lints_def::ImportPosition; +use crate::lint::lints_def::ReImport; +use crate::lint::lints_def::UnusedImport; +use crate::lint_methods; +use crate::resolver::scope::Scope; +use kclvm_ast::ast; +use kclvm_error::Handler; + +/// Call the `check_*` method of each lintpass in CombinedLintLass.check_*. +/// ```ignore +/// fn check_ident(&mut self, handler: &mut Handler, ctx: &mut LintContext, id: &ast::Identifier, ){ +/// self.LintPassA.check_ident(handler, ctx, id); +/// self.LintPassB.check_ident(handler, ctx, id); +/// ... +/// } +/// ``` +macro_rules! expand_combined_lint_pass_method { + ([$($passes:ident),*], $self: ident, $name: ident, $params:tt) => ({ + $($self.$passes.$name $params;)* + }) +} + +/// Expand all methods defined in macro `lint_methods` in the `CombinedLintLass`. +/// +/// ```ignore +/// fn check_ident(&mut self, handler: &mut Handler, ctx: &mut LintContext, id: &ast::Identifier){}; +/// fn check_stmt(&mut self, handler: &mut Handler, ctx: &mut LintContext, module: &ast::Module){}; +/// ... +/// ``` +macro_rules! expand_combined_lint_pass_methods { + ($handler:ty, $ctx:ty, $passes:tt, [$($(#[$attr:meta])* fn $name:ident($($param:ident: $arg:ty),*);)*]) => ( + $(fn $name(&mut self, handler: &mut $handler, ctx: &mut $ctx, $($param: $arg),*) { + expand_combined_lint_pass_method!($passes, self, $name, (handler, ctx, $($param),*)); + })* + ) +} + +/// Expand all definitions of `CombinedLintPass`. The results are as follows: +/// +/// ```ignore +/// pub struct CombinedLintPass { +/// LintPassA: LintPassA; +/// LintPassB: LintPassB; +/// ... +/// } +/// +/// impl CombinedLintPass{ +/// pub fn new() -> Self { +/// Self { +/// LintPassA: LintPassA, +/// LintPassB: LintPassB, +/// ... +/// } +/// } +/// pub fn get_lints() -> LintArray { +/// let mut lints = Vec::new(); +/// lints.extend_from_slice(&LintPassA::get_lints()); +/// lints.extend_from_slice(&LintPassB::get_lints()); +/// ... +/// lints +/// } +/// } +/// +/// impl LintPass for CombinedLintPass { +/// fn check_ident(&mut self, handler: &mut Handler, ctx: &mut LintContext, id: &ast::Identifier, ){ +/// self.LintPassA.check_ident(handler, ctx, id); +/// self.LintPassB.check_ident(handler, ctx, id); +/// ... +/// } +/// fn check_stmt(&mut self, handler: &mut Handler ctx: &mut LintContext, module: &ast::Module){ +/// self.LintPassA.check_stmt(handler, ctx, stmt); +/// self.LintPassB.check_stmt(handler, ctx, stmt); +/// ... +/// } +/// ... +/// } +/// ``` +macro_rules! declare_combined_lint_pass { + ([$v:vis $name:ident, [$($passes:ident: $constructor:expr,)*]], $methods:tt) => ( + #[allow(non_snake_case)] + $v struct $name { + $($passes: $passes,)* + } + + impl $name { + $v fn new() -> Self { + Self { + $($passes: $constructor,)* + } + } + + $v fn get_lints() -> LintArray { + let mut lints = Vec::new(); + $(lints.extend_from_slice(&$passes::get_lints());)* + lints + } + } + + impl LintPass for $name { + expand_combined_lint_pass_methods!(Handler, LintContext,[$($passes),*], $methods); + } + ) +} + +macro_rules! default_lint_passes { + ($macro:path, $args:tt) => { + $macro!( + $args, + [ + ImportPosition: ImportPosition, + UnusedImport: UnusedImport, + ReImport: ReImport, + ] + ); + }; +} + +macro_rules! declare_combined_default_pass { + ([$name:ident], $passes:tt) => ( + lint_methods!(declare_combined_lint_pass, [pub $name, $passes]); + ) +} + +// Define CombinedLintPass +default_lint_passes!(declare_combined_default_pass, [CombinedLintPass]); diff --git a/kclvm/sema/src/lint/lint.rs b/kclvm/sema/src/lint/lint.rs new file mode 100644 index 000000000..7545c3c9f --- /dev/null +++ b/kclvm/sema/src/lint/lint.rs @@ -0,0 +1,44 @@ +use kclvm_error::{Level, Position}; + +/// Record the information at `LintContext` when traversing the AST for analysis across AST nodes, e.g., record +/// used importstmt(used_import_names) when traversing `ast::Identifier` and `ast::SchemaAttr`, and detect unused +/// importstmt after traversing the entire module. +pub struct LintContext { + /// What source file are we in. + pub filename: String, + /// Are we resolving the ast node start position. + pub start_pos: Position, + /// Are we resolving the ast node end position. + pub end_pos: Position, +} + +/// Definition of `Lint` struct +/// Note that Lint declarations don't carry any "state" - they are merely global identifiers and descriptions of lints. +pub struct Lint { + /// A string identifier for the lint. + pub name: &'static str, + + /// Level for the lint. + pub level: Level, + + /// Description of the lint or the issue it detects. + /// e.g., "imports that are never used" + pub desc: &'static str, + + // Error/Warning code + pub code: &'static str, + + // Suggest methods to fix this problem + pub note: Option<&'static str>, +} + +pub type LintArray = Vec<&'static Lint>; + +/// Declares a static `LintArray` and return it as an expression. +#[macro_export] +macro_rules! lint_array { + ($( $lint:expr ),* ,) => { lint_array!( $($lint),* ) }; + ($( $lint:expr ),*) => {{ + vec![$($lint),*] + }} +} diff --git a/kclvm/sema/src/lint/lintpass.rs b/kclvm/sema/src/lint/lintpass.rs new file mode 100644 index 000000000..9e64a0a2d --- /dev/null +++ b/kclvm/sema/src/lint/lintpass.rs @@ -0,0 +1,112 @@ +use crate::lint::lint::LintContext; +use crate::resolver::scope::Scope; +use kclvm_ast::ast; +use kclvm_error::Handler; + +#[macro_export] +/// A summary of the methods that need to be implemented in lintpass, to be added when constructing new lint +/// lint and lintpass. When defining lintpass, the default implementation of these methods is provided: null +/// check (see macro `expand_default_lint_pass_methods`). So what need to do is to override the specific +/// `check_*` function. Some of the methods are commented out here to avoid useless empty functions, which +/// can be added when needed. +macro_rules! lint_methods { + ($macro:path, $args:tt) => ( + $macro!($args, [ + + fn check_scope(_scope: &Scope); + + fn check_module(_module: &ast::Module); + /* + * Stmt + */ + + // fn check_expr_stmt(expr_stmt: &ast::ExprStmt); + // fn check_unification_stmt(unification_stmt: &ast::UnificationStmt); + // fn check_type_alias_stmt(type_alias_stmt: &ast::TypeAliasStmt); + // fn check_assign_stmt(assign_stmt: &ast::AssignStmt); + // fn check_aug_assign_stmt(aug_assign_stmt: &ast::AugAssignStmt); + // fn check_assert_stmt(assert_stmt: &ast::AssertStmt); + // fn check_if_stmt(if_stmt: &ast::IfStmt); + // fn check_import_stmt(import_stmt: &ast::ImportStmt); + // fn check_schema_stmt(schema_stmt: &ast::SchemaStmt); + // fn check_rule_stmt(rule_stmt: &ast::RuleStmt); + + /* + * Expr + */ + + // fn check_expr(expr: &ast::Node<&ast::Expr>); + // fn check_quant_expr(quant_expr: &ast::QuantExpr); + // fn check_schema_attr(schema_attr: &ast::SchemaAttr); + // fn check_if_expr(if_expr: &ast::IfExpr); + // fn check_unary_expr(unary_expr: &ast::UnaryExpr); + // fn check_binary_expr(binary_expr: &ast::BinaryExpr); + // fn check_selector_expr(selector_expr: &ast::SelectorExpr); + // fn check_call_expr(call_expr: &ast::CallExpr); + // fn check_subscript(subscript: &ast::Subscript); + // fn check_paren_expr(paren_expr: &ast::ParenExpr); + // fn check_list_expr(list_expr: &ast::ListExpr); + // fn check_list_comp(list_comp: &ast::ListComp); + // fn check_list_if_item_expr(list_if_item_expr: &ast::ListIfItemExpr); + // fn check_starred_expr(starred_expr: &ast::StarredExpr); + // fn check_dict_comp(dict_comp: &ast::DictComp); + // fn check_config_if_entry_expr(config_if_entry_expr: &ast::ConfigIfEntryExpr, + // ); + // fn check_comp_clause(comp_clause: &ast::CompClause); + // fn check_schema_expr(schema_expr: &ast::SchemaExpr); + // fn check_config_expr(config_expr: &ast::ConfigExpr); + // fn check_check_expr(check_expr: &ast::CheckExpr); + // fn check_lambda_expr(lambda_expr: &ast::LambdaExpr); + // fn check_keyword(keyword: &ast::Keyword); + // fn check_arguments(arguments: &ast::Arguments); + // fn check_compare(compare: &ast::Compare); + // fn check_identifier(id: &ast::Identifier); + // fn check_number_lit(number_lit: &ast::NumberLit); + // fn check_string_lit(string_lit: &ast::StringLit); + // fn check_name_constant_lit(name_constant_lit: &ast::NameConstantLit); + // fn check_joined_string(joined_string: &ast::JoinedString); + // fn check_formatted_value(formatted_value: &ast::FormattedValue); + // fn check_comment(comment: &ast::Comment); + ]); + ) +} + +/// Provide a default implementation of the methods in lint_methods for each lintpass: null checking +macro_rules! expand_default_lint_pass_methods { + ($handler:ty, $ctx:ty, [$($(#[$attr:meta])* fn $name:ident($($param:ident: $arg:ty),*);)*]) => ( + $(#[inline(always)] fn $name(&mut self, _handler: &mut $handler, _ctx: &mut $ctx, $($param: $arg),*) {})* + ) +} + +/// Definition of `LintPass` trait +macro_rules! declare_default_lint_pass_impl { + ([], [$($methods:tt)*]) => ( + pub trait LintPass { + expand_default_lint_pass_methods!(Handler, LintContext, [$($methods)*]); + } + ) +} + +// Define LintPass +lint_methods!(declare_default_lint_pass_impl, []); + +/// The macro to define the LintPass and bind a set of corresponding Lint. +/// +/// Here is a `LintArray`, which means that multiple lint checks can be implemented in a single lintpass. +#[macro_export] +macro_rules! declare_lint_pass { + ($(#[$m:meta])* $name:ident => [$($lint:expr),* $(,)?]) => { + $(#[$m])* #[derive(Copy, Clone)] pub struct $name; + $crate::impl_lint_pass!($name => [$($lint),*]); + }; +} + +/// Implements `LintPass for $ty` with the given list of `Lint` statics. +#[macro_export] +macro_rules! impl_lint_pass { + ($ty:ty => [$($lint:expr),* $(,)?]) => { + impl $ty { + pub fn get_lints() -> LintArray { $crate::lint_array!($($lint),*) } + } + }; +} diff --git a/kclvm/sema/src/lint/lints_def.rs b/kclvm/sema/src/lint/lints_def.rs new file mode 100644 index 000000000..4361296db --- /dev/null +++ b/kclvm/sema/src/lint/lints_def.rs @@ -0,0 +1,177 @@ +use crate::lint::lint::{Lint, LintArray, LintContext}; +use crate::lint::lintpass::LintPass; +use crate::resolver::scope::Scope; +use crate::{declare_lint_pass, resolver::scope::ScopeObjectKind}; +use indexmap::IndexSet; +use kclvm_ast::ast; +use kclvm_ast::pos::GetPos; +use kclvm_error::{Handler, Level, Message, Style, WarningKind}; + +/// The 'import_position' lint detects import statements that are not declared at the top of file. +/// ### Example +/// +/// ```kcl +/// schema Person: +/// name: str +/// +/// import foo +/// +/// ``` +/// ### Explanation +/// +/// According to the KCL code style conventions, import statement are always declared at the top of the file. +pub static IMPORT_POSITION: &Lint = &Lint { + name: stringify!("IMPORT_POSITION"), + level: Level::Warning, + desc: "Check for importstmt that are not defined at the top of file", + code: "W0413", + note: Some("Consider moving tihs statement to the top of the file"), +}; + +declare_lint_pass!(ImportPosition => [IMPORT_POSITION]); + +impl LintPass for ImportPosition { + fn check_module( + &mut self, + handler: &mut Handler, + _ctx: &mut LintContext, + module: &ast::Module, + ) { + let mut first_non_importstmt = std::u64::MAX; + for stmt in &module.body { + match &stmt.node { + ast::Stmt::Import(_import_stmt) => {} + _ => { + if stmt.line < first_non_importstmt { + first_non_importstmt = stmt.line + } + } + } + } + for stmt in &module.body { + if let ast::Stmt::Import(_import_stmt) = &stmt.node { + if stmt.line > first_non_importstmt { + handler.add_warning( + WarningKind::ImportPositionWarning, + &[Message { + range: stmt.get_span_pos(), + style: Style::Line, + message: format!( + "The import stmt should be placed at the top of the module" + ), + note: Some( + "Consider moving tihs statement to the top of the file".to_string(), + ), + suggested_replacement: None, + }], + ); + } + } + } + } +} + +/// The 'unused_import' lint detects import statements that are declared but not used. +/// +/// ### Example +/// +/// ```kcl +/// import foo +/// +/// schema Person: +/// name: str +/// +/// ``` +/// ### Explanation +/// +/// Useless imports can affect the speed of compilation. It is necessary to remove useless imports from the kcl code. +pub static UNUSED_IMPORT: &Lint = &Lint { + name: stringify!("UNUSED_IMPORT"), + level: Level::Warning, + desc: "Check for unused importstmt", + code: "W0411", + note: Some("Consider removing this statement"), +}; + +declare_lint_pass!(UnusedImport => [UNUSED_IMPORT]); + +impl LintPass for UnusedImport { + fn check_scope(&mut self, handler: &mut Handler, _ctx: &mut LintContext, scope: &Scope) { + let scope_objs = &scope.elems; + for (_, scope_obj) in scope_objs { + let scope_obj = scope_obj.borrow(); + if let ScopeObjectKind::Module(m) = &scope_obj.kind { + for (stmt, has_used) in &m.import_stmts { + if !has_used { + handler.add_warning( + WarningKind::UnusedImportWarning, + &[Message { + range: stmt.get_span_pos(), + style: Style::Line, + message: format!("Module '{}' imported but unused", scope_obj.name), + note: Some("Consider removing this statement".to_string()), + suggested_replacement: None, + }], + ); + } + } + } + } + } +} + +/// The 'reimport' lint detects deplicate import statement +/// ### Example +/// +/// ```kcl +/// import foo +/// import foo +/// +/// schema Person: +/// name: str +/// +/// ``` +/// ### Explanation +/// +/// The import statement should be declared only once +pub static REIMPORT: &Lint = &Lint { + name: stringify!("REIMPORT"), + level: Level::Warning, + desc: "Check for deplicate importstmt", + code: "W0404", + note: Some("Consider removing this statement"), +}; + +declare_lint_pass!(ReImport => [REIMPORT]); + +impl LintPass for ReImport { + fn check_module( + &mut self, + handler: &mut Handler, + _ctx: &mut LintContext, + module: &ast::Module, + ) { + let mut import_names = IndexSet::::new(); + for stmt in &module.body { + if let ast::Stmt::Import(import_stmt) = &stmt.node { + if import_names.contains(&import_stmt.path.node) { + handler.add_warning( + WarningKind::ReimportWarning, + &[Message { + range: stmt.get_span_pos(), + style: Style::Line, + message: format!( + "Module '{}' is reimported multiple times", + &import_stmt.name + ), + note: Some("Consider removing this statement".to_string()), + suggested_replacement: None, + }], + ); + } else { + import_names.insert(import_stmt.path.node.clone()); + } + } + } + } +} diff --git a/kclvm/sema/src/lint/mod.rs b/kclvm/sema/src/lint/mod.rs new file mode 100644 index 000000000..9ae492ce3 --- /dev/null +++ b/kclvm/sema/src/lint/mod.rs @@ -0,0 +1,402 @@ +//! The design and implementation of KCL Lint refer to the [rust-lang/rustc](https://github.com/rust-lang/rust) lint and follow Apache License Version 2.0 +//! +//! This file is the implementation of KCLLint, which is used to perform some additional checks on KCL code. +//! The main structures of the file are Lint, LintPass, CombinedLintPass and Linter. +//! For details see the: https://github.com/kcl-lang/kcl/issues/109 +//! +//! File dependencies: +//! mode -> combinedlintpass -> lints_def -> lintpass -> lint +//! +//! mode.rs: Definition of `Linter`, the entry for lint check +//! combinedlintpass.rs: `CombinedLintPass` collects all the lints defined in the lints_def.rs +//! lints_def.rs: Defined the various lints and the corresponding lintpasses implementation +//! lintpass.rs: Definition of `Lintpass` +//! lint.rs: Definition of `Lint` +//! +//! Steps to define a new lint: +//! 1. Define a static instance of the `Lint` structure in lints_def.rs,e.g., +//! +//! ```ignore +//! pub static IMPORT_POSITION: &Lint = &Lint { +//! ... +//! } +//! ``` +//! +//! 2. Define a lintpass, which is used to implement the checking process,e.g., +//! +//! ```ignore +//! declare_lint_pass!(ImportPosition => [IMPORT_POSITION]); +//! ``` +//! +//! The `ImportPosition` is the defined LintPass structure and the `IMPORT_POSITION` is the `Lint` structure +//! defined in step 1. Here is a `LintArray`, which means that multiple lint checks can be implemented +//! in a single lintpass. +//! +//! 3. Implement the lintpass check process, e.g., +//! +//! ```ignore +//! impl LintPass for ImportPosition { +//! fn check_module(&mut self, handler: &mut Handler, ctx: &mut LintContext,module: &ast::Module){ +//! ... +//! } +//! } +//! ``` +//! +//! 4. Add the `check_*` methods in lintpass to the macro `lint_methods`, or skip it if it exists +//! +//! ```ignore +//! macro_rules! lint_methods { +//! ($macro:path, $args:tt) => ( +//! $macro!($args, [ +//! fn check_module(module: &ast::Module); +//! ]); +//! ) +//! } +//! ``` +//! +//! 5. Add the new lintpass to the macro `default_lint_passes` in lintpass.rs , noting that `:` is preceded and followed by +//! the name of the lintpass. e.g., +//! +//! ```ignore +//! macro_rules! default_lint_passes { +//! ($macro:path, $args:tt) => { +//! $macro!( +//! $args, +//! [ +//! ImportPosition: ImportPosition, +//! ] +//! ); +//! }; +//! } +//! ``` +//! +//! 6. If new `check_*` method was added in step 4, it needs to override the walk_* method in Linter. +//! In addition to calling the self.pass.check_* function, the original walk method in MutSelfWalker +//! should be copied here so that it can continue to traverse the child nodes. + +use crate::resolver::{scope::Scope, Resolver}; +use kclvm_ast::pos::GetPos; +use kclvm_error::{Handler, Position}; +mod combinedlintpass; +mod lint; +mod lintpass; +mod lints_def; +use kclvm_ast::ast; +use kclvm_ast::walker::MutSelfWalker; + +pub use self::{combinedlintpass::CombinedLintPass, lint::LintContext, lintpass::LintPass}; + +/// The struct `Linter` is used to traverse the AST and call the `check_*` method defined in `CombinedLintPass`. +pub struct Linter { + pub pass: T, + pub handler: Handler, + pub ctx: LintContext, +} + +impl LintContext { + pub fn dummy_ctx() -> Self { + LintContext { + filename: "".to_string(), + start_pos: Position::dummy_pos(), + end_pos: Position::dummy_pos(), + } + } +} + +impl Linter { + pub fn new() -> Self { + Linter:: { + pass: CombinedLintPass::new(), + handler: Handler::default(), + ctx: LintContext::dummy_ctx(), + } + } + pub fn walk_scope(&mut self, scope: &Scope) { + self.pass + .check_scope(&mut self.handler, &mut self.ctx, scope); + } +} + +impl Resolver<'_> { + /// Iterate the module and run lint checks, generating diagnostics and save them in `lint.handler` + pub fn lint_check_module(&mut self, module: &ast::Module) { + self.linter.ctx.filename = module.filename.clone(); + self.linter.walk_module(module); + } + /// Recursively iterate the scope and its child scope, run lint checks, generating diagnostics and save them in `lint.handler` + pub fn lint_check_scope(&mut self, scope: &Scope) { + self.linter.walk_scope(scope); + for children in &scope.children { + self.lint_check_scope(&children.borrow().clone()) + } + } + + /// Iterate the resolver.scope_map and run lint checks, generating diagnostics and save them in `lint.handler` + pub fn lint_check_scope_map(&mut self) { + let scope_map = self.scope_map.clone(); + for (_, scope) in scope_map.iter() { + self.lint_check_scope(&scope.borrow()) + } + } +} + +macro_rules! walk_set_list { + ($walker: expr, $method: ident, $list: expr) => { + for elem in &$list { + set_pos!($walker, elem); + $walker.$method(&elem.node) + } + }; +} + +macro_rules! walk_set_if { + ($walker: expr, $method: ident, $value: expr) => { + match &$value { + Some(v) => { + set_pos!($walker, &v); + $walker.$method(&v.node); + } + None => (), + } + }; +} + +macro_rules! set_pos { + ($walker: expr, $value: expr) => { + $walker.set_pos(&$value.get_pos(), &$value.get_end_pos()); + }; +} + +impl Linter { + fn set_pos(&mut self, start_pos: &Position, end_pos: &Position) { + self.ctx.start_pos = start_pos.clone(); + self.ctx.end_pos = end_pos.clone(); + } +} + +impl MutSelfWalker for Linter { + fn walk_module(&mut self, module: &ast::Module) { + self.pass + .check_module(&mut self.handler, &mut self.ctx, module); + walk_set_list!(self, walk_stmt, module.body); + } + + fn walk_expr_stmt(&mut self, expr_stmt: &ast::ExprStmt) { + for expr in &expr_stmt.exprs { + set_pos!(self, &expr); + self.walk_expr(&expr.node) + } + } + + fn walk_type_alias_stmt(&mut self, type_alias_stmt: &ast::TypeAliasStmt) { + set_pos!(self, &type_alias_stmt.type_name); + self.walk_identifier(&type_alias_stmt.type_name.node); + } + fn walk_unification_stmt(&mut self, unification_stmt: &ast::UnificationStmt) { + set_pos!(self, &unification_stmt.target); + self.walk_identifier(&unification_stmt.target.node); + set_pos!(self, &unification_stmt.value); + self.walk_schema_expr(&unification_stmt.value.node); + } + fn walk_assign_stmt(&mut self, assign_stmt: &ast::AssignStmt) { + for target in &assign_stmt.targets { + set_pos!(self, &target); + self.walk_target(&target.node) + } + set_pos!(self, &assign_stmt.value); + self.walk_expr(&assign_stmt.value.node); + } + fn walk_aug_assign_stmt(&mut self, aug_assign_stmt: &ast::AugAssignStmt) { + set_pos!(self, &aug_assign_stmt.target); + self.walk_target(&aug_assign_stmt.target.node); + set_pos!(self, &aug_assign_stmt.value); + self.walk_expr(&aug_assign_stmt.value.node); + } + fn walk_assert_stmt(&mut self, assert_stmt: &ast::AssertStmt) { + set_pos!(self, &assert_stmt.test); + self.walk_expr(&assert_stmt.test.node); + walk_set_if!(self, walk_expr, assert_stmt.if_cond); + walk_set_if!(self, walk_expr, assert_stmt.msg); + } + fn walk_if_stmt(&mut self, if_stmt: &ast::IfStmt) { + set_pos!(self, &if_stmt.cond); + self.walk_expr(&if_stmt.cond.node); + walk_set_list!(self, walk_stmt, if_stmt.body); + walk_set_list!(self, walk_stmt, if_stmt.orelse); + } + fn walk_import_stmt(&mut self, import_stmt: &ast::ImportStmt) { + // Nothing to do. + let _ = import_stmt; + } + fn walk_schema_attr(&mut self, schema_attr: &ast::SchemaAttr) { + walk_set_list!(self, walk_call_expr, schema_attr.decorators); + walk_set_if!(self, walk_expr, schema_attr.value); + } + fn walk_schema_stmt(&mut self, schema_stmt: &ast::SchemaStmt) { + walk_set_if!(self, walk_identifier, schema_stmt.parent_name); + walk_set_if!(self, walk_identifier, schema_stmt.for_host_name); + walk_set_if!(self, walk_arguments, schema_stmt.args); + if let Some(schema_index_signature) = &schema_stmt.index_signature { + let value = &schema_index_signature.node.value; + walk_set_if!(self, walk_expr, value); + } + walk_set_list!(self, walk_identifier, schema_stmt.mixins); + walk_set_list!(self, walk_call_expr, schema_stmt.decorators); + walk_set_list!(self, walk_check_expr, schema_stmt.checks); + walk_set_list!(self, walk_stmt, schema_stmt.body); + } + fn walk_rule_stmt(&mut self, rule_stmt: &ast::RuleStmt) { + walk_set_list!(self, walk_identifier, rule_stmt.parent_rules); + walk_set_list!(self, walk_call_expr, rule_stmt.decorators); + walk_set_list!(self, walk_check_expr, rule_stmt.checks); + walk_set_if!(self, walk_arguments, rule_stmt.args); + walk_set_if!(self, walk_identifier, rule_stmt.for_host_name); + } + fn walk_quant_expr(&mut self, quant_expr: &ast::QuantExpr) { + set_pos!(self, &quant_expr.target); + self.walk_expr(&quant_expr.target.node); + walk_set_list!(self, walk_identifier, quant_expr.variables); + set_pos!(self, &quant_expr.test); + self.walk_expr(&quant_expr.test.node); + walk_set_if!(self, walk_expr, quant_expr.if_cond); + } + fn walk_if_expr(&mut self, if_expr: &ast::IfExpr) { + set_pos!(self, &if_expr.cond); + self.walk_expr(&if_expr.cond.node); + set_pos!(self, &if_expr.body); + self.walk_expr(&if_expr.body.node); + set_pos!(self, &if_expr.orelse); + self.walk_expr(&if_expr.orelse.node); + } + fn walk_unary_expr(&mut self, unary_expr: &ast::UnaryExpr) { + set_pos!(self, &unary_expr.operand); + self.walk_expr(&unary_expr.operand.node); + } + fn walk_binary_expr(&mut self, binary_expr: &ast::BinaryExpr) { + set_pos!(self, &binary_expr.left); + self.walk_expr(&binary_expr.left.node); + set_pos!(self, &binary_expr.right); + self.walk_expr(&binary_expr.right.node); + } + fn walk_selector_expr(&mut self, selector_expr: &ast::SelectorExpr) { + set_pos!(self, &selector_expr.value); + self.walk_expr(&selector_expr.value.node); + set_pos!(self, &selector_expr.attr); + self.walk_identifier(&selector_expr.attr.node); + } + fn walk_call_expr(&mut self, call_expr: &ast::CallExpr) { + set_pos!(self, &call_expr.func); + self.walk_expr(&call_expr.func.node); + walk_set_list!(self, walk_expr, call_expr.args); + walk_set_list!(self, walk_keyword, call_expr.keywords); + } + fn walk_subscript(&mut self, subscript: &ast::Subscript) { + set_pos!(self, &subscript.value); + self.walk_expr(&subscript.value.node); + walk_set_if!(self, walk_expr, subscript.index); + walk_set_if!(self, walk_expr, subscript.lower); + walk_set_if!(self, walk_expr, subscript.upper); + walk_set_if!(self, walk_expr, subscript.step); + } + fn walk_paren_expr(&mut self, paren_expr: &ast::ParenExpr) { + set_pos!(self, &paren_expr.expr); + self.walk_expr(&paren_expr.expr.node); + } + fn walk_list_expr(&mut self, list_expr: &ast::ListExpr) { + walk_set_list!(self, walk_expr, list_expr.elts); + } + fn walk_list_comp(&mut self, list_comp: &ast::ListComp) { + set_pos!(self, &list_comp.elt); + self.walk_expr(&list_comp.elt.node); + walk_set_list!(self, walk_comp_clause, list_comp.generators); + } + fn walk_list_if_item_expr(&mut self, list_if_item_expr: &ast::ListIfItemExpr) { + set_pos!(self, &list_if_item_expr.if_cond); + self.walk_expr(&list_if_item_expr.if_cond.node); + walk_set_list!(self, walk_expr, list_if_item_expr.exprs); + walk_set_if!(self, walk_expr, list_if_item_expr.orelse); + } + fn walk_starred_expr(&mut self, starred_expr: &ast::StarredExpr) { + set_pos!(self, &starred_expr.value); + self.walk_expr(&starred_expr.value.node); + } + fn walk_dict_comp(&mut self, dict_comp: &ast::DictComp) { + if let Some(key) = &dict_comp.entry.key { + set_pos!(self, &key); + self.walk_expr(&key.node); + } + set_pos!(self, &dict_comp.entry.value); + self.walk_expr(&dict_comp.entry.value.node); + walk_set_list!(self, walk_comp_clause, dict_comp.generators); + } + fn walk_config_if_entry_expr(&mut self, config_if_entry_expr: &ast::ConfigIfEntryExpr) { + set_pos!(self, &config_if_entry_expr.if_cond); + self.walk_expr(&config_if_entry_expr.if_cond.node); + for config_entry in &config_if_entry_expr.items { + walk_set_if!(self, walk_expr, config_entry.node.key); + set_pos!(self, &config_entry.node.value); + self.walk_expr(&config_entry.node.value.node); + } + walk_set_if!(self, walk_expr, config_if_entry_expr.orelse); + } + fn walk_comp_clause(&mut self, comp_clause: &ast::CompClause) { + walk_set_list!(self, walk_identifier, comp_clause.targets); + set_pos!(self, &comp_clause.iter); + self.walk_expr(&comp_clause.iter.node); + walk_set_list!(self, walk_expr, comp_clause.ifs); + } + fn walk_schema_expr(&mut self, schema_expr: &ast::SchemaExpr) { + set_pos!(self, &schema_expr.name); + self.walk_identifier(&schema_expr.name.node); + walk_set_list!(self, walk_expr, schema_expr.args); + walk_set_list!(self, walk_keyword, schema_expr.kwargs); + set_pos!(self, &schema_expr.config); + self.walk_expr(&schema_expr.config.node); + } + fn walk_config_expr(&mut self, config_expr: &ast::ConfigExpr) { + for config_entry in &config_expr.items { + walk_set_if!(self, walk_expr, config_entry.node.key); + set_pos!(self, &config_entry.node.value); + self.walk_expr(&config_entry.node.value.node); + } + } + fn walk_check_expr(&mut self, check_expr: &ast::CheckExpr) { + set_pos!(self, &check_expr.test); + self.walk_expr(&check_expr.test.node); + walk_set_if!(self, walk_expr, check_expr.if_cond); + walk_set_if!(self, walk_expr, check_expr.msg); + } + fn walk_lambda_expr(&mut self, lambda_expr: &ast::LambdaExpr) { + walk_set_if!(self, walk_arguments, lambda_expr.args); + walk_set_list!(self, walk_stmt, lambda_expr.body); + } + fn walk_keyword(&mut self, keyword: &ast::Keyword) { + set_pos!(self, &keyword.arg); + self.walk_identifier(&keyword.arg.node); + if let Some(v) = &keyword.value { + set_pos!(self, &v); + self.walk_expr(&v.node) + } + } + fn walk_arguments(&mut self, arguments: &ast::Arguments) { + walk_set_list!(self, walk_identifier, arguments.args); + for default in &arguments.defaults { + if let Some(d) = default { + set_pos!(self, d); + self.walk_expr(&d.node) + } + } + } + fn walk_compare(&mut self, compare: &ast::Compare) { + set_pos!(self, &compare.left); + self.walk_expr(&compare.left.node); + walk_set_list!(self, walk_expr, compare.comparators); + } + fn walk_joined_string(&mut self, joined_string: &ast::JoinedString) { + walk_set_list!(self, walk_expr, joined_string.values); + } + fn walk_formatted_value(&mut self, formatted_value: &ast::FormattedValue) { + set_pos!(self, &formatted_value.value); + self.walk_expr(&formatted_value.value.node); + } +} diff --git a/kclvm/sema/src/macros.rs b/kclvm/sema/src/macros.rs new file mode 100644 index 000000000..8848527c2 --- /dev/null +++ b/kclvm/sema/src/macros.rs @@ -0,0 +1,11 @@ +//! Copyright The KCL Authors. All rights reserved. + +#[macro_export] +macro_rules! pkgpath_without_prefix { + ($pkgpath: expr) => { + match $pkgpath.strip_prefix('@') { + Some(v) => v.to_string(), + None => $pkgpath.to_string(), + } + }; +} diff --git a/kclvm/sema/src/namer/mod.rs b/kclvm/sema/src/namer/mod.rs new file mode 100644 index 000000000..5c6560672 --- /dev/null +++ b/kclvm/sema/src/namer/mod.rs @@ -0,0 +1,368 @@ +/* + ┌─────────────────────────────────────────────────────────────────────────────────────────────────┐ + │ namer │ + ├─────────────────────────────────────────────────────────────────────────────────────────────────┤ + │ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ + │ │ ast::Expression │ │ ast::Expression │ │ ast::Expression │ │ + │ └─────────────────┘ └─────────────────┘ └─────────────────┘ │ + │ │ │ │ │ + │ │ find_symbols │ find_symbols │ find_symbols │ + │ ▼ ▼ ▼ │ + │ ┌─────────────────────────┐ ┌─────────────────────────┐ ┌─────────────────────────┐ │ + │ │ core::SymbolRef │ │ core::SymbolRef │ │ core::SymbolRef │ │ + │ └─────────────────────────┘ └─────────────────────────┘ └─────────────────────────┘ │ + │ │ │ │ │ + │ │ │ │ │ + │ └───────────────────────────────┼───────────────────────────────┘ │ + │ │ │ + │ │ merge findSymbols results │ + │ ▼ │ + │ ┌─────────────────────────┐ │ + │ │ core::SymbolRef │ │ + │ └─────────────────────────┘ │ + │ │ │ + │ │ define_symbols(FQN) │ + │ ■ │ + │ (mutates GlobalState) | + │ │ + └─────────────────────────────────────────────────────────────────────────────────────────────────┘ + + The early stage of the namer will be based on file level , which collects global symbols defined in the file, + and then merges the symbols based on FQN to obtain a unique GlobalState + + Based on file level, it means that we can easily perform incremental compilation in the future + + Now we just run namer pass serially + +*/ + +use std::path::Path; +use std::sync::Arc; + +use crate::builtin::{ + get_system_member_function_ty, get_system_module_members, BUILTIN_FUNCTIONS, + STANDARD_SYSTEM_MODULES, STRING_MEMBER_FUNCTIONS, +}; +use crate::core::global_state::GlobalState; +use crate::core::package::{ModuleInfo, PackageInfo}; +use crate::core::symbol::{ + FunctionSymbol, PackageSymbol, SymbolRef, BUILTIN_FUNCTION_PACKAGE, BUILTIN_STR_PACKAGE, +}; +use crate::resolver::scope::NodeKey; +use indexmap::IndexSet; +use kclvm_ast::ast::AstIndex; +use kclvm_ast::ast::Program; +use kclvm_ast::walker::MutSelfTypedResultWalker; +use kclvm_error::Position; +mod node; + +pub const BUILTIN_SYMBOL_PKG_PATH: &str = "@builtin"; + +pub struct Namer<'ctx> { + gs: &'ctx mut GlobalState, + ctx: NamerContext<'ctx>, +} + +struct NamerContext<'ctx> { + pub program: &'ctx Program, + pub current_package_info: Option, + pub current_module_info: Option, + pub owner_symbols: Vec, + pub value_fully_qualified_name_set: IndexSet, +} + +impl<'ctx> NamerContext<'ctx> { + pub fn get_node_key(&self, id: &AstIndex) -> NodeKey { + NodeKey { + pkgpath: self + .current_package_info + .clone() + .unwrap() + .fully_qualified_name, + id: id.clone(), + } + } +} + +impl<'ctx> Namer<'ctx> { + fn new(program: &'ctx Program, gs: &'ctx mut GlobalState) -> Self { + Self { + ctx: NamerContext { + program, + current_package_info: None, + current_module_info: None, + owner_symbols: Vec::default(), + value_fully_qualified_name_set: IndexSet::default(), + }, + gs, + } + } + + // serial namer pass + pub fn find_symbols(program: &'ctx Program, gs: &'ctx mut GlobalState) { + let mut namer = Self::new(program, gs); + namer.ctx.current_package_info = Some(PackageInfo::new( + BUILTIN_SYMBOL_PKG_PATH.to_string(), + "".to_string(), + true, + )); + namer.init_builtin_symbols(); + namer + .gs + .get_packages_mut() + .add_package(namer.ctx.current_package_info.take().unwrap()); + + for (name, modules) in namer.ctx.program.pkgs.iter() { + namer.walk_pkg(name, modules); + } + + namer.define_symbols(); + } + + fn walk_pkg(&mut self, name: &String, modules: &Vec) { + // new pkgs or invalidate pkg + if self.gs.get_packages().get_package_info(name).is_some() + && !self.gs.new_or_invalidate_pkgs.contains(name) + { + return; + } + + // add new pkgs to invalidate pkgs + self.gs.new_or_invalidate_pkgs.insert(name.clone()); + + { + if modules.is_empty() { + return; + } + self.ctx.value_fully_qualified_name_set.clear(); + let mut real_path = Path::new(&self.ctx.program.root) + .join(name.replace('.', &std::path::MAIN_SEPARATOR.to_string())) + .to_str() + .unwrap() + .to_string(); + if name == kclvm_ast::MAIN_PKG { + real_path = self.ctx.program.root.clone() + } + let pkg_pos = Position { + filename: real_path.clone(), + line: 0, + column: None, + }; + + let pkg_symbol = PackageSymbol::new(name.clone(), pkg_pos.clone(), pkg_pos); + let symbol_ref = self + .gs + .get_symbols_mut() + .alloc_package_symbol(pkg_symbol, name.to_string()); + self.ctx.owner_symbols.push(symbol_ref); + + self.ctx.current_package_info = + Some(PackageInfo::new(name.to_string(), real_path, false)); + } + + let modules = self.ctx.program.get_modules_for_pkg(name); + for module in modules.iter() { + let module = module.read().expect("Failed to acquire module lock"); + self.ctx + .current_package_info + .as_mut() + .unwrap() + .kfile_paths + .insert(module.filename.clone()); + self.ctx.current_module_info = + Some(ModuleInfo::new(module.filename.clone(), name.to_string())); + self.walk_module(&module); + self.gs + .get_packages_mut() + .add_module_info(self.ctx.current_module_info.take().unwrap()); + } + + self.ctx.owner_symbols.pop(); + self.gs + .get_packages_mut() + .add_package(self.ctx.current_package_info.take().unwrap()) + } + + fn init_builtin_symbols(&mut self) { + //add global built functions + for (name, builtin_func) in BUILTIN_FUNCTIONS.iter() { + let mut func_symbol = FunctionSymbol::new( + name.to_string(), + Position::dummy_pos(), + Position::dummy_pos(), + None, + true, + ); + + func_symbol.sema_info.ty = Some(Arc::new(builtin_func.clone())); + func_symbol.sema_info.doc = builtin_func.ty_doc(); + let symbol_ref = self.gs.get_symbols_mut().alloc_function_symbol( + func_symbol, + self.ctx.get_node_key(&AstIndex::default()), + BUILTIN_FUNCTION_PACKAGE.to_string(), + ); + self.gs + .get_symbols_mut() + .symbols_info + .global_builtin_symbols + .insert(name.to_string(), symbol_ref); + } + + //add system modules + for system_pkg_name in STANDARD_SYSTEM_MODULES { + let package_symbol_ref = self.gs.get_symbols_mut().alloc_package_symbol( + PackageSymbol::new( + system_pkg_name.to_string(), + Position::dummy_pos(), + Position::dummy_pos(), + ), + system_pkg_name.to_string(), + ); + for func_name in get_system_module_members(system_pkg_name) { + let func_ty = get_system_member_function_ty(*system_pkg_name, func_name); + let mut func_symbol = FunctionSymbol::new( + func_name.to_string(), + Position::dummy_pos(), + Position::dummy_pos(), + Some(package_symbol_ref), + false, + ); + + func_symbol.sema_info.ty = Some(func_ty.clone()); + func_symbol.sema_info.doc = func_ty.ty_doc(); + let func_symbol_ref = self.gs.get_symbols_mut().alloc_function_symbol( + func_symbol, + self.ctx.get_node_key(&AstIndex::default()), + system_pkg_name.to_string(), + ); + self.gs + .get_symbols_mut() + .packages + .get_mut(package_symbol_ref.get_id()) + .unwrap() + .members + .insert(func_name.to_string(), func_symbol_ref); + } + } + + //add string builtin function + let package_symbol_ref = self.gs.get_symbols_mut().alloc_package_symbol( + PackageSymbol::new( + BUILTIN_STR_PACKAGE.to_string(), + Position::dummy_pos(), + Position::dummy_pos(), + ), + BUILTIN_STR_PACKAGE.to_string(), + ); + for (name, builtin_func) in STRING_MEMBER_FUNCTIONS.iter() { + let mut func_symbol = FunctionSymbol::new( + name.to_string(), + Position::dummy_pos(), + Position::dummy_pos(), + Some(package_symbol_ref), + true, + ); + + func_symbol.sema_info.ty = Some(Arc::new(builtin_func.clone())); + func_symbol.sema_info.doc = builtin_func.ty_doc(); + let symbol_ref = self.gs.get_symbols_mut().alloc_function_symbol( + func_symbol, + self.ctx.get_node_key(&AstIndex::default()), + BUILTIN_STR_PACKAGE.to_string(), + ); + self.gs + .get_symbols_mut() + .packages + .get_mut(package_symbol_ref.get_id()) + .unwrap() + .members + .insert(name.to_string(), symbol_ref); + } + } + + fn define_symbols(&mut self) { + self.gs.get_symbols_mut().build_fully_qualified_name_map(); + } +} + +#[cfg(test)] +mod tests { + use super::Namer; + use crate::core::global_state::GlobalState; + use crate::core::symbol::SymbolKind; + use kclvm_parser::load_program; + use kclvm_parser::ParseSession; + use std::sync::Arc; + + #[test] + fn test_find_symbols() { + let sess = Arc::new(ParseSession::default()); + let program = load_program( + sess.clone(), + &["./src/namer/test_data/schema_symbols.k"], + None, + None, + ) + .unwrap() + .program; + let mut gs = GlobalState::default(); + Namer::find_symbols(&program, &mut gs); + + let symbols = gs.get_symbols(); + + let excepts_symbols = vec![ + // package + ("import_test.a", SymbolKind::Package), + ("import_test.b", SymbolKind::Package), + ("import_test.c", SymbolKind::Package), + ("import_test.d", SymbolKind::Package), + ("import_test.e", SymbolKind::Package), + ("import_test.f", SymbolKind::Package), + ("__main__", SymbolKind::Package), + ("pkg", SymbolKind::Package), + // schema + ("import_test.f.UnionType", SymbolKind::Schema), + ("import_test.a.Person", SymbolKind::Schema), + ("import_test.c.TestOfMixin", SymbolKind::Schema), + ("import_test.d.Parent", SymbolKind::Schema), + ("import_test.e.UnionType", SymbolKind::Schema), + ("pkg.Name", SymbolKind::Schema), + ("pkg.Person", SymbolKind::Schema), + ("__main__.Main", SymbolKind::Schema), + // attribute + ("import_test.f.UnionType.b", SymbolKind::Attribute), + ("import_test.a.Person.name", SymbolKind::Attribute), + ("import_test.a.Person.age", SymbolKind::Attribute), + ("pkg.Name.name", SymbolKind::Attribute), + ("pkg.Person.name", SymbolKind::Attribute), + ("import_test.c.TestOfMixin.age", SymbolKind::Attribute), + ("import_test.d.Parent.age1", SymbolKind::Attribute), + ("import_test.e.UnionType.a", SymbolKind::Attribute), + ("__main__.Main.name", SymbolKind::Attribute), + ("__main__.Main.age", SymbolKind::Attribute), + ("__main__.Main.person", SymbolKind::Attribute), + ("__main__.Main.list_union_type", SymbolKind::Attribute), + ("__main__.Main.dict_union_type", SymbolKind::Attribute), + // value + ("__main__.p", SymbolKind::Value), + ("__main__.person", SymbolKind::Value), + ("__main__._c", SymbolKind::Value), + ("import_test.a._a", SymbolKind::Value), + ("import_test.b._b", SymbolKind::Value), + ]; + + for (fqn, kind) in excepts_symbols { + assert!(symbols + .symbols_info + .fully_qualified_name_map + .contains_key(fqn)); + assert_eq!( + symbols + .get_symbol_by_fully_qualified_name(fqn) + .unwrap() + .get_kind(), + kind + ); + } + } +} diff --git a/kclvm/sema/src/namer/node.rs b/kclvm/sema/src/namer/node.rs new file mode 100644 index 000000000..92b0dfc86 --- /dev/null +++ b/kclvm/sema/src/namer/node.rs @@ -0,0 +1,429 @@ +use crate::core::package::ImportInfo; +use crate::core::symbol::{ + AttributeSymbol, RuleSymbol, SchemaSymbol, SymbolKind, SymbolRef, TypeAliasSymbol, ValueSymbol, +}; + +use super::Namer; +use kclvm_ast::ast; +use kclvm_ast::pos::GetPos; +use kclvm_ast::walker::MutSelfTypedResultWalker; +use kclvm_ast_pretty::{print_ast_node, ASTNode}; +use kclvm_error::diagnostic::Range; + +impl<'ctx> MutSelfTypedResultWalker<'ctx> for Namer<'_> { + type Result = Option>; + fn walk_module(&mut self, module: &'ctx ast::Module) -> Self::Result { + let owner = *self.ctx.owner_symbols.last().unwrap(); + for stmt_node in module.body.iter() { + let symbol_refs = self.walk_stmt(&stmt_node.node); + + if let Some(symbol_refs) = symbol_refs { + for symbol_ref in symbol_refs { + let full_name = self + .gs + .get_symbols() + .get_fully_qualified_name(symbol_ref) + .unwrap(); + let name = full_name.split(".").last().unwrap().to_string(); + + let package_symbol = self + .gs + .get_symbols_mut() + .packages + .get_mut(owner.get_id()) + .unwrap(); + + if !package_symbol.members.contains_key(&name) { + package_symbol.members.insert(name, symbol_ref); + } + } + } + } + + None + } + + fn walk_expr_stmt(&mut self, _expr_stmt: &'ctx ast::ExprStmt) -> Self::Result { + None + } + + fn walk_unification_stmt( + &mut self, + unification_stmt: &'ctx ast::UnificationStmt, + ) -> Self::Result { + let (start_pos, end_pos): Range = unification_stmt.target.get_span_pos(); + let owner = self.ctx.owner_symbols.last().unwrap().clone(); + if unification_stmt.target.node.names.len() == 1 { + let owner_fully_qualified_name = self + .gs + .get_symbols() + .get_fully_qualified_name(owner) + .unwrap(); + let value_name = unification_stmt.target.node.get_name(); + if self.gs.get_symbols().get_schema_symbol(owner).is_some() { + let attribute_ref = self.gs.get_symbols_mut().alloc_attribute_symbol( + AttributeSymbol::new(value_name, start_pos, end_pos, owner, false, None), + self.ctx + .get_node_key(&unification_stmt.target.node.names[0].id), + self.ctx + .current_package_info + .clone() + .unwrap() + .fully_qualified_name, + ); + Some(vec![attribute_ref]) + } else { + let value_fully_qualified_name = owner_fully_qualified_name + "." + &value_name; + if !self + .ctx + .value_fully_qualified_name_set + .contains(&value_fully_qualified_name) + { + let value_ref = self.gs.get_symbols_mut().alloc_value_symbol( + ValueSymbol::new(value_name, start_pos, end_pos, Some(owner), true), + self.ctx.get_node_key(&unification_stmt.target.id), + self.ctx + .current_package_info + .clone() + .unwrap() + .fully_qualified_name, + ); + self.ctx + .value_fully_qualified_name_set + .insert(value_fully_qualified_name); + Some(vec![value_ref]) + } else { + None + } + } + } else { + None + } + } + + fn walk_type_alias_stmt(&mut self, type_alias_stmt: &'ctx ast::TypeAliasStmt) -> Self::Result { + let (start_pos, end_pos): Range = type_alias_stmt.type_name.get_span_pos(); + let owner = self.ctx.owner_symbols.last().unwrap().clone(); + let type_alias_ref = self.gs.get_symbols_mut().alloc_type_alias_symbol( + TypeAliasSymbol::new( + type_alias_stmt.type_name.node.get_name(), + start_pos, + end_pos, + owner, + ), + self.ctx.get_node_key(&type_alias_stmt.type_name.id), + self.ctx + .current_package_info + .clone() + .unwrap() + .fully_qualified_name, + ); + Some(vec![type_alias_ref]) + } + + fn walk_assign_stmt(&mut self, assign_stmt: &'ctx ast::AssignStmt) -> Self::Result { + let mut value_symbols = vec![]; + for target in assign_stmt.targets.iter() { + let (start_pos, end_pos): Range = target.get_span_pos(); + let owner = self.ctx.owner_symbols.last().unwrap().clone(); + if target.node.paths.is_empty() { + let owner_fully_qualified_name = self + .gs + .get_symbols() + .get_fully_qualified_name(owner) + .unwrap(); + let value_name = target.node.get_name(); + let value_fully_qualified_name = owner_fully_qualified_name + "." + &value_name; + if !self + .ctx + .value_fully_qualified_name_set + .contains(&value_fully_qualified_name) + { + let value_ref = self.gs.get_symbols_mut().alloc_value_symbol( + ValueSymbol::new( + value_name.to_string(), + start_pos, + end_pos, + Some(owner), + true, + ), + self.ctx.get_node_key(&target.id), + self.ctx + .current_package_info + .clone() + .unwrap() + .fully_qualified_name, + ); + self.ctx + .value_fully_qualified_name_set + .insert(value_fully_qualified_name); + value_symbols.push(value_ref) + } + } + } + Some(value_symbols) + } + + fn walk_aug_assign_stmt(&mut self, _aug_assign_stmt: &'ctx ast::AugAssignStmt) -> Self::Result { + None + } + + fn walk_assert_stmt(&mut self, _assert_stmt: &'ctx ast::AssertStmt) -> Self::Result { + None + } + + fn walk_if_stmt(&mut self, if_stmt: &'ctx ast::IfStmt) -> Self::Result { + let mut all_symbols = vec![]; + for stmt in if_stmt.body.iter() { + let mut symbols = self.walk_stmt(&stmt.node); + if let Some(symbols) = &mut symbols { + all_symbols.append(symbols); + } + } + for stmt in if_stmt.orelse.iter() { + let mut symbols = self.walk_stmt(&stmt.node); + if let Some(symbols) = &mut symbols { + all_symbols.append(symbols); + } + } + Some(all_symbols) + } + + fn walk_import_stmt(&mut self, import_stmt: &'ctx ast::ImportStmt) -> Self::Result { + self.ctx + .current_module_info + .as_mut() + .unwrap() + .add_import_info(ImportInfo::new( + import_stmt.name.clone(), + import_stmt.path.node.clone(), + )); + + None + } + + fn walk_schema_stmt(&mut self, schema_stmt: &'ctx ast::SchemaStmt) -> Self::Result { + let (start_pos, end_pos): Range = schema_stmt.name.get_span_pos(); + let owner = self.ctx.owner_symbols.last().unwrap(); + let shcema_ref = self.gs.get_symbols_mut().alloc_schema_symbol( + SchemaSymbol::new(schema_stmt.name.node.clone(), start_pos, end_pos, *owner), + self.ctx.get_node_key(&schema_stmt.name.id), + self.ctx + .current_package_info + .clone() + .unwrap() + .fully_qualified_name, + ); + self.ctx.owner_symbols.push(shcema_ref); + + for stmt in schema_stmt.body.iter() { + let symbol_refs = self.walk_stmt(&stmt.node); + if let Some(symbol_refs) = symbol_refs { + for symbol_ref in symbol_refs { + if matches!(&symbol_ref.get_kind(), SymbolKind::Attribute) { + let full_attribute_name = self + .gs + .get_symbols() + .get_fully_qualified_name(symbol_ref) + .unwrap(); + self.ctx + .value_fully_qualified_name_set + .insert(full_attribute_name.clone()); + let attribute_name = + full_attribute_name.split(".").last().unwrap().to_string(); + + let schema_symbol = self + .gs + .get_symbols_mut() + .schemas + .get_mut(shcema_ref.get_id()) + .unwrap(); + if !schema_symbol.attributes.contains_key(&attribute_name) { + schema_symbol.attributes.insert(attribute_name, symbol_ref); + } + } + } + } + } + self.ctx.owner_symbols.pop(); + Some(vec![shcema_ref]) + } + + fn walk_rule_stmt(&mut self, rule_stmt: &'ctx ast::RuleStmt) -> Self::Result { + let (start_pos, end_pos): Range = rule_stmt.name.get_span_pos(); + let owner = self.ctx.owner_symbols.last().unwrap().clone(); + let rule_ref = self.gs.get_symbols_mut().alloc_rule_symbol( + RuleSymbol::new(rule_stmt.name.node.clone(), start_pos, end_pos, owner), + self.ctx.get_node_key(&rule_stmt.name.id), + self.ctx + .current_package_info + .clone() + .unwrap() + .fully_qualified_name, + ); + Some(vec![rule_ref]) + } + + fn walk_quant_expr(&mut self, _quant_expr: &'ctx ast::QuantExpr) -> Self::Result { + None + } + + fn walk_schema_attr(&mut self, schema_attr: &'ctx ast::SchemaAttr) -> Self::Result { + let (start_pos, end_pos): Range = schema_attr.name.get_span_pos(); + let owner = self.ctx.owner_symbols.last().unwrap().clone(); + let default_value = schema_attr + .value + .as_ref() + .map(|v| print_ast_node(ASTNode::Expr(v))); + let attribute_ref = self.gs.get_symbols_mut().alloc_attribute_symbol( + AttributeSymbol::new( + schema_attr.name.node.clone(), + start_pos, + end_pos, + owner, + schema_attr.is_optional, + default_value, + ), + self.ctx.get_node_key(&schema_attr.name.id), + self.ctx + .current_package_info + .clone() + .unwrap() + .fully_qualified_name, + ); + Some(vec![attribute_ref]) + } + + /// if else -> sup([body, orelse]) + fn walk_if_expr(&mut self, _if_expr: &'ctx ast::IfExpr) -> Self::Result { + None + } + + fn walk_unary_expr(&mut self, _unary_expr: &'ctx ast::UnaryExpr) -> Self::Result { + None + } + + fn walk_binary_expr(&mut self, _binary_expr: &'ctx ast::BinaryExpr) -> Self::Result { + None + } + + fn walk_selector_expr(&mut self, _selector_expr: &'ctx ast::SelectorExpr) -> Self::Result { + None + } + + fn walk_call_expr(&mut self, _call_expr: &'ctx ast::CallExpr) -> Self::Result { + None + } + + fn walk_subscript(&mut self, _subscript: &'ctx ast::Subscript) -> Self::Result { + None + } + + fn walk_paren_expr(&mut self, _paren_expr: &'ctx ast::ParenExpr) -> Self::Result { + None + } + + fn walk_list_expr(&mut self, _list_expr: &'ctx ast::ListExpr) -> Self::Result { + None + } + + fn walk_list_comp(&mut self, _list_comp: &'ctx ast::ListComp) -> Self::Result { + None + } + + fn walk_dict_comp(&mut self, _dict_comp: &'ctx ast::DictComp) -> Self::Result { + None + } + + fn walk_list_if_item_expr( + &mut self, + _list_if_item_expr: &'ctx ast::ListIfItemExpr, + ) -> Self::Result { + None + } + + fn walk_starred_expr(&mut self, _starred_expr: &'ctx ast::StarredExpr) -> Self::Result { + None + } + + fn walk_config_if_entry_expr( + &mut self, + _config_if_entry_expr: &'ctx ast::ConfigIfEntryExpr, + ) -> Self::Result { + None + } + + fn walk_comp_clause(&mut self, _comp_clause: &'ctx ast::CompClause) -> Self::Result { + None + } + + fn walk_schema_expr(&mut self, _schema_expr: &'ctx ast::SchemaExpr) -> Self::Result { + None + } + + fn walk_config_expr(&mut self, _config_expr: &'ctx ast::ConfigExpr) -> Self::Result { + None + } + + fn walk_check_expr(&mut self, _check_expr: &'ctx ast::CheckExpr) -> Self::Result { + None + } + + fn walk_lambda_expr(&mut self, _lambda_expr: &'ctx ast::LambdaExpr) -> Self::Result { + None + } + + fn walk_keyword(&mut self, _keyword: &'ctx ast::Keyword) -> Self::Result { + None + } + + fn walk_arguments(&mut self, _arguments: &'ctx ast::Arguments) -> Self::Result { + None + } + + fn walk_compare(&mut self, _compare: &'ctx ast::Compare) -> Self::Result { + None + } + + fn walk_identifier(&mut self, _identifier: &'ctx ast::Identifier) -> Self::Result { + None + } + + fn walk_target(&mut self, _target: &'ctx ast::Target) -> Self::Result { + None + } + + fn walk_number_lit(&mut self, _number_lit: &'ctx ast::NumberLit) -> Self::Result { + None + } + + fn walk_string_lit(&mut self, _string_lit: &'ctx ast::StringLit) -> Self::Result { + None + } + + fn walk_name_constant_lit( + &mut self, + _name_constant_lit: &'ctx ast::NameConstantLit, + ) -> Self::Result { + None + } + + fn walk_joined_string(&mut self, _joined_string: &'ctx ast::JoinedString) -> Self::Result { + None + } + + fn walk_formatted_value( + &mut self, + _formatted_value: &'ctx ast::FormattedValue, + ) -> Self::Result { + None + } + + fn walk_comment(&mut self, _comment: &'ctx ast::Comment) -> Self::Result { + None + } + + fn walk_missing_expr(&mut self, _missing_expr: &'ctx ast::MissingExpr) -> Self::Result { + None + } +} diff --git a/kclvm/sema/src/namer/test_data/import_test/a.k b/kclvm/sema/src/namer/test_data/import_test/a.k new file mode 100644 index 000000000..8b6a81409 --- /dev/null +++ b/kclvm/sema/src/namer/test_data/import_test/a.k @@ -0,0 +1,4 @@ +_a = 1 +schema Person: + name: str + age: int diff --git a/kclvm/sema/src/namer/test_data/import_test/b.k b/kclvm/sema/src/namer/test_data/import_test/b.k new file mode 100644 index 000000000..79fa8ccc7 --- /dev/null +++ b/kclvm/sema/src/namer/test_data/import_test/b.k @@ -0,0 +1 @@ +_b = 1 diff --git a/kclvm/sema/src/namer/test_data/import_test/c.k b/kclvm/sema/src/namer/test_data/import_test/c.k new file mode 100644 index 000000000..f4832d10f --- /dev/null +++ b/kclvm/sema/src/namer/test_data/import_test/c.k @@ -0,0 +1,2 @@ +schema TestOfMixin: + age?: int diff --git a/kclvm/sema/src/namer/test_data/import_test/d.k b/kclvm/sema/src/namer/test_data/import_test/d.k new file mode 100644 index 000000000..78dcd8b21 --- /dev/null +++ b/kclvm/sema/src/namer/test_data/import_test/d.k @@ -0,0 +1,2 @@ +schema Parent: + age1?: int diff --git a/kclvm/sema/src/namer/test_data/import_test/e.k b/kclvm/sema/src/namer/test_data/import_test/e.k new file mode 100644 index 000000000..98fabf8f4 --- /dev/null +++ b/kclvm/sema/src/namer/test_data/import_test/e.k @@ -0,0 +1,2 @@ +schema UnionType: + a?: int diff --git a/kclvm/sema/src/namer/test_data/import_test/f.k b/kclvm/sema/src/namer/test_data/import_test/f.k new file mode 100644 index 000000000..65a0fa043 --- /dev/null +++ b/kclvm/sema/src/namer/test_data/import_test/f.k @@ -0,0 +1,2 @@ +schema UnionType: + b?: int diff --git a/test/test_units/test_kclvm/test_tools/test_lint/test_checker/test_data/kcl.mod b/kclvm/sema/src/namer/test_data/kcl.mod similarity index 100% rename from test/test_units/test_kclvm/test_tools/test_lint/test_checker/test_data/kcl.mod rename to kclvm/sema/src/namer/test_data/kcl.mod diff --git a/kclvm/sema/src/namer/test_data/pkg/pkg.k b/kclvm/sema/src/namer/test_data/pkg/pkg.k new file mode 100644 index 000000000..f8c946eff --- /dev/null +++ b/kclvm/sema/src/namer/test_data/pkg/pkg.k @@ -0,0 +1,5 @@ +schema Name: + name?: str + +schema Person: + name: Name = Name {name = "Alice"} diff --git a/kclvm/sema/src/namer/test_data/schema_symbols.k b/kclvm/sema/src/namer/test_data/schema_symbols.k new file mode 100644 index 000000000..5452a4a94 --- /dev/null +++ b/kclvm/sema/src/namer/test_data/schema_symbols.k @@ -0,0 +1,32 @@ +import import_test.a +import import_test.b +import import_test.c +import import_test.d +import import_test.e +import import_test.f as g +import pkg +import regex + +schema Main(d.Parent): + mixin [c.TestOfMixin] + name?: str + age?: int = 18 + person?: a.Person + list_union_type: [e.UnionType|int] + dict_union_type: {g.UnionType|int:float} + + check: + regex.match(name, r"[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*") if name + +if a._a > 1: + _c = 1 +elif a._a == 1: + _c = 2 +else: + _c = 3 + +p = Main{ + age = b._b +} + +person = pkg.Person {} diff --git a/kclvm/sema/src/pre_process/config.rs b/kclvm/sema/src/pre_process/config.rs index 32611334e..ad4c7c6cf 100644 --- a/kclvm/sema/src/pre_process/config.rs +++ b/kclvm/sema/src/pre_process/config.rs @@ -1,3 +1,4 @@ +use crate::info::is_private_field; use indexmap::{IndexMap, IndexSet}; use kclvm_ast::walker::MutSelfMutWalker; use kclvm_ast::{ast, walk_if_mut}; @@ -11,11 +12,30 @@ impl ConfigNestAttrTransformer { pub fn walk_config_entry(&mut self, config_entry: &mut Box>) { if let Some(key) = config_entry.node.key.as_mut() { if let ast::Expr::Identifier(identifier) = &mut key.node { + // desuger config expr, e.g., desuger + // ``` + // foo = Foo { + // bar.baz : xxx + // } + // ``` + // to: + // ``` + // foo = Foo { + // bar : Bar { + // baz : xxx + // } + // } + // ``` if identifier.names.len() > 1 { let mut names = identifier.names.clone(); let names = &mut names[1..]; names.reverse(); identifier.names = vec![identifier.names[0].clone()]; + key.filename = identifier.names[0].filename.clone(); + key.line = identifier.names[0].line; + key.column = identifier.names[0].column; + key.end_line = identifier.names[0].end_line; + key.end_column = identifier.names[0].end_column; let mut value = config_entry.node.value.clone(); for (i, name) in names.iter().enumerate() { @@ -28,11 +48,11 @@ impl ConfigNestAttrTransformer { let entry_value = ast::ConfigEntry { key: Some(Box::new(ast::Node::new( ast::Expr::Identifier(name_node), - key.filename.clone(), - key.line, - key.column, - key.end_line, - key.end_column, + name.filename.clone(), + name.line, + name.column, + name.end_line, + name.end_column, ))), value: value.clone(), operation: if is_last_item { @@ -40,23 +60,22 @@ impl ConfigNestAttrTransformer { } else { ast::ConfigEntryOperation::Union }, - insert_index: -1, }; let config_expr = ast::ConfigExpr { items: vec![Box::new(ast::Node::new( entry_value, - key.filename.clone(), - key.line, - key.column, - key.end_line, - key.end_column, + config_entry.filename.clone(), + name.line, + name.column, + config_entry.end_line, + config_entry.end_column, ))], }; value = Box::new(ast::Node::new( ast::Expr::Config(config_expr), value.filename.clone(), - value.line, - value.column, + name.line, + name.column, value.end_line, value.end_column, )) @@ -88,7 +107,7 @@ impl<'ctx> MutSelfMutWalker<'ctx> for ConfigNestAttrTransformer { } } -#[derive(Debug)] +#[derive(Debug, Default)] struct ConfigMergeTransformer {} #[derive(Debug)] @@ -99,62 +118,73 @@ enum ConfigMergeKind { impl ConfigMergeTransformer { pub fn merge(&mut self, program: &mut ast::Program) { - // {name: (filename, index, kind)} - let mut name_declaration_mapping: IndexMap> = - IndexMap::default(); + // {name: (filename, module index in main package, statement index in the module body, kind)} + // module index is to prevent same filename in main package + let mut name_declaration_mapping: IndexMap< + String, + Vec<(String, usize, usize, ConfigMergeKind)>, + > = IndexMap::default(); // 1. Collect merged config - if let Some(modules) = program.pkgs.get_mut(kclvm_ast::MAIN_PKG) { - for module in modules { - for (i, stmt) in module.body.iter_mut().enumerate() { - match &mut stmt.node { - ast::Stmt::Unification(unification_stmt) => { - let name = &unification_stmt.target.node.names[0]; - match name_declaration_mapping.get_mut(name) { - Some(declarations) => declarations.push(( - module.filename.to_string(), - i, - ConfigMergeKind::Union, - )), - None => { - name_declaration_mapping.insert( - name.to_string(), - vec![( - module.filename.to_string(), - i, - ConfigMergeKind::Union, - )], - ); - } + let modules = program.get_modules_for_pkg(kclvm_ast::MAIN_PKG); + for (module_id, module) in modules.iter().enumerate() { + let mut module = module.write().expect("Failed to acquire module lock"); + let filename = module.filename.to_string(); + for (i, stmt) in module.body.iter_mut().enumerate() { + match &mut stmt.node { + ast::Stmt::Unification(unification_stmt) + if !unification_stmt.target.node.names.is_empty() => + { + let name = &unification_stmt.target.node.names[0].node; + match name_declaration_mapping.get_mut(name) { + Some(declarations) => declarations.push(( + filename.clone(), + module_id, + i, + ConfigMergeKind::Union, + )), + None => { + name_declaration_mapping.insert( + name.to_string(), + vec![(filename.clone(), module_id, i, ConfigMergeKind::Union)], + ); } } - ast::Stmt::Assign(assign_stmt) => { - if let ast::Expr::Schema(_) = assign_stmt.value.node { - for target in &assign_stmt.targets { - if target.node.names.len() == 1 { - let name = &target.node.names[0]; - match name_declaration_mapping.get_mut(name) { - Some(declarations) => declarations.push(( - module.filename.to_string(), - i, - ConfigMergeKind::Override, - )), - None => { - name_declaration_mapping.insert( - name.to_string(), - vec![( - module.filename.to_string(), - i, - ConfigMergeKind::Override, - )], - ); + } + ast::Stmt::Assign(assign_stmt) => { + if let ast::Expr::Schema(_) = assign_stmt.value.node { + for target in &assign_stmt.targets { + if target.node.paths.is_empty() { + let name = &target.node.name.node; + match name_declaration_mapping.get_mut(name) { + Some(declarations) => { + // A hidden var is mutable. + if is_private_field(name) { + declarations.clear(); + declarations.push(( + filename.clone(), + module_id, + i, + ConfigMergeKind::Override, + )) } } + None => { + name_declaration_mapping.insert( + name.to_string(), + vec![( + filename.clone(), + module_id, + i, + ConfigMergeKind::Override, + )], + ); + } } } } } - _ => {} } + _ => {} } } } @@ -162,107 +192,107 @@ impl ConfigMergeTransformer { for (_, index_list) in &name_declaration_mapping { let index_len = index_list.len(); if index_len > 1 { - let (filename, merged_index, merged_kind) = index_list.last().unwrap(); + let (filename, merged_id, merged_index, merged_kind) = index_list.last().unwrap(); let mut items: Vec> = vec![]; - for (merged_filename, index, kind) in index_list { - if let Some(modules) = program.pkgs.get_mut(kclvm_ast::MAIN_PKG) { - for module in modules { - if &module.filename == merged_filename { - let stmt = module.body.get_mut(*index).unwrap(); - match &mut stmt.node { - ast::Stmt::Unification(unification_stmt) - if matches!(kind, ConfigMergeKind::Union) => + for (merged_filename, merged_id, index, kind) in index_list { + let modules = program.get_modules_for_pkg(kclvm_ast::MAIN_PKG); + for (module_id, module) in modules.iter().enumerate() { + let mut module = module.write().expect("Failed to acquire module lock"); + if &module.filename == merged_filename && module_id == *merged_id { + let stmt = module.body.get_mut(*index).unwrap(); + match &mut stmt.node { + ast::Stmt::Unification(unification_stmt) + if matches!(kind, ConfigMergeKind::Union) => + { + if let ast::Expr::Config(config_expr) = + &mut unification_stmt.value.node.config.node + { + let mut config_items = config_expr.items.clone(); + items.append(&mut config_items); + } + } + ast::Stmt::Assign(assign_stmt) + if matches!(kind, ConfigMergeKind::Override) => + { + if let ast::Expr::Schema(schema_expr) = + &mut assign_stmt.value.node { if let ast::Expr::Config(config_expr) = - &mut unification_stmt.value.node.config.node + &mut schema_expr.config.node { let mut config_items = config_expr.items.clone(); items.append(&mut config_items); } } - ast::Stmt::Assign(assign_stmt) - if matches!(kind, ConfigMergeKind::Override) => - { - if let ast::Expr::Schema(schema_expr) = - &mut assign_stmt.value.node - { - if let ast::Expr::Config(config_expr) = - &mut schema_expr.config.node - { - let mut config_items = config_expr.items.clone(); - items.append(&mut config_items); - } - } - } - _ => { - bug!("mismatch ast node and config merge kind: {:?}", kind) - } + } + _ => { + bug!("mismatch ast node and config merge kind: {:?}", kind) } } } } } - if let Some(modules) = program.pkgs.get_mut(kclvm_ast::MAIN_PKG) { - for module in modules { - if &module.filename == filename { - if let Some(stmt) = module.body.get_mut(*merged_index) { - match &mut stmt.node { - ast::Stmt::Unification(unification_stmt) - if matches!(merged_kind, ConfigMergeKind::Union) => + for (module_id, module) in modules.iter().enumerate() { + let mut module = module.write().expect("Failed to acquire module lock"); + if &module.filename == filename && module_id == *merged_id { + if let Some(stmt) = module.body.get_mut(*merged_index) { + match &mut stmt.node { + ast::Stmt::Unification(unification_stmt) + if matches!(merged_kind, ConfigMergeKind::Union) => + { + if let ast::Expr::Config(config_expr) = + &mut unification_stmt.value.node.config.node { - if let ast::Expr::Config(config_expr) = - &mut unification_stmt.value.node.config.node - { - config_expr.items = unify_config_entries(&items); - } + config_expr.items = unify_config_entries(&items); } - ast::Stmt::Assign(assign_stmt) - if matches!(merged_kind, ConfigMergeKind::Override) => + } + ast::Stmt::Assign(assign_stmt) + if matches!(merged_kind, ConfigMergeKind::Override) => + { + if let ast::Expr::Schema(schema_expr) = + &mut assign_stmt.value.node { - if let ast::Expr::Schema(schema_expr) = - &mut assign_stmt.value.node + if let ast::Expr::Config(config_expr) = + &mut schema_expr.config.node { - if let ast::Expr::Config(config_expr) = - &mut schema_expr.config.node - { - config_expr.items = unify_config_entries(&items); - } + config_expr.items = unify_config_entries(&items); } } - _ => bug!( - "mismatch ast node and config merge kind: {:?}", - merged_kind - ), } + _ => bug!( + "mismatch ast node and config merge kind: {:?}", + merged_kind + ), } - break; } + break; } } } } // 3. Delete redundant config. - if let Some(modules) = program.pkgs.get_mut(kclvm_ast::MAIN_PKG) { - for module in modules { - let mut delete_index_set: IndexSet = IndexSet::default(); - for (_, index_list) in &name_declaration_mapping { - let index_len = index_list.len(); - if index_len > 1 { - for (filename, index, _) in &index_list[..index_len - 1] { - if &module.filename == filename { - delete_index_set.insert(*index); - } + for (i, module) in modules.iter().enumerate() { + let mut module = module.write().expect("Failed to acquire module lock"); + let mut delete_index_set: IndexSet = IndexSet::default(); + for (_, index_list) in &name_declaration_mapping { + let index_len = index_list.len(); + if index_len > 1 { + for (filename, module_id, index, _) in &index_list[..index_len - 1] { + // Use module filename and index to prevent the same compile filenames + // in the main package. + if &module.filename == filename && i == *module_id { + delete_index_set.insert(*index); } } } - let mut body: Vec<(usize, &ast::NodeRef)> = - module.body.iter().enumerate().collect(); - body.retain(|(idx, _)| !delete_index_set.contains(idx)); - module.body = body - .iter() - .map(|(_, stmt)| (*stmt).clone()) - .collect::>>(); } + let mut body: Vec<(usize, &ast::NodeRef)> = + module.body.iter().enumerate().collect(); + body.retain(|(idx, _)| !delete_index_set.contains(idx)); + module.body = body + .iter() + .map(|(_, stmt)| (*stmt).clone()) + .collect::>>(); } } } @@ -284,7 +314,14 @@ fn unify_config_entries( }; let entry = entry.clone(); match bucket.get_mut(&name) { - Some(values) => values.push(entry), + Some(values) => { + // If the attribute operation is override, clear all previous entries and override + // with current entry. + if let ast::ConfigEntryOperation::Override = entry.node.operation { + values.clear(); + } + values.push(entry); + } None => { let values = vec![entry]; bucket.insert(name, values); @@ -292,70 +329,8 @@ fn unify_config_entries( } } let mut entries = vec![]; - for (key, items) in bucket.iter_mut() { - if key == NAME_NONE_BUCKET_KEY { - entries.append(items); - } else { - let mut schema_index = None; - for (i, item) in items.iter().enumerate() { - if let ast::Expr::Schema(_) = item.node.value.node { - schema_index = Some(i); - break; - } - } - match schema_index { - Some(index) => { - let mut merged_schema = items[index].as_ref().clone(); - for (i, item) in items.iter().enumerate() { - match &item.node.value.node { - ast::Expr::Schema(item_schema_expr) => { - if let ast::Expr::Schema(schema_expr) = - &mut merged_schema.node.value.node - { - if let ast::Expr::Config(schema_config) = - &mut schema_expr.config.node - { - if let ast::Expr::Config(config_expr) = - &item_schema_expr.config.node - { - if i < index { - let mut items = config_expr.items.clone(); - items.append(&mut schema_config.items); - schema_config.items = items; - } else if i > index { - let mut items = config_expr.items.clone(); - schema_config.items.append(&mut items); - } - } - } - } - } - ast::Expr::Config(item_config_expr) => { - if let ast::Expr::Schema(schema_expr) = - &mut merged_schema.node.value.node - { - if let ast::Expr::Config(schema_config) = - &mut schema_expr.config.node - { - if i < index { - let mut items = item_config_expr.items.clone(); - items.append(&mut schema_config.items); - schema_config.items = items; - } else if i > index { - let mut items = item_config_expr.items.clone(); - schema_config.items.append(&mut items); - } - } - } - } - _ => entries.push(item.clone()), - } - } - entries.push(Box::new(merged_schema)); - } - None => entries.append(items), - }; - } + for (_, items) in bucket.iter_mut() { + entries.append(items); } // Unify config entries recursively. for entry in &mut entries { @@ -374,9 +349,10 @@ fn unify_config_entries( entries } -/// Merge program +/// Merge program for multiple file config. +#[inline] pub fn merge_program(program: &mut ast::Program) { - let mut merger = ConfigMergeTransformer {}; + let mut merger = ConfigMergeTransformer::default(); merger.merge(program); } diff --git a/kclvm/sema/src/pre_process/identifier.rs b/kclvm/sema/src/pre_process/identifier.rs index 2a6fc9d84..3149fcff7 100644 --- a/kclvm/sema/src/pre_process/identifier.rs +++ b/kclvm/sema/src/pre_process/identifier.rs @@ -1,6 +1,6 @@ use crate::info::is_private_field; -use crate::resolver::pos::GetPos; use indexmap::{IndexMap, IndexSet}; +use kclvm_ast::pos::GetPos; use kclvm_ast::walker::MutSelfMutWalker; use kclvm_ast::{ast, walk_if_mut, walk_list_mut}; use kclvm_error::*; @@ -13,36 +13,16 @@ struct QualifiedIdentifierTransformer { pub global_names: IndexMap, pub local_vars: IndexSet, pub scope_level: usize, - pub handler: Handler, } impl<'ctx> MutSelfMutWalker<'ctx> for QualifiedIdentifierTransformer { fn walk_rule_stmt(&mut self, rule_stmt: &'ctx mut ast::RuleStmt) { let name = &rule_stmt.name.node; - if !self.global_names.contains_key(name) { - if self.scope_level == 0 { - self.global_names - .insert(name.to_string(), rule_stmt.name.get_pos()); - } - } else { - self.handler.add_error( - ErrorKind::UniqueKeyError, - &[ - Message { - pos: rule_stmt.name.get_pos(), - style: Style::LineAndColumn, - message: format!("Unique key error name '{}'", name), - note: None, - }, - Message { - pos: self.global_names.get(name).unwrap().clone(), - style: Style::LineAndColumn, - message: format!("The variable '{}' is declared here firstly", name), - note: None, - }, - ], - ); + if !self.global_names.contains_key(name) && self.scope_level == 0 { + self.global_names + .insert(name.to_string(), rule_stmt.name.get_pos()); } + walk_list_mut!(self, walk_identifier, rule_stmt.parent_rules); walk_list_mut!(self, walk_call_expr, rule_stmt.decorators); walk_if_mut!(self, walk_arguments, rule_stmt.args); @@ -53,29 +33,9 @@ impl<'ctx> MutSelfMutWalker<'ctx> for QualifiedIdentifierTransformer { } fn walk_schema_stmt(&mut self, schema_stmt: &'ctx mut ast::SchemaStmt) { let name = &schema_stmt.name.node; - if !self.global_names.contains_key(name) { - if self.scope_level == 0 { - self.global_names - .insert(name.to_string(), schema_stmt.name.get_pos()); - } - } else { - self.handler.add_error( - ErrorKind::UniqueKeyError, - &[ - Message { - pos: schema_stmt.name.get_pos(), - style: Style::LineAndColumn, - message: format!("Unique key error name '{}'", name), - note: None, - }, - Message { - pos: self.global_names.get(name).unwrap().clone(), - style: Style::LineAndColumn, - message: format!("The variable '{}' is declared here firstly", name), - note: None, - }, - ], - ); + if !self.global_names.contains_key(name) && self.scope_level == 0 { + self.global_names + .insert(name.to_string(), schema_stmt.name.get_pos()); } walk_if_mut!(self, walk_identifier, schema_stmt.parent_name); walk_if_mut!(self, walk_identifier, schema_stmt.for_host_name); @@ -94,64 +54,24 @@ impl<'ctx> MutSelfMutWalker<'ctx> for QualifiedIdentifierTransformer { fn walk_assign_stmt(&mut self, assign_stmt: &'ctx mut ast::AssignStmt) { let is_config = matches!(assign_stmt.value.node, ast::Expr::Schema(_)); for target in &assign_stmt.targets { - let name = &target.node.names[0]; - if is_private_field(name) || !self.global_names.contains_key(name) || is_config { - if self.scope_level == 0 { - self.global_names.insert(name.to_string(), target.get_pos()); - } - } else { - self.handler.add_error( - ErrorKind::UniqueKeyError, - &[ - Message { - pos: target.get_pos(), - style: Style::LineAndColumn, - message: format!("Unique key error name '{}'", name), - note: None, - }, - Message { - pos: self.global_names.get(name).unwrap().clone(), - style: Style::LineAndColumn, - message: format!("The variable '{}' is declared here firstly", name), - note: None, - }, - ], - ); + let name = &target.node.name.node; + if (is_private_field(name) || !self.global_names.contains_key(name) || is_config) + && self.scope_level == 0 + { + self.global_names.insert(name.to_string(), target.get_pos()); } } self.walk_expr(&mut assign_stmt.value.node); } fn walk_aug_assign_stmt(&mut self, aug_assign_stmt: &'ctx mut ast::AugAssignStmt) { let is_config = matches!(aug_assign_stmt.value.node, ast::Expr::Schema(_)); - let name = &aug_assign_stmt.target.node.names[0]; + let name = &aug_assign_stmt.target.node.name.node; if is_private_field(name) || !self.global_names.contains_key(name) || is_config { if self.scope_level == 0 { self.global_names .insert(name.to_string(), aug_assign_stmt.target.get_pos()); } - } else { - self.handler.add_error( - ErrorKind::ImmutableError, - &[ - Message { - pos: aug_assign_stmt.target.get_pos(), - style: Style::LineAndColumn, - message: format!( - "Immutable variable '{}' is modified during compiling", - name - ), - note: None, - }, - Message { - pos: self.global_names.get(name).unwrap().clone(), - style: Style::LineAndColumn, - message: format!("The variable '{}' is declared here firstly", name), - note: None, - }, - ], - ); } - self.walk_expr(&mut aug_assign_stmt.value.node); } fn walk_schema_expr(&mut self, schema_expr: &'ctx mut ast::SchemaExpr) { @@ -170,7 +90,10 @@ impl<'ctx> MutSelfMutWalker<'ctx> for QualifiedIdentifierTransformer { fn walk_list_comp(&mut self, list_comp: &'ctx mut ast::ListComp) { for gen in &mut list_comp.generators { for target in &gen.node.targets { - self.local_vars.insert(target.node.names[0].to_string()); + if !target.node.names.is_empty() { + self.local_vars + .insert(target.node.names[0].node.to_string()); + } } } self.walk_expr(&mut list_comp.elt.node); @@ -180,7 +103,10 @@ impl<'ctx> MutSelfMutWalker<'ctx> for QualifiedIdentifierTransformer { fn walk_dict_comp(&mut self, dict_comp: &'ctx mut ast::DictComp) { for gen in &dict_comp.generators { for target in &gen.node.targets { - self.local_vars.insert(target.node.names[0].to_string()); + if !target.node.names.is_empty() { + self.local_vars + .insert(target.node.names[0].node.to_string()); + } } } if let Some(key) = dict_comp.entry.key.as_deref_mut() { @@ -192,7 +118,10 @@ impl<'ctx> MutSelfMutWalker<'ctx> for QualifiedIdentifierTransformer { } fn walk_quant_expr(&mut self, quant_expr: &'ctx mut ast::QuantExpr) { for target in &quant_expr.variables { - self.local_vars.insert(target.node.names[0].to_string()); + if !target.node.names.is_empty() { + self.local_vars + .insert(target.node.names[0].node.to_string()); + } } self.walk_expr(&mut quant_expr.target.node); self.walk_expr(&mut quant_expr.test.node); @@ -202,7 +131,7 @@ impl<'ctx> MutSelfMutWalker<'ctx> for QualifiedIdentifierTransformer { fn walk_identifier(&mut self, identifier: &'ctx mut ast::Identifier) { if identifier.names.len() >= 2 { // skip global name and generator local variables in list/dict comp and quant expression - let name = &identifier.names[0]; + let name = &identifier.names[0].node; if !self.global_names.contains_key(name) && !self.local_vars.contains(name) { if let Some(pkgpath) = self.import_names.get(name) { identifier.pkgpath = pkgpath.clone() @@ -210,6 +139,17 @@ impl<'ctx> MutSelfMutWalker<'ctx> for QualifiedIdentifierTransformer { } } } + fn walk_target(&mut self, target: &'ctx mut ast::Target) { + if !target.paths.is_empty() { + // skip global name and generator local variables in list/dict comp and quant expression + let name = &target.name.node; + if !self.global_names.contains_key(name) && !self.local_vars.contains(name) { + if let Some(pkgpath) = self.import_names.get(name) { + target.pkgpath = pkgpath.clone() + } + } + } + } } #[inline] @@ -224,15 +164,28 @@ fn remove_raw_ident_prefix(name: &str) -> String { struct RawIdentifierTransformer; impl<'ctx> MutSelfMutWalker<'ctx> for RawIdentifierTransformer { + fn walk_target(&mut self, target: &'ctx mut ast::Target) { + target.name.node = remove_raw_ident_prefix(&target.name.node); + for path in target.paths.iter_mut() { + match path { + ast::MemberOrIndex::Member(member) => { + member.node = remove_raw_ident_prefix(&member.node); + } + ast::MemberOrIndex::Index(index) => self.walk_expr(&mut index.node), + } + } + } fn walk_identifier(&mut self, identifier: &'ctx mut ast::Identifier) { - identifier.names = identifier - .names - .iter() - .map(|n| remove_raw_ident_prefix(n)) - .collect::>(); + for name in identifier.names.iter_mut() { + name.node = remove_raw_ident_prefix(&name.node); + } } fn walk_schema_attr(&mut self, schema_attr: &'ctx mut ast::SchemaAttr) { - schema_attr.name.node = remove_raw_ident_prefix(&schema_attr.name.node); + // If the attribute is an identifier and then fix it. + // Note that we do not fix a string-like attribute e.g., `"$name"` + if schema_attr.is_ident_attr() { + schema_attr.name.node = remove_raw_ident_prefix(&schema_attr.name.node); + } walk_list_mut!(self, walk_call_expr, schema_attr.decorators); walk_if_mut!(self, walk_expr, schema_attr.value); } @@ -259,11 +212,11 @@ impl<'ctx> MutSelfMutWalker<'ctx> for RawIdentifierTransformer { walk_if_mut!(self, walk_identifier, rule_stmt.for_host_name); } fn walk_import_stmt(&mut self, import_stmt: &'ctx mut ast::ImportStmt) { - if let Some(name) = import_stmt.asname.as_mut() { - *name = remove_raw_ident_prefix(name); + if let Some(name) = &mut import_stmt.asname { + name.node = remove_raw_ident_prefix(&name.node); } import_stmt.name = remove_raw_ident_prefix(&import_stmt.name); - import_stmt.path = remove_raw_ident_prefix(&import_stmt.path); + import_stmt.path.node = remove_raw_ident_prefix(&import_stmt.path.node); } } @@ -277,19 +230,19 @@ pub fn fix_qualified_identifier<'ctx>( // 0. init import names. for stmt in &module.body { if let ast::Stmt::Import(import_stmt) = &stmt.node { - import_names.insert(import_stmt.name.clone(), import_stmt.path.clone()); + import_names.insert(import_stmt.name.clone(), import_stmt.path.node.clone()); } } - // 1. fix_global_ident - let mut global_names_walker = QualifiedIdentifierTransformer { + // 1. fix qualified identifier + let mut walker = QualifiedIdentifierTransformer { import_names: import_names.clone(), ..Default::default() }; - global_names_walker.walk_module(module); - global_names_walker.handler.abort_if_any_errors(); + walker.walk_module(module); } /// Fix AST raw identifier prefix `$`, e.g., $filter -> filter +#[inline] pub fn fix_raw_identifier_prefix(module: &'_ mut ast::Module) { RawIdentifierTransformer::default().walk_module(module); } diff --git a/kclvm/sema/src/pre_process/lit_ty_default_value.rs b/kclvm/sema/src/pre_process/lit_ty_default_value.rs new file mode 100644 index 000000000..1d91aef52 --- /dev/null +++ b/kclvm/sema/src/pre_process/lit_ty_default_value.rs @@ -0,0 +1,89 @@ +use kclvm_ast::ast; +use kclvm_ast::walker::MutSelfMutWalker; + +#[derive(Default)] +struct LitTypeDefaultValueTransformer; + +impl<'ctx> MutSelfMutWalker<'ctx> for LitTypeDefaultValueTransformer { + fn walk_schema_attr(&mut self, schema_attr: &'ctx mut ast::SchemaAttr) { + if schema_attr.value.is_none() && !schema_attr.is_optional { + if let ast::Type::Literal(literal_ty) = &schema_attr.ty.node { + let filename = schema_attr.ty.filename.clone(); + let line = schema_attr.ty.end_line; + // Append ` = ` width for th column. + let column = schema_attr.ty.end_column + 3; + schema_attr.op = Some(ast::AugOp::Assign); + match literal_ty { + ast::LiteralType::Bool(val) => { + let column_offset = if *val { 4 } else { 5 }; + schema_attr.value = Some(Box::new(ast::Node::new( + ast::Expr::NameConstantLit(ast::NameConstantLit { + value: if *val { + ast::NameConstant::True + } else { + ast::NameConstant::False + }, + }), + filename, + line, + column, + line, + column + column_offset, + ))); + } + ast::LiteralType::Int(val) => { + let value = val.value.to_string(); + let mut column_offset = value.len() as u64; + if let Some(suffix) = &val.suffix { + column_offset += suffix.value().len() as u64 + } + schema_attr.value = Some(Box::new(ast::Node::new( + ast::Expr::NumberLit(ast::NumberLit { + binary_suffix: val.suffix.clone(), + value: ast::NumberLitValue::Int(val.value), + }), + filename, + line, + column, + line, + column + column_offset, + ))); + } + ast::LiteralType::Float(val) => { + let value = kclvm_runtime::float_to_string(*val); + let column_offset = value.len() as u64; + schema_attr.value = Some(Box::new(ast::Node::new( + ast::Expr::NumberLit(ast::NumberLit { + binary_suffix: None, + value: ast::NumberLitValue::Float(*val), + }), + filename, + line, + column, + line, + column + column_offset, + ))); + } + ast::LiteralType::Str(val) => { + let value: ast::StringLit = val.to_string().into(); + let column_offset = value.raw_value.len() as u64; + schema_attr.value = Some(Box::new(ast::Node::new( + ast::Expr::StringLit(value), + filename, + line, + column, + line, + column + column_offset, + ))); + } + } + } + } + } +} + +/// Fix literal type default value. e.g., `a: "value"` -> `a: "value" = "value"`. +#[inline] +pub fn fix_lit_ty_default_value(module: &'_ mut ast::Module) { + LitTypeDefaultValueTransformer::default().walk_module(module); +} diff --git a/kclvm/sema/src/pre_process/mod.rs b/kclvm/sema/src/pre_process/mod.rs index 58a858bcb..d2474ca37 100644 --- a/kclvm/sema/src/pre_process/mod.rs +++ b/kclvm/sema/src/pre_process/mod.rs @@ -1,5 +1,7 @@ mod config; mod identifier; +mod lit_ty_default_value; +mod multi_assign; use indexmap::IndexMap; use kclvm_ast::ast; @@ -9,29 +11,45 @@ mod tests; pub use config::{fix_config_expr_nest_attr, merge_program}; pub use identifier::{fix_qualified_identifier, fix_raw_identifier_prefix}; +pub use lit_ty_default_value::fix_lit_ty_default_value; +pub use multi_assign::transform_multi_assign; + +use crate::resolver::Options; /// Pre-process AST program. -pub fn pre_process_program(program: &mut ast::Program) { - for (pkgpath, modules) in program.pkgs.iter_mut() { +pub fn pre_process_program(program: &mut ast::Program, opts: &Options) { + for (pkgpath, modules) in program.pkgs.iter() { let mut import_names = IndexMap::default(); if pkgpath == kclvm_ast::MAIN_PKG { - for module in modules.iter_mut() { + for module in modules.iter() { + let module = program + .get_module(module) + .expect("Failed to acquire module lock") + .expect(&format!("module {:?} not found in program", module)); for stmt in &module.body { if let ast::Stmt::Import(import_stmt) = &stmt.node { - import_names.insert(import_stmt.name.clone(), import_stmt.path.clone()); + import_names + .insert(import_stmt.name.clone(), import_stmt.path.node.clone()); } } } } - for module in modules.iter_mut() { + for module in modules.iter() { + let mut module = program + .get_module_mut(module) + .expect("Failed to acquire module lock") + .expect(&format!("module {:?} not found in program", module)); if pkgpath != kclvm_ast::MAIN_PKG { import_names.clear(); } // First we should transform the raw identifier to avoid raw identifier that happens to be a package path. - fix_raw_identifier_prefix(module); - fix_qualified_identifier(module, &mut import_names); - fix_config_expr_nest_attr(module); + fix_raw_identifier_prefix(&mut module); + fix_qualified_identifier(&mut module, &mut import_names); + fix_config_expr_nest_attr(&mut module); + fix_lit_ty_default_value(&mut module); } } - merge_program(program); + if opts.merge_program { + merge_program(program); + } } diff --git a/kclvm/sema/src/pre_process/multi_assign.rs b/kclvm/sema/src/pre_process/multi_assign.rs new file mode 100644 index 000000000..5425fa8ca --- /dev/null +++ b/kclvm/sema/src/pre_process/multi_assign.rs @@ -0,0 +1,96 @@ +use std::collections::HashMap; + +use kclvm_ast::{ast, walker::MutSelfMutWalker}; + +/// Transform AST and split multi target assign statements to multiple assign statements. +/// +/// # Examples +/// +/// ``` +/// use kclvm_parser::parse_file_force_errors; +/// use kclvm_sema::pre_process::transform_multi_assign; +/// +/// let mut module = parse_file_force_errors("", Some("a = b = Config {}".to_string())).unwrap(); +/// assert_eq!(module.body.len(), 1); +/// transform_multi_assign(&mut module); +/// assert_eq!(module.body.len(), 2); +/// ``` +pub fn transform_multi_assign(m: &mut ast::Module) { + let mut transformer = MultiAssignTransformer::default(); + transformer.walk_module(m); + let mut insert_count = 0; + for (index, assign_stmt_list) in transformer.multi_assign_mapping { + // Get the origin assign statement insert index in AST module body with offset. + // offset denotes the sum of the number of assigned stmt has been inserted. + let insert_index = index + insert_count; + let pos = match m.body.get(insert_index) { + Some(stmt) => stmt.pos().clone(), + None => bug!("AST module body index {} out of bound", insert_index), + }; + for (insert_offset, assign_stmt) in assign_stmt_list.iter().enumerate() { + // Insert behind the node with the insert offset, so the index plus one. + m.body.insert( + insert_index + insert_offset + 1, + Box::new(ast::Node::node_with_pos( + ast::Stmt::Assign(assign_stmt.clone()), + pos.clone(), + )), + ); + insert_count += 1; + } + } +} + +/// MultiAssignTransformer is used to transform AST Module and split top level +/// multiple target assign statement to multiple assign statements +/// +/// - Before +/// +/// ```kcl +/// a = b = Config {} +/// ``` +/// +/// - After +/// +/// ```kcl +/// a = Config {} +/// b = Config {} +/// ``` +#[derive(Debug, Default)] +struct MultiAssignTransformer { + pub multi_assign_mapping: HashMap>, + pub index: usize, +} + +impl<'ctx> MutSelfMutWalker<'ctx> for MultiAssignTransformer { + fn walk_stmt(&mut self, stmt: &'ctx mut ast::Stmt) { + if let ast::Stmt::Assign(assign_stmt) = stmt { + self.walk_assign_stmt(assign_stmt) + } + // Statement count. + self.index += 1; + } + fn walk_assign_stmt(&mut self, assign_stmt: &'ctx mut ast::AssignStmt) { + if assign_stmt.targets.len() <= 1 { + return; + } + let mut assign_stmt_list = vec![]; + for target in &assign_stmt.targets[1..] { + let mut new_assign_stmt = assign_stmt.clone(); + new_assign_stmt.targets = vec![target.clone()]; + assign_stmt_list.push(new_assign_stmt); + } + self.multi_assign_mapping + .insert(self.index, assign_stmt_list); + assign_stmt.targets = vec![assign_stmt.targets[0].clone()]; + } + fn walk_if_stmt(&mut self, _: &'ctx mut ast::IfStmt) { + // Do not fix AssignStmt in IfStmt + } + fn walk_schema_stmt(&mut self, _: &'ctx mut ast::SchemaStmt) { + // Do not fix AssignStmt in SchemaStmt + } + fn walk_lambda_expr(&mut self, _: &'ctx mut ast::LambdaExpr) { + // Do not fix AssignStmt in LambdaExpr + } +} diff --git a/kclvm/sema/src/pre_process/test_data/config_merge/config1.k b/kclvm/sema/src/pre_process/test_data/config_merge/config1.k new file mode 100644 index 000000000..d370b4523 --- /dev/null +++ b/kclvm/sema/src/pre_process/test_data/config_merge/config1.k @@ -0,0 +1,3 @@ +person: Person { + name = "Alice" +} diff --git a/kclvm/sema/src/pre_process/test_data/config_merge/config2.k b/kclvm/sema/src/pre_process/test_data/config_merge/config2.k new file mode 100644 index 000000000..fcdf98985 --- /dev/null +++ b/kclvm/sema/src/pre_process/test_data/config_merge/config2.k @@ -0,0 +1,3 @@ +person: Person { + age = 18 +} diff --git a/test/test_units/test_kclvm/test_tools/test_doc/doc_data/source_files/base_schema_pkg/base/person.k b/kclvm/sema/src/pre_process/test_data/config_merge/def.k similarity index 100% rename from test/test_units/test_kclvm/test_tools/test_doc/doc_data/source_files/base_schema_pkg/base/person.k rename to kclvm/sema/src/pre_process/test_data/config_merge/def.k diff --git a/kclvm/sema/src/pre_process/test_data/config_override.k b/kclvm/sema/src/pre_process/test_data/config_override.k new file mode 100644 index 000000000..9cdfc221d --- /dev/null +++ b/kclvm/sema/src/pre_process/test_data/config_override.k @@ -0,0 +1,17 @@ +schema ConfigMapping: + [str]: Config + +schema Config: + [str]: any + +configMapping: ConfigMapping { + key = Config { + data.key: "value" + } +} + +configMapping: ConfigMapping { + key = Config { + data.key: "value1" + } +} diff --git a/kclvm/sema/src/pre_process/test_data/lit_ty_default_val.k b/kclvm/sema/src/pre_process/test_data/lit_ty_default_val.k new file mode 100644 index 000000000..c259dcec2 --- /dev/null +++ b/kclvm/sema/src/pre_process/test_data/lit_ty_default_val.k @@ -0,0 +1,7 @@ +schema LitTyConfig: + val0: "val" + val1: 1 + val2: 1Ki + val3: 2.0 + val4: True + val5: False diff --git a/kclvm/sema/src/pre_process/test_data/multi_assign.k b/kclvm/sema/src/pre_process/test_data/multi_assign.k new file mode 100644 index 000000000..1503add28 --- /dev/null +++ b/kclvm/sema/src/pre_process/test_data/multi_assign.k @@ -0,0 +1,4 @@ +schema Config: + id?: int + +a = b = c = d = Config {} diff --git a/kclvm/sema/src/pre_process/test_data/raw_identifier.k b/kclvm/sema/src/pre_process/test_data/raw_identifier.k index d86374741..33298a1bc 100644 --- a/kclvm/sema/src/pre_process/test_data/raw_identifier.k +++ b/kclvm/sema/src/pre_process/test_data/raw_identifier.k @@ -1 +1,9 @@ $schema = 1 + +schema Name: + $name?: str + "$name"?: str + +n = Name { + "$name": "1" +} diff --git a/kclvm/sema/src/pre_process/test_data/skip_merge/config1.k b/kclvm/sema/src/pre_process/test_data/skip_merge/config1.k new file mode 100644 index 000000000..d370b4523 --- /dev/null +++ b/kclvm/sema/src/pre_process/test_data/skip_merge/config1.k @@ -0,0 +1,3 @@ +person: Person { + name = "Alice" +} diff --git a/kclvm/sema/src/pre_process/test_data/skip_merge/config2.k b/kclvm/sema/src/pre_process/test_data/skip_merge/config2.k new file mode 100644 index 000000000..48b33fd71 --- /dev/null +++ b/kclvm/sema/src/pre_process/test_data/skip_merge/config2.k @@ -0,0 +1,3 @@ +person: Person { + name = "bob" +} diff --git a/kclvm/sema/src/pre_process/test_data/skip_merge/def.k b/kclvm/sema/src/pre_process/test_data/skip_merge/def.k new file mode 100644 index 000000000..bb8a82ad6 --- /dev/null +++ b/kclvm/sema/src/pre_process/test_data/skip_merge/def.k @@ -0,0 +1,2 @@ +schema Person: + name: str diff --git a/kclvm/sema/src/pre_process/tests.rs b/kclvm/sema/src/pre_process/tests.rs index 3083b88fa..ce0f2846a 100644 --- a/kclvm/sema/src/pre_process/tests.rs +++ b/kclvm/sema/src/pre_process/tests.rs @@ -1,11 +1,15 @@ +use std::sync::Arc; + use super::*; use indexmap::IndexMap; -use kclvm_parser::parse_file; +use kclvm_ast::path::get_attr_paths_from_config_expr; +use kclvm_parser::{load_program, parse_file_force_errors, ParseSession}; #[test] fn test_fix_qualified_identifier() { let mut module = - parse_file("./src/pre_process/test_data/qualified_identifier.k", None).unwrap(); + parse_file_force_errors("./src/pre_process/test_data/qualified_identifier.k", None) + .unwrap(); fix_qualified_identifier(&mut module, &mut IndexMap::default()); if let ast::Stmt::Assign(assign_stmt) = &module.body[1].node { if let ast::Expr::Identifier(identifier) = &assign_stmt.value.node { @@ -18,18 +22,294 @@ fn test_fix_qualified_identifier() { } } +#[test] +fn test_fix_lit_ty_default_value() { + let mut module = + parse_file_force_errors("./src/pre_process/test_data/lit_ty_default_val.k", None).unwrap(); + fix_lit_ty_default_value(&mut module); + if let ast::Stmt::Schema(schema_stmt) = &module.body[0].node { + if let ast::Stmt::SchemaAttr(schema_attr) = &schema_stmt.body[0].node { + assert_eq!( + schema_attr.value.as_ref().unwrap().node, + ast::Expr::StringLit(ast::StringLit { + is_long_string: false, + raw_value: "\"val\"".to_string(), + value: "val".to_string(), + }) + ) + } else { + panic!("invalid schema attr value") + } + if let ast::Stmt::SchemaAttr(schema_attr) = &schema_stmt.body[1].node { + assert_eq!( + schema_attr.value.as_ref().unwrap().node, + ast::Expr::NumberLit(ast::NumberLit { + value: ast::NumberLitValue::Int(1), + binary_suffix: None, + }) + ) + } else { + panic!("invalid schema attr value") + } + if let ast::Stmt::SchemaAttr(schema_attr) = &schema_stmt.body[2].node { + assert_eq!( + schema_attr.value.as_ref().unwrap().node, + ast::Expr::NumberLit(ast::NumberLit { + value: ast::NumberLitValue::Int(1), + binary_suffix: Some(ast::NumberBinarySuffix::Ki), + }) + ) + } else { + panic!("invalid schema attr value") + } + if let ast::Stmt::SchemaAttr(schema_attr) = &schema_stmt.body[3].node { + assert_eq!( + schema_attr.value.as_ref().unwrap().node, + ast::Expr::NumberLit(ast::NumberLit { + value: ast::NumberLitValue::Float(2.0), + binary_suffix: None, + }) + ) + } else { + panic!("invalid schema attr value") + } + if let ast::Stmt::SchemaAttr(schema_attr) = &schema_stmt.body[4].node { + assert_eq!( + schema_attr.value.as_ref().unwrap().node, + ast::Expr::NameConstantLit(ast::NameConstantLit { + value: ast::NameConstant::True, + }) + ) + } else { + panic!("invalid schema attr value") + } + if let ast::Stmt::SchemaAttr(schema_attr) = &schema_stmt.body[5].node { + assert_eq!( + schema_attr.value.as_ref().unwrap().node, + ast::Expr::NameConstantLit(ast::NameConstantLit { + value: ast::NameConstant::False, + }) + ) + } else { + panic!("invalid schema attr value") + } + } else { + panic!("invalid schema statement") + } +} + #[test] fn test_fix_raw_identifier_prefix() { - let mut module = parse_file("./src/pre_process/test_data/raw_identifier.k", None).unwrap(); + let mut module = + parse_file_force_errors("./src/pre_process/test_data/raw_identifier.k", None).unwrap(); if let ast::Stmt::Assign(assign_stmt) = &module.body[0].node { - assert_eq!(assign_stmt.targets[0].node.names[0], "$schema") + assert_eq!(assign_stmt.targets[0].node.name.node, "$schema") } else { panic!("invalid assign statement") } fix_raw_identifier_prefix(&mut module); if let ast::Stmt::Assign(assign_stmt) = &module.body[0].node { - assert_eq!(assign_stmt.targets[0].node.names[0], "schema") + assert_eq!(assign_stmt.targets[0].node.name.node, "schema") + } else { + panic!("invalid assign statement") + } + if let ast::Stmt::Schema(schema_stmt) = &module.body[1].node { + if let ast::Stmt::SchemaAttr(attr) = &schema_stmt.body[0].node { + assert_eq!(attr.name.node, "name"); + } else { + panic!("invalid schema attr") + } + if let ast::Stmt::SchemaAttr(attr) = &schema_stmt.body[1].node { + assert_eq!(attr.name.node, "$name"); + } else { + panic!("invalid schema attr") + } + } else { + panic!("invalid schema statement") + } +} + +#[test] +fn test_transform_multi_assign() { + let targets = ["a", "b", "c", "d"]; + let mut module = + parse_file_force_errors("./src/pre_process/test_data/multi_assign.k", None).unwrap(); + if let ast::Stmt::Assign(assign_stmt) = &module.body[1].node { + assert_eq!(assign_stmt.targets.len(), targets.len()); + for (i, target) in targets.iter().enumerate() { + assert_eq!(assign_stmt.targets[i].node.get_name(), *target); + } } else { panic!("invalid assign statement") } + transform_multi_assign(&mut module); + for (i, target) in targets.iter().enumerate() { + if let ast::Stmt::Assign(assign_stmt) = &module.body[i + 1].node { + assert_eq!(assign_stmt.targets.len(), 1); + assert_eq!(assign_stmt.targets[0].node.get_name(), *target); + } else { + panic!("invalid assign statement") + } + } +} + +#[test] +fn test_config_merge() { + let sess = Arc::new(ParseSession::default()); + let mut program = load_program( + sess, + &[ + "./src/pre_process/test_data/config_merge/def.k", + "./src/pre_process/test_data/config_merge/config1.k", + "./src/pre_process/test_data/config_merge/config2.k", + "./src/pre_process/test_data/config_merge/config2.k", + ], + None, + None, + ) + .unwrap() + .program; + merge_program(&mut program); + let modules = program.pkgs.get(kclvm_ast::MAIN_PKG).unwrap(); + assert_eq!(modules.len(), 3); + // Test the module merge result + let module = modules.last().unwrap(); + let module = program + .get_module(module) + .expect("Failed to acquire module lock") + .expect(&format!("module {:?} not found in program", module)); + if let ast::Stmt::Unification(unification) = &module.body[0].node { + let schema = &unification.value.node; + if let ast::Expr::Config(config) = &schema.config.node { + // 2 contains `name` in `config1.k`, `age` in `config2.k`. + // person: Person { + // name = "Alice" + // age = 18 + // } + assert_eq!(config.items.len(), 2); + assert_eq!( + get_attr_paths_from_config_expr(config), + vec!["name".to_string(), "age".to_string()] + ); + } else { + panic!( + "test failed, expect config expression, got {:?}", + schema.config + ) + } + } else { + panic!( + "test failed, expect unification statement, got {:?}", + module.body[0] + ) + } +} + +#[test] +fn test_config_override() { + let sess = Arc::new(ParseSession::default()); + let mut program = load_program( + sess, + &["./src/pre_process/test_data/config_override.k"], + None, + None, + ) + .unwrap() + .program; + merge_program(&mut program); + let modules = program.pkgs.get(kclvm_ast::MAIN_PKG).unwrap(); + assert_eq!(modules.len(), 1); + // Test the module merge result + let module = modules.first().unwrap(); + let module = program + .get_module(module) + .expect("Failed to acquire module lock") + .expect(&format!("module {:?} not found in program", module)); + if let ast::Stmt::Unification(unification) = &module.body[2].node { + let schema = &unification.value.node; + if let ast::Expr::Config(config) = &schema.config.node { + // key = Config { + // data.key: "value1" + // } + assert_eq!(config.items.len(), 1); + assert_eq!( + get_attr_paths_from_config_expr(config), + vec!["key".to_string(), "key.data.key".to_string()] + ); + } else { + panic!( + "test failed, expect config expression, got {:?}", + schema.config + ) + } + } else { + panic!( + "test failed, expect unification statement, got {:?}", + module.body[2] + ) + } +} + +#[test] +fn test_skip_merge_program() { + let sess = Arc::new(ParseSession::default()); + let program = load_program( + sess, + &[ + "./src/pre_process/test_data/config_merge/def.k", + "./src/pre_process/test_data/config_merge/config1.k", + "./src/pre_process/test_data/config_merge/config2.k", + ], + None, + None, + ) + .unwrap() + .program; + // skip merge program and save raw config ast node + // merge_program(&mut program); + let modules = program.pkgs.get(kclvm_ast::MAIN_PKG).unwrap(); + assert_eq!(modules.len(), 3); + let config1 = &modules[1]; + let config2 = &modules[1]; + let config1 = program + .get_module(config1) + .expect("Failed to acquire module lock") + .expect(&format!("module {:?} not found in program", config1)); + let config2 = program + .get_module(config2) + .expect("Failed to acquire module lock") + .expect(&format!("module {:?} not found in program", config2)); + if let ast::Stmt::Unification(unification) = &config1.body[0].node { + let schema = &unification.value.node; + if let ast::Expr::Config(config) = &schema.config.node { + assert_eq!(config.items.len(), 1); + } else { + panic!( + "test failed, expect config expression, got {:?}", + schema.config + ) + } + } else { + panic!( + "test failed, expect unification statement, got {:?}", + config1.body[0] + ) + } + + if let ast::Stmt::Unification(unification) = &config2.body[0].node { + let schema = &unification.value.node; + if let ast::Expr::Config(config) = &schema.config.node { + assert_eq!(config.items.len(), 1); + } else { + panic!( + "test failed, expect config expression, got {:?}", + schema.config + ) + } + } else { + panic!( + "test failed, expect unification statement, got {:?}", + config2.body[0] + ) + } } diff --git a/kclvm/sema/src/resolver/arg.rs b/kclvm/sema/src/resolver/arg.rs index 20b661070..fd1c5de18 100644 --- a/kclvm/sema/src/resolver/arg.rs +++ b/kclvm/sema/src/resolver/arg.rs @@ -1,67 +1,179 @@ use crate::resolver::Resolver; -use crate::ty::{Parameter, Type}; +use crate::ty::FunctionType; +use compiler_base_error::unit_type::{TypeWithUnit, UnitUsize}; use indexmap::IndexSet; use kclvm_ast::ast; -use std::rc::Rc; -use crate::resolver::pos::GetPos; +use kclvm_ast::pos::GetPos; +use kclvm_error::diagnostic::Range; + +use crate::ty::TypeRef; + +impl<'ctx> Resolver<'_> { + fn get_func_name(&mut self, func: &ast::Expr) -> String { + let mut callee = func; + loop { + match callee { + ast::Expr::Identifier(identifier) => { + return format!("\"{}\"", identifier.get_name()); + } + ast::Expr::Selector(selector_expr) => { + return format!("\"{}\"", selector_expr.attr.node.get_name()); + } + ast::Expr::Paren(paren_expr) => callee = &paren_expr.expr.node, + _ => return "anonymous function".to_string(), + } + } + } -impl<'ctx> Resolver<'ctx> { /// Do schema/function/decorator argument type check. pub fn do_arguments_type_check( &mut self, + func: &ast::NodeRef, args: &'ctx [ast::NodeRef], kwargs: &'ctx [ast::NodeRef], - params: &[Parameter], + func_ty: &FunctionType, ) { - let arg_types = self.exprs(args); - let mut kwarg_types: Vec<(String, Rc)> = vec![]; + let func_name = self.get_func_name(&func.node); let mut check_table: IndexSet = IndexSet::default(); - for kw in kwargs { - let arg_name = &kw.node.arg.node.names[0]; - if check_table.contains(arg_name) { - self.handler.add_compile_error( - &format!("duplicated keyword argument {}", arg_name), - kw.get_pos(), - ); - } - check_table.insert(arg_name.to_string()); - let arg_value_type = self.expr_or_any_type(&kw.node.value); - kwarg_types.push((arg_name.to_string(), arg_value_type.clone())); + let mut prev_kw_pos = None; + for (i, arg) in args.iter().enumerate() { + match func_ty.params.get(i) { + Some(param) => { + self.upgrade_type_for_expr( + param.ty.clone(), + arg, + arg.get_span_pos(), + Some(param.range.clone()), + ); + } + None => { + // If the parameter has not a expected type, just check the argument type + // and do not upgrade the type. + self.expr(arg); + if !func_ty.is_variadic { + self.handler.add_compile_error_with_suggestions( + &format!( + "{} takes {} but {} were given", + func_name, + UnitUsize(func_ty.params.len(), "positional argument".to_string()) + .into_string_with_unit(), + args.len(), + ), + args[i].get_span_pos(), + Some(vec![]), + ); + break; + } + } + }; } - if !params.is_empty() { - for (i, ty) in arg_types.iter().enumerate() { - let expected_ty = params[i].ty.clone(); - self.must_assignable_to(ty.clone(), expected_ty, args[i].get_pos(), None) - } - for (i, (arg_name, kwarg_ty)) in kwarg_types.iter().enumerate() { - if !params + for (i, kw) in kwargs.iter().enumerate() { + if !kw.node.arg.node.names.is_empty() { + let previous_pos = if let Some(prev_pos) = prev_kw_pos { + prev_pos + } else { + kw.get_end_pos() + }; + let arg_name = &kw.node.arg.node.names[0].node; + + if check_table.contains(arg_name) { + self.handler.add_compile_error_with_suggestions( + &format!("{} has duplicated keyword argument {}", func_name, arg_name), + (previous_pos, kw.get_end_pos()), + Some(vec![]), + ); + } + check_table.insert(arg_name.to_string()); + + if !func_ty + .params .iter() .map(|p| p.name.clone()) .any(|x| x == *arg_name) + && !func_ty.is_variadic { - self.handler.add_compile_error( + let (suggs, msg) = self.get_arg_kw_err_suggestion_from_name(arg_name, func_ty); + self.handler.add_compile_error_with_suggestions( &format!( - "arguments got an unexpected keyword argument '{}'", - arg_name + "{} got an unexpected keyword argument '{}'{}", + func_name, arg_name, msg ), - kwargs[i].get_pos(), + kwargs[i].node.arg.get_span_pos(), + Some(suggs), ); } - let expected_types: Vec> = params + + let expected_types_and_ranges: Vec<(TypeRef, Range)> = func_ty + .params .iter() .filter(|p| p.name == *arg_name) - .map(|p| p.ty.clone()) + .map(|p| (p.ty.clone(), p.range.clone())) .collect(); - if !expected_types.is_empty() { - self.must_assignable_to( - kwarg_ty.clone(), - expected_types[0].clone(), - kwargs[i].get_pos(), - None, - ); - }; + + if let Some((expected_ty, def_range)) = expected_types_and_ranges.first() { + if let Some(value) = &kw.node.value { + let arg_value_type = self.upgrade_type_for_expr( + expected_ty.clone(), + value, + value.get_span_pos(), + Some(def_range.clone()), + ); + self.node_ty_map + .borrow_mut() + .insert(self.get_node_key(kw.id.clone()), arg_value_type.clone()); + } + } + } else { + self.handler + .add_compile_error(&format!("missing argument"), kw.get_span_pos()); } + prev_kw_pos = Some(kw.get_end_pos()); } + // Do few argument count check + if !func_ty.is_variadic { + let mut got_count = 0; + let mut expect_count = 0; + for param in &func_ty.params { + if !param.has_default { + expect_count += 1; + if check_table.contains(¶m.name) { + got_count += 1 + } + } + } + got_count += args.len(); + if got_count < expect_count { + self.handler.add_compile_error( + &format!( + "expected {}, found {}", + UnitUsize(expect_count, "positional argument".to_string()) + .into_string_with_unit(), + got_count + ), + func.get_span_pos(), + ); + } + } + } + + /// Generate suggestions for keyword argument errors. + pub(crate) fn get_arg_kw_err_suggestion_from_name( + &self, + arg_name: &str, + func_ty: &FunctionType, + ) -> (Vec, String) { + let valid_params: Vec<&str> = func_ty + .params + .iter() + .map(|param| param.name.as_str()) + .collect(); + let suggs = suggestions::provide_suggestions(arg_name, valid_params.into_iter()); + let suggestion = if !suggs.is_empty() { + format!(", did you mean '{}'?", suggs.join(" or ")) + } else { + String::new() + }; + (suggs, suggestion) } } diff --git a/kclvm/sema/src/resolver/attr.rs b/kclvm/sema/src/resolver/attr.rs index 2a08ce2ac..d95192715 100644 --- a/kclvm/sema/src/resolver/attr.rs +++ b/kclvm/sema/src/resolver/attr.rs @@ -1,29 +1,38 @@ -use std::rc::Rc; +use std::sync::Arc; use crate::builtin::system_module::{get_system_module_members, UNITS, UNITS_NUMBER_MULTIPLIER}; -use crate::builtin::STRING_MEMBER_FUNCTIONS; +use crate::builtin::{get_system_member_function_ty, STRING_MEMBER_FUNCTIONS}; use crate::resolver::Resolver; -use crate::ty::{ModuleKind, Type, TypeKind}; +use crate::ty::TypeKind::Schema; +use crate::ty::{ + DictType, ModuleKind, Parameter, Type, TypeKind, TypeRef, SCHEMA_MEMBER_FUNCTIONS, +}; +use kclvm_ast::ast; +use kclvm_error::diagnostic::{dummy_range, Range}; use kclvm_error::*; use super::node::ResolvedResult; -impl<'ctx> Resolver<'ctx> { - pub fn check_attr_ty(&mut self, attr_ty: &Type, pos: Position) { +impl<'ctx> Resolver<'_> { + pub fn check_attr_ty(&mut self, attr_ty: &Type, range: Range) { if !attr_ty.is_any() && !attr_ty.is_key() { self.handler.add_error( ErrorKind::IllegalAttributeError, &[Message { - pos, + range, style: Style::LineAndColumn, - message: format!("type '{}'", attr_ty.ty_str()), + message: format!( + "A attribute must be string type, got '{}'", + attr_ty.ty_str() + ), note: None, + suggested_replacement: None, }], ); } } - pub fn load_attr(&mut self, obj: Rc, attr: &str, pos: Position) -> ResolvedResult { + pub fn load_attr(&mut self, obj: TypeRef, attr: &str, range: Range) -> ResolvedResult { let (result, return_ty) = match &obj.kind { TypeKind::Any => (true, self.any_ty()), TypeKind::None @@ -39,10 +48,20 @@ impl<'ctx> Resolver<'ctx> { | TypeKind::Named(_) | TypeKind::Void => (false, self.any_ty()), TypeKind::Str | TypeKind::StrLit(_) => match STRING_MEMBER_FUNCTIONS.get(attr) { - Some(ty) => (true, Rc::new(ty.clone())), + Some(ty) => (true, Arc::new(ty.clone())), None => (false, self.any_ty()), }, - TypeKind::Dict(_, val_ty) => (true, Rc::new(val_ty.as_ref().clone())), + TypeKind::Dict(DictType { + key_ty: _, + val_ty, + attrs, + }) => ( + true, + attrs + .get(attr) + .map(|attr| attr.ty.clone()) + .unwrap_or(Arc::new(val_ty.as_ref().clone())), + ), // union type load attr based the type guard. e.g, a: str|int; if a is str: xxx; if a is int: xxx; // return sup([self.load_attr_type(t, attr, filename, line, column) for t in obj.types]) TypeKind::Union(_) => (true, self.any_ty()), @@ -53,10 +72,17 @@ impl<'ctx> Resolver<'ctx> { } else if schema_ty.is_member_functions(attr) { ( true, - Rc::new(Type::function( + Arc::new(Type::function( Some(obj.clone()), Type::list_ref(self.any_ty()), - &[], + &[Parameter { + name: "full_pkg".to_string(), + ty: Type::bool_ref(), + // Default value is False + has_default: true, + default_value: None, + range: dummy_range(), + }], "", false, None, @@ -73,7 +99,7 @@ impl<'ctx> Resolver<'ctx> { Some(v) => { if v.borrow().ty.is_module() { self.handler - .add_compile_error(&format!("can not import the attribute '{}' from the module '{}'", attr, module_ty.pkgpath), pos.clone()); + .add_compile_error(&format!("can not import the attribute '{}' from the module '{}'", attr, module_ty.pkgpath), range.clone()); } (true, v.borrow().ty.clone()) } @@ -83,20 +109,174 @@ impl<'ctx> Resolver<'ctx> { }, ModuleKind::System => { if module_ty.pkgpath == UNITS && attr == UNITS_NUMBER_MULTIPLIER { - (true, Rc::new(Type::number_multiplier_non_lit_ty())) + (true, Arc::new(Type::number_multiplier_non_lit_ty())) } else { let members = get_system_module_members(&module_ty.pkgpath); - (members.contains(&attr), self.any_ty()) + ( + members.contains(&attr), + get_system_member_function_ty(&module_ty.pkgpath, attr), + ) } } ModuleKind::Plugin => (true, self.any_ty()), } } }; + if !result { - self.handler - .add_type_error(&format!("{} has no attribute {}", obj.ty_str(), attr), pos); + // The attr user input. + let (attr, suggestion) = if attr.is_empty() { + ("[missing name]", "".to_string()) + } else { + let mut suggestion = String::new(); + // Calculate the closest miss attributes. + if let Schema(schema_ty) = &obj.kind { + // Get all the attributes of the schema. + let attrs = if schema_ty.is_instance { + schema_ty.attrs.keys().cloned().collect::>() + } else { + SCHEMA_MEMBER_FUNCTIONS + .iter() + .map(|s| s.to_string()) + .collect::>() + }; + let suggs = suggestions::provide_suggestions(attr, &attrs); + if suggs.len() > 0 { + suggestion = format!(", did you mean '{:?}'?", suggs); + } + } + (attr, suggestion) + }; + + self.handler.add_type_error( + &format!( + "attribute '{}' not found in '{}'{}", + attr, + obj.ty_str(), + suggestion + ), + range, + ); } return_ty } + + pub fn subscript_index( + &mut self, + value_ty: TypeRef, + index: &'ctx ast::NodeRef, + range: Range, + ) -> ResolvedResult { + if value_ty.is_any() { + value_ty + } else { + match &value_ty.kind { + TypeKind::Str | TypeKind::StrLit(_) | TypeKind::List(_) => { + self.must_be_type(index, self.int_ty()); + if value_ty.is_list() { + value_ty.list_item_ty() + } else { + self.str_ty() + } + } + TypeKind::Dict(DictType { + key_ty: _, val_ty, .. + }) => { + let index_key_ty = self.expr(index); + if index_key_ty.is_none_or_any() { + val_ty.clone() + } else if !index_key_ty.is_key() { + self.handler.add_compile_error( + &format!("invalid dict/schema key type: '{}'", index_key_ty.ty_str()), + range, + ); + self.any_ty() + } else if let TypeKind::StrLit(lit_value) = &index_key_ty.kind { + self.load_attr(value_ty, lit_value, range) + } else { + val_ty.clone() + } + } + TypeKind::Schema(schema_ty) => { + let index_key_ty = self.expr(index); + if index_key_ty.is_none_or_any() { + schema_ty.val_ty() + } else if !index_key_ty.is_key() { + self.handler.add_compile_error( + &format!("invalid dict/schema key type: '{}'", index_key_ty.ty_str()), + range, + ); + self.any_ty() + } else if let TypeKind::StrLit(lit_value) = &index_key_ty.kind { + self.load_attr(value_ty, lit_value, range) + } else { + schema_ty.val_ty() + } + } + _ => { + self.handler.add_compile_error( + &format!("'{}' object is not subscriptable", value_ty.ty_str()), + range, + ); + self.any_ty() + } + } + } + } + + pub fn subscript( + &mut self, + value_ty: TypeRef, + index: &'ctx Option>, + lower: &'ctx Option>, + upper: &'ctx Option>, + step: &'ctx Option>, + range: Range, + ) -> ResolvedResult { + if value_ty.is_any() { + value_ty + } else { + match &value_ty.kind { + TypeKind::Str | TypeKind::StrLit(_) | TypeKind::List(_) => { + if let Some(index) = &index { + self.subscript_index(value_ty, index, range) + } else { + for expr in [lower, upper, step].iter().copied().flatten() { + self.must_be_type(expr, self.int_ty()); + } + if value_ty.is_list() { + value_ty + } else { + self.str_ty() + } + } + } + TypeKind::Dict(DictType { key_ty: _, .. }) => { + if let Some(index) = &index { + self.subscript_index(value_ty, index, range) + } else { + self.handler + .add_compile_error("unhashable type: 'slice'", range); + self.any_ty() + } + } + TypeKind::Schema(_) => { + if let Some(index) = &index { + self.subscript_index(value_ty, index, range) + } else { + self.handler + .add_compile_error("unhashable type: 'slice'", range); + self.any_ty() + } + } + _ => { + self.handler.add_compile_error( + &format!("'{}' object is not subscriptable", value_ty.ty_str()), + range, + ); + self.any_ty() + } + } + } + } } diff --git a/kclvm/sema/src/resolver/calculation.rs b/kclvm/sema/src/resolver/calculation.rs index bbe2e1644..a3715eebb 100644 --- a/kclvm/sema/src/resolver/calculation.rs +++ b/kclvm/sema/src/resolver/calculation.rs @@ -1,9 +1,12 @@ -use std::rc::Rc; +use std::sync::Arc; use crate::resolver::Resolver; -use crate::ty::{has_any_type, is_upper_bound, sup, Type, TypeInferMethods, ZERO_LIT_TYPES}; +use crate::ty::{ + has_any_type, is_upper_bound, sup, Type, TypeInferMethods, TypeKind, TypeRef, ZERO_LIT_TYPES, +}; +use indexmap::IndexMap; use kclvm_ast::ast; -use kclvm_error::Position; +use kclvm_error::diagnostic::Range; const DIV_OR_MOD_ZERO_MSG: &str = "integer division or modulo by zero"; @@ -53,11 +56,11 @@ impl<'ctx> Resolver<'ctx> { /// Or: any_type1 or any_type1 -> sup([any_type1, any_type2]) pub fn binary( &mut self, - left: Rc, - right: Rc, + left: TypeRef, + right: TypeRef, op: &ast::BinOp, - pos: Position, - ) -> Rc { + range: Range, + ) -> TypeRef { let t1 = self .ctx .ty_ctx @@ -69,11 +72,11 @@ impl<'ctx> Resolver<'ctx> { if has_any_type(&[t1.clone(), t2.clone()]) { return self.any_ty(); } - let number_binary = |left: &Rc, right: &Rc| { + let number_binary = |left: &TypeRef, right: &TypeRef| { if left.is_float() || right.is_float() { - Rc::new(Type::FLOAT) + Arc::new(Type::FLOAT) } else { - Rc::new(Type::INT) + Arc::new(Type::INT) } }; let (result, return_ty) = match op { @@ -123,7 +126,7 @@ impl<'ctx> Resolver<'ctx> { if t1.is_number() && t2.is_number() { if ZERO_LIT_TYPES.contains(&t2) { self.handler - .add_type_error(DIV_OR_MOD_ZERO_MSG, pos.clone()); + .add_type_error(DIV_OR_MOD_ZERO_MSG, range.clone()); } (true, number_binary(&t1, &t2)) } else { @@ -134,7 +137,7 @@ impl<'ctx> Resolver<'ctx> { if t1.is_number() && t2.is_number() { if ZERO_LIT_TYPES.contains(&t2) { self.handler - .add_type_error(DIV_OR_MOD_ZERO_MSG, pos.clone()); + .add_type_error(DIV_OR_MOD_ZERO_MSG, range.clone()); } (true, self.int_ty()) } else { @@ -160,12 +163,23 @@ impl<'ctx> Resolver<'ctx> { true, Type::list_ref(sup(&[t1.list_item_ty(), t2.list_item_ty()])), ) - } else if t1.is_dict() && t2.is_dict() { - let (t1_key_ty, t1_val_ty) = t1.dict_entry_ty(); - let (t2_key_ty, t2_val_ty) = t2.dict_entry_ty(); + } else if let (TypeKind::Dict(t1_dict_ty), TypeKind::Dict(t2_dict_ty)) = + (&t1.kind, &t2.kind) + { + let mut attrs = IndexMap::new(); + for (k, v) in &t1_dict_ty.attrs { + attrs.insert(k.to_string(), v.clone()); + } + for (k, v) in &t2_dict_ty.attrs { + attrs.insert(k.to_string(), v.clone()); + } ( true, - Type::dict_ref(sup(&[t1_key_ty, t2_key_ty]), sup(&[t1_val_ty, t2_val_ty])), + Arc::new(Type::dict_with_attrs( + sup(&[t1_dict_ty.key_ty.clone(), t2_dict_ty.key_ty.clone()]), + sup(&[t1_dict_ty.val_ty.clone(), t2_dict_ty.val_ty.clone()]), + attrs, + )), ) } else if t1.is_schema() && (t2.is_schema() || t2.is_dict()) { (true, t1) @@ -183,10 +197,10 @@ impl<'ctx> Resolver<'ctx> { self.handler.add_type_error( &format!( "Conversion of type '{}' to type '{}' may be a mistake because neither type sufficiently overlaps with the other", - t1.ty_str(), - t2.ty_str() + t1.full_ty_str(), + t2.full_ty_str() ), - pos.clone(), + range.clone(), ); } (true, t2) @@ -201,7 +215,7 @@ impl<'ctx> Resolver<'ctx> { left.ty_str(), right.ty_str() ), - pos, + range, ); } return_ty @@ -213,7 +227,7 @@ impl<'ctx> Resolver<'ctx> { /// - number unary negation (int, float) /// ~ number unary bitwise inversion (int) /// not x logical negation (any type) - pub fn unary(&mut self, ty: Rc, op: &ast::UnaryOp, pos: Position) -> Rc { + pub fn unary(&mut self, ty: TypeRef, op: &ast::UnaryOp, range: Range) -> TypeRef { if has_any_type(&[ty.clone()]) { return self.any_ty(); } @@ -235,7 +249,7 @@ impl<'ctx> Resolver<'ctx> { op.symbol(), ty.ty_str(), ), - pos, + range, ); self.any_ty() } @@ -243,19 +257,18 @@ impl<'ctx> Resolver<'ctx> { /// Compare operator calculation table /// - /// bool # False < True False < True - /// int # mathematical 1 < 2 - /// float # as defined by IEEE 754 1.0 < 2.0 - /// string # lexicographical "1" < 2 - /// list # lexicographical [1] == [2] - /// iterable # 1 in [1, 2, 3], "s" in "ss", "key" in Schema + /// int # mathematical 1 < 2 + /// float # as defined by IEEE 754 1.0 < 2.0 + /// list/config/schema # lexicographical [1] == [2] + /// iterable # 1 in [1, 2, 3], "s" in "ss", "key" in Schema + /// relation # a is True, b is Undefined pub fn compare( &mut self, - left: Rc, - right: Rc, + left: TypeRef, + right: TypeRef, op: &ast::CmpOp, - pos: Position, - ) -> Rc { + range: Range, + ) -> TypeRef { let t1 = self.ctx.ty_ctx.literal_union_type_to_variable_type(left); let t2 = self.ctx.ty_ctx.literal_union_type_to_variable_type(right); if has_any_type(&[t1.clone(), t2.clone()]) { @@ -264,11 +277,11 @@ impl<'ctx> Resolver<'ctx> { if self .ctx .ty_ctx - .is_number_type_or_number_union_type(t1.clone()) + .is_number_bool_type_or_number_bool_union_type(t1.clone()) && self .ctx .ty_ctx - .is_number_type_or_number_union_type(t2.clone()) + .is_number_bool_type_or_number_bool_union_type(t2.clone()) && !matches!(op, ast::CmpOp::In | ast::CmpOp::NotIn) { return self.bool_ty(); @@ -285,10 +298,10 @@ impl<'ctx> Resolver<'ctx> { { return self.bool_ty(); } - if t1.is_list() && t2.is_list() { + if matches!(op, ast::CmpOp::Eq) && t1.is_list() && t2.is_list() { return self.bool_ty(); } - if t1.is_dict_or_schema() && t2.is_dict_or_schema() { + if matches!(op, ast::CmpOp::Eq) && t1.is_dict_or_schema() && t2.is_dict_or_schema() { return self.bool_ty(); } if matches!(op, ast::CmpOp::In | ast::CmpOp::NotIn) && t2.is_iterable() { @@ -313,7 +326,7 @@ impl<'ctx> Resolver<'ctx> { t1.ty_str(), t2.ty_str(), ), - pos, + range, ); self.any_ty() } diff --git a/kclvm/sema/src/resolver/config.rs b/kclvm/sema/src/resolver/config.rs index 78cb72c6d..bae4a701b 100644 --- a/kclvm/sema/src/resolver/config.rs +++ b/kclvm/sema/src/resolver/config.rs @@ -1,14 +1,16 @@ -use std::rc::Rc; +use std::{collections::HashSet, sync::Arc}; use super::{ - scope::{ScopeObject, ScopeObjectKind}, + scope::{ScopeKind, ScopeObject, ScopeObjectKind}, Resolver, }; -use crate::resolver::pos::GetPos; -use crate::ty::SchemaType; +use crate::ty::{sup, DictType, TypeInferMethods, TypeRef}; +use crate::ty::{Attr, SchemaType}; use crate::ty::{Type, TypeKind}; +use indexmap::IndexMap; use kclvm_ast::ast; -use kclvm_error::Position; +use kclvm_ast::pos::GetPos; +use kclvm_error::{diagnostic::Range, ErrorKind, Message, Position, Style}; /// Config Expr type check state. /// @@ -26,12 +28,12 @@ pub enum SwitchConfigContextState { SwitchConfigOnce = 1, } -impl<'ctx> Resolver<'ctx> { +impl<'ctx> Resolver<'_> { #[inline] pub(crate) fn new_config_expr_context_item( &mut self, name: &str, - ty: Rc, + ty: TypeRef, start: Position, end: Position, ) -> ScopeObject { @@ -41,6 +43,7 @@ impl<'ctx> Resolver<'ctx> { end, ty, kind: ScopeObjectKind::Attribute, + doc: None, } } @@ -69,7 +72,15 @@ impl<'ctx> Resolver<'ctx> { let obj = obj.clone(); match obj { Some(obj) => match &obj.ty.kind { - TypeKind::Dict(_, val_ty) => Some(self.new_config_expr_context_item( + TypeKind::List(elem_type) => Some(self.new_config_expr_context_item( + key_name, + elem_type.clone(), + obj.start.clone(), + obj.end.clone(), + )), + TypeKind::Dict(DictType { + key_ty: _, val_ty, .. + }) => Some(self.new_config_expr_context_item( key_name, val_ty.clone(), obj.start.clone(), @@ -77,12 +88,33 @@ impl<'ctx> Resolver<'ctx> { )), TypeKind::Schema(schema_ty) => { match schema_ty.get_obj_of_attr(key_name) { - Some(attr_ty_obj) => Some(self.new_config_expr_context_item( - key_name, - attr_ty_obj.ty.clone(), - attr_ty_obj.pos.clone(), - attr_ty_obj.pos.clone(), - )), + Some(attr_ty_obj) => { + let ty = match &attr_ty_obj.ty.kind { + TypeKind::Schema(schema_ty) => { + let runtime_type = + kclvm_runtime::schema_runtime_type( + &schema_ty.name, + &schema_ty.pkgpath, + ); + if let Some(runtime_scehma_ty) = + self.ctx.schema_mapping.get(&runtime_type) + { + Arc::new(Type::schema( + runtime_scehma_ty.borrow().clone(), + )) + } else { + attr_ty_obj.ty.clone() + } + } + _ => attr_ty_obj.ty.clone(), + }; + Some(self.new_config_expr_context_item( + key_name, + ty, + attr_ty_obj.range.0.clone(), + attr_ty_obj.range.1.clone(), + )) + } None => match &schema_ty.index_signature { Some(index_signature) => { Some(self.new_config_expr_context_item( @@ -96,6 +128,38 @@ impl<'ctx> Resolver<'ctx> { }, } } + TypeKind::Union(types) => { + let mut possible_types = vec![]; + for ty in types { + match &ty.kind { + TypeKind::Schema(schema_ty) => { + match schema_ty.get_obj_of_attr(key_name) { + Some(attr_ty_obj) => { + possible_types.push(attr_ty_obj.ty.clone()); + } + None => match &schema_ty.index_signature { + Some(index_signature) => { + possible_types + .push(index_signature.val_ty.clone()); + } + None => continue, + }, + } + } + TypeKind::Dict(DictType { val_ty, .. }) => { + possible_types.push(val_ty.clone()); + } + _ => continue, + } + } + + Some(self.new_config_expr_context_item( + key_name, + crate::ty::sup(&possible_types).into(), + obj.start.clone(), + obj.end.clone(), + )) + } _ => None, }, None => None, @@ -120,12 +184,12 @@ impl<'ctx> Resolver<'ctx> { match key { Some(key) => { let names: Vec = match &key.node { - ast::Expr::Identifier(identifier) => identifier.names.clone(), + ast::Expr::Identifier(identifier) => identifier.get_names(), ast::Expr::Subscript(subscript) => { if let ast::Expr::Identifier(identifier) = &subscript.value.node { if let Some(index) = &subscript.index { if matches!(index.node, ast::Expr::NumberLit(_)) { - identifier.names.clone() + identifier.get_names() } else { return SwitchConfigContextState::KeepConfigUnchanged as usize; } @@ -137,14 +201,27 @@ impl<'ctx> Resolver<'ctx> { } } ast::Expr::StringLit(string_lit) => vec![string_lit.value.clone()], + // There may be a valid configuration key for joined string and missing expressions here, + // and we will restore it to a null value to avoid unfriendly error messages. + ast::Expr::JoinedString(_) | ast::Expr::Missing(_) => vec!["".to_string()], _ => return SwitchConfigContextState::KeepConfigUnchanged as usize, }; self.switch_config_expr_context_by_names(&names) } + // Double star expression None => SwitchConfigContextState::KeepConfigUnchanged as usize, } } + /// Switch the context in 'config_expr_context' stack by the list index `[]` + /// + /// Returns: + /// push stack times + #[inline] + pub(crate) fn switch_list_expr_context(&mut self) -> usize { + self.switch_config_expr_context_by_names(&["[]".to_string()]) + } + /// Switch the context in 'config_expr_context' stack by name /// /// find the next item that needs to be pushed into the stack, @@ -155,7 +232,7 @@ impl<'ctx> Resolver<'ctx> { /// /// Returns: /// push stack times - pub(crate) fn switch_config_exprr_context_by_name(&mut self, name: &str) -> usize { + pub(crate) fn switch_config_expr_context_by_name(&mut self, name: &str) -> usize { let ctx_obj = self.find_schema_attr_obj_from_schema_expr_stack(name); self.switch_config_expr_context(ctx_obj) as usize } @@ -178,7 +255,7 @@ impl<'ctx> Resolver<'ctx> { /// Pop method for the 'config_expr_context' stack /// /// Returns: - /// the item poped from stack. + /// the item popped from stack. #[inline] pub(crate) fn restore_config_expr_context(&mut self) -> Option { match self.ctx.config_expr_context.pop() { @@ -216,7 +293,7 @@ impl<'ctx> Resolver<'ctx> { pub(crate) fn switch_config_expr_context_by_names(&mut self, names: &[String]) -> usize { let mut stack_depth = 0; for name in names { - stack_depth += self.switch_config_exprr_context_by_name(name); + stack_depth += self.switch_config_expr_context_by_name(name); } stack_depth } @@ -234,11 +311,57 @@ impl<'ctx> Resolver<'ctx> { ) { if !name.is_empty() { if let Some(Some(obj)) = self.ctx.config_expr_context.last() { - let obj = obj.clone(); - if let TypeKind::Schema(schema_ty) = &obj.ty.kind { - self.check_config_attr(name, &key.get_pos(), schema_ty); + let ty = obj.ty.clone(); + self.must_check_config_attr(name, &ty, &key.get_span_pos(), None); + } + } + } + + fn check_config_value_recursively(&mut self, value_ty: &TypeRef, value_span: &Range) { + match &value_ty.kind { + TypeKind::Dict(DictType { + key_ty: _, + val_ty: _, + attrs, + }) => { + for (key, attr) in attrs { + self.check_attr_recursively(&key, &attr.ty, &attr.range, value_span); + } + } + TypeKind::Schema(schema_ty) => { + for (key, attr) in &schema_ty.attrs { + self.check_attr_recursively(&key, &attr.ty, &attr.range, value_span); } } + _ => {} + } + } + + fn check_attr_recursively( + &mut self, + key: &str, + attr_ty: &TypeRef, + attr_span: &Range, + value_span: &Range, + ) { + if !key.is_empty() { + if let Some(Some(obj)) = self.ctx.config_expr_context.last() { + let ty = obj.ty.clone(); + self.must_check_config_attr(key, &ty, value_span, Some(attr_span)); + } + let stack_depth = self.switch_config_expr_context_by_name(key); + if let Some(Some(obj)) = self.ctx.config_expr_context.last() { + let ty = obj.ty.clone(); + self.attr_must_assignable_to( + attr_ty.clone(), + ty, + value_span.clone(), + Some(obj.get_span_pos()), + Some(attr_span.clone()), + ); + } + self.check_config_value_recursively(attr_ty, value_span); + self.clear_config_expr_context(stack_depth, false); } } @@ -255,96 +378,274 @@ impl<'ctx> Resolver<'ctx> { &mut self, key: &'ctx Option>, value: &'ctx ast::NodeRef, - ) { + ) -> Option { if let Some(key) = key { if let Some(Some(_)) = self.ctx.config_expr_context.last() { - let mut has_index = false; let names: Vec = match &key.node { - ast::Expr::Identifier(identifier) => identifier.names.clone(), + ast::Expr::Identifier(identifier) => identifier.get_names(), ast::Expr::Subscript(subscript) => { if let ast::Expr::Identifier(identifier) = &subscript.value.node { if let Some(index) = &subscript.index { if matches!(index.node, ast::Expr::NumberLit(_)) { - has_index = true; - identifier.names.clone() + identifier.get_names() + } else if let ast::Expr::Unary(unary_expr) = &index.node { + // Negative index constant + if matches!(unary_expr.operand.node, ast::Expr::NumberLit(_)) { + identifier.get_names() + } else { + return None; + } } else { - return; + return None; } } else { - return; + return None; } } else { - return; + return None; } } ast::Expr::StringLit(string_lit) => vec![string_lit.value.clone()], - _ => return, + _ => return None, }; let mut stack_depth = 0; for name in &names { self.check_config_expr_by_key_name(name, key); - stack_depth += self.switch_config_exprr_context_by_name(name); + stack_depth += self.switch_config_expr_context_by_name(name); } let mut val_ty = self.expr(value); + + let return_ty = Some(val_ty.clone()); + for _ in 0..names.len() - 1 { val_ty = Type::dict_ref(self.str_ty(), val_ty); } - if has_index { - val_ty = Type::list_ref(val_ty); - } if let Some(Some(obj_last)) = self.ctx.config_expr_context.last() { let ty = obj_last.ty.clone(); - let pos = obj_last.start.clone(); - self.must_assignable_to(val_ty, ty, key.get_pos(), Some(pos)); + self.must_assignable_to( + val_ty, + ty, + key.get_span_pos(), + Some(obj_last.get_span_pos()), + ); } self.clear_config_expr_context(stack_depth, false); + return return_ty; + } + } else { + // For double star expression, we can recursively check nested configuration properties at compile time. + let value_ty = self.expr(value); + self.check_config_value_recursively(&value_ty, &value.get_span_pos()); + return Some(value_ty); + } + None + } + + #[inline] + pub(crate) fn get_config_attr_err_suggestion_from_schema( + &self, + attr: &str, + schema_ty: &SchemaType, + ) -> (Vec, String) { + self.get_config_attr_err_suggestion(attr, schema_ty.attrs.keys()) + } + + pub(crate) fn get_config_attr_err_suggestion( + &self, + attr: &str, + keys: I, + ) -> (Vec, String) + where + T: AsRef, + I: IntoIterator, + { + let mut suggestion = String::new(); + // Calculate the closest miss attributes. + let suggs = suggestions::provide_suggestions(attr, keys); + if suggs.len() > 0 { + suggestion = format!(", did you mean '{:?}'?", suggs); + } + (suggs, suggestion) + } + + /// Check config attr has been defined. + pub(crate) fn must_check_config_attr( + &mut self, + attr: &str, + ty: &TypeRef, + range: &Range, + attr_range: Option<&Range>, + ) { + if let TypeKind::Schema(schema_ty) = &ty.kind { + self.check_config_attr(attr, schema_ty, range, attr_range); + } else if let TypeKind::Union(types) = &ty.kind { + let mut schema_names = vec![]; + let mut total_suggs = vec![]; + for ty in types { + match &ty.kind { + TypeKind::Schema(schema_ty) => { + if schema_ty.get_obj_of_attr(attr).is_none() + && !schema_ty.is_mixin + && schema_ty.index_signature.is_none() + { + let mut suggs = + suggestions::provide_suggestions(attr, schema_ty.attrs.keys()); + total_suggs.append(&mut suggs); + schema_names.push(schema_ty.name.clone()); + } else { + // If there is a schema attribute that meets the condition, the type check passes + return; + } + } + TypeKind::Dict(..) => return, + _ => continue, + } + } + if !schema_names.is_empty() { + let mut msgs = vec![Message { + range: range.clone(), + style: Style::LineAndColumn, + message: format!( + "Cannot add member '{}' to '{}'{}", + attr, + if schema_names.len() > 1 { + format!("schemas {:?}", schema_names) + } else { + format!("schema {}", schema_names[0]) + }, + if total_suggs.is_empty() { + "".to_string() + } else { + format!(", did you mean '{:?}'?", total_suggs) + }, + ), + note: None, + suggested_replacement: Some(total_suggs), + }]; + if let Some(attr_range) = attr_range { + msgs.push(Message { + range: attr_range.clone(), + style: Style::LineAndColumn, + message: "config attribute is defined here".to_string(), + note: None, + suggested_replacement: None, + }); + } + self.handler.add_error(ErrorKind::CompileError, &msgs); } } } /// Check config attr has been defined. - pub(crate) fn check_config_attr(&mut self, attr: &str, pos: &Position, schema_ty: &SchemaType) { - let runtime_type = kclvm::schema_runtime_type(&schema_ty.name, &schema_ty.pkgpath); + pub(crate) fn check_config_attr( + &mut self, + attr: &str, + schema_ty: &SchemaType, + range: &Range, + attr_range: Option<&Range>, + ) { + let runtime_type = kclvm_runtime::schema_runtime_type(&schema_ty.name, &schema_ty.pkgpath); match self.ctx.schema_mapping.get(&runtime_type) { Some(schema_mapping_ty) => { - let schema_ty = schema_mapping_ty.borrow(); - if schema_ty.get_obj_of_attr(attr).is_none() - && !schema_ty.is_mixin - && schema_ty.index_signature.is_none() - { - self.handler.add_compile_error( - &format!( - "Cannot add member '{}' to schema '{}'", - attr, schema_ty.name - ), - pos.clone(), - ); - } + let schema_ty = schema_mapping_ty.clone(); + let schema_ty_ref = schema_ty.borrow(); + self.check_config_attr_without_schema_mapping( + attr, + &schema_ty_ref, + range, + attr_range, + ); } None => { - if schema_ty.get_obj_of_attr(attr).is_none() - && !schema_ty.is_mixin - && schema_ty.index_signature.is_none() - { - self.handler.add_compile_error( - &format!( - "Cannot add member '{}' to schema '{}'", - attr, schema_ty.name - ), - pos.clone(), - ); - } + self.check_config_attr_without_schema_mapping(attr, schema_ty, range, attr_range); } }; } + fn check_config_attr_without_schema_mapping( + &mut self, + attr: &str, + schema_ty: &SchemaType, + range: &Range, + attr_range: Option<&Range>, + ) { + if schema_ty.get_obj_of_attr(attr).is_none() + && !schema_ty.is_mixin + && schema_ty.index_signature.is_none() + { + let (suggs, msg) = self.get_config_attr_err_suggestion_from_schema(attr, schema_ty); + self.add_config_attr_error(attr, schema_ty, range, attr_range, suggs, msg); + } + if let Some(index_signature) = &schema_ty.index_signature { + // Here we need to check whether the key of the index signature is a string literal type or a string literal union types + if !index_signature.any_other { + match &index_signature.key_ty.kind { + TypeKind::StrLit(name) => { + if name != attr { + let (suggs, msg) = self.get_config_attr_err_suggestion(attr, &[name]); + self.add_config_attr_error( + attr, schema_ty, range, attr_range, suggs, msg, + ); + } + } + TypeKind::Union(types) => { + let mut keys: HashSet = HashSet::default(); + for ty in types { + if let TypeKind::StrLit(name) = &ty.kind { + keys.insert(name.clone()); + } + } + if !keys.contains(attr) { + let (suggs, msg) = self.get_config_attr_err_suggestion(attr, &keys); + self.add_config_attr_error( + attr, schema_ty, range, attr_range, suggs, msg, + ); + } + } + _ => {} + } + } + } + } + + fn add_config_attr_error( + &mut self, + attr: &str, + schema_ty: &SchemaType, + range: &Range, + attr_range: Option<&Range>, + suggs: Vec, + msg: String, + ) { + let mut msgs = vec![Message { + range: range.clone(), + style: Style::LineAndColumn, + message: format!( + "Cannot add member '{}' to schema '{}'{}", + attr, schema_ty.name, msg, + ), + note: None, + suggested_replacement: Some(suggs), + }]; + if let Some(attr_range) = attr_range { + msgs.push(Message { + range: attr_range.clone(), + style: Style::LineAndColumn, + message: "config attribute is defined here".to_string(), + note: None, + suggested_replacement: None, + }); + } + self.handler.add_error(ErrorKind::CompileError, &msgs); + } + /// Schema load atr pub(crate) fn schema_load_attr( &mut self, schema_ty: &SchemaType, attr: &str, - ) -> (bool, Rc) { - let runtime_type = kclvm::schema_runtime_type(&schema_ty.name, &schema_ty.pkgpath); + ) -> (bool, TypeRef) { + let runtime_type = kclvm_runtime::schema_runtime_type(&schema_ty.name, &schema_ty.pkgpath); match self.ctx.schema_mapping.get(&runtime_type) { Some(schema_mapping_ty) => { let schema_ty = schema_mapping_ty.borrow(); @@ -371,4 +672,209 @@ impl<'ctx> Resolver<'ctx> { }, } } + + pub(crate) fn walk_config_entries( + &mut self, + entries: &'ctx [ast::NodeRef], + ) -> TypeRef { + let (start, end) = match entries.len() { + 0 => (self.ctx.start_pos.clone(), self.ctx.end_pos.clone()), + 1 => entries[0].get_span_pos(), + _ => ( + entries.first().unwrap().get_pos(), + entries.last().unwrap().get_end_pos(), + ), + }; + self.enter_scope(start, end, ScopeKind::Config); + let mut key_types: Vec = vec![]; + let mut val_types: Vec = vec![]; + let mut attrs: IndexMap = IndexMap::new(); + for item in entries { + let key = &item.node.key; + let value = &item.node.value; + let op = &item.node.operation; + let mut stack_depth: usize = 0; + let value_ty = self.check_config_entry(key, value); + stack_depth += self.switch_config_expr_context_by_key(key); + let val_ty = match key { + Some(key) => match &key.node { + ast::Expr::Identifier(identifier) => { + let mut val_ty = value_ty.unwrap_or_else(|| self.expr(value)); + + for _ in 0..identifier.names.len() - 1 { + val_ty = Type::dict_ref(self.str_ty(), val_ty.clone()); + } + let key_ty = if identifier.names.len() == 1 { + let name = &identifier.names[0].node; + let key_ty = if self.ctx.local_vars.contains(name) { + // set key context expected schema as None + self.ctx.config_expr_context.push(None); + let key_ty = self.expr(key); + self.ctx.config_expr_context.pop(); + key_ty + } else { + Arc::new(Type::str_lit(name)) + }; + self.check_attr_ty(&key_ty, key.get_span_pos()); + let ty = if let Some(attr) = attrs.get(name) { + sup(&[attr.ty.clone(), val_ty.clone()]) + } else { + val_ty.clone() + }; + attrs.insert( + name.to_string(), + Attr { + ty: self.ctx.ty_ctx.infer_to_variable_type(ty.clone()), + range: key.get_span_pos(), + }, + ); + self.insert_object( + name, + ScopeObject { + name: name.to_string(), + start: key.get_pos(), + end: key.get_end_pos(), + ty, + kind: ScopeObjectKind::Attribute, + doc: None, + }, + ); + key_ty + } else { + self.str_ty() + }; + key_types.push(key_ty); + val_types.push(val_ty.clone()); + val_ty + } + ast::Expr::Subscript(subscript) if subscript.has_name_and_constant_index() => { + let val_ty = value_ty.unwrap_or_else(|| self.expr(value)); + key_types.push(self.str_ty()); + if matches!(op, ast::ConfigEntryOperation::Insert) { + val_types.push(val_ty.clone()); + } else { + val_types.push(Type::list_ref(val_ty.clone())); + } + val_ty + } + _ => { + // set key context expected schema as None + self.ctx.config_expr_context.push(None); + let key_ty = self.expr(key); + self.ctx.config_expr_context.pop(); + let val_ty = value_ty.unwrap_or_else(|| self.expr(value)); + self.check_attr_ty(&key_ty, key.get_span_pos()); + if let ast::Expr::StringLit(string_lit) = &key.node { + let ty = if let Some(attr) = attrs.get(&string_lit.value) { + sup(&[attr.ty.clone(), val_ty.clone()]) + } else { + val_ty.clone() + }; + attrs.insert( + string_lit.value.clone(), + Attr { + ty: self.ctx.ty_ctx.infer_to_variable_type(ty.clone()), + range: key.get_span_pos(), + }, + ); + self.insert_object( + &string_lit.value, + ScopeObject { + name: string_lit.value.clone(), + start: key.get_pos(), + end: key.get_end_pos(), + ty, + kind: ScopeObjectKind::Attribute, + doc: None, + }, + ); + } + key_types.push(key_ty); + val_types.push(val_ty.clone()); + val_ty + } + }, + None => { + let val_ty = value_ty.unwrap_or_else(|| self.expr(value)); + match &val_ty.kind { + TypeKind::None | TypeKind::Any => { + val_types.push(val_ty.clone()); + } + TypeKind::Dict(DictType { + key_ty, + val_ty, + attrs: merged_attrs, + }) => { + key_types.push(key_ty.clone()); + val_types.push(val_ty.clone()); + for (key, value) in merged_attrs { + attrs.insert(key.to_string(), value.clone()); + } + } + TypeKind::Schema(schema_ty) => { + key_types.push(schema_ty.key_ty()); + val_types.push(schema_ty.val_ty()); + for (key, attr) in &schema_ty.attrs { + attrs.insert( + key.to_string(), + Attr { + ty: attr.ty.clone(), + range: attr.range.clone(), + }, + ); + } + } + TypeKind::Union(types) + if self + .ctx + .ty_ctx + .is_config_type_or_config_union_type(val_ty.clone()) => + { + key_types.push(sup(&types + .iter() + .map(|ty| ty.config_key_ty()) + .collect::>())); + val_types.push(sup(&types + .iter() + .map(|ty| ty.config_val_ty()) + .collect::>())); + } + _ => { + self.handler.add_compile_error( + &format!( + "only dict and schema can be used ** unpack, got '{}'", + val_ty.ty_str() + ), + value.get_span_pos(), + ); + } + } + val_ty + } + }; + if matches!(op, ast::ConfigEntryOperation::Insert) + && !val_ty.is_any() + && !val_ty.is_list() + { + self.handler.add_error( + ErrorKind::IllegalAttributeError, + &[Message { + range: value.get_span_pos(), + style: Style::LineAndColumn, + message: format!( + "only list type can in inserted, got '{}'", + val_ty.ty_str() + ), + note: None, + suggested_replacement: None, + }], + ); + } + self.clear_config_expr_context(stack_depth, false); + } + self.leave_scope(); + let key_ty = sup(&key_types); + let val_ty = sup(&val_types); + Type::dict_ref_with_attrs(key_ty, val_ty, attrs) + } } diff --git a/kclvm/sema/src/resolver/doc.rs b/kclvm/sema/src/resolver/doc.rs new file mode 100644 index 000000000..089e4897d --- /dev/null +++ b/kclvm/sema/src/resolver/doc.rs @@ -0,0 +1,678 @@ +use kclvm_ast::ast::{self, SchemaStmt}; +use std::collections::{HashMap, HashSet}; +use std::iter::Iterator; +use std::str; + +const SINGLE_QUOTES_STR: &str = "'''"; +const DOUBLE_QUOTES_STR: &str = "\"\"\""; + +/// Strip leading and trailing triple quotes from the original docstring content +fn strip_quotes(original: &str) -> &str { + match original.chars().next() { + Some('\'') => match original.strip_prefix(SINGLE_QUOTES_STR) { + Some(s) => match s.strip_suffix(SINGLE_QUOTES_STR) { + Some(s) => s, + None => original, + }, + None => original, + }, + Some('"') => match original.strip_prefix(DOUBLE_QUOTES_STR) { + Some(s) => match s.strip_suffix(DOUBLE_QUOTES_STR) { + Some(s) => s, + None => original, + }, + None => original, + }, + // Raw string prefix 'r' + Some('r') => match original.strip_prefix('r') { + Some(s) => strip_quotes(s), + None => original, + }, + // Raw string prefix 'R' + Some('R') => match original.strip_prefix('R') { + Some(s) => strip_quotes(s), + None => original, + }, + _ => original, + } +} + +fn expand_tabs(s: &str, spaces_per_tab: usize) -> String { + s.replace("\t", &" ".repeat(spaces_per_tab)) +} + +/// Clean up indentation by removing any common leading whitespace on all lines after the first line. +fn clean_doc(doc: &str) -> String { + let tab_expanded = expand_tabs(&doc, 4); + let mut lines: Vec<&str> = tab_expanded.split('\n').collect(); + // Find minimum indentation of any non-blank lines after first line. + // Skip first line since it's not indented. + if !lines.is_empty() { + let margin = lines[1..] // skip first line + .iter() + .filter(|line| !line.trim().is_empty()) // skip empty lines + .map(|line| line.chars().take_while(|c| c.is_whitespace()).count()) // count leading whitespaces of each line + .min() // return the minimum indentation + .unwrap_or(0); + + lines[1..].iter_mut().for_each(|line| { + *line = if line.trim().len() > 0 { + if let Some(sub) = line.get(margin..) { + sub + } else { + line.trim() + } + } else { + line.trim() + }; // remove command indentation + }); + + // Remove trailing and leading blank lines. + while !lines.is_empty() && lines.last().unwrap().trim().is_empty() { + lines.pop(); + } + while !lines.is_empty() && lines[0].trim().is_empty() { + lines.remove(0); + } + } + lines.join("\n") +} + +/// A line-based string reader. +struct Reader { + data: Vec, + l: usize, +} + +impl Reader { + fn new(data: String) -> Self { + let data_vec: Vec = data.split('\n').map(|s| s.to_string()).collect(); + Self { + data: data_vec, + l: 0, + } + } + fn reset(&mut self) { + self.l = 0; + } + + fn read(&mut self) -> String { + if !self.eof() { + let out = self.data[self.l].clone(); + self.l += 1; + return out; + } else { + return "".to_string(); + } + } + + fn seek_next_non_empty_line(&mut self) { + for l in self.data[self.l..].iter() { + if l.trim().len() > 0 { + break; + } else { + self.l += 1; + } + } + } + + fn eof(&self) -> bool { + self.l >= self.data.len() + } + + fn read_to_condition(&mut self, condition_func: &dyn Fn(&str) -> bool) -> Vec { + let start = self.l; + for line in self.data[start..].iter() { + if condition_func(line) { + return self.data[start..self.l].to_vec(); + } + self.l += 1; + if self.eof() { + return self.data[start..self.l].to_vec(); + } + } + return vec![]; + } + + fn read_to_next_empty_line(&mut self) -> Vec { + self.seek_next_non_empty_line(); + + fn is_empty(line: &str) -> bool { + return line.trim().len() == 0; + } + + return self.read_to_condition(&is_empty); + } + + fn read_to_next_unindented_line(&mut self) -> Vec { + fn is_unindented(line: &str) -> bool { + return line.trim().len() > 0 && line.trim_start().len() == line.len(); + } + + return self.read_to_condition(&is_unindented); + } + + fn peek(&self, n: usize, positive: bool) -> String { + if positive { + if self.l + n < self.data.len() { + return self.data[self.l + n].clone(); + } else { + return "".to_string(); + } + } else { + if self.l >= n { + return self.data[self.l - n].clone(); + } else { + return "".to_string(); + } + } + } +} + +/// Checks if current line is at the beginning of a section +fn is_at_section(doc: &mut Reader) -> bool { + doc.seek_next_non_empty_line(); + if doc.eof() { + return false; + } + let l1 = doc.peek(0, true); + let l1 = l1.trim(); + let l2 = doc.peek(1, true); + let l2 = l2.trim(); // ---------- or ========== + let l2_char_set = l2.chars().collect::>(); + + if l2.len() >= 3 + && l2_char_set.len() == 1 + && (l2.contains('-') || l2.contains('=')) + && l1.len() != l1.len() + { + // todo: when line2 is conformed with "-" or "=", but the number of the "-/=" mismatch the section title length, mark as a section and return a warning + return false; + } + l2.starts_with(&"-".repeat(l1.len())) || l2.starts_with(&"=".repeat(l1.len())) +} + +/// Reads lines before next section beginning, continuous empty lines will be merged to one +fn read_to_next_section(doc: &mut Reader) -> Vec { + let mut section = doc.read_to_next_empty_line(); + + while !is_at_section(doc) && !doc.eof() { + if doc.peek(1, false).trim().is_empty() { + section.push(doc.peek(1, false)); + } + section.append(&mut doc.read_to_next_empty_line()); + } + section +} + +/// Parse the Attribute Section of the docstring to list of Attribute +fn parse_attr_list(content: String) -> Vec { + let mut r = Reader::new(content); + let mut attrs = vec![]; + while !r.eof() { + let header = r.read(); + let header = header.trim(); + if header.contains(": ") { + let parts: Vec<&str> = header.split(": ").collect(); + let arg_name = parts[0].trim(); + + let desc_lines = r + .read_to_next_unindented_line() + .iter() + .map(|s| s.trim().to_string()) + .collect(); + attrs.push(Attribute::new(arg_name.to_string(), desc_lines)); + } else { + r.read_to_next_unindented_line(); + } + } + attrs +} + +/// Parse the summary of the schema. The final summary content will be a concat of lines in the original summary with whitespace. +fn parse_summary(doc: &mut Reader) -> String { + if is_at_section(doc) { + // no summary provided + return "".to_string(); + } + let lines = read_to_next_section(doc); + lines + .iter() + .map(|s| s.trim()) + .collect::>() + .join(" ") + .trim() + .to_string() +} + +/// Parse the schema docstring to Doc. +/// The summary of the schema content will be concatenated to a single line string by whitespace. +/// The description of each attribute will be returned as separate lines. +pub fn parse_schema_doc_string(ori: &str) -> SchemaDoc { + if ori.is_empty() { + return SchemaDoc::new("".to_string(), vec![], HashMap::new()); + } + let mut doc = Reader::new(clean_doc(strip_quotes(&ori))); + doc.reset(); + let summary = parse_summary(&mut doc); + + let attr_section = read_to_next_section(&mut doc); + + let attr_content = attr_section.join("\n"); + + let attrs = parse_attr_list(attr_content); + + let mut examples = HashMap::new(); + let example_section = read_to_next_section(&mut doc); + if !example_section.is_empty() { + let default_example_content = match example_section.len() { + 0 | 1 | 2 => "".to_string(), + _ => example_section[2..].join("\n"), + }; + examples.insert( + "Default example".to_string(), + Example::new("".to_string(), "".to_string(), default_example_content), + ); + } + SchemaDoc::new(summary, attrs, examples) +} + +/// The Doc struct contains a summary of schema and all the attributes described in the the docstring. +#[derive(Debug, PartialEq, Eq, Clone)] +pub struct SchemaDoc { + pub summary: String, + pub attrs: Vec, + pub examples: HashMap, +} + +impl SchemaDoc { + pub fn new(summary: String, attrs: Vec, examples: HashMap) -> Self { + Self { + summary, + attrs, + examples, + } + } + pub fn new_from_schema_stmt(schema: &SchemaStmt) -> Self { + let attrs = schema + .get_left_identifier_list() + .iter() + .map(|(_, _, attr_name)| attr_name.clone()) + .collect::>(); + Self { + summary: "".to_string(), + attrs: attrs + .iter() + .map(|name| Attribute::new(name.clone(), vec![])) + .collect(), + examples: HashMap::new(), + } + } + + pub fn to_doc_string(self) -> String { + let summary = self.summary; + let attrs_string = self + .attrs + .iter() + .map(|attr| format!("{}: {}", attr.name, attr.desc.join("\n"))) + .collect::>() + .join("\n"); + let examples_string = self + .examples + .values() + .map(|example| { + format!( + "{}\n{}\n{}", + example.summary, example.description, example.value + ) + }) + .collect::>() + .join("\n"); + format!("{summary}\n\nAttributes\n----------\n{attrs_string}\n\nExamples\n--------{examples_string}\n") + } +} + +/// The Attribute struct contains the attribute name and the corresponding description. +#[derive(Debug, PartialEq, Eq, Clone)] +pub struct Attribute { + pub name: String, + pub desc: Vec, +} + +impl Attribute { + fn new(name: String, desc: Vec) -> Self { + Self { name, desc } + } +} + +/// The Example struct contains the example summary and the literal content +#[derive(Debug, PartialEq, Eq, Clone)] +pub struct Example { + pub summary: String, + pub description: String, + pub value: String, +} + +impl Example { + fn new(summary: String, description: String, value: String) -> Self { + Self { + summary, + description, + value, + } + } +} + +/// Extract doc string from the AST body, if the first statement is a long string expression +/// statement, convert it to a doc string. +pub fn extract_doc_from_body(stmts: &[Box>]) -> Option { + match stmts.first() { + Some(stmt) => match &stmt.node { + ast::Stmt::Expr(expr_stmt) => match expr_stmt.exprs.first() { + Some(expr) => match &expr.node { + ast::Expr::StringLit(str) if str.is_long_string => Some(str.raw_value.clone()), + ast::Expr::JoinedString(str) if str.is_long_string => { + Some(str.raw_value.clone()) + } + _ => None, + }, + None => None, + }, + _ => None, + }, + None => None, + } + .map(|v| clean_doc(strip_quotes(&v))) +} + +#[cfg(test)] +mod tests { + use super::{clean_doc, is_at_section, read_to_next_section, strip_quotes, Reader}; + use crate::resolver::doc::{parse_schema_doc_string, Example}; + use std::fs::File; + use std::io::prelude::*; + use std::path::PathBuf; + + fn read_doc_content() -> String { + let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + path.push("src/resolver/test_data/doc.txt"); + let mut file = File::open(path).expect("Unable to open file"); + + let mut contents = String::new(); + file.read_to_string(&mut contents) + .expect("Unable to read file"); + + if cfg!(windows) { + contents = contents.replace("\r\n", "\n") + } + contents + } + + #[test] + fn test_strip_quotes() { + let ori_from_file = read_doc_content(); + + let oris = [ + r#""""abcde""""#, + r#"'''abc +de'''"#, + ori_from_file.as_str(), + ]; + let results = [ + "abcde", + "abc +de", + r#" + Server is the common user interface for long-running + services adopting the best practice of Kubernetes. + + Attributes + ---------- + workloadType : str, default is "Deployment", required + Use this attribute to specify which kind of long-running service you want. + Valid values: Deployment, CafeDeployment. + See also: kusion_models/core/v1/workload_metadata.k. + name : str, required + A Server-level attribute. + The name of the long-running service. + See also: kusion_models/core/v1/metadata.k. + labels: {str:str}, optional + A Server-level attribute. + The labels of the long-running service. + See also: kusion_models/core/v1/metadata.k. + + Examples + ---------------------- + myCustomApp = AppConfiguration { + name = "componentName" + } + "#, + ]; + + for (ori, res) in oris.iter().zip(results.iter()) { + assert_eq!(strip_quotes(ori).to_string(), res.to_string()); + } + } + + #[test] + fn test_clean_doc() { + let ori = clean_doc(strip_quotes(&read_doc_content())); + let expect_cleaned = r#"Server is the common user interface for long-running +services adopting the best practice of Kubernetes. + +Attributes +---------- +workloadType : str, default is "Deployment", required + Use this attribute to specify which kind of long-running service you want. + Valid values: Deployment, CafeDeployment. + See also: kusion_models/core/v1/workload_metadata.k. +name : str, required + A Server-level attribute. + The name of the long-running service. + See also: kusion_models/core/v1/metadata.k. +labels: {str:str}, optional + A Server-level attribute. + The labels of the long-running service. + See also: kusion_models/core/v1/metadata.k. + +Examples +---------------------- +myCustomApp = AppConfiguration { + name = "componentName" +}"#; + assert_eq!(ori.to_string(), expect_cleaned.to_string()); + } + + #[test] + fn test_seek_next_non_empty_line() { + let data = "line1 + line2 + + + line3 + + line4 + + "; + let mut reader = Reader::new(data.to_string()); + + // Test initial position + assert_eq!(reader.l, 0); + + // Test seek to next non-empty line + reader.seek_next_non_empty_line(); + assert_eq!(reader.l, 0); // line1 + assert_eq!(reader.read(), "line1"); + reader.seek_next_non_empty_line(); + assert_eq!(reader.l, 1); // line2 + assert_eq!(reader.read(), " line2"); + reader.seek_next_non_empty_line(); + assert_eq!(reader.l, 4); // line3 + assert_eq!(reader.read(), " line3"); + reader.seek_next_non_empty_line(); + assert_eq!(reader.l, 6); // line4 + assert_eq!(reader.read(), " line4"); + // Test seek at the end of the data + reader.seek_next_non_empty_line(); + assert_eq!(reader.l, 9); // end of data + assert_eq!(reader.read(), ""); + assert!(reader.eof()); + } + + #[test] + fn test_read_to_next_empty_line() { + let data = "hello + world + + foo + bar + +abc + "; + let mut reader = Reader::new(data.to_string()); + + let output = reader.read_to_next_empty_line(); + assert_eq!(output, vec!["hello", " world"]); + + let output = reader.read_to_next_empty_line(); + assert_eq!(output, vec![" foo", " bar"]); + + let output = reader.read_to_next_empty_line(); + assert_eq!(output, vec!["abc"]); + + let output = reader.read_to_next_empty_line(); + assert_eq!(output.len(), 0); + } + + #[test] + fn test_read_to_next_unindented_line() { + let data = " + indented line + indented line + indented line + indented line + +unindented line + "; + let mut reader = Reader::new(data.to_string()); + let result = reader.read_to_next_unindented_line(); + assert_eq!( + result, + vec![ + "", + " indented line", + " indented line", + " indented line", + " indented line", + "" + ] + ); + } + + #[test] + fn test_at_section() { + let data = "Summary + Attribute + --------- + description" + .to_string(); + + let data = clean_doc(&data); + let mut doc = Reader::new(data); + assert!(!is_at_section(&mut doc)); + + assert_eq!(doc.read(), "Summary"); + assert!(is_at_section(&mut doc)); + + assert_eq!(doc.read(), "Attribute"); + assert!(!is_at_section(&mut doc)); + } + + #[test] + fn test_read_to_next_section() { + let data = "Summary + + + SummaryContinue + + + Attribute + --------- + attr1 + description + + attr2 + description + + Example + ------- + content + + content + + See Also + -------- + content" + .to_string(); + let data = clean_doc(&data); + let mut doc = Reader::new(data); + assert_eq!( + read_to_next_section(&mut doc), + vec!["Summary", "", "SummaryContinue"] + ); + } + + #[test] + fn test_parse_doc() { + let mut content = read_doc_content(); + let doc = parse_schema_doc_string(&mut content); + assert_eq!( + doc.summary, + "Server is the common user interface for long-running services adopting the best practice of Kubernetes." + ); + + assert_eq!(doc.attrs.len(), 3); + assert_eq!(doc.attrs[0].name, "workloadType".to_string()); + assert_eq!( + doc.attrs[0].desc, + vec![ + "Use this attribute to specify which kind of long-running service you want." + .to_string(), + "Valid values: Deployment, CafeDeployment.".to_string(), + "See also: kusion_models/core/v1/workload_metadata.k.".to_string() + ] + ); + + assert_eq!(doc.attrs[1].name, "name".to_string()); + assert_eq!( + doc.attrs[1].desc, + vec![ + "A Server-level attribute.".to_string(), + "The name of the long-running service.".to_string(), + "See also: kusion_models/core/v1/metadata.k.".to_string(), + ] + ); + + assert_eq!(doc.attrs[2].name, "labels".to_string()); + assert_eq!( + doc.attrs[2].desc, + vec![ + "A Server-level attribute.".to_string(), + "The labels of the long-running service.".to_string(), + "See also: kusion_models/core/v1/metadata.k.".to_string(), + ] + ); + assert!(doc.examples.contains_key("Default example")); + assert_eq!( + doc.examples.get("Default example"), + Some(&Example::new( + "".to_string(), + "".to_string(), + "myCustomApp = AppConfiguration { + name = \"componentName\" +}" + .to_string() + )) + ); + } +} diff --git a/kclvm/sema/src/resolver/global.rs b/kclvm/sema/src/resolver/global.rs index 6d0e9a73c..9f5c97adc 100644 --- a/kclvm/sema/src/resolver/global.rs +++ b/kclvm/sema/src/resolver/global.rs @@ -1,35 +1,46 @@ use std::cell::RefCell; -use std::rc::Rc; +use std::sync::Arc; use crate::info::is_private_field; use crate::resolver::Resolver; use crate::ty::{ - is_upper_bound, DecoratorTarget, FunctionType, Parameter, SchemaAttr, SchemaIndexSignature, - SchemaType, Type, TypeKind, RESERVED_TYPE_IDENTIFIERS, + full_ty_str, is_upper_bound, DecoratorTarget, FunctionType, Parameter, SchemaAttr, + SchemaIndexSignature, SchemaType, Type, TypeKind, RESERVED_TYPE_IDENTIFIERS, }; use indexmap::IndexMap; use kclvm_ast::ast; -use kclvm_ast::walker::MutSelfTypedResultWalker; +use kclvm_ast_pretty::{print_ast_node, print_schema_expr, ASTNode}; use kclvm_error::*; +use super::doc::parse_schema_doc_string; use super::scope::{ScopeObject, ScopeObjectKind}; -use crate::resolver::pos::GetPos; +use kclvm_ast::pos::GetPos; const MAX_SCOPE_SCAN_COUNT: usize = 3; pub const MIXIN_SUFFIX: &str = "Mixin"; pub const PROTOCOL_SUFFIX: &str = "Protocol"; -impl<'ctx> Resolver<'ctx> { +impl<'ctx> Resolver<'_> { /// Init global types including top-level global variable types and /// schema types. Because the schema allows backward references, /// we scan multiple times. pub(crate) fn init_global_types(&mut self) { // 1. Scan all schema and rule type symbols let pkgpath = &self.ctx.pkgpath; - match self.program.pkgs.get(pkgpath) { + match self + .program + .pkgs + .get(pkgpath) + .or(self.program.pkgs_not_imported.get(pkgpath)) + { Some(modules) => { // 1. Scan all schema and rule type symbol for module in modules { + let module = self + .program + .get_module(module) + .expect("Failed to acquire module lock") + .expect(&format!("module {:?} not found in program", module)); let pkgpath = &self.ctx.pkgpath.clone(); let filename = &module.filename; self.change_package_context(pkgpath, filename); @@ -38,33 +49,52 @@ impl<'ctx> Resolver<'ctx> { let (name, doc, is_mixin, is_protocol, is_rule) = match &stmt.node { ast::Stmt::Schema(schema_stmt) => ( &schema_stmt.name.node, - &schema_stmt.doc, + { + if let Some(doc) = &schema_stmt.doc { + doc.node.clone() + } else { + "".to_string() + } + }, schema_stmt.is_mixin, schema_stmt.is_protocol, false, ), - ast::Stmt::Rule(rule_stmt) => { - (&rule_stmt.name.node, &rule_stmt.doc, false, false, true) - } + ast::Stmt::Rule(rule_stmt) => ( + &rule_stmt.name.node, + { + if let Some(doc) = &rule_stmt.doc { + doc.node.clone() + } else { + "".to_string() + } + }, + false, + false, + true, + ), _ => continue, }; if self.contains_object(name) { self.handler.add_error( ErrorKind::UniqueKeyError, &[Message { - pos: start.clone(), + range: stmt.get_span_pos(), style: Style::LineAndColumn, - message: format!("unique key error name '{}'", name), + message: format!("Unique key error name '{}'", name), note: None, + suggested_replacement: None, }], ); continue; } + let parsed_doc = parse_schema_doc_string(&doc); let schema_ty = SchemaType { name: name.to_string(), pkgpath: self.ctx.pkgpath.clone(), filename: self.ctx.filename.clone(), - doc: doc.to_string(), + doc: parsed_doc.summary.clone(), + examples: parsed_doc.examples, is_instance: false, is_mixin, is_protocol, @@ -74,10 +104,10 @@ impl<'ctx> Resolver<'ctx> { mixins: vec![], attrs: IndexMap::default(), func: Box::new(FunctionType { - doc: doc.to_string(), + doc: parsed_doc.summary.clone(), params: vec![], self_ty: None, - return_ty: Rc::new(Type::VOID), + return_ty: Arc::new(Type::VOID), is_variadic: false, kw_only_index: None, }), @@ -90,8 +120,9 @@ impl<'ctx> Resolver<'ctx> { name: name.to_string(), start, end, - ty: Rc::new(Type::schema(schema_ty)), + ty: Arc::new(Type::schema(schema_ty.clone())), kind: ScopeObjectKind::Definition, + doc: Some(parsed_doc.summary.clone()), }, ) } @@ -101,6 +132,11 @@ impl<'ctx> Resolver<'ctx> { // 3. Build all schema types for i in 0..MAX_SCOPE_SCAN_COUNT { for module in modules { + let module = self + .program + .get_module(module) + .expect("Failed to acquire module lock") + .expect(&format!("module {:?} not found in program", module)); let pkgpath = &self.ctx.pkgpath.clone(); let filename = &module.filename; self.change_package_context(pkgpath, filename); @@ -133,8 +169,9 @@ impl<'ctx> Resolver<'ctx> { name: schema_ty.name.to_string(), start, end, - ty: Rc::new(Type::schema(schema_ty)), + ty: Arc::new(Type::schema(schema_ty.clone())), kind: ScopeObjectKind::Definition, + doc: Some(schema_ty.doc), }, ) } @@ -154,6 +191,12 @@ impl<'ctx> Resolver<'ctx> { Some(modules) => { // 1. Scan all schema and rule type symbol for module in modules { + let module = self + .program + .get_module(module) + .expect("Failed to acquire module lock") + .expect(&format!("module {:?} not found in program", module)); + self.ctx.filename = module.filename.to_string(); for stmt in &module.body { if matches!(stmt.node, ast::Stmt::TypeAlias(_)) { self.stmt(stmt); @@ -163,17 +206,19 @@ impl<'ctx> Resolver<'ctx> { } } None => { + let pos = Position { + filename: self.ctx.filename.clone(), + line: 1, + column: None, + }; self.handler.add_error( ErrorKind::CannotFindModule, &[Message { - pos: Position { - filename: self.ctx.filename.clone(), - line: 1, - column: Some(1), - }, + range: (pos.clone(), pos), style: Style::Line, message: format!("pkgpath {} not found in the program", self.ctx.pkgpath), note: None, + suggested_replacement: None, }], ); } @@ -191,7 +236,7 @@ impl<'ctx> Resolver<'ctx> { self.init_scope_with_assign_stmt(assign_stmt, unique_check) } ast::Stmt::Unification(unification_stmt) => { - self.init_scope_with_unification_stmt(unification_stmt, unique_check) + self.init_scope_with_unification_stmt(unification_stmt) } ast::Stmt::If(if_stmt) => { self.init_scope_with_stmts(&if_stmt.body, unique_check); @@ -208,42 +253,46 @@ impl<'ctx> Resolver<'ctx> { unique_check: bool, ) { for target in &assign_stmt.targets { - let name = &target.node.names[0]; + let name = &target.node.name.node; let (start, end) = target.get_span_pos(); if self.contains_object(name) && !is_private_field(name) && unique_check { self.handler.add_error( ErrorKind::ImmutableError, &[ Message { - pos: start.clone(), + range: target.get_span_pos(), style: Style::LineAndColumn, message: format!( "Can not change the value of '{}', because it was declared immutable", name ), note: None, + suggested_replacement: None, }, Message { - pos: self + range: self .scope .borrow() .elems .get(name) .unwrap() .borrow() - .start - .clone(), + .get_span_pos(), style: Style::LineAndColumn, - message: format!("The variable '{}' is declared here firstly", name), - note: Some(format!("change the variable name to '_{}'", name)), + message: format!("The variable '{}' is declared here", name), + note: Some(format!( + "change the variable name to '_{}' to make it mutable", + name + )), + suggested_replacement: None, }, ], ); continue; } let ty = if let Some(ty_annotation) = &assign_stmt.ty { - let ty = &ty_annotation.node; - let ty = self.parse_ty_with_scope(ty, ty_annotation.get_pos()); + let ty = + self.parse_ty_with_scope(Some(&ty_annotation), ty_annotation.get_span_pos()); if let Some(obj) = self.scope.borrow().elems.get(name) { let obj = obj.borrow(); if !is_upper_bound(obj.ty.clone(), ty.clone()) { @@ -251,16 +300,22 @@ impl<'ctx> Resolver<'ctx> { ErrorKind::TypeError, &[ Message { - pos: obj.start.clone(), + range: target.get_span_pos(), style: Style::LineAndColumn, - message: format!("expect {}", obj.ty.ty_str()), + message: format!( + "can not change the type of '{}' to {}", + name, + obj.ty.ty_str() + ), note: None, + suggested_replacement: None, }, Message { - pos: start.clone(), + range: obj.get_span_pos(), style: Style::LineAndColumn, - message: format!("can not change the type of '{}'", name), - note: Some(format!("got {}", ty.ty_str())), + message: format!("expected {}", obj.ty.ty_str()), + note: None, + suggested_replacement: None, }, ], ); @@ -280,51 +335,20 @@ impl<'ctx> Resolver<'ctx> { end, ty, kind: ScopeObjectKind::Variable, + doc: None, }, ); } } - fn init_scope_with_unification_stmt( - &mut self, - unification_stmt: &'ctx ast::UnificationStmt, - unique_check: bool, - ) { + fn init_scope_with_unification_stmt(&mut self, unification_stmt: &'ctx ast::UnificationStmt) { let target = &unification_stmt.target; - let name = &target.node.names[0]; - let (start, end) = target.get_span_pos(); - if self.contains_object(name) && !is_private_field(name) && unique_check { - self.handler.add_error( - ErrorKind::ImmutableError, - &[ - Message { - pos: start, - style: Style::LineAndColumn, - message: format!( - "Can not change the value of '{}', because it was declared immutable", - name - ), - note: None, - }, - Message { - pos: self - .scope - .borrow() - .elems - .get(name) - .unwrap() - .borrow() - .start - .clone(), - style: Style::LineAndColumn, - message: format!("The variable '{}' is declared here firstly", name), - note: Some(format!("Change the variable name to '_{}'", name)), - }, - ], - ); + if target.node.names.is_empty() { return; } - let ty = self.walk_identifier(&unification_stmt.value.node.name.node); + let name = &target.node.names[0].node; + let (start, end) = target.get_span_pos(); + let ty = self.walk_identifier_expr(&unification_stmt.value.node.name); self.insert_object( name, ScopeObject { @@ -333,6 +357,7 @@ impl<'ctx> Resolver<'ctx> { end, ty, kind: ScopeObjectKind::Variable, + doc: None, }, ); } @@ -342,7 +367,7 @@ impl<'ctx> Resolver<'ctx> { rule_stmt: &'ctx ast::RuleStmt, ) -> Option> { if let Some(host_name) = &rule_stmt.for_host_name { - let ty = self.walk_identifier(&host_name.node); + let ty = self.walk_identifier_expr(&host_name); match &ty.kind { TypeKind::Schema(schema_ty) if schema_ty.is_protocol && !schema_ty.is_instance => { Some(Box::new(schema_ty.clone())) @@ -351,13 +376,14 @@ impl<'ctx> Resolver<'ctx> { self.handler.add_error( ErrorKind::IllegalInheritError, &[Message { - pos: host_name.get_pos(), + range: host_name.get_span_pos(), style: Style::LineAndColumn, message: format!( "invalid schema inherit object type, expect protocol, got '{}'", ty.ty_str() ), note: None, + suggested_replacement: None, }], ); None @@ -377,16 +403,17 @@ impl<'ctx> Resolver<'ctx> { self.handler.add_error( ErrorKind::IllegalInheritError, &[Message { - pos: host_name.get_pos(), + range: host_name.get_span_pos(), style: Style::LineAndColumn, message: "only schema mixin can inherit from protocol".to_string(), note: None, + suggested_replacement: None, }], ); return None; } // Mixin type check with protocol - let ty = self.walk_identifier(&host_name.node); + let ty = self.walk_identifier_expr(&host_name); match &ty.kind { TypeKind::Schema(schema_ty) if schema_ty.is_protocol && !schema_ty.is_instance => { Some(Box::new(schema_ty.clone())) @@ -395,13 +422,14 @@ impl<'ctx> Resolver<'ctx> { self.handler.add_error( ErrorKind::IllegalInheritError, &[Message { - pos: host_name.get_pos(), + range: host_name.get_span_pos(), style: Style::LineAndColumn, message: format!( "invalid schema inherit object type, expect protocol, got '{}'", ty.ty_str() ), note: None, + suggested_replacement: None, }], ); None @@ -417,7 +445,7 @@ impl<'ctx> Resolver<'ctx> { schema_stmt: &'ctx ast::SchemaStmt, ) -> Option> { if let Some(parent_name) = &schema_stmt.parent_name { - let ty = self.walk_identifier(&parent_name.node); + let ty = self.walk_identifier_expr(&parent_name); match &ty.kind { TypeKind::Schema(schema_ty) if !schema_ty.is_protocol && !schema_ty.is_mixin && !schema_ty.is_instance => @@ -428,13 +456,14 @@ impl<'ctx> Resolver<'ctx> { self.handler.add_error( ErrorKind::IllegalInheritError, &[Message { - pos: parent_name.get_pos(), + range: parent_name.get_span_pos(), style: Style::LineAndColumn, message: format!( - "invalid schema inherit object type, expect protocol, got '{}'", + "invalid schema inherit object type, expect schema, got '{}'", ty.ty_str() ), note: None, + suggested_replacement: None, }], ); None @@ -453,31 +482,30 @@ impl<'ctx> Resolver<'ctx> { should_add_schema_ref: bool, ) -> SchemaType { let name = &schema_stmt.name.node; - let pos = schema_stmt.name.get_end_pos(); if RESERVED_TYPE_IDENTIFIERS.contains(&name.as_str()) { - self.handler.add_compile_error( + self.handler.add_compile_error_with_suggestions( &format!( "schema name '{}' cannot be the same as the built-in types ({:?})", name, RESERVED_TYPE_IDENTIFIERS ), - pos.clone(), + schema_stmt.name.get_span_pos(), + Some(vec![]), ); } if schema_stmt.is_protocol && !name.ends_with(PROTOCOL_SUFFIX) { - self.handler.add_error( - ErrorKind::CompileError, - &[Message { - pos: pos.clone(), - style: Style::LineAndColumn, - message: format!("schema protocol name must end with '{}'", PROTOCOL_SUFFIX), - note: None, - }], + self.handler.add_compile_error_with_suggestions( + &format!("schema protocol name must end with '{}'", PROTOCOL_SUFFIX), + ( + schema_stmt.name.get_end_pos(), + schema_stmt.name.get_end_pos(), + ), + Some(vec![PROTOCOL_SUFFIX.to_string()]), ); } if schema_stmt.is_protocol && !schema_stmt.has_only_attribute_definitions() { self.handler.add_compile_error( "a protocol is only allowed to define attributes in it", - pos.clone(), + schema_stmt.name.get_span_pos(), ); } let parent_name = parent_ty @@ -487,10 +515,11 @@ impl<'ctx> Resolver<'ctx> { self.handler.add_error( ErrorKind::IllegalInheritError, &[Message { - pos: pos.clone(), + range: schema_stmt.name.get_span_pos(), style: Style::LineAndColumn, message: format!("mixin inheritance {} is prohibited", parent_name), note: None, + suggested_replacement: None, }], ); } @@ -501,25 +530,26 @@ impl<'ctx> Resolver<'ctx> { .collect(); let index_signature = if let Some(index_signature) = &schema_stmt.index_signature { if let Some(index_sign_name) = &index_signature.node.key_name { - if schema_attr_names.contains(index_sign_name) { + if schema_attr_names.contains(&index_sign_name.node) { self.handler.add_error( ErrorKind::IndexSignatureError, &[Message { - pos: index_signature.get_pos(), + range: index_signature.get_span_pos(), style: Style::LineAndColumn, - message: format!("index signature attribute name '{}' cannot have the same name as schema attributes", index_sign_name), + message: format!("index signature attribute name '{}' cannot have the same name as schema attributes", index_sign_name.node), note: None, + suggested_replacement: None, }], ); } } let key_ty = self.parse_ty_str_with_scope( - &index_signature.node.key_type.node, - index_signature.node.key_type.get_pos(), + &index_signature.node.key_ty.node.to_string(), + index_signature.node.key_ty.get_span_pos(), ); - let val_ty = self.parse_ty_str_with_scope( - &index_signature.node.value_type.node, - index_signature.node.value_type.get_pos(), + let val_ty = self.parse_ty_with_scope( + Some(&index_signature.node.value_ty), + index_signature.node.value_ty.get_span_pos(), ); if !self .ctx @@ -529,15 +559,16 @@ impl<'ctx> Resolver<'ctx> { self.handler.add_error( ErrorKind::IndexSignatureError, &[Message { - pos: pos.clone(), + range: schema_stmt.name.get_span_pos(), style: Style::LineAndColumn, message: format!("invalid index signature key type: '{}'", key_ty.ty_str()), note: None, + suggested_replacement: None, }], ); } Some(Box::new(SchemaIndexSignature { - key_name: index_signature.node.key_name.clone(), + key_name: index_signature.node.key_name.clone().map(|n| n.node), key_ty, val_ty, any_other: index_signature.node.any_other, @@ -547,44 +578,59 @@ impl<'ctx> Resolver<'ctx> { }; // Schema attributes let mut attr_obj_map: IndexMap = IndexMap::default(); - attr_obj_map.insert( - kclvm::SCHEMA_SETTINGS_ATTR_NAME.to_string(), - SchemaAttr { - is_optional: true, - has_default: false, - ty: Type::dict_ref(self.str_ty(), self.any_ty()), - pos: Position { - filename: self.ctx.filename.clone(), - line: pos.line, - column: pos.column, - }, - }, + let parsed_doc = parse_schema_doc_string( + &schema_stmt + .doc + .as_ref() + .map(|doc| doc.node.clone()) + .unwrap_or_default(), ); for stmt in &schema_stmt.body { - let pos = stmt.get_pos(); - let (name, ty, is_optional, has_default) = match &stmt.node { + let (name, ty, is_optional, default, decorators, range) = match &stmt.node { ast::Stmt::Unification(unification_stmt) => { - let name = unification_stmt.value.node.name.node.names[0].clone(); - let ty = self.parse_ty_str_with_scope(&name, pos.clone()); - let is_optional = true; - let has_default = true; - (name, ty, is_optional, has_default) + let name = unification_stmt.value.node.name.node.get_name(); + let ty = self.parse_ty_str_with_scope(&name, stmt.get_span_pos()); + let is_optional = false; + let default = if self.options.resolve_val { + print_schema_expr(&unification_stmt.value.node) + } else { + "".to_string() + }; + ( + unification_stmt.target.node.get_name(), + ty, + is_optional, + Some(default), + vec![], + stmt.get_span_pos(), + ) } ast::Stmt::SchemaAttr(schema_attr) => { let name = schema_attr.name.node.clone(); - let ty = self.parse_ty_with_scope( - &schema_attr - .ty - .as_ref() - .map_or(ast::Type::Any, |ty| ty.node.clone()), - schema_attr - .ty - .as_ref() - .map_or(pos.clone(), |ty| ty.get_pos()), - ); + let ty = self + .parse_ty_with_scope(Some(&schema_attr.ty), schema_attr.ty.get_span_pos()); let is_optional = schema_attr.is_optional; - let has_default = schema_attr.value.is_some(); - (name, ty, is_optional, has_default) + let default = schema_attr.value.as_ref().map(|v| { + if self.options.resolve_val { + print_ast_node(ASTNode::Expr(v)) + } else { + "".to_string() + } + }); + // Schema attribute decorators + let decorators = self.resolve_decorators( + &schema_attr.decorators, + DecoratorTarget::Attribute, + &name, + ); + ( + name, + ty, + is_optional, + default, + decorators, + stmt.get_span_pos(), + ) } _ => continue, }; @@ -594,13 +640,23 @@ impl<'ctx> Resolver<'ctx> { }; if !attr_obj_map.contains_key(&name) { let existed_attr = parent_ty.as_ref().and_then(|ty| ty.get_obj_of_attr(&name)); + let doc_str = parsed_doc.attrs.iter().find_map(|attr| { + if attr.name == name { + Some(attr.desc.join("\n")) + } else { + None + } + }); attr_obj_map.insert( name.clone(), SchemaAttr { is_optional: existed_attr.map_or(is_optional, |attr| attr.is_optional), - has_default, + has_default: default.is_some(), + default, ty: ty.clone(), - pos: pos.clone(), + range: range.clone(), + doc: doc_str, + decorators, }, ); } @@ -614,7 +670,7 @@ impl<'ctx> Resolver<'ctx> { attr_obj_map.get(&name).unwrap().ty.clone().ty_str(), ty.ty_str() ), - pos.clone(), + stmt.get_span_pos(), ); } if is_optional && !attr_obj_map.get(&name).unwrap().is_optional { @@ -623,7 +679,7 @@ impl<'ctx> Resolver<'ctx> { "can't change the required schema attribute of '{}' to optional", name ), - pos.clone(), + stmt.get_span_pos(), ); } if let Some(ref index_signature_obj) = index_signature { @@ -633,10 +689,11 @@ impl<'ctx> Resolver<'ctx> { self.handler.add_error( ErrorKind::IndexSignatureError, &[Message { - pos: pos.clone(), + range: stmt.get_span_pos(), style: Style::LineAndColumn, message: format!("the type '{}' of schema attribute '{}' does not meet the index signature definition {}", ty.ty_str(), name, index_signature_obj.ty_str()), note: None, + suggested_replacement: None, }], ); } @@ -645,22 +702,23 @@ impl<'ctx> Resolver<'ctx> { // Mixin types let mut mixin_types: Vec = vec![]; for mixin in &schema_stmt.mixins { - let mixin_names = &mixin.node.names; + let mixin_names = &mixin.node.get_names(); if !mixin_names[mixin_names.len() - 1].ends_with(MIXIN_SUFFIX) { self.handler.add_error( ErrorKind::NameError, &[Message { - pos: pos.clone(), + range: mixin.get_span_pos(), style: Style::LineAndColumn, message: format!( "a valid mixin name should end with 'Mixin', got '{}'", mixin_names[mixin_names.len() - 1] ), note: None, + suggested_replacement: None, }], ); } - let ty = self.walk_identifier(&mixin.node); + let ty = self.walk_identifier_expr(&mixin); let mixin_ty = match &ty.kind { TypeKind::Schema(schema_ty) if !schema_ty.is_protocol && schema_ty.is_mixin && !schema_ty.is_instance => @@ -671,10 +729,14 @@ impl<'ctx> Resolver<'ctx> { self.handler.add_error( ErrorKind::IllegalInheritError, &[Message { - pos: mixin.get_pos(), + range: mixin.get_span_pos(), style: Style::LineAndColumn, - message: format!("illegal schema mixin object type '{}'", ty.ty_str()), + message: format!( + "illegal schema mixin object type, expected mixin, got '{}'", + ty.ty_str() + ), note: None, + suggested_replacement: None, }], ); None @@ -695,37 +757,67 @@ impl<'ctx> Resolver<'ctx> { if let Some(args) = &schema_stmt.args { for (i, para) in args.node.args.iter().enumerate() { let name = para.node.get_name(); - let pos = para.get_pos(); if schema_attr_names.contains(&name) { self.handler.add_compile_error( &format!( "Unexpected parameter name '{}' with the same name as the schema attribute", name ), - pos.clone(), + para.get_span_pos(), ); } - let ty = args.node.get_arg_type(i); - let ty = self.parse_ty_with_scope(&ty, pos); + let ty = args.node.get_arg_type_node(i); + let ty = self.parse_ty_with_scope(ty, para.get_span_pos()); params.push(Parameter { name, ty: ty.clone(), - has_default: args.node.defaults.get(i).is_some(), + has_default: args.node.defaults.get(i).map_or(false, |arg| arg.is_some()), + default_value: args.node.defaults.get(i).map_or(None, |arg| { + arg.as_ref().map(|v| print_ast_node(ASTNode::Expr(&v))) + }), + range: args.node.args[i].get_span_pos(), }); } } - let schema_runtime_ty = kclvm::schema_runtime_type(name, &self.ctx.pkgpath); + + let schema_full_ty_str = full_ty_str(&self.ctx.pkgpath, name); + if should_add_schema_ref { - let idx1 = self - .ctx - .ty_ctx - .dep_graph - .add_node(schema_runtime_ty.clone()); if let Some(ref parent_ty) = parent_ty { - let parent_schema_runtime_ty = - kclvm::schema_runtime_type(&parent_ty.name, &parent_ty.pkgpath); - let idx2 = self.ctx.ty_ctx.dep_graph.add_node(parent_schema_runtime_ty); - self.ctx.ty_ctx.dep_graph.add_edge(idx1, idx2, ()); + let parent_full_ty_str = parent_ty.full_ty_str(); + self.ctx.ty_ctx.add_dependencies( + &schema_full_ty_str, + &parent_full_ty_str, + schema_stmt.name.get_span_pos(), + ); + + if self.ctx.ty_ctx.is_cyclic_from_node(&schema_full_ty_str) { + let cycles = self.ctx.ty_ctx.find_cycle_nodes(&schema_full_ty_str); + for cycle in cycles { + let node_names: Vec = cycle + .iter() + .map(|idx| { + if let Some(name) = self.ctx.ty_ctx.dep_graph.node_weight(*idx) { + name.clone() + } else { + "".to_string() + } + }) + .filter(|name| !name.is_empty()) + .collect(); + for node in &cycle { + if let Some(range) = self.ctx.ty_ctx.get_node_range(node) { + self.handler.add_compile_error( + &format!( + "There is a circular reference between schemas {}", + node_names.join(", "), + ), + range, + ); + } + } + } + } } } let decorators = self.resolve_decorators( @@ -737,7 +829,8 @@ impl<'ctx> Resolver<'ctx> { name: schema_stmt.name.node.clone(), pkgpath: self.ctx.pkgpath.clone(), filename: self.ctx.filename.clone(), - doc: schema_stmt.doc.clone(), + doc: parsed_doc.summary.clone(), + examples: parsed_doc.examples, is_instance: false, is_mixin: schema_stmt.is_mixin, is_protocol: schema_stmt.is_protocol, @@ -747,19 +840,20 @@ impl<'ctx> Resolver<'ctx> { mixins: mixin_types, attrs: attr_obj_map, func: Box::new(FunctionType { - doc: schema_stmt.doc.clone(), + doc: parsed_doc.summary.clone(), params, self_ty: None, - return_ty: Rc::new(Type::ANY), + return_ty: Arc::new(Type::ANY), is_variadic: false, kw_only_index: None, }), index_signature, decorators, }; + let schema_runtime_ty = kclvm_runtime::schema_runtime_type(name, &self.ctx.pkgpath); self.ctx .schema_mapping - .insert(schema_runtime_ty, Rc::new(RefCell::new(schema_ty.clone()))); + .insert(schema_runtime_ty, Arc::new(RefCell::new(schema_ty.clone()))); schema_ty } @@ -770,32 +864,32 @@ impl<'ctx> Resolver<'ctx> { should_add_schema_ref: bool, ) -> SchemaType { let name = &rule_stmt.name.node; - let pos = rule_stmt.name.get_end_pos(); if RESERVED_TYPE_IDENTIFIERS.contains(&name.as_str()) { self.handler.add_compile_error( &format!( "rule name '{}' cannot be the same as the built-in types ({:?})", name, RESERVED_TYPE_IDENTIFIERS ), - pos, + rule_stmt.name.get_span_pos(), ); } // Parent types let mut parent_types: Vec = vec![]; for rule in &rule_stmt.parent_rules { - let ty = self.walk_identifier(&rule.node); + let ty = self.walk_identifier_expr(&rule); let parent_ty = match &ty.kind { - TypeKind::Schema(schema_ty) if !schema_ty.is_rule && !schema_ty.is_instance => { + TypeKind::Schema(schema_ty) if schema_ty.is_rule && !schema_ty.is_instance => { Some(schema_ty.clone()) } _ => { self.handler.add_error( ErrorKind::IllegalInheritError, &[Message { - pos: rule.get_pos(), + range: rule.get_span_pos(), style: Style::LineAndColumn, - message: format!("illegal schema mixin object type '{}'", ty.ty_str()), + message: format!("illegal rule type '{}'", ty.ty_str()), note: None, + suggested_replacement: None, }], ); None @@ -810,24 +904,56 @@ impl<'ctx> Resolver<'ctx> { if let Some(args) = &rule_stmt.args { for (i, para) in args.node.args.iter().enumerate() { let name = para.node.get_name(); - let pos = para.get_pos(); - let ty = args.node.get_arg_type(i); - let ty = self.parse_ty_with_scope(&ty, pos); + let ty = args.node.get_arg_type_node(i); + let ty = self.parse_ty_with_scope(ty, para.get_span_pos()); params.push(Parameter { name, ty: ty.clone(), has_default: args.node.defaults.get(i).is_some(), + default_value: args.node.defaults.get(i).map_or(None, |arg| { + arg.as_ref().map(|v| print_ast_node(ASTNode::Expr(&v))) + }), + range: args.node.args[i].get_span_pos(), }); } } if should_add_schema_ref { - let schema_runtime_ty = kclvm::schema_runtime_type(name, &self.ctx.pkgpath); - let idx1 = self.ctx.ty_ctx.dep_graph.add_node(schema_runtime_ty); + let schema_full_ty_str = full_ty_str(&self.ctx.pkgpath, &name); + for parent_ty in &parent_types { - let parent_schema_runtime_ty = - kclvm::schema_runtime_type(&parent_ty.name, &parent_ty.pkgpath); - let idx2 = self.ctx.ty_ctx.dep_graph.add_node(parent_schema_runtime_ty); - self.ctx.ty_ctx.dep_graph.add_edge(idx1, idx2, ()); + let parent_full_ty_str = parent_ty.full_ty_str(); + self.ctx.ty_ctx.add_dependencies( + &schema_full_ty_str, + &parent_full_ty_str, + rule_stmt.name.get_span_pos(), + ); + if self.ctx.ty_ctx.is_cyclic_from_node(&schema_full_ty_str) { + let cycles = self.ctx.ty_ctx.find_cycle_nodes(&schema_full_ty_str); + for cycle in cycles { + let node_names: Vec = cycle + .iter() + .map(|idx| { + if let Some(name) = self.ctx.ty_ctx.dep_graph.node_weight(*idx) { + name.clone() + } else { + "".to_string() + } + }) + .filter(|name| !name.is_empty()) + .collect(); + for node in &cycle { + if let Some(range) = self.ctx.ty_ctx.get_node_range(node) { + self.handler.add_compile_error( + &format!( + "There is a circular reference between rules {}", + node_names.join(", "), + ), + range, + ); + } + } + } + } } } let decorators = self.resolve_decorators( @@ -835,11 +961,24 @@ impl<'ctx> Resolver<'ctx> { DecoratorTarget::Schema, &rule_stmt.name.node, ); + + let parsed_doc = parse_schema_doc_string( + &rule_stmt + .doc + .as_ref() + .map(|doc| doc.node.clone()) + .unwrap_or_default(), + ); + let index_signature = match &protocol_ty { + Some(ty) => ty.index_signature.clone(), + None => None, + }; SchemaType { name: rule_stmt.name.node.clone(), pkgpath: self.ctx.pkgpath.clone(), filename: self.ctx.filename.clone(), - doc: rule_stmt.doc.clone(), + doc: parsed_doc.summary.clone(), + examples: parsed_doc.examples, is_instance: false, is_mixin: false, is_protocol: false, @@ -849,14 +988,18 @@ impl<'ctx> Resolver<'ctx> { mixins: parent_types, attrs: IndexMap::default(), func: Box::new(FunctionType { - doc: rule_stmt.doc.clone(), + doc: rule_stmt + .doc + .as_ref() + .map(|doc| doc.node.clone()) + .unwrap_or_default(), params, self_ty: None, - return_ty: Rc::new(Type::ANY), + return_ty: Arc::new(Type::ANY), is_variadic: false, kw_only_index: None, }), - index_signature: None, + index_signature, decorators, } } diff --git a/kclvm/sema/src/resolver/import.rs b/kclvm/sema/src/resolver/import.rs index ca83dd70a..c2a9a6a25 100644 --- a/kclvm/sema/src/resolver/import.rs +++ b/kclvm/sema/src/resolver/import.rs @@ -1,27 +1,36 @@ use crate::plugin::PLUGIN_MODULE_PREFIX; +use crate::resolver::scope::Module; use crate::resolver::Resolver; use crate::ty::ModuleKind; use crate::{ builtin::system_module::STANDARD_SYSTEM_MODULES, ty::{Type, TypeKind}, }; -use indexmap::IndexMap; +use indexmap::{IndexMap, IndexSet}; use kclvm_ast::ast; use kclvm_error::*; -use std::{cell::RefCell, path::Path, rc::Rc}; +use std::rc::Rc; +use std::sync::Arc; +use std::{cell::RefCell, path::Path}; use super::scope::{Scope, ScopeKind, ScopeObject, ScopeObjectKind}; -use crate::resolver::pos::GetPos; +use kclvm_ast::pos::GetPos; +use kclvm_utils::pkgpath::parse_external_pkg_name; impl<'ctx> Resolver<'ctx> { /// Check import error pub fn resolve_import(&mut self) { let main_files = self.program.get_main_files(); for modules in self.program.pkgs.values() { - for m in modules { - for stmt in &m.body { + for module in modules { + let module = self + .program + .get_module(module) + .expect("Failed to acquire module lock") + .expect(&format!("module {:?} not found in program", module)); + for stmt in &module.body { if let ast::Stmt::Import(import_stmt) = &stmt.node { - let pkgpath = &import_stmt.path; + let pkgpath = &import_stmt.path.node; // System module. if STANDARD_SYSTEM_MODULES.contains(&pkgpath.as_str()) { continue; @@ -33,40 +42,66 @@ impl<'ctx> Resolver<'ctx> { let real_path = Path::new(&self.program.root).join(pkgpath.replace('.', "/")); if !self.program.pkgs.contains_key(pkgpath) { - self.handler.add_error( - ErrorKind::CannotFindModule, - &[Message { - pos: Position { - filename: m.filename.clone(), - line: stmt.line, - column: Some(1), - }, - style: Style::Line, - message: format!( - "Cannot find the module {} from {}", - import_stmt.rawpath, - real_path.to_str().unwrap() - ), - note: None, - }], - ); + self.ctx.invalid_pkg_scope.insert(pkgpath.to_string()); + if real_path.exists() { + self.handler.add_error( + ErrorKind::CannotFindModule, + &[Message { + range: stmt.get_span_pos(), + style: Style::Line, + message: format!( + "Failed to import the module {} from {}. No KCL files found in the specified folder", + import_stmt.rawpath, + real_path.to_str().unwrap(), + ), + note: None, + suggested_replacement: None, + }], + ); + } else { + self.handler.add_error( + ErrorKind::CannotFindModule, + &[Message { + range: stmt.get_span_pos(), + style: Style::Line, + message: format!( + "Cannot find the module {} from {}", + import_stmt.rawpath, + real_path.to_str().unwrap() + ), + note: None, + suggested_replacement: None, + }], + ); + let mut suggestions = vec![format!( + "browse more packages at 'https://artifacthub.io'" + )]; + + if let Ok(pkg_name) = parse_external_pkg_name(pkgpath) { + suggestions.insert( + 0, + format!( + "try 'kcl mod add {}' to download the missing package", + pkg_name + ), + ); + } + self.handler.add_suggestions(suggestions); + } } else { let file = real_path.to_str().unwrap().to_string(); if real_path.is_file() && main_files.contains(&file) { self.handler.add_error( ErrorKind::CompileError, &[Message { - pos: Position { - filename: self.ctx.filename.clone(), - line: stmt.line, - column: Some(1), - }, + range: stmt.get_span_pos(), style: Style::Line, message: format!( "Cannot import {} in the main package", file ), note: None, + suggested_replacement: None, }], ); } @@ -90,41 +125,74 @@ impl<'ctx> Resolver<'ctx> { let modules = self.program.pkgs.get(&self.ctx.pkgpath); match modules { Some(modules) => { + let mut import_table: IndexMap = IndexMap::default(); for module in modules { + let module = self + .program + .get_module(module) + .expect("Failed to acquire module lock") + .expect(&format!("module {:?} not found in program", module)); self.ctx.filename = module.filename.clone(); - self.ctx.pkgpath = module.pkg.clone(); for stmt in &module.body { if let ast::Stmt::Import(import_stmt) = &stmt.node { - { - match self.ctx.import_names.get_mut(&self.ctx.filename) { - Some(mapping) => { - mapping.insert( - import_stmt.name.to_string(), - import_stmt.path.to_string(), - ); - } - None => { - let mut mapping = IndexMap::default(); - mapping.insert( - import_stmt.name.to_string(), - import_stmt.path.to_string(), - ); - self.ctx - .import_names - .insert(self.ctx.filename.clone(), mapping); - } + // 'import sub as s' and 'import sub.sub as s' will raise this error. + // 'import sub' and 'import sub' will not raise this error. + // 'import sub as s' and 'import sub as s' will not raise this error. + if let Some(path) = import_table.get(&import_stmt.name) { + if path != &import_stmt.path.node { + self.handler.add_compile_error( + &format!( + "the name '{}' is defined multiple times, '{}' must be defined only once", + import_stmt.name, import_stmt.name + ), + stmt.get_span_pos(), + ); + } + } else { + import_table.insert( + import_stmt.name.clone(), + import_stmt.path.node.clone(), + ); + } + match self.ctx.import_names.get_mut(&self.ctx.filename) { + Some(mapping) => { + mapping.insert( + import_stmt.name.to_string(), + import_stmt.path.node.to_string(), + ); + } + None => { + let mut mapping = IndexMap::default(); + mapping.insert( + import_stmt.name.to_string(), + import_stmt.path.node.to_string(), + ); + self.ctx + .import_names + .insert(self.ctx.filename.clone(), mapping); } + } + { let mut scope = self.scope.borrow_mut(); - let is_user_module = match scope.elems.get(&import_stmt.path) { + let is_user_module = match scope.elems.get(&import_stmt.name) { Some(scope_obj) => { let mut obj = scope_obj.borrow_mut(); + match &mut obj.kind { + ScopeObjectKind::Module(m) => { + m.import_stmts.push((stmt.clone(), false)) + }, + _ => bug!( + "invalid module type in the import check function {}", + scope_obj.borrow().ty.ty_str() + ) + } match &obj.ty.kind { TypeKind::Module(module_ty) => { let mut module_ty = module_ty.clone(); module_ty .imported .push(self.ctx.filename.to_string()); - obj.ty = Rc::new(Type::module( + obj.ty = Arc::new(Type::module( &module_ty.pkgpath, &module_ty.imported, module_ty.kind.clone(), @@ -138,32 +206,40 @@ impl<'ctx> Resolver<'ctx> { } } None => { - let kind = - if import_stmt.path.starts_with(PLUGIN_MODULE_PREFIX) { - ModuleKind::Plugin - } else if STANDARD_SYSTEM_MODULES - .contains(&import_stmt.path.as_str()) - { - ModuleKind::System - } else { - ModuleKind::User - }; + let kind = if import_stmt + .path + .node + .starts_with(PLUGIN_MODULE_PREFIX) + { + ModuleKind::Plugin + } else if STANDARD_SYSTEM_MODULES + .contains(&import_stmt.path.node.as_str()) + { + ModuleKind::System + } else { + ModuleKind::User + }; let ty = Type::module( - &import_stmt.path, + &import_stmt.path.node, &[self.ctx.filename.clone()], kind.clone(), ); let (start, end) = stmt.get_span_pos(); + scope.elems.insert( - import_stmt.path.to_string(), + import_stmt.name.clone(), Rc::new(RefCell::new(ScopeObject { - name: import_stmt.path.to_string(), + name: import_stmt.name.clone(), start, end, - ty: Rc::new(ty), - kind: ScopeObjectKind::Module, + ty: Arc::new(ty), + kind: ScopeObjectKind::Module(Module { + import_stmts: vec![(stmt.clone(), false)], + }), + doc: None, })), ); + matches!(kind, ModuleKind::User) } }; @@ -173,12 +249,43 @@ impl<'ctx> Resolver<'ctx> { } let current_pkgpath = self.ctx.pkgpath.clone(); let current_filename = self.ctx.filename.clone(); - let idx1 = self.ctx.ty_ctx.dep_graph.add_node(self.ctx.pkgpath.clone()); - let idx2 = self.ctx.ty_ctx.dep_graph.add_node(import_stmt.path.clone()); - self.ctx.ty_ctx.dep_graph.add_edge(idx1, idx2, ()); + self.ctx.ty_ctx.add_dependencies( + &self.ctx.pkgpath, + &import_stmt.path.node, + stmt.get_span_pos(), + ); + if self.ctx.ty_ctx.is_cyclic_from_node(&self.ctx.pkgpath) { + let cycles = self.ctx.ty_ctx.find_cycle_nodes(&self.ctx.pkgpath); + for cycle in cycles { + let node_names: Vec = cycle + .iter() + .map(|idx| { + if let Some(name) = + self.ctx.ty_ctx.dep_graph.node_weight(*idx) + { + name.clone() + } else { + "".to_string() + } + }) + .filter(|name| !name.is_empty()) + .collect(); + for node in &cycle { + if let Some(range) = self.ctx.ty_ctx.get_node_range(node) { + self.handler.add_compile_error( + &format!( + "There is a circular reference between modules {}", + node_names.join(", "), + ), + range + ); + } + } + } + } // Switch pkgpath context - if !self.scope_map.contains_key(&import_stmt.path) { - self.check(&import_stmt.path); + if !self.scope_map.contains_key(&import_stmt.path.node) { + self.check(&import_stmt.path.node); } // Restore the current context self.change_package_context(¤t_pkgpath, ¤t_filename); @@ -194,6 +301,7 @@ impl<'ctx> Resolver<'ctx> { if pkgpath.is_empty() { return; } + if !self.scope_map.contains_key(pkgpath) { let scope = Rc::new(RefCell::new(Scope { parent: Some(Rc::downgrade(&self.builtin_scope)), @@ -201,7 +309,7 @@ impl<'ctx> Resolver<'ctx> { elems: IndexMap::default(), start: Position::dummy_pos(), end: Position::dummy_pos(), - kind: ScopeKind::Package, + kind: ScopeKind::Package(IndexSet::new()), })); self.scope_map .insert(pkgpath.to_string(), Rc::clone(&scope)); @@ -209,6 +317,7 @@ impl<'ctx> Resolver<'ctx> { } self.ctx.pkgpath = pkgpath.to_string(); self.ctx.filename = filename.to_string(); - self.scope = self.scope_map.get(pkgpath).unwrap().clone(); + let scope = self.scope_map.get(pkgpath).unwrap().clone(); + self.scope = scope; } } diff --git a/kclvm/sema/src/resolver/loop.rs b/kclvm/sema/src/resolver/loop.rs index b4a17b5cc..51cca4e8d 100644 --- a/kclvm/sema/src/resolver/loop.rs +++ b/kclvm/sema/src/resolver/loop.rs @@ -1,21 +1,16 @@ -use std::rc::Rc; - use crate::resolver::Resolver; -use crate::ty::{sup, Type, TypeKind}; +use crate::ty::{sup, DictType, TypeKind, TypeRef}; use kclvm_ast::ast; -use kclvm_error::Position; - -use crate::resolver::pos::GetPos; +use kclvm_error::diagnostic::Range; impl<'ctx> Resolver<'ctx> { /// Do loop type check including quant and comp for expression. pub(crate) fn do_loop_type_check( &mut self, - target_node: &'ctx ast::NodeRef, - first_var_name: Option, - second_var_name: Option, - iter_ty: Rc, - iter_pos: Position, + first_var_name: Option<&ast::Node>, + second_var_name: Option<&ast::Node>, + iter_ty: TypeRef, + iter_range: Range, ) { let types = match &iter_ty.kind { TypeKind::Union(types) => types.clone(), @@ -27,7 +22,7 @@ impl<'ctx> Resolver<'ctx> { if !(iter_ty.is_iterable() || iter_ty.is_any()) { self.handler.add_compile_error( &format!("'{}' object is not iterable", iter_ty.ty_str()), - iter_pos.clone(), + iter_range.clone(), ); } match &iter_ty.kind { @@ -35,55 +30,55 @@ impl<'ctx> Resolver<'ctx> { if second_var_name.is_some() { first_var_ty = sup(&[self.int_ty(), first_var_ty.clone()]); second_var_ty = sup(&[item_ty.clone(), second_var_ty.clone()]); - self.set_type_to_scope( - first_var_name.as_ref().unwrap(), + self.set_infer_type_to_scope( + &first_var_name.unwrap().node, first_var_ty.clone(), - target_node.get_pos(), + &first_var_name.unwrap(), ); - self.set_type_to_scope( - second_var_name.as_ref().unwrap(), + self.set_infer_type_to_scope( + &second_var_name.unwrap().node, second_var_ty.clone(), - target_node.get_pos(), + &second_var_name.unwrap(), ); } else { first_var_ty = sup(&[item_ty.clone(), first_var_ty.clone()]); - self.set_type_to_scope( - first_var_name.as_ref().unwrap(), + self.set_infer_type_to_scope( + &first_var_name.unwrap().node, first_var_ty.clone(), - target_node.get_pos(), + &first_var_name.unwrap(), ); } } - TypeKind::Dict(key_ty, val_ty) => { + TypeKind::Dict(DictType { key_ty, val_ty, .. }) => { first_var_ty = sup(&[key_ty.clone(), first_var_ty.clone()]); - self.set_type_to_scope( - first_var_name.as_ref().unwrap(), + self.set_infer_type_to_scope( + &first_var_name.unwrap().node, first_var_ty.clone(), - target_node.get_pos(), + &first_var_name.unwrap(), ); if second_var_name.is_some() { second_var_ty = sup(&[val_ty.clone(), second_var_ty.clone()]); - self.set_type_to_scope( - second_var_name.as_ref().unwrap(), + self.set_infer_type_to_scope( + &second_var_name.unwrap().node, second_var_ty.clone(), - target_node.get_pos(), + &second_var_name.unwrap(), ); } } TypeKind::Schema(schema_ty) => { let (key_ty, val_ty) = (schema_ty.key_ty(), schema_ty.val_ty()); first_var_ty = sup(&[key_ty, first_var_ty.clone()]); - self.set_type_to_scope( - first_var_name.as_ref().unwrap(), + self.set_infer_type_to_scope( + &first_var_name.unwrap().node, first_var_ty.clone(), - target_node.get_pos(), + &first_var_name.unwrap(), ); if second_var_name.is_some() { second_var_ty = sup(&[val_ty, second_var_ty.clone()]); - self.set_type_to_scope( - second_var_name.as_ref().unwrap(), + self.set_infer_type_to_scope( + &second_var_name.unwrap().node, second_var_ty.clone(), - target_node.get_pos(), + &second_var_name.unwrap(), ); } } @@ -91,22 +86,22 @@ impl<'ctx> Resolver<'ctx> { if second_var_name.is_some() { first_var_ty = sup(&[self.int_ty(), first_var_ty.clone()]); second_var_ty = sup(&[self.str_ty(), second_var_ty.clone()]); - self.set_type_to_scope( - first_var_name.as_ref().unwrap(), + self.set_infer_type_to_scope( + &first_var_name.unwrap().node, first_var_ty.clone(), - target_node.get_pos(), + &first_var_name.unwrap(), ); - self.set_type_to_scope( - second_var_name.as_ref().unwrap(), + self.set_infer_type_to_scope( + &second_var_name.unwrap().node, second_var_ty.clone(), - target_node.get_pos(), + &second_var_name.unwrap(), ); } else { first_var_ty = sup(&[self.str_ty(), first_var_ty.clone()]); - self.set_type_to_scope( - first_var_name.as_ref().unwrap(), + self.set_infer_type_to_scope( + &first_var_name.unwrap().node, first_var_ty.clone(), - target_node.get_pos(), + &first_var_name.unwrap(), ); } } diff --git a/kclvm/sema/src/resolver/mod.rs b/kclvm/sema/src/resolver/mod.rs index baae874b9..3987f821a 100644 --- a/kclvm/sema/src/resolver/mod.rs +++ b/kclvm/sema/src/resolver/mod.rs @@ -2,36 +2,39 @@ mod arg; mod attr; mod calculation; mod config; +pub mod doc; mod format; pub mod global; mod import; mod r#loop; mod node; mod para; -pub mod pos; mod schema; pub mod scope; -mod ty; +pub(crate) mod ty; mod ty_alias; +mod ty_erasure; mod var; #[cfg(test)] mod tests; -use indexmap::IndexMap; +use indexmap::{IndexMap, IndexSet}; +use kclvm_error::diagnostic::Range; +use std::sync::Arc; use std::{cell::RefCell, rc::Rc}; +use crate::lint::{CombinedLintPass, Linter}; use crate::pre_process::pre_process_program; use crate::resolver::scope::ScopeObject; -use crate::resolver::ty_alias::process_program_type_alias; +use crate::resolver::ty_alias::type_alias_pass; +use crate::resolver::ty_erasure::type_func_erasure_pass; +use crate::ty::TypeContext; use crate::{resolver::scope::Scope, ty::SchemaType}; use kclvm_ast::ast::Program; -use kclvm_ast::walker::MutSelfTypedResultWalker; use kclvm_error::*; -use crate::ty::TypeContext; - -use self::scope::{builtin_scope, ProgramScope}; +use self::scope::{builtin_scope, KCLScopeCache, NodeTyMap, ProgramScope}; /// Resolver is responsible for program semantic checking, mainly /// including type checking and contract model checking. @@ -39,10 +42,13 @@ pub struct Resolver<'ctx> { pub program: &'ctx Program, pub scope_map: IndexMap>>, pub scope: Rc>, + pub scope_level: usize, + pub node_ty_map: Rc>, pub builtin_scope: Rc>, pub ctx: Context, pub options: Options, pub handler: Handler, + pub linter: Linter, } impl<'ctx> Resolver<'ctx> { @@ -54,32 +60,74 @@ impl<'ctx> Resolver<'ctx> { scope_map: IndexMap::default(), builtin_scope, scope, + scope_level: 0, + node_ty_map: Rc::new(RefCell::new(IndexMap::default())), ctx: Context::default(), options, handler: Handler::default(), + linter: Linter::::new(), } } /// The check main function. - pub(crate) fn check(&mut self, pkgpath: &str) -> ProgramScope { + pub(crate) fn check(&mut self, pkgpath: &str) { self.check_import(pkgpath); self.init_global_types(); - match self.program.pkgs.get(pkgpath) { + match self + .program + .pkgs + .get(pkgpath) + .or(self.program.pkgs_not_imported.get(pkgpath)) + { Some(modules) => { for module in modules { + let module = self + .program + .get_module(module) + .expect("Failed to acquire module lock") + .expect(&format!("module {:?} not found in program", module)); self.ctx.filename = module.filename.to_string(); + if let scope::ScopeKind::Package(files) = &mut self.scope.borrow_mut().kind { + files.insert(module.filename.to_string()); + } for stmt in &module.body { - self.walk_stmt(&stmt.node); + self.stmt(&stmt); + } + if self.options.lint_check { + self.lint_check_module(&module); } } } None => {} } - ProgramScope { - scope_map: self.scope_map.clone(), - import_names: self.ctx.import_names.clone(), - diagnostics: self.handler.diagnostics.clone(), + } + + pub(crate) fn check_and_lint_all_pkgs(&mut self) -> ProgramScope { + self.check(kclvm_ast::MAIN_PKG); + self.lint_check_scope_map(); + let mut handler = self.handler.clone(); + for diag in &self.linter.handler.diagnostics { + handler.diagnostics.insert(diag.clone()); + } + + for pkg in self.program.pkgs_not_imported.keys() { + if !self.scope_map.contains_key(pkg) { + self.check(pkg); + } } + + let mut scope_map = self.scope_map.clone(); + for invalid_pkg_scope in &self.ctx.invalid_pkg_scope { + scope_map.remove(invalid_pkg_scope); + } + let scope = ProgramScope { + scope_map, + import_names: self.ctx.import_names.clone(), + node_ty_map: self.node_ty_map.clone(), + handler, + schema_mapping: self.ctx.schema_mapping.clone(), + }; + scope } } @@ -92,12 +140,14 @@ pub struct Context { pub pkgpath: String, /// What schema are we in. pub schema: Option>>, - /// What schema are we in. - pub schema_mapping: IndexMap>>, + /// Global schemas name and type mapping. + pub schema_mapping: IndexMap>>, /// For loop local vars. pub local_vars: Vec, /// Import pkgpath and name pub import_names: IndexMap>, + /// Global names at top level of the program. + pub global_names: IndexMap>, /// Are we resolving the left value. pub l_value: bool, /// Are we resolving the statement start position. @@ -112,29 +162,83 @@ pub struct Context { pub ty_ctx: TypeContext, /// Type alias mapping pub type_alias_mapping: IndexMap>, + /// invalid pkg scope, remove when after resolve + pub invalid_pkg_scope: IndexSet, } -/// Resolve options -#[derive(Clone, Debug, Default)] +/// Resolve options. +/// - lint_check: whether to run lint passes +/// - resolve_val: whether to resolve and print their AST to value for some nodes. +#[derive(Clone, Debug)] pub struct Options { - pub raise_err: bool, - pub config_auto_fix: bool, + pub lint_check: bool, + pub resolve_val: bool, + pub merge_program: bool, + pub type_erasure: bool, } -/// Resolve program +impl Default for Options { + fn default() -> Self { + Self { + lint_check: true, + resolve_val: false, + merge_program: true, + type_erasure: true, + } + } +} + +/// Resolve program with default options. +#[inline] pub fn resolve_program(program: &mut Program) -> ProgramScope { - pre_process_program(program); - let mut resolver = Resolver::new( - program, - Options { - raise_err: true, - config_auto_fix: false, - }, - ); + resolve_program_with_opts(program, Options::default(), None) +} + +/// Resolve program with options. See [Options] +pub fn resolve_program_with_opts( + program: &mut Program, + opts: Options, + cached_scope: Option, +) -> ProgramScope { + pre_process_program(program, &opts); + let mut resolver = Resolver::new(program, opts.clone()); resolver.resolve_import(); - let scope = resolver.check(kclvm_ast::MAIN_PKG); - let type_alias_mapping = resolver.ctx.type_alias_mapping.clone(); - process_program_type_alias(program, type_alias_mapping); - scope.check_scope_diagnostics(); + if let Some(cached_scope) = cached_scope.as_ref() { + if let Some(mut cached_scope) = cached_scope.try_write() { + cached_scope.invalidate_pkgs.clear(); + cached_scope.update(program); + resolver.scope_map = cached_scope.scope_map.clone(); + resolver.node_ty_map = Rc::new(RefCell::new(cached_scope.node_ty_map.clone())); + resolver.ctx.schema_mapping = cached_scope.schema_mapping.clone(); + cached_scope + .invalidate_pkgs + .insert(kclvm_ast::MAIN_PKG.to_string()); + for pkg in &cached_scope.invalidate_pkgs { + resolver.scope_map.remove(pkg); + } + } + } + let scope = resolver.check_and_lint_all_pkgs(); + + if let Some(cached_scope) = cached_scope.as_ref() { + if let Some(mut cached_scope) = cached_scope.try_write() { + cached_scope.update(program); + cached_scope.scope_map = scope.scope_map.clone(); + cached_scope.node_ty_map = scope.node_ty_map.borrow().clone(); + cached_scope.scope_map.remove(kclvm_ast::MAIN_PKG); + cached_scope.schema_mapping = resolver.ctx.schema_mapping; + cached_scope + .invalidate_pkgs + .insert(kclvm_ast::MAIN_PKG.to_string()); + cached_scope.invalidate_pkg_modules = None; + } + } + if opts.type_erasure { + let type_alias_mapping = resolver.ctx.type_alias_mapping.clone(); + // Erase all the function type to a named type "function" + type_func_erasure_pass(program); + // Erase types with their type alias + type_alias_pass(program, type_alias_mapping); + } scope } diff --git a/kclvm/sema/src/resolver/node.rs b/kclvm/sema/src/resolver/node.rs index e8539b6b8..6817f4075 100644 --- a/kclvm/sema/src/resolver/node.rs +++ b/kclvm/sema/src/resolver/node.rs @@ -1,26 +1,27 @@ -use std::rc::Rc; - -use crate::resolver::pos::GetPos; use indexmap::IndexMap; use kclvm_ast::ast; +use kclvm_ast::pos::GetPos; use kclvm_ast::walker::MutSelfTypedResultWalker; +use kclvm_ast_pretty::{print_ast_node, ASTNode}; use kclvm_error::*; +use std::sync::Arc; +use crate::info::is_private_field; use crate::ty::{ - sup, DecoratorTarget, Parameter, Type, TypeInferMethods, TypeKind, RESERVED_TYPE_IDENTIFIERS, + sup, DictType, FunctionType, Parameter, Type, TypeInferMethods, TypeKind, TypeRef, + RESERVED_TYPE_IDENTIFIERS, }; +use super::doc::extract_doc_from_body; use super::format::VALID_FORMAT_SPEC_SET; use super::scope::{ScopeKind, ScopeObject, ScopeObjectKind}; use super::ty::ty_str_replace_pkgpath; use super::Resolver; - -pub type TypeRef = Rc; /// ResolvedResult denotes the result, when the result is error, /// put the message string into the diagnostic vector. pub type ResolvedResult = TypeRef; -impl<'ctx> MutSelfTypedResultWalker<'ctx> for Resolver<'ctx> { +impl<'ctx> MutSelfTypedResultWalker<'ctx> for Resolver<'_> { type Result = ResolvedResult; fn walk_module(&mut self, module: &'ctx ast::Module) -> Self::Result { @@ -29,12 +30,12 @@ impl<'ctx> MutSelfTypedResultWalker<'ctx> for Resolver<'ctx> { fn walk_expr_stmt(&mut self, expr_stmt: &'ctx ast::ExprStmt) -> Self::Result { let expr_types = self.exprs(&expr_stmt.exprs); - if !expr_types.is_empty() { - let ty = expr_types[expr_types.len() - 1].clone(); + if let Some(last) = expr_types.last() { + let ty = last.clone(); if expr_types.len() > 1 { self.handler.add_compile_error( "expression statement can only have one expression", - expr_stmt.exprs[1].get_pos(), + expr_stmt.exprs[1].get_span_pos(), ); } ty @@ -51,25 +52,33 @@ impl<'ctx> MutSelfTypedResultWalker<'ctx> for Resolver<'ctx> { if names.len() > 1 { self.handler.add_compile_error( "unification identifier can not be selected", - unification_stmt.target.get_pos(), + unification_stmt.target.get_span_pos(), ); } + let (start, end) = unification_stmt.value.get_span_pos(); + if names.is_empty() { + self.handler.add_compile_error( + "missing target in the unification statement", + unification_stmt.value.get_span_pos(), + ); + return self.any_ty(); + } self.ctx.l_value = true; let expected_ty = self.walk_identifier_expr(&unification_stmt.target); self.ctx.l_value = false; - let (start, end) = unification_stmt.value.get_span_pos(); - let obj = self.new_config_expr_context_item(&names[0], expected_ty.clone(), start, end); + let obj = + self.new_config_expr_context_item(&names[0].node, expected_ty.clone(), start, end); let init_stack_depth = self.switch_config_expr_context(Some(obj)); let ty = self.walk_schema_expr(&unification_stmt.value.node); self.clear_config_expr_context(init_stack_depth as usize, false); self.must_assignable_to( ty.clone(), expected_ty.clone(), - unification_stmt.target.get_pos(), + unification_stmt.target.get_span_pos(), None, ); if !ty.is_any() && expected_ty.is_any() { - self.set_type_to_scope(&names[0], ty, unification_stmt.target.get_pos()); + self.set_infer_type_to_scope(&names[0].node, ty, &names[0]); } expected_ty } @@ -77,14 +86,14 @@ impl<'ctx> MutSelfTypedResultWalker<'ctx> for Resolver<'ctx> { fn walk_type_alias_stmt(&mut self, type_alias_stmt: &'ctx ast::TypeAliasStmt) -> Self::Result { let (start, end) = type_alias_stmt.type_name.get_span_pos(); let mut ty = self - .parse_ty_str_with_scope(&type_alias_stmt.type_value.node, start.clone()) + .parse_ty_with_scope(Some(&type_alias_stmt.ty), (start.clone(), end.clone())) .as_ref() .clone(); if let TypeKind::Schema(schema_ty) = &mut ty.kind { schema_ty.is_instance = false; } ty.is_type_alias = true; - let ty = Rc::new(ty); + let ty = Arc::new(ty); let ty_str = ty.into_type_annotation_str(); let name = type_alias_stmt.type_name.node.get_name(); let mut mapping = IndexMap::default(); @@ -97,7 +106,7 @@ impl<'ctx> MutSelfTypedResultWalker<'ctx> for Resolver<'ctx> { "type alias '{}' cannot be the same as the built-in types ({:?})", name, RESERVED_TYPE_IDENTIFIERS ), - start.clone(), + type_alias_stmt.type_name.get_span_pos(), ); } self.insert_object( @@ -108,46 +117,86 @@ impl<'ctx> MutSelfTypedResultWalker<'ctx> for Resolver<'ctx> { end, ty: ty.clone(), kind: ScopeObjectKind::TypeAlias, + doc: None, }, ); + self.node_ty_map.borrow_mut().insert( + self.get_node_key(type_alias_stmt.type_name.id.clone()), + ty.clone(), + ); ty } fn walk_assign_stmt(&mut self, assign_stmt: &'ctx ast::AssignStmt) -> Self::Result { self.ctx.local_vars.clear(); let mut value_ty = self.any_ty(); - let start = assign_stmt.targets[0].get_pos(); - let end = assign_stmt.value.get_pos(); + let start = if assign_stmt.targets.is_empty() { + assign_stmt.value.get_pos() + } else { + assign_stmt.targets[0].get_pos() + }; + let end = assign_stmt.value.get_end_pos(); + let is_config = matches!(assign_stmt.value.node, ast::Expr::Schema(_)); for target in &assign_stmt.targets { - let name = &target.node.names[0]; - if target.node.names.len() == 1 { + let name = &target.node.name.node; + // Add global names. + if (is_private_field(name) || is_config || !self.contains_global_name(name)) + && self.scope_level == 0 + { + self.insert_global_name(name, &target.get_span_pos()); + } + if target.node.paths.is_empty() { self.ctx.l_value = true; - let expected_ty = self.walk_identifier_expr(target); + let expected_ty = self.walk_target_expr(target); self.ctx.l_value = false; - if let TypeKind::Schema(ty) = &expected_ty.kind { - let obj = self.new_config_expr_context_item( - &ty.name, - expected_ty.clone(), - start.clone(), - end.clone(), - ); - let init_stack_depth = self.switch_config_expr_context(Some(obj)); - value_ty = self.expr(&assign_stmt.value); - self.clear_config_expr_context(init_stack_depth as usize, false) - } else { - value_ty = self.expr(&assign_stmt.value); - self.must_assignable_to( - value_ty.clone(), - expected_ty.clone(), - target.get_pos(), - None, - ) + match &expected_ty.kind { + TypeKind::Schema(ty) => { + let obj = self.new_config_expr_context_item( + &ty.name, + expected_ty.clone(), + start.clone(), + end.clone(), + ); + let init_stack_depth = self.switch_config_expr_context(Some(obj)); + value_ty = self.expr(&assign_stmt.value); + self.clear_config_expr_context(init_stack_depth as usize, false) + } + TypeKind::List(_) | TypeKind::Dict(_) | TypeKind::Union(_) => { + let obj = self.new_config_expr_context_item( + "[]", + expected_ty.clone(), + start.clone(), + end.clone(), + ); + let init_stack_depth = self.switch_config_expr_context(Some(obj)); + value_ty = self.expr(&assign_stmt.value); + self.check_assignment_type_annotation(assign_stmt, value_ty.clone()); + self.clear_config_expr_context(init_stack_depth as usize, false) + } + _ => { + value_ty = self.expr(&assign_stmt.value); + // Check type annotation if exists. + self.check_assignment_type_annotation(assign_stmt, value_ty.clone()); + } } - if !value_ty.is_any() - && expected_ty.is_any() - && assign_stmt.type_annotation.is_none() - { - self.set_type_to_scope(name, value_ty.clone(), target.get_pos()); + self.must_assignable_to( + value_ty.clone(), + expected_ty.clone(), + target.get_span_pos(), + None, + ); + let upgrade_schema_type = + self.upgrade_dict_to_schema(value_ty.clone(), expected_ty.clone()); + self.node_ty_map.borrow_mut().insert( + self.get_node_key(assign_stmt.value.id.clone()), + upgrade_schema_type.clone(), + ); + + if !value_ty.is_any() && expected_ty.is_any() && assign_stmt.ty.is_none() { + // When the type is inferred and paths of target are empty, set the type to + // the whole AST node `target` and the first name of node `target.node.name` + self.set_infer_type_to_scope(name, value_ty.clone(), &target); + self.set_infer_type_to_scope(name, value_ty.clone(), &target.node.name); if let Some(schema_ty) = &self.ctx.schema { let mut schema_ty = schema_ty.borrow_mut(); schema_ty.set_type_of_attr( @@ -157,12 +206,25 @@ impl<'ctx> MutSelfTypedResultWalker<'ctx> for Resolver<'ctx> { } } } else { - self.lookup_type_from_scope(name, target.get_pos()); + self.lookup_type_from_scope(name, target.get_span_pos()); self.ctx.l_value = true; - let expected_ty = self.walk_identifier_expr(target); + let expected_ty = self.walk_target_expr(target); self.ctx.l_value = false; value_ty = self.expr(&assign_stmt.value); - self.must_assignable_to(value_ty.clone(), expected_ty, target.get_pos(), None) + // Check type annotation if exists. + self.check_assignment_type_annotation(assign_stmt, value_ty.clone()); + self.must_assignable_to( + value_ty.clone(), + expected_ty.clone(), + target.get_span_pos(), + None, + ); + let upgrade_schema_type = + self.upgrade_dict_to_schema(value_ty.clone(), expected_ty.clone()); + self.node_ty_map.borrow_mut().insert( + self.get_node_key(assign_stmt.value.id.clone()), + upgrade_schema_type.clone(), + ); } } value_ty @@ -170,19 +232,54 @@ impl<'ctx> MutSelfTypedResultWalker<'ctx> for Resolver<'ctx> { fn walk_aug_assign_stmt(&mut self, aug_assign_stmt: &'ctx ast::AugAssignStmt) -> Self::Result { self.ctx.l_value = false; - let left_ty = self.walk_identifier_expr(&aug_assign_stmt.target); + let is_config = matches!(aug_assign_stmt.value.node, ast::Expr::Schema(_)); + let name = &aug_assign_stmt.target.node.name.node; + // Add global names. + if is_private_field(name) || is_config || !self.contains_global_name(name) { + if self.scope_level == 0 { + self.insert_global_name(name, &aug_assign_stmt.target.get_span_pos()); + } + } else { + let mut msgs = vec![Message { + range: aug_assign_stmt.target.get_span_pos(), + style: Style::LineAndColumn, + message: format!("Immutable variable '{}' is modified during compiling", name), + note: None, + suggested_replacement: None, + }]; + if let Some(pos) = self.get_global_name_pos(name) { + msgs.push(Message { + range: pos.clone(), + style: Style::LineAndColumn, + message: format!("The variable '{}' is declared here firstly", name), + note: Some(format!( + "change the variable name to '_{}' to make it mutable", + name + )), + suggested_replacement: None, + }) + } + self.handler.add_error(ErrorKind::ImmutableError, &msgs); + } + + let left_ty = self.walk_target_expr(&aug_assign_stmt.target); let right_ty = self.expr(&aug_assign_stmt.value); let op = match aug_assign_stmt.op.clone().try_into() { Ok(op) => op, Err(msg) => bug!("{}", msg), }; - let new_target_ty = self.binary(left_ty, right_ty, &op, aug_assign_stmt.target.get_pos()); + let new_target_ty = self.binary( + left_ty, + right_ty, + &op, + aug_assign_stmt.target.get_span_pos(), + ); self.ctx.l_value = true; - let expected_ty = self.walk_identifier_expr(&aug_assign_stmt.target); + let expected_ty = self.walk_target_expr(&aug_assign_stmt.target); self.must_assignable_to( new_target_ty.clone(), expected_ty, - aug_assign_stmt.target.get_pos(), + aug_assign_stmt.target.get_span_pos(), None, ); self.ctx.l_value = false; @@ -200,9 +297,9 @@ impl<'ctx> MutSelfTypedResultWalker<'ctx> for Resolver<'ctx> { fn walk_if_stmt(&mut self, if_stmt: &'ctx ast::IfStmt) -> Self::Result { self.expr(&if_stmt.cond); - self.stmts(&if_stmt.body); - self.stmts(&if_stmt.orelse); - self.any_ty() + let if_ty = self.stmts(&if_stmt.body); + let orelse_ty = self.stmts(&if_stmt.orelse); + sup(&[if_ty, orelse_ty]) } fn walk_import_stmt(&mut self, _import_stmt: &'ctx ast::ImportStmt) -> Self::Result { @@ -220,59 +317,75 @@ impl<'ctx> MutSelfTypedResultWalker<'ctx> for Resolver<'ctx> { fn walk_quant_expr(&mut self, quant_expr: &'ctx ast::QuantExpr) -> Self::Result { let iter_ty = self.expr(&quant_expr.target); - if iter_ty.is_any() { - iter_ty - } else { - let (start, end) = (self.ctx.start_pos.clone(), self.ctx.end_pos.clone()); - self.enter_scope(start, end, ScopeKind::Loop); - let (mut key_name, mut val_name) = (None, None); - let mut target_node = None; - for (i, target) in quant_expr.variables.iter().enumerate() { - target_node = Some(target); - let name = &target.node.names[0]; - if i == 0 { - key_name = Some(name.to_string()); - } - if i == 1 { - val_name = Some(name.to_string()) - } - self.ctx.local_vars.push(name.to_string()); - let (start, end) = target.get_span_pos(); - self.insert_object( - name, - ScopeObject { - name: name.to_string(), - start, - end, - ty: self.any_ty(), - kind: ScopeObjectKind::Variable, - }, + let (start, mut end) = quant_expr.test.get_span_pos(); + if let Some(if_cond) = &quant_expr.if_cond { + end = if_cond.get_end_pos(); + } + self.enter_scope(start, end, ScopeKind::Loop); + let (mut key_name, mut val_name) = (None, None); + for (i, target) in quant_expr.variables.iter().enumerate() { + if target.node.names.is_empty() { + continue; + } + if target.node.names.len() > 1 { + self.handler.add_compile_error( + "loop variables can only be ordinary identifiers", + target.get_span_pos(), ); } - self.do_loop_type_check( - target_node.unwrap(), - key_name, - val_name, - iter_ty, - quant_expr.target.get_pos(), - ); - self.expr_or_any_type(&quant_expr.if_cond); - let item_ty = self.expr(&quant_expr.test); - self.leave_scope(); - match &quant_expr.op { - ast::QuantOperation::All | ast::QuantOperation::Any => self.bool_ty(), - ast::QuantOperation::Filter => item_ty, - ast::QuantOperation::Map => Rc::new(Type::list(item_ty)), + let name = &target.node.names[0]; + if i == 0 { + key_name = Some(name); + } else if i == 1 { + val_name = Some(name) + } else { + self.handler.add_compile_error( + &format!( + "the number of loop variables is {}, which can only be 1 or 2", + quant_expr.variables.len() + ), + target.get_span_pos(), + ); + break; } + self.ctx.local_vars.push(name.node.to_string()); + let (start, end) = target.get_span_pos(); + self.insert_object( + &name.node, + ScopeObject { + name: name.node.to_string(), + start, + end, + ty: self.any_ty(), + kind: ScopeObjectKind::Variable, + doc: None, + }, + ); + } + self.do_loop_type_check( + key_name, + val_name, + iter_ty.clone(), + quant_expr.target.get_span_pos(), + ); + self.expr_or_any_type(&quant_expr.if_cond); + let item_ty = self.expr(&quant_expr.test); + self.leave_scope(); + match &quant_expr.op { + ast::QuantOperation::All | ast::QuantOperation::Any => self.bool_ty(), + ast::QuantOperation::Filter => iter_ty, + ast::QuantOperation::Map => Arc::new(Type::list(item_ty)), } } fn walk_schema_attr(&mut self, schema_attr: &'ctx ast::SchemaAttr) -> Self::Result { self.ctx.local_vars.clear(); let (start, end) = schema_attr.name.get_span_pos(); - let name = if schema_attr.name.node.contains('.') { - self.handler - .add_compile_error("schema attribute can not be selected", start.clone()); + let name = if schema_attr.is_ident_attr() && schema_attr.name.node.contains('.') { + self.handler.add_compile_error( + "schema attribute can not be selected", + schema_attr.name.get_span_pos(), + ); schema_attr.name.node.split('.').collect::>()[0] } else { &schema_attr.name.node @@ -282,8 +395,19 @@ impl<'ctx> MutSelfTypedResultWalker<'ctx> for Resolver<'ctx> { .borrow() .get_type_of_attr(name) .map_or(self.any_ty(), |ty| ty); - // Schema attribute decorators - self.resolve_decorators(&schema_attr.decorators, DecoratorTarget::Attribute, name); + + self.node_ty_map.borrow_mut().insert( + self.get_node_key(schema_attr.name.id.clone()), + expected_ty.clone(), + ); + + let doc_str = schema + .borrow() + .attrs + .get(name) + .map(|attr| attr.doc.clone()) + .flatten(); + self.insert_object( name, ScopeObject { @@ -291,7 +415,8 @@ impl<'ctx> MutSelfTypedResultWalker<'ctx> for Resolver<'ctx> { start, end, ty: expected_ty.clone(), - kind: ScopeObjectKind::Variable, + kind: ScopeObjectKind::Attribute, + doc: doc_str, }, ); if let Some(value) = &schema_attr.value { @@ -306,19 +431,39 @@ impl<'ctx> MutSelfTypedResultWalker<'ctx> for Resolver<'ctx> { } else { self.expr(value) }; - let pos = schema_attr.name.get_pos(); match &schema_attr.op { Some(bin_or_aug) => match bin_or_aug { // Union - ast::BinOrAugOp::Aug(ast::AugOp::BitOr) => { + ast::AugOp::BitOr => { let op = ast::BinOp::BitOr; - let value_ty = self.binary(value_ty, expected_ty.clone(), &op, pos.clone()); - self.must_assignable_to(value_ty, expected_ty, pos, None); + let value_ty = self.binary( + value_ty, + expected_ty.clone(), + &op, + schema_attr.name.get_span_pos(), + ); + self.must_assignable_to( + value_ty, + expected_ty, + schema_attr.name.get_span_pos(), + None, + ); } // Assign - _ => self.must_assignable_to(value_ty, expected_ty, pos, None), + _ => self.must_assignable_to( + value_ty, + expected_ty, + schema_attr.name.get_span_pos(), + None, + ), }, - None => bug!("invalid ast schema attr op kind"), + // Default is Assign + None => self.must_assignable_to( + value_ty, + expected_ty, + schema_attr.name.get_span_pos(), + None, + ), } } self.any_ty() @@ -334,83 +479,135 @@ impl<'ctx> MutSelfTypedResultWalker<'ctx> for Resolver<'ctx> { fn walk_unary_expr(&mut self, unary_expr: &'ctx ast::UnaryExpr) -> Self::Result { let operand_ty = self.expr(&unary_expr.operand); - self.unary(operand_ty, &unary_expr.op, unary_expr.operand.get_pos()) + self.unary( + operand_ty, + &unary_expr.op, + unary_expr.operand.get_span_pos(), + ) } fn walk_binary_expr(&mut self, binary_expr: &'ctx ast::BinaryExpr) -> Self::Result { let left_ty = self.expr(&binary_expr.left); let mut right_ty = self.expr(&binary_expr.right); - let pos = binary_expr.left.get_pos(); + let range = (binary_expr.left.get_pos(), binary_expr.right.get_end_pos()); match &binary_expr.op { - ast::BinOrCmpOp::Bin(bin_op) => match bin_op { - ast::BinOp::As => { - if let ast::Expr::Identifier(identifier) = &binary_expr.right.node { - right_ty = self.parse_ty_str_with_scope( - &identifier.get_name(), - binary_expr.right.get_pos(), - ); - if right_ty.is_schema() { - let mut schema_ty = right_ty.into_schema_type(); - schema_ty.is_instance = true; - right_ty = Rc::new(Type::schema(schema_ty)); - } - let ty_annotation_str = right_ty.into_type_annotation_str(); - self.add_type_alias( - &identifier.get_name(), - &ty_str_replace_pkgpath(&ty_annotation_str, &self.ctx.pkgpath), - ); - } else { - self.handler - .add_compile_error("keyword 'as' right operand must be a type", pos); - return left_ty; + ast::BinOp::As => { + if let ast::Expr::Identifier(identifier) = &binary_expr.right.node { + right_ty = self.parse_ty_str_with_scope( + &identifier.get_name(), + binary_expr.right.get_span_pos(), + ); + if right_ty.is_schema() { + let mut schema_ty = right_ty.into_schema_type(); + schema_ty.is_instance = true; + right_ty = Arc::new(Type::schema(schema_ty)); } - self.binary(left_ty, right_ty, bin_op, pos) + let ty_annotation_str = right_ty.into_type_annotation_str(); + self.add_type_alias( + &identifier.get_name(), + &ty_str_replace_pkgpath(&ty_annotation_str, &self.ctx.pkgpath), + ); + } else { + self.handler + .add_compile_error("keyword 'as' right operand must be a type", range); + return left_ty; } - _ => self.binary(left_ty, right_ty, bin_op, pos), - }, - ast::BinOrCmpOp::Cmp(cmp_op) => self.compare(left_ty, right_ty, cmp_op, pos), + self.binary(left_ty, right_ty, &binary_expr.op, range) + } + _ => self.binary(left_ty, right_ty, &binary_expr.op, range), } } fn walk_selector_expr(&mut self, selector_expr: &'ctx ast::SelectorExpr) -> Self::Result { let mut value_ty = self.expr(&selector_expr.value); - let pos = selector_expr.attr.get_pos(); + if value_ty.is_module() && selector_expr.has_question { + let attr = selector_expr.attr.node.get_name(); + + self.handler.add_compile_error_with_suggestions( + &format!( + "For the module type, the use of '?.{}' is unnecessary and it can be modified as '.{}'", + attr, + attr + ), + (selector_expr.value.get_end_pos(), selector_expr.attr.get_pos()), + Some(vec![".".to_string()]) + ); + } + + self.node_ty_map.borrow_mut().insert( + self.get_node_key(selector_expr.attr.id.clone()), + value_ty.clone(), + ); + for name in &selector_expr.attr.node.names { - value_ty = self.load_attr(value_ty.clone(), name, pos.clone()); + value_ty = self.load_attr( + value_ty.clone(), + &name.node, + selector_expr.attr.get_span_pos(), + ); + self.node_ty_map + .borrow_mut() + .insert(self.get_node_key(name.id.clone()), value_ty.clone()); + } + + if let TypeKind::Function(func) = &value_ty.kind { + self.insert_object( + &selector_expr.attr.node.get_name(), + ScopeObject { + name: selector_expr.attr.node.get_name(), + start: selector_expr.attr.get_pos(), + end: selector_expr.attr.get_end_pos(), + ty: value_ty.clone(), + kind: ScopeObjectKind::FunctionCall, + doc: Some(func.doc.clone()), + }, + ) } + value_ty } fn walk_call_expr(&mut self, call_expr: &'ctx ast::CallExpr) -> Self::Result { let call_ty = self.expr(&call_expr.func); - let pos = call_expr.func.get_pos(); + let range = call_expr.func.get_span_pos(); if call_ty.is_any() { - self.do_arguments_type_check(&call_expr.args, &call_expr.keywords, &[]); + self.do_arguments_type_check( + &call_expr.func, + &call_expr.args, + &call_expr.keywords, + &FunctionType::variadic_func(), + ); self.any_ty() } else if let TypeKind::Function(func_ty) = &call_ty.kind { - self.do_arguments_type_check(&call_expr.args, &call_expr.keywords, &func_ty.params); + self.do_arguments_type_check( + &call_expr.func, + &call_expr.args, + &call_expr.keywords, + &func_ty, + ); func_ty.return_ty.clone() } else if let TypeKind::Schema(schema_ty) = &call_ty.kind { if schema_ty.is_instance { self.handler.add_compile_error( &format!("schema '{}' instance is not callable", call_ty.ty_str()), - pos, + range, ); self.any_ty() } else { self.do_arguments_type_check( + &call_expr.func, &call_expr.args, &call_expr.keywords, - &schema_ty.func.params, + &schema_ty.func, ); let mut return_ty = schema_ty.clone(); return_ty.is_instance = true; - Rc::new(Type::schema(return_ty)) + Arc::new(Type::schema(return_ty)) } } else { self.handler.add_compile_error( &format!("'{}' object is not callable", call_ty.ty_str()), - pos, + range, ); self.any_ty() } @@ -418,93 +615,15 @@ impl<'ctx> MutSelfTypedResultWalker<'ctx> for Resolver<'ctx> { fn walk_subscript(&mut self, subscript: &'ctx ast::Subscript) -> Self::Result { let value_ty = self.expr(&subscript.value); - let pos = subscript.value.get_pos(); - if value_ty.is_any() { - value_ty - } else { - match &value_ty.kind { - TypeKind::Str | TypeKind::StrLit(_) | TypeKind::List(_) => { - if let Some(index) = &subscript.index { - self.must_be_type(index, self.any_ty()); - if value_ty.is_list() { - value_ty.list_item_ty() - } else { - self.str_ty() - } - } else { - for expr in [&subscript.lower, &subscript.upper, &subscript.step] - .iter() - .copied() - .flatten() - { - self.must_be_type(expr, self.int_ty()); - } - if value_ty.is_list() { - value_ty - } else { - self.str_ty() - } - } - } - TypeKind::Dict(_, val_ty) => { - if let Some(index) = &subscript.index { - let index_key_ty = self.expr(index); - if index_key_ty.is_none_or_any() { - val_ty.clone() - } else if !index_key_ty.is_key() { - self.handler.add_compile_error( - &format!( - "invalid dict/schema key type: '{}'", - index_key_ty.ty_str() - ), - pos, - ); - self.any_ty() - } else if let ast::Expr::StringLit(string_lit) = &subscript.value.node { - self.load_attr(value_ty, &string_lit.value, pos) - } else { - val_ty.clone() - } - } else { - self.handler - .add_compile_error("unhashable type: 'slice'", pos); - self.any_ty() - } - } - TypeKind::Schema(schema_ty) => { - if let Some(index) = &subscript.index { - let index_key_ty = self.expr(index); - if index_key_ty.is_none_or_any() { - schema_ty.val_ty() - } else if !index_key_ty.is_key() { - self.handler.add_compile_error( - &format!( - "invalid dict/schema key type: '{}'", - index_key_ty.ty_str() - ), - pos, - ); - self.any_ty() - } else if let ast::Expr::StringLit(string_lit) = &subscript.value.node { - self.load_attr(value_ty, &string_lit.value, pos) - } else { - schema_ty.val_ty() - } - } else { - self.handler - .add_compile_error("unhashable type: 'slice'", pos); - self.any_ty() - } - } - _ => { - self.handler.add_compile_error( - &format!("'{}' object is not subscriptable", value_ty.ty_str()), - subscript.value.get_pos(), - ); - self.any_ty() - } - } - } + let range = subscript.value.get_span_pos(); + self.subscript( + value_ty, + &subscript.index, + &subscript.lower, + &subscript.upper, + &subscript.step, + range, + ) } fn walk_paren_expr(&mut self, paren_expr: &'ctx ast::ParenExpr) -> Self::Result { @@ -512,12 +631,15 @@ impl<'ctx> MutSelfTypedResultWalker<'ctx> for Resolver<'ctx> { } fn walk_list_expr(&mut self, list_expr: &'ctx ast::ListExpr) -> Self::Result { + let stack_depth = self.switch_list_expr_context(); let item_type = sup(&self.exprs(&list_expr.elts).to_vec()); + self.clear_config_expr_context(stack_depth, false); Type::list_ref(item_type) } fn walk_list_comp(&mut self, list_comp: &'ctx ast::ListComp) -> Self::Result { let start = list_comp.elt.get_pos(); + let stack_depth = self.switch_list_expr_context(); let end = match list_comp.generators.last() { Some(last) => last.get_end_pos(), None => list_comp.elt.get_end_pos(), @@ -527,29 +649,82 @@ impl<'ctx> MutSelfTypedResultWalker<'ctx> for Resolver<'ctx> { self.walk_comp_clause(&comp_clause.node); } if let ast::Expr::Starred(_) = list_comp.elt.node { - self.handler - .add_compile_error("list unpacking cannot be used in list comprehension", start); + self.handler.add_compile_error( + "list unpacking cannot be used in list comprehension", + list_comp.elt.get_span_pos(), + ); } let item_ty = self.expr(&list_comp.elt); self.leave_scope(); + self.clear_config_expr_context(stack_depth, false); Type::list_ref(item_ty) } fn walk_dict_comp(&mut self, dict_comp: &'ctx ast::DictComp) -> Self::Result { - let key = dict_comp.entry.key.as_ref().unwrap(); - let start = key.get_pos(); - let end = match dict_comp.generators.last() { - Some(last) => last.get_end_pos(), - None => dict_comp.entry.value.get_end_pos(), - }; - self.enter_scope(start, end, ScopeKind::Loop); - for comp_clause in &dict_comp.generators { - self.walk_comp_clause(&comp_clause.node); + if dict_comp.entry.key.is_none() { + self.handler.add_compile_error( + "dict unpacking cannot be used in dict comprehension", + dict_comp.entry.value.get_span_pos(), + ); + let start = dict_comp.entry.value.get_pos(); + let end = match dict_comp.generators.last() { + Some(last) => last.get_end_pos(), + None => dict_comp.entry.value.get_end_pos(), + }; + self.enter_scope(start.clone(), end, ScopeKind::Loop); + for comp_clause in &dict_comp.generators { + self.walk_comp_clause(&comp_clause.node); + } + let stack_depth = self.switch_config_expr_context_by_key(&dict_comp.entry.key); + let val_ty = self.expr(&dict_comp.entry.value); + let key_ty = match &val_ty.kind { + TypeKind::None | TypeKind::Any => val_ty.clone(), + TypeKind::Dict(DictType { key_ty, .. }) => key_ty.clone(), + TypeKind::Schema(schema_ty) => schema_ty.key_ty().clone(), + TypeKind::Union(types) + if self + .ctx + .ty_ctx + .is_config_type_or_config_union_type(val_ty.clone()) => + { + sup(&types + .iter() + .map(|ty| ty.config_key_ty()) + .collect::>()) + } + _ => { + self.handler.add_compile_error( + &format!( + "only dict and schema can be used ** unpack, got '{}'", + val_ty.ty_str() + ), + dict_comp.entry.value.get_span_pos(), + ); + self.any_ty() + } + }; + self.clear_config_expr_context(stack_depth, false); + self.leave_scope(); + Type::dict_ref(key_ty, val_ty) + } else { + let key = dict_comp.entry.key.as_ref().unwrap(); + let end = match dict_comp.generators.last() { + Some(last) => last.get_end_pos(), + None => dict_comp.entry.value.get_end_pos(), + }; + let start = key.get_pos(); + self.enter_scope(start.clone(), end, ScopeKind::Loop); + for comp_clause in &dict_comp.generators { + self.walk_comp_clause(&comp_clause.node); + } + let key_ty = self.expr(key); + self.check_attr_ty(&key_ty, key.get_span_pos()); + let stack_depth = self.switch_config_expr_context_by_key(&dict_comp.entry.key); + let val_ty = self.expr(&dict_comp.entry.value); + self.clear_config_expr_context(stack_depth, false); + self.leave_scope(); + Type::dict_ref(key_ty, val_ty) } - let key_ty = self.expr(key); - let val_ty = self.expr(&dict_comp.entry.value); - self.leave_scope(); - Type::dict_ref(key_ty, val_ty) } fn walk_list_if_item_expr( @@ -557,7 +732,11 @@ impl<'ctx> MutSelfTypedResultWalker<'ctx> for Resolver<'ctx> { list_if_item_expr: &'ctx ast::ListIfItemExpr, ) -> Self::Result { self.expr(&list_if_item_expr.if_cond); - let or_else_ty = self.expr_or_any_type(&list_if_item_expr.orelse); + let mut or_else_ty = self.expr_or_any_type(&list_if_item_expr.orelse); + // `orelse` node maybe a list unpack node, use its item type instead. + if let TypeKind::List(item_ty) = &or_else_ty.kind { + or_else_ty = item_ty.clone(); + } let exprs_ty = sup(&self.exprs(&list_if_item_expr.exprs).to_vec()); sup(&[or_else_ty, exprs_ty]) } @@ -568,7 +747,7 @@ impl<'ctx> MutSelfTypedResultWalker<'ctx> for Resolver<'ctx> { match &ty.kind { TypeKind::None | TypeKind::Any => (ty.clone(), true), TypeKind::List(item_ty) => (item_ty.clone(), true), - TypeKind::Dict(key_ty, _) => (key_ty.clone(), true), + TypeKind::Dict(DictType { key_ty, .. }) => (key_ty.clone(), true), TypeKind::Schema(schema_ty) => (schema_ty.key_ty(), true), TypeKind::Union(types) => { let results = types @@ -584,7 +763,7 @@ impl<'ctx> MutSelfTypedResultWalker<'ctx> for Resolver<'ctx> { results.iter().all(|(_, r)| *r), ) } - _ => (Rc::new(Type::ANY), false), + _ => (Arc::new(Type::ANY), false), } } let (ty, result) = starred_ty_walk_fn(&value_ty); @@ -594,7 +773,7 @@ impl<'ctx> MutSelfTypedResultWalker<'ctx> for Resolver<'ctx> { "only list, dict, schema object can be used * unpacked, got {}", ty.ty_str() ), - starred_expr.value.get_pos(), + starred_expr.value.get_span_pos(), ); } ty @@ -605,106 +784,70 @@ impl<'ctx> MutSelfTypedResultWalker<'ctx> for Resolver<'ctx> { config_if_entry_expr: &'ctx ast::ConfigIfEntryExpr, ) -> Self::Result { self.expr(&config_if_entry_expr.if_cond); - let mut key_types: Vec = vec![]; - let mut val_types: Vec = vec![]; - for entry in &config_if_entry_expr.items { - let key = &entry.node.key; - let value = &entry.node.value; - let mut stack_depth = 0; - self.check_config_entry(key, value); - stack_depth += self.switch_config_expr_context_by_key(key) as usize; - let mut entry_key_ty = self.any_ty(); - let mut entry_val_ty = self.expr(value).clone(); - match key { - Some(key) => { - if let ast::Expr::Identifier(identifier) = &key.node { - entry_key_ty = self.str_ty(); - for _ in 0..identifier.names.len() - 1 { - entry_val_ty = Type::dict_ref(self.str_ty(), entry_val_ty.clone()) - } - } - } - None => match &entry_val_ty.kind { - TypeKind::None | TypeKind::Any => {} - TypeKind::Dict(key_ty, val_ty) => { - entry_key_ty = key_ty.clone(); - entry_val_ty = val_ty.clone(); - } - TypeKind::Schema(schema_ty) => { - entry_key_ty = schema_ty.key_ty(); - entry_val_ty = schema_ty.val_ty(); - } - TypeKind::Union(types) - if self - .ctx - .ty_ctx - .is_config_type_or_config_union_type(entry_val_ty.clone()) => - { - entry_key_ty = sup(&types - .iter() - .map(|ty| ty.config_key_ty()) - .collect::>()); - entry_val_ty = sup(&types - .iter() - .map(|ty| ty.config_val_ty()) - .collect::>()); - } - _ => { - self.handler.add_compile_error( - &format!( - "only dict and schema can be used ** unpack, got '{}'", - entry_val_ty.ty_str() - ), - value.get_pos(), - ); - } - }, - } - key_types.push(entry_key_ty); - val_types.push(entry_val_ty); - self.clear_config_expr_context(stack_depth, false); + let dict_ty = self.walk_config_entries(&config_if_entry_expr.items); + if let Some(orelse) = &config_if_entry_expr.orelse { + let or_else_ty = self.expr(orelse); + sup(&[dict_ty, or_else_ty]) + } else { + dict_ty } - let dict_ty = Type::dict_ref(sup(&key_types), sup(&val_types)); - let or_else_ty = self.expr_or_any_type(&config_if_entry_expr.orelse); - sup(&[dict_ty, or_else_ty]) } fn walk_comp_clause(&mut self, comp_clause: &'ctx ast::CompClause) -> Self::Result { let iter_ty = self.expr(&comp_clause.iter); let (mut key_name, mut val_name) = (None, None); - let mut target_node = None; + let mut prev_target_pos = None; for (i, target) in comp_clause.targets.iter().enumerate() { - target_node = Some(target); + if target.node.names.is_empty() { + continue; + } + if target.node.names.len() > 1 { + self.handler.add_compile_error( + "loop variables can only be ordinary identifiers", + target.get_span_pos(), + ); + } let name = &target.node.names[0]; if i == 0 { - key_name = Some(name.to_string()); - } - if i == 1 { - val_name = Some(name.to_string()) + key_name = Some(name); + } else if i == 1 { + val_name = Some(name); + } else { + let previous_pos = if let Some(prev_pos) = prev_target_pos { + prev_pos + } else { + target.get_end_pos() + }; + self.handler.add_compile_error_with_suggestions( + &format!( + "the number of loop variables is {}, which can only be 1 or 2", + comp_clause.targets.len() + ), + (previous_pos, target.get_end_pos()), + Some(vec![]), + ); + break; } - self.ctx.local_vars.push(name.to_string()); + self.ctx.local_vars.push(name.node.to_string()); let (start, end) = target.get_span_pos(); self.insert_object( - name, + &name.node, ScopeObject { - name: name.to_string(), + name: name.node.to_string(), start, end, ty: self.any_ty(), kind: ScopeObjectKind::Variable, + doc: None, }, ); + prev_target_pos = Some(target.get_end_pos()); } if iter_ty.is_any() { + self.exprs(&comp_clause.ifs); iter_ty } else { - self.do_loop_type_check( - target_node.unwrap(), - key_name, - val_name, - iter_ty, - comp_clause.iter.get_pos(), - ); + self.do_loop_type_check(key_name, val_name, iter_ty, comp_clause.iter.get_span_pos()); self.exprs(&comp_clause.ifs); self.any_ty() } @@ -715,12 +858,12 @@ impl<'ctx> MutSelfTypedResultWalker<'ctx> for Resolver<'ctx> { if !matches!(&schema_expr.config.node, ast::Expr::Config(_)) { self.handler.add_compile_error( "Invalid schema config expr, expect config entries, e.g., {k1 = v1, k2 = v2}", - schema_expr.config.get_pos(), + schema_expr.config.get_span_pos(), ); } - let mut pos = schema_expr.name.get_pos(); + let mut range = schema_expr.name.get_span_pos(); let ret_ty = match &def_ty.kind { - TypeKind::Dict(_, _) => { + TypeKind::Dict(DictType { .. }) => { let obj = self.new_config_expr_context_item( "", def_ty.clone(), @@ -730,16 +873,18 @@ impl<'ctx> MutSelfTypedResultWalker<'ctx> for Resolver<'ctx> { let init_stack_depth = self.switch_config_expr_context(Some(obj)); let config_ty = self.expr(&schema_expr.config); self.clear_config_expr_context(init_stack_depth as usize, false); - self.binary(def_ty.clone(), config_ty, &ast::BinOp::BitOr, pos) + self.binary(def_ty.clone(), config_ty, &ast::BinOp::BitOr, range) } TypeKind::Schema(schema_ty) => { if !schema_ty.is_instance { - let ty_annotation_str = ty_str_replace_pkgpath( - &def_ty.into_type_annotation_str(), - &self.ctx.pkgpath, - ); let name = schema_expr.name.node.get_name(); - self.add_type_alias(&name, &ty_annotation_str); + if !self.ctx.local_vars.contains(&name) { + let ty_annotation_str = ty_str_replace_pkgpath( + &def_ty.into_type_annotation_str(), + &self.ctx.pkgpath, + ); + self.add_type_alias(&name, &ty_annotation_str); + } } let obj = self.new_config_expr_context_item( &schema_ty.name, @@ -749,27 +894,42 @@ impl<'ctx> MutSelfTypedResultWalker<'ctx> for Resolver<'ctx> { ); let init_stack_depth = self.switch_config_expr_context(Some(obj)); self.expr(&schema_expr.config); + self.node_ty_map.borrow_mut().insert( + self.get_node_key(schema_expr.config.id.clone()), + def_ty.clone(), + ); self.clear_config_expr_context(init_stack_depth as usize, false); if schema_ty.is_instance { if !schema_expr.args.is_empty() || !schema_expr.kwargs.is_empty() { self.handler.add_compile_error( "Arguments cannot be used in the schema modification expression", - pos, + range, ); } } else { + let func = Box::new(ast::Node::node_with_pos( + ast::Expr::Identifier(schema_expr.name.node.clone()), + schema_expr.name.pos(), + )); self.do_arguments_type_check( + &func, &schema_expr.args, &schema_expr.kwargs, - &schema_ty.func.params, + &schema_ty.func, ); } self.any_ty() } + TypeKind::Any => { + return self.any_ty(); + } _ => { - pos.filename = self.ctx.filename.clone(); - self.handler - .add_compile_error(&format!("Invalid schema type '{}'", def_ty.ty_str()), pos); + range.0.filename = self.ctx.filename.clone(); + range.1.filename = self.ctx.filename.clone(); + self.handler.add_compile_error( + &format!("Invalid schema type '{}'", def_ty.ty_str()), + range, + ); return self.any_ty(); } }; @@ -778,127 +938,14 @@ impl<'ctx> MutSelfTypedResultWalker<'ctx> for Resolver<'ctx> { schema_ty.is_instance = true; } if def_ty_clone.is_schema() { - Rc::new(def_ty_clone) + Arc::new(def_ty_clone) } else { ret_ty } } fn walk_config_expr(&mut self, config_expr: &'ctx ast::ConfigExpr) -> Self::Result { - let mut key_types: Vec = vec![]; - let mut val_types: Vec = vec![]; - for item in &config_expr.items { - let key = &item.node.key; - let value = &item.node.value; - let op = &item.node.operation; - let mut stack_depth: usize = 0; - self.check_config_entry(key, value); - stack_depth += self.switch_config_expr_context_by_key(key) as usize; - let mut has_insert_index = false; - let val_ty = match key { - Some(key) => match &key.node { - ast::Expr::Identifier(identifier) => { - let key_ty = if identifier.names.len() == 1 { - let name = &identifier.names[0]; - let key_ty = if self.ctx.local_vars.contains(name) { - self.expr(key) - } else { - self.str_ty() - }; - self.check_attr_ty(&key_ty, key.get_pos()); - key_ty - } else { - self.str_ty() - }; - let mut val_ty = self.expr(value); - for _ in 0..identifier.names.len() - 1 { - val_ty = Type::dict_ref(self.str_ty(), val_ty.clone()); - } - key_types.push(key_ty); - val_types.push(val_ty.clone()); - val_ty - } - ast::Expr::Subscript(subscript) - if matches!(subscript.value.node, ast::Expr::Identifier(_)) => - { - has_insert_index = true; - let val_ty = self.expr(value); - key_types.push(self.str_ty()); - val_types.push(Type::list_ref(val_ty.clone())); - val_ty - } - _ => { - let key_ty = self.expr(key); - let val_ty = self.expr(value); - self.check_attr_ty(&key_ty, key.get_pos()); - key_types.push(key_ty); - val_types.push(val_ty.clone()); - val_ty - } - }, - None => { - let val_ty = self.expr(value); - match &val_ty.kind { - TypeKind::None | TypeKind::Any => { - val_types.push(val_ty.clone()); - } - TypeKind::Dict(key_ty, val_ty) => { - key_types.push(key_ty.clone()); - val_types.push(val_ty.clone()); - } - TypeKind::Schema(schema_ty) => { - key_types.push(schema_ty.key_ty()); - val_types.push(schema_ty.val_ty()); - } - TypeKind::Union(types) - if self - .ctx - .ty_ctx - .is_config_type_or_config_union_type(val_ty.clone()) => - { - key_types.push(sup(&types - .iter() - .map(|ty| ty.config_key_ty()) - .collect::>())); - val_types.push(sup(&types - .iter() - .map(|ty| ty.config_val_ty()) - .collect::>())); - } - _ => { - self.handler.add_compile_error( - &format!( - "only dict and schema can be used ** unpack, got '{}'", - val_ty.ty_str() - ), - value.get_pos(), - ); - } - } - val_ty - } - }; - if matches!(op, ast::ConfigEntryOperation::Insert) - && !has_insert_index - && !val_ty.is_any() - && !val_ty.is_list() - { - self.handler.add_error( - ErrorKind::IllegalAttributeError, - &[Message { - pos: value.get_pos(), - style: Style::LineAndColumn, - message: format!( - "only list type can in inserted, got '{}'", - val_ty.ty_str() - ), - note: None, - }], - ); - } - self.clear_config_expr_context(stack_depth, false); - } - self.any_ty() + self.walk_config_entries(&config_expr.items) } fn walk_check_expr(&mut self, check_expr: &'ctx ast::CheckExpr) -> Self::Result { @@ -917,20 +964,43 @@ impl<'ctx> MutSelfTypedResultWalker<'ctx> for Resolver<'ctx> { if let Some(args) = &lambda_expr.args { for (i, arg) in args.node.args.iter().enumerate() { let name = arg.node.get_name(); - let arg_ty = args.node.get_arg_type(i); - let ty = self.parse_ty_with_scope(&arg_ty, arg.get_pos()); + let arg_ty = args.node.get_arg_type_node(i); + let range = match arg_ty { + Some(arg_type_node) => arg_type_node.get_span_pos(), + None => arg.get_span_pos(), + }; + let ty = self.parse_ty_with_scope(arg_ty, range); + + // If the arguments type of a lambda is a schema type, + // It should be marked as an schema instance type. + let ty = if let TypeKind::Schema(sty) = &ty.kind { + let mut arg_ty = sty.clone(); + arg_ty.is_instance = true; + Arc::new(Type::schema(arg_ty)) + } else { + ty.clone() + }; + if let Some(name) = arg.node.names.last() { + self.node_ty_map + .borrow_mut() + .insert(self.get_node_key(name.id.clone()), ty.clone()); + } + + let value = &args.node.defaults[i]; params.push(Parameter { name, ty: ty.clone(), - has_default: false, + has_default: value.is_some(), + default_value: value.as_ref().map(|v| print_ast_node(ASTNode::Expr(v))), + range: args.node.args[i].get_span_pos(), }); - let value = &args.node.defaults[i]; self.expr_or_any_type(value); } } let (start, end) = (self.ctx.start_pos.clone(), self.ctx.end_pos.clone()); if let Some(ret_annotation_ty) = &lambda_expr.return_ty { - ret_ty = self.parse_ty_with_scope(&ret_annotation_ty.node, start.clone()); + ret_ty = + self.parse_ty_with_scope(Some(&ret_annotation_ty), (start.clone(), end.clone())); } self.enter_scope(start.clone(), end.clone(), ScopeKind::Lambda); self.ctx.in_lambda_expr.push(true); @@ -944,28 +1014,72 @@ impl<'ctx> MutSelfTypedResultWalker<'ctx> for Resolver<'ctx> { end: end.clone(), ty: param.ty.clone(), kind: ScopeObjectKind::Parameter, + doc: None, }, ) } if let Some(stmt) = lambda_expr.body.last() { if !matches!( stmt.node, - ast::Stmt::Expr(_) | ast::Stmt::Assign(_) | ast::Stmt::AugAssign(_) + ast::Stmt::Expr(_) + | ast::Stmt::Assign(_) + | ast::Stmt::AugAssign(_) + | ast::Stmt::Assert(_) ) { self.handler.add_compile_error( "The last statement of the lambda body must be a expression e.g., x, 1, etc.", - stmt.get_pos(), + stmt.get_span_pos(), ); } } - let real_ret_ty = self.stmts(&lambda_expr.body); + // Walk lambda body statements except the last statement. + if lambda_expr.body.len() > 1 { + self.stmts(&lambda_expr.body[..lambda_expr.body.len() - 1]); + } + // Upgrade return value type to schema if return type is schema + let real_ret_ty = if let Some(stmt) = lambda_expr.body.last() { + if let ast::Stmt::Expr(expr_stmt) = &stmt.node { + if let Some(expr) = expr_stmt.exprs.last() { + self.upgrade_type_for_expr( + ret_ty.clone(), + expr, + expr.get_span_pos(), + lambda_expr.return_ty.as_ref().map(|ty| ty.get_span_pos()), + ) + } else { + let real_ret_ty = self.stmt(stmt); + self.must_assignable_to( + real_ret_ty.clone(), + ret_ty.clone(), + (start, end), + None, + ); + real_ret_ty + } + } else { + let real_ret_ty = self.stmt(stmt); + self.must_assignable_to(real_ret_ty.clone(), ret_ty.clone(), (start, end), None); + real_ret_ty + } + } else { + self.any_ty() + }; + // Leave the lambda scope. self.leave_scope(); self.ctx.in_lambda_expr.pop(); - self.must_assignable_to(real_ret_ty.clone(), ret_ty.clone(), end, None); - if !real_ret_ty.is_any() && ret_ty.is_any() && lambda_expr.return_type_str.is_none() { + + if !real_ret_ty.is_any() && ret_ty.is_any() && lambda_expr.return_ty.is_none() { ret_ty = real_ret_ty; } - Rc::new(Type::function(None, ret_ty, ¶ms, "", false, None)) + let doc = extract_doc_from_body(&lambda_expr.body); + Arc::new(Type::function( + None, + ret_ty, + ¶ms, + &doc.unwrap_or_default(), + false, + None, + )) } fn walk_keyword(&mut self, keyword: &'ctx ast::Keyword) -> Self::Result { @@ -975,8 +1089,13 @@ impl<'ctx> MutSelfTypedResultWalker<'ctx> for Resolver<'ctx> { fn walk_arguments(&mut self, arguments: &'ctx ast::Arguments) -> Self::Result { for (i, arg) in arguments.args.iter().enumerate() { - let ty = arguments.get_arg_type(i); - self.parse_ty_with_scope(&ty, arg.get_pos()); + let ty = arguments.get_arg_type_node(i); + let ty = self.parse_ty_with_scope(ty, arg.get_span_pos()); + if let Some(name) = arg.node.names.last() { + self.node_ty_map + .borrow_mut() + .insert(self.get_node_key(name.id.clone()), ty.clone()); + } let value = &arguments.defaults[i]; self.expr_or_any_type(value); } @@ -990,21 +1109,53 @@ impl<'ctx> MutSelfTypedResultWalker<'ctx> for Resolver<'ctx> { t1.clone(), t2.clone(), &compare.ops[0], - compare.comparators[0].get_pos(), + (compare.left.get_pos(), compare.comparators[0].get_end_pos()), ); for i in 1..compare.comparators.len() - 1 { let op = &compare.ops[i + 1]; - self.compare(t1.clone(), t2.clone(), op, compare.comparators[i].get_pos()); + let t2 = self.expr(&compare.comparators[i]); + self.compare( + t1.clone(), + t2.clone(), + op, + compare.comparators[i].get_span_pos(), + ); } self.bool_ty() } fn walk_identifier(&mut self, identifier: &'ctx ast::Identifier) -> Self::Result { - self.resolve_var( - &identifier.names, + let tys = self.resolve_var( + &identifier.get_names(), &identifier.pkgpath, - self.ctx.start_pos.clone(), - ) + (self.ctx.start_pos.clone(), self.ctx.end_pos.clone()), + ); + for (index, name) in identifier.names.iter().enumerate() { + self.node_ty_map + .borrow_mut() + .insert(self.get_node_key(name.id.clone()), tys[index].clone()); + } + tys.last().unwrap().clone() + } + + fn walk_target(&mut self, target: &'ctx ast::Target) -> Self::Result { + let tys = self.resolve_target( + &target, + (self.ctx.start_pos.clone(), self.ctx.end_pos.clone()), + ); + if let Some(ty) = tys.first() { + self.node_ty_map + .borrow_mut() + .insert(self.get_node_key(target.name.id.clone()), ty.clone()); + } + for (index, name) in target.paths.iter().enumerate() { + self.node_ty_map.borrow_mut().insert( + self.get_node_key(name.id()), + tys.get(index + 1).unwrap_or(&self.any_ty()).clone(), + ); + } + let target_ty = tys.last().unwrap_or(&self.any_ty()).clone(); + target_ty } fn walk_number_lit(&mut self, number_lit: &'ctx ast::NumberLit) -> Self::Result { @@ -1015,28 +1166,28 @@ impl<'ctx> MutSelfTypedResultWalker<'ctx> for Resolver<'ctx> { ast::NumberLitValue::Float(float_val) => { self.handler.add_compile_error( "float literal can not be followed the unit suffix", - self.ctx.start_pos.clone(), + (self.ctx.start_pos.clone(), self.ctx.end_pos.clone()), ); float_val as i64 } }; let binary_suffix_str: String = binary_suffix.value(); - let value = kclvm::units::cal_num(raw_value, &binary_suffix_str); - Rc::new(Type::number_multiplier( + let value = kclvm_runtime::units::cal_num(raw_value, &binary_suffix_str); + Arc::new(Type::number_multiplier( value, raw_value, &binary_suffix_str, )) } None => match number_lit.value { - ast::NumberLitValue::Int(int_val) => Rc::new(Type::int_lit(int_val)), - ast::NumberLitValue::Float(float_val) => Rc::new(Type::float_lit(float_val)), + ast::NumberLitValue::Int(int_val) => Arc::new(Type::int_lit(int_val)), + ast::NumberLitValue::Float(float_val) => Arc::new(Type::float_lit(float_val)), }, } } fn walk_string_lit(&mut self, string_lit: &'ctx ast::StringLit) -> Self::Result { - Rc::new(Type::str_lit(&string_lit.value)) + Arc::new(Type::str_lit(&string_lit.value)) } fn walk_name_constant_lit( @@ -1044,8 +1195,8 @@ impl<'ctx> MutSelfTypedResultWalker<'ctx> for Resolver<'ctx> { name_constant_lit: &'ctx ast::NameConstantLit, ) -> Self::Result { match &name_constant_lit.value { - ast::NameConstant::True => Rc::new(Type::bool_lit(true)), - ast::NameConstant::False => Rc::new(Type::bool_lit(false)), + ast::NameConstant::True => Arc::new(Type::bool_lit(true)), + ast::NameConstant::False => Arc::new(Type::bool_lit(false)), ast::NameConstant::None | ast::NameConstant::Undefined => self.none_ty(), } } @@ -1062,7 +1213,7 @@ impl<'ctx> MutSelfTypedResultWalker<'ctx> for Resolver<'ctx> { if !VALID_FORMAT_SPEC_SET.contains(&spec_lower.as_str()) { self.handler.add_compile_error( &format!("{} is a invalid format spec", spec), - formatted_value.value.get_pos(), + formatted_value.value.get_span_pos(), ); } } @@ -1073,15 +1224,16 @@ impl<'ctx> MutSelfTypedResultWalker<'ctx> for Resolver<'ctx> { // Nothing to do. self.any_ty() } + + fn walk_missing_expr(&mut self, _missing_expr: &'ctx ast::MissingExpr) -> Self::Result { + // Nothing to do. + self.any_ty() + } } -impl<'ctx> Resolver<'ctx> { - #[inline] +impl<'ctx> Resolver<'_> { pub fn stmts(&mut self, stmts: &'ctx [ast::NodeRef]) -> ResolvedResult { - let stmt_types: Vec = stmts - .iter() - .map(|stmt| self.walk_stmt(&stmt.node)) - .collect(); + let stmt_types: Vec = stmts.iter().map(|stmt| self.stmt(&stmt)).collect(); match stmt_types.last() { Some(ty) => ty.clone(), _ => self.any_ty(), @@ -1090,50 +1242,103 @@ impl<'ctx> Resolver<'ctx> { #[inline] pub fn exprs(&mut self, exprs: &'ctx [ast::NodeRef]) -> Vec { - exprs - .iter() - .map(|expr| self.walk_expr(&expr.node)) - .collect() + exprs.iter().map(|expr| self.expr(&expr)).collect() } - #[inline] pub fn expr(&mut self, expr: &'ctx ast::NodeRef) -> ResolvedResult { if let ast::Expr::Identifier(_) = &expr.node { let (start, end) = expr.get_span_pos(); self.ctx.start_pos = start; self.ctx.end_pos = end; } - self.walk_expr(&expr.node) + + let expected_ty = match self.ctx.config_expr_context.last() { + Some(ty) => ty.clone().map(|o| o.ty), + None => None, + }; + + let ty = self.walk_expr(&expr.node); + + if let Some(expected_ty) = expected_ty { + let upgrade_ty = self.upgrade_dict_to_schema(ty.clone(), expected_ty); + self.node_ty_map + .borrow_mut() + .insert(self.get_node_key(expr.id.clone()), upgrade_ty); + } else { + self.node_ty_map + .borrow_mut() + .insert(self.get_node_key(expr.id.clone()), ty.clone()); + } + + ty } - #[inline] pub fn stmt(&mut self, stmt: &'ctx ast::NodeRef) -> ResolvedResult { let (start, end) = stmt.get_span_pos(); self.ctx.start_pos = start; self.ctx.end_pos = end; - self.walk_stmt(&stmt.node) + let ty = self.walk_stmt(&stmt.node); + self.node_ty_map + .borrow_mut() + .insert(self.get_node_key(stmt.id.clone()), ty.clone()); + ty } - #[inline] pub fn expr_or_any_type( &mut self, expr: &'ctx Option>, ) -> ResolvedResult { match expr { - Some(expr) => self.walk_expr(&expr.node), + Some(expr) => { + let ty = self.walk_expr(&expr.node); + self.node_ty_map + .borrow_mut() + .insert(self.get_node_key(expr.id.clone()), ty.clone()); + ty + } None => self.any_ty(), } } - #[inline] pub fn walk_identifier_expr( &mut self, identifier: &'ctx ast::NodeRef, ) -> ResolvedResult { - self.resolve_var( - &identifier.node.names, + let tys = self.resolve_var( + &identifier.node.get_names(), &identifier.node.pkgpath, - identifier.get_pos(), - ) + identifier.get_span_pos(), + ); + for (index, name) in identifier.node.names.iter().enumerate() { + self.node_ty_map + .borrow_mut() + .insert(self.get_node_key(name.id.clone()), tys[index].clone()); + } + let ident_ty = tys.last().unwrap().clone(); + self.node_ty_map + .borrow_mut() + .insert(self.get_node_key(identifier.id.clone()), ident_ty.clone()); + + ident_ty + } + + pub fn walk_target_expr(&mut self, target: &'ctx ast::NodeRef) -> ResolvedResult { + let tys = self.resolve_target(&target.node, target.get_span_pos()); + if let Some(ty) = tys.first() { + self.node_ty_map + .borrow_mut() + .insert(self.get_node_key(target.node.name.id.clone()), ty.clone()); + } + for (index, name) in target.node.paths.iter().enumerate() { + self.node_ty_map.borrow_mut().insert( + self.get_node_key(name.id()), + tys.get(index + 1).unwrap_or(&self.any_ty()).clone(), + ); + } + let target_ty = tys.last().unwrap_or(&self.any_ty()).clone(); + self.node_ty_map + .borrow_mut() + .insert(self.get_node_key(target.id.clone()), target_ty.clone()); + target_ty } } diff --git a/kclvm/sema/src/resolver/para.rs b/kclvm/sema/src/resolver/para.rs index 0e79b472b..461def87d 100644 --- a/kclvm/sema/src/resolver/para.rs +++ b/kclvm/sema/src/resolver/para.rs @@ -1,9 +1,9 @@ -use crate::resolver::pos::GetPos; use crate::resolver::Resolver; use kclvm_ast::ast; +use kclvm_ast::pos::GetPos; use kclvm_error::*; -impl<'ctx> Resolver<'ctx> { +impl<'ctx> Resolver<'_> { /// Do parameter type check. pub fn do_parameters_check(&mut self, args: &'ctx Option>) { if let Some(args) = args { @@ -17,11 +17,12 @@ impl<'ctx> Resolver<'ctx> { self.handler.add_error( ErrorKind::IllegalParameterError, &[Message { - pos: default.get_pos(), + range: default.get_span_pos(), style: Style::LineAndColumn, message: "non-default argument follows default argument" .to_string(), note: Some("A default argument".to_string()), + suggested_replacement: None, }], ); } diff --git a/kclvm/sema/src/resolver/schema.rs b/kclvm/sema/src/resolver/schema.rs index 1d55fbb83..571410cfe 100644 --- a/kclvm/sema/src/resolver/schema.rs +++ b/kclvm/sema/src/resolver/schema.rs @@ -1,26 +1,59 @@ use std::cell::RefCell; +use std::collections::HashMap; use std::rc::Rc; use crate::builtin::BUILTIN_DECORATORS; -use crate::resolver::pos::GetPos; use crate::resolver::Resolver; -use crate::ty::{Decorator, DecoratorTarget, TypeKind}; +use crate::ty::{Decorator, DecoratorTarget, TypeKind, TypeRef}; use kclvm_ast::ast; +use kclvm_ast::pos::GetPos; use kclvm_ast::walker::MutSelfTypedResultWalker; -use kclvm_error::Position; +use kclvm_ast_pretty::{print_ast_node, ASTNode}; +use kclvm_error::diagnostic::Range; +use kclvm_error::{ErrorKind, Message, Position, Style}; use super::node::ResolvedResult; use super::scope::{ScopeKind, ScopeObject, ScopeObjectKind}; -impl<'ctx> Resolver<'ctx> { +impl<'ctx> Resolver<'_> { pub(crate) fn resolve_schema_stmt( &mut self, schema_stmt: &'ctx ast::SchemaStmt, ) -> ResolvedResult { - let ty = self.lookup_type_from_scope(&schema_stmt.name.node, schema_stmt.name.get_pos()); - let scope_ty = ty.into_schema_type(); + let (start, end) = (self.ctx.start_pos.clone(), self.ctx.end_pos.clone()); + self.resolve_unique_key(&schema_stmt.name.node, &schema_stmt.name.get_span_pos()); + let ty = + self.lookup_type_from_scope(&schema_stmt.name.node, schema_stmt.name.get_span_pos()); + self.node_ty_map + .borrow_mut() + .insert(self.get_node_key(schema_stmt.name.id.clone()), ty.clone()); + let scope_ty = if ty.is_schema() { + ty.into_schema_type() + } else { + self.handler.add_error( + ErrorKind::TypeError, + &[Message { + range: schema_stmt.get_span_pos(), + style: Style::LineAndColumn, + message: format!("expected schema type, got {}", ty.ty_str()), + note: None, + suggested_replacement: None, + }], + ); + return ty; + }; self.ctx.schema = Some(Rc::new(RefCell::new(scope_ty.clone()))); - let (start, end) = schema_stmt.get_span_pos(); + if let Some(args) = &schema_stmt.args { + for (i, arg) in args.node.args.iter().enumerate() { + let ty = args.node.get_arg_type_node(i); + let ty = self.parse_ty_with_scope(ty, arg.get_span_pos()); + if let Some(name) = arg.node.names.last() { + self.node_ty_map + .borrow_mut() + .insert(self.get_node_key(name.id.clone()), ty.clone()); + } + } + } self.do_parameters_check(&schema_stmt.args); self.enter_scope( start.clone(), @@ -36,6 +69,7 @@ impl<'ctx> Resolver<'ctx> { end: end.clone(), ty: param.ty.clone(), kind: ScopeObjectKind::Parameter, + doc: None, }, ) } @@ -43,6 +77,7 @@ impl<'ctx> Resolver<'ctx> { if let (Some(index_signature), Some(index_signature_node)) = (scope_ty.index_signature, &schema_stmt.index_signature) { + // Insert the schema index signature key name into the scope. if let Some(key_name) = index_signature.key_name { let (start, end) = index_signature_node.get_span_pos(); self.insert_object( @@ -53,9 +88,35 @@ impl<'ctx> Resolver<'ctx> { end, ty: index_signature.key_ty.clone(), kind: ScopeObjectKind::Variable, + doc: None, }, ) } + // Check index signature default value type. + if let Some(value) = &index_signature_node.node.value { + let expected_ty = index_signature.val_ty; + let value_ty = if let TypeKind::Schema(ty) = &expected_ty.kind { + let (start, end) = value.get_span_pos(); + let obj = self.new_config_expr_context_item( + &ty.name, + expected_ty.clone(), + start, + end, + ); + let init_stack_depth = self.switch_config_expr_context(Some(obj)); + let value_ty = self.expr(value); + self.clear_config_expr_context(init_stack_depth as usize, false); + value_ty + } else { + self.expr(value) + }; + self.must_assignable_to( + value_ty, + expected_ty, + index_signature_node.get_span_pos(), + None, + ); + } } let schema_attr_names = schema_stmt.get_left_identifier_list(); for (line, column, name) in schema_attr_names { @@ -72,6 +133,7 @@ impl<'ctx> Resolver<'ctx> { end: Position::dummy_pos(), ty: self.any_ty(), kind: ScopeObjectKind::Variable, + doc: None, }, ); } @@ -88,8 +150,26 @@ impl<'ctx> Resolver<'ctx> { } pub(crate) fn resolve_rule_stmt(&mut self, rule_stmt: &'ctx ast::RuleStmt) -> ResolvedResult { - let ty = self.lookup_type_from_scope(&rule_stmt.name.node, rule_stmt.name.get_pos()); - let scope_ty = ty.into_schema_type(); + self.resolve_unique_key(&rule_stmt.name.node, &rule_stmt.name.get_span_pos()); + let ty = self.lookup_type_from_scope(&rule_stmt.name.node, rule_stmt.name.get_span_pos()); + self.node_ty_map + .borrow_mut() + .insert(self.get_node_key(rule_stmt.name.id.clone()), ty.clone()); + let scope_ty = if ty.is_schema() { + ty.into_schema_type() + } else { + self.handler.add_error( + ErrorKind::TypeError, + &[Message { + range: rule_stmt.get_span_pos(), + style: Style::LineAndColumn, + message: format!("expected rule type, got {}", ty.ty_str()), + note: None, + suggested_replacement: None, + }], + ); + return ty; + }; self.ctx.schema = Some(Rc::new(RefCell::new(scope_ty.clone()))); let (start, end) = rule_stmt.get_span_pos(); self.do_parameters_check(&rule_stmt.args); @@ -107,6 +187,7 @@ impl<'ctx> Resolver<'ctx> { end: end.clone(), ty: param.ty.clone(), kind: ScopeObjectKind::Parameter, + doc: None, }, ) } @@ -129,7 +210,7 @@ impl<'ctx> Resolver<'ctx> { for decorator in decorators { let name = if let ast::Expr::Identifier(identifier) = &decorator.node.func.node { if identifier.names.len() == 1 { - Some(identifier.names[0].clone()) + Some(identifier.names[0].node.clone()) } else { None } @@ -141,33 +222,111 @@ impl<'ctx> Resolver<'ctx> { Some(ty) => match &ty.kind { TypeKind::Function(func_ty) => { self.do_arguments_type_check( + &decorator.node.func, + &decorator.node.args, + &decorator.node.keywords, + &func_ty, + ); + let (arguments, keywords) = self.arguments_to_string( &decorator.node.args, &decorator.node.keywords, - &func_ty.params, ); decorator_objs.push(Decorator { target: target.clone(), name, key: key.to_string(), + arguments, + keywords, }) } _ => bug!("invalid builtin decorator function type"), }, None => { - self.handler.add_compile_error( + self.handler.add_compile_error_with_suggestions( &format!("UnKnown decorator {}", name), - decorator.get_pos(), + decorator.get_span_pos(), + Some(vec![]), ); } }, None => { self.handler.add_type_error( "decorator name must be a single identifier", - decorator.get_pos(), + decorator.get_span_pos(), ); } } } decorator_objs } + + /// Walk expr and check the type and return the value type. + pub(crate) fn upgrade_type_for_expr( + &mut self, + expected_ty: TypeRef, + expr: &'ctx ast::NodeRef, + target_range: Range, + def_range: Option, + ) -> TypeRef { + let (start, end) = expr.get_span_pos(); + let value_ty = match &expected_ty.kind { + TypeKind::Schema(ty) => { + let obj = + self.new_config_expr_context_item(&ty.name, expected_ty.clone(), start, end); + let init_stack_depth = self.switch_config_expr_context(Some(obj)); + let value_ty = self.expr(expr); + self.clear_config_expr_context(init_stack_depth as usize, false); + value_ty + } + TypeKind::List(_) | TypeKind::Dict(_) | TypeKind::Union(_) => { + let obj = self.new_config_expr_context_item("[]", expected_ty.clone(), start, end); + let init_stack_depth = self.switch_config_expr_context(Some(obj)); + let value_ty = self.expr(expr); + self.clear_config_expr_context(init_stack_depth as usize, false); + value_ty + } + _ => { + self.ctx.config_expr_context.push(None); + let value_ty = self.expr(expr); + self.ctx.config_expr_context.pop(); + value_ty + } + }; + self.must_assignable_to( + value_ty.clone(), + expected_ty.clone(), + target_range, + def_range, + ); + value_ty + } + + fn arguments_to_string( + &mut self, + args: &'ctx [ast::NodeRef], + kwargs: &'ctx [ast::NodeRef], + ) -> (Vec, HashMap) { + if self.options.resolve_val { + ( + args.iter() + .map(|a| print_ast_node(ASTNode::Expr(a))) + .collect(), + kwargs + .iter() + .map(|a| { + ( + a.node.arg.node.get_name(), + a.node + .value + .as_ref() + .map(|v| print_ast_node(ASTNode::Expr(v))) + .unwrap_or_default(), + ) + }) + .collect(), + ) + } else { + (vec![], HashMap::new()) + } + } } diff --git a/kclvm/sema/src/resolver/scope.rs b/kclvm/sema/src/resolver/scope.rs index 03a6430fd..40da9fc69 100644 --- a/kclvm/sema/src/resolver/scope.rs +++ b/kclvm/sema/src/resolver/scope.rs @@ -1,19 +1,31 @@ -use indexmap::IndexMap; -use indexmap::IndexSet; +use anyhow::bail; +use compiler_base_session::Session; +use indexmap::{IndexMap, IndexSet}; +use kclvm_ast::ast::NodeRef; +use kclvm_ast::ast::Stmt; +use kclvm_ast::ast::Stmt::Import; use kclvm_ast::{ast, MAIN_PKG}; -use kclvm_error::Diagnostic; -use kclvm_error::Handler; - +use kclvm_error::diagnostic::Range; +use kclvm_error::{Handler, Level}; +use std::collections::HashMap; +use std::collections::HashSet; +use std::collections::VecDeque; +use std::sync::Arc; use std::{ cell::RefCell, rc::{Rc, Weak}, }; -use crate::resolver::pos::ContainsPos; use crate::resolver::Resolver; -use crate::ty::Type; +use crate::ty::SchemaType; +use crate::ty::TypeRef; use crate::{builtin::BUILTIN_FUNCTIONS, ty::TypeInferMethods}; +use kclvm_ast::ast::AstIndex; +use kclvm_ast::pos::ContainsPos; +use kclvm_ast::pos::GetPos; use kclvm_error::Position; +use parking_lot::RwLock; +use serde::Serialize; /// The object stored in the scope. #[derive(PartialEq, Clone, Debug)] @@ -25,9 +37,11 @@ pub struct ScopeObject { /// The scope object end position. pub end: Position, /// The type of the scope object. - pub ty: Rc, + pub ty: TypeRef, /// The scope object kind. pub kind: ScopeObjectKind, + /// The doc of the scope object, will be None unless the scope object represents a schema or schema attribute. + pub doc: Option, } impl ScopeObject { @@ -38,6 +52,25 @@ impl ScopeObject { } } +impl ContainsPos for ScopeObject { + fn contains_pos(&self, pos: &Position) -> bool { + self.start.less_equal(pos) && pos.less_equal(&self.end) + } +} + +impl GetPos for ScopeObject { + fn get_span_pos(&self) -> Range { + (self.start.clone(), self.end.clone()) + } + fn get_pos(&self) -> Position { + self.start.clone() + } + + fn get_end_pos(&self) -> Position { + self.end.clone() + } +} + #[derive(PartialEq, Clone, Debug)] pub enum ScopeObjectKind { Variable, @@ -45,7 +78,16 @@ pub enum ScopeObjectKind { Definition, Parameter, TypeAlias, - Module, + FunctionCall, + Module(Module), +} + +/// A scope object of module type represents an import stmt on an AST and +/// is used to record information on the AST +#[derive(PartialEq, Clone, Debug)] +pub struct Module { + /// Record stmts which import this module and whether has been used, for check unused imported module and var definition + pub import_stmts: Vec<(NodeRef, bool)>, } /// A Scope maintains a set of objects and links to its containing @@ -86,8 +128,35 @@ impl Scope { } } + /// Get all usable scope objects in current and parent scope. + pub fn all_usable_objects(&self) -> IndexMap>> { + let mut res = match &self.parent { + Some(parent) => match parent.upgrade() { + Some(parent) => parent.borrow().all_usable_objects(), + None => IndexMap::new(), + }, + None => IndexMap::new(), + }; + + for (name, obj) in &self.elems { + match &obj.borrow().kind { + ScopeObjectKind::Module(module) => { + for stmt in &module.import_stmts { + if let Import(import_stmt) = &stmt.0.node { + res.insert(import_stmt.name.clone(), obj.clone()); + } + } + } + _ => { + res.insert(name.clone(), obj.clone()); + } + } + } + res + } + /// Set a type by name to existed object, return true if found. - pub fn set_ty(&mut self, name: &str, ty: Rc) -> bool { + pub fn set_ty(&mut self, name: &str, ty: TypeRef) -> bool { match self.elems.get_mut(name) { Some(obj) => { let mut obj = obj.borrow_mut(); @@ -102,14 +171,17 @@ impl Scope { impl ContainsPos for Scope { /// Check if current scope contains a position fn contains_pos(&self, pos: &Position) -> bool { - self.start.less_equal(pos) && pos.less_equal(&self.end) + match &self.kind { + ScopeKind::Package(files) => files.contains(&pos.filename), + _ => self.start.less_equal(pos) && pos.less_equal(&self.end), + } } } #[derive(Clone, Debug)] pub enum ScopeKind { /// Package scope. - Package, + Package(IndexSet), /// Builtin scope. Builtin, /// Schema name string. @@ -120,6 +192,8 @@ pub enum ScopeKind { CondStmt, /// Lambda expression. Lambda, + /// Config expression + Config, } impl Scope { @@ -187,39 +261,98 @@ impl Scope { None => None, } } + + /// Search scope obj by the object name. + pub fn search_obj_by_name(&self, name: &str) -> Vec { + let mut res = vec![]; + for (obj_name, obj) in &self.elems { + if obj_name == name { + res.push(obj.borrow().clone()) + } + } + for c in &self.children { + let c = c.borrow(); + let mut objs = c.search_obj_by_name(name); + res.append(&mut objs); + } + res + } } /// Program scope is scope contains a multiple scopes related to the /// package path. -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Default)] pub struct ProgramScope { pub scope_map: IndexMap>>, pub import_names: IndexMap>, - pub diagnostics: IndexSet, + pub schema_mapping: IndexMap>>, + pub node_ty_map: Rc>, + pub handler: Handler, } +unsafe impl Send for ProgramScope {} + +unsafe impl Send for Scope {} +unsafe impl Sync for Scope {} + impl ProgramScope { + /// Get all package paths. #[inline] pub fn pkgpaths(&self) -> Vec { self.scope_map.keys().cloned().collect::>() } + /// Get the scope in the main package. #[inline] pub fn main_scope(&self) -> Option<&Rc>> { self.scope_map.get(MAIN_PKG) } - pub fn check_scope_diagnostics(&self) { - if self.diagnostics.len() > 0 { - let mut err_handler = Handler::default(); - err_handler.diagnostics = self.diagnostics.clone(); - err_handler.alert_if_any_errors(); + /// Return diagnostic pretty string but do not abort if the session exists any diagnostic. + pub fn emit_diagnostics_to_string( + &self, + sess: Arc, + include_warning: bool, + ) -> Result<(), String> { + let emit_error = || -> anyhow::Result<()> { + // Add resolve errors into the session + for diag in &self.handler.diagnostics { + if matches!(diag.level, Level::Error) || matches!(diag.level, Level::Suggestions) { + sess.add_err(diag.clone())?; + } + if include_warning && matches!(diag.level, Level::Warning) { + sess.add_err(diag.clone())?; + } + } + // If has syntax and resolve errors, return its string format. + if sess.diag_handler.has_errors()? { + let errors = sess.emit_all_diags_into_string()?; + let mut error_strings = vec![]; + for error in errors { + error_strings.push(error?); + } + bail!(error_strings.join("\n")) + } else { + Ok(()) + } + }; + emit_error().map_err(|e| e.to_string()) + } + + /// Returns the inner most scope on the position. + pub fn inner_most_scope(&self, pos: &Position) -> Option { + for (_, scope) in &self.scope_map { + match scope.borrow().inner_most(&pos) { + Some(scope) => return Some(scope), + None => continue, + } } + None } } /// Construct a builtin scope -pub(crate) fn builtin_scope() -> Scope { +pub fn builtin_scope() -> Scope { let mut elems = IndexMap::default(); for (name, builtin_func) in BUILTIN_FUNCTIONS.iter() { elems.insert( @@ -228,8 +361,9 @@ pub(crate) fn builtin_scope() -> Scope { name: name.to_string(), start: Position::dummy_pos(), end: Position::dummy_pos(), - ty: Rc::new(builtin_func.clone()), + ty: Arc::new(builtin_func.clone()), kind: ScopeObjectKind::Definition, + doc: None, })), ); } @@ -262,6 +396,7 @@ impl<'ctx> Resolver<'ctx> { children.push(Rc::clone(&scope)); // Deref self.scope } + self.scope_level += 1; self.scope = Rc::clone(&scope); } @@ -272,12 +407,13 @@ impl<'ctx> Resolver<'ctx> { Some(parent) => parent.upgrade().unwrap(), None => bug!("the scope parent is empty, can't leave the scope"), }; + self.scope_level -= 1; self.scope = Rc::clone(&parent); } /// Find scope object type by name. #[inline] - pub fn find_type_in_scope(&mut self, name: &str) -> Option> { + pub fn find_type_in_scope(&mut self, name: &str) -> Option { self.scope .borrow() .lookup(name) @@ -286,31 +422,72 @@ impl<'ctx> Resolver<'ctx> { /// Lookup type from the scope by name, if not found, emit a compile error and /// return the any type. - pub fn lookup_type_from_scope(&mut self, name: &str, pos: Position) -> Rc { + pub fn lookup_type_from_scope(&mut self, name: &str, range: Range) -> TypeRef { match self.find_type_in_scope(name) { Some(ty) => ty, + None => { + let mut suggestion = String::new(); + let names = self + .scope + .borrow() + .all_usable_objects() + .keys() + .cloned() + .collect::>(); + let suggs = suggestions::provide_suggestions(name, &names); + if suggs.len() > 0 { + suggestion = format!(", did you mean '{:?}'?", suggs); + } + self.handler.add_compile_error_with_suggestions( + &format!( + "name '{}' is not defined{}", + name.replace('@', ""), + suggestion + ), + range, + Some(suggs.clone()), + ); + self.any_ty() + } + } + } + + /// Set type to the scope exited object, if not found, emit a compile error. + pub fn set_infer_type_to_scope(&mut self, name: &str, ty: TypeRef, node: &ast::Node) { + let mut scope = self.scope.borrow_mut(); + match scope.elems.get_mut(name) { + Some(obj) => { + let mut obj = obj.borrow_mut(); + let infer_ty = self.ctx.ty_ctx.infer_to_variable_type(ty); + self.node_ty_map + .borrow_mut() + .insert(self.get_node_key(node.id.clone()), infer_ty.clone()); + obj.ty = infer_ty; + } None => { self.handler.add_compile_error( &format!("name '{}' is not defined", name.replace('@', "")), - pos, + node.get_span_pos(), ); - self.any_ty() } } } /// Set type to the scope exited object, if not found, emit a compile error. - pub fn set_type_to_scope(&mut self, name: &str, ty: Rc, pos: Position) { + pub fn set_type_to_scope(&mut self, name: &str, ty: TypeRef, node: &ast::Node) { let mut scope = self.scope.borrow_mut(); match scope.elems.get_mut(name) { Some(obj) => { let mut obj = obj.borrow_mut(); - obj.ty = self.ctx.ty_ctx.infer_to_variable_type(ty); + self.node_ty_map + .borrow_mut() + .insert(self.get_node_key(node.id.clone()), ty.clone()); + obj.ty = ty; } None => { self.handler.add_compile_error( &format!("name '{}' is not defined", name.replace('@', "")), - pos, + node.get_span_pos(), ); } } @@ -330,4 +507,266 @@ impl<'ctx> Resolver<'ctx> { pub fn contains_object(&mut self, name: &str) -> bool { self.scope.borrow().elems.contains_key(name) } + + pub fn get_node_key(&self, id: AstIndex) -> NodeKey { + NodeKey { + pkgpath: self.ctx.pkgpath.clone(), + id, + } + } +} + +#[derive(Clone, Debug, Hash, PartialEq, Eq, Serialize)] +pub struct NodeKey { + pub pkgpath: String, + pub id: AstIndex, +} + +pub type NodeTyMap = IndexMap; +pub type KCLScopeCache = Arc>; + +/// For CachedScope, we assume that all changed files must be located in kclvm_ast::MAIN_PKG , +/// if this is not the case, please clear the cache directly +#[derive(Debug, Clone, Default)] +pub struct CachedScope { + pub program_root: String, + pub scope_map: IndexMap>>, + pub schema_mapping: IndexMap>>, + pub node_ty_map: NodeTyMap, + pub invalidate_pkgs: HashSet, + /// Specify the invalid module in the program packages, used for invalidate_module(). + /// If it is None, all modules in the main package will be invalidated + pub invalidate_pkg_modules: Option>, + dependency_graph: DependencyGraph, +} + +unsafe impl Send for CachedScope {} +unsafe impl Sync for CachedScope {} + +#[derive(Debug, Clone, Default)] +struct DependencyGraph { + /// map filename to pkgpath + pub module_map: HashMap>, + /// map pkgpath to node + pub node_map: HashMap, +} + +impl DependencyGraph { + pub fn clear(&mut self) { + self.module_map.clear(); + self.node_map.clear(); + } + + pub fn update( + &mut self, + program: &ast::Program, + invalidate_pkg_modules: &Option>, + ) -> Result, String> { + let mut new_modules = HashMap::new(); + for (pkgpath, modules) in program.pkgs.iter() { + if pkgpath == kclvm_ast::MAIN_PKG { + continue; + } + if !self.node_map.contains_key(pkgpath) { + self.node_map.insert( + pkgpath.to_string(), + DependencyNode { + pkgpath: pkgpath.to_string(), + parents: HashSet::new(), + children: HashSet::new(), + }, + ); + } + for module in modules { + let module = program + .get_module(module) + .expect("Failed to acquire module lock") + .expect(&format!("module {:?} not found in program", module)); + let filename = module.filename.clone(); + if !self.module_map.contains_key(&filename) { + new_modules.insert(filename.clone(), module); + self.module_map.insert(filename.clone(), HashSet::new()); + } + self.module_map + .get_mut(&filename) + .unwrap() + .insert(pkgpath.to_string()); + } + } + + for new_module in new_modules.values() { + self.add_new_module(new_module); + } + + let mut invalidated_set = HashSet::new(); + + match invalidate_pkg_modules { + Some(modules) => { + for module_name in modules { + let result = self.invalidate_module(module_name)?; + for pkg in result { + invalidated_set.insert(pkg); + } + self.remove_dependency_from_pkg(&module_name); + if let Ok(m) = program.get_module(module_name) { + if let Some(module) = m { + self.add_new_module(&module); + } + } + } + } + None => { + if let Some(main_modules) = program.pkgs.get(kclvm_ast::MAIN_PKG) { + for module in main_modules { + let module = program + .get_module(module) + .expect("Failed to acquire module lock") + .expect(&format!("module {:?} not found in program", module)); + let result = self.invalidate_module(&module.filename)?; + for pkg in result { + invalidated_set.insert(pkg); + } + self.remove_dependency_from_pkg(&module.filename); + self.add_new_module(&module); + } + } + } + } + Ok(invalidated_set) + } + + fn add_new_module(&mut self, new_module: &ast::Module) { + let module_file = new_module.filename.clone(); + if let Some(pkgpaths) = self.module_map.get(&module_file) { + for stmt in &new_module.body { + if let ast::Stmt::Import(import_stmt) = &stmt.node { + let parent_pkg = &import_stmt.path.node; + if let Some(parent_node) = self.node_map.get_mut(parent_pkg) { + parent_node.children.insert(new_module.filename.clone()); + } + for pkgpath in pkgpaths { + let cur_node = self.node_map.get_mut(pkgpath).unwrap(); + cur_node.parents.insert(parent_pkg.clone()); + } + } + } + } + } + + fn invalidate_module(&mut self, changed_module: &str) -> Result, String> { + let mut invalidated_set = HashSet::new(); + if let Some(pkgpaths) = self.module_map.get(changed_module).cloned() { + let mut pkg_queue = VecDeque::new(); + for pkgpath in pkgpaths.iter() { + pkg_queue.push_back(self.node_map.get(pkgpath)); + } + + let mut old_size: i64 = -1; + while old_size < invalidated_set.len() as i64 { + old_size = invalidated_set.len() as i64; + let cur_node = loop { + match pkg_queue.pop_front() { + Some(cur_node) => match cur_node { + None => continue, + Some(cur_node) => { + if invalidated_set.contains(&cur_node.pkgpath) { + continue; + } + invalidated_set.insert(cur_node.pkgpath.clone()); + break Some(cur_node); + } + }, + None => break None, + } + }; + if let Some(cur_node) = cur_node { + for child in cur_node.children.iter() { + if let Some(child_pkgs) = self.module_map.get(child) { + for child_pkg in child_pkgs { + if invalidated_set.contains(child_pkg) { + continue; + } + pkg_queue.push_back(self.node_map.get(child_pkg)); + } + } + } + } + } + }; + Ok(invalidated_set) + } + + fn remove_dependency_from_pkg(&mut self, filename: &str) { + if let Some(pkgpaths) = self.module_map.get(filename).cloned() { + for pkgpath in pkgpaths { + if let Some(node) = self.node_map.get(&pkgpath).cloned() { + for parent in node.parents { + if let Some(parent_node) = self.node_map.get_mut(&parent) { + parent_node.children.remove(filename); + } + } + } + } + } + } +} + +#[derive(Debug, Clone, Default)] +struct DependencyNode { + // The package path of the current node. + pkgpath: String, + // The pkgpath which is imported by this package. + parents: HashSet, + // Files which import this package. + children: HashSet, +} + +impl CachedScope { + pub fn new(scope: &ProgramScope, program: &ast::Program) -> Self { + let mut cached_scope = Self { + program_root: program.root.to_string(), + scope_map: scope.scope_map.clone(), + node_ty_map: scope.node_ty_map.borrow().clone(), + invalidate_pkgs: HashSet::default(), + dependency_graph: DependencyGraph::default(), + schema_mapping: scope.schema_mapping.clone(), + invalidate_pkg_modules: None, + }; + let invalidated_pkgs = cached_scope + .dependency_graph + .update(program, &cached_scope.invalidate_pkg_modules); + cached_scope.invalidate_cache(invalidated_pkgs.as_ref()); + cached_scope + } + + pub fn clear(&mut self) { + self.scope_map.clear(); + self.node_ty_map.clear(); + self.dependency_graph.clear(); + self.invalidate_pkgs.clear(); + self.invalidate_pkg_modules = None; + } + + pub fn invalidate_cache(&mut self, invalidated_pkgs: Result<&HashSet, &String>) { + match invalidated_pkgs { + Ok(invalidated_pkgs) => { + for invalidated_pkg in invalidated_pkgs.iter() { + self.scope_map.remove(invalidated_pkg); + } + self.invalidate_pkgs = invalidated_pkgs.clone(); + } + Err(_) => self.clear(), + } + } + + pub fn update(&mut self, program: &ast::Program) { + if self.program_root != program.root { + self.clear(); + self.program_root = program.root.clone(); + } + let invalidated_pkgs = self + .dependency_graph + .update(program, &self.invalidate_pkg_modules); + self.invalidate_cache(invalidated_pkgs.as_ref()); + } } diff --git a/kclvm/sema/src/resolver/test_data/annotation_check_assignment.k b/kclvm/sema/src/resolver/test_data/annotation_check_assignment.k new file mode 100644 index 000000000..cc26f36b0 --- /dev/null +++ b/kclvm/sema/src/resolver/test_data/annotation_check_assignment.k @@ -0,0 +1,6 @@ +params = option("params") or {} +# Use `k = v` to override existing annotations +annotations: {str:str} = {k = v for k, v in params.annotations or {}} +items = [item | { + metadata.annotations: annotations +} for item in option("items")] \ No newline at end of file diff --git a/kclvm/sema/src/resolver/test_data/assign_in_lambda.k b/kclvm/sema/src/resolver/test_data/assign_in_lambda.k new file mode 100644 index 000000000..cd8ca643d --- /dev/null +++ b/kclvm/sema/src/resolver/test_data/assign_in_lambda.k @@ -0,0 +1,6 @@ +lambda { + containers = [] + if True: + containers = [] + images: [str] = [c.image for c in containers] +} diff --git a/kclvm/sema/src/resolver/test_data/attr_ty_check.k b/kclvm/sema/src/resolver/test_data/attr_ty_check.k new file mode 100644 index 000000000..2c86d4710 --- /dev/null +++ b/kclvm/sema/src/resolver/test_data/attr_ty_check.k @@ -0,0 +1,9 @@ +schema Data: + id?: int + +schema Config: + datas: [Data] + +config = Config { + datas: [{id = "1"}] +} diff --git a/kclvm/parser/testdata/a3.k b/kclvm/sema/src/resolver/test_data/cache/a/a.k similarity index 100% rename from kclvm/parser/testdata/a3.k rename to kclvm/sema/src/resolver/test_data/cache/a/a.k diff --git a/kclvm/sema/src/resolver/test_data/cache/b/b.k b/kclvm/sema/src/resolver/test_data/cache/b/b.k new file mode 100644 index 000000000..163eb2f6e --- /dev/null +++ b/kclvm/sema/src/resolver/test_data/cache/b/b.k @@ -0,0 +1 @@ +import ..c \ No newline at end of file diff --git a/kclvm/sema/src/resolver/test_data/cache/c/c.k b/kclvm/sema/src/resolver/test_data/cache/c/c.k new file mode 100644 index 000000000..0d2a01c6e --- /dev/null +++ b/kclvm/sema/src/resolver/test_data/cache/c/c.k @@ -0,0 +1 @@ +a = 1 \ No newline at end of file diff --git a/kclvm/sema/src/resolver/test_data/cache/main.k b/kclvm/sema/src/resolver/test_data/cache/main.k new file mode 100644 index 000000000..94de74caf --- /dev/null +++ b/kclvm/sema/src/resolver/test_data/cache/main.k @@ -0,0 +1,5 @@ + +# main -> a +# -> b -> c +import .a +import .b diff --git a/kclvm/sema/src/resolver/test_data/doc.k b/kclvm/sema/src/resolver/test_data/doc.k new file mode 100644 index 000000000..5ac8e6154 --- /dev/null +++ b/kclvm/sema/src/resolver/test_data/doc.k @@ -0,0 +1,31 @@ +schema Server: + """ + Server is the common user interface for long-running + services adopting the best practice of Kubernetes. + + Attributes + ---------- + workloadType : str, default is "Deployment", required + Use this attribute to specify which kind of long-running service you want. + Valid values: Deployment, CafeDeployment. + See also: kusion_models/core/v1/workload_metadata.k. + name : str, required + A Server-level attribute. + The name of the long-running service. + See also: kusion_models/core/v1/metadata.k. + labels : {str:str}, optional + A Server-level attribute. + The labels of the long-running service. + See also: kusion_models/core/v1/metadata.k. + + Examples + -------- + myCustomApp = AppConfiguration { + name = "componentName" + } + + """ + workloadType : str = "Deployment" + name: str + labels?: {str: str} + \ No newline at end of file diff --git a/kclvm/sema/src/resolver/test_data/doc.txt b/kclvm/sema/src/resolver/test_data/doc.txt new file mode 100644 index 000000000..6cf94821d --- /dev/null +++ b/kclvm/sema/src/resolver/test_data/doc.txt @@ -0,0 +1,25 @@ +""" + Server is the common user interface for long-running + services adopting the best practice of Kubernetes. + + Attributes + ---------- + workloadType : str, default is "Deployment", required + Use this attribute to specify which kind of long-running service you want. + Valid values: Deployment, CafeDeployment. + See also: kusion_models/core/v1/workload_metadata.k. + name : str, required + A Server-level attribute. + The name of the long-running service. + See also: kusion_models/core/v1/metadata.k. + labels: {str:str}, optional + A Server-level attribute. + The labels of the long-running service. + See also: kusion_models/core/v1/metadata.k. + + Examples + ---------------------- + myCustomApp = AppConfiguration { + name = "componentName" + } + """ \ No newline at end of file diff --git a/kclvm/sema/src/resolver/test_data/function_with_default_values.k b/kclvm/sema/src/resolver/test_data/function_with_default_values.k new file mode 100644 index 000000000..8d28c586b --- /dev/null +++ b/kclvm/sema/src/resolver/test_data/function_with_default_values.k @@ -0,0 +1,4 @@ +is_alpha = lambda s: str, locale: str = 'en-US', options: {str:} = {} -> bool { + False +} +a = is_alpha("c") diff --git a/kclvm/sema/src/resolver/test_data/import_test/a.k b/kclvm/sema/src/resolver/test_data/import_test/a.k new file mode 100644 index 000000000..8b6a81409 --- /dev/null +++ b/kclvm/sema/src/resolver/test_data/import_test/a.k @@ -0,0 +1,4 @@ +_a = 1 +schema Person: + name: str + age: int diff --git a/kclvm/sema/src/resolver/test_data/import_test/b.k b/kclvm/sema/src/resolver/test_data/import_test/b.k new file mode 100644 index 000000000..79fa8ccc7 --- /dev/null +++ b/kclvm/sema/src/resolver/test_data/import_test/b.k @@ -0,0 +1 @@ +_b = 1 diff --git a/kclvm/sema/src/resolver/test_data/import_test/c.k b/kclvm/sema/src/resolver/test_data/import_test/c.k new file mode 100644 index 000000000..f4832d10f --- /dev/null +++ b/kclvm/sema/src/resolver/test_data/import_test/c.k @@ -0,0 +1,2 @@ +schema TestOfMixin: + age?: int diff --git a/kclvm/sema/src/resolver/test_data/import_test/d.k b/kclvm/sema/src/resolver/test_data/import_test/d.k new file mode 100644 index 000000000..78dcd8b21 --- /dev/null +++ b/kclvm/sema/src/resolver/test_data/import_test/d.k @@ -0,0 +1,2 @@ +schema Parent: + age1?: int diff --git a/kclvm/sema/src/resolver/test_data/import_test/e.k b/kclvm/sema/src/resolver/test_data/import_test/e.k new file mode 100644 index 000000000..98fabf8f4 --- /dev/null +++ b/kclvm/sema/src/resolver/test_data/import_test/e.k @@ -0,0 +1,2 @@ +schema UnionType: + a?: int diff --git a/kclvm/sema/src/resolver/test_data/import_test/f.k b/kclvm/sema/src/resolver/test_data/import_test/f.k new file mode 100644 index 000000000..65a0fa043 --- /dev/null +++ b/kclvm/sema/src/resolver/test_data/import_test/f.k @@ -0,0 +1,2 @@ +schema UnionType: + b?: int diff --git a/kclvm/sema/src/resolver/test_data/index_signature_check.k b/kclvm/sema/src/resolver/test_data/index_signature_check.k new file mode 100644 index 000000000..a0b10414e --- /dev/null +++ b/kclvm/sema/src/resolver/test_data/index_signature_check.k @@ -0,0 +1,8 @@ +schema Template: + [...str]: int + name: str + +t: Template = { + name: "" + id: 1 +} diff --git a/kclvm/sema/src/resolver/test_data/kcl.mod b/kclvm/sema/src/resolver/test_data/kcl.mod new file mode 100644 index 000000000..c51d42cae --- /dev/null +++ b/kclvm/sema/src/resolver/test_data/kcl.mod @@ -0,0 +1,2 @@ +[package] + diff --git a/kclvm/sema/src/resolver/test_data/lint.k b/kclvm/sema/src/resolver/test_data/lint.k new file mode 100644 index 000000000..e44eb6ea8 --- /dev/null +++ b/kclvm/sema/src/resolver/test_data/lint.k @@ -0,0 +1,26 @@ +import import_test.a # UnusedImport +import import_test.a # ReImport +import regex + +schema Person: + name: str + age: int + +b1 = b._b + +import import_test.b # ImportPosition + +requires = option("params").requires or [] +# Define the validation function +validate_required_labels = lambda item, requires { + if requires: + requires_map = {r.key: r.allowedRegex or "" for r in requires} + labels = item.metadata.labels or {} + if labels: + assert all k, v in labels { + regex.match(v, requires_map[k]) if requires_map[k] + }, "must provide labels with the regex ${requires_map}" + item +} +# Validate All resource +items = [validate_required_labels(i, requires) for i in option("items")] diff --git a/kclvm/sema/src/resolver/test_data/pkg/pkg.k b/kclvm/sema/src/resolver/test_data/pkg/pkg.k new file mode 100644 index 000000000..f8c946eff --- /dev/null +++ b/kclvm/sema/src/resolver/test_data/pkg/pkg.k @@ -0,0 +1,5 @@ +schema Name: + name?: str + +schema Person: + name: Name = Name {name = "Alice"} diff --git a/kclvm/sema/src/resolver/test_data/pkg_asname/pkg/main.k b/kclvm/sema/src/resolver/test_data/pkg_asname/pkg/main.k new file mode 100644 index 000000000..156a89f90 --- /dev/null +++ b/kclvm/sema/src/resolver/test_data/pkg_asname/pkg/main.k @@ -0,0 +1,5 @@ +schema Name: + name?: str + +schema Person: + name: Name = Name {name = "Alice"} \ No newline at end of file diff --git a/kclvm/sema/src/resolver/test_data/pkg_asname/pkg/sub_pkg/main.k b/kclvm/sema/src/resolver/test_data/pkg_asname/pkg/sub_pkg/main.k new file mode 100644 index 000000000..156a89f90 --- /dev/null +++ b/kclvm/sema/src/resolver/test_data/pkg_asname/pkg/sub_pkg/main.k @@ -0,0 +1,5 @@ +schema Name: + name?: str + +schema Person: + name: Name = Name {name = "Alice"} \ No newline at end of file diff --git a/kclvm/sema/src/resolver/test_data/pkg_asname/pkg_asname.k b/kclvm/sema/src/resolver/test_data/pkg_asname/pkg_asname.k new file mode 100644 index 000000000..c32c27c3f --- /dev/null +++ b/kclvm/sema/src/resolver/test_data/pkg_asname/pkg_asname.k @@ -0,0 +1,5 @@ +import .pkg as p1 +import .pkg.sub_pkg as p2 + +p = pkg.Person{} +pp = subpkg.Person{} diff --git a/kclvm/sema/src/resolver/test_data/pkg_init_in_schema.k b/kclvm/sema/src/resolver/test_data/pkg_init_in_schema.k new file mode 100644 index 000000000..dcb1a37f3 --- /dev/null +++ b/kclvm/sema/src/resolver/test_data/pkg_init_in_schema.k @@ -0,0 +1,3 @@ +import pkg + +person = pkg.Person {} diff --git a/kclvm/sema/src/resolver/test_data/pkg_not_found_suggestion.k b/kclvm/sema/src/resolver/test_data/pkg_not_found_suggestion.k new file mode 100644 index 000000000..0655110e0 --- /dev/null +++ b/kclvm/sema/src/resolver/test_data/pkg_not_found_suggestion.k @@ -0,0 +1,3 @@ +import k9s + +a = k9s.a \ No newline at end of file diff --git a/kclvm/sema/src/resolver/test_data/pkg_scope.k b/kclvm/sema/src/resolver/test_data/pkg_scope.k new file mode 100644 index 000000000..91667ad12 --- /dev/null +++ b/kclvm/sema/src/resolver/test_data/pkg_scope.k @@ -0,0 +1,3 @@ +import pkg +schema Person1: + name: str \ No newline at end of file diff --git a/kclvm/sema/src/resolver/test_data/record_used_module.k b/kclvm/sema/src/resolver/test_data/record_used_module.k new file mode 100644 index 000000000..92c7c2442 --- /dev/null +++ b/kclvm/sema/src/resolver/test_data/record_used_module.k @@ -0,0 +1,33 @@ +import import_test.a +import import_test.b +import import_test.c +import import_test.d +import import_test.e +import import_test.f as g +import pkg +import math +import regex + +schema Main(d.Parent): + mixin [c.TestOfMixin] + name?: str + age?: int = 18 + person?: a.Person + list_union_type: [e.UnionType|int] + dict_union_type: {g.UnionType|int:float} + + check: + regex.match(name, r"[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*") if name + +if a._a > 1: + _c = 1 +elif a._a == 1: + _c = 2 +else: + _c = 3 + +p = Main{ + age = b._b +} + +person = pkg.Person {} diff --git a/kclvm/sema/src/resolver/test_data/schema_params_miss.k b/kclvm/sema/src/resolver/test_data/schema_params_miss.k new file mode 100644 index 000000000..4c8c7d387 --- /dev/null +++ b/kclvm/sema/src/resolver/test_data/schema_params_miss.k @@ -0,0 +1,6 @@ +schema D[name: str]: # '' + n: str = name + +d = D() { # expected 1 positional argument, found 0 + n = "" +} \ No newline at end of file diff --git a/kclvm/sema/src/resolver/test_data/system_package.k b/kclvm/sema/src/resolver/test_data/system_package.k new file mode 100644 index 000000000..2873bc47e --- /dev/null +++ b/kclvm/sema/src/resolver/test_data/system_package.k @@ -0,0 +1,4 @@ +import base64 + +base64_encode = base64.encode +base64_decode = base64.decode diff --git a/kclvm/sema/src/resolver/test_data/test_builtin/glob.k b/kclvm/sema/src/resolver/test_data/test_builtin/glob.k new file mode 100644 index 000000000..ca68b1a5c --- /dev/null +++ b/kclvm/sema/src/resolver/test_data/test_builtin/glob.k @@ -0,0 +1,2 @@ +import file +b = file.glob() \ No newline at end of file diff --git a/kclvm/sema/src/resolver/test_data/test_builtin/read.k b/kclvm/sema/src/resolver/test_data/test_builtin/read.k new file mode 100644 index 000000000..b8fae7ab5 --- /dev/null +++ b/kclvm/sema/src/resolver/test_data/test_builtin/read.k @@ -0,0 +1,2 @@ +import file +a = file.read() \ No newline at end of file diff --git a/kclvm/sema/src/resolver/test_data/ty_in_lambda.k b/kclvm/sema/src/resolver/test_data/ty_in_lambda.k new file mode 100644 index 000000000..4b9a1929c --- /dev/null +++ b/kclvm/sema/src/resolver/test_data/ty_in_lambda.k @@ -0,0 +1,9 @@ +_b = True +a = lambda item: {str:}, c: {str:} -> {str:str} { + result = {"aaa": "bbb"} + if _b : + result = {} + result +} + +result = {"ccc": "ddd"} diff --git a/kclvm/sema/src/resolver/test_data/undef_lambda_param.k b/kclvm/sema/src/resolver/test_data/undef_lambda_param.k new file mode 100644 index 000000000..dd2cd7f86 --- /dev/null +++ b/kclvm/sema/src/resolver/test_data/undef_lambda_param.k @@ -0,0 +1,3 @@ +lambda x: Undef { # 'Undef' is undefined + x +} \ No newline at end of file diff --git a/kclvm/sema/src/resolver/test_fail_data/attr.k b/kclvm/sema/src/resolver/test_fail_data/attr.k new file mode 100644 index 000000000..6be262743 --- /dev/null +++ b/kclvm/sema/src/resolver/test_fail_data/attr.k @@ -0,0 +1,5 @@ +schema Data: + id: int = 1 + +dataList = [{data = 1} for data in [Data {}]] +dataMap = {data = 1 for data in [Data {}]} diff --git a/kclvm/sema/src/resolver/test_fail_data/cannot_find_member_0.k b/kclvm/sema/src/resolver/test_fail_data/cannot_find_member_0.k new file mode 100644 index 000000000..48b3e40aa --- /dev/null +++ b/kclvm/sema/src/resolver/test_fail_data/cannot_find_member_0.k @@ -0,0 +1,9 @@ +schema Name: + name: [A] + +schema A: + aa: int + +n = Name { + name = [{a = 1}] +} diff --git a/kclvm/sema/src/resolver/test_fail_data/cannot_find_member_1.k b/kclvm/sema/src/resolver/test_fail_data/cannot_find_member_1.k new file mode 100644 index 000000000..0cca8aa4b --- /dev/null +++ b/kclvm/sema/src/resolver/test_fail_data/cannot_find_member_1.k @@ -0,0 +1,9 @@ +schema Name: + name: {str: A} + +schema A: + aa: int + +n = Name { + name = {a = {a = 1}} +} diff --git a/kclvm/sema/src/resolver/test_fail_data/cannot_find_module.k b/kclvm/sema/src/resolver/test_fail_data/cannot_find_module.k new file mode 100644 index 000000000..46a204396 --- /dev/null +++ b/kclvm/sema/src/resolver/test_fail_data/cannot_find_module.k @@ -0,0 +1 @@ +import non_exist_file diff --git a/kclvm/sema/src/resolver/test_fail_data/comp_clause_error_0.k b/kclvm/sema/src/resolver/test_fail_data/comp_clause_error_0.k new file mode 100644 index 000000000..26e7e558d --- /dev/null +++ b/kclvm/sema/src/resolver/test_fail_data/comp_clause_error_0.k @@ -0,0 +1 @@ +data = [i for i, j, k in [1, 2, 3]] diff --git a/kclvm/sema/src/resolver/test_fail_data/comp_clause_error_1.k b/kclvm/sema/src/resolver/test_fail_data/comp_clause_error_1.k new file mode 100644 index 000000000..26e7e558d --- /dev/null +++ b/kclvm/sema/src/resolver/test_fail_data/comp_clause_error_1.k @@ -0,0 +1 @@ +data = [i for i, j, k in [1, 2, 3]] diff --git a/kclvm/sema/src/resolver/test_fail_data/comp_clause_error_2.k b/kclvm/sema/src/resolver/test_fail_data/comp_clause_error_2.k new file mode 100644 index 000000000..ce39d5851 --- /dev/null +++ b/kclvm/sema/src/resolver/test_fail_data/comp_clause_error_2.k @@ -0,0 +1,3 @@ +data = all i.j.k in [1, 2, 3] { + i > 0 +} diff --git a/kclvm/sema/src/resolver/test_fail_data/comp_clause_error_3.k b/kclvm/sema/src/resolver/test_fail_data/comp_clause_error_3.k new file mode 100644 index 000000000..26002e49f --- /dev/null +++ b/kclvm/sema/src/resolver/test_fail_data/comp_clause_error_3.k @@ -0,0 +1 @@ +z = {**i for i in [{}, {}]} diff --git a/kclvm/sema/src/resolver/test_fail_data/comp_clause_error_4.k b/kclvm/sema/src/resolver/test_fail_data/comp_clause_error_4.k new file mode 100644 index 000000000..67687bf00 --- /dev/null +++ b/kclvm/sema/src/resolver/test_fail_data/comp_clause_error_4.k @@ -0,0 +1 @@ +z = {**i for i in [1, 2]} diff --git a/kclvm/sema/src/resolver/test_fail_data/config_expr.k b/kclvm/sema/src/resolver/test_fail_data/config_expr.k new file mode 100644 index 000000000..f7ee275ce --- /dev/null +++ b/kclvm/sema/src/resolver/test_fail_data/config_expr.k @@ -0,0 +1 @@ +data: int = {key = 1} diff --git a/kclvm/sema/src/resolver/test_fail_data/cycle_reference/file1.k b/kclvm/sema/src/resolver/test_fail_data/cycle_reference/file1.k new file mode 100644 index 000000000..62e69d62e --- /dev/null +++ b/kclvm/sema/src/resolver/test_fail_data/cycle_reference/file1.k @@ -0,0 +1,20 @@ +import .file2 + +schema SchemaBase(SchemaSub): + +schema SchemaSub(SchemaBase): + +rule RuleBase(RuleSub): + True + +rule RuleSub(RuleBase): + True + +schema A(B): + name: str + +schema B(C): + name: str + +schema C(A): + name: str diff --git a/kclvm/sema/src/resolver/test_fail_data/cycle_reference/file2.k b/kclvm/sema/src/resolver/test_fail_data/cycle_reference/file2.k new file mode 100644 index 000000000..5587df66c --- /dev/null +++ b/kclvm/sema/src/resolver/test_fail_data/cycle_reference/file2.k @@ -0,0 +1 @@ +import .file1 diff --git a/kclvm/sema/src/resolver/test_fail_data/invalid_mixin_0.k b/kclvm/sema/src/resolver/test_fail_data/invalid_mixin_0.k new file mode 100644 index 000000000..da4ab098f --- /dev/null +++ b/kclvm/sema/src/resolver/test_fail_data/invalid_mixin_0.k @@ -0,0 +1,7 @@ +schema Person: + mixin [Fullname] + firstName: str + lastName: str + +schema Fullname: # It is a mixin, but 'Fullname' is not end with 'Mixin + fullName = "{} {}".format(firstName, lastName) diff --git a/kclvm/sema/src/resolver/test_fail_data/lambda_schema_ty_0.k b/kclvm/sema/src/resolver/test_fail_data/lambda_schema_ty_0.k new file mode 100644 index 000000000..69d1097ec --- /dev/null +++ b/kclvm/sema/src/resolver/test_fail_data/lambda_schema_ty_0.k @@ -0,0 +1,11 @@ +schema ProviderFamily: + version: str + marketplace: bool = True + +providerFamily = lambda family: ProviderFamily -> ProviderFamily { + {} +} + +v = providerFamily({ + version: 1 +}) diff --git a/kclvm/sema/src/resolver/test_fail_data/lambda_schema_ty_1.k b/kclvm/sema/src/resolver/test_fail_data/lambda_schema_ty_1.k new file mode 100644 index 000000000..a1f350f7c --- /dev/null +++ b/kclvm/sema/src/resolver/test_fail_data/lambda_schema_ty_1.k @@ -0,0 +1,12 @@ +schema ProviderFamily: + version: str + marketplace: bool = True + +providerFamily = lambda family: ProviderFamily -> ProviderFamily { + {} +} + +v = providerFamily({ + version: "1.6.0" + hello: "world" +}) diff --git a/kclvm/sema/src/resolver/test_fail_data/lambda_schema_ty_2.k b/kclvm/sema/src/resolver/test_fail_data/lambda_schema_ty_2.k new file mode 100644 index 000000000..fbf135d45 --- /dev/null +++ b/kclvm/sema/src/resolver/test_fail_data/lambda_schema_ty_2.k @@ -0,0 +1,13 @@ +schema ProviderFamily: + version: str + marketplace: bool = True + +providerFamily = lambda family: ProviderFamily -> ProviderFamily { + { + version: 1 + } +} + +v = providerFamily({ + version: "1.6.0" +}) diff --git a/kclvm/sema/src/resolver/test_fail_data/lambda_schema_ty_3.k b/kclvm/sema/src/resolver/test_fail_data/lambda_schema_ty_3.k new file mode 100644 index 000000000..65da2f660 --- /dev/null +++ b/kclvm/sema/src/resolver/test_fail_data/lambda_schema_ty_3.k @@ -0,0 +1,14 @@ +schema ProviderFamily: + version: str + marketplace: bool = True + +providerFamily = lambda family: ProviderFamily -> ProviderFamily { + { + version: "1.6.0" + hello: "world" + } +} + +v = providerFamily({ + version: "1.6.0" +}) diff --git a/kclvm/sema/src/resolver/test_fail_data/lambda_ty_error.k b/kclvm/sema/src/resolver/test_fail_data/lambda_ty_error.k new file mode 100644 index 000000000..e07633419 --- /dev/null +++ b/kclvm/sema/src/resolver/test_fail_data/lambda_ty_error.k @@ -0,0 +1,6 @@ +_func = lambda x: int, y: int -> int { + x - y +} # Ok +_func = lambda x: int, y: int -> str { + str(x + y) +} # Error: expect function (int, int) -> str, got function (int, int) -> int \ No newline at end of file diff --git a/kclvm/sema/src/resolver/test_fail_data/module_optional_select.k b/kclvm/sema/src/resolver/test_fail_data/module_optional_select.k new file mode 100644 index 000000000..4d05daf61 --- /dev/null +++ b/kclvm/sema/src/resolver/test_fail_data/module_optional_select.k @@ -0,0 +1,3 @@ +import math + +a = math?.log(10) diff --git a/kclvm/sema/src/resolver/test_fail_data/mutable_error_0.k b/kclvm/sema/src/resolver/test_fail_data/mutable_error_0.k new file mode 100644 index 000000000..e83d70d94 --- /dev/null +++ b/kclvm/sema/src/resolver/test_fail_data/mutable_error_0.k @@ -0,0 +1,2 @@ +a = 1 +a = 2 diff --git a/kclvm/sema/src/resolver/test_fail_data/mutable_error_1.k b/kclvm/sema/src/resolver/test_fail_data/mutable_error_1.k new file mode 100644 index 000000000..9eb6e2c22 --- /dev/null +++ b/kclvm/sema/src/resolver/test_fail_data/mutable_error_1.k @@ -0,0 +1,2 @@ +a = 1 +a += 2 diff --git a/kclvm/sema/src/resolver/test_fail_data/not_found_suggest/main.k b/kclvm/sema/src/resolver/test_fail_data/not_found_suggest/main.k new file mode 100644 index 000000000..46fc19516 --- /dev/null +++ b/kclvm/sema/src/resolver/test_fail_data/not_found_suggest/main.k @@ -0,0 +1,3 @@ +import sub as s1 + +main = s.sub \ No newline at end of file diff --git a/kclvm/sema/src/resolver/test_fail_data/not_found_suggest/sub/main.k b/kclvm/sema/src/resolver/test_fail_data/not_found_suggest/sub/main.k new file mode 100644 index 000000000..fd778d797 --- /dev/null +++ b/kclvm/sema/src/resolver/test_fail_data/not_found_suggest/sub/main.k @@ -0,0 +1 @@ +sub = "sub" \ No newline at end of file diff --git a/kclvm/sema/src/resolver/test_fail_data/redefine_import/main.k b/kclvm/sema/src/resolver/test_fail_data/redefine_import/main.k new file mode 100644 index 000000000..2534d9819 --- /dev/null +++ b/kclvm/sema/src/resolver/test_fail_data/redefine_import/main.k @@ -0,0 +1,5 @@ +import sub as s + +import sub.sub as s + +main = s.sub_sub \ No newline at end of file diff --git a/kclvm/sema/src/resolver/test_fail_data/redefine_import/sub/main.k b/kclvm/sema/src/resolver/test_fail_data/redefine_import/sub/main.k new file mode 100644 index 000000000..fd778d797 --- /dev/null +++ b/kclvm/sema/src/resolver/test_fail_data/redefine_import/sub/main.k @@ -0,0 +1 @@ +sub = "sub" \ No newline at end of file diff --git a/kclvm/sema/src/resolver/test_fail_data/redefine_import/sub/sub/main.k b/kclvm/sema/src/resolver/test_fail_data/redefine_import/sub/sub/main.k new file mode 100644 index 000000000..7f92e0de0 --- /dev/null +++ b/kclvm/sema/src/resolver/test_fail_data/redefine_import/sub/sub/main.k @@ -0,0 +1 @@ +sub_sub = "sub_sub" \ No newline at end of file diff --git a/kclvm/sema/src/resolver/test_fail_data/unique_key_error_0.k b/kclvm/sema/src/resolver/test_fail_data/unique_key_error_0.k new file mode 100644 index 000000000..fca0dd17e --- /dev/null +++ b/kclvm/sema/src/resolver/test_fail_data/unique_key_error_0.k @@ -0,0 +1,4 @@ +a = 1 + +schema a: + id?: int diff --git a/kclvm/sema/src/resolver/test_fail_data/unique_key_error_1.k b/kclvm/sema/src/resolver/test_fail_data/unique_key_error_1.k new file mode 100644 index 000000000..1c2bc8123 --- /dev/null +++ b/kclvm/sema/src/resolver/test_fail_data/unique_key_error_1.k @@ -0,0 +1,4 @@ +a = 1 + +rule a: + True diff --git a/kclvm/sema/src/resolver/test_fail_data/unmatched_args.k b/kclvm/sema/src/resolver/test_fail_data/unmatched_args.k new file mode 100644 index 000000000..2160a0b5e --- /dev/null +++ b/kclvm/sema/src/resolver/test_fail_data/unmatched_args.k @@ -0,0 +1,12 @@ +schema Foo[a : int]: + bar? : int + +f = lambda x {} + +foo = Foo(1,2,3) +f(1,2) + +schema Foo2[a : int, b: int]: + bar? : int + +foo2 = Foo2(1,2,3) \ No newline at end of file diff --git a/kclvm/sema/src/resolver/test_fail_data/unmatched_index_sign_default_value.k b/kclvm/sema/src/resolver/test_fail_data/unmatched_index_sign_default_value.k new file mode 100644 index 000000000..98e93a0f5 --- /dev/null +++ b/kclvm/sema/src/resolver/test_fail_data/unmatched_index_sign_default_value.k @@ -0,0 +1,5 @@ +schema WithComponent: + name: str + +schema WithComponents: + [name: str]: WithComponent = 1 diff --git a/kclvm/sema/src/resolver/test_fail_data/unmatched_nest_schema_attr_0.k b/kclvm/sema/src/resolver/test_fail_data/unmatched_nest_schema_attr_0.k new file mode 100644 index 000000000..1750f4f3f --- /dev/null +++ b/kclvm/sema/src/resolver/test_fail_data/unmatched_nest_schema_attr_0.k @@ -0,0 +1,11 @@ +schema Name: + name: str + +schema Config: + n: {str:Name} + +Config { + n = { + n.n = "n" + } +} diff --git a/kclvm/sema/src/resolver/test_fail_data/unmatched_nest_schema_attr_1.k b/kclvm/sema/src/resolver/test_fail_data/unmatched_nest_schema_attr_1.k new file mode 100644 index 000000000..66f6324ba --- /dev/null +++ b/kclvm/sema/src/resolver/test_fail_data/unmatched_nest_schema_attr_1.k @@ -0,0 +1,11 @@ +schema Name: + name: str + +schema Config: + n: [Name] + +Config { + n = [{ + n = "n" + }] +} diff --git a/kclvm/sema/src/resolver/test_fail_data/unmatched_nest_schema_attr_2.k b/kclvm/sema/src/resolver/test_fail_data/unmatched_nest_schema_attr_2.k new file mode 100644 index 000000000..77ff72246 --- /dev/null +++ b/kclvm/sema/src/resolver/test_fail_data/unmatched_nest_schema_attr_2.k @@ -0,0 +1,11 @@ +schema Name: + name: str + +schema Config: + n: {str:[Name]} + +Config { + n = {n = [{ + n = "n" + }]} +} diff --git a/kclvm/sema/src/resolver/test_fail_data/unmatched_nest_schema_attr_3.k b/kclvm/sema/src/resolver/test_fail_data/unmatched_nest_schema_attr_3.k new file mode 100644 index 000000000..8b7f9eff4 --- /dev/null +++ b/kclvm/sema/src/resolver/test_fail_data/unmatched_nest_schema_attr_3.k @@ -0,0 +1,14 @@ +schema Name1: + name1: str + +schema Name2: + name2: str + +schema Config: + n: Name1 | Name2 + +Config { + n = { + n = "n" + } +} diff --git a/kclvm/sema/src/resolver/test_fail_data/unmatched_schema_attr_0.k b/kclvm/sema/src/resolver/test_fail_data/unmatched_schema_attr_0.k new file mode 100644 index 000000000..f311d3092 --- /dev/null +++ b/kclvm/sema/src/resolver/test_fail_data/unmatched_schema_attr_0.k @@ -0,0 +1,6 @@ +schema Name: + name: str + +n: {str:Name} = { + n.n = "n" +} diff --git a/kclvm/sema/src/resolver/test_fail_data/unmatched_schema_attr_1.k b/kclvm/sema/src/resolver/test_fail_data/unmatched_schema_attr_1.k new file mode 100644 index 000000000..bc80e9a91 --- /dev/null +++ b/kclvm/sema/src/resolver/test_fail_data/unmatched_schema_attr_1.k @@ -0,0 +1,6 @@ +schema Name: + name: str + +n: [Name] = [{ + n = "n" +}] diff --git a/kclvm/sema/src/resolver/test_fail_data/unmatched_schema_attr_2.k b/kclvm/sema/src/resolver/test_fail_data/unmatched_schema_attr_2.k new file mode 100644 index 000000000..6522cdd80 --- /dev/null +++ b/kclvm/sema/src/resolver/test_fail_data/unmatched_schema_attr_2.k @@ -0,0 +1,6 @@ +schema Name: + name: str + +n: {str:[Name]} = {n = [{ + n = "n" +}]} diff --git a/kclvm/sema/src/resolver/test_fail_data/unmatched_schema_attr_3.k b/kclvm/sema/src/resolver/test_fail_data/unmatched_schema_attr_3.k new file mode 100644 index 000000000..819b2751e --- /dev/null +++ b/kclvm/sema/src/resolver/test_fail_data/unmatched_schema_attr_3.k @@ -0,0 +1,9 @@ +schema Name1: + name1: str + +schema Name2: + name2: str + +n: Name1 | Name2 = { + n = "n" +} diff --git a/kclvm/sema/src/resolver/tests.rs b/kclvm/sema/src/resolver/tests.rs index 285199bef..88b3d8682 100644 --- a/kclvm/sema/src/resolver/tests.rs +++ b/kclvm/sema/src/resolver/tests.rs @@ -1,9 +1,50 @@ +use super::Options; +use super::Resolver; use crate::builtin::BUILTIN_FUNCTION_NAMES; +use crate::pre_process::pre_process_program; use crate::resolver::resolve_program; +use crate::resolver::resolve_program_with_opts; use crate::resolver::scope::*; -use crate::ty::Type; -use kclvm_parser::parse_program; -use std::rc::Rc; +use crate::ty::{Type, TypeKind}; +use anyhow::Result; +use kclvm_ast::ast; +use kclvm_ast::pos::ContainsPos; +use kclvm_ast::MAIN_PKG; +use kclvm_error::*; +use kclvm_parser::load_program; +use kclvm_parser::parse_file_force_errors; +use kclvm_parser::LoadProgramOptions; +use kclvm_parser::ParseSession; +use kclvm_utils::path::PathPrefix; +use parking_lot::lock_api::RwLock; +use std::collections::HashMap; +use std::collections::HashSet; +use std::path::Path; +use std::sync::Arc; +use std::sync::RwLock as Lock; + +pub fn parse_program(filename: &str) -> Result { + let abspath = std::fs::canonicalize(std::path::PathBuf::from(filename)).expect(filename); + + let mut prog = ast::Program { + root: abspath.parent().unwrap().adjust_canonicalization(), + pkgs: HashMap::new(), + modules: HashMap::new(), + pkgs_not_imported: HashMap::new(), + modules_not_imported: HashMap::new(), + }; + + let mut module = parse_file_force_errors(abspath.to_str().unwrap(), None)?; + module.filename = filename.to_string(); + + prog.pkgs + .insert(kclvm_ast::MAIN_PKG.to_string(), vec![filename.to_string()]); + + prog.modules + .insert(filename.to_string(), Arc::new(Lock::new(module))); + + Ok(prog) +} #[test] fn test_scope() { @@ -14,7 +55,7 @@ fn test_scope() { assert!(obj_ref.ty.is_func()); } for name in BUILTIN_FUNCTION_NAMES { - scope.set_ty(name, Rc::new(Type::ANY)); + scope.set_ty(name, Arc::new(Type::ANY)); } for name in BUILTIN_FUNCTION_NAMES { let obj = scope.lookup(name).unwrap(); @@ -34,3 +75,1026 @@ fn test_resolve_program() { assert!(main_scope.lookup("b").is_some()); assert!(main_scope.lookup("print").is_none()); } + +#[test] +fn test_resolve_program_with_cache() { + let mut program = parse_program("./src/resolver/test_data/assign.k").unwrap(); + + let scope = resolve_program_with_opts( + &mut program, + Options { + merge_program: false, + type_erasure: false, + ..Default::default() + }, + None, + ); + let cached_scope = Arc::new(RwLock::new(CachedScope::new(&scope, &program))); + let scope = resolve_program_with_opts( + &mut program, + Options { + merge_program: false, + type_erasure: false, + ..Default::default() + }, + Some(cached_scope), + ); + assert_eq!(scope.pkgpaths(), vec!["__main__".to_string()]); + let main_scope = scope.main_scope().unwrap(); + let main_scope = main_scope.borrow_mut(); + assert!(main_scope.lookup("a").is_some()); + assert!(main_scope.lookup("b").is_some()); + assert!(main_scope.lookup("print").is_none()); +} + +#[test] +fn test_pkg_init_in_schema_resolve() { + let sess = Arc::new(ParseSession::default()); + let mut program = load_program( + sess.clone(), + &["./src/resolver/test_data/pkg_init_in_schema.k"], + None, + None, + ) + .unwrap() + .program; + let scope = resolve_program(&mut program); + assert_eq!( + scope.pkgpaths(), + vec!["__main__".to_string(), "pkg".to_string()] + ); + let module = &program.pkgs["pkg"][0]; + let module = program + .get_module(&module) + .expect("Failed to acquire module lock") + .expect(&format!("module {:?} not found in program", module)); + if let ast::Stmt::Schema(schema) = &module.body[1].node { + if let ast::Stmt::SchemaAttr(attr) = &schema.body[0].node { + let value = attr.value.as_ref().unwrap(); + if let ast::Expr::Schema(schema_expr) = &value.node { + assert_eq!(schema_expr.name.node.get_names(), vec!["Name".to_string()]); + } else { + panic!("test failed, expect schema expr, got {:?}", value) + } + } else { + panic!( + "test failed, expect schema attribute, got {:?}", + schema.body[0] + ) + } + } else { + panic!( + "test failed, expect schema statement, got {:?}", + module.body[1] + ) + } +} + +#[test] +fn test_resolve_program_fail() { + let work_dir = "./src/resolver/test_fail_data/"; + let cases = &[ + "attr.k", + "cannot_find_member_0.k", + "cannot_find_member_1.k", + "cannot_find_module.k", + "comp_clause_error_0.k", + "comp_clause_error_1.k", + "comp_clause_error_2.k", + "comp_clause_error_3.k", + "comp_clause_error_4.k", + "config_expr.k", + "invalid_mixin_0.k", + "lambda_schema_ty_0.k", + "lambda_schema_ty_1.k", + "lambda_schema_ty_2.k", + "lambda_schema_ty_3.k", + "module_optional_select.k", + "mutable_error_0.k", + "mutable_error_1.k", + "unique_key_error_0.k", + "unique_key_error_1.k", + "unmatched_index_sign_default_value.k", + "unmatched_args.k", + "unmatched_nest_schema_attr_0.k", + "unmatched_nest_schema_attr_1.k", + "unmatched_nest_schema_attr_2.k", + "unmatched_nest_schema_attr_3.k", + "unmatched_schema_attr_0.k", + "unmatched_schema_attr_1.k", + "unmatched_schema_attr_2.k", + "unmatched_schema_attr_3.k", + ]; + for case in cases { + let path = Path::new(work_dir).join(case); + let mut program = parse_program(&path.to_string_lossy()).unwrap(); + let scope = resolve_program(&mut program); + assert!(scope.handler.diagnostics.len() > 0, "{}", case); + } +} + +#[test] +fn test_resolve_program_redefine() { + let sess = Arc::new(ParseSession::default()); + let mut program = load_program( + sess.clone(), + &["./src/resolver/test_fail_data/redefine_import/main.k"], + None, + None, + ) + .unwrap() + .program; + + let scope = resolve_program(&mut program); + assert_eq!(scope.handler.diagnostics.len(), 2); + let diag = &scope.handler.diagnostics[0]; + assert_eq!( + diag.code, + Some(DiagnosticId::Error(ErrorKind::CompileError)) + ); + assert_eq!(diag.messages.len(), 1); + assert_eq!( + diag.messages[0].message, + "the name 's' is defined multiple times, 's' must be defined only once" + ); +} + +#[test] +fn test_resolve_program_mismatch_type_fail() { + let mut program = parse_program("./src/resolver/test_fail_data/config_expr.k").unwrap(); + let scope = resolve_program(&mut program); + assert_eq!(scope.handler.diagnostics.len(), 1); + let diag = &scope.handler.diagnostics[0]; + assert_eq!(diag.code, Some(DiagnosticId::Error(ErrorKind::TypeError))); + assert_eq!(diag.messages.len(), 1); + assert_eq!( + diag.messages[0].message, + "expected int, got {str(key):int(1)}" + ); +} + +#[test] +fn test_resolve_program_cycle_reference_fail() { + let sess = Arc::new(ParseSession::default()); + let mut program = load_program( + sess.clone(), + &["./src/resolver/test_fail_data/cycle_reference/file2.k"], + None, + None, + ) + .unwrap() + .program; + let scope = resolve_program(&mut program); + let err_messages = [ + "There is a circular reference between modules file1, file2", + "There is a circular reference between modules file1, file2", + "There is a circular reference between schemas file1.SchemaBase, file1.SchemaSub", + "There is a circular reference between schemas file1.SchemaBase, file1.SchemaSub", + "There is a circular reference between rules file1.RuleBase, file1.RuleSub", + "There is a circular reference between rules file1.RuleBase, file1.RuleSub", + "There is a circular reference between schemas file1.A, file1.B, file1.C", + "There is a circular reference between schemas file1.A, file1.B, file1.C", + "There is a circular reference between schemas file1.A, file1.B, file1.C", + "Module 'file1' imported but unused", + "Module 'file2' imported but unused", + ]; + assert_eq!(scope.handler.diagnostics.len(), err_messages.len()); + for (diag, msg) in scope.handler.diagnostics.iter().zip(err_messages.iter()) { + assert_eq!(diag.messages[0].message, msg.to_string(),); + } +} + +#[test] +fn test_record_used_module() { + let sess = Arc::new(ParseSession::default()); + let mut program = load_program( + sess.clone(), + &["./src/resolver/test_data/record_used_module.k"], + None, + None, + ) + .unwrap() + .program; + let scope = resolve_program(&mut program); + let main_scope = scope + .scope_map + .get(kclvm_runtime::MAIN_PKG_PATH) + .unwrap() + .borrow_mut() + .clone(); + for (_, obj) in main_scope.elems { + let obj = obj.borrow_mut().clone(); + if let ScopeObjectKind::Module(m) = obj.kind { + for (_, used) in m.import_stmts { + if obj.name == "math" { + assert!(!used); + } else { + assert!(used); + } + } + } + } +} + +#[test] +fn test_resolve_program_illegal_attr_fail() { + let mut program = parse_program("./src/resolver/test_fail_data/attr.k").unwrap(); + let scope = resolve_program(&mut program); + assert_eq!(scope.handler.diagnostics.len(), 2); + let expect_err_msg = "A attribute must be string type, got 'Data'"; + let diag = &scope.handler.diagnostics[0]; + assert_eq!( + diag.code, + Some(DiagnosticId::Error(ErrorKind::IllegalAttributeError)) + ); + assert_eq!(diag.messages.len(), 1); + assert_eq!(diag.messages[0].range.0.line, 4); + assert_eq!(diag.messages[0].message, expect_err_msg,); + let diag = &scope.handler.diagnostics[1]; + assert_eq!( + diag.code, + Some(DiagnosticId::Error(ErrorKind::IllegalAttributeError)) + ); + assert_eq!(diag.messages.len(), 1); + assert_eq!(diag.messages[0].message, expect_err_msg,); + assert_eq!(diag.messages[0].range.0.line, 5); +} + +#[test] +fn test_resolve_program_unmatched_args_fail() { + let mut program = parse_program("./src/resolver/test_fail_data/unmatched_args.k").unwrap(); + let scope = resolve_program(&mut program); + assert_eq!(scope.handler.diagnostics.len(), 3); + let expect_err_msg = "\"Foo\" takes 1 positional argument but 3 were given"; + let diag = &scope.handler.diagnostics[0]; + assert_eq!( + diag.code, + Some(DiagnosticId::Error(ErrorKind::CompileError)) + ); + assert_eq!(diag.messages.len(), 1); + assert_eq!(diag.messages[0].range.0.line, 6); + assert_eq!(diag.messages[0].message, expect_err_msg); + + let expect_err_msg = "\"f\" takes 1 positional argument but 2 were given"; + let diag = &scope.handler.diagnostics[1]; + assert_eq!( + diag.code, + Some(DiagnosticId::Error(ErrorKind::CompileError)) + ); + assert_eq!(diag.messages.len(), 1); + assert_eq!(diag.messages[0].range.0.line, 7); + assert_eq!(diag.messages[0].message, expect_err_msg); + + let expect_err_msg = "\"Foo2\" takes 2 positional arguments but 3 were given"; + let diag = &scope.handler.diagnostics[2]; + assert_eq!( + diag.code, + Some(DiagnosticId::Error(ErrorKind::CompileError)) + ); + assert_eq!(diag.messages.len(), 1); + assert_eq!(diag.messages[0].range.0.line, 12); + assert_eq!(diag.messages[0].message, expect_err_msg); +} + +#[test] +fn test_resolve_program_module_optional_select_fail() { + let mut program = + parse_program("./src/resolver/test_fail_data/module_optional_select.k").unwrap(); + let scope = resolve_program(&mut program); + assert_eq!(scope.handler.diagnostics.len(), 2); + let expect_err_msg = + "For the module type, the use of '?.log' is unnecessary and it can be modified as '.log'"; + let diag = &scope.handler.diagnostics[0]; + assert_eq!( + diag.code, + Some(DiagnosticId::Error(ErrorKind::CompileError)) + ); + assert_eq!(diag.messages.len(), 1); + assert_eq!(diag.messages[0].range.0.line, 3); + assert_eq!(diag.messages[0].message, expect_err_msg); + + let expect_err_msg = "Module 'math' imported but unused"; + let diag = &scope.handler.diagnostics[1]; + assert_eq!( + diag.code, + Some(DiagnosticId::Warning(WarningKind::UnusedImportWarning)) + ); + assert_eq!(diag.messages.len(), 1); + assert_eq!(diag.messages[0].range.0.line, 1); + assert_eq!(diag.messages[0].message, expect_err_msg); +} + +#[test] +fn test_lint() { + let sess = Arc::new(ParseSession::default()); + let mut program = load_program( + sess.clone(), + &["./src/resolver/test_data/lint.k"], + None, + None, + ) + .unwrap() + .program; + let opts = Options::default(); + pre_process_program(&mut program, &opts); + let mut resolver = Resolver::new(&program, opts); + resolver.resolve_import(); + resolver.check_and_lint_all_pkgs(); + + let root = &program.root.clone(); + let filename = Path::new(&root.clone()) + .join("lint.k") + .display() + .to_string(); + let mut handler = Handler::default(); + handler.add_warning( + WarningKind::ImportPositionWarning, + &[Message { + range: ( + Position { + filename: filename.clone(), + line: 11, + column: Some(0), + }, + Position { + filename: filename.clone(), + line: 11, + column: Some(20), + }, + ), + style: Style::Line, + message: format!("The import stmt should be placed at the top of the module"), + note: Some("Consider moving tihs statement to the top of the file".to_string()), + suggested_replacement: None, + }], + ); + handler.add_warning( + WarningKind::ReimportWarning, + &[Message { + range: ( + Position { + filename: filename.clone(), + line: 2, + column: Some(0), + }, + Position { + filename: filename.clone(), + line: 2, + column: Some(20), + }, + ), + style: Style::Line, + message: format!("Module 'a' is reimported multiple times"), + note: Some("Consider removing this statement".to_string()), + suggested_replacement: None, + }], + ); + handler.add_warning( + WarningKind::UnusedImportWarning, + &[Message { + range: ( + Position { + filename: filename.clone(), + line: 1, + column: Some(0), + }, + Position { + filename: filename.clone(), + line: 1, + column: Some(20), + }, + ), + style: Style::Line, + message: format!("Module 'a' imported but unused"), + note: Some("Consider removing this statement".to_string()), + suggested_replacement: None, + }], + ); + for (d1, d2) in resolver + .linter + .handler + .diagnostics + .iter() + .zip(handler.diagnostics.iter()) + { + assert_eq!(d1, d2); + } +} + +#[test] +fn test_resolve_schema_doc() { + let mut program = parse_program("./src/resolver/test_data/doc.k").unwrap(); + let scope = resolve_program(&mut program); + let main_scope = scope + .scope_map + .get(kclvm_runtime::MAIN_PKG_PATH) + .unwrap() + .borrow_mut() + .clone(); + + let schema_scope_obj = &main_scope.elems[0].borrow().clone(); + let schema_summary = match &schema_scope_obj.ty.kind { + TypeKind::Schema(schema_ty) => schema_ty.doc.clone(), + _ => "".to_string(), + }; + + let schema_scope = &main_scope.children[0]; + let attrs_scope = &schema_scope.borrow().elems; + assert_eq!("Server is the common user interface for long-running services adopting the best practice of Kubernetes.".to_string(), schema_summary); + assert_eq!( + Some( + "Use this attribute to specify which kind of long-running service you want. +Valid values: Deployment, CafeDeployment. +See also: kusion_models/core/v1/workload_metadata.k." + .to_string() + ), + attrs_scope.get("workloadType").unwrap().borrow().doc + ); + assert_eq!( + Some( + "A Server-level attribute. +The name of the long-running service. +See also: kusion_models/core/v1/metadata.k." + .to_string() + ), + attrs_scope.get("name").unwrap().borrow().doc + ); + assert_eq!( + Some( + "A Server-level attribute. +The labels of the long-running service. +See also: kusion_models/core/v1/metadata.k." + .to_string() + ), + attrs_scope.get("labels").unwrap().borrow().doc + ); +} + +#[test] +fn test_pkg_scope() { + let sess = Arc::new(ParseSession::default()); + let mut program = load_program( + sess.clone(), + &["./src/resolver/test_data/pkg_scope.k"], + None, + None, + ) + .unwrap() + .program; + let scope = resolve_program(&mut program); + + assert_eq!(scope.scope_map.len(), 2); + let main_scope = scope + .scope_map + .get(kclvm_runtime::MAIN_PKG_PATH) + .unwrap() + .borrow_mut() + .clone(); + let pkg_scope = scope.scope_map.get("pkg").unwrap().borrow_mut().clone(); + + let root = &program.root.clone(); + let filename = Path::new(&root.clone()) + .join("pkg_scope.k") + .display() + .to_string(); + + let pos = Position { + filename: filename.clone(), + line: 2, + column: Some(0), + }; + + assert!(main_scope.contains_pos(&pos)); + + let filename = Path::new(&root.clone()) + .join("pkg") + .join("pkg.k") + .display() + .to_string(); + + let pos = Position { + filename: filename.clone(), + line: 4, + column: Some(0), + }; + + assert!(pkg_scope.contains_pos(&pos)); +} + +#[test] +fn test_system_package() { + let sess = Arc::new(ParseSession::default()); + let mut program = load_program( + sess.clone(), + &["./src/resolver/test_data/system_package.k"], + None, + None, + ) + .unwrap() + .program; + let scope = resolve_program(&mut program); + let main_scope = scope + .scope_map + .get(kclvm_runtime::MAIN_PKG_PATH) + .unwrap() + .borrow_mut() + .clone(); + + assert!(main_scope.lookup("base64").unwrap().borrow().ty.is_module()); + assert!(main_scope + .lookup("base64_encode") + .unwrap() + .borrow() + .ty + .is_func()); + assert!(main_scope + .lookup("base64_decode") + .unwrap() + .borrow() + .ty + .is_func()); +} + +#[test] +fn test_resolve_program_import_suggest() { + let sess = Arc::new(ParseSession::default()); + let mut program = load_program( + sess.clone(), + &["./src/resolver/test_fail_data/not_found_suggest/main.k"], + None, + None, + ) + .unwrap() + .program; + let scope = resolve_program(&mut program); + assert_eq!(scope.handler.diagnostics.len(), 2); + let diag = &scope.handler.diagnostics[0]; + assert_eq!( + diag.code, + Some(DiagnosticId::Error(ErrorKind::CompileError)) + ); + assert_eq!(diag.messages.len(), 1); + assert_eq!( + diag.messages[0].message, + "name 's' is not defined, did you mean '[\"s1\"]'?" + ); +} + +#[test] +fn test_resolve_assignment_in_lambda() { + let sess = Arc::new(ParseSession::default()); + let mut program = load_program( + sess.clone(), + &["./src/resolver/test_data/assign_in_lambda.k"], + None, + None, + ) + .unwrap() + .program; + let scope = resolve_program(&mut program); + let main_scope = scope.scope_map.get("__main__").unwrap().clone(); + assert_eq!(main_scope.borrow().children.len(), 1); + let lambda_scope = main_scope.borrow().children[0].clone(); + assert_eq!(lambda_scope.borrow().elems.len(), 2); + let images_scope_obj = lambda_scope.borrow().elems.get("images").unwrap().clone(); + assert_eq!(images_scope_obj.borrow().ty.ty_str(), "[str]"); +} + +#[test] +fn test_resolve_function_with_default_values() { + let sess = Arc::new(ParseSession::default()); + let mut program = load_program( + sess.clone(), + &["./src/resolver/test_data/function_with_default_values.k"], + None, + None, + ) + .unwrap() + .program; + let scope = resolve_program(&mut program); + assert!(!scope.handler.has_errors()); + let main_scope = scope.main_scope().unwrap(); + let func = main_scope.borrow().lookup("is_alpha").unwrap(); + assert!(func.borrow().ty.is_func()); + let func_ty = func.borrow().ty.into_func_type(); + assert_eq!(func_ty.params.len(), 3); + assert_eq!(func_ty.params[0].has_default, false); + assert_eq!(func_ty.params[1].has_default, true); + assert_eq!(func_ty.params[2].has_default, true); +} + +#[test] +fn test_assignment_type_annotation_check_in_lambda() { + let sess = Arc::new(ParseSession::default()); + let opts = LoadProgramOptions::default(); + let mut program = load_program( + sess.clone(), + &["./src/resolver/test_data/annotation_check_assignment.k"], + Some(opts), + None, + ) + .unwrap() + .program; + let scope = resolve_program(&mut program); + assert_eq!(scope.handler.diagnostics.len(), 0); +} + +#[test] +fn test_resolve_lambda_assignment_diagnostic() { + let sess = Arc::new(ParseSession::default()); + let mut program = load_program( + sess.clone(), + &["./src/resolver/test_fail_data/lambda_ty_error.k"], + None, + None, + ) + .unwrap() + .program; + let scope = resolve_program(&mut program); + assert_eq!(scope.handler.diagnostics.len(), 1); + let diag = &scope.handler.diagnostics[0]; + assert_eq!(diag.code, Some(DiagnosticId::Error(ErrorKind::TypeError))); + assert_eq!(diag.messages.len(), 1); + assert_eq!( + diag.messages[0].message, + "expected (int, int) -> int, got (int, int) -> str" + ); +} + +#[test] +fn test_ty_check_in_dict_assign_to_schema() { + let sess = Arc::new(ParseSession::default()); + let mut program = load_program( + sess.clone(), + &["./src/resolver/test_data/attr_ty_check.k"], + None, + None, + ) + .unwrap() + .program; + let scope = resolve_program(&mut program); + assert_eq!(scope.handler.diagnostics.len(), 2); + let diag = &scope.handler.diagnostics[0]; + assert_eq!(diag.code, Some(DiagnosticId::Error(ErrorKind::TypeError))); + assert_eq!(diag.messages.len(), 2); + assert_eq!(diag.messages[0].message, "expected int, got str(1)"); + assert_eq!( + diag.messages[1].message, + "variable is defined here, its type is int, but got str(1)" + ); +} + +#[test] +fn test_pkg_not_found_suggestion() { + let sess = Arc::new(ParseSession::default()); + let mut program = load_program( + sess.clone(), + &["./src/resolver/test_data/pkg_not_found_suggestion.k"], + None, + None, + ) + .unwrap() + .program; + let scope = resolve_program(&mut program); + assert_eq!(scope.handler.diagnostics.len(), 4); + let diag = &scope.handler.diagnostics[1]; + assert_eq!(diag.code, Some(DiagnosticId::Suggestions)); + assert_eq!(diag.messages.len(), 1); + assert_eq!( + diag.messages[0].message, + "try 'kcl mod add k9s' to download the missing package" + ); + let diag = &scope.handler.diagnostics[2]; + assert_eq!(diag.code, Some(DiagnosticId::Suggestions)); + assert_eq!(diag.messages.len(), 1); + assert_eq!( + diag.messages[0].message, + "browse more packages at 'https://artifacthub.io'" + ); +} + +#[test] +fn undef_lambda_param() { + let sess = Arc::new(ParseSession::default()); + let mut program = load_program( + sess.clone(), + &["./src/resolver/test_data/undef_lambda_param.k"], + None, + None, + ) + .unwrap() + .program; + let scope = resolve_program(&mut program); + assert_eq!(scope.handler.diagnostics.len(), 1); + + let root = &program.root.clone(); + let filename = Path::new(&root.clone()) + .join("undef_lambda_param.k") + .display() + .to_string(); + + let range = scope.handler.diagnostics[0].messages[0].range.clone(); + + assert_eq!( + range, + ( + Position { + filename: filename.clone(), + line: 1, + column: Some(10), + }, + Position { + filename: filename.clone(), + line: 1, + column: Some(15), + } + ) + ); +} + +#[test] +fn test_schema_params_count() { + let sess = Arc::new(ParseSession::default()); + let mut program = load_program( + sess.clone(), + &["./src/resolver/test_data/schema_params_miss.k"], + None, + None, + ) + .unwrap() + .program; + let scope = resolve_program(&mut program); + assert_eq!(scope.handler.diagnostics.len(), 1); + let diag = &scope.handler.diagnostics[0]; + assert_eq!( + diag.code, + Some(DiagnosticId::Error(ErrorKind::CompileError)) + ); + assert_eq!(diag.messages.len(), 1); + assert_eq!( + diag.messages[0].message, + "expected 1 positional argument, found 0" + ); +} + +#[test] +fn test_set_ty_in_lambda() { + let sess = Arc::new(ParseSession::default()); + let mut program = load_program( + sess.clone(), + &["./src/resolver/test_data/ty_in_lambda.k"], + None, + None, + ) + .unwrap() + .program; + assert_eq!( + resolve_program(&mut program) + .main_scope() + .unwrap() + .borrow() + .lookup("result") + .unwrap() + .borrow() + .ty + .clone() + .ty_str(), + "{str:str}" + ); +} + +#[test] +fn test_pkg_asname() { + let sess = Arc::new(ParseSession::default()); + let mut program = load_program( + sess.clone(), + &["./src/resolver/test_data/pkg_asname/pkg_asname.k"], + None, + None, + ) + .unwrap() + .program; + let scope = resolve_program(&mut program); + let diags = scope.handler.diagnostics; + assert_eq!(diags.len(), 4); + assert_eq!(diags[0].messages[0].message, "name 'pkg' is not defined"); + assert_eq!(diags[1].messages[0].message, "name 'subpkg' is not defined"); +} + +#[test] +fn test_builtin_file_invalid() { + let test_cases = [ + ( + "./src/resolver/test_data/test_builtin/read.k", + "expected 1 positional argument, found 0", + ), + ( + "./src/resolver/test_data/test_builtin/glob.k", + "expected 1 positional argument, found 0", + ), + ]; + + for (file, expected_message) in &test_cases { + let sess = Arc::new(ParseSession::default()); + let mut program = load_program(sess.clone(), &[file], None, None) + .unwrap() + .program; + let scope = resolve_program(&mut program); + let diags = scope.handler.diagnostics; + assert_eq!(diags.len(), 1); + assert_eq!(diags[0].messages[0].message, *expected_message); + } +} + +#[test] +fn test_schema_index_signature_check() { + let sess = Arc::new(ParseSession::default()); + let mut program = load_program( + sess.clone(), + &["./src/resolver/test_data/index_signature_check.k"], + None, + None, + ) + .unwrap() + .program; + let scope = resolve_program(&mut program); + let diags = scope.handler.diagnostics; + assert!(diags.is_empty()) +} + +#[test] +fn test_clear_cache_by_module() { + let sess = Arc::new(ParseSession::default()); + let mut program = load_program( + sess.clone(), + &["./src/resolver/test_data/cache/main.k"], + None, + None, + ) + .unwrap() + .program; + + let scope = resolve_program_with_opts( + &mut program, + Options { + merge_program: false, + type_erasure: false, + ..Default::default() + }, + None, + ); + let cached_scope = Arc::new(RwLock::new(CachedScope::new(&scope, &program))); + // first compile + let _ = resolve_program_with_opts( + &mut program, + Options { + merge_program: false, + type_erasure: false, + ..Default::default() + }, + Some(cached_scope.clone()), + ); + + // recompile and clear cache + let invalidate_module = std::fs::canonicalize(std::path::PathBuf::from( + "./src/resolver/test_data/cache/main.k", + )) + .unwrap() + .to_str() + .unwrap() + .to_string() + .adjust_canonicalization(); + + if let Some(mut cached_scope) = cached_scope.try_write() { + let mut invalidate_pkg_modules = HashSet::new(); + invalidate_pkg_modules.insert(invalidate_module); + cached_scope.invalidate_pkg_modules = Some(invalidate_pkg_modules); + }; + + let _ = resolve_program_with_opts( + &mut program, + Options { + merge_program: false, + type_erasure: false, + ..Default::default() + }, + Some(cached_scope.clone()), + ); + if let Some(cached_scope) = cached_scope.try_write() { + // main - a + // - b - c + // invalidate main, invalidate_pkgs main + let mut expect = HashSet::new(); + expect.insert(MAIN_PKG.to_string()); + assert_eq!(cached_scope.invalidate_pkgs, expect); + }; + + // recompile and clear cache + let invalidate_module = std::fs::canonicalize(std::path::PathBuf::from( + "./src/resolver/test_data/cache/a/a.k", + )) + .unwrap() + .to_str() + .unwrap() + .to_string() + .adjust_canonicalization(); + + if let Some(mut cached_scope) = cached_scope.try_write() { + let mut invalidate_pkg_modules = HashSet::new(); + invalidate_pkg_modules.insert(invalidate_module); + cached_scope.invalidate_pkg_modules = Some(invalidate_pkg_modules); + }; + + let _ = resolve_program_with_opts( + &mut program, + Options { + merge_program: false, + type_erasure: false, + ..Default::default() + }, + Some(cached_scope.clone()), + ); + + if let Some(cached_scope) = cached_scope.try_write() { + // main - a + // - b - c + // invalidate a, invalidate_pkgs a, main + let mut expect = HashSet::new(); + expect.insert(MAIN_PKG.to_string()); + expect.insert("cache.a".to_string()); + assert_eq!(cached_scope.invalidate_pkgs, expect); + }; + + // recompile and clear cache + let invalidate_module = std::fs::canonicalize(std::path::PathBuf::from( + "./src/resolver/test_data/cache/b/b.k", + )) + .unwrap() + .to_str() + .unwrap() + .to_string() + .adjust_canonicalization(); + + if let Some(mut cached_scope) = cached_scope.try_write() { + let mut invalidate_pkg_modules = HashSet::new(); + invalidate_pkg_modules.insert(invalidate_module); + cached_scope.invalidate_pkg_modules = Some(invalidate_pkg_modules); + }; + + let _ = resolve_program_with_opts( + &mut program, + Options { + merge_program: false, + type_erasure: false, + ..Default::default() + }, + Some(cached_scope.clone()), + ); + + if let Some(cached_scope) = cached_scope.try_write() { + // main - a + // - b - c + // invalidate b, invalidate_pkgs b, main + let mut expect = HashSet::new(); + expect.insert(MAIN_PKG.to_string()); + expect.insert("cache.b".to_string()); + assert_eq!(cached_scope.invalidate_pkgs, expect); + }; + + // recompile and clear cache + let invalidate_module = std::fs::canonicalize(std::path::PathBuf::from( + "./src/resolver/test_data/cache/c/c.k", + )) + .unwrap() + .to_str() + .unwrap() + .to_string() + .adjust_canonicalization(); + + if let Some(mut cached_scope) = cached_scope.try_write() { + let mut invalidate_pkg_modules = HashSet::new(); + invalidate_pkg_modules.insert(invalidate_module); + cached_scope.invalidate_pkg_modules = Some(invalidate_pkg_modules); + }; + + let _ = resolve_program_with_opts( + &mut program, + Options { + merge_program: false, + type_erasure: false, + ..Default::default() + }, + Some(cached_scope.clone()), + ); + + if let Some(cached_scope) = cached_scope.try_write() { + // main - a + // - b - c + // invalidate c, invalidate_pkgs c, b, main + let mut expect = HashSet::new(); + expect.insert(MAIN_PKG.to_string()); + expect.insert("cache.b".to_string()); + expect.insert("cache.c".to_string()); + assert_eq!(cached_scope.invalidate_pkgs, expect); + }; +} diff --git a/kclvm/sema/src/resolver/ty.rs b/kclvm/sema/src/resolver/ty.rs index 1a249dc00..9aef61371 100644 --- a/kclvm/sema/src/resolver/ty.rs +++ b/kclvm/sema/src/resolver/ty.rs @@ -1,15 +1,17 @@ -use std::rc::Rc; +use std::sync::Arc; -use crate::resolver::pos::GetPos; +use super::node::ResolvedResult; use crate::resolver::Resolver; use crate::ty::parser::parse_type_str; -use crate::ty::{assignable_to, SchemaType, Type, TypeKind}; +use crate::ty::{ + assignable_to, is_upper_bound, Attr, DictType, Parameter, SchemaType, Type, TypeKind, TypeRef, +}; use indexmap::IndexMap; use kclvm_ast::ast; +use kclvm_ast::pos::GetPos; +use kclvm_error::diagnostic::Range; use kclvm_error::*; -use super::node::ResolvedResult; - fn ty_str_to_pkgpath(ty_str: &str) -> &str { let splits: Vec<&str> = ty_str.rsplitn(2, '.').collect(); let len = splits.len(); @@ -25,164 +27,469 @@ pub fn ty_str_replace_pkgpath(ty_str: &str, pkgpath: &str) -> String { } } -impl<'ctx> Resolver<'ctx> { +impl<'ctx> Resolver<'_> { #[inline] - pub fn any_ty(&self) -> Rc { + pub fn any_ty(&self) -> TypeRef { self.ctx.ty_ctx.builtin_types.any.clone() } #[inline] - pub fn int_ty(&self) -> Rc { + pub fn int_ty(&self) -> TypeRef { self.ctx.ty_ctx.builtin_types.int.clone() } #[inline] - pub fn float_ty(&self) -> Rc { + pub fn float_ty(&self) -> TypeRef { self.ctx.ty_ctx.builtin_types.float.clone() } #[inline] - pub fn bool_ty(&self) -> Rc { + pub fn bool_ty(&self) -> TypeRef { self.ctx.ty_ctx.builtin_types.bool.clone() } #[inline] - pub fn str_ty(&self) -> Rc { + pub fn str_ty(&self) -> TypeRef { self.ctx.ty_ctx.builtin_types.str.clone() } #[inline] - pub fn none_ty(&self) -> Rc { + pub fn none_ty(&self) -> TypeRef { self.ctx.ty_ctx.builtin_types.none.clone() } #[inline] - pub fn void_ty(&self) -> Rc { + pub fn void_ty(&self) -> TypeRef { self.ctx.ty_ctx.builtin_types.void.clone() } /// Parse the type string with the scope, if parse_ty returns a Named type(schema type or type alias), /// found it from the scope. - pub fn parse_ty_with_scope(&mut self, ty: &ast::Type, pos: Position) -> ResolvedResult { - let ty: Rc = Rc::new(ty.clone().into()); + pub fn parse_ty_with_scope( + &mut self, + ty_node: Option<&ast::Node>, + range: Range, + ) -> ResolvedResult { + let ty: TypeRef = if let Some(ty) = ty_node { + Arc::new(ty.node.clone().into()) + } else { + Arc::new(Type::ANY) + }; // If a named type, find it from scope to get the specific type - let ret_ty = self.upgrade_named_ty_with_scope(ty.clone(), &pos); + let ret_ty = self.upgrade_named_ty_with_scope(ty.clone(), &range, ty_node); self.add_type_alias( &ty.into_type_annotation_str(), &ret_ty.into_type_annotation_str(), ); + if let Some(ty) = ty_node { + self.node_ty_map + .borrow_mut() + .insert(self.get_node_key(ty.id.clone()), ret_ty.clone()); + }; ret_ty } - pub fn parse_ty_str_with_scope(&mut self, ty_str: &str, pos: Position) -> ResolvedResult { - let ty: Rc = parse_type_str(ty_str); + pub fn parse_ty_str_with_scope(&mut self, ty_str: &str, range: Range) -> ResolvedResult { + let ty: TypeRef = parse_type_str(ty_str); // If a named type, find it from scope to get the specific type - let ret_ty = self.upgrade_named_ty_with_scope(ty, &pos); + let ret_ty = self.upgrade_named_ty_with_scope(ty, &range, None); self.add_type_alias(ty_str, &ret_ty.into_type_annotation_str()); ret_ty } /// The given expression must be the expected type. #[inline] - pub fn must_be_type(&mut self, expr: &'ctx ast::NodeRef, expected_ty: Rc) { + pub fn must_be_type(&mut self, expr: &'ctx ast::NodeRef, expected_ty: TypeRef) { let ty = self.expr(expr); - self.must_assignable_to(ty, expected_ty, expr.get_pos(), None); + self.must_assignable_to(ty, expected_ty, expr.get_span_pos(), None); } /// Must assignable to the expected type. #[inline] pub fn must_assignable_to( &mut self, - ty: Rc, - expected_ty: Rc, - pos: Position, - expected_pos: Option, + ty: TypeRef, + expected_ty: TypeRef, + range: Range, + def_range: Option, ) { - if !self.check_type(ty.clone(), expected_ty.clone(), &pos) { + self.attr_must_assignable_to(ty, expected_ty, range, def_range, None); + } + + /// Attribute must assignable to the expected type. + pub fn attr_must_assignable_to( + &mut self, + ty: TypeRef, + expected_ty: TypeRef, + range: Range, + def_range: Option, + attr_range: Option, + ) { + if !self.check_type(ty.clone(), expected_ty.clone(), &range) { let mut msgs = vec![Message { - pos, + range, style: Style::LineAndColumn, - message: format!("expect {}, got {}", expected_ty.ty_str(), ty.ty_str(),), + message: format!("expected {}, got {}", expected_ty.ty_str(), ty.ty_str(),), note: None, + suggested_replacement: None, }]; - if let Some(expected_pos) = expected_pos { + if let Some(def_range) = def_range { + // If the range is not a dummy range, append the definition error message + // in the diagnostic. + if !def_range.0.filename.is_empty() && !def_range.1.filename.is_empty() { + msgs.push(Message { + range: def_range, + style: Style::LineAndColumn, + message: format!( + "variable is defined here, its type is {}, but got {}", + expected_ty.ty_str(), + ty.ty_str(), + ), + note: None, + suggested_replacement: None, + }); + } + } + if let Some(attr_range) = attr_range { msgs.push(Message { - pos: expected_pos, + range: attr_range.clone(), style: Style::LineAndColumn, - message: format!( - "variable is defined here, its type is {}, but got {}", - expected_ty.ty_str(), - ty.ty_str(), - ), + message: "config attribute is defined here".to_string(), note: None, + suggested_replacement: None, }); } self.handler.add_error(ErrorKind::TypeError, &msgs); } } + // Upgrade the dict type into schema type if it is expected to schema + pub(crate) fn upgrade_dict_to_schema(&mut self, ty: TypeRef, expected_ty: TypeRef) -> TypeRef { + match (&ty.kind, &expected_ty.kind) { + (TypeKind::Dict(dict_ty), TypeKind::Schema(schema_ty)) => { + if self.upgrade_dict_to_schema_attr_check(dict_ty, schema_ty) { + expected_ty + } else { + ty + } + } + (TypeKind::List(item_ty), TypeKind::List(expected_item_ty)) => { + Type::list(self.upgrade_dict_to_schema(item_ty.clone(), expected_item_ty.clone())) + .into() + } + ( + TypeKind::Dict(DictType { key_ty, val_ty, .. }), + TypeKind::Dict(DictType { + key_ty: expected_key_ty, + val_ty: expected_val_ty, + .. + }), + ) => Type::dict( + self.upgrade_dict_to_schema(key_ty.clone(), expected_key_ty.clone()), + self.upgrade_dict_to_schema(val_ty.clone(), expected_val_ty.clone()), + ) + .into(), + (TypeKind::Dict(dict_ty), TypeKind::Union(expected_union_type)) => { + let types: Vec> = expected_union_type + .iter() + .filter(|ty| match ty.kind { + TypeKind::Schema(_) => true, + _ => false, + }) + .filter(|ty| { + self.upgrade_dict_to_schema_attr_check(dict_ty, &ty.into_schema_type()) + }) + .map(|ty| ty.clone()) + .collect(); + crate::ty::sup(&types).into() + } + _ => ty, + } + } + + /// Check the type assignment statement between type annotation and target. + pub fn check_assignment_type_annotation( + &mut self, + assign_stmt: &kclvm_ast::ast::AssignStmt, + value_ty: TypeRef, + ) { + if assign_stmt.ty.is_none() { + return; + } + for target in &assign_stmt.targets { + let name = &target.node.name.node; + // If the assignment statement has type annotation, check the type of value and the type annotation of target + + if let Some(ty_annotation) = &assign_stmt.ty { + let annotation_ty = + self.parse_ty_with_scope(Some(&ty_annotation), ty_annotation.get_span_pos()); + // If the target defined in the scope, check the type of value and the type annotation of target + let target_ty = if let Some(obj) = self.scope.borrow().elems.get(name) { + let obj = obj.borrow(); + if obj.ty.is_any() { + annotation_ty + } else { + if !is_upper_bound(annotation_ty.clone(), obj.ty.clone()) { + self.handler.add_error( + ErrorKind::TypeError, + &[ + Message { + range: target.get_span_pos(), + style: Style::LineAndColumn, + message: format!( + "can not change the type of '{}' to {}", + name, + annotation_ty.ty_str() + ), + note: None, + suggested_replacement: None, + }, + Message { + range: obj.get_span_pos(), + style: Style::LineAndColumn, + message: format!("expected {}", obj.ty.ty_str()), + note: None, + suggested_replacement: None, + }, + ], + ); + } + obj.ty.clone() + } + } else { + annotation_ty + }; + + self.set_type_to_scope(name, target_ty.clone(), &target.node.name); + + // Check the type of value and the type annotation of target + self.must_assignable_to(value_ty.clone(), target_ty, target.get_span_pos(), None) + } + } + } + /// The check type main function, returns a boolean result. #[inline] - pub fn check_type(&mut self, ty: Rc, expected_ty: Rc, pos: &Position) -> bool { + pub fn check_type(&mut self, ty: TypeRef, expected_ty: TypeRef, range: &Range) -> bool { + // Check assignable between types. match (&ty.kind, &expected_ty.kind) { (TypeKind::List(item_ty), TypeKind::List(expected_item_ty)) => { - self.check_type(item_ty.clone(), expected_item_ty.clone(), pos) + self.check_type(item_ty.clone(), expected_item_ty.clone(), range) } - (TypeKind::Dict(key_ty, val_ty), TypeKind::Dict(expected_key_ty, expected_val_ty)) => { - self.check_type(key_ty.clone(), expected_key_ty.clone(), pos) - && self.check_type(val_ty.clone(), expected_val_ty.clone(), pos) + ( + TypeKind::Dict(DictType { key_ty, val_ty, .. }), + TypeKind::Dict(DictType { + key_ty: expected_key_ty, + val_ty: expected_val_ty, + .. + }), + ) => { + self.check_type(key_ty.clone(), expected_key_ty.clone(), range) + && self.check_type(val_ty.clone(), expected_val_ty.clone(), range) } - (TypeKind::Dict(key_ty, val_ty), TypeKind::Schema(schema_ty)) => { - self.dict_assignable_to_schema(key_ty.clone(), val_ty.clone(), schema_ty, pos) + (TypeKind::Dict(dict_ty), TypeKind::Schema(schema_ty)) => { + self.dict_assignable_to_schema(dict_ty, schema_ty, range) } (TypeKind::Union(types), _) => types .iter() - .all(|ty| self.check_type(ty.clone(), expected_ty.clone(), pos)), + .all(|ty| self.check_type(ty.clone(), expected_ty.clone(), range)), (_, TypeKind::Union(types)) => types .iter() - .any(|expected_ty| self.check_type(ty.clone(), expected_ty.clone(), pos)), + .any(|expected_ty| self.check_type(ty.clone(), expected_ty.clone(), range)), _ => assignable_to(ty, expected_ty), } } /// Judge a dict can be converted to schema in compile time /// Do relaxed schema check key and value type check. - pub fn dict_assignable_to_schema( + pub(crate) fn dict_assignable_to_schema( &mut self, - key_ty: Rc, - val_ty: Rc, + dict_ty: &DictType, schema_ty: &SchemaType, - pos: &Position, + range: &Range, ) -> bool { + let (key_ty, val_ty) = (dict_ty.key_ty.clone(), dict_ty.val_ty.clone()); if let Some(index_signature) = &schema_ty.index_signature { - if !assignable_to(val_ty.clone(), index_signature.val_ty.clone()) { - self.handler.add_type_error( - &format!( - "expected schema index signature value type {}, got {}", - index_signature.val_ty.ty_str(), - val_ty.ty_str() - ), - pos.clone(), - ); - } - if index_signature.any_other { - return assignable_to(key_ty, index_signature.key_ty.clone()) - && assignable_to(val_ty, index_signature.val_ty.clone()); + let val_ty = match (&key_ty.kind, &val_ty.kind) { + (TypeKind::Union(key_tys), TypeKind::Union(val_tys)) => { + let mut index_signature_val_tys: Vec = vec![]; + for (i, key_ty) in key_tys.iter().enumerate() { + if let TypeKind::StrLit(s) = &key_ty.kind { + if schema_ty.attrs.get(s).is_none() && val_tys.get(i).is_some() { + index_signature_val_tys.push(val_tys.get(i).unwrap().clone()); + } + } + } + crate::ty::sup(&index_signature_val_tys).into() + } + _ => val_ty, + }; + if dict_ty.attrs.is_empty() { + if !self.check_type(val_ty.clone(), index_signature.val_ty.clone(), range) { + self.handler.add_type_error( + &format!( + "expected schema index signature value type {}, got {}", + index_signature.val_ty.ty_str(), + val_ty.ty_str() + ), + range.clone(), + ); + } + } else { + for (name, attr) in &dict_ty.attrs { + if index_signature.any_other { + if let Some(attr_obj) = schema_ty.attrs.get(name) { + self.must_assignable_to( + attr.ty.clone(), + attr_obj.ty.clone(), + range.clone(), + Some(attr_obj.range.clone()), + ); + } else { + self.must_assignable_to( + attr.ty.clone(), + index_signature.val_ty.clone(), + attr.range.clone(), + None, + ); + } + } else { + self.must_assignable_to( + attr.ty.clone(), + index_signature.val_ty.clone(), + attr.range.clone(), + None, + ); + } + } } true } else { + // When assigning a dict type to an instance of a schema type, + // check whether the type of key value pair in dict matches the attribute type in the schema. + if let TypeKind::StrLit(key_name) = &key_ty.kind { + if let Some(attr_obj) = schema_ty.attrs.get(key_name) { + if let Some(attr) = dict_ty.attrs.get(key_name) { + self.must_assignable_to( + attr.ty.clone(), + attr_obj.ty.clone(), + range.clone(), + Some(attr_obj.range.clone()), + ); + } + return true; + } + } true } } - fn upgrade_named_ty_with_scope(&mut self, ty: Rc, pos: &Position) -> ResolvedResult { + /// Judge a dict can be upgrade to schema. + /// More strict than `dict_assign_to_schema()`: schema attr contains all attributes in key + pub fn upgrade_dict_to_schema_attr_check( + &mut self, + dict_ty: &DictType, + schema_ty: &SchemaType, + ) -> bool { + if schema_ty.index_signature.is_some() { + return true; + } + match &dict_ty.key_ty.kind { + // empty dict {} + TypeKind::Any => true, + // single key: {key1: value1} + TypeKind::StrLit(s) => schema_ty.attrs.len() >= 1 && schema_ty.attrs.contains_key(s), + // multi key: { + // key1: value1 + // key2: value2 + // ... + // } + TypeKind::Union(types) => { + let (attrs, has_index_signature) = Self::get_schema_attrs(schema_ty); + match (attrs.len() >= types.len(), has_index_signature) { + (true, _) => types.iter().all(|ty| match &ty.kind { + TypeKind::StrLit(s) => attrs.contains(s), + _ => false, + }), + // TODO: do more index_signature check with dict type attrs + (false, true) => true, + (false, false) => false, + } + } + _ => false, + } + } + + fn get_schema_attrs(schema_ty: &SchemaType) -> (Vec, bool) { + let mut attrs: Vec = schema_ty.attrs.keys().map(|attr| attr.clone()).collect(); + let mut has_index_signature = schema_ty.index_signature.is_some(); + if let Some(base) = &schema_ty.base { + let (base_attrs, index_signature) = Self::get_schema_attrs(base); + attrs.extend(base_attrs); + has_index_signature &= index_signature; + } + (attrs, has_index_signature) + } + + fn upgrade_named_ty_with_scope( + &mut self, + ty: TypeRef, + range: &Range, + ty_node: Option<&ast::Node>, + ) -> ResolvedResult { match &ty.kind { TypeKind::List(item_ty) => { - Type::list_ref(self.upgrade_named_ty_with_scope(item_ty.clone(), pos)) + let mut inner_node = None; + if let Some(ty_node) = ty_node { + if let ast::Type::List(list_type) = &ty_node.node { + inner_node = list_type.inner_type.as_ref().map(|ty| ty.as_ref()) + } + }; + Type::list_ref(self.upgrade_named_ty_with_scope(item_ty.clone(), range, inner_node)) + } + TypeKind::Dict(DictType { + key_ty, + val_ty, + attrs, + }) => { + let mut key_node = None; + let mut value_node = None; + if let Some(ty_node) = ty_node { + if let ast::Type::Dict(dict_type) = &ty_node.node { + key_node = dict_type.key_type.as_ref().map(|ty| ty.as_ref()); + value_node = dict_type.value_type.as_ref().map(|ty| ty.as_ref()); + } + }; + Type::dict_ref_with_attrs( + self.upgrade_named_ty_with_scope(key_ty.clone(), range, key_node), + self.upgrade_named_ty_with_scope(val_ty.clone(), range, value_node), + attrs + .into_iter() + .map(|(key, attr)| { + ( + key.to_string(), + Attr { + ty: self.upgrade_named_ty_with_scope( + val_ty.clone(), + range, + None, + ), + range: attr.range.clone(), + }, + ) + }) + .collect(), + ) } - TypeKind::Dict(key_ty, val_ty) => Type::dict_ref( - self.upgrade_named_ty_with_scope(key_ty.clone(), pos), - self.upgrade_named_ty_with_scope(val_ty.clone(), pos), - ), TypeKind::Union(types) => Type::union_ref( &types .iter() - .map(|ty| self.upgrade_named_ty_with_scope(ty.clone(), pos)) - .collect::>>(), + .enumerate() + .map(|(index, ty)| { + let mut elem_node = None; + if let Some(ty_node) = ty_node { + if let ast::Type::Union(union_type) = &ty_node.node { + elem_node = + union_type.type_elements.get(index).map(|ty| ty.as_ref()) + } + }; + self.upgrade_named_ty_with_scope(ty.clone(), range, elem_node) + }) + .collect::>(), ), TypeKind::Named(ty_str) => { let ty_str = ty_str_replace_pkgpath(ty_str, &self.ctx.pkgpath); @@ -192,6 +499,11 @@ impl<'ctx> Resolver<'ctx> { } else { ty_str.split('.').collect() }; + if names.is_empty() { + self.handler + .add_compile_error("missing type annotation", range.clone()); + return self.any_ty(); + } let mut pkgpath = "".to_string(); let name = names[0]; if names.len() > 1 && !self.ctx.local_vars.contains(&name.to_string()) { @@ -202,11 +514,69 @@ impl<'ctx> Resolver<'ctx> { } } self.ctx.l_value = false; - self.resolve_var( + let tys = self.resolve_var( &names.iter().map(|n| n.to_string()).collect::>(), &pkgpath, - pos.clone(), - ) + range.clone(), + ); + + if let Some(ty_node) = ty_node { + if let ast::Type::Named(identifier) = &ty_node.node { + for (index, name) in identifier.names.iter().enumerate() { + self.node_ty_map + .borrow_mut() + .insert(self.get_node_key(name.id.clone()), tys[index].clone()); + } + let ident_ty = tys.last().unwrap().clone(); + self.node_ty_map + .borrow_mut() + .insert(self.get_node_key(ty_node.id.clone()), ident_ty.clone()); + } + }; + tys.last().unwrap().clone() + } + TypeKind::Function(fn_ty) => { + // Replace the type 'Named' to the real type in function params and return type + let mut params_ty = vec![]; + let mut ret_ty = Type::any_ref(); + if let Some(ty_node) = ty_node { + if let ast::Type::Function(fn_ast_type) = &ty_node.node { + if let Some(params_ast_ty) = fn_ast_type.params_ty.as_ref() { + for (ast_ty, ty) in params_ast_ty.iter().zip(fn_ty.params.iter()) { + params_ty.push(Parameter { + name: ty.name.clone(), + ty: self.upgrade_named_ty_with_scope( + ty.ty.clone(), + range, + Some(ast_ty.as_ref()), + ), + has_default: ty.has_default, + default_value: ty.default_value.clone(), + range: ty_node.get_span_pos(), + }); + } + } + + ret_ty = if let Some(ret_ast_ty) = fn_ast_type.ret_ty.as_ref() { + self.upgrade_named_ty_with_scope( + fn_ty.return_ty.clone(), + range, + Some(ret_ast_ty.as_ref()), + ) + } else { + Type::any_ref() + }; + } + }; + + Arc::new(Type::function( + fn_ty.self_ty.clone(), + ret_ty, + params_ty.as_slice(), + &fn_ty.doc, + fn_ty.is_variadic, + fn_ty.kw_only_index, + )) } _ => ty.clone(), } diff --git a/kclvm/sema/src/resolver/ty_alias.rs b/kclvm/sema/src/resolver/ty_alias.rs index 5d4f76a2d..4f5017c6c 100644 --- a/kclvm/sema/src/resolver/ty_alias.rs +++ b/kclvm/sema/src/resolver/ty_alias.rs @@ -1,9 +1,11 @@ use indexmap::IndexMap; +use kclvm_ast::ast::Node; use kclvm_ast::walker::MutSelfMutWalker; use kclvm_ast::{ast, walk_if_mut, walk_list_mut}; #[derive(Default)] struct TypeAliasTransformer { + pub pkgpath: String, pub type_alias_mapping: IndexMap, } @@ -23,15 +25,15 @@ impl<'ctx> MutSelfMutWalker<'ctx> for TypeAliasTransformer { let value = &mut schema_index_signature.node.value; if let Some(type_alias) = self .type_alias_mapping - .get(&schema_index_signature.node.key_type.node) + .get(&schema_index_signature.node.key_ty.node.to_string()) { - schema_index_signature.node.key_type.node = type_alias.clone(); + schema_index_signature.node.key_ty.node = type_alias.clone().into(); } if let Some(type_alias) = self .type_alias_mapping - .get(&schema_index_signature.node.value_type.node) + .get(&schema_index_signature.node.value_ty.node.to_string()) { - schema_index_signature.node.value_type.node = type_alias.clone(); + schema_index_signature.node.value_ty.node = type_alias.clone().into(); } walk_if_mut!(self, walk_expr, value); } @@ -42,15 +44,18 @@ impl<'ctx> MutSelfMutWalker<'ctx> for TypeAliasTransformer { } fn walk_schema_attr(&mut self, schema_attr: &'ctx mut ast::SchemaAttr) { // walk_list_mut!(self, walk_call_expr, schema_attr.decorators); - if let Some(type_alias) = self.type_alias_mapping.get(&schema_attr.type_str.node) { - schema_attr.type_str.node = type_alias.clone(); + if let Some(type_alias) = self + .type_alias_mapping + .get(&schema_attr.ty.node.to_string()) + { + schema_attr.ty.node = type_alias.clone().into(); } walk_if_mut!(self, walk_expr, schema_attr.value); } fn walk_assign_stmt(&mut self, assign_stmt: &'ctx mut ast::AssignStmt) { - if let Some(ty_str) = &mut assign_stmt.type_annotation { - if let Some(type_alias) = self.type_alias_mapping.get(&ty_str.node) { - ty_str.node = type_alias.clone(); + if let Some(ty) = &mut assign_stmt.ty { + if let Some(type_alias) = self.type_alias_mapping.get(&ty.node.to_string()) { + ty.node = type_alias.clone().into(); } } self.walk_expr(&mut assign_stmt.value.node); @@ -62,17 +67,20 @@ impl<'ctx> MutSelfMutWalker<'ctx> for TypeAliasTransformer { fn walk_lambda_expr(&mut self, lambda_expr: &'ctx mut ast::LambdaExpr) { walk_if_mut!(self, walk_arguments, lambda_expr.args); walk_list_mut!(self, walk_stmt, lambda_expr.body); - if let Some(ty_str) = &mut lambda_expr.return_type_str { - if let Some(type_alias) = self.type_alias_mapping.get(ty_str) { - *ty_str = type_alias.clone(); + if let Some(ty) = &mut lambda_expr.return_ty { + if let Some(type_alias) = self.type_alias_mapping.get(&ty.node.to_string()) { + ty.node = type_alias.clone().into(); } } } fn walk_arguments(&mut self, arguments: &'ctx mut ast::Arguments) { walk_list_mut!(self, walk_identifier, arguments.args); - for type_annotation in (&mut arguments.type_annotation_list.iter_mut()).flatten() { - if let Some(type_alias) = self.type_alias_mapping.get(&type_annotation.node) { - type_annotation.node = type_alias.clone(); + for type_annotation in (&mut arguments.ty_list.iter_mut()).flatten() { + if let Some(type_alias) = self + .type_alias_mapping + .get(&type_annotation.node.to_string()) + { + type_annotation.node = type_alias.clone().into(); } } for default in arguments.defaults.iter_mut() { @@ -83,13 +91,38 @@ impl<'ctx> MutSelfMutWalker<'ctx> for TypeAliasTransformer { } fn walk_identifier(&mut self, identifier: &'ctx mut ast::Identifier) { if let Some(type_alias) = self.type_alias_mapping.get(&identifier.get_name()) { - if type_alias.starts_with('@') { + if type_alias.starts_with('@') && type_alias.contains('.') { let splits: Vec<&str> = type_alias.rsplitn(2, '.').collect(); - identifier.pkgpath = splits[1].to_string(); - identifier.names = vec![splits[1].to_string(), splits[0].to_string()]; + let pkgpath = splits[1].to_string(); + // Do not replace package identifier name in the same package. + // For example, the following code: + // + // ``` + // schema Name: + // name: str + // schema Person: + // name: Name + // ``` + if self.pkgpath != &pkgpath[1..] { + identifier.pkgpath = pkgpath; + let mut first_node = identifier.names[0].clone(); + first_node.node = splits[1].to_string(); + let mut second_node = identifier.names[0].clone(); + second_node.node = splits[0].to_string(); + identifier.names = vec![first_node, second_node]; + } } else { let names = type_alias.split('.').collect::>(); - identifier.names = names.iter().map(|n| n.to_string()).collect(); + let new_names: Vec> = names + .iter() + .zip(&identifier.names) + .map(|(name, pos_name)| { + let mut new_name = pos_name.clone(); + new_name.node = name.to_string(); + new_name.clone() + }) + .collect(); + identifier.names = new_names; } } } @@ -97,22 +130,30 @@ impl<'ctx> MutSelfMutWalker<'ctx> for TypeAliasTransformer { /// Replace type alias. fn fix_type_alias_identifier<'ctx>( + pkg: &String, module: &'ctx mut ast::Module, type_alias_mapping: IndexMap, ) { - let mut type_alias_transformer = TypeAliasTransformer { type_alias_mapping }; + let mut type_alias_transformer = TypeAliasTransformer { + pkgpath: pkg.clone(), + type_alias_mapping, + }; type_alias_transformer.walk_module(module); } /// Process type alias. -pub fn process_program_type_alias( +pub fn type_alias_pass( program: &mut ast::Program, type_alias_mapping: IndexMap>, ) { - for (pkgpath, modules) in program.pkgs.iter_mut() { - for module in modules.iter_mut() { + for (pkgpath, modules) in program.pkgs.iter() { + for module in modules.iter() { + let mut module = program + .get_module_mut(module) + .expect("Failed to acquire module lock") + .expect(&format!("module {:?} not found in program", module)); if let Some(type_alias_mapping) = type_alias_mapping.get(pkgpath) { - fix_type_alias_identifier(module, type_alias_mapping.clone()); + fix_type_alias_identifier(pkgpath, &mut module, type_alias_mapping.clone()); } } } diff --git a/kclvm/sema/src/resolver/ty_erasure.rs b/kclvm/sema/src/resolver/ty_erasure.rs new file mode 100644 index 000000000..eead1b252 --- /dev/null +++ b/kclvm/sema/src/resolver/ty_erasure.rs @@ -0,0 +1,78 @@ +use kclvm_ast::walker::MutSelfMutWalker; +use kclvm_ast::{ast, walk_if_mut, walk_list_mut}; + +#[derive(Default)] +struct TypeErasureTransformer; +const FUNCTION: &str = "function"; + +impl<'ctx> MutSelfMutWalker<'ctx> for TypeErasureTransformer { + fn walk_schema_stmt(&mut self, schema_stmt: &'ctx mut ast::SchemaStmt) { + if let Some(schema_index_signature) = schema_stmt.index_signature.as_deref_mut() { + if let kclvm_ast::ast::Type::Function(_) = + &mut schema_index_signature.node.value_ty.node + { + schema_index_signature.node.value_ty.node = FUNCTION.to_string().into(); + } + } + walk_if_mut!(self, walk_arguments, schema_stmt.args); + walk_list_mut!(self, walk_call_expr, schema_stmt.decorators); + walk_list_mut!(self, walk_check_expr, schema_stmt.checks); + walk_list_mut!(self, walk_stmt, schema_stmt.body); + } + fn walk_schema_attr(&mut self, schema_attr: &'ctx mut ast::SchemaAttr) { + walk_list_mut!(self, walk_call_expr, schema_attr.decorators); + walk_if_mut!(self, walk_expr, schema_attr.value); + if let kclvm_ast::ast::Type::Function(_) = schema_attr.ty.as_ref().node { + schema_attr.ty.node = FUNCTION.to_string().into(); + } + } + fn walk_assign_stmt(&mut self, assign_stmt: &'ctx mut ast::AssignStmt) { + if let Some(ty) = &mut assign_stmt.ty { + if let kclvm_ast::ast::Type::Function(_) = ty.as_ref().node { + if let Some(ty_anno) = &mut assign_stmt.ty { + ty_anno.node = FUNCTION.to_string().into(); + } + } + } + self.walk_expr(&mut assign_stmt.value.node); + } + fn walk_type_alias_stmt(&mut self, type_alias_stmt: &'ctx mut ast::TypeAliasStmt) { + if let kclvm_ast::ast::Type::Function(_) = type_alias_stmt.ty.as_ref().node { + type_alias_stmt.type_value.node = FUNCTION.to_string(); + } + } + fn walk_arguments(&mut self, arguments: &'ctx mut ast::Arguments) { + for ty in (&mut arguments.ty_list.iter_mut()).flatten() { + if let kclvm_ast::ast::Type::Function(_) = ty.as_ref().node { + ty.node = FUNCTION.to_string().into(); + } + } + for default in arguments.defaults.iter_mut() { + if let Some(d) = default.as_deref_mut() { + self.walk_expr(&mut d.node) + } + } + } + fn walk_lambda_expr(&mut self, lambda_expr: &'ctx mut ast::LambdaExpr) { + walk_if_mut!(self, walk_arguments, lambda_expr.args); + walk_list_mut!(self, walk_stmt, lambda_expr.body); + if let Some(ty) = lambda_expr.return_ty.as_mut() { + if let kclvm_ast::ast::Type::Function(_) = ty.as_ref().node { + ty.node = FUNCTION.to_string().into(); + } + } + } +} + +/// Run a pass on AST and change the function type to the `Named("function")` type +pub fn type_func_erasure_pass<'ctx>(program: &'ctx mut ast::Program) { + for (_, modules) in program.pkgs.iter() { + for module in modules.iter() { + let mut module = program + .get_module_mut(module) + .expect("Failed to acquire module lock") + .expect(&format!("module {:?} not found in program", module)); + TypeErasureTransformer::default().walk_module(&mut module); + } + } +} diff --git a/kclvm/sema/src/resolver/var.rs b/kclvm/sema/src/resolver/var.rs index 968c16d86..6b4142aeb 100644 --- a/kclvm/sema/src/resolver/var.rs +++ b/kclvm/sema/src/resolver/var.rs @@ -1,22 +1,25 @@ use crate::resolver::Resolver; -use crate::ty::TypeKind; +use indexmap::IndexMap; +use kclvm_ast::ast; +use kclvm_ast::pos::GetPos; +use kclvm_error::diagnostic::Range; use kclvm_error::*; use super::node::ResolvedResult; use super::scope::{ScopeObject, ScopeObjectKind}; -impl<'ctx> Resolver<'ctx> { +impl<'ctx> Resolver<'_> { /// Resolve variables. pub fn resolve_var( &mut self, names: &[String], pkgpath: &str, - pos: Position, - ) -> ResolvedResult { + range: Range, + ) -> Vec { if !pkgpath.is_empty() && self.ctx.l_value { self.handler.add_compile_error( "only schema and dict object can be updated attribute", - pos.clone(), + range.clone(), ); } if names.len() == 1 { @@ -24,18 +27,42 @@ impl<'ctx> Resolver<'ctx> { let scope_schema_ty = self.ctx.schema.clone(); if let Some(schema_ty) = &scope_schema_ty { let mut schema_ty = schema_ty.borrow_mut(); + // Find attribute type in the schema. let ty = schema_ty.get_type_of_attr(name); - // Load from schema if in schema + // Load from schema if the variable in schema if !self.ctx.l_value { + // Find the type from from local and global scope. let scope_ty = self.find_type_in_scope(name); if self.ctx.local_vars.contains(name) { - return scope_ty.map_or(self.any_ty(), |ty| ty); - } else if let Some(ref ty) = ty { + return vec![scope_ty.map_or(self.any_ty(), |ty| ty)]; + } + // If it is a schema attribute, return the attribute type. + if let Some(ref ty) = ty { if !ty.is_any() { - return ty.clone(); + return vec![ty.clone()]; } } - scope_ty.map_or(self.any_ty(), |ty| ty) + // Find from mixin schemas of a non-mixin schema + if ty.is_none() && !schema_ty.is_mixin { + for mixin in &schema_ty.mixins { + if let Some(ty) = mixin.get_type_of_attr(name) { + return vec![ty.clone()]; + } + } + } + // If the variable is not found in a schema but not a schema mixin or rule, + // raise an error and return an any type. + // At present, retaining certain dynamic characteristics for mixins and rules + // requires further consideration of their semantics. + if ty.is_none() + && scope_ty.is_none() + && !schema_ty.is_mixin + && !schema_ty.is_rule + { + vec![self.lookup_type_from_scope(name, range)] + } else { + vec![scope_ty.map_or(self.any_ty(), |ty| ty)] + } } // Store else { @@ -44,24 +71,24 @@ impl<'ctx> Resolver<'ctx> { name, ScopeObject { name: name.to_string(), - start: pos.clone(), - end: pos.clone(), + start: range.0.clone(), + end: range.1.clone(), ty: self.any_ty(), kind: ScopeObjectKind::Variable, + doc: None, }, ); if ty.is_none() { schema_ty.set_type_of_attr(name, self.any_ty()) } - return self.any_ty(); + return vec![self.any_ty()]; } - // FIXME: self.check_config_attr(name, &pos, &schema_ty); - ty.map_or(self.lookup_type_from_scope(name, pos.clone()), |ty| ty) + vec![ty.map_or(self.lookup_type_from_scope(name, range.clone()), |ty| ty)] } } else { // Load from schema if in schema if !self.ctx.l_value { - self.lookup_type_from_scope(name, pos) + vec![self.lookup_type_from_scope(name, range)] } // Store else { @@ -70,38 +97,145 @@ impl<'ctx> Resolver<'ctx> { name, ScopeObject { name: name.to_string(), - start: pos.clone(), - end: pos.clone(), + start: range.0.clone(), + end: range.1.clone(), ty: self.any_ty(), kind: ScopeObjectKind::Variable, + doc: None, }, ); - return self.any_ty(); + return vec![self.any_ty()]; + } + vec![self.lookup_type_from_scope(name, range)] + } + } + } else if !names.is_empty() { + // Lookup pkgpath scope object and record it as "used". When enter child scope, e.g., in a schema scope, cant find module object. + // It should be recursively search whole scope to lookup scope object, not the current scope.element. + if !pkgpath.is_empty() { + if let Some(obj) = self.scope.borrow().lookup(&names[0]) { + if let ScopeObjectKind::Module(m) = &mut obj.borrow_mut().kind { + for (stmt, used) in m.import_stmts.iter_mut() { + if stmt.get_pos().filename == range.0.filename { + *used = true; + } + } } - self.lookup_type_from_scope(name, pos) } } - } else { // Load type - let mut ty = self.resolve_var( - &[if !pkgpath.is_empty() { - pkgpath.to_string() - } else { - names[0].clone() - }], - pkgpath, - pos.clone(), - ); + let mut tys = self.resolve_var(&[names[0].clone()], pkgpath, range.clone()); + let mut ty = tys[0].clone(); + for name in &names[1..] { // Store and config attr check if self.ctx.l_value { - if let TypeKind::Schema(schema_ty) = &ty.kind { - self.check_config_attr(name, &pos, schema_ty); + self.must_check_config_attr(name, &ty, &range, None); + } + ty = self.load_attr(ty, name, range.clone()); + tys.push(ty.clone()); + } + tys + } else { + self.handler + .add_compile_error("missing variable", range.clone()); + vec![self.any_ty()] + } + } + + /// Resolve left-hand target in the assign statement. + pub fn resolve_target( + &mut self, + target: &'ctx ast::Target, + range: Range, + ) -> Vec { + let mut tys = self.resolve_var( + &[target.get_name().to_string()], + &target.pkgpath, + range.clone(), + ); + if target.paths.is_empty() { + tys + } else { + let mut ty = tys[0].clone(); + let last_ctx_l_value = self.ctx.l_value; + self.ctx.l_value = false; + for path in &target.paths { + match path { + ast::MemberOrIndex::Member(member) => { + let attr = &member.node; + self.must_check_config_attr(attr, &ty, &range, None); + ty = self.load_attr(ty, attr, range.clone()); + tys.push(ty.clone()); + } + ast::MemberOrIndex::Index(index) => { + if let ast::Expr::StringLit(string_lit) = &index.node { + self.must_check_config_attr(&string_lit.value, &ty, &range, None); + } + ty = self.subscript_index(ty, index, range.clone()); + tys.push(ty.clone()); } } - ty = self.load_attr(ty, name, pos.clone()) } - ty + self.ctx.l_value = last_ctx_l_value; + tys + } + } + + /// Resolve an unique key in the current package. + pub(crate) fn resolve_unique_key(&mut self, name: &str, range: &Range) { + if !self.contains_global_name(name) && self.scope_level == 0 { + self.insert_global_name(name, range); + } else { + let mut msgs = vec![Message { + range: range.clone(), + style: Style::LineAndColumn, + message: format!("Unique key error name '{}'", name), + note: None, + suggested_replacement: None, + }]; + if let Some(pos) = self.get_global_name_pos(name) { + msgs.push(Message { + range: pos.clone(), + style: Style::LineAndColumn, + message: format!("The variable '{}' is declared here", name), + note: None, + suggested_replacement: None, + }); + } + self.handler.add_error(ErrorKind::UniqueKeyError, &msgs); + } + } + + /// Insert global name in the current package. + pub(crate) fn insert_global_name(&mut self, name: &str, range: &Range) { + match self.ctx.global_names.get_mut(&self.ctx.pkgpath) { + Some(mapping) => { + mapping.insert(name.to_string(), range.clone()); + } + None => { + let mut mapping = IndexMap::default(); + mapping.insert(name.to_string(), range.clone()); + self.ctx + .global_names + .insert(self.ctx.pkgpath.clone(), mapping); + } + } + } + + /// Whether contains global name in the current package. + pub(crate) fn contains_global_name(&mut self, name: &str) -> bool { + match self.ctx.global_names.get_mut(&self.ctx.pkgpath) { + Some(mapping) => mapping.contains_key(name), + None => false, + } + } + + /// Get global name position in the current package. + pub(crate) fn get_global_name_pos(&mut self, name: &str) -> Option<&Range> { + match self.ctx.global_names.get_mut(&self.ctx.pkgpath) { + Some(mapping) => mapping.get(name), + None => None, } } } diff --git a/kclvm/sema/src/ty/constants.rs b/kclvm/sema/src/ty/constants.rs index 01ead742e..b433c28ec 100644 --- a/kclvm/sema/src/ty/constants.rs +++ b/kclvm/sema/src/ty/constants.rs @@ -1,4 +1,4 @@ -use std::rc::Rc; +use std::sync::Arc; use super::{Type, TypeFlags, TypeKind}; @@ -57,24 +57,24 @@ pub const TYPES_MAPPING: Lazy> = Lazy::new(|| { mapping.insert(STR_TYPE_STR.to_string(), Type::STR); mapping.insert(BOOL_TYPE_STR.to_string(), Type::BOOL); mapping.insert(ANY_TYPE_STR.to_string(), Type::ANY); - mapping.insert("[]".to_string(), Type::list(Rc::new(Type::ANY))); - mapping.insert("[any]".to_string(), Type::list(Rc::new(Type::ANY))); - mapping.insert("[str]".to_string(), Type::list(Rc::new(Type::STR))); + mapping.insert("[]".to_string(), Type::list(Arc::new(Type::ANY))); + mapping.insert("[any]".to_string(), Type::list(Arc::new(Type::ANY))); + mapping.insert("[str]".to_string(), Type::list(Arc::new(Type::STR))); mapping.insert( "{:}".to_string(), - Type::dict(Rc::new(Type::ANY), Rc::new(Type::ANY)), + Type::dict(Arc::new(Type::ANY), Arc::new(Type::ANY)), ); mapping.insert( "{str:}".to_string(), - Type::dict(Rc::new(Type::STR), Rc::new(Type::ANY)), + Type::dict(Arc::new(Type::STR), Arc::new(Type::ANY)), ); mapping.insert( "{str:any}".to_string(), - Type::dict(Rc::new(Type::STR), Rc::new(Type::ANY)), + Type::dict(Arc::new(Type::STR), Arc::new(Type::ANY)), ); mapping.insert( "{str:str}".to_string(), - Type::dict(Rc::new(Type::STR), Rc::new(Type::STR)), + Type::dict(Arc::new(Type::STR), Arc::new(Type::STR)), ); mapping }); diff --git a/kclvm/sema/src/ty/constructor.rs b/kclvm/sema/src/ty/constructor.rs index caa773690..90f11c0e9 100644 --- a/kclvm/sema/src/ty/constructor.rs +++ b/kclvm/sema/src/ty/constructor.rs @@ -1,23 +1,48 @@ use super::*; impl Type { + /// Construct an int type reference. + #[inline] + pub fn int_ref() -> TypeRef { + Arc::new(Type::INT) + } + /// Construct a float type reference. + #[inline] + pub fn float_ref() -> TypeRef { + Arc::new(Type::FLOAT) + } + /// Construct a bool type reference. + #[inline] + pub fn bool_ref() -> TypeRef { + Arc::new(Type::BOOL) + } + /// Construct a str type reference. + #[inline] + pub fn str_ref() -> TypeRef { + Arc::new(Type::STR) + } + /// Construct a any type reference. + #[inline] + pub fn any_ref() -> TypeRef { + Arc::new(Type::ANY) + } /// Construct a union type #[inline] - pub fn union(types: &[Rc]) -> Type { + pub fn union(types: &[TypeRef]) -> Type { Type { kind: TypeKind::Union(types.to_owned()), flags: TypeFlags::UNION, is_type_alias: false, } } - /// Construct a union type ref + /// Construct an union type reference. #[inline] - pub fn union_ref(types: &[Rc]) -> Rc { - Rc::new(Self::union(types)) + pub fn union_ref(types: &[TypeRef]) -> TypeRef { + Arc::new(Self::union(types)) } /// Construct a list type #[inline] - pub fn list(item_ty: Rc) -> Type { + pub fn list(item_ty: TypeRef) -> Type { Type { kind: TypeKind::List(item_ty), flags: TypeFlags::LIST, @@ -26,22 +51,52 @@ impl Type { } /// Construct a list type ref #[inline] - pub fn list_ref(item_ty: Rc) -> Rc { - Rc::new(Self::list(item_ty)) + pub fn list_ref(item_ty: TypeRef) -> TypeRef { + Arc::new(Self::list(item_ty)) } /// Construct a dict type #[inline] - pub fn dict(key_ty: Rc, val_ty: Rc) -> Type { + pub fn dict(key_ty: TypeRef, val_ty: TypeRef) -> Type { Type { - kind: TypeKind::Dict(key_ty, val_ty), + kind: TypeKind::Dict(DictType { + key_ty, + val_ty, + attrs: IndexMap::new(), + }), flags: TypeFlags::DICT, is_type_alias: false, } } /// Construct a dict type ref #[inline] - pub fn dict_ref(key_ty: Rc, val_ty: Rc) -> Rc { - Rc::new(Self::dict(key_ty, val_ty)) + pub fn dict_ref(key_ty: TypeRef, val_ty: TypeRef) -> TypeRef { + Arc::new(Self::dict(key_ty, val_ty)) + } + /// Construct a dict type with attrs + #[inline] + pub fn dict_with_attrs( + key_ty: TypeRef, + val_ty: TypeRef, + attrs: IndexMap, + ) -> Type { + Type { + kind: TypeKind::Dict(DictType { + key_ty, + val_ty, + attrs, + }), + flags: TypeFlags::DICT, + is_type_alias: false, + } + } + /// Construct a dict type reference with attrs + #[inline] + pub fn dict_ref_with_attrs( + key_ty: TypeRef, + val_ty: TypeRef, + attrs: IndexMap, + ) -> TypeRef { + Arc::new(Self::dict_with_attrs(key_ty, val_ty, attrs)) } /// Construct a bool literal type. #[inline] @@ -118,8 +173,8 @@ impl Type { /// Construct a function type. #[inline] pub fn function( - self_ty: Option>, - return_ty: Rc, + self_ty: Option, + return_ty: TypeRef, params: &[Parameter], doc: &str, is_variadic: bool, @@ -159,20 +214,18 @@ impl Type { } } /// Construct a iterable type - pub fn iterable() -> Rc { - Rc::new(Type::union(&[ - Rc::new(Type::STR), - Rc::new(Type::dict(Rc::new(Type::ANY), Rc::new(Type::ANY))), - Rc::new(Type::list(Rc::new(Type::ANY))), + #[inline] + pub fn iterable() -> TypeRef { + Arc::new(Type::union(&[ + Arc::new(Type::STR), + Arc::new(Type::dict(Arc::new(Type::ANY), Arc::new(Type::ANY))), + Arc::new(Type::list(Arc::new(Type::ANY))), ])) } - /// Construct a number type - pub fn number() -> Rc { - Rc::new(Type::union(&[ - Rc::new(Type::INT), - Rc::new(Type::FLOAT), - Rc::new(Type::STR), - ])) + /// Construct a number type. + #[inline] + pub fn number() -> TypeRef { + Type::union_ref(&[Type::int_ref(), Type::float_ref()]) } /// Whether is a any type. #[inline] @@ -234,9 +287,7 @@ impl Type { /// Whether is a number type. #[inline] pub fn is_number(&self) -> bool { - self.flags.contains(TypeFlags::INT) - || self.flags.contains(TypeFlags::FLOAT) - || self.flags.contains(TypeFlags::BOOL) + self.flags.contains(TypeFlags::INT) || self.flags.contains(TypeFlags::FLOAT) } /// Whether is a void type. #[inline] @@ -310,7 +361,7 @@ impl Type { | TypeKind::Str | TypeKind::StrLit(_) | TypeKind::List(_) - | TypeKind::Dict(_, _) + | TypeKind::Dict(DictType { .. }) | TypeKind::Union(_) | TypeKind::Schema(_) | TypeKind::NumberMultiplier(_) diff --git a/kclvm/sema/src/ty/context.rs b/kclvm/sema/src/ty/context.rs index 5af42fc0d..145c2849d 100644 --- a/kclvm/sema/src/ty/context.rs +++ b/kclvm/sema/src/ty/context.rs @@ -1,8 +1,11 @@ -use std::rc::Rc; +use std::collections::HashMap; +use std::sync::Arc; -use super::{sup, Type, TypeFlags, TypeKind}; -use petgraph::algo::is_cyclic_directed; -use petgraph::graph::DiGraph; +use super::{sup, DictType, Type, TypeFlags, TypeKind, TypeRef}; +use kclvm_error::diagnostic::Range; +use petgraph::algo::kosaraju_scc; +use petgraph::graph::{DiGraph, NodeIndex}; +use petgraph::visit::{depth_first_search, DfsEvent}; /// TypeContext responsible for type generation, calculation, /// and equality and subtype judgment between types. @@ -10,17 +13,19 @@ use petgraph::graph::DiGraph; pub struct TypeContext { pub dep_graph: DiGraph, pub builtin_types: BuiltinTypes, + node_index_map: HashMap, + node_range_map: HashMap, } #[derive(Debug)] pub struct BuiltinTypes { - pub any: Rc, - pub bool: Rc, - pub int: Rc, - pub float: Rc, - pub str: Rc, - pub void: Rc, - pub none: Rc, + pub any: TypeRef, + pub bool: TypeRef, + pub int: TypeRef, + pub float: TypeRef, + pub str: TypeRef, + pub void: TypeRef, + pub none: TypeRef, } impl Default for TypeContext { @@ -35,26 +40,77 @@ impl TypeContext { TypeContext { dep_graph: DiGraph::new(), builtin_types: BuiltinTypes { - any: Rc::new(Type::ANY), - bool: Rc::new(Type::BOOL), - int: Rc::new(Type::INT), - float: Rc::new(Type::FLOAT), - str: Rc::new(Type::STR), - void: Rc::new(Type::VOID), - none: Rc::new(Type::NONE), + any: Arc::new(Type::ANY), + bool: Arc::new(Type::BOOL), + int: Arc::new(Type::INT), + float: Arc::new(Type::FLOAT), + str: Arc::new(Type::STR), + void: Arc::new(Type::VOID), + none: Arc::new(Type::NONE), }, + node_index_map: HashMap::new(), + node_range_map: HashMap::new(), } } - /// Return true if the dep graph contains a cycle. + /// Return true if the dep graph contains a cycle from node. #[inline] - pub fn is_cyclic(&self) -> bool { - is_cyclic_directed(&self.dep_graph) + pub fn is_cyclic_from_node(&self, node: &String) -> bool { + let idx = match self.node_index_map.get(node) { + Some(idx) => idx, + None => return false, + }; + depth_first_search(&self.dep_graph, vec![idx.clone()], |event| match event { + DfsEvent::BackEdge(_, _) => Err(()), + _ => Ok(()), + }) + .is_err() + } + + pub fn find_cycle_nodes(&self, node: &String) -> Vec> { + let idx = match self.node_index_map.get(node) { + Some(idx) => idx, + None => return vec![], + }; + let mut res = vec![]; + let strongly_connected_components: Vec> = kosaraju_scc(&self.dep_graph); + for comp in strongly_connected_components { + if comp.len() > 1 && comp.contains(idx) { + res.push(comp) + } + } + res + } + + #[inline] + pub fn get_node_range(&self, idx: &NodeIndex) -> Option { + self.node_range_map.get(idx).cloned() + } + + /// Add dependencies between "from" and "to". + pub fn add_dependencies(&mut self, from: &str, to: &str, from_node_range: Range) { + let from_idx = self.get_or_insert_node_index(from); + let to_idx = self.get_or_insert_node_index(to); + self.dep_graph.add_edge(from_idx, to_idx, ()); + self.node_range_map.insert(from_idx, from_node_range); + } + + /// Get the node index from the node index map or insert it into the dependency graph. + #[inline] + fn get_or_insert_node_index(&mut self, name: &str) -> NodeIndex { + match self.node_index_map.get(name) { + Some(idx) => *idx, + None => { + let idx = self.dep_graph.add_node(name.to_string()); + self.node_index_map.insert(name.to_string(), idx); + idx + } + } } /// Convert the literal union type to its variable type /// e.g., 1|2 -> int, 's'|'ss' -> str. - pub fn literal_union_type_to_variable_type(&self, ty: Rc) -> Rc { + pub fn literal_union_type_to_variable_type(&self, ty: TypeRef) -> TypeRef { if ty.is_union() { self.infer_to_variable_type(ty) } else { @@ -64,7 +120,7 @@ impl TypeContext { /// Judge a type kind in the type kind list or the union /// type kinds are all in the type kind. - pub fn is_kind_type_or_kind_union_type(&self, ty: Rc, flags: &[TypeFlags]) -> bool { + pub fn is_kind_type_or_kind_union_type(&self, ty: TypeRef, flags: &[TypeFlags]) -> bool { match &ty.kind { TypeKind::Union(types) => types .iter() @@ -74,7 +130,12 @@ impl TypeContext { } #[inline] - pub fn is_number_type_or_number_union_type(&self, ty: Rc) -> bool { + pub fn is_number_type_or_number_union_type(&self, ty: TypeRef) -> bool { + self.is_kind_type_or_kind_union_type(ty, &[TypeFlags::INT, TypeFlags::FLOAT]) + } + + #[inline] + pub fn is_number_bool_type_or_number_bool_union_type(&self, ty: TypeRef) -> bool { self.is_kind_type_or_kind_union_type( ty, &[TypeFlags::INT, TypeFlags::FLOAT, TypeFlags::BOOL], @@ -82,17 +143,17 @@ impl TypeContext { } #[inline] - pub fn is_config_type_or_config_union_type(&self, ty: Rc) -> bool { + pub fn is_config_type_or_config_union_type(&self, ty: TypeRef) -> bool { self.is_kind_type_or_kind_union_type(ty, &[TypeFlags::DICT, TypeFlags::SCHEMA]) } #[inline] - pub fn is_str_type_or_str_union_type(&self, ty: Rc) -> bool { + pub fn is_str_type_or_str_union_type(&self, ty: TypeRef) -> bool { self.is_kind_type_or_kind_union_type(ty, &[TypeFlags::STR]) } #[inline] - pub fn is_primitive_type_or_primitive_union_type(&self, ty: Rc) -> bool { + pub fn is_primitive_type_or_primitive_union_type(&self, ty: TypeRef) -> bool { self.is_kind_type_or_kind_union_type( ty, &[ @@ -105,13 +166,12 @@ impl TypeContext { } #[inline] - pub fn is_mul_val_type_or_mul_val_union_type(&self, ty: Rc) -> bool { + pub fn is_mul_val_type_or_mul_val_union_type(&self, ty: TypeRef) -> bool { self.is_kind_type_or_kind_union_type( ty, &[ TypeFlags::INT, TypeFlags::FLOAT, - TypeFlags::BOOL, TypeFlags::STR, TypeFlags::LIST, ], @@ -120,19 +180,19 @@ impl TypeContext { /// Convert type to the real type annotation #[inline] - pub fn into_type_annotation_str(&self, ty: Rc) -> String { + pub fn into_type_annotation_str(&self, ty: TypeRef) -> String { ty.into_type_annotation_str() } } pub trait TypeInferMethods { /// Infer the value type to the variable type" - fn infer_to_variable_type(&self, ty: Rc) -> Rc; + fn infer_to_variable_type(&self, ty: TypeRef) -> TypeRef; } impl TypeInferMethods for TypeContext { /// Infer the value type to the variable type" - fn infer_to_variable_type(&self, ty: Rc) -> Rc { + fn infer_to_variable_type(&self, ty: TypeRef) -> TypeRef { match &ty.kind { // None/Undefined type to any type e.g., None -> any TypeKind::None => self.builtin_types.any.clone(), @@ -143,15 +203,20 @@ impl TypeInferMethods for TypeContext { TypeKind::StrLit(_) => self.builtin_types.str.clone(), TypeKind::List(item_ty) => Type::list_ref(self.infer_to_variable_type(item_ty.clone())), // Dict type e.g., {str:1|2} -> {str:int} - TypeKind::Dict(key_ty, val_ty) => Type::dict_ref( + TypeKind::Dict(DictType { + key_ty, + val_ty, + attrs, + }) => Type::dict_ref_with_attrs( self.infer_to_variable_type(key_ty.clone()), self.infer_to_variable_type(val_ty.clone()), + attrs.clone(), ), // Union type e.g., 1|2|"s" -> int|str TypeKind::Union(types) => sup(&types .iter() .map(|ty| self.infer_to_variable_type(ty.clone())) - .collect::>>()), + .collect::>()), _ => ty.clone(), } } diff --git a/kclvm/sema/src/ty/into.rs b/kclvm/sema/src/ty/into.rs index ac22c021b..21ded369e 100644 --- a/kclvm/sema/src/ty/into.rs +++ b/kclvm/sema/src/ty/into.rs @@ -1,9 +1,10 @@ use super::*; +use kclvm_ast::pos::GetPos; impl Type { /// Downcast ty into the list type. #[inline] - pub fn list_item_ty(&self) -> Rc { + pub fn list_item_ty(&self) -> TypeRef { match &self.kind { TypeKind::List(item_ty) => item_ty.clone(), _ => bug!("invalid list type {}", self.ty_str()), @@ -11,33 +12,35 @@ impl Type { } /// Downcast ty into the dict entry type. #[inline] - pub fn dict_entry_ty(&self) -> (Rc, Rc) { + pub fn dict_entry_ty(&self) -> (TypeRef, TypeRef) { match &self.kind { - TypeKind::Dict(key_ty, val_ty) => (key_ty.clone(), val_ty.clone()), + TypeKind::Dict(DictType { key_ty, val_ty, .. }) => (key_ty.clone(), val_ty.clone()), _ => bug!("invalid dict type {}", self.ty_str()), } } /// Downcast ty into the config key type. #[inline] - pub fn config_key_ty(&self) -> Rc { + pub fn config_key_ty(&self) -> TypeRef { match &self.kind { - TypeKind::Dict(key_ty, _) => key_ty.clone(), + TypeKind::Dict(DictType { key_ty, .. }) => key_ty.clone(), TypeKind::Schema(schema_ty) => schema_ty.key_ty(), _ => bug!("invalid config type {}", self.ty_str()), } } /// Downcast ty into the config value type. #[inline] - pub fn config_val_ty(&self) -> Rc { + pub fn config_val_ty(&self) -> TypeRef { match &self.kind { - TypeKind::Dict(_, val_ty) => val_ty.clone(), + TypeKind::Dict(DictType { + key_ty: _, val_ty, .. + }) => val_ty.clone(), TypeKind::Schema(schema_ty) => schema_ty.val_ty(), _ => bug!("invalid config type {}", self.ty_str()), } } /// Get types from the union type. #[inline] - pub fn union_types(&self) -> Vec> { + pub fn union_types(&self) -> Vec { match &self.kind { TypeKind::Union(types) => types.clone(), _ => bug!("invalid {} into union type", self.ty_str()), @@ -51,6 +54,14 @@ impl Type { _ => bug!("invalid type {} into schema type", self.ty_str()), } } + /// Into function type. + #[inline] + pub fn into_func_type(&self) -> FunctionType { + match &self.kind { + TypeKind::Function(func_ty) => func_ty.clone(), + _ => bug!("invalid type {} into function type", self.ty_str()), + } + } /// Into number multiplier type. #[inline] pub fn into_number_multiplier(&self) -> NumberMultiplierType { @@ -77,9 +88,9 @@ impl Type { } float_str } - TypeKind::StrLit(v) => (format!("\"{}\"", v.replace('"', "\\\""))), + TypeKind::StrLit(v) => format!("\"{}\"", v.replace('"', "\\\"")), TypeKind::List(item_ty) => format!("[{}]", item_ty.into_type_annotation_str()), - TypeKind::Dict(key_ty, val_ty) => { + TypeKind::Dict(DictType { key_ty, val_ty, .. }) => { format!( "{{{}:{}}}", key_ty.into_type_annotation_str(), @@ -90,8 +101,8 @@ impl Type { .iter() .map(|ty| ty.into_type_annotation_str()) .collect::>() - .join("|"), - TypeKind::Schema(schema_ty) => schema_ty.ty_str_with_pkgpath(), + .join(" | "), + TypeKind::Schema(schema_ty) => schema_ty.ty_str_with_at_pkgpath_prefix(), TypeKind::NumberMultiplier(number_multiplier) => { if number_multiplier.is_literal { format!( @@ -104,6 +115,7 @@ impl Type { NUMBER_MULTIPLIER_PKG_TYPE_STR.to_string() } } + TypeKind::Function(fn_ty) => fn_ty.ty_str(), _ => self.ty_str(), } } @@ -124,30 +136,33 @@ impl From for Type { list_ty .inner_type .as_ref() - .map_or(Rc::new(Type::ANY), |ty| Rc::new(ty.node.clone().into())), + .map_or(Arc::new(Type::ANY), |ty| Arc::new(ty.node.clone().into())), ), ast::Type::Dict(dict_ty) => Type::dict( dict_ty .key_type .as_ref() - .map_or(Rc::new(Type::ANY), |ty| Rc::new(ty.node.clone().into())), + .map_or(Arc::new(Type::ANY), |ty| Arc::new(ty.node.clone().into())), dict_ty .value_type .as_ref() - .map_or(Rc::new(Type::ANY), |ty| Rc::new(ty.node.clone().into())), + .map_or(Arc::new(Type::ANY), |ty| Arc::new(ty.node.clone().into())), ), ast::Type::Union(union_ty) => Type::union( &union_ty .type_elements .iter() - .map(|ty| Rc::new(ty.node.clone().into())) - .collect::>>(), + .map(|ty| Arc::new(ty.node.clone().into())) + .collect::>(), ), ast::Type::Literal(literal_ty) => match literal_ty { ast::LiteralType::Bool(v) => Type::bool_lit(v), - ast::LiteralType::Int(v, suffix_option) => match suffix_option { + ast::LiteralType::Int(ast::IntLiteralType { + value: v, + suffix: suffix_option, + }) => match suffix_option { Some(suffix) => Type::number_multiplier( - kclvm::cal_num(v, &suffix.value()), + kclvm_runtime::cal_num(v, &suffix.value()), v, &suffix.value(), ), @@ -156,6 +171,31 @@ impl From for Type { ast::LiteralType::Float(v) => Type::float_lit(v), ast::LiteralType::Str(v) => Type::str_lit(&v), }, + // Ast::function => Sema::function, + ast::Type::Function(func_ty) => Type::function( + None, + func_ty + .ret_ty + .as_ref() + .map_or(Arc::new(Type::ANY), |ty| Arc::new(ty.node.clone().into())), + func_ty + .params_ty + .map_or(vec![], |tys| { + tys.iter() + .map(|ty| Parameter { + name: "".to_string(), + ty: Arc::new(ty.node.clone().into()), + has_default: false, + range: ty.get_span_pos(), + default_value: None, + }) + .collect::>() + }) + .as_slice(), + "", + false, + None, + ), } } } diff --git a/kclvm/sema/src/ty/mod.rs b/kclvm/sema/src/ty/mod.rs index fd13eb686..d35975b30 100644 --- a/kclvm/sema/src/ty/mod.rs +++ b/kclvm/sema/src/ty/mod.rs @@ -6,21 +6,29 @@ pub mod parser; mod unify; mod walker; -use std::rc::Rc; +use std::collections::HashMap; +use std::sync::Arc; pub use constants::*; pub use context::{TypeContext, TypeInferMethods}; +use indexmap::IndexMap; use kclvm_ast::ast; use kclvm_ast::MAIN_PKG; +use kclvm_error::diagnostic::Range; use kclvm_error::Position; pub use unify::*; pub use walker::walk_type; -use indexmap::IndexMap; +use super::resolver::doc::Example; #[cfg(test)] mod tests; +/// TypeRef represents a reference to a type that exists to avoid copying types everywhere affecting +/// performance. For example, for two instances that are both integer types, there is actually no +/// difference between them. +pub type TypeRef = Arc; + #[derive(Debug, Clone, PartialEq)] pub struct Type { // The type kind. @@ -32,19 +40,31 @@ pub struct Type { flags: TypeFlags, } +unsafe impl Send for Type {} + impl Type { /// Whether the type contains the flag. #[inline] pub fn contains_flags(&self, flag: TypeFlags) -> bool { self.flags.contains(flag) } - /// Returns the type string used for error handler. + /// Returns the type string used for the error handler. pub fn ty_str(&self) -> String { match &self.kind { TypeKind::None => NONE_TYPE_STR.to_string(), TypeKind::Any => ANY_TYPE_STR.to_string(), TypeKind::Bool => BOOL_TYPE_STR.to_string(), - TypeKind::BoolLit(v) => format!("{}({})", BOOL_TYPE_STR, v), + TypeKind::BoolLit(v) => { + format!( + "{}({})", + BOOL_TYPE_STR, + if *v { + NAME_CONSTANT_TRUE + } else { + NAME_CONSTANT_FALSE + } + ) + } TypeKind::Int => INT_TYPE_STR.to_string(), TypeKind::IntLit(v) => format!("{}({})", INT_TYPE_STR, v), TypeKind::Float => FLOAT_TYPE_STR.to_string(), @@ -52,29 +72,70 @@ impl Type { TypeKind::Str => STR_TYPE_STR.to_string(), TypeKind::StrLit(v) => format!("{}({})", STR_TYPE_STR, v), TypeKind::List(item_ty) => format!("[{}]", item_ty.ty_str()), - TypeKind::Dict(key_ty, val_ty) => { + TypeKind::Dict(DictType { key_ty, val_ty, .. }) => { format!("{{{}:{}}}", key_ty.ty_str(), val_ty.ty_str()) } TypeKind::Union(types) => types .iter() .map(|ty| ty.ty_str()) .collect::>() - .join("|"), + .join(" | "), TypeKind::Schema(schema_ty) => schema_ty.name.to_string(), - TypeKind::NumberMultiplier(number_multiplier) => format!( - "{}({}{})", - NUMBER_MULTIPLIER_TYPE_STR, - number_multiplier.raw_value, - number_multiplier.binary_suffix - ), - TypeKind::Function(_) => FUNCTION_TYPE_STR.to_string(), + TypeKind::NumberMultiplier(number_multiplier) => number_multiplier.ty_str(), + TypeKind::Function(func_ty) => func_ty.ty_str(), TypeKind::Void => VOID_TYPE_STR.to_string(), TypeKind::Module(module_ty) => format!("{} '{}'", MODULE_TYPE_STR, module_ty.pkgpath), TypeKind::Named(name) => name.to_string(), } } + + pub fn ty_hint(&self) -> String { + match &self.kind { + TypeKind::StrLit(s) => format!("\"{}\"", s), + TypeKind::IntLit(v) => v.to_string(), + TypeKind::FloatLit(v) => v.to_string(), + TypeKind::List(item_ty) => format!("[{}]", item_ty.ty_hint()), + TypeKind::Dict(DictType { key_ty, val_ty, .. }) => { + format!("{{{}:{}}}", key_ty.ty_hint(), val_ty.ty_hint()) + } + TypeKind::Union(types) => types + .iter() + .map(|ty| ty.ty_hint()) + .collect::>() + .join(" | "), + _ => self.ty_str(), + } + } + + /// Returns the full type string with the package path used for the error handler. + pub fn full_ty_str(&self) -> String { + match &self.kind { + TypeKind::List(item_ty) => format!("[{}]", item_ty.full_ty_str()), + TypeKind::Dict(DictType { key_ty, val_ty, .. }) => { + format!("{{{}:{}}}", key_ty.full_ty_str(), val_ty.full_ty_str()) + } + TypeKind::Union(types) => types + .iter() + .map(|ty| ty.full_ty_str()) + .collect::>() + .join(" | "), + TypeKind::Schema(schema_ty) => schema_ty.full_ty_str(), + _ => self.ty_str(), + } + } + + pub fn ty_doc(&self) -> Option { + match &self.kind { + TypeKind::Schema(schema) => Some(schema.doc.clone()), + TypeKind::Function(func) => Some(func.doc.clone()), + _ => None, + } + } } +unsafe impl Send for TypeKind {} +unsafe impl Sync for TypeKind {} + #[derive(Debug, Clone, PartialEq)] pub enum TypeKind { /// A primitive None name constant. @@ -98,11 +159,11 @@ pub enum TypeKind { /// A primitive string literal type. StrLit(String), /// The pointer of an array slice. Written as `[T]`. - List(Rc), + List(TypeRef), /// A map type. Written as `{kT, vT}`. - Dict(Rc, Rc), + Dict(DictType), /// A union type. Written as ty1 | ty2 | ... | tyn - Union(Vec>), + Union(Vec), /// A schema type. Schema(SchemaType), /// A number multiplier type. @@ -140,6 +201,19 @@ bitflags::bitflags! { } } +#[derive(Debug, Clone, PartialEq)] +pub struct DictType { + pub key_ty: TypeRef, + pub val_ty: TypeRef, + pub attrs: IndexMap, +} + +#[derive(Debug, Clone, PartialEq)] +pub struct Attr { + pub ty: TypeRef, + pub range: Range, +} + /// The schema type. #[derive(Debug, Clone, PartialEq)] pub struct SchemaType { @@ -151,6 +225,8 @@ pub struct SchemaType { pub filename: String, /// The schema definition document string. pub doc: String, + /// The code snippets of the schema usage examples + pub examples: HashMap, /// Indicates whether the schema is a type of a instance or /// a type (value). Besides, it is necessary to distinguish /// between a type instance and a type value, such as the following code: @@ -191,28 +267,35 @@ pub struct SchemaType { } impl SchemaType { - /// Get the object type string with pkgpath - pub fn ty_str_with_pkgpath(&self) -> String { + /// Get the object type string with @pkgpath prefix. + pub fn ty_str_with_at_pkgpath_prefix(&self) -> String { if self.pkgpath.is_empty() || self.pkgpath == MAIN_PKG { self.name.clone() } else { format!("@{}.{}", self.pkgpath, self.name) } } + /// Get the object type string. + pub fn full_ty_str(&self) -> String { + full_ty_str(&self.pkgpath, &self.name) + } /// Is `name` a schema member function pub fn is_member_functions(&self, name: &str) -> bool { !self.is_instance && SCHEMA_MEMBER_FUNCTIONS.contains(&name) } - pub fn set_type_of_attr(&mut self, attr: &str, ty: Rc) { + pub fn set_type_of_attr(&mut self, attr: &str, ty: TypeRef) { match self.attrs.get_mut(attr) { Some(attr) => attr.ty = ty, None => { let schema_attr = SchemaAttr { is_optional: true, has_default: false, + default: None, ty, - pos: Position::dummy_pos(), + range: (Position::dummy_pos(), Position::dummy_pos()), + doc: None, + decorators: vec![], }; self.attrs.insert(attr.to_string(), schema_attr); } @@ -220,7 +303,7 @@ impl SchemaType { } #[inline] - pub fn get_type_of_attr(&self, attr: &str) -> Option> { + pub fn get_type_of_attr(&self, attr: &str) -> Option { self.get_obj_of_attr(attr).map(|attr| attr.ty.clone()) } @@ -237,32 +320,104 @@ impl SchemaType { } } - pub fn key_ty(&self) -> Rc { - Rc::new(Type::STR) + pub fn key_ty(&self) -> TypeRef { + Arc::new(Type::STR) } - pub fn val_ty(&self) -> Rc { + pub fn val_ty(&self) -> TypeRef { if let Some(index_signature) = &self.index_signature { index_signature.val_ty.clone() } else { - Rc::new(Type::ANY) + Arc::new(Type::ANY) } } + + pub fn schema_ty_signature_str(&self) -> (String, String) { + let base: String = if let Some(base) = &self.base { + format!("({})", base.name) + } else { + "".to_string() + }; + let params: String = if self.func.params.is_empty() { + "".to_string() + } else { + format!( + "[{}]", + self.func + .params + .iter() + .map(|p| format!("{}: {}", p.name.clone(), p.ty.ty_str())) + .collect::>() + .join(", ") + ) + }; + + let rest_sign = format!("schema {}{}{}:", self.name, params, base); + + (self.pkgpath.clone(), rest_sign) + } + + pub fn schema_ty_signature_no_pkg(&self) -> String { + let base: String = if let Some(base) = &self.base { + format!("({})", base.name) + } else { + "".to_string() + }; + let params: String = if self.func.params.is_empty() { + "".to_string() + } else { + format!( + "[{}]", + self.func + .params + .iter() + .map(|p| format!("{}: {}", p.name.clone(), p.ty.ty_str())) + .collect::>() + .join(", ") + ) + }; + let params_str = if !params.is_empty() && !base.is_empty() { + format!("\\{}{}", params, base) + } else if !params.is_empty() { + format!("{}", params) + } else if !base.is_empty() { + format!("{}", base) + } else { + "".to_string() + }; + format!("schema {}{}", self.name, params_str) + } +} + +pub fn full_ty_str(pkgpath: &str, name: &str) -> String { + if pkgpath.is_empty() || pkgpath == MAIN_PKG { + name.to_string() + } else { + format!("{}.{}", pkgpath, name) + } } #[derive(Debug, Clone, PartialEq)] pub struct SchemaAttr { pub is_optional: bool, pub has_default: bool, - pub ty: Rc, - pub pos: Position, + /// `default` denotes the schema attribute optional value string. For example, + /// for the schema attribute definition `name?: str = "Alice"`, the value of + /// `default` is [Some("Alice")]. + /// For the schema attribute definition `name?: str`, the value of `default` + /// is [None]. + pub default: Option, + pub ty: TypeRef, + pub range: Range, + pub doc: Option, + pub decorators: Vec, } #[derive(Debug, Clone, PartialEq)] pub struct SchemaIndexSignature { pub key_name: Option, - pub key_ty: Rc, - pub val_ty: Rc, + pub key_ty: TypeRef, + pub val_ty: TypeRef, pub any_other: bool, } @@ -297,11 +452,16 @@ pub enum ModuleKind { #[derive(Debug, Clone, PartialEq)] pub struct Decorator { + /// The decorator target e.g., the schema statement or schema attribute. pub target: DecoratorTarget, /// The decorator name. pub name: String, - /// The schema or attribute name of decorator dimension + /// The schema or attribute name of decorator dimension. pub key: String, + /// The decorator argument list values. + pub arguments: Vec, + /// The decorator keyword mapping values. + pub keywords: HashMap, } #[derive(Debug, Clone, PartialEq)] @@ -321,10 +481,14 @@ pub struct NumberMultiplierType { impl NumberMultiplierType { pub fn ty_str(&self) -> String { - format!( - "{}({}{})", - NUMBER_MULTIPLIER_TYPE_STR, self.raw_value, self.binary_suffix - ) + if self.is_literal { + format!( + "{}({}{})", + NUMBER_MULTIPLIER_TYPE_STR, self.raw_value, self.binary_suffix + ) + } else { + NUMBER_MULTIPLIER_TYPE_STR.to_string() + } } } @@ -333,16 +497,59 @@ impl NumberMultiplierType { pub struct FunctionType { pub doc: String, pub params: Vec, - pub self_ty: Option>, - pub return_ty: Rc, + pub self_ty: Option, + pub return_ty: TypeRef, pub is_variadic: bool, pub kw_only_index: Option, } -/// The function parameter. +impl FunctionType { + pub fn ty_str(&self) -> String { + format!( + "({}) -> {}", + self.params + .iter() + .map(|param| param.ty.ty_str()) + .collect::>() + .join(", "), + self.return_ty.ty_str() + ) + } + + pub fn func_signature_str(&self, name: &String) -> String { + format!( + "function {}({}) -> {}", + name, + self.params + .iter() + .map(|param| format!("{}: {}", param.name, param.ty.ty_str())) + .collect::>() + .join(", "), + self.return_ty.ty_str() + ) + } +} + +impl FunctionType { + #[inline] + pub fn variadic_func() -> Self { + Self { + doc: "".to_string(), + params: vec![], + self_ty: None, + return_ty: Type::any_ref(), + is_variadic: true, + kw_only_index: None, + } + } +} + +/// The function parameter type and position information. #[derive(Debug, Clone, PartialEq)] pub struct Parameter { pub name: String, - pub ty: Rc, + pub ty: TypeRef, pub has_default: bool, + pub default_value: Option, + pub range: Range, } diff --git a/kclvm/sema/src/ty/parser.rs b/kclvm/sema/src/ty/parser.rs index a998c6f8d..285a4720a 100644 --- a/kclvm/sema/src/ty/parser.rs +++ b/kclvm/sema/src/ty/parser.rs @@ -3,13 +3,13 @@ use crate::eval::str_literal_eval; use super::*; /// Parse type string -pub fn parse_type_str(ty_str: &str) -> Rc { +pub fn parse_type_str(ty_str: &str) -> TypeRef { if ty_str.is_empty() { - return Rc::new(Type::ANY); + return Arc::new(Type::ANY); } let ty_str = ty_str_strip(ty_str); match TYPES_MAPPING.get(ty_str) { - Some(ty) => Rc::new(ty.clone()), + Some(ty) => Arc::new(ty.clone()), None => { if is_union_type_str(ty_str) { parse_union_type_str(ty_str) @@ -19,12 +19,12 @@ pub fn parse_type_str(ty_str: &str) -> Rc { parse_number_multiplier_literal_type_str(ty_str) } else if is_dict_type_str(ty_str) { let (key_ty_str, val_ty_str) = separate_kv(&dereference_type(ty_str)); - Rc::new(Type::dict( + Arc::new(Type::dict( parse_type_str(&key_ty_str), parse_type_str(&val_ty_str), )) } else if is_list_type_str(ty_str) { - Rc::new(Type::list(parse_type_str(&dereference_type(ty_str)))) + Arc::new(Type::list(parse_type_str(&dereference_type(ty_str)))) } else { parse_named_type_str(ty_str) } @@ -157,31 +157,31 @@ pub fn split_type_union(ty_str: &str) -> Vec<&str> { } /// Parse union type string. -pub fn parse_union_type_str(ty_str: &str) -> Rc { +pub fn parse_union_type_str(ty_str: &str) -> TypeRef { let types = split_type_union(ty_str) .iter() .map(|ty_str| parse_type_str(ty_str)) - .collect::>>(); + .collect::>(); sup(&types) } /// Parse literal type string. -pub fn parse_lit_type_str(ty_str: &str) -> Rc { +pub fn parse_lit_type_str(ty_str: &str) -> TypeRef { // Bool literal type. if ty_str == NAME_CONSTANT_TRUE { - return Rc::new(Type::bool_lit(true)); + return Arc::new(Type::bool_lit(true)); } else if ty_str == NAME_CONSTANT_FALSE { - return Rc::new(Type::bool_lit(false)); + return Arc::new(Type::bool_lit(false)); } match ty_str.parse::() { // Float literal type. - Ok(v) => Rc::new(Type::int_lit(v)), + Ok(v) => Arc::new(Type::int_lit(v)), Err(_) => match ty_str.parse::() { // Int literal type. - Ok(v) => Rc::new(Type::float_lit(v)), + Ok(v) => Arc::new(Type::float_lit(v)), // Maybe string literal type Err(_) => match str_literal_eval(ty_str, false, false) { - Some(v) => Rc::new(Type::str_lit(&v)), + Some(v) => Arc::new(Type::str_lit(&v)), None => bug!("invalid literal type string {}", ty_str), }, }, @@ -189,8 +189,8 @@ pub fn parse_lit_type_str(ty_str: &str) -> Rc { } /// Parse number multiplier literal type. -pub fn parse_number_multiplier_literal_type_str(ty_str: &str) -> Rc { - let suffix_index = if &ty_str[ty_str.len() - 1..] == kclvm::IEC_SUFFIX { +pub fn parse_number_multiplier_literal_type_str(ty_str: &str) -> TypeRef { + let suffix_index = if &ty_str[ty_str.len() - 1..] == kclvm_runtime::IEC_SUFFIX { ty_str.len() - 2 } else { ty_str.len() - 1 @@ -202,8 +202,8 @@ pub fn parse_number_multiplier_literal_type_str(ty_str: &str) -> Rc { }, &ty_str[suffix_index..], ); - Rc::new(Type::number_multiplier( - kclvm::cal_num(value, suffix), + Arc::new(Type::number_multiplier( + kclvm_runtime::cal_num(value, suffix), value, suffix, )) @@ -211,8 +211,8 @@ pub fn parse_number_multiplier_literal_type_str(ty_str: &str) -> Rc { /// Please note Named type to find it in the scope (e.g. schema type, type alias). #[inline] -pub fn parse_named_type_str(ty_str: &str) -> Rc { - Rc::new(Type::named(ty_str)) +pub fn parse_named_type_str(ty_str: &str) -> TypeRef { + Arc::new(Type::named(ty_str)) } /// separate_kv function separates key_type and value_type in the dictionary type strings, diff --git a/kclvm/sema/src/ty/tests.rs b/kclvm/sema/src/ty/tests.rs index c23ebc5f9..e634ae027 100644 --- a/kclvm/sema/src/ty/tests.rs +++ b/kclvm/sema/src/ty/tests.rs @@ -3,62 +3,62 @@ use super::*; #[test] fn test_sup() { let cases = vec![ - (vec![], Rc::new(Type::ANY)), - (vec![Rc::new(Type::ANY)], Rc::new(Type::ANY)), - (vec![Rc::new(Type::STR)], Rc::new(Type::STR)), + (vec![], Arc::new(Type::ANY)), + (vec![Arc::new(Type::ANY)], Arc::new(Type::ANY)), + (vec![Arc::new(Type::STR)], Arc::new(Type::STR)), ( - vec![Rc::new(Type::STR), Rc::new(Type::INT)], - Type::union_ref(&[Rc::new(Type::STR), Rc::new(Type::INT)]), + vec![Arc::new(Type::STR), Arc::new(Type::INT)], + Type::union_ref(&[Arc::new(Type::STR), Arc::new(Type::INT)]), ), ( - vec![Rc::new(Type::BOOL), Rc::new(Type::bool_lit(true))], - Rc::new(Type::BOOL), + vec![Arc::new(Type::BOOL), Arc::new(Type::bool_lit(true))], + Arc::new(Type::BOOL), ), ( vec![ - Rc::new(Type::str_lit("Blue")), - Rc::new(Type::str_lit("Yellow")), - Rc::new(Type::str_lit("Red")), + Arc::new(Type::str_lit("Blue")), + Arc::new(Type::str_lit("Yellow")), + Arc::new(Type::str_lit("Red")), ], Type::union_ref(&[ - Rc::new(Type::str_lit("Blue")), - Rc::new(Type::str_lit("Yellow")), - Rc::new(Type::str_lit("Red")), + Arc::new(Type::str_lit("Blue")), + Arc::new(Type::str_lit("Yellow")), + Arc::new(Type::str_lit("Red")), ]), ), ( vec![ Type::list_ref(Type::union_ref(&[ - Rc::new(Type::int_lit(1)), - Rc::new(Type::int_lit(2)), + Arc::new(Type::int_lit(1)), + Arc::new(Type::int_lit(2)), ])), Type::list_ref(Type::union_ref(&[ - Rc::new(Type::int_lit(3)), - Rc::new(Type::int_lit(4)), + Arc::new(Type::int_lit(3)), + Arc::new(Type::int_lit(4)), ])), ], Type::union_ref(&[ Type::list_ref(Type::union_ref(&[ - Rc::new(Type::int_lit(1)), - Rc::new(Type::int_lit(2)), + Arc::new(Type::int_lit(1)), + Arc::new(Type::int_lit(2)), ])), Type::list_ref(Type::union_ref(&[ - Rc::new(Type::int_lit(3)), - Rc::new(Type::int_lit(4)), + Arc::new(Type::int_lit(3)), + Arc::new(Type::int_lit(4)), ])), ]), ), ( vec![ Type::union_ref(&[ - Rc::new(Type::STR), - Type::dict_ref(Rc::new(Type::STR), Rc::new(Type::STR)), + Arc::new(Type::STR), + Type::dict_ref(Arc::new(Type::STR), Arc::new(Type::STR)), ]), - Type::dict_ref(Rc::new(Type::ANY), Rc::new(Type::ANY)), + Type::dict_ref(Arc::new(Type::ANY), Arc::new(Type::ANY)), ], Type::union_ref(&[ - Rc::new(Type::STR), - Type::dict_ref(Rc::new(Type::ANY), Rc::new(Type::ANY)), + Arc::new(Type::STR), + Type::dict_ref(Arc::new(Type::ANY), Arc::new(Type::ANY)), ]), ), ]; @@ -70,40 +70,40 @@ fn test_sup() { #[test] fn test_type_walker() { - fn walk_fn(ty: &Type) -> Rc { + fn walk_fn(ty: &Type) -> TypeRef { if ty.is_int() { - Rc::new(Type::STR) + Arc::new(Type::STR) } else { - Rc::new(ty.clone()) + Arc::new(ty.clone()) } } let cases = [ - (Rc::new(Type::ANY), Rc::new(Type::ANY)), - (Rc::new(Type::INT), Rc::new(Type::STR)), - (Rc::new(Type::STR), Rc::new(Type::STR)), + (Arc::new(Type::ANY), Arc::new(Type::ANY)), + (Arc::new(Type::INT), Arc::new(Type::STR)), + (Arc::new(Type::STR), Arc::new(Type::STR)), ( - Type::list_ref(Rc::new(Type::INT)), - Type::list_ref(Rc::new(Type::STR)), + Type::list_ref(Arc::new(Type::INT)), + Type::list_ref(Arc::new(Type::STR)), ), ( - Type::union_ref(&[Rc::new(Type::INT), Rc::new(Type::STR)]), - Type::union_ref(&[Rc::new(Type::STR), Rc::new(Type::STR)]), + Type::union_ref(&[Arc::new(Type::INT), Arc::new(Type::STR)]), + Type::union_ref(&[Arc::new(Type::STR), Arc::new(Type::STR)]), ), ( Type::union_ref(&[ - Rc::new(Type::INT), - Rc::new(Type::STR), - Type::union_ref(&[Rc::new(Type::INT), Rc::new(Type::STR)]), + Arc::new(Type::INT), + Arc::new(Type::STR), + Type::union_ref(&[Arc::new(Type::INT), Arc::new(Type::STR)]), ]), Type::union_ref(&[ - Rc::new(Type::STR), - Rc::new(Type::STR), - Type::union_ref(&[Rc::new(Type::STR), Rc::new(Type::STR)]), + Arc::new(Type::STR), + Arc::new(Type::STR), + Type::union_ref(&[Arc::new(Type::STR), Arc::new(Type::STR)]), ]), ), ( - Type::dict_ref(Rc::new(Type::INT), Rc::new(Type::INT)), - Type::dict_ref(Rc::new(Type::STR), Rc::new(Type::STR)), + Type::dict_ref(Arc::new(Type::INT), Arc::new(Type::INT)), + Type::dict_ref(Arc::new(Type::STR), Arc::new(Type::STR)), ), ]; for (ty, expected) in cases { diff --git a/kclvm/sema/src/ty/unify.rs b/kclvm/sema/src/ty/unify.rs index 331fb0d26..3d1c49de6 100644 --- a/kclvm/sema/src/ty/unify.rs +++ b/kclvm/sema/src/ty/unify.rs @@ -1,12 +1,14 @@ -use std::{collections::HashSet, rc::Rc}; +use std::{collections::HashSet, sync::Arc}; -use super::{SchemaType, Type, TypeKind}; +use indexmap::IndexMap; + +use super::{SchemaType, Type, TypeKind, TypeRef}; /// The type can be assigned to the expected type. /// /// For security and performance considerations, dynamic dispatch of /// types is not supported at this stage. -pub fn subsume(ty_lhs: Rc, ty_rhs: Rc, check_left_any: bool) -> bool { +pub fn subsume(ty_lhs: TypeRef, ty_rhs: TypeRef, check_left_any: bool) -> bool { if (check_left_any && ty_lhs.is_any()) || (ty_rhs.is_any() || ty_lhs.is_none()) { true } else if ty_lhs.is_union() { @@ -64,6 +66,29 @@ pub fn subsume(ty_lhs: Rc, ty_rhs: Rc, check_left_any: bool) -> bool let (ty_rhs_key, ty_rhs_val) = ty_rhs.dict_entry_ty(); subsume(ty_lhs_key, ty_rhs_key, check_left_any) && subsume(ty_lhs_val, ty_rhs_val, check_left_any) + } else if ty_lhs.is_str() && ty_rhs.is_literal() && ty_rhs.is_str() { + return true; + } else if ty_lhs.is_func() && ty_rhs.is_func() { + let ty_lhs_fn_ty = ty_lhs.into_func_type(); + let ty_rhs_fn_ty = ty_rhs.into_func_type(); + let mut is_ok = ty_lhs_fn_ty.params.len() == ty_rhs_fn_ty.params.len(); + for (ty_lhs_param, ty_rhs_param) in + ty_lhs_fn_ty.params.iter().zip(ty_rhs_fn_ty.params.iter()) + { + is_ok = is_ok + && (subsume( + ty_rhs_param.ty.clone(), + ty_lhs_param.ty.clone(), + check_left_any, + )); + } + is_ok = is_ok + && (subsume( + ty_lhs_fn_ty.return_ty.clone(), + ty_rhs_fn_ty.return_ty.clone(), + check_left_any, + )); + is_ok } else { equal(ty_lhs, ty_rhs) } @@ -71,13 +96,13 @@ pub fn subsume(ty_lhs: Rc, ty_rhs: Rc, check_left_any: bool) -> bool /// Are the two types exactly equal. #[inline] -pub fn equal(ty_lhs: Rc, ty_rhs: Rc) -> bool { +pub fn equal(ty_lhs: TypeRef, ty_rhs: TypeRef) -> bool { ty_lhs.kind == ty_rhs.kind } /// Whether the schema is sub schema of another schema. pub fn is_sub_schema_of(schema_ty_lhs: &SchemaType, schema_ty_rhs: &SchemaType) -> bool { - if schema_ty_lhs.ty_str_with_pkgpath() == schema_ty_rhs.ty_str_with_pkgpath() { + if schema_ty_lhs.full_ty_str() == schema_ty_rhs.full_ty_str() { true } else { match &schema_ty_lhs.base { @@ -89,7 +114,7 @@ pub fn is_sub_schema_of(schema_ty_lhs: &SchemaType, schema_ty_rhs: &SchemaType) /// The type can be assigned to the expected type. #[inline] -pub fn assignable_to(ty: Rc, expected_ty: Rc) -> bool { +pub fn assignable_to(ty: TypeRef, expected_ty: TypeRef) -> bool { if !ty.is_assignable_type() { return false; } @@ -98,72 +123,72 @@ pub fn assignable_to(ty: Rc, expected_ty: Rc) -> bool { /// Whether `lhs_ty` is the upper bound of the `rhs_ty` #[inline] -pub fn is_upper_bound(lhs_ty: Rc, rhs_ty: Rc) -> bool { +pub fn is_upper_bound(lhs_ty: TypeRef, rhs_ty: TypeRef) -> bool { subsume(rhs_ty, lhs_ty, false) } /// Whether the type list contains the `any` type. #[inline] -pub fn has_any_type(types: &[Rc]) -> bool { +pub fn has_any_type(types: &[TypeRef]) -> bool { types.iter().any(|ty| ty.is_any()) } /// The sup function returns the minimum supremum of all types in an array of types. #[inline] -pub fn sup(types: &[Rc]) -> Rc { +pub fn sup(types: &[TypeRef]) -> TypeRef { r#typeof(types, true) } /// Typeof types -pub fn r#typeof(types: &[Rc], should_remove_sub_types: bool) -> Rc { +pub fn r#typeof(types: &[TypeRef], should_remove_sub_types: bool) -> TypeRef { // 1. Initialize an ordered set to store the type array - let mut type_set: Vec> = vec![]; + let mut type_set: IndexMap<*const Type, TypeRef> = IndexMap::default(); // 2. Add the type array to the ordered set for sorting by the type id and de-duplication. add_types_to_type_set(&mut type_set, types); // 3. Remove sub types according to partial order relation rules e.g. sub schema types. if should_remove_sub_types { let mut remove_index_set = HashSet::new(); - for (i, source) in type_set.iter().enumerate() { - for (j, target) in type_set.iter().enumerate() { - if i != j && subsume(source.clone(), target.clone(), false) { - remove_index_set.insert(i); + for (i, (source_addr, source)) in type_set.iter().enumerate() { + for j in i + 1..type_set.len() { + let (target_addr, target) = type_set.get_index(j).unwrap(); + if subsume(source.clone(), target.clone(), false) { + remove_index_set.insert(*source_addr); + } else if subsume(target.clone(), source.clone(), false) { + remove_index_set.insert(*target_addr); } } } - let types: Vec<(usize, &Rc)> = type_set - .iter() - .enumerate() - .filter(|(i, _)| !remove_index_set.contains(i)) - .collect(); - type_set = types - .iter() - .map(|(_, ty)| <&Rc>::clone(ty).clone()) - .collect(); + for i in remove_index_set { + type_set.remove(&i); + } } if type_set.is_empty() { - Rc::new(Type::ANY) + Arc::new(Type::ANY) } else if type_set.len() == 1 { type_set[0].clone() } else { - Rc::new(Type::union(&type_set)) + Arc::new(Type::union( + &type_set.values().cloned().collect::>(), + )) } } -fn add_types_to_type_set(type_set: &mut Vec>, types: &[Rc]) { +fn add_types_to_type_set(type_set: &mut IndexMap<*const Type, TypeRef>, types: &[TypeRef]) { for ty in types { add_type_to_type_set(type_set, ty.clone()); } } -fn add_type_to_type_set(type_set: &mut Vec>, ty: Rc) { +fn add_type_to_type_set(type_set: &mut IndexMap<*const Type, TypeRef>, ty: TypeRef) { match &ty.kind { TypeKind::Union(types) => { add_types_to_type_set(type_set, types); } _ => { + let ref_addr = ty.as_ref() as *const Type; // Remove the bottom type. - if !ty.is_void() && !type_set.contains(&ty) { - type_set.push(ty.clone()) + if !ty.is_void() && !type_set.contains_key(&ref_addr) { + type_set.insert(ref_addr, ty.clone()); } } } diff --git a/kclvm/sema/src/ty/walker.rs b/kclvm/sema/src/ty/walker.rs index 3f996ff6c..22deb0609 100644 --- a/kclvm/sema/src/ty/walker.rs +++ b/kclvm/sema/src/ty/walker.rs @@ -1,21 +1,37 @@ -use std::rc::Rc; +use std::sync::Arc; -use super::Type; +use super::{Attr, DictType, Type, TypeRef}; /// Walk one type recursively and deal the type using the `walk_fn` -pub fn walk_type(ty: &Type, walk_fn: impl Fn(&Type) -> Rc + Copy) -> Rc { +pub fn walk_type(ty: &Type, walk_fn: impl Fn(&Type) -> TypeRef + Copy) -> TypeRef { let ty = walk_fn(ty); match &ty.kind { - super::TypeKind::List(item_ty) => Rc::new(Type::list(walk_type(item_ty, walk_fn))), - super::TypeKind::Dict(key_ty, val_ty) => Rc::new(Type::dict( + super::TypeKind::List(item_ty) => Arc::new(Type::list(walk_type(item_ty, walk_fn))), + super::TypeKind::Dict(DictType { + key_ty, + val_ty, + attrs, + }) => Arc::new(Type::dict_with_attrs( walk_type(key_ty, walk_fn), walk_type(val_ty, walk_fn), + attrs + .into_iter() + .map(|(key, attr)| { + ( + key.to_string(), + Attr { + ty: walk_type(&attr.ty, walk_fn), + range: attr.range.clone(), + }, + ) + }) + .collect(), )), - super::TypeKind::Union(types) => Rc::new(Type::union( + super::TypeKind::Union(types) => Arc::new(Type::union( &types .iter() .map(|ty| walk_type(ty, walk_fn)) - .collect::>>(), + .collect::>(), )), _ => ty, } diff --git a/kclvm/span/Cargo.toml b/kclvm/span/Cargo.toml index 3e486eed9..8c7ef5611 100644 --- a/kclvm/span/Cargo.toml +++ b/kclvm/span/Cargo.toml @@ -1,12 +1,13 @@ [package] name = "kclvm-span" -version = "0.1.0" +version = "0.11.0" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -rustc_span = { path = "../3rdparty/rustc_span" } +compiler_base_span = "0.1.2" kclvm-macros = { path = "../macros" } -scoped-tls = "1.0" \ No newline at end of file +scoped-tls = "1.0" +parking_lot = "0.11" diff --git a/kclvm/span/src/lib.rs b/kclvm/span/src/lib.rs index 77c2d81f4..7f50765e6 100644 --- a/kclvm/span/src/lib.rs +++ b/kclvm/span/src/lib.rs @@ -8,21 +8,15 @@ //! Reference: https://github.com/rust-lang/rust/blob/master/compiler/rustc_span/src/lib.rs mod session_globals; -pub mod span; pub mod symbol; #[cfg(test)] mod tests; +pub use compiler_base_span::{BytePos, FilePathMapping, Loc, SourceFile, SourceMap, Span}; pub use session_globals::create_session_globals_then; use session_globals::with_session_globals; -pub use span::{BytePos, Span, DUMMY_SP}; pub use symbol::{Ident, Symbol}; -pub type SourceMap = rustc_span::SourceMap; -pub type SourceFile = rustc_span::SourceFile; -pub type FilePathMapping = rustc_span::source_map::FilePathMapping; -pub type Loc = rustc_span::Loc; - #[macro_use] extern crate kclvm_macros; diff --git a/kclvm/span/src/session_globals.rs b/kclvm/span/src/session_globals.rs index 1791a5d7d..c655a369a 100644 --- a/kclvm/span/src/session_globals.rs +++ b/kclvm/span/src/session_globals.rs @@ -1,6 +1,6 @@ -use std::{cell::RefCell, collections::HashMap}; - use crate::symbol::Symbol; +use parking_lot::Mutex; +use std::{collections::HashMap, sync::Arc}; /// Per-session global variables: this struct is stored in thread-local storage /// in such a way that it is accessible without any kind of handle to all @@ -48,58 +48,57 @@ where SESSION_GLOBALS.with(f) } -// If this ever becomes non thread-local, `decode_syntax_context` -// and `decode_expn_id` will need to be updated to handle concurrent -// deserialization. +// Global sessions to store strings and symbols. scoped_tls::scoped_thread_local!(static SESSION_GLOBALS: SessionGlobals); #[derive(Debug)] -pub struct Interner(RefCell); +pub struct Interner(Arc>); // This type is private to prevent accidentally constructing more than one // `Interner` on the same thread, which makes it easy to mixup `Symbol`s // between `Interner`s. #[derive(Default, Debug)] struct InternerInner { - names: HashMap<&'static str, Symbol>, - strings: Vec<&'static str>, + names: HashMap, + strings: Vec, } impl Default for Interner { fn default() -> Self { - Interner(RefCell::new(InternerInner::default())) + Interner(Arc::new(Mutex::new(InternerInner::default()))) } } impl Interner { pub fn prefill(init: &[&'static str]) -> Self { - Interner(RefCell::new(InternerInner { - strings: init.into(), - names: init.iter().copied().zip((0..).map(Symbol::new)).collect(), - })) + Interner(Arc::new(Mutex::new(InternerInner { + strings: init.iter().map(|s| s.to_string()).collect(), + names: init + .iter() + .map(|s| s.to_string()) + .zip((0..).map(Symbol::new)) + .collect(), + }))) } #[inline] pub fn intern(&self, string: &str) -> Symbol { - let mut inner = self.0.borrow_mut(); + let mut inner = self.0.lock(); if let Some(&name) = inner.names.get(string) { return name; } let name = Symbol::new(inner.strings.len() as u32); - // SAFETY: we can extend the arena allocation to `'static` because we - // only access these while the arena is still alive. - let string: &'static str = Box::leak(Box::new(string.to_string())); - inner.strings.push(string); + inner.strings.push(string.to_string()); - inner.names.insert(string, name); + inner.names.insert(string.to_string(), name); name } // Get the symbol as a string. `Symbol::as_str()` should be used in // preference to this function. - pub fn get(&self, symbol: Symbol) -> &str { - self.0.borrow().strings[symbol.0.idx as usize] + pub fn get(&self, symbol: Symbol) -> String { + self.0.lock().strings[symbol.0.idx as usize].clone() } } diff --git a/kclvm/span/src/span.rs b/kclvm/span/src/span.rs deleted file mode 100644 index 7a9a160c1..000000000 --- a/kclvm/span/src/span.rs +++ /dev/null @@ -1,5 +0,0 @@ -use rustc_span; - -pub type BytePos = rustc_span::BytePos; -pub type Span = rustc_span::Span; -pub const DUMMY_SP: Span = rustc_span::DUMMY_SP; diff --git a/kclvm/span/src/symbol.rs b/kclvm/span/src/symbol.rs index d6e4be7c4..d57abd990 100644 --- a/kclvm/span/src/symbol.rs +++ b/kclvm/span/src/symbol.rs @@ -1,14 +1,11 @@ +use compiler_base_span::{Span, DUMMY_SP}; use std::{ fmt, hash::{Hash, Hasher}, }; -use crate::{ - span::{Span, DUMMY_SP}, - with_session_globals, -}; - use crate::session_globals::Interner; +use crate::with_session_globals; // The proc macro code for this is in `kclvm_macros/src/symbols.rs`. symbols! { @@ -59,12 +56,12 @@ symbols! { /// /// ``` /// use kclvm_span::*; -/// use rustc_span::BytePos; +/// use compiler_base_span::span::new_byte_pos; /// /// create_session_globals_then(||{ /// let ident = Ident::new( /// Symbol::intern("identifier"), -/// Span::new(BytePos(0), BytePos(10)), +/// Span::new(new_byte_pos(0), new_byte_pos(10)), /// ); /// }) /// ``` @@ -112,7 +109,7 @@ impl Ident { /// /// Note that the lifetime of the return value is a lie. See /// `Symbol::as_str()` for details. - pub fn as_str(&self) -> &str { + pub fn as_str(&self) -> String { self.name.as_str() } } @@ -167,10 +164,8 @@ impl Symbol { /// interner. Interners are long-lived, and there are very few of them, and /// this function is typically used for short-lived things, so in practice /// it works out ok. - pub fn as_str(&self) -> &str { - with_session_globals(|session_globals| unsafe { - std::mem::transmute::<&str, &str>(session_globals.symbol_interner.get(*self)) - }) + pub fn as_str(&self) -> String { + with_session_globals(|session_globals| session_globals.symbol_interner.get(*self)) } pub fn as_u32(self) -> u32 { @@ -188,13 +183,13 @@ impl Symbol { impl fmt::Display for Symbol { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Display::fmt(self.as_str(), f) + fmt::Display::fmt(&self.as_str(), f) } } -impl Into for Symbol { - fn into(self) -> String { - self.as_str().to_string() +impl From for String { + fn from(val: Symbol) -> Self { + val.as_str() } } @@ -233,6 +228,15 @@ pub mod sym { } } +pub mod reserved { + + pub use super::reserved_word; + + pub fn is_reserved_word(word: &str) -> bool { + reserved_word::reserved_words.contains(&word) + } +} + /// Special symbols related to KCL keywords. impl Symbol { /// Returns `true` if the symbol is `true` or `false`. diff --git a/kclvm/spec/gpyrpc/gpyrpc.proto b/kclvm/spec/gpyrpc/gpyrpc.proto new file mode 100644 index 000000000..fc7244d22 --- /dev/null +++ b/kclvm/spec/gpyrpc/gpyrpc.proto @@ -0,0 +1,1477 @@ +// Copyright The KCL Authors. All rights reserved. +// +// This file defines the request parameters and return structure of the KCL RPC server. + +syntax = "proto3"; + +package gpyrpc; + +// Message representing an external package for KCL. +// kcl main.k -E pkg_name=pkg_path +message ExternalPkg { + // Name of the package. + string pkg_name = 1; + // Path of the package. + string pkg_path = 2; +} + +// Message representing a key-value argument for KCL. +// kcl main.k -D name=value +message Argument { + // Name of the argument. + string name = 1; + // Value of the argument. + string value = 2; +} + +// ---------------------------------------------------------------------------- +// Error types +// ---------------------------------------------------------------------------- + +// Message representing an error. +message Error { + // Level of the error (e.g., "Error", "Warning"). + string level = 1; + // Error code. (e.g., "E1001") + string code = 2; + // List of error messages. + repeated Message messages = 3; +} + +// Message representing a detailed error message with a position. +message Message { + // The error message text. + string msg = 1; + // The position in the source code where the error occurred. + Position pos = 2; +} + +// ---------------------------------------------------------------------------- +// service request/response +// ---------------------------------------------------------------------------- + +// Service for built-in functionality. +service BuiltinService { + // Sends a ping request. + rpc Ping(Ping_Args) returns (Ping_Result); + // Lists available methods. + rpc ListMethod(ListMethod_Args) returns (ListMethod_Result); +} + +// Service for KCL VM interactions. +service KclvmService { + /// Ping KclvmService, return the same value as the parameter + /// + /// # Examples + /// + /// ```jsonrpc + /// // Request + /// { + /// "jsonrpc": "2.0", + /// "method": "Ping", + /// "params": { + /// "value": "hello" + /// }, + /// "id": 1 + /// } + /// + /// // Response + /// { + /// "jsonrpc": "2.0", + /// "result": { + /// "value": "hello" + /// }, + /// "id": 1 + /// } + /// ``` + rpc Ping(Ping_Args) returns (Ping_Result); + + /// GetVersion KclvmService, return the kclvm service version information + /// + /// # Examples + /// + /// ```jsonrpc + /// // Request + /// { + /// "jsonrpc": "2.0", + /// "method": "GetVersion", + /// "params": {}, + /// "id": 1 + /// } + /// + /// // Response + /// { + /// "jsonrpc": "2.0", + /// "result": { + /// "version": "0.9.1", + /// "checksum": "c020ab3eb4b9179219d6837a57f5d323", + /// "git_sha": "1a9a72942fffc9f62cb8f1ae4e1d5ca32aa1f399", + /// "version_info": "Version: 0.9.1-c020ab3eb4b9179219d6837a57f5d323\nPlatform: aarch64-apple-darwin\nGitCommit: 1a9a72942fffc9f62cb8f1ae4e1d5ca32aa1f399" + /// }, + /// "id": 1 + /// } + /// ``` + rpc GetVersion(GetVersion_Args) returns (GetVersion_Result); + + /// Parse KCL program with entry files. + /// + /// # Examples + /// + /// ```jsonrpc + /// // Request + /// { + /// "jsonrpc": "2.0", + /// "method": "ParseProgram", + /// "params": { + /// "paths": ["./src/testdata/test.k"] + /// }, + /// "id": 1 + /// } + /// + /// // Response + /// { + /// "jsonrpc": "2.0", + /// "result": { + /// "ast_json": "{...}", + /// "paths": ["./src/testdata/test.k"], + /// "errors": [] + /// }, + /// "id": 1 + /// } + /// ``` + rpc ParseProgram(ParseProgram_Args) returns (ParseProgram_Result); + + /// Parse KCL single file to Module AST JSON string with import dependencies + /// and parse errors. + /// + /// # Examples + /// + /// ```jsonrpc + /// // Request + /// { + /// "jsonrpc": "2.0", + /// "method": "ParseFile", + /// "params": { + /// "path": "./src/testdata/parse/main.k" + /// }, + /// "id": 1 + /// } + /// + /// // Response + /// { + /// "jsonrpc": "2.0", + /// "result": { + /// "ast_json": "{...}", + /// "deps": ["./dep1", "./dep2"], + /// "errors": [] + /// }, + /// "id": 1 + /// } + /// ``` + rpc ParseFile(ParseFile_Args) returns (ParseFile_Result); + + /// load_package provides users with the ability to parse kcl program and semantic model + /// information including symbols, types, definitions, etc. + /// + /// # Examples + /// + /// ```jsonrpc + /// // Request + /// { + /// "jsonrpc": "2.0", + /// "method": "LoadPackage", + /// "params": { + /// "parse_args": { + /// "paths": ["./src/testdata/parse/main.k"] + /// }, + /// "resolve_ast": true + /// }, + /// "id": 1 + /// } + /// + /// // Response + /// { + /// "jsonrpc": "2.0", + /// "result": { + /// "program": "{...}", + /// "paths": ["./src/testdata/parse/main.k"], + /// "parse_errors": [], + /// "type_errors": [], + /// "symbols": { ... }, + /// "scopes": { ... }, + /// "node_symbol_map": { ... }, + /// "symbol_node_map": { ... }, + /// "fully_qualified_name_map": { ... }, + /// "pkg_scope_map": { ... } + /// }, + /// "id": 1 + /// } + /// ``` + rpc LoadPackage(LoadPackage_Args) returns (LoadPackage_Result); + + /// list_options provides users with the ability to parse kcl program and get all option information. + /// + /// # Examples + /// + /// ```jsonrpc + /// // Request + /// { + /// "jsonrpc": "2.0", + /// "method": "ListOptions", + /// "params": { + /// "paths": ["./src/testdata/option/main.k"] + /// }, + /// "id": 1 + /// } + /// + /// // Response + /// { + /// "jsonrpc": "2.0", + /// "result": { + /// "options": [ + /// { "name": "option1", "type": "str", "required": true, "default_value": "", "help": "option 1 help" }, + /// { "name": "option2", "type": "int", "required": false, "default_value": "0", "help": "option 2 help" }, + /// { "name": "option3", "type": "bool", "required": false, "default_value": "false", "help": "option 3 help" } + /// ] + /// }, + /// "id": 1 + /// } + /// ``` + rpc ListOptions(ParseProgram_Args) returns (ListOptions_Result); + + /// list_variables provides users with the ability to parse kcl program and get all variables by specs. + /// + /// # Examples + /// + /// ```jsonrpc + /// // Request + /// { + /// "jsonrpc": "2.0", + /// "method": "ListVariables", + /// "params": { + /// "files": ["./src/testdata/variables/main.k"], + /// "specs": ["a"] + /// }, + /// "id": 1 + /// } + /// + /// // Response + /// { + /// "jsonrpc": "2.0", + /// "result": { + /// "variables": { + /// "a": { + /// "variables": [ + /// { "value": "1", "type_name": "int", "op_sym": "", "list_items": [], "dict_entries": [] } + /// ] + /// } + /// }, + /// "unsupported_codes": [], + /// "parse_errors": [] + /// }, + /// "id": 1 + /// } + /// ``` + rpc ListVariables(ListVariables_Args) returns (ListVariables_Result); + + /// Execute KCL file with args. **Note that it is not thread safe.** + /// + /// # Examples + /// + /// ```jsonrpc + /// // Request + /// { + /// "jsonrpc": "2.0", + /// "method": "ExecProgram", + /// "params": { + /// "work_dir": "./src/testdata", + /// "k_filename_list": ["test.k"] + /// }, + /// "id": 1 + /// } + /// + /// // Response + /// { + /// "jsonrpc": "2.0", + /// "result": { + /// "json_result": "{\"alice\": {\"age\": 18}}", + /// "yaml_result": "alice:\n age: 18", + /// "log_message": "", + /// "err_message": "" + /// }, + /// "id": 1 + /// } + /// + /// // Request with code + /// { + /// "jsonrpc": "2.0", + /// "method": "ExecProgram", + /// "params": { + /// "k_filename_list": ["file.k"], + /// "k_code_list": ["alice = {age = 18}"] + /// }, + /// "id": 2 + /// } + /// + /// // Response + /// { + /// "jsonrpc": "2.0", + /// "result": { + /// "json_result": "{\"alice\": {\"age\": 18}}", + /// "yaml_result": "alice:\n age: 18", + /// "log_message": "", + /// "err_message": "" + /// }, + /// "id": 2 + /// } + /// + /// // Error case - cannot find file + /// { + /// "jsonrpc": "2.0", + /// "method": "ExecProgram", + /// "params": { + /// "k_filename_list": ["invalid_file.k"] + /// }, + /// "id": 3 + /// } + /// + /// // Error Response + /// { + /// "jsonrpc": "2.0", + /// "error": { + /// "code": -32602, + /// "message": "Cannot find the kcl file" + /// }, + /// "id": 3 + /// } + /// + /// // Error case - no input files + /// { + /// "jsonrpc": "2.0", + /// "method": "ExecProgram", + /// "params": { + /// "k_filename_list": [] + /// }, + /// "id": 4 + /// } + /// + /// // Error Response + /// { + /// "jsonrpc": "2.0", + /// "error": { + /// "code": -32602, + /// "message": "No input KCL files or paths" + /// }, + /// "id": 4 + /// } + /// ``` + rpc ExecProgram(ExecProgram_Args) returns (ExecProgram_Result); + + /// Build the KCL program to an artifact. + /// + /// # Examples + /// + /// ```jsonrpc + /// // Request + /// { + /// "jsonrpc": "2.0", + /// "method": "BuildProgram", + /// "params": { + /// "exec_args": { + /// "work_dir": "./src/testdata", + /// "k_filename_list": ["test.k"] + /// }, + /// "output": "./build" + /// }, + /// "id": 1 + /// } + /// + /// // Response + /// { + /// "jsonrpc": "2.0", + /// "result": { + /// "path": "./build/test.k" + /// }, + /// "id": 1 + /// } + /// ``` + rpc BuildProgram(BuildProgram_Args) returns (BuildProgram_Result); + + /// Execute the KCL artifact with args. **Note that it is not thread safe.** + /// + /// # Examples + /// + /// ```jsonrpc + /// // Request + /// { + /// "jsonrpc": "2.0", + /// "method": "ExecArtifact", + /// "params": { + /// "path": "./artifact_path", + /// "exec_args": { + /// "work_dir": "./src/testdata", + /// "k_filename_list": ["test.k"] + /// } + /// }, + /// "id": 1 + /// } + /// + /// // Response + /// { + /// "jsonrpc": "2.0", + /// "result": { + /// "json_result": "{\"alice\": {\"age\": 18}}", + /// "yaml_result": "alice:\n age: 18", + /// "log_message": "", + /// "err_message": "" + /// }, + /// "id": 1 + /// } + /// ``` + rpc ExecArtifact(ExecArtifact_Args) returns (ExecProgram_Result); + + /// Override KCL file with args. + /// + /// # Examples + /// + /// ```jsonrpc + /// // Request + /// { + /// "jsonrpc": "2.0", + /// "method": "OverrideFile", + /// "params": { + /// "file": "./src/testdata/test.k", + /// "specs": ["alice.age=18"] + /// }, + /// "id": 1 + /// } + /// + /// // Response + /// { + /// "jsonrpc": "2.0", + /// "result": { + /// "result": true, + /// "parse_errors": [] + /// }, + /// "id": 1 + /// } + /// ``` + rpc OverrideFile(OverrideFile_Args) returns (OverrideFile_Result); + + /// Get schema type mapping. + /// + /// # Examples + /// + /// ```jsonrpc + /// // Request + /// { + /// "jsonrpc": "2.0", + /// "method": "GetSchemaTypeMapping", + /// "params": { + /// "exec_args": { + /// "work_dir": "./src/testdata", + /// "k_filename_list": ["main.k"], + /// "external_pkgs": [ + /// { + /// "pkg_name":"pkg", + /// "pkg_path": "./src/testdata/pkg" + /// } + /// ] + /// }, + /// "schema_name": "Person" + /// }, + /// "id": 1 + /// } + /// + /// // Response + /// { + /// "jsonrpc": "2.0", + /// "result": { + /// "schema_type_mapping": { + /// "Person": { + /// "type": "schema", + /// "schema_name": "Person", + /// "properties": { + /// "name": { "type": "str" }, + /// "age": { "type": "int" } + /// }, + /// "required": ["name", "age"], + /// "decorators": [] + /// } + /// } + /// }, + /// "id": 1 + /// } + /// ``` + rpc GetSchemaTypeMapping(GetSchemaTypeMapping_Args) returns (GetSchemaTypeMapping_Result); + + /// Format code source. + /// + /// # Examples + /// + /// ```jsonrpc + /// // Request + /// { + /// "jsonrpc": "2.0", + /// "method": "FormatCode", + /// "params": { + /// "source": "schema Person {\n name: str\n age: int\n}\nperson = Person {\n name = \"Alice\"\n age = 18\n}\n" + /// }, + /// "id": 1 + /// } + /// + /// // Response + /// { + /// "jsonrpc": "2.0", + /// "result": { + /// "formatted": "schema Person {\n name: str\n age: int\n}\nperson = Person {\n name = \"Alice\"\n age = 18\n}\n" + /// }, + /// "id": 1 + /// } + /// ``` + rpc FormatCode(FormatCode_Args) returns (FormatCode_Result); + + /// Format KCL file or directory path contains KCL files and returns the changed file paths. + /// + /// # Examples + /// + /// ```jsonrpc + /// // Request + /// { + /// "jsonrpc": "2.0", + /// "method": "FormatPath", + /// "params": { + /// "path": "./src/testdata/test.k" + /// }, + /// "id": 1 + /// } + /// + /// // Response + /// { + /// "jsonrpc": "2.0", + /// "result": { + /// "changed_paths": [] + /// }, + /// "id": 1 + /// } + /// ``` + rpc FormatPath(FormatPath_Args) returns (FormatPath_Result); + + /// Lint files and return error messages including errors and warnings. + /// + /// # Examples + /// + /// ```jsonrpc + /// // Request + /// { + /// "jsonrpc": "2.0", + /// "method": "LintPath", + /// "params": { + /// "paths": ["./src/testdata/test-lint.k"] + /// }, + /// "id": 1 + /// } + /// + /// // Response + /// { + /// "jsonrpc": "2.0", + /// "result": { + /// "results": ["Module 'math' imported but unused"] + /// }, + /// "id": 1 + /// } + /// ``` + rpc LintPath(LintPath_Args) returns (LintPath_Result); + + /// Validate code using schema and data strings. + /// + /// **Note that it is not thread safe.** + /// + /// # Examples + /// + /// ```jsonrpc + /// // Request + /// { + /// "jsonrpc": "2.0", + /// "method": "ValidateCode", + /// "params": { + /// "code": "schema Person {\n name: str\n age: int\n check: 0 < age < 120\n}", + /// "data": "{\"name\": \"Alice\", \"age\": 10}" + /// }, + /// "id": 1 + /// } + /// + /// // Response + /// { + /// "jsonrpc": "2.0", + /// "result": { + /// "success": true, + /// "err_message": "" + /// }, + /// "id": 1 + /// } + /// ``` + rpc ValidateCode(ValidateCode_Args) returns (ValidateCode_Result); + + rpc ListDepFiles(ListDepFiles_Args) returns (ListDepFiles_Result); + /// Build setting file config from args. + /// + /// # Examples + /// + /// + /// // Request + /// { + /// "jsonrpc": "2.0", + /// "method": "LoadSettingsFiles", + /// "params": { + /// "work_dir": "./src/testdata/settings", + /// "files": ["./src/testdata/settings/kcl.yaml"] + /// }, + /// "id": 1 + /// } + /// + /// // Response + /// { + /// "jsonrpc": "2.0", + /// "result": { + /// "kcl_cli_configs": { + /// "files": ["./src/testdata/settings/kcl.yaml"], + /// "output": "", + /// "overrides": [], + /// "path_selector": [], + /// "strict_range_check": false, + /// "disable_none": false, + /// "verbose": 0, + /// "debug": false, + /// "sort_keys": false, + /// "show_hidden": false, + /// "include_schema_type_path": false, + /// "fast_eval": false + /// }, + /// "kcl_options": [] + /// }, + /// "id": 1 + /// } + /// ``` + rpc LoadSettingsFiles(LoadSettingsFiles_Args) returns (LoadSettingsFiles_Result); + + /// Rename all the occurrences of the target symbol in the files. This API will rewrite files if they contain symbols to be renamed. + /// Return the file paths that got changed. + /// + /// # Examples + /// + /// + /// // Request + /// { + /// "jsonrpc": "2.0", + /// "method": "Rename", + /// "params": { + /// "package_root": "./src/testdata/rename_doc", + /// "symbol_path": "a", + /// "file_paths": ["./src/testdata/rename_doc/main.k"], + /// "new_name": "a2" + /// }, + /// "id": 1 + /// } + /// + /// // Response + /// { + /// "jsonrpc": "2.0", + /// "result": { + /// "changed_files": ["./src/testdata/rename_doc/main.k"] + /// }, + /// "id": 1 + /// } + /// ``` + rpc Rename(Rename_Args) returns (Rename_Result); + + /// Rename all the occurrences of the target symbol and return the modified code if any code has been changed. This API won't rewrite files but return the changed code. + /// + /// # Examples + /// + /// + /// // Request + /// { + /// "jsonrpc": "2.0", + /// "method": "RenameCode", + /// "params": { + /// "package_root": "/mock/path", + /// "symbol_path": "a", + /// "source_codes": { + /// "/mock/path/main.k": "a = 1\nb = a" + /// }, + /// "new_name": "a2" + /// }, + /// "id": 1 + /// } + /// + /// // Response + /// { + /// "jsonrpc": "2.0", + /// "result": { + /// "changed_codes": { + /// "/mock/path/main.k": "a2 = 1\nb = a2" + /// } + /// }, + /// "id": 1 + /// } + /// ``` + rpc RenameCode(RenameCode_Args) returns (RenameCode_Result); + + /// Test KCL packages with test arguments. + /// + /// # Examples + /// + /// + /// // Request + /// { + /// "jsonrpc": "2.0", + /// "method": "Test", + /// "params": { + /// "exec_args": { + /// "work_dir": "./src/testdata/testing/module", + /// "k_filename_list": ["main.k"] + /// }, + /// "pkg_list": ["./src/testdata/testing/module/..."] + /// }, + /// "id": 1 + /// } + /// + /// // Response + /// { + /// "jsonrpc": "2.0", + /// "result": { + /// "info": [ + /// {"name": "test_case_1", "error": "", "duration": 1000, "log_message": ""}, + /// {"name": "test_case_2", "error": "some error", "duration": 2000, "log_message": ""} + /// ] + /// }, + /// "id": 1 + /// } + /// ``` + rpc Test(Test_Args) returns (Test_Result); + + /// Download and update dependencies defined in the kcl.mod file. + /// + /// # Examples + /// + /// + /// // Request + /// { + /// "jsonrpc": "2.0", + /// "method": "UpdateDependencies", + /// "params": { + /// "manifest_path": "./src/testdata/update_dependencies" + /// }, + /// "id": 1 + /// } + /// + /// // Response + /// { + /// "jsonrpc": "2.0", + /// "result": { + /// "external_pkgs": [ + /// {"pkg_name": "pkg1", "pkg_path": "./src/testdata/update_dependencies/pkg1"} + /// ] + /// }, + /// "id": 1 + /// } + /// + /// // Request with vendor flag + /// { + /// "jsonrpc": "2.0", + /// "method": "UpdateDependencies", + /// "params": { + /// "manifest_path": "./src/testdata/update_dependencies", + /// "vendor": true + /// }, + /// "id": 2 + /// } + /// + /// // Response + /// { + /// "jsonrpc": "2.0", + /// "result": { + /// "external_pkgs": [ + /// {"pkg_name": "pkg1", "pkg_path": "./src/testdata/update_dependencies/pkg1"} + /// ] + /// }, + /// "id": 2 + /// } + /// ``` + rpc UpdateDependencies(UpdateDependencies_Args) returns (UpdateDependencies_Result); +} + +// Message for ping request arguments. +message Ping_Args { + // Value to be sent in the ping request. + string value = 1; +} + +// Message for ping response. +message Ping_Result { + // Value received in the ping response. + string value = 1; +} + +// Message for version request arguments. Empty message. +message GetVersion_Args { + // empty +} + +// Message for version response. +message GetVersion_Result { + // KCL version. + string version = 1; + // Checksum of the KCL version. + string checksum = 2; + // Git Git SHA of the KCL code repo. + string git_sha = 3; + // Detailed version information as a string. + string version_info = 4; +} + +// Message for list method request arguments. Empty message. +message ListMethod_Args { + // empty +} + +// Message for list method response. +message ListMethod_Result { + // List of available method names. + repeated string method_name_list = 1; +} + +// Message for parse file request arguments. +message ParseFile_Args { + // Path of the file to be parsed. + string path = 1; + // Source code to be parsed. + string source = 2; + // External packages path. + repeated ExternalPkg external_pkgs = 3; +} + +// Message for parse file response. +message ParseFile_Result { + // Abstract Syntax Tree (AST) in JSON format. + string ast_json = 1; + // File dependency paths. + repeated string deps = 2; + // List of parse errors. + repeated Error errors = 3; +} + +// Message for parse program request arguments. +message ParseProgram_Args { + // Paths of the program files to be parsed. + repeated string paths = 1; + // Source codes to be parsed. + repeated string sources = 2; + // External packages path. + repeated ExternalPkg external_pkgs = 3; +} + +// Message for parse program response. +message ParseProgram_Result { + // Abstract Syntax Tree (AST) in JSON format. + string ast_json = 1; + // Returns the files in the order they should be compiled. + repeated string paths = 2; + // List of parse errors. + repeated Error errors = 3; +} + +// Message for load package request arguments. +message LoadPackage_Args { + // Arguments for parsing the program. + ParseProgram_Args parse_args = 1; + // Flag indicating whether to resolve AST. + bool resolve_ast = 2; + // Flag indicating whether to load built-in modules. + bool load_builtin = 3; + // Flag indicating whether to include AST index. + bool with_ast_index = 4; +} + +// Message for load package response. +message LoadPackage_Result { + // Program Abstract Syntax Tree (AST) in JSON format. + string program = 1; + // Returns the files in the order they should be compiled. + repeated string paths = 2; + // List of parse errors. + repeated Error parse_errors = 3; + // List of type errors. + repeated Error type_errors = 4; + // Map of scopes with scope index as key. + map scopes = 5; + // Map of symbols with symbol index as key. + map symbols = 6; + // Map of node-symbol associations with AST index UUID as key. + map node_symbol_map = 7; + // Map of symbol-node associations with symbol index as key. + map symbol_node_map = 8; + // Map of fully qualified names with symbol index as key. + map fully_qualified_name_map = 9; + // Map of package scope with package path as key. + map pkg_scope_map = 10; +} + +// Message for list options response. +message ListOptions_Result { + // List of available options. + repeated OptionHelp options = 2; +} + +// Message representing a help option. +message OptionHelp { + // Name of the option. + string name = 1; + // Type of the option. + string type = 2; + // Flag indicating if the option is required. + bool required = 3; + // Default value of the option. + string default_value = 4; + // Help text for the option. + string help = 5; +} + +// Message representing a symbol in KCL. +message Symbol { + // Type of the symbol. + KclType ty = 1; + // Name of the symbol. + string name = 2; + // Owner of the symbol. + SymbolIndex owner = 3; + // Definition of the symbol. + SymbolIndex def = 4; + // Attributes of the symbol. + repeated SymbolIndex attrs = 5; + // Flag indicating if the symbol is global. + bool is_global = 6; +} + +// Message representing a scope in KCL. +message Scope { + // Type of the scope. + string kind = 1; + // Parent scope. + ScopeIndex parent = 2; + // Owner of the scope. + SymbolIndex owner = 3; + // Children of the scope. + repeated ScopeIndex children = 4; + // Definitions in the scope. + repeated SymbolIndex defs = 5; +} + +// Message representing a symbol index. +message SymbolIndex { + // Index identifier. + uint64 i = 1; + // Global identifier. + uint64 g = 2; + // Type of the symbol or scope. + string kind = 3; +} + +// Message representing a scope index. +message ScopeIndex { + // Index identifier. + uint64 i = 1; + // Global identifier. + uint64 g = 2; + // Type of the scope. + string kind = 3; +} + +// Message for execute program request arguments. +message ExecProgram_Args { + // Working directory. + string work_dir = 1; + // List of KCL filenames. + repeated string k_filename_list = 2; + // List of KCL codes. + repeated string k_code_list = 3; + // Arguments for the program. + repeated Argument args = 4; + // Override configurations. + repeated string overrides = 5; + // Flag to disable YAML result. + bool disable_yaml_result = 6; + // Flag to print override AST. + bool print_override_ast = 7; + // Flag for strict range check. + bool strict_range_check = 8; + // Flag to disable none values. + bool disable_none = 9; + // Verbose level. + int32 verbose = 10; + // Debug level. + int32 debug = 11; + // Flag to sort keys in YAML/JSON results. + bool sort_keys = 12; + // External packages path. + repeated ExternalPkg external_pkgs = 13; + // Flag to include schema type path in results. + bool include_schema_type_path = 14; + // Flag to compile only without execution. + bool compile_only = 15; + // Flag to show hidden attributes. + bool show_hidden = 16; + // Path selectors for results. + repeated string path_selector = 17; + // Flag for fast evaluation. + bool fast_eval = 18; +} + +// Message for execute program response. +message ExecProgram_Result { + // Result in JSON format. + string json_result = 1; + // Result in YAML format. + string yaml_result = 2; + // Log message from execution. + string log_message = 3; + // Error message from execution. + string err_message = 4; +} + +// Message for build program request arguments. +message BuildProgram_Args { + // Arguments for executing the program. + ExecProgram_Args exec_args = 1; + // Output path. + string output = 2; +} + +// Message for build program response. +message BuildProgram_Result { + // Path of the built program. + string path = 1; +} + +// Message for execute artifact request arguments. +message ExecArtifact_Args { + // Path of the artifact. + string path = 1; + // Arguments for executing the program. + ExecProgram_Args exec_args = 2; +} + +// Message for format code request arguments. +message FormatCode_Args { + // Source code to be formatted. + string source = 1; +} + +// Message for format code response. +message FormatCode_Result { + // Formatted code as bytes. + bytes formatted = 1; +} + +// Message for format file path request arguments. +message FormatPath_Args { + // Path of the file to format. + string path = 1; +} + +// Message for format file path response. +message FormatPath_Result { + // List of changed file paths. + repeated string changed_paths = 1; +} + +// Message for lint file path request arguments. +message LintPath_Args { + // Paths of the files to lint. + repeated string paths = 1; +} + +// Message for lint file path response. +message LintPath_Result { + // List of lint results. + repeated string results = 1; +} + +// Message for override file request arguments. +message OverrideFile_Args { + // Path of the file to override. + string file = 1; + // List of override specifications. + repeated string specs = 2; + // List of import paths. + repeated string import_paths = 3; +} + +// Message for override file response. +message OverrideFile_Result { + // Result of the override operation. + bool result = 1; + // List of parse errors encountered. + repeated Error parse_errors = 2; +} + +// Message for list variables options. +message ListVariables_Options { + // Flag to merge program configuration. + bool merge_program = 1; +} + +// Message representing a list of variables. +message VariableList { + // List of variables. + repeated Variable variables = 1; +} + +// Message for list variables request arguments. +message ListVariables_Args { + // Files to be processed. + repeated string files = 1; + // Specifications for variables. + repeated string specs = 2; + // Options for listing variables. + ListVariables_Options options = 3; +} + +// Message for list variables response. +message ListVariables_Result { + // Map of variable lists by file. + map variables = 1; + // List of unsupported codes. + repeated string unsupported_codes = 2; + // List of parse errors encountered. + repeated Error parse_errors = 3; +} + +// Message representing a variable. +message Variable { + // Value of the variable. + string value = 1; + // Type name of the variable. + string type_name = 2; + // Operation symbol associated with the variable. + string op_sym = 3; + // List items if the variable is a list. + repeated Variable list_items = 4; + // Dictionary entries if the variable is a dictionary. + repeated MapEntry dict_entries = 5; +} + +// Message representing a map entry. +message MapEntry { + // Key of the map entry. + string key = 1; + // Value of the map entry. + Variable value = 2; +} + +// Message for get schema type mapping request arguments. +message GetSchemaTypeMapping_Args { + // Arguments for executing the program. + ExecProgram_Args exec_args = 1; + // Name of the schema. + string schema_name = 2; +} + +// Message for get schema type mapping response. +message GetSchemaTypeMapping_Result { + // Map of schema type mappings. + map schema_type_mapping = 1; +} + +// Message for get schema type mapping response. +message GetSchemaTypeMappingUnderPath_Result { + // Map of pkg and schema types mappings. + map schema_type_mapping = 1; +} + +message SchemaTypes { + // List of schema type mappings. + repeated KclType schema_type = 1; +} + +// Message for validate code request arguments. +message ValidateCode_Args { + // Path to the data file. + string datafile = 1; + // Data content. + string data = 2; + // Path to the code file. + string file = 3; + // Source code content. + string code = 4; + // Name of the schema. + string schema = 5; + // Name of the attribute. + string attribute_name = 6; + // Format of the validation (e.g., "json", "yaml"). + string format = 7; +} + +// Message for validate code response. +message ValidateCode_Result { + // Flag indicating if validation was successful. + bool success = 1; + // Error message from validation. + string err_message = 2; +} + +// Message representing a position in the source code. +message Position { + // Line number. + int64 line = 1; + // Column number. + int64 column = 2; + // Filename the position refers to. + string filename = 3; +} + +// Message for list dependency files request arguments. +message ListDepFiles_Args { + // Working directory. + string work_dir = 1; + // Flag to use absolute paths. + bool use_abs_path = 2; + // Flag to include all files. + bool include_all = 3; + // Flag to use fast parser. + bool use_fast_parser = 4; +} + +// Message for list dependency files response. +message ListDepFiles_Result { + // Root package path. + string pkgroot = 1; + // Package path. + string pkgpath = 2; + // List of file paths in the package. + repeated string files = 3; +} + +// --------------------------------------------------------------------------------- +// LoadSettingsFiles API +// Input work dir and setting files and return the merged kcl singleton config. +// --------------------------------------------------------------------------------- + +// Message for load settings files request arguments. +message LoadSettingsFiles_Args { + // Working directory. + string work_dir = 1; + // Setting files to load. + repeated string files = 2; +} + +// Message for load settings files response. +message LoadSettingsFiles_Result { + // KCL CLI configuration. + CliConfig kcl_cli_configs = 1; + // List of KCL options as key-value pairs. + repeated KeyValuePair kcl_options = 2; +} + +// Message representing KCL CLI configuration. +message CliConfig { + // List of files. + repeated string files = 1; + // Output path. + string output = 2; + // List of overrides. + repeated string overrides = 3; + // Path selectors. + repeated string path_selector = 4; + // Flag for strict range check. + bool strict_range_check = 5; + // Flag to disable none values. + bool disable_none = 6; + // Verbose level. + int64 verbose = 7; + // Debug flag. + bool debug = 8; + // Flag to sort keys in YAML/JSON results. + bool sort_keys = 9; + // Flag to show hidden attributes. + bool show_hidden = 10; + // Flag to include schema type path in results. + bool include_schema_type_path = 11; + // Flag for fast evaluation. + bool fast_eval = 12; +} + +// Message representing a key-value pair. +message KeyValuePair { + // Key of the pair. + string key = 1; + // Value of the pair. + string value = 2; +} + +// --------------------------------------------------------------------------------- +// Rename API +// Find all the occurrences of the target symbol and rename them. +// This API will rewrite files if they contain symbols to be renamed. +// --------------------------------------------------------------------------------- + +// Message for rename request arguments. +message Rename_Args { + // File path to the package root. + string package_root = 1; + // Path to the target symbol to be renamed. + string symbol_path = 2; + // Paths to the source code files. + repeated string file_paths = 3; + // New name of the symbol. + string new_name = 4; +} + +// Message for rename response. +message Rename_Result { + // List of file paths that got changed. + repeated string changed_files = 1; +} + +// --------------------------------------------------------------------------------- +// RenameCode API +// Find all the occurrences of the target symbol and rename them. +// This API won't rewrite files but return the modified code if any code has been changed. +// --------------------------------------------------------------------------------- + +// Message for rename code request arguments. +message RenameCode_Args { + // File path to the package root. + string package_root = 1; + // Path to the target symbol to be renamed. + string symbol_path = 2; + // Map of source code with filename as key and code as value. + map source_codes = 3; + // New name of the symbol. + string new_name = 4; +} + +// Message for rename code response. +message RenameCode_Result { + // Map of changed code with filename as key and modified code as value. + map changed_codes = 1; +} + +// --------------------------------------------------------------------------------- +// Test API +// Test KCL packages with test arguments. +// --------------------------------------------------------------------------------- + +// Message for test request arguments. +message Test_Args { + // Execution program arguments. + ExecProgram_Args exec_args = 1; + // List of KCL package paths to be tested. + repeated string pkg_list = 2; + // Regular expression for filtering tests to run. + string run_regexp = 3; + // Flag to stop the test run on the first failure. + bool fail_fast = 4; +} + +// Message for test response. +message Test_Result { + // List of test case information. + repeated TestCaseInfo info = 2; +} + +// Message representing information about a single test case. +message TestCaseInfo { + // Name of the test case. + string name = 1; + // Error message if any. + string error = 2; + // Duration of the test case in microseconds. + uint64 duration = 3; + // Log message from the test case. + string log_message = 4; +} + +// --------------------------------------------------------------------------------- +// UpdateDependencies API +// Download and update dependencies defined in the kcl.mod file. +// --------------------------------------------------------------------------------- + +// Message for update dependencies request arguments. +message UpdateDependencies_Args { + // Path to the manifest file. + string manifest_path = 1; + // Flag to vendor dependencies locally. + bool vendor = 2; +} + +// Message for update dependencies response. +message UpdateDependencies_Result { + // List of external packages updated. + repeated ExternalPkg external_pkgs = 3; +} + +// ---------------------------------------------------------------------------- +// KCL Type Structure +// ---------------------------------------------------------------------------- + +// Message representing a KCL type. +message KclType { + // Type name (e.g., schema, dict, list, str, int, float, bool, any, union, number_multiplier). + string type = 1; + // Union types if applicable. + repeated KclType union_types = 2; + // Default value of the type. + string default = 3; + // Name of the schema if applicable. + string schema_name = 4; + // Documentation for the schema. + string schema_doc = 5; + // Properties of the schema as a map with property name as key. + map properties = 6; + // List of required schema properties. + repeated string required = 7; + // Key type if the KclType is a dictionary. + KclType key = 8; + // Item type if the KclType is a list or dictionary. + KclType item = 9; + // Line number where the type is defined. + int32 line = 10; + // List of decorators for the schema. + repeated Decorator decorators = 11; + // Absolute path of the file where the attribute is located. + string filename = 12; + // Path of the package where the attribute is located. + string pkg_path = 13; + // Documentation for the attribute. + string description = 14; + // Map of examples with example name as key. + map examples = 15; + // Base schema if applicable. + KclType base_schema = 16; +} + +// Message representing a decorator in KCL. +message Decorator { + // Name of the decorator. + string name = 1; + // Arguments for the decorator. + repeated string arguments = 2; + // Keyword arguments for the decorator as a map with keyword name as key. + map keywords = 3; +} + +// Message representing an example in KCL. +message Example { + // Short description for the example. + string summary = 1; + // Long description for the example. + string description = 2; + // Embedded literal example. + string value = 3; +} + +// ---------------------------------------------------------------------------- +// END +// ---------------------------------------------------------------------------- diff --git a/kclvm/src/capi.rs b/kclvm/src/capi.rs new file mode 100644 index 000000000..feea2d0bf --- /dev/null +++ b/kclvm/src/capi.rs @@ -0,0 +1,261 @@ +#![allow(clippy::missing_safety_doc)] + +use kclvm_runner::runner::KCL_RUNTIME_PANIC_RECORD; +use std::alloc::{alloc, dealloc, Layout}; +use std::ffi::c_char; +use std::ffi::{CStr, CString}; +use std::{mem, ptr}; + +use crate::{intern_fmt, intern_run}; + +/// Exposes an allocation function to the WASM host. +/// +/// _This implementation is copied from wasm-bindgen_ +#[no_mangle] +pub unsafe extern "C" fn kcl_malloc(size: usize) -> *mut u8 { + let align = mem::align_of::(); + let layout = Layout::from_size_align(size, align).expect("Invalid layout"); + if layout.size() > 0 { + let ptr = alloc(layout); + if !ptr.is_null() { + ptr::write_bytes(ptr, 0, size); + ptr + } else { + std::alloc::handle_alloc_error(layout); + } + } else { + align as *mut u8 + } +} + +/// Expose a deallocation function to the WASM host. +/// +/// _This implementation is copied from wasm-bindgen_ +#[no_mangle] +pub unsafe extern "C" fn kcl_free(ptr: *mut u8, size: usize) { + // This happens for zero-length slices, and in that case `ptr` is + // likely bogus so don't actually send this to the system allocator + if size == 0 { + return; + } + let align = mem::align_of::(); + let layout = Layout::from_size_align_unchecked(size, align); + dealloc(ptr, layout); +} + +#[repr(C)] +pub struct ExecProgramResult { + json_result: *const c_char, + yaml_result: *const c_char, + log_message: *const c_char, + err_message: *const c_char, +} + +/// Execute KCL file with arguments and return the JSON/YAML result. +#[no_mangle] +pub unsafe extern "C" fn kcl_exec_program( + filename_ptr: *const c_char, + src_ptr: *const c_char, +) -> *const ExecProgramResult { + if filename_ptr.is_null() || src_ptr.is_null() { + return std::ptr::null(); + } + let filename = unsafe { CStr::from_ptr(filename_ptr).to_str().unwrap() }; + let src = unsafe { CStr::from_ptr(src_ptr).to_str().unwrap() }; + + match intern_run(filename, src) { + Ok(result) => { + let json = CString::new(result.json_result).unwrap().into_raw(); + let yaml = CString::new(result.yaml_result).unwrap().into_raw(); + let log = CString::new(result.log_message).unwrap().into_raw(); + let err = CString::new(result.err_message).unwrap().into_raw(); + + let exec_result = ExecProgramResult { + json_result: json, + yaml_result: yaml, + log_message: log, + err_message: err, + }; + + Box::into_raw(Box::new(exec_result)) as *const ExecProgramResult + } + Err(err) => { + let result = ExecProgramResult { + err_message: CString::new(err).unwrap().into_raw(), + json_result: std::ptr::null(), + yaml_result: std::ptr::null(), + log_message: std::ptr::null(), + }; + Box::into_raw(Box::new(result)) as *const ExecProgramResult + } + } +} + +/// Free memory allocated for the ExecProgramResult. +#[no_mangle] +pub unsafe extern "C" fn kcl_free_exec_program_result(result: *const ExecProgramResult) { + if result.is_null() { + return; + } + + let result = Box::from_raw(result as *mut ExecProgramResult); + + if !result.json_result.is_null() { + let _ = CString::from_raw(result.json_result as *mut c_char); // Free the C string + } + if !result.yaml_result.is_null() { + let _ = CString::from_raw(result.yaml_result as *mut c_char); // Free the C string + } + if !result.log_message.is_null() { + let _ = CString::from_raw(result.log_message as *mut c_char); // Free the C string + } + if !result.err_message.is_null() { + let _ = CString::from_raw(result.err_message as *mut c_char); // Free the C string + } + + // Result itself will be freed when going out of scope +} + +/// Get the YAML result from ExecProgramResult. +#[no_mangle] +pub unsafe extern "C" fn kcl_result_get_yaml_result( + result: *const ExecProgramResult, +) -> *const c_char { + if result.is_null() { + return std::ptr::null(); + } + + let result = &*result; + if result.yaml_result.is_null() { + return std::ptr::null(); + } + + result.yaml_result +} + +/// Get the JSON result from ExecProgramResult. +#[no_mangle] +pub unsafe extern "C" fn kcl_result_get_json_result( + result: *const ExecProgramResult, +) -> *const c_char { + if result.is_null() { + return std::ptr::null(); + } + + let result = &*result; + if result.json_result.is_null() { + return std::ptr::null(); + } + + result.json_result +} + +/// Get the error message from ExecProgramResult. +#[no_mangle] +pub unsafe extern "C" fn kcl_result_get_err_message( + result: *const ExecProgramResult, +) -> *const c_char { + if result.is_null() { + return std::ptr::null(); + } + + let result = &*result; + if result.err_message.is_null() { + return std::ptr::null(); + } + + result.err_message +} + +/// Get the log message from ExecProgramResult. +#[no_mangle] +pub unsafe extern "C" fn kcl_result_get_log_message( + result: *const ExecProgramResult, +) -> *const c_char { + if result.is_null() { + return std::ptr::null(); + } + + let result = &*result; + if result.log_message.is_null() { + return std::ptr::null(); + } + + result.log_message +} + +/// Exposes a normal kcl run function to the WASM host. +#[no_mangle] +pub unsafe extern "C" fn kcl_run( + filename_ptr: *const c_char, + src_ptr: *const c_char, +) -> *const c_char { + if filename_ptr.is_null() || src_ptr.is_null() { + return std::ptr::null(); + } + let filename = unsafe { CStr::from_ptr(filename_ptr).to_str().unwrap() }; + let src = unsafe { CStr::from_ptr(src_ptr).to_str().unwrap() }; + + match intern_run(filename, src) { + Ok(result) => CString::new(result.yaml_result).unwrap().into_raw(), + Err(err) => CString::new(format!("ERROR:{}", err)).unwrap().into_raw(), + } +} + +/// Exposes a normal kcl run function with the log message to the WASM host. +#[no_mangle] +pub unsafe extern "C" fn kcl_run_with_log_message( + filename_ptr: *const c_char, + src_ptr: *const c_char, +) -> *const c_char { + if filename_ptr.is_null() || src_ptr.is_null() { + return std::ptr::null(); + } + let filename = unsafe { CStr::from_ptr(filename_ptr).to_str().unwrap() }; + let src = unsafe { CStr::from_ptr(src_ptr).to_str().unwrap() }; + + match intern_run(filename, src) { + Ok(result) => CString::new(result.log_message + &result.yaml_result) + .unwrap() + .into_raw(), + Err(err) => CString::new(format!("ERROR:{}", err)).unwrap().into_raw(), + } +} + +/// Exposes a normal kcl fmt function to the WASM host. +#[no_mangle] +pub unsafe extern "C" fn kcl_fmt(src_ptr: *const c_char) -> *const c_char { + if src_ptr.is_null() { + return std::ptr::null(); + } + let src = unsafe { CStr::from_ptr(src_ptr).to_str().unwrap() }; + + match intern_fmt(src) { + Ok(result) => CString::new(result).unwrap().into_raw(), + Err(err) => CString::new(format!("ERROR:{}", err)).unwrap().into_raw(), + } +} + +/// Exposes a normal kcl version function to the WASM host. +#[no_mangle] +pub unsafe extern "C" fn kcl_version() -> *const c_char { + CString::new(kclvm_version::VERSION).unwrap().into_raw() +} + +/// Exposes a normal kcl runtime error function to the WASM host. +#[no_mangle] +pub unsafe extern "C" fn kcl_runtime_err(buffer: *mut u8, length: usize) -> isize { + KCL_RUNTIME_PANIC_RECORD.with(|e| { + let message = &e.borrow().message; + if !message.is_empty() { + let bytes = message.as_bytes(); + let copy_len = std::cmp::min(bytes.len(), length); + unsafe { + std::ptr::copy_nonoverlapping(bytes.as_ptr(), buffer, copy_len); + } + copy_len as isize + } else { + 0 + } + }) +} diff --git a/kclvm/src/lib.rs b/kclvm/src/lib.rs index 291f5dc3a..649194fd8 100644 --- a/kclvm/src/lib.rs +++ b/kclvm/src/lib.rs @@ -1,23 +1,25 @@ -extern crate serde; +#![allow(clippy::missing_safety_doc)] -use std::collections::HashMap; -use std::path::{Path, PathBuf}; -use std::sync::mpsc::channel; -use threadpool::ThreadPool; +use std::ffi::{c_char, c_int, CStr}; +use std::process::ExitCode; -use indexmap::IndexMap; -use kclvm_ast::ast; -use kclvm_compiler::codegen::{llvm::emit_code, EmitOptions}; -use kclvm_config::cache::*; -use kclvm_parser::load_program; -use kclvm_sema::resolver::resolve_program; +use kclvm_api::FormatCodeArgs; +use kclvm_api::{ExecProgramArgs, API}; -use kclvm_runner::command::Command; -use kclvm_runner::runner::*; -use kclvm_tools::query::apply_overrides; +mod capi; +pub use capi::*; +use kclvm_parser::ParseSessionRef; +use kclvm_runner::exec_program; +use kclvm_runtime::PanicInfo; +/// KCL CLI run function CAPI. +/// +/// args is a ExecProgramArgs JSON string. #[no_mangle] -pub extern "C" fn kclvm_cli_run(args: *const i8, plugin_agent: *const i8) -> *const i8 { +pub unsafe extern "C" fn kclvm_cli_run( + args: *const c_char, + plugin_agent: *const c_char, +) -> *const c_char { let prev_hook = std::panic::take_hook(); // disable print panic info @@ -32,180 +34,98 @@ pub extern "C" fn kclvm_cli_run(args: *const i8, plugin_agent: *const i8) -> *co let c_string = std::ffi::CString::new(result.as_str()).expect("CString::new failed"); let ptr = c_string.into_raw(); - ptr as *const i8 + ptr as *const c_char } Err(result) => { - let result = format!("ERROR:{}", result); + let result = format!("ERROR:{result}"); let c_string = std::ffi::CString::new(result.as_str()).expect("CString::new failed"); let ptr = c_string.into_raw(); - ptr as *const i8 + ptr as *const c_char } }, - Err(panic_err) => { - let err_message = if let Some(s) = panic_err.downcast_ref::<&str>() { - s.to_string() - } else if let Some(s) = panic_err.downcast_ref::<&String>() { - (*s).clone() - } else if let Some(s) = panic_err.downcast_ref::() { - (*s).clone() - } else { - "".to_string() - }; - - let result = format!("ERROR:{:}", err_message); + Err(err) => { + let err_message = kclvm_error::err_to_str(err); + let result = format!("ERROR:{err_message:}"); let c_string = std::ffi::CString::new(result.as_str()).expect("CString::new failed"); let ptr = c_string.into_raw(); - ptr as *const i8 + ptr as *const c_char } } } -pub fn kclvm_cli_run_unsafe(args: *const i8, plugin_agent: *const i8) -> Result { - let args = ExecProgramArgs::from_str(kclvm::c2str(args)); - let plugin_agent = plugin_agent as u64; - - let files = args.get_files(); - let opts = args.get_load_program_options(); +/// KCL CLI run function CAPI. +fn kclvm_cli_run_unsafe( + args: *const c_char, + plugin_agent: *const c_char, +) -> Result { + let mut args = kclvm_runner::ExecProgramArgs::from_str( + unsafe { std::ffi::CStr::from_ptr(args) }.to_str().unwrap(), + ); + args.plugin_agent = plugin_agent as u64; + exec_program(ParseSessionRef::default(), &args) + .map_err(|e| PanicInfo::from(e.to_string()).to_json_string()) + .map(|r| r.json_result) +} - // load ast - let mut program = load_program(&files, Some(opts))?; - apply_overrides(&mut program, &args.overrides, &[]); - let scope = resolve_program(&mut program); - scope.check_scope_diagnostics(); - // gen bc or ll file - let ll_file = "_a.out"; - let path = std::path::Path::new(ll_file); - if path.exists() { - std::fs::remove_file(path).unwrap(); - } - for entry in glob::glob(&format!("{}*.ll", ll_file)).unwrap() { - match entry { - Ok(path) => { - if path.exists() { - std::fs::remove_file(path).unwrap(); - } - } - Err(e) => println!("{:?}", e), - }; - } +/// KCL CLI main function CAPI. +#[no_mangle] +pub unsafe extern "C" fn kclvm_cli_main(argc: c_int, argv: *const *const c_char) -> *mut ExitCode { + let prev_hook = std::panic::take_hook(); - let cache_dir = Path::new(&program.root) - .join(".kclvm") - .join("cache") - .join(kclvm_version::get_full_version()); - if !cache_dir.exists() { - std::fs::create_dir_all(&cache_dir).unwrap(); - } - let mut compile_progs: IndexMap< - String, - ( - ast::Program, - IndexMap>, - PathBuf, - ), - > = IndexMap::default(); - for (pkgpath, modules) in program.pkgs { - let mut pkgs = HashMap::new(); - pkgs.insert(pkgpath.clone(), modules); - let compile_prog = ast::Program { - root: program.root.clone(), - main: program.main.clone(), - pkgs, - cmd_args: vec![], - cmd_overrides: vec![], + // disable print panic info + std::panic::set_hook(Box::new(|_info| {})); + let kclvm_cli_main_result = std::panic::catch_unwind(|| { + let args: Vec<&str> = unsafe { + std::slice::from_raw_parts(argv, argc as usize) + .iter() + .map(|ptr| CStr::from_ptr(*ptr).to_str().unwrap()) + .collect() }; - compile_progs.insert( - pkgpath, - (compile_prog, scope.import_names.clone(), cache_dir.clone()), - ); - } - let pool = ThreadPool::new(4); - let (tx, rx) = channel(); - let prog_count = compile_progs.len(); - for (pkgpath, (compile_prog, import_names, cache_dir)) in compile_progs { - let tx = tx.clone(); - pool.execute(move || { - let root = &compile_prog.root; - let is_main_pkg = pkgpath == kclvm_ast::MAIN_PKG; - let file = if is_main_pkg { - PathBuf::from(&pkgpath) - } else { - cache_dir.join(&pkgpath) - }; - let ll_file = file.to_str().unwrap(); - let ll_path = format!("{}.ll", ll_file); - let dylib_path = format!("{}{}", ll_file, Command::get_lib_suffix()); - let mut ll_path_lock = fslock::LockFile::open(&format!("{}.lock", ll_path)).unwrap(); - ll_path_lock.lock().unwrap(); - if Path::new(&ll_path).exists() { - std::fs::remove_file(&ll_path).unwrap(); - } - let dylib_path = if is_main_pkg { - emit_code( - &compile_prog, - import_names, - &EmitOptions { - from_path: None, - emit_path: Some(&ll_file), - no_link: true, - }, - ) - .expect("Compile KCL to LLVM error"); - let mut cmd = Command::new(plugin_agent); - cmd.run_clang_single(&ll_path, &dylib_path) - } else { - // If AST module has been modified, ignore the dylib cache - let dylib_relative_path: Option = - load_pkg_cache(root, &pkgpath, CacheOption::default()); - match dylib_relative_path { - Some(dylib_relative_path) => { - if dylib_relative_path.starts_with('.') { - dylib_relative_path.replacen(".", root, 1) - } else { - dylib_relative_path - } - } - None => { - emit_code( - &compile_prog, - import_names, - &EmitOptions { - from_path: None, - emit_path: Some(&ll_file), - no_link: true, - }, - ) - .expect("Compile KCL to LLVM error"); - let mut cmd = Command::new(plugin_agent); - let dylib_path = cmd.run_clang_single(&ll_path, &dylib_path); - let dylib_relative_path = dylib_path.replacen(root, ".", 1); + kclvm_cmd::main(args.as_slice()) + }); + std::panic::set_hook(prev_hook); - save_pkg_cache(root, &pkgpath, dylib_relative_path, CacheOption::default()); - dylib_path - } + match kclvm_cli_main_result { + Ok(result) => match result { + Ok(()) => Box::into_raw(Box::new(ExitCode::SUCCESS)), + Err(err) => { + let backtrace = format!("{}", err.backtrace()); + if backtrace.is_empty() || backtrace.contains("disabled backtrace") { + eprintln!("{err}"); + } else { + eprintln!("{err}\nStack backtrace:\n{backtrace}"); } - }; - if Path::new(&ll_path).exists() { - std::fs::remove_file(&ll_path).unwrap(); + Box::into_raw(Box::new(ExitCode::FAILURE)) + } + }, + Err(err) => { + let err_str = kclvm_error::err_to_str(err); + if !err_str.is_empty() { + eprintln!("{err_str}"); } - ll_path_lock.unlock().unwrap(); - tx.send(dylib_path) - .expect("channel will be there waiting for the pool"); - }); + Box::into_raw(Box::new(ExitCode::FAILURE)) + } } - let dylib_paths = rx.iter().take(prog_count).collect::>(); - let mut cmd = Command::new(plugin_agent); - // link all dylibs - let dylib_path = cmd.link_dylibs(&dylib_paths, ""); +} - // Config uild - // run dylib - let runner = KclvmRunner::new( - dylib_path.as_str(), - Some(KclvmRunnerOptions { - plugin_agent_ptr: plugin_agent, - }), - ); - runner.run(&args) +fn intern_run(filename: &str, src: &str) -> Result { + let api = API::default(); + let args = &ExecProgramArgs { + k_filename_list: vec![filename.to_string()], + k_code_list: vec![src.to_string()], + ..Default::default() + }; + api.exec_program(args).map_err(|err| err.to_string()) +} + +fn intern_fmt(src: &str) -> Result { + let api = API::default(); + let args = &FormatCodeArgs { + source: src.to_string(), + }; + match api.format_code(args) { + Ok(result) => String::from_utf8(result.formatted).map_err(|err| err.to_string()), + Err(err) => Err(err.to_string()), + } } diff --git a/kclvm/src/main.rs b/kclvm/src/main.rs deleted file mode 100644 index 934dce543..000000000 --- a/kclvm/src/main.rs +++ /dev/null @@ -1,223 +0,0 @@ -//! The `kclvm` command-line interface. - -#[macro_use] -extern crate clap; - -use indexmap::IndexMap; -use std::path::PathBuf; -use std::thread; -use std::{collections::HashMap, path::Path}; - -use clap::ArgMatches; -use kclvm_ast::ast; -use kclvm_compiler::codegen::{llvm::emit_code, EmitOptions}; -use kclvm_config::cache::*; -use kclvm_config::settings::{load_file, merge_settings, SettingsFile}; -use kclvm_parser::{load_program, parse_file}; -use kclvm_runner::command::Command; -use kclvm_sema::resolver::resolve_program; - -fn main() { - let matches = clap_app!(kcl => - (@subcommand run => - (@arg INPUT: ... "Sets the input file to use") - (@arg OUTPUT: -o --output +takes_value "Sets the LLVM IR/BC output file path") - (@arg SETTING: ... -Y --setting "Sets the input file to use") - (@arg EMIT_TYPE: --emit +takes_value "Sets the emit type, expect (ast)") - (@arg BC_PATH: --bc +takes_value "Sets the linked LLVM bitcode file path") - (@arg verbose: -v --verbose "Print test information verbosely") - (@arg disable_none: -n --disable-none "Disable dumping None values") - (@arg debug: -d --debug "Run in debug mode (for developers only)") - (@arg sort_key: -k --sort "Sort result keys") - (@arg ARGUMENT: ... -D --argument "Specify the top-level argument") - ) - ) - .get_matches(); - if let Some(matches) = matches.subcommand_matches("run") { - if let Some(files) = matches.values_of("INPUT") { - let files: Vec<&str> = files.into_iter().collect::>(); - if let Some(emit_ty) = matches.value_of("EMIT_TYPE") { - if emit_ty == "ast" { - let module = parse_file(files[0], None); - println!("{}", serde_json::to_string(&module).unwrap()) - } - } else { - // load ast - let mut program = load_program(&files, None).unwrap(); - let scope = resolve_program(&mut program); - scope.check_scope_diagnostics(); - // gen bc or ll file - let ll_file = "_a.out"; - let path = std::path::Path::new(ll_file); - if path.exists() { - std::fs::remove_file(path).unwrap(); - } - for entry in glob::glob(&format!("{}*.ll", ll_file)).unwrap() { - match entry { - Ok(path) => { - if path.exists() { - std::fs::remove_file(path).unwrap(); - } - } - Err(e) => println!("{:?}", e), - }; - } - - let cache_dir = Path::new(&program.root) - .join(".kclvm") - .join("cache") - .join(kclvm_version::get_full_version()); - if !cache_dir.exists() { - std::fs::create_dir_all(&cache_dir).unwrap(); - } - let mut compile_progs: IndexMap< - String, - ( - ast::Program, - IndexMap>, - PathBuf, - ), - > = IndexMap::default(); - - for (pkgpath, modules) in program.pkgs { - let mut pkgs = HashMap::new(); - pkgs.insert(pkgpath.clone(), modules); - let compile_prog = ast::Program { - root: program.root.clone(), - main: program.main.clone(), - pkgs, - cmd_args: vec![], - cmd_overrides: vec![], - }; - compile_progs.insert( - pkgpath, - (compile_prog, scope.import_names.clone(), cache_dir.clone()), - ); - } - let mut theads = vec![]; - for (pkgpath, (compile_prog, import_names, cache_dir)) in compile_progs { - let t = thread::spawn(move || { - let root = &compile_prog.root; - let is_main_pkg = pkgpath == kclvm_ast::MAIN_PKG; - let file = if is_main_pkg { - let main_file = - format!("{}{}", pkgpath, chrono::Local::now().timestamp_nanos()); - cache_dir.join(&main_file) - } else { - cache_dir.join(&pkgpath) - }; - let lock_file = - format!("{}.lock", cache_dir.join(&pkgpath).to_str().unwrap()); - let ll_file = file.to_str().unwrap(); - let ll_path = format!("{}.ll", ll_file); - let dylib_path = format!("{}{}", ll_file, Command::get_lib_suffix()); - let mut ll_path_lock = fslock::LockFile::open(&lock_file).unwrap(); - ll_path_lock.lock().unwrap(); - if Path::new(&ll_path).exists() { - std::fs::remove_file(&ll_path).unwrap(); - } - let dylib_path = if is_main_pkg { - emit_code( - &compile_prog, - import_names, - &EmitOptions { - from_path: None, - emit_path: Some(&ll_file), - no_link: true, - }, - ) - .expect("Compile KCL to LLVM error"); - let mut cmd = Command::new(0); - cmd.run_clang_single(&ll_path, &dylib_path) - } else { - // If AST module has been modified, ignore the dylib cache - let dylib_relative_path: Option = - load_pkg_cache(root, &pkgpath, CacheOption::default()); - match dylib_relative_path { - Some(dylib_relative_path) => { - if dylib_relative_path.starts_with('.') { - dylib_relative_path.replacen(".", root, 1) - } else { - dylib_relative_path - } - } - None => { - emit_code( - &compile_prog, - import_names, - &EmitOptions { - from_path: None, - emit_path: Some(&ll_file), - no_link: true, - }, - ) - .expect("Compile KCL to LLVM error"); - let mut cmd = Command::new(0); - let dylib_path = cmd.run_clang_single(&ll_path, &dylib_path); - let dylib_relative_path = dylib_path.replacen(root, ".", 1); - - save_pkg_cache( - root, - &pkgpath, - dylib_relative_path, - CacheOption::default(), - ); - dylib_path - } - } - }; - if Path::new(&ll_path).exists() { - std::fs::remove_file(&ll_path).unwrap(); - } - ll_path_lock.unlock().unwrap(); - dylib_path - }); - theads.push(t); - } - let mut dylib_paths = vec![]; - for t in theads { - let dylib_path = t.join().unwrap(); - dylib_paths.push(dylib_path); - } - let mut cmd = Command::new(0); - // link all dylibs - let dylib_path = cmd.link_dylibs(&dylib_paths, ""); - // Config build - let settings = build_settings(&matches); - cmd.run_dylib_with_settings(&dylib_path, settings).unwrap(); - for dylib_path in dylib_paths { - if dylib_path.contains(kclvm_ast::MAIN_PKG) && Path::new(&dylib_path).exists() { - std::fs::remove_file(&dylib_path).unwrap(); - } - } - } - } else { - println!("{}", matches.usage()); - } - } else { - println!("{}", matches.usage()); - } -} - -/// Build settings from arg matches. -fn build_settings(matches: &ArgMatches) -> SettingsFile { - let debug_mode = matches.occurrences_of("debug") > 0; - let disable_none = matches.occurrences_of("disable_none") > 0; - - let mut settings = if let Some(files) = matches.values_of("SETTING") { - let files: Vec<&str> = files.into_iter().collect::>(); - merge_settings( - &files - .iter() - .map(|f| load_file(f)) - .collect::>(), - ) - } else { - SettingsFile::new() - }; - if let Some(config) = &mut settings.kcl_cli_configs { - config.debug = Some(debug_mode); - config.disable_none = Some(disable_none); - } - settings -} diff --git a/kclvm/tests/Cargo.toml b/kclvm/tests/Cargo.toml index 54c6cd0f3..ec8ef80a9 100644 --- a/kclvm/tests/Cargo.toml +++ b/kclvm/tests/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tests" -version = "0.1.0" +version = "0.5.0" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/kclvm/tests/fuzz/Cargo.lock b/kclvm/tests/fuzz/Cargo.lock index e132a2503..414b2c723 100644 --- a/kclvm/tests/fuzz/Cargo.lock +++ b/kclvm/tests/fuzz/Cargo.lock @@ -2,6 +2,21 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "addr2line" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4fa78e18c64fce05e902adecd7a5eed15a5e0a3439f7b0e169f0252214865e3" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + [[package]] name = "ahash" version = "0.7.6" @@ -15,26 +30,128 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "0.7.18" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" +checksum = "43f6cb1bf222025340178f382c426f13757b2960e89779dfcb319c32542a5a41" dependencies = [ "memchr", ] +[[package]] +name = "always-assert" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4436e0292ab1bb631b42973c61205e704475fe8126af845c8d923c0996328127" +dependencies = [ + "log", +] + +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + [[package]] name = "annotate-snippets" -version = "0.8.0" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccaf7e9dfbb6ab22c82e473cd1a8a7bd313c19a5b7e40970f3d89ef5a5c9e81e" +dependencies = [ + "unicode-width", + "yansi-term", +] + +[[package]] +name = "anstream" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d78ea013094e5ea606b1c05fe35f1dd7ea1eb1ea259908d040b25bd5ec677ee5" +checksum = "0ca84f3628370c59db74ee214b3263d58f9aadd9b4fe7e711fd87dc452b7f163" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon 1.0.1", + "colorchoice", + "is-terminal", + "utf8parse", +] [[package]] -name = "ansi_term" -version = "0.12.1" +name = "anstream" +version = "0.6.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" +checksum = "418c75fa768af9c03be99d17643f93f79bbba589895012a80e3452a19ddda15b" dependencies = [ - "winapi", + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon 3.0.3", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b" + +[[package]] +name = "anstyle-parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "938874ff5980b03a87c5524b3ae5b59cf99b1d6bc836848df7bc5ada9643c333" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b" +dependencies = [ + "windows-sys 0.48.0", +] + +[[package]] +name = "anstyle-wincon" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "180abfa45703aebe0093f79badacc01b8fd4ea2e35118747e5811127f926e188" +dependencies = [ + "anstyle", + "windows-sys 0.48.0", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19" +dependencies = [ + "anstyle", + "windows-sys 0.52.0", +] + +[[package]] +name = "anyhow" +version = "1.0.72" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b13c32d80ecc7ab747b80c3784bce54ee8a7a0cc4fbda9bf4cda2cf6fe90854" +dependencies = [ + "backtrace", ] [[package]] @@ -52,13 +169,35 @@ version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6" +[[package]] +name = "async-stream" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd56dd203fef61ac097dd65721a419ddccb106b2d2b70ba60a6b529f03961a51" +dependencies = [ + "async-stream-impl", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-stream-impl" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.67", +] + [[package]] name = "atty" version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" dependencies = [ - "hermit-abi", + "hermit-abi 0.1.19", "libc", "winapi", ] @@ -69,12 +208,39 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +[[package]] +name = "backtrace" +version = "0.3.68" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4319208da049c43661739c5fade2ba182f09d1dc2299b32298d3a31692b17e12" +dependencies = [ + "addr2line", + "cc", + "cfg-if 1.0.0", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + +[[package]] +name = "base-x" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cbbc9d0964165b47557570cce6c952866c2678457aca742aafc9fb771d30270" + [[package]] name = "base64" version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + [[package]] name = "bit-set" version = "0.5.2" @@ -96,13 +262,40 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bitflags" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" + +[[package]] +name = "bitmaps" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "031043d04099746d8db04daf1fa424b2bc8bd69d92b25962dcde24da39ab64a2" +dependencies = [ + "typenum", +] + +[[package]] +name = "block-buffer" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b" +dependencies = [ + "block-padding", + "byte-tools", + "byteorder", + "generic-array 0.12.4", +] + [[package]] name = "block-buffer" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" dependencies = [ - "generic-array", + "generic-array 0.14.5", ] [[package]] @@ -111,7 +304,16 @@ version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0bf7fe51849ea569fd452f37822f606a5cabb684dc918707a0193fd4664ff324" dependencies = [ - "generic-array", + "generic-array 0.14.5", +] + +[[package]] +name = "block-padding" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5" +dependencies = [ + "byte-tools", ] [[package]] @@ -122,14 +324,38 @@ checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223" dependencies = [ "lazy_static", "memchr", - "regex-automata", + "regex-automata 0.1.10", ] +[[package]] +name = "bumpalo" +version = "3.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1" + +[[package]] +name = "byte-tools" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" + [[package]] name = "cc" -version = "1.0.73" +version = "1.0.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" +checksum = "96c51067fd44124faa7f870b4b1c969379ad32b2ba805aa959430ceaa384f695" [[package]] name = "cfg-if" @@ -145,32 +371,108 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chrono" -version = "0.4.19" +version = "0.4.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73" +checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" dependencies = [ - "libc", - "num-integer", + "android-tzdata", + "iana-time-zone", + "js-sys", "num-traits", - "time", - "winapi", + "serde", + "wasm-bindgen", + "windows-targets 0.52.0", ] [[package]] name = "clap" -version = "2.34.0" +version = "4.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" +checksum = "5fd304a20bff958a57f04c4e96a2e7594cc4490a0e809cbd48bb6437edaa452d" dependencies = [ - "ansi_term", - "atty", - "bitflags", + "clap_builder", +] + +[[package]] +name = "clap_builder" +version = "4.3.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01c6a3f08f1fe5662a35cfe393aec09c4df95f60ee93b7556505260f75eee9e1" +dependencies = [ + "anstream 0.3.2", + "anstyle", + "clap_lex", "strsim", - "textwrap", - "unicode-width", - "vec_map", ] +[[package]] +name = "clap_lex" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2da6da31387c7e4ef160ffab6d5e7f00c42626fe39aea70a7b0f1773f7dd6c1b" + +[[package]] +name = "colorchoice" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" + +[[package]] +name = "compiler_base_error" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32e6a143200e9657a565b093fde64a590af93884d1f820829db6461de1ff0086" +dependencies = [ + "anyhow", + "compiler_base_macros", + "compiler_base_span", + "fluent", + "pretty_assertions", + "rustc_errors", + "rustc_span", + "termcolor", + "unic-langid", + "walkdir", +] + +[[package]] +name = "compiler_base_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21900034f34b69f860a5ff66e0577b8e66d310090b04bf0334afea9a041e0cee" + +[[package]] +name = "compiler_base_session" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67411f0b5421d9c9f045ec08c4d01fe3861197d11215d1e2e448be663aff9ad9" +dependencies = [ + "anyhow", + "compiler_base_error", + "compiler_base_span", +] + +[[package]] +name = "compiler_base_span" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a42aae2adfa4b418441ede52835f3c96e9ca63d595f0ac861d94935757e9cb2e" +dependencies = [ + "rustc_span", +] + +[[package]] +name = "const_fn" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbdcdcb6d86f71c5e97409ad45898af11cbc995b4ee8112d59095a28d376c935" + +[[package]] +name = "core-foundation-sys" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" + [[package]] name = "cpufeatures" version = "0.2.2" @@ -180,6 +482,25 @@ dependencies = [ "libc", ] +[[package]] +name = "crc32fast" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" +dependencies = [ + "cfg-if 1.0.0", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82a9b73a36529d9c47029b9fb3a6f0ea3cc916a261195352ba19e770fc1748b2" +dependencies = [ + "cfg-if 1.0.0", + "crossbeam-utils", +] + [[package]] name = "crossbeam-deque" version = "0.8.1" @@ -207,12 +528,11 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.8" +version = "0.8.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bf124c720b7686e3c2663cf54062ab0f68a88af2fb6a030e87e30bf721fcb38" +checksum = "c3a430a770ebd84726f584a90ee7f020d28db52c6d02138900f22341f866d39c" dependencies = [ "cfg-if 1.0.0", - "lazy_static", ] [[package]] @@ -221,10 +541,28 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57952ca27b5e3606ff4dd79b0020231aaf9d6aa76dc05fd30137538c50bd3ce8" dependencies = [ - "generic-array", + "generic-array 0.14.5", "typenum", ] +[[package]] +name = "dashmap" +version = "5.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3495912c9c1ccf2e18976439f4443f3fee0fd61f424ff99fde6a66b15ecb448f" +dependencies = [ + "cfg-if 1.0.0", + "hashbrown 0.12.3", + "lock_api", + "parking_lot_core 0.9.3", +] + +[[package]] +name = "deranged" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7684a49fb1af197853ef7b2ee694bc1f5b4179556f1e5710e1760c5db6f5e929" + [[package]] name = "derive_arbitrary" version = "1.1.0" @@ -233,7 +571,22 @@ checksum = "98e23c06c035dac87bd802d98f368df73a7f2cb05a66ffbd1f377e821fac4af9" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.95", +] + +[[package]] +name = "diff" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" + +[[package]] +name = "digest" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5" +dependencies = [ + "generic-array 0.12.4", ] [[package]] @@ -242,17 +595,56 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" dependencies = [ - "generic-array", + "generic-array 0.14.5", ] [[package]] name = "digest" -version = "0.10.3" +version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2fb860ca6fafa5552fb6d0e816a69c8e49f0908bf524e30a90d97c85892d506" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer 0.10.2", "crypto-common", + "subtle", +] + +[[package]] +name = "dirs" +version = "5.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225" +dependencies = [ + "dirs-sys", +] + +[[package]] +name = "dirs-sys" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" +dependencies = [ + "libc", + "option-ext", + "redox_users", + "windows-sys 0.48.0", +] + +[[package]] +name = "discard" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0" + +[[package]] +name = "displaydoc" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.67", ] [[package]] @@ -280,1469 +672,3956 @@ dependencies = [ ] [[package]] -name = "fancy-regex" -version = "0.7.1" +name = "env_filter" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d6b8560a05112eb52f04b00e5d3790c0dd75d9d980eb8a122fb23b92a623ccf" +checksum = "a009aa4810eb158359dda09d0c87378e4bbb89b5a801f016885a4707ba24f7ea" dependencies = [ - "bit-set", + "log", "regex", ] [[package]] -name = "fastrand" -version = "1.7.0" +name = "env_logger" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3fcf0cee53519c866c09b5de1f6c56ff9d647101f81c1964fa632e148896cdf" +checksum = "38b35839ba51819680ba087cd351788c9a3c476841207e0b8cee0b04722343b9" dependencies = [ - "instant", + "anstream 0.6.14", + "anstyle", + "env_filter", + "humantime", + "log", ] [[package]] -name = "fixedbitset" -version = "0.4.1" +name = "equivalent" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "279fb028e20b3c4c320317955b77c5e0c9701f05a1d309905d6fc702cdc5053e" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] -name = "fslock" -version = "0.2.1" +name = "erased-serde" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04412b8935272e3a9bae6f48c7bfff74c2911f60525404edfdd28e49884c3bfb" +checksum = "da96524cc884f6558f1769b6c46686af2fe8e8b4cd253bd5a3cdba8181b8e070" dependencies = [ - "libc", - "winapi", + "serde", ] [[package]] -name = "fuchsia-cprng" -version = "0.1.1" +name = "errno" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" +checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] [[package]] -name = "gcc" -version = "0.3.55" +name = "fancy-regex" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f5f3913fa0bfe7ee1fd8248b6b9f42a5af4b9d65ec2dd2c3c26132b950ecfc2" +checksum = "9d6b8560a05112eb52f04b00e5d3790c0dd75d9d980eb8a122fb23b92a623ccf" +dependencies = [ + "bit-set", + "regex", +] [[package]] -name = "generic-array" -version = "0.14.5" +name = "fastrand" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd48d33ec7f05fbfa152300fdad764757cbded343c1aa1cff2fbaf4134851803" -dependencies = [ - "typenum", - "version_check", -] +checksum = "6999dc1837253364c2ebb0704ba97994bd874e8f195d665c50b7548f6ea92764" [[package]] -name = "getrandom" -version = "0.2.6" +name = "filetime" +version = "0.2.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9be70c98951c83b8d2f8f60d7065fa6d5146873094452a1008da8c2f1e4205ad" +checksum = "1ee447700ac8aa0b2f2bd7bc4462ad686ba06baa6727ac149a2d6277f0d240fd" dependencies = [ "cfg-if 1.0.0", "libc", - "wasi", + "redox_syscall 0.4.1", + "windows-sys 0.52.0", ] [[package]] -name = "glob" -version = "0.3.0" +name = "fixedbitset" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" +checksum = "279fb028e20b3c4c320317955b77c5e0c9701f05a1d309905d6fc702cdc5053e" [[package]] -name = "hashbrown" -version = "0.11.2" +name = "flate2" +version = "1.0.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" +checksum = "5f54427cfd1c7829e2a139fcefea601bf088ebca651d2bf53ebc600eac295dae" +dependencies = [ + "crc32fast", + "miniz_oxide", +] [[package]] -name = "hermit-abi" -version = "0.1.19" +name = "fluent" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +checksum = "61f69378194459db76abd2ce3952b790db103ceb003008d3d50d97c41ff847a7" dependencies = [ - "libc", + "fluent-bundle", + "unic-langid", ] [[package]] -name = "indexmap" -version = "1.8.1" +name = "fluent-bundle" +version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f647032dfaa1f8b6dc29bd3edb7bbef4861b8b8007ebb118d6db284fd59f6ee" +checksum = "e242c601dec9711505f6d5bbff5bedd4b61b2469f2e8bb8e57ee7c9747a87ffd" dependencies = [ - "autocfg", - "hashbrown", - "rustc-rayon", + "fluent-langneg", + "fluent-syntax", + "intl-memoizer", + "intl_pluralrules", + "rustc-hash", + "self_cell 0.10.3", + "smallvec", + "unic-langid", ] [[package]] -name = "inkwell" -version = "0.1.0" -source = "git+https://github.com/TheDan64/inkwell?branch=master#02fb7045f7a952c80bc983e19093c62c6ccffe3d" +name = "fluent-langneg" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c4ad0989667548f06ccd0e306ed56b61bd4d35458d54df5ec7587c0e8ed5e94" dependencies = [ - "either", - "inkwell_internals", - "libc", - "llvm-sys", - "once_cell", - "parking_lot", + "unic-langid", ] [[package]] -name = "inkwell_internals" -version = "0.5.0" -source = "git+https://github.com/TheDan64/inkwell?branch=master#02fb7045f7a952c80bc983e19093c62c6ccffe3d" +name = "fluent-syntax" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0abed97648395c902868fee9026de96483933faa54ea3b40d652f7dfe61ca78" dependencies = [ - "proc-macro2", - "quote", - "syn", + "thiserror", ] [[package]] -name = "instant" -version = "0.1.12" +name = "fnv" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" -dependencies = [ - "cfg-if 1.0.0", -] +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] -name = "itertools" -version = "0.10.3" +name = "form_urlencoded" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" dependencies = [ - "either", + "percent-encoding", ] [[package]] -name = "itoa" -version = "1.0.2" +name = "fsevent-sys" +version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d" +checksum = "76ee7a02da4d231650c7cea31349b889be2f45ddb3ef3032d2ec8185f6313fd2" +dependencies = [ + "libc", +] [[package]] -name = "jobserver" -version = "0.1.24" +name = "fslock" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af25a77299a7f711a01975c35a6a424eb6862092cc2d6c72c4ed6cbc56dfc1fa" +checksum = "04412b8935272e3a9bae6f48c7bfff74c2911f60525404edfdd28e49884c3bfb" dependencies = [ "libc", + "winapi", ] [[package]] -name = "json_minimal" -version = "0.1.3" +name = "fst" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ab85b9b05e3978cc9a9cf8fea7f01b494e1a09ed3037e16ba39edc7a29eb61a" [[package]] -name = "kclvm" -version = "0.1.0" +name = "futures" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40" dependencies = [ - "chrono", - "clap", - "fslock", - "glob", - "indexmap", - "kclvm-ast", - "kclvm-compiler", - "kclvm-config", - "kclvm-error", - "kclvm-parser", - "kclvm-runner", - "kclvm-runtime", - "kclvm-sema", - "kclvm-tools", - "kclvm-version", - "libc", - "libloading", - "serde", - "serde_json", - "threadpool", - "walkdir", + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", ] [[package]] -name = "kclvm-ast" -version = "0.1.0" +name = "futures-channel" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" dependencies = [ - "kclvm-span", - "rustc_span", - "serde", - "serde_json", + "futures-core", + "futures-sink", ] [[package]] -name = "kclvm-compiler" -version = "0.1.0" +name = "futures-core" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" + +[[package]] +name = "futures-executor" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0" dependencies = [ - "ahash", - "bit-set", - "bitflags", - "fancy-regex", - "indexmap", - "inkwell", - "kclvm-ast", - "kclvm-error", - "kclvm-runtime", - "kclvm-sema", - "once_cell", - "phf", - "time", - "unicode_names2", + "futures-core", + "futures-task", + "futures-util", ] [[package]] -name = "kclvm-config" -version = "0.1.0" +name = "futures-io" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" + +[[package]] +name = "futures-macro" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ - "ahash", - "chrono", - "fslock", - "glob", - "indexmap", - "kclvm-version", - "pathdiff", - "ron", - "rust-crypto", - "serde", - "serde_yaml", - "toml", + "proc-macro2", + "quote", + "syn 2.0.67", ] [[package]] -name = "kclvm-error" -version = "0.1.0" +name = "futures-sink" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" + +[[package]] +name = "futures-task" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" + +[[package]] +name = "futures-util" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" dependencies = [ - "annotate-snippets", - "atty", - "indexmap", - "kclvm-runtime", - "kclvm-span", - "rustc_span", - "termcolor", - "termize", - "tracing", + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", ] [[package]] -name = "kclvm-lexer" -version = "0.1.0" +name = "generational-arena" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877e94aff08e743b651baaea359664321055749b398adff8740a7399af7796e7" dependencies = [ - "kclvm-error", - "rustc_lexer", - "unic-emoji-char", + "cfg-if 1.0.0", ] [[package]] -name = "kclvm-macros" -version = "0.1.0" +name = "generic-array" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffdf9f34f1447443d37393cc6c2b8313aebddcd96906caf34e54c68d8e57d7bd" dependencies = [ - "proc-macro2", - "quote", - "syn", - "synstructure", + "typenum", ] [[package]] -name = "kclvm-parser" -version = "0.1.0" +name = "generic-array" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd48d33ec7f05fbfa152300fdad764757cbded343c1aa1cff2fbaf4134851803" dependencies = [ - "bstr", - "either", - "enquote", - "kclvm-ast", - "kclvm-config", - "kclvm-error", - "kclvm-lexer", - "kclvm-runtime", - "kclvm-sema", - "kclvm-span", - "num-bigint", - "rustc_data_structures", - "rustc_lexer", - "rustc_span", - "serde", - "serde_json", - "tracing", - "unicode_names2", + "typenum", + "version_check", ] [[package]] -name = "kclvm-runner" -version = "0.1.0" +name = "getrandom" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ - "clap", - "fslock", - "glob", - "indexmap", - "kclvm-ast", - "kclvm-compiler", - "kclvm-config", - "kclvm-parser", - "kclvm-runtime", - "kclvm-sema", - "kclvm-version", + "cfg-if 1.0.0", "libc", - "libloading", - "serde", - "serde_json", - "walkdir", + "wasi", ] [[package]] -name = "kclvm-runtime" -version = "0.1.0" +name = "gimli" +version = "0.27.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e" + +[[package]] +name = "glob" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" + +[[package]] +name = "handlebars" +version = "5.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d08485b96a0e6393e9e4d1b8d48cf74ad6c063cd905eb33f42c1ce3f0377539b" dependencies = [ - "ahash", - "base64", - "bstr", - "chrono", - "fancy-regex", - "indexmap", - "itertools", - "json_minimal", - "kclvm_runtime_internal_macros", - "libc", - "md5", - "num-integer", - "phf", - "regex", + "log", + "pest", + "pest_derive", "serde", "serde_json", - "serde_yaml", - "sha1", + "thiserror", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + +[[package]] +name = "hashbrown" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" + +[[package]] +name = "heck" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "hermit-abi" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b" + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest 0.10.7", +] + +[[package]] +name = "http" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-auth" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "643c9bbf6a4ea8a656d6b4cd53d34f79e3f841ad5203c1a55fb7d761923bc255" +dependencies = [ + "memchr", +] + +[[package]] +name = "http-body" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cac85db508abc24a2e48553ba12a996e87244a0395ce011e62b37158745d643" +dependencies = [ + "bytes", + "http", +] + +[[package]] +name = "http-body-util" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" +dependencies = [ + "bytes", + "futures-util", + "http", + "http-body", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fcc0b4a115bf80b728eb8ea024ad5bd707b615bfed49e0665b6e0f86fd082d9" + +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + +[[package]] +name = "hyper" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe575dd17d0862a9a33781c8c4696a55c320909004a67a00fb286ba8b1bc496d" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "http", + "http-body", + "httparse", + "itoa", + "pin-project-lite", + "smallvec", + "tokio", + "want", +] + +[[package]] +name = "hyper-rustls" +version = "0.27.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ee4be2c948921a1a5320b629c4193916ed787a7f7f293fd3f7f5a6c9de74155" +dependencies = [ + "futures-util", + "http", + "hyper", + "hyper-util", + "rustls", + "rustls-pki-types", + "tokio", + "tokio-rustls", + "tower-service", + "webpki-roots", +] + +[[package]] +name = "hyper-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b875924a60b96e5d7b9ae7b066540b1dd1cbd90d1828f54c92e02a283351c56" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "http", + "http-body", + "hyper", + "pin-project-lite", + "socket2", + "tokio", + "tower", + "tower-service", + "tracing", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "idna" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "im-rc" +version = "15.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af1955a75fa080c677d3972822ec4bad316169ab1cfc6c257a942c2265dbe5fe" +dependencies = [ + "bitmaps", + "rand_core", + "rand_xoshiro", + "sized-chunks", + "typenum", + "version_check", +] + +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown 0.12.3", + "rustc-rayon 0.5.0", +] + +[[package]] +name = "indexmap" +version = "2.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" +dependencies = [ + "equivalent", + "hashbrown 0.14.3", +] + +[[package]] +name = "inotify" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8069d3ec154eb856955c1c0fbffefbf5f3c40a104ec912d4797314c1801abff" +dependencies = [ + "bitflags 1.3.2", + "inotify-sys", + "libc", +] + +[[package]] +name = "inotify-sys" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e05c02b5e89bff3b946cedeca278abc628fe811e604f027c45a8aa3cf793d0eb" +dependencies = [ + "libc", +] + +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if 1.0.0", +] + +[[package]] +name = "intl-memoizer" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c310433e4a310918d6ed9243542a6b83ec1183df95dff8f23f87bb88a264a66f" +dependencies = [ + "type-map", + "unic-langid", +] + +[[package]] +name = "intl_pluralrules" +version = "7.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "078ea7b7c29a2b4df841a7f6ac8775ff6074020c6776d48491ce2268e068f972" +dependencies = [ + "unic-langid", +] + +[[package]] +name = "inventory" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a53088c87cf71c9d4f3372a2cb9eea1e7b8a0b1bf8b7f7d23fe5b76dbb07e63b" + +[[package]] +name = "ipnet" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" + +[[package]] +name = "is-terminal" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" +dependencies = [ + "hermit-abi 0.3.2", + "rustix", + "windows-sys 0.48.0", +] + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800" + +[[package]] +name = "itertools" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d" + +[[package]] +name = "jobserver" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af25a77299a7f711a01975c35a6a424eb6862092cc2d6c72c4ed6cbc56dfc1fa" +dependencies = [ + "libc", +] + +[[package]] +name = "jod-thread" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b23360e99b8717f20aaa4598f5a6541efbe30630039fbc7706cf954a87947ae" + +[[package]] +name = "js-sys" +version = "0.3.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "json-spanned-value" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb343fa4e3b1b22b344937deedac88da995abf139c2232cbeaa436c38380a210" +dependencies = [ + "serde", + "serde_json", +] + +[[package]] +name = "jsonrpc-core" +version = "18.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14f7f76aef2d054868398427f6c54943cf3d1caa9a7ec7d0c38d69df97a965eb" +dependencies = [ + "futures", + "futures-executor", + "futures-util", + "log", + "serde", + "serde_derive", + "serde_json", +] + +[[package]] +name = "jsonrpc-stdio-server" +version = "18.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6878586767497326eb3d011bd6dbb583e9f008b11528f82fd47798ec46bb6c26" +dependencies = [ + "futures", + "jsonrpc-core", + "log", + "tokio", + "tokio-util 0.6.10", +] + +[[package]] +name = "jwt" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6204285f77fe7d9784db3fdc449ecce1a0114927a51d5a41c4c7a292011c015f" +dependencies = [ + "base64 0.13.0", + "crypto-common", + "digest 0.10.7", + "hmac", + "serde", + "serde_json", + "sha2 0.10.2", +] + +[[package]] +name = "kcl-language-server" +version = "0.9.0" +dependencies = [ + "anyhow", + "chrono", + "clap", + "compiler_base_session", + "crossbeam-channel", + "dashmap", + "env_logger", + "im-rc", + "indexmap 1.9.3", + "kclvm-ast", + "kclvm-config", + "kclvm-driver", + "kclvm-error", + "kclvm-parser", + "kclvm-query", + "kclvm-sema", + "kclvm-span", + "kclvm-tools", + "kclvm-utils", + "kclvm-version", + "log", + "lsp-server", + "lsp-types", + "maplit", + "parking_lot 0.12.3", + "proc_macro_crate", + "ra_ap_vfs", + "ra_ap_vfs-notify", + "ropey", + "rustc-hash", + "rustc_lexer", + "salsa", + "serde", + "serde_json", + "threadpool", + "tokio", + "tokio-test", +] + +[[package]] +name = "kclvm" +version = "0.9.0" +dependencies = [ + "kclvm-api", + "kclvm-ast", + "kclvm-cmd", + "kclvm-compiler", + "kclvm-config", + "kclvm-driver", + "kclvm-error", + "kclvm-evaluator", + "kclvm-loader", + "kclvm-parser", + "kclvm-query", + "kclvm-runner", + "kclvm-runtime", + "kclvm-sema", + "kclvm-tools", + "kclvm-version", +] + +[[package]] +name = "kclvm-api" +version = "0.9.0" +dependencies = [ + "anyhow", + "futures", + "indexmap 1.9.3", + "jsonrpc-stdio-server", + "kcl-language-server", + "kclvm-ast", + "kclvm-ast-pretty", + "kclvm-config", + "kclvm-driver", + "kclvm-error", + "kclvm-loader", + "kclvm-parser", + "kclvm-query", + "kclvm-runner", + "kclvm-runtime", + "kclvm-sema", + "kclvm-tools", + "kclvm-utils", + "maplit", + "once_cell", + "prost", + "prost-build", + "prost-types", + "prost-wkt", + "prost-wkt-build", + "prost-wkt-types", + "protoc-bin-vendored", + "serde", + "serde_json", + "serde_yaml", + "tempfile", + "tokio", +] + +[[package]] +name = "kclvm-ast" +version = "0.9.0" +dependencies = [ + "compiler_base_span", + "kclvm-error", + "kclvm-span", + "kclvm-utils", + "serde", + "serde_json", + "thread_local", + "uuid", +] + +[[package]] +name = "kclvm-ast-pretty" +version = "0.9.0" +dependencies = [ + "compiler_base_macros", + "compiler_base_session", + "fancy-regex", + "indexmap 1.9.3", + "kclvm-ast", + "kclvm-error", + "pretty_assertions", +] + +[[package]] +name = "kclvm-cmd" +version = "0.9.0" +dependencies = [ + "anyhow", + "clap", + "compiler_base_session", + "kclvm-api", + "kclvm-config", + "kclvm-driver", + "kclvm-error", + "kclvm-parser", + "kclvm-runner", + "kclvm-runtime", + "kclvm-tools", + "kclvm-version", +] + +[[package]] +name = "kclvm-compiler" +version = "0.9.0" +dependencies = [ + "ahash", + "bit-set", + "bitflags 1.3.2", + "fancy-regex", + "indexmap 1.9.3", + "kclvm-ast", + "kclvm-error", + "kclvm-runtime", + "kclvm-sema", + "once_cell", + "phf", + "time 0.2.27", + "unicode_names2", +] + +[[package]] +name = "kclvm-config" +version = "0.9.0" +dependencies = [ + "ahash", + "anyhow", + "chrono", + "dirs", + "glob", + "indexmap 1.9.3", + "kclvm-ast", + "kclvm-utils", + "kclvm-version", + "md-5 0.8.0", + "pathdiff", + "regex", + "ron", + "serde", + "serde_json", + "serde_yaml", + "toml", +] + +[[package]] +name = "kclvm-driver" +version = "0.9.0" +dependencies = [ + "anyhow", + "flate2", + "glob", + "indexmap 2.2.6", + "kclvm-ast", + "kclvm-config", + "kclvm-parser", + "kclvm-runtime", + "kclvm-utils", + "notify 6.1.1", + "oci-distribution", + "once_cell", + "parking_lot 0.12.3", + "serde", + "serde_json", + "tar", + "tokio", + "walkdir", +] + +[[package]] +name = "kclvm-error" +version = "0.9.0" +dependencies = [ + "annotate-snippets", + "anyhow", + "atty", + "compiler_base_error", + "compiler_base_macros", + "compiler_base_session", + "compiler_base_span", + "indexmap 1.9.3", + "kclvm-runtime", + "kclvm-span", + "kclvm-utils", + "serde", + "serde_json", + "termize", + "thiserror", + "tracing", +] + +[[package]] +name = "kclvm-evaluator" +version = "0.9.0" +dependencies = [ + "anyhow", + "generational-arena", + "indexmap 1.9.3", + "kclvm-ast", + "kclvm-error", + "kclvm-runtime", + "kclvm-sema", +] + +[[package]] +name = "kclvm-lexer" +version = "0.9.0" +dependencies = [ + "kclvm-error", + "rustc_lexer", + "unic-emoji-char", +] + +[[package]] +name = "kclvm-loader" +version = "0.9.0" +dependencies = [ + "anyhow", + "indexmap 1.9.3", + "kclvm-ast", + "kclvm-ast-pretty", + "kclvm-error", + "kclvm-parser", + "kclvm-query", + "kclvm-sema", + "maplit", +] + +[[package]] +name = "kclvm-macros" +version = "0.9.0" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.95", + "synstructure", +] + +[[package]] +name = "kclvm-parser" +version = "0.9.0" +dependencies = [ + "anyhow", + "bstr", + "compiler_base_error", + "compiler_base_macros", + "compiler_base_session", + "compiler_base_span", + "either", + "enquote", + "indexmap 1.9.3", + "kclvm-ast", + "kclvm-config", + "kclvm-error", + "kclvm-lexer", + "kclvm-sema", + "kclvm-span", + "kclvm-utils", + "num-bigint", + "petgraph", + "regex", + "rustc_lexer", + "serde", + "serde_json", + "tracing", + "unicode_names2", +] + +[[package]] +name = "kclvm-query" +version = "0.9.0" +dependencies = [ + "anyhow", + "compiler_base_macros", + "compiler_base_session", + "fancy-regex", + "indexmap 1.9.3", + "kclvm-ast", + "kclvm-ast-pretty", + "kclvm-error", + "kclvm-parser", + "kclvm-sema", + "maplit", + "serde", + "serde_json", +] + +[[package]] +name = "kclvm-runner" +version = "0.9.0" +dependencies = [ + "anyhow", + "cc", + "chrono", + "compiler_base_macros", + "compiler_base_session", + "glob", + "indexmap 1.9.3", + "kclvm-ast", + "kclvm-compiler", + "kclvm-config", + "kclvm-driver", + "kclvm-error", + "kclvm-evaluator", + "kclvm-parser", + "kclvm-query", + "kclvm-runtime", + "kclvm-sema", + "kclvm-utils", + "kclvm-version", + "libc", + "libloading", + "once_cell", + "serde", + "serde_json", + "tempfile", + "threadpool", + "uuid", + "walkdir", +] + +[[package]] +name = "kclvm-runtime" +version = "0.9.0" +dependencies = [ + "ahash", + "base64 0.13.0", + "bstr", + "chrono", + "fancy-regex", + "generational-arena", + "glob", + "handlebars", + "indexmap 1.9.3", + "itertools", + "kclvm_runtime_internal_macros", + "lazy_static", + "libc", + "md5", + "num-integer", + "phf", + "regex", + "serde", + "serde_json", + "serde_yaml", + "sha1", "sha2 0.9.9", "unic-ucd-bidi", "unic-ucd-category", "unicode-casing", + "uuid", +] + +[[package]] +name = "kclvm-sema" +version = "0.9.0" +dependencies = [ + "ahash", + "anyhow", + "bit-set", + "bitflags 1.3.2", + "compiler_base_error", + "compiler_base_macros", + "compiler_base_session", + "compiler_base_span", + "fancy-regex", + "generational-arena", + "indexmap 1.9.3", + "kclvm-ast", + "kclvm-ast-pretty", + "kclvm-error", + "kclvm-runtime", + "kclvm-span", + "kclvm-utils", + "lazy_static", + "once_cell", + "petgraph", + "phf", + "regex", + "serde", + "serde_json", + "suggestions", + "unicode_names2", +] + +[[package]] +name = "kclvm-span" +version = "0.9.0" +dependencies = [ + "compiler_base_span", + "kclvm-macros", + "parking_lot 0.11.2", + "scoped-tls", +] + +[[package]] +name = "kclvm-tools" +version = "0.9.0" +dependencies = [ + "anyhow", + "compiler_base_session", + "compiler_base_span", + "fancy-regex", + "indexmap 1.9.3", + "json-spanned-value", + "kclvm-ast", + "kclvm-ast-pretty", + "kclvm-config", + "kclvm-driver", + "kclvm-error", + "kclvm-parser", + "kclvm-query", + "kclvm-runner", + "kclvm-runtime", + "kclvm-sema", + "kclvm-utils", + "located_yaml", + "once_cell", + "regex", + "rustc_lexer", + "serde_json", + "serde_yaml", + "walkdir", +] + +[[package]] +name = "kclvm-utils" +version = "0.9.0" +dependencies = [ + "anyhow", + "fslock", + "regex", +] + +[[package]] +name = "kclvm-version" +version = "0.9.0" +dependencies = [ + "vergen", +] + +[[package]] +name = "kclvm_runtime_internal_macros" +version = "0.5.0" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.95", +] + +[[package]] +name = "kqueue" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7447f1ca1b7b563588a205fe93dea8df60fd981423a768bc1c0ded35ed147d0c" +dependencies = [ + "kqueue-sys", + "libc", +] + +[[package]] +name = "kqueue-sys" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed9625ffda8729b85e45cf04090035ac368927b8cebc34898e7c120f52e4838b" +dependencies = [ + "bitflags 1.3.2", + "libc", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.155" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" + +[[package]] +name = "libfuzzer-sys" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "336244aaeab6a12df46480dc585802aa743a72d66b11937844c61bbca84c991d" +dependencies = [ + "arbitrary", + "cc", + "once_cell", +] + +[[package]] +name = "libloading" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "efbc0f03f9a775e9f6aed295c6a1ba2253c5757a9e03d55c6caa46a681abcddd" +dependencies = [ + "cfg-if 1.0.0", + "winapi", +] + +[[package]] +name = "linked-hash-map" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" +dependencies = [ + "serde", +] + +[[package]] +name = "linux-raw-sys" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" + +[[package]] +name = "located_yaml" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bc68ee6f87a1be7fdba1dcfd854528371aa84a8390279b5d7a99d5da82add76" +dependencies = [ + "linked-hash-map", + "serde", + "yaml-rust", +] + +[[package]] +name = "lock_api" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "327fa5b6a6940e4699ec49a9beae1ea4845c6bab9314e4f84ac68742139d8c53" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" + +[[package]] +name = "lsp-server" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "248f65b78f6db5d8e1b1604b4098a28b43d21a8eb1deeca22b1c421b276c7095" +dependencies = [ + "crossbeam-channel", + "log", + "serde", + "serde_json", +] + +[[package]] +name = "lsp-types" +version = "0.93.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9be6e9c7e2d18f651974370d7aff703f9513e0df6e464fd795660edc77e6ca51" +dependencies = [ + "bitflags 1.3.2", + "serde", + "serde_json", + "serde_repr", + "url", +] + +[[package]] +name = "maplit" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d" + +[[package]] +name = "matches" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" + +[[package]] +name = "md-5" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a18af3dcaf2b0219366cdb4e2af65a6101457b415c3d1a5c71dd9c2b7c77b9c8" +dependencies = [ + "block-buffer 0.7.3", + "digest 0.8.1", + "opaque-debug 0.2.3", +] + +[[package]] +name = "md-5" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "658646b21e0b72f7866c7038ab086d3d5e1cd6271f060fd37defb241949d0582" +dependencies = [ + "digest 0.10.7", +] + +[[package]] +name = "md5" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "490cc448043f947bae3cbee9c203358d62dbee0db12107a74be5c30ccfd09771" + +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "memmap2" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "723e3ebdcdc5c023db1df315364573789f8857c11b631a2fdfad7c00f5c046b4" +dependencies = [ + "libc", +] + +[[package]] +name = "memoffset" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" +dependencies = [ + "autocfg", +] + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "miniz_oxide" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" +dependencies = [ + "adler", +] + +[[package]] +name = "mio" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" +dependencies = [ + "libc", + "log", + "wasi", + "windows-sys 0.48.0", +] + +[[package]] +name = "miow" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52ffbca2f655e33c08be35d87278e5b18b89550a37dbd598c20db92f6a471123" +dependencies = [ + "windows-sys 0.42.0", +] + +[[package]] +name = "multimap" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a" + +[[package]] +name = "notify" +version = "5.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "729f63e1ca555a43fe3efa4f3efdf4801c479da85b432242a7b726f353c88486" +dependencies = [ + "bitflags 1.3.2", + "crossbeam-channel", + "filetime", + "fsevent-sys", + "inotify", + "kqueue", + "libc", + "mio", + "walkdir", + "windows-sys 0.45.0", +] + +[[package]] +name = "notify" +version = "6.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6205bd8bb1e454ad2e27422015fb5e4f2bcc7e08fa8f27058670d208324a4d2d" +dependencies = [ + "bitflags 2.5.0", + "crossbeam-channel", + "filetime", + "fsevent-sys", + "inotify", + "kqueue", + "libc", + "log", + "mio", + "walkdir", + "windows-sys 0.48.0", +] + +[[package]] +name = "num-bigint" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-integer" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_cpus" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" +dependencies = [ + "hermit-abi 0.1.19", + "libc", +] + +[[package]] +name = "num_threads" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2819ce041d2ee131036f4fc9d6ae7ae125a3a40e97ba64d04fe799ad9dabbb44" +dependencies = [ + "libc", +] + +[[package]] +name = "object" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8bda667d9f2b5051b8833f59f3bf748b28ef54f850f4fcb389a252aa383866d1" +dependencies = [ + "memchr", +] + +[[package]] +name = "oci-distribution" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b95a2c51531af0cb93761f66094044ca6ea879320bccd35ab747ff3fcab3f422" +dependencies = [ + "bytes", + "chrono", + "futures-util", + "http", + "http-auth", + "jwt", + "lazy_static", + "olpc-cjson", + "regex", + "reqwest", + "serde", + "serde_json", + "sha2 0.10.2", + "thiserror", + "tokio", + "tracing", + "unicase", +] + +[[package]] +name = "olpc-cjson" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d637c9c15b639ccff597da8f4fa968300651ad2f1e968aefc3b4927a6fb2027a" +dependencies = [ + "serde", + "serde_json", + "unicode-normalization", +] + +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "oorandom" +version = "11.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" + +[[package]] +name = "opaque-debug" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" + +[[package]] +name = "opaque-debug" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" + +[[package]] +name = "option-ext" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" + +[[package]] +name = "parking_lot" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" +dependencies = [ + "instant", + "lock_api", + "parking_lot_core 0.8.6", +] + +[[package]] +name = "parking_lot" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" +dependencies = [ + "lock_api", + "parking_lot_core 0.9.3", +] + +[[package]] +name = "parking_lot_core" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc" +dependencies = [ + "cfg-if 1.0.0", + "instant", + "libc", + "redox_syscall 0.2.13", + "smallvec", + "winapi", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09a279cbf25cb0757810394fbc1e359949b59e348145c643a939a525692e6929" +dependencies = [ + "cfg-if 1.0.0", + "libc", + "redox_syscall 0.2.13", + "smallvec", + "windows-sys 0.36.1", +] + +[[package]] +name = "pathdiff" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd" + +[[package]] +name = "percent-encoding" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" + +[[package]] +name = "pest" +version = "2.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "560131c633294438da9f7c4b08189194b20946c8274c6b9e38881a7874dc8ee8" +dependencies = [ + "memchr", + "thiserror", + "ucd-trie", +] + +[[package]] +name = "pest_derive" +version = "2.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26293c9193fbca7b1a3bf9b79dc1e388e927e6cacaa78b4a3ab705a1d3d41459" +dependencies = [ + "pest", + "pest_generator", +] + +[[package]] +name = "pest_generator" +version = "2.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ec22af7d3fb470a85dd2ca96b7c577a1eb4ef6f1683a9fe9a8c16e136c04687" +dependencies = [ + "pest", + "pest_meta", + "proc-macro2", + "quote", + "syn 2.0.67", +] + +[[package]] +name = "pest_meta" +version = "2.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7a240022f37c361ec1878d646fc5b7d7c4d28d5946e1a80ad5a7a4f4ca0bdcd" +dependencies = [ + "once_cell", + "pest", + "sha2 0.10.2", +] + +[[package]] +name = "petgraph" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a13a2fa9d0b63e5f22328828741e523766fff0ee9e779316902290dff3f824f" +dependencies = [ + "fixedbitset", + "indexmap 1.9.3", +] + +[[package]] +name = "phf" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2ac8b67553a7ca9457ce0e526948cad581819238f4a9d1ea74545851fa24f37" +dependencies = [ + "phf_macros", + "phf_shared", + "proc-macro-hack", +] + +[[package]] +name = "phf_generator" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d43f3220d96e0080cc9ea234978ccd80d904eafb17be31bb0f76daaea6493082" +dependencies = [ + "phf_shared", + "rand", +] + +[[package]] +name = "phf_macros" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b706f5936eb50ed880ae3009395b43ed19db5bff2ebd459c95e7bf013a89ab86" +dependencies = [ + "phf_generator", + "phf_shared", + "proc-macro-hack", + "proc-macro2", + "quote", + "syn 1.0.95", +] + +[[package]] +name = "phf_shared" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a68318426de33640f02be62b4ae8eb1261be2efbc337b60c54d845bf4484e0d9" +dependencies = [ + "siphasher", +] + +[[package]] +name = "pin-project" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.67", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "ppv-lite86" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" + +[[package]] +name = "pretty_assertions" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af7cee1a6c8a5b9208b3cb1061f10c0cb689087b3d8ce85fb9d2dd7a29b6ba66" +dependencies = [ + "diff", + "yansi", +] + +[[package]] +name = "prettyplease" +version = "0.1.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c8646e95016a7a6c4adea95bafa8a16baab64b583356217f2c85db4a39d9a86" +dependencies = [ + "proc-macro2", + "syn 1.0.95", +] + +[[package]] +name = "proc-macro-hack" +version = "0.5.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" + +[[package]] +name = "proc-macro2" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "proc_macro_crate" +version = "0.1.0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.67", +] + +[[package]] +name = "prost" +version = "0.11.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b82eaa1d779e9a4bc1c3217db8ffbeabaae1dca241bf70183242128d48681cd" +dependencies = [ + "bytes", + "prost-derive", +] + +[[package]] +name = "prost-build" +version = "0.11.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "119533552c9a7ffacc21e099c24a0ac8bb19c2a2a3f363de84cd9b844feab270" +dependencies = [ + "bytes", + "heck 0.4.1", + "itertools", + "lazy_static", + "log", + "multimap", + "petgraph", + "prettyplease", + "prost", + "prost-types", + "regex", + "syn 1.0.95", + "tempfile", + "which", +] + +[[package]] +name = "prost-derive" +version = "0.11.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5d2d8d10f3c6ded6da8b05b5fb3b8a5082514344d56c9f871412d29b4e075b4" +dependencies = [ + "anyhow", + "itertools", + "proc-macro2", + "quote", + "syn 1.0.95", +] + +[[package]] +name = "prost-types" +version = "0.11.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "213622a1460818959ac1181aaeb2dc9c7f63df720db7d788b3e24eacd1983e13" +dependencies = [ + "prost", +] + +[[package]] +name = "prost-wkt" +version = "0.4.1" +dependencies = [ + "chrono", + "inventory", + "prost", + "serde", + "serde_derive", + "serde_json", + "typetag", +] + +[[package]] +name = "prost-wkt-build" +version = "0.4.1" +dependencies = [ + "heck 0.4.1", + "prost", + "prost-build", + "prost-types", + "quote", +] + +[[package]] +name = "prost-wkt-types" +version = "0.4.1" +dependencies = [ + "chrono", + "prost", + "prost-build", + "prost-types", + "prost-wkt", + "prost-wkt-build", + "protoc-bin-vendored", + "regex", + "serde", + "serde_derive", + "serde_json", +] + +[[package]] +name = "protoc-bin-vendored" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "005ca8623e5633e298ad1f917d8be0a44bcf406bf3cde3b80e63003e49a3f27d" +dependencies = [ + "protoc-bin-vendored-linux-aarch_64", + "protoc-bin-vendored-linux-ppcle_64", + "protoc-bin-vendored-linux-x86_32", + "protoc-bin-vendored-linux-x86_64", + "protoc-bin-vendored-macos-x86_64", + "protoc-bin-vendored-win32", +] + +[[package]] +name = "protoc-bin-vendored-linux-aarch_64" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fb9fc9cce84c8694b6ea01cc6296617b288b703719b725b8c9c65f7c5874435" + +[[package]] +name = "protoc-bin-vendored-linux-ppcle_64" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02d2a07dcf7173a04d49974930ccbfb7fd4d74df30ecfc8762cf2f895a094516" + +[[package]] +name = "protoc-bin-vendored-linux-x86_32" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d54fef0b04fcacba64d1d80eed74a20356d96847da8497a59b0a0a436c9165b0" + +[[package]] +name = "protoc-bin-vendored-linux-x86_64" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8782f2ce7d43a9a5c74ea4936f001e9e8442205c244f7a3d4286bd4c37bc924" + +[[package]] +name = "protoc-bin-vendored-macos-x86_64" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5de656c7ee83f08e0ae5b81792ccfdc1d04e7876b1d9a38e6876a9e09e02537" + +[[package]] +name = "protoc-bin-vendored-win32" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9653c3ed92974e34c5a6e0a510864dab979760481714c172e0a34e437cb98804" + +[[package]] +name = "quinn" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4ceeeeabace7857413798eb1ffa1e9c905a9946a57d81fb69b4b71c4d8eb3ad" +dependencies = [ + "bytes", + "pin-project-lite", + "quinn-proto", + "quinn-udp", + "rustc-hash", + "rustls", + "thiserror", + "tokio", + "tracing", +] + +[[package]] +name = "quinn-proto" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddf517c03a109db8100448a4be38d498df8a210a99fe0e1b9eaf39e78c640efe" +dependencies = [ + "bytes", + "rand", + "ring", + "rustc-hash", + "rustls", + "slab", + "thiserror", + "tinyvec", + "tracing", +] + +[[package]] +name = "quinn-udp" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9096629c45860fc7fb143e125eb826b5e721e10be3263160c7d60ca832cf8c46" +dependencies = [ + "libc", + "once_cell", + "socket2", + "tracing", + "windows-sys 0.52.0", +] + +[[package]] +name = "quote" +version = "1.0.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "ra_ap_paths" +version = "0.0.149" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d780b450680460bd7ea3e2483dcf15a3ac0ce0ec028696caa342c577d65e5506" + +[[package]] +name = "ra_ap_stdx" +version = "0.0.149" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d776542bf771f4fdf40c21ced864bf213924d8a60d580c970715818471ebd74c" +dependencies = [ + "always-assert", + "libc", + "miow", + "winapi", +] + +[[package]] +name = "ra_ap_vfs" +version = "0.0.149" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8cd60adecd0947e1dd41a3077713381aa0cdcba6dc8777300d7d5b83b9fbe84" +dependencies = [ + "fst", + "indexmap 1.9.3", + "ra_ap_paths", + "ra_ap_stdx", + "rustc-hash", +] + +[[package]] +name = "ra_ap_vfs-notify" +version = "0.0.149" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a680f2dbd796844ebeaa2a4d01ae209f412ddc2981f6512ab8bc9b471156e6cd" +dependencies = [ + "crossbeam-channel", + "jod-thread", + "notify 5.2.0", + "ra_ap_paths", + "ra_ap_vfs", + "tracing", + "walkdir", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rand_xoshiro" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f97cdb2a36ed4183de61b2f824cc45c9f1037f28afe0a322e9fff4c108b5aaa" +dependencies = [ + "rand_core", +] + +[[package]] +name = "redox_syscall" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42" +dependencies = [ + "bitflags 1.3.2", +] + +[[package]] +name = "redox_syscall" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" +dependencies = [ + "bitflags 1.3.2", +] + +[[package]] +name = "redox_syscall" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +dependencies = [ + "bitflags 1.3.2", +] + +[[package]] +name = "redox_users" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" +dependencies = [ + "getrandom", + "redox_syscall 0.2.13", + "thiserror", +] + +[[package]] +name = "regex" +version = "1.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b91213439dad192326a0d7c6ee3955910425f441d7038e0d6933b0aec5c4517f" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata 0.4.7", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" + +[[package]] +name = "regex-automata" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" + +[[package]] +name = "reqwest" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7d6d2a27d57148378eb5e111173f4276ad26340ecc5c49a4a2152167a2d6a37" +dependencies = [ + "base64 0.22.1", + "bytes", + "futures-core", + "futures-util", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-rustls", + "hyper-util", + "ipnet", + "js-sys", + "log", + "mime", + "once_cell", + "percent-encoding", + "pin-project-lite", + "quinn", + "rustls", + "rustls-pemfile", + "rustls-pki-types", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper", + "tokio", + "tokio-rustls", + "tokio-util 0.7.11", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "wasm-streams", + "web-sys", + "webpki-roots", + "winreg", +] + +[[package]] +name = "ring" +version = "0.17.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" +dependencies = [ + "cc", + "cfg-if 1.0.0", + "getrandom", + "libc", + "spin", + "untrusted", + "windows-sys 0.52.0", +] + +[[package]] +name = "ron" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b861ecaade43ac97886a512b360d01d66be9f41f3c61088b42cedf92e03d678" +dependencies = [ + "base64 0.13.0", + "bitflags 1.3.2", + "serde", +] + +[[package]] +name = "ropey" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93411e420bcd1a75ddd1dc3caf18c23155eda2c090631a85af21ba19e97093b5" +dependencies = [ + "smallvec", + "str_indices", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "rustc-rayon" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9974ab223660e61c1b4e7b43b827379df286736ca988308ce7e16f59f2d89246" +dependencies = [ + "crossbeam-deque", + "either", + "rustc-rayon-core 0.3.2", +] + +[[package]] +name = "rustc-rayon" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb81aadc8837ca6ecebe0fe1353f15df83b3b3cc2cf7a8afd571bc22aa121710" +dependencies = [ + "either", + "rustc-rayon-core 0.5.0", +] + +[[package]] +name = "rustc-rayon-core" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "564bfd27be8db888d0fa76aa4335e7851aaed0c2c11ad1e93aeb9349f6b88500" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", + "lazy_static", + "num_cpus", +] + +[[package]] +name = "rustc-rayon-core" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67668daaf00e359c126f6dcb40d652d89b458a008c8afa727a42a2d20fca0b7f" +dependencies = [ + "crossbeam-channel", + "crossbeam-deque", + "crossbeam-utils", + "num_cpus", +] + +[[package]] +name = "rustc_data_structures" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a38bae9c6afa27015bcaa2869e03bb111ecf0d0e0edc2da559a91d4057174c9a" +dependencies = [ + "arrayvec", + "bitflags 1.3.2", + "cfg-if 0.1.10", + "ena", + "indexmap 1.9.3", + "jobserver", + "libc", + "memmap2", + "parking_lot 0.12.3", + "rustc-hash", + "rustc-rayon 0.3.2", + "rustc-rayon-core 0.3.2", + "stable_deref_trait", + "tempfile", + "tracing", + "winapi", +] + +[[package]] +name = "rustc_errors" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00299b1841816d2c41129e6d4f86b0b446ee387e8203871c2551e1c405b1243c" +dependencies = [ + "termcolor", + "winapi", +] + +[[package]] +name = "rustc_lexer" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c86aae0c77166108c01305ee1a36a1e77289d7dc6ca0a3cd91ff4992de2d16a5" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "rustc_span" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "043e9cc06c53de1f6a125e41e4b915d23a130241610a114ad4fe4f654617eae4" +dependencies = [ + "cfg-if 0.1.10", + "md-5 0.10.1", + "rustc_data_structures", + "scoped-tls", + "sha-1", + "sha2 0.10.2", + "tracing", + "unicode-width", +] + +[[package]] +name = "rustc_version" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" +dependencies = [ + "semver 0.9.0", +] + +[[package]] +name = "rustc_version" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +dependencies = [ + "semver 1.0.18", +] + +[[package]] +name = "rustix" +version = "0.38.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" +dependencies = [ + "bitflags 2.5.0", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.52.0", +] + +[[package]] +name = "rustls" +version = "0.23.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05cff451f60db80f490f3c182b77c35260baace73209e9cdbbe526bfe3a4d402" +dependencies = [ + "once_cell", + "ring", + "rustls-pki-types", + "rustls-webpki", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-pemfile" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29993a25686778eb88d4189742cd713c9bce943bc54251a33509dc63cbacf73d" +dependencies = [ + "base64 0.22.1", + "rustls-pki-types", +] + +[[package]] +name = "rustls-pki-types" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "976295e77ce332211c0d24d92c0e83e50f5c5f046d11082cea19f3df13a3562d" + +[[package]] +name = "rustls-webpki" +version = "0.102.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff448f7e92e913c4b7d4c6d8e4540a1724b319b4152b8aef6d4cf8339712b33e" +dependencies = [ + "ring", + "rustls-pki-types", + "untrusted", +] + +[[package]] +name = "rustversion" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" + +[[package]] +name = "ryu" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3f6f92acf49d1b98f7a81226834412ada05458b7364277387724a237f062695" + +[[package]] +name = "salsa" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b84d9f96071f3f3be0dc818eae3327625d8ebc95b58da37d6850724f31d3403" +dependencies = [ + "crossbeam-utils", + "indexmap 1.9.3", + "lock_api", + "log", + "oorandom", + "parking_lot 0.11.2", + "rustc-hash", + "salsa-macros", + "smallvec", +] + +[[package]] +name = "salsa-macros" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd3904a4ba0a9d0211816177fd34b04c7095443f8cdacd11175064fe541c8fe2" +dependencies = [ + "heck 0.3.3", + "proc-macro2", + "quote", + "syn 1.0.95", +] + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", ] [[package]] -name = "kclvm-sema" -version = "0.1.0" +name = "scoped-tls" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2" + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "self_cell" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e14e4d63b804dc0c7ec4a1e52bcb63f02c7ac94476755aa579edac21e01f915d" dependencies = [ - "ahash", - "bit-set", - "bitflags", - "fancy-regex", - "indexmap", - "kclvm-ast", - "kclvm-error", - "kclvm-runtime", - "kclvm-span", - "once_cell", - "petgraph", - "phf", - "unicode_names2", + "self_cell 1.0.2", ] [[package]] -name = "kclvm-span" -version = "0.1.0" +name = "self_cell" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e388332cd64eb80cd595a00941baf513caffae8dce9cfd0467fc9c66397dade6" + +[[package]] +name = "semver" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" dependencies = [ - "kclvm-macros", - "rustc_span", - "scoped-tls", + "semver-parser", ] [[package]] -name = "kclvm-tools" -version = "0.1.0" +name = "semver" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0293b4b29daaf487284529cc2f5675b8e57c61f70167ba415a463651fd6a918" + +[[package]] +name = "semver-parser" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" + +[[package]] +name = "serde" +version = "1.0.203" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094" dependencies = [ - "fancy-regex", - "indexmap", - "kclvm-ast", - "kclvm-error", - "kclvm-parser", + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.203" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.67", +] + +[[package]] +name = "serde_json" +version = "1.0.115" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12dc5c46daa8e9fdf4f5e71b6cf9a53f2487da0e86e55808e2d35539666497dd" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_repr" +version = "0.1.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3081f5ffbb02284dda55132aa26daecedd7372a42417bbbab6f14ab7d6bb9145" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.67", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_yaml" +version = "0.9.34+deprecated" +dependencies = [ + "indexmap 2.2.6", + "itoa", + "ryu", + "serde", + "unsafe-libyaml", +] + +[[package]] +name = "sha-1" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "028f48d513f9678cda28f6e4064755b3fbb2af6acd672f2c209b62323f7aea0f" +dependencies = [ + "cfg-if 1.0.0", + "cpufeatures", + "digest 0.10.7", +] + +[[package]] +name = "sha1" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1da05c97445caa12d05e848c4a4fcbbea29e748ac28f7e80e9b010392063770" +dependencies = [ + "sha1_smol", +] + +[[package]] +name = "sha1_smol" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae1a47186c03a32177042e55dbc5fd5aee900b8e0069a8d70fba96a9375cd012" + +[[package]] +name = "sha2" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" +dependencies = [ + "block-buffer 0.9.0", + "cfg-if 1.0.0", + "cpufeatures", + "digest 0.9.0", + "opaque-debug 0.3.0", +] + +[[package]] +name = "sha2" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55deaec60f81eefe3cce0dc50bda92d6d8e88f2a27df7c5033b42afeb1ed2676" +dependencies = [ + "cfg-if 1.0.0", + "cpufeatures", + "digest 0.10.7", +] + +[[package]] +name = "signal-hook-registry" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" +dependencies = [ + "libc", +] + +[[package]] +name = "siphasher" +version = "0.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7bd3e3206899af3f8b12af284fafc038cc1dc2b41d1b89dd17297221c5d225de" + +[[package]] +name = "sized-chunks" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16d69225bde7a69b235da73377861095455d298f2b970996eec25ddbb42b3d1e" +dependencies = [ + "bitmaps", + "typenum", +] + +[[package]] +name = "slab" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6528351c9bc8ab22353f9d776db39a20288e8d6c37ef8cfe3317cf875eecfc2d" +dependencies = [ + "autocfg", +] + +[[package]] +name = "smallvec" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" + +[[package]] +name = "socket2" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" + +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + +[[package]] +name = "standback" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e113fb6f3de07a243d434a56ec6f186dfd51cb08448239fe7bcae73f87ff28ff" +dependencies = [ + "version_check", +] + +[[package]] +name = "stdweb" +version = "0.4.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d022496b16281348b52d0e30ae99e01a73d737b2f45d38fed4edf79f9325a1d5" +dependencies = [ + "discard", + "rustc_version 0.2.3", + "stdweb-derive", + "stdweb-internal-macros", + "stdweb-internal-runtime", + "wasm-bindgen", +] + +[[package]] +name = "stdweb-derive" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c87a60a40fccc84bef0652345bbbbbe20a605bf5d0ce81719fc476f5c03b50ef" +dependencies = [ + "proc-macro2", + "quote", + "serde", + "serde_derive", + "syn 1.0.95", +] + +[[package]] +name = "stdweb-internal-macros" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58fa5ff6ad0d98d1ffa8cb115892b6e69d67799f6763e162a1c9db421dc22e11" +dependencies = [ + "base-x", + "proc-macro2", + "quote", + "serde", + "serde_derive", + "serde_json", + "sha1", + "syn 1.0.95", +] + +[[package]] +name = "stdweb-internal-runtime" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "213701ba3370744dcd1a12960caa4843b3d68b4d1c0a5d575e0d65b2ee9d16c0" + +[[package]] +name = "str_indices" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9557cb6521e8d009c51a8666f09356f4b817ba9ba0981a305bd86aee47bd35c" + +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + +[[package]] +name = "subtle" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d0208408ba0c3df17ed26eb06992cb1a1268d41b2c0e12e65203fbe3972cee5" + +[[package]] +name = "suggestions" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5441c382482e49aaac2c3ea9cbcd24290531246e879ee94af5dfc4b144f11e80" +dependencies = [ + "strsim", ] [[package]] -name = "kclvm-version" -version = "0.1.0" +name = "syn" +version = "1.0.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbaf6116ab8924f39d52792136fb74fd60a80194cf1b1c6ffa6453eef1c3f942" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] [[package]] -name = "kclvm_runtime_internal_macros" -version = "0.1.0" +name = "syn" +version = "2.0.67" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff8655ed1d86f3af4ee3fd3263786bc14245ad17c4c7e85ba7187fb3ae028c90" dependencies = [ "proc-macro2", "quote", - "syn", + "unicode-ident", ] [[package]] -name = "lazy_static" -version = "1.4.0" +name = "sync_wrapper" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394" [[package]] -name = "libc" -version = "0.2.126" +name = "synstructure" +version = "0.12.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" +checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.95", + "unicode-xid", +] [[package]] -name = "libfuzzer-sys" -version = "0.4.3" +name = "tar" +version = "0.4.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "336244aaeab6a12df46480dc585802aa743a72d66b11937844c61bbca84c991d" +checksum = "cb797dad5fb5b76fcf519e702f4a589483b5ef06567f160c392832c1f5e44909" dependencies = [ - "arbitrary", - "cc", - "once_cell", + "filetime", + "libc", + "xattr", ] [[package]] -name = "libloading" -version = "0.7.3" +name = "tempfile" +version = "3.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efbc0f03f9a775e9f6aed295c6a1ba2253c5757a9e03d55c6caa46a681abcddd" +checksum = "dc02fddf48964c42031a0b3fe0428320ecf3a73c401040fc0096f97794310651" dependencies = [ "cfg-if 1.0.0", - "winapi", + "fastrand", + "redox_syscall 0.3.5", + "rustix", + "windows-sys 0.48.0", ] [[package]] -name = "linked-hash-map" -version = "0.5.4" +name = "termcolor" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fb9b38af92608140b86b693604b9ffcc5824240a484d1ecd4795bacb2fe88f3" +checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" +dependencies = [ + "winapi-util", +] [[package]] -name = "llvm-sys" -version = "120.2.4" +name = "termize" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09b716322964966a62377cf86e64f00ca7043505fdf27bd2ec7d41ae6682d1e7" +checksum = "1706be6b564323ce7092f5f7e6b118a14c8ef7ed0e69c8c5329c914a9f101295" dependencies = [ - "cc", - "lazy_static", "libc", - "regex", - "semver", + "winapi", ] [[package]] -name = "lock_api" -version = "0.4.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "327fa5b6a6940e4699ec49a9beae1ea4845c6bab9314e4f84ac68742139d8c53" +name = "tests-fuzz" +version = "0.0.0" dependencies = [ - "autocfg", - "scopeguard", + "arbitrary", + "kclvm", + "kclvm-parser", + "kclvm-runtime", + "libfuzzer-sys", + "serde_json", ] [[package]] -name = "log" -version = "0.4.17" +name = "thiserror" +version = "1.0.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" +checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709" dependencies = [ - "cfg-if 1.0.0", + "thiserror-impl", ] [[package]] -name = "matches" -version = "0.1.9" +name = "thiserror-impl" +version = "1.0.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" +checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.67", +] [[package]] -name = "md-5" -version = "0.10.1" +name = "thread_local" +version = "1.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "658646b21e0b72f7866c7038ab086d3d5e1cd6271f060fd37defb241949d0582" +checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152" dependencies = [ - "digest 0.10.3", + "cfg-if 1.0.0", + "once_cell", ] [[package]] -name = "md5" -version = "0.7.0" +name = "threadpool" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "490cc448043f947bae3cbee9c203358d62dbee0db12107a74be5c30ccfd09771" +checksum = "d050e60b33d41c19108b32cea32164033a9013fe3b46cbd4457559bfbf77afaa" +dependencies = [ + "num_cpus", +] [[package]] -name = "memchr" -version = "2.5.0" +name = "time" +version = "0.2.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +checksum = "4752a97f8eebd6854ff91f1c1824cd6160626ac4bd44287f7f4ea2035a02a242" +dependencies = [ + "const_fn", + "libc", + "standback", + "stdweb", + "time-macros 0.1.1", + "version_check", + "winapi", +] [[package]] -name = "memmap2" -version = "0.2.3" +name = "time" +version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "723e3ebdcdc5c023db1df315364573789f8857c11b631a2fdfad7c00f5c046b4" +checksum = "b0fdd63d58b18d663fbdf70e049f00a22c8e42be082203be7f26589213cd75ea" dependencies = [ + "deranged", + "itoa", "libc", + "num_threads", + "serde", + "time-core", + "time-macros 0.2.11", ] [[package]] -name = "memoffset" -version = "0.6.5" +name = "time-core" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" -dependencies = [ - "autocfg", -] +checksum = "7300fbefb4dadc1af235a9cef3737cea692a9d97e1b9cbcd4ebdae6f8868e6fb" [[package]] -name = "num-bigint" -version = "0.4.3" +name = "time-macros" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f" +checksum = "957e9c6e26f12cb6d0dd7fc776bb67a706312e7299aed74c8dd5b17ebb27e2f1" dependencies = [ - "autocfg", - "num-integer", - "num-traits", + "proc-macro-hack", + "time-macros-impl", ] [[package]] -name = "num-integer" -version = "0.1.45" +name = "time-macros" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +checksum = "eb71511c991639bb078fd5bf97757e03914361c48100d52878b8e52b46fb92cd" dependencies = [ - "autocfg", - "num-traits", + "time-core", ] [[package]] -name = "num-traits" -version = "0.2.15" +name = "time-macros-impl" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +checksum = "fd3c141a1b43194f3f56a1411225df8646c55781d5f26db825b3d98507eb482f" dependencies = [ - "autocfg", + "proc-macro-hack", + "proc-macro2", + "quote", + "standback", + "syn 1.0.95", ] [[package]] -name = "num_cpus" -version = "1.13.1" +name = "tinystr" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" +checksum = "7ac3f5b6856e931e15e07b478e98c8045239829a65f9156d4fa7e7788197a5ef" dependencies = [ - "hermit-abi", - "libc", + "displaydoc", ] [[package]] -name = "once_cell" -version = "1.12.0" +name = "tinyvec" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7709cef83f0c1f58f666e746a08b21e0085f7440fa6a29cc194d68aac97a4225" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +dependencies = [ + "tinyvec_macros", +] [[package]] -name = "opaque-debug" -version = "0.3.0" +name = "tinyvec_macros" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] -name = "parking_lot" -version = "0.12.0" +name = "tokio" +version = "1.38.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87f5ec2493a61ac0506c0f4199f99070cbe83857b0337006a30f3e6719b8ef58" +checksum = "ba4f4a02a7a80d6f274636f0aa95c7e383b912d41fe721a31f29e29698585a4a" dependencies = [ - "lock_api", - "parking_lot_core", + "backtrace", + "bytes", + "libc", + "mio", + "num_cpus", + "parking_lot 0.12.3", + "pin-project-lite", + "signal-hook-registry", + "socket2", + "tokio-macros", + "windows-sys 0.48.0", ] [[package]] -name = "parking_lot_core" -version = "0.9.3" +name = "tokio-macros" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09a279cbf25cb0757810394fbc1e359949b59e348145c643a939a525692e6929" +checksum = "5f5ae998a069d4b5aba8ee9dad856af7d520c3699e6159b185c2acd48155d39a" dependencies = [ - "cfg-if 1.0.0", - "libc", - "redox_syscall", - "smallvec", - "windows-sys", + "proc-macro2", + "quote", + "syn 2.0.67", ] [[package]] -name = "pathdiff" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd" - -[[package]] -name = "pest" -version = "2.1.3" +name = "tokio-rustls" +version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10f4872ae94d7b90ae48754df22fd42ad52ce740b8f370b03da4835417403e53" +checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4" dependencies = [ - "ucd-trie", + "rustls", + "rustls-pki-types", + "tokio", ] [[package]] -name = "petgraph" -version = "0.6.0" +name = "tokio-stream" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a13a2fa9d0b63e5f22328828741e523766fff0ee9e779316902290dff3f824f" +checksum = "397c988d37662c7dda6d2208364a706264bf3d6138b11d436cbac0ad38832842" dependencies = [ - "fixedbitset", - "indexmap", + "futures-core", + "pin-project-lite", + "tokio", ] [[package]] -name = "phf" -version = "0.9.0" +name = "tokio-test" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2ac8b67553a7ca9457ce0e526948cad581819238f4a9d1ea74545851fa24f37" +checksum = "e89b3cbabd3ae862100094ae433e1def582cf86451b4e9bf83aa7ac1d8a7d719" dependencies = [ - "phf_macros", - "phf_shared", - "proc-macro-hack", + "async-stream", + "bytes", + "futures-core", + "tokio", + "tokio-stream", ] [[package]] -name = "phf_generator" -version = "0.9.1" +name = "tokio-util" +version = "0.6.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d43f3220d96e0080cc9ea234978ccd80d904eafb17be31bb0f76daaea6493082" +checksum = "36943ee01a6d67977dd3f84a5a1d2efeb4ada3a1ae771cadfaa535d9d9fc6507" dependencies = [ - "phf_shared", - "rand 0.8.5", + "bytes", + "futures-core", + "futures-sink", + "log", + "pin-project-lite", + "tokio", ] [[package]] -name = "phf_macros" -version = "0.9.0" +name = "tokio-util" +version = "0.7.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b706f5936eb50ed880ae3009395b43ed19db5bff2ebd459c95e7bf013a89ab86" +checksum = "9cf6b47b3771c49ac75ad09a6162f53ad4b8088b76ac60e8ec1455b31a189fe1" dependencies = [ - "phf_generator", - "phf_shared", - "proc-macro-hack", - "proc-macro2", - "quote", - "syn", + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", ] [[package]] -name = "phf_shared" -version = "0.9.0" +name = "toml" +version = "0.5.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a68318426de33640f02be62b4ae8eb1261be2efbc337b60c54d845bf4484e0d9" +checksum = "8d82e1a7758622a465f8cee077614c73484dac5b836c02ff6a40d5d1010324d7" dependencies = [ - "siphasher", + "serde", ] [[package]] -name = "pin-project-lite" -version = "0.2.9" +name = "tower" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" +checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" +dependencies = [ + "futures-core", + "futures-util", + "pin-project", + "pin-project-lite", + "tokio", + "tower-layer", + "tower-service", +] [[package]] -name = "ppv-lite86" -version = "0.2.16" +name = "tower-layer" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" +checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" [[package]] -name = "proc-macro-hack" -version = "0.5.19" +name = "tower-service" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" +checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" [[package]] -name = "proc-macro2" -version = "1.0.39" +name = "tracing" +version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c54b25569025b7fc9651de43004ae593a75ad88543b17178aa5e1b9c4f15f56f" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ - "unicode-ident", + "log", + "pin-project-lite", + "tracing-attributes", + "tracing-core", ] [[package]] -name = "psm" -version = "0.1.18" +name = "tracing-attributes" +version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "871372391786ccec00d3c5d3d6608905b3d4db263639cfe075d3b60a736d115a" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ - "cc", + "proc-macro2", + "quote", + "syn 2.0.67", ] [[package]] -name = "quote" -version = "1.0.18" +name = "tracing-core" +version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" dependencies = [ - "proc-macro2", + "once_cell", ] [[package]] -name = "rand" -version = "0.3.23" +name = "try-lock" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64ac302d8f83c0c1974bf758f6b041c6c8ada916fbb44a609158ca8b064cc76c" -dependencies = [ - "libc", - "rand 0.4.6", -] +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] -name = "rand" -version = "0.4.6" +name = "type-map" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" +checksum = "b6d3364c5e96cb2ad1603037ab253ddd34d7fb72a58bdddf4b7350760fc69a46" dependencies = [ - "fuchsia-cprng", - "libc", - "rand_core 0.3.1", - "rdrand", - "winapi", + "rustc-hash", ] [[package]] -name = "rand" -version = "0.8.5" +name = "typenum" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" -dependencies = [ - "libc", - "rand_chacha", - "rand_core 0.6.3", -] +checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" [[package]] -name = "rand_chacha" -version = "0.3.1" +name = "typetag" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +checksum = "aec6850cc671cd0cfb3ab285465e48a3b927d9de155051c35797446b32f9169f" dependencies = [ - "ppv-lite86", - "rand_core 0.6.3", + "erased-serde", + "inventory", + "once_cell", + "serde", + "typetag-impl", ] [[package]] -name = "rand_core" -version = "0.3.1" +name = "typetag-impl" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" +checksum = "30c49a6815b4f8379c36f06618bc1b80ca77aaf8a3fd4d8549dca6fdb016000f" dependencies = [ - "rand_core 0.4.2", + "proc-macro2", + "quote", + "syn 2.0.67", ] [[package]] -name = "rand_core" -version = "0.4.2" +name = "ucd-trie" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" +checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9" [[package]] -name = "rand_core" -version = "0.6.3" +name = "unic-char-property" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" +checksum = "a8c57a407d9b6fa02b4795eb81c5b6652060a15a7903ea981f3d723e6c0be221" dependencies = [ - "getrandom", + "unic-char-range", ] [[package]] -name = "rdrand" -version = "0.4.0" +name = "unic-char-range" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" -dependencies = [ - "rand_core 0.3.1", -] +checksum = "0398022d5f700414f6b899e10b8348231abf9173fa93144cbc1a43b9793c1fbc" [[package]] -name = "redox_syscall" -version = "0.2.13" +name = "unic-common" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42" -dependencies = [ - "bitflags", -] +checksum = "80d7ff825a6a654ee85a63e80f92f054f904f21e7d12da4e22f9834a4aaa35bc" [[package]] -name = "regex" -version = "1.5.6" +name = "unic-emoji-char" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d83f127d94bdbcda4c8cc2e50f6f84f4b611f69c902699ca385a39c3a75f9ff1" +checksum = "0b07221e68897210270a38bde4babb655869637af0f69407f96053a34f76494d" dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", + "unic-char-property", + "unic-char-range", + "unic-ucd-version", ] [[package]] -name = "regex-automata" -version = "0.1.10" +name = "unic-langid" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" +checksum = "398f9ad7239db44fd0f80fe068d12ff22d78354080332a5077dc6f52f14dcf2f" +dependencies = [ + "unic-langid-impl", + "unic-langid-macros", +] [[package]] -name = "regex-syntax" -version = "0.6.26" +name = "unic-langid-impl" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49b3de9ec5dc0a3417da371aab17d729997c15010e7fd24ff707773a33bddb64" +checksum = "e35bfd2f2b8796545b55d7d3fd3e89a0613f68a0d1c8bc28cb7ff96b411a35ff" +dependencies = [ + "tinystr", +] [[package]] -name = "remove_dir_all" -version = "0.5.3" +name = "unic-langid-macros" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" +checksum = "055e618bf694161ffff0466d95cef3e1a5edc59f6ba1888e97801f2b4ebdc4fe" dependencies = [ - "winapi", + "proc-macro-hack", + "tinystr", + "unic-langid-impl", + "unic-langid-macros-impl", ] [[package]] -name = "ron" -version = "0.7.0" +name = "unic-langid-macros-impl" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b861ecaade43ac97886a512b360d01d66be9f41f3c61088b42cedf92e03d678" +checksum = "1f5cdec05b907f4e2f6843f4354f4ce6a5bebe1a56df320a49134944477ce4d8" dependencies = [ - "base64", - "bitflags", - "serde", + "proc-macro-hack", + "quote", + "syn 1.0.95", + "unic-langid-impl", ] [[package]] -name = "rust-crypto" -version = "0.2.36" +name = "unic-ucd-bidi" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f76d05d3993fd5f4af9434e8e436db163a12a9d40e1a58a726f27a01dfd12a2a" +checksum = "d1d568b51222484e1f8209ce48caa6b430bf352962b877d592c29ab31fb53d8c" dependencies = [ - "gcc", - "libc", - "rand 0.3.23", - "rustc-serialize", - "time", + "unic-char-property", + "unic-char-range", + "unic-ucd-version", ] [[package]] -name = "rustc-hash" -version = "1.1.0" +name = "unic-ucd-category" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" +checksum = "1b8d4591f5fcfe1bd4453baaf803c40e1b1e69ff8455c47620440b46efef91c0" +dependencies = [ + "matches", + "unic-char-property", + "unic-char-range", + "unic-ucd-version", +] [[package]] -name = "rustc-rayon" -version = "0.3.2" +name = "unic-ucd-version" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9974ab223660e61c1b4e7b43b827379df286736ca988308ce7e16f59f2d89246" +checksum = "96bd2f2237fe450fcd0a1d2f5f4e91711124f7857ba2e964247776ebeeb7b0c4" dependencies = [ - "crossbeam-deque", - "either", - "rustc-rayon-core", + "unic-common", ] [[package]] -name = "rustc-rayon-core" -version = "0.3.2" +name = "unicase" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "564bfd27be8db888d0fa76aa4335e7851aaed0c2c11ad1e93aeb9349f6b88500" +checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89" dependencies = [ - "crossbeam-deque", - "crossbeam-utils", - "lazy_static", - "num_cpus", + "version_check", ] [[package]] -name = "rustc-serialize" -version = "0.3.24" +name = "unicode-bidi" +version = "0.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda" +checksum = "6f2528f27a9eb2b21e69c95319b30bd0efd85d09c379741b0f78ea1d86be2416" [[package]] -name = "rustc_data_structures" -version = "0.0.0" -dependencies = [ - "arrayvec", - "bitflags", - "cfg-if 0.1.10", - "ena", - "indexmap", - "jobserver", - "libc", - "memmap2", - "parking_lot", - "rustc-hash", - "rustc-rayon", - "rustc-rayon-core", - "stable_deref_trait", - "stacker", - "tempfile", - "tracing", - "winapi", -] +name = "unicode-casing" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "623f59e6af2a98bdafeb93fa277ac8e1e40440973001ca15cf4ae1541cd16d56" [[package]] -name = "rustc_lexer" -version = "0.1.0" +name = "unicode-ident" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c86aae0c77166108c01305ee1a36a1e77289d7dc6ca0a3cd91ff4992de2d16a5" -dependencies = [ - "unicode-xid", -] +checksum = "d22af068fba1eb5edcb4aea19d382b2a3deb4c8f9d475c589b6ada9e0fd493ee" [[package]] -name = "rustc_span" -version = "0.0.0" +name = "unicode-normalization" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" dependencies = [ - "cfg-if 0.1.10", - "md-5", - "rustc_data_structures", - "scoped-tls", - "sha-1", - "sha2 0.10.2", - "tracing", - "unicode-width", + "tinyvec", ] [[package]] -name = "ryu" -version = "1.0.10" +name = "unicode-segmentation" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3f6f92acf49d1b98f7a81226834412ada05458b7364277387724a237f062695" +checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" [[package]] -name = "same-file" -version = "1.0.6" +name = "unicode-width" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" -dependencies = [ - "winapi-util", -] +checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" [[package]] -name = "scoped-tls" -version = "1.0.0" +name = "unicode-xid" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2" +checksum = "957e51f3646910546462e67d5f7599b9e4fb8acdd304b087a6494730f9eebf04" [[package]] -name = "scopeguard" -version = "1.1.0" +name = "unicode_names2" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" +checksum = "87d6678d7916394abad0d4b19df4d3802e1fd84abd7d701f39b75ee71b9e8cf1" [[package]] -name = "semver" -version = "0.11.0" +name = "unsafe-libyaml" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6" -dependencies = [ - "semver-parser", -] +checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" [[package]] -name = "semver-parser" -version = "0.10.2" +name = "untrusted" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0bef5b7f9e0df16536d3961cfb6e84331c065b4066afb39768d0e319411f7" -dependencies = [ - "pest", -] +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] -name = "serde" -version = "1.0.137" +name = "url" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61ea8d54c77f8315140a05f4c7237403bf38b72704d031543aa1d16abbf517d1" +checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" dependencies = [ - "serde_derive", + "form_urlencoded", + "idna", + "percent-encoding", + "serde", ] [[package]] -name = "serde_derive" -version = "1.0.137" +name = "utf8parse" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f26faba0c3959972377d3b2d306ee9f71faee9714294e41bb777f83f88578be" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] +checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" [[package]] -name = "serde_json" -version = "1.0.81" +name = "uuid" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b7ce2b32a1aed03c558dc61a5cd328f15aff2dbc17daad8fb8af04d2100e15c" +checksum = "a183cf7feeba97b4dd1c0d46788634f6221d87fa961b305bed08c851829efcc0" dependencies = [ - "itoa", - "ryu", + "getrandom", "serde", ] [[package]] -name = "serde_yaml" -version = "0.8.24" +name = "vergen" +version = "8.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "707d15895415db6628332b737c838b88c598522e4dc70647e59b72312924aebc" +checksum = "bbc5ad0d9d26b2c49a5ab7da76c3e79d3ee37e7821799f8223fcb8f2f391a2e7" dependencies = [ - "indexmap", - "ryu", - "serde", - "yaml-rust", + "anyhow", + "rustc_version 0.4.0", + "rustversion", + "time 0.3.25", ] [[package]] -name = "sha-1" -version = "0.10.0" +name = "version_check" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "028f48d513f9678cda28f6e4064755b3fbb2af6acd672f2c209b62323f7aea0f" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "walkdir" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" dependencies = [ - "cfg-if 1.0.0", - "cpufeatures", - "digest 0.10.3", + "same-file", + "winapi", + "winapi-util", ] [[package]] -name = "sha1" -version = "0.6.1" +name = "want" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1da05c97445caa12d05e848c4a4fcbbea29e748ac28f7e80e9b010392063770" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" dependencies = [ - "sha1_smol", + "try-lock", ] [[package]] -name = "sha1_smol" -version = "1.0.0" +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae1a47186c03a32177042e55dbc5fd5aee900b8e0069a8d70fba96a9375cd012" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] -name = "sha2" -version = "0.9.9" +name = "wasm-bindgen" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" +checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" dependencies = [ - "block-buffer 0.9.0", "cfg-if 1.0.0", - "cpufeatures", - "digest 0.9.0", - "opaque-debug", + "wasm-bindgen-macro", ] [[package]] -name = "sha2" -version = "0.10.2" +name = "wasm-bindgen-backend" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55deaec60f81eefe3cce0dc50bda92d6d8e88f2a27df7c5033b42afeb1ed2676" +checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd" dependencies = [ - "cfg-if 1.0.0", - "cpufeatures", - "digest 0.10.3", + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn 2.0.67", + "wasm-bindgen-shared", ] [[package]] -name = "siphasher" -version = "0.3.10" +name = "wasm-bindgen-futures" +version = "0.4.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7bd3e3206899af3f8b12af284fafc038cc1dc2b41d1b89dd17297221c5d225de" +checksum = "c02dbc21516f9f1f04f187958890d7e6026df8d16540b7ad9492bc34a67cea03" +dependencies = [ + "cfg-if 1.0.0", + "js-sys", + "wasm-bindgen", + "web-sys", +] [[package]] -name = "smallvec" -version = "1.8.0" +name = "wasm-bindgen-macro" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83" +checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] [[package]] -name = "stable_deref_trait" -version = "1.2.0" +name = "wasm-bindgen-macro-support" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" +checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.67", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] [[package]] -name = "stacker" -version = "0.1.14" +name = "wasm-bindgen-shared" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90939d5171a4420b3ff5fbc8954d641e7377335454c259dcb80786f3f21dc9b4" -dependencies = [ - "cc", - "cfg-if 1.0.0", - "libc", - "psm", - "winapi", -] +checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" [[package]] -name = "strsim" -version = "0.8.0" +name = "wasm-streams" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" +checksum = "b65dc4c90b63b118468cf747d8bf3566c1913ef60be765b5730ead9e0a3ba129" +dependencies = [ + "futures-util", + "js-sys", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] [[package]] -name = "syn" -version = "1.0.95" +name = "web-sys" +version = "0.3.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbaf6116ab8924f39d52792136fb74fd60a80194cf1b1c6ffa6453eef1c3f942" +checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b" dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", + "js-sys", + "wasm-bindgen", ] [[package]] -name = "synstructure" -version = "0.12.6" +name = "webpki-roots" +version = "0.26.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" +checksum = "bd7c23921eeb1713a4e851530e9b9756e4fb0e89978582942612524cf09f01cd" dependencies = [ - "proc-macro2", - "quote", - "syn", - "unicode-xid", + "rustls-pki-types", ] [[package]] -name = "tempfile" -version = "3.3.0" +name = "which" +version = "4.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" +checksum = "2441c784c52b289a054b7201fc93253e288f094e2f4be9058343127c4226a269" dependencies = [ - "cfg-if 1.0.0", - "fastrand", + "either", "libc", - "redox_syscall", - "remove_dir_all", - "winapi", + "once_cell", ] [[package]] -name = "termcolor" -version = "1.1.3" +name = "winapi" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" dependencies = [ - "winapi-util", + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", ] [[package]] -name = "termize" -version = "0.1.1" +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1706be6b564323ce7092f5f7e6b118a14c8ef7ed0e69c8c5329c914a9f101295" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" dependencies = [ - "libc", "winapi", ] [[package]] -name = "tests-fuzz" -version = "0.0.0" -dependencies = [ - "arbitrary", - "kclvm", - "kclvm-parser", - "kclvm-runtime", - "libfuzzer-sys", - "serde_json", -] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] -name = "textwrap" -version = "0.11.0" +name = "windows-core" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" dependencies = [ - "unicode-width", + "windows-targets 0.52.0", ] [[package]] -name = "thiserror" -version = "1.0.31" +name = "windows-sys" +version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd829fe32373d27f76265620b5309d0340cb8550f523c1dda251d6298069069a" +checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2" dependencies = [ - "thiserror-impl", + "windows_aarch64_msvc 0.36.1", + "windows_i686_gnu 0.36.1", + "windows_i686_msvc 0.36.1", + "windows_x86_64_gnu 0.36.1", + "windows_x86_64_msvc 0.36.1", ] [[package]] -name = "thiserror-impl" -version = "1.0.31" +name = "windows-sys" +version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0396bc89e626244658bef819e22d0cc459e795a5ebe878e6ec336d1674a8d79a" +checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" dependencies = [ - "proc-macro2", - "quote", - "syn", + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", ] [[package]] -name = "threadpool" -version = "1.8.1" +name = "windows-sys" +version = "0.45.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d050e60b33d41c19108b32cea32164033a9013fe3b46cbd4457559bfbf77afaa" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" dependencies = [ - "num_cpus", + "windows-targets 0.42.2", ] [[package]] -name = "time" -version = "0.1.44" +name = "windows-sys" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ - "libc", - "wasi", - "winapi", + "windows-targets 0.48.1", ] [[package]] -name = "toml" -version = "0.5.9" +name = "windows-sys" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d82e1a7758622a465f8cee077614c73484dac5b836c02ff6a40d5d1010324d7" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "serde", + "windows-targets 0.52.0", ] [[package]] -name = "tracing" -version = "0.1.34" +name = "windows-targets" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d0ecdcb44a79f0fe9844f0c4f33a342cbcbb5117de8001e6ba0dc2351327d09" +checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" dependencies = [ - "cfg-if 1.0.0", - "pin-project-lite", - "tracing-attributes", - "tracing-core", + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", ] [[package]] -name = "tracing-attributes" -version = "0.1.21" +name = "windows-targets" +version = "0.48.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc6b8ad3567499f98a1db7a752b07a7c8c7c7c34c332ec00effb2b0027974b7c" +checksum = "05d4b17490f70499f20b9e791dcf6a299785ce8af4d709018206dc5b4953e95f" dependencies = [ - "proc-macro2", - "quote", - "syn", + "windows_aarch64_gnullvm 0.48.0", + "windows_aarch64_msvc 0.48.0", + "windows_i686_gnu 0.48.0", + "windows_i686_msvc 0.48.0", + "windows_x86_64_gnu 0.48.0", + "windows_x86_64_gnullvm 0.48.0", + "windows_x86_64_msvc 0.48.0", ] [[package]] -name = "tracing-core" -version = "0.1.26" +name = "windows-targets" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f54c8ca710e81886d498c2fd3331b56c93aa248d49de2222ad2742247c60072f" +checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" dependencies = [ - "lazy_static", + "windows_aarch64_gnullvm 0.52.0", + "windows_aarch64_msvc 0.52.0", + "windows_i686_gnu 0.52.0", + "windows_i686_msvc 0.52.0", + "windows_x86_64_gnu 0.52.0", + "windows_x86_64_gnullvm 0.52.0", + "windows_x86_64_msvc 0.52.0", ] [[package]] -name = "typenum" -version = "1.15.0" +name = "windows_aarch64_gnullvm" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" [[package]] -name = "ucd-trie" -version = "0.1.3" +name = "windows_aarch64_gnullvm" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c" +checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" [[package]] -name = "unic-char-property" -version = "0.9.0" +name = "windows_aarch64_gnullvm" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8c57a407d9b6fa02b4795eb81c5b6652060a15a7903ea981f3d723e6c0be221" -dependencies = [ - "unic-char-range", -] +checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" [[package]] -name = "unic-char-range" -version = "0.9.0" +name = "windows_aarch64_msvc" +version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0398022d5f700414f6b899e10b8348231abf9173fa93144cbc1a43b9793c1fbc" +checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" [[package]] -name = "unic-common" -version = "0.9.0" +name = "windows_aarch64_msvc" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80d7ff825a6a654ee85a63e80f92f054f904f21e7d12da4e22f9834a4aaa35bc" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" [[package]] -name = "unic-emoji-char" -version = "0.9.0" +name = "windows_aarch64_msvc" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b07221e68897210270a38bde4babb655869637af0f69407f96053a34f76494d" -dependencies = [ - "unic-char-property", - "unic-char-range", - "unic-ucd-version", -] +checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" [[package]] -name = "unic-ucd-bidi" -version = "0.9.0" +name = "windows_aarch64_msvc" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1d568b51222484e1f8209ce48caa6b430bf352962b877d592c29ab31fb53d8c" -dependencies = [ - "unic-char-property", - "unic-char-range", - "unic-ucd-version", -] +checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" [[package]] -name = "unic-ucd-category" -version = "0.9.0" +name = "windows_i686_gnu" +version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b8d4591f5fcfe1bd4453baaf803c40e1b1e69ff8455c47620440b46efef91c0" -dependencies = [ - "matches", - "unic-char-property", - "unic-char-range", - "unic-ucd-version", -] +checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" [[package]] -name = "unic-ucd-version" -version = "0.9.0" +name = "windows_i686_gnu" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96bd2f2237fe450fcd0a1d2f5f4e91711124f7857ba2e964247776ebeeb7b0c4" -dependencies = [ - "unic-common", -] +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" [[package]] -name = "unicode-casing" -version = "0.1.0" +name = "windows_i686_gnu" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "623f59e6af2a98bdafeb93fa277ac8e1e40440973001ca15cf4ae1541cd16d56" +checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" [[package]] -name = "unicode-ident" -version = "1.0.0" +name = "windows_i686_gnu" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d22af068fba1eb5edcb4aea19d382b2a3deb4c8f9d475c589b6ada9e0fd493ee" +checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" [[package]] -name = "unicode-width" -version = "0.1.9" +name = "windows_i686_msvc" +version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" +checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" [[package]] -name = "unicode-xid" -version = "0.2.3" +name = "windows_i686_msvc" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "957e51f3646910546462e67d5f7599b9e4fb8acdd304b087a6494730f9eebf04" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" [[package]] -name = "unicode_names2" -version = "0.4.0" +name = "windows_i686_msvc" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87d6678d7916394abad0d4b19df4d3802e1fd84abd7d701f39b75ee71b9e8cf1" +checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" [[package]] -name = "vec_map" -version = "0.8.2" +name = "windows_i686_msvc" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" +checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" [[package]] -name = "version_check" -version = "0.9.4" +name = "windows_x86_64_gnu" +version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" [[package]] -name = "walkdir" -version = "2.3.2" +name = "windows_x86_64_gnu" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" -dependencies = [ - "same-file", - "winapi", - "winapi-util", -] +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" [[package]] -name = "wasi" -version = "0.10.0+wasi-snapshot-preview1" +name = "windows_x86_64_gnu" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" +checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" [[package]] -name = "winapi" -version = "0.3.9" +name = "windows_x86_64_gnu" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] +checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" [[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" +name = "windows_x86_64_gnullvm" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" [[package]] -name = "winapi-util" -version = "0.1.5" +name = "windows_x86_64_gnullvm" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" -dependencies = [ - "winapi", -] +checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" [[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" +name = "windows_x86_64_gnullvm" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" [[package]] -name = "windows-sys" +name = "windows_x86_64_msvc" version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2" -dependencies = [ - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_msvc", -] +checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" [[package]] -name = "windows_aarch64_msvc" -version = "0.36.1" +name = "windows_x86_64_msvc" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" [[package]] -name = "windows_i686_gnu" -version = "0.36.1" +name = "windows_x86_64_msvc" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" +checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" [[package]] -name = "windows_i686_msvc" -version = "0.36.1" +name = "windows_x86_64_msvc" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" +checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" [[package]] -name = "windows_x86_64_gnu" -version = "0.36.1" +name = "winreg" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" +checksum = "a277a57398d4bfa075df44f501a17cfdf8542d224f0d36095a2adc7aee4ef0a5" +dependencies = [ + "cfg-if 1.0.0", + "windows-sys 0.48.0", +] [[package]] -name = "windows_x86_64_msvc" -version = "0.36.1" +name = "xattr" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" +checksum = "8da84f1a25939b27f6820d92aed108f83ff920fdf11a7b19366c27c4cda81d4f" +dependencies = [ + "libc", + "linux-raw-sys", + "rustix", +] [[package]] name = "yaml-rust" @@ -1752,3 +4631,24 @@ checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85" dependencies = [ "linked-hash-map", ] + +[[package]] +name = "yansi" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" + +[[package]] +name = "yansi-term" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe5c30ade05e61656247b2e334a031dfd0cc466fadef865bdcdea8d537951bf1" +dependencies = [ + "winapi", +] + +[[package]] +name = "zeroize" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" diff --git a/kclvm/tests/fuzz/Cargo.toml b/kclvm/tests/fuzz/Cargo.toml index 6148f3393..75867f156 100644 --- a/kclvm/tests/fuzz/Cargo.toml +++ b/kclvm/tests/fuzz/Cargo.toml @@ -9,8 +9,8 @@ edition = "2018" cargo-fuzz = true [dependencies] -kclvm-runtime = {path = "../../runtime", version = "0.1.0"} -kclvm-parser = {path="../../parser", version="0.1.0"} +kclvm-runtime = {path = "../../runtime"} +kclvm-parser = {path = "../../parser"} libfuzzer-sys = { version = "0.4.0", features = ["arbitrary-derive"] } arbitrary = { version = "1", features = ["derive"] } serde_json = "1.0" diff --git a/kclvm/tests/fuzz/fuzz_targets/fuzz_parser.rs b/kclvm/tests/fuzz/fuzz_targets/fuzz_parser.rs index feafa1f55..3c22d3444 100644 --- a/kclvm/tests/fuzz/fuzz_targets/fuzz_parser.rs +++ b/kclvm/tests/fuzz/fuzz_targets/fuzz_parser.rs @@ -1,6 +1,6 @@ #![no_main] -use kclvm::PanicInfo; use kclvm_parser::parse_expr; +use kclvm_runtime::PanicInfo; use libfuzzer_sys::arbitrary::Arbitrary; use libfuzzer_sys::fuzz_target; use serde_json; diff --git a/kclvm/tests/integration/grammar/test_grammar.py b/kclvm/tests/integration/grammar/test_grammar.py index bdbe5f4c9..88f15fbd7 100644 --- a/kclvm/tests/integration/grammar/test_grammar.py +++ b/kclvm/tests/integration/grammar/test_grammar.py @@ -3,20 +3,17 @@ import os import subprocess import re -import yaml import pathlib from ruamel.yaml import YAML TEST_FILE = "main.k" STDOUT_GOLDEN = "stdout.golden" STDERR_GOLDEN = "stderr.golden" -STDOUT_GOLDEN_PY = "stdout.golden.py" -STDERR_GOLDEN_PY = "stderr.golden.py" SETTINGS_FILE = "settings.yaml" TEST_PATH = "test/grammar" # Ruamel YAML instance -ruamel_yaml = YAML(typ="unsafe", pure=True) +ruamel_yaml = YAML(pure=True) # Convert None to null ruamel_yaml.representer.add_representer( type(None), @@ -92,7 +89,7 @@ def read_settings_file(settings_file_name): if os.path.isfile(settings_file_name): try: with open(settings_file_name, "r") as stream: - settings = yaml.safe_load(stream) + settings = ruamel_yaml.load(stream) except Exception: raise return settings @@ -106,11 +103,21 @@ def read_settings_file(settings_file_name): test_dirs = find_test_dirs(str(test_path), "") +def remove_ansi_escape_sequences(text): + ansi_escape_pattern = re.compile(r'(?:\x1B[@-_]|[\x80-\x9F])[0-?]*[ -/]*[@-~]') + return ansi_escape_pattern.sub('', text) + + +def remove_extra_empty_lines(text): + lines = [line for line in text.splitlines() if line.strip()] + return '\n'.join(lines) + + @pytest.mark.parametrize("test_dir", test_dirs) def test_grammar(test_dir): print("Testing {}".format(test_dir)) test_settings = read_settings_file(os.path.join(test_dir, SETTINGS_FILE)) - kcl_command = ["kcl", "--target", "native", TEST_FILE] + kcl_command = ["kclvm_cli", "run", TEST_FILE] if test_settings and test_settings["kcl_options"]: kcl_command.extend(test_settings["kcl_options"].split()) process = subprocess.Popen( @@ -123,32 +130,37 @@ def test_grammar(test_dir): stdout, stderr = process.communicate() print("STDOUT:\n{}".format(stdout.decode())) print("STDERR:\n{}".format(stderr.decode())) - RETURN_CODE = 0 - KCLVM_OUTPUT = 1 - GOLDEN_FILE = 2 - GOLDEN_FILE_SCRIPT = 3 - settings = { - "stdout": (None, stdout, STDOUT_GOLDEN, STDOUT_GOLDEN_PY), - "stderr": (1, stderr, STDERR_GOLDEN, STDERR_GOLDEN_PY), - } - for _, setting in settings.items(): - # Attempt to generate a golden stdout. - golden_file_result = generate_golden_file( - os.path.join(test_dir, setting[GOLDEN_FILE_SCRIPT]) - ) - if golden_file_result: - compare_results(setting[KCLVM_OUTPUT], golden_file_result) - else: - # Attempt to use existing golden stdout. - try: - with open( - os.path.join(test_dir, setting[GOLDEN_FILE]), "r" - ) as golden_file: - compare_results_with_lines(setting[KCLVM_OUTPUT], golden_file) - if setting[RETURN_CODE] is not None: - assert process.returncode == setting[RETURN_CODE] - except OSError: - # Ignore when a golden file does not exist. - pass - except Exception: - raise + # Attempt to use existing golden stdout. + try: + with open( + os.path.join(test_dir, STDOUT_GOLDEN), "r" + ) as golden_file: + compare_results_with_lines(stdout, golden_file) + assert process.returncode == 0 + except OSError: + # Ignore when a golden file does not exist. + pass + except Exception: + raise + + # Attempt to compare existing golden stdout. + try: + with open( + os.path.join(test_dir, STDOUT_GOLDEN), "r" + ) as golden_file: + compare_results_with_lines(stdout, golden_file) + assert process.returncode == 0 + except OSError: + # Ignore when a golden file does not exist. + pass + except Exception: + raise + + stderr_file = pathlib.Path(test_dir).joinpath(STDERR_GOLDEN) + cwd = os.path.abspath(test_dir) + if stderr_file.exists(): + golden = remove_extra_empty_lines(remove_ansi_escape_sequences(stderr_file.read_text())) + stderr = remove_extra_empty_lines(remove_ansi_escape_sequences(stderr.decode())) + golden = golden.replace("${CWD}", cwd) + assert golden in stderr + assert process.returncode > 0 diff --git a/kclvm/tests/integration/konfig/test_konfig_kcl.py b/kclvm/tests/integration/konfig/test_konfig_kcl.py new file mode 100644 index 000000000..0461deda6 --- /dev/null +++ b/kclvm/tests/integration/konfig/test_konfig_kcl.py @@ -0,0 +1,127 @@ +""" +this testing framework is developed based on pytest. +see quick start of pytest: https://docs.pytest.org/en/latest/example/simple.html + +""" +import os +import subprocess +from pathlib import Path + +import pytest +from ruamel.yaml import YAML +from collections.abc import Mapping, Sequence + +TEST_FILE = "kcl.yaml" +CI_TEST_DIR = "ci-test" +STDOUT_GOLDEN = "stdout.golden.yaml" +SETTINGS_FILE = "settings.yaml" +SKIP_TESTS = ["kcl-vault-csi"] + +ROOT_STR = "test/integration/konfig" +ROOT = str(Path(__file__).parent.parent.parent.parent.parent.joinpath(ROOT_STR)) + +yaml = YAML(typ="unsafe", pure=True) + + +def find_test_dirs(): + result = [] + root_dirs = [ROOT] + for root_dir in root_dirs: + for root, _, files in os.walk(root_dir): + for name in files: + if name == TEST_FILE: + if any([p in SKIP_TESTS for p in Path(root).parts]): + print(f"Skip {root}") + else: + result.append(root) + return result + + +def compare_results(result, golden_result): + """Convert result and golden_result string to string lines with line ending stripped, then compare.""" + result = [ + r + for r in list(yaml.load_all(result)) + if r and r.get("kind") != "SecretProviderClass" + ] + # Convert kusion compile spec to kcl result + expected = [ + r + for r in list(yaml.load_all(golden_result))[0] + if r["attributes"] + # Remove CRDs + and not r["id"].startswith("apiextensions.k8s.io/v1:CustomResourceDefinition") + ] + print(len(result), len(expected)) + assert compare_unordered_yaml_objects(result, expected) + + +def compare_unordered_yaml_objects(result, golden_result): + """Comparing the contents of two YAML objects for equality in an unordered manner""" + if isinstance(result, Mapping) and isinstance(golden_result, Mapping): + if result.keys() != golden_result.keys(): + return False + for key in result.keys(): + if not compare_unordered_yaml_objects(result[key], golden_result[key]): + return False + + return True + elif isinstance(result, Sequence) and isinstance(golden_result, Sequence): + if len(result) != len(golden_result): + return False + for item in result: + if item not in golden_result: + return False + for item in golden_result: + if item not in result: + return False + return True + else: + return result == golden_result + + +def has_settings_file(directory): + settings_file = directory / SETTINGS_FILE + return settings_file.is_file() + + +print("##### K Language Grammar Test Suite #####") +test_dirs = find_test_dirs() +pwd = str(Path(__file__).parent.parent.parent.parent) +os.environ["PYTHONPATH"] = pwd + + +@pytest.mark.parametrize("test_dir", test_dirs) +def test_konfigs(test_dir): + print(f"Testing {test_dir}") + test_dir = Path(test_dir) + kcl_file_name = test_dir / TEST_FILE + ci_test_dir = test_dir / CI_TEST_DIR + if not ci_test_dir.is_dir(): + # Skip invalid test cases + return + golden_file = ci_test_dir / STDOUT_GOLDEN + if not golden_file.is_file(): + # Skip invalid test cases + return + kcl_command = ["kcl"] + if has_settings_file(ci_test_dir): + kcl_command.append("-Y") + kcl_command.append(f"{CI_TEST_DIR}/{SETTINGS_FILE}") + kcl_command.append(f"kcl.yaml") + else: + kcl_command.append(f"{TEST_FILE}") + process = subprocess.run( + kcl_command, capture_output=True, cwd=test_dir, env=dict(os.environ) + ) + stdout, stderr = process.stdout, process.stderr + print(f"STDOUT:\n{stdout.decode()}") + assert ( + process.returncode == 0 and len(stderr) == 0 + ), f"Error executing file {kcl_file_name}.\nexit code = {process.returncode}\nstderr = {stderr}" + if process.returncode == 0 and len(stderr) == 0: + try: + with open(golden_file, "r") as golden: + compare_results(stdout.decode(), golden) + except FileNotFoundError: + raise Exception(f"Error reading expected result from file {golden_file}") diff --git a/kclvm/tests/test_units/runtime/base64/test_base64.py b/kclvm/tests/test_units/runtime/base64/test_base64.py index afd1a0fc5..a42f09f0b 100644 --- a/kclvm/tests/test_units/runtime/base64/test_base64.py +++ b/kclvm/tests/test_units/runtime/base64/test_base64.py @@ -1,4 +1,4 @@ -# Copyright 2021 The KCL Authors. All rights reserved. +# Copyright The KCL Authors. All rights reserved. import typing import unittest diff --git a/kclvm/tests/test_units/runtime/crypto/test_crypto.py b/kclvm/tests/test_units/runtime/crypto/test_crypto.py index bf467a410..8224964f9 100644 --- a/kclvm/tests/test_units/runtime/crypto/test_crypto.py +++ b/kclvm/tests/test_units/runtime/crypto/test_crypto.py @@ -1,4 +1,4 @@ -# Copyright 2021 The KCL Authors. All rights reserved. +# Copyright The KCL Authors. All rights reserved. import typing import unittest @@ -38,6 +38,9 @@ def sha384(self, value: str) -> str: def sha512(self, value: str) -> str: return self.dylib.Invoke(f"crypto.sha512", value) + def blake3(self, value: str) -> str: + return self.dylib.Invoke(f"crypto.blake3", value) + def test_md5(self): self.assertEqual( self.md5("The quick brown fox jumps over the lazy dog"), @@ -77,6 +80,12 @@ def test_sha512(self): self.sha512(""), "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e", ) + + def test_blake3(self): + self.assertEqual( + self.blake3(""), + "af1349b9f5f9a1a6a0404dea36dcc9499bcb25c9adc112b7cc9a93cae41f3262", + ) if __name__ == "__main__": diff --git a/kclvm/tests/test_units/runtime/datetime/test_datetime.py b/kclvm/tests/test_units/runtime/datetime/test_datetime.py index d63c92d29..70d1675a1 100644 --- a/kclvm/tests/test_units/runtime/datetime/test_datetime.py +++ b/kclvm/tests/test_units/runtime/datetime/test_datetime.py @@ -1,4 +1,4 @@ -# Copyright 2021 The KCL Authors. All rights reserved. +# Copyright The KCL Authors. All rights reserved. import typing import unittest diff --git a/kclvm/tests/test_units/runtime/json/test_json.py b/kclvm/tests/test_units/runtime/json/test_json.py index e847cac7c..2bdd1fccb 100644 --- a/kclvm/tests/test_units/runtime/json/test_json.py +++ b/kclvm/tests/test_units/runtime/json/test_json.py @@ -1,4 +1,4 @@ -# Copyright 2021 The KCL Authors. All rights reserved. +# Copyright The KCL Authors. All rights reserved. import typing import unittest diff --git a/kclvm/tests/test_units/runtime/kclvm_runtime.py b/kclvm/tests/test_units/runtime/kclvm_runtime.py new file mode 100644 index 000000000..6d6588610 --- /dev/null +++ b/kclvm/tests/test_units/runtime/kclvm_runtime.py @@ -0,0 +1,99 @@ +# Copyright The KCL Authors. All rights reserved. + +import ctypes +import json +import os +import sys + + +def _find_default_dylib_path() -> str: + _executable_root = os.path.dirname(os.environ.get("KCLVM_CLI_BIN_PATH") or sys.executable) + + pathList = [ + f"{_executable_root}/lib/libkclvm_cli_cdylib.dylib", + f"{_executable_root}/lib/libkclvm_cli_cdylib.so", + f"{_executable_root}/bin/libkclvm_cli_cdylib.dylib", + f"{_executable_root}/bin/libkclvm_cli_cdylib.so", + f"{_executable_root}\\bin\\kclvm_cli_cdylib.dll", + f"{os.path.dirname(__file__)}/../../../target/release/libkclvm_cli_cdylib.dylib", + f"{os.path.dirname(__file__)}/../../../target/release/libkclvm_cli_cdylib.so", + f"{os.path.dirname(__file__)}\\..\\..\\..\\target\\release\\kclvm_cli_cdylib.dll", + f"{os.path.dirname(__file__)}/../../../target/debug/libkclvm_cli_cdylib.dylib", + f"{os.path.dirname(__file__)}/../../../target/debug/libkclvm_cli_cdylib.so", + f"{os.path.dirname(__file__)}\\..\\..\\..\\target\\debug\\kclvm_cli_cdylib.dll", + ] + + for s in pathList: + if os.path.exists(s): + return s + return "" + + +class KclvmRuntimeDylib: + def __init__(self, dllpath: str = None): + if dllpath is None: + dllpath = _find_default_dylib_path() + if not dllpath: + raise f"kclvm runtime lib not found" + + self.dllpath = dllpath + self._app_dll = ctypes.cdll.LoadLibrary(dllpath) + self._app_lib = ctypes.CDLL(dllpath) + self.ctx = None + + # kclvm_context_t* kclvm_context_new(); + self._app_lib.kclvm_context_new.restype = ctypes.c_void_p + + # void kclvm_context_delete(kclvm_context_t* p); + self._app_lib.kclvm_context_delete.argtypes = [ + ctypes.c_void_p, + ] + + # const char* kclvm_context_invoke(kclvm_context_t* p, const char* method, const char* args, const char* kwargs); + self._app_lib.kclvm_context_invoke.restype = ctypes.c_char_p + self._app_lib.kclvm_context_invoke.argtypes = [ + ctypes.c_void_p, + ctypes.c_char_p, + ctypes.c_char_p, + ctypes.c_char_p, + ] + + def _kclvm_context_new(self) -> ctypes.c_void_p: + return self._app_lib.kclvm_context_new() + + def kclvm_context_delete(self, ctx: ctypes.c_void_p): + self._app_lib.kclvm_context_delete(ctx) + + def _kclvm_context_invoke( + self, ctx: ctypes.c_void_p, method: str, args: str, kwargs: str + ) -> any: + jsonValue = self._app_lib.kclvm_context_invoke( + ctx, method.encode(), args.encode(), kwargs.encode() + ) + return json.loads(jsonValue) + + def Path(self) -> str: + return self.dllpath + + def Invoke(self, method: str, *args, **kwargs) -> any: + if self.ctx is None: + self.ctx = self._kclvm_context_new() + + if not method.startswith("kclvm_"): + if method.startswith("str."): + # str.startswith => kclvm_builtin_str_startswith + method = f'kclvm_builtin_{method.replace(".", "_")}' + elif "." in method: + # regex.match => kclvm_regex_match + method = f'kclvm_{method.replace(".", "_")}' # json.encode => kclvm_json_encode + else: + method = f"kclvm_builtin_{method}" # print => kclvm_builtin_print + + return self._kclvm_context_invoke( + self.ctx, method, json.dumps(args), json.dumps(kwargs) + ) + + +if __name__ == "__main__": + dylib = KclvmRuntimeDylib() + dylib.Invoke(f"print", "hello kclvm") diff --git a/kclvm/tests/test_units/runtime/math/test_math.py b/kclvm/tests/test_units/runtime/math/test_math.py index 344ee51e9..18feb84b7 100644 --- a/kclvm/tests/test_units/runtime/math/test_math.py +++ b/kclvm/tests/test_units/runtime/math/test_math.py @@ -1,4 +1,4 @@ -# Copyright 2021 The KCL Authors. All rights reserved. +# Copyright The KCL Authors. All rights reserved. import sys import typing @@ -501,8 +501,8 @@ def testIsfinite(self): self.assertTrue(math.isfinite(-0.0)) self.assertTrue(math.isfinite(1.0)) self.assertTrue(math.isfinite(-1.0)) - self.assertFalse(math.isfinite(float("nan"))) - self.assertFalse(math.isfinite(float("inf"))) + #self.assertFalse(math.isfinite(float("nan"))) + #self.assertFalse(math.isfinite(float("inf"))) # self.assertFalse(math.isfinite(float("-inf"))) def testIsnan(self): @@ -518,7 +518,7 @@ def testIsinf(self): # self.assertTrue(math.isinf(float("-inf"))) # self.assertTrue(math.isinf(1e400)) # self.assertTrue(math.isinf(-1e400)) - self.assertFalse(math.isinf(float("nan"))) + #self.assertFalse(math.isinf(float("nan"))) self.assertFalse(math.isinf(0.0)) self.assertFalse(math.isinf(1.0)) diff --git a/kclvm/tests/test_units/runtime/net/test_net.py b/kclvm/tests/test_units/runtime/net/test_net.py index 46c3b6b6c..19606b595 100644 --- a/kclvm/tests/test_units/runtime/net/test_net.py +++ b/kclvm/tests/test_units/runtime/net/test_net.py @@ -1,4 +1,4 @@ -# Copyright 2021 The KCL Authors. All rights reserved. +# Copyright The KCL Authors. All rights reserved. import typing import unittest diff --git a/kclvm/tests/test_units/runtime/regex/test_regex.py b/kclvm/tests/test_units/runtime/regex/test_regex.py index 0ad72bd7c..351b8199b 100644 --- a/kclvm/tests/test_units/runtime/regex/test_regex.py +++ b/kclvm/tests/test_units/runtime/regex/test_regex.py @@ -1,4 +1,4 @@ -# Copyright 2021 The KCL Authors. All rights reserved. +# Copyright The KCL Authors. All rights reserved. import typing import unittest diff --git a/kclvm/tests/test_units/runtime/str/Makefile b/kclvm/tests/test_units/runtime/str/Makefile index 08fb119e3..7668a7923 100644 --- a/kclvm/tests/test_units/runtime/str/Makefile +++ b/kclvm/tests/test_units/runtime/str/Makefile @@ -1,7 +1,7 @@ -# Copyright 2021 The KCL Authors. All rights reserved. +# Copyright The KCL Authors. All rights reserved. default: python3 -m black . - kclvm -m pytest + python3 -m pytest clean: diff --git a/kclvm/tests/test_units/runtime/str/test_str.py b/kclvm/tests/test_units/runtime/str/test_str.py index e00fffeb2..e9a7ac488 100644 --- a/kclvm/tests/test_units/runtime/str/test_str.py +++ b/kclvm/tests/test_units/runtime/str/test_str.py @@ -1,4 +1,4 @@ -# Copyright 2021 The KCL Authors. All rights reserved. +# Copyright The KCL Authors. All rights reserved. import sys import unittest @@ -17,6 +17,12 @@ def checkequal(self, result, obj, methodname, *args, **kwargs): realresult = dylib.Invoke(f"str.{methodname}", obj, *args, **kwargs) self.assertEqual(result, realresult) + def test_chars(self): + self.checkequal([], "", "chars") + self.checkequal(["a"], "a", "chars") + self.checkequal(["a", "b", "c"], "abc", "chars") + self.checkequal(["一", "二", "三"], "一二三", "chars") + def test_count(self): self.checkequal(3, "aaa", "count", "a") self.checkequal(0, "aaa", "count", "b") @@ -521,6 +527,76 @@ def test_capitalize(self): # self.checkraises(TypeError, 'hello', 'capitalize', 42) + def test_removeprefix(self): + self.checkequal("a ", " aa ", "removeprefix", " a") + self.checkequal(" ", " aa ", "removeprefix", " aa") + self.checkequal("", " aa ", "removeprefix", " aa ") + + s = 'foobarfoo' + s_ref='foobarfoo' + + self.checkequal(s_ref[1:], s, "removeprefix", "f") + self.checkequal(s_ref[2:], s, "removeprefix", "fo") + self.checkequal(s_ref[3:], s, "removeprefix", "foo") + + self.checkequal(s_ref, s, "removeprefix", "") + self.checkequal(s_ref, s, "removeprefix", "bar") + self.checkequal(s_ref, s, "removeprefix", "lol") + self.checkequal(s_ref, s, "removeprefix", "_foo") + self.checkequal(s_ref, s, "removeprefix", "-foo") + self.checkequal(s_ref, s, "removeprefix", "afoo") + self.checkequal(s_ref, s, "removeprefix", "*foo") + + s_uc = '😱foobarfoo🖖' + s_ref_uc = '😱foobarfoo🖖' + + self.checkequal(s_ref_uc[1:], s_uc, "removeprefix", "😱") + self.checkequal(s_ref_uc[3:], s_uc, "removeprefix", "😱fo") + self.checkequal(s_ref_uc[4:], s_uc, "removeprefix", "😱foo") + + self.checkequal(s_ref_uc, s_uc, "removeprefix", "🖖") + self.checkequal(s_ref_uc, s_uc, "removeprefix", "foo") + self.checkequal(s_ref_uc, s_uc, "removeprefix", " ") + self.checkequal(s_ref_uc, s_uc, "removeprefix", "_😱") + self.checkequal(s_ref_uc, s_uc, "removeprefix", " 😱") + self.checkequal(s_ref_uc, s_uc, "removeprefix", "-😱") + self.checkequal(s_ref_uc, s_uc, "removeprefix", "#😱") + + def test_removesuffix(self): + self.checkequal(" a", " aa ", "removesuffix", "a ") + self.checkequal(" ", " aa ", "removesuffix", "aa ") + self.checkequal("", " aa ", "removesuffix", " aa ") + + s = 'foobarfoo' + s_ref='foobarfoo' + + self.checkequal(s_ref[:-1], s, "removesuffix", "o") + self.checkequal(s_ref[:-2], s, "removesuffix", "oo") + self.checkequal(s_ref[:-3], s, "removesuffix", "foo") + + self.checkequal(s_ref, s, "removesuffix", "") + self.checkequal(s_ref, s, "removesuffix", "bar") + self.checkequal(s_ref, s, "removesuffix", "lol") + self.checkequal(s_ref, s, "removesuffix", "_foo") + self.checkequal(s_ref, s, "removesuffix", "-foo") + self.checkequal(s_ref, s, "removesuffix", "afoo") + self.checkequal(s_ref, s, "removesuffix", "*foo") + + s_uc = '😱foobarfoo🖖' + s_ref_uc = '😱foobarfoo🖖' + + self.checkequal(s_ref_uc[:-1], s_uc, "removesuffix", "🖖") + self.checkequal(s_ref_uc[:-3], s_uc, "removesuffix", "oo🖖") + self.checkequal(s_ref_uc[:-4], s_uc, "removesuffix", "foo🖖") + + self.checkequal(s_ref_uc, s_uc, "removesuffix", "😱") + self.checkequal(s_ref_uc, s_uc, "removesuffix", "foo") + self.checkequal(s_ref_uc, s_uc, "removesuffix", " ") + self.checkequal(s_ref_uc, s_uc, "removesuffix", "🖖_") + self.checkequal(s_ref_uc, s_uc, "removesuffix", "🖖 ") + self.checkequal(s_ref_uc, s_uc, "removesuffix", "🖖-") + self.checkequal(s_ref_uc, s_uc, "removesuffix", "🖖#") + def test_additional_split(self): self.checkequal( ["this", "is", "the", "split", "function"], diff --git a/kclvm/tests/test_units/runtime/units/test_units.py b/kclvm/tests/test_units/runtime/units/test_units.py index 744904021..cd45fd57d 100644 --- a/kclvm/tests/test_units/runtime/units/test_units.py +++ b/kclvm/tests/test_units/runtime/units/test_units.py @@ -1,4 +1,4 @@ -# Copyright 2021 The KCL Authors. All rights reserved. +# Copyright The KCL Authors. All rights reserved. import typing import unittest diff --git a/kclvm/tests/test_units/runtime/yaml/test_yaml.py b/kclvm/tests/test_units/runtime/yaml/test_yaml.py index 00093e905..d067e3aa9 100644 --- a/kclvm/tests/test_units/runtime/yaml/test_yaml.py +++ b/kclvm/tests/test_units/runtime/yaml/test_yaml.py @@ -1,4 +1,4 @@ -# Copyright 2021 The KCL Authors. All rights reserved. +# Copyright The KCL Authors. All rights reserved. import typing import unittest diff --git a/kclvm/runtime/src/3rdparty/json_minimal/.gitignore b/kclvm/third-party/prost-wkt/.gitignore similarity index 100% rename from kclvm/runtime/src/3rdparty/json_minimal/.gitignore rename to kclvm/third-party/prost-wkt/.gitignore diff --git a/kclvm/third-party/prost-wkt/Cargo.toml b/kclvm/third-party/prost-wkt/Cargo.toml new file mode 100644 index 000000000..c25fbf9d0 --- /dev/null +++ b/kclvm/third-party/prost-wkt/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "prost-wkt" +version = "0.4.1" +authors = ["fdeantoni "] +license = "Apache-2.0" +repository = "https://github.com/fdeantoni/prost-wkt" +description = "Helper crate for prost to allow JSON serialization and deserialization of Well Known Types." +readme = "README.md" +documentation = "https://docs.rs/prost-wkt-derive" +edition = "2021" + +[dependencies] +prost = "0.11.6" +inventory = "0.3.0" +serde = "1.0" +serde_json = "1.0" +serde_derive = "1.0" +chrono = { version = "0.4", default-features = false, features = ["serde"] } +typetag = "0.2" diff --git a/kclvm/third-party/prost-wkt/LICENSE b/kclvm/third-party/prost-wkt/LICENSE new file mode 100644 index 000000000..16fe87b06 --- /dev/null +++ b/kclvm/third-party/prost-wkt/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/kclvm/third-party/prost-wkt/README.md b/kclvm/third-party/prost-wkt/README.md new file mode 100644 index 000000000..d39122a6b --- /dev/null +++ b/kclvm/third-party/prost-wkt/README.md @@ -0,0 +1,303 @@ +# *PROST Well Known Types JSON Serialization and Deserialization* # +[![crates.io](https://buildstats.info/crate/prost-wkt-types)](https://crates.io/crates/prost-wkt-types) [![build](https://github.com/fdeantoni/prost-wkt/actions/workflows/rust.yml/badge.svg)](https://github.com/fdeantoni/prost-wkt/actions/workflows/rust.yml) + +[Prost](https://github.com/tokio-rs/prost) is a [Protocol Buffers](https://developers.google.com/protocol-buffers/) +implementation for the [Rust Language](https://www.rust-lang.org/) that generates simple, idiomatic Rust code from +`proto2` and `proto3` files. + +It includes `prost-types` which gives basic support for protobuf Well-Known-Types (WKT), but support is basic. For +example, it does not include packing or unpacking of messages in the `Any` type, nor much support in the way of JSON +serialization and deserialization of that type. + +This crate can help you if you need: + - helper methods for packing and unpacking messages to/from an [Any](https://developers.google.com/protocol-buffers/docs/reference/google.protobuf#google.protobuf.Any), + - helper methods for converting [chrono](https://github.com/chronotope/chrono) types to [Timestamp](https://developers.google.com/protocol-buffers/docs/reference/google.protobuf#google.protobuf.Timestamp) and back again, + - helper methods for converting common rust types to [Value](https://developers.google.com/protocol-buffers/docs/reference/google.protobuf#google.protobuf.Value) and back again, + - serde support for the types above. + +To use it, include this crate along with prost: + +```toml +[dependencies] +prost = "0.11" +prost-wkt = "0.4" +prost-wkt-types = "0.4" +serde = { version = "1.0", features = ["derive"] } + +[build-dependencies] +prost-build = "0.11" +prost-wkt-build = "0.4" +``` + +In your `build.rs`, make sure to add the following options: +```rust +use std::{env, path::PathBuf}; +use prost_wkt_build::*; + +fn main() { + let out = PathBuf::from(env::var("OUT_DIR").unwrap()); + let descriptor_file = out.join("descriptors.bin"); + let mut prost_build = prost_build::Config::new(); + prost_build + .type_attribute( + ".", + "#[derive(serde::Serialize,serde::Deserialize)]" + ) + .extern_path( + ".google.protobuf.Any", + "::prost_wkt_types::Any" + ) + .extern_path( + ".google.protobuf.Timestamp", + "::prost_wkt_types::Timestamp" + ) + .extern_path( + ".google.protobuf.Value", + "::prost_wkt_types::Value" + ) + .file_descriptor_set_path(&descriptor_file) + .compile_protos( + &[ + "proto/messages.proto" + ], + &["proto/"], + ) + .unwrap(); + + let descriptor_bytes = + std::fs::read(descriptor_file) + .unwrap(); + + let descriptor = + FileDescriptorSet::decode(&descriptor_bytes[..]) + .unwrap(); + + prost_wkt_build::add_serde(out, descriptor); +} +``` + +The above configuration will include `Serialize`, and `Deserialize` on each generated struct. This will allow you to +use `serde` fully. Moreover, it ensures that the `Any` type is deserialized properly as JSON. For example, assume we +have the following messages defined in our proto file: + +```proto +syntax = "proto3"; + +import "google/protobuf/any.proto"; +import "google/protobuf/timestamp.proto"; + +package my.pkg; + +message Request { + string requestId = 1; + google.protobuf.Any payload = 2; +} + +message Foo { + string data = 1; + google.protobuf.Timestamp timestamp = 2; +} +``` + +After generating the rust structs for the above using `prost-build` with the above configuration, you will then be able +to do the following: + +```rust +use serde::{Deserialize, Serialize}; +use chrono::prelude::*; + +use prost_wkt_types::*; + +include!(concat!(env!("OUT_DIR"), "/my.pkg.rs")); + +fn main() -> Result<(), AnyError> { + let foo_msg: Foo = Foo { + data: "Hello World".to_string(), + timestamp: Some(Utc::now().into()), + }; + + let mut request: Request = Request::default(); + let any = Any::try_pack(foo_msg)?; + request.request_id = "test1".to_string(); + request.payload = Some(any); + + let json = serde_json::to_string_pretty(&request).expect("Failed to serialize request"); + + println!("JSON:\n{}", json); + + let back: Request = serde_json::from_str(&json).expect("Failed to deserialize request"); + + if let Some(payload) = back.payload { + let unpacked: Box< dyn MessageSerde> = payload.try_unpack()?; + + let unpacked_foo: &Foo = unpacked + .downcast_ref::() + .expect("Failed to downcast payload to Foo"); + + println!("Unpacked: {:?}", unpacked_foo); + } +} +``` + +The above will generate the following stdout: + +``` +JSON: +{ + "requestId": "test1", + "payload": { + "@type": "type.googleapis.com/my.pkg.Foo", + "data": "Hello World", + "timestamp": "2020-05-25T12:19:57.755998Z" + } +} +Unpacked: Foo { data: "Hello World", timestamp: Some(Timestamp { seconds: 1590409197, nanos: 755998000 }) } +``` + +Notice that the request message is properly serialized to JSON as per the [protobuf specification](https://developers.google.com/protocol-buffers/docs/reference/google.protobuf#google.protobuf.Any), +and that it can be deserialized as well. + +See the `example` sub-project for a fully functioning example. + +## Known Problems ## + +### oneOf types ### + +The way `prost-build` generates the `oneOf` type is to place it in a sub module, for example: + +```proto +message SomeOne { + oneof body { + string some_string = 1; + bool some_bool = 2; + float some_float = 3; + } +} +``` + +is converted to rust as follows: +```rust +#[derive(Serialize, Deserialize)] +#[derive(Clone, PartialEq, ::prost::Message)] +#[prost(package="my.pkg")] +pub struct SomeOne { + #[prost(oneof="some_one::Body", tags="1, 2, 3")] + pub body: ::core::option::Option, +} +/// Nested message and enum types in `SomeOne`. +pub mod some_one { + #[derive(Serialize, Deserialize)] + #[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum Body { + #[prost(string, tag="1")] + SomeString(::prost::alloc::string::String), + #[prost(bool, tag="2")] + SomeBool(bool), + #[prost(float, tag="3")] + SomeFloat(f32), + } +} +``` + +However, rust requires the importation of macros in each module, so each should have the following added: +```rust +use serde::{Serialize, Deserialize}; +``` + +In the generated code snippet, the above statement is missing in the `some_one` module, and the rust compiler will +complain about it. To fix it, we would have to add the appropriate use statement in the `some_one` module like so: +```rust +#[derive(Serialize, Deserialize)] +#[derive(Clone, PartialEq, ::prost::Message)] +#[prost(package="my.pkg")] +pub struct SomeOne { + #[prost(oneof="some_one::Body", tags="1, 2, 3")] + pub body: ::core::option::Option, +} +/// Nested message and enum types in `SomeOne`. +pub mod some_one { + use serde::{Serialize, Deserialize}; + #[derive(Serialize, Deserialize)] + #[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum Body { + #[prost(string, tag="1")] + SomeString(::prost::alloc::string::String), + #[prost(bool, tag="2")] + SomeBool(bool), + #[prost(float, tag="3")] + SomeFloat(f32), + } +} +``` + +Luckily, you can achieve the above by tweaking the `build.rs`. The configuration below, for example, will add the +required serde import to the `some_one` module as needed: +```rust +fn main() { + let out = PathBuf::from(env::var("OUT_DIR").unwrap()); + let descriptor_file = out.join("descriptors.bin"); + let mut prost_build = prost_build::Config::new(); + prost_build + .type_attribute( + ".my.pkg.MyEnum", + "#[derive(serde::Serialize,serde::Deserialize)]" + ) + .type_attribute( + ".my.pkg.MyMessage", + "#[derive(serde::Serialize,serde::Deserialize)] #[serde(default)]" + ) + .type_attribute( + ".my.pkg.SomeOne.body", + "#[derive(serde::Serialize,serde::Deserialize)]" + ) + .extern_path( + ".google.protobuf.Any", + "::prost_wkt_types::Any" + ) + .extern_path( + ".google.protobuf.Timestamp", + "::prost_wkt_types::Timestamp" + ) + .extern_path( + ".google.protobuf.Value", + "::prost_wkt_types::Value" + ) + .file_descriptor_set_path(&descriptor_file) + .compile_protos( + &[ + "proto/messages.proto" + ], + &["proto/"], + ) + .unwrap(); + + let descriptor_bytes = + std::fs::read(descriptor_file).unwrap(); + + let descriptor = + FileDescriptorSet::decode(&descriptor_bytes[..]).unwrap(); + + prost_wkt_build::add_serde(out, descriptor); +} +``` + +## Development ## + +Contributions are welcome! + +### Upgrading Prost ### + +When upgrading Prost to the latest version, make sure to also run `wkt-types/resources/update.sh` script. This will +grab the latest source files from `prost-types` and merge them into `prost-wkt-types` at build time. After the script +has run, be sure to validate that the selected line numbers in functions `process_prost_types_lib` and +`process_prost_types_datetime` in the `wkt-types/build.rs` are still correct! + +Please see `wkt-types/README.md` for more info. + +## License ## + +`prost-wkt` is distributed under the terms of the Apache License (Version 2.0). + +See [LICENSE](LICENSE) for details. + +Copyright 2023 Ferdinand de Antoni diff --git a/kclvm/third-party/prost-wkt/src/lib.rs b/kclvm/third-party/prost-wkt/src/lib.rs new file mode 100644 index 000000000..0186a6e1f --- /dev/null +++ b/kclvm/third-party/prost-wkt/src/lib.rs @@ -0,0 +1,95 @@ +pub use inventory; + +pub use typetag; + +/// Trait to support serialization and deserialization of `prost` messages. +#[typetag::serde(tag = "@type")] +pub trait MessageSerde: prost::Message + std::any::Any { + /// message name as in proto file + fn message_name(&self) -> &'static str; + /// package name as in proto file + fn package_name(&self) -> &'static str; + /// the message proto type url e.g. type.googleapis.com/my.package.MyMessage + fn type_url(&self) -> &'static str; + /// Creates a new instance of this message using the protobuf encoded data + fn new_instance(&self, data: Vec) -> Result, prost::DecodeError>; + /// Returns the encoded protobuf message as bytes + fn try_encoded(&self) -> Result, prost::EncodeError>; +} + +/// The implementation here is a direct copy of the `impl dyn` of [`std::any::Any`]! +impl dyn MessageSerde { + /// Returns `true` if the inner type is the same as `T`. + #[inline] + pub fn is(&self) -> bool { + // Get `TypeId` of the type this function is instantiated with. + let t = std::any::TypeId::of::(); + + // Get `TypeId` of the type in the trait object (`self`). + let concrete = self.type_id(); + + // Compare both `TypeId`s on equality. + t == concrete + } + + /// Returns some reference to the inner value if it is of type `T`, or + /// `None` if it isn't. + #[inline] + pub fn downcast_ref(&self) -> Option<&T> { + if self.is::() { + // SAFETY: just checked whether we are pointing to the correct type, and we can rely on + // that check for memory safety because we have implemented Any for all types; no other + // impls can exist as they would conflict with our impl. + unsafe { Some(self.downcast_ref_unchecked()) } + } else { + Option::None + } + } + + /// Returns some mutable reference to the boxed value if it is of type `T`, + /// or `None` if it isn't. + #[inline] + pub fn downcast_mut(&mut self) -> Option<&mut T> { + if self.is::() { + // SAFETY: just checked whether we are pointing to the correct type, and we can rely on + // that check for memory safety because we have implemented Any for all types; no other + // impls can exist as they would conflict with our impl. + unsafe { Some(self.downcast_mut_unchecked()) } + } else { + Option::None + } + } + + /// Returns a reference to the inner value as type `dyn T`. + /// + /// # Safety + /// + /// The contained value must be of type `T`. Calling this method + /// with the incorrect type is *undefined behavior*. + #[inline] + pub unsafe fn downcast_ref_unchecked(&self) -> &T { + debug_assert!(self.is::()); + // SAFETY: caller guarantees that T is the correct type + unsafe { &*(self as *const dyn MessageSerde as *const T) } + } + + /// Returns a mutable reference to the inner value as type `dyn T`. + /// + /// # Safety + /// + /// The contained value must be of type `T`. Calling this method + /// with the incorrect type is *undefined behavior*. + #[inline] + pub unsafe fn downcast_mut_unchecked(&mut self) -> &mut T { + &mut *(self as *mut Self as *mut T) + } +} + +type MessageSerdeDecoderFn = fn(&[u8]) -> Result, ::prost::DecodeError>; + +pub struct MessageSerdeDecoderEntry { + pub type_url: &'static str, + pub decoder: MessageSerdeDecoderFn, +} + +inventory::collect!(MessageSerdeDecoderEntry); diff --git a/kclvm/third-party/prost-wkt/wkt-build/Cargo.toml b/kclvm/third-party/prost-wkt/wkt-build/Cargo.toml new file mode 100644 index 000000000..690baf2de --- /dev/null +++ b/kclvm/third-party/prost-wkt/wkt-build/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "prost-wkt-build" +version = "0.4.1" +authors = ["fdeantoni "] +license = "Apache-2.0" +repository = "https://github.com/fdeantoni/prost-wkt" +description = "Helper crate for prost to allow JSON serialization and deserialization of Well Known Types." +readme = "../README.md" +documentation = "https://docs.rs/prost-wkt-build" +edition = "2021" + +[dependencies] +prost = "0.11.6" +prost-types = "0.11.5" +prost-build = "0.11.5" +quote = "1.0" +heck = "0.4" diff --git a/kclvm/third-party/prost-wkt/wkt-build/src/lib.rs b/kclvm/third-party/prost-wkt/wkt-build/src/lib.rs new file mode 100644 index 000000000..c576f0a7e --- /dev/null +++ b/kclvm/third-party/prost-wkt/wkt-build/src/lib.rs @@ -0,0 +1,98 @@ +use heck::{ToShoutySnakeCase, ToUpperCamelCase}; +use quote::{format_ident, quote}; +use std::fs::{File, OpenOptions}; +use std::io::Write; +use std::path::PathBuf; + +pub use prost::Message; +pub use prost_types::FileDescriptorSet; + +use prost_build::Module; + +pub fn add_serde(out: PathBuf, descriptor: FileDescriptorSet) { + for fd in &descriptor.file { + let package_name = match fd.package { + Some(ref pkg) => pkg, + None => continue, + }; + + let rust_path = out + .join(Module::from_protobuf_package_name(package_name).to_file_name_or(package_name)); + + // In some cases the generated file would be in empty. These files are no longer created by Prost, so + // we'll create here. Otherwise we append. + let mut rust_file = OpenOptions::new() + .create(true) + .append(true) + .open(rust_path) + .unwrap(); + + for msg in &fd.message_type { + let message_name = match msg.name { + Some(ref name) => name, + None => continue, + }; + + let type_url = format!("type.googleapis.com/{package_name}.{message_name}"); + + gen_trait_impl(&mut rust_file, package_name, message_name, &type_url); + } + } +} + +// This method uses the `heck` crate (the same that prost uses) to properly format the message name +// to UpperCamelCase as the prost_build::ident::{to_snake, to_upper_camel} methods +// in the `ident` module of prost_build is private. +fn gen_trait_impl(rust_file: &mut File, package_name: &str, message_name: &str, type_url: &str) { + let type_name = message_name.to_upper_camel_case(); + let type_name = format_ident!("{}", type_name); + + let dummy_const = format_ident!( + "IMPL_MESSAGE_SERDE_FOR_{}", + message_name.to_shouty_snake_case() + ); + + let tokens = quote! { + #[allow(dead_code)] + const #dummy_const: () = { + use ::prost_wkt::typetag; + #[typetag::serde(name=#type_url)] + impl ::prost_wkt::MessageSerde for #type_name { + fn package_name(&self) -> &'static str { + #package_name + } + fn message_name(&self) -> &'static str { + #message_name + } + fn type_url(&self) -> &'static str { + #type_url + } + fn new_instance(&self, data: Vec) -> Result, ::prost::DecodeError> { + let mut target = Self::default(); + ::prost::Message::merge(&mut target, data.as_slice())?; + let erased: Box = Box::new(target); + Ok(erased) + } + fn try_encoded(&self) -> Result, ::prost::EncodeError> { + let mut buf = Vec::new(); + buf.reserve(::prost::Message::encoded_len(self)); + ::prost::Message::encode(self, &mut buf)?; + Ok(buf) + } + } + + ::prost_wkt::inventory::submit!{ + ::prost_wkt::MessageSerdeDecoderEntry { + type_url: #type_url, + decoder: |buf: &[u8]| { + let msg: #type_name = ::prost::Message::decode(buf)?; + Ok(Box::new(msg)) + } + } + } + }; + }; + + writeln!(rust_file).unwrap(); + writeln!(rust_file, "{}", &tokens).unwrap(); +} diff --git a/kclvm/third-party/prost-wkt/wkt-types/Cargo.toml b/kclvm/third-party/prost-wkt/wkt-types/Cargo.toml new file mode 100644 index 000000000..cd3ffdfac --- /dev/null +++ b/kclvm/third-party/prost-wkt/wkt-types/Cargo.toml @@ -0,0 +1,35 @@ +[package] +name = "prost-wkt-types" +version = "0.4.1" +authors = ["fdeantoni "] +license = "Apache-2.0" +repository = "https://github.com/fdeantoni/prost-wkt" +description = "Helper crate for prost to allow JSON serialization and deserialization of Well Known Types." +readme = "../README.md" +documentation = "https://docs.rs/prost-wkt" +keywords = ["protobuf", "serde", "json"] +categories = ["encoding"] +edition = "2021" + +[lib] +doctest = false + +[features] +default = ["std"] +std = [] + +[dependencies] +prost-wkt = { version = "0.4.1", path = ".." } +prost = "0.11.6" +serde = "1.0" +serde_json = "1.0" +serde_derive = "1.0" +chrono = { version = "0.4", default-features = false, features = ["serde"] } + +[build-dependencies] +protoc-bin-vendored = { git = "https://github.com/kcl-lang/rust-protoc-bin-vendored", version = "3.2.0" } +prost = "0.11.6" +prost-types = "0.11.5" +prost-build = "0.11.5" +prost-wkt-build = { version = "0.4.1", path = "../wkt-build" } +regex = "1" diff --git a/kclvm/third-party/prost-wkt/wkt-types/build.rs b/kclvm/third-party/prost-wkt/wkt-types/build.rs new file mode 100644 index 000000000..620c759ae --- /dev/null +++ b/kclvm/third-party/prost-wkt/wkt-types/build.rs @@ -0,0 +1,97 @@ +//6 April 2023 - Modified by NeverRaR +use std::env; +use std::fs::create_dir_all; +use std::path::{Path, PathBuf}; + +use std::fs::File; +use std::io::Write; + +use prost::Message; +use prost_types::FileDescriptorSet; + +use regex::Regex; + +fn main() { + //hack: set protoc_bin_vendored::protoc_bin_path() to PROTOC + if env::var("PROTOC").is_err() { + env::set_var( + "PROTOC", + protoc_bin_vendored::protoc_bin_path().unwrap().as_os_str(), + ); + } + let dir = PathBuf::from(env::var("OUT_DIR").unwrap()); + process_prost_pbtime(&dir); + + build(&dir, "pbtime"); + build(&dir, "pbstruct"); + build(&dir, "pbany"); + build(&dir, "pbempty"); +} + +fn build(dir: &Path, proto: &str) { + let out = dir.join(proto); + create_dir_all(&out).unwrap(); + let source = format!("proto/{proto}.proto"); + let descriptor_file = out.join("descriptors.bin"); + let mut prost_build = prost_build::Config::new(); + prost_build + .compile_well_known_types() + .type_attribute( + "google.protobuf.Duration", + "#[derive(serde_derive::Serialize, serde_derive::Deserialize)] #[serde(default)]", + ) + .type_attribute( + "google.protobuf.Empty", + "#[derive(serde_derive::Serialize, serde_derive::Deserialize)]", + ) + .file_descriptor_set_path(&descriptor_file) + .out_dir(&out) + .compile_protos(&[source], &["proto/".to_string()]) + .unwrap(); + + let descriptor_bytes = std::fs::read(descriptor_file).unwrap(); + let descriptor = FileDescriptorSet::decode(&descriptor_bytes[..]).unwrap(); + + prost_wkt_build::add_serde(out, descriptor); +} + +fn process_prost_pbtime(dir: &Path) { + process_prost_types_lib(dir); + process_prost_types_datetime(dir); +} + +fn process_prost_types_lib(dir: &Path) { + let source: String = std::fs::read_to_string("./resources/lib.rs").unwrap(); + let lines: Vec<&str> = source.split('\n').collect(); + let selection = &lines[25..402]; + let mut string = String::new(); + for line in selection { + string.push_str(line); + string.push('\n'); + } + + let file = dir.join("prost_snippet.rs"); + File::create(file) + .unwrap() + .write_all(string.as_bytes()) + .unwrap(); +} + +fn process_prost_types_datetime(dir: &Path) { + let source: String = std::fs::read_to_string("./resources/datetime.rs").unwrap(); + let lines: Vec<&str> = source.split('\n').collect(); + let selection = &lines[0..585]; + let mut string = String::new(); + for line in selection { + string.push_str(line); + string.push('\n'); + } + + let re = Regex::new(r"crate").unwrap(); + let result = re.replace_all(&string, "super").to_string(); + let file = dir.join("datetime.rs"); + File::create(file) + .unwrap() + .write_all(result.as_bytes()) + .unwrap(); +} diff --git a/kclvm/third-party/prost-wkt/wkt-types/proto/pbany.proto b/kclvm/third-party/prost-wkt/wkt-types/proto/pbany.proto new file mode 100644 index 000000000..c096a1a85 --- /dev/null +++ b/kclvm/third-party/prost-wkt/wkt-types/proto/pbany.proto @@ -0,0 +1,5 @@ +syntax = "proto3"; + +import "google/protobuf/any.proto"; + +package pbany; \ No newline at end of file diff --git a/kclvm/third-party/prost-wkt/wkt-types/proto/pbempty.proto b/kclvm/third-party/prost-wkt/wkt-types/proto/pbempty.proto new file mode 100644 index 000000000..3f217ae7b --- /dev/null +++ b/kclvm/third-party/prost-wkt/wkt-types/proto/pbempty.proto @@ -0,0 +1,5 @@ +syntax = "proto3"; + +import "google/protobuf/empty.proto"; + +package empty; diff --git a/kclvm/third-party/prost-wkt/wkt-types/proto/pbstruct.proto b/kclvm/third-party/prost-wkt/wkt-types/proto/pbstruct.proto new file mode 100644 index 000000000..cf64d69a9 --- /dev/null +++ b/kclvm/third-party/prost-wkt/wkt-types/proto/pbstruct.proto @@ -0,0 +1,5 @@ +syntax = "proto3"; + +import "google/protobuf/struct.proto"; + +package pbstruct; \ No newline at end of file diff --git a/kclvm/third-party/prost-wkt/wkt-types/proto/pbtime.proto b/kclvm/third-party/prost-wkt/wkt-types/proto/pbtime.proto new file mode 100644 index 000000000..4e892062c --- /dev/null +++ b/kclvm/third-party/prost-wkt/wkt-types/proto/pbtime.proto @@ -0,0 +1,6 @@ +syntax = "proto3"; + +import "google/protobuf/duration.proto"; +import "google/protobuf/timestamp.proto"; + +package pbtime; diff --git a/kclvm/third-party/prost-wkt/wkt-types/resources/README.md b/kclvm/third-party/prost-wkt/wkt-types/resources/README.md new file mode 100644 index 000000000..ce60da696 --- /dev/null +++ b/kclvm/third-party/prost-wkt/wkt-types/resources/README.md @@ -0,0 +1,5 @@ +The files contained in this directory is from [prost-types](https://raw.githubusercontent.com/tokio-rs/prost/v0.10.0/prost-types/src/). It is used by `build.rs` to create the appropriate `prost_snippet.rs` in `./src/pbtime.rs`. + +When updating the Prost dependencies in this project you should run the `update.sh` script in this directory. This script +will update the above mentioned files. If the files are updated, do validate whether the line numbers selected in the +`../build.rs` are still correct. diff --git a/kclvm/third-party/prost-wkt/wkt-types/resources/datetime.rs b/kclvm/third-party/prost-wkt/wkt-types/resources/datetime.rs new file mode 100644 index 000000000..f6c3cca1c --- /dev/null +++ b/kclvm/third-party/prost-wkt/wkt-types/resources/datetime.rs @@ -0,0 +1,869 @@ +//! A date/time type which exists primarily to convert [`Timestamp`]s into an RFC 3339 formatted +//! string. + +use core::fmt; + +use crate::Duration; +use crate::Timestamp; + +/// A point in time, represented as a date and time in the UTC timezone. +#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +pub(crate) struct DateTime { + /// The year. + pub(crate) year: i64, + /// The month of the year, from 1 to 12, inclusive. + pub(crate) month: u8, + /// The day of the month, from 1 to 31, inclusive. + pub(crate) day: u8, + /// The hour of the day, from 0 to 23, inclusive. + pub(crate) hour: u8, + /// The minute of the hour, from 0 to 59, inclusive. + pub(crate) minute: u8, + /// The second of the minute, from 0 to 59, inclusive. + pub(crate) second: u8, + /// The nanoseconds, from 0 to 999_999_999, inclusive. + pub(crate) nanos: u32, +} + +impl DateTime { + /// The minimum representable [`Timestamp`] as a `DateTime`. + pub(crate) const MIN: DateTime = DateTime { + year: -292_277_022_657, + month: 1, + day: 27, + hour: 8, + minute: 29, + second: 52, + nanos: 0, + }; + + /// The maximum representable [`Timestamp`] as a `DateTime`. + pub(crate) const MAX: DateTime = DateTime { + year: 292_277_026_596, + month: 12, + day: 4, + hour: 15, + minute: 30, + second: 7, + nanos: 999_999_999, + }; + + /// Returns `true` if the `DateTime` is a valid calendar date. + pub(crate) fn is_valid(&self) -> bool { + self >= &DateTime::MIN + && self <= &DateTime::MAX + && self.month > 0 + && self.month <= 12 + && self.day > 0 + && self.day <= days_in_month(self.year, self.month) + && self.hour < 24 + && self.minute < 60 + && self.second < 60 + && self.nanos < 1_000_000_000 + } +} + +impl fmt::Display for DateTime { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + // Pad years to at least 4 digits. + if self.year > 9999 { + write!(f, "+{}", self.year)?; + } else if self.year < 0 { + write!(f, "{:05}", self.year)?; + } else { + write!(f, "{:04}", self.year)?; + }; + + write!( + f, + "-{:02}-{:02}T{:02}:{:02}:{:02}", + self.month, self.day, self.hour, self.minute, self.second, + )?; + + // Format subseconds to either nothing, millis, micros, or nanos. + let nanos = self.nanos; + if nanos == 0 { + write!(f, "Z") + } else if nanos % 1_000_000 == 0 { + write!(f, ".{:03}Z", nanos / 1_000_000) + } else if nanos % 1_000 == 0 { + write!(f, ".{:06}Z", nanos / 1_000) + } else { + write!(f, ".{:09}Z", nanos) + } + } +} + +impl From for DateTime { + /// musl's [`__secs_to_tm`][1] converted to Rust via [c2rust][2] and then cleaned up by hand. + /// + /// All existing `strftime`-like APIs in Rust are unable to handle the full range of timestamps + /// representable by `Timestamp`, including `strftime` itself, since tm.tm_year is an int. + /// + /// [1]: http://git.musl-libc.org/cgit/musl/tree/src/time/__secs_to_tm.c + /// [2]: https://c2rust.com/ + fn from(mut timestamp: Timestamp) -> DateTime { + timestamp.normalize(); + + let t = timestamp.seconds; + let nanos = timestamp.nanos; + + // 2000-03-01 (mod 400 year, immediately after feb29 + const LEAPOCH: i64 = 946_684_800 + 86400 * (31 + 29); + const DAYS_PER_400Y: i32 = 365 * 400 + 97; + const DAYS_PER_100Y: i32 = 365 * 100 + 24; + const DAYS_PER_4Y: i32 = 365 * 4 + 1; + const DAYS_IN_MONTH: [u8; 12] = [31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 31, 29]; + + // Note(dcb): this bit is rearranged slightly to avoid integer overflow. + let mut days: i64 = (t / 86_400) - (LEAPOCH / 86_400); + let mut remsecs: i32 = (t % 86_400) as i32; + if remsecs < 0i32 { + remsecs += 86_400; + days -= 1 + } + + let mut qc_cycles: i32 = (days / i64::from(DAYS_PER_400Y)) as i32; + let mut remdays: i32 = (days % i64::from(DAYS_PER_400Y)) as i32; + if remdays < 0 { + remdays += DAYS_PER_400Y; + qc_cycles -= 1; + } + + let mut c_cycles: i32 = remdays / DAYS_PER_100Y; + if c_cycles == 4 { + c_cycles -= 1; + } + remdays -= c_cycles * DAYS_PER_100Y; + + let mut q_cycles: i32 = remdays / DAYS_PER_4Y; + if q_cycles == 25 { + q_cycles -= 1; + } + remdays -= q_cycles * DAYS_PER_4Y; + + let mut remyears: i32 = remdays / 365; + if remyears == 4 { + remyears -= 1; + } + remdays -= remyears * 365; + + let mut years: i64 = i64::from(remyears) + + 4 * i64::from(q_cycles) + + 100 * i64::from(c_cycles) + + 400 * i64::from(qc_cycles); + + let mut months: i32 = 0; + while i32::from(DAYS_IN_MONTH[months as usize]) <= remdays { + remdays -= i32::from(DAYS_IN_MONTH[months as usize]); + months += 1 + } + + if months >= 10 { + months -= 12; + years += 1; + } + + let date_time = DateTime { + year: years + 2000, + month: (months + 3) as u8, + day: (remdays + 1) as u8, + hour: (remsecs / 3600) as u8, + minute: (remsecs / 60 % 60) as u8, + second: (remsecs % 60) as u8, + nanos: nanos as u32, + }; + debug_assert!(date_time.is_valid()); + date_time + } +} + +/// Returns the number of days in the month. +fn days_in_month(year: i64, month: u8) -> u8 { + const DAYS_IN_MONTH: [u8; 12] = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]; + let (_, is_leap) = year_to_seconds(year); + DAYS_IN_MONTH[usize::from(month - 1)] + u8::from(is_leap && month == 2) +} + +macro_rules! ensure { + ($expr:expr) => {{ + if !$expr { + return None; + } + }}; +} + +/// Parses a date in RFC 3339 format from ASCII string `b`, returning the year, month, day, and +/// remaining input. +/// +/// The date is not validated according to a calendar. +fn parse_date(s: &str) -> Option<(i64, u8, u8, &str)> { + debug_assert!(s.is_ascii()); + + // Smallest valid date is YYYY-MM-DD. + ensure!(s.len() >= 10); + + // Parse the year in one of three formats: + // * +YYYY[Y]+ + // * -[Y]+ + // * YYYY + let (year, s) = match s.as_bytes()[0] { + b'+' => { + let (digits, s) = parse_digits(&s[1..]); + ensure!(digits.len() >= 5); + let date: i64 = digits.parse().ok()?; + (date, s) + } + b'-' => { + let (digits, s) = parse_digits(&s[1..]); + ensure!(digits.len() >= 4); + let date: i64 = digits.parse().ok()?; + (-date, s) + } + _ => { + // Parse a 4 digit numeric. + let (n1, s) = parse_two_digit_numeric(s)?; + let (n2, s) = parse_two_digit_numeric(s)?; + (i64::from(n1) * 100 + i64::from(n2), s) + } + }; + + let s = parse_char(s, b'-')?; + let (month, s) = parse_two_digit_numeric(s)?; + let s = parse_char(s, b'-')?; + let (day, s) = parse_two_digit_numeric(s)?; + Some((year, month, day, s)) +} + +/// Parses a time in RFC 3339 format from ASCII string `s`, returning the hour, minute, second, and +/// nanos. +/// +/// The date is not validated according to a calendar. +fn parse_time(s: &str) -> Option<(u8, u8, u8, u32, &str)> { + debug_assert!(s.is_ascii()); + + let (hour, s) = parse_two_digit_numeric(s)?; + let s = parse_char(s, b':')?; + let (minute, s) = parse_two_digit_numeric(s)?; + let s = parse_char(s, b':')?; + let (second, s) = parse_two_digit_numeric(s)?; + + let (nanos, s) = parse_nanos(s)?; + + Some((hour, minute, second, nanos, s)) +} + +/// Parses an optional nanosecond time from ASCII string `s`, returning the nanos and remaining +/// string. +fn parse_nanos(s: &str) -> Option<(u32, &str)> { + debug_assert!(s.is_ascii()); + + // Parse the nanoseconds, if present. + let (nanos, s) = if let Some(s) = parse_char(s, b'.') { + let (digits, s) = parse_digits(s); + ensure!(digits.len() <= 9); + let nanos = 10u32.pow(9 - digits.len() as u32) * digits.parse::().ok()?; + (nanos, s) + } else { + (0, s) + }; + + Some((nanos, s)) +} + +/// Parses a timezone offset in RFC 3339 format from ASCII string `s`, returning the offset hour, +/// offset minute, and remaining input. +fn parse_offset(s: &str) -> Option<(i8, i8, &str)> { + debug_assert!(s.is_ascii()); + + if s.is_empty() { + // If no timezone specified, assume UTC. + return Some((0, 0, s)); + } + + // Snowflake's timestamp format contains a space separator before the offset. + let s = parse_char(s, b' ').unwrap_or(s); + + if let Some(s) = parse_char_ignore_case(s, b'Z') { + Some((0, 0, s)) + } else { + let (is_positive, s) = if let Some(s) = parse_char(s, b'+') { + (true, s) + } else if let Some(s) = parse_char(s, b'-') { + (false, s) + } else { + return None; + }; + + let (hour, s) = parse_two_digit_numeric(s)?; + + let (minute, s) = if s.is_empty() { + // No offset minutes are sepcified, e.g. +00 or +07. + (0, s) + } else { + // Optional colon separator between the hour and minute digits. + let s = parse_char(s, b':').unwrap_or(s); + let (minute, s) = parse_two_digit_numeric(s)?; + (minute, s) + }; + + // '-00:00' indicates an unknown local offset. + ensure!(is_positive || hour > 0 || minute > 0); + + ensure!(hour < 24 && minute < 60); + + let hour = hour as i8; + let minute = minute as i8; + + if is_positive { + Some((hour, minute, s)) + } else { + Some((-hour, -minute, s)) + } + } +} + +/// Parses a two-digit base-10 number from ASCII string `s`, returning the number and the remaining +/// string. +fn parse_two_digit_numeric(s: &str) -> Option<(u8, &str)> { + debug_assert!(s.is_ascii()); + + let (digits, s) = s.split_at(2); + Some((digits.parse().ok()?, s)) +} + +/// Splits ASCII string `s` at the first occurrence of a non-digit character. +fn parse_digits(s: &str) -> (&str, &str) { + debug_assert!(s.is_ascii()); + + let idx = s + .as_bytes() + .iter() + .position(|c| !c.is_ascii_digit()) + .unwrap_or(s.len()); + s.split_at(idx) +} + +/// Attempts to parse ASCII character `c` from ASCII string `s`, returning the remaining string. If +/// the character can not be parsed, returns `None`. +fn parse_char(s: &str, c: u8) -> Option<&str> { + debug_assert!(s.is_ascii()); + + ensure!(*s.as_bytes().first()? == c); + Some(&s[1..]) +} + +/// Attempts to parse ASCII character `c` from ASCII string `s`, ignoring ASCII case, returning the +/// remaining string. If the character can not be parsed, returns `None`. +fn parse_char_ignore_case(s: &str, c: u8) -> Option<&str> { + debug_assert!(s.is_ascii()); + + ensure!(s.as_bytes().first()?.eq_ignore_ascii_case(&c)); + Some(&s[1..]) +} + +/// Returns the offset in seconds from the Unix epoch of the date time. +/// +/// This is musl's [`__tm_to_secs`][1] converted to Rust via [c2rust[2] and then cleaned up by +/// hand. +/// +/// [1]: https://git.musl-libc.org/cgit/musl/tree/src/time/__tm_to_secs.c +/// [2]: https://c2rust.com/ +fn date_time_to_seconds(tm: &DateTime) -> i64 { + let (start_of_year, is_leap) = year_to_seconds(tm.year); + + let seconds_within_year = month_to_seconds(tm.month, is_leap) + + 86400 * u32::from(tm.day - 1) + + 3600 * u32::from(tm.hour) + + 60 * u32::from(tm.minute) + + u32::from(tm.second); + + (start_of_year + i128::from(seconds_within_year)) as i64 +} + +/// Returns the number of seconds in the year prior to the start of the provided month. +/// +/// This is musl's [`__month_to_secs`][1] converted to Rust via c2rust and then cleaned up by hand. +/// +/// [1]: https://git.musl-libc.org/cgit/musl/tree/src/time/__month_to_secs.c +fn month_to_seconds(month: u8, is_leap: bool) -> u32 { + const SECS_THROUGH_MONTH: [u32; 12] = [ + 0, + 31 * 86400, + 59 * 86400, + 90 * 86400, + 120 * 86400, + 151 * 86400, + 181 * 86400, + 212 * 86400, + 243 * 86400, + 273 * 86400, + 304 * 86400, + 334 * 86400, + ]; + let t = SECS_THROUGH_MONTH[usize::from(month - 1)]; + if is_leap && month > 2 { + t + 86400 + } else { + t + } +} + +/// Returns the offset in seconds from the Unix epoch of the start of a year. +/// +/// musl's [`__year_to_secs`][1] converted to Rust via c2rust and then cleaned up by hand. +/// +/// Returns an i128 because the start of the earliest supported year underflows i64. +/// +/// [1]: https://git.musl-libc.org/cgit/musl/tree/src/time/__year_to_secs.c +pub(crate) fn year_to_seconds(year: i64) -> (i128, bool) { + let is_leap; + let year = year - 1900; + + // Fast path for years 1900 - 2038. + if year as u64 <= 138 { + let mut leaps: i64 = (year - 68) >> 2; + if (year - 68).trailing_zeros() >= 2 { + leaps -= 1; + is_leap = true; + } else { + is_leap = false; + } + return ( + i128::from(31_536_000 * (year - 70) + 86400 * leaps), + is_leap, + ); + } + + let centuries: i64; + let mut leaps: i64; + + let mut cycles: i64 = (year - 100) / 400; + let mut rem: i64 = (year - 100) % 400; + + if rem < 0 { + cycles -= 1; + rem += 400 + } + if rem == 0 { + is_leap = true; + centuries = 0; + leaps = 0; + } else { + if rem >= 200 { + if rem >= 300 { + centuries = 3; + rem -= 300; + } else { + centuries = 2; + rem -= 200; + } + } else if rem >= 100 { + centuries = 1; + rem -= 100; + } else { + centuries = 0; + } + if rem == 0 { + is_leap = false; + leaps = 0; + } else { + leaps = rem / 4; + rem %= 4; + is_leap = rem == 0; + } + } + leaps += 97 * cycles + 24 * centuries - i64::from(is_leap); + + ( + i128::from((year - 100) * 31_536_000) + i128::from(leaps * 86400 + 946_684_800 + 86400), + is_leap, + ) +} + +/// Parses a timestamp in RFC 3339 format from `s`. +pub(crate) fn parse_timestamp(s: &str) -> Option { + // Check that the string is ASCII, since subsequent parsing steps use byte-level indexing. + ensure!(s.is_ascii()); + + let (year, month, day, s) = parse_date(s)?; + + if s.is_empty() { + // The string only contained a date. + let date_time = DateTime { + year, + month, + day, + ..DateTime::default() + }; + + ensure!(date_time.is_valid()); + + return Some(Timestamp::from(date_time)); + } + + // Accept either 'T' or ' ' as delimiter between date and time. + let s = parse_char_ignore_case(s, b'T').or_else(|| parse_char(s, b' '))?; + let (hour, minute, mut second, nanos, s) = parse_time(s)?; + let (offset_hour, offset_minute, s) = parse_offset(s)?; + + ensure!(s.is_empty()); + + // Detect whether the timestamp falls in a leap second. If this is the case, roll it back + // to the previous second. To be maximally conservative, this should be checking that the + // timestamp is the last second in the UTC day (23:59:60), and even potentially checking + // that it's the final day of the UTC month, however these checks are non-trivial because + // at this point we have, in effect, a local date time, since the offset has not been + // applied. + if second == 60 { + second = 59; + } + + let date_time = DateTime { + year, + month, + day, + hour, + minute, + second, + nanos, + }; + + ensure!(date_time.is_valid()); + + let Timestamp { seconds, nanos } = Timestamp::from(date_time); + + let seconds = + seconds.checked_sub(i64::from(offset_hour) * 3600 + i64::from(offset_minute) * 60)?; + + Some(Timestamp { seconds, nanos }) +} + +/// Parse a duration in the [Protobuf JSON encoding spec format][1]. +/// +/// [1]: https://developers.google.com/protocol-buffers/docs/proto3#json +pub(crate) fn parse_duration(s: &str) -> Option { + // Check that the string is ASCII, since subsequent parsing steps use byte-level indexing. + ensure!(s.is_ascii()); + + let (is_negative, s) = match parse_char(s, b'-') { + Some(s) => (true, s), + None => (false, s), + }; + + let (digits, s) = parse_digits(s); + let seconds = digits.parse::().ok()?; + + let (nanos, s) = parse_nanos(s)?; + + let s = parse_char(s, b's')?; + ensure!(s.is_empty()); + ensure!(nanos < crate::NANOS_PER_SECOND as u32); + + // If the duration is negative, also flip the nanos sign. + let (seconds, nanos) = if is_negative { + (-seconds, -(nanos as i32)) + } else { + (seconds, nanos as i32) + }; + + Some(Duration { + seconds, + nanos: nanos as i32, + }) +} + +impl From for Timestamp { + fn from(date_time: DateTime) -> Timestamp { + let seconds = date_time_to_seconds(&date_time); + let nanos = date_time.nanos; + Timestamp { + seconds, + nanos: nanos as i32, + } + } +} + +#[cfg(test)] +mod tests { + + use std::convert::TryFrom; + + use proptest::prelude::*; + + use super::*; + + #[test] + fn test_min_max() { + assert_eq!( + DateTime::MIN, + DateTime::from(Timestamp { + seconds: i64::MIN, + nanos: 0 + }), + ); + assert_eq!( + DateTime::MAX, + DateTime::from(Timestamp { + seconds: i64::MAX, + nanos: 999_999_999 + }), + ); + } + + #[test] + fn test_datetime_from_timestamp() { + let case = |expected: &str, secs: i64, nanos: i32| { + let timestamp = Timestamp { + seconds: secs, + nanos, + }; + assert_eq!( + expected, + format!("{}", DateTime::from(timestamp.clone())), + "timestamp: {:?}", + timestamp + ); + }; + + // Mostly generated with: + // - date -jur +"%Y-%m-%dT%H:%M:%S.000000000Z" + // - http://unixtimestamp.50x.eu/ + + case("1970-01-01T00:00:00Z", 0, 0); + + case("1970-01-01T00:00:00.000000001Z", 0, 1); + case("1970-01-01T00:00:00.123450Z", 0, 123_450_000); + case("1970-01-01T00:00:00.050Z", 0, 50_000_000); + case("1970-01-01T00:00:01.000000001Z", 1, 1); + case("1970-01-01T00:01:01.000000001Z", 60 + 1, 1); + case("1970-01-01T01:01:01.000000001Z", 60 * 60 + 60 + 1, 1); + case( + "1970-01-02T01:01:01.000000001Z", + 24 * 60 * 60 + 60 * 60 + 60 + 1, + 1, + ); + + case("1969-12-31T23:59:59Z", -1, 0); + case("1969-12-31T23:59:59.000001Z", -1, 1_000); + case("1969-12-31T23:59:59.500Z", -1, 500_000_000); + case("1969-12-31T23:58:59.000001Z", -60 - 1, 1_000); + case("1969-12-31T22:58:59.000001Z", -60 * 60 - 60 - 1, 1_000); + case( + "1969-12-30T22:58:59.000000001Z", + -24 * 60 * 60 - 60 * 60 - 60 - 1, + 1, + ); + + case("2038-01-19T03:14:07Z", i32::MAX as i64, 0); + case("2038-01-19T03:14:08Z", i32::MAX as i64 + 1, 0); + case("1901-12-13T20:45:52Z", i32::MIN as i64, 0); + case("1901-12-13T20:45:51Z", i32::MIN as i64 - 1, 0); + + // Skipping these tests on windows as std::time::SysteTime range is low + // on Windows compared with that of Unix which can cause the following + // high date value tests to panic + #[cfg(not(target_os = "windows"))] + { + case("+292277026596-12-04T15:30:07Z", i64::MAX, 0); + case("+292277026596-12-04T15:30:06Z", i64::MAX - 1, 0); + case("-292277022657-01-27T08:29:53Z", i64::MIN + 1, 0); + } + + case("1900-01-01T00:00:00Z", -2_208_988_800, 0); + case("1899-12-31T23:59:59Z", -2_208_988_801, 0); + case("0000-01-01T00:00:00Z", -62_167_219_200, 0); + case("-0001-12-31T23:59:59Z", -62_167_219_201, 0); + + case("1234-05-06T07:08:09Z", -23_215_049_511, 0); + case("-1234-05-06T07:08:09Z", -101_097_651_111, 0); + case("2345-06-07T08:09:01Z", 11_847_456_541, 0); + case("-2345-06-07T08:09:01Z", -136_154_620_259, 0); + } + + #[test] + fn test_parse_timestamp() { + // RFC 3339 Section 5.8 Examples + assert_eq!( + "1985-04-12T23:20:50.52Z".parse::(), + Timestamp::date_time_nanos(1985, 4, 12, 23, 20, 50, 520_000_000), + ); + assert_eq!( + "1996-12-19T16:39:57-08:00".parse::(), + Timestamp::date_time(1996, 12, 20, 0, 39, 57), + ); + assert_eq!( + "1996-12-19T16:39:57-08:00".parse::(), + Timestamp::date_time(1996, 12, 20, 0, 39, 57), + ); + assert_eq!( + "1990-12-31T23:59:60Z".parse::(), + Timestamp::date_time(1990, 12, 31, 23, 59, 59), + ); + assert_eq!( + "1990-12-31T15:59:60-08:00".parse::(), + Timestamp::date_time(1990, 12, 31, 23, 59, 59), + ); + assert_eq!( + "1937-01-01T12:00:27.87+00:20".parse::(), + Timestamp::date_time_nanos(1937, 1, 1, 11, 40, 27, 870_000_000), + ); + + // Date + assert_eq!( + "1937-01-01".parse::(), + Timestamp::date(1937, 1, 1), + ); + + // Negative year + assert_eq!( + "-0008-01-01".parse::(), + Timestamp::date(-8, 1, 1), + ); + + // Plus year + assert_eq!( + "+19370-01-01".parse::(), + Timestamp::date(19370, 1, 1), + ); + + // Full nanos + assert_eq!( + "2020-02-03T01:02:03.123456789Z".parse::(), + Timestamp::date_time_nanos(2020, 2, 3, 1, 2, 3, 123_456_789), + ); + + // Leap day + assert_eq!( + "2020-02-29T01:02:03.00Z".parse::().unwrap(), + Timestamp::from(DateTime { + year: 2020, + month: 2, + day: 29, + hour: 1, + minute: 2, + second: 3, + nanos: 0, + }), + ); + + // Test extensions to RFC 3339. + // ' ' instead of 'T' as date/time separator. + assert_eq!( + "1985-04-12 23:20:50.52Z".parse::(), + Timestamp::date_time_nanos(1985, 4, 12, 23, 20, 50, 520_000_000), + ); + + // No time zone specified. + assert_eq!( + "1985-04-12T23:20:50.52".parse::(), + Timestamp::date_time_nanos(1985, 4, 12, 23, 20, 50, 520_000_000), + ); + + // Offset without minutes specified. + assert_eq!( + "1996-12-19T16:39:57-08".parse::(), + Timestamp::date_time(1996, 12, 20, 0, 39, 57), + ); + + // Snowflake stage style. + assert_eq!( + "2015-09-12 00:47:19.591 Z".parse::(), + Timestamp::date_time_nanos(2015, 9, 12, 0, 47, 19, 591_000_000), + ); + assert_eq!( + "2020-06-15 00:01:02.123 +0800".parse::(), + Timestamp::date_time_nanos(2020, 6, 14, 16, 1, 2, 123_000_000), + ); + } + + #[test] + fn test_parse_duration() { + let case = |s: &str, seconds: i64, nanos: i32| { + assert_eq!( + s.parse::().unwrap(), + Duration { seconds, nanos }, + "duration: {}", + s + ); + }; + + case("0s", 0, 0); + case("0.0s", 0, 0); + case("0.000s", 0, 0); + + case("-0s", 0, 0); + case("-0.0s", 0, 0); + case("-0.000s", 0, 0); + + case("-0s", 0, 0); + case("-0.0s", 0, 0); + case("-0.000s", 0, 0); + + case("0.05s", 0, 50_000_000); + case("0.050s", 0, 50_000_000); + + case("-0.05s", 0, -50_000_000); + case("-0.050s", 0, -50_000_000); + + case("1s", 1, 0); + case("1.0s", 1, 0); + case("1.000s", 1, 0); + + case("-1s", -1, 0); + case("-1.0s", -1, 0); + case("-1.000s", -1, 0); + + case("15s", 15, 0); + case("15.1s", 15, 100_000_000); + case("15.100s", 15, 100_000_000); + + case("-15s", -15, 0); + case("-15.1s", -15, -100_000_000); + case("-15.100s", -15, -100_000_000); + + case("100.000000009s", 100, 9); + case("-100.000000009s", -100, -9); + } + + #[test] + fn test_parse_non_ascii() { + assert!("2021️⃣-06-15 00:01:02.123 +0800" + .parse::() + .is_err()); + + assert!("1️⃣s".parse::().is_err()); + } + + proptest! { + #[cfg(feature = "std")] + #[test] + fn check_timestamp_parse_to_string_roundtrip( + system_time in std::time::SystemTime::arbitrary(), + ) { + + let ts = Timestamp::from(system_time); + + assert_eq!( + ts, + ts.to_string().parse::().unwrap(), + ) + } + + #[test] + fn check_duration_parse_to_string_roundtrip( + duration in core::time::Duration::arbitrary(), + ) { + let duration = match Duration::try_from(duration) { + Ok(duration) => duration, + Err(_) => return Err(TestCaseError::reject("duration out of range")), + }; + + prop_assert_eq!( + &duration, + &duration.to_string().parse::().unwrap(), + "{}", duration.to_string() + ); + } + } +} diff --git a/kclvm/third-party/prost-wkt/wkt-types/resources/lib.rs b/kclvm/third-party/prost-wkt/wkt-types/resources/lib.rs new file mode 100644 index 000000000..b51e7fdfb --- /dev/null +++ b/kclvm/third-party/prost-wkt/wkt-types/resources/lib.rs @@ -0,0 +1,679 @@ +#![doc(html_root_url = "https://docs.rs/prost-types/0.11.5")] + +//! Protocol Buffers well-known types. +//! +//! Note that the documentation for the types defined in this crate are generated from the Protobuf +//! definitions, so code examples are not in Rust. +//! +//! See the [Protobuf reference][1] for more information about well-known types. +//! +//! [1]: https://developers.google.com/protocol-buffers/docs/reference/google.protobuf + +#![cfg_attr(not(feature = "std"), no_std)] + +use core::convert::TryFrom; +use core::fmt; +use core::i32; +use core::i64; +use core::str::FromStr; +use core::time; + +include!("protobuf.rs"); +pub mod compiler { + include!("compiler.rs"); +} + +mod datetime; + +// The Protobuf `Duration` and `Timestamp` types can't delegate to the standard library equivalents +// because the Protobuf versions are signed. To make them easier to work with, `From` conversions +// are defined in both directions. + +const NANOS_PER_SECOND: i32 = 1_000_000_000; +const NANOS_MAX: i32 = NANOS_PER_SECOND - 1; + +impl Duration { + /// Normalizes the duration to a canonical format. + /// + /// Based on [`google::protobuf::util::CreateNormalized`][1]. + /// + /// [1]: https://github.com/google/protobuf/blob/v3.3.2/src/google/protobuf/util/time_util.cc#L79-L100 + pub fn normalize(&mut self) { + // Make sure nanos is in the range. + if self.nanos <= -NANOS_PER_SECOND || self.nanos >= NANOS_PER_SECOND { + if let Some(seconds) = self + .seconds + .checked_add((self.nanos / NANOS_PER_SECOND) as i64) + { + self.seconds = seconds; + self.nanos %= NANOS_PER_SECOND; + } else if self.nanos < 0 { + // Negative overflow! Set to the least normal value. + self.seconds = i64::MIN; + self.nanos = -NANOS_MAX; + } else { + // Positive overflow! Set to the greatest normal value. + self.seconds = i64::MAX; + self.nanos = NANOS_MAX; + } + } + + // nanos should have the same sign as seconds. + if self.seconds < 0 && self.nanos > 0 { + if let Some(seconds) = self.seconds.checked_add(1) { + self.seconds = seconds; + self.nanos -= NANOS_PER_SECOND; + } else { + // Positive overflow! Set to the greatest normal value. + debug_assert_eq!(self.seconds, i64::MAX); + self.nanos = NANOS_MAX; + } + } else if self.seconds > 0 && self.nanos < 0 { + if let Some(seconds) = self.seconds.checked_sub(1) { + self.seconds = seconds; + self.nanos += NANOS_PER_SECOND; + } else { + // Negative overflow! Set to the least normal value. + debug_assert_eq!(self.seconds, i64::MIN); + self.nanos = -NANOS_MAX; + } + } + // TODO: should this be checked? + // debug_assert!(self.seconds >= -315_576_000_000 && self.seconds <= 315_576_000_000, + // "invalid duration: {:?}", self); + } +} + +impl TryFrom for Duration { + type Error = DurationError; + + /// Converts a `std::time::Duration` to a `Duration`, failing if the duration is too large. + fn try_from(duration: time::Duration) -> Result { + let seconds = i64::try_from(duration.as_secs()).map_err(|_| DurationError::OutOfRange)?; + let nanos = duration.subsec_nanos() as i32; + + let mut duration = Duration { seconds, nanos }; + duration.normalize(); + Ok(duration) + } +} + +impl TryFrom for time::Duration { + type Error = DurationError; + + /// Converts a `Duration` to a `std::time::Duration`, failing if the duration is negative. + fn try_from(mut duration: Duration) -> Result { + duration.normalize(); + if duration.seconds >= 0 { + Ok(time::Duration::new( + duration.seconds as u64, + duration.nanos as u32, + )) + } else { + Err(DurationError::NegativeDuration(time::Duration::new( + (-duration.seconds) as u64, + (-duration.nanos) as u32, + ))) + } + } +} + +impl fmt::Display for Duration { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let mut d = self.clone(); + d.normalize(); + if self.seconds < 0 && self.nanos < 0 { + write!(f, "-")?; + } + write!(f, "{}", d.seconds.abs())?; + + // Format subseconds to either nothing, millis, micros, or nanos. + let nanos = d.nanos.abs(); + if nanos == 0 { + write!(f, "s") + } else if nanos % 1_000_000 == 0 { + write!(f, ".{:03}s", nanos / 1_000_000) + } else if nanos % 1_000 == 0 { + write!(f, ".{:06}s", nanos / 1_000) + } else { + write!(f, ".{:09}s", nanos) + } + } +} + +/// A duration handling error. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Debug, PartialEq)] +#[non_exhaustive] +pub enum DurationError { + /// Indicates failure to parse a [`Duration`] from a string. + /// + /// The [`Duration`] string format is specified in the [Protobuf JSON mapping specification][1]. + /// + /// [1]: https://developers.google.com/protocol-buffers/docs/proto3#json + ParseFailure, + + /// Indicates failure to convert a `prost_types::Duration` to a `std::time::Duration` because + /// the duration is negative. The included `std::time::Duration` matches the magnitude of the + /// original negative `prost_types::Duration`. + NegativeDuration(time::Duration), + + /// Indicates failure to convert a `std::time::Duration` to a `prost_types::Duration`. + /// + /// Converting a `std::time::Duration` to a `prost_types::Duration` fails if the magnitude + /// exceeds that representable by `prost_types::Duration`. + OutOfRange, +} + +impl fmt::Display for DurationError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + DurationError::ParseFailure => write!(f, "failed to parse duration"), + DurationError::NegativeDuration(duration) => { + write!(f, "failed to convert negative duration: {:?}", duration) + } + DurationError::OutOfRange => { + write!(f, "failed to convert duration out of range") + } + } + } +} + +#[cfg(feature = "std")] +impl std::error::Error for DurationError {} + +impl FromStr for Duration { + type Err = DurationError; + + fn from_str(s: &str) -> Result { + datetime::parse_duration(s).ok_or(DurationError::ParseFailure) + } +} + +impl Timestamp { + /// Normalizes the timestamp to a canonical format. + /// + /// Based on [`google::protobuf::util::CreateNormalized`][1]. + /// + /// [1]: https://github.com/google/protobuf/blob/v3.3.2/src/google/protobuf/util/time_util.cc#L59-L77 + pub fn normalize(&mut self) { + // Make sure nanos is in the range. + if self.nanos <= -NANOS_PER_SECOND || self.nanos >= NANOS_PER_SECOND { + if let Some(seconds) = self + .seconds + .checked_add((self.nanos / NANOS_PER_SECOND) as i64) + { + self.seconds = seconds; + self.nanos %= NANOS_PER_SECOND; + } else if self.nanos < 0 { + // Negative overflow! Set to the earliest normal value. + self.seconds = i64::MIN; + self.nanos = 0; + } else { + // Positive overflow! Set to the latest normal value. + self.seconds = i64::MAX; + self.nanos = 999_999_999; + } + } + + // For Timestamp nanos should be in the range [0, 999999999]. + if self.nanos < 0 { + if let Some(seconds) = self.seconds.checked_sub(1) { + self.seconds = seconds; + self.nanos += NANOS_PER_SECOND; + } else { + // Negative overflow! Set to the earliest normal value. + debug_assert_eq!(self.seconds, i64::MIN); + self.nanos = 0; + } + } + + // TODO: should this be checked? + // debug_assert!(self.seconds >= -62_135_596_800 && self.seconds <= 253_402_300_799, + // "invalid timestamp: {:?}", self); + } + + /// Creates a new `Timestamp` at the start of the provided UTC date. + pub fn date(year: i64, month: u8, day: u8) -> Result { + Timestamp::date_time_nanos(year, month, day, 0, 0, 0, 0) + } + + /// Creates a new `Timestamp` instance with the provided UTC date and time. + pub fn date_time( + year: i64, + month: u8, + day: u8, + hour: u8, + minute: u8, + second: u8, + ) -> Result { + Timestamp::date_time_nanos(year, month, day, hour, minute, second, 0) + } + + /// Creates a new `Timestamp` instance with the provided UTC date and time. + pub fn date_time_nanos( + year: i64, + month: u8, + day: u8, + hour: u8, + minute: u8, + second: u8, + nanos: u32, + ) -> Result { + let date_time = datetime::DateTime { + year, + month, + day, + hour, + minute, + second, + nanos, + }; + + if date_time.is_valid() { + Ok(Timestamp::from(date_time)) + } else { + Err(TimestampError::InvalidDateTime) + } + } +} + +/// Implements the unstable/naive version of `Eq`: a basic equality check on the internal fields of the `Timestamp`. +/// This implies that `normalized_ts != non_normalized_ts` even if `normalized_ts == non_normalized_ts.normalized()`. +#[cfg(feature = "std")] +impl Eq for Timestamp {} + +#[cfg(feature = "std")] +#[allow(clippy::derive_hash_xor_eq)] // Derived logic is correct: comparing the 2 fields for equality +impl std::hash::Hash for Timestamp { + fn hash(&self, state: &mut H) { + self.seconds.hash(state); + self.nanos.hash(state); + } +} + +#[cfg(feature = "std")] +impl From for Timestamp { + fn from(system_time: std::time::SystemTime) -> Timestamp { + let (seconds, nanos) = match system_time.duration_since(std::time::UNIX_EPOCH) { + Ok(duration) => { + let seconds = i64::try_from(duration.as_secs()).unwrap(); + (seconds, duration.subsec_nanos() as i32) + } + Err(error) => { + let duration = error.duration(); + let seconds = i64::try_from(duration.as_secs()).unwrap(); + let nanos = duration.subsec_nanos() as i32; + if nanos == 0 { + (-seconds, 0) + } else { + (-seconds - 1, 1_000_000_000 - nanos) + } + } + }; + Timestamp { seconds, nanos } + } +} + +/// A timestamp handling error. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Debug, PartialEq)] +#[non_exhaustive] +pub enum TimestampError { + /// Indicates that a [`Timestamp`] could not be converted to + /// [`SystemTime`][std::time::SystemTime] because it is out of range. + /// + /// The range of times that can be represented by `SystemTime` depends on the platform. All + /// `Timestamp`s are likely representable on 64-bit Unix-like platforms, but other platforms, + /// such as Windows and 32-bit Linux, may not be able to represent the full range of + /// `Timestamp`s. + OutOfSystemRange(Timestamp), + + /// An error indicating failure to parse a timestamp in RFC-3339 format. + ParseFailure, + + /// Indicates an error when constructing a timestamp due to invalid date or time data. + InvalidDateTime, +} + +impl fmt::Display for TimestampError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + TimestampError::OutOfSystemRange(timestamp) => { + write!( + f, + "{} is not representable as a `SystemTime` because it is out of range", + timestamp + ) + } + TimestampError::ParseFailure => { + write!(f, "failed to parse RFC-3339 formatted timestamp") + } + TimestampError::InvalidDateTime => { + write!(f, "invalid date or time") + } + } + } +} + +#[cfg(feature = "std")] +impl std::error::Error for TimestampError {} + +#[cfg(feature = "std")] +impl TryFrom for std::time::SystemTime { + type Error = TimestampError; + + fn try_from(mut timestamp: Timestamp) -> Result { + let orig_timestamp = timestamp.clone(); + timestamp.normalize(); + + let system_time = if timestamp.seconds >= 0 { + std::time::UNIX_EPOCH.checked_add(time::Duration::from_secs(timestamp.seconds as u64)) + } else { + std::time::UNIX_EPOCH.checked_sub(time::Duration::from_secs( + timestamp + .seconds + .checked_neg() + .ok_or_else(|| TimestampError::OutOfSystemRange(timestamp.clone()))? + as u64, + )) + }; + + let system_time = system_time.and_then(|system_time| { + system_time.checked_add(time::Duration::from_nanos(timestamp.nanos as u64)) + }); + + system_time.ok_or(TimestampError::OutOfSystemRange(orig_timestamp)) + } +} + +impl FromStr for Timestamp { + type Err = TimestampError; + + fn from_str(s: &str) -> Result { + datetime::parse_timestamp(s).ok_or(TimestampError::ParseFailure) + } +} + +impl fmt::Display for Timestamp { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + datetime::DateTime::from(self.clone()).fmt(f) + } +} + +#[cfg(test)] +mod tests { + use std::time::{self, SystemTime, UNIX_EPOCH}; + + use proptest::prelude::*; + + use super::*; + + #[cfg(feature = "std")] + proptest! { + #[test] + fn check_system_time_roundtrip( + system_time in SystemTime::arbitrary(), + ) { + prop_assert_eq!(SystemTime::try_from(Timestamp::from(system_time)).unwrap(), system_time); + } + + #[test] + fn check_timestamp_roundtrip_via_system_time( + seconds in i64::arbitrary(), + nanos in i32::arbitrary(), + ) { + let mut timestamp = Timestamp { seconds, nanos }; + timestamp.normalize(); + if let Ok(system_time) = SystemTime::try_from(timestamp.clone()) { + prop_assert_eq!(Timestamp::from(system_time), timestamp); + } + } + + #[test] + fn check_duration_roundtrip( + std_duration in time::Duration::arbitrary(), + ) { + let prost_duration = match Duration::try_from(std_duration) { + Ok(duration) => duration, + Err(_) => return Err(TestCaseError::reject("duration out of range")), + }; + prop_assert_eq!(time::Duration::try_from(prost_duration.clone()).unwrap(), std_duration); + + if std_duration != time::Duration::default() { + let neg_prost_duration = Duration { + seconds: -prost_duration.seconds, + nanos: -prost_duration.nanos, + }; + + prop_assert!( + matches!( + time::Duration::try_from(neg_prost_duration), + Err(DurationError::NegativeDuration(d)) if d == std_duration, + ) + ) + } + } + } + + #[cfg(feature = "std")] + #[test] + fn check_timestamp_negative_seconds() { + // Representative tests for the case of timestamps before the UTC Epoch time: + // validate the expected behaviour that "negative second values with fractions + // must still have non-negative nanos values that count forward in time" + // https://developers.google.com/protocol-buffers/docs/reference/google.protobuf#google.protobuf.Timestamp + // + // To ensure cross-platform compatibility, all nanosecond values in these + // tests are in minimum 100 ns increments. This does not affect the general + // character of the behaviour being tested, but ensures that the tests are + // valid for both POSIX (1 ns precision) and Windows (100 ns precision). + assert_eq!( + Timestamp::from(UNIX_EPOCH - time::Duration::new(1_001, 0)), + Timestamp { + seconds: -1_001, + nanos: 0 + } + ); + assert_eq!( + Timestamp::from(UNIX_EPOCH - time::Duration::new(0, 999_999_900)), + Timestamp { + seconds: -1, + nanos: 100 + } + ); + assert_eq!( + Timestamp::from(UNIX_EPOCH - time::Duration::new(2_001_234, 12_300)), + Timestamp { + seconds: -2_001_235, + nanos: 999_987_700 + } + ); + assert_eq!( + Timestamp::from(UNIX_EPOCH - time::Duration::new(768, 65_432_100)), + Timestamp { + seconds: -769, + nanos: 934_567_900 + } + ); + } + + #[cfg(all(unix, feature = "std"))] + #[test] + fn check_timestamp_negative_seconds_1ns() { + // UNIX-only test cases with 1 ns precision + assert_eq!( + Timestamp::from(UNIX_EPOCH - time::Duration::new(0, 999_999_999)), + Timestamp { + seconds: -1, + nanos: 1 + } + ); + assert_eq!( + Timestamp::from(UNIX_EPOCH - time::Duration::new(1_234_567, 123)), + Timestamp { + seconds: -1_234_568, + nanos: 999_999_877 + } + ); + assert_eq!( + Timestamp::from(UNIX_EPOCH - time::Duration::new(890, 987_654_321)), + Timestamp { + seconds: -891, + nanos: 12_345_679 + } + ); + } + + #[test] + fn check_duration_normalize() { + #[rustfmt::skip] // Don't mangle the table formatting. + let cases = [ + // --- Table of test cases --- + // test seconds test nanos expected seconds expected nanos + (line!(), 0, 0, 0, 0), + (line!(), 1, 1, 1, 1), + (line!(), -1, -1, -1, -1), + (line!(), 0, 999_999_999, 0, 999_999_999), + (line!(), 0, -999_999_999, 0, -999_999_999), + (line!(), 0, 1_000_000_000, 1, 0), + (line!(), 0, -1_000_000_000, -1, 0), + (line!(), 0, 1_000_000_001, 1, 1), + (line!(), 0, -1_000_000_001, -1, -1), + (line!(), -1, 1, 0, -999_999_999), + (line!(), 1, -1, 0, 999_999_999), + (line!(), -1, 1_000_000_000, 0, 0), + (line!(), 1, -1_000_000_000, 0, 0), + (line!(), i64::MIN , 0, i64::MIN , 0), + (line!(), i64::MIN + 1, 0, i64::MIN + 1, 0), + (line!(), i64::MIN , 1, i64::MIN + 1, -999_999_999), + (line!(), i64::MIN , 1_000_000_000, i64::MIN + 1, 0), + (line!(), i64::MIN , -1_000_000_000, i64::MIN , -999_999_999), + (line!(), i64::MIN + 1, -1_000_000_000, i64::MIN , 0), + (line!(), i64::MIN + 2, -1_000_000_000, i64::MIN + 1, 0), + (line!(), i64::MIN , -1_999_999_998, i64::MIN , -999_999_999), + (line!(), i64::MIN + 1, -1_999_999_998, i64::MIN , -999_999_998), + (line!(), i64::MIN + 2, -1_999_999_998, i64::MIN + 1, -999_999_998), + (line!(), i64::MIN , -1_999_999_999, i64::MIN , -999_999_999), + (line!(), i64::MIN + 1, -1_999_999_999, i64::MIN , -999_999_999), + (line!(), i64::MIN + 2, -1_999_999_999, i64::MIN + 1, -999_999_999), + (line!(), i64::MIN , -2_000_000_000, i64::MIN , -999_999_999), + (line!(), i64::MIN + 1, -2_000_000_000, i64::MIN , -999_999_999), + (line!(), i64::MIN + 2, -2_000_000_000, i64::MIN , 0), + (line!(), i64::MIN , -999_999_998, i64::MIN , -999_999_998), + (line!(), i64::MIN + 1, -999_999_998, i64::MIN + 1, -999_999_998), + (line!(), i64::MAX , 0, i64::MAX , 0), + (line!(), i64::MAX - 1, 0, i64::MAX - 1, 0), + (line!(), i64::MAX , -1, i64::MAX - 1, 999_999_999), + (line!(), i64::MAX , 1_000_000_000, i64::MAX , 999_999_999), + (line!(), i64::MAX - 1, 1_000_000_000, i64::MAX , 0), + (line!(), i64::MAX - 2, 1_000_000_000, i64::MAX - 1, 0), + (line!(), i64::MAX , 1_999_999_998, i64::MAX , 999_999_999), + (line!(), i64::MAX - 1, 1_999_999_998, i64::MAX , 999_999_998), + (line!(), i64::MAX - 2, 1_999_999_998, i64::MAX - 1, 999_999_998), + (line!(), i64::MAX , 1_999_999_999, i64::MAX , 999_999_999), + (line!(), i64::MAX - 1, 1_999_999_999, i64::MAX , 999_999_999), + (line!(), i64::MAX - 2, 1_999_999_999, i64::MAX - 1, 999_999_999), + (line!(), i64::MAX , 2_000_000_000, i64::MAX , 999_999_999), + (line!(), i64::MAX - 1, 2_000_000_000, i64::MAX , 999_999_999), + (line!(), i64::MAX - 2, 2_000_000_000, i64::MAX , 0), + (line!(), i64::MAX , 999_999_998, i64::MAX , 999_999_998), + (line!(), i64::MAX - 1, 999_999_998, i64::MAX - 1, 999_999_998), + ]; + + for case in cases.iter() { + let mut test_duration = Duration { + seconds: case.1, + nanos: case.2, + }; + test_duration.normalize(); + + assert_eq!( + test_duration, + Duration { + seconds: case.3, + nanos: case.4, + }, + "test case on line {} doesn't match", + case.0, + ); + } + } + + #[cfg(feature = "std")] + #[test] + fn check_timestamp_normalize() { + // Make sure that `Timestamp::normalize` behaves correctly on and near overflow. + #[rustfmt::skip] // Don't mangle the table formatting. + let cases = [ + // --- Table of test cases --- + // test seconds test nanos expected seconds expected nanos + (line!(), 0, 0, 0, 0), + (line!(), 1, 1, 1, 1), + (line!(), -1, -1, -2, 999_999_999), + (line!(), 0, 999_999_999, 0, 999_999_999), + (line!(), 0, -999_999_999, -1, 1), + (line!(), 0, 1_000_000_000, 1, 0), + (line!(), 0, -1_000_000_000, -1, 0), + (line!(), 0, 1_000_000_001, 1, 1), + (line!(), 0, -1_000_000_001, -2, 999_999_999), + (line!(), -1, 1, -1, 1), + (line!(), 1, -1, 0, 999_999_999), + (line!(), -1, 1_000_000_000, 0, 0), + (line!(), 1, -1_000_000_000, 0, 0), + (line!(), i64::MIN , 0, i64::MIN , 0), + (line!(), i64::MIN + 1, 0, i64::MIN + 1, 0), + (line!(), i64::MIN , 1, i64::MIN , 1), + (line!(), i64::MIN , 1_000_000_000, i64::MIN + 1, 0), + (line!(), i64::MIN , -1_000_000_000, i64::MIN , 0), + (line!(), i64::MIN + 1, -1_000_000_000, i64::MIN , 0), + (line!(), i64::MIN + 2, -1_000_000_000, i64::MIN + 1, 0), + (line!(), i64::MIN , -1_999_999_998, i64::MIN , 0), + (line!(), i64::MIN + 1, -1_999_999_998, i64::MIN , 0), + (line!(), i64::MIN + 2, -1_999_999_998, i64::MIN , 2), + (line!(), i64::MIN , -1_999_999_999, i64::MIN , 0), + (line!(), i64::MIN + 1, -1_999_999_999, i64::MIN , 0), + (line!(), i64::MIN + 2, -1_999_999_999, i64::MIN , 1), + (line!(), i64::MIN , -2_000_000_000, i64::MIN , 0), + (line!(), i64::MIN + 1, -2_000_000_000, i64::MIN , 0), + (line!(), i64::MIN + 2, -2_000_000_000, i64::MIN , 0), + (line!(), i64::MIN , -999_999_998, i64::MIN , 0), + (line!(), i64::MIN + 1, -999_999_998, i64::MIN , 2), + (line!(), i64::MAX , 0, i64::MAX , 0), + (line!(), i64::MAX - 1, 0, i64::MAX - 1, 0), + (line!(), i64::MAX , -1, i64::MAX - 1, 999_999_999), + (line!(), i64::MAX , 1_000_000_000, i64::MAX , 999_999_999), + (line!(), i64::MAX - 1, 1_000_000_000, i64::MAX , 0), + (line!(), i64::MAX - 2, 1_000_000_000, i64::MAX - 1, 0), + (line!(), i64::MAX , 1_999_999_998, i64::MAX , 999_999_999), + (line!(), i64::MAX - 1, 1_999_999_998, i64::MAX , 999_999_998), + (line!(), i64::MAX - 2, 1_999_999_998, i64::MAX - 1, 999_999_998), + (line!(), i64::MAX , 1_999_999_999, i64::MAX , 999_999_999), + (line!(), i64::MAX - 1, 1_999_999_999, i64::MAX , 999_999_999), + (line!(), i64::MAX - 2, 1_999_999_999, i64::MAX - 1, 999_999_999), + (line!(), i64::MAX , 2_000_000_000, i64::MAX , 999_999_999), + (line!(), i64::MAX - 1, 2_000_000_000, i64::MAX , 999_999_999), + (line!(), i64::MAX - 2, 2_000_000_000, i64::MAX , 0), + (line!(), i64::MAX , 999_999_998, i64::MAX , 999_999_998), + (line!(), i64::MAX - 1, 999_999_998, i64::MAX - 1, 999_999_998), + ]; + + for case in cases.iter() { + let mut test_timestamp = crate::Timestamp { + seconds: case.1, + nanos: case.2, + }; + test_timestamp.normalize(); + + assert_eq!( + test_timestamp, + crate::Timestamp { + seconds: case.3, + nanos: case.4, + }, + "test case on line {} doesn't match", + case.0, + ); + } + } +} diff --git a/kclvm/third-party/prost-wkt/wkt-types/resources/update.sh b/kclvm/third-party/prost-wkt/wkt-types/resources/update.sh new file mode 100755 index 000000000..71f68570f --- /dev/null +++ b/kclvm/third-party/prost-wkt/wkt-types/resources/update.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +WORKSPACE=`cargo metadata --format-version 1 | jq -r '.workspace_root '` +RESOURCES="${WORKSPACE}/wkt-types/resources" +VERSION=`cargo metadata --format-version 1 | jq -r '.packages[] | select( .name == "prost" ) | .version '` + +REPO="https://raw.githubusercontent.com/tokio-rs/prost/v${VERSION}/prost-types" +LIB_FILE="${REPO}/src/lib.rs" +DATETIME_FILE="${REPO}/src/datetime.rs" + +curl --silent ${LIB_FILE} > ${RESOURCES}/lib.rs +curl --silent ${DATETIME_FILE} > ${RESOURCES}/datetime.rs + +printf "\n!! Please update ${WORKSPACE}/wkt-types/build.rs to reflect new lib.rs !!\n\n" diff --git a/kclvm/third-party/prost-wkt/wkt-types/src/lib.rs b/kclvm/third-party/prost-wkt/wkt-types/src/lib.rs new file mode 100644 index 000000000..7d4dfcc2d --- /dev/null +++ b/kclvm/third-party/prost-wkt/wkt-types/src/lib.rs @@ -0,0 +1,15 @@ +//! `prost-wkt` adds helper methods to deal with protobuf well known types. + +mod pbtime; +pub use crate::pbtime::*; + +mod pbstruct; +pub use crate::pbstruct::*; + +mod pbany; +pub use crate::pbany::*; + +mod pbempty; +pub use crate::pbempty::*; + +pub use prost_wkt::MessageSerde; diff --git a/kclvm/third-party/prost-wkt/wkt-types/src/pbany.rs b/kclvm/third-party/prost-wkt/wkt-types/src/pbany.rs new file mode 100644 index 000000000..4c46183fc --- /dev/null +++ b/kclvm/third-party/prost-wkt/wkt-types/src/pbany.rs @@ -0,0 +1,241 @@ +use prost_wkt::MessageSerde; +use serde::de::{Deserialize, Deserializer}; +use serde::ser::{Serialize, SerializeStruct, Serializer}; + +include!(concat!(env!("OUT_DIR"), "/pbany/google.protobuf.rs")); + +use prost::{DecodeError, Message}; + +use std::borrow::Cow; + +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct AnyError { + description: Cow<'static, str>, +} + +impl AnyError { + pub fn new(description: S) -> Self + where + S: Into>, + { + AnyError { + description: description.into(), + } + } +} + +impl std::error::Error for AnyError { + fn description(&self) -> &str { + &self.description + } +} + +impl std::fmt::Display for AnyError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_str("failed to convert Value: ")?; + f.write_str(&self.description) + } +} + +impl From for AnyError { + fn from(error: DecodeError) -> Self { + AnyError::new(format!("Error decoding message: {error:?}")) + } +} + +impl From for AnyError { + fn from(error: prost::EncodeError) -> Self { + AnyError::new(format!("Error encoding message: {error:?}")) + } +} + +impl Any { + /// Packs a message into an `Any` containing a `type_url` which will take the format + /// of `type.googleapis.com/package_name.struct_name`, and a value containing the + /// encoded message. + #[deprecated(since = "0.3.0", note = "please use `try_pack` instead")] + pub fn pack(message: T) -> Self + where + T: Message + MessageSerde + Default, + { + let type_url = MessageSerde::type_url(&message).to_string(); + // Serialize the message into a value + let mut buf = Vec::new(); + buf.reserve(message.encoded_len()); + message.encode(&mut buf).expect("Failed to encode message"); + Any { + type_url, + value: buf, + } + } + + /// Packs a message into an `Any` containing a `type_url` which will take the format + /// of `type.googleapis.com/package_name.struct_name`, and a value containing the + /// encoded message. + pub fn try_pack(message: T) -> Result + where + T: Message + MessageSerde + Default, + { + let type_url = MessageSerde::type_url(&message).to_string(); + // Serialize the message into a value + let mut buf = Vec::new(); + buf.reserve(message.encoded_len()); + message.encode(&mut buf)?; + let encoded = Any { + type_url, + value: buf, + }; + Ok(encoded) + } + + /// Unpacks the contents of the `Any` into the provided message type. Example usage: + /// + /// ```ignore + /// let back: Foo = any.unpack_as(Foo::default())?; + /// ``` + pub fn unpack_as(self, mut target: T) -> Result { + let instance = target.merge(self.value.as_slice()).map(|_| target)?; + Ok(instance) + } + + #[deprecated(since = "0.3.0", note = "Method renamed to `try_unpack`")] + pub fn unpack(self) -> Result, AnyError> { + self.try_unpack() + } + + /// Unpacks the contents of the `Any` into the `MessageSerde` trait object. Example + /// usage: + /// + /// ```ignore + /// let back: Box = any.try_unpack()?; + /// ``` + pub fn try_unpack(self) -> Result, AnyError> { + ::prost_wkt::inventory::iter::<::prost_wkt::MessageSerdeDecoderEntry> + .into_iter() + .find(|entry| self.type_url == entry.type_url) + .ok_or_else(|| format!("Failed to deserialize {}. Make sure prost-wkt-build is executed.", self.type_url)) + .and_then(|entry| { + (entry.decoder)(&self.value).map_err(|error| { + format!( + "Failed to deserialize {}. Make sure it implements prost::Message. Error reported: {}", + self.type_url, + error + ) + }) + }) + .map_err(AnyError::new) + } +} + +impl Serialize for Any { + fn serialize(&self, serializer: S) -> Result<::Ok, ::Error> + where + S: Serializer, + { + match self.clone().try_unpack() { + Ok(result) => serde::ser::Serialize::serialize(result.as_ref(), serializer), + Err(_) => { + let mut state = serializer.serialize_struct("Any", 3)?; + state.serialize_field("@type", &self.type_url)?; + state.serialize_field("value", &self.value)?; + state.end() + } + } + } +} + +impl<'de> Deserialize<'de> for Any { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let erased: Box = + serde::de::Deserialize::deserialize(deserializer)?; + let type_url = erased.type_url().to_string(); + let value = erased.try_encoded().map_err(|err| { + serde::de::Error::custom(format!("Failed to encode message: {err:?}")) + })?; + Ok(Any { type_url, value }) + } +} + +#[cfg(test)] +mod tests { + use crate::pbany::*; + use prost::{DecodeError, EncodeError, Message}; + use prost_wkt::*; + use serde::*; + use serde_json::json; + + #[derive(Clone, Eq, PartialEq, ::prost::Message, Serialize, Deserialize)] + #[serde(default, rename_all = "camelCase")] + pub struct Foo { + #[prost(string, tag = "1")] + pub string: std::string::String, + } + + #[typetag::serde(name = "type.googleapis.com/any.test.Foo")] + impl prost_wkt::MessageSerde for Foo { + fn message_name(&self) -> &'static str { + "Foo" + } + + fn package_name(&self) -> &'static str { + "any.test" + } + + fn type_url(&self) -> &'static str { + "type.googleapis.com/any.test.Foo" + } + fn new_instance(&self, data: Vec) -> Result, DecodeError> { + let mut target = Self::default(); + Message::merge(&mut target, data.as_slice())?; + let erased: Box = Box::new(target); + Ok(erased) + } + + fn try_encoded(&self) -> Result, EncodeError> { + let mut buf = Vec::new(); + buf.reserve(Message::encoded_len(self)); + Message::encode(self, &mut buf)?; + Ok(buf) + } + } + + #[test] + fn pack_unpack_test() { + let msg = Foo { + string: "Hello World!".to_string(), + }; + let any = Any::try_pack(msg.clone()).unwrap(); + println!("{any:?}"); + let unpacked = any.unpack_as(Foo::default()).unwrap(); + println!("{unpacked:?}"); + assert_eq!(unpacked, msg) + } + + #[test] + fn pack_unpack_with_downcast_test() { + let msg = Foo { + string: "Hello World!".to_string(), + }; + let any = Any::try_pack(msg.clone()).unwrap(); + println!("{any:?}"); + let unpacked: &dyn MessageSerde = &any.unpack_as(Foo::default()).unwrap(); + let downcast = unpacked.downcast_ref::().unwrap(); + assert_eq!(downcast, &msg); + } + + #[test] + fn deserialize_default_test() { + let type_url = "type.googleapis.com/any.test.Foo"; + let data = json!({ + "@type": type_url, + "value": {} + }); + let erased: Box = serde_json::from_value(data).unwrap(); + let foo: &Foo = erased.downcast_ref::().unwrap(); + println!("Deserialize default: {foo:?}"); + assert_eq!(foo, &Foo::default()) + } +} diff --git a/kclvm/third-party/prost-wkt/wkt-types/src/pbempty.rs b/kclvm/third-party/prost-wkt/wkt-types/src/pbempty.rs new file mode 100644 index 000000000..12ab968aa --- /dev/null +++ b/kclvm/third-party/prost-wkt/wkt-types/src/pbempty.rs @@ -0,0 +1,37 @@ +include!(concat!(env!("OUT_DIR"), "/pbempty/google.protobuf.rs")); + +const EMPTY: Empty = Empty {}; + +impl From<()> for Empty { + fn from(_value: ()) -> Self { + EMPTY + } +} + +#[cfg(test)] +mod tests { + + use crate::pbempty::*; + + #[test] + fn serialize_empty() { + let msg = EMPTY; + println!( + "Serialized to string: {}", + serde_json::to_string_pretty(&msg).unwrap() + ); + } + + #[test] + fn deserialize_empty() { + let msg: Empty = + serde_json::from_str("{}").expect("Could not deserialize `{}` to an Empty struct!"); + assert_eq!(msg, EMPTY); + } + + #[test] + fn convert_unit() { + let msg: Empty = ().into(); + assert_eq!(msg, Empty {}); + } +} diff --git a/kclvm/third-party/prost-wkt/wkt-types/src/pbstruct.rs b/kclvm/third-party/prost-wkt/wkt-types/src/pbstruct.rs new file mode 100644 index 000000000..26b8e82f9 --- /dev/null +++ b/kclvm/third-party/prost-wkt/wkt-types/src/pbstruct.rs @@ -0,0 +1,430 @@ +use serde::de::{self, Deserialize, Deserializer, MapAccess, SeqAccess, Visitor}; +use serde::ser::{Serialize, SerializeMap, SerializeSeq, Serializer}; + +use std::borrow::Cow; +use std::convert::TryFrom; +use std::fmt; + +include!(concat!(env!("OUT_DIR"), "/pbstruct/google.protobuf.rs")); + +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct ValueError { + description: Cow<'static, str>, +} + +impl ValueError { + pub fn new(description: S) -> Self + where + S: Into>, + { + ValueError { + description: description.into(), + } + } +} + +impl std::error::Error for ValueError { + fn description(&self) -> &str { + &self.description + } +} + +impl std::fmt::Display for ValueError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_str("failed to convert Value: ")?; + f.write_str(&self.description) + } +} + +impl Value { + pub fn null() -> Self { + let kind = Some(value::Kind::NullValue(0)); + Value { kind } + } + pub fn number(num: f64) -> Self { + Value::from(num) + } + pub fn string(s: String) -> Self { + Value::from(s) + } + pub fn bool(b: bool) -> Self { + Value::from(b) + } + pub fn pb_struct(m: std::collections::HashMap) -> Self { + Value::from(m) + } + pub fn pb_list(l: std::vec::Vec) -> Self { + Value::from(l) + } +} + +impl From for Value { + fn from(_: NullValue) -> Self { + Value::null() + } +} + +impl From for Value { + fn from(num: f64) -> Self { + let kind = Some(value::Kind::NumberValue(num)); + Value { kind } + } +} + +impl TryFrom for f64 { + type Error = ValueError; + + fn try_from(value: Value) -> Result { + match value.kind { + Some(value::Kind::NumberValue(num)) => Ok(num), + Some(_other) => Err(ValueError::new( + "Cannot convert to f64 because this is not a ValueNumber.", + )), + _ => Err(ValueError::new( + "Conversion to f64 failed because value is empty!", + )), + } + } +} + +impl From for Value { + fn from(s: String) -> Self { + let kind = Some(value::Kind::StringValue(s)); + Value { kind } + } +} + +impl TryFrom for String { + type Error = ValueError; + + fn try_from(value: Value) -> Result { + match value.kind { + Some(value::Kind::StringValue(string)) => Ok(string), + Some(_other) => Err(ValueError::new( + "Cannot convert to String because this is not a StringValue.", + )), + _ => Err(ValueError::new( + "Conversion to String failed because value is empty!", + )), + } + } +} + +impl From for Value { + fn from(b: bool) -> Self { + let kind = Some(value::Kind::BoolValue(b)); + Value { kind } + } +} + +impl TryFrom for bool { + type Error = ValueError; + + fn try_from(value: Value) -> Result { + match value.kind { + Some(value::Kind::BoolValue(b)) => Ok(b), + Some(_other) => Err(ValueError::new( + "Cannot convert to bool because this is not a BoolValue.", + )), + _ => Err(ValueError::new( + "Conversion to bool failed because value is empty!", + )), + } + } +} + +impl From> for Value { + fn from(fields: std::collections::HashMap) -> Self { + let s = Struct { fields }; + let kind = Some(value::Kind::StructValue(s)); + Value { kind } + } +} + +impl TryFrom for std::collections::HashMap { + type Error = ValueError; + + fn try_from(value: Value) -> Result { + match value.kind { + Some(value::Kind::StructValue(s)) => Ok(s.fields), + Some(_other) => Err(ValueError::new( + "Cannot convert to HashMap because this is not a StructValue.", + )), + _ => Err(ValueError::new( + "Conversion to HashMap failed because value is empty!", + )), + } + } +} + +impl From> for Value { + fn from(values: Vec) -> Self { + let v = ListValue { values }; + let kind = Some(value::Kind::ListValue(v)); + Value { kind } + } +} + +impl TryFrom for std::vec::Vec { + type Error = ValueError; + + fn try_from(value: Value) -> Result { + match value.kind { + Some(value::Kind::ListValue(list)) => Ok(list.values), + Some(_other) => Err(ValueError::new( + "Cannot convert to Vec because this is not a ListValue.", + )), + _ => Err(ValueError::new( + "Conversion to Vec failed because value is empty!", + )), + } + } +} + +impl Serialize for ListValue { + fn serialize(&self, serializer: S) -> Result<::Ok, ::Error> + where + S: Serializer, + { + let mut seq = serializer.serialize_seq(Some(self.values.len()))?; + for e in &self.values { + seq.serialize_element(e)?; + } + seq.end() + } +} + +impl Serialize for Struct { + fn serialize(&self, serializer: S) -> Result<::Ok, ::Error> + where + S: Serializer, + { + let mut map = serializer.serialize_map(Some(self.fields.len()))?; + for (k, v) in &self.fields { + map.serialize_entry(k, v)?; + } + map.end() + } +} + +impl Serialize for Value { + fn serialize(&self, serializer: S) -> Result<::Ok, ::Error> + where + S: Serializer, + { + match &self.kind { + Some(value::Kind::NumberValue(num)) => serializer.serialize_f64(*num), + Some(value::Kind::StringValue(string)) => serializer.serialize_str(string), + Some(value::Kind::BoolValue(boolean)) => serializer.serialize_bool(*boolean), + Some(value::Kind::NullValue(_)) => serializer.serialize_none(), + Some(value::Kind::ListValue(list)) => list.serialize(serializer), + Some(value::Kind::StructValue(object)) => object.serialize(serializer), + _ => serializer.serialize_none(), + } + } +} + +struct ListValueVisitor; +impl<'de> Visitor<'de> for ListValueVisitor { + type Value = crate::ListValue; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a prost_wkt_types::ListValue struct") + } + + fn visit_seq(self, mut seq: A) -> Result + where + A: SeqAccess<'de>, + { + let mut values: Vec = Vec::new(); + while let Some(el) = seq.next_element()? { + values.push(el) + } + Ok(ListValue { values }) + } +} + +impl<'de> Deserialize<'de> for ListValue { + fn deserialize(deserializer: D) -> Result>::Error> + where + D: Deserializer<'de>, + { + deserializer.deserialize_seq(ListValueVisitor) + } +} + +struct StructVisitor; +impl<'de> Visitor<'de> for StructVisitor { + type Value = crate::Struct; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a prost_wkt_types::Struct struct") + } + + fn visit_map(self, mut map: A) -> Result + where + A: MapAccess<'de>, + { + let mut fields: std::collections::HashMap = std::collections::HashMap::new(); + while let Some((key, value)) = map.next_entry::()? { + fields.insert(key, value); + } + Ok(Struct { fields }) + } +} + +impl<'de> Deserialize<'de> for Struct { + fn deserialize(deserializer: D) -> Result>::Error> + where + D: Deserializer<'de>, + { + deserializer.deserialize_map(StructVisitor) + } +} + +impl<'de> Deserialize<'de> for Value { + fn deserialize(deserializer: D) -> Result>::Error> + where + D: Deserializer<'de>, + { + struct ValueVisitor; + + impl<'de> Visitor<'de> for ValueVisitor { + type Value = crate::Value; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a prost_wkt_types::Value struct") + } + + fn visit_bool(self, value: bool) -> Result + where + E: de::Error, + { + Ok(Value::from(value)) + } + + fn visit_i64(self, value: i64) -> Result + where + E: de::Error, + { + Ok(Value::from(value as f64)) + } + + fn visit_u64(self, value: u64) -> Result + where + E: de::Error, + { + Ok(Value::from(value as f64)) + } + + fn visit_f64(self, value: f64) -> Result + where + E: de::Error, + { + Ok(Value::from(value)) + } + + fn visit_str(self, value: &str) -> Result + where + E: de::Error, + { + Ok(Value::from(String::from(value))) + } + + fn visit_string(self, value: String) -> Result + where + E: de::Error, + { + Ok(Value::from(value)) + } + + fn visit_none(self) -> Result + where + E: de::Error, + { + Ok(Value::null()) + } + + fn visit_unit(self) -> Result + where + E: de::Error, + { + Ok(Value::null()) + } + + fn visit_seq(self, seq: A) -> Result + where + A: SeqAccess<'de>, + { + ListValueVisitor.visit_seq(seq).map(|lv| { + let kind = Some(value::Kind::ListValue(lv)); + Value { kind } + }) + } + + fn visit_map(self, map: A) -> Result + where + A: MapAccess<'de>, + { + StructVisitor.visit_map(map).map(|s| { + let kind = Some(value::Kind::StructValue(s)); + Value { kind } + }) + } + } + deserializer.deserialize_any(ValueVisitor) + } +} + +#[cfg(test)] +mod tests { + use crate::pbstruct::*; + use std::collections::HashMap; + + #[test] + fn conversion_test() { + let number: Value = Value::from(10.0); + println!("Number: {number:?}"); + let null: Value = Value::null(); + println!("Null: {null:?}"); + let string: Value = Value::from(String::from("Hello")); + println!("String: {string:?}"); + let list = vec![Value::null(), Value::from(100.0)]; + let pb_list: Value = Value::from(list); + println!("List: {pb_list:?}"); + let mut map: HashMap = HashMap::new(); + map.insert(String::from("some_number"), number); + map.insert(String::from("a_null_value"), null); + map.insert(String::from("string"), string); + map.insert(String::from("list"), pb_list); + let pb_struct: Value = Value::from(map); + println!("Struct: {pb_struct:?}"); + } + + #[test] + fn convert_serde_json_test() { + let data = r#"{ + "string":"hello", + "timestamp":"1970-01-01T00:01:39.000000042Z", + "boolean":true, + "data": { + "test_number": 1.0, + "test_bool": true, + "testString": "hi there", + "testList": [1.0, 2.0, 3.0, 4.0], + "testInnerStruct": { + "one": 1.0, + "two": 2.0 + } + }, + "list": [] + }"#; + let sj: serde_json::Value = serde_json::from_str(data).unwrap(); + println!("serde_json::Value: {sj:#?}"); + let pj: Value = serde_json::from_value(sj.clone()).unwrap(); + let string: String = serde_json::to_string_pretty(&pj).unwrap(); + println!("prost_wkt_types String: {string}"); + let back: serde_json::Value = serde_json::from_str(&string).unwrap(); + assert_eq!(sj, back); + } +} diff --git a/kclvm/third-party/prost-wkt/wkt-types/src/pbtime.rs b/kclvm/third-party/prost-wkt/wkt-types/src/pbtime.rs new file mode 100644 index 000000000..055d17819 --- /dev/null +++ b/kclvm/third-party/prost-wkt/wkt-types/src/pbtime.rs @@ -0,0 +1,122 @@ +use core::convert::TryFrom; +use core::str::FromStr; +use core::*; +use std::convert::TryInto; + +use chrono::prelude::*; + +use serde::de::{self, Deserialize, Deserializer, Visitor}; +use serde::ser::{Serialize, Serializer}; + +include!(concat!(env!("OUT_DIR"), "/pbtime/google.protobuf.rs")); +include!(concat!(env!("OUT_DIR"), "/prost_snippet.rs")); + +/// Converts chrono's `NaiveDateTime` to `Timestamp`.. +impl From for Timestamp { + fn from(dt: NaiveDateTime) -> Self { + Timestamp { + seconds: dt.and_utc().timestamp(), + nanos: dt.and_utc().timestamp_subsec_nanos() as i32, + } + } +} + +/// Converts chrono's `DateTime` to `Timestamp` +impl From> for Timestamp { + fn from(dt: DateTime) -> Self { + Timestamp { + seconds: dt.timestamp(), + nanos: dt.timestamp_subsec_nanos() as i32, + } + } +} + +/// Converts proto timestamp to chrono's DateTime +impl From for DateTime { + fn from(val: Timestamp) -> Self { + let mut value = val; + // A call to `normalize` should capture all out-of-bound sitations hopefully + // ensuring a panic never happens! Ideally this implementation should be + // deprecated in favour of TryFrom but unfortunately having `TryFrom` along with + // `From` causes a conflict. + value.normalize(); + DateTime::from_timestamp(value.seconds, value.nanos as u32) + .expect("invalid or out-of-range datetime") + } +} + +impl Serialize for Timestamp { + fn serialize(&self, serializer: S) -> Result<::Ok, ::Error> + where + S: Serializer, + { + let mut ts = Timestamp { + seconds: self.seconds, + nanos: self.nanos, + }; + ts.normalize(); + let dt: DateTime = ts.try_into().map_err(serde::ser::Error::custom)?; + serializer.serialize_str(format!("{dt:?}").as_str()) + } +} + +impl<'de> Deserialize<'de> for Timestamp { + fn deserialize(deserializer: D) -> Result>::Error> + where + D: Deserializer<'de>, + { + struct TimestampVisitor; + + impl<'de> Visitor<'de> for TimestampVisitor { + type Value = Timestamp; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Timestamp in RFC3339 format") + } + + fn visit_str(self, value: &str) -> Result + where + E: de::Error, + { + let utc: DateTime = chrono::DateTime::from_str(value).map_err(|err| { + serde::de::Error::custom(format!( + "Failed to parse {value} as datetime: {err:?}" + )) + })?; + let ts = Timestamp::from(utc); + Ok(ts) + } + } + deserializer.deserialize_str(TimestampVisitor) + } +} + +#[cfg(test)] +mod tests { + + use crate::pbtime::*; + use chrono::{DateTime, Utc}; + + #[test] + fn serialize_duration() { + let duration = Duration { + seconds: 10, + nanos: 100, + }; + let json = serde_json::to_string_pretty(&duration).expect("json"); + println!("{json}"); + let back: Duration = serde_json::from_str(&json).expect("duration"); + assert_eq!(duration, back); + } + + #[test] + fn invalid_timestamp_test() { + let ts = Timestamp { + seconds: 10, + nanos: 2000000000, + }; + let datetime_utc: DateTime = ts.into(); + + println!("{datetime_utc:?}"); + } +} diff --git a/kclvm/third-party/prost-wkt/wkt-types/tests/pbany_test.rs b/kclvm/third-party/prost-wkt/wkt-types/tests/pbany_test.rs new file mode 100644 index 000000000..815c14e09 --- /dev/null +++ b/kclvm/third-party/prost-wkt/wkt-types/tests/pbany_test.rs @@ -0,0 +1,179 @@ +use prost::{DecodeError, EncodeError, Message}; +use prost_wkt::*; +use prost_wkt_types::*; +use serde::{Deserialize, Serialize}; +use std::collections::HashMap; + +#[derive(Clone, PartialEq, ::prost::Message, Serialize, Deserialize)] +#[prost(package = "any.test")] +#[serde(rename_all = "camelCase")] +pub struct Foo { + #[prost(string, tag = "1")] + pub string: std::string::String, + #[prost(message, optional, tag = "2")] + pub timestamp: ::std::option::Option<::prost_wkt_types::Timestamp>, + #[prost(bool, tag = "3")] + pub boolean: bool, + #[prost(message, optional, tag = "4")] + pub value_data: ::std::option::Option<::prost_wkt_types::Value>, + #[prost(string, repeated, tag = "5")] + pub list: ::std::vec::Vec, + #[prost(message, optional, tag = "6")] + pub payload: ::std::option::Option<::prost_wkt_types::Any>, +} + +#[typetag::serde(name = "type.googleapis.com/any.test.Foo")] +impl prost_wkt::MessageSerde for Foo { + fn message_name(&self) -> &'static str { + "Foo" + } + + fn package_name(&self) -> &'static str { + "any.test" + } + + fn type_url(&self) -> &'static str { + "type.googleapis.com/any.test.Foo" + } + + fn new_instance(&self, data: Vec) -> Result, DecodeError> { + let mut target = Self::default(); + Message::merge(&mut target, data.as_slice())?; + let erased: Box = Box::new(target); + Ok(erased) + } + + fn try_encoded(&self) -> Result, EncodeError> { + let mut buf = Vec::new(); + buf.reserve(Message::encoded_len(self)); + Message::encode(self, &mut buf)?; + Ok(buf) + } +} + +::prost_wkt::inventory::submit! { + ::prost_wkt::MessageSerdeDecoderEntry { + type_url: "type.googleapis.com/any.test.Foo", + decoder: |buf: &[u8]| { + let msg: Foo = ::prost::Message::decode(buf)?; + Ok(Box::new(msg)) + } + } +} + +fn create_struct() -> Value { + let number: Value = Value::from(10.0); + let null: Value = Value::null(); + let string: Value = Value::from(String::from("Hello")); + let list = vec![Value::null(), Value::from(100.0)]; + let pb_list: Value = Value::from(list); + let mut map: HashMap = HashMap::new(); + map.insert(String::from("number"), number); + map.insert(String::from("null"), null); + map.insert(String::from("string"), string); + map.insert(String::from("list"), pb_list); + Value::from(map) +} + +#[test] +fn test_any_serialization() { + let inner = Foo { + string: String::from("inner"), + timestamp: None, + boolean: false, + value_data: Some(create_struct()), + list: vec!["een".to_string(), "twee".to_string()], + payload: None, + }; + + let msg = Foo { + string: String::from("hello"), + timestamp: Some(prost_wkt_types::Timestamp { + seconds: 99, + nanos: 42, + }), + boolean: true, + value_data: Some(prost_wkt_types::Value::from("world".to_string())), + list: vec!["one".to_string(), "two".to_string()], + payload: prost_wkt_types::Any::try_pack(inner).ok(), + }; + println!( + "Serialized to string: {}", + serde_json::to_string_pretty(&msg).unwrap() + ); + let erased = &msg as &dyn MessageSerde; + let json = serde_json::to_string(erased).unwrap(); + println!("Erased json: {json}"); +} + +#[test] +fn test_any_deserialize_string() { + let data = r#"{ + "string":"hello", + "timestamp":"1970-01-01T00:01:39.000000042Z", + "boolean":true, + "valueData": { + "test_number": 1, + "test_bool": true, + "test_string": "hi there", + "test_list": [1, 2, 3, 4], + "test_inner_struct": { + "one": 1, + "two": 2 + } + }, + "list": [] + }"#; + let msg: Foo = serde_json::from_str(data).unwrap(); + println!("Deserialized from string: {msg:?}"); + let serialized = serde_json::to_string_pretty(&msg).expect("serialized Foo"); + println!("{serialized}") +} + +#[test] +fn test_any_serialize_deserialize() { + let inner = Foo { + string: String::from("inner"), + timestamp: None, + boolean: false, + value_data: None, + list: vec!["een".to_string(), "twee".to_string()], + payload: None, + }; + + let original = Foo { + string: String::from("original"), + timestamp: Some(prost_wkt_types::Timestamp { + seconds: 99, + nanos: 42, + }), + boolean: true, + value_data: Some(prost_wkt_types::Value::from("world".to_string())), + list: vec!["one".to_string(), "two".to_string()], + payload: prost_wkt_types::Any::try_pack(inner).ok(), + }; + + let json = serde_json::to_string(&original).unwrap(); + println!("Serialized Foo: {json}"); + let back: Foo = serde_json::from_str(&json).unwrap(); + println!("Deserialized Foo: {:?}", &back); + assert_eq!(back, original) +} + +#[test] +#[allow(clippy::disallowed_names)] +fn test_any_unpack() { + let payload = Foo { + string: String::from("hello payload"), + timestamp: None, + boolean: false, + value_data: None, + list: vec!["een".to_string(), "twee".to_string()], + payload: None, + }; + let any = prost_wkt_types::Any::try_pack(payload).unwrap(); + let unpacked = any.try_unpack().unwrap(); + let foo = unpacked.downcast_ref::().unwrap(); + println!("Unpacked: {foo:?}"); + assert_eq!(foo.string, "hello payload"); +} diff --git a/kclvm/third-party/prost-wkt/wkt-types/tests/pbstruct_test.rs b/kclvm/third-party/prost-wkt/wkt-types/tests/pbstruct_test.rs new file mode 100644 index 000000000..add9ef65e --- /dev/null +++ b/kclvm/third-party/prost-wkt/wkt-types/tests/pbstruct_test.rs @@ -0,0 +1,59 @@ +use prost_wkt_types::*; +use std::collections::HashMap; + +fn create_struct() -> Value { + let number: Value = Value::from(10.0); + let null: Value = Value::null(); + let string: Value = Value::from(String::from("Hello")); + let list = vec![Value::null(), Value::from(100.0)]; + let pb_list: Value = Value::from(list); + let mut map: HashMap = HashMap::new(); + map.insert(String::from("number"), number); + map.insert(String::from("null"), null); + map.insert(String::from("some_string"), string); + map.insert(String::from("list"), pb_list); + Value::from(map) +} + +#[test] +fn test_serde() { + let value = create_struct(); + let string = serde_json::to_string_pretty(&value).expect("Json string"); + println!("{string}"); + let back: Value = serde_json::from_str(&string).expect("Value"); + println!("{back:?}"); + assert_eq!(value, back); +} + +#[test] +fn test_flatten_struct() { + let mut fields: HashMap = HashMap::new(); + fields.insert("test".to_string(), create_struct()); + let strct = Struct { + fields: fields.clone(), + }; + let string_strct = serde_json::to_string_pretty(&strct).expect("Serialized struct"); + println!("{string_strct}"); + + let value = Value::from(fields); + let string = serde_json::to_string_pretty(&value).expect("A Value serialized to string"); + println!("{string}"); + + assert_eq!(string_strct, string); +} + +#[test] +fn test_flatten_list() { + let values: Vec = vec![Value::null(), Value::from(20.0), Value::from(true)]; + let list: ListValue = ListValue { + values: values.clone(), + }; + let string_list = serde_json::to_string_pretty(&list).expect("Serialized list"); + println!("{string_list}"); + + let value = Value::from(values); + let string = serde_json::to_string_pretty(&value).expect("A Value serialized to string"); + println!("{string}"); + + assert_eq!(string_list, string); +} diff --git a/kclvm/third-party/serde_yaml/.github/FUNDING.yml b/kclvm/third-party/serde_yaml/.github/FUNDING.yml new file mode 100644 index 000000000..750707701 --- /dev/null +++ b/kclvm/third-party/serde_yaml/.github/FUNDING.yml @@ -0,0 +1 @@ +github: dtolnay diff --git a/kclvm/third-party/serde_yaml/.github/workflows/ci.yml b/kclvm/third-party/serde_yaml/.github/workflows/ci.yml new file mode 100644 index 000000000..624334b8b --- /dev/null +++ b/kclvm/third-party/serde_yaml/.github/workflows/ci.yml @@ -0,0 +1,111 @@ +name: CI + +on: + push: + pull_request: + workflow_dispatch: + schedule: [cron: "40 1 * * *"] + +permissions: + contents: read + +env: + RUSTFLAGS: -Dwarnings + +jobs: + pre_ci: + uses: dtolnay/.github/.github/workflows/pre_ci.yml@master + + test: + name: Rust ${{matrix.rust}} + needs: pre_ci + if: needs.pre_ci.outputs.continue + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + rust: [nightly, beta, stable, 1.64.0] + timeout-minutes: 45 + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@master + with: + toolchain: ${{matrix.rust}} + - name: Enable type layout randomization + run: echo RUSTFLAGS=${RUSTFLAGS}\ -Zrandomize-layout >> $GITHUB_ENV + if: matrix.rust == 'nightly' + - run: cargo build + - run: cargo test + + doc: + name: Documentation + needs: pre_ci + if: needs.pre_ci.outputs.continue + runs-on: ubuntu-latest + timeout-minutes: 45 + env: + RUSTDOCFLAGS: -Dwarnings + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@nightly + - uses: dtolnay/install@cargo-docs-rs + - run: cargo docs-rs + + clippy: + name: Clippy + runs-on: ubuntu-latest + if: github.event_name != 'pull_request' + timeout-minutes: 45 + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@clippy + - run: cargo clippy --tests -- -Dclippy::all -Dclippy::pedantic + + miri: + name: Miri + needs: pre_ci + if: needs.pre_ci.outputs.continue + runs-on: ubuntu-latest + timeout-minutes: 45 + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@miri + - run: cargo miri setup + - run: cargo miri test + env: + MIRIFLAGS: -Zmiri-strict-provenance + + minimal: + name: Minimal versions + needs: pre_ci + if: needs.pre_ci.outputs.continue + runs-on: ubuntu-latest + timeout-minutes: 45 + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@nightly + - run: cargo generate-lockfile -Z minimal-versions + - run: cargo check --locked + + fuzz: + name: Fuzz + needs: pre_ci + if: needs.pre_ci.outputs.continue + runs-on: ubuntu-latest + timeout-minutes: 45 + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@nightly + - uses: dtolnay/install@cargo-fuzz + - run: cargo fuzz check + + outdated: + name: Outdated + runs-on: ubuntu-latest + if: github.event_name != 'pull_request' + timeout-minutes: 45 + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/install@cargo-outdated + - run: cargo outdated --workspace --exit-code 1 + - run: cargo outdated --manifest-path fuzz/Cargo.toml --exit-code 1 diff --git a/kclvm/third-party/serde_yaml/.gitignore b/kclvm/third-party/serde_yaml/.gitignore new file mode 100644 index 000000000..a9d37c560 --- /dev/null +++ b/kclvm/third-party/serde_yaml/.gitignore @@ -0,0 +1,2 @@ +target +Cargo.lock diff --git a/kclvm/third-party/serde_yaml/Cargo.toml b/kclvm/third-party/serde_yaml/Cargo.toml new file mode 100644 index 000000000..749e18bc2 --- /dev/null +++ b/kclvm/third-party/serde_yaml/Cargo.toml @@ -0,0 +1,62 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2021" +rust-version = "1.64" +name = "serde_yaml" +version = "0.9.34+deprecated" +authors = ["David Tolnay "] +description = "YAML data format for Serde" +documentation = "https://docs.rs/serde_yaml/" +readme = "README.md" +keywords = [ + "yaml", + "serde", + "serialization", +] +categories = [ + "encoding", + "parser-implementations", +] +license = "MIT OR Apache-2.0" +repository = "https://github.com/dtolnay/serde-yaml" + +[package.metadata.docs.rs] +rustdoc-args = ["--generate-link-to-definition"] +targets = ["x86_64-unknown-linux-gnu"] + +[lib] +doc-scrape-examples = false + +[dependencies.indexmap] +version = "2.2.1" + +[dependencies.itoa] +version = "1.0" + +[dependencies.ryu] +version = "1.0" + +[dependencies.serde] +version = "1.0.195" + +[dependencies.unsafe-libyaml] +version = "0.2.11" + +[dev-dependencies.anyhow] +version = "1.0.79" + +[dev-dependencies.indoc] +version = "2.0" + +[dev-dependencies.serde_derive] +version = "1.0.195" diff --git a/kclvm/third-party/serde_yaml/LICENSE-APACHE b/kclvm/third-party/serde_yaml/LICENSE-APACHE new file mode 100644 index 000000000..1b5ec8b78 --- /dev/null +++ b/kclvm/third-party/serde_yaml/LICENSE-APACHE @@ -0,0 +1,176 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS diff --git a/kclvm/third-party/serde_yaml/LICENSE-MIT b/kclvm/third-party/serde_yaml/LICENSE-MIT new file mode 100644 index 000000000..31aa79387 --- /dev/null +++ b/kclvm/third-party/serde_yaml/LICENSE-MIT @@ -0,0 +1,23 @@ +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/kclvm/third-party/serde_yaml/README.md b/kclvm/third-party/serde_yaml/README.md new file mode 100644 index 000000000..1a3416644 --- /dev/null +++ b/kclvm/third-party/serde_yaml/README.md @@ -0,0 +1,153 @@ +Serde YAML +========== + +[github](https://github.com/dtolnay/serde-yaml) +[crates.io](https://crates.io/crates/serde_yaml) +[docs.rs](https://docs.rs/serde_yaml) +[build status](https://github.com/dtolnay/serde-yaml/actions?query=branch%3Amaster) + +Rust library for using the [Serde] serialization framework with data in [YAML] +file format. _(This project is no longer maintained.)_ + +[Serde]: https://github.com/serde-rs/serde +[YAML]: https://yaml.org/ + +## Dependency + +```toml +[dependencies] +serde = "1.0" +serde_yaml = "0.9" +``` + +Release notes are available under [GitHub releases]. + +[GitHub releases]: https://github.com/dtolnay/serde-yaml/releases + +## Using Serde YAML + +[API documentation is available in rustdoc form][docs.rs] but the general idea +is: + +[docs.rs]: https://docs.rs/serde_yaml + +```rust +use std::collections::BTreeMap; + +fn main() -> Result<(), serde_yaml::Error> { + // You have some type. + let mut map = BTreeMap::new(); + map.insert("x".to_string(), 1.0); + map.insert("y".to_string(), 2.0); + + // Serialize it to a YAML string. + // y is quoted to avoid ambiguity in parsers that might read it as `true`. + let yaml = serde_yaml::to_string(&map)?; + assert_eq!(yaml, "x: 1.0\n'y': 2.0\n"); + + // Deserialize it back to a Rust type. + let deserialized_map: BTreeMap = serde_yaml::from_str(&yaml)?; + assert_eq!(map, deserialized_map); + Ok(()) +} +``` + +It can also be used with Serde's derive macros to handle structs and enums +defined in your program. + +```toml +[dependencies] +serde = { version = "1.0", features = ["derive"] } +serde_yaml = "0.9" +``` + +Structs serialize in the obvious way: + +```rust +use serde::{Serialize, Deserialize}; + +#[derive(Debug, PartialEq, Serialize, Deserialize)] +struct Point { + x: f64, + y: f64, +} + +fn main() -> Result<(), serde_yaml::Error> { + let point = Point { x: 1.0, y: 2.0 }; + + let yaml = serde_yaml::to_string(&point)?; + assert_eq!(yaml, "x: 1.0\n'y': 2.0\n"); + + let deserialized_point: Point = serde_yaml::from_str(&yaml)?; + assert_eq!(point, deserialized_point); + Ok(()) +} +``` + +Enums serialize using YAML's `!tag` syntax to identify the variant name. + +```rust +use serde::{Serialize, Deserialize}; + +#[derive(Serialize, Deserialize, PartialEq, Debug)] +enum Enum { + Unit, + Newtype(usize), + Tuple(usize, usize, usize), + Struct { x: f64, y: f64 }, +} + +fn main() -> Result<(), serde_yaml::Error> { + let yaml = " + - !Newtype 1 + - !Tuple [0, 0, 0] + - !Struct {x: 1.0, y: 2.0} + "; + let values: Vec = serde_yaml::from_str(yaml).unwrap(); + assert_eq!(values[0], Enum::Newtype(1)); + assert_eq!(values[1], Enum::Tuple(0, 0, 0)); + assert_eq!(values[2], Enum::Struct { x: 1.0, y: 2.0 }); + + // The last two in YAML's block style instead: + let yaml = " + - !Tuple + - 0 + - 0 + - 0 + - !Struct + x: 1.0 + y: 2.0 + "; + let values: Vec = serde_yaml::from_str(yaml).unwrap(); + assert_eq!(values[0], Enum::Tuple(0, 0, 0)); + assert_eq!(values[1], Enum::Struct { x: 1.0, y: 2.0 }); + + // Variants with no data can be written using !Tag or just the string name. + let yaml = " + - Unit # serialization produces this one + - !Unit + "; + let values: Vec = serde_yaml::from_str(yaml).unwrap(); + assert_eq!(values[0], Enum::Unit); + assert_eq!(values[1], Enum::Unit); + + Ok(()) +} +``` + +
+ +#### License + + +Licensed under either of
Apache License, Version +2.0 or MIT license at your option. + + +
+ + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in this crate by you, as defined in the Apache-2.0 license, shall +be dual licensed as above, without any additional terms or conditions. + diff --git a/kclvm/third-party/serde_yaml/src/de.rs b/kclvm/third-party/serde_yaml/src/de.rs new file mode 100644 index 000000000..640e8795e --- /dev/null +++ b/kclvm/third-party/serde_yaml/src/de.rs @@ -0,0 +1,1876 @@ +use crate::error::{self, Error, ErrorImpl}; +use crate::libyaml::error::Mark; +use crate::libyaml::parser::{MappingStart, Scalar, ScalarStyle, SequenceStart}; +use crate::libyaml::tag::Tag; +use crate::loader::{Document, Loader}; +use crate::path::Path; +use serde::de::value::StrDeserializer; +use serde::de::{ + self, Deserialize, DeserializeOwned, DeserializeSeed, Expected, IgnoredAny, Unexpected, Visitor, +}; +use std::fmt; +use std::io; +use std::mem; +use std::num::ParseIntError; +use std::str; +use std::sync::Arc; + +type Result = std::result::Result; + +/// A structure that deserializes YAML into Rust values. +/// +/// # Examples +/// +/// Deserializing a single document: +/// +/// ``` +/// use anyhow::Result; +/// use serde::Deserialize; +/// use serde_yaml::Value; +/// +/// fn main() -> Result<()> { +/// let input = "k: 107\n"; +/// let de = serde_yaml::Deserializer::from_str(input); +/// let value = Value::deserialize(de)?; +/// println!("{:?}", value); +/// Ok(()) +/// } +/// ``` +/// +/// Deserializing multi-doc YAML: +/// +/// ``` +/// use anyhow::Result; +/// use serde::Deserialize; +/// use serde_yaml::Value; +/// +/// fn main() -> Result<()> { +/// let input = "---\nk: 107\n...\n---\nj: 106\n"; +/// +/// for document in serde_yaml::Deserializer::from_str(input) { +/// let value = Value::deserialize(document)?; +/// println!("{:?}", value); +/// } +/// +/// Ok(()) +/// } +/// ``` +pub struct Deserializer<'de> { + progress: Progress<'de>, +} + +pub(crate) enum Progress<'de> { + Str(&'de str), + Slice(&'de [u8]), + Read(Box), + Iterable(Loader<'de>), + Document(Document<'de>), + Fail(Arc), +} + +impl<'de> Deserializer<'de> { + /// Creates a YAML deserializer from a `&str`. + pub fn from_str(s: &'de str) -> Self { + let progress = Progress::Str(s); + Deserializer { progress } + } + + /// Creates a YAML deserializer from a `&[u8]`. + pub fn from_slice(v: &'de [u8]) -> Self { + let progress = Progress::Slice(v); + Deserializer { progress } + } + + /// Creates a YAML deserializer from an `io::Read`. + /// + /// Reader-based deserializers do not support deserializing borrowed types + /// like `&str`, since the `std::io::Read` trait has no non-copying methods + /// -- everything it does involves copying bytes out of the data source. + pub fn from_reader(rdr: R) -> Self + where + R: io::Read + 'de, + { + let progress = Progress::Read(Box::new(rdr)); + Deserializer { progress } + } + + fn de( + self, + f: impl for<'document> FnOnce(&mut DeserializerFromEvents<'de, 'document>) -> Result, + ) -> Result { + let mut pos = 0; + let mut jumpcount = 0; + + match self.progress { + Progress::Iterable(_) => return Err(error::new(ErrorImpl::MoreThanOneDocument)), + Progress::Document(document) => { + let t = f(&mut DeserializerFromEvents { + document: &document, + pos: &mut pos, + jumpcount: &mut jumpcount, + path: Path::Root, + remaining_depth: 128, + current_enum: None, + })?; + if let Some(parse_error) = document.error { + return Err(error::shared(parse_error)); + } + return Ok(t); + } + _ => {} + } + + let mut loader = Loader::new(self.progress)?; + let document = match loader.next_document() { + Some(document) => document, + None => return Err(error::new(ErrorImpl::EndOfStream)), + }; + let t = f(&mut DeserializerFromEvents { + document: &document, + pos: &mut pos, + jumpcount: &mut jumpcount, + path: Path::Root, + remaining_depth: 128, + current_enum: None, + })?; + if let Some(parse_error) = document.error { + return Err(error::shared(parse_error)); + } + if loader.next_document().is_none() { + Ok(t) + } else { + Err(error::new(ErrorImpl::MoreThanOneDocument)) + } + } +} + +impl<'de> Iterator for Deserializer<'de> { + type Item = Self; + + fn next(&mut self) -> Option { + match &mut self.progress { + Progress::Iterable(loader) => { + let document = loader.next_document()?; + return Some(Deserializer { + progress: Progress::Document(document), + }); + } + Progress::Document(_) => return None, + Progress::Fail(err) => { + return Some(Deserializer { + progress: Progress::Fail(Arc::clone(err)), + }); + } + _ => {} + } + + let dummy = Progress::Str(""); + let input = mem::replace(&mut self.progress, dummy); + match Loader::new(input) { + Ok(loader) => { + self.progress = Progress::Iterable(loader); + self.next() + } + Err(err) => { + let fail = err.shared(); + self.progress = Progress::Fail(Arc::clone(&fail)); + Some(Deserializer { + progress: Progress::Fail(fail), + }) + } + } + } +} + +impl<'de> de::Deserializer<'de> for Deserializer<'de> { + type Error = Error; + + fn deserialize_any(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.de(|state| state.deserialize_any(visitor)) + } + + fn deserialize_bool(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.de(|state| state.deserialize_bool(visitor)) + } + + fn deserialize_i8(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.de(|state| state.deserialize_i8(visitor)) + } + + fn deserialize_i16(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.de(|state| state.deserialize_i16(visitor)) + } + + fn deserialize_i32(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.de(|state| state.deserialize_i32(visitor)) + } + + fn deserialize_i64(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.de(|state| state.deserialize_i64(visitor)) + } + + fn deserialize_i128(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.de(|state| state.deserialize_i128(visitor)) + } + + fn deserialize_u8(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.de(|state| state.deserialize_u8(visitor)) + } + + fn deserialize_u16(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.de(|state| state.deserialize_u16(visitor)) + } + + fn deserialize_u32(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.de(|state| state.deserialize_u32(visitor)) + } + + fn deserialize_u64(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.de(|state| state.deserialize_u64(visitor)) + } + + fn deserialize_u128(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.de(|state| state.deserialize_u128(visitor)) + } + + fn deserialize_f32(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.de(|state| state.deserialize_f32(visitor)) + } + + fn deserialize_f64(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.de(|state| state.deserialize_f64(visitor)) + } + + fn deserialize_char(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.de(|state| state.deserialize_char(visitor)) + } + + fn deserialize_str(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.de(|state| state.deserialize_str(visitor)) + } + + fn deserialize_string(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.de(|state| state.deserialize_string(visitor)) + } + + fn deserialize_bytes(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.de(|state| state.deserialize_bytes(visitor)) + } + + fn deserialize_byte_buf(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.de(|state| state.deserialize_byte_buf(visitor)) + } + + fn deserialize_option(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.de(|state| state.deserialize_option(visitor)) + } + + fn deserialize_unit(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.de(|state| state.deserialize_unit(visitor)) + } + + fn deserialize_unit_struct(self, name: &'static str, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.de(|state| state.deserialize_unit_struct(name, visitor)) + } + + fn deserialize_newtype_struct(self, name: &'static str, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.de(|state| state.deserialize_newtype_struct(name, visitor)) + } + + fn deserialize_seq(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.de(|state| state.deserialize_seq(visitor)) + } + + fn deserialize_tuple(self, len: usize, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.de(|state| state.deserialize_tuple(len, visitor)) + } + + fn deserialize_tuple_struct( + self, + name: &'static str, + len: usize, + visitor: V, + ) -> Result + where + V: Visitor<'de>, + { + self.de(|state| state.deserialize_tuple_struct(name, len, visitor)) + } + + fn deserialize_map(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.de(|state| state.deserialize_map(visitor)) + } + + fn deserialize_struct( + self, + name: &'static str, + fields: &'static [&'static str], + visitor: V, + ) -> Result + where + V: Visitor<'de>, + { + self.de(|state| state.deserialize_struct(name, fields, visitor)) + } + + fn deserialize_enum( + self, + name: &'static str, + variants: &'static [&'static str], + visitor: V, + ) -> Result + where + V: Visitor<'de>, + { + self.de(|state| state.deserialize_enum(name, variants, visitor)) + } + + fn deserialize_identifier(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.de(|state| state.deserialize_identifier(visitor)) + } + + fn deserialize_ignored_any(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.de(|state| state.deserialize_ignored_any(visitor)) + } +} + +#[derive(Debug)] +pub(crate) enum Event<'de> { + Alias(usize), + Scalar(Scalar<'de>), + SequenceStart(SequenceStart), + SequenceEnd, + MappingStart(MappingStart), + MappingEnd, + Void, +} + +struct DeserializerFromEvents<'de, 'document> { + document: &'document Document<'de>, + pos: &'document mut usize, + jumpcount: &'document mut usize, + path: Path<'document>, + remaining_depth: u8, + current_enum: Option>, +} + +#[derive(Copy, Clone)] +struct CurrentEnum<'document> { + name: Option<&'static str>, + tag: &'document str, +} + +impl<'de, 'document> DeserializerFromEvents<'de, 'document> { + fn peek_event(&self) -> Result<&'document Event<'de>> { + self.peek_event_mark().map(|(event, _mark)| event) + } + + fn peek_event_mark(&self) -> Result<(&'document Event<'de>, Mark)> { + match self.document.events.get(*self.pos) { + Some((event, mark)) => Ok((event, *mark)), + None => Err(match &self.document.error { + Some(parse_error) => error::shared(Arc::clone(parse_error)), + None => error::new(ErrorImpl::EndOfStream), + }), + } + } + + fn next_event(&mut self) -> Result<&'document Event<'de>> { + self.next_event_mark().map(|(event, _mark)| event) + } + + fn next_event_mark(&mut self) -> Result<(&'document Event<'de>, Mark)> { + self.peek_event_mark().map(|(event, mark)| { + *self.pos += 1; + self.current_enum = None; + (event, mark) + }) + } + + fn jump<'anchor>( + &'anchor mut self, + pos: &'anchor mut usize, + ) -> Result> { + *self.jumpcount += 1; + if *self.jumpcount > self.document.events.len() * 100 { + return Err(error::new(ErrorImpl::RepetitionLimitExceeded)); + } + match self.document.aliases.get(pos) { + Some(found) => { + *pos = *found; + Ok(DeserializerFromEvents { + document: self.document, + pos, + jumpcount: self.jumpcount, + path: Path::Alias { parent: &self.path }, + remaining_depth: self.remaining_depth, + current_enum: None, + }) + } + None => panic!("unresolved alias: {}", *pos), + } + } + + fn ignore_any(&mut self) -> Result<()> { + enum Nest { + Sequence, + Mapping, + } + + let mut stack = Vec::new(); + + loop { + match self.next_event()? { + Event::Alias(_) | Event::Scalar(_) | Event::Void => {} + Event::SequenceStart(_) => { + stack.push(Nest::Sequence); + } + Event::MappingStart(_) => { + stack.push(Nest::Mapping); + } + Event::SequenceEnd => match stack.pop() { + Some(Nest::Sequence) => {} + None | Some(Nest::Mapping) => { + panic!("unexpected end of sequence"); + } + }, + Event::MappingEnd => match stack.pop() { + Some(Nest::Mapping) => {} + None | Some(Nest::Sequence) => { + panic!("unexpected end of mapping"); + } + }, + } + if stack.is_empty() { + return Ok(()); + } + } + } + + fn visit_sequence(&mut self, visitor: V, mark: Mark) -> Result + where + V: Visitor<'de>, + { + let (value, len) = self.recursion_check(mark, |de| { + let mut seq = SeqAccess { + empty: false, + de, + len: 0, + }; + let value = visitor.visit_seq(&mut seq)?; + Ok((value, seq.len)) + })?; + self.end_sequence(len)?; + Ok(value) + } + + fn visit_mapping(&mut self, visitor: V, mark: Mark) -> Result + where + V: Visitor<'de>, + { + let (value, len) = self.recursion_check(mark, |de| { + let mut map = MapAccess { + empty: false, + de, + len: 0, + key: None, + }; + let value = visitor.visit_map(&mut map)?; + Ok((value, map.len)) + })?; + self.end_mapping(len)?; + Ok(value) + } + + fn end_sequence(&mut self, len: usize) -> Result<()> { + let total = { + let mut seq = SeqAccess { + empty: false, + de: self, + len, + }; + while de::SeqAccess::next_element::(&mut seq)?.is_some() {} + seq.len + }; + match self.next_event()? { + Event::SequenceEnd | Event::Void => {} + _ => panic!("expected a SequenceEnd event"), + } + if total == len { + Ok(()) + } else { + struct ExpectedSeq(usize); + impl Expected for ExpectedSeq { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + if self.0 == 1 { + write!(formatter, "sequence of 1 element") + } else { + write!(formatter, "sequence of {} elements", self.0) + } + } + } + Err(de::Error::invalid_length(total, &ExpectedSeq(len))) + } + } + + fn end_mapping(&mut self, len: usize) -> Result<()> { + let total = { + let mut map = MapAccess { + empty: false, + de: self, + len, + key: None, + }; + while de::MapAccess::next_entry::(&mut map)?.is_some() {} + map.len + }; + match self.next_event()? { + Event::MappingEnd | Event::Void => {} + _ => panic!("expected a MappingEnd event"), + } + if total == len { + Ok(()) + } else { + struct ExpectedMap(usize); + impl Expected for ExpectedMap { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + if self.0 == 1 { + write!(formatter, "map containing 1 entry") + } else { + write!(formatter, "map containing {} entries", self.0) + } + } + } + Err(de::Error::invalid_length(total, &ExpectedMap(len))) + } + } + + fn recursion_check Result, T>( + &mut self, + mark: Mark, + f: F, + ) -> Result { + let previous_depth = self.remaining_depth; + self.remaining_depth = match previous_depth.checked_sub(1) { + Some(depth) => depth, + None => return Err(error::new(ErrorImpl::RecursionLimitExceeded(mark))), + }; + let result = f(self); + self.remaining_depth = previous_depth; + result + } +} + +struct SeqAccess<'de, 'document, 'seq> { + empty: bool, + de: &'seq mut DeserializerFromEvents<'de, 'document>, + len: usize, +} + +impl<'de, 'document, 'seq> de::SeqAccess<'de> for SeqAccess<'de, 'document, 'seq> { + type Error = Error; + + fn next_element_seed(&mut self, seed: T) -> Result> + where + T: DeserializeSeed<'de>, + { + if self.empty { + return Ok(None); + } + match self.de.peek_event()? { + Event::SequenceEnd | Event::Void => Ok(None), + _ => { + let mut element_de = DeserializerFromEvents { + document: self.de.document, + pos: self.de.pos, + jumpcount: self.de.jumpcount, + path: Path::Seq { + parent: &self.de.path, + index: self.len, + }, + remaining_depth: self.de.remaining_depth, + current_enum: None, + }; + self.len += 1; + seed.deserialize(&mut element_de).map(Some) + } + } + } +} + +struct MapAccess<'de, 'document, 'map> { + empty: bool, + de: &'map mut DeserializerFromEvents<'de, 'document>, + len: usize, + key: Option<&'document [u8]>, +} + +impl<'de, 'document, 'map> de::MapAccess<'de> for MapAccess<'de, 'document, 'map> { + type Error = Error; + + fn next_key_seed(&mut self, seed: K) -> Result> + where + K: DeserializeSeed<'de>, + { + if self.empty { + return Ok(None); + } + match self.de.peek_event()? { + Event::MappingEnd | Event::Void => Ok(None), + Event::Scalar(scalar) => { + self.len += 1; + self.key = Some(&scalar.value); + seed.deserialize(&mut *self.de).map(Some) + } + _ => { + self.len += 1; + self.key = None; + seed.deserialize(&mut *self.de).map(Some) + } + } + } + + fn next_value_seed(&mut self, seed: V) -> Result + where + V: DeserializeSeed<'de>, + { + let mut value_de = DeserializerFromEvents { + document: self.de.document, + pos: self.de.pos, + jumpcount: self.de.jumpcount, + path: if let Some(key) = self.key.and_then(|key| str::from_utf8(key).ok()) { + Path::Map { + parent: &self.de.path, + key, + } + } else { + Path::Unknown { + parent: &self.de.path, + } + }, + remaining_depth: self.de.remaining_depth, + current_enum: None, + }; + seed.deserialize(&mut value_de) + } +} + +struct EnumAccess<'de, 'document, 'variant> { + de: &'variant mut DeserializerFromEvents<'de, 'document>, + name: Option<&'static str>, + tag: &'document str, +} + +impl<'de, 'document, 'variant> de::EnumAccess<'de> for EnumAccess<'de, 'document, 'variant> { + type Error = Error; + type Variant = DeserializerFromEvents<'de, 'variant>; + + fn variant_seed(self, seed: V) -> Result<(V::Value, Self::Variant)> + where + V: DeserializeSeed<'de>, + { + let str_de = StrDeserializer::::new(self.tag); + let variant = seed.deserialize(str_de)?; + let visitor = DeserializerFromEvents { + document: self.de.document, + pos: self.de.pos, + jumpcount: self.de.jumpcount, + path: self.de.path, + remaining_depth: self.de.remaining_depth, + current_enum: Some(CurrentEnum { + name: self.name, + tag: self.tag, + }), + }; + Ok((variant, visitor)) + } +} + +impl<'de, 'document> de::VariantAccess<'de> for DeserializerFromEvents<'de, 'document> { + type Error = Error; + + fn unit_variant(mut self) -> Result<()> { + Deserialize::deserialize(&mut self) + } + + fn newtype_variant_seed(mut self, seed: T) -> Result + where + T: DeserializeSeed<'de>, + { + seed.deserialize(&mut self) + } + + fn tuple_variant(mut self, _len: usize, visitor: V) -> Result + where + V: Visitor<'de>, + { + de::Deserializer::deserialize_seq(&mut self, visitor) + } + + fn struct_variant(mut self, fields: &'static [&'static str], visitor: V) -> Result + where + V: Visitor<'de>, + { + de::Deserializer::deserialize_struct(&mut self, "", fields, visitor) + } +} + +struct UnitVariantAccess<'de, 'document, 'variant> { + de: &'variant mut DeserializerFromEvents<'de, 'document>, +} + +impl<'de, 'document, 'variant> de::EnumAccess<'de> for UnitVariantAccess<'de, 'document, 'variant> { + type Error = Error; + type Variant = Self; + + fn variant_seed(self, seed: V) -> Result<(V::Value, Self::Variant)> + where + V: DeserializeSeed<'de>, + { + Ok((seed.deserialize(&mut *self.de)?, self)) + } +} + +impl<'de, 'document, 'variant> de::VariantAccess<'de> + for UnitVariantAccess<'de, 'document, 'variant> +{ + type Error = Error; + + fn unit_variant(self) -> Result<()> { + Ok(()) + } + + fn newtype_variant_seed(self, _seed: T) -> Result + where + T: DeserializeSeed<'de>, + { + Err(de::Error::invalid_type( + Unexpected::UnitVariant, + &"newtype variant", + )) + } + + fn tuple_variant(self, _len: usize, _visitor: V) -> Result + where + V: Visitor<'de>, + { + Err(de::Error::invalid_type( + Unexpected::UnitVariant, + &"tuple variant", + )) + } + + fn struct_variant(self, _fields: &'static [&'static str], _visitor: V) -> Result + where + V: Visitor<'de>, + { + Err(de::Error::invalid_type( + Unexpected::UnitVariant, + &"struct variant", + )) + } +} + +fn visit_scalar<'de, V>(visitor: V, scalar: &Scalar<'de>, tagged_already: bool) -> Result +where + V: Visitor<'de>, +{ + let v = match str::from_utf8(&scalar.value) { + Ok(v) => v, + Err(_) => { + return Err(de::Error::invalid_type( + Unexpected::Bytes(&scalar.value), + &visitor, + )) + } + }; + if let (Some(tag), false) = (&scalar.tag, tagged_already) { + if tag == Tag::BOOL { + return match parse_bool(v) { + Some(v) => visitor.visit_bool(v), + None => Err(de::Error::invalid_value(Unexpected::Str(v), &"a boolean")), + }; + } else if tag == Tag::INT { + return match visit_int(visitor, v) { + Ok(result) => result, + Err(_) => Err(de::Error::invalid_value(Unexpected::Str(v), &"an integer")), + }; + } else if tag == Tag::FLOAT { + return match parse_f64(v) { + Some(v) => visitor.visit_f64(v), + None => Err(de::Error::invalid_value(Unexpected::Str(v), &"a float")), + }; + } else if tag == Tag::NULL { + return match parse_null(v.as_bytes()) { + Some(()) => visitor.visit_unit(), + None => Err(de::Error::invalid_value(Unexpected::Str(v), &"null")), + }; + } else if tag.starts_with("!") && scalar.style == ScalarStyle::Plain { + return visit_untagged_scalar(visitor, v, scalar.repr, scalar.style); + } + } else if scalar.style == ScalarStyle::Plain { + return visit_untagged_scalar(visitor, v, scalar.repr, scalar.style); + } + if let Some(borrowed) = parse_borrowed_str(v, scalar.repr, scalar.style) { + visitor.visit_borrowed_str(borrowed) + } else { + visitor.visit_str(v) + } +} + +fn parse_borrowed_str<'de>( + utf8_value: &str, + repr: Option<&'de [u8]>, + style: ScalarStyle, +) -> Option<&'de str> { + let borrowed_repr = repr?; + let expected_offset = match style { + ScalarStyle::Plain => 0, + ScalarStyle::SingleQuoted | ScalarStyle::DoubleQuoted => 1, + ScalarStyle::Literal | ScalarStyle::Folded => return None, + }; + let expected_end = borrowed_repr.len().checked_sub(expected_offset)?; + let expected_start = expected_end.checked_sub(utf8_value.len())?; + let borrowed_bytes = borrowed_repr.get(expected_start..expected_end)?; + if borrowed_bytes == utf8_value.as_bytes() { + return Some(unsafe { str::from_utf8_unchecked(borrowed_bytes) }); + } + None +} + +fn parse_null(scalar: &[u8]) -> Option<()> { + match scalar { + b"null" | b"Null" | b"NULL" | b"~" => Some(()), + _ => None, + } +} + +fn parse_bool(scalar: &str) -> Option { + match scalar { + "true" | "True" | "TRUE" => Some(true), + "false" | "False" | "FALSE" => Some(false), + _ => None, + } +} + +fn parse_unsigned_int( + scalar: &str, + from_str_radix: fn(&str, radix: u32) -> Result, +) -> Option { + let unpositive = scalar.strip_prefix('+').unwrap_or(scalar); + if let Some(rest) = unpositive.strip_prefix("0x") { + if rest.starts_with(['+', '-']) { + return None; + } + if let Ok(int) = from_str_radix(rest, 16) { + return Some(int); + } + } + if let Some(rest) = unpositive.strip_prefix("0o") { + if rest.starts_with(['+', '-']) { + return None; + } + if let Ok(int) = from_str_radix(rest, 8) { + return Some(int); + } + } + if let Some(rest) = unpositive.strip_prefix("0b") { + if rest.starts_with(['+', '-']) { + return None; + } + if let Ok(int) = from_str_radix(rest, 2) { + return Some(int); + } + } + if unpositive.starts_with(['+', '-']) { + return None; + } + if digits_but_not_number(scalar) { + return None; + } + from_str_radix(unpositive, 10).ok() +} + +fn parse_signed_int( + scalar: &str, + from_str_radix: fn(&str, radix: u32) -> Result, +) -> Option { + let unpositive = if let Some(unpositive) = scalar.strip_prefix('+') { + if unpositive.starts_with(['+', '-']) { + return None; + } + unpositive + } else { + scalar + }; + if let Some(rest) = unpositive.strip_prefix("0x") { + if rest.starts_with(['+', '-']) { + return None; + } + if let Ok(int) = from_str_radix(rest, 16) { + return Some(int); + } + } + if let Some(rest) = scalar.strip_prefix("-0x") { + let negative = format!("-{}", rest); + if let Ok(int) = from_str_radix(&negative, 16) { + return Some(int); + } + } + if let Some(rest) = unpositive.strip_prefix("0o") { + if rest.starts_with(['+', '-']) { + return None; + } + if let Ok(int) = from_str_radix(rest, 8) { + return Some(int); + } + } + if let Some(rest) = scalar.strip_prefix("-0o") { + let negative = format!("-{}", rest); + if let Ok(int) = from_str_radix(&negative, 8) { + return Some(int); + } + } + if let Some(rest) = unpositive.strip_prefix("0b") { + if rest.starts_with(['+', '-']) { + return None; + } + if let Ok(int) = from_str_radix(rest, 2) { + return Some(int); + } + } + if let Some(rest) = scalar.strip_prefix("-0b") { + let negative = format!("-{}", rest); + if let Ok(int) = from_str_radix(&negative, 2) { + return Some(int); + } + } + if digits_but_not_number(scalar) { + return None; + } + from_str_radix(unpositive, 10).ok() +} + +fn parse_negative_int( + scalar: &str, + from_str_radix: fn(&str, radix: u32) -> Result, +) -> Option { + if let Some(rest) = scalar.strip_prefix("-0x") { + let negative = format!("-{}", rest); + if let Ok(int) = from_str_radix(&negative, 16) { + return Some(int); + } + } + if let Some(rest) = scalar.strip_prefix("-0o") { + let negative = format!("-{}", rest); + if let Ok(int) = from_str_radix(&negative, 8) { + return Some(int); + } + } + if let Some(rest) = scalar.strip_prefix("-0b") { + let negative = format!("-{}", rest); + if let Ok(int) = from_str_radix(&negative, 2) { + return Some(int); + } + } + if digits_but_not_number(scalar) { + return None; + } + from_str_radix(scalar, 10).ok() +} + +pub(crate) fn parse_f64(scalar: &str) -> Option { + let unpositive = if let Some(unpositive) = scalar.strip_prefix('+') { + if unpositive.starts_with(['+', '-']) { + return None; + } + unpositive + } else { + scalar + }; + if let ".inf" | ".Inf" | ".INF" = unpositive { + return Some(f64::INFINITY); + } + if let "-.inf" | "-.Inf" | "-.INF" = scalar { + return Some(f64::NEG_INFINITY); + } + if let ".nan" | ".NaN" | ".NAN" = scalar { + return Some(f64::NAN.copysign(1.0)); + } + if let Ok(float) = unpositive.parse::() { + if float.is_finite() { + return Some(float); + } + } + None +} + +pub(crate) fn digits_but_not_number(scalar: &str) -> bool { + // Leading zero(s) followed by numeric characters is a string according to + // the YAML 1.2 spec. https://yaml.org/spec/1.2/spec.html#id2761292 + let scalar = scalar.strip_prefix(['-', '+']).unwrap_or(scalar); + scalar.len() > 1 && scalar.starts_with('0') && scalar[1..].bytes().all(|b| b.is_ascii_digit()) +} + +/// If a string looks like it could be parsed as some other type by some YAML +/// parser on the round trip, or could otherwise be ambiguous, then we should +/// serialize it with quotes to be safe. +/// This avoids the norway problem https://hitchdev.com/strictyaml/why/implicit-typing-removed/ +pub(crate) fn ambiguous_string(scalar: &str) -> bool { + let lower_scalar = scalar.to_lowercase(); + parse_bool(&lower_scalar).is_some() + || parse_null(&lower_scalar.as_bytes()).is_some() + || lower_scalar.len() == 0 + // Can unwrap because we just checked the length. + || lower_scalar.bytes().nth(0).unwrap().is_ascii_digit() + || lower_scalar.starts_with('-') + || lower_scalar.starts_with('.') + || lower_scalar.starts_with("+") + // Things that we don't parse as bool but could be parsed as bool by + // other YAML parsers. + || lower_scalar == "y" + || lower_scalar == "yes" + || lower_scalar == "n" + || lower_scalar == "no" + || lower_scalar == "on" + || lower_scalar == "off" + || lower_scalar == "true" + || lower_scalar == "false" + || lower_scalar == "null" + || lower_scalar == "nil" + || lower_scalar == "~" + || lower_scalar == "nan" +} + +pub(crate) fn visit_int<'de, V>(visitor: V, v: &str) -> Result, V> +where + V: Visitor<'de>, +{ + if let Some(int) = parse_unsigned_int(v, u64::from_str_radix) { + return Ok(visitor.visit_u64(int)); + } + if let Some(int) = parse_negative_int(v, i64::from_str_radix) { + return Ok(visitor.visit_i64(int)); + } + if let Some(int) = parse_unsigned_int(v, u128::from_str_radix) { + return Ok(visitor.visit_u128(int)); + } + if let Some(int) = parse_negative_int(v, i128::from_str_radix) { + return Ok(visitor.visit_i128(int)); + } + Err(visitor) +} + +pub(crate) fn visit_untagged_scalar<'de, V>( + visitor: V, + v: &str, + repr: Option<&'de [u8]>, + style: ScalarStyle, +) -> Result +where + V: Visitor<'de>, +{ + if v.is_empty() || parse_null(v.as_bytes()) == Some(()) { + return visitor.visit_unit(); + } + if let Some(boolean) = parse_bool(v) { + return visitor.visit_bool(boolean); + } + let visitor = match visit_int(visitor, v) { + Ok(result) => return result, + Err(visitor) => visitor, + }; + if !digits_but_not_number(v) { + if let Some(float) = parse_f64(v) { + return visitor.visit_f64(float); + } + } + if let Some(borrowed) = parse_borrowed_str(v, repr, style) { + visitor.visit_borrowed_str(borrowed) + } else { + visitor.visit_str(v) + } +} + +fn is_plain_or_tagged_literal_scalar( + expected: &str, + scalar: &Scalar, + tagged_already: bool, +) -> bool { + match (scalar.style, &scalar.tag, tagged_already) { + (ScalarStyle::Plain, _, _) => true, + (ScalarStyle::Literal, Some(tag), false) => tag == expected, + _ => false, + } +} + +fn invalid_type(event: &Event, exp: &dyn Expected) -> Error { + enum Void {} + + struct InvalidType<'a> { + exp: &'a dyn Expected, + } + + impl<'de, 'a> Visitor<'de> for InvalidType<'a> { + type Value = Void; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + self.exp.fmt(formatter) + } + } + + match event { + Event::Alias(_) => unreachable!(), + Event::Scalar(scalar) => { + let get_type = InvalidType { exp }; + match visit_scalar(get_type, scalar, false) { + Ok(void) => match void {}, + Err(invalid_type) => invalid_type, + } + } + Event::SequenceStart(_) => de::Error::invalid_type(Unexpected::Seq, exp), + Event::MappingStart(_) => de::Error::invalid_type(Unexpected::Map, exp), + Event::SequenceEnd => panic!("unexpected end of sequence"), + Event::MappingEnd => panic!("unexpected end of mapping"), + Event::Void => error::new(ErrorImpl::EndOfStream), + } +} + +fn parse_tag(libyaml_tag: &Option) -> Option<&str> { + let mut bytes: &[u8] = libyaml_tag.as_ref()?; + if let (b'!', rest) = bytes.split_first()? { + if !rest.is_empty() { + bytes = rest; + } + str::from_utf8(bytes).ok() + } else { + None + } +} + +impl<'de, 'document> de::Deserializer<'de> for &mut DeserializerFromEvents<'de, 'document> { + type Error = Error; + + fn deserialize_any(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + let tagged_already = self.current_enum.is_some(); + let (next, mark) = self.next_event_mark()?; + fn enum_tag(tag: &Option, tagged_already: bool) -> Option<&str> { + if tagged_already { + return None; + } + parse_tag(tag) + } + loop { + match next { + Event::Alias(mut pos) => break self.jump(&mut pos)?.deserialize_any(visitor), + Event::Scalar(scalar) => { + if let Some(tag) = enum_tag(&scalar.tag, tagged_already) { + *self.pos -= 1; + break visitor.visit_enum(EnumAccess { + de: self, + name: None, + tag, + }); + } + break visit_scalar(visitor, scalar, tagged_already); + } + Event::SequenceStart(sequence) => { + if let Some(tag) = enum_tag(&sequence.tag, tagged_already) { + *self.pos -= 1; + break visitor.visit_enum(EnumAccess { + de: self, + name: None, + tag, + }); + } + break self.visit_sequence(visitor, mark); + } + Event::MappingStart(mapping) => { + if let Some(tag) = enum_tag(&mapping.tag, tagged_already) { + *self.pos -= 1; + break visitor.visit_enum(EnumAccess { + de: self, + name: None, + tag, + }); + } + break self.visit_mapping(visitor, mark); + } + Event::SequenceEnd => panic!("unexpected end of sequence"), + Event::MappingEnd => panic!("unexpected end of mapping"), + Event::Void => break visitor.visit_none(), + } + } + // The de::Error impl creates errors with unknown line and column. Fill + // in the position here by looking at the current index in the input. + .map_err(|err| error::fix_mark(err, mark, self.path)) + } + + fn deserialize_bool(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + let tagged_already = self.current_enum.is_some(); + let (next, mark) = self.next_event_mark()?; + loop { + match next { + Event::Alias(mut pos) => break self.jump(&mut pos)?.deserialize_bool(visitor), + Event::Scalar(scalar) + if is_plain_or_tagged_literal_scalar(Tag::BOOL, scalar, tagged_already) => + { + if let Ok(value) = str::from_utf8(&scalar.value) { + if let Some(boolean) = parse_bool(value) { + break visitor.visit_bool(boolean); + } + } + } + _ => {} + } + break Err(invalid_type(next, &visitor)); + } + .map_err(|err| error::fix_mark(err, mark, self.path)) + } + + fn deserialize_i8(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_i64(visitor) + } + + fn deserialize_i16(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_i64(visitor) + } + + fn deserialize_i32(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_i64(visitor) + } + + fn deserialize_i64(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + let tagged_already = self.current_enum.is_some(); + let (next, mark) = self.next_event_mark()?; + loop { + match next { + Event::Alias(mut pos) => break self.jump(&mut pos)?.deserialize_i64(visitor), + Event::Scalar(scalar) + if is_plain_or_tagged_literal_scalar(Tag::INT, scalar, tagged_already) => + { + if let Ok(value) = str::from_utf8(&scalar.value) { + if let Some(int) = parse_signed_int(value, i64::from_str_radix) { + break visitor.visit_i64(int); + } + } + } + _ => {} + } + break Err(invalid_type(next, &visitor)); + } + .map_err(|err| error::fix_mark(err, mark, self.path)) + } + + fn deserialize_i128(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + let tagged_already = self.current_enum.is_some(); + let (next, mark) = self.next_event_mark()?; + loop { + match next { + Event::Alias(mut pos) => break self.jump(&mut pos)?.deserialize_i128(visitor), + Event::Scalar(scalar) + if is_plain_or_tagged_literal_scalar(Tag::INT, scalar, tagged_already) => + { + if let Ok(value) = str::from_utf8(&scalar.value) { + if let Some(int) = parse_signed_int(value, i128::from_str_radix) { + break visitor.visit_i128(int); + } + } + } + _ => {} + } + break Err(invalid_type(next, &visitor)); + } + .map_err(|err| error::fix_mark(err, mark, self.path)) + } + + fn deserialize_u8(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_u64(visitor) + } + + fn deserialize_u16(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_u64(visitor) + } + + fn deserialize_u32(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_u64(visitor) + } + + fn deserialize_u64(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + let tagged_already = self.current_enum.is_some(); + let (next, mark) = self.next_event_mark()?; + loop { + match next { + Event::Alias(mut pos) => break self.jump(&mut pos)?.deserialize_u64(visitor), + Event::Scalar(scalar) + if is_plain_or_tagged_literal_scalar(Tag::INT, scalar, tagged_already) => + { + if let Ok(value) = str::from_utf8(&scalar.value) { + if let Some(int) = parse_unsigned_int(value, u64::from_str_radix) { + break visitor.visit_u64(int); + } + } + } + _ => {} + } + break Err(invalid_type(next, &visitor)); + } + .map_err(|err| error::fix_mark(err, mark, self.path)) + } + + fn deserialize_u128(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + let tagged_already = self.current_enum.is_some(); + let (next, mark) = self.next_event_mark()?; + loop { + match next { + Event::Alias(mut pos) => break self.jump(&mut pos)?.deserialize_u128(visitor), + Event::Scalar(scalar) + if is_plain_or_tagged_literal_scalar(Tag::INT, scalar, tagged_already) => + { + if let Ok(value) = str::from_utf8(&scalar.value) { + if let Some(int) = parse_unsigned_int(value, u128::from_str_radix) { + break visitor.visit_u128(int); + } + } + } + _ => {} + } + break Err(invalid_type(next, &visitor)); + } + .map_err(|err| error::fix_mark(err, mark, self.path)) + } + + fn deserialize_f32(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_f64(visitor) + } + + fn deserialize_f64(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + let tagged_already = self.current_enum.is_some(); + let (next, mark) = self.next_event_mark()?; + loop { + match next { + Event::Alias(mut pos) => break self.jump(&mut pos)?.deserialize_f64(visitor), + Event::Scalar(scalar) + if is_plain_or_tagged_literal_scalar(Tag::FLOAT, scalar, tagged_already) => + { + if let Ok(value) = str::from_utf8(&scalar.value) { + if let Some(float) = parse_f64(value) { + break visitor.visit_f64(float); + } + } + } + _ => {} + } + break Err(invalid_type(next, &visitor)); + } + .map_err(|err| error::fix_mark(err, mark, self.path)) + } + + fn deserialize_char(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_str(visitor) + } + + fn deserialize_str(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + let (next, mark) = self.next_event_mark()?; + match next { + Event::Scalar(scalar) => { + if let Ok(v) = str::from_utf8(&scalar.value) { + if let Some(borrowed) = parse_borrowed_str(v, scalar.repr, scalar.style) { + visitor.visit_borrowed_str(borrowed) + } else { + visitor.visit_str(v) + } + } else { + Err(invalid_type(next, &visitor)) + } + } + Event::Alias(mut pos) => self.jump(&mut pos)?.deserialize_str(visitor), + other => Err(invalid_type(other, &visitor)), + } + .map_err(|err: Error| error::fix_mark(err, mark, self.path)) + } + + fn deserialize_string(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_str(visitor) + } + + fn deserialize_bytes(self, _visitor: V) -> Result + where + V: Visitor<'de>, + { + Err(error::new(ErrorImpl::BytesUnsupported)) + } + + fn deserialize_byte_buf(self, _visitor: V) -> Result + where + V: Visitor<'de>, + { + Err(error::new(ErrorImpl::BytesUnsupported)) + } + + /// Parses `null` as None and any other values as `Some(...)`. + fn deserialize_option(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + let is_some = match self.peek_event()? { + Event::Alias(mut pos) => { + *self.pos += 1; + return self.jump(&mut pos)?.deserialize_option(visitor); + } + Event::Scalar(scalar) => { + let tagged_already = self.current_enum.is_some(); + if scalar.style != ScalarStyle::Plain { + true + } else if let (Some(tag), false) = (&scalar.tag, tagged_already) { + if tag == Tag::NULL { + if let Some(()) = parse_null(&scalar.value) { + false + } else if let Ok(v) = str::from_utf8(&scalar.value) { + return Err(de::Error::invalid_value(Unexpected::Str(v), &"null")); + } else { + return Err(de::Error::invalid_value( + Unexpected::Bytes(&scalar.value), + &"null", + )); + } + } else { + true + } + } else { + !scalar.value.is_empty() && parse_null(&scalar.value).is_none() + } + } + Event::SequenceStart(_) | Event::MappingStart(_) => true, + Event::SequenceEnd => panic!("unexpected end of sequence"), + Event::MappingEnd => panic!("unexpected end of mapping"), + Event::Void => false, + }; + if is_some { + visitor.visit_some(self) + } else { + *self.pos += 1; + self.current_enum = None; + visitor.visit_none() + } + } + + fn deserialize_unit(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + let tagged_already = self.current_enum.is_some(); + let (next, mark) = self.next_event_mark()?; + match next { + Event::Scalar(scalar) => { + let is_null = if scalar.style != ScalarStyle::Plain { + false + } else if let (Some(tag), false) = (&scalar.tag, tagged_already) { + tag == Tag::NULL && parse_null(&scalar.value).is_some() + } else { + scalar.value.is_empty() || parse_null(&scalar.value).is_some() + }; + if is_null { + visitor.visit_unit() + } else if let Ok(v) = str::from_utf8(&scalar.value) { + Err(de::Error::invalid_value(Unexpected::Str(v), &"null")) + } else { + Err(de::Error::invalid_value( + Unexpected::Bytes(&scalar.value), + &"null", + )) + } + } + Event::Alias(mut pos) => self.jump(&mut pos)?.deserialize_unit(visitor), + Event::Void => visitor.visit_unit(), + other => Err(invalid_type(other, &visitor)), + } + .map_err(|err| error::fix_mark(err, mark, self.path)) + } + + fn deserialize_unit_struct(self, _name: &'static str, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_unit(visitor) + } + + /// Parses a newtype struct as the underlying value. + fn deserialize_newtype_struct(self, _name: &'static str, visitor: V) -> Result + where + V: Visitor<'de>, + { + let (_event, mark) = self.peek_event_mark()?; + self.recursion_check(mark, |de| visitor.visit_newtype_struct(de)) + } + + fn deserialize_seq(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + let (next, mark) = self.next_event_mark()?; + match next { + Event::Alias(mut pos) => self.jump(&mut pos)?.deserialize_seq(visitor), + Event::SequenceStart(_) => self.visit_sequence(visitor, mark), + other => { + if match other { + Event::Void => true, + Event::Scalar(scalar) => { + scalar.value.is_empty() && scalar.style == ScalarStyle::Plain + } + _ => false, + } { + visitor.visit_seq(SeqAccess { + empty: true, + de: self, + len: 0, + }) + } else { + Err(invalid_type(other, &visitor)) + } + } + } + .map_err(|err| error::fix_mark(err, mark, self.path)) + } + + fn deserialize_tuple(self, _len: usize, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_seq(visitor) + } + + fn deserialize_tuple_struct( + self, + _name: &'static str, + _len: usize, + visitor: V, + ) -> Result + where + V: Visitor<'de>, + { + self.deserialize_seq(visitor) + } + + fn deserialize_map(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + let (next, mark) = self.next_event_mark()?; + match next { + Event::Alias(mut pos) => self.jump(&mut pos)?.deserialize_map(visitor), + Event::MappingStart(_) => self.visit_mapping(visitor, mark), + other => { + if match other { + Event::Void => true, + Event::Scalar(scalar) => { + scalar.value.is_empty() && scalar.style == ScalarStyle::Plain + } + _ => false, + } { + visitor.visit_map(MapAccess { + empty: true, + de: self, + len: 0, + key: None, + }) + } else { + Err(invalid_type(other, &visitor)) + } + } + } + .map_err(|err| error::fix_mark(err, mark, self.path)) + } + + fn deserialize_struct( + self, + _name: &'static str, + _fields: &'static [&'static str], + visitor: V, + ) -> Result + where + V: Visitor<'de>, + { + self.deserialize_map(visitor) + } + + /// Parses an enum as a single key:value pair where the key identifies the + /// variant and the value gives the content. A String will also parse correctly + /// to a unit enum value. + fn deserialize_enum( + self, + name: &'static str, + variants: &'static [&'static str], + visitor: V, + ) -> Result + where + V: Visitor<'de>, + { + let (next, mark) = self.peek_event_mark()?; + loop { + if let Some(current_enum) = self.current_enum { + if let Event::Scalar(scalar) = next { + if !scalar.value.is_empty() { + break visitor.visit_enum(UnitVariantAccess { de: self }); + } + } + let message = if let Some(name) = current_enum.name { + format!( + "deserializing nested enum in {}::{} from YAML is not supported yet", + name, current_enum.tag, + ) + } else { + format!( + "deserializing nested enum in !{} from YAML is not supported yet", + current_enum.tag, + ) + }; + break Err(error::new(ErrorImpl::Message(message, None))); + } + break match next { + Event::Alias(mut pos) => { + *self.pos += 1; + self.jump(&mut pos)? + .deserialize_enum(name, variants, visitor) + } + Event::Scalar(scalar) => { + if let Some(tag) = parse_tag(&scalar.tag) { + return visitor.visit_enum(EnumAccess { + de: self, + name: Some(name), + tag, + }); + } + visitor.visit_enum(UnitVariantAccess { de: self }) + } + Event::MappingStart(mapping) => { + if let Some(tag) = parse_tag(&mapping.tag) { + return visitor.visit_enum(EnumAccess { + de: self, + name: Some(name), + tag, + }); + } + let err = + de::Error::invalid_type(Unexpected::Map, &"a YAML tag starting with '!'"); + Err(error::fix_mark(err, mark, self.path)) + } + Event::SequenceStart(sequence) => { + if let Some(tag) = parse_tag(&sequence.tag) { + return visitor.visit_enum(EnumAccess { + de: self, + name: Some(name), + tag, + }); + } + let err = + de::Error::invalid_type(Unexpected::Seq, &"a YAML tag starting with '!'"); + Err(error::fix_mark(err, mark, self.path)) + } + Event::SequenceEnd => panic!("unexpected end of sequence"), + Event::MappingEnd => panic!("unexpected end of mapping"), + Event::Void => Err(error::new(ErrorImpl::EndOfStream)), + }; + } + .map_err(|err| error::fix_mark(err, mark, self.path)) + } + + fn deserialize_identifier(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_str(visitor) + } + + fn deserialize_ignored_any(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.ignore_any()?; + visitor.visit_unit() + } +} + +/// Deserialize an instance of type `T` from a string of YAML text. +/// +/// This conversion can fail if the structure of the Value does not match the +/// structure expected by `T`, for example if `T` is a struct type but the Value +/// contains something other than a YAML map. It can also fail if the structure +/// is correct but `T`'s implementation of `Deserialize` decides that something +/// is wrong with the data, for example required struct fields are missing from +/// the YAML map or some number is too big to fit in the expected primitive +/// type. +pub fn from_str<'de, T>(s: &'de str) -> Result +where + T: Deserialize<'de>, +{ + T::deserialize(Deserializer::from_str(s)) +} + +/// Deserialize an instance of type `T` from an IO stream of YAML. +/// +/// This conversion can fail if the structure of the Value does not match the +/// structure expected by `T`, for example if `T` is a struct type but the Value +/// contains something other than a YAML map. It can also fail if the structure +/// is correct but `T`'s implementation of `Deserialize` decides that something +/// is wrong with the data, for example required struct fields are missing from +/// the YAML map or some number is too big to fit in the expected primitive +/// type. +pub fn from_reader(rdr: R) -> Result +where + R: io::Read, + T: DeserializeOwned, +{ + T::deserialize(Deserializer::from_reader(rdr)) +} + +/// Deserialize an instance of type `T` from bytes of YAML text. +/// +/// This conversion can fail if the structure of the Value does not match the +/// structure expected by `T`, for example if `T` is a struct type but the Value +/// contains something other than a YAML map. It can also fail if the structure +/// is correct but `T`'s implementation of `Deserialize` decides that something +/// is wrong with the data, for example required struct fields are missing from +/// the YAML map or some number is too big to fit in the expected primitive +/// type. +pub fn from_slice<'de, T>(v: &'de [u8]) -> Result +where + T: Deserialize<'de>, +{ + T::deserialize(Deserializer::from_slice(v)) +} diff --git a/kclvm/third-party/serde_yaml/src/error.rs b/kclvm/third-party/serde_yaml/src/error.rs new file mode 100644 index 000000000..01f8ed126 --- /dev/null +++ b/kclvm/third-party/serde_yaml/src/error.rs @@ -0,0 +1,290 @@ +use crate::libyaml::{emitter, error as libyaml}; +use crate::path::Path; +use serde::{de, ser}; +use std::error::Error as StdError; +use std::fmt::{self, Debug, Display}; +use std::io; +use std::result; +use std::string; +use std::sync::Arc; + +/// An error that happened serializing or deserializing YAML data. +pub struct Error(Box); + +/// Alias for a `Result` with the error type `serde_yaml::Error`. +pub type Result = result::Result; + +#[derive(Debug)] +pub(crate) enum ErrorImpl { + Message(String, Option), + + Libyaml(libyaml::Error), + Io(io::Error), + FromUtf8(string::FromUtf8Error), + + EndOfStream, + MoreThanOneDocument, + RecursionLimitExceeded(libyaml::Mark), + RepetitionLimitExceeded, + BytesUnsupported, + UnknownAnchor(libyaml::Mark), + SerializeNestedEnum, + ScalarInMerge, + TaggedInMerge, + ScalarInMergeElement, + SequenceInMergeElement, + EmptyTag, + FailedToParseNumber, + + Shared(Arc), +} + +#[derive(Debug)] +pub(crate) struct Pos { + mark: libyaml::Mark, + path: String, +} + +/// The input location that an error occured. +#[derive(Debug)] +pub struct Location { + index: usize, + line: usize, + column: usize, +} + +impl Location { + /// The byte index of the error + pub fn index(&self) -> usize { + self.index + } + + /// The line of the error + pub fn line(&self) -> usize { + self.line + } + + /// The column of the error + pub fn column(&self) -> usize { + self.column + } + + // This is to keep decoupled with the yaml crate + #[doc(hidden)] + fn from_mark(mark: libyaml::Mark) -> Self { + Location { + index: mark.index() as usize, + // `line` and `column` returned from libyaml are 0-indexed but all error messages add +1 to this value + line: mark.line() as usize + 1, + column: mark.column() as usize + 1, + } + } +} + +impl Error { + /// Returns the Location from the error if one exists. + /// + /// Not all types of errors have a location so this can return `None`. + /// + /// # Examples + /// + /// ``` + /// # use serde_yaml::{Value, Error}; + /// # + /// // The `@` character as the first character makes this invalid yaml + /// let invalid_yaml: Result = serde_yaml::from_str("@invalid_yaml"); + /// + /// let location = invalid_yaml.unwrap_err().location().unwrap(); + /// + /// assert_eq!(location.line(), 1); + /// assert_eq!(location.column(), 1); + /// ``` + pub fn location(&self) -> Option { + self.0.location() + } +} + +pub(crate) fn new(inner: ErrorImpl) -> Error { + Error(Box::new(inner)) +} + +pub(crate) fn shared(shared: Arc) -> Error { + Error(Box::new(ErrorImpl::Shared(shared))) +} + +pub(crate) fn fix_mark(mut error: Error, mark: libyaml::Mark, path: Path) -> Error { + if let ErrorImpl::Message(_, none @ None) = error.0.as_mut() { + *none = Some(Pos { + mark, + path: path.to_string(), + }); + } + error +} + +impl Error { + pub(crate) fn shared(self) -> Arc { + if let ErrorImpl::Shared(err) = *self.0 { + err + } else { + Arc::from(self.0) + } + } +} + +impl From for Error { + fn from(err: libyaml::Error) -> Self { + Error(Box::new(ErrorImpl::Libyaml(err))) + } +} + +impl From for Error { + fn from(err: emitter::Error) -> Self { + match err { + emitter::Error::Libyaml(err) => Self::from(err), + emitter::Error::Io(err) => new(ErrorImpl::Io(err)), + } + } +} + +impl StdError for Error { + fn source(&self) -> Option<&(dyn StdError + 'static)> { + self.0.source() + } +} + +impl Display for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.0.display(f) + } +} + +// Remove two layers of verbosity from the debug representation. Humans often +// end up seeing this representation because it is what unwrap() shows. +impl Debug for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.0.debug(f) + } +} + +impl ser::Error for Error { + fn custom(msg: T) -> Self { + Error(Box::new(ErrorImpl::Message(msg.to_string(), None))) + } +} + +impl de::Error for Error { + fn custom(msg: T) -> Self { + Error(Box::new(ErrorImpl::Message(msg.to_string(), None))) + } +} + +impl ErrorImpl { + fn location(&self) -> Option { + self.mark().map(Location::from_mark) + } + + fn source(&self) -> Option<&(dyn StdError + 'static)> { + match self { + ErrorImpl::Io(err) => err.source(), + ErrorImpl::FromUtf8(err) => err.source(), + ErrorImpl::Shared(err) => err.source(), + _ => None, + } + } + + fn mark(&self) -> Option { + match self { + ErrorImpl::Message(_, Some(Pos { mark, path: _ })) + | ErrorImpl::RecursionLimitExceeded(mark) + | ErrorImpl::UnknownAnchor(mark) => Some(*mark), + ErrorImpl::Libyaml(err) => Some(err.mark()), + ErrorImpl::Shared(err) => err.mark(), + _ => None, + } + } + + fn message_no_mark(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + ErrorImpl::Message(msg, None) => f.write_str(msg), + ErrorImpl::Message(msg, Some(Pos { mark: _, path })) => { + if path != "." { + write!(f, "{}: ", path)?; + } + f.write_str(msg) + } + ErrorImpl::Libyaml(_) => unreachable!(), + ErrorImpl::Io(err) => Display::fmt(err, f), + ErrorImpl::FromUtf8(err) => Display::fmt(err, f), + ErrorImpl::EndOfStream => f.write_str("EOF while parsing a value"), + ErrorImpl::MoreThanOneDocument => f.write_str( + "deserializing from YAML containing more than one document is not supported", + ), + ErrorImpl::RecursionLimitExceeded(_mark) => f.write_str("recursion limit exceeded"), + ErrorImpl::RepetitionLimitExceeded => f.write_str("repetition limit exceeded"), + ErrorImpl::BytesUnsupported => { + f.write_str("serialization and deserialization of bytes in YAML is not implemented") + } + ErrorImpl::UnknownAnchor(_mark) => f.write_str("unknown anchor"), + ErrorImpl::SerializeNestedEnum => { + f.write_str("serializing nested enums in YAML is not supported yet") + } + ErrorImpl::ScalarInMerge => { + f.write_str("expected a mapping or list of mappings for merging, but found scalar") + } + ErrorImpl::TaggedInMerge => f.write_str("unexpected tagged value in merge"), + ErrorImpl::ScalarInMergeElement => { + f.write_str("expected a mapping for merging, but found scalar") + } + ErrorImpl::SequenceInMergeElement => { + f.write_str("expected a mapping for merging, but found sequence") + } + ErrorImpl::EmptyTag => f.write_str("empty YAML tag is not allowed"), + ErrorImpl::FailedToParseNumber => f.write_str("failed to parse YAML number"), + ErrorImpl::Shared(_) => unreachable!(), + } + } + + fn display(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + ErrorImpl::Libyaml(err) => Display::fmt(err, f), + ErrorImpl::Shared(err) => err.display(f), + _ => { + self.message_no_mark(f)?; + if let Some(mark) = self.mark() { + if mark.line() != 0 || mark.column() != 0 { + write!(f, " at {}", mark)?; + } + } + Ok(()) + } + } + } + + fn debug(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + ErrorImpl::Libyaml(err) => Debug::fmt(err, f), + ErrorImpl::Shared(err) => err.debug(f), + _ => { + f.write_str("Error(")?; + struct MessageNoMark<'a>(&'a ErrorImpl); + impl<'a> Display for MessageNoMark<'a> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.0.message_no_mark(f) + } + } + let msg = MessageNoMark(self).to_string(); + Debug::fmt(&msg, f)?; + if let Some(mark) = self.mark() { + write!( + f, + ", line: {}, column: {}", + mark.line() + 1, + mark.column() + 1, + )?; + } + f.write_str(")") + } + } + } +} diff --git a/kclvm/third-party/serde_yaml/src/lib.rs b/kclvm/third-party/serde_yaml/src/lib.rs new file mode 100644 index 000000000..ad773cf85 --- /dev/null +++ b/kclvm/third-party/serde_yaml/src/lib.rs @@ -0,0 +1,194 @@ +//! [![github]](https://github.com/dtolnay/serde-yaml) [![crates-io]](https://crates.io/crates/serde-yaml) [![docs-rs]](https://docs.rs/serde-yaml) +//! +//! [github]: https://img.shields.io/badge/github-8da0cb?style=for-the-badge&labelColor=555555&logo=github +//! [crates-io]: https://img.shields.io/badge/crates.io-fc8d62?style=for-the-badge&labelColor=555555&logo=rust +//! [docs-rs]: https://img.shields.io/badge/docs.rs-66c2a5?style=for-the-badge&labelColor=555555&logo=docs.rs +//! +//!
+//! +//! Rust library for using the [Serde] serialization framework with data in +//! [YAML] file format. _(This project is no longer maintained.)_ +//! +//! [Serde]: https://github.com/serde-rs/serde +//! [YAML]: https://yaml.org/ +//! +//! # Examples +//! +//! ``` +//! use std::collections::BTreeMap; +//! +//! fn main() -> Result<(), serde_yaml::Error> { +//! // You have some type. +//! let mut map = BTreeMap::new(); +//! map.insert("x".to_string(), 1.0); +//! map.insert("y".to_string(), 2.0); +//! +//! // Serialize it to a YAML string. +//! // 'y' is quoted to avoid ambiguity in parsers that might read it as `true`. +//! let yaml = serde_yaml::to_string(&map)?; +//! assert_eq!(yaml, "x: 1.0\n'y': 2.0\n"); +//! +//! // Deserialize it back to a Rust type. +//! let deserialized_map: BTreeMap = serde_yaml::from_str(&yaml)?; +//! assert_eq!(map, deserialized_map); +//! Ok(()) +//! } +//! ``` +//! +//! ## Using Serde derive +//! +//! It can also be used with Serde's derive macros to handle structs and enums +//! defined in your program. +//! +//! Structs serialize in the obvious way: +//! +//! ``` +//! # use serde_derive::{Serialize, Deserialize}; +//! # use serde::Deserialize as _; +//! # use serde::Serialize as _; +//! +//! #[derive(Serialize, Deserialize, PartialEq, Debug)] +//! struct Point { +//! x: f64, +//! y: f64, +//! } +//! +//! fn main() -> Result<(), serde_yaml::Error> { +//! let point = Point { x: 1.0, y: 2.0 }; +//! +//! let yaml = serde_yaml::to_string(&point)?; +//! assert_eq!(yaml, "x: 1.0\n'y': 2.0\n"); +//! +//! let deserialized_point: Point = serde_yaml::from_str(&yaml)?; +//! assert_eq!(point, deserialized_point); +//! Ok(()) +//! } +//! ``` +//! +//! Enums serialize using YAML's `!tag` syntax to identify the variant name. +//! +//! ``` +//! # use serde_derive::{Serialize, Deserialize}; +//! # use serde::Deserialize as _; +//! # use serde::Serialize as _; +//! +//! #[derive(Serialize, Deserialize, PartialEq, Debug)] +//! enum Enum { +//! Unit, +//! Newtype(usize), +//! Tuple(usize, usize, usize), +//! Struct { x: f64, y: f64 }, +//! } +//! +//! fn main() -> Result<(), serde_yaml::Error> { +//! let yaml = " +//! - !Newtype 1 +//! - !Tuple [0, 0, 0] +//! - !Struct {x: 1.0, y: 2.0} +//! "; +//! let values: Vec = serde_yaml::from_str(yaml).unwrap(); +//! assert_eq!(values[0], Enum::Newtype(1)); +//! assert_eq!(values[1], Enum::Tuple(0, 0, 0)); +//! assert_eq!(values[2], Enum::Struct { x: 1.0, y: 2.0 }); +//! +//! // The last two in YAML's block style instead: +//! let yaml = " +//! - !Tuple +//! - 0 +//! - 0 +//! - 0 +//! - !Struct +//! x: 1.0 +//! y: 2.0 +//! "; +//! let values: Vec = serde_yaml::from_str(yaml).unwrap(); +//! assert_eq!(values[0], Enum::Tuple(0, 0, 0)); +//! assert_eq!(values[1], Enum::Struct { x: 1.0, y: 2.0 }); +//! +//! // Variants with no data can be written using !Tag or just the string name. +//! let yaml = " +//! - Unit # serialization produces this one +//! - !Unit +//! "; +//! let values: Vec = serde_yaml::from_str(yaml).unwrap(); +//! assert_eq!(values[0], Enum::Unit); +//! assert_eq!(values[1], Enum::Unit); +//! +//! Ok(()) +//! } +//! ``` + +#![doc(html_root_url = "https://docs.rs/serde_yaml/0.9.34+deprecated")] +#![deny(missing_docs, unsafe_op_in_unsafe_fn)] +// Suppressed clippy_pedantic lints +#![allow( + // buggy + clippy::iter_not_returning_iterator, // https://github.com/rust-lang/rust-clippy/issues/8285 + clippy::ptr_arg, // https://github.com/rust-lang/rust-clippy/issues/9218 + clippy::question_mark, // https://github.com/rust-lang/rust-clippy/issues/7859 + // private Deserializer::next + clippy::should_implement_trait, + // things are often more readable this way + clippy::cast_lossless, + clippy::checked_conversions, + clippy::if_not_else, + clippy::manual_assert, + clippy::match_like_matches_macro, + clippy::match_same_arms, + clippy::module_name_repetitions, + clippy::needless_pass_by_value, + clippy::redundant_else, + clippy::single_match_else, + // code is acceptable + clippy::blocks_in_conditions, + clippy::cast_possible_truncation, + clippy::cast_possible_wrap, + clippy::cast_precision_loss, + clippy::cast_sign_loss, + clippy::derive_partial_eq_without_eq, + clippy::derived_hash_with_manual_eq, + clippy::doc_markdown, + clippy::items_after_statements, + clippy::let_underscore_untyped, + clippy::manual_map, + clippy::missing_panics_doc, + clippy::never_loop, + clippy::return_self_not_must_use, + clippy::too_many_lines, + clippy::uninlined_format_args, + clippy::unsafe_removed_from_name, + clippy::wildcard_in_or_patterns, + // noisy + clippy::missing_errors_doc, + clippy::must_use_candidate, +)] + +pub use crate::de::{from_reader, from_slice, from_str, Deserializer}; +pub use crate::error::{Error, Location, Result}; +pub use crate::ser::{to_string, to_writer, Serializer}; +#[doc(inline)] +pub use crate::value::{from_value, to_value, Index, Number, Sequence, Value}; + +#[doc(inline)] +pub use crate::mapping::Mapping; + +mod de; +mod error; +mod libyaml; +mod loader; +pub mod mapping; +mod number; +mod path; +mod ser; +pub mod value; +pub mod with; + +// Prevent downstream code from implementing the Index trait. +mod private { + pub trait Sealed {} + impl Sealed for usize {} + impl Sealed for str {} + impl Sealed for String {} + impl Sealed for crate::Value {} + impl<'a, T> Sealed for &'a T where T: ?Sized + Sealed {} +} diff --git a/kclvm/third-party/serde_yaml/src/libyaml/cstr.rs b/kclvm/third-party/serde_yaml/src/libyaml/cstr.rs new file mode 100644 index 000000000..6e82535be --- /dev/null +++ b/kclvm/third-party/serde_yaml/src/libyaml/cstr.rs @@ -0,0 +1,127 @@ +use std::fmt::{self, Debug, Display, Write as _}; +use std::marker::PhantomData; +use std::ptr::NonNull; +use std::slice; +use std::str; + +#[derive(Copy, Clone)] +pub(crate) struct CStr<'a> { + ptr: NonNull, + marker: PhantomData<&'a [u8]>, +} + +unsafe impl<'a> Send for CStr<'a> {} +unsafe impl<'a> Sync for CStr<'a> {} + +impl<'a> CStr<'a> { + pub fn from_bytes_with_nul(bytes: &'static [u8]) -> Self { + assert_eq!(bytes.last(), Some(&b'\0')); + let ptr = NonNull::from(bytes).cast(); + unsafe { Self::from_ptr(ptr) } + } + + pub unsafe fn from_ptr(ptr: NonNull) -> Self { + CStr { + ptr: ptr.cast(), + marker: PhantomData, + } + } + + pub fn len(self) -> usize { + let start = self.ptr.as_ptr(); + let mut end = start; + unsafe { + while *end != 0 { + end = end.add(1); + } + end.offset_from(start) as usize + } + } + + pub fn to_bytes(self) -> &'a [u8] { + let len = self.len(); + unsafe { slice::from_raw_parts(self.ptr.as_ptr(), len) } + } +} + +impl<'a> Display for CStr<'a> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let ptr = self.ptr.as_ptr(); + let len = self.len(); + let bytes = unsafe { slice::from_raw_parts(ptr, len) }; + display_lossy(bytes, formatter) + } +} + +impl<'a> Debug for CStr<'a> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let ptr = self.ptr.as_ptr(); + let len = self.len(); + let bytes = unsafe { slice::from_raw_parts(ptr, len) }; + debug_lossy(bytes, formatter) + } +} + +fn display_lossy(mut bytes: &[u8], formatter: &mut fmt::Formatter) -> fmt::Result { + loop { + match str::from_utf8(bytes) { + Ok(valid) => return formatter.write_str(valid), + Err(utf8_error) => { + let valid_up_to = utf8_error.valid_up_to(); + let valid = unsafe { str::from_utf8_unchecked(&bytes[..valid_up_to]) }; + formatter.write_str(valid)?; + formatter.write_char(char::REPLACEMENT_CHARACTER)?; + if let Some(error_len) = utf8_error.error_len() { + bytes = &bytes[valid_up_to + error_len..]; + } else { + return Ok(()); + } + } + } + } +} + +pub(crate) fn debug_lossy(mut bytes: &[u8], formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_char('"')?; + + while !bytes.is_empty() { + let from_utf8_result = str::from_utf8(bytes); + let valid = match from_utf8_result { + Ok(valid) => valid, + Err(utf8_error) => { + let valid_up_to = utf8_error.valid_up_to(); + unsafe { str::from_utf8_unchecked(&bytes[..valid_up_to]) } + } + }; + + let mut written = 0; + for (i, ch) in valid.char_indices() { + let esc = ch.escape_debug(); + if esc.len() != 1 && ch != '\'' { + formatter.write_str(&valid[written..i])?; + for ch in esc { + formatter.write_char(ch)?; + } + written = i + ch.len_utf8(); + } + } + formatter.write_str(&valid[written..])?; + + match from_utf8_result { + Ok(_valid) => break, + Err(utf8_error) => { + let end_of_broken = if let Some(error_len) = utf8_error.error_len() { + valid.len() + error_len + } else { + bytes.len() + }; + for b in &bytes[valid.len()..end_of_broken] { + write!(formatter, "\\x{:02x}", b)?; + } + bytes = &bytes[end_of_broken..]; + } + } + } + + formatter.write_char('"') +} diff --git a/kclvm/third-party/serde_yaml/src/libyaml/emitter.rs b/kclvm/third-party/serde_yaml/src/libyaml/emitter.rs new file mode 100644 index 000000000..686f06ef2 --- /dev/null +++ b/kclvm/third-party/serde_yaml/src/libyaml/emitter.rs @@ -0,0 +1,217 @@ +use crate::libyaml; +use crate::libyaml::util::Owned; +use std::ffi::c_void; +use std::io; +use std::mem::{self, MaybeUninit}; +use std::ptr::{self, addr_of_mut}; +use std::slice; +use unsafe_libyaml as sys; + +#[derive(Debug)] +pub(crate) enum Error { + Libyaml(libyaml::error::Error), + Io(io::Error), +} + +pub(crate) struct Emitter<'a> { + pin: Owned>, +} + +struct EmitterPinned<'a> { + sys: sys::yaml_emitter_t, + write: Box, + write_error: Option, +} + +#[derive(Debug)] +pub(crate) enum Event<'a> { + StreamStart, + StreamEnd, + DocumentStart, + DocumentEnd, + Scalar(Scalar<'a>), + SequenceStart(Sequence), + SequenceEnd, + MappingStart(Mapping), + MappingEnd, +} + +#[derive(Debug)] +pub(crate) struct Scalar<'a> { + pub tag: Option, + pub value: &'a str, + pub style: ScalarStyle, +} + +#[derive(Debug)] +pub(crate) enum ScalarStyle { + Any, + Plain, + SingleQuoted, + Literal, +} + +#[derive(Debug)] +pub(crate) struct Sequence { + pub tag: Option, +} + +#[derive(Debug)] +pub(crate) struct Mapping { + pub tag: Option, +} + +impl<'a> Emitter<'a> { + pub fn new(write: Box) -> Emitter<'a> { + let owned = Owned::::new_uninit(); + let pin = unsafe { + let emitter = addr_of_mut!((*owned.ptr).sys); + if sys::yaml_emitter_initialize(emitter).fail { + panic!("malloc error: {}", libyaml::Error::emit_error(emitter)); + } + sys::yaml_emitter_set_unicode(emitter, true); + sys::yaml_emitter_set_width(emitter, -1); + addr_of_mut!((*owned.ptr).write).write(write); + addr_of_mut!((*owned.ptr).write_error).write(None); + sys::yaml_emitter_set_output(emitter, write_handler, owned.ptr.cast()); + Owned::assume_init(owned) + }; + Emitter { pin } + } + + pub fn emit(&mut self, event: Event) -> Result<(), Error> { + let mut sys_event = MaybeUninit::::uninit(); + let sys_event = sys_event.as_mut_ptr(); + unsafe { + let emitter = addr_of_mut!((*self.pin.ptr).sys); + let initialize_status = match event { + Event::StreamStart => { + sys::yaml_stream_start_event_initialize(sys_event, sys::YAML_UTF8_ENCODING) + } + Event::StreamEnd => sys::yaml_stream_end_event_initialize(sys_event), + Event::DocumentStart => { + let version_directive = ptr::null_mut(); + let tag_directives_start = ptr::null_mut(); + let tag_directives_end = ptr::null_mut(); + let implicit = true; + sys::yaml_document_start_event_initialize( + sys_event, + version_directive, + tag_directives_start, + tag_directives_end, + implicit, + ) + } + Event::DocumentEnd => { + let implicit = true; + sys::yaml_document_end_event_initialize(sys_event, implicit) + } + Event::Scalar(mut scalar) => { + let anchor = ptr::null(); + let tag = scalar.tag.as_mut().map_or_else(ptr::null, |tag| { + tag.push('\0'); + tag.as_ptr() + }); + let value = scalar.value.as_ptr(); + let length = scalar.value.len() as i32; + let plain_implicit = tag.is_null(); + let quoted_implicit = tag.is_null(); + let style = match scalar.style { + ScalarStyle::Any => sys::YAML_ANY_SCALAR_STYLE, + ScalarStyle::Plain => sys::YAML_PLAIN_SCALAR_STYLE, + ScalarStyle::SingleQuoted => sys::YAML_SINGLE_QUOTED_SCALAR_STYLE, + ScalarStyle::Literal => sys::YAML_LITERAL_SCALAR_STYLE, + }; + sys::yaml_scalar_event_initialize( + sys_event, + anchor, + tag, + value, + length, + plain_implicit, + quoted_implicit, + style, + ) + } + Event::SequenceStart(mut sequence) => { + let anchor = ptr::null(); + let tag = sequence.tag.as_mut().map_or_else(ptr::null, |tag| { + tag.push('\0'); + tag.as_ptr() + }); + let implicit = tag.is_null(); + let style = sys::YAML_ANY_SEQUENCE_STYLE; + sys::yaml_sequence_start_event_initialize( + sys_event, anchor, tag, implicit, style, + ) + } + Event::SequenceEnd => sys::yaml_sequence_end_event_initialize(sys_event), + Event::MappingStart(mut mapping) => { + let anchor = ptr::null(); + let tag = mapping.tag.as_mut().map_or_else(ptr::null, |tag| { + tag.push('\0'); + tag.as_ptr() + }); + let implicit = tag.is_null(); + let style = sys::YAML_ANY_MAPPING_STYLE; + sys::yaml_mapping_start_event_initialize( + sys_event, anchor, tag, implicit, style, + ) + } + Event::MappingEnd => sys::yaml_mapping_end_event_initialize(sys_event), + }; + if initialize_status.fail { + return Err(Error::Libyaml(libyaml::Error::emit_error(emitter))); + } + if sys::yaml_emitter_emit(emitter, sys_event).fail { + return Err(self.error()); + } + } + Ok(()) + } + + pub fn flush(&mut self) -> Result<(), Error> { + unsafe { + let emitter = addr_of_mut!((*self.pin.ptr).sys); + if sys::yaml_emitter_flush(emitter).fail { + return Err(self.error()); + } + } + Ok(()) + } + + pub fn into_inner(self) -> Box { + let sink = Box::new(io::sink()); + unsafe { mem::replace(&mut (*self.pin.ptr).write, sink) } + } + + fn error(&mut self) -> Error { + let emitter = unsafe { &mut *self.pin.ptr }; + if let Some(write_error) = emitter.write_error.take() { + Error::Io(write_error) + } else { + Error::Libyaml(unsafe { libyaml::Error::emit_error(&emitter.sys) }) + } + } +} + +unsafe fn write_handler(data: *mut c_void, buffer: *mut u8, size: u64) -> i32 { + let data = data.cast::(); + match io::Write::write_all(unsafe { &mut *(*data).write }, unsafe { + slice::from_raw_parts(buffer, size as usize) + }) { + Ok(()) => 1, + Err(err) => { + unsafe { + (*data).write_error = Some(err); + } + 0 + } + } +} + +impl<'a> Drop for EmitterPinned<'a> { + fn drop(&mut self) { + unsafe { sys::yaml_emitter_delete(&mut self.sys) } + } +} diff --git a/kclvm/third-party/serde_yaml/src/libyaml/error.rs b/kclvm/third-party/serde_yaml/src/libyaml/error.rs new file mode 100644 index 000000000..8397f6e2b --- /dev/null +++ b/kclvm/third-party/serde_yaml/src/libyaml/error.rs @@ -0,0 +1,162 @@ +use crate::libyaml::cstr::CStr; +use std::fmt::{self, Debug, Display}; +use std::mem::MaybeUninit; +use std::ptr::NonNull; +use unsafe_libyaml as sys; + +pub(crate) type Result = std::result::Result; + +pub(crate) struct Error { + kind: sys::yaml_error_type_t, + problem: CStr<'static>, + problem_offset: u64, + problem_mark: Mark, + context: Option>, + context_mark: Mark, +} + +impl Error { + pub unsafe fn parse_error(parser: *const sys::yaml_parser_t) -> Self { + Error { + kind: unsafe { (*parser).error }, + problem: match NonNull::new(unsafe { (*parser).problem as *mut _ }) { + Some(problem) => unsafe { CStr::from_ptr(problem) }, + None => CStr::from_bytes_with_nul(b"libyaml parser failed but there is no error\0"), + }, + problem_offset: unsafe { (*parser).problem_offset }, + problem_mark: Mark { + sys: unsafe { (*parser).problem_mark }, + }, + context: match NonNull::new(unsafe { (*parser).context as *mut _ }) { + Some(context) => Some(unsafe { CStr::from_ptr(context) }), + None => None, + }, + context_mark: Mark { + sys: unsafe { (*parser).context_mark }, + }, + } + } + + pub unsafe fn emit_error(emitter: *const sys::yaml_emitter_t) -> Self { + Error { + kind: unsafe { (*emitter).error }, + problem: match NonNull::new(unsafe { (*emitter).problem as *mut _ }) { + Some(problem) => unsafe { CStr::from_ptr(problem) }, + None => { + CStr::from_bytes_with_nul(b"libyaml emitter failed but there is no error\0") + } + }, + problem_offset: 0, + problem_mark: Mark { + sys: unsafe { MaybeUninit::::zeroed().assume_init() }, + }, + context: None, + context_mark: Mark { + sys: unsafe { MaybeUninit::::zeroed().assume_init() }, + }, + } + } + + pub fn mark(&self) -> Mark { + self.problem_mark + } +} + +impl Display for Error { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + write!(formatter, "{}", self.problem)?; + if self.problem_mark.sys.line != 0 || self.problem_mark.sys.column != 0 { + write!(formatter, " at {}", self.problem_mark)?; + } else if self.problem_offset != 0 { + write!(formatter, " at position {}", self.problem_offset)?; + } + if let Some(context) = &self.context { + write!(formatter, ", {}", context)?; + if (self.context_mark.sys.line != 0 || self.context_mark.sys.column != 0) + && (self.context_mark.sys.line != self.problem_mark.sys.line + || self.context_mark.sys.column != self.problem_mark.sys.column) + { + write!(formatter, " at {}", self.context_mark)?; + } + } + Ok(()) + } +} + +impl Debug for Error { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("Error"); + if let Some(kind) = match self.kind { + sys::YAML_MEMORY_ERROR => Some("MEMORY"), + sys::YAML_READER_ERROR => Some("READER"), + sys::YAML_SCANNER_ERROR => Some("SCANNER"), + sys::YAML_PARSER_ERROR => Some("PARSER"), + sys::YAML_COMPOSER_ERROR => Some("COMPOSER"), + sys::YAML_WRITER_ERROR => Some("WRITER"), + sys::YAML_EMITTER_ERROR => Some("EMITTER"), + _ => None, + } { + formatter.field("kind", &format_args!("{}", kind)); + } + formatter.field("problem", &self.problem); + if self.problem_mark.sys.line != 0 || self.problem_mark.sys.column != 0 { + formatter.field("problem_mark", &self.problem_mark); + } else if self.problem_offset != 0 { + formatter.field("problem_offset", &self.problem_offset); + } + if let Some(context) = &self.context { + formatter.field("context", context); + if self.context_mark.sys.line != 0 || self.context_mark.sys.column != 0 { + formatter.field("context_mark", &self.context_mark); + } + } + formatter.finish() + } +} + +#[derive(Copy, Clone)] +pub(crate) struct Mark { + pub(super) sys: sys::yaml_mark_t, +} + +impl Mark { + pub fn index(&self) -> u64 { + self.sys.index + } + + pub fn line(&self) -> u64 { + self.sys.line + } + + pub fn column(&self) -> u64 { + self.sys.column + } +} + +impl Display for Mark { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + if self.sys.line != 0 || self.sys.column != 0 { + write!( + formatter, + "line {} column {}", + self.sys.line + 1, + self.sys.column + 1, + ) + } else { + write!(formatter, "position {}", self.sys.index) + } + } +} + +impl Debug for Mark { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("Mark"); + if self.sys.line != 0 || self.sys.column != 0 { + formatter.field("line", &(self.sys.line + 1)); + formatter.field("column", &(self.sys.column + 1)); + } else { + formatter.field("index", &self.sys.index); + } + formatter.finish() + } +} diff --git a/kclvm/third-party/serde_yaml/src/libyaml/mod.rs b/kclvm/third-party/serde_yaml/src/libyaml/mod.rs new file mode 100644 index 000000000..9e160b17c --- /dev/null +++ b/kclvm/third-party/serde_yaml/src/libyaml/mod.rs @@ -0,0 +1,8 @@ +mod cstr; +pub mod emitter; +pub mod error; +pub mod parser; +pub mod tag; +mod util; + +use self::error::Error; diff --git a/kclvm/third-party/serde_yaml/src/libyaml/parser.rs b/kclvm/third-party/serde_yaml/src/libyaml/parser.rs new file mode 100644 index 000000000..3492edd0b --- /dev/null +++ b/kclvm/third-party/serde_yaml/src/libyaml/parser.rs @@ -0,0 +1,201 @@ +use crate::libyaml::cstr::{self, CStr}; +use crate::libyaml::error::{Error, Mark, Result}; +use crate::libyaml::tag::Tag; +use crate::libyaml::util::Owned; +use std::borrow::Cow; +use std::fmt::{self, Debug}; +use std::mem::MaybeUninit; +use std::ptr::{addr_of_mut, NonNull}; +use std::slice; +use unsafe_libyaml as sys; + +pub(crate) struct Parser<'input> { + pin: Owned>, +} + +struct ParserPinned<'input> { + sys: sys::yaml_parser_t, + input: Cow<'input, [u8]>, +} + +#[derive(Debug)] +pub(crate) enum Event<'input> { + StreamStart, + StreamEnd, + DocumentStart, + DocumentEnd, + Alias(Anchor), + Scalar(Scalar<'input>), + SequenceStart(SequenceStart), + SequenceEnd, + MappingStart(MappingStart), + MappingEnd, +} + +pub(crate) struct Scalar<'input> { + pub anchor: Option, + pub tag: Option, + pub value: Box<[u8]>, + pub style: ScalarStyle, + pub repr: Option<&'input [u8]>, +} + +#[derive(Debug)] +pub(crate) struct SequenceStart { + pub anchor: Option, + pub tag: Option, +} + +#[derive(Debug)] +pub(crate) struct MappingStart { + pub anchor: Option, + pub tag: Option, +} + +#[derive(Ord, PartialOrd, Eq, PartialEq)] +pub(crate) struct Anchor(Box<[u8]>); + +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +pub(crate) enum ScalarStyle { + Plain, + SingleQuoted, + DoubleQuoted, + Literal, + Folded, +} + +impl<'input> Parser<'input> { + pub fn new(input: Cow<'input, [u8]>) -> Parser<'input> { + let owned = Owned::::new_uninit(); + let pin = unsafe { + let parser = addr_of_mut!((*owned.ptr).sys); + if sys::yaml_parser_initialize(parser).fail { + panic!("malloc error: {}", Error::parse_error(parser)); + } + sys::yaml_parser_set_encoding(parser, sys::YAML_UTF8_ENCODING); + sys::yaml_parser_set_input_string(parser, input.as_ptr(), input.len() as u64); + addr_of_mut!((*owned.ptr).input).write(input); + Owned::assume_init(owned) + }; + Parser { pin } + } + + pub fn next(&mut self) -> Result<(Event<'input>, Mark)> { + let mut event = MaybeUninit::::uninit(); + unsafe { + let parser = addr_of_mut!((*self.pin.ptr).sys); + if (*parser).error != sys::YAML_NO_ERROR { + return Err(Error::parse_error(parser)); + } + let event = event.as_mut_ptr(); + if sys::yaml_parser_parse(parser, event).fail { + return Err(Error::parse_error(parser)); + } + let ret = convert_event(&*event, &(*self.pin.ptr).input); + let mark = Mark { + sys: (*event).start_mark, + }; + sys::yaml_event_delete(event); + Ok((ret, mark)) + } + } +} + +unsafe fn convert_event<'input>( + sys: &sys::yaml_event_t, + input: &Cow<'input, [u8]>, +) -> Event<'input> { + match sys.type_ { + sys::YAML_STREAM_START_EVENT => Event::StreamStart, + sys::YAML_STREAM_END_EVENT => Event::StreamEnd, + sys::YAML_DOCUMENT_START_EVENT => Event::DocumentStart, + sys::YAML_DOCUMENT_END_EVENT => Event::DocumentEnd, + sys::YAML_ALIAS_EVENT => { + Event::Alias(unsafe { optional_anchor(sys.data.alias.anchor) }.unwrap()) + } + sys::YAML_SCALAR_EVENT => Event::Scalar(Scalar { + anchor: unsafe { optional_anchor(sys.data.scalar.anchor) }, + tag: unsafe { optional_tag(sys.data.scalar.tag) }, + value: Box::from(unsafe { + slice::from_raw_parts(sys.data.scalar.value, sys.data.scalar.length as usize) + }), + style: match unsafe { sys.data.scalar.style } { + sys::YAML_PLAIN_SCALAR_STYLE => ScalarStyle::Plain, + sys::YAML_SINGLE_QUOTED_SCALAR_STYLE => ScalarStyle::SingleQuoted, + sys::YAML_DOUBLE_QUOTED_SCALAR_STYLE => ScalarStyle::DoubleQuoted, + sys::YAML_LITERAL_SCALAR_STYLE => ScalarStyle::Literal, + sys::YAML_FOLDED_SCALAR_STYLE => ScalarStyle::Folded, + sys::YAML_ANY_SCALAR_STYLE | _ => unreachable!(), + }, + repr: if let Cow::Borrowed(input) = input { + Some(&input[sys.start_mark.index as usize..sys.end_mark.index as usize]) + } else { + None + }, + }), + sys::YAML_SEQUENCE_START_EVENT => Event::SequenceStart(SequenceStart { + anchor: unsafe { optional_anchor(sys.data.sequence_start.anchor) }, + tag: unsafe { optional_tag(sys.data.sequence_start.tag) }, + }), + sys::YAML_SEQUENCE_END_EVENT => Event::SequenceEnd, + sys::YAML_MAPPING_START_EVENT => Event::MappingStart(MappingStart { + anchor: unsafe { optional_anchor(sys.data.mapping_start.anchor) }, + tag: unsafe { optional_tag(sys.data.mapping_start.tag) }, + }), + sys::YAML_MAPPING_END_EVENT => Event::MappingEnd, + sys::YAML_NO_EVENT => unreachable!(), + _ => unimplemented!(), + } +} + +unsafe fn optional_anchor(anchor: *const u8) -> Option { + let ptr = NonNull::new(anchor as *mut i8)?; + let cstr = unsafe { CStr::from_ptr(ptr) }; + Some(Anchor(Box::from(cstr.to_bytes()))) +} + +unsafe fn optional_tag(tag: *const u8) -> Option { + let ptr = NonNull::new(tag as *mut i8)?; + let cstr = unsafe { CStr::from_ptr(ptr) }; + Some(Tag(Box::from(cstr.to_bytes()))) +} + +impl<'input> Debug for Scalar<'input> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let Scalar { + anchor, + tag, + value, + style, + repr: _, + } = self; + + struct LossySlice<'a>(&'a [u8]); + + impl<'a> Debug for LossySlice<'a> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + cstr::debug_lossy(self.0, formatter) + } + } + + formatter + .debug_struct("Scalar") + .field("anchor", anchor) + .field("tag", tag) + .field("value", &LossySlice(value)) + .field("style", style) + .finish() + } +} + +impl Debug for Anchor { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + cstr::debug_lossy(&self.0, formatter) + } +} + +impl<'input> Drop for ParserPinned<'input> { + fn drop(&mut self) { + unsafe { sys::yaml_parser_delete(&mut self.sys) } + } +} diff --git a/kclvm/third-party/serde_yaml/src/libyaml/tag.rs b/kclvm/third-party/serde_yaml/src/libyaml/tag.rs new file mode 100644 index 000000000..1f731859a --- /dev/null +++ b/kclvm/third-party/serde_yaml/src/libyaml/tag.rs @@ -0,0 +1,38 @@ +use crate::libyaml::cstr; +use std::fmt::{self, Debug}; +use std::ops::Deref; + +#[derive(Ord, PartialOrd, Eq, PartialEq)] +pub(crate) struct Tag(pub(in crate::libyaml) Box<[u8]>); + +impl Tag { + pub const NULL: &'static str = "tag:yaml.org,2002:null"; + pub const BOOL: &'static str = "tag:yaml.org,2002:bool"; + pub const INT: &'static str = "tag:yaml.org,2002:int"; + pub const FLOAT: &'static str = "tag:yaml.org,2002:float"; +} + +impl Tag { + pub fn starts_with(&self, prefix: &str) -> bool { + self.0.starts_with(prefix.as_bytes()) + } +} + +impl PartialEq for Tag { + fn eq(&self, other: &str) -> bool { + *self.0 == *other.as_bytes() + } +} + +impl Deref for Tag { + type Target = [u8]; + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl Debug for Tag { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + cstr::debug_lossy(&self.0, formatter) + } +} diff --git a/kclvm/third-party/serde_yaml/src/libyaml/util.rs b/kclvm/third-party/serde_yaml/src/libyaml/util.rs new file mode 100644 index 000000000..1f5010da0 --- /dev/null +++ b/kclvm/third-party/serde_yaml/src/libyaml/util.rs @@ -0,0 +1,48 @@ +use std::marker::PhantomData; +use std::mem::{self, MaybeUninit}; +use std::ops::Deref; +use std::ptr::{addr_of, NonNull}; + +pub(crate) struct Owned { + ptr: NonNull, + marker: PhantomData>, +} + +impl Owned { + pub fn new_uninit() -> Owned, T> { + // FIXME: use Box::new_uninit when stable + let boxed = Box::new(MaybeUninit::::uninit()); + Owned { + ptr: unsafe { NonNull::new_unchecked(Box::into_raw(boxed)) }, + marker: PhantomData, + } + } + + pub unsafe fn assume_init(definitely_init: Owned, T>) -> Owned { + let ptr = definitely_init.ptr; + mem::forget(definitely_init); + Owned { + ptr: ptr.cast(), + marker: PhantomData, + } + } +} + +#[repr(transparent)] +pub(crate) struct InitPtr { + pub ptr: *mut T, +} + +impl Deref for Owned { + type Target = InitPtr; + + fn deref(&self) -> &Self::Target { + unsafe { &*addr_of!(self.ptr).cast::>() } + } +} + +impl Drop for Owned { + fn drop(&mut self) { + let _ = unsafe { Box::from_raw(self.ptr.as_ptr()) }; + } +} diff --git a/kclvm/third-party/serde_yaml/src/loader.rs b/kclvm/third-party/serde_yaml/src/loader.rs new file mode 100644 index 000000000..7c7c7b655 --- /dev/null +++ b/kclvm/third-party/serde_yaml/src/loader.rs @@ -0,0 +1,119 @@ +use crate::de::{Event, Progress}; +use crate::error::{self, Error, ErrorImpl, Result}; +use crate::libyaml::error::Mark; +use crate::libyaml::parser::{Event as YamlEvent, Parser}; +use std::borrow::Cow; +use std::collections::BTreeMap; +use std::sync::Arc; + +pub(crate) struct Loader<'input> { + parser: Option>, + document_count: usize, +} + +pub(crate) struct Document<'input> { + pub events: Vec<(Event<'input>, Mark)>, + pub error: Option>, + /// Map from alias id to index in events. + pub aliases: BTreeMap, +} + +impl<'input> Loader<'input> { + pub fn new(progress: Progress<'input>) -> Result { + let input = match progress { + Progress::Str(s) => Cow::Borrowed(s.as_bytes()), + Progress::Slice(bytes) => Cow::Borrowed(bytes), + Progress::Read(mut rdr) => { + let mut buffer = Vec::new(); + if let Err(io_error) = rdr.read_to_end(&mut buffer) { + return Err(error::new(ErrorImpl::Io(io_error))); + } + Cow::Owned(buffer) + } + Progress::Iterable(_) | Progress::Document(_) => unreachable!(), + Progress::Fail(err) => return Err(error::shared(err)), + }; + + Ok(Loader { + parser: Some(Parser::new(input)), + document_count: 0, + }) + } + + pub fn next_document(&mut self) -> Option> { + let parser = match &mut self.parser { + Some(parser) => parser, + None => return None, + }; + + let first = self.document_count == 0; + self.document_count += 1; + + let mut anchors = BTreeMap::new(); + let mut document = Document { + events: Vec::new(), + error: None, + aliases: BTreeMap::new(), + }; + + loop { + let (event, mark) = match parser.next() { + Ok((event, mark)) => (event, mark), + Err(err) => { + document.error = Some(Error::from(err).shared()); + return Some(document); + } + }; + let event = match event { + YamlEvent::StreamStart => continue, + YamlEvent::StreamEnd => { + self.parser = None; + return if first { + if document.events.is_empty() { + document.events.push((Event::Void, mark)); + } + Some(document) + } else { + None + }; + } + YamlEvent::DocumentStart => continue, + YamlEvent::DocumentEnd => return Some(document), + YamlEvent::Alias(alias) => match anchors.get(&alias) { + Some(id) => Event::Alias(*id), + None => { + document.error = Some(error::new(ErrorImpl::UnknownAnchor(mark)).shared()); + return Some(document); + } + }, + YamlEvent::Scalar(mut scalar) => { + if let Some(anchor) = scalar.anchor.take() { + let id = anchors.len(); + anchors.insert(anchor, id); + document.aliases.insert(id, document.events.len()); + } + Event::Scalar(scalar) + } + YamlEvent::SequenceStart(mut sequence_start) => { + if let Some(anchor) = sequence_start.anchor.take() { + let id = anchors.len(); + anchors.insert(anchor, id); + document.aliases.insert(id, document.events.len()); + } + Event::SequenceStart(sequence_start) + } + YamlEvent::SequenceEnd => Event::SequenceEnd, + YamlEvent::MappingStart(mut mapping_start) => { + if let Some(anchor) = mapping_start.anchor.take() { + let id = anchors.len(); + anchors.insert(anchor, id); + document.aliases.insert(id, document.events.len()); + } + Event::MappingStart(mapping_start) + } + YamlEvent::MappingEnd => Event::MappingEnd, + }; + document.events.push((event, mark)); + } + } +} diff --git a/kclvm/third-party/serde_yaml/src/mapping.rs b/kclvm/third-party/serde_yaml/src/mapping.rs new file mode 100644 index 000000000..667cd4b42 --- /dev/null +++ b/kclvm/third-party/serde_yaml/src/mapping.rs @@ -0,0 +1,851 @@ +//! A YAML mapping and its iterator types. + +use crate::{private, Value}; +use indexmap::IndexMap; +use serde::{Deserialize, Deserializer, Serialize}; +use std::cmp::Ordering; +use std::collections::hash_map::DefaultHasher; +use std::fmt::{self, Display}; +use std::hash::{Hash, Hasher}; +use std::mem; + +/// A YAML mapping in which the keys and values are both `serde_yaml::Value`. +#[derive(Clone, Default, Eq, PartialEq)] +pub struct Mapping { + map: IndexMap, +} + +impl Mapping { + /// Creates an empty YAML map. + #[inline] + pub fn new() -> Self { + Self::default() + } + + /// Creates an empty YAML map with the given initial capacity. + #[inline] + pub fn with_capacity(capacity: usize) -> Self { + Mapping { + map: IndexMap::with_capacity(capacity), + } + } + + /// Reserves capacity for at least `additional` more elements to be inserted + /// into the map. The map may reserve more space to avoid frequent + /// allocations. + /// + /// # Panics + /// + /// Panics if the new allocation size overflows `usize`. + #[inline] + pub fn reserve(&mut self, additional: usize) { + self.map.reserve(additional); + } + + /// Shrinks the capacity of the map as much as possible. It will drop down + /// as much as possible while maintaining the internal rules and possibly + /// leaving some space in accordance with the resize policy. + #[inline] + pub fn shrink_to_fit(&mut self) { + self.map.shrink_to_fit(); + } + + /// Inserts a key-value pair into the map. If the key already existed, the + /// old value is returned. + #[inline] + pub fn insert(&mut self, k: Value, v: Value) -> Option { + self.map.insert(k, v) + } + + /// Checks if the map contains the given key. + #[inline] + pub fn contains_key(&self, index: I) -> bool { + index.is_key_into(self) + } + + /// Returns the value corresponding to the key in the map. + #[inline] + pub fn get(&self, index: I) -> Option<&Value> { + index.index_into(self) + } + + /// Returns the mutable reference corresponding to the key in the map. + #[inline] + pub fn get_mut(&mut self, index: I) -> Option<&mut Value> { + index.index_into_mut(self) + } + + /// Gets the given key's corresponding entry in the map for insertion and/or + /// in-place manipulation. + #[inline] + pub fn entry(&mut self, k: Value) -> Entry { + match self.map.entry(k) { + indexmap::map::Entry::Occupied(occupied) => Entry::Occupied(OccupiedEntry { occupied }), + indexmap::map::Entry::Vacant(vacant) => Entry::Vacant(VacantEntry { vacant }), + } + } + + /// Removes and returns the value corresponding to the key from the map. + /// + /// This is equivalent to [`.swap_remove(index)`][Self::swap_remove], + /// replacing this entry's position with the last element. If you need to + /// preserve the relative order of the keys in the map, use + /// [`.shift_remove(key)`][Self::shift_remove] instead. + #[inline] + pub fn remove(&mut self, index: I) -> Option { + self.swap_remove(index) + } + + /// Remove and return the key-value pair. + /// + /// This is equivalent to [`.swap_remove_entry(index)`][Self::swap_remove_entry], + /// replacing this entry's position with the last element. If you need to + /// preserve the relative order of the keys in the map, use + /// [`.shift_remove_entry(key)`][Self::shift_remove_entry] instead. + #[inline] + pub fn remove_entry(&mut self, index: I) -> Option<(Value, Value)> { + self.swap_remove_entry(index) + } + + /// Removes and returns the value corresponding to the key from the map. + /// + /// Like [`Vec::swap_remove`], the entry is removed by swapping it with the + /// last element of the map and popping it off. This perturbs the position + /// of what used to be the last element! + #[inline] + pub fn swap_remove(&mut self, index: I) -> Option { + index.swap_remove_from(self) + } + + /// Remove and return the key-value pair. + /// + /// Like [`Vec::swap_remove`], the entry is removed by swapping it with the + /// last element of the map and popping it off. This perturbs the position + /// of what used to be the last element! + #[inline] + pub fn swap_remove_entry(&mut self, index: I) -> Option<(Value, Value)> { + index.swap_remove_entry_from(self) + } + + /// Removes and returns the value corresponding to the key from the map. + /// + /// Like [`Vec::remove`], the entry is removed by shifting all of the + /// elements that follow it, preserving their relative order. This perturbs + /// the index of all of those elements! + #[inline] + pub fn shift_remove(&mut self, index: I) -> Option { + index.shift_remove_from(self) + } + + /// Remove and return the key-value pair. + /// + /// Like [`Vec::remove`], the entry is removed by shifting all of the + /// elements that follow it, preserving their relative order. This perturbs + /// the index of all of those elements! + #[inline] + pub fn shift_remove_entry(&mut self, index: I) -> Option<(Value, Value)> { + index.shift_remove_entry_from(self) + } + + /// Scan through each key-value pair in the map and keep those where the + /// closure `keep` returns true. + #[inline] + pub fn retain(&mut self, keep: F) + where + F: FnMut(&Value, &mut Value) -> bool, + { + self.map.retain(keep); + } + + /// Returns the maximum number of key-value pairs the map can hold without + /// reallocating. + #[inline] + pub fn capacity(&self) -> usize { + self.map.capacity() + } + + /// Returns the number of key-value pairs in the map. + #[inline] + pub fn len(&self) -> usize { + self.map.len() + } + + /// Returns whether the map is currently empty. + #[inline] + pub fn is_empty(&self) -> bool { + self.map.is_empty() + } + + /// Clears the map of all key-value pairs. + #[inline] + pub fn clear(&mut self) { + self.map.clear(); + } + + /// Returns a double-ended iterator visiting all key-value pairs in order of + /// insertion. Iterator element type is `(&'a Value, &'a Value)`. + #[inline] + pub fn iter(&self) -> Iter { + Iter { + iter: self.map.iter(), + } + } + + /// Returns a double-ended iterator visiting all key-value pairs in order of + /// insertion. Iterator element type is `(&'a Value, &'a mut ValuE)`. + #[inline] + pub fn iter_mut(&mut self) -> IterMut { + IterMut { + iter: self.map.iter_mut(), + } + } + + /// Return an iterator over the keys of the map. + pub fn keys(&self) -> Keys { + Keys { + iter: self.map.keys(), + } + } + + /// Return an owning iterator over the keys of the map. + pub fn into_keys(self) -> IntoKeys { + IntoKeys { + iter: self.map.into_keys(), + } + } + + /// Return an iterator over the values of the map. + pub fn values(&self) -> Values { + Values { + iter: self.map.values(), + } + } + + /// Return an iterator over mutable references to the values of the map. + pub fn values_mut(&mut self) -> ValuesMut { + ValuesMut { + iter: self.map.values_mut(), + } + } + + /// Return an owning iterator over the values of the map. + pub fn into_values(self) -> IntoValues { + IntoValues { + iter: self.map.into_values(), + } + } +} + +/// A type that can be used to index into a `serde_yaml::Mapping`. See the +/// methods `get`, `get_mut`, `contains_key`, and `remove` of `Value`. +/// +/// This trait is sealed and cannot be implemented for types outside of +/// `serde_yaml`. +pub trait Index: private::Sealed { + #[doc(hidden)] + fn is_key_into(&self, v: &Mapping) -> bool; + + #[doc(hidden)] + fn index_into<'a>(&self, v: &'a Mapping) -> Option<&'a Value>; + + #[doc(hidden)] + fn index_into_mut<'a>(&self, v: &'a mut Mapping) -> Option<&'a mut Value>; + + #[doc(hidden)] + fn swap_remove_from(&self, v: &mut Mapping) -> Option; + + #[doc(hidden)] + fn swap_remove_entry_from(&self, v: &mut Mapping) -> Option<(Value, Value)>; + + #[doc(hidden)] + fn shift_remove_from(&self, v: &mut Mapping) -> Option; + + #[doc(hidden)] + fn shift_remove_entry_from(&self, v: &mut Mapping) -> Option<(Value, Value)>; +} + +struct HashLikeValue<'a>(&'a str); + +impl<'a> indexmap::Equivalent for HashLikeValue<'a> { + fn equivalent(&self, key: &Value) -> bool { + match key { + Value::String(string) => self.0 == string, + _ => false, + } + } +} + +// NOTE: This impl must be consistent with Value's Hash impl. +impl<'a> Hash for HashLikeValue<'a> { + fn hash(&self, state: &mut H) { + const STRING: Value = Value::String(String::new()); + mem::discriminant(&STRING).hash(state); + self.0.hash(state); + } +} + +impl Index for Value { + fn is_key_into(&self, v: &Mapping) -> bool { + v.map.contains_key(self) + } + fn index_into<'a>(&self, v: &'a Mapping) -> Option<&'a Value> { + v.map.get(self) + } + fn index_into_mut<'a>(&self, v: &'a mut Mapping) -> Option<&'a mut Value> { + v.map.get_mut(self) + } + fn swap_remove_from(&self, v: &mut Mapping) -> Option { + v.map.swap_remove(self) + } + fn swap_remove_entry_from(&self, v: &mut Mapping) -> Option<(Value, Value)> { + v.map.swap_remove_entry(self) + } + fn shift_remove_from(&self, v: &mut Mapping) -> Option { + v.map.shift_remove(self) + } + fn shift_remove_entry_from(&self, v: &mut Mapping) -> Option<(Value, Value)> { + v.map.shift_remove_entry(self) + } +} + +impl Index for str { + fn is_key_into(&self, v: &Mapping) -> bool { + v.map.contains_key(&HashLikeValue(self)) + } + fn index_into<'a>(&self, v: &'a Mapping) -> Option<&'a Value> { + v.map.get(&HashLikeValue(self)) + } + fn index_into_mut<'a>(&self, v: &'a mut Mapping) -> Option<&'a mut Value> { + v.map.get_mut(&HashLikeValue(self)) + } + fn swap_remove_from(&self, v: &mut Mapping) -> Option { + v.map.swap_remove(&HashLikeValue(self)) + } + fn swap_remove_entry_from(&self, v: &mut Mapping) -> Option<(Value, Value)> { + v.map.swap_remove_entry(&HashLikeValue(self)) + } + fn shift_remove_from(&self, v: &mut Mapping) -> Option { + v.map.shift_remove(&HashLikeValue(self)) + } + fn shift_remove_entry_from(&self, v: &mut Mapping) -> Option<(Value, Value)> { + v.map.shift_remove_entry(&HashLikeValue(self)) + } +} + +impl Index for String { + fn is_key_into(&self, v: &Mapping) -> bool { + self.as_str().is_key_into(v) + } + fn index_into<'a>(&self, v: &'a Mapping) -> Option<&'a Value> { + self.as_str().index_into(v) + } + fn index_into_mut<'a>(&self, v: &'a mut Mapping) -> Option<&'a mut Value> { + self.as_str().index_into_mut(v) + } + fn swap_remove_from(&self, v: &mut Mapping) -> Option { + self.as_str().swap_remove_from(v) + } + fn swap_remove_entry_from(&self, v: &mut Mapping) -> Option<(Value, Value)> { + self.as_str().swap_remove_entry_from(v) + } + fn shift_remove_from(&self, v: &mut Mapping) -> Option { + self.as_str().shift_remove_from(v) + } + fn shift_remove_entry_from(&self, v: &mut Mapping) -> Option<(Value, Value)> { + self.as_str().shift_remove_entry_from(v) + } +} + +impl Index for &T +where + T: ?Sized + Index, +{ + fn is_key_into(&self, v: &Mapping) -> bool { + (**self).is_key_into(v) + } + fn index_into<'a>(&self, v: &'a Mapping) -> Option<&'a Value> { + (**self).index_into(v) + } + fn index_into_mut<'a>(&self, v: &'a mut Mapping) -> Option<&'a mut Value> { + (**self).index_into_mut(v) + } + fn swap_remove_from(&self, v: &mut Mapping) -> Option { + (**self).swap_remove_from(v) + } + fn swap_remove_entry_from(&self, v: &mut Mapping) -> Option<(Value, Value)> { + (**self).swap_remove_entry_from(v) + } + fn shift_remove_from(&self, v: &mut Mapping) -> Option { + (**self).shift_remove_from(v) + } + fn shift_remove_entry_from(&self, v: &mut Mapping) -> Option<(Value, Value)> { + (**self).shift_remove_entry_from(v) + } +} + +#[allow(clippy::derived_hash_with_manual_eq)] +impl Hash for Mapping { + fn hash(&self, state: &mut H) { + // Hash the kv pairs in a way that is not sensitive to their order. + let mut xor = 0; + for (k, v) in self { + let mut hasher = DefaultHasher::new(); + k.hash(&mut hasher); + v.hash(&mut hasher); + xor ^= hasher.finish(); + } + xor.hash(state); + } +} + +impl PartialOrd for Mapping { + fn partial_cmp(&self, other: &Self) -> Option { + let mut self_entries = Vec::from_iter(self); + let mut other_entries = Vec::from_iter(other); + + // Sort in an arbitrary order that is consistent with Value's PartialOrd + // impl. + fn total_cmp(a: &Value, b: &Value) -> Ordering { + match (a, b) { + (Value::Null, Value::Null) => Ordering::Equal, + (Value::Null, _) => Ordering::Less, + (_, Value::Null) => Ordering::Greater, + + (Value::Bool(a), Value::Bool(b)) => a.cmp(b), + (Value::Bool(_), _) => Ordering::Less, + (_, Value::Bool(_)) => Ordering::Greater, + + (Value::Number(a), Value::Number(b)) => a.total_cmp(b), + (Value::Number(_), _) => Ordering::Less, + (_, Value::Number(_)) => Ordering::Greater, + + (Value::String(a), Value::String(b)) => a.cmp(b), + (Value::String(_), _) => Ordering::Less, + (_, Value::String(_)) => Ordering::Greater, + + (Value::Sequence(a), Value::Sequence(b)) => iter_cmp_by(a, b, total_cmp), + (Value::Sequence(_), _) => Ordering::Less, + (_, Value::Sequence(_)) => Ordering::Greater, + + (Value::Mapping(a), Value::Mapping(b)) => { + iter_cmp_by(a, b, |(ak, av), (bk, bv)| { + total_cmp(ak, bk).then_with(|| total_cmp(av, bv)) + }) + } + (Value::Mapping(_), _) => Ordering::Less, + (_, Value::Mapping(_)) => Ordering::Greater, + + (Value::Tagged(a), Value::Tagged(b)) => a + .tag + .cmp(&b.tag) + .then_with(|| total_cmp(&a.value, &b.value)), + } + } + + fn iter_cmp_by(this: I, other: I, mut cmp: F) -> Ordering + where + I: IntoIterator, + F: FnMut(I::Item, I::Item) -> Ordering, + { + let mut this = this.into_iter(); + let mut other = other.into_iter(); + + loop { + let x = match this.next() { + None => { + if other.next().is_none() { + return Ordering::Equal; + } else { + return Ordering::Less; + } + } + Some(val) => val, + }; + + let y = match other.next() { + None => return Ordering::Greater, + Some(val) => val, + }; + + match cmp(x, y) { + Ordering::Equal => {} + non_eq => return non_eq, + } + } + } + + // While sorting by map key, we get to assume that no two keys are + // equal, otherwise they wouldn't both be in the map. This is not a safe + // assumption outside of this situation. + let total_cmp = |&(a, _): &_, &(b, _): &_| total_cmp(a, b); + self_entries.sort_by(total_cmp); + other_entries.sort_by(total_cmp); + self_entries.partial_cmp(&other_entries) + } +} + +impl std::ops::Index for Mapping +where + I: Index, +{ + type Output = Value; + + #[inline] + #[track_caller] + fn index(&self, index: I) -> &Value { + index.index_into(self).unwrap() + } +} + +impl std::ops::IndexMut for Mapping +where + I: Index, +{ + #[inline] + #[track_caller] + fn index_mut(&mut self, index: I) -> &mut Value { + index.index_into_mut(self).unwrap() + } +} + +impl Extend<(Value, Value)> for Mapping { + #[inline] + fn extend>(&mut self, iter: I) { + self.map.extend(iter); + } +} + +impl FromIterator<(Value, Value)> for Mapping { + #[inline] + fn from_iter>(iter: I) -> Self { + Mapping { + map: IndexMap::from_iter(iter), + } + } +} + +macro_rules! delegate_iterator { + (($name:ident $($generics:tt)*) => $item:ty) => { + impl $($generics)* Iterator for $name $($generics)* { + type Item = $item; + #[inline] + fn next(&mut self) -> Option { + self.iter.next() + } + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } + } + + impl $($generics)* ExactSizeIterator for $name $($generics)* { + #[inline] + fn len(&self) -> usize { + self.iter.len() + } + } + } +} + +/// Iterator over `&serde_yaml::Mapping`. +pub struct Iter<'a> { + iter: indexmap::map::Iter<'a, Value, Value>, +} + +delegate_iterator!((Iter<'a>) => (&'a Value, &'a Value)); + +impl<'a> IntoIterator for &'a Mapping { + type Item = (&'a Value, &'a Value); + type IntoIter = Iter<'a>; + #[inline] + fn into_iter(self) -> Self::IntoIter { + Iter { + iter: self.map.iter(), + } + } +} + +/// Iterator over `&mut serde_yaml::Mapping`. +pub struct IterMut<'a> { + iter: indexmap::map::IterMut<'a, Value, Value>, +} + +delegate_iterator!((IterMut<'a>) => (&'a Value, &'a mut Value)); + +impl<'a> IntoIterator for &'a mut Mapping { + type Item = (&'a Value, &'a mut Value); + type IntoIter = IterMut<'a>; + #[inline] + fn into_iter(self) -> Self::IntoIter { + IterMut { + iter: self.map.iter_mut(), + } + } +} + +/// Iterator over `serde_yaml::Mapping` by value. +pub struct IntoIter { + iter: indexmap::map::IntoIter, +} + +delegate_iterator!((IntoIter) => (Value, Value)); + +impl IntoIterator for Mapping { + type Item = (Value, Value); + type IntoIter = IntoIter; + #[inline] + fn into_iter(self) -> Self::IntoIter { + IntoIter { + iter: self.map.into_iter(), + } + } +} + +/// Iterator of the keys of a `&serde_yaml::Mapping`. +pub struct Keys<'a> { + iter: indexmap::map::Keys<'a, Value, Value>, +} + +delegate_iterator!((Keys<'a>) => &'a Value); + +/// Iterator of the keys of a `serde_yaml::Mapping`. +pub struct IntoKeys { + iter: indexmap::map::IntoKeys, +} + +delegate_iterator!((IntoKeys) => Value); + +/// Iterator of the values of a `&serde_yaml::Mapping`. +pub struct Values<'a> { + iter: indexmap::map::Values<'a, Value, Value>, +} + +delegate_iterator!((Values<'a>) => &'a Value); + +/// Iterator of the values of a `&mut serde_yaml::Mapping`. +pub struct ValuesMut<'a> { + iter: indexmap::map::ValuesMut<'a, Value, Value>, +} + +delegate_iterator!((ValuesMut<'a>) => &'a mut Value); + +/// Iterator of the values of a `serde_yaml::Mapping`. +pub struct IntoValues { + iter: indexmap::map::IntoValues, +} + +delegate_iterator!((IntoValues) => Value); + +/// Entry for an existing key-value pair or a vacant location to insert one. +pub enum Entry<'a> { + /// Existing slot with equivalent key. + Occupied(OccupiedEntry<'a>), + /// Vacant slot (no equivalent key in the map). + Vacant(VacantEntry<'a>), +} + +/// A view into an occupied entry in a [`Mapping`]. It is part of the [`Entry`] +/// enum. +pub struct OccupiedEntry<'a> { + occupied: indexmap::map::OccupiedEntry<'a, Value, Value>, +} + +/// A view into a vacant entry in a [`Mapping`]. It is part of the [`Entry`] +/// enum. +pub struct VacantEntry<'a> { + vacant: indexmap::map::VacantEntry<'a, Value, Value>, +} + +impl<'a> Entry<'a> { + /// Returns a reference to this entry's key. + pub fn key(&self) -> &Value { + match self { + Entry::Vacant(e) => e.key(), + Entry::Occupied(e) => e.key(), + } + } + + /// Ensures a value is in the entry by inserting the default if empty, and + /// returns a mutable reference to the value in the entry. + pub fn or_insert(self, default: Value) -> &'a mut Value { + match self { + Entry::Vacant(entry) => entry.insert(default), + Entry::Occupied(entry) => entry.into_mut(), + } + } + + /// Ensures a value is in the entry by inserting the result of the default + /// function if empty, and returns a mutable reference to the value in the + /// entry. + pub fn or_insert_with(self, default: F) -> &'a mut Value + where + F: FnOnce() -> Value, + { + match self { + Entry::Vacant(entry) => entry.insert(default()), + Entry::Occupied(entry) => entry.into_mut(), + } + } + + /// Provides in-place mutable access to an occupied entry before any + /// potential inserts into the map. + pub fn and_modify(self, f: F) -> Self + where + F: FnOnce(&mut Value), + { + match self { + Entry::Occupied(mut entry) => { + f(entry.get_mut()); + Entry::Occupied(entry) + } + Entry::Vacant(entry) => Entry::Vacant(entry), + } + } +} + +impl<'a> OccupiedEntry<'a> { + /// Gets a reference to the key in the entry. + #[inline] + pub fn key(&self) -> &Value { + self.occupied.key() + } + + /// Gets a reference to the value in the entry. + #[inline] + pub fn get(&self) -> &Value { + self.occupied.get() + } + + /// Gets a mutable reference to the value in the entry. + #[inline] + pub fn get_mut(&mut self) -> &mut Value { + self.occupied.get_mut() + } + + /// Converts the entry into a mutable reference to its value. + #[inline] + pub fn into_mut(self) -> &'a mut Value { + self.occupied.into_mut() + } + + /// Sets the value of the entry with the `OccupiedEntry`'s key, and returns + /// the entry's old value. + #[inline] + pub fn insert(&mut self, value: Value) -> Value { + self.occupied.insert(value) + } + + /// Takes the value of the entry out of the map, and returns it. + #[inline] + pub fn remove(self) -> Value { + self.occupied.swap_remove() + } + + /// Remove and return the key, value pair stored in the map for this entry. + #[inline] + pub fn remove_entry(self) -> (Value, Value) { + self.occupied.swap_remove_entry() + } +} + +impl<'a> VacantEntry<'a> { + /// Gets a reference to the key that would be used when inserting a value + /// through the VacantEntry. + #[inline] + pub fn key(&self) -> &Value { + self.vacant.key() + } + + /// Takes ownership of the key, leaving the entry vacant. + #[inline] + pub fn into_key(self) -> Value { + self.vacant.into_key() + } + + /// Sets the value of the entry with the VacantEntry's key, and returns a + /// mutable reference to it. + #[inline] + pub fn insert(self, value: Value) -> &'a mut Value { + self.vacant.insert(value) + } +} + +impl Serialize for Mapping { + #[inline] + fn serialize(&self, serializer: S) -> Result { + use serde::ser::SerializeMap; + let mut map_serializer = serializer.serialize_map(Some(self.len()))?; + for (k, v) in self { + map_serializer.serialize_entry(k, v)?; + } + map_serializer.end() + } +} + +impl<'de> Deserialize<'de> for Mapping { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct Visitor; + + impl<'de> serde::de::Visitor<'de> for Visitor { + type Value = Mapping; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a YAML mapping") + } + + #[inline] + fn visit_unit(self) -> Result + where + E: serde::de::Error, + { + Ok(Mapping::new()) + } + + #[inline] + fn visit_map(self, mut data: A) -> Result + where + A: serde::de::MapAccess<'de>, + { + let mut mapping = Mapping::new(); + + while let Some(key) = data.next_key()? { + match mapping.entry(key) { + Entry::Occupied(entry) => { + return Err(serde::de::Error::custom(DuplicateKeyError { entry })); + } + Entry::Vacant(entry) => { + let value = data.next_value()?; + entry.insert(value); + } + } + } + + Ok(mapping) + } + } + + deserializer.deserialize_map(Visitor) + } +} + +struct DuplicateKeyError<'a> { + entry: OccupiedEntry<'a>, +} + +impl<'a> Display for DuplicateKeyError<'a> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("duplicate entry ")?; + match self.entry.key() { + Value::Null => formatter.write_str("with null key"), + Value::Bool(boolean) => write!(formatter, "with key `{}`", boolean), + Value::Number(number) => write!(formatter, "with key {}", number), + Value::String(string) => write!(formatter, "with key {:?}", string), + Value::Sequence(_) | Value::Mapping(_) | Value::Tagged(_) => { + formatter.write_str("in YAML map") + } + } + } +} diff --git a/kclvm/third-party/serde_yaml/src/number.rs b/kclvm/third-party/serde_yaml/src/number.rs new file mode 100644 index 000000000..5ebe39577 --- /dev/null +++ b/kclvm/third-party/serde_yaml/src/number.rs @@ -0,0 +1,561 @@ +use crate::de; +use crate::error::{self, Error, ErrorImpl}; +use serde::de::{Unexpected, Visitor}; +use serde::{forward_to_deserialize_any, Deserialize, Deserializer, Serialize, Serializer}; +use std::cmp::Ordering; +use std::fmt::{self, Display}; +use std::hash::{Hash, Hasher}; +use std::str::FromStr; + +/// Represents a YAML number, whether integer or floating point. +#[derive(Clone, PartialEq, PartialOrd)] +pub struct Number { + n: N, +} + +// "N" is a prefix of "NegInt"... this is a false positive. +// https://github.com/Manishearth/rust-clippy/issues/1241 +#[allow(clippy::enum_variant_names)] +#[derive(Copy, Clone)] +enum N { + PosInt(u64), + /// Always less than zero. + NegInt(i64), + /// May be infinite or NaN. + Float(f64), +} + +impl Number { + /// Returns true if the `Number` is an integer between `i64::MIN` and + /// `i64::MAX`. + /// + /// For any Number on which `is_i64` returns true, `as_i64` is guaranteed to + /// return the integer value. + /// + /// ``` + /// # fn main() -> serde_yaml::Result<()> { + /// let big = i64::MAX as u64 + 10; + /// let v: serde_yaml::Value = serde_yaml::from_str(r#" + /// a: 64 + /// b: 9223372036854775817 + /// c: 256.0 + /// "#)?; + /// + /// assert!(v["a"].is_i64()); + /// + /// // Greater than i64::MAX. + /// assert!(!v["b"].is_i64()); + /// + /// // Numbers with a decimal point are not considered integers. + /// assert!(!v["c"].is_i64()); + /// # Ok(()) + /// # } + /// ``` + #[inline] + #[allow(clippy::cast_sign_loss)] + pub fn is_i64(&self) -> bool { + match self.n { + N::PosInt(v) => v <= i64::max_value() as u64, + N::NegInt(_) => true, + N::Float(_) => false, + } + } + + /// Returns true if the `Number` is an integer between zero and `u64::MAX`. + /// + /// For any Number on which `is_u64` returns true, `as_u64` is guaranteed to + /// return the integer value. + /// + /// ``` + /// # fn main() -> serde_yaml::Result<()> { + /// let v: serde_yaml::Value = serde_yaml::from_str(r#" + /// a: 64 + /// b: -64 + /// c: 256.0 + /// "#)?; + /// + /// assert!(v["a"].is_u64()); + /// + /// // Negative integer. + /// assert!(!v["b"].is_u64()); + /// + /// // Numbers with a decimal point are not considered integers. + /// assert!(!v["c"].is_u64()); + /// # Ok(()) + /// # } + /// ``` + #[inline] + pub fn is_u64(&self) -> bool { + match self.n { + N::PosInt(_) => true, + N::NegInt(_) | N::Float(_) => false, + } + } + + /// Returns true if the `Number` can be represented by f64. + /// + /// For any Number on which `is_f64` returns true, `as_f64` is guaranteed to + /// return the floating point value. + /// + /// Currently this function returns true if and only if both `is_i64` and + /// `is_u64` return false but this is not a guarantee in the future. + /// + /// ``` + /// # fn main() -> serde_yaml::Result<()> { + /// let v: serde_yaml::Value = serde_yaml::from_str(r#" + /// a: 256.0 + /// b: 64 + /// c: -64 + /// "#)?; + /// + /// assert!(v["a"].is_f64()); + /// + /// // Integers. + /// assert!(!v["b"].is_f64()); + /// assert!(!v["c"].is_f64()); + /// # Ok(()) + /// # } + /// ``` + #[inline] + pub fn is_f64(&self) -> bool { + match self.n { + N::Float(_) => true, + N::PosInt(_) | N::NegInt(_) => false, + } + } + + /// If the `Number` is an integer, represent it as i64 if possible. Returns + /// None otherwise. + /// + /// ``` + /// # fn main() -> serde_yaml::Result<()> { + /// let big = i64::MAX as u64 + 10; + /// let v: serde_yaml::Value = serde_yaml::from_str(r#" + /// a: 64 + /// b: 9223372036854775817 + /// c: 256.0 + /// "#)?; + /// + /// assert_eq!(v["a"].as_i64(), Some(64)); + /// assert_eq!(v["b"].as_i64(), None); + /// assert_eq!(v["c"].as_i64(), None); + /// # Ok(()) + /// # } + /// ``` + #[inline] + pub fn as_i64(&self) -> Option { + match self.n { + N::PosInt(n) => { + if n <= i64::max_value() as u64 { + Some(n as i64) + } else { + None + } + } + N::NegInt(n) => Some(n), + N::Float(_) => None, + } + } + + /// If the `Number` is an integer, represent it as u64 if possible. Returns + /// None otherwise. + /// + /// ``` + /// # fn main() -> serde_yaml::Result<()> { + /// let v: serde_yaml::Value = serde_yaml::from_str(r#" + /// a: 64 + /// b: -64 + /// c: 256.0 + /// "#)?; + /// + /// assert_eq!(v["a"].as_u64(), Some(64)); + /// assert_eq!(v["b"].as_u64(), None); + /// assert_eq!(v["c"].as_u64(), None); + /// # Ok(()) + /// # } + /// ``` + #[inline] + pub fn as_u64(&self) -> Option { + match self.n { + N::PosInt(n) => Some(n), + N::NegInt(_) | N::Float(_) => None, + } + } + + /// Represents the number as f64 if possible. Returns None otherwise. + /// + /// ``` + /// # fn main() -> serde_yaml::Result<()> { + /// let v: serde_yaml::Value = serde_yaml::from_str(r#" + /// a: 256.0 + /// b: 64 + /// c: -64 + /// "#)?; + /// + /// assert_eq!(v["a"].as_f64(), Some(256.0)); + /// assert_eq!(v["b"].as_f64(), Some(64.0)); + /// assert_eq!(v["c"].as_f64(), Some(-64.0)); + /// # Ok(()) + /// # } + /// ``` + /// + /// ``` + /// # fn main() -> serde_yaml::Result<()> { + /// let v: serde_yaml::Value = serde_yaml::from_str(".inf")?; + /// assert_eq!(v.as_f64(), Some(f64::INFINITY)); + /// + /// let v: serde_yaml::Value = serde_yaml::from_str("-.inf")?; + /// assert_eq!(v.as_f64(), Some(f64::NEG_INFINITY)); + /// + /// let v: serde_yaml::Value = serde_yaml::from_str(".nan")?; + /// assert!(v.as_f64().unwrap().is_nan()); + /// # Ok(()) + /// # } + /// ``` + #[inline] + pub fn as_f64(&self) -> Option { + match self.n { + N::PosInt(n) => Some(n as f64), + N::NegInt(n) => Some(n as f64), + N::Float(n) => Some(n), + } + } + + /// Returns true if this value is NaN and false otherwise. + /// + /// ``` + /// # use serde_yaml::Number; + /// # + /// assert!(!Number::from(256.0).is_nan()); + /// + /// assert!(Number::from(f64::NAN).is_nan()); + /// + /// assert!(!Number::from(f64::INFINITY).is_nan()); + /// + /// assert!(!Number::from(f64::NEG_INFINITY).is_nan()); + /// + /// assert!(!Number::from(1).is_nan()); + /// ``` + #[inline] + pub fn is_nan(&self) -> bool { + match self.n { + N::PosInt(_) | N::NegInt(_) => false, + N::Float(f) => f.is_nan(), + } + } + + /// Returns true if this value is positive infinity or negative infinity and + /// false otherwise. + /// + /// ``` + /// # use serde_yaml::Number; + /// # + /// assert!(!Number::from(256.0).is_infinite()); + /// + /// assert!(!Number::from(f64::NAN).is_infinite()); + /// + /// assert!(Number::from(f64::INFINITY).is_infinite()); + /// + /// assert!(Number::from(f64::NEG_INFINITY).is_infinite()); + /// + /// assert!(!Number::from(1).is_infinite()); + /// ``` + #[inline] + pub fn is_infinite(&self) -> bool { + match self.n { + N::PosInt(_) | N::NegInt(_) => false, + N::Float(f) => f.is_infinite(), + } + } + + /// Returns true if this number is neither infinite nor NaN. + /// + /// ``` + /// # use serde_yaml::Number; + /// # + /// assert!(Number::from(256.0).is_finite()); + /// + /// assert!(!Number::from(f64::NAN).is_finite()); + /// + /// assert!(!Number::from(f64::INFINITY).is_finite()); + /// + /// assert!(!Number::from(f64::NEG_INFINITY).is_finite()); + /// + /// assert!(Number::from(1).is_finite()); + /// ``` + #[inline] + pub fn is_finite(&self) -> bool { + match self.n { + N::PosInt(_) | N::NegInt(_) => true, + N::Float(f) => f.is_finite(), + } + } +} + +impl Display for Number { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + match self.n { + N::PosInt(i) => formatter.write_str(itoa::Buffer::new().format(i)), + N::NegInt(i) => formatter.write_str(itoa::Buffer::new().format(i)), + N::Float(f) if f.is_nan() => formatter.write_str(".nan"), + N::Float(f) if f.is_infinite() => { + if f.is_sign_negative() { + formatter.write_str("-.inf") + } else { + formatter.write_str(".inf") + } + } + N::Float(f) => formatter.write_str(ryu::Buffer::new().format_finite(f)), + } + } +} + +impl FromStr for Number { + type Err = Error; + + fn from_str(repr: &str) -> Result { + if let Ok(result) = de::visit_int(NumberVisitor, repr) { + return result; + } + if !de::digits_but_not_number(repr) { + if let Some(float) = de::parse_f64(repr) { + return Ok(float.into()); + } + } + Err(error::new(ErrorImpl::FailedToParseNumber)) + } +} + +impl PartialEq for N { + fn eq(&self, other: &N) -> bool { + match (*self, *other) { + (N::PosInt(a), N::PosInt(b)) => a == b, + (N::NegInt(a), N::NegInt(b)) => a == b, + (N::Float(a), N::Float(b)) => { + if a.is_nan() && b.is_nan() { + // YAML only has one NaN; + // the bit representation isn't preserved + true + } else { + a == b + } + } + _ => false, + } + } +} + +impl PartialOrd for N { + fn partial_cmp(&self, other: &Self) -> Option { + match (*self, *other) { + (N::Float(a), N::Float(b)) => { + if a.is_nan() && b.is_nan() { + // YAML only has one NaN + Some(Ordering::Equal) + } else { + a.partial_cmp(&b) + } + } + _ => Some(self.total_cmp(other)), + } + } +} + +impl N { + fn total_cmp(&self, other: &Self) -> Ordering { + match (*self, *other) { + (N::PosInt(a), N::PosInt(b)) => a.cmp(&b), + (N::NegInt(a), N::NegInt(b)) => a.cmp(&b), + // negint is always less than zero + (N::NegInt(_), N::PosInt(_)) => Ordering::Less, + (N::PosInt(_), N::NegInt(_)) => Ordering::Greater, + (N::Float(a), N::Float(b)) => a.partial_cmp(&b).unwrap_or_else(|| { + // arbitrarily sort the NaN last + if !a.is_nan() { + Ordering::Less + } else if !b.is_nan() { + Ordering::Greater + } else { + Ordering::Equal + } + }), + // arbitrarily sort integers below floats + // FIXME: maybe something more sensible? + (_, N::Float(_)) => Ordering::Less, + (N::Float(_), _) => Ordering::Greater, + } + } +} + +impl Number { + pub(crate) fn total_cmp(&self, other: &Self) -> Ordering { + self.n.total_cmp(&other.n) + } +} + +impl Serialize for Number { + #[inline] + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + match self.n { + N::PosInt(i) => serializer.serialize_u64(i), + N::NegInt(i) => serializer.serialize_i64(i), + N::Float(f) => serializer.serialize_f64(f), + } + } +} + +struct NumberVisitor; + +impl<'de> Visitor<'de> for NumberVisitor { + type Value = Number; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a number") + } + + #[inline] + fn visit_i64(self, value: i64) -> Result { + Ok(value.into()) + } + + #[inline] + fn visit_u64(self, value: u64) -> Result { + Ok(value.into()) + } + + #[inline] + fn visit_f64(self, value: f64) -> Result { + Ok(value.into()) + } +} + +impl<'de> Deserialize<'de> for Number { + #[inline] + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_any(NumberVisitor) + } +} + +impl<'de> Deserializer<'de> for Number { + type Error = Error; + + #[inline] + fn deserialize_any(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + match self.n { + N::PosInt(i) => visitor.visit_u64(i), + N::NegInt(i) => visitor.visit_i64(i), + N::Float(f) => visitor.visit_f64(f), + } + } + + forward_to_deserialize_any! { + bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string + bytes byte_buf option unit unit_struct newtype_struct seq tuple + tuple_struct map struct enum identifier ignored_any + } +} + +impl<'de, 'a> Deserializer<'de> for &'a Number { + type Error = Error; + + #[inline] + fn deserialize_any(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + match self.n { + N::PosInt(i) => visitor.visit_u64(i), + N::NegInt(i) => visitor.visit_i64(i), + N::Float(f) => visitor.visit_f64(f), + } + } + + forward_to_deserialize_any! { + bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string + bytes byte_buf option unit unit_struct newtype_struct seq tuple + tuple_struct map struct enum identifier ignored_any + } +} + +macro_rules! from_signed { + ($($signed_ty:ident)*) => { + $( + impl From<$signed_ty> for Number { + #[inline] + #[allow(clippy::cast_sign_loss)] + fn from(i: $signed_ty) -> Self { + if i < 0 { + Number { n: N::NegInt(i as i64) } + } else { + Number { n: N::PosInt(i as u64) } + } + } + } + )* + }; +} + +macro_rules! from_unsigned { + ($($unsigned_ty:ident)*) => { + $( + impl From<$unsigned_ty> for Number { + #[inline] + fn from(u: $unsigned_ty) -> Self { + Number { n: N::PosInt(u as u64) } + } + } + )* + }; +} + +from_signed!(i8 i16 i32 i64 isize); +from_unsigned!(u8 u16 u32 u64 usize); + +impl From for Number { + fn from(f: f32) -> Self { + Number::from(f as f64) + } +} + +impl From for Number { + fn from(mut f: f64) -> Self { + if f.is_nan() { + // Destroy NaN sign, signaling, and payload. YAML only has one NaN. + f = f64::NAN.copysign(1.0); + } + Number { n: N::Float(f) } + } +} + +// This is fine, because we don't _really_ implement hash for floats +// all other hash functions should work as expected +#[allow(clippy::derived_hash_with_manual_eq)] +impl Hash for Number { + fn hash(&self, state: &mut H) { + match self.n { + N::Float(_) => { + // you should feel bad for using f64 as a map key + 3.hash(state); + } + N::PosInt(u) => u.hash(state), + N::NegInt(i) => i.hash(state), + } + } +} + +pub(crate) fn unexpected(number: &Number) -> Unexpected { + match number.n { + N::PosInt(u) => Unexpected::Unsigned(u), + N::NegInt(i) => Unexpected::Signed(i), + N::Float(f) => Unexpected::Float(f), + } +} diff --git a/kclvm/third-party/serde_yaml/src/path.rs b/kclvm/third-party/serde_yaml/src/path.rs new file mode 100644 index 000000000..095add017 --- /dev/null +++ b/kclvm/third-party/serde_yaml/src/path.rs @@ -0,0 +1,34 @@ +use std::fmt::{self, Display}; + +/// Path to the current value in the input, like `dependencies.serde.typo1`. +#[derive(Copy, Clone)] +pub enum Path<'a> { + Root, + Seq { parent: &'a Path<'a>, index: usize }, + Map { parent: &'a Path<'a>, key: &'a str }, + Alias { parent: &'a Path<'a> }, + Unknown { parent: &'a Path<'a> }, +} + +impl<'a> Display for Path<'a> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> { + struct Parent<'a>(&'a Path<'a>); + + impl<'a> Display for Parent<'a> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> { + match self.0 { + Path::Root => Ok(()), + path => write!(formatter, "{}.", path), + } + } + } + + match self { + Path::Root => formatter.write_str("."), + Path::Seq { parent, index } => write!(formatter, "{}[{}]", parent, index), + Path::Map { parent, key } => write!(formatter, "{}{}", Parent(parent), key), + Path::Alias { parent } => write!(formatter, "{}", parent), + Path::Unknown { parent } => write!(formatter, "{}?", Parent(parent)), + } + } +} diff --git a/kclvm/third-party/serde_yaml/src/ser.rs b/kclvm/third-party/serde_yaml/src/ser.rs new file mode 100644 index 000000000..08b0567a3 --- /dev/null +++ b/kclvm/third-party/serde_yaml/src/ser.rs @@ -0,0 +1,714 @@ +//! YAML Serialization +//! +//! This module provides YAML serialization with the type `Serializer`. + +use crate::error::{self, Error, ErrorImpl}; +use crate::libyaml; +use crate::libyaml::emitter::{Emitter, Event, Mapping, Scalar, ScalarStyle, Sequence}; +use crate::value::tagged::{self, MaybeTag}; +use serde::de::Visitor; +use serde::ser::{self, Serializer as _}; +use std::fmt::{self, Display}; +use std::io; +use std::marker::PhantomData; +use std::mem; +use std::num; +use std::str; + +type Result = std::result::Result; + +/// A structure for serializing Rust values into YAML. +/// +/// # Example +/// +/// ``` +/// use anyhow::Result; +/// use serde::Serialize; +/// use std::collections::BTreeMap; +/// +/// fn main() -> Result<()> { +/// let mut buffer = Vec::new(); +/// let mut ser = serde_yaml::Serializer::new(&mut buffer); +/// +/// let mut object = BTreeMap::new(); +/// object.insert("k", 107); +/// object.serialize(&mut ser)?; +/// +/// object.insert("J", 74); +/// object.serialize(&mut ser)?; +/// +/// assert_eq!(buffer, b"k: 107\n---\nJ: 74\nk: 107\n"); +/// Ok(()) +/// } +/// ``` +pub struct Serializer { + depth: usize, + state: State, + emitter: Emitter<'static>, + writer: PhantomData, +} + +enum State { + NothingInParticular, + CheckForTag, + CheckForDuplicateTag, + FoundTag(String), + AlreadyTagged, +} + +impl Serializer +where + W: io::Write, +{ + /// Creates a new YAML serializer. + pub fn new(writer: W) -> Self { + let mut emitter = Emitter::new({ + let writer = Box::new(writer); + unsafe { mem::transmute::, Box>(writer) } + }); + emitter.emit(Event::StreamStart).unwrap(); + Serializer { + depth: 0, + state: State::NothingInParticular, + emitter, + writer: PhantomData, + } + } + + /// Calls [`.flush()`](io::Write::flush) on the underlying `io::Write` + /// object. + pub fn flush(&mut self) -> Result<()> { + self.emitter.flush()?; + Ok(()) + } + + /// Unwrap the underlying `io::Write` object from the `Serializer`. + pub fn into_inner(mut self) -> Result { + self.emitter.emit(Event::StreamEnd)?; + self.emitter.flush()?; + let writer = self.emitter.into_inner(); + Ok(*unsafe { Box::from_raw(Box::into_raw(writer).cast::()) }) + } + + fn emit_scalar(&mut self, mut scalar: Scalar) -> Result<()> { + self.flush_mapping_start()?; + if let Some(tag) = self.take_tag() { + scalar.tag = Some(tag); + } + self.value_start()?; + self.emitter.emit(Event::Scalar(scalar))?; + self.value_end() + } + + fn emit_sequence_start(&mut self) -> Result<()> { + self.flush_mapping_start()?; + self.value_start()?; + let tag = self.take_tag(); + self.emitter.emit(Event::SequenceStart(Sequence { tag }))?; + Ok(()) + } + + fn emit_sequence_end(&mut self) -> Result<()> { + self.emitter.emit(Event::SequenceEnd)?; + self.value_end() + } + + fn emit_mapping_start(&mut self) -> Result<()> { + self.flush_mapping_start()?; + self.value_start()?; + let tag = self.take_tag(); + self.emitter.emit(Event::MappingStart(Mapping { tag }))?; + Ok(()) + } + + fn emit_mapping_end(&mut self) -> Result<()> { + self.emitter.emit(Event::MappingEnd)?; + self.value_end() + } + + fn value_start(&mut self) -> Result<()> { + if self.depth == 0 { + self.emitter.emit(Event::DocumentStart)?; + } + self.depth += 1; + Ok(()) + } + + fn value_end(&mut self) -> Result<()> { + self.depth -= 1; + if self.depth == 0 { + self.emitter.emit(Event::DocumentEnd)?; + } + Ok(()) + } + + fn take_tag(&mut self) -> Option { + let state = mem::replace(&mut self.state, State::NothingInParticular); + if let State::FoundTag(mut tag) = state { + if !tag.starts_with('!') { + tag.insert(0, '!'); + } + Some(tag) + } else { + self.state = state; + None + } + } + + fn flush_mapping_start(&mut self) -> Result<()> { + if let State::CheckForTag = self.state { + self.state = State::NothingInParticular; + self.emit_mapping_start()?; + } else if let State::CheckForDuplicateTag = self.state { + self.state = State::NothingInParticular; + } + Ok(()) + } +} + +impl<'a, W> ser::Serializer for &'a mut Serializer +where + W: io::Write, +{ + type Ok = (); + type Error = Error; + + type SerializeSeq = Self; + type SerializeTuple = Self; + type SerializeTupleStruct = Self; + type SerializeTupleVariant = Self; + type SerializeMap = Self; + type SerializeStruct = Self; + type SerializeStructVariant = Self; + + fn serialize_bool(self, v: bool) -> Result<()> { + self.emit_scalar(Scalar { + tag: None, + value: if v { "true" } else { "false" }, + style: ScalarStyle::Plain, + }) + } + + fn serialize_i8(self, v: i8) -> Result<()> { + self.emit_scalar(Scalar { + tag: None, + value: itoa::Buffer::new().format(v), + style: ScalarStyle::Plain, + }) + } + + fn serialize_i16(self, v: i16) -> Result<()> { + self.emit_scalar(Scalar { + tag: None, + value: itoa::Buffer::new().format(v), + style: ScalarStyle::Plain, + }) + } + + fn serialize_i32(self, v: i32) -> Result<()> { + self.emit_scalar(Scalar { + tag: None, + value: itoa::Buffer::new().format(v), + style: ScalarStyle::Plain, + }) + } + + fn serialize_i64(self, v: i64) -> Result<()> { + self.emit_scalar(Scalar { + tag: None, + value: itoa::Buffer::new().format(v), + style: ScalarStyle::Plain, + }) + } + + fn serialize_i128(self, v: i128) -> Result<()> { + self.emit_scalar(Scalar { + tag: None, + value: itoa::Buffer::new().format(v), + style: ScalarStyle::Plain, + }) + } + + fn serialize_u8(self, v: u8) -> Result<()> { + self.emit_scalar(Scalar { + tag: None, + value: itoa::Buffer::new().format(v), + style: ScalarStyle::Plain, + }) + } + + fn serialize_u16(self, v: u16) -> Result<()> { + self.emit_scalar(Scalar { + tag: None, + value: itoa::Buffer::new().format(v), + style: ScalarStyle::Plain, + }) + } + + fn serialize_u32(self, v: u32) -> Result<()> { + self.emit_scalar(Scalar { + tag: None, + value: itoa::Buffer::new().format(v), + style: ScalarStyle::Plain, + }) + } + + fn serialize_u64(self, v: u64) -> Result<()> { + self.emit_scalar(Scalar { + tag: None, + value: itoa::Buffer::new().format(v), + style: ScalarStyle::Plain, + }) + } + + fn serialize_u128(self, v: u128) -> Result<()> { + self.emit_scalar(Scalar { + tag: None, + value: itoa::Buffer::new().format(v), + style: ScalarStyle::Plain, + }) + } + + fn serialize_f32(self, v: f32) -> Result<()> { + let mut buffer = ryu::Buffer::new(); + self.emit_scalar(Scalar { + tag: None, + value: match v.classify() { + num::FpCategory::Infinite if v.is_sign_positive() => ".inf", + num::FpCategory::Infinite => "-.inf", + num::FpCategory::Nan => ".nan", + _ => buffer.format_finite(v), + }, + style: ScalarStyle::Plain, + }) + } + + fn serialize_f64(self, v: f64) -> Result<()> { + let mut buffer = ryu::Buffer::new(); + self.emit_scalar(Scalar { + tag: None, + value: match v.classify() { + num::FpCategory::Infinite if v.is_sign_positive() => ".inf", + num::FpCategory::Infinite => "-.inf", + num::FpCategory::Nan => ".nan", + _ => buffer.format_finite(v), + }, + style: ScalarStyle::Plain, + }) + } + + fn serialize_char(self, value: char) -> Result<()> { + self.emit_scalar(Scalar { + tag: None, + value: value.encode_utf8(&mut [0u8; 4]), + style: ScalarStyle::SingleQuoted, + }) + } + + fn serialize_str(self, value: &str) -> Result<()> { + struct InferScalarStyle; + + impl<'de> Visitor<'de> for InferScalarStyle { + type Value = ScalarStyle; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("I wonder") + } + + fn visit_bool(self, _v: bool) -> Result { + Ok(ScalarStyle::SingleQuoted) + } + + fn visit_i64(self, _v: i64) -> Result { + Ok(ScalarStyle::SingleQuoted) + } + + fn visit_i128(self, _v: i128) -> Result { + Ok(ScalarStyle::SingleQuoted) + } + + fn visit_u64(self, _v: u64) -> Result { + Ok(ScalarStyle::SingleQuoted) + } + + fn visit_u128(self, _v: u128) -> Result { + Ok(ScalarStyle::SingleQuoted) + } + + fn visit_f64(self, _v: f64) -> Result { + Ok(ScalarStyle::SingleQuoted) + } + + fn visit_str(self, v: &str) -> Result { + if crate::de::ambiguous_string(v) { + Ok(ScalarStyle::SingleQuoted) + } else { + Ok(ScalarStyle::Any) + } + } + + fn visit_unit(self) -> Result { + Ok(ScalarStyle::SingleQuoted) + } + } + + let style = if value.contains('\n') { + ScalarStyle::Literal + } else { + let result = crate::de::visit_untagged_scalar( + InferScalarStyle, + value, + None, + libyaml::parser::ScalarStyle::Plain, + ); + result.unwrap_or(ScalarStyle::Any) + }; + + self.emit_scalar(Scalar { + tag: None, + value, + style, + }) + } + + fn serialize_bytes(self, _value: &[u8]) -> Result<()> { + Err(error::new(ErrorImpl::BytesUnsupported)) + } + + fn serialize_unit(self) -> Result<()> { + self.emit_scalar(Scalar { + tag: None, + value: "null", + style: ScalarStyle::Plain, + }) + } + + fn serialize_unit_struct(self, _name: &'static str) -> Result<()> { + self.serialize_unit() + } + + fn serialize_unit_variant( + self, + _name: &'static str, + _variant_index: u32, + variant: &'static str, + ) -> Result<()> { + self.serialize_str(variant) + } + + fn serialize_newtype_struct(self, _name: &'static str, value: &T) -> Result<()> + where + T: ?Sized + ser::Serialize, + { + value.serialize(self) + } + + fn serialize_newtype_variant( + self, + _name: &'static str, + _variant_index: u32, + variant: &'static str, + value: &T, + ) -> Result<()> + where + T: ?Sized + ser::Serialize, + { + if let State::FoundTag(_) = self.state { + return Err(error::new(ErrorImpl::SerializeNestedEnum)); + } + self.state = State::FoundTag(variant.to_owned()); + value.serialize(&mut *self) + } + + fn serialize_none(self) -> Result<()> { + self.serialize_unit() + } + + fn serialize_some(self, value: &V) -> Result<()> + where + V: ?Sized + ser::Serialize, + { + value.serialize(self) + } + + fn serialize_seq(self, _len: Option) -> Result { + self.emit_sequence_start()?; + Ok(self) + } + + fn serialize_tuple(self, _len: usize) -> Result { + self.emit_sequence_start()?; + Ok(self) + } + + fn serialize_tuple_struct( + self, + _name: &'static str, + _len: usize, + ) -> Result { + self.emit_sequence_start()?; + Ok(self) + } + + fn serialize_tuple_variant( + self, + _enm: &'static str, + _idx: u32, + variant: &'static str, + _len: usize, + ) -> Result { + if let State::FoundTag(_) = self.state { + return Err(error::new(ErrorImpl::SerializeNestedEnum)); + } + self.state = State::FoundTag(variant.to_owned()); + self.emit_sequence_start()?; + Ok(self) + } + + fn serialize_map(self, len: Option) -> Result { + if len == Some(1) { + self.state = if let State::FoundTag(_) = self.state { + self.emit_mapping_start()?; + State::CheckForDuplicateTag + } else { + State::CheckForTag + }; + } else { + self.emit_mapping_start()?; + } + Ok(self) + } + + fn serialize_struct(self, _name: &'static str, _len: usize) -> Result { + self.emit_mapping_start()?; + Ok(self) + } + + fn serialize_struct_variant( + self, + _enm: &'static str, + _idx: u32, + variant: &'static str, + _len: usize, + ) -> Result { + if let State::FoundTag(_) = self.state { + return Err(error::new(ErrorImpl::SerializeNestedEnum)); + } + self.state = State::FoundTag(variant.to_owned()); + self.emit_mapping_start()?; + Ok(self) + } + + fn collect_str(self, value: &T) -> Result + where + T: ?Sized + Display, + { + let string = if let State::CheckForTag | State::CheckForDuplicateTag = self.state { + match tagged::check_for_tag(value) { + MaybeTag::NotTag(string) => string, + MaybeTag::Tag(string) => { + return if let State::CheckForDuplicateTag = self.state { + Err(error::new(ErrorImpl::SerializeNestedEnum)) + } else { + self.state = State::FoundTag(string); + Ok(()) + }; + } + } + } else { + value.to_string() + }; + + self.serialize_str(&string) + } +} + +impl<'a, W> ser::SerializeSeq for &'a mut Serializer +where + W: io::Write, +{ + type Ok = (); + type Error = Error; + + fn serialize_element(&mut self, elem: &T) -> Result<()> + where + T: ?Sized + ser::Serialize, + { + elem.serialize(&mut **self) + } + + fn end(self) -> Result<()> { + self.emit_sequence_end() + } +} + +impl<'a, W> ser::SerializeTuple for &'a mut Serializer +where + W: io::Write, +{ + type Ok = (); + type Error = Error; + + fn serialize_element(&mut self, elem: &T) -> Result<()> + where + T: ?Sized + ser::Serialize, + { + elem.serialize(&mut **self) + } + + fn end(self) -> Result<()> { + self.emit_sequence_end() + } +} + +impl<'a, W> ser::SerializeTupleStruct for &'a mut Serializer +where + W: io::Write, +{ + type Ok = (); + type Error = Error; + + fn serialize_field(&mut self, value: &V) -> Result<()> + where + V: ?Sized + ser::Serialize, + { + value.serialize(&mut **self) + } + + fn end(self) -> Result<()> { + self.emit_sequence_end() + } +} + +impl<'a, W> ser::SerializeTupleVariant for &'a mut Serializer +where + W: io::Write, +{ + type Ok = (); + type Error = Error; + + fn serialize_field(&mut self, v: &V) -> Result<()> + where + V: ?Sized + ser::Serialize, + { + v.serialize(&mut **self) + } + + fn end(self) -> Result<()> { + self.emit_sequence_end() + } +} + +impl<'a, W> ser::SerializeMap for &'a mut Serializer +where + W: io::Write, +{ + type Ok = (); + type Error = Error; + + fn serialize_key(&mut self, key: &T) -> Result<()> + where + T: ?Sized + ser::Serialize, + { + self.flush_mapping_start()?; + key.serialize(&mut **self) + } + + fn serialize_value(&mut self, value: &T) -> Result<()> + where + T: ?Sized + ser::Serialize, + { + value.serialize(&mut **self) + } + + fn serialize_entry(&mut self, key: &K, value: &V) -> Result<(), Self::Error> + where + K: ?Sized + ser::Serialize, + V: ?Sized + ser::Serialize, + { + key.serialize(&mut **self)?; + let tagged = matches!(self.state, State::FoundTag(_)); + value.serialize(&mut **self)?; + if tagged { + self.state = State::AlreadyTagged; + } + Ok(()) + } + + fn end(self) -> Result<()> { + if let State::CheckForTag = self.state { + self.emit_mapping_start()?; + } + if !matches!(self.state, State::AlreadyTagged) { + self.emit_mapping_end()?; + } + self.state = State::NothingInParticular; + Ok(()) + } +} + +impl<'a, W> ser::SerializeStruct for &'a mut Serializer +where + W: io::Write, +{ + type Ok = (); + type Error = Error; + + fn serialize_field(&mut self, key: &'static str, value: &V) -> Result<()> + where + V: ?Sized + ser::Serialize, + { + self.serialize_str(key)?; + value.serialize(&mut **self) + } + + fn end(self) -> Result<()> { + self.emit_mapping_end() + } +} + +impl<'a, W> ser::SerializeStructVariant for &'a mut Serializer +where + W: io::Write, +{ + type Ok = (); + type Error = Error; + + fn serialize_field(&mut self, field: &'static str, v: &V) -> Result<()> + where + V: ?Sized + ser::Serialize, + { + self.serialize_str(field)?; + v.serialize(&mut **self) + } + + fn end(self) -> Result<()> { + self.emit_mapping_end() + } +} + +/// Serialize the given data structure as YAML into the IO stream. +/// +/// Serialization can fail if `T`'s implementation of `Serialize` decides to +/// return an error. +pub fn to_writer(writer: W, value: &T) -> Result<()> +where + W: io::Write, + T: ?Sized + ser::Serialize, +{ + let mut serializer = Serializer::new(writer); + value.serialize(&mut serializer) +} + +/// Serialize the given data structure as a String of YAML. +/// +/// Serialization can fail if `T`'s implementation of `Serialize` decides to +/// return an error. +pub fn to_string(value: &T) -> Result +where + T: ?Sized + ser::Serialize, +{ + let mut vec = Vec::with_capacity(128); + to_writer(&mut vec, value)?; + String::from_utf8(vec).map_err(|error| error::new(ErrorImpl::FromUtf8(error))) +} diff --git a/kclvm/third-party/serde_yaml/src/value/de.rs b/kclvm/third-party/serde_yaml/src/value/de.rs new file mode 100644 index 000000000..b1ff57696 --- /dev/null +++ b/kclvm/third-party/serde_yaml/src/value/de.rs @@ -0,0 +1,1242 @@ +use crate::value::tagged::{self, TagStringVisitor}; +use crate::value::TaggedValue; +use crate::{number, Error, Mapping, Sequence, Value}; +use serde::de::value::{BorrowedStrDeserializer, StrDeserializer}; +use serde::de::{ + self, Deserialize, DeserializeSeed, Deserializer, EnumAccess, Error as _, Expected, MapAccess, + SeqAccess, Unexpected, VariantAccess, Visitor, +}; +use serde::forward_to_deserialize_any; +use std::fmt; +use std::slice; +use std::vec; + +impl<'de> Deserialize<'de> for Value { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct ValueVisitor; + + impl<'de> Visitor<'de> for ValueVisitor { + type Value = Value; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("any YAML value") + } + + fn visit_bool(self, b: bool) -> Result + where + E: de::Error, + { + Ok(Value::Bool(b)) + } + + fn visit_i64(self, i: i64) -> Result + where + E: de::Error, + { + Ok(Value::Number(i.into())) + } + + fn visit_u64(self, u: u64) -> Result + where + E: de::Error, + { + Ok(Value::Number(u.into())) + } + + fn visit_f64(self, f: f64) -> Result + where + E: de::Error, + { + Ok(Value::Number(f.into())) + } + + fn visit_str(self, s: &str) -> Result + where + E: de::Error, + { + Ok(Value::String(s.to_owned())) + } + + fn visit_string(self, s: String) -> Result + where + E: de::Error, + { + Ok(Value::String(s)) + } + + fn visit_unit(self) -> Result + where + E: de::Error, + { + Ok(Value::Null) + } + + fn visit_none(self) -> Result + where + E: de::Error, + { + Ok(Value::Null) + } + + fn visit_some(self, deserializer: D) -> Result + where + D: Deserializer<'de>, + { + Deserialize::deserialize(deserializer) + } + + fn visit_seq(self, data: A) -> Result + where + A: SeqAccess<'de>, + { + let de = serde::de::value::SeqAccessDeserializer::new(data); + let sequence = Sequence::deserialize(de)?; + Ok(Value::Sequence(sequence)) + } + + fn visit_map(self, data: A) -> Result + where + A: MapAccess<'de>, + { + let de = serde::de::value::MapAccessDeserializer::new(data); + let mapping = Mapping::deserialize(de)?; + Ok(Value::Mapping(mapping)) + } + + fn visit_enum(self, data: A) -> Result + where + A: EnumAccess<'de>, + { + let (tag, contents) = data.variant_seed(TagStringVisitor)?; + let value = contents.newtype_variant()?; + Ok(Value::Tagged(Box::new(TaggedValue { tag, value }))) + } + } + + deserializer.deserialize_any(ValueVisitor) + } +} + +impl Value { + fn deserialize_number<'de, V>(&self, visitor: V) -> Result + where + V: Visitor<'de>, + { + match self.untag_ref() { + Value::Number(n) => n.deserialize_any(visitor), + other => Err(other.invalid_type(&visitor)), + } + } +} + +fn visit_sequence<'de, V>(sequence: Sequence, visitor: V) -> Result +where + V: Visitor<'de>, +{ + let len = sequence.len(); + let mut deserializer = SeqDeserializer::new(sequence); + let seq = visitor.visit_seq(&mut deserializer)?; + let remaining = deserializer.iter.len(); + if remaining == 0 { + Ok(seq) + } else { + Err(Error::invalid_length(len, &"fewer elements in sequence")) + } +} + +fn visit_sequence_ref<'de, V>(sequence: &'de Sequence, visitor: V) -> Result +where + V: Visitor<'de>, +{ + let len = sequence.len(); + let mut deserializer = SeqRefDeserializer::new(sequence); + let seq = visitor.visit_seq(&mut deserializer)?; + let remaining = deserializer.iter.len(); + if remaining == 0 { + Ok(seq) + } else { + Err(Error::invalid_length(len, &"fewer elements in sequence")) + } +} + +fn visit_mapping<'de, V>(mapping: Mapping, visitor: V) -> Result +where + V: Visitor<'de>, +{ + let len = mapping.len(); + let mut deserializer = MapDeserializer::new(mapping); + let map = visitor.visit_map(&mut deserializer)?; + let remaining = deserializer.iter.len(); + if remaining == 0 { + Ok(map) + } else { + Err(Error::invalid_length(len, &"fewer elements in map")) + } +} + +fn visit_mapping_ref<'de, V>(mapping: &'de Mapping, visitor: V) -> Result +where + V: Visitor<'de>, +{ + let len = mapping.len(); + let mut deserializer = MapRefDeserializer::new(mapping); + let map = visitor.visit_map(&mut deserializer)?; + let remaining = deserializer.iter.unwrap().len(); + if remaining == 0 { + Ok(map) + } else { + Err(Error::invalid_length(len, &"fewer elements in map")) + } +} + +impl<'de> Deserializer<'de> for Value { + type Error = Error; + + fn deserialize_any(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + match self { + Value::Null => visitor.visit_unit(), + Value::Bool(v) => visitor.visit_bool(v), + Value::Number(n) => n.deserialize_any(visitor), + Value::String(v) => visitor.visit_string(v), + Value::Sequence(v) => visit_sequence(v, visitor), + Value::Mapping(v) => visit_mapping(v, visitor), + Value::Tagged(tagged) => visitor.visit_enum(*tagged), + } + } + + fn deserialize_bool(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + match self.untag() { + Value::Bool(v) => visitor.visit_bool(v), + other => Err(other.invalid_type(&visitor)), + } + } + + fn deserialize_i8(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_number(visitor) + } + + fn deserialize_i16(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_number(visitor) + } + + fn deserialize_i32(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_number(visitor) + } + + fn deserialize_i64(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_number(visitor) + } + + fn deserialize_i128(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_number(visitor) + } + + fn deserialize_u8(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_number(visitor) + } + + fn deserialize_u16(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_number(visitor) + } + + fn deserialize_u32(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_number(visitor) + } + + fn deserialize_u64(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_number(visitor) + } + + fn deserialize_u128(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_number(visitor) + } + + fn deserialize_f32(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_number(visitor) + } + + fn deserialize_f64(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_number(visitor) + } + + fn deserialize_char(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_string(visitor) + } + + fn deserialize_str(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_string(visitor) + } + + fn deserialize_string(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + match self.untag() { + Value::String(v) => visitor.visit_string(v), + other => Err(other.invalid_type(&visitor)), + } + } + + fn deserialize_bytes(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_byte_buf(visitor) + } + + fn deserialize_byte_buf(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + match self.untag() { + Value::String(v) => visitor.visit_string(v), + Value::Sequence(v) => visit_sequence(v, visitor), + other => Err(other.invalid_type(&visitor)), + } + } + + fn deserialize_option(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + match self { + Value::Null => visitor.visit_none(), + _ => visitor.visit_some(self), + } + } + + fn deserialize_unit(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + match self { + Value::Null => visitor.visit_unit(), + _ => Err(self.invalid_type(&visitor)), + } + } + + fn deserialize_unit_struct(self, _name: &'static str, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_unit(visitor) + } + + fn deserialize_newtype_struct( + self, + _name: &'static str, + visitor: V, + ) -> Result + where + V: Visitor<'de>, + { + visitor.visit_newtype_struct(self) + } + + fn deserialize_seq(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + match self.untag() { + Value::Sequence(v) => visit_sequence(v, visitor), + Value::Null => visit_sequence(Sequence::new(), visitor), + other => Err(other.invalid_type(&visitor)), + } + } + + fn deserialize_tuple(self, _len: usize, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_seq(visitor) + } + + fn deserialize_tuple_struct( + self, + _name: &'static str, + _len: usize, + visitor: V, + ) -> Result + where + V: Visitor<'de>, + { + self.deserialize_seq(visitor) + } + + fn deserialize_map(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + match self.untag() { + Value::Mapping(v) => visit_mapping(v, visitor), + Value::Null => visit_mapping(Mapping::new(), visitor), + other => Err(other.invalid_type(&visitor)), + } + } + + fn deserialize_struct( + self, + _name: &'static str, + _fields: &'static [&'static str], + visitor: V, + ) -> Result + where + V: Visitor<'de>, + { + self.deserialize_map(visitor) + } + + fn deserialize_enum( + self, + _name: &str, + _variants: &'static [&'static str], + visitor: V, + ) -> Result + where + V: Visitor<'de>, + { + let tag; + visitor.visit_enum(match self { + Value::Tagged(tagged) => EnumDeserializer { + tag: { + tag = tagged.tag.string; + tagged::nobang(&tag) + }, + value: Some(tagged.value), + }, + Value::String(variant) => EnumDeserializer { + tag: { + tag = variant; + &tag + }, + value: None, + }, + other => { + return Err(Error::invalid_type( + other.unexpected(), + &"a Value::Tagged enum", + )); + } + }) + } + + fn deserialize_identifier(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_string(visitor) + } + + fn deserialize_ignored_any(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + drop(self); + visitor.visit_unit() + } +} + +struct EnumDeserializer<'a> { + tag: &'a str, + value: Option, +} + +impl<'a, 'de> EnumAccess<'de> for EnumDeserializer<'a> { + type Error = Error; + type Variant = VariantDeserializer; + + fn variant_seed(self, seed: V) -> Result<(V::Value, Self::Variant), Error> + where + V: DeserializeSeed<'de>, + { + let str_de = StrDeserializer::::new(self.tag); + let variant = seed.deserialize(str_de)?; + let visitor = VariantDeserializer { value: self.value }; + Ok((variant, visitor)) + } +} + +struct VariantDeserializer { + value: Option, +} + +impl<'de> VariantAccess<'de> for VariantDeserializer { + type Error = Error; + + fn unit_variant(self) -> Result<(), Error> { + match self.value { + Some(value) => value.unit_variant(), + None => Ok(()), + } + } + + fn newtype_variant_seed(self, seed: T) -> Result + where + T: DeserializeSeed<'de>, + { + match self.value { + Some(value) => value.newtype_variant_seed(seed), + None => Err(Error::invalid_type( + Unexpected::UnitVariant, + &"newtype variant", + )), + } + } + + fn tuple_variant(self, len: usize, visitor: V) -> Result + where + V: Visitor<'de>, + { + match self.value { + Some(value) => value.tuple_variant(len, visitor), + None => Err(Error::invalid_type( + Unexpected::UnitVariant, + &"tuple variant", + )), + } + } + + fn struct_variant( + self, + fields: &'static [&'static str], + visitor: V, + ) -> Result + where + V: Visitor<'de>, + { + match self.value { + Some(value) => value.struct_variant(fields, visitor), + None => Err(Error::invalid_type( + Unexpected::UnitVariant, + &"struct variant", + )), + } + } +} + +pub(crate) struct SeqDeserializer { + iter: vec::IntoIter, +} + +impl SeqDeserializer { + pub(crate) fn new(vec: Vec) -> Self { + SeqDeserializer { + iter: vec.into_iter(), + } + } +} + +impl<'de> Deserializer<'de> for SeqDeserializer { + type Error = Error; + + #[inline] + fn deserialize_any(mut self, visitor: V) -> Result + where + V: Visitor<'de>, + { + let len = self.iter.len(); + if len == 0 { + visitor.visit_unit() + } else { + let ret = visitor.visit_seq(&mut self)?; + let remaining = self.iter.len(); + if remaining == 0 { + Ok(ret) + } else { + Err(Error::invalid_length(len, &"fewer elements in sequence")) + } + } + } + + fn deserialize_ignored_any(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + drop(self); + visitor.visit_unit() + } + + forward_to_deserialize_any! { + bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char str string bytes + byte_buf option unit unit_struct newtype_struct seq tuple tuple_struct + map struct enum identifier + } +} + +impl<'de> SeqAccess<'de> for SeqDeserializer { + type Error = Error; + + fn next_element_seed(&mut self, seed: T) -> Result, Error> + where + T: DeserializeSeed<'de>, + { + match self.iter.next() { + Some(value) => seed.deserialize(value).map(Some), + None => Ok(None), + } + } + + fn size_hint(&self) -> Option { + match self.iter.size_hint() { + (lower, Some(upper)) if lower == upper => Some(upper), + _ => None, + } + } +} + +pub(crate) struct MapDeserializer { + iter: ::IntoIter, + value: Option, +} + +impl MapDeserializer { + pub(crate) fn new(map: Mapping) -> Self { + MapDeserializer { + iter: map.into_iter(), + value: None, + } + } +} + +impl<'de> MapAccess<'de> for MapDeserializer { + type Error = Error; + + fn next_key_seed(&mut self, seed: T) -> Result, Error> + where + T: DeserializeSeed<'de>, + { + match self.iter.next() { + Some((key, value)) => { + self.value = Some(value); + seed.deserialize(key).map(Some) + } + None => Ok(None), + } + } + + fn next_value_seed(&mut self, seed: T) -> Result + where + T: DeserializeSeed<'de>, + { + match self.value.take() { + Some(value) => seed.deserialize(value), + None => panic!("visit_value called before visit_key"), + } + } + + fn size_hint(&self) -> Option { + match self.iter.size_hint() { + (lower, Some(upper)) if lower == upper => Some(upper), + _ => None, + } + } +} + +impl<'de> Deserializer<'de> for MapDeserializer { + type Error = Error; + + #[inline] + fn deserialize_any(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + visitor.visit_map(self) + } + + fn deserialize_ignored_any(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + drop(self); + visitor.visit_unit() + } + + forward_to_deserialize_any! { + bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char str string bytes + byte_buf option unit unit_struct newtype_struct seq tuple tuple_struct + map struct enum identifier + } +} + +impl<'de> Deserializer<'de> for &'de Value { + type Error = Error; + + fn deserialize_any(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + match self { + Value::Null => visitor.visit_unit(), + Value::Bool(v) => visitor.visit_bool(*v), + Value::Number(n) => n.deserialize_any(visitor), + Value::String(v) => visitor.visit_borrowed_str(v), + Value::Sequence(v) => visit_sequence_ref(v, visitor), + Value::Mapping(v) => visit_mapping_ref(v, visitor), + Value::Tagged(tagged) => visitor.visit_enum(&**tagged), + } + } + + fn deserialize_bool(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + match self.untag_ref() { + Value::Bool(v) => visitor.visit_bool(*v), + other => Err(other.invalid_type(&visitor)), + } + } + + fn deserialize_i8(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_number(visitor) + } + + fn deserialize_i16(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_number(visitor) + } + + fn deserialize_i32(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_number(visitor) + } + + fn deserialize_i64(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_number(visitor) + } + + fn deserialize_i128(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_number(visitor) + } + + fn deserialize_u8(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_number(visitor) + } + + fn deserialize_u16(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_number(visitor) + } + + fn deserialize_u32(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_number(visitor) + } + + fn deserialize_u64(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_number(visitor) + } + + fn deserialize_u128(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_number(visitor) + } + + fn deserialize_f32(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_number(visitor) + } + + fn deserialize_f64(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_number(visitor) + } + + fn deserialize_char(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_string(visitor) + } + + fn deserialize_str(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + match self.untag_ref() { + Value::String(v) => visitor.visit_borrowed_str(v), + other => Err(other.invalid_type(&visitor)), + } + } + + fn deserialize_string(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_str(visitor) + } + + fn deserialize_bytes(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + match self.untag_ref() { + Value::String(v) => visitor.visit_borrowed_str(v), + Value::Sequence(v) => visit_sequence_ref(v, visitor), + other => Err(other.invalid_type(&visitor)), + } + } + + fn deserialize_byte_buf(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_bytes(visitor) + } + + fn deserialize_option(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + match self { + Value::Null => visitor.visit_none(), + _ => visitor.visit_some(self), + } + } + + fn deserialize_unit(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + match self { + Value::Null => visitor.visit_unit(), + _ => Err(self.invalid_type(&visitor)), + } + } + + fn deserialize_unit_struct(self, _name: &'static str, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_unit(visitor) + } + + fn deserialize_newtype_struct( + self, + _name: &'static str, + visitor: V, + ) -> Result + where + V: Visitor<'de>, + { + visitor.visit_newtype_struct(self) + } + + fn deserialize_seq(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + static EMPTY: Sequence = Sequence::new(); + match self.untag_ref() { + Value::Sequence(v) => visit_sequence_ref(v, visitor), + Value::Null => visit_sequence_ref(&EMPTY, visitor), + other => Err(other.invalid_type(&visitor)), + } + } + + fn deserialize_tuple(self, _len: usize, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_seq(visitor) + } + + fn deserialize_tuple_struct( + self, + _name: &'static str, + _len: usize, + visitor: V, + ) -> Result + where + V: Visitor<'de>, + { + self.deserialize_seq(visitor) + } + + fn deserialize_map(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + match self.untag_ref() { + Value::Mapping(v) => visit_mapping_ref(v, visitor), + Value::Null => visitor.visit_map(&mut MapRefDeserializer { + iter: None, + value: None, + }), + other => Err(other.invalid_type(&visitor)), + } + } + + fn deserialize_struct( + self, + _name: &'static str, + _fields: &'static [&'static str], + visitor: V, + ) -> Result + where + V: Visitor<'de>, + { + self.deserialize_map(visitor) + } + + fn deserialize_enum( + self, + _name: &str, + _variants: &'static [&'static str], + visitor: V, + ) -> Result + where + V: Visitor<'de>, + { + visitor.visit_enum(match self { + Value::Tagged(tagged) => EnumRefDeserializer { + tag: tagged::nobang(&tagged.tag.string), + value: Some(&tagged.value), + }, + Value::String(variant) => EnumRefDeserializer { + tag: variant, + value: None, + }, + other => { + return Err(Error::invalid_type( + other.unexpected(), + &"a Value::Tagged enum", + )); + } + }) + } + + fn deserialize_identifier(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_string(visitor) + } + + fn deserialize_ignored_any(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + visitor.visit_unit() + } +} + +struct EnumRefDeserializer<'de> { + tag: &'de str, + value: Option<&'de Value>, +} + +impl<'de> EnumAccess<'de> for EnumRefDeserializer<'de> { + type Error = Error; + type Variant = VariantRefDeserializer<'de>; + + fn variant_seed(self, seed: V) -> Result<(V::Value, Self::Variant), Error> + where + V: DeserializeSeed<'de>, + { + let str_de = BorrowedStrDeserializer::::new(self.tag); + let variant = seed.deserialize(str_de)?; + let visitor = VariantRefDeserializer { value: self.value }; + Ok((variant, visitor)) + } +} + +struct VariantRefDeserializer<'de> { + value: Option<&'de Value>, +} + +impl<'de> VariantAccess<'de> for VariantRefDeserializer<'de> { + type Error = Error; + + fn unit_variant(self) -> Result<(), Error> { + match self.value { + Some(value) => value.unit_variant(), + None => Ok(()), + } + } + + fn newtype_variant_seed(self, seed: T) -> Result + where + T: DeserializeSeed<'de>, + { + match self.value { + Some(value) => value.newtype_variant_seed(seed), + None => Err(Error::invalid_type( + Unexpected::UnitVariant, + &"newtype variant", + )), + } + } + + fn tuple_variant(self, len: usize, visitor: V) -> Result + where + V: Visitor<'de>, + { + match self.value { + Some(value) => value.tuple_variant(len, visitor), + None => Err(Error::invalid_type( + Unexpected::UnitVariant, + &"tuple variant", + )), + } + } + + fn struct_variant( + self, + fields: &'static [&'static str], + visitor: V, + ) -> Result + where + V: Visitor<'de>, + { + match self.value { + Some(value) => value.struct_variant(fields, visitor), + None => Err(Error::invalid_type( + Unexpected::UnitVariant, + &"struct variant", + )), + } + } +} + +pub(crate) struct SeqRefDeserializer<'de> { + iter: slice::Iter<'de, Value>, +} + +impl<'de> SeqRefDeserializer<'de> { + pub(crate) fn new(slice: &'de [Value]) -> Self { + SeqRefDeserializer { iter: slice.iter() } + } +} + +impl<'de> Deserializer<'de> for SeqRefDeserializer<'de> { + type Error = Error; + + #[inline] + fn deserialize_any(mut self, visitor: V) -> Result + where + V: Visitor<'de>, + { + let len = self.iter.len(); + if len == 0 { + visitor.visit_unit() + } else { + let ret = visitor.visit_seq(&mut self)?; + let remaining = self.iter.len(); + if remaining == 0 { + Ok(ret) + } else { + Err(Error::invalid_length(len, &"fewer elements in sequence")) + } + } + } + + fn deserialize_ignored_any(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + visitor.visit_unit() + } + + forward_to_deserialize_any! { + bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char str string bytes + byte_buf option unit unit_struct newtype_struct seq tuple tuple_struct + map struct enum identifier + } +} + +impl<'de> SeqAccess<'de> for SeqRefDeserializer<'de> { + type Error = Error; + + fn next_element_seed(&mut self, seed: T) -> Result, Error> + where + T: DeserializeSeed<'de>, + { + match self.iter.next() { + Some(value) => seed.deserialize(value).map(Some), + None => Ok(None), + } + } + + fn size_hint(&self) -> Option { + match self.iter.size_hint() { + (lower, Some(upper)) if lower == upper => Some(upper), + _ => None, + } + } +} + +pub(crate) struct MapRefDeserializer<'de> { + iter: Option<<&'de Mapping as IntoIterator>::IntoIter>, + value: Option<&'de Value>, +} + +impl<'de> MapRefDeserializer<'de> { + pub(crate) fn new(map: &'de Mapping) -> Self { + MapRefDeserializer { + iter: Some(map.iter()), + value: None, + } + } +} + +impl<'de> MapAccess<'de> for MapRefDeserializer<'de> { + type Error = Error; + + fn next_key_seed(&mut self, seed: T) -> Result, Error> + where + T: DeserializeSeed<'de>, + { + match self.iter.as_mut().and_then(Iterator::next) { + Some((key, value)) => { + self.value = Some(value); + seed.deserialize(key).map(Some) + } + None => Ok(None), + } + } + + fn next_value_seed(&mut self, seed: T) -> Result + where + T: DeserializeSeed<'de>, + { + match self.value.take() { + Some(value) => seed.deserialize(value), + None => panic!("visit_value called before visit_key"), + } + } + + fn size_hint(&self) -> Option { + match self.iter.as_ref()?.size_hint() { + (lower, Some(upper)) if lower == upper => Some(upper), + _ => None, + } + } +} + +impl<'de> Deserializer<'de> for MapRefDeserializer<'de> { + type Error = Error; + + #[inline] + fn deserialize_any(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + visitor.visit_map(self) + } + + fn deserialize_ignored_any(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + visitor.visit_unit() + } + + forward_to_deserialize_any! { + bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char str string bytes + byte_buf option unit unit_struct newtype_struct seq tuple tuple_struct + map struct enum identifier + } +} + +impl Value { + #[cold] + fn invalid_type(&self, exp: &dyn Expected) -> E + where + E: de::Error, + { + de::Error::invalid_type(self.unexpected(), exp) + } + + #[cold] + pub(crate) fn unexpected(&self) -> Unexpected { + match self { + Value::Null => Unexpected::Unit, + Value::Bool(b) => Unexpected::Bool(*b), + Value::Number(n) => number::unexpected(n), + Value::String(s) => Unexpected::Str(s), + Value::Sequence(_) => Unexpected::Seq, + Value::Mapping(_) => Unexpected::Map, + Value::Tagged(_) => Unexpected::Enum, + } + } +} diff --git a/kclvm/third-party/serde_yaml/src/value/debug.rs b/kclvm/third-party/serde_yaml/src/value/debug.rs new file mode 100644 index 000000000..060f9ecdf --- /dev/null +++ b/kclvm/third-party/serde_yaml/src/value/debug.rs @@ -0,0 +1,57 @@ +use crate::mapping::Mapping; +use crate::value::{Number, Value}; +use std::fmt::{self, Debug, Display}; + +impl Debug for Value { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + match self { + Value::Null => formatter.write_str("Null"), + Value::Bool(boolean) => write!(formatter, "Bool({})", boolean), + Value::Number(number) => write!(formatter, "Number({})", number), + Value::String(string) => write!(formatter, "String({:?})", string), + Value::Sequence(sequence) => { + formatter.write_str("Sequence ")?; + formatter.debug_list().entries(sequence).finish() + } + Value::Mapping(mapping) => Debug::fmt(mapping, formatter), + Value::Tagged(tagged) => Debug::fmt(tagged, formatter), + } + } +} + +struct DisplayNumber<'a>(&'a Number); + +impl<'a> Debug for DisplayNumber<'a> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + Display::fmt(self.0, formatter) + } +} + +impl Debug for Number { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + write!(formatter, "Number({})", self) + } +} + +impl Debug for Mapping { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Mapping ")?; + let mut debug = formatter.debug_map(); + for (k, v) in self { + let tmp; + debug.entry( + match k { + Value::Bool(boolean) => boolean, + Value::Number(number) => { + tmp = DisplayNumber(number); + &tmp + } + Value::String(string) => string, + _ => k, + }, + v, + ); + } + debug.finish() + } +} diff --git a/kclvm/third-party/serde_yaml/src/value/from.rs b/kclvm/third-party/serde_yaml/src/value/from.rs new file mode 100644 index 000000000..82412c4f2 --- /dev/null +++ b/kclvm/third-party/serde_yaml/src/value/from.rs @@ -0,0 +1,178 @@ +use crate::{Mapping, Value}; + +// Implement a bunch of conversion to make it easier to create YAML values +// on the fly. + +macro_rules! from_number { + ($($ty:ident)*) => { + $( + impl From<$ty> for Value { + fn from(n: $ty) -> Self { + Value::Number(n.into()) + } + } + )* + }; +} + +from_number! { + i8 i16 i32 i64 isize + u8 u16 u32 u64 usize + f32 f64 +} + +impl From for Value { + /// Convert boolean to `Value` + /// + /// # Examples + /// + /// ``` + /// use serde_yaml::Value; + /// + /// let b = false; + /// let x: Value = b.into(); + /// ``` + fn from(f: bool) -> Self { + Value::Bool(f) + } +} + +impl From for Value { + /// Convert `String` to `Value` + /// + /// # Examples + /// + /// ``` + /// use serde_yaml::Value; + /// + /// let s: String = "lorem".to_string(); + /// let x: Value = s.into(); + /// ``` + fn from(f: String) -> Self { + Value::String(f) + } +} + +impl<'a> From<&'a str> for Value { + /// Convert string slice to `Value` + /// + /// # Examples + /// + /// ``` + /// use serde_yaml::Value; + /// + /// let s: &str = "lorem"; + /// let x: Value = s.into(); + /// ``` + fn from(f: &str) -> Self { + Value::String(f.to_string()) + } +} + +use std::borrow::Cow; + +impl<'a> From> for Value { + /// Convert copy-on-write string to `Value` + /// + /// # Examples + /// + /// ``` + /// use serde_yaml::Value; + /// use std::borrow::Cow; + /// + /// let s: Cow = Cow::Borrowed("lorem"); + /// let x: Value = s.into(); + /// ``` + /// + /// ``` + /// use serde_yaml::Value; + /// use std::borrow::Cow; + /// + /// let s: Cow = Cow::Owned("lorem".to_string()); + /// let x: Value = s.into(); + /// ``` + fn from(f: Cow<'a, str>) -> Self { + Value::String(f.to_string()) + } +} + +impl From for Value { + /// Convert map (with string keys) to `Value` + /// + /// # Examples + /// + /// ``` + /// use serde_yaml::{Mapping, Value}; + /// + /// let mut m = Mapping::new(); + /// m.insert("Lorem".into(), "ipsum".into()); + /// let x: Value = m.into(); + /// ``` + fn from(f: Mapping) -> Self { + Value::Mapping(f) + } +} + +impl> From> for Value { + /// Convert a `Vec` to `Value` + /// + /// # Examples + /// + /// ``` + /// use serde_yaml::Value; + /// + /// let v = vec!["lorem", "ipsum", "dolor"]; + /// let x: Value = v.into(); + /// ``` + fn from(f: Vec) -> Self { + Value::Sequence(f.into_iter().map(Into::into).collect()) + } +} + +impl<'a, T: Clone + Into> From<&'a [T]> for Value { + /// Convert a slice to `Value` + /// + /// # Examples + /// + /// ``` + /// use serde_yaml::Value; + /// + /// let v: &[&str] = &["lorem", "ipsum", "dolor"]; + /// let x: Value = v.into(); + /// ``` + fn from(f: &'a [T]) -> Self { + Value::Sequence(f.iter().cloned().map(Into::into).collect()) + } +} + +impl> FromIterator for Value { + /// Convert an iteratable type to a YAML sequence + /// + /// # Examples + /// + /// ``` + /// use serde_yaml::Value; + /// + /// let v = std::iter::repeat(42).take(5); + /// let x: Value = v.collect(); + /// ``` + /// + /// ``` + /// use serde_yaml::Value; + /// + /// let v: Vec<_> = vec!["lorem", "ipsum", "dolor"]; + /// let x: Value = v.into_iter().collect(); + /// ``` + /// + /// ``` + /// use std::iter::FromIterator; + /// use serde_yaml::Value; + /// + /// let x: Value = Value::from_iter(vec!["lorem", "ipsum", "dolor"]); + /// ``` + fn from_iter>(iter: I) -> Self { + let vec = iter.into_iter().map(T::into).collect(); + + Value::Sequence(vec) + } +} diff --git a/kclvm/third-party/serde_yaml/src/value/index.rs b/kclvm/third-party/serde_yaml/src/value/index.rs new file mode 100644 index 000000000..9a886d547 --- /dev/null +++ b/kclvm/third-party/serde_yaml/src/value/index.rs @@ -0,0 +1,279 @@ +use crate::mapping::Entry; +use crate::{mapping, private, Mapping, Value}; +use std::fmt::{self, Debug}; +use std::ops; + +/// A type that can be used to index into a `serde_yaml::Value`. See the `get` +/// and `get_mut` methods of `Value`. +/// +/// This trait is sealed and cannot be implemented for types outside of +/// `serde_yaml`. +pub trait Index: private::Sealed { + /// Return None if the key is not already in the sequence or object. + #[doc(hidden)] + fn index_into<'v>(&self, v: &'v Value) -> Option<&'v Value>; + + /// Return None if the key is not already in the sequence or object. + #[doc(hidden)] + fn index_into_mut<'v>(&self, v: &'v mut Value) -> Option<&'v mut Value>; + + /// Panic if sequence index out of bounds. If key is not already in the object, + /// insert it with a value of null. Panic if Value is a type that cannot be + /// indexed into, except if Value is null then it can be treated as an empty + /// object. + #[doc(hidden)] + fn index_or_insert<'v>(&self, v: &'v mut Value) -> &'v mut Value; +} + +impl Index for usize { + fn index_into<'v>(&self, v: &'v Value) -> Option<&'v Value> { + match v.untag_ref() { + Value::Sequence(vec) => vec.get(*self), + Value::Mapping(vec) => vec.get(&Value::Number((*self).into())), + _ => None, + } + } + fn index_into_mut<'v>(&self, v: &'v mut Value) -> Option<&'v mut Value> { + match v.untag_mut() { + Value::Sequence(vec) => vec.get_mut(*self), + Value::Mapping(vec) => vec.get_mut(&Value::Number((*self).into())), + _ => None, + } + } + fn index_or_insert<'v>(&self, mut v: &'v mut Value) -> &'v mut Value { + loop { + match v { + Value::Sequence(vec) => { + let len = vec.len(); + return vec.get_mut(*self).unwrap_or_else(|| { + panic!( + "cannot access index {} of YAML sequence of length {}", + self, len + ) + }); + } + Value::Mapping(map) => { + let n = Value::Number((*self).into()); + return map.entry(n).or_insert(Value::Null); + } + Value::Tagged(tagged) => v = &mut tagged.value, + _ => panic!("cannot access index {} of YAML {}", self, Type(v)), + } + } + } +} + +fn index_into_mapping<'v, I>(index: &I, v: &'v Value) -> Option<&'v Value> +where + I: ?Sized + mapping::Index, +{ + match v.untag_ref() { + Value::Mapping(map) => map.get(index), + _ => None, + } +} + +fn index_into_mut_mapping<'v, I>(index: &I, v: &'v mut Value) -> Option<&'v mut Value> +where + I: ?Sized + mapping::Index, +{ + match v.untag_mut() { + Value::Mapping(map) => map.get_mut(index), + _ => None, + } +} + +fn index_or_insert_mapping<'v, I>(index: &I, mut v: &'v mut Value) -> &'v mut Value +where + I: ?Sized + mapping::Index + ToOwned + Debug, + Value: From, +{ + if let Value::Null = *v { + *v = Value::Mapping(Mapping::new()); + return match v { + Value::Mapping(map) => match map.entry(index.to_owned().into()) { + Entry::Vacant(entry) => entry.insert(Value::Null), + Entry::Occupied(_) => unreachable!(), + }, + _ => unreachable!(), + }; + } + loop { + match v { + Value::Mapping(map) => { + return map.entry(index.to_owned().into()).or_insert(Value::Null); + } + Value::Tagged(tagged) => v = &mut tagged.value, + _ => panic!("cannot access key {:?} in YAML {}", index, Type(v)), + } + } +} + +impl Index for Value { + fn index_into<'v>(&self, v: &'v Value) -> Option<&'v Value> { + index_into_mapping(self, v) + } + fn index_into_mut<'v>(&self, v: &'v mut Value) -> Option<&'v mut Value> { + index_into_mut_mapping(self, v) + } + fn index_or_insert<'v>(&self, v: &'v mut Value) -> &'v mut Value { + index_or_insert_mapping(self, v) + } +} + +impl Index for str { + fn index_into<'v>(&self, v: &'v Value) -> Option<&'v Value> { + index_into_mapping(self, v) + } + fn index_into_mut<'v>(&self, v: &'v mut Value) -> Option<&'v mut Value> { + index_into_mut_mapping(self, v) + } + fn index_or_insert<'v>(&self, v: &'v mut Value) -> &'v mut Value { + index_or_insert_mapping(self, v) + } +} + +impl Index for String { + fn index_into<'v>(&self, v: &'v Value) -> Option<&'v Value> { + self.as_str().index_into(v) + } + fn index_into_mut<'v>(&self, v: &'v mut Value) -> Option<&'v mut Value> { + self.as_str().index_into_mut(v) + } + fn index_or_insert<'v>(&self, v: &'v mut Value) -> &'v mut Value { + self.as_str().index_or_insert(v) + } +} + +impl<'a, T> Index for &'a T +where + T: ?Sized + Index, +{ + fn index_into<'v>(&self, v: &'v Value) -> Option<&'v Value> { + (**self).index_into(v) + } + fn index_into_mut<'v>(&self, v: &'v mut Value) -> Option<&'v mut Value> { + (**self).index_into_mut(v) + } + fn index_or_insert<'v>(&self, v: &'v mut Value) -> &'v mut Value { + (**self).index_or_insert(v) + } +} + +/// Used in panic messages. +struct Type<'a>(&'a Value); + +impl<'a> fmt::Display for Type<'a> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + match self.0 { + Value::Null => formatter.write_str("null"), + Value::Bool(_) => formatter.write_str("boolean"), + Value::Number(_) => formatter.write_str("number"), + Value::String(_) => formatter.write_str("string"), + Value::Sequence(_) => formatter.write_str("sequence"), + Value::Mapping(_) => formatter.write_str("mapping"), + Value::Tagged(_) => unreachable!(), + } + } +} + +// The usual semantics of Index is to panic on invalid indexing. +// +// That said, the usual semantics are for things like `Vec` and `BTreeMap` which +// have different use cases than Value. If you are working with a Vec, you know +// that you are working with a Vec and you can get the len of the Vec and make +// sure your indices are within bounds. The Value use cases are more +// loosey-goosey. You got some YAML from an endpoint and you want to pull values +// out of it. Outside of this Index impl, you already have the option of using +// `value.as_sequence()` and working with the Vec directly, or matching on +// `Value::Sequence` and getting the Vec directly. The Index impl means you can +// skip that and index directly into the thing using a concise syntax. You don't +// have to check the type, you don't have to check the len, it is all about what +// you expect the Value to look like. +// +// Basically the use cases that would be well served by panicking here are +// better served by using one of the other approaches: `get` and `get_mut`, +// `as_sequence`, or match. The value of this impl is that it adds a way of +// working with Value that is not well served by the existing approaches: +// concise and careless and sometimes that is exactly what you want. +impl ops::Index for Value +where + I: Index, +{ + type Output = Value; + + /// Index into a `serde_yaml::Value` using the syntax `value[0]` or + /// `value["k"]`. + /// + /// Returns `Value::Null` if the type of `self` does not match the type of + /// the index, for example if the index is a string and `self` is a sequence + /// or a number. Also returns `Value::Null` if the given key does not exist + /// in the map or the given index is not within the bounds of the sequence. + /// + /// For retrieving deeply nested values, you should have a look at the + /// `Value::pointer` method. + /// + /// # Examples + /// + /// ``` + /// # use serde_yaml::Value; + /// # + /// # fn main() -> serde_yaml::Result<()> { + /// let data: serde_yaml::Value = serde_yaml::from_str(r#"{ x: { y: [z, zz] } }"#)?; + /// + /// assert_eq!(data["x"]["y"], serde_yaml::from_str::(r#"["z", "zz"]"#).unwrap()); + /// assert_eq!(data["x"]["y"][0], serde_yaml::from_str::(r#""z""#).unwrap()); + /// + /// assert_eq!(data["a"], serde_yaml::from_str::(r#"null"#).unwrap()); // returns null for undefined values + /// assert_eq!(data["a"]["b"], serde_yaml::from_str::(r#"null"#).unwrap()); // does not panic + /// # Ok(()) + /// # } + /// ``` + fn index(&self, index: I) -> &Value { + static NULL: Value = Value::Null; + index.index_into(self).unwrap_or(&NULL) + } +} + +impl ops::IndexMut for Value +where + I: Index, +{ + /// Write into a `serde_yaml::Value` using the syntax `value[0] = ...` or + /// `value["k"] = ...`. + /// + /// If the index is a number, the value must be a sequence of length bigger + /// than the index. Indexing into a value that is not a sequence or a + /// sequence that is too small will panic. + /// + /// If the index is a string, the value must be an object or null which is + /// treated like an empty object. If the key is not already present in the + /// object, it will be inserted with a value of null. Indexing into a value + /// that is neither an object nor null will panic. + /// + /// # Examples + /// + /// ``` + /// # fn main() -> serde_yaml::Result<()> { + /// let mut data: serde_yaml::Value = serde_yaml::from_str(r#"{x: 0}"#)?; + /// + /// // replace an existing key + /// data["x"] = serde_yaml::from_str(r#"1"#)?; + /// + /// // insert a new key + /// data["y"] = serde_yaml::from_str(r#"[false, false, false]"#)?; + /// + /// // replace a value in a sequence + /// data["y"][0] = serde_yaml::from_str(r#"true"#)?; + /// + /// // inserted a deeply nested key + /// data["a"]["b"]["c"]["d"] = serde_yaml::from_str(r#"true"#)?; + /// + /// println!("{:?}", data); + /// # Ok(()) + /// # } + /// ``` + fn index_mut(&mut self, index: I) -> &mut Value { + index.index_or_insert(self) + } +} diff --git a/kclvm/third-party/serde_yaml/src/value/mod.rs b/kclvm/third-party/serde_yaml/src/value/mod.rs new file mode 100644 index 000000000..b855f5bc0 --- /dev/null +++ b/kclvm/third-party/serde_yaml/src/value/mod.rs @@ -0,0 +1,698 @@ +//! The Value enum, a loosely typed way of representing any valid YAML value. + +mod de; +mod debug; +mod from; +mod index; +mod partial_eq; +mod ser; +pub(crate) mod tagged; + +use crate::error::{self, Error, ErrorImpl}; +use serde::de::{Deserialize, DeserializeOwned, IntoDeserializer}; +use serde::Serialize; +use std::hash::{Hash, Hasher}; +use std::mem; + +pub use self::index::Index; +pub use self::ser::Serializer; +pub use self::tagged::{Tag, TaggedValue}; +#[doc(inline)] +pub use crate::mapping::Mapping; +pub use crate::number::Number; + +/// Represents any valid YAML value. +#[derive(Clone, PartialEq, PartialOrd)] +pub enum Value { + /// Represents a YAML null value. + Null, + /// Represents a YAML boolean. + Bool(bool), + /// Represents a YAML numerical value, whether integer or floating point. + Number(Number), + /// Represents a YAML string. + String(String), + /// Represents a YAML sequence in which the elements are + /// `serde_yaml::Value`. + Sequence(Sequence), + /// Represents a YAML mapping in which the keys and values are both + /// `serde_yaml::Value`. + Mapping(Mapping), + /// A representation of YAML's `!Tag` syntax, used for enums. + Tagged(Box), +} + +/// The default value is `Value::Null`. +/// +/// This is useful for handling omitted `Value` fields when deserializing. +/// +/// # Examples +/// +/// ``` +/// # use serde_derive::Deserialize; +/// # use serde::Deserialize as _; +/// use serde_yaml::Value; +/// +/// #[derive(Deserialize)] +/// struct Settings { +/// level: i32, +/// #[serde(default)] +/// extras: Value, +/// } +/// +/// # fn try_main() -> Result<(), serde_yaml::Error> { +/// let data = r#" { "level": 42 } "#; +/// let s: Settings = serde_yaml::from_str(data)?; +/// +/// assert_eq!(s.level, 42); +/// assert_eq!(s.extras, Value::Null); +/// # +/// # Ok(()) +/// # } +/// # +/// # try_main().unwrap() +/// ``` +impl Default for Value { + fn default() -> Value { + Value::Null + } +} + +/// A YAML sequence in which the elements are `serde_yaml::Value`. +pub type Sequence = Vec; + +/// Convert a `T` into `serde_yaml::Value` which is an enum that can represent +/// any valid YAML data. +/// +/// This conversion can fail if `T`'s implementation of `Serialize` decides to +/// return an error. +/// +/// ``` +/// # use serde_yaml::Value; +/// let val = serde_yaml::to_value("s").unwrap(); +/// assert_eq!(val, Value::String("s".to_owned())); +/// ``` +pub fn to_value(value: T) -> Result +where + T: Serialize, +{ + value.serialize(Serializer) +} + +/// Interpret a `serde_yaml::Value` as an instance of type `T`. +/// +/// This conversion can fail if the structure of the Value does not match the +/// structure expected by `T`, for example if `T` is a struct type but the Value +/// contains something other than a YAML map. It can also fail if the structure +/// is correct but `T`'s implementation of `Deserialize` decides that something +/// is wrong with the data, for example required struct fields are missing from +/// the YAML map or some number is too big to fit in the expected primitive +/// type. +/// +/// ``` +/// # use serde_yaml::Value; +/// let val = Value::String("foo".to_owned()); +/// let s: String = serde_yaml::from_value(val).unwrap(); +/// assert_eq!("foo", s); +/// ``` +pub fn from_value(value: Value) -> Result +where + T: DeserializeOwned, +{ + Deserialize::deserialize(value) +} + +impl Value { + /// Index into a YAML sequence or map. A string index can be used to access + /// a value in a map, and a usize index can be used to access an element of + /// an sequence. + /// + /// Returns `None` if the type of `self` does not match the type of the + /// index, for example if the index is a string and `self` is a sequence or + /// a number. Also returns `None` if the given key does not exist in the map + /// or the given index is not within the bounds of the sequence. + /// + /// ``` + /// # fn main() -> serde_yaml::Result<()> { + /// use serde_yaml::Value; + /// + /// let object: Value = serde_yaml::from_str(r#"{ A: 65, B: 66, C: 67 }"#)?; + /// let x = object.get("A").unwrap(); + /// assert_eq!(x, 65); + /// + /// let sequence: Value = serde_yaml::from_str(r#"[ "A", "B", "C" ]"#)?; + /// let x = sequence.get(2).unwrap(); + /// assert_eq!(x, &Value::String("C".into())); + /// + /// assert_eq!(sequence.get("A"), None); + /// # Ok(()) + /// # } + /// ``` + /// + /// Square brackets can also be used to index into a value in a more concise + /// way. This returns `Value::Null` in cases where `get` would have returned + /// `None`. + /// + /// ``` + /// # use serde_yaml::Value; + /// # + /// # fn main() -> serde_yaml::Result<()> { + /// let object: Value = serde_yaml::from_str(r#" + /// A: [a, á, à] + /// B: [b, b́] + /// C: [c, ć, ć̣, ḉ] + /// 42: true + /// "#)?; + /// assert_eq!(object["B"][0], Value::String("b".into())); + /// + /// assert_eq!(object[Value::String("D".into())], Value::Null); + /// assert_eq!(object["D"], Value::Null); + /// assert_eq!(object[0]["x"]["y"]["z"], Value::Null); + /// + /// assert_eq!(object[42], Value::Bool(true)); + /// # Ok(()) + /// # } + /// ``` + pub fn get(&self, index: I) -> Option<&Value> { + index.index_into(self) + } + + /// Index into a YAML sequence or map. A string index can be used to access + /// a value in a map, and a usize index can be used to access an element of + /// an sequence. + /// + /// Returns `None` if the type of `self` does not match the type of the + /// index, for example if the index is a string and `self` is a sequence or + /// a number. Also returns `None` if the given key does not exist in the map + /// or the given index is not within the bounds of the sequence. + pub fn get_mut(&mut self, index: I) -> Option<&mut Value> { + index.index_into_mut(self) + } + + /// Returns true if the `Value` is a Null. Returns false otherwise. + /// + /// For any Value on which `is_null` returns true, `as_null` is guaranteed + /// to return `Some(())`. + /// + /// ``` + /// # use serde_yaml::Value; + /// let v: Value = serde_yaml::from_str("null").unwrap(); + /// assert!(v.is_null()); + /// ``` + /// + /// ``` + /// # use serde_yaml::Value; + /// let v: Value = serde_yaml::from_str("false").unwrap(); + /// assert!(!v.is_null()); + /// ``` + pub fn is_null(&self) -> bool { + if let Value::Null = self.untag_ref() { + true + } else { + false + } + } + + /// If the `Value` is a Null, returns (). Returns None otherwise. + /// + /// ``` + /// # use serde_yaml::Value; + /// let v: Value = serde_yaml::from_str("null").unwrap(); + /// assert_eq!(v.as_null(), Some(())); + /// ``` + /// + /// ``` + /// # use serde_yaml::Value; + /// let v: Value = serde_yaml::from_str("false").unwrap(); + /// assert_eq!(v.as_null(), None); + /// ``` + pub fn as_null(&self) -> Option<()> { + match self.untag_ref() { + Value::Null => Some(()), + _ => None, + } + } + + /// Returns true if the `Value` is a Boolean. Returns false otherwise. + /// + /// For any Value on which `is_boolean` returns true, `as_bool` is + /// guaranteed to return the boolean value. + /// + /// ``` + /// # use serde_yaml::Value; + /// let v: Value = serde_yaml::from_str("true").unwrap(); + /// assert!(v.is_bool()); + /// ``` + /// + /// ``` + /// # use serde_yaml::Value; + /// let v: Value = serde_yaml::from_str("42").unwrap(); + /// assert!(!v.is_bool()); + /// ``` + pub fn is_bool(&self) -> bool { + self.as_bool().is_some() + } + + /// If the `Value` is a Boolean, returns the associated bool. Returns None + /// otherwise. + /// + /// ``` + /// # use serde_yaml::Value; + /// let v: Value = serde_yaml::from_str("true").unwrap(); + /// assert_eq!(v.as_bool(), Some(true)); + /// ``` + /// + /// ``` + /// # use serde_yaml::Value; + /// let v: Value = serde_yaml::from_str("42").unwrap(); + /// assert_eq!(v.as_bool(), None); + /// ``` + pub fn as_bool(&self) -> Option { + match self.untag_ref() { + Value::Bool(b) => Some(*b), + _ => None, + } + } + + /// Returns true if the `Value` is a Number. Returns false otherwise. + /// + /// ``` + /// # use serde_yaml::Value; + /// let v: Value = serde_yaml::from_str("5").unwrap(); + /// assert!(v.is_number()); + /// ``` + /// + /// ``` + /// # use serde_yaml::Value; + /// let v: Value = serde_yaml::from_str("true").unwrap(); + /// assert!(!v.is_number()); + /// ``` + pub fn is_number(&self) -> bool { + match self.untag_ref() { + Value::Number(_) => true, + _ => false, + } + } + + /// Returns true if the `Value` is an integer between `i64::MIN` and + /// `i64::MAX`. + /// + /// For any Value on which `is_i64` returns true, `as_i64` is guaranteed to + /// return the integer value. + /// + /// ``` + /// # use serde_yaml::Value; + /// let v: Value = serde_yaml::from_str("1337").unwrap(); + /// assert!(v.is_i64()); + /// ``` + /// + /// ``` + /// # use serde_yaml::Value; + /// let v: Value = serde_yaml::from_str("null").unwrap(); + /// assert!(!v.is_i64()); + /// ``` + pub fn is_i64(&self) -> bool { + self.as_i64().is_some() + } + + /// If the `Value` is an integer, represent it as i64 if possible. Returns + /// None otherwise. + /// + /// ``` + /// # use serde_yaml::Value; + /// let v: Value = serde_yaml::from_str("1337").unwrap(); + /// assert_eq!(v.as_i64(), Some(1337)); + /// ``` + /// + /// ``` + /// # use serde_yaml::Value; + /// let v: Value = serde_yaml::from_str("false").unwrap(); + /// assert_eq!(v.as_i64(), None); + /// ``` + pub fn as_i64(&self) -> Option { + match self.untag_ref() { + Value::Number(n) => n.as_i64(), + _ => None, + } + } + + /// Returns true if the `Value` is an integer between `u64::MIN` and + /// `u64::MAX`. + /// + /// For any Value on which `is_u64` returns true, `as_u64` is guaranteed to + /// return the integer value. + /// + /// ``` + /// # use serde_yaml::Value; + /// let v: Value = serde_yaml::from_str("1337").unwrap(); + /// assert!(v.is_u64()); + /// ``` + /// + /// ``` + /// # use serde_yaml::Value; + /// let v: Value = serde_yaml::from_str("null").unwrap(); + /// assert!(!v.is_u64()); + /// ``` + pub fn is_u64(&self) -> bool { + self.as_u64().is_some() + } + + /// If the `Value` is an integer, represent it as u64 if possible. Returns + /// None otherwise. + /// + /// ``` + /// # use serde_yaml::Value; + /// let v: Value = serde_yaml::from_str("1337").unwrap(); + /// assert_eq!(v.as_u64(), Some(1337)); + /// ``` + /// + /// ``` + /// # use serde_yaml::Value; + /// let v: Value = serde_yaml::from_str("false").unwrap(); + /// assert_eq!(v.as_u64(), None); + /// ``` + pub fn as_u64(&self) -> Option { + match self.untag_ref() { + Value::Number(n) => n.as_u64(), + _ => None, + } + } + + /// Returns true if the `Value` is a number that can be represented by f64. + /// + /// For any Value on which `is_f64` returns true, `as_f64` is guaranteed to + /// return the floating point value. + /// + /// Currently this function returns true if and only if both `is_i64` and + /// `is_u64` return false but this is not a guarantee in the future. + /// + /// ``` + /// # use serde_yaml::Value; + /// let v: Value = serde_yaml::from_str("256.01").unwrap(); + /// assert!(v.is_f64()); + /// ``` + /// + /// ``` + /// # use serde_yaml::Value; + /// let v: Value = serde_yaml::from_str("true").unwrap(); + /// assert!(!v.is_f64()); + /// ``` + pub fn is_f64(&self) -> bool { + match self.untag_ref() { + Value::Number(n) => n.is_f64(), + _ => false, + } + } + + /// If the `Value` is a number, represent it as f64 if possible. Returns + /// None otherwise. + /// + /// ``` + /// # use serde_yaml::Value; + /// let v: Value = serde_yaml::from_str("13.37").unwrap(); + /// assert_eq!(v.as_f64(), Some(13.37)); + /// ``` + /// + /// ``` + /// # use serde_yaml::Value; + /// let v: Value = serde_yaml::from_str("false").unwrap(); + /// assert_eq!(v.as_f64(), None); + /// ``` + pub fn as_f64(&self) -> Option { + match self.untag_ref() { + Value::Number(i) => i.as_f64(), + _ => None, + } + } + + /// Returns true if the `Value` is a String. Returns false otherwise. + /// + /// For any Value on which `is_string` returns true, `as_str` is guaranteed + /// to return the string slice. + /// + /// ``` + /// # use serde_yaml::Value; + /// let v: Value = serde_yaml::from_str("'lorem ipsum'").unwrap(); + /// assert!(v.is_string()); + /// ``` + /// + /// ``` + /// # use serde_yaml::Value; + /// let v: Value = serde_yaml::from_str("42").unwrap(); + /// assert!(!v.is_string()); + /// ``` + pub fn is_string(&self) -> bool { + self.as_str().is_some() + } + + /// If the `Value` is a String, returns the associated str. Returns None + /// otherwise. + /// + /// ``` + /// # use serde_yaml::Value; + /// let v: Value = serde_yaml::from_str("'lorem ipsum'").unwrap(); + /// assert_eq!(v.as_str(), Some("lorem ipsum")); + /// ``` + /// + /// ``` + /// # use serde_yaml::Value; + /// let v: Value = serde_yaml::from_str("false").unwrap(); + /// assert_eq!(v.as_str(), None); + /// ``` + pub fn as_str(&self) -> Option<&str> { + match self.untag_ref() { + Value::String(s) => Some(s), + _ => None, + } + } + + /// Returns true if the `Value` is a sequence. Returns false otherwise. + /// + /// ``` + /// # use serde_yaml::Value; + /// let v: Value = serde_yaml::from_str("[1, 2, 3]").unwrap(); + /// assert!(v.is_sequence()); + /// ``` + /// + /// ``` + /// # use serde_yaml::Value; + /// let v: Value = serde_yaml::from_str("true").unwrap(); + /// assert!(!v.is_sequence()); + /// ``` + pub fn is_sequence(&self) -> bool { + self.as_sequence().is_some() + } + + /// If the `Value` is a sequence, return a reference to it if possible. + /// Returns None otherwise. + /// + /// ``` + /// # use serde_yaml::{Value, Number}; + /// let v: Value = serde_yaml::from_str("[1, 2]").unwrap(); + /// assert_eq!(v.as_sequence(), Some(&vec![Value::Number(Number::from(1)), Value::Number(Number::from(2))])); + /// ``` + /// + /// ``` + /// # use serde_yaml::Value; + /// let v: Value = serde_yaml::from_str("false").unwrap(); + /// assert_eq!(v.as_sequence(), None); + /// ``` + pub fn as_sequence(&self) -> Option<&Sequence> { + match self.untag_ref() { + Value::Sequence(seq) => Some(seq), + _ => None, + } + } + + /// If the `Value` is a sequence, return a mutable reference to it if + /// possible. Returns None otherwise. + /// + /// ``` + /// # use serde_yaml::{Value, Number}; + /// let mut v: Value = serde_yaml::from_str("[1]").unwrap(); + /// let s = v.as_sequence_mut().unwrap(); + /// s.push(Value::Number(Number::from(2))); + /// assert_eq!(s, &vec![Value::Number(Number::from(1)), Value::Number(Number::from(2))]); + /// ``` + /// + /// ``` + /// # use serde_yaml::Value; + /// let mut v: Value = serde_yaml::from_str("false").unwrap(); + /// assert_eq!(v.as_sequence_mut(), None); + /// ``` + pub fn as_sequence_mut(&mut self) -> Option<&mut Sequence> { + match self.untag_mut() { + Value::Sequence(seq) => Some(seq), + _ => None, + } + } + + /// Returns true if the `Value` is a mapping. Returns false otherwise. + /// + /// ``` + /// # use serde_yaml::Value; + /// let v: Value = serde_yaml::from_str("a: 42").unwrap(); + /// assert!(v.is_mapping()); + /// ``` + /// + /// ``` + /// # use serde_yaml::Value; + /// let v: Value = serde_yaml::from_str("true").unwrap(); + /// assert!(!v.is_mapping()); + /// ``` + pub fn is_mapping(&self) -> bool { + self.as_mapping().is_some() + } + + /// If the `Value` is a mapping, return a reference to it if possible. + /// Returns None otherwise. + /// + /// ``` + /// # use serde_yaml::{Value, Mapping, Number}; + /// let v: Value = serde_yaml::from_str("a: 42").unwrap(); + /// + /// let mut expected = Mapping::new(); + /// expected.insert(Value::String("a".into()),Value::Number(Number::from(42))); + /// + /// assert_eq!(v.as_mapping(), Some(&expected)); + /// ``` + /// + /// ``` + /// # use serde_yaml::Value; + /// let v: Value = serde_yaml::from_str("false").unwrap(); + /// assert_eq!(v.as_mapping(), None); + /// ``` + pub fn as_mapping(&self) -> Option<&Mapping> { + match self.untag_ref() { + Value::Mapping(map) => Some(map), + _ => None, + } + } + + /// If the `Value` is a mapping, return a reference to it if possible. + /// Returns None otherwise. + /// + /// ``` + /// # use serde_yaml::{Value, Mapping, Number}; + /// let mut v: Value = serde_yaml::from_str("a: 42").unwrap(); + /// let m = v.as_mapping_mut().unwrap(); + /// m.insert(Value::String("b".into()), Value::Number(Number::from(21))); + /// + /// let mut expected = Mapping::new(); + /// expected.insert(Value::String("a".into()), Value::Number(Number::from(42))); + /// expected.insert(Value::String("b".into()), Value::Number(Number::from(21))); + /// + /// assert_eq!(m, &expected); + /// ``` + /// + /// ``` + /// # use serde_yaml::{Value, Mapping}; + /// let mut v: Value = serde_yaml::from_str("false").unwrap(); + /// assert_eq!(v.as_mapping_mut(), None); + /// ``` + pub fn as_mapping_mut(&mut self) -> Option<&mut Mapping> { + match self.untag_mut() { + Value::Mapping(map) => Some(map), + _ => None, + } + } + + /// Performs merging of `<<` keys into the surrounding mapping. + /// + /// The intended use of this in YAML is described in + /// . + /// + /// ``` + /// use serde_yaml::Value; + /// + /// let config = "\ + /// tasks: + /// build: &webpack_shared + /// command: webpack + /// args: build + /// inputs: + /// - 'src/**/*' + /// start: + /// <<: *webpack_shared + /// args: start + /// "; + /// + /// let mut value: Value = serde_yaml::from_str(config).unwrap(); + /// value.apply_merge().unwrap(); + /// + /// assert_eq!(value["tasks"]["start"]["command"], "webpack"); + /// assert_eq!(value["tasks"]["start"]["args"], "start"); + /// ``` + pub fn apply_merge(&mut self) -> Result<(), Error> { + let mut stack = Vec::new(); + stack.push(self); + while let Some(node) = stack.pop() { + match node { + Value::Mapping(mapping) => { + match mapping.remove("<<") { + Some(Value::Mapping(merge)) => { + for (k, v) in merge { + mapping.entry(k).or_insert(v); + } + } + Some(Value::Sequence(sequence)) => { + for value in sequence { + match value { + Value::Mapping(merge) => { + for (k, v) in merge { + mapping.entry(k).or_insert(v); + } + } + Value::Sequence(_) => { + return Err(error::new(ErrorImpl::SequenceInMergeElement)); + } + Value::Tagged(_) => { + return Err(error::new(ErrorImpl::TaggedInMerge)); + } + _unexpected => { + return Err(error::new(ErrorImpl::ScalarInMergeElement)); + } + } + } + } + None => {} + Some(Value::Tagged(_)) => return Err(error::new(ErrorImpl::TaggedInMerge)), + Some(_unexpected) => return Err(error::new(ErrorImpl::ScalarInMerge)), + } + stack.extend(mapping.values_mut()); + } + Value::Sequence(sequence) => stack.extend(sequence), + Value::Tagged(tagged) => stack.push(&mut tagged.value), + _ => {} + } + } + Ok(()) + } +} + +impl Eq for Value {} + +// NOTE: This impl must be kept consistent with HashLikeValue's Hash impl in +// mapping.rs in order for value[str] indexing to work. +impl Hash for Value { + fn hash(&self, state: &mut H) { + mem::discriminant(self).hash(state); + match self { + Value::Null => {} + Value::Bool(v) => v.hash(state), + Value::Number(v) => v.hash(state), + Value::String(v) => v.hash(state), + Value::Sequence(v) => v.hash(state), + Value::Mapping(v) => v.hash(state), + Value::Tagged(v) => v.hash(state), + } + } +} + +impl<'de> IntoDeserializer<'de, Error> for Value { + type Deserializer = Self; + + fn into_deserializer(self) -> Self::Deserializer { + self + } +} diff --git a/kclvm/third-party/serde_yaml/src/value/partial_eq.rs b/kclvm/third-party/serde_yaml/src/value/partial_eq.rs new file mode 100644 index 000000000..023b7dd54 --- /dev/null +++ b/kclvm/third-party/serde_yaml/src/value/partial_eq.rs @@ -0,0 +1,87 @@ +use crate::Value; + +impl PartialEq for Value { + /// Compare `str` with YAML value + /// + /// # Examples + /// + /// ``` + /// # use serde_yaml::Value; + /// assert!(Value::String("lorem".into()) == *"lorem"); + /// ``` + fn eq(&self, other: &str) -> bool { + self.as_str().map_or(false, |s| s == other) + } +} + +impl<'a> PartialEq<&'a str> for Value { + /// Compare `&str` with YAML value + /// + /// # Examples + /// + /// ``` + /// # use serde_yaml::Value; + /// assert!(Value::String("lorem".into()) == "lorem"); + /// ``` + fn eq(&self, other: &&str) -> bool { + self.as_str().map_or(false, |s| s == *other) + } +} + +impl PartialEq for Value { + /// Compare YAML value with String + /// + /// # Examples + /// + /// ``` + /// # use serde_yaml::Value; + /// assert!(Value::String("lorem".into()) == "lorem".to_string()); + /// ``` + fn eq(&self, other: &String) -> bool { + self.as_str().map_or(false, |s| s == other) + } +} + +impl PartialEq for Value { + /// Compare YAML value with bool + /// + /// # Examples + /// + /// ``` + /// # use serde_yaml::Value; + /// assert!(Value::Bool(true) == true); + /// ``` + fn eq(&self, other: &bool) -> bool { + self.as_bool().map_or(false, |b| b == *other) + } +} + +macro_rules! partialeq_numeric { + ($([$($ty:ty)*], $conversion:ident, $base:ty)*) => { + $($( + impl PartialEq<$ty> for Value { + fn eq(&self, other: &$ty) -> bool { + self.$conversion().map_or(false, |i| i == (*other as $base)) + } + } + + impl<'a> PartialEq<$ty> for &'a Value { + fn eq(&self, other: &$ty) -> bool { + self.$conversion().map_or(false, |i| i == (*other as $base)) + } + } + + impl<'a> PartialEq<$ty> for &'a mut Value { + fn eq(&self, other: &$ty) -> bool { + self.$conversion().map_or(false, |i| i == (*other as $base)) + } + } + )*)* + } +} + +partialeq_numeric! { + [i8 i16 i32 i64 isize], as_i64, i64 + [u8 u16 u32 u64 usize], as_u64, u64 + [f32 f64], as_f64, f64 +} diff --git a/kclvm/third-party/serde_yaml/src/value/ser.rs b/kclvm/third-party/serde_yaml/src/value/ser.rs new file mode 100644 index 000000000..50b08d6b5 --- /dev/null +++ b/kclvm/third-party/serde_yaml/src/value/ser.rs @@ -0,0 +1,840 @@ +use crate::error::{self, Error, ErrorImpl}; +use crate::value::tagged::{self, MaybeTag}; +use crate::value::{to_value, Mapping, Number, Sequence, Tag, TaggedValue, Value}; +use serde::ser::{self, Serialize}; +use std::fmt::Display; +use std::mem; + +type Result = std::result::Result; + +impl Serialize for Value { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + match self { + Value::Null => serializer.serialize_unit(), + Value::Bool(b) => serializer.serialize_bool(*b), + Value::Number(n) => n.serialize(serializer), + Value::String(s) => serializer.serialize_str(s), + Value::Sequence(seq) => seq.serialize(serializer), + Value::Mapping(mapping) => { + use serde::ser::SerializeMap; + let mut map = serializer.serialize_map(Some(mapping.len()))?; + for (k, v) in mapping { + map.serialize_entry(k, v)?; + } + map.end() + } + Value::Tagged(tagged) => tagged.serialize(serializer), + } + } +} + +/// Serializer whose output is a `Value`. +/// +/// This is the serializer that backs [`serde_yaml::to_value`][crate::to_value]. +/// Unlike the main serde_yaml serializer which goes from some serializable +/// value of type `T` to YAML text, this one goes from `T` to +/// `serde_yaml::Value`. +/// +/// The `to_value` function is implementable as: +/// +/// ``` +/// use serde::Serialize; +/// use serde_yaml::{Error, Value}; +/// +/// pub fn to_value(input: T) -> Result +/// where +/// T: Serialize, +/// { +/// input.serialize(serde_yaml::value::Serializer) +/// } +/// ``` +pub struct Serializer; + +impl ser::Serializer for Serializer { + type Ok = Value; + type Error = Error; + + type SerializeSeq = SerializeArray; + type SerializeTuple = SerializeArray; + type SerializeTupleStruct = SerializeArray; + type SerializeTupleVariant = SerializeTupleVariant; + type SerializeMap = SerializeMap; + type SerializeStruct = SerializeStruct; + type SerializeStructVariant = SerializeStructVariant; + + fn serialize_bool(self, v: bool) -> Result { + Ok(Value::Bool(v)) + } + + fn serialize_i8(self, v: i8) -> Result { + Ok(Value::Number(Number::from(v))) + } + + fn serialize_i16(self, v: i16) -> Result { + Ok(Value::Number(Number::from(v))) + } + + fn serialize_i32(self, v: i32) -> Result { + Ok(Value::Number(Number::from(v))) + } + + fn serialize_i64(self, v: i64) -> Result { + Ok(Value::Number(Number::from(v))) + } + + fn serialize_i128(self, v: i128) -> Result { + if let Ok(v) = u64::try_from(v) { + self.serialize_u64(v) + } else if let Ok(v) = i64::try_from(v) { + self.serialize_i64(v) + } else { + Ok(Value::String(v.to_string())) + } + } + + fn serialize_u8(self, v: u8) -> Result { + Ok(Value::Number(Number::from(v))) + } + + fn serialize_u16(self, v: u16) -> Result { + Ok(Value::Number(Number::from(v))) + } + + fn serialize_u32(self, v: u32) -> Result { + Ok(Value::Number(Number::from(v))) + } + + fn serialize_u64(self, v: u64) -> Result { + Ok(Value::Number(Number::from(v))) + } + + fn serialize_u128(self, v: u128) -> Result { + if let Ok(v) = u64::try_from(v) { + self.serialize_u64(v) + } else { + Ok(Value::String(v.to_string())) + } + } + + fn serialize_f32(self, v: f32) -> Result { + Ok(Value::Number(Number::from(v))) + } + + fn serialize_f64(self, v: f64) -> Result { + Ok(Value::Number(Number::from(v))) + } + + fn serialize_char(self, value: char) -> Result { + Ok(Value::String(value.to_string())) + } + + fn serialize_str(self, value: &str) -> Result { + Ok(Value::String(value.to_owned())) + } + + fn serialize_bytes(self, value: &[u8]) -> Result { + let vec = value + .iter() + .map(|&b| Value::Number(Number::from(b))) + .collect(); + Ok(Value::Sequence(vec)) + } + + fn serialize_unit(self) -> Result { + Ok(Value::Null) + } + + fn serialize_unit_struct(self, _name: &'static str) -> Result { + self.serialize_unit() + } + + fn serialize_unit_variant( + self, + _name: &str, + _variant_index: u32, + variant: &str, + ) -> Result { + Ok(Value::String(variant.to_owned())) + } + + fn serialize_newtype_struct(self, _name: &'static str, value: &T) -> Result + where + T: ?Sized + ser::Serialize, + { + value.serialize(self) + } + + fn serialize_newtype_variant( + self, + _name: &str, + _variant_index: u32, + variant: &str, + value: &T, + ) -> Result + where + T: ?Sized + ser::Serialize, + { + if variant.is_empty() { + return Err(error::new(ErrorImpl::EmptyTag)); + } + Ok(Value::Tagged(Box::new(TaggedValue { + tag: Tag::new(variant), + value: to_value(value)?, + }))) + } + + fn serialize_none(self) -> Result { + self.serialize_unit() + } + + fn serialize_some(self, value: &V) -> Result + where + V: ?Sized + ser::Serialize, + { + value.serialize(self) + } + + fn serialize_seq(self, len: Option) -> Result { + let sequence = match len { + None => Sequence::new(), + Some(len) => Sequence::with_capacity(len), + }; + Ok(SerializeArray { sequence }) + } + + fn serialize_tuple(self, len: usize) -> Result { + self.serialize_seq(Some(len)) + } + + fn serialize_tuple_struct(self, _name: &'static str, len: usize) -> Result { + self.serialize_seq(Some(len)) + } + + fn serialize_tuple_variant( + self, + _enum: &'static str, + _idx: u32, + variant: &'static str, + len: usize, + ) -> Result { + if variant.is_empty() { + return Err(error::new(ErrorImpl::EmptyTag)); + } + Ok(SerializeTupleVariant { + tag: variant, + sequence: Sequence::with_capacity(len), + }) + } + + fn serialize_map(self, len: Option) -> Result { + if len == Some(1) { + Ok(SerializeMap::CheckForTag) + } else { + Ok(SerializeMap::Untagged { + mapping: Mapping::new(), + next_key: None, + }) + } + } + + fn serialize_struct(self, _name: &'static str, _len: usize) -> Result { + Ok(SerializeStruct { + mapping: Mapping::new(), + }) + } + + fn serialize_struct_variant( + self, + _enum: &'static str, + _idx: u32, + variant: &'static str, + _len: usize, + ) -> Result { + if variant.is_empty() { + return Err(error::new(ErrorImpl::EmptyTag)); + } + Ok(SerializeStructVariant { + tag: variant, + mapping: Mapping::new(), + }) + } +} + +pub struct SerializeArray { + sequence: Sequence, +} + +impl ser::SerializeSeq for SerializeArray { + type Ok = Value; + type Error = Error; + + fn serialize_element(&mut self, elem: &T) -> Result<()> + where + T: ?Sized + ser::Serialize, + { + self.sequence.push(to_value(elem)?); + Ok(()) + } + + fn end(self) -> Result { + Ok(Value::Sequence(self.sequence)) + } +} + +impl ser::SerializeTuple for SerializeArray { + type Ok = Value; + type Error = Error; + + fn serialize_element(&mut self, elem: &T) -> Result<()> + where + T: ?Sized + ser::Serialize, + { + ser::SerializeSeq::serialize_element(self, elem) + } + + fn end(self) -> Result { + ser::SerializeSeq::end(self) + } +} + +impl ser::SerializeTupleStruct for SerializeArray { + type Ok = Value; + type Error = Error; + + fn serialize_field(&mut self, value: &V) -> Result<()> + where + V: ?Sized + ser::Serialize, + { + ser::SerializeSeq::serialize_element(self, value) + } + + fn end(self) -> Result { + ser::SerializeSeq::end(self) + } +} + +pub struct SerializeTupleVariant { + tag: &'static str, + sequence: Sequence, +} + +impl ser::SerializeTupleVariant for SerializeTupleVariant { + type Ok = Value; + type Error = Error; + + fn serialize_field(&mut self, v: &V) -> Result<()> + where + V: ?Sized + ser::Serialize, + { + self.sequence.push(to_value(v)?); + Ok(()) + } + + fn end(self) -> Result { + Ok(Value::Tagged(Box::new(TaggedValue { + tag: Tag::new(self.tag), + value: Value::Sequence(self.sequence), + }))) + } +} + +pub enum SerializeMap { + CheckForTag, + Tagged(TaggedValue), + Untagged { + mapping: Mapping, + next_key: Option, + }, +} + +impl ser::SerializeMap for SerializeMap { + type Ok = Value; + type Error = Error; + + fn serialize_key(&mut self, key: &T) -> Result<()> + where + T: ?Sized + ser::Serialize, + { + let key = Some(to_value(key)?); + match self { + SerializeMap::CheckForTag => { + *self = SerializeMap::Untagged { + mapping: Mapping::new(), + next_key: key, + }; + } + SerializeMap::Tagged(tagged) => { + let mut mapping = Mapping::new(); + mapping.insert( + Value::String(tagged.tag.to_string()), + mem::take(&mut tagged.value), + ); + *self = SerializeMap::Untagged { + mapping, + next_key: key, + }; + } + SerializeMap::Untagged { next_key, .. } => *next_key = key, + } + Ok(()) + } + + fn serialize_value(&mut self, value: &T) -> Result<()> + where + T: ?Sized + ser::Serialize, + { + let (mapping, key) = match self { + SerializeMap::CheckForTag | SerializeMap::Tagged(_) => unreachable!(), + SerializeMap::Untagged { mapping, next_key } => (mapping, next_key), + }; + match key.take() { + Some(key) => mapping.insert(key, to_value(value)?), + None => panic!("serialize_value called before serialize_key"), + }; + Ok(()) + } + + fn serialize_entry(&mut self, key: &K, value: &V) -> Result<()> + where + K: ?Sized + ser::Serialize, + V: ?Sized + ser::Serialize, + { + struct CheckForTag; + struct NotTag { + delegate: T, + } + + impl ser::Serializer for CheckForTag { + type Ok = MaybeTag; + type Error = Error; + + type SerializeSeq = NotTag; + type SerializeTuple = NotTag; + type SerializeTupleStruct = NotTag; + type SerializeTupleVariant = NotTag; + type SerializeMap = NotTag; + type SerializeStruct = NotTag; + type SerializeStructVariant = NotTag; + + fn serialize_bool(self, v: bool) -> Result { + Serializer.serialize_bool(v).map(MaybeTag::NotTag) + } + + fn serialize_i8(self, v: i8) -> Result { + Serializer.serialize_i8(v).map(MaybeTag::NotTag) + } + + fn serialize_i16(self, v: i16) -> Result { + Serializer.serialize_i16(v).map(MaybeTag::NotTag) + } + + fn serialize_i32(self, v: i32) -> Result { + Serializer.serialize_i32(v).map(MaybeTag::NotTag) + } + + fn serialize_i64(self, v: i64) -> Result { + Serializer.serialize_i64(v).map(MaybeTag::NotTag) + } + + fn serialize_i128(self, v: i128) -> Result { + Serializer.serialize_i128(v).map(MaybeTag::NotTag) + } + + fn serialize_u8(self, v: u8) -> Result { + Serializer.serialize_u8(v).map(MaybeTag::NotTag) + } + + fn serialize_u16(self, v: u16) -> Result { + Serializer.serialize_u16(v).map(MaybeTag::NotTag) + } + + fn serialize_u32(self, v: u32) -> Result { + Serializer.serialize_u32(v).map(MaybeTag::NotTag) + } + + fn serialize_u64(self, v: u64) -> Result { + Serializer.serialize_u64(v).map(MaybeTag::NotTag) + } + + fn serialize_u128(self, v: u128) -> Result { + Serializer.serialize_u128(v).map(MaybeTag::NotTag) + } + + fn serialize_f32(self, v: f32) -> Result { + Serializer.serialize_f32(v).map(MaybeTag::NotTag) + } + + fn serialize_f64(self, v: f64) -> Result { + Serializer.serialize_f64(v).map(MaybeTag::NotTag) + } + + fn serialize_char(self, value: char) -> Result { + Serializer.serialize_char(value).map(MaybeTag::NotTag) + } + + fn serialize_str(self, value: &str) -> Result { + Serializer.serialize_str(value).map(MaybeTag::NotTag) + } + + fn serialize_bytes(self, value: &[u8]) -> Result { + Serializer.serialize_bytes(value).map(MaybeTag::NotTag) + } + + fn serialize_unit(self) -> Result { + Serializer.serialize_unit().map(MaybeTag::NotTag) + } + + fn serialize_unit_struct(self, name: &'static str) -> Result { + Serializer.serialize_unit_struct(name).map(MaybeTag::NotTag) + } + + fn serialize_unit_variant( + self, + name: &'static str, + variant_index: u32, + variant: &'static str, + ) -> Result { + Serializer + .serialize_unit_variant(name, variant_index, variant) + .map(MaybeTag::NotTag) + } + + fn serialize_newtype_struct(self, name: &'static str, value: &T) -> Result + where + T: ?Sized + ser::Serialize, + { + Serializer + .serialize_newtype_struct(name, value) + .map(MaybeTag::NotTag) + } + + fn serialize_newtype_variant( + self, + name: &'static str, + variant_index: u32, + variant: &'static str, + value: &T, + ) -> Result + where + T: ?Sized + ser::Serialize, + { + Serializer + .serialize_newtype_variant(name, variant_index, variant, value) + .map(MaybeTag::NotTag) + } + + fn serialize_none(self) -> Result { + Serializer.serialize_none().map(MaybeTag::NotTag) + } + + fn serialize_some(self, value: &V) -> Result + where + V: ?Sized + ser::Serialize, + { + Serializer.serialize_some(value).map(MaybeTag::NotTag) + } + + fn serialize_seq(self, len: Option) -> Result { + Ok(NotTag { + delegate: Serializer.serialize_seq(len)?, + }) + } + + fn serialize_tuple(self, len: usize) -> Result { + Ok(NotTag { + delegate: Serializer.serialize_tuple(len)?, + }) + } + + fn serialize_tuple_struct( + self, + name: &'static str, + len: usize, + ) -> Result { + Ok(NotTag { + delegate: Serializer.serialize_tuple_struct(name, len)?, + }) + } + + fn serialize_tuple_variant( + self, + name: &'static str, + variant_index: u32, + variant: &'static str, + len: usize, + ) -> Result { + Ok(NotTag { + delegate: Serializer.serialize_tuple_variant( + name, + variant_index, + variant, + len, + )?, + }) + } + + fn serialize_map(self, len: Option) -> Result { + Ok(NotTag { + delegate: Serializer.serialize_map(len)?, + }) + } + + fn serialize_struct( + self, + name: &'static str, + len: usize, + ) -> Result { + Ok(NotTag { + delegate: Serializer.serialize_struct(name, len)?, + }) + } + + fn serialize_struct_variant( + self, + name: &'static str, + variant_index: u32, + variant: &'static str, + len: usize, + ) -> Result { + Ok(NotTag { + delegate: Serializer.serialize_struct_variant( + name, + variant_index, + variant, + len, + )?, + }) + } + + fn collect_str(self, value: &T) -> Result + where + T: ?Sized + Display, + { + Ok(match tagged::check_for_tag(value) { + MaybeTag::Tag(tag) => MaybeTag::Tag(tag), + MaybeTag::NotTag(string) => MaybeTag::NotTag(Value::String(string)), + }) + } + } + + impl ser::SerializeSeq for NotTag { + type Ok = MaybeTag; + type Error = Error; + + fn serialize_element(&mut self, elem: &T) -> Result<()> + where + T: ?Sized + ser::Serialize, + { + self.delegate.serialize_element(elem) + } + + fn end(self) -> Result { + self.delegate.end().map(MaybeTag::NotTag) + } + } + + impl ser::SerializeTuple for NotTag { + type Ok = MaybeTag; + type Error = Error; + + fn serialize_element(&mut self, elem: &T) -> Result<()> + where + T: ?Sized + ser::Serialize, + { + self.delegate.serialize_element(elem) + } + + fn end(self) -> Result { + self.delegate.end().map(MaybeTag::NotTag) + } + } + + impl ser::SerializeTupleStruct for NotTag { + type Ok = MaybeTag; + type Error = Error; + + fn serialize_field(&mut self, value: &V) -> Result<()> + where + V: ?Sized + ser::Serialize, + { + self.delegate.serialize_field(value) + } + + fn end(self) -> Result { + self.delegate.end().map(MaybeTag::NotTag) + } + } + + impl ser::SerializeTupleVariant for NotTag { + type Ok = MaybeTag; + type Error = Error; + + fn serialize_field(&mut self, v: &V) -> Result<()> + where + V: ?Sized + ser::Serialize, + { + self.delegate.serialize_field(v) + } + + fn end(self) -> Result { + self.delegate.end().map(MaybeTag::NotTag) + } + } + + impl ser::SerializeMap for NotTag { + type Ok = MaybeTag; + type Error = Error; + + fn serialize_key(&mut self, key: &T) -> Result<()> + where + T: ?Sized + ser::Serialize, + { + self.delegate.serialize_key(key) + } + + fn serialize_value(&mut self, value: &T) -> Result<()> + where + T: ?Sized + ser::Serialize, + { + self.delegate.serialize_value(value) + } + + fn serialize_entry(&mut self, key: &K, value: &V) -> Result<()> + where + K: ?Sized + ser::Serialize, + V: ?Sized + ser::Serialize, + { + self.delegate.serialize_entry(key, value) + } + + fn end(self) -> Result { + self.delegate.end().map(MaybeTag::NotTag) + } + } + + impl ser::SerializeStruct for NotTag { + type Ok = MaybeTag; + type Error = Error; + + fn serialize_field(&mut self, key: &'static str, value: &V) -> Result<()> + where + V: ?Sized + ser::Serialize, + { + self.delegate.serialize_field(key, value) + } + + fn end(self) -> Result { + self.delegate.end().map(MaybeTag::NotTag) + } + } + + impl ser::SerializeStructVariant for NotTag { + type Ok = MaybeTag; + type Error = Error; + + fn serialize_field(&mut self, field: &'static str, v: &V) -> Result<()> + where + V: ?Sized + ser::Serialize, + { + self.delegate.serialize_field(field, v) + } + + fn end(self) -> Result { + self.delegate.end().map(MaybeTag::NotTag) + } + } + + match self { + SerializeMap::CheckForTag => { + let key = key.serialize(CheckForTag)?; + let mut mapping = Mapping::new(); + *self = match key { + MaybeTag::Tag(string) => SerializeMap::Tagged(TaggedValue { + tag: Tag::new(string), + value: to_value(value)?, + }), + MaybeTag::NotTag(key) => { + mapping.insert(key, to_value(value)?); + SerializeMap::Untagged { + mapping, + next_key: None, + } + } + }; + } + SerializeMap::Tagged(tagged) => { + let mut mapping = Mapping::new(); + mapping.insert( + Value::String(tagged.tag.to_string()), + mem::take(&mut tagged.value), + ); + mapping.insert(to_value(key)?, to_value(value)?); + *self = SerializeMap::Untagged { + mapping, + next_key: None, + }; + } + SerializeMap::Untagged { mapping, .. } => { + mapping.insert(to_value(key)?, to_value(value)?); + } + } + Ok(()) + } + + fn end(self) -> Result { + Ok(match self { + SerializeMap::CheckForTag => Value::Mapping(Mapping::new()), + SerializeMap::Tagged(tagged) => Value::Tagged(Box::new(tagged)), + SerializeMap::Untagged { mapping, .. } => Value::Mapping(mapping), + }) + } +} + +pub struct SerializeStruct { + mapping: Mapping, +} + +impl ser::SerializeStruct for SerializeStruct { + type Ok = Value; + type Error = Error; + + fn serialize_field(&mut self, key: &'static str, value: &V) -> Result<()> + where + V: ?Sized + ser::Serialize, + { + self.mapping.insert(to_value(key)?, to_value(value)?); + Ok(()) + } + + fn end(self) -> Result { + Ok(Value::Mapping(self.mapping)) + } +} + +pub struct SerializeStructVariant { + tag: &'static str, + mapping: Mapping, +} + +impl ser::SerializeStructVariant for SerializeStructVariant { + type Ok = Value; + type Error = Error; + + fn serialize_field(&mut self, field: &'static str, v: &V) -> Result<()> + where + V: ?Sized + ser::Serialize, + { + self.mapping.insert(to_value(field)?, to_value(v)?); + Ok(()) + } + + fn end(self) -> Result { + Ok(Value::Tagged(Box::new(TaggedValue { + tag: Tag::new(self.tag), + value: Value::Mapping(self.mapping), + }))) + } +} diff --git a/kclvm/third-party/serde_yaml/src/value/tagged.rs b/kclvm/third-party/serde_yaml/src/value/tagged.rs new file mode 100644 index 000000000..baf6a0aeb --- /dev/null +++ b/kclvm/third-party/serde_yaml/src/value/tagged.rs @@ -0,0 +1,474 @@ +use crate::value::de::{MapDeserializer, MapRefDeserializer, SeqDeserializer, SeqRefDeserializer}; +use crate::value::Value; +use crate::Error; +use serde::de::value::{BorrowedStrDeserializer, StrDeserializer}; +use serde::de::{ + Deserialize, DeserializeSeed, Deserializer, EnumAccess, Error as _, VariantAccess, Visitor, +}; +use serde::forward_to_deserialize_any; +use serde::ser::{Serialize, SerializeMap, Serializer}; +use std::cmp::Ordering; +use std::fmt::{self, Debug, Display}; +use std::hash::{Hash, Hasher}; +use std::mem; + +/// A representation of YAML's `!Tag` syntax, used for enums. +/// +/// Refer to the example code on [`TaggedValue`] for an example of deserializing +/// tagged values. +#[derive(Clone)] +pub struct Tag { + pub(crate) string: String, +} + +/// A `Tag` + `Value` representing a tagged YAML scalar, sequence, or mapping. +/// +/// ``` +/// use serde_yaml::value::TaggedValue; +/// use std::collections::BTreeMap; +/// +/// let yaml = " +/// scalar: !Thing x +/// sequence_flow: !Thing [first] +/// sequence_block: !Thing +/// - first +/// mapping_flow: !Thing {k: v} +/// mapping_block: !Thing +/// k: v +/// "; +/// +/// let data: BTreeMap = serde_yaml::from_str(yaml).unwrap(); +/// assert!(data["scalar"].tag == "Thing"); +/// assert!(data["sequence_flow"].tag == "Thing"); +/// assert!(data["sequence_block"].tag == "Thing"); +/// assert!(data["mapping_flow"].tag == "Thing"); +/// assert!(data["mapping_block"].tag == "Thing"); +/// +/// // The leading '!' in tags are not significant. The following is also true. +/// assert!(data["scalar"].tag == "!Thing"); +/// ``` +#[derive(Clone, PartialEq, PartialOrd, Hash, Debug)] +pub struct TaggedValue { + #[allow(missing_docs)] + pub tag: Tag, + #[allow(missing_docs)] + pub value: Value, +} + +impl Tag { + /// Create tag. + /// + /// The leading '!' is not significant. It may be provided, but does not + /// have to be. The following are equivalent: + /// + /// ``` + /// use serde_yaml::value::Tag; + /// + /// assert_eq!(Tag::new("!Thing"), Tag::new("Thing")); + /// + /// let tag = Tag::new("Thing"); + /// assert!(tag == "Thing"); + /// assert!(tag == "!Thing"); + /// assert!(tag.to_string() == "!Thing"); + /// + /// let tag = Tag::new("!Thing"); + /// assert!(tag == "Thing"); + /// assert!(tag == "!Thing"); + /// assert!(tag.to_string() == "!Thing"); + /// ``` + /// + /// Such a tag would serialize to `!Thing` in YAML regardless of whether a + /// '!' was included in the call to `Tag::new`. + /// + /// # Panics + /// + /// Panics if `string.is_empty()`. There is no syntax in YAML for an empty + /// tag. + pub fn new(string: impl Into) -> Self { + let tag: String = string.into(); + assert!(!tag.is_empty(), "empty YAML tag is not allowed"); + Tag { string: tag } + } +} + +impl Value { + pub(crate) fn untag(self) -> Self { + let mut cur = self; + while let Value::Tagged(tagged) = cur { + cur = tagged.value; + } + cur + } + + pub(crate) fn untag_ref(&self) -> &Self { + let mut cur = self; + while let Value::Tagged(tagged) = cur { + cur = &tagged.value; + } + cur + } + + pub(crate) fn untag_mut(&mut self) -> &mut Self { + let mut cur = self; + while let Value::Tagged(tagged) = cur { + cur = &mut tagged.value; + } + cur + } +} + +pub(crate) fn nobang(maybe_banged: &str) -> &str { + match maybe_banged.strip_prefix('!') { + Some("") | None => maybe_banged, + Some(unbanged) => unbanged, + } +} + +impl Eq for Tag {} + +impl PartialEq for Tag { + fn eq(&self, other: &Tag) -> bool { + PartialEq::eq(nobang(&self.string), nobang(&other.string)) + } +} + +impl PartialEq for Tag +where + T: ?Sized + AsRef, +{ + fn eq(&self, other: &T) -> bool { + PartialEq::eq(nobang(&self.string), nobang(other.as_ref())) + } +} + +impl Ord for Tag { + fn cmp(&self, other: &Self) -> Ordering { + Ord::cmp(nobang(&self.string), nobang(&other.string)) + } +} + +impl PartialOrd for Tag { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +impl Hash for Tag { + fn hash(&self, hasher: &mut H) { + nobang(&self.string).hash(hasher); + } +} + +impl Display for Tag { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + write!(formatter, "!{}", nobang(&self.string)) + } +} + +impl Debug for Tag { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + Display::fmt(self, formatter) + } +} + +impl Serialize for TaggedValue { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + struct SerializeTag<'a>(&'a Tag); + + impl<'a> Serialize for SerializeTag<'a> { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.collect_str(self.0) + } + } + + let mut map = serializer.serialize_map(Some(1))?; + map.serialize_entry(&SerializeTag(&self.tag), &self.value)?; + map.end() + } +} + +impl<'de> Deserialize<'de> for TaggedValue { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct TaggedValueVisitor; + + impl<'de> Visitor<'de> for TaggedValueVisitor { + type Value = TaggedValue; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a YAML value with a !Tag") + } + + fn visit_enum(self, data: A) -> Result + where + A: EnumAccess<'de>, + { + let (tag, contents) = data.variant_seed(TagStringVisitor)?; + let value = contents.newtype_variant()?; + Ok(TaggedValue { tag, value }) + } + } + + deserializer.deserialize_any(TaggedValueVisitor) + } +} + +impl<'de> Deserializer<'de> for TaggedValue { + type Error = Error; + + fn deserialize_any(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + visitor.visit_enum(self) + } + + fn deserialize_ignored_any(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + drop(self); + visitor.visit_unit() + } + + forward_to_deserialize_any! { + bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char str string bytes + byte_buf option unit unit_struct newtype_struct seq tuple tuple_struct + map struct enum identifier + } +} + +impl<'de> EnumAccess<'de> for TaggedValue { + type Error = Error; + type Variant = Value; + + fn variant_seed(self, seed: V) -> Result<(V::Value, Self::Variant), Error> + where + V: DeserializeSeed<'de>, + { + let tag = StrDeserializer::::new(nobang(&self.tag.string)); + let value = seed.deserialize(tag)?; + Ok((value, self.value)) + } +} + +impl<'de> VariantAccess<'de> for Value { + type Error = Error; + + fn unit_variant(self) -> Result<(), Error> { + Deserialize::deserialize(self) + } + + fn newtype_variant_seed(self, seed: T) -> Result + where + T: DeserializeSeed<'de>, + { + seed.deserialize(self) + } + + fn tuple_variant(self, _len: usize, visitor: V) -> Result + where + V: Visitor<'de>, + { + if let Value::Sequence(v) = self { + Deserializer::deserialize_any(SeqDeserializer::new(v), visitor) + } else { + Err(Error::invalid_type(self.unexpected(), &"tuple variant")) + } + } + + fn struct_variant( + self, + _fields: &'static [&'static str], + visitor: V, + ) -> Result + where + V: Visitor<'de>, + { + if let Value::Mapping(v) = self { + Deserializer::deserialize_any(MapDeserializer::new(v), visitor) + } else { + Err(Error::invalid_type(self.unexpected(), &"struct variant")) + } + } +} + +impl<'de> Deserializer<'de> for &'de TaggedValue { + type Error = Error; + + fn deserialize_any(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + visitor.visit_enum(self) + } + + fn deserialize_ignored_any(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + visitor.visit_unit() + } + + forward_to_deserialize_any! { + bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char str string bytes + byte_buf option unit unit_struct newtype_struct seq tuple tuple_struct + map struct enum identifier + } +} + +impl<'de> EnumAccess<'de> for &'de TaggedValue { + type Error = Error; + type Variant = &'de Value; + + fn variant_seed(self, seed: V) -> Result<(V::Value, Self::Variant), Error> + where + V: DeserializeSeed<'de>, + { + let tag = BorrowedStrDeserializer::::new(nobang(&self.tag.string)); + let value = seed.deserialize(tag)?; + Ok((value, &self.value)) + } +} + +impl<'de> VariantAccess<'de> for &'de Value { + type Error = Error; + + fn unit_variant(self) -> Result<(), Error> { + Deserialize::deserialize(self) + } + + fn newtype_variant_seed(self, seed: T) -> Result + where + T: DeserializeSeed<'de>, + { + seed.deserialize(self) + } + + fn tuple_variant(self, _len: usize, visitor: V) -> Result + where + V: Visitor<'de>, + { + if let Value::Sequence(v) = self { + Deserializer::deserialize_any(SeqRefDeserializer::new(v), visitor) + } else { + Err(Error::invalid_type(self.unexpected(), &"tuple variant")) + } + } + + fn struct_variant( + self, + _fields: &'static [&'static str], + visitor: V, + ) -> Result + where + V: Visitor<'de>, + { + if let Value::Mapping(v) = self { + Deserializer::deserialize_any(MapRefDeserializer::new(v), visitor) + } else { + Err(Error::invalid_type(self.unexpected(), &"struct variant")) + } + } +} + +pub(crate) struct TagStringVisitor; + +impl<'de> Visitor<'de> for TagStringVisitor { + type Value = Tag; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a YAML tag string") + } + + fn visit_str(self, string: &str) -> Result + where + E: serde::de::Error, + { + self.visit_string(string.to_owned()) + } + + fn visit_string(self, string: String) -> Result + where + E: serde::de::Error, + { + if string.is_empty() { + return Err(E::custom("empty YAML tag is not allowed")); + } + Ok(Tag::new(string)) + } +} + +impl<'de> DeserializeSeed<'de> for TagStringVisitor { + type Value = Tag; + + fn deserialize(self, deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_string(self) + } +} + +pub(crate) enum MaybeTag { + Tag(String), + NotTag(T), +} + +pub(crate) fn check_for_tag(value: &T) -> MaybeTag +where + T: ?Sized + Display, +{ + enum CheckForTag { + Empty, + Bang, + Tag(String), + NotTag(String), + } + + impl fmt::Write for CheckForTag { + fn write_str(&mut self, s: &str) -> fmt::Result { + if s.is_empty() { + return Ok(()); + } + match self { + CheckForTag::Empty => { + if s == "!" { + *self = CheckForTag::Bang; + } else { + *self = CheckForTag::NotTag(s.to_owned()); + } + } + CheckForTag::Bang => { + *self = CheckForTag::Tag(s.to_owned()); + } + CheckForTag::Tag(string) => { + let mut string = mem::take(string); + string.push_str(s); + *self = CheckForTag::NotTag(string); + } + CheckForTag::NotTag(string) => { + string.push_str(s); + } + } + Ok(()) + } + } + + let mut check_for_tag = CheckForTag::Empty; + fmt::write(&mut check_for_tag, format_args!("{}", value)).unwrap(); + match check_for_tag { + CheckForTag::Empty => MaybeTag::NotTag(String::new()), + CheckForTag::Bang => MaybeTag::NotTag("!".to_owned()), + CheckForTag::Tag(string) => MaybeTag::Tag(string), + CheckForTag::NotTag(string) => MaybeTag::NotTag(string), + } +} diff --git a/kclvm/third-party/serde_yaml/src/with.rs b/kclvm/third-party/serde_yaml/src/with.rs new file mode 100644 index 000000000..51d5baab4 --- /dev/null +++ b/kclvm/third-party/serde_yaml/src/with.rs @@ -0,0 +1,2127 @@ +//! Customizations to use with Serde's `#[serde(with = …)]` attribute. + +/// Serialize/deserialize an enum using a YAML map containing one entry in which +/// the key identifies the variant name. +/// +/// # Example +/// +/// ``` +/// # use serde_derive::{Deserialize, Serialize}; +/// # use serde::Deserialize as _; +/// # use serde::Serialize as _; +/// +/// #[derive(Serialize, Deserialize, PartialEq, Debug)] +/// enum Enum { +/// Unit, +/// Newtype(usize), +/// Tuple(usize, usize), +/// Struct { value: usize }, +/// } +/// +/// #[derive(Serialize, Deserialize, PartialEq, Debug)] +/// struct Struct { +/// #[serde(with = "serde_yaml::with::singleton_map")] +/// w: Enum, +/// #[serde(with = "serde_yaml::with::singleton_map")] +/// x: Enum, +/// #[serde(with = "serde_yaml::with::singleton_map")] +/// y: Enum, +/// #[serde(with = "serde_yaml::with::singleton_map")] +/// z: Enum, +/// } +/// +/// fn main() { +/// let object = Struct { +/// w: Enum::Unit, +/// x: Enum::Newtype(1), +/// y: Enum::Tuple(1, 1), +/// z: Enum::Struct { value: 1 }, +/// }; +/// +/// let yaml = serde_yaml::to_string(&object).unwrap(); +/// print!("{}", yaml); +/// +/// let deserialized: Struct = serde_yaml::from_str(&yaml).unwrap(); +/// assert_eq!(object, deserialized); +/// } +/// ``` +/// +/// The representation using `singleton_map` on all the fields is: +/// +/// ```yaml +/// w: Unit +/// x: +/// Newtype: 1 +/// y: +/// Tuple: +/// - 1 +/// - 1 +/// z: +/// Struct: +/// value: 1 +/// ``` +/// +/// Without `singleton_map`, the default behavior would have been to serialize +/// as: +/// +/// ```yaml +/// w: Unit +/// x: !Newtype 1 +/// y: !Tuple +/// - 1 +/// - 1 +/// z: !Struct +/// value: 1 +/// ``` +pub mod singleton_map { + use crate::value::{Mapping, Sequence, Value}; + use serde::de::{ + self, Deserialize, DeserializeSeed, Deserializer, EnumAccess, IgnoredAny, MapAccess, + Unexpected, VariantAccess, Visitor, + }; + use serde::ser::{ + self, Serialize, SerializeMap, SerializeStructVariant, SerializeTupleVariant, Serializer, + }; + use std::fmt::{self, Display}; + + #[allow(missing_docs)] + pub fn serialize(value: &T, serializer: S) -> Result + where + T: Serialize, + S: Serializer, + { + value.serialize(SingletonMap { + delegate: serializer, + }) + } + + #[allow(missing_docs)] + pub fn deserialize<'de, T, D>(deserializer: D) -> Result + where + T: Deserialize<'de>, + D: Deserializer<'de>, + { + T::deserialize(SingletonMap { + delegate: deserializer, + }) + } + + struct SingletonMap { + delegate: D, + } + + impl Serialize for SingletonMap + where + D: Serialize, + { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + self.delegate.serialize(SingletonMap { + delegate: serializer, + }) + } + } + + impl Serializer for SingletonMap + where + D: Serializer, + { + type Ok = D::Ok; + type Error = D::Error; + + type SerializeSeq = D::SerializeSeq; + type SerializeTuple = D::SerializeTuple; + type SerializeTupleStruct = D::SerializeTupleStruct; + type SerializeTupleVariant = SerializeTupleVariantAsSingletonMap; + type SerializeMap = D::SerializeMap; + type SerializeStruct = D::SerializeStruct; + type SerializeStructVariant = SerializeStructVariantAsSingletonMap; + + fn serialize_bool(self, v: bool) -> Result { + self.delegate.serialize_bool(v) + } + + fn serialize_i8(self, v: i8) -> Result { + self.delegate.serialize_i8(v) + } + + fn serialize_i16(self, v: i16) -> Result { + self.delegate.serialize_i16(v) + } + + fn serialize_i32(self, v: i32) -> Result { + self.delegate.serialize_i32(v) + } + + fn serialize_i64(self, v: i64) -> Result { + self.delegate.serialize_i64(v) + } + + fn serialize_i128(self, v: i128) -> Result { + self.delegate.serialize_i128(v) + } + + fn serialize_u8(self, v: u8) -> Result { + self.delegate.serialize_u8(v) + } + + fn serialize_u16(self, v: u16) -> Result { + self.delegate.serialize_u16(v) + } + + fn serialize_u32(self, v: u32) -> Result { + self.delegate.serialize_u32(v) + } + + fn serialize_u64(self, v: u64) -> Result { + self.delegate.serialize_u64(v) + } + + fn serialize_u128(self, v: u128) -> Result { + self.delegate.serialize_u128(v) + } + + fn serialize_f32(self, v: f32) -> Result { + self.delegate.serialize_f32(v) + } + + fn serialize_f64(self, v: f64) -> Result { + self.delegate.serialize_f64(v) + } + + fn serialize_char(self, v: char) -> Result { + self.delegate.serialize_char(v) + } + + fn serialize_str(self, v: &str) -> Result { + self.delegate.serialize_str(v) + } + + fn serialize_bytes(self, v: &[u8]) -> Result { + self.delegate.serialize_bytes(v) + } + + fn serialize_unit(self) -> Result { + self.delegate.serialize_unit() + } + + fn serialize_unit_struct(self, name: &'static str) -> Result { + self.delegate.serialize_unit_struct(name) + } + + fn serialize_unit_variant( + self, + name: &'static str, + variant_index: u32, + variant: &'static str, + ) -> Result { + self.delegate + .serialize_unit_variant(name, variant_index, variant) + } + + fn serialize_newtype_struct( + self, + name: &'static str, + value: &T, + ) -> Result + where + T: ?Sized + Serialize, + { + self.delegate.serialize_newtype_struct(name, value) + } + + fn serialize_newtype_variant( + self, + _name: &'static str, + _variant_index: u32, + variant: &'static str, + value: &T, + ) -> Result + where + T: ?Sized + Serialize, + { + let mut map = self.delegate.serialize_map(Some(1))?; + map.serialize_entry(variant, value)?; + map.end() + } + + fn serialize_none(self) -> Result { + self.delegate.serialize_none() + } + + fn serialize_some(self, value: &V) -> Result + where + V: ?Sized + Serialize, + { + self.delegate + .serialize_some(&SingletonMap { delegate: value }) + } + + fn serialize_seq(self, len: Option) -> Result { + self.delegate.serialize_seq(len) + } + + fn serialize_tuple(self, len: usize) -> Result { + self.delegate.serialize_tuple(len) + } + + fn serialize_tuple_struct( + self, + name: &'static str, + len: usize, + ) -> Result { + self.delegate.serialize_tuple_struct(name, len) + } + + fn serialize_tuple_variant( + self, + _name: &'static str, + _variant_index: u32, + variant: &'static str, + len: usize, + ) -> Result { + let mut map = self.delegate.serialize_map(Some(1))?; + map.serialize_key(variant)?; + let sequence = Sequence::with_capacity(len); + Ok(SerializeTupleVariantAsSingletonMap { map, sequence }) + } + + fn serialize_map(self, len: Option) -> Result { + self.delegate.serialize_map(len) + } + + fn serialize_struct( + self, + name: &'static str, + len: usize, + ) -> Result { + self.delegate.serialize_struct(name, len) + } + + fn serialize_struct_variant( + self, + _name: &'static str, + _variant_index: u32, + variant: &'static str, + len: usize, + ) -> Result { + let mut map = self.delegate.serialize_map(Some(1))?; + map.serialize_key(variant)?; + let mapping = Mapping::with_capacity(len); + Ok(SerializeStructVariantAsSingletonMap { map, mapping }) + } + + fn collect_str(self, value: &T) -> Result + where + T: ?Sized + Display, + { + self.delegate.collect_str(value) + } + + fn is_human_readable(&self) -> bool { + self.delegate.is_human_readable() + } + } + + struct SerializeTupleVariantAsSingletonMap { + map: M, + sequence: Sequence, + } + + impl SerializeTupleVariant for SerializeTupleVariantAsSingletonMap + where + M: SerializeMap, + { + type Ok = M::Ok; + type Error = M::Error; + + fn serialize_field(&mut self, field: &T) -> Result<(), Self::Error> + where + T: ?Sized + Serialize, + { + let value = field + .serialize(crate::value::Serializer) + .map_err(ser::Error::custom)?; + self.sequence.push(value); + Ok(()) + } + + fn end(mut self) -> Result { + self.map.serialize_value(&self.sequence)?; + self.map.end() + } + } + + struct SerializeStructVariantAsSingletonMap { + map: M, + mapping: Mapping, + } + + impl SerializeStructVariant for SerializeStructVariantAsSingletonMap + where + M: SerializeMap, + { + type Ok = M::Ok; + type Error = M::Error; + + fn serialize_field(&mut self, name: &'static str, field: &T) -> Result<(), Self::Error> + where + T: ?Sized + Serialize, + { + let value = field + .serialize(crate::value::Serializer) + .map_err(ser::Error::custom)?; + self.mapping.insert(Value::String(name.to_owned()), value); + Ok(()) + } + + fn end(mut self) -> Result { + self.map.serialize_value(&self.mapping)?; + self.map.end() + } + } + + impl<'de, D> Deserializer<'de> for SingletonMap + where + D: Deserializer<'de>, + { + type Error = D::Error; + + fn deserialize_any(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.delegate.deserialize_any(visitor) + } + + fn deserialize_bool(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.delegate.deserialize_bool(visitor) + } + + fn deserialize_i8(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.delegate.deserialize_i8(visitor) + } + + fn deserialize_i16(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.delegate.deserialize_i16(visitor) + } + + fn deserialize_i32(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.delegate.deserialize_i32(visitor) + } + + fn deserialize_i64(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.delegate.deserialize_i64(visitor) + } + + fn deserialize_i128(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.delegate.deserialize_i128(visitor) + } + + fn deserialize_u8(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.delegate.deserialize_u8(visitor) + } + + fn deserialize_u16(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.delegate.deserialize_u16(visitor) + } + + fn deserialize_u32(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.delegate.deserialize_u32(visitor) + } + + fn deserialize_u64(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.delegate.deserialize_u64(visitor) + } + + fn deserialize_u128(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.delegate.deserialize_u128(visitor) + } + + fn deserialize_f32(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.delegate.deserialize_f32(visitor) + } + + fn deserialize_f64(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.delegate.deserialize_f64(visitor) + } + + fn deserialize_char(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.delegate.deserialize_char(visitor) + } + + fn deserialize_str(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.delegate.deserialize_str(visitor) + } + + fn deserialize_string(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.delegate.deserialize_string(visitor) + } + + fn deserialize_bytes(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.delegate.deserialize_bytes(visitor) + } + + fn deserialize_byte_buf(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.delegate.deserialize_byte_buf(visitor) + } + + fn deserialize_option(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.delegate.deserialize_option(SingletonMapAsEnum { + name: "", + delegate: visitor, + }) + } + + fn deserialize_unit(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.delegate.deserialize_unit(visitor) + } + + fn deserialize_unit_struct( + self, + name: &'static str, + visitor: V, + ) -> Result + where + V: Visitor<'de>, + { + self.delegate.deserialize_unit_struct(name, visitor) + } + + fn deserialize_newtype_struct( + self, + name: &'static str, + visitor: V, + ) -> Result + where + V: Visitor<'de>, + { + self.delegate.deserialize_newtype_struct(name, visitor) + } + + fn deserialize_seq(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.delegate.deserialize_seq(visitor) + } + + fn deserialize_tuple(self, len: usize, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.delegate.deserialize_tuple(len, visitor) + } + + fn deserialize_tuple_struct( + self, + name: &'static str, + len: usize, + visitor: V, + ) -> Result + where + V: Visitor<'de>, + { + self.delegate.deserialize_tuple_struct(name, len, visitor) + } + + fn deserialize_map(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.delegate.deserialize_map(visitor) + } + + fn deserialize_struct( + self, + name: &'static str, + fields: &'static [&'static str], + visitor: V, + ) -> Result + where + V: Visitor<'de>, + { + self.delegate.deserialize_struct(name, fields, visitor) + } + + fn deserialize_enum( + self, + name: &'static str, + _variants: &'static [&'static str], + visitor: V, + ) -> Result + where + V: Visitor<'de>, + { + self.delegate.deserialize_any(SingletonMapAsEnum { + name, + delegate: visitor, + }) + } + + fn deserialize_identifier(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.delegate.deserialize_identifier(visitor) + } + + fn deserialize_ignored_any(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.delegate.deserialize_ignored_any(visitor) + } + + fn is_human_readable(&self) -> bool { + self.delegate.is_human_readable() + } + } + + struct SingletonMapAsEnum { + name: &'static str, + delegate: D, + } + + impl<'de, V> Visitor<'de> for SingletonMapAsEnum + where + V: Visitor<'de>, + { + type Value = V::Value; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + self.delegate.expecting(formatter) + } + + fn visit_str(self, v: &str) -> Result + where + E: de::Error, + { + self.delegate.visit_enum(de::value::StrDeserializer::new(v)) + } + + fn visit_borrowed_str(self, v: &'de str) -> Result + where + E: de::Error, + { + self.delegate + .visit_enum(de::value::BorrowedStrDeserializer::new(v)) + } + + fn visit_string(self, v: String) -> Result + where + E: de::Error, + { + self.delegate + .visit_enum(de::value::StringDeserializer::new(v)) + } + + fn visit_none(self) -> Result + where + E: de::Error, + { + self.delegate.visit_none() + } + + fn visit_some(self, deserializer: D) -> Result + where + D: Deserializer<'de>, + { + self.delegate.visit_some(SingletonMap { + delegate: deserializer, + }) + } + + fn visit_unit(self) -> Result + where + E: de::Error, + { + self.delegate.visit_unit() + } + + fn visit_map(self, map: A) -> Result + where + A: MapAccess<'de>, + { + self.delegate.visit_enum(SingletonMapAsEnum { + name: self.name, + delegate: map, + }) + } + } + + impl<'de, D> EnumAccess<'de> for SingletonMapAsEnum + where + D: MapAccess<'de>, + { + type Error = D::Error; + type Variant = Self; + + fn variant_seed(mut self, seed: V) -> Result<(V::Value, Self::Variant), Self::Error> + where + V: DeserializeSeed<'de>, + { + match self.delegate.next_key_seed(seed)? { + Some(value) => Ok((value, self)), + None => Err(de::Error::invalid_value( + Unexpected::Map, + &"map with a single key", + )), + } + } + } + + impl<'de, D> VariantAccess<'de> for SingletonMapAsEnum + where + D: MapAccess<'de>, + { + type Error = D::Error; + + fn unit_variant(self) -> Result<(), Self::Error> { + Err(de::Error::invalid_type(Unexpected::Map, &"unit variant")) + } + + fn newtype_variant_seed(mut self, seed: T) -> Result + where + T: DeserializeSeed<'de>, + { + let value = self.delegate.next_value_seed(seed)?; + match self.delegate.next_key()? { + None => Ok(value), + Some(IgnoredAny) => Err(de::Error::invalid_value( + Unexpected::Map, + &"map with a single key", + )), + } + } + + fn tuple_variant(mut self, len: usize, visitor: V) -> Result + where + V: Visitor<'de>, + { + let value = self + .delegate + .next_value_seed(TupleVariantSeed { len, visitor })?; + match self.delegate.next_key()? { + None => Ok(value), + Some(IgnoredAny) => Err(de::Error::invalid_value( + Unexpected::Map, + &"map with a single key", + )), + } + } + + fn struct_variant( + mut self, + fields: &'static [&'static str], + visitor: V, + ) -> Result + where + V: Visitor<'de>, + { + let value = self.delegate.next_value_seed(StructVariantSeed { + name: self.name, + fields, + visitor, + })?; + match self.delegate.next_key()? { + None => Ok(value), + Some(IgnoredAny) => Err(de::Error::invalid_value( + Unexpected::Map, + &"map with a single key", + )), + } + } + } + + struct TupleVariantSeed { + len: usize, + visitor: V, + } + + impl<'de, V> DeserializeSeed<'de> for TupleVariantSeed + where + V: Visitor<'de>, + { + type Value = V::Value; + + fn deserialize(self, deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_tuple(self.len, self.visitor) + } + } + + struct StructVariantSeed { + name: &'static str, + fields: &'static [&'static str], + visitor: V, + } + + impl<'de, V> DeserializeSeed<'de> for StructVariantSeed + where + V: Visitor<'de>, + { + type Value = V::Value; + + fn deserialize(self, deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_struct(self.name, self.fields, self.visitor) + } + } +} + +/// Apply [`singleton_map`] to *all* enums contained within the data structure. +/// +/// # Example +/// +/// ``` +/// # use serde_derive::{Deserialize, Serialize}; +/// # use serde::Deserialize as _; +/// # use serde::Serialize as _; +/// +/// #[derive(Serialize, Deserialize, PartialEq, Debug)] +/// enum Enum { +/// Int(i32), +/// } +/// +/// #[derive(Serialize, Deserialize, PartialEq, Debug)] +/// struct Inner { +/// a: Enum, +/// bs: Vec, +/// } +/// +/// #[derive(Serialize, Deserialize, PartialEq, Debug)] +/// struct Outer { +/// tagged_style: Inner, +/// +/// #[serde(with = "serde_yaml::with::singleton_map_recursive")] +/// singleton_map_style: Inner, +/// } +/// +/// fn main() { +/// let object = Outer { +/// tagged_style: Inner { +/// a: Enum::Int(0), +/// bs: vec![Enum::Int(1)], +/// }, +/// singleton_map_style: Inner { +/// a: Enum::Int(2), +/// bs: vec![Enum::Int(3)], +/// }, +/// }; +/// +/// let yaml = serde_yaml::to_string(&object).unwrap(); +/// print!("{}", yaml); +/// +/// let deserialized: Outer = serde_yaml::from_str(&yaml).unwrap(); +/// assert_eq!(object, deserialized); +/// } +/// ``` +/// +/// The serialized output is: +/// +/// ```yaml +/// tagged_style: +/// a: !Int 0 +/// bs: +/// - !Int 1 +/// singleton_map_style: +/// a: +/// Int: 2 +/// bs: +/// - Int: 3 +/// ``` +/// +/// This module can also be used for the top-level serializer or deserializer +/// call, without `serde(with = …)`, as follows. +/// +/// ``` +/// # use serde_derive::{Deserialize, Serialize}; +/// # use serde::Deserialize as _; +/// # use serde::Serialize as _; +/// # +/// # #[derive(Serialize, Deserialize, PartialEq, Debug)] +/// # enum Enum { +/// # Int(i32), +/// # } +/// # +/// # #[derive(Serialize, Deserialize, PartialEq, Debug)] +/// # struct Inner { +/// # a: Enum, +/// # bs: Vec, +/// # } +/// # +/// use std::io::{self, Write}; +/// +/// fn main() { +/// let object = Inner { +/// a: Enum::Int(0), +/// bs: vec![Enum::Int(1)], +/// }; +/// +/// let mut buf = Vec::new(); +/// let mut serializer = serde_yaml::Serializer::new(&mut buf); +/// serde_yaml::with::singleton_map_recursive::serialize(&object, &mut serializer).unwrap(); +/// io::stdout().write_all(&buf).unwrap(); +/// +/// let deserializer = serde_yaml::Deserializer::from_slice(&buf); +/// let deserialized: Inner = serde_yaml::with::singleton_map_recursive::deserialize(deserializer).unwrap(); +/// assert_eq!(object, deserialized); +/// } +/// ``` +pub mod singleton_map_recursive { + use crate::value::{Mapping, Sequence, Value}; + use serde::de::{ + self, Deserialize, DeserializeSeed, Deserializer, EnumAccess, IgnoredAny, MapAccess, + SeqAccess, Unexpected, VariantAccess, Visitor, + }; + use serde::ser::{ + self, Serialize, SerializeMap, SerializeSeq, SerializeStruct, SerializeStructVariant, + SerializeTuple, SerializeTupleStruct, SerializeTupleVariant, Serializer, + }; + use std::fmt::{self, Display}; + + #[allow(missing_docs)] + pub fn serialize(value: &T, serializer: S) -> Result + where + T: Serialize, + S: Serializer, + { + value.serialize(SingletonMapRecursive { + delegate: serializer, + }) + } + + #[allow(missing_docs)] + pub fn deserialize<'de, T, D>(deserializer: D) -> Result + where + T: Deserialize<'de>, + D: Deserializer<'de>, + { + T::deserialize(SingletonMapRecursive { + delegate: deserializer, + }) + } + + struct SingletonMapRecursive { + delegate: D, + } + + impl Serialize for SingletonMapRecursive + where + D: Serialize, + { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + self.delegate.serialize(SingletonMapRecursive { + delegate: serializer, + }) + } + } + + impl Serializer for SingletonMapRecursive + where + D: Serializer, + { + type Ok = D::Ok; + type Error = D::Error; + + type SerializeSeq = SingletonMapRecursive; + type SerializeTuple = SingletonMapRecursive; + type SerializeTupleStruct = SingletonMapRecursive; + type SerializeTupleVariant = SerializeTupleVariantAsSingletonMapRecursive; + type SerializeMap = SingletonMapRecursive; + type SerializeStruct = SingletonMapRecursive; + type SerializeStructVariant = + SerializeStructVariantAsSingletonMapRecursive; + + fn serialize_bool(self, v: bool) -> Result { + self.delegate.serialize_bool(v) + } + + fn serialize_i8(self, v: i8) -> Result { + self.delegate.serialize_i8(v) + } + + fn serialize_i16(self, v: i16) -> Result { + self.delegate.serialize_i16(v) + } + + fn serialize_i32(self, v: i32) -> Result { + self.delegate.serialize_i32(v) + } + + fn serialize_i64(self, v: i64) -> Result { + self.delegate.serialize_i64(v) + } + + fn serialize_i128(self, v: i128) -> Result { + self.delegate.serialize_i128(v) + } + + fn serialize_u8(self, v: u8) -> Result { + self.delegate.serialize_u8(v) + } + + fn serialize_u16(self, v: u16) -> Result { + self.delegate.serialize_u16(v) + } + + fn serialize_u32(self, v: u32) -> Result { + self.delegate.serialize_u32(v) + } + + fn serialize_u64(self, v: u64) -> Result { + self.delegate.serialize_u64(v) + } + + fn serialize_u128(self, v: u128) -> Result { + self.delegate.serialize_u128(v) + } + + fn serialize_f32(self, v: f32) -> Result { + self.delegate.serialize_f32(v) + } + + fn serialize_f64(self, v: f64) -> Result { + self.delegate.serialize_f64(v) + } + + fn serialize_char(self, v: char) -> Result { + self.delegate.serialize_char(v) + } + + fn serialize_str(self, v: &str) -> Result { + self.delegate.serialize_str(v) + } + + fn serialize_bytes(self, v: &[u8]) -> Result { + self.delegate.serialize_bytes(v) + } + + fn serialize_unit(self) -> Result { + self.delegate.serialize_unit() + } + + fn serialize_unit_struct(self, name: &'static str) -> Result { + self.delegate.serialize_unit_struct(name) + } + + fn serialize_unit_variant( + self, + name: &'static str, + variant_index: u32, + variant: &'static str, + ) -> Result { + self.delegate + .serialize_unit_variant(name, variant_index, variant) + } + + fn serialize_newtype_struct( + self, + name: &'static str, + value: &T, + ) -> Result + where + T: ?Sized + Serialize, + { + self.delegate + .serialize_newtype_struct(name, &SingletonMapRecursive { delegate: value }) + } + + fn serialize_newtype_variant( + self, + _name: &'static str, + _variant_index: u32, + variant: &'static str, + value: &T, + ) -> Result + where + T: ?Sized + Serialize, + { + let mut map = self.delegate.serialize_map(Some(1))?; + map.serialize_entry(variant, &SingletonMapRecursive { delegate: value })?; + map.end() + } + + fn serialize_none(self) -> Result { + self.delegate.serialize_none() + } + + fn serialize_some(self, value: &V) -> Result + where + V: ?Sized + Serialize, + { + self.delegate + .serialize_some(&SingletonMapRecursive { delegate: value }) + } + + fn serialize_seq(self, len: Option) -> Result { + Ok(SingletonMapRecursive { + delegate: self.delegate.serialize_seq(len)?, + }) + } + + fn serialize_tuple(self, len: usize) -> Result { + Ok(SingletonMapRecursive { + delegate: self.delegate.serialize_tuple(len)?, + }) + } + + fn serialize_tuple_struct( + self, + name: &'static str, + len: usize, + ) -> Result { + Ok(SingletonMapRecursive { + delegate: self.delegate.serialize_tuple_struct(name, len)?, + }) + } + + fn serialize_tuple_variant( + self, + _name: &'static str, + _variant_index: u32, + variant: &'static str, + len: usize, + ) -> Result { + let mut map = self.delegate.serialize_map(Some(1))?; + map.serialize_key(variant)?; + let sequence = Sequence::with_capacity(len); + Ok(SerializeTupleVariantAsSingletonMapRecursive { map, sequence }) + } + + fn serialize_map(self, len: Option) -> Result { + Ok(SingletonMapRecursive { + delegate: self.delegate.serialize_map(len)?, + }) + } + + fn serialize_struct( + self, + name: &'static str, + len: usize, + ) -> Result { + Ok(SingletonMapRecursive { + delegate: self.delegate.serialize_struct(name, len)?, + }) + } + + fn serialize_struct_variant( + self, + _name: &'static str, + _variant_index: u32, + variant: &'static str, + len: usize, + ) -> Result { + let mut map = self.delegate.serialize_map(Some(1))?; + map.serialize_key(variant)?; + let mapping = Mapping::with_capacity(len); + Ok(SerializeStructVariantAsSingletonMapRecursive { map, mapping }) + } + + fn collect_str(self, value: &T) -> Result + where + T: ?Sized + Display, + { + self.delegate.collect_str(value) + } + + fn is_human_readable(&self) -> bool { + self.delegate.is_human_readable() + } + } + + impl SerializeSeq for SingletonMapRecursive + where + D: SerializeSeq, + { + type Ok = D::Ok; + type Error = D::Error; + + fn serialize_element(&mut self, elem: &T) -> Result<(), Self::Error> + where + T: ?Sized + ser::Serialize, + { + self.delegate + .serialize_element(&SingletonMapRecursive { delegate: elem }) + } + + fn end(self) -> Result { + self.delegate.end() + } + } + + impl SerializeTuple for SingletonMapRecursive + where + D: SerializeTuple, + { + type Ok = D::Ok; + type Error = D::Error; + + fn serialize_element(&mut self, elem: &T) -> Result<(), Self::Error> + where + T: ?Sized + ser::Serialize, + { + self.delegate + .serialize_element(&SingletonMapRecursive { delegate: elem }) + } + + fn end(self) -> Result { + self.delegate.end() + } + } + + impl SerializeTupleStruct for SingletonMapRecursive + where + D: SerializeTupleStruct, + { + type Ok = D::Ok; + type Error = D::Error; + + fn serialize_field(&mut self, value: &V) -> Result<(), Self::Error> + where + V: ?Sized + ser::Serialize, + { + self.delegate + .serialize_field(&SingletonMapRecursive { delegate: value }) + } + + fn end(self) -> Result { + self.delegate.end() + } + } + + struct SerializeTupleVariantAsSingletonMapRecursive { + map: M, + sequence: Sequence, + } + + impl SerializeTupleVariant for SerializeTupleVariantAsSingletonMapRecursive + where + M: SerializeMap, + { + type Ok = M::Ok; + type Error = M::Error; + + fn serialize_field(&mut self, field: &T) -> Result<(), Self::Error> + where + T: ?Sized + Serialize, + { + let value = field + .serialize(SingletonMapRecursive { + delegate: crate::value::Serializer, + }) + .map_err(ser::Error::custom)?; + self.sequence.push(value); + Ok(()) + } + + fn end(mut self) -> Result { + self.map.serialize_value(&self.sequence)?; + self.map.end() + } + } + + impl SerializeMap for SingletonMapRecursive + where + D: SerializeMap, + { + type Ok = D::Ok; + type Error = D::Error; + + fn serialize_key(&mut self, key: &T) -> Result<(), Self::Error> + where + T: ?Sized + ser::Serialize, + { + self.delegate + .serialize_key(&SingletonMapRecursive { delegate: key }) + } + + fn serialize_value(&mut self, value: &T) -> Result<(), Self::Error> + where + T: ?Sized + ser::Serialize, + { + self.delegate + .serialize_value(&SingletonMapRecursive { delegate: value }) + } + + fn serialize_entry(&mut self, key: &K, value: &V) -> Result<(), Self::Error> + where + K: ?Sized + ser::Serialize, + V: ?Sized + ser::Serialize, + { + self.delegate.serialize_entry( + &SingletonMapRecursive { delegate: key }, + &SingletonMapRecursive { delegate: value }, + ) + } + + fn end(self) -> Result { + self.delegate.end() + } + } + + impl SerializeStruct for SingletonMapRecursive + where + D: SerializeStruct, + { + type Ok = D::Ok; + type Error = D::Error; + + fn serialize_field(&mut self, key: &'static str, value: &V) -> Result<(), Self::Error> + where + V: ?Sized + ser::Serialize, + { + self.delegate + .serialize_field(key, &SingletonMapRecursive { delegate: value }) + } + + fn end(self) -> Result { + self.delegate.end() + } + } + + struct SerializeStructVariantAsSingletonMapRecursive { + map: M, + mapping: Mapping, + } + + impl SerializeStructVariant for SerializeStructVariantAsSingletonMapRecursive + where + M: SerializeMap, + { + type Ok = M::Ok; + type Error = M::Error; + + fn serialize_field(&mut self, name: &'static str, field: &T) -> Result<(), Self::Error> + where + T: ?Sized + Serialize, + { + let value = field + .serialize(SingletonMapRecursive { + delegate: crate::value::Serializer, + }) + .map_err(ser::Error::custom)?; + self.mapping.insert(Value::String(name.to_owned()), value); + Ok(()) + } + + fn end(mut self) -> Result { + self.map.serialize_value(&self.mapping)?; + self.map.end() + } + } + + impl<'de, D> Deserializer<'de> for SingletonMapRecursive + where + D: Deserializer<'de>, + { + type Error = D::Error; + + fn deserialize_any(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.delegate + .deserialize_any(SingletonMapRecursive { delegate: visitor }) + } + + fn deserialize_bool(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.delegate + .deserialize_bool(SingletonMapRecursive { delegate: visitor }) + } + + fn deserialize_i8(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.delegate + .deserialize_i8(SingletonMapRecursive { delegate: visitor }) + } + + fn deserialize_i16(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.delegate + .deserialize_i16(SingletonMapRecursive { delegate: visitor }) + } + + fn deserialize_i32(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.delegate + .deserialize_i32(SingletonMapRecursive { delegate: visitor }) + } + + fn deserialize_i64(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.delegate + .deserialize_i64(SingletonMapRecursive { delegate: visitor }) + } + + fn deserialize_i128(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.delegate + .deserialize_i128(SingletonMapRecursive { delegate: visitor }) + } + + fn deserialize_u8(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.delegate + .deserialize_u8(SingletonMapRecursive { delegate: visitor }) + } + + fn deserialize_u16(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.delegate + .deserialize_u16(SingletonMapRecursive { delegate: visitor }) + } + + fn deserialize_u32(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.delegate + .deserialize_u32(SingletonMapRecursive { delegate: visitor }) + } + + fn deserialize_u64(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.delegate + .deserialize_u64(SingletonMapRecursive { delegate: visitor }) + } + + fn deserialize_u128(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.delegate + .deserialize_u128(SingletonMapRecursive { delegate: visitor }) + } + + fn deserialize_f32(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.delegate + .deserialize_f32(SingletonMapRecursive { delegate: visitor }) + } + + fn deserialize_f64(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.delegate + .deserialize_f64(SingletonMapRecursive { delegate: visitor }) + } + + fn deserialize_char(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.delegate + .deserialize_char(SingletonMapRecursive { delegate: visitor }) + } + + fn deserialize_str(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.delegate + .deserialize_str(SingletonMapRecursive { delegate: visitor }) + } + + fn deserialize_string(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.delegate + .deserialize_string(SingletonMapRecursive { delegate: visitor }) + } + + fn deserialize_bytes(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.delegate + .deserialize_bytes(SingletonMapRecursive { delegate: visitor }) + } + + fn deserialize_byte_buf(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.delegate + .deserialize_byte_buf(SingletonMapRecursive { delegate: visitor }) + } + + fn deserialize_option(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.delegate + .deserialize_option(SingletonMapRecursiveAsEnum { + name: "", + delegate: visitor, + }) + } + + fn deserialize_unit(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.delegate + .deserialize_unit(SingletonMapRecursive { delegate: visitor }) + } + + fn deserialize_unit_struct( + self, + name: &'static str, + visitor: V, + ) -> Result + where + V: Visitor<'de>, + { + self.delegate + .deserialize_unit_struct(name, SingletonMapRecursive { delegate: visitor }) + } + + fn deserialize_newtype_struct( + self, + name: &'static str, + visitor: V, + ) -> Result + where + V: Visitor<'de>, + { + self.delegate + .deserialize_newtype_struct(name, SingletonMapRecursive { delegate: visitor }) + } + + fn deserialize_seq(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.delegate + .deserialize_seq(SingletonMapRecursive { delegate: visitor }) + } + + fn deserialize_tuple(self, len: usize, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.delegate + .deserialize_tuple(len, SingletonMapRecursive { delegate: visitor }) + } + + fn deserialize_tuple_struct( + self, + name: &'static str, + len: usize, + visitor: V, + ) -> Result + where + V: Visitor<'de>, + { + self.delegate.deserialize_tuple_struct( + name, + len, + SingletonMapRecursive { delegate: visitor }, + ) + } + + fn deserialize_map(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.delegate + .deserialize_map(SingletonMapRecursive { delegate: visitor }) + } + + fn deserialize_struct( + self, + name: &'static str, + fields: &'static [&'static str], + visitor: V, + ) -> Result + where + V: Visitor<'de>, + { + self.delegate.deserialize_struct( + name, + fields, + SingletonMapRecursive { delegate: visitor }, + ) + } + + fn deserialize_enum( + self, + name: &'static str, + _variants: &'static [&'static str], + visitor: V, + ) -> Result + where + V: Visitor<'de>, + { + self.delegate.deserialize_any(SingletonMapRecursiveAsEnum { + name, + delegate: visitor, + }) + } + + fn deserialize_identifier(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.delegate + .deserialize_identifier(SingletonMapRecursive { delegate: visitor }) + } + + fn deserialize_ignored_any(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.delegate + .deserialize_ignored_any(SingletonMapRecursive { delegate: visitor }) + } + + fn is_human_readable(&self) -> bool { + self.delegate.is_human_readable() + } + } + + impl<'de, V> Visitor<'de> for SingletonMapRecursive + where + V: Visitor<'de>, + { + type Value = V::Value; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + self.delegate.expecting(formatter) + } + + fn visit_bool(self, v: bool) -> Result + where + E: de::Error, + { + self.delegate.visit_bool(v) + } + + fn visit_i8(self, v: i8) -> Result + where + E: de::Error, + { + self.delegate.visit_i8(v) + } + + fn visit_i16(self, v: i16) -> Result + where + E: de::Error, + { + self.delegate.visit_i16(v) + } + + fn visit_i32(self, v: i32) -> Result + where + E: de::Error, + { + self.delegate.visit_i32(v) + } + + fn visit_i64(self, v: i64) -> Result + where + E: de::Error, + { + self.delegate.visit_i64(v) + } + + fn visit_i128(self, v: i128) -> Result + where + E: de::Error, + { + self.delegate.visit_i128(v) + } + + fn visit_u8(self, v: u8) -> Result + where + E: de::Error, + { + self.delegate.visit_u8(v) + } + + fn visit_u16(self, v: u16) -> Result + where + E: de::Error, + { + self.delegate.visit_u16(v) + } + + fn visit_u32(self, v: u32) -> Result + where + E: de::Error, + { + self.delegate.visit_u32(v) + } + + fn visit_u64(self, v: u64) -> Result + where + E: de::Error, + { + self.delegate.visit_u64(v) + } + + fn visit_u128(self, v: u128) -> Result + where + E: de::Error, + { + self.delegate.visit_u128(v) + } + + fn visit_f32(self, v: f32) -> Result + where + E: de::Error, + { + self.delegate.visit_f32(v) + } + + fn visit_f64(self, v: f64) -> Result + where + E: de::Error, + { + self.delegate.visit_f64(v) + } + + fn visit_char(self, v: char) -> Result + where + E: de::Error, + { + self.delegate.visit_char(v) + } + + fn visit_str(self, v: &str) -> Result + where + E: de::Error, + { + self.delegate.visit_str(v) + } + + fn visit_borrowed_str(self, v: &'de str) -> Result + where + E: de::Error, + { + self.delegate.visit_borrowed_str(v) + } + + fn visit_string(self, v: String) -> Result + where + E: de::Error, + { + self.delegate.visit_string(v) + } + + fn visit_bytes(self, v: &[u8]) -> Result + where + E: de::Error, + { + self.delegate.visit_bytes(v) + } + + fn visit_borrowed_bytes(self, v: &'de [u8]) -> Result + where + E: de::Error, + { + self.delegate.visit_borrowed_bytes(v) + } + + fn visit_byte_buf(self, v: Vec) -> Result + where + E: de::Error, + { + self.delegate.visit_byte_buf(v) + } + + fn visit_none(self) -> Result + where + E: de::Error, + { + self.delegate.visit_none() + } + + fn visit_some(self, deserializer: D) -> Result + where + D: Deserializer<'de>, + { + self.delegate.visit_some(SingletonMapRecursive { + delegate: deserializer, + }) + } + + fn visit_unit(self) -> Result + where + E: de::Error, + { + self.delegate.visit_unit() + } + + fn visit_newtype_struct(self, deserializer: D) -> Result + where + D: Deserializer<'de>, + { + self.delegate.visit_newtype_struct(SingletonMapRecursive { + delegate: deserializer, + }) + } + + fn visit_seq(self, seq: A) -> Result + where + A: SeqAccess<'de>, + { + self.delegate + .visit_seq(SingletonMapRecursive { delegate: seq }) + } + + fn visit_map(self, map: A) -> Result + where + A: MapAccess<'de>, + { + self.delegate + .visit_map(SingletonMapRecursive { delegate: map }) + } + } + + impl<'de, T> DeserializeSeed<'de> for SingletonMapRecursive + where + T: DeserializeSeed<'de>, + { + type Value = T::Value; + + fn deserialize(self, deserializer: D) -> Result + where + D: Deserializer<'de>, + { + self.delegate.deserialize(SingletonMapRecursive { + delegate: deserializer, + }) + } + } + + impl<'de, S> SeqAccess<'de> for SingletonMapRecursive + where + S: SeqAccess<'de>, + { + type Error = S::Error; + + fn next_element_seed(&mut self, seed: T) -> Result, Self::Error> + where + T: DeserializeSeed<'de>, + { + self.delegate + .next_element_seed(SingletonMapRecursive { delegate: seed }) + } + } + + impl<'de, M> MapAccess<'de> for SingletonMapRecursive + where + M: MapAccess<'de>, + { + type Error = M::Error; + + fn next_key_seed(&mut self, seed: K) -> Result, Self::Error> + where + K: DeserializeSeed<'de>, + { + self.delegate + .next_key_seed(SingletonMapRecursive { delegate: seed }) + } + + fn next_value_seed(&mut self, seed: V) -> Result + where + V: DeserializeSeed<'de>, + { + self.delegate + .next_value_seed(SingletonMapRecursive { delegate: seed }) + } + } + + struct SingletonMapRecursiveAsEnum { + name: &'static str, + delegate: D, + } + + impl<'de, V> Visitor<'de> for SingletonMapRecursiveAsEnum + where + V: Visitor<'de>, + { + type Value = V::Value; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + self.delegate.expecting(formatter) + } + + fn visit_str(self, v: &str) -> Result + where + E: de::Error, + { + self.delegate.visit_enum(de::value::StrDeserializer::new(v)) + } + + fn visit_borrowed_str(self, v: &'de str) -> Result + where + E: de::Error, + { + self.delegate + .visit_enum(de::value::BorrowedStrDeserializer::new(v)) + } + + fn visit_string(self, v: String) -> Result + where + E: de::Error, + { + self.delegate + .visit_enum(de::value::StringDeserializer::new(v)) + } + + fn visit_none(self) -> Result + where + E: de::Error, + { + self.delegate.visit_none() + } + + fn visit_some(self, deserializer: D) -> Result + where + D: Deserializer<'de>, + { + self.delegate.visit_some(SingletonMapRecursive { + delegate: deserializer, + }) + } + + fn visit_unit(self) -> Result + where + E: de::Error, + { + self.delegate.visit_unit() + } + + fn visit_map(self, map: A) -> Result + where + A: MapAccess<'de>, + { + self.delegate.visit_enum(SingletonMapRecursiveAsEnum { + name: self.name, + delegate: map, + }) + } + } + + impl<'de, D> EnumAccess<'de> for SingletonMapRecursiveAsEnum + where + D: MapAccess<'de>, + { + type Error = D::Error; + type Variant = Self; + + fn variant_seed(mut self, seed: V) -> Result<(V::Value, Self::Variant), Self::Error> + where + V: DeserializeSeed<'de>, + { + match self.delegate.next_key_seed(seed)? { + Some(value) => Ok((value, self)), + None => Err(de::Error::invalid_value( + Unexpected::Map, + &"map with a single key", + )), + } + } + } + + impl<'de, D> VariantAccess<'de> for SingletonMapRecursiveAsEnum + where + D: MapAccess<'de>, + { + type Error = D::Error; + + fn unit_variant(self) -> Result<(), Self::Error> { + Err(de::Error::invalid_type(Unexpected::Map, &"unit variant")) + } + + fn newtype_variant_seed(mut self, seed: T) -> Result + where + T: DeserializeSeed<'de>, + { + let value = self + .delegate + .next_value_seed(SingletonMapRecursive { delegate: seed })?; + match self.delegate.next_key()? { + None => Ok(value), + Some(IgnoredAny) => Err(de::Error::invalid_value( + Unexpected::Map, + &"map with a single key", + )), + } + } + + fn tuple_variant(mut self, len: usize, visitor: V) -> Result + where + V: Visitor<'de>, + { + let value = self.delegate.next_value_seed(TupleVariantSeed { + len, + visitor: SingletonMapRecursive { delegate: visitor }, + })?; + match self.delegate.next_key()? { + None => Ok(value), + Some(IgnoredAny) => Err(de::Error::invalid_value( + Unexpected::Map, + &"map with a single key", + )), + } + } + + fn struct_variant( + mut self, + fields: &'static [&'static str], + visitor: V, + ) -> Result + where + V: Visitor<'de>, + { + let value = self.delegate.next_value_seed(StructVariantSeed { + name: self.name, + fields, + visitor: SingletonMapRecursive { delegate: visitor }, + })?; + match self.delegate.next_key()? { + None => Ok(value), + Some(IgnoredAny) => Err(de::Error::invalid_value( + Unexpected::Map, + &"map with a single key", + )), + } + } + } + + struct TupleVariantSeed { + len: usize, + visitor: V, + } + + impl<'de, V> DeserializeSeed<'de> for TupleVariantSeed + where + V: Visitor<'de>, + { + type Value = V::Value; + + fn deserialize(self, deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_tuple(self.len, self.visitor) + } + } + + struct StructVariantSeed { + name: &'static str, + fields: &'static [&'static str], + visitor: V, + } + + impl<'de, V> DeserializeSeed<'de> for StructVariantSeed + where + V: Visitor<'de>, + { + type Value = V::Value; + + fn deserialize(self, deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_struct(self.name, self.fields, self.visitor) + } + } +} diff --git a/kclvm/third-party/serde_yaml/tests/test_de.rs b/kclvm/third-party/serde_yaml/tests/test_de.rs new file mode 100644 index 000000000..b9e948de0 --- /dev/null +++ b/kclvm/third-party/serde_yaml/tests/test_de.rs @@ -0,0 +1,717 @@ +#![allow( + clippy::cast_lossless, + clippy::cast_possible_wrap, + clippy::derive_partial_eq_without_eq, + clippy::similar_names, + clippy::uninlined_format_args +)] + +use indoc::indoc; +use serde_derive::Deserialize; +use serde_yaml::{Deserializer, Number, Value}; +use std::collections::BTreeMap; +use std::fmt::Debug; + +fn test_de(yaml: &str, expected: &T) +where + T: serde::de::DeserializeOwned + PartialEq + Debug, +{ + let deserialized: T = serde_yaml::from_str(yaml).unwrap(); + assert_eq!(*expected, deserialized); + + let value: Value = serde_yaml::from_str(yaml).unwrap(); + let deserialized = T::deserialize(&value).unwrap(); + assert_eq!(*expected, deserialized); + + let deserialized: T = serde_yaml::from_value(value).unwrap(); + assert_eq!(*expected, deserialized); + + serde_yaml::from_str::(yaml).unwrap(); + + let mut deserializer = Deserializer::from_str(yaml); + let document = deserializer.next().unwrap(); + let deserialized = T::deserialize(document).unwrap(); + assert_eq!(*expected, deserialized); + assert!(deserializer.next().is_none()); +} + +fn test_de_no_value<'de, T>(yaml: &'de str, expected: &T) +where + T: serde::de::Deserialize<'de> + PartialEq + Debug, +{ + let deserialized: T = serde_yaml::from_str(yaml).unwrap(); + assert_eq!(*expected, deserialized); + + serde_yaml::from_str::(yaml).unwrap(); + serde_yaml::from_str::(yaml).unwrap(); +} + +fn test_de_seed<'de, T, S>(yaml: &'de str, seed: S, expected: &T) +where + T: PartialEq + Debug, + S: serde::de::DeserializeSeed<'de, Value = T>, +{ + let deserialized: T = seed.deserialize(Deserializer::from_str(yaml)).unwrap(); + assert_eq!(*expected, deserialized); + + serde_yaml::from_str::(yaml).unwrap(); + serde_yaml::from_str::(yaml).unwrap(); +} + +#[test] +fn test_borrowed() { + let yaml = indoc! {" + - plain nonàscii + - 'single quoted' + - \"double quoted\" + "}; + let expected = vec!["plain nonàscii", "single quoted", "double quoted"]; + test_de_no_value(yaml, &expected); +} + +#[test] +fn test_alias() { + let yaml = indoc! {" + first: + &alias + 1 + second: + *alias + third: 3 + "}; + let mut expected = BTreeMap::new(); + expected.insert("first".to_owned(), 1); + expected.insert("second".to_owned(), 1); + expected.insert("third".to_owned(), 3); + test_de(yaml, &expected); +} + +#[test] +fn test_option() { + #[derive(Deserialize, PartialEq, Debug)] + struct Data { + a: Option, + b: Option, + c: Option, + } + let yaml = indoc! {" + b: + c: true + "}; + let expected = Data { + a: None, + b: None, + c: Some(true), + }; + test_de(yaml, &expected); +} + +#[test] +fn test_option_alias() { + #[derive(Deserialize, PartialEq, Debug)] + struct Data { + a: Option, + b: Option, + c: Option, + d: Option, + e: Option, + f: Option, + } + let yaml = indoc! {" + none_f: + &none_f + ~ + none_s: + &none_s + ~ + none_b: + &none_b + ~ + + some_f: + &some_f + 1.0 + some_s: + &some_s + x + some_b: + &some_b + true + + a: *none_f + b: *none_s + c: *none_b + d: *some_f + e: *some_s + f: *some_b + "}; + let expected = Data { + a: None, + b: None, + c: None, + d: Some(1.0), + e: Some("x".to_owned()), + f: Some(true), + }; + test_de(yaml, &expected); +} + +#[test] +fn test_enum_alias() { + #[derive(Deserialize, PartialEq, Debug)] + enum E { + A, + B(u8, u8), + } + #[derive(Deserialize, PartialEq, Debug)] + struct Data { + a: E, + b: E, + } + let yaml = indoc! {" + aref: + &aref + A + bref: + &bref + !B + - 1 + - 2 + + a: *aref + b: *bref + "}; + let expected = Data { + a: E::A, + b: E::B(1, 2), + }; + test_de(yaml, &expected); +} + +#[test] +fn test_enum_representations() { + #[derive(Deserialize, PartialEq, Debug)] + enum Enum { + Unit, + Tuple(i32, i32), + Struct { x: i32, y: i32 }, + String(String), + Number(f64), + } + + let yaml = indoc! {" + - Unit + - 'Unit' + - !Unit + - !Unit ~ + - !Unit null + - !Tuple [0, 0] + - !Tuple + - 0 + - 0 + - !Struct {x: 0, y: 0} + - !Struct + x: 0 + y: 0 + - !String '...' + - !String ... + - !Number 0 + "}; + + let expected = vec![ + Enum::Unit, + Enum::Unit, + Enum::Unit, + Enum::Unit, + Enum::Unit, + Enum::Tuple(0, 0), + Enum::Tuple(0, 0), + Enum::Struct { x: 0, y: 0 }, + Enum::Struct { x: 0, y: 0 }, + Enum::String("...".to_owned()), + Enum::String("...".to_owned()), + Enum::Number(0.0), + ]; + + test_de(yaml, &expected); + + let yaml = indoc! {" + - !String + "}; + let expected = vec![Enum::String(String::new())]; + test_de_no_value(yaml, &expected); +} + +#[test] +fn test_number_as_string() { + #[derive(Deserialize, PartialEq, Debug)] + struct Num { + value: String, + } + let yaml = indoc! {" + # Cannot be represented as u128 + value: 340282366920938463463374607431768211457 + "}; + let expected = Num { + value: "340282366920938463463374607431768211457".to_owned(), + }; + test_de_no_value(yaml, &expected); +} + +#[test] +fn test_empty_string() { + #[derive(Deserialize, PartialEq, Debug)] + struct Struct { + empty: String, + tilde: String, + } + let yaml = indoc! {" + empty: + tilde: ~ + "}; + let expected = Struct { + empty: String::new(), + tilde: "~".to_owned(), + }; + test_de_no_value(yaml, &expected); +} + +#[test] +fn test_i128_big() { + let expected: i128 = i64::MIN as i128 - 1; + let yaml = indoc! {" + -9223372036854775809 + "}; + assert_eq!(expected, serde_yaml::from_str::(yaml).unwrap()); + + let octal = indoc! {" + -0o1000000000000000000001 + "}; + assert_eq!(expected, serde_yaml::from_str::(octal).unwrap()); +} + +#[test] +fn test_u128_big() { + let expected: u128 = u64::MAX as u128 + 1; + let yaml = indoc! {" + 18446744073709551616 + "}; + assert_eq!(expected, serde_yaml::from_str::(yaml).unwrap()); + + let octal = indoc! {" + 0o2000000000000000000000 + "}; + assert_eq!(expected, serde_yaml::from_str::(octal).unwrap()); +} + +#[test] +fn test_number_alias_as_string() { + #[derive(Deserialize, PartialEq, Debug)] + struct Num { + version: String, + value: String, + } + let yaml = indoc! {" + version: &a 1.10 + value: *a + "}; + let expected = Num { + version: "1.10".to_owned(), + value: "1.10".to_owned(), + }; + test_de_no_value(yaml, &expected); +} + +#[test] +fn test_de_mapping() { + #[derive(Debug, Deserialize, PartialEq)] + struct Data { + pub substructure: serde_yaml::Mapping, + } + let yaml = indoc! {" + substructure: + a: 'foo' + b: 'bar' + "}; + + let mut expected = Data { + substructure: serde_yaml::Mapping::new(), + }; + expected.substructure.insert( + serde_yaml::Value::String("a".to_owned()), + serde_yaml::Value::String("foo".to_owned()), + ); + expected.substructure.insert( + serde_yaml::Value::String("b".to_owned()), + serde_yaml::Value::String("bar".to_owned()), + ); + + test_de(yaml, &expected); +} + +#[test] +fn test_byte_order_mark() { + let yaml = "\u{feff}- 0\n"; + let expected = vec![0]; + test_de(yaml, &expected); +} + +#[test] +fn test_bomb() { + #[derive(Debug, Deserialize, PartialEq)] + struct Data { + expected: String, + } + + // This would deserialize an astronomical number of elements if we were + // vulnerable. + let yaml = indoc! {" + a: &a ~ + b: &b [*a,*a,*a,*a,*a,*a,*a,*a,*a] + c: &c [*b,*b,*b,*b,*b,*b,*b,*b,*b] + d: &d [*c,*c,*c,*c,*c,*c,*c,*c,*c] + e: &e [*d,*d,*d,*d,*d,*d,*d,*d,*d] + f: &f [*e,*e,*e,*e,*e,*e,*e,*e,*e] + g: &g [*f,*f,*f,*f,*f,*f,*f,*f,*f] + h: &h [*g,*g,*g,*g,*g,*g,*g,*g,*g] + i: &i [*h,*h,*h,*h,*h,*h,*h,*h,*h] + j: &j [*i,*i,*i,*i,*i,*i,*i,*i,*i] + k: &k [*j,*j,*j,*j,*j,*j,*j,*j,*j] + l: &l [*k,*k,*k,*k,*k,*k,*k,*k,*k] + m: &m [*l,*l,*l,*l,*l,*l,*l,*l,*l] + n: &n [*m,*m,*m,*m,*m,*m,*m,*m,*m] + o: &o [*n,*n,*n,*n,*n,*n,*n,*n,*n] + p: &p [*o,*o,*o,*o,*o,*o,*o,*o,*o] + q: &q [*p,*p,*p,*p,*p,*p,*p,*p,*p] + r: &r [*q,*q,*q,*q,*q,*q,*q,*q,*q] + s: &s [*r,*r,*r,*r,*r,*r,*r,*r,*r] + t: &t [*s,*s,*s,*s,*s,*s,*s,*s,*s] + u: &u [*t,*t,*t,*t,*t,*t,*t,*t,*t] + v: &v [*u,*u,*u,*u,*u,*u,*u,*u,*u] + w: &w [*v,*v,*v,*v,*v,*v,*v,*v,*v] + x: &x [*w,*w,*w,*w,*w,*w,*w,*w,*w] + y: &y [*x,*x,*x,*x,*x,*x,*x,*x,*x] + z: &z [*y,*y,*y,*y,*y,*y,*y,*y,*y] + expected: string + "}; + + let expected = Data { + expected: "string".to_owned(), + }; + + assert_eq!(expected, serde_yaml::from_str::(yaml).unwrap()); +} + +#[test] +fn test_numbers() { + let cases = [ + ("0xF0", "240"), + ("+0xF0", "240"), + ("-0xF0", "-240"), + ("0o70", "56"), + ("+0o70", "56"), + ("-0o70", "-56"), + ("0b10", "2"), + ("+0b10", "2"), + ("-0b10", "-2"), + ("127", "127"), + ("+127", "127"), + ("-127", "-127"), + (".inf", ".inf"), + (".Inf", ".inf"), + (".INF", ".inf"), + ("-.inf", "-.inf"), + ("-.Inf", "-.inf"), + ("-.INF", "-.inf"), + (".nan", ".nan"), + (".NaN", ".nan"), + (".NAN", ".nan"), + ("0.1", "0.1"), + ]; + for &(yaml, expected) in &cases { + let value = serde_yaml::from_str::(yaml).unwrap(); + match value { + Value::Number(number) => assert_eq!(number.to_string(), expected), + _ => panic!("expected number. input={:?}, result={:?}", yaml, value), + } + } + + // NOT numbers. + let cases = [ + "0127", "+0127", "-0127", "++.inf", "+-.inf", "++1", "+-1", "-+1", "--1", "0x+1", "0x-1", + "-0x+1", "-0x-1", "++0x1", "+-0x1", "-+0x1", "--0x1", + ]; + for yaml in &cases { + let value = serde_yaml::from_str::(yaml).unwrap(); + match value { + Value::String(string) => assert_eq!(string, *yaml), + _ => panic!("expected string. input={:?}, result={:?}", yaml, value), + } + } +} + +#[test] +fn test_nan() { + // There is no negative NaN in YAML. + assert!(serde_yaml::from_str::(".nan") + .unwrap() + .is_sign_positive()); + assert!(serde_yaml::from_str::(".nan") + .unwrap() + .is_sign_positive()); +} + +#[test] +fn test_stateful() { + struct Seed(i64); + + impl<'de> serde::de::DeserializeSeed<'de> for Seed { + type Value = i64; + fn deserialize(self, deserializer: D) -> Result + where + D: serde::de::Deserializer<'de>, + { + struct Visitor(i64); + impl<'de> serde::de::Visitor<'de> for Visitor { + type Value = i64; + + fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(formatter, "an integer") + } + + fn visit_i64(self, v: i64) -> Result { + Ok(v * self.0) + } + + fn visit_u64(self, v: u64) -> Result { + Ok(v as i64 * self.0) + } + } + + deserializer.deserialize_any(Visitor(self.0)) + } + } + + let cases = [("3", 5, 15), ("6", 7, 42), ("-5", 9, -45)]; + for &(yaml, seed, expected) in &cases { + test_de_seed(yaml, Seed(seed), &expected); + } +} + +#[test] +fn test_ignore_tag() { + #[derive(Deserialize, Debug, PartialEq)] + struct Data { + struc: Struc, + tuple: Tuple, + newtype: Newtype, + map: BTreeMap, + vec: Vec, + } + + #[derive(Deserialize, Debug, PartialEq)] + struct Struc { + x: usize, + } + + #[derive(Deserialize, Debug, PartialEq)] + struct Tuple(usize, usize); + + #[derive(Deserialize, Debug, PartialEq)] + struct Newtype(usize); + + let yaml = indoc! {" + struc: !wat + x: 0 + tuple: !wat + - 0 + - 0 + newtype: !wat 0 + map: !wat + x: 0 + vec: !wat + - 0 + "}; + + let expected = Data { + struc: Struc { x: 0 }, + tuple: Tuple(0, 0), + newtype: Newtype(0), + map: { + let mut map = BTreeMap::new(); + map.insert('x', 0); + map + }, + vec: vec![0], + }; + + test_de(yaml, &expected); +} + +#[test] +fn test_no_required_fields() { + #[derive(Deserialize, PartialEq, Debug)] + pub struct NoRequiredFields { + optional: Option, + } + + for document in ["", "# comment\n"] { + let expected = NoRequiredFields { optional: None }; + let deserialized: NoRequiredFields = serde_yaml::from_str(document).unwrap(); + assert_eq!(expected, deserialized); + + let expected = Vec::::new(); + let deserialized: Vec = serde_yaml::from_str(document).unwrap(); + assert_eq!(expected, deserialized); + + let expected = BTreeMap::new(); + let deserialized: BTreeMap = serde_yaml::from_str(document).unwrap(); + assert_eq!(expected, deserialized); + + let expected = None; + let deserialized: Option = serde_yaml::from_str(document).unwrap(); + assert_eq!(expected, deserialized); + + let expected = Value::Null; + let deserialized: Value = serde_yaml::from_str(document).unwrap(); + assert_eq!(expected, deserialized); + } +} + +#[test] +fn test_empty_scalar() { + #[derive(Deserialize, PartialEq, Debug)] + struct Struct { + thing: T, + } + + let yaml = "thing:\n"; + let expected = Struct { + thing: serde_yaml::Sequence::new(), + }; + test_de(yaml, &expected); + + let expected = Struct { + thing: serde_yaml::Mapping::new(), + }; + test_de(yaml, &expected); +} + +#[test] +fn test_python_safe_dump() { + #[derive(Deserialize, PartialEq, Debug)] + struct Frob { + foo: u32, + } + + // This matches output produced by PyYAML's `yaml.safe_dump` when using the + // default_style parameter. + // + // >>> import yaml + // >>> d = {"foo": 7200} + // >>> print(yaml.safe_dump(d, default_style="|")) + // "foo": !!int |- + // 7200 + // + let yaml = indoc! {r#" + "foo": !!int |- + 7200 + "#}; + + let expected = Frob { foo: 7200 }; + test_de(yaml, &expected); +} + +#[test] +fn test_tag_resolution() { + // https://yaml.org/spec/1.2.2/#1032-tag-resolution + let yaml = indoc! {" + - null + - Null + - NULL + - ~ + - + - true + - True + - TRUE + - false + - False + - FALSE + - y + - Y + - yes + - Yes + - YES + - n + - N + - no + - No + - NO + - on + - On + - ON + - off + - Off + - OFF + "}; + + let expected = vec![ + Value::Null, + Value::Null, + Value::Null, + Value::Null, + Value::Null, + Value::Bool(true), + Value::Bool(true), + Value::Bool(true), + Value::Bool(false), + Value::Bool(false), + Value::Bool(false), + Value::String("y".to_owned()), + Value::String("Y".to_owned()), + Value::String("yes".to_owned()), + Value::String("Yes".to_owned()), + Value::String("YES".to_owned()), + Value::String("n".to_owned()), + Value::String("N".to_owned()), + Value::String("no".to_owned()), + Value::String("No".to_owned()), + Value::String("NO".to_owned()), + Value::String("on".to_owned()), + Value::String("On".to_owned()), + Value::String("ON".to_owned()), + Value::String("off".to_owned()), + Value::String("Off".to_owned()), + Value::String("OFF".to_owned()), + ]; + + test_de(yaml, &expected); +} + +#[test] +fn test_parse_number() { + let n = "111".parse::().unwrap(); + assert_eq!(n, Number::from(111)); + + let n = "-111".parse::().unwrap(); + assert_eq!(n, Number::from(-111)); + + let n = "-1.1".parse::().unwrap(); + assert_eq!(n, Number::from(-1.1)); + + let n = ".nan".parse::().unwrap(); + assert_eq!(n, Number::from(f64::NAN)); + assert!(n.as_f64().unwrap().is_sign_positive()); + + let n = ".inf".parse::().unwrap(); + assert_eq!(n, Number::from(f64::INFINITY)); + + let n = "-.inf".parse::().unwrap(); + assert_eq!(n, Number::from(f64::NEG_INFINITY)); + + let err = "null".parse::().unwrap_err(); + assert_eq!(err.to_string(), "failed to parse YAML number"); + + let err = " 1 ".parse::().unwrap_err(); + assert_eq!(err.to_string(), "failed to parse YAML number"); +} diff --git a/kclvm/third-party/serde_yaml/tests/test_error.rs b/kclvm/third-party/serde_yaml/tests/test_error.rs new file mode 100644 index 000000000..883bb6da0 --- /dev/null +++ b/kclvm/third-party/serde_yaml/tests/test_error.rs @@ -0,0 +1,500 @@ +#![allow(clippy::zero_sized_map_values)] + +use indoc::indoc; +use serde::de::Deserialize; +#[cfg(not(miri))] +use serde::de::{SeqAccess, Visitor}; +use serde_derive::{Deserialize, Serialize}; +use serde_yaml::value::{Tag, TaggedValue}; +use serde_yaml::{Deserializer, Value}; +#[cfg(not(miri))] +use std::collections::BTreeMap; +#[cfg(not(miri))] +use std::fmt; +use std::fmt::Debug; + +fn test_error<'de, T>(yaml: &'de str, expected: &str) +where + T: Deserialize<'de> + Debug, +{ + let result = serde_yaml::from_str::(yaml); + assert_eq!(expected, result.unwrap_err().to_string()); + + let mut deserializer = Deserializer::from_str(yaml); + if let Some(first_document) = deserializer.next() { + if deserializer.next().is_none() { + let result = T::deserialize(first_document); + assert_eq!(expected, result.unwrap_err().to_string()); + } + } +} + +#[test] +fn test_scan_error() { + let yaml = ">\n@"; + let expected = "found character that cannot start any token at line 2 column 1, while scanning for the next token"; + test_error::(yaml, expected); +} + +#[test] +fn test_incorrect_type() { + let yaml = indoc! {" + --- + str + "}; + let expected = "invalid type: string \"str\", expected i16 at line 2 column 1"; + test_error::(yaml, expected); +} + +#[test] +fn test_incorrect_nested_type() { + #[derive(Deserialize, Debug)] + pub struct A { + #[allow(dead_code)] + pub b: Vec, + } + #[derive(Deserialize, Debug)] + pub enum B { + C(#[allow(dead_code)] C), + } + #[derive(Deserialize, Debug)] + pub struct C { + #[allow(dead_code)] + pub d: bool, + } + let yaml = indoc! {" + b: + - !C + d: fase + "}; + let expected = "b[0].d: invalid type: string \"fase\", expected a boolean at line 3 column 8"; + test_error::(yaml, expected); +} + +#[test] +fn test_empty() { + let expected = "EOF while parsing a value"; + test_error::("", expected); +} + +#[test] +fn test_missing_field() { + #[derive(Deserialize, Debug)] + pub struct Basic { + #[allow(dead_code)] + pub v: bool, + #[allow(dead_code)] + pub w: bool, + } + let yaml = indoc! {" + --- + v: true + "}; + let expected = "missing field `w` at line 2 column 1"; + test_error::(yaml, expected); +} + +#[test] +fn test_unknown_anchor() { + let yaml = indoc! {" + --- + *some + "}; + let expected = "unknown anchor at line 2 column 1"; + test_error::(yaml, expected); +} + +#[test] +fn test_ignored_unknown_anchor() { + #[derive(Deserialize, Debug)] + pub struct Wrapper { + #[allow(dead_code)] + pub c: (), + } + let yaml = indoc! {" + b: [*a] + c: ~ + "}; + let expected = "unknown anchor at line 1 column 5"; + test_error::(yaml, expected); +} + +#[test] +fn test_bytes() { + let expected = "serialization and deserialization of bytes in YAML is not implemented"; + test_error::<&[u8]>("...", expected); +} + +#[test] +fn test_two_documents() { + let yaml = indoc! {" + --- + 0 + --- + 1 + "}; + let expected = "deserializing from YAML containing more than one document is not supported"; + test_error::(yaml, expected); +} + +#[test] +fn test_second_document_syntax_error() { + let yaml = indoc! {" + --- + 0 + --- + ] + "}; + + let mut de = Deserializer::from_str(yaml); + let first_doc = de.next().unwrap(); + let result = ::deserialize(first_doc); + assert_eq!(0, result.unwrap()); + + let second_doc = de.next().unwrap(); + let result = ::deserialize(second_doc); + let expected = + "did not find expected node content at line 4 column 1, while parsing a block node"; + assert_eq!(expected, result.unwrap_err().to_string()); +} + +#[test] +fn test_missing_enum_tag() { + #[derive(Deserialize, Debug)] + pub enum E { + V(#[allow(dead_code)] usize), + } + let yaml = indoc! {r#" + "V": 16 + "other": 32 + "#}; + let expected = "invalid type: map, expected a YAML tag starting with '!'"; + test_error::(yaml, expected); +} + +#[test] +fn test_serialize_nested_enum() { + #[derive(Serialize, Debug)] + pub enum Outer { + Inner(Inner), + } + #[derive(Serialize, Debug)] + pub enum Inner { + Newtype(usize), + Tuple(usize, usize), + Struct { x: usize }, + } + + let expected = "serializing nested enums in YAML is not supported yet"; + + let e = Outer::Inner(Inner::Newtype(0)); + let error = serde_yaml::to_string(&e).unwrap_err(); + assert_eq!(error.to_string(), expected); + + let e = Outer::Inner(Inner::Tuple(0, 0)); + let error = serde_yaml::to_string(&e).unwrap_err(); + assert_eq!(error.to_string(), expected); + + let e = Outer::Inner(Inner::Struct { x: 0 }); + let error = serde_yaml::to_string(&e).unwrap_err(); + assert_eq!(error.to_string(), expected); + + let e = Value::Tagged(Box::new(TaggedValue { + tag: Tag::new("Outer"), + value: Value::Tagged(Box::new(TaggedValue { + tag: Tag::new("Inner"), + value: Value::Null, + })), + })); + let error = serde_yaml::to_string(&e).unwrap_err(); + assert_eq!(error.to_string(), expected); +} + +#[test] +fn test_deserialize_nested_enum() { + #[derive(Deserialize, Debug)] + pub enum Outer { + Inner(#[allow(dead_code)] Inner), + } + #[derive(Deserialize, Debug)] + pub enum Inner { + Variant(#[allow(dead_code)] Vec), + } + + let yaml = indoc! {" + --- + !Inner [] + "}; + let expected = "deserializing nested enum in Outer::Inner from YAML is not supported yet at line 2 column 1"; + test_error::(yaml, expected); + + let yaml = indoc! {" + --- + !Variant [] + "}; + let expected = "unknown variant `Variant`, expected `Inner`"; + test_error::(yaml, expected); + + let yaml = indoc! {" + --- + !Inner !Variant [] + "}; + let expected = "deserializing nested enum in Outer::Inner from YAML is not supported yet at line 2 column 1"; + test_error::(yaml, expected); +} + +#[test] +fn test_variant_not_a_seq() { + #[derive(Deserialize, Debug)] + pub enum E { + V(#[allow(dead_code)] usize), + } + let yaml = indoc! {" + --- + !V + value: 0 + "}; + let expected = "invalid type: map, expected usize at line 2 column 1"; + test_error::(yaml, expected); +} + +#[test] +fn test_struct_from_sequence() { + #[derive(Deserialize, Debug)] + pub struct Struct { + #[allow(dead_code)] + pub x: usize, + #[allow(dead_code)] + pub y: usize, + } + let yaml = indoc! {" + [0, 0] + "}; + let expected = "invalid type: sequence, expected struct Struct"; + test_error::(yaml, expected); +} + +#[test] +fn test_bad_bool() { + let yaml = indoc! {" + --- + !!bool str + "}; + let expected = "invalid value: string \"str\", expected a boolean at line 2 column 1"; + test_error::(yaml, expected); +} + +#[test] +fn test_bad_int() { + let yaml = indoc! {" + --- + !!int str + "}; + let expected = "invalid value: string \"str\", expected an integer at line 2 column 1"; + test_error::(yaml, expected); +} + +#[test] +fn test_bad_float() { + let yaml = indoc! {" + --- + !!float str + "}; + let expected = "invalid value: string \"str\", expected a float at line 2 column 1"; + test_error::(yaml, expected); +} + +#[test] +fn test_bad_null() { + let yaml = indoc! {" + --- + !!null str + "}; + let expected = "invalid value: string \"str\", expected null at line 2 column 1"; + test_error::<()>(yaml, expected); +} + +#[test] +fn test_short_tuple() { + let yaml = indoc! {" + --- + [0, 0] + "}; + let expected = "invalid length 2, expected a tuple of size 3 at line 2 column 1"; + test_error::<(u8, u8, u8)>(yaml, expected); +} + +#[test] +fn test_long_tuple() { + let yaml = indoc! {" + --- + [0, 0, 0] + "}; + let expected = "invalid length 3, expected sequence of 2 elements at line 2 column 1"; + test_error::<(u8, u8)>(yaml, expected); +} + +#[test] +fn test_invalid_scalar_type() { + #[derive(Deserialize, Debug)] + pub struct S { + #[allow(dead_code)] + pub x: [i32; 1], + } + + let yaml = "x: ''\n"; + let expected = "x: invalid type: string \"\", expected an array of length 1 at line 1 column 4"; + test_error::(yaml, expected); +} + +#[cfg(not(miri))] +#[test] +fn test_infinite_recursion_objects() { + #[derive(Deserialize, Debug)] + pub struct S { + #[allow(dead_code)] + pub x: Option>, + } + + let yaml = "&a {'x': *a}"; + let expected = "recursion limit exceeded"; + test_error::(yaml, expected); +} + +#[cfg(not(miri))] +#[test] +fn test_infinite_recursion_arrays() { + #[derive(Deserialize, Debug)] + pub struct S( + #[allow(dead_code)] pub usize, + #[allow(dead_code)] pub Option>, + ); + + let yaml = "&a [0, *a]"; + let expected = "recursion limit exceeded"; + test_error::(yaml, expected); +} + +#[cfg(not(miri))] +#[test] +fn test_infinite_recursion_newtype() { + #[derive(Deserialize, Debug)] + pub struct S(#[allow(dead_code)] pub Option>); + + let yaml = "&a [*a]"; + let expected = "recursion limit exceeded"; + test_error::(yaml, expected); +} + +#[cfg(not(miri))] +#[test] +fn test_finite_recursion_objects() { + #[derive(Deserialize, Debug)] + pub struct S { + #[allow(dead_code)] + pub x: Option>, + } + + let yaml = "{'x':".repeat(1_000) + &"}".repeat(1_000); + let expected = "recursion limit exceeded at line 1 column 641"; + test_error::(&yaml, expected); +} + +#[cfg(not(miri))] +#[test] +fn test_finite_recursion_arrays() { + #[derive(Deserialize, Debug)] + pub struct S( + #[allow(dead_code)] pub usize, + #[allow(dead_code)] pub Option>, + ); + + let yaml = "[0, ".repeat(1_000) + &"]".repeat(1_000); + let expected = "recursion limit exceeded at line 1 column 513"; + test_error::(&yaml, expected); +} + +#[cfg(not(miri))] +#[test] +fn test_billion_laughs() { + #[derive(Debug)] + struct X; + + impl<'de> Visitor<'de> for X { + type Value = X; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("exponential blowup") + } + + fn visit_unit(self) -> Result { + Ok(X) + } + + fn visit_seq(self, mut seq: S) -> Result + where + S: SeqAccess<'de>, + { + while let Some(X) = seq.next_element()? {} + Ok(X) + } + } + + impl<'de> Deserialize<'de> for X { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + deserializer.deserialize_any(X) + } + } + + let yaml = indoc! {" + a: &a ~ + b: &b [*a,*a,*a,*a,*a,*a,*a,*a,*a] + c: &c [*b,*b,*b,*b,*b,*b,*b,*b,*b] + d: &d [*c,*c,*c,*c,*c,*c,*c,*c,*c] + e: &e [*d,*d,*d,*d,*d,*d,*d,*d,*d] + f: &f [*e,*e,*e,*e,*e,*e,*e,*e,*e] + g: &g [*f,*f,*f,*f,*f,*f,*f,*f,*f] + h: &h [*g,*g,*g,*g,*g,*g,*g,*g,*g] + i: &i [*h,*h,*h,*h,*h,*h,*h,*h,*h] + "}; + let expected = "repetition limit exceeded"; + test_error::>(yaml, expected); +} + +#[test] +fn test_duplicate_keys() { + let yaml = indoc! {" + --- + thing: true + thing: false + "}; + let expected = "duplicate entry with key \"thing\" at line 2 column 1"; + test_error::(yaml, expected); + + let yaml = indoc! {" + --- + null: true + ~: false + "}; + let expected = "duplicate entry with null key at line 2 column 1"; + test_error::(yaml, expected); + + let yaml = indoc! {" + --- + 99: true + 99: false + "}; + let expected = "duplicate entry with key 99 at line 2 column 1"; + test_error::(yaml, expected); + + let yaml = indoc! {" + --- + {}: true + {}: false + "}; + let expected = "duplicate entry in YAML map at line 2 column 1"; + test_error::(yaml, expected); +} diff --git a/kclvm/third-party/serde_yaml/tests/test_serde.rs b/kclvm/third-party/serde_yaml/tests/test_serde.rs new file mode 100644 index 000000000..1a892705a --- /dev/null +++ b/kclvm/third-party/serde_yaml/tests/test_serde.rs @@ -0,0 +1,648 @@ +#![allow( + clippy::decimal_literal_representation, + clippy::derive_partial_eq_without_eq, + clippy::unreadable_literal, + clippy::shadow_unrelated +)] + +use indoc::indoc; +use serde::ser::SerializeMap; +use serde_derive::{Deserialize, Serialize}; +use serde_yaml::{Mapping, Number, Value}; +use std::collections::BTreeMap; +use std::fmt::Debug; +use std::iter; + +fn test_serde(thing: &T, yaml: &str) +where + T: serde::Serialize + serde::de::DeserializeOwned + PartialEq + Debug, +{ + let serialized = serde_yaml::to_string(&thing).unwrap(); + assert_eq!(yaml, serialized); + + let value = serde_yaml::to_value(thing).unwrap(); + let serialized = serde_yaml::to_string(&value).unwrap(); + assert_eq!(yaml, serialized); + + let deserialized: T = serde_yaml::from_str(yaml).unwrap(); + assert_eq!(*thing, deserialized); + + let value: Value = serde_yaml::from_str(yaml).unwrap(); + let deserialized = T::deserialize(&value).unwrap(); + assert_eq!(*thing, deserialized); + + let deserialized: T = serde_yaml::from_value(value).unwrap(); + assert_eq!(*thing, deserialized); + + serde_yaml::from_str::(yaml).unwrap(); +} + +#[test] +fn test_default() { + assert_eq!(Value::default(), Value::Null); +} + +#[test] +fn test_int() { + let thing = 256; + let yaml = indoc! {" + 256 + "}; + test_serde(&thing, yaml); +} + +#[test] +fn test_int_max_u64() { + let thing = u64::MAX; + let yaml = indoc! {" + 18446744073709551615 + "}; + test_serde(&thing, yaml); +} + +#[test] +fn test_int_min_i64() { + let thing = i64::MIN; + let yaml = indoc! {" + -9223372036854775808 + "}; + test_serde(&thing, yaml); +} + +#[test] +fn test_int_max_i64() { + let thing = i64::MAX; + let yaml = indoc! {" + 9223372036854775807 + "}; + test_serde(&thing, yaml); +} + +#[test] +fn test_i128_small() { + let thing: i128 = -256; + let yaml = indoc! {" + -256 + "}; + test_serde(&thing, yaml); +} + +#[test] +fn test_u128_small() { + let thing: u128 = 256; + let yaml = indoc! {" + 256 + "}; + test_serde(&thing, yaml); +} + +#[test] +fn test_float() { + let thing = 25.6; + let yaml = indoc! {" + 25.6 + "}; + test_serde(&thing, yaml); + + let thing = 25.; + let yaml = indoc! {" + 25.0 + "}; + test_serde(&thing, yaml); + + let thing = f64::INFINITY; + let yaml = indoc! {" + .inf + "}; + test_serde(&thing, yaml); + + let thing = f64::NEG_INFINITY; + let yaml = indoc! {" + -.inf + "}; + test_serde(&thing, yaml); + + let float: f64 = serde_yaml::from_str(indoc! {" + .nan + "}) + .unwrap(); + assert!(float.is_nan()); +} + +#[test] +fn test_float32() { + let thing: f32 = 25.5; + let yaml = indoc! {" + 25.5 + "}; + test_serde(&thing, yaml); + + let thing = f32::INFINITY; + let yaml = indoc! {" + .inf + "}; + test_serde(&thing, yaml); + + let thing = f32::NEG_INFINITY; + let yaml = indoc! {" + -.inf + "}; + test_serde(&thing, yaml); + + let single_float: f32 = serde_yaml::from_str(indoc! {" + .nan + "}) + .unwrap(); + assert!(single_float.is_nan()); +} + +#[test] +fn test_char() { + let ch = '.'; + let yaml = indoc! {" + '.' + "}; + assert_eq!(yaml, serde_yaml::to_string(&ch).unwrap()); + + let ch = '#'; + let yaml = indoc! {" + '#' + "}; + assert_eq!(yaml, serde_yaml::to_string(&ch).unwrap()); + + let ch = '-'; + let yaml = indoc! {" + '-' + "}; + assert_eq!(yaml, serde_yaml::to_string(&ch).unwrap()); +} + +#[test] +fn test_vec() { + let thing = vec![1, 2, 3]; + let yaml = indoc! {" + - 1 + - 2 + - 3 + "}; + test_serde(&thing, yaml); +} + +#[test] +fn test_map() { + let mut thing = BTreeMap::new(); + thing.insert("x".to_owned(), 1); + thing.insert("y".to_owned(), 2); + let yaml = indoc! {" + x: 1 + 'y': 2 + "}; + test_serde(&thing, yaml); +} + +#[test] +fn test_map_key_value() { + struct Map; + + impl serde::Serialize for Map { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + // Test maps which do not serialize using serialize_entry. + let mut map = serializer.serialize_map(Some(1))?; + map.serialize_key("k")?; + map.serialize_value("v")?; + map.end() + } + } + + let yaml = indoc! {" + k: v + "}; + assert_eq!(yaml, serde_yaml::to_string(&Map).unwrap()); +} + +#[test] +fn test_basic_struct() { + #[derive(Serialize, Deserialize, PartialEq, Debug)] + struct Basic { + x: isize, + y: String, + z: bool, + } + let thing = Basic { + x: -4, + y: "hi\tquoted".to_owned(), + z: true, + }; + let yaml = indoc! {r#" + x: -4 + 'y': "hi\tquoted" + z: true + "#}; + test_serde(&thing, yaml); +} + +#[test] +fn test_string_escapes() { + let yaml = indoc! {" + ascii + "}; + test_serde(&"ascii".to_owned(), yaml); + + let yaml = indoc! {r#" + "\0\a\b\t\n\v\f\r\e\"\\\N\L\P" + "#}; + test_serde( + &"\0\u{7}\u{8}\t\n\u{b}\u{c}\r\u{1b}\"\\\u{85}\u{2028}\u{2029}".to_owned(), + yaml, + ); + + let yaml = indoc! {r#" + "\x1F\uFEFF" + "#}; + test_serde(&"\u{1f}\u{feff}".to_owned(), yaml); + + let yaml = indoc! {" + 🎉 + "}; + test_serde(&"\u{1f389}".to_owned(), yaml); +} + +#[test] +fn test_multiline_string() { + #[derive(Serialize, Deserialize, PartialEq, Debug)] + struct Struct { + trailing_newline: String, + no_trailing_newline: String, + } + let thing = Struct { + trailing_newline: "aaa\nbbb\n".to_owned(), + no_trailing_newline: "aaa\nbbb".to_owned(), + }; + let yaml = indoc! {" + trailing_newline: | + aaa + bbb + no_trailing_newline: |- + aaa + bbb + "}; + test_serde(&thing, yaml); +} + +#[test] +fn test_strings_needing_quote() { + #[derive(Serialize, Deserialize, PartialEq, Debug)] + struct Struct { + boolean: String, + integer: String, + void: String, + leading_zeros: String, + } + let thing = Struct { + boolean: "true".to_owned(), + integer: "1".to_owned(), + void: "null".to_owned(), + leading_zeros: "007".to_owned(), + }; + let yaml = indoc! {" + boolean: 'true' + integer: '1' + void: 'null' + leading_zeros: '007' + "}; + test_serde(&thing, yaml); +} + +#[test] +fn test_moar_strings_needing_quote() { + #[derive(Serialize, Deserialize, PartialEq, Debug)] + struct Struct { + s: String, + } + + for s in &[ + // Short hex values. + "0x0", + "0x1", + // Long hex values that don't fit in a u64 need to be quoted. + "0xffaed20B7B67e498A3bEEf97386ec1849EFeE6Ac", + // "empty" strings. + "", + " ", + // The norway problem https://hitchdev.com/strictyaml/why/implicit-typing-removed/ + "NO", + "no", + "No", + "Yes", + "YES", + "yes", + "True", + "TRUE", + "true", + "False", + "FALSE", + "false", + "y", + "Y", + "n", + "N", + "on", + "On", + "ON", + "off", + "Off", + "OFF", + "0", + "1", + "null", + "Null", + "NULL", + "nil", + "Nil", + "NIL", + // https://hitchdev.com/strictyaml/why/implicit-typing-removed/#string-or-float + "9.3", + // https://github.com/dtolnay/serde-yaml/pull/398#discussion_r1432944356 + "2E234567", + // https://yaml.org/spec/1.2.2/#1022-tag-resolution + "0o7", + "0x3A", + "+12.3", + "0.", + "-0.0", + "12e3", + "-2E+05", + "0", + "-0", + "3", + "-19", + ] { + let thing = Struct { s: s.to_string() }; + let yaml = format!("s: '{}'\n", s); + test_serde(&thing, &yaml); + } +} + +#[test] +fn test_nested_vec() { + let thing = vec![vec![1, 2, 3], vec![4, 5, 6]]; + let yaml = indoc! {" + - - 1 + - 2 + - 3 + - - 4 + - 5 + - 6 + "}; + test_serde(&thing, yaml); +} + +#[test] +fn test_nested_struct() { + #[derive(Serialize, Deserialize, PartialEq, Debug)] + struct Outer { + inner: Inner, + } + #[derive(Serialize, Deserialize, PartialEq, Debug)] + struct Inner { + v: u16, + } + let thing = Outer { + inner: Inner { v: 512 }, + }; + let yaml = indoc! {" + inner: + v: 512 + "}; + test_serde(&thing, yaml); +} + +#[test] +fn test_nested_enum() { + #[derive(Serialize, Deserialize, PartialEq, Debug)] + enum Outer { + Inner(Inner), + } + #[derive(Serialize, Deserialize, PartialEq, Debug)] + enum Inner { + Unit, + } + let thing = Outer::Inner(Inner::Unit); + let yaml = indoc! {" + !Inner Unit + "}; + test_serde(&thing, yaml); +} + +#[test] +fn test_option() { + let thing = vec![Some(1), None, Some(3)]; + let yaml = indoc! {" + - 1 + - null + - 3 + "}; + test_serde(&thing, yaml); +} + +#[test] +fn test_unit() { + let thing = vec![(), ()]; + let yaml = indoc! {" + - null + - null + "}; + test_serde(&thing, yaml); +} + +#[test] +fn test_unit_struct() { + #[derive(Serialize, Deserialize, PartialEq, Debug)] + struct Foo; + let thing = Foo; + let yaml = indoc! {" + null + "}; + test_serde(&thing, yaml); +} + +#[test] +fn test_unit_variant() { + #[derive(Serialize, Deserialize, PartialEq, Debug)] + enum Variant { + First, + Second, + } + let thing = Variant::First; + let yaml = indoc! {" + First + "}; + test_serde(&thing, yaml); +} + +#[test] +fn test_newtype_struct() { + #[derive(Serialize, Deserialize, PartialEq, Debug)] + struct OriginalType { + v: u16, + } + #[derive(Serialize, Deserialize, PartialEq, Debug)] + struct NewType(OriginalType); + let thing = NewType(OriginalType { v: 1 }); + let yaml = indoc! {" + v: 1 + "}; + test_serde(&thing, yaml); +} + +#[test] +fn test_newtype_variant() { + #[derive(Serialize, Deserialize, PartialEq, Debug)] + enum Variant { + Size(usize), + } + let thing = Variant::Size(127); + let yaml = indoc! {" + !Size 127 + "}; + test_serde(&thing, yaml); +} + +#[test] +fn test_tuple_variant() { + #[derive(Serialize, Deserialize, PartialEq, Debug)] + enum Variant { + Rgb(u8, u8, u8), + } + let thing = Variant::Rgb(32, 64, 96); + let yaml = indoc! {" + !Rgb + - 32 + - 64 + - 96 + "}; + test_serde(&thing, yaml); +} + +#[test] +fn test_struct_variant() { + #[derive(Serialize, Deserialize, PartialEq, Debug)] + enum Variant { + Color { r: u8, g: u8, b: u8 }, + } + let thing = Variant::Color { + r: 32, + g: 64, + b: 96, + }; + let yaml = indoc! {" + !Color + r: 32 + g: 64 + b: 96 + "}; + test_serde(&thing, yaml); +} + +#[test] +fn test_tagged_map_value() { + #[derive(Serialize, Deserialize, PartialEq, Debug)] + struct Bindings { + profile: Profile, + } + #[derive(Serialize, Deserialize, PartialEq, Debug)] + enum Profile { + ClassValidator { class_name: String }, + } + let thing = Bindings { + profile: Profile::ClassValidator { + class_name: "ApplicationConfig".to_owned(), + }, + }; + let yaml = indoc! {" + profile: !ClassValidator + class_name: ApplicationConfig + "}; + test_serde(&thing, yaml); +} + +#[test] +fn test_value() { + #[derive(Serialize, Deserialize, PartialEq, Debug)] + pub struct GenericInstructions { + #[serde(rename = "type")] + pub typ: String, + pub config: Value, + } + let thing = GenericInstructions { + typ: "primary".to_string(), + config: Value::Sequence(vec![ + Value::Null, + Value::Bool(true), + Value::Number(Number::from(65535)), + Value::Number(Number::from(0.54321)), + Value::String("s".into()), + Value::Mapping(Mapping::new()), + ]), + }; + let yaml = indoc! {" + type: primary + config: + - null + - true + - 65535 + - 0.54321 + - s + - {} + "}; + test_serde(&thing, yaml); +} + +#[test] +fn test_mapping() { + #[derive(Serialize, Deserialize, PartialEq, Debug)] + struct Data { + pub substructure: Mapping, + } + + let mut thing = Data { + substructure: Mapping::new(), + }; + thing.substructure.insert( + Value::String("a".to_owned()), + Value::String("foo".to_owned()), + ); + thing.substructure.insert( + Value::String("b".to_owned()), + Value::String("bar".to_owned()), + ); + + let yaml = indoc! {" + substructure: + a: foo + b: bar + "}; + + test_serde(&thing, yaml); +} + +#[test] +fn test_long_string() { + #[derive(Serialize, Deserialize, PartialEq, Debug)] + struct Data { + pub string: String, + } + + let thing = Data { + string: iter::repeat(["word", " "]).flatten().take(69).collect(), + }; + + let yaml = indoc! {" + string: word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word + "}; + + test_serde(&thing, yaml); +} diff --git a/kclvm/third-party/serde_yaml/tests/test_value.rs b/kclvm/third-party/serde_yaml/tests/test_value.rs new file mode 100644 index 000000000..4aca75b63 --- /dev/null +++ b/kclvm/third-party/serde_yaml/tests/test_value.rs @@ -0,0 +1,152 @@ +#![allow( + clippy::derive_partial_eq_without_eq, + clippy::eq_op, + clippy::uninlined_format_args +)] + +use indoc::indoc; +use serde::{de::IntoDeserializer, Deserialize as _}; +use serde_derive::{Deserialize, Serialize}; +use serde_yaml::{Number, Value}; + +#[test] +fn test_nan() { + let pos_nan = serde_yaml::from_str::(".nan").unwrap(); + assert!(pos_nan.is_f64()); + assert_eq!(pos_nan, pos_nan); + + let neg_fake_nan = serde_yaml::from_str::("-.nan").unwrap(); + assert!(neg_fake_nan.is_string()); + + let significand_mask = 0xF_FFFF_FFFF_FFFF; + let bits = (f64::NAN.copysign(1.0).to_bits() ^ significand_mask) | 1; + let different_pos_nan = Value::Number(Number::from(f64::from_bits(bits))); + assert_eq!(pos_nan, different_pos_nan); +} + +#[test] +fn test_digits() { + let num_string = serde_yaml::from_str::("01").unwrap(); + assert!(num_string.is_string()); +} + +#[test] +fn test_into_deserializer() { + #[derive(Debug, Deserialize, PartialEq)] + struct Test { + first: String, + second: u32, + } + + let value = serde_yaml::from_str::("xyz").unwrap(); + let s = String::deserialize(value.into_deserializer()).unwrap(); + assert_eq!(s, "xyz"); + + let value = serde_yaml::from_str::("- first\n- second\n- third").unwrap(); + let arr = Vec::::deserialize(value.into_deserializer()).unwrap(); + assert_eq!(arr, &["first", "second", "third"]); + + let value = serde_yaml::from_str::("first: abc\nsecond: 99").unwrap(); + let test = Test::deserialize(value.into_deserializer()).unwrap(); + assert_eq!( + test, + Test { + first: "abc".to_string(), + second: 99 + } + ); +} + +#[test] +fn test_merge() { + // From https://yaml.org/type/merge.html. + let yaml = indoc! {" + --- + - &CENTER { x: 1, y: 2 } + - &LEFT { x: 0, y: 2 } + - &BIG { r: 10 } + - &SMALL { r: 1 } + + # All the following maps are equal: + + - # Explicit keys + x: 1 + y: 2 + r: 10 + label: center/big + + - # Merge one map + << : *CENTER + r: 10 + label: center/big + + - # Merge multiple maps + << : [ *CENTER, *BIG ] + label: center/big + + - # Override + << : [ *BIG, *LEFT, *SMALL ] + x: 1 + label: center/big + "}; + + let mut value: Value = serde_yaml::from_str(yaml).unwrap(); + value.apply_merge().unwrap(); + for i in 5..=7 { + assert_eq!(value[4], value[i]); + } +} + +#[test] +fn test_debug() { + let yaml = indoc! {" + 'Null': ~ + Bool: true + Number: 1 + String: ... + Sequence: + - true + EmptySequence: [] + EmptyMapping: {} + Tagged: !tag true + "}; + + let value: Value = serde_yaml::from_str(yaml).unwrap(); + let debug = format!("{:#?}", value); + + let expected = indoc! {r#" + Mapping { + "Null": Null, + "Bool": Bool(true), + "Number": Number(1), + "String": String("..."), + "Sequence": Sequence [ + Bool(true), + ], + "EmptySequence": Sequence [], + "EmptyMapping": Mapping {}, + "Tagged": TaggedValue { + tag: !tag, + value: Bool(true), + }, + }"# + }; + + assert_eq!(debug, expected); +} + +#[test] +fn test_tagged() { + #[derive(Serialize)] + enum Enum { + Variant(usize), + } + + let value = serde_yaml::to_value(&Enum::Variant(0)).unwrap(); + + let deserialized: serde_yaml::Value = serde_yaml::from_value(value.clone()).unwrap(); + assert_eq!(value, deserialized); + + let serialized = serde_yaml::to_value(&value).unwrap(); + assert_eq!(value, serialized); +} diff --git a/kclvm/tools/Cargo.lock b/kclvm/tools/Cargo.lock index c878f0d1a..92b7c5482 100644 --- a/kclvm/tools/Cargo.lock +++ b/kclvm/tools/Cargo.lock @@ -2,6 +2,21 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "addr2line" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + [[package]] name = "ahash" version = "0.7.6" @@ -15,26 +30,45 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "0.7.18" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" dependencies = [ "memchr", ] +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + [[package]] name = "annotate-snippets" -version = "0.8.0" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d78ea013094e5ea606b1c05fe35f1dd7ea1eb1ea259908d040b25bd5ec677ee5" +checksum = "ccaf7e9dfbb6ab22c82e473cd1a8a7bd313c19a5b7e40970f3d89ef5a5c9e81e" +dependencies = [ + "unicode-width", + "yansi-term", +] [[package]] -name = "ansi_term" -version = "0.12.1" +name = "anyhow" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" +checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" dependencies = [ - "winapi", + "backtrace", ] [[package]] @@ -60,12 +94,39 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +[[package]] +name = "backtrace" +version = "0.3.73" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a" +dependencies = [ + "addr2line", + "cc", + "cfg-if 1.0.0", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + +[[package]] +name = "base-x" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cbbc9d0964165b47557570cce6c952866c2678457aca742aafc9fb771d30270" + [[package]] name = "base64" version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + [[package]] name = "bit-set" version = "0.5.2" @@ -87,13 +148,31 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bitflags" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" + +[[package]] +name = "block-buffer" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b" +dependencies = [ + "block-padding", + "byte-tools", + "byteorder", + "generic-array 0.12.4", +] + [[package]] name = "block-buffer" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" dependencies = [ - "generic-array", + "generic-array 0.14.5", ] [[package]] @@ -102,7 +181,16 @@ version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0bf7fe51849ea569fd452f37822f606a5cabb684dc918707a0193fd4664ff324" dependencies = [ - "generic-array", + "generic-array 0.14.5", +] + +[[package]] +name = "block-padding" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5" +dependencies = [ + "byte-tools", ] [[package]] @@ -113,14 +201,48 @@ checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223" dependencies = [ "lazy_static", "memchr", - "regex-automata", + "regex-automata 0.1.10", + "serde", +] + +[[package]] +name = "bumpalo" +version = "3.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535" + +[[package]] +name = "byte-tools" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" + +[[package]] +name = "cast" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c24dab4283a142afa2fdca129b80ad2c6284e073930f964c3a1293c225ee39a" +dependencies = [ + "rustc_version 0.4.0", ] [[package]] name = "cc" -version = "1.0.73" +version = "1.0.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" +checksum = "96c51067fd44124faa7f870b4b1c969379ad32b2ba805aa959430ceaa384f695" [[package]] name = "cfg-if" @@ -136,17 +258,98 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chrono" -version = "0.4.19" +version = "0.4.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73" +checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" dependencies = [ - "libc", - "num-integer", + "android-tzdata", + "iana-time-zone", + "js-sys", "num-traits", - "time", - "winapi", + "serde", + "wasm-bindgen", + "windows-targets 0.52.5", +] + +[[package]] +name = "clap" +version = "2.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" +dependencies = [ + "bitflags 1.3.2", + "textwrap", + "unicode-width", +] + +[[package]] +name = "compiler_base_error" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32e6a143200e9657a565b093fde64a590af93884d1f820829db6461de1ff0086" +dependencies = [ + "anyhow", + "compiler_base_macros", + "compiler_base_span", + "fluent", + "pretty_assertions", + "rustc_errors", + "rustc_span", + "termcolor", + "unic-langid", + "walkdir", +] + +[[package]] +name = "compiler_base_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21900034f34b69f860a5ff66e0577b8e66d310090b04bf0334afea9a041e0cee" + +[[package]] +name = "compiler_base_session" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67411f0b5421d9c9f045ec08c4d01fe3861197d11215d1e2e448be663aff9ad9" +dependencies = [ + "anyhow", + "compiler_base_error", + "compiler_base_span", +] + +[[package]] +name = "compiler_base_span" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a42aae2adfa4b418441ede52835f3c96e9ca63d595f0ac861d94935757e9cb2e" +dependencies = [ + "rustc_span", ] +[[package]] +name = "console" +version = "0.15.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e1f83fc076bd6dd27517eacdf25fef6c4dfe5f1d7448bafaaf3a26f13b5e4eb" +dependencies = [ + "encode_unicode", + "lazy_static", + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "const_fn" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "373e9fafaa20882876db20562275ff58d50e0caa2590077fe7ce7bef90211d0d" + +[[package]] +name = "core-foundation-sys" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" + [[package]] name = "cpufeatures" version = "0.2.2" @@ -156,6 +359,61 @@ dependencies = [ "libc", ] +[[package]] +name = "crc32fast" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" +dependencies = [ + "cfg-if 1.0.0", +] + +[[package]] +name = "criterion" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1604dafd25fba2fe2d5895a9da139f8dc9b319a5fe5354ca137cbbce4e178d10" +dependencies = [ + "atty", + "cast", + "clap", + "criterion-plot", + "csv", + "itertools", + "lazy_static", + "num-traits", + "oorandom", + "plotters", + "rayon", + "regex", + "serde", + "serde_cbor", + "serde_derive", + "serde_json", + "tinytemplate", + "walkdir", +] + +[[package]] +name = "criterion-plot" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d00996de9f2f7559f7f4dc286073197f83e92256a59ed395f9aac01fe717da57" +dependencies = [ + "cast", + "itertools", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aaa7bd5fb665c6864b5f963dd9097905c54125909c7aa94c9e18507cdbe6c53" +dependencies = [ + "cfg-if 1.0.0", + "crossbeam-utils", +] + [[package]] name = "crossbeam-deque" version = "0.8.1" @@ -197,10 +455,32 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57952ca27b5e3606ff4dd79b0020231aaf9d6aa76dc05fd30137538c50bd3ce8" dependencies = [ - "generic-array", + "generic-array 0.14.5", "typenum", ] +[[package]] +name = "csv" +version = "1.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22813a6dc45b335f9bade10bf7271dc477e81113e89eb251a0bc2a8a81c536e1" +dependencies = [ + "bstr", + "csv-core", + "itoa 0.4.8", + "ryu", + "serde", +] + +[[package]] +name = "csv-core" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b2466559f260f48ad25fe6317b3c8dac77b5bdb5763ac7d9d6103530663bc90" +dependencies = [ + "memchr", +] + [[package]] name = "ctor" version = "0.1.22" @@ -208,7 +488,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f877be4f7c9f246b183111634f75baa039715e3f46ce860677d3b19a69fb229c" dependencies = [ "quote", - "syn", + "syn 1.0.107", +] + +[[package]] +name = "deranged" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +dependencies = [ + "powerfmt", ] [[package]] @@ -217,23 +506,71 @@ version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0e25ea47919b1560c4e3b7fe0aaab9becf5b84a10325ddf7db0f0ba5e1026499" +[[package]] +name = "digest" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5" +dependencies = [ + "generic-array 0.12.4", +] + [[package]] name = "digest" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" dependencies = [ - "generic-array", + "generic-array 0.14.5", ] [[package]] name = "digest" -version = "0.10.3" +version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2fb860ca6fafa5552fb6d0e816a69c8e49f0908bf524e30a90d97c85892d506" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer 0.10.2", "crypto-common", + "subtle", +] + +[[package]] +name = "dirs" +version = "5.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225" +dependencies = [ + "dirs-sys", +] + +[[package]] +name = "dirs-sys" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" +dependencies = [ + "libc", + "option-ext", + "redox_users", + "windows-sys 0.48.0", +] + +[[package]] +name = "discard" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0" + +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.67", ] [[package]] @@ -251,6 +588,12 @@ dependencies = [ "log", ] +[[package]] +name = "encode_unicode" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" + [[package]] name = "enquote" version = "1.1.0" @@ -260,6 +603,22 @@ dependencies = [ "thiserror", ] +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "errno" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + [[package]] name = "fancy-regex" version = "0.7.1" @@ -272,11 +631,20 @@ dependencies = [ [[package]] name = "fastrand" -version = "1.7.0" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" + +[[package]] +name = "filetime" +version = "0.2.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3fcf0cee53519c866c09b5de1f6c56ff9d647101f81c1964fa632e148896cdf" +checksum = "1ee447700ac8aa0b2f2bd7bc4462ad686ba06baa6727ac149a2d6277f0d240fd" dependencies = [ - "instant", + "cfg-if 1.0.0", + "libc", + "redox_syscall 0.4.1", + "windows-sys 0.52.0", ] [[package]] @@ -286,59 +654,236 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "279fb028e20b3c4c320317955b77c5e0c9701f05a1d309905d6fc702cdc5053e" [[package]] -name = "fslock" -version = "0.2.1" +name = "flate2" +version = "1.0.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04412b8935272e3a9bae6f48c7bfff74c2911f60525404edfdd28e49884c3bfb" +checksum = "5f54427cfd1c7829e2a139fcefea601bf088ebca651d2bf53ebc600eac295dae" dependencies = [ - "libc", - "winapi", + "crc32fast", + "miniz_oxide", ] [[package]] -name = "fuchsia-cprng" -version = "0.1.1" +name = "fluent" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" +checksum = "bb74634707bebd0ce645a981148e8fb8c7bccd4c33c652aeffd28bf2f96d555a" +dependencies = [ + "fluent-bundle", + "unic-langid", +] [[package]] -name = "gcc" -version = "0.3.55" +name = "fluent-bundle" +version = "0.15.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f5f3913fa0bfe7ee1fd8248b6b9f42a5af4b9d65ec2dd2c3c26132b950ecfc2" +checksum = "7fe0a21ee80050c678013f82edf4b705fe2f26f1f9877593d13198612503f493" +dependencies = [ + "fluent-langneg", + "fluent-syntax", + "intl-memoizer", + "intl_pluralrules", + "rustc-hash", + "self_cell 0.10.3", + "smallvec", + "unic-langid", +] [[package]] -name = "generic-array" -version = "0.14.5" +name = "fluent-langneg" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd48d33ec7f05fbfa152300fdad764757cbded343c1aa1cff2fbaf4134851803" +checksum = "2c4ad0989667548f06ccd0e306ed56b61bd4d35458d54df5ec7587c0e8ed5e94" dependencies = [ - "typenum", - "version_check", + "unic-langid", ] [[package]] -name = "getrandom" -version = "0.2.6" +name = "fluent-syntax" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9be70c98951c83b8d2f8f60d7065fa6d5146873094452a1008da8c2f1e4205ad" +checksum = "2a530c4694a6a8d528794ee9bbd8ba0122e779629ac908d15ad5a7ae7763a33d" dependencies = [ - "cfg-if 1.0.0", - "libc", - "wasi", + "thiserror", ] [[package]] -name = "glob" -version = "0.3.0" +name = "fnv" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] -name = "hashbrown" -version = "0.11.2" +name = "form_urlencoded" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "fsevent-sys" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76ee7a02da4d231650c7cea31349b889be2f45ddb3ef3032d2ec8185f6313fd2" +dependencies = [ + "libc", +] + +[[package]] +name = "fslock" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04412b8935272e3a9bae6f48c7bfff74c2911f60525404edfdd28e49884c3bfb" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "futures-channel" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" +dependencies = [ + "futures-core", +] + +[[package]] +name = "futures-core" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" + +[[package]] +name = "futures-io" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" + +[[package]] +name = "futures-macro" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.67", +] + +[[package]] +name = "futures-sink" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" + +[[package]] +name = "futures-task" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" + +[[package]] +name = "futures-util" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" +dependencies = [ + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "generational-arena" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877e94aff08e743b651baaea359664321055749b398adff8740a7399af7796e7" +dependencies = [ + "cfg-if 1.0.0", +] + +[[package]] +name = "generic-array" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffdf9f34f1447443d37393cc6c2b8313aebddcd96906caf34e54c68d8e57d7bd" +dependencies = [ + "typenum", +] + +[[package]] +name = "generic-array" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd48d33ec7f05fbfa152300fdad764757cbded343c1aa1cff2fbaf4134851803" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +dependencies = [ + "cfg-if 1.0.0", + "libc", + "wasi", +] + +[[package]] +name = "gimli" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" + +[[package]] +name = "glob" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" + +[[package]] +name = "half" +version = "1.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" +checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" + +[[package]] +name = "handlebars" +version = "5.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d08485b96a0e6393e9e4d1b8d48cf74ad6c063cd905eb33f42c1ce3f0377539b" +dependencies = [ + "log", + "pest", + "pest_derive", + "serde", + "serde_json", + "thiserror", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" [[package]] name = "hermit-abi" @@ -349,15 +894,230 @@ dependencies = [ "libc", ] +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest 0.10.7", +] + +[[package]] +name = "http" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" +dependencies = [ + "bytes", + "fnv", + "itoa 1.0.1", +] + +[[package]] +name = "http-auth" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "643c9bbf6a4ea8a656d6b4cd53d34f79e3f841ad5203c1a55fb7d761923bc255" +dependencies = [ + "memchr", +] + +[[package]] +name = "http-body" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cac85db508abc24a2e48553ba12a996e87244a0395ce011e62b37158745d643" +dependencies = [ + "bytes", + "http", +] + +[[package]] +name = "http-body-util" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" +dependencies = [ + "bytes", + "futures-util", + "http", + "http-body", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fcc0b4a115bf80b728eb8ea024ad5bd707b615bfed49e0665b6e0f86fd082d9" + +[[package]] +name = "hyper" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe575dd17d0862a9a33781c8c4696a55c320909004a67a00fb286ba8b1bc496d" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "http", + "http-body", + "httparse", + "itoa 1.0.1", + "pin-project-lite", + "smallvec", + "tokio", + "want", +] + +[[package]] +name = "hyper-rustls" +version = "0.27.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ee4be2c948921a1a5320b629c4193916ed787a7f7f293fd3f7f5a6c9de74155" +dependencies = [ + "futures-util", + "http", + "hyper", + "hyper-util", + "rustls", + "rustls-pki-types", + "tokio", + "tokio-rustls", + "tower-service", + "webpki-roots", +] + +[[package]] +name = "hyper-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b875924a60b96e5d7b9ae7b066540b1dd1cbd90d1828f54c92e02a283351c56" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "http", + "http-body", + "hyper", + "pin-project-lite", + "socket2", + "tokio", + "tower", + "tower-service", + "tracing", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "idna" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + [[package]] name = "indexmap" -version = "1.8.1" +version = "1.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f647032dfaa1f8b6dc29bd3edb7bbef4861b8b8007ebb118d6db284fd59f6ee" +checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399" dependencies = [ "autocfg", - "hashbrown", - "rustc-rayon", + "hashbrown 0.12.3", + "rustc-rayon 0.4.0", +] + +[[package]] +name = "indexmap" +version = "2.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" +dependencies = [ + "equivalent", + "hashbrown 0.14.5", +] + +[[package]] +name = "inkwell" +version = "0.1.0" +source = "git+https://github.com/TheDan64/inkwell?branch=master#468320973ec40c237ad34e266a680a875605aa3a" +dependencies = [ + "either", + "inkwell_internals", + "libc", + "llvm-sys", + "once_cell", + "parking_lot 0.12.3", +] + +[[package]] +name = "inkwell_internals" +version = "0.7.0" +source = "git+https://github.com/TheDan64/inkwell?branch=master#468320973ec40c237ad34e266a680a875605aa3a" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.107", +] + +[[package]] +name = "inotify" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8069d3ec154eb856955c1c0fbffefbf5f3c40a104ec912d4797314c1801abff" +dependencies = [ + "bitflags 1.3.2", + "inotify-sys", + "libc", +] + +[[package]] +name = "inotify-sys" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e05c02b5e89bff3b946cedeca278abc628fe811e604f027c45a8aa3cf793d0eb" +dependencies = [ + "libc", +] + +[[package]] +name = "insta" +version = "1.17.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6de657c6e99c9f665a595db63c6342de64cbd076a817f24c4a548847a81aee5" +dependencies = [ + "console", + "once_cell", + "serde", + "serde_json", + "serde_yaml 0.8.26", + "similar", ] [[package]] @@ -369,6 +1129,31 @@ dependencies = [ "cfg-if 1.0.0", ] +[[package]] +name = "intl-memoizer" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe22e020fce238ae18a6d5d8c502ee76a52a6e880d99477657e6acc30ec57bda" +dependencies = [ + "type-map", + "unic-langid", +] + +[[package]] +name = "intl_pluralrules" +version = "7.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "078ea7b7c29a2b4df841a7f6ac8775ff6074020c6776d48491ce2268e068f972" +dependencies = [ + "unic-langid", +] + +[[package]] +name = "ipnet" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" + [[package]] name = "itertools" version = "0.10.3" @@ -378,6 +1163,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" + [[package]] name = "itoa" version = "1.0.1" @@ -394,55 +1185,171 @@ dependencies = [ ] [[package]] -name = "json_minimal" -version = "0.1.3" +name = "js-sys" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "json-spanned-value" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb343fa4e3b1b22b344937deedac88da995abf139c2232cbeaa436c38380a210" +dependencies = [ + "serde", + "serde_json", +] + +[[package]] +name = "jwt" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6204285f77fe7d9784db3fdc449ecce1a0114927a51d5a41c4c7a292011c015f" +dependencies = [ + "base64 0.13.0", + "crypto-common", + "digest 0.10.7", + "hmac", + "serde", + "serde_json", + "sha2 0.10.2", +] [[package]] name = "kclvm-ast" -version = "0.1.0" +version = "0.9.0" dependencies = [ + "compiler_base_span", + "kclvm-error", "kclvm-span", - "rustc_span", + "kclvm-utils", "serde", "serde_json", + "thread_local", + "uuid", +] + +[[package]] +name = "kclvm-ast-pretty" +version = "0.9.0" +dependencies = [ + "compiler_base_macros", + "compiler_base_session", + "fancy-regex", + "indexmap 1.9.2", + "kclvm-ast", + "kclvm-error", + "pretty_assertions", +] + +[[package]] +name = "kclvm-compiler" +version = "0.9.0" +dependencies = [ + "ahash", + "bit-set", + "bitflags 1.3.2", + "fancy-regex", + "indexmap 1.9.2", + "inkwell", + "kclvm-ast", + "kclvm-error", + "kclvm-runtime", + "kclvm-sema", + "once_cell", + "phf", + "time 0.2.27", + "unicode_names2", ] [[package]] name = "kclvm-config" -version = "0.1.0" +version = "0.9.0" dependencies = [ "ahash", + "anyhow", "chrono", - "fslock", + "dirs", "glob", - "indexmap", + "indexmap 1.9.2", + "kclvm-ast", + "kclvm-utils", "kclvm-version", + "md-5 0.8.0", "pathdiff", + "regex", "ron", - "rust-crypto", "serde", - "serde_yaml", + "serde_json", + "serde_yaml 0.9.34+deprecated", "toml", ] +[[package]] +name = "kclvm-driver" +version = "0.9.0" +dependencies = [ + "anyhow", + "flate2", + "glob", + "indexmap 2.2.6", + "kclvm-ast", + "kclvm-config", + "kclvm-parser", + "kclvm-runtime", + "kclvm-utils", + "notify", + "oci-distribution", + "once_cell", + "parking_lot 0.12.3", + "serde", + "serde_json", + "tar", + "tokio", + "walkdir", +] + [[package]] name = "kclvm-error" -version = "0.1.0" +version = "0.9.0" dependencies = [ "annotate-snippets", + "anyhow", "atty", - "indexmap", + "compiler_base_error", + "compiler_base_macros", + "compiler_base_session", + "compiler_base_span", + "indexmap 1.9.2", "kclvm-runtime", "kclvm-span", - "rustc_span", - "termcolor", + "kclvm-utils", + "serde", + "serde_json", "termize", + "thiserror", "tracing", ] +[[package]] +name = "kclvm-evaluator" +version = "0.9.0" +dependencies = [ + "anyhow", + "generational-arena", + "indexmap 1.9.2", + "kclvm-ast", + "kclvm-error", + "kclvm-runtime", + "kclvm-sema", +] + [[package]] name = "kclvm-lexer" -version = "0.1.0" +version = "0.9.0" dependencies = [ "kclvm-error", "rustc_lexer", @@ -451,51 +1358,113 @@ dependencies = [ [[package]] name = "kclvm-macros" -version = "0.1.0" +version = "0.9.0" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.107", + "synstructure", +] + +[[package]] +name = "kclvm-parser" +version = "0.9.0" +dependencies = [ + "anyhow", + "bstr", + "compiler_base_error", + "compiler_base_macros", + "compiler_base_session", + "compiler_base_span", + "either", + "enquote", + "indexmap 1.9.2", + "kclvm-ast", + "kclvm-config", + "kclvm-error", + "kclvm-lexer", + "kclvm-sema", + "kclvm-span", + "kclvm-utils", + "num-bigint", + "petgraph", + "regex", + "rustc_lexer", + "serde", + "serde_json", + "tracing", + "unicode_names2", +] + +[[package]] +name = "kclvm-query" +version = "0.9.0" dependencies = [ - "proc-macro2", - "quote", - "syn", - "synstructure", + "anyhow", + "compiler_base_macros", + "compiler_base_session", + "fancy-regex", + "indexmap 1.9.2", + "kclvm-ast", + "kclvm-ast-pretty", + "kclvm-error", + "kclvm-parser", + "kclvm-sema", + "maplit", + "serde", + "serde_json", ] [[package]] -name = "kclvm-parser" -version = "0.1.0" +name = "kclvm-runner" +version = "0.9.0" dependencies = [ - "bstr", - "either", - "enquote", + "anyhow", + "cc", + "chrono", + "compiler_base_macros", + "compiler_base_session", + "glob", + "indexmap 1.9.2", "kclvm-ast", + "kclvm-compiler", "kclvm-config", + "kclvm-driver", "kclvm-error", - "kclvm-lexer", + "kclvm-evaluator", + "kclvm-parser", + "kclvm-query", "kclvm-runtime", "kclvm-sema", - "kclvm-span", - "num-bigint", - "rustc_data_structures", - "rustc_lexer", - "rustc_span", + "kclvm-utils", + "kclvm-version", + "libc", + "libloading", + "once_cell", "serde", "serde_json", - "tracing", - "unicode_names2", + "tempfile", + "threadpool", + "uuid", + "walkdir", ] [[package]] name = "kclvm-runtime" -version = "0.1.0" +version = "0.9.0" dependencies = [ "ahash", - "base64", + "base64 0.13.0", "bstr", "chrono", "fancy-regex", - "indexmap", + "generational-arena", + "glob", + "handlebars", + "indexmap 1.9.2", "itertools", - "json_minimal", "kclvm_runtime_internal_macros", + "lazy_static", "libc", "md5", "num-integer", @@ -503,65 +1472,133 @@ dependencies = [ "regex", "serde", "serde_json", - "serde_yaml", + "serde_yaml 0.9.34+deprecated", "sha1", "sha2 0.9.9", "unic-ucd-bidi", "unic-ucd-category", "unicode-casing", + "uuid", ] [[package]] name = "kclvm-sema" -version = "0.1.0" +version = "0.9.0" dependencies = [ "ahash", + "anyhow", "bit-set", - "bitflags", + "bitflags 1.3.2", + "compiler_base_error", + "compiler_base_macros", + "compiler_base_session", + "compiler_base_span", "fancy-regex", - "indexmap", + "generational-arena", + "indexmap 1.9.2", "kclvm-ast", + "kclvm-ast-pretty", "kclvm-error", "kclvm-runtime", "kclvm-span", + "kclvm-utils", + "lazy_static", "once_cell", "petgraph", "phf", + "regex", + "serde", + "serde_json", + "suggestions", "unicode_names2", ] [[package]] name = "kclvm-span" -version = "0.1.0" +version = "0.9.0" dependencies = [ + "compiler_base_span", "kclvm-macros", - "rustc_span", + "parking_lot 0.11.2", "scoped-tls", ] [[package]] name = "kclvm-tools" -version = "0.1.0" +version = "0.9.0" dependencies = [ + "anyhow", + "compiler_base_session", + "compiler_base_span", + "criterion", "fancy-regex", - "indexmap", + "indexmap 1.9.2", + "insta", + "json-spanned-value", "kclvm-ast", + "kclvm-ast-pretty", + "kclvm-config", + "kclvm-driver", "kclvm-error", "kclvm-parser", + "kclvm-query", + "kclvm-runner", + "kclvm-runtime", + "kclvm-sema", + "kclvm-utils", + "located_yaml", + "once_cell", "pretty_assertions", + "regex", + "rustc_lexer", + "serde_json", + "serde_yaml 0.9.34+deprecated", + "walkdir", +] + +[[package]] +name = "kclvm-utils" +version = "0.9.0" +dependencies = [ + "anyhow", + "fslock", + "regex", ] [[package]] name = "kclvm-version" -version = "0.1.0" +version = "0.9.0" +dependencies = [ + "vergen", +] [[package]] name = "kclvm_runtime_internal_macros" -version = "0.1.0" +version = "0.5.0" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.107", +] + +[[package]] +name = "kqueue" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7447f1ca1b7b563588a205fe93dea8df60fd981423a768bc1c0ded35ed147d0c" +dependencies = [ + "kqueue-sys", + "libc", +] + +[[package]] +name = "kqueue-sys" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed9625ffda8729b85e45cf04090035ac368927b8cebc34898e7c120f52e4838b" +dependencies = [ + "bitflags 1.3.2", + "libc", ] [[package]] @@ -572,15 +1609,69 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.125" +version = "0.2.155" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" + +[[package]] +name = "libloading" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" +dependencies = [ + "cfg-if 1.0.0", + "winapi", +] + +[[package]] +name = "libredox" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5916d2ae698f6de9bfb891ad7a8d65c09d232dc58cc4ac433c7da3b2fd84bc2b" +checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" +dependencies = [ + "bitflags 2.5.0", + "libc", +] [[package]] name = "linked-hash-map" version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7fb9b38af92608140b86b693604b9ffcc5824240a484d1ecd4795bacb2fe88f3" +dependencies = [ + "serde", + "serde_test", +] + +[[package]] +name = "linux-raw-sys" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" + +[[package]] +name = "llvm-sys" +version = "120.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "909fd0ded1d3becfa3d52581b33602d87160d63da6a3844a86a51b0c93e8460c" +dependencies = [ + "cc", + "lazy_static", + "libc", + "regex", + "semver 0.11.0", +] + +[[package]] +name = "located_yaml" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bc68ee6f87a1be7fdba1dcfd854528371aa84a8390279b5d7a99d5da82add76" +dependencies = [ + "linked-hash-map", + "serde", + "yaml-rust", +] [[package]] name = "lock_api" @@ -601,19 +1692,36 @@ dependencies = [ "cfg-if 1.0.0", ] +[[package]] +name = "maplit" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d" + [[package]] name = "matches" version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" +[[package]] +name = "md-5" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a18af3dcaf2b0219366cdb4e2af65a6101457b415c3d1a5c71dd9c2b7c77b9c8" +dependencies = [ + "block-buffer 0.7.3", + "digest 0.8.1", + "opaque-debug 0.2.3", +] + [[package]] name = "md-5" version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "658646b21e0b72f7866c7038ab086d3d5e1cd6271f060fd37defb241949d0582" dependencies = [ - "digest 0.10.3", + "digest 0.10.7", ] [[package]] @@ -624,9 +1732,9 @@ checksum = "490cc448043f947bae3cbee9c203358d62dbee0db12107a74be5c30ccfd09771" [[package]] name = "memchr" -version = "2.5.0" +version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "memmap2" @@ -646,6 +1754,52 @@ dependencies = [ "autocfg", ] +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "miniz_oxide" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" +dependencies = [ + "adler", +] + +[[package]] +name = "mio" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" +dependencies = [ + "libc", + "log", + "wasi", + "windows-sys 0.48.0", +] + +[[package]] +name = "notify" +version = "6.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6205bd8bb1e454ad2e27422015fb5e4f2bcc7e08fa8f27058670d208324a4d2d" +dependencies = [ + "bitflags 2.5.0", + "crossbeam-channel", + "filetime", + "fsevent-sys", + "inotify", + "kqueue", + "libc", + "log", + "mio", + "walkdir", + "windows-sys 0.48.0", +] + [[package]] name = "num-bigint" version = "0.4.3" @@ -657,6 +1811,12 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + [[package]] name = "num-integer" version = "0.1.45" @@ -686,55 +1846,203 @@ dependencies = [ "libc", ] +[[package]] +name = "num_threads" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c7398b9c8b70908f6371f47ed36737907c87c52af34c268fed0bf0ceb92ead9" +dependencies = [ + "libc", +] + +[[package]] +name = "object" +version = "0.36.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "576dfe1fc8f9df304abb159d767a29d0476f7750fbf8aa7ad07816004a207434" +dependencies = [ + "memchr", +] + +[[package]] +name = "oci-distribution" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b95a2c51531af0cb93761f66094044ca6ea879320bccd35ab747ff3fcab3f422" +dependencies = [ + "bytes", + "chrono", + "futures-util", + "http", + "http-auth", + "jwt", + "lazy_static", + "olpc-cjson", + "regex", + "reqwest", + "serde", + "serde_json", + "sha2 0.10.2", + "thiserror", + "tokio", + "tracing", + "unicase", +] + +[[package]] +name = "olpc-cjson" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d637c9c15b639ccff597da8f4fa968300651ad2f1e968aefc3b4927a6fb2027a" +dependencies = [ + "serde", + "serde_json", + "unicode-normalization", +] + [[package]] name = "once_cell" -version = "1.10.0" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "oorandom" +version = "11.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" + +[[package]] +name = "opaque-debug" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" + +[[package]] +name = "opaque-debug" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" + +[[package]] +name = "option-ext" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" + +[[package]] +name = "output_vt100" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "628223faebab4e3e40667ee0b2336d34a5b960ff60ea743ddfdbcf7770bcfb66" +dependencies = [ + "winapi", +] + +[[package]] +name = "parking_lot" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" +dependencies = [ + "instant", + "lock_api", + "parking_lot_core 0.8.6", +] + +[[package]] +name = "parking_lot" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" +dependencies = [ + "lock_api", + "parking_lot_core 0.9.3", +] + +[[package]] +name = "parking_lot_core" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc" +dependencies = [ + "cfg-if 1.0.0", + "instant", + "libc", + "redox_syscall 0.2.13", + "smallvec", + "winapi", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09a279cbf25cb0757810394fbc1e359949b59e348145c643a939a525692e6929" +dependencies = [ + "cfg-if 1.0.0", + "libc", + "redox_syscall 0.2.13", + "smallvec", + "windows-sys 0.36.1", +] + +[[package]] +name = "pathdiff" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87f3e037eac156d1775da914196f0f37741a274155e34a0b7e427c35d2a2ecb9" +checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd" [[package]] -name = "opaque-debug" -version = "0.3.0" +name = "percent-encoding" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] -name = "output_vt100" -version = "0.1.3" +name = "pest" +version = "2.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "628223faebab4e3e40667ee0b2336d34a5b960ff60ea743ddfdbcf7770bcfb66" +checksum = "560131c633294438da9f7c4b08189194b20946c8274c6b9e38881a7874dc8ee8" dependencies = [ - "winapi", + "memchr", + "thiserror", + "ucd-trie", ] [[package]] -name = "parking_lot" -version = "0.12.0" +name = "pest_derive" +version = "2.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87f5ec2493a61ac0506c0f4199f99070cbe83857b0337006a30f3e6719b8ef58" +checksum = "26293c9193fbca7b1a3bf9b79dc1e388e927e6cacaa78b4a3ab705a1d3d41459" dependencies = [ - "lock_api", - "parking_lot_core", + "pest", + "pest_generator", ] [[package]] -name = "parking_lot_core" -version = "0.9.3" +name = "pest_generator" +version = "2.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09a279cbf25cb0757810394fbc1e359949b59e348145c643a939a525692e6929" +checksum = "3ec22af7d3fb470a85dd2ca96b7c577a1eb4ef6f1683a9fe9a8c16e136c04687" dependencies = [ - "cfg-if 1.0.0", - "libc", - "redox_syscall", - "smallvec", - "windows-sys", + "pest", + "pest_meta", + "proc-macro2", + "quote", + "syn 2.0.67", ] [[package]] -name = "pathdiff" -version = "0.2.1" +name = "pest_meta" +version = "2.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd" +checksum = "d7a240022f37c361ec1878d646fc5b7d7c4d28d5946e1a80ad5a7a4f4ca0bdcd" +dependencies = [ + "once_cell", + "pest", + "sha2 0.10.2", +] [[package]] name = "petgraph" @@ -743,7 +2051,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4a13a2fa9d0b63e5f22328828741e523766fff0ee9e779316902290dff3f824f" dependencies = [ "fixedbitset", - "indexmap", + "indexmap 1.9.2", ] [[package]] @@ -764,7 +2072,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d43f3220d96e0080cc9ea234978ccd80d904eafb17be31bb0f76daaea6493082" dependencies = [ "phf_shared", - "rand 0.8.5", + "rand", ] [[package]] @@ -778,7 +2086,7 @@ dependencies = [ "proc-macro-hack", "proc-macro2", "quote", - "syn", + "syn 1.0.107", ] [[package]] @@ -790,11 +2098,71 @@ dependencies = [ "siphasher", ] +[[package]] +name = "pin-project" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.67", +] + [[package]] name = "pin-project-lite" -version = "0.2.9" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "plotters" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a3fd9ec30b9749ce28cd91f255d569591cdf937fe280c312143e3c4bad6f2a" +dependencies = [ + "num-traits", + "plotters-backend", + "plotters-svg", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "plotters-backend" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d88417318da0eaf0fdcdb51a0ee6c3bed624333bff8f946733049380be67ac1c" + +[[package]] +name = "plotters-svg" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "521fa9638fa597e1dc53e9412a4f9cefb01187ee1f7413076f9e6749e2885ba9" +dependencies = [ + "plotters-backend", +] + +[[package]] +name = "powerfmt" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" [[package]] name = "ppv-lite86" @@ -804,14 +2172,14 @@ checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" [[package]] name = "pretty_assertions" -version = "1.2.1" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c89f989ac94207d048d92db058e4f6ec7342b0971fc58d1271ca148b799b3563" +checksum = "a25e9bcb20aa780fd0bb16b72403a9064d6b3f22f026946029acb941a50af755" dependencies = [ - "ansi_term", "ctor", "diff", "output_vt100", + "yansi", ] [[package]] @@ -822,52 +2190,67 @@ checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" [[package]] name = "proc-macro2" -version = "1.0.38" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9027b48e9d4c9175fa2218adf3557f91c1137021739951d4932f5f8268ac48aa" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" dependencies = [ - "unicode-xid", + "unicode-ident", ] [[package]] -name = "psm" -version = "0.1.18" +name = "quinn" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "871372391786ccec00d3c5d3d6608905b3d4db263639cfe075d3b60a736d115a" +checksum = "e4ceeeeabace7857413798eb1ffa1e9c905a9946a57d81fb69b4b71c4d8eb3ad" dependencies = [ - "cc", + "bytes", + "pin-project-lite", + "quinn-proto", + "quinn-udp", + "rustc-hash", + "rustls", + "thiserror", + "tokio", + "tracing", ] [[package]] -name = "quote" -version = "1.0.18" +name = "quinn-proto" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1" +checksum = "ddf517c03a109db8100448a4be38d498df8a210a99fe0e1b9eaf39e78c640efe" dependencies = [ - "proc-macro2", + "bytes", + "rand", + "ring", + "rustc-hash", + "rustls", + "slab", + "thiserror", + "tinyvec", + "tracing", ] [[package]] -name = "rand" -version = "0.3.23" +name = "quinn-udp" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64ac302d8f83c0c1974bf758f6b041c6c8ada916fbb44a609158ca8b064cc76c" +checksum = "9096629c45860fc7fb143e125eb826b5e721e10be3263160c7d60ca832cf8c46" dependencies = [ "libc", - "rand 0.4.6", + "once_cell", + "socket2", + "tracing", + "windows-sys 0.52.0", ] [[package]] -name = "rand" -version = "0.4.6" +name = "quote" +version = "1.0.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" dependencies = [ - "fuchsia-cprng", - "libc", - "rand_core 0.3.1", - "rdrand", - "winapi", + "proc-macro2", ] [[package]] @@ -878,7 +2261,7 @@ checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", "rand_chacha", - "rand_core 0.6.3", + "rand_core", ] [[package]] @@ -888,59 +2271,80 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", - "rand_core 0.6.3", + "rand_core", ] [[package]] name = "rand_core" -version = "0.3.1" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" +checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" dependencies = [ - "rand_core 0.4.2", + "getrandom", ] [[package]] -name = "rand_core" -version = "0.4.2" +name = "rayon" +version = "1.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" +checksum = "bd99e5772ead8baa5215278c9b15bf92087709e9c1b2d1f97cdb5a183c933a7d" +dependencies = [ + "autocfg", + "crossbeam-deque", + "either", + "rayon-core", +] [[package]] -name = "rand_core" -version = "0.6.3" +name = "rayon-core" +version = "1.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" +checksum = "258bcdb5ac6dad48491bb2992db6b7cf74878b0384908af124823d118c99683f" dependencies = [ - "getrandom", + "crossbeam-channel", + "crossbeam-deque", + "crossbeam-utils", + "num_cpus", ] [[package]] -name = "rdrand" -version = "0.4.0" +name = "redox_syscall" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" +checksum = "62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42" dependencies = [ - "rand_core 0.3.1", + "bitflags 1.3.2", ] [[package]] name = "redox_syscall" -version = "0.2.13" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +dependencies = [ + "bitflags 1.3.2", +] + +[[package]] +name = "redox_users" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd283d9651eeda4b2a83a43c1c91b266c40fd76ecd39a50a8c630ae69dc72891" dependencies = [ - "bitflags", + "getrandom", + "libredox", + "thiserror", ] [[package]] name = "regex" -version = "1.5.5" +version = "1.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a11647b6b25ff05a515cb92c365cec08801e83423a235b51e231e1808747286" +checksum = "b91213439dad192326a0d7c6ee3955910425f441d7038e0d6933b0aec5c4517f" dependencies = [ "aho-corasick", "memchr", + "regex-automata 0.4.7", "regex-syntax", ] @@ -950,19 +2354,80 @@ version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" +[[package]] +name = "regex-automata" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + [[package]] name = "regex-syntax" -version = "0.6.25" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" +checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" [[package]] -name = "remove_dir_all" -version = "0.5.3" +name = "reqwest" +version = "0.12.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" +checksum = "c7d6d2a27d57148378eb5e111173f4276ad26340ecc5c49a4a2152167a2d6a37" dependencies = [ - "winapi", + "base64 0.22.1", + "bytes", + "futures-core", + "futures-util", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-rustls", + "hyper-util", + "ipnet", + "js-sys", + "log", + "mime", + "once_cell", + "percent-encoding", + "pin-project-lite", + "quinn", + "rustls", + "rustls-pemfile", + "rustls-pki-types", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper", + "tokio", + "tokio-rustls", + "tokio-util", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "wasm-streams", + "web-sys", + "webpki-roots", + "winreg", +] + +[[package]] +name = "ring" +version = "0.17.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" +dependencies = [ + "cc", + "cfg-if 1.0.0", + "getrandom", + "libc", + "spin", + "untrusted", + "windows-sys 0.52.0", ] [[package]] @@ -971,23 +2436,16 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b861ecaade43ac97886a512b360d01d66be9f41f3c61088b42cedf92e03d678" dependencies = [ - "base64", - "bitflags", + "base64 0.13.0", + "bitflags 1.3.2", "serde", ] [[package]] -name = "rust-crypto" -version = "0.2.36" +name = "rustc-demangle" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f76d05d3993fd5f4af9434e8e436db163a12a9d40e1a58a726f27a01dfd12a2a" -dependencies = [ - "gcc", - "libc", - "rand 0.3.23", - "rustc-serialize", - "time", -] +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" [[package]] name = "rustc-hash" @@ -1003,7 +2461,19 @@ checksum = "9974ab223660e61c1b4e7b43b827379df286736ca988308ce7e16f59f2d89246" dependencies = [ "crossbeam-deque", "either", - "rustc-rayon-core", + "rustc-rayon-core 0.3.2", +] + +[[package]] +name = "rustc-rayon" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a79f0b0b2609e2eacf9758013f50e7176cb4b29fd6436a747b14a5362c8727a" +dependencies = [ + "autocfg", + "crossbeam-deque", + "either", + "rustc-rayon-core 0.4.1", ] [[package]] @@ -1019,34 +2489,51 @@ dependencies = [ ] [[package]] -name = "rustc-serialize" -version = "0.3.24" +name = "rustc-rayon-core" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda" +checksum = "02269144a0db9bb55cf5d4a41a5a0e95b334b0b78b08269018ca9b0250718c30" +dependencies = [ + "crossbeam-channel", + "crossbeam-deque", + "crossbeam-utils", + "num_cpus", +] [[package]] name = "rustc_data_structures" -version = "0.0.0" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a38bae9c6afa27015bcaa2869e03bb111ecf0d0e0edc2da559a91d4057174c9a" dependencies = [ "arrayvec", - "bitflags", + "bitflags 1.3.2", "cfg-if 0.1.10", "ena", - "indexmap", + "indexmap 1.9.2", "jobserver", "libc", "memmap2", - "parking_lot", + "parking_lot 0.12.3", "rustc-hash", - "rustc-rayon", - "rustc-rayon-core", + "rustc-rayon 0.3.2", + "rustc-rayon-core 0.3.2", "stable_deref_trait", - "stacker", "tempfile", "tracing", "winapi", ] +[[package]] +name = "rustc_errors" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00299b1841816d2c41129e6d4f86b0b446ee387e8203871c2551e1c405b1243c" +dependencies = [ + "termcolor", + "winapi", +] + [[package]] name = "rustc_lexer" version = "0.1.0" @@ -1058,10 +2545,12 @@ dependencies = [ [[package]] name = "rustc_span" -version = "0.0.0" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "043e9cc06c53de1f6a125e41e4b915d23a130241610a114ad4fe4f654617eae4" dependencies = [ "cfg-if 0.1.10", - "md-5", + "md-5 0.10.1", "rustc_data_structures", "scoped-tls", "sha-1", @@ -1071,66 +2560,249 @@ dependencies = [ ] [[package]] -name = "ryu" -version = "1.0.9" +name = "rustc_version" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" +dependencies = [ + "semver 0.9.0", +] + +[[package]] +name = "rustc_version" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +dependencies = [ + "semver 1.0.10", +] + +[[package]] +name = "rustix" +version = "0.38.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" +dependencies = [ + "bitflags 2.5.0", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.52.0", +] + +[[package]] +name = "rustls" +version = "0.23.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05cff451f60db80f490f3c182b77c35260baace73209e9cdbbe526bfe3a4d402" +dependencies = [ + "once_cell", + "ring", + "rustls-pki-types", + "rustls-webpki", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-pemfile" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29993a25686778eb88d4189742cd713c9bce943bc54251a33509dc63cbacf73d" +dependencies = [ + "base64 0.22.1", + "rustls-pki-types", +] + +[[package]] +name = "rustls-pki-types" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "976295e77ce332211c0d24d92c0e83e50f5c5f046d11082cea19f3df13a3562d" + +[[package]] +name = "rustls-webpki" +version = "0.102.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff448f7e92e913c4b7d4c6d8e4540a1724b319b4152b8aef6d4cf8339712b33e" +dependencies = [ + "ring", + "rustls-pki-types", + "untrusted", +] + +[[package]] +name = "rustversion" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" + +[[package]] +name = "ryu" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "scoped-tls" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2" + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "self_cell" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e14e4d63b804dc0c7ec4a1e52bcb63f02c7ac94476755aa579edac21e01f915d" +dependencies = [ + "self_cell 1.0.4", +] + +[[package]] +name = "self_cell" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d369a96f978623eb3dc28807c4852d6cc617fed53da5d3c400feff1ef34a714a" + +[[package]] +name = "semver" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" +dependencies = [ + "semver-parser 0.7.0", +] + +[[package]] +name = "semver" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6" +dependencies = [ + "semver-parser 0.10.2", +] + +[[package]] +name = "semver" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f" +checksum = "a41d061efea015927ac527063765e73601444cdc344ba855bc7bd44578b25e1c" [[package]] -name = "scoped-tls" -version = "1.0.0" +name = "semver-parser" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2" +checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] -name = "scopeguard" -version = "1.1.0" +name = "semver-parser" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" +checksum = "00b0bef5b7f9e0df16536d3961cfb6e84331c065b4066afb39768d0e319411f7" +dependencies = [ + "pest", +] [[package]] name = "serde" -version = "1.0.137" +version = "1.0.203" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61ea8d54c77f8315140a05f4c7237403bf38b72704d031543aa1d16abbf517d1" +checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094" dependencies = [ "serde_derive", ] +[[package]] +name = "serde_cbor" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bef2ebfde456fb76bbcf9f59315333decc4fda0b2b44b420243c11e0f5ec1f5" +dependencies = [ + "half", + "serde", +] + [[package]] name = "serde_derive" -version = "1.0.137" +version = "1.0.203" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f26faba0c3959972377d3b2d306ee9f71faee9714294e41bb777f83f88578be" +checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.67", ] [[package]] name = "serde_json" -version = "1.0.81" +version = "1.0.115" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12dc5c46daa8e9fdf4f5e71b6cf9a53f2487da0e86e55808e2d35539666497dd" +dependencies = [ + "itoa 1.0.1", + "ryu", + "serde", +] + +[[package]] +name = "serde_test" +version = "1.0.176" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a2f49ace1498612d14f7e0b8245519584db8299541dfe31a06374a828d620ab" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b7ce2b32a1aed03c558dc61a5cd328f15aff2dbc17daad8fb8af04d2100e15c" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" dependencies = [ - "itoa", + "form_urlencoded", + "itoa 1.0.1", "ryu", "serde", ] [[package]] name = "serde_yaml" -version = "0.8.24" +version = "0.8.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "707d15895415db6628332b737c838b88c598522e4dc70647e59b72312924aebc" +checksum = "578a7433b776b56a35785ed5ce9a7e777ac0598aac5a6dd1b4b18a307c7fc71b" dependencies = [ - "indexmap", + "indexmap 1.9.2", "ryu", "serde", "yaml-rust", ] +[[package]] +name = "serde_yaml" +version = "0.9.34+deprecated" +dependencies = [ + "indexmap 2.2.6", + "itoa 1.0.1", + "ryu", + "serde", + "unsafe-libyaml", +] + [[package]] name = "sha-1" version = "0.10.0" @@ -1139,7 +2811,7 @@ checksum = "028f48d513f9678cda28f6e4064755b3fbb2af6acd672f2c209b62323f7aea0f" dependencies = [ "cfg-if 1.0.0", "cpufeatures", - "digest 0.10.3", + "digest 0.10.7", ] [[package]] @@ -1167,7 +2839,7 @@ dependencies = [ "cfg-if 1.0.0", "cpufeatures", "digest 0.9.0", - "opaque-debug", + "opaque-debug 0.3.0", ] [[package]] @@ -1178,20 +2850,60 @@ checksum = "55deaec60f81eefe3cce0dc50bda92d6d8e88f2a27df7c5033b42afeb1ed2676" dependencies = [ "cfg-if 1.0.0", "cpufeatures", - "digest 0.10.3", + "digest 0.10.7", +] + +[[package]] +name = "signal-hook-registry" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" +dependencies = [ + "libc", ] +[[package]] +name = "similar" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa42c91313f1d05da9b26f267f931cf178d4aba455b4c4622dd7355eb80c6640" + [[package]] name = "siphasher" version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7bd3e3206899af3f8b12af284fafc038cc1dc2b41d1b89dd17297221c5d225de" +[[package]] +name = "slab" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] + [[package]] name = "smallvec" -version = "1.8.0" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" + +[[package]] +name = "socket2" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "spin" +version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" [[package]] name = "stable_deref_trait" @@ -1200,29 +2912,112 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" [[package]] -name = "stacker" -version = "0.1.14" +name = "standback" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90939d5171a4420b3ff5fbc8954d641e7377335454c259dcb80786f3f21dc9b4" +checksum = "e113fb6f3de07a243d434a56ec6f186dfd51cb08448239fe7bcae73f87ff28ff" dependencies = [ - "cc", - "cfg-if 1.0.0", - "libc", - "psm", - "winapi", + "version_check", +] + +[[package]] +name = "stdweb" +version = "0.4.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d022496b16281348b52d0e30ae99e01a73d737b2f45d38fed4edf79f9325a1d5" +dependencies = [ + "discard", + "rustc_version 0.2.3", + "stdweb-derive", + "stdweb-internal-macros", + "stdweb-internal-runtime", + "wasm-bindgen", +] + +[[package]] +name = "stdweb-derive" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c87a60a40fccc84bef0652345bbbbbe20a605bf5d0ce81719fc476f5c03b50ef" +dependencies = [ + "proc-macro2", + "quote", + "serde", + "serde_derive", + "syn 1.0.107", +] + +[[package]] +name = "stdweb-internal-macros" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58fa5ff6ad0d98d1ffa8cb115892b6e69d67799f6763e162a1c9db421dc22e11" +dependencies = [ + "base-x", + "proc-macro2", + "quote", + "serde", + "serde_derive", + "serde_json", + "sha1", + "syn 1.0.107", +] + +[[package]] +name = "stdweb-internal-runtime" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "213701ba3370744dcd1a12960caa4843b3d68b4d1c0a5d575e0d65b2ee9d16c0" + +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + +[[package]] +name = "subtle" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d0208408ba0c3df17ed26eb06992cb1a1268d41b2c0e12e65203fbe3972cee5" + +[[package]] +name = "suggestions" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5441c382482e49aaac2c3ea9cbcd24290531246e879ee94af5dfc4b144f11e80" +dependencies = [ + "strsim", ] [[package]] name = "syn" -version = "1.0.93" +version = "1.0.107" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04066589568b72ec65f42d65a1a52436e954b168773148893c020269563decf2" +checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5" dependencies = [ "proc-macro2", "quote", - "unicode-xid", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.67" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff8655ed1d86f3af4ee3fd3263786bc14245ad17c4c7e85ba7187fb3ae028c90" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", ] +[[package]] +name = "sync_wrapper" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394" + [[package]] name = "synstructure" version = "0.12.6" @@ -1231,22 +3026,31 @@ checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.107", "unicode-xid", ] +[[package]] +name = "tar" +version = "0.4.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb797dad5fb5b76fcf519e702f4a589483b5ef06567f160c392832c1f5e44909" +dependencies = [ + "filetime", + "libc", + "xattr", +] + [[package]] name = "tempfile" -version = "3.3.0" +version = "3.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" +checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" dependencies = [ "cfg-if 1.0.0", "fastrand", - "libc", - "redox_syscall", - "remove_dir_all", - "winapi", + "rustix", + "windows-sys 0.52.0", ] [[package]] @@ -1268,37 +3072,213 @@ dependencies = [ "winapi", ] +[[package]] +name = "textwrap" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" +dependencies = [ + "unicode-width", +] + [[package]] name = "thiserror" -version = "1.0.31" +version = "1.0.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd829fe32373d27f76265620b5309d0340cb8550f523c1dda251d6298069069a" +checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.31" +version = "1.0.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0396bc89e626244658bef819e22d0cc459e795a5ebe878e6ec336d1674a8d79a" +checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.67", +] + +[[package]] +name = "thread_local" +version = "1.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" +dependencies = [ + "cfg-if 1.0.0", + "once_cell", +] + +[[package]] +name = "threadpool" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d050e60b33d41c19108b32cea32164033a9013fe3b46cbd4457559bfbf77afaa" +dependencies = [ + "num_cpus", ] [[package]] name = "time" -version = "0.1.44" +version = "0.2.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255" +checksum = "4752a97f8eebd6854ff91f1c1824cd6160626ac4bd44287f7f4ea2035a02a242" dependencies = [ + "const_fn", "libc", - "wasi", + "standback", + "stdweb", + "time-macros 0.1.1", + "version_check", "winapi", ] +[[package]] +name = "time" +version = "0.3.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" +dependencies = [ + "deranged", + "itoa 1.0.1", + "libc", + "num-conv", + "num_threads", + "powerfmt", + "serde", + "time-core", + "time-macros 0.2.18", +] + +[[package]] +name = "time-core" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" + +[[package]] +name = "time-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "957e9c6e26f12cb6d0dd7fc776bb67a706312e7299aed74c8dd5b17ebb27e2f1" +dependencies = [ + "proc-macro-hack", + "time-macros-impl", +] + +[[package]] +name = "time-macros" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" +dependencies = [ + "num-conv", + "time-core", +] + +[[package]] +name = "time-macros-impl" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd3c141a1b43194f3f56a1411225df8646c55781d5f26db825b3d98507eb482f" +dependencies = [ + "proc-macro-hack", + "proc-macro2", + "quote", + "standback", + "syn 1.0.107", +] + +[[package]] +name = "tinystr" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" +dependencies = [ + "displaydoc", +] + +[[package]] +name = "tinytemplate" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc" +dependencies = [ + "serde", + "serde_json", +] + +[[package]] +name = "tinyvec" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "tokio" +version = "1.38.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba4f4a02a7a80d6f274636f0aa95c7e383b912d41fe721a31f29e29698585a4a" +dependencies = [ + "backtrace", + "bytes", + "libc", + "mio", + "num_cpus", + "parking_lot 0.12.3", + "pin-project-lite", + "signal-hook-registry", + "socket2", + "tokio-macros", + "windows-sys 0.48.0", +] + +[[package]] +name = "tokio-macros" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f5ae998a069d4b5aba8ee9dad856af7d520c3699e6159b185c2acd48155d39a" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.67", +] + +[[package]] +name = "tokio-rustls" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4" +dependencies = [ + "rustls", + "rustls-pki-types", + "tokio", +] + +[[package]] +name = "tokio-util" +version = "0.7.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cf6b47b3771c49ac75ad09a6162f53ad4b8088b76ac60e8ec1455b31a189fe1" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", +] + [[package]] name = "toml" version = "0.5.9" @@ -1308,6 +3288,33 @@ dependencies = [ "serde", ] +[[package]] +name = "tower" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" +dependencies = [ + "futures-core", + "futures-util", + "pin-project", + "pin-project-lite", + "tokio", + "tower-layer", + "tower-service", +] + +[[package]] +name = "tower-layer" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" + +[[package]] +name = "tower-service" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" + [[package]] name = "tracing" version = "0.1.34" @@ -1315,6 +3322,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5d0ecdcb44a79f0fe9844f0c4f33a342cbcbb5117de8001e6ba0dc2351327d09" dependencies = [ "cfg-if 1.0.0", + "log", "pin-project-lite", "tracing-attributes", "tracing-core", @@ -1328,7 +3336,7 @@ checksum = "cc6b8ad3567499f98a1db7a752b07a7c8c7c7c34c332ec00effb2b0027974b7c" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.107", ] [[package]] @@ -1340,12 +3348,33 @@ dependencies = [ "lazy_static", ] +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + +[[package]] +name = "type-map" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "deb68604048ff8fa93347f02441e4487594adc20bb8a084f9e564d2b827a0a9f" +dependencies = [ + "rustc-hash", +] + [[package]] name = "typenum" version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" +[[package]] +name = "ucd-trie" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e79c4d996edb816c91e4308506774452e55e95c3c9de07b6729e17e15a5ef81" + [[package]] name = "unic-char-property" version = "0.9.0" @@ -1378,6 +3407,49 @@ dependencies = [ "unic-ucd-version", ] +[[package]] +name = "unic-langid" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23dd9d1e72a73b25e07123a80776aae3e7b0ec461ef94f9151eed6ec88005a44" +dependencies = [ + "unic-langid-impl", + "unic-langid-macros", +] + +[[package]] +name = "unic-langid-impl" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a5422c1f65949306c99240b81de9f3f15929f5a8bfe05bb44b034cc8bf593e5" +dependencies = [ + "tinystr", +] + +[[package]] +name = "unic-langid-macros" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0da1cd2c042d3c7569a1008806b02039e7a4a2bdf8f8e96bd3c792434a0e275e" +dependencies = [ + "proc-macro-hack", + "tinystr", + "unic-langid-impl", + "unic-langid-macros-impl", +] + +[[package]] +name = "unic-langid-macros-impl" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ed7f4237ba393424195053097c1516bd4590dc82b84f2f97c5c69e12704555b" +dependencies = [ + "proc-macro-hack", + "quote", + "syn 2.0.67", + "unic-langid-impl", +] + [[package]] name = "unic-ucd-bidi" version = "0.9.0" @@ -1410,12 +3482,42 @@ dependencies = [ "unic-common", ] +[[package]] +name = "unicase" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89" +dependencies = [ + "version_check", +] + +[[package]] +name = "unicode-bidi" +version = "0.3.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" + [[package]] name = "unicode-casing" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "623f59e6af2a98bdafeb93fa277ac8e1e40440973001ca15cf4ae1541cd16d56" +[[package]] +name = "unicode-ident" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc" + +[[package]] +name = "unicode-normalization" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" +dependencies = [ + "tinyvec", +] + [[package]] name = "unicode-width" version = "0.1.9" @@ -1434,17 +3536,181 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "87d6678d7916394abad0d4b19df4d3802e1fd84abd7d701f39b75ee71b9e8cf1" +[[package]] +name = "unsafe-libyaml" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" + +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + +[[package]] +name = "url" +version = "2.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + +[[package]] +name = "uuid" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a183cf7feeba97b4dd1c0d46788634f6221d87fa961b305bed08c851829efcc0" +dependencies = [ + "getrandom", + "serde", +] + +[[package]] +name = "vergen" +version = "8.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e27d6bdd219887a9eadd19e1c34f32e47fa332301184935c6d9bca26f3cca525" +dependencies = [ + "anyhow", + "cfg-if 1.0.0", + "rustc_version 0.4.0", + "rustversion", + "time 0.3.36", +] + [[package]] name = "version_check" version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +[[package]] +name = "walkdir" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" +dependencies = [ + "same-file", + "winapi", + "winapi-util", +] + +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + [[package]] name = "wasi" -version = "0.10.0+wasi-snapshot-preview1" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" +dependencies = [ + "cfg-if 1.0.0", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn 2.0.67", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0" +dependencies = [ + "cfg-if 1.0.0", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.67", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" + +[[package]] +name = "wasm-streams" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b65dc4c90b63b118468cf747d8bf3566c1913ef60be765b5730ead9e0a3ba129" +dependencies = [ + "futures-util", + "js-sys", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "web-sys" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "webpki-roots" +version = "0.26.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" +checksum = "bd7c23921eeb1713a4e851530e9b9756e4fb0e89978582942612524cf09f01cd" +dependencies = [ + "rustls-pki-types", +] [[package]] name = "winapi" @@ -1477,49 +3743,218 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows-core" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +dependencies = [ + "windows-targets 0.52.5", +] + [[package]] name = "windows-sys" version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2" dependencies = [ - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_msvc", + "windows_aarch64_msvc 0.36.1", + "windows_i686_gnu 0.36.1", + "windows_i686_msvc 0.36.1", + "windows_x86_64_gnu 0.36.1", + "windows_x86_64_msvc 0.36.1", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", ] +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.5", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" +dependencies = [ + "windows_aarch64_gnullvm 0.52.5", + "windows_aarch64_msvc 0.52.5", + "windows_i686_gnu 0.52.5", + "windows_i686_gnullvm", + "windows_i686_msvc 0.52.5", + "windows_x86_64_gnu 0.52.5", + "windows_x86_64_gnullvm 0.52.5", + "windows_x86_64_msvc 0.52.5", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" + [[package]] name = "windows_aarch64_msvc" version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" + [[package]] name = "windows_i686_gnu" version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" + [[package]] name = "windows_i686_msvc" version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" + [[package]] name = "windows_x86_64_gnu" version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" + [[package]] name = "windows_x86_64_msvc" version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" + +[[package]] +name = "winreg" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a277a57398d4bfa075df44f501a17cfdf8542d224f0d36095a2adc7aee4ef0a5" +dependencies = [ + "cfg-if 1.0.0", + "windows-sys 0.48.0", +] + +[[package]] +name = "xattr" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8da84f1a25939b27f6820d92aed108f83ff920fdf11a7b19366c27c4cda81d4f" +dependencies = [ + "libc", + "linux-raw-sys", + "rustix", +] + [[package]] name = "yaml-rust" version = "0.4.5" @@ -1528,3 +3963,24 @@ checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85" dependencies = [ "linked-hash-map", ] + +[[package]] +name = "yansi" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" + +[[package]] +name = "yansi-term" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe5c30ade05e61656247b2e334a031dfd0cc466fadef865bdcdea8d537951bf1" +dependencies = [ + "winapi", +] + +[[package]] +name = "zeroize" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" diff --git a/kclvm/tools/Cargo.toml b/kclvm/tools/Cargo.toml index c1b9d3a0b..9c09941e3 100644 --- a/kclvm/tools/Cargo.toml +++ b/kclvm/tools/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "kclvm-tools" -version = "0.1.0" +version = "0.11.0" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html @@ -8,10 +8,39 @@ edition = "2021" [dependencies] indexmap = "1.0" fancy-regex = "0.7.1" +walkdir = "2" +anyhow = "1.0" +compiler_base_session = "0.1.3" -kclvm-ast = {path = "../ast", version = "0.1.0"} -kclvm-error = {path = "../error", version = "0.1.0"} -kclvm-parser = {path = "../parser", version = "0.1.0"} +rustc_lexer = "0.1.0" +kclvm-ast = {path = "../ast"} +kclvm-error = {path = "../error"} +kclvm-parser = {path = "../parser"} +kclvm-sema = {path = "../sema"} +kclvm-config = {path = "../config"} +kclvm-ast-pretty = {path = "../ast_pretty"} +kclvm-query = {path = "../query"} +kclvm-runner = {path = "../runner"} +kclvm-runtime = {path = "../runtime"} +kclvm-driver = {path = "../driver"} +kclvm-utils ={ path = "../utils"} + +serde_json = "1.0" +serde_yaml = {path = "../third-party/serde_yaml"} +once_cell = "1.15.0" +regex = "1.3" +json-spanned-value = "0.2.2" +compiler_base_span = "0.1.2" +located_yaml = "0.2.1" [dev-dependencies] pretty_assertions = "1.2.1" +criterion = "0.5" +insta = "1.8.0" + +[[bench]] +name = "benchmark" +harness = false + +[features] +llvm = ["kclvm-runner/llvm"] diff --git a/kclvm/tools/benches/benchmark.rs b/kclvm/tools/benches/benchmark.rs new file mode 100644 index 000000000..e9288ea6e --- /dev/null +++ b/kclvm/tools/benches/benchmark.rs @@ -0,0 +1,109 @@ +use criterion::{criterion_group, criterion_main, Criterion}; +use kclvm_query::override_file; +use kclvm_tools::format::{format, FormatOptions}; +use std::{ + fmt, + time::{Duration, Instant}, +}; + +pub fn criterion_benchmark_override(c: &mut Criterion) { + c.bench_function("override", |b| { + b.iter(|| { + override_file( + "./benches/test_data/simple.k", + &["config.image=\"image/image:v1\"".to_string()], + &["pkg.to.path".to_string()], + ) + .unwrap(); + }) + }); +} + +pub fn criterion_benchmark_format(c: &mut Criterion) { + c.bench_function("format", |b| { + b.iter(|| { + format("./benches/test_data/format.k", &FormatOptions::default()).unwrap(); + }) + }); +} + +criterion_group!( + benches, + criterion_benchmark_override, + criterion_benchmark_format +); +criterion_main!(benches); + +pub struct StopWatch { + time: Instant, +} + +pub struct StopWatchSpan { + pub time: Duration, +} + +impl StopWatch { + pub fn start() -> StopWatch { + let time = Instant::now(); + StopWatch { time } + } + + pub fn elapsed(&mut self) -> StopWatchSpan { + let time = self.time.elapsed(); + + StopWatchSpan { time } + } +} + +impl fmt::Display for StopWatchSpan { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{:.2?}", self.time)?; + Ok(()) + } +} + +/// Utility for writing benchmark tests. +/// +/// If you need to benchmark the entire test, you can directly add the macro `#[bench_test]` like this: +/// ```no_check +/// #[test] +/// #[bench_test] +/// fn benchmark_foo() { +/// actual_work(analysis) +/// } +/// ``` +/// +/// If you need to skip some preparation stages and only test some parts of test, you can use the `bench()` method. +/// A benchmark test looks like this: +/// +/// ```no_check +/// #[test] +/// fn benchmark_foo() { +/// let data = bench_fixture::some_fixture(); +/// let analysis = some_setup(); +/// +/// { +/// let _b = bench("foo"); +/// actual_work(analysis) +/// }; +/// } +/// ``` +/// +/// +pub fn bench(label: &'static str) -> impl Drop { + struct Bencher { + sw: StopWatch, + label: &'static str, + } + + impl Drop for Bencher { + fn drop(&mut self) { + eprintln!("{}: {}", self.label, self.sw.elapsed()); + } + } + + Bencher { + sw: StopWatch::start(), + label, + } +} diff --git a/kclvm/tools/benches/proc_macro_crate/Cargo.toml b/kclvm/tools/benches/proc_macro_crate/Cargo.toml new file mode 100644 index 000000000..a112f709b --- /dev/null +++ b/kclvm/tools/benches/proc_macro_crate/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "proc_macro_crate" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[lib] +proc-macro = true + +[dependencies] +proc-macro2 = "1.0.7" +quote = "1" +syn = { version = "2.0.29", features = ["full","extra-traits"] } diff --git a/kclvm/tools/benches/proc_macro_crate/src/lib.rs b/kclvm/tools/benches/proc_macro_crate/src/lib.rs new file mode 100644 index 000000000..b03050131 --- /dev/null +++ b/kclvm/tools/benches/proc_macro_crate/src/lib.rs @@ -0,0 +1,32 @@ +use proc_macro::TokenStream; +use quote::quote; +use syn::{parse_macro_input, ItemFn}; + +#[proc_macro_attribute] +pub fn bench_test(_attr: TokenStream, item: TokenStream) -> TokenStream { + let mut input_fn = parse_macro_input!(item as ItemFn); + + let fn_name = &input_fn.sig.ident; + let fn_body = &input_fn.block; + + let timing_code = quote! { + { + let start_time = std::time::Instant::now(); + let result = #fn_body; + let end_time = std::time::Instant::now(); + let time = (end_time - start_time).as_micros(); + println!("{} took {} μs", stringify!(#fn_name), (end_time - start_time).as_micros()); + // 400 ms + assert!(time < 400000, "Bench mark test failed"); + result + } + }; + + input_fn.block = Box::new(syn::parse2(timing_code).unwrap()); + + let output = quote! { + #input_fn + }; + + output.into() +} diff --git a/kclvm/tools/benches/test_data/format.k b/kclvm/tools/benches/test_data/format.k new file mode 100644 index 000000000..469dbe5f3 --- /dev/null +++ b/kclvm/tools/benches/test_data/format.k @@ -0,0 +1,10 @@ +schema Data: + id?: int = 0 + value?: str = "value" + +schema Config: + image: str + data?: Data + +config = Config {image = "image/image:v1"} + diff --git a/kclvm/tools/benches/test_data/simple.k b/kclvm/tools/benches/test_data/simple.k new file mode 100644 index 000000000..71b4a59e2 --- /dev/null +++ b/kclvm/tools/benches/test_data/simple.k @@ -0,0 +1,14 @@ +import pkg.to.path +schema Data: + id?: int = 0 + value?: str = "value" + +schema Config: + image: str + data?: Data + +config = Config { + image = "image/image:v1" + data = {id = 1, value = "override_value"} +} + diff --git a/kclvm/tools/src/LSP/Cargo.toml b/kclvm/tools/src/LSP/Cargo.toml new file mode 100644 index 000000000..e3967bb50 --- /dev/null +++ b/kclvm/tools/src/LSP/Cargo.toml @@ -0,0 +1,53 @@ +[package] +name = "kcl-language-server" +version = "0.11.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +chrono = "0.4.19" +indexmap = "1.0" +env_logger = "0.11.2" +ropey = "1.3.2" +tokio-test = "0.4.2" +serde = { version = "1.0", features = ["derive"] } +dashmap = "5.1.0" +log = "0.4.14" +im-rc = "15.0.0" +rustc_lexer = "0.1.0" +clap = { version = "4.3.0", features = ["string"] } +maplit = "1.0.2" + +kclvm-tools = { path = "../../../tools" } +kclvm-error = { path = "../../../error" } +kclvm-config = { path = "../../../config" } +kclvm-driver = { path = "../../../driver" } +kclvm-parser = { path = "../../../parser" } +kclvm-sema = { path = "../../../sema" } +kclvm-ast = { path = "../../../ast" } +kclvm-utils = { path = "../../../utils" } +kclvm-version = { path = "../../../version" } +compiler_base_session = "0.1.3" +kclvm-query = { path = "../../../query" } +kclvm-span = { path = "../../../span" } + +lsp-server = { version = "0.7.7", default-features = false } +anyhow = { version = "1.0", default-features = false, features = ["std"] } +crossbeam-channel = { version = "0.5.7", default-features = false } +ra_ap_vfs = "0.0.149" +ra_ap_vfs-notify = "0.0.149" +lsp-types = { version = "0.93.0", features = ["proposed"] } +threadpool = { version = "1.8.1", default-features = false } +salsa = { version = "0.16.1", default-features = false } +serde_json = { version = "1.0", default-features = false } +parking_lot = { version = "0.12.0", default-features = false } +rustc-hash = { version = "1.1.0", default-features = false } +proc_macro_crate = { path = "../../benches/proc_macro_crate" } +notify = "7.0.0" + +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +tokio = { version = "1.37.0", features = ["full"] } + +[dev-dependencies] +insta = "1.8.0" diff --git a/kclvm/tools/src/LSP/src/analysis.rs b/kclvm/tools/src/LSP/src/analysis.rs new file mode 100644 index 000000000..fbcef2258 --- /dev/null +++ b/kclvm/tools/src/LSP/src/analysis.rs @@ -0,0 +1,42 @@ +use indexmap::{IndexMap, IndexSet}; +use kclvm_ast::ast::Program; +use kclvm_driver::WorkSpaceKind; +use kclvm_error::Diagnostic; +use kclvm_sema::{core::global_state::GlobalState, ty::SchemaType}; +use parking_lot::RwLock; +use std::{ + collections::{HashMap, HashSet}, + sync::Arc, +}; + +pub type DocumentVersion = i32; + +#[derive(Default, Clone)] +pub struct OpenFileInfo { + pub version: DocumentVersion, + pub workspaces: HashSet, +} + +/// Analysis holds the analysis mapping (FileId -> AnalysisDatabase) +#[derive(Default)] +pub struct Analysis { + pub workspaces: Arc>>, +} + +#[derive(Clone)] +pub enum DBState { + Ready(Arc), + // The previous version of db + Compiling(Arc), + Init, + Failed(String), +} + +/// AnalysisDatabase holds the result of the compile +#[derive(Default, Clone)] +pub struct AnalysisDatabase { + pub prog: Program, + pub gs: GlobalState, + pub diags: IndexSet, + pub schema_map: IndexMap>, +} diff --git a/kclvm/tools/src/LSP/src/app.rs b/kclvm/tools/src/LSP/src/app.rs new file mode 100644 index 000000000..0e57011c6 --- /dev/null +++ b/kclvm/tools/src/LSP/src/app.rs @@ -0,0 +1,20 @@ +use crate::state::LanguageServerState; +use clap::{builder::Str, Command}; +use lsp_server::Connection; +use lsp_types::InitializeParams; + +/// Runs the main loop of the language server. This will receive requests and handle them. +pub fn main_loop( + connection: Connection, + initialize_params: InitializeParams, +) -> anyhow::Result<()> { + LanguageServerState::new(connection.sender, initialize_params).run(connection.receiver) +} + +/// Get the kcl language server CLI application. +pub fn app() -> Command { + Command::new("kcl-language-server") + .version(Str::from(kclvm_version::get_version_info())) + .about("KCL language server CLI.") + .subcommand(Command::new("version").about("Show the KCL language server version")) +} diff --git a/kclvm/tools/src/LSP/src/capabilities.rs b/kclvm/tools/src/LSP/src/capabilities.rs new file mode 100644 index 000000000..f7c0c65a1 --- /dev/null +++ b/kclvm/tools/src/LSP/src/capabilities.rs @@ -0,0 +1,75 @@ +use lsp_types::{ + ClientCapabilities, CodeActionKind, CodeActionOptions, CodeActionProviderCapability, + CompletionOptions, HoverProviderCapability, OneOf, SemanticTokensFullOptions, + SemanticTokensLegend, SemanticTokensOptions, ServerCapabilities, SignatureHelpOptions, + TextDocumentSyncCapability, TextDocumentSyncKind, WorkDoneProgressOptions, +}; + +use crate::semantic_token::LEGEND_TYPE; + +/// Returns the capabilities of this LSP server implementation given the capabilities of the client. +pub fn server_capabilities(client_caps: &ClientCapabilities) -> ServerCapabilities { + ServerCapabilities { + text_document_sync: Some(TextDocumentSyncCapability::Kind(TextDocumentSyncKind::FULL)), + semantic_tokens_provider: Some( + lsp_types::SemanticTokensServerCapabilities::SemanticTokensOptions( + SemanticTokensOptions { + work_done_progress_options: WorkDoneProgressOptions::default(), + legend: SemanticTokensLegend { + token_types: LEGEND_TYPE.into(), + token_modifiers: vec![], + }, + range: Some(false), + full: Some(SemanticTokensFullOptions::Bool(true)), + }, + ), + ), + document_symbol_provider: Some(OneOf::Left(true)), + completion_provider: Some(CompletionOptions { + resolve_provider: None, + trigger_characters: Some(vec![ + String::from("."), + String::from("="), + String::from(":"), + String::from("\n"), + ]), + all_commit_characters: None, + work_done_progress_options: WorkDoneProgressOptions { + work_done_progress: None, + }, + completion_item: None, + }), + hover_provider: Some(HoverProviderCapability::Simple(true)), + definition_provider: Some(OneOf::Left(true)), + code_action_provider: Some( + client_caps + .text_document + .as_ref() + .and_then(|it| it.code_action.as_ref()) + .and_then(|it| it.code_action_literal_support.as_ref()) + .map_or(CodeActionProviderCapability::Simple(true), |_| { + CodeActionProviderCapability::Options(CodeActionOptions { + // Advertise support for all built-in CodeActionKinds. + // Ideally we would base this off of the client capabilities + // but the client is supposed to fall back gracefully for unknown values. + code_action_kinds: Some(vec![CodeActionKind::QUICKFIX]), + resolve_provider: None, + work_done_progress_options: Default::default(), + }) + }), + ), + document_formatting_provider: Some(OneOf::Left(true)), + document_range_formatting_provider: Some(OneOf::Left(true)), + references_provider: Some(OneOf::Left(true)), + rename_provider: Some(OneOf::Left(true)), + inlay_hint_provider: Some(lsp_types::OneOf::Left(true)), + signature_help_provider: Some(SignatureHelpOptions { + trigger_characters: Some(vec!["(".to_owned(), ",".to_owned()]), + retrigger_characters: None, + work_done_progress_options: WorkDoneProgressOptions { + work_done_progress: None, + }, + }), + ..Default::default() + } +} diff --git a/kclvm/tools/src/LSP/src/compile.rs b/kclvm/tools/src/LSP/src/compile.rs new file mode 100644 index 000000000..3bfc02ff6 --- /dev/null +++ b/kclvm/tools/src/LSP/src/compile.rs @@ -0,0 +1,182 @@ +use indexmap::{IndexMap, IndexSet}; +use kclvm_ast::ast::Program; +use kclvm_driver::{lookup_compile_workspace, toolchain}; +use kclvm_error::Diagnostic; +use kclvm_parser::{ + entry::get_normalized_k_files_from_paths, load_all_files_under_paths, KCLModuleCache, + LoadProgramOptions, ParseSessionRef, +}; +use kclvm_query::query::filter_pkg_schemas; +use kclvm_sema::{ + advanced_resolver::AdvancedResolver, + core::global_state::GlobalState, + namer::Namer, + resolver::{resolve_program_with_opts, scope::KCLScopeCache}, + ty::SchemaType, +}; +use std::collections::HashSet; +use std::path::PathBuf; + +use crate::{ + state::{KCLGlobalStateCache, KCLVfs}, + util::load_files_code_from_vfs, +}; + +pub struct Params { + pub file: Option, + pub module_cache: Option, + pub scope_cache: Option, + pub vfs: Option, + pub gs_cache: Option, +} + +pub fn compile( + params: Params, + files: &mut [String], + opts: Option, +) -> ( + IndexSet, + anyhow::Result<(Program, IndexMap>, GlobalState)>, +) { + // Ignore the kcl plugin sematic check. + let mut opts = opts.unwrap_or_default(); + opts.load_plugins = true; + // Get input files code from vfs + let normalized_files = match get_normalized_k_files_from_paths(files, &opts) { + Ok(file_list) => file_list, + Err(e) => { + return ( + IndexSet::new(), + Err(anyhow::anyhow!("Compile failed: {:?}", e)), + ) + } + }; + let normalized_files: Vec<&str> = normalized_files.iter().map(|s| s.as_str()).collect(); + // Update opt.k_code_list + if let Some(vfs) = ¶ms.vfs { + let mut k_code_list = match load_files_code_from_vfs(&normalized_files, vfs) { + Ok(code_list) => code_list, + Err(e) => { + return ( + IndexSet::new(), + Err(anyhow::anyhow!("Compile failed: {:?}", e)), + ) + } + }; + opts.k_code_list.append(&mut k_code_list); + } + let mut diags = IndexSet::new(); + + let files: Vec<&str> = files.iter().map(|s| s.as_str()).collect(); + + // Parser + let sess = ParseSessionRef::default(); + + // update cache + if params.file.is_some() && params.module_cache.is_some() { + match &mut params.module_cache.clone().unwrap().write() { + Ok(module_cache) => { + let path = PathBuf::from(params.file.clone().unwrap()); + module_cache.clear(&path); + if let Some(vfs) = ¶ms.vfs { + if let Ok(code_list) = + load_files_code_from_vfs(&[¶ms.file.clone().unwrap()], vfs) + { + module_cache.source_code.insert(path, code_list[0].clone()); + }; + } + } + Err(e) => { + return ( + diags, + Err(anyhow::anyhow!( + "Failed to get module cache RwLock: {:?}", + e + )), + ) + } + } + } + + let mut program = + match load_all_files_under_paths(sess.clone(), &files, Some(opts), params.module_cache) { + Ok(r) => r.program, + Err(e) => return (diags, Err(anyhow::anyhow!("Parse failed: {:?}", e))), + }; + diags.extend(sess.1.read().diagnostics.clone()); + + // Resolver + if let Some(cached_scope) = params.scope_cache.as_ref() { + if let Some(file) = ¶ms.file { + if let Some(mut cached_scope) = cached_scope.try_write() { + let mut invalidate_pkg_modules = HashSet::new(); + invalidate_pkg_modules.insert(file.clone()); + cached_scope.invalidate_pkg_modules = Some(invalidate_pkg_modules); + } + } + } + + let prog_scope = resolve_program_with_opts( + &mut program, + kclvm_sema::resolver::Options { + merge_program: false, + type_erasure: false, + ..Default::default() + }, + params.scope_cache.clone(), + ); + let schema_map: IndexMap> = filter_pkg_schemas(&prog_scope, None, None); + diags.extend(prog_scope.handler.diagnostics); + + let mut default = GlobalState::default(); + let mut gs_ref; + + let gs = match ¶ms.gs_cache { + Some(cache) => match cache.try_lock() { + Ok(locked_state) => { + gs_ref = locked_state; + &mut gs_ref + } + Err(_) => &mut default, + }, + None => &mut default, + }; + + gs.new_or_invalidate_pkgs = match ¶ms.scope_cache { + Some(cache) => match cache.try_write() { + Some(scope) => scope.invalidate_pkgs.clone(), + None => HashSet::new(), + }, + None => HashSet::new(), + }; + + gs.new_or_invalidate_pkgs + .extend(program.pkgs_not_imported.keys().map(|n| n.clone())); + + gs.clear_cache(); + + Namer::find_symbols(&program, gs); + + match AdvancedResolver::resolve_program(&program, gs, prog_scope.node_ty_map) { + Ok(_) => (diags, Ok((program, schema_map, gs.clone()))), + Err(e) => (diags, Err(anyhow::anyhow!("Resolve failed: {:?}", e))), + } +} + +#[allow(unused)] +pub fn compile_with_params( + params: Params, +) -> ( + IndexSet, + anyhow::Result<(Program, IndexMap>, GlobalState)>, +) { + let file = PathBuf::from(params.file.clone().unwrap()) + .canonicalize() + .unwrap() + .to_str() + .unwrap() + .to_string(); + // Lookup compile workspace from the cursor file. + let (mut files, opts, _) = lookup_compile_workspace(&toolchain::default(), &file, true); + compile(params, &mut files, opts) +} diff --git a/kclvm/tools/src/LSP/src/completion.rs b/kclvm/tools/src/LSP/src/completion.rs new file mode 100644 index 000000000..83f763f09 --- /dev/null +++ b/kclvm/tools/src/LSP/src/completion.rs @@ -0,0 +1,2323 @@ +//! Complete for KCL +//! Now supports code completion in trigger mode (triggered when user enters `.`, `:` and `=`), schema attr and global variables +//! and the content of the completion includes: +//! + variable +//! + schema attr name +//! + dot(.) +//! + import path +//! + schema attr +//! + builtin function(str function) +//! + definitions in pkg +//! + system module functions +//! + assign(=, :) +//! + schema attr value +//! + variable value +//! + new line +//! + schema init + +use crate::goto_def::{find_def, find_symbol}; +use crate::to_lsp::lsp_pos; +use indexmap::{IndexMap, IndexSet}; +use kclvm_ast::ast::{self, ImportStmt, Program, Stmt}; +use kclvm_ast::MAIN_PKG; +use kclvm_config::modfile::KCL_FILE_EXTENSION; +use kclvm_driver::toolchain::{get_real_path_from_external, Metadata, Toolchain}; +use kclvm_error::diagnostic::Range; +use kclvm_parser::get_kcl_files; +use kclvm_sema::core::global_state::GlobalState; +use std::io; +use std::{fs, path::Path}; + +use kclvm_error::Position as KCLPos; +use kclvm_sema::builtin::{BUILTIN_FUNCTIONS, STANDARD_SYSTEM_MODULES}; +use kclvm_sema::core::package::ModuleInfo; +use kclvm_sema::core::scope::{LocalSymbolScopeKind, ScopeKind}; +use kclvm_sema::core::symbol::SymbolKind; +use kclvm_sema::resolver::doc::{parse_schema_doc_string, SchemaDoc}; +use kclvm_sema::ty::{FunctionType, SchemaType, Type, TypeKind}; +use kclvm_utils::path::PathPrefix; +use lsp_types::{CompletionItem, CompletionItemKind, InsertTextFormat}; + +use crate::util::{inner_most_expr_in_stmt, is_in_docstring}; + +#[derive(Debug, Clone, PartialEq, Hash, Eq)] +pub enum KCLCompletionItemKind { + Function, + Variable, + File, + Dir, + Schema, + SchemaAttr, + Module, + Doc, +} + +impl From for CompletionItemKind { + fn from(val: KCLCompletionItemKind) -> Self { + match val { + KCLCompletionItemKind::Function => CompletionItemKind::FUNCTION, + KCLCompletionItemKind::Variable => CompletionItemKind::VARIABLE, + KCLCompletionItemKind::File => CompletionItemKind::FILE, + KCLCompletionItemKind::Schema => CompletionItemKind::CLASS, + KCLCompletionItemKind::SchemaAttr => CompletionItemKind::FIELD, + KCLCompletionItemKind::Module => CompletionItemKind::MODULE, + KCLCompletionItemKind::Dir => CompletionItemKind::FOLDER, + KCLCompletionItemKind::Doc => CompletionItemKind::SNIPPET, + } + } +} + +#[derive(Debug, Clone, PartialEq, Hash, Eq, Default)] +pub struct TextEdit { + pub range: Range, + pub new_text: String, +} + +/// Abstraction of CompletionItem in KCL +#[derive(Debug, Clone, PartialEq, Hash, Eq, Default)] +pub(crate) struct KCLCompletionItem { + pub label: String, + pub detail: Option, + pub documentation: Option, + pub kind: Option, + pub insert_text: Option, + pub additional_text_edits: Option>, +} + +/// Computes completions at the given position. +pub fn completion( + trigger_character: Option, + program: &Program, + pos: &KCLPos, + gs: &GlobalState, + tool: &dyn Toolchain, + metadata: Option, + schema_map: &IndexMap>, +) -> Option { + match trigger_character { + Some(c) => match c { + '.' => completion_dot(program, pos, gs, tool), + '=' | ':' => completion_assign(pos, gs), + '\n' => completion_newline(program, pos, gs), + _ => None, + }, + None => { + let mut completions: IndexSet = IndexSet::new(); + // Complete builtin pkgs if in import stmt + completions.extend(completion_import_stmt(program, pos, metadata)); + if !completions.is_empty() { + return Some(into_completion_items(&completions).into()); + } + + // Complete import pkgs name + if let Some(pkg_info) = gs.get_packages().get_module_info(&pos.filename) { + completions.extend(pkg_info.get_imports().keys().map(|key| KCLCompletionItem { + label: key.clone(), + detail: None, + documentation: None, + kind: Some(KCLCompletionItemKind::Module), + insert_text: None, + additional_text_edits: None, + })); + } + + if let Some(scope) = gs.look_up_scope(pos) { + // Complete builtin functions in root scope and lambda + match scope.get_kind() { + kclvm_sema::core::scope::ScopeKind::Local => { + if let Some(local_scope) = gs.get_scopes().try_get_local_scope(&scope) { + match local_scope.get_kind() { + kclvm_sema::core::scope::LocalSymbolScopeKind::Lambda => { + completions.extend(BUILTIN_FUNCTIONS.iter().map( + |(name, ty)| KCLCompletionItem { + label: func_ty_complete_label( + name, + &ty.into_func_type(), + ), + detail: Some( + ty.into_func_type().func_signature_str(name), + ), + documentation: ty.ty_doc(), + kind: Some(KCLCompletionItemKind::Function), + insert_text: Some(func_ty_complete_insert_text( + name, + &ty.into_func_type(), + )), + additional_text_edits: None, + }, + )); + } + _ => {} + } + } + } + kclvm_sema::core::scope::ScopeKind::Root => { + completions.extend(BUILTIN_FUNCTIONS.iter().map(|(name, ty)| { + KCLCompletionItem { + label: func_ty_complete_label(name, &ty.into_func_type()), + detail: Some(ty.into_func_type().func_signature_str(name)), + documentation: ty.ty_doc(), + kind: Some(KCLCompletionItemKind::Function), + insert_text: Some(func_ty_complete_insert_text( + name, + &ty.into_func_type(), + )), + additional_text_edits: None, + } + })); + // Complete all schema def in gs if in main pkg + if program.get_main_files().contains(&pos.filename) { + completions.extend(unimport_schemas(&pos.filename, gs, schema_map)); + } + } + } + + // Complete all usable symbol obj in inner most scope + if let Some(defs) = gs.get_all_defs_in_scope(scope, pos) { + for symbol_ref in defs { + match gs.get_symbols().get_symbol(symbol_ref) { + Some(def) => { + let sema_info = def.get_sema_info(); + let name = def.get_name(); + match &sema_info.ty { + Some(ty) => match symbol_ref.get_kind() { + SymbolKind::Schema => { + let schema_ty = ty.into_schema_type(); + // complete schema type + completions.insert(schema_ty_to_type_complete_item( + &schema_ty, + )); + // complete schema value + completions.insert(schema_ty_to_value_complete_item( + &schema_ty, true, + )); + } + SymbolKind::Package => { + completions.insert(KCLCompletionItem { + label: name, + detail: Some(ty.ty_str()), + documentation: sema_info.doc.clone(), + kind: Some(KCLCompletionItemKind::Module), + insert_text: None, + additional_text_edits: None, + }); + } + _ => { + let detail = match &ty.kind { + TypeKind::Function(func_ty) => { + func_ty.func_signature_str(&name) + } + _ => ty.ty_str(), + }; + completions.insert(KCLCompletionItem { + label: name, + detail: Some(detail), + documentation: sema_info.doc.clone(), + kind: type_to_item_kind(ty), + insert_text: None, + additional_text_edits: None, + }); + } + }, + None => {} + } + } + None => {} + } + } + } + } + + Some(into_completion_items(&completions).into()) + } + } +} + +fn completion_dot( + program: &Program, + pos: &KCLPos, + gs: &GlobalState, + tool: &dyn Toolchain, +) -> Option { + let mut items: IndexSet = IndexSet::new(); + + // get pre position of trigger character '.' + let pre_pos = KCLPos { + filename: pos.filename.clone(), + line: pos.line, + column: pos.column.map(|c| if c >= 1 { c - 1 } else { 0 }), + }; + + if let Some(stmt) = program.pos_to_stmt(&pre_pos) { + match stmt.node { + Stmt::Import(stmt) => return dot_completion_in_import_stmt(&stmt, pos, program, tool), + _ => { + let (expr, _) = inner_most_expr_in_stmt(&stmt.node, pos, None); + if let Some(node) = expr { + match node.node { + // if the complete trigger character in string, skip it + ast::Expr::StringLit(_) | ast::Expr::JoinedString(_) => { + return Some(into_completion_items(&items).into()) + } + _ => {} + } + } + } + } + } + + // look_up_exact_symbol + let mut symbol = find_symbol(&pre_pos, gs, true); + if symbol.is_none() { + symbol = find_symbol(pos, gs, false); + } + let def = match symbol { + Some(symbol_ref) => { + if let SymbolKind::Unresolved = symbol_ref.get_kind() { + let unresolved_symbol = gs.get_symbols().get_unresolved_symbol(symbol_ref).unwrap(); + if unresolved_symbol.is_type() { + return Some(into_completion_items(&items).into()); + } + } + match gs.get_symbols().get_symbol(symbol_ref) { + Some(symbol) => symbol.get_definition(), + None => None, + } + } + None => None, + }; + + match def { + Some(def_ref) => { + if let Some(def) = gs.get_symbols().get_symbol(def_ref) { + let module_info = gs.get_packages().get_module_info(&pos.filename); + let attrs = def.get_all_attributes(gs.get_symbols(), module_info); + for attr in attrs { + let attr_def = gs.get_symbols().get_symbol(attr); + if let Some(attr_def) = attr_def { + let sema_info = attr_def.get_sema_info(); + let name = attr_def.get_name(); + match &sema_info.ty { + Some(attr_ty) => { + let label: String = match &attr_ty.kind { + TypeKind::Function(func_ty) => { + func_ty_complete_label(&name, func_ty) + } + _ => name.clone(), + }; + let insert_text = match &attr_ty.kind { + TypeKind::Function(func_ty) => { + Some(func_ty_complete_insert_text(&name, func_ty)) + } + _ => None, + }; + let kind = match &def.get_sema_info().ty { + Some(symbol_ty) => match &symbol_ty.kind { + TypeKind::Schema(_) => { + Some(KCLCompletionItemKind::SchemaAttr) + } + _ => type_to_item_kind(attr_ty), + }, + None => type_to_item_kind(attr_ty), + }; + let documentation = match &sema_info.doc { + Some(doc) => { + if doc.is_empty() { + None + } else { + Some(doc.clone()) + } + } + None => None, + }; + items.insert(KCLCompletionItem { + label, + detail: Some(format!("{}: {}", name, attr_ty.ty_str())), + documentation, + kind, + insert_text, + additional_text_edits: None, + }); + } + None => { + items.insert(KCLCompletionItem { + label: name, + detail: None, + documentation: None, + kind: None, + insert_text: None, + additional_text_edits: None, + }); + } + } + } + } + } + } + None => {} + } + Some(into_completion_items(&items).into()) +} + +/// Get completion items for trigger '=' or ':' +/// Now, just completion for schema attr value +fn completion_assign(pos: &KCLPos, gs: &GlobalState) -> Option { + let mut items = IndexSet::new(); + if let Some(symbol_ref) = find_def(pos, gs, false) { + if let Some(symbol) = gs.get_symbols().get_symbol(symbol_ref) { + if let Some(def) = symbol.get_definition() { + match def.get_kind() { + SymbolKind::Attribute => { + let sema_info = symbol.get_sema_info(); + match &sema_info.ty { + Some(ty) => { + items.extend( + ty_complete_label_and_inser_text( + ty, + gs.get_packages().get_module_info(&pos.filename), + ) + .iter() + .map( + |(label, insert_text)| KCLCompletionItem { + label: format!(" {}", label), + detail: Some(format!( + "{}: {}", + symbol.get_name(), + ty.ty_str() + )), + kind: Some(KCLCompletionItemKind::Variable), + documentation: sema_info.doc.clone(), + insert_text: Some(format!(" {}", insert_text)), + additional_text_edits: None, + }, + ), + ); + return Some(into_completion_items(&items).into()); + } + None => {} + } + } + _ => {} + } + } + } + } + None +} + +fn completion_newline( + program: &Program, + pos: &KCLPos, + gs: &GlobalState, +) -> Option { + let mut completions: IndexSet = IndexSet::new(); + + if let Some((doc, schema)) = is_in_docstring(program, pos) { + let doc = parse_schema_doc_string(&doc.node); + if doc.summary.is_empty() && doc.attrs.is_empty() && doc.examples.is_empty() { + // empty docstring, provide total completion + let doc_parsed = SchemaDoc::new_from_schema_stmt(&schema); + let label = doc_parsed.to_doc_string(); + // generate docstring from doc + completions.insert(KCLCompletionItem { + label, + detail: Some("generate docstring".to_string()), + documentation: Some(format!("docstring for {}", schema.name.node.clone())), + kind: Some(KCLCompletionItemKind::Doc), + insert_text: None, + additional_text_edits: None, + }); + } + return Some(into_completion_items(&completions).into()); + } + + // Complete schema attr when input newline in schema + if let Some(scope) = gs.look_up_scope(pos) { + if let ScopeKind::Local = scope.get_kind() { + if let Some(locol_scope) = gs.get_scopes().try_get_local_scope(&scope) { + if let LocalSymbolScopeKind::Config = locol_scope.get_kind() { + if let Some(defs) = gs.get_defs_within_scope(scope, pos) { + for symbol_ref in defs { + match gs.get_symbols().get_symbol(symbol_ref) { + Some(def) => { + let sema_info = def.get_sema_info(); + let name = def.get_name(); + match symbol_ref.get_kind() { + SymbolKind::Attribute => { + completions.insert(KCLCompletionItem { + label: name.clone(), + detail: sema_info + .ty + .as_ref() + .map(|ty| format!("{}: {}", name, ty.ty_str())), + documentation: match &sema_info.doc { + Some(doc) => { + if doc.is_empty() { + None + } else { + Some(doc.clone()) + } + } + None => None, + }, + kind: Some(KCLCompletionItemKind::SchemaAttr), + insert_text: None, + additional_text_edits: None, + }); + } + _ => {} + } + } + None => {} + } + } + } + } + } + } + } + + Some(into_completion_items(&completions).into()) +} + +fn completion_import_stmt( + program: &Program, + pos: &KCLPos, + metadata: Option, +) -> IndexSet { + let mut completions: IndexSet = IndexSet::new(); + // completion position not contained in import stmt + // import + // | | | <- input `m` here for complete `math` + // |<----------->| <- import stmt only contains this range, so we need to check the beginning of line + let line_start_pos = &KCLPos { + filename: pos.filename.clone(), + line: pos.line, + column: Some(0), + }; + + if let Some(node) = program.pos_to_stmt(line_start_pos) { + if let Stmt::Import(_) = node.node { + completions.extend(completion_import_builtin_pkg()); + completions.extend(completion_import_internal_pkg(program, line_start_pos)); + completions.extend(completion_import_external_pkg(metadata)); + } + } + completions +} + +fn completion_import_builtin_pkg() -> IndexSet { + STANDARD_SYSTEM_MODULES + .iter() + .map(|s| KCLCompletionItem { + label: s.to_string(), + detail: None, + documentation: None, + kind: Some(KCLCompletionItemKind::Module), + insert_text: None, + additional_text_edits: None, + }) + .collect() +} + +fn completion_import_internal_pkg( + program: &Program, + line_start_pos: &KCLPos, +) -> IndexSet { + let mut completions: IndexSet = IndexSet::new(); + if let Ok(entries) = fs::read_dir(program.root.clone()) { + for entry in entries { + if let Ok(entry) = entry { + if let Ok(file_type) = entry.file_type() { + // internal pkgs + if file_type.is_dir() { + if let Ok(files) = get_kcl_files(entry.path(), true) { + // skip folder if without kcl file + if files.is_empty() { + continue; + } + } else { + continue; + } + if let Some(name) = entry.file_name().to_str() { + completions.insert(KCLCompletionItem { + label: name.to_string(), + detail: None, + documentation: None, + kind: Some(KCLCompletionItemKind::Dir), + insert_text: None, + additional_text_edits: None, + }); + } + } else { + // internal module + let path = entry.path(); + if path.to_str().unwrap_or("").adjust_canonicalization() + == line_start_pos.filename.adjust_canonicalization() + { + continue; + } + if let Some(extension) = path.extension() { + if extension == KCL_FILE_EXTENSION { + if let Some(name) = path.file_stem() { + if let Some(name) = name.to_str() { + completions.insert(KCLCompletionItem { + label: name.to_string(), + detail: None, + documentation: None, + kind: Some(KCLCompletionItemKind::Module), + insert_text: None, + additional_text_edits: None, + }); + } + } + } + } + } + } + } + } + } + completions +} + +fn completion_import_external_pkg(metadata: Option) -> IndexSet { + match metadata { + Some(metadata) => metadata + .packages + .keys() + .map(|name| KCLCompletionItem { + label: name.to_string(), + detail: None, + documentation: None, + kind: Some(KCLCompletionItemKind::Dir), + insert_text: None, + additional_text_edits: None, + }) + .collect(), + None => IndexSet::new(), + } +} + +/// Complete schema value +/// +/// ```no_check +/// #[cfg(not(test))] +/// p = P +/// ``` +/// complete to +/// ```no_check +/// #[cfg(not(test))] +/// import pkg +/// p = pkg.Person(param1, param2){} +/// ``` +fn schema_ty_to_value_complete_item(schema_ty: &SchemaType, has_import: bool) -> KCLCompletionItem { + let schema = schema_ty.clone(); + let param = schema_ty.func.params.clone(); + let pkg_path_last_name = if schema.pkgpath.is_empty() || schema.pkgpath == MAIN_PKG { + "".to_string() + } else { + format!("{}", schema.pkgpath.split('.').last().unwrap()) + }; + let need_import = !pkg_path_last_name.is_empty() && !has_import; + + let label = format!( + "{}{}{}{}", + schema.name, + if param.is_empty() { + "".to_string() + } else { + format!( + "({})", + param + .iter() + .map(|p| p.name.clone()) + .collect::>() + .join(", ") + ) + }, + "{}", + if need_import { + format!("(import {})", schema.pkgpath) + } else { + "".to_string() + }, + ); + + // `pkg_path.schema_name{}` or `schema_name{}` + let insert_text = format!( + "{}{}{}{}{}", + pkg_path_last_name, + if pkg_path_last_name.is_empty() { + "" + } else { + "." + }, + schema.name, + if param.is_empty() { + "".to_string() + } else { + format!( + "({})", + param + .iter() + .enumerate() + .map(|(idx, p)| format!("${{{}:{}}}", idx + 1, p.name.clone())) + .collect::>() + .join(", ") + ) + }, + "{$0}" + ); + + // insert `import pkg` + let additional_text_edits = if need_import { + Some(vec![TextEdit { + range: (KCLPos::dummy_pos(), KCLPos::dummy_pos()), + new_text: format!("import {}\n", schema.pkgpath), + }]) + } else { + None + }; + + let detail = { + let mut details = vec![]; + let (pkgpath, rest_sign) = schema_ty.schema_ty_signature_str(); + details.push(format!("{}\n\n{}", pkgpath, rest_sign)); + details.push("Attributes:".to_string()); + for (name, attr) in &schema_ty.attrs { + details.push(format!( + "{}{}: {}", + name, + if attr.is_optional { "?" } else { "" }, + attr.ty.ty_str(), + )); + } + details.join("\n") + }; + + KCLCompletionItem { + label, + detail: Some(detail), + documentation: Some(schema_ty.doc.clone()), + kind: Some(KCLCompletionItemKind::Schema), + insert_text: Some(insert_text), + additional_text_edits, + } +} + +/// Complete schema type +/// +/// ```no_check +/// #[cfg(not(test))] +/// p: P +/// ``` +/// complete to +/// ```no_check +/// #[cfg(not(test))] +/// p: Person +/// ``` +fn schema_ty_to_type_complete_item(schema_ty: &SchemaType) -> KCLCompletionItem { + let detail = { + let mut details = vec![]; + let (pkgpath, rest_sign) = schema_ty.schema_ty_signature_str(); + details.push(format!("{}\n\n{}", pkgpath, rest_sign)); + details.push("Attributes:".to_string()); + for (name, attr) in &schema_ty.attrs { + details.push(format!( + "{}{}: {}", + name, + if attr.is_optional { "?" } else { "" }, + attr.ty.ty_str(), + )); + } + details.join("\n") + }; + KCLCompletionItem { + label: schema_ty.name.clone(), + detail: Some(detail), + documentation: Some(schema_ty.doc.clone()), + kind: Some(KCLCompletionItemKind::Schema), + insert_text: None, + additional_text_edits: None, + } +} + +fn dot_completion_in_import_stmt( + stmt: &ImportStmt, + _pos: &KCLPos, + program: &Program, + tool: &dyn Toolchain, +) -> Option { + let mut items: IndexSet = IndexSet::new(); + let pkgpath = &stmt.path.node; + let mut real_path = + Path::new(&program.root).join(pkgpath.replace('.', std::path::MAIN_SEPARATOR_STR)); + if !real_path.exists() { + real_path = + get_real_path_from_external(tool, &stmt.pkg_name, pkgpath, program.root.clone().into()); + } + if real_path.is_dir() { + if let Ok(entries) = fs::read_dir(real_path) { + let mut entries = entries + .map(|res| res.map(|e| e.path())) + .collect::, io::Error>>() + .unwrap(); + entries.sort(); + for path in entries { + let filename = path.file_name().unwrap().to_str().unwrap().to_string(); + if path.is_dir() { + items.insert(KCLCompletionItem { + label: filename, + detail: None, + documentation: None, + kind: Some(KCLCompletionItemKind::Dir), + insert_text: None, + additional_text_edits: None, + }); + } else if path.is_file() { + if let Some(extension) = path.extension() { + if extension == KCL_FILE_EXTENSION { + items.insert(KCLCompletionItem { + label: path + .with_extension("") + .file_name() + .unwrap() + .to_str() + .unwrap() + .to_string(), + detail: None, + documentation: None, + kind: Some(KCLCompletionItemKind::File), + insert_text: None, + additional_text_edits: None, + }); + } + } + } + } + } + } + Some(into_completion_items(&items).into()) +} + +fn ty_complete_label_and_inser_text( + ty: &Type, + module: Option<&ModuleInfo>, +) -> Vec<(String, String)> { + match &ty.kind { + TypeKind::Bool => vec![ + ("True".to_string(), "True".to_string()), + ("False".to_string(), "False".to_string()), + ], + TypeKind::BoolLit(b) => { + vec![if *b { + ("True".to_string(), "True".to_string()) + } else { + ("False".to_string(), "False".to_string()) + }] + } + TypeKind::IntLit(i) => vec![(i.to_string(), i.to_string())], + TypeKind::FloatLit(f) => vec![(f.to_string(), f.to_string())], + TypeKind::Str => vec![(r#""""#.to_string(), r#""""#.to_string())], + TypeKind::StrLit(s) => vec![(format!("{:?}", s), format!("{:?}", s))], + TypeKind::List(_) => vec![("[]".to_string(), "[$1]".to_string())], + TypeKind::Dict(_) => vec![("{}".to_string(), "{$1}".to_string())], + TypeKind::Union(types) => types + .iter() + .flat_map(|ty| ty_complete_label_and_inser_text(ty, module)) + .collect(), + TypeKind::Schema(schema) => { + vec![( + format!( + "{}{}{}", + if schema.pkgpath.is_empty() || schema.pkgpath == MAIN_PKG { + "".to_string() + } else if let Some(m) = module { + format!("{}.", pkg_real_name(&schema.pkgpath, m)) + } else { + format!("{}.", schema.pkgpath.split('.').last().unwrap()) + }, + schema.name, + "{}" + ), + "{$1}".to_string(), // `$1`` is used to determine the cursor position after completion + )] + } + _ => vec![], + } +} + +/// get pkg_path real name: as_name if not none or pkg last name +fn pkg_real_name(pkg: &String, module: &ModuleInfo) -> String { + let imports = module.get_imports(); + for (name, import_info) in imports { + if &import_info.get_fully_qualified_name() == pkg { + return name; + } + } + pkg.split('.').last().unwrap().to_string() +} + +fn func_ty_complete_label(func_name: &String, _func_type: &FunctionType) -> String { + format!("{}(…)", func_name,) +} + +fn func_ty_complete_insert_text(func_name: &String, func_type: &FunctionType) -> String { + format!( + "{}({})", + func_name, + func_type + .params + .iter() + .enumerate() + .map(|(idx, param)| format!("${{{}:{}}}", idx + 1, param.name.clone())) + .collect::>() + .join(", "), + ) +} +fn type_to_item_kind(ty: &Type) -> Option { + match ty.kind { + TypeKind::Bool + | TypeKind::BoolLit(_) + | TypeKind::Int + | TypeKind::IntLit(_) + | TypeKind::Float + | TypeKind::FloatLit(_) + | TypeKind::Str + | TypeKind::StrLit(_) + | TypeKind::List(_) + | TypeKind::Dict(_) + | TypeKind::Union(_) + | TypeKind::NumberMultiplier(_) + | TypeKind::Named(_) => Some(KCLCompletionItemKind::Variable), + TypeKind::Schema(_) => Some(KCLCompletionItemKind::Schema), + TypeKind::Function(_) => Some(KCLCompletionItemKind::Function), + TypeKind::Module(_) => Some(KCLCompletionItemKind::Module), + TypeKind::Void | TypeKind::None | TypeKind::Any => None, + } +} + +pub(crate) fn into_completion_items(items: &IndexSet) -> Vec { + items + .iter() + .map(|item| { + let additional_text_edits = match &item.additional_text_edits { + Some(edits) => { + let mut res = vec![]; + for edit in edits { + res.push(lsp_types::TextEdit { + range: lsp_types::Range { + start: lsp_pos(&edit.range.0), + end: lsp_pos(&edit.range.1), + }, + new_text: edit.new_text.clone(), + }) + } + + Some(res) + } + None => None, + }; + + CompletionItem { + label: item.label.clone(), + detail: item.detail.clone(), + documentation: item + .documentation + .clone() + .map(lsp_types::Documentation::String), + kind: item.kind.clone().map(|kind| kind.into()), + insert_text: item.insert_text.clone(), + insert_text_format: if item.insert_text.is_some() { + Some(InsertTextFormat::SNIPPET) + } else { + None + }, + additional_text_edits, + + ..Default::default() + } + }) + .collect() +} + +fn unimport_schemas( + filename: &str, + gs: &GlobalState, + schema_map: &IndexMap>, +) -> IndexSet { + let module = gs.get_packages().get_module_info(filename); + let mut completions: IndexSet = IndexSet::new(); + for (_, schemas) in schema_map { + for schema in schemas { + let has_import = match module { + Some(m) => m + .get_imports() + .iter() + .any(|(_, info)| info.get_fully_qualified_name() == schema.pkgpath), + None => false, + }; + if schema.pkgpath != MAIN_PKG { + completions.insert(schema_ty_to_value_complete_item(&schema, has_import)); + } + } + } + completions +} + +#[cfg(test)] +mod tests { + use crate::{ + completion::{ + completion, func_ty_complete_insert_text, func_ty_complete_label, + into_completion_items, KCLCompletionItem, KCLCompletionItemKind, + }, + tests::{compile_test_file, compile_test_file_and_metadata}, + }; + use indexmap::IndexSet; + use kclvm_driver::toolchain; + use kclvm_error::Position as KCLPos; + use kclvm_sema::builtin::{ + BUILTIN_FUNCTIONS, MATH_FUNCTION_TYPES, STANDARD_SYSTEM_MODULES, STRING_MEMBER_FUNCTIONS, + }; + use lsp_types::{CompletionItem, CompletionItemKind, CompletionResponse, InsertTextFormat}; + use proc_macro_crate::bench_test; + + #[test] + #[bench_test] + fn var_completion_test() { + let (file, program, _, gs, schema_map) = + compile_test_file("src/test_data/completion_test/dot/completion/completion.k"); + + // test completion for var + let pos = KCLPos { + filename: file.to_owned(), + line: 26, + column: Some(1), + }; + + let tool = toolchain::default(); + let got = completion(None, &program, &pos, &gs, &tool, None, &schema_map).unwrap(); + let mut got_labels: Vec = match got { + CompletionResponse::Array(arr) => arr.iter().map(|item| item.label.clone()).collect(), + CompletionResponse::List(_) => panic!("test failed"), + }; + + let mut expected_labels: Vec = vec![ + "", // generate from error recovery of "pkg." + "subpkg", + "math", + "Person", + "Person1{}", + "Person{}", + "P", + "P{}", + "p", + "p1", + "p2", + "p3", + "p4", + "aaaa", + "Config", + "Config{}", + "n", + ] + .iter() + .map(|s| s.to_string()) + .collect(); + + expected_labels.extend( + BUILTIN_FUNCTIONS + .iter() + .map(|(name, func)| func_ty_complete_label(name, &func.into_func_type())), + ); + got_labels.sort(); + expected_labels.sort(); + + assert_eq!(got_labels, expected_labels); + + // test completion for schema attr + let pos = KCLPos { + filename: file.to_owned(), + line: 24, + column: Some(4), + }; + + let got = completion(None, &program, &pos, &gs, &tool, None, &schema_map).unwrap(); + let mut got_labels: Vec = match got { + CompletionResponse::Array(arr) => arr.iter().map(|item| item.label.clone()).collect(), + CompletionResponse::List(_) => panic!("test failed"), + }; + + expected_labels = ["", "age", "math", "name", "subpkg"] + .iter() + .map(|s| s.to_string()) + .collect(); + got_labels.sort(); + expected_labels.sort(); + assert_eq!(got_labels, expected_labels); + } + + #[test] + #[bench_test] + fn dot_completion_test() { + let (file, program, _, gs, schema_map) = + compile_test_file("src/test_data/completion_test/dot/completion/completion.k"); + + // test completion for schema attr + let pos = KCLPos { + filename: file.to_owned(), + line: 12, + column: Some(7), + }; + + let tool = toolchain::default(); + let got = completion(Some('.'), &program, &pos, &gs, &tool, None, &schema_map).unwrap(); + let got_labels: Vec = match got { + CompletionResponse::Array(arr) => arr.iter().map(|item| item.label.clone()).collect(), + CompletionResponse::List(_) => panic!("test failed"), + }; + + let expected_labels: Vec<&str> = vec!["name", "age"]; + assert_eq!(got_labels, expected_labels); + + let pos = KCLPos { + filename: file.to_owned(), + line: 14, + column: Some(12), + }; + + // test completion for str builtin function + let got = completion(Some('.'), &program, &pos, &gs, &tool, None, &schema_map).unwrap(); + let got_labels: Vec = match &got { + CompletionResponse::Array(arr) => arr.iter().map(|item| item.label.clone()).collect(), + CompletionResponse::List(_) => panic!("test failed"), + }; + let expected_labels: Vec = STRING_MEMBER_FUNCTIONS + .iter() + .map(|(name, ty)| func_ty_complete_label(name, &ty.into_func_type())) + .collect(); + assert_eq!(got_labels, expected_labels); + + let got_insert_text: Vec = match &got { + CompletionResponse::Array(arr) => arr + .iter() + .map(|item| item.insert_text.clone().unwrap()) + .collect(), + CompletionResponse::List(_) => panic!("test failed"), + }; + let expected_insert_text: Vec = STRING_MEMBER_FUNCTIONS + .iter() + .map(|(name, ty)| func_ty_complete_insert_text(name, &ty.into_func_type())) + .collect(); + assert_eq!(got_insert_text, expected_insert_text); + + // test completion for import pkg path + let pos = KCLPos { + filename: file.to_owned(), + line: 1, + column: Some(12), + }; + + let got = completion(Some('.'), &program, &pos, &gs, &tool, None, &schema_map).unwrap(); + let got_labels: Vec = match got { + CompletionResponse::Array(arr) => arr.iter().map(|item| item.label.clone()).collect(), + CompletionResponse::List(_) => panic!("test failed"), + }; + + let expected_labels: Vec<&str> = vec!["file1", "file2", "subpkg"]; + assert_eq!(got_labels, expected_labels); + + // test completion for import pkg' schema + let pos = KCLPos { + filename: file.to_owned(), + line: 16, + column: Some(12), + }; + + let got = completion(Some('.'), &program, &pos, &gs, &tool, None, &schema_map).unwrap(); + let got_labels: Vec = match got { + CompletionResponse::Array(arr) => arr.iter().map(|item| item.label.clone()).collect(), + CompletionResponse::List(_) => panic!("test failed"), + }; + + let expected_labels: Vec<&str> = vec!["Person1"]; + assert_eq!(got_labels, expected_labels); + + let pos = KCLPos { + filename: file.to_owned(), + line: 19, + column: Some(5), + }; + let got = completion(Some('.'), &program, &pos, &gs, &tool, None, &schema_map).unwrap(); + let got_labels: Vec = match got { + CompletionResponse::Array(arr) => arr.iter().map(|item| item.label.clone()).collect(), + CompletionResponse::List(_) => panic!("test failed"), + }; + let expected_labels: Vec = MATH_FUNCTION_TYPES + .iter() + .map(|(name, ty)| func_ty_complete_label(name, &ty.into_func_type())) + .collect(); + assert_eq!(got_labels, expected_labels); + + // test completion for literal str builtin function + let pos = KCLPos { + filename: file.clone(), + line: 21, + column: Some(4), + }; + + let got = completion(Some('.'), &program, &pos, &gs, &tool, None, &schema_map).unwrap(); + let got_labels: Vec = match got { + CompletionResponse::Array(arr) => arr.iter().map(|item| item.label.clone()).collect(), + CompletionResponse::List(_) => panic!("test failed"), + }; + + let expected_labels: Vec = STRING_MEMBER_FUNCTIONS + .iter() + .map(|(name, ty)| func_ty_complete_label(name, &ty.into_func_type())) + .collect(); + assert_eq!(got_labels, expected_labels); + + let pos = KCLPos { + filename: file.clone(), + line: 30, + column: Some(11), + }; + + let got = completion(Some('.'), &program, &pos, &gs, &tool, None, &schema_map).unwrap(); + let got_labels: Vec = match got { + CompletionResponse::Array(arr) => arr.iter().map(|item| item.label.clone()).collect(), + CompletionResponse::List(_) => panic!("test failed"), + }; + + let expected_labels: Vec<&str> = vec!["a"]; + assert_eq!(got_labels, expected_labels); + + // test completion for string union type + let pos = KCLPos { + filename: file.clone(), + line: 36, + column: Some(30), + }; + + let got = completion(Some('.'), &program, &pos, &gs, &tool, None, &schema_map).unwrap(); + let got_labels: Vec = match got { + CompletionResponse::Array(arr) => arr.iter().map(|item| item.label.clone()).collect(), + CompletionResponse::List(_) => panic!("test failed"), + }; + + let expected_labels: Vec = STRING_MEMBER_FUNCTIONS + .iter() + .map(|(name, ty)| func_ty_complete_label(name, &ty.into_func_type())) + .collect(); + assert_eq!(got_labels, expected_labels); + } + + #[test] + #[bench_test] + fn dot_completion_test_without_dot() { + let (file, program, _, gs, schema_map) = + compile_test_file("src/test_data/completion_test/without_dot/completion.k"); + + // test completion for schema attr + let pos = KCLPos { + filename: file.to_owned(), + line: 12, + column: Some(7), + }; + + let tool = toolchain::default(); + let got = completion(Some('.'), &program, &pos, &gs, &tool, None, &schema_map).unwrap(); + let got_labels: Vec = match got { + CompletionResponse::Array(arr) => arr.iter().map(|item| item.label.clone()).collect(), + CompletionResponse::List(_) => panic!("test failed"), + }; + + let expected_labels: Vec<&str> = vec!["name", "age"]; + assert_eq!(got_labels, expected_labels); + + let pos = KCLPos { + filename: file.to_owned(), + line: 14, + column: Some(12), + }; + + // test completion for str builtin function + let got = completion(Some('.'), &program, &pos, &gs, &tool, None, &schema_map).unwrap(); + let got_labels: Vec = match got { + CompletionResponse::Array(arr) => arr.iter().map(|item| item.label.clone()).collect(), + CompletionResponse::List(_) => panic!("test failed"), + }; + let expected_labels: Vec = STRING_MEMBER_FUNCTIONS + .iter() + .map(|(name, ty)| func_ty_complete_label(name, &ty.into_func_type())) + .collect(); + assert_eq!(got_labels, expected_labels); + + // test completion for import pkg path + let pos = KCLPos { + filename: file.to_owned(), + line: 1, + column: Some(12), + }; + + let got = completion(Some('.'), &program, &pos, &gs, &tool, None, &schema_map).unwrap(); + let got_labels: Vec = match got { + CompletionResponse::Array(arr) => arr.iter().map(|item| item.label.clone()).collect(), + CompletionResponse::List(_) => panic!("test failed"), + }; + + let expected_labels: Vec<&str> = vec!["file1", "file2", "subpkg"]; + assert_eq!(got_labels, expected_labels); + + // test completion for import pkg' schema + let pos = KCLPos { + filename: file.to_owned(), + line: 16, + column: Some(12), + }; + + let got = completion(Some('.'), &program, &pos, &gs, &tool, None, &schema_map).unwrap(); + let got_labels: Vec = match got { + CompletionResponse::Array(arr) => arr.iter().map(|item| item.label.clone()).collect(), + CompletionResponse::List(_) => panic!("test failed"), + }; + + let expected_labels: Vec<&str> = vec!["Person1"]; + assert_eq!(got_labels, expected_labels); + + let pos = KCLPos { + filename: file.to_owned(), + line: 19, + column: Some(5), + }; + let got = completion(Some('.'), &program, &pos, &gs, &tool, None, &schema_map).unwrap(); + let got_labels: Vec = match &got { + CompletionResponse::Array(arr) => arr.iter().map(|item| item.label.clone()).collect(), + CompletionResponse::List(_) => panic!("test failed"), + }; + let expected_labels: Vec = MATH_FUNCTION_TYPES + .iter() + .map(|(name, ty)| func_ty_complete_label(name, &ty.into_func_type())) + .collect(); + assert_eq!(got_labels, expected_labels); + + let got_insert_text: Vec = match &got { + CompletionResponse::Array(arr) => arr + .iter() + .map(|item| item.insert_text.clone().unwrap()) + .collect(), + CompletionResponse::List(_) => panic!("test failed"), + }; + let expected_insert_text: Vec = MATH_FUNCTION_TYPES + .iter() + .map(|(name, ty)| func_ty_complete_insert_text(name, &ty.into_func_type())) + .collect(); + assert_eq!(got_insert_text, expected_insert_text); + + // test completion for literal str builtin function + let pos = KCLPos { + filename: file.clone(), + line: 21, + column: Some(4), + }; + + let got = completion(Some('.'), &program, &pos, &gs, &tool, None, &schema_map).unwrap(); + let got_labels: Vec = match &got { + CompletionResponse::Array(arr) => arr.iter().map(|item| item.label.clone()).collect(), + CompletionResponse::List(_) => panic!("test failed"), + }; + + let expected_labels: Vec = STRING_MEMBER_FUNCTIONS + .iter() + .map(|(name, ty)| func_ty_complete_label(name, &ty.into_func_type())) + .collect(); + assert_eq!(got_labels, expected_labels); + + let got_insert_text: Vec = match &got { + CompletionResponse::Array(arr) => arr + .iter() + .map(|item| item.insert_text.clone().unwrap()) + .collect(), + CompletionResponse::List(_) => panic!("test failed"), + }; + let expected_insert_text: Vec = STRING_MEMBER_FUNCTIONS + .iter() + .map(|(name, ty)| func_ty_complete_insert_text(name, &ty.into_func_type())) + .collect(); + assert_eq!(got_insert_text, expected_insert_text); + + let pos = KCLPos { + filename: file.clone(), + line: 30, + column: Some(11), + }; + + let got = completion(Some('.'), &program, &pos, &gs, &tool, None, &schema_map).unwrap(); + let got_labels: Vec = match got { + CompletionResponse::Array(arr) => arr.iter().map(|item| item.label.clone()).collect(), + CompletionResponse::List(_) => panic!("test failed"), + }; + + let expected_labels: Vec<&str> = vec!["a"]; + assert_eq!(got_labels, expected_labels); + + // test completion for str union types + let pos = KCLPos { + filename: file.clone(), + line: 36, + column: Some(30), + }; + + let got = completion(Some('.'), &program, &pos, &gs, &tool, None, &schema_map).unwrap(); + let got_labels: Vec = match &got { + CompletionResponse::Array(arr) => arr.iter().map(|item| item.label.clone()).collect(), + CompletionResponse::List(_) => panic!("test failed"), + }; + + let expected_labels: Vec = STRING_MEMBER_FUNCTIONS + .iter() + .map(|(name, ty)| func_ty_complete_label(name, &ty.into_func_type())) + .collect(); + assert_eq!(got_labels, expected_labels); + + let got_insert_text: Vec = match &got { + CompletionResponse::Array(arr) => arr + .iter() + .map(|item| item.insert_text.clone().unwrap()) + .collect(), + CompletionResponse::List(_) => panic!("test failed"), + }; + let expected_insert_text: Vec = STRING_MEMBER_FUNCTIONS + .iter() + .map(|(name, ty)| func_ty_complete_insert_text(name, &ty.into_func_type())) + .collect(); + assert_eq!(got_insert_text, expected_insert_text); + } + + #[test] + #[bench_test] + fn import_builtin_package() { + let (file, program, _, gs, schema_map) = + compile_test_file("src/test_data/completion_test/import/builtin/builtin_pkg.k"); + let mut items: IndexSet = IndexSet::new(); + + // test completion for builtin packages + let pos = KCLPos { + filename: file.to_owned(), + line: 1, + column: Some(8), + }; + + let tool = toolchain::default(); + let got = completion(None, &program, &pos, &gs, &tool, None, &schema_map).unwrap(); + let _got_labels: Vec = match &got { + CompletionResponse::Array(arr) => arr.iter().map(|item| item.label.clone()).collect(), + CompletionResponse::List(_) => panic!("test failed"), + }; + items.extend( + [ + "collection", + "net", + "manifests", + "math", + "datetime", + "regex", + "yaml", + "json", + "crypto", + "base64", + "units", + "file", + "template", + "runtime", + ] + .iter() + .map(|name| KCLCompletionItem { + label: name.to_string(), + kind: Some(KCLCompletionItemKind::Module), + detail: None, + documentation: None, + insert_text: None, + additional_text_edits: None, + }) + .collect::>(), + ); + let expect: CompletionResponse = into_completion_items(&items).into(); + assert_eq!(got, expect); + } + + #[test] + #[bench_test] + fn attr_value_completion() { + let (file, program, _, gs, schema_map) = + compile_test_file("src/test_data/completion_test/assign/completion.k"); + + let pos = KCLPos { + filename: file.to_owned(), + line: 14, + column: Some(6), + }; + + let tool = toolchain::default(); + let got = completion(Some(':'), &program, &pos, &gs, &tool, None, &schema_map).unwrap(); + let got_labels: Vec = match got { + CompletionResponse::Array(arr) => arr.iter().map(|item| item.label.clone()).collect(), + CompletionResponse::List(_) => panic!("test failed"), + }; + let expected_labels: Vec<&str> = vec![" True", " False"]; + assert_eq!(got_labels, expected_labels); + + let pos = KCLPos { + filename: file.to_owned(), + line: 16, + column: Some(6), + }; + let got = completion(Some(':'), &program, &pos, &gs, &tool, None, &schema_map).unwrap(); + let got_labels: Vec = match got { + CompletionResponse::Array(arr) => arr.iter().map(|item| item.label.clone()).collect(), + CompletionResponse::List(_) => panic!("test failed"), + }; + let expected_labels: Vec<&str> = vec![" \"abc\"", " \"def\""]; + assert_eq!(got_labels, expected_labels); + + let pos = KCLPos { + filename: file.to_owned(), + line: 18, + column: Some(6), + }; + let got = completion(Some(':'), &program, &pos, &gs, &tool, None, &schema_map).unwrap(); + let got_labels: Vec = match got { + CompletionResponse::Array(arr) => arr.iter().map(|item| item.label.clone()).collect(), + CompletionResponse::List(_) => panic!("test failed"), + }; + let expected_labels: Vec<&str> = vec![" []"]; + assert_eq!(got_labels, expected_labels); + + let pos = KCLPos { + filename: file.to_owned(), + line: 20, + column: Some(6), + }; + let got = completion(Some(':'), &program, &pos, &gs, &tool, None, &schema_map).unwrap(); + let got_labels: Vec = match got { + CompletionResponse::Array(arr) => arr.iter().map(|item| item.label.clone()).collect(), + CompletionResponse::List(_) => panic!("test failed"), + }; + let expected_labels: Vec<&str> = vec![" 1"]; + assert_eq!(got_labels, expected_labels); + + let pos = KCLPos { + filename: file.to_owned(), + line: 22, + column: Some(6), + }; + let got = completion(Some(':'), &program, &pos, &gs, &tool, None, &schema_map).unwrap(); + let got_labels: Vec = match got { + CompletionResponse::Array(arr) => arr.iter().map(|item| item.label.clone()).collect(), + CompletionResponse::List(_) => panic!("test failed"), + }; + let expected_labels: Vec<&str> = vec![" True"]; + assert_eq!(got_labels, expected_labels); + + let pos = KCLPos { + filename: file.to_owned(), + line: 24, + column: Some(6), + }; + let got = completion(Some(':'), &program, &pos, &gs, &tool, None, &schema_map).unwrap(); + let got_labels: Vec = match got { + CompletionResponse::Array(arr) => arr.iter().map(|item| item.label.clone()).collect(), + CompletionResponse::List(_) => panic!("test failed"), + }; + let expected_labels: Vec<&str> = vec![" {}"]; + assert_eq!(got_labels, expected_labels); + + let pos = KCLPos { + filename: file.to_owned(), + line: 26, + column: Some(6), + }; + let got = completion(Some(':'), &program, &pos, &gs, &tool, None, &schema_map).unwrap(); + let got_labels: Vec = match &got { + CompletionResponse::Array(arr) => arr.iter().map(|item| item.label.clone()).collect(), + CompletionResponse::List(_) => panic!("test failed"), + }; + let expected_labels: Vec<&str> = vec![" sub.Person1{}"]; + assert_eq!(got_labels, expected_labels); + + let got_insert_test: Vec = match &got { + CompletionResponse::Array(arr) => arr + .iter() + .map(|item| item.clone().insert_text.unwrap().clone()) + .collect(), + CompletionResponse::List(_) => panic!("test failed"), + }; + let expected_insert_test: Vec<&str> = vec![" {$1}"]; + assert_eq!(got_insert_test, expected_insert_test); + } + + #[test] + #[bench_test] + fn schema_sig_completion() { + let (file, program, _, gs, schema_map) = + compile_test_file("src/test_data/completion_test/schema/schema/schema.k"); + + let pos = KCLPos { + filename: file.to_owned(), + line: 7, + column: Some(5), + }; + + let tool = toolchain::default(); + let mut got = completion(None, &program, &pos, &gs, &tool, None, &schema_map).unwrap(); + match &mut got { + CompletionResponse::Array(arr) => { + assert_eq!( + arr.iter().find(|item| item.label == "Person(b){}").unwrap(), + &CompletionItem { + label: "Person(b){}".to_string(), + kind: Some(CompletionItemKind::CLASS), + detail: Some( + "__main__\n\nschema Person[b: int](Base):\nAttributes:\nc: int" + .to_string() + ), + documentation: Some(lsp_types::Documentation::String("".to_string())), + insert_text: Some("Person(${1:b}){$0}".to_string()), + insert_text_format: Some(InsertTextFormat::SNIPPET), + ..Default::default() + } + ) + } + CompletionResponse::List(_) => panic!("test failed"), + } + } + + #[test] + fn schema_docstring_newline_completion() { + let (file, program, _, gs, schema_map) = + compile_test_file("src/test_data/completion_test/newline/docstring_newline.k"); + + let pos = KCLPos { + filename: file.to_owned(), + line: 3, + column: Some(4), + }; + let tool = toolchain::default(); + let mut got = + completion(Some('\n'), &program, &pos, &gs, &tool, None, &schema_map).unwrap(); + match &mut got { + CompletionResponse::Array(arr) => { + arr.sort_by(|a, b| a.label.cmp(&b.label)); + assert_eq!( + arr[0], + CompletionItem { + label: "\n\nAttributes\n----------\nname: \nworkloadType: \nreplica: \n\nExamples\n--------\n".to_string(), + detail: Some("generate docstring".to_string()), + kind: Some(CompletionItemKind::SNIPPET), + documentation: Some(lsp_types::Documentation::String("docstring for Server".to_string())), + ..Default::default() + } + ) + } + CompletionResponse::List(_) => panic!("test failed"), + } + } + + #[test] + fn str_dot_completion() { + let (file, program, _, gs, schema_map) = + compile_test_file("src/test_data/completion_test/dot/lit_str/lit_str.k"); + + // test complete str functions when at the end of literal str + let pos = KCLPos { + filename: file.to_owned(), + line: 1, + column: Some(10), + }; + + let tool = toolchain::default(); + let got = completion(Some('.'), &program, &pos, &gs, &tool, None, &schema_map).unwrap(); + + match &got { + CompletionResponse::Array(arr) => { + assert!(arr + .iter() + .all(|item| item.kind == Some(CompletionItemKind::FUNCTION))) + } + CompletionResponse::List(_) => panic!("test failed"), + }; + + let got_labels: Vec = match &got { + CompletionResponse::Array(arr) => arr.iter().map(|item| item.label.clone()).collect(), + CompletionResponse::List(_) => panic!("test failed"), + }; + + let expected_labels: Vec = STRING_MEMBER_FUNCTIONS + .iter() + .map(|(name, ty)| func_ty_complete_label(name, &ty.into_func_type())) + .collect(); + assert_eq!(got_labels, expected_labels); + + let got_insert_text: Vec = match &got { + CompletionResponse::Array(arr) => arr + .iter() + .map(|item| item.insert_text.clone().unwrap()) + .collect(), + CompletionResponse::List(_) => panic!("test failed"), + }; + let expected_insert_text: Vec = STRING_MEMBER_FUNCTIONS + .iter() + .map(|(name, ty)| func_ty_complete_insert_text(name, &ty.into_func_type())) + .collect(); + assert_eq!(got_insert_text, expected_insert_text); + + let pos = KCLPos { + filename: file.to_owned(), + line: 2, + column: Some(6), + }; + + let got = completion(Some('.'), &program, &pos, &gs, &tool, None, &schema_map).unwrap(); + let got_labels: Vec = match got { + CompletionResponse::Array(arr) => arr.iter().map(|item| item.label.clone()).collect(), + CompletionResponse::List(_) => panic!("test failed"), + }; + assert_eq!(got_labels, expected_labels); + + // not complete inside literal str + let pos = KCLPos { + filename: file.to_owned(), + line: 2, + column: Some(5), + }; + + let got = completion(Some('.'), &program, &pos, &gs, &tool, None, &schema_map).unwrap(); + match got { + CompletionResponse::Array(arr) => assert!(arr.is_empty()), + CompletionResponse::List(_) => panic!("test failed"), + }; + + // not complete inside literal str + let pos = KCLPos { + filename: file.to_owned(), + line: 1, + column: Some(8), + }; + + let got = completion(Some('.'), &program, &pos, &gs, &tool, None, &schema_map).unwrap(); + match got { + CompletionResponse::Array(arr) => assert!(arr.is_empty()), + CompletionResponse::List(_) => panic!("test failed"), + }; + + let pos = KCLPos { + filename: file.to_owned(), + line: 3, + column: Some(2), + }; + let got = completion(Some('.'), &program, &pos, &gs, &tool, None, &schema_map).unwrap(); + match got { + CompletionResponse::Array(arr) => { + assert!(arr + .iter() + .all(|item| item.kind == Some(CompletionItemKind::FUNCTION))) + } + CompletionResponse::List(_) => panic!("test failed"), + }; + } + + #[test] + fn schema_ty_attr_complete() { + let (file, program, _, gs, schema_map) = + compile_test_file("src/test_data/completion_test/dot/schema_ty_attr/schema_ty_attr.k"); + + let pos = KCLPos { + filename: file.to_owned(), + line: 13, + column: Some(2), + }; + + let tool = toolchain::default(); + let got = completion(Some('.'), &program, &pos, &gs, &tool, None, &schema_map).unwrap(); + match got { + CompletionResponse::Array(arr) => { + assert_eq!( + arr[0], + CompletionItem { + label: "name".to_string(), + detail: Some("name: Name".to_string()), + kind: Some(CompletionItemKind::FIELD), + ..Default::default() + } + ) + } + CompletionResponse::List(_) => panic!("test failed"), + } + } + + #[test] + fn schema_end_pos() { + let (file, program, _, gs, schema_map) = + compile_test_file("src/test_data/completion_test/schema/schema_pos/schema_pos.k"); + + let pos = KCLPos { + filename: file.to_owned(), + line: 6, + column: Some(16), + }; + + let tool = toolchain::default(); + let got = completion(None, &program, &pos, &gs, &tool, None, &schema_map).unwrap(); + match got { + CompletionResponse::Array(arr) => { + assert_eq!(arr.len(), 4); + let labels: Vec = arr.iter().map(|item| item.label.clone()).collect(); + assert!(labels.contains(&"min".to_string())); + assert!(labels.contains(&"max".to_string())); + } + CompletionResponse::List(_) => panic!("test failed"), + } + } + + #[test] + fn comment_completion() { + let (file, program, _, gs, schema_map) = + compile_test_file("src/test_data/completion_test/dot/lit_str/lit_str.k"); + + let pos = KCLPos { + filename: file.to_owned(), + line: 4, + column: Some(4), + }; + + let tool = toolchain::default(); + let got = completion(Some('.'), &program, &pos, &gs, &tool, None, &schema_map).unwrap(); + + match &got { + CompletionResponse::Array(arr) => { + assert_eq!(arr.len(), 0) + } + CompletionResponse::List(_) => panic!("test failed"), + }; + } + + #[test] + #[bench_test] + fn missing_expr_completion() { + let (file, program, _, gs, schema_map) = + compile_test_file("src/test_data/completion_test/dot/missing_expr/missing_expr.k"); + + let pos = KCLPos { + filename: file.to_owned(), + line: 10, + column: Some(16), + }; + + let tool = toolchain::default(); + let got = completion(Some('.'), &program, &pos, &gs, &tool, None, &schema_map).unwrap(); + match got { + CompletionResponse::Array(arr) => { + assert_eq!(arr.len(), 2); + let labels: Vec = arr.iter().map(|item| item.label.clone()).collect(); + assert!(labels.contains(&"cpu".to_string())); + assert!(labels.contains(&"memory".to_string())); + } + CompletionResponse::List(_) => panic!("test failed"), + } + } + + #[test] + #[bench_test] + fn check_scope_completion() { + let (file, program, _, gs, schema_map) = + compile_test_file("src/test_data/completion_test/check/check.k"); + + let pos = KCLPos { + filename: file.to_owned(), + line: 4, + column: Some(10), + }; + + let tool = toolchain::default(); + let got = completion(Some(':'), &program, &pos, &gs, &tool, None, &schema_map); + assert!(got.is_none()); + + let pos = KCLPos { + filename: file.to_owned(), + line: 5, + column: Some(9), + }; + + let got = completion(None, &program, &pos, &gs, &tool, None, &schema_map).unwrap(); + match got { + CompletionResponse::Array(arr) => { + assert_eq!(arr.len(), 3); + let labels: Vec = arr.iter().map(|item| item.label.clone()).collect(); + assert!(labels.contains(&"name".to_string())); + } + CompletionResponse::List(_) => panic!("test failed"), + } + } + + #[test] + #[bench_test] + fn join_str_inner_completion() { + let (file, program, _, gs, schema_map) = + compile_test_file("src/test_data/completion_test/dot/lit_str/lit_str.k"); + + let pos = KCLPos { + filename: file.to_owned(), + line: 6, + column: Some(28), + }; + + let tool = toolchain::default(); + let got = completion(Some('.'), &program, &pos, &gs, &tool, None, &schema_map).unwrap(); + match &got { + CompletionResponse::Array(arr) => { + assert!(arr.is_empty()) + } + CompletionResponse::List(_) => panic!("test failed"), + } + + let pos = KCLPos { + filename: file.to_owned(), + line: 7, + column: Some(27), + }; + + let tool = toolchain::default(); + let got = completion(Some('.'), &program, &pos, &gs, &tool, None, &schema_map).unwrap(); + match &got { + CompletionResponse::Array(arr) => { + assert!(arr.is_empty()) + } + CompletionResponse::List(_) => panic!("test failed"), + } + } + + #[test] + #[bench_test] + fn schema_type_attr_completion() { + let (file, program, _, gs, schema_map) = + compile_test_file("src/test_data/completion_test/schema/schema/schema.k"); + + let pos = KCLPos { + filename: file.to_owned(), + line: 18, + column: Some(15), + }; + + let tool = toolchain::default(); + let mut got = completion(None, &program, &pos, &gs, &tool, None, &schema_map).unwrap(); + match &mut got { + CompletionResponse::Array(arr) => { + let labels: Vec = arr.iter().map(|item| item.label.clone()).collect(); + assert!(labels.contains(&"name".to_string())); + } + CompletionResponse::List(_) => panic!("test failed"), + } + + let pos = KCLPos { + filename: file.to_owned(), + line: 19, + column: Some(21), + }; + + let tool = toolchain::default(); + let mut got = completion(None, &program, &pos, &gs, &tool, None, &schema_map).unwrap(); + match &mut got { + CompletionResponse::Array(arr) => { + let labels: Vec = arr.iter().map(|item| item.label.clone()).collect(); + assert!(labels.contains(&"name".to_string())); + } + CompletionResponse::List(_) => panic!("test failed"), + } + } + + #[test] + #[bench_test] + fn nested_1_test() { + let (file, program, _, gs, schema_map) = + compile_test_file("src/test_data/completion_test/dot/nested/nested_1/nested_1.k"); + + let pos = KCLPos { + filename: file.to_owned(), + line: 9, + column: Some(9), + }; + let tool = toolchain::default(); + + let mut got = completion(None, &program, &pos, &gs, &tool, None, &schema_map).unwrap(); + + match &mut got { + CompletionResponse::Array(arr) => { + let labels: Vec = arr.iter().map(|item| item.label.clone()).collect(); + insta::assert_snapshot!(format!("{:?}", labels)); + } + CompletionResponse::List(_) => panic!("test failed"), + } + } + + #[test] + #[bench_test] + fn nested_2_test() { + let (file, program, _, gs, schema_map) = + compile_test_file("src/test_data/completion_test/dot/nested/nested_2/nested_2.k"); + + let pos = KCLPos { + filename: file.to_owned(), + line: 9, + column: Some(9), + }; + + let tool = toolchain::default(); + + let mut got = completion(None, &program, &pos, &gs, &tool, None, &schema_map).unwrap(); + + match &mut got { + CompletionResponse::Array(arr) => { + let labels: Vec = arr.iter().map(|item| item.label.clone()).collect(); + insta::assert_snapshot!(format!("{:?}", labels)); + } + CompletionResponse::List(_) => panic!("test failed"), + } + } + #[test] + #[bench_test] + fn nested_3_test() { + let (file, program, _, gs, schema_map) = + compile_test_file("src/test_data/completion_test/dot/nested/nested_3/nested_3.k"); + + let pos = KCLPos { + filename: file.to_owned(), + line: 10, + column: Some(13), + }; + + let tool = toolchain::default(); + let mut got = completion(None, &program, &pos, &gs, &tool, None, &schema_map).unwrap(); + + match &mut got { + CompletionResponse::Array(arr) => { + let labels: Vec = arr.iter().map(|item| item.label.clone()).collect(); + insta::assert_snapshot!(format!("{:?}", labels)); + } + CompletionResponse::List(_) => panic!("test failed"), + } + } + + #[test] + #[bench_test] + fn nested_4_test() { + let (file, program, _, gs, schema_map) = + compile_test_file("src/test_data/completion_test/dot/nested/nested_4/nested_4.k"); + + let pos = KCLPos { + filename: file.to_owned(), + line: 9, + column: Some(9), + }; + + let tool = toolchain::default(); + + let mut got = completion(None, &program, &pos, &gs, &tool, None, &schema_map).unwrap(); + + match &mut got { + CompletionResponse::Array(arr) => { + let labels: Vec = arr.iter().map(|item| item.label.clone()).collect(); + insta::assert_snapshot!(format!("{:?}", labels)); + } + CompletionResponse::List(_) => panic!("test failed"), + } + } + + #[macro_export] + macro_rules! completion_label_test_snapshot { + ($name:ident, $file:expr, $line:expr, $column: expr, $trigger: expr) => { + #[test] + fn $name() { + let (file, program, _, gs, schema_map) = compile_test_file($file); + + let pos = KCLPos { + filename: file.clone(), + line: $line, + column: Some($column), + }; + let tool = toolchain::default(); + + let mut got = + completion($trigger, &program, &pos, &gs, &tool, None, &schema_map).unwrap(); + + let got_labels = match &mut got { + CompletionResponse::Array(arr) => { + let mut labels: Vec = + arr.iter().map(|item| item.label.clone()).collect(); + labels.sort(); + labels + } + CompletionResponse::List(_) => panic!("test failed"), + }; + insta::assert_snapshot!(format!("{:?}", got_labels)); + } + }; + } + + #[macro_export] + macro_rules! completion_label_without_builtin_func_test_snapshot { + ($name:ident, $file:expr, $line:expr, $column: expr, $trigger: expr) => { + #[test] + fn $name() { + let (file, program, _, gs, schema_map) = compile_test_file($file); + + let pos = KCLPos { + filename: file.clone(), + line: $line, + column: Some($column), + }; + let tool = toolchain::default(); + + let mut got = + completion($trigger, &program, &pos, &gs, &tool, None, &schema_map).unwrap(); + + let got_labels = match &mut got { + CompletionResponse::Array(arr) => { + let mut labels: Vec = + arr.iter().map(|item| item.label.clone()).collect(); + labels.sort(); + let builtin_func_lables: Vec = BUILTIN_FUNCTIONS + .iter() + .map(|(name, func)| { + func_ty_complete_label(name, &func.into_func_type()) + }) + .collect(); + let labels: Vec = labels + .iter() + .filter(|label| !builtin_func_lables.contains(label)) + .map(|label| label.clone()) + .collect(); + + labels + } + CompletionResponse::List(_) => panic!("test failed"), + }; + insta::assert_snapshot!(format!("{:?}", got_labels)); + } + }; + } + + #[macro_export] + macro_rules! completion_label_without_system_pkg_test_snapshot { + ($name:ident, $file:expr, $line:expr, $column: expr, $trigger: expr) => { + #[test] + fn $name() { + let (file, program, _, gs, metadata, schema_map) = + compile_test_file_and_metadata($file); + let pos = KCLPos { + filename: file.clone(), + line: $line, + column: Some($column), + }; + let tool = toolchain::default(); + let mut got = + completion($trigger, &program, &pos, &gs, &tool, metadata, &schema_map) + .unwrap(); + let got_labels = match &mut got { + CompletionResponse::Array(arr) => { + let mut labels: Vec = + arr.iter().map(|item| item.label.clone()).collect(); + labels.sort(); + let labels: Vec = labels + .iter() + .filter(|label| !STANDARD_SYSTEM_MODULES.contains(&label.as_str())) + .cloned() + .collect(); + + labels + } + CompletionResponse::List(_) => panic!("test failed"), + }; + insta::assert_snapshot!(format!("{:?}", got_labels)); + } + }; + } + + completion_label_without_builtin_func_test_snapshot!( + lambda_1, + "src/test_data/completion_test/lambda/lambda_1/lambda_1.k", + 8, + 5, + None + ); + + completion_label_without_builtin_func_test_snapshot!( + schema_attr_newline_completion_0, + "src/test_data/completion_test/newline/schema/schema_0/schema_0.k", + 8, + 4, + Some('\n') + ); + + completion_label_without_builtin_func_test_snapshot!( + schema_attr_newline_completion_0_1, + "src/test_data/completion_test/newline/schema/schema_0/schema_0.k", + 5, + 4, + Some('\n') + ); + + completion_label_without_builtin_func_test_snapshot!( + schema_attr_newline_completion_1, + "src/test_data/completion_test/newline/schema/schema_1/schema_1.k", + 10, + 4, + Some('\n') + ); + + completion_label_without_system_pkg_test_snapshot!( + import_internal_pkg_test, + "src/test_data/completion_test/import/internal/main.k", + 1, + 8, + None + ); + + completion_label_without_system_pkg_test_snapshot!( + import_external_pkg_test, + "src/test_data/completion_test/import/external/external_1/main.k", + 1, + 8, + None + ); + + completion_label_without_builtin_func_test_snapshot!( + func_return_ty_1, + "src/test_data/completion_test/dot/func_return/func_return_1/func_return_1.k", + 4, + 8, + Some('.') + ); + + completion_label_without_builtin_func_test_snapshot!( + func_return_ty_2, + "src/test_data/completion_test/dot/func_return/func_return_2/func_return_2.k", + 8, + 12, + Some('.') + ); + + completion_label_without_builtin_func_test_snapshot!( + func_return_ty_3, + "src/test_data/completion_test/dot/func_return/func_return_3/func_return_3.k", + 3, + 2, + Some('.') + ); + + completion_label_test_snapshot!( + func_doc_completion, + "src/test_data/completion_test/schema_doc/schema_doc.k", + 7, + 14, + Some('.') + ); + + completion_label_test_snapshot!( + schema_attr_in_right, + "src/test_data/completion_test/schema/schema/schema.k", + 23, + 11, + None + ); + + completion_label_test_snapshot!( + schema_def_1, + "src/test_data/completion_test/schema_def/schema_def.k", + 10, + 22, + None + ); + + completion_label_test_snapshot!( + schema_def_2, + "src/test_data/completion_test/schema_def/schema_def.k", + 12, + 5, + None + ); + + completion_label_test_snapshot!( + schema_def_3, + "src/test_data/completion_test/schema_def/schema_def.k", + 13, + 8, + None + ); + + completion_label_test_snapshot!( + schema_def_4, + "src/test_data/completion_test/schema_def/schema_def.k", + 3, + 12, + None + ); + + completion_label_test_snapshot!( + schema_attr_ty_0, + "src/test_data/completion_test/dot/schema_attr_ty/schema_attr_ty.k", + 5, + 13, + Some('.') + ); + + completion_label_test_snapshot!( + schema_attr_ty_1, + "src/test_data/completion_test/dot/schema_attr_ty/schema_attr_ty.k", + 6, + 14, + Some('.') + ); + + completion_label_test_snapshot!( + schema_attr_ty_2, + "src/test_data/completion_test/dot/schema_attr_ty/schema_attr_ty.k", + 7, + 18, + Some('.') + ); + + completion_label_test_snapshot!( + schema_attr_ty_3, + "src/test_data/completion_test/dot/schema_attr_ty/schema_attr_ty.k", + 8, + 17, + Some('.') + ); + + completion_label_test_snapshot!( + schema_attr_ty_4, + "src/test_data/completion_test/dot/schema_attr_ty/schema_attr_ty.k", + 10, + 15, + Some('.') + ); + + completion_label_test_snapshot!( + complete_after_compare_expr_1, + "src/test_data/completion_test/dot/special_expr/compare.k", + 2, + 23, + Some('.') + ); + + completion_label_without_builtin_func_test_snapshot!( + complete_unimport_schemas, + "src/test_data/completion_test/unimport/unimport/main.k", + 1, + 1, + None + ); +} diff --git a/kclvm/tools/src/LSP/src/dispatcher.rs b/kclvm/tools/src/LSP/src/dispatcher.rs new file mode 100644 index 000000000..6fa40d2f0 --- /dev/null +++ b/kclvm/tools/src/LSP/src/dispatcher.rs @@ -0,0 +1,305 @@ +use crossbeam_channel::Sender; +use lsp_server::{ExtractError, Request}; +use serde::de::DeserializeOwned; +use serde::Serialize; +use std::error::Error; + +use crate::{ + error::LSPError, + state::{LanguageServerSnapshot, LanguageServerState, Task}, + util::from_json, +}; + +pub(crate) struct NotificationDispatcher<'a> { + state: &'a mut LanguageServerState, + notification: Option, +} + +impl<'a> NotificationDispatcher<'a> { + /// Constructs a new dispatcher for the specified request + pub fn new(state: &'a mut LanguageServerState, notification: lsp_server::Notification) -> Self { + NotificationDispatcher { + state, + notification: Some(notification), + } + } + + /// Try to dispatch the event as the given Notification type. + pub fn on( + &mut self, + handle_notification_fn: fn(&mut LanguageServerState, N::Params) -> anyhow::Result<()>, + ) -> anyhow::Result<&mut Self> + where + N: lsp_types::notification::Notification + 'static, + N::Params: DeserializeOwned + Send + 'static, + { + let notification = match self.notification.take() { + Some(it) => it, + None => return Ok(self), + }; + let params = match notification.extract::(N::METHOD) { + Ok(it) => it, + Err(ExtractError::JsonError { method, error }) => { + panic!("Invalid request\nMethod: {method}\n error: {error}",) + } + Err(ExtractError::MethodMismatch(notification)) => { + self.notification = Some(notification); + return Ok(self); + } + }; + handle_notification_fn(self.state, params)?; + Ok(self) + } + + /// Wraps-up the dispatcher. If the notification was not handled, log an error. + pub fn finish(&mut self) { + if let Some(notification) = &self.notification { + if !notification.method.starts_with("$/") { + log::error!("unhandled notification: {:?}", notification); + } + } + } +} + +/// A helper struct to ergonomically dispatch LSP requests to functions. +pub(crate) struct RequestDispatcher<'a> { + state: &'a mut LanguageServerState, + request: Option, +} + +impl<'a> RequestDispatcher<'a> { + /// Constructs a new dispatcher for the specified request + pub fn new(state: &'a mut LanguageServerState, request: lsp_server::Request) -> Self { + RequestDispatcher { + state, + request: Some(request), + } + } + + /// Try to dispatch the event as the given Request type on the current thread. + pub fn on_sync( + &mut self, + compute_response_fn: fn(&mut LanguageServerState, R::Params) -> anyhow::Result, + ) -> anyhow::Result<&mut Self> + where + R: lsp_types::request::Request + 'static, + R::Params: DeserializeOwned + 'static, + R::Result: Serialize + 'static, + { + let (req, params) = match self.parse::() { + Some(it) => it, + None => return Ok(self), + }; + + let result = compute_response_fn(self.state, params); + let response = result_to_response::(req.id, result); + let _result = self.state.respond(response); + Ok(self) + } + + /// Try to dispatch the event as the given Request type on the thread pool. + pub fn on( + &mut self, + compute_response_fn: fn( + LanguageServerSnapshot, + R::Params, + Sender, + ) -> anyhow::Result, + ) -> anyhow::Result<&mut Self> + where + R: lsp_types::request::Request + 'static, + R::Params: DeserializeOwned + 'static + Send, + R::Result: Serialize + 'static, + { + let (req, params) = match self.parse::() { + Some(it) => it, + None => return Ok(self), + }; + + self.state.thread_pool.execute({ + let snapshot = self.state.snapshot(); + let sender = self.state.task_sender.clone(); + + move || { + let result = compute_response_fn(snapshot, params, sender.clone()); + match &result { + Err(e) + if e.downcast_ref::() + .map_or(false, |lsp_err| matches!(lsp_err, LSPError::Retry)) => + { + sender.send(Task::Retry(req)).unwrap(); + } + _ => { + sender + .send(Task::Response(result_to_response::(req.id, result))) + .unwrap(); + } + } + } + }); + + Ok(self) + } + + /// Try to dispatch the event as the given Request type on the thread pool. + pub fn on_maybe_retry( + &mut self, + compute_response_fn: fn( + LanguageServerSnapshot, + R::Params, + Sender, + ) -> anyhow::Result, + ) -> anyhow::Result<&mut Self> + where + R: lsp_types::request::Request + 'static, + R::Params: DeserializeOwned + 'static + Send, + R::Result: Serialize + 'static, + { + let (req, params) = match self.parse::() { + Some(it) => it, + None => return Ok(self), + }; + + self.state.thread_pool.execute({ + let snapshot = self.state.snapshot(); + let sender = self.state.task_sender.clone(); + let request_retry = self.state.request_retry.clone(); + move || { + let result = compute_response_fn(snapshot, params, sender.clone()); + match &result { + Err(e) + if e.downcast_ref::() + .map_or(false, |lsp_err| matches!(lsp_err, LSPError::Retry)) => + { + sender.send(Task::Retry(req.clone())).unwrap(); + let mut request_retry = request_retry.write(); + match request_retry.get_mut(&req.clone().id) { + Some(t) => *t += 1, + None => { + request_retry.insert(req.id.clone(), 1); + } + } + } + _ => { + sender + .send(Task::Response(result_to_response::(req.id, result))) + .unwrap(); + } + } + } + }); + + Ok(self) + } + + /// Tries to parse the request as the specified type. If the request is of the specified type, + /// the request is transferred and any subsequent call to this method will return None. If an + /// error is encountered during parsing of the request parameters an error is send to the + /// client. + fn parse(&mut self) -> Option<(Request, R::Params)> + where + R: lsp_types::request::Request + 'static, + R::Params: DeserializeOwned + 'static, + { + let req = match &self.request { + Some(req) if req.method == R::METHOD => self.request.take().unwrap(), + _ => return None, + }; + + match from_json(R::METHOD, req.params.clone()) { + Ok(params) => Some((req, params)), + Err(err) => { + let response = lsp_server::Response::new_err( + req.id, + lsp_server::ErrorCode::InvalidParams as i32, + err.to_string(), + ); + let _result = self.state.respond(response); + None + } + } + } + + /// Wraps-up the dispatcher. If the request was not handled, report back that this is an + /// unknown request. + pub fn finish(&mut self) { + if let Some(req) = self.request.take() { + log::error!("unknown request: {:?}", req); + let response = lsp_server::Response::new_err( + req.id, + lsp_server::ErrorCode::MethodNotFound as i32, + "unknown request".to_string(), + ); + let _result = self.state.respond(response); + } + } +} + +/// Converts the specified results of an LSP request into an LSP response handling any errors that +/// may have occurred. +fn result_to_response( + id: lsp_server::RequestId, + result: anyhow::Result, +) -> lsp_server::Response +where + R: lsp_types::request::Request + 'static, + R::Params: DeserializeOwned + 'static, + R::Result: Serialize + 'static, +{ + match result { + Ok(resp) => lsp_server::Response::new_ok(id, &resp), + Err(e) => { + if is_canceled(&*e) { + lsp_server::Response::new_err( + id, + lsp_server::ErrorCode::ContentModified as i32, + "content modified".to_string(), + ) + } else { + lsp_server::Response::new_err( + id, + lsp_server::ErrorCode::InternalError as i32, + e.to_string(), + ) + } + } + } +} + +/// An error signifying a cancelled operation. +pub struct Canceled { + // This is here so that you cannot construct a Canceled + _private: (), +} + +impl Canceled { + #[allow(unused)] + fn new() -> Self { + Canceled { _private: () } + } + #[allow(unused)] + pub fn throw() -> ! { + // We use resume and not panic here to avoid running the panic + // hook (that is, to avoid collecting and printing backtrace). + std::panic::resume_unwind(Box::new(Canceled::new())) + } +} + +impl std::fmt::Display for Canceled { + fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + fmt.write_str("canceled") + } +} + +impl std::fmt::Debug for Canceled { + fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(fmt, "Canceled") + } +} + +impl std::error::Error for Canceled {} + +/// Returns true if the specified error is of type [`Canceled`] +pub(crate) fn is_canceled(e: &(dyn Error + 'static)) -> bool { + e.downcast_ref::().is_some() +} diff --git a/kclvm/tools/src/LSP/src/document_symbol.rs b/kclvm/tools/src/LSP/src/document_symbol.rs new file mode 100644 index 000000000..b2315ce8b --- /dev/null +++ b/kclvm/tools/src/LSP/src/document_symbol.rs @@ -0,0 +1,210 @@ +use kclvm_ast::MAIN_PKG; +use kclvm_error::Position; +use kclvm_sema::core::global_state::GlobalState; +use kclvm_sema::core::symbol::KCLSymbol; +use kclvm_sema::core::symbol::SymbolKind as KCLSymbolKind; +use lsp_types::Range; +use lsp_types::{DocumentSymbol, DocumentSymbolResponse, SymbolKind}; + +use crate::to_lsp::lsp_pos; + +pub fn document_symbol(file: &str, gs: &GlobalState) -> Option { + let mut document_symbols: Vec = vec![]; + + let dummy_pos = Position { + filename: file.to_string(), + line: 1, + column: Some(0), + }; + if let Some(scope) = gs.get_scopes().get_root_scope(MAIN_PKG.to_owned()) { + if let Some(defs) = gs.get_all_defs_in_scope(scope, &dummy_pos) { + for symbol_ref in defs { + match gs.get_symbols().get_symbol(symbol_ref) { + Some(symbol) => { + let def = symbol.get_definition(); + match def { + Some(def) => { + let symbol_range = symbol.get_range(); + // filter current file symbols + if symbol_range.0.filename == file { + match def.get_kind() { + KCLSymbolKind::Schema => { + match &mut symbol_to_document_symbol(symbol) { + Some(schema_symbol) => { + let module_info = gs + .get_packages() + .get_module_info(&dummy_pos.filename); + let attrs = symbol.get_all_attributes( + gs.get_symbols(), + module_info, + ); + let mut children = vec![]; + + for attr in attrs { + match gs.get_symbols().get_symbol(attr) { + Some(attr_symbol) => { + match symbol_to_document_symbol( + attr_symbol, + ) { + Some(symbol) => { + children.push(symbol) + } + None => {} + } + } + None => {} + } + } + + schema_symbol.children = Some(children); + schema_symbol.name = + format!("schema {}", schema_symbol.name); + document_symbols.push(schema_symbol.clone()); + } + None => {} + } + } + _ => { + if let Some(symbol) = symbol_to_document_symbol(symbol) + { + document_symbols.push(symbol) + } + } + } + } + } + None => {} + } + } + None => {} + } + } + } + } + Some(DocumentSymbolResponse::Nested(document_symbols)) +} + +fn symbol_to_document_symbol(symbol: &KCLSymbol) -> Option { + let sema_info = symbol.get_sema_info(); + let def = symbol.get_definition(); + match def { + Some(def) => { + let name = symbol.get_name(); + let symbol_range = symbol.get_range(); + let range = Range { + start: lsp_pos(&symbol_range.0), + end: lsp_pos(&symbol_range.1), + }; + let kind = def.get_kind(); + let kind = symbol_kind_to_document_symbol_kind(kind)?; + let detail = sema_info.ty.clone().map(|ty| ty.ty_str()); + + #[allow(deprecated)] + Some(DocumentSymbol { + name, + kind, + range, + selection_range: range, + detail, + tags: None, + children: None, + deprecated: None, + }) + } + None => None, + } +} + +fn symbol_kind_to_document_symbol_kind(kind: KCLSymbolKind) -> Option { + match kind { + KCLSymbolKind::Schema => Some(SymbolKind::STRUCT), + KCLSymbolKind::Attribute => Some(SymbolKind::PROPERTY), + KCLSymbolKind::Value => Some(SymbolKind::VARIABLE), + KCLSymbolKind::Function => Some(SymbolKind::FUNCTION), + KCLSymbolKind::Package => Some(SymbolKind::PACKAGE), + KCLSymbolKind::TypeAlias => Some(SymbolKind::TYPE_PARAMETER), + KCLSymbolKind::Unresolved => Some(SymbolKind::NULL), + KCLSymbolKind::Rule => Some(SymbolKind::FUNCTION), + KCLSymbolKind::Expression => None, + KCLSymbolKind::Comment => None, + KCLSymbolKind::Decorator => None, + } +} + +#[cfg(test)] +mod tests { + use lsp_types::{DocumentSymbol, DocumentSymbolResponse, Position, Range, SymbolKind}; + use proc_macro_crate::bench_test; + + use crate::{document_symbol::document_symbol, tests::compile_test_file}; + + #[allow(deprecated)] + fn build_document_symbol( + name: &str, + kind: SymbolKind, + range: ((u32, u32), (u32, u32)), + child: Option>, + detail: Option, + ) -> DocumentSymbol { + let range: Range = Range { + start: Position { + line: range.0 .0, + character: range.0 .1, + }, + end: Position { + line: range.1 .0, + character: range.1 .1, + }, + }; + DocumentSymbol { + name: name.to_string(), + detail, + kind, + tags: None, + deprecated: None, + range, + selection_range: range, + children: child, + } + } + + #[test] + #[bench_test] + fn document_symbol_test() { + let (file, _, _, gs, _) = + compile_test_file("src/test_data/document_symbol/document_symbol.k"); + + let mut res = document_symbol(file.as_str(), &gs).unwrap(); + let mut expect = vec![]; + expect.push(build_document_symbol( + "schema Person4", + SymbolKind::STRUCT, + ((0, 7), (0, 14)), + Some(vec![build_document_symbol( + "name", + SymbolKind::PROPERTY, + ((1, 4), (1, 8)), + None, + Some("str".to_string()), + )]), + Some("Person4".to_string()), + )); + expect.push(build_document_symbol( + "p", + SymbolKind::VARIABLE, + ((3, 0), (3, 1)), + None, + Some("Person4".to_string()), + )); + + expect.sort_by(|a, b| a.name.cmp(&b.name)); + + match &mut res { + DocumentSymbolResponse::Flat(_) => panic!("test failed"), + DocumentSymbolResponse::Nested(got) => { + got.sort_by(|a, b| a.name.cmp(&b.name)); + assert_eq!(got, &expect) + } + } + } +} diff --git a/kclvm/tools/src/LSP/src/error.rs b/kclvm/tools/src/LSP/src/error.rs new file mode 100644 index 000000000..8c0b1da20 --- /dev/null +++ b/kclvm/tools/src/LSP/src/error.rs @@ -0,0 +1,38 @@ +use std::fmt; + +use ra_ap_vfs::VfsPath; + +pub(crate) const RETRY_REQUEST: &str = "Retry Request"; + +#[derive(Debug, Clone)] +pub(crate) enum LSPError { + Retry, + FileIdNotFound(VfsPath), + WorkSpaceIsEmpty(VfsPath), + AnalysisDatabaseNotFound(VfsPath), +} + +impl fmt::Display for LSPError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + LSPError::Retry => write!(f, "{}", RETRY_REQUEST), + LSPError::FileIdNotFound(path) => { + write!(f, "Internal bug: Path {path} fileId not found") + } + LSPError::AnalysisDatabaseNotFound(path) => { + write!( + f, + "Internal bug: Path {path} analysisDatabase not found, maybe compile failed" + ) + } + LSPError::WorkSpaceIsEmpty(path) => { + write!( + f, + "Internal bug: Path {path} does not belong to any workspace" + ) + } + } + } +} + +impl std::error::Error for LSPError {} diff --git a/kclvm/tools/src/LSP/src/find_refs.rs b/kclvm/tools/src/LSP/src/find_refs.rs new file mode 100644 index 000000000..68d977e9f --- /dev/null +++ b/kclvm/tools/src/LSP/src/find_refs.rs @@ -0,0 +1,151 @@ +use crate::to_lsp::lsp_location; +use kclvm_error::Position as KCLPos; +use kclvm_sema::core::global_state::GlobalState; +use lsp_types::Location; +use std::collections::HashSet; + +pub fn find_refs(kcl_pos: &KCLPos, gs: &GlobalState) -> Option> { + match gs.look_up_exact_symbol(kcl_pos) { + Some(symbol_ref) => match gs.get_symbols().get_symbol(symbol_ref) { + Some(symbol) => match symbol.get_definition() { + Some(def_ref) => { + if let Some(def) = gs.get_symbols().get_symbol(def_ref) { + let refs = def.get_references(); + let mut refs_locs: HashSet<(KCLPos, KCLPos)> = refs + .iter() + .filter_map(|symbol| { + gs.get_symbols() + .get_symbol(*symbol) + .map(|sym| sym.get_range()) + }) + .collect(); + refs_locs.insert(symbol.get_range()); + refs_locs.insert(def.get_range()); + let mut res: Vec = refs_locs + .iter() + .filter_map(|(start, end)| { + lsp_location(start.filename.clone(), &start, &end).map(|loc| loc) + }) + .collect(); + res.sort_by_key(|e| e.range.start.line); + return Some(res); + } + } + None => {} + }, + None => {} + }, + None => {} + }; + None +} + +#[cfg(test)] +mod tests { + use crate::find_refs::find_refs; + use crate::from_lsp::file_path_from_url; + use lsp_types::Location; + use std::path::{Path, PathBuf}; + + use crate::tests::compile_test_file; + use kclvm_error::Position as KCLPos; + + #[macro_export] + macro_rules! find_ref_test_snapshot { + ($name:ident, $file:expr, $line:expr, $column: expr) => { + #[test] + fn $name() { + let (file, _program, _, gs, _) = compile_test_file($file); + + let pos = KCLPos { + filename: file.clone(), + line: $line, + column: Some($column), + }; + let res = find_refs(&pos, &gs); + insta::assert_snapshot!(format!("{}", { fmt_resp(&res) })); + } + }; + } + + fn fmt_resp(resp: &Option>) -> String { + let root_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + match resp { + Some(resp) => { + let mut res = String::new(); + for loc in resp { + let url = file_path_from_url(&loc.uri).unwrap(); + let got_path = Path::new(&url); + let relative_path = got_path + .strip_prefix(root_path.clone()) + .unwrap() + .display() + .to_string() + .replace("\\", "/"); + res.push_str(&format!( + "path: {:?}, range: {:?}\n", + relative_path, loc.range + )); + } + res + } + None => "None".to_string(), + } + } + + find_ref_test_snapshot!( + find_refs_variable_def_test, + "src/test_data/find_refs_test/main.k", + 1, + 1 + ); + + find_ref_test_snapshot!( + find_refs_variable_ref_test, + "src/test_data/find_refs_test/main.k", + 2, + 5 + ); + + find_ref_test_snapshot!( + find_refs_schema_name_test, + "src/test_data/find_refs_test/main.k", + 5, + 8 + ); + + find_ref_test_snapshot!( + find_refs_schema_name_ref_test, + "src/test_data/find_refs_test/main.k", + 9, + 8 + ); + + find_ref_test_snapshot!( + find_refs_schema_attr_test, + "src/test_data/find_refs_test/main.k", + 6, + 7 + ); + + find_ref_test_snapshot!( + find_refs_schema_attr_ref_test, + "src/test_data/find_refs_test/main.k", + 13, + 11 + ); + + find_ref_test_snapshot!( + find_refs_schema_arg_test, + "src/test_data/find_refs_test/main.k", + 17, + 17 + ); + + find_ref_test_snapshot!( + find_refs_schema_arg_1_test, + "src/test_data/find_refs_test/main.k", + 18, + 17 + ); +} diff --git a/kclvm/tools/src/LSP/src/formatting.rs b/kclvm/tools/src/LSP/src/formatting.rs new file mode 100644 index 000000000..4ba39ac09 --- /dev/null +++ b/kclvm/tools/src/LSP/src/formatting.rs @@ -0,0 +1,135 @@ +use kclvm_tools::format::{format_source, FormatOptions}; +use lsp_types::{Position, Range, TextEdit}; + +pub fn format( + file: String, + src: String, + range: Option, +) -> anyhow::Result>> { + let (source, is_formatted) = format_source( + &file, + &src, + &FormatOptions { + omit_errors: true, + ..Default::default() + }, + ) + .map_err(|err| anyhow::anyhow!("Formatting failed: {}", err))?; + if is_formatted { + Ok(Some(vec![TextEdit { + range: range.unwrap_or(Range::new( + Position::new(0, 0), + Position::new(i32::MAX as u32, i32::MAX as u32), + )), + new_text: source, + }])) + } else { + Ok(None) + } +} + +#[cfg(test)] +mod tests { + use std::{ops::Index, path::PathBuf}; + + use super::format; + use lsp_types::{Position, Range, TextEdit}; + use proc_macro_crate::bench_test; + + use crate::{from_lsp::text_range, tests::compile_test_file}; + + #[test] + fn format_signle_file_test() { + const FILE_INPUT_SUFFIX: &str = ".input"; + const FILE_OUTPUT_SUFFIX: &str = ".golden"; + const TEST_CASES: &[&str; 17] = &[ + "assert", + "check", + "blankline", + "breakline", + "codelayout", + "collection_if", + "comment", + "comp_for", + "import", + "indent", + "inline_comment", + "lambda", + "quant", + "schema", + "string", + "type_alias", + "unary", + ]; + + let path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + let test_file = path; + let test_dir = test_file + .parent() + .unwrap() + .join("format") + .join("test_data") + .join("format_data"); + for case in TEST_CASES { + let test_file = test_dir + .join(format!("{}{}", case, FILE_INPUT_SUFFIX)) + .to_str() + .unwrap() + .to_string(); + let test_src = std::fs::read_to_string(&test_file).unwrap(); + let got = format(test_file.to_string(), test_src, None) + .unwrap() + .unwrap(); + let data_output = std::fs::read_to_string( + test_dir + .join(format!("{}{}", case, FILE_OUTPUT_SUFFIX)) + .to_str() + .unwrap(), + ) + .unwrap(); + + #[cfg(target_os = "windows")] + let data_output = data_output.replace("\r\n", "\n"); + + let expect = vec![TextEdit { + range: Range::new( + Position::new(0, 0), + Position::new(i32::MAX as u32, i32::MAX as u32), + ), + new_text: data_output, + }]; + assert_eq!(expect, got); + } + + // empty test case, without change after fmt + let test_file = test_dir + .join(format!("{}{}", "empty", FILE_INPUT_SUFFIX)) + .to_str() + .unwrap() + .to_string(); + let test_src = std::fs::read_to_string(&test_file).unwrap(); + let got = format(test_file, test_src, None).unwrap(); + assert_eq!(got, None) + } + + #[test] + #[bench_test] + fn format_range_test() { + let (file, _program, _, _gs, _) = compile_test_file("src/test_data/format/format_range.k"); + let lsp_range = Range::new(Position::new(0, 0), Position::new(11, 0)); + let text = std::fs::read_to_string(file.clone()).unwrap(); + + let range = text_range(&text, lsp_range); + let src = text.index(range); + + let got = format(file, src.to_owned(), Some(lsp_range)) + .unwrap() + .unwrap(); + + let expected = vec![TextEdit { + range: lsp_range, + new_text: "a = 1\n\nb = 2\n\nc = 3\n".to_string(), + }]; + assert_eq!(got, expected) + } +} diff --git a/kclvm/tools/src/LSP/src/from_lsp.rs b/kclvm/tools/src/LSP/src/from_lsp.rs new file mode 100644 index 000000000..5d1e8ecf0 --- /dev/null +++ b/kclvm/tools/src/LSP/src/from_lsp.rs @@ -0,0 +1,61 @@ +use std::ops::Range; + +use kclvm_error::Position as KCLPos; +use kclvm_utils::path::PathPrefix; +use lsp_types::{Position, Url}; +use ra_ap_vfs::AbsPathBuf; + +/// Converts the specified `uri` to an absolute path. Returns an error if the url could not be +/// converted to an absolute path. +pub(crate) fn abs_path(uri: &Url) -> anyhow::Result { + uri.to_file_path() + .ok() + .and_then(|path| AbsPathBuf::try_from(path).ok()) + .ok_or_else(|| anyhow::anyhow!("invalid uri: {}", uri)) +} + +// Convert pos format +// The position in lsp protocol is different with position in ast node whose line number is 1 based. +pub(crate) fn kcl_pos(file: &str, pos: Position) -> KCLPos { + KCLPos { + filename: kclvm_utils::path::convert_windows_drive_letter(file).adjust_canonicalization(), + line: (pos.line + 1) as u64, + column: Some(pos.character as u64), + } +} + +/// Converts the given lsp range to `Range` +pub(crate) fn text_range(text: &str, range: lsp_types::Range) -> Range { + let mut lines_length = vec![]; + let lines_text: Vec<&str> = text.split('\n').collect(); + let mut pre_total_length = 0; + // range line base-zeror + for i in 0..range.end.line + 1 { + let i = i as usize; + if i < lines_text.len() { + let line = lines_text.get(i).unwrap(); + lines_length.push(pre_total_length); + pre_total_length += line.len() + "\n".len(); + } else { + lines_length.push(pre_total_length); + } + } + + let start = + lines_length.get(range.start.line as usize).unwrap() + range.start.character as usize; + let end = lines_length.get(range.end.line as usize).unwrap() + range.end.character as usize; + + Range { start, end } +} + +/// Converts the specified `url` to a utf8 encoded file path string. Returns an error if the url could not be +/// converted to a valid utf8 encoded file path string. +pub(crate) fn file_path_from_url(url: &Url) -> anyhow::Result { + url.to_file_path() + .ok() + .and_then(|path| { + path.to_str() + .map(kclvm_utils::path::convert_windows_drive_letter) + }) + .ok_or_else(|| anyhow::anyhow!("can't convert url to file path: {}", url)) +} diff --git a/kclvm/tools/src/LSP/src/goto_def.rs b/kclvm/tools/src/LSP/src/goto_def.rs new file mode 100644 index 000000000..562f42494 --- /dev/null +++ b/kclvm/tools/src/LSP/src/goto_def.rs @@ -0,0 +1,589 @@ +//! GotoDefinition for KCL +//! Github Issue: https://github.com/kcl-lang/kcl/issues/476 +//! Now supports goto definition for the following situation: +//! + variable +//! + schema definition +//! + mixin definition +//! + schema attr +//! + attr type + +use crate::to_lsp::lsp_location; +use indexmap::IndexSet; +use kclvm_error::Position as KCLPos; +use kclvm_sema::core::global_state::GlobalState; +use kclvm_sema::core::symbol::SymbolRef; +use lsp_types::GotoDefinitionResponse; + +/// Navigates to the definition of an identifier. +pub fn goto_def(kcl_pos: &KCLPos, gs: &GlobalState) -> Option { + let mut res = IndexSet::new(); + let def = find_def(kcl_pos, gs, true); + + match def { + Some(def_ref) => match gs.get_symbols().get_symbol(def_ref) { + Some(def) => match def_ref.get_kind() { + kclvm_sema::core::symbol::SymbolKind::Package => { + let pkg_info = match gs.get_packages().get_package_info(&def.get_name()) { + Some(pkg_info) => pkg_info, + None => return None, + }; + if pkg_info.is_system() { + return None; + } + for file in pkg_info.get_kfile_paths() { + let dummy_pos = KCLPos { + filename: file.clone(), + line: 1, + column: None, + }; + res.insert((dummy_pos.clone(), dummy_pos)); + } + } + _ => { + res.insert(def.get_range()); + } + }, + None => {} + }, + None => {} + } + positions_to_goto_def_resp(&res) +} + +pub(crate) fn find_def(kcl_pos: &KCLPos, gs: &GlobalState, exact: bool) -> Option { + let def = if exact { + match gs.look_up_exact_symbol(kcl_pos) { + Some(symbol_ref) => match gs.get_symbols().get_symbol(symbol_ref) { + Some(symbol) => symbol.get_definition(), + None => None, + }, + None => None, + } + } else { + match gs.look_up_closest_symbol(kcl_pos) { + Some(symbol_ref) => match gs.get_symbols().get_symbol(symbol_ref) { + Some(symbol) => symbol.get_definition(), + None => None, + }, + None => None, + } + }; + + def +} + +pub(crate) fn find_symbol(kcl_pos: &KCLPos, gs: &GlobalState, exact: bool) -> Option { + let res = if exact { + gs.look_up_exact_symbol(kcl_pos) + } else { + gs.look_up_closest_symbol(kcl_pos) + }; + res +} + +// Convert kcl position to GotoDefinitionResponse. This function will convert to +// None, Scalar or Array according to the number of positions +fn positions_to_goto_def_resp( + positions: &IndexSet<(KCLPos, KCLPos)>, +) -> Option { + match positions.len() { + 0 => None, + 1 => { + let (start, end) = positions.iter().next().unwrap().clone(); + let loc = lsp_location(start.filename.clone(), &start, &end)?; + Some(lsp_types::GotoDefinitionResponse::Scalar(loc)) + } + _ => { + let mut res = vec![]; + for (start, end) in positions { + let loc = lsp_location(start.filename.clone(), start, end)?; + res.push(loc) + } + Some(lsp_types::GotoDefinitionResponse::Array(res)) + } + } +} + +#[cfg(test)] +mod tests { + use super::goto_def; + use crate::{from_lsp::file_path_from_url, tests::compile_test_file}; + use kclvm_error::Position as KCLPos; + use std::path::{Path, PathBuf}; + + #[macro_export] + macro_rules! goto_def_test_snapshot { + ($name:ident, $file:expr, $line:expr, $column: expr) => { + #[test] + fn $name() { + let (file, _program, _, gs, _) = compile_test_file($file); + + let pos = KCLPos { + filename: file.clone(), + line: $line, + column: Some($column), + }; + let res = goto_def(&pos, &gs); + insta::assert_snapshot!(format!("{:?}", { fmt_resp(&res) })); + } + }; + } + + fn fmt_resp(resp: &Option) -> String { + let root_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")) + .canonicalize() + .unwrap(); + match resp { + Some(resp) => match resp { + lsp_types::GotoDefinitionResponse::Scalar(loc) => { + let url = file_path_from_url(&loc.uri).unwrap(); + let got_path = Path::new(&url).canonicalize().unwrap(); + let relative_path = got_path + .strip_prefix(root_path) + .unwrap() + .display() + .to_string() + .replace("\\", "/"); + format!("path: {:?}, range: {:?}", relative_path, loc.range) + } + lsp_types::GotoDefinitionResponse::Array(vec_location) => { + let mut res = String::new(); + for loc in vec_location { + let url = file_path_from_url(&loc.uri).unwrap(); + let got_path = Path::new(&url).canonicalize().unwrap(); + let relative_path = got_path + .strip_prefix(root_path.clone()) + .unwrap() + .display() + .to_string() + .replace("\\", "/"); + res.push_str(&format!( + "path: {:?}, range: {:?}\n", + relative_path, loc.range + )); + } + res + } + lsp_types::GotoDefinitionResponse::Link(vec_location_link) => { + let mut res = String::new(); + for loc in vec_location_link { + let url = file_path_from_url(&loc.target_uri).unwrap(); + let got_path = Path::new(&url).canonicalize().unwrap(); + let relative_path = got_path + .strip_prefix(root_path.clone()) + .unwrap() + .display() + .to_string() + .replace("\\", "/"); + res.push_str(&format!( + "path: {:?}, range: {:?}\n", + relative_path, loc.target_selection_range + )); + } + res + } + }, + None => "None".to_string(), + } + } + + goto_def_test_snapshot!( + goto_import_pkg_test, + "src/test_data/goto_def_test/goto_import_pkg_test/goto_import_pkg_test.k", + 1, + 11 + ); + + goto_def_test_snapshot!( + goto_pkg_prefix_def_test, + "src/test_data/goto_def_test/goto_pkg_prefix_def_test/goto_pkg_prefix_def_test.k", + 3, + 7 + ); + + goto_def_test_snapshot!( + goto_var_def_in_config_and_config_if_test1, + "src/test_data/goto_def_test/goto_var_def_in_config_and_config_if_test/goto_var_def_in_config_and_config_if_test.k", + 7, + 36 + ); + + goto_def_test_snapshot!( + goto_var_def_in_config_and_config_if_test2, + "src/test_data/goto_def_test/goto_var_def_in_config_and_config_if_test/goto_var_def_in_config_and_config_if_test.k", + 7, + 44 + ); + + goto_def_test_snapshot!( + goto_var_def_in_config_and_config_if_test3, + "src/test_data/goto_def_test/goto_var_def_in_config_and_config_if_test/goto_var_def_in_config_and_config_if_test.k", + 4, + 11 + ); + + goto_def_test_snapshot!( + goto_var_def_in_config_and_config_if_test4, + "src/test_data/goto_def_test/goto_var_def_in_config_and_config_if_test/goto_var_def_in_config_and_config_if_test.k", + 7, + 10 + ); + + goto_def_test_snapshot!( + goto_var_def_in_dict_comp_test1, + "src/test_data/goto_def_test/goto_var_def_in_dict_comp_test/goto_var_def_in_dict_comp_test.k", + 5, + 68 + ); + + goto_def_test_snapshot!( + goto_var_def_in_dict_comp_test2, + "src/test_data/goto_def_test/goto_var_def_in_dict_comp_test/goto_var_def_in_dict_comp_test.k", + 5, + 61 + ); + + goto_def_test_snapshot!( + test_goto_identifier_names1, + "src/test_data/goto_def_test/test_goto_identifier_names/test_goto_identifier_names.k", + 13, + 5 + ); + + goto_def_test_snapshot!( + test_goto_identifier_names2, + "src/test_data/goto_def_test/test_goto_identifier_names/test_goto_identifier_names.k", + 13, + 8 + ); + + goto_def_test_snapshot!( + test_goto_identifier_names3, + "src/test_data/goto_def_test/test_goto_identifier_names/test_goto_identifier_names.k", + 13, + 12 + ); + + goto_def_test_snapshot!( + goto_local_var_def_test1, + "src/test_data/goto_def_test/goto_local_var_def_test/goto_local_var_def_test.k", + 7, + 11 + ); + + goto_def_test_snapshot!( + goto_local_var_def_test2, + "src/test_data/goto_def_test/goto_local_var_def_test/goto_local_var_def_test.k", + 9, + 11 + ); + + goto_def_test_snapshot!( + goto_local_var_def_test3, + "src/test_data/goto_def_test/goto_local_var_def_test/goto_local_var_def_test.k", + 11, + 11 + ); + + goto_def_test_snapshot!( + goto_lambda_param_goto_def1, + "src/test_data/goto_def_test/goto_lambda_param_goto_def/goto_lambda_param_goto_def.k", + 3, + 5 + ); + + goto_def_test_snapshot!( + goto_lambda_param_goto_def2, + "src/test_data/goto_def_test/goto_lambda_param_goto_def/goto_lambda_param_goto_def.k", + 3, + 9 + ); + + // To implement + goto_def_test_snapshot!( + goto_system_pkg_test, + "src/test_data/goto_def_test/goto_system_pkg_test/goto_system_pkg_test.k", + 1, + 1 + ); + + goto_def_test_snapshot!( + lambda_local_var_test, + "src/test_data/goto_def_test/lambda_local_var_test/lambda_local_var_test.k", + 2, + 9 + ); + + goto_def_test_snapshot!( + goto_dict_to_schema_attr_test1, + "src/test_data/goto_def_test/dict_to_schema/dict_to_schema.k", + 13, + 15 + ); + + goto_def_test_snapshot!( + goto_dict_to_schema_attr_test2, + "src/test_data/goto_def_test/dict_to_schema/dict_to_schema.k", + 15, + 7 + ); + + goto_def_test_snapshot!( + goto_dict_to_schema_attr_test3, + "src/test_data/goto_def_test/dict_to_schema/dict_to_schema.k", + 19, + 7 + ); + + goto_def_test_snapshot!( + goto_dict_to_schema_attr_test4, + "src/test_data/goto_def_test/dict_to_schema/dict_to_schema.k", + 26, + 11 + ); + + goto_def_test_snapshot!( + goto_dict_to_schema_attr_test5, + "src/test_data/goto_def_test/dict_to_schema/dict_to_schema.k", + 33, + 11 + ); + + goto_def_test_snapshot!( + goto_dict_to_schema_attr_test6, + "src/test_data/goto_def_test/dict_to_schema/dict_to_schema.k", + 52, + 7 + ); + + goto_def_test_snapshot!( + goto_dict_to_schema_attr_test7, + "src/test_data/goto_def_test/dict_to_schema/dict_to_schema.k", + 55, + 7 + ); + + goto_def_test_snapshot!( + goto_dict_to_schema_attr_test8, + "src/test_data/goto_def_test/dict_to_schema/dict_to_schema.k", + 58, + 7 + ); + + goto_def_test_snapshot!( + list_if_expr_test, + "src/test_data/goto_def_test/list_if_expr_test/list_if_expr_test.k", + 3, + 8 + ); + + goto_def_test_snapshot!( + goto_identifier_def_test, + "src/test_data/goto_def_test/goto_identifier_def_test/goto_identifier_def_test.k", + 8, + 6 + ); + + goto_def_test_snapshot!( + complex_select_goto_def, + "src/test_data/goto_def_test/complex_select_goto_def/complex_select_goto_def.k", + 13, + 22 + ); + + goto_def_test_snapshot!( + schema_attribute_def_goto_def, + "src/test_data/goto_def_test/schema_attribute_def_goto_def/schema_attribute_def_goto_def.k", + 2, + 5 + ); + + goto_def_test_snapshot!( + config_desuger_def_goto_def, + "src/test_data/goto_def_test/config_desuger_def_goto_def/config_desuger_def_goto_def.k", + 7, + 9 + ); + + goto_def_test_snapshot!( + goto_schema_attr_ty_def_test5, + "src/test_data/goto_def_test/goto_schema_attr_ty_def_test/goto_schema_attr_ty_def_test.k", + 7, + 28 + ); + + goto_def_test_snapshot!( + goto_schema_attr_ty_def_test4, + "src/test_data/goto_def_test/goto_schema_attr_ty_def_test/goto_schema_attr_ty_def_test.k", + 7, + 17 + ); + + goto_def_test_snapshot!( + goto_schema_attr_ty_def_test3, + "src/test_data/goto_def_test/goto_schema_attr_ty_def_test/goto_schema_attr_ty_def_test.k", + 6, + 22 + ); + + goto_def_test_snapshot!( + goto_schema_attr_ty_def_test2, + "src/test_data/goto_def_test/goto_schema_attr_ty_def_test/goto_schema_attr_ty_def_test.k", + 5, + 15 + ); + + goto_def_test_snapshot!( + goto_schema_attr_ty_def_test1, + "src/test_data/goto_def_test/goto_schema_attr_ty_def_test/goto_schema_attr_ty_def_test.k", + 4, + 15 + ); + + goto_def_test_snapshot!( + goto_assign_type_test, + "src/test_data/goto_def_test/goto_assign_type_test/goto_assign_type_test.k", + 5, + 17 + ); + + goto_def_test_snapshot!( + goto_schema_def_test, + "src/test_data/goto_def_test/goto_schema_def_test/goto_schema_def_test.k", + 3, + 11 + ); + + goto_def_test_snapshot!( + goto_schema_attr_def_test1, + "src/test_data/goto_def_test/goto_schema_attr_def_test/goto_schema_attr_def_test.k", + 4, + 7 + ); + + goto_def_test_snapshot!( + goto_schema_attr_def_test2, + "src/test_data/goto_def_test/goto_schema_attr_def_test/goto_schema_attr_def_test.k", + 18, + 12 + ); + + goto_def_test_snapshot!( + goto_lambda_param_schema_test, + "src/test_data/goto_def_test/goto_lambda_param_schema_test/goto_lambda_param_schema_test.k", + 8, + 10 + ); + + goto_def_test_snapshot!( + goto_lambda_return_schema_test, + "src/test_data/goto_def_test/goto_lambda_return_schema_test/goto_lambda_return_schema_test.k", + 6, + 10 + ); + + goto_def_test_snapshot!( + goto_nested_schema_attr_test, + "src/test_data/goto_def_test/goto_nested_schema_attr_test/goto_nested_schema_attr_test.k", + 22, + 22 + ); + + goto_def_test_snapshot!( + goto_base_schema_attr_test, + "src/test_data/goto_def_test/goto_base_schema_attr_test/goto_base_schema_attr_test.k", + 8, + 12 + ); + + goto_def_test_snapshot!( + goto_base_schema_attr_1_test, + "src/test_data/goto_def_test/goto_base_schema_attr_1_test/goto_base_schema_attr_1_test.k", + 4, + 12 + ); + + goto_def_test_snapshot!( + goto_unification_schema_attr_test, + "src/test_data/goto_def_test/goto_unification_schema_attr_test/goto_unification_schema_attr_test.k", + 7, + 7 + ); + + goto_def_test_snapshot!( + goto_duplicate_var_name_in_schema, + "src/test_data/goto_def_test/duplicate_var_name_test/duplicate_var_name.k", + 8, + 11 + ); + + goto_def_test_snapshot!( + goto_attr_in_schema_def_1, + "src/test_data/goto_def_test/goto_attr_in_schema_def/goto_attr_in_schema_def.k", + 9, + 14 + ); + + goto_def_test_snapshot!( + goto_attr_in_schema_def_2, + "src/test_data/goto_def_test/goto_attr_in_schema_def/goto_attr_in_schema_def.k", + 10, + 14 + ); + + goto_def_test_snapshot!( + goto_attr_in_schema_def_3, + "src/test_data/goto_def_test/goto_attr_in_schema_def/goto_attr_in_schema_def.k", + 11, + 14 + ); + + goto_def_test_snapshot!( + goto_attr_in_schema_def_4, + "src/test_data/goto_def_test/goto_attr_in_schema_def/goto_attr_in_schema_def.k", + 17, + 12 + ); + + goto_def_test_snapshot!( + goto_attr_in_schema_def_5, + "src/test_data/goto_def_test/goto_attr_in_schema_def/goto_attr_in_schema_def.k", + 32, + 15 + ); + + goto_def_test_snapshot!( + goto_attr_in_schema_def_6, + "src/test_data/goto_def_test/goto_attr_in_schema_def/goto_attr_in_schema_def.k", + 33, + 15 + ); + + goto_def_test_snapshot!( + goto_attr_in_schema_def_7, + "src/test_data/goto_def_test/goto_attr_in_schema_def/goto_attr_in_schema_def.k", + 32, + 10 + ); + + goto_def_test_snapshot!( + goto_attr_in_schema_def_8, + "src/test_data/goto_def_test/goto_attr_in_schema_def/goto_attr_in_schema_def.k", + 33, + 10 + ); + + goto_def_test_snapshot!( + goto_protocol_attr, + "src/test_data/goto_def_test/goto_protocol/goto_protocol.k", + 6, + 17 + ); + + goto_def_test_snapshot!( + goto_protocol_attr_1, + "src/test_data/goto_def_test/goto_protocol/goto_protocol.k", + 8, + 13 + ); +} diff --git a/kclvm/tools/src/LSP/src/hover.rs b/kclvm/tools/src/LSP/src/hover.rs new file mode 100644 index 000000000..c69c19b40 --- /dev/null +++ b/kclvm/tools/src/LSP/src/hover.rs @@ -0,0 +1,780 @@ +use kclvm_error::Position as KCLPos; +use kclvm_sema::{ + builtin::BUILTIN_DECORATORS, + core::global_state::GlobalState, + ty::{FunctionType, Type, ANY_TYPE_STR}, +}; +use lsp_types::{Hover, HoverContents, MarkedString}; + +use crate::goto_def::find_def; + +enum MarkedStringType { + String, + LanguageString, +} + +/// Returns a short text describing element at position. +/// Specifically, the doc for schema and schema attr(todo) +pub fn hover(kcl_pos: &KCLPos, gs: &GlobalState) -> Option { + let mut docs: Vec<(String, MarkedStringType)> = vec![]; + + let def = find_def(kcl_pos, gs, true); + match def { + Some(def_ref) => match gs.get_symbols().get_symbol(def_ref) { + Some(obj) => match def_ref.get_kind() { + kclvm_sema::core::symbol::SymbolKind::Schema => match &obj.get_sema_info().ty { + Some(ty) => { + // Build hover content for schema definition + // Schema Definition hover + // ``` + // pkg + // ---------------- + // schema Foo(Base)[param: type]: + // attr1: type + // attr2? type = defalut_value + // ----------------- + // doc + // ``` + let schema_ty = ty.into_schema_type(); + let (pkgpath, rest_sign) = schema_ty.schema_ty_signature_str(); + if !pkgpath.is_empty() { + docs.push((pkgpath.clone(), MarkedStringType::String)); + } + + // The attr of schema_ty does not contain the attrs from inherited base schema. + // Use the api provided by GlobalState to get all attrs + let module_info = gs.get_packages().get_module_info(&kcl_pos.filename); + let schema_attrs = obj.get_all_attributes(gs.get_symbols(), module_info); + let mut attrs: Vec = vec![]; + for schema_attr in schema_attrs { + if let kclvm_sema::core::symbol::SymbolKind::Attribute = + schema_attr.get_kind() + { + let attr = gs.get_symbols().get_symbol(schema_attr).unwrap(); + let name = attr.get_name(); + let attr_symbol = + gs.get_symbols().get_attr_symbol(schema_attr).unwrap(); + let default_value_content = match attr_symbol.get_default_value() { + Some(s) => format!(" = {}", s), + None => "".to_string(), + }; + let attr_ty_str = match &attr.get_sema_info().ty { + Some(ty) => ty_hover_content(ty), + None => ANY_TYPE_STR.to_string(), + }; + attrs.push(format!( + " {}{}: {}{}", + name, + if attr_symbol.is_optional() { "?" } else { "" }, + attr_ty_str, + default_value_content + )); + } + } + + let merged_doc = format!("{}\n{}", rest_sign.clone(), attrs.join("\n")); + docs.push((merged_doc, MarkedStringType::LanguageString)); + + if !schema_ty.doc.is_empty() { + docs.push((schema_ty.doc.clone(), MarkedStringType::String)); + } + } + _ => {} + }, + kclvm_sema::core::symbol::SymbolKind::Attribute => { + let sema_info = obj.get_sema_info(); + let attr_symbol = gs.get_symbols().get_attr_symbol(def_ref).unwrap(); + let default_value_content = match attr_symbol.get_default_value() { + Some(s) => format!(" = {}", s), + None => "".to_string(), + }; + match &sema_info.ty { + Some(ty) => { + docs.push(( + format!( + "{}: {}{}", + &obj.get_name(), + ty.ty_hint(), + default_value_content + ), + MarkedStringType::LanguageString, + )); + if let Some(doc) = &sema_info.doc { + if !doc.is_empty() { + docs.push((doc.clone(), MarkedStringType::String)); + } + } + } + _ => {} + } + } + kclvm_sema::core::symbol::SymbolKind::Value + | kclvm_sema::core::symbol::SymbolKind::Function => match &obj.get_sema_info().ty { + Some(ty) => match &ty.kind { + kclvm_sema::ty::TypeKind::Function(func_ty) => { + docs.append(&mut build_func_hover_content( + func_ty.clone(), + obj.get_name().clone(), + )); + } + _ => { + docs.push(( + format!("{}: {}", &obj.get_name(), ty.ty_str()), + MarkedStringType::LanguageString, + )); + } + }, + _ => {} + }, + kclvm_sema::core::symbol::SymbolKind::Expression => return None, + kclvm_sema::core::symbol::SymbolKind::Comment => return None, + kclvm_sema::core::symbol::SymbolKind::Decorator => { + match BUILTIN_DECORATORS.get(&obj.get_name()) { + Some(ty) => { + let mut hover_content = build_func_hover_content( + ty.into_func_type(), + obj.get_name().clone(), + ); + + docs.append(&mut hover_content); + } + None => todo!(), + } + } + _ => { + let ty_str = match &obj.get_sema_info().ty { + Some(ty) => ty.ty_str(), + None => "".to_string(), + }; + docs.push(( + format!("{}: {}", &obj.get_name(), ty_str), + MarkedStringType::LanguageString, + )); + } + }, + None => {} + }, + None => {} + } + docs_to_hover(docs) +} + +fn ty_hover_content(ty: &Type) -> String { + ty.ty_hint() +} + +// Convert doc to Marked String. This function will convert docs to Markedstrings +fn convert_doc_to_marked_string(doc: &(String, MarkedStringType)) -> MarkedString { + match doc.1 { + MarkedStringType::String => MarkedString::String(doc.0.clone()), + MarkedStringType::LanguageString => { + MarkedString::LanguageString(lsp_types::LanguageString { + language: "KCL".to_owned(), + value: doc.0.clone(), + }) + } + } +} + +// Convert docs to Hover. This function will convert to +// None, Scalar or Array according to the number of positions +fn docs_to_hover(docs: Vec<(String, MarkedStringType)>) -> Option { + let mut all_docs: Vec = Vec::new(); + + for doc in docs { + all_docs.push(convert_doc_to_marked_string(&doc)); + } + + match all_docs.len() { + 0 => None, + 1 => Some(Hover { + contents: HoverContents::Scalar(all_docs.remove(0)), + range: None, + }), + _ => Some(Hover { + contents: HoverContents::Array(all_docs), + range: None, + }), + } +} + +// Build hover content for function call +// ``` +// pkg +// ----------------- +// function func_name(arg1: type, arg2: type, ..) -> type +// ----------------- +// doc +// ``` +fn build_func_hover_content( + func_ty: FunctionType, + name: String, +) -> Vec<(String, MarkedStringType)> { + let mut docs: Vec<(String, MarkedStringType)> = vec![]; + if let Some(ty) = &func_ty.self_ty { + let self_ty = format!("{}\n\n", ty.ty_str()); + docs.push((self_ty, MarkedStringType::String)); + } + + let mut sig = format!("function {}(", name); + if func_ty.params.is_empty() { + sig.push(')'); + } else { + for (i, p) in func_ty.params.iter().enumerate() { + let default_value = match &p.default_value { + Some(s) => format!(" = {}", s), + None => "".to_string(), + }; + sig.push_str(&format!("{}: {}{}", p.name, p.ty.ty_str(), default_value)); + + if i != func_ty.params.len() - 1 { + sig.push_str(", "); + } + } + sig.push(')'); + } + sig.push_str(&format!(" -> {}", func_ty.return_ty.ty_str())); + docs.push((sig, MarkedStringType::LanguageString)); + + if !func_ty.doc.is_empty() { + docs.push(( + func_ty.doc.clone().replace('\n', "\n\n"), + MarkedStringType::String, + )); + } + docs +} + +#[cfg(test)] +mod tests { + use crate::hover::docs_to_hover; + use crate::hover::MarkedStringType; + use std::path::PathBuf; + + use kclvm_error::Position as KCLPos; + use lsp_types::{LanguageString, MarkedString}; + use proc_macro_crate::bench_test; + + use crate::tests::compile_test_file; + + use super::hover; + + #[test] + fn schema_doc_hover_test() { + let path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + + let (file, _program, _, gs, _) = + compile_test_file("src/test_data/goto_def_test/goto_def.k"); + + let mut expected_path = path; + expected_path.push("src/test_data/goto_def_test/pkg/schema_def.k"); + + // test hover of schema doc: p = pkg.Person + let pos = KCLPos { + filename: file.clone(), + line: 4, + column: Some(11), + }; + let got = hover(&pos, &gs).unwrap(); + match got.contents { + lsp_types::HoverContents::Array(vec) => { + if let MarkedString::String(s) = vec[0].clone() { + assert_eq!(s, "pkg"); + } + if let MarkedString::LanguageString(s) = vec[1].clone() { + assert_eq!( + s.value, + "schema Person:\n name: str\n age: int".to_string() + ); + } else { + unreachable!("test error"); + } + if let MarkedString::String(s) = vec[2].clone() { + assert_eq!(s, "hover doc test"); + } else { + unreachable!("test error"); + } + } + _ => unreachable!("test error"), + } + let pos = KCLPos { + filename: file, + line: 5, + column: Some(7), + }; + let got = hover(&pos, &gs).unwrap(); + match got.contents { + lsp_types::HoverContents::Scalar(marked_string) => { + if let MarkedString::LanguageString(s) = marked_string { + assert_eq!(s.value, "name: str"); + } + } + _ => unreachable!("test error"), + } + } + + #[test] + #[bench_test] + fn test_docs_to_hover_multiple_docs() { + // Given multiple documentation strings + let docs = vec![ + ( + "Documentation string 1".to_string(), + MarkedStringType::String, + ), + ( + "Documentation string 2".to_string(), + MarkedStringType::String, + ), + ( + "Documentation string 3".to_string(), + MarkedStringType::String, + ), + ]; + + // When converting to hover content + let hover = docs_to_hover(docs); + + // Then the result should be a Hover object with an Array of MarkedString::String + assert!(hover.is_some()); + let hover = hover.unwrap(); + match hover.contents { + lsp_types::HoverContents::Array(vec) => { + assert_eq!(vec.len(), 3); + assert_eq!( + vec[0], + MarkedString::String("Documentation string 1".to_string()) + ); + assert_eq!( + vec[1], + MarkedString::String("Documentation string 2".to_string()) + ); + assert_eq!( + vec[2], + MarkedString::String("Documentation string 3".to_string()) + ); + } + _ => panic!("Unexpected hover contents"), + } + } + + #[test] + #[bench_test] + fn schema_doc_hover_test1() { + let (file, _program, _, gs, _) = compile_test_file("src/test_data/hover_test/hover.k"); + + let pos = KCLPos { + filename: file.clone(), + line: 16, + column: Some(8), + }; + let got = hover(&pos, &gs).unwrap(); + + match got.contents { + lsp_types::HoverContents::Array(vec) => { + if let MarkedString::String(s) = vec[0].clone() { + assert_eq!(s, "__main__"); + } + if let MarkedString::LanguageString(s) = vec[1].clone() { + assert_eq!(s.value, "schema Person:\n name: str\n age?: int"); + } + if let MarkedString::String(s) = vec[2].clone() { + assert_eq!(s, "hover doc test"); + } + } + _ => unreachable!("test error"), + } + } + + #[test] + #[bench_test] + fn schema_attr_hover_test() { + let (file, _program, _, gs, _) = compile_test_file("src/test_data/hover_test/hover.k"); + + let pos = KCLPos { + filename: file.clone(), + line: 17, + column: Some(7), + }; + let got = hover(&pos, &gs).unwrap(); + + match got.contents { + lsp_types::HoverContents::Array(vec) => { + if let MarkedString::LanguageString(s) = vec[0].clone() { + assert_eq!(s.value, "name: str"); + } + if let MarkedString::String(s) = vec[1].clone() { + assert_eq!(s, "name doc test"); + } + } + _ => unreachable!("test error"), + } + + let pos = KCLPos { + filename: file.clone(), + line: 18, + column: Some(7), + }; + let got = hover(&pos, &gs).unwrap(); + + match got.contents { + lsp_types::HoverContents::Array(vec) => { + if let MarkedString::LanguageString(s) = vec[0].clone() { + assert_eq!(s.value, "age: int"); + } + if let MarkedString::String(s) = vec[0].clone() { + assert_eq!(s, "age doc test"); + } + } + _ => unreachable!("test error"), + } + } + + #[test] + #[bench_test] + fn lambda_doc_hover_test() { + let (file, _program, _, gs, _) = compile_test_file("src/test_data/hover_test/lambda.k"); + + let pos = KCLPos { + filename: file.clone(), + line: 1, + column: Some(1), + }; + let got = hover(&pos, &gs).unwrap(); + + match got.contents { + lsp_types::HoverContents::Array(vec) => { + if let MarkedString::LanguageString(s) = vec[0].clone() { + assert_eq!(s.value, "function f(x: int = 1) -> int"); + } + if let MarkedString::String(s) = vec[0].clone() { + assert_eq!(s, "lambda documents"); + } + } + _ => unreachable!("test error"), + } + } + + #[test] + #[bench_test] + fn func_def_hover() { + let (file, _program, _, gs, _) = compile_test_file("src/test_data/hover_test/hover.k"); + + let pos = KCLPos { + filename: file.clone(), + line: 22, + column: Some(18), + }; + let got = hover(&pos, &gs).unwrap(); + + match got.contents { + lsp_types::HoverContents::Array(vec) => { + assert_eq!(vec.len(), 2); + if let MarkedString::LanguageString(s) = vec[0].clone() { + assert_eq!(s.value, "function encode(value: str, encoding: str) -> str"); + } + if let MarkedString::String(s) = vec[1].clone() { + assert_eq!( + s, + "Encode the string `value` using the codec registered for encoding." + ); + } + } + _ => unreachable!("test error"), + } + + let pos = KCLPos { + filename: file.clone(), + line: 23, + column: Some(14), + }; + let got = hover(&pos, &gs).unwrap(); + + match got.contents { + lsp_types::HoverContents::Array(vec) => { + assert_eq!(vec.len(), 3); + if let MarkedString::String(s) = vec[0].clone() { + assert_eq!(s, "str\n\n"); + } + if let MarkedString::LanguageString(s) = vec[1].clone() { + assert_eq!( + s.value, + "function count(sub: str, start: int, end: int) -> int" + ); + } + if let MarkedString::String(s) = vec[2].clone() { + assert_eq!(s, "Return the number of non-overlapping occurrences of substring sub in the range [start, end]. Optional arguments start and end are interpreted as in slice notation."); + } + } + _ => unreachable!("test error"), + } + + let pos = KCLPos { + filename: file.clone(), + line: 25, + column: Some(4), + }; + let got = hover(&pos, &gs).unwrap(); + + match got.contents { + lsp_types::HoverContents::Array(vec) => { + assert_eq!(vec.len(), 2); + if let MarkedString::LanguageString(s) = vec[0].clone() { + assert_eq!(s.value, "function print() -> NoneType"); + } + if let MarkedString::String(s) = vec[1].clone() { + assert_eq!(s, "Prints the values to a stream, or to the system stdout by default.\n\nOptional keyword arguments:\n\nsep: string inserted between values, default a space.\n\nend: string appended after the last value, default a newline."); + } + } + _ => unreachable!("test error"), + } + } + + #[test] + #[bench_test] + fn complex_select_hover() { + let (file, _program, _, gs, _) = compile_test_file("src/test_data/hover_test/fib.k"); + let pos = KCLPos { + filename: file.clone(), + line: 14, + column: Some(22), + }; + let got = hover(&pos, &gs).unwrap(); + match got.contents { + lsp_types::HoverContents::Scalar(marked_string) => { + if let MarkedString::LanguageString(s) = marked_string { + assert_eq!(s.value, "value: int"); + } + } + _ => unreachable!("test error"), + } + } + + #[test] + #[bench_test] + fn assignment_ty_in_lambda_hover() { + let (file, _program, _, gs, _) = + compile_test_file("src/test_data/hover_test/ty_in_lambda.k"); + let pos = KCLPos { + filename: file.clone(), + line: 3, + column: Some(8), + }; + let got = hover(&pos, &gs).unwrap(); + match got.contents { + lsp_types::HoverContents::Scalar(marked_string) => { + if let MarkedString::LanguageString(s) = marked_string { + assert_eq!(s.value, "result: {str:str}"); + } + } + _ => unreachable!("test error"), + } + } + + #[test] + #[bench_test] + fn str_var_func_hover() { + let (file, _program, _, gs, _) = compile_test_file("src/test_data/hover_test/hover.k"); + let pos = KCLPos { + filename: file.clone(), + line: 28, + column: Some(12), + }; + let got = hover(&pos, &gs).unwrap(); + match got.contents { + lsp_types::HoverContents::Array(vec) => { + assert_eq!(vec.len(), 3); + if let MarkedString::String(s) = vec[0].clone() { + assert_eq!(s, "str\n\n"); + } + if let MarkedString::LanguageString(s) = vec[1].clone() { + assert_eq!(s.value, "function capitalize() -> str"); + } + if let MarkedString::String(s) = vec[2].clone() { + assert_eq!(s, "Return a copy of the string with its first character capitalized and the rest lowercased."); + } + } + _ => unreachable!("test error"), + } + } + + #[test] + #[bench_test] + fn import_pkg_hover() { + let (file, _program, _, gs, _) = compile_test_file("src/test_data/hover_test/import_pkg.k"); + let pos = KCLPos { + filename: file.clone(), + line: 3, + column: Some(7), + }; + let got = hover(&pos, &gs).unwrap(); + match got.contents { + lsp_types::HoverContents::Array(vec) => { + assert_eq!(vec.len(), 2); + if let MarkedString::String(s) = vec[0].clone() { + assert_eq!(s, "fib"); + } + if let MarkedString::LanguageString(s) = vec[1].clone() { + assert_eq!(s.value, "schema Fib:\n n: int\n value: int"); + } + } + _ => unreachable!("test error"), + } + } + + #[test] + #[bench_test] + fn expr_after_config_if_hover() { + let (file, _program, _, gs, _) = compile_test_file("src/test_data/hover_test/hover.k"); + let pos = KCLPos { + filename: file.clone(), + line: 41, + column: Some(13), + }; + let got = hover(&pos, &gs).unwrap(); + match got.contents { + lsp_types::HoverContents::Scalar(marked_string) => { + if let MarkedString::LanguageString(s) = marked_string { + assert_eq!(s.value, "stratege: str"); + } + } + _ => unreachable!("test error"), + } + } + + #[test] + #[bench_test] + fn schema_scope_variable_hover() { + let (file, _program, _, gs, _) = compile_test_file("src/test_data/hover_test/fib.k"); + let pos = KCLPos { + filename: file.clone(), + line: 3, + column: Some(11), + }; + let got = hover(&pos, &gs).unwrap(); + match got.contents { + lsp_types::HoverContents::Scalar(marked_string) => { + if let MarkedString::LanguageString(s) = marked_string { + assert_eq!(s.value, "n1: int"); + } + } + _ => unreachable!("test error"), + } + } + + #[test] + #[bench_test] + fn decorator_hover() { + let (file, _program, _, gs, _) = compile_test_file("src/test_data/hover_test/decorator.k"); + let pos = KCLPos { + filename: file.clone(), + line: 1, + column: Some(1), + }; + let got = hover(&pos, &gs).unwrap(); + let expect_content = vec![ + MarkedString::LanguageString(LanguageString { + language: "KCL".to_string(), + value: "function deprecated(version: str, reason: str, strict: bool) -> any".to_string(), + }), + MarkedString::String( + "This decorator is used to get the deprecation message according to the wrapped key-value pair.".to_string(), + ), + ]; + match got.contents { + lsp_types::HoverContents::Array(vec) => { + assert_eq!(vec, expect_content) + } + _ => unreachable!("test error"), + } + + let pos = KCLPos { + filename: file.clone(), + line: 3, + column: Some(8), + }; + let got = hover(&pos, &gs).unwrap(); + match got.contents { + lsp_types::HoverContents::Array(vec) => { + assert_eq!(vec, expect_content); + } + _ => unreachable!("test error"), + } + } + + #[test] + #[bench_test] + fn inherit_schema_attr_hover() { + let (file, _program, _, gs, _) = compile_test_file("src/test_data/hover_test/inherit.k"); + let pos = KCLPos { + filename: file.clone(), + line: 5, + column: Some(9), + }; + let got = hover(&pos, &gs).unwrap(); + + let expect_content = vec![ + MarkedString::String("__main__".to_string()), + MarkedString::LanguageString(LanguageString { + language: "KCL".to_string(), + value: "schema Data1[m: {str:str}](Data):\n name: str = \"1\"\n age: int" + .to_string(), + }), + ]; + + match got.contents { + lsp_types::HoverContents::Array(vec) => { + assert_eq!(vec, expect_content); + } + _ => unreachable!("test error"), + } + } + + #[test] + #[bench_test] + fn dict_key_in_schema() { + let (file, _program, _, gs, _) = + compile_test_file("src/test_data/hover_test/dict_key_in_schema/dict_key_in_schema.k"); + let pos = KCLPos { + filename: file.clone(), + line: 5, + column: Some(5), + }; + let got = hover(&pos, &gs).unwrap(); + + match got.contents { + lsp_types::HoverContents::Scalar(marked_string) => { + if let MarkedString::LanguageString(s) = marked_string { + assert_eq!(s.value, "name: int"); + } + } + _ => unreachable!("test error"), + } + + let pos = KCLPos { + filename: file.clone(), + line: 9, + column: Some(5), + }; + let got = hover(&pos, &gs).unwrap(); + let expected = + lsp_types::HoverContents::Scalar(MarkedString::LanguageString(LanguageString { + language: "KCL".to_string(), + value: "name: int".to_string(), + })); + assert_eq!(got.contents, expected); + + let pos = KCLPos { + filename: file.clone(), + line: 13, + column: Some(5), + }; + let got = hover(&pos, &gs).unwrap(); + let expected = + lsp_types::HoverContents::Scalar(MarkedString::LanguageString(LanguageString { + language: "KCL".to_string(), + value: "name: int".to_string(), + })); + assert_eq!(got.contents, expected); + } +} diff --git a/kclvm/tools/src/LSP/src/inlay_hints.rs b/kclvm/tools/src/LSP/src/inlay_hints.rs new file mode 100644 index 000000000..11f8e7da4 --- /dev/null +++ b/kclvm/tools/src/LSP/src/inlay_hints.rs @@ -0,0 +1,180 @@ +use indexmap::{IndexMap, IndexSet}; +use kclvm_sema::core::global_state::GlobalState; +use kclvm_sema::core::symbol::{SymbolHint, SymbolHintKind}; +use lsp_types::{ + InlayHint, InlayHintKind, InlayHintLabelPart, Position as LspPosition, Range, TextEdit, +}; +use std::hash::Hash; + +use crate::to_lsp::lsp_pos; + +#[derive(Clone, Debug)] +struct KCLInlayHint { + /// The position of this hint. + pub position: LspPosition, + + /// An inlay hint label part allows for interactive and composite labels + /// of inlay hints. + pub part: InlayHintLabelPart, + + pub kind: InlayHintKind, + + /// Optional text edits that are performed when accepting(e.g. double-click in VSCode) this inlay hint. + pub text_edits: Option>, +} + +impl Hash for KCLInlayHint { + fn hash(&self, state: &mut H) { + self.position.line.hash(state); + self.position.character.hash(state); + self.part.value.hash(state); + } +} + +impl PartialEq for KCLInlayHint { + fn eq(&self, other: &Self) -> bool { + self.position == other.position && self.part.value == other.part.value + } +} + +impl Eq for KCLInlayHint {} + +pub fn inlay_hints(file: &str, gs: &GlobalState) -> Option> { + let mut inlay_hints: IndexSet = Default::default(); + let sema_db = gs.get_sema_db(); + if let Some(file_sema) = sema_db.get_file_sema(file) { + let mut line_hint: IndexMap = IndexMap::new(); + for hint in file_sema.get_hints() { + match &hint.kind { + SymbolHintKind::KeyTypeHint(_) => match line_hint.get(&hint.pos.line) { + Some(h) => { + if hint.pos.column.unwrap_or_default() > h.pos.column.unwrap_or_default() { + line_hint.insert(hint.pos.line, hint.clone()); + } + } + None => { + line_hint.insert(hint.pos.line, hint.clone()); + } + }, + _ => { + inlay_hints.insert(generate_inlay_hint(hint)); + } + } + } + inlay_hints.extend(line_hint.values().map(|h| generate_inlay_hint(h))); + } + + Some( + inlay_hints + .into_iter() + .map(|h| into_lsp_inlay_hint(&h)) + .collect(), + ) +} +#[inline] +fn generate_inlay_hint(hint: &SymbolHint) -> KCLInlayHint { + let (part, position, kind) = get_hint_label(hint); + let text_edits = match hint.kind { + SymbolHintKind::TypeHint(_) => Some(vec![TextEdit { + range: Range { + start: position.clone(), + end: position.clone(), + }, + new_text: part.value.clone(), + }]), + SymbolHintKind::VarHint(_) => None, + SymbolHintKind::KeyTypeHint(_) => None, + }; + KCLInlayHint { + position, + part, + kind, + text_edits, + } +} + +#[inline] +fn into_lsp_inlay_hint(hint: &KCLInlayHint) -> InlayHint { + InlayHint { + position: hint.position.clone(), + label: lsp_types::InlayHintLabel::LabelParts(vec![hint.part.clone()]), + kind: Some(hint.kind), + text_edits: hint.text_edits.clone(), + tooltip: None, + padding_left: None, + padding_right: None, + data: None, + } +} + +fn get_hint_label(hint: &SymbolHint) -> (InlayHintLabelPart, LspPosition, InlayHintKind) { + match &hint.kind { + SymbolHintKind::TypeHint(ty) => ( + InlayHintLabelPart { + value: format!(": {ty}"), + ..Default::default() + }, + lsp_pos(&hint.pos), + InlayHintKind::TYPE, + ), + SymbolHintKind::VarHint(var) => ( + InlayHintLabelPart { + value: format!("{var}: "), + ..Default::default() + }, + lsp_pos(&hint.pos), + InlayHintKind::PARAMETER, + ), + SymbolHintKind::KeyTypeHint(ty) => ( + InlayHintLabelPart { + value: format!(": {ty}"), + ..Default::default() + }, + lsp_pos(&hint.pos), + InlayHintKind::TYPE, + ), + } +} + +#[cfg(test)] +mod tests { + use super::inlay_hints; + use crate::tests::compile_test_file; + + #[macro_export] + macro_rules! inlay_hints_test_snapshot { + ($name:ident, $file:expr) => { + #[test] + fn $name() { + let (file, _, _, gs, _) = compile_test_file($file); + let res = inlay_hints(&file, &gs); + insta::assert_snapshot!(format!("{:#?}", res)); + } + }; + } + + inlay_hints_test_snapshot!( + test_assign_stmt_type_hint, + "src/test_data/inlay_hints/assign_stmt_type_hint/assign_stmt_type_hint.k" + ); + + inlay_hints_test_snapshot!( + test_function_call_arg_hint, + "src/test_data/inlay_hints/function_call/function_call.k" + ); + + inlay_hints_test_snapshot!( + test_schema_arg_hint, + "src/test_data/inlay_hints/schema_args/schema_args_hint.k" + ); + + inlay_hints_test_snapshot!( + test_config_key_ty, + "src/test_data/inlay_hints/config_key/config_key.k" + ); + + inlay_hints_test_snapshot!( + test_config_key_ty_1, + "src/test_data/inlay_hints/config_key1/config_key.k" + ); +} diff --git a/kclvm/tools/src/LSP/src/lib.rs b/kclvm/tools/src/LSP/src/lib.rs new file mode 100644 index 000000000..0a306581b --- /dev/null +++ b/kclvm/tools/src/LSP/src/lib.rs @@ -0,0 +1,27 @@ +pub mod analysis; +pub mod capabilities; +pub mod completion; +pub mod document_symbol; +pub mod find_refs; +pub mod formatting; +pub mod goto_def; +pub mod hover; +pub mod inlay_hints; +pub mod quick_fix; +pub mod rename; +pub mod request; +pub mod semantic_token; +pub mod signature_help; + +pub mod app; +pub mod compile; +mod dispatcher; +mod error; +pub mod from_lsp; +mod notification; +mod state; +#[cfg(test)] +mod tests; +pub mod to_lsp; +mod util; +mod word_index; diff --git a/kclvm/tools/src/LSP/src/main.rs b/kclvm/tools/src/LSP/src/main.rs new file mode 100644 index 000000000..7f26bff06 --- /dev/null +++ b/kclvm/tools/src/LSP/src/main.rs @@ -0,0 +1,95 @@ +mod analysis; +mod app; +mod capabilities; +mod compile; +mod completion; +mod dispatcher; +mod document_symbol; +mod error; +mod find_refs; +mod formatting; +mod from_lsp; +mod goto_def; +mod hover; +mod inlay_hints; +mod notification; +mod quick_fix; +mod request; +mod semantic_token; +mod signature_help; +mod state; +mod to_lsp; +mod util; +mod word_index; + +#[cfg(test)] +mod tests; + +use app::{app, main_loop}; + +/// Main entry point for the `kcl-language-server` executable. +fn main() -> Result<(), anyhow::Error> { + let args: Vec = std::env::args().collect(); + let matches = app() + .arg_required_else_help(false) + .try_get_matches_from(args); + match matches { + Ok(arg_matches) => match arg_matches.subcommand() { + Some(("version", _)) => { + println!("{}", kclvm_version::get_version_info()); + Ok(()) + } + Some((subcommand, _)) => Err(anyhow::anyhow!("unknown subcommand: {}", subcommand)), + None => { + let status: Result = { + run_server().map_err(|e| anyhow::anyhow!("{}", e))?; + Ok(ExitStatus::Success) + }; + match status.unwrap() { + ExitStatus::Success => {} + ExitStatus::Error => std::process::exit(1), + }; + Ok(()) + } + }, + Err(e) => e.exit(), + } +} + +#[allow(dead_code)] +/// Main entry point for the language server +fn run_server() -> anyhow::Result<()> { + // Setup IO connections + let (connection, io_threads) = lsp_server::Connection::stdio(); + // Wait for a client to connect + let (initialize_id, initialize_params) = connection.initialize_start()?; + + let initialize_params = + util::from_json::("InitializeParams", initialize_params)?; + + let server_capabilities = capabilities::server_capabilities(&initialize_params.capabilities); + + let initialize_result = lsp_types::InitializeResult { + capabilities: server_capabilities, + server_info: Some(lsp_types::ServerInfo { + name: String::from("kcl-language-server"), + version: None, + }), + offset_encoding: None, + }; + + let initialize_result = serde_json::to_value(initialize_result) + .map_err(|_| anyhow::anyhow!("Initialize result error"))?; + + connection.initialize_finish(initialize_id, initialize_result)?; + main_loop(connection, initialize_params)?; + io_threads.join()?; + Ok(()) +} + +#[allow(dead_code)] +#[derive(Copy, Debug, Clone, PartialEq, Eq)] +enum ExitStatus { + Success, + Error, +} diff --git a/kclvm/tools/src/LSP/src/notification.rs b/kclvm/tools/src/LSP/src/notification.rs new file mode 100644 index 000000000..f73b7488a --- /dev/null +++ b/kclvm/tools/src/LSP/src/notification.rs @@ -0,0 +1,139 @@ +use lsp_types::notification::{ + Cancel, DidChangeTextDocument, DidChangeWatchedFiles, DidCloseTextDocument, + DidOpenTextDocument, DidSaveTextDocument, +}; +use std::collections::HashSet; + +use crate::util::apply_document_changes; +use crate::{ + analysis::OpenFileInfo, dispatcher::NotificationDispatcher, from_lsp, + state::LanguageServerState, +}; + +impl LanguageServerState { + pub fn on_notification( + &mut self, + notification: lsp_server::Notification, + ) -> anyhow::Result<()> { + NotificationDispatcher::new(self, notification) + .on::(LanguageServerState::on_did_open_text_document)? + .on::(LanguageServerState::on_did_change_text_document)? + .on::(LanguageServerState::on_did_save_text_document)? + .on::(LanguageServerState::on_did_close_text_document)? + .on::(LanguageServerState::on_did_change_watched_files)? + .on::(LanguageServerState::cancel)? + .finish(); + Ok(()) + } + + fn cancel(&mut self, params: lsp_types::CancelParams) -> anyhow::Result<()> { + let id: lsp_server::RequestId = match params.id { + lsp_types::NumberOrString::Number(id) => id.into(), + lsp_types::NumberOrString::String(id) => id.into(), + }; + self.request_queue.incoming.complete(&id); + Ok(()) + } + + /// Called when a `DidOpenTextDocument` notification was received. + fn on_did_open_text_document( + &mut self, + params: lsp_types::DidOpenTextDocumentParams, + ) -> anyhow::Result<()> { + let path = from_lsp::abs_path(¶ms.text_document.uri)?; + self.log_message(format!("on did open file: {:?}", path)); + let mut vfs = self.vfs.write(); + vfs.set_file_contents( + path.clone().into(), + Some(params.text_document.text.into_bytes()), + ); + if let Some(id) = vfs.file_id(&path.into()) { + self.opened_files.write().insert( + id, + OpenFileInfo { + version: params.text_document.version, + workspaces: HashSet::new(), + }, + ); + } + Ok(()) + } + + /// Called when a `DidChangeTextDocument` notification was received. + fn on_did_save_text_document( + &mut self, + params: lsp_types::DidSaveTextDocumentParams, + ) -> anyhow::Result<()> { + let lsp_types::DidSaveTextDocumentParams { + text_document, + text: _, + } = params; + + let path = from_lsp::abs_path(&text_document.uri)?; + self.log_message(format!("on did save file: {:?}", path)); + Ok(()) + } + + /// Called when a `DidChangeTextDocument` notification was received. + fn on_did_change_text_document( + &mut self, + params: lsp_types::DidChangeTextDocumentParams, + ) -> anyhow::Result<()> { + let lsp_types::DidChangeTextDocumentParams { + text_document, + content_changes, + } = params; + + let path = from_lsp::abs_path(&text_document.uri)?; + self.log_message(format!("on did_change file: {:?}", path)); + + // Update vfs + let vfs = &mut *self.vfs.write(); + let file_id = vfs + .file_id(&path.clone().into()) + .ok_or(anyhow::anyhow!("Already checked that the file_id exists!"))?; + + let mut text = String::from_utf8(vfs.file_contents(file_id).to_vec())?; + apply_document_changes(&mut text, content_changes); + vfs.set_file_contents(path.into(), Some(text.clone().into_bytes())); + let mut opened_files = self.opened_files.write(); + let file_info = opened_files.get_mut(&file_id).unwrap(); + file_info.version = text_document.version; + drop(opened_files); + + Ok(()) + } + + /// Called when a `DidCloseTextDocument` notification was received. + fn on_did_close_text_document( + &mut self, + params: lsp_types::DidCloseTextDocumentParams, + ) -> anyhow::Result<()> { + let path = from_lsp::abs_path(¶ms.text_document.uri)?; + self.log_message(format!("on did_close file: {:?}", path)); + + if let Some(id) = self.vfs.read().file_id(&path.clone().into()) { + self.opened_files.write().remove(&id); + } + + // Update vfs + let vfs = &mut *self.vfs.write(); + vfs.set_file_contents(path.clone().into(), None); + self.loader.handle.invalidate(path); + + Ok(()) + } + + /// Called when a `DidChangeWatchedFiles` was received + fn on_did_change_watched_files( + &mut self, + params: lsp_types::DidChangeWatchedFilesParams, + ) -> anyhow::Result<()> { + for change in params.changes { + let path = from_lsp::abs_path(&change.uri)?; + self.loader.handle.invalidate(path.clone()); + } + + Ok(()) + } +} diff --git a/kclvm/tools/src/LSP/src/quick_fix.rs b/kclvm/tools/src/LSP/src/quick_fix.rs new file mode 100644 index 000000000..0810c04c2 --- /dev/null +++ b/kclvm/tools/src/LSP/src/quick_fix.rs @@ -0,0 +1,273 @@ +use std::collections::HashMap; + +use kclvm_error::{DiagnosticId, ErrorKind, WarningKind}; +use lsp_types::{ + CodeAction, CodeActionKind, CodeActionOrCommand, Diagnostic, NumberOrString, TextEdit, Url, +}; +use serde_json::Value; + +pub fn quick_fix(uri: &Url, diags: &[Diagnostic]) -> Vec { + let mut code_actions: Vec = vec![]; + for diag in diags { + if let Some(code) = &diag.code { + if let Some(id) = convert_code_to_kcl_diag_id(code) { + match id { + DiagnosticId::Error(error) => match error { + ErrorKind::CompileError => { + let replacement_texts = extract_suggested_replacements(&diag.data); + for replacement_text in replacement_texts { + let mut changes = HashMap::new(); + changes.insert( + uri.clone(), + vec![TextEdit { + range: diag.range, + new_text: replacement_text.clone(), + }], + ); + + let action_title = if replacement_text.is_empty() { + "Consider removing the problematic code".to_string() + } else { + format!( + "A local variable with a similar name exists: `{}`", + replacement_text + ) + }; + + code_actions.push(CodeActionOrCommand::CodeAction(CodeAction { + title: action_title, + kind: Some(CodeActionKind::QUICKFIX), + diagnostics: Some(vec![diag.clone()]), + edit: Some(lsp_types::WorkspaceEdit { + changes: Some(changes), + ..Default::default() + }), + ..Default::default() + })); + } + } + ErrorKind::InvalidSyntax => { + let replacement_texts = extract_suggested_replacements(&diag.data); + for replacement_text in replacement_texts { + let title = "Consider fix the problematic code".to_string(); + let mut changes = HashMap::new(); + changes.insert( + uri.clone(), + vec![TextEdit { + range: diag.range, + new_text: replacement_text.clone(), + }], + ); + code_actions.push(CodeActionOrCommand::CodeAction(CodeAction { + title, + kind: Some(CodeActionKind::QUICKFIX), + diagnostics: Some(vec![diag.clone()]), + edit: Some(lsp_types::WorkspaceEdit { + changes: Some(changes), + ..Default::default() + }), + ..Default::default() + })); + } + } + _ => continue, + }, + DiagnosticId::Warning(warn) => match warn { + WarningKind::UnusedImportWarning => { + let mut changes = HashMap::new(); + changes.insert( + uri.clone(), + vec![TextEdit { + range: diag.range, + new_text: "".to_string(), + }], + ); + code_actions.push(CodeActionOrCommand::CodeAction(CodeAction { + title: WarningKind::UnusedImportWarning.name(), + kind: Some(CodeActionKind::QUICKFIX), + diagnostics: Some(vec![diag.clone()]), + edit: Some(lsp_types::WorkspaceEdit { + changes: Some(changes), + ..Default::default() + }), + ..Default::default() + })) + } + WarningKind::ReimportWarning => { + let mut changes = HashMap::new(); + changes.insert( + uri.clone(), + vec![TextEdit { + range: diag.range, + new_text: "".to_string(), + }], + ); + code_actions.push(CodeActionOrCommand::CodeAction(CodeAction { + title: WarningKind::ReimportWarning.name(), + kind: Some(CodeActionKind::QUICKFIX), + diagnostics: Some(vec![diag.clone()]), + edit: Some(lsp_types::WorkspaceEdit { + changes: Some(changes), + ..Default::default() + }), + ..Default::default() + })) + } + _ => continue, + }, + DiagnosticId::Suggestions => continue, + } + } + } + } + code_actions +} + +fn extract_suggested_replacements(data: &Option) -> Vec { + data.as_ref() + .and_then(|data| match data { + Value::Object(obj) => obj.get("suggested_replacement").map(|val| match val { + Value::String(s) => vec![s.clone()], + Value::Array(arr) => arr + .iter() + .filter_map(|v| v.as_str().map(String::from)) + .collect(), + _ => vec![], + }), + _ => None, + }) + .unwrap_or_default() +} + +pub(crate) fn convert_code_to_kcl_diag_id(code: &NumberOrString) -> Option { + match code { + NumberOrString::Number(_) => None, + NumberOrString::String(code) => match code.as_str() { + "CompilerWarning" => Some(DiagnosticId::Warning(WarningKind::CompilerWarning)), + "UnusedImportWarning" => Some(DiagnosticId::Warning(WarningKind::UnusedImportWarning)), + "ReimportWarning" => Some(DiagnosticId::Warning(WarningKind::ReimportWarning)), + "CompileError" => Some(DiagnosticId::Error(ErrorKind::CompileError)), + "InvalidSyntax" => Some(DiagnosticId::Error(ErrorKind::InvalidSyntax)), + "ImportPositionWarning" => { + Some(DiagnosticId::Warning(WarningKind::ImportPositionWarning)) + } + _ => None, + }, + } +} + +#[cfg(test)] +mod tests { + use lsp_types::{ + CodeAction, CodeActionKind, CodeActionOrCommand, Diagnostic, Position, Range, TextEdit, + Url, WorkspaceEdit, + }; + use proc_macro_crate::bench_test; + use std::path::PathBuf; + + use super::quick_fix; + use crate::{ + compile::{compile_with_params, Params}, + state::KCLVfs, + to_lsp::kcl_diag_to_lsp_diags_by_file, + }; + + #[test] + #[bench_test] + fn quick_fix_test() { + let path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + let test_file = path.clone(); + let test_file = test_file + .join("src") + .join("test_data") + .join("code_action") + .join("quick_fix") + .join("quick_fix.k"); + let file = test_file.to_str().unwrap(); + + let diags = compile_with_params(Params { + file: Some(file.to_string()), + module_cache: None, + scope_cache: None, + vfs: Some(KCLVfs::default()), + gs_cache: None, + }) + .0; + + let diagnostics = diags + .iter() + .flat_map(|diag| kcl_diag_to_lsp_diags_by_file(diag, file)) + .collect::>(); + + let uri = Url::from_file_path(file).unwrap(); + let code_actions = quick_fix(&uri, &diagnostics); + + let expected = vec![ + CodeActionOrCommand::CodeAction(CodeAction { + title: "ReimportWarning".to_string(), + kind: Some(CodeActionKind::QUICKFIX), + diagnostics: Some(vec![diagnostics[0].clone()]), + edit: Some(WorkspaceEdit { + changes: Some( + vec![( + uri.clone(), + vec![TextEdit { + range: Range { + start: Position { + line: 1, + character: 0, + }, + end: Position { + line: 1, + character: 20, + }, + }, + new_text: "".to_string(), + }], + )] + .into_iter() + .collect(), + ), + ..Default::default() + }), + ..Default::default() + }), + CodeActionOrCommand::CodeAction(CodeAction { + title: "UnusedImportWarning".to_string(), + kind: Some(CodeActionKind::QUICKFIX), + diagnostics: Some(vec![diagnostics[1].clone()]), + edit: Some(WorkspaceEdit { + changes: Some( + vec![( + uri.clone(), + vec![TextEdit { + range: Range { + start: Position { + line: 0, + character: 0, + }, + end: Position { + line: 0, + character: 20, + }, + }, + new_text: "".to_string(), + }], + )] + .into_iter() + .collect(), + ), + ..Default::default() + }), + ..Default::default() + }), + ]; + + for (get, expected) in code_actions.iter().zip(expected.iter()) { + assert_eq!(get, expected) + } + + assert_eq!(expected[0], code_actions[0]); + assert_eq!(expected[1], code_actions[1]); + } +} diff --git a/kclvm/tools/src/LSP/src/rename.rs b/kclvm/tools/src/LSP/src/rename.rs new file mode 100644 index 000000000..6a0c74fea --- /dev/null +++ b/kclvm/tools/src/LSP/src/rename.rs @@ -0,0 +1,907 @@ +use crate::state::KCLVfs; +use crate::word_index::{build_virtual_word_index, VirtualLocation}; +use crate::{from_lsp::kcl_pos, goto_def::find_def}; +use anyhow::{anyhow, Result}; +use kclvm_ast::ast::{self, Program}; +use kclvm_error::diagnostic; +use kclvm_parser::{load_program, LoadProgramOptions, ParseSessionRef}; +use kclvm_query::{path::parse_attribute_path, selector::parse_symbol_selector_spec}; +use kclvm_sema::{ + advanced_resolver::AdvancedResolver, core::global_state::GlobalState, namer::Namer, + resolver::resolve_program_with_opts, +}; +use lsp_types::{Position, Range, TextEdit}; +use ra_ap_vfs::VfsPath; +use std::collections::{HashMap, HashSet}; +use std::fs; +use std::path::PathBuf; + +/// [`rename_symbol_on_file`] will rename the symbol in the given files +/// It will load the file content from file system and save to vfs, and then call [`rename_symbol`] to rename the symbol +pub fn rename_symbol_on_file( + pkg_root: &str, + symbol_path: &str, + file_paths: &[String], + new_name: String, +) -> Result> { + // load file content from file system and save to vfs + let vfs = KCLVfs::default(); + let mut source_codes = HashMap::::new(); + for path in file_paths { + let content = fs::read_to_string(path.clone())?; + vfs.write().set_file_contents( + VfsPath::new_real_path(path.to_string()), + Some(content.clone().into_bytes()), + ); + source_codes.insert(path.to_string(), content.clone()); + } + let changes = rename_symbol(pkg_root, vfs, symbol_path, new_name, VfsPath::new_real_path)?; + let new_codes = apply_rename_changes(&changes, source_codes)?; + let mut changed_paths = vec![]; + for (path, content) in new_codes.iter() { + fs::write(path.clone(), content)?; + changed_paths.push(path.clone()); + } + Ok(changed_paths) +} + +/// [`rename_symbol_on_code`] will rename the symbol in the given code +/// It will create a vfs from the file paths and codes, and then call [`rename_symbol`] to rename the symbol +pub fn rename_symbol_on_code( + pkg_root: &str, + symbol_path: &str, + source_codes: HashMap, + new_name: String, +) -> Result> { + // prepare a vfs from given file_paths + let vfs = KCLVfs::default(); + let f = if source_codes.keys().all(|path| path.starts_with("/")) { + VfsPath::new_virtual_path + } else { + VfsPath::new_real_path + }; + + for (filepath, code) in &source_codes { + vfs.write() + .set_file_contents(f(filepath.clone()), Some(code.as_bytes().to_vec())); + } + let changes: HashMap> = + rename_symbol(pkg_root, vfs, symbol_path, new_name, f)?; + apply_rename_changes(&changes, source_codes) +} + +fn package_path_to_file_path(pkg_path: &str, vfs: KCLVfs) -> Vec { + let pkg = PathBuf::from(pkg_path); + let vfs_read = vfs.read(); + let mut result: Vec = vec![]; + + // first search as directory(KCL package in the strict sense) + result.extend(vfs_read.iter().filter_map(|(_, vfs_path)| { + let path = PathBuf::from(vfs_path.to_string()); + if let Some(parent) = path.parent() { + if parent == pkg { + return Some(vfs_path.to_string()); + } + } + None + })); + + if result.is_empty() { + // then search as file(KCL module) + result.extend(vfs_read.iter().filter_map(|(_, vfs_path)| { + let path = PathBuf::from(vfs_path.to_string()); + if pkg.with_extension("k") == path { + return Some(vfs_path.to_string()); + } + None + })); + } + + result +} + +/// Select a symbol by the symbol path +/// The symbol path should be in the format of: `pkg.sub_pkg:name.sub_name` +/// returns the symbol name and definition range +fn select_symbol( + symbol_spec: &ast::SymbolSelectorSpec, + vfs: KCLVfs, + trans_vfs_path: F, +) -> Option<(String, diagnostic::Range)> +where + F: Fn(String) -> VfsPath, +{ + let mut pkg = PathBuf::from(&symbol_spec.pkg_root); + let fields = parse_attribute_path(&symbol_spec.field_path).unwrap_or_default(); + if !symbol_spec.pkgpath.is_empty() { + let pkg_names = symbol_spec.pkgpath.split('.'); + for n in pkg_names { + pkg = pkg.join(n) + } + } + let pkg_path = pkg.as_path().to_str().unwrap(); + + let file_paths = package_path_to_file_path(pkg_path, vfs.clone()); + + if let Ok((_, gs)) = parse_files_with_vfs( + pkg_path.to_string(), + file_paths, + vfs.clone(), + trans_vfs_path, + ) { + if let Some(symbol_ref) = gs + .get_symbols() + .get_symbol_by_fully_qualified_name(kclvm_ast::MAIN_PKG) + { + let mut owner_ref = symbol_ref; + let mut target = None; + for field in &fields { + let owner = gs.get_symbols().get_symbol(owner_ref).unwrap(); + target = owner.get_attribute(field, gs.get_symbols(), None); + if let Some(target) = target { + owner_ref = target; + } + } + let target_symbol = gs.get_symbols().get_symbol(target?)?; + return Some((target_symbol.get_name(), target_symbol.get_range().clone())); + } + } + None +} + +fn parse_files_with_vfs( + work_dir: String, + file_paths: Vec, + vfs: KCLVfs, + trans_vfs_path: F, +) -> anyhow::Result<(Program, GlobalState)> +where + F: Fn(String) -> VfsPath, +{ + let opts = LoadProgramOptions { + work_dir, + load_plugins: true, + k_code_list: { + let mut list = vec![]; + let vfs = &vfs.read(); + for file in &file_paths { + if let Some(id) = vfs.file_id(&trans_vfs_path(file.clone())) { + // Load code from vfs + list.push(String::from_utf8(vfs.file_contents(id).to_vec()).unwrap()); + } + } + list + }, + ..Default::default() + }; + let files: Vec<&str> = file_paths.iter().map(|s| s.as_str()).collect(); + let sess: ParseSessionRef = ParseSessionRef::default(); + let mut program = load_program(sess.clone(), &files, Some(opts), None)?.program; + + let prog_scope = resolve_program_with_opts( + &mut program, + kclvm_sema::resolver::Options { + merge_program: false, + type_erasure: false, + ..Default::default() + }, + None, + ); + + let mut gs = GlobalState::default(); + Namer::find_symbols(&program, &mut gs); + let node_ty_map = prog_scope.node_ty_map; + AdvancedResolver::resolve_program(&program, &mut gs, node_ty_map)?; + + Ok((program, gs)) +} + +fn apply_rename_changes( + changes: &HashMap>, + source_codes: HashMap, +) -> Result> { + let mut result = HashMap::new(); + for (file_path, edits) in changes { + let file_content = source_codes + .get(file_path) + .ok_or(anyhow!("File content is None"))? + .to_string(); + let file_content_lines: Vec<&str> = file_content.lines().collect(); + let mut updated_lines: Vec = file_content_lines + .iter() + .map(|&line| line.to_string()) + .collect(); + + let mut to_removed = HashSet::new(); + + for edit in edits { + let start_line = edit.range.start.line as usize; + let end_line = edit.range.end.line as usize; + + if start_line == end_line { + // the text edit belongs to a single line + let line = &file_content_lines[start_line]; + let updated_line = apply_text_edit(edit, line); + updated_lines[start_line] = updated_line; + } else { + let start_line_text = &file_content_lines[start_line]; + let end_line_text = &file_content_lines[end_line]; + let start_line_edit = TextEdit { + range: Range { + start: edit.range.start, + end: Position { + line: edit.range.start.line, + character: start_line_text.len() as u32, + }, + }, + new_text: edit.new_text.clone(), + }; + let end_line_edit = TextEdit { + range: Range { + start: Position { + line: edit.range.end.line, + character: 0, + }, + end: edit.range.end, + }, + new_text: String::new(), + }; + let updated_start_line = apply_text_edit(&start_line_edit, start_line_text); + let updated_end_line = apply_text_edit(&end_line_edit, end_line_text); + updated_lines[start_line] = format!("{}{}", updated_start_line, updated_end_line); + + for line_num in (start_line + 1)..end_line + 1 { + // todo, record lines to be deleted, instead of update to empty string + // from start+1 to end + updated_lines[line_num] = String::new(); + to_removed.insert(line_num); + } + } + } + + let retained_lines: Vec<_> = updated_lines + .into_iter() + .enumerate() + .filter(|(index, _)| !to_removed.contains(index)) + .map(|(_, item)| item.to_string()) + .collect(); + + let new_file_content = retained_lines.join("\n"); + result.insert(file_path.to_string(), new_file_content); + } + Ok(result) +} + +/// apply_text_edit applys the text edit to a single line +fn apply_text_edit(edit: &TextEdit, line: &str) -> String { + let range = edit.range; + let start = range.start.character as usize; + let end = range.end.character as usize; + + let mut updated_line = line.to_owned(); + updated_line.replace_range(start..end, &edit.new_text); + updated_line +} + +/// match_pkgpath_and_code matches the pkgpath and code from the symbol selector spec +pub fn match_pkgpath_and_code( + selector: &ast::SymbolSelectorSpec, +) -> (Option, Option) { + let mut pkg = PathBuf::from(&selector.pkg_root); + let pkg_names = selector.pkgpath.split('.'); + if !selector.pkgpath.is_empty() { + for n in pkg_names { + pkg = pkg.join(n) + } + } + + match pkg.as_path().to_str() { + Some(pkgpath) => (Some(pkgpath.to_string()), None), + None => (None, None), + } +} + +/// Find all the occurrences of the target symbol and return the text edit actions to rename them. +/// +/// ## Parameters +/// - pkg_root: the absolute file path to the root package +/// - vfs: contains all the files and contents to be renamed +/// - symbol_path: path to the symbol. The symbol path should be in the format of: `pkg.sub_pkg:name.sub_name` +/// - new_name: the new name of the symbol +pub fn rename_symbol( + pkg_root: &str, + vfs: KCLVfs, + symbol_path: &str, + new_name: String, + trans_vfs_path: F, +) -> Result>> +where + F: Fn(String) -> VfsPath, +{ + // 1. from symbol path to the symbol + let symbol_spec = parse_symbol_selector_spec(pkg_root, symbol_path)?; + // 2. get the symbol name and definition range from symbol path + match select_symbol(&symbol_spec, vfs.clone(), &trans_vfs_path) { + Some((name, range)) => { + // 3. build word index, find refs within given scope + // vfs to source code contents + let mut source_codes = HashMap::::new(); + let vfs_content = vfs.read(); + for (file_id, vfspath) in vfs_content.iter() { + let content = std::str::from_utf8(vfs_content.file_contents(file_id)).unwrap(); + source_codes.insert(vfspath.to_string(), content.to_string()); + } + let word_index = build_virtual_word_index(source_codes, true)?; + if let Some(locations) = word_index.get(&name) { + // 4. filter out the matched refs + // 4.1 collect matched words(names) and remove Duplicates of the file paths + let file_map = locations.iter().fold( + HashMap::>::new(), + |mut acc, loc| { + acc.entry(loc.filepath.clone()).or_default().push(loc); + acc + }, + ); + let mut refs = vec![]; + for (fp, locs) in file_map.iter() { + if let Ok((_, gs)) = parse_files_with_vfs( + pkg_root.to_string(), + vec![fp.to_string()], + vfs.clone(), + &trans_vfs_path, + ) { + for loc in locs { + let kcl_pos = kcl_pos(fp, loc.range.start); + if let Some(symbol_ref) = find_def(&kcl_pos, &gs, true) { + if let Some(symbol_def) = gs.get_symbols().get_symbol(symbol_ref) { + if symbol_def.get_range() == range { + refs.push(loc) + } + } + } + } + }; + } + // 5. refs to rename actions + let changes = refs.into_iter().fold(HashMap::new(), |mut map, location| { + map.entry(location.filepath.clone()) + .or_insert_with(Vec::new) + .push(TextEdit { + range: location.range, + new_text: new_name.clone(), + }); + map + }); + Ok(changes) + } else { + Ok(HashMap::new()) + } + } + None => Err(anyhow!( + "get symbol from symbol path failed, {}", + symbol_path + )), + } +} + +#[cfg(test)] +mod tests { + use kclvm_ast::ast; + use kclvm_error::diagnostic; + use lsp_types::{Position, Range, TextEdit}; + use maplit::hashmap; + use std::collections::{HashMap, HashSet}; + use std::fs; + use std::path::PathBuf; + + use crate::rename::rename_symbol_on_code; + + use super::{ + apply_rename_changes, package_path_to_file_path, rename_symbol, rename_symbol_on_file, + select_symbol, + }; + + use crate::state::KCLVfs; + use ra_ap_vfs::VfsPath; + + /// prepare_vfs constructs a vfs for test: + /// /mock_root + /// ├── config.k + /// └── base + /// ├── server.k + /// └── person.k + fn prepare_vfs() -> (PathBuf, PathBuf, PathBuf, PathBuf, PathBuf, KCLVfs) { + // mock paths + let root = PathBuf::from("/mock_root"); + let base_path = root.join("base"); + let server_path = root.join("base").join("server.k"); + let person_path = root.join("base").join("person.k"); + let config_path = root.join("config.k"); + // mock file contents + let person_content = r#"schema Person: + name: Name + age: int + +schema Name: + first: str + +a = { + abc: "d" +} + +d = a.abc +e = a["abc"] +"#; + let server_content = r#"schema Server: + name: str +"#; + let config_content = r#""#; + + // set vfs + let vfs = KCLVfs::default(); + vfs.write().set_file_contents( + VfsPath::new_virtual_path(person_path.as_path().to_str().unwrap().to_string()), + Some(person_content.as_bytes().to_owned()), + ); + vfs.write().set_file_contents( + VfsPath::new_virtual_path(server_path.as_path().to_str().unwrap().to_string()), + Some(server_content.as_bytes().to_owned()), + ); + vfs.write().set_file_contents( + VfsPath::new_virtual_path(config_path.as_path().to_str().unwrap().to_string()), + Some(config_content.as_bytes().to_owned()), + ); + + (root, base_path, person_path, server_path, config_path, vfs) + } + + #[test] + fn test_package_path_to_file_path() { + let (root, base_path, person_path, server_path, config_path, vfs) = prepare_vfs(); + + let files = package_path_to_file_path(base_path.as_path().to_str().unwrap(), vfs.clone()); + assert_eq!( + files, + vec![ + person_path.as_path().to_str().unwrap().to_string(), + server_path.as_path().to_str().unwrap().to_string() + ] + ); + + let files = package_path_to_file_path( + root.join("base").join("person").as_path().to_str().unwrap(), + vfs.clone(), + ); + assert_eq!( + files, + vec![person_path.as_path().to_str().unwrap().to_string()] + ); + + let files = + package_path_to_file_path(root.join("config").as_path().to_str().unwrap(), vfs.clone()); + assert_eq!( + files, + vec![config_path.as_path().to_str().unwrap().to_string()] + ); + } + + #[test] + fn test_select_symbol() { + let (root, _, person_path, server_path, _config_path, vfs) = prepare_vfs(); + let pkg_root = root.as_path().to_str().unwrap().to_string(); + + if let Some((name, range)) = select_symbol( + &ast::SymbolSelectorSpec { + pkg_root: pkg_root.clone(), + pkgpath: "base".to_string(), + field_path: "Person.name".to_string(), + }, + vfs.clone(), + VfsPath::new_virtual_path, + ) { + assert_eq!(name, "name"); + assert_eq!( + range, + ( + diagnostic::Position { + filename: person_path.as_path().to_str().unwrap().to_string(), + line: 2, + column: Some(4), + }, + diagnostic::Position { + filename: person_path.as_path().to_str().unwrap().to_string(), + line: 2, + column: Some(8), + }, + ) + ); + } else { + unreachable!("select symbol failed") + } + + if let Some((name, range)) = select_symbol( + &ast::SymbolSelectorSpec { + pkg_root: pkg_root.clone(), + pkgpath: "base".to_string(), + field_path: "Name.first".to_string(), + }, + vfs.clone(), + VfsPath::new_virtual_path, + ) { + assert_eq!(name, "first"); + assert_eq!( + range, + ( + diagnostic::Position { + filename: person_path.as_path().to_str().unwrap().to_string(), + line: 6, + column: Some(4), + }, + diagnostic::Position { + filename: person_path.as_path().to_str().unwrap().to_string(), + line: 6, + column: Some(9), + }, + ) + ); + } else { + unreachable!("select symbol failed") + } + + if let Some((name, range)) = select_symbol( + &ast::SymbolSelectorSpec { + pkg_root: pkg_root.clone(), + pkgpath: "base".to_string(), + field_path: "Person".to_string(), + }, + vfs.clone(), + VfsPath::new_virtual_path, + ) { + assert_eq!(name, "Person"); + assert_eq!( + range, + ( + diagnostic::Position { + filename: person_path.as_path().to_str().unwrap().to_string(), + line: 1, + column: Some(7), + }, + diagnostic::Position { + filename: person_path.as_path().to_str().unwrap().to_string(), + line: 1, + column: Some(13), + }, + ) + ); + } else { + unreachable!("select symbol failed") + } + + if let Some((name, range)) = select_symbol( + &ast::SymbolSelectorSpec { + pkg_root: pkg_root.clone(), + pkgpath: "base".to_string(), + field_path: "a".to_string(), + }, + vfs.clone(), + VfsPath::new_virtual_path, + ) { + assert_eq!(name, "a"); + assert_eq!( + range, + ( + diagnostic::Position { + filename: person_path.as_path().to_str().unwrap().to_string(), + line: 8, + column: Some(0), + }, + diagnostic::Position { + filename: person_path.as_path().to_str().unwrap().to_string(), + line: 8, + column: Some(1), + }, + ) + ); + } else { + unreachable!("select symbol failed") + } + + if let Some((name, range)) = select_symbol( + &ast::SymbolSelectorSpec { + pkg_root: pkg_root.clone(), + pkgpath: "base".to_string(), + field_path: "Server.name".to_string(), + }, + vfs.clone(), + VfsPath::new_virtual_path, + ) { + assert_eq!(name, "name"); + assert_eq!( + range, + ( + diagnostic::Position { + filename: server_path.as_path().to_str().unwrap().to_string(), + line: 2, + column: Some(4), + }, + diagnostic::Position { + filename: server_path.as_path().to_str().unwrap().to_string(), + line: 2, + column: Some(8), + }, + ) + ); + } else { + unreachable!("select symbol failed") + } + } + + #[test] + fn test_select_symbol_failed() { + let (root, _, _, _, _, vfs) = prepare_vfs(); + let pkg_root = root.as_path().to_str().unwrap().to_string(); + let result = select_symbol( + &ast::SymbolSelectorSpec { + pkg_root: pkg_root.clone(), + pkgpath: "base".to_string(), + field_path: "name".to_string(), + }, + vfs.clone(), + VfsPath::new_virtual_path, + ); + assert!(result.is_none(), "should not find the target symbol") + } + + #[test] + fn test_rename() { + let root = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + let root = root.join("src").join("test_data").join("rename_test"); + + let main_path = root.clone(); + let base_path = root.clone(); + let base_path = base_path.join("base").join("person.k"); + let main_path = main_path.join("config.k"); + + let base_path = base_path.to_str().unwrap(); + let main_path = main_path.to_str().unwrap(); + + let vfs = KCLVfs::default(); + for path in [base_path, main_path] { + let content = fs::read_to_string(path).unwrap(); + vfs.write().set_file_contents( + VfsPath::new_real_path(path.to_string()), + Some(content.into_bytes()), + ); + } + + if let Ok(changes) = rename_symbol( + root.to_str().unwrap(), + vfs.clone(), + "base:Person", + "NewPerson".to_string(), + VfsPath::new_real_path, + ) { + assert_eq!(changes.len(), 2); + assert!(changes.contains_key(base_path)); + assert!(changes.contains_key(main_path)); + assert!(changes.get(base_path).unwrap().len() == 1); + assert!(changes.get(base_path).unwrap()[0].range.start == Position::new(0, 7)); + assert!(changes.get(main_path).unwrap().len() == 1); + assert!(changes.get(main_path).unwrap()[0].range.start == Position::new(2, 9)); + assert!(changes.get(main_path).unwrap()[0].new_text == "NewPerson"); + } else { + unreachable!("rename failed") + } + + if let Ok(changes) = rename_symbol( + root.to_str().unwrap(), + vfs.clone(), + "base:Person.name", + "new_name".to_string(), + VfsPath::new_real_path, + ) { + assert_eq!(changes.len(), 2); + assert!(changes.contains_key(base_path)); + assert!(changes.contains_key(main_path)); + assert!(changes.get(base_path).unwrap().len() == 1); + assert!(changes.get(base_path).unwrap()[0].range.start == Position::new(1, 4)); + assert!(changes.get(main_path).unwrap().len() == 1); + assert!(changes.get(main_path).unwrap()[0].range.start == Position::new(4, 4)); + assert!(changes.get(main_path).unwrap()[0].new_text == "new_name"); + } else { + unreachable!("rename failed") + } + } + + #[test] + fn test_apply_rename_changes() { + let path = "/mock_root/main.k".to_string(); + let mut source_codes = HashMap::new(); + source_codes.insert( + path.clone(), + r#"import .pkg.vars + +Bob = vars.Person { + name: "Bob" + age: 30 +}"# + .to_string(), + ); + + struct TestCase { + changes: HashMap>, + expected: String, + } + + let test_cases = vec![TestCase { + changes: HashMap::from([( + path.clone(), + vec![TextEdit { + range: Range { + start: Position { + line: 2, + character: 11, + }, + end: Position { + line: 2, + character: 17, + }, + }, + new_text: "Person2".to_string(), + }], + )]), + expected: "import .pkg.vars\n\nBob = vars.Person2 {\n name: \"Bob\"\n age: 30\n}" + .to_string(), + }]; + + for test_case in test_cases { + let result = apply_rename_changes(&test_case.changes, source_codes.clone()); + assert_eq!(result.unwrap().get(&path).unwrap(), &test_case.expected); + } + } + + #[test] + fn test_rename_symbol_on_file() { + let root = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + let root = root + .join("src") + .join("test_data") + .join("rename_test") + .join("rename_on_file"); + + let main_path = root.clone(); + let base_path = root.clone(); + let main_path = main_path.join("config.k"); + let base_path = base_path.join("base").join("person.k"); + let base_path_string = base_path.to_str().unwrap().to_string(); + let main_path_string = main_path.to_str().unwrap().to_string(); + + // before test, back up the old file content + for path in [base_path.clone(), main_path.clone()] { + let content = fs::read_to_string(path.clone()).unwrap(); + let backup_path = path.with_extension("bak"); + fs::write(backup_path.clone(), content).unwrap(); + } + + let result = rename_symbol_on_file( + root.to_str().unwrap(), + "base:Person", + &[base_path_string.clone(), main_path_string.clone()], + "NewPerson".to_string(), + ); + let expect_changed_paths: HashSet<_> = [base_path_string.clone(), main_path_string.clone()] + .iter() + .cloned() + .collect(); + let got_changed_paths: HashSet<_> = result.unwrap().iter().cloned().collect(); + assert_eq!(expect_changed_paths, got_changed_paths); + let base_new_content = fs::read_to_string(base_path.clone()).unwrap(); + let main_new_content = fs::read_to_string(main_path.clone()).unwrap(); + assert_eq!( + base_new_content, + r#"schema NewPerson: + name: Name + age: int + +schema Name: + first: str + +a = { + abc: "d" +} + +d = a.abc +e = a["abc"]"# + ); + assert_eq!(main_new_content, "import .base\n\na = base.NewPerson {\n age: 1,\n name: {\n first: \"aa\"\n }\n}"); + + // after test, restore the old file content + for path in [base_path.clone(), main_path.clone()] { + let backup_path = path.with_extension("bak"); + let content = fs::read_to_string(backup_path.clone()).unwrap(); + fs::write(path.clone(), content).unwrap(); + fs::remove_file(backup_path.clone()).unwrap(); + } + } + + #[test] + fn test_rename_symbol_on_code() { + let root = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + + let root = root.join("src").join("test_data").join("rename_test"); + + let base_path = root.clone(); + let main_path = root.clone(); + + let base_path = base_path.join("base").join("person.k"); + let main_path = main_path.join("config.k"); + + let base_path_string = base_path.to_str().unwrap().to_string(); + let main_path_string = main_path.to_str().unwrap().to_string(); + + let base_source_code = r#"schema Person: + name: Name + age: int + +schema Name: + first: str + +a = { + abc: "d" +} + +d = a.abc +e = a["abc"]"#; + + let main_source_code = r#"import .base + +a = base.Person { + age: 1, + name: { + first: "aa" + } +}"#; + + let result: HashMap = rename_symbol_on_code( + root.to_str().unwrap(), + "base:Person", + hashmap! { + base_path_string.clone() => base_source_code.to_string(), + main_path_string.clone() => main_source_code.to_string(), + }, + "NewPerson".to_string(), + ) + .unwrap(); + + let base_new_content = result.get(base_path_string.clone().as_str()).unwrap(); + assert_eq!( + base_new_content, + r#"schema NewPerson: + name: Name + age: int + +schema Name: + first: str + +a = { + abc: "d" +} + +d = a.abc +e = a["abc"]"# + ); + + let main_new_content = result.get(main_path_string.clone().as_str()).unwrap(); + assert_eq!( + main_new_content, + r#"import .base + +a = base.NewPerson { + age: 1, + name: { + first: "aa" + } +}"# + ); + } +} diff --git a/kclvm/tools/src/LSP/src/request.rs b/kclvm/tools/src/LSP/src/request.rs new file mode 100644 index 000000000..3e43655a8 --- /dev/null +++ b/kclvm/tools/src/LSP/src/request.rs @@ -0,0 +1,500 @@ +use anyhow::anyhow; +use crossbeam_channel::Sender; + +use kclvm_driver::WorkSpaceKind; +use kclvm_sema::info::is_valid_kcl_name; +use lsp_types::{Location, SemanticTokensResult, TextEdit}; +use ra_ap_vfs::VfsPath; +use std::collections::HashMap; +use std::sync::Arc; +use std::time::Instant; + +use crate::{ + analysis::{AnalysisDatabase, DBState}, + completion::completion, + dispatcher::RequestDispatcher, + document_symbol::document_symbol, + error::LSPError, + find_refs::find_refs, + formatting::format, + from_lsp::{self, file_path_from_url, kcl_pos}, + goto_def::goto_def, + hover, + inlay_hints::inlay_hints, + quick_fix, + semantic_token::semantic_tokens_full, + signature_help::signature_help, + state::{log_message, LanguageServerSnapshot, LanguageServerState, Task}, +}; + +impl LanguageServerState { + /// Handles a language server protocol request + pub(super) fn on_request( + &mut self, + request: lsp_server::Request, + request_received: Instant, + ) -> anyhow::Result<()> { + self.register_request(&request, request_received); + + // If a shutdown was requested earlier, immediately respond with an error + if self.shutdown_requested { + self.respond(lsp_server::Response::new_err( + request.id, + lsp_server::ErrorCode::InvalidRequest as i32, + "shutdown was requested".to_owned(), + ))?; + return Ok(()); + } + + // Dispatch the event based on the type of event + RequestDispatcher::new(self, request) + .on_sync::(|state, _request| { + state.shutdown_requested = true; + Ok(()) + })? + .on::(handle_goto_definition)? + .on::(handle_reference)? + .on::(handle_hover)? + .on::(handle_document_symbol)? + .on::(handle_code_action)? + .on::(handle_formatting)? + .on::(handle_range_formatting)? + .on::(handle_rename)? + .on::(handle_semantic_tokens_full)? + .on::(handle_inlay_hint)? + .on::(handle_signature_help)? + .on_maybe_retry::(handle_completion)? + .finish(); + + Ok(()) + } +} + +impl LanguageServerSnapshot { + // defend against non-kcl files + pub(crate) fn verify_request_path(&self, path: &VfsPath, sender: &Sender) -> bool { + self.verify_vfs(path, sender) + } + + pub(crate) fn verify_vfs(&self, path: &VfsPath, sender: &Sender) -> bool { + let valid = self.vfs.read().file_id(path).is_some(); + if !valid { + let _ = log_message( + format!("Vfs not contains: {}, request failed", path), + sender, + ); + } + valid + } + + /// Attempts to get db in cache, this function does not block. + /// return Ok(Some(db)) -> Compile completed + /// return Ok(None) -> In compiling or rw lock, retry to wait compile completed + /// return Err(_) -> Compile failed + pub(crate) fn try_get_db( + &self, + path: &VfsPath, + sender: &Sender, + ) -> anyhow::Result>> { + match self.try_get_db_state(path) { + Ok(db) => match db { + Some((_, db)) => match db { + DBState::Ready(db) => Ok(Some(db.clone())), + DBState::Compiling(_) | DBState::Init => { + log_message( + format!("Try get {:?} db state: In compiling, retry", path), + sender, + )?; + Ok(None) + } + DBState::Failed(e) => { + log_message( + format!("Try get {:?} db state: Failed: {:?}", path, e), + sender, + )?; + Err(anyhow::anyhow!(e)) + } + }, + None => Ok(None), + }, + Err(e) => Err(e), + } + } + + /// Attempts to get db in cache, this function does not block. + /// return Ok(Some(db)) -> Compile completed + /// return Ok(None) -> RWlock, retry to unlock + /// return Err(_) -> Compile failed + pub(crate) fn try_get_db_state( + &self, + path: &VfsPath, + ) -> anyhow::Result> { + match self.vfs.try_read() { + Some(vfs) => match vfs.file_id(path) { + Some(file_id) => { + let open_file = self.opened_files.read(); + let file_info = open_file.get(&file_id).unwrap(); + match self.temporary_workspace.read().get(&file_id) { + Some(option_workspace) => match option_workspace { + Some(work_space) => match self.workspaces.try_read() { + Some(workspaces) => match workspaces.get(work_space) { + Some(db) => Ok(Some((work_space.clone(), db.clone()))), + None => Err(anyhow::anyhow!( + LSPError::AnalysisDatabaseNotFound(path.clone()) + )), + }, + None => Ok(None), + }, + None => Ok(None), + }, + + None => { + if file_info.workspaces.is_empty() { + return Err(anyhow::anyhow!(LSPError::WorkSpaceIsEmpty( + path.clone() + ))); + } + // todo: now just get first, need get all workspaces + let work_space = file_info.workspaces.iter().next().unwrap(); + match self.workspaces.try_read() { + Some(workspaces) => match workspaces.get(work_space) { + Some(db) => Ok(Some((work_space.clone(), db.clone()))), + None => Err(anyhow::anyhow!( + LSPError::AnalysisDatabaseNotFound(path.clone()) + )), + }, + None => Ok(None), + } + } + } + } + + None => Err(anyhow::anyhow!(LSPError::FileIdNotFound(path.clone()))), + }, + None => Ok(None), + } + } +} + +pub(crate) fn handle_semantic_tokens_full( + snapshot: LanguageServerSnapshot, + params: lsp_types::SemanticTokensParams, + sender: Sender, +) -> anyhow::Result> { + let file = file_path_from_url(¶ms.text_document.uri)?; + let path: VfsPath = from_lsp::abs_path(¶ms.text_document.uri)?.into(); + let db = match snapshot.try_get_db(&path, &sender) { + Ok(option_db) => match option_db { + Some(db) => db, + None => return Err(anyhow!(LSPError::Retry)), + }, + Err(_) => return Ok(None), + }; + let res = semantic_tokens_full(&file, &db.gs); + + Ok(res) +} + +pub(crate) fn handle_formatting( + snapshot: LanguageServerSnapshot, + params: lsp_types::DocumentFormattingParams, + _sender: Sender, +) -> anyhow::Result>> { + let file = file_path_from_url(¶ms.text_document.uri)?; + let path = from_lsp::abs_path(¶ms.text_document.uri)?; + let src = { + let vfs = snapshot.vfs.read(); + let file_id = vfs + .file_id(&path.into()) + .ok_or(anyhow::anyhow!("Already checked that the file_id exists!"))?; + + String::from_utf8(vfs.file_contents(file_id).to_vec())? + }; + + format(file, src, None) +} + +pub(crate) fn handle_range_formatting( + snapshot: LanguageServerSnapshot, + params: lsp_types::DocumentRangeFormattingParams, + _sender: Sender, +) -> anyhow::Result>> { + let file = file_path_from_url(¶ms.text_document.uri)?; + let path = from_lsp::abs_path(¶ms.text_document.uri)?; + let vfs = &*snapshot.vfs.read(); + + let file_id = vfs + .file_id(&path.clone().into()) + .ok_or(anyhow::anyhow!("Already checked that the file_id exists!"))?; + + let text = String::from_utf8(vfs.file_contents(file_id).to_vec())?; + let range = from_lsp::text_range(&text, params.range); + if let Some(src) = text.get(range) { + format(file, src.to_owned(), Some(params.range)) + } else { + Ok(None) + } +} + +/// Called when a `textDocument/codeAction` request was received. +pub(crate) fn handle_code_action( + _snapshot: LanguageServerSnapshot, + params: lsp_types::CodeActionParams, + _sender: Sender, +) -> anyhow::Result> { + let mut code_actions: Vec = vec![]; + code_actions.extend(quick_fix::quick_fix( + ¶ms.text_document.uri, + ¶ms.context.diagnostics, + )); + Ok(Some(code_actions)) +} + +/// Called when a `textDocument/definition` request was received. +pub(crate) fn handle_goto_definition( + snapshot: LanguageServerSnapshot, + params: lsp_types::GotoDefinitionParams, + sender: Sender, +) -> anyhow::Result> { + let file = file_path_from_url(¶ms.text_document_position_params.text_document.uri)?; + let path = from_lsp::abs_path(¶ms.text_document_position_params.text_document.uri)?; + if !snapshot.verify_request_path(&path.clone().into(), &sender) { + return Ok(None); + }; + let db = match snapshot.try_get_db(&path.clone().into(), &sender) { + Ok(option_db) => match option_db { + Some(db) => db, + None => return Err(anyhow!(LSPError::Retry)), + }, + Err(_) => return Ok(None), + }; + let kcl_pos = kcl_pos(&file, params.text_document_position_params.position); + let res = goto_def(&kcl_pos, &db.gs); + if res.is_none() { + log_message("Definition item not found".to_string(), &sender)?; + } + Ok(res) +} + +/// Called when a `textDocument/references` request was received +pub(crate) fn handle_reference( + snapshot: LanguageServerSnapshot, + params: lsp_types::ReferenceParams, + sender: Sender, +) -> anyhow::Result>> { + let file = file_path_from_url(¶ms.text_document_position.text_document.uri)?; + + let path = from_lsp::abs_path(¶ms.text_document_position.text_document.uri)?; + + if !snapshot.verify_request_path(&path.clone().into(), &sender) { + return Ok(None); + } + let db = match snapshot.try_get_db(&path.clone().into(), &sender) { + Ok(option_db) => match option_db { + Some(db) => db, + None => return Err(anyhow!(LSPError::Retry)), + }, + Err(_) => return Ok(None), + }; + let pos = kcl_pos(&file, params.text_document_position.position); + let res = find_refs(&pos, &db.gs); + Ok(res) +} + +/// Called when a `textDocument/completion` request was received. +pub(crate) fn handle_completion( + snapshot: LanguageServerSnapshot, + params: lsp_types::CompletionParams, + sender: Sender, +) -> anyhow::Result> { + let file = file_path_from_url(¶ms.text_document_position.text_document.uri)?; + let path: VfsPath = + from_lsp::abs_path(¶ms.text_document_position.text_document.uri)?.into(); + if !snapshot.verify_request_path(&path.clone().into(), &sender) { + return Ok(None); + } + + let (workspace, db_state) = match snapshot.try_get_db_state(&path) { + Ok(option_state) => match option_state { + Some(db) => db, + None => return Err(anyhow!(LSPError::Retry)), + }, + Err(_) => return Ok(None), + }; + + let completion_trigger_character = params + .context + .and_then(|ctx| ctx.trigger_character) + .and_then(|s| s.chars().next()); + + if matches!(completion_trigger_character, Some('\n')) { + match db_state { + DBState::Compiling(_) | DBState::Init => return Err(anyhow!(LSPError::Retry)), + DBState::Failed(_) => return Ok(None), + _ => {} + } + } + + let db = match db_state { + DBState::Ready(db) => db, + DBState::Compiling(db) => db, + DBState::Init => return Err(anyhow!(LSPError::Retry)), + DBState::Failed(_) => return Ok(None), + }; + + let kcl_pos = kcl_pos(&file, params.text_document_position.position); + + let metadata = snapshot + .workspace_config_cache + .read() + .get(&workspace) + .and_then(|opt| opt.2.clone()); + + let res = completion( + completion_trigger_character, + &db.prog, + &kcl_pos, + &db.gs, + &*snapshot.tool.read(), + metadata, + &db.schema_map, + ); + + if res.is_none() { + log_message("Completion item not found".to_string(), &sender)?; + } + Ok(res) +} + +/// Called when a `textDocument/hover` request was received. +pub(crate) fn handle_hover( + snapshot: LanguageServerSnapshot, + params: lsp_types::HoverParams, + sender: Sender, +) -> anyhow::Result> { + let file = file_path_from_url(¶ms.text_document_position_params.text_document.uri)?; + let path = from_lsp::abs_path(¶ms.text_document_position_params.text_document.uri)?; + if !snapshot.verify_request_path(&path.clone().into(), &sender) { + return Ok(None); + } + let db = match snapshot.try_get_db(&path.clone().into(), &sender) { + Ok(option_db) => match option_db { + Some(db) => db, + None => return Err(anyhow!(LSPError::Retry)), + }, + Err(_) => return Ok(None), + }; + let kcl_pos = kcl_pos(&file, params.text_document_position_params.position); + let res = hover::hover(&kcl_pos, &db.gs); + if res.is_none() { + log_message("Hover definition not found".to_string(), &sender)?; + } + Ok(res) +} + +/// Called when a `textDocument/documentSymbol` request was received. +pub(crate) fn handle_document_symbol( + snapshot: LanguageServerSnapshot, + params: lsp_types::DocumentSymbolParams, + sender: Sender, +) -> anyhow::Result> { + let file = file_path_from_url(¶ms.text_document.uri)?; + let path = from_lsp::abs_path(¶ms.text_document.uri)?; + let db = match snapshot.try_get_db(&path.clone().into(), &sender) { + Ok(option_db) => match option_db { + Some(db) => db, + None => return Err(anyhow!(LSPError::Retry)), + }, + Err(_) => return Ok(None), + }; + let res = document_symbol(&file, &db.gs); + Ok(res) +} + +/// Called when a `textDocument/rename` request was received. +pub(crate) fn handle_rename( + snapshot: LanguageServerSnapshot, + params: lsp_types::RenameParams, + sender: Sender, +) -> anyhow::Result> { + // 1. check the new name validity + let new_name = params.new_name; + if !is_valid_kcl_name(new_name.as_str()) { + return Err(anyhow!("Can not rename to: {new_name}, invalid name")); + } + + // 2. find all the references of the symbol + let file = file_path_from_url(¶ms.text_document_position.text_document.uri)?; + let path = from_lsp::abs_path(¶ms.text_document_position.text_document.uri)?; + if !snapshot.verify_request_path(&path.clone().into(), &sender) { + return Ok(None); + } + let db = match snapshot.try_get_db(&path.clone().into(), &sender) { + Ok(option_db) => match option_db { + Some(db) => db, + None => return Err(anyhow!(LSPError::Retry)), + }, + Err(_) => return Ok(None), + }; + let kcl_pos = kcl_pos(&file, params.text_document_position.position); + let references = find_refs(&kcl_pos, &db.gs); + match references { + Some(locations) => { + let mut workspace_edit = lsp_types::WorkspaceEdit::default(); + let changes = locations.into_iter().fold( + HashMap::new(), + |mut map: HashMap>, location| { + let uri = location.uri; + map.entry(uri.clone()).or_default().push(TextEdit { + range: location.range, + new_text: new_name.clone(), + }); + map + }, + ); + workspace_edit.changes = Some(changes); + return anyhow::Ok(Some(workspace_edit)); + } + None => {} + } + Ok(None) +} + +pub(crate) fn handle_inlay_hint( + snapshot: LanguageServerSnapshot, + params: lsp_types::InlayHintParams, + sender: Sender, +) -> anyhow::Result>> { + let file = file_path_from_url(¶ms.text_document.uri)?; + let path = from_lsp::abs_path(¶ms.text_document.uri)?; + let db = match snapshot.try_get_db(&path.clone().into(), &sender) { + Ok(option_db) => match option_db { + Some(db) => db, + None => return Err(anyhow!(LSPError::Retry)), + }, + Err(_) => return Ok(None), + }; + let res = inlay_hints(&file, &db.gs); + Ok(res) +} + +pub(crate) fn handle_signature_help( + snapshot: LanguageServerSnapshot, + params: lsp_types::SignatureHelpParams, + sender: Sender, +) -> anyhow::Result> { + let file = file_path_from_url(¶ms.text_document_position_params.text_document.uri)?; + let pos = kcl_pos(&file, params.text_document_position_params.position); + let trigger_character = params.context.and_then(|ctx| ctx.trigger_character); + let path = from_lsp::abs_path(¶ms.text_document_position_params.text_document.uri)?; + let db = match snapshot.try_get_db(&path.clone().into(), &sender) { + Ok(option_db) => match option_db { + Some(db) => db, + None => return Err(anyhow!(LSPError::Retry)), + }, + Err(_) => return Ok(None), + }; + let res = signature_help(&pos, &db.gs, trigger_character); + + Ok(res) +} diff --git a/kclvm/tools/src/LSP/src/semantic_token.rs b/kclvm/tools/src/LSP/src/semantic_token.rs new file mode 100644 index 000000000..f5b33db61 --- /dev/null +++ b/kclvm/tools/src/LSP/src/semantic_token.rs @@ -0,0 +1,220 @@ +use std::vec; + +use kclvm_error::Position; +use kclvm_sema::core::{ + global_state::GlobalState, + symbol::{KCLSymbol, SymbolKind, SymbolRef}, +}; +use kclvm_sema::ty::TypeKind; +use lsp_types::{SemanticToken, SemanticTokenType, SemanticTokens, SemanticTokensResult}; + +pub const LEGEND_TYPE: &[SemanticTokenType] = &[ + SemanticTokenType::VARIABLE, + SemanticTokenType::STRUCT, + SemanticTokenType::PROPERTY, + SemanticTokenType::NAMESPACE, + SemanticTokenType::TYPE, + SemanticTokenType::MACRO, + SemanticTokenType::COMMENT, + SemanticTokenType::PARAMETER, + SemanticTokenType::FUNCTION, +]; + +pub(crate) struct KCLSemanticToken { + pub start: Position, + pub kind: u32, + pub length: u32, +} + +pub fn semantic_tokens_full(file: &str, gs: &GlobalState) -> Option { + let mut kcl_tokens: Vec = vec![]; + let sema_db = gs.get_sema_db(); + if let Some(file_sema) = sema_db.get_file_sema(file) { + let symbols = file_sema.get_symbols(); + for symbol_ref in symbols { + if let Some(symbol) = gs.get_symbols().get_symbol(*symbol_ref) { + let (start, end) = symbol.get_range(); + match get_kind(*symbol_ref, symbol, gs) { + Some(kind) => { + kcl_tokens.push(KCLSemanticToken { + start: start.clone(), + kind, + length: if start.line == end.line { + (end.column.unwrap_or(0) - start.column.unwrap_or(0)) as u32 + } else { + symbol.get_name().len() as u32 + }, + }); + } + None => continue, + } + } + } + } + + Some(SemanticTokensResult::Tokens(SemanticTokens { + result_id: None, + data: kcl_semantic_tokens_to_semantic_tokens(&mut kcl_tokens), + })) +} + +pub(crate) fn get_kind(symbol_ref: SymbolRef, symbol: &KCLSymbol, gs: &GlobalState) -> Option { + match symbol_ref.get_kind() { + SymbolKind::Schema => Some(type_index(SemanticTokenType::STRUCT)), + SymbolKind::Attribute => Some(type_index(SemanticTokenType::PROPERTY)), + SymbolKind::Package => Some(type_index(SemanticTokenType::NAMESPACE)), + SymbolKind::TypeAlias => Some(type_index(SemanticTokenType::TYPE)), + SymbolKind::Value => { + if let Some(ty) = &symbol.get_sema_info().ty { + match ty.kind { + TypeKind::Function(_) => Some(type_index(SemanticTokenType::FUNCTION)), + _ => Some(type_index(SemanticTokenType::VARIABLE)), + } + } else { + Some(type_index(SemanticTokenType::VARIABLE)) + } + } + SymbolKind::Function => Some(type_index(SemanticTokenType::FUNCTION)), + SymbolKind::Rule => Some(type_index(SemanticTokenType::MACRO)), + SymbolKind::Unresolved => match &symbol.get_definition() { + Some(def_ref) => match gs.get_symbols().get_symbol(*def_ref) { + Some(symbol) => get_kind(*def_ref, symbol, gs), + None => Some(type_index(SemanticTokenType::VARIABLE)), + }, + None => { + let unresolved_symbol = gs.get_symbols().get_unresolved_symbol(symbol_ref).unwrap(); + if unresolved_symbol.is_type() { + Some(type_index(SemanticTokenType::TYPE)) + } else { + Some(type_index(SemanticTokenType::VARIABLE)) + } + } + }, + SymbolKind::Expression => None, + SymbolKind::Comment => None, + SymbolKind::Decorator => Some(type_index(SemanticTokenType::PARAMETER)), + } +} + +pub(crate) fn type_index(ty: SemanticTokenType) -> u32 { + LEGEND_TYPE.iter().position(|it| *it == ty).unwrap() as u32 +} + +pub(crate) fn kcl_semantic_tokens_to_semantic_tokens( + tokens: &mut [KCLSemanticToken], +) -> Vec { + tokens.sort_by(|a, b| { + if a.start.line == b.start.line { + a.start + .column + .unwrap_or(0) + .cmp(&b.start.column.unwrap_or(0)) + } else { + a.start.line.cmp(&b.start.line) + } + }); + + // ref: https://github.com/microsoft/vscode-extension-samples/blob/5ae1f7787122812dcc84e37427ca90af5ee09f14/semantic-tokens-sample/vscode.proposed.d.ts#L71 + // A file can contain many tokens, perhaps even hundreds of thousands of tokens. Therefore, to improve + // the memory consumption around describing semantic tokens, we have decided to avoid allocating an object + // for each token and we represent tokens from a file as an array of integers. Furthermore, the position + // of each token is expressed relative to the token before it because most tokens remain stable relative to + // each other when edits are made in a file. + + let mut semantic_tokens: Vec = vec![]; + if tokens.is_empty() { + return semantic_tokens; + } + let first_token = tokens.first().unwrap(); + + semantic_tokens.push(SemanticToken { + delta_line: (first_token.start.line - 1) as u32, + delta_start: (first_token.start.column.unwrap_or(0)) as u32, + length: first_token.length, + token_type: first_token.kind, + token_modifiers_bitset: 0, + }); + + for token_tuple in tokens.windows(2) { + let first_token = &token_tuple[0]; + let second_token = &token_tuple[1]; + let delta_line = (second_token.start.line - first_token.start.line) as u32; + let delta_start = (if delta_line == 0 { + second_token.start.column.unwrap_or(0) - first_token.start.column.unwrap_or(0) + } else { + second_token.start.column.unwrap_or(0) + }) as u32; + if delta_line != 0 || delta_start != 0 { + semantic_tokens.push(SemanticToken { + delta_line, + delta_start, + length: second_token.length, + token_type: second_token.kind, + token_modifiers_bitset: 0, + }); + } + } + semantic_tokens +} + +#[cfg(test)] +mod tests { + use crate::tests::compile_test_file; + use proc_macro_crate::bench_test; + + use super::semantic_tokens_full; + + #[test] + #[bench_test] + fn semantic_tokens_full_test() { + let (file, _, _, gs, _) = compile_test_file("src/test_data/sema_token/sema_token.k"); + let res = semantic_tokens_full(&file, &gs); + if let Some(tokens) = res { + match &tokens { + lsp_types::SemanticTokensResult::Tokens(tokens) => { + let get: Vec<(u32, u32, u32, u32)> = tokens + .data + .iter() + .map(|token| { + ( + token.delta_line, + token.delta_start, + token.length, + token.token_type, + ) + }) + .collect(); + // (delta line, delta col(if delta line != 0, from 0), length, kind) + // (0, 15, 1, 3), // m + // (1, 5, 3, 4), // num + // (1, 7, 7, 1), // Persons + // (1, 4, 4, 2), // name + // (2, 0, 2, 0), // p5 + // (0, 4, 7, 1), // Persons + // (0, 10, 7, 1), // Persons + // (1, 4, 4, 2), // name + // (2, 0, 1, 0), // n + // (0, 3, 3, 4), // num + // (2, 0, 4, 8), // func + // (0, 14, 1, 0), // x + // (1, 4, 1, 0), // x + // (3, 0, 1, 0), // a + // (0, 4, 4, 8), // func + // (1, 0, 1, 0), // b + // (0, 4, 4, 8), // func + // (0, 5, 1, 0) // x + // (2, 7, 8, 1) // Manifest + // (1, 5, 4, 0) // name + // (2, 0, 3, 0) // aaa + // (0, 5, 3, 4) // any + // (2, 0, 3, 0) // bbb + // (0, 10, 4, 0) // item + insta::assert_snapshot!(format!("{:?}", get)); + } + lsp_types::SemanticTokensResult::Partial(_) => { + panic!("test failed") + } + } + } + } +} diff --git a/kclvm/tools/src/LSP/src/signature_help.rs b/kclvm/tools/src/LSP/src/signature_help.rs new file mode 100644 index 000000000..a3934db60 --- /dev/null +++ b/kclvm/tools/src/LSP/src/signature_help.rs @@ -0,0 +1,232 @@ +use crate::goto_def::find_def; +use kclvm_error::Position as KCLPos; +use kclvm_sema::core::global_state::GlobalState; +use kclvm_sema::core::scope::Scope; +use kclvm_sema::core::symbol::SymbolKind; +use kclvm_sema::core::symbol::SymbolRef; +use kclvm_sema::ty::FunctionType; +use lsp_types::ParameterInformation; +use lsp_types::SignatureHelp; +use lsp_types::SignatureInformation; + +pub fn signature_help( + pos: &KCLPos, + gs: &GlobalState, + trigger_character: Option, +) -> Option { + trigger_character.as_ref()?; + match trigger_character.unwrap().as_str() { + // func + "(" => { + let def = find_def(pos, gs, false)?; + match def.get_kind() { + SymbolKind::Value | SymbolKind::Function => { + let symbol = gs.get_symbols().get_symbol(def)?; + let ty = &symbol.get_sema_info().ty.clone()?; + if let kclvm_sema::ty::TypeKind::Function(func_ty) = &ty.kind { + let (label, parameters) = + function_signatue_help(&symbol.get_name(), func_ty); + let documentation = symbol + .get_sema_info() + .doc + .clone() + .map(lsp_types::Documentation::String); + + return Some(SignatureHelp { + signatures: vec![SignatureInformation { + label, + documentation, + parameters, + active_parameter: Some(0), + }], + active_signature: None, + active_parameter: None, + }); + } + } + _ => {} + } + None + } + // func(arg1) + "," => { + let scope = gs.look_up_scope(pos)?; + if let kclvm_sema::core::scope::ScopeKind::Local = scope.get_kind() { + let local_scope = gs.get_scopes().try_get_local_scope(&scope)?; + if let kclvm_sema::core::scope::LocalSymbolScopeKind::Callable = + local_scope.get_kind() + { + let func_symbol = local_scope.get_owner()?; + let symbol = gs.get_symbols().get_symbol(func_symbol)?; + let ty = &symbol.get_sema_info().ty.clone()?; + if let kclvm_sema::ty::TypeKind::Function(func_ty) = &ty.kind { + let (label, parameters) = + function_signatue_help(&symbol.get_name(), func_ty); + let documentation = symbol + .get_sema_info() + .doc + .clone() + .map(lsp_types::Documentation::String); + + // highlight parameter's index + // if None, it will highlight first param(maybe default) + // if index >= param len, it will be no highlight + let active_parameter = match gs.get_scope_symbols(scope) { + Some(arg_symbols) => { + // func(a, 1, z = 3) + // Unresolved => variable ref: a + // Expression => 1, 3, + // filter kw symbol `z` + let actually_symbol: Vec = arg_symbols + .into_iter() + .filter(|symbol| { + matches!( + symbol.get_kind(), + SymbolKind::Unresolved | SymbolKind::Expression + ) + }) + .collect(); + let mut index: usize = 0; + for (i, symbol) in actually_symbol.iter().enumerate() { + let s = gs.get_symbols().get_symbol(*symbol).unwrap(); + let start = s.get_range().0; + if pos.less_equal(&start) { + index = i; + break; + } + } + Some(index as u32) + } + None => None, + }; + + return Some(SignatureHelp { + signatures: vec![SignatureInformation { + label, + documentation, + parameters, + active_parameter, + }], + active_signature: None, + active_parameter: None, + }); + } + } + } + None + } + _ => None, + } +} + +fn function_signatue_help( + name: &String, + func_ty: &FunctionType, +) -> (String, Option>) { + let label = func_ty.func_signature_str(name); + let parameters = Some( + func_ty + .params + .iter() + .map(|param| ParameterInformation { + label: lsp_types::ParameterLabel::Simple(format!( + "{}: {}", + param.name, + param.ty.ty_str() + )), + documentation: None, + }) + .collect::>(), + ); + (label, parameters) +} + +#[cfg(test)] +mod tests { + use super::signature_help; + + use crate::tests::compile_test_file; + use kclvm_error::Position as KCLPos; + + #[macro_export] + macro_rules! signature_help_test_snapshot { + ($name:ident, $file:expr, $line:expr, $column: expr, $trigger_character: expr) => { + #[test] + fn $name() { + let (file, _program, _, gs, _) = compile_test_file($file); + + let pos = KCLPos { + filename: file.clone(), + line: $line, + column: Some($column), + }; + let res = signature_help(&pos, &gs, $trigger_character).unwrap(); + insta::assert_snapshot!(format!("{:#?}", res)); + } + }; + } + + signature_help_test_snapshot!( + lambda_signatue_help_test_0, + "src/test_data/signature_help/lambda_signature_help/lambda_signature_help.k", + 5, + 9, + Some("(".to_string()) + ); + + signature_help_test_snapshot!( + lambda_signatue_help_test_1, + "src/test_data/signature_help/lambda_signature_help/lambda_signature_help.k", + 6, + 11, + Some(",".to_string()) + ); + + signature_help_test_snapshot!( + lambda_signatue_help_test_2, + "src/test_data/signature_help/lambda_signature_help/lambda_signature_help.k", + 7, + 14, + Some(",".to_string()) + ); + + signature_help_test_snapshot!( + lambda_signatue_help_test_3, + "src/test_data/signature_help/lambda_signature_help/lambda_signature_help.k", + 8, + 21, + Some(",".to_string()) + ); + + signature_help_test_snapshot!( + builtin_function_signature_help_test_0, + "src/test_data/signature_help/builtin_function_signature_help/builtin_function_signature_help.k", + 1, + 4, + Some("(".to_string()) + ); + + signature_help_test_snapshot!( + builtin_function_signature_help_test_1, + "src/test_data/signature_help/builtin_function_signature_help/builtin_function_signature_help.k", + 2, + 6, + Some(",".to_string()) + ); + + signature_help_test_snapshot!( + pkg_function_signature_help_test_0, + "src/test_data/signature_help/pkg_function_signature_help/pkg_function_signature_help.k", + 3, + 9, + Some("(".to_string()) + ); + + signature_help_test_snapshot!( + pkg_function_signature_help_test_1, + "src/test_data/signature_help/pkg_function_signature_help/pkg_function_signature_help.k", + 4, + 11, + Some(",".to_string()) + ); +} diff --git a/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__completion__tests__complete_after_compare_expr_1.snap b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__completion__tests__complete_after_compare_expr_1.snap new file mode 100644 index 000000000..f3e7f40c9 --- /dev/null +++ b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__completion__tests__complete_after_compare_expr_1.snap @@ -0,0 +1,5 @@ +--- +source: tools/src/LSP/src/completion.rs +expression: "format!(\"{:?}\", got_labels)" +--- +["capitalize(…)", "chars(…)", "count(…)", "endswith(…)", "find(…)", "format(…)", "index(…)", "isalnum(…)", "isalpha(…)", "isdigit(…)", "islower(…)", "isspace(…)", "istitle(…)", "isupper(…)", "join(…)", "lower(…)", "lstrip(…)", "removeprefix(…)", "removesuffix(…)", "replace(…)", "rfind(…)", "rindex(…)", "rsplit(…)", "rstrip(…)", "split(…)", "splitlines(…)", "startswith(…)", "strip(…)", "title(…)", "upper(…)"] diff --git a/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__completion__tests__complete_unimport_schemas.snap b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__completion__tests__complete_unimport_schemas.snap new file mode 100644 index 000000000..2c22b7558 --- /dev/null +++ b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__completion__tests__complete_unimport_schemas.snap @@ -0,0 +1,5 @@ +--- +source: tools/src/LSP/src/completion.rs +expression: "format! (\"{:?}\", got_labels)" +--- +["Name{}(import pkg)", "SubPKg{}(import subpkg)"] diff --git a/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__completion__tests__func_doc_completion.snap b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__completion__tests__func_doc_completion.snap new file mode 100644 index 000000000..f9d531ae0 --- /dev/null +++ b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__completion__tests__func_doc_completion.snap @@ -0,0 +1,5 @@ +--- +source: tools/src/LSP/src/completion.rs +expression: "format!(\"{:?}\", got_labels)" +--- +[] diff --git a/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__completion__tests__func_return_ty_1.snap b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__completion__tests__func_return_ty_1.snap new file mode 100644 index 000000000..f3e7f40c9 --- /dev/null +++ b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__completion__tests__func_return_ty_1.snap @@ -0,0 +1,5 @@ +--- +source: tools/src/LSP/src/completion.rs +expression: "format!(\"{:?}\", got_labels)" +--- +["capitalize(…)", "chars(…)", "count(…)", "endswith(…)", "find(…)", "format(…)", "index(…)", "isalnum(…)", "isalpha(…)", "isdigit(…)", "islower(…)", "isspace(…)", "istitle(…)", "isupper(…)", "join(…)", "lower(…)", "lstrip(…)", "removeprefix(…)", "removesuffix(…)", "replace(…)", "rfind(…)", "rindex(…)", "rsplit(…)", "rstrip(…)", "split(…)", "splitlines(…)", "startswith(…)", "strip(…)", "title(…)", "upper(…)"] diff --git a/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__completion__tests__func_return_ty_2.snap b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__completion__tests__func_return_ty_2.snap new file mode 100644 index 000000000..8b28f7593 --- /dev/null +++ b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__completion__tests__func_return_ty_2.snap @@ -0,0 +1,5 @@ +--- +source: tools/src/LSP/src/completion.rs +expression: "format!(\"{:?}\", got_labels)" +--- +["name"] diff --git a/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__completion__tests__func_return_ty_3.snap b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__completion__tests__func_return_ty_3.snap new file mode 100644 index 000000000..f9d531ae0 --- /dev/null +++ b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__completion__tests__func_return_ty_3.snap @@ -0,0 +1,5 @@ +--- +source: tools/src/LSP/src/completion.rs +expression: "format!(\"{:?}\", got_labels)" +--- +[] diff --git a/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__completion__tests__import_external_pkg_test.snap b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__completion__tests__import_external_pkg_test.snap new file mode 100644 index 000000000..4a31d9cec --- /dev/null +++ b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__completion__tests__import_external_pkg_test.snap @@ -0,0 +1,5 @@ +--- +source: tools/src/LSP/src/completion.rs +expression: "format!(\"{:?}\", got_labels)" +--- +["k8s"] diff --git a/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__completion__tests__import_internal_pkg_test.snap b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__completion__tests__import_internal_pkg_test.snap new file mode 100644 index 000000000..5adaa214a --- /dev/null +++ b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__completion__tests__import_internal_pkg_test.snap @@ -0,0 +1,5 @@ +--- +source: tools/src/LSP/src/completion.rs +expression: "format!(\"{:?}\", got_labels)" +--- +["foo", "tt"] diff --git a/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__completion__tests__lambda_1.snap b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__completion__tests__lambda_1.snap new file mode 100644 index 000000000..d726dffad --- /dev/null +++ b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__completion__tests__lambda_1.snap @@ -0,0 +1,5 @@ +--- +source: tools/src/LSP/src/completion.rs +expression: "format!(\"{:?}\", got_labels)" +--- +["case", "cases", "func1"] diff --git a/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__completion__tests__nested_1_test.snap b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__completion__tests__nested_1_test.snap new file mode 100644 index 000000000..6738b1987 --- /dev/null +++ b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__completion__tests__nested_1_test.snap @@ -0,0 +1,5 @@ +--- +source: tools/src/LSP/src/completion.rs +expression: "format!(\"{:?}\", labels)" +--- +["ab"] diff --git a/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__completion__tests__nested_2_test.snap b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__completion__tests__nested_2_test.snap new file mode 100644 index 000000000..6738b1987 --- /dev/null +++ b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__completion__tests__nested_2_test.snap @@ -0,0 +1,5 @@ +--- +source: tools/src/LSP/src/completion.rs +expression: "format!(\"{:?}\", labels)" +--- +["ab"] diff --git a/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__completion__tests__nested_3_test.snap b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__completion__tests__nested_3_test.snap new file mode 100644 index 000000000..6738b1987 --- /dev/null +++ b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__completion__tests__nested_3_test.snap @@ -0,0 +1,5 @@ +--- +source: tools/src/LSP/src/completion.rs +expression: "format!(\"{:?}\", labels)" +--- +["ab"] diff --git a/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__completion__tests__nested_4_test.snap b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__completion__tests__nested_4_test.snap new file mode 100644 index 000000000..6738b1987 --- /dev/null +++ b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__completion__tests__nested_4_test.snap @@ -0,0 +1,5 @@ +--- +source: tools/src/LSP/src/completion.rs +expression: "format!(\"{:?}\", labels)" +--- +["ab"] diff --git a/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__completion__tests__schema_attr_in_right.snap b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__completion__tests__schema_attr_in_right.snap new file mode 100644 index 000000000..5e9f2ba44 --- /dev/null +++ b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__completion__tests__schema_attr_in_right.snap @@ -0,0 +1,5 @@ +--- +source: tools/src/LSP/src/completion.rs +expression: "format!(\"{:?}\", got_labels)" +--- +["Base", "Base{}", "Config", "Config{}", "Name", "Name{}", "Person", "Person(b){}", "n", "p"] diff --git a/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__completion__tests__schema_attr_newline_completion_0.snap b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__completion__tests__schema_attr_newline_completion_0.snap new file mode 100644 index 000000000..dd1886bcd --- /dev/null +++ b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__completion__tests__schema_attr_newline_completion_0.snap @@ -0,0 +1,5 @@ +--- +source: tools/src/LSP/src/completion.rs +expression: "format!(\"{:?}\", got_labels)" +--- +["a", "c"] diff --git a/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__completion__tests__schema_attr_newline_completion_0_1.snap b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__completion__tests__schema_attr_newline_completion_0_1.snap new file mode 100644 index 000000000..f9d531ae0 --- /dev/null +++ b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__completion__tests__schema_attr_newline_completion_0_1.snap @@ -0,0 +1,5 @@ +--- +source: tools/src/LSP/src/completion.rs +expression: "format!(\"{:?}\", got_labels)" +--- +[] diff --git a/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__completion__tests__schema_attr_newline_completion_1.snap b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__completion__tests__schema_attr_newline_completion_1.snap new file mode 100644 index 000000000..8b28f7593 --- /dev/null +++ b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__completion__tests__schema_attr_newline_completion_1.snap @@ -0,0 +1,5 @@ +--- +source: tools/src/LSP/src/completion.rs +expression: "format!(\"{:?}\", got_labels)" +--- +["name"] diff --git a/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__completion__tests__schema_attr_ty_0.snap b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__completion__tests__schema_attr_ty_0.snap new file mode 100644 index 000000000..f9d531ae0 --- /dev/null +++ b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__completion__tests__schema_attr_ty_0.snap @@ -0,0 +1,5 @@ +--- +source: tools/src/LSP/src/completion.rs +expression: "format!(\"{:?}\", got_labels)" +--- +[] diff --git a/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__completion__tests__schema_attr_ty_1.snap b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__completion__tests__schema_attr_ty_1.snap new file mode 100644 index 000000000..f9d531ae0 --- /dev/null +++ b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__completion__tests__schema_attr_ty_1.snap @@ -0,0 +1,5 @@ +--- +source: tools/src/LSP/src/completion.rs +expression: "format!(\"{:?}\", got_labels)" +--- +[] diff --git a/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__completion__tests__schema_attr_ty_2.snap b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__completion__tests__schema_attr_ty_2.snap new file mode 100644 index 000000000..f9d531ae0 --- /dev/null +++ b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__completion__tests__schema_attr_ty_2.snap @@ -0,0 +1,5 @@ +--- +source: tools/src/LSP/src/completion.rs +expression: "format!(\"{:?}\", got_labels)" +--- +[] diff --git a/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__completion__tests__schema_attr_ty_3.snap b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__completion__tests__schema_attr_ty_3.snap new file mode 100644 index 000000000..f9d531ae0 --- /dev/null +++ b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__completion__tests__schema_attr_ty_3.snap @@ -0,0 +1,5 @@ +--- +source: tools/src/LSP/src/completion.rs +expression: "format!(\"{:?}\", got_labels)" +--- +[] diff --git a/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__completion__tests__schema_attr_ty_4.snap b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__completion__tests__schema_attr_ty_4.snap new file mode 100644 index 000000000..f9d531ae0 --- /dev/null +++ b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__completion__tests__schema_attr_ty_4.snap @@ -0,0 +1,5 @@ +--- +source: tools/src/LSP/src/completion.rs +expression: "format!(\"{:?}\", got_labels)" +--- +[] diff --git a/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__completion__tests__schema_def_1.snap b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__completion__tests__schema_def_1.snap new file mode 100644 index 000000000..f3bf7669e --- /dev/null +++ b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__completion__tests__schema_def_1.snap @@ -0,0 +1,5 @@ +--- +source: tools/src/LSP/src/completion.rs +expression: "format!(\"{:?}\", got_labels)" +--- +["Config", "Config{}", "Container", "Container{}", "Server", "Server(inputConfig){}", "config", "inputConfig", "mainContainer"] diff --git a/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__completion__tests__schema_def_2.snap b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__completion__tests__schema_def_2.snap new file mode 100644 index 000000000..f3bf7669e --- /dev/null +++ b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__completion__tests__schema_def_2.snap @@ -0,0 +1,5 @@ +--- +source: tools/src/LSP/src/completion.rs +expression: "format!(\"{:?}\", got_labels)" +--- +["Config", "Config{}", "Container", "Container{}", "Server", "Server(inputConfig){}", "config", "inputConfig", "mainContainer"] diff --git a/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__completion__tests__schema_def_3.snap b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__completion__tests__schema_def_3.snap new file mode 100644 index 000000000..f3bf7669e --- /dev/null +++ b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__completion__tests__schema_def_3.snap @@ -0,0 +1,5 @@ +--- +source: tools/src/LSP/src/completion.rs +expression: "format!(\"{:?}\", got_labels)" +--- +["Config", "Config{}", "Container", "Container{}", "Server", "Server(inputConfig){}", "config", "inputConfig", "mainContainer"] diff --git a/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__completion__tests__schema_def_4.snap b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__completion__tests__schema_def_4.snap new file mode 100644 index 000000000..324543e61 --- /dev/null +++ b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__completion__tests__schema_def_4.snap @@ -0,0 +1,5 @@ +--- +source: tools/src/LSP/src/completion.rs +expression: "format!(\"{:?}\", got_labels)" +--- +["Config", "Config{}", "Container", "Container{}", "Server", "Server(inputConfig){}", "name", "name1"] diff --git a/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__find_refs__tests__find_refs_from_variable_test.snap b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__find_refs__tests__find_refs_from_variable_test.snap new file mode 100644 index 000000000..342da8d6a --- /dev/null +++ b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__find_refs__tests__find_refs_from_variable_test.snap @@ -0,0 +1,7 @@ +--- +source: tools/src/LSP/src/find_refs.rs +expression: "format!(\"{}\", { fmt_resp(& res) })" +--- +path: "src/test_data/find_refs_test/main.k", range: Range { start: Position { line: 12, character: 14 }, end: Position { line: 12, character: 15 } } +path: "src/test_data/find_refs_test/main.k", range: Range { start: Position { line: 2, character: 4 }, end: Position { line: 2, character: 5 } } +path: "src/test_data/find_refs_test/main.k", range: Range { start: Position { line: 1, character: 4 }, end: Position { line: 1, character: 5 } } diff --git a/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__find_refs__tests__find_refs_schema_arg_1_test.snap b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__find_refs__tests__find_refs_schema_arg_1_test.snap new file mode 100644 index 000000000..b20d35b46 --- /dev/null +++ b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__find_refs__tests__find_refs_schema_arg_1_test.snap @@ -0,0 +1,6 @@ +--- +source: tools/src/LSP/src/find_refs.rs +expression: "format!(\"{}\", { fmt_resp(& res) })" +--- +path: "src/test_data/find_refs_test/main.k", range: Range { start: Position { line: 16, character: 14 }, end: Position { line: 16, character: 19 } } +path: "src/test_data/find_refs_test/main.k", range: Range { start: Position { line: 17, character: 13 }, end: Position { line: 17, character: 18 } } diff --git a/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__find_refs__tests__find_refs_schema_arg_test.snap b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__find_refs__tests__find_refs_schema_arg_test.snap new file mode 100644 index 000000000..b20d35b46 --- /dev/null +++ b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__find_refs__tests__find_refs_schema_arg_test.snap @@ -0,0 +1,6 @@ +--- +source: tools/src/LSP/src/find_refs.rs +expression: "format!(\"{}\", { fmt_resp(& res) })" +--- +path: "src/test_data/find_refs_test/main.k", range: Range { start: Position { line: 16, character: 14 }, end: Position { line: 16, character: 19 } } +path: "src/test_data/find_refs_test/main.k", range: Range { start: Position { line: 17, character: 13 }, end: Position { line: 17, character: 18 } } diff --git a/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__find_refs__tests__find_refs_schema_attr_ref_test.snap b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__find_refs__tests__find_refs_schema_attr_ref_test.snap new file mode 100644 index 000000000..ff2e4f64f --- /dev/null +++ b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__find_refs__tests__find_refs_schema_attr_ref_test.snap @@ -0,0 +1,6 @@ +--- +source: tools/src/LSP/src/find_refs.rs +expression: "format!(\"{}\", { fmt_resp(& res) })" +--- +path: "src/test_data/find_refs_test/main.k", range: Range { start: Position { line: 5, character: 4 }, end: Position { line: 5, character: 8 } } +path: "src/test_data/find_refs_test/main.k", range: Range { start: Position { line: 12, character: 8 }, end: Position { line: 12, character: 12 } } diff --git a/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__find_refs__tests__find_refs_schema_attr_test.snap b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__find_refs__tests__find_refs_schema_attr_test.snap new file mode 100644 index 000000000..ff2e4f64f --- /dev/null +++ b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__find_refs__tests__find_refs_schema_attr_test.snap @@ -0,0 +1,6 @@ +--- +source: tools/src/LSP/src/find_refs.rs +expression: "format!(\"{}\", { fmt_resp(& res) })" +--- +path: "src/test_data/find_refs_test/main.k", range: Range { start: Position { line: 5, character: 4 }, end: Position { line: 5, character: 8 } } +path: "src/test_data/find_refs_test/main.k", range: Range { start: Position { line: 12, character: 8 }, end: Position { line: 12, character: 12 } } diff --git a/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__find_refs__tests__find_refs_schema_name_ref_test.snap b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__find_refs__tests__find_refs_schema_name_ref_test.snap new file mode 100644 index 000000000..101c3649a --- /dev/null +++ b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__find_refs__tests__find_refs_schema_name_ref_test.snap @@ -0,0 +1,7 @@ +--- +source: tools/src/LSP/src/find_refs.rs +expression: "format!(\"{}\", { fmt_resp(& res) })" +--- +path: "src/test_data/find_refs_test/main.k", range: Range { start: Position { line: 4, character: 7 }, end: Position { line: 4, character: 11 } } +path: "src/test_data/find_refs_test/main.k", range: Range { start: Position { line: 8, character: 7 }, end: Position { line: 8, character: 11 } } +path: "src/test_data/find_refs_test/main.k", range: Range { start: Position { line: 11, character: 7 }, end: Position { line: 11, character: 11 } } diff --git a/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__find_refs__tests__find_refs_schema_name_test.snap b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__find_refs__tests__find_refs_schema_name_test.snap new file mode 100644 index 000000000..101c3649a --- /dev/null +++ b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__find_refs__tests__find_refs_schema_name_test.snap @@ -0,0 +1,7 @@ +--- +source: tools/src/LSP/src/find_refs.rs +expression: "format!(\"{}\", { fmt_resp(& res) })" +--- +path: "src/test_data/find_refs_test/main.k", range: Range { start: Position { line: 4, character: 7 }, end: Position { line: 4, character: 11 } } +path: "src/test_data/find_refs_test/main.k", range: Range { start: Position { line: 8, character: 7 }, end: Position { line: 8, character: 11 } } +path: "src/test_data/find_refs_test/main.k", range: Range { start: Position { line: 11, character: 7 }, end: Position { line: 11, character: 11 } } diff --git a/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__find_refs__tests__find_refs_variable_def_test.snap b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__find_refs__tests__find_refs_variable_def_test.snap new file mode 100644 index 000000000..7bbe27eb8 --- /dev/null +++ b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__find_refs__tests__find_refs_variable_def_test.snap @@ -0,0 +1,8 @@ +--- +source: tools/src/LSP/src/find_refs.rs +expression: "format!(\"{}\", { fmt_resp(& res) })" +--- +path: "src/test_data/find_refs_test/main.k", range: Range { start: Position { line: 0, character: 0 }, end: Position { line: 0, character: 1 } } +path: "src/test_data/find_refs_test/main.k", range: Range { start: Position { line: 1, character: 4 }, end: Position { line: 1, character: 5 } } +path: "src/test_data/find_refs_test/main.k", range: Range { start: Position { line: 2, character: 4 }, end: Position { line: 2, character: 5 } } +path: "src/test_data/find_refs_test/main.k", range: Range { start: Position { line: 12, character: 14 }, end: Position { line: 12, character: 15 } } diff --git a/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__find_refs__tests__find_refs_variable_ref_test.snap b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__find_refs__tests__find_refs_variable_ref_test.snap new file mode 100644 index 000000000..7bbe27eb8 --- /dev/null +++ b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__find_refs__tests__find_refs_variable_ref_test.snap @@ -0,0 +1,8 @@ +--- +source: tools/src/LSP/src/find_refs.rs +expression: "format!(\"{}\", { fmt_resp(& res) })" +--- +path: "src/test_data/find_refs_test/main.k", range: Range { start: Position { line: 0, character: 0 }, end: Position { line: 0, character: 1 } } +path: "src/test_data/find_refs_test/main.k", range: Range { start: Position { line: 1, character: 4 }, end: Position { line: 1, character: 5 } } +path: "src/test_data/find_refs_test/main.k", range: Range { start: Position { line: 2, character: 4 }, end: Position { line: 2, character: 5 } } +path: "src/test_data/find_refs_test/main.k", range: Range { start: Position { line: 12, character: 14 }, end: Position { line: 12, character: 15 } } diff --git a/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__complex_select_goto_def.snap b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__complex_select_goto_def.snap new file mode 100644 index 000000000..3fb4b21c5 --- /dev/null +++ b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__complex_select_goto_def.snap @@ -0,0 +1,5 @@ +--- +source: tools/src/LSP/src/goto_def.rs +expression: "format!(\"{:?}\", { fmt_resp(& res) })" +--- +"path: \"src/test_data/goto_def_test/complex_select_goto_def/complex_select_goto_def.k\", range: Range { start: Position { line: 4, character: 4 }, end: Position { line: 4, character: 9 } }" diff --git a/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__config_desuger_def_goto_def.snap b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__config_desuger_def_goto_def.snap new file mode 100644 index 000000000..4c84ca2d7 --- /dev/null +++ b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__config_desuger_def_goto_def.snap @@ -0,0 +1,5 @@ +--- +source: tools/src/LSP/src/goto_def.rs +expression: "format!(\"{:?}\", { fmt_resp(& res) })" +--- +"path: \"src/test_data/goto_def_test/config_desuger_def_goto_def/config_desuger_def_goto_def.k\", range: Range { start: Position { line: 0, character: 7 }, end: Position { line: 0, character: 13 } }" diff --git a/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_assign_type_test.snap b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_assign_type_test.snap new file mode 100644 index 000000000..9368e4ad1 --- /dev/null +++ b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_assign_type_test.snap @@ -0,0 +1,5 @@ +--- +source: tools/src/LSP/src/goto_def.rs +expression: "format!(\"{:?}\", { fmt_resp(& res) })" +--- +"path: \"src/test_data/goto_def_test/goto_assign_type_test/goto_assign_type_test.k\", range: Range { start: Position { line: 0, character: 7 }, end: Position { line: 0, character: 15 } }" diff --git a/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_attr_in_schema_def_1.snap b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_attr_in_schema_def_1.snap new file mode 100644 index 000000000..d20ad9209 --- /dev/null +++ b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_attr_in_schema_def_1.snap @@ -0,0 +1,5 @@ +--- +source: tools/src/LSP/src/goto_def.rs +expression: "format!(\"{:?}\", { fmt_resp(& res) })" +--- +"path: \"src/test_data/goto_def_test/goto_attr_in_schema_def/goto_attr_in_schema_def.k\", range: Range { start: Position { line: 5, character: 0 }, end: Position { line: 5, character: 5 } }" diff --git a/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_attr_in_schema_def_2.snap b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_attr_in_schema_def_2.snap new file mode 100644 index 000000000..196e3cea7 --- /dev/null +++ b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_attr_in_schema_def_2.snap @@ -0,0 +1,5 @@ +--- +source: tools/src/LSP/src/goto_def.rs +expression: "format!(\"{:?}\", { fmt_resp(& res) })" +--- +"path: \"src/test_data/goto_def_test/goto_attr_in_schema_def/goto_attr_in_schema_def.k\", range: Range { start: Position { line: 8, character: 4 }, end: Position { line: 8, character: 9 } }" diff --git a/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_attr_in_schema_def_3.snap b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_attr_in_schema_def_3.snap new file mode 100644 index 000000000..cc43318b7 --- /dev/null +++ b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_attr_in_schema_def_3.snap @@ -0,0 +1,5 @@ +--- +source: tools/src/LSP/src/goto_def.rs +expression: "format!(\"{:?}\", { fmt_resp(& res) })" +--- +"path: \"src/test_data/goto_def_test/goto_attr_in_schema_def/goto_attr_in_schema_def.k\", range: Range { start: Position { line: 9, character: 4 }, end: Position { line: 9, character: 9 } }" diff --git a/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_attr_in_schema_def_4.snap b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_attr_in_schema_def_4.snap new file mode 100644 index 000000000..a90ea278d --- /dev/null +++ b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_attr_in_schema_def_4.snap @@ -0,0 +1,5 @@ +--- +source: tools/src/LSP/src/goto_def.rs +expression: "format!(\"{:?}\", { fmt_resp(& res) })" +--- +"path: \"src/test_data/goto_def_test/goto_attr_in_schema_def/goto_attr_in_schema_def.k\", range: Range { start: Position { line: 14, character: 4 }, end: Position { line: 14, character: 5 } }" diff --git a/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_attr_in_schema_def_5.snap b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_attr_in_schema_def_5.snap new file mode 100644 index 000000000..39d8a63b3 --- /dev/null +++ b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_attr_in_schema_def_5.snap @@ -0,0 +1,5 @@ +--- +source: tools/src/LSP/src/goto_def.rs +expression: "format!(\"{:?}\", { fmt_resp(& res) })" +--- +"path: \"src/test_data/goto_def_test/goto_attr_in_schema_def/goto_attr_in_schema_def.k\", range: Range { start: Position { line: 26, character: 4 }, end: Position { line: 26, character: 7 } }" diff --git a/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_attr_in_schema_def_6.snap b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_attr_in_schema_def_6.snap new file mode 100644 index 000000000..de9991b65 --- /dev/null +++ b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_attr_in_schema_def_6.snap @@ -0,0 +1,5 @@ +--- +source: tools/src/LSP/src/goto_def.rs +expression: "format!(\"{:?}\", { fmt_resp(& res) })" +--- +"path: \"src/test_data/goto_def_test/goto_attr_in_schema_def/goto_attr_in_schema_def.k\", range: Range { start: Position { line: 28, character: 4 }, end: Position { line: 28, character: 7 } }" diff --git a/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_attr_in_schema_def_7.snap b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_attr_in_schema_def_7.snap new file mode 100644 index 000000000..d21ffc774 --- /dev/null +++ b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_attr_in_schema_def_7.snap @@ -0,0 +1,5 @@ +--- +source: tools/src/LSP/src/goto_def.rs +expression: "format!(\"{:?}\", { fmt_resp(& res) })" +--- +"path: \"src/test_data/goto_def_test/goto_attr_in_schema_def/goto_attr_in_schema_def.k\", range: Range { start: Position { line: 21, character: 4 }, end: Position { line: 21, character: 7 } }" diff --git a/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_attr_in_schema_def_8.snap b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_attr_in_schema_def_8.snap new file mode 100644 index 000000000..1fb53c9fb --- /dev/null +++ b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_attr_in_schema_def_8.snap @@ -0,0 +1,5 @@ +--- +source: tools/src/LSP/src/goto_def.rs +expression: "format!(\"{:?}\", { fmt_resp(& res) })" +--- +"path: \"src/test_data/goto_def_test/goto_attr_in_schema_def/goto_attr_in_schema_def.k\", range: Range { start: Position { line: 22, character: 4 }, end: Position { line: 22, character: 7 } }" diff --git a/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_base_schema_attr_1_test.snap b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_base_schema_attr_1_test.snap new file mode 100644 index 000000000..9bf25067f --- /dev/null +++ b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_base_schema_attr_1_test.snap @@ -0,0 +1,5 @@ +--- +source: tools/src/LSP/src/goto_def.rs +expression: "format!(\"{:?}\", { fmt_resp(& res) })" +--- +"path: \"src/test_data/goto_def_test/goto_base_schema_attr_1_test/types/host.k\", range: Range { start: Position { line: 1, character: 4 }, end: Position { line: 1, character: 8 } }" diff --git a/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_base_schema_attr_test.snap b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_base_schema_attr_test.snap new file mode 100644 index 000000000..45d6761cd --- /dev/null +++ b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_base_schema_attr_test.snap @@ -0,0 +1,5 @@ +--- +source: tools/src/LSP/src/goto_def.rs +expression: "format!(\"{:?}\", { fmt_resp(& res) })" +--- +"path: \"src/test_data/goto_def_test/goto_base_schema_attr_test/goto_base_schema_attr_test.k\", range: Range { start: Position { line: 1, character: 4 }, end: Position { line: 1, character: 8 } }" diff --git a/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_dict_to_schema_attr_test1.snap b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_dict_to_schema_attr_test1.snap new file mode 100644 index 000000000..e7c113435 --- /dev/null +++ b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_dict_to_schema_attr_test1.snap @@ -0,0 +1,5 @@ +--- +source: tools/src/LSP/src/goto_def.rs +expression: "format!(\"{:?}\", { fmt_resp(& res) })" +--- +"path: \"src/test_data/goto_def_test/dict_to_schema/dict_to_schema.k\", range: Range { start: Position { line: 1, character: 4 }, end: Position { line: 1, character: 8 } }" diff --git a/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_dict_to_schema_attr_test2.snap b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_dict_to_schema_attr_test2.snap new file mode 100644 index 000000000..b140ff9e4 --- /dev/null +++ b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_dict_to_schema_attr_test2.snap @@ -0,0 +1,5 @@ +--- +source: tools/src/LSP/src/goto_def.rs +expression: "format!(\"{:?}\", { fmt_resp(& res) })" +--- +"path: \"src/test_data/goto_def_test/dict_to_schema/dict_to_schema.k\", range: Range { start: Position { line: 4, character: 4 }, end: Position { line: 4, character: 8 } }" diff --git a/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_dict_to_schema_attr_test3.snap b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_dict_to_schema_attr_test3.snap new file mode 100644 index 000000000..c4c738294 --- /dev/null +++ b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_dict_to_schema_attr_test3.snap @@ -0,0 +1,5 @@ +--- +source: tools/src/LSP/src/goto_def.rs +expression: "format!(\"{:?}\", { fmt_resp(& res) })" +--- +"path: \"src/test_data/goto_def_test/dict_to_schema/dict_to_schema.k\", range: Range { start: Position { line: 9, character: 4 }, end: Position { line: 9, character: 8 } }" diff --git a/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_dict_to_schema_attr_test4.snap b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_dict_to_schema_attr_test4.snap new file mode 100644 index 000000000..b140ff9e4 --- /dev/null +++ b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_dict_to_schema_attr_test4.snap @@ -0,0 +1,5 @@ +--- +source: tools/src/LSP/src/goto_def.rs +expression: "format!(\"{:?}\", { fmt_resp(& res) })" +--- +"path: \"src/test_data/goto_def_test/dict_to_schema/dict_to_schema.k\", range: Range { start: Position { line: 4, character: 4 }, end: Position { line: 4, character: 8 } }" diff --git a/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_dict_to_schema_attr_test5.snap b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_dict_to_schema_attr_test5.snap new file mode 100644 index 000000000..c4c738294 --- /dev/null +++ b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_dict_to_schema_attr_test5.snap @@ -0,0 +1,5 @@ +--- +source: tools/src/LSP/src/goto_def.rs +expression: "format!(\"{:?}\", { fmt_resp(& res) })" +--- +"path: \"src/test_data/goto_def_test/dict_to_schema/dict_to_schema.k\", range: Range { start: Position { line: 9, character: 4 }, end: Position { line: 9, character: 8 } }" diff --git a/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_dict_to_schema_attr_test6.snap b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_dict_to_schema_attr_test6.snap new file mode 100644 index 000000000..00a8370f7 --- /dev/null +++ b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_dict_to_schema_attr_test6.snap @@ -0,0 +1,5 @@ +--- +source: tools/src/LSP/src/goto_def.rs +expression: "format!(\"{:?}\", { fmt_resp(& res) })" +--- +"path: \"src/test_data/goto_def_test/dict_to_schema/dict_to_schema.k\", range: Range { start: Position { line: 39, character: 4 }, end: Position { line: 39, character: 8 } }" diff --git a/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_dict_to_schema_attr_test7.snap b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_dict_to_schema_attr_test7.snap new file mode 100644 index 000000000..00a8370f7 --- /dev/null +++ b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_dict_to_schema_attr_test7.snap @@ -0,0 +1,5 @@ +--- +source: tools/src/LSP/src/goto_def.rs +expression: "format!(\"{:?}\", { fmt_resp(& res) })" +--- +"path: \"src/test_data/goto_def_test/dict_to_schema/dict_to_schema.k\", range: Range { start: Position { line: 39, character: 4 }, end: Position { line: 39, character: 8 } }" diff --git a/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_dict_to_schema_attr_test8.snap b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_dict_to_schema_attr_test8.snap new file mode 100644 index 000000000..00a8370f7 --- /dev/null +++ b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_dict_to_schema_attr_test8.snap @@ -0,0 +1,5 @@ +--- +source: tools/src/LSP/src/goto_def.rs +expression: "format!(\"{:?}\", { fmt_resp(& res) })" +--- +"path: \"src/test_data/goto_def_test/dict_to_schema/dict_to_schema.k\", range: Range { start: Position { line: 39, character: 4 }, end: Position { line: 39, character: 8 } }" diff --git a/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_duplicate_var_name_in_schema.snap b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_duplicate_var_name_in_schema.snap new file mode 100644 index 000000000..475019c58 --- /dev/null +++ b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_duplicate_var_name_in_schema.snap @@ -0,0 +1,5 @@ +--- +source: tools/src/LSP/src/goto_def.rs +expression: "format!(\"{:?}\", { fmt_resp(& res) })" +--- +"path: \"src/test_data/goto_def_test/duplicate_var_name_test/duplicate_var_name.k\", range: Range { start: Position { line: 4, character: 0 }, end: Position { line: 4, character: 3 } }" diff --git a/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_identifier_def_test.snap b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_identifier_def_test.snap new file mode 100644 index 000000000..20b5a7686 --- /dev/null +++ b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_identifier_def_test.snap @@ -0,0 +1,5 @@ +--- +source: tools/src/LSP/src/goto_def.rs +expression: "format!(\"{:?}\", { fmt_resp(& res) })" +--- +"path: \"src/test_data/goto_def_test/goto_identifier_def_test/goto_identifier_def_test.k\", range: Range { start: Position { line: 2, character: 0 }, end: Position { line: 2, character: 1 } }" diff --git a/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_identifier_names1.snap b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_identifier_names1.snap new file mode 100644 index 000000000..6f1f49e4b --- /dev/null +++ b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_identifier_names1.snap @@ -0,0 +1,5 @@ +--- +source: tools/src/LSP/src/goto_def.rs +expression: "format!(\"{:?}\", { fmt_resp(& res) })" +--- +"path: \"src/test_data/goto_def_test/test_goto_identifier_names/test_goto_identifier_names.k\", range: Range { start: Position { line: 8, character: 0 }, end: Position { line: 8, character: 2 } }" diff --git a/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_identifier_names2.snap b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_identifier_names2.snap new file mode 100644 index 000000000..622128f0f --- /dev/null +++ b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_identifier_names2.snap @@ -0,0 +1,5 @@ +--- +source: tools/src/LSP/src/goto_def.rs +expression: "format!(\"{:?}\", { fmt_resp(& res) })" +--- +"path: \"src/test_data/goto_def_test/test_goto_identifier_names/test_goto_identifier_names.k\", range: Range { start: Position { line: 6, character: 4 }, end: Position { line: 6, character: 5 } }" diff --git a/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_identifier_names3.snap b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_identifier_names3.snap new file mode 100644 index 000000000..de726db9b --- /dev/null +++ b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_identifier_names3.snap @@ -0,0 +1,5 @@ +--- +source: tools/src/LSP/src/goto_def.rs +expression: "format!(\"{:?}\", { fmt_resp(& res) })" +--- +"path: \"src/test_data/goto_def_test/test_goto_identifier_names/test_goto_identifier_names.k\", range: Range { start: Position { line: 3, character: 4 }, end: Position { line: 3, character: 8 } }" diff --git a/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_import_pkg_test.snap b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_import_pkg_test.snap new file mode 100644 index 000000000..795a0ddb6 --- /dev/null +++ b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_import_pkg_test.snap @@ -0,0 +1,5 @@ +--- +source: tools/src/LSP/src/goto_def.rs +expression: "format!(\"{:?}\", { fmt_resp(& res) })" +--- +"path: \"src/test_data/goto_def_test/pkg/schema_def.k\", range: Range { start: Position { line: 0, character: 0 }, end: Position { line: 0, character: 0 } }\npath: \"src/test_data/goto_def_test/pkg/schema_def1.k\", range: Range { start: Position { line: 0, character: 0 }, end: Position { line: 0, character: 0 } }\n" diff --git a/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_lambda_param_goto_def1.snap b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_lambda_param_goto_def1.snap new file mode 100644 index 000000000..785071f98 --- /dev/null +++ b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_lambda_param_goto_def1.snap @@ -0,0 +1,5 @@ +--- +source: tools/src/LSP/src/goto_def.rs +expression: "format!(\"{:?}\", { fmt_resp(& res) })" +--- +"path: \"src/test_data/goto_def_test/goto_lambda_param_goto_def/goto_lambda_param_goto_def.k\", range: Range { start: Position { line: 1, character: 14 }, end: Position { line: 1, character: 15 } }" diff --git a/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_lambda_param_goto_def2.snap b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_lambda_param_goto_def2.snap new file mode 100644 index 000000000..3025a3f1b --- /dev/null +++ b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_lambda_param_goto_def2.snap @@ -0,0 +1,5 @@ +--- +source: tools/src/LSP/src/goto_def.rs +expression: "format!(\"{:?}\", { fmt_resp(& res) })" +--- +"path: \"src/test_data/goto_def_test/goto_lambda_param_goto_def/goto_lambda_param_goto_def.k\", range: Range { start: Position { line: 1, character: 22 }, end: Position { line: 1, character: 23 } }" diff --git a/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_lambda_param_schema_test.snap b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_lambda_param_schema_test.snap new file mode 100644 index 000000000..d3a17ba01 --- /dev/null +++ b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_lambda_param_schema_test.snap @@ -0,0 +1,5 @@ +--- +source: tools/src/LSP/src/goto_def.rs +expression: "format!(\"{:?}\", { fmt_resp(& res) })" +--- +"path: \"src/test_data/goto_def_test/goto_lambda_param_schema_test/goto_lambda_param_schema_test.k\", range: Range { start: Position { line: 1, character: 4 }, end: Position { line: 1, character: 8 } }" diff --git a/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_lambda_return_schema_test.snap b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_lambda_return_schema_test.snap new file mode 100644 index 000000000..a1b1ef677 --- /dev/null +++ b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_lambda_return_schema_test.snap @@ -0,0 +1,5 @@ +--- +source: tools/src/LSP/src/goto_def.rs +expression: "format!(\"{:?}\", { fmt_resp(& res) })" +--- +"path: \"src/test_data/goto_def_test/goto_lambda_return_schema_test/goto_lambda_return_schema_test.k\", range: Range { start: Position { line: 1, character: 4 }, end: Position { line: 1, character: 8 } }" diff --git a/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_local_var_def_test1.snap b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_local_var_def_test1.snap new file mode 100644 index 000000000..afa39cf96 --- /dev/null +++ b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_local_var_def_test1.snap @@ -0,0 +1,5 @@ +--- +source: tools/src/LSP/src/goto_def.rs +expression: "format!(\"{:?}\", { fmt_resp(& res) })" +--- +"path: \"src/test_data/goto_def_test/goto_local_var_def_test/goto_local_var_def_test.k\", range: Range { start: Position { line: 4, character: 4 }, end: Position { line: 4, character: 9 } }" diff --git a/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_local_var_def_test2.snap b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_local_var_def_test2.snap new file mode 100644 index 000000000..afa39cf96 --- /dev/null +++ b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_local_var_def_test2.snap @@ -0,0 +1,5 @@ +--- +source: tools/src/LSP/src/goto_def.rs +expression: "format!(\"{:?}\", { fmt_resp(& res) })" +--- +"path: \"src/test_data/goto_def_test/goto_local_var_def_test/goto_local_var_def_test.k\", range: Range { start: Position { line: 4, character: 4 }, end: Position { line: 4, character: 9 } }" diff --git a/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_local_var_def_test3.snap b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_local_var_def_test3.snap new file mode 100644 index 000000000..afa39cf96 --- /dev/null +++ b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_local_var_def_test3.snap @@ -0,0 +1,5 @@ +--- +source: tools/src/LSP/src/goto_def.rs +expression: "format!(\"{:?}\", { fmt_resp(& res) })" +--- +"path: \"src/test_data/goto_def_test/goto_local_var_def_test/goto_local_var_def_test.k\", range: Range { start: Position { line: 4, character: 4 }, end: Position { line: 4, character: 9 } }" diff --git a/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_nested_schema_attr_test.snap b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_nested_schema_attr_test.snap new file mode 100644 index 000000000..94701bcb3 --- /dev/null +++ b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_nested_schema_attr_test.snap @@ -0,0 +1,5 @@ +--- +source: tools/src/LSP/src/goto_def.rs +expression: "format!(\"{:?}\", { fmt_resp(& res) })" +--- +"path: \"src/test_data/goto_def_test/goto_nested_schema_attr_test/goto_nested_schema_attr_test.k\", range: Range { start: Position { line: 14, character: 4 }, end: Position { line: 14, character: 8 } }" diff --git a/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_pkg_prefix_def_test.snap b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_pkg_prefix_def_test.snap new file mode 100644 index 000000000..795a0ddb6 --- /dev/null +++ b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_pkg_prefix_def_test.snap @@ -0,0 +1,5 @@ +--- +source: tools/src/LSP/src/goto_def.rs +expression: "format!(\"{:?}\", { fmt_resp(& res) })" +--- +"path: \"src/test_data/goto_def_test/pkg/schema_def.k\", range: Range { start: Position { line: 0, character: 0 }, end: Position { line: 0, character: 0 } }\npath: \"src/test_data/goto_def_test/pkg/schema_def1.k\", range: Range { start: Position { line: 0, character: 0 }, end: Position { line: 0, character: 0 } }\n" diff --git a/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_protocol_attr.snap b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_protocol_attr.snap new file mode 100644 index 000000000..2acbdbb07 --- /dev/null +++ b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_protocol_attr.snap @@ -0,0 +1,5 @@ +--- +source: tools/src/LSP/src/goto_def.rs +expression: "format!(\"{:?}\", { fmt_resp(& res) })" +--- +"path: \"src/test_data/goto_def_test/goto_protocol/goto_protocol.k\", range: Range { start: Position { line: 1, character: 4 }, end: Position { line: 1, character: 8 } }" diff --git a/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_protocol_attr_1.snap b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_protocol_attr_1.snap new file mode 100644 index 000000000..2acbdbb07 --- /dev/null +++ b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_protocol_attr_1.snap @@ -0,0 +1,5 @@ +--- +source: tools/src/LSP/src/goto_def.rs +expression: "format!(\"{:?}\", { fmt_resp(& res) })" +--- +"path: \"src/test_data/goto_def_test/goto_protocol/goto_protocol.k\", range: Range { start: Position { line: 1, character: 4 }, end: Position { line: 1, character: 8 } }" diff --git a/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_schema_attr_def_test1.snap b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_schema_attr_def_test1.snap new file mode 100644 index 000000000..43c375758 --- /dev/null +++ b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_schema_attr_def_test1.snap @@ -0,0 +1,5 @@ +--- +source: tools/src/LSP/src/goto_def.rs +expression: "format!(\"{:?}\", { fmt_resp(& res) })" +--- +"path: \"src/test_data/goto_def_test/pkg/schema_def.k\", range: Range { start: Position { line: 4, character: 4 }, end: Position { line: 4, character: 8 } }" diff --git a/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_schema_attr_def_test2.snap b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_schema_attr_def_test2.snap new file mode 100644 index 000000000..d40a663d2 --- /dev/null +++ b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_schema_attr_def_test2.snap @@ -0,0 +1,5 @@ +--- +source: tools/src/LSP/src/goto_def.rs +expression: "format!(\"{:?}\", { fmt_resp(& res) })" +--- +"path: \"src/test_data/goto_def_test/goto_schema_attr_def_test/goto_schema_attr_def_test.k\", range: Range { start: Position { line: 8, character: 4 }, end: Position { line: 8, character: 8 } }" diff --git a/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_schema_attr_ty_def_test1.snap b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_schema_attr_ty_def_test1.snap new file mode 100644 index 000000000..5f10e3803 --- /dev/null +++ b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_schema_attr_ty_def_test1.snap @@ -0,0 +1,5 @@ +--- +source: tools/src/LSP/src/goto_def.rs +expression: "format!(\"{:?}\", { fmt_resp(& res) })" +--- +"path: \"src/test_data/goto_def_test/pkg/schema_def.k\", range: Range { start: Position { line: 0, character: 7 }, end: Position { line: 0, character: 13 } }" diff --git a/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_schema_attr_ty_def_test2.snap b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_schema_attr_ty_def_test2.snap new file mode 100644 index 000000000..5f10e3803 --- /dev/null +++ b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_schema_attr_ty_def_test2.snap @@ -0,0 +1,5 @@ +--- +source: tools/src/LSP/src/goto_def.rs +expression: "format!(\"{:?}\", { fmt_resp(& res) })" +--- +"path: \"src/test_data/goto_def_test/pkg/schema_def.k\", range: Range { start: Position { line: 0, character: 7 }, end: Position { line: 0, character: 13 } }" diff --git a/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_schema_attr_ty_def_test3.snap b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_schema_attr_ty_def_test3.snap new file mode 100644 index 000000000..5f10e3803 --- /dev/null +++ b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_schema_attr_ty_def_test3.snap @@ -0,0 +1,5 @@ +--- +source: tools/src/LSP/src/goto_def.rs +expression: "format!(\"{:?}\", { fmt_resp(& res) })" +--- +"path: \"src/test_data/goto_def_test/pkg/schema_def.k\", range: Range { start: Position { line: 0, character: 7 }, end: Position { line: 0, character: 13 } }" diff --git a/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_schema_attr_ty_def_test4.snap b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_schema_attr_ty_def_test4.snap new file mode 100644 index 000000000..5f10e3803 --- /dev/null +++ b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_schema_attr_ty_def_test4.snap @@ -0,0 +1,5 @@ +--- +source: tools/src/LSP/src/goto_def.rs +expression: "format!(\"{:?}\", { fmt_resp(& res) })" +--- +"path: \"src/test_data/goto_def_test/pkg/schema_def.k\", range: Range { start: Position { line: 0, character: 7 }, end: Position { line: 0, character: 13 } }" diff --git a/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_schema_attr_ty_def_test5.snap b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_schema_attr_ty_def_test5.snap new file mode 100644 index 000000000..fa5f0671a --- /dev/null +++ b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_schema_attr_ty_def_test5.snap @@ -0,0 +1,5 @@ +--- +source: tools/src/LSP/src/goto_def.rs +expression: "format!(\"{:?}\", { fmt_resp(& res) })" +--- +"path: \"src/test_data/goto_def_test/pkg/schema_def1.k\", range: Range { start: Position { line: 0, character: 7 }, end: Position { line: 0, character: 14 } }" diff --git a/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_schema_def_test.snap b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_schema_def_test.snap new file mode 100644 index 000000000..5f10e3803 --- /dev/null +++ b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_schema_def_test.snap @@ -0,0 +1,5 @@ +--- +source: tools/src/LSP/src/goto_def.rs +expression: "format!(\"{:?}\", { fmt_resp(& res) })" +--- +"path: \"src/test_data/goto_def_test/pkg/schema_def.k\", range: Range { start: Position { line: 0, character: 7 }, end: Position { line: 0, character: 13 } }" diff --git a/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_system_pkg_test.snap b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_system_pkg_test.snap new file mode 100644 index 000000000..31cff5237 --- /dev/null +++ b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_system_pkg_test.snap @@ -0,0 +1,5 @@ +--- +source: tools/src/LSP/src/goto_def.rs +expression: "format!(\"{:?}\", { fmt_resp(& res) })" +--- +"None" diff --git a/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_unification_schema_attr_test.snap b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_unification_schema_attr_test.snap new file mode 100644 index 000000000..7b968d1db --- /dev/null +++ b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_unification_schema_attr_test.snap @@ -0,0 +1,5 @@ +--- +source: tools/src/LSP/src/goto_def.rs +expression: "format!(\"{:?}\", { fmt_resp(& res) })" +--- +"path: \"src/test_data/goto_def_test/goto_unification_schema_attr_test/goto_unification_schema_attr_test.k\", range: Range { start: Position { line: 3, character: 4 }, end: Position { line: 3, character: 12 } }" diff --git a/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_var_def_in_config_and_config_if_test1.snap b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_var_def_in_config_and_config_if_test1.snap new file mode 100644 index 000000000..0195e007f --- /dev/null +++ b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_var_def_in_config_and_config_if_test1.snap @@ -0,0 +1,5 @@ +--- +source: tools/src/LSP/src/goto_def.rs +expression: "format!(\"{:?}\", { fmt_resp(& res) })" +--- +"path: \"src/test_data/goto_def_test/goto_var_def_in_config_and_config_if_test/goto_var_def_in_config_and_config_if_test.k\", range: Range { start: Position { line: 5, character: 11 }, end: Position { line: 5, character: 14 } }" diff --git a/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_var_def_in_config_and_config_if_test2.snap b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_var_def_in_config_and_config_if_test2.snap new file mode 100644 index 000000000..a66f933da --- /dev/null +++ b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_var_def_in_config_and_config_if_test2.snap @@ -0,0 +1,5 @@ +--- +source: tools/src/LSP/src/goto_def.rs +expression: "format!(\"{:?}\", { fmt_resp(& res) })" +--- +"path: \"src/test_data/goto_def_test/goto_var_def_in_config_and_config_if_test/goto_var_def_in_config_and_config_if_test.k\", range: Range { start: Position { line: 5, character: 16 }, end: Position { line: 5, character: 21 } }" diff --git a/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_var_def_in_config_and_config_if_test3.snap b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_var_def_in_config_and_config_if_test3.snap new file mode 100644 index 000000000..880481d17 --- /dev/null +++ b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_var_def_in_config_and_config_if_test3.snap @@ -0,0 +1,5 @@ +--- +source: tools/src/LSP/src/goto_def.rs +expression: "format!(\"{:?}\", { fmt_resp(& res) })" +--- +"path: \"src/test_data/goto_def_test/goto_var_def_in_config_and_config_if_test/goto_var_def_in_config_and_config_if_test.k\", range: Range { start: Position { line: 10, character: 6 }, end: Position { line: 10, character: 10 } }" diff --git a/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_var_def_in_config_and_config_if_test4.snap b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_var_def_in_config_and_config_if_test4.snap new file mode 100644 index 000000000..880481d17 --- /dev/null +++ b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_var_def_in_config_and_config_if_test4.snap @@ -0,0 +1,5 @@ +--- +source: tools/src/LSP/src/goto_def.rs +expression: "format!(\"{:?}\", { fmt_resp(& res) })" +--- +"path: \"src/test_data/goto_def_test/goto_var_def_in_config_and_config_if_test/goto_var_def_in_config_and_config_if_test.k\", range: Range { start: Position { line: 10, character: 6 }, end: Position { line: 10, character: 10 } }" diff --git a/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_var_def_in_dict_comp_test1.snap b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_var_def_in_dict_comp_test1.snap new file mode 100644 index 000000000..18d9b9ccb --- /dev/null +++ b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_var_def_in_dict_comp_test1.snap @@ -0,0 +1,5 @@ +--- +source: tools/src/LSP/src/goto_def.rs +expression: "format!(\"{:?}\", { fmt_resp(& res) })" +--- +"path: \"src/test_data/goto_def_test/goto_var_def_in_dict_comp_test/goto_var_def_in_dict_comp_test.k\", range: Range { start: Position { line: 4, character: 143 }, end: Position { line: 4, character: 145 } }" diff --git a/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_var_def_in_dict_comp_test2.snap b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_var_def_in_dict_comp_test2.snap new file mode 100644 index 000000000..18d9b9ccb --- /dev/null +++ b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_var_def_in_dict_comp_test2.snap @@ -0,0 +1,5 @@ +--- +source: tools/src/LSP/src/goto_def.rs +expression: "format!(\"{:?}\", { fmt_resp(& res) })" +--- +"path: \"src/test_data/goto_def_test/goto_var_def_in_dict_comp_test/goto_var_def_in_dict_comp_test.k\", range: Range { start: Position { line: 4, character: 143 }, end: Position { line: 4, character: 145 } }" diff --git a/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__lambda_local_var_test.snap b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__lambda_local_var_test.snap new file mode 100644 index 000000000..cfab544a2 --- /dev/null +++ b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__lambda_local_var_test.snap @@ -0,0 +1,5 @@ +--- +source: tools/src/LSP/src/goto_def.rs +expression: "format!(\"{:?}\", { fmt_resp(& res) })" +--- +"path: \"src/test_data/goto_def_test/lambda_local_var_test/lambda_local_var_test.k\", range: Range { start: Position { line: 0, character: 11 }, end: Position { line: 0, character: 12 } }" diff --git a/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__list_if_expr_test.snap b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__list_if_expr_test.snap new file mode 100644 index 000000000..ff34fe027 --- /dev/null +++ b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__list_if_expr_test.snap @@ -0,0 +1,5 @@ +--- +source: tools/src/LSP/src/goto_def.rs +expression: "format!(\"{:?}\", { fmt_resp(& res) })" +--- +"path: \"src/test_data/goto_def_test/list_if_expr_test/list_if_expr_test.k\", range: Range { start: Position { line: 0, character: 0 }, end: Position { line: 0, character: 1 } }" diff --git a/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__schema_attribute_def_goto_def.snap b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__schema_attribute_def_goto_def.snap new file mode 100644 index 000000000..4f7634cc4 --- /dev/null +++ b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__schema_attribute_def_goto_def.snap @@ -0,0 +1,5 @@ +--- +source: tools/src/LSP/src/goto_def.rs +expression: "format!(\"{:?}\", { fmt_resp(& res) })" +--- +"path: \"src/test_data/goto_def_test/schema_attribute_def_goto_def/schema_attribute_def_goto_def.k\", range: Range { start: Position { line: 1, character: 4 }, end: Position { line: 1, character: 8 } }" diff --git a/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__inlay_hints__tests__assign_stmt_type_hint.snap b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__inlay_hints__tests__assign_stmt_type_hint.snap new file mode 100644 index 000000000..2d8d04cdb --- /dev/null +++ b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__inlay_hints__tests__assign_stmt_type_hint.snap @@ -0,0 +1,488 @@ +--- +source: tools/src/LSP/src/inlay_hints.rs +expression: "format!(\"{:#?}\", res)" +--- +Some( + [ + InlayHint { + position: Position { + line: 0, + character: 1, + }, + label: LabelParts( + [ + InlayHintLabelPart { + value: ": int", + tooltip: None, + location: None, + command: None, + }, + ], + ), + kind: Some( + Type, + ), + text_edits: Some( + [ + TextEdit { + range: Range { + start: Position { + line: 0, + character: 1, + }, + end: Position { + line: 0, + character: 1, + }, + }, + new_text: ": int", + }, + ], + ), + tooltip: None, + padding_left: None, + padding_right: None, + data: None, + }, + InlayHint { + position: Position { + line: 1, + character: 1, + }, + label: LabelParts( + [ + InlayHintLabelPart { + value: ": str", + tooltip: None, + location: None, + command: None, + }, + ], + ), + kind: Some( + Type, + ), + text_edits: Some( + [ + TextEdit { + range: Range { + start: Position { + line: 1, + character: 1, + }, + end: Position { + line: 1, + character: 1, + }, + }, + new_text: ": str", + }, + ], + ), + tooltip: None, + padding_left: None, + padding_right: None, + data: None, + }, + InlayHint { + position: Position { + line: 2, + character: 1, + }, + label: LabelParts( + [ + InlayHintLabelPart { + value: ": str", + tooltip: None, + location: None, + command: None, + }, + ], + ), + kind: Some( + Type, + ), + text_edits: Some( + [ + TextEdit { + range: Range { + start: Position { + line: 2, + character: 1, + }, + end: Position { + line: 2, + character: 1, + }, + }, + new_text: ": str", + }, + ], + ), + tooltip: None, + padding_left: None, + padding_right: None, + data: None, + }, + InlayHint { + position: Position { + line: 3, + character: 1, + }, + label: LabelParts( + [ + InlayHintLabelPart { + value: ": (int) -> int", + tooltip: None, + location: None, + command: None, + }, + ], + ), + kind: Some( + Type, + ), + text_edits: Some( + [ + TextEdit { + range: Range { + start: Position { + line: 3, + character: 1, + }, + end: Position { + line: 3, + character: 1, + }, + }, + new_text: ": (int) -> int", + }, + ], + ), + tooltip: None, + padding_left: None, + padding_right: None, + data: None, + }, + InlayHint { + position: Position { + line: 10, + character: 1, + }, + label: LabelParts( + [ + InlayHintLabelPart { + value: ": Name", + tooltip: None, + location: None, + command: None, + }, + ], + ), + kind: Some( + Type, + ), + text_edits: Some( + [ + TextEdit { + range: Range { + start: Position { + line: 10, + character: 1, + }, + end: Position { + line: 10, + character: 1, + }, + }, + new_text: ": Name", + }, + ], + ), + tooltip: None, + padding_left: None, + padding_right: None, + data: None, + }, + InlayHint { + position: Position { + line: 13, + character: 2, + }, + label: LabelParts( + [ + InlayHintLabelPart { + value: ": Name", + tooltip: None, + location: None, + command: None, + }, + ], + ), + kind: Some( + Type, + ), + text_edits: Some( + [ + TextEdit { + range: Range { + start: Position { + line: 13, + character: 2, + }, + end: Position { + line: 13, + character: 2, + }, + }, + new_text: ": Name", + }, + ], + ), + tooltip: None, + padding_left: None, + padding_right: None, + data: None, + }, + InlayHint { + position: Position { + line: 14, + character: 4, + }, + label: LabelParts( + [ + InlayHintLabelPart { + value: ": any", + tooltip: None, + location: None, + command: None, + }, + ], + ), + kind: Some( + Type, + ), + text_edits: Some( + [ + TextEdit { + range: Range { + start: Position { + line: 14, + character: 4, + }, + end: Position { + line: 14, + character: 4, + }, + }, + new_text: ": any", + }, + ], + ), + tooltip: None, + padding_left: None, + padding_right: None, + data: None, + }, + InlayHint { + position: Position { + line: 16, + character: 1, + }, + label: LabelParts( + [ + InlayHintLabelPart { + value: ": str", + tooltip: None, + location: None, + command: None, + }, + ], + ), + kind: Some( + Type, + ), + text_edits: Some( + [ + TextEdit { + range: Range { + start: Position { + line: 16, + character: 1, + }, + end: Position { + line: 16, + character: 1, + }, + }, + new_text: ": str", + }, + ], + ), + tooltip: None, + padding_left: None, + padding_right: None, + data: None, + }, + InlayHint { + position: Position { + line: 17, + character: 2, + }, + label: LabelParts( + [ + InlayHintLabelPart { + value: ": [int | str]", + tooltip: None, + location: None, + command: None, + }, + ], + ), + kind: Some( + Type, + ), + text_edits: Some( + [ + TextEdit { + range: Range { + start: Position { + line: 17, + character: 2, + }, + end: Position { + line: 17, + character: 2, + }, + }, + new_text: ": [int | str]", + }, + ], + ), + tooltip: None, + padding_left: None, + padding_right: None, + data: None, + }, + InlayHint { + position: Position { + line: 18, + character: 2, + }, + label: LabelParts( + [ + InlayHintLabelPart { + value: ": {str:str}", + tooltip: None, + location: None, + command: None, + }, + ], + ), + kind: Some( + Type, + ), + text_edits: Some( + [ + TextEdit { + range: Range { + start: Position { + line: 18, + character: 2, + }, + end: Position { + line: 18, + character: 2, + }, + }, + new_text: ": {str:str}", + }, + ], + ), + tooltip: None, + padding_left: None, + padding_right: None, + data: None, + }, + InlayHint { + position: Position { + line: 21, + character: 3, + }, + label: LabelParts( + [ + InlayHintLabelPart { + value: ": number_multiplier(1Ki)", + tooltip: None, + location: None, + command: None, + }, + ], + ), + kind: Some( + Type, + ), + text_edits: Some( + [ + TextEdit { + range: Range { + start: Position { + line: 21, + character: 3, + }, + end: Position { + line: 21, + character: 3, + }, + }, + new_text: ": number_multiplier(1Ki)", + }, + ], + ), + tooltip: None, + padding_left: None, + padding_right: None, + data: None, + }, + InlayHint { + position: Position { + line: 23, + character: 4, + }, + label: LabelParts( + [ + InlayHintLabelPart { + value: ": (any, any, any) -> any", + tooltip: None, + location: None, + command: None, + }, + ], + ), + kind: Some( + Type, + ), + text_edits: Some( + [ + TextEdit { + range: Range { + start: Position { + line: 23, + character: 4, + }, + end: Position { + line: 23, + character: 4, + }, + }, + new_text: ": (any, any, any) -> any", + }, + ], + ), + tooltip: None, + padding_left: None, + padding_right: None, + data: None, + }, + ], +) diff --git a/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__inlay_hints__tests__config_key_ty.snap b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__inlay_hints__tests__config_key_ty.snap new file mode 100644 index 000000000..7ae1593a3 --- /dev/null +++ b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__inlay_hints__tests__config_key_ty.snap @@ -0,0 +1,144 @@ +--- +source: tools/src/LSP/src/inlay_hints.rs +expression: "format! (\"{:#?}\", res)" +--- +Some( + [ + InlayHint { + position: Position { + line: 6, + character: 3, + }, + label: LabelParts( + [ + InlayHintLabelPart { + value: ": App", + tooltip: None, + location: None, + command: None, + }, + ], + ), + kind: Some( + Type, + ), + text_edits: Some( + [ + TextEdit { + range: Range { + start: Position { + line: 6, + character: 3, + }, + end: Position { + line: 6, + character: 3, + }, + }, + new_text: ": App", + }, + ], + ), + tooltip: None, + padding_left: None, + padding_right: None, + data: None, + }, + InlayHint { + position: Position { + line: 7, + character: 5, + }, + label: LabelParts( + [ + InlayHintLabelPart { + value: ": int", + tooltip: None, + location: None, + command: None, + }, + ], + ), + kind: Some( + Type, + ), + text_edits: None, + tooltip: None, + padding_left: None, + padding_right: None, + data: None, + }, + InlayHint { + position: Position { + line: 8, + character: 5, + }, + label: LabelParts( + [ + InlayHintLabelPart { + value: ": 1 | 2", + tooltip: None, + location: None, + command: None, + }, + ], + ), + kind: Some( + Type, + ), + text_edits: None, + tooltip: None, + padding_left: None, + padding_right: None, + data: None, + }, + InlayHint { + position: Position { + line: 9, + character: 5, + }, + label: LabelParts( + [ + InlayHintLabelPart { + value: ": str", + tooltip: None, + location: None, + command: None, + }, + ], + ), + kind: Some( + Type, + ), + text_edits: None, + tooltip: None, + padding_left: None, + padding_right: None, + data: None, + }, + InlayHint { + position: Position { + line: 10, + character: 5, + }, + label: LabelParts( + [ + InlayHintLabelPart { + value: ": \"A\" | \"B\"", + tooltip: None, + location: None, + command: None, + }, + ], + ), + kind: Some( + Type, + ), + text_edits: None, + tooltip: None, + padding_left: None, + padding_right: None, + data: None, + }, + ], +) diff --git a/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__inlay_hints__tests__config_key_ty_1.snap b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__inlay_hints__tests__config_key_ty_1.snap new file mode 100644 index 000000000..94a2071e7 --- /dev/null +++ b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__inlay_hints__tests__config_key_ty_1.snap @@ -0,0 +1,72 @@ +--- +source: tools/src/LSP/src/inlay_hints.rs +expression: "format! (\"{:#?}\", res)" +--- +Some( + [ + InlayHint { + position: Position { + line: 6, + character: 1, + }, + label: LabelParts( + [ + InlayHintLabelPart { + value: ": Person", + tooltip: None, + location: None, + command: None, + }, + ], + ), + kind: Some( + Type, + ), + text_edits: Some( + [ + TextEdit { + range: Range { + start: Position { + line: 6, + character: 1, + }, + end: Position { + line: 6, + character: 1, + }, + }, + new_text: ": Person", + }, + ], + ), + tooltip: None, + padding_left: None, + padding_right: None, + data: None, + }, + InlayHint { + position: Position { + line: 7, + character: 13, + }, + label: LabelParts( + [ + InlayHintLabelPart { + value: ": str", + tooltip: None, + location: None, + command: None, + }, + ], + ), + kind: Some( + Type, + ), + text_edits: None, + tooltip: None, + padding_left: None, + padding_right: None, + data: None, + }, + ], +) diff --git a/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__inlay_hints__tests__function_call_arg_hint.snap b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__inlay_hints__tests__function_call_arg_hint.snap new file mode 100644 index 000000000..43be80669 --- /dev/null +++ b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__inlay_hints__tests__function_call_arg_hint.snap @@ -0,0 +1,616 @@ +--- +source: tools/src/LSP/src/inlay_hints.rs +expression: "format!(\"{:#?}\", res)" +--- +Some( + [ + InlayHint { + position: Position { + line: 0, + character: 1, + }, + label: LabelParts( + [ + InlayHintLabelPart { + value: ": int", + tooltip: None, + location: None, + command: None, + }, + ], + ), + kind: Some( + Type, + ), + text_edits: Some( + [ + TextEdit { + range: Range { + start: Position { + line: 0, + character: 1, + }, + end: Position { + line: 0, + character: 1, + }, + }, + new_text: ": int", + }, + ], + ), + tooltip: None, + padding_left: None, + padding_right: None, + data: None, + }, + InlayHint { + position: Position { + line: 2, + character: 4, + }, + label: LabelParts( + [ + InlayHintLabelPart { + value: ": (any, any, any) -> any", + tooltip: None, + location: None, + command: None, + }, + ], + ), + kind: Some( + Type, + ), + text_edits: Some( + [ + TextEdit { + range: Range { + start: Position { + line: 2, + character: 4, + }, + end: Position { + line: 2, + character: 4, + }, + }, + new_text: ": (any, any, any) -> any", + }, + ], + ), + tooltip: None, + padding_left: None, + padding_right: None, + data: None, + }, + InlayHint { + position: Position { + line: 6, + character: 1, + }, + label: LabelParts( + [ + InlayHintLabelPart { + value: ": any", + tooltip: None, + location: None, + command: None, + }, + ], + ), + kind: Some( + Type, + ), + text_edits: Some( + [ + TextEdit { + range: Range { + start: Position { + line: 6, + character: 1, + }, + end: Position { + line: 6, + character: 1, + }, + }, + new_text: ": any", + }, + ], + ), + tooltip: None, + padding_left: None, + padding_right: None, + data: None, + }, + InlayHint { + position: Position { + line: 6, + character: 9, + }, + label: LabelParts( + [ + InlayHintLabelPart { + value: "x: ", + tooltip: None, + location: None, + command: None, + }, + ], + ), + kind: Some( + Parameter, + ), + text_edits: None, + tooltip: None, + padding_left: None, + padding_right: None, + data: None, + }, + InlayHint { + position: Position { + line: 6, + character: 12, + }, + label: LabelParts( + [ + InlayHintLabelPart { + value: "y: ", + tooltip: None, + location: None, + command: None, + }, + ], + ), + kind: Some( + Parameter, + ), + text_edits: None, + tooltip: None, + padding_left: None, + padding_right: None, + data: None, + }, + InlayHint { + position: Position { + line: 8, + character: 1, + }, + label: LabelParts( + [ + InlayHintLabelPart { + value: ": int", + tooltip: None, + location: None, + command: None, + }, + ], + ), + kind: Some( + Type, + ), + text_edits: Some( + [ + TextEdit { + range: Range { + start: Position { + line: 8, + character: 1, + }, + end: Position { + line: 8, + character: 1, + }, + }, + new_text: ": int", + }, + ], + ), + tooltip: None, + padding_left: None, + padding_right: None, + data: None, + }, + InlayHint { + position: Position { + line: 9, + character: 2, + }, + label: LabelParts( + [ + InlayHintLabelPart { + value: ": any", + tooltip: None, + location: None, + command: None, + }, + ], + ), + kind: Some( + Type, + ), + text_edits: Some( + [ + TextEdit { + range: Range { + start: Position { + line: 9, + character: 2, + }, + end: Position { + line: 9, + character: 2, + }, + }, + new_text: ": any", + }, + ], + ), + tooltip: None, + padding_left: None, + padding_right: None, + data: None, + }, + InlayHint { + position: Position { + line: 9, + character: 13, + }, + label: LabelParts( + [ + InlayHintLabelPart { + value: "y: ", + tooltip: None, + location: None, + command: None, + }, + ], + ), + kind: Some( + Parameter, + ), + text_edits: None, + tooltip: None, + padding_left: None, + padding_right: None, + data: None, + }, + InlayHint { + position: Position { + line: 11, + character: 1, + }, + label: LabelParts( + [ + InlayHintLabelPart { + value: ": int", + tooltip: None, + location: None, + command: None, + }, + ], + ), + kind: Some( + Type, + ), + text_edits: Some( + [ + TextEdit { + range: Range { + start: Position { + line: 11, + character: 1, + }, + end: Position { + line: 11, + character: 1, + }, + }, + new_text: ": int", + }, + ], + ), + tooltip: None, + padding_left: None, + padding_right: None, + data: None, + }, + InlayHint { + position: Position { + line: 11, + character: 12, + }, + label: LabelParts( + [ + InlayHintLabelPart { + value: "sub: ", + tooltip: None, + location: None, + command: None, + }, + ], + ), + kind: Some( + Parameter, + ), + text_edits: None, + tooltip: None, + padding_left: None, + padding_right: None, + data: None, + }, + InlayHint { + position: Position { + line: 11, + character: 19, + }, + label: LabelParts( + [ + InlayHintLabelPart { + value: "start: ", + tooltip: None, + location: None, + command: None, + }, + ], + ), + kind: Some( + Parameter, + ), + text_edits: None, + tooltip: None, + padding_left: None, + padding_right: None, + data: None, + }, + InlayHint { + position: Position { + line: 11, + character: 22, + }, + label: LabelParts( + [ + InlayHintLabelPart { + value: "end: ", + tooltip: None, + location: None, + command: None, + }, + ], + ), + kind: Some( + Parameter, + ), + text_edits: None, + tooltip: None, + padding_left: None, + padding_right: None, + data: None, + }, + InlayHint { + position: Position { + line: 12, + character: 1, + }, + label: LabelParts( + [ + InlayHintLabelPart { + value: ": int", + tooltip: None, + location: None, + command: None, + }, + ], + ), + kind: Some( + Type, + ), + text_edits: Some( + [ + TextEdit { + range: Range { + start: Position { + line: 12, + character: 1, + }, + end: Position { + line: 12, + character: 1, + }, + }, + new_text: ": int", + }, + ], + ), + tooltip: None, + padding_left: None, + padding_right: None, + data: None, + }, + InlayHint { + position: Position { + line: 12, + character: 12, + }, + label: LabelParts( + [ + InlayHintLabelPart { + value: "sub: ", + tooltip: None, + location: None, + command: None, + }, + ], + ), + kind: Some( + Parameter, + ), + text_edits: None, + tooltip: None, + padding_left: None, + padding_right: None, + data: None, + }, + InlayHint { + position: Position { + line: 12, + character: 19, + }, + label: LabelParts( + [ + InlayHintLabelPart { + value: "start: ", + tooltip: None, + location: None, + command: None, + }, + ], + ), + kind: Some( + Parameter, + ), + text_edits: None, + tooltip: None, + padding_left: None, + padding_right: None, + data: None, + }, + InlayHint { + position: Position { + line: 12, + character: 22, + }, + label: LabelParts( + [ + InlayHintLabelPart { + value: "end: ", + tooltip: None, + location: None, + command: None, + }, + ], + ), + kind: Some( + Parameter, + ), + text_edits: None, + tooltip: None, + padding_left: None, + padding_right: None, + data: None, + }, + InlayHint { + position: Position { + line: 13, + character: 1, + }, + label: LabelParts( + [ + InlayHintLabelPart { + value: ": int", + tooltip: None, + location: None, + command: None, + }, + ], + ), + kind: Some( + Type, + ), + text_edits: Some( + [ + TextEdit { + range: Range { + start: Position { + line: 13, + character: 1, + }, + end: Position { + line: 13, + character: 1, + }, + }, + new_text: ": int", + }, + ], + ), + tooltip: None, + padding_left: None, + padding_right: None, + data: None, + }, + InlayHint { + position: Position { + line: 13, + character: 12, + }, + label: LabelParts( + [ + InlayHintLabelPart { + value: "sub: ", + tooltip: None, + location: None, + command: None, + }, + ], + ), + kind: Some( + Parameter, + ), + text_edits: None, + tooltip: None, + padding_left: None, + padding_right: None, + data: None, + }, + InlayHint { + position: Position { + line: 13, + character: 19, + }, + label: LabelParts( + [ + InlayHintLabelPart { + value: "start: ", + tooltip: None, + location: None, + command: None, + }, + ], + ), + kind: Some( + Parameter, + ), + text_edits: None, + tooltip: None, + padding_left: None, + padding_right: None, + data: None, + }, + InlayHint { + position: Position { + line: 13, + character: 22, + }, + label: LabelParts( + [ + InlayHintLabelPart { + value: "end: ", + tooltip: None, + location: None, + command: None, + }, + ], + ), + kind: Some( + Parameter, + ), + text_edits: None, + tooltip: None, + padding_left: None, + padding_right: None, + data: None, + }, + ], +) diff --git a/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__inlay_hints__tests__schema_arg_hint.snap b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__inlay_hints__tests__schema_arg_hint.snap new file mode 100644 index 000000000..1a655ca67 --- /dev/null +++ b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__inlay_hints__tests__schema_arg_hint.snap @@ -0,0 +1,176 @@ +--- +source: tools/src/LSP/src/inlay_hints.rs +expression: "format!(\"{:#?}\", res)" +--- +Some( + [ + InlayHint { + position: Position { + line: 1, + character: 5, + }, + label: LabelParts( + [ + InlayHintLabelPart { + value: ": int", + tooltip: None, + location: None, + command: None, + }, + ], + ), + kind: Some( + Type, + ), + text_edits: Some( + [ + TextEdit { + range: Range { + start: Position { + line: 1, + character: 5, + }, + end: Position { + line: 1, + character: 5, + }, + }, + new_text: ": int", + }, + ], + ), + tooltip: None, + padding_left: None, + padding_right: None, + data: None, + }, + InlayHint { + position: Position { + line: 2, + character: 5, + }, + label: LabelParts( + [ + InlayHintLabelPart { + value: ": str", + tooltip: None, + location: None, + command: None, + }, + ], + ), + kind: Some( + Type, + ), + text_edits: Some( + [ + TextEdit { + range: Range { + start: Position { + line: 2, + character: 5, + }, + end: Position { + line: 2, + character: 5, + }, + }, + new_text: ": str", + }, + ], + ), + tooltip: None, + padding_left: None, + padding_right: None, + data: None, + }, + InlayHint { + position: Position { + line: 4, + character: 1, + }, + label: LabelParts( + [ + InlayHintLabelPart { + value: ": Person", + tooltip: None, + location: None, + command: None, + }, + ], + ), + kind: Some( + Type, + ), + text_edits: Some( + [ + TextEdit { + range: Range { + start: Position { + line: 4, + character: 1, + }, + end: Position { + line: 4, + character: 1, + }, + }, + new_text: ": Person", + }, + ], + ), + tooltip: None, + padding_left: None, + padding_right: None, + data: None, + }, + InlayHint { + position: Position { + line: 4, + character: 11, + }, + label: LabelParts( + [ + InlayHintLabelPart { + value: "age: ", + tooltip: None, + location: None, + command: None, + }, + ], + ), + kind: Some( + Parameter, + ), + text_edits: None, + tooltip: None, + padding_left: None, + padding_right: None, + data: None, + }, + InlayHint { + position: Position { + line: 4, + character: 14, + }, + label: LabelParts( + [ + InlayHintLabelPart { + value: "name: ", + tooltip: None, + location: None, + command: None, + }, + ], + ), + kind: Some( + Parameter, + ), + text_edits: None, + tooltip: None, + padding_left: None, + padding_right: None, + data: None, + }, + ], +) diff --git a/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__semantic_token__tests__semantic_tokens_full_test.snap b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__semantic_token__tests__semantic_tokens_full_test.snap new file mode 100644 index 000000000..2d75a79ad --- /dev/null +++ b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__semantic_token__tests__semantic_tokens_full_test.snap @@ -0,0 +1,5 @@ +--- +source: tools/src/LSP/src/semantic_token.rs +expression: "format!(\"{:?}\", get)" +--- +[(0, 15, 1, 3), (1, 5, 3, 4), (1, 7, 7, 1), (1, 4, 4, 2), (2, 0, 2, 0), (0, 4, 7, 1), (0, 10, 7, 1), (1, 4, 4, 2), (2, 0, 1, 0), (0, 3, 3, 4), (2, 0, 4, 8), (0, 14, 1, 0), (1, 4, 1, 0), (3, 0, 1, 0), (0, 4, 4, 8), (1, 0, 1, 0), (0, 4, 4, 8), (0, 5, 1, 0), (2, 7, 8, 1), (1, 5, 4, 0), (2, 0, 3, 0), (0, 5, 3, 4), (2, 0, 3, 0), (0, 10, 4, 0)] diff --git a/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__signature_help__tests__builtin_function_signature_help_test_0.snap b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__signature_help__tests__builtin_function_signature_help_test_0.snap new file mode 100644 index 000000000..6f4ebea78 --- /dev/null +++ b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__signature_help__tests__builtin_function_signature_help_test_0.snap @@ -0,0 +1,43 @@ +--- +source: tools/src/LSP/src/signature_help.rs +expression: "format!(\"{:#?}\", res)" +--- +SignatureHelp { + signatures: [ + SignatureInformation { + label: "function pow(x: int | float, y: int | float, z: int | float) -> int | float", + documentation: Some( + String( + "Equivalent to `x ** y` (with two arguments) or `x ** y % z` (with three arguments)\n\nSome types, such as ints, are able to use a more efficient algorithm when\ninvoked using the three argument form.", + ), + ), + parameters: Some( + [ + ParameterInformation { + label: Simple( + "x: int | float", + ), + documentation: None, + }, + ParameterInformation { + label: Simple( + "y: int | float", + ), + documentation: None, + }, + ParameterInformation { + label: Simple( + "z: int | float", + ), + documentation: None, + }, + ], + ), + active_parameter: Some( + 0, + ), + }, + ], + active_signature: None, + active_parameter: None, +} diff --git a/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__signature_help__tests__builtin_function_signature_help_test_1.snap b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__signature_help__tests__builtin_function_signature_help_test_1.snap new file mode 100644 index 000000000..90cbb6c07 --- /dev/null +++ b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__signature_help__tests__builtin_function_signature_help_test_1.snap @@ -0,0 +1,43 @@ +--- +source: tools/src/LSP/src/signature_help.rs +expression: "format!(\"{:#?}\", res)" +--- +SignatureHelp { + signatures: [ + SignatureInformation { + label: "function pow(x: int | float, y: int | float, z: int | float) -> int | float", + documentation: Some( + String( + "Equivalent to `x ** y` (with two arguments) or `x ** y % z` (with three arguments)\n\nSome types, such as ints, are able to use a more efficient algorithm when\ninvoked using the three argument form.", + ), + ), + parameters: Some( + [ + ParameterInformation { + label: Simple( + "x: int | float", + ), + documentation: None, + }, + ParameterInformation { + label: Simple( + "y: int | float", + ), + documentation: None, + }, + ParameterInformation { + label: Simple( + "z: int | float", + ), + documentation: None, + }, + ], + ), + active_parameter: Some( + 1, + ), + }, + ], + active_signature: None, + active_parameter: None, +} diff --git a/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__signature_help__tests__lambda_signatue_help_test_0.snap b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__signature_help__tests__lambda_signatue_help_test_0.snap new file mode 100644 index 000000000..357ea5051 --- /dev/null +++ b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__signature_help__tests__lambda_signatue_help_test_0.snap @@ -0,0 +1,39 @@ +--- +source: tools/src/LSP/src/signature_help.rs +expression: "format!(\"{:#?}\", res)" +--- +SignatureHelp { + signatures: [ + SignatureInformation { + label: "function func(x: any, y: any, z: any) -> any", + documentation: None, + parameters: Some( + [ + ParameterInformation { + label: Simple( + "x: any", + ), + documentation: None, + }, + ParameterInformation { + label: Simple( + "y: any", + ), + documentation: None, + }, + ParameterInformation { + label: Simple( + "z: any", + ), + documentation: None, + }, + ], + ), + active_parameter: Some( + 0, + ), + }, + ], + active_signature: None, + active_parameter: None, +} diff --git a/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__signature_help__tests__lambda_signatue_help_test_1.snap b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__signature_help__tests__lambda_signatue_help_test_1.snap new file mode 100644 index 000000000..4609efb2d --- /dev/null +++ b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__signature_help__tests__lambda_signatue_help_test_1.snap @@ -0,0 +1,39 @@ +--- +source: tools/src/LSP/src/signature_help.rs +expression: "format!(\"{:#?}\", res)" +--- +SignatureHelp { + signatures: [ + SignatureInformation { + label: "function func(x: any, y: any, z: any) -> any", + documentation: None, + parameters: Some( + [ + ParameterInformation { + label: Simple( + "x: any", + ), + documentation: None, + }, + ParameterInformation { + label: Simple( + "y: any", + ), + documentation: None, + }, + ParameterInformation { + label: Simple( + "z: any", + ), + documentation: None, + }, + ], + ), + active_parameter: Some( + 1, + ), + }, + ], + active_signature: None, + active_parameter: None, +} diff --git a/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__signature_help__tests__lambda_signatue_help_test_2.snap b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__signature_help__tests__lambda_signatue_help_test_2.snap new file mode 100644 index 000000000..7b2a70480 --- /dev/null +++ b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__signature_help__tests__lambda_signatue_help_test_2.snap @@ -0,0 +1,39 @@ +--- +source: tools/src/LSP/src/signature_help.rs +expression: "format!(\"{:#?}\", res)" +--- +SignatureHelp { + signatures: [ + SignatureInformation { + label: "function func(x: any, y: any, z: any) -> any", + documentation: None, + parameters: Some( + [ + ParameterInformation { + label: Simple( + "x: any", + ), + documentation: None, + }, + ParameterInformation { + label: Simple( + "y: any", + ), + documentation: None, + }, + ParameterInformation { + label: Simple( + "z: any", + ), + documentation: None, + }, + ], + ), + active_parameter: Some( + 2, + ), + }, + ], + active_signature: None, + active_parameter: None, +} diff --git a/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__signature_help__tests__lambda_signatue_help_test_3.snap b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__signature_help__tests__lambda_signatue_help_test_3.snap new file mode 100644 index 000000000..980245199 --- /dev/null +++ b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__signature_help__tests__lambda_signatue_help_test_3.snap @@ -0,0 +1,39 @@ +--- +source: tools/src/LSP/src/signature_help.rs +expression: "format!(\"{:#?}\", res)" +--- +SignatureHelp { + signatures: [ + SignatureInformation { + label: "function func(x: any, y: any, z: any) -> any", + documentation: None, + parameters: Some( + [ + ParameterInformation { + label: Simple( + "x: any", + ), + documentation: None, + }, + ParameterInformation { + label: Simple( + "y: any", + ), + documentation: None, + }, + ParameterInformation { + label: Simple( + "z: any", + ), + documentation: None, + }, + ], + ), + active_parameter: Some( + 3, + ), + }, + ], + active_signature: None, + active_parameter: None, +} diff --git a/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__signature_help__tests__pkg_function_signature_help_test_0.snap b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__signature_help__tests__pkg_function_signature_help_test_0.snap new file mode 100644 index 000000000..64ee3219b --- /dev/null +++ b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__signature_help__tests__pkg_function_signature_help_test_0.snap @@ -0,0 +1,37 @@ +--- +source: tools/src/LSP/src/signature_help.rs +expression: "format!(\"{:#?}\", res)" +--- +SignatureHelp { + signatures: [ + SignatureInformation { + label: "function gcd(a: int, b: int) -> int", + documentation: Some( + String( + "Return the greatest common divisor of `x` and `y`.", + ), + ), + parameters: Some( + [ + ParameterInformation { + label: Simple( + "a: int", + ), + documentation: None, + }, + ParameterInformation { + label: Simple( + "b: int", + ), + documentation: None, + }, + ], + ), + active_parameter: Some( + 0, + ), + }, + ], + active_signature: None, + active_parameter: None, +} diff --git a/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__signature_help__tests__pkg_function_signature_help_test_1.snap b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__signature_help__tests__pkg_function_signature_help_test_1.snap new file mode 100644 index 000000000..496ff88c5 --- /dev/null +++ b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__signature_help__tests__pkg_function_signature_help_test_1.snap @@ -0,0 +1,33 @@ +--- +source: tools/src/LSP/src/signature_help.rs +expression: "format!(\"{:#?}\", res)" +--- +SignatureHelp { + signatures: [ + SignatureInformation { + label: "function gcd(a: int, b: int) -> int", + documentation: None, + parameters: Some( + [ + ParameterInformation { + label: Simple( + "a: int", + ), + documentation: None, + }, + ParameterInformation { + label: Simple( + "b: int", + ), + documentation: None, + }, + ], + ), + active_parameter: Some( + 1, + ), + }, + ], + active_signature: None, + active_parameter: None, +} diff --git a/kclvm/tools/src/LSP/src/state.rs b/kclvm/tools/src/LSP/src/state.rs new file mode 100644 index 000000000..d377b153b --- /dev/null +++ b/kclvm/tools/src/LSP/src/state.rs @@ -0,0 +1,842 @@ +use crate::analysis::{Analysis, AnalysisDatabase, DBState, OpenFileInfo}; +use crate::compile::{compile, Params}; +use crate::from_lsp::file_path_from_url; +use crate::to_lsp::{kcl_diag_to_lsp_diags, url_from_path}; +use crate::util::{filter_kcl_config_file, get_file_name, to_json}; +use crossbeam_channel::{select, unbounded, Receiver, Sender}; +use indexmap::IndexSet; +use kclvm_driver::toolchain::{self, Toolchain}; +use kclvm_driver::{ + lookup_compile_workspace, lookup_compile_workspaces, CompileUnitOptions, WorkSpaceKind, +}; +use kclvm_parser::KCLModuleCache; +use kclvm_sema::core::global_state::GlobalState; +use kclvm_sema::resolver::scope::KCLScopeCache; +use lsp_server::RequestId; +use lsp_server::{ReqQueue, Request, Response}; +use lsp_types::{ + notification::{Notification, PublishDiagnostics}, + InitializeParams, PublishDiagnosticsParams, WorkspaceFolder, +}; +use notify::{RecommendedWatcher, RecursiveMode, Watcher}; +use parking_lot::RwLock; +use ra_ap_vfs::{ChangeKind, ChangedFile, FileId, Vfs}; +use std::collections::HashMap; +use std::path::{Path, PathBuf}; +use std::sync::Mutex; +use std::thread; +use std::time::Duration; +use std::{sync::mpsc, sync::Arc, time::Instant}; + +pub(crate) type RequestHandler = fn(&mut LanguageServerState, lsp_server::Response); + +/// A `Task` is something that is send from async tasks to the entry point for processing. This +/// enables synchronizing resources like the connection with the client. +#[allow(unused)] +#[derive(Debug, Clone)] +pub(crate) enum Task { + Response(Response), + Notify(lsp_server::Notification), + Retry(Request), + ChangedFile(FileId, ChangeKind), + ReOpenFile(FileId, ChangeKind), +} + +#[derive(Debug, Clone)] +pub(crate) enum Event { + Task(Task), + Lsp(lsp_server::Message), + FileWatcher(FileWatcherEvent), +} + +#[allow(unused)] +#[derive(Debug, Clone)] +pub(crate) enum FileWatcherEvent { + ChangedConfigFile(Vec), + RemoveConfigFile(Vec), + CreateConfigFile(Vec), +} + +pub(crate) struct Handle { + pub(crate) handle: H, + pub(crate) _receiver: C, +} + +pub(crate) type KCLVfs = Arc>; + +pub(crate) type KCLWorkSpaceConfigCache = Arc>>; + +pub(crate) type KCLToolChain = Arc>; +pub(crate) type KCLGlobalStateCache = Arc>; + +/// State for the language server +pub(crate) struct LanguageServerState { + /// Channel to send language server messages to the client + pub(crate) sender: Sender, + /// The request queue keeps track of all incoming and outgoing requests. + pub(crate) request_queue: lsp_server::ReqQueue<(String, Instant), RequestHandler>, + /// Thread pool for async execution + pub thread_pool: threadpool::ThreadPool, + /// Channel to send tasks to from background operations + pub task_sender: Sender, + /// Channel to receive tasks on from background operations + pub task_receiver: Receiver, + /// True if the client requested that we shut down + pub shutdown_requested: bool, + /// The virtual filesystem that holds all the file contents + pub vfs: KCLVfs, + /// Holds the state of the analysis process + pub analysis: Analysis, + /// Documents that are currently kept in memory from the client + pub opened_files: Arc>>, + /// The VFS loader + pub loader: Handle, Receiver>, + /// request retry time + pub request_retry: Arc>>, + /// KCL parse cache + pub module_cache: KCLModuleCache, + /// KCL resolver cache + pub scope_cache: KCLScopeCache, + /// Toolchain is used to provider KCL tool features for the language server. + pub tool: KCLToolChain, + /// KCL globalstate cache + pub gs_cache: KCLGlobalStateCache, + /// Compile config cache + pub workspace_config_cache: KCLWorkSpaceConfigCache, + /// Process files that are not in any defined workspace and delete the workspace when closing the file + pub temporary_workspace: Arc>>>, + pub workspace_folders: Option>, + /// Actively monitor file system changes. These changes will not be notified through lsp, + /// e.g., execute `kcl mod add xxx`, `kcl fmt xxx` + pub fs_event_watcher: Handle< + Box, + mpsc::Receiver>, + >, +} + +/// A snapshot of the state of the language server +#[allow(unused)] +pub(crate) struct LanguageServerSnapshot { + /// The virtual filesystem that holds all the file contents + pub vfs: Arc>, + /// Holds the state of the analysis process + pub workspaces: Arc>>, + /// Documents that are currently kept in memory from the client + pub opened_files: Arc>>, + /// request retry time + pub request_retry: Arc>>, + /// KCL parse cache + pub module_cache: KCLModuleCache, + /// KCL resolver cache + pub scope_cache: KCLScopeCache, + /// Toolchain is used to provider KCL tool features for the language server. + pub tool: KCLToolChain, + /// Process files that are not in any defined workspace and delete the work + pub temporary_workspace: Arc>>>, + /// Compile config cache + pub workspace_config_cache: KCLWorkSpaceConfigCache, +} + +#[allow(unused)] +impl LanguageServerState { + pub fn new(sender: Sender, initialize_params: InitializeParams) -> Self { + let (task_sender, task_receiver) = unbounded::(); + + let loader = { + let (sender, _receiver) = unbounded::(); + let handle: ra_ap_vfs_notify::NotifyHandle = + ra_ap_vfs::loader::Handle::spawn(Box::new(move |msg| sender.send(msg).unwrap())); + let handle = Box::new(handle) as Box; + Handle { handle, _receiver } + }; + + let fs_event_watcher = { + let (tx, rx) = mpsc::channel::>(); + let mut watcher = notify::recommended_watcher(tx).unwrap(); + let handle = Box::new(watcher); + Handle { + handle, + _receiver: rx, + } + }; + + let mut state = LanguageServerState { + sender, + request_queue: ReqQueue::default(), + vfs: Arc::new(RwLock::new(Default::default())), + thread_pool: threadpool::ThreadPool::default(), + task_sender: task_sender.clone(), + task_receiver, + shutdown_requested: false, + analysis: Analysis::default(), + opened_files: Arc::new(RwLock::new(HashMap::new())), + loader, + module_cache: KCLModuleCache::default(), + scope_cache: KCLScopeCache::default(), + tool: Arc::new(RwLock::new(toolchain::default())), + gs_cache: KCLGlobalStateCache::default(), + request_retry: Arc::new(RwLock::new(HashMap::new())), + workspace_config_cache: KCLWorkSpaceConfigCache::default(), + temporary_workspace: Arc::new(RwLock::new(HashMap::new())), + workspace_folders: initialize_params.workspace_folders.clone(), + fs_event_watcher, + }; + + state.init_workspaces(); + + state + } + + /// Blocks until a new event is received from one of the many channels the language server + /// listens to. Returns the first event that is received. + fn next_event(&self, receiver: &Receiver) -> Option { + for event in self.fs_event_watcher._receiver.try_iter() { + if let Ok(e) = event { + match e.kind { + notify::EventKind::Modify(kind) => { + if let notify::event::ModifyKind::Data(data_change) = kind { + if let notify::event::DataChange::Content = data_change { + let paths = e.paths; + let kcl_config_file: Vec = filter_kcl_config_file(&paths); + if !kcl_config_file.is_empty() { + // TODO: wait for fix `kcl mod metadata` to read only. Otherwise it will lead to an infinite loop + // return Some(Event::FileWatcher( + // FileWatcherEvent::ChangedConfigFile(kcl_config_file), + // )); + } + } + } + } + notify::EventKind::Remove(remove_kind) => { + if let notify::event::RemoveKind::File = remove_kind { + let paths = e.paths; + let kcl_config_file: Vec = filter_kcl_config_file(&paths); + if !kcl_config_file.is_empty() { + return Some(Event::FileWatcher( + FileWatcherEvent::RemoveConfigFile(kcl_config_file), + )); + } + } + } + + notify::EventKind::Create(create_kind) => { + if let notify::event::CreateKind::File = create_kind { + let paths = e.paths; + let kcl_config_file: Vec = filter_kcl_config_file(&paths); + if !kcl_config_file.is_empty() { + return Some(Event::FileWatcher( + FileWatcherEvent::CreateConfigFile(kcl_config_file), + )); + } + } + } + _ => {} + } + } + } + + select! { + recv(receiver) -> msg => msg.ok().map(Event::Lsp), + recv(self.task_receiver) -> task => Some(Event::Task(task.unwrap())), + } + } + + /// Runs the language server to completion + pub fn run(mut self, receiver: Receiver) -> anyhow::Result<()> { + while let Some(event) = self.next_event(&receiver) { + if let Event::Lsp(lsp_server::Message::Notification(notification)) = &event { + if notification.method == lsp_types::notification::Exit::METHOD { + return Ok(()); + } + } + self.handle_event(event)?; + } + Ok(()) + } + + /// Handles an event from one of the many sources that the language server subscribes to. + fn handle_event(&mut self, event: Event) -> anyhow::Result<()> { + let start_time = Instant::now(); + // 1. Process the incoming event + match event { + Event::Task(task) => self.handle_task(task, start_time)?, + Event::Lsp(msg) => { + match msg { + lsp_server::Message::Request(req) => self.on_request(req, start_time)?, + lsp_server::Message::Notification(not) => self.on_notification(not)?, + // lsp_server::Message::Response(resp) => self.complete_request(resp), + _ => {} + } + } + Event::FileWatcher(file_watcher_event) => { + self.handle_file_watcher_event(file_watcher_event)? + } + }; + + // 2. Process changes + + self.process_vfs_changes(); + Ok(()) + } + + /// Processes any and all changes that have been applied to the virtual filesystem. Generates + /// an `AnalysisChange` and applies it if there are changes. True is returned if things changed, + /// otherwise false. + pub fn process_vfs_changes(&mut self) -> bool { + // Get all the changes since the last time we processed + let changed_files = { + let mut vfs = self.vfs.write(); + vfs.take_changes() + }; + if changed_files.is_empty() { + return false; + } + + // Construct an AnalysisChange to apply to the analysis + for file in changed_files { + self.process_changed_file(file); + } + true + } + + /// Process vfs changed file. Update db cache when create(did_open_file), modify(did_change) or delete(did_close_file) vfs files. + fn process_changed_file(&mut self, file: ChangedFile) { + match file.change_kind { + // open file + ChangeKind::Create => { + let filename = get_file_name(self.vfs.read(), file.file_id); + self.log_message(format!("Process changed file, open {:?}", filename)); + match filename { + Ok(filename) => { + let uri = url_from_path(&filename).unwrap(); + let mut state_workspaces = self.analysis.workspaces.read(); + self.temporary_workspace.write().insert(file.file_id, None); + + let mut may_contain = false; + + // If some workspace has compiled this file, record open file's workspace + for (workspace, state) in state_workspaces.iter() { + match state { + DBState::Ready(db) => { + if db.prog.modules.get(&filename).is_some() { + let mut openfiles = self.opened_files.write(); + let file_info = openfiles.get_mut(&file.file_id).unwrap(); + file_info.workspaces.insert(workspace.clone()); + drop(openfiles); + may_contain = true; + } + } + DBState::Compiling(_) | DBState::Init => { + may_contain = true; + self.task_sender + .send(Task::ChangedFile(file.file_id, file.change_kind)) + .unwrap(); + } + DBState::Failed(_) => continue, + } + } + + // If all workspaces do not contain the current file, get files workspace and store in temporary_workspace + if !may_contain { + self.log_message(format!( + "Not contains in any workspace, compile: {:?}", + filename + )); + + let tool = Arc::clone(&self.tool); + let (workspaces, failed) = match Path::new(&filename).parent() { + Some(parent_dir) => { + let (workspaces, failed) = lookup_compile_workspaces( + &*tool.read(), + &parent_dir.to_str().unwrap().to_string(), + true, + ); + if workspaces.is_empty() { + lookup_compile_workspaces(&*tool.read(), &filename, true) + } else { + (workspaces, failed) + } + } + None => lookup_compile_workspaces(&*tool.read(), &filename, true), + }; + + if workspaces.is_empty() { + self.temporary_workspace.write().remove(&file.file_id); + self.log_message(format!( + "Not found any workspace for {:?}", + filename + )); + } else { + for (workspace, opts) in workspaces { + self.async_compile(workspace, opts, Some(file.file_id), true); + } + } + } else { + self.temporary_workspace.write().remove(&file.file_id); + } + } + Err(err) => self.log_message(format!("{:?} not found: {}", file.file_id, err)), + } + } + // edit file + ChangeKind::Modify => { + let filename = get_file_name(self.vfs.read(), file.file_id); + self.log_message(format!("Process changed file, modify {:?}", filename)); + match filename { + Ok(filename) => { + let opened_files = self.opened_files.read(); + let file_workspaces = + opened_files.get(&file.file_id).unwrap().workspaces.clone(); + + // In workspace + if !file_workspaces.is_empty() { + for workspace in file_workspaces { + let opts = self + .workspace_config_cache + .read() + .get(&workspace) + .unwrap() + .clone(); + + self.async_compile(workspace, opts, Some(file.file_id), false); + } + } else { + // In temporary_workspace + let workspace = match self.temporary_workspace.read().get(&file.file_id) + { + Some(w) => match w { + Some(w) => Some(w.clone()), + None => { + // In compiling, retry and wait for compile complete + self.task_sender + .send(Task::ChangedFile(file.file_id, file.change_kind)) + .unwrap(); + None + } + }, + None => None, + }; + match workspace { + Some(workspace) => { + let opts = self + .workspace_config_cache + .read() + .get(&workspace) + .unwrap() + .clone(); + + self.async_compile(workspace, opts, Some(file.file_id), true); + } + None => { + self.log_message(format!( + "Internal Bug: not found any workspace for file {:?}. Try to reload", + filename + )); + + self.task_sender + .send(Task::ReOpenFile(file.file_id, ChangeKind::Create)) + .unwrap(); + } + } + } + } + Err(err) => { + self.log_message(format!("{:?} not found: {}", file.file_id, err)); + } + } + } + // close file + ChangeKind::Delete => { + let filename = get_file_name(self.vfs.read(), file.file_id); + self.log_message(format!("Process changed file, close {:?}", filename)); + + let mut temporary_workspace = self.temporary_workspace.write(); + if let Some(workspace) = temporary_workspace.remove(&file.file_id) { + let mut workspaces = self.analysis.workspaces.write(); + if let Some(w) = workspace { + let opened_file = self.opened_files.read(); + let contain = opened_file.values().any(|f| f.workspaces.contains(&w)); + + if !contain { + self.log_message(format!("Remove workspace {:?}", w)); + workspaces.remove(&w); + } + } + } + } + } + } + + /// Handles a task sent by another async task + #[allow(clippy::unnecessary_wraps)] + fn handle_task(&mut self, task: Task, request_received: Instant) -> anyhow::Result<()> { + match task { + Task::Notify(notification) => { + self.send(notification.into()); + } + Task::Response(response) => self.respond(response)?, + Task::Retry(req) if !self.is_completed(&req) => { + thread::sleep(Duration::from_millis(20)); + self.on_request(req, request_received)? + } + Task::Retry(_) => (), + Task::ChangedFile(file_id, change_kind) => { + thread::sleep(Duration::from_millis(20)); + self.process_changed_file(ChangedFile { + file_id, + change_kind, + }) + } + Task::ReOpenFile(file_id, change_kind) => self.process_changed_file(ChangedFile { + file_id, + change_kind, + }), + } + Ok(()) + } + + /// Handles a task sent by another async task + #[allow(clippy::unnecessary_wraps)] + fn handle_file_watcher_event(&mut self, event: FileWatcherEvent) -> anyhow::Result<()> { + match event { + FileWatcherEvent::ChangedConfigFile(paths) => self.handle_changed_confg_file(&paths), + FileWatcherEvent::CreateConfigFile(paths) => self.handle_create_confg_file(&paths), + FileWatcherEvent::RemoveConfigFile(paths) => self.handle_remove_confg_file(&paths), + } + Ok(()) + } + + /// Sends a response to the client. This method logs the time it took us to reply + /// to a request from the client. + pub(super) fn respond(&mut self, response: lsp_server::Response) -> anyhow::Result<()> { + if let Some((method, start)) = self.request_queue.incoming.complete(&response.id) { + let duration = start.elapsed(); + self.send(response.into())?; + self.log_message(format!( + "Finished request {:?} in {:?} micros", + method, + duration.as_micros() + )); + } + Ok(()) + } + + /// Sends a message to the client + pub(crate) fn send(&self, message: lsp_server::Message) -> anyhow::Result<()> { + self.sender.send(message)?; + Ok(()) + } + + /// Registers a request with the server. We register all these request to make sure they all get + /// handled and so we can measure the time it takes for them to complete from the point of view + /// of the client. + pub(crate) fn register_request( + &mut self, + request: &lsp_server::Request, + request_received: Instant, + ) { + self.request_queue.incoming.register( + request.id.clone(), + (request.method.clone(), request_received), + ) + } + + pub fn snapshot(&self) -> LanguageServerSnapshot { + LanguageServerSnapshot { + vfs: self.vfs.clone(), + opened_files: self.opened_files.clone(), + module_cache: self.module_cache.clone(), + scope_cache: self.scope_cache.clone(), + tool: self.tool.clone(), + request_retry: self.request_retry.clone(), + workspaces: self.analysis.workspaces.clone(), + temporary_workspace: self.temporary_workspace.clone(), + workspace_config_cache: self.workspace_config_cache.clone(), + } + } + + pub fn log_message(&self, message: String) { + let typ = lsp_types::MessageType::INFO; + let not = lsp_server::Notification::new( + lsp_types::notification::LogMessage::METHOD.to_string(), + lsp_types::LogMessageParams { typ, message }, + ); + self.send(not.into()); + } + + pub(crate) fn is_completed(&self, request: &lsp_server::Request) -> bool { + self.request_queue.incoming.is_completed(&request.id) + } + + pub(crate) fn init_workspaces(&mut self) { + self.log_message("Init workspaces".to_string()); + if let Some(workspace_folders) = &self.workspace_folders { + for folder in workspace_folders { + let path = file_path_from_url(&folder.uri).unwrap(); + let mut watcher = &mut self.fs_event_watcher.handle; + watcher + .watch(std::path::Path::new(&path), RecursiveMode::Recursive) + .unwrap(); + self.log_message(format!("Start watch {:?}", path)); + let tool = Arc::clone(&self.tool); + let (workspaces, failed) = lookup_compile_workspaces(&*tool.read(), &path, true); + + if let Some(failed) = failed { + for (key, err) in failed { + self.log_message(format!("parse kcl.work failed: {}: {}", key, err)); + } + } + + for (workspace, opts) in workspaces { + self.async_compile(workspace, opts, None, false); + } + } + } + } + + pub(crate) fn async_compile( + &self, + workspace: WorkSpaceKind, + opts: CompileUnitOptions, + changed_file_id: Option, + temp: bool, + ) { + let filename = match changed_file_id { + Some(id) => get_file_name(self.vfs.read(), id).ok(), + None => None, + }; + + let mut workspace_config_cache = self.workspace_config_cache.write(); + workspace_config_cache.insert(workspace.clone(), opts.clone()); + drop(workspace_config_cache); + + self.thread_pool.execute({ + let mut snapshot = self.snapshot(); + let sender = self.task_sender.clone(); + let module_cache = Arc::clone(&self.module_cache); + let scope_cache = Arc::clone(&self.scope_cache); + let tool = Arc::clone(&self.tool); + let gs_cache = Arc::clone(&self.gs_cache); + + let mut files = opts.0.clone(); + move || { + let old_diags = { + match snapshot.workspaces.read().get(&workspace) { + Some(option_db) => match option_db { + DBState::Ready(db) => db.diags.clone(), + DBState::Compiling(db) => db.diags.clone(), + DBState::Init | DBState::Failed(_) => IndexSet::new(), + }, + None => IndexSet::new(), + } + }; + + { + let mut workspaces = snapshot.workspaces.write(); + let state = match workspaces.get_mut(&workspace) { + Some(state) => match state { + DBState::Ready(db) => DBState::Compiling(db.clone()), + DBState::Compiling(db) => DBState::Compiling(db.clone()), + DBState::Init | DBState::Failed(_) => DBState::Init, + }, + None => DBState::Init, + }; + workspaces.insert(workspace.clone(), state); + } + let start = Instant::now(); + + let (diags, compile_res) = compile( + Params { + file: filename.clone(), + module_cache: Some(module_cache), + scope_cache: Some(scope_cache), + vfs: Some(snapshot.vfs), + gs_cache: Some(gs_cache), + }, + &mut files, + opts.1.clone(), + ); + + log_message( + format!( + "Compile workspace: {:?}, main_pkg files: {:?}, changed file: {:?}, options: {:?}, metadate: {:?}, use {:?} micros", + workspace, + files, + filename, + opts.1, + opts.2, + start.elapsed().as_micros() + ), + &sender, + ); + + let mut old_diags_maps = HashMap::new(); + for diag in &old_diags { + let lsp_diag = kcl_diag_to_lsp_diags(diag); + for (key, value) in lsp_diag { + old_diags_maps.entry(key).or_insert(vec![]).extend(value); + } + } + + // publish diags + let mut new_diags_maps = HashMap::new(); + + for diag in &diags { + let lsp_diag = kcl_diag_to_lsp_diags(diag); + for (key, value) in lsp_diag { + new_diags_maps.entry(key).or_insert(vec![]).extend(value); + } + } + + for (file, diags) in old_diags_maps { + if !new_diags_maps.contains_key(&file) { + if let Ok(uri) = url_from_path(file) { + sender.send(Task::Notify(lsp_server::Notification { + method: PublishDiagnostics::METHOD.to_owned(), + params: to_json(PublishDiagnosticsParams { + uri: uri.clone(), + diagnostics: vec![], + version: None, + }) + .unwrap(), + })); + } + } + } + + for (filename, diagnostics) in new_diags_maps { + if let Ok(uri) = url_from_path(filename) { + sender.send(Task::Notify(lsp_server::Notification { + method: PublishDiagnostics::METHOD.to_owned(), + params: to_json(PublishDiagnosticsParams { + uri: uri.clone(), + diagnostics, + version: None, + }) + .unwrap(), + })); + } + } + + match compile_res { + Ok((prog, schema_map, gs)) => { + let mut workspaces = snapshot.workspaces.write(); + log_message( + format!( + "Workspace {:?} compile success",workspace + ), + &sender, + ); + workspaces.insert( + workspace.clone(), + DBState::Ready(Arc::new(AnalysisDatabase { prog, gs, diags,schema_map })), + ); + drop(workspaces); + if temp && changed_file_id.is_some() { + let mut temporary_workspace = snapshot.temporary_workspace.write(); + + log_message( + format!( + "Insert file {:?} and workspace {:?} to temporary workspace", filename, workspace + ), + &sender, + ); + temporary_workspace + .insert(changed_file_id.unwrap(), Some(workspace.clone())); + drop(temporary_workspace); + } + } + Err(e) => { + let mut workspaces = snapshot.workspaces.write(); + log_message( + format!( + "Workspace {:?} compile failed: {:?}",workspace, e + ), + &sender, + ); + workspaces.insert(workspace, DBState::Failed(e.to_string())); + if temp && changed_file_id.is_some() { + let mut temporary_workspace = snapshot.temporary_workspace.write(); + log_message( + format!( + "Reomve temporary workspace file id: {:?}",changed_file_id + ), + &sender, + ); + temporary_workspace.remove(&changed_file_id.unwrap()); + drop(temporary_workspace); + } + } + } + } + }) + } + + // Configuration file modifications that do not occur on the IDE client side, e.g., `kcl mod add xxx`` + pub(crate) fn handle_changed_confg_file(&self, paths: &[PathBuf]) { + for path in paths { + self.log_message(format!("Changed config file {:?}", path)); + // In workspaces + let mut workspaces = self.analysis.workspaces.write(); + for workspace in workspaces.keys() { + if let Some(p) = match workspace { + WorkSpaceKind::ModFile(path_buf) => Some(path_buf.clone()), + WorkSpaceKind::SettingFile(path_buf) => Some(path_buf.clone()), + _ => None, + } { + let opts = + lookup_compile_workspace(&*self.tool.read(), &p.to_str().unwrap(), true); + self.async_compile(workspace.clone(), opts, None, false); + } + } + drop(workspaces); + + // In temp workspaces + let mut temp_workspace = self.temporary_workspace.write(); + + for (file_id, workspace) in temp_workspace.iter_mut() { + if let Some(p) = if let Some(w) = workspace { + match w { + WorkSpaceKind::ModFile(path_buf) => Some(path_buf.clone()), + WorkSpaceKind::SettingFile(path_buf) => Some(path_buf.clone()), + _ => None, + } + } else { + None + } { + let opts = + lookup_compile_workspace(&*self.tool.read(), &p.to_str().unwrap(), true); + self.async_compile( + workspace.clone().unwrap(), + opts, + Some(file_id.clone()), + false, + ); + } + } + } + } + + fn handle_create_confg_file(&self, paths: &[PathBuf]) { + for path in paths { + // Just log, nothing to do + self.log_message(format!("Create config file: {:?}", path)); + } + } + + fn handle_remove_confg_file(&self, paths: &[PathBuf]) { + for path in paths { + self.log_message(format!("Remove config file: {:?}", path)); + // todo: clear cache + } + } +} + +pub(crate) fn log_message(message: String, sender: &Sender) -> anyhow::Result<()> { + let typ = lsp_types::MessageType::INFO; + sender.send(Task::Notify(lsp_server::Notification::new( + lsp_types::notification::LogMessage::METHOD.to_string(), + lsp_types::LogMessageParams { typ, message }, + )))?; + Ok(()) +} diff --git a/kclvm/tools/src/LSP/src/test_data/code_action/quick_fix/load_pkg_test.k b/kclvm/tools/src/LSP/src/test_data/code_action/quick_fix/load_pkg_test.k new file mode 100644 index 000000000..52fa61550 --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/code_action/quick_fix/load_pkg_test.k @@ -0,0 +1,2 @@ +schema Person: + age: int \ No newline at end of file diff --git a/kclvm/tools/src/LSP/src/test_data/code_action/quick_fix/quick_fix.k b/kclvm/tools/src/LSP/src/test_data/code_action/quick_fix/quick_fix.k new file mode 100644 index 000000000..3f5bd5a63 --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/code_action/quick_fix/quick_fix.k @@ -0,0 +1,2 @@ +import load_pkg_test +import load_pkg_test diff --git a/kclvm/tools/src/LSP/src/test_data/completion_test/assign/completion.k b/kclvm/tools/src/LSP/src/test_data/completion_test/assign/completion.k new file mode 100644 index 000000000..dbf87d567 --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/completion_test/assign/completion.k @@ -0,0 +1,27 @@ +import .pkg +import .pkg.subpkg as sub + +schema Person2: + a: bool + b: "abc" | "def" + c: [int] + d: 1 + e: True + f: {str:str} + g: sub.Person1 + +p: Person2{ + a # complete `True` and `False` + + b # complete `"abc"` and `"def"` + + c # complete `[]` + + d # complete `1` + + e # complete `True` + + f # complete `{}` + + g # complete `subpkg.Person1{}` +} diff --git a/scripts/docker/kclvm/.keep b/kclvm/tools/src/LSP/src/test_data/completion_test/assign/pkg/file1.k similarity index 100% rename from scripts/docker/kclvm/.keep rename to kclvm/tools/src/LSP/src/test_data/completion_test/assign/pkg/file1.k diff --git a/test/test_units/test_kclvm/test_compiler/test_build/hello.k b/kclvm/tools/src/LSP/src/test_data/completion_test/assign/pkg/file2.k similarity index 100% rename from test/test_units/test_kclvm/test_compiler/test_build/hello.k rename to kclvm/tools/src/LSP/src/test_data/completion_test/assign/pkg/file2.k diff --git a/kclvm/tools/src/LSP/src/test_data/completion_test/assign/pkg/subpkg/file1.k b/kclvm/tools/src/LSP/src/test_data/completion_test/assign/pkg/subpkg/file1.k new file mode 100644 index 000000000..3ab0802b2 --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/completion_test/assign/pkg/subpkg/file1.k @@ -0,0 +1,3 @@ +schema Person1: + name: str + age: int \ No newline at end of file diff --git a/kclvm/tools/src/LSP/src/test_data/completion_test/check/check.k b/kclvm/tools/src/LSP/src/test_data/completion_test/check/check.k new file mode 100644 index 000000000..1cdaab92d --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/completion_test/check/check.k @@ -0,0 +1,5 @@ +schema Person: + name: str + + check: + \ No newline at end of file diff --git a/kclvm/tools/src/LSP/src/test_data/completion_test/dot/compare/compare.k b/kclvm/tools/src/LSP/src/test_data/completion_test/dot/compare/compare.k new file mode 100644 index 000000000..326459b62 --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/completion_test/dot/compare/compare.k @@ -0,0 +1,3 @@ +v = "" +if v == "" and "" == v : + a = 1 diff --git a/kclvm/tools/src/LSP/src/test_data/completion_test/dot/completion/completion.k b/kclvm/tools/src/LSP/src/test_data/completion_test/dot/completion/completion.k new file mode 100644 index 000000000..07d6f91f5 --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/completion_test/dot/completion/completion.k @@ -0,0 +1,37 @@ +import .pkg. # complete import path +import .pkg.subpkg +schema Person: + name: str + age: int + +p = Person { + name: "alice" + age: 1 +} + +p1 = p. # complete schema attr + +p2 = p.name. # complete builtin (str) function + +p3 = subpkg. # complete user module definition + +import math +math. # complete system module definition + +"a". + +p4 = Person{ + +} + +schema P: + a: int = 1 + +aaaa = P{}. + +schema Config: + containerRuntime?: "runc" | "rund" + +n = Config { + containerRuntime = "runc". +} \ No newline at end of file diff --git a/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/empty.k b/kclvm/tools/src/LSP/src/test_data/completion_test/dot/completion/pkg/file1.k similarity index 100% rename from test/test_units/test_kclvm/test_compiler/test_eval/eval_data/empty.k rename to kclvm/tools/src/LSP/src/test_data/completion_test/dot/completion/pkg/file1.k diff --git a/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/empty.yaml b/kclvm/tools/src/LSP/src/test_data/completion_test/dot/completion/pkg/file2.k similarity index 100% rename from test/test_units/test_kclvm/test_compiler/test_eval/eval_data/empty.yaml rename to kclvm/tools/src/LSP/src/test_data/completion_test/dot/completion/pkg/file2.k diff --git a/kclvm/tools/src/LSP/src/test_data/completion_test/dot/completion/pkg/subpkg/file1.k b/kclvm/tools/src/LSP/src/test_data/completion_test/dot/completion/pkg/subpkg/file1.k new file mode 100644 index 000000000..3ab0802b2 --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/completion_test/dot/completion/pkg/subpkg/file1.k @@ -0,0 +1,3 @@ +schema Person1: + name: str + age: int \ No newline at end of file diff --git a/kclvm/tools/src/LSP/src/test_data/completion_test/dot/func_return/func_return_1/func_return_1.k b/kclvm/tools/src/LSP/src/test_data/completion_test/dot/func_return/func_return_1/func_return_1.k new file mode 100644 index 000000000..84932f666 --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/completion_test/dot/func_return/func_return_1/func_return_1.k @@ -0,0 +1,4 @@ +f: () -> str = lambda { + "" +} +a = f() diff --git a/kclvm/tools/src/LSP/src/test_data/completion_test/dot/func_return/func_return_2/func_return_2.k b/kclvm/tools/src/LSP/src/test_data/completion_test/dot/func_return/func_return_2/func_return_2.k new file mode 100644 index 000000000..bad592256 --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/completion_test/dot/func_return/func_return_2/func_return_2.k @@ -0,0 +1,8 @@ +schema Name: + name: str + +f1: (str) -> Name = lambda s: str -> Name { + Name {name: s} +} + +b = f1("a") diff --git a/kclvm/tools/src/LSP/src/test_data/completion_test/dot/func_return/func_return_3/func_return_3.k b/kclvm/tools/src/LSP/src/test_data/completion_test/dot/func_return/func_return_3/func_return_3.k new file mode 100644 index 000000000..2159d44b7 --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/completion_test/dot/func_return/func_return_3/func_return_3.k @@ -0,0 +1,3 @@ +f: () -> str = lambda { + "" +} \ No newline at end of file diff --git a/kclvm/tools/src/LSP/src/test_data/completion_test/dot/lit_str/lit_str.k b/kclvm/tools/src/LSP/src/test_data/completion_test/dot/lit_str/lit_str.k new file mode 100644 index 000000000..9b694fdf4 --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/completion_test/dot/lit_str/lit_str.k @@ -0,0 +1,7 @@ +a = "aaa" +"aaa" +a +# a + +join_str = "hello world ${}" +join_recover_str = "hello world ${" \ No newline at end of file diff --git a/kclvm/tools/src/LSP/src/test_data/completion_test/dot/missing_expr/missing_expr.k b/kclvm/tools/src/LSP/src/test_data/completion_test/dot/missing_expr/missing_expr.k new file mode 100644 index 000000000..baebba0f5 --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/completion_test/dot/missing_expr/missing_expr.k @@ -0,0 +1,10 @@ +schema ResourceRequirement: + cpu?: str + memory?: str + +schema ResourceRequirements: + limits?: ResourceRequirement + requests?: ResourceRequirement + + check: + limits? diff --git a/kclvm/tools/src/LSP/src/test_data/completion_test/dot/nested/nested_1/nested_1.k b/kclvm/tools/src/LSP/src/test_data/completion_test/dot/nested/nested_1/nested_1.k new file mode 100644 index 000000000..c2406b87e --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/completion_test/dot/nested/nested_1/nested_1.k @@ -0,0 +1,11 @@ +schema N: + ab: int + +schema ListN: + a: [N] + +list_N: ListN = { + a: [{ + + }] +} diff --git a/kclvm/tools/src/LSP/src/test_data/completion_test/dot/nested/nested_2/nested_2.k b/kclvm/tools/src/LSP/src/test_data/completion_test/dot/nested/nested_2/nested_2.k new file mode 100644 index 000000000..aee84c4b1 --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/completion_test/dot/nested/nested_2/nested_2.k @@ -0,0 +1,11 @@ +schema N: + ab: int + +schema DictN: + a: {str:N} + +dictN: DictN = { + a.c = { + + } +} \ No newline at end of file diff --git a/kclvm/tools/src/LSP/src/test_data/completion_test/dot/nested/nested_3/nested_3.k b/kclvm/tools/src/LSP/src/test_data/completion_test/dot/nested/nested_3/nested_3.k new file mode 100644 index 000000000..3743bc87f --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/completion_test/dot/nested/nested_3/nested_3.k @@ -0,0 +1,13 @@ +schema N: + ab: int + +schema DictN: + a: {str:N} + +dictN1: DictN = { + a : { + c: { + + } + } +} \ No newline at end of file diff --git a/kclvm/tools/src/LSP/src/test_data/completion_test/dot/nested/nested_4/nested_4.k b/kclvm/tools/src/LSP/src/test_data/completion_test/dot/nested/nested_4/nested_4.k new file mode 100644 index 000000000..47c0cdd2b --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/completion_test/dot/nested/nested_4/nested_4.k @@ -0,0 +1,11 @@ +schema N: + ab: int + +schema ListListN: + a: [[N]] + +listlistN: ListListN = { + a: [[{ + + }]] +} diff --git a/kclvm/tools/src/LSP/src/test_data/completion_test/dot/schema_attr_ty/schema_attr_ty.k b/kclvm/tools/src/LSP/src/test_data/completion_test/dot/schema_attr_ty/schema_attr_ty.k new file mode 100644 index 000000000..29e590cb0 --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/completion_test/dot/schema_attr_ty/schema_attr_ty.k @@ -0,0 +1,10 @@ +schema A: + n: str + +schema B: + named: A + list: [A] + dict: {str:A} + union: str|A + +a: A \ No newline at end of file diff --git a/kclvm/tools/src/LSP/src/test_data/completion_test/dot/schema_ty_attr/schema_ty_attr.k b/kclvm/tools/src/LSP/src/test_data/completion_test/dot/schema_ty_attr/schema_ty_attr.k new file mode 100644 index 000000000..696ab652f --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/completion_test/dot/schema_ty_attr/schema_ty_attr.k @@ -0,0 +1,13 @@ +schema Name: + name: str + +schema Person: + name: Name + +p = Person{ + name: Name{ + name: "a" + } +} + +p. \ No newline at end of file diff --git a/kclvm/tools/src/LSP/src/test_data/completion_test/dot/special_expr/compare.k b/kclvm/tools/src/LSP/src/test_data/completion_test/dot/special_expr/compare.k new file mode 100644 index 000000000..326459b62 --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/completion_test/dot/special_expr/compare.k @@ -0,0 +1,3 @@ +v = "" +if v == "" and "" == v : + a = 1 diff --git a/kclvm/tools/src/LSP/src/test_data/completion_test/import/builtin/builtin_pkg.k b/kclvm/tools/src/LSP/src/test_data/completion_test/import/builtin/builtin_pkg.k new file mode 100644 index 000000000..e49b15106 --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/completion_test/import/builtin/builtin_pkg.k @@ -0,0 +1 @@ +import \ No newline at end of file diff --git a/kclvm/tools/src/LSP/src/test_data/completion_test/import/external/external_0/kcl.mod b/kclvm/tools/src/LSP/src/test_data/completion_test/import/external/external_0/kcl.mod new file mode 100644 index 000000000..8ea06569b --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/completion_test/import/external/external_0/kcl.mod @@ -0,0 +1,5 @@ +[package] + +[dependencies] +k8s = { oci = "oci://ghcr.io/kcl-lang/k8s", tag = "1.28" } + diff --git a/kclvm/tools/src/LSP/src/test_data/completion_test/import/external/external_0/main.k b/kclvm/tools/src/LSP/src/test_data/completion_test/import/external/external_0/main.k new file mode 100644 index 000000000..8becefd02 --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/completion_test/import/external/external_0/main.k @@ -0,0 +1 @@ +import k8s \ No newline at end of file diff --git a/kclvm/tools/src/LSP/src/test_data/completion_test/import/external/external_1/kcl.mod b/kclvm/tools/src/LSP/src/test_data/completion_test/import/external/external_1/kcl.mod new file mode 100644 index 000000000..4ae72f07f --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/completion_test/import/external/external_1/kcl.mod @@ -0,0 +1,4 @@ +[package] + +[dependencies] +k8s = { oci = "oci://ghcr.io/kcl-lang/k8s", tag = "1.28" } diff --git a/kclvm/tools/src/LSP/src/test_data/completion_test/import/external/external_1/main.k b/kclvm/tools/src/LSP/src/test_data/completion_test/import/external/external_1/main.k new file mode 100644 index 000000000..e49b15106 --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/completion_test/import/external/external_1/main.k @@ -0,0 +1 @@ +import \ No newline at end of file diff --git a/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/line_continue.yaml b/kclvm/tools/src/LSP/src/test_data/completion_test/import/internal/foo.k similarity index 100% rename from test/test_units/test_kclvm/test_compiler/test_eval/eval_data/line_continue.yaml rename to kclvm/tools/src/LSP/src/test_data/completion_test/import/internal/foo.k diff --git a/test/test_units/test_kclvm/test_tools/test_lint/test_lint_integration/test_data/kcl.mod b/kclvm/tools/src/LSP/src/test_data/completion_test/import/internal/kcl.mod similarity index 100% rename from test/test_units/test_kclvm/test_tools/test_lint/test_lint_integration/test_data/kcl.mod rename to kclvm/tools/src/LSP/src/test_data/completion_test/import/internal/kcl.mod diff --git a/kclvm/tools/src/LSP/src/test_data/completion_test/import/internal/main.k b/kclvm/tools/src/LSP/src/test_data/completion_test/import/internal/main.k new file mode 100644 index 000000000..e49b15106 --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/completion_test/import/internal/main.k @@ -0,0 +1 @@ +import \ No newline at end of file diff --git a/test/test_units/test_kclvm/test_compiler/test_vfs/pkg/pkg.k b/kclvm/tools/src/LSP/src/test_data/completion_test/import/internal/tt/tt.k similarity index 100% rename from test/test_units/test_kclvm/test_compiler/test_vfs/pkg/pkg.k rename to kclvm/tools/src/LSP/src/test_data/completion_test/import/internal/tt/tt.k diff --git a/test/test_units/test_kclvm/test_config/test_data/base.k b/kclvm/tools/src/LSP/src/test_data/completion_test/import/internal/without_k_file/.gitkeep similarity index 100% rename from test/test_units/test_kclvm/test_config/test_data/base.k rename to kclvm/tools/src/LSP/src/test_data/completion_test/import/internal/without_k_file/.gitkeep diff --git a/kclvm/tools/src/LSP/src/test_data/completion_test/lambda/lambda_1/lambda_1.k b/kclvm/tools/src/LSP/src/test_data/completion_test/lambda/lambda_1/lambda_1.k new file mode 100644 index 000000000..5874be935 --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/completion_test/lambda/lambda_1/lambda_1.k @@ -0,0 +1,9 @@ +cases: [str] = ["a"] + +func1 = lambda elems: [any], func: (any) -> (any) { + +} + +func1(cases, lambda case: str { + +}) diff --git a/kclvm/tools/src/LSP/src/test_data/completion_test/newline/docstring_newline.k b/kclvm/tools/src/LSP/src/test_data/completion_test/newline/docstring_newline.k new file mode 100644 index 000000000..d4bbd0ba2 --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/completion_test/newline/docstring_newline.k @@ -0,0 +1,6 @@ +schema Server: + """ + """ + name: str + workloadType: "Deployment" | "StatefulSet" + replica: int = 1 diff --git a/kclvm/tools/src/LSP/src/test_data/completion_test/newline/newline_with_version/newline_with_version.k b/kclvm/tools/src/LSP/src/test_data/completion_test/newline/newline_with_version/newline_with_version.k new file mode 100644 index 000000000..cd37b7c40 --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/completion_test/newline/newline_with_version/newline_with_version.k @@ -0,0 +1,6 @@ +schema Name: + name: str + +name1 = "" + +name: Name{} \ No newline at end of file diff --git a/kclvm/tools/src/LSP/src/test_data/completion_test/newline/schema/schema_0/schema_0.k b/kclvm/tools/src/LSP/src/test_data/completion_test/newline/schema/schema_0/schema_0.k new file mode 100644 index 000000000..0abb2a503 --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/completion_test/newline/schema/schema_0/schema_0.k @@ -0,0 +1,9 @@ +schema Base: + a: int + +schema Person[b: int](Base): + c: int + +p1= Person(b){ + +} diff --git a/kclvm/tools/src/LSP/src/test_data/completion_test/newline/schema/schema_1/schema_1.k b/kclvm/tools/src/LSP/src/test_data/completion_test/newline/schema/schema_1/schema_1.k new file mode 100644 index 000000000..e91d1c571 --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/completion_test/newline/schema/schema_1/schema_1.k @@ -0,0 +1,13 @@ +schema Name: + name: str + +schema Person: + name: Name + age: int + +p = Person{ + name: Name{ + + } +} + \ No newline at end of file diff --git a/kclvm/tools/src/LSP/src/test_data/completion_test/schema/schema/schema.k b/kclvm/tools/src/LSP/src/test_data/completion_test/schema/schema/schema.k new file mode 100644 index 000000000..3d3af8123 --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/completion_test/schema/schema/schema.k @@ -0,0 +1,24 @@ +schema Base: + a: int + +schema Person[b: int](Base): + c: int + +p = + +schema Name: + name: str + +schema Config: + names: [Name] + names1: {str: Name} + names2: str | Name + +Config{ + names: [{ }] + names1: {"a": { }} +} + +n = Name{ + name: +} \ No newline at end of file diff --git a/kclvm/tools/src/LSP/src/test_data/completion_test/schema/schema_pos/schema_pos.k b/kclvm/tools/src/LSP/src/test_data/completion_test/schema/schema_pos/schema_pos.k new file mode 100644 index 000000000..170ab9cae --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/completion_test/schema/schema_pos/schema_pos.k @@ -0,0 +1,6 @@ +schema Params: + min: int + max: int + + check: + min <= diff --git a/kclvm/tools/src/LSP/src/test_data/completion_test/schema_def/schema_def.k b/kclvm/tools/src/LSP/src/test_data/completion_test/schema_def/schema_def.k new file mode 100644 index 000000000..fa268bf58 --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/completion_test/schema_def/schema_def.k @@ -0,0 +1,13 @@ +schema Container: + name: str + name1: + +schema Config: + mainContainer: Container + image: str + +schema Server[inputConfig: Config]: + config: Config = + mainContainer: {str:} + + if diff --git a/kclvm/tools/src/LSP/src/test_data/completion_test/schema_doc/schema_doc.k b/kclvm/tools/src/LSP/src/test_data/completion_test/schema_doc/schema_doc.k new file mode 100644 index 000000000..810a02ec6 --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/completion_test/schema_doc/schema_doc.k @@ -0,0 +1,14 @@ +schema Name: + """ + + + Attributes + ---------- + name: str + + Examples + -------- + """ + name: str + +# aaax \ No newline at end of file diff --git a/kclvm/tools/src/LSP/src/test_data/completion_test/unimport/pkg/kcl.mod b/kclvm/tools/src/LSP/src/test_data/completion_test/unimport/pkg/kcl.mod new file mode 100644 index 000000000..950182eb1 --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/completion_test/unimport/pkg/kcl.mod @@ -0,0 +1,6 @@ +[package] +name = "pkg" +edition = "v0.9.0" +version = "0.0.1" + + diff --git a/kclvm/tools/src/LSP/src/test_data/completion_test/unimport/pkg/main.k b/kclvm/tools/src/LSP/src/test_data/completion_test/unimport/pkg/main.k new file mode 100644 index 000000000..ac99847b1 --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/completion_test/unimport/pkg/main.k @@ -0,0 +1,2 @@ +schema Name: + name: str \ No newline at end of file diff --git a/kclvm/tools/src/LSP/src/test_data/completion_test/unimport/unimport/kcl.mod b/kclvm/tools/src/LSP/src/test_data/completion_test/unimport/unimport/kcl.mod new file mode 100644 index 000000000..d4dd9b6a8 --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/completion_test/unimport/unimport/kcl.mod @@ -0,0 +1,7 @@ +[package] +name = "unimport" +edition = "v0.9.0" +version = "0.0.1" + +[dependencies] +pkg = { path = "../pkg" } diff --git a/test/test_units/test_kclvm/test_tools/test_lint/test_exception/test_data/main.k b/kclvm/tools/src/LSP/src/test_data/completion_test/unimport/unimport/main.k similarity index 100% rename from test/test_units/test_kclvm/test_tools/test_lint/test_exception/test_data/main.k rename to kclvm/tools/src/LSP/src/test_data/completion_test/unimport/unimport/main.k diff --git a/kclvm/tools/src/LSP/src/test_data/completion_test/unimport/unimport/subpkg/subpkg.k b/kclvm/tools/src/LSP/src/test_data/completion_test/unimport/unimport/subpkg/subpkg.k new file mode 100644 index 000000000..9dfbc5485 --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/completion_test/unimport/unimport/subpkg/subpkg.k @@ -0,0 +1,2 @@ +schema SubPKg: + name: str \ No newline at end of file diff --git a/kclvm/tools/src/LSP/src/test_data/completion_test/without_dot/completion.k b/kclvm/tools/src/LSP/src/test_data/completion_test/without_dot/completion.k new file mode 100644 index 000000000..65c8639c7 --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/completion_test/without_dot/completion.k @@ -0,0 +1,37 @@ +import .pkg # complete import path +import .pkg.subpkg +schema Person: + name: str + age: int + +p = Person { + name: "alice" + age: 1 +} + +p1 = p # complete schema attr + +p2 = p.name # complete builtin (str) function + +p3 = subpkg # complete user module definition + +import math +math # complete system module definition + +"a" + +p4 = Person{ + +} + +schema P: + a: int = 1 + +aaaa = P{} + +schema Config: + containerRuntime?: "runc" | "rund" + +n = Config { + containerRuntime = "runc" +} diff --git a/test/test_units/test_kclvm/test_tools/test_format/format_data/empty.golden b/kclvm/tools/src/LSP/src/test_data/completion_test/without_dot/pkg/file1.k similarity index 100% rename from test/test_units/test_kclvm/test_tools/test_format/format_data/empty.golden rename to kclvm/tools/src/LSP/src/test_data/completion_test/without_dot/pkg/file1.k diff --git a/test/test_units/test_kclvm/test_tools/test_format/format_data/empty.input b/kclvm/tools/src/LSP/src/test_data/completion_test/without_dot/pkg/file2.k similarity index 100% rename from test/test_units/test_kclvm/test_tools/test_format/format_data/empty.input rename to kclvm/tools/src/LSP/src/test_data/completion_test/without_dot/pkg/file2.k diff --git a/kclvm/tools/src/LSP/src/test_data/completion_test/without_dot/pkg/subpkg/file1.k b/kclvm/tools/src/LSP/src/test_data/completion_test/without_dot/pkg/subpkg/file1.k new file mode 100644 index 000000000..3ab0802b2 --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/completion_test/without_dot/pkg/subpkg/file1.k @@ -0,0 +1,3 @@ +schema Person1: + name: str + age: int \ No newline at end of file diff --git a/kclvm/tools/src/LSP/src/test_data/diagnostics/diagnostics.k b/kclvm/tools/src/LSP/src/test_data/diagnostics/diagnostics.k new file mode 100644 index 000000000..f24dac378 --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/diagnostics/diagnostics.k @@ -0,0 +1,11 @@ +import abc +a = +b: str = 1 +c: Person = Person { + age: 1 +} + +d = 1 +d = 2 +number = 2 +count = nu \ No newline at end of file diff --git a/kclvm/tools/src/LSP/src/test_data/diagnostics/load_pkg_test.k b/kclvm/tools/src/LSP/src/test_data/diagnostics/load_pkg_test.k new file mode 100644 index 000000000..52fa61550 --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/diagnostics/load_pkg_test.k @@ -0,0 +1,2 @@ +schema Person: + age: int \ No newline at end of file diff --git a/kclvm/tools/src/LSP/src/test_data/document_symbol/document_symbol.k b/kclvm/tools/src/LSP/src/test_data/document_symbol/document_symbol.k new file mode 100644 index 000000000..35c1e24d6 --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/document_symbol/document_symbol.k @@ -0,0 +1,6 @@ +schema Person4: + name: str + +p: Person4 = Person4 { + name: "alice" +} \ No newline at end of file diff --git a/kclvm/tools/src/LSP/src/test_data/error_code/aug_assign/aug_assign.k b/kclvm/tools/src/LSP/src/test_data/error_code/aug_assign/aug_assign.k new file mode 100644 index 000000000..e27c7eaad --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/error_code/aug_assign/aug_assign.k @@ -0,0 +1 @@ +a += 1 \ No newline at end of file diff --git a/kclvm/tools/src/LSP/src/test_data/find_refs_test/main.k b/kclvm/tools/src/LSP/src/test_data/find_refs_test/main.k new file mode 100644 index 000000000..c879917f9 --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/find_refs_test/main.k @@ -0,0 +1,18 @@ +a = "demo" +b = a +c = a + +schema Name: + name: str + +schema Person: + n: Name + +p2 = Person { + n: Name{ + name: a + } +} + +schema Inpust[input: str]: + s: str = input diff --git a/test/test_units/test_kclvm/test_tools/test_format/format_data/blankline.input b/kclvm/tools/src/LSP/src/test_data/format/format_range.k similarity index 100% rename from test/test_units/test_kclvm/test_tools/test_format/format_data/blankline.input rename to kclvm/tools/src/LSP/src/test_data/format/format_range.k diff --git a/kclvm/tools/src/LSP/src/test_data/goto_def_test/complex_select_goto_def/complex_select_goto_def.k b/kclvm/tools/src/LSP/src/test_data/goto_def_test/complex_select_goto_def/complex_select_goto_def.k new file mode 100644 index 000000000..a1abceb60 --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/goto_def_test/complex_select_goto_def/complex_select_goto_def.k @@ -0,0 +1,13 @@ +schema Fib: + n1 = n - 1 + n2 = n1 - 1 + n: int + value: int + if n <= 1: + value = 1 + elif n == 2: + value = 1 + else: + value = Fib {n = n1}.value + Fib {n = n2}.value + +fib8 = Fib {n = 8}.value diff --git a/kclvm/tools/src/LSP/src/test_data/goto_def_test/config_desuger_def_goto_def/config_desuger_def_goto_def.k b/kclvm/tools/src/LSP/src/test_data/goto_def_test/config_desuger_def_goto_def/config_desuger_def_goto_def.k new file mode 100644 index 000000000..1c3175ad8 --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/goto_def_test/config_desuger_def_goto_def/config_desuger_def_goto_def.k @@ -0,0 +1,8 @@ +schema Person: + n: Name + +schema Name: + name: str + +p4 = Person {n.name: "a"} + diff --git a/kclvm/tools/src/LSP/src/test_data/goto_def_test/dict_to_schema/dict_to_schema.k b/kclvm/tools/src/LSP/src/test_data/goto_def_test/dict_to_schema/dict_to_schema.k new file mode 100644 index 000000000..9b29ae205 --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/goto_def_test/dict_to_schema/dict_to_schema.k @@ -0,0 +1,59 @@ +schema Name1: + name: str + +schema Name2: + name: str + age: int + +schema Name3: + [...str]: str + name: str + age: int + +a: Name1 = {name: ""} +b: Name1 | Name2 = { + name: "a" + age: 1 +} +c: Name1 | Name2 | Name3 = { + name: "a" + age: 1 + "c": "c" +} + +d: Name1 | Name2 | {str:Name1} | {str:Name2} = { + "b": { + name: "a" + age: 1 + } +} + +e: Name1 | Name2 | {str:Name1} | {str:Name2} | {str: Name3} = { + "b": { + name: "a" + age: 1 + "c": "c" + } +} + +schema Config: + name: str + age: int = 1 + +schema Name[c: Config]: + name: str = "Bob" + cc: any = c + +ff = lambda c: Config { + c +} + +n1 = Name({ + name = "Alice" +}) {} +n2 = Name({ + name = "Alice" +}) +n3 = ff({ + name = "Alice" +}) \ No newline at end of file diff --git a/kclvm/tools/src/LSP/src/test_data/goto_def_test/duplicate_var_name_test/duplicate_var_name.k b/kclvm/tools/src/LSP/src/test_data/goto_def_test/duplicate_var_name_test/duplicate_var_name.k new file mode 100644 index 000000000..24d53d40b --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/goto_def_test/duplicate_var_name_test/duplicate_var_name.k @@ -0,0 +1,9 @@ +schema Config: + env: str + name: str + +env = "prod" + +c = Config{ + env: env +} \ No newline at end of file diff --git a/kclvm/tools/src/LSP/src/test_data/goto_def_test/goto_assign_type_test/goto_assign_type_test.k b/kclvm/tools/src/LSP/src/test_data/goto_def_test/goto_assign_type_test/goto_assign_type_test.k new file mode 100644 index 000000000..6b2d9f4f0 --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/goto_def_test/goto_assign_type_test/goto_assign_type_test.k @@ -0,0 +1,5 @@ +schema Reviewer: + teams?: [int] + users?: [int] + +reviewers: [Reviewer] = [Reviewer {teams: [1]}] diff --git a/kclvm/tools/src/LSP/src/test_data/goto_def_test/goto_attr_in_schema_def/goto_attr_in_schema_def.k b/kclvm/tools/src/LSP/src/test_data/goto_def_test/goto_attr_in_schema_def/goto_attr_in_schema_def.k new file mode 100644 index 000000000..7604626e6 --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/goto_def_test/goto_attr_in_schema_def/goto_attr_in_schema_def.k @@ -0,0 +1,34 @@ +schema Name: + name1: str + name2: str + name3: str + +name1 = "1" + +name = Name{ + name1 = name1 # (5,0) (5,5) + name2 = name1 # (8,4) (8,9) + name3 = name2 # (9,4) (9,9) +} + +schema Nested: + a: bool + b: {:} = { + if a: + aa: "aa" + } + +schema Baz: + foo: [str] + bar: Name + +schema RoleBinding: + + foo?: [str] + + bar: Name + + baz: Baz = Baz { + foo: foo + bar: bar + } diff --git a/kclvm/tools/src/LSP/src/test_data/goto_def_test/goto_base_schema_attr_1_test/goto_base_schema_attr_1_test.k b/kclvm/tools/src/LSP/src/test_data/goto_def_test/goto_base_schema_attr_1_test/goto_base_schema_attr_1_test.k new file mode 100644 index 000000000..71e535e6f --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/goto_def_test/goto_base_schema_attr_1_test/goto_base_schema_attr_1_test.k @@ -0,0 +1,6 @@ +import types + +hosts: {str: types.HostPort} = { + foo: { host: "foo.example.net", port: 80} +} + diff --git a/test/test_units/test_kclvm/test_tools/test_lint/test_reporter/test_data/kcl.mod b/kclvm/tools/src/LSP/src/test_data/goto_def_test/goto_base_schema_attr_1_test/kcl.mod similarity index 100% rename from test/test_units/test_kclvm/test_tools/test_lint/test_reporter/test_data/kcl.mod rename to kclvm/tools/src/LSP/src/test_data/goto_def_test/goto_base_schema_attr_1_test/kcl.mod diff --git a/kclvm/tools/src/LSP/src/test_data/goto_def_test/goto_base_schema_attr_1_test/types/host.k b/kclvm/tools/src/LSP/src/test_data/goto_def_test/goto_base_schema_attr_1_test/types/host.k new file mode 100644 index 000000000..92357410f --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/goto_def_test/goto_base_schema_attr_1_test/types/host.k @@ -0,0 +1,5 @@ +schema Host: + host: str + +schema HostPort(Host): + port: int \ No newline at end of file diff --git a/kclvm/tools/src/LSP/src/test_data/goto_def_test/goto_base_schema_attr_test/goto_base_schema_attr_test.k b/kclvm/tools/src/LSP/src/test_data/goto_def_test/goto_base_schema_attr_test/goto_base_schema_attr_test.k new file mode 100644 index 000000000..f540bce9a --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/goto_def_test/goto_base_schema_attr_test/goto_base_schema_attr_test.k @@ -0,0 +1,9 @@ +schema Host: + host: str + +schema HostPort(Host): + port: int + +hosts: {str:HostPort} = { + foo: {host: "foo.example.net", port: 80} +} \ No newline at end of file diff --git a/kclvm/tools/src/LSP/src/test_data/goto_def_test/goto_def.k b/kclvm/tools/src/LSP/src/test_data/goto_def_test/goto_def.k new file mode 100644 index 000000000..aaa5ba56a --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/goto_def_test/goto_def.k @@ -0,0 +1,97 @@ +import .pkg +import .pkg.schema_def + +p = pkg.Person { + name: "alice" + age: 1 +} + +p1 = p + +schema Person3: + p1: pkg.Person + p2: [pkg.Person] + p3: {str: pkg.Person} + p4: pkg.Person | pkg.Person1 + + +schema Name: + name: str + +schema Person: + n: Name + +p2 = Person { + n: Name{ + name: pkg.m.name + } +} + +s = p2.n.name + +a: int = 1 + +schema Reviewer: + teams?: [int] + users?: [int] + +reviewers: [Reviewer] = [Reviewer {teams: [1]}] + +schema Fib: + n1 = n - 1 + n2 = n1 - 1 + n: int + value: int + + if n <= 1: + value = 1 + elif n == 2: + value = 1 + else: + value = Fib {n = n1}.value + Fib {n = n2}.value +fib8 = Fib {n = 8}.value + +schema_map: {str: Person} = { + person: p2 + person1: p2 +} + +p3 = schema_map.person.n.name + +params = option("params") +toMatch = params.toMatch +toAdd = params.toAdd +items = [item | { + # If all annotations are matched, patch more annotations + if all key, value in toMatch { + item.metadata.annotations[key] == value + }: + metadata.annotations: toAdd +} for item in option("items")] + + +capabilities = option("params").capabilities or ["SETUID", "SETFCAP"] +items1 = [item | { + if item.kind == "Pod": + spec.containers: [{ + "securityContext": {"capabilities": {"add" += [cc] if cc not in (container?.securityContext?.capabilities?.drop or []) else [] for cc in capabilities}} + } for container in item.spec.containers] +} for item in option("items")] + +p4 = Person { + n.name: "a" +} + +func = lambda x: int, y: int -> int { + x + y +} + +b = True +command: [str] = [ + if b: + "a" +] + +f = lambda a: [str], b: [str], c: [str] -> [str] { + c + a + b +} diff --git a/kclvm/tools/src/LSP/src/test_data/goto_def_test/goto_identifier_def_test/goto_identifier_def_test.k b/kclvm/tools/src/LSP/src/test_data/goto_def_test/goto_identifier_def_test/goto_identifier_def_test.k new file mode 100644 index 000000000..195f64d20 --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/goto_def_test/goto_identifier_def_test/goto_identifier_def_test.k @@ -0,0 +1,8 @@ +import ..pkg + +p = pkg.Person { + name: "alice" + age: 1 +} + +p1 = p diff --git a/kclvm/tools/src/LSP/src/test_data/goto_def_test/goto_import_file_test/goto_import_file_test.k b/kclvm/tools/src/LSP/src/test_data/goto_def_test/goto_import_file_test/goto_import_file_test.k new file mode 100644 index 000000000..e63f728c7 --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/goto_def_test/goto_import_file_test/goto_import_file_test.k @@ -0,0 +1 @@ +import ..pkg.schema_def diff --git a/kclvm/tools/src/LSP/src/test_data/goto_def_test/goto_import_pkg_test/goto_import_pkg_test.k b/kclvm/tools/src/LSP/src/test_data/goto_def_test/goto_import_pkg_test/goto_import_pkg_test.k new file mode 100644 index 000000000..f175c17db --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/goto_def_test/goto_import_pkg_test/goto_import_pkg_test.k @@ -0,0 +1 @@ +import ..pkg diff --git a/kclvm/tools/src/LSP/src/test_data/goto_def_test/goto_lambda_param_goto_def/goto_lambda_param_goto_def.k b/kclvm/tools/src/LSP/src/test_data/goto_def_test/goto_lambda_param_goto_def/goto_lambda_param_goto_def.k new file mode 100644 index 000000000..466e58a33 --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/goto_def_test/goto_lambda_param_goto_def/goto_lambda_param_goto_def.k @@ -0,0 +1,4 @@ +x = 1 +func = lambda x: int, y: int -> int { + x + y +} diff --git a/kclvm/tools/src/LSP/src/test_data/goto_def_test/goto_lambda_param_schema_test/goto_lambda_param_schema_test.k b/kclvm/tools/src/LSP/src/test_data/goto_def_test/goto_lambda_param_schema_test/goto_lambda_param_schema_test.k new file mode 100644 index 000000000..017f6ad14 --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/goto_def_test/goto_lambda_param_schema_test/goto_lambda_param_schema_test.k @@ -0,0 +1,8 @@ +schema Person: + name: str + +f = lambda p: Person { + p +} + +p = f({name = ""}) \ No newline at end of file diff --git a/kclvm/tools/src/LSP/src/test_data/goto_def_test/goto_lambda_return_schema_test/goto_lambda_return_schema_test.k b/kclvm/tools/src/LSP/src/test_data/goto_def_test/goto_lambda_return_schema_test/goto_lambda_return_schema_test.k new file mode 100644 index 000000000..36e5f2d53 --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/goto_def_test/goto_lambda_return_schema_test/goto_lambda_return_schema_test.k @@ -0,0 +1,8 @@ +schema Person: + name: str + +f = lambda -> Person { + { + name: "" + } +} \ No newline at end of file diff --git a/kclvm/tools/src/LSP/src/test_data/goto_def_test/goto_local_var_def_test/goto_local_var_def_test.k b/kclvm/tools/src/LSP/src/test_data/goto_def_test/goto_local_var_def_test/goto_local_var_def_test.k new file mode 100644 index 000000000..8dd5c96e0 --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/goto_def_test/goto_local_var_def_test/goto_local_var_def_test.k @@ -0,0 +1,12 @@ +schema Fib: + n1 = n - 1 + n2 = n1 - 1 + n: int + value: int + if n <= 1: + value = 1 + elif n == 2: + value = 1 + else: + value = Fib {n = n1}.value + Fib {n = n2}.value + diff --git a/kclvm/tools/src/LSP/src/test_data/goto_def_test/goto_nested_schema_attr_test/goto_nested_schema_attr_test.k b/kclvm/tools/src/LSP/src/test_data/goto_def_test/goto_nested_schema_attr_test/goto_nested_schema_attr_test.k new file mode 100644 index 000000000..fda1258a7 --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/goto_def_test/goto_nested_schema_attr_test/goto_nested_schema_attr_test.k @@ -0,0 +1,27 @@ +schema Foo: + data: Data + + +schema Data: + spec: Spec + +schema Spec: + config: Config + +schema Config: + template: Template + +schema Template: + name: str + +foo = Foo { + data: { + spec: { + config: { + template: { + name: "template" + } + } + } + } +} \ No newline at end of file diff --git a/kclvm/tools/src/LSP/src/test_data/goto_def_test/goto_pkg_prefix_def_test/goto_pkg_prefix_def_test.k b/kclvm/tools/src/LSP/src/test_data/goto_def_test/goto_pkg_prefix_def_test/goto_pkg_prefix_def_test.k new file mode 100644 index 000000000..7ca8eae50 --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/goto_def_test/goto_pkg_prefix_def_test/goto_pkg_prefix_def_test.k @@ -0,0 +1,7 @@ +import ..pkg + +p = pkg.Person { + name: "alice" + age: 1 +} + diff --git a/kclvm/tools/src/LSP/src/test_data/goto_def_test/goto_protocol/goto_protocol.k b/kclvm/tools/src/LSP/src/test_data/goto_def_test/goto_protocol/goto_protocol.k new file mode 100644 index 000000000..2788435cc --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/goto_def_test/goto_protocol/goto_protocol.k @@ -0,0 +1,8 @@ +protocol AProtocol: + name?: str + +mixin AMixin for AProtocol: + config = { + data = name + } + data = name \ No newline at end of file diff --git a/kclvm/tools/src/LSP/src/test_data/goto_def_test/goto_schema_attr_def_test/goto_schema_attr_def_test.k b/kclvm/tools/src/LSP/src/test_data/goto_def_test/goto_schema_attr_def_test/goto_schema_attr_def_test.k new file mode 100644 index 000000000..f106cc0b8 --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/goto_def_test/goto_schema_attr_def_test/goto_schema_attr_def_test.k @@ -0,0 +1,18 @@ +import ..pkg + +p = pkg.Person { + name: "alice" + age: 1 +} + +schema Name: + name: str + +schema Person: + n: Name + +p2 = Person { + n: Name {name: pkg.m.name} +} + +s = p2.n.name diff --git a/kclvm/tools/src/LSP/src/test_data/goto_def_test/goto_schema_attr_ty_def_test/goto_schema_attr_ty_def_test.k b/kclvm/tools/src/LSP/src/test_data/goto_def_test/goto_schema_attr_ty_def_test/goto_schema_attr_ty_def_test.k new file mode 100644 index 000000000..ed3910720 --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/goto_def_test/goto_schema_attr_ty_def_test/goto_schema_attr_ty_def_test.k @@ -0,0 +1,8 @@ +import ..pkg + +schema Person3: + p1: pkg.Person + p2: [pkg.Person] + p3: {str:pkg.Person} + p4: pkg.Person | pkg.Person1 + diff --git a/kclvm/tools/src/LSP/src/test_data/goto_def_test/goto_schema_def_test/goto_schema_def_test.k b/kclvm/tools/src/LSP/src/test_data/goto_def_test/goto_schema_def_test/goto_schema_def_test.k new file mode 100644 index 000000000..7ca8eae50 --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/goto_def_test/goto_schema_def_test/goto_schema_def_test.k @@ -0,0 +1,7 @@ +import ..pkg + +p = pkg.Person { + name: "alice" + age: 1 +} + diff --git a/test/test_units/test_kclvm/test_tools/test_lint/test_lint_integration/test_data/empty_file.k b/kclvm/tools/src/LSP/src/test_data/goto_def_test/goto_system_pkg_test/goto_system_pkg_test.k similarity index 100% rename from test/test_units/test_kclvm/test_tools/test_lint/test_lint_integration/test_data/empty_file.k rename to kclvm/tools/src/LSP/src/test_data/goto_def_test/goto_system_pkg_test/goto_system_pkg_test.k diff --git a/kclvm/tools/src/LSP/src/test_data/goto_def_test/goto_unification_schema_attr_test/goto_unification_schema_attr_test.k b/kclvm/tools/src/LSP/src/test_data/goto_def_test/goto_unification_schema_attr_test/goto_unification_schema_attr_test.k new file mode 100644 index 000000000..a862bb026 --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/goto_def_test/goto_unification_schema_attr_test/goto_unification_schema_attr_test.k @@ -0,0 +1,8 @@ +schema Metadata: + +schema Object: + metadata: Metadata {} + +o = Object { + metadata: {} +} diff --git a/kclvm/tools/src/LSP/src/test_data/goto_def_test/goto_var_def_in_config_and_config_if_test/goto_var_def_in_config_and_config_if_test.k b/kclvm/tools/src/LSP/src/test_data/goto_def_test/goto_var_def_in_config_and_config_if_test/goto_var_def_in_config_and_config_if_test.k new file mode 100644 index 000000000..9a0a70022 --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/goto_def_test/goto_var_def_in_config_and_config_if_test/goto_var_def_in_config_and_config_if_test.k @@ -0,0 +1,11 @@ +params = option("params") +toMatch = params.toMatch +toAdd = params.toAdd +items = [item | { + # If all annotations are matched, patch more annotations + if all key, value in toMatch { + item.metadata.annotations[key] == value + }: + metadata.annotations: toAdd + +} for item in option("items")] diff --git a/kclvm/tools/src/LSP/src/test_data/goto_def_test/goto_var_def_in_dict_comp_test/goto_var_def_in_dict_comp_test.k b/kclvm/tools/src/LSP/src/test_data/goto_def_test/goto_var_def_in_dict_comp_test/goto_var_def_in_dict_comp_test.k new file mode 100644 index 000000000..16d866cb5 --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/goto_def_test/goto_var_def_in_dict_comp_test/goto_var_def_in_dict_comp_test.k @@ -0,0 +1,8 @@ +capabilities = option("params").capabilities or ["SETUID", "SETFCAP"] +items1 = [item | { + if item.kind == "Pod": + spec.containers: [{ + "securityContext": {"capabilities": {"add" += [cc] if cc not in (container?.securityContext?.capabilities?.drop or []) else [] for cc in capabilities}} + } for container in item.spec.containers] + +} for item in option("items")] diff --git a/test/test_units/test_kclvm/test_tools/test_list_attr/test_data/kcl.mod b/kclvm/tools/src/LSP/src/test_data/goto_def_test/kcl.mod similarity index 100% rename from test/test_units/test_kclvm/test_tools/test_list_attr/test_data/kcl.mod rename to kclvm/tools/src/LSP/src/test_data/goto_def_test/kcl.mod diff --git a/test/test_units/test_kclvm/test_tools/test_list_attr/test_data/importfile/_import_file.k b/kclvm/tools/src/LSP/src/test_data/goto_def_test/kcl.yaml similarity index 100% rename from test/test_units/test_kclvm/test_tools/test_list_attr/test_data/importfile/_import_file.k rename to kclvm/tools/src/LSP/src/test_data/goto_def_test/kcl.yaml diff --git a/kclvm/tools/src/LSP/src/test_data/goto_def_test/lambda_local_var_test/lambda_local_var_test.k b/kclvm/tools/src/LSP/src/test_data/goto_def_test/lambda_local_var_test/lambda_local_var_test.k new file mode 100644 index 000000000..a2c975096 --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/goto_def_test/lambda_local_var_test/lambda_local_var_test.k @@ -0,0 +1,3 @@ +f = lambda a: [str], b: [str], c: [str] -> [str] { + c + a + b +} diff --git a/kclvm/tools/src/LSP/src/test_data/goto_def_test/list_if_expr_test/list_if_expr_test.k b/kclvm/tools/src/LSP/src/test_data/goto_def_test/list_if_expr_test/list_if_expr_test.k new file mode 100644 index 000000000..c0896bc06 --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/goto_def_test/list_if_expr_test/list_if_expr_test.k @@ -0,0 +1,6 @@ +b = True +command: [str] = [ + if b: + "a" + +] diff --git a/kclvm/tools/src/LSP/src/test_data/goto_def_test/pkg/schema_def.k b/kclvm/tools/src/LSP/src/test_data/goto_def_test/pkg/schema_def.k new file mode 100644 index 000000000..13e310f76 --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/goto_def_test/pkg/schema_def.k @@ -0,0 +1,10 @@ +schema Person: + """ + hover doc test + """ + name: str + age: int + +m : {str: str} = { + name: "a" +} diff --git a/kclvm/tools/src/LSP/src/test_data/goto_def_test/pkg/schema_def1.k b/kclvm/tools/src/LSP/src/test_data/goto_def_test/pkg/schema_def1.k new file mode 100644 index 000000000..b4ba6786a --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/goto_def_test/pkg/schema_def1.k @@ -0,0 +1,3 @@ +schema Person1: + name: str + age: int diff --git a/kclvm/tools/src/LSP/src/test_data/goto_def_test/schema_attribute_def_goto_def/schema_attribute_def_goto_def.k b/kclvm/tools/src/LSP/src/test_data/goto_def_test/schema_attribute_def_goto_def/schema_attribute_def_goto_def.k new file mode 100644 index 000000000..c0287b6c1 --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/goto_def_test/schema_attribute_def_goto_def/schema_attribute_def_goto_def.k @@ -0,0 +1,3 @@ +schema Name: + name: str + diff --git a/kclvm/tools/src/LSP/src/test_data/goto_def_test/system_pkg/goto_sys_pkg.k b/kclvm/tools/src/LSP/src/test_data/goto_def_test/system_pkg/goto_sys_pkg.k new file mode 100644 index 000000000..e0beed2c9 --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/goto_def_test/system_pkg/goto_sys_pkg.k @@ -0,0 +1,3 @@ +import yaml + +yaml.decode("") \ No newline at end of file diff --git a/kclvm/tools/src/LSP/src/test_data/goto_def_test/test_goto_identifier_names/test_goto_identifier_names.k b/kclvm/tools/src/LSP/src/test_data/goto_def_test/test_goto_identifier_names/test_goto_identifier_names.k new file mode 100644 index 000000000..a36869aea --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/goto_def_test/test_goto_identifier_names/test_goto_identifier_names.k @@ -0,0 +1,13 @@ +import ..pkg + +schema Name: + name: str + +schema Person: + n: Name + +p2 = Person { + n: Name {name: pkg.m.name} +} + +s = p2.n.name diff --git a/kclvm/tools/src/LSP/src/test_data/goto_def_with_line_test/dep-with-line/kcl.mod b/kclvm/tools/src/LSP/src/test_data/goto_def_with_line_test/dep-with-line/kcl.mod new file mode 100644 index 000000000..2f4e3935d --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/goto_def_with_line_test/dep-with-line/kcl.mod @@ -0,0 +1,5 @@ +[package] +name = "dep-with-line" +edition = "0.0.1" +version = "0.0.1" + diff --git a/test/test_units/test_kclvm/test_tools/test_list_attr/test_data/importfile/testfile_test.k b/kclvm/tools/src/LSP/src/test_data/goto_def_with_line_test/dep-with-line/kcl.mod.lock similarity index 100% rename from test/test_units/test_kclvm/test_tools/test_list_attr/test_data/importfile/testfile_test.k rename to kclvm/tools/src/LSP/src/test_data/goto_def_with_line_test/dep-with-line/kcl.mod.lock diff --git a/kclvm/tools/src/LSP/src/test_data/goto_def_with_line_test/dep-with-line/main.k b/kclvm/tools/src/LSP/src/test_data/goto_def_with_line_test/dep-with-line/main.k new file mode 100644 index 000000000..0df3165c8 --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/goto_def_with_line_test/dep-with-line/main.k @@ -0,0 +1 @@ +The_first_kcl_program = 'Hello World aa!' \ No newline at end of file diff --git a/kclvm/tools/src/LSP/src/test_data/goto_def_with_line_test/main_pkg/kcl.mod b/kclvm/tools/src/LSP/src/test_data/goto_def_with_line_test/main_pkg/kcl.mod new file mode 100644 index 000000000..076c66f4d --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/goto_def_with_line_test/main_pkg/kcl.mod @@ -0,0 +1,7 @@ +[package] +name = "b" +edition = "0.0.1" +version = "0.0.1" + +[dependencies] +dep-with-line = { path = "../dep-with-line" } diff --git a/kclvm/tools/src/LSP/src/test_data/goto_def_with_line_test/main_pkg/kcl.mod.lock b/kclvm/tools/src/LSP/src/test_data/goto_def_with_line_test/main_pkg/kcl.mod.lock new file mode 100644 index 000000000..176cb7dec --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/goto_def_with_line_test/main_pkg/kcl.mod.lock @@ -0,0 +1,6 @@ +[dependencies] + [dependencies.dep-with-line] + name = "dep-with-line" + full_name = "dep-with-line_0.0.1" + version = "0.0.1" + sum = "O2Z1djaB1lC38kNfhwUUYAlqGKE7seUqqys3DPcJfEw=" diff --git a/kclvm/tools/src/LSP/src/test_data/goto_def_with_line_test/main_pkg/main.k b/kclvm/tools/src/LSP/src/test_data/goto_def_with_line_test/main_pkg/main.k new file mode 100644 index 000000000..e78a5fba4 --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/goto_def_with_line_test/main_pkg/main.k @@ -0,0 +1,3 @@ +import dep_with_line as dwl + +The_first_kcl_program = dwl.The_first_kcl_program \ No newline at end of file diff --git a/kclvm/tools/src/LSP/src/test_data/goto_import_def_test/kcl.mod b/kclvm/tools/src/LSP/src/test_data/goto_import_def_test/kcl.mod new file mode 100644 index 000000000..05c442f22 --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/goto_import_def_test/kcl.mod @@ -0,0 +1,8 @@ +[package] +name = "kcl1" +edition = "0.0.1" +version = "0.0.4" + +[dependencies] +konfig = { git = "https://github.com/awesome-kusion/konfig.git", tag = "v0.0.1" } + diff --git a/kclvm/tools/src/LSP/src/test_data/goto_import_def_test/kcl.mod.lock b/kclvm/tools/src/LSP/src/test_data/goto_import_def_test/kcl.mod.lock new file mode 100644 index 000000000..3fc8b46f8 --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/goto_import_def_test/kcl.mod.lock @@ -0,0 +1,7 @@ +[dependencies] + [dependencies.konfig] + name = "konfig" + full_name = "_" + sum = "XFvHdBAoY/+qpJWmj8cjwOwZO8a3nX/7SE35cTxQOFU=" + url = "https://github.com/awesome-kusion/konfig.git" + git_tag = "v0.0.1" diff --git a/kclvm/tools/src/LSP/src/test_data/goto_import_def_test/main.k b/kclvm/tools/src/LSP/src/test_data/goto_import_def_test/main.k new file mode 100644 index 000000000..d886bace8 --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/goto_import_def_test/main.k @@ -0,0 +1,3 @@ +import konfig.base.examples.native.nginx_deployment as nd + +demo = nd.demo diff --git a/kclvm/tools/src/LSP/src/test_data/hover_test/assign_in_lambda.k b/kclvm/tools/src/LSP/src/test_data/hover_test/assign_in_lambda.k new file mode 100644 index 000000000..cd8ca643d --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/hover_test/assign_in_lambda.k @@ -0,0 +1,6 @@ +lambda { + containers = [] + if True: + containers = [] + images: [str] = [c.image for c in containers] +} diff --git a/kclvm/tools/src/LSP/src/test_data/hover_test/decorator.k b/kclvm/tools/src/LSP/src/test_data/hover_test/decorator.k new file mode 100644 index 000000000..90df4d87e --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/hover_test/decorator.k @@ -0,0 +1,5 @@ +@deprecated() +schema ObsoleteSchema: + @deprecated(version="1.16", reason="use firstName and lastName instead", strict=True) + attr: str + diff --git a/kclvm/tools/src/LSP/src/test_data/hover_test/dict_key_in_schema/dict_key_in_schema.k b/kclvm/tools/src/LSP/src/test_data/hover_test/dict_key_in_schema/dict_key_in_schema.k new file mode 100644 index 000000000..2abb1da0f --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/hover_test/dict_key_in_schema/dict_key_in_schema.k @@ -0,0 +1,14 @@ +schema Name: + name: int + +n1: Name = { + name = 1 +} + +n2 = Name{ + name: 1 +} + +n3: Name = Name{ + name: 1 +} \ No newline at end of file diff --git a/kclvm/tools/src/LSP/src/test_data/hover_test/fib.k b/kclvm/tools/src/LSP/src/test_data/hover_test/fib.k new file mode 100644 index 000000000..96926c055 --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/hover_test/fib.k @@ -0,0 +1,14 @@ +schema Fib: + n1 = n - 1 + n2 = n1 - 1 + n: int + value: int + + if n <= 1: + value = 1 + elif n == 2: + value = 1 + else: + value = Fib {n = n1}.value + Fib {n = n2}.value + +fib8 = Fib {n = 8}.value diff --git a/kclvm/tools/src/LSP/src/test_data/hover_test/hover.k b/kclvm/tools/src/LSP/src/test_data/hover_test/hover.k new file mode 100644 index 000000000..d4ed155e5 --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/hover_test/hover.k @@ -0,0 +1,43 @@ +schema Person: + """ + hover doc test + + Attributes + ---------- + name : str, default is False, required + name doc test + age : int, default is False, optional + age doc test + + """ + name: str + age?: int + +p = Person{ + name: "Alice" + age: 1 +} + +import base64 +abdc = base64.encode("1") +abcd = "a".count() + +print(1) + +a = "".capitalize() +b = a.capitalize() + +schema Deployment: + spec: DeploymentSpec + +schema DeploymentSpec: + stratege: str + replicas?: int + +d = Deployment{ + spec: DeploymentSpec { + if True: + replicas = 1 + stratege: "a" + } +} diff --git a/kclvm/tools/src/LSP/src/test_data/hover_test/import_pkg.k b/kclvm/tools/src/LSP/src/test_data/hover_test/import_pkg.k new file mode 100644 index 000000000..a972f027f --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/hover_test/import_pkg.k @@ -0,0 +1,3 @@ +import .fib + +fib.Fib{} \ No newline at end of file diff --git a/kclvm/tools/src/LSP/src/test_data/hover_test/inherit.k b/kclvm/tools/src/LSP/src/test_data/hover_test/inherit.k new file mode 100644 index 000000000..0e8c08f5b --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/hover_test/inherit.k @@ -0,0 +1,7 @@ +schema Data: + name: str = "1" + age: int + +schema Data1[m: {str:str}](Data): + name = m.name + \ No newline at end of file diff --git a/kclvm/tools/src/LSP/src/test_data/hover_test/lambda.k b/kclvm/tools/src/LSP/src/test_data/hover_test/lambda.k new file mode 100644 index 000000000..88c659b32 --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/hover_test/lambda.k @@ -0,0 +1,4 @@ +f = lambda x: int = 1 { + """lambda documents""" + x +} diff --git a/kclvm/tools/src/LSP/src/test_data/hover_test/ty_in_lambda.k b/kclvm/tools/src/LSP/src/test_data/hover_test/ty_in_lambda.k new file mode 100644 index 000000000..4b9a1929c --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/hover_test/ty_in_lambda.k @@ -0,0 +1,9 @@ +_b = True +a = lambda item: {str:}, c: {str:} -> {str:str} { + result = {"aaa": "bbb"} + if _b : + result = {} + result +} + +result = {"ccc": "ddd"} diff --git a/kclvm/tools/src/LSP/src/test_data/inlay_hints/assign_stmt_type_hint/assign_stmt_type_hint.k b/kclvm/tools/src/LSP/src/test_data/inlay_hints/assign_stmt_type_hint/assign_stmt_type_hint.k new file mode 100644 index 000000000..0c2cf8bf1 --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/inlay_hints/assign_stmt_type_hint/assign_stmt_type_hint.k @@ -0,0 +1,26 @@ +a = 1 +b = "" +c = "" +d = lambda x: int { + x = 1 + x +} +schema Name: + name: str + +n = Name { + +} +bb = n +aaaa = None +type name = "asdad" +f = "" +cc = [1, "", 3] +ee = { + a: "asda" +} +ccc = 1Ki + +func = lambda x, y, z{ + x * y + z +} diff --git a/kclvm/tools/src/LSP/src/test_data/inlay_hints/config_key/config_key.k b/kclvm/tools/src/LSP/src/test_data/inlay_hints/config_key/config_key.k new file mode 100644 index 000000000..019a4a90b --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/inlay_hints/config_key/config_key.k @@ -0,0 +1,12 @@ +schema App: + a: int + b: 1 | 2 + c: str + d: "A" | "B" + +app = App { + a: 1 + b: 1 + c: "1" + d: "A" +} diff --git a/kclvm/tools/src/LSP/src/test_data/inlay_hints/config_key1/config_key.k b/kclvm/tools/src/LSP/src/test_data/inlay_hints/config_key1/config_key.k new file mode 100644 index 000000000..50b3ed7b4 --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/inlay_hints/config_key1/config_key.k @@ -0,0 +1,9 @@ +schema Name: + name: str + +schema Person: + name: Name + +p = Person{ + name.name = "" +} \ No newline at end of file diff --git a/kclvm/tools/src/LSP/src/test_data/inlay_hints/function_call/function_call.k b/kclvm/tools/src/LSP/src/test_data/inlay_hints/function_call/function_call.k new file mode 100644 index 000000000..d64294ac8 --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/inlay_hints/function_call/function_call.k @@ -0,0 +1,14 @@ +a = 10 + +func = lambda x, y, z{ + x * y + z +} + +k = func(a, 1, z = 2) + +x = 1 +k1 = func(x, 1, z = 2) + +b = "".find("abc", 0, -1) +c = "".find("abc", 0, 1) +d = "".find("abc", 0, 1 + 1) \ No newline at end of file diff --git a/kclvm/tools/src/LSP/src/test_data/inlay_hints/schema_args/schema_args_hint.k b/kclvm/tools/src/LSP/src/test_data/inlay_hints/schema_args/schema_args_hint.k new file mode 100644 index 000000000..367507a2f --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/inlay_hints/schema_args/schema_args_hint.k @@ -0,0 +1,5 @@ +schema Person[age: int, name: str]: + a = age + n = name + +p = Person(1, "Alice") diff --git a/kclvm/tools/src/LSP/src/test_data/rename_test/base/person.k b/kclvm/tools/src/LSP/src/test_data/rename_test/base/person.k new file mode 100644 index 000000000..781b5249f --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/rename_test/base/person.k @@ -0,0 +1,13 @@ +schema Person: + name: Name + age: int + +schema Name: + first: str + +a = { + abc: "d" +} + +d = a.abc +e = a["abc"] \ No newline at end of file diff --git a/kclvm/tools/src/LSP/src/test_data/rename_test/config.k b/kclvm/tools/src/LSP/src/test_data/rename_test/config.k new file mode 100644 index 000000000..746f34df6 --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/rename_test/config.k @@ -0,0 +1,8 @@ +import .base + +a = base.Person { + age: 1, + name: { + first: "aa" + } +} \ No newline at end of file diff --git a/kclvm/tools/src/LSP/src/test_data/rename_test/main.k b/kclvm/tools/src/LSP/src/test_data/rename_test/main.k new file mode 100644 index 000000000..efd22bf88 --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/rename_test/main.k @@ -0,0 +1,6 @@ +import .pkg.vars + +Bob = vars.Person { + name: "Bob" + age: 30 +} \ No newline at end of file diff --git a/kclvm/tools/src/LSP/src/test_data/rename_test/pkg/vars.k b/kclvm/tools/src/LSP/src/test_data/rename_test/pkg/vars.k new file mode 100644 index 000000000..6f32c0650 --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/rename_test/pkg/vars.k @@ -0,0 +1,13 @@ +schema Person: + name: str + age: int + +John = Person { + name: "John" + age: 20 +} + +Alice = Person { + name: "Alice" + age: 30 +} \ No newline at end of file diff --git a/kclvm/tools/src/LSP/src/test_data/rename_test/rename_on_file/base/person.k b/kclvm/tools/src/LSP/src/test_data/rename_test/rename_on_file/base/person.k new file mode 100644 index 000000000..781b5249f --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/rename_test/rename_on_file/base/person.k @@ -0,0 +1,13 @@ +schema Person: + name: Name + age: int + +schema Name: + first: str + +a = { + abc: "d" +} + +d = a.abc +e = a["abc"] \ No newline at end of file diff --git a/kclvm/tools/src/LSP/src/test_data/rename_test/rename_on_file/config.k b/kclvm/tools/src/LSP/src/test_data/rename_test/rename_on_file/config.k new file mode 100644 index 000000000..746f34df6 --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/rename_test/rename_on_file/config.k @@ -0,0 +1,8 @@ +import .base + +a = base.Person { + age: 1, + name: { + first: "aa" + } +} \ No newline at end of file diff --git a/kclvm/tools/src/LSP/src/test_data/rename_test/rename_on_file/main.k b/kclvm/tools/src/LSP/src/test_data/rename_test/rename_on_file/main.k new file mode 100644 index 000000000..efd22bf88 --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/rename_test/rename_on_file/main.k @@ -0,0 +1,6 @@ +import .pkg.vars + +Bob = vars.Person { + name: "Bob" + age: 30 +} \ No newline at end of file diff --git a/kclvm/tools/src/LSP/src/test_data/rename_test/rename_on_file/pkg/vars.k b/kclvm/tools/src/LSP/src/test_data/rename_test/rename_on_file/pkg/vars.k new file mode 100644 index 000000000..6f32c0650 --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/rename_test/rename_on_file/pkg/vars.k @@ -0,0 +1,13 @@ +schema Person: + name: str + age: int + +John = Person { + name: "John" + age: 20 +} + +Alice = Person { + name: "Alice" + age: 30 +} \ No newline at end of file diff --git a/kclvm/tools/src/LSP/src/test_data/rename_test/rename_on_file/server.k b/kclvm/tools/src/LSP/src/test_data/rename_test/rename_on_file/server.k new file mode 100644 index 000000000..291e67dc6 --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/rename_test/rename_on_file/server.k @@ -0,0 +1,2 @@ +schema Server: + name: str diff --git a/kclvm/tools/src/LSP/src/test_data/rename_test/server.k b/kclvm/tools/src/LSP/src/test_data/rename_test/server.k new file mode 100644 index 000000000..291e67dc6 --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/rename_test/server.k @@ -0,0 +1,2 @@ +schema Server: + name: str diff --git a/kclvm/tools/src/LSP/src/test_data/sema_token/sema_token.k b/kclvm/tools/src/LSP/src/test_data/sema_token/sema_token.k new file mode 100644 index 000000000..481f1d39d --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/sema_token/sema_token.k @@ -0,0 +1,23 @@ +import math as m +type num = int | float +schema Persons: + name: str + +p5: Persons = Persons { + name: "alice" +} +n: num = 1 + +func = lambda x{ + x +} + +a = func("123") +b = func(x="123") + +schema Manifest: + [name: str] = "" + +aaa: any = 1 + +bbb = any item in [] { True } \ No newline at end of file diff --git a/kclvm/tools/src/LSP/src/test_data/signature_help/builtin_function_signature_help/builtin_function_signature_help.k b/kclvm/tools/src/LSP/src/test_data/signature_help/builtin_function_signature_help/builtin_function_signature_help.k new file mode 100644 index 000000000..e8c9b056c --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/signature_help/builtin_function_signature_help/builtin_function_signature_help.k @@ -0,0 +1,2 @@ +pow +pow(1) \ No newline at end of file diff --git a/kclvm/tools/src/LSP/src/test_data/signature_help/lambda_signature_help/lambda_signature_help.k b/kclvm/tools/src/LSP/src/test_data/signature_help/lambda_signature_help/lambda_signature_help.k new file mode 100644 index 000000000..384ff29cc --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/signature_help/lambda_signature_help/lambda_signature_help.k @@ -0,0 +1,9 @@ +func = lambda x, y, z{ + x * y + z +} + +a = func +b = func(a) +c = func(a, 1) +c = func(a, 1, z = 1) + diff --git a/kclvm/tools/src/LSP/src/test_data/signature_help/pkg_function_signature_help/pkg_function_signature_help.k b/kclvm/tools/src/LSP/src/test_data/signature_help/pkg_function_signature_help/pkg_function_signature_help.k new file mode 100644 index 000000000..1b7d0929d --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/signature_help/pkg_function_signature_help/pkg_function_signature_help.k @@ -0,0 +1,4 @@ +import math + +math.gcd +math.gcd(1) \ No newline at end of file diff --git a/kclvm/tools/src/LSP/src/test_data/test_vendor/kcl4_v0.0.1/k4/main.k b/kclvm/tools/src/LSP/src/test_data/test_vendor/kcl4_v0.0.1/k4/main.k new file mode 100644 index 000000000..97eac82ed --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/test_vendor/kcl4_v0.0.1/k4/main.k @@ -0,0 +1 @@ +demo = 4 \ No newline at end of file diff --git a/kclvm/tools/src/LSP/src/test_data/test_vendor/kcl4_v0.0.1/kcl.mod b/kclvm/tools/src/LSP/src/test_data/test_vendor/kcl4_v0.0.1/kcl.mod new file mode 100644 index 000000000..52280a04b --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/test_vendor/kcl4_v0.0.1/kcl.mod @@ -0,0 +1,6 @@ +[package] +name = "kcl4" +edition = "0.0.1" +version = "0.0.1" + +[dependencies] \ No newline at end of file diff --git a/kclvm/tools/src/LSP/src/test_data/watcher/modify/kcl.mod b/kclvm/tools/src/LSP/src/test_data/watcher/modify/kcl.mod new file mode 100644 index 000000000..3b4edd7c7 --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/watcher/modify/kcl.mod @@ -0,0 +1,6 @@ +[package] +name = "add" +edition = "v0.9.0" +version = "0.0.1" + +[dependencies] diff --git a/kclvm/tools/src/LSP/src/test_data/watcher/modify/main.k b/kclvm/tools/src/LSP/src/test_data/watcher/modify/main.k new file mode 100644 index 000000000..f5bde4bd0 --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/watcher/modify/main.k @@ -0,0 +1 @@ +import helloworld \ No newline at end of file diff --git a/test/test_units/test_kclvm/test_compiler/test_vfs/main.k b/kclvm/tools/src/LSP/src/test_data/workspace/init/folder/a.k similarity index 100% rename from test/test_units/test_kclvm/test_compiler/test_vfs/main.k rename to kclvm/tools/src/LSP/src/test_data/workspace/init/folder/a.k diff --git a/test/test_units/test_kclvm/test_tools/test_overrides/file_test_data/kcl.mod b/kclvm/tools/src/LSP/src/test_data/workspace/init/folder/b.k similarity index 100% rename from test/test_units/test_kclvm/test_tools/test_overrides/file_test_data/kcl.mod rename to kclvm/tools/src/LSP/src/test_data/workspace/init/folder/b.k diff --git a/kclvm/tools/src/LSP/src/test_data/workspace/init/folder/sub/c.k b/kclvm/tools/src/LSP/src/test_data/workspace/init/folder/sub/c.k new file mode 100644 index 000000000..d25d49e0f --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/workspace/init/folder/sub/c.k @@ -0,0 +1 @@ +a = 1 \ No newline at end of file diff --git a/kclvm/tools/src/LSP/src/test_data/workspace/init/mod/kcl.mod b/kclvm/tools/src/LSP/src/test_data/workspace/init/mod/kcl.mod new file mode 100644 index 000000000..7e9dad4d0 --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/workspace/init/mod/kcl.mod @@ -0,0 +1,4 @@ +[package] +name = "mod" +edition = "v0.9.0" +version = "0.0.1" diff --git a/kclvm/tools/src/LSP/src/test_data/workspace/init/mod/main.k b/kclvm/tools/src/LSP/src/test_data/workspace/init/mod/main.k new file mode 100644 index 000000000..77c8de288 --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/workspace/init/mod/main.k @@ -0,0 +1 @@ +The_first_kcl_program = 'Hello World!' diff --git a/test/test_units/test_kclvm/test_tools/test_overrides/test_data/empty.input b/kclvm/tools/src/LSP/src/test_data/workspace/init/setting/a.k similarity index 100% rename from test/test_units/test_kclvm/test_tools/test_overrides/test_data/empty.input rename to kclvm/tools/src/LSP/src/test_data/workspace/init/setting/a.k diff --git a/test/test_units/test_kclvm/test_tools/test_overrides/test_data/empty.output b/kclvm/tools/src/LSP/src/test_data/workspace/init/setting/b.k similarity index 100% rename from test/test_units/test_kclvm/test_tools/test_overrides/test_data/empty.output rename to kclvm/tools/src/LSP/src/test_data/workspace/init/setting/b.k diff --git a/kclvm/tools/src/LSP/src/test_data/workspace/init/setting/kcl.yaml b/kclvm/tools/src/LSP/src/test_data/workspace/init/setting/kcl.yaml new file mode 100644 index 000000000..fee707610 --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/workspace/init/setting/kcl.yaml @@ -0,0 +1,3 @@ +kcl_cli_configs: + file: + - a.k \ No newline at end of file diff --git a/test/test_units/test_kclvm/test_tools/test_printer/test_data/empty.output b/kclvm/tools/src/LSP/src/test_data/workspace/init/work/a/a.k similarity index 100% rename from test/test_units/test_kclvm/test_tools/test_printer/test_data/empty.output rename to kclvm/tools/src/LSP/src/test_data/workspace/init/work/a/a.k diff --git a/test/test_units/test_kclvm/test_types/err_collect_test_data/kcl.mod b/kclvm/tools/src/LSP/src/test_data/workspace/init/work/b/b.k similarity index 100% rename from test/test_units/test_kclvm/test_types/err_collect_test_data/kcl.mod rename to kclvm/tools/src/LSP/src/test_data/workspace/init/work/b/b.k diff --git a/test/test_units/test_kclvm/test_types/invalid_test_data/import/kcl.mod b/kclvm/tools/src/LSP/src/test_data/workspace/init/work/c.k similarity index 100% rename from test/test_units/test_kclvm/test_types/invalid_test_data/import/kcl.mod rename to kclvm/tools/src/LSP/src/test_data/workspace/init/work/c.k diff --git a/kclvm/tools/src/LSP/src/test_data/workspace/init/work/kcl.work b/kclvm/tools/src/LSP/src/test_data/workspace/init/work/kcl.work new file mode 100644 index 000000000..f9f9acf5f --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/workspace/init/work/kcl.work @@ -0,0 +1,3 @@ +workspace ./a +workspace ./b +workspace ./c.k diff --git a/test/test_units/test_kclvm/test_types/invalid_test_data/module/kcl.mod b/kclvm/tools/src/LSP/src/test_data/workspace/pkg_mod_test/base/base.k similarity index 100% rename from test/test_units/test_kclvm/test_types/invalid_test_data/module/kcl.mod rename to kclvm/tools/src/LSP/src/test_data/workspace/pkg_mod_test/base/base.k diff --git a/kclvm/tools/src/LSP/src/test_data/workspace/pkg_mod_test/kcl.mod b/kclvm/tools/src/LSP/src/test_data/workspace/pkg_mod_test/kcl.mod new file mode 100644 index 000000000..ef51dad31 --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/workspace/pkg_mod_test/kcl.mod @@ -0,0 +1,2 @@ +[package] +name = "pkg_mod_test" diff --git a/kclvm/tools/src/LSP/src/test_data/workspace/pkg_mod_test/pkg1/a.k b/kclvm/tools/src/LSP/src/test_data/workspace/pkg_mod_test/pkg1/a.k new file mode 100644 index 000000000..26dee57bd --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/workspace/pkg_mod_test/pkg1/a.k @@ -0,0 +1,3 @@ +import pkg2 +schema Name: + name: str \ No newline at end of file diff --git a/test/test_units/test_kclvm/test_types/invalid_test_data/protocol/kcl.mod b/kclvm/tools/src/LSP/src/test_data/workspace/pkg_mod_test/pkg2/b.k similarity index 100% rename from test/test_units/test_kclvm/test_types/invalid_test_data/protocol/kcl.mod rename to kclvm/tools/src/LSP/src/test_data/workspace/pkg_mod_test/pkg2/b.k diff --git a/kclvm/tools/src/LSP/src/test_data/workspace/pkg_mod_test/test/kcl.mod b/kclvm/tools/src/LSP/src/test_data/workspace/pkg_mod_test/test/kcl.mod new file mode 100644 index 000000000..37fddc5ec --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/workspace/pkg_mod_test/test/kcl.mod @@ -0,0 +1,8 @@ +[package] +name = "pkg_mod" + +[dependencies] +pkg_mod_test = { path = "../../pkg_mod_test" } + +[profile] +entries = ["../base/base.k", "main.k", "${pkg_mod_test:KCL_MOD}/pkg1/a.k"] \ No newline at end of file diff --git a/kclvm/tools/src/LSP/src/test_data/workspace/pkg_mod_test/test/main.k b/kclvm/tools/src/LSP/src/test_data/workspace/pkg_mod_test/test/main.k new file mode 100644 index 000000000..d8bd4746a --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/workspace/pkg_mod_test/test/main.k @@ -0,0 +1,3 @@ +import pkg_mod_test + +import pkg_mod_test.pkg2 \ No newline at end of file diff --git a/kclvm/tools/src/LSP/src/tests.rs b/kclvm/tools/src/LSP/src/tests.rs new file mode 100644 index 000000000..6143fb414 --- /dev/null +++ b/kclvm/tools/src/LSP/src/tests.rs @@ -0,0 +1,2688 @@ +use crossbeam_channel::after; +use crossbeam_channel::select; +use indexmap::IndexMap; +use indexmap::IndexSet; +use kclvm_driver::lookup_compile_workspace; +use kclvm_driver::toolchain; +use kclvm_driver::toolchain::Metadata; +use kclvm_driver::WorkSpaceKind; +use kclvm_sema::core::global_state::GlobalState; +use kclvm_sema::ty::SchemaType; +use kclvm_utils::path::PathPrefix; + +use kclvm_sema::resolver::scope::KCLScopeCache; +use lsp_server::RequestId; +use lsp_server::Response; +use lsp_types::notification::Exit; +use lsp_types::request::GotoTypeDefinitionResponse; +use lsp_types::CompletionContext; +use lsp_types::CompletionItem; +use lsp_types::CompletionItemKind; +use lsp_types::CompletionParams; +use lsp_types::CompletionResponse; +use lsp_types::CompletionTriggerKind; +use lsp_types::DocumentFormattingParams; +use lsp_types::DocumentSymbolParams; +use lsp_types::GotoDefinitionParams; +use lsp_types::GotoDefinitionResponse; +use lsp_types::Hover; +use lsp_types::HoverContents; +use lsp_types::HoverParams; +use lsp_types::InitializeParams; +use lsp_types::MarkedString; +use lsp_types::PartialResultParams; +use lsp_types::PublishDiagnosticsParams; +use lsp_types::ReferenceContext; +use lsp_types::ReferenceParams; +use lsp_types::RenameParams; +use lsp_types::SemanticTokensParams; +use lsp_types::TextDocumentIdentifier; +use lsp_types::TextDocumentItem; +use lsp_types::TextDocumentPositionParams; +use lsp_types::TextEdit; +use lsp_types::Url; +use lsp_types::WorkDoneProgressParams; +use lsp_types::WorkspaceEdit; +use lsp_types::WorkspaceFolder; + +use parking_lot::lock_api::RwLock; +use serde::Serialize; +use std::cell::Cell; +use std::cell::RefCell; +use std::collections::HashMap; +use std::collections::HashSet; +use std::env; +use std::path::Path; +use std::path::PathBuf; +use std::process::Command; + +use std::sync::Arc; +use std::thread; +use std::time::Duration; + +use kclvm_ast::ast::Program; +use kclvm_error::Diagnostic as KCLDiagnostic; +use kclvm_error::Position as KCLPos; +use kclvm_parser::KCLModuleCache; + +use lsp_types::Diagnostic; +use lsp_types::DiagnosticRelatedInformation; +use lsp_types::DiagnosticSeverity; +use lsp_types::Location; +use lsp_types::NumberOrString; +use lsp_types::{Position, Range, TextDocumentContentChangeEvent}; + +use proc_macro_crate::bench_test; + +use lsp_server::{Connection, Message, Notification, Request}; + +use crate::compile::compile_with_params; +use crate::completion::completion; +use crate::from_lsp::file_path_from_url; + +use crate::app::main_loop; +use crate::compile::Params; +use crate::goto_def::goto_def; +use crate::hover::hover; +use crate::state::KCLGlobalStateCache; +use crate::state::KCLVfs; +use crate::to_lsp::kcl_diag_to_lsp_diags_by_file; +use crate::util::apply_document_changes; +use crate::util::to_json; + +macro_rules! wait_async { + () => { + thread::sleep(Duration::from_millis(100)); + }; + ($time_ms:expr) => { + thread::sleep(Duration::from_millis($time_ms)); + }; +} + +pub(crate) fn compare_goto_res( + res: Option, + pos: (&String, u32, u32, u32, u32), +) { + match res.unwrap() { + lsp_types::GotoDefinitionResponse::Scalar(loc) => { + let got_path = file_path_from_url(&loc.uri).unwrap(); + assert_eq!( + got_path.adjust_canonicalization(), + pos.0.to_string().adjust_canonicalization() + ); + + let (got_start, got_end) = (loc.range.start, loc.range.end); + + let expected_start = Position { + line: pos.1, // zero-based + character: pos.2, + }; + + let expected_end = Position { + line: pos.3, // zero-based + character: pos.4, + }; + assert_eq!(got_start, expected_start); + assert_eq!(got_end, expected_end); + } + _ => { + unreachable!("test error") + } + } +} + +pub(crate) fn compile_test_file( + testfile: &str, +) -> ( + String, + Program, + IndexSet, + GlobalState, + IndexMap>, +) { + let path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + let file = path + .join(testfile) + .canonicalize() + .unwrap() + .display() + .to_string() + .adjust_canonicalization(); + + let (diags, compile_res) = compile_with_params(Params { + file: Some(file.clone()), + module_cache: Some(KCLModuleCache::default()), + scope_cache: Some(KCLScopeCache::default()), + vfs: Some(KCLVfs::default()), + gs_cache: Some(KCLGlobalStateCache::default()), + }); + let (program, schema_map, gs) = compile_res.unwrap(); + (file, program, diags, gs, schema_map) +} + +pub(crate) fn compile_test_file_and_metadata( + testfile: &str, +) -> ( + String, + Program, + IndexSet, + GlobalState, + Option, + IndexMap>, +) { + let path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + + let file = path + .join(testfile) + .canonicalize() + .unwrap() + .display() + .to_string() + .adjust_canonicalization(); + + let metadata = lookup_compile_workspace(&toolchain::default(), &file, true).2; + let (diags, compile_res) = compile_with_params(Params { + file: Some(file.clone()), + module_cache: Some(KCLModuleCache::default()), + scope_cache: Some(KCLScopeCache::default()), + vfs: Some(KCLVfs::default()), + gs_cache: Some(KCLGlobalStateCache::default()), + }); + let (program, schema_map, gs) = compile_res.unwrap(); + + (file, program, diags, gs, metadata, schema_map) +} + +type Info = (String, (u32, u32, u32, u32), String); + +fn build_lsp_diag( + pos: (u32, u32, u32, u32), + message: String, + severity: Option, + related_info: Vec, + code: Option, + data: Option, +) -> Diagnostic { + let related_information = if related_info.is_empty() { + None + } else { + Some( + related_info + .iter() + .map(|(file, pos, msg)| DiagnosticRelatedInformation { + location: Location { + uri: Url::from_file_path(file).unwrap(), + range: Range { + start: Position { + line: pos.0, + character: pos.1, + }, + end: Position { + line: pos.2, + character: pos.3, + }, + }, + }, + message: msg.clone(), + }) + .collect(), + ) + }; + Diagnostic { + range: lsp_types::Range { + start: Position { + line: pos.0, + character: pos.1, + }, + end: Position { + line: pos.2, + character: pos.3, + }, + }, + severity, + code, + code_description: None, + source: None, + message, + related_information, + tags: None, + data, + } +} + +fn build_expect_diags() -> Vec { + let path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + let mut test_file = path.clone(); + test_file.push("src/test_data/diagnostics/diagnostics.k"); + let file = test_file.to_str().unwrap(); + let expected_diags: Vec = vec![ + build_lsp_diag( + (1, 4, 2, 0), + "expected one of [\"identifier\", \"literal\", \"(\", \"[\", \"{\"] got newline" + .to_string(), + Some(DiagnosticSeverity::ERROR), + vec![], + Some(NumberOrString::String("InvalidSyntax".to_string())), + None, + ), + build_lsp_diag( + (0, 0, 0, 10), + "pkgpath abc not found in the program".to_string(), + Some(DiagnosticSeverity::ERROR), + vec![], + Some(NumberOrString::String("CannotFindModule".to_string())), + None, + ), + build_lsp_diag( + (0, 0, 0, 10), + format!( + "Cannot find the module abc from {}/src/test_data/diagnostics/abc", + path.to_str().unwrap() + ), + Some(DiagnosticSeverity::ERROR), + vec![], + Some(NumberOrString::String("CannotFindModule".to_string())), + None, + ), + build_lsp_diag( + (8, 0, 8, 1), + "Can not change the value of 'd', because it was declared immutable".to_string(), + Some(DiagnosticSeverity::ERROR), + vec![( + file.to_string(), + (7, 0, 7, 1), + "The variable 'd' is declared here".to_string(), + )], + Some(NumberOrString::String("ImmutableError".to_string())), + None, + ), + build_lsp_diag( + (7, 0, 7, 1), + "The variable 'd' is declared here".to_string(), + Some(DiagnosticSeverity::ERROR), + vec![( + file.to_string(), + (8, 0, 8, 1), + "Can not change the value of 'd', because it was declared immutable".to_string(), + )], + Some(NumberOrString::String("ImmutableError".to_string())), + None, + ), + build_lsp_diag( + (2, 0, 2, 1), + "expected str, got int(1)".to_string(), + Some(DiagnosticSeverity::ERROR), + vec![], + Some(NumberOrString::String("TypeError".to_string())), + None, + ), + build_lsp_diag( + (10, 8, 10, 10), + "name 'nu' is not defined, did you mean '[\"number\"]'?".to_string(), + Some(DiagnosticSeverity::ERROR), + vec![], + Some(NumberOrString::String("CompileError".to_string())), + Some(serde_json::json!({ "suggested_replacement": ["number"] })), + ), + build_lsp_diag( + (0, 0, 0, 10), + "Module 'abc' imported but unused".to_string(), + Some(DiagnosticSeverity::WARNING), + vec![], + Some(NumberOrString::String("UnusedImportWarning".to_string())), + None, + ), + ]; + expected_diags +} + +#[test] +#[bench_test] +fn diagnostics_test() { + let path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + let mut test_file = path.clone(); + test_file.push("src/test_data/diagnostics/diagnostics.k"); + let file = test_file.to_str().unwrap(); + + let diags = compile_with_params(Params { + file: Some(file.to_string()), + module_cache: None, + scope_cache: None, + vfs: Some(KCLVfs::default()), + gs_cache: Some(KCLGlobalStateCache::default()), + }) + .0; + + let diagnostics = diags + .iter() + .flat_map(|diag| kcl_diag_to_lsp_diags_by_file(diag, file)) + .collect::>(); + + let expected_diags: Vec = build_expect_diags(); + + for (get, expected) in diagnostics.iter().zip(expected_diags.iter()) { + assert_eq!(get, expected) + } +} + +#[test] +#[bench_test] +fn test_apply_document_changes() { + macro_rules! change { + [$($sl:expr, $sc:expr; $el:expr, $ec:expr => $text:expr),+] => { + vec![$(TextDocumentContentChangeEvent { + range: Some(Range { + start: Position { line: $sl, character: $sc }, + end: Position { line: $el, character: $ec }, + }), + range_length: None, + text: String::from($text), + }),+] + }; + } + + let mut text = String::new(); + apply_document_changes(&mut text, vec![]); + assert_eq!(text, ""); + + // Test if full updates work (without a range) + apply_document_changes( + &mut text, + vec![TextDocumentContentChangeEvent { + range: None, + range_length: None, + text: String::from("the"), + }], + ); + + assert_eq!(text, "the"); + apply_document_changes(&mut text, change![0, 3; 0, 3 => " quick"]); + assert_eq!(text, "the quick"); + + apply_document_changes(&mut text, change![0, 0; 0, 4 => "", 0, 5; 0, 5 => " foxes"]); + assert_eq!(text, "quick foxes"); + + apply_document_changes(&mut text, change![0, 11; 0, 11 => "\ndream"]); + assert_eq!(text, "quick foxes\ndream"); + + apply_document_changes(&mut text, change![1, 0; 1, 0 => "have "]); + assert_eq!(text, "quick foxes\nhave dream"); + + apply_document_changes( + &mut text, + change![0, 0; 0, 0 => "the ", 1, 4; 1, 4 => " quiet", 1, 16; 1, 16 => "s\n"], + ); + assert_eq!(text, "the quick foxes\nhave quiet dreams\n"); + + apply_document_changes( + &mut text, + change![0, 15; 0, 15 => "\n", 2, 17; 2, 17 => "\n"], + ); + assert_eq!(text, "the quick foxes\n\nhave quiet dreams\n\n"); + + apply_document_changes( + &mut text, + change![1, 0; 1, 0 => "DREAM", 2, 0; 2, 0 => "they ", 3, 0; 3, 0 => "DON'T THEY?"], + ); + assert_eq!( + text, + "the quick foxes\nDREAM\nthey have quiet dreams\nDON'T THEY?\n" + ); + + apply_document_changes(&mut text, change![0, 10; 1, 5 => "", 2, 0; 2, 12 => ""]); + assert_eq!(text, "the quick \nthey have quiet dreams\n"); + + text = String::from("❤️"); + apply_document_changes(&mut text, change![0, 0; 0, 0 => "a"]); + assert_eq!(text, "a❤️"); + + // todo: Non-ASCII char + // text = String::from("a\nb"); + // apply_document_changes(&mut text, change![0, 1; 1, 0 => "\nțc", 0, 1; 1, 1 => "d"]); + // assert_eq!(text, "adcb"); + + // text = String::from("a\nb"); + // apply_document_changes(&mut text, change![0, 1; 1, 0 => "ț\nc", 0, 2; 0, 2 => "c"]); + // assert_eq!(text, "ațc\ncb"); +} + +#[test] +#[bench_test] +fn file_path_from_url_test() { + if cfg!(windows) { + let url = + Url::parse("file:///c%3A/Users/abc/Desktop/%E4%B8%AD%E6%96%87/ab%20c/abc.k").unwrap(); + let path = file_path_from_url(&url).unwrap(); + assert_eq!(path, "C:\\Users\\abc\\Desktop\\中文\\ab c\\abc.k"); + } else { + let url = Url::parse("file:///Users/abc/Desktop/%E4%B8%AD%E6%96%87/ab%20c/abc.k").unwrap(); + let path = file_path_from_url(&url).unwrap(); + assert_eq!(path, "/Users/abc/Desktop/中文/ab c/abc.k"); + } +} + +#[test] +fn test_lsp_with_kcl_mod_in_order() { + goto_import_external_file_test(); + println!("goto_import_external_file_test PASS"); + goto_import_pkg_with_line_test(); + println!("goto_import_pkg_with_line_test PASS"); + complete_import_external_file_test(); + println!("complete_import_external_file_test PASS"); +} + +fn goto_import_pkg_with_line_test() { + let path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + let (file, _program, _, gs, _) = + compile_test_file("src/test_data/goto_def_with_line_test/main_pkg/main.k"); + let pos = KCLPos { + filename: file.adjust_canonicalization(), + line: 1, + column: Some(27), + }; + + let res = goto_def(&pos, &gs); + + match res.unwrap() { + lsp_types::GotoDefinitionResponse::Scalar(loc) => { + let got_path = file_path_from_url(&loc.uri).unwrap(); + let expected_path = path + .join("src/test_data/goto_def_with_line_test/dep-with-line/main.k") + .canonicalize() + .unwrap() + .display() + .to_string() + .adjust_canonicalization(); + assert_eq!(got_path, expected_path) + } + _ => { + unreachable!("test error") + } + } +} + +fn complete_import_external_file_test() { + let path = PathBuf::from(".") + .join("src") + .join("test_data") + .join("completion_test") + .join("import") + .join("external") + .join("external_0") + .join("main.k") + .canonicalize() + .unwrap() + .display() + .to_string(); + + let _ = Command::new("kcl") + .arg("mod") + .arg("metadata") + .arg("--update") + .current_dir( + PathBuf::from(".") + .join("src") + .join("test_data") + .join("completion_test") + .join("import") + .join("external") + .join("external_0") + .canonicalize() + .unwrap() + .display() + .to_string(), + ) + .output() + .unwrap(); + + let (program, schema_map, gs) = compile_with_params(Params { + file: Some(path.to_string()), + module_cache: None, + scope_cache: None, + vfs: Some(KCLVfs::default()), + gs_cache: Some(KCLGlobalStateCache::default()), + }) + .1 + .unwrap(); + + let pos = KCLPos { + filename: path.to_string().adjust_canonicalization(), + line: 1, + column: Some(11), + }; + let tool = toolchain::default(); + let res = completion(Some('.'), &program, &pos, &gs, &tool, None, &schema_map).unwrap(); + + let got_labels: Vec = match &res { + CompletionResponse::Array(arr) => arr.iter().map(|item| item.label.clone()).collect(), + CompletionResponse::List(_) => panic!("test failed"), + }; + let expected_labels: Vec<&str> = vec![ + "api", + "apiextensions_apiserver", + "apimachinery", + "kube_aggregator", + "vendor", + ]; + assert_eq!(got_labels, expected_labels); +} + +fn goto_import_external_file_test() { + let path = PathBuf::from(".") + .join("src") + .join("test_data") + .join("goto_import_def_test") + .join("main.k") + .canonicalize() + .unwrap() + .display() + .to_string(); + + let _ = Command::new("kcl") + .arg("mod") + .arg("metadata") + .arg("--update") + .current_dir( + PathBuf::from(".") + .join("src") + .join("test_data") + .join("goto_import_def_test") + .canonicalize() + .unwrap() + .display() + .to_string(), + ) + .output() + .unwrap(); + + let (diags, compile_res) = compile_with_params(Params { + file: Some(path.to_string()), + module_cache: None, + scope_cache: None, + vfs: Some(KCLVfs::default()), + gs_cache: Some(KCLGlobalStateCache::default()), + }); + let gs = compile_res.unwrap().2; + + assert_eq!(diags.len(), 0); + + // test goto import file: import .pkg.schema_def + let pos = KCLPos { + filename: path.to_string().adjust_canonicalization(), + line: 1, + column: Some(57), + }; + let res = goto_def(&pos, &gs); + assert!(res.is_some()); +} + +// LSP e2e test + +/// A `Project` represents a project that a language server can work with. Call the [`server`] +/// method to instantiate a language server that will serve information about the project. +pub struct Project {} + +impl Project { + /// Instantiates a language server for this project. + pub fn server(self, initialize_params: InitializeParams) -> Server { + Server::new(initialize_params) + } +} + +/// An object that runs the language server main loop and enables sending and receiving messages +/// to and from it. +pub struct Server { + next_request_id: Cell, + worker: Option>, + client: Connection, + messages: RefCell>, +} + +impl Server { + /// Constructs and initializes a new `Server` + pub fn new(initialize_params: InitializeParams) -> Self { + let (connection, client) = Connection::memory(); + + let worker = std::thread::spawn(move || { + main_loop(connection, initialize_params).unwrap(); + }); + + Self { + next_request_id: Cell::new(1), + worker: Some(worker), + client, + messages: RefCell::new(Vec::new()), + } + } + + /// Sends a request to the language server, returning the response + pub fn send_request(&self, params: R::Params) { + let id = self.next_request_id.get(); + self.next_request_id.set(id.wrapping_add(1)); + let r = Request::new(id.into(), R::METHOD.to_string(), params); + self.client.sender.send(r.into()).unwrap(); + } + + /// Sends an LSP notification to the main loop. + pub(crate) fn notification(&self, params: N::Params) + where + N::Params: Serialize, + { + let r = Notification::new(N::METHOD.to_string(), params); + self.send_notification(r); + } + + /// Sends a server notification to the main loop + fn send_notification(&self, not: Notification) { + self.client.sender.send(Message::Notification(not)).unwrap(); + wait_async!(); + } + + /// A function to wait for a specific message to arrive + fn wait_for_message_cond(&self, n: usize, cond: &dyn Fn(&Message) -> bool) { + let mut total = 0; + for msg in self.messages.borrow().iter() { + if cond(msg) { + total += 1 + } + } + while total < n { + let msg = self.recv().expect("no response"); + if cond(&msg) { + total += 1; + } + } + } + + /// Receives a message from the message or timeout. + pub(crate) fn recv(&self) -> Option { + let timeout = Duration::from_secs(5); + let msg = select! { + recv(self.client.receiver) -> msg => msg.ok(), + recv(after(timeout)) -> _ => panic!("timed out"), + }; + if let Some(ref msg) = msg { + self.messages.borrow_mut().push(msg.clone()); + } + msg + } + + /// Receives a message from the message, if timeout, return None. + pub(crate) fn recv_without_timeout(&self) -> Option { + let timeout = Duration::from_secs(5); + let msg = select! { + recv(self.client.receiver) -> msg => msg.ok(), + recv(after(timeout)) -> _ => return None, + }; + if let Some(ref msg) = msg { + self.messages.borrow_mut().push(msg.clone()); + } + msg + } + + /// Sends a request to the main loop and receives its response + fn send_and_receive(&self, r: Request) -> Response { + let id = r.id.clone(); + self.client.sender.send(r.into()).unwrap(); + while let Some(msg) = self.recv() { + match msg { + Message::Request(req) => { + panic!("did not expect a request as a response to a request: {req:?}") + } + Message::Notification(_) => (), + Message::Response(res) => { + assert_eq!(res.id, id); + return res; + } + } + } + panic!("did not receive a response to our request"); + } + + fn receive_response(&self, id: RequestId) -> Option { + while let Some(msg) = self.recv_without_timeout() { + match msg { + Message::Request(req) => { + panic!("did not expect a request as a response to a request: {req:?}") + } + Message::Notification(_) => (), + Message::Response(res) => { + if res.id == id { + return Some(res); + } + } + } + } + None + } +} + +impl Drop for Server { + fn drop(&mut self) { + // Send the proper shutdown sequence to ensure the main loop terminates properly + self.notification::(()); + + // Cancel the main_loop + if let Some(worker) = self.worker.take() { + worker.join().unwrap(); + } + } +} + +#[test] +fn notification_test() { + let root = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + let mut path = root.clone(); + + path.push("src/test_data/diagnostics/diagnostics.k"); + + let path = path.to_str().unwrap(); + let src = std::fs::read_to_string(path).unwrap(); + let server = Project {}.server(InitializeParams::default()); + + // Mock open file + server.notification::( + lsp_types::DidOpenTextDocumentParams { + text_document: TextDocumentItem { + uri: Url::from_file_path(path).unwrap(), + language_id: "KCL".to_string(), + version: 0, + text: src, + }, + }, + ); + + // Wait for first "textDocument/publishDiagnostics" notification + server.wait_for_message_cond(1, &|msg: &Message| match msg { + Message::Notification(not) => not.method == "textDocument/publishDiagnostics", + _ => false, + }); + + let msgs = server.messages.borrow(); + for msg in msgs.iter() { + match msg { + Message::Notification(not) => { + if let Some(uri) = not.params.get("uri") { + if uri.clone() == to_json(Url::from_file_path(path).unwrap()).unwrap() { + assert_eq!( + not.params, + to_json(PublishDiagnosticsParams { + uri: Url::from_file_path(path).unwrap(), + diagnostics: build_expect_diags(), + version: None, + }) + .unwrap() + ); + break; + } + } + } + _ => {} + } + } +} + +#[test] +fn close_file_test() { + let root = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + let mut path = root.clone(); + + path.push("src/test_data/diagnostics/diagnostics.k"); + + let path = path.to_str().unwrap(); + let src = std::fs::read_to_string(path).unwrap(); + let server = Project {}.server(InitializeParams::default()); + + // Mock open file + server.notification::( + lsp_types::DidOpenTextDocumentParams { + text_document: TextDocumentItem { + uri: Url::from_file_path(path).unwrap(), + language_id: "KCL".to_string(), + version: 0, + text: src.clone(), + }, + }, + ); + + // Mock close file + server.notification::( + lsp_types::DidCloseTextDocumentParams { + text_document: TextDocumentIdentifier { + uri: Url::from_file_path(path).unwrap(), + }, + }, + ); + + // Mock reopen file + server.notification::( + lsp_types::DidOpenTextDocumentParams { + text_document: TextDocumentItem { + uri: Url::from_file_path(path).unwrap(), + language_id: "KCL".to_string(), + version: 0, + text: src, + }, + }, + ); +} + +#[test] +fn non_kcl_file_test() { + let root = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + + let server = Project {}.server(InitializeParams::default()); + let mut path = root.clone(); + path.push("src/test_data/diagnostics.kcl"); + + // Mock open a Non-KCL file + server.notification::( + lsp_types::DidOpenTextDocumentParams { + text_document: TextDocumentItem { + uri: Url::from_file_path(path.clone()).unwrap(), + language_id: "KCL".to_string(), + version: 0, + text: "".to_string(), + }, + }, + ); + + let id = server.next_request_id.get(); + server.next_request_id.set(id.wrapping_add(1)); + + let r: Request = Request::new( + id.into(), + "textDocument/documentSymbol".to_string(), + DocumentSymbolParams { + text_document: TextDocumentIdentifier { + uri: Url::from_file_path(path).unwrap(), + }, + work_done_progress_params: Default::default(), + partial_result_params: Default::default(), + }, + ); + + // Send request and wait for it's response + let res = server.send_and_receive(r); + assert!(res.result.is_some()); +} + +#[test] +fn cancel_test() { + let root = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + let mut path = root.clone(); + + path.push("src/test_data/goto_def_test/goto_def.k"); + + let path = path.to_str().unwrap(); + let src = std::fs::read_to_string(path).unwrap(); + let server = Project {}.server(InitializeParams::default()); + + // Mock open file + server.notification::( + lsp_types::DidOpenTextDocumentParams { + text_document: TextDocumentItem { + uri: Url::from_file_path(path).unwrap(), + language_id: "KCL".to_string(), + version: 0, + text: src, + }, + }, + ); + + let id = server.next_request_id.get(); + server.next_request_id.set(id.wrapping_add(1)); + + // send request + server.send_request::(GotoDefinitionParams { + text_document_position_params: TextDocumentPositionParams { + text_document: TextDocumentIdentifier { + uri: Url::from_file_path(path).unwrap(), + }, + position: Position::new(23, 9), + }, + work_done_progress_params: Default::default(), + partial_result_params: Default::default(), + }); + + // cancel request + server.notification::(lsp_types::CancelParams { + id: NumberOrString::Number(id), + }); + + assert!(server.receive_response(id.into()).is_none()); +} + +#[test] +fn goto_def_test() { + let root = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + let path = root.clone(); + let path = path + .join("src") + .join("test_data") + .join("goto_def_test") + .join("goto_def.k"); + + let path = path.to_str().unwrap(); + let src = std::fs::read_to_string(path).unwrap(); + let server = Project {}.server(InitializeParams::default()); + + // Mock open file + server.notification::( + lsp_types::DidOpenTextDocumentParams { + text_document: TextDocumentItem { + uri: Url::from_file_path(path).unwrap(), + language_id: "KCL".to_string(), + version: 0, + text: src, + }, + }, + ); + + let id = server.next_request_id.get(); + server.next_request_id.set(id.wrapping_add(1)); + + let r: Request = Request::new( + id.into(), + "textDocument/definition".to_string(), + GotoDefinitionParams { + text_document_position_params: TextDocumentPositionParams { + text_document: TextDocumentIdentifier { + uri: Url::from_file_path(path).unwrap(), + }, + position: Position::new(23, 9), + }, + work_done_progress_params: Default::default(), + partial_result_params: Default::default(), + }, + ); + + // Send request and wait for it's response + let res = server.send_and_receive(r); + + assert_eq!( + res.result.unwrap(), + to_json(GotoDefinitionResponse::Scalar(Location { + uri: Url::from_file_path(path).unwrap(), + range: Range { + start: Position::new(20, 7), + end: Position::new(20, 13), + }, + })) + .unwrap() + ); +} + +#[test] +fn complete_test() { + let root = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + let path = root.clone(); + let path = path + .join("src") + .join("test_data") + .join("completion_test") + .join("dot") + .join("completion") + .join("completion.k"); + + let path = path.to_str().unwrap(); + let src = std::fs::read_to_string(path).unwrap(); + let server = Project {}.server(InitializeParams::default()); + + // Mock open file + server.notification::( + lsp_types::DidOpenTextDocumentParams { + text_document: TextDocumentItem { + uri: Url::from_file_path(path).unwrap(), + language_id: "KCL".to_string(), + version: 0, + text: src, + }, + }, + ); + + let id = server.next_request_id.get(); + server.next_request_id.set(id.wrapping_add(1)); + + let r: Request = Request::new( + id.into(), + "textDocument/completion".to_string(), + CompletionParams { + text_document_position: TextDocumentPositionParams { + text_document: TextDocumentIdentifier { + uri: Url::from_file_path(path).unwrap(), + }, + position: Position::new(11, 7), + }, + work_done_progress_params: Default::default(), + partial_result_params: Default::default(), + context: Some(CompletionContext { + trigger_kind: CompletionTriggerKind::TRIGGER_CHARACTER, + trigger_character: Some(".".to_string()), + }), + }, + ); + + // Send request and wait for it's response + let res = server.send_and_receive(r); + + assert_eq!( + res.result.unwrap(), + to_json(CompletionResponse::Array(vec![ + CompletionItem { + label: "name".to_string(), + kind: Some(CompletionItemKind::FIELD), + detail: Some("name: str".to_string()), + ..Default::default() + }, + CompletionItem { + label: "age".to_string(), + kind: Some(CompletionItemKind::FIELD), + detail: Some("age: int".to_string()), + ..Default::default() + } + ])) + .unwrap() + ) +} + +#[test] +fn complete_with_version_test() { + let root = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + let path = root.clone(); + let path = path + .join("src") + .join("test_data") + .join("completion_test") + .join("newline") + .join("newline_with_version") + .join("newline_with_version.k"); + let path = path.to_str().unwrap(); + let src = std::fs::read_to_string(path).unwrap(); + let server = Project {}.server(InitializeParams::default()); + + // Mock open file + server.notification::( + lsp_types::DidOpenTextDocumentParams { + text_document: TextDocumentItem { + uri: Url::from_file_path(path).unwrap(), + language_id: "KCL".to_string(), + version: 0, + text: src, + }, + }, + ); + + server.notification::( + lsp_types::DidChangeTextDocumentParams { + text_document: lsp_types::VersionedTextDocumentIdentifier { + uri: Url::from_file_path(path).unwrap(), + version: 1, + }, + content_changes: vec![TextDocumentContentChangeEvent { + range: None, + range_length: None, + text: "schema Name:\n name: str\n\nname1 = \"\"\n\nname: Name{\n \n}" + .to_string(), + }], + }, + ); + + let id = server.next_request_id.get(); + server.next_request_id.set(id.wrapping_add(1)); + + let r: Request = Request::new( + id.into(), + "textDocument/completion".to_string(), + CompletionParams { + text_document_position: TextDocumentPositionParams { + text_document: TextDocumentIdentifier { + uri: Url::from_file_path(path).unwrap(), + }, + position: Position::new(6, 4), + }, + work_done_progress_params: Default::default(), + partial_result_params: Default::default(), + context: Some(CompletionContext { + trigger_kind: CompletionTriggerKind::TRIGGER_CHARACTER, + trigger_character: Some("\n".to_string()), + }), + }, + ); + + let id = r.id.clone(); + server.client.sender.send(r.into()).unwrap(); + + while let Some(msg) = server.recv() { + match msg { + Message::Request(req) => { + panic!("did not expect a request as a response to a request: {req:?}") + } + Message::Notification(_) => (), + Message::Response(res) => { + assert_eq!(res.id, id); + assert_eq!( + res.result.unwrap(), + to_json(CompletionResponse::Array(vec![CompletionItem { + label: "name".to_string(), + kind: Some(CompletionItemKind::FIELD), + detail: Some("name: str".to_string()), + ..Default::default() + },])) + .unwrap() + ); + break; + } + } + } +} + +#[test] +fn hover_test() { + let root = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + let path = root + .join("src") + .join("test_data") + .join("hover_test") + .join("hover.k"); + let path = path.to_str().unwrap(); + + let src = std::fs::read_to_string(path).unwrap(); + let server = Project {}.server(InitializeParams::default()); + + // Mock open file + server.notification::( + lsp_types::DidOpenTextDocumentParams { + text_document: TextDocumentItem { + uri: Url::from_file_path(path).unwrap(), + language_id: "KCL".to_string(), + version: 0, + text: src, + }, + }, + ); + + let id = server.next_request_id.get(); + server.next_request_id.set(id.wrapping_add(1)); + + let r: Request = Request::new( + id.into(), + "textDocument/hover".to_string(), + HoverParams { + text_document_position_params: TextDocumentPositionParams { + text_document: TextDocumentIdentifier { + uri: Url::from_file_path(path).unwrap(), + }, + position: Position::new(15, 7), + }, + work_done_progress_params: Default::default(), + }, + ); + + // Send request and wait for it's response + let res = server.send_and_receive(r); + + assert_eq!( + res.result.unwrap(), + to_json(Hover { + contents: HoverContents::Array(vec![ + MarkedString::String("__main__".to_string()), + MarkedString::LanguageString(lsp_types::LanguageString { + language: "KCL".to_string(), + value: "schema Person:\n name: str\n age?: int".to_string() + }), + MarkedString::String("hover doc test".to_string()), + ]), + range: None + }) + .unwrap() + ) +} + +#[test] +fn hover_assign_in_lambda_test() { + let root = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + let mut path = root.clone(); + + path.push("src/test_data/hover_test/assign_in_lambda.k"); + + let path = path.to_str().unwrap(); + let src = std::fs::read_to_string(path).unwrap(); + let server = Project {}.server(InitializeParams::default()); + + // Mock open file + server.notification::( + lsp_types::DidOpenTextDocumentParams { + text_document: TextDocumentItem { + uri: Url::from_file_path(path).unwrap(), + language_id: "KCL".to_string(), + version: 0, + text: src, + }, + }, + ); + + let id = server.next_request_id.get(); + server.next_request_id.set(id.wrapping_add(1)); + + let r: Request = Request::new( + id.into(), + "textDocument/hover".to_string(), + HoverParams { + text_document_position_params: TextDocumentPositionParams { + text_document: TextDocumentIdentifier { + uri: Url::from_file_path(path).unwrap(), + }, + position: Position::new(4, 7), + }, + work_done_progress_params: Default::default(), + }, + ); + + // Send request and wait for it's response + let res = server.send_and_receive(r); + + assert_eq!( + res.result.unwrap(), + to_json(Hover { + contents: HoverContents::Scalar(MarkedString::LanguageString( + lsp_types::LanguageString { + language: "KCL".to_string(), + value: "images: [str]".to_string() + } + )), + range: None + }) + .unwrap() + ) +} + +#[test] +fn formatting_test() { + let root = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + let mut path = root.clone(); + + path.push("src/test_data/format/format_range.k"); + + let path = path.to_str().unwrap(); + let src = std::fs::read_to_string(path).unwrap(); + let server = Project {}.server(InitializeParams::default()); + + // Mock open file + server.notification::( + lsp_types::DidOpenTextDocumentParams { + text_document: TextDocumentItem { + uri: Url::from_file_path(path).unwrap(), + language_id: "KCL".to_string(), + version: 0, + text: src, + }, + }, + ); + + let id = server.next_request_id.get(); + server.next_request_id.set(id.wrapping_add(1)); + + let r: Request = Request::new( + id.into(), + "textDocument/formatting".to_string(), + DocumentFormattingParams { + text_document: TextDocumentIdentifier { + uri: Url::from_file_path(path).unwrap(), + }, + options: Default::default(), + work_done_progress_params: Default::default(), + }, + ); + + // Send request and wait for it's response + let res = server.send_and_receive(r); + + assert_eq!( + res.result.unwrap(), + to_json(Some(vec![TextEdit { + range: Range::new( + Position::new(0, 0), + Position::new(i32::MAX as u32, i32::MAX as u32), + ), + new_text: "a = 1\n\nb = 2\n\nc = 3\n\nd = 4\n".to_string() + }])) + .unwrap() + ) +} + +#[test] +fn formatting_unsaved_test() { + let root = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + let mut path = root.clone(); + + path.push("src/test_data/format/format_range.k"); + + let path = path.to_str().unwrap(); + let src = std::fs::read_to_string(path).unwrap(); + let server = Project {}.server(InitializeParams::default()); + + let uri = Url::from_file_path(path).unwrap(); + + // Mock open file + server.notification::( + lsp_types::DidOpenTextDocumentParams { + text_document: TextDocumentItem { + uri: uri.clone(), + language_id: "KCL".to_string(), + version: 0, + text: src, + }, + }, + ); + + // Mock edit file + server.notification::( + lsp_types::DidChangeTextDocumentParams { + text_document: lsp_types::VersionedTextDocumentIdentifier { + uri: uri.clone(), + version: 1, + }, + content_changes: vec![lsp_types::TextDocumentContentChangeEvent { + range: Some(lsp_types::Range::new( + lsp_types::Position::new(0, 0), + lsp_types::Position::new(0, 0), + )), + range_length: Some(0), + text: String::from("unsaved = 0\n"), + }], + }, + ); + + let id = server.next_request_id.get(); + server.next_request_id.set(id.wrapping_add(1)); + + let r: Request = Request::new( + id.into(), + "textDocument/formatting".to_string(), + DocumentFormattingParams { + text_document: TextDocumentIdentifier { + uri: Url::from_file_path(path).unwrap(), + }, + options: Default::default(), + work_done_progress_params: Default::default(), + }, + ); + + // Send request and wait for it's response + let res = server.send_and_receive(r); + + assert_eq!( + res.result.unwrap(), + to_json(Some(vec![TextEdit { + range: Range::new( + Position::new(0, 0), + Position::new(i32::MAX as u32, i32::MAX as u32), + ), + new_text: "unsaved = 0\n\na = 1\n\nb = 2\n\nc = 3\n\nd = 4\n".to_string() + }])) + .unwrap() + ) +} + +#[test] +fn complete_import_external_file_e2e_test() { + let root = PathBuf::from(env!("CARGO_MANIFEST_DIR")) + .join("src") + .join("test_data") + .join("completion_test") + .join("import") + .join("external") + .join("external_1"); + let path = root + .join("main.k") + .canonicalize() + .unwrap() + .display() + .to_string(); + let _ = Command::new("kcl") + .arg("mod") + .arg("metadata") + .arg("--update") + .current_dir( + PathBuf::from(".") + .join("src") + .join("test_data") + .join("completion_test") + .join("import") + .join("external") + .join("external_1") + .canonicalize() + .unwrap() + .display() + .to_string(), + ) + .output() + .unwrap(); + + let src = std::fs::read_to_string(path.clone()).unwrap(); + + let initialize_params = InitializeParams { + workspace_folders: Some(vec![WorkspaceFolder { + uri: Url::from_file_path(root.clone()).unwrap(), + name: "test".to_string(), + }]), + ..Default::default() + }; + let server = Project {}.server(initialize_params); + + // FIXME: It takes longer to parse the k8s package on Windows + #[cfg(target_os = "windows")] + wait_async!(20000); + + // Mock open file + server.notification::( + lsp_types::DidOpenTextDocumentParams { + text_document: TextDocumentItem { + uri: Url::from_file_path(path.clone()).unwrap(), + language_id: "KCL".to_string(), + version: 0, + text: src, + }, + }, + ); + wait_async!(5000); + + let id = server.next_request_id.get(); + server.next_request_id.set(id.wrapping_add(1)); + + let r: Request = Request::new( + id.into(), + "textDocument/completion".to_string(), + CompletionParams { + text_document_position: TextDocumentPositionParams { + text_document: TextDocumentIdentifier { + uri: Url::from_file_path(path).unwrap(), + }, + position: Position::new(0, 7), + }, + work_done_progress_params: Default::default(), + partial_result_params: Default::default(), + context: None, + }, + ); + + // Send request and wait for it's response + let res = server.send_and_receive(r); + match res.result.unwrap() { + serde_json::Value::Array(vec) => { + assert!( + (vec.iter() + .find(|v| match v { + serde_json::Value::Object(map) => { + map.get("label").unwrap() == "k8s" + } + _ => false, + }) + .is_some()), + "" + ); + } + _ => panic!("test failed"), + } +} + +// TODO: wait for fix `kcl mod metadata` to read only. Otherwise it will lead to an infinite loop +#[allow(dead_code)] +// #[test] +fn mod_file_watcher_test() { + let path = PathBuf::from(".") + .join("src") + .join("test_data") + .join("watcher") + .join("modify") + .canonicalize() + .unwrap(); + + let mod_file_path = path.join("kcl.mod"); + let main_path = path.join("main.k"); + + let mod_src_bac = std::fs::read_to_string(mod_file_path.clone()).unwrap(); + let main_src = std::fs::read_to_string(main_path.clone()).unwrap(); + + let initialize_params = InitializeParams { + workspace_folders: Some(vec![WorkspaceFolder { + uri: Url::from_file_path(path.clone()).unwrap(), + name: "test".to_string(), + }]), + ..Default::default() + }; + let server = Project {}.server(initialize_params); + + // Mock open file + server.notification::( + lsp_types::DidOpenTextDocumentParams { + text_document: TextDocumentItem { + uri: Url::from_file_path(main_path.clone()).unwrap(), + language_id: "KCL".to_string(), + version: 0, + text: main_src, + }, + }, + ); + + let _ = Command::new("kcl") + .arg("mod") + .arg("add") + .arg("helloworld") + .current_dir(path) + .output() + .unwrap(); + + // wait for download dependence + wait_async!(2000); + + let id = server.next_request_id.get(); + server.next_request_id.set(id.wrapping_add(1)); + + let r: Request = Request::new( + id.into(), + "textDocument/hover".to_string(), + HoverParams { + text_document_position_params: TextDocumentPositionParams { + text_document: TextDocumentIdentifier { + uri: Url::from_file_path(main_path).unwrap(), + }, + position: Position::new(0, 8), + }, + work_done_progress_params: Default::default(), + }, + ); + + // Send request and wait for it's response + let res = server.send_and_receive(r); + + std::fs::write(mod_file_path, mod_src_bac).unwrap(); + assert_eq!( + res.result.unwrap(), + to_json(Hover { + contents: HoverContents::Scalar(MarkedString::LanguageString( + lsp_types::LanguageString { + language: "KCL".to_owned(), + value: "helloworld: ".to_string(), + } + )), + range: None + }) + .unwrap() + ) +} + +// Integration testing of lsp and konfig +fn konfig_path() -> PathBuf { + let konfig_path = Path::new(".") + .canonicalize() + .unwrap() + .parent() + .unwrap() + .parent() + .unwrap() + .parent() + .unwrap() + .parent() + .unwrap() + .join("test") + .join("integration") + .join("konfig"); + konfig_path +} + +#[test] +fn konfig_goto_def_test_base() { + let konfig_path = konfig_path(); + let base_path = konfig_path + .clone() + .join("appops") + .join("nginx-example") + .join("base") + .join("base.k"); + let base_path_str = base_path.to_str().unwrap().to_string(); + let (_program, _, gs) = compile_with_params(Params { + file: Some(base_path_str.clone()), + module_cache: None, + scope_cache: None, + vfs: Some(KCLVfs::default()), + gs_cache: Some(KCLGlobalStateCache::default()), + }) + .1 + .unwrap(); + + // schema def + let pos = KCLPos { + filename: base_path_str.clone().adjust_canonicalization(), + line: 7, + column: Some(30), + }; + let res = goto_def(&pos, &gs); + let expected_path = konfig_path + .clone() + .join("base") + .join("pkg") + .join("kusion_models") + .join("kube") + .join("frontend") + .join("server.k"); + + compare_goto_res( + res, + (&expected_path.to_str().unwrap().to_string(), 12, 7, 12, 13), + ); + + // schema def + let pos = KCLPos { + filename: base_path_str.clone().adjust_canonicalization(), + line: 9, + column: Some(32), + }; + let res = goto_def(&pos, &gs); + let expected_path = konfig_path + .clone() + .join("base") + .join("pkg") + .join("kusion_models") + .join("kube") + .join("frontend") + .join("container") + .join("container.k"); + compare_goto_res( + res, + (&expected_path.to_str().unwrap().to_string(), 5, 7, 5, 11), + ); + + // schema attr + let pos = KCLPos { + filename: base_path_str.clone().adjust_canonicalization(), + line: 9, + column: Some(9), + }; + let res = goto_def(&pos, &gs); + let expected_path = konfig_path + .clone() + .join("base") + .join("pkg") + .join("kusion_models") + .join("kube") + .join("frontend") + .join("server.k"); + compare_goto_res( + res, + ( + &expected_path.to_str().unwrap().to_string(), + 115, + 4, + 115, + 17, + ), + ); + + // schema attr + let pos = KCLPos { + filename: base_path_str.clone().adjust_canonicalization(), + line: 10, + column: Some(10), + }; + let res = goto_def(&pos, &gs); + let expected_path = konfig_path + .clone() + .join("base") + .join("pkg") + .join("kusion_models") + .join("kube") + .join("frontend") + .join("container") + .join("container.k"); + compare_goto_res( + res, + (&expected_path.to_str().unwrap().to_string(), 69, 4, 69, 9), + ); + + // import pkg + let pos = KCLPos { + filename: base_path_str.clone().adjust_canonicalization(), + line: 2, + column: Some(49), + }; + let res = goto_def(&pos, &gs); + + let expected_path = konfig_path + .clone() + .join("base") + .join("pkg") + .join("kusion_models") + .join("kube") + .join("frontend") + .join("service") + .join("service.k"); + compare_goto_res( + res, + (&expected_path.to_str().unwrap().to_string(), 0, 0, 0, 0), + ); +} + +#[test] +fn konfig_goto_def_test_main() { + let konfig_path = konfig_path(); + let main_path = konfig_path + .clone() + .join("appops") + .join("nginx-example") + .join("dev") + .join("main.k"); + let main_path_str = main_path.to_str().unwrap().to_string(); + let (_program, _, gs) = compile_with_params(Params { + file: Some(main_path_str.clone()), + module_cache: None, + scope_cache: None, + vfs: Some(KCLVfs::default()), + gs_cache: Some(KCLGlobalStateCache::default()), + }) + .1 + .unwrap(); + + // schema def + let pos = KCLPos { + filename: main_path_str.clone().adjust_canonicalization(), + line: 6, + column: Some(31), + }; + let res = goto_def(&pos, &gs); + let expected_path = konfig_path + .clone() + .join("base") + .join("pkg") + .join("kusion_models") + .join("kube") + .join("frontend") + .join("server.k"); + compare_goto_res( + res, + (&expected_path.to_str().unwrap().to_string(), 12, 7, 12, 13), + ); + + // schema attr + let pos = KCLPos { + filename: main_path_str.clone().adjust_canonicalization(), + line: 7, + column: Some(14), + }; + let res = goto_def(&pos, &gs); + let expected_path = konfig_path + .clone() + .join("base") + .join("pkg") + .join("kusion_models") + .join("kube") + .join("frontend") + .join("server.k"); + compare_goto_res( + res, + ( + &expected_path.to_str().unwrap().to_string(), + 112, + 4, + 112, + 22, + ), + ); + + // import pkg + let pos = KCLPos { + filename: main_path_str.clone().adjust_canonicalization(), + line: 2, + column: Some(61), + }; + let res = goto_def(&pos, &gs); + let expected_path = konfig_path + .clone() + .join("base") + .join("pkg") + .join("kusion_models") + .join("kube") + .join("templates") + .join("resource.k"); + compare_goto_res( + res, + (&expected_path.to_str().unwrap().to_string(), 0, 0, 0, 0), + ); +} + +#[test] +fn konfig_completion_test_main() { + let konfig_path = konfig_path(); + let main_path = konfig_path + .clone() + .join("appops") + .join("nginx-example") + .join("dev") + .join("main.k"); + let main_path_str = main_path.to_str().unwrap().to_string(); + let (program, schema_map, gs) = compile_with_params(Params { + file: Some(main_path_str.clone()), + module_cache: None, + scope_cache: None, + vfs: Some(KCLVfs::default()), + gs_cache: Some(KCLGlobalStateCache::default()), + }) + .1 + .unwrap(); + + // pkg's definition(schema) completion + let pos = KCLPos { + filename: main_path_str.clone().adjust_canonicalization(), + line: 6, + column: Some(27), + }; + let tool = toolchain::default(); + let got = completion(Some('.'), &program, &pos, &gs, &tool, None, &schema_map).unwrap(); + let got_labels: Vec = match got { + CompletionResponse::Array(arr) => arr.iter().map(|item| item.label.clone()).collect(), + CompletionResponse::List(_) => panic!("test failed"), + }; + + let expected_labels: Vec = ["Job", "Server"] + .iter() + .map(|attr| attr.to_string()) + .collect(); + assert_eq!(got_labels, expected_labels); + + // schema attr completion + let pos = KCLPos { + filename: main_path_str.clone().adjust_canonicalization(), + line: 7, + column: Some(4), + }; + let tool = toolchain::default(); + let got = completion(None, &program, &pos, &gs, &tool, None, &schema_map).unwrap(); + let mut got_labels: Vec = match got { + CompletionResponse::Array(arr) => arr.iter().map(|item| item.label.clone()).collect(), + CompletionResponse::List(_) => panic!("test failed"), + }; + let mut attr = [ + "annotations", + "configMaps", + "database", + "enableMonitoring", + "frontend", + "image", + "ingresses", + "initContainers", + "labels", + "mainContainer", + "name", + "needNamespace", + "podMetadata", + "renderType", + "replicas", + "res_tpl", + "schedulingStrategy", + "secrets", + "selector", + "serviceAccount", + "services", + "sidecarContainers", + "storage", + "useBuiltInLabels", + "useBuiltInSelector", + "volumes", + "workloadType", + ]; + got_labels.sort(); + attr.sort(); + assert_eq!(got_labels, attr); + + // import path completion + let pos = KCLPos { + filename: main_path_str.clone().adjust_canonicalization(), + line: 1, + column: Some(35), + }; + let tool = toolchain::default(); + let got = completion(Some('.'), &program, &pos, &gs, &tool, None, &schema_map).unwrap(); + let mut got_labels: Vec = match got { + CompletionResponse::Array(arr) => arr.iter().map(|item| item.label.clone()).collect(), + CompletionResponse::List(_) => panic!("test failed"), + }; + let mut pkgs = [ + "common", + "configmap", + "container", + "ingress", + "job", + "rbac", + "resource", + "secret", + "server", + "service", + "serviceaccount", + "sidecar", + "storage", + "strategy", + "volume", + ]; + got_labels.sort(); + pkgs.sort(); + assert_eq!(got_labels, pkgs); +} + +#[test] +fn konfig_hover_test_main() { + let konfig_path = konfig_path(); + let main_path = konfig_path + .clone() + .join("appops") + .join("nginx-example") + .join("dev") + .join("main.k"); + + let main_path_str = main_path.to_str().unwrap().to_string(); + let (_program, _, gs) = compile_with_params(Params { + file: Some(main_path_str.clone()), + module_cache: None, + scope_cache: None, + vfs: Some(KCLVfs::default()), + gs_cache: Some(KCLGlobalStateCache::default()), + }) + .1 + .unwrap(); + + // schema def hover + let pos = KCLPos { + filename: main_path_str.clone().adjust_canonicalization(), + line: 6, + column: Some(32), + }; + let got = hover(&pos, &gs).unwrap(); + match got.contents { + HoverContents::Array(arr) => { + let expect: Vec = vec![ + MarkedString::String("base.pkg.kusion_models.kube.frontend".to_string()), + MarkedString::LanguageString(lsp_types::LanguageString { + language: "KCL".to_string(), + value: "schema Server:\n name?: str\n workloadType: \"Deployment\" | \"StatefulSet\" = \"Deployment\"\n renderType?: \"Server\" | \"KubeVelaApplication\" = \"Server\"\n replicas: int = option(\"replicas\") or 1\n image: str = option(\"image\")\n schedulingStrategy: SchedulingStrategy = strategy.SchedulingStrategy {}\n mainContainer: Main\n sidecarContainers?: [Sidecar]\n initContainers?: [Sidecar]\n useBuiltInLabels?: bool = True\n labels?: {str:str}\n annotations?: {str:str}\n useBuiltInSelector?: bool = True\n selector?: {str:str}\n podMetadata?: ObjectMeta\n volumes?: [Volume]\n needNamespace?: bool = True\n enableMonitoring?: bool = False\n configMaps?: [ConfigMap]\n secrets?: [Secret]\n services?: [Service]\n ingresses?: [Ingress]\n serviceAccount?: ServiceAccount\n storage?: ObjectStorage\n database?: DataBase".to_string() + }), + MarkedString::String("Server is abstaction of Deployment and StatefulSet.".to_string()), + ]; + assert_eq!(expect, arr); + } + _ => unreachable!("test error"), + } + + // schema attr def hover + let pos = KCLPos { + filename: main_path_str.clone().adjust_canonicalization(), + line: 7, + column: Some(15), + }; + let got = hover(&pos, &gs).unwrap(); + match got.contents { + HoverContents::Array(arr) => { + let expect: Vec = vec![ + MarkedString::LanguageString(lsp_types::LanguageString { + language: "KCL".to_string(), + value: + "schedulingStrategy: SchedulingStrategy = strategy.SchedulingStrategy {}" + .to_string(), + }), + MarkedString::String( + "SchedulingStrategy represents scheduling strategy.".to_string(), + ), + ]; + assert_eq!(expect, arr); + } + _ => unreachable!("test error"), + } + + // variable hover + let pos = KCLPos { + filename: main_path_str.clone().adjust_canonicalization(), + line: 6, + column: Some(3), + }; + let got = hover(&pos, &gs).unwrap(); + match got.contents { + HoverContents::Scalar(s) => { + assert_eq!( + s, + MarkedString::LanguageString(lsp_types::LanguageString { + language: "KCL".to_string(), + value: "appConfiguration: Server".to_string() + }) + ); + } + _ => unreachable!("test error"), + } +} + +#[test] +fn lsp_version_test() { + let args = vec!["kcl-language-server".to_string(), "version".to_string()]; + let matches = crate::app::app() + .arg_required_else_help(false) + .try_get_matches_from(args); + match matches { + Ok(arg_match) => match arg_match.subcommand() { + Some(("version", _)) => {} + _ => panic!("test failed"), + }, + Err(_) => panic!("test failed"), + } +} + +#[test] +fn lsp_run_test() { + let args = vec!["kcl-language-server".to_string()]; + let matches = crate::app::app() + .arg_required_else_help(false) + .try_get_matches_from(args); + match matches { + Ok(arg_match) => match arg_match.subcommand() { + None => {} + _ => panic!("test failed"), + }, + Err(_) => panic!("test failed"), + } +} + +#[test] +fn lsp_invalid_subcommand_test() { + let args = vec!["kcl-language-server".to_string(), "invalid".to_string()]; + let matches = crate::app::app() + .arg_required_else_help(false) + .try_get_matches_from(args); + match matches { + Ok(_) => panic!("test failed"), + Err(e) => match e.kind() { + clap::error::ErrorKind::InvalidSubcommand => {} + _ => panic!("test failed"), + }, + } +} + +#[test] +fn find_refs_test() { + let root = PathBuf::from(env!("CARGO_MANIFEST_DIR")) + .join("src") + .join("test_data") + .join("find_refs_test"); + let mut path = root.clone(); + path.push("main.k"); + + let path = path.to_str().unwrap(); + let src = std::fs::read_to_string(path).unwrap(); + let initialize_params = InitializeParams { + workspace_folders: Some(vec![WorkspaceFolder { + uri: Url::from_file_path(root.clone()).unwrap(), + name: "test".to_string(), + }]), + ..Default::default() + }; + let server = Project {}.server(initialize_params); + + // Wait for async build word_index_map + wait_async!(); + + let url = Url::from_file_path(path).unwrap(); + + // Mock open file + server.notification::( + lsp_types::DidOpenTextDocumentParams { + text_document: TextDocumentItem { + uri: url.clone(), + language_id: "KCL".to_string(), + version: 0, + text: src, + }, + }, + ); + + let id = server.next_request_id.get(); + server.next_request_id.set(id.wrapping_add(1)); + + let r: Request = Request::new( + id.into(), + "textDocument/references".to_string(), + ReferenceParams { + text_document_position: TextDocumentPositionParams { + text_document: TextDocumentIdentifier { uri: url.clone() }, + position: Position::new(0, 1), + }, + work_done_progress_params: Default::default(), + partial_result_params: Default::default(), + context: ReferenceContext { + include_declaration: true, + }, + }, + ); + + // Send request and wait for it's response + let res = server.send_and_receive(r); + + assert_eq!( + res.result.unwrap(), + to_json(vec![ + Location { + uri: url.clone(), + range: Range { + start: Position::new(0, 0), + end: Position::new(0, 1), + }, + }, + Location { + uri: url.clone(), + range: Range { + start: Position::new(1, 4), + end: Position::new(1, 5), + }, + }, + Location { + uri: url.clone(), + range: Range { + start: Position::new(2, 4), + end: Position::new(2, 5), + }, + }, + Location { + uri: url.clone(), + range: Range { + start: Position::new(12, 14), + end: Position::new(12, 15), + }, + }, + ]) + .unwrap() + ); +} + +#[test] +fn find_refs_with_file_change_test() { + let root = PathBuf::from(env!("CARGO_MANIFEST_DIR")) + .join("src") + .join("test_data") + .join("find_refs_test"); + let mut path = root.clone(); + path.push("main.k"); + + let path = path.to_str().unwrap(); + let src = std::fs::read_to_string(path).unwrap(); + let initialize_params = InitializeParams { + workspace_folders: Some(vec![WorkspaceFolder { + uri: Url::from_file_path(root.clone()).unwrap(), + name: "test".to_string(), + }]), + ..Default::default() + }; + let server = Project {}.server(initialize_params); + + // Wait for async build word_index_map + wait_async!(); + + let url = Url::from_file_path(path).unwrap(); + + // Mock open file + server.notification::( + lsp_types::DidOpenTextDocumentParams { + text_document: TextDocumentItem { + uri: url.clone(), + language_id: "KCL".to_string(), + version: 0, + text: src, + }, + }, + ); + + // Mock change file content + server.notification::( + lsp_types::DidChangeTextDocumentParams { + text_document: lsp_types::VersionedTextDocumentIdentifier { + uri: url.clone(), + version: 1, + }, + content_changes: vec![lsp_types::TextDocumentContentChangeEvent { + range: None, + range_length: None, + text: r#"a = "demo" + +schema Name: + name: str + +schema Person: + n: Name + +p2 = Person { + n: Name{ + name: a + } +}"# + .to_string(), + }], + }, + ); + + let id = server.next_request_id.get(); + server.next_request_id.set(id.wrapping_add(1)); + // Mock trigger find references + let r: Request = Request::new( + id.into(), + "textDocument/references".to_string(), + ReferenceParams { + text_document_position: TextDocumentPositionParams { + text_document: TextDocumentIdentifier { uri: url.clone() }, + position: Position::new(0, 1), + }, + work_done_progress_params: Default::default(), + partial_result_params: Default::default(), + context: ReferenceContext { + include_declaration: true, + }, + }, + ); + + // Send request and wait for it's response + let res = server.send_and_receive(r); + assert_eq!( + res.result.unwrap(), + to_json(vec![ + Location { + uri: url.clone(), + range: Range { + start: Position::new(0, 0), + end: Position::new(0, 1), + }, + }, + Location { + uri: url.clone(), + range: Range { + start: Position::new(10, 14), + end: Position::new(10, 15), + }, + }, + ]) + .unwrap() + ); +} + +#[test] +fn rename_test() { + let root = PathBuf::from(env!("CARGO_MANIFEST_DIR")) + .join("src") + .join("test_data") + .join("rename_test"); + let path = root.clone(); + let main_path = root.clone(); + let path = path.join("pkg").join("vars.k"); + let main_path = main_path.join("main.k"); + + let path = path.to_str().unwrap(); + let src = std::fs::read_to_string(path).unwrap(); + let initialize_params = InitializeParams { + workspace_folders: Some(vec![WorkspaceFolder { + uri: Url::from_file_path(root.clone()).unwrap(), + name: "test".to_string(), + }]), + ..Default::default() + }; + let server = Project {}.server(initialize_params); + + wait_async!(); + + let url = Url::from_file_path(path).unwrap(); + let main_url = Url::from_file_path(main_path).unwrap(); + + // Mock open file + server.notification::( + lsp_types::DidOpenTextDocumentParams { + text_document: TextDocumentItem { + uri: url.clone(), + language_id: "KCL".to_string(), + version: 0, + text: src, + }, + }, + ); + + let id = server.next_request_id.get(); + server.next_request_id.set(id.wrapping_add(1)); + + let new_name = String::from("Person2"); + let r: Request = Request::new( + id.into(), + "textDocument/rename".to_string(), + RenameParams { + text_document_position: TextDocumentPositionParams { + text_document: TextDocumentIdentifier { uri: url.clone() }, + position: Position::new(0, 7), + }, + new_name: new_name.clone(), + work_done_progress_params: Default::default(), + }, + ); + + // Send request and wait for it's response + let res = server.send_and_receive(r); + let expect = WorkspaceEdit { + changes: Some(HashMap::from_iter(vec![ + ( + url.clone(), + vec![ + TextEdit { + range: Range { + start: Position::new(0, 7), + end: Position::new(0, 13), + }, + new_text: new_name.clone(), + }, + TextEdit { + range: Range { + start: Position::new(4, 7), + end: Position::new(4, 13), + }, + new_text: new_name.clone(), + }, + TextEdit { + range: Range { + start: Position::new(9, 8), + end: Position::new(9, 14), + }, + new_text: new_name.clone(), + }, + ], + ), + ( + main_url.clone(), + vec![TextEdit { + range: Range { + start: Position::new(2, 11), + end: Position::new(2, 17), + }, + new_text: new_name.clone(), + }], + ), + ])), + ..Default::default() + }; + assert_eq!(res.result.unwrap(), to_json(expect).unwrap()); +} + +#[test] +fn kcl_workspace_init_kclwork_test() { + let tool: crate::state::KCLToolChain = Arc::new(RwLock::new(toolchain::default())); + let tool = Arc::clone(&tool); + + let root = PathBuf::from(env!("CARGO_MANIFEST_DIR")) + .join("src") + .join("test_data") + .join("workspace") + .join("init"); + + let mut work = root.clone(); + work.push("work"); + + let (workspaces, failed) = + kclvm_driver::lookup_compile_workspaces(&*tool.read(), work.to_str().unwrap(), true); + + let mut expected = HashSet::new(); + + expected.insert(WorkSpaceKind::Folder( + PathBuf::from(env!("CARGO_MANIFEST_DIR")) + .join("src") + .join("test_data") + .join("workspace") + .join("init") + .join("work") + .join("a"), + )); + + expected.insert(WorkSpaceKind::Folder( + PathBuf::from(env!("CARGO_MANIFEST_DIR")) + .join("src") + .join("test_data") + .join("workspace") + .join("init") + .join("work") + .join("b"), + )); + + expected.insert(WorkSpaceKind::File( + PathBuf::from(env!("CARGO_MANIFEST_DIR")) + .join("src") + .join("test_data") + .join("workspace") + .join("init") + .join("work") + .join("c.k"), + )); + + assert_eq!(expected, workspaces.keys().cloned().collect()); + + assert!(failed.is_some()); + assert!(failed.unwrap().is_empty()); +} + +#[test] +fn kcl_workspace_init_kclmod_test() { + let tool: crate::state::KCLToolChain = Arc::new(RwLock::new(toolchain::default())); + let tool = Arc::clone(&tool); + + let root = PathBuf::from(env!("CARGO_MANIFEST_DIR")) + .join("src") + .join("test_data") + .join("workspace") + .join("init"); + + let mut work = root.clone(); + work.push("mod"); + + let mut main = work.clone(); + main.push("main.k"); + + let (workspaces, failed) = + kclvm_driver::lookup_compile_workspaces(&*tool.read(), work.to_str().unwrap(), true); + + let mut expected = HashSet::new(); + + expected.insert(WorkSpaceKind::ModFile( + PathBuf::from(env!("CARGO_MANIFEST_DIR")) + .join("src") + .join("test_data") + .join("workspace") + .join("init") + .join("mod") + .join("kcl.mod"), + )); + + assert_eq!(expected, workspaces.keys().cloned().collect()); + assert_eq!( + vec![main.to_str().unwrap().to_string()], + workspaces.values().next().unwrap().0 + ); + assert!(failed.is_none()); +} + +#[test] +fn kcl_workspace_init_settings_file_test() { + let tool: crate::state::KCLToolChain = Arc::new(RwLock::new(toolchain::default())); + let tool = Arc::clone(&tool); + + let root = PathBuf::from(env!("CARGO_MANIFEST_DIR")) + .join("src") + .join("test_data") + .join("workspace") + .join("init"); + + let mut work = root.clone(); + work.push("setting"); + + let mut a = work.clone(); + a.push("a.k"); + + let (workspaces, failed) = + kclvm_driver::lookup_compile_workspaces(&*tool.read(), work.to_str().unwrap(), true); + + let mut expected = HashSet::new(); + + expected.insert(WorkSpaceKind::SettingFile( + PathBuf::from(env!("CARGO_MANIFEST_DIR")) + .join("src") + .join("test_data") + .join("workspace") + .join("init") + .join("setting") + .join("kcl.yaml"), + )); + + assert_eq!(expected, workspaces.keys().cloned().collect()); + assert!(failed.is_none()); + assert_eq!( + vec![a.file_name().unwrap().to_str().unwrap().to_string()], + workspaces.values().next().unwrap().0 + ); +} + +#[test] +fn kcl_workspace_init_folder_test() { + let tool: crate::state::KCLToolChain = Arc::new(RwLock::new(toolchain::default())); + let tool = Arc::clone(&tool); + + let root = PathBuf::from(env!("CARGO_MANIFEST_DIR")) + .join("src") + .join("test_data") + .join("workspace") + .join("init"); + + let mut work = root.clone(); + work.push("folder"); + + let (workspaces, failed) = + kclvm_driver::lookup_compile_workspaces(&*tool.read(), work.to_str().unwrap(), true); + + let mut expected = HashSet::new(); + + expected.insert(WorkSpaceKind::Folder( + PathBuf::from(env!("CARGO_MANIFEST_DIR")) + .join("src") + .join("test_data") + .join("workspace") + .join("init") + .join("folder"), + )); + + assert_eq!(expected, workspaces.keys().cloned().collect()); + + assert!(failed.is_none()); +} + +#[test] +fn init_workspace_sema_token_test() { + let root = PathBuf::from(env!("CARGO_MANIFEST_DIR")) + .join("src") + .join("test_data") + .join("workspace") + .join("init") + .join("folder"); + + let mut a_path = root.clone(); + a_path.push("a.k"); + + let mut c_path = root.clone(); + c_path.push("sub"); + c_path.push("c.k"); + + let a_path = a_path.to_str().unwrap(); + let c_path = c_path.to_str().unwrap(); + let a_src = std::fs::read_to_string(a_path).unwrap(); + let c_src = std::fs::read_to_string(c_path).unwrap(); + let initialize_params = InitializeParams { + workspace_folders: Some(vec![WorkspaceFolder { + uri: Url::from_file_path(root.clone()).unwrap(), + name: "test".to_string(), + }]), + ..Default::default() + }; + let server = Project {}.server(initialize_params); + + let a_url = Url::from_file_path(a_path).unwrap(); + let c_url = Url::from_file_path(c_path).unwrap(); + + // Mock open file in init workspace + server.notification::( + lsp_types::DidOpenTextDocumentParams { + text_document: TextDocumentItem { + uri: a_url.clone(), + language_id: "KCL".to_string(), + version: 0, + text: a_src, + }, + }, + ); + + let id = server.next_request_id.get(); + server.next_request_id.set(id.wrapping_add(1)); + + let r: Request = Request::new( + id.into(), + "textDocument/semanticTokens/full".to_string(), + SemanticTokensParams { + text_document: TextDocumentIdentifier { uri: a_url }, + work_done_progress_params: WorkDoneProgressParams { + work_done_token: None, + }, + partial_result_params: PartialResultParams { + partial_result_token: None, + }, + }, + ); + + let res = server.send_and_receive(r); + assert!(res.result.is_some()); + + // Mock open file not in init workspace + server.notification::( + lsp_types::DidOpenTextDocumentParams { + text_document: TextDocumentItem { + uri: c_url.clone(), + language_id: "KCL".to_string(), + version: 0, + text: c_src, + }, + }, + ); + + let id = server.next_request_id.get(); + server.next_request_id.set(id.wrapping_add(1)); + + let r: Request = Request::new( + id.into(), + "textDocument/semanticTokens/full".to_string(), + SemanticTokensParams { + text_document: TextDocumentIdentifier { uri: c_url }, + work_done_progress_params: WorkDoneProgressParams { + work_done_token: None, + }, + partial_result_params: PartialResultParams { + partial_result_token: None, + }, + }, + ); + + let res = server.send_and_receive(r); + assert!(res.result.is_some()); +} + +#[test] +fn pkg_mod_test() { + let (_file, _program, diags, _gs, _) = + compile_test_file("src/test_data/workspace/pkg_mod_test/test/main.k"); + assert_eq!(diags.iter().filter(|diag| diag.is_error()).count(), 0); +} + +#[test] +fn aug_assign_without_define() { + let (_file, _program, diags, _gs, _) = + compile_test_file("src/test_data/error_code/aug_assign/aug_assign.k"); + assert_eq!(diags.len(), 1); +} diff --git a/kclvm/tools/src/LSP/src/to_lsp.rs b/kclvm/tools/src/LSP/src/to_lsp.rs new file mode 100644 index 000000000..b95615f77 --- /dev/null +++ b/kclvm/tools/src/LSP/src/to_lsp.rs @@ -0,0 +1,221 @@ +use im_rc::HashMap; +use kclvm_error::Diagnostic as KCLDiagnostic; +use kclvm_error::DiagnosticId; +use kclvm_error::Level; +use kclvm_error::Message; +use kclvm_error::Position as KCLPos; +use kclvm_utils::path::PathPrefix; +use lsp_types::*; +use serde_json::json; + +use std::{ + path::{Component, Path, Prefix}, + str::FromStr, +}; + +/// Convert pos format to lsp position. +/// The position in lsp protocol is different with position in ast node whose line number is 1 based. +pub fn lsp_pos(pos: &KCLPos) -> Position { + Position { + line: pos.line.checked_sub(1).unwrap_or(0) as u32, + character: pos.column.unwrap_or(0) as u32, + } +} + +/// Convert start and pos format to lsp location. +/// The position of the location in lsp protocol is different with position in ast node whose line number is 1 based. +pub fn lsp_location(file_path: String, start: &KCLPos, end: &KCLPos) -> Option { + let uri = Url::from_file_path(file_path).ok()?; + Some(Location { + uri, + range: Range { + start: lsp_pos(start), + end: lsp_pos(end), + }, + }) +} + +/// Convert KCL message to the LSP diagnostic. +pub fn kcl_msg_to_lsp_diags( + msg: &Message, + severity: DiagnosticSeverity, + related_msg: Vec, + code: Option, +) -> Diagnostic { + let range = msg.range.clone(); + let start_position = lsp_pos(&range.0); + let end_position = lsp_pos(&range.1); + + let data = msg + .suggested_replacement + .as_ref() + .map(|s_vec| { + s_vec + .iter() + .filter(|s| !s.is_empty()) + .collect::>() + }) + .map(|s| { + if s.is_empty() { + json!({ "suggested_replacement": "" }) + } else { + json!({ "suggested_replacement": s }) + } + }); + + let related_information = if related_msg.is_empty() { + None + } else { + Some( + related_msg + .iter() + .filter_map(|m| match Url::from_file_path(m.range.0.filename.clone()) { + Ok(uri) => Some(DiagnosticRelatedInformation { + location: Location { + uri, + range: Range { + start: lsp_pos(&m.range.0), + end: lsp_pos(&m.range.1), + }, + }, + message: m.message.clone(), + }), + Err(_) => None, + }) + .collect(), + ) + }; + + Diagnostic { + range: Range::new(start_position, end_position), + severity: Some(severity), + code, + code_description: None, + source: None, + message: msg.message.clone(), + related_information, + tags: None, + data, + } +} + +/// Convert KCL error level to the LSP diagnostic severity. +pub fn kcl_err_level_to_severity(level: Level) -> DiagnosticSeverity { + match level { + Level::Error => DiagnosticSeverity::ERROR, + Level::Warning => DiagnosticSeverity::WARNING, + Level::Note => DiagnosticSeverity::HINT, + Level::Suggestions => DiagnosticSeverity::HINT, + } +} + +/// Convert KCL Diagnostic to LSP Diagnostics. +pub fn kcl_diag_to_lsp_diags(diag: &KCLDiagnostic) -> HashMap> { + let mut diags_map: HashMap> = HashMap::new(); + + for (idx, msg) in diag.messages.iter().enumerate() { + let filename = msg.range.0.filename.clone(); + + let mut related_msg = diag.messages.clone(); + related_msg.remove(idx); + let code = if diag.code.is_some() { + Some(kcl_diag_id_to_lsp_diag_code(diag.code.clone().unwrap())) + } else { + None + }; + + let lsp_diag = kcl_msg_to_lsp_diags( + msg, + kcl_err_level_to_severity(diag.level), + related_msg, + code, + ); + + diags_map.entry(filename).or_insert(vec![]).push(lsp_diag); + } + diags_map +} + +/// Convert KCL Diagnostic to LSP Diagnostics. +#[allow(unused)] +pub(crate) fn kcl_diag_to_lsp_diags_by_file( + diag: &KCLDiagnostic, + file_name: &str, +) -> Vec { + let mut diags = vec![]; + for (idx, msg) in diag.messages.iter().enumerate() { + if msg.range.0.filename.adjust_canonicalization() == file_name.adjust_canonicalization() { + let mut related_msg = diag.messages.clone(); + related_msg.remove(idx); + let code = if diag.code.is_some() { + Some(kcl_diag_id_to_lsp_diag_code(diag.code.clone().unwrap())) + } else { + None + }; + + let lsp_diag = kcl_msg_to_lsp_diags( + msg, + kcl_err_level_to_severity(diag.level), + related_msg, + code, + ); + + diags.push(lsp_diag); + } + } + diags +} + +/// Convert KCL Diagnostic ID to LSP Diagnostics code. +/// Todo: use unique id/code instead of name() +pub(crate) fn kcl_diag_id_to_lsp_diag_code(id: DiagnosticId) -> NumberOrString { + match id { + DiagnosticId::Error(err) => NumberOrString::String(err.name()), + DiagnosticId::Warning(warn) => NumberOrString::String(warn.name()), + DiagnosticId::Suggestions => NumberOrString::String("suggestion".to_string()), + } +} + +pub(crate) fn url_from_path(path: impl AsRef) -> anyhow::Result { + url_from_path_with_drive_lowercasing(path) +} + +/// Returns a `Url` object from a given path, will lowercase drive letters if present. +/// This will only happen when processing Windows paths. +/// +/// When processing non-windows path, this is essentially do the same as `Url::from_file_path`. +pub(crate) fn url_from_path_with_drive_lowercasing(path: impl AsRef) -> anyhow::Result { + let component_has_windows_drive = path.as_ref().components().any(|comp| { + if let Component::Prefix(c) = comp { + match c.kind() { + Prefix::Disk(_) | Prefix::VerbatimDisk(_) => return true, + _ => return false, + } + } + false + }); + + // VSCode expects drive letters to be lowercased, whereas rust will uppercase the drive letters. + if component_has_windows_drive { + let url_original = Url::from_file_path(&path).map_err(|_| { + anyhow::anyhow!("can't convert path to url: {}", path.as_ref().display()) + })?; + + let drive_partition: Vec<&str> = url_original.as_str().rsplitn(2, ':').collect(); + + // There is a drive partition, but we never found a colon. + // This should not happen, but in this case we just pass it through. + if drive_partition.len() == 1 { + return Ok(url_original); + } + + let joined = drive_partition[1].to_ascii_lowercase() + ":" + drive_partition[0]; + let url = Url::from_str(&joined) + .map_err(|e| anyhow::anyhow!("Url from str ParseError: {}", e))?; + Ok(url) + } else { + Ok(Url::from_file_path(&path).map_err(|_| { + anyhow::anyhow!("can't convert path to url: {}", path.as_ref().display()) + })?) + } +} diff --git a/kclvm/tools/src/LSP/src/util.rs b/kclvm/tools/src/LSP/src/util.rs new file mode 100644 index 000000000..42d092a1a --- /dev/null +++ b/kclvm/tools/src/LSP/src/util.rs @@ -0,0 +1,667 @@ +use kclvm_ast::ast::{ + ConfigEntry, Expr, Identifier, MemberOrIndex, Node, NodeRef, PosTuple, Program, SchemaStmt, + Stmt, Type, +}; +use kclvm_ast::node_ref; +use kclvm_ast::pos::ContainsPos; + +use kclvm_error::Position as KCLPos; +use kclvm_parser::entry::get_dir_files; + +use crate::from_lsp; +use crate::state::KCLVfs; +use lsp_types::Url; +use parking_lot::RwLockReadGuard; +use ra_ap_vfs::{FileId, Vfs}; +use serde::{de::DeserializeOwned, Serialize}; + +use std::fs; +use std::path::{Path, PathBuf}; + +/// Deserializes a `T` from a json value. +pub(crate) fn from_json( + what: &'static str, + json: serde_json::Value, +) -> anyhow::Result { + T::deserialize(&json) + .map_err(|e| anyhow::anyhow!("could not deserialize {}: {}: {}", what, e, json)) +} + +/// Converts the `T` to a json value +pub(crate) fn to_json(value: T) -> anyhow::Result { + serde_json::to_value(value).map_err(|e| anyhow::anyhow!("could not serialize to json: {}", e)) +} + +/// Get the filename from the given VFS using the file id. +pub(crate) fn get_file_name(vfs: RwLockReadGuard, file_id: FileId) -> anyhow::Result { + if let Some(path) = vfs.file_path(file_id).as_path() { + Ok(path + .as_ref() + .to_str() + .ok_or(anyhow::anyhow!("Failed to get file file"))? + .to_string()) + } else { + Err(anyhow::anyhow!( + "{} isn't on the file system.", + vfs.file_path(file_id) + )) + } +} + +/// Update text with TextDocumentContentChangeEvent param +pub(crate) fn apply_document_changes( + old_text: &mut String, + content_changes: Vec, +) { + for change in content_changes { + match change.range { + Some(range) => { + let range = from_lsp::text_range(old_text, range); + old_text.replace_range(range, &change.text); + } + None => { + *old_text = change.text; + } + } + } +} + +pub(crate) fn load_files_code_from_vfs( + files: &[&str], + vfs: &KCLVfs, +) -> anyhow::Result> { + let mut res = vec![]; + let vfs = &mut vfs.read(); + for file in files { + let url = Url::from_file_path(file) + .map_err(|_| anyhow::anyhow!("can't convert file to url: {}", file))?; + let path = from_lsp::abs_path(&url)?; + match vfs.file_id(&path.clone().into()) { + Some(id) => { + // Load code from vfs if exist + res.push(String::from_utf8(vfs.file_contents(id).to_vec()).unwrap()); + } + None => { + // In order to ensure that k_file corresponds to k_code, load the code from the file system if not exist + let p: &Path = path.as_ref(); + if p.is_file() { + res.push( + fs::read_to_string(path) + .map_err(|_| anyhow::anyhow!("can't convert file to url: {}", file))?, + ); + } else if p.is_dir() { + let k_files = get_dir_files(p.to_str().unwrap(), false) + .map_err(|_| anyhow::anyhow!("can't get dir files: {} ", file))?; + for k_file in k_files { + let k_file_path = Path::new(k_file.as_str()); + res.push( + fs::read_to_string(k_file_path).map_err(|_| { + anyhow::anyhow!("can't convert file to url: {}", file) + })?, + ); + } + } + } + } + } + Ok(res) +} + +pub(crate) fn filter_kcl_config_file(paths: &[PathBuf]) -> Vec { + paths + .iter() + .filter(|p| { + p.file_name().map(|n| n.to_str().unwrap()) == Some(kclvm_config::modfile::KCL_MOD_FILE) + || p.file_name().map(|n| n.to_str().unwrap()) + == Some(kclvm_config::settings::DEFAULT_SETTING_FILE) + }) + .map(|p| p.clone()) + .collect() +} + +macro_rules! walk_if_contains { + ($expr: expr, $pos: expr, $schema_def: expr) => { + if $expr.contains_pos($pos) { + return inner_most_expr(&$expr, &$pos, $schema_def); + } + }; +} + +macro_rules! walk_if_contains_with_new_expr { + ($expr: expr, $pos: expr, $schema_def: expr, $kind: expr) => { + if $expr.contains_pos($pos) { + walk_if_contains!( + Node::node_with_pos( + $kind($expr.node.clone()), + ( + $expr.filename.clone(), + $expr.line, + $expr.column, + $expr.end_line, + $expr.end_column, + ), + ), + $pos, + $schema_def + ); + } + }; +} + +macro_rules! walk_option_if_contains { + ($opt: expr, $pos: expr, $schema_def: expr) => { + if let Some(expr) = &$opt { + walk_if_contains!(expr, $pos, $schema_def) + } + }; +} + +macro_rules! walk_list_if_contains { + ($list: expr, $pos: expr, $schema_def: expr) => { + for elem in &$list { + walk_if_contains!(elem, $pos, $schema_def) + } + }; +} + +fn transfer_ident_names(names: Vec, pos: &PosTuple) -> Vec> { + let mut new_names = vec![]; + let mut col = pos.2; + for name in &names { + let mut name_pos = pos.clone(); + name_pos.2 = col; + name_pos.4 = col + name.len() as u64; + new_names.push(Node::node_with_pos(name.clone(), name_pos)); + col = col + name.len() as u64 + ".".len() as u64; + } + new_names +} + +/// Recursively finds the inner most expr and its schema_def expr if in a schema expr(e.g., schema_attr and schema_expr) +/// in a stmt according to the position. +pub(crate) fn inner_most_expr_in_stmt( + stmt: &Stmt, + pos: &KCLPos, + schema_def: Option>, +) -> (Option>, Option>) { + match stmt { + Stmt::Assign(assign_stmt) => { + if let Some(ty) = &assign_stmt.ty { + if ty.contains_pos(pos) { + return (build_identifier_from_ty_string(ty, pos), schema_def); + } + } + walk_if_contains!(assign_stmt.value, pos, schema_def); + + for expr in &assign_stmt.targets { + walk_if_contains_with_new_expr!(expr, pos, schema_def, Expr::Target); + } + (None, schema_def) + } + Stmt::TypeAlias(type_alias_stmt) => { + walk_if_contains_with_new_expr!( + type_alias_stmt.type_name, + pos, + schema_def, + Expr::Identifier + ); + (None, schema_def) + } + Stmt::Expr(expr_stmt) => { + walk_list_if_contains!(expr_stmt.exprs, pos, schema_def); + (None, schema_def) + } + Stmt::Unification(unification_stmt) => { + walk_if_contains_with_new_expr!( + unification_stmt.target, + pos, + schema_def, + Expr::Identifier + ); + + walk_if_contains_with_new_expr!(unification_stmt.value, pos, schema_def, Expr::Schema); + + (None, schema_def) + } + Stmt::AugAssign(aug_assign_stmt) => { + walk_if_contains!(aug_assign_stmt.value, pos, schema_def); + walk_if_contains_with_new_expr!(aug_assign_stmt.target, pos, schema_def, Expr::Target); + (None, schema_def) + } + Stmt::Assert(assert_stmt) => { + walk_if_contains!(assert_stmt.test, pos, schema_def); + walk_option_if_contains!(assert_stmt.if_cond, pos, schema_def); + walk_option_if_contains!(assert_stmt.msg, pos, schema_def); + (None, schema_def) + } + Stmt::If(if_stmt) => { + walk_if_contains!(if_stmt.cond, pos, schema_def); + for stmt in &if_stmt.body { + if stmt.contains_pos(pos) { + return inner_most_expr_in_stmt(&stmt.node, pos, schema_def); + } + } + for stmt in &if_stmt.orelse { + if stmt.contains_pos(pos) { + return inner_most_expr_in_stmt(&stmt.node, pos, schema_def); + } + } + (None, schema_def) + } + Stmt::Schema(schema_stmt) => { + walk_if_contains!( + Node::node_with_pos( + Expr::Identifier(Identifier { + names: transfer_ident_names( + vec![schema_stmt.name.node.clone()], + &( + schema_stmt.name.filename.clone(), + schema_stmt.name.line, + schema_stmt.name.column, + schema_stmt.name.end_line, + schema_stmt.name.end_column, + ), + ), + pkgpath: "".to_string(), + ctx: kclvm_ast::ast::ExprContext::Load, + }), + ( + schema_stmt.name.filename.clone(), + schema_stmt.name.line, + schema_stmt.name.column, + schema_stmt.name.end_line, + schema_stmt.name.end_column, + ), + ), + pos, + schema_def + ); + if let Some(parent_id) = &schema_stmt.parent_name { + walk_if_contains_with_new_expr!(parent_id, pos, schema_def, Expr::Identifier); + } + if let Some(host) = &schema_stmt.for_host_name { + walk_if_contains_with_new_expr!(host, pos, schema_def, Expr::Identifier); + } + for mixin in &schema_stmt.mixins { + walk_if_contains_with_new_expr!(mixin, pos, schema_def, Expr::Identifier); + } + for stmt in &schema_stmt.body { + if stmt.contains_pos(pos) { + return inner_most_expr_in_stmt(&stmt.node, pos, schema_def); + } + } + for decorator in &schema_stmt.decorators { + walk_if_contains_with_new_expr!(decorator, pos, schema_def, Expr::Call); + } + for check in &schema_stmt.checks { + walk_if_contains_with_new_expr!(check, pos, schema_def, Expr::Check); + } + (None, schema_def) + } + Stmt::SchemaAttr(schema_attr_expr) => { + walk_if_contains!( + Node::node_with_pos( + Expr::Identifier(Identifier { + names: vec![*schema_attr_expr.name.clone()], + pkgpath: "".to_string(), + ctx: kclvm_ast::ast::ExprContext::Load, + }), + ( + schema_attr_expr.name.filename.clone(), + schema_attr_expr.name.line, + schema_attr_expr.name.column, + schema_attr_expr.name.end_line, + schema_attr_expr.name.end_column, + ), + ), + pos, + schema_def + ); + if schema_attr_expr.ty.contains_pos(pos) { + return ( + build_identifier_from_ty_string(&schema_attr_expr.ty, pos), + schema_def, + ); + } + walk_option_if_contains!(schema_attr_expr.value, pos, schema_def); + for decorator in &schema_attr_expr.decorators { + walk_if_contains_with_new_expr!(decorator, pos, schema_def, Expr::Call); + } + (None, schema_def) + } + Stmt::Rule(rule_stmt) => { + for parent_id in &rule_stmt.parent_rules { + walk_if_contains_with_new_expr!(parent_id, pos, schema_def, Expr::Identifier); + } + for decorator in &rule_stmt.decorators { + walk_if_contains_with_new_expr!(decorator, pos, schema_def, Expr::Call); + } + for check in &rule_stmt.checks { + walk_if_contains_with_new_expr!(check, pos, schema_def, Expr::Check); + } + (None, schema_def) + } + Stmt::Import(_) => (None, schema_def), + } +} + +/// Recursively finds the inner most expr and its schema_def expr if in a schema expr(e.g., schema_attr in schema_expr) +/// in a expr according to the position. +pub(crate) fn inner_most_expr( + expr: &Node, + pos: &KCLPos, + schema_def: Option>, +) -> (Option>, Option>) { + if !expr.contains_pos(pos) { + return (None, None); + } + match &expr.node { + Expr::Identifier(_) => (Some(expr.clone()), schema_def), + Expr::Target(target) => { + for path in &target.paths { + if let MemberOrIndex::Index(index) = path { + if index.contains_pos(pos) { + return (Some(*index.clone()), schema_def); + } + } + } + (Some(expr.clone()), schema_def) + } + Expr::Selector(select_expr) => { + walk_if_contains!(select_expr.value, pos, schema_def); + (Some(expr.clone()), schema_def) + } + Expr::Schema(schema_expr) => { + walk_if_contains_with_new_expr!(schema_expr.name, pos, schema_def, Expr::Identifier); + walk_list_if_contains!(schema_expr.args, pos, schema_def); + + for kwargs in &schema_expr.kwargs { + walk_if_contains_with_new_expr!(kwargs, pos, schema_def, Expr::Keyword); + } + if schema_expr.config.contains_pos(pos) { + return inner_most_expr(&schema_expr.config, pos, Some(expr.clone())); + } + (Some(expr.clone()), schema_def) + } + Expr::Config(config_expr) => { + for item in &config_expr.items { + if item.contains_pos(pos) { + return inner_most_expr_in_config_entry(item, pos, schema_def); + } + } + (Some(expr.clone()), schema_def) + } + Expr::Unary(unary_expr) => { + walk_if_contains!(unary_expr.operand, pos, schema_def); + (Some(expr.clone()), schema_def) + } + Expr::Binary(binary_expr) => { + walk_if_contains!(binary_expr.left, pos, schema_def); + walk_if_contains!(binary_expr.right, pos, schema_def); + (Some(expr.clone()), schema_def) + } + Expr::If(if_expr) => { + walk_if_contains!(if_expr.body, pos, schema_def); + walk_if_contains!(if_expr.cond, pos, schema_def); + walk_if_contains!(if_expr.orelse, pos, schema_def); + (Some(expr.clone()), schema_def) + } + Expr::Call(call_expr) => { + walk_list_if_contains!(call_expr.args, pos, schema_def); + for keyword in &call_expr.keywords { + walk_if_contains_with_new_expr!(keyword, pos, schema_def, Expr::Keyword); + } + walk_if_contains!(call_expr.func, pos, schema_def); + (Some(expr.clone()), schema_def) + } + Expr::Paren(paren_expr) => { + walk_if_contains!(paren_expr.expr, pos, schema_def); + (Some(expr.clone()), schema_def) + } + Expr::Quant(quant_expr) => { + walk_if_contains!(quant_expr.target, pos, schema_def); + for var in &quant_expr.variables { + walk_if_contains_with_new_expr!(var, pos, schema_def, Expr::Identifier); + } + walk_if_contains!(quant_expr.test, pos, schema_def); + walk_option_if_contains!(quant_expr.if_cond, pos, schema_def); + (Some(expr.clone()), schema_def) + } + Expr::List(list_expr) => { + walk_list_if_contains!(list_expr.elts, pos, schema_def); + (Some(expr.clone()), schema_def) + } + Expr::ListIfItem(list_if_item_expr) => { + walk_if_contains!(list_if_item_expr.if_cond, pos, schema_def); + walk_list_if_contains!(list_if_item_expr.exprs, pos, schema_def); + walk_option_if_contains!(list_if_item_expr.orelse, pos, schema_def); + (Some(expr.clone()), schema_def) + } + Expr::ListComp(list_comp_expr) => { + walk_if_contains!(list_comp_expr.elt, pos, schema_def); + for comp_clause in &list_comp_expr.generators { + walk_if_contains_with_new_expr!(comp_clause, pos, schema_def, Expr::CompClause); + } + (Some(expr.clone()), schema_def) + } + Expr::Starred(starred_exor) => { + walk_if_contains!(starred_exor.value, pos, schema_def); + (Some(expr.clone()), schema_def) + } + Expr::DictComp(dict_comp) => { + walk_option_if_contains!(dict_comp.entry.key, pos, schema_def); + walk_if_contains!(dict_comp.entry.value, pos, schema_def); + + for generator in &dict_comp.generators { + if generator.contains_pos(pos) { + walk_if_contains_with_new_expr!(generator, pos, schema_def, Expr::CompClause); + } + } + (Some(expr.clone()), schema_def) + } + Expr::ConfigIfEntry(config_if_entry_expr) => { + walk_if_contains!(config_if_entry_expr.if_cond, pos, schema_def); + for item in &config_if_entry_expr.items { + if item.contains_pos(pos) { + return inner_most_expr_in_config_entry(item, pos, schema_def); + } + } + walk_option_if_contains!(config_if_entry_expr.orelse, pos, schema_def); + (Some(expr.clone()), schema_def) + } + Expr::CompClause(comp_clause) => { + for target in &comp_clause.targets { + walk_if_contains_with_new_expr!(target, pos, schema_def, Expr::Identifier); + } + walk_if_contains!(comp_clause.iter, pos, schema_def); + walk_list_if_contains!(comp_clause.ifs, pos, schema_def); + (Some(expr.clone()), schema_def) + } + Expr::Check(check_expr) => { + walk_if_contains!(check_expr.test, pos, schema_def); + walk_option_if_contains!(check_expr.if_cond, pos, schema_def); + walk_option_if_contains!(check_expr.msg, pos, schema_def); + (Some(expr.clone()), schema_def) + } + Expr::Lambda(lambda_expr) => { + if let Some(args) = &lambda_expr.args { + walk_if_contains_with_new_expr!(args, pos, schema_def, Expr::Arguments); + } + for stmt in &lambda_expr.body { + if stmt.contains_pos(pos) { + return inner_most_expr_in_stmt(&stmt.node, pos, schema_def); + } + } + + (Some(expr.clone()), schema_def) + } + Expr::Subscript(subscript_expr) => { + walk_if_contains!(subscript_expr.value, pos, schema_def); + walk_option_if_contains!(subscript_expr.index, pos, schema_def); + walk_option_if_contains!(subscript_expr.lower, pos, schema_def); + walk_option_if_contains!(subscript_expr.upper, pos, schema_def); + walk_option_if_contains!(subscript_expr.step, pos, schema_def); + (Some(expr.clone()), schema_def) + } + Expr::Keyword(keyword) => { + walk_if_contains_with_new_expr!(keyword.arg, pos, schema_def, Expr::Identifier); + walk_option_if_contains!(keyword.value, pos, schema_def); + (Some(expr.clone()), schema_def) + } + Expr::Arguments(argument) => { + for arg in &argument.args { + walk_if_contains_with_new_expr!(arg, pos, schema_def, Expr::Identifier); + } + for default in &argument.defaults { + walk_option_if_contains!(default, pos, schema_def); + } + for ty in argument.ty_list.iter().flatten() { + if ty.contains_pos(pos) { + return ( + Some(build_identifier_from_string(&node_ref!( + ty.node.to_string(), + ty.pos() + ))), + schema_def, + ); + } + } + (Some(expr.clone()), schema_def) + } + Expr::Compare(compare_expr) => { + walk_if_contains!(compare_expr.left, pos, schema_def); + walk_list_if_contains!(compare_expr.comparators, pos, schema_def); + (Some(expr.clone()), schema_def) + } + Expr::NumberLit(_) => (Some(expr.clone()), schema_def), + Expr::StringLit(_) => (Some(expr.clone()), schema_def), + Expr::NameConstantLit(_) => (Some(expr.clone()), schema_def), + Expr::JoinedString(joined_string) => { + walk_list_if_contains!(joined_string.values, pos, schema_def); + (Some(expr.clone()), schema_def) + } + Expr::FormattedValue(formatted_value) => { + walk_if_contains!(formatted_value.value, pos, schema_def); + (Some(expr.clone()), schema_def) + } + Expr::Missing(_) => (Some(expr.clone()), schema_def), + } +} + +fn inner_most_expr_in_config_entry( + config_entry: &Node, + pos: &KCLPos, + schema_def: Option>, +) -> (Option>, Option>) { + if let Some(key) = &config_entry.node.key { + if key.contains_pos(pos) { + return inner_most_expr(key, pos, schema_def); + } + } + if config_entry.node.value.contains_pos(pos) { + inner_most_expr(&config_entry.node.value, pos, None) + } else { + (None, schema_def) + } +} + +pub(crate) fn is_in_docstring( + program: &Program, + pos: &KCLPos, +) -> Option<(NodeRef, SchemaStmt)> { + match program.pos_to_stmt(pos) { + Some(node) => match node.node.clone() { + Stmt::Schema(schema) => match schema.doc { + Some(ref doc) => { + if doc.contains_pos(pos) { + Some((doc.clone(), schema)) + } else { + None + } + } + None => None, + }, + _ => None, + }, + None => None, + } +} + +/// Build a temp identifier expr with string +fn build_identifier_from_string(s: &NodeRef) -> Node { + Node::node_with_pos( + Expr::Identifier(Identifier { + names: transfer_ident_names( + vec![s.node.clone()], + &( + s.filename.clone(), + s.line, + s.column, + s.end_line, + s.end_column, + ), + ), + pkgpath: "".to_string(), + ctx: kclvm_ast::ast::ExprContext::Load, + }), + ( + s.filename.clone(), + s.line, + s.column, + s.end_line, + s.end_column, + ), + ) +} + +/// Build a temp identifier expr with string +fn build_identifier_from_ty_string(ty: &NodeRef, pos: &KCLPos) -> Option> { + if !ty.contains_pos(pos) { + return None; + } + match &ty.node { + Type::Any => None, + Type::Named(id) => Some(Node::node_with_pos( + Expr::Identifier(id.clone()), + ( + ty.filename.clone(), + ty.line, + ty.column, + ty.end_line, + ty.end_column, + ), + )), + Type::Basic(_) => None, + Type::List(list_ty) => { + if let Some(inner) = &list_ty.inner_type { + if inner.contains_pos(pos) { + return build_identifier_from_ty_string(inner, pos); + } + } + None + } + Type::Dict(dict_ty) => { + if let Some(key_ty) = &dict_ty.key_type { + if key_ty.contains_pos(pos) { + return build_identifier_from_ty_string(key_ty, pos); + } + } + if let Some(value_ty) = &dict_ty.value_type { + if value_ty.contains_pos(pos) { + return build_identifier_from_ty_string(value_ty, pos); + } + } + None + } + Type::Union(union_ty) => { + for ty in &union_ty.type_elements { + if ty.contains_pos(pos) { + return build_identifier_from_ty_string(ty, pos); + } + } + None + } + Type::Literal(_) => None, + Type::Function(_) => None, + } +} diff --git a/kclvm/tools/src/LSP/src/word_index.rs b/kclvm/tools/src/LSP/src/word_index.rs new file mode 100644 index 000000000..26c36e7e8 --- /dev/null +++ b/kclvm/tools/src/LSP/src/word_index.rs @@ -0,0 +1,234 @@ +use kclvm_span::symbol::reserved; +use lsp_types::{Position, Range}; +use std::collections::HashMap; + +/// WordIndex represents the correspondence between Word and all its positions +/// VirtualWordIndexMap represents the correspondence between Word and all its positions +pub type VirtualWordIndexMap = HashMap>; +/// WordMap represents the correspondence between text and all its positions +pub type WordMap = HashMap>; + +/// Word describes an arbitrary word in a certain line including +/// start position, end position and the word itself. +#[derive(Debug, PartialEq, Eq, Clone)] +pub struct Word { + start_col: u32, + end_col: u32, + word: String, +} + +impl Word { + fn new(start_col: u32, end_col: u32, word: String) -> Self { + Self { + start_col, + end_col, + word, + } + } +} + +/// Split one line into identifier words. +fn line_to_words(text: String, prune: bool) -> WordMap { + let mut result = HashMap::new(); + let mut chars: Vec = text.chars().collect(); + chars.push('\n'); + let mut start_pos = usize::MAX; + let mut continue_pos = usize::MAX - 1; // avoid overflow + let mut prev_word = false; + let mut words: Vec = vec![]; + for (i, ch) in chars.iter().enumerate() { + if prune && *ch == '#' { + break; + } + let is_id_start = rustc_lexer::is_id_start(*ch); + let is_id_continue = rustc_lexer::is_id_continue(*ch); + // If the character is valid identifier start and the previous character is not valid identifier continue, mark the start position. + if is_id_start && !prev_word { + start_pos = i; + } + if is_id_continue { + // Continue searching for the end position. + if start_pos != usize::MAX { + continue_pos = i; + } + } else { + // Find out the end position. + if continue_pos + 1 == i { + let word = chars[start_pos..i].iter().collect::().clone(); + // Skip word if it should be pruned + if !prune || !reserved::is_reserved_word(&word) { + words.push(Word::new(start_pos as u32, i as u32, word)); + } + } + // Reset the start position. + start_pos = usize::MAX; + } + prev_word = is_id_continue; + } + + for w in words { + result.entry(w.word.clone()).or_insert(Vec::new()).push(w); + } + result +} + +/// VirtualLocation represents a location inside a resource, such as a line inside a text file. +#[allow(unused)] +pub(crate) struct VirtualLocation { + pub(crate) filepath: String, + pub(crate) range: Range, +} + +#[allow(unused)] +pub(crate) fn build_virtual_word_index( + source_codes: HashMap, + prune: bool, +) -> anyhow::Result { + let mut index: VirtualWordIndexMap = HashMap::new(); + for (filepath, content) in source_codes.iter() { + for (key, values) in build_virtual_word_index_with_file_content( + filepath.to_string(), + content.to_string(), + prune, + ) { + index.entry(key).or_default().extend(values); + } + } + Ok(index) +} + +#[allow(unused)] +fn build_virtual_word_index_with_file_content( + filepath: String, + content: String, + prune: bool, +) -> VirtualWordIndexMap { + let mut index: HashMap> = HashMap::new(); + let lines: Vec<&str> = content.lines().collect(); + let mut in_docstring = false; + for (li, line) in lines.into_iter().enumerate() { + if prune && !in_docstring && line.trim_start().starts_with("\"\"\"") { + in_docstring = true; + continue; + } + if prune && in_docstring { + if line.trim_end().ends_with("\"\"\"") { + in_docstring = false; + } + continue; + } + let words = line_to_words(line.to_string(), prune); + for (key, values) in words { + index + .entry(key) + .or_default() + .extend(values.iter().map(|w| VirtualLocation { + filepath: filepath.clone(), + range: Range { + start: Position::new(li as u32, w.start_col), + end: Position::new(li as u32, w.end_col), + }, + })); + } + } + index +} + +#[cfg(test)] +mod tests { + use super::{line_to_words, Word}; + use std::collections::HashMap; + + #[test] + fn test_line_to_words() { + let lines = [ + "schema Person:", + "name. name again", + "some_word word !word", + "# this line is a single-line comment", + "name # end of line comment", + ]; + + let expects: Vec>> = vec![ + vec![( + "Person".to_string(), + vec![Word { + start_col: 7, + end_col: 13, + word: "Person".to_string(), + }], + )] + .into_iter() + .collect(), + vec![ + ( + "name".to_string(), + vec![ + Word { + start_col: 0, + end_col: 4, + word: "name".to_string(), + }, + Word { + start_col: 6, + end_col: 10, + word: "name".to_string(), + }, + ], + ), + ( + "again".to_string(), + vec![Word { + start_col: 11, + end_col: 16, + word: "again".to_string(), + }], + ), + ] + .into_iter() + .collect(), + vec![ + ( + "some_word".to_string(), + vec![Word { + start_col: 0, + end_col: 9, + word: "some_word".to_string(), + }], + ), + ( + "word".to_string(), + vec![ + Word { + start_col: 10, + end_col: 14, + word: "word".to_string(), + }, + Word { + start_col: 16, + end_col: 20, + word: "word".to_string(), + }, + ], + ), + ] + .into_iter() + .collect(), + HashMap::new(), + vec![( + "name".to_string(), + vec![Word { + start_col: 0, + end_col: 4, + word: "name".to_string(), + }], + )] + .into_iter() + .collect(), + ]; + for i in 0..lines.len() { + let got = line_to_words(lines[i].to_string(), true); + assert_eq!(expects[i], got) + } + } +} diff --git a/kclvm/tools/src/fix/LICENSE b/kclvm/tools/src/fix/LICENSE new file mode 100644 index 000000000..989e2c59e --- /dev/null +++ b/kclvm/tools/src/fix/LICENSE @@ -0,0 +1,201 @@ +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. \ No newline at end of file diff --git a/kclvm/tools/src/fix/mod.rs b/kclvm/tools/src/fix/mod.rs new file mode 100644 index 000000000..8d9b8abef --- /dev/null +++ b/kclvm/tools/src/fix/mod.rs @@ -0,0 +1,171 @@ +mod replace; +#[cfg(test)] +mod tests; +use anyhow::{ensure, Error}; +use kclvm_error::{diagnostic::Range as KCLRange, Diagnostic}; +use std::collections::HashMap; +use std::fs; +use std::ops::Range; + +/// A structure for handling code fixes. +pub struct CodeFix { + data: replace::Data, +} + +impl CodeFix { + pub fn new(s: &str) -> CodeFix { + CodeFix { + data: replace::Data::new(s.as_bytes()), + } + } + + pub fn apply(&mut self, suggestion: &Suggestion) -> Result<(), Error> { + let snippet = &suggestion.replacement.snippet; + self.data.replace_range( + snippet.range.start, + snippet.range.end.saturating_sub(1), + suggestion.replacement.replacement.as_bytes(), + )?; + Ok(()) + } + + pub fn finish(&self) -> Result { + Ok(String::from_utf8(self.data.to_vec())?) + } +} + +#[derive(Debug, Clone, Hash, PartialEq, Eq)] +/// An error/warning and possible solutions for fixing it +pub struct Suggestion { + pub message: String, + pub replacement: Replacement, +} + +#[derive(Debug, Clone, Hash, PartialEq, Eq)] +pub struct Replacement { + pub snippet: Snippet, + pub replacement: String, +} + +#[derive(Debug, Clone, Hash, PartialEq, Eq)] +pub struct Snippet { + pub file_name: String, + pub range: Range, +} + +pub fn diag_to_suggestion( + diag: Diagnostic, + files: &mut HashMap, +) -> anyhow::Result> { + let mut suggestions = vec![]; + + for msg in &diag.messages { + let replacements = msg + .suggested_replacement + .clone() + .unwrap_or_else(|| vec!["".to_string()]); + let replacement_str = replacements.first().cloned().unwrap_or_default(); + + let file_name = msg.range.0.filename.clone(); + let src = match files.get(&file_name) { + Some(src) => src.clone(), + None => { + let src = fs::read_to_string(&file_name).expect("Unable to read file"); + files.insert(file_name.clone(), src.clone()); + src + } + }; + + suggestions.push(Suggestion { + message: msg.message.clone(), + replacement: Replacement { + snippet: Snippet { + file_name, + range: text_range(src.as_str(), &msg.range)?, + }, + replacement: replacement_str, + }, + }); + } + Ok(suggestions) +} + +fn is_newline_at_index(s: &str, index: usize) -> bool { + let length = s.len(); + + if index >= length { + return false; + } + + let bytes = s.as_bytes(); + + if bytes[index] == b'\n' { + return true; + } + #[cfg(target_os = "windows")] + if bytes[index] == b'\r' && index + 1 < length && bytes[index + 1] == b'\n' { + return true; + } + + false +} + +pub(crate) fn text_range(text: &str, range: &KCLRange) -> anyhow::Result, Error> { + let mut lines_length = vec![]; + let lines_text: Vec<&str> = text.split('\n').collect(); + let mut pre_total_length = 0; + + for line in &lines_text { + lines_length.push(pre_total_length); + pre_total_length += line.len() + "\n".len(); + } + + ensure!( + (range.0.line as usize) <= lines_length.len() + && (range.1.line as usize) <= lines_length.len() + ); + + // The KCL diagnostic line is 1-based and the column is 0-based. + let start = + lines_length.get(range.0.line as usize - 1).unwrap() + range.0.column.unwrap_or(0) as usize; + let mut end = + lines_length.get(range.1.line as usize - 1).unwrap() + range.1.column.unwrap_or(0) as usize; + + if is_newline_at_index(text, end) { + if cfg!(windows) { + end += "\r\n".len() + } else { + end += "\n".len() + } + } + + Ok(Range { start, end }) +} + +pub fn fix(diags: Vec) -> Result<(), Error> { + let mut suggestions = vec![]; + let mut source_code = HashMap::new(); + for diag in diags { + suggestions.extend(diag_to_suggestion(diag, &mut source_code)?) + } + + let mut files = HashMap::new(); + for suggestion in suggestions { + let file = suggestion.replacement.snippet.file_name.clone(); + files.entry(file).or_insert_with(Vec::new).push(suggestion); + } + + for (source_file, suggestions) in &files { + println!("fix file: {:?}", source_file); + let source = fs::read_to_string(source_file)?; + let mut fix = CodeFix::new(&source); + for suggestion in suggestions.iter() { + if let Err(e) = fix.apply(suggestion) { + eprintln!("Failed to apply suggestion to {}: {}", source_file, e); + } + } + let fixes = fix.finish()?; + fs::write(source_file, fixes)?; + } + Ok(()) +} diff --git a/kclvm/tools/src/fix/replace.rs b/kclvm/tools/src/fix/replace.rs new file mode 100644 index 000000000..4bc4d5c31 --- /dev/null +++ b/kclvm/tools/src/fix/replace.rs @@ -0,0 +1,274 @@ +//! The following code and tests are copied and modified from +//! [rust-lang/rustfix](https://github.com/rust-lang/rustfix/blob/master/src/replace.rs) +//! +//! A small module giving you a simple container that allows easy and cheap +//! replacement of parts of its content, with the ability to prevent changing +//! the same parts multiple times. + +use anyhow::{anyhow, ensure, Error}; +use std::rc::Rc; + +#[derive(Debug, Clone, PartialEq, Eq)] +enum State { + Initial, + Replaced(Rc<[u8]>), + Inserted(Rc<[u8]>), +} + +impl State { + fn is_inserted(&self) -> bool { + matches!(*self, State::Inserted(..)) + } +} + +#[derive(Debug, Clone, PartialEq, Eq)] +struct Span { + /// Start of this span in parent data + start: usize, + /// up to end including + end: usize, + data: State, +} + +/// A container that allows easily replacing chunks of its data +#[derive(Debug, Clone, Default)] +pub struct Data { + original: Vec, + parts: Vec, +} + +impl Data { + /// Create a new data container from a slice of bytes + pub fn new(data: &[u8]) -> Self { + Data { + original: data.into(), + parts: vec![Span { + data: State::Initial, + start: 0, + end: data.len().saturating_sub(1), + }], + } + } + + /// Render this data as a vector of bytes + pub fn to_vec(&self) -> Vec { + if self.original.is_empty() { + return Vec::new(); + } + + self.parts.iter().fold(Vec::new(), |mut acc, d| { + match d.data { + State::Initial => acc.extend_from_slice(&self.original[d.start..=d.end]), + State::Replaced(ref d) | State::Inserted(ref d) => acc.extend_from_slice(d), + }; + acc + }) + } + + /// Replace a chunk of data with the given slice, erroring when this part + /// was already changed previously. + pub fn replace_range( + &mut self, + from: usize, + up_to_and_including: usize, + data: &[u8], + ) -> Result<(), Error> { + let exclusive_end = up_to_and_including + 1; + + ensure!( + from <= exclusive_end, + "Invalid range {}...{}, start is larger than end", + from, + up_to_and_including + ); + + ensure!( + up_to_and_including <= self.original.len(), + "Invalid range {}...{} given, original data is only {} byte long", + from, + up_to_and_including, + self.original.len() + ); + + let insert_only = from == exclusive_end; + + // Since we error out when replacing an already replaced chunk of data, + // we can take some shortcuts here. For example, there can be no + // overlapping replacements -- we _always_ split a chunk of 'initial' + // data into three[^empty] parts, and there can't ever be two 'initial' + // parts touching. + // + // [^empty]: Leading and trailing ones might be empty if we replace + // the whole chunk. As an optimization and without loss of generality we + // don't add empty parts. + let new_parts = { + let index_of_part_to_split = self + .parts + .iter() + .position(|p| { + !p.data.is_inserted() && p.start <= from && p.end >= up_to_and_including + }) + .ok_or_else(|| { + anyhow!( + "Could not replace range {}...{} in file \ + -- maybe parts of it were already replaced?", + from, + up_to_and_including + ) + })?; + + let part_to_split = &self.parts[index_of_part_to_split]; + + // If this replacement matches exactly the part that we would + // otherwise split then we ignore this for now. This means that you + // can replace the exact same range with the exact same content + // multiple times and we'll process and allow it. + if part_to_split.start == from && part_to_split.end == up_to_and_including { + if let State::Replaced(ref replacement) = part_to_split.data { + if &**replacement == data { + return Ok(()); + } + } + } + + ensure!( + part_to_split.data == State::Initial, + "Cannot replace slice of data that was already replaced" + ); + + let mut new_parts = Vec::with_capacity(self.parts.len() + 2); + + // Previous parts + if let Some(ps) = self.parts.get(..index_of_part_to_split) { + new_parts.extend_from_slice(ps); + } + + // Keep initial data on left side of part + if from > part_to_split.start { + new_parts.push(Span { + start: part_to_split.start, + end: from.saturating_sub(1), + data: State::Initial, + }); + } + + // New part + new_parts.push(Span { + start: from, + end: up_to_and_including, + data: if insert_only { + State::Inserted(data.into()) + } else { + State::Replaced(data.into()) + }, + }); + + // Keep initial data on right side of part + if up_to_and_including < part_to_split.end { + new_parts.push(Span { + start: up_to_and_including + 1, + end: part_to_split.end, + data: State::Initial, + }); + } + + // Following parts + if let Some(ps) = self.parts.get(index_of_part_to_split + 1..) { + new_parts.extend_from_slice(ps); + } + + new_parts + }; + + self.parts = new_parts; + + Ok(()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + fn str(i: &[u8]) -> &str { + ::std::str::from_utf8(i).unwrap() + } + + #[test] + fn replace_some_stuff() { + let mut d = Data::new(b"foo bar baz"); + d.replace_range(4, 6, b"lol").unwrap(); + assert_eq!("foo lol baz", str(&d.to_vec())); + } + + #[test] + fn replace_a_single_char() { + let mut d = Data::new(b"let y = true;"); + d.replace_range(4, 4, b"mut y").unwrap(); + assert_eq!("let mut y = true;", str(&d.to_vec())); + } + + #[test] + fn replace_multiple_lines() { + let mut d = Data::new(b"lorem\nipsum\ndolor"); + + d.replace_range(6, 10, b"lol").unwrap(); + assert_eq!("lorem\nlol\ndolor", str(&d.to_vec())); + + d.replace_range(12, 16, b"lol").unwrap(); + assert_eq!("lorem\nlol\nlol", str(&d.to_vec())); + } + + #[test] + fn replace_multiple_lines_with_insert_only() { + let mut d = Data::new(b"foo!"); + + d.replace_range(3, 2, b"bar").unwrap(); + assert_eq!("foobar!", str(&d.to_vec())); + + d.replace_range(0, 2, b"baz").unwrap(); + assert_eq!("bazbar!", str(&d.to_vec())); + + d.replace_range(3, 3, b"?").unwrap(); + assert_eq!("bazbar?", str(&d.to_vec())); + } + + #[test] + fn replace_invalid_range() { + let mut d = Data::new(b"foo!"); + + assert!(d.replace_range(2, 0, b"bar").is_err()); + assert!(d.replace_range(0, 2, b"bar").is_ok()); + } + + #[test] + fn empty_to_vec_roundtrip() { + let s = ""; + assert_eq!(s.as_bytes(), Data::new(s.as_bytes()).to_vec().as_slice()); + } + + #[test] + #[should_panic(expected = "Cannot replace slice of data that was already replaced")] + fn replace_overlapping_stuff_errs() { + let mut d = Data::new(b"foo bar baz"); + + d.replace_range(4, 6, b"lol").unwrap(); + assert_eq!("foo lol baz", str(&d.to_vec())); + + d.replace_range(4, 6, b"lol2").unwrap(); + } + + #[test] + #[should_panic(expected = "original data is only 3 byte long")] + fn broken_replacements() { + let mut d = Data::new(b"foo"); + d.replace_range(4, 7, b"lol").unwrap(); + } + + #[test] + fn replace_same_twice() { + let mut d = Data::new(b"foo"); + d.replace_range(0, 0, b"b").unwrap(); + d.replace_range(0, 0, b"b").unwrap(); + assert_eq!("boo", str(&d.to_vec())); + } +} diff --git a/kclvm/tools/src/fix/test_data/fix_import.k b/kclvm/tools/src/fix/test_data/fix_import.k new file mode 100644 index 000000000..4632b86c3 --- /dev/null +++ b/kclvm/tools/src/fix/test_data/fix_import.k @@ -0,0 +1,5 @@ +import regex +import math +import regex + +a = math.pow(1, 1) \ No newline at end of file diff --git a/kclvm/tools/src/fix/test_data/unused_import.k b/kclvm/tools/src/fix/test_data/unused_import.k new file mode 100644 index 000000000..02202730e --- /dev/null +++ b/kclvm/tools/src/fix/test_data/unused_import.k @@ -0,0 +1 @@ +import math \ No newline at end of file diff --git a/kclvm/tools/src/fix/tests.rs b/kclvm/tools/src/fix/tests.rs new file mode 100644 index 000000000..a76afbe8a --- /dev/null +++ b/kclvm/tools/src/fix/tests.rs @@ -0,0 +1,42 @@ +use std::fs; + +use crate::lint::lint_files; + +use super::fix; + +#[test] +fn test_lint() { + let (errors, warnings) = lint_files( + &[ + "./src/fix/test_data/fix_import.k", + "./src/fix/test_data/unused_import.k", + ], + None, + ); + assert_eq!(errors.len(), 0); + let mut diags = vec![]; + diags.extend(warnings); + + match fix(diags) { + Ok(_) => { + let src = fs::read_to_string("./src/fix/test_data/fix_import.k").unwrap(); + #[cfg(target_os = "windows")] + assert_eq!(src, "import math\r\n\r\na = math.pow(1, 1)".to_string()); + #[cfg(not(target_os = "windows"))] + assert_eq!(src, "import math\n\na = math.pow(1, 1)".to_string()); + fs::write( + "./src/fix/test_data/fix_import.k", + r#"import regex +import math +import regex + +a = math.pow(1, 1)"#, + ) + .unwrap(); + let src = fs::read_to_string("./src/fix/test_data/unused_import.k").unwrap(); + assert_eq!(src, "".to_string()); + fs::write("./src/fix/test_data/unused_import.k", r#"import math"#).unwrap(); + } + Err(e) => panic!("fix failed: {:?}", e), + } +} diff --git a/kclvm/tools/src/format/mod.rs b/kclvm/tools/src/format/mod.rs new file mode 100644 index 000000000..d716e424b --- /dev/null +++ b/kclvm/tools/src/format/mod.rs @@ -0,0 +1,94 @@ +//! [kclvm_tools::format] module mainly contains some functions of language formatting, +//! the main API function is `format`, which accepts a path to be formatted and +//! formatted options. +//! +//! The basic principle is to call the [kclvm_parser::parse_file] function to parse the +//! AST Module, and then use the AST printer [kclvm_tools::printer::print_ast_module] +//! to print it as source code string. +use anyhow::Result; +use kclvm_ast_pretty::print_ast_module; +use kclvm_parser::get_kcl_files; +use std::path::Path; + +use kclvm_parser::{parse_file_force_errors, parse_single_file}; + +#[cfg(test)] +mod tests; + +/// FormatOptions contains two options: +/// - is_stdout: whether to output the formatted result to stdout. +/// - recursively: whether to recursively traverse a folder and format all KCL files in it. +/// - omit_errors: whether to omit the parse errors when format the KCL code. +#[derive(Debug, Default)] +pub struct FormatOptions { + pub is_stdout: bool, + pub recursively: bool, + pub omit_errors: bool, +} + +/// Formats kcl file or directory path contains kcl files and +/// returns the changed file paths. +/// +/// # Examples +/// +/// ```no_run +/// use kclvm_tools::format::{format, FormatOptions}; +/// +/// // Format a single file. +/// format("path_to_a_single_file.k", &FormatOptions::default()).unwrap(); +/// // Format a folder contains kcl files +/// format("path_to_a_folder", &FormatOptions::default()).unwrap(); +/// ``` +pub fn format>(path: P, opts: &FormatOptions) -> Result> { + let mut changed_paths: Vec = vec![]; + let path_ref = path.as_ref(); + if path_ref.is_dir() { + for file in &get_kcl_files(path, opts.recursively)? { + if format_file(file, opts)? { + changed_paths.push(file.clone()) + } + } + } else if path_ref.is_file() { + let file = path_ref.to_str().unwrap().to_string(); + if format_file(&file, opts)? { + changed_paths.push(file) + } + } + if opts.is_stdout { + let n = changed_paths.len(); + println!( + "KCL format done and {} {} formatted:", + n, + if n <= 1 { "file was" } else { "files were" } + ); + for p in &changed_paths { + println!("{}", p); + } + } + Ok(changed_paths) +} + +/// Formats a file and returns whether the file has been formatted and modified. +pub fn format_file(file: &str, opts: &FormatOptions) -> Result { + let src = std::fs::read_to_string(file)?; + let (source, is_formatted) = format_source(file, &src, opts)?; + if opts.is_stdout { + println!("{}", source); + } else { + std::fs::write(file, &source)? + } + Ok(is_formatted) +} + +/// Formats a code source and returns the formatted source and +/// whether the source is changed. +pub fn format_source(file: &str, src: &str, opts: &FormatOptions) -> Result<(String, bool)> { + let module = if opts.omit_errors { + parse_single_file(file, Some(src.to_string()))?.module + } else { + parse_file_force_errors(file, Some(src.to_string()))? + }; + let formatted_src = print_ast_module(&module); + let is_formatted = src != formatted_src; + Ok((formatted_src, is_formatted)) +} diff --git a/kclvm/tools/src/format/test_data/fail_format_data/syntax_err.k b/kclvm/tools/src/format/test_data/fail_format_data/syntax_err.k new file mode 100644 index 000000000..193e81a22 --- /dev/null +++ b/kclvm/tools/src/format/test_data/fail_format_data/syntax_err.k @@ -0,0 +1 @@ +a = \ No newline at end of file diff --git a/kclvm/tools/src/format/test_data/format_data/assert.golden b/kclvm/tools/src/format/test_data/format_data/assert.golden new file mode 100644 index 000000000..f2597860e --- /dev/null +++ b/kclvm/tools/src/format/test_data/format_data/assert.golden @@ -0,0 +1,4 @@ +assert True if True, "message" +# Comment +assert False if data, "message" +assert 1 diff --git a/test/test_units/test_kclvm/test_tools/test_format/format_data/assert.input b/kclvm/tools/src/format/test_data/format_data/assert.input similarity index 100% rename from test/test_units/test_kclvm/test_tools/test_format/format_data/assert.input rename to kclvm/tools/src/format/test_data/format_data/assert.input diff --git a/test/test_units/test_kclvm/test_tools/test_format/format_data/blankline.golden b/kclvm/tools/src/format/test_data/format_data/blankline.golden similarity index 81% rename from test/test_units/test_kclvm/test_tools/test_format/format_data/blankline.golden rename to kclvm/tools/src/format/test_data/format_data/blankline.golden index b92ce49ef..3b4a5410d 100644 --- a/test/test_units/test_kclvm/test_tools/test_format/format_data/blankline.golden +++ b/kclvm/tools/src/format/test_data/format_data/blankline.golden @@ -5,3 +5,4 @@ b = 2 c = 3 d = 4 +e = 5 diff --git a/kclvm/tools/src/format/test_data/format_data/blankline.input b/kclvm/tools/src/format/test_data/format_data/blankline.input new file mode 100644 index 000000000..6a8c1ab53 --- /dev/null +++ b/kclvm/tools/src/format/test_data/format_data/blankline.input @@ -0,0 +1,13 @@ + +a=1 + + +b= 2 + + +c =3 + + + +d = 4 +e = 5 \ No newline at end of file diff --git a/test/test_units/test_kclvm/test_tools/test_format/format_data/breakline.golden b/kclvm/tools/src/format/test_data/format_data/breakline.golden similarity index 100% rename from test/test_units/test_kclvm/test_tools/test_format/format_data/breakline.golden rename to kclvm/tools/src/format/test_data/format_data/breakline.golden diff --git a/test/test_units/test_kclvm/test_tools/test_format/format_data/breakline.input b/kclvm/tools/src/format/test_data/format_data/breakline.input similarity index 100% rename from test/test_units/test_kclvm/test_tools/test_format/format_data/breakline.input rename to kclvm/tools/src/format/test_data/format_data/breakline.input diff --git a/test/test_units/test_kclvm/test_tools/test_format/format_data/check.golden b/kclvm/tools/src/format/test_data/format_data/check.golden similarity index 100% rename from test/test_units/test_kclvm/test_tools/test_format/format_data/check.golden rename to kclvm/tools/src/format/test_data/format_data/check.golden index 84cef43b7..f804e1273 100644 --- a/test/test_units/test_kclvm/test_tools/test_format/format_data/check.golden +++ b/kclvm/tools/src/format/test_data/format_data/check.golden @@ -1,8 +1,8 @@ - schema Person: firstName: str = "John" lastName: str times: int + check: len(lastName) > 0 if times > 5 diff --git a/test/test_units/test_kclvm/test_tools/test_format/format_data/check.input b/kclvm/tools/src/format/test_data/format_data/check.input similarity index 100% rename from test/test_units/test_kclvm/test_tools/test_format/format_data/check.input rename to kclvm/tools/src/format/test_data/format_data/check.input diff --git a/test/test_units/test_kclvm/test_tools/test_format/format_data/codelayout.golden b/kclvm/tools/src/format/test_data/format_data/codelayout.golden similarity index 75% rename from test/test_units/test_kclvm/test_tools/test_format/format_data/codelayout.golden rename to kclvm/tools/src/format/test_data/format_data/codelayout.golden index 6d7e766da..e6b081f08 100644 --- a/test/test_units/test_kclvm/test_tools/test_format/format_data/codelayout.golden +++ b/kclvm/tools/src/format/test_data/format_data/codelayout.golden @@ -1,9 +1,13 @@ import math as alias_math -schema Person: - name: str # inline comment +schema Person(Base): + # inline comment + name: str age: int + check: + age > 0 if age, "age must > 0" + person = Person { name: "Alice" age: 18 @@ -46,8 +50,12 @@ _list = [*_list, [4, 5, 6]] _dict = {**{"k": "v"}, **{"k": "v"}} a = [1, 2, 3] b = [ - 1, 2, 3, - 4, 5, 6, + 1 + 2 + 3 + 4 + 5 + 6 ] _dict = { "k1": "v1" @@ -60,14 +68,21 @@ foo = 1 if foo is not None: _a = 1 _dict |= {} - hello = "world{}".format(1)[2:4].lower() + hello = "world{}".format(1)[2:4:].lower() range_int = [i for i in range(10) if i > 1] + op = 1 + 2 - -3 + (3 - 1) // 3 op += 1 op -= 12 + 23 print(" ", end='') log = math.log(12) aa = 1 -assert aa == 1, "message" +assert aa == 1 if aa, "message" aaaa = (1 + 2 / 2) if _a == 2 + +134.3 else ("a" * 3) bbbb = "{}".format(a) +config: Config { + main: Container { + name: "main" + image: "test/test:v2" + } +} diff --git a/kclvm/tools/src/format/test_data/format_data/codelayout.input b/kclvm/tools/src/format/test_data/format_data/codelayout.input new file mode 100644 index 000000000..457450043 --- /dev/null +++ b/kclvm/tools/src/format/test_data/format_data/codelayout.input @@ -0,0 +1,83 @@ + + + +import math as alias_math +schema Person ( Base): + name:str# inline comment + age:int + check : + age >0 if age, "age must > 0" +person = Person{ + name:"Alice" + age:18 +} +if True: + a = 1 +elif True: + b = 2 +else: + c = 3 +d = 1 + 2 +e = ( 1 + 2 ) +f=[ 1, 2, 3 ] +g = { "key" : "value" } +# block comment +print (1) +dct={"key": "value"} +lst=[1,2,3] +h = dct [ 'key' ] +i = lst [ 1 ] +x = 1 +y = 2 +long_variable = 3 +i = i+1 +submitted+=1 +x = x*2 - 1 +hypot2 = x*x + y*y +_c = (a+b) * (a-b) +_b=2 +_c= 3 +_d =4 + +_value = (1 + 2 * 3) +_value = (1+2*3) +_value =1+ - 2 * ~ 3 +_list = [1, 2, 3] +_list = [*_list, [4, 5 ,6]] +_list = [* _list, [4, 5 ,6]] + +_dict = {** {"k": "v"}, ** {"k": "v"}} +a = [1,2,3] +b = [ + 1,2,3, + 4,5,6, +] +_dict={ + "k1":"v1" + "k2" :"v2" + "k3": "v3" + "k4" : "v4" + "k5" : "v5" +} +foo=1 +if foo is not None: + _a = 1 + _dict|={} + hello = "world{}" . format( 1 )[2 : 4] . lower( ) + range_int = [ i for i in range( 10 ) if i > 1 ] +op = 1+2 - - 3 + (3 - 1) // 3 +op += 1 +op -= 12 + 23 +print( " " , end= '') +log = math. log(12) +aa = 1 +assert aa == 1 if aa,"message" +aaaa = (1 + 2 / 2) if _a == 2 + + 134.3 else ("a"*3) +bbbb = "{}". format(a) +config: Config { + main: Container { + name: "main" + image: "test/test:v2" + } + +} \ No newline at end of file diff --git a/test/test_units/test_kclvm/test_tools/test_format/format_data/collection_if.golden b/kclvm/tools/src/format/test_data/format_data/collection_if.golden similarity index 100% rename from test/test_units/test_kclvm/test_tools/test_format/format_data/collection_if.golden rename to kclvm/tools/src/format/test_data/format_data/collection_if.golden diff --git a/test/test_units/test_kclvm/test_tools/test_format/format_data/collection_if.input b/kclvm/tools/src/format/test_data/format_data/collection_if.input similarity index 100% rename from test/test_units/test_kclvm/test_tools/test_format/format_data/collection_if.input rename to kclvm/tools/src/format/test_data/format_data/collection_if.input diff --git a/kclvm/tools/src/format/test_data/format_data/comment.golden b/kclvm/tools/src/format/test_data/format_data/comment.golden new file mode 100644 index 000000000..b9585cf35 --- /dev/null +++ b/kclvm/tools/src/format/test_data/format_data/comment.golden @@ -0,0 +1,16 @@ +# Block comment +# Inline comment +a = 1 +schema Person: + """ + Schema doc string + """ + # Inline comment in schema + name: str = "Alice" + # Block comment in schema + age: int = 18 + +config = { + # Data comment + data = 1 +} diff --git a/kclvm/tools/src/format/test_data/format_data/comment.input b/kclvm/tools/src/format/test_data/format_data/comment.input new file mode 100644 index 000000000..3dbc998f6 --- /dev/null +++ b/kclvm/tools/src/format/test_data/format_data/comment.input @@ -0,0 +1,14 @@ +# Block comment +a = 1# Inline comment +schema Person: + """ + Schema doc string + """ + name:str="Alice"# Inline comment in schema + # Block comment in schema + age:int=18 + +config = { + # Data comment + data = 1 +} diff --git a/kclvm/tools/src/format/test_data/format_data/comp_for.golden b/kclvm/tools/src/format/test_data/format_data/comp_for.golden new file mode 100644 index 000000000..5d71e3f79 --- /dev/null +++ b/kclvm/tools/src/format/test_data/format_data/comp_for.golden @@ -0,0 +1,3 @@ +data0 = [i + 1 for i in range(10) if i > 1] +data1 = [i + 1 for i in range(10) if i > 1] +data2 = {k = v for k in ["k1", "k2"] for v in [1, 2]} diff --git a/kclvm/tools/src/format/test_data/format_data/comp_for.input b/kclvm/tools/src/format/test_data/format_data/comp_for.input new file mode 100644 index 000000000..cafb0849d --- /dev/null +++ b/kclvm/tools/src/format/test_data/format_data/comp_for.input @@ -0,0 +1,8 @@ +data0 = [ + i + 1 for i in range(10) if i > 1 +] +data1 = [ + i + 1 for i in range(10) + if i > 1 +] +data2 = {k = v for k in ["k1", "k2"] for v in [1, 2]} diff --git a/kclvm/tools/src/format/test_data/format_data/different_stmts_line_breaks.golden b/kclvm/tools/src/format/test_data/format_data/different_stmts_line_breaks.golden new file mode 100644 index 000000000..fea668c1a --- /dev/null +++ b/kclvm/tools/src/format/test_data/format_data/different_stmts_line_breaks.golden @@ -0,0 +1,7 @@ +import a + +schema A: + name: str = a.name + +A {} +# Break one blank line between different statements e.g., import, schema and expression statements. diff --git a/kclvm/tools/src/format/test_data/format_data/different_stmts_line_breaks.input b/kclvm/tools/src/format/test_data/format_data/different_stmts_line_breaks.input new file mode 100644 index 000000000..60d9818b9 --- /dev/null +++ b/kclvm/tools/src/format/test_data/format_data/different_stmts_line_breaks.input @@ -0,0 +1,5 @@ +import a +schema A: + name: str = a.name +A{} +# Break one blank line between different statements e.g., import, schema and expression statements. diff --git a/test/test_units/test_kclvm/test_types/invalid_test_data/schema/kcl.mod b/kclvm/tools/src/format/test_data/format_data/empty.golden similarity index 100% rename from test/test_units/test_kclvm/test_types/invalid_test_data/schema/kcl.mod rename to kclvm/tools/src/format/test_data/format_data/empty.golden diff --git a/test/test_units/test_kclvm/test_types/invalid_test_data/type_alias/kcl.mod b/kclvm/tools/src/format/test_data/format_data/empty.input similarity index 100% rename from test/test_units/test_kclvm/test_types/invalid_test_data/type_alias/kcl.mod rename to kclvm/tools/src/format/test_data/format_data/empty.input diff --git a/test/test_units/test_kclvm/test_tools/test_format/format_data/import.golden b/kclvm/tools/src/format/test_data/format_data/import.golden similarity index 100% rename from test/test_units/test_kclvm/test_tools/test_format/format_data/import.golden rename to kclvm/tools/src/format/test_data/format_data/import.golden diff --git a/kclvm/tools/src/format/test_data/format_data/import.input b/kclvm/tools/src/format/test_data/format_data/import.input new file mode 100644 index 000000000..b30e8564f --- /dev/null +++ b/kclvm/tools/src/format/test_data/format_data/import.input @@ -0,0 +1,12 @@ +import a + +import b + +import c +import d + +import e as e + + + +a = 1 diff --git a/kclvm/tools/src/format/test_data/format_data/import_only.golden b/kclvm/tools/src/format/test_data/format_data/import_only.golden new file mode 100644 index 000000000..c2d4d9515 --- /dev/null +++ b/kclvm/tools/src/format/test_data/format_data/import_only.golden @@ -0,0 +1,2 @@ +import math +import abc diff --git a/kclvm/tools/src/format/test_data/format_data/import_only.input b/kclvm/tools/src/format/test_data/format_data/import_only.input new file mode 100644 index 000000000..598699503 --- /dev/null +++ b/kclvm/tools/src/format/test_data/format_data/import_only.input @@ -0,0 +1,2 @@ +import math +import abc \ No newline at end of file diff --git a/test/test_units/test_kclvm/test_tools/test_format/format_data/indent.golden b/kclvm/tools/src/format/test_data/format_data/indent.golden similarity index 100% rename from test/test_units/test_kclvm/test_tools/test_format/format_data/indent.golden rename to kclvm/tools/src/format/test_data/format_data/indent.golden index 874e8f629..738448654 100644 --- a/test/test_units/test_kclvm/test_tools/test_format/format_data/indent.golden +++ b/kclvm/tools/src/format/test_data/format_data/indent.golden @@ -8,7 +8,7 @@ elif True: d = 4 else: e = 8 - schema Person: name: str age: int + diff --git a/test/test_units/test_kclvm/test_tools/test_format/format_data/indent.input b/kclvm/tools/src/format/test_data/format_data/indent.input similarity index 100% rename from test/test_units/test_kclvm/test_tools/test_format/format_data/indent.input rename to kclvm/tools/src/format/test_data/format_data/indent.input diff --git a/test/test_units/test_kclvm/test_tools/test_format/format_data/inline_comment.golden b/kclvm/tools/src/format/test_data/format_data/inline_comment.golden similarity index 100% rename from test/test_units/test_kclvm/test_tools/test_format/format_data/inline_comment.golden rename to kclvm/tools/src/format/test_data/format_data/inline_comment.golden diff --git a/test/test_units/test_kclvm/test_tools/test_format/format_data/inline_comment.input b/kclvm/tools/src/format/test_data/format_data/inline_comment.input similarity index 100% rename from test/test_units/test_kclvm/test_tools/test_format/format_data/inline_comment.input rename to kclvm/tools/src/format/test_data/format_data/inline_comment.input diff --git a/kclvm/tools/src/format/test_data/format_data/lambda.golden b/kclvm/tools/src/format/test_data/format_data/lambda.golden new file mode 100644 index 000000000..cb5410afe --- /dev/null +++ b/kclvm/tools/src/format/test_data/format_data/lambda.golden @@ -0,0 +1,13 @@ +f0 = lambda { + 1 + 1 +} +f1 = lambda x: int, y: int -> int { + x + y +} +f2 = lambda { + lambda x { + lambda y { + y + 1 + } + } +} diff --git a/kclvm/tools/src/format/test_data/format_data/lambda.input b/kclvm/tools/src/format/test_data/format_data/lambda.input new file mode 100644 index 000000000..9d07cfec9 --- /dev/null +++ b/kclvm/tools/src/format/test_data/format_data/lambda.input @@ -0,0 +1,13 @@ +f0 = lambda { + 1 + 1 +} +f1 = lambda x : int , y : int ->int{ + x + y +} +f2 = lambda { + lambda x { + lambda y { + y + 1 + } + } +} diff --git a/kclvm/tools/src/format/test_data/format_data/layout_import_stmt.golden b/kclvm/tools/src/format/test_data/format_data/layout_import_stmt.golden new file mode 100644 index 000000000..792e3ac36 --- /dev/null +++ b/kclvm/tools/src/format/test_data/format_data/layout_import_stmt.golden @@ -0,0 +1,6 @@ +import a.b.c +import d + +schema A: + name: str + diff --git a/kclvm/tools/src/format/test_data/format_data/layout_import_stmt.input b/kclvm/tools/src/format/test_data/format_data/layout_import_stmt.input new file mode 100644 index 000000000..7d3da4d41 --- /dev/null +++ b/kclvm/tools/src/format/test_data/format_data/layout_import_stmt.input @@ -0,0 +1,4 @@ +import a.b.c +import d +schema A: + name: str \ No newline at end of file diff --git a/kclvm/tools/src/format/test_data/format_data/list_dict_schema_expr.golden b/kclvm/tools/src/format/test_data/format_data/list_dict_schema_expr.golden new file mode 100644 index 000000000..a71205411 --- /dev/null +++ b/kclvm/tools/src/format/test_data/format_data/list_dict_schema_expr.golden @@ -0,0 +1,20 @@ +dict = { + "key": "value" +} + +dict2 = {"key": "value"} + +list = [ + first + second +] + +list2 = [first, second] + +expr = Person { + name: "Alice" +} + +expr2 = Person {name: "Alice"} + +# It's both acceptable to write each entry in the list/dict/schema expr without line breaks, or separate each entry with one line break. diff --git a/kclvm/tools/src/format/test_data/format_data/list_dict_schema_expr.input b/kclvm/tools/src/format/test_data/format_data/list_dict_schema_expr.input new file mode 100644 index 000000000..a71205411 --- /dev/null +++ b/kclvm/tools/src/format/test_data/format_data/list_dict_schema_expr.input @@ -0,0 +1,20 @@ +dict = { + "key": "value" +} + +dict2 = {"key": "value"} + +list = [ + first + second +] + +list2 = [first, second] + +expr = Person { + name: "Alice" +} + +expr2 = Person {name: "Alice"} + +# It's both acceptable to write each entry in the list/dict/schema expr without line breaks, or separate each entry with one line break. diff --git a/test/test_units/test_kclvm/test_tools/test_format/format_data/quant.golden b/kclvm/tools/src/format/test_data/format_data/quant.golden similarity index 100% rename from test/test_units/test_kclvm/test_tools/test_format/format_data/quant.golden rename to kclvm/tools/src/format/test_data/format_data/quant.golden diff --git a/kclvm/tools/src/format/test_data/format_data/quant.input b/kclvm/tools/src/format/test_data/format_data/quant.input new file mode 100644 index 000000000..af1e84f0d --- /dev/null +++ b/kclvm/tools/src/format/test_data/format_data/quant.input @@ -0,0 +1,8 @@ +a = all x in [-1, 0, 1, 2, 3] { + x >= 1 if x > 0 +} +b = any x in {k1 = "v1", k2 = "v2"} {x in ["k1", "v2"]} +c = map x in {k1 = "v1", k2 = "v2"} { x } +d = filter x in [1, 2, 3] { + x > 1 +} diff --git a/kclvm/tools/src/format/test_data/format_data/schema.golden b/kclvm/tools/src/format/test_data/format_data/schema.golden new file mode 100644 index 000000000..c366fc642 --- /dev/null +++ b/kclvm/tools/src/format/test_data/format_data/schema.golden @@ -0,0 +1,25 @@ +import math + +mixin XXMixin: + nameVar: str + +schema Base: + """ + Base schema doc string + """ + mixin [ + XXMixin, + XXMixin + ] + name: str = "Alice" + labels: {str:str} = None + +schema Person[para1: str = "value", para2 = "value"](Base): + age: int = 18 + name = para + + check: + True + bool(math.log(10)) + +person = Person(para1="12") {} diff --git a/test/test_units/test_kclvm/test_tools/test_format/format_data/schema.input b/kclvm/tools/src/format/test_data/format_data/schema.input similarity index 100% rename from test/test_units/test_kclvm/test_tools/test_format/format_data/schema.input rename to kclvm/tools/src/format/test_data/format_data/schema.input diff --git a/test/test_units/test_kclvm/test_tools/test_format/format_data/string.golden b/kclvm/tools/src/format/test_data/format_data/string.golden similarity index 100% rename from test/test_units/test_kclvm/test_tools/test_format/format_data/string.golden rename to kclvm/tools/src/format/test_data/format_data/string.golden diff --git a/test/test_units/test_kclvm/test_tools/test_format/format_data/string.input b/kclvm/tools/src/format/test_data/format_data/string.input similarity index 100% rename from test/test_units/test_kclvm/test_tools/test_format/format_data/string.input rename to kclvm/tools/src/format/test_data/format_data/string.input diff --git a/test/test_units/test_kclvm/test_tools/test_format/format_data/type_alias.golden b/kclvm/tools/src/format/test_data/format_data/type_alias.golden similarity index 100% rename from test/test_units/test_kclvm/test_tools/test_format/format_data/type_alias.golden rename to kclvm/tools/src/format/test_data/format_data/type_alias.golden diff --git a/test/test_units/test_kclvm/test_tools/test_format/format_data/type_alias.input b/kclvm/tools/src/format/test_data/format_data/type_alias.input similarity index 100% rename from test/test_units/test_kclvm/test_tools/test_format/format_data/type_alias.input rename to kclvm/tools/src/format/test_data/format_data/type_alias.input diff --git a/test/test_units/test_kclvm/test_tools/test_format/format_data/unary.golden b/kclvm/tools/src/format/test_data/format_data/unary.golden similarity index 79% rename from test/test_units/test_kclvm/test_tools/test_format/format_data/unary.golden rename to kclvm/tools/src/format/test_data/format_data/unary.golden index 146472978..a08f55c96 100644 --- a/test/test_units/test_kclvm/test_tools/test_format/format_data/unary.golden +++ b/kclvm/tools/src/format/test_data/format_data/unary.golden @@ -1,3 +1,3 @@ x = not True or not False y = +1 + -1 -z = ~0x11 +z = ~17 diff --git a/test/test_units/test_kclvm/test_tools/test_format/format_data/unary.input b/kclvm/tools/src/format/test_data/format_data/unary.input similarity index 100% rename from test/test_units/test_kclvm/test_tools/test_format/format_data/unary.input rename to kclvm/tools/src/format/test_data/format_data/unary.input diff --git a/kclvm/tools/src/format/test_data/format_data/union_types.golden b/kclvm/tools/src/format/test_data/format_data/union_types.golden new file mode 100644 index 000000000..b4f853579 --- /dev/null +++ b/kclvm/tools/src/format/test_data/format_data/union_types.golden @@ -0,0 +1,11 @@ +workloadType: "Deployment" | "StatefulSet" = "Deployment" +ServiceType: "LoadBalance" | "ClusterIP" = "LoadBalance" +abc: A | B | C = A {} + +schema Server: + [name: str | int]: str | int + workloadType: "Deployment" | "StatefulSet" + dict: {str:str | int} + +type some_alias = "abc" | "def" | {str | int:} +# In union types, there should be one and only one whitespace both before and after the union operator | diff --git a/kclvm/tools/src/format/test_data/format_data/union_types.input b/kclvm/tools/src/format/test_data/format_data/union_types.input new file mode 100644 index 000000000..03d8b64fd --- /dev/null +++ b/kclvm/tools/src/format/test_data/format_data/union_types.input @@ -0,0 +1,11 @@ +workloadType: "Deployment"|"StatefulSet" = "Deployment" +ServiceType: "LoadBalance" |"ClusterIP" = "LoadBalance" +abc: A|B|C = A{} + +schema Server: + [name: str|int]: str|int + workloadType: "Deployment"| "StatefulSet" + dict: {str: str|int} + +type some_alias = "abc"|"def"|{str|int:} +# In union types, there should be one and only one whitespace both before and after the union operator | diff --git a/test/test_units/test_kclvm/test_ast/test_ast/test_data/check_sum.k b/kclvm/tools/src/format/test_data/format_path_data/folder/first.k similarity index 100% rename from test/test_units/test_kclvm/test_ast/test_ast/test_data/check_sum.k rename to kclvm/tools/src/format/test_data/format_path_data/folder/first.k diff --git a/kclvm/tools/src/format/test_data/format_path_data/folder/second.k b/kclvm/tools/src/format/test_data/format_path_data/folder/second.k new file mode 100644 index 000000000..a67860308 --- /dev/null +++ b/kclvm/tools/src/format/test_data/format_path_data/folder/second.k @@ -0,0 +1 @@ +b = 2 diff --git a/test/test_units/test_kclvm/test_tools/test_format/format_path_data/internal_pkg/test.k b/kclvm/tools/src/format/test_data/format_path_data/if.k similarity index 100% rename from test/test_units/test_kclvm/test_tools/test_format/format_path_data/internal_pkg/test.k rename to kclvm/tools/src/format/test_data/format_path_data/if.k diff --git a/test/test_units/test_kclvm/test_tools/test_format/format_path_data/test.k b/kclvm/tools/src/format/test_data/format_path_data/internal_pkg/test.k similarity index 100% rename from test/test_units/test_kclvm/test_tools/test_format/format_path_data/test.k rename to kclvm/tools/src/format/test_data/format_path_data/internal_pkg/test.k diff --git a/kclvm/tools/src/format/test_data/format_path_data/single_file.k b/kclvm/tools/src/format/test_data/format_path_data/single_file.k new file mode 100644 index 000000000..b6030a42a --- /dev/null +++ b/kclvm/tools/src/format/test_data/format_path_data/single_file.k @@ -0,0 +1,2 @@ +a = 1 +b = "2" diff --git a/kclvm/tools/src/format/tests.rs b/kclvm/tools/src/format/tests.rs new file mode 100644 index 000000000..a76abc70f --- /dev/null +++ b/kclvm/tools/src/format/tests.rs @@ -0,0 +1,233 @@ +use super::*; +use kclvm_parser::parse_file_force_errors; +use pretty_assertions::assert_eq; +use walkdir::WalkDir; + +const FILE_INPUT_SUFFIX: &str = ".input"; +const FILE_OUTPUT_SUFFIX: &str = ".golden"; +const TEST_CASES: &[&str; 22] = &[ + "assert", + "check", + "blankline", + "breakline", + "codelayout", + "collection_if", + "comment", + "comp_for", + "empty", + "import", + "import_only", + "indent", + "inline_comment", + "lambda", + "quant", + "schema", + "string", + "type_alias", + "unary", + "union_types", + "layout_import_stmt", + "different_stmts_line_breaks", + // "list_dict_schema_expr", +]; + +fn read_data(data_name: &str) -> (String, String) { + let src = std::fs::read_to_string(format!( + "./src/format/test_data/format_data/{}{}", + data_name, FILE_INPUT_SUFFIX + )) + .unwrap(); + + ( + format_source("", &src, &Default::default()).unwrap().0, + std::fs::read_to_string(format!( + "./src/format/test_data/format_data/{}{}", + data_name, FILE_OUTPUT_SUFFIX + )) + .unwrap(), + ) +} + +#[test] +fn test_format_source() { + for case in TEST_CASES { + let (data_input, data_output) = read_data(case); + #[cfg(target_os = "windows")] + let data_output = data_output.replace("\r\n", "\n"); + assert_eq!(data_input, data_output, "Test failed on {}", case); + } +} + +#[test] +fn test_format_single_file() { + assert!(format( + "./src/format/test_data/format_path_data/single_file.k", + &FormatOptions::default() + ) + .is_ok()); +} + +#[test] +fn test_format_folder() { + assert!(format( + "./src/format/test_data/format_path_data/folder", + &FormatOptions::default() + ) + .is_ok()); +} + +#[test] +fn test_format_with_stdout_option() { + let opts = FormatOptions { + is_stdout: true, + recursively: false, + omit_errors: false, + }; + let changed_files = format("./src/format/test_data/format_path_data/if.k", &opts).unwrap(); + assert_eq!(changed_files.len(), 1); + let changed_files = format("./src/format/test_data/format_path_data/", &opts).unwrap(); + assert_eq!(changed_files.len(), 1); + let opts = FormatOptions { + is_stdout: true, + recursively: true, + omit_errors: false, + }; + let changed_files = format("./src/format/test_data/format_path_data/", &opts).unwrap(); + assert_eq!(changed_files.len(), 2); +} + +#[test] +fn test_format_with_omit_error_option() { + let opts = FormatOptions { + is_stdout: false, + recursively: false, + omit_errors: true, + }; + let cases = [ + ( + r#"x = { +a: { +b: 1 +c: 2 +} +d: 3 +} +"#, + r#"x = { + a: { + b: 1 + c: 2 + } + d: 3 +} +"#, + ), + ( + r#"x = { +a: { + b: 1 + c: 2 +} +} +"#, + r#"x = { + a: { + b: 1 + c: 2 + } +} +"#, + ), + ( + r#"x = { + a: 1 + b: 2 + c: 3 +} +"#, + r#"x = { + a: 1 + b: 2 + c: 3 +} +"#, + ), + ( + r#"x = { + a: 1 + b: 2 + c: 3 +} +"#, + r#"x = { + a: 1 + b: 2 + c: 3 +} +"#, + ), + ]; + for (code, expected_code) in cases { + let (actual_code, _) = format_source("error_indent.k", code, &opts).unwrap(); + assert_eq!(actual_code, expected_code); + } +} + +#[test] +fn test_format_integration_konfig() -> Result<()> { + let konfig_path = Path::new(".") + .canonicalize()? + .parent() + .unwrap() + .parent() + .unwrap() + .join("test") + .join("integration") + .join("konfig"); + let files = get_files(konfig_path, true, true, ".k"); + for file in &files { + // Skip test and hidden files. + if file.ends_with("_test.k") || file.starts_with('_') { + continue; + } + assert!( + parse_file_force_errors(file, None).is_ok(), + "file {} test format failed", + file + ); + let src = std::fs::read_to_string(file)?; + let (formatted_src, _) = format_source("", &src, &Default::default())?; + let parse_result = parse_file_force_errors("test.k", Some(formatted_src.clone() + "\n")); + assert!( + parse_result.is_ok(), + "file {} test format failed, the formatted source is\n{}\n the parse error is\n{}", + file, + formatted_src, + parse_result.err().unwrap(), + ); + } + Ok(()) +} + +/// Get kcl files from path. +fn get_files>( + path: P, + recursively: bool, + sorted: bool, + suffix: &str, +) -> Vec { + let mut files = vec![]; + for entry in WalkDir::new(path).into_iter().filter_map(|e| e.ok()) { + let path = entry.path(); + if path.is_file() { + let file = path.to_str().unwrap(); + if file.ends_with(suffix) && (recursively || entry.depth() == 1) { + files.push(file.to_string()) + } + } + } + if sorted { + files.sort(); + } + files +} diff --git a/kclvm/tools/src/lib.rs b/kclvm/tools/src/lib.rs index 066865e5b..703c3b406 100644 --- a/kclvm/tools/src/lib.rs +++ b/kclvm/tools/src/lib.rs @@ -1,5 +1,6 @@ -pub mod printer; -pub mod query; - -#[macro_use] -extern crate kclvm_error; +pub mod fix; +pub mod format; +pub mod lint; +pub mod testing; +pub mod util; +pub mod vet; diff --git a/kclvm/tools/src/lint/mod.rs b/kclvm/tools/src/lint/mod.rs new file mode 100644 index 000000000..4a0b66fb5 --- /dev/null +++ b/kclvm/tools/src/lint/mod.rs @@ -0,0 +1,97 @@ +use std::sync::Arc; + +use indexmap::IndexSet; +use kclvm_error::{Diagnostic, Handler}; +use kclvm_parser::{load_program, LoadProgramOptions, ParseSession}; +use kclvm_runtime::PanicInfo; +use kclvm_sema::resolver::resolve_program_with_opts; +#[cfg(test)] +mod tests; + +/// KCL Lint tools API, check a set of files, skips execute, divides and returns diagnostics into error and warning +/// +/// # Parameters +/// +/// `file`: [&str] +/// The File that need to be check +/// +/// `opts`: Option +/// The compilation parameters of KCL, same as the compilation process +/// +/// # Returns +/// +/// result: (IndexSet, IndexSet) +/// Error and warning diagenostics. +/// +/// # Examples +/// +/// ```no_run +/// use kclvm_tools::lint::lint_files; +/// let (errors, warnings) = lint_files(&["test.k"], None); +/// ``` +/// +/// - test.k +/// +/// ```kcl +/// import math +/// schema Person: +/// age: int +/// ``` +/// +/// - return +/// ```no_check +/// error: [] +/// warning: [ +/// Diagnostic { +/// level: Warning +/// messages: [Message { +/// range: ( +/// Position { +/// filename: test.k, +/// line: 1, +/// column: None, +/// }, +/// Position { +/// filename: test.k, +/// line: 1, +/// column: None, +/// }, +/// ), +/// style: Style::Line, +/// message: "Module 'math' imported but unused", +/// note: Some("Consider removing this statement".to_string()), +/// }], +/// code: Some, +/// } +/// ] +/// ``` +pub fn lint_files( + files: &[&str], + opts: Option, +) -> (IndexSet, IndexSet) { + // Parse AST program. + let sess = Arc::new(ParseSession::default()); + let mut opts = opts.unwrap_or_default(); + opts.load_plugins = true; + let mut program = match load_program(sess.clone(), files, Some(opts), None) { + Ok(p) => p.program, + Err(err_str) => { + return Handler::default() + .add_panic_info(&PanicInfo::from(err_str.to_string())) + .classification(); + } + }; + sess.append_diagnostic( + resolve_program_with_opts( + &mut program, + kclvm_sema::resolver::Options { + merge_program: false, + ..Default::default() + }, + None, + ) + .handler + .diagnostics, + ) + .classification() +} diff --git a/test/test_units/test_kclvm/test_types/invalid_test_data/type_as/kcl.mod b/kclvm/tools/src/lint/test_data/import_test/a.k similarity index 100% rename from test/test_units/test_kclvm/test_types/invalid_test_data/type_as/kcl.mod rename to kclvm/tools/src/lint/test_data/import_test/a.k diff --git a/kclvm/tools/src/lint/test_data/import_test/b.k b/kclvm/tools/src/lint/test_data/import_test/b.k new file mode 100644 index 000000000..3ffa2426b --- /dev/null +++ b/kclvm/tools/src/lint/test_data/import_test/b.k @@ -0,0 +1 @@ +_b = 1 \ No newline at end of file diff --git a/kclvm/tools/src/lint/test_data/lint.k b/kclvm/tools/src/lint/test_data/lint.k new file mode 100644 index 000000000..9e2fc7327 --- /dev/null +++ b/kclvm/tools/src/lint/test_data/lint.k @@ -0,0 +1,12 @@ +import import_test.a # UnusedImport +import import_test.a # ReImport +import abc + + +schema Person: + name: str + age: int + +b1 = b._b + +import import_test.b # ImportPosition diff --git a/kclvm/tools/src/lint/test_data/unused_check_for_each_file/a.k b/kclvm/tools/src/lint/test_data/unused_check_for_each_file/a.k new file mode 100644 index 000000000..02202730e --- /dev/null +++ b/kclvm/tools/src/lint/test_data/unused_check_for_each_file/a.k @@ -0,0 +1 @@ +import math \ No newline at end of file diff --git a/kclvm/tools/src/lint/test_data/unused_check_for_each_file/b.k b/kclvm/tools/src/lint/test_data/unused_check_for_each_file/b.k new file mode 100644 index 000000000..b59d572e1 --- /dev/null +++ b/kclvm/tools/src/lint/test_data/unused_check_for_each_file/b.k @@ -0,0 +1,2 @@ +import math +a = math.pow(1, 1) \ No newline at end of file diff --git a/kclvm/tools/src/lint/tests.rs b/kclvm/tools/src/lint/tests.rs new file mode 100644 index 000000000..51354f595 --- /dev/null +++ b/kclvm/tools/src/lint/tests.rs @@ -0,0 +1,70 @@ +use super::lint_files; +use std::path::PathBuf; + +#[test] +fn test_lint() { + let (errors, warnings) = lint_files(&["./src/lint/test_data/lint.k"], None); + let msgs = [ + "The import stmt should be placed at the top of the module", + "Module 'a' is reimported multiple times", + "Module 'a' imported but unused", + "Module 'a' imported but unused", + "Module 'abc' imported but unused", + ]; + assert_eq!(warnings.len(), msgs.len()); + for (diag, m) in warnings.iter().zip(msgs.iter()) { + assert_eq!(diag.messages[0].message, m.to_string()); + } + + let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + path.push("src"); + path.push("lint"); + path.push("test_data"); + path.push("abc"); + + let msgs = [ + "pkgpath abc not found in the program", + "try 'kcl mod add abc' to download the missing package", + "browse more packages at 'https://artifacthub.io'", + &format!("Cannot find the module abc from {}", path.to_str().unwrap()), + ]; + assert_eq!( + errors.len(), + msgs.len(), + "{:?}", + errors + .iter() + .map(|e| e.messages[0].message.clone()) + .collect::>() + ); + for (diag, m) in errors.iter().zip(msgs.iter()) { + assert_eq!(diag.messages[0].message, m.to_string()); + } +} + +#[test] +fn test_unused_check_for_each_file() { + let (errs, warnings) = lint_files( + &[ + "./src/lint/test_data/unused_check_for_each_file/a.k", + "./src/lint/test_data/unused_check_for_each_file/b.k", + ], + None, + ); + assert_eq!(errs.len(), 0); + assert_eq!(warnings.len(), 1); + assert_eq!( + warnings[0].messages[0].message, + "Module 'math' imported but unused".to_string() + ); + let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + path.push("src"); + path.push("lint"); + path.push("test_data"); + path.push("unused_check_for_each_file"); + path.push("a.k"); + assert_eq!( + warnings[0].messages[0].range.0.filename, + path.to_str().unwrap().to_string() + ); +} diff --git a/kclvm/tools/src/printer/mod.rs b/kclvm/tools/src/printer/mod.rs deleted file mode 100644 index 2f043e96a..000000000 --- a/kclvm/tools/src/printer/mod.rs +++ /dev/null @@ -1,258 +0,0 @@ -use indexmap::IndexMap; -use std::collections::VecDeque; - -use kclvm_ast::{ast, token::TokenKind, walker::MutSelfTypedResultWalker}; - -mod node; - -#[cfg(test)] -mod tests; - -pub const WHITESPACE: &str = " "; -pub const TAB: &str = "\t"; -pub const NEWLINE: &str = "\n"; - -#[derive(Debug, Clone)] -pub enum Indentation { - Indent = 0, - Dedent = 1, - Newline = 2, - IndentWithNewline = 3, - DedentWithNewline = 4, - Fill = 5, -} - -/// Printer config -#[derive(Debug)] -pub struct Config { - pub tab_len: usize, - pub indent_len: usize, - pub use_spaces: bool, - pub write_comments: bool, -} - -impl Default for Config { - fn default() -> Self { - Self { - tab_len: 4, - indent_len: 4, - use_spaces: true, - write_comments: true, - } - } -} - -#[derive(Copy, Clone)] -pub struct NoHook; - -impl PrinterHook for NoHook {} - -pub enum ASTNode<'p> { - Stmt(&'p ast::NodeRef), - Expr(&'p ast::NodeRef), -} - -pub trait PrinterHook { - fn pre(&self, _printer: &mut Printer<'_>, _node: ASTNode<'_>) {} - fn post(&self, _printer: &mut Printer<'_>, _node: ASTNode<'_>) {} -} - -pub struct Printer<'p> { - /// Output string buffer. - pub out: String, - pub indent: usize, - pub cfg: Config, - /// Print comments, - pub last_ast_line: u64, - pub comments: VecDeque>, - pub import_spec: IndexMap, - pub hook: &'p (dyn PrinterHook + 'p), -} - -impl Default for Printer<'_> { - fn default() -> Self { - Self { - out: Default::default(), - indent: Default::default(), - cfg: Default::default(), - last_ast_line: Default::default(), - comments: Default::default(), - import_spec: Default::default(), - hook: &NoHook, - } - } -} - -impl<'p> Printer<'p> { - pub fn new(cfg: Config, hook: &'p (dyn PrinterHook + 'p)) -> Self { - Self { - out: "".to_string(), - indent: 0, - cfg, - last_ast_line: 0, - comments: VecDeque::default(), - import_spec: IndexMap::default(), - hook, - } - } - - // -------------------------- - // Write functions - // -------------------------- - - /// Write a string - #[inline] - pub fn write(&mut self, text: &str) { - self.write_string(text); - } - - /// Write a string with newline. - #[inline] - pub fn writeln(&mut self, text: &str) { - self.write_string(text); - self.write_string(NEWLINE); - self.fill(""); - } - - /// Write a space. - #[inline] - pub fn write_space(&mut self) { - self.write_string(WHITESPACE); - } - - /// Fill a indent - pub fn fill(&mut self, text: &str) { - if self.cfg.use_spaces { - self.write(&format!( - "{}{}", - WHITESPACE.repeat(self.indent * self.cfg.indent_len), - text - )); - } else { - self.write(&format!("{}{}", TAB.repeat(self.indent), text)); - } - } - - /// Print string - #[inline] - pub fn write_string(&mut self, string: &str) { - self.out.push_str(string); - } - - pub fn write_indentation(&mut self, indentation: Indentation) { - match indentation { - Indentation::Indent => self.enter(), - Indentation::Dedent => self.leave(), - Indentation::Newline => self.write_newline(), - Indentation::IndentWithNewline => { - self.enter(); - self.write_newline() - } - Indentation::DedentWithNewline => { - self.leave(); - self.write_newline(); - } - Indentation::Fill => self.fill(""), - } - } - - #[inline] - pub fn write_newline(&mut self) { - self.writeln("") - } - - #[inline] - pub fn write_newline_without_fill(&mut self) { - self.write_string(NEWLINE); - } - - /// Print value - #[inline] - pub fn write_value(&mut self, value: T) { - self.write(&format!("{}", value)); - } - - /// Print ast token - #[inline] - pub fn write_token(&mut self, tok: TokenKind) { - let tok_str: String = tok.into(); - self.write_string(&tok_str); - } - - /// Print ast node - #[inline] - pub fn write_node(&mut self, node: ASTNode<'_>) { - match node { - ASTNode::Stmt(stmt) => self.stmt(stmt), - ASTNode::Expr(expr) => self.expr(expr), - } - } - - /// Print ast module. - #[inline] - pub fn write_module(&mut self, module: &ast::Module) { - self.walk_module(module); - while let Some(comment) = self.comments.pop_front() { - self.writeln(&comment.node.text); - self.fill(""); - } - } - - /// Print ast comments. - pub fn write_ast_comments(&mut self, node: &ast::NodeRef) { - if !self.cfg.write_comments { - return; - } - if node.line > self.last_ast_line { - self.last_ast_line = node.line; - let mut index = None; - for (i, comment) in self.comments.iter().enumerate() { - if comment.line <= node.line { - index = Some(i); - } else { - break; - } - } - if let Some(index) = index { - let mut count = index as isize; - while count >= 0 { - match self.comments.pop_front() { - Some(comment) => { - self.writeln(&comment.node.text); - } - None => break, - } - count -= 1; - } - } - } - } - - // -------------------------- - // Indent and scope functions - // -------------------------- - - /// Enter with a indent - pub fn enter(&mut self) { - self.indent += 1; - } - - /// Leave with a dedent - pub fn leave(&mut self) { - self.indent -= 1; - } -} - -/// Print AST to string -pub fn print_ast_module(module: &ast::Module) -> String { - let mut printer = Printer::default(); - printer.write_module(module); - printer.out -} - -/// Print AST to string -pub fn print_ast_node(node: ASTNode) -> String { - let mut printer = Printer::default(); - printer.write_node(node); - printer.out -} diff --git a/kclvm/tools/src/printer/node.rs b/kclvm/tools/src/printer/node.rs deleted file mode 100644 index 20b0947a7..000000000 --- a/kclvm/tools/src/printer/node.rs +++ /dev/null @@ -1,856 +0,0 @@ -use std::collections::HashSet; - -use kclvm_ast::ast::{self, CallExpr}; -use kclvm_ast::token::{DelimToken, TokenKind}; -use kclvm_ast::walker::MutSelfTypedResultWalker; - -use super::{Indentation, Printer}; - -type ParameterType<'a> = ( - ( - &'a ast::NodeRef, - &'a Option>, - ), - &'a Option>, -); - -const COMMA_WHITESPACE: &str = ", "; -const IDENTIFIER_REGEX: &str = r#"^\$?[a-zA-Z_]\w*$"#; - -macro_rules! interleave { - ($inter: expr, $f: expr, $seq: expr) => { - if !$seq.is_empty() { - $f(&$seq[0]); - for s in &$seq[1..] { - $inter(); - $f(s); - } - } - }; -} - -impl<'p, 'ctx> MutSelfTypedResultWalker<'ctx> for Printer<'p> { - type Result = (); - - fn walk_module(&mut self, module: &'ctx ast::Module) -> Self::Result { - for comment in &module.comments { - self.comments.push_back(comment.clone()); - } - self.stmts(&module.body); - } - - fn walk_expr_stmt(&mut self, expr_stmt: &'ctx ast::ExprStmt) -> Self::Result { - interleave!( - || self.write(COMMA_WHITESPACE), - |expr| self.expr(expr), - expr_stmt.exprs - ); - self.write_newline_without_fill(); - } - - fn walk_unification_stmt( - &mut self, - unification_stmt: &'ctx ast::UnificationStmt, - ) -> Self::Result { - self.walk_identifier(&unification_stmt.target.node); - self.write(": "); - self.walk_schema_expr(&unification_stmt.value.node); - self.write_newline_without_fill(); - } - - fn walk_type_alias_stmt(&mut self, type_alias_stmt: &'ctx ast::TypeAliasStmt) -> Self::Result { - self.write("type"); - self.write_space(); - self.walk_identifier(&type_alias_stmt.type_name.node); - self.write(" = "); - self.write(&type_alias_stmt.type_value.node); - self.write_newline_without_fill(); - } - - fn walk_assign_stmt(&mut self, assign_stmt: &'ctx ast::AssignStmt) -> Self::Result { - for (i, target) in assign_stmt.targets.iter().enumerate() { - self.walk_identifier(&target.node); - if i == 0 { - if let Some(ty) = &assign_stmt.ty { - self.write(": "); - self.write(&ty.node.to_string()); - } - } - self.write(" = "); - } - self.expr(&assign_stmt.value); - self.write_newline_without_fill(); - if matches!(assign_stmt.value.node, ast::Expr::Schema(_)) { - self.write_newline_without_fill(); - } - } - - fn walk_aug_assign_stmt(&mut self, aug_assign_stmt: &'ctx ast::AugAssignStmt) -> Self::Result { - self.walk_identifier(&aug_assign_stmt.target.node); - self.write_space(); - self.write(aug_assign_stmt.op.symbol()); - self.write_space(); - self.expr(&aug_assign_stmt.value); - self.write_newline_without_fill(); - } - - fn walk_assert_stmt(&mut self, assert_stmt: &'ctx ast::AssertStmt) -> Self::Result { - self.write("assert "); - self.expr(&assert_stmt.test); - if let Some(if_cond) = &assert_stmt.if_cond { - self.write(" if "); - self.expr(if_cond); - } - if let Some(msg) = &assert_stmt.msg { - self.write(COMMA_WHITESPACE); - self.expr(msg); - } - self.write_newline_without_fill(); - } - - fn walk_if_stmt(&mut self, if_stmt: &'ctx ast::IfStmt) -> Self::Result { - self.write("if "); - self.expr(&if_stmt.cond); - self.write_token(TokenKind::Colon); - self.write_newline_without_fill(); - self.write_indentation(Indentation::Indent); - self.stmts(&if_stmt.body); - self.write_indentation(Indentation::Dedent); - if !if_stmt.orelse.is_empty() { - if let ast::Stmt::If(elif_stmt) = &if_stmt.orelse[0].node { - self.write("el"); - self.walk_if_stmt(elif_stmt); - } else { - self.write("else:"); - self.write_newline(); - self.write_indentation(Indentation::Indent); - self.stmts(&if_stmt.orelse); - self.write_indentation(Indentation::Dedent); - self.write_newline_without_fill(); - } - } else { - self.write_newline_without_fill(); - } - } - - fn walk_import_stmt(&mut self, import_stmt: &'ctx ast::ImportStmt) -> Self::Result { - self.write("import "); - self.write(&import_stmt.path); - if let Some(as_name) = &import_stmt.asname { - self.write(" as "); - self.write(as_name); - } - self.write_newline_without_fill(); - } - - fn walk_schema_stmt(&mut self, schema_stmt: &'ctx ast::SchemaStmt) -> Self::Result { - interleave!( - || self.write_newline(), - |expr: &ast::NodeRef| { - self.write("@"); - self.walk_call_expr(&expr.node); - }, - schema_stmt.decorators - ); - if !schema_stmt.decorators.is_empty() { - self.write_newline(); - } - if schema_stmt.is_mixin { - self.write("mixin "); - } else if schema_stmt.is_protocol { - self.write("protocol "); - } else { - self.write("schema "); - } - self.write(&schema_stmt.name.node); - if let Some(args) = &schema_stmt.args { - self.write("["); - self.walk_arguments(&args.node); - self.write("]"); - } - if let Some(parent_name) = &schema_stmt.parent_name { - self.write("("); - self.walk_identifier(&parent_name.node); - self.write(")"); - } - if let Some(host_name) = &schema_stmt.for_host_name { - self.write(" for "); - self.walk_identifier(&host_name.node); - } - self.write_token(TokenKind::Colon); - self.write_newline_without_fill(); - self.write_indentation(Indentation::Indent); - if !schema_stmt.doc.is_empty() { - self.fill(""); - self.write(&schema_stmt.doc); - self.write_newline_without_fill(); - } - if !schema_stmt.mixins.is_empty() { - self.fill(""); - self.write("mixin ["); - self.write_indentation(Indentation::IndentWithNewline); - interleave!( - || { - self.write(","); - self.write_newline(); - }, - |mixin_name: &ast::NodeRef| self.walk_identifier(&mixin_name.node), - schema_stmt.mixins - ); - self.write_indentation(Indentation::Dedent); - self.write_newline(); - self.write("]"); - self.write_newline_without_fill(); - } - if let Some(index_signature) = &schema_stmt.index_signature { - self.fill(""); - self.write_token(TokenKind::OpenDelim(DelimToken::Bracket)); - if index_signature.node.any_other { - self.write_token(TokenKind::DotDotDot); - } - if let Some(key_name) = &index_signature.node.key_name { - self.write(&format!("{}: ", key_name)); - } - self.write(&index_signature.node.key_type.node); - self.write_token(TokenKind::CloseDelim(DelimToken::Bracket)); - self.write_token(TokenKind::Colon); - self.write_space(); - self.write(&index_signature.node.value_type.node); - if let Some(value) = &index_signature.node.value { - self.write(" = "); - self.expr(value); - } - self.write_newline_without_fill(); - } - self.stmts(&schema_stmt.body); - self.write_newline_without_fill(); - if !schema_stmt.checks.is_empty() { - self.fill("check:"); - // Schema check indent - self.write_indentation(Indentation::IndentWithNewline); - interleave!( - || self.write_newline(), - |check_expr: &ast::NodeRef| self.walk_check_expr(&check_expr.node), - schema_stmt.checks - ); - self.write_newline_without_fill(); - // Schema check dedent - self.write_indentation(Indentation::Dedent); - self.write_newline_without_fill(); - } - // Schema Stmt dedent - self.write_indentation(Indentation::Dedent); - } - - fn walk_rule_stmt(&mut self, rule_stmt: &'ctx ast::RuleStmt) -> Self::Result { - interleave!( - || self.write_newline(), - |expr: &ast::NodeRef| { - self.write("@"); - self.walk_call_expr(&expr.node); - }, - rule_stmt.decorators - ); - if !rule_stmt.decorators.is_empty() { - self.write_newline(); - } - self.write("rule "); - self.write(&rule_stmt.name.node); - if let Some(args) = &rule_stmt.args { - self.write("["); - self.walk_arguments(&args.node); - self.write("]"); - } - if !rule_stmt.parent_rules.is_empty() { - self.write("("); - interleave!( - || self.write(COMMA_WHITESPACE), - |identifier: &ast::NodeRef| self.walk_identifier(&identifier.node), - rule_stmt.parent_rules - ); - self.write(")"); - } - if let Some(host_name) = &rule_stmt.for_host_name { - self.write(" for "); - self.walk_identifier(&host_name.node); - } - self.write_token(TokenKind::Colon); - // Rule Stmt indent - self.write_indentation(Indentation::IndentWithNewline); - if !rule_stmt.doc.is_empty() { - self.write(&rule_stmt.doc); - self.write_newline(); - } - if !rule_stmt.checks.is_empty() { - interleave!( - || self.write_newline(), - |check_expr: &ast::NodeRef| self.walk_check_expr(&check_expr.node), - rule_stmt.checks - ); - self.write_newline_without_fill(); - } - // Rule Stmt dedent - self.write_indentation(Indentation::Dedent); - } - - fn walk_quant_expr(&mut self, quant_expr: &'ctx ast::QuantExpr) -> Self::Result { - let in_one_line = false; - let quant_op_string: String = quant_expr.op.clone().into(); - self.write(&quant_op_string); - self.write_space(); - interleave!( - || self.write(COMMA_WHITESPACE), - |identifier: &ast::NodeRef| self.walk_identifier(&identifier.node), - quant_expr.variables - ); - self.write(" in "); - self.expr(&quant_expr.target); - self.write(" {"); - if !in_one_line { - self.write_indentation(Indentation::IndentWithNewline); - } - self.expr(&quant_expr.test); - if let Some(if_cond) = &quant_expr.if_cond { - self.write(" if "); - self.expr(if_cond); - } - if !in_one_line { - self.write_indentation(Indentation::DedentWithNewline) - } - self.write("}") - } - - fn walk_schema_attr(&mut self, schema_attr: &'ctx ast::SchemaAttr) -> Self::Result { - interleave!( - || self.write_newline(), - |expr: &ast::NodeRef| { - self.write("@"); - self.walk_call_expr(&expr.node) - }, - schema_attr.decorators - ); - if !schema_attr.decorators.is_empty() { - self.write_newline(); - } - self.write(&schema_attr.name.node); - if schema_attr.is_optional { - self.write("?"); - } - self.write(": "); - self.write(&schema_attr.type_str.node); - if let Some(op) = &schema_attr.op { - let symbol = match op { - ast::BinOrAugOp::Bin(bin_op) => bin_op.symbol(), - ast::BinOrAugOp::Aug(aug_op) => aug_op.symbol(), - }; - self.write_space(); - self.write(symbol); - self.write_space(); - } - if let Some(value) = &schema_attr.value { - self.expr(&value); - } - self.write_newline_without_fill(); - } - - fn walk_if_expr(&mut self, if_expr: &'ctx ast::IfExpr) -> Self::Result { - self.expr(&if_expr.body); - self.write(" if "); - self.expr(&if_expr.cond); - self.write(" else "); - self.expr(&if_expr.orelse); - } - - fn walk_unary_expr(&mut self, unary_expr: &'ctx ast::UnaryExpr) -> Self::Result { - self.write(unary_expr.op.symbol()); - self.expr(&unary_expr.operand); - } - - fn walk_binary_expr(&mut self, binary_expr: &'ctx ast::BinaryExpr) -> Self::Result { - let symbol = match &binary_expr.op { - ast::BinOrCmpOp::Bin(bin_op) => bin_op.symbol(), - ast::BinOrCmpOp::Cmp(cmp_op) => cmp_op.symbol(), - }; - self.expr(&binary_expr.left); - self.write_space(); - self.write(symbol); - self.write_space(); - self.expr(&binary_expr.right); - } - - fn walk_selector_expr(&mut self, selector_expr: &'ctx ast::SelectorExpr) -> Self::Result { - self.expr(&selector_expr.value); - self.write(if selector_expr.has_question { - "?." - } else { - "." - }); - self.walk_identifier(&selector_expr.attr.node); - } - - fn walk_call_expr(&mut self, call_expr: &'ctx ast::CallExpr) -> Self::Result { - self.expr(&call_expr.func); - self.write("("); - self.write_args_and_kwargs(&call_expr.args, &call_expr.keywords); - self.write(")"); - } - - fn walk_subscript(&mut self, subscript: &'ctx ast::Subscript) -> Self::Result { - self.expr(&subscript.value); - if subscript.has_question { - self.write("?"); - } - self.write("["); - if let Some(index) = &subscript.index { - self.expr(index); - } else { - if let Some(lower) = &subscript.lower { - self.expr(lower); - } - self.write_token(TokenKind::Colon); - if let Some(upper) = &subscript.upper { - self.expr(upper); - } - self.write_token(TokenKind::Colon); - if let Some(step) = &subscript.step { - self.expr(step); - } - } - self.write("]"); - } - - fn walk_paren_expr(&mut self, paren_expr: &'ctx ast::ParenExpr) -> Self::Result { - self.write_token(TokenKind::OpenDelim(DelimToken::Paren)); - self.expr(&paren_expr.expr); - self.write_token(TokenKind::CloseDelim(DelimToken::Paren)); - } - - fn walk_list_expr(&mut self, list_expr: &'ctx ast::ListExpr) -> Self::Result { - let line_set = list_expr - .elts - .iter() - .map(|e| e.line) - .collect::>(); - let mut in_one_line = line_set.len() <= 1; - if let Some(elt) = list_expr.elts.first() { - if let ast::Expr::ListIfItem(_) = &elt.node { - in_one_line = false; - } - } - self.write_token(TokenKind::OpenDelim(DelimToken::Bracket)); - if !in_one_line { - self.write_indentation(Indentation::IndentWithNewline); - } - interleave!( - || if in_one_line { - self.write(COMMA_WHITESPACE); - } else { - self.write_newline(); - }, - |elt| self.expr(elt), - list_expr.elts - ); - if !in_one_line { - self.write_indentation(Indentation::DedentWithNewline); - } - self.write_token(TokenKind::CloseDelim(DelimToken::Bracket)); - } - - fn walk_list_comp(&mut self, list_comp: &'ctx ast::ListComp) -> Self::Result { - self.write_token(TokenKind::OpenDelim(DelimToken::Bracket)); - self.expr(&list_comp.elt); - for gen in &list_comp.generators { - self.walk_comp_clause(&gen.node); - } - self.write_token(TokenKind::CloseDelim(DelimToken::Bracket)); - } - - fn walk_list_if_item_expr( - &mut self, - list_if_item_expr: &'ctx ast::ListIfItemExpr, - ) -> Self::Result { - self.write("if "); - self.expr(&list_if_item_expr.if_cond); - self.write(":"); - self.write_indentation(Indentation::IndentWithNewline); - interleave!( - || self.write_newline(), - |expr| self.expr(expr), - list_if_item_expr.exprs - ); - self.write_indentation(Indentation::DedentWithNewline); - if let Some(orelse) = &list_if_item_expr.orelse { - match &orelse.node { - ast::Expr::List(list_expr) => { - self.write("else:"); - self.write_indentation(Indentation::IndentWithNewline); - interleave!( - || self.write_newline(), - |expr| self.expr(expr), - list_expr.elts - ); - self.write_indentation(Indentation::Dedent); - } - ast::Expr::ListIfItem(_) => { - self.write("el"); - self.expr(orelse); - } - _ => bug!("Invalid list if expr orelse node {:?}", orelse.node), - } - } - } - - fn walk_starred_expr(&mut self, starred_expr: &'ctx ast::StarredExpr) -> Self::Result { - self.write("*"); - self.expr(&starred_expr.value) - } - - fn walk_dict_comp(&mut self, dict_comp: &'ctx ast::DictComp) -> Self::Result { - self.write_token(TokenKind::OpenDelim(DelimToken::Brace)); - self.expr(match &dict_comp.entry.key { - Some(key) => key, - None => bug!("Invalid dict comp key"), - }); - if !matches!(dict_comp.entry.operation, ast::ConfigEntryOperation::Union) { - self.write_space(); - } - self.write(dict_comp.entry.operation.symbol()); - self.write_space(); - for gen in &dict_comp.generators { - self.walk_comp_clause(&gen.node); - } - self.write_token(TokenKind::CloseDelim(DelimToken::Brace)); - } - - fn walk_config_if_entry_expr( - &mut self, - config_if_entry_expr: &'ctx ast::ConfigIfEntryExpr, - ) -> Self::Result { - self.write("if "); - self.expr(&config_if_entry_expr.if_cond); - self.write_token(TokenKind::Colon); - self.write_indentation(Indentation::IndentWithNewline); - interleave!( - || self.write_newline(), - |entry: &ast::NodeRef| self.write_entry(entry), - config_if_entry_expr.items - ); - self.write_indentation(Indentation::DedentWithNewline); - if let Some(orelse) = &config_if_entry_expr.orelse { - match &orelse.node { - ast::Expr::Config(config_expr) => { - self.write("else:"); - self.write_indentation(Indentation::IndentWithNewline); - interleave!( - || self.write_newline(), - |entry: &ast::NodeRef| self.write_entry(entry), - config_expr.items - ); - self.write_indentation(Indentation::Dedent); - } - ast::Expr::ConfigIfEntry(_) => { - self.write("el"); - self.expr(orelse); - } - _ => bug!("Invalid config if expr orelse node {:?}", orelse.node), - } - } - } - - fn walk_comp_clause(&mut self, comp_clause: &'ctx ast::CompClause) -> Self::Result { - self.write(" for "); - interleave!( - || self.write(COMMA_WHITESPACE), - |target: &ast::NodeRef| self.walk_identifier(&target.node), - comp_clause.targets - ); - self.write(" in "); - self.expr(&comp_clause.iter); - for if_clause in &comp_clause.ifs { - self.write(" if "); - self.expr(if_clause); - } - } - - fn walk_schema_expr(&mut self, schema_expr: &'ctx ast::SchemaExpr) -> Self::Result { - self.walk_identifier(&schema_expr.name.node); - if !schema_expr.args.is_empty() || !schema_expr.kwargs.is_empty() { - self.write_token(TokenKind::OpenDelim(DelimToken::Paren)); - self.write_args_and_kwargs(&schema_expr.args, &schema_expr.kwargs); - self.write_token(TokenKind::CloseDelim(DelimToken::Paren)); - } - self.write_space(); - self.expr(&schema_expr.config) - } - - fn walk_config_expr(&mut self, config_expr: &'ctx ast::ConfigExpr) -> Self::Result { - let line_set: HashSet = config_expr.items.iter().map(|item| item.line).collect(); - let mut in_one_line = line_set.len() <= 1; - if let Some(item) = config_expr.items.first() { - if let ast::Expr::ConfigIfEntry(_) = &item.node.value.node { - in_one_line = false; - } - } - self.write_token(TokenKind::OpenDelim(DelimToken::Brace)); - if !config_expr.items.is_empty() { - if !in_one_line { - self.write_indentation(Indentation::IndentWithNewline); - } - interleave!( - || if in_one_line { - self.write(COMMA_WHITESPACE); - } else { - self.write_newline(); - }, - |entry: &ast::NodeRef| self.write_entry(entry), - config_expr.items - ); - if !in_one_line { - self.write_indentation(Indentation::DedentWithNewline); - } - } - self.write_token(TokenKind::CloseDelim(DelimToken::Brace)); - } - - fn walk_check_expr(&mut self, check_expr: &'ctx ast::CheckExpr) -> Self::Result { - self.expr(&check_expr.test); - if let Some(if_cond) = &check_expr.if_cond { - self.write(" if "); - self.expr(if_cond); - } - if let Some(msg) = &check_expr.msg { - self.write(COMMA_WHITESPACE); - self.expr(msg); - } - } - - fn walk_lambda_expr(&mut self, lambda_expr: &'ctx ast::LambdaExpr) -> Self::Result { - self.write("lambda"); - if let Some(args) = &lambda_expr.args { - self.write_space(); - self.walk_arguments(&args.node); - } - if let Some(ty_str) = &lambda_expr.return_type_str { - self.write_space(); - self.write_token(TokenKind::RArrow); - self.write_space(); - self.write(ty_str); - } - self.write_space(); - self.write_token(TokenKind::OpenDelim(DelimToken::Brace)); - self.write_newline(); - self.write_indentation(Indentation::Indent); - - // lambda body - self.stmts(&lambda_expr.body); - - self.write_indentation(Indentation::Dedent); - self.write_newline(); - self.write_token(TokenKind::CloseDelim(DelimToken::Brace)); - } - - fn walk_keyword(&mut self, keyword: &'ctx ast::Keyword) -> Self::Result { - self.walk_identifier(&keyword.arg.node); - if let Some(value) = &keyword.value { - self.write("="); - self.expr(value); - } - } - - fn walk_arguments(&mut self, arguments: &'ctx ast::Arguments) -> Self::Result { - let parameter_zip_list: Vec> = arguments - .args - .iter() - .zip(arguments.type_annotation_list.iter()) - .zip(arguments.defaults.iter()) - .collect(); - interleave!( - || self.write(COMMA_WHITESPACE), - |para: &ParameterType<'_>| { - let ((arg, ty_str), default) = para; - self.walk_identifier(&arg.node); - if let Some(ty_str) = ty_str { - self.write(&format!(": {}", ty_str.node)); - } - if let Some(default) = default { - self.write(" = "); - self.expr(default); - } - }, - parameter_zip_list - ); - } - - fn walk_compare(&mut self, compare: &'ctx ast::Compare) -> Self::Result { - self.expr(&compare.left); - for (op, expr) in compare.ops.iter().zip(compare.comparators.iter()) { - self.write_space(); - self.write(op.symbol()); - self.write_space(); - self.expr(expr); - } - } - - #[inline] - fn walk_identifier(&mut self, identifier: &'ctx ast::Identifier) -> Self::Result { - self.write(&identifier.get_name()); - } - - fn walk_number_lit(&mut self, number_lit: &'ctx ast::NumberLit) -> Self::Result { - match number_lit.value { - ast::NumberLitValue::Int(int_val) => self.write(&int_val.to_string()), - ast::NumberLitValue::Float(float_val) => self.write(&float_val.to_string()), - } - } - - fn walk_string_lit(&mut self, string_lit: &'ctx ast::StringLit) -> Self::Result { - if !string_lit.raw_value.is_empty() { - self.write(&string_lit.raw_value) - } else { - self.write(&format!("\"{}\"", string_lit.value.replace('\"', "\\\""))); - } - } - - #[inline] - fn walk_name_constant_lit( - &mut self, - name_constant_lit: &'ctx ast::NameConstantLit, - ) -> Self::Result { - self.write(name_constant_lit.value.symbol()); - } - - fn walk_joined_string(&mut self, joined_string: &'ctx ast::JoinedString) -> Self::Result { - self.write("\""); - for value in &joined_string.values { - match &value.node { - ast::Expr::StringLit(string_lit) => { - self.write(&string_lit.value.replace('\"', "\\\"")); - } - _ => self.expr(value), - } - } - self.write("\""); - } - - fn walk_formatted_value(&mut self, formatted_value: &'ctx ast::FormattedValue) -> Self::Result { - self.write("${"); - self.expr(&formatted_value.value); - if let Some(spec) = &formatted_value.format_spec { - self.write(&format!(": {}", spec)); - } - self.write("}"); - } - - fn walk_comment(&mut self, comment: &'ctx ast::Comment) -> Self::Result { - self.writeln(&comment.text); - self.fill(""); - } -} - -impl<'p> Printer<'p> { - pub fn write_args_and_kwargs( - &mut self, - args: &[ast::NodeRef], - kwargs: &[ast::NodeRef], - ) { - interleave!(|| self.write(COMMA_WHITESPACE), |arg| self.expr(arg), args); - if !args.is_empty() && !kwargs.is_empty() { - self.write(COMMA_WHITESPACE); - } - interleave!( - || self.write(COMMA_WHITESPACE), - |kwarg: &ast::NodeRef| self.walk_keyword(&kwarg.node), - kwargs - ); - } - - pub fn write_entry(&mut self, item: &ast::NodeRef) { - match &item.node.key { - Some(key) => { - let print_right_brace_count = self.write_config_key(key); - if item.node.insert_index >= 0 { - self.write(&format!("[{}]", item.node.insert_index)); - } - if !matches!(item.node.operation, ast::ConfigEntryOperation::Union) { - self.write_space(); - } - self.write(item.node.operation.symbol()); - self.write_space(); - self.expr(&item.node.value); - self.write(&"}".repeat(print_right_brace_count)); - } - None => { - if !matches!(&item.node.value.node, ast::Expr::ConfigIfEntry(_)) { - self.write("**"); - } - self.expr(&item.node.value) - } - }; - } - - fn write_config_key(&mut self, key: &ast::NodeRef) -> usize { - match &key.node { - ast::Expr::Identifier(identifier) => { - self.hook.pre(self, super::ASTNode::Expr(key)); - self.write_ast_comments(key); - // Judge contains string identifier, e.g., "x-y-z" - let names = &identifier.names; - - let re = fancy_regex::Regex::new(IDENTIFIER_REGEX).unwrap(); - let need_right_brace = !names.iter().all(|n| re.is_match(n).unwrap_or(false)); - let count = if need_right_brace { - self.write( - &names - .iter() - .map(|n| n.replace('\"', "\\\"")) - .collect::>() - .join(": {"), - ); - names.len() - 1 - } else { - self.expr(key); - 0 - }; - self.hook.post(self, super::ASTNode::Expr(key)); - count - } - _ => { - self.expr(key); - 0 - } - } - } -} - -impl<'p> Printer<'p> { - // ------------------------------ - // Expr and Stmt walker functions - // ------------------------------ - - pub fn expr(&mut self, expr: &ast::NodeRef) { - self.hook.pre(self, super::ASTNode::Expr(expr)); - self.write_ast_comments(expr); - self.walk_expr(&expr.node); - self.hook.post(self, super::ASTNode::Expr(expr)); - } - - pub fn stmt(&mut self, stmt: &ast::NodeRef) { - self.hook.pre(self, super::ASTNode::Stmt(stmt)); - self.fill(""); - self.write_ast_comments(stmt); - self.walk_stmt(&stmt.node); - self.hook.post(self, super::ASTNode::Stmt(stmt)); - } - - pub fn exprs(&mut self, exprs: &[ast::NodeRef]) { - for expr in exprs { - self.expr(expr); - } - } - - pub fn stmts(&mut self, stmts: &[ast::NodeRef]) { - for stmt in stmts { - self.stmt(stmt); - } - } -} diff --git a/kclvm/tools/src/printer/test_data/codelayout.input b/kclvm/tools/src/printer/test_data/codelayout.input deleted file mode 100644 index b8eeb768d..000000000 --- a/kclvm/tools/src/printer/test_data/codelayout.input +++ /dev/null @@ -1,76 +0,0 @@ - - - -import math as alias_math -schema Person ( Base): - name:str - age:int - check : - age>0 if age , "age must > 0" -person = Person{ - name:"Alice" - age:18 -} -if True: - a = 1 -elif True: - b = 2 -else: - c = 3 -d = 1 + 2 -e = ( 1 + 2 ) -f=[ 1, 2, 3 ] -g = { "key" : "value" } -print (1) -dct={"key": "value"} -lst=[1,2,3] -h = dct [ 'key' ] -i = lst [ 1 ] -x = 1 -y = 2 -long_variable = 3 -i = i+1 -submitted+=1 -x = x*2 - 1 -hypot2 = x*x + y*y -_c = (a+b) * (a-b) -_b=2 -_c= 3 -_d =4 - -_value = (1 + 2 * 3) -_value = (1+2*3) -_value =1+ - 2 * ~ 3 -_list = [1, 2, 3] -_list = [*_list, [4, 5 ,6]] -_list = [* _list, [4, 5 ,6]] - -_dict = {** {"k": "v"}, ** {"k": "v"}} -a = [1,2,3] -b = [ - 1,2,3, - 4,5,6, -] -_dict={ - "k1":"v1" - "k2" :"v2" - "k3": "v3" - "k4" : "v4" - "k5" : "v5" -} -foo=1 -if foo is not None: - _a = 1 - _dict|={} - hello = "world{}" . format( 1 )[2 : 4] . lower( ) - range_int = [ i for i in range( 10 ) ] -op = 1+2 - - 3 + (3 - 1) // 3 -op += 1 -op -= 12 + 23 -print( " " , end= '') -log = math. log(12) -aa = 1 -assert aa == 1,"message" -assert aa == 1 if aa,"message" -aaaa = (1 + 2 / 2) if _a == 2 + + 134.3 else ("a"*3) -bbbb = "{}". format(a) \ No newline at end of file diff --git a/kclvm/tools/src/printer/test_data/codelayout.output b/kclvm/tools/src/printer/test_data/codelayout.output deleted file mode 100644 index 61df4a554..000000000 --- a/kclvm/tools/src/printer/test_data/codelayout.output +++ /dev/null @@ -1,80 +0,0 @@ -import math as alias_math -schema Person(Base): - name: str - age: int - - check: - age > 0 if age, "age must > 0" - -person = Person { - name: "Alice" - age: 18 -} - -if True: - a = 1 -elif True: - b = 2 -else: - c = 3 - -d = 1 + 2 -e = (1 + 2) -f = [1, 2, 3] -g = {"key": "value"} -print(1) -dct = {"key": "value"} -lst = [1, 2, 3] -h = dct['key'] -i = lst[1] -x = 1 -y = 2 -long_variable = 3 -i = i + 1 -submitted += 1 -x = x * 2 - 1 -hypot2 = x * x + y * y -_c = (a + b) * (a - b) -_b = 2 -_c = 3 -_d = 4 -_value = (1 + 2 * 3) -_value = (1 + 2 * 3) -_value = 1 + -2 * ~3 -_list = [1, 2, 3] -_list = [*_list, [4, 5, 6]] -_list = [*_list, [4, 5, 6]] -_dict = {**{"k": "v"}, **{"k": "v"}} -a = [1, 2, 3] -b = [ - 1 - 2 - 3 - 4 - 5 - 6 -] -_dict = { - "k1": "v1" - "k2": "v2" - "k3": "v3" - "k4": "v4" - "k5": "v5" -} -foo = 1 -if foo is not None: - _a = 1 - _dict |= {} - hello = "world{}".format(1)[2:4:].lower() - range_int = [i for i in range(10)] - -op = 1 + 2 - -3 + (3 - 1) // 3 -op += 1 -op -= 12 + 23 -print(" ", end='') -log = math.log(12) -aa = 1 -assert aa == 1, "message" -assert aa == 1 if aa, "message" -aaaa = (1 + 2 / 2) if _a == 2 + +134.3 else ("a" * 3) -bbbb = "{}".format(a) diff --git a/kclvm/tools/src/printer/test_data/collection_if.input b/kclvm/tools/src/printer/test_data/collection_if.input deleted file mode 100644 index 080538c1c..000000000 --- a/kclvm/tools/src/printer/test_data/collection_if.input +++ /dev/null @@ -1,51 +0,0 @@ -schema Config: - name: str - env: str - data: [int] -env = "env" -data1 = Config { - if env == "env": - name: env - env: env - data += [0] - else: - name = "name" - env = "name" - data += [1] -} -data1 = Config { - if env == "env": - name: env - env: env - else: - name: "name" - env: "name" -} -data2 = Config { - if env != "env": - name: env - env: env - else: - name: "name" - env: "name" -} -data3 = { - if True: - key1: "value1" - elif True: - key2: "value2" - elif True: - key3: "value3" - else: - key4: "value4" -} -data4 = [ - if True: - "value1" - elif True: - "value2" - elif True: - "value3" - else: - "value4" -] diff --git a/kclvm/tools/src/printer/test_data/collection_if.output b/kclvm/tools/src/printer/test_data/collection_if.output deleted file mode 100644 index 009f8947a..000000000 --- a/kclvm/tools/src/printer/test_data/collection_if.output +++ /dev/null @@ -1,55 +0,0 @@ -schema Config: - name: str - env: str - data: [int] - -env = "env" -data1 = Config { - if env == "env": - name: env - env: env - data += [0] - else: - name = "name" - env = "name" - data += [1] -} - -data1 = Config { - if env == "env": - name: env - env: env - else: - name: "name" - env: "name" -} - -data2 = Config { - if env != "env": - name: env - env: env - else: - name: "name" - env: "name" -} - -data3 = { - if True: - key1: "value1" - elif True: - key2: "value2" - elif True: - key3: "value3" - else: - key4: "value4" -} -data4 = [ - if True: - "value1" - elif True: - "value2" - elif True: - "value3" - else: - "value4" -] diff --git a/kclvm/tools/src/printer/test_data/comment.input b/kclvm/tools/src/printer/test_data/comment.input deleted file mode 100644 index 681a69c31..000000000 --- a/kclvm/tools/src/printer/test_data/comment.input +++ /dev/null @@ -1,38 +0,0 @@ -# Comment One -schema Main: - name?: str - env?: [{str:}] - -# Comment Two -schema AppConfiguration: - appName: str - image: str - overQuota: bool = False - resource: {str:} - mainContainer?: Main - labels: {str:} - -# Comment Three -appConfiguration = AppConfiguration { - # Comment Four - appName: "kusion" - image: "test-image:v1" # Comment Five - resource: { - cpu: "4" - disk: "50Gi" - memory: "12Gi" - } - labels: { - key: { - key: 12 - } - } - # Comment Six - mainContainer: Main { - name: "kusion_override" - }# Comment Seven - - # Comment Eight - overQuota: True -} -# Comment Nine diff --git a/kclvm/tools/src/printer/test_data/comment.output b/kclvm/tools/src/printer/test_data/comment.output deleted file mode 100644 index bae5a376c..000000000 --- a/kclvm/tools/src/printer/test_data/comment.output +++ /dev/null @@ -1,34 +0,0 @@ -# Comment One -schema Main: - name?: str - env?: [{str:}] - -# Comment Two -schema AppConfiguration: - appName: str - image: str - overQuota: bool = False - resource: {str:} - mainContainer?: Main - labels: {str:} - -# Comment Three -appConfiguration = AppConfiguration { - # Comment Four - appName: "kusion" - # Comment Five - image: "test-image:v1" - resource: { - cpu: "4" - disk: "50Gi" - memory: "12Gi" - } - labels: {key: {key: 12}} - # Comment Six - mainContainer: Main {name: "kusion_override"} - # Comment Seven - # Comment Eight - overQuota: True -} - -# Comment Nine diff --git a/kclvm/tools/src/printer/test_data/lambda.input b/kclvm/tools/src/printer/test_data/lambda.input deleted file mode 100644 index 5402976ca..000000000 --- a/kclvm/tools/src/printer/test_data/lambda.input +++ /dev/null @@ -1,20 +0,0 @@ -sumFunc1 = lambda x, y { - z = x + y - z + x -} -sumFunc2 = lambda x, y = 1 { - x + y - -} -sumFunc3 = lambda x = 1, y = 1 { - x + y - -} -sumFunc4 = lambda x: int = 1, y: int = 1 -> int { - x + y - -} -x0 = sumFunc1(1, 2) -x1 = sumFunc1(2, 3) -x2 = sumFunc1(3, 4) -x3 = sumFunc1(4, 5) diff --git a/kclvm/tools/src/printer/test_data/lambda.output b/kclvm/tools/src/printer/test_data/lambda.output deleted file mode 100644 index db23acee4..000000000 --- a/kclvm/tools/src/printer/test_data/lambda.output +++ /dev/null @@ -1,21 +0,0 @@ -sumFunc1 = lambda x, y { - z = x + y - z + x - -} -sumFunc2 = lambda x, y = 1 { - x + y - -} -sumFunc3 = lambda x = 1, y = 1 { - x + y - -} -sumFunc4 = lambda x: int = 1, y: int = 1 -> int { - x + y - -} -x0 = sumFunc1(1, 2) -x1 = sumFunc1(2, 3) -x2 = sumFunc1(3, 4) -x3 = sumFunc1(4, 5) diff --git a/kclvm/tools/src/printer/test_data/quant.output b/kclvm/tools/src/printer/test_data/quant.output deleted file mode 100644 index 4d35a3ba6..000000000 --- a/kclvm/tools/src/printer/test_data/quant.output +++ /dev/null @@ -1,12 +0,0 @@ -a = all x in [-1, 0, 1, 2, 3] { - x >= 1 if x > 0 -} -b = any x in {k1 = "v1", k2 = "v2"} { - x in ["k1", "v2"] -} -c = map x in {k1 = "v1", k2 = "v2"} { - x -} -d = filter x in [1, 2, 3] { - x > 1 -} diff --git a/kclvm/tools/src/printer/test_data/rule.output b/kclvm/tools/src/printer/test_data/rule.output deleted file mode 100644 index 6d4543302..000000000 --- a/kclvm/tools/src/printer/test_data/rule.output +++ /dev/null @@ -1,16 +0,0 @@ -age = 1 -protocol MainProtocol: - """Protocol doc""" - var: int - -mixin MainMixin for MainProtocol: - var: int - -@deprecated() -rule Base: - """Rule doc""" - age > 0 - age < 10 -rule Main[var](Base) for MainProtocol: - var -Main(1) diff --git a/kclvm/tools/src/printer/test_data/type_alias.output b/kclvm/tools/src/printer/test_data/type_alias.output deleted file mode 100644 index d80ac1c1b..000000000 --- a/kclvm/tools/src/printer/test_data/type_alias.output +++ /dev/null @@ -1,13 +0,0 @@ -type Color = "Red"|"Yellow"|"Blue" -colorRed: Color = "Red" -colorYellow: Color = "Yellow" -colorBlue: Color = "Blue" -schema Data: - color: Color - -dataColorRed = Data {color = "Red"} - -dataColorYellow = Data {color = "Yellow"} - -dataColorBlue = Data {color = "Blue"} - diff --git a/kclvm/tools/src/printer/test_data/unification.output b/kclvm/tools/src/printer/test_data/unification.output deleted file mode 100644 index 4db7bd2d5..000000000 --- a/kclvm/tools/src/printer/test_data/unification.output +++ /dev/null @@ -1,4 +0,0 @@ -schema Config: - name: str - -config: Config {name = "name"} diff --git a/kclvm/tools/src/printer/tests.rs b/kclvm/tools/src/printer/tests.rs deleted file mode 100644 index 786221c32..000000000 --- a/kclvm/tools/src/printer/tests.rs +++ /dev/null @@ -1,44 +0,0 @@ -use super::*; -use kclvm_parser::parse_file; -use pretty_assertions::assert_eq; - -const FILE_INPUT_SUFFIX: &str = ".input"; -const FILE_OUTPUT_SUFFIX: &str = ".output"; -const TEST_CASES: &[&'static str; 12] = &[ - "arguments", - "empty", - "codelayout", - "collection_if", - "comment", - "index_sign", - "joined_str", - "lambda", - "quant", - "rule", - "type_alias", - "unification", -]; - -fn read_data(data_name: &str) -> (String, String) { - let module = parse_file( - &format!("./src/printer/test_data/{}{}", data_name, FILE_INPUT_SUFFIX), - None, - ); - - ( - print_ast_module(&module.unwrap()), - std::fs::read_to_string(&format!( - "./src/printer/test_data/{}{}", - data_name, FILE_OUTPUT_SUFFIX - )) - .unwrap(), - ) -} - -#[test] -fn test_ast_printer() { - for case in TEST_CASES { - let (data_input, data_output) = read_data(case); - assert_eq!(data_input, data_output, "Test failed on {}", case); - } -} diff --git a/kclvm/tools/src/query/mod.rs b/kclvm/tools/src/query/mod.rs deleted file mode 100644 index 54781f51d..000000000 --- a/kclvm/tools/src/query/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ -pub mod r#override; - -pub use r#override::apply_overrides; diff --git a/kclvm/tools/src/query/override.rs b/kclvm/tools/src/query/override.rs deleted file mode 100644 index 638d7f4ea..000000000 --- a/kclvm/tools/src/query/override.rs +++ /dev/null @@ -1,181 +0,0 @@ -use kclvm_ast::walker::MutSelfMutWalker; -use kclvm_ast::{ast, walk_if_mut}; -use kclvm_parser::parse_expr; - -pub struct OverrideInfo { - pub pkgpath: String, - pub filename: String, - pub module: ast::Module, -} - -pub fn apply_overrides( - prog: &mut ast::Program, - overrides: &[ast::CmdOverrideSpec], - _import_paths: &[String], -) { - for o in overrides { - let pkgpath = if o.pkgpath.is_empty() { - &prog.main - } else { - &o.pkgpath - }; - match prog.pkgs.get_mut(pkgpath) { - Some(modules) => { - for m in modules.iter_mut() { - if fix_module_override(m, o) {} - // module_add_import_paths(m, import_paths) - } - } - None => {} - } - } -} - -pub fn fix_module_override(m: &mut ast::Module, o: &ast::CmdOverrideSpec) -> bool { - let ss = o.field_path.split(".").collect::>(); - if ss.len() <= 1 { - false - } else { - let target_id = ss[0]; - let field = ss[1..].join("."); - let value = &o.field_value; - let key = ast::Identifier { - names: field.split(".").map(|s| s.to_string()).collect(), - ctx: ast::ExprContext::Store, - pkgpath: "".to_string(), - }; - let val = build_node_from_string(value); - let mut transformer = OverrideTransformer { - target_id: target_id.to_string(), - field_path: field, - override_key: key, - override_value: val, - override_target_count: 0, - has_override: false, - action: o.action.clone(), - }; - transformer.walk_module(m); - transformer.has_override - } -} - -pub fn build_node_from_string(value: &str) -> ast::NodeRef { - let expr = parse_expr(value); - expr -} - -pub struct OverrideTransformer { - pub target_id: String, - pub field_path: String, - pub override_key: ast::Identifier, - pub override_value: ast::NodeRef, - pub override_target_count: usize, - pub has_override: bool, - pub action: ast::OverrideAction, -} - -impl<'ctx> MutSelfMutWalker<'ctx> for OverrideTransformer { - fn walk_schema_stmt(&mut self, _: &'ctx mut ast::SchemaStmt) { - // Do not override AssignStmt in SchemaStmt - } - - fn walk_unification_stmt(&mut self, unification_stmt: &'ctx mut ast::UnificationStmt) { - if unification_stmt.target.node.names[0] != self.target_id { - return; - } - self.override_target_count = 1; - self.has_override = true; - self.walk_schema_expr(&mut unification_stmt.value.node); - } - - fn walk_assign_stmt(&mut self, assign_stmt: &'ctx mut ast::AssignStmt) { - if let ast::Expr::Schema(_) = &assign_stmt.value.node { - self.override_target_count = 0; - for target in &assign_stmt.targets { - if target.node.names.len() != 1 { - continue; - } - if target.node.names[0] != self.target_id { - continue; - } - self.override_target_count += 1; - } - if self.override_target_count == 0 { - return; - } - self.has_override = true; - self.walk_expr(&mut assign_stmt.value.node); - } - } - - fn walk_schema_expr(&mut self, schema_expr: &'ctx mut ast::SchemaExpr) { - if self.override_target_count == 0 { - return; - } - if true { - // Not exist and append an override value when the action is CREATE_OR_UPDATE - if let ast::OverrideAction::CreateOrUpdate = self.action { - if let ast::Expr::Config(config_expr) = &mut schema_expr.config.node { - config_expr - .items - .push(Box::new(ast::Node::dummy_node(ast::ConfigEntry { - key: Some(Box::new(ast::Node::dummy_node(ast::Expr::Identifier( - self.override_key.clone(), - )))), - value: self.override_value.clone(), - operation: ast::ConfigEntryOperation::Override, - insert_index: -1, - }))); - } - } - } - self.override_target_count = 0; - } - - fn walk_config_expr(&mut self, config_expr: &'ctx mut ast::ConfigExpr) { - for config_entry in config_expr.items.iter_mut() { - walk_if_mut!(self, walk_expr, config_entry.node.key); - self.walk_expr(&mut config_entry.node.value.node); - } - } -} - -impl OverrideTransformer { - pub(crate) fn _get_schema_config_field_paths( - &mut self, - schema_expr: &mut ast::SchemaExpr, - ) -> (Vec, Vec) { - if let ast::Expr::Config(config_expr) = &mut schema_expr.config.node { - self._get_config_field_paths(config_expr) - } else { - (vec![], vec![]) - } - } - pub(crate) fn _get_config_field_paths( - &mut self, - config: &mut ast::ConfigExpr, - ) -> (Vec, Vec) { - let mut paths = vec![]; - let mut paths_with_id = vec![]; - for entry in config.items.iter_mut() { - let (mut _paths, mut _paths_with_id) = self._get_key_value_paths(&mut entry.node); - paths.append(&mut _paths); - paths_with_id.append(&mut &mut _paths_with_id); - } - (paths, paths_with_id) - } - pub(crate) fn _get_key_value_paths( - &mut self, - _entry: &mut ast::ConfigEntry, - ) -> (Vec, Vec) { - (vec![], vec![]) - } - pub(crate) fn _find_schema_config_and_repalce( - &mut self, - _schema_config: &mut ast::SchemaExpr, - _field_path: &str, - _value: &ast::NodeRef, - ) -> bool { - false - } -} diff --git a/kclvm/tools/src/testing/mod.rs b/kclvm/tools/src/testing/mod.rs new file mode 100644 index 000000000..88aa328fa --- /dev/null +++ b/kclvm/tools/src/testing/mod.rs @@ -0,0 +1,58 @@ +//! [kclvm_tools::testing] module mainly contains some functions of language testing tool. +//! +//! The basic principle of the testing tool is to search for test files in the KCL package +//! that have the suffix "_test.k" and do not start with "_". These test files will be regard +//! as test suites. Within these files, any lambda literals starting with "test_" will be +//! considered as test cases, but these lambda functions should not have any parameters. +//! To perform the testing, the tool compiles the test suite file and its dependencies into an +//! [kclvm_runner::Artifact], which is regard as a new compilation entry point. Then, +//! it executes each test case separately and collects information about the test cases, +//! such as the execution time and whether the test passes or fails. +pub use crate::testing::suite::{load_test_suites, TestSuite}; +use anyhow::{Error, Result}; +use indexmap::IndexMap; +use kclvm_runner::ExecProgramArgs; +use std::time::Duration; + +mod suite; + +#[cfg(test)] +mod tests; + +/// Trait for running tests. +pub trait TestRun { + type Options; + type Result; + + /// Run the test with the given options and return the result. + fn run(&self, opts: &Self::Options) -> Result; +} + +/// Represents the result of a test. +#[derive(Debug, Default)] +pub struct TestResult { + /// This field stores test case information in an [IndexMap], where the key is a [String] and the value is a [TestCaseInfo] struct. + pub info: IndexMap, +} + +/// Represents information about a test case. +#[derive(Debug, Default)] +pub struct TestCaseInfo { + /// This field stores the log message of the test. + pub log_message: String, + /// This field stores the error associated with the test case, if any. + pub error: Option, + /// This field stores the duration of the test case. + pub duration: Duration, +} + +/// Represents options for running tests. +#[derive(Debug, Default, Clone)] +pub struct TestOptions { + /// This field stores the execution program arguments. + pub exec_args: ExecProgramArgs, + /// This field stores a regular expression for filtering tests to run. + pub run_regexp: String, + /// This field determines whether the test run should stop on the first failure. + pub fail_fast: bool, +} diff --git a/kclvm/tools/src/testing/suite.rs b/kclvm/tools/src/testing/suite.rs new file mode 100644 index 000000000..2d07d66e9 --- /dev/null +++ b/kclvm/tools/src/testing/suite.rs @@ -0,0 +1,223 @@ +use std::{fs::remove_file, path::Path}; + +use crate::testing::{TestCaseInfo, TestOptions, TestResult, TestRun}; +use anyhow::{anyhow, Result}; +use indexmap::IndexMap; +use kclvm_ast::ast; +use kclvm_driver::get_pkg_list; +use kclvm_parser::get_kcl_files; +use kclvm_parser::{parse_file_force_errors, ParseSessionRef}; +#[cfg(feature = "llvm")] +use kclvm_runner::build_program; +use kclvm_runner::exec_program; +#[cfg(feature = "llvm")] +use kclvm_runner::runner::ProgramRunner; +use kclvm_runner::{Artifact, ExecProgramArgs, KCL_FAST_EVAL_ENV_VAR}; +use std::time::Instant; + +/// File suffix for test files. +pub const TEST_FILE_SUFFIX: &str = "_test.k"; +/// Prefix for test suite names. +pub const TEST_SUITE_PREFIX: &str = "test_"; + +const TEST_MAIN_FILE: &str = "_kcl_test.k"; +const TEST_CASE_RUN_OPTION: &str = "_kcl_test_case_run"; +const TEST_MAIN_FILE_PREFIX: &str = r#" +# Auto generated by the kcl test tool; DO NOT EDIT! + +_kcl_test_case_run = option("_kcl_test_case_run", type="str", default="") + +"#; + +pub struct TestSuite { + /// Package path of the test suite. e.g. ./path/to/pkg + pub pkg: String, + /// List of normal files in the package. + pub normal_files: Vec, + /// List of normal files without the `_test.k` suffix in the package. + pub test_files: Vec, + // Map of test cases in the test suite. + pub cases: IndexMap, + // Flag indicating whether the test suite should be skipped. + pub skip: bool, +} + +impl TestRun for TestSuite { + type Options = TestOptions; + type Result = TestResult; + + /// Run the test suite with the given options and return the result. + fn run(&self, opts: &Self::Options) -> Result { + let mut result = TestResult::default(); + // Skip test suite if marked as skipped or if there are no test cases. + if self.skip || self.cases.is_empty() { + return Ok(result); + } + // Generate the test main entry file. + let main_file = self.gen_test_main_file()?; + // Set up execution arguments. + let mut args = ExecProgramArgs { + k_filename_list: self.get_input_files(&main_file), + overrides: vec![], + disable_yaml_result: true, + ..opts.exec_args.clone() + }; + let is_fast_eval_mode = std::env::var(KCL_FAST_EVAL_ENV_VAR).is_ok(); + // Build the program + let artifact: Option = if is_fast_eval_mode { + None + } else { + #[cfg(feature = "llvm")] + let artifact = Some(build_program::( + ParseSessionRef::default(), + &args, + None, + )?); + #[cfg(not(feature = "llvm"))] + let artifact = None; + artifact + }; + // Save the user argument options. + let user_args = args.args; + // Test every case in the suite. + for (name, _) in &self.cases { + args.args = vec![ast::Argument { + name: TEST_CASE_RUN_OPTION.into(), + value: format!("{:?}", name), + }]; + args.args.append(&mut user_args.clone()); + let start = Instant::now(); + // Check if is the fast eval mode. + let exec_result = if let Some(_artifact) = &artifact { + #[cfg(feature = "llvm")] + let exec_result = _artifact.run(&args)?; + #[cfg(not(feature = "llvm"))] + let exec_result = exec_program(ParseSessionRef::default(), &args)?; + exec_result + } else { + args.fast_eval = true; + exec_program(ParseSessionRef::default(), &args)? + }; + // Check if there was an error. + let error = if exec_result.err_message.is_empty() { + None + } else { + Some(anyhow!("{}", exec_result.err_message)) + }; + // Check if the fail_fast option is enabled and there was an error. + let fail_fast = error.is_some() && opts.fail_fast; + // Add test case information to the result. + result.info.insert( + name.clone(), + TestCaseInfo { + log_message: exec_result.log_message.clone(), + duration: Instant::now() - start, + error, + }, + ); + if fail_fast { + break; + } + } + // Remove the temp test main file + if opts.exec_args.debug == 0 { + remove_file(main_file)?; + } + Ok(result) + } +} + +impl TestSuite { + fn gen_test_main_file(&self) -> Result { + let test_codes = self + .cases + .keys() + .map(|c| format!("if {} == '{}': {}()", TEST_CASE_RUN_OPTION, c, c)) + .collect::>(); + let code = format!("{}{}", TEST_MAIN_FILE_PREFIX, test_codes.join("\n")); + let path = Path::new(&self.pkg).join(TEST_MAIN_FILE); + let test_main_file = path + .to_str() + .ok_or(anyhow!("{} is not found", TEST_MAIN_FILE))?; + std::fs::write(test_main_file, code)?; + Ok(test_main_file.into()) + } + + fn get_input_files(&self, main_file: &str) -> Vec { + // Construct test package files. + let mut files = vec![]; + let mut normal_files = self.normal_files.clone(); + let mut test_files = self.test_files.clone(); + files.append(&mut normal_files); + files.append(&mut test_files); + files.push(main_file.into()); + files + } +} + +pub struct TestCase; + +/// Load test suite from path +pub fn load_test_suites>(path: P, opts: &TestOptions) -> Result> { + let pkg_list = get_pkg_list(path.as_ref())?; + let mut suites = vec![]; + for pkg in &pkg_list { + let (normal_files, test_files) = get_test_files(pkg)?; + let mut cases = IndexMap::new(); + for file in &test_files { + let module = parse_file_force_errors(file, None)?; + for stmt in &module.body { + if let ast::Stmt::Assign(assign_stmt) = &stmt.node { + if let ast::Expr::Lambda(_lambda_expr) = &assign_stmt.value.node { + for target in &assign_stmt.targets { + let func_name = target.node.get_name(); + if is_test_suite(func_name) && should_run(&opts.run_regexp, func_name) { + cases.insert(func_name.to_string(), TestCase {}); + } + } + } + } + } + } + suites.push(TestSuite { + pkg: pkg.clone(), + cases, + normal_files, + test_files, + skip: false, + }); + } + Ok(suites) +} + +#[inline] +fn get_test_files>(pkg: P) -> Result<(Vec, Vec)> { + let files = get_kcl_files(pkg, false)?; + let normal_files = files + .iter() + .filter(|x| !x.starts_with('_') && !x.ends_with(TEST_FILE_SUFFIX)) + .cloned() + .collect::>(); + let test_files = files + .iter() + .filter(|x| !x.starts_with('_') && x.ends_with(TEST_FILE_SUFFIX)) + .cloned() + .collect::>(); + Ok((normal_files, test_files)) +} + +#[inline] +fn is_test_suite(name: &str) -> bool { + name.starts_with(TEST_SUITE_PREFIX) +} + +#[inline] +fn should_run(run_regexp: &str, name: &str) -> bool { + if !run_regexp.is_empty() { + regex::Regex::new(run_regexp) + .map(|re| re.is_match(name)) + .unwrap_or_default() + } else { + true + } +} diff --git a/kclvm/tools/src/testing/test_data/module/kcl.mod b/kclvm/tools/src/testing/test_data/module/kcl.mod new file mode 100644 index 000000000..35d888aa7 --- /dev/null +++ b/kclvm/tools/src/testing/test_data/module/kcl.mod @@ -0,0 +1,3 @@ +[package] +name = "test_data" + diff --git a/kclvm/tools/src/testing/test_data/module/pkg/func.k b/kclvm/tools/src/testing/test_data/module/pkg/func.k new file mode 100644 index 000000000..26df9cf5a --- /dev/null +++ b/kclvm/tools/src/testing/test_data/module/pkg/func.k @@ -0,0 +1,3 @@ +func = lambda x { + x +} diff --git a/kclvm/tools/src/testing/test_data/module/pkg/func_test.k b/kclvm/tools/src/testing/test_data/module/pkg/func_test.k new file mode 100644 index 000000000..91c6b9ca2 --- /dev/null +++ b/kclvm/tools/src/testing/test_data/module/pkg/func_test.k @@ -0,0 +1,11 @@ +test_func_0 = lambda { + assert func("a") == "a" +} + +test_func_1 = lambda { + assert func("a") == "d" +} + +test_func_2 = lambda { + assert func("a") == option("a"), "got {}".format(option("a")) +} diff --git a/kclvm/tools/src/testing/tests.rs b/kclvm/tools/src/testing/tests.rs new file mode 100644 index 000000000..f183f3bda --- /dev/null +++ b/kclvm/tools/src/testing/tests.rs @@ -0,0 +1,49 @@ +use kclvm_ast::ast::Argument; +use kclvm_runner::ExecProgramArgs; + +use crate::testing::TestRun; + +use super::{load_test_suites, TestOptions}; +use std::path::Path; + +#[test] +fn test_load_test_suites_and_run() { + let opts = TestOptions { + exec_args: ExecProgramArgs { + args: vec![Argument { + name: "a".to_string(), + value: "\"a\"".to_string(), + }], + ..Default::default() + }, + ..Default::default() + }; + let suites = load_test_suites( + Path::new(".") + .join("src") + .join("testing") + .join("test_data") + .join("module") + .join("pkg") + .to_str() + .unwrap(), + &opts, + ) + .unwrap(); + assert_eq!(suites.len(), 1); + assert_eq!(suites[0].cases.len(), 3); + let test_result = suites[0].run(&opts).unwrap(); + assert_eq!(test_result.info.len(), 3); + assert!(test_result.info[0].error.is_none()); + assert!(test_result.info[1] + .error + .as_ref() + .unwrap() + .to_string() + .contains("Error"),); + assert!( + test_result.info[2].error.is_none(), + "{:?}", + test_result.info[2].error + ); +} diff --git a/kclvm/tools/src/util/loader.rs b/kclvm/tools/src/util/loader.rs new file mode 100644 index 000000000..f13fdda33 --- /dev/null +++ b/kclvm/tools/src/util/loader.rs @@ -0,0 +1,154 @@ +use std::{fs, path::PathBuf}; + +use anyhow::{bail, Context, Result}; +use compiler_base_span::{span::new_byte_pos, BytePos, FilePathMapping, SourceMap}; +use json_spanned_value::{self as jsv, spanned}; +use kclvm_ast::ast::PosTuple; +use located_yaml::YamlLoader; + +pub(crate) trait Loader { + fn load(&self) -> Result; +} + +/// Types of verifiable files currently supported by KCL-Vet, +/// currently only YAML files and Json files are supported. +#[derive(Clone, Copy)] +pub enum LoaderKind { + YAML, + JSON, +} + +/// DataLoader for Json or Yaml +/// If `DataLoader` is constructed using a file path, then `content` is the content of the file. +/// If `DataLoader` is constructed using a Json/Yaml string, then `content` is the string +pub(crate) struct DataLoader { + kind: LoaderKind, + content: String, + // SourceMap is used to find the position of the error in the file + sm: SourceMap, +} + +impl DataLoader { + /// If `DataLoader` is constructed using a file path, then `content` is the content of the file. + pub(crate) fn new_with_file_path(loader_kind: LoaderKind, file_path: &str) -> Result { + let content = fs::read_to_string(file_path) + .with_context(|| format!("Failed to Load '{}'", file_path))?; + let sm = SourceMap::new(FilePathMapping::empty()); + sm.new_source_file(PathBuf::from(file_path).into(), content.clone()); + Ok(Self { + kind: loader_kind, + content, + sm, + }) + } + + /// If `DataLoader` is constructed using a Json/Yaml string, then `content` is the string + #[allow(dead_code)] + pub(crate) fn new_with_str(loader_kind: LoaderKind, content: &str) -> Result { + let sm = SourceMap::new(FilePathMapping::empty()); + sm.new_source_file(PathBuf::from("").into(), content.to_string()); + Ok(Self { + kind: loader_kind, + content: content.to_string(), + sm, + }) + } + + pub(crate) fn get_data(&self) -> &str { + &self.content + } + + pub(crate) fn get_kind(&self) -> &LoaderKind { + &self.kind + } + + /// Convert the position in the source map to the position in the source file + pub fn byte_pos_to_pos_in_sourcemap(&self, lo: BytePos, hi: BytePos) -> PosTuple { + let lo = self.sm.lookup_char_pos(lo); + let hi = self.sm.lookup_char_pos(hi); + let filename = kclvm_utils::path::convert_windows_drive_letter(&format!( + "{}", + lo.file.name.prefer_remapped() + )); + ( + filename, + lo.line as u64, + lo.col.0 as u64, + hi.line as u64, + hi.col.0 as u64, + ) + } + + pub fn file_name(&self) -> String { + kclvm_utils::path::convert_windows_drive_letter(&format!( + "{}", + self.sm + .lookup_char_pos(new_byte_pos(0)) + .file + .name + .prefer_remapped() + )) + } +} + +impl Loader for DataLoader { + /// Load data into Json value. + fn load(&self) -> Result { + let v = match self.kind { + LoaderKind::JSON => serde_json::from_str(self.get_data()) + .with_context(|| format!("Failed to String '{}' to Json", self.get_data()))?, + _ => { + bail!("Failed to String to Json Value") + } + }; + + Ok(v) + } +} + +/// Load data into Json value with span. +impl Loader for DataLoader { + fn load(&self) -> Result { + let v = match self.kind { + LoaderKind::JSON => jsv::from_str(self.get_data()) + .with_context(|| format!("Failed to String '{}' to Json", self.get_data()))?, + _ => { + bail!("Failed to String to Json Value") + } + }; + + Ok(v) + } +} + +/// Load data into Json value with span. +impl Loader for DataLoader { + fn load(&self) -> Result { + let v = match self.kind { + LoaderKind::YAML => YamlLoader::load_from_str(self.get_data()) + .with_context(|| format!("Failed to String '{}' to Yaml", self.get_data()))?, + _ => { + bail!("Failed to String to Yaml Value") + } + }; + + v.docs + .first() + .map_or_else(|| bail!("Failed to Load YAML"), |res| Ok(res.clone())) + } +} + +impl Loader for DataLoader { + /// Load data into Yaml value. + fn load(&self) -> Result { + let v = match self.kind { + LoaderKind::YAML => serde_yaml::from_str(self.get_data()) + .with_context(|| format!("Failed to String '{}' to Yaml", self.get_data()))?, + _ => { + bail!("Failed to String to Yaml Value") + } + }; + + Ok(v) + } +} diff --git a/kclvm/tools/src/util/mod.rs b/kclvm/tools/src/util/mod.rs new file mode 100644 index 000000000..c8474ee40 --- /dev/null +++ b/kclvm/tools/src/util/mod.rs @@ -0,0 +1,3 @@ +pub mod loader; +#[cfg(test)] +mod tests; diff --git a/kclvm/tools/src/util/test_datas/test.json b/kclvm/tools/src/util/test_datas/test.json new file mode 100644 index 000000000..e02809804 --- /dev/null +++ b/kclvm/tools/src/util/test_datas/test.json @@ -0,0 +1,12 @@ +{ + "name": "John Doe", + "age": 43, + "address": { + "street": "10 Downing Street", + "city": "London" + }, + "phones": [ + "+44 1234567", + "+44 2345678" + ] +} diff --git a/kclvm/tools/src/util/test_datas/test.yaml b/kclvm/tools/src/util/test_datas/test.yaml new file mode 100644 index 000000000..f6016b17b --- /dev/null +++ b/kclvm/tools/src/util/test_datas/test.yaml @@ -0,0 +1,9 @@ +languages: + - Ruby + - Perl + - Python +websites: + YAML: yaml.org + Ruby: ruby-lang.org + Python: python.org + Perl: use.perl.org diff --git a/kclvm/tools/src/util/test_datas/test_invalid.json b/kclvm/tools/src/util/test_datas/test_invalid.json new file mode 100644 index 000000000..08348a880 --- /dev/null +++ b/kclvm/tools/src/util/test_datas/test_invalid.json @@ -0,0 +1,9 @@ +languages: + - Ruby + - Perl + - Python +websites: + YAML: yaml.org + Ruby: ruby-lang.org + Python: python.org + Perl: use.perl.org \ No newline at end of file diff --git a/kclvm/tools/src/util/test_datas/test_invalid.yaml b/kclvm/tools/src/util/test_datas/test_invalid.yaml new file mode 100644 index 000000000..2a27c807d --- /dev/null +++ b/kclvm/tools/src/util/test_datas/test_invalid.yaml @@ -0,0 +1,2 @@ +"name": "John Doe", +invalid diff --git a/kclvm/tools/src/util/tests.rs b/kclvm/tools/src/util/tests.rs new file mode 100644 index 000000000..81f191844 --- /dev/null +++ b/kclvm/tools/src/util/tests.rs @@ -0,0 +1,256 @@ +use std::path::PathBuf; + +use anyhow::{Context, Result}; + +const CARGO_DIR: &str = env!("CARGO_MANIFEST_DIR"); +const REL_PATH: &str = "src/util/test_datas"; +const FILE_TEST_CASES: &[&str] = &["test"]; + +const FILE_EXTENSIONS: &[&str] = &[".json", ".yaml"]; + +const JSON_STR_TEST_CASES: &[&str] = &[r#"{ + "name": "John Doe", + "age": 43, + "address": { + "street": "10 Downing Street", + "city": "London" + }, + "phones": [ + "+44 1234567", + "+44 2345678" + ] +} +"#]; + +const YAML_STR_TEST_CASES: &[&str] = &[r#"languages: + - Ruby + - Perl + - Python +websites: + YAML: yaml.org + Ruby: ruby-lang.org + Python: python.org + Perl: use.perl.org +"#]; + +fn construct_full_path(path: &str) -> Result { + let mut cargo_file_path = PathBuf::from(CARGO_DIR); + cargo_file_path.push(REL_PATH); + cargo_file_path.push(path); + Ok(cargo_file_path + .to_str() + .with_context(|| format!("No such file or directory '{}'", path))? + .to_string()) +} + +mod test_loader { + mod test_data_loader { + use regex::Regex; + + use crate::util::{ + loader::{DataLoader, Loader, LoaderKind}, + tests::{ + construct_full_path, FILE_EXTENSIONS, FILE_TEST_CASES, JSON_STR_TEST_CASES, + YAML_STR_TEST_CASES, + }, + }; + + fn data_loader_from_file(loader_kind: LoaderKind, file_path: &str) -> DataLoader { + let test_case_path = construct_full_path(file_path).unwrap(); + + DataLoader::new_with_file_path(loader_kind, &test_case_path).unwrap() + } + + fn data_loader_from_str(loader_kind: LoaderKind, s: &str) -> DataLoader { + DataLoader::new_with_str(loader_kind, s).unwrap() + } + + #[test] + fn test_new_with_file_path_json() { + for test_case in FILE_TEST_CASES { + let json_loader = data_loader_from_file( + LoaderKind::JSON, + &format!("{}{}", test_case, FILE_EXTENSIONS[0]), + ); + + #[cfg(not(target_os = "windows"))] + let got_data = json_loader.get_data(); + #[cfg(target_os = "windows")] + let got_data = json_loader.get_data().replace("\r\n", "\n"); + + assert_eq!( + got_data, + r#"{ + "name": "John Doe", + "age": 43, + "address": { + "street": "10 Downing Street", + "city": "London" + }, + "phones": [ + "+44 1234567", + "+44 2345678" + ] +} +"# + ); + } + } + + #[test] + fn test_new_with_str_json() { + for test_case in JSON_STR_TEST_CASES { + let json_loader = data_loader_from_str(LoaderKind::JSON, test_case); + assert_eq!(json_loader.get_data(), *test_case); + } + } + + #[test] + fn test_new_with_file_path_yaml() { + for test_case in FILE_TEST_CASES { + let yaml_loader = data_loader_from_file( + LoaderKind::YAML, + &format!("{}{}", test_case, FILE_EXTENSIONS[1]), + ); + + #[cfg(not(target_os = "windows"))] + let got_data = yaml_loader.get_data(); + #[cfg(target_os = "windows")] + let got_data = yaml_loader.get_data().replace("\r\n", "\n"); + + assert_eq!( + got_data, + r#"languages: + - Ruby + - Perl + - Python +websites: + YAML: yaml.org + Ruby: ruby-lang.org + Python: python.org + Perl: use.perl.org +"# + ); + } + } + + #[test] + fn test_new_with_str_yaml() { + for test_case in YAML_STR_TEST_CASES { + let yaml_loader = data_loader_from_str(LoaderKind::JSON, test_case); + assert_eq!(yaml_loader.get_data(), *test_case); + } + } + + #[test] + fn test_load() { + let yaml_loader = data_loader_from_file( + LoaderKind::YAML, + &format!("{}{}", FILE_TEST_CASES[0], FILE_EXTENSIONS[1]), + ); + + let got_yaml = >::load(&yaml_loader).unwrap(); + let expect_yaml: serde_yaml::Value = + serde_yaml::from_str(yaml_loader.get_data()).unwrap(); + + assert_eq!(got_yaml, expect_yaml); + + let json_loader = data_loader_from_file( + LoaderKind::JSON, + &format!("{}{}", FILE_TEST_CASES[0], FILE_EXTENSIONS[0]), + ); + + let got_json = >::load(&json_loader).unwrap(); + let expect_json: serde_json::Value = + serde_json::from_str(json_loader.get_data()).unwrap(); + + assert_eq!(got_json, expect_json); + } + + #[test] + fn test_load_invalid() { + let yaml_loader = data_loader_from_file( + LoaderKind::YAML, + &format!("{}{}", FILE_TEST_CASES[0], FILE_EXTENSIONS[1]), + ); + + match >::load(&yaml_loader) { + Ok(_) => { + panic!("unreachable") + } + Err(err) => { + assert_eq!(format!("{:?}", err), "Failed to String to Json Value"); + } + } + + let json_loader = data_loader_from_file( + LoaderKind::JSON, + &format!("{}{}", FILE_TEST_CASES[0], FILE_EXTENSIONS[0]), + ); + + match >::load(&json_loader) { + Ok(_) => { + panic!("unreachable") + } + Err(err) => { + assert_eq!(format!("{:?}", err), "Failed to String to Yaml Value"); + } + } + } + + #[test] + fn new_with_file_path_invalid() { + match DataLoader::new_with_file_path(LoaderKind::JSON, "invalid file path") { + Ok(_) => { + panic!("unreachable") + } + Err(err) => { + assert!( + Regex::new(r"^Failed to Load 'invalid file path'\n\nCaused by:.*") + .unwrap() + .is_match(&format!("{:?}", err)) + ); + } + }; + } + + #[test] + fn test_invalid_file() { + let invalid_json_file_path = construct_full_path("test_invalid.json").unwrap(); + let json_loader = + DataLoader::new_with_file_path(LoaderKind::JSON, &invalid_json_file_path).unwrap(); + + match >::load(&json_loader) { + Ok(_) => { + panic!("unreachable") + } + Err(err) => { + #[cfg(not(target_os = "windows"))] + let got_err = format!("{:?}", err); + #[cfg(target_os = "windows")] + let got_err = format!("{:?}", err).replace("\r\n", "\n"); + + assert_eq!(got_err, "Failed to String 'languages:\n - Ruby\n - Perl\n - Python \nwebsites:\n YAML: yaml.org \n Ruby: ruby-lang.org \n Python: python.org \n Perl: use.perl.org' to Json\n\nCaused by:\n expected value at line 1 column 1"); + } + } + + let invalid_yaml_file_path = construct_full_path("test_invalid.yaml").unwrap(); + let yaml_loader = + DataLoader::new_with_file_path(LoaderKind::YAML, &invalid_yaml_file_path).unwrap(); + + match >::load(&yaml_loader) { + Ok(_) => { + panic!("unreachable") + } + Err(err) => { + #[cfg(not(target_os = "windows"))] + let got_err = format!("{:?}", err); + #[cfg(target_os = "windows")] + let got_err = format!("{:?}", err).replace("\r\n", "\n"); + + assert_eq!(got_err, "Failed to String '\"name\": \"John Doe\",\ninvalid\n' to Yaml\n\nCaused by:\n did not find expected key at line 1 column 19, while parsing a block mapping"); + } + } + } + } +} diff --git a/kclvm/tools/src/vet/expr_builder.rs b/kclvm/tools/src/vet/expr_builder.rs new file mode 100644 index 000000000..4f1204e8a --- /dev/null +++ b/kclvm/tools/src/vet/expr_builder.rs @@ -0,0 +1,598 @@ +use compiler_base_span::span::new_byte_pos; +use kclvm_ast::{ + ast::{ + ConfigEntry, ConfigEntryOperation, ConfigExpr, Expr, ExprContext, Identifier, ListExpr, + NameConstant, NameConstantLit, Node, NodeRef, NumberLit, NumberLitValue, SchemaExpr, + }, + node_ref, +}; +use serde_json::json; + +use crate::util::loader::{DataLoader, Loader, LoaderKind}; +use anyhow::{bail, Context, Result}; + +const FAIL_LOAD_VALIDATED_ERR_MSG: &str = "Failed to load the validated file"; + +trait ExprGenerator { + fn generate(&self, value: &T, schema_name: &Option) -> Result>; +} + +/// `ExprBuilder` will generate ast expr from Json/Yaml. +/// `Object` in Json and `Mapping` in Yaml is mapped to `Schema Expr`. +/// You should set `schema_name` for `Schema Expr` before using `ExprBuilder`. +pub(crate) struct ExprBuilder { + loader: DataLoader, +} + +impl ExprBuilder { + pub(crate) fn new_with_file_path(kind: LoaderKind, file_path: String) -> Result { + let loader = DataLoader::new_with_file_path(kind, &file_path) + .with_context(|| format!("Failed to Load '{}'", file_path))?; + + Ok(Self { loader }) + } + + #[allow(dead_code)] + pub(crate) fn new_with_str(kind: LoaderKind, content: String) -> Result { + let loader = DataLoader::new_with_str(kind, &content) + .with_context(|| format!("Failed to Parse String '{}'", content))?; + + Ok(Self { loader }) + } + + /// Generate ast expr from Json/Yaml depends on `LoaderKind`. + pub(crate) fn build(&self, schema_name: Option) -> Result> { + match self.loader.get_kind() { + LoaderKind::JSON => { + let value = , + >>::load(&self.loader) + .with_context(|| "Failed to Load JSON".to_string())?; + Ok(self + .generate(&value, &schema_name) + .with_context(|| "Failed to Load JSON".to_string())?) + } + LoaderKind::YAML => { + let value = >::load(&self.loader) + .with_context(|| "Failed to Load YAML".to_string())?; + Ok(self + .generate(&value, &schema_name) + .with_context(|| "Failed to Load YAML".to_string())?) + } + } + } +} + +impl ExprGenerator for ExprBuilder { + fn generate( + &self, + value: &serde_yaml::Value, + schema_name: &Option, + ) -> Result> { + match value { + serde_yaml::Value::Null => Ok(node_ref!(Expr::NameConstantLit(NameConstantLit { + value: NameConstant::None, + }))), + serde_yaml::Value::Bool(j_bool) => { + let name_const = match NameConstant::try_from(*j_bool) { + Ok(nc) => nc, + Err(err) => { + bail!("{FAIL_LOAD_VALIDATED_ERR_MSG}, {err}") + } + }; + + Ok(node_ref!(Expr::NameConstantLit(NameConstantLit { + value: name_const + }))) + } + serde_yaml::Value::Number(j_num) => { + if j_num.is_f64() { + let number_lit = match j_num.as_f64() { + Some(num_f64) => num_f64, + None => { + bail!("{FAIL_LOAD_VALIDATED_ERR_MSG}") + } + }; + + Ok(node_ref!(Expr::NumberLit(NumberLit { + binary_suffix: None, + value: NumberLitValue::Float(number_lit) + }))) + } else if j_num.is_i64() { + let number_lit = match j_num.as_i64() { + Some(j_num) => j_num, + None => { + bail!("{FAIL_LOAD_VALIDATED_ERR_MSG}") + } + }; + + Ok(node_ref!(Expr::NumberLit(NumberLit { + binary_suffix: None, + value: NumberLitValue::Int(number_lit) + }))) + } else { + bail!("{FAIL_LOAD_VALIDATED_ERR_MSG}, Unsupported Unsigned 64"); + } + } + serde_yaml::Value::String(j_string) => { + let str_lit = From::from(j_string.to_string()); + Ok(node_ref!(Expr::StringLit(str_lit))) + } + serde_yaml::Value::Sequence(j_arr) => { + let mut j_arr_ast_nodes: Vec> = Vec::new(); + for j_arr_item in j_arr { + j_arr_ast_nodes.push( + self.generate(j_arr_item, schema_name) + .with_context(|| FAIL_LOAD_VALIDATED_ERR_MSG)?, + ); + } + Ok(node_ref!(Expr::List(ListExpr { + ctx: ExprContext::Load, + elts: j_arr_ast_nodes + }))) + } + serde_yaml::Value::Mapping(j_map) => { + let mut config_entries: Vec> = Vec::new(); + + for (k, v) in j_map.iter() { + // The configuration builder already in the schema no longer needs a schema name + let k = self + .generate(k, &None) + .with_context(|| FAIL_LOAD_VALIDATED_ERR_MSG)?; + let v = self + .generate(v, &None) + .with_context(|| FAIL_LOAD_VALIDATED_ERR_MSG)?; + + let config_entry = node_ref!(ConfigEntry { + key: Some(k), + value: v, + operation: ConfigEntryOperation::Union, + }); + config_entries.push(config_entry); + } + + let config_expr = node_ref!(Expr::Config(ConfigExpr { + items: config_entries + })); + + match schema_name { + Some(s_name) => { + let iden = node_ref!(Identifier { + names: vec![Node::dummy_node(s_name.to_string())], + pkgpath: String::new(), + ctx: ExprContext::Load + }); + Ok(node_ref!(Expr::Schema(SchemaExpr { + name: iden, + config: config_expr, + args: vec![], + kwargs: vec![] + }))) + } + None => Ok(config_expr), + } + } + serde_yaml::Value::Tagged(v) => { + bail!( + "{FAIL_LOAD_VALIDATED_ERR_MSG}, Unsupported Yaml tag {}", + v.tag + ) + } + } + } +} + +impl ExprGenerator for ExprBuilder { + fn generate( + &self, + value: &located_yaml::Yaml, + schema_name: &Option, + ) -> Result> { + let loc = ( + self.loader.file_name(), + value.marker.line as u64, + value.marker.col as u64, + 0, + 0, + ); + match &value.yaml { + located_yaml::YamlElt::Null => Ok(node_ref!( + Expr::NameConstantLit(NameConstantLit { + value: NameConstant::None, + }), + loc + )), + located_yaml::YamlElt::Boolean(j_bool) => { + let name_const = match NameConstant::try_from(*j_bool) { + Ok(nc) => nc, + Err(err) => { + bail!("{FAIL_LOAD_VALIDATED_ERR_MSG}, {err}") + } + }; + + Ok(node_ref!( + Expr::NameConstantLit(NameConstantLit { value: name_const }), + loc + )) + } + located_yaml::YamlElt::Integer(j_int) => { + if json!(j_int).is_i64() { + Ok(node_ref!( + Expr::NumberLit(NumberLit { + binary_suffix: None, + value: NumberLitValue::Int(*j_int) + }), + loc + )) + } else { + bail!("{FAIL_LOAD_VALIDATED_ERR_MSG}, Unsupported Number Type"); + } + } + located_yaml::YamlElt::Real(j_float) => { + if let Ok(number_lit) = j_float.parse::() { + if format!("{}", number_lit) != *j_float { + bail!("{FAIL_LOAD_VALIDATED_ERR_MSG}, Unsupported Number Type",) + } + Ok(node_ref!( + Expr::NumberLit(NumberLit { + binary_suffix: None, + value: NumberLitValue::Float(number_lit) + }), + loc + )) + } else { + bail!("{FAIL_LOAD_VALIDATED_ERR_MSG}, Unsupported Number Type",) + } + } + located_yaml::YamlElt::String(j_string) => { + let str_lit = From::from(j_string.to_string()); + Ok(node_ref!(Expr::StringLit(str_lit), loc)) + } + located_yaml::YamlElt::Array(j_arr) => { + let mut j_arr_ast_nodes: Vec> = Vec::new(); + for j_arr_item in j_arr { + j_arr_ast_nodes.push( + self.generate(j_arr_item, schema_name) + .with_context(|| FAIL_LOAD_VALIDATED_ERR_MSG)?, + ); + } + Ok(node_ref!( + Expr::List(ListExpr { + ctx: ExprContext::Load, + elts: j_arr_ast_nodes + }), + loc + )) + } + located_yaml::YamlElt::Hash(j_map) => { + let mut config_entries: Vec> = Vec::new(); + + for (k, v) in j_map.iter() { + // The configuration builder already in the schema no longer needs a schema name + let k = self + .generate(k, &None) + .with_context(|| FAIL_LOAD_VALIDATED_ERR_MSG)?; + let v = self + .generate(v, &None) + .with_context(|| FAIL_LOAD_VALIDATED_ERR_MSG)?; + + let config_entry = node_ref!( + ConfigEntry { + key: Some(k), + value: v, + operation: ConfigEntryOperation::Union, + }, + loc.clone() + ); + config_entries.push(config_entry); + } + + let config_expr = node_ref!( + Expr::Config(ConfigExpr { + items: config_entries + }), + loc.clone() + ); + + match schema_name { + Some(s_name) => { + let iden = node_ref!( + Identifier { + names: vec![Node::new( + s_name.to_string(), + loc.0.clone(), + loc.1, + loc.2, + loc.3, + loc.4 + )], + pkgpath: String::new(), + ctx: ExprContext::Load + }, + loc.clone() + ); + Ok(node_ref!( + Expr::Schema(SchemaExpr { + name: iden, + config: config_expr, + args: vec![], + kwargs: vec![] + }), + loc.clone() + )) + } + None => Ok(config_expr), + } + } + _ => { + bail!("{FAIL_LOAD_VALIDATED_ERR_MSG}, Unsupported Yaml Element",) + } + } + } +} + +/// `ExprBuilder` will generate ast expr from Json with span. +impl ExprGenerator> for ExprBuilder { + fn generate( + &self, + value: &json_spanned_value::Spanned, + schema_name: &Option, + ) -> Result> { + let loc = self.loader.byte_pos_to_pos_in_sourcemap( + new_byte_pos(value.span().0 as u32), + new_byte_pos(value.span().1 as u32), + ); + match value.get_ref() { + json_spanned_value::Value::Null => Ok(node_ref!( + Expr::NameConstantLit(NameConstantLit { + value: NameConstant::None, + }), + loc + )), + json_spanned_value::Value::Bool(j_bool) => { + let name_const = match NameConstant::try_from(*j_bool) { + Ok(nc) => nc, + Err(err) => { + bail!("{FAIL_LOAD_VALIDATED_ERR_MSG}, {err}") + } + }; + + Ok(node_ref!( + Expr::NameConstantLit(NameConstantLit { value: name_const }), + loc + )) + } + json_spanned_value::Value::Number(j_num) => { + if j_num.is_f64() { + let number_lit = match j_num.as_f64() { + Some(num_f64) => num_f64, + None => { + bail!("{FAIL_LOAD_VALIDATED_ERR_MSG}") + } + }; + + Ok(node_ref!( + Expr::NumberLit(NumberLit { + binary_suffix: None, + value: NumberLitValue::Float(number_lit) + }), + loc + )) + } else if j_num.is_i64() { + let number_lit = match j_num.as_i64() { + Some(j_num) => j_num, + None => { + bail!("{FAIL_LOAD_VALIDATED_ERR_MSG}") + } + }; + + Ok(node_ref!( + Expr::NumberLit(NumberLit { + binary_suffix: None, + value: NumberLitValue::Int(number_lit) + }), + loc + )) + } else { + bail!("{FAIL_LOAD_VALIDATED_ERR_MSG}, Unsupported Unsigned 64"); + } + } + json_spanned_value::Value::String(j_string) => { + let str_lit = From::from(j_string.to_string()); + + Ok(node_ref!(Expr::StringLit(str_lit), loc)) + } + json_spanned_value::Value::Array(j_arr) => { + let mut j_arr_ast_nodes: Vec> = Vec::new(); + for j_arr_item in j_arr { + j_arr_ast_nodes.push( + self.generate(j_arr_item, schema_name) + .with_context(|| FAIL_LOAD_VALIDATED_ERR_MSG)?, + ); + } + Ok(node_ref!( + Expr::List(ListExpr { + ctx: ExprContext::Load, + elts: j_arr_ast_nodes + }), + loc + )) + } + json_spanned_value::Value::Object(j_map) => { + let mut config_entries: Vec> = Vec::new(); + + for (k, v) in j_map.iter() { + let k_span = k.span(); + let k = From::from(k.to_string()); + let v = self + .generate(v, &None) + .with_context(|| FAIL_LOAD_VALIDATED_ERR_MSG)?; + + let config_entry = node_ref!( + ConfigEntry { + key: Some(node_ref!( + Expr::StringLit(k), + self.loader.byte_pos_to_pos_in_sourcemap( + new_byte_pos(k_span.0 as u32), + new_byte_pos(k_span.1 as u32) + ) + )), + value: v, + operation: ConfigEntryOperation::Union, + }, + loc.clone() + ); + config_entries.push(config_entry); + } + + let config_expr = node_ref!( + Expr::Config(ConfigExpr { + items: config_entries + }), + loc.clone() + ); + + match schema_name { + Some(s_name) => { + let iden = node_ref!( + Identifier { + names: vec![Node::new( + s_name.to_string(), + loc.0.clone(), + loc.1, + loc.2, + loc.3, + loc.4 + )], + pkgpath: String::new(), + ctx: ExprContext::Load + }, + loc.clone() + ); + Ok(node_ref!( + Expr::Schema(SchemaExpr { + name: iden, + config: config_expr, + args: vec![], + kwargs: vec![] + }), + loc + )) + } + None => Ok(config_expr), + } + } + } + } +} + +impl ExprGenerator for ExprBuilder { + fn generate( + &self, + value: &serde_json::Value, + schema_name: &Option, + ) -> Result> { + match value { + serde_json::Value::Null => Ok(node_ref!(Expr::NameConstantLit(NameConstantLit { + value: NameConstant::None, + }))), + serde_json::Value::Bool(j_bool) => { + let name_const = match NameConstant::try_from(*j_bool) { + Ok(nc) => nc, + Err(err) => { + bail!("{FAIL_LOAD_VALIDATED_ERR_MSG}, {err}") + } + }; + + Ok(node_ref!(Expr::NameConstantLit(NameConstantLit { + value: name_const + }))) + } + serde_json::Value::Number(j_num) => { + if j_num.is_f64() { + let number_lit = match j_num.as_f64() { + Some(num_f64) => num_f64, + None => { + bail!("{FAIL_LOAD_VALIDATED_ERR_MSG}") + } + }; + + Ok(node_ref!(Expr::NumberLit(NumberLit { + binary_suffix: None, + value: NumberLitValue::Float(number_lit) + }))) + } else if j_num.is_i64() { + let number_lit = match j_num.as_i64() { + Some(j_num) => j_num, + None => { + bail!("{FAIL_LOAD_VALIDATED_ERR_MSG}") + } + }; + + Ok(node_ref!(Expr::NumberLit(NumberLit { + binary_suffix: None, + value: NumberLitValue::Int(number_lit) + }))) + } else { + bail!("{FAIL_LOAD_VALIDATED_ERR_MSG}, Unsupported Unsigned 64"); + } + } + serde_json::Value::String(j_string) => { + let str_lit = From::from(j_string.to_string()); + + Ok(node_ref!(Expr::StringLit(str_lit))) + } + serde_json::Value::Array(j_arr) => { + let mut j_arr_ast_nodes: Vec> = Vec::new(); + for j_arr_item in j_arr { + j_arr_ast_nodes.push( + self.generate(j_arr_item, schema_name) + .with_context(|| FAIL_LOAD_VALIDATED_ERR_MSG)?, + ); + } + Ok(node_ref!(Expr::List(ListExpr { + ctx: ExprContext::Load, + elts: j_arr_ast_nodes + }))) + } + serde_json::Value::Object(j_map) => { + let mut config_entries: Vec> = Vec::new(); + + for (k, v) in j_map.iter() { + let k = From::from(k.to_string()); + let v = self + .generate(v, &None) + .with_context(|| FAIL_LOAD_VALIDATED_ERR_MSG)?; + + let config_entry = node_ref!(ConfigEntry { + key: Some(node_ref!(Expr::StringLit(k))), + value: v, + operation: ConfigEntryOperation::Union, + }); + config_entries.push(config_entry); + } + + let config_expr = node_ref!(Expr::Config(ConfigExpr { + items: config_entries + })); + + match schema_name { + Some(s_name) => { + let iden = node_ref!(Identifier { + names: vec![Node::dummy_node(s_name.to_string())], + pkgpath: String::new(), + ctx: ExprContext::Load + }); + Ok(node_ref!(Expr::Schema(SchemaExpr { + name: iden, + config: config_expr, + args: vec![], + kwargs: vec![] + }))) + } + None => Ok(config_expr), + } + } + } + } +} diff --git a/kclvm/tools/src/vet/mod.rs b/kclvm/tools/src/vet/mod.rs new file mode 100644 index 000000000..48c1e275c --- /dev/null +++ b/kclvm/tools/src/vet/mod.rs @@ -0,0 +1,5 @@ +pub mod expr_builder; +pub mod validator; + +#[cfg(test)] +mod tests; diff --git a/kclvm/tools/src/vet/snapshots/kclvm_tools__vet__tests__test_expr_builder__build_json_with_filepath-2.snap b/kclvm/tools/src/vet/snapshots/kclvm_tools__vet__tests__test_expr_builder__build_json_with_filepath-2.snap new file mode 100644 index 000000000..4f1c36430 --- /dev/null +++ b/kclvm/tools/src/vet/snapshots/kclvm_tools__vet__tests__test_expr_builder__build_json_with_filepath-2.snap @@ -0,0 +1,159 @@ +--- +source: tools/src/vet/tests.rs +expression: got_ast_json_str +--- +{ + "column": 0, + "end_column": 1, + "end_line": 5, + "filename": "/simple.k.json", + "line": 1, + "node": { + "args": [], + "config": { + "column": 0, + "end_column": 1, + "end_line": 5, + "filename": "/simple.k.json", + "line": 1, + "node": { + "items": [ + { + "column": 0, + "end_column": 1, + "end_line": 5, + "filename": "/simple.k.json", + "line": 1, + "node": { + "key": { + "column": 4, + "end_column": 9, + "end_line": 3, + "filename": "/simple.k.json", + "line": 3, + "node": { + "is_long_string": false, + "raw_value": "\"age\"", + "type": "StringLit", + "value": "age" + } + }, + "operation": "Union", + "value": { + "column": 11, + "end_column": 13, + "end_line": 3, + "filename": "/simple.k.json", + "line": 3, + "node": { + "binary_suffix": null, + "type": "NumberLit", + "value": { + "type": "Int", + "value": 18 + } + } + } + } + }, + { + "column": 0, + "end_column": 1, + "end_line": 5, + "filename": "/simple.k.json", + "line": 1, + "node": { + "key": { + "column": 4, + "end_column": 13, + "end_line": 4, + "filename": "/simple.k.json", + "line": 4, + "node": { + "is_long_string": false, + "raw_value": "\"message\"", + "type": "StringLit", + "value": "message" + } + }, + "operation": "Union", + "value": { + "column": 15, + "end_column": 30, + "end_line": 4, + "filename": "/simple.k.json", + "line": 4, + "node": { + "is_long_string": false, + "raw_value": "\"This is Alice\"", + "type": "StringLit", + "value": "This is Alice" + } + } + } + }, + { + "column": 0, + "end_column": 1, + "end_line": 5, + "filename": "/simple.k.json", + "line": 1, + "node": { + "key": { + "column": 4, + "end_column": 10, + "end_line": 2, + "filename": "/simple.k.json", + "line": 2, + "node": { + "is_long_string": false, + "raw_value": "\"name\"", + "type": "StringLit", + "value": "name" + } + }, + "operation": "Union", + "value": { + "column": 12, + "end_column": 19, + "end_line": 2, + "filename": "/simple.k.json", + "line": 2, + "node": { + "is_long_string": false, + "raw_value": "\"Alice\"", + "type": "StringLit", + "value": "Alice" + } + } + } + } + ], + "type": "Config" + } + }, + "kwargs": [], + "name": { + "column": 0, + "end_column": 1, + "end_line": 5, + "filename": "/simple.k.json", + "line": 1, + "node": { + "ctx": "Load", + "names": [ + { + "column": 0, + "end_column": 1, + "end_line": 5, + "filename": "/simple.k.json", + "line": 1, + "node": "simple" + } + ], + "pkgpath": "" + } + }, + "type": "Schema" + } +} diff --git a/kclvm/tools/src/vet/snapshots/kclvm_tools__vet__tests__test_expr_builder__build_json_with_filepath-3.snap b/kclvm/tools/src/vet/snapshots/kclvm_tools__vet__tests__test_expr_builder__build_json_with_filepath-3.snap new file mode 100644 index 000000000..19165aa64 --- /dev/null +++ b/kclvm/tools/src/vet/snapshots/kclvm_tools__vet__tests__test_expr_builder__build_json_with_filepath-3.snap @@ -0,0 +1,19 @@ +--- +source: tools/src/vet/tests.rs +expression: got_ast_json_str +--- +{ + "column": 0, + "end_column": 1, + "end_line": 1, + "filename": "/plain_value.k.json", + "line": 1, + "node": { + "binary_suffix": null, + "type": "NumberLit", + "value": { + "type": "Int", + "value": 1 + } + } +} diff --git a/kclvm/tools/src/vet/snapshots/kclvm_tools__vet__tests__test_expr_builder__build_json_with_filepath-4.snap b/kclvm/tools/src/vet/snapshots/kclvm_tools__vet__tests__test_expr_builder__build_json_with_filepath-4.snap new file mode 100644 index 000000000..d235d60bb --- /dev/null +++ b/kclvm/tools/src/vet/snapshots/kclvm_tools__vet__tests__test_expr_builder__build_json_with_filepath-4.snap @@ -0,0 +1,172 @@ +--- +source: tools/src/vet/tests.rs +expression: got_ast_json_str +--- +{ + "column": 0, + "end_column": 1, + "end_line": 7, + "filename": "/list.k.json", + "line": 1, + "node": { + "ctx": "Load", + "elts": [ + { + "column": 4, + "end_column": 5, + "end_line": 6, + "filename": "/list.k.json", + "line": 2, + "node": { + "args": [], + "config": { + "column": 4, + "end_column": 5, + "end_line": 6, + "filename": "/list.k.json", + "line": 2, + "node": { + "items": [ + { + "column": 4, + "end_column": 5, + "end_line": 6, + "filename": "/list.k.json", + "line": 2, + "node": { + "key": { + "column": 8, + "end_column": 13, + "end_line": 4, + "filename": "/list.k.json", + "line": 4, + "node": { + "is_long_string": false, + "raw_value": "\"age\"", + "type": "StringLit", + "value": "age" + } + }, + "operation": "Union", + "value": { + "column": 15, + "end_column": 17, + "end_line": 4, + "filename": "/list.k.json", + "line": 4, + "node": { + "binary_suffix": null, + "type": "NumberLit", + "value": { + "type": "Int", + "value": 18 + } + } + } + } + }, + { + "column": 4, + "end_column": 5, + "end_line": 6, + "filename": "/list.k.json", + "line": 2, + "node": { + "key": { + "column": 8, + "end_column": 17, + "end_line": 5, + "filename": "/list.k.json", + "line": 5, + "node": { + "is_long_string": false, + "raw_value": "\"message\"", + "type": "StringLit", + "value": "message" + } + }, + "operation": "Union", + "value": { + "column": 19, + "end_column": 34, + "end_line": 5, + "filename": "/list.k.json", + "line": 5, + "node": { + "is_long_string": false, + "raw_value": "\"This is Alice\"", + "type": "StringLit", + "value": "This is Alice" + } + } + } + }, + { + "column": 4, + "end_column": 5, + "end_line": 6, + "filename": "/list.k.json", + "line": 2, + "node": { + "key": { + "column": 8, + "end_column": 14, + "end_line": 3, + "filename": "/list.k.json", + "line": 3, + "node": { + "is_long_string": false, + "raw_value": "\"name\"", + "type": "StringLit", + "value": "name" + } + }, + "operation": "Union", + "value": { + "column": 16, + "end_column": 23, + "end_line": 3, + "filename": "/list.k.json", + "line": 3, + "node": { + "is_long_string": false, + "raw_value": "\"Alice\"", + "type": "StringLit", + "value": "Alice" + } + } + } + } + ], + "type": "Config" + } + }, + "kwargs": [], + "name": { + "column": 4, + "end_column": 5, + "end_line": 6, + "filename": "/list.k.json", + "line": 2, + "node": { + "ctx": "Load", + "names": [ + { + "column": 4, + "end_column": 5, + "end_line": 6, + "filename": "/list.k.json", + "line": 2, + "node": "list" + } + ], + "pkgpath": "" + } + }, + "type": "Schema" + } + } + ], + "type": "List" + } +} diff --git a/kclvm/tools/src/vet/snapshots/kclvm_tools__vet__tests__test_expr_builder__build_json_with_filepath-5.snap b/kclvm/tools/src/vet/snapshots/kclvm_tools__vet__tests__test_expr_builder__build_json_with_filepath-5.snap new file mode 100644 index 000000000..4e27587c0 --- /dev/null +++ b/kclvm/tools/src/vet/snapshots/kclvm_tools__vet__tests__test_expr_builder__build_json_with_filepath-5.snap @@ -0,0 +1,420 @@ +--- +source: tools/src/vet/tests.rs +expression: got_ast_json_str +--- +{ + "column": 0, + "end_column": 1, + "end_line": 13, + "filename": "/complex.k.json", + "line": 1, + "node": { + "args": [], + "config": { + "column": 0, + "end_column": 1, + "end_line": 13, + "filename": "/complex.k.json", + "line": 1, + "node": { + "items": [ + { + "column": 0, + "end_column": 1, + "end_line": 13, + "filename": "/complex.k.json", + "line": 1, + "node": { + "key": { + "column": 4, + "end_column": 9, + "end_line": 3, + "filename": "/complex.k.json", + "line": 3, + "node": { + "is_long_string": false, + "raw_value": "\"age\"", + "type": "StringLit", + "value": "age" + } + }, + "operation": "Union", + "value": { + "column": 11, + "end_column": 13, + "end_line": 3, + "filename": "/complex.k.json", + "line": 3, + "node": { + "binary_suffix": null, + "type": "NumberLit", + "value": { + "type": "Int", + "value": 18 + } + } + } + } + }, + { + "column": 0, + "end_column": 1, + "end_line": 13, + "filename": "/complex.k.json", + "line": 1, + "node": { + "key": { + "column": 4, + "end_column": 10, + "end_line": 5, + "filename": "/complex.k.json", + "line": 5, + "node": { + "is_long_string": false, + "raw_value": "\"data\"", + "type": "StringLit", + "value": "data" + } + }, + "operation": "Union", + "value": { + "column": 12, + "end_column": 5, + "end_line": 8, + "filename": "/complex.k.json", + "line": 5, + "node": { + "items": [ + { + "column": 12, + "end_column": 5, + "end_line": 8, + "filename": "/complex.k.json", + "line": 5, + "node": { + "key": { + "column": 8, + "end_column": 12, + "end_line": 6, + "filename": "/complex.k.json", + "line": 6, + "node": { + "is_long_string": false, + "raw_value": "\"id\"", + "type": "StringLit", + "value": "id" + } + }, + "operation": "Union", + "value": { + "column": 14, + "end_column": 15, + "end_line": 6, + "filename": "/complex.k.json", + "line": 6, + "node": { + "binary_suffix": null, + "type": "NumberLit", + "value": { + "type": "Int", + "value": 1 + } + } + } + } + }, + { + "column": 12, + "end_column": 5, + "end_line": 8, + "filename": "/complex.k.json", + "line": 5, + "node": { + "key": { + "column": 8, + "end_column": 15, + "end_line": 7, + "filename": "/complex.k.json", + "line": 7, + "node": { + "is_long_string": false, + "raw_value": "\"value\"", + "type": "StringLit", + "value": "value" + } + }, + "operation": "Union", + "value": { + "column": 17, + "end_column": 25, + "end_line": 7, + "filename": "/complex.k.json", + "line": 7, + "node": { + "is_long_string": false, + "raw_value": "\"value1\"", + "type": "StringLit", + "value": "value1" + } + } + } + } + ], + "type": "Config" + } + } + } + }, + { + "column": 0, + "end_column": 1, + "end_line": 13, + "filename": "/complex.k.json", + "line": 1, + "node": { + "key": { + "column": 4, + "end_column": 8, + "end_line": 12, + "filename": "/complex.k.json", + "line": 12, + "node": { + "is_long_string": false, + "raw_value": "\"hc\"", + "type": "StringLit", + "value": "hc" + } + }, + "operation": "Union", + "value": { + "column": 10, + "end_column": 19, + "end_line": 12, + "filename": "/complex.k.json", + "line": 12, + "node": { + "ctx": "Load", + "elts": [ + { + "column": 11, + "end_column": 12, + "end_line": 12, + "filename": "/complex.k.json", + "line": 12, + "node": { + "binary_suffix": null, + "type": "NumberLit", + "value": { + "type": "Int", + "value": 1 + } + } + }, + { + "column": 14, + "end_column": 15, + "end_line": 12, + "filename": "/complex.k.json", + "line": 12, + "node": { + "binary_suffix": null, + "type": "NumberLit", + "value": { + "type": "Int", + "value": 2 + } + } + }, + { + "column": 17, + "end_column": 18, + "end_line": 12, + "filename": "/complex.k.json", + "line": 12, + "node": { + "binary_suffix": null, + "type": "NumberLit", + "value": { + "type": "Int", + "value": 3 + } + } + } + ], + "type": "List" + } + } + } + }, + { + "column": 0, + "end_column": 1, + "end_line": 13, + "filename": "/complex.k.json", + "line": 1, + "node": { + "key": { + "column": 4, + "end_column": 12, + "end_line": 9, + "filename": "/complex.k.json", + "line": 9, + "node": { + "is_long_string": false, + "raw_value": "\"labels\"", + "type": "StringLit", + "value": "labels" + } + }, + "operation": "Union", + "value": { + "column": 14, + "end_column": 5, + "end_line": 11, + "filename": "/complex.k.json", + "line": 9, + "node": { + "items": [ + { + "column": 14, + "end_column": 5, + "end_line": 11, + "filename": "/complex.k.json", + "line": 9, + "node": { + "key": { + "column": 8, + "end_column": 13, + "end_line": 10, + "filename": "/complex.k.json", + "line": 10, + "node": { + "is_long_string": false, + "raw_value": "\"key\"", + "type": "StringLit", + "value": "key" + } + }, + "operation": "Union", + "value": { + "column": 15, + "end_column": 22, + "end_line": 10, + "filename": "/complex.k.json", + "line": 10, + "node": { + "is_long_string": false, + "raw_value": "\"value\"", + "type": "StringLit", + "value": "value" + } + } + } + } + ], + "type": "Config" + } + } + } + }, + { + "column": 0, + "end_column": 1, + "end_line": 13, + "filename": "/complex.k.json", + "line": 1, + "node": { + "key": { + "column": 4, + "end_column": 13, + "end_line": 4, + "filename": "/complex.k.json", + "line": 4, + "node": { + "is_long_string": false, + "raw_value": "\"message\"", + "type": "StringLit", + "value": "message" + } + }, + "operation": "Union", + "value": { + "column": 15, + "end_column": 30, + "end_line": 4, + "filename": "/complex.k.json", + "line": 4, + "node": { + "is_long_string": false, + "raw_value": "\"This is Alice\"", + "type": "StringLit", + "value": "This is Alice" + } + } + } + }, + { + "column": 0, + "end_column": 1, + "end_line": 13, + "filename": "/complex.k.json", + "line": 1, + "node": { + "key": { + "column": 4, + "end_column": 10, + "end_line": 2, + "filename": "/complex.k.json", + "line": 2, + "node": { + "is_long_string": false, + "raw_value": "\"name\"", + "type": "StringLit", + "value": "name" + } + }, + "operation": "Union", + "value": { + "column": 12, + "end_column": 19, + "end_line": 2, + "filename": "/complex.k.json", + "line": 2, + "node": { + "is_long_string": false, + "raw_value": "\"Alice\"", + "type": "StringLit", + "value": "Alice" + } + } + } + } + ], + "type": "Config" + } + }, + "kwargs": [], + "name": { + "column": 0, + "end_column": 1, + "end_line": 13, + "filename": "/complex.k.json", + "line": 1, + "node": { + "ctx": "Load", + "names": [ + { + "column": 0, + "end_column": 1, + "end_line": 13, + "filename": "/complex.k.json", + "line": 1, + "node": "complex" + } + ], + "pkgpath": "" + } + }, + "type": "Schema" + } +} diff --git a/kclvm/tools/src/vet/snapshots/kclvm_tools__vet__tests__test_expr_builder__build_json_with_filepath-6.snap b/kclvm/tools/src/vet/snapshots/kclvm_tools__vet__tests__test_expr_builder__build_json_with_filepath-6.snap new file mode 100644 index 000000000..b4c6df045 --- /dev/null +++ b/kclvm/tools/src/vet/snapshots/kclvm_tools__vet__tests__test_expr_builder__build_json_with_filepath-6.snap @@ -0,0 +1,83 @@ +--- +source: tools/src/vet/tests.rs +expression: got_ast_json_str +--- +{ + "column": 0, + "end_column": 1, + "end_line": 3, + "filename": "/only_with_null.json", + "line": 1, + "node": { + "args": [], + "config": { + "column": 0, + "end_column": 1, + "end_line": 3, + "filename": "/only_with_null.json", + "line": 1, + "node": { + "items": [ + { + "column": 0, + "end_column": 1, + "end_line": 3, + "filename": "/only_with_null.json", + "line": 1, + "node": { + "key": { + "column": 4, + "end_column": 16, + "end_line": 2, + "filename": "/only_with_null.json", + "line": 2, + "node": { + "is_long_string": false, + "raw_value": "\"null_value\"", + "type": "StringLit", + "value": "null_value" + } + }, + "operation": "Union", + "value": { + "column": 18, + "end_column": 22, + "end_line": 2, + "filename": "/only_with_null.json", + "line": 2, + "node": { + "type": "NameConstantLit", + "value": "None" + } + } + } + } + ], + "type": "Config" + } + }, + "kwargs": [], + "name": { + "column": 0, + "end_column": 1, + "end_line": 3, + "filename": "/only_with_null.json", + "line": 1, + "node": { + "ctx": "Load", + "names": [ + { + "column": 0, + "end_column": 1, + "end_line": 3, + "filename": "/only_with_null.json", + "line": 1, + "node": "only_with_null" + } + ], + "pkgpath": "" + } + }, + "type": "Schema" + } +} diff --git a/kclvm/tools/src/vet/snapshots/kclvm_tools__vet__tests__test_expr_builder__build_json_with_filepath-7.snap b/kclvm/tools/src/vet/snapshots/kclvm_tools__vet__tests__test_expr_builder__build_json_with_filepath-7.snap new file mode 100644 index 000000000..f854f561b --- /dev/null +++ b/kclvm/tools/src/vet/snapshots/kclvm_tools__vet__tests__test_expr_builder__build_json_with_filepath-7.snap @@ -0,0 +1,83 @@ +--- +source: tools/src/vet/tests.rs +expression: got_ast_json_str +--- +{ + "column": 0, + "end_column": 1, + "end_line": 3, + "filename": "/only_with_bool.json", + "line": 1, + "node": { + "args": [], + "config": { + "column": 0, + "end_column": 1, + "end_line": 3, + "filename": "/only_with_bool.json", + "line": 1, + "node": { + "items": [ + { + "column": 0, + "end_column": 1, + "end_line": 3, + "filename": "/only_with_bool.json", + "line": 1, + "node": { + "key": { + "column": 4, + "end_column": 10, + "end_line": 2, + "filename": "/only_with_bool.json", + "line": 2, + "node": { + "is_long_string": false, + "raw_value": "\"flag\"", + "type": "StringLit", + "value": "flag" + } + }, + "operation": "Union", + "value": { + "column": 12, + "end_column": 16, + "end_line": 2, + "filename": "/only_with_bool.json", + "line": 2, + "node": { + "type": "NameConstantLit", + "value": "True" + } + } + } + } + ], + "type": "Config" + } + }, + "kwargs": [], + "name": { + "column": 0, + "end_column": 1, + "end_line": 3, + "filename": "/only_with_bool.json", + "line": 1, + "node": { + "ctx": "Load", + "names": [ + { + "column": 0, + "end_column": 1, + "end_line": 3, + "filename": "/only_with_bool.json", + "line": 1, + "node": "only_with_bool" + } + ], + "pkgpath": "" + } + }, + "type": "Schema" + } +} diff --git a/kclvm/tools/src/vet/snapshots/kclvm_tools__vet__tests__test_expr_builder__build_json_with_filepath-8.snap b/kclvm/tools/src/vet/snapshots/kclvm_tools__vet__tests__test_expr_builder__build_json_with_filepath-8.snap new file mode 100644 index 000000000..13a23a65e --- /dev/null +++ b/kclvm/tools/src/vet/snapshots/kclvm_tools__vet__tests__test_expr_builder__build_json_with_filepath-8.snap @@ -0,0 +1,87 @@ +--- +source: tools/src/vet/tests.rs +expression: got_ast_json_str +--- +{ + "column": 0, + "end_column": 1, + "end_line": 3, + "filename": "/only_with_float.json", + "line": 1, + "node": { + "args": [], + "config": { + "column": 0, + "end_column": 1, + "end_line": 3, + "filename": "/only_with_float.json", + "line": 1, + "node": { + "items": [ + { + "column": 0, + "end_column": 1, + "end_line": 3, + "filename": "/only_with_float.json", + "line": 1, + "node": { + "key": { + "column": 4, + "end_column": 17, + "end_line": 2, + "filename": "/only_with_float.json", + "line": 2, + "node": { + "is_long_string": false, + "raw_value": "\"float_value\"", + "type": "StringLit", + "value": "float_value" + } + }, + "operation": "Union", + "value": { + "column": 19, + "end_column": 23, + "end_line": 2, + "filename": "/only_with_float.json", + "line": 2, + "node": { + "binary_suffix": null, + "type": "NumberLit", + "value": { + "type": "Float", + "value": 0.33 + } + } + } + } + } + ], + "type": "Config" + } + }, + "kwargs": [], + "name": { + "column": 0, + "end_column": 1, + "end_line": 3, + "filename": "/only_with_float.json", + "line": 1, + "node": { + "ctx": "Load", + "names": [ + { + "column": 0, + "end_column": 1, + "end_line": 3, + "filename": "/only_with_float.json", + "line": 1, + "node": "only_with_float" + } + ], + "pkgpath": "" + } + }, + "type": "Schema" + } +} diff --git a/kclvm/tools/src/vet/snapshots/kclvm_tools__vet__tests__test_expr_builder__build_json_with_filepath.snap b/kclvm/tools/src/vet/snapshots/kclvm_tools__vet__tests__test_expr_builder__build_json_with_filepath.snap new file mode 100644 index 000000000..b45462c7d --- /dev/null +++ b/kclvm/tools/src/vet/snapshots/kclvm_tools__vet__tests__test_expr_builder__build_json_with_filepath.snap @@ -0,0 +1,292 @@ +--- +source: tools/src/vet/tests.rs +expression: got_ast_json_str +--- +{ + "column": 0, + "end_column": 1, + "end_line": 12, + "filename": "/test.k.json", + "line": 1, + "node": { + "args": [], + "config": { + "column": 0, + "end_column": 1, + "end_line": 12, + "filename": "/test.k.json", + "line": 1, + "node": { + "items": [ + { + "column": 0, + "end_column": 1, + "end_line": 12, + "filename": "/test.k.json", + "line": 1, + "node": { + "key": { + "column": 4, + "end_column": 13, + "end_line": 4, + "filename": "/test.k.json", + "line": 4, + "node": { + "is_long_string": false, + "raw_value": "\"address\"", + "type": "StringLit", + "value": "address" + } + }, + "operation": "Union", + "value": { + "column": 15, + "end_column": 5, + "end_line": 7, + "filename": "/test.k.json", + "line": 4, + "node": { + "items": [ + { + "column": 15, + "end_column": 5, + "end_line": 7, + "filename": "/test.k.json", + "line": 4, + "node": { + "key": { + "column": 8, + "end_column": 14, + "end_line": 6, + "filename": "/test.k.json", + "line": 6, + "node": { + "is_long_string": false, + "raw_value": "\"city\"", + "type": "StringLit", + "value": "city" + } + }, + "operation": "Union", + "value": { + "column": 16, + "end_column": 24, + "end_line": 6, + "filename": "/test.k.json", + "line": 6, + "node": { + "is_long_string": false, + "raw_value": "\"London\"", + "type": "StringLit", + "value": "London" + } + } + } + }, + { + "column": 15, + "end_column": 5, + "end_line": 7, + "filename": "/test.k.json", + "line": 4, + "node": { + "key": { + "column": 8, + "end_column": 16, + "end_line": 5, + "filename": "/test.k.json", + "line": 5, + "node": { + "is_long_string": false, + "raw_value": "\"street\"", + "type": "StringLit", + "value": "street" + } + }, + "operation": "Union", + "value": { + "column": 18, + "end_column": 37, + "end_line": 5, + "filename": "/test.k.json", + "line": 5, + "node": { + "is_long_string": false, + "raw_value": "\"10 Downing Street\"", + "type": "StringLit", + "value": "10 Downing Street" + } + } + } + } + ], + "type": "Config" + } + } + } + }, + { + "column": 0, + "end_column": 1, + "end_line": 12, + "filename": "/test.k.json", + "line": 1, + "node": { + "key": { + "column": 4, + "end_column": 9, + "end_line": 3, + "filename": "/test.k.json", + "line": 3, + "node": { + "is_long_string": false, + "raw_value": "\"age\"", + "type": "StringLit", + "value": "age" + } + }, + "operation": "Union", + "value": { + "column": 11, + "end_column": 13, + "end_line": 3, + "filename": "/test.k.json", + "line": 3, + "node": { + "binary_suffix": null, + "type": "NumberLit", + "value": { + "type": "Int", + "value": 43 + } + } + } + } + }, + { + "column": 0, + "end_column": 1, + "end_line": 12, + "filename": "/test.k.json", + "line": 1, + "node": { + "key": { + "column": 4, + "end_column": 10, + "end_line": 2, + "filename": "/test.k.json", + "line": 2, + "node": { + "is_long_string": false, + "raw_value": "\"name\"", + "type": "StringLit", + "value": "name" + } + }, + "operation": "Union", + "value": { + "column": 12, + "end_column": 22, + "end_line": 2, + "filename": "/test.k.json", + "line": 2, + "node": { + "is_long_string": false, + "raw_value": "\"John Doe\"", + "type": "StringLit", + "value": "John Doe" + } + } + } + }, + { + "column": 0, + "end_column": 1, + "end_line": 12, + "filename": "/test.k.json", + "line": 1, + "node": { + "key": { + "column": 4, + "end_column": 12, + "end_line": 8, + "filename": "/test.k.json", + "line": 8, + "node": { + "is_long_string": false, + "raw_value": "\"phones\"", + "type": "StringLit", + "value": "phones" + } + }, + "operation": "Union", + "value": { + "column": 14, + "end_column": 5, + "end_line": 11, + "filename": "/test.k.json", + "line": 8, + "node": { + "ctx": "Load", + "elts": [ + { + "column": 8, + "end_column": 21, + "end_line": 9, + "filename": "/test.k.json", + "line": 9, + "node": { + "is_long_string": false, + "raw_value": "\"+44 1234567\"", + "type": "StringLit", + "value": "+44 1234567" + } + }, + { + "column": 8, + "end_column": 21, + "end_line": 10, + "filename": "/test.k.json", + "line": 10, + "node": { + "is_long_string": false, + "raw_value": "\"+44 2345678\"", + "type": "StringLit", + "value": "+44 2345678" + } + } + ], + "type": "List" + } + } + } + } + ], + "type": "Config" + } + }, + "kwargs": [], + "name": { + "column": 0, + "end_column": 1, + "end_line": 12, + "filename": "/test.k.json", + "line": 1, + "node": { + "ctx": "Load", + "names": [ + { + "column": 0, + "end_column": 1, + "end_line": 12, + "filename": "/test.k.json", + "line": 1, + "node": "test" + } + ], + "pkgpath": "" + } + }, + "type": "Schema" + } +} diff --git a/kclvm/tools/src/vet/snapshots/kclvm_tools__vet__tests__test_expr_builder__build_json_with_str-2.snap b/kclvm/tools/src/vet/snapshots/kclvm_tools__vet__tests__test_expr_builder__build_json_with_str-2.snap new file mode 100644 index 000000000..a063aa90f --- /dev/null +++ b/kclvm/tools/src/vet/snapshots/kclvm_tools__vet__tests__test_expr_builder__build_json_with_str-2.snap @@ -0,0 +1,159 @@ +--- +source: tools/src/vet/tests.rs +expression: got_ast_json_str +--- +{ + "column": 0, + "end_column": 1, + "end_line": 5, + "filename": "", + "line": 1, + "node": { + "args": [], + "config": { + "column": 0, + "end_column": 1, + "end_line": 5, + "filename": "", + "line": 1, + "node": { + "items": [ + { + "column": 0, + "end_column": 1, + "end_line": 5, + "filename": "", + "line": 1, + "node": { + "key": { + "column": 4, + "end_column": 9, + "end_line": 3, + "filename": "", + "line": 3, + "node": { + "is_long_string": false, + "raw_value": "\"age\"", + "type": "StringLit", + "value": "age" + } + }, + "operation": "Union", + "value": { + "column": 11, + "end_column": 13, + "end_line": 3, + "filename": "", + "line": 3, + "node": { + "binary_suffix": null, + "type": "NumberLit", + "value": { + "type": "Int", + "value": 18 + } + } + } + } + }, + { + "column": 0, + "end_column": 1, + "end_line": 5, + "filename": "", + "line": 1, + "node": { + "key": { + "column": 4, + "end_column": 13, + "end_line": 4, + "filename": "", + "line": 4, + "node": { + "is_long_string": false, + "raw_value": "\"message\"", + "type": "StringLit", + "value": "message" + } + }, + "operation": "Union", + "value": { + "column": 15, + "end_column": 30, + "end_line": 4, + "filename": "", + "line": 4, + "node": { + "is_long_string": false, + "raw_value": "\"This is Alice\"", + "type": "StringLit", + "value": "This is Alice" + } + } + } + }, + { + "column": 0, + "end_column": 1, + "end_line": 5, + "filename": "", + "line": 1, + "node": { + "key": { + "column": 4, + "end_column": 10, + "end_line": 2, + "filename": "", + "line": 2, + "node": { + "is_long_string": false, + "raw_value": "\"name\"", + "type": "StringLit", + "value": "name" + } + }, + "operation": "Union", + "value": { + "column": 12, + "end_column": 19, + "end_line": 2, + "filename": "", + "line": 2, + "node": { + "is_long_string": false, + "raw_value": "\"Alice\"", + "type": "StringLit", + "value": "Alice" + } + } + } + } + ], + "type": "Config" + } + }, + "kwargs": [], + "name": { + "column": 0, + "end_column": 1, + "end_line": 5, + "filename": "", + "line": 1, + "node": { + "ctx": "Load", + "names": [ + { + "column": 0, + "end_column": 1, + "end_line": 5, + "filename": "", + "line": 1, + "node": "simple" + } + ], + "pkgpath": "" + } + }, + "type": "Schema" + } +} diff --git a/kclvm/tools/src/vet/snapshots/kclvm_tools__vet__tests__test_expr_builder__build_json_with_str-3.snap b/kclvm/tools/src/vet/snapshots/kclvm_tools__vet__tests__test_expr_builder__build_json_with_str-3.snap new file mode 100644 index 000000000..1d2ef3c01 --- /dev/null +++ b/kclvm/tools/src/vet/snapshots/kclvm_tools__vet__tests__test_expr_builder__build_json_with_str-3.snap @@ -0,0 +1,19 @@ +--- +source: tools/src/vet/tests.rs +expression: got_ast_json_str +--- +{ + "column": 0, + "end_column": 1, + "end_line": 1, + "filename": "", + "line": 1, + "node": { + "binary_suffix": null, + "type": "NumberLit", + "value": { + "type": "Int", + "value": 1 + } + } +} diff --git a/kclvm/tools/src/vet/snapshots/kclvm_tools__vet__tests__test_expr_builder__build_json_with_str-4.snap b/kclvm/tools/src/vet/snapshots/kclvm_tools__vet__tests__test_expr_builder__build_json_with_str-4.snap new file mode 100644 index 000000000..2ed630993 --- /dev/null +++ b/kclvm/tools/src/vet/snapshots/kclvm_tools__vet__tests__test_expr_builder__build_json_with_str-4.snap @@ -0,0 +1,172 @@ +--- +source: tools/src/vet/tests.rs +expression: got_ast_json_str +--- +{ + "column": 0, + "end_column": 1, + "end_line": 7, + "filename": "", + "line": 1, + "node": { + "ctx": "Load", + "elts": [ + { + "column": 4, + "end_column": 5, + "end_line": 6, + "filename": "", + "line": 2, + "node": { + "args": [], + "config": { + "column": 4, + "end_column": 5, + "end_line": 6, + "filename": "", + "line": 2, + "node": { + "items": [ + { + "column": 4, + "end_column": 5, + "end_line": 6, + "filename": "", + "line": 2, + "node": { + "key": { + "column": 8, + "end_column": 13, + "end_line": 4, + "filename": "", + "line": 4, + "node": { + "is_long_string": false, + "raw_value": "\"age\"", + "type": "StringLit", + "value": "age" + } + }, + "operation": "Union", + "value": { + "column": 15, + "end_column": 17, + "end_line": 4, + "filename": "", + "line": 4, + "node": { + "binary_suffix": null, + "type": "NumberLit", + "value": { + "type": "Int", + "value": 18 + } + } + } + } + }, + { + "column": 4, + "end_column": 5, + "end_line": 6, + "filename": "", + "line": 2, + "node": { + "key": { + "column": 8, + "end_column": 17, + "end_line": 5, + "filename": "", + "line": 5, + "node": { + "is_long_string": false, + "raw_value": "\"message\"", + "type": "StringLit", + "value": "message" + } + }, + "operation": "Union", + "value": { + "column": 19, + "end_column": 34, + "end_line": 5, + "filename": "", + "line": 5, + "node": { + "is_long_string": false, + "raw_value": "\"This is Alice\"", + "type": "StringLit", + "value": "This is Alice" + } + } + } + }, + { + "column": 4, + "end_column": 5, + "end_line": 6, + "filename": "", + "line": 2, + "node": { + "key": { + "column": 8, + "end_column": 14, + "end_line": 3, + "filename": "", + "line": 3, + "node": { + "is_long_string": false, + "raw_value": "\"name\"", + "type": "StringLit", + "value": "name" + } + }, + "operation": "Union", + "value": { + "column": 16, + "end_column": 23, + "end_line": 3, + "filename": "", + "line": 3, + "node": { + "is_long_string": false, + "raw_value": "\"Alice\"", + "type": "StringLit", + "value": "Alice" + } + } + } + } + ], + "type": "Config" + } + }, + "kwargs": [], + "name": { + "column": 4, + "end_column": 5, + "end_line": 6, + "filename": "", + "line": 2, + "node": { + "ctx": "Load", + "names": [ + { + "column": 4, + "end_column": 5, + "end_line": 6, + "filename": "", + "line": 2, + "node": "list" + } + ], + "pkgpath": "" + } + }, + "type": "Schema" + } + } + ], + "type": "List" + } +} diff --git a/kclvm/tools/src/vet/snapshots/kclvm_tools__vet__tests__test_expr_builder__build_json_with_str-5.snap b/kclvm/tools/src/vet/snapshots/kclvm_tools__vet__tests__test_expr_builder__build_json_with_str-5.snap new file mode 100644 index 000000000..5ce3d0ea9 --- /dev/null +++ b/kclvm/tools/src/vet/snapshots/kclvm_tools__vet__tests__test_expr_builder__build_json_with_str-5.snap @@ -0,0 +1,420 @@ +--- +source: tools/src/vet/tests.rs +expression: got_ast_json_str +--- +{ + "column": 0, + "end_column": 1, + "end_line": 13, + "filename": "", + "line": 1, + "node": { + "args": [], + "config": { + "column": 0, + "end_column": 1, + "end_line": 13, + "filename": "", + "line": 1, + "node": { + "items": [ + { + "column": 0, + "end_column": 1, + "end_line": 13, + "filename": "", + "line": 1, + "node": { + "key": { + "column": 4, + "end_column": 9, + "end_line": 3, + "filename": "", + "line": 3, + "node": { + "is_long_string": false, + "raw_value": "\"age\"", + "type": "StringLit", + "value": "age" + } + }, + "operation": "Union", + "value": { + "column": 11, + "end_column": 13, + "end_line": 3, + "filename": "", + "line": 3, + "node": { + "binary_suffix": null, + "type": "NumberLit", + "value": { + "type": "Int", + "value": 18 + } + } + } + } + }, + { + "column": 0, + "end_column": 1, + "end_line": 13, + "filename": "", + "line": 1, + "node": { + "key": { + "column": 4, + "end_column": 10, + "end_line": 5, + "filename": "", + "line": 5, + "node": { + "is_long_string": false, + "raw_value": "\"data\"", + "type": "StringLit", + "value": "data" + } + }, + "operation": "Union", + "value": { + "column": 12, + "end_column": 5, + "end_line": 8, + "filename": "", + "line": 5, + "node": { + "items": [ + { + "column": 12, + "end_column": 5, + "end_line": 8, + "filename": "", + "line": 5, + "node": { + "key": { + "column": 8, + "end_column": 12, + "end_line": 6, + "filename": "", + "line": 6, + "node": { + "is_long_string": false, + "raw_value": "\"id\"", + "type": "StringLit", + "value": "id" + } + }, + "operation": "Union", + "value": { + "column": 14, + "end_column": 15, + "end_line": 6, + "filename": "", + "line": 6, + "node": { + "binary_suffix": null, + "type": "NumberLit", + "value": { + "type": "Int", + "value": 1 + } + } + } + } + }, + { + "column": 12, + "end_column": 5, + "end_line": 8, + "filename": "", + "line": 5, + "node": { + "key": { + "column": 8, + "end_column": 15, + "end_line": 7, + "filename": "", + "line": 7, + "node": { + "is_long_string": false, + "raw_value": "\"value\"", + "type": "StringLit", + "value": "value" + } + }, + "operation": "Union", + "value": { + "column": 17, + "end_column": 25, + "end_line": 7, + "filename": "", + "line": 7, + "node": { + "is_long_string": false, + "raw_value": "\"value1\"", + "type": "StringLit", + "value": "value1" + } + } + } + } + ], + "type": "Config" + } + } + } + }, + { + "column": 0, + "end_column": 1, + "end_line": 13, + "filename": "", + "line": 1, + "node": { + "key": { + "column": 4, + "end_column": 8, + "end_line": 12, + "filename": "", + "line": 12, + "node": { + "is_long_string": false, + "raw_value": "\"hc\"", + "type": "StringLit", + "value": "hc" + } + }, + "operation": "Union", + "value": { + "column": 10, + "end_column": 19, + "end_line": 12, + "filename": "", + "line": 12, + "node": { + "ctx": "Load", + "elts": [ + { + "column": 11, + "end_column": 12, + "end_line": 12, + "filename": "", + "line": 12, + "node": { + "binary_suffix": null, + "type": "NumberLit", + "value": { + "type": "Int", + "value": 1 + } + } + }, + { + "column": 14, + "end_column": 15, + "end_line": 12, + "filename": "", + "line": 12, + "node": { + "binary_suffix": null, + "type": "NumberLit", + "value": { + "type": "Int", + "value": 2 + } + } + }, + { + "column": 17, + "end_column": 18, + "end_line": 12, + "filename": "", + "line": 12, + "node": { + "binary_suffix": null, + "type": "NumberLit", + "value": { + "type": "Int", + "value": 3 + } + } + } + ], + "type": "List" + } + } + } + }, + { + "column": 0, + "end_column": 1, + "end_line": 13, + "filename": "", + "line": 1, + "node": { + "key": { + "column": 4, + "end_column": 12, + "end_line": 9, + "filename": "", + "line": 9, + "node": { + "is_long_string": false, + "raw_value": "\"labels\"", + "type": "StringLit", + "value": "labels" + } + }, + "operation": "Union", + "value": { + "column": 14, + "end_column": 5, + "end_line": 11, + "filename": "", + "line": 9, + "node": { + "items": [ + { + "column": 14, + "end_column": 5, + "end_line": 11, + "filename": "", + "line": 9, + "node": { + "key": { + "column": 8, + "end_column": 13, + "end_line": 10, + "filename": "", + "line": 10, + "node": { + "is_long_string": false, + "raw_value": "\"key\"", + "type": "StringLit", + "value": "key" + } + }, + "operation": "Union", + "value": { + "column": 15, + "end_column": 22, + "end_line": 10, + "filename": "", + "line": 10, + "node": { + "is_long_string": false, + "raw_value": "\"value\"", + "type": "StringLit", + "value": "value" + } + } + } + } + ], + "type": "Config" + } + } + } + }, + { + "column": 0, + "end_column": 1, + "end_line": 13, + "filename": "", + "line": 1, + "node": { + "key": { + "column": 4, + "end_column": 13, + "end_line": 4, + "filename": "", + "line": 4, + "node": { + "is_long_string": false, + "raw_value": "\"message\"", + "type": "StringLit", + "value": "message" + } + }, + "operation": "Union", + "value": { + "column": 15, + "end_column": 30, + "end_line": 4, + "filename": "", + "line": 4, + "node": { + "is_long_string": false, + "raw_value": "\"This is Alice\"", + "type": "StringLit", + "value": "This is Alice" + } + } + } + }, + { + "column": 0, + "end_column": 1, + "end_line": 13, + "filename": "", + "line": 1, + "node": { + "key": { + "column": 4, + "end_column": 10, + "end_line": 2, + "filename": "", + "line": 2, + "node": { + "is_long_string": false, + "raw_value": "\"name\"", + "type": "StringLit", + "value": "name" + } + }, + "operation": "Union", + "value": { + "column": 12, + "end_column": 19, + "end_line": 2, + "filename": "", + "line": 2, + "node": { + "is_long_string": false, + "raw_value": "\"Alice\"", + "type": "StringLit", + "value": "Alice" + } + } + } + } + ], + "type": "Config" + } + }, + "kwargs": [], + "name": { + "column": 0, + "end_column": 1, + "end_line": 13, + "filename": "", + "line": 1, + "node": { + "ctx": "Load", + "names": [ + { + "column": 0, + "end_column": 1, + "end_line": 13, + "filename": "", + "line": 1, + "node": "complex" + } + ], + "pkgpath": "" + } + }, + "type": "Schema" + } +} diff --git a/kclvm/tools/src/vet/snapshots/kclvm_tools__vet__tests__test_expr_builder__build_json_with_str-6.snap b/kclvm/tools/src/vet/snapshots/kclvm_tools__vet__tests__test_expr_builder__build_json_with_str-6.snap new file mode 100644 index 000000000..a13001bb6 --- /dev/null +++ b/kclvm/tools/src/vet/snapshots/kclvm_tools__vet__tests__test_expr_builder__build_json_with_str-6.snap @@ -0,0 +1,83 @@ +--- +source: tools/src/vet/tests.rs +expression: got_ast_json_str +--- +{ + "column": 0, + "end_column": 1, + "end_line": 3, + "filename": "", + "line": 1, + "node": { + "args": [], + "config": { + "column": 0, + "end_column": 1, + "end_line": 3, + "filename": "", + "line": 1, + "node": { + "items": [ + { + "column": 0, + "end_column": 1, + "end_line": 3, + "filename": "", + "line": 1, + "node": { + "key": { + "column": 4, + "end_column": 16, + "end_line": 2, + "filename": "", + "line": 2, + "node": { + "is_long_string": false, + "raw_value": "\"null_value\"", + "type": "StringLit", + "value": "null_value" + } + }, + "operation": "Union", + "value": { + "column": 18, + "end_column": 22, + "end_line": 2, + "filename": "", + "line": 2, + "node": { + "type": "NameConstantLit", + "value": "None" + } + } + } + } + ], + "type": "Config" + } + }, + "kwargs": [], + "name": { + "column": 0, + "end_column": 1, + "end_line": 3, + "filename": "", + "line": 1, + "node": { + "ctx": "Load", + "names": [ + { + "column": 0, + "end_column": 1, + "end_line": 3, + "filename": "", + "line": 1, + "node": "only_with_null" + } + ], + "pkgpath": "" + } + }, + "type": "Schema" + } +} diff --git a/kclvm/tools/src/vet/snapshots/kclvm_tools__vet__tests__test_expr_builder__build_json_with_str-7.snap b/kclvm/tools/src/vet/snapshots/kclvm_tools__vet__tests__test_expr_builder__build_json_with_str-7.snap new file mode 100644 index 000000000..41b75418e --- /dev/null +++ b/kclvm/tools/src/vet/snapshots/kclvm_tools__vet__tests__test_expr_builder__build_json_with_str-7.snap @@ -0,0 +1,83 @@ +--- +source: tools/src/vet/tests.rs +expression: got_ast_json_str +--- +{ + "column": 0, + "end_column": 1, + "end_line": 3, + "filename": "", + "line": 1, + "node": { + "args": [], + "config": { + "column": 0, + "end_column": 1, + "end_line": 3, + "filename": "", + "line": 1, + "node": { + "items": [ + { + "column": 0, + "end_column": 1, + "end_line": 3, + "filename": "", + "line": 1, + "node": { + "key": { + "column": 4, + "end_column": 10, + "end_line": 2, + "filename": "", + "line": 2, + "node": { + "is_long_string": false, + "raw_value": "\"flag\"", + "type": "StringLit", + "value": "flag" + } + }, + "operation": "Union", + "value": { + "column": 12, + "end_column": 16, + "end_line": 2, + "filename": "", + "line": 2, + "node": { + "type": "NameConstantLit", + "value": "True" + } + } + } + } + ], + "type": "Config" + } + }, + "kwargs": [], + "name": { + "column": 0, + "end_column": 1, + "end_line": 3, + "filename": "", + "line": 1, + "node": { + "ctx": "Load", + "names": [ + { + "column": 0, + "end_column": 1, + "end_line": 3, + "filename": "", + "line": 1, + "node": "only_with_bool" + } + ], + "pkgpath": "" + } + }, + "type": "Schema" + } +} diff --git a/kclvm/tools/src/vet/snapshots/kclvm_tools__vet__tests__test_expr_builder__build_json_with_str-8.snap b/kclvm/tools/src/vet/snapshots/kclvm_tools__vet__tests__test_expr_builder__build_json_with_str-8.snap new file mode 100644 index 000000000..5d2391c89 --- /dev/null +++ b/kclvm/tools/src/vet/snapshots/kclvm_tools__vet__tests__test_expr_builder__build_json_with_str-8.snap @@ -0,0 +1,87 @@ +--- +source: tools/src/vet/tests.rs +expression: got_ast_json_str +--- +{ + "column": 0, + "end_column": 1, + "end_line": 3, + "filename": "", + "line": 1, + "node": { + "args": [], + "config": { + "column": 0, + "end_column": 1, + "end_line": 3, + "filename": "", + "line": 1, + "node": { + "items": [ + { + "column": 0, + "end_column": 1, + "end_line": 3, + "filename": "", + "line": 1, + "node": { + "key": { + "column": 4, + "end_column": 17, + "end_line": 2, + "filename": "", + "line": 2, + "node": { + "is_long_string": false, + "raw_value": "\"float_value\"", + "type": "StringLit", + "value": "float_value" + } + }, + "operation": "Union", + "value": { + "column": 19, + "end_column": 23, + "end_line": 2, + "filename": "", + "line": 2, + "node": { + "binary_suffix": null, + "type": "NumberLit", + "value": { + "type": "Float", + "value": 0.33 + } + } + } + } + } + ], + "type": "Config" + } + }, + "kwargs": [], + "name": { + "column": 0, + "end_column": 1, + "end_line": 3, + "filename": "", + "line": 1, + "node": { + "ctx": "Load", + "names": [ + { + "column": 0, + "end_column": 1, + "end_line": 3, + "filename": "", + "line": 1, + "node": "only_with_float" + } + ], + "pkgpath": "" + } + }, + "type": "Schema" + } +} diff --git a/kclvm/tools/src/vet/snapshots/kclvm_tools__vet__tests__test_expr_builder__build_json_with_str.snap b/kclvm/tools/src/vet/snapshots/kclvm_tools__vet__tests__test_expr_builder__build_json_with_str.snap new file mode 100644 index 000000000..5c11935d5 --- /dev/null +++ b/kclvm/tools/src/vet/snapshots/kclvm_tools__vet__tests__test_expr_builder__build_json_with_str.snap @@ -0,0 +1,292 @@ +--- +source: tools/src/vet/tests.rs +expression: got_ast_json_str +--- +{ + "column": 0, + "end_column": 1, + "end_line": 12, + "filename": "", + "line": 1, + "node": { + "args": [], + "config": { + "column": 0, + "end_column": 1, + "end_line": 12, + "filename": "", + "line": 1, + "node": { + "items": [ + { + "column": 0, + "end_column": 1, + "end_line": 12, + "filename": "", + "line": 1, + "node": { + "key": { + "column": 4, + "end_column": 13, + "end_line": 4, + "filename": "", + "line": 4, + "node": { + "is_long_string": false, + "raw_value": "\"address\"", + "type": "StringLit", + "value": "address" + } + }, + "operation": "Union", + "value": { + "column": 15, + "end_column": 5, + "end_line": 7, + "filename": "", + "line": 4, + "node": { + "items": [ + { + "column": 15, + "end_column": 5, + "end_line": 7, + "filename": "", + "line": 4, + "node": { + "key": { + "column": 8, + "end_column": 14, + "end_line": 6, + "filename": "", + "line": 6, + "node": { + "is_long_string": false, + "raw_value": "\"city\"", + "type": "StringLit", + "value": "city" + } + }, + "operation": "Union", + "value": { + "column": 16, + "end_column": 24, + "end_line": 6, + "filename": "", + "line": 6, + "node": { + "is_long_string": false, + "raw_value": "\"London\"", + "type": "StringLit", + "value": "London" + } + } + } + }, + { + "column": 15, + "end_column": 5, + "end_line": 7, + "filename": "", + "line": 4, + "node": { + "key": { + "column": 8, + "end_column": 16, + "end_line": 5, + "filename": "", + "line": 5, + "node": { + "is_long_string": false, + "raw_value": "\"street\"", + "type": "StringLit", + "value": "street" + } + }, + "operation": "Union", + "value": { + "column": 18, + "end_column": 37, + "end_line": 5, + "filename": "", + "line": 5, + "node": { + "is_long_string": false, + "raw_value": "\"10 Downing Street\"", + "type": "StringLit", + "value": "10 Downing Street" + } + } + } + } + ], + "type": "Config" + } + } + } + }, + { + "column": 0, + "end_column": 1, + "end_line": 12, + "filename": "", + "line": 1, + "node": { + "key": { + "column": 4, + "end_column": 9, + "end_line": 3, + "filename": "", + "line": 3, + "node": { + "is_long_string": false, + "raw_value": "\"age\"", + "type": "StringLit", + "value": "age" + } + }, + "operation": "Union", + "value": { + "column": 11, + "end_column": 13, + "end_line": 3, + "filename": "", + "line": 3, + "node": { + "binary_suffix": null, + "type": "NumberLit", + "value": { + "type": "Int", + "value": 43 + } + } + } + } + }, + { + "column": 0, + "end_column": 1, + "end_line": 12, + "filename": "", + "line": 1, + "node": { + "key": { + "column": 4, + "end_column": 10, + "end_line": 2, + "filename": "", + "line": 2, + "node": { + "is_long_string": false, + "raw_value": "\"name\"", + "type": "StringLit", + "value": "name" + } + }, + "operation": "Union", + "value": { + "column": 12, + "end_column": 22, + "end_line": 2, + "filename": "", + "line": 2, + "node": { + "is_long_string": false, + "raw_value": "\"John Doe\"", + "type": "StringLit", + "value": "John Doe" + } + } + } + }, + { + "column": 0, + "end_column": 1, + "end_line": 12, + "filename": "", + "line": 1, + "node": { + "key": { + "column": 4, + "end_column": 12, + "end_line": 8, + "filename": "", + "line": 8, + "node": { + "is_long_string": false, + "raw_value": "\"phones\"", + "type": "StringLit", + "value": "phones" + } + }, + "operation": "Union", + "value": { + "column": 14, + "end_column": 5, + "end_line": 11, + "filename": "", + "line": 8, + "node": { + "ctx": "Load", + "elts": [ + { + "column": 8, + "end_column": 21, + "end_line": 9, + "filename": "", + "line": 9, + "node": { + "is_long_string": false, + "raw_value": "\"+44 1234567\"", + "type": "StringLit", + "value": "+44 1234567" + } + }, + { + "column": 8, + "end_column": 21, + "end_line": 10, + "filename": "", + "line": 10, + "node": { + "is_long_string": false, + "raw_value": "\"+44 2345678\"", + "type": "StringLit", + "value": "+44 2345678" + } + } + ], + "type": "List" + } + } + } + } + ], + "type": "Config" + } + }, + "kwargs": [], + "name": { + "column": 0, + "end_column": 1, + "end_line": 12, + "filename": "", + "line": 1, + "node": { + "ctx": "Load", + "names": [ + { + "column": 0, + "end_column": 1, + "end_line": 12, + "filename": "", + "line": 1, + "node": "test" + } + ], + "pkgpath": "" + } + }, + "type": "Schema" + } +} diff --git a/kclvm/tools/src/vet/snapshots/kclvm_tools__vet__tests__test_expr_builder__build_with_json_no_schema_name-2.snap b/kclvm/tools/src/vet/snapshots/kclvm_tools__vet__tests__test_expr_builder__build_with_json_no_schema_name-2.snap new file mode 100644 index 000000000..b9305a4e6 --- /dev/null +++ b/kclvm/tools/src/vet/snapshots/kclvm_tools__vet__tests__test_expr_builder__build_with_json_no_schema_name-2.snap @@ -0,0 +1,126 @@ +--- +source: tools/src/vet/tests.rs +expression: got_ast_json_str +--- +{ + "column": 0, + "end_column": 1, + "end_line": 5, + "filename": "/simple.k.json", + "line": 1, + "node": { + "items": [ + { + "column": 0, + "end_column": 1, + "end_line": 5, + "filename": "/simple.k.json", + "line": 1, + "node": { + "key": { + "column": 4, + "end_column": 9, + "end_line": 3, + "filename": "/simple.k.json", + "line": 3, + "node": { + "is_long_string": false, + "raw_value": "\"age\"", + "type": "StringLit", + "value": "age" + } + }, + "operation": "Union", + "value": { + "column": 11, + "end_column": 13, + "end_line": 3, + "filename": "/simple.k.json", + "line": 3, + "node": { + "binary_suffix": null, + "type": "NumberLit", + "value": { + "type": "Int", + "value": 18 + } + } + } + } + }, + { + "column": 0, + "end_column": 1, + "end_line": 5, + "filename": "/simple.k.json", + "line": 1, + "node": { + "key": { + "column": 4, + "end_column": 13, + "end_line": 4, + "filename": "/simple.k.json", + "line": 4, + "node": { + "is_long_string": false, + "raw_value": "\"message\"", + "type": "StringLit", + "value": "message" + } + }, + "operation": "Union", + "value": { + "column": 15, + "end_column": 30, + "end_line": 4, + "filename": "/simple.k.json", + "line": 4, + "node": { + "is_long_string": false, + "raw_value": "\"This is Alice\"", + "type": "StringLit", + "value": "This is Alice" + } + } + } + }, + { + "column": 0, + "end_column": 1, + "end_line": 5, + "filename": "/simple.k.json", + "line": 1, + "node": { + "key": { + "column": 4, + "end_column": 10, + "end_line": 2, + "filename": "/simple.k.json", + "line": 2, + "node": { + "is_long_string": false, + "raw_value": "\"name\"", + "type": "StringLit", + "value": "name" + } + }, + "operation": "Union", + "value": { + "column": 12, + "end_column": 19, + "end_line": 2, + "filename": "/simple.k.json", + "line": 2, + "node": { + "is_long_string": false, + "raw_value": "\"Alice\"", + "type": "StringLit", + "value": "Alice" + } + } + } + } + ], + "type": "Config" + } +} diff --git a/kclvm/tools/src/vet/snapshots/kclvm_tools__vet__tests__test_expr_builder__build_with_json_no_schema_name-3.snap b/kclvm/tools/src/vet/snapshots/kclvm_tools__vet__tests__test_expr_builder__build_with_json_no_schema_name-3.snap new file mode 100644 index 000000000..19165aa64 --- /dev/null +++ b/kclvm/tools/src/vet/snapshots/kclvm_tools__vet__tests__test_expr_builder__build_with_json_no_schema_name-3.snap @@ -0,0 +1,19 @@ +--- +source: tools/src/vet/tests.rs +expression: got_ast_json_str +--- +{ + "column": 0, + "end_column": 1, + "end_line": 1, + "filename": "/plain_value.k.json", + "line": 1, + "node": { + "binary_suffix": null, + "type": "NumberLit", + "value": { + "type": "Int", + "value": 1 + } + } +} diff --git a/kclvm/tools/src/vet/snapshots/kclvm_tools__vet__tests__test_expr_builder__build_with_json_no_schema_name-4.snap b/kclvm/tools/src/vet/snapshots/kclvm_tools__vet__tests__test_expr_builder__build_with_json_no_schema_name-4.snap new file mode 100644 index 000000000..ffb0c638c --- /dev/null +++ b/kclvm/tools/src/vet/snapshots/kclvm_tools__vet__tests__test_expr_builder__build_with_json_no_schema_name-4.snap @@ -0,0 +1,139 @@ +--- +source: tools/src/vet/tests.rs +expression: got_ast_json_str +--- +{ + "column": 0, + "end_column": 1, + "end_line": 7, + "filename": "/list.k.json", + "line": 1, + "node": { + "ctx": "Load", + "elts": [ + { + "column": 4, + "end_column": 5, + "end_line": 6, + "filename": "/list.k.json", + "line": 2, + "node": { + "items": [ + { + "column": 4, + "end_column": 5, + "end_line": 6, + "filename": "/list.k.json", + "line": 2, + "node": { + "key": { + "column": 8, + "end_column": 13, + "end_line": 4, + "filename": "/list.k.json", + "line": 4, + "node": { + "is_long_string": false, + "raw_value": "\"age\"", + "type": "StringLit", + "value": "age" + } + }, + "operation": "Union", + "value": { + "column": 15, + "end_column": 17, + "end_line": 4, + "filename": "/list.k.json", + "line": 4, + "node": { + "binary_suffix": null, + "type": "NumberLit", + "value": { + "type": "Int", + "value": 18 + } + } + } + } + }, + { + "column": 4, + "end_column": 5, + "end_line": 6, + "filename": "/list.k.json", + "line": 2, + "node": { + "key": { + "column": 8, + "end_column": 17, + "end_line": 5, + "filename": "/list.k.json", + "line": 5, + "node": { + "is_long_string": false, + "raw_value": "\"message\"", + "type": "StringLit", + "value": "message" + } + }, + "operation": "Union", + "value": { + "column": 19, + "end_column": 34, + "end_line": 5, + "filename": "/list.k.json", + "line": 5, + "node": { + "is_long_string": false, + "raw_value": "\"This is Alice\"", + "type": "StringLit", + "value": "This is Alice" + } + } + } + }, + { + "column": 4, + "end_column": 5, + "end_line": 6, + "filename": "/list.k.json", + "line": 2, + "node": { + "key": { + "column": 8, + "end_column": 14, + "end_line": 3, + "filename": "/list.k.json", + "line": 3, + "node": { + "is_long_string": false, + "raw_value": "\"name\"", + "type": "StringLit", + "value": "name" + } + }, + "operation": "Union", + "value": { + "column": 16, + "end_column": 23, + "end_line": 3, + "filename": "/list.k.json", + "line": 3, + "node": { + "is_long_string": false, + "raw_value": "\"Alice\"", + "type": "StringLit", + "value": "Alice" + } + } + } + } + ], + "type": "Config" + } + } + ], + "type": "List" + } +} diff --git a/kclvm/tools/src/vet/snapshots/kclvm_tools__vet__tests__test_expr_builder__build_with_json_no_schema_name-5.snap b/kclvm/tools/src/vet/snapshots/kclvm_tools__vet__tests__test_expr_builder__build_with_json_no_schema_name-5.snap new file mode 100644 index 000000000..33bff5b22 --- /dev/null +++ b/kclvm/tools/src/vet/snapshots/kclvm_tools__vet__tests__test_expr_builder__build_with_json_no_schema_name-5.snap @@ -0,0 +1,387 @@ +--- +source: tools/src/vet/tests.rs +expression: got_ast_json_str +--- +{ + "column": 0, + "end_column": 1, + "end_line": 13, + "filename": "/complex.k.json", + "line": 1, + "node": { + "items": [ + { + "column": 0, + "end_column": 1, + "end_line": 13, + "filename": "/complex.k.json", + "line": 1, + "node": { + "key": { + "column": 4, + "end_column": 9, + "end_line": 3, + "filename": "/complex.k.json", + "line": 3, + "node": { + "is_long_string": false, + "raw_value": "\"age\"", + "type": "StringLit", + "value": "age" + } + }, + "operation": "Union", + "value": { + "column": 11, + "end_column": 13, + "end_line": 3, + "filename": "/complex.k.json", + "line": 3, + "node": { + "binary_suffix": null, + "type": "NumberLit", + "value": { + "type": "Int", + "value": 18 + } + } + } + } + }, + { + "column": 0, + "end_column": 1, + "end_line": 13, + "filename": "/complex.k.json", + "line": 1, + "node": { + "key": { + "column": 4, + "end_column": 10, + "end_line": 5, + "filename": "/complex.k.json", + "line": 5, + "node": { + "is_long_string": false, + "raw_value": "\"data\"", + "type": "StringLit", + "value": "data" + } + }, + "operation": "Union", + "value": { + "column": 12, + "end_column": 5, + "end_line": 8, + "filename": "/complex.k.json", + "line": 5, + "node": { + "items": [ + { + "column": 12, + "end_column": 5, + "end_line": 8, + "filename": "/complex.k.json", + "line": 5, + "node": { + "key": { + "column": 8, + "end_column": 12, + "end_line": 6, + "filename": "/complex.k.json", + "line": 6, + "node": { + "is_long_string": false, + "raw_value": "\"id\"", + "type": "StringLit", + "value": "id" + } + }, + "operation": "Union", + "value": { + "column": 14, + "end_column": 15, + "end_line": 6, + "filename": "/complex.k.json", + "line": 6, + "node": { + "binary_suffix": null, + "type": "NumberLit", + "value": { + "type": "Int", + "value": 1 + } + } + } + } + }, + { + "column": 12, + "end_column": 5, + "end_line": 8, + "filename": "/complex.k.json", + "line": 5, + "node": { + "key": { + "column": 8, + "end_column": 15, + "end_line": 7, + "filename": "/complex.k.json", + "line": 7, + "node": { + "is_long_string": false, + "raw_value": "\"value\"", + "type": "StringLit", + "value": "value" + } + }, + "operation": "Union", + "value": { + "column": 17, + "end_column": 25, + "end_line": 7, + "filename": "/complex.k.json", + "line": 7, + "node": { + "is_long_string": false, + "raw_value": "\"value1\"", + "type": "StringLit", + "value": "value1" + } + } + } + } + ], + "type": "Config" + } + } + } + }, + { + "column": 0, + "end_column": 1, + "end_line": 13, + "filename": "/complex.k.json", + "line": 1, + "node": { + "key": { + "column": 4, + "end_column": 8, + "end_line": 12, + "filename": "/complex.k.json", + "line": 12, + "node": { + "is_long_string": false, + "raw_value": "\"hc\"", + "type": "StringLit", + "value": "hc" + } + }, + "operation": "Union", + "value": { + "column": 10, + "end_column": 19, + "end_line": 12, + "filename": "/complex.k.json", + "line": 12, + "node": { + "ctx": "Load", + "elts": [ + { + "column": 11, + "end_column": 12, + "end_line": 12, + "filename": "/complex.k.json", + "line": 12, + "node": { + "binary_suffix": null, + "type": "NumberLit", + "value": { + "type": "Int", + "value": 1 + } + } + }, + { + "column": 14, + "end_column": 15, + "end_line": 12, + "filename": "/complex.k.json", + "line": 12, + "node": { + "binary_suffix": null, + "type": "NumberLit", + "value": { + "type": "Int", + "value": 2 + } + } + }, + { + "column": 17, + "end_column": 18, + "end_line": 12, + "filename": "/complex.k.json", + "line": 12, + "node": { + "binary_suffix": null, + "type": "NumberLit", + "value": { + "type": "Int", + "value": 3 + } + } + } + ], + "type": "List" + } + } + } + }, + { + "column": 0, + "end_column": 1, + "end_line": 13, + "filename": "/complex.k.json", + "line": 1, + "node": { + "key": { + "column": 4, + "end_column": 12, + "end_line": 9, + "filename": "/complex.k.json", + "line": 9, + "node": { + "is_long_string": false, + "raw_value": "\"labels\"", + "type": "StringLit", + "value": "labels" + } + }, + "operation": "Union", + "value": { + "column": 14, + "end_column": 5, + "end_line": 11, + "filename": "/complex.k.json", + "line": 9, + "node": { + "items": [ + { + "column": 14, + "end_column": 5, + "end_line": 11, + "filename": "/complex.k.json", + "line": 9, + "node": { + "key": { + "column": 8, + "end_column": 13, + "end_line": 10, + "filename": "/complex.k.json", + "line": 10, + "node": { + "is_long_string": false, + "raw_value": "\"key\"", + "type": "StringLit", + "value": "key" + } + }, + "operation": "Union", + "value": { + "column": 15, + "end_column": 22, + "end_line": 10, + "filename": "/complex.k.json", + "line": 10, + "node": { + "is_long_string": false, + "raw_value": "\"value\"", + "type": "StringLit", + "value": "value" + } + } + } + } + ], + "type": "Config" + } + } + } + }, + { + "column": 0, + "end_column": 1, + "end_line": 13, + "filename": "/complex.k.json", + "line": 1, + "node": { + "key": { + "column": 4, + "end_column": 13, + "end_line": 4, + "filename": "/complex.k.json", + "line": 4, + "node": { + "is_long_string": false, + "raw_value": "\"message\"", + "type": "StringLit", + "value": "message" + } + }, + "operation": "Union", + "value": { + "column": 15, + "end_column": 30, + "end_line": 4, + "filename": "/complex.k.json", + "line": 4, + "node": { + "is_long_string": false, + "raw_value": "\"This is Alice\"", + "type": "StringLit", + "value": "This is Alice" + } + } + } + }, + { + "column": 0, + "end_column": 1, + "end_line": 13, + "filename": "/complex.k.json", + "line": 1, + "node": { + "key": { + "column": 4, + "end_column": 10, + "end_line": 2, + "filename": "/complex.k.json", + "line": 2, + "node": { + "is_long_string": false, + "raw_value": "\"name\"", + "type": "StringLit", + "value": "name" + } + }, + "operation": "Union", + "value": { + "column": 12, + "end_column": 19, + "end_line": 2, + "filename": "/complex.k.json", + "line": 2, + "node": { + "is_long_string": false, + "raw_value": "\"Alice\"", + "type": "StringLit", + "value": "Alice" + } + } + } + } + ], + "type": "Config" + } +} diff --git a/kclvm/tools/src/vet/snapshots/kclvm_tools__vet__tests__test_expr_builder__build_with_json_no_schema_name-6.snap b/kclvm/tools/src/vet/snapshots/kclvm_tools__vet__tests__test_expr_builder__build_with_json_no_schema_name-6.snap new file mode 100644 index 000000000..72f2a5a52 --- /dev/null +++ b/kclvm/tools/src/vet/snapshots/kclvm_tools__vet__tests__test_expr_builder__build_with_json_no_schema_name-6.snap @@ -0,0 +1,50 @@ +--- +source: tools/src/vet/tests.rs +expression: got_ast_json_str +--- +{ + "column": 0, + "end_column": 1, + "end_line": 3, + "filename": "/only_with_null.json", + "line": 1, + "node": { + "items": [ + { + "column": 0, + "end_column": 1, + "end_line": 3, + "filename": "/only_with_null.json", + "line": 1, + "node": { + "key": { + "column": 4, + "end_column": 16, + "end_line": 2, + "filename": "/only_with_null.json", + "line": 2, + "node": { + "is_long_string": false, + "raw_value": "\"null_value\"", + "type": "StringLit", + "value": "null_value" + } + }, + "operation": "Union", + "value": { + "column": 18, + "end_column": 22, + "end_line": 2, + "filename": "/only_with_null.json", + "line": 2, + "node": { + "type": "NameConstantLit", + "value": "None" + } + } + } + } + ], + "type": "Config" + } +} diff --git a/kclvm/tools/src/vet/snapshots/kclvm_tools__vet__tests__test_expr_builder__build_with_json_no_schema_name-7.snap b/kclvm/tools/src/vet/snapshots/kclvm_tools__vet__tests__test_expr_builder__build_with_json_no_schema_name-7.snap new file mode 100644 index 000000000..39c2625f4 --- /dev/null +++ b/kclvm/tools/src/vet/snapshots/kclvm_tools__vet__tests__test_expr_builder__build_with_json_no_schema_name-7.snap @@ -0,0 +1,50 @@ +--- +source: tools/src/vet/tests.rs +expression: got_ast_json_str +--- +{ + "column": 0, + "end_column": 1, + "end_line": 3, + "filename": "/only_with_bool.json", + "line": 1, + "node": { + "items": [ + { + "column": 0, + "end_column": 1, + "end_line": 3, + "filename": "/only_with_bool.json", + "line": 1, + "node": { + "key": { + "column": 4, + "end_column": 10, + "end_line": 2, + "filename": "/only_with_bool.json", + "line": 2, + "node": { + "is_long_string": false, + "raw_value": "\"flag\"", + "type": "StringLit", + "value": "flag" + } + }, + "operation": "Union", + "value": { + "column": 12, + "end_column": 16, + "end_line": 2, + "filename": "/only_with_bool.json", + "line": 2, + "node": { + "type": "NameConstantLit", + "value": "True" + } + } + } + } + ], + "type": "Config" + } +} diff --git a/kclvm/tools/src/vet/snapshots/kclvm_tools__vet__tests__test_expr_builder__build_with_json_no_schema_name-8.snap b/kclvm/tools/src/vet/snapshots/kclvm_tools__vet__tests__test_expr_builder__build_with_json_no_schema_name-8.snap new file mode 100644 index 000000000..d33ba3462 --- /dev/null +++ b/kclvm/tools/src/vet/snapshots/kclvm_tools__vet__tests__test_expr_builder__build_with_json_no_schema_name-8.snap @@ -0,0 +1,54 @@ +--- +source: tools/src/vet/tests.rs +expression: got_ast_json_str +--- +{ + "column": 0, + "end_column": 1, + "end_line": 3, + "filename": "/only_with_float.json", + "line": 1, + "node": { + "items": [ + { + "column": 0, + "end_column": 1, + "end_line": 3, + "filename": "/only_with_float.json", + "line": 1, + "node": { + "key": { + "column": 4, + "end_column": 17, + "end_line": 2, + "filename": "/only_with_float.json", + "line": 2, + "node": { + "is_long_string": false, + "raw_value": "\"float_value\"", + "type": "StringLit", + "value": "float_value" + } + }, + "operation": "Union", + "value": { + "column": 19, + "end_column": 23, + "end_line": 2, + "filename": "/only_with_float.json", + "line": 2, + "node": { + "binary_suffix": null, + "type": "NumberLit", + "value": { + "type": "Float", + "value": 0.33 + } + } + } + } + } + ], + "type": "Config" + } +} diff --git a/kclvm/tools/src/vet/snapshots/kclvm_tools__vet__tests__test_expr_builder__build_with_json_no_schema_name.snap b/kclvm/tools/src/vet/snapshots/kclvm_tools__vet__tests__test_expr_builder__build_with_json_no_schema_name.snap new file mode 100644 index 000000000..e9fb5ad11 --- /dev/null +++ b/kclvm/tools/src/vet/snapshots/kclvm_tools__vet__tests__test_expr_builder__build_with_json_no_schema_name.snap @@ -0,0 +1,259 @@ +--- +source: tools/src/vet/tests.rs +expression: got_ast_json_str +--- +{ + "column": 0, + "end_column": 1, + "end_line": 12, + "filename": "/test.k.json", + "line": 1, + "node": { + "items": [ + { + "column": 0, + "end_column": 1, + "end_line": 12, + "filename": "/test.k.json", + "line": 1, + "node": { + "key": { + "column": 4, + "end_column": 13, + "end_line": 4, + "filename": "/test.k.json", + "line": 4, + "node": { + "is_long_string": false, + "raw_value": "\"address\"", + "type": "StringLit", + "value": "address" + } + }, + "operation": "Union", + "value": { + "column": 15, + "end_column": 5, + "end_line": 7, + "filename": "/test.k.json", + "line": 4, + "node": { + "items": [ + { + "column": 15, + "end_column": 5, + "end_line": 7, + "filename": "/test.k.json", + "line": 4, + "node": { + "key": { + "column": 8, + "end_column": 14, + "end_line": 6, + "filename": "/test.k.json", + "line": 6, + "node": { + "is_long_string": false, + "raw_value": "\"city\"", + "type": "StringLit", + "value": "city" + } + }, + "operation": "Union", + "value": { + "column": 16, + "end_column": 24, + "end_line": 6, + "filename": "/test.k.json", + "line": 6, + "node": { + "is_long_string": false, + "raw_value": "\"London\"", + "type": "StringLit", + "value": "London" + } + } + } + }, + { + "column": 15, + "end_column": 5, + "end_line": 7, + "filename": "/test.k.json", + "line": 4, + "node": { + "key": { + "column": 8, + "end_column": 16, + "end_line": 5, + "filename": "/test.k.json", + "line": 5, + "node": { + "is_long_string": false, + "raw_value": "\"street\"", + "type": "StringLit", + "value": "street" + } + }, + "operation": "Union", + "value": { + "column": 18, + "end_column": 37, + "end_line": 5, + "filename": "/test.k.json", + "line": 5, + "node": { + "is_long_string": false, + "raw_value": "\"10 Downing Street\"", + "type": "StringLit", + "value": "10 Downing Street" + } + } + } + } + ], + "type": "Config" + } + } + } + }, + { + "column": 0, + "end_column": 1, + "end_line": 12, + "filename": "/test.k.json", + "line": 1, + "node": { + "key": { + "column": 4, + "end_column": 9, + "end_line": 3, + "filename": "/test.k.json", + "line": 3, + "node": { + "is_long_string": false, + "raw_value": "\"age\"", + "type": "StringLit", + "value": "age" + } + }, + "operation": "Union", + "value": { + "column": 11, + "end_column": 13, + "end_line": 3, + "filename": "/test.k.json", + "line": 3, + "node": { + "binary_suffix": null, + "type": "NumberLit", + "value": { + "type": "Int", + "value": 43 + } + } + } + } + }, + { + "column": 0, + "end_column": 1, + "end_line": 12, + "filename": "/test.k.json", + "line": 1, + "node": { + "key": { + "column": 4, + "end_column": 10, + "end_line": 2, + "filename": "/test.k.json", + "line": 2, + "node": { + "is_long_string": false, + "raw_value": "\"name\"", + "type": "StringLit", + "value": "name" + } + }, + "operation": "Union", + "value": { + "column": 12, + "end_column": 22, + "end_line": 2, + "filename": "/test.k.json", + "line": 2, + "node": { + "is_long_string": false, + "raw_value": "\"John Doe\"", + "type": "StringLit", + "value": "John Doe" + } + } + } + }, + { + "column": 0, + "end_column": 1, + "end_line": 12, + "filename": "/test.k.json", + "line": 1, + "node": { + "key": { + "column": 4, + "end_column": 12, + "end_line": 8, + "filename": "/test.k.json", + "line": 8, + "node": { + "is_long_string": false, + "raw_value": "\"phones\"", + "type": "StringLit", + "value": "phones" + } + }, + "operation": "Union", + "value": { + "column": 14, + "end_column": 5, + "end_line": 11, + "filename": "/test.k.json", + "line": 8, + "node": { + "ctx": "Load", + "elts": [ + { + "column": 8, + "end_column": 21, + "end_line": 9, + "filename": "/test.k.json", + "line": 9, + "node": { + "is_long_string": false, + "raw_value": "\"+44 1234567\"", + "type": "StringLit", + "value": "+44 1234567" + } + }, + { + "column": 8, + "end_column": 21, + "end_line": 10, + "filename": "/test.k.json", + "line": 10, + "node": { + "is_long_string": false, + "raw_value": "\"+44 2345678\"", + "type": "StringLit", + "value": "+44 2345678" + } + } + ], + "type": "List" + } + } + } + } + ], + "type": "Config" + } +} diff --git a/kclvm/tools/src/vet/snapshots/kclvm_tools__vet__tests__test_expr_builder__build_with_yaml_no_schema_name-2.snap b/kclvm/tools/src/vet/snapshots/kclvm_tools__vet__tests__test_expr_builder__build_with_yaml_no_schema_name-2.snap new file mode 100644 index 000000000..5bb8cc69b --- /dev/null +++ b/kclvm/tools/src/vet/snapshots/kclvm_tools__vet__tests__test_expr_builder__build_with_yaml_no_schema_name-2.snap @@ -0,0 +1,5 @@ +--- +source: tools/src/vet/tests.rs +expression: got_ast_yaml_str +--- +{"node":{"type":"Config","items":[{"node":{"key":{"node":{"type":"StringLit","is_long_string":false,"raw_value":"\"name\"","value":"name"},"filename":"/simple.k.yaml","line":1,"column":0,"end_line":0,"end_column":0},"value":{"node":{"type":"StringLit","is_long_string":false,"raw_value":"\"Alice,\"","value":"Alice,"},"filename":"/simple.k.yaml","line":1,"column":6,"end_line":0,"end_column":0},"operation":"Union"},"filename":"/simple.k.yaml","line":1,"column":4,"end_line":0,"end_column":0},{"node":{"key":{"node":{"type":"StringLit","is_long_string":false,"raw_value":"\"age\"","value":"age"},"filename":"/simple.k.yaml","line":2,"column":0,"end_line":0,"end_column":0},"value":{"node":{"type":"StringLit","is_long_string":false,"raw_value":"\"18,\"","value":"18,"},"filename":"/simple.k.yaml","line":2,"column":5,"end_line":0,"end_column":0},"operation":"Union"},"filename":"/simple.k.yaml","line":1,"column":4,"end_line":0,"end_column":0},{"node":{"key":{"node":{"type":"StringLit","is_long_string":false,"raw_value":"\"message\"","value":"message"},"filename":"/simple.k.yaml","line":3,"column":0,"end_line":0,"end_column":0},"value":{"node":{"type":"StringLit","is_long_string":false,"raw_value":"\"This is Alice\"","value":"This is Alice"},"filename":"/simple.k.yaml","line":3,"column":9,"end_line":0,"end_column":0},"operation":"Union"},"filename":"/simple.k.yaml","line":1,"column":4,"end_line":0,"end_column":0}]},"filename":"/simple.k.yaml","line":1,"column":4,"end_line":0,"end_column":0} diff --git a/kclvm/tools/src/vet/snapshots/kclvm_tools__vet__tests__test_expr_builder__build_with_yaml_no_schema_name-3.snap b/kclvm/tools/src/vet/snapshots/kclvm_tools__vet__tests__test_expr_builder__build_with_yaml_no_schema_name-3.snap new file mode 100644 index 000000000..0a462296b --- /dev/null +++ b/kclvm/tools/src/vet/snapshots/kclvm_tools__vet__tests__test_expr_builder__build_with_yaml_no_schema_name-3.snap @@ -0,0 +1,5 @@ +--- +source: tools/src/vet/tests.rs +expression: got_ast_yaml_str +--- +{"node":{"type":"NumberLit","binary_suffix":null,"value":{"type":"Int","value":1}},"filename":"/plain_value.k.yaml","line":1,"column":0,"end_line":0,"end_column":0} diff --git a/kclvm/tools/src/vet/snapshots/kclvm_tools__vet__tests__test_expr_builder__build_with_yaml_no_schema_name-4.snap b/kclvm/tools/src/vet/snapshots/kclvm_tools__vet__tests__test_expr_builder__build_with_yaml_no_schema_name-4.snap new file mode 100644 index 000000000..73de0030d --- /dev/null +++ b/kclvm/tools/src/vet/snapshots/kclvm_tools__vet__tests__test_expr_builder__build_with_yaml_no_schema_name-4.snap @@ -0,0 +1,5 @@ +--- +source: tools/src/vet/tests.rs +expression: got_ast_yaml_str +--- +{"node":{"type":"List","elts":[{"node":{"type":"Config","items":[{"node":{"key":{"node":{"type":"StringLit","is_long_string":false,"raw_value":"\"name\"","value":"name"},"filename":"/list.k.yaml","line":1,"column":2,"end_line":0,"end_column":0},"value":{"node":{"type":"StringLit","is_long_string":false,"raw_value":"\"Alice\"","value":"Alice"},"filename":"/list.k.yaml","line":1,"column":8,"end_line":0,"end_column":0},"operation":"Union"},"filename":"/list.k.yaml","line":1,"column":6,"end_line":0,"end_column":0},{"node":{"key":{"node":{"type":"StringLit","is_long_string":false,"raw_value":"\"age\"","value":"age"},"filename":"/list.k.yaml","line":2,"column":2,"end_line":0,"end_column":0},"value":{"node":{"type":"NumberLit","binary_suffix":null,"value":{"type":"Int","value":18}},"filename":"/list.k.yaml","line":2,"column":7,"end_line":0,"end_column":0},"operation":"Union"},"filename":"/list.k.yaml","line":1,"column":6,"end_line":0,"end_column":0},{"node":{"key":{"node":{"type":"StringLit","is_long_string":false,"raw_value":"\"message\"","value":"message"},"filename":"/list.k.yaml","line":3,"column":2,"end_line":0,"end_column":0},"value":{"node":{"type":"StringLit","is_long_string":false,"raw_value":"\"This is Alice\"","value":"This is Alice"},"filename":"/list.k.yaml","line":3,"column":11,"end_line":0,"end_column":0},"operation":"Union"},"filename":"/list.k.yaml","line":1,"column":6,"end_line":0,"end_column":0}]},"filename":"/list.k.yaml","line":1,"column":6,"end_line":0,"end_column":0}],"ctx":"Load"},"filename":"/list.k.yaml","line":1,"column":0,"end_line":0,"end_column":0} diff --git a/kclvm/tools/src/vet/snapshots/kclvm_tools__vet__tests__test_expr_builder__build_with_yaml_no_schema_name-5.snap b/kclvm/tools/src/vet/snapshots/kclvm_tools__vet__tests__test_expr_builder__build_with_yaml_no_schema_name-5.snap new file mode 100644 index 000000000..725b9bbad --- /dev/null +++ b/kclvm/tools/src/vet/snapshots/kclvm_tools__vet__tests__test_expr_builder__build_with_yaml_no_schema_name-5.snap @@ -0,0 +1,5 @@ +--- +source: tools/src/vet/tests.rs +expression: got_ast_yaml_str +--- +{"node":{"type":"Config","items":[{"node":{"key":{"node":{"type":"StringLit","is_long_string":false,"raw_value":"\"name\"","value":"name"},"filename":"/complex.k.yaml","line":1,"column":0,"end_line":0,"end_column":0},"value":{"node":{"type":"StringLit","is_long_string":false,"raw_value":"\"Alice\"","value":"Alice"},"filename":"/complex.k.yaml","line":1,"column":6,"end_line":0,"end_column":0},"operation":"Union"},"filename":"/complex.k.yaml","line":1,"column":4,"end_line":0,"end_column":0},{"node":{"key":{"node":{"type":"StringLit","is_long_string":false,"raw_value":"\"age\"","value":"age"},"filename":"/complex.k.yaml","line":2,"column":0,"end_line":0,"end_column":0},"value":{"node":{"type":"NumberLit","binary_suffix":null,"value":{"type":"Int","value":18}},"filename":"/complex.k.yaml","line":2,"column":5,"end_line":0,"end_column":0},"operation":"Union"},"filename":"/complex.k.yaml","line":1,"column":4,"end_line":0,"end_column":0},{"node":{"key":{"node":{"type":"StringLit","is_long_string":false,"raw_value":"\"message\"","value":"message"},"filename":"/complex.k.yaml","line":3,"column":0,"end_line":0,"end_column":0},"value":{"node":{"type":"StringLit","is_long_string":false,"raw_value":"\"This is Alice\"","value":"This is Alice"},"filename":"/complex.k.yaml","line":3,"column":9,"end_line":0,"end_column":0},"operation":"Union"},"filename":"/complex.k.yaml","line":1,"column":4,"end_line":0,"end_column":0},{"node":{"key":{"node":{"type":"StringLit","is_long_string":false,"raw_value":"\"data\"","value":"data"},"filename":"/complex.k.yaml","line":4,"column":0,"end_line":0,"end_column":0},"value":{"node":{"type":"Config","items":[{"node":{"key":{"node":{"type":"StringLit","is_long_string":false,"raw_value":"\"id\"","value":"id"},"filename":"/complex.k.yaml","line":5,"column":4,"end_line":0,"end_column":0},"value":{"node":{"type":"NumberLit","binary_suffix":null,"value":{"type":"Int","value":1}},"filename":"/complex.k.yaml","line":5,"column":8,"end_line":0,"end_column":0},"operation":"Union"},"filename":"/complex.k.yaml","line":5,"column":6,"end_line":0,"end_column":0},{"node":{"key":{"node":{"type":"StringLit","is_long_string":false,"raw_value":"\"value\"","value":"value"},"filename":"/complex.k.yaml","line":6,"column":4,"end_line":0,"end_column":0},"value":{"node":{"type":"StringLit","is_long_string":false,"raw_value":"\"value1\"","value":"value1"},"filename":"/complex.k.yaml","line":6,"column":11,"end_line":0,"end_column":0},"operation":"Union"},"filename":"/complex.k.yaml","line":5,"column":6,"end_line":0,"end_column":0}]},"filename":"/complex.k.yaml","line":5,"column":6,"end_line":0,"end_column":0},"operation":"Union"},"filename":"/complex.k.yaml","line":1,"column":4,"end_line":0,"end_column":0},{"node":{"key":{"node":{"type":"StringLit","is_long_string":false,"raw_value":"\"labels\"","value":"labels"},"filename":"/complex.k.yaml","line":7,"column":0,"end_line":0,"end_column":0},"value":{"node":{"type":"Config","items":[{"node":{"key":{"node":{"type":"StringLit","is_long_string":false,"raw_value":"\"key\"","value":"key"},"filename":"/complex.k.yaml","line":8,"column":4,"end_line":0,"end_column":0},"value":{"node":{"type":"StringLit","is_long_string":false,"raw_value":"\"value\"","value":"value"},"filename":"/complex.k.yaml","line":8,"column":9,"end_line":0,"end_column":0},"operation":"Union"},"filename":"/complex.k.yaml","line":8,"column":7,"end_line":0,"end_column":0}]},"filename":"/complex.k.yaml","line":8,"column":7,"end_line":0,"end_column":0},"operation":"Union"},"filename":"/complex.k.yaml","line":1,"column":4,"end_line":0,"end_column":0},{"node":{"key":{"node":{"type":"StringLit","is_long_string":false,"raw_value":"\"hc\"","value":"hc"},"filename":"/complex.k.yaml","line":9,"column":0,"end_line":0,"end_column":0},"value":{"node":{"type":"List","elts":[{"node":{"type":"NumberLit","binary_suffix":null,"value":{"type":"Int","value":1}},"filename":"/complex.k.yaml","line":10,"column":6,"end_line":0,"end_column":0},{"node":{"type":"NumberLit","binary_suffix":null,"value":{"type":"Int","value":2}},"filename":"/complex.k.yaml","line":11,"column":6,"end_line":0,"end_column":0},{"node":{"type":"NumberLit","binary_suffix":null,"value":{"type":"Int","value":3}},"filename":"/complex.k.yaml","line":12,"column":6,"end_line":0,"end_column":0}],"ctx":"Load"},"filename":"/complex.k.yaml","line":10,"column":4,"end_line":0,"end_column":0},"operation":"Union"},"filename":"/complex.k.yaml","line":1,"column":4,"end_line":0,"end_column":0}]},"filename":"/complex.k.yaml","line":1,"column":4,"end_line":0,"end_column":0} diff --git a/kclvm/tools/src/vet/snapshots/kclvm_tools__vet__tests__test_expr_builder__build_with_yaml_no_schema_name-6.snap b/kclvm/tools/src/vet/snapshots/kclvm_tools__vet__tests__test_expr_builder__build_with_yaml_no_schema_name-6.snap new file mode 100644 index 000000000..964bf7bea --- /dev/null +++ b/kclvm/tools/src/vet/snapshots/kclvm_tools__vet__tests__test_expr_builder__build_with_yaml_no_schema_name-6.snap @@ -0,0 +1,5 @@ +--- +source: tools/src/vet/tests.rs +expression: got_ast_yaml_str +--- +{"node":{"type":"Config","items":[{"node":{"key":{"node":{"type":"StringLit","is_long_string":false,"raw_value":"\"null_val\"","value":"null_val"},"filename":"/only_with_null.yaml","line":1,"column":0,"end_line":0,"end_column":0},"value":{"node":{"type":"NameConstantLit","value":"None"},"filename":"/only_with_null.yaml","line":1,"column":10,"end_line":0,"end_column":0},"operation":"Union"},"filename":"/only_with_null.yaml","line":1,"column":8,"end_line":0,"end_column":0}]},"filename":"/only_with_null.yaml","line":1,"column":8,"end_line":0,"end_column":0} diff --git a/kclvm/tools/src/vet/snapshots/kclvm_tools__vet__tests__test_expr_builder__build_with_yaml_no_schema_name-7.snap b/kclvm/tools/src/vet/snapshots/kclvm_tools__vet__tests__test_expr_builder__build_with_yaml_no_schema_name-7.snap new file mode 100644 index 000000000..fbfca6d63 --- /dev/null +++ b/kclvm/tools/src/vet/snapshots/kclvm_tools__vet__tests__test_expr_builder__build_with_yaml_no_schema_name-7.snap @@ -0,0 +1,5 @@ +--- +source: tools/src/vet/tests.rs +expression: got_ast_yaml_str +--- +{"node":{"type":"Config","items":[{"node":{"key":{"node":{"type":"StringLit","is_long_string":false,"raw_value":"\"bool_val\"","value":"bool_val"},"filename":"/only_with_bool.yaml","line":1,"column":0,"end_line":0,"end_column":0},"value":{"node":{"type":"NameConstantLit","value":"True"},"filename":"/only_with_bool.yaml","line":1,"column":10,"end_line":0,"end_column":0},"operation":"Union"},"filename":"/only_with_bool.yaml","line":1,"column":8,"end_line":0,"end_column":0}]},"filename":"/only_with_bool.yaml","line":1,"column":8,"end_line":0,"end_column":0} diff --git a/kclvm/tools/src/vet/snapshots/kclvm_tools__vet__tests__test_expr_builder__build_with_yaml_no_schema_name-8.snap b/kclvm/tools/src/vet/snapshots/kclvm_tools__vet__tests__test_expr_builder__build_with_yaml_no_schema_name-8.snap new file mode 100644 index 000000000..bddd79005 --- /dev/null +++ b/kclvm/tools/src/vet/snapshots/kclvm_tools__vet__tests__test_expr_builder__build_with_yaml_no_schema_name-8.snap @@ -0,0 +1,5 @@ +--- +source: tools/src/vet/tests.rs +expression: got_ast_yaml_str +--- +{"node":{"type":"Config","items":[{"node":{"key":{"node":{"type":"StringLit","is_long_string":false,"raw_value":"\"float_val\"","value":"float_val"},"filename":"/only_with_float.yaml","line":1,"column":0,"end_line":0,"end_column":0},"value":{"node":{"type":"NumberLit","binary_suffix":null,"value":{"type":"Float","value":0.33}},"filename":"/only_with_float.yaml","line":1,"column":11,"end_line":0,"end_column":0},"operation":"Union"},"filename":"/only_with_float.yaml","line":1,"column":9,"end_line":0,"end_column":0}]},"filename":"/only_with_float.yaml","line":1,"column":9,"end_line":0,"end_column":0} diff --git a/kclvm/tools/src/vet/snapshots/kclvm_tools__vet__tests__test_expr_builder__build_with_yaml_no_schema_name.snap b/kclvm/tools/src/vet/snapshots/kclvm_tools__vet__tests__test_expr_builder__build_with_yaml_no_schema_name.snap new file mode 100644 index 000000000..d457141bd --- /dev/null +++ b/kclvm/tools/src/vet/snapshots/kclvm_tools__vet__tests__test_expr_builder__build_with_yaml_no_schema_name.snap @@ -0,0 +1,5 @@ +--- +source: tools/src/vet/tests.rs +expression: got_ast_yaml_str +--- +{"node":{"type":"Config","items":[{"node":{"key":{"node":{"type":"StringLit","is_long_string":false,"raw_value":"\"languages\"","value":"languages"},"filename":"/test.k.yaml","line":1,"column":0,"end_line":0,"end_column":0},"value":{"node":{"type":"List","elts":[{"node":{"type":"StringLit","is_long_string":false,"raw_value":"\"Ruby\"","value":"Ruby"},"filename":"/test.k.yaml","line":2,"column":4,"end_line":0,"end_column":0},{"node":{"type":"StringLit","is_long_string":false,"raw_value":"\"Perl\"","value":"Perl"},"filename":"/test.k.yaml","line":3,"column":4,"end_line":0,"end_column":0},{"node":{"type":"StringLit","is_long_string":false,"raw_value":"\"Python\"","value":"Python"},"filename":"/test.k.yaml","line":4,"column":4,"end_line":0,"end_column":0}],"ctx":"Load"},"filename":"/test.k.yaml","line":2,"column":2,"end_line":0,"end_column":0},"operation":"Union"},"filename":"/test.k.yaml","line":1,"column":9,"end_line":0,"end_column":0},{"node":{"key":{"node":{"type":"StringLit","is_long_string":false,"raw_value":"\"websites\"","value":"websites"},"filename":"/test.k.yaml","line":5,"column":0,"end_line":0,"end_column":0},"value":{"node":{"type":"Config","items":[{"node":{"key":{"node":{"type":"StringLit","is_long_string":false,"raw_value":"\"YAML\"","value":"YAML"},"filename":"/test.k.yaml","line":6,"column":2,"end_line":0,"end_column":0},"value":{"node":{"type":"StringLit","is_long_string":false,"raw_value":"\"yaml.org\"","value":"yaml.org"},"filename":"/test.k.yaml","line":6,"column":8,"end_line":0,"end_column":0},"operation":"Union"},"filename":"/test.k.yaml","line":6,"column":6,"end_line":0,"end_column":0},{"node":{"key":{"node":{"type":"StringLit","is_long_string":false,"raw_value":"\"Ruby\"","value":"Ruby"},"filename":"/test.k.yaml","line":7,"column":2,"end_line":0,"end_column":0},"value":{"node":{"type":"StringLit","is_long_string":false,"raw_value":"\"ruby-lang.org\"","value":"ruby-lang.org"},"filename":"/test.k.yaml","line":7,"column":8,"end_line":0,"end_column":0},"operation":"Union"},"filename":"/test.k.yaml","line":6,"column":6,"end_line":0,"end_column":0},{"node":{"key":{"node":{"type":"StringLit","is_long_string":false,"raw_value":"\"Python\"","value":"Python"},"filename":"/test.k.yaml","line":8,"column":2,"end_line":0,"end_column":0},"value":{"node":{"type":"StringLit","is_long_string":false,"raw_value":"\"python.org\"","value":"python.org"},"filename":"/test.k.yaml","line":8,"column":10,"end_line":0,"end_column":0},"operation":"Union"},"filename":"/test.k.yaml","line":6,"column":6,"end_line":0,"end_column":0},{"node":{"key":{"node":{"type":"StringLit","is_long_string":false,"raw_value":"\"Perl\"","value":"Perl"},"filename":"/test.k.yaml","line":9,"column":2,"end_line":0,"end_column":0},"value":{"node":{"type":"StringLit","is_long_string":false,"raw_value":"\"use.perl.org\"","value":"use.perl.org"},"filename":"/test.k.yaml","line":9,"column":8,"end_line":0,"end_column":0},"operation":"Union"},"filename":"/test.k.yaml","line":6,"column":6,"end_line":0,"end_column":0}]},"filename":"/test.k.yaml","line":6,"column":6,"end_line":0,"end_column":0},"operation":"Union"},"filename":"/test.k.yaml","line":1,"column":9,"end_line":0,"end_column":0}]},"filename":"/test.k.yaml","line":1,"column":9,"end_line":0,"end_column":0} diff --git a/kclvm/tools/src/vet/snapshots/kclvm_tools__vet__tests__test_expr_builder__build_yaml-2.snap b/kclvm/tools/src/vet/snapshots/kclvm_tools__vet__tests__test_expr_builder__build_yaml-2.snap new file mode 100644 index 000000000..70c7813dc --- /dev/null +++ b/kclvm/tools/src/vet/snapshots/kclvm_tools__vet__tests__test_expr_builder__build_yaml-2.snap @@ -0,0 +1,5 @@ +--- +source: tools/src/vet/tests.rs +expression: got_ast_yaml_str +--- +{"node":{"type":"Schema","name":{"node":{"names":[{"node":"simple","filename":"/simple.k.yaml","line":1,"column":4,"end_line":0,"end_column":0}],"pkgpath":"","ctx":"Load"},"filename":"/simple.k.yaml","line":1,"column":4,"end_line":0,"end_column":0},"args":[],"kwargs":[],"config":{"node":{"type":"Config","items":[{"node":{"key":{"node":{"type":"StringLit","is_long_string":false,"raw_value":"\"name\"","value":"name"},"filename":"/simple.k.yaml","line":1,"column":0,"end_line":0,"end_column":0},"value":{"node":{"type":"StringLit","is_long_string":false,"raw_value":"\"Alice,\"","value":"Alice,"},"filename":"/simple.k.yaml","line":1,"column":6,"end_line":0,"end_column":0},"operation":"Union"},"filename":"/simple.k.yaml","line":1,"column":4,"end_line":0,"end_column":0},{"node":{"key":{"node":{"type":"StringLit","is_long_string":false,"raw_value":"\"age\"","value":"age"},"filename":"/simple.k.yaml","line":2,"column":0,"end_line":0,"end_column":0},"value":{"node":{"type":"StringLit","is_long_string":false,"raw_value":"\"18,\"","value":"18,"},"filename":"/simple.k.yaml","line":2,"column":5,"end_line":0,"end_column":0},"operation":"Union"},"filename":"/simple.k.yaml","line":1,"column":4,"end_line":0,"end_column":0},{"node":{"key":{"node":{"type":"StringLit","is_long_string":false,"raw_value":"\"message\"","value":"message"},"filename":"/simple.k.yaml","line":3,"column":0,"end_line":0,"end_column":0},"value":{"node":{"type":"StringLit","is_long_string":false,"raw_value":"\"This is Alice\"","value":"This is Alice"},"filename":"/simple.k.yaml","line":3,"column":9,"end_line":0,"end_column":0},"operation":"Union"},"filename":"/simple.k.yaml","line":1,"column":4,"end_line":0,"end_column":0}]},"filename":"/simple.k.yaml","line":1,"column":4,"end_line":0,"end_column":0}},"filename":"/simple.k.yaml","line":1,"column":4,"end_line":0,"end_column":0} diff --git a/kclvm/tools/src/vet/snapshots/kclvm_tools__vet__tests__test_expr_builder__build_yaml-3.snap b/kclvm/tools/src/vet/snapshots/kclvm_tools__vet__tests__test_expr_builder__build_yaml-3.snap new file mode 100644 index 000000000..0a462296b --- /dev/null +++ b/kclvm/tools/src/vet/snapshots/kclvm_tools__vet__tests__test_expr_builder__build_yaml-3.snap @@ -0,0 +1,5 @@ +--- +source: tools/src/vet/tests.rs +expression: got_ast_yaml_str +--- +{"node":{"type":"NumberLit","binary_suffix":null,"value":{"type":"Int","value":1}},"filename":"/plain_value.k.yaml","line":1,"column":0,"end_line":0,"end_column":0} diff --git a/kclvm/tools/src/vet/snapshots/kclvm_tools__vet__tests__test_expr_builder__build_yaml-4.snap b/kclvm/tools/src/vet/snapshots/kclvm_tools__vet__tests__test_expr_builder__build_yaml-4.snap new file mode 100644 index 000000000..542d11746 --- /dev/null +++ b/kclvm/tools/src/vet/snapshots/kclvm_tools__vet__tests__test_expr_builder__build_yaml-4.snap @@ -0,0 +1,5 @@ +--- +source: tools/src/vet/tests.rs +expression: got_ast_yaml_str +--- +{"node":{"type":"List","elts":[{"node":{"type":"Schema","name":{"node":{"names":[{"node":"list","filename":"/list.k.yaml","line":1,"column":6,"end_line":0,"end_column":0}],"pkgpath":"","ctx":"Load"},"filename":"/list.k.yaml","line":1,"column":6,"end_line":0,"end_column":0},"args":[],"kwargs":[],"config":{"node":{"type":"Config","items":[{"node":{"key":{"node":{"type":"StringLit","is_long_string":false,"raw_value":"\"name\"","value":"name"},"filename":"/list.k.yaml","line":1,"column":2,"end_line":0,"end_column":0},"value":{"node":{"type":"StringLit","is_long_string":false,"raw_value":"\"Alice\"","value":"Alice"},"filename":"/list.k.yaml","line":1,"column":8,"end_line":0,"end_column":0},"operation":"Union"},"filename":"/list.k.yaml","line":1,"column":6,"end_line":0,"end_column":0},{"node":{"key":{"node":{"type":"StringLit","is_long_string":false,"raw_value":"\"age\"","value":"age"},"filename":"/list.k.yaml","line":2,"column":2,"end_line":0,"end_column":0},"value":{"node":{"type":"NumberLit","binary_suffix":null,"value":{"type":"Int","value":18}},"filename":"/list.k.yaml","line":2,"column":7,"end_line":0,"end_column":0},"operation":"Union"},"filename":"/list.k.yaml","line":1,"column":6,"end_line":0,"end_column":0},{"node":{"key":{"node":{"type":"StringLit","is_long_string":false,"raw_value":"\"message\"","value":"message"},"filename":"/list.k.yaml","line":3,"column":2,"end_line":0,"end_column":0},"value":{"node":{"type":"StringLit","is_long_string":false,"raw_value":"\"This is Alice\"","value":"This is Alice"},"filename":"/list.k.yaml","line":3,"column":11,"end_line":0,"end_column":0},"operation":"Union"},"filename":"/list.k.yaml","line":1,"column":6,"end_line":0,"end_column":0}]},"filename":"/list.k.yaml","line":1,"column":6,"end_line":0,"end_column":0}},"filename":"/list.k.yaml","line":1,"column":6,"end_line":0,"end_column":0}],"ctx":"Load"},"filename":"/list.k.yaml","line":1,"column":0,"end_line":0,"end_column":0} diff --git a/kclvm/tools/src/vet/snapshots/kclvm_tools__vet__tests__test_expr_builder__build_yaml-5.snap b/kclvm/tools/src/vet/snapshots/kclvm_tools__vet__tests__test_expr_builder__build_yaml-5.snap new file mode 100644 index 000000000..b870affed --- /dev/null +++ b/kclvm/tools/src/vet/snapshots/kclvm_tools__vet__tests__test_expr_builder__build_yaml-5.snap @@ -0,0 +1,5 @@ +--- +source: tools/src/vet/tests.rs +expression: got_ast_yaml_str +--- +{"node":{"type":"Schema","name":{"node":{"names":[{"node":"complex","filename":"/complex.k.yaml","line":1,"column":4,"end_line":0,"end_column":0}],"pkgpath":"","ctx":"Load"},"filename":"/complex.k.yaml","line":1,"column":4,"end_line":0,"end_column":0},"args":[],"kwargs":[],"config":{"node":{"type":"Config","items":[{"node":{"key":{"node":{"type":"StringLit","is_long_string":false,"raw_value":"\"name\"","value":"name"},"filename":"/complex.k.yaml","line":1,"column":0,"end_line":0,"end_column":0},"value":{"node":{"type":"StringLit","is_long_string":false,"raw_value":"\"Alice\"","value":"Alice"},"filename":"/complex.k.yaml","line":1,"column":6,"end_line":0,"end_column":0},"operation":"Union"},"filename":"/complex.k.yaml","line":1,"column":4,"end_line":0,"end_column":0},{"node":{"key":{"node":{"type":"StringLit","is_long_string":false,"raw_value":"\"age\"","value":"age"},"filename":"/complex.k.yaml","line":2,"column":0,"end_line":0,"end_column":0},"value":{"node":{"type":"NumberLit","binary_suffix":null,"value":{"type":"Int","value":18}},"filename":"/complex.k.yaml","line":2,"column":5,"end_line":0,"end_column":0},"operation":"Union"},"filename":"/complex.k.yaml","line":1,"column":4,"end_line":0,"end_column":0},{"node":{"key":{"node":{"type":"StringLit","is_long_string":false,"raw_value":"\"message\"","value":"message"},"filename":"/complex.k.yaml","line":3,"column":0,"end_line":0,"end_column":0},"value":{"node":{"type":"StringLit","is_long_string":false,"raw_value":"\"This is Alice\"","value":"This is Alice"},"filename":"/complex.k.yaml","line":3,"column":9,"end_line":0,"end_column":0},"operation":"Union"},"filename":"/complex.k.yaml","line":1,"column":4,"end_line":0,"end_column":0},{"node":{"key":{"node":{"type":"StringLit","is_long_string":false,"raw_value":"\"data\"","value":"data"},"filename":"/complex.k.yaml","line":4,"column":0,"end_line":0,"end_column":0},"value":{"node":{"type":"Config","items":[{"node":{"key":{"node":{"type":"StringLit","is_long_string":false,"raw_value":"\"id\"","value":"id"},"filename":"/complex.k.yaml","line":5,"column":4,"end_line":0,"end_column":0},"value":{"node":{"type":"NumberLit","binary_suffix":null,"value":{"type":"Int","value":1}},"filename":"/complex.k.yaml","line":5,"column":8,"end_line":0,"end_column":0},"operation":"Union"},"filename":"/complex.k.yaml","line":5,"column":6,"end_line":0,"end_column":0},{"node":{"key":{"node":{"type":"StringLit","is_long_string":false,"raw_value":"\"value\"","value":"value"},"filename":"/complex.k.yaml","line":6,"column":4,"end_line":0,"end_column":0},"value":{"node":{"type":"StringLit","is_long_string":false,"raw_value":"\"value1\"","value":"value1"},"filename":"/complex.k.yaml","line":6,"column":11,"end_line":0,"end_column":0},"operation":"Union"},"filename":"/complex.k.yaml","line":5,"column":6,"end_line":0,"end_column":0}]},"filename":"/complex.k.yaml","line":5,"column":6,"end_line":0,"end_column":0},"operation":"Union"},"filename":"/complex.k.yaml","line":1,"column":4,"end_line":0,"end_column":0},{"node":{"key":{"node":{"type":"StringLit","is_long_string":false,"raw_value":"\"labels\"","value":"labels"},"filename":"/complex.k.yaml","line":7,"column":0,"end_line":0,"end_column":0},"value":{"node":{"type":"Config","items":[{"node":{"key":{"node":{"type":"StringLit","is_long_string":false,"raw_value":"\"key\"","value":"key"},"filename":"/complex.k.yaml","line":8,"column":4,"end_line":0,"end_column":0},"value":{"node":{"type":"StringLit","is_long_string":false,"raw_value":"\"value\"","value":"value"},"filename":"/complex.k.yaml","line":8,"column":9,"end_line":0,"end_column":0},"operation":"Union"},"filename":"/complex.k.yaml","line":8,"column":7,"end_line":0,"end_column":0}]},"filename":"/complex.k.yaml","line":8,"column":7,"end_line":0,"end_column":0},"operation":"Union"},"filename":"/complex.k.yaml","line":1,"column":4,"end_line":0,"end_column":0},{"node":{"key":{"node":{"type":"StringLit","is_long_string":false,"raw_value":"\"hc\"","value":"hc"},"filename":"/complex.k.yaml","line":9,"column":0,"end_line":0,"end_column":0},"value":{"node":{"type":"List","elts":[{"node":{"type":"NumberLit","binary_suffix":null,"value":{"type":"Int","value":1}},"filename":"/complex.k.yaml","line":10,"column":6,"end_line":0,"end_column":0},{"node":{"type":"NumberLit","binary_suffix":null,"value":{"type":"Int","value":2}},"filename":"/complex.k.yaml","line":11,"column":6,"end_line":0,"end_column":0},{"node":{"type":"NumberLit","binary_suffix":null,"value":{"type":"Int","value":3}},"filename":"/complex.k.yaml","line":12,"column":6,"end_line":0,"end_column":0}],"ctx":"Load"},"filename":"/complex.k.yaml","line":10,"column":4,"end_line":0,"end_column":0},"operation":"Union"},"filename":"/complex.k.yaml","line":1,"column":4,"end_line":0,"end_column":0}]},"filename":"/complex.k.yaml","line":1,"column":4,"end_line":0,"end_column":0}},"filename":"/complex.k.yaml","line":1,"column":4,"end_line":0,"end_column":0} diff --git a/kclvm/tools/src/vet/snapshots/kclvm_tools__vet__tests__test_expr_builder__build_yaml-6.snap b/kclvm/tools/src/vet/snapshots/kclvm_tools__vet__tests__test_expr_builder__build_yaml-6.snap new file mode 100644 index 000000000..06cc63172 --- /dev/null +++ b/kclvm/tools/src/vet/snapshots/kclvm_tools__vet__tests__test_expr_builder__build_yaml-6.snap @@ -0,0 +1,5 @@ +--- +source: tools/src/vet/tests.rs +expression: got_ast_yaml_str +--- +{"node":{"type":"Schema","name":{"node":{"names":[{"node":"only_with_null","filename":"/only_with_null.yaml","line":1,"column":8,"end_line":0,"end_column":0}],"pkgpath":"","ctx":"Load"},"filename":"/only_with_null.yaml","line":1,"column":8,"end_line":0,"end_column":0},"args":[],"kwargs":[],"config":{"node":{"type":"Config","items":[{"node":{"key":{"node":{"type":"StringLit","is_long_string":false,"raw_value":"\"null_val\"","value":"null_val"},"filename":"/only_with_null.yaml","line":1,"column":0,"end_line":0,"end_column":0},"value":{"node":{"type":"NameConstantLit","value":"None"},"filename":"/only_with_null.yaml","line":1,"column":10,"end_line":0,"end_column":0},"operation":"Union"},"filename":"/only_with_null.yaml","line":1,"column":8,"end_line":0,"end_column":0}]},"filename":"/only_with_null.yaml","line":1,"column":8,"end_line":0,"end_column":0}},"filename":"/only_with_null.yaml","line":1,"column":8,"end_line":0,"end_column":0} diff --git a/kclvm/tools/src/vet/snapshots/kclvm_tools__vet__tests__test_expr_builder__build_yaml-7.snap b/kclvm/tools/src/vet/snapshots/kclvm_tools__vet__tests__test_expr_builder__build_yaml-7.snap new file mode 100644 index 000000000..79ad51025 --- /dev/null +++ b/kclvm/tools/src/vet/snapshots/kclvm_tools__vet__tests__test_expr_builder__build_yaml-7.snap @@ -0,0 +1,5 @@ +--- +source: tools/src/vet/tests.rs +expression: got_ast_yaml_str +--- +{"node":{"type":"Schema","name":{"node":{"names":[{"node":"only_with_bool","filename":"/only_with_bool.yaml","line":1,"column":8,"end_line":0,"end_column":0}],"pkgpath":"","ctx":"Load"},"filename":"/only_with_bool.yaml","line":1,"column":8,"end_line":0,"end_column":0},"args":[],"kwargs":[],"config":{"node":{"type":"Config","items":[{"node":{"key":{"node":{"type":"StringLit","is_long_string":false,"raw_value":"\"bool_val\"","value":"bool_val"},"filename":"/only_with_bool.yaml","line":1,"column":0,"end_line":0,"end_column":0},"value":{"node":{"type":"NameConstantLit","value":"True"},"filename":"/only_with_bool.yaml","line":1,"column":10,"end_line":0,"end_column":0},"operation":"Union"},"filename":"/only_with_bool.yaml","line":1,"column":8,"end_line":0,"end_column":0}]},"filename":"/only_with_bool.yaml","line":1,"column":8,"end_line":0,"end_column":0}},"filename":"/only_with_bool.yaml","line":1,"column":8,"end_line":0,"end_column":0} diff --git a/kclvm/tools/src/vet/snapshots/kclvm_tools__vet__tests__test_expr_builder__build_yaml-8.snap b/kclvm/tools/src/vet/snapshots/kclvm_tools__vet__tests__test_expr_builder__build_yaml-8.snap new file mode 100644 index 000000000..c99e38db8 --- /dev/null +++ b/kclvm/tools/src/vet/snapshots/kclvm_tools__vet__tests__test_expr_builder__build_yaml-8.snap @@ -0,0 +1,5 @@ +--- +source: tools/src/vet/tests.rs +expression: got_ast_yaml_str +--- +{"node":{"type":"Schema","name":{"node":{"names":[{"node":"only_with_float","filename":"/only_with_float.yaml","line":1,"column":9,"end_line":0,"end_column":0}],"pkgpath":"","ctx":"Load"},"filename":"/only_with_float.yaml","line":1,"column":9,"end_line":0,"end_column":0},"args":[],"kwargs":[],"config":{"node":{"type":"Config","items":[{"node":{"key":{"node":{"type":"StringLit","is_long_string":false,"raw_value":"\"float_val\"","value":"float_val"},"filename":"/only_with_float.yaml","line":1,"column":0,"end_line":0,"end_column":0},"value":{"node":{"type":"NumberLit","binary_suffix":null,"value":{"type":"Float","value":0.33}},"filename":"/only_with_float.yaml","line":1,"column":11,"end_line":0,"end_column":0},"operation":"Union"},"filename":"/only_with_float.yaml","line":1,"column":9,"end_line":0,"end_column":0}]},"filename":"/only_with_float.yaml","line":1,"column":9,"end_line":0,"end_column":0}},"filename":"/only_with_float.yaml","line":1,"column":9,"end_line":0,"end_column":0} diff --git a/kclvm/tools/src/vet/snapshots/kclvm_tools__vet__tests__test_expr_builder__build_yaml.snap b/kclvm/tools/src/vet/snapshots/kclvm_tools__vet__tests__test_expr_builder__build_yaml.snap new file mode 100644 index 000000000..4e062d1df --- /dev/null +++ b/kclvm/tools/src/vet/snapshots/kclvm_tools__vet__tests__test_expr_builder__build_yaml.snap @@ -0,0 +1,5 @@ +--- +source: tools/src/vet/tests.rs +expression: got_ast_yaml_str +--- +{"node":{"type":"Schema","name":{"node":{"names":[{"node":"test","filename":"/test.k.yaml","line":1,"column":9,"end_line":0,"end_column":0}],"pkgpath":"","ctx":"Load"},"filename":"/test.k.yaml","line":1,"column":9,"end_line":0,"end_column":0},"args":[],"kwargs":[],"config":{"node":{"type":"Config","items":[{"node":{"key":{"node":{"type":"StringLit","is_long_string":false,"raw_value":"\"languages\"","value":"languages"},"filename":"/test.k.yaml","line":1,"column":0,"end_line":0,"end_column":0},"value":{"node":{"type":"List","elts":[{"node":{"type":"StringLit","is_long_string":false,"raw_value":"\"Ruby\"","value":"Ruby"},"filename":"/test.k.yaml","line":2,"column":4,"end_line":0,"end_column":0},{"node":{"type":"StringLit","is_long_string":false,"raw_value":"\"Perl\"","value":"Perl"},"filename":"/test.k.yaml","line":3,"column":4,"end_line":0,"end_column":0},{"node":{"type":"StringLit","is_long_string":false,"raw_value":"\"Python\"","value":"Python"},"filename":"/test.k.yaml","line":4,"column":4,"end_line":0,"end_column":0}],"ctx":"Load"},"filename":"/test.k.yaml","line":2,"column":2,"end_line":0,"end_column":0},"operation":"Union"},"filename":"/test.k.yaml","line":1,"column":9,"end_line":0,"end_column":0},{"node":{"key":{"node":{"type":"StringLit","is_long_string":false,"raw_value":"\"websites\"","value":"websites"},"filename":"/test.k.yaml","line":5,"column":0,"end_line":0,"end_column":0},"value":{"node":{"type":"Config","items":[{"node":{"key":{"node":{"type":"StringLit","is_long_string":false,"raw_value":"\"YAML\"","value":"YAML"},"filename":"/test.k.yaml","line":6,"column":2,"end_line":0,"end_column":0},"value":{"node":{"type":"StringLit","is_long_string":false,"raw_value":"\"yaml.org\"","value":"yaml.org"},"filename":"/test.k.yaml","line":6,"column":8,"end_line":0,"end_column":0},"operation":"Union"},"filename":"/test.k.yaml","line":6,"column":6,"end_line":0,"end_column":0},{"node":{"key":{"node":{"type":"StringLit","is_long_string":false,"raw_value":"\"Ruby\"","value":"Ruby"},"filename":"/test.k.yaml","line":7,"column":2,"end_line":0,"end_column":0},"value":{"node":{"type":"StringLit","is_long_string":false,"raw_value":"\"ruby-lang.org\"","value":"ruby-lang.org"},"filename":"/test.k.yaml","line":7,"column":8,"end_line":0,"end_column":0},"operation":"Union"},"filename":"/test.k.yaml","line":6,"column":6,"end_line":0,"end_column":0},{"node":{"key":{"node":{"type":"StringLit","is_long_string":false,"raw_value":"\"Python\"","value":"Python"},"filename":"/test.k.yaml","line":8,"column":2,"end_line":0,"end_column":0},"value":{"node":{"type":"StringLit","is_long_string":false,"raw_value":"\"python.org\"","value":"python.org"},"filename":"/test.k.yaml","line":8,"column":10,"end_line":0,"end_column":0},"operation":"Union"},"filename":"/test.k.yaml","line":6,"column":6,"end_line":0,"end_column":0},{"node":{"key":{"node":{"type":"StringLit","is_long_string":false,"raw_value":"\"Perl\"","value":"Perl"},"filename":"/test.k.yaml","line":9,"column":2,"end_line":0,"end_column":0},"value":{"node":{"type":"StringLit","is_long_string":false,"raw_value":"\"use.perl.org\"","value":"use.perl.org"},"filename":"/test.k.yaml","line":9,"column":8,"end_line":0,"end_column":0},"operation":"Union"},"filename":"/test.k.yaml","line":6,"column":6,"end_line":0,"end_column":0}]},"filename":"/test.k.yaml","line":6,"column":6,"end_line":0,"end_column":0},"operation":"Union"},"filename":"/test.k.yaml","line":1,"column":9,"end_line":0,"end_column":0}]},"filename":"/test.k.yaml","line":1,"column":9,"end_line":0,"end_column":0}},"filename":"/test.k.yaml","line":1,"column":9,"end_line":0,"end_column":0} diff --git a/kclvm/tools/src/vet/test_datas/invalid/test_invalid.json b/kclvm/tools/src/vet/test_datas/invalid/test_invalid.json new file mode 100644 index 000000000..070921a8e --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/invalid/test_invalid.json @@ -0,0 +1,2 @@ +languages: + - Ruby diff --git a/kclvm/tools/src/vet/test_datas/invalid/test_invalid.yaml b/kclvm/tools/src/vet/test_datas/invalid/test_invalid.yaml new file mode 100644 index 000000000..b133b3df2 --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/invalid/test_invalid.yaml @@ -0,0 +1,5 @@ +{ + "name": "John Doe", + "city": "London" +invalid + diff --git a/kclvm/tools/src/vet/test_datas/invalid/unsupported/json_with_u64.ast.json b/kclvm/tools/src/vet/test_datas/invalid/unsupported/json_with_u64.ast.json new file mode 100644 index 000000000..dcfd32f1e --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/invalid/unsupported/json_with_u64.ast.json @@ -0,0 +1,3 @@ +{ + "u64_value": 9223372036854775808 +} diff --git a/kclvm/tools/src/vet/test_datas/invalid/unsupported/json_with_u64.json b/kclvm/tools/src/vet/test_datas/invalid/unsupported/json_with_u64.json new file mode 100644 index 000000000..dcfd32f1e --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/invalid/unsupported/json_with_u64.json @@ -0,0 +1,3 @@ +{ + "u64_value": 9223372036854775808 +} diff --git a/kclvm/tools/src/vet/test_datas/invalid/unsupported/yaml_with_u64.ast.yaml b/kclvm/tools/src/vet/test_datas/invalid/unsupported/yaml_with_u64.ast.yaml new file mode 100644 index 000000000..dcfd32f1e --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/invalid/unsupported/yaml_with_u64.ast.yaml @@ -0,0 +1,3 @@ +{ + "u64_value": 9223372036854775808 +} diff --git a/kclvm/tools/src/vet/test_datas/invalid/unsupported/yaml_with_u64.yaml b/kclvm/tools/src/vet/test_datas/invalid/unsupported/yaml_with_u64.yaml new file mode 100644 index 000000000..dcfd32f1e --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/invalid/unsupported/yaml_with_u64.yaml @@ -0,0 +1,3 @@ +{ + "u64_value": 9223372036854775808 +} diff --git a/test/test_units/test_kclvm/test_tools/test_validation/json_test_data/complex.k b/kclvm/tools/src/vet/test_datas/invalid_validate_cases/complex.k similarity index 100% rename from test/test_units/test_kclvm/test_tools/test_validation/json_test_data/complex.k rename to kclvm/tools/src/vet/test_datas/invalid_validate_cases/complex.k diff --git a/kclvm/tools/src/vet/test_datas/invalid_validate_cases/complex.k.json b/kclvm/tools/src/vet/test_datas/invalid_validate_cases/complex.k.json new file mode 100644 index 000000000..00890e982 --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/invalid_validate_cases/complex.k.json @@ -0,0 +1,10 @@ +{ + "name": "Alice", + "age": 18, + "message": "This is Alice", + "data": 10, + "labels": { + "key": "value" + }, + "hc": [1, 2, 3] +} diff --git a/kclvm/tools/src/vet/test_datas/invalid_validate_cases/complex.k.stderr.json b/kclvm/tools/src/vet/test_datas/invalid_validate_cases/complex.k.stderr.json new file mode 100644 index 000000000..9bfb4e464 --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/invalid_validate_cases/complex.k.stderr.json @@ -0,0 +1,18 @@ +{ + "__kcl_PanicInfo__": true, + "rust_file": "", + "rust_line": 0, + "rust_col": 0, + "kcl_pkgpath": "", + "kcl_file": "", + "kcl_line": 1, + "kcl_col": 1, + "kcl_arg_msg": "", + "kcl_config_meta_file": "", + "kcl_config_meta_line": 0, + "kcl_config_meta_col": 0, + "kcl_config_meta_arg_msg": "", + "message": "expect Data, got int(10)", + "err_type_code": 5, + "is_warning": false +} \ No newline at end of file diff --git a/kclvm/tools/src/vet/test_datas/invalid_validate_cases/complex.k.yaml b/kclvm/tools/src/vet/test_datas/invalid_validate_cases/complex.k.yaml new file mode 100644 index 000000000..17dbf2761 --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/invalid_validate_cases/complex.k.yaml @@ -0,0 +1,10 @@ +name: Alice +age: 18 +message: This is Alice +data: 10 +labels: + key: value +hc: + - 1 + - 2 + - 3 diff --git a/test/test_units/test_kclvm/test_tools/test_validation/json_test_data/list.k b/kclvm/tools/src/vet/test_datas/invalid_validate_cases/list.k similarity index 100% rename from test/test_units/test_kclvm/test_tools/test_validation/json_test_data/list.k rename to kclvm/tools/src/vet/test_datas/invalid_validate_cases/list.k diff --git a/kclvm/tools/src/vet/test_datas/invalid_validate_cases/list.k.json b/kclvm/tools/src/vet/test_datas/invalid_validate_cases/list.k.json new file mode 100644 index 000000000..4e4da006d --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/invalid_validate_cases/list.k.json @@ -0,0 +1,7 @@ +[ + { + "name": 10, + "age": 18, + "message": "This is Alice" + } +] diff --git a/kclvm/tools/src/vet/test_datas/invalid_validate_cases/list.k.stderr.json b/kclvm/tools/src/vet/test_datas/invalid_validate_cases/list.k.stderr.json new file mode 100644 index 000000000..9030cae6c --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/invalid_validate_cases/list.k.stderr.json @@ -0,0 +1,18 @@ +{ + "__kcl_PanicInfo__": true, + "rust_file": "", + "rust_line": 0, + "rust_col": 0, + "kcl_pkgpath": "", + "kcl_file": "", + "kcl_line": 1, + "kcl_col": 1, + "kcl_arg_msg": "", + "kcl_config_meta_file": "", + "kcl_config_meta_line": 0, + "kcl_config_meta_col": 0, + "kcl_config_meta_arg_msg": "", + "message": "expect str, got int(10)", + "err_type_code": 5, + "is_warning": false +} \ No newline at end of file diff --git a/kclvm/tools/src/vet/test_datas/invalid_validate_cases/list.k.yaml b/kclvm/tools/src/vet/test_datas/invalid_validate_cases/list.k.yaml new file mode 100644 index 000000000..2a038e8b5 --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/invalid_validate_cases/list.k.yaml @@ -0,0 +1,4 @@ +- name: 10 + age: 18 + message: This is Alice + \ No newline at end of file diff --git a/test/test_units/test_kclvm/test_tools/test_validation/json_test_data/plain_value.k b/kclvm/tools/src/vet/test_datas/invalid_validate_cases/plain_value.k similarity index 100% rename from test/test_units/test_kclvm/test_tools/test_validation/json_test_data/plain_value.k rename to kclvm/tools/src/vet/test_datas/invalid_validate_cases/plain_value.k diff --git a/kclvm/tools/src/vet/test_datas/invalid_validate_cases/plain_value.k.json b/kclvm/tools/src/vet/test_datas/invalid_validate_cases/plain_value.k.json new file mode 100644 index 000000000..573541ac9 --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/invalid_validate_cases/plain_value.k.json @@ -0,0 +1 @@ +0 diff --git a/kclvm/tools/src/vet/test_datas/invalid_validate_cases/plain_value.k.stderr.json b/kclvm/tools/src/vet/test_datas/invalid_validate_cases/plain_value.k.stderr.json new file mode 100644 index 000000000..b1e3dd64c --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/invalid_validate_cases/plain_value.k.stderr.json @@ -0,0 +1,18 @@ +{ + "__kcl_PanicInfo__": true, + "rust_file": "runtime/src/stdlib/assert_api.rs", + "rust_line": 19, + "rust_col": 9, + "kcl_pkgpath": "", + "kcl_file": "validationTempKCLCode.k", + "kcl_line": 2, + "kcl_col": 0, + "kcl_arg_msg": "", + "kcl_config_meta_file": "", + "kcl_config_meta_line": 0, + "kcl_config_meta_col": 0, + "kcl_config_meta_arg_msg": "", + "message": "", + "err_type_code": 29, + "is_warning": false +} \ No newline at end of file diff --git a/kclvm/tools/src/vet/test_datas/invalid_validate_cases/plain_value.k.yaml b/kclvm/tools/src/vet/test_datas/invalid_validate_cases/plain_value.k.yaml new file mode 100644 index 000000000..573541ac9 --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/invalid_validate_cases/plain_value.k.yaml @@ -0,0 +1 @@ +0 diff --git a/test/test_units/test_kclvm/test_tools/test_validation/json_test_data/simple.k b/kclvm/tools/src/vet/test_datas/invalid_validate_cases/simple.k similarity index 100% rename from test/test_units/test_kclvm/test_tools/test_validation/json_test_data/simple.k rename to kclvm/tools/src/vet/test_datas/invalid_validate_cases/simple.k diff --git a/kclvm/tools/src/vet/test_datas/invalid_validate_cases/simple.k.json b/kclvm/tools/src/vet/test_datas/invalid_validate_cases/simple.k.json new file mode 100644 index 000000000..558a22e13 --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/invalid_validate_cases/simple.k.json @@ -0,0 +1,5 @@ +{ + "name": 10, + "age": 18, + "message": "This is Alice" +} diff --git a/kclvm/tools/src/vet/test_datas/invalid_validate_cases/simple.k.stderr.json b/kclvm/tools/src/vet/test_datas/invalid_validate_cases/simple.k.stderr.json new file mode 100644 index 000000000..9030cae6c --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/invalid_validate_cases/simple.k.stderr.json @@ -0,0 +1,18 @@ +{ + "__kcl_PanicInfo__": true, + "rust_file": "", + "rust_line": 0, + "rust_col": 0, + "kcl_pkgpath": "", + "kcl_file": "", + "kcl_line": 1, + "kcl_col": 1, + "kcl_arg_msg": "", + "kcl_config_meta_file": "", + "kcl_config_meta_line": 0, + "kcl_config_meta_col": 0, + "kcl_config_meta_arg_msg": "", + "message": "expect str, got int(10)", + "err_type_code": 5, + "is_warning": false +} \ No newline at end of file diff --git a/kclvm/tools/src/vet/test_datas/invalid_validate_cases/simple.k.yaml b/kclvm/tools/src/vet/test_datas/invalid_validate_cases/simple.k.yaml new file mode 100644 index 000000000..0acfbba39 --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/invalid_validate_cases/simple.k.yaml @@ -0,0 +1,3 @@ +name: 10 +age: 18 +message: This is Alice diff --git a/test/test_units/test_kclvm/test_tools/test_validation/json_test_data/schema_with_check.k b/kclvm/tools/src/vet/test_datas/invalid_validate_cases/test.k similarity index 100% rename from test/test_units/test_kclvm/test_tools/test_validation/json_test_data/schema_with_check.k rename to kclvm/tools/src/vet/test_datas/invalid_validate_cases/test.k diff --git a/kclvm/tools/src/vet/test_datas/invalid_validate_cases/test.k.json b/kclvm/tools/src/vet/test_datas/invalid_validate_cases/test.k.json new file mode 100644 index 000000000..8b12f2738 --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/invalid_validate_cases/test.k.json @@ -0,0 +1,5 @@ +{ + "name": "Tom", + "age": 18, + "message": "This is Alice" +} diff --git a/kclvm/tools/src/vet/test_datas/invalid_validate_cases/test.k.stderr.json b/kclvm/tools/src/vet/test_datas/invalid_validate_cases/test.k.stderr.json new file mode 100644 index 000000000..eedceca94 --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/invalid_validate_cases/test.k.stderr.json @@ -0,0 +1,18 @@ +{ + "__kcl_PanicInfo__": true, + "rust_file": "runtime/src/value/api.rs", + "rust_line": 2204, + "rust_col": 9, + "kcl_pkgpath": "__main__", + "kcl_file": "validationTempKCLCode.k", + "kcl_line": 7, + "kcl_col": 0, + "kcl_arg_msg": "Check failed on the condition", + "kcl_config_meta_file": "", + "kcl_config_meta_line": 1, + "kcl_config_meta_col": 1, + "kcl_config_meta_arg_msg": "Instance check failed", + "message": "", + "err_type_code": 17, + "is_warning": false +} \ No newline at end of file diff --git a/kclvm/tools/src/vet/test_datas/invalid_validate_cases/test.k.yaml b/kclvm/tools/src/vet/test_datas/invalid_validate_cases/test.k.yaml new file mode 100644 index 000000000..26beecf48 --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/invalid_validate_cases/test.k.yaml @@ -0,0 +1,3 @@ +name: Tom +age: 18 +message: This is Alice diff --git a/kclvm/tools/src/vet/test_datas/invalid_vet_cases_json/complex.k b/kclvm/tools/src/vet/test_datas/invalid_vet_cases_json/complex.k new file mode 100644 index 000000000..09c880103 --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/invalid_vet_cases_json/complex.k @@ -0,0 +1,11 @@ +schema User: + name: str + age: int + message?: str + data: Data + labels: {str:} + hc: [int] + +schema Data: + id: int + value: str diff --git a/kclvm/tools/src/vet/test_datas/invalid_vet_cases_json/complex.k.json b/kclvm/tools/src/vet/test_datas/invalid_vet_cases_json/complex.k.json new file mode 100644 index 000000000..00890e982 --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/invalid_vet_cases_json/complex.k.json @@ -0,0 +1,10 @@ +{ + "name": "Alice", + "age": 18, + "message": "This is Alice", + "data": 10, + "labels": { + "key": "value" + }, + "hc": [1, 2, 3] +} diff --git a/kclvm/tools/src/vet/test_datas/invalid_vet_cases_json/dep/kcl.mod b/kclvm/tools/src/vet/test_datas/invalid_vet_cases_json/dep/kcl.mod new file mode 100644 index 000000000..ad4478c32 --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/invalid_vet_cases_json/dep/kcl.mod @@ -0,0 +1,5 @@ +[package] +name = "dep" +edition = "v0.8.0" +version = "0.0.1" + diff --git a/kclvm/tools/src/vet/test_datas/invalid_vet_cases_json/dep/main.k b/kclvm/tools/src/vet/test_datas/invalid_vet_cases_json/dep/main.k new file mode 100644 index 000000000..eae94c15d --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/invalid_vet_cases_json/dep/main.k @@ -0,0 +1,2 @@ +schema A : + name: str \ No newline at end of file diff --git a/kclvm/tools/src/vet/test_datas/invalid_vet_cases_json/list.k b/kclvm/tools/src/vet/test_datas/invalid_vet_cases_json/list.k new file mode 100644 index 000000000..ef6d67aed --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/invalid_vet_cases_json/list.k @@ -0,0 +1,9 @@ +schema User: + name: str + age: int + message?: str + +assert typeof(value) == "list" +assert all v in value { + typeof(v) == "User" +} diff --git a/kclvm/tools/src/vet/test_datas/invalid_vet_cases_json/list.k.json b/kclvm/tools/src/vet/test_datas/invalid_vet_cases_json/list.k.json new file mode 100644 index 000000000..4e4da006d --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/invalid_vet_cases_json/list.k.json @@ -0,0 +1,7 @@ +[ + { + "name": 10, + "age": 18, + "message": "This is Alice" + } +] diff --git a/kclvm/tools/src/vet/test_datas/invalid_vet_cases_json/plain_value.k b/kclvm/tools/src/vet/test_datas/invalid_vet_cases_json/plain_value.k new file mode 100644 index 000000000..820fab7ce --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/invalid_vet_cases_json/plain_value.k @@ -0,0 +1,2 @@ +assert typeof(value) == "int" +assert value >= 1 diff --git a/kclvm/tools/src/vet/test_datas/invalid_vet_cases_json/plain_value.k.json b/kclvm/tools/src/vet/test_datas/invalid_vet_cases_json/plain_value.k.json new file mode 100644 index 000000000..573541ac9 --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/invalid_vet_cases_json/plain_value.k.json @@ -0,0 +1 @@ +0 diff --git a/test/test_units/test_kclvm/test_tools/test_validation/json_invalid_test_data/schema.k b/kclvm/tools/src/vet/test_datas/invalid_vet_cases_json/simple.k similarity index 100% rename from test/test_units/test_kclvm/test_tools/test_validation/json_invalid_test_data/schema.k rename to kclvm/tools/src/vet/test_datas/invalid_vet_cases_json/simple.k diff --git a/kclvm/tools/src/vet/test_datas/invalid_vet_cases_json/simple.k.json b/kclvm/tools/src/vet/test_datas/invalid_vet_cases_json/simple.k.json new file mode 100644 index 000000000..558a22e13 --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/invalid_vet_cases_json/simple.k.json @@ -0,0 +1,5 @@ +{ + "name": 10, + "age": 18, + "message": "This is Alice" +} diff --git a/kclvm/tools/src/vet/test_datas/invalid_vet_cases_json/test.k b/kclvm/tools/src/vet/test_datas/invalid_vet_cases_json/test.k new file mode 100644 index 000000000..39d538064 --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/invalid_vet_cases_json/test.k @@ -0,0 +1,9 @@ +schema User: + name: str + age: int + message?: str + + check: + name == "Alice" + age > 10 + diff --git a/kclvm/tools/src/vet/test_datas/invalid_vet_cases_json/test.k.json b/kclvm/tools/src/vet/test_datas/invalid_vet_cases_json/test.k.json new file mode 100644 index 000000000..8b12f2738 --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/invalid_vet_cases_json/test.k.json @@ -0,0 +1,5 @@ +{ + "name": "Tom", + "age": 18, + "message": "This is Alice" +} diff --git a/kclvm/tools/src/vet/test_datas/invalid_vet_cases_json/with_import.k b/kclvm/tools/src/vet/test_datas/invalid_vet_cases_json/with_import.k new file mode 100644 index 000000000..5d779160f --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/invalid_vet_cases_json/with_import.k @@ -0,0 +1,4 @@ +import .dep as dep + +schema B: + a: dep.A \ No newline at end of file diff --git a/kclvm/tools/src/vet/test_datas/invalid_vet_cases_json/with_import.k.json b/kclvm/tools/src/vet/test_datas/invalid_vet_cases_json/with_import.k.json new file mode 100644 index 000000000..6789fb1d7 --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/invalid_vet_cases_json/with_import.k.json @@ -0,0 +1,3 @@ +{ + "a": 1 +} \ No newline at end of file diff --git a/kclvm/tools/src/vet/test_datas/invalid_vet_cases_yaml/complex.k b/kclvm/tools/src/vet/test_datas/invalid_vet_cases_yaml/complex.k new file mode 100644 index 000000000..09c880103 --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/invalid_vet_cases_yaml/complex.k @@ -0,0 +1,11 @@ +schema User: + name: str + age: int + message?: str + data: Data + labels: {str:} + hc: [int] + +schema Data: + id: int + value: str diff --git a/kclvm/tools/src/vet/test_datas/invalid_vet_cases_yaml/complex.k.stderr.json b/kclvm/tools/src/vet/test_datas/invalid_vet_cases_yaml/complex.k.stderr.json new file mode 100644 index 000000000..9bfb4e464 --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/invalid_vet_cases_yaml/complex.k.stderr.json @@ -0,0 +1,18 @@ +{ + "__kcl_PanicInfo__": true, + "rust_file": "", + "rust_line": 0, + "rust_col": 0, + "kcl_pkgpath": "", + "kcl_file": "", + "kcl_line": 1, + "kcl_col": 1, + "kcl_arg_msg": "", + "kcl_config_meta_file": "", + "kcl_config_meta_line": 0, + "kcl_config_meta_col": 0, + "kcl_config_meta_arg_msg": "", + "message": "expect Data, got int(10)", + "err_type_code": 5, + "is_warning": false +} \ No newline at end of file diff --git a/kclvm/tools/src/vet/test_datas/invalid_vet_cases_yaml/complex.k.yaml b/kclvm/tools/src/vet/test_datas/invalid_vet_cases_yaml/complex.k.yaml new file mode 100644 index 000000000..17dbf2761 --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/invalid_vet_cases_yaml/complex.k.yaml @@ -0,0 +1,10 @@ +name: Alice +age: 18 +message: This is Alice +data: 10 +labels: + key: value +hc: + - 1 + - 2 + - 3 diff --git a/kclvm/tools/src/vet/test_datas/invalid_vet_cases_yaml/dep/kcl.mod b/kclvm/tools/src/vet/test_datas/invalid_vet_cases_yaml/dep/kcl.mod new file mode 100644 index 000000000..ad4478c32 --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/invalid_vet_cases_yaml/dep/kcl.mod @@ -0,0 +1,5 @@ +[package] +name = "dep" +edition = "v0.8.0" +version = "0.0.1" + diff --git a/kclvm/tools/src/vet/test_datas/invalid_vet_cases_yaml/dep/main.k b/kclvm/tools/src/vet/test_datas/invalid_vet_cases_yaml/dep/main.k new file mode 100644 index 000000000..eae94c15d --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/invalid_vet_cases_yaml/dep/main.k @@ -0,0 +1,2 @@ +schema A : + name: str \ No newline at end of file diff --git a/kclvm/tools/src/vet/test_datas/invalid_vet_cases_yaml/list.k b/kclvm/tools/src/vet/test_datas/invalid_vet_cases_yaml/list.k new file mode 100644 index 000000000..ef6d67aed --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/invalid_vet_cases_yaml/list.k @@ -0,0 +1,9 @@ +schema User: + name: str + age: int + message?: str + +assert typeof(value) == "list" +assert all v in value { + typeof(v) == "User" +} diff --git a/kclvm/tools/src/vet/test_datas/invalid_vet_cases_yaml/list.k.stderr.json b/kclvm/tools/src/vet/test_datas/invalid_vet_cases_yaml/list.k.stderr.json new file mode 100644 index 000000000..9030cae6c --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/invalid_vet_cases_yaml/list.k.stderr.json @@ -0,0 +1,18 @@ +{ + "__kcl_PanicInfo__": true, + "rust_file": "", + "rust_line": 0, + "rust_col": 0, + "kcl_pkgpath": "", + "kcl_file": "", + "kcl_line": 1, + "kcl_col": 1, + "kcl_arg_msg": "", + "kcl_config_meta_file": "", + "kcl_config_meta_line": 0, + "kcl_config_meta_col": 0, + "kcl_config_meta_arg_msg": "", + "message": "expect str, got int(10)", + "err_type_code": 5, + "is_warning": false +} \ No newline at end of file diff --git a/kclvm/tools/src/vet/test_datas/invalid_vet_cases_yaml/list.k.yaml b/kclvm/tools/src/vet/test_datas/invalid_vet_cases_yaml/list.k.yaml new file mode 100644 index 000000000..2a038e8b5 --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/invalid_vet_cases_yaml/list.k.yaml @@ -0,0 +1,4 @@ +- name: 10 + age: 18 + message: This is Alice + \ No newline at end of file diff --git a/kclvm/tools/src/vet/test_datas/invalid_vet_cases_yaml/plain_value.k b/kclvm/tools/src/vet/test_datas/invalid_vet_cases_yaml/plain_value.k new file mode 100644 index 000000000..820fab7ce --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/invalid_vet_cases_yaml/plain_value.k @@ -0,0 +1,2 @@ +assert typeof(value) == "int" +assert value >= 1 diff --git a/kclvm/tools/src/vet/test_datas/invalid_vet_cases_yaml/plain_value.k.stderr.json b/kclvm/tools/src/vet/test_datas/invalid_vet_cases_yaml/plain_value.k.stderr.json new file mode 100644 index 000000000..b1e3dd64c --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/invalid_vet_cases_yaml/plain_value.k.stderr.json @@ -0,0 +1,18 @@ +{ + "__kcl_PanicInfo__": true, + "rust_file": "runtime/src/stdlib/assert_api.rs", + "rust_line": 19, + "rust_col": 9, + "kcl_pkgpath": "", + "kcl_file": "validationTempKCLCode.k", + "kcl_line": 2, + "kcl_col": 0, + "kcl_arg_msg": "", + "kcl_config_meta_file": "", + "kcl_config_meta_line": 0, + "kcl_config_meta_col": 0, + "kcl_config_meta_arg_msg": "", + "message": "", + "err_type_code": 29, + "is_warning": false +} \ No newline at end of file diff --git a/kclvm/tools/src/vet/test_datas/invalid_vet_cases_yaml/plain_value.k.yaml b/kclvm/tools/src/vet/test_datas/invalid_vet_cases_yaml/plain_value.k.yaml new file mode 100644 index 000000000..573541ac9 --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/invalid_vet_cases_yaml/plain_value.k.yaml @@ -0,0 +1 @@ +0 diff --git a/kclvm/tools/src/vet/test_datas/invalid_vet_cases_yaml/simple.k b/kclvm/tools/src/vet/test_datas/invalid_vet_cases_yaml/simple.k new file mode 100644 index 000000000..7a78b3aac --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/invalid_vet_cases_yaml/simple.k @@ -0,0 +1,4 @@ +schema User: + name: str + age: int + message?: str diff --git a/kclvm/tools/src/vet/test_datas/invalid_vet_cases_yaml/simple.k.stderr.json b/kclvm/tools/src/vet/test_datas/invalid_vet_cases_yaml/simple.k.stderr.json new file mode 100644 index 000000000..9030cae6c --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/invalid_vet_cases_yaml/simple.k.stderr.json @@ -0,0 +1,18 @@ +{ + "__kcl_PanicInfo__": true, + "rust_file": "", + "rust_line": 0, + "rust_col": 0, + "kcl_pkgpath": "", + "kcl_file": "", + "kcl_line": 1, + "kcl_col": 1, + "kcl_arg_msg": "", + "kcl_config_meta_file": "", + "kcl_config_meta_line": 0, + "kcl_config_meta_col": 0, + "kcl_config_meta_arg_msg": "", + "message": "expect str, got int(10)", + "err_type_code": 5, + "is_warning": false +} \ No newline at end of file diff --git a/kclvm/tools/src/vet/test_datas/invalid_vet_cases_yaml/simple.k.yaml b/kclvm/tools/src/vet/test_datas/invalid_vet_cases_yaml/simple.k.yaml new file mode 100644 index 000000000..0acfbba39 --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/invalid_vet_cases_yaml/simple.k.yaml @@ -0,0 +1,3 @@ +name: 10 +age: 18 +message: This is Alice diff --git a/kclvm/tools/src/vet/test_datas/invalid_vet_cases_yaml/test.k b/kclvm/tools/src/vet/test_datas/invalid_vet_cases_yaml/test.k new file mode 100644 index 000000000..4c5653da4 --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/invalid_vet_cases_yaml/test.k @@ -0,0 +1,8 @@ +schema User: + name: str + age: int + message?: str + + check: + name == "Alice" + age > 10 diff --git a/kclvm/tools/src/vet/test_datas/invalid_vet_cases_yaml/test.k.stderr.json b/kclvm/tools/src/vet/test_datas/invalid_vet_cases_yaml/test.k.stderr.json new file mode 100644 index 000000000..eedceca94 --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/invalid_vet_cases_yaml/test.k.stderr.json @@ -0,0 +1,18 @@ +{ + "__kcl_PanicInfo__": true, + "rust_file": "runtime/src/value/api.rs", + "rust_line": 2204, + "rust_col": 9, + "kcl_pkgpath": "__main__", + "kcl_file": "validationTempKCLCode.k", + "kcl_line": 7, + "kcl_col": 0, + "kcl_arg_msg": "Check failed on the condition", + "kcl_config_meta_file": "", + "kcl_config_meta_line": 1, + "kcl_config_meta_col": 1, + "kcl_config_meta_arg_msg": "Instance check failed", + "message": "", + "err_type_code": 17, + "is_warning": false +} \ No newline at end of file diff --git a/kclvm/tools/src/vet/test_datas/invalid_vet_cases_yaml/test.k.yaml b/kclvm/tools/src/vet/test_datas/invalid_vet_cases_yaml/test.k.yaml new file mode 100644 index 000000000..26beecf48 --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/invalid_vet_cases_yaml/test.k.yaml @@ -0,0 +1,3 @@ +name: Tom +age: 18 +message: This is Alice diff --git a/kclvm/tools/src/vet/test_datas/invalid_vet_cases_yaml/with_import.k b/kclvm/tools/src/vet/test_datas/invalid_vet_cases_yaml/with_import.k new file mode 100644 index 000000000..5d779160f --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/invalid_vet_cases_yaml/with_import.k @@ -0,0 +1,4 @@ +import .dep as dep + +schema B: + a: dep.A \ No newline at end of file diff --git a/kclvm/tools/src/vet/test_datas/invalid_vet_cases_yaml/with_import.k.stderr.json b/kclvm/tools/src/vet/test_datas/invalid_vet_cases_yaml/with_import.k.stderr.json new file mode 100644 index 000000000..a016ac454 --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/invalid_vet_cases_yaml/with_import.k.stderr.json @@ -0,0 +1 @@ +a: 1 \ No newline at end of file diff --git a/kclvm/tools/src/vet/test_datas/invalid_vet_cases_yaml/with_import.k.yaml b/kclvm/tools/src/vet/test_datas/invalid_vet_cases_yaml/with_import.k.yaml new file mode 100644 index 000000000..a016ac454 --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/invalid_vet_cases_yaml/with_import.k.yaml @@ -0,0 +1 @@ +a: 1 \ No newline at end of file diff --git a/kclvm/tools/src/vet/test_datas/json/complex.k.ast.json b/kclvm/tools/src/vet/test_datas/json/complex.k.ast.json new file mode 100644 index 000000000..6c33f2d9d --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/json/complex.k.ast.json @@ -0,0 +1,443 @@ +{ + "column": 0, + "end_column": 1, + "end_line": 13, + "filename": "/complex.k.json", + "line": 1, + "node": { + "Schema": { + "args": [], + "config": { + "column": 0, + "end_column": 1, + "end_line": 13, + "filename": "/complex.k.json", + "line": 1, + "node": { + "Config": { + "items": [ + { + "column": 0, + "end_column": 1, + "end_line": 13, + "filename": "/complex.k.json", + "line": 1, + "node": { + "insert_index": -1, + "key": { + "column": 4, + "end_column": 9, + "end_line": 3, + "filename": "/complex.k.json", + "line": 3, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"age\"", + "value": "age" + } + } + }, + "operation": "Union", + "value": { + "column": 11, + "end_column": 13, + "end_line": 3, + "filename": "/complex.k.json", + "line": 3, + "node": { + "NumberLit": { + "binary_suffix": null, + "value": { + "Int": 18 + } + } + } + } + } + }, + { + "column": 0, + "end_column": 1, + "end_line": 13, + "filename": "/complex.k.json", + "line": 1, + "node": { + "insert_index": -1, + "key": { + "column": 4, + "end_column": 10, + "end_line": 5, + "filename": "/complex.k.json", + "line": 5, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"data\"", + "value": "data" + } + } + }, + "operation": "Union", + "value": { + "column": 12, + "end_column": 5, + "end_line": 8, + "filename": "/complex.k.json", + "line": 5, + "node": { + "Config": { + "items": [ + { + "column": 12, + "end_column": 5, + "end_line": 8, + "filename": "/complex.k.json", + "line": 5, + "node": { + "insert_index": -1, + "key": { + "column": 8, + "end_column": 12, + "end_line": 6, + "filename": "/complex.k.json", + "line": 6, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"id\"", + "value": "id" + } + } + }, + "operation": "Union", + "value": { + "column": 14, + "end_column": 15, + "end_line": 6, + "filename": "/complex.k.json", + "line": 6, + "node": { + "NumberLit": { + "binary_suffix": null, + "value": { + "Int": 1 + } + } + } + } + } + }, + { + "column": 12, + "end_column": 5, + "end_line": 8, + "filename": "/complex.k.json", + "line": 5, + "node": { + "insert_index": -1, + "key": { + "column": 8, + "end_column": 15, + "end_line": 7, + "filename": "/complex.k.json", + "line": 7, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"value\"", + "value": "value" + } + } + }, + "operation": "Union", + "value": { + "column": 17, + "end_column": 25, + "end_line": 7, + "filename": "/complex.k.json", + "line": 7, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"value1\"", + "value": "value1" + } + } + } + } + } + ] + } + } + } + } + }, + { + "column": 0, + "end_column": 1, + "end_line": 13, + "filename": "/complex.k.json", + "line": 1, + "node": { + "insert_index": -1, + "key": { + "column": 4, + "end_column": 8, + "end_line": 12, + "filename": "/complex.k.json", + "line": 12, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"hc\"", + "value": "hc" + } + } + }, + "operation": "Union", + "value": { + "column": 10, + "end_column": 19, + "end_line": 12, + "filename": "/complex.k.json", + "line": 12, + "node": { + "List": { + "ctx": "Load", + "elts": [ + { + "column": 11, + "end_column": 12, + "end_line": 12, + "filename": "/complex.k.json", + "line": 12, + "node": { + "NumberLit": { + "binary_suffix": null, + "value": { + "Int": 1 + } + } + } + }, + { + "column": 14, + "end_column": 15, + "end_line": 12, + "filename": "/complex.k.json", + "line": 12, + "node": { + "NumberLit": { + "binary_suffix": null, + "value": { + "Int": 2 + } + } + } + }, + { + "column": 17, + "end_column": 18, + "end_line": 12, + "filename": "/complex.k.json", + "line": 12, + "node": { + "NumberLit": { + "binary_suffix": null, + "value": { + "Int": 3 + } + } + } + } + ] + } + } + } + } + }, + { + "column": 0, + "end_column": 1, + "end_line": 13, + "filename": "/complex.k.json", + "line": 1, + "node": { + "insert_index": -1, + "key": { + "column": 4, + "end_column": 12, + "end_line": 9, + "filename": "/complex.k.json", + "line": 9, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"labels\"", + "value": "labels" + } + } + }, + "operation": "Union", + "value": { + "column": 14, + "end_column": 5, + "end_line": 11, + "filename": "/complex.k.json", + "line": 9, + "node": { + "Config": { + "items": [ + { + "column": 14, + "end_column": 5, + "end_line": 11, + "filename": "/complex.k.json", + "line": 9, + "node": { + "insert_index": -1, + "key": { + "column": 8, + "end_column": 13, + "end_line": 10, + "filename": "/complex.k.json", + "line": 10, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"key\"", + "value": "key" + } + } + }, + "operation": "Union", + "value": { + "column": 15, + "end_column": 22, + "end_line": 10, + "filename": "/complex.k.json", + "line": 10, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"value\"", + "value": "value" + } + } + } + } + } + ] + } + } + } + } + }, + { + "column": 0, + "end_column": 1, + "end_line": 13, + "filename": "/complex.k.json", + "line": 1, + "node": { + "insert_index": -1, + "key": { + "column": 4, + "end_column": 13, + "end_line": 4, + "filename": "/complex.k.json", + "line": 4, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"message\"", + "value": "message" + } + } + }, + "operation": "Union", + "value": { + "column": 15, + "end_column": 30, + "end_line": 4, + "filename": "/complex.k.json", + "line": 4, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"This is Alice\"", + "value": "This is Alice" + } + } + } + } + }, + { + "column": 0, + "end_column": 1, + "end_line": 13, + "filename": "/complex.k.json", + "line": 1, + "node": { + "insert_index": -1, + "key": { + "column": 4, + "end_column": 10, + "end_line": 2, + "filename": "/complex.k.json", + "line": 2, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"name\"", + "value": "name" + } + } + }, + "operation": "Union", + "value": { + "column": 12, + "end_column": 19, + "end_line": 2, + "filename": "/complex.k.json", + "line": 2, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"Alice\"", + "value": "Alice" + } + } + } + } + } + ] + } + } + }, + "kwargs": [], + "name": { + "column": 0, + "end_column": 1, + "end_line": 13, + "filename": "/complex.k.json", + "line": 1, + "node": { + "ctx": "Load", + "names": [ + { + "column": 0, + "end_column": 1, + "end_line": 13, + "filename": "/complex.k.json", + "line": 1, + "node": "complex" + } + ], + "pkgpath": "" + } + } + } + } +} \ No newline at end of file diff --git a/test/test_units/test_kclvm/test_tools/test_validation/json_test_data/complex.k.json b/kclvm/tools/src/vet/test_datas/json/complex.k.json similarity index 100% rename from test/test_units/test_kclvm/test_tools/test_validation/json_test_data/complex.k.json rename to kclvm/tools/src/vet/test_datas/json/complex.k.json diff --git a/kclvm/tools/src/vet/test_datas/json/list.k.ast.json b/kclvm/tools/src/vet/test_datas/json/list.k.ast.json new file mode 100644 index 000000000..21f95eb77 --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/json/list.k.ast.json @@ -0,0 +1,179 @@ +{ + "column": 0, + "end_column": 1, + "end_line": 7, + "filename": "/list.k.json", + "line": 1, + "node": { + "List": { + "ctx": "Load", + "elts": [ + { + "column": 4, + "end_column": 5, + "end_line": 6, + "filename": "/list.k.json", + "line": 2, + "node": { + "Schema": { + "args": [], + "config": { + "column": 4, + "end_column": 5, + "end_line": 6, + "filename": "/list.k.json", + "line": 2, + "node": { + "Config": { + "items": [ + { + "column": 4, + "end_column": 5, + "end_line": 6, + "filename": "/list.k.json", + "line": 2, + "node": { + "insert_index": -1, + "key": { + "column": 8, + "end_column": 13, + "end_line": 4, + "filename": "/list.k.json", + "line": 4, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"age\"", + "value": "age" + } + } + }, + "operation": "Union", + "value": { + "column": 15, + "end_column": 17, + "end_line": 4, + "filename": "/list.k.json", + "line": 4, + "node": { + "NumberLit": { + "binary_suffix": null, + "value": { + "Int": 18 + } + } + } + } + } + }, + { + "column": 4, + "end_column": 5, + "end_line": 6, + "filename": "/list.k.json", + "line": 2, + "node": { + "insert_index": -1, + "key": { + "column": 8, + "end_column": 17, + "end_line": 5, + "filename": "/list.k.json", + "line": 5, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"message\"", + "value": "message" + } + } + }, + "operation": "Union", + "value": { + "column": 19, + "end_column": 34, + "end_line": 5, + "filename": "/list.k.json", + "line": 5, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"This is Alice\"", + "value": "This is Alice" + } + } + } + } + }, + { + "column": 4, + "end_column": 5, + "end_line": 6, + "filename": "/list.k.json", + "line": 2, + "node": { + "insert_index": -1, + "key": { + "column": 8, + "end_column": 14, + "end_line": 3, + "filename": "/list.k.json", + "line": 3, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"name\"", + "value": "name" + } + } + }, + "operation": "Union", + "value": { + "column": 16, + "end_column": 23, + "end_line": 3, + "filename": "/list.k.json", + "line": 3, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"Alice\"", + "value": "Alice" + } + } + } + } + } + ] + } + } + }, + "kwargs": [], + "name": { + "column": 4, + "end_column": 5, + "end_line": 6, + "filename": "/list.k.json", + "line": 2, + "node": { + "ctx": "Load", + "names": [ + { + "column": 4, + "end_column": 5, + "end_line": 6, + "filename": "/list.k.json", + "line": 2, + "node": "list" + } + ], + "pkgpath": "" + } + } + } + } + } + ] + } + } +} \ No newline at end of file diff --git a/test/test_units/test_kclvm/test_tools/test_validation/json_test_data/list.k.json b/kclvm/tools/src/vet/test_datas/json/list.k.json similarity index 100% rename from test/test_units/test_kclvm/test_tools/test_validation/json_test_data/list.k.json rename to kclvm/tools/src/vet/test_datas/json/list.k.json diff --git a/kclvm/tools/src/vet/test_datas/json/no_schema_name/complex.k.ast.json b/kclvm/tools/src/vet/test_datas/json/no_schema_name/complex.k.ast.json new file mode 100644 index 000000000..94c9fcbab --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/json/no_schema_name/complex.k.ast.json @@ -0,0 +1,409 @@ +{ + "column": 0, + "end_column": 1, + "end_line": 13, + "filename": "/complex.k.json", + "line": 1, + "node": { + "Config": { + "items": [ + { + "column": 0, + "end_column": 1, + "end_line": 13, + "filename": "/complex.k.json", + "line": 1, + "node": { + "insert_index": -1, + "key": { + "column": 4, + "end_column": 9, + "end_line": 3, + "filename": "/complex.k.json", + "line": 3, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"age\"", + "value": "age" + } + } + }, + "operation": "Union", + "value": { + "column": 11, + "end_column": 13, + "end_line": 3, + "filename": "/complex.k.json", + "line": 3, + "node": { + "NumberLit": { + "binary_suffix": null, + "value": { + "Int": 18 + } + } + } + } + } + }, + { + "column": 0, + "end_column": 1, + "end_line": 13, + "filename": "/complex.k.json", + "line": 1, + "node": { + "insert_index": -1, + "key": { + "column": 4, + "end_column": 10, + "end_line": 5, + "filename": "/complex.k.json", + "line": 5, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"data\"", + "value": "data" + } + } + }, + "operation": "Union", + "value": { + "column": 12, + "end_column": 5, + "end_line": 8, + "filename": "/complex.k.json", + "line": 5, + "node": { + "Config": { + "items": [ + { + "column": 12, + "end_column": 5, + "end_line": 8, + "filename": "/complex.k.json", + "line": 5, + "node": { + "insert_index": -1, + "key": { + "column": 8, + "end_column": 12, + "end_line": 6, + "filename": "/complex.k.json", + "line": 6, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"id\"", + "value": "id" + } + } + }, + "operation": "Union", + "value": { + "column": 14, + "end_column": 15, + "end_line": 6, + "filename": "/complex.k.json", + "line": 6, + "node": { + "NumberLit": { + "binary_suffix": null, + "value": { + "Int": 1 + } + } + } + } + } + }, + { + "column": 12, + "end_column": 5, + "end_line": 8, + "filename": "/complex.k.json", + "line": 5, + "node": { + "insert_index": -1, + "key": { + "column": 8, + "end_column": 15, + "end_line": 7, + "filename": "/complex.k.json", + "line": 7, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"value\"", + "value": "value" + } + } + }, + "operation": "Union", + "value": { + "column": 17, + "end_column": 25, + "end_line": 7, + "filename": "/complex.k.json", + "line": 7, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"value1\"", + "value": "value1" + } + } + } + } + } + ] + } + } + } + } + }, + { + "column": 0, + "end_column": 1, + "end_line": 13, + "filename": "/complex.k.json", + "line": 1, + "node": { + "insert_index": -1, + "key": { + "column": 4, + "end_column": 8, + "end_line": 12, + "filename": "/complex.k.json", + "line": 12, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"hc\"", + "value": "hc" + } + } + }, + "operation": "Union", + "value": { + "column": 10, + "end_column": 19, + "end_line": 12, + "filename": "/complex.k.json", + "line": 12, + "node": { + "List": { + "ctx": "Load", + "elts": [ + { + "column": 11, + "end_column": 12, + "end_line": 12, + "filename": "/complex.k.json", + "line": 12, + "node": { + "NumberLit": { + "binary_suffix": null, + "value": { + "Int": 1 + } + } + } + }, + { + "column": 14, + "end_column": 15, + "end_line": 12, + "filename": "/complex.k.json", + "line": 12, + "node": { + "NumberLit": { + "binary_suffix": null, + "value": { + "Int": 2 + } + } + } + }, + { + "column": 17, + "end_column": 18, + "end_line": 12, + "filename": "/complex.k.json", + "line": 12, + "node": { + "NumberLit": { + "binary_suffix": null, + "value": { + "Int": 3 + } + } + } + } + ] + } + } + } + } + }, + { + "column": 0, + "end_column": 1, + "end_line": 13, + "filename": "/complex.k.json", + "line": 1, + "node": { + "insert_index": -1, + "key": { + "column": 4, + "end_column": 12, + "end_line": 9, + "filename": "/complex.k.json", + "line": 9, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"labels\"", + "value": "labels" + } + } + }, + "operation": "Union", + "value": { + "column": 14, + "end_column": 5, + "end_line": 11, + "filename": "/complex.k.json", + "line": 9, + "node": { + "Config": { + "items": [ + { + "column": 14, + "end_column": 5, + "end_line": 11, + "filename": "/complex.k.json", + "line": 9, + "node": { + "insert_index": -1, + "key": { + "column": 8, + "end_column": 13, + "end_line": 10, + "filename": "/complex.k.json", + "line": 10, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"key\"", + "value": "key" + } + } + }, + "operation": "Union", + "value": { + "column": 15, + "end_column": 22, + "end_line": 10, + "filename": "/complex.k.json", + "line": 10, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"value\"", + "value": "value" + } + } + } + } + } + ] + } + } + } + } + }, + { + "column": 0, + "end_column": 1, + "end_line": 13, + "filename": "/complex.k.json", + "line": 1, + "node": { + "insert_index": -1, + "key": { + "column": 4, + "end_column": 13, + "end_line": 4, + "filename": "/complex.k.json", + "line": 4, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"message\"", + "value": "message" + } + } + }, + "operation": "Union", + "value": { + "column": 15, + "end_column": 30, + "end_line": 4, + "filename": "/complex.k.json", + "line": 4, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"This is Alice\"", + "value": "This is Alice" + } + } + } + } + }, + { + "column": 0, + "end_column": 1, + "end_line": 13, + "filename": "/complex.k.json", + "line": 1, + "node": { + "insert_index": -1, + "key": { + "column": 4, + "end_column": 10, + "end_line": 2, + "filename": "/complex.k.json", + "line": 2, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"name\"", + "value": "name" + } + } + }, + "operation": "Union", + "value": { + "column": 12, + "end_column": 19, + "end_line": 2, + "filename": "/complex.k.json", + "line": 2, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"Alice\"", + "value": "Alice" + } + } + } + } + } + ] + } + } +} \ No newline at end of file diff --git a/kclvm/tools/src/vet/test_datas/json/no_schema_name/list.k.ast.json b/kclvm/tools/src/vet/test_datas/json/no_schema_name/list.k.ast.json new file mode 100644 index 000000000..5328534c9 --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/json/no_schema_name/list.k.ast.json @@ -0,0 +1,145 @@ +{ + "column": 0, + "end_column": 1, + "end_line": 7, + "filename": "/list.k.json", + "line": 1, + "node": { + "List": { + "ctx": "Load", + "elts": [ + { + "column": 4, + "end_column": 5, + "end_line": 6, + "filename": "/list.k.json", + "line": 2, + "node": { + "Config": { + "items": [ + { + "column": 4, + "end_column": 5, + "end_line": 6, + "filename": "/list.k.json", + "line": 2, + "node": { + "insert_index": -1, + "key": { + "column": 8, + "end_column": 13, + "end_line": 4, + "filename": "/list.k.json", + "line": 4, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"age\"", + "value": "age" + } + } + }, + "operation": "Union", + "value": { + "column": 15, + "end_column": 17, + "end_line": 4, + "filename": "/list.k.json", + "line": 4, + "node": { + "NumberLit": { + "binary_suffix": null, + "value": { + "Int": 18 + } + } + } + } + } + }, + { + "column": 4, + "end_column": 5, + "end_line": 6, + "filename": "/list.k.json", + "line": 2, + "node": { + "insert_index": -1, + "key": { + "column": 8, + "end_column": 17, + "end_line": 5, + "filename": "/list.k.json", + "line": 5, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"message\"", + "value": "message" + } + } + }, + "operation": "Union", + "value": { + "column": 19, + "end_column": 34, + "end_line": 5, + "filename": "/list.k.json", + "line": 5, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"This is Alice\"", + "value": "This is Alice" + } + } + } + } + }, + { + "column": 4, + "end_column": 5, + "end_line": 6, + "filename": "/list.k.json", + "line": 2, + "node": { + "insert_index": -1, + "key": { + "column": 8, + "end_column": 14, + "end_line": 3, + "filename": "/list.k.json", + "line": 3, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"name\"", + "value": "name" + } + } + }, + "operation": "Union", + "value": { + "column": 16, + "end_column": 23, + "end_line": 3, + "filename": "/list.k.json", + "line": 3, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"Alice\"", + "value": "Alice" + } + } + } + } + } + ] + } + } + } + ] + } + } +} \ No newline at end of file diff --git a/kclvm/tools/src/vet/test_datas/json/no_schema_name/only_with_bool.ast.json b/kclvm/tools/src/vet/test_datas/json/no_schema_name/only_with_bool.ast.json new file mode 100644 index 000000000..31ebdf6f2 --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/json/no_schema_name/only_with_bool.ast.json @@ -0,0 +1,50 @@ +{ + "column": 0, + "end_column": 1, + "end_line": 3, + "filename": "/only_with_bool.json", + "line": 1, + "node": { + "Config": { + "items": [ + { + "column": 0, + "end_column": 1, + "end_line": 3, + "filename": "/only_with_bool.json", + "line": 1, + "node": { + "insert_index": -1, + "key": { + "column": 4, + "end_column": 10, + "end_line": 2, + "filename": "/only_with_bool.json", + "line": 2, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"flag\"", + "value": "flag" + } + } + }, + "operation": "Union", + "value": { + "column": 12, + "end_column": 16, + "end_line": 2, + "filename": "/only_with_bool.json", + "line": 2, + "node": { + "NameConstantLit": { + "value": "True" + } + } + } + } + } + ] + } + } +} \ No newline at end of file diff --git a/kclvm/tools/src/vet/test_datas/json/no_schema_name/only_with_float.ast.json b/kclvm/tools/src/vet/test_datas/json/no_schema_name/only_with_float.ast.json new file mode 100644 index 000000000..2f3a0968a --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/json/no_schema_name/only_with_float.ast.json @@ -0,0 +1,53 @@ +{ + "column": 0, + "end_column": 1, + "end_line": 3, + "filename": "/only_with_float.json", + "line": 1, + "node": { + "Config": { + "items": [ + { + "column": 0, + "end_column": 1, + "end_line": 3, + "filename": "/only_with_float.json", + "line": 1, + "node": { + "insert_index": -1, + "key": { + "column": 4, + "end_column": 17, + "end_line": 2, + "filename": "/only_with_float.json", + "line": 2, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"float_value\"", + "value": "float_value" + } + } + }, + "operation": "Union", + "value": { + "column": 19, + "end_column": 23, + "end_line": 2, + "filename": "/only_with_float.json", + "line": 2, + "node": { + "NumberLit": { + "binary_suffix": null, + "value": { + "Float": 0.33 + } + } + } + } + } + } + ] + } + } +} \ No newline at end of file diff --git a/kclvm/tools/src/vet/test_datas/json/no_schema_name/only_with_null.ast.json b/kclvm/tools/src/vet/test_datas/json/no_schema_name/only_with_null.ast.json new file mode 100644 index 000000000..f4723b7ff --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/json/no_schema_name/only_with_null.ast.json @@ -0,0 +1,50 @@ +{ + "column": 0, + "end_column": 1, + "end_line": 3, + "filename": "/only_with_null.json", + "line": 1, + "node": { + "Config": { + "items": [ + { + "column": 0, + "end_column": 1, + "end_line": 3, + "filename": "/only_with_null.json", + "line": 1, + "node": { + "insert_index": -1, + "key": { + "column": 4, + "end_column": 16, + "end_line": 2, + "filename": "/only_with_null.json", + "line": 2, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"null_value\"", + "value": "null_value" + } + } + }, + "operation": "Union", + "value": { + "column": 18, + "end_column": 22, + "end_line": 2, + "filename": "/only_with_null.json", + "line": 2, + "node": { + "NameConstantLit": { + "value": "None" + } + } + } + } + } + ] + } + } +} \ No newline at end of file diff --git a/kclvm/tools/src/vet/test_datas/json/no_schema_name/plain_value.k.ast.json b/kclvm/tools/src/vet/test_datas/json/no_schema_name/plain_value.k.ast.json new file mode 100644 index 000000000..3110dbc86 --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/json/no_schema_name/plain_value.k.ast.json @@ -0,0 +1,15 @@ +{ + "column": 0, + "end_column": 1, + "end_line": 1, + "filename": "/plain_value.k.json", + "line": 1, + "node": { + "NumberLit": { + "binary_suffix": null, + "value": { + "Int": 1 + } + } + } +} \ No newline at end of file diff --git a/kclvm/tools/src/vet/test_datas/json/no_schema_name/simple.k.ast.json b/kclvm/tools/src/vet/test_datas/json/no_schema_name/simple.k.ast.json new file mode 100644 index 000000000..76b85ff1a --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/json/no_schema_name/simple.k.ast.json @@ -0,0 +1,131 @@ +{ + "column": 0, + "end_column": 1, + "end_line": 5, + "filename": "/simple.k.json", + "line": 1, + "node": { + "Config": { + "items": [ + { + "column": 0, + "end_column": 1, + "end_line": 5, + "filename": "/simple.k.json", + "line": 1, + "node": { + "insert_index": -1, + "key": { + "column": 4, + "end_column": 9, + "end_line": 3, + "filename": "/simple.k.json", + "line": 3, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"age\"", + "value": "age" + } + } + }, + "operation": "Union", + "value": { + "column": 11, + "end_column": 13, + "end_line": 3, + "filename": "/simple.k.json", + "line": 3, + "node": { + "NumberLit": { + "binary_suffix": null, + "value": { + "Int": 18 + } + } + } + } + } + }, + { + "column": 0, + "end_column": 1, + "end_line": 5, + "filename": "/simple.k.json", + "line": 1, + "node": { + "insert_index": -1, + "key": { + "column": 4, + "end_column": 13, + "end_line": 4, + "filename": "/simple.k.json", + "line": 4, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"message\"", + "value": "message" + } + } + }, + "operation": "Union", + "value": { + "column": 15, + "end_column": 30, + "end_line": 4, + "filename": "/simple.k.json", + "line": 4, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"This is Alice\"", + "value": "This is Alice" + } + } + } + } + }, + { + "column": 0, + "end_column": 1, + "end_line": 5, + "filename": "/simple.k.json", + "line": 1, + "node": { + "insert_index": -1, + "key": { + "column": 4, + "end_column": 10, + "end_line": 2, + "filename": "/simple.k.json", + "line": 2, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"name\"", + "value": "name" + } + } + }, + "operation": "Union", + "value": { + "column": 12, + "end_column": 19, + "end_line": 2, + "filename": "/simple.k.json", + "line": 2, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"Alice\"", + "value": "Alice" + } + } + } + } + } + ] + } + } +} \ No newline at end of file diff --git a/kclvm/tools/src/vet/test_datas/json/no_schema_name/test.k.ast.json b/kclvm/tools/src/vet/test_datas/json/no_schema_name/test.k.ast.json new file mode 100644 index 000000000..e683f9346 --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/json/no_schema_name/test.k.ast.json @@ -0,0 +1,275 @@ +{ + "column": 0, + "end_column": 1, + "end_line": 12, + "filename": "/test.k.json", + "line": 1, + "node": { + "Config": { + "items": [ + { + "column": 0, + "end_column": 1, + "end_line": 12, + "filename": "/test.k.json", + "line": 1, + "node": { + "insert_index": -1, + "key": { + "column": 4, + "end_column": 13, + "end_line": 4, + "filename": "/test.k.json", + "line": 4, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"address\"", + "value": "address" + } + } + }, + "operation": "Union", + "value": { + "column": 15, + "end_column": 5, + "end_line": 7, + "filename": "/test.k.json", + "line": 4, + "node": { + "Config": { + "items": [ + { + "column": 15, + "end_column": 5, + "end_line": 7, + "filename": "/test.k.json", + "line": 4, + "node": { + "insert_index": -1, + "key": { + "column": 8, + "end_column": 14, + "end_line": 6, + "filename": "/test.k.json", + "line": 6, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"city\"", + "value": "city" + } + } + }, + "operation": "Union", + "value": { + "column": 16, + "end_column": 24, + "end_line": 6, + "filename": "/test.k.json", + "line": 6, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"London\"", + "value": "London" + } + } + } + } + }, + { + "column": 15, + "end_column": 5, + "end_line": 7, + "filename": "/test.k.json", + "line": 4, + "node": { + "insert_index": -1, + "key": { + "column": 8, + "end_column": 16, + "end_line": 5, + "filename": "/test.k.json", + "line": 5, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"street\"", + "value": "street" + } + } + }, + "operation": "Union", + "value": { + "column": 18, + "end_column": 37, + "end_line": 5, + "filename": "/test.k.json", + "line": 5, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"10 Downing Street\"", + "value": "10 Downing Street" + } + } + } + } + } + ] + } + } + } + } + }, + { + "column": 0, + "end_column": 1, + "end_line": 12, + "filename": "/test.k.json", + "line": 1, + "node": { + "insert_index": -1, + "key": { + "column": 4, + "end_column": 9, + "end_line": 3, + "filename": "/test.k.json", + "line": 3, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"age\"", + "value": "age" + } + } + }, + "operation": "Union", + "value": { + "column": 11, + "end_column": 13, + "end_line": 3, + "filename": "/test.k.json", + "line": 3, + "node": { + "NumberLit": { + "binary_suffix": null, + "value": { + "Int": 43 + } + } + } + } + } + }, + { + "column": 0, + "end_column": 1, + "end_line": 12, + "filename": "/test.k.json", + "line": 1, + "node": { + "insert_index": -1, + "key": { + "column": 4, + "end_column": 10, + "end_line": 2, + "filename": "/test.k.json", + "line": 2, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"name\"", + "value": "name" + } + } + }, + "operation": "Union", + "value": { + "column": 12, + "end_column": 22, + "end_line": 2, + "filename": "/test.k.json", + "line": 2, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"John Doe\"", + "value": "John Doe" + } + } + } + } + }, + { + "column": 0, + "end_column": 1, + "end_line": 12, + "filename": "/test.k.json", + "line": 1, + "node": { + "insert_index": -1, + "key": { + "column": 4, + "end_column": 12, + "end_line": 8, + "filename": "/test.k.json", + "line": 8, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"phones\"", + "value": "phones" + } + } + }, + "operation": "Union", + "value": { + "column": 14, + "end_column": 5, + "end_line": 11, + "filename": "/test.k.json", + "line": 8, + "node": { + "List": { + "ctx": "Load", + "elts": [ + { + "column": 8, + "end_column": 21, + "end_line": 9, + "filename": "/test.k.json", + "line": 9, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"+44 1234567\"", + "value": "+44 1234567" + } + } + }, + { + "column": 8, + "end_column": 21, + "end_line": 10, + "filename": "/test.k.json", + "line": 10, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"+44 2345678\"", + "value": "+44 2345678" + } + } + } + ] + } + } + } + } + } + ] + } + } +} \ No newline at end of file diff --git a/kclvm/tools/src/vet/test_datas/json/only_with_bool.ast.json b/kclvm/tools/src/vet/test_datas/json/only_with_bool.ast.json new file mode 100644 index 000000000..0913c16c2 --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/json/only_with_bool.ast.json @@ -0,0 +1,84 @@ +{ + "column": 0, + "end_column": 1, + "end_line": 3, + "filename": "/only_with_bool.json", + "line": 1, + "node": { + "Schema": { + "args": [], + "config": { + "column": 0, + "end_column": 1, + "end_line": 3, + "filename": "/only_with_bool.json", + "line": 1, + "node": { + "Config": { + "items": [ + { + "column": 0, + "end_column": 1, + "end_line": 3, + "filename": "/only_with_bool.json", + "line": 1, + "node": { + "insert_index": -1, + "key": { + "column": 4, + "end_column": 10, + "end_line": 2, + "filename": "/only_with_bool.json", + "line": 2, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"flag\"", + "value": "flag" + } + } + }, + "operation": "Union", + "value": { + "column": 12, + "end_column": 16, + "end_line": 2, + "filename": "/only_with_bool.json", + "line": 2, + "node": { + "NameConstantLit": { + "value": "True" + } + } + } + } + } + ] + } + } + }, + "kwargs": [], + "name": { + "column": 0, + "end_column": 1, + "end_line": 3, + "filename": "/only_with_bool.json", + "line": 1, + "node": { + "ctx": "Load", + "names": [ + { + "column": 0, + "end_column": 1, + "end_line": 3, + "filename": "/only_with_bool.json", + "line": 1, + "node": "only_with_bool" + } + ], + "pkgpath": "" + } + } + } + } +} \ No newline at end of file diff --git a/kclvm/tools/src/vet/test_datas/json/only_with_bool.json b/kclvm/tools/src/vet/test_datas/json/only_with_bool.json new file mode 100644 index 000000000..ca087fd5f --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/json/only_with_bool.json @@ -0,0 +1,3 @@ +{ + "flag": true +} \ No newline at end of file diff --git a/kclvm/tools/src/vet/test_datas/json/only_with_float.ast.json b/kclvm/tools/src/vet/test_datas/json/only_with_float.ast.json new file mode 100644 index 000000000..e897394ba --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/json/only_with_float.ast.json @@ -0,0 +1,87 @@ +{ + "column": 0, + "end_column": 1, + "end_line": 3, + "filename": "/only_with_float.json", + "line": 1, + "node": { + "Schema": { + "args": [], + "config": { + "column": 0, + "end_column": 1, + "end_line": 3, + "filename": "/only_with_float.json", + "line": 1, + "node": { + "Config": { + "items": [ + { + "column": 0, + "end_column": 1, + "end_line": 3, + "filename": "/only_with_float.json", + "line": 1, + "node": { + "insert_index": -1, + "key": { + "column": 4, + "end_column": 17, + "end_line": 2, + "filename": "/only_with_float.json", + "line": 2, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"float_value\"", + "value": "float_value" + } + } + }, + "operation": "Union", + "value": { + "column": 19, + "end_column": 23, + "end_line": 2, + "filename": "/only_with_float.json", + "line": 2, + "node": { + "NumberLit": { + "binary_suffix": null, + "value": { + "Float": 0.33 + } + } + } + } + } + } + ] + } + } + }, + "kwargs": [], + "name": { + "column": 0, + "end_column": 1, + "end_line": 3, + "filename": "/only_with_float.json", + "line": 1, + "node": { + "ctx": "Load", + "names": [ + { + "column": 0, + "end_column": 1, + "end_line": 3, + "filename": "/only_with_float.json", + "line": 1, + "node": "only_with_float" + } + ], + "pkgpath": "" + } + } + } + } +} \ No newline at end of file diff --git a/kclvm/tools/src/vet/test_datas/json/only_with_float.json b/kclvm/tools/src/vet/test_datas/json/only_with_float.json new file mode 100644 index 000000000..8f6133170 --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/json/only_with_float.json @@ -0,0 +1,3 @@ +{ + "float_value": 0.33 +} \ No newline at end of file diff --git a/kclvm/tools/src/vet/test_datas/json/only_with_null.ast.json b/kclvm/tools/src/vet/test_datas/json/only_with_null.ast.json new file mode 100644 index 000000000..afde4b451 --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/json/only_with_null.ast.json @@ -0,0 +1,84 @@ +{ + "column": 0, + "end_column": 1, + "end_line": 3, + "filename": "/only_with_null.json", + "line": 1, + "node": { + "Schema": { + "args": [], + "config": { + "column": 0, + "end_column": 1, + "end_line": 3, + "filename": "/only_with_null.json", + "line": 1, + "node": { + "Config": { + "items": [ + { + "column": 0, + "end_column": 1, + "end_line": 3, + "filename": "/only_with_null.json", + "line": 1, + "node": { + "insert_index": -1, + "key": { + "column": 4, + "end_column": 16, + "end_line": 2, + "filename": "/only_with_null.json", + "line": 2, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"null_value\"", + "value": "null_value" + } + } + }, + "operation": "Union", + "value": { + "column": 18, + "end_column": 22, + "end_line": 2, + "filename": "/only_with_null.json", + "line": 2, + "node": { + "NameConstantLit": { + "value": "None" + } + } + } + } + } + ] + } + } + }, + "kwargs": [], + "name": { + "column": 0, + "end_column": 1, + "end_line": 3, + "filename": "/only_with_null.json", + "line": 1, + "node": { + "ctx": "Load", + "names": [ + { + "column": 0, + "end_column": 1, + "end_line": 3, + "filename": "/only_with_null.json", + "line": 1, + "node": "only_with_null" + } + ], + "pkgpath": "" + } + } + } + } +} \ No newline at end of file diff --git a/kclvm/tools/src/vet/test_datas/json/only_with_null.json b/kclvm/tools/src/vet/test_datas/json/only_with_null.json new file mode 100644 index 000000000..0578d4d6e --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/json/only_with_null.json @@ -0,0 +1,3 @@ +{ + "null_value": null +} \ No newline at end of file diff --git a/kclvm/tools/src/vet/test_datas/json/plain_value.k.ast.json b/kclvm/tools/src/vet/test_datas/json/plain_value.k.ast.json new file mode 100644 index 000000000..3110dbc86 --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/json/plain_value.k.ast.json @@ -0,0 +1,15 @@ +{ + "column": 0, + "end_column": 1, + "end_line": 1, + "filename": "/plain_value.k.json", + "line": 1, + "node": { + "NumberLit": { + "binary_suffix": null, + "value": { + "Int": 1 + } + } + } +} \ No newline at end of file diff --git a/test/test_units/test_kclvm/test_tools/test_validation/json_test_data/plain_value.k.json b/kclvm/tools/src/vet/test_datas/json/plain_value.k.json similarity index 100% rename from test/test_units/test_kclvm/test_tools/test_validation/json_test_data/plain_value.k.json rename to kclvm/tools/src/vet/test_datas/json/plain_value.k.json diff --git a/kclvm/tools/src/vet/test_datas/json/simple.k.ast.json b/kclvm/tools/src/vet/test_datas/json/simple.k.ast.json new file mode 100644 index 000000000..45841497c --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/json/simple.k.ast.json @@ -0,0 +1,165 @@ +{ + "column": 0, + "end_column": 1, + "end_line": 5, + "filename": "/simple.k.json", + "line": 1, + "node": { + "Schema": { + "args": [], + "config": { + "column": 0, + "end_column": 1, + "end_line": 5, + "filename": "/simple.k.json", + "line": 1, + "node": { + "Config": { + "items": [ + { + "column": 0, + "end_column": 1, + "end_line": 5, + "filename": "/simple.k.json", + "line": 1, + "node": { + "insert_index": -1, + "key": { + "column": 4, + "end_column": 9, + "end_line": 3, + "filename": "/simple.k.json", + "line": 3, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"age\"", + "value": "age" + } + } + }, + "operation": "Union", + "value": { + "column": 11, + "end_column": 13, + "end_line": 3, + "filename": "/simple.k.json", + "line": 3, + "node": { + "NumberLit": { + "binary_suffix": null, + "value": { + "Int": 18 + } + } + } + } + } + }, + { + "column": 0, + "end_column": 1, + "end_line": 5, + "filename": "/simple.k.json", + "line": 1, + "node": { + "insert_index": -1, + "key": { + "column": 4, + "end_column": 13, + "end_line": 4, + "filename": "/simple.k.json", + "line": 4, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"message\"", + "value": "message" + } + } + }, + "operation": "Union", + "value": { + "column": 15, + "end_column": 30, + "end_line": 4, + "filename": "/simple.k.json", + "line": 4, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"This is Alice\"", + "value": "This is Alice" + } + } + } + } + }, + { + "column": 0, + "end_column": 1, + "end_line": 5, + "filename": "/simple.k.json", + "line": 1, + "node": { + "insert_index": -1, + "key": { + "column": 4, + "end_column": 10, + "end_line": 2, + "filename": "/simple.k.json", + "line": 2, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"name\"", + "value": "name" + } + } + }, + "operation": "Union", + "value": { + "column": 12, + "end_column": 19, + "end_line": 2, + "filename": "/simple.k.json", + "line": 2, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"Alice\"", + "value": "Alice" + } + } + } + } + } + ] + } + } + }, + "kwargs": [], + "name": { + "column": 0, + "end_column": 1, + "end_line": 5, + "filename": "/simple.k.json", + "line": 1, + "node": { + "ctx": "Load", + "names": [ + { + "column": 0, + "end_column": 1, + "end_line": 5, + "filename": "/simple.k.json", + "line": 1, + "node": "simple" + } + ], + "pkgpath": "" + } + } + } + } +} \ No newline at end of file diff --git a/test/test_units/test_kclvm/test_tools/test_validation/json_test_data/simple.k.json b/kclvm/tools/src/vet/test_datas/json/simple.k.json similarity index 100% rename from test/test_units/test_kclvm/test_tools/test_validation/json_test_data/simple.k.json rename to kclvm/tools/src/vet/test_datas/json/simple.k.json diff --git a/kclvm/tools/src/vet/test_datas/json/test.k.ast.json b/kclvm/tools/src/vet/test_datas/json/test.k.ast.json new file mode 100644 index 000000000..2669ed139 --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/json/test.k.ast.json @@ -0,0 +1,309 @@ +{ + "column": 0, + "end_column": 1, + "end_line": 12, + "filename": "/test.k.json", + "line": 1, + "node": { + "Schema": { + "args": [], + "config": { + "column": 0, + "end_column": 1, + "end_line": 12, + "filename": "/test.k.json", + "line": 1, + "node": { + "Config": { + "items": [ + { + "column": 0, + "end_column": 1, + "end_line": 12, + "filename": "/test.k.json", + "line": 1, + "node": { + "insert_index": -1, + "key": { + "column": 4, + "end_column": 13, + "end_line": 4, + "filename": "/test.k.json", + "line": 4, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"address\"", + "value": "address" + } + } + }, + "operation": "Union", + "value": { + "column": 15, + "end_column": 5, + "end_line": 7, + "filename": "/test.k.json", + "line": 4, + "node": { + "Config": { + "items": [ + { + "column": 15, + "end_column": 5, + "end_line": 7, + "filename": "/test.k.json", + "line": 4, + "node": { + "insert_index": -1, + "key": { + "column": 8, + "end_column": 14, + "end_line": 6, + "filename": "/test.k.json", + "line": 6, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"city\"", + "value": "city" + } + } + }, + "operation": "Union", + "value": { + "column": 16, + "end_column": 24, + "end_line": 6, + "filename": "/test.k.json", + "line": 6, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"London\"", + "value": "London" + } + } + } + } + }, + { + "column": 15, + "end_column": 5, + "end_line": 7, + "filename": "/test.k.json", + "line": 4, + "node": { + "insert_index": -1, + "key": { + "column": 8, + "end_column": 16, + "end_line": 5, + "filename": "/test.k.json", + "line": 5, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"street\"", + "value": "street" + } + } + }, + "operation": "Union", + "value": { + "column": 18, + "end_column": 37, + "end_line": 5, + "filename": "/test.k.json", + "line": 5, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"10 Downing Street\"", + "value": "10 Downing Street" + } + } + } + } + } + ] + } + } + } + } + }, + { + "column": 0, + "end_column": 1, + "end_line": 12, + "filename": "/test.k.json", + "line": 1, + "node": { + "insert_index": -1, + "key": { + "column": 4, + "end_column": 9, + "end_line": 3, + "filename": "/test.k.json", + "line": 3, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"age\"", + "value": "age" + } + } + }, + "operation": "Union", + "value": { + "column": 11, + "end_column": 13, + "end_line": 3, + "filename": "/test.k.json", + "line": 3, + "node": { + "NumberLit": { + "binary_suffix": null, + "value": { + "Int": 43 + } + } + } + } + } + }, + { + "column": 0, + "end_column": 1, + "end_line": 12, + "filename": "/test.k.json", + "line": 1, + "node": { + "insert_index": -1, + "key": { + "column": 4, + "end_column": 10, + "end_line": 2, + "filename": "/test.k.json", + "line": 2, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"name\"", + "value": "name" + } + } + }, + "operation": "Union", + "value": { + "column": 12, + "end_column": 22, + "end_line": 2, + "filename": "/test.k.json", + "line": 2, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"John Doe\"", + "value": "John Doe" + } + } + } + } + }, + { + "column": 0, + "end_column": 1, + "end_line": 12, + "filename": "/test.k.json", + "line": 1, + "node": { + "insert_index": -1, + "key": { + "column": 4, + "end_column": 12, + "end_line": 8, + "filename": "/test.k.json", + "line": 8, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"phones\"", + "value": "phones" + } + } + }, + "operation": "Union", + "value": { + "column": 14, + "end_column": 5, + "end_line": 11, + "filename": "/test.k.json", + "line": 8, + "node": { + "List": { + "ctx": "Load", + "elts": [ + { + "column": 8, + "end_column": 21, + "end_line": 9, + "filename": "/test.k.json", + "line": 9, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"+44 1234567\"", + "value": "+44 1234567" + } + } + }, + { + "column": 8, + "end_column": 21, + "end_line": 10, + "filename": "/test.k.json", + "line": 10, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"+44 2345678\"", + "value": "+44 2345678" + } + } + } + ] + } + } + } + } + } + ] + } + } + }, + "kwargs": [], + "name": { + "column": 0, + "end_column": 1, + "end_line": 12, + "filename": "/test.k.json", + "line": 1, + "node": { + "ctx": "Load", + "names": [ + { + "column": 0, + "end_column": 1, + "end_line": 12, + "filename": "/test.k.json", + "line": 1, + "node": "test" + } + ], + "pkgpath": "" + } + } + } + } +} \ No newline at end of file diff --git a/kclvm/tools/src/vet/test_datas/json/test.k.json b/kclvm/tools/src/vet/test_datas/json/test.k.json new file mode 100644 index 000000000..e02809804 --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/json/test.k.json @@ -0,0 +1,12 @@ +{ + "name": "John Doe", + "age": 43, + "address": { + "street": "10 Downing Street", + "city": "London" + }, + "phones": [ + "+44 1234567", + "+44 2345678" + ] +} diff --git a/kclvm/tools/src/vet/test_datas/json_str/complex.k.ast.json b/kclvm/tools/src/vet/test_datas/json_str/complex.k.ast.json new file mode 100644 index 000000000..77bb882b7 --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/json_str/complex.k.ast.json @@ -0,0 +1,443 @@ +{ + "column": 0, + "end_column": 1, + "end_line": 13, + "filename": "", + "line": 1, + "node": { + "Schema": { + "args": [], + "config": { + "column": 0, + "end_column": 1, + "end_line": 13, + "filename": "", + "line": 1, + "node": { + "Config": { + "items": [ + { + "column": 0, + "end_column": 1, + "end_line": 13, + "filename": "", + "line": 1, + "node": { + "insert_index": -1, + "key": { + "column": 4, + "end_column": 9, + "end_line": 3, + "filename": "", + "line": 3, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"age\"", + "value": "age" + } + } + }, + "operation": "Union", + "value": { + "column": 11, + "end_column": 13, + "end_line": 3, + "filename": "", + "line": 3, + "node": { + "NumberLit": { + "binary_suffix": null, + "value": { + "Int": 18 + } + } + } + } + } + }, + { + "column": 0, + "end_column": 1, + "end_line": 13, + "filename": "", + "line": 1, + "node": { + "insert_index": -1, + "key": { + "column": 4, + "end_column": 10, + "end_line": 5, + "filename": "", + "line": 5, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"data\"", + "value": "data" + } + } + }, + "operation": "Union", + "value": { + "column": 12, + "end_column": 5, + "end_line": 8, + "filename": "", + "line": 5, + "node": { + "Config": { + "items": [ + { + "column": 12, + "end_column": 5, + "end_line": 8, + "filename": "", + "line": 5, + "node": { + "insert_index": -1, + "key": { + "column": 8, + "end_column": 12, + "end_line": 6, + "filename": "", + "line": 6, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"id\"", + "value": "id" + } + } + }, + "operation": "Union", + "value": { + "column": 14, + "end_column": 15, + "end_line": 6, + "filename": "", + "line": 6, + "node": { + "NumberLit": { + "binary_suffix": null, + "value": { + "Int": 1 + } + } + } + } + } + }, + { + "column": 12, + "end_column": 5, + "end_line": 8, + "filename": "", + "line": 5, + "node": { + "insert_index": -1, + "key": { + "column": 8, + "end_column": 15, + "end_line": 7, + "filename": "", + "line": 7, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"value\"", + "value": "value" + } + } + }, + "operation": "Union", + "value": { + "column": 17, + "end_column": 25, + "end_line": 7, + "filename": "", + "line": 7, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"value1\"", + "value": "value1" + } + } + } + } + } + ] + } + } + } + } + }, + { + "column": 0, + "end_column": 1, + "end_line": 13, + "filename": "", + "line": 1, + "node": { + "insert_index": -1, + "key": { + "column": 4, + "end_column": 8, + "end_line": 12, + "filename": "", + "line": 12, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"hc\"", + "value": "hc" + } + } + }, + "operation": "Union", + "value": { + "column": 10, + "end_column": 19, + "end_line": 12, + "filename": "", + "line": 12, + "node": { + "List": { + "ctx": "Load", + "elts": [ + { + "column": 11, + "end_column": 12, + "end_line": 12, + "filename": "", + "line": 12, + "node": { + "NumberLit": { + "binary_suffix": null, + "value": { + "Int": 1 + } + } + } + }, + { + "column": 14, + "end_column": 15, + "end_line": 12, + "filename": "", + "line": 12, + "node": { + "NumberLit": { + "binary_suffix": null, + "value": { + "Int": 2 + } + } + } + }, + { + "column": 17, + "end_column": 18, + "end_line": 12, + "filename": "", + "line": 12, + "node": { + "NumberLit": { + "binary_suffix": null, + "value": { + "Int": 3 + } + } + } + } + ] + } + } + } + } + }, + { + "column": 0, + "end_column": 1, + "end_line": 13, + "filename": "", + "line": 1, + "node": { + "insert_index": -1, + "key": { + "column": 4, + "end_column": 12, + "end_line": 9, + "filename": "", + "line": 9, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"labels\"", + "value": "labels" + } + } + }, + "operation": "Union", + "value": { + "column": 14, + "end_column": 5, + "end_line": 11, + "filename": "", + "line": 9, + "node": { + "Config": { + "items": [ + { + "column": 14, + "end_column": 5, + "end_line": 11, + "filename": "", + "line": 9, + "node": { + "insert_index": -1, + "key": { + "column": 8, + "end_column": 13, + "end_line": 10, + "filename": "", + "line": 10, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"key\"", + "value": "key" + } + } + }, + "operation": "Union", + "value": { + "column": 15, + "end_column": 22, + "end_line": 10, + "filename": "", + "line": 10, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"value\"", + "value": "value" + } + } + } + } + } + ] + } + } + } + } + }, + { + "column": 0, + "end_column": 1, + "end_line": 13, + "filename": "", + "line": 1, + "node": { + "insert_index": -1, + "key": { + "column": 4, + "end_column": 13, + "end_line": 4, + "filename": "", + "line": 4, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"message\"", + "value": "message" + } + } + }, + "operation": "Union", + "value": { + "column": 15, + "end_column": 30, + "end_line": 4, + "filename": "", + "line": 4, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"This is Alice\"", + "value": "This is Alice" + } + } + } + } + }, + { + "column": 0, + "end_column": 1, + "end_line": 13, + "filename": "", + "line": 1, + "node": { + "insert_index": -1, + "key": { + "column": 4, + "end_column": 10, + "end_line": 2, + "filename": "", + "line": 2, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"name\"", + "value": "name" + } + } + }, + "operation": "Union", + "value": { + "column": 12, + "end_column": 19, + "end_line": 2, + "filename": "", + "line": 2, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"Alice\"", + "value": "Alice" + } + } + } + } + } + ] + } + } + }, + "kwargs": [], + "name": { + "column": 0, + "end_column": 1, + "end_line": 13, + "filename": "", + "line": 1, + "node": { + "ctx": "Load", + "names": [ + { + "column": 0, + "end_column": 1, + "end_line": 13, + "filename": "", + "line": 1, + "node": "complex" + } + ], + "pkgpath": "" + } + } + } + } +} \ No newline at end of file diff --git a/kclvm/tools/src/vet/test_datas/json_str/complex.k.json b/kclvm/tools/src/vet/test_datas/json_str/complex.k.json new file mode 100644 index 000000000..d3e9b575d --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/json_str/complex.k.json @@ -0,0 +1,13 @@ +{ + "name": "Alice", + "age": 18, + "message": "This is Alice", + "data": { + "id": 1, + "value": "value1" + }, + "labels": { + "key": "value" + }, + "hc": [1, 2, 3] +} diff --git a/kclvm/tools/src/vet/test_datas/json_str/list.k.ast.json b/kclvm/tools/src/vet/test_datas/json_str/list.k.ast.json new file mode 100644 index 000000000..8167b9857 --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/json_str/list.k.ast.json @@ -0,0 +1,179 @@ +{ + "column": 0, + "end_column": 1, + "end_line": 7, + "filename": "", + "line": 1, + "node": { + "List": { + "ctx": "Load", + "elts": [ + { + "column": 4, + "end_column": 5, + "end_line": 6, + "filename": "", + "line": 2, + "node": { + "Schema": { + "args": [], + "config": { + "column": 4, + "end_column": 5, + "end_line": 6, + "filename": "", + "line": 2, + "node": { + "Config": { + "items": [ + { + "column": 4, + "end_column": 5, + "end_line": 6, + "filename": "", + "line": 2, + "node": { + "insert_index": -1, + "key": { + "column": 8, + "end_column": 13, + "end_line": 4, + "filename": "", + "line": 4, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"age\"", + "value": "age" + } + } + }, + "operation": "Union", + "value": { + "column": 15, + "end_column": 17, + "end_line": 4, + "filename": "", + "line": 4, + "node": { + "NumberLit": { + "binary_suffix": null, + "value": { + "Int": 18 + } + } + } + } + } + }, + { + "column": 4, + "end_column": 5, + "end_line": 6, + "filename": "", + "line": 2, + "node": { + "insert_index": -1, + "key": { + "column": 8, + "end_column": 17, + "end_line": 5, + "filename": "", + "line": 5, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"message\"", + "value": "message" + } + } + }, + "operation": "Union", + "value": { + "column": 19, + "end_column": 34, + "end_line": 5, + "filename": "", + "line": 5, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"This is Alice\"", + "value": "This is Alice" + } + } + } + } + }, + { + "column": 4, + "end_column": 5, + "end_line": 6, + "filename": "", + "line": 2, + "node": { + "insert_index": -1, + "key": { + "column": 8, + "end_column": 14, + "end_line": 3, + "filename": "", + "line": 3, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"name\"", + "value": "name" + } + } + }, + "operation": "Union", + "value": { + "column": 16, + "end_column": 23, + "end_line": 3, + "filename": "", + "line": 3, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"Alice\"", + "value": "Alice" + } + } + } + } + } + ] + } + } + }, + "kwargs": [], + "name": { + "column": 4, + "end_column": 5, + "end_line": 6, + "filename": "", + "line": 2, + "node": { + "ctx": "Load", + "names": [ + { + "column": 4, + "end_column": 5, + "end_line": 6, + "filename": "", + "line": 2, + "node": "list" + } + ], + "pkgpath": "" + } + } + } + } + } + ] + } + } +} \ No newline at end of file diff --git a/kclvm/tools/src/vet/test_datas/json_str/list.k.json b/kclvm/tools/src/vet/test_datas/json_str/list.k.json new file mode 100644 index 000000000..b6f772ebe --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/json_str/list.k.json @@ -0,0 +1,7 @@ +[ + { + "name": "Alice", + "age": 18, + "message": "This is Alice" + } +] diff --git a/kclvm/tools/src/vet/test_datas/json_str/only_with_bool.ast.json b/kclvm/tools/src/vet/test_datas/json_str/only_with_bool.ast.json new file mode 100644 index 000000000..78a504fc7 --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/json_str/only_with_bool.ast.json @@ -0,0 +1,84 @@ +{ + "column": 0, + "end_column": 1, + "end_line": 3, + "filename": "", + "line": 1, + "node": { + "Schema": { + "args": [], + "config": { + "column": 0, + "end_column": 1, + "end_line": 3, + "filename": "", + "line": 1, + "node": { + "Config": { + "items": [ + { + "column": 0, + "end_column": 1, + "end_line": 3, + "filename": "", + "line": 1, + "node": { + "insert_index": -1, + "key": { + "column": 4, + "end_column": 10, + "end_line": 2, + "filename": "", + "line": 2, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"flag\"", + "value": "flag" + } + } + }, + "operation": "Union", + "value": { + "column": 12, + "end_column": 16, + "end_line": 2, + "filename": "", + "line": 2, + "node": { + "NameConstantLit": { + "value": "True" + } + } + } + } + } + ] + } + } + }, + "kwargs": [], + "name": { + "column": 0, + "end_column": 1, + "end_line": 3, + "filename": "", + "line": 1, + "node": { + "ctx": "Load", + "names": [ + { + "column": 0, + "end_column": 1, + "end_line": 3, + "filename": "", + "line": 1, + "node": "only_with_bool" + } + ], + "pkgpath": "" + } + } + } + } +} \ No newline at end of file diff --git a/kclvm/tools/src/vet/test_datas/json_str/only_with_bool.json b/kclvm/tools/src/vet/test_datas/json_str/only_with_bool.json new file mode 100644 index 000000000..ca087fd5f --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/json_str/only_with_bool.json @@ -0,0 +1,3 @@ +{ + "flag": true +} \ No newline at end of file diff --git a/kclvm/tools/src/vet/test_datas/json_str/only_with_float.ast.json b/kclvm/tools/src/vet/test_datas/json_str/only_with_float.ast.json new file mode 100644 index 000000000..d98c1a8ab --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/json_str/only_with_float.ast.json @@ -0,0 +1,87 @@ +{ + "column": 0, + "end_column": 1, + "end_line": 3, + "filename": "", + "line": 1, + "node": { + "Schema": { + "args": [], + "config": { + "column": 0, + "end_column": 1, + "end_line": 3, + "filename": "", + "line": 1, + "node": { + "Config": { + "items": [ + { + "column": 0, + "end_column": 1, + "end_line": 3, + "filename": "", + "line": 1, + "node": { + "insert_index": -1, + "key": { + "column": 4, + "end_column": 17, + "end_line": 2, + "filename": "", + "line": 2, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"float_value\"", + "value": "float_value" + } + } + }, + "operation": "Union", + "value": { + "column": 19, + "end_column": 23, + "end_line": 2, + "filename": "", + "line": 2, + "node": { + "NumberLit": { + "binary_suffix": null, + "value": { + "Float": 0.33 + } + } + } + } + } + } + ] + } + } + }, + "kwargs": [], + "name": { + "column": 0, + "end_column": 1, + "end_line": 3, + "filename": "", + "line": 1, + "node": { + "ctx": "Load", + "names": [ + { + "column": 0, + "end_column": 1, + "end_line": 3, + "filename": "", + "line": 1, + "node": "only_with_float" + } + ], + "pkgpath": "" + } + } + } + } +} \ No newline at end of file diff --git a/kclvm/tools/src/vet/test_datas/json_str/only_with_float.json b/kclvm/tools/src/vet/test_datas/json_str/only_with_float.json new file mode 100644 index 000000000..8f6133170 --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/json_str/only_with_float.json @@ -0,0 +1,3 @@ +{ + "float_value": 0.33 +} \ No newline at end of file diff --git a/kclvm/tools/src/vet/test_datas/json_str/only_with_null.ast.json b/kclvm/tools/src/vet/test_datas/json_str/only_with_null.ast.json new file mode 100644 index 000000000..04e2a4540 --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/json_str/only_with_null.ast.json @@ -0,0 +1,84 @@ +{ + "column": 0, + "end_column": 1, + "end_line": 3, + "filename": "", + "line": 1, + "node": { + "Schema": { + "args": [], + "config": { + "column": 0, + "end_column": 1, + "end_line": 3, + "filename": "", + "line": 1, + "node": { + "Config": { + "items": [ + { + "column": 0, + "end_column": 1, + "end_line": 3, + "filename": "", + "line": 1, + "node": { + "insert_index": -1, + "key": { + "column": 4, + "end_column": 16, + "end_line": 2, + "filename": "", + "line": 2, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"null_value\"", + "value": "null_value" + } + } + }, + "operation": "Union", + "value": { + "column": 18, + "end_column": 22, + "end_line": 2, + "filename": "", + "line": 2, + "node": { + "NameConstantLit": { + "value": "None" + } + } + } + } + } + ] + } + } + }, + "kwargs": [], + "name": { + "column": 0, + "end_column": 1, + "end_line": 3, + "filename": "", + "line": 1, + "node": { + "ctx": "Load", + "names": [ + { + "column": 0, + "end_column": 1, + "end_line": 3, + "filename": "", + "line": 1, + "node": "only_with_null" + } + ], + "pkgpath": "" + } + } + } + } +} \ No newline at end of file diff --git a/kclvm/tools/src/vet/test_datas/json_str/only_with_null.json b/kclvm/tools/src/vet/test_datas/json_str/only_with_null.json new file mode 100644 index 000000000..0578d4d6e --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/json_str/only_with_null.json @@ -0,0 +1,3 @@ +{ + "null_value": null +} \ No newline at end of file diff --git a/kclvm/tools/src/vet/test_datas/json_str/plain_value.k.ast.json b/kclvm/tools/src/vet/test_datas/json_str/plain_value.k.ast.json new file mode 100644 index 000000000..3d322f34f --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/json_str/plain_value.k.ast.json @@ -0,0 +1,15 @@ +{ + "column": 0, + "end_column": 1, + "end_line": 1, + "filename": "", + "line": 1, + "node": { + "NumberLit": { + "binary_suffix": null, + "value": { + "Int": 1 + } + } + } +} \ No newline at end of file diff --git a/kclvm/tools/src/vet/test_datas/json_str/plain_value.k.json b/kclvm/tools/src/vet/test_datas/json_str/plain_value.k.json new file mode 100644 index 000000000..d00491fd7 --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/json_str/plain_value.k.json @@ -0,0 +1 @@ +1 diff --git a/kclvm/tools/src/vet/test_datas/json_str/simple.k.ast.json b/kclvm/tools/src/vet/test_datas/json_str/simple.k.ast.json new file mode 100644 index 000000000..373b8a71b --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/json_str/simple.k.ast.json @@ -0,0 +1,165 @@ +{ + "column": 0, + "end_column": 1, + "end_line": 5, + "filename": "", + "line": 1, + "node": { + "Schema": { + "args": [], + "config": { + "column": 0, + "end_column": 1, + "end_line": 5, + "filename": "", + "line": 1, + "node": { + "Config": { + "items": [ + { + "column": 0, + "end_column": 1, + "end_line": 5, + "filename": "", + "line": 1, + "node": { + "insert_index": -1, + "key": { + "column": 4, + "end_column": 9, + "end_line": 3, + "filename": "", + "line": 3, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"age\"", + "value": "age" + } + } + }, + "operation": "Union", + "value": { + "column": 11, + "end_column": 13, + "end_line": 3, + "filename": "", + "line": 3, + "node": { + "NumberLit": { + "binary_suffix": null, + "value": { + "Int": 18 + } + } + } + } + } + }, + { + "column": 0, + "end_column": 1, + "end_line": 5, + "filename": "", + "line": 1, + "node": { + "insert_index": -1, + "key": { + "column": 4, + "end_column": 13, + "end_line": 4, + "filename": "", + "line": 4, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"message\"", + "value": "message" + } + } + }, + "operation": "Union", + "value": { + "column": 15, + "end_column": 30, + "end_line": 4, + "filename": "", + "line": 4, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"This is Alice\"", + "value": "This is Alice" + } + } + } + } + }, + { + "column": 0, + "end_column": 1, + "end_line": 5, + "filename": "", + "line": 1, + "node": { + "insert_index": -1, + "key": { + "column": 4, + "end_column": 10, + "end_line": 2, + "filename": "", + "line": 2, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"name\"", + "value": "name" + } + } + }, + "operation": "Union", + "value": { + "column": 12, + "end_column": 19, + "end_line": 2, + "filename": "", + "line": 2, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"Alice\"", + "value": "Alice" + } + } + } + } + } + ] + } + } + }, + "kwargs": [], + "name": { + "column": 0, + "end_column": 1, + "end_line": 5, + "filename": "", + "line": 1, + "node": { + "ctx": "Load", + "names": [ + { + "column": 0, + "end_column": 1, + "end_line": 5, + "filename": "", + "line": 1, + "node": "simple" + } + ], + "pkgpath": "" + } + } + } + } +} \ No newline at end of file diff --git a/kclvm/tools/src/vet/test_datas/json_str/simple.k.json b/kclvm/tools/src/vet/test_datas/json_str/simple.k.json new file mode 100644 index 000000000..02fd725d1 --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/json_str/simple.k.json @@ -0,0 +1,5 @@ +{ + "name": "Alice", + "age": 18, + "message": "This is Alice" +} diff --git a/kclvm/tools/src/vet/test_datas/json_str/test.k.ast.json b/kclvm/tools/src/vet/test_datas/json_str/test.k.ast.json new file mode 100644 index 000000000..46dfd3472 --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/json_str/test.k.ast.json @@ -0,0 +1,309 @@ +{ + "column": 0, + "end_column": 1, + "end_line": 12, + "filename": "", + "line": 1, + "node": { + "Schema": { + "args": [], + "config": { + "column": 0, + "end_column": 1, + "end_line": 12, + "filename": "", + "line": 1, + "node": { + "Config": { + "items": [ + { + "column": 0, + "end_column": 1, + "end_line": 12, + "filename": "", + "line": 1, + "node": { + "insert_index": -1, + "key": { + "column": 4, + "end_column": 13, + "end_line": 4, + "filename": "", + "line": 4, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"address\"", + "value": "address" + } + } + }, + "operation": "Union", + "value": { + "column": 15, + "end_column": 5, + "end_line": 7, + "filename": "", + "line": 4, + "node": { + "Config": { + "items": [ + { + "column": 15, + "end_column": 5, + "end_line": 7, + "filename": "", + "line": 4, + "node": { + "insert_index": -1, + "key": { + "column": 8, + "end_column": 14, + "end_line": 6, + "filename": "", + "line": 6, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"city\"", + "value": "city" + } + } + }, + "operation": "Union", + "value": { + "column": 16, + "end_column": 24, + "end_line": 6, + "filename": "", + "line": 6, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"London\"", + "value": "London" + } + } + } + } + }, + { + "column": 15, + "end_column": 5, + "end_line": 7, + "filename": "", + "line": 4, + "node": { + "insert_index": -1, + "key": { + "column": 8, + "end_column": 16, + "end_line": 5, + "filename": "", + "line": 5, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"street\"", + "value": "street" + } + } + }, + "operation": "Union", + "value": { + "column": 18, + "end_column": 37, + "end_line": 5, + "filename": "", + "line": 5, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"10 Downing Street\"", + "value": "10 Downing Street" + } + } + } + } + } + ] + } + } + } + } + }, + { + "column": 0, + "end_column": 1, + "end_line": 12, + "filename": "", + "line": 1, + "node": { + "insert_index": -1, + "key": { + "column": 4, + "end_column": 9, + "end_line": 3, + "filename": "", + "line": 3, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"age\"", + "value": "age" + } + } + }, + "operation": "Union", + "value": { + "column": 11, + "end_column": 13, + "end_line": 3, + "filename": "", + "line": 3, + "node": { + "NumberLit": { + "binary_suffix": null, + "value": { + "Int": 43 + } + } + } + } + } + }, + { + "column": 0, + "end_column": 1, + "end_line": 12, + "filename": "", + "line": 1, + "node": { + "insert_index": -1, + "key": { + "column": 4, + "end_column": 10, + "end_line": 2, + "filename": "", + "line": 2, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"name\"", + "value": "name" + } + } + }, + "operation": "Union", + "value": { + "column": 12, + "end_column": 22, + "end_line": 2, + "filename": "", + "line": 2, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"John Doe\"", + "value": "John Doe" + } + } + } + } + }, + { + "column": 0, + "end_column": 1, + "end_line": 12, + "filename": "", + "line": 1, + "node": { + "insert_index": -1, + "key": { + "column": 4, + "end_column": 12, + "end_line": 8, + "filename": "", + "line": 8, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"phones\"", + "value": "phones" + } + } + }, + "operation": "Union", + "value": { + "column": 14, + "end_column": 5, + "end_line": 11, + "filename": "", + "line": 8, + "node": { + "List": { + "ctx": "Load", + "elts": [ + { + "column": 8, + "end_column": 21, + "end_line": 9, + "filename": "", + "line": 9, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"+44 1234567\"", + "value": "+44 1234567" + } + } + }, + { + "column": 8, + "end_column": 21, + "end_line": 10, + "filename": "", + "line": 10, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"+44 2345678\"", + "value": "+44 2345678" + } + } + } + ] + } + } + } + } + } + ] + } + } + }, + "kwargs": [], + "name": { + "column": 0, + "end_column": 1, + "end_line": 12, + "filename": "", + "line": 1, + "node": { + "ctx": "Load", + "names": [ + { + "column": 0, + "end_column": 1, + "end_line": 12, + "filename": "", + "line": 1, + "node": "test" + } + ], + "pkgpath": "" + } + } + } + } +} \ No newline at end of file diff --git a/kclvm/tools/src/vet/test_datas/json_str/test.k.json b/kclvm/tools/src/vet/test_datas/json_str/test.k.json new file mode 100644 index 000000000..e02809804 --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/json_str/test.k.json @@ -0,0 +1,12 @@ +{ + "name": "John Doe", + "age": 43, + "address": { + "street": "10 Downing Street", + "city": "London" + }, + "phones": [ + "+44 1234567", + "+44 2345678" + ] +} diff --git a/kclvm/tools/src/vet/test_datas/json_str_win/complex.k.ast.json b/kclvm/tools/src/vet/test_datas/json_str_win/complex.k.ast.json new file mode 100644 index 000000000..8da01354f --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/json_str_win/complex.k.ast.json @@ -0,0 +1,443 @@ +{ + "column": 0, + "end_column": 13, + "end_line": 13, + "filename": "", + "line": 1, + "node": { + "Schema": { + "args": [], + "config": { + "column": 0, + "end_column": 13, + "end_line": 13, + "filename": "", + "line": 1, + "node": { + "Config": { + "items": [ + { + "column": 0, + "end_column": 13, + "end_line": 13, + "filename": "", + "line": 1, + "node": { + "insert_index": -1, + "key": { + "column": 6, + "end_column": 11, + "end_line": 3, + "filename": "", + "line": 3, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"age\"", + "value": "age" + } + } + }, + "operation": "Union", + "value": { + "column": 13, + "end_column": 0, + "end_line": 4, + "filename": "", + "line": 3, + "node": { + "NumberLit": { + "binary_suffix": null, + "value": { + "Int": 18 + } + } + } + } + } + }, + { + "column": 0, + "end_column": 13, + "end_line": 13, + "filename": "", + "line": 1, + "node": { + "insert_index": -1, + "key": { + "column": 8, + "end_column": 0, + "end_line": 6, + "filename": "", + "line": 5, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"data\"", + "value": "data" + } + } + }, + "operation": "Union", + "value": { + "column": 2, + "end_column": 5, + "end_line": 9, + "filename": "", + "line": 6, + "node": { + "Config": { + "items": [ + { + "column": 2, + "end_column": 5, + "end_line": 9, + "filename": "", + "line": 6, + "node": { + "insert_index": -1, + "key": { + "column": 13, + "end_column": 0, + "end_line": 7, + "filename": "", + "line": 6, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"id\"", + "value": "id" + } + } + }, + "operation": "Union", + "value": { + "column": 2, + "end_column": 3, + "end_line": 7, + "filename": "", + "line": 7, + "node": { + "NumberLit": { + "binary_suffix": null, + "value": { + "Int": 1 + } + } + } + } + } + }, + { + "column": 2, + "end_column": 5, + "end_line": 9, + "filename": "", + "line": 6, + "node": { + "insert_index": -1, + "key": { + "column": 14, + "end_column": 21, + "end_line": 7, + "filename": "", + "line": 7, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"value\"", + "value": "value" + } + } + }, + "operation": "Union", + "value": { + "column": 23, + "end_column": 5, + "end_line": 8, + "filename": "", + "line": 7, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"value1\"", + "value": "value1" + } + } + } + } + } + ] + } + } + } + } + }, + { + "column": 0, + "end_column": 13, + "end_line": 13, + "filename": "", + "line": 1, + "node": { + "insert_index": -1, + "key": { + "column": 15, + "end_column": 19, + "end_line": 12, + "filename": "", + "line": 12, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"hc\"", + "value": "hc" + } + } + }, + "operation": "Union", + "value": { + "column": 1, + "end_column": 10, + "end_line": 13, + "filename": "", + "line": 13, + "node": { + "List": { + "ctx": "Load", + "elts": [ + { + "column": 2, + "end_column": 3, + "end_line": 13, + "filename": "", + "line": 13, + "node": { + "NumberLit": { + "binary_suffix": null, + "value": { + "Int": 1 + } + } + } + }, + { + "column": 5, + "end_column": 6, + "end_line": 13, + "filename": "", + "line": 13, + "node": { + "NumberLit": { + "binary_suffix": null, + "value": { + "Int": 2 + } + } + } + }, + { + "column": 8, + "end_column": 9, + "end_line": 13, + "filename": "", + "line": 13, + "node": { + "NumberLit": { + "binary_suffix": null, + "value": { + "Int": 3 + } + } + } + } + ] + } + } + } + } + }, + { + "column": 0, + "end_column": 13, + "end_line": 13, + "filename": "", + "line": 1, + "node": { + "insert_index": -1, + "key": { + "column": 12, + "end_column": 4, + "end_line": 10, + "filename": "", + "line": 9, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"labels\"", + "value": "labels" + } + } + }, + "operation": "Union", + "value": { + "column": 6, + "end_column": 8, + "end_line": 12, + "filename": "", + "line": 10, + "node": { + "Config": { + "items": [ + { + "column": 6, + "end_column": 8, + "end_line": 12, + "filename": "", + "line": 10, + "node": { + "insert_index": -1, + "key": { + "column": 17, + "end_column": 22, + "end_line": 10, + "filename": "", + "line": 10, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"key\"", + "value": "key" + } + } + }, + "operation": "Union", + "value": { + "column": 1, + "end_column": 1, + "end_line": 12, + "filename": "", + "line": 11, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"value\"", + "value": "value" + } + } + } + } + } + ] + } + } + } + } + }, + { + "column": 0, + "end_column": 13, + "end_line": 13, + "filename": "", + "line": 1, + "node": { + "insert_index": -1, + "key": { + "column": 7, + "end_column": 16, + "end_line": 4, + "filename": "", + "line": 4, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"message\"", + "value": "message" + } + } + }, + "operation": "Union", + "value": { + "column": 18, + "end_column": 1, + "end_line": 5, + "filename": "", + "line": 4, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"This is Alice\"", + "value": "This is Alice" + } + } + } + } + }, + { + "column": 0, + "end_column": 13, + "end_line": 13, + "filename": "", + "line": 1, + "node": { + "insert_index": -1, + "key": { + "column": 5, + "end_column": 11, + "end_line": 2, + "filename": "", + "line": 2, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"name\"", + "value": "name" + } + } + }, + "operation": "Union", + "value": { + "column": 13, + "end_column": 20, + "end_line": 2, + "filename": "", + "line": 2, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"Alice\"", + "value": "Alice" + } + } + } + } + } + ] + } + } + }, + "kwargs": [], + "name": { + "column": 0, + "end_column": 13, + "end_line": 13, + "filename": "", + "line": 1, + "node": { + "ctx": "Load", + "names": [ + { + "column": 0, + "end_column": 13, + "end_line": 13, + "filename": "", + "line": 1, + "node": "complex" + } + ], + "pkgpath": "" + } + } + } + } +} \ No newline at end of file diff --git a/kclvm/tools/src/vet/test_datas/json_str_win/complex.k.json b/kclvm/tools/src/vet/test_datas/json_str_win/complex.k.json new file mode 100644 index 000000000..d3e9b575d --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/json_str_win/complex.k.json @@ -0,0 +1,13 @@ +{ + "name": "Alice", + "age": 18, + "message": "This is Alice", + "data": { + "id": 1, + "value": "value1" + }, + "labels": { + "key": "value" + }, + "hc": [1, 2, 3] +} diff --git a/kclvm/tools/src/vet/test_datas/json_str_win/list.k.ast.json b/kclvm/tools/src/vet/test_datas/json_str_win/list.k.ast.json new file mode 100644 index 000000000..17925c434 --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/json_str_win/list.k.ast.json @@ -0,0 +1,179 @@ +{ + "column": 0, + "end_column": 7, + "end_line": 7, + "filename": "", + "line": 1, + "node": { + "List": { + "ctx": "Load", + "elts": [ + { + "column": 5, + "end_column": 4, + "end_line": 7, + "filename": "", + "line": 2, + "node": { + "Schema": { + "args": [], + "config": { + "column": 5, + "end_column": 4, + "end_line": 7, + "filename": "", + "line": 2, + "node": { + "Config": { + "items": [ + { + "column": 5, + "end_column": 4, + "end_line": 7, + "filename": "", + "line": 2, + "node": { + "insert_index": -1, + "key": { + "column": 11, + "end_column": 16, + "end_line": 4, + "filename": "", + "line": 4, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"age\"", + "value": "age" + } + } + }, + "operation": "Union", + "value": { + "column": 18, + "end_column": 1, + "end_line": 5, + "filename": "", + "line": 4, + "node": { + "NumberLit": { + "binary_suffix": null, + "value": { + "Int": 18 + } + } + } + } + } + }, + { + "column": 5, + "end_column": 4, + "end_line": 7, + "filename": "", + "line": 2, + "node": { + "insert_index": -1, + "key": { + "column": 12, + "end_column": 21, + "end_line": 5, + "filename": "", + "line": 5, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"message\"", + "value": "message" + } + } + }, + "operation": "Union", + "value": { + "column": 23, + "end_column": 3, + "end_line": 6, + "filename": "", + "line": 5, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"This is Alice\"", + "value": "This is Alice" + } + } + } + } + }, + { + "column": 5, + "end_column": 4, + "end_line": 7, + "filename": "", + "line": 2, + "node": { + "insert_index": -1, + "key": { + "column": 10, + "end_column": 16, + "end_line": 3, + "filename": "", + "line": 3, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"name\"", + "value": "name" + } + } + }, + "operation": "Union", + "value": { + "column": 18, + "end_column": 0, + "end_line": 4, + "filename": "", + "line": 3, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"Alice\"", + "value": "Alice" + } + } + } + } + } + ] + } + } + }, + "kwargs": [], + "name": { + "column": 5, + "end_column": 4, + "end_line": 7, + "filename": "", + "line": 2, + "node": { + "ctx": "Load", + "names": [ + { + "column": 5, + "end_column": 4, + "end_line": 7, + "filename": "", + "line": 2, + "node": "list" + } + ], + "pkgpath": "" + } + } + } + } + } + ] + } + } +} \ No newline at end of file diff --git a/kclvm/tools/src/vet/test_datas/json_str_win/list.k.json b/kclvm/tools/src/vet/test_datas/json_str_win/list.k.json new file mode 100644 index 000000000..b6f772ebe --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/json_str_win/list.k.json @@ -0,0 +1,7 @@ +[ + { + "name": "Alice", + "age": 18, + "message": "This is Alice" + } +] diff --git a/kclvm/tools/src/vet/test_datas/json_str_win/only_with_bool.ast.json b/kclvm/tools/src/vet/test_datas/json_str_win/only_with_bool.ast.json new file mode 100644 index 000000000..4794707cf --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/json_str_win/only_with_bool.ast.json @@ -0,0 +1,84 @@ +{ + "column": 0, + "end_column": 3, + "end_line": 3, + "filename": "", + "line": 1, + "node": { + "Schema": { + "args": [], + "config": { + "column": 0, + "end_column": 3, + "end_line": 3, + "filename": "", + "line": 1, + "node": { + "Config": { + "items": [ + { + "column": 0, + "end_column": 3, + "end_line": 3, + "filename": "", + "line": 1, + "node": { + "insert_index": -1, + "key": { + "column": 5, + "end_column": 11, + "end_line": 2, + "filename": "", + "line": 2, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"flag\"", + "value": "flag" + } + } + }, + "operation": "Union", + "value": { + "column": 13, + "end_column": 0, + "end_line": 3, + "filename": "", + "line": 2, + "node": { + "NameConstantLit": { + "value": "True" + } + } + } + } + } + ] + } + } + }, + "kwargs": [], + "name": { + "column": 0, + "end_column": 3, + "end_line": 3, + "filename": "", + "line": 1, + "node": { + "ctx": "Load", + "names": [ + { + "column": 0, + "end_column": 3, + "end_line": 3, + "filename": "", + "line": 1, + "node": "only_with_bool" + } + ], + "pkgpath": "" + } + } + } + } +} \ No newline at end of file diff --git a/kclvm/tools/src/vet/test_datas/json_str_win/only_with_bool.json b/kclvm/tools/src/vet/test_datas/json_str_win/only_with_bool.json new file mode 100644 index 000000000..ca087fd5f --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/json_str_win/only_with_bool.json @@ -0,0 +1,3 @@ +{ + "flag": true +} \ No newline at end of file diff --git a/kclvm/tools/src/vet/test_datas/json_str_win/only_with_float.ast.json b/kclvm/tools/src/vet/test_datas/json_str_win/only_with_float.ast.json new file mode 100644 index 000000000..4efc9d4e1 --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/json_str_win/only_with_float.ast.json @@ -0,0 +1,87 @@ +{ + "column": 0, + "end_column": 3, + "end_line": 3, + "filename": "", + "line": 1, + "node": { + "Schema": { + "args": [], + "config": { + "column": 0, + "end_column": 3, + "end_line": 3, + "filename": "", + "line": 1, + "node": { + "Config": { + "items": [ + { + "column": 0, + "end_column": 3, + "end_line": 3, + "filename": "", + "line": 1, + "node": { + "insert_index": -1, + "key": { + "column": 5, + "end_column": 18, + "end_line": 2, + "filename": "", + "line": 2, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"float_value\"", + "value": "float_value" + } + } + }, + "operation": "Union", + "value": { + "column": 20, + "end_column": 0, + "end_line": 3, + "filename": "", + "line": 2, + "node": { + "NumberLit": { + "binary_suffix": null, + "value": { + "Float": 0.33 + } + } + } + } + } + } + ] + } + } + }, + "kwargs": [], + "name": { + "column": 0, + "end_column": 3, + "end_line": 3, + "filename": "", + "line": 1, + "node": { + "ctx": "Load", + "names": [ + { + "column": 0, + "end_column": 3, + "end_line": 3, + "filename": "", + "line": 1, + "node": "only_with_float" + } + ], + "pkgpath": "" + } + } + } + } +} \ No newline at end of file diff --git a/kclvm/tools/src/vet/test_datas/json_str_win/only_with_float.json b/kclvm/tools/src/vet/test_datas/json_str_win/only_with_float.json new file mode 100644 index 000000000..8f6133170 --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/json_str_win/only_with_float.json @@ -0,0 +1,3 @@ +{ + "float_value": 0.33 +} \ No newline at end of file diff --git a/kclvm/tools/src/vet/test_datas/json_str_win/only_with_null.ast.json b/kclvm/tools/src/vet/test_datas/json_str_win/only_with_null.ast.json new file mode 100644 index 000000000..e7d0f16df --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/json_str_win/only_with_null.ast.json @@ -0,0 +1,84 @@ +{ + "column": 0, + "end_column": 3, + "end_line": 3, + "filename": "", + "line": 1, + "node": { + "Schema": { + "args": [], + "config": { + "column": 0, + "end_column": 3, + "end_line": 3, + "filename": "", + "line": 1, + "node": { + "Config": { + "items": [ + { + "column": 0, + "end_column": 3, + "end_line": 3, + "filename": "", + "line": 1, + "node": { + "insert_index": -1, + "key": { + "column": 5, + "end_column": 17, + "end_line": 2, + "filename": "", + "line": 2, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"null_value\"", + "value": "null_value" + } + } + }, + "operation": "Union", + "value": { + "column": 19, + "end_column": 0, + "end_line": 3, + "filename": "", + "line": 2, + "node": { + "NameConstantLit": { + "value": "None" + } + } + } + } + } + ] + } + } + }, + "kwargs": [], + "name": { + "column": 0, + "end_column": 3, + "end_line": 3, + "filename": "", + "line": 1, + "node": { + "ctx": "Load", + "names": [ + { + "column": 0, + "end_column": 3, + "end_line": 3, + "filename": "", + "line": 1, + "node": "only_with_null" + } + ], + "pkgpath": "" + } + } + } + } +} \ No newline at end of file diff --git a/kclvm/tools/src/vet/test_datas/json_str_win/only_with_null.json b/kclvm/tools/src/vet/test_datas/json_str_win/only_with_null.json new file mode 100644 index 000000000..0578d4d6e --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/json_str_win/only_with_null.json @@ -0,0 +1,3 @@ +{ + "null_value": null +} \ No newline at end of file diff --git a/kclvm/tools/src/vet/test_datas/json_str_win/plain_value.k.ast.json b/kclvm/tools/src/vet/test_datas/json_str_win/plain_value.k.ast.json new file mode 100644 index 000000000..3d322f34f --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/json_str_win/plain_value.k.ast.json @@ -0,0 +1,15 @@ +{ + "column": 0, + "end_column": 1, + "end_line": 1, + "filename": "", + "line": 1, + "node": { + "NumberLit": { + "binary_suffix": null, + "value": { + "Int": 1 + } + } + } +} \ No newline at end of file diff --git a/kclvm/tools/src/vet/test_datas/json_str_win/plain_value.k.json b/kclvm/tools/src/vet/test_datas/json_str_win/plain_value.k.json new file mode 100644 index 000000000..d00491fd7 --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/json_str_win/plain_value.k.json @@ -0,0 +1 @@ +1 diff --git a/kclvm/tools/src/vet/test_datas/json_str_win/simple.k.ast.json b/kclvm/tools/src/vet/test_datas/json_str_win/simple.k.ast.json new file mode 100644 index 000000000..bf2c6061d --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/json_str_win/simple.k.ast.json @@ -0,0 +1,165 @@ +{ + "column": 0, + "end_column": 5, + "end_line": 5, + "filename": "", + "line": 1, + "node": { + "Schema": { + "args": [], + "config": { + "column": 0, + "end_column": 5, + "end_line": 5, + "filename": "", + "line": 1, + "node": { + "Config": { + "items": [ + { + "column": 0, + "end_column": 5, + "end_line": 5, + "filename": "", + "line": 1, + "node": { + "insert_index": -1, + "key": { + "column": 6, + "end_column": 11, + "end_line": 3, + "filename": "", + "line": 3, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"age\"", + "value": "age" + } + } + }, + "operation": "Union", + "value": { + "column": 13, + "end_column": 0, + "end_line": 4, + "filename": "", + "line": 3, + "node": { + "NumberLit": { + "binary_suffix": null, + "value": { + "Int": 18 + } + } + } + } + } + }, + { + "column": 0, + "end_column": 5, + "end_line": 5, + "filename": "", + "line": 1, + "node": { + "insert_index": -1, + "key": { + "column": 7, + "end_column": 16, + "end_line": 4, + "filename": "", + "line": 4, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"message\"", + "value": "message" + } + } + }, + "operation": "Union", + "value": { + "column": 18, + "end_column": 2, + "end_line": 5, + "filename": "", + "line": 4, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"This is Alice\"", + "value": "This is Alice" + } + } + } + } + }, + { + "column": 0, + "end_column": 5, + "end_line": 5, + "filename": "", + "line": 1, + "node": { + "insert_index": -1, + "key": { + "column": 5, + "end_column": 11, + "end_line": 2, + "filename": "", + "line": 2, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"name\"", + "value": "name" + } + } + }, + "operation": "Union", + "value": { + "column": 13, + "end_column": 20, + "end_line": 2, + "filename": "", + "line": 2, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"Alice\"", + "value": "Alice" + } + } + } + } + } + ] + } + } + }, + "kwargs": [], + "name": { + "column": 0, + "end_column": 5, + "end_line": 5, + "filename": "", + "line": 1, + "node": { + "ctx": "Load", + "names": [ + { + "column": 0, + "end_column": 5, + "end_line": 5, + "filename": "", + "line": 1, + "node": "simple" + } + ], + "pkgpath": "" + } + } + } + } +} \ No newline at end of file diff --git a/kclvm/tools/src/vet/test_datas/json_str_win/simple.k.json b/kclvm/tools/src/vet/test_datas/json_str_win/simple.k.json new file mode 100644 index 000000000..02fd725d1 --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/json_str_win/simple.k.json @@ -0,0 +1,5 @@ +{ + "name": "Alice", + "age": 18, + "message": "This is Alice" +} diff --git a/kclvm/tools/src/vet/test_datas/json_str_win/test.k.ast.json b/kclvm/tools/src/vet/test_datas/json_str_win/test.k.ast.json new file mode 100644 index 000000000..94fbde486 --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/json_str_win/test.k.ast.json @@ -0,0 +1,309 @@ +{ + "column": 0, + "end_column": 12, + "end_line": 12, + "filename": "", + "line": 1, + "node": { + "Schema": { + "args": [], + "config": { + "column": 0, + "end_column": 12, + "end_line": 12, + "filename": "", + "line": 1, + "node": { + "Config": { + "items": [ + { + "column": 0, + "end_column": 12, + "end_line": 12, + "filename": "", + "line": 1, + "node": { + "insert_index": -1, + "key": { + "column": 7, + "end_column": 16, + "end_line": 4, + "filename": "", + "line": 4, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"address\"", + "value": "address" + } + } + }, + "operation": "Union", + "value": { + "column": 1, + "end_column": 4, + "end_line": 8, + "filename": "", + "line": 5, + "node": { + "Config": { + "items": [ + { + "column": 1, + "end_column": 4, + "end_line": 8, + "filename": "", + "line": 5, + "node": { + "insert_index": -1, + "key": { + "column": 13, + "end_column": 19, + "end_line": 6, + "filename": "", + "line": 6, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"city\"", + "value": "city" + } + } + }, + "operation": "Union", + "value": { + "column": 21, + "end_column": 4, + "end_line": 7, + "filename": "", + "line": 6, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"London\"", + "value": "London" + } + } + } + } + }, + { + "column": 1, + "end_column": 4, + "end_line": 8, + "filename": "", + "line": 5, + "node": { + "insert_index": -1, + "key": { + "column": 12, + "end_column": 20, + "end_line": 5, + "filename": "", + "line": 5, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"street\"", + "value": "street" + } + } + }, + "operation": "Union", + "value": { + "column": 22, + "end_column": 2, + "end_line": 6, + "filename": "", + "line": 5, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"10 Downing Street\"", + "value": "10 Downing Street" + } + } + } + } + } + ] + } + } + } + } + }, + { + "column": 0, + "end_column": 12, + "end_line": 12, + "filename": "", + "line": 1, + "node": { + "insert_index": -1, + "key": { + "column": 6, + "end_column": 11, + "end_line": 3, + "filename": "", + "line": 3, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"age\"", + "value": "age" + } + } + }, + "operation": "Union", + "value": { + "column": 13, + "end_column": 0, + "end_line": 4, + "filename": "", + "line": 3, + "node": { + "NumberLit": { + "binary_suffix": null, + "value": { + "Int": 43 + } + } + } + } + } + }, + { + "column": 0, + "end_column": 12, + "end_line": 12, + "filename": "", + "line": 1, + "node": { + "insert_index": -1, + "key": { + "column": 5, + "end_column": 11, + "end_line": 2, + "filename": "", + "line": 2, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"name\"", + "value": "name" + } + } + }, + "operation": "Union", + "value": { + "column": 13, + "end_column": 23, + "end_line": 2, + "filename": "", + "line": 2, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"John Doe\"", + "value": "John Doe" + } + } + } + } + }, + { + "column": 0, + "end_column": 12, + "end_line": 12, + "filename": "", + "line": 1, + "node": { + "insert_index": -1, + "key": { + "column": 11, + "end_column": 3, + "end_line": 9, + "filename": "", + "line": 8, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"phones\"", + "value": "phones" + } + } + }, + "operation": "Union", + "value": { + "column": 5, + "end_column": 9, + "end_line": 12, + "filename": "", + "line": 9, + "node": { + "List": { + "ctx": "Load", + "elts": [ + { + "column": 16, + "end_column": 6, + "end_line": 10, + "filename": "", + "line": 9, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"+44 1234567\"", + "value": "+44 1234567" + } + } + }, + { + "column": 17, + "end_column": 2, + "end_line": 12, + "filename": "", + "line": 10, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"+44 2345678\"", + "value": "+44 2345678" + } + } + } + ] + } + } + } + } + } + ] + } + } + }, + "kwargs": [], + "name": { + "column": 0, + "end_column": 12, + "end_line": 12, + "filename": "", + "line": 1, + "node": { + "ctx": "Load", + "names": [ + { + "column": 0, + "end_column": 12, + "end_line": 12, + "filename": "", + "line": 1, + "node": "test" + } + ], + "pkgpath": "" + } + } + } + } +} \ No newline at end of file diff --git a/kclvm/tools/src/vet/test_datas/json_str_win/test.k.json b/kclvm/tools/src/vet/test_datas/json_str_win/test.k.json new file mode 100644 index 000000000..e02809804 --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/json_str_win/test.k.json @@ -0,0 +1,12 @@ +{ + "name": "John Doe", + "age": 43, + "address": { + "street": "10 Downing Street", + "city": "London" + }, + "phones": [ + "+44 1234567", + "+44 2345678" + ] +} diff --git a/kclvm/tools/src/vet/test_datas/json_win/complex.k.ast.json b/kclvm/tools/src/vet/test_datas/json_win/complex.k.ast.json new file mode 100644 index 000000000..ecce3da6a --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/json_win/complex.k.ast.json @@ -0,0 +1,443 @@ +{ + "column": 0, + "end_column": 13, + "end_line": 13, + "filename": "/complex.k.json", + "line": 1, + "node": { + "Schema": { + "args": [], + "config": { + "column": 0, + "end_column": 13, + "end_line": 13, + "filename": "/complex.k.json", + "line": 1, + "node": { + "Config": { + "items": [ + { + "column": 0, + "end_column": 13, + "end_line": 13, + "filename": "/complex.k.json", + "line": 1, + "node": { + "insert_index": -1, + "key": { + "column": 6, + "end_column": 11, + "end_line": 3, + "filename": "/complex.k.json", + "line": 3, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"age\"", + "value": "age" + } + } + }, + "operation": "Union", + "value": { + "column": 13, + "end_column": 0, + "end_line": 4, + "filename": "/complex.k.json", + "line": 3, + "node": { + "NumberLit": { + "binary_suffix": null, + "value": { + "Int": 18 + } + } + } + } + } + }, + { + "column": 0, + "end_column": 13, + "end_line": 13, + "filename": "/complex.k.json", + "line": 1, + "node": { + "insert_index": -1, + "key": { + "column": 8, + "end_column": 0, + "end_line": 6, + "filename": "/complex.k.json", + "line": 5, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"data\"", + "value": "data" + } + } + }, + "operation": "Union", + "value": { + "column": 2, + "end_column": 5, + "end_line": 9, + "filename": "/complex.k.json", + "line": 6, + "node": { + "Config": { + "items": [ + { + "column": 2, + "end_column": 5, + "end_line": 9, + "filename": "/complex.k.json", + "line": 6, + "node": { + "insert_index": -1, + "key": { + "column": 13, + "end_column": 0, + "end_line": 7, + "filename": "/complex.k.json", + "line": 6, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"id\"", + "value": "id" + } + } + }, + "operation": "Union", + "value": { + "column": 2, + "end_column": 3, + "end_line": 7, + "filename": "/complex.k.json", + "line": 7, + "node": { + "NumberLit": { + "binary_suffix": null, + "value": { + "Int": 1 + } + } + } + } + } + }, + { + "column": 2, + "end_column": 5, + "end_line": 9, + "filename": "/complex.k.json", + "line": 6, + "node": { + "insert_index": -1, + "key": { + "column": 14, + "end_column": 21, + "end_line": 7, + "filename": "/complex.k.json", + "line": 7, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"value\"", + "value": "value" + } + } + }, + "operation": "Union", + "value": { + "column": 23, + "end_column": 5, + "end_line": 8, + "filename": "/complex.k.json", + "line": 7, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"value1\"", + "value": "value1" + } + } + } + } + } + ] + } + } + } + } + }, + { + "column": 0, + "end_column": 13, + "end_line": 13, + "filename": "/complex.k.json", + "line": 1, + "node": { + "insert_index": -1, + "key": { + "column": 15, + "end_column": 19, + "end_line": 12, + "filename": "/complex.k.json", + "line": 12, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"hc\"", + "value": "hc" + } + } + }, + "operation": "Union", + "value": { + "column": 1, + "end_column": 10, + "end_line": 13, + "filename": "/complex.k.json", + "line": 13, + "node": { + "List": { + "ctx": "Load", + "elts": [ + { + "column": 2, + "end_column": 3, + "end_line": 13, + "filename": "/complex.k.json", + "line": 13, + "node": { + "NumberLit": { + "binary_suffix": null, + "value": { + "Int": 1 + } + } + } + }, + { + "column": 5, + "end_column": 6, + "end_line": 13, + "filename": "/complex.k.json", + "line": 13, + "node": { + "NumberLit": { + "binary_suffix": null, + "value": { + "Int": 2 + } + } + } + }, + { + "column": 8, + "end_column": 9, + "end_line": 13, + "filename": "/complex.k.json", + "line": 13, + "node": { + "NumberLit": { + "binary_suffix": null, + "value": { + "Int": 3 + } + } + } + } + ] + } + } + } + } + }, + { + "column": 0, + "end_column": 13, + "end_line": 13, + "filename": "/complex.k.json", + "line": 1, + "node": { + "insert_index": -1, + "key": { + "column": 12, + "end_column": 4, + "end_line": 10, + "filename": "/complex.k.json", + "line": 9, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"labels\"", + "value": "labels" + } + } + }, + "operation": "Union", + "value": { + "column": 6, + "end_column": 8, + "end_line": 12, + "filename": "/complex.k.json", + "line": 10, + "node": { + "Config": { + "items": [ + { + "column": 6, + "end_column": 8, + "end_line": 12, + "filename": "/complex.k.json", + "line": 10, + "node": { + "insert_index": -1, + "key": { + "column": 17, + "end_column": 22, + "end_line": 10, + "filename": "/complex.k.json", + "line": 10, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"key\"", + "value": "key" + } + } + }, + "operation": "Union", + "value": { + "column": 1, + "end_column": 1, + "end_line": 12, + "filename": "/complex.k.json", + "line": 11, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"value\"", + "value": "value" + } + } + } + } + } + ] + } + } + } + } + }, + { + "column": 0, + "end_column": 13, + "end_line": 13, + "filename": "/complex.k.json", + "line": 1, + "node": { + "insert_index": -1, + "key": { + "column": 7, + "end_column": 16, + "end_line": 4, + "filename": "/complex.k.json", + "line": 4, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"message\"", + "value": "message" + } + } + }, + "operation": "Union", + "value": { + "column": 18, + "end_column": 1, + "end_line": 5, + "filename": "/complex.k.json", + "line": 4, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"This is Alice\"", + "value": "This is Alice" + } + } + } + } + }, + { + "column": 0, + "end_column": 13, + "end_line": 13, + "filename": "/complex.k.json", + "line": 1, + "node": { + "insert_index": -1, + "key": { + "column": 5, + "end_column": 11, + "end_line": 2, + "filename": "/complex.k.json", + "line": 2, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"name\"", + "value": "name" + } + } + }, + "operation": "Union", + "value": { + "column": 13, + "end_column": 20, + "end_line": 2, + "filename": "/complex.k.json", + "line": 2, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"Alice\"", + "value": "Alice" + } + } + } + } + } + ] + } + } + }, + "kwargs": [], + "name": { + "column": 0, + "end_column": 13, + "end_line": 13, + "filename": "/complex.k.json", + "line": 1, + "node": { + "ctx": "Load", + "names": [ + { + "column": 0, + "end_column": 13, + "end_line": 13, + "filename": "/complex.k.json", + "line": 1, + "node": "complex" + } + ], + "pkgpath": "" + } + } + } + } +} \ No newline at end of file diff --git a/kclvm/tools/src/vet/test_datas/json_win/list.k.ast.json b/kclvm/tools/src/vet/test_datas/json_win/list.k.ast.json new file mode 100644 index 000000000..b8c212c40 --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/json_win/list.k.ast.json @@ -0,0 +1,179 @@ +{ + "column": 0, + "end_column": 7, + "end_line": 7, + "filename": "/list.k.json", + "line": 1, + "node": { + "List": { + "ctx": "Load", + "elts": [ + { + "column": 5, + "end_column": 4, + "end_line": 7, + "filename": "/list.k.json", + "line": 2, + "node": { + "Schema": { + "args": [], + "config": { + "column": 5, + "end_column": 4, + "end_line": 7, + "filename": "/list.k.json", + "line": 2, + "node": { + "Config": { + "items": [ + { + "column": 5, + "end_column": 4, + "end_line": 7, + "filename": "/list.k.json", + "line": 2, + "node": { + "insert_index": -1, + "key": { + "column": 11, + "end_column": 16, + "end_line": 4, + "filename": "/list.k.json", + "line": 4, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"age\"", + "value": "age" + } + } + }, + "operation": "Union", + "value": { + "column": 18, + "end_column": 1, + "end_line": 5, + "filename": "/list.k.json", + "line": 4, + "node": { + "NumberLit": { + "binary_suffix": null, + "value": { + "Int": 18 + } + } + } + } + } + }, + { + "column": 5, + "end_column": 4, + "end_line": 7, + "filename": "/list.k.json", + "line": 2, + "node": { + "insert_index": -1, + "key": { + "column": 12, + "end_column": 21, + "end_line": 5, + "filename": "/list.k.json", + "line": 5, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"message\"", + "value": "message" + } + } + }, + "operation": "Union", + "value": { + "column": 23, + "end_column": 3, + "end_line": 6, + "filename": "/list.k.json", + "line": 5, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"This is Alice\"", + "value": "This is Alice" + } + } + } + } + }, + { + "column": 5, + "end_column": 4, + "end_line": 7, + "filename": "/list.k.json", + "line": 2, + "node": { + "insert_index": -1, + "key": { + "column": 10, + "end_column": 16, + "end_line": 3, + "filename": "/list.k.json", + "line": 3, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"name\"", + "value": "name" + } + } + }, + "operation": "Union", + "value": { + "column": 18, + "end_column": 0, + "end_line": 4, + "filename": "/list.k.json", + "line": 3, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"Alice\"", + "value": "Alice" + } + } + } + } + } + ] + } + } + }, + "kwargs": [], + "name": { + "column": 5, + "end_column": 4, + "end_line": 7, + "filename": "/list.k.json", + "line": 2, + "node": { + "ctx": "Load", + "names": [ + { + "column": 5, + "end_column": 4, + "end_line": 7, + "filename": "/list.k.json", + "line": 2, + "node": "list" + } + ], + "pkgpath": "" + } + } + } + } + } + ] + } + } +} \ No newline at end of file diff --git a/kclvm/tools/src/vet/test_datas/json_win/no_schema_name/complex.k.ast.json b/kclvm/tools/src/vet/test_datas/json_win/no_schema_name/complex.k.ast.json new file mode 100644 index 000000000..5f74bd0af --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/json_win/no_schema_name/complex.k.ast.json @@ -0,0 +1,409 @@ +{ + "column": 0, + "end_column": 13, + "end_line": 13, + "filename": "\\complex.k.json", + "line": 1, + "node": { + "Config": { + "items": [ + { + "column": 0, + "end_column": 13, + "end_line": 13, + "filename": "\\complex.k.json", + "line": 1, + "node": { + "insert_index": -1, + "key": { + "column": 6, + "end_column": 11, + "end_line": 3, + "filename": "\\complex.k.json", + "line": 3, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"age\"", + "value": "age" + } + } + }, + "operation": "Union", + "value": { + "column": 13, + "end_column": 0, + "end_line": 4, + "filename": "\\complex.k.json", + "line": 3, + "node": { + "NumberLit": { + "binary_suffix": null, + "value": { + "Int": 18 + } + } + } + } + } + }, + { + "column": 0, + "end_column": 13, + "end_line": 13, + "filename": "\\complex.k.json", + "line": 1, + "node": { + "insert_index": -1, + "key": { + "column": 8, + "end_column": 0, + "end_line": 6, + "filename": "\\complex.k.json", + "line": 5, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"data\"", + "value": "data" + } + } + }, + "operation": "Union", + "value": { + "column": 2, + "end_column": 5, + "end_line": 9, + "filename": "\\complex.k.json", + "line": 6, + "node": { + "Config": { + "items": [ + { + "column": 2, + "end_column": 5, + "end_line": 9, + "filename": "\\complex.k.json", + "line": 6, + "node": { + "insert_index": -1, + "key": { + "column": 13, + "end_column": 0, + "end_line": 7, + "filename": "\\complex.k.json", + "line": 6, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"id\"", + "value": "id" + } + } + }, + "operation": "Union", + "value": { + "column": 2, + "end_column": 3, + "end_line": 7, + "filename": "\\complex.k.json", + "line": 7, + "node": { + "NumberLit": { + "binary_suffix": null, + "value": { + "Int": 1 + } + } + } + } + } + }, + { + "column": 2, + "end_column": 5, + "end_line": 9, + "filename": "\\complex.k.json", + "line": 6, + "node": { + "insert_index": -1, + "key": { + "column": 14, + "end_column": 21, + "end_line": 7, + "filename": "\\complex.k.json", + "line": 7, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"value\"", + "value": "value" + } + } + }, + "operation": "Union", + "value": { + "column": 23, + "end_column": 5, + "end_line": 8, + "filename": "\\complex.k.json", + "line": 7, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"value1\"", + "value": "value1" + } + } + } + } + } + ] + } + } + } + } + }, + { + "column": 0, + "end_column": 13, + "end_line": 13, + "filename": "\\complex.k.json", + "line": 1, + "node": { + "insert_index": -1, + "key": { + "column": 15, + "end_column": 19, + "end_line": 12, + "filename": "\\complex.k.json", + "line": 12, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"hc\"", + "value": "hc" + } + } + }, + "operation": "Union", + "value": { + "column": 1, + "end_column": 10, + "end_line": 13, + "filename": "\\complex.k.json", + "line": 13, + "node": { + "List": { + "ctx": "Load", + "elts": [ + { + "column": 2, + "end_column": 3, + "end_line": 13, + "filename": "\\complex.k.json", + "line": 13, + "node": { + "NumberLit": { + "binary_suffix": null, + "value": { + "Int": 1 + } + } + } + }, + { + "column": 5, + "end_column": 6, + "end_line": 13, + "filename": "\\complex.k.json", + "line": 13, + "node": { + "NumberLit": { + "binary_suffix": null, + "value": { + "Int": 2 + } + } + } + }, + { + "column": 8, + "end_column": 9, + "end_line": 13, + "filename": "\\complex.k.json", + "line": 13, + "node": { + "NumberLit": { + "binary_suffix": null, + "value": { + "Int": 3 + } + } + } + } + ] + } + } + } + } + }, + { + "column": 0, + "end_column": 13, + "end_line": 13, + "filename": "\\complex.k.json", + "line": 1, + "node": { + "insert_index": -1, + "key": { + "column": 12, + "end_column": 4, + "end_line": 10, + "filename": "\\complex.k.json", + "line": 9, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"labels\"", + "value": "labels" + } + } + }, + "operation": "Union", + "value": { + "column": 6, + "end_column": 8, + "end_line": 12, + "filename": "\\complex.k.json", + "line": 10, + "node": { + "Config": { + "items": [ + { + "column": 6, + "end_column": 8, + "end_line": 12, + "filename": "\\complex.k.json", + "line": 10, + "node": { + "insert_index": -1, + "key": { + "column": 17, + "end_column": 22, + "end_line": 10, + "filename": "\\complex.k.json", + "line": 10, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"key\"", + "value": "key" + } + } + }, + "operation": "Union", + "value": { + "column": 1, + "end_column": 1, + "end_line": 12, + "filename": "\\complex.k.json", + "line": 11, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"value\"", + "value": "value" + } + } + } + } + } + ] + } + } + } + } + }, + { + "column": 0, + "end_column": 13, + "end_line": 13, + "filename": "\\complex.k.json", + "line": 1, + "node": { + "insert_index": -1, + "key": { + "column": 7, + "end_column": 16, + "end_line": 4, + "filename": "\\complex.k.json", + "line": 4, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"message\"", + "value": "message" + } + } + }, + "operation": "Union", + "value": { + "column": 18, + "end_column": 1, + "end_line": 5, + "filename": "\\complex.k.json", + "line": 4, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"This is Alice\"", + "value": "This is Alice" + } + } + } + } + }, + { + "column": 0, + "end_column": 13, + "end_line": 13, + "filename": "\\complex.k.json", + "line": 1, + "node": { + "insert_index": -1, + "key": { + "column": 5, + "end_column": 11, + "end_line": 2, + "filename": "\\complex.k.json", + "line": 2, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"name\"", + "value": "name" + } + } + }, + "operation": "Union", + "value": { + "column": 13, + "end_column": 20, + "end_line": 2, + "filename": "\\complex.k.json", + "line": 2, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"Alice\"", + "value": "Alice" + } + } + } + } + } + ] + } + } +} \ No newline at end of file diff --git a/kclvm/tools/src/vet/test_datas/json_win/no_schema_name/list.k.ast.json b/kclvm/tools/src/vet/test_datas/json_win/no_schema_name/list.k.ast.json new file mode 100644 index 000000000..ad7f66fc7 --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/json_win/no_schema_name/list.k.ast.json @@ -0,0 +1,145 @@ +{ + "column": 0, + "end_column": 7, + "end_line": 7, + "filename": "\\list.k.json", + "line": 1, + "node": { + "List": { + "ctx": "Load", + "elts": [ + { + "column": 5, + "end_column": 4, + "end_line": 7, + "filename": "\\list.k.json", + "line": 2, + "node": { + "Config": { + "items": [ + { + "column": 5, + "end_column": 4, + "end_line": 7, + "filename": "\\list.k.json", + "line": 2, + "node": { + "insert_index": -1, + "key": { + "column": 11, + "end_column": 16, + "end_line": 4, + "filename": "\\list.k.json", + "line": 4, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"age\"", + "value": "age" + } + } + }, + "operation": "Union", + "value": { + "column": 18, + "end_column": 1, + "end_line": 5, + "filename": "\\list.k.json", + "line": 4, + "node": { + "NumberLit": { + "binary_suffix": null, + "value": { + "Int": 18 + } + } + } + } + } + }, + { + "column": 5, + "end_column": 4, + "end_line": 7, + "filename": "\\list.k.json", + "line": 2, + "node": { + "insert_index": -1, + "key": { + "column": 12, + "end_column": 21, + "end_line": 5, + "filename": "\\list.k.json", + "line": 5, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"message\"", + "value": "message" + } + } + }, + "operation": "Union", + "value": { + "column": 23, + "end_column": 3, + "end_line": 6, + "filename": "\\list.k.json", + "line": 5, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"This is Alice\"", + "value": "This is Alice" + } + } + } + } + }, + { + "column": 5, + "end_column": 4, + "end_line": 7, + "filename": "\\list.k.json", + "line": 2, + "node": { + "insert_index": -1, + "key": { + "column": 10, + "end_column": 16, + "end_line": 3, + "filename": "\\list.k.json", + "line": 3, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"name\"", + "value": "name" + } + } + }, + "operation": "Union", + "value": { + "column": 18, + "end_column": 0, + "end_line": 4, + "filename": "\\list.k.json", + "line": 3, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"Alice\"", + "value": "Alice" + } + } + } + } + } + ] + } + } + } + ] + } + } +} \ No newline at end of file diff --git a/kclvm/tools/src/vet/test_datas/json_win/no_schema_name/only_with_bool.ast.json b/kclvm/tools/src/vet/test_datas/json_win/no_schema_name/only_with_bool.ast.json new file mode 100644 index 000000000..f55ee7c62 --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/json_win/no_schema_name/only_with_bool.ast.json @@ -0,0 +1,50 @@ +{ + "column": 0, + "end_column": 3, + "end_line": 3, + "filename": "\\only_with_bool.json", + "line": 1, + "node": { + "Config": { + "items": [ + { + "column": 0, + "end_column": 3, + "end_line": 3, + "filename": "\\only_with_bool.json", + "line": 1, + "node": { + "insert_index": -1, + "key": { + "column": 5, + "end_column": 11, + "end_line": 2, + "filename": "\\only_with_bool.json", + "line": 2, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"flag\"", + "value": "flag" + } + } + }, + "operation": "Union", + "value": { + "column": 13, + "end_column": 0, + "end_line": 3, + "filename": "\\only_with_bool.json", + "line": 2, + "node": { + "NameConstantLit": { + "value": "True" + } + } + } + } + } + ] + } + } +} \ No newline at end of file diff --git a/kclvm/tools/src/vet/test_datas/json_win/no_schema_name/only_with_float.ast.json b/kclvm/tools/src/vet/test_datas/json_win/no_schema_name/only_with_float.ast.json new file mode 100644 index 000000000..608d85f9e --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/json_win/no_schema_name/only_with_float.ast.json @@ -0,0 +1,53 @@ +{ + "column": 0, + "end_column": 3, + "end_line": 3, + "filename": "\\only_with_float.json", + "line": 1, + "node": { + "Config": { + "items": [ + { + "column": 0, + "end_column": 3, + "end_line": 3, + "filename": "\\only_with_float.json", + "line": 1, + "node": { + "insert_index": -1, + "key": { + "column": 5, + "end_column": 18, + "end_line": 2, + "filename": "\\only_with_float.json", + "line": 2, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"float_value\"", + "value": "float_value" + } + } + }, + "operation": "Union", + "value": { + "column": 20, + "end_column": 0, + "end_line": 3, + "filename": "\\only_with_float.json", + "line": 2, + "node": { + "NumberLit": { + "binary_suffix": null, + "value": { + "Float": 0.33 + } + } + } + } + } + } + ] + } + } +} \ No newline at end of file diff --git a/kclvm/tools/src/vet/test_datas/json_win/no_schema_name/only_with_null.ast.json b/kclvm/tools/src/vet/test_datas/json_win/no_schema_name/only_with_null.ast.json new file mode 100644 index 000000000..2d3731770 --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/json_win/no_schema_name/only_with_null.ast.json @@ -0,0 +1,50 @@ +{ + "column": 0, + "end_column": 3, + "end_line": 3, + "filename": "\\only_with_null.json", + "line": 1, + "node": { + "Config": { + "items": [ + { + "column": 0, + "end_column": 3, + "end_line": 3, + "filename": "\\only_with_null.json", + "line": 1, + "node": { + "insert_index": -1, + "key": { + "column": 5, + "end_column": 17, + "end_line": 2, + "filename": "\\only_with_null.json", + "line": 2, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"null_value\"", + "value": "null_value" + } + } + }, + "operation": "Union", + "value": { + "column": 19, + "end_column": 0, + "end_line": 3, + "filename": "\\only_with_null.json", + "line": 2, + "node": { + "NameConstantLit": { + "value": "None" + } + } + } + } + } + ] + } + } +} \ No newline at end of file diff --git a/kclvm/tools/src/vet/test_datas/json_win/no_schema_name/plain_value.k.ast.json b/kclvm/tools/src/vet/test_datas/json_win/no_schema_name/plain_value.k.ast.json new file mode 100644 index 000000000..02f360fd3 --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/json_win/no_schema_name/plain_value.k.ast.json @@ -0,0 +1,15 @@ +{ + "column": 0, + "end_column": 1, + "end_line": 1, + "filename": "\\plain_value.k.json", + "line": 1, + "node": { + "NumberLit": { + "binary_suffix": null, + "value": { + "Int": 1 + } + } + } +} \ No newline at end of file diff --git a/kclvm/tools/src/vet/test_datas/json_win/no_schema_name/simple.k.ast.json b/kclvm/tools/src/vet/test_datas/json_win/no_schema_name/simple.k.ast.json new file mode 100644 index 000000000..4b5360af4 --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/json_win/no_schema_name/simple.k.ast.json @@ -0,0 +1,131 @@ +{ + "column": 0, + "end_column": 5, + "end_line": 5, + "filename": "\\simple.k.json", + "line": 1, + "node": { + "Config": { + "items": [ + { + "column": 0, + "end_column": 5, + "end_line": 5, + "filename": "\\simple.k.json", + "line": 1, + "node": { + "insert_index": -1, + "key": { + "column": 6, + "end_column": 11, + "end_line": 3, + "filename": "\\simple.k.json", + "line": 3, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"age\"", + "value": "age" + } + } + }, + "operation": "Union", + "value": { + "column": 13, + "end_column": 0, + "end_line": 4, + "filename": "\\simple.k.json", + "line": 3, + "node": { + "NumberLit": { + "binary_suffix": null, + "value": { + "Int": 18 + } + } + } + } + } + }, + { + "column": 0, + "end_column": 5, + "end_line": 5, + "filename": "\\simple.k.json", + "line": 1, + "node": { + "insert_index": -1, + "key": { + "column": 7, + "end_column": 16, + "end_line": 4, + "filename": "\\simple.k.json", + "line": 4, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"message\"", + "value": "message" + } + } + }, + "operation": "Union", + "value": { + "column": 18, + "end_column": 2, + "end_line": 5, + "filename": "\\simple.k.json", + "line": 4, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"This is Alice\"", + "value": "This is Alice" + } + } + } + } + }, + { + "column": 0, + "end_column": 5, + "end_line": 5, + "filename": "\\simple.k.json", + "line": 1, + "node": { + "insert_index": -1, + "key": { + "column": 5, + "end_column": 11, + "end_line": 2, + "filename": "\\simple.k.json", + "line": 2, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"name\"", + "value": "name" + } + } + }, + "operation": "Union", + "value": { + "column": 13, + "end_column": 20, + "end_line": 2, + "filename": "\\simple.k.json", + "line": 2, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"Alice\"", + "value": "Alice" + } + } + } + } + } + ] + } + } +} \ No newline at end of file diff --git a/kclvm/tools/src/vet/test_datas/json_win/no_schema_name/test.k.ast.json b/kclvm/tools/src/vet/test_datas/json_win/no_schema_name/test.k.ast.json new file mode 100644 index 000000000..b11b921ce --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/json_win/no_schema_name/test.k.ast.json @@ -0,0 +1,275 @@ +{ + "column": 0, + "end_column": 12, + "end_line": 12, + "filename": "\\test.k.json", + "line": 1, + "node": { + "Config": { + "items": [ + { + "column": 0, + "end_column": 12, + "end_line": 12, + "filename": "\\test.k.json", + "line": 1, + "node": { + "insert_index": -1, + "key": { + "column": 7, + "end_column": 16, + "end_line": 4, + "filename": "\\test.k.json", + "line": 4, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"address\"", + "value": "address" + } + } + }, + "operation": "Union", + "value": { + "column": 1, + "end_column": 4, + "end_line": 8, + "filename": "\\test.k.json", + "line": 5, + "node": { + "Config": { + "items": [ + { + "column": 1, + "end_column": 4, + "end_line": 8, + "filename": "\\test.k.json", + "line": 5, + "node": { + "insert_index": -1, + "key": { + "column": 13, + "end_column": 19, + "end_line": 6, + "filename": "\\test.k.json", + "line": 6, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"city\"", + "value": "city" + } + } + }, + "operation": "Union", + "value": { + "column": 21, + "end_column": 4, + "end_line": 7, + "filename": "\\test.k.json", + "line": 6, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"London\"", + "value": "London" + } + } + } + } + }, + { + "column": 1, + "end_column": 4, + "end_line": 8, + "filename": "\\test.k.json", + "line": 5, + "node": { + "insert_index": -1, + "key": { + "column": 12, + "end_column": 20, + "end_line": 5, + "filename": "\\test.k.json", + "line": 5, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"street\"", + "value": "street" + } + } + }, + "operation": "Union", + "value": { + "column": 22, + "end_column": 2, + "end_line": 6, + "filename": "\\test.k.json", + "line": 5, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"10 Downing Street\"", + "value": "10 Downing Street" + } + } + } + } + } + ] + } + } + } + } + }, + { + "column": 0, + "end_column": 12, + "end_line": 12, + "filename": "\\test.k.json", + "line": 1, + "node": { + "insert_index": -1, + "key": { + "column": 6, + "end_column": 11, + "end_line": 3, + "filename": "\\test.k.json", + "line": 3, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"age\"", + "value": "age" + } + } + }, + "operation": "Union", + "value": { + "column": 13, + "end_column": 0, + "end_line": 4, + "filename": "\\test.k.json", + "line": 3, + "node": { + "NumberLit": { + "binary_suffix": null, + "value": { + "Int": 43 + } + } + } + } + } + }, + { + "column": 0, + "end_column": 12, + "end_line": 12, + "filename": "\\test.k.json", + "line": 1, + "node": { + "insert_index": -1, + "key": { + "column": 5, + "end_column": 11, + "end_line": 2, + "filename": "\\test.k.json", + "line": 2, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"name\"", + "value": "name" + } + } + }, + "operation": "Union", + "value": { + "column": 13, + "end_column": 23, + "end_line": 2, + "filename": "\\test.k.json", + "line": 2, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"John Doe\"", + "value": "John Doe" + } + } + } + } + }, + { + "column": 0, + "end_column": 12, + "end_line": 12, + "filename": "\\test.k.json", + "line": 1, + "node": { + "insert_index": -1, + "key": { + "column": 11, + "end_column": 3, + "end_line": 9, + "filename": "\\test.k.json", + "line": 8, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"phones\"", + "value": "phones" + } + } + }, + "operation": "Union", + "value": { + "column": 5, + "end_column": 9, + "end_line": 12, + "filename": "\\test.k.json", + "line": 9, + "node": { + "List": { + "ctx": "Load", + "elts": [ + { + "column": 16, + "end_column": 6, + "end_line": 10, + "filename": "\\test.k.json", + "line": 9, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"+44 1234567\"", + "value": "+44 1234567" + } + } + }, + { + "column": 17, + "end_column": 2, + "end_line": 12, + "filename": "\\test.k.json", + "line": 10, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"+44 2345678\"", + "value": "+44 2345678" + } + } + } + ] + } + } + } + } + } + ] + } + } +} \ No newline at end of file diff --git a/kclvm/tools/src/vet/test_datas/json_win/only_with_bool.ast.json b/kclvm/tools/src/vet/test_datas/json_win/only_with_bool.ast.json new file mode 100644 index 000000000..ce2204d12 --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/json_win/only_with_bool.ast.json @@ -0,0 +1,84 @@ +{ + "column": 0, + "end_column": 3, + "end_line": 3, + "filename": "/only_with_bool.json", + "line": 1, + "node": { + "Schema": { + "args": [], + "config": { + "column": 0, + "end_column": 3, + "end_line": 3, + "filename": "/only_with_bool.json", + "line": 1, + "node": { + "Config": { + "items": [ + { + "column": 0, + "end_column": 3, + "end_line": 3, + "filename": "/only_with_bool.json", + "line": 1, + "node": { + "insert_index": -1, + "key": { + "column": 5, + "end_column": 11, + "end_line": 2, + "filename": "/only_with_bool.json", + "line": 2, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"flag\"", + "value": "flag" + } + } + }, + "operation": "Union", + "value": { + "column": 13, + "end_column": 0, + "end_line": 3, + "filename": "/only_with_bool.json", + "line": 2, + "node": { + "NameConstantLit": { + "value": "True" + } + } + } + } + } + ] + } + } + }, + "kwargs": [], + "name": { + "column": 0, + "end_column": 3, + "end_line": 3, + "filename": "/only_with_bool.json", + "line": 1, + "node": { + "ctx": "Load", + "names": [ + { + "column": 0, + "end_column": 3, + "end_line": 3, + "filename": "/only_with_bool.json", + "line": 1, + "node": "only_with_bool" + } + ], + "pkgpath": "" + } + } + } + } +} \ No newline at end of file diff --git a/kclvm/tools/src/vet/test_datas/json_win/only_with_float.ast.json b/kclvm/tools/src/vet/test_datas/json_win/only_with_float.ast.json new file mode 100644 index 000000000..d399bb08d --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/json_win/only_with_float.ast.json @@ -0,0 +1,87 @@ +{ + "column": 0, + "end_column": 3, + "end_line": 3, + "filename": "/only_with_float.json", + "line": 1, + "node": { + "Schema": { + "args": [], + "config": { + "column": 0, + "end_column": 3, + "end_line": 3, + "filename": "/only_with_float.json", + "line": 1, + "node": { + "Config": { + "items": [ + { + "column": 0, + "end_column": 3, + "end_line": 3, + "filename": "/only_with_float.json", + "line": 1, + "node": { + "insert_index": -1, + "key": { + "column": 5, + "end_column": 18, + "end_line": 2, + "filename": "/only_with_float.json", + "line": 2, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"float_value\"", + "value": "float_value" + } + } + }, + "operation": "Union", + "value": { + "column": 20, + "end_column": 0, + "end_line": 3, + "filename": "/only_with_float.json", + "line": 2, + "node": { + "NumberLit": { + "binary_suffix": null, + "value": { + "Float": 0.33 + } + } + } + } + } + } + ] + } + } + }, + "kwargs": [], + "name": { + "column": 0, + "end_column": 3, + "end_line": 3, + "filename": "/only_with_float.json", + "line": 1, + "node": { + "ctx": "Load", + "names": [ + { + "column": 0, + "end_column": 3, + "end_line": 3, + "filename": "/only_with_float.json", + "line": 1, + "node": "only_with_float" + } + ], + "pkgpath": "" + } + } + } + } +} \ No newline at end of file diff --git a/kclvm/tools/src/vet/test_datas/json_win/only_with_null.ast.json b/kclvm/tools/src/vet/test_datas/json_win/only_with_null.ast.json new file mode 100644 index 000000000..efa3c5353 --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/json_win/only_with_null.ast.json @@ -0,0 +1,84 @@ +{ + "column": 0, + "end_column": 3, + "end_line": 3, + "filename": "/only_with_null.json", + "line": 1, + "node": { + "Schema": { + "args": [], + "config": { + "column": 0, + "end_column": 3, + "end_line": 3, + "filename": "/only_with_null.json", + "line": 1, + "node": { + "Config": { + "items": [ + { + "column": 0, + "end_column": 3, + "end_line": 3, + "filename": "/only_with_null.json", + "line": 1, + "node": { + "insert_index": -1, + "key": { + "column": 5, + "end_column": 17, + "end_line": 2, + "filename": "/only_with_null.json", + "line": 2, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"null_value\"", + "value": "null_value" + } + } + }, + "operation": "Union", + "value": { + "column": 19, + "end_column": 0, + "end_line": 3, + "filename": "/only_with_null.json", + "line": 2, + "node": { + "NameConstantLit": { + "value": "None" + } + } + } + } + } + ] + } + } + }, + "kwargs": [], + "name": { + "column": 0, + "end_column": 3, + "end_line": 3, + "filename": "/only_with_null.json", + "line": 1, + "node": { + "ctx": "Load", + "names": [ + { + "column": 0, + "end_column": 3, + "end_line": 3, + "filename": "/only_with_null.json", + "line": 1, + "node": "only_with_null" + } + ], + "pkgpath": "" + } + } + } + } +} \ No newline at end of file diff --git a/kclvm/tools/src/vet/test_datas/json_win/plain_value.k.ast.json b/kclvm/tools/src/vet/test_datas/json_win/plain_value.k.ast.json new file mode 100644 index 000000000..3110dbc86 --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/json_win/plain_value.k.ast.json @@ -0,0 +1,15 @@ +{ + "column": 0, + "end_column": 1, + "end_line": 1, + "filename": "/plain_value.k.json", + "line": 1, + "node": { + "NumberLit": { + "binary_suffix": null, + "value": { + "Int": 1 + } + } + } +} \ No newline at end of file diff --git a/kclvm/tools/src/vet/test_datas/json_win/simple.k.ast.json b/kclvm/tools/src/vet/test_datas/json_win/simple.k.ast.json new file mode 100644 index 000000000..af431e2bf --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/json_win/simple.k.ast.json @@ -0,0 +1,165 @@ +{ + "column": 0, + "end_column": 5, + "end_line": 5, + "filename": "/simple.k.json", + "line": 1, + "node": { + "Schema": { + "args": [], + "config": { + "column": 0, + "end_column": 5, + "end_line": 5, + "filename": "/simple.k.json", + "line": 1, + "node": { + "Config": { + "items": [ + { + "column": 0, + "end_column": 5, + "end_line": 5, + "filename": "/simple.k.json", + "line": 1, + "node": { + "insert_index": -1, + "key": { + "column": 6, + "end_column": 11, + "end_line": 3, + "filename": "/simple.k.json", + "line": 3, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"age\"", + "value": "age" + } + } + }, + "operation": "Union", + "value": { + "column": 13, + "end_column": 0, + "end_line": 4, + "filename": "/simple.k.json", + "line": 3, + "node": { + "NumberLit": { + "binary_suffix": null, + "value": { + "Int": 18 + } + } + } + } + } + }, + { + "column": 0, + "end_column": 5, + "end_line": 5, + "filename": "/simple.k.json", + "line": 1, + "node": { + "insert_index": -1, + "key": { + "column": 7, + "end_column": 16, + "end_line": 4, + "filename": "/simple.k.json", + "line": 4, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"message\"", + "value": "message" + } + } + }, + "operation": "Union", + "value": { + "column": 18, + "end_column": 2, + "end_line": 5, + "filename": "/simple.k.json", + "line": 4, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"This is Alice\"", + "value": "This is Alice" + } + } + } + } + }, + { + "column": 0, + "end_column": 5, + "end_line": 5, + "filename": "/simple.k.json", + "line": 1, + "node": { + "insert_index": -1, + "key": { + "column": 5, + "end_column": 11, + "end_line": 2, + "filename": "/simple.k.json", + "line": 2, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"name\"", + "value": "name" + } + } + }, + "operation": "Union", + "value": { + "column": 13, + "end_column": 20, + "end_line": 2, + "filename": "/simple.k.json", + "line": 2, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"Alice\"", + "value": "Alice" + } + } + } + } + } + ] + } + } + }, + "kwargs": [], + "name": { + "column": 0, + "end_column": 5, + "end_line": 5, + "filename": "/simple.k.json", + "line": 1, + "node": { + "ctx": "Load", + "names": [ + { + "column": 0, + "end_column": 5, + "end_line": 5, + "filename": "/simple.k.json", + "line": 1, + "node": "simple" + } + ], + "pkgpath": "" + } + } + } + } +} \ No newline at end of file diff --git a/kclvm/tools/src/vet/test_datas/json_win/test.k.ast.json b/kclvm/tools/src/vet/test_datas/json_win/test.k.ast.json new file mode 100644 index 000000000..3d1fb6680 --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/json_win/test.k.ast.json @@ -0,0 +1,309 @@ +{ + "column": 0, + "end_column": 12, + "end_line": 12, + "filename": "/test.k.json", + "line": 1, + "node": { + "Schema": { + "args": [], + "config": { + "column": 0, + "end_column": 12, + "end_line": 12, + "filename": "/test.k.json", + "line": 1, + "node": { + "Config": { + "items": [ + { + "column": 0, + "end_column": 12, + "end_line": 12, + "filename": "/test.k.json", + "line": 1, + "node": { + "insert_index": -1, + "key": { + "column": 7, + "end_column": 16, + "end_line": 4, + "filename": "/test.k.json", + "line": 4, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"address\"", + "value": "address" + } + } + }, + "operation": "Union", + "value": { + "column": 1, + "end_column": 4, + "end_line": 8, + "filename": "/test.k.json", + "line": 5, + "node": { + "Config": { + "items": [ + { + "column": 1, + "end_column": 4, + "end_line": 8, + "filename": "/test.k.json", + "line": 5, + "node": { + "insert_index": -1, + "key": { + "column": 13, + "end_column": 19, + "end_line": 6, + "filename": "/test.k.json", + "line": 6, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"city\"", + "value": "city" + } + } + }, + "operation": "Union", + "value": { + "column": 21, + "end_column": 4, + "end_line": 7, + "filename": "/test.k.json", + "line": 6, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"London\"", + "value": "London" + } + } + } + } + }, + { + "column": 1, + "end_column": 4, + "end_line": 8, + "filename": "/test.k.json", + "line": 5, + "node": { + "insert_index": -1, + "key": { + "column": 12, + "end_column": 20, + "end_line": 5, + "filename": "/test.k.json", + "line": 5, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"street\"", + "value": "street" + } + } + }, + "operation": "Union", + "value": { + "column": 22, + "end_column": 2, + "end_line": 6, + "filename": "/test.k.json", + "line": 5, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"10 Downing Street\"", + "value": "10 Downing Street" + } + } + } + } + } + ] + } + } + } + } + }, + { + "column": 0, + "end_column": 12, + "end_line": 12, + "filename": "/test.k.json", + "line": 1, + "node": { + "insert_index": -1, + "key": { + "column": 6, + "end_column": 11, + "end_line": 3, + "filename": "/test.k.json", + "line": 3, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"age\"", + "value": "age" + } + } + }, + "operation": "Union", + "value": { + "column": 13, + "end_column": 0, + "end_line": 4, + "filename": "/test.k.json", + "line": 3, + "node": { + "NumberLit": { + "binary_suffix": null, + "value": { + "Int": 43 + } + } + } + } + } + }, + { + "column": 0, + "end_column": 12, + "end_line": 12, + "filename": "/test.k.json", + "line": 1, + "node": { + "insert_index": -1, + "key": { + "column": 5, + "end_column": 11, + "end_line": 2, + "filename": "/test.k.json", + "line": 2, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"name\"", + "value": "name" + } + } + }, + "operation": "Union", + "value": { + "column": 13, + "end_column": 23, + "end_line": 2, + "filename": "/test.k.json", + "line": 2, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"John Doe\"", + "value": "John Doe" + } + } + } + } + }, + { + "column": 0, + "end_column": 12, + "end_line": 12, + "filename": "/test.k.json", + "line": 1, + "node": { + "insert_index": -1, + "key": { + "column": 11, + "end_column": 3, + "end_line": 9, + "filename": "/test.k.json", + "line": 8, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"phones\"", + "value": "phones" + } + } + }, + "operation": "Union", + "value": { + "column": 5, + "end_column": 9, + "end_line": 12, + "filename": "/test.k.json", + "line": 9, + "node": { + "List": { + "ctx": "Load", + "elts": [ + { + "column": 16, + "end_column": 6, + "end_line": 10, + "filename": "/test.k.json", + "line": 9, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"+44 1234567\"", + "value": "+44 1234567" + } + } + }, + { + "column": 17, + "end_column": 2, + "end_line": 12, + "filename": "/test.k.json", + "line": 10, + "node": { + "StringLit": { + "is_long_string": false, + "raw_value": "\"+44 2345678\"", + "value": "+44 2345678" + } + } + } + ] + } + } + } + } + } + ] + } + } + }, + "kwargs": [], + "name": { + "column": 0, + "end_column": 12, + "end_line": 12, + "filename": "/test.k.json", + "line": 1, + "node": { + "ctx": "Load", + "names": [ + { + "column": 0, + "end_column": 12, + "end_line": 12, + "filename": "/test.k.json", + "line": 1, + "node": "test" + } + ], + "pkgpath": "" + } + } + } + } +} \ No newline at end of file diff --git a/kclvm/tools/src/vet/test_datas/validate_cases/complex.k b/kclvm/tools/src/vet/test_datas/validate_cases/complex.k new file mode 100644 index 000000000..09c880103 --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/validate_cases/complex.k @@ -0,0 +1,11 @@ +schema User: + name: str + age: int + message?: str + data: Data + labels: {str:} + hc: [int] + +schema Data: + id: int + value: str diff --git a/kclvm/tools/src/vet/test_datas/validate_cases/complex.k.json b/kclvm/tools/src/vet/test_datas/validate_cases/complex.k.json new file mode 100644 index 000000000..d3e9b575d --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/validate_cases/complex.k.json @@ -0,0 +1,13 @@ +{ + "name": "Alice", + "age": 18, + "message": "This is Alice", + "data": { + "id": 1, + "value": "value1" + }, + "labels": { + "key": "value" + }, + "hc": [1, 2, 3] +} diff --git a/kclvm/tools/src/vet/test_datas/validate_cases/complex.k.yaml b/kclvm/tools/src/vet/test_datas/validate_cases/complex.k.yaml new file mode 100644 index 000000000..ec6d7e0cd --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/validate_cases/complex.k.yaml @@ -0,0 +1,12 @@ +name: Alice +age: 18 +message: This is Alice +data: + id: 1 + value: value1 +labels: + key: value +hc: + - 1 + - 2 + - 3 diff --git a/kclvm/tools/src/vet/test_datas/validate_cases/dep/kcl.mod b/kclvm/tools/src/vet/test_datas/validate_cases/dep/kcl.mod new file mode 100644 index 000000000..ad4478c32 --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/validate_cases/dep/kcl.mod @@ -0,0 +1,5 @@ +[package] +name = "dep" +edition = "v0.8.0" +version = "0.0.1" + diff --git a/kclvm/tools/src/vet/test_datas/validate_cases/dep/main.k b/kclvm/tools/src/vet/test_datas/validate_cases/dep/main.k new file mode 100644 index 000000000..eae94c15d --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/validate_cases/dep/main.k @@ -0,0 +1,2 @@ +schema A : + name: str \ No newline at end of file diff --git a/kclvm/tools/src/vet/test_datas/validate_cases/list.k b/kclvm/tools/src/vet/test_datas/validate_cases/list.k new file mode 100644 index 000000000..ef6d67aed --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/validate_cases/list.k @@ -0,0 +1,9 @@ +schema User: + name: str + age: int + message?: str + +assert typeof(value) == "list" +assert all v in value { + typeof(v) == "User" +} diff --git a/kclvm/tools/src/vet/test_datas/validate_cases/list.k.json b/kclvm/tools/src/vet/test_datas/validate_cases/list.k.json new file mode 100644 index 000000000..b6f772ebe --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/validate_cases/list.k.json @@ -0,0 +1,7 @@ +[ + { + "name": "Alice", + "age": 18, + "message": "This is Alice" + } +] diff --git a/kclvm/tools/src/vet/test_datas/validate_cases/list.k.yaml b/kclvm/tools/src/vet/test_datas/validate_cases/list.k.yaml new file mode 100644 index 000000000..9ca9f4801 --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/validate_cases/list.k.yaml @@ -0,0 +1,4 @@ +- name: Alice + age: 18 + message: This is Alice + \ No newline at end of file diff --git a/kclvm/tools/src/vet/test_datas/validate_cases/plain_value.k b/kclvm/tools/src/vet/test_datas/validate_cases/plain_value.k new file mode 100644 index 000000000..820fab7ce --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/validate_cases/plain_value.k @@ -0,0 +1,2 @@ +assert typeof(value) == "int" +assert value >= 1 diff --git a/kclvm/tools/src/vet/test_datas/validate_cases/plain_value.k.json b/kclvm/tools/src/vet/test_datas/validate_cases/plain_value.k.json new file mode 100644 index 000000000..d00491fd7 --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/validate_cases/plain_value.k.json @@ -0,0 +1 @@ +1 diff --git a/kclvm/tools/src/vet/test_datas/validate_cases/plain_value.k.yaml b/kclvm/tools/src/vet/test_datas/validate_cases/plain_value.k.yaml new file mode 100644 index 000000000..d00491fd7 --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/validate_cases/plain_value.k.yaml @@ -0,0 +1 @@ +1 diff --git a/kclvm/tools/src/vet/test_datas/validate_cases/simple.k b/kclvm/tools/src/vet/test_datas/validate_cases/simple.k new file mode 100644 index 000000000..7a78b3aac --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/validate_cases/simple.k @@ -0,0 +1,4 @@ +schema User: + name: str + age: int + message?: str diff --git a/kclvm/tools/src/vet/test_datas/validate_cases/simple.k.json b/kclvm/tools/src/vet/test_datas/validate_cases/simple.k.json new file mode 100644 index 000000000..02fd725d1 --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/validate_cases/simple.k.json @@ -0,0 +1,5 @@ +{ + "name": "Alice", + "age": 18, + "message": "This is Alice" +} diff --git a/kclvm/tools/src/vet/test_datas/validate_cases/simple.k.yaml b/kclvm/tools/src/vet/test_datas/validate_cases/simple.k.yaml new file mode 100644 index 000000000..039156972 --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/validate_cases/simple.k.yaml @@ -0,0 +1,3 @@ +name: Alice +age: 18 +message: This is Alice diff --git a/kclvm/tools/src/vet/test_datas/validate_cases/test.k b/kclvm/tools/src/vet/test_datas/validate_cases/test.k new file mode 100644 index 000000000..4c5653da4 --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/validate_cases/test.k @@ -0,0 +1,8 @@ +schema User: + name: str + age: int + message?: str + + check: + name == "Alice" + age > 10 diff --git a/kclvm/tools/src/vet/test_datas/validate_cases/test.k.json b/kclvm/tools/src/vet/test_datas/validate_cases/test.k.json new file mode 100644 index 000000000..02fd725d1 --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/validate_cases/test.k.json @@ -0,0 +1,5 @@ +{ + "name": "Alice", + "age": 18, + "message": "This is Alice" +} diff --git a/kclvm/tools/src/vet/test_datas/validate_cases/test.k.yaml b/kclvm/tools/src/vet/test_datas/validate_cases/test.k.yaml new file mode 100644 index 000000000..039156972 --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/validate_cases/test.k.yaml @@ -0,0 +1,3 @@ +name: Alice +age: 18 +message: This is Alice diff --git a/kclvm/tools/src/vet/test_datas/validate_cases/with_import.k b/kclvm/tools/src/vet/test_datas/validate_cases/with_import.k new file mode 100644 index 000000000..5d779160f --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/validate_cases/with_import.k @@ -0,0 +1,4 @@ +import .dep as dep + +schema B: + a: dep.A \ No newline at end of file diff --git a/kclvm/tools/src/vet/test_datas/validate_cases/with_import.k.json b/kclvm/tools/src/vet/test_datas/validate_cases/with_import.k.json new file mode 100644 index 000000000..58198466c --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/validate_cases/with_import.k.json @@ -0,0 +1,5 @@ +{ + "a": { + "name": "name" + } +} \ No newline at end of file diff --git a/kclvm/tools/src/vet/test_datas/validate_cases/with_import.k.yaml b/kclvm/tools/src/vet/test_datas/validate_cases/with_import.k.yaml new file mode 100644 index 000000000..7eabf3069 --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/validate_cases/with_import.k.yaml @@ -0,0 +1,2 @@ +a: + name: name \ No newline at end of file diff --git a/kclvm/tools/src/vet/test_datas/yaml/complex.k.ast.yaml b/kclvm/tools/src/vet/test_datas/yaml/complex.k.ast.yaml new file mode 100644 index 000000000..994e9dd8e --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/yaml/complex.k.ast.yaml @@ -0,0 +1,443 @@ +{ + "node": { + "!Schema": { + "name": { + "node": { + "names": [ + { + "node": "complex", + "filename": "/complex.k.yaml", + "line": 1, + "column": 4, + "end_line": 0, + "end_column": 0 + } + ], + "pkgpath": "", + "ctx": "Load" + }, + "filename": "/complex.k.yaml", + "line": 1, + "column": 4, + "end_line": 0, + "end_column": 0 + }, + "args": [], + "kwargs": [], + "config": { + "node": { + "!Config": { + "items": [ + { + "node": { + "key": { + "node": { + "!StringLit": { + "is_long_string": false, + "raw_value": "\"name\"", + "value": "name" + } + }, + "filename": "/complex.k.yaml", + "line": 1, + "column": 0, + "end_line": 0, + "end_column": 0 + }, + "value": { + "node": { + "!StringLit": { + "is_long_string": false, + "raw_value": "\"Alice\"", + "value": "Alice" + } + }, + "filename": "/complex.k.yaml", + "line": 1, + "column": 6, + "end_line": 0, + "end_column": 0 + }, + "operation": "Union", + "insert_index": -1 + }, + "filename": "/complex.k.yaml", + "line": 1, + "column": 4, + "end_line": 0, + "end_column": 0 + }, + { + "node": { + "key": { + "node": { + "!StringLit": { + "is_long_string": false, + "raw_value": "\"age\"", + "value": "age" + } + }, + "filename": "/complex.k.yaml", + "line": 2, + "column": 0, + "end_line": 0, + "end_column": 0 + }, + "value": { + "node": { + "!NumberLit": { + "binary_suffix": null, + "value": { + "!Int": 18 + } + } + }, + "filename": "/complex.k.yaml", + "line": 2, + "column": 5, + "end_line": 0, + "end_column": 0 + }, + "operation": "Union", + "insert_index": -1 + }, + "filename": "/complex.k.yaml", + "line": 1, + "column": 4, + "end_line": 0, + "end_column": 0 + }, + { + "node": { + "key": { + "node": { + "!StringLit": { + "is_long_string": false, + "raw_value": "\"message\"", + "value": "message" + } + }, + "filename": "/complex.k.yaml", + "line": 3, + "column": 0, + "end_line": 0, + "end_column": 0 + }, + "value": { + "node": { + "!StringLit": { + "is_long_string": false, + "raw_value": "\"This is Alice\"", + "value": "This is Alice" + } + }, + "filename": "/complex.k.yaml", + "line": 3, + "column": 9, + "end_line": 0, + "end_column": 0 + }, + "operation": "Union", + "insert_index": -1 + }, + "filename": "/complex.k.yaml", + "line": 1, + "column": 4, + "end_line": 0, + "end_column": 0 + }, + { + "node": { + "key": { + "node": { + "!StringLit": { + "is_long_string": false, + "raw_value": "\"data\"", + "value": "data" + } + }, + "filename": "/complex.k.yaml", + "line": 4, + "column": 0, + "end_line": 0, + "end_column": 0 + }, + "value": { + "node": { + "!Config": { + "items": [ + { + "node": { + "key": { + "node": { + "!StringLit": { + "is_long_string": false, + "raw_value": "\"id\"", + "value": "id" + } + }, + "filename": "/complex.k.yaml", + "line": 5, + "column": 4, + "end_line": 0, + "end_column": 0 + }, + "value": { + "node": { + "!NumberLit": { + "binary_suffix": null, + "value": { + "!Int": 1 + } + } + }, + "filename": "/complex.k.yaml", + "line": 5, + "column": 8, + "end_line": 0, + "end_column": 0 + }, + "operation": "Union", + "insert_index": -1 + }, + "filename": "/complex.k.yaml", + "line": 5, + "column": 6, + "end_line": 0, + "end_column": 0 + }, + { + "node": { + "key": { + "node": { + "!StringLit": { + "is_long_string": false, + "raw_value": "\"value\"", + "value": "value" + } + }, + "filename": "/complex.k.yaml", + "line": 6, + "column": 4, + "end_line": 0, + "end_column": 0 + }, + "value": { + "node": { + "!StringLit": { + "is_long_string": false, + "raw_value": "\"value1\"", + "value": "value1" + } + }, + "filename": "/complex.k.yaml", + "line": 6, + "column": 11, + "end_line": 0, + "end_column": 0 + }, + "operation": "Union", + "insert_index": -1 + }, + "filename": "/complex.k.yaml", + "line": 5, + "column": 6, + "end_line": 0, + "end_column": 0 + } + ] + } + }, + "filename": "/complex.k.yaml", + "line": 5, + "column": 6, + "end_line": 0, + "end_column": 0 + }, + "operation": "Union", + "insert_index": -1 + }, + "filename": "/complex.k.yaml", + "line": 1, + "column": 4, + "end_line": 0, + "end_column": 0 + }, + { + "node": { + "key": { + "node": { + "!StringLit": { + "is_long_string": false, + "raw_value": "\"labels\"", + "value": "labels" + } + }, + "filename": "/complex.k.yaml", + "line": 7, + "column": 0, + "end_line": 0, + "end_column": 0 + }, + "value": { + "node": { + "!Config": { + "items": [ + { + "node": { + "key": { + "node": { + "!StringLit": { + "is_long_string": false, + "raw_value": "\"key\"", + "value": "key" + } + }, + "filename": "/complex.k.yaml", + "line": 8, + "column": 4, + "end_line": 0, + "end_column": 0 + }, + "value": { + "node": { + "!StringLit": { + "is_long_string": false, + "raw_value": "\"value\"", + "value": "value" + } + }, + "filename": "/complex.k.yaml", + "line": 8, + "column": 9, + "end_line": 0, + "end_column": 0 + }, + "operation": "Union", + "insert_index": -1 + }, + "filename": "/complex.k.yaml", + "line": 8, + "column": 7, + "end_line": 0, + "end_column": 0 + } + ] + } + }, + "filename": "/complex.k.yaml", + "line": 8, + "column": 7, + "end_line": 0, + "end_column": 0 + }, + "operation": "Union", + "insert_index": -1 + }, + "filename": "/complex.k.yaml", + "line": 1, + "column": 4, + "end_line": 0, + "end_column": 0 + }, + { + "node": { + "key": { + "node": { + "!StringLit": { + "is_long_string": false, + "raw_value": "\"hc\"", + "value": "hc" + } + }, + "filename": "/complex.k.yaml", + "line": 9, + "column": 0, + "end_line": 0, + "end_column": 0 + }, + "value": { + "node": { + "!List": { + "elts": [ + { + "node": { + "!NumberLit": { + "binary_suffix": null, + "value": { + "!Int": 1 + } + } + }, + "filename": "/complex.k.yaml", + "line": 10, + "column": 6, + "end_line": 0, + "end_column": 0 + }, + { + "node": { + "!NumberLit": { + "binary_suffix": null, + "value": { + "!Int": 2 + } + } + }, + "filename": "/complex.k.yaml", + "line": 11, + "column": 6, + "end_line": 0, + "end_column": 0 + }, + { + "node": { + "!NumberLit": { + "binary_suffix": null, + "value": { + "!Int": 3 + } + } + }, + "filename": "/complex.k.yaml", + "line": 12, + "column": 6, + "end_line": 0, + "end_column": 0 + } + ], + "ctx": "Load" + } + }, + "filename": "/complex.k.yaml", + "line": 10, + "column": 4, + "end_line": 0, + "end_column": 0 + }, + "operation": "Union", + "insert_index": -1 + }, + "filename": "/complex.k.yaml", + "line": 1, + "column": 4, + "end_line": 0, + "end_column": 0 + } + ] + } + }, + "filename": "/complex.k.yaml", + "line": 1, + "column": 4, + "end_line": 0, + "end_column": 0 + } + } + }, + "filename": "/complex.k.yaml", + "line": 1, + "column": 4, + "end_line": 0, + "end_column": 0 +} \ No newline at end of file diff --git a/kclvm/tools/src/vet/test_datas/yaml/complex.k.yaml b/kclvm/tools/src/vet/test_datas/yaml/complex.k.yaml new file mode 100644 index 000000000..ec6d7e0cd --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/yaml/complex.k.yaml @@ -0,0 +1,12 @@ +name: Alice +age: 18 +message: This is Alice +data: + id: 1 + value: value1 +labels: + key: value +hc: + - 1 + - 2 + - 3 diff --git a/kclvm/tools/src/vet/test_datas/yaml/list.k.ast.yaml b/kclvm/tools/src/vet/test_datas/yaml/list.k.ast.yaml new file mode 100644 index 000000000..dbd19b9af --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/yaml/list.k.ast.yaml @@ -0,0 +1,179 @@ +{ + "node": { + "!List": { + "elts": [ + { + "node": { + "!Schema": { + "name": { + "node": { + "names": [ + { + "node": "list", + "filename": "/list.k.yaml", + "line": 1, + "column": 6, + "end_line": 0, + "end_column": 0 + } + ], + "pkgpath": "", + "ctx": "Load" + }, + "filename": "/list.k.yaml", + "line": 1, + "column": 6, + "end_line": 0, + "end_column": 0 + }, + "args": [], + "kwargs": [], + "config": { + "node": { + "!Config": { + "items": [ + { + "node": { + "key": { + "node": { + "!StringLit": { + "is_long_string": false, + "raw_value": "\"name\"", + "value": "name" + } + }, + "filename": "/list.k.yaml", + "line": 1, + "column": 2, + "end_line": 0, + "end_column": 0 + }, + "value": { + "node": { + "!StringLit": { + "is_long_string": false, + "raw_value": "\"Alice\"", + "value": "Alice" + } + }, + "filename": "/list.k.yaml", + "line": 1, + "column": 8, + "end_line": 0, + "end_column": 0 + }, + "operation": "Union", + "insert_index": -1 + }, + "filename": "/list.k.yaml", + "line": 1, + "column": 6, + "end_line": 0, + "end_column": 0 + }, + { + "node": { + "key": { + "node": { + "!StringLit": { + "is_long_string": false, + "raw_value": "\"age\"", + "value": "age" + } + }, + "filename": "/list.k.yaml", + "line": 2, + "column": 2, + "end_line": 0, + "end_column": 0 + }, + "value": { + "node": { + "!NumberLit": { + "binary_suffix": null, + "value": { + "!Int": 18 + } + } + }, + "filename": "/list.k.yaml", + "line": 2, + "column": 7, + "end_line": 0, + "end_column": 0 + }, + "operation": "Union", + "insert_index": -1 + }, + "filename": "/list.k.yaml", + "line": 1, + "column": 6, + "end_line": 0, + "end_column": 0 + }, + { + "node": { + "key": { + "node": { + "!StringLit": { + "is_long_string": false, + "raw_value": "\"message\"", + "value": "message" + } + }, + "filename": "/list.k.yaml", + "line": 3, + "column": 2, + "end_line": 0, + "end_column": 0 + }, + "value": { + "node": { + "!StringLit": { + "is_long_string": false, + "raw_value": "\"This is Alice\"", + "value": "This is Alice" + } + }, + "filename": "/list.k.yaml", + "line": 3, + "column": 11, + "end_line": 0, + "end_column": 0 + }, + "operation": "Union", + "insert_index": -1 + }, + "filename": "/list.k.yaml", + "line": 1, + "column": 6, + "end_line": 0, + "end_column": 0 + } + ] + } + }, + "filename": "/list.k.yaml", + "line": 1, + "column": 6, + "end_line": 0, + "end_column": 0 + } + } + }, + "filename": "/list.k.yaml", + "line": 1, + "column": 6, + "end_line": 0, + "end_column": 0 + } + ], + "ctx": "Load" + } + }, + "filename": "/list.k.yaml", + "line": 1, + "column": 0, + "end_line": 0, + "end_column": 0 +} \ No newline at end of file diff --git a/kclvm/tools/src/vet/test_datas/yaml/list.k.yaml b/kclvm/tools/src/vet/test_datas/yaml/list.k.yaml new file mode 100644 index 000000000..9ca9f4801 --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/yaml/list.k.yaml @@ -0,0 +1,4 @@ +- name: Alice + age: 18 + message: This is Alice + \ No newline at end of file diff --git a/kclvm/tools/src/vet/test_datas/yaml/no_schema_name/complex.k.ast.yaml b/kclvm/tools/src/vet/test_datas/yaml/no_schema_name/complex.k.ast.yaml new file mode 100644 index 000000000..45d0b3902 --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/yaml/no_schema_name/complex.k.ast.yaml @@ -0,0 +1,409 @@ +{ + "node": { + "!Config": { + "items": [ + { + "node": { + "key": { + "node": { + "!StringLit": { + "is_long_string": false, + "raw_value": "\"name\"", + "value": "name" + } + }, + "filename": "/complex.k.yaml", + "line": 1, + "column": 0, + "end_line": 0, + "end_column": 0 + }, + "value": { + "node": { + "!StringLit": { + "is_long_string": false, + "raw_value": "\"Alice\"", + "value": "Alice" + } + }, + "filename": "/complex.k.yaml", + "line": 1, + "column": 6, + "end_line": 0, + "end_column": 0 + }, + "operation": "Union", + "insert_index": -1 + }, + "filename": "/complex.k.yaml", + "line": 1, + "column": 4, + "end_line": 0, + "end_column": 0 + }, + { + "node": { + "key": { + "node": { + "!StringLit": { + "is_long_string": false, + "raw_value": "\"age\"", + "value": "age" + } + }, + "filename": "/complex.k.yaml", + "line": 2, + "column": 0, + "end_line": 0, + "end_column": 0 + }, + "value": { + "node": { + "!NumberLit": { + "binary_suffix": null, + "value": { + "!Int": 18 + } + } + }, + "filename": "/complex.k.yaml", + "line": 2, + "column": 5, + "end_line": 0, + "end_column": 0 + }, + "operation": "Union", + "insert_index": -1 + }, + "filename": "/complex.k.yaml", + "line": 1, + "column": 4, + "end_line": 0, + "end_column": 0 + }, + { + "node": { + "key": { + "node": { + "!StringLit": { + "is_long_string": false, + "raw_value": "\"message\"", + "value": "message" + } + }, + "filename": "/complex.k.yaml", + "line": 3, + "column": 0, + "end_line": 0, + "end_column": 0 + }, + "value": { + "node": { + "!StringLit": { + "is_long_string": false, + "raw_value": "\"This is Alice\"", + "value": "This is Alice" + } + }, + "filename": "/complex.k.yaml", + "line": 3, + "column": 9, + "end_line": 0, + "end_column": 0 + }, + "operation": "Union", + "insert_index": -1 + }, + "filename": "/complex.k.yaml", + "line": 1, + "column": 4, + "end_line": 0, + "end_column": 0 + }, + { + "node": { + "key": { + "node": { + "!StringLit": { + "is_long_string": false, + "raw_value": "\"data\"", + "value": "data" + } + }, + "filename": "/complex.k.yaml", + "line": 4, + "column": 0, + "end_line": 0, + "end_column": 0 + }, + "value": { + "node": { + "!Config": { + "items": [ + { + "node": { + "key": { + "node": { + "!StringLit": { + "is_long_string": false, + "raw_value": "\"id\"", + "value": "id" + } + }, + "filename": "/complex.k.yaml", + "line": 5, + "column": 4, + "end_line": 0, + "end_column": 0 + }, + "value": { + "node": { + "!NumberLit": { + "binary_suffix": null, + "value": { + "!Int": 1 + } + } + }, + "filename": "/complex.k.yaml", + "line": 5, + "column": 8, + "end_line": 0, + "end_column": 0 + }, + "operation": "Union", + "insert_index": -1 + }, + "filename": "/complex.k.yaml", + "line": 5, + "column": 6, + "end_line": 0, + "end_column": 0 + }, + { + "node": { + "key": { + "node": { + "!StringLit": { + "is_long_string": false, + "raw_value": "\"value\"", + "value": "value" + } + }, + "filename": "/complex.k.yaml", + "line": 6, + "column": 4, + "end_line": 0, + "end_column": 0 + }, + "value": { + "node": { + "!StringLit": { + "is_long_string": false, + "raw_value": "\"value1\"", + "value": "value1" + } + }, + "filename": "/complex.k.yaml", + "line": 6, + "column": 11, + "end_line": 0, + "end_column": 0 + }, + "operation": "Union", + "insert_index": -1 + }, + "filename": "/complex.k.yaml", + "line": 5, + "column": 6, + "end_line": 0, + "end_column": 0 + } + ] + } + }, + "filename": "/complex.k.yaml", + "line": 5, + "column": 6, + "end_line": 0, + "end_column": 0 + }, + "operation": "Union", + "insert_index": -1 + }, + "filename": "/complex.k.yaml", + "line": 1, + "column": 4, + "end_line": 0, + "end_column": 0 + }, + { + "node": { + "key": { + "node": { + "!StringLit": { + "is_long_string": false, + "raw_value": "\"labels\"", + "value": "labels" + } + }, + "filename": "/complex.k.yaml", + "line": 7, + "column": 0, + "end_line": 0, + "end_column": 0 + }, + "value": { + "node": { + "!Config": { + "items": [ + { + "node": { + "key": { + "node": { + "!StringLit": { + "is_long_string": false, + "raw_value": "\"key\"", + "value": "key" + } + }, + "filename": "/complex.k.yaml", + "line": 8, + "column": 4, + "end_line": 0, + "end_column": 0 + }, + "value": { + "node": { + "!StringLit": { + "is_long_string": false, + "raw_value": "\"value\"", + "value": "value" + } + }, + "filename": "/complex.k.yaml", + "line": 8, + "column": 9, + "end_line": 0, + "end_column": 0 + }, + "operation": "Union", + "insert_index": -1 + }, + "filename": "/complex.k.yaml", + "line": 8, + "column": 7, + "end_line": 0, + "end_column": 0 + } + ] + } + }, + "filename": "/complex.k.yaml", + "line": 8, + "column": 7, + "end_line": 0, + "end_column": 0 + }, + "operation": "Union", + "insert_index": -1 + }, + "filename": "/complex.k.yaml", + "line": 1, + "column": 4, + "end_line": 0, + "end_column": 0 + }, + { + "node": { + "key": { + "node": { + "!StringLit": { + "is_long_string": false, + "raw_value": "\"hc\"", + "value": "hc" + } + }, + "filename": "/complex.k.yaml", + "line": 9, + "column": 0, + "end_line": 0, + "end_column": 0 + }, + "value": { + "node": { + "!List": { + "elts": [ + { + "node": { + "!NumberLit": { + "binary_suffix": null, + "value": { + "!Int": 1 + } + } + }, + "filename": "/complex.k.yaml", + "line": 10, + "column": 6, + "end_line": 0, + "end_column": 0 + }, + { + "node": { + "!NumberLit": { + "binary_suffix": null, + "value": { + "!Int": 2 + } + } + }, + "filename": "/complex.k.yaml", + "line": 11, + "column": 6, + "end_line": 0, + "end_column": 0 + }, + { + "node": { + "!NumberLit": { + "binary_suffix": null, + "value": { + "!Int": 3 + } + } + }, + "filename": "/complex.k.yaml", + "line": 12, + "column": 6, + "end_line": 0, + "end_column": 0 + } + ], + "ctx": "Load" + } + }, + "filename": "/complex.k.yaml", + "line": 10, + "column": 4, + "end_line": 0, + "end_column": 0 + }, + "operation": "Union", + "insert_index": -1 + }, + "filename": "/complex.k.yaml", + "line": 1, + "column": 4, + "end_line": 0, + "end_column": 0 + } + ] + } + }, + "filename": "/complex.k.yaml", + "line": 1, + "column": 4, + "end_line": 0, + "end_column": 0 +} \ No newline at end of file diff --git a/kclvm/tools/src/vet/test_datas/yaml/no_schema_name/list.k.ast.yaml b/kclvm/tools/src/vet/test_datas/yaml/no_schema_name/list.k.ast.yaml new file mode 100644 index 000000000..e79438795 --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/yaml/no_schema_name/list.k.ast.yaml @@ -0,0 +1,145 @@ +{ + "node": { + "!List": { + "elts": [ + { + "node": { + "!Config": { + "items": [ + { + "node": { + "key": { + "node": { + "!StringLit": { + "is_long_string": false, + "raw_value": "\"name\"", + "value": "name" + } + }, + "filename": "/list.k.yaml", + "line": 1, + "column": 2, + "end_line": 0, + "end_column": 0 + }, + "value": { + "node": { + "!StringLit": { + "is_long_string": false, + "raw_value": "\"Alice\"", + "value": "Alice" + } + }, + "filename": "/list.k.yaml", + "line": 1, + "column": 8, + "end_line": 0, + "end_column": 0 + }, + "operation": "Union", + "insert_index": -1 + }, + "filename": "/list.k.yaml", + "line": 1, + "column": 6, + "end_line": 0, + "end_column": 0 + }, + { + "node": { + "key": { + "node": { + "!StringLit": { + "is_long_string": false, + "raw_value": "\"age\"", + "value": "age" + } + }, + "filename": "/list.k.yaml", + "line": 2, + "column": 2, + "end_line": 0, + "end_column": 0 + }, + "value": { + "node": { + "!NumberLit": { + "binary_suffix": null, + "value": { + "!Int": 18 + } + } + }, + "filename": "/list.k.yaml", + "line": 2, + "column": 7, + "end_line": 0, + "end_column": 0 + }, + "operation": "Union", + "insert_index": -1 + }, + "filename": "/list.k.yaml", + "line": 1, + "column": 6, + "end_line": 0, + "end_column": 0 + }, + { + "node": { + "key": { + "node": { + "!StringLit": { + "is_long_string": false, + "raw_value": "\"message\"", + "value": "message" + } + }, + "filename": "/list.k.yaml", + "line": 3, + "column": 2, + "end_line": 0, + "end_column": 0 + }, + "value": { + "node": { + "!StringLit": { + "is_long_string": false, + "raw_value": "\"This is Alice\"", + "value": "This is Alice" + } + }, + "filename": "/list.k.yaml", + "line": 3, + "column": 11, + "end_line": 0, + "end_column": 0 + }, + "operation": "Union", + "insert_index": -1 + }, + "filename": "/list.k.yaml", + "line": 1, + "column": 6, + "end_line": 0, + "end_column": 0 + } + ] + } + }, + "filename": "/list.k.yaml", + "line": 1, + "column": 6, + "end_line": 0, + "end_column": 0 + } + ], + "ctx": "Load" + } + }, + "filename": "/list.k.yaml", + "line": 1, + "column": 0, + "end_line": 0, + "end_column": 0 +} \ No newline at end of file diff --git a/kclvm/tools/src/vet/test_datas/yaml/no_schema_name/only_with_bool.ast.yaml b/kclvm/tools/src/vet/test_datas/yaml/no_schema_name/only_with_bool.ast.yaml new file mode 100644 index 000000000..fe0d8abda --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/yaml/no_schema_name/only_with_bool.ast.yaml @@ -0,0 +1,50 @@ +{ + "node": { + "!Config": { + "items": [ + { + "node": { + "key": { + "node": { + "!StringLit": { + "is_long_string": false, + "raw_value": "\"bool_val\"", + "value": "bool_val" + } + }, + "filename": "/only_with_bool.yaml", + "line": 1, + "column": 0, + "end_line": 0, + "end_column": 0 + }, + "value": { + "node": { + "!NameConstantLit": { + "value": "True" + } + }, + "filename": "/only_with_bool.yaml", + "line": 1, + "column": 10, + "end_line": 0, + "end_column": 0 + }, + "operation": "Union", + "insert_index": -1 + }, + "filename": "/only_with_bool.yaml", + "line": 1, + "column": 8, + "end_line": 0, + "end_column": 0 + } + ] + } + }, + "filename": "/only_with_bool.yaml", + "line": 1, + "column": 8, + "end_line": 0, + "end_column": 0 +} \ No newline at end of file diff --git a/kclvm/tools/src/vet/test_datas/yaml/no_schema_name/only_with_float.ast.yaml b/kclvm/tools/src/vet/test_datas/yaml/no_schema_name/only_with_float.ast.yaml new file mode 100644 index 000000000..931b4e4ed --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/yaml/no_schema_name/only_with_float.ast.yaml @@ -0,0 +1,53 @@ +{ + "node": { + "!Config": { + "items": [ + { + "node": { + "key": { + "node": { + "!StringLit": { + "is_long_string": false, + "raw_value": "\"float_val\"", + "value": "float_val" + } + }, + "filename": "/only_with_float.yaml", + "line": 1, + "column": 0, + "end_line": 0, + "end_column": 0 + }, + "value": { + "node": { + "!NumberLit": { + "binary_suffix": null, + "value": { + "!Float": 0.33 + } + } + }, + "filename": "/only_with_float.yaml", + "line": 1, + "column": 11, + "end_line": 0, + "end_column": 0 + }, + "operation": "Union", + "insert_index": -1 + }, + "filename": "/only_with_float.yaml", + "line": 1, + "column": 9, + "end_line": 0, + "end_column": 0 + } + ] + } + }, + "filename": "/only_with_float.yaml", + "line": 1, + "column": 9, + "end_line": 0, + "end_column": 0 +} \ No newline at end of file diff --git a/kclvm/tools/src/vet/test_datas/yaml/no_schema_name/only_with_null.ast.yaml b/kclvm/tools/src/vet/test_datas/yaml/no_schema_name/only_with_null.ast.yaml new file mode 100644 index 000000000..9ddf82fb5 --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/yaml/no_schema_name/only_with_null.ast.yaml @@ -0,0 +1,50 @@ +{ + "node": { + "!Config": { + "items": [ + { + "node": { + "key": { + "node": { + "!StringLit": { + "is_long_string": false, + "raw_value": "\"null_val\"", + "value": "null_val" + } + }, + "filename": "/only_with_null.yaml", + "line": 1, + "column": 0, + "end_line": 0, + "end_column": 0 + }, + "value": { + "node": { + "!NameConstantLit": { + "value": "None" + } + }, + "filename": "/only_with_null.yaml", + "line": 1, + "column": 10, + "end_line": 0, + "end_column": 0 + }, + "operation": "Union", + "insert_index": -1 + }, + "filename": "/only_with_null.yaml", + "line": 1, + "column": 8, + "end_line": 0, + "end_column": 0 + } + ] + } + }, + "filename": "/only_with_null.yaml", + "line": 1, + "column": 8, + "end_line": 0, + "end_column": 0 +} \ No newline at end of file diff --git a/kclvm/tools/src/vet/test_datas/yaml/no_schema_name/plain_value.k.ast.yaml b/kclvm/tools/src/vet/test_datas/yaml/no_schema_name/plain_value.k.ast.yaml new file mode 100644 index 000000000..e94a58580 --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/yaml/no_schema_name/plain_value.k.ast.yaml @@ -0,0 +1,15 @@ +{ + "node": { + "!NumberLit": { + "binary_suffix": null, + "value": { + "!Int": 1 + } + } + }, + "filename": "/plain_value.k.yaml", + "line": 1, + "column": 0, + "end_line": 0, + "end_column": 0 +} \ No newline at end of file diff --git a/kclvm/tools/src/vet/test_datas/yaml/no_schema_name/simple.k.ast.yaml b/kclvm/tools/src/vet/test_datas/yaml/no_schema_name/simple.k.ast.yaml new file mode 100644 index 000000000..4a83ae487 --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/yaml/no_schema_name/simple.k.ast.yaml @@ -0,0 +1,130 @@ +{ + "node": { + "!Config": { + "items": [ + { + "node": { + "key": { + "node": { + "!StringLit": { + "is_long_string": false, + "raw_value": "\"name\"", + "value": "name" + } + }, + "filename": "/simple.k.yaml", + "line": 1, + "column": 0, + "end_line": 0, + "end_column": 0 + }, + "value": { + "node": { + "!StringLit": { + "is_long_string": false, + "raw_value": "\"Alice,\"", + "value": "Alice," + } + }, + "filename": "/simple.k.yaml", + "line": 1, + "column": 6, + "end_line": 0, + "end_column": 0 + }, + "operation": "Union", + "insert_index": -1 + }, + "filename": "/simple.k.yaml", + "line": 1, + "column": 4, + "end_line": 0, + "end_column": 0 + }, + { + "node": { + "key": { + "node": { + "!StringLit": { + "is_long_string": false, + "raw_value": "\"age\"", + "value": "age" + } + }, + "filename": "/simple.k.yaml", + "line": 2, + "column": 0, + "end_line": 0, + "end_column": 0 + }, + "value": { + "node": { + "!StringLit": { + "is_long_string": false, + "raw_value": "\"18,\"", + "value": "18," + } + }, + "filename": "/simple.k.yaml", + "line": 2, + "column": 5, + "end_line": 0, + "end_column": 0 + }, + "operation": "Union", + "insert_index": -1 + }, + "filename": "/simple.k.yaml", + "line": 1, + "column": 4, + "end_line": 0, + "end_column": 0 + }, + { + "node": { + "key": { + "node": { + "!StringLit": { + "is_long_string": false, + "raw_value": "\"message\"", + "value": "message" + } + }, + "filename": "/simple.k.yaml", + "line": 3, + "column": 0, + "end_line": 0, + "end_column": 0 + }, + "value": { + "node": { + "!StringLit": { + "is_long_string": false, + "raw_value": "\"This is Alice\"", + "value": "This is Alice" + } + }, + "filename": "/simple.k.yaml", + "line": 3, + "column": 9, + "end_line": 0, + "end_column": 0 + }, + "operation": "Union", + "insert_index": -1 + }, + "filename": "/simple.k.yaml", + "line": 1, + "column": 4, + "end_line": 0, + "end_column": 0 + } + ] + } + }, + "filename": "/simple.k.yaml", + "line": 1, + "column": 4, + "end_line": 0, + "end_column": 0 +} \ No newline at end of file diff --git a/kclvm/tools/src/vet/test_datas/yaml/no_schema_name/test.k.ast.yaml b/kclvm/tools/src/vet/test_datas/yaml/no_schema_name/test.k.ast.yaml new file mode 100644 index 000000000..dab696bad --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/yaml/no_schema_name/test.k.ast.yaml @@ -0,0 +1,288 @@ +{ + "node": { + "!Config": { + "items": [ + { + "node": { + "key": { + "node": { + "!StringLit": { + "is_long_string": false, + "raw_value": "\"languages\"", + "value": "languages" + } + }, + "filename": "/test.k.yaml", + "line": 1, + "column": 0, + "end_line": 0, + "end_column": 0 + }, + "value": { + "node": { + "!List": { + "elts": [ + { + "node": { + "!StringLit": { + "is_long_string": false, + "raw_value": "\"Ruby\"", + "value": "Ruby" + } + }, + "filename": "/test.k.yaml", + "line": 2, + "column": 4, + "end_line": 0, + "end_column": 0 + }, + { + "node": { + "!StringLit": { + "is_long_string": false, + "raw_value": "\"Perl\"", + "value": "Perl" + } + }, + "filename": "/test.k.yaml", + "line": 3, + "column": 4, + "end_line": 0, + "end_column": 0 + }, + { + "node": { + "!StringLit": { + "is_long_string": false, + "raw_value": "\"Python\"", + "value": "Python" + } + }, + "filename": "/test.k.yaml", + "line": 4, + "column": 4, + "end_line": 0, + "end_column": 0 + } + ], + "ctx": "Load" + } + }, + "filename": "/test.k.yaml", + "line": 2, + "column": 2, + "end_line": 0, + "end_column": 0 + }, + "operation": "Union", + "insert_index": -1 + }, + "filename": "/test.k.yaml", + "line": 1, + "column": 9, + "end_line": 0, + "end_column": 0 + }, + { + "node": { + "key": { + "node": { + "!StringLit": { + "is_long_string": false, + "raw_value": "\"websites\"", + "value": "websites" + } + }, + "filename": "/test.k.yaml", + "line": 5, + "column": 0, + "end_line": 0, + "end_column": 0 + }, + "value": { + "node": { + "!Config": { + "items": [ + { + "node": { + "key": { + "node": { + "!StringLit": { + "is_long_string": false, + "raw_value": "\"YAML\"", + "value": "YAML" + } + }, + "filename": "/test.k.yaml", + "line": 6, + "column": 2, + "end_line": 0, + "end_column": 0 + }, + "value": { + "node": { + "!StringLit": { + "is_long_string": false, + "raw_value": "\"yaml.org\"", + "value": "yaml.org" + } + }, + "filename": "/test.k.yaml", + "line": 6, + "column": 8, + "end_line": 0, + "end_column": 0 + }, + "operation": "Union", + "insert_index": -1 + }, + "filename": "/test.k.yaml", + "line": 6, + "column": 6, + "end_line": 0, + "end_column": 0 + }, + { + "node": { + "key": { + "node": { + "!StringLit": { + "is_long_string": false, + "raw_value": "\"Ruby\"", + "value": "Ruby" + } + }, + "filename": "/test.k.yaml", + "line": 7, + "column": 2, + "end_line": 0, + "end_column": 0 + }, + "value": { + "node": { + "!StringLit": { + "is_long_string": false, + "raw_value": "\"ruby-lang.org\"", + "value": "ruby-lang.org" + } + }, + "filename": "/test.k.yaml", + "line": 7, + "column": 8, + "end_line": 0, + "end_column": 0 + }, + "operation": "Union", + "insert_index": -1 + }, + "filename": "/test.k.yaml", + "line": 6, + "column": 6, + "end_line": 0, + "end_column": 0 + }, + { + "node": { + "key": { + "node": { + "!StringLit": { + "is_long_string": false, + "raw_value": "\"Python\"", + "value": "Python" + } + }, + "filename": "/test.k.yaml", + "line": 8, + "column": 2, + "end_line": 0, + "end_column": 0 + }, + "value": { + "node": { + "!StringLit": { + "is_long_string": false, + "raw_value": "\"python.org\"", + "value": "python.org" + } + }, + "filename": "/test.k.yaml", + "line": 8, + "column": 10, + "end_line": 0, + "end_column": 0 + }, + "operation": "Union", + "insert_index": -1 + }, + "filename": "/test.k.yaml", + "line": 6, + "column": 6, + "end_line": 0, + "end_column": 0 + }, + { + "node": { + "key": { + "node": { + "!StringLit": { + "is_long_string": false, + "raw_value": "\"Perl\"", + "value": "Perl" + } + }, + "filename": "/test.k.yaml", + "line": 9, + "column": 2, + "end_line": 0, + "end_column": 0 + }, + "value": { + "node": { + "!StringLit": { + "is_long_string": false, + "raw_value": "\"use.perl.org\"", + "value": "use.perl.org" + } + }, + "filename": "/test.k.yaml", + "line": 9, + "column": 8, + "end_line": 0, + "end_column": 0 + }, + "operation": "Union", + "insert_index": -1 + }, + "filename": "/test.k.yaml", + "line": 6, + "column": 6, + "end_line": 0, + "end_column": 0 + } + ] + } + }, + "filename": "/test.k.yaml", + "line": 6, + "column": 6, + "end_line": 0, + "end_column": 0 + }, + "operation": "Union", + "insert_index": -1 + }, + "filename": "/test.k.yaml", + "line": 1, + "column": 9, + "end_line": 0, + "end_column": 0 + } + ] + } + }, + "filename": "/test.k.yaml", + "line": 1, + "column": 9, + "end_line": 0, + "end_column": 0 +} \ No newline at end of file diff --git a/kclvm/tools/src/vet/test_datas/yaml/only_with_bool.ast.yaml b/kclvm/tools/src/vet/test_datas/yaml/only_with_bool.ast.yaml new file mode 100644 index 000000000..d0defd343 --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/yaml/only_with_bool.ast.yaml @@ -0,0 +1,84 @@ +{ + "node": { + "!Schema": { + "name": { + "node": { + "names": [ + { + "node": "only_with_bool", + "filename": "/only_with_bool.yaml", + "line": 1, + "column": 8, + "end_line": 0, + "end_column": 0 + } + ], + "pkgpath": "", + "ctx": "Load" + }, + "filename": "/only_with_bool.yaml", + "line": 1, + "column": 8, + "end_line": 0, + "end_column": 0 + }, + "args": [], + "kwargs": [], + "config": { + "node": { + "!Config": { + "items": [ + { + "node": { + "key": { + "node": { + "!StringLit": { + "is_long_string": false, + "raw_value": "\"bool_val\"", + "value": "bool_val" + } + }, + "filename": "/only_with_bool.yaml", + "line": 1, + "column": 0, + "end_line": 0, + "end_column": 0 + }, + "value": { + "node": { + "!NameConstantLit": { + "value": "True" + } + }, + "filename": "/only_with_bool.yaml", + "line": 1, + "column": 10, + "end_line": 0, + "end_column": 0 + }, + "operation": "Union", + "insert_index": -1 + }, + "filename": "/only_with_bool.yaml", + "line": 1, + "column": 8, + "end_line": 0, + "end_column": 0 + } + ] + } + }, + "filename": "/only_with_bool.yaml", + "line": 1, + "column": 8, + "end_line": 0, + "end_column": 0 + } + } + }, + "filename": "/only_with_bool.yaml", + "line": 1, + "column": 8, + "end_line": 0, + "end_column": 0 +} \ No newline at end of file diff --git a/kclvm/tools/src/vet/test_datas/yaml/only_with_bool.yaml b/kclvm/tools/src/vet/test_datas/yaml/only_with_bool.yaml new file mode 100644 index 000000000..f95f38f53 --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/yaml/only_with_bool.yaml @@ -0,0 +1 @@ +bool_val: true diff --git a/kclvm/tools/src/vet/test_datas/yaml/only_with_float.ast.yaml b/kclvm/tools/src/vet/test_datas/yaml/only_with_float.ast.yaml new file mode 100644 index 000000000..97e725388 --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/yaml/only_with_float.ast.yaml @@ -0,0 +1,87 @@ +{ + "node": { + "!Schema": { + "name": { + "node": { + "names": [ + { + "node": "only_with_float", + "filename": "/only_with_float.yaml", + "line": 1, + "column": 9, + "end_line": 0, + "end_column": 0 + } + ], + "pkgpath": "", + "ctx": "Load" + }, + "filename": "/only_with_float.yaml", + "line": 1, + "column": 9, + "end_line": 0, + "end_column": 0 + }, + "args": [], + "kwargs": [], + "config": { + "node": { + "!Config": { + "items": [ + { + "node": { + "key": { + "node": { + "!StringLit": { + "is_long_string": false, + "raw_value": "\"float_val\"", + "value": "float_val" + } + }, + "filename": "/only_with_float.yaml", + "line": 1, + "column": 0, + "end_line": 0, + "end_column": 0 + }, + "value": { + "node": { + "!NumberLit": { + "binary_suffix": null, + "value": { + "!Float": 0.33 + } + } + }, + "filename": "/only_with_float.yaml", + "line": 1, + "column": 11, + "end_line": 0, + "end_column": 0 + }, + "operation": "Union", + "insert_index": -1 + }, + "filename": "/only_with_float.yaml", + "line": 1, + "column": 9, + "end_line": 0, + "end_column": 0 + } + ] + } + }, + "filename": "/only_with_float.yaml", + "line": 1, + "column": 9, + "end_line": 0, + "end_column": 0 + } + } + }, + "filename": "/only_with_float.yaml", + "line": 1, + "column": 9, + "end_line": 0, + "end_column": 0 +} \ No newline at end of file diff --git a/kclvm/tools/src/vet/test_datas/yaml/only_with_float.yaml b/kclvm/tools/src/vet/test_datas/yaml/only_with_float.yaml new file mode 100644 index 000000000..910ecfea9 --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/yaml/only_with_float.yaml @@ -0,0 +1 @@ +float_val: 0.33 diff --git a/kclvm/tools/src/vet/test_datas/yaml/only_with_null.ast.yaml b/kclvm/tools/src/vet/test_datas/yaml/only_with_null.ast.yaml new file mode 100644 index 000000000..22ab167c1 --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/yaml/only_with_null.ast.yaml @@ -0,0 +1,84 @@ +{ + "node": { + "!Schema": { + "name": { + "node": { + "names": [ + { + "node": "only_with_null", + "filename": "/only_with_null.yaml", + "line": 1, + "column": 8, + "end_line": 0, + "end_column": 0 + } + ], + "pkgpath": "", + "ctx": "Load" + }, + "filename": "/only_with_null.yaml", + "line": 1, + "column": 8, + "end_line": 0, + "end_column": 0 + }, + "args": [], + "kwargs": [], + "config": { + "node": { + "!Config": { + "items": [ + { + "node": { + "key": { + "node": { + "!StringLit": { + "is_long_string": false, + "raw_value": "\"null_val\"", + "value": "null_val" + } + }, + "filename": "/only_with_null.yaml", + "line": 1, + "column": 0, + "end_line": 0, + "end_column": 0 + }, + "value": { + "node": { + "!NameConstantLit": { + "value": "None" + } + }, + "filename": "/only_with_null.yaml", + "line": 1, + "column": 10, + "end_line": 0, + "end_column": 0 + }, + "operation": "Union", + "insert_index": -1 + }, + "filename": "/only_with_null.yaml", + "line": 1, + "column": 8, + "end_line": 0, + "end_column": 0 + } + ] + } + }, + "filename": "/only_with_null.yaml", + "line": 1, + "column": 8, + "end_line": 0, + "end_column": 0 + } + } + }, + "filename": "/only_with_null.yaml", + "line": 1, + "column": 8, + "end_line": 0, + "end_column": 0 +} \ No newline at end of file diff --git a/kclvm/tools/src/vet/test_datas/yaml/only_with_null.yaml b/kclvm/tools/src/vet/test_datas/yaml/only_with_null.yaml new file mode 100644 index 000000000..5f508c6a2 --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/yaml/only_with_null.yaml @@ -0,0 +1 @@ +null_val: ~ diff --git a/kclvm/tools/src/vet/test_datas/yaml/plain_value.k.ast.yaml b/kclvm/tools/src/vet/test_datas/yaml/plain_value.k.ast.yaml new file mode 100644 index 000000000..e94a58580 --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/yaml/plain_value.k.ast.yaml @@ -0,0 +1,15 @@ +{ + "node": { + "!NumberLit": { + "binary_suffix": null, + "value": { + "!Int": 1 + } + } + }, + "filename": "/plain_value.k.yaml", + "line": 1, + "column": 0, + "end_line": 0, + "end_column": 0 +} \ No newline at end of file diff --git a/kclvm/tools/src/vet/test_datas/yaml/plain_value.k.yaml b/kclvm/tools/src/vet/test_datas/yaml/plain_value.k.yaml new file mode 100644 index 000000000..d00491fd7 --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/yaml/plain_value.k.yaml @@ -0,0 +1 @@ +1 diff --git a/kclvm/tools/src/vet/test_datas/yaml/simple.k.ast.yaml b/kclvm/tools/src/vet/test_datas/yaml/simple.k.ast.yaml new file mode 100644 index 000000000..e2898cb74 --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/yaml/simple.k.ast.yaml @@ -0,0 +1,164 @@ +{ + "node": { + "!Schema": { + "name": { + "node": { + "names": [ + { + "node": "simple", + "filename": "/simple.k.yaml", + "line": 1, + "column": 4, + "end_line": 0, + "end_column": 0 + } + ], + "pkgpath": "", + "ctx": "Load" + }, + "filename": "/simple.k.yaml", + "line": 1, + "column": 4, + "end_line": 0, + "end_column": 0 + }, + "args": [], + "kwargs": [], + "config": { + "node": { + "!Config": { + "items": [ + { + "node": { + "key": { + "node": { + "!StringLit": { + "is_long_string": false, + "raw_value": "\"name\"", + "value": "name" + } + }, + "filename": "/simple.k.yaml", + "line": 1, + "column": 0, + "end_line": 0, + "end_column": 0 + }, + "value": { + "node": { + "!StringLit": { + "is_long_string": false, + "raw_value": "\"Alice,\"", + "value": "Alice," + } + }, + "filename": "/simple.k.yaml", + "line": 1, + "column": 6, + "end_line": 0, + "end_column": 0 + }, + "operation": "Union", + "insert_index": -1 + }, + "filename": "/simple.k.yaml", + "line": 1, + "column": 4, + "end_line": 0, + "end_column": 0 + }, + { + "node": { + "key": { + "node": { + "!StringLit": { + "is_long_string": false, + "raw_value": "\"age\"", + "value": "age" + } + }, + "filename": "/simple.k.yaml", + "line": 2, + "column": 0, + "end_line": 0, + "end_column": 0 + }, + "value": { + "node": { + "!StringLit": { + "is_long_string": false, + "raw_value": "\"18,\"", + "value": "18," + } + }, + "filename": "/simple.k.yaml", + "line": 2, + "column": 5, + "end_line": 0, + "end_column": 0 + }, + "operation": "Union", + "insert_index": -1 + }, + "filename": "/simple.k.yaml", + "line": 1, + "column": 4, + "end_line": 0, + "end_column": 0 + }, + { + "node": { + "key": { + "node": { + "!StringLit": { + "is_long_string": false, + "raw_value": "\"message\"", + "value": "message" + } + }, + "filename": "/simple.k.yaml", + "line": 3, + "column": 0, + "end_line": 0, + "end_column": 0 + }, + "value": { + "node": { + "!StringLit": { + "is_long_string": false, + "raw_value": "\"This is Alice\"", + "value": "This is Alice" + } + }, + "filename": "/simple.k.yaml", + "line": 3, + "column": 9, + "end_line": 0, + "end_column": 0 + }, + "operation": "Union", + "insert_index": -1 + }, + "filename": "/simple.k.yaml", + "line": 1, + "column": 4, + "end_line": 0, + "end_column": 0 + } + ] + } + }, + "filename": "/simple.k.yaml", + "line": 1, + "column": 4, + "end_line": 0, + "end_column": 0 + } + } + }, + "filename": "/simple.k.yaml", + "line": 1, + "column": 4, + "end_line": 0, + "end_column": 0 +} \ No newline at end of file diff --git a/kclvm/tools/src/vet/test_datas/yaml/simple.k.yaml b/kclvm/tools/src/vet/test_datas/yaml/simple.k.yaml new file mode 100644 index 000000000..6d0e1a006 --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/yaml/simple.k.yaml @@ -0,0 +1,3 @@ +name: Alice, +age: 18, +message: This is Alice diff --git a/kclvm/tools/src/vet/test_datas/yaml/test.k.ast.yaml b/kclvm/tools/src/vet/test_datas/yaml/test.k.ast.yaml new file mode 100644 index 000000000..e65e74bed --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/yaml/test.k.ast.yaml @@ -0,0 +1,322 @@ +{ + "node": { + "!Schema": { + "name": { + "node": { + "names": [ + { + "node": "test", + "filename": "/test.k.yaml", + "line": 1, + "column": 9, + "end_line": 0, + "end_column": 0 + } + ], + "pkgpath": "", + "ctx": "Load" + }, + "filename": "/test.k.yaml", + "line": 1, + "column": 9, + "end_line": 0, + "end_column": 0 + }, + "args": [], + "kwargs": [], + "config": { + "node": { + "!Config": { + "items": [ + { + "node": { + "key": { + "node": { + "!StringLit": { + "is_long_string": false, + "raw_value": "\"languages\"", + "value": "languages" + } + }, + "filename": "/test.k.yaml", + "line": 1, + "column": 0, + "end_line": 0, + "end_column": 0 + }, + "value": { + "node": { + "!List": { + "elts": [ + { + "node": { + "!StringLit": { + "is_long_string": false, + "raw_value": "\"Ruby\"", + "value": "Ruby" + } + }, + "filename": "/test.k.yaml", + "line": 2, + "column": 4, + "end_line": 0, + "end_column": 0 + }, + { + "node": { + "!StringLit": { + "is_long_string": false, + "raw_value": "\"Perl\"", + "value": "Perl" + } + }, + "filename": "/test.k.yaml", + "line": 3, + "column": 4, + "end_line": 0, + "end_column": 0 + }, + { + "node": { + "!StringLit": { + "is_long_string": false, + "raw_value": "\"Python\"", + "value": "Python" + } + }, + "filename": "/test.k.yaml", + "line": 4, + "column": 4, + "end_line": 0, + "end_column": 0 + } + ], + "ctx": "Load" + } + }, + "filename": "/test.k.yaml", + "line": 2, + "column": 2, + "end_line": 0, + "end_column": 0 + }, + "operation": "Union", + "insert_index": -1 + }, + "filename": "/test.k.yaml", + "line": 1, + "column": 9, + "end_line": 0, + "end_column": 0 + }, + { + "node": { + "key": { + "node": { + "!StringLit": { + "is_long_string": false, + "raw_value": "\"websites\"", + "value": "websites" + } + }, + "filename": "/test.k.yaml", + "line": 5, + "column": 0, + "end_line": 0, + "end_column": 0 + }, + "value": { + "node": { + "!Config": { + "items": [ + { + "node": { + "key": { + "node": { + "!StringLit": { + "is_long_string": false, + "raw_value": "\"YAML\"", + "value": "YAML" + } + }, + "filename": "/test.k.yaml", + "line": 6, + "column": 2, + "end_line": 0, + "end_column": 0 + }, + "value": { + "node": { + "!StringLit": { + "is_long_string": false, + "raw_value": "\"yaml.org\"", + "value": "yaml.org" + } + }, + "filename": "/test.k.yaml", + "line": 6, + "column": 8, + "end_line": 0, + "end_column": 0 + }, + "operation": "Union", + "insert_index": -1 + }, + "filename": "/test.k.yaml", + "line": 6, + "column": 6, + "end_line": 0, + "end_column": 0 + }, + { + "node": { + "key": { + "node": { + "!StringLit": { + "is_long_string": false, + "raw_value": "\"Ruby\"", + "value": "Ruby" + } + }, + "filename": "/test.k.yaml", + "line": 7, + "column": 2, + "end_line": 0, + "end_column": 0 + }, + "value": { + "node": { + "!StringLit": { + "is_long_string": false, + "raw_value": "\"ruby-lang.org\"", + "value": "ruby-lang.org" + } + }, + "filename": "/test.k.yaml", + "line": 7, + "column": 8, + "end_line": 0, + "end_column": 0 + }, + "operation": "Union", + "insert_index": -1 + }, + "filename": "/test.k.yaml", + "line": 6, + "column": 6, + "end_line": 0, + "end_column": 0 + }, + { + "node": { + "key": { + "node": { + "!StringLit": { + "is_long_string": false, + "raw_value": "\"Python\"", + "value": "Python" + } + }, + "filename": "/test.k.yaml", + "line": 8, + "column": 2, + "end_line": 0, + "end_column": 0 + }, + "value": { + "node": { + "!StringLit": { + "is_long_string": false, + "raw_value": "\"python.org\"", + "value": "python.org" + } + }, + "filename": "/test.k.yaml", + "line": 8, + "column": 10, + "end_line": 0, + "end_column": 0 + }, + "operation": "Union", + "insert_index": -1 + }, + "filename": "/test.k.yaml", + "line": 6, + "column": 6, + "end_line": 0, + "end_column": 0 + }, + { + "node": { + "key": { + "node": { + "!StringLit": { + "is_long_string": false, + "raw_value": "\"Perl\"", + "value": "Perl" + } + }, + "filename": "/test.k.yaml", + "line": 9, + "column": 2, + "end_line": 0, + "end_column": 0 + }, + "value": { + "node": { + "!StringLit": { + "is_long_string": false, + "raw_value": "\"use.perl.org\"", + "value": "use.perl.org" + } + }, + "filename": "/test.k.yaml", + "line": 9, + "column": 8, + "end_line": 0, + "end_column": 0 + }, + "operation": "Union", + "insert_index": -1 + }, + "filename": "/test.k.yaml", + "line": 6, + "column": 6, + "end_line": 0, + "end_column": 0 + } + ] + } + }, + "filename": "/test.k.yaml", + "line": 6, + "column": 6, + "end_line": 0, + "end_column": 0 + }, + "operation": "Union", + "insert_index": -1 + }, + "filename": "/test.k.yaml", + "line": 1, + "column": 9, + "end_line": 0, + "end_column": 0 + } + ] + } + }, + "filename": "/test.k.yaml", + "line": 1, + "column": 9, + "end_line": 0, + "end_column": 0 + } + } + }, + "filename": "/test.k.yaml", + "line": 1, + "column": 9, + "end_line": 0, + "end_column": 0 +} \ No newline at end of file diff --git a/kclvm/tools/src/vet/test_datas/yaml/test.k.yaml b/kclvm/tools/src/vet/test_datas/yaml/test.k.yaml new file mode 100644 index 000000000..f6016b17b --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/yaml/test.k.yaml @@ -0,0 +1,9 @@ +languages: + - Ruby + - Perl + - Python +websites: + YAML: yaml.org + Ruby: ruby-lang.org + Python: python.org + Perl: use.perl.org diff --git a/kclvm/tools/src/vet/test_datas/yaml_win/complex.k.ast.yaml b/kclvm/tools/src/vet/test_datas/yaml_win/complex.k.ast.yaml new file mode 100644 index 000000000..5047ccbaf --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/yaml_win/complex.k.ast.yaml @@ -0,0 +1 @@ +{"node":{"!Schema":{"name":{"node":{"names":[{"node":"complex","filename":"/complex.k.yaml","line":1,"column":4,"end_line":0,"end_column":0}],"pkgpath":"","ctx":"Load"},"filename":"/complex.k.yaml","line":1,"column":4,"end_line":0,"end_column":0},"args":[],"kwargs":[],"config":{"node":{"!Config":{"items":[{"node":{"key":{"node":{"!StringLit":{"is_long_string":false,"raw_value":"\"name\"","value":"name"}},"filename":"/complex.k.yaml","line":1,"column":0,"end_line":0,"end_column":0},"value":{"node":{"!StringLit":{"is_long_string":false,"raw_value":"\"Alice\"","value":"Alice"}},"filename":"/complex.k.yaml","line":1,"column":6,"end_line":0,"end_column":0},"operation":"Union","insert_index":-1},"filename":"/complex.k.yaml","line":1,"column":4,"end_line":0,"end_column":0},{"node":{"key":{"node":{"!StringLit":{"is_long_string":false,"raw_value":"\"age\"","value":"age"}},"filename":"/complex.k.yaml","line":2,"column":0,"end_line":0,"end_column":0},"value":{"node":{"!NumberLit":{"binary_suffix":null,"value":{"!Int":18}}},"filename":"/complex.k.yaml","line":2,"column":5,"end_line":0,"end_column":0},"operation":"Union","insert_index":-1},"filename":"/complex.k.yaml","line":1,"column":4,"end_line":0,"end_column":0},{"node":{"key":{"node":{"!StringLit":{"is_long_string":false,"raw_value":"\"message\"","value":"message"}},"filename":"/complex.k.yaml","line":3,"column":0,"end_line":0,"end_column":0},"value":{"node":{"!StringLit":{"is_long_string":false,"raw_value":"\"This is Alice\"","value":"This is Alice"}},"filename":"/complex.k.yaml","line":3,"column":9,"end_line":0,"end_column":0},"operation":"Union","insert_index":-1},"filename":"/complex.k.yaml","line":1,"column":4,"end_line":0,"end_column":0},{"node":{"key":{"node":{"!StringLit":{"is_long_string":false,"raw_value":"\"data\"","value":"data"}},"filename":"/complex.k.yaml","line":4,"column":0,"end_line":0,"end_column":0},"value":{"node":{"!Config":{"items":[{"node":{"key":{"node":{"!StringLit":{"is_long_string":false,"raw_value":"\"id\"","value":"id"}},"filename":"/complex.k.yaml","line":5,"column":4,"end_line":0,"end_column":0},"value":{"node":{"!NumberLit":{"binary_suffix":null,"value":{"!Int":1}}},"filename":"/complex.k.yaml","line":5,"column":8,"end_line":0,"end_column":0},"operation":"Union","insert_index":-1},"filename":"/complex.k.yaml","line":5,"column":6,"end_line":0,"end_column":0},{"node":{"key":{"node":{"!StringLit":{"is_long_string":false,"raw_value":"\"value\"","value":"value"}},"filename":"/complex.k.yaml","line":6,"column":4,"end_line":0,"end_column":0},"value":{"node":{"!StringLit":{"is_long_string":false,"raw_value":"\"value1\"","value":"value1"}},"filename":"/complex.k.yaml","line":6,"column":11,"end_line":0,"end_column":0},"operation":"Union","insert_index":-1},"filename":"/complex.k.yaml","line":5,"column":6,"end_line":0,"end_column":0}]}},"filename":"/complex.k.yaml","line":5,"column":6,"end_line":0,"end_column":0},"operation":"Union","insert_index":-1},"filename":"/complex.k.yaml","line":1,"column":4,"end_line":0,"end_column":0},{"node":{"key":{"node":{"!StringLit":{"is_long_string":false,"raw_value":"\"labels\"","value":"labels"}},"filename":"/complex.k.yaml","line":7,"column":0,"end_line":0,"end_column":0},"value":{"node":{"!Config":{"items":[{"node":{"key":{"node":{"!StringLit":{"is_long_string":false,"raw_value":"\"key\"","value":"key"}},"filename":"/complex.k.yaml","line":8,"column":4,"end_line":0,"end_column":0},"value":{"node":{"!StringLit":{"is_long_string":false,"raw_value":"\"value\"","value":"value"}},"filename":"/complex.k.yaml","line":8,"column":9,"end_line":0,"end_column":0},"operation":"Union","insert_index":-1},"filename":"/complex.k.yaml","line":8,"column":7,"end_line":0,"end_column":0}]}},"filename":"/complex.k.yaml","line":8,"column":7,"end_line":0,"end_column":0},"operation":"Union","insert_index":-1},"filename":"/complex.k.yaml","line":1,"column":4,"end_line":0,"end_column":0},{"node":{"key":{"node":{"!StringLit":{"is_long_string":false,"raw_value":"\"hc\"","value":"hc"}},"filename":"/complex.k.yaml","line":9,"column":0,"end_line":0,"end_column":0},"value":{"node":{"!List":{"elts":[{"node":{"!NumberLit":{"binary_suffix":null,"value":{"!Int":1}}},"filename":"/complex.k.yaml","line":10,"column":6,"end_line":0,"end_column":0},{"node":{"!NumberLit":{"binary_suffix":null,"value":{"!Int":2}}},"filename":"/complex.k.yaml","line":11,"column":6,"end_line":0,"end_column":0},{"node":{"!NumberLit":{"binary_suffix":null,"value":{"!Int":3}}},"filename":"/complex.k.yaml","line":12,"column":6,"end_line":0,"end_column":0}],"ctx":"Load"}},"filename":"/complex.k.yaml","line":10,"column":4,"end_line":0,"end_column":0},"operation":"Union","insert_index":-1},"filename":"/complex.k.yaml","line":1,"column":4,"end_line":0,"end_column":0}]}},"filename":"/complex.k.yaml","line":1,"column":4,"end_line":0,"end_column":0}}},"filename":"/complex.k.yaml","line":1,"column":4,"end_line":0,"end_column":0} \ No newline at end of file diff --git a/kclvm/tools/src/vet/test_datas/yaml_win/list.k.ast.yaml b/kclvm/tools/src/vet/test_datas/yaml_win/list.k.ast.yaml new file mode 100644 index 000000000..0049e35fa --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/yaml_win/list.k.ast.yaml @@ -0,0 +1 @@ +{"node":{"!List":{"elts":[{"node":{"!Schema":{"name":{"node":{"names":[{"node":"list","filename":"/list.k.yaml","line":1,"column":6,"end_line":0,"end_column":0}],"pkgpath":"","ctx":"Load"},"filename":"/list.k.yaml","line":1,"column":6,"end_line":0,"end_column":0},"args":[],"kwargs":[],"config":{"node":{"!Config":{"items":[{"node":{"key":{"node":{"!StringLit":{"is_long_string":false,"raw_value":"\"name\"","value":"name"}},"filename":"/list.k.yaml","line":1,"column":2,"end_line":0,"end_column":0},"value":{"node":{"!StringLit":{"is_long_string":false,"raw_value":"\"Alice\"","value":"Alice"}},"filename":"/list.k.yaml","line":1,"column":8,"end_line":0,"end_column":0},"operation":"Union","insert_index":-1},"filename":"/list.k.yaml","line":1,"column":6,"end_line":0,"end_column":0},{"node":{"key":{"node":{"!StringLit":{"is_long_string":false,"raw_value":"\"age\"","value":"age"}},"filename":"/list.k.yaml","line":2,"column":2,"end_line":0,"end_column":0},"value":{"node":{"!NumberLit":{"binary_suffix":null,"value":{"!Int":18}}},"filename":"/list.k.yaml","line":2,"column":7,"end_line":0,"end_column":0},"operation":"Union","insert_index":-1},"filename":"/list.k.yaml","line":1,"column":6,"end_line":0,"end_column":0},{"node":{"key":{"node":{"!StringLit":{"is_long_string":false,"raw_value":"\"message\"","value":"message"}},"filename":"/list.k.yaml","line":3,"column":2,"end_line":0,"end_column":0},"value":{"node":{"!StringLit":{"is_long_string":false,"raw_value":"\"This is Alice\"","value":"This is Alice"}},"filename":"/list.k.yaml","line":3,"column":11,"end_line":0,"end_column":0},"operation":"Union","insert_index":-1},"filename":"/list.k.yaml","line":1,"column":6,"end_line":0,"end_column":0}]}},"filename":"/list.k.yaml","line":1,"column":6,"end_line":0,"end_column":0}}},"filename":"/list.k.yaml","line":1,"column":6,"end_line":0,"end_column":0}],"ctx":"Load"}},"filename":"/list.k.yaml","line":1,"column":0,"end_line":0,"end_column":0} \ No newline at end of file diff --git a/kclvm/tools/src/vet/test_datas/yaml_win/no_schema_name/complex.k.ast.yaml b/kclvm/tools/src/vet/test_datas/yaml_win/no_schema_name/complex.k.ast.yaml new file mode 100644 index 000000000..9c87a26d4 --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/yaml_win/no_schema_name/complex.k.ast.yaml @@ -0,0 +1 @@ +{"node":{"!Config":{"items":[{"node":{"key":{"node":{"!StringLit":{"is_long_string":false,"raw_value":"\"name\"","value":"name"}},"filename":"/complex.k.yaml","line":1,"column":0,"end_line":0,"end_column":0},"value":{"node":{"!StringLit":{"is_long_string":false,"raw_value":"\"Alice\"","value":"Alice"}},"filename":"/complex.k.yaml","line":1,"column":6,"end_line":0,"end_column":0},"operation":"Union","insert_index":-1},"filename":"/complex.k.yaml","line":1,"column":4,"end_line":0,"end_column":0},{"node":{"key":{"node":{"!StringLit":{"is_long_string":false,"raw_value":"\"age\"","value":"age"}},"filename":"/complex.k.yaml","line":2,"column":0,"end_line":0,"end_column":0},"value":{"node":{"!NumberLit":{"binary_suffix":null,"value":{"!Int":18}}},"filename":"/complex.k.yaml","line":2,"column":5,"end_line":0,"end_column":0},"operation":"Union","insert_index":-1},"filename":"/complex.k.yaml","line":1,"column":4,"end_line":0,"end_column":0},{"node":{"key":{"node":{"!StringLit":{"is_long_string":false,"raw_value":"\"message\"","value":"message"}},"filename":"/complex.k.yaml","line":3,"column":0,"end_line":0,"end_column":0},"value":{"node":{"!StringLit":{"is_long_string":false,"raw_value":"\"This is Alice\"","value":"This is Alice"}},"filename":"/complex.k.yaml","line":3,"column":9,"end_line":0,"end_column":0},"operation":"Union","insert_index":-1},"filename":"/complex.k.yaml","line":1,"column":4,"end_line":0,"end_column":0},{"node":{"key":{"node":{"!StringLit":{"is_long_string":false,"raw_value":"\"data\"","value":"data"}},"filename":"/complex.k.yaml","line":4,"column":0,"end_line":0,"end_column":0},"value":{"node":{"!Config":{"items":[{"node":{"key":{"node":{"!StringLit":{"is_long_string":false,"raw_value":"\"id\"","value":"id"}},"filename":"/complex.k.yaml","line":5,"column":4,"end_line":0,"end_column":0},"value":{"node":{"!NumberLit":{"binary_suffix":null,"value":{"!Int":1}}},"filename":"/complex.k.yaml","line":5,"column":8,"end_line":0,"end_column":0},"operation":"Union","insert_index":-1},"filename":"/complex.k.yaml","line":5,"column":6,"end_line":0,"end_column":0},{"node":{"key":{"node":{"!StringLit":{"is_long_string":false,"raw_value":"\"value\"","value":"value"}},"filename":"/complex.k.yaml","line":6,"column":4,"end_line":0,"end_column":0},"value":{"node":{"!StringLit":{"is_long_string":false,"raw_value":"\"value1\"","value":"value1"}},"filename":"/complex.k.yaml","line":6,"column":11,"end_line":0,"end_column":0},"operation":"Union","insert_index":-1},"filename":"/complex.k.yaml","line":5,"column":6,"end_line":0,"end_column":0}]}},"filename":"/complex.k.yaml","line":5,"column":6,"end_line":0,"end_column":0},"operation":"Union","insert_index":-1},"filename":"/complex.k.yaml","line":1,"column":4,"end_line":0,"end_column":0},{"node":{"key":{"node":{"!StringLit":{"is_long_string":false,"raw_value":"\"labels\"","value":"labels"}},"filename":"/complex.k.yaml","line":7,"column":0,"end_line":0,"end_column":0},"value":{"node":{"!Config":{"items":[{"node":{"key":{"node":{"!StringLit":{"is_long_string":false,"raw_value":"\"key\"","value":"key"}},"filename":"/complex.k.yaml","line":8,"column":4,"end_line":0,"end_column":0},"value":{"node":{"!StringLit":{"is_long_string":false,"raw_value":"\"value\"","value":"value"}},"filename":"/complex.k.yaml","line":8,"column":9,"end_line":0,"end_column":0},"operation":"Union","insert_index":-1},"filename":"/complex.k.yaml","line":8,"column":7,"end_line":0,"end_column":0}]}},"filename":"/complex.k.yaml","line":8,"column":7,"end_line":0,"end_column":0},"operation":"Union","insert_index":-1},"filename":"/complex.k.yaml","line":1,"column":4,"end_line":0,"end_column":0},{"node":{"key":{"node":{"!StringLit":{"is_long_string":false,"raw_value":"\"hc\"","value":"hc"}},"filename":"/complex.k.yaml","line":9,"column":0,"end_line":0,"end_column":0},"value":{"node":{"!List":{"elts":[{"node":{"!NumberLit":{"binary_suffix":null,"value":{"!Int":1}}},"filename":"/complex.k.yaml","line":10,"column":6,"end_line":0,"end_column":0},{"node":{"!NumberLit":{"binary_suffix":null,"value":{"!Int":2}}},"filename":"/complex.k.yaml","line":11,"column":6,"end_line":0,"end_column":0},{"node":{"!NumberLit":{"binary_suffix":null,"value":{"!Int":3}}},"filename":"/complex.k.yaml","line":12,"column":6,"end_line":0,"end_column":0}],"ctx":"Load"}},"filename":"/complex.k.yaml","line":10,"column":4,"end_line":0,"end_column":0},"operation":"Union","insert_index":-1},"filename":"/complex.k.yaml","line":1,"column":4,"end_line":0,"end_column":0}]}},"filename":"/complex.k.yaml","line":1,"column":4,"end_line":0,"end_column":0} \ No newline at end of file diff --git a/kclvm/tools/src/vet/test_datas/yaml_win/no_schema_name/list.k.ast.yaml b/kclvm/tools/src/vet/test_datas/yaml_win/no_schema_name/list.k.ast.yaml new file mode 100644 index 000000000..4f1ba042b --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/yaml_win/no_schema_name/list.k.ast.yaml @@ -0,0 +1 @@ +{"node":{"!List":{"elts":[{"node":{"!Config":{"items":[{"node":{"key":{"node":{"!StringLit":{"is_long_string":false,"raw_value":"\"name\"","value":"name"}},"filename":"/list.k.yaml","line":1,"column":2,"end_line":0,"end_column":0},"value":{"node":{"!StringLit":{"is_long_string":false,"raw_value":"\"Alice\"","value":"Alice"}},"filename":"/list.k.yaml","line":1,"column":8,"end_line":0,"end_column":0},"operation":"Union","insert_index":-1},"filename":"/list.k.yaml","line":1,"column":6,"end_line":0,"end_column":0},{"node":{"key":{"node":{"!StringLit":{"is_long_string":false,"raw_value":"\"age\"","value":"age"}},"filename":"/list.k.yaml","line":2,"column":2,"end_line":0,"end_column":0},"value":{"node":{"!NumberLit":{"binary_suffix":null,"value":{"!Int":18}}},"filename":"/list.k.yaml","line":2,"column":7,"end_line":0,"end_column":0},"operation":"Union","insert_index":-1},"filename":"/list.k.yaml","line":1,"column":6,"end_line":0,"end_column":0},{"node":{"key":{"node":{"!StringLit":{"is_long_string":false,"raw_value":"\"message\"","value":"message"}},"filename":"/list.k.yaml","line":3,"column":2,"end_line":0,"end_column":0},"value":{"node":{"!StringLit":{"is_long_string":false,"raw_value":"\"This is Alice\"","value":"This is Alice"}},"filename":"/list.k.yaml","line":3,"column":11,"end_line":0,"end_column":0},"operation":"Union","insert_index":-1},"filename":"/list.k.yaml","line":1,"column":6,"end_line":0,"end_column":0}]}},"filename":"/list.k.yaml","line":1,"column":6,"end_line":0,"end_column":0}],"ctx":"Load"}},"filename":"/list.k.yaml","line":1,"column":0,"end_line":0,"end_column":0} \ No newline at end of file diff --git a/kclvm/tools/src/vet/test_datas/yaml_win/no_schema_name/only_with_bool.ast.yaml b/kclvm/tools/src/vet/test_datas/yaml_win/no_schema_name/only_with_bool.ast.yaml new file mode 100644 index 000000000..15f8b70f0 --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/yaml_win/no_schema_name/only_with_bool.ast.yaml @@ -0,0 +1 @@ +{"node":{"!Config":{"items":[{"node":{"key":{"node":{"!StringLit":{"is_long_string":false,"raw_value":"\"bool_val\"","value":"bool_val"}},"filename":"/only_with_bool.yaml","line":1,"column":0,"end_line":0,"end_column":0},"value":{"node":{"!NameConstantLit":{"value":"True"}},"filename":"/only_with_bool.yaml","line":1,"column":10,"end_line":0,"end_column":0},"operation":"Union","insert_index":-1},"filename":"/only_with_bool.yaml","line":1,"column":8,"end_line":0,"end_column":0}]}},"filename":"/only_with_bool.yaml","line":1,"column":8,"end_line":0,"end_column":0} \ No newline at end of file diff --git a/kclvm/tools/src/vet/test_datas/yaml_win/no_schema_name/only_with_float.ast.yaml b/kclvm/tools/src/vet/test_datas/yaml_win/no_schema_name/only_with_float.ast.yaml new file mode 100644 index 000000000..74b3498fc --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/yaml_win/no_schema_name/only_with_float.ast.yaml @@ -0,0 +1 @@ +{"node":{"!Config":{"items":[{"node":{"key":{"node":{"!StringLit":{"is_long_string":false,"raw_value":"\"float_val\"","value":"float_val"}},"filename":"/only_with_float.yaml","line":1,"column":0,"end_line":0,"end_column":0},"value":{"node":{"!NumberLit":{"binary_suffix":null,"value":{"!Float":0.33}}},"filename":"/only_with_float.yaml","line":1,"column":11,"end_line":0,"end_column":0},"operation":"Union","insert_index":-1},"filename":"/only_with_float.yaml","line":1,"column":9,"end_line":0,"end_column":0}]}},"filename":"/only_with_float.yaml","line":1,"column":9,"end_line":0,"end_column":0} \ No newline at end of file diff --git a/kclvm/tools/src/vet/test_datas/yaml_win/no_schema_name/only_with_null.ast.yaml b/kclvm/tools/src/vet/test_datas/yaml_win/no_schema_name/only_with_null.ast.yaml new file mode 100644 index 000000000..d488b40f9 --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/yaml_win/no_schema_name/only_with_null.ast.yaml @@ -0,0 +1 @@ +{"node":{"!Config":{"items":[{"node":{"key":{"node":{"!StringLit":{"is_long_string":false,"raw_value":"\"null_val\"","value":"null_val"}},"filename":"/only_with_null.yaml","line":1,"column":0,"end_line":0,"end_column":0},"value":{"node":{"!NameConstantLit":{"value":"None"}},"filename":"/only_with_null.yaml","line":1,"column":10,"end_line":0,"end_column":0},"operation":"Union","insert_index":-1},"filename":"/only_with_null.yaml","line":1,"column":8,"end_line":0,"end_column":0}]}},"filename":"/only_with_null.yaml","line":1,"column":8,"end_line":0,"end_column":0} \ No newline at end of file diff --git a/kclvm/tools/src/vet/test_datas/yaml_win/no_schema_name/plain_value.k.ast.yaml b/kclvm/tools/src/vet/test_datas/yaml_win/no_schema_name/plain_value.k.ast.yaml new file mode 100644 index 000000000..77ee8b2ff --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/yaml_win/no_schema_name/plain_value.k.ast.yaml @@ -0,0 +1 @@ +{"node":{"!NumberLit":{"binary_suffix":null,"value":{"!Int":1}}},"filename":"/plain_value.k.yaml","line":1,"column":0,"end_line":0,"end_column":0} \ No newline at end of file diff --git a/kclvm/tools/src/vet/test_datas/yaml_win/no_schema_name/simple.k.ast.yaml b/kclvm/tools/src/vet/test_datas/yaml_win/no_schema_name/simple.k.ast.yaml new file mode 100644 index 000000000..d43c49020 --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/yaml_win/no_schema_name/simple.k.ast.yaml @@ -0,0 +1 @@ +{"node":{"!Config":{"items":[{"node":{"key":{"node":{"!StringLit":{"is_long_string":false,"raw_value":"\"name\"","value":"name"}},"filename":"/simple.k.yaml","line":1,"column":0,"end_line":0,"end_column":0},"value":{"node":{"!StringLit":{"is_long_string":false,"raw_value":"\"Alice,\"","value":"Alice,"}},"filename":"/simple.k.yaml","line":1,"column":6,"end_line":0,"end_column":0},"operation":"Union","insert_index":-1},"filename":"/simple.k.yaml","line":1,"column":4,"end_line":0,"end_column":0},{"node":{"key":{"node":{"!StringLit":{"is_long_string":false,"raw_value":"\"age\"","value":"age"}},"filename":"/simple.k.yaml","line":2,"column":0,"end_line":0,"end_column":0},"value":{"node":{"!StringLit":{"is_long_string":false,"raw_value":"\"18,\"","value":"18,"}},"filename":"/simple.k.yaml","line":2,"column":5,"end_line":0,"end_column":0},"operation":"Union","insert_index":-1},"filename":"/simple.k.yaml","line":1,"column":4,"end_line":0,"end_column":0},{"node":{"key":{"node":{"!StringLit":{"is_long_string":false,"raw_value":"\"message\"","value":"message"}},"filename":"/simple.k.yaml","line":3,"column":0,"end_line":0,"end_column":0},"value":{"node":{"!StringLit":{"is_long_string":false,"raw_value":"\"This is Alice\"","value":"This is Alice"}},"filename":"/simple.k.yaml","line":3,"column":9,"end_line":0,"end_column":0},"operation":"Union","insert_index":-1},"filename":"/simple.k.yaml","line":1,"column":4,"end_line":0,"end_column":0}]}},"filename":"/simple.k.yaml","line":1,"column":4,"end_line":0,"end_column":0} \ No newline at end of file diff --git a/kclvm/tools/src/vet/test_datas/yaml_win/no_schema_name/test.k.ast.yaml b/kclvm/tools/src/vet/test_datas/yaml_win/no_schema_name/test.k.ast.yaml new file mode 100644 index 000000000..e6ab4d182 --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/yaml_win/no_schema_name/test.k.ast.yaml @@ -0,0 +1 @@ +{"node":{"!Config":{"items":[{"node":{"key":{"node":{"!StringLit":{"is_long_string":false,"raw_value":"\"languages\"","value":"languages"}},"filename":"/test.k.yaml","line":1,"column":0,"end_line":0,"end_column":0},"value":{"node":{"!List":{"elts":[{"node":{"!StringLit":{"is_long_string":false,"raw_value":"\"Ruby\"","value":"Ruby"}},"filename":"/test.k.yaml","line":2,"column":4,"end_line":0,"end_column":0},{"node":{"!StringLit":{"is_long_string":false,"raw_value":"\"Perl\"","value":"Perl"}},"filename":"/test.k.yaml","line":3,"column":4,"end_line":0,"end_column":0},{"node":{"!StringLit":{"is_long_string":false,"raw_value":"\"Python\"","value":"Python"}},"filename":"/test.k.yaml","line":4,"column":4,"end_line":0,"end_column":0}],"ctx":"Load"}},"filename":"/test.k.yaml","line":2,"column":2,"end_line":0,"end_column":0},"operation":"Union","insert_index":-1},"filename":"/test.k.yaml","line":1,"column":9,"end_line":0,"end_column":0},{"node":{"key":{"node":{"!StringLit":{"is_long_string":false,"raw_value":"\"websites\"","value":"websites"}},"filename":"/test.k.yaml","line":5,"column":0,"end_line":0,"end_column":0},"value":{"node":{"!Config":{"items":[{"node":{"key":{"node":{"!StringLit":{"is_long_string":false,"raw_value":"\"YAML\"","value":"YAML"}},"filename":"/test.k.yaml","line":6,"column":2,"end_line":0,"end_column":0},"value":{"node":{"!StringLit":{"is_long_string":false,"raw_value":"\"yaml.org\"","value":"yaml.org"}},"filename":"/test.k.yaml","line":6,"column":8,"end_line":0,"end_column":0},"operation":"Union","insert_index":-1},"filename":"/test.k.yaml","line":6,"column":6,"end_line":0,"end_column":0},{"node":{"key":{"node":{"!StringLit":{"is_long_string":false,"raw_value":"\"Ruby\"","value":"Ruby"}},"filename":"/test.k.yaml","line":7,"column":2,"end_line":0,"end_column":0},"value":{"node":{"!StringLit":{"is_long_string":false,"raw_value":"\"ruby-lang.org\"","value":"ruby-lang.org"}},"filename":"/test.k.yaml","line":7,"column":8,"end_line":0,"end_column":0},"operation":"Union","insert_index":-1},"filename":"/test.k.yaml","line":6,"column":6,"end_line":0,"end_column":0},{"node":{"key":{"node":{"!StringLit":{"is_long_string":false,"raw_value":"\"Python\"","value":"Python"}},"filename":"/test.k.yaml","line":8,"column":2,"end_line":0,"end_column":0},"value":{"node":{"!StringLit":{"is_long_string":false,"raw_value":"\"python.org\"","value":"python.org"}},"filename":"/test.k.yaml","line":8,"column":10,"end_line":0,"end_column":0},"operation":"Union","insert_index":-1},"filename":"/test.k.yaml","line":6,"column":6,"end_line":0,"end_column":0},{"node":{"key":{"node":{"!StringLit":{"is_long_string":false,"raw_value":"\"Perl\"","value":"Perl"}},"filename":"/test.k.yaml","line":9,"column":2,"end_line":0,"end_column":0},"value":{"node":{"!StringLit":{"is_long_string":false,"raw_value":"\"use.perl.org\"","value":"use.perl.org"}},"filename":"/test.k.yaml","line":9,"column":8,"end_line":0,"end_column":0},"operation":"Union","insert_index":-1},"filename":"/test.k.yaml","line":6,"column":6,"end_line":0,"end_column":0}]}},"filename":"/test.k.yaml","line":6,"column":6,"end_line":0,"end_column":0},"operation":"Union","insert_index":-1},"filename":"/test.k.yaml","line":1,"column":9,"end_line":0,"end_column":0}]}},"filename":"/test.k.yaml","line":1,"column":9,"end_line":0,"end_column":0} \ No newline at end of file diff --git a/kclvm/tools/src/vet/test_datas/yaml_win/only_with_bool.ast.yaml b/kclvm/tools/src/vet/test_datas/yaml_win/only_with_bool.ast.yaml new file mode 100644 index 000000000..497ce691e --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/yaml_win/only_with_bool.ast.yaml @@ -0,0 +1 @@ +{"node":{"!Schema":{"name":{"node":{"names":[{"node":"only_with_bool","filename":"/only_with_bool.yaml","line":1,"column":8,"end_line":0,"end_column":0}],"pkgpath":"","ctx":"Load"},"filename":"/only_with_bool.yaml","line":1,"column":8,"end_line":0,"end_column":0},"args":[],"kwargs":[],"config":{"node":{"!Config":{"items":[{"node":{"key":{"node":{"!StringLit":{"is_long_string":false,"raw_value":"\"bool_val\"","value":"bool_val"}},"filename":"/only_with_bool.yaml","line":1,"column":0,"end_line":0,"end_column":0},"value":{"node":{"!NameConstantLit":{"value":"True"}},"filename":"/only_with_bool.yaml","line":1,"column":10,"end_line":0,"end_column":0},"operation":"Union","insert_index":-1},"filename":"/only_with_bool.yaml","line":1,"column":8,"end_line":0,"end_column":0}]}},"filename":"/only_with_bool.yaml","line":1,"column":8,"end_line":0,"end_column":0}}},"filename":"/only_with_bool.yaml","line":1,"column":8,"end_line":0,"end_column":0} \ No newline at end of file diff --git a/kclvm/tools/src/vet/test_datas/yaml_win/only_with_float.ast.yaml b/kclvm/tools/src/vet/test_datas/yaml_win/only_with_float.ast.yaml new file mode 100644 index 000000000..ca5c407b6 --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/yaml_win/only_with_float.ast.yaml @@ -0,0 +1 @@ +{"node":{"!Schema":{"name":{"node":{"names":[{"node":"only_with_float","filename":"/only_with_float.yaml","line":1,"column":9,"end_line":0,"end_column":0}],"pkgpath":"","ctx":"Load"},"filename":"/only_with_float.yaml","line":1,"column":9,"end_line":0,"end_column":0},"args":[],"kwargs":[],"config":{"node":{"!Config":{"items":[{"node":{"key":{"node":{"!StringLit":{"is_long_string":false,"raw_value":"\"float_val\"","value":"float_val"}},"filename":"/only_with_float.yaml","line":1,"column":0,"end_line":0,"end_column":0},"value":{"node":{"!NumberLit":{"binary_suffix":null,"value":{"!Float":0.33}}},"filename":"/only_with_float.yaml","line":1,"column":11,"end_line":0,"end_column":0},"operation":"Union","insert_index":-1},"filename":"/only_with_float.yaml","line":1,"column":9,"end_line":0,"end_column":0}]}},"filename":"/only_with_float.yaml","line":1,"column":9,"end_line":0,"end_column":0}}},"filename":"/only_with_float.yaml","line":1,"column":9,"end_line":0,"end_column":0} \ No newline at end of file diff --git a/kclvm/tools/src/vet/test_datas/yaml_win/only_with_null.ast.yaml b/kclvm/tools/src/vet/test_datas/yaml_win/only_with_null.ast.yaml new file mode 100644 index 000000000..4435356de --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/yaml_win/only_with_null.ast.yaml @@ -0,0 +1 @@ +{"node":{"!Schema":{"name":{"node":{"names":[{"node":"only_with_null","filename":"/only_with_null.yaml","line":1,"column":8,"end_line":0,"end_column":0}],"pkgpath":"","ctx":"Load"},"filename":"/only_with_null.yaml","line":1,"column":8,"end_line":0,"end_column":0},"args":[],"kwargs":[],"config":{"node":{"!Config":{"items":[{"node":{"key":{"node":{"!StringLit":{"is_long_string":false,"raw_value":"\"null_val\"","value":"null_val"}},"filename":"/only_with_null.yaml","line":1,"column":0,"end_line":0,"end_column":0},"value":{"node":{"!NameConstantLit":{"value":"None"}},"filename":"/only_with_null.yaml","line":1,"column":10,"end_line":0,"end_column":0},"operation":"Union","insert_index":-1},"filename":"/only_with_null.yaml","line":1,"column":8,"end_line":0,"end_column":0}]}},"filename":"/only_with_null.yaml","line":1,"column":8,"end_line":0,"end_column":0}}},"filename":"/only_with_null.yaml","line":1,"column":8,"end_line":0,"end_column":0} \ No newline at end of file diff --git a/kclvm/tools/src/vet/test_datas/yaml_win/plain_value.k.ast.yaml b/kclvm/tools/src/vet/test_datas/yaml_win/plain_value.k.ast.yaml new file mode 100644 index 000000000..77ee8b2ff --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/yaml_win/plain_value.k.ast.yaml @@ -0,0 +1 @@ +{"node":{"!NumberLit":{"binary_suffix":null,"value":{"!Int":1}}},"filename":"/plain_value.k.yaml","line":1,"column":0,"end_line":0,"end_column":0} \ No newline at end of file diff --git a/kclvm/tools/src/vet/test_datas/yaml_win/simple.k.ast.yaml b/kclvm/tools/src/vet/test_datas/yaml_win/simple.k.ast.yaml new file mode 100644 index 000000000..578b80342 --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/yaml_win/simple.k.ast.yaml @@ -0,0 +1 @@ +{"node":{"!Schema":{"name":{"node":{"names":[{"node":"simple","filename":"/simple.k.yaml","line":1,"column":4,"end_line":0,"end_column":0}],"pkgpath":"","ctx":"Load"},"filename":"/simple.k.yaml","line":1,"column":4,"end_line":0,"end_column":0},"args":[],"kwargs":[],"config":{"node":{"!Config":{"items":[{"node":{"key":{"node":{"!StringLit":{"is_long_string":false,"raw_value":"\"name\"","value":"name"}},"filename":"/simple.k.yaml","line":1,"column":0,"end_line":0,"end_column":0},"value":{"node":{"!StringLit":{"is_long_string":false,"raw_value":"\"Alice,\"","value":"Alice,"}},"filename":"/simple.k.yaml","line":1,"column":6,"end_line":0,"end_column":0},"operation":"Union","insert_index":-1},"filename":"/simple.k.yaml","line":1,"column":4,"end_line":0,"end_column":0},{"node":{"key":{"node":{"!StringLit":{"is_long_string":false,"raw_value":"\"age\"","value":"age"}},"filename":"/simple.k.yaml","line":2,"column":0,"end_line":0,"end_column":0},"value":{"node":{"!StringLit":{"is_long_string":false,"raw_value":"\"18,\"","value":"18,"}},"filename":"/simple.k.yaml","line":2,"column":5,"end_line":0,"end_column":0},"operation":"Union","insert_index":-1},"filename":"/simple.k.yaml","line":1,"column":4,"end_line":0,"end_column":0},{"node":{"key":{"node":{"!StringLit":{"is_long_string":false,"raw_value":"\"message\"","value":"message"}},"filename":"/simple.k.yaml","line":3,"column":0,"end_line":0,"end_column":0},"value":{"node":{"!StringLit":{"is_long_string":false,"raw_value":"\"This is Alice\"","value":"This is Alice"}},"filename":"/simple.k.yaml","line":3,"column":9,"end_line":0,"end_column":0},"operation":"Union","insert_index":-1},"filename":"/simple.k.yaml","line":1,"column":4,"end_line":0,"end_column":0}]}},"filename":"/simple.k.yaml","line":1,"column":4,"end_line":0,"end_column":0}}},"filename":"/simple.k.yaml","line":1,"column":4,"end_line":0,"end_column":0} \ No newline at end of file diff --git a/kclvm/tools/src/vet/test_datas/yaml_win/test.k.ast.yaml b/kclvm/tools/src/vet/test_datas/yaml_win/test.k.ast.yaml new file mode 100644 index 000000000..5bb5163ca --- /dev/null +++ b/kclvm/tools/src/vet/test_datas/yaml_win/test.k.ast.yaml @@ -0,0 +1 @@ +{"node":{"!Schema":{"name":{"node":{"names":[{"node":"test","filename":"/test.k.yaml","line":1,"column":9,"end_line":0,"end_column":0}],"pkgpath":"","ctx":"Load"},"filename":"/test.k.yaml","line":1,"column":9,"end_line":0,"end_column":0},"args":[],"kwargs":[],"config":{"node":{"!Config":{"items":[{"node":{"key":{"node":{"!StringLit":{"is_long_string":false,"raw_value":"\"languages\"","value":"languages"}},"filename":"/test.k.yaml","line":1,"column":0,"end_line":0,"end_column":0},"value":{"node":{"!List":{"elts":[{"node":{"!StringLit":{"is_long_string":false,"raw_value":"\"Ruby\"","value":"Ruby"}},"filename":"/test.k.yaml","line":2,"column":4,"end_line":0,"end_column":0},{"node":{"!StringLit":{"is_long_string":false,"raw_value":"\"Perl\"","value":"Perl"}},"filename":"/test.k.yaml","line":3,"column":4,"end_line":0,"end_column":0},{"node":{"!StringLit":{"is_long_string":false,"raw_value":"\"Python\"","value":"Python"}},"filename":"/test.k.yaml","line":4,"column":4,"end_line":0,"end_column":0}],"ctx":"Load"}},"filename":"/test.k.yaml","line":2,"column":2,"end_line":0,"end_column":0},"operation":"Union","insert_index":-1},"filename":"/test.k.yaml","line":1,"column":9,"end_line":0,"end_column":0},{"node":{"key":{"node":{"!StringLit":{"is_long_string":false,"raw_value":"\"websites\"","value":"websites"}},"filename":"/test.k.yaml","line":5,"column":0,"end_line":0,"end_column":0},"value":{"node":{"!Config":{"items":[{"node":{"key":{"node":{"!StringLit":{"is_long_string":false,"raw_value":"\"YAML\"","value":"YAML"}},"filename":"/test.k.yaml","line":6,"column":2,"end_line":0,"end_column":0},"value":{"node":{"!StringLit":{"is_long_string":false,"raw_value":"\"yaml.org\"","value":"yaml.org"}},"filename":"/test.k.yaml","line":6,"column":8,"end_line":0,"end_column":0},"operation":"Union","insert_index":-1},"filename":"/test.k.yaml","line":6,"column":6,"end_line":0,"end_column":0},{"node":{"key":{"node":{"!StringLit":{"is_long_string":false,"raw_value":"\"Ruby\"","value":"Ruby"}},"filename":"/test.k.yaml","line":7,"column":2,"end_line":0,"end_column":0},"value":{"node":{"!StringLit":{"is_long_string":false,"raw_value":"\"ruby-lang.org\"","value":"ruby-lang.org"}},"filename":"/test.k.yaml","line":7,"column":8,"end_line":0,"end_column":0},"operation":"Union","insert_index":-1},"filename":"/test.k.yaml","line":6,"column":6,"end_line":0,"end_column":0},{"node":{"key":{"node":{"!StringLit":{"is_long_string":false,"raw_value":"\"Python\"","value":"Python"}},"filename":"/test.k.yaml","line":8,"column":2,"end_line":0,"end_column":0},"value":{"node":{"!StringLit":{"is_long_string":false,"raw_value":"\"python.org\"","value":"python.org"}},"filename":"/test.k.yaml","line":8,"column":10,"end_line":0,"end_column":0},"operation":"Union","insert_index":-1},"filename":"/test.k.yaml","line":6,"column":6,"end_line":0,"end_column":0},{"node":{"key":{"node":{"!StringLit":{"is_long_string":false,"raw_value":"\"Perl\"","value":"Perl"}},"filename":"/test.k.yaml","line":9,"column":2,"end_line":0,"end_column":0},"value":{"node":{"!StringLit":{"is_long_string":false,"raw_value":"\"use.perl.org\"","value":"use.perl.org"}},"filename":"/test.k.yaml","line":9,"column":8,"end_line":0,"end_column":0},"operation":"Union","insert_index":-1},"filename":"/test.k.yaml","line":6,"column":6,"end_line":0,"end_column":0}]}},"filename":"/test.k.yaml","line":6,"column":6,"end_line":0,"end_column":0},"operation":"Union","insert_index":-1},"filename":"/test.k.yaml","line":1,"column":9,"end_line":0,"end_column":0}]}},"filename":"/test.k.yaml","line":1,"column":9,"end_line":0,"end_column":0}}},"filename":"/test.k.yaml","line":1,"column":9,"end_line":0,"end_column":0} \ No newline at end of file diff --git a/kclvm/tools/src/vet/tests.rs b/kclvm/tools/src/vet/tests.rs new file mode 100644 index 000000000..ca9c714b4 --- /dev/null +++ b/kclvm/tools/src/vet/tests.rs @@ -0,0 +1,632 @@ +use std::path::{Path, PathBuf}; + +use anyhow::{Context, Result}; + +use crate::util::loader::LoaderKind; + +const CARGO_DIR: &str = env!("CARGO_MANIFEST_DIR"); +pub(crate) fn rel_path() -> String { + Path::new("src") + .join("vet") + .join("test_datas") + .display() + .to_string() +} + +const TEST_CASES: &[&str] = &[ + "test.k", + "simple.k", + "plain_value.k", + "list.k", + "complex.k", + "only_with_null", + "only_with_bool", + "only_with_float", +]; + +const SCHEMA_NAMES: &[&str] = &[ + "test", + "simple", + "plain_value", + "list", + "complex", + "only_with_null", + "only_with_bool", + "only_with_float", +]; + +const FILE_EXTENSIONS: &[&str] = &["json", "yaml", "ast.json", "ast.yaml", "k"]; + +const LOADER_KIND: [&LoaderKind; 2] = [&LoaderKind::JSON, &LoaderKind::YAML]; + +const INVALID_FILE_RESULT: &[&str] = &[ +"Failed to Load JSON\n\nCaused by:\n 0: Failed to String 'languages:\n - Ruby\n ' to Json\n 1: expected value at line 1 column 1", +"Failed to Load YAML\n\nCaused by:\n 0: Failed to String '{\n \"name\": \"John Doe\",\n \"city\": \"London\"\n invalid\n \n ' to Yaml\n 1: while parsing a flow mapping, did not find expected ',' or '}' at line 4 column 1" +]; + +fn construct_full_path(path: &str) -> Result { + let mut cargo_file_path = PathBuf::from(CARGO_DIR); + cargo_file_path.push(&rel_path()); + cargo_file_path.push(path); + Ok(cargo_file_path + .to_str() + .with_context(|| format!("No such file or directory '{}'", path))? + .to_string()) +} + +mod test_expr_builder { + use regex::Regex; + + use crate::{ + util::loader::LoaderKind, + vet::{ + expr_builder::ExprBuilder, + tests::{ + construct_full_path, deal_windows_filepath, FILE_EXTENSIONS, INVALID_FILE_RESULT, + LOADER_KIND, SCHEMA_NAMES, TEST_CASES, + }, + }, + }; + use std::panic; + #[cfg(not(target_os = "windows"))] + use std::{fs, path::Path}; + + #[test] + #[cfg(not(target_os = "windows"))] + fn test_build_with_json_no_schema_name() { + for test_name in TEST_CASES { + let file_path = construct_full_path(&format!( + "{}.{}", + Path::new(FILE_EXTENSIONS[0]).join(test_name).display(), + FILE_EXTENSIONS[0] + )) + .unwrap(); + let expr_builder = + ExprBuilder::new_with_file_path(*LOADER_KIND[0], file_path.clone()).unwrap(); + let expr_ast = expr_builder.build(None).unwrap(); + let got_ast_json = serde_json::to_value(&expr_ast).unwrap(); + + let got_ast_json_str = serde_json::to_string_pretty(&got_ast_json) + .unwrap() + .replace( + &deal_windows_filepath(construct_full_path("json").unwrap(), |s| { + s.replace('\\', "\\\\") + }), + "", + ); + + insta::assert_snapshot!(got_ast_json_str); + } + } + + #[test] + fn test_build_with_yaml_no_schema_name() { + for test_name in TEST_CASES { + let file_path = construct_full_path(&format!( + "{}/{}.{}", + FILE_EXTENSIONS[1], test_name, FILE_EXTENSIONS[1] + )) + .unwrap(); + let expr_builder = + ExprBuilder::new_with_file_path(*LOADER_KIND[1], file_path.clone()).unwrap(); + let expr_ast = expr_builder.build(None).unwrap(); + let got_ast_yaml = serde_yaml::to_value(&expr_ast).unwrap(); + + let got_ast_yaml_str = serde_json::to_string(&got_ast_yaml).unwrap().replace( + &deal_windows_filepath(construct_full_path("yaml").unwrap(), |s| { + s.replace('\\', "\\\\") + }), + "", + ); + + insta::assert_snapshot!(got_ast_yaml_str) + } + } + + #[test] + #[cfg(not(target_os = "windows"))] + /// Test `expr_builder.build()` with input json files. + fn test_build_json_with_filepath() { + for i in 0..TEST_CASES.len() { + let file_path = + construct_full_path(&format!("{1}/{0}.{1}", TEST_CASES[i], FILE_EXTENSIONS[0])) + .unwrap(); + let expr_builder = ExprBuilder::new_with_file_path(*LOADER_KIND[0], file_path).unwrap(); + let expr_ast = expr_builder + .build(Some(SCHEMA_NAMES[i].to_string())) + .unwrap(); + let got_ast_json = serde_json::to_value(&expr_ast).unwrap(); + + let got_ast_json_str = serde_json::to_string_pretty(&got_ast_json) + .unwrap() + .replace( + &deal_windows_filepath(construct_full_path("json").unwrap(), |s| { + s.replace('\\', "\\\\") + }), + "", + ); + + insta::assert_snapshot!(got_ast_json_str); + } + } + + #[test] + #[cfg(not(target_os = "windows"))] + /// Test `expr_builder.build()` with input json files. + fn test_build_json_with_str() { + for i in 0..TEST_CASES.len() { + let file_path = + construct_full_path(&format!("{1}/{0}.{1}", TEST_CASES[i], FILE_EXTENSIONS[0])) + .unwrap(); + + let content = fs::read_to_string(file_path).unwrap(); + + let expr_builder = ExprBuilder::new_with_str(*LOADER_KIND[0], content).unwrap(); + let expr_ast = expr_builder + .build(Some(SCHEMA_NAMES[i].to_string())) + .unwrap(); + let got_ast_json = serde_json::to_value(&expr_ast).unwrap(); + + let got_ast_json_str = serde_json::to_string_pretty(&got_ast_json) + .unwrap() + .replace( + &deal_windows_filepath(construct_full_path("json").unwrap(), |s| { + s.replace('\\', "\\\\") + }), + "", + ); + + insta::assert_snapshot!(got_ast_json_str); + } + } + + #[test] + /// Test `expr_builder.build()` with input yaml files. + fn test_build_yaml() { + for i in 0..TEST_CASES.len() { + let file_path = + construct_full_path(&format!("{1}/{0}.{1}", TEST_CASES[i], FILE_EXTENSIONS[1])) + .unwrap(); + let expr_builder = ExprBuilder::new_with_file_path(*LOADER_KIND[1], file_path).unwrap(); + let expr_ast = expr_builder + .build(Some(SCHEMA_NAMES[i].to_string())) + .unwrap(); + let got_ast_yaml = serde_yaml::to_value(&expr_ast).unwrap(); + + let got_ast_yaml_str = serde_json::to_string(&got_ast_yaml).unwrap().replace( + &deal_windows_filepath(construct_full_path("yaml").unwrap(), |s| { + s.replace('\\', "\\\\") + }), + "", + ); + + insta::assert_snapshot!(got_ast_yaml_str); + } + } + + #[test] + /// Test `expr_builder.build()` with input invalid json/yaml files. + fn test_build_with_invalid() { + for i in 0..2 { + let file_path = construct_full_path(&format!( + "invalid/{}.{}", + "test_invalid", FILE_EXTENSIONS[i] + )) + .unwrap(); + let expr_builder = ExprBuilder::new_with_file_path(*LOADER_KIND[i], file_path).unwrap(); + match expr_builder.build(None) { + Ok(_) => { + panic!("This test case should be failed.") + } + Err(err) => { + #[cfg(not(target_os = "windows"))] + let got_err = format!("{:?}", err); + #[cfg(target_os = "windows")] + let got_err = format!("{:?}", err).replace("\r\n", "\n"); + + assert_eq!(got_err, INVALID_FILE_RESULT[i]); + } + }; + } + } + + #[test] + /// Test `expr_builder.build()` with files that do not exist. + fn test_build_with_noexist_file() { + for i in 0..2 { + let file_path = construct_full_path(&format!( + "json/{}.{}", + "test_json_not_exist", FILE_EXTENSIONS[i] + )) + .unwrap(); + match ExprBuilder::new_with_file_path(*LOADER_KIND[i], file_path.clone()) { + Ok(_) => { + panic!("This test case should be failed.") + } + Err(err) => { + assert!(Regex::new( + r"^Failed to Load '.*'\n\nCaused by:\n 0: Failed to Load '.*'\n .*" + ) + .unwrap() + .is_match(&format!("{:?}", err))) + } + }; + } + } + + #[test] + /// Test `expr_builder.build()` with yaml files and json data loader. + fn test_build_with_yaml_file_with_json_kind() { + let file_path = construct_full_path(&format!("yaml/{}", "test.k.yaml")).unwrap(); + let expr_builder = ExprBuilder::new_with_file_path(LoaderKind::JSON, file_path).unwrap(); + + match expr_builder.build(None) { + Ok(_) => { + panic!("This test case should be failed.") + } + Err(err) => { + #[cfg(not(target_os = "windows"))] + let got_err = format!("{:?}", err); + #[cfg(target_os = "windows")] + let got_err = format!("{:?}", err).replace("\r\n", "\n"); + + assert_eq!( + got_err, + "Failed to Load JSON\n\nCaused by:\n 0: Failed to String 'languages:\n - Ruby\n - Perl\n - Python \n websites:\n YAML: yaml.org \n Ruby: ruby-lang.org \n Python: python.org \n Perl: use.perl.org\n ' to Json\n 1: expected value at line 1 column 1" + ) + } + } + } + + #[test] + fn test_unsupported_u64_json() { + // unsupported u64 json + let file_path = construct_full_path("invalid/unsupported/json_with_u64.json").unwrap(); + let expr_builder = ExprBuilder::new_with_file_path(*LOADER_KIND[0], file_path).unwrap(); + match expr_builder.build(None) { + Ok(_) => { + panic!("unreachable") + } + Err(err) => { + assert_eq!(format!("{:?}", err), "Failed to Load JSON\n\nCaused by:\n 0: Failed to load the validated file\n 1: Failed to load the validated file, Unsupported Unsigned 64"); + } + }; + } + + #[test] + fn test_unsupported_u64_yaml() { + // unsupported u64 yaml + let file_path = construct_full_path("invalid/unsupported/yaml_with_u64.yaml").unwrap(); + let expr_builder = ExprBuilder::new_with_file_path(*LOADER_KIND[1], file_path).unwrap(); + match expr_builder.build(None) { + Ok(_) => { + panic!("unreachable") + } + Err(err) => { + assert_eq!(format!("{:?}", err), "Failed to Load YAML\n\nCaused by:\n 0: Failed to load the validated file\n 1: Failed to load the validated file, Unsupported Number Type"); + } + }; + } +} + +mod test_validater { + use std::{ + fs, panic, + path::{Path, PathBuf}, + }; + + use crate::{ + util::loader::LoaderKind, + vet::{ + tests::deal_windows_filepath, + validator::{validate, ValidateOption}, + }, + }; + + use super::{construct_full_path, LOADER_KIND}; + + const KCL_TEST_CASES: &[&str] = &[ + "test.k", + "simple.k", + "list.k", + "plain_value.k", + "complex.k", + "with_import.k", + ]; + const KCL_TEST_CASES_WITH_CODE: &[&str] = + &["test.k", "simple.k", "list.k", "plain_value.k", "complex.k"]; + const VALIDATED_FILE_TYPE: &[&str] = &["json", "yaml"]; + + #[test] + fn test_validator() { + test_validate(); + println!("test_validate - PASS"); + test_invalid_validate_only_code(); + println!("test_invalid_validate_only_code - PASS"); + test_validate_with_invalid_kcl_path(); + println!("test_validate_with_invalid_kcl_path - PASS"); + test_validate_with_invalid_file_path(); + println!("test_validate_with_invalid_file_path - PASS"); + test_validate_with_invalid_file_type(); + println!("test_validate_with_invalid_file_type - PASS"); + test_invalid_validate_with_json_pos(); + println!("test_invalid_validate_with_json_pos - PASS"); + test_invalid_validate_with_yaml_pos(); + println!("test_invalid_validate_with_yaml_pos - PASS"); + } + + fn test_validate() { + for (i, file_suffix) in VALIDATED_FILE_TYPE.iter().enumerate() { + for case in KCL_TEST_CASES { + let validated_file_path = construct_full_path(&format!( + "{}.{}", + Path::new("validate_cases").join(case).display(), + file_suffix + )) + .unwrap(); + + let kcl_file_path = construct_full_path( + &Path::new("validate_cases").join(case).display().to_string(), + ) + .unwrap(); + + let opt = ValidateOption::new( + None, + "value".to_string(), + validated_file_path.clone(), + *LOADER_KIND[i], + Some(kcl_file_path.to_string()), + None, + ); + + match validate(opt) { + Ok(res) => assert!(res), + Err(err) => unreachable!("{:?}", err), + } + } + } + } + + fn test_invalid_validate_with_json_pos() { + let root_path = PathBuf::from(construct_full_path("invalid_vet_cases_json").unwrap()) + .canonicalize() + .unwrap(); + for (i, _) in VALIDATED_FILE_TYPE.iter().enumerate() { + for case in KCL_TEST_CASES { + let validated_file_path = construct_full_path(&format!( + "{}.{}", + Path::new("invalid_vet_cases_json").join(case).display(), + "json" + )) + .unwrap(); + + let kcl_code = fs::read_to_string( + construct_full_path( + &Path::new("invalid_vet_cases_json") + .join(case) + .display() + .to_string(), + ) + .unwrap(), + ) + .expect("Something went wrong reading the file"); + + let kcl_path = construct_full_path( + &Path::new("invalid_vet_cases_json") + .join(case) + .display() + .to_string(), + ) + .unwrap(); + + let opt = ValidateOption::new( + None, + "value".to_string(), + validated_file_path.clone(), + *LOADER_KIND[i], + Some(kcl_path), + Some(kcl_code), + ); + + let result = validate(opt).unwrap_err(); + println!("{}", result); + assert!( + result.to_string().replace('\\', "").contains( + &deal_windows_filepath(root_path.join(case).display().to_string(), |s| { + s.replace('\\', "\\\\") + }) + .replace('\\', "") + ), + "{result}" + ); + } + } + } + + fn test_invalid_validate_with_yaml_pos() { + let root_path = PathBuf::from(construct_full_path("invalid_vet_cases_yaml").unwrap()) + .canonicalize() + .unwrap(); + for case in KCL_TEST_CASES { + let validated_file_path = construct_full_path(&format!( + "{}.{}", + Path::new("invalid_vet_cases_yaml").join(case).display(), + "yaml" + )) + .unwrap(); + + let kcl_code = fs::read_to_string( + construct_full_path( + &Path::new("invalid_vet_cases_yaml") + .join(case) + .display() + .to_string(), + ) + .unwrap(), + ) + .expect("Something went wrong reading the file"); + + let kcl_path = construct_full_path( + &Path::new("invalid_vet_cases_yaml") + .join(case) + .display() + .to_string(), + ) + .unwrap(); + + let opt = ValidateOption::new( + None, + "value".to_string(), + validated_file_path.clone(), + LoaderKind::YAML, + Some(kcl_path), + Some(kcl_code), + ); + + let result = validate(opt).unwrap_err(); + println!("{}", result); + assert!( + result.to_string().replace('\\', "").contains( + &deal_windows_filepath(root_path.join(case).display().to_string(), |s| { + s.replace('\\', "\\\\") + }) + .replace('\\', "") + ), + "{result}" + ); + } + } + + #[test] + fn test_invalid_validate_only_code() { + for (i, file_suffix) in VALIDATED_FILE_TYPE.iter().enumerate() { + for case in KCL_TEST_CASES_WITH_CODE { + let validated_file_path = construct_full_path(&format!( + "{}.{}", + Path::new("invalid_validate_cases").join(case).display(), + file_suffix + )) + .unwrap(); + + let kcl_code = fs::read_to_string( + construct_full_path( + &Path::new("invalid_validate_cases") + .join(case) + .display() + .to_string(), + ) + .unwrap(), + ) + .expect("Something went wrong reading the file"); + + let opt = ValidateOption::new( + None, + "value".to_string(), + validated_file_path.clone(), + *LOADER_KIND[i], + None, + Some(kcl_code), + ); + + let result = validate(opt).unwrap_err(); + assert!(result.to_string().contains("Error"), "{result}"); + } + } + } + + fn test_validate_with_invalid_kcl_path() { + let opt = ValidateOption::new( + None, + "value".to_string(), + "The validated file path is invalid".to_string(), + LoaderKind::JSON, + None, + None, + ); + + match validate(opt) { + Ok(_) => { + panic!("unreachable") + } + Err(err) => { + assert_eq!( + err.to_string(), + "Cannot find the kcl file, please check the file path validationTempKCLCode.k" + ); + } + } + } + + fn test_validate_with_invalid_file_path() { + let kcl_code = fs::read_to_string( + construct_full_path(&format!("{}/{}", "validate_cases", "test.k")).unwrap(), + ) + .expect("Something went wrong reading the file"); + + let opt = ValidateOption::new( + None, + "value".to_string(), + "invalid/file/path".to_string(), + LoaderKind::JSON, + None, + Some(kcl_code), + ); + + match validate(opt) { + Ok(_) => { + panic!("unreachable") + } + Err(err) => { + assert_eq!(err.to_string(), "Failed to Load 'invalid/file/path'") + } + } + } + + fn test_validate_with_invalid_file_type() { + let kcl_code = fs::read_to_string( + construct_full_path(&format!("{}/{}", "validate_cases", "test.k")).unwrap(), + ) + .expect("Something went wrong reading the file"); + + let validated_file_path = + construct_full_path(&format!("{}/{}", "validate_cases", "test.k.yaml")).unwrap(); + + let opt = ValidateOption::new( + None, + "value".to_string(), + validated_file_path, + LoaderKind::JSON, + None, + Some(kcl_code), + ); + + match validate(opt) { + Ok(_) => { + panic!("unreachable") + } + Err(err) => { + assert_eq!(err.to_string(), "Failed to Load JSON") + } + } + } +} + +/// Deal with windows filepath +#[allow(unused)] +fn deal_windows_filepath(filepath: String, transform: F) -> String +where + F: FnOnce(String) -> String, +{ + #[cfg(not(target_os = "windows"))] + return filepath; + #[cfg(target_os = "windows")] + { + use kclvm_utils::path::PathPrefix; + let path = PathBuf::from(filepath) + .canonicalize() + .unwrap() + .display() + .to_string(); + return transform(Path::new(&path).adjust_canonicalization()); + } +} diff --git a/kclvm/tools/src/vet/validator.rs b/kclvm/tools/src/vet/validator.rs new file mode 100644 index 000000000..402e38dce --- /dev/null +++ b/kclvm/tools/src/vet/validator.rs @@ -0,0 +1,295 @@ +//! KCL-Vet can use KCL to validate the content of json or yaml files. +//! +//! The entry point of KCL-Vet is method `validate`, for more information, see doc above method `validate`. +//! +//! The main principle consists of three parts: +//! +//! - Validation rules for validating file contents are defined in KCL statment. +//! - Convert the json or yaml file to be verified into a KCL assign expression. +//! - Combine KCL statment and KCL expression into a KCL program, +//! and the KCL program is checked by the KCLVM compiler. +//! +//! For example. +//! +//! 1. If the json file to be verified is as follows: +//! (kclvm/tools/src/vet/test_datas/validate_cases/test.json) +//! +//! ```ignore +//! { +//! "name": "Alice", +//! "age": 18, +//! "message": "This is Alice" +//! } +//! ``` +//! +//! 2. You can define KCL like below and define validation rules in check block. +//! (kclvm/tools/src/vet/test_datas/validate_cases/test.k) +//! +//! ```ignore +//! schema User: +//! name: str +//! age: int +//! message?: str +//! +//! check: +//! name == "Alice" +//! age > 10 +//! ``` +//! +//! 3. The json file mentioned in 1 will generate the following kcl expression: +//! +//! ```ignore +//! value = User { +//! name: "Alice", +//! age: 18, +//! message: "This is Alice" +//! } +//! ``` +//! +//! 4. Finally, a KCL program like the following will be handed over to KCLVM to compile and check for problems. +//! +//! ```ignore +//! value = User { +//! name: "Alice", +//! age: 18, +//! message: "This is Alice" +//! } +//! +//! schema User: +//! name: str +//! age: int +//! message?: str +//! +//! check: +//! name == "Alice" +//! age > 10 +//! ``` + +use super::expr_builder::ExprBuilder; +pub use crate::util::loader::LoaderKind; +use anyhow::Result; +use kclvm_ast::{ + ast::{AssignStmt, Expr, Node, NodeRef, Program, SchemaStmt, Stmt, Target}, + node_ref, +}; +use kclvm_parser::{LoadProgramOptions, ParseSessionRef}; +use kclvm_runner::{execute, ExecProgramArgs, MapErrorResult}; + +const TMP_FILE: &str = "validationTempKCLCode.k"; + +/// Validate the data string using the schema code string, when the parameter +/// `schema` is omitted, use the first schema appeared in the kcl code. +/// +/// Returns a bool result denoting whether validating success, raise an error +/// when validating failed because of the file not found error, schema not found +/// error, syntax error, check error, etc. +/// +/// When the content of the json file conforms to the rules, a normal kcl expression will be returned. +/// +/// # Examples +/// +/// 1. If you want to verify the following json file. +/// (kclvm/tools/src/vet/test_datas/validate_cases/test.json) +/// ```ignore +/// { +/// "name": "Alice", +/// "age": 18, +/// "message": "This is Alice" +/// } +/// ``` +/// +/// 2. First, you can create a KCL schema and write validation rules. +/// (kclvm/tools/src/vet/test_datas/validate_cases/test.k) +/// ```ignore +/// schema User: +/// name: str +/// age: int +/// message?: str +/// +/// check: +/// name == "Alice" +/// age > 10 +/// ``` +/// +/// 3. Second, you can call this method as follows to validate the content of the json file with the kcl file. +/// ``` +/// use kclvm_tools::vet::validator::validate; +/// use std::path::PathBuf; +/// use kclvm_tools::util::loader::LoaderKind; +/// use kclvm_tools::vet::validator::ValidateOption; +/// // First get the file path of the file to be verified. +/// let mut validated_file_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); +/// validated_file_path.push("src/vet/test_datas/validate_cases/test.json"); +/// let validated_file_path = validated_file_path.to_str().unwrap(); +/// +/// // Then get the path to the KCL file. +/// let mut kcl_file_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); +/// kcl_file_path.push("src/vet/test_datas/validate_cases/test.k"); +/// let kcl_file_path = Some(kcl_file_path.to_str().unwrap()); +/// +/// // Get the name of the schema defined in the kcl file +/// let schema_name = Some("User".to_string()); +/// +/// // Define the name of an attribute. +/// // The name of this property is related to the rules in the KCL file. +/// let attr_name = "value".to_string(); +/// +/// // Define the kind of file you want to validate. +/// let kind = LoaderKind::JSON; +/// +/// // One of the KCL file path or the content of the KCL file is enough. +/// let result = validate(ValidateOption::new(schema_name, attr_name, validated_file_path.to_string(), kind, None, None)); +/// ``` +/// +/// The json file used above conforms to the schema rules, so the content of `result` you get is : +/// +/// If you change the content of the above json file to : +/// ```ignore +/// { +/// "name": "Tom", +/// "age": 18, +/// "message": "This is Alice" +/// } +/// ``` +/// +/// You will get an error message like this: +/// ```ignore +/// { +/// "__kcl_PanicInfo__": true, +/// "rust_file": "runtime/src/value/api.rs", +/// "rust_line": 2203, +/// "rust_col": 9, +/// "kcl_pkgpath": "__main__", +/// "kcl_file": "kclvm/tools/src/vet/test_datas/invalid_validate_cases/test.json", +/// "kcl_line": 7, +/// "kcl_col": 0, +/// "kcl_arg_msg": "Check failed on the condition", +/// "kcl_config_meta_file": "", +/// "kcl_config_meta_line": 1, +/// "kcl_config_meta_col": 1, +/// "kcl_config_meta_arg_msg": "Instance check failed", +/// "message": "", +/// "err_type_code": 17, +/// "is_warning": false +/// } +/// ``` +pub fn validate(val_opt: ValidateOption) -> Result { + let k_path = val_opt.kcl_path.unwrap_or_else(|| TMP_FILE.to_string()); + let k_code = val_opt.kcl_code.map_or_else(Vec::new, |code| vec![code]); + + let sess = ParseSessionRef::default(); + let compile_res = kclvm_parser::load_program( + sess, + [k_path] + .iter() + .map(|s| s.as_str()) + .collect::>() + .as_slice(), + Some(LoadProgramOptions { + k_code_list: k_code, + package_maps: Default::default(), + load_plugins: true, + ..Default::default() + }), + None, + )?; + + let schemas = filter_schema_stmt_from_prog(&compile_res.program); + let schema_name = match val_opt.schema_name { + Some(name) => Some(name), + None => schemas.first().map(|schema| schema.name.node.clone()), + }; + + let expr_builder = + ExprBuilder::new_with_file_path(val_opt.validated_file_kind, val_opt.validated_file_path)?; + + let validated_expr = expr_builder.build(schema_name)?; + + let assign_stmt = build_assign(&val_opt.attribute_name, validated_expr); + + match compile_res.program.pkgs.get(kclvm_ast::MAIN_PKG) { + Some(pkg) => { + if let Some(module) = pkg.first() { + let mut m = compile_res + .program + .get_module_mut(module) + .expect("Failed to acquire module lock") + .expect(&format!("module {:?} not found in program", module)); + m.body.insert(0, assign_stmt); + } else { + return Err(anyhow::anyhow!("No main module found")); + } + } + None => { + return Err(anyhow::anyhow!("No main package found")); + } + } + + execute( + ParseSessionRef::default(), + compile_res.program, + &ExecProgramArgs::default(), + ) + .map_err_to_result() + .map(|_| true) +} + +fn build_assign(attr_name: &str, node: NodeRef) -> NodeRef { + node_ref!(Stmt::Assign(AssignStmt { + targets: vec![node_ref!(Target { + name: Node::dummy_node(attr_name.to_string()), + paths: vec![], + pkgpath: "".to_string(), + })], + value: node, + ty: None, + })) +} + +fn filter_schema_stmt_from_prog(prog: &Program) -> Vec { + let mut result = vec![]; + for (pkg_name, modules) in &prog.pkgs { + if pkg_name != kclvm_ast::MAIN_PKG { + continue; + } + for module in modules { + let module = prog.get_module(&module).unwrap().unwrap(); + for stmt in &module.body { + if let Stmt::Schema(s) = &stmt.node { + result.push(s.clone()); + } + } + } + } + + result +} + +pub struct ValidateOption { + schema_name: Option, + attribute_name: String, + validated_file_path: String, + validated_file_kind: LoaderKind, + kcl_path: Option, + kcl_code: Option, +} + +impl ValidateOption { + pub fn new( + schema_name: Option, + attribute_name: String, + validated_file_path: String, + validated_file_kind: LoaderKind, + kcl_path: Option, + kcl_code: Option, + ) -> Self { + Self { + schema_name, + attribute_name, + validated_file_path, + validated_file_kind, + kcl_path, + kcl_code, + } + } +} diff --git a/kclvm/utils/Cargo.toml b/kclvm/utils/Cargo.toml new file mode 100644 index 000000000..7337f69b0 --- /dev/null +++ b/kclvm/utils/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "kclvm-utils" +version = "0.11.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +anyhow = "1" +regex = "1.3" + + +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +fslock = "0.2.1" diff --git a/kclvm/utils/src/fslock.rs b/kclvm/utils/src/fslock.rs new file mode 100644 index 000000000..34d6685fb --- /dev/null +++ b/kclvm/utils/src/fslock.rs @@ -0,0 +1,31 @@ +//! Copyright The KCL Authors. All rights reserved. + +#[cfg(unix)] +pub fn open_lock_file(path: &str) -> Result { + return fslock::LockFile::open(path); +} + +#[cfg(windows)] +pub fn open_lock_file(path: &str) -> Result { + return fslock::LockFile::open(path); +} + +#[cfg(target_arch = "wasm32")] +pub fn open_lock_file(_path: &str) -> Result { + Ok(LockFile { _fd: 0 }) +} + +#[cfg(target_arch = "wasm32")] +pub struct LockFile { + _fd: i32, +} + +#[cfg(target_arch = "wasm32")] +impl LockFile { + pub fn lock(&mut self) -> Result<(), std::io::Error> { + Ok(()) // TODO: support wasm32 + } + pub fn unlock(&mut self) -> Result<(), std::io::Error> { + Ok(()) // TODO: support wasm32 + } +} diff --git a/kclvm/utils/src/lib.rs b/kclvm/utils/src/lib.rs new file mode 100644 index 000000000..78d566ee1 --- /dev/null +++ b/kclvm/utils/src/lib.rs @@ -0,0 +1,3 @@ +pub mod fslock; +pub mod path; +pub mod pkgpath; diff --git a/kclvm/utils/src/path.rs b/kclvm/utils/src/path.rs new file mode 100644 index 000000000..baa27ba78 --- /dev/null +++ b/kclvm/utils/src/path.rs @@ -0,0 +1,151 @@ +//! This file primarily offers utils for working with file paths, +//! enabling them to be automatically formatted according to the OS. + +use std::path::Path; + +/// Util methods for file path prefixes +pub trait PathPrefix { + /// In the Windows system, the file path returned by method [`canonicalize()`], + /// in rust [`PathBuf`] or [`Path`], will include the '\\?\' character, + /// which is prepared for the Windows API. + /// + /// Paths containing "\\?\" may sometimes result in the file being unable to be found. + /// As such, [`adjust_canonicalization()`] is required to remove this '\\?\'. + /// On non-Windows systems, this method does not make any modifications to the file path. + /// + /// For more information about "\\?\", + /// see https://learn.microsoft.com/en-us/windows/win32/fileio/naming-a-file#short-vs-long-names + fn adjust_canonicalization(&self) -> String; +} + +impl

PathPrefix for P +where + P: AsRef, +{ + #[cfg(not(target_os = "windows"))] + /// On non-Windows systems, this method does not make any modifications to the file path. + /// + /// # Examples + /// + /// ```rust + /// use std::path::Path; + /// use kclvm_utils::path::PathPrefix; + /// + /// let path = Path::new(".").canonicalize().unwrap(); + /// assert_eq!( + /// path.clone().adjust_canonicalization(), + /// path.display().to_string() + /// ); + /// ``` + fn adjust_canonicalization(&self) -> String { + self.as_ref().display().to_string() + } + + #[cfg(target_os = "windows")] + /// For kclvm on windows, the "\\?\ " will cause the obj file to not be found when linking by "cl.exe". + /// + /// Slicing this path directly is not a good solution, + /// we will find a more fluent way to solve this problem in the future. @zongz + /// Note: On windows systems, a file path that is too long may cause "cl.exe" to crash. + /// For more information, see doc in trait [`PathPrefix`]. + /// + /// # Examples + /// + /// ```rust + /// use std::path::Path; + /// use kclvm_utils::path::PathPrefix; + /// + /// let path = Path::new(".").canonicalize().unwrap(); + /// assert!(path.display().to_string().contains("\\\\?\\")); + /// assert!(!path.adjust_canonicalization().contains("\\\\?\\")); + /// ``` + fn adjust_canonicalization(&self) -> String { + const VERBATIM_PREFIX: &str = r#"\\?\"#; + const ESCAPE_VERBATIM_PREFIX: &str = r#"\\\\?\\"#; + let p = self.as_ref().display().to_string(); + if p.starts_with(VERBATIM_PREFIX) { + p[VERBATIM_PREFIX.len()..].to_string() + } else if p.starts_with(ESCAPE_VERBATIM_PREFIX) { + p[ESCAPE_VERBATIM_PREFIX.len()..].to_string() + } else { + p + } + } +} + +/// Convert windows drive letter to upcase +pub fn convert_windows_drive_letter(path: &str) -> String { + #[cfg(target_os = "windows")] + { + let regex = regex::Regex::new(r"(?i)^\\\\\?\\[a-z]:\\").unwrap(); + const VERBATIM_PREFIX: &str = r#"\\?\"#; + let mut p = path.to_string(); + if p.starts_with(VERBATIM_PREFIX) && regex.is_match(&p) { + let drive_letter = p[VERBATIM_PREFIX.len()..VERBATIM_PREFIX.len() + 1].to_string(); + p.replace_range( + VERBATIM_PREFIX.len()..VERBATIM_PREFIX.len() + 1, + &drive_letter.to_uppercase(), + ); + } + let regex = regex::Regex::new(r"[a-z]:\\").unwrap(); + if regex.is_match(&p) { + let drive_letter = p[0..1].to_string(); + p.replace_range(0..1, &drive_letter.to_uppercase()); + } + p + } + #[cfg(not(target_os = "windows"))] + { + path.to_owned() + } +} + +#[test] +fn test_convert_drive_letter() { + #[cfg(target_os = "windows")] + { + let path = r"\\?\d:\xx"; + assert_eq!(convert_windows_drive_letter(path), r"\\?\D:\xx".to_string()); + + let path = r"d:\xx"; + assert_eq!(convert_windows_drive_letter(path), r"D:\xx".to_string()); + } + #[cfg(not(target_os = "windows"))] + { + let path = r".\xx"; + assert_eq!(convert_windows_drive_letter(path), path.to_string()); + } +} + +#[test] +#[cfg(target_os = "windows")] +fn test_adjust_canonicalization() { + let path = Path::new(".").canonicalize().unwrap(); + assert!(path.display().to_string().contains("\\\\?\\")); + assert!(!path.adjust_canonicalization().contains("\\\\?\\")); +} + +#[test] +#[cfg(not(target_os = "windows"))] +fn test_adjust_canonicalization1() { + let path = Path::new(".").canonicalize().unwrap(); + assert_eq!( + path.clone().adjust_canonicalization(), + path.display().to_string() + ); +} + +#[inline] +pub fn is_dir(path: &str) -> bool { + std::path::Path::new(path).is_dir() +} + +#[inline] +pub fn is_absolute(path: &str) -> bool { + std::path::Path::new(path).is_absolute() +} + +#[inline] +pub fn path_exist(path: &str) -> bool { + std::path::Path::new(path).exists() +} diff --git a/kclvm/utils/src/pkgpath.rs b/kclvm/utils/src/pkgpath.rs new file mode 100644 index 000000000..ca837359e --- /dev/null +++ b/kclvm/utils/src/pkgpath.rs @@ -0,0 +1,34 @@ +//! This file primarily offers utils for working with kcl package paths. + +use anyhow::{anyhow, Result}; + +/// Remove the external package name prefix from the current import absolute path. +/// +/// # Note +/// [`rm_external_pkg_name`] just remove the prefix of the import path, +/// so it can't distinguish whether the current path is an internal package or an external package. +/// +/// # Error +/// An error is returned if an empty string is passed in. +pub fn rm_external_pkg_name(pkgpath: &str) -> Result { + Ok(pkgpath + .to_string() + .trim_start_matches(parse_external_pkg_name(pkgpath)?.as_str()) + .to_string()) +} + +/// Remove the external package name prefix from the current import absolute path. +/// +/// # Note +/// [`rm_external_pkg_name`] just remove the prefix of the import path, +/// so it can't distinguish whether the current path is an internal package or an external package. +/// +/// # Error +/// An error is returned if an empty string is passed in. +pub fn parse_external_pkg_name(pkgpath: &str) -> Result { + let mut names = pkgpath.splitn(2, '.'); + match names.next() { + Some(it) => Ok(it.to_string()), + None => Err(anyhow!("Invalid external package name `{}`", pkgpath)), + } +} diff --git a/kclvm/version/Cargo.toml b/kclvm/version/Cargo.toml index ed73f8905..925d9b7d3 100644 --- a/kclvm/version/Cargo.toml +++ b/kclvm/version/Cargo.toml @@ -1,8 +1,11 @@ [package] name = "kclvm-version" -version = "0.1.0" +version = "0.11.0" edition = "2021" +[build-dependencies] +vergen-gitcl = { version = "1.0.0", features = ["rustc"] } + # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] diff --git a/kclvm/version/build.rs b/kclvm/version/build.rs new file mode 100644 index 000000000..a667e863d --- /dev/null +++ b/kclvm/version/build.rs @@ -0,0 +1,14 @@ +use std::error::Error; +use vergen_gitcl::*; + +fn main() -> Result<(), Box> { + let gitcl = GitclBuilder::default().sha(false).build()?; + let rustc = RustcBuilder::all_rustc()?; + + Emitter::default() + .add_instructions(&gitcl)? + .add_instructions(&rustc)? + .emit()?; + + Ok(()) +} diff --git a/kclvm/version/src/lib.rs b/kclvm/version/src/lib.rs index d395488b9..978285988 100644 --- a/kclvm/version/src/lib.rs +++ b/kclvm/version/src/lib.rs @@ -1,8 +1,29 @@ -// Copyright 2021 The KCL Authors. All rights reserved. +//! Copyright The KCL Authors. All rights reserved. -pub const VERSION: &str = "0.4.2"; -pub const CHECK_SUM: &str = "e07ed7af0d9bd1e86a3131714e4bd20c"; +pub const VERSION: &str = include_str!("./../../../VERSION"); +pub const CHECK_SUM: &str = "c020ab3eb4b9179219d6837a57f5d323"; +pub const GIT_SHA: &str = env!("VERGEN_GIT_SHA"); +pub const HOST_TRIPLE: &str = env!("VERGEN_RUSTC_HOST_TRIPLE"); -pub fn get_full_version() -> String { +/// Get KCL full version string with the format `{version}-{check_sum}`. +#[inline] +pub fn get_version_string() -> String { format!("{}-{}", VERSION, CHECK_SUM) } + +/// Get KCL build git sha. +#[inline] +pub fn get_git_sha() -> &'static str { + option_env!("KCL_BUILD_GIT_SHA").unwrap_or_else(|| GIT_SHA) +} + +/// Get version info including version string, platform. +#[inline] +pub fn get_version_info() -> String { + format!( + "Version: {}\r\nPlatform: {}\r\nGitCommit: {}", + get_version_string(), + HOST_TRIPLE, + get_git_sha(), + ) +} diff --git a/plugins b/plugins deleted file mode 160000 index 23fc581db..000000000 --- a/plugins +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 23fc581dbfcb041f10a72b57fb6aa4f3a2ae824a diff --git a/run.sh b/run.sh index 38bbbf578..fae2cc480 100755 --- a/run.sh +++ b/run.sh @@ -1,36 +1,35 @@ #!/usr/bin/env bash # Environment -if [ -f "/etc/os-release" ]; then - source /etc/os-release - os=$ID -else - os=$(uname) -fi +getSystemInfo() { + arch=$(uname -m) + case $arch in + armv7*) arch="arm";; + aarch64) arch="arm64";; + x86_64) arch="amd64";; + esac + + os=$(echo `uname`|tr '[:upper:]' '[:lower:]') +} + +getSystemInfo topdir=$PWD +version=v$(cat VERSION) # Options help_message=$(cat <<-END Usage: run.sh -h - Print this help message + Print this help message. run.sh -a [action] - Perform an action + Perform an action. run.sh - Perform an action interactively + Perform an action interactively. Available actions: build - Build everything - build-cpython - Configure and build CPython - build-kclvm - Package CPython and the KCLVM extension into KCLVM - update-kclvm - Quickly update KCLVM without packaging CPython and site-packages - test - Perform testing + Build the KCL package. release - Create a package for releasing + Create a releasing for the KCL package. END ) action= @@ -53,25 +52,13 @@ done if [ "$action" == "" ]; then PS3='Please select the action: ' - options=("build" "build-cpython" "build-kclvm" "update-kclvm" "test" "release") + options=("build" "release") select action in "${options[@]}" do case $action in "build") break ;; - "build-cpython") - break - ;; - "build-kclvm") - break - ;; - "update-kclvm") - break - ;; - "test") - break - ;; "release") break ;; @@ -83,4 +70,4 @@ if [ "$action" == "" ]; then done fi -os=$os topdir=$topdir sslpath=$sslpath $topdir/internal/kclvm_py/scripts/$action.sh +topdir=$topdir version=$version sslpath=$sslpath $topdir/scripts/$action.sh diff --git a/samples/README.md b/samples/README.md new file mode 100644 index 000000000..f75459356 --- /dev/null +++ b/samples/README.md @@ -0,0 +1,3 @@ +# Examples + +More examples can be found at [here](https://github.com/kcl-lang/kcl-lang.io/tree/main/examples). diff --git a/samples/fib.k b/samples/fib.k index fcb164f58..96926c055 100644 --- a/samples/fib.k +++ b/samples/fib.k @@ -1,6 +1,6 @@ schema Fib: - n1: int = n - 1 - n2: int = n1 - 1 + n1 = n - 1 + n2 = n1 - 1 n: int value: int @@ -9,6 +9,6 @@ schema Fib: elif n == 2: value = 1 else: - value = Fib {n: n1}.value + Fib {n: n2}.value + value = Fib {n = n1}.value + Fib {n = n2}.value -fib8 = Fib {n: 8}.value +fib8 = Fib {n = 8}.value diff --git a/samples/kubernetes.k b/samples/kubernetes.k new file mode 100644 index 000000000..357c2d2d5 --- /dev/null +++ b/samples/kubernetes.k @@ -0,0 +1,18 @@ +apiVersion = "apps/v1" +kind = "Deployment" +metadata = { + name = "nginx" + labels.app = "nginx" +} +spec = { + replicas = 3 + selector.matchLabels = metadata.labels + template.metadata.labels = metadata.labels + template.spec.containers = [ + { + name = metadata.name + image = "${metadata.name}:1.14.2" + ports = [{ containerPort = 80 }] + } + ] +} diff --git a/samples/math.k b/samples/math.k new file mode 100644 index 000000000..d62071862 --- /dev/null +++ b/samples/math.k @@ -0,0 +1,3 @@ +import math + +a = math.log10(100) # 2 diff --git a/scripts/build-llvm/build.ps1 b/scripts/build-llvm/build.ps1 new file mode 100755 index 000000000..62277b859 --- /dev/null +++ b/scripts/build-llvm/build.ps1 @@ -0,0 +1,69 @@ +$LLVM_VERSION = $args[0] +$LLVM_REPO_URL = $args[1] + +if ([string]::IsNullOrEmpty($LLVM_REPO_URL)) { + $LLVM_REPO_URL = "https://github.com/llvm/llvm-project.git" +} + +if ([string]::IsNullOrEmpty($LLVM_VERSION)) { + Write-Output "Usage: $PSCommandPath " + Write-Output "" + Write-Output "# Arguments" + Write-Output " llvm-version The name of a LLVM release branch without the 'release/' prefix" + Write-Output " llvm-repository-url The URL used to clone LLVM sources (default: https://github.com/llvm/llvm-project.git)" + + exit 1 +} + +# Clone the LLVM project. +if (-not (Test-Path -Path "llvm-project" -PathType Container)) { + git clone "$LLVM_REPO_URL" llvm-project +} + +Set-Location llvm-project +git fetch origin +git checkout "release/$LLVM_VERSION" +git reset --hard origin/"release/$LLVM_VERSION" + +# Create a directory to build the project. +New-Item -Path "build" -Force -ItemType "directory" +Set-Location build + +# Create a directory to receive the complete installation. +New-Item -Path "install" -Force -ItemType "directory" + +# Adjust compilation based on the OS. +$CMAKE_ARGUMENTS = "" + +# Adjust cross compilation +$CROSS_COMPILE = "" + +# Run `cmake` to configure the project. +cmake ` + -G "Visual Studio 16 2019" ` + -DCMAKE_BUILD_TYPE=MinSizeRel ` + -DCMAKE_INSTALL_PREFIX=destdir ` + -DLLVM_ENABLE_PROJECTS="clang;lld" ` + -DLLVM_ENABLE_TERMINFO=OFF ` + -DLLVM_ENABLE_ZLIB=OFF ` + -DLLVM_INCLUDE_DOCS=OFF ` + -DLLVM_INCLUDE_EXAMPLES=OFF ` + -DLLVM_INCLUDE_GO_TESTS=OFF ` + -DLLVM_INCLUDE_TESTS=OFF ` + -DLLVM_INCLUDE_TOOLS=ON ` + -DLLVM_INCLUDE_UTILS=OFF ` + -DLLVM_OPTIMIZED_TABLEGEN=ON ` + -DLLVM_TARGETS_TO_BUILD="X86;AArch64" ` + $CROSS_COMPILE ` + $CMAKE_ARGUMENTS ` + ../llvm + +# Showtime! +cmake --build . --config Release + +# Not using DESTDIR here, quote from +# https://cmake.org/cmake/help/latest/envvar/DESTDIR.html +# > `DESTDIR` may not be used on Windows because installation prefix +# > usually contains a drive letter like in `C:/Program Files` which cannot +# > be prepended with some other prefix. +cmake --install . --strip --config Release diff --git a/scripts/build-llvm/build.sh b/scripts/build-llvm/build.sh new file mode 100755 index 000000000..56f05da22 --- /dev/null +++ b/scripts/build-llvm/build.sh @@ -0,0 +1,84 @@ +#!/bin/bash + +# Display all commands before executing them. +set -o errexit +set -o errtrace + +LLVM_VERSION=$1 +LLVM_REPO_URL=${2:-https://github.com/llvm/llvm-project.git} +LLVM_CROSS="$3" + +if [[ -z "$LLVM_REPO_URL" || -z "$LLVM_VERSION" ]] +then + echo "Usage: $0 [aarch64]" + echo + echo "# Arguments" + echo " llvm-version The name of a LLVM release branch without the 'release/' prefix" + echo " llvm-repository-url The URL used to clone LLVM sources (default: https://github.com/llvm/llvm-project.git)" + echo " aarch64 To cross-compile an aarch64 version of LLVM" + + exit 1 +fi + +# Clone the LLVM project. +if [ ! -d llvm-project ] +then + git clone "$LLVM_REPO_URL" llvm-project +fi + + +cd llvm-project +git fetch origin +git checkout "release/$LLVM_VERSION" +git reset --hard origin/"release/$LLVM_VERSION" + +# Create a directory to build the project. +mkdir -p build +cd build + +# Create a directory to receive the complete installation. +mkdir -p install + +# Adjust compilation based on the OS. +CMAKE_ARGUMENTS="" + +case "${OSTYPE}" in + darwin*) ;; + linux*) ;; + *) ;; +esac + +# Adjust cross compilation +CROSS_COMPILE="" + +case "${LLVM_CROSS}" in + aarch64*) CROSS_COMPILE="-DLLVM_HOST_TRIPLE=aarch64-linux-gnu" ;; + *) ;; +esac + +# Run `cmake` to configure the project. +cmake \ + -G "Unix Makefiles" \ + -DCMAKE_BUILD_TYPE=MinSizeRel \ + -DCMAKE_INSTALL_PREFIX="/" \ + -DLLVM_ENABLE_PROJECTS="clang;lld" \ + -DLLVM_ENABLE_TERMINFO=OFF \ + -DLLVM_ENABLE_ZLIB=OFF \ + -DLLVM_INCLUDE_DOCS=OFF \ + -DLLVM_INCLUDE_EXAMPLES=OFF \ + -DLLVM_INCLUDE_GO_TESTS=OFF \ + -DLLVM_INCLUDE_TESTS=OFF \ + -DLLVM_INCLUDE_TOOLS=ON \ + -DLLVM_INCLUDE_UTILS=OFF \ + -DLLVM_OPTIMIZED_TABLEGEN=ON \ + -DLLVM_TARGETS_TO_BUILD="X86;AArch64" \ + "${CROSS_COMPILE}" \ + "${CMAKE_ARGUMENTS}" \ + ../llvm + +# Showtime! +cmake --build . --config MinSizeRel +DESTDIR=destdir cmake --install . --strip --config MinSizeRel + +# move usr/bin/* to bin/ or llvm-config will be broken +mv destdir/usr/bin/* destdir/bin/ diff --git a/scripts/build-windows/Makefile b/scripts/build-windows/Makefile deleted file mode 100644 index cb26484d5..000000000 --- a/scripts/build-windows/Makefile +++ /dev/null @@ -1,73 +0,0 @@ -# Copyright 2021 The KCL Authors. All rights reserved. - -# Only on windows platform: use mingw32-make to run. - -default: - go run download-file.go - go run unzip.go - - go run gen_pth.go - - # install pip - _output/kclvm-windows/python.exe get-pip.py - - # pip install -r ./requirements.txt - _output/kclvm-windows/python.exe -m pip install -r ./requirements.release.txt --target=_output/kclvm-windows/Lib/site-packages - - # install kclvm - go run ./copy-dir.go ../../internal/kclvm_py ./_output/kclvm-windows/Lib/site-packages/kclvm - - # go run gen-kclvm-py.go - - # renname - go run rename.go -old="_output/kclvm-windows/python.exe" -new="_output/kclvm-windows/kclvm.exe" - - # install python39 include and libs - go run ./copy-dir.go ./py39-libs ./_output/kclvm-windows - - # install kclvm-runtime - cd ../../kclvm/runtime && cargo build --release - go run ./copy-file.go -src=../../kclvm/runtime/target/release/kclvm.dll -dst=./_output/kclvm-windows/libs/kclvm.dll - go run ./copy-file.go -src=../../kclvm/runtime/target/release/kclvm.dll.lib -dst=./_output/kclvm-windows/libs/kclvm.dll.lib - go run ./copy-file.go -src=../../kclvm/runtime/src/_kclvm.ll -dst=./_output/kclvm-windows/libs/_kclvm.ll - go run ./copy-file.go -src=../../kclvm/runtime/src/_kclvm.bc -dst=./_output/kclvm-windows/libs/_kclvm.bc - go run ./copy-file.go -src=../../kclvm/runtime/src/_kclvm.h -dst=./_output/kclvm-windows/libs/_kclvm.h - go run ./copy-file.go -src=../../kclvm/runtime/src/_kclvm_main_win.c -dst=./_output/kclvm-windows/libs/_kclvm_main_win.c - - # install kclvm-plugin - ./_output/kclvm-windows/kclvm.exe ../../kclvm/plugin/setup.py install_lib - - # install kclvm-cli - cd ../../kclvm && cargo build --release - go run ./copy-file.go -src=../../kclvm/target/release/kclvm_cli.exe -dst=./_output/kclvm-windows/kclvm_cli.exe - go run ./copy-file.go -src=../../kclvm/target/release/kclvm_cli_cdylib.dll -dst=./_output/kclvm-windows/kclvm_cli_cdylib.dll - go run ./copy-file.go -src=../../kclvm/target/release/kclvm_cli_cdylib.dll.lib -dst=./_output/kclvm-windows/libs/kclvm_cli_cdylib.dll.lib - - # build rust std lib - go run install-rust-std.go -outdir=./_output/kclvm-windows - - # install kcl plugins - go run ./copy-dir.go ../../plugins ./_output/kclvm-windows/plugins - - # install hello.k - go run ./copy-file.go -src=../../samples/hello.k -dst=./_output/kclvm-windows/hello.k - - # install tools - go build -o ./_output/kclvm-windows/kcl.exe kcl.go - go build -o ./_output/kclvm-windows/kcl-doc.exe kcl-doc.go - go build -o ./_output/kclvm-windows/kcl-lint.exe kcl-lint.go - go build -o ./_output/kclvm-windows/kcl-fmt.exe kcl-fmt.go - go build -o ./_output/kclvm-windows/kcl-plugin.exe kcl-plugin.go - go build -o ./_output/kclvm-windows/kcl-vet.exe kcl-vet.go - go build -o ./_output/kclvm-windows/kcl-fmt.exe kcl-fmt.go - - # todo: build zip - - # todo: run hello.k - # _output/kclvm-windows/kclvm.exe -m kclvm ../../samples/hello.k - # _output/kclvm-windows/kcl-go.exe run ../../samples/hello.k - # _output/kclvm-windows/kcl.exe ../../samples/hello.k - - -clean: - diff --git a/scripts/build-windows/build-win-installer.nsi b/scripts/build-windows/build-win-installer.nsi deleted file mode 100644 index 138069229..000000000 --- a/scripts/build-windows/build-win-installer.nsi +++ /dev/null @@ -1,50 +0,0 @@ -; Copyright 2021 The KCL Authors. All rights reserved. - -; makensis.exe build-win-installer.nsi - -!include LogicLib.nsh - -;-------------------------------- - -; The name of the installer -Name "KCLVM" - -; The file to write -OutFile "kclvm-installer.exe" - -; Request application privileges for Windows Vista -RequestExecutionLevel user - -; Build Unicode installer -Unicode True - -; The default installation directory - -InstallDir $PROFILE\.kusion\kclvm - -;-------------------------------- - -; Pages - -Page directory -Page instfiles - -;-------------------------------- - -; The stuff to install -Section "" ;No components page, name is not important - - ; Set output path to the installation directory. - SetOutPath $INSTDIR - - ; Put file there - File /r "_output\kclvm-windows\" - - ; update %path% - ReadRegStr $R0 HKCU "Environment" PATH - StrCpy $R1 "$R0;$INSTDIR" - WriteRegExpandStr HKCU "Environment" "Path" "$R1" - -SectionEnd - -;-------------------------------- diff --git a/scripts/build-windows/build.bat b/scripts/build-windows/build.bat deleted file mode 100644 index ff93e7efe..000000000 --- a/scripts/build-windows/build.bat +++ /dev/null @@ -1,83 +0,0 @@ -:: Copyright 2021 The KCL Authors. All rights reserved. - -setlocal - -cd %~dp0 - -go run download-file.go -go run unzip.go - -go run gen_pth.go - -:: renname -go run rename.go -old="_output\kclvm-windows\python.exe" -new="_output\kclvm-windows\kclvm.exe" - -:: install pip -_output\kclvm-windows\kclvm.exe get-pip.py - -:: pip install -r ..\requirements.txt -_output\kclvm-windows\kclvm.exe -m pip install ^ - -r .\requirements.release.txt ^ - --target=_output\kclvm-windows\Lib\site-packages ^ - -i http://mirrors.aliyun.com/pypi/simple/ ^ - --trusted-host mirrors.aliyun.com - -:: install kclvm -go run gen-kclvm-py.go - -:: install python39 include and libs -go run .\copy-dir.go .\py39-libs .\_output\kclvm-windows - -:: install kclvm-runtime -cd ..\..\kclvm\runtime -cargo build --release -cd %~dp0 - -go run .\copy-file.go --src=..\..\kclvm\runtime\target\release\kclvm.dll --dst=.\_output\kclvm-windows\kclvm.dll -go run .\copy-file.go --src=..\..\kclvm\runtime\target\release\kclvm.dll.lib --dst=.\_output\kclvm-windows\libs\kclvm.dll.lib -go run .\copy-file.go --src=..\..\kclvm\runtime\src\_kclvm.ll --dst=.\_output\kclvm-windows\libs\_kclvm.ll -go run .\copy-file.go --src=..\..\kclvm\runtime\src\_kclvm.bc --dst=.\_output\kclvm-windows\libs\_kclvm.bc -go run .\copy-file.go --src=..\..\kclvm\runtime\src\_kclvm.h --dst=.\_output\kclvm-windows\libs\_kclvm.h -go run .\copy-file.go --src=..\..\kclvm\runtime\src\_kclvm_main_win.c --dst=.\_output\kclvm-windows\libs\_kclvm_main_win.c - -:: install kclvm-runtime (wasm) -cd ..\..\kclvm\runtime -cargo build --release --target=wasm32-unknown-unknown-wasm -cd %~dp0 - -go run .\copy-file.go --src=..\..\kclvm\runtime\target\wasm32-unknown-unknown\release\libkclvm.a --dst=.\_output\kclvm-windows\libs\libkclvm_wasm32.a -go run .\copy-file.go --src=..\..\kclvm\runtime\src\_kclvm_undefined_wasm.txt --dst=.\_output\kclvm-windows\libs\_kclvm_undefined_wasm.txt - -:: install kclvm-plugin -.\_output\kclvm-windows\kclvm.exe ..\..\kclvm\plugin\setup.py install_lib -go run .\copy-file.go --src=..\..\kclvm\plugin\kclvm_plugin.py --dst=.\_output\kclvm-windows\Lib\site-packages\kclvm_plugin.py -go run .\copy-file.go --src=..\..\kclvm\plugin\kclvm_runtime.py --dst=.\_output\kclvm-windows\Lib\site-packages\kclvm_runtime.py - -:: install kclvm-cli -cd ..\..\kclvm -cargo build --release -cd %~dp0 - -go run .\copy-file.go --src=..\..\kclvm\target\release\kclvm.exe --dst=.\_output\kclvm-windows\kclvm-cli.exe - -:: install clang -go run .\copy-file.go ^ - --src=%LLVM_SYS_120_PREFIX%\bin\clang.exe ^ - --dst=.\_output\kclvm-windows\tools\clang\bin\clang.exe - -:: install hello.k -go run .\copy-file.go --src=..\..\hello.k --dst=.\_output\kclvm-windows\hello.k - -:: install tools -go build -o .\_output\kclvm-windows\kcl.exe kcl.go -go build -o .\_output\kclvm-windows\kcl-doc.exe kcl-doc.go -go build -o .\_output\kclvm-windows\kcl-lint.exe kcl-lint.go -go build -o .\_output\kclvm-windows\kcl-fmt.exe kcl-fmt.go -go build -o .\_output\kclvm-windows\kcl-plugin.exe kcl-plugin.go -go build -o .\_output\kclvm-windows\kcl-vet.exe kcl-vet.go - -:: run hello.k -_output\kclvm-windows\kclvm.exe -m kclvm ..\..\hello.k -_output\kclvm-windows\kcl-go.exe run ..\..\hello.k -_output\kclvm-windows\kcl.exe ..\..\hello.k - diff --git a/scripts/build-windows/build.ps1 b/scripts/build-windows/build.ps1 new file mode 100644 index 000000000..c6f81258a --- /dev/null +++ b/scripts/build-windows/build.ps1 @@ -0,0 +1,40 @@ +# Copyright The KCL Authors. All rights reserved. + +Set-Location $PSScriptRoot +# 1. Install kclvm_cli_cdylib.dll +Set-Location "..\..\kclvm" +# cargo build --release --features llvm +cargo build --release +Set-Location $PSScriptRoot + +New-Item -ErrorAction Ignore -Path ".\_output" -ItemType "directory" +New-Item -ErrorAction Ignore -Path ".\_output\kclvm-windows" -ItemType "directory" +New-Item -ErrorAction Ignore -Path ".\_output\kclvm-windows\bin" -ItemType "directory" + +Copy-Item -Path "..\..\kclvm\target\release\kclvm_cli_cdylib.dll" -Destination ".\_output\kclvm-windows\bin\kclvm_cli_cdylib.dll" -Force +Copy-Item -Path "..\..\kclvm\target\release\kclvm_cli_cdylib.dll.lib" -Destination ".\_output\kclvm-windows\bin\kclvm_cli_cdylib.lib" -Force +Copy-Item -Path "..\..\kclvm\target\release\kclvm_cli_cdylib.dll.lib" -Destination "..\..\kclvm\target\release\kclvm_cli_cdylib.lib" -Force + +Set-Location $PSScriptRoot +# 2. Install kclvm CLI +Set-Location "..\..\cli" +cargo build --release +Set-Location $PSScriptRoot +Copy-Item -Path "..\..\cli\target\release\kclvm_cli.exe" -Destination ".\_output\kclvm-windows\bin\" -Force + +Set-Location $PSScriptRoot +# 3. Install kcl language server +Set-Location "..\..\kclvm\tools\src\LSP" +cargo build --release +Set-Location $PSScriptRoot +Copy-Item -Path "..\..\kclvm\target\release\kcl-language-server.exe" -Destination ".\_output\kclvm-windows\bin\" + +Set-Location $PSScriptRoot +# Install hello.k +Copy-Item -Path "..\..\samples\hello.k" -Destination ".\_output\kclvm-windows" -Force + +# Run KCL files +.\_output\kclvm-windows\bin\kclvm_cli.exe run ..\..\samples\fib.k +.\_output\kclvm-windows\bin\kclvm_cli.exe run ..\..\samples\hello.k +.\_output\kclvm-windows\bin\kclvm_cli.exe run ..\..\samples\kubernetes.k +.\_output\kclvm-windows\bin\kclvm_cli.exe run ..\..\samples\math.k diff --git a/scripts/build-windows/clean.bat b/scripts/build-windows/clean.bat deleted file mode 100644 index b41703d59..000000000 --- a/scripts/build-windows/clean.bat +++ /dev/null @@ -1,9 +0,0 @@ -:: Copyright 2021 The KCL Authors. All rights reserved. - -setlocal - -cd %~dp0 - -rmdir _output - -del *.zip diff --git a/scripts/build-windows/clean.ps1 b/scripts/build-windows/clean.ps1 new file mode 100644 index 000000000..0088729bf --- /dev/null +++ b/scripts/build-windows/clean.ps1 @@ -0,0 +1,10 @@ +# Copyright The KCL Authors. All rights reserved. + +Set-Location $PSScriptRoot + +Remove-Item -Recurse -Force "_output" +Remove-Item -Recurse -Force "*.obj" +Remove-Item -Recurse -Force "*.exp" +Remove-Item -Recurse -Force "*.lib" +Remove-Item -Recurse -Force "*.dll" +Remove-Item -Force "*.zip" diff --git a/scripts/build-windows/copy-dir.go b/scripts/build-windows/copy-dir.go deleted file mode 100644 index 690e8ae0d..000000000 --- a/scripts/build-windows/copy-dir.go +++ /dev/null @@ -1,95 +0,0 @@ -// Copyright 2021 The KCL Authors. All rights reserved. - -//go:build ingore -// +build ingore - -// -// Copy dir, support regexp. -// -// Example: -// cpdir src dst -// cpdir src dst "\.go$" -// -// Help: -// cpdir -h -// -package main - -import ( - "fmt" - "io" - "io/ioutil" - "log" - "os" - "path/filepath" - "regexp" -) - -const usage = ` -Usage: cpdir src dst [filter] - cpdir -h - -Example: - cpdir src dst - cpdir src dst "\.go$" -` - -func main() { - if len(os.Args) < 3 { - fmt.Fprintln(os.Stderr, usage[1:len(usage)-1]) - os.Exit(0) - } - filter := ".*" - if len(os.Args) > 3 { - filter = os.Args[3] - } - total := cpDir(os.Args[2], os.Args[1], filter) - fmt.Printf("total %d\n", total) -} - -func cpDir(dst, src, filter string) (total int) { - entryList, err := ioutil.ReadDir(src) - if err != nil && !os.IsExist(err) { - log.Fatal("cpDir: ", err) - } - for _, entry := range entryList { - if entry.IsDir() { - cpDir(dst+"/"+entry.Name(), src+"/"+entry.Name(), filter) - } else { - mathed, err := regexp.MatchString(filter, entry.Name()) - if err != nil { - log.Fatal("regexp.MatchString: ", err) - } - if mathed { - srcFname := filepath.Clean(src + "/" + entry.Name()) - dstFname := filepath.Clean(dst + "/" + entry.Name()) - fmt.Printf("copy %s\n", srcFname) - - cpFile(dstFname, srcFname) - total++ - } - } - } - return -} - -func cpFile(dst, src string) { - err := os.MkdirAll(filepath.Dir(dst), 0777) - if err != nil && !os.IsExist(err) { - log.Fatal("cpFile: ", err) - } - fsrc, err := os.Open(src) - if err != nil { - log.Fatal("cpFile: ", err) - } - defer fsrc.Close() - - fdst, err := os.Create(dst) - if err != nil { - log.Fatal("cpFile: ", err) - } - defer fdst.Close() - if _, err = io.Copy(fdst, fsrc); err != nil { - log.Fatal("cpFile: ", err) - } -} diff --git a/scripts/build-windows/copy-file.go b/scripts/build-windows/copy-file.go deleted file mode 100644 index a3ef4e5e5..000000000 --- a/scripts/build-windows/copy-file.go +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright 2021 The KCL Authors. All rights reserved. - -//go:build ingore -// +build ingore - -package main - -import ( - "flag" - "io" - "log" - "os" - "path/filepath" -) - -var ( - flagDst = flag.String("dst", "", "set dst path") - flagSrc = flag.String("src", "", "set src path") -) - -func init() { - log.SetFlags(log.Lshortfile) -} - -func main() { - flag.Parse() - - if *flagDst == "" { - log.Fatal("dst path missing") - } - if *flagSrc == "" { - log.Fatal("src path missing") - } - - cpFile(*flagDst, *flagSrc) -} - -func cpFile(dst, src string) { - err := os.MkdirAll(filepath.Dir(dst), 0777) - if err != nil && !os.IsExist(err) { - log.Fatal("cpFile: ", err) - } - fsrc, err := os.Open(src) - if err != nil { - log.Fatal("cpFile: ", err) - } - defer fsrc.Close() - - fdst, err := os.Create(dst) - if err != nil { - log.Fatal("cpFile: ", err) - } - defer fdst.Close() - if _, err = io.Copy(fdst, fsrc); err != nil { - log.Fatal("cpFile: ", err) - } -} diff --git a/scripts/build-windows/download-file.go b/scripts/build-windows/download-file.go deleted file mode 100644 index 3878cd3b8..000000000 --- a/scripts/build-windows/download-file.go +++ /dev/null @@ -1,94 +0,0 @@ -// Copyright 2021 The KCL Authors. All rights reserved. - -//go:build ingore -// +build ingore - -package main - -import ( - "archive/zip" - "crypto/tls" - "flag" - "fmt" - "io" - "log" - "net/http" - "os" - "strings" -) - -const ( - // https://www.python.org/ftp/python/3.9.6/python-3.9.6-embed-amd64.zip - // https://npm.taobao.org/mirrors/python/3.9.6/python-3.9.6-embed-amd64.zip - - baseUrl = "https://www.python.org/ftp/python" - baseUrl_taobao = "https://npm.taobao.org/mirrors/python" -) - -var ( - flagDownloadUrl = flag.String("url", baseUrl_taobao+"/3.9.6/python-3.9.6-embed-amd64.zip", "set python-x.y.z-embed-amd64.zip") - flagOutputFile = flag.String("output", "python-3.9.6-embed-amd64.zip", "set output file") -) - -func main() { - flag.Parse() - - if s := *flagOutputFile; fileExists(s) { - fmt.Printf("File %s exists\n", s) - return - } - - var err error - if err = DownloadFile(*flagDownloadUrl, *flagOutputFile); err != nil { - log.Fatal(err) - } - fmt.Printf("Download %s ok\n", *flagDownloadUrl) -} - -func DownloadFile(url, filename string) (errRet error) { - f, err := os.Create(filename) - if err != nil { - return fmt.Errorf("failed to create %s: %v", filename, err) - } - defer f.Close() - defer func() { - if errRet != nil { - os.Remove(filename) - } - }() - - tr := &http.Transport{ - TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, - } - client := &http.Client{Transport: tr} - - resp, err := client.Get(url) - if err != nil { - return fmt.Errorf("failed to download %s: %v", url, err) - } - defer resp.Body.Close() - - _, err = io.Copy(f, resp.Body) - if err != nil { - return fmt.Errorf("failed to write %s: %v", filename, err) - } - return nil -} - -func fileExists(name string) bool { - if strings.HasSuffix(name, "zip") { - archive, err := zip.OpenReader(name) - if err != nil { - return false - } - defer archive.Close() - return true - } else { - f, err := os.Open(name) - if err != nil { - return false - } - defer f.Close() - return true - } -} diff --git a/scripts/build-windows/gen_pth.go b/scripts/build-windows/gen_pth.go deleted file mode 100644 index 9dca8456f..000000000 --- a/scripts/build-windows/gen_pth.go +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright 2021 The KCL Authors. All rights reserved. - -//go:build ingore -// +build ingore - -package main - -import ( - "flag" - "os" -) - -var ( - flagFile = flag.String("file", "./_output/kclvm-windows/python39._pth", "set output file") -) - -func main() { - flag.Parse() - if err := os.WriteFile(*flagFile, []byte(code), 0666); err != nil { - panic(err) - } -} - -const code = ` -python39.zip -Lib -Lib\site-packages -. - -# Uncomment to run site.main() automatically -#import site -` diff --git a/scripts/build-windows/get-pip.py b/scripts/build-windows/get-pip.py deleted file mode 100644 index 446e14264..000000000 --- a/scripts/build-windows/get-pip.py +++ /dev/null @@ -1,24556 +0,0 @@ -#!/usr/bin/env python -# -# Hi There! -# -# You may be wondering what this giant blob of binary data here is, you might -# even be worried that we're up to something nefarious (good for you for being -# paranoid!). This is a base85 encoding of a zip file, this zip file contains -# an entire copy of pip (version 21.2.3). -# -# Pip is a thing that installs packages, pip itself is a package that someone -# might want to install, especially if they're looking to run this get-pip.py -# script. Pip has a lot of code to deal with the security of installing -# packages, various edge cases on various platforms, and other such sort of -# "tribal knowledge" that has been encoded in its code base. Because of this -# we basically include an entire copy of pip inside this blob. We do this -# because the alternatives are attempt to implement a "minipip" that probably -# doesn't do things correctly and has weird edge cases, or compress pip itself -# down into a single file. -# -# If you're wondering how this is created, it is generated using -# `scripts/generate.py` in https://github.com/pypa/get-pip. - -import sys - -this_python = sys.version_info[:2] -min_version = (3, 6) -if this_python < min_version: - message_parts = [ - "This script does not work on Python {}.{}".format(*this_python), - "The minimum supported Python version is {}.{}.".format(*min_version), - "Please use https://bootstrap.pypa.io/pip/{}.{}/get-pip.py instead.".format(*this_python), - ] - print("ERROR: " + " ".join(message_parts)) - sys.exit(1) - - -import os.path -import pkgutil -import shutil -import tempfile -from base64 import b85decode - - -def determine_pip_install_arguments(): - implicit_pip = True - implicit_setuptools = True - implicit_wheel = True - - # Check if the user has requested us not to install setuptools - if "--no-setuptools" in sys.argv or os.environ.get("PIP_NO_SETUPTOOLS"): - args = [x for x in sys.argv[1:] if x != "--no-setuptools"] - implicit_setuptools = False - else: - args = sys.argv[1:] - - # Check if the user has requested us not to install wheel - if "--no-wheel" in args or os.environ.get("PIP_NO_WHEEL"): - args = [x for x in args if x != "--no-wheel"] - implicit_wheel = False - - # We only want to implicitly install setuptools and wheel if they don't - # already exist on the target platform. - if implicit_setuptools: - try: - import setuptools # noqa - implicit_setuptools = False - except ImportError: - pass - if implicit_wheel: - try: - import wheel # noqa - implicit_wheel = False - except ImportError: - pass - - # Add any implicit installations to the end of our args - if implicit_pip: - args += ["pip"] - if implicit_setuptools: - args += ["setuptools"] - if implicit_wheel: - args += ["wheel"] - - return ["install", "--upgrade", "--force-reinstall"] + args - - -def monkeypatch_for_cert(tmpdir): - """Patches `pip install` to provide default certificate with the lowest priority. - - This ensures that the bundled certificates are used unless the user specifies a - custom cert via any of pip's option passing mechanisms (config, env-var, CLI). - - A monkeypatch is the easiest way to achieve this, without messing too much with - the rest of pip's internals. - """ - from pip._internal.commands.install import InstallCommand - - # We want to be using the internal certificates. - cert_path = os.path.join(tmpdir, "cacert.pem") - with open(cert_path, "wb") as cert: - cert.write(pkgutil.get_data("pip._vendor.certifi", "cacert.pem")) - - install_parse_args = InstallCommand.parse_args - - def cert_parse_args(self, args): - if not self.parser.get_default_values().cert: - # There are no user provided cert -- force use of bundled cert - self.parser.defaults["cert"] = cert_path # calculated above - return install_parse_args(self, args) - - InstallCommand.parse_args = cert_parse_args - - -def bootstrap(tmpdir): - monkeypatch_for_cert(tmpdir) - - # Execute the included pip and use it to install the latest pip and - # setuptools from PyPI - from pip._internal.cli.main import main as pip_entry_point - args = determine_pip_install_arguments() - sys.exit(pip_entry_point(args)) - - -def main(): - tmpdir = None - try: - # Create a temporary working directory - tmpdir = tempfile.mkdtemp() - - # Unpack the zipfile into the temporary directory - pip_zip = os.path.join(tmpdir, "pip.zip") - with open(pip_zip, "wb") as fp: - fp.write(b85decode(DATA.replace(b"\n", b""))) - - # Add the zipfile to sys.path so that we can import it - sys.path.insert(0, pip_zip) - - # Run the bootstrap - bootstrap(tmpdir=tmpdir) - finally: - # Clean up our temporary working directory - if tmpdir: - shutil.rmtree(tmpdir, ignore_errors=True) - - -DATA = b""" -P)h>@6aWAK2mnY{22-I%P<8+T0043U000jF003}la4%n9X>MtBUtcb8c|DLpOT;h`h3|#_hoKi;SW{d -DwV>cd5JWwATb7V*r|m$Sgqf*J|GlZpHsp|bnfLg3Er$_wj^sO_F$PxnAki&+MWx`~kY{;j?Ju&V(OP -(hVs~qH=B`+N@~puYMo0eIaVOPk+b=15Q9c}!c!JUu|J&ZeL$6aCu!*!EW0y47~@)KM>9#PT;yZY=;%gfC0PovO_VThjlP -CnU00nk|4=(v#%d1SxZ-+EQx%4e2-M4H7y=8s{(AeLh0{u(=wiLvz!Q$D0j2RN+6Q`=%L%(oIv_YYtA1k@8xM2$Jjg;FR@j-u7+AwgQjRu+lk -zBM5h!!Jg1hLtrJiO|H+aMPx#|X`zD0q03ocqfR2cl?c3Hait(9(_~Veln|ef>{4`Op_^C~DYBwfAw_B;_lu*HF+G)UJQSZ}O(&fubeL?3bsz`8)6LCw3dfg~ZHMJOO -IjEW?&vfHIH5Pqfhq8nCszMoWOE&f|P)h>@6aWAK2mnY{22%nz$56!p001HZ000aC003}la4&FqE_8W -tWn?9eu};M>3`O@!{fE1;JoO(K7}(x`#B5sAT1xCFaSHu=oHANEzULGvkOsnPIg@TkqKr~)uap;j9+D -X1gOOYkXIAG8qIh0@m_9I`nguXVbdn_cijQxrgSYArT-K3$bEr9bi*+e4F&9HsDdF|`J}&qXk{`Mjd| -X9zpC{4S$>d@>0;1}aE$s9ktS76mt_;(3-625@3t{h6DGa>e?YHpi^VF48tp~qhJxF(Ma0@Mug!|pE! -govM#MHPg^YjN$O9KQH0000807zB_Qvk|?QCk5308jz|02u%P0B~t=FJEbHbY*gGVQep7UukY>bYEXC -aCvo+F;B!W42Abf{SVf$+)0owNWe)jG9g&l5ITj{ZH>|-*enUk918+fh_x>$_Pgh@<$5t?mTdnNitC*^j~r#PsItsxSI~Ts)fXLK=$22~Z?0e}k -c{H!#hj@Pg3#5U{hVPmJK>vhRQ<_?mSC>YbIy>rK)57^xj$^f_Y`@OpGgJxs|or_{{>#nn}DbH8m1N? -mnmv!3GG^B`MTAG3HW(L9Or^YaF-;XXy&z}bzV>$a}IzSU~=IFh|iATtW`yRjQNq|iZ|qNIQzEmKwj9 -gS}C3y38W%3~ROWQ?t`9P~(C0V?IKsras=0}6Dg-f}zzL4;8?%eH9-(s6!qZJL_AWZziu4T;Ps&BgiE -rTd0F6#p&9VN_mnvhL5KKDb26M;zPs%<;RukILfv1W-!@1QY-O00;m`Rt8fX^hNw&3;+PHC;$K&0001 -RX>c!JX>N37a&BR4FJg6RY-C?$ZgwtkdF5K&bK|xVf4`agA5h%`$t%fenrYL~L}~6rmw0-$J!fCqRHI -=i60%WKBnwcobvORsyNeGJ0BQR&d5m5xfxC;ve*AW^^lUbJy=PTPmi2-0rry!IBYQzhvTZnFqN(zZH8 -m;soYhxEluUGFgBRtLXD*Ti)zoqpG3>Dkg{~IO8Sdw0z5oP7{GVP-x4p49OMkGTc;Xg6`PTp8t~P1>NMu%_Xc31bApe -@$>mId-LP+%|A{~e~8IRM|r-fsQ%V9JSOkKIx#tGQM0^?$pwXtHqN{rKKMZS+@*XG`=uge|llp1vWgcZ28a&HLE^s-knnH$xEuMkDIh-^tDwY -Z`Rt@rufTpE&rWYrfj6~r$2m%hGB33^*-LgAcX0Rgk(w9saFA4~WV@&WdJk4%cT?&~jTQ`*E&z}+aOvncgdZ(R7!5#3k-{oAbz -LSe67BdYVFHFj%aQgRhEzGhy-+?P5q-sz9XkiO^3(Glp+r(fq%Rwf_D2B9=*#e;d5k~ADh@DtQsK)`g3NbxXau~17Cgpr_a1iRD -W62va&A?IT8IoRZa26L%c3=9xv*2?|B60HJJaMpGrSbJJR+@Y4jsA)%MD2=5I{QUrgss6glYw#90N}9 -RgH1B98y1Xv)3XGV6<3nju112l5@mkv+Q1*@FAUT;0Oc*UQL`H&{ni@x5UekUt5DJt5)ER_!311jQHt -8DD0a>x<9G0qM!uNHJScd_q#GC*Wv8o~)s_Fr-uo^apB^Q8dElgGgV&z-fYp=eDX3q<%g9B}I4u3-%T -Ozh!-2t3yqgssxy2h>RF^S(bi6VS|91+nirvkbkz)0*(g-)zlBbiET -r^TafVUnEcH?3>-J4*rJv44~)jEG92sDv9#IpSIp^*r*iO7< -;TX=I2*cvk7M}XTECq`Ls=MIqPUBxnji(k%z6$fo5H!9i&4rN^_A(fC;0>cc)|GLF-mobU<6#WLZ6yp -V>kNpF#=zu3InaB$S)R -mwa#S5g9EdA|R?79L0#Ux;Sss5K%uiRV#Eun>w+Ll#%T!6D6{6K#+t%-SAyr1yBeYi0CRm2GOG`>iUE -#uGWJQvEP$G?bBP8;t6`xOBnz);}jE&mSF{yp=+M>kXL&uAPD`Sc6Chi7CNsoRD7niMpG#bT -BnL%bkw_M&Tc>=PvdvIm0E39AGmRX}q_(iRdLvl-$TeqJ|VY+AacEglpCIxl3;1#u1F0&Y~2b;lzttI -DStK9#`a9>xR%dbNO}9wJ>NO)KT0%dOrqjAFahbh7&1_aq9?Iq_J`1xRNHkuC>@hu(ohMd-@({RqUn8 -!Q_hnFp5GSi1?}(raxB}2Pcj#(Sdpr_5DBR`5vx0qOt@at;69y8q3&26n3NhGCR7>$W!?x8RUkk59A{ej< -4)D8UL<1{Zz{EMDa-nVvJSl=hM)VtVZ=cY29B=(c0(etx{o-_-2cyY&9Wu%HFH#&E->DgAwmEpX% -i&&M5OnouoI_Sj5CR%+WDb$2v^K;{}E87&-uOD0F?BzGY-|DhOXFgu^zu$2bXb`i@A;2_`4T46r^NU( -hR1$R#v^@6j(0$O(sz5;sb>SOcNRSaH9wf5gP7yKt*T6uF%S#rx{7Y&A4u<XNVMxV8Y?)cx3dd`!*8n2RyMoHa_1fh;;6!fB=<;}*ZKigzCxx0}GVIedorr -vl)kDrzETiLPTPG9UiKP@AyAz?`Bj|wAOhO8uz!ED0+NKTr4JVQZCn%3fSZQv&y!CtAo-3|tag*6o0X -;y1B{69lGdz{eur!jKlCCajw^HBWL5!E>^;(WmC86aVxbEnIz@M>*3hw|3jy<*&Tq6*zZO!ILPMR$V^ --YQb{@>;RVPz!sB^~ZBe0e)2#DlVs&(Ur8VfaQ(h^^r0AyYEFQz@kMrkbG#&SPW*Ng0?=-7iK$@dL{s -*qR}SnrEVt$Tt8B)CDm)!=IdO_Lv;VC8u)}Y`Pyt@&`(vwiFh#N4D3d1GCw;N^2J;%(y1R&CJ9iHnZ- -jiGXA^;gA`7Ey#BE*&OM9vG{DuyPu84JdjCWCjDvga5$U9^hqc~w6tJbM)?EVTfrvn8;XZ% -3te)8{sF6ZP;QwxSuXw@l^k00Lu-5+Dwo5jYfHeBevUBGw{^wrqgLT+#JJ#0Qmv#1@Uu}Z1D>1MgWBT -Gel4p^|#7y3HbY~ty!fP8(wUwHG5m9K=QpWO$lOSv4M`!f5Xx;tdi$>v~{>s2#xG{5D=(i&SYp%hq4HFSX85h&bo`4<&(PawE5RUNx_clgljh{= -)B6UjTZX*_m5XF8X&& -^~r9$}BYaStw*pY^cbyPjjn(K}k~JN1&?Y!AD(ulCUeB*Cl;{z*|$2)J?JnL{dM@do}|?atJaK1 -T44EI40_CT4I9M-tzI$C?t-0sfmroa=XPh{s;P=9%u!q^zHDb^X>BW#~-}NN2{1gXpkK2+aC5r>hdd7 -fH##H3gdMz=SMjguB)T@>8Gh;)~^BcuH&H!hSZfBd%Hvv8tMxmsF(!gj~)Y{U<<%V!yuD}5B#f{^9kZ -WPXhr%X&D+V;k2KFd5u96+((gnrIfFjvpuiyH2M_7n&XRMdCJuKAgdr@pzA=p`qO$n(USr>&ofDe#<% -Fdny)87%-bW8{E1{sfDN{^B-$HJfT9~37^jlU50Q%1H>jKOE&R!F?TOS>*bt5`Ubj -SAsJeJ||Q_?kUg0vtX|E%4MgBA+O+uUXdZjhy%Rut~Jlfnl}0AVmG3-cTbhDwJgWdLbnGRK7}i*EEtp -V0iya2GJCW9a5YmVQ~%*{Wegc?|7XQS7=LwW!G5u%2% -p|v8&a>`Q^O*J8jNd{|#X1FBp`8>*FhE-;$=4T~s1le2D|{9U#V!&)PHo=2w7iF2rx2?oCMfJ&bn -zV;7Kg^}hX0ru*GpmUzwtg|+Tv*H%(PS}r+nIL=4@4^T@31QY-O00;m`Rt8fj)c!JX>N37a&BR4FJob2Xk{*NdEHuVkK4Er{=UHe2Ufvh`t70-8qz2g<%ioK}p`B@Z2=V#|RTvb-9vZL~vMqjzXhnAPJy6YBQ!|#XY9+0PQGBG$in-q~+v9G -g2>R!w6{DagYw@QQI@HM>6?qpS%2go#fP-@NXF0(3wF;pk|iO_7-IZV10_L|1xjC7u53!Ha;R)`JD(C -2`m+{VRXd49&=^8{T=ELn_hbYrYe7<}C>*weq^4>t)s_h(@nT`>-Wd|e7=cKq41=S*#22q~i5>0?Shj -!O(Mg)W^I&Av8q0c3&y>`olb>Vs~;xs0f}=Aa6*ilZb-ShS252@{oRw8*&0rKFh)M^HNk+OSF8{;^3# -m4j*Gh!#YPMY#;xdi$&FzYkIP=3mmtd;1mrn*DouFGYOU^NAq==K#%|G?O2P=Z7%RBtjI4w -nV;phTewHZA-mOHNFWCnmp_Q_zBMZOjRXSM_I`0x&C&kQ8M>Z&OV@ByWLdiaSih=t3$|K~_6Up%`6+YKQzipHw5GK*2Gy($F(;F)u*Q+)hDqQ&e;1e*wR2ef0sh7<+c(BSF!bj -6q+|uIcaU~B=szIjtLX{*DA<8l7Q<~TDgl{FfM+vEyg1Ytc!C`p-9`o^wuBuZX{hSLb}M~)pO7Cdp5j -Ujh=2Zk4eaF{pCzy>w>ty{_rNi{hMEE80n&a&lQ)`g9f%kRVwm+C<``#uts0bG89z9IGpA=VHt-)UN! -M6cGE@gF%DN3a)60#UMnwZ_36qArA03uPgQM3 -9bCL%FCt@KGI7pFDv-f;vcj~Z}Grc70XpEoP)`-e7Y8BO-PmnxUF$cxo#w+Ppp`mjnKdi -J2(t6&?!U>unKdya<;FJV4|wuABG@r7^sGIS|3sKZN_h)a8$|IL!5iKB1z=Bt#d)5s69l7T+340BST1 --`V@B7)@FHmxdow`bqcdD>toF?0j69^V<3rN{^i+UU(7h$O*Dp+WS8-vpI}d{Z3Uk!Z^vDgA6UL}qGD -tML5f#0i31E6qZeh#TojV>`Va(9WCkj0$+b_=h`iCL9e@W=9V`}EFgDWr?nMG7wQd8B)ls7ZS!H<%9M -~G(#bAZNPj-!AP*sg1EEXwy18Mah*9GP=t?l;w4#Eu(9wLIkQwB>SJVA+3lAOaAWDq|GV32_;u6zjCt -9x-W@l}ALTCN5tWE7+VcnM~>M-K)sNB`q6RuR@wwNI{uS!F=rfXrd)aygG2w;{L#0UOK&g1DPc?)7_5 -tS+tHIQedt&u)`e)|+R`=flJE<%{9r#q##n7r8~2L~N#5K`;XH6MmUWhUO-7-H+>VPL?kM)k6(~zRjy -)Kr4gn>FOd#6NhOI6YB^;C_SAr&(ZAElA4@uWD#WFfSFOkZ54GBXm3CgGtdS5k!*w;M&ix$eTuza8Dl -U)nE@gS8UEk}E7;qNz4Ls& -{?19IS7RYIr`9uWIgrYYNYX<+q$?@Fcau&Ot;pDB^fPFl3`F#NG??!g5FHD9m}BOi7i4h|%pfgD|fQ< -os1#8agHP_ZLcHTyM;;c1cMYv^#md>o)Srp|#bA+L7JcE0x90?P%ossCz3%C6FF%F@d=3HS|Hp?(n+w -U3<}nfHdHiR&UXm+9-u|(bV$y1Dt&Yqi|XKf|30dP{+Yo{r~QPzr$}g -h8ZFp%xpZ1Kv!bnPekUJ?)Dspta#6zm9D>@fsCZ1E$^;tuOwNO!ake=D8&}ig`#3c;IRgPIXrfv-b>h5DYSptQrx%aaehzBHA&f9oe5&Cxn{W!k -y!%g;+P+c={SY(c5hWT@j=Tzl5-FTvdQSkRAXxL?>1kO1Lu`D20>*1Zbg#ln<0JKWGV!EG9HE|2HO$l -6gwLsh#P9$e1o#{0ACE2AvN3@QK4fn#0IX*!PrjsXTgTEAHgvlIwhTDQx~&KBka+y7GjP0^R|N6ykHX -$7~hK@MYCLGy(J77uCF&$qs{HkIM~Naw4!-cqTUVA!gcvVB(6s%c?j?-h&+828%_2N3UuCEFK&k{3BH@e|DJ_fZu0;+xyrBXKRuLW1(jo`?q@LF&c+!3Z%KfSqnmwkM5b#< -M+dim$YW{#ot6hrc6)snAHP6MS0Xu=l-~mDi5 -^v%GL4o_W2|jlOksKj&Xchroap}UfJ9*!z2JxrEQHEIb*Rze(#{MCiv+f%4xA6s9=2As>N;c_NPcuFy -MC$DcjT6m`$9Jmwom#{;M^248>cv~b)v(CPu49U5jevQq#6x}P9=%VJwX=cbVIf)%Hawtsu47|g+mV|hNMgwCk -s4$$&2;=UJwL$b+#@GUg=$B!Ug5^k6E!uGHQLjxq-9l?}exz#SWekE~$1U;-h~*%6B7j%of#%oB(~3> -x_=bDHHJhjBelWO89zSBBn_;BJVdP9;YFdtc+ro!!~#s(fb9J3x$ClB0&goxI5*%;G>QgZ-8Gv6`L$Q -E2`J@v`A8#!n$GSS(}Pw^)X3Vri_dJg%L2bOe(Yf)5+QK`KPNV)~}gZnAJ2F8%|?5VFb^cHQxR**(%& -GBs<8&;ZEegCI{qd1+Z30p6>7c%<>d=XzGRmeh)@ORD6iAe>y*VbMiKReRMTFJ9;;Tl>rSMOVE6i}fzKrP`#TXbG?+NLEg75}pECrOb(9!xxl<)FOPrrO6)Fkk -o?&G?9NrS+RxN4kJ#>ELqTS5D!LVa5&I=Ks)3zQ6;<*Xt%?`A-vUSd(dXzkLP%oBF}cDSd5vNa1wi%+Jr(Y>kfUfCW8i@R_Xk*p%_~WgpXrXI -1r>5T(6&kdMp~ek1j8d8nsHHJXpo~32|O4Vl&_LfkX^AMTX0#h2gCqnWS}%PdUymolLOb1^l#SgVYEb -vs6y@Z%T<8YA***pL^bI(AG_EFF2+qOc?{I<6TS&{0EaO=@)=4NCz5n$8 --`3lV`+SVjLTSRUfjh5kH6hC&~cYX%Cv) -DZaqkSoQUxEyvoel^884O3w3W;RflSKHlwai0BztI@wbo+Ve7*Zi37OBDjP78*u3pkv+2(QF# -o&>@7LDha%zPfqTMN~iwul`EC1u#g#80}fO2O=w7$oUjGSEX;tt%R0No`r99e>i -L*+~s3s52q*-)z`DE#6^ktW(zu->njAPO^B20=h2z{EB1k1kHYCqP70fwdMSFaa&bqNtn!nDkwyT{Qe -CG=o?Spfyl7c?wn)HfUAQ*2$a~xCkd17#*etDnfjrK)eU -}9nQq?LDKHQ0~+!07#R1`1}K3-0IO`vIw?c&{}7CO7!QZ-t=>=8 -S7b_LcmnpzJbEh{tS8M4Y$6|!*L0Df|J-5>MN3lgWO0j^QVAdYd;bCgez}opv+c1FBi}j7j3gECdJ5hTH(;q*<1#6mUMcmXhE@#jDZiL(SH+3;Q?_~#5 -9Fi>uCzq)~1P8^$jkiBUXlAx_fEtSL|j*MFkd?6`WPOru3p|(?bP}oq6S}mt~(uV=bPcwyCw) -GVJMrMR~VIBuK^}$x1nO+0J>haO73V}>z5lDbgH10>tOUWBBiNqJ*6*Rz@hh8+T5~Ul074niMO(86eJs{BAuoRl0 -qM0g0ddD*7zV6x+u3wM66FY1>B*B9DelbBu!hZ-Nkw#Fh6uIWms=t!gi@Mm+W&Xra+0hN^NghC;T=B# -Emx$9o{%nxXC-@@JXF)$=(M9@wDjuAp!@CLgmtt=u^b{owWA8Ymw!PLAO-3T#Jd@IPgPo1EzWsA{UU~0W|PivV;#Y6uI8qL_r%?hdFp -}<$mjACnJD$2{A~rtW?5j->UmYu5~az`#HOyN&GZxzDRfRlhW*Y8{xPdP_{3PXs=+8(&!E6REF$_Yq$ ->IK~f8W=2yEFOb1-8s -{71=%Me=z)jGgl*wM8zgV=KjEJ@c)ODX6raE)aduH6>=R<=8liZ4W+A0k%R<#N!h>Gk)L1I2l@v&hm! -a?jAh%_JQuJ|Yd2z8LxQf-BQhIX3VZ=6xW4(ufr0MpY8DRZ);5a#f5FJZ2}DTL~MU`WO(oVgS|*EEFK -L1!s&|_@l3By@_`_I=;ikW|;zlp<`t;I>mv6Gn4>KG|@2GfP-Lg{l)R96xwONvGq&jstxWLNe2g2`Of>I&K20IVJu*Gg*Uy -rbiG%j_juE=2$Jn!1IJ;(KOVP_0+vQ$lDoRBca!w4tFld$=>TH}9H^-tmkfR_AVRl3GD*OjvZ5AZF!= -4*c;L54;KlW!*8%8t8y2Cr+L)jXGWa_~Y7NLbg#UWlP_TqAopr2Xj$>ae@V@(uNU6MnpiRbB{@2pcAM -dQ3&&pDC4S*Ja8krxMr)Oxv5BB4uqfqND^LnTB3iGi;j-iJVGFJQTZ3hpG;m9L1~a^?9E+mO(^bjKKe -ZKdQj$8=b_TgBAu2K##20yRP_VVbX!HO;pqm6NQ41*9oEgrL9g<$pC(5#Mu=@w+QcF5vS>z0a5{oHw$FEtsTnuxJWo{a%fx~tMQ)p|>dd{D`D4}j!UF_OVAn~E&pdqtbJkAhWK2X -@LCNE1?zGOmdsCfCq -kAMEtXC;GO6I?we6mB4jd=ls>22nSR9v;bJm4IymcP^f33gJf$z~L;68sXp&Mdfg9U|9GD0xq9I=3{r -n?T@7DM47bCRJ4QKj-*R+W41uQn(lx3@hj*qkDtgtho55!x*H0=SAb^^`rI`WR@T;@Vwp2ORhz&rYv~ -)rU<`+jP0E3F9gT!;l~`19eOBADqDl1ZYj0t&`wVA!`sD)l}D0wMJq(2Dc77BV3Ssi_d+Dl!doSYs?FDr*#1p9jYXQr$JcGo77(ST -RBbjZTGaAyRkXeD!8^3qgmxQI~?Kp^4^X$n4~FUdOHb#&tXFa*H`n%5V%-$1X|#k>YW-Ck|}~iRHU70 -J0R)6#b^*cvArs}+M{xT1lm>l(nU;IKl@=kH&b|>!MI$i>$t6f)SifY$0&H{n)7uDh5Yi%FJmRj@IQF -W#Y&BFppaIyDfQ@{8~>8r)Z>vqLgupSSH!R>WuV4%c7a>tFm0u5Mjt8}zoe>{r!*cE%+~Y%QpDA}>FM -d1yesbNiE>q902rG}MfGsla+5DqTg2YnX^Y9qR0om0R$I3-^;QF4M#4Zn!hx5yLIf_STl!M)CyM7v9; -^}CnLT~gti`#tXSdGnyL-ih-cduBUWv*qM3*(?h?`Bh{^q`yS~~GhXAA6UYx=|>j+1av^)GmEnvX$}r;{}t$CIZtYoBQtHZwtPZNh7tIFi -~ld;FNc!J -X>N37a&BR4FJ*XRWpH$9Z*FrgaCy~R>u=jQ68~PH{{zqcU>mTtx6cng8QBcEVVGI(y^%5eG2omTva%4V2&1lRKk=d%2Xm6Zr|EJ& -)|zGKn{X-yKb|#c>IXLhiGoO*`{*k=P%FT8RygkXi=GiSb%+87XQH?Ov%&KPdm4dxVqFL6M2a=9zTjx -ZVY=Pi&L$Yp49r8Iu<}3KXW5+5hnagrz1c6gp^cij_)iTPcR_!T;xLYw4uUe?)2-XcE~!Gzm#fHY0`K -wyF>VWF29O&l^-DfO6B6ED0#w5zL&K9@|H{Vft#(!8IQrT3{oGxJiR!6dVFy_VoI~on_r&K&tE-zJz| --o%GU6AZb|Gl(kQe}rdGd;xMVy}?6k`S-bP?qOHXt%_REf^m*7HWrNKupbR`(j2xo0XdCx2q0h_>L%* -afpT&Fwa+3mjG&@>9m1b})d -HgIOs_=~HFW4~~kXO_j++t(FF1CWTDQ$wZ@}l|W5eorb>~fs -HyF}-ZVMQ8>f}2pN|GFm317X37(n{JM7PDw3bbih#Tba%u%VbkM2F~Xa4KwHu4T+^Y;4HLJWi_wVrZr -`49>wUGHz9t$}2&HuZ1?K1T>&jSsH;%td+4zTdHF+y4$I;meH;ip)(XP?Z9-MP06tR^ -!NBup-JErLO?MjMnVW_zGqXWRZn5qWM(LT4Z1gnf`rsuEK%RNbd|yUCht(xSq -Cdr+jZxSH9OKr%B)`A(%w0B=Z2mU~GqIlr;Yim|zB7WBp#k)*^S%}kjHtgiW1uLQv{!N#N~sQ6w{a|3 -sRnrA2VfpAAx!F8o?|zDJPoBkz;|o;sK1M<5PC9=YQ+zzyw>*g?@3P>@Y~Xx4&C9WjL;jEim -pI+I8#*5Q5@=Q((kft&!r;2=ee2xS9pU{(n=uR%Cf69~~%0acd$^rC0fC{bqoT;uU1GH7NsK95ODS4wdBAd5x>k)S} -A}Ec6s?kY&J)imzJBbKG+juAg=u}1F|Ab;MWqSL9Kwl292s;1XHEZ{1}KZWNWw#xC8#`yrHGx75(nML -q_l&{_di6_b#*VzREL7krgRs(4#IY9=)wGBtT;b1Z|7Cy<4zRXNFf1jlTVdzMEkI*cgoeb1<)uvOGr~ -XxBoV1yY*@Qkn%)>G*Tw74NE5p%vCt_rslI2u^-9AT2=DYYsb0hS~$sAq%rRid6!U3<{T6%T|A+r5fo -BYM&W3v?wR|hi-}2tb&zZ^Yr%w(5{I%Y-2MJ78{i#%VB!Lr`YFd< -S$)Vl<$*kDr>+*kb%x^YkfPi5G$rT66$6P<2SO1uQ`;TXfg|Sj2&T!IMyL)WYBvh-oPAJJE&&XYZ-&91IS -p1n~N2&uw#={-CzqtSTbag5MLApD(aXdN|<~MwYS3Z2@r}Xam|JnUr~1@FJz7o#%;)00JXKrF%hD`j* -T&pVqO30!^yjbNFvZcMIK9h4+2UA8kE2EFPAuFGHo%|s?B|$Z;TJNr?(7tL_OWf^ltq3fT{J^E`h4K`z^N*HrI5P=<)Cu4W+NdP -+?tf%*2DO#h>1!3T$9_m9848o0V7D3aZ5W6jImiKxc|+);}y*p;z!tabqg&dm2{jJr2b6a_+_6_n2+HaTA-1yHSRnTnk7LQjT0 -f$^Mpo8c^BLo1ZTHcTRhsY-=?FAGHM$x6Pf(QlU=Vn*tpY@_LTy0_Y#v5hJLt1WTlzV7$~54QtKHfNK -Cx_~}`C}HG^@L(!qY}-w}qQF<%-2YygGEnHD#(1zOm~im)HCX8hd#Vx;YAiJ%e}JU+UQ5uSAGixsl@g -0Xt6g^y=GpOw*Kf}+PM2rL@6N)c<<)l7k!z5uIz{0VfIuY47!ON9s_);v=m$VEtDzi@g~+mzz#IBA1gAL_D`19pglCvese7bswPPDF%w0LKu?-X+t3vu#$lzj8n_eTEI)_JoBZSC8DYf6U33a7Ml -EYX;4H<}2AHUz; -K@>szI=a1E1Q!duydeJffX!?#AA_Hky?)``t~>V9*?U*u?#X9i=7RX_qE~YZfbtFHJBX^TR0d6OKO(l -Y98?%eci(r?-TB_shArHdnPwP~2uav%(+#(7RpS|>9CdVrRVii_dyKId52biI+ZdFI{nENCM80Wpm_0 -(V7>8)o;M%t{MNk~dnG^o8oKJq0!$1i_#nzGaB)?9H9lot}On?X -~tpM{5^nr|(YLo8yyTj-Q{tV^3eRSFbPF%j1iaGY0P%nlAkP+1uAI>G|#Hf8L+JJ$-rl>f&8bZ_mzOo -JP#0Y|?L4BvclLLh{<3F(_g%h}c0rY7Hof*lUcRHxkbz#b=&j@e-0mBukbR1A4+X_U>Ojaz0dLeCKSB -V1_p@AeTi4b32%^y20KCxTV>1ku5Gi(t#9pjp5s;Pxh*+{VQDn{q#Tp;FiM{Q34d`ZbiC*09|e~GCpt -*M81T*6#+kE2hqIt?ziGIP}$(6)*+-}9=eM2>n_Boq2LB@VbJB>t#ClkHbG2f3Ir -&=%+Pw1h0Z?&Z&59sM8J9&I};4|1Ppa`1=(Jc}Y+pJ8kM4{-XIn3AA->BVvBMA5bvgwlJ*gl|$h3#>u -;i+kCAQIwDuM)3@nGRlZ_D(ELKGu8se;3j+guf2A6gxSL4>)zz}cm@SJJyCDr;<$Fo -2m5kzSlq#&$^b5zg^J1DAW3%1$dq3L{ -(|>N|is07gUE%`v3PJ;O*DuJ{~qi+|lgKmM%0Zds4#N{|ABcO#plLCUOm^L*+-K7&&6@BBw2mM>DoYU -AWtBwCp{1-Rk2Abc^6I{QobJJv<&d03N)D6)4{oHOMjDJisrVw`+H8eBIp7soz;x=q{;!W#ilzigvx= -Mq9_F9SB{*-ti{ddW3Fu+f2O+Zxvt#*O`x}g}My+57xS8smOQoX(Bk|!1==Hq-QpcJuBY3+mI|?m-!! -1O9KQH0000807zB_Q@_)1i}e5i0BivO02KfL0B~t=FJEbHbY*gGVQepLVQFqIaCtqDL2HCS42AE4{~_ -4R3R}Gt+6voaPo=%|wk*r6Mh%QJA&D*i`;HZNW)30by?pa}i4)ku6b7J)qZoXU+7Z6kCAY`q=!Fg -XebCxf0oW5BY>Gf3xQRbvB(U2tCYXEnK8N_cz&3bsuaMe#k7LV7HyC_mUi9|fZCpp8MJN6=P?O~FQIY -2yNFE#H%i>pI#9phI)y^$3axqZw;c*8|x&->NoFH81RHCay_!My;QpUSFy^ -fcADvieJF~c*m9ySNAgN?s!db>ea_LvmK>+IcHbs6bYklqo$Gf#sradr$`Gk^pRD#NAFgu -8cwo>*=Au4R6W89FWw;q}jAD98t{O+kL^P>{B_H-2TuyK;ACqLwNwH}cf-%hzQ`t0#H@y`^IR>A7MjC -d_EVy*SgB*S}A%3KIQDH{`-F1!k1&YsI?6mwTZNZCi>D-zy~*O5WbotRXwDcP+TFlg&;WmCOB?_1*0a -fzKOsnca~bd|i{xk7O@p>s~2ldL>Bie&L5}j+=;zp^Ac_&NZQ;o|b?Gd9;ihb}9($xh4$;3VsqU2pZs -I){~Vd`ownK&?)%^(zNTSIp)2<;IVqAWv?o>t05|tk!rZG-|hkS!~co-QkSTy{35xyuC5@fapw~Axbl -Ym((|_dG-xpVS7s=0HQ7dGldmoptP1krOj!ARnIv%lg~u2Ax -y0M;je!$CjUcyK4AVH-NIBlT0F)`LyS7uW$7K*zC%Z6uPy>#mZc5+Xu)MfyggZ#eE_eBIWm$)n>4&-C -AyC5K2inyLZR!ssjw!m$%g!sYO4hvDm1ibuv<+&zW+#Y0jRE+hAKS#ME)fOo3tdK6Qd&1bEI0V3}Iip -mRH=g1JNC;c*9v;P8!mnf-N6pWqXdu#(Cymuk@0Slb#Uz?`p7%N?4T2j;Yy@&#>Np^|BGdkY@%37zKm -mjZ}-VV2BqWi$DSk*C7+X+a8M3fZ-&(0o_C&W#85qJG*ns4zwBoWoy_I>bW2i9;;^#?Y1@iti|$?6u8DC`5)k#Dv134OAOO8@<1bP~TY(_gL73i8EJHIBbqrjbLKkhr*KMU_ -fDKqw_BJzc#pXU0m*{7y|j3p^~U1h?3Go#kd|D%YA_oo-hM|Du5r?SU`DNyX#5D*4gFyP@`i#K;n}vq -QZFQ=1646L_UWdCZHxDuG_3P&E{PO69bZbmpa{buAjDUik1j}d9$7t+2HTAg%w!k*Ov!o^31;5xObVC -VXbC&SH&GF1SG>IYJeTcXY7)SYNpAl*T&YiFS4-q-^^DK&a()V_6%i(6dT(j6jM#Xh5_DG)HMk;4s%8 -X4bT%|&V**0jgT97y>UB~#M%jDp=abR#4u=)T_-iHhf?_m?g$P5lvGu($n%j2yNi?J8Vl*nYgm2e6pR -cyqN0Yiiqm}y9j2h0MZ*skeqbL9QhD8vWr+>;1f3Yvz=SXoCs4lj^B02x<{)o5fTJ+`fyV%{ImNwlz= -xo*E|+V}hEhl~6>5}LSRCa5{KJJ~0`SN5dRB3YA~IdDru?!QvtPM}fS@av69zZsj>6rMY(Y4uj6o4%oMPbi -c5-l<1@e~0qD6mMu#tKVo1nXm&jcwC*ot*v|2OmNXFmE{1fH6-(K94Rtc5;wd52^d!3aY_lbEQ^iu|- -wAEv;oLf;%!Vf5c@?ukcw=;=mm3fPmrJ35>2bgg;=!*3298GH`Fmd+stGrSvixcA5%F;>i{((e5ByAV -w#eKxRgrK!?jX;5QTs7qOnGkZ>Su;&~IVyLV%R?ll$|b{`ePC_Q$i?^j1>G3Bui$Y+0YT+w2mfjOZ^Q -8yhW4Be`QaRvslQx6!!EJKg=7)5LD&KjO`O+1->WmWGs$G-6t5NnRL=|L6jA!j&Zc-|dZWG&Hsht$pg -@=OJP395Nr -c$;d*NMgJ*g+bmFq?gNw&7@75a-=?iCge6!d9_stC??08xLklNca3pGYTX7qT=;+Ab^L}U#5V={^6S9xLC`W1Otj{NK#HqXQSOl^~LHICPuEn|# -Y$1$T2_xRGnp1bz;#KLPlDRzJew&vfyb3%<&i3B7n7!U=)s9{E4qf6C1l8#z9WdCm({F;!zGW4 -?)Tv39btJwhvGn5PMPGl~^3tckmiJ}B>^B46pQt9RR#h;~HjZ5zA9s~}M_CS2L57Tg+2-thmWvS?X1x -D?|qZf2X_boh_ZZPqJ{{iZBYP4X_5`DXm235^#WaDl&4e?}x={C`wfjm=TJjqR%%pw&k$uD>^u;=)d? -FB!tK#?8XTvTljXZY8U83%00W?Js3)MTVoju^#y@(~FIWA!xKz0lgjB2QXSm*kV2u|2%a2djjg|I!EE -&s^Yl>Fpe~_moUyJ4+y#v7$g%z^QN%7u{AQEcG+;3-||`4Q}2_i$QqanruM$u+bXtcPo44W5Yhr4h(6 -4e*RhZwK@G1mWL=QUfA*QxT^am`|g7q;ng2Y$PeAx-8_nARL@vccKe&9&6gT0g$_F*yr?KMzc- -C%v;(+BfZ|vz53Y!k=C~H&i|974{NsWE{eQF&5#vj!#|1vSo&thr|tGh@r2GHXVP)h>@6aWAK2mnY{2 -2&t$ck%!U000jf001Na003}la4%nJZggdGZeeUMb7gF1UvG7EWMOn=WM5-wWn*hDaCwzjZExJT5&j+^ -|AAFtSX-=xA~>{#ds{S39Ngh@*C2LVT(5zSmMAY{NmNP7>%}4ez0Z)MR+QxQx*v9zFEbp@%QG{SO{cV -FCAY%LMm&Ee{luP|eJyXt@h79&aZszfJK5fiW7XM?YjdJjChNG}k7IK*&!1IVHOwA6P_kkEReRjBH?p -wLpAGAs?6Ukpw58HuQQUJnD0>jvNYw^1cNpWw|H+5dn1^hw&@Hbs*_PrlD^y*J!YUnjyp!$y>oEBRLN -A2KD;kc}@BQpsH@QmP2+N^W9w_dF%}Y`7zP7n&AEZ`oBU-yot4dLu%m|VWH_JOMDib(ehw1m26#KKfUw?D;`n&witDCF*?e{lq$C9%jFV32av-0Nbo6EEBFVC+3mC)wr&&Ua3kX`V -`3>tpt=F&WGc_Z?C<99;sEGPXN3pXdx-FkX2j+@Kp&lo;0$T7twOO4eVcJXJ1U%!G)`R&mPgOl(-gSu -gzbmLcv4;F@K$;_U=eEC&6(rmK5cr4|eFg8$VVSC*=LN8rWb7RP;)oW7cHOV+gn;cl5H9j&}U?}WeG8Gewb`mjqDB}OUG57!2i9)c0V5Mr$Ej#em!k}x+1f9cFZ^@WsYi9#S5;F;CY9Dwl%WO&7!MlUk{H4>-rnbkEd&4qLxvT -CRM -SG<;zX~{TLn#Nl8f*uiU*=zajKai{dMD@b0|TlHT+&M0#Mk4TapSO>}-R`aB1zhIC75IX^1qCoWdoRX -)|}PHK~43hako|bmEb{jHMw*p;JqC3*6Xa)Ei0~AgOD1r>6Y)UI0{hTh6b^u~qeYW{n$Y(>o(8%(7Cf{Nx(0;WC5_YvsI) -Cn|q|Yj650_(G~qkmlq@623-q05ajR5hgdd`7*`ghRYvZ&U5oq)?hlwhK>p%Be?>LHL{&livtt6*`jY3s4QdCRf -+Dv>J(9yA)9(K6$(rX@soF0kN#bC};I6`980d&08yQjzgJDqq4TZCh=+Yq#G*L=}Yad;#^xd82h?@pk -2!%88ZC!-8TD=q%hBVvwBRo+7lSx8Z2AS1)?#eK$H?Me4F2x3@3NN0Q5dUnJJc9Mu9sL -}SkhCUg!R6gwxnga^|etq>JfBgzTl)w4*1EC~XsmhlPA!`#qHB7+^Ord3GT_T;E@#Mn)zd@a;29pjMF -lILit~jfa4MW$tn-OJW!|8TTAaqtG$7mFCN?huvV==oM{31Km_)}<`LO!@GsulECMXL_!1V~=6Hv-L9 -BjLHy)hz*}Uoua9x%^kHI(@tq?w79xxi60*kJj0d -jU$a0Yo2xRicMFM#ztOM%!6@&QE36$NOFf~NSsT7_kjx*!R_C7y7t?c4gmCV;^;Brdup>0#OjbAd3!I)-CJHm38>)42FUbx)T{j1vR -&=ryZRPTQ6TXSN24fCY4!h?)pKwXot^E(>3~yVz*dd-aUu^bWJX|wbtdrerytLhPcq=F{0Xwqv`01t1 -=qHaC2fWYX*+uBjIIf2YeL_l@&Mm@Rr!l{f9adbB8q{f*gv^VS-N2W)Ps%e_@(@B@?HBsl=`mU~=r<< -fMGvGAmx!)b1pqIUE7Ihu_6{*K{xmCoJwFW!cyf1k%TIE!-|S|z@$!PvY9)J)uk(qoY+_iAG9NXJb7* -u|Tr|k*n)nqB@IPJW;3{8g0r##S7Qs}Z)a4Ic*8G+pP1@=DlvAOahO#WO4>dZ}XTfDrIq|!OTQn@xa= -1Jk;L0)bRMF!GJnft?@4%0fqcdNumrD4;mKQ{;Tr3!r+QN(#pXc*4J-3KQQS_GRf1V&7nYd_5ipu1dc --v=o;a-4~shiRBY(`lN*gEsAC#AY=@YU) -NbVFj=Wu>Db~)_gBJ?ffY(d9avVGFg=TA?Af+9DipP|RQ3XgG@3oVu6wqNMz#@U`4F;xBjP0j&_OI4? -w9dx8zGcp$!XCs^{HBX!n?Y~e<0|XQR000O8NLB_@Jbi(ZGYkL#L@xjU9smFUaA|NaUukZ1WpZv|Y%h -0cWo2w%Vs&Y3WMy(LaCyxdYj4{|^1A{5hmDLvBuev|pt;@|P=PdciU4U7#7XXh5fHSvmUyN}hD+K}i~ -jeUnSF3~xsv5v4m|-jq~*@+ykE=NZ1%cauDR&Dyl*;o4S!cdSruiyVs~rKE5WY2X2V|AqR*@9E&nu>9 -pCV}7wPfQY&JVSIzB2lZPWFvYE~=wt2rczdLTeiuKT!)$tMG?zb%-ryf14w+VX=XXRHFPuRMp`y5w-d->-jCsu`b7QwwJD=s;BUyGr|=UhGsBHQ -pjFY-Rus8+nsNV{19LhZ_{q4yXcL7M`MAg#*!Mnk`X@B8)=W{1t-?xqFJ5{D_7oC`-wipZ9?PapsA03 -=z(SNU=q!X=*sadrF?{=ov-`Y3nb^n=i3YN_%84O`X)?9X6z56q?%OAWw5ogD|YbO~GMVx3)=X#1s5< -SW{Eu?L^v{m}MJQ;Cc?*SI(N4bQBH%Zlf9mUk<$57}_lcFmFt%Z;ik8<+RM_I%SKD;n}0{QenaxP(v> -R)K^Yy3uJdf@FP@!CDaFc4@Z4S9Cm70q@vC$DOKd1F?>cMK07{Q@HxSl%g!mktcGtBI1xRt=bQ4k-$Vk1giJx*5Qy$-X0v;8QZP7V=u$RdcRFfwg&LAHwnSCc7eCX1P?RwK1&Z -=9krsqDv&-~)1Y$@@7BNA2&9L*%JI-VC>;NBDpfFP)j4~1`YhUFS -aW)if^1$?>7w<7C_6UF&XhLqGE%o6VU-=%~HN`n-+LmZ*SiCFYO)Q9}{YSpdSr7B^_cy)sEbDhd&frJ -M=7-l;GMIm^8S<3*5jg;t(5~Ldv;R(xy7&cT`thxOJeI&olOVv7J&~;_2oC6ALR_G$9(8-lVEhtK<+? -#qlJv21yL@bFjV0MT(D2`L}h1}>Ln2DjAw&qr|GTGpYVtfq5W>*lODOjwdHrn4BuaT1V*^hMMn3w~KV$gO)R!DNgTTD;Z>@2 -9GH^679EWiY<-$XzvJV%pNT~B5Y^O!RLarIKTX(hm>oEntyJ=oUyQl&5Teov-ZcM?$2ozxB{2PC$kh( -yUF{=B?$yAsh!q-IMV}Jgok{VEE11P3!G-5J(?W+k8nj#K6l7ZJ&i12SC00kJA>^1La-LiC{<0{RIqx -Csu{_E)&VV)1mr(8g4zKF#R?kzLORfta2m|0tX-)$`{{&7H`+8>1}(Q$_+&fZAd#w% -8U>UyR&OsF|ye}wV>IlGrdz&#q)giQA1$inP#`eYWnD#chVTRy7up?h*n){N!jsl81o@r*??$>3Oqtp -n8dg1tF^!@mFiJ7x};w6lY>G1aw&Of7cI%Y;+evtTrRNP33arX6}YHa440;*}vfIPX%&$(sgi2Mrhjf -hy})RdWSVV(-5D`-Bl6WM~?AvZhuQ{5V0BX+{nZuT=);8T}0603_&XA>ew*IAo7T -!MR@W`r^Fn-~b3Rd^-NP%exvJ(l?f$oSQS%-z$pF;OoqrUzzru?eE}aZq(9MHlX+|cq`BrOFOkla@B^PedUIwV5! -9Duq(6J*K$D9q}$$AY>9%W1Eg|oea611EJa!iBlV#WFctmRhz5U=%aiRnH$c%%Sr>~L$zVoG&=*FQF0 -6VSMeFo@J7=68pvfo2c=@zrt3);JFx82!P`ncZW;5M@pZUvG-O$a*>8ZqcDlwux)Z+y_*w{dcUwZKm) -+Bt2IGzyeDEe#AN(jF`sZQXT-ung!L$r$>mjd`v>RU`T8rVFwjz!pL0acp)R87uzBiZXo(X;W`1q5~muMdlmL5bJbh!YZYC -vf{R{jN<;m-DeK6Nwj*v2dYZ{bQgGImFvw0TLT;}8chf>@qgQCsO>@hgp3cx2fUz$t=FdBxW0z#-v@< -pjhXMVW>xygv9xtG&TYOUhDfyG9e}|QMK#TTgOpv3XH0Sq#j-pD}{Bu#RfXyhrkH-r$R5oUexq5EbEd -d-VI~!5DJ5+UXuHVoJl@Asr`{V0_i^i!eLt(&T3Mxhn;aqW*;KdiT={Mm%kDI5t4h`~_K}q!Q^?ZAaPdB-uL88$f%nYnWRQyQWp -|`-R?aQHA8aqiEdq7x%o@>pWh^E8nUNx4RWi?x58T+>+6o8)8^4IWN@Io6zNUmD(SGLq-;ZAaKW}Jl< -$$dKGc`F@e9aC6%0++c=RL<8(X?6DfD^%NU -g~DYM%36fHV#gG;{?*H?=6Wq2m}kH1ir_2NhnFw8!|~J&e`I(qgbYrupV#Iv=t>gvj7cj1L^xmn#|BK -TS=A#|Ki}347n-NK9E?eM8c~_hHf?dGacAL9dWT)~kKdcuFXz6J&#PYTTi#FmtVD7N?Njb&h$3X;*D( -6rbj83;hD!>UimYTE>s?+D=?>?I++_pb(}G`J38o9M2=+px18Z7jiq~?P{y$W79%xu6^e+qTBbs{x!tv3608mQ<1QY-O00;m`Rt8fLM#&m&000 -1p0000T0001RX>c!JX>N37a&BR4FJo+JFJE72ZfSI1UoLQYC5%fB10f8>_DI~}i7tAe_5vBm%tQ?d;< -M=Oi`1=cIi>VkN2C0qi;>+XiHThxRrrY}?Kw8Dm8?L;7-EzANtw}EX>!@Ra11G>7-D$feapZp`cG|&+ -rE8KoCnM&q&DvpV;$AYQXVn<08mQ<1QY-O00;m`Rt8hD`7Jl;2LJ$~82|ty0001RX>c!JX>N37a&BR4 -FJo+JFJX0bZ)0z5aBO9CX>V>WaCx0rOOM+)623Rk|AC_%T0-2KNsiv}0KrUSH`wfUBgtS6h9R+Ky3LI -&YDucw{`XtOheXnH9;=IGlJ&0oSfwn>K8PpY5WT0G^x}m{Md+YKBMyDbG#4G=ozk>z*_J$>NL}~5C(~ -|Sm)BQWmR(<6U-3gPq$Z-*J(Y@03u=5-CwSjUaUfhXsfB12aa+xv^3HAQQ_s66zw@p;Ey#N~Paj*hAR -oBW3v%D1c-o?1Lj!u174P5}td>p7%L6d1j4E;zA{o`J3U=nH#o<7^?WCLgUu}5nj2eIQXv9@qu` -)GZZk*;9tKh?b!|D_k~fYsJ2tG>u&a}?QcT9kd{Cgv%er>1%X2PEH&!{DRYF3dQ)7MjBz5ZXaM9+0orY0SsB-=y?8OzHFR!! -Vg`FdyRDE%HPNn&#V(6VSe076aJ|p7+pI_m)j6pn>sa>;#b%3Saa1AP*~HG7Qz>x_)Db9o0hRJ1KHN5 -#_0E_UFNyR-XnA4=KIqD_p`GYBc-a_yeh58{2hkOvOo=zdq<@85l0Ob68FCY@N_6dM^;r(AIA;frm=P -PsqHSi#Fg7!E9^xF9jPNuQ0eoJec)e$m5h{_`Wz%TRg6!ZIptku!w9oMX)D!pa$fZE0p8MK4e0qsUil -=9ckIE&;@u?obSqukCtZDMoYV0Y>Pk%lwzNLL~T=%OTh=3-C)CI)AA -oQ)VsOshbjDQ~fvImb36wz@(g9o==9t+HbM%f=XY46~3d$#km)DHvQZ`Efy>3q$H&ty|1Kc=_lvdz8G -Hv&#`c2k5Ux-t~i?7x`rriEoL(FJTEfWqOJKh8s2HRM)>E^>1~(z;~dBR|4LLKWHlai|&VnUs -3}|fnmgk)H{h8mnk2vMam+9k}wyLa6x{t>41Mst|7P08Bo}1!;>%1m{t&Q){>Pw0VR>5t}R${v$~m3R -gsrHZ}!lL{&(O8ke}2X*dWI@8#3h)@Lw(vYpK?(gB#chG=o}+Kvr=#l%bKTh?8u --_eq=>+z_#x8E5~$R{}m^WBz*e&1+#|l0?f!?E3%;uJ^A1Jw88xP7aS81SQT&o3U?|c1s{ByJNB5 -u2^o(TXe_%k(*T?Cq3gzH+GmHL(pP%CX!%oKEKx{Yfn9l-cGICB@;>c)jY}oW)57zIx6BL1&ucL8l8n -pio!G+GvMioYDgIPhe^SVZ~wO|WaYhUn`1zj9-M&~RcMd@MGQDG+uQw{PD`fZp*o~h&}QR;e{hdpkGT -z-U!8IKbt)*qjN_AEIOGMhbX+>E!hll$__1I9Do=?3T2aW=H=%CF=to-s30JeT2^Nj$H1CFBG%@^57Hf$ZSNMkP=QAYpw#BAI?HlSbk89`%R2RP*K@ib5v^(YVSZ2y9&(PJ`f@By -4{Dl}~#Z-3zyFlr4j;S4quLCyrToi-whRBucu>oN0v+yvf7 --BWmc#s9ViTalo0gR2mP;y$<{(z`HVl`3>BLLf}kD<=5cncm6E4lGApoD4Pha_p^LfCdL>03iSX0B~t=FJEbHbY -*gGVQepBY-ulIVRL0)V{dJ3VQyqDaCyyH?Qh#Q8vkCP{{x|7s14X!*M2z!=Q}h_wi#=aAa%L}ih-ad+ -Tm3eb)*!>H|&4E-$P2WL`!M+WjG;-W%A+k{z^wtbS|u9@APgb@{}c+uy)4i)yPbg5}&#%RW5B5MbDo- -f2MYYHYLmScB}Gj_&rW^zEQ_zU6h3|Rvs5@`)Uuz_tJ<&u0`_Y`Lm7DyY?Kb_dkiOlD6I~4+TgyTW|B -jjJ;R3oU!YoR5};gjIF97lfSt@OVee(Pn!*h9idwo0e?>D!XpO -)8mANl#+^8E$BSl;sP_TAMlSJ%H@_0~QuZ&!D3-(OyR;#b!z{^RxC)djYugRIEMM0zC#Oq`3fR#T0({ -&s1MHucgnhZGq+4d=V-SF+q|^99PvWfE@Q82O-dWzQ>>r5DO{_wI5vfO42~ICf^^R2D`i4!jYdS(51! -=Qb*n@ZnPKT6ema$roOT@}BE`K4Lk4xQ>_R$=Sylya!)+AdPT8cvwv{C>jNZ; -zPEM4m|4PTz6UQM%!Bf?G=?dSWS?FGy!|G7TTe(GynFABH*=&~n1lnz;*COMzj8zVA5L*g>X2EmG)PUA!{}RH<*79MxKHuVIb4BrwqT#5+Wn&6XoED0pj@<>3rc(M)+U_iVkbGD65R7=E+;m=I~ -fT4>6v%E%0iek2L6GTvL!95Eo>km*ncXhlRtp3Gq%<`1I&*ivo1>!U@A9^Ls(UEKCv>}zb!F|48IE4i;L~ud>f_0?V#3+BxiNJZP6V3y -$#wd&CrL%vk_0Z$b+UoT=2(RCuV6ti##f!!tEwlH!%2E=L)wPV3nw9s;*5BC{CA>JE#j0E3wc(-n)(_ -%D6smL?gKXegvQfZ0$|mX2;&4-_V-NZhA)a)cW7a1(?F;c1Oqcf(2@Ba$WUMX54G1K6tD%7P4~<_jGQ5Ts{*;hSfcOBOr0WXb -Z2#kG=wpVI`&(UU*J!mG|Y9uEV+t6>1y0*eIT+FQ7qK}avx+PaKLH~j_4dK@d&LK>;nvi++if!%K<$8 -I8z(9p^&~Gy>d?-;RO@Gf~ss~UUmpVTM{LJ_`DYuv2P~z*%^y+%^lLHX9bjtVdbIkHCue6X7V%I%HNz -eQGPngG(w>(z0&1!hYoWGW~A?Dx)hwta6(oS>fl90d%Uhi{p`9|qIK4lbt9;1lQL32TK1~E_p}I6(+^Lk0a(ZwcVug38i0*Lp36cCO(nMX6&j&^-V -YxBr}%%tewA!jSv2gZd&*@rpA^>;3YE^|>Kx44Hbi69?8(A-=_2!EO=WzSxOW+sd~Pk7ND^tST4$1C$ -Dvg_=kQ4;Mb6;O0kVK>9Hfu1GEn)Yb@DaS>OF*-Os8EMOF-qmo@57VBB^ha!ep+2D|F2SR*nq-T6qSi6oS&&;4*8=w#>>Dj&#X?nVn^9`4!v2tkot*4iR -c+T^B?-(U$CtFjPKqV(@!=o21~Cl?LzdQGxtKHf)L%ohYs7x(|MW0~UiD+ml(`M -1oY!(7Ih+~Knr&**0#===f+F+XKHL%OQ)&n^Q0P&T0C1hboqG4 -6%H9b#u3hsF#XjPZ=}lt@c)g*kQB778%J_%h#E}ret3$}6_+Xz*#x6ilM#{H(TwJdq<(Pr>EF$E?9;?j&68Z6wW8K*Z6PfkFlgQ^L~`hj!fI@$}9pXPz)iB^cRCbu5g%kS -(Edmx3a|KxbjgZl}jDe68iR{O7)B#bk$5XW9T4+1Ab}Q{Aaew#5N8m#pXFN)&SgqF -Alj+IEBGKkU@i{)1@yu5Y60y&^L~EO9MWENVS+UpYoRZ`uq9Z5otc>Al7}a{bkfe{8R`xIkMu6NEXjE -lP)1+<*-Bki3iYx!?owU$VB2g;!*Z1-&nELhntJ#?f0w84>#ZAoz;nz&aww#6uH}Ml>fSUIZ$<4D+&h -ZJM%dv8rO1tBgb192i0Q{z5XG7GvqyR@JcTJ_U6r-U^7fb(d$>QU(Kl$W~k^9TF%yeHd3G$mX^!h1<^ -pu`(%=c=5uImUZYv`2$8WeozpcInGOc4Z8xa92=zUYR1#c**gH$Kqn<1z5`Uf?Sc@G}(EZyWE?2(yD$ -9@}U$1Q(xJ$#$&+ -U3V&*j#PhL*qRG)O0!smdbUtokW+-{Wv)D*H_eCAUohBr=`WpRQ;Qg4%1_|_a|Zm&NFtg-aNzi-*+;@^0Q4`u|3I!>a234)JZQM&DUa@-OFg?3aO)R`C2lJv`Huskw4Fow@+&QiG8+KvTKhVP3_!iFVI~xDeFBl~_l%lV`~8HtvHL1`!A0iTyKnqY7CgrlWi6BAf_NgPT&Q$@5fCyRF_N_4ni5{Ke(@-A@ -BOR{OJI?3m!t+2oYSpV0O%^03yzq%=MoQx)N0apD)(=!E>GKtf3<%V>Z(xF##?aQ^~d5mvT%zsC6y@L -P%YekuIgWsXbYqnDR;W(TGJ0Z>Z=1QY-O00;m`Rt8h9Wh0ep9smGrasU7y0001RX>c!JX>N37a&BR4F -Jo+JFJoxxpPSMQw@Pot>STot>GTSw~Uy^hvW$YPk?))n;YUh@@DERb6hY=IN8CPcGL|RCQL -QS(Qt%mbDaFBid3drgENP`^*K+gp$to}BNuKXw@ecacGHJ>}%w< --rph40aNOxJg7DBgWg)7hZe$aSDy!6Iv66+XliUDo@3IuIE? -QX^h`^Yp*sRNKz9Yg$>f&_2%{^x(^~%=7XN@CI5eWRtCm`00}fiTU)&G -l4YY7C5=I+-v}f8W2I(a#P*{#bMG-xdHl?fE*x*gc8ebyRBu6a5lSYHwCQfENv$|ev%*knBwJr=(u`Bv)DG&UOCLN0&~`sJ=d;;2{01#smA$ehe`5ThSp!WwjvkHzH{gb$}oU4hl{>=w -kLtm7(4Z;};2inncM=LOG>GMy`436I;(0}k?(t9Y|4eqn -|N8)o1~qAWVdyhYj{7>(-VGpU-zt7$oIO}+3xK0zQ%1*BVyIAUBk*!oi6F&89nRmOiYZ|Nwbz_z89D0 -?|ykRdwYEGb`Mp#*CuOH-3Qi8Th2?I5B>+bO4Lc#$QiGqnM86Ane)>?hPlbqi2J5l(IOm)$#>$HvXIl -KPXzp<<&GcD5i;l$)sxf^$~Fxmw)B~Yih0~oj7VYE<9gL7a6)Kw0FsN5Ql%;C1a7D?G!45=2x(L&j07 -&lI6xbkh$FF#J}|hC+;l2Fz>AMw8@-U@CFs6kB%=6t&{#uw88=m)wZqY9#O=Ll!uye>|0cOHp@UU^`3Pf~JQi3;Tbgm*CGP+hIghi?a33de4LSYhJ8)5O`$H`)$h&xojG)rnG -ird;UC0)z(W=7JJ=d<}X%NH}=r-$w&nyJ$4W7Wev);ju%-(SN-afv*A(z9BA$Qo4d;%+S^s_LbvWIbs -BzbdYFptGG_7Az70Z_GlO0?Cq%MF+Q7Z;_bIz7*SPf%~}EF+dx;J3Z*_7%>9dMKs$Aq#9%cD3omT7Mp -}*Z^G4-E&VajN^+);|NQqy8j_wO@&mLZ3d69l8plu=SBC>l@fCU`ZCejL;9~)L3r8Pm;0P7Ryo#8~TA -;=vVt%_%v^*H8GgC~8-Efn@(q%ly40kkgXQ_49mX&AQxyX&E{E=)R}CCBil$@Ffo1@+UG=km -MGM(C_7tNiRDs@*J3M?wWtHti^+uMt}H1L1;Cy|1Ez&;flm}I)T1~W`@P_0dXvjrnIC=Syc&f|4CdI* -z*rz#&aTqV!s2anDsb-t5|XXgvy^^BLk>|yZLyHB4{ox8>?s&<+qAev=1Gf`_m&jVSuQ?%S@kU@jq2a -l5{L{eIUy>O2{*#Uz?MF+Vi7K#kTx?|_%L^rHA~SepY9qjwlBaMge?~~>phJWDVja+lXFs-W~TT95Qbfi6PRy*I` -Rg^9SiAiFkcmAEj{o7%Fo0p3%9Z_QIyKNA}^Cgqs$h>P&lk<#0I2`#sRkmhL;*tQ*P^2QinPNH_*6}_ -+-*lGR>A*sum}BR1L1o9SJ2s(@<7h5HK+7%*Kq?FSu+tS_Npr_7NLp)GIgS+U+H*t3SzVbItEiyMSO9 -cJgS%=_Q4Oko5^RH~b`Du?2uds|gn>m&t@Bb)qE|)`kX$pFsr2$N*3{zQlDP$&6OpWKxt9n4;pyoVH5 -^0_9=CvT;NrXWE3oG{p!S_plshm|_SpoiUIxA(&}_+G!L=fd*8J^7Msmavuv_Nmj1JBCDtVxSwPpA$J -0n8iL!Bk-l>jV=aK}!pNppl-nW)uP&Sca`-kT;!LD1OI|1*%=wKjZ-62s8LfbX>5kHsx+26 -pd<-&5a;17!x_z>ln8$}ppPNL~E#&?RQK_m3L4<4=3Tra1;s&a#RD5BZli3dkEa25`(@|00GF&IHX37 -vX4RJI%nwJ^AbFbHA^C8mDEo8}>B6@&Terx}PTf-2pGvEnpqb_nG~NVHzzr&w@8kpR8qG&88->aTUk0 -4r?HM6@5`ctGJ>z$H_V}A14S$e_g<8If~pTDpuw_!_P<2#k#zsk7TzHx3Z=L`In0s`soLvHqk(QoIKD -Wa$u9dZq(LWX*-d1&G9T3ZD$cj=i7opdl|WPdIW(ZfW3}e9C_NsZB~~Bh1qVwgv1%~?t@FjUCB{OUgf -q<*ql>aqNYwQ|FO*gPXO0$lN{h4M51Q`@uqDVlpH9HYyrAQSg2z$PqJJ&9I>IR8h&CMIznJxI**y~25 -aZd0d)7neTpKmU(L(rP)Tv|SCD+vgNGXHwA>bLi0}(fw%=s86665vhjQCi+cq|_5a9e`k+txiBfS_qo -|6{<@=)Ra^-8oE_$_u-6eXBdIYvJYTM)2&Qh$GP8tNl>5?z2Zia|y}kT6WovyB`EHKf%K!u&U%K?teC -Aot<^DL5KO^&#TR_nCt%$SJxE2ch~82UUXOBkDbRxE#64hD3_?{sTnHRWdAIVwjdS@UAM01)Xw~;%~? -2znuQ^W-MNxpT9e2SSRPFm!~JkKY^{g!br9Uh+NBN)KOG!?D6SSUB78}l>~yW%PciK=Wo -qX4rbiYM80DTmkmdwfb5Z#q7LOR$OhZdAn2-V1Wb6Y0jq5X#J+N<^A{2Qw+cme#`aoWi=jedD*i=%8i -f=E>OYi_#?rC0gx-<&ZL-XA={*AL$!*4zb{=eGo51FEr0gP>>h2R>XJ_yPiIWJWK?R?bp_~CsPqSqO$ -nt^v*bikf0E@i2p-2Nka+MxE=qNq!=^;u_M+!j+!2-$zX>j=Gl#B>KcI7BuI^qmsi -L{N8gh==~g6&fE?JY2k6{KqxDkKxHJJ}hfzCSYV^*z3@_sP3Un;63E|WL;(WwKtugllR$XyAj29Gslq -5QYbh=Cg~de+(L5TNu6dUZ7YFA+Qf?VLNn`(RpH1^7QdGV$|Foxb$3>l8Yp~YmQy2BpEN;3Ce1Q0lMZ -oS`qa5V?-#h+l0(1u4{Y?LBU1m*WU{iKHgu -y)*SbJ&dTvNm0h#V{LD91K3)jj{@V&qv@4;?eam8O`-N#BSP~mGy(Avu7v3?!LUaPrCZNSM7H;NUiVB -UjICiMGEc@7!Jn*L1XL!vn=M@Vv)<(Bg83frMKXIEWq6d%~Qii3cYDo`Ry;H6oZS4pTvm+_%~VeN0{d -TH5@u*i!$AsD3u2TRW;e=S-}y@K1VCfGw3{fEUgJjAIUBF{gl_jilOySGQ)5Hsl(u1>VqjKFz^SP7H< -4>wvlj19*M2hV^wFjNYWe00b6|M@(_p%92QJB$7#ot_u01257e5Oqb>>71YkMOs$G@2kCZ>JN9~B}uj -fC7M8tf6xS`-BcJWB}eFF9g^uhfEXUquz;*5hb;*|0VI$CsOL^Ha?JR7y+aIy@UKDDgMCIh>IdzTuGOVxRLh^2Z;yNgdIF{H>(UY0j>G}(#?cmu^^l4r$D!=%MPGHhQR3jy2BsNHAD&(dXXHgBG3g}O`ks}{4nuw0Fr1|zIWgf5t_(I!qOn5l!2oz05MEL^E&^eC-vLO1 -#ZKbhQi!er(Tq402YW`gaVJE00P)xG<98qbNyM$MD?6t&o2L6xDONo!|k{4E-rsL{`vI-b;-|3eZxtT -I2aNie@|8FVOG;IAfq!D@>U{Q%k63{veu*Iq6DHN!Pd#G#KQ_y&NZFpyuG|UyXYgIb0+s$)Jub5TD5tR**OV2OC52hnjgea46)xXO@f?)f7E@#TpBmD+ga4tlldwJFPW4%IlL6f{kRE$Lz4=2ZhN|&-pC%8F#5EBUqt8GrH7ax}10GilG^ -DI9PBjjWMhDRXW13|}&7%=B#3*S6Rx9g-lqZ@50}E!51DsCxHod*57dNbX(Wx^8o==|ABA0&5#a$iVn+&ljG$}CP~_Hv9oDiZ!r5o1bIH3zZ#o#sUY -#MN7#DS1=zZr-r?nS9=b-l>75jX!A -owh}tFo?fn2OU$sU@}-U<$#JPR8{6+X^tq(ti<9k73tINFJ~E31O}^~63qJKGOfU=+TaixTnsCOs>Dn -^ltPjGBuovv;k}^TR2W>7M`hq&z_E9w|3c>`M8=C7Ps2$1wd!7B)wdMXfkLCzk66_lm0v=V792vYQV+3snGu<4_H@dr%Ry@A -o=-qU)VgjdvI)Lvd0$`!>s$N&c-K>bqF{V2d%_kUGJ!DV-c(uD1n+-kV+1BA0$`q^Asg;SA$WjXKjct -qdt_z(&kjj&y#zO$P29b#O%}41NdFvq>lutdW>W-%75?%v2)(w#eE^D|rP}+qx>Tv{l(CuqeU**A;a- -<9!%pZc?S>75~hzbQL7w+Llscoz?YqST}XTpgEa0YbmRbG}#KM6_U{SMfLTtB8zm=+NR -wNOp`p*s=mveN%BPzM628p#nX_Q=u`}n$566Y>do@758`Z==^2G_l}@q{lztzQg!|<-xZtqdhP!Z)Tomi%R=^0{k|8x3iSNX#Zd -uO|H_{+I20ZVGaX#$~hu8+1i18bR=GeGcLrPq`oSKnI>Eu16*eIeiJ!U)Xpyfyn1nM->8w;t -A#nd405wI1+J(CbXDf^)ywJiwMMtCcTP7~La^!(|;?9_&#dVmg5r9 -q_tyeDXid?tSu>ZS6^-omwnG6Sd?GJc`y?FmImb@44v(Yu)M&NRnu?J5=3X@KJ8+q)^^Ewc?1=13@pk -D4$<~wH5DKJRDXn@A0t)L5=5Co*M*p@M|Pe&NnU%4d$kjFR4OI_h$CH?s^rwVTtPVzE?|dbYPuk(~q3))FxvKaB(>Q4d;bczMw~Ml!=#6?|!GV@Ad~+5<`xC --f?Q5x*GI-l!jZgAeR}2~N&2Z2rHO^<i0WYr)Rr>Y)U%ZNI*q-|4 -$1HHi=sSglQCVVW&6dhE%0g4$gFqQYvZ2zWguE(^*(#1oW3VnS}BCrnsoK|1X&{wR)a;$IRhh@ -~R+Rgs;<)Cw@`zgM-yg;aJva(EYVSU;)=(qz&CdU(Sq3!ny#2dbq2I#OWx9kNLs?Jf55M)CHg@A6sAl -K{#yDK@7`e?A%mFy89v|{k`0PnsIUHLssH&iNa3jOK&g3vC}joeEJjLT%AA-%19YvaDAJ~i%biu|Dl- -qjP{1jF)c_MM#DNz~N*TTG6;CXRfY*&gYd#lDhb5M|e#uxNneYHd -*83x1_r$Zf>)wc#2e~hx)lIo^HH({eW7JD@MnFZGg9Q)$o(gk{oS?VCXupf{c=zP2E>o=CP#&}OQqW*QoVi -{~(@dXSX(6Rp30B$nvk82XGj)|@8IJbJnSp_ -ez2~uxXKF#YGM71TbjZj4_&{V7YRow1PQFM-Kmv!4B<&H#{xH-%? -zHWbpNU!=?64o(WuQcS*fy0*{O@?}J^FoR)nsNo~g()+sD!n&Vvw0P#+}yJXkUaZ}cs=3Uu0+9NX}Pl -rT9iZM`FXcPDO@|NW49u<>IN^c%h>iIx*|6rfo)yzRI1fOgeo_d8{c>Tj8rh(m~@QJxHBXIJ%w~0I^Z -I;W*^y!B_Y;mF6iSmU-kJ_N;&NK;J_&vy$G0*yvWeh%_moBrv#9Gl-Wui68E<4y&Culn3u2D`xFE@h` -Kh01t=NV-(2;cZ6AC9Cl&A5F35n%{S3?SARNPVp7y!0o;8afbB(tmv`&j4fhibmk$08C#4bGYZ?8(X; -WJvR5`+KD*9HcoX4FaO;JqE%6oS{c^6j7TqbjA+>9AW7~o2lU-U53PX+O#=v -XzwGd4BRWm$)0a2?#boC7vH6@*ZS_Ehl`BGfwz3rTT2@{zSS5Z#qGq&h@9koyxC;Y|A&pFUHJ7U--NABOC$|}Z8F?Gi=T6@j$Ols3A@-l`{RtxVn-KnujR)H -f-ere@%@AA)d2dYE7(hX5x5UioVC52-)FGANVJ-&MW}?pYRkALK@8orbm>)TFY0^5Y+UDr_wyB>}lKF -F;_&d)EJeWbLGr`>ulzUAm-4kwFDkzcDAVist5HQ?}2kxvC?KQ!C&$*Fe>#U(AIcAE~QlFb8b1+1e@*G3Q}r(R^yeDhgZfzcR%zspc-$xCS`6qG+ -__w83tJ06YC}sGt?&ICjB=Sg#j`<(`5&Ilu{ey1cPETnAk23WKlOdm5x6_%MndlUDk5ZR$KR{$pfP@nm5%*~hMz2iQfwUw; -1a*?SkIjJ-Q>%RHVLGUHCbi_w?UxM*>bHuHwhc(4`pBtF`w@F4+;7e@P&7+_)H@refKib;eeXh<%)+; -%~E91Xh+RYn2lUMdIcyR2RCHbnHF0z%xGD~#>oD({MSKQtR1yZZgZN9)!KM2zMqA~bG`@*hdimutk?E -mo8s>)joDA2sXbtFQlU8s0sc%+rO0b!3u>6u+IwvQ1!OGMAJ?=KWoPhfYx8NYg=JH3;dZAqj^0;x_-` -qeZ2Es!B*_B!ie+$#+BB6-O2RvJ%-&xE#V=v`s#WVvs@0D>uLdE`$N?b_SFglyj!G%3jbmSFV>@ -ga=?|arE42i$>6!Iv(!?`H*{-2vl*_3*-YTQo|KJQphJn#1*}$=L!ITKF2E!hpKWPdZ4qWZ;mvEF%A; -#fb{x~jC90y7ST4?W-~w2jt|{zoPumGGy@A{7Vq@`|o%3lR&LqA|lwYgf^nH$Mu^)Ub6yF!=Q_8X>LqSU_9)rXDXtaCDnW8^q(T#`mX%C+1J&hrvAFc(T$$bv=<=V!9P+XfwUB~3Uc?99GqrWJz -#%f~WxC+?5$C@CZ8CJyeed0E_gTp2>K0^U8Jaj@=G@ZFg|U2P0_TYvvqT?#5BJw8cdnb@o0$zM{68V# -XGb_YA}CUmyFgblp);nR(2c95y*Zv-F82=v^xWEvcQiY9isQY?2za3WBnL$u>H#HYshji$k;_I^|Mmz -@DhNI^by?j5eF4RRkp0eG#DSN|hY#dMi(r{Ftva8>yuwLaOQ}w-u6-dQjL6c~r6dU+(T;iF!qPZU1^OHpREcwuzM&w}P -cuO-{s=N!Xn}9i8Rg3nl>>j4tRCTpnsOGSUIOYf0R1Q1{6EqbxkWzSo#6Zj^!zKqDT={afV1AeeS~(q -A|t7bsfbk8pdzw8uGMjesr!d9=(=$y9`9Yq?L6<^a_ziS_lf#Xg2XhsYuEXnmu_CZz5&!f8F;_*FrZr -{ohRxtMdyikQK8$?xxdDFjMu2SU+oQW?$h9uU7<^lokx3J=%5>3$?QMs*OE?~KvxBCy6ZzVK;ivpuY! -B1`1n_>JxGYm6=NPNyvxTzUc+POk-cBa$Nhf*P)h>@6aWAK2mnY{22+b9Fv&6j000vM001Na003}la4 -%nJZggdGZeeUMV{B(#D8eJpS&JrBR=r5t0)**?PgQgEs>+fkuHp;3EV4Bpvg8Ek5O`xAo -$lD2-iUk2Ga=a@07CseMrHL%XJp5-9Sx$WGy+W-l%}d-t?x{3c8`X8(vf&e}&{-cAc9tfBqk>vUsjVg -{vkpw1i-$+??kt=EAKk76%<|#_=A#_f6ud7R#h>$dtnF2q4q_}~F1}<(wVr#54GJR1rGwDm&C)AgjU@ -Bbz+PHMw-tu-{u{yDI8cQBsK1XNP1_rTMU;G}_*#DfP)h>@6aWAK2mnY{22(KON}!tr008a@000>P003}la4%nJZggdGZ -eeUMV{Bl*(Ys+}A(~$Ms4BA$NqkPa%l4G?KPi?~2`(9kuko_nBQu -cGC0=Hv2O3%*-<{>nzK@I<=Q>6teHNs$@{s2r|Kqy;UX@mls)7GHX{BlYFQB-E?EC}EErPK!#bLJq-JcHe7?E=}rZr}V$7d#Oy>OXtbWdU01mb1z -N(zGAxbvqt4eh99fYOGPn|Md_>RKRajLyW&GodXcQDca-R65|~MNdoxp7v=r{*SzeY#?x`$SEO&WvC4 -RHQ*sw5SYB6{c9CW@CwE}F=<4@wdkFa5I=HCCUpw?EZvB5v-^>X>*iMdqfV4sP3W{?xrg}7}5f(E~E1^k#qx2(8508Z@NJX}1gX7X-9g7~Xsq2mnu$ErK9!^6p0S#_LMc -*6CLwD%)#)yt+hR}Hq>~)a3+pkbj;5ilP4zFd1jAM -D(UGO3tsaFBe0OJJ)o-}GstFZW(i^8(62>@@_w3SBXoh^a&PNFQ$8v133uR4R+e$BmDy@Cac={q%*Ci -;!staM!sjlK4TjI$B5RPW6&#mSMI^7GhnN_>5Fb7FXKG8q-NIKjNH*h)87nNpP94oCti4W-Oa;sUJL1 -eL?+0R{ddK6Zq9RSQnwnIg%*XZeCOq;J@#uqldIEFz*3e39euaJjxy+SnB7^KD-%h9eiN`k!@sA&_pV -$yzU5QWDG^!oYHAuqw{6&E~rYDvbT=v|hp>uXrDruzWW_e?T^n7#%$8r0B9(2XgDVS}t&kqk@9QFzTLoS)t{rYnWw{6Q-!bQqIZ(=@Y*ywf`0t}w%v$l)FKfb%-Xm->=qaRCJ{{bBDnH) -ctwol-=4!e=@pXoEB^DS|vf&vc`N6@nR5|H8uCwWyN9}+tMO|VRCb2axQRrjaF@I<3g7!R$9F{zEDGA?atdXGtZ11MbWQdWm74H -R*4*;)CO|hSZBK2kpM(f06w*vwZJ_f)Iv7U3S-f%S5XwLSL>CmTWuU@J3iVoJ(ot;;La_Z4)-6VbqU; -ctwJ{R8m(;8Og0WpBUG9z8I<$7(5;gM=WCj24>Ir|5y_PsW>aE> -#$=2zD>rENzT!#OKtPT(tanU%Fv!el{o)ek=9*u$UjdG+6o(bq$FPAZ$$(&oX0qmfSb8I2`ZefZYsip -!T}La8i+1018=pm3ORd$PVNQ38>F3NWJ+8?9Fbmhf6V-oozPl@jjPE1(ax`o`N>&k2LBGnCl{B|L!$@ -5aK-hueW3Y(9t&R|3Sn27fv$Dm+C0G~aTH@XG-F9UKQDoT6mX7DbUgP&>0;cz7?A#hJVeZ9cq7f_OW# -X+%u`Dy8p*n#W>1hfw>`VmnVREuUpf#dOJ -OTXHdtNm`3fI8-C6jPBZaCLH|qf@FZQ%z!JpFb`p7u&nl|xbRbj;Zvg@?ZTI5#R2Y2hipcB0QVrPMjM -=*^)w7428z}LZwqEofi^eNgXy(r7oPFa3BH5ltliNwcW?jW&oA&ic%)vGI<*}g%=sl+aKraHfw?9SAb3Jq?5!@_CN=xukjY{k&2Ei8mZLXhtB)=3=P4V -f)N3bCOHjiG^z9s5;av~AMT(p)^W4jIa#Cb+~KE90vk#1E`rF9yIn^a^V99e+dHk5-JC}AFbo5@r6+Q -AS_H}%59|Cd_ZPmC$p!UlAWz?UUvmC8Yu9c!?1KJ6mY4p*_SjEsrq^w1T|wB>M?;j2mwRUWhNiZuk_} -pHFSPJUx;c$#OTm{f{>#rkk+U__Y`=oTgb>6Q9w9`~o^eQL1QpYe4$hCLYWlhI?L@CgBi3u)uE -%?rpa+i+62A2wxkj*K56&`af64h>zR~xfZBDilzaKQ-R0yhuT)MxDArRY` -kZ{^67GK+x`rW>dRoW3qU1okZ)sCh4KJjkYLI0mY9<}Iub=+$>Fi&h%6DJBoPCMU6zz(y2UrP3VyC_F -ALilhyS^8FloX0Y7F#YWN2g~styD<|wJC8zIrL3Vr0SKp5Te1&pr}C!FP+SbHB%q;v$QN*x@BdV;kc( -ys)kBQKKD$i-QQW$y%+tKDp)&p>M1_7H3M$y;B~fm`h>s*Dt=8moX%PQya5f6E7o5KFo+F|Co4Are~l -_HtYsjDnyp9)`{k-EQ^}fDPM*@&z@agkGB~)c||^nmf6+uIx-7&LUJwb?I0DoV1zb&-LjfobF -~>4DD?8chAcp#RnN82?unVTmdTdhlt{L8WRr7{=FczYBe|9ikgs~Sg3rNZuhmAsG-i$}DM2n<4 -q7fH{|`&E<%@H2LjJs;3|0-A$cj-uS~7c~WWErMs7vFACD;QfURsHohl{-e&h!H(^hD<-7PRYFTc`8EV3}Ez9&Y`y;g7+)JC257y0VN#kl=9LIcMnVqa|DV;T%&&;- -nvzDVYHiCGHzZLY{Pn9k`%uSZsig2?+v3hn22?3d#61l;uIhnJA%9f|1s_+lZj}?m1oSj$v=@~@vTiF ->-kt#2ESpIUs7EB_v1R4uJvk(`Bk&D+1v?*_M#G -+7G(!vM5 -NdQeYO|Ot$!<8}9^LaABu%y$$NHPHKU%MLWhj#szt?1A -w8AA97toLyH8vx2sZbV@EAT@iYLNPhxvyKuYH2Q4=p%(rPxISzXgL7?pfY=R07-2UZxDaL!c)QI3kVD -!V<2F7+O#;Ta1~Q=NzGsz!G=PHH*zy748rCmv-Pes2wg4hn01;g=K>>snpQ}OTxJ6%|hMm%K`Q5nK&N -JWw^%|lEFhVby`p6;PFbdCQKJjI5bWs}dyFE#tRN)?G(e)n%gJye<(Z@n2^~iba=?V&s9 -H-h+W}=2kEn!7DSr{Yn1c)J;`TFJK6v@C`PqHByT_eZx+iaW5@JWEB@j4#+|MzxXV~@54_@WvgEHwGDNE%^qQbY;te4bHNNIokiA`Rpa`I)X3q -Hvt?Q8KLj}CsM&XZ^MJECX5gB1CBiMXymX7H`zi`k0+Vui_QSJ8PwItEXN(j?Bj%X=ilWaK=)p;nUUz -zg(EQ?{bi^7;Bt7fnnK$x6j>u$?@5|$iei1GMYF1)OWw#<>tToALAE+Nz?tiiZXE+!oq8`$S81gCS8o -#)Z8|9QRP)n-hO7%TSaaYw2Rt1fM3G<3p_;fgml?6LNW_oBtl68JDgK29&--J$;3#3%N*o=bQzg>Fr` -<~`$5G}tLw5NsxbLf%sVOg<&wp>ofoCdp2#2v-0a_-FFQY#81JebCe`ALz;EtdZgmHpsNp9|r((a>;f -U>OpYZHy`1zw@20Q;!x6NE3=~MM*u-h%X4RTQ?X7>*ZwCC*9~FVIF6Yt(Lu?g(pB;ru&o{?s%il6RFi -tZY9_QLsBMA7-Lxc-JM<3#ooSz3sK2WX>n-V1}(T -5?h4y|2_Kwa4as32!}ufd^Lx+D1SdCd%GnB|gnBQ9u@g_eT;NnWd%Ht(`+UVJ94g^h=2l{SlYXD*W}x~b{3l6zc~Xq$S7n2g9=P(!~1bXGBF3w1|D -P#$A)$iV=}Uvoo35T4ctFgP~>Ck^1T7AUk8HlQHTw`dgY|j+iEOQh9T*aq1Mn|l@IWapt5GDN)?1GEi8kfrp`UL0z9~RD2&e|$nnX^F;wmq#o|Bo -aXedvipF+n^`}=9YFh0YkQ_)McqO-YZod@Q=e123XvXkPSo -D>k_*?M@y@wQdCVqFI-G8+MdbkM&sKQWe_$4DdCZD%rJT{EdK|wy(^26hu)8{X++Ek3z#dsp1D_>*4F -%px0UynGDLv%$H0LQhB}BuV0Zsxdo$=HW^hK;@V|vfk!8$ -~rNN#--6Zw}5+t3>^p`L&!IbmIIRZr83tC;qSPSE$8+o`ziPxA^PgK>?aF{Md3 -IS?G<*SOigDePU|{%9g+7M+0aW?n*B#M3{|Q}-fpQ2nPgvRZ;5W*A3ZA4-$YKlFK~h~I@ -D|Qz|SF?2TVqbD%xn4OHX;{#zg(07VDs~jXGZ(pakQP0;qR?)akmZp=X64E;O<61k6zNu`(J?*ihXU# -}gzNg5om+>UH}^K;a8PWU$9L;W-Lj;em_^w~8Aq<|ElXLUdiHPDsfC$mDY*pOIR)gBspLm3S@s%di1w -BfM$y_o9NlQQq4!J|bsLog-j7!PdnkIW7JI7;;0exET5gYT9>3?ghy{7XBz`?bQY2r*mKiw(~J)m{{r -W4_DYxVCF-*QA9KF<5$xS&`;<6nE97^x)IY)k&j7g*hC4w2-N2cDGU$G!BMT&MdF7yBD_+Ym2z&@csu5ee`kmgC{)JZ008y2M=3*AOIhV4v{9?7|ZOO`L`KU`@6aWAK2mnY{22)|3Ye2CI003qo001HY003}la -4%nJZggdGZeeUMV{BFa%FRKUt(c$b1ras#aV5S+qe<_9w7gLP!PnLC7j4t@ -Hiw`{1A~@mn^{>@Nou{m!~OR@!xxG2+vcvt)j`&lG#t)6^G?ZCqqJqx3T>6D%>8@P-!U8fo@=#YMlNb -zv2g$D@=urVK1^6C=De-!RMvL7WFa8_^5?%!khY^xR*6sl61ulW6Y57=LoHB8M}Dd%&cu`?4|D -{WZ8YY?u4=VF)AOqi^Tsx3+2tBtW@^@d0p3`d+U9dmapzkg5M7NW82jr)QwL8Q1fJ7@1y?c}|G4{pGw -MpUA((}@1GsJJnsMhl3gMS128I_Fh2*jv7oU>Z>TLW7NCUI?)F>(fZizU~*fcF?uaLr+2tK8;mX_ -uZh!W8-S!X&HD*{5EV9fS$oRbw|(fK&nAEE`XblkX6I-r4e-b5==XNBfpHOKyY#gHNBwi5)-a4e3`3h -cjt60N{}p(48!buyKzmXZSmG6;Y4u0-6hn5Mthm9t2oY`24WNy8HeET@%W?nzc-G?#p*HlatkXXc4-oip?}j -?umwdTrD!m^QL3^FRJ9ss{K0AW@rE2e7f*91&hivmA}d*C> -4(1T*E%^M5xIZ#58{FR|T)6-`4inF5>5!PPSxdQx{PYIqN2X;@^ -Jf!}i>F}-6vuzANLAv7oq+JloJF~w=Iqis&Rts5W8k -bGMd&6Hu9I&ARTWWlcU_fE`5_p9675K~tyTd%O0zWWAKd5+*^gEWs7j;mK!{Gs2THBbjlamD;zn -xKAbJA=O1NF&j(`-&85}hz7FJ8X6dDDn`l5(S9g;R#cU_u;M)I3CfBPF!hZ!>AOz4MrT_e=n3P=uULtMByt9|DHQT;E -5s=L(eb)Onm819aYWFv|k!SCo>GU)M|6M(AOx4yhpU6sG4_Q(InDh+o8;t4T>#I}~~`h`M676EhvU$(7+yBH*c&* -pIzTP)8SpR_!3XsnB<1pV1JUv`@K$D78iRGNKOVtjD-*N+i~U{@P%1%I8(piZ?6uMG~uFb2RQsvuWpZ -d5c)d9**D~1t`Yl!-qjDbcR!E#ykZ}?)K~AUEeX|&M5oWkEf@nPv5?H{vCDT-PN~)s~6co>+eH}dmr# -m8?^tng8gnKXJGObwBQRoHC8)VfYoC*+8V>*-ruliWBQw}iuU;<{1IZ7$^mh2~?F&fDm=^8~p>F4>Lw9aoZMxV3O{PajtNEFGyB|EC#Q+Cp^CMdHLll -=-k;o}y=CFa0GI!4h!@^v!LGmx^Myt;)EO0_pB{c=G{!_ -5AdOKWZox=B&aZ9lElN;v}{e+8aIZH?RM3aWb#?wRrht)-Gm(>n@DG+f$y=N81q++vs-eJg`>(29hMm -!35eThmY`Fj8XsFoIu@8V2qhduUsLa&dK#x@l1tk0>&8R_heP7?Ba7O@dlOuOK3k_$1-+hRAz+Nv!aUCG!Fu88)nh-#;jeZ;kiDjJ9x)afrD -%(m7#)W8$aLA;2!&IyNF{Fc9+QXPe#``*P$KkvWf(r~A9~4A<{%q6{9I2jtcy_MnoXbz*@d$;}{DPlF -(l28Cm4+jgr~Q{_N5fHy$Uv$wQ?oC0#2HUi1AyFnt&8AohP*6?2o3ZPasY;kuVy7uUH^!nZqTJ467@G -~KCjwgi1c57@{f9Y -EycdPFn#wHu|w0{2Fr`Q37CoCRz#>RiUtB;G)Dd7OCj^r+0N4b2(`kfbHhq>*L-YHw0V!jH!bmqB>b6 -gl+y^TEeZ}hlH{|4_)=ld1jHRuPag_^oC>qwXC&xVY9q2b%2%&*becwe#(4r*x0cpPqh3BS|6aSL}b0c4+bG=Ml+>|B=Uk08mQ<1QY-O00;m`Rt -8g4@6rP?5&!^cLI40D0001RX>c!JX>N37a&BR4FJo+JFLGsZUt@1=ZDDR?E^v9(J8N&`xRKunnE$|Qf -0*{5Ti$Gt1TmmocE?V}$jpv!#>pU933Mtv{TkL{7I!xKg62lb0`EzPQ?rBSj5^g<|`r>?_W4$?;L -n6mN5xcig^E4b4{Q*%Ygr?&XV`^HS8;tZeS;s>w@s!Y=dTCcox?5p~HWEAlqqh)Q$^7*oIMSYOw?08( --(ssj`Iwvinoe)+-&+~>tk)Lb4It}U-BCOXA#VLgrHrCA!U3&GWj@veY%Efx!0oWWT&*VjPWaNnrmQX -SxWE1Nyr_I1%UO{FX)u;xzWm3iH?9XtTGnz#SRtDalf?$F}W&8zR~!-~BVs#~!SZ3m3bs};NI+lnJi1 -kj2$$wb|82``fZ7C0dOyyLujgHPgPD`7_#`?4YYYHnnLijWyOSump{voK~jfWg!IE&zL@pS~CO7j+Z` -zc09^Du6tfvXLuxDfz8vdi8xTs`5-odK|@s(!U3Cs)~bTq(%2m)HiSJ!v_Fctwh;YYmtHWR4WP%O3o{ -lD2_A0I2i6^yR1EQJ1{l2{4CHvKYANjv~A^D!y-KBmLU%TZ028P$FlRa{GSoQMd3kE;%GacAp2E#Ih&cNimd{gn&%=-%LcJ -3XSQ;GMMw7HRZ0VIKm!HDBo!fCvyxMRSe{SN-Ppe(4F)`K3xfmTh`qsYiqE -%f(r{SjZ?&cK0kZnLKEO7O~HsXJcW467DxMy~-DHATOTVu6WKL;1eVN+APTU%_KAPqMPZD)Q{=&;pUy -;OB<-hzc-eH(*_AR#tl2TOqqXuXufHCzcQpK*m{*rkRcJ(QBd$2kxfUmnUF9@95bw%j$g3v+Nkhy?jB -zj2SaAt_Qr8sFx8Bc6^E;NIFFfy!cLsL$*g4wgtaq{ih9+HqvDqbYYpX(dBXCVA7W*-?9uAF1jpRqEL -?6`cLeKrsk)50RB`DW(&~6z+>kfz$A8t(;=MvI68taz!OAhr~ETfx#!?oN{0yaLF5**URG*ZR1hjn@H -jQGjA$EX!1(nei1y1Dhg4YFN8a@klY$Bcux85$D?_Y|WZf$+*R5=BMG3*#%#jT2)dp?}0pfrB;=I^mF -2R7nI`+X}K6n@4@+nO67SoF*Tsy#q_UVM6STc7w -J)Kw2se(zJ2?2$fP&r^n%y1sjF>v!cFb7EOKom6tvxBS(B{Bj?J>20nsIsdms28Xf@SpcpH|R0yTwFO -ut@Cx_ue<|=FnHErD-d8yX7B}~-}*YuAl(e?VWRiIXu9XqVhllNV-2e1MH!+}{xLhF@3LfZF*GE|@V4F~@LUIVkj2w64TbzQ4YPf -o5yx9c~Uex2xS;bebk4<|w?AnxQ3zyIU!*^MY}FirRIpjX0FHsmXsk`{QN6W&PASNZJp{g6X_pd2f21 -_^n%%^Wz{CaTQyv~^w;{vUNp&XjR7^ryz2@qIFB2>On%gGSW!CDm?CtCXKC9rfkbrN=# -e>I|>P6EyVCA&CAou5((xgigvLu(Fn#PBmU|A=e293`x=*-6ZR028Ei3X_Fh1Dc-NvEI|woKH%%#sop -cTAKrQY_$o0N9-+_1LR``%mI<1$k&@5ADBpiH6%t0&pQm90s&8)f_5m7*of@`MCOi-PW90$ -WOVhfhr@%Vf+EPG&DeC19$0z~IF8m^+VnU|=m))L~A+JUJZhggQoISnua;=*X^t+?*7a)u~iTe+g$CBETMM3Z(Q7)&j8)z##e!%0w9(_-XL0=%=-dm%2p}t^?c69VAv&jb<0hYq-9dPuRcZ^o#<>P!ExIdg --#~)Y0Gx#4qHPeg3;H$G5o(c>ns1PvGgB=vsutpz?2Z&D!ve#rEgr}ig3#`z0%uKpa+?K~=)EgmCawf -%fenn8kY4Jhm&rRI(C+eEf!^Q1Hz-tExU;4S8At4We#0RPhiZ9-z0?VVidunAIcQ82+U064TlL(bV_a -rwQ&v*&aupD;1V*TJ(6@^ZnBUw9#aAN>@AxZ;CSjRSf#-va-Le{(gq+WBb5S8J$;3Qt+BKUL;BQ#84O -HK(tb0nqP?x`3g-*!{zRo3Sx0(cc{KX5}rLwu24MW--|8{u#IwMk|C -g1=4;@w$x{=+|F1#EJD`S$#M_WAAk`Md1RcW>UFM@M};|F4Yjz}qjH2(*^FT-KS`W>D2;xyoeIbj#2t -KoLLm9XJ_CpK(0O3XNX%WkcRfVS4)aTHFstaDla#sf`&F$3iwW^-eSp%2YvpU9meUI!?AfR?tGaFcVE2Ph)9rYDkBnP^yHU5h-T4V!H^4gJ7?ybQ59*W5m ->ErUS5a>pg1#1_n)iFhR6F$WnSyF6Kavyya72K=uu#!9pD%8QL>b!7P~W&@t0VREcd0;hJ-0@%h}k6* -;j{DC2Y`_Dg_O2V8#NmN^9*GnFGj%h@A~_cMB~rh#w(gOe5v7<6M#-jC@X3V3wLK$FiGKb(E|{E5+8f -c?Bii)Qbkd|(#LA|>MiCvB?^tT7;C%u67)Yzmc#=7iTLirRW77&5@(jO2ISz8d)M(UhiaaVP5Ee!D;q -HhEPXuHo%sUWgNjGM5Mu#Rlx}?_Ff*SyiIt4mS25Df?!|Y2vkRB_&389e=j?sMXI}0gCSxYVj+bSzxv -SK>%ZofVxgLH&DG%7$r}nsQ7at%K}raN)#k-6PsNAL@IQL5GayW>z0Fm?T!6u%0Gcu45W -TcAibEVbeYrfCq{6fk#o$$fjAO`EGwX7tX*e$J#p!%gGM0fLnIyh=oS3MM#*`@PlT?s?E<4+TatXbY* -d~%e#eC|vfrorBES|ypT*DnT+^~n>6u(|^Jgt8zJcpc#SN=}&0eJ;UHdyNeypGP}_UwwVxn0_-Fq3A_B) -iR}068pUH3{(1FG+@~5)zu7D0a-EVG8mdP>&6%6PPa6X0(Zp8g?zfcg{4pw-BZHbzU6S7S{ru&XE6eP -_TmbZniuJv2m5@pk2nz$Y5JUiqXZl-+cScIL*WR0DCBP+#RvZ>=U}43-<;b%f{UyT>*e1o<_HY@b^$l -aM&F?jqHo9T(vO!9Ahued8_wvPyHQS=RJrhL#xjeB)+F?(=?Uy)*egHs~8+B?r=o9j*_O2#)Am;r>JJZ?|^cE%J<8fs;r)m8 -rAhwKgyI>3~RZLYdCn1u3dBs7emH@S6?L^g0{lRWpgFnPKzk^vu{L$QhihEB-s>$g`|mu_0+A(D9w8J -yimK=@=g6yG3NaVho`Jec7F(rGvWiUf}PdN+$?y#_m28^Cm6FXg9VXd7bEe -;~!2!_&&9?CG#W5*gx#aL9)q5-}xA69GO^@Lw(6ap6!OVtvQATPnpcM?i-@rsCSY4w^i(+==gvn0!FY -V2EkNE`w&Lk_C;lj4=1XDA$pt?#(JTvw#JW$_-e9=ac=0!C9xybx5gp&Z(L>Y5alOTmvUnw#moExDSK -z+OenG(4iZ8ki!{BaL31O3;%Hd;{}4$yIajEX*ym`c0qs%oNLjg3sJA}c1^br>TPUW$(AHnG-f((stmL>?7lhbd@lhv=1^o0~aw)&DV6i^i9QH{u=2CR*c}@oAGoe9u}fV -SoT;FQjbE^w~g5=68e0PZd^clb}N9(E(GjNsI*h}e#IV}YWbaV7AfY4{)l6Zpk6xDO!QqT -&&?)#+MPWgk=50CY}OA5+tZRP<@;`CQd}x?27+m3*!`{t{Juo*F(^1)r{dUN09(t~5wKeF@D+A49b@smO?j%cJn@s$pl=HCbMkz_KTtl%FY -i$AJ;5@b|1#&Hl8X>1lhnOvB`QSXOjZqavAewBt&>f*J*FBurKnsY++rgIXP7NSq5n>i*S?aq?IT63u -7hOpK^r*xLUp-dR%YcNx!Pq=kAiGap^l|2k{Go@+xhL93w_ -Vk%!-!5ID0B00AHHzxZh5g?pI$HO@+2AzXhmXuihd>voj*C;ht%uh?2PxvX`HZ@X4*MoF2I4wyXL_Ft -&b4;`+4OARtB%?pEbmywbNn2o=AIZJz4?jgnQL*sT7sQ}nI8}z$C8@%1PstmMCi|p|2%$`=-&MdJ@|Y -5x)cSqAVAs#m@e4DKO8=;KKw+%{vwZqN0DCp{}t~P=bB$TURkCsMqa&sjm(IzXi~8GpXr%yX?(vId(u -4H- -re=SlXW|&&Zn}G*6Uoy_@S1q{;tH;l}G!o_KcR1EJOs^v{K+pDxv6%)@VDX-ttZ^pHgpjmf+7ju0QE& -%n;B?eY{U>s$lPIVQMV3)_hs8TVggw2=XooJJW}vX)BU4_Bq|f@!9x|b?Sd!ofO1@$zfX?f&EVvz3-* -d=%>-1i@^VmL8#0YW54@8&c>;Mrum3aQIBqR!>P9XCGxm0BJ#zvt -@6aWAK2mnY{22&IL`+u4S0040m0012T003}la4 -%nJZggdGZeeUMV{B -&&y04AEnl0%x`i~v1(&>Ic77k;@;TfqlzS#c{INjIx#lNtyx;(Tz%lx?3eTTi+69XF5isV)vL?v>Y;m -BLSL)7iV824i(-@I+}A9wXBWR*USA!cuS}^AEQJR}BDCjT8cm{zLRj{!wmJgM>##PQ&o$4)d_E$&hZXDAx7A_6vgC<+dM`2~y+{$S8B&i*(EzS%FY{0(hqi8r{k9sbA1iC1S*kDJ|wM_ -hquA&|E^OAcR^!J22Vi~$KZG6x4PW)I7OsrS9^)U!A*_{~qqeRWW=%G)_ -^n`^Efm)`%qdP98^)7_nZi~+J|MLu*n4|Q=zS!CNvaAYv7Nnkut%r`!grJ3!2}8nb}zh#LMwb>b%(wQ -lAdIqY=)zI&Q}%(cW7Mlu#cnBS0?U%YEWCDwt%~@paSd%y^Fy^SJX-*Z*3vU3i5!xb65g?SW;vQ#JtT -&0XK$=^+YzMg-H#ilyYpSfh@lnjhXOqL_DqqJRy~0xy6Y(sWTJD+#!unvS&l1W5EPawqZ|BS(WYxwD2 -)6lpi6Ci5bKp6(GWIgvcjck!;crN!W|bF(q#VEa11&OgAPFI-G3{~A -4(}TP1)QXZvi~e0X#Z}X5!Ce+ZL7y@Uq^Yt+dx{Ni)y -^RP@iE-EU%7J;KYrINy=lSC;;MY9`94`k8SJTww?#5hfQp)J)2e?Zg)()&t}Fe)jxW>G7aFx3G#2TN> -1jL|PGh)C}}BP3w(u2z{8P9FAs8P#b2kTqlkP*ue9075cY&IxLIEm@Nt#hpDzy1q2UN02B(6VzY~vm* -bj^j6{U(6Vxva9TMqs#Wx6O;At&R&}bqWnsW@LX(2p;zUFYztDGI<4r%EO>4i~*t2N)atwtIYIxc}&p -TU)+a#`3=*ecP4_^rPp={U+XdUzfttB^0z;Gd_d2ztFH8?gOjGa-{f?KmkFKie6N5ifTX$|?w|U>B%H -yS&P|@!rGUZdzx9;VYS7Fqy}Nb(nw~JNrp?BL$lGN?fJNrk{VFyK!)+3z+amY7>P1zW9mE{%iYhD -J7LhcMcQ~GhFI>O@PJ$-(eQfUZ(e`Kp*bY7uj$QY3X7w&0DHk*#e2Xx=Mu%k9Zrl8^gaS2GwjwXz4S@ -;*#MG^jwn`c7=ZmWu!Y~nTiycIiX19`KSsBYS9&nF&9B4tlMI>=2eY;VNwdy`j~JFD&ke3BO%mPrMF}{nfz8r;kTf^5^#a{xjUOqm -mnzU8nS7=$@w&w`BXYr2si!i`^Qh~yRF)T(3Ee%2(bsS_c!JX>N37a&BR4FJo+JFLQKZbaiu -IV{c?-b1rasJHcH^) -Cs2(4)K?ILc$QezkA+@BfYtJI3P#oNo3BNu(#g1{1=t)_$QF;hoBP)h>@6aWAK2mnY{22)4}DO|z?00 -1x#001HY003}la4%nJZggdGZeeUMV{dJ3VQyq|FJE72ZfSI1UoLQYomWe5<2De!2k?IwxChw_M=g3O5 -FiE81i=Pqn*iI#AqWgw8d*drQYEQ)y}!OQq-e`oC9T#M(wx`FZ>ZsLKA+Fd9z^jhwg`pMUPvwV7KBpJ -%9fUzM(EPb&gQH+JCjXotcN%#xtX0+)-Xnnu^vW<)Eem29`EWd-Anl=Lxhkyy62lhurOq&OEUL%FuqozB|W -)hdt#=!;kq-1muK(i*PI-owq9(9G@pTS%U+=37t! -{^7whsQT`pG%0jEY8QBH<1FwAcH`51^KdlyBgzm2V&5x?MM7zeZLHq6EV+;_h1s2 -D~Rcw~eRy2XDwX|X}=L$#p7F$Pab=O=^fjj~^990SJdBe2HeyV~p~$M21@Pc)9j=k-t&c-K_UL2S$@Q -DcaT8jI)2kdjq)&66=ue^C*r_G8(q#S7nl4b@M{1*XInb&0x=Zy+?flH2JJgIQ+-B?0PiVGQzbLi5F} -3{`62in>*1L(>yaqgkaIUDVU_n#{6KVK$oEAfb}^a2HDcyQ!r6YWk;_tg>sKj9{2k9i$t~2TGdA5&6m --*K{O$*e;)cjYm>eKYv4Qj#gBDY4RSPlOz8kqzd;{Y-9Q+D>x&zM$iTDlhGxs>~EfoW$c$usxngJBAC -7D>`8$dOI|J9^b^z@WglrA!$NCRG7(shzPxaiM`HL?$(Of2xP}_I{>Zf!R=5=oL{BFX>sv0SoH3aZM+ein2 -=xgP-_1%az%oT^zti{RA&^cIspic{s^a{)~IKSRTB{>XoC5;}K5uoX8)4=(9{!62Dgd-DrBH{R>b_0| -XQR000O8NLB_@3GMnhTL=IE9UTAw9{>OVaA|NaUukZ1WpZv|Y%gPPZEaz0WOFZLVPj}zE^v9xS#59QH -WL0GApe0-v5?f-%C4(T{2;^7is#CHRK$R<*g1l-TM2TI%U`9=Sd!^a@9%TDyeil?>~I_`NM?V{rmd*{oU -OtEB#o|Rx#elfui?9a4{jbtkrL$%*MT%uh(8w)>QojBUE5iYW+s${b;gSH2H=u7AekOUKDjMCArRvid -xNy{Z40>7X+Rtip3%bpz% -t1pQwJp<8TevxN-bi;kN4P9pETPaHmPTEW*C>){YacsPa;B@YLCAIZaXYVt6Ds5(gM1d<_Px_W#Z@|u -8>1M_fRhwaFxlCDTzmJ4ncLn3LtO3Cycxq*xv3J4#Z$%>68m08b|^d$Ji&f<6yPUHnr&tqK_!%0}YY9 -6Eei*atSGw*6Ok8~KK!E8}+R!})lVm%#CNNnR2rvuW8*6lpHqcyH5tQM&47RuYGCHaOo>lx8vNMg07x -;l(NFSY4Wcr=2Fj5YA7YO_8bR4bGou%PXrULz0tN>$iLe%r32}5ti79fFI$f3&SKyG=RHUOezh0x)73#?K4@2$Iz4#$#E7EY -~LY5u8n}u=>7H1UUJc$4~E&e%})R=&RqL43mqE*-E0w$6*g@aHgVP(sFS<^C$(vV$H)rrRJMZVQvk-t -+|pc@8=XV%1#N0@V6a`64|_EC=kh`L0-=HIak(G3L*1{aMolDv^AQJl0?V9jU4wWN6_B+7o}45|{gHd --c5bvj&5XF6?l&z(zQK=e*)+`|pE%G;L0##~WBC(e0Xsz%Dx8I$!gl-LiV;)os$(_>=G#H^@?Z)cC5> -82YvZ2H))(AT0&Gwa8h?%VN0L(;GOU|D_&23UOdDo0Zd?8zB)bbe=(#P^(I7qLhBZbKU-;{eF4qqz8! -qotLO+pdYf1ml}-v#6A67rNVodV{t^8RgdwB1io?v5i6tX}c(QKFLa2LZXwPtHS -5jHfxX@`Vm^UwL@j6Vn&`ve0w=l3OW)>z>xv>O}AM>pASv%zwYmEO<;g2EW-iMe|0!~D@Ow~&SkAS%F -0Q*3?;DG!iJMl*C>x1;+ont4)Qh{-5BqHfFlNE0a|Wr+EWqFC=-^FqZ -nB1`)ZoO?#uTYG=PRCn;enXkM+_G(D9>m+8-v#?P6WVZi#Z{wddwk78dO2)Sd>8PaZR3KdIQ!MCiW`W -8oHNGS6R?CE=Y|8VkiQ}4-&s-n_cn-!!@BzP~!R;)Nc-kNP`c%E}-xVc8dfjdUlH-S|nE$T>YMyq8cI -5!w+upP0)?RkU1oKc4W4P66gv)@jwY+Hm|DwbT*Br=zCC3z#G2^rz>i#Ga)j)E!5a%On2qzv!|mFwLK -d=cjjd$2ok!O@r21LXcO@Z^tAeX?8XYg@n|?F4+!jx;;a){Fk=xaNd}nuldJs$Z)-V4#29gp45bla4m -lT7S<#BaD70(HyCcO||RvM40T->*F+Lv=;G)R`f!L(fY|8fX|Hzhx=wDAsPcQgj+8ftYvkTWnRw}z2q3dSONC&4x*!#tQ> -0{sAuxN(?EU~6Xv$?l*Mc2v9fYX{S2?OVaA|NaUukZ1WpZv|Y%gPPZEaz0WOFZLXk}w-E^v9RlwFJBFcgOG1^>fA7-*qe_ -F9;QMdohU1!d<(q{Q^JW=)f9K4$RW?@4VnIu0^0K`_nvdh?vqiq2^3LF%>@s+~?6t2@xf8)hAXI9gwr -4Cn@f4bu==x -DJgrtYL$yK6ywJ*(e208LhGx?V(CW`B!}y-HSUL2?aBh)#Obt~`PI*a(lvtBrezRckLb|dOj*q3@te{ -jncoTXk5iMGH92u7_`se;Et187htg1ZvO($G3=U@>v4tTQRKc63U&StY0w4yn{Nf`{H9qiaE0%0};U@ -H-7G^lD+T%ao{GM0!*f+Kg*(;q><9*os3tf}u2-6nCau>l)Y=1?{T3=Z>QA_`!(rKi~cHBG`Mhi^Yfn -xBv1aizE+&J{tZsNmL-h`Z#o{G5p}$KZl)sTwJ`kAwL5zN=ZX&r>Olwm_BtBKJLd(mE!cpS|LGMbfDi -WlwUg)7VWp_*@3Y5-0M9q`+nHRk^s*!O7m6`~E*Tpr6HmL0F9Y0^W9l??5nnfa -c{e5#I^e)DvC0~qkkQ#Rk`z&F~SbT7uJGezN&JYlhboOH((ii -IL+7^AV>iFF}TTnW@a=c(O`=w!P^&VA9!BIPcqPfa%);N8X{{v7<0|XQR000O8NLB_@K3(E_=mP)%y$ -b*UBme*aaA|NaUukZ1WpZv|Y%gPPZEaz0WOFZLZ*6dFWprt8ZZ2?ntyXPs+cpsXZovQH;2My$T57$I2 -2>z*Js?r=zN5LFQ8lz!9(UnjC%K>Btew!b|H@|m3gszR!6E(aXr)N(QZNC8;4r=gVGhbh>t~YqeaX0`R783Aa&5Apr907s`HJI(xqT{ii>!GpNi`CUv-- -fYmmcd`k^{0(L8Xu4K^5&Pj(`f{^w{7*#Fz4r5!5`Q2A8D;FSHZ=X>t)5_!k@x;3cr4M7n8?#JZB6XX -!vkC)$`Iz0&WU1Ny3~daDVGE07o6IQVpq^l;j=Gxl3{$8I?1L7IQ3(LIzK%h$Te&(-aC4#^7E=h5TF+ -@jji5?R$b?AdvkRxNov<+Xb{c1;=?_rI+&Js_9*u`4@rf#Pn -)hh+%2qo9fVvMDYZY5Jq+nlgs#ylGteb-OFl6#3R-htX_23jMb+92qp{HNG55R}Qat -nLsG -ExYAwC4L9G?E)%%nB=llAs>QnYC$Rwzm|Y4;WWl1=Z|Gd{*a8gZB^F%VsZN&Q@;?RcxFiE<^>=8r7Lv~ay^5uX -%4$wD#&!fKAvv51(l5!V7x5v@04=871$p*-nH~UP)h>@6aWAK2mnY{22-VBpLFjD000am001Wd003}l -a4%nJZggdGZeeUMV{dJ3VQyq|FJo_RW@%@2a$$67Z*DGddA%CjZreEay+HqgqoS|`$U?i1#(02kn(YR -gnFL8Q^WZfE*`jT2Wl2j)NsS=?zUS~Fku>F`2)cfVEVWlgom)F}Z5mqOP*??HdKz6it#ARZAJXP1a?RtTIm1b- -mwbRjw(V$;VL~-ezsb0V}6mUK-p) -Iv`;MM=3@{RV(|A9=T>-`7;gp+D<&(VR0@GcS1879~%VZZrmLK&v)|wFM!TD{1s3(0fAFga7F -=#x{z2PjT!kuCC)usIRPou>mqAuP9BPOM^H!_oFn+H0>_29z|qTHB>?X5@fKCS%!VqDvC3&$SRb5e1Z^(4oamr%2Dt#b<>6C+Ikc?5%z=3EUlZ@OKtnJWYkpivYv99)DdS3By0 -%XB!Hw5>AN2M#It`(yweFt`ULayL7dnh=Cy~>j8>l}2p&ZKwjvZkRG&=SaPEiQO)x!vj@X#vMsSGI{^ -dh)i|RyCt3qyOy+xZcC@!OXuht&WbPZO#X4#ov4M60-Oex0u$#Pk&nq8+;CCF`Y`&A-~G&w8`2XEZ~z -q(>OX9nxXe`IIiG`VOZnP!r)#+SJ>H+3_-Xg%kxx%@sQJU6Orj}KV -N*kx*-z}CDSABGgf3PbjJccttBAl`y!`#;$TL@V`SRJ%Vj9N)-OZ3Ci2lqL8dJ@!k9Gwk(Jyl&dD803 -?#)5yrui;12E`|1$9*(Ca>lbo!!qRuKaW!MXdR0%we?kGlwfbow;?#7@F-fLH$`?MH$GF0s;+d6|?D< -)m;;Qh;4C1W>jHaC89}8RBV~4A`(&o+j5!l7QAIk5pSTjF~ZFbQc6h~hv@xiGZ|p04rX#=yia9fbYu~ -r%WJS2(hL+&sSH0ZBm`y+h*cEEQWt~|AY6gSZCyYSjy0%w@X`~p*kVFz=9rf!Qy=fhX9^YI9tr?uD#M -zJNhn&3X?R_HSc-R0_Go#|?1RYKFriqSdID+i2ZeMGC6nBYgztHT;k2P_Q?q>%#2%cO1j&Eu0+bJRDa -}K@brds&8}gNgz3R3XJl2^rHIqI#b0 -2zyfn^>lyn&hnqGXP2Le%oz%^EF5J=R~c_>=xIlvng(Fn%v#nnU(zZxH4~BfoP3;l-NS@) -vIxtdLGAs}5vR<7^gDPoM0V_Zg=j!sP*s3Ppo(lDv;_`UIJDp>)}a-*6R4-~LI*YKnjfj5d_7w#YMK< -mL;Mq~3JTnN{=o`~$IhxUxF?_jOM5T^SJme1DGc88`FjQ%4MZ&_b+Ppd4l%~eNBP8#dx1MF1-Bm!vzI -K+eYpbZh~*HdTLN;q3w&JJ_2KJyi|uoISmZs6WFdo>VD)dO(;+umbeR||hiCWHcK*;}b*OKDnhNE3V? ->D_&g7B&>U$Ye$JO{Nmt;Xad8;N6ImYo}erYeR04 -;W#Z8AE>W$VDqdSbg6&!p6i=;A4J+Ty&5ly;#rsOe!v04Wk^nkp@wLtk1G#4xeQL<@%OWL~k0C*Ata8>^}5j9}FC2QkGkwBBc<9oONtF|2}585Aq!60us -FEPiHsRzFuGuM>a@AnlR4jk)GqBV>qsNN=srsCz+@NObqjRj@ch67EsvgWVnsTb@8VT0Y -0>uTwh$Lk3c@@pebWv^yHb%`fCkE#V2fg3iOJouD${sclnC4u12lmN`#xyfm6NxOV?Rhh6^=3ljrgDu?E^1Akh3;K8-fFC(CYO -@M?~K+f&8}*?&aCdxGDD$>URSjGbVGowd+5%MJh`k0&NZQ*2~cX&a6yV0_N@O$psFJc3itaA+wEyY2^#XJU7`7n*50Tq~pJ?p*v7mnMX( -kO&OXZ$oa4h=1BY&YD*Jy^Du7qBY;b3%_4QkycM0AXxdZg~wO74eoz2b30Pu&g#!(-1o*Z*)ZGCk7EJ -{P;IFh}&Kwf7^}CCxxJjEes;Xm|L@7e^9MbSA-(FP+e7aH0NnL5|&w805^OP6cP77I3|pWgB{`qoOh# -5#ygPSV|+X;hl*>AioL*n9!h@6aWAK2mnY -{22*vmc?!D-006@p0018V003}la4%nJZggdGZeeUMV{dJ3VQyq|FJxt6b!RScd5sxcZ`-!|y+Hp1=b? -}UxI+7C%mun6#W_IM^(@I=vVfo^%H}GG8c8KJg8cXMeY{ANd|CXE(ByZ&lNL=Ul_9k(Sk2$Q5#j50E8 -6YwUFu<}_pq*%Y>4bk$CT#8pZv+{o`*xT@3;;pzsa(%`7LaXr$9a&e{T0naw!V4B-cX2-`_hUWXtNeZ -w9uV=yLkV+fph|BihLeu8gQeAo#T7iXQ>%Sn-{qV)-Li8dwAbrw7w+LH#MR4>STKrIn~Tr50Fp6b)xA -?8r^DhAR+1FX}<0qA8`-N}qzvHw;)8vT0ab2DA(J^(4+nHefXDJEw-JEjP5=o84*Aa&4IDHLxs4SKZu -QTwLAU9LJGuCAPh?3Xc*-n@7iN$kc7!!{%DKasDp<*T=E2z(s%T(p%;lX -rSW-sxmX5Y=PNX+t(q5Vq!M32VaiEKPvVr|_#Jb8ypbs|%=kh>+unLwOQr7g;sUJWKpUswap6dK}>p= -~F1q4EL!<%@0Ex);Vo3x9_d#;Ln3+5&?D$pTYkTx+=`iZ}8Rs!F>DXjX92DPD;mL@J{ -D3RaMHsc4J3FOdvpKG;@g5h+U=EOU$obIwla)?U`5js;J_{#5+e61MXbQ)(KjeWPf#GT! -0X%R+l&8zG+=_xNLfSm)PxnLXLY?NvV}k0_bpXi%U%^jaDeG2EY>6$NhDFgO$A9Nw36U3N?nzsG|H7K -iTmAiMCc_>i)}48tcGxi_Us5S+v1PBUVj)8C-OVEj2WZSh}|-lJDYmfr?oI^<$2ko=9k -{jtD8g4!<>;lWFv_ZrX!#M_}I26epO=A+qQA2xK{(AR?`wOngj@>2oMIML4WV&sB=bL%Z2*PsXDHsVQ -)37{qyFwSS+CX60_qze+Job2oAn9GpHV~H(yS9A} -hVt?1=`2aFp&uoG9ce4kCy6Vn>xP0436UjJ>;t{$=8eo(gL;!WJe^`^-9Trhr~(nO%+~FhkuV3FotW=lIZ3|0WX#nwY^zg$$yxbJ=3GU9p|xlPR>zMYf*zAw5O(x~t5Kkv4P;Q$35czSss*Z~ij1P}I=jj0GR)BqiiQUW?)e}gQIic9<0 -lb1>_ow7}j_{HV^F*V!NE~jQ(2s;I6reTWyga`Qfn9?q-LS=wEGetU6hRx>!(-}e -}G0}r)_?r~r>eGjmC3f2jg2Kw20W0~% -dfwV04+9gQDI!3(?0xeda0z(_g>_4Q@g?TdaN;hQaB2Fd7s~dm$DxEc2#jC|ChAdB&FgC3Rq!)Duwm> -?yT=3>pW<*sM+s#2?WBSk1b>Z3p<5;UF8#11uR--mf$=srAyh#1t>wKWv;GJZgu>d5&#Cvr+zrEY>|d -AJPfWECHM2^zxZS~(c6f}`?o!)u*1GGnb(eiVBa0d4rL=L`V+}$gw#2gDNat6Jj*8)%2NDN+8eBs!1( -Z3p67FoG2895=;I`q)-gLdOxS{FF%JB*UHxN;CO2v+~5I-mmP(T?)!Se_zwtn>Zg^#~}Hi68aJt?Ny2 -`qef8?mBqXW;n{Ui1cMbdNG_oWTN#AQo6(8{QTYD}cv7JUA;Yfa8@DmIfdB=A;hKPEniMJ#jxRAPIc` -f-1$!i29k+$y3A`!J&Q_EE`_d@O6%H?5Q>G*Adx8f$9|`04M1j`3WVrzn!ER5cR89;9g!iMwftfbpME<=a-fPh@6aWAK2mnY{22&DR+y{7RB0fd@QLyU0@1WJ3I)=8rp@h*C)KP@b0!QZ -L3vtm7PyLCi8`4S`V?n6umqtUeSzFiwFQ&ct*N9qDXidYUdY{!iZV$54PP6kUNbgWfDDp}U81p?-QaERkyoUZLDANeo?y=E`CkC&_nvgem+Lk= -|GI}O&kHU9Po_sV`4((OXpQh<4RVy{p*136=rnmb-$3eS4%gjfCwE2IY-^b4?{;}tdP%B|WXj$f7BGJ -G%3$nT=e@Ov%K`kNnd)tyMqfQ5jWN1@qf&Z|ovFvoRSX?F>V|lUgx?#MurG2raka-F9RE*Sea$Y=Am`xPI%0*14H*zA=4oZ -8x(E0$t3odM%np4rdPo0ESVh+R%}C(yhVZgbhe0uMtDT{SujS+)u<=-ppC>`mv>*|;E8m(O|AQoZ#-MaHD@)8$_Eq=0F@e> -Y*XE$3gGLdtz!l68YCL< -M9mUxDjbq1-q^w7We5?&rAdhGh%s)Yy?*BTj94Xm+s4Cc)G5iS#NeC|)r6wcUad30Ane^W?=bIO38)) -#J4{ImQ)*cvzTEamMMOHFDq?F6y=feA(rmbkxpKwV?3f{Uj0#LK~ZqDjen8tuNZVBTkCN>&X23L6tZI -GyguJj;zT>pC+8g+h=yZyPm4c`1<2L1$!C6OBB9+Gs%g|(4<@UE!7r6d|OGTJ(7cgOh`kbS>md6;^hk -hoXtWa%qG-stHA{W?=BdQGPBip#z!4z%xHtNRo^#*r4RZt1Z$)RcLeN215hrDVr&A##A$b(>o>ow$7* ->=_C$foqUVcptaC2&K29PNm0WhL4k!F}{^Os@HC}16Kk%Y;27la9_6N9iUrw+J5N6@w0vFB$_`PN0tZ -Q>L*&>UreK~GWMGT`^Ji;8dookci1vtw}k2Gr7gUuwjhr|lJ%`;a-L -2rA!0&Y5^Y^^r{pJ}(Z%qN_QrYY=4;j*FPl>TfYMU05uB$03ZMW0B~t=FJEbHbY*gGVQepBZ*6U1Ze(*WW^! -d^dSxzfd97AUZ`?Kzz8mm=AQmX3MORAC3#b>z35pg?0XMn0hQO6(wTvl}u$ -P?qhMaF+6s^(LF?__!i@nt?)5aNY5ts;)cU*Q5h3?S^)kM)B0^Q}sATq+_rBDv6;xezKh+0)!lTD!&K -BbxOI6_(Jw&kjhu&c0q5`&Jr4hdBQM$FCItE=mqn?;N^V0nLyd~X5%8yyU*MNH>}#GEc>xQpuOYAJT5 -xo^<>{_^@=`Pc8SZ&<-TC4^2kEJ1Lcaav3CtD0D{V%ItFs}BbNnSA!p%Zo~KME0t`z~FB>{9kV`FBpB -R)hhgW(>c@8EfhH}CDhFD>Yg{=dBrUJ+X)LTD2HsXZOdKm5AeWIk6U1pE<;#?a8?oP8QBAc!ifi9NdA -#f+Zt>>IX?XCkgSlK6S%b% -Q4Gk|aN>DbwG-&acNl81EtEH>y0%VdP^TrSAJPDyb4Wr!}`3*$?Rs%_di`^xJ%*)9g2efpf_p`)fgne -+Ers5Ex{_4B-ikCp6d$enV41Ef>!wY0X^Q)nie{|f^aJlP80*&hFMDQ^#$hu1>V|wD5*oR6t(}#dhuI(vt --ca6|nmahgdg>z?ibe(!@Czp9swbu3BJG3t1Vt%H!(4&S;o!zB%_g&>i1w%RWR@y@A1*b -uh*7)WnyL8?ajNBaW=j6)c4 -Y!(w|xKkD3;Qr3al=$LHn$P)h>@6aWAK2mnY{22--#i!bZ~006fJ0015U003}la4%nJZggdGZeeUMV{ -dJ3VQyq|FKA(NXfAMheN}C1+b|IR9>{+Xg<=~VvCm;Hl#;E3(n8YhOIL(qpKYzS#?HtPW@MYL<&qtCpzFc3c}ELGq0^J&Z#8+M(4bx)H`M7eUmC -jxr%FXvrIzH-hfD0hX(_<+2z}u7=~gHpX(>8?-9Gj5eF?_HLV!-PfzD&2INk)82~4P#5IU?9=79yX}| -z4ZFVFU8DK^_U`txKWzR7(h8H05E^*F^17E#CM7RgSYWERUGJlI6oMw%$R(}7-uSziG09tCEOC0vMc! -~@$TfNw!jHoP@?l%JOg#O&f*>;29k40_CR_A1$hy+Ca -aYP5E212{OpB>7Nj+#6b%roNTKk)18(`gfdNWLWWPZQCQc38-ndt1Bs%Z3s>lP@h)~izl8+AVf>27Mf -Kf@MfrVGHXOPcmcdvUGu?oPTih>1<*g#VzWOYGqm4v{DTkf9btyeVkXb~S(+=^B_O7VZin@VAZ>NZN} -8dym-i{2IIwGug)Y*rs9Iy`r8&LU$mxVQKv?;D%V>us)6L(^pu=4#06!5NncOxl`Y>@M5C|3tJ@y5;s -H%pq0`l>Sgc#xrM=BsrnYH?XFdP|!B;#wxA)F8+|tnN6m7(Y^HfNJ+@fI<$X^bywlZb^L>|`q5_$J7< -zGQ4*=_pg4Da>QkrDiur@e@IHAcKFA-bV@HW*jCHemqh(elDnlm-raXoMAr~9mSI=83)AVgmQ;R`>x;?Vy_vn0x4cx!>=KP -7=?cUP)h>@6aWAK2mnY{22+k$2sHBn005N)0015U003}la4%nJZggdGZeeUMV{dJ3VQyq|FKA_Ka4v9 -pbyH1?+dvGx2l5|8O0ff3({t$VB`oYhZ)tl8!Axw~p4RhG&3Ln+^uJf*c#_ynbuqT|o}QlMii`qdy%p -pTq_T!Qd>3tpZa%9*(x0rwhuM3*R|LmFOa7`) -#v%-fr(=@V!9mrO|HE;hD%#5I3I{t#A%ru(d-j9iGeedn{Cq?G#=x)CVI(WD0_t??u&q|X@i4%8uzCf8YJLmu?wqIn5+0s_Ctk>WQ{&|Qpr|OtZ+9a%Q#aAPp9=5{Q(k|**lxSQThh7>E{FKpkb~ -SOE{d)v+yv|=XuuOAG?w+CpuM`YoWp#0>$prJ~Z$R#_8aQpphBlCa?JOp}?yy@x8x|iBLk{k-pyAH7l -!YV{JTdVr=GwsOA+qR(Q|1G!l(m3!z-im|c~0`lmL>OAA>1j+j4-WIqP6vcB6y!N8XZYmtw=N|ZPq5K -g88g+hDg>|sp!j}8)&fBoBkC{5r2lI(|(I%U@72ohC3PHyOS&`IriyOdet)6K)8(h=o!5q|+tO9KQH0 -000807zB_Q#&kpAnFAG05}r>03QGV0B~t=FJEbHbY*gGVQepBZ*6U1Ze(*WX>Md?crI{xl~`?S+&B>a -9>{;tZ7FMm>ubL*=R!%_BT&+iw1s0?jACmyy4aE{$w`-x|K8D?SF*ji%YN9krJ2#pGp}0Oc3ddb@ZFB -G-Ra3z@D}k-by!G(sNMa6o1RFwsrDUE`mGOapP_R_1iooVhQ3g#GW4}mlr!99=sSal(-X(q(Jn9V39G -rtJ6zpieP(`7gaj%t@eA4EYX8G7X2?CnGAM%+;efnqsOPKNnwxXwG0I$!pJm0{7PH!OowJ(!`dje6JF -^={nWe(2m%v{W>A62$U46aE(DnDTvrpI8^Q=~^%q791y7io$0E)5(xPTNyHx1Uh!^@V>$|1ihV$Jg+o -Wh@k;37jGL6o33y(YQf>ND?IouNzGnf+OjRND>;HVvs17lQ*RyF2rX&oEjKl5(qG2kuL|`q?bba<_nB -qw&xuXq!7hwu4pIe)$qsi6E>Z^A2@l6c#(8%5JZ24>9!3EMA(mS!PDm0~dFogbZU3;JUUevs?f!oY+! -Xd4>l;6)AbIx?brJ)p-P16h5JHP~(ePOUjbrmXu|x=}u3o21{wf&p9%g#A3QSJwfnUEEe|RoXHN*K{` -rAYa#~WdrTXheaLET@kho-MCO46``AmpT^xk!&+AU`9del{(O*u=`w4eVwg}gC=~68LFK$!x<~_RLjI -0g<580S&^2kdOa}JbxL8kr){fTz+!+}X4m+lxBq=cmIsUXq`Ptx>dVj%in%)@wjLm3wP7jtsf>_grIw -{e(Z1?L1DExsd8P`T5=ksNqNNLvwxD2s`VYNn=(U}p-sB>_S3t>RPPW`T-htDona_p=Tq(K8bT8FDtP -T(ij#L=3#?hO&kxvoS#inHa>_Eu=^TAq#jt#^x@3BrjI>a2y1|?KgdvGKSIS5tu50gaZzofdHrs+2~@WoeQ41LOGKVSndHun|7pHkABK}d)|EFsZR#>^ -;7Od)0p#P<3<*uMTm_9Y*o}(*YM2VwVRznudvxmv*yihcz<xEHb(&8TB@r>gZ8?2j_Bu|SIjRTYeg<{BY%1%M+p+4U&OD|9vA{tjNV7oQScVg+n -m}ut)6c(FX?lmVG1gALs+6IQ}joH-i^wHz!ZWcybmPHe|V3WF2WEydT6BEJyaa1OVFaY?gC=h>khSyk -dLS7=^PU6Cx;;R{6Bjl_VX22H!RzXUHNf2F-Xw`&=-{0K9{0J#D27T`OhfTW;%{Lt&o$_^|B}!{4^i@ -&kwBA-WD(T_*o6t?6tX7ujeny8(kS^(5N6ZXblp1Qi6lMKPif^JP>1I@hbxbG_K0 -R?<1%eB6vV43($>UQR+mShO;ngZ;`!HO256Kar5$m?h(9({TQ{~d|jOYH68EJNU@*7Y~0|XQR000O8N -LB_@K9;td1RDSVQ*HnNApigXaA|NaUukZ1WpZv|Y%gPPZEaz0WOFZRZgX^DY-}!YdCfg*kKD$Q-wpUb -bSMbJL1wtN50?w}LgQpSo_|J>y;1v|oQ!$zScBcX{7-;{##7irvsx_4u>u`PW}cp_4~XNoT*puKD>GJ_Tt^U>`xc3-mK -W4^LpSywe1i4s=3xJU-mHHrsga5suKN*{kZR|w#i`@)qG#=lkAo^W!okDy!e=3L+=Cu5qgXwZ`!6R^1 -AvTo;CRmcRN=N%mG6tMPBR-h=18}UO&et;kI>UhQBFWf=bM_OvWa<(@p-7XMNsX^FG@j`d!=1cJBDkS -<&9ymDM8Iw%twM!#bP3Yim8gAL;3H`7qdBG6KSw09?h#akcJacA&iwg(Z2YHrv@{Xz#uQ&f%SnzHaQQUk8UEPD_A3_jzx4=jH1cKmH|5AhLZ4%u -L@hU;(qsBqK8S-H}1IRn5gg^!!E-&~wpecU{$^$bf;4fn2xO*Os7xHNS!2sT6||L -sxqcNu2=dP*3+=+w(%c!QnHYzG_=ZD$n4*y9y-OozPqgOW;{M^!uToEfBjX-x3oW!B{u{>mP-g?R}h@LB4EkZ-_J -mNE}_J+gX01tod@`lM%=V8lkATlqo@dMSjj|l;b;lHY&#Z3%dxMTE|bd;(Aiy3f(!Q=#qNaGXdUl|u3 -?c}O9ax$p8)Y`wG1s?BE6_{Av6M%GKi;|YpL)MMUniXdN8TfK?xy!o$G1W?9JiLOBSP2Z2KKj7tre`E -|zQ%$kvwpVq(t=;5OjMMECyl^LNOUe*->YLsyS4UV-YV&8t#zQpNoifPWYrxSEM}=nBsAuGoRB#&(M5 -t34o1v`h?pBz&P|I)X>c5?MgP`cRxjD|WZ5iXB35Ta{c6l{bv%;sAR6!1`9L=fHAk+t!>}st#XoxSol -ZiG@}9br66}AP<9R#-74t*X&Z6C|B$cLF9eUF4bPF3D;}WK1q_fq1K%(SOJjMla$kdW+NTR;NCUU}@6j^6&AW6Fcn3R~4|Sj7# -(A%Hyxymai3kE*x9krv)b|NnxIHAWKOFR^tlw1v%x&o2v^~g*eVv1p;Ge*{ApwBgezt8LNgRkGd~m@4-U_nNlCv|DK -VnQlG6*A3S~b=FN*|@1H&W=_fT2{1+VSFVfmeSp1H28?v%329yS57ZO0Y`sBmAi?`Vi&)!{xhr@Q;0o -Nj(j$|1HWGJzJO&MS)hy%yK9!b*z{nuMAsS3C}ugTs8TL57Q? -~x(1btS$)aKmH_HngfypN3_;673+Tpvw+6hz!nl3y|( -Pm|IN&)~xy=P(lfRRl!AiIcd -ih9I)Fhu7X?gf&)|ER1M&2*WQiD11u0=h*asCqQOmghAj)?@lt_$&Yr4oS2OlQL=Z*bWjLFKOry|Ig7 -~@4JD3c-D%jMpn%{BBld!YJ&~>0uKwBB7Kx=;{fVIUIXPBh{$9RYNu%Q7(5oj!ybL(+&jtg@agYQwM5 -EX*))RMIn97_UwAP7!{>X*|h=+=U-JFbuyCRJ*b%{Dq!3cS?=Fvscyq1v!&D=~!F%j=Hk^}ajYAtb(y2xPm{&lu7!^aVgElua^!6UraRKh~1~BwdT5~! -?D5=D^n8V{#L{&K$hubYj_Ax92rq*39EEwnQY`eRj?Iv%K!+-N&!n9PGLb>7rq0I8f_<&NOR-%aeb!J@Dgp$U -#ir&zriLz4`Q3M6tbPK=)}uLO58<#F^JtQaL3fqb|LmeJ^AJk<4~?eMUZcb1x7D!o`WvGD5qT9_XID^ -i)13;~0AI))vmFU6t2grHq>n|M04B*d0{@Mtjg}t -zwk+12$OjRjKE&L>^#Pv(AyNG+fibW^_vQJtV?efqM~~jqK$IerZjxXd(8Nk?~(Th?0O!SZ1P@AM3VqrjxJ~_XQWM+hE=9sS(1IiMAA!y&ePJffI`@!`t9^oN_{9NHj^*Ia -!gBxiA_KNrt06Y#FEgY&M#jI1%2PtV`%Sn*jSduDYED*;nP!XJnhFQab{$n3qKTQRD$g<- -Dc`4E-=wa2&r{?<%fuxE$3vNO=pT2i&jr0@?Wa;k}=>6LX*5tzgrZf^${pArr-;Y9zqf_hquYv&l_~wEycFc?UzK<4M21{tpWF|qLQJ9)NoBS`aQX|5ibMsWP5L6?2Mh?t!An<{f6GGSN=M)6;pHPRXq -Tg!dmIU45u2L{36i}5&`x<6iUR81W2ojOFy-XAJ@#Dwh6c=hR38Q^5)_VL-_{}G1-KCQ?|xI(){KRB3 -f*ZxMEmC;c=G~shNXNs>-#4P&33ND}r&3{;=ogO4kH+hom`g+klojORi70-Tnz}kAOPoeol^k%=w_tD -WQ%SmE0p`IYIvUiz-Aribcua+Nz1?7aU+r`~)5csOpcfsHVLm -GWy#fobb2V8=4e}uIATyaq!2mrNxTn0_hZ7^DPy3(NxxUQ;(D;bEWIOoc^57^5C*fG6R>7VF#VUMe9 -ULgE2|tq0RKQf>qwZplRR=KT4#Baw^b1us++!Q8uJoIno3KyY3L0=BU{}DxFZ*z<%4%%Sb}0%WB4c@w -mr<9eL3<3x_piKFpA=byjTa_tjByjHT!jI<^BY*>K*Bg;s92P(sg&(u7`5uoQ?H0tkW7Z2)I8^DCRso -63q@PEU-5TvmhXkdNYe&iCrhkQdvw{k@@N{OsBro`ynhfwmG~Cq%yI(3gfD{%UUF{-Cngric1{pJ7o~ -n`|UsX_wm1vTHE@z{?NpBf@hsfDgg-$s72fP0?wBd-DbgPxendqL%tcI%5ZS6U>h1Uj+Ds@kf40^~vQ -V?|Z}qh@p6aN_?^Or5xZ0x8u??eMlK{fyMn*GfojwhFEZvs>X>ta_qMWdzudLl>dTpVBIp>TVW<_Gf* -lF=a?}+Kmd7T%%>g$U~i+(`0dO3vpY(n5?@~e)|c{eFZA)>nOXL^5MgwQB;TXn((9UtR7)QpU5r#SA^ -kLC>zVffy2Xz+Iq)hd%+aaVrth1vtD_*=CiUK4Ho -*A&i15d?b^{l|A?)1�}&1|8SW^Y$v0p^p&dgQlquG#Kd|pp_U!~SU|p+|Y6T^SvQ}g? -dZyk47RTiwb9chkNhwwj(<%*21IB8?6|R?pSgAY15^as9{W+gT0_bogott;^(%;+Xs^Hp19p%?t=n7_Am3oY#Zh2oC5D9&2J&tK=ee5~S?R#$IUT2!qlFISjYq -X(CrdlFQ06~+Tbs7uu|2d0JwwhU9{<7b)`?J32!>tkVeG4MU~@<+S?DG@R$C^c$PfdW${VrAzFg1HMV*`|K1qCTP --DSm&n>BfJhy~tF()9xC0pgN&fey;~tGYa2e|r^zR)2JjLclhYgpIId0cdR@Is@-?1HCcl08??4a9x% -CQ5p&*F$jhuaV-2S-urbGPld@3NB|S|P8}-`RkYh-^6~R)i52(a3HY)xx{n9>6(IDPC?#rmrj8Q>_ -1pm`TuQ0Ed_qce#%>^lJ2JOIG=P3_nS$!=}(KLxro%jZ~=!z0zmD-e`i7+KuW>9}G%9oDO6$-jd% -q|ldQVECYoh4V6aWxy)wD1bgE649{b8SH^X7HT7)mP3j=H$f?jNKNn~V0S>b(@$l{16CCNx -1JnPP~%;b|~!CC%=u>}#L+H03U3%Y|M79>(bGRv}6mqZV|m12&2m&V>zlOt->-^e(@x@VHtf4`YS~Q> -S9odB<&wiCY}Yf?*`+c|r?FH|1;wQTg3B-+i;zZ=%N_^f)HX`P4rD$mJCqc~P`O6Ra+cWM+$7zRWJ~= -~(0#^!vx*)b_4k|M>pm98X;%EP@GekyttGYgObxS>Kf`V^tY?aYoW8*;^hLiY0Yhjl2d5%v!}j-lpjz -iK)$}mv-N)%WncPOlxW5*lxd2jf#oK%;j!BW7jY2vknvLx&ocl0mB}Py7 -o)g2z8GjX=RiZcw!rTmpJ;V(X|xVb?IHmcTds_W41E7r}LoJ;xQ5xJ`-X!!T{yHjdV_Gb}E_Unmd3(2 -9&W=6yJp6XXAhi+qI&U-rydZqc9u(&s$4sUFm9rp6V|Xs8jimdam|VnVXkxY;NU6;jYHb!oayc1|ZB$ -n{fcWD-WIieTQml_dL|({?53R!JQIi6v#P`eP?NB#L*NrI^Ac{;QT2qCuLwQ5m%z+zn#uMMq_qh`$#j -BbUoV2NuW+B*2i`fMdm&eW^M;*W!ai@9o7b%piDbCApJ8b)TSkYu{kZWa54-GaEIyj|wqO~dJ9A?{W_5a@q*>OUcWBiBO_+r#=;+E -od3oI0I7&fpO4WVeRsu~YS?dN=F@k)=k#x!7!^25I9=0@GgH^U9Eu^Pp)0U71qO9ixM_La~QBfM6muL -BHi)<>#Q!Z^#B#d)9^lKZDQrKt`In$M7hH5R+#L}){8uuP{DF=$6o5D0IQgaSB-p4&pl+d%#q&Ji|s6 -$Jv^=?~%M=Kj|ezO#8PS*@xyngn>tBZ_o8+`W?oY~VkpBFhikg&K^S5|@`IcY6-T<-H8Rh2yLh-zR8{ -0dbUdj2cjn}qTm^3X)7jpFZ!{gRHwPE(tKwCqD9p~8oY3M$RO3Gc&&8lBF|fZ`_2MK>R{&bp)w(sMQF -;M6DZyb}5oXgsErrqRPr<=N%P^I>G`wgqG17{mEWSua*75;W^e%KaI6yDmT%()I0YeL72D`hY=R7HY?(;V1SMQ~J7$XED?Cv`$ZqeI< -!>*On(sn{Jvh=krk>@$0N=TDw|_vWaBK82%d?bCQru5KPFbi%s>Yb@h?%V@6-y8AGe` -6_Xd$uE@|dN*zJqd6~?hIr?{f;KU%rLfq7AJzf_lEAez~o?jGquG|PZ&}4hKvWALe6o{u$0LwpzKsV7 --GED~oNj*1u8sj43U${B2wkQUCedsHSg?H-uJ}}>SL1nBu@U9i7qDEiBQq;(iV^7$B0T))f)cR7JPA+1tz>71(IkUCC^9~Rl(+V{2co`aZpk%!A=Lvhauj -sCEgMy~i=?3ENoG#en<9@}mie_mc;d1@$75i<d-_`+p$dF&Aqk%2>|(!W;Ocnl&mk^<$T^CQlAju -f3>C3x(m*ni9teBY;)zKxtLdB}`AdMX>mDO3y8Dg1`V&~}yWf2?#wyg`5hBcniR1N;7q8!2?=gE%M$z -Ql6FiUIHcR$BPPd$6G*3AH>E-M9=Tb{330Ph4dg-o^oa?~Mgsm?oX^eWoc3K-$ZWQHCB%H=9}*?fe8Z`=uaSNSBX8tK9X{M$WPv5-{lnX+`nne4l+0l+nGp7_b;B|`%G5 -5_oA{sfOJ?143Yt7Oan0Z>Z=1QY-O00;m`Rt8fCPxGfu3;+N+F8}}@0001RX>c!JX>N37a&BR4FJo_Q -ZDDR?b1!UZb963ndEFY@j@!8PJwX0}P!L!yJi_kl01nWdX464~P0*xU6oY|6TeQuLENMw9hda)p{xl{}CW>CEEXuBZq*l#22)@(uEk3$Rp)>NvePb|@a4^@53x~3P^K- -V`Exv56QTj@?()2{FMnzsCRR(EvIVr1UI(Qs0=Zn;OkI0`#tR%hjrOC?EaPL$Kk@9OCM -t3T_DS?oPiw4sVRjGw4ve*=pOz8X=01=%uHv+kCQzT2}-<*9&TT3Jbkd;(TI2)3CtDM53!><1Y^efAyc1lpx*ydr=EX3SAR;Izymi#}bg1 -`ZtGL<;MjP}-zKP@E{OJ<{pA-76R&)xpP{F@4VI(so)-9Ei)Clo!IPf(vF4bkX>C4nIb9*R$ilTVMZy -8ZLMw$SI^sA4cdP2#%$6zG=hOm1jDA{n=n0^`2CtU$4 -<9N(;b3J6XA1Q|R;X4-ZBK6?R*)e965zr39V3YB$Mp^bWwc|WiiDVcv|4b;6k0pyd6gx=8{RTVTI?Jg -Ksd?jx1tAsldM4!k}Q3Ky2@zz8quCU!7K?;v~=mR0?}XVYh|rdQeDptq_G#~KpWxZK~`~w^70`x;TL(76+oB=h~Nv_ZdB)Ayd>_y|%tB*Ec`L^o?t05 -hZ9R5Qpz6Ckoi;fLOyegf>lWZkc5`Hkf^6^+oKqhTXP@PT)K6TFx#vCV-%{sgbrA2x>=dyl8HkJrCQE%cfN%s-*oK*F{RQA667pU9G-jzDTh7Iyi12b|98*if1{jKSbdC;$t*9;aY30dvY77K_(e7Q+Kg#=`KoI7c$r-0c(hFB0261} -d;Ljq(`0H*80Awv7ivuC<^lw4%q^XIi*0J6ya3dY&_D~rjNTTAQ!Zy9Dr`uFiqH9B5ipgCc^WU$#5`< -2>($8HrjF;|GA6ztR-$ve;Xs1Y3>M*VsU^bpHJY2_IcxfH0n;G#WOOpNnZ4-%jn5!B-c&t=ISfd;bFk -}&qazQD`t`H`SjMw|wbsX#mT@oA(*BPu@eCw@u>^8Oe^)=y?uIp{@F7EH0wCt{RE{E*MPvLjJHaPzb9 -h!7aT);rB2`;nJ@*w{JC?}=Q={l&n>cO6N5mRj#y=Bw5+Rq#?;JDeZer}pBQ8b77Jgxlzk>PmT00W&R -Ny{*=Q_bU1v%t;>1+H!%FYIprd&O&9JC_k*>o{Od2lQU2(Lju|xD>pf4>BL9yA6A@NEE&@T>RXm>e-kyf -}VCeu3^WHj6o|0MSU{awe22{jmYN@PDuE8h^vq~$++bkF!o*7Ses-d>;VozzYb$1!xPMyrLO -?LL4;6U>&8E1+`0;r5hNJ))bUYWWUF{F7TRjw1`wcwhfXpoZ$v$L~QUKR -%L@BR6`OFzDZn~(wAzjoR&tpkjx~SM;zdHdpY9X!P`1b-FF27g4l;bu9~=OmA8?Xn8_WeJjhN-15mYA($3tz`m>hDDJSnU-F_Nm{MJahLsH%PhP2?~4Fi76qXF$0xU`4-*-2b$Lwdb~dK|@Vn*2itK5#QUu> -1ph5G^|X4|Ic00+%YUV69y}f&-K@$fv01JK>Vw$VuGO)T?YiavivgR*eo6JNVdnz;|X?zT9w=ID#2Zm -Jxa~H(4rvK8kX)(?_6zOjm-gNqPj7+&wq`yyWhK69ibV;b?pe9m9Hs|LXXr@%Px&^FxZ@5@`Qm -6v-TG9PgjT@q-B_4|%}kmH(x^a{7fU=m}p?YbeYj|rd7-+euZu{sbV=XR^daeI=)}VddeFzAqk^*@+d0&*o1))IW=LHQ*5du3Gu^%a+Hq>M^Q -A)-Hx&L2se-g;f$FE$vk9WFjAk!lxT> -V0%&51sL!lV!QTsvX}GuDxY@*8FEgq^Va)sJG681l6;z6^C|+0y;0p*Dq{4y*ip9jx`S@9`UYU6#FgN -lK@RF31iHqN{_!Mk2Mv{%qrQqG|Uu!c&fo6Djxhp+Z{6GA&QuXB=Jd@l_8a+>0go@rd7q?}n7cbGckT -m!y0y=eP|(LkN0zEVCVa!gkZ5<6y5$K~14g1a^+A1BRmG9;;gYlqNYfIxTPmgw6QC{PPj!t)E63dV}4 -S`GwiFbB|z&c09_S5wj}ReWZ0>y*oH3chJuW55(*v& -L9qrDRcF@LkIaoN-18%KB+M!$RW$k5Gq)VSDa8r@mrdq-IM9?e#8sN?R(1t~~Tee8KxLbfe!Lb*RDv$ -Glb3%R%4&F2w67*bGrbwo`>Pq_y`+c#j)`k9CI&h2Wd-^KPMc>^zCva`A{>-h*f*i@tLd8Y+j}U~g^ipfx16Rj&BLfc0J`>^7O`Qb{U_7x=&L9A0#xl=fu~;7H`T@tp -5mXudBCsYzaJw_I$WKH>IV?JCXl=JlZJXU*>Qoup;GaKF!Gxk^_#XF@-HvXRA}tcpBmE6od`h$Fj_Yb -M$H4PSYpqSPgoig}7ZXZNFOJ1hgEfecPr -X^i{rg*aSmPrM4UZ7P>m3_$EZdV2unn{q1M@v6ZAX^ptJr!#&$s*$oFx1Rx@S|Ov}~4C1woOAVAWw#O% -2c&u(w2QcxWcc%;#(h5jr<(ah9R*EK88?=@VDm#N-sWAmBz;%nJoX -61rYzPDHF&zDdaB6}c<~YdIU&)79P(sdt#s)jk~*$etH%SZeh0EQaOv>zdP@JsiOq@5Tt`d(4mD@J_jE5ngS`LPk5rwvd-J?m$;Z*H<6Gs;uKnGdmBD+Su3d;!r3k>265| -R{;=LMN1h(GFRR*ge=QY%hl -q;(BAx?tx_hi_fis_owdy4jFoMakalbYTT --otY+`GYQ4`S{C<*Hg~NjY3n`&Zg;pt!5*Uz5f;#BN*q`tS4aKI5ta(s&H>xV1G9cJB>`p__#Jf{`e@m7Nc(WJV@9`~5e#^^0`)Y{4 -}{t+DC)kIr{ph2?kLo|de6#f`YVT8p}o`=E0|Vb#pELAf~BAt6hYsGeZUuRSV5sNLKg&T7rA3(MFlit -mIg=gs;8uJL+{)Gqt^T$J6Gd)0B!^=B&auLK$zj`!eV{dn|A!R$9{{#&+3lCy+)lPiH!%9VD|z2{uJq -Fc2K=q>~|N)f`@tNqt@pn{u=;wD@Wba5Rs1-P%Yf^GN3!QvN~7ntClVrfyuOE?+YdGe8)jR!Ys04mtAjfZ1d`&60f5!E;{@Rp$jry~@D` -O~Cxb1&%u({ZOQhdaCbzHHxC;^^#he)IbL{PfL~JXa*PTnS9EZFxb79l+Z+1bHKDj8+Z_4n@E;37>R!-F2K>SoX#h*z8=Ay&$E%q1f-47DbA?AoJU;p4Kv#kySVgIn-$sWF};% -N%7VGEt%|(b3p>nB>t8e$AaLo1Pe^tph(+{YbZiX5Yqvk`!qAMr}y!q>%yFgxK;ZT^1> -~3YYC8GZpBRz8Iwgc0fr<9RnTdgO(Xk9Uqk-ihJ-iVsD(Wna?-DfUpYsoVFg!$;gVs(40j!#ym@y;XGn)R_=$v6u)BMBs*3NBw*wGIQl3eh --L(T-;ua~#uwy=BuW1%czAsuw5Zb{jj%d?o9F=-jwF7tYsaJ=X5em!9M|-rXV38nUVm^pk1YZHJ3yzD -p!~oQ-|T4v70g`;-V2Un`Kd79I5zht3e_5dL+B3t$YhEKJWM-%8ME9Ij|og!vrgFu!~O$MO9KQH0000 -807zB_Q^^?GN&X1{01zMm03HAU0B~t=FJEbHbY*gGVQepBZ*6U1Ze(*Wb7*gOE^v9hSzC|WxD|dMVEz -N)BCwRoLefXK3b38cwAoE3!Ay4d!7yZ6qHQ&@s8Et8-o^g+o^wb_)WzNuC~5>_i{iQPTtA*<$5N`ACD -rNnCey!jx!-5SzI`rveaN%z?afZfBa>xaa#aat-u}$k`aAu2k*2D7-Bdu8idN>^$Hxzk0ekxC?(Xf=(_97R!2a-$Q6$E->$zh{-zB9={EHZ`6Y-6Rx?tiM8F|DM*on9LH#KJL4{NpfCQ?CBt%&Cxyc?Js -X{7<^{4nf`%$SXS($I&##R@hu2svJgxvc9aU-UVwe_T%=69M^quoK+1i3}?sz!xt -&~QvlF%sSLyb^f+q*-sc`OFW3&gQTvj2F3RRnv#(O23(t8# -3ZQ;9?R82t^44AR!(o}+gakYmhO!*Z=|C($JaqXBm+p$8{dSm~1I;g{Et_lcgZ%%o)WFK<@*~B0cPFX -4#wMHY{ERZJzz2@4bxh_3 -n{Z;p9Ofm^Y8tN;Q-nVxj9>1scUVSz^bp2&igDTopfe&-=_en6|g0%(pV<~twfnDc-Js&_EzA-M;g1& -{5%~mBPzyJ~M!;Vb_U2S1AtrOQOy@U$IkIWeHBc2mhAWfm*X)VXrpv_^AUK@K%F82FH|DZkXUCk{+op -BHfXwO7@2WqYrs(0N(QQATiVA%hF-8Rd!`plj)P@p;=^Q`y`nO`5EQKk|Oj-{l561Um#ZG~3!{LKa`o -94FJpynZ1Smq~zuL1_Bf&sVyTF~=Zs?VBv*&cCeb$K1KU&wcx4JiqX!DeU#qS$Q05E&|QlqaFB@}=Q9 -<44&P+Em1_Ejol(HXF3tX7g99g!Ta&zc`jPgbRsayet9CAt=;h$X|c~j4}TbvL7JbNND|Ry^x<>WPm? -(?2+~ip&b2My;`#fumZq*qNg95hc;K|28KAbqIYVI{Vt$wuZ1z4>Jj^`^ -Ce0R+dD?A+axY_TM$^`3MvY$LnvV??rH0pNcvrWkqe0x!i&}D2IJu$pZF4@0lq|H;s~w*6{Zj%6N$CP -ff*~>ZwUide%>SXuUV<%CU9l@m>jr6CrD=jBgZHWn~X#!0fxxTgq;UWk=qVRMY?1!Dg?#wFZ?&8wP)D -)J?I#tXLMM=yEfRpq)`eSM21|Bu1^&8Z4Nk!nIu~cFf@A6qKwrH;m>T1^vETM3*8+NLq}5bV!(&|V<{E0a*js!}L|L2(Bl28d+{e|tJp-o){0ZVUVvg?J -#bBdPy_8(QK8M~>N#NMjf$<3&(J7*ZD&RITO4=L3E-}bX9z2}qSnxp(b|Jxb*!qf)Bnk;Q-$$=WMU1{ -py!ojlalJ~zzm-Sgy7rENoSTCi@EI-cQo+?MKInjyJmATskjeGbz6nlVWl0637 -|3j$pCLyPRkZBn|oT#a$6tWj53R~_Mc56)Vj9|hn7^bAgvC#^Cg)QoWhik2SJJXXY|JLT~n@SAk+S8&cT0&4A>eu)M( -aNg_SS8IXKOi&ysR!OtYsf?iG1n(5Gh?7d!{q;OL?avy?;M2Yn5Z%}3REpTe2*t=aUFI@iuJJ_<5#wF -WInRhoh94oeKgjn$R@Ybj=f_4OC|103yL((Cc&Y_FM@9ikHqciz)nWUXAJ2YnPBGF?ze)I<+nv1pW@--kR-CA_BOJ?$832lS+q1~$`>X~O!vK*Ud>EbJJbE;pn5+)&^IsIpcOfa5gwz8AnY+ZGrrzHC2T)4`1QY-O00;m`Rt8hC&51vy1ONd14FCWm0001RX>c!JX>N37a&BR4FJ -o_QZDDR?b1!vnX>N0LVQg$JaCxOyZExE)5dIz@|KVVukObI7KL=I5r2SB=8wO+@Fa&|jNGF@9L~0~u$ -1D2Zcck7eDH}E;u`Tl6_}s(0vnVU2Efnf-5b|()lWSFis%*uzK@iRE@4Tqdw43%)kz}{^MHqW~({5Fw -V#x_*rZlT~`i(oAthS;soqWork|O1W_zM%sOPneTX;DjFu(S~Dg&Ry#RhC?4o&H1fxT>S^&uf)OG)5@ -dYW^%%+sR$Hzq-d`+>ko58UC+%9D{x@(TN*=(9Gy -*4zAM8lkEw?)B%Fu-351goI#B}-*&2M}h1BK#!PS;8p4T;pA5ZU?{C8X=<_(NMnA8<{!_dxZVIy4a(V -V9?eTt1g|ueow?aiuBkR1SpW75MJ;|=z&yFqU9O4+=ZJVWuv5ok_xwwi-J6zks|2bu`aO3REx^OS@Wt -wJr3yQvJg&&CoEL8-?I^z&DYw{i70nHz5wqi`3HDX4J6O-p*{CKFviw|b{am6>Fwk98Y5>J=D@QoX|+ -OwMIOQK9)3|0?>f@}Zk?s27c^|p2nP}O3U)f!()(`YIM_~Q=!)Ao7)N$3!Bb~C4jhy+o9pMiE^Pete6 -`_Hcj7t@+(ECkj#yN2Fi_R~+anGPDu`5+Eg}8#K~Rx}34FoSU~^vQiUIs~B$hXbxcWGVpTF6Er#zuhJ6QvE0vBBK8Pu5u9L*eKC*B!_u71xCvudH@5>#$(;yC#SeL6ti -acbTAlH*Wvja5+sQWDWigNZd@GtJ+Fj!=*<-pQ*5uFV^8 -T4|@Tkojua*(kAO`nk={Nr>EA%b%GP>7iBQ^I5iK#Uf>?y|6}Ex1+qZ5nGAE)NZ4=!!@`f6aO6 -+Ze5d8`)8%haO9KQH0000807zB_Q$0`|b|VJ>0Noe>03QGV0B~t=FJEbHbY*gGVQepBZ*6U1Ze(*WcW -7m0Y%XwlwOH$GBR3HL9?1Wo`Z%%%dvpCzTEgv7?ga;>h349R2w_on$F>?-+LN@-xqp2}uYJfHb9U)Mo -Ly;tqtU!HBerd%GK9Z!isA!v -Kd1*sUtC3v|Ix@Tc{O3UOqiCaO^$04W*I-K3L*w -)$3u{`PZ<($l8iZ~Ylr>WeBBa_<&i;Y2p=NW0fq`vfA(6>v{CCmpR(?Xup;_xj(h&ajb&vi=oZRyZs{&BDo(WyKIZY+p+n4XE-wf^v)RnQytPYv6rrlxu -pPPpN<#LsRb-%CO{}NY(155xR19=(SG7DmnjwYTmsvJw2D%2zXG_h(A?0cXN)vHq2y^G*>Yqn!`OSvcOweC#lUt4W4MQ>F?UN%au$z8}I_vH1!ltedBu@wXLhU9tv9Av3RD0Bq$hMf*7$^YPCN*HG38o}_xTVO7WMmCxpbmFM4}r2d%7g)ASKplYAZPee+=_vd0 -81(;RNMO&F&=4D!93b3=MvcPCB8)$y`{>O7x{}1R2fAF|NKhP&*p=O3Ya5xz_%mycewW?0Wur(gc5YK -pBHhZ%QqD)pHB -6n5&kaHz0MC@xDs8F7oa#z1 -+Y4ROtDG3Z;fZWs2;w@z`$7yH<|2%{t)NfSxB@(7uZJFe`2WFSr7s7;dfgu@mwY#nSH=7hq+JA0;KOk -BRJh>*#szsu4*z`;O)9Za`F%*oDk5BDQMdlcaAevm+=yZy -jCo=Q5Zg7cj_1G4!|qW_hJ)3oDHwL}2`0B-{T04D$d0B~t=FJEbHbY*gGVQepCX>)XPX<~JBX>V?GFJE72Zf -SI1UoLQYm6E|~!!Qhn?}5C7=niWk%LDW<7;J~02HjxC;3P^b=Gd+5EcERsC(Y*3j8caj6h)tY{Z_-ag -##V(f{aHtO6N5>&s27vtZ{j%90Iim%O0Le$*9UdM}MSAa}D7_I5FOA#}(d4==X?vB7B74DuD4AUisj> -(m%zUG2G&@BgPhuPm}P}*g&g3v4|TNjpYeY@Nda7O+ZeRShGXs~(5pf4EHF;HPgh-)-o@8jHdv$V9BDleJ_-iY?@9_kkT(Gp7a2j{2I)S!3s-QETH1r4+qw* -*!TU(34AbL!#xSoWz`Pq{uwk5~2w)4E<@G$Vq9xS86Rk)K;&qj#;J{UA?K{iD*YcL~#Trreg3b?5Mr~ -j)=$2~dBr0LxD-ZIoTP)h>@6aWAK2mnY{22(4}U7{NT007(s001KZ003}la4%nJZggdGZeeUMWNCABa -%p09bZKvHb1!0Hb7d}Yd5x3HZrd;rMfV2$4+C#10k%HCK#Ha>Ad99&(OpppBXMlAp-5&(#qr;Fs8^)c -2x>qJKJJ|}<4fIm#}Tlq*Q*1&2I9qQdj#F@fAvv2i)OtVj=lCp`9xMZF8sr>WD2h3n!>2~s6%93wMn; -BX&Z^ftI$@_bK$Xmz$2B1wB%9#t>69JZC+I~J&u>}Y=~&gcY16!Q$seUitANvFa)@*gaqq2C(0U%*d5 -c4_{;>->+97zs+WI3l#=}-r?XFPH2_sCejzf$`Bw&eGuzVq;g66<3zwO9K9CpC7%A(%9qZKap -$lf4PXanf~E}-D!GtuMhA+d>qc8yEDM0eh6W`-CdEWuqkR*hcFa^qbLrW8sdaYO`Xi%C*8=6mtZ-r-{ -*C}=9ZwJ_wtmsjcEUpw+{ic){LQL)IgaG&+Bi-k4F#3bW4Z>H2_j2Ki91M};)KE3G&OGRE^66Qn%!T?V-CBwaPKV -bCvym`C(iO>a>!?AV%8=6COMAv-leSK5NE+UIrRc^q*yLqVyWhVPmUeM_>_On$M9>$#i%9u_b%Qw-gN -Y&J~2Da^8W(yOkTphC|{04%$7ZFp?~)K<%8cs)oP@6aWAK2mnY{22 -)}ZK=?`l005f;001Ze003}la4%nJZggdGZeeUMWNCABa%p09bZKvHb1!Lbb97;BY-MCFaCvQ!!D_=W4 -2JK4yo2beh0YJq!(cE5yKH0ZHinU7B{g+q&vwT0_OqL&OQ62l(*OOxtTwnF(&!C$V0!ODf>)o6W3+Wu -S8XYKSUnkhR{%)6^|ySVAN1_Yn9$k~Qv_r%GXgH&qToyG$I(R4E`J2O1WdUFd4w -$X7_dMABcvlipzpziTsPdh&`-5vE}{*DdYpKQh@o-49};PCjWgS6YN4YfS38i)pWQ~X?GEnluS@(~j` -(#Mv7A6@2n@6aWAK2mnY{22-~X?JxfX004Cl001Na003}la4%nJZggdGZeeUMWNCABa%p09bZKvH -b1!pbX>)WgaCxOyZHwGC5dMB}|3UaDc)@YWhtRUHg_d4RAT38P-$GEd_Ux{5wxmk(y>Q%r&q%U%CEK^ -q<{-IP(u|&YX6Dg^_eyF@I=SC-vA?|7Y1tF|r0|3Auy+f#A|D6U!R5txKyg*mdl0SEwYu9=4Mq;S0TX -S0=f-Nj9W0k3x8lNr7Obnc1MgZ2;y&8^<`%BSJ=aq7Anc-5n>aT0mKliVzix4dH8#I`!38`vpuBxFeJ -_k)L|He_ -g7g8)(N2J7|C(qM(Ue@Hf1=DEmRrjTy_*mti-~>2IAmYvN*Wqg+h6Lp%=C+z2n}XX+7Zz+1@SCC{Mg3 -KBu>irdT|D#fnn3&F+K-Dy_6lof+rdcC1H(t5eOaJ#%ojPjs7N@BE2zyH|5YY{S91@m>MXgw66fz-nU -OvbfcIm!A_O*jqjs<_l#N#T8271B~>=7r*r3b?vm<=)zg7P^4lQsPnPLkN9{a~z{5?XB3pe+WlAaKCJ-b -OM^7$38orB1SYqqC!M;s@pz6&D_S|LdRuei?qP*7H(vqXvSBrf&R=3PzDp8VK^Cc!JX>N3 -7a&BR4FJx(RbaH88b#!TOZgVepXk}$=E^v8`Q^AVcFc7^P@()9LNx;>q^blyFQ1(6U`GDX}xfd$Hr5zlkX_31z -%N&UbRzH)|6GsMDhl;kXcF)Eru7iFD*x~izUbn2xTPw6%M;cJW|uAt6xEWEU$O-11&L-r!MLQfyw=xeKKGJ-q*1jPO~&Guk(cGC&*%Mv5pgBFy%tmqpX -EJ0@Dr7_C2Z^AbG8$r~1a10^9m4h^IdjOCQ-)QS^Deyn|m9lVj{&1lt -!z%E>1ZX-`J8vJ8VqOq`!A5zHdA?NB$VfyQARa{Py76zGYk^~7s98G|GJ4=u&l!K8Ciaae!a?lsODP- -}bQw2vP?-TR65N!BGB&|*ol`c3P+D=X8v)Mb@6aWAK2mnY{22+vLmSG|Q001BW0018V003}la4%nJZggdGZeeUM -X>Md?crRaHX>MtBUtcb8c~eqS^2|#~tx(9!D@iR%OfJdH&r?XwPf6wFQc_al -vCBx4N5R%(+fCfrynOSY?ITjd$AA0|^A4A3Ou0ns!X7!FraetXWPuK=jg#t(T2cP-)4efsq2?_9f~$z -<~U+0|BxT~^j&-!*%srBG|pZc8n8s^}^y;Hp(ZKGM5)WqtozRh7(J)ucIJt+eWzTeBHxt$np>Bu*6!K5tAUcL{F80FtK3c5$|inYsm-RWH|}2fSB-R+T~k%%UAoU2J$Ts2-#e*W_xN#F -rLt|LOy5*;C+qeKuAe_!H)j9 -t_~M6bk5tUVAG4h-uDZSJ@Y5dUl~v~U5_zw4`}UU_Uc&VpB~Co;%YC|fkaeLN5eW3pF!4l~nd@O&D-> --z{Veq!)=7S%X(}IcN$dr^+UEGCX;hPl%gc9k6|+{>AP|_(Nar7Adr%FatF9R(ru#@|K&Gs8S^*esZv -^J2+G?3K`F5pqwRfv|NzX3v(P-D2IfA}g13$Lg`*MHDPd?eJYs<<_uE|O*S8LU*bepxE9_>jz(sfx$f -R=Q9OT9uq%LgC;?>^CWSL)pM+Gk~RfI)HDiwu-B>)P!KyRJYHMu|M+ZcMmz3zr)8w(nkNbx{^sEA?A= -{XW~k7%2WrYLTbG`?K^rlTdit9{Axu2{_g6BcSZ%F@u*tb>*vobK);h&AsY= -HVuiZaEr1aIxIxm-pA~W~R=cbP48Ys~2U{RC14%5f(OjJW#pxP$y;-n^fi-)l)V+X}6MuVsDYzeqq6Q -l&#VH -u<_rvR&_)rYd(&baMdz%pTz>q^%4*$vX0ezBMagz(o8?`BMXWga2REWy0Wv=*x$Rf`KXdt()NZfKE&0 -Ze7PTFtbq)(KdAfL7hE5Y8lLXMyFE?HkqZgMH0D7s7&8r90w}`UUdxaQvMS-MN`b0QPpy?OPGMFlRH(f5S(>VLa>SMS~G0WG^|*+W)R)Igda4~ ->R{Dg8kJSUUv%sZx0YqHDK_fH9h5BGyf|F@`scol>~b`>JeFh#m{ZHsNq!Pd-eyZM&Z)g8tUik0+KM) -^Bd5fE6N6<0KL3wI%x*(`%qFuNAZ-V&I5P=#{Xe#SRMEHc$I@Q)BpooXprMZ -3WUG-_RSTe!`RLc9S#py7+S-^=@P>&inYP90Toc9g>CdzD!%t9slWqiFp7F#=B4U%bre;3FOdTi7$Ex -|wCl1V$hu|7$Bj|RP)!is*@G$zQK&;*sjR@bHWO9Wz|=72NF6DH^9Y(FDCSv>*tnD66d<tnK -i}X#wMW9n`5NaS2&zm9JQVnV7_ZHRg5VB)DI|y6zo8!#oZAE-x`KF(f+$^6rzt90-fknuwo -+t)W=Y2iP(Zqen2P#D|aB3HH@bQ)95q~xXT{T0Vm5ZX%4WoXpCxgP6QK5`$2}5l|BvKB7YF5nbaOq0* -;(j`$S-pYz1E;VIi5u{@PUDk9c -En&k?^q^{>gr;!stv3oI$mSP+)TipgFp_Ud{kW>`~4LphU;g#WUiZmsT#|FNS&gbt&)nLDdiK#=f0nyE6Il0Q$3Q^`n<;Q>cM1@W^Au=BwKecy3Lxq -!G`TuULo1BdtiBmX)$>iM_|Bm+bCy1{BoHp(>nZpE0Yg7bYs4>gg--T>UP^beACG~VN0LWN1-Uyo$8( -RXmTk?NwdIZjD>CdDzBsOp2eee64RrSmGesk%Y~9i$HUR7=0eEGbentR73&K$WKI_FKvd$IyTsG0h%+ -Ac;KFu(>?x&K~Z>+z?c^*({9@tFSAwmG6szH`+?fQuSGH=KM#>oNpwG4U)#-TmLG}#VQ^L$fsJZa@(d -S1sgZ-QhF2A_a#L!Xw$Vp`*AE5Ey*n)cJ16B#VY+eIX+JJ3DyhlR>J#NR>$C5VKq&MK-9z~5t{M)jaj -&=P{w9*IZg0gC%rK{&|2z5RD=^q1RP(PkU#Kq5L61?~Yb#7_zFBE*WuoM$cAEpSs9V*zL-7ar`etV;P -7ty;Em^@@lvRUtqHm|m?wKk_Z{GQ;X2#bt$(tgj3t@sL#zCL$M}fqCLMH{}b6Z9oJj!2w4F<~e51No7 -H6C;SS$s$&trDjES0WK%XC&?7exbE2W@ONyevuKv9PyaKLEML{>-k_!prZ0S3FdQUf_UHz3p?~ALoO~?4M*<#XoMN0uDV+T8W{yy4 -o;ykwiw@=ngvd}%Rz3^lDOsK>f+*p3$+)Bt$(BV1Ora}A5^hDvjy8*XT>PY8J2H3)bZupGh10?@+eWc -+qXwDvrbq*Z;eXj-B;gpnQVI_GN!GX?)Dd6suC_=9NC*A3?3^=|~^iuj -pzvNi+9mj_mt(=sY5xk6C>W76ukngIOOLnj1{LETSHPK>CzohN8E=_KF5+NsDr_WC|W#YJ%C)!Y2urf -hDtI$t>MelM|dRqdQ;kiPWQ_qY!@gjH*YtyM$ZyCgDE4XNznu#024w?I&aVvp`kS5rYlHEJ&TT36Vl) -b8I`>XC?S9sj+30hn2s(LCLZ%gu43;@-`X~qn06HXW+oG;97%rQ=f!39Ei%CcD&;(DPkfeh%b3C_hcS -3waxU_utj{7PF4XM*k~5f4GauAj}=#CxfXgjAm-5%7@iFsNa>B2ncd4H_|CiID7NMaWFl0(v#IlYT6?5*i^8}?0r -KStd~k{0W}xb~p{e7`uibgEv}!t*@@$tqY6xnU2-3M<%R`ex}iU$AQjDz|}rvRgX_J24Nq<@9EH8 -)~f~aM%=NKRYAqD*nMg&G9fi%Mh4-TD=95SuMp&=!E$C%1xC1SvRY$y#0b{{+M=eL(h7%W$e+yDJ)&A;NQnJE*sL1)VF -XA%DM{5a9+^CGvu?_ljIOdrmNWt<=E_3xY*lln+|;f< -~e?)MfH{ur7Gy!9r!k`8qt~&lD~_3utm(tsiS25(^QWa*$sz(?|z2h)Em%lT)B#j<0_nG97Gu3<-=)> -9CcQG?67>t57g;+V8~00k`7N|HRLif7tA#;{Eac_kj9BJ|YoqT6`8Us%R4zTGECz>nN#{NhZ@1QV&m> -`9o&C_ih!IZb5o2Sk0r!GvyJVI3nE`z5uT}+C -v1jW*P7@3bYGInhZ%GfG4d+`H4F_tHDIkz;?!Q(8<@=~<`%7N6Mr>mSdH6JSen7Ot@AFmztdWsP_%G}EqYFL -fErZ8>~2db(=wSqsqOPgpq|_@h?6<##QDnAgL>oyQ&^f{&ZwW+ELP?>VwbkHxvzm73J+E1QZH0z%t^Y -6_7x8?z-fHRDYK3()i7I879vDF;r^riu7!e*NW*uV21)TkYXFVhYW<=rab|3oh4kN~20XO2mf+Ra4pnH+HaKiB_;$ZHg=;ay%;4HsvlP0wEoi4CQ7Q?|w2N#2=o}prg3ci|M=+e308)JM;+aMoc?mh`Ycy)$QMI2+FRIAVBG1>s+LXNkYD2|#!SN&}Dn_&hLPd!gM)89c=p -p0Ysym-eTD+ud~J$LKgrr+-q^9qpU;!hLq1z%XOJU(gpeOfDq^=L{Br%!Bf1NDjwL0g#o#z*HHZ) -j81L0E%y4Nb)e>YN0-P0TKg%xcIZmr2yzC#pN*+zCc6bjf_IG$+FDTV>k&^}GSM^W%`Oz12rEA2a0YM -7Ya^pgkqNx?CUE9+p|^B%2vd>hNhWhwYO3pU-oF+(NJs7MTP#u`@6}l)eEzc=k%mETrUPqB7T?Q&G=x!)|?;H*$X~+(jL9B@N@Dd9oicR -j{6352bL?4b!b(o5W=35H{PtZ=NvuGy>04!bIN4ArLs!&9h5m1#&KzWkB^9nQ;KTcdYqVBuEN;g8{BB -euJ2V&x(kpoS`7N&cvy_JUo^9B*^Q#Xcg}%X?Z*O9wui>^r>20Yu=u9TTNt1MRRd=Up#sH!!hTZ?S%W -`lg+B*dJ0&VGx_>z#4aoK|8h&>@Vsr4Lzv0udsV~PKj`XD1^2KO-B<5}qxQ#XKSvRzZbhKqmF%W6qG^|{>GYbI{5S*tE6s$ -wywchuHuMb90G{`5yp2>g -K6AoUOooE@2;U8pFC%rsxP!FWu4|IY6fO-tqBzDmM15ir?1QY-O00;m`Rt8hZJFuIWA^-pYkpKWC000 -1RX>c!JX>N37a&BR4FKKRMWq2=eVPk7yXJubzX>Md?axQRr?LBLg+s2XKUFH8US;a*#<|2}Psk`t@(_)30fqot^#A9J;EOO0;rYc -5)@UMm)WF`eY`mdL`dTb#`|4=_j9laz{MhNU?6V+vd8euf($1?PT2vwP_C9mAI4uVAs3`03|$Zc2ew{ -3VyF@(P76!cW7mfaCSHQo4HV3TP?fuX5Up!U2YeT%dL_)P_^4PZ3i9dW!E%YWuH`?Y{Mtp=IRP?v46J -!VBI!5(cSD3NB#J5+x#l)XR@1#Cjg_o+{&5wwo>r-_j>r5pr4-~_W0Y6H9SOI2-v>b=f!JTubMXBm&; -e>l?Pkx<+55=vQ=ZP^RB#7rpxp4YP2n^$JRDpmUUBC%W_-&DvP?@$gJaxm>>h$0bwyi8zH&1HSmD{ac&A7!k6>`Dl0egSfbdQ@uZ -GL)EzlJ%le%eU6eOzrNPF?@>W33K*97yud@OYZUj2Jjy0?SHZrPiSLZB@T|Xdce=9JlaLC86w^mE5Wv -7GhPcV22nmdNL&<|Iqw624UT_yRs{mP2IK4)-oqOeaH{Tx+8}E6vo;rS+>hfp_a|w;`@xAJ;O)iU6C* -_r()mAwQ{}n_J -;AFF@j5W -w${IQxvd{MIjdAViN3)$xKX8q}aXogH(rYhmW7qeB@)KS37xuU_Sk1OUnvy>=I`MNzkI0;_qK0tw0t- -3zGL2B>XS3=?i@hTmaHDJf~g&L_6v;z!@g~pYjGeYDwoccmMH)uRCb46%1eoe?hVf|F@EBQSdt8PLCH -ukAy$XY5QwosAV${c-_oXh`i7ZtE;+cWej#MF5yIlnb7fzl2n}Er)P8SMyEf1`9Z<~UJKZoaGbYvre9 -TXkOIPhEMXS$t -3VLO$dHXYUHalf5Tek;%w1JC#(yc|^bRh-jA#}4Q3o*$j`Ol!UX1j8q!L|?SHJyh24Cpl1gl#<<0m#c -n$*kW1KNH;9!T^Jfv#Qo~+IGTHOYykCnLs$C*JPFk_S(pvlL#0Q(*Lx)^{s}Um{w}(X+n1S*Cm{y{na -OCj%Ot%2}nMRq^5lP=}ygL^aP)`2g$;Cxh<6 -`qCJ3m4jIbA|F@-glc(EQW;p?1`NR!2n!=~!9?7ZfS`P{-&V`Ynudq~Ta+uXy{SP^G%e}$gne3dMd7g_D6?yC(KY=^3m^;B`^_3!$zNG_S951eUZ7&&wFng6d7$cgt^AeYv)B -7^=mfI51Gaww-0@vg8)JyhYy8_2IhI55qffVR>S)TtTD1Z#sci*o%POH1_

#9TVp{Et`IJq^~6%`w -!?3!#%V`I%FUXBNxxCKcR%>>%tvN>cr%-s>}9fBB1X?HHUU7>HB2^KLSrxT_1^fbpRE9WaKI-sGw1Fe -9{APh~L8DqaAKf@M>FiH+m<)|Dp40#v$KH?y63Ewl0ZpS(9 -f0U9siZ$LDl?5G1eFE<#*1X@;mlB3a?GSi-7Ye8U1;g`i+KI)L+meGd9a8e`QHM(WTDDRU~=@$;Le7FUd56QpR@QX(M1Zae>s3nvA!A -F6i&Iv9T035(h>nR&C!TGYM^~)kM<4Y1rP}UH!1W(JdnNuR@Y|V{Yl)F)XYrJe?8G-<8m^Dxp>Q8-Z} -lw#}|ZiVT5yp7yg8Hiowip8nt}W*+y@?-y++|2RidRDbN@?_&ZBmMDR<({E6m1!ImXS_emcN4#ws{(y -??L{CaY5PGW(6PgoBvAArUH|6O9(Ggd6l%-ErPK@K4*EMos(5+BValkecrL9i7FdUq7zlD~a7(LUh;Y -p^GehHW!5aUM4@wOzSv)SG*E&v0V2jOcLlCpF1`t@e`>md=0@z~}>ucM^?4FNgnOy=cL%-;A&|3QK|n -+EtN?7!1IVXJlLxJgylko|~RuFCvpsx16vOzgZ*?!9hd}n_RaI$UnWx{!AMSEeqjJ2k3GKR+Ft+6!`=LG)@kp)!y;o&W#~BssaTZP6*((<^c -Mc+B8k4>Ucdt^96Wi%5`4Z#_+!L4RifNVg@7 -Vmwb6uCY2pf*G7PkP>ly=h{j5ctrUt(7*Deph5Lx(FIm(xv`=waJlJ-X{Miq$Wy;TGU{&^b841@R^Eb -Y^dfBT27?~l@CpRd9yIRW0qV8=Oek}N8rT~# ->a%DXbzq4qq*MT(WT?)a0;TUThD@RPCfTh)bg4EZDCA2NgWhxAU|1SdJ?*^J5*min;J&2u5*yZIN%I9 -f*u73RT!v7V6tKxJ?w>6VBPRn6Fytf`OTQ3&s=1{Kx@k5z0`7^PCCa6?4VhwV@i!GUR^0RgxN6aRxN-fKl_@r(;!pD&_Fm*Eb> -ooe+-_~hSdq@1$hLf)41pbSYZSAsOmVmY6ZWHQ{1Q+gD9}UConjMO!E$XINRaa7>8{$Hru6Kma(|Xc-1RM{zxOie6^}R$etz@txF1y-2onQ9wvM&kv} -;FQA^nn`wwI|Z^$90L+VR1a;W7Ly&2Iq@$k_bt=NHzY!woEo{7*C) -inAaBxCrA;V7l-0s5)Horb*(*kVr5G55*ctBR!coO`s#hWL*CYTDK2b~E@3lPi=y4Dk~@bOt&aGjX{1~wSc(a<{* -2C6)sa56Yp)Basnme!LohXm6gh@JL|9SS;%z{iK3!RaDvvT!t9KXnU7{u!=gmACu??UX6&4xbfW1Da1 -1Zt_@Ee7ab3aAzT_Oxu01R%EI~Kw&^LOh$;9IR{R75ZmIq#LhX##-IP#t#h?l$vUWQ1pcjl$Lm*y?1U -C?K;dpSj#FbHpphrqNKG;t7`_4knsl`Y?&H!LsELl$0hN*+XU{*k{3S?IO4^Bn-?eqV?I+GHu8z6;|H -2XK3G5JW>{VEW==F<@l%M_q(}#%&Gm3;V6-gz_ZFBKRw6nUo@nH5>9Fgn1@nB=x+^}!ywk -B0XuZ+b`NE%%n16BOk!-`TX>#xP8uijPf(O1E?OBD?Lz>e)S>r~4X2v-mL!-Eg&TsZ1VdMl*ubP$;m| -?=&Hl%RFULPPO#TRI--{6xaWqF9}d?CUwJ)W!9b;JL|Ex4rvamzPuJ?Iz*O)ct`w5L3vUrs(Ow0LaavMomYUSEPbPo -_fojO#&%!N)C?Ft+ybtVIpzC{jV{jD?A3ftNgJkf&Wb}K!Qqbh2{wQspoy3p{iQ}%5`q;J7Q2*m-zAP -Zh43i)#%^l#lh!K?LUFoDci2-k1HKJ7Gg6K;FeQ`FdKdO{eZLe9iDZXYS4AszrpfTVe+Ndn8)qqabPH -Nvbhs{WaAtrlQh^CWk^n1104z*-XEk=YDeJ4`gxHNu3hOm+Q`hVPmuvtQJQBiO^bg&X -u7@A311rv29G~1wyplH>Hg+iB&roqRPxVCs&k2_l?dt=Q}f+HOQNJuL34*|VAJxUgIk|39H_%`!*O}~TUi$epmjy&a;vu|%e;xlQ|7iJS+s3MS@n -B7n(;1WE2BJw0FCEC5QNeelrC7~;wVHe)DTHj0P{;!FJ^%YlkTi*3y_09fa}!DLGcec5QECoJ{#C3F) -++%F<^{IX)cTTj%Yql$OhK8$H_(SJba8+uM0ZNU9xj&T9!J{A%WgRT-6Arec-iWgxy--me&kc>Ntg&HF -cOY>d07!J!lfg_BHbE-o!Qdu=seUg9T7r(n7vE_=1^2nW$TfI|2PnO+O3rsT$%Eb<&wF%umh|+( -V>vU3c*Fgm{3Qdx0*cJ+_9og(AjfzL0@)8)?q^Jh0@?C>stLg}hVGxcV(LF=H&be)_swJyTNV#u=j0n -BJ{T;426_@aGH{aC?l~rA!Cxl@$a1`24b~!j5h`3YV`Ez(myfQQ(N6D2MCcF>XPiB$8a1fjx;5vIt!v -$H$?(pi3_+B4g6whvP=_mL(o?K!wMQ9OwIgY6Gv?XY#$@>vu>(j4Yq_1v(RR_J#vr*e^Aj#ZOZ#HJr^ -*hIP8T4(CzhU0Tqqc3@REjJSB(5VhfZ5sGcevg8!jkh>=({5J{xY1GsLg^d+YM#spTS~~1k<}Lw~6F`dPvWXG3D9Dek)0gT=#JUNzHAI3V$3(x_XR)7Pw>{CD>E)#uYJ|K0SrlUWQdF&+C`L0Ql$Oo~q -4qj1h}^2NOu9x#gZ(X|kiDY2r+-0SUZuP0`1`HCxEPX#2BXa!=FS_PM3fPw -Cb-vuD}Oq(Kh@EbCgKIM8!X~d{8YBO)3S)T*EW8CQXJ(aog2sz{pC7m`3{(nsG$B{t%2_6tc&eNXux@ --~WI4tEvc_+FJbqDuX{q!wTD3>T)N>{R{H@wdFOC}0>OBi}OdV$gTDir8Xt49hErL36 -nbcUgMRMz%LIUzcBKYW2?k6}BGs^uZXmIsw+aL%#pc6d;b=_~vl_H_<5)&&jFW8Q5ZOieXS|zD96QJ& -a#=`ZrQk_!D|DzZn+X2DliJAOgF%++rqDVsUSX5VO^;clJuy1>pe_Z6G)K_*Aq2_^QRDMjK=|ldJaD=gpg5>g4>v+I{IC9)-kxV`fqry@7(nb6Lu -nSft!yK;Zj8eI#(_Zq@Eenc7=tfWC4j))jBoq+3?tyy{H@{thkt1}BFS1H>u4A}?%cyZiwe!A|Tv?ah -BKqbIW(9AW>t2+Mf96uRb1Zm#fs*fq;B>qHFDT|06nn4qsZ$S@sK)L*SzY(TQm;6BDLB=K5|_dR;)M9 -^q5C|zf#rm%XQ)#ht4N-uX4#i$|0gq~{twdWmu1$#GWr-3VSO@}U93r3(t0+u{6&(4y;1OgK66EO<2ckx1#iN70~TGl5l~2;>Q+Q`eDz>}o6qb|L{BjFEvjV -t~c9Pah~Cq609-Htj*7LwwVKx}M0@js`>1Z9{HgE@?hQSw)!$`)Xg90YKxq0z)zqi#L_TsvcgY^XzvP -{usL_1(L(xD|+2qj7aLFWn17JL+8Wzcu9UcX&^ic+QS&f1=9Qdrr5i+`@E-@95c=5a~ -xwz{q_2*mXQSXAZgFob2Qx7@&e$X+tKAlXUdwxNleqxz*SBo3%EmOm69nZrfrFRDE?7Qw3(iKJb~FL* -`&!fGHuj)eab%toYS|e00IZo&XJirf{GFztA1@nZ1Y3pkRG1vmy7cG -i^Mj)>$_4Gw9gZJ}P-f3Vk>@XmXQ94lkmt$T(QCLis?DIobOlU)@+`Xa6=*LeQFXajrNxii44QR`GON -aSWXY0;g=3>d@!nTpQ^a~(yN$yuz2yvd!`9mY3tjy+>>LE8dOI&ks^|!#11Xy6$VrAR7m14eIv%O996 -A&N682KAPvOJf0phXbdt_Zd)NJNC=crzvm%`MXbm_haIn3Sk&Itbq@FIgu5&CajAEX!AO7H5BdP%Y2y -P1#V3V8YDgXKXyR_kAOWo@=uf_Y%`Ho-pWExPxck@=&1aO(vhE7$W_>f}CCs^m!`J8Nd-X>p<{i%>x+E-k_jc`$5q$!8Os+cp!5`Nu)B|W6@d1N%Sk(QSolN$BdqNs_ -^fiP$+=XEaYGbfsiu{L!}JI$injkD{mz@Bh3Yaft{wmnP%^Ax@m6VDx1i(3&(c!j+io)fo95H#sY9)J -GiMYMz_y&$Pr7s$-}ln6~?}KGhc4Xs?KQ&l|Dctq?t~61SihuLQXJ*$GZpdY7Die<1W>tvhiH+KuXHi -2s0<<;)#dRPb_&$+vmMW;z0ZpQG<}`C(n!u=TXjbHzpjtQ2RtNBNyoG8RR{*!uXV})T0^+xq1wHSl4m -Ozj^fakAI$OVHTD_iI1CZL;8~UYQbztnX~xjLGLn81Scxm8XWm&-!}NJ8-5=NiAsJ~nZW;ZQ7sxbJQ? -rUESZucR<*uwZf`)6+aX9Ua3!LGmH9m8+@90SdD>*c({!7w%KvNi6_VvM44jjyE9ltYQ3cwD#*$vi9` -*a<<-Oo=vcamfI)>re7UYozQYISOk;y(xb9!+~Bt=_(T%TY;`D+PkT#@ -cTb&Sq%?U_s*I3%jE2zKq*Cgz+az`dx1_kE*E2N8ZB(`Av?l+jcr}eWipVdn@BRX8^$Y3+cS#cw|U~# -$TM-+U$x~*a=POCy5pX=H_R_+HIU}-Zn?q8K7TxVvqvunKAw3Ng@+Su1C18uVIX4Cci6d0hG}yIl!vw -V{&4Do*F046E#sK2Hu8S*)TQo#Uu_Ktn2~6)U&ca1w8R$d?Nb~@>WSTM8c2vRg7SL@xr%Fz6tTz6dW#BgaA5KW@$MA+0YF;=ncjTS -pbdl>u45E^A%lYNLXLAP#Phss&TS|y!Ndg4alXg(L$ -9&!%{S35z5|+$HGhnmCQ%=pXckk&Te5-Od+L<&ljgkR^cjfv9pe@%kHcB#wY%PKZ(S2}cFJA7v#(~l# -Uf0eoXla_zI21A-YXCY+5nMHA@HpPrmJ0=lA8hTNotPho`Wxk3E@n*ER!J;92r?HuO*jt8a*RU;+l^! -`%~^H^80BD(tlCCweJT~a-Z3(6Eg5qujnQPt*X7c*<^9^T^}@`sbaOhr$bd#MZ=c_bR=k^ycb#P7g#e -abN9&N@IZW}JKg{MD~;xT`?f%FW?G(M@gTXI28V_JTID<#AfDCpQ;_3(d8X`(Q!bS)>gH#=t@wq4t48 -ukQA-Rb(4{Q~$E6ZX9R--s6&4!dt&EuC%bEZgf`YM%96b^G<<@gsfaCuC`*x1_8iRGy6vbuPp5M#wPF -#~-Vjea;hjw0@BMcGqg66b;vs}Pm?ue)U3l&j7nfzBW~?o{GIsV2-eHo{65l9x -c77J82H018_-%XXk_PC-ym~=z#fVrpdB{}!l*OK_%8;$k-WquC9B1+s(zhYtcW2(Ktd6|3?nIFhypP! -lkEdu&1jXOF{=!-Q{t -Bvg#|wB7Np8*i(Btb@wq8FF;<@6aWAK2mnY{22&db>D -K)P004a&0015U003}la4%nJZggdGZeeUMX>Md?crSBrb#h~6b1ras?O1J(;x-Wej>LbksHzR8koGezr -=G4|6^UL?+ikzBPzb?*wI+^iv$y>F&WxQ`vfM8FqP8kRkk~Whd424$*yT!FCe>ymvQ57y-1|=KxIN_D -lq0Ho%oDqnV%hJlwc0Tt15W1WJ|mIbTAq1)QU?JrAf9 -DtHkm`;xscBg`$j)#pEdoQe?LU^9-IlY4=tD>0V32YF5Qo#V{5!_`zo!>tw%6OFm(c1&u-{a?K`%H=_ --=Ga3uxI7@asj)zEhsrK2bG{pcz;j5cYW9Oa)jcHKh08Cb*E(7O3u-OelL}YG34Gq)Ly52-0v~?{FG~zb8Qdqb;Z{V!x0!R*F!dXU*>`n>ACPT7!0ns-RsOSyX6eb< -ysyvvrs_D#2Uvnzc5T?JOc8HS0}=7_DR|44)SZqAxf)Xv{pJGe;1nMU|(G3m#LI$1*EA}El_KuW6J|b -(gsyaGM4CcEABXGX)F%?di~pst%W>KMP!W8;I?)Y`=(+p9ZH={&Qq}_k9nO8TM5lmD-Tc7rQbtMV#w> -Q-N_hL3P>+V^D#44lUA4uULQ?yt1u(l?71;9K9`IkGK$nrE)!|^@aFqDn@rfi@_YLoE;Fd7ReTBA`7` -OR^uZ-qQ03atuj_rl42^mR2u|KuEJmZX$W|kA=Hy4Lx`LWuOr+lf(d%dp_z>XFuq>GK -!NzAS+VD((SOZd$>JXpGkVpX7La2gajTApn3EoJ*)db+y(yTfq;9aI{s|BJAEM<5OGgMrmZaRczBlhGUq`903H2}_`vu35tVyqd -vrfth`tOTa1E)ZnDGHFYr8h|d5^%&F6a&%twbnu#8#$0W6TD!Dt9 -G=LNOcVwWhxuB$=?E@Fi1}K*MulKSWalM7lWWm@-u;`6E7<1QAhbW6{@kv0Y)YBJj6IE>~oZCx~(kjE -51{fKee{MTGOps{_ocl8FE*&0%O+b4Bou%n%dC*Q6Km>mT8w^^~(B3RO-o6n__u9>WqGBqjV>7C*!EZ -;A`RNhm|A6EpCyT>KpgAAE0QujD|YK6G0*}JlAhT>g3@u#iC4T4U#w1&B+zYviUH|BVD&cg9X4e~@cmDs0(R~bx^7|avV<>_#wbbQG>DE~l`@4p6nhd0iw3{ -+Opz1tq#>zt7ymgJ#1$tC_FVBGxiOe8mLbklC)A(`Th9JUvf5kOu -9L9Gu}B8RxO4iV-s!77Xf|XfKJK-xAF%{fiaz$+p9L^)fTE<@U_*URo$&#&Bli%m;S*CfS6Y4?#u?rY -mkAT!OXL>i*L;Za*0i*G+&L`phf9U_gvuZ7q}RY1QY-SFfs<9O(y9r`rluHq|8A2?08g@Rr9sGr;NTN -Is+jAC>XMikQDWT_Jm~Bux4!0nY4k*-3Hcf2Eq8_b6L~IuDY6Z4Tep=W`RwbuPs`vrAg5ch8+bqIUX8 -@o&GBv~?}bt+|?=TpIqMhMoKW%c}U?kUc -7F&d^5Ks4Hp5t+Kp*fABK7{Ob8hi!>|0VmX0F4u7%|fanqv=HRiqj2zStG+tD3oN<2*r97DY4Nyx11Q -Y-O00;m`Rt8hl?y|F{4FCW@EdT%`0001RX>c!JX>N37a&BR4FKlmPVRUJ4ZgVeRUukY>bYEXCaCyyIe -N)`V8UNoi{tjC?o=BNHVT|LXOh`+B#=MY9x=M!Eg&3ngdY$ -1~gWTMavSke_~JW8eGJ$(L*;m?m}2k(=;T?iuCKYTyXi`TqL=IJj*nao9wzi)Xd!G-r$mg5AhOvSxf6 -f!B~eKIZ6Iln8)8?!7$#gj!kzDcjSG;6g46Z8VVBVr**(kx37w!Wep8pc3$5*`z2rpWmRnMAt4g -=>B!O#D*m|GM4@yJLSm823chb+(&6#h`R>tCqT})zV=pKTz)Hk5T$o$hj2^HtY;=4>jCK$-Z;9)VG0z -U7i<`@+K{hQ)eOwrLk|oVM!CI4vK3&}tJ`!neB21sc_Z0w3CljdYuAm2@Q=zds8UL>G4?rR1n2OJX9^ -osQYl&pVIL-QC{ SUg>SxVi$ZvDVeqm7-2B@q2C~_SKbh0JHsb+W6|#>n}Hl<5`+t^C5-pp%L7WI -3tJ*^WK-zB%kj7_3uJCn;Xc0iJl`a-sy+Qm@q61ylBQ>@VHdxg;Dv50QmxxUuB=+wbxdgtAoNo;w -L)9b;cE{Pco^oRPfEhj*&#a8Lh -O#3n6vL|g*`o&gkNUN$OQW4JVTZA^_hI-cv<`BX3VC|Ga$YRNW==j*~jM?97Xx50HoPs1lMymW|61y}`C ->kaZVQImlvA-PvN}q|O(?SapdHH@Rcs9`{rX<*{1R6fhU_y%)#d@3LZ%Da(qN%0^0Ak21>j0Dp=m1r9 -C{;BlfhAgM2z9jkl&T_!Fzl#*F1A_tiVYcx`-ZXTvdbBPeq`vpOUoRUu$=3J7Zw>D%JgILDgGU>oZoe -qz8J6@zEsAcERQg5+k#)#JgLhJqzALATFC8|vBvA@ur{| -2pPia4;VzKgyws%60?{(Nq?f8y-Y@xK2(m7Li^U$w0$~Orzzw+_`e+p&&!&BbOOGncvA8E%4qHjuc_Nsb -VI9(DD#4

5ZstB?f8qg -7pCVQzi#v6lq0R~!0ZdG1tB2{SX0~K0sBCjceTpkA3K`3%mDVC=8h#kGTlNO0$k=NYc^P(vkLHM{ROO -&K&P8TRzPnV~7FhdrmMrBmsqb45ORU{>9POq+fj6&BXsLBgzx;IqeTBEu@R+uOJRx+822|+IzzhCHTn -764Tf{Jp?-4TzNW)*_kTID=Nu#DogPnj=E;hppTF0N=kyHMHE9+n~Mtj(SeT^#qiD6 -)~l}+kY;RStp9!S`pw(dU&jq5c_S7HQISZHEz%4zUUu@Yf_^B$bKue(yy++rw0lazOQOivGrS~LrbzwsFeXR -+p8dt(9T%`kp&gzM_7oz{4@z2U=e0;wNComj>zAKRWD*1)#M0t -esCIPjO+B!x9eM2RU36)N)$@6T^m>}!>~N34xNR#nuUB!@j}yipcucu7Lqm#}YM`pjTu+wN4T6s5KDv!smb!)ZnWEL$osvm|PBJqGC2_fA(9Qu4M=N1y&mwB -P10m$`4U@B?M%^+l(A7~;?l?n6>N3-@N8EsXKU5Vcw4uT&X+_tQczWpaCydsG&q`iwZf{+Z8bg$~C52 -r*a_HGb?WXe$6rt=}w)s%(G`JOJg?JS(T*3DZ+fpsOhvD@l`_s-En!>fyJ|J5&D_!rT531&=?rE%bE7 -rM}r)4InW_Q7UHKw;F467kMa1lSy;{X_<9hP*WyN>4_YjY>t(NRK?yEna?Aw(kbDf(v?ZVlMieTlO0t -~k3dO-8rzcfg*Q+$)-6h3yfSXR%S#3ex`ErbmsvJU>B&-HJHY)7DT^GSKG_*fh}A6#shjThLUlW>VEf -vf7vfTQg?bQz1i4b!t_^B-^J`-z?|}wU(&);y_JC`?bqDAvA!FnuC<%^y%94Ej -hvuo7TEMJDjp*QLi9GNdwUnX(@XLnU6{|v0zoz6zYc#X#?a-HD;qLJ`g*urJBaB;Hy~A#Lr^hn3;zm8 -Z>U_e_y?Q`+CzKnP^{837Wc%9dEo~|6F4UfvWo|TJLP9g>()oP1mFh-?n4rjysk{qpY5KW4~fCD$TGNit1fjnkPiCls?k@QA6+)+GMswFR_ktLAe$kDz56pq*;@@q2NDn{GX -;k&VRVJAu1fXE>Wv#Moqt;wMTMz(_jtp`0OIPd-Y*_MCMRZo~XhBy8 -G-PnNL%v0i8|9&AXa??e4N^0wf80XOqv_Z^5Ya%G5sqR?J9w(~@s6$r!J5Hah<~u>^0JJP0w6^{#%Uo0t?-YqG- -K%bKVZkn2R(r8(K>+wKP)h>@6aWAK2mnY{22&~ -bZKvHb1z?HX>)XSbZKmJE^v9JSX+60t=ek(v**J>}D4LEi?(O71-s;euu5=@JodJq-kSX4W~S|zbB8)k{Ivz-<>$=My+!vYGlEb -X;w$s}Gcf916iq)6^sr7cX`Y@nxqSEhe72RyH}+ObN)PAhAZm%ECE?U%5OH?YI7S8+eAowE7$Jh~l3+ -`jzV>wmm1{{H%3w?E4gU!k?9Ey7|^UQiEDeB`5)jj%;~uv^s>wOj>yduS=*f#em!ma!Yi$k@9Oy^Ou@ -+FE4npAFtKR&rx0mX5uZZ4OJU(4fqBsuHBR+zOmg^w+(erSF|?ajt>C?BQo7j52EPwN8+b;GvAAjJAx)x>43ls&U7jjFj7)mc%k7Hj!qTv8BenA7oOV{D?R)sP;U+6LjZ=-4u?IVKT1q`8WN6bb=BE$0Db(p-oUoO4wroXkz>z43L40_0CRNefi{juBjZ;>84AGH;!wRIH5TZl>ZLs)(K`66AfG?SQ6x|$&>7isEj4~C$x -c7nVf8PHBRTBw%)~-ggS3#NBkkiYV~Q+!`$65p5KQW>SRJx5qc9mRpy$ -#B3((F)2#7q2=^oX7xP%m0YNx6(d4uNYK;`jDa1KdT(_Ko}48&&nFELoZ;RjBC``Hj_`HLt#msE!0>& -hRrgzPH1iUg?_(=<>eRu|7&t8!8v#&f!3B^==YKYnLEwPKA?V~FY9rfM^z_tF9wWBFR5P&4^EnYjwH^ -=r9TX}O;2%?ARn9VpWCFTxOwg*{9Xt-kT3uro#tn8pzI&b8YAmH#~o-W$C1(8TAfN1RLsDH{hmbhI<8 -`R(B!~OD@wVRfE%blMs{ruyo}RYYz5B+8Y{*P2{Dzq$eFav^3T95#Hkb&3Lk-apuALe%U -XoGfE}ZAG8+r!o8^4XUcC4{XmdPr^7-u92(E8Ho&_; -u%un%H^|oY-?Fc3qCFW-3enU7RYsH|3*>ita$mEd2a*A^+}bCEKVqf9#*_nMTMR>z{>38-14rifHSG1 -3lUmQqL9TXO_yi=al(d6BU3t72)d)hr@ubWhvcO{*x~Et68T^ZQ90nb*iA4-UQ|0Rs!>8GTfyOt@8+> -9xE66v(os)HLdQJrHHne-WO1GNLHf&uSu&k{J!a|0lhJyAAn{PB^hcfII0EpeXjD;Y`5;Cv8f2q&i+w -NTD?|U&lgP|wcQ5XzVt*JtGAo;Ezk9K`@2%H<9*nbJ9FHkB|My_rw`Uso&W*_5A^53b`2xQigZ -Mh@!CRpVxsQ1h~BJBy%c_zMg&xx3@`%|1j#l^xx5UDt(4>H*MWB4$|eXdRlrNCB37m}xJW+$;i<&ye#>v=^DeSTG7MfzS9 -(faYVBKJ>vh{79A0HCLYwG1-1A%PmvX%X)qZ>0HxTeN76giG(2;(J|x$fvsyelRF2sGjzpDIS4=s(Ac -C0OTW!=#G}sz=(=gE48|Rr7{1LHP9sINKy4#yoQbZC~`hS-g6#aC?A$+}WNSEPk -u&miI%hB)>CIji=RucdbHouW8&Glh^qc&#l1d;r`q_aU~y~Kg5TI9TK9nXUl`_ -Vnd9R_k9e7n2FFKBeQxxk7&TpHb)?iMe?-u(7}sdm?^O%^APCsXH=NdfCnAb1@6aWAK -2mnY{22bZKvHb1z?Wd2?fLZf0p`E^v9hSzT} -2$Q6ALkpD1X9xQEXx@mzv2yg*!>U7=p#zvepTLb|$B1hK56o=rDmW3eyz30vcIg}{dTLfL~dL?r1nYs -6#`!$m5O4SX^rEc0r7CNE7jJ;xSFMj{+e8%3Ynq@0q-iowVs!3kHkXE8lx3{vq?Y=ABebn2*=S-DL*) -MFim63b-Vp*#-t7Mg=vTQ_M@*)urnW!46O3mEzi}IcqGQY`IVlCdN^+J}M7R2nM7WGA`8(tLViCZ~}y -H>e?a@wGH=$kjcod0&7{(AnOo0!=RMun|m?q%Jyyb$HRm#^EhgeqxU=Ausf_nmIZg6nR#ThXLz{#DiK -T9){GFKTV{kUCZRAzjvdEjFsYBXP2>sM)DEa{}p0^K6o)B^IXXl-9j`@ru1ujnGV$3@2XVAV0BXTV}? -H3BCVVF0p?Lvx#EM=5snoE|$D4n$#L(GM&#sfxJ9wn0Npc*g`-?u)ij+{~R-|ShEtfIMS?Cgt*~b)+o -mH9bVvcnicX+uxPX54b-94>?o~jv6K%-%o!aA#A3}Vcnjd`C}AH~LJI=y4$PX`LYI02{Tl+@$YzBz0A -eND8mE()W}B5P1mjtz+OokB7$6zXk5?)qK)(r{xM7)su|>`nTlVI9+pJUxRh$WWhLWQSoV08Vof3AjB -uxm;0`Dwfxe^wC*%q*D_qK#LiK-<@d^@?(1T@3V``v!5@|Q_IU6cwdWV -(t!~NoWl$S^kix{kY2w(e|!G^{rNwfWO{ae0bwlXO;b;T(?kS8ei1e7;lQF86e@+|6U@R=y;5zFr>z! -4YC4}zrtJ9dY@t*!d-;OlpD2pntOV2}FPv4d0}MQ$4`mCvsCm5w)dICi+PcK#pjs~4#(K)bAm-P+%-N -+Z1^a+KHCu6Qxuh$RNnSWWi$rTZMtt|4yulNK`f%np;72*}LfT2G*wG -l`S#sb~h4P-|I$46s^`5alqBeCOSD+ui;yg)>)1vpOhz;+O|Xu-Z?yG~=`eTHZ-{vjP{8>Qt#>fvK(< -j{~iWX33R-EQ-_OA+3UIE`wXs%;+eR>FSvfLfNB+0m;ao!a+Y7JPw#w2BWYyPs=f3ukq4`9e22wq&(H -=w>#IEZE+WW3q;B*Vxdp#KDnGD1|NHL^=#ixaKecr|8s3BiL;rnvD?UBjg0vEZ(kVlTrKCqG@X?1BW3 -koOOYOsTX3!?addr?@3*dmC`IYVH_J6Wtev?9K=b$v{95m -6R(7oM}00)xR^3^8ZnPD&&V~fYFKgiBYB7M62uxSqO+c#E+|HqO}r7NJ=~KObRYXblsU|S!&2QYfdW& -VvSsuQ`8L^UUdWo?({D=KPragtfJS3^|Bwg7JNN@fc`p0`aaVo@N_*9uMSBhZs7iY}IOGHJG#p)ZtTe -@F`9P`sE0LLs4YrQTCQ9~pa=?Q$8->)2_A(s^R6m*LXwj2d?#Hp6whOqvpSGWo`Gd^@x9)_1*~l)$^d -`n-LMj9TKY|F(HwM+{bC?ky0~cV_@(oeQ0WML84-Boo)D21D)Y+lLN>TlOf)cdo|G@>?$8+I;Q_PYd< -dmU(9I_pQKUO&=T+$b2z7tzbyOH)bIz&T#e})*vU`~Q?P5R4~oBwg-&(4yr2gi6s(|hE4)oAdgUqdDx -yxM=@3Z(lg9z>S*&%V5TVY6n?Fx!vmJ+E!78Mvu$wrNnzM@TwAJ9%p@nFOqQitutKkmt^ -C4@H><&()&U4#Oe}PxgAM!~U{mg3%ymN6IpabmJjR5qr|2&;nb}QZ%8VbmtVPx+YJ<%zT#I8OR6aoHe -JF2BRg2t=od~$}7wzE0S+tQc|>$|H@?~W4oNq98;qe>hoS6zO3{#^oFh>W*71gm6qqyt?Cs@bc=i53)Nh(GpvNC6j=}mdGCbq_;x|6wH80TBBun|Y8K5%{cihgX(T$4)G?4;H8NudynCy+8~q6U^ZuXDEM -+0{+(GlnaVK@=L2yMgcX>~CL8*@5gvmXR${Kd#PZRwgJrCO=??Go#P^i|HQ;VE`OsE{pt&TbH(zE?S2I(&zS$%+>-v^{V)W0x4_P -$Xi%Yf}%n@6aWAK2mnY{22-x%FZde+003VG0018V003}la4%nJZggdGZeeUMY;R*>bZKvHb1 -!0Hb7d}Yd3{t}Zxb;Pe6Q61u)02Qfz|=>fK&-Y1wmAZ2Bob4A#`%?_7W4vKH0uB0rkH#zK`ZZlsrWC* -*iNsvum}itP51uCJ)wXe|)6cFLt~1D)4r*@w@BXno`XkzJyJs47SHdrL#+_R3$QH0y`tMsDsj;x|_19 -3g!Ic7sX1sP)p5b)yKHn7{F(>DcEJ(^O*01E~-kaTn1$gy;qJ=kW-8dx7VXd_U_`{$5HnFazd~B+@kh -?$z?w04ErHp%4_EsHGSEHIlf9yGJ=8UDY2M|4)mpXl@Ow_c=0?D2dP|}D*1CS{@f=5`YdHgpQ13)r -Gu-bJt)SzJgXd+YJFIPDjzjD9dvi%Z;JpKtrt-{@yjZc#?uaBM*7HaOOxHP`|Lx7mUHKR0YpKC+~PeR2)Kbkcqa=o0j#=RNE0tXn` -TD!Ojp&>S{SnGK9Fa)}N_H3e%9TpW;uOuSYhO>O|#Rz(|IlXMI!oMQ%ojESITKyzuJ1!-$$xHyd=Fi5 -m*+A?emL&xRgYkEdI)4R2#SG01rVy8Et>8)P%@6aWAK2mnY{22;ZYzN;w -$003A9001HY003}la4%nJZggdGZeeUMZDn*}WMOn+FJE72ZfSI1UoLQYt(3uz(=ZT*@0I!vqh9Dr-8? -`gI3N%g1Q%{ql}w#UW7e@F+gTKzp0VAe-gGNK+MXiM%>U2KXScDY13&gspFwuLu^zrk=XdbE_tI!o>( -zSIgrwqxj;5TC{QZgZtUL`NZx>HK>t|_=?nwJkR+gw#S;BibtXIIl&9ZE>%K};Te10Zh*3{sjd`WlW_ -s)N{M5?S8cE`}!dc~q}M|}GLj~|xv>@UKb%@^|ETY^g^Sn4e~PQhRSjj=H-25b2cGT|Z^2bCYKbX?~L -s~w<*%m<`)9wF#d6>zkA=U(gwI`UYf$2-I!xBPeFS3ZgOWX(4#xIaqW7=Dhmv?RQ-Oz0001RX>c! -JX>N37a&BR4FKuOXVPs)+VJ~7~b7d}YdDU5KZyPrj{T?9yflxN6w2)`}Wr5a3iq*z))>}UW$4SvOyd! -Fck{ENyS&}11O|!p!?{PWj2l9{$u*~r=!z%WB=~05`ra`D_OmemU78-`Fv!VrVGKEk5+}h9&=;MU -(a$xp`v{JAU)>j<%?3Loaa%zVKP-Z%4u>D!C=!})Q1GQF4_OfDwz>EvWus(0Y_ebA!&{E-TtQZ&U>YiFl -X@A-x0aD2v15)L*t6?_rr*DFKFD{^smaJElQ)P|9iExF`~N!CoW2vy?Cwm)YViJu8-g2CuahAXAAM6v|Sn&x6lC|PpB%+^>2VM*OJ@+ip@mnnb(+q|kb+^) -SS^Es*oxgE{mCsaJ6#D)z=^La#$mNlT;4F6GLw%I}no)E$1^_biM8kLq=TvhzK_oZxqU+aS)qW&Kv)aUOX6sMIn;&xvcwENxQ=}p4Br#_*lK|cAAn!og9Tt!Mcd3Ux -ziU(e-7L>dJ-P^Hzz44scLPJ_$ju5`wO^-FjbR+XxrU=<8rjw<>iRicngG2#{-K7{`a)TV|Hm^hHZ)k -&`1Sl(*3n&Dd0HT+sv1Om_@HP%Ns`s3lCYNzxumaiVmKKl^HTE+F -Gf#m>ygHc?XzaNBKDw*NZBQo8VR^|YLnmpp;UNTT1Qf$Pjc#KXz9D=0=JTD(0Q3MW*Bm8*-&4gr$zY% -1obu2nx%8#4by!2-M;io;t7C@qPn_cb)Ua?E)i2v4($$ll8kDGyYTZplC;n&K6(>P+wQRQutR8{6JN6 -Mu12%=(Pw)1QP7lwbXXx}n?0BaW-@!>gI%)(mR|@QfUOhnXwp6Ja8-@hkfKAZ;9oc+H?k&SE}^4`Sj&;JabKU<&5xAjOr}gGysSVl6n=(j5E@l|;pLnUq+vK}XHVny=@F^Z -zMj}{tt74~0l?rBNm%{fkrp6fXxY}Fi*|yf)ym``ruS4C6z%|=5meeBfNV(%VTXw@p2l_rcr1_YJ;c! -%r0@pM89O!)wye?!uK}Goubx8&cOAlP+_Xz?`LE6&bZ*sQm@j!PFj;JgDHhJxK9wbdA_-}U*fo@IT4EcK55 -^C4d9lE$Z$97A52r;ZAGBZ?2-iGWHwL|MHq4G`%Dvl=Zvqwsd`4l;HATgTPdX -V044%N~F-Cx`^e?!GEdEg|c{g(71=d-jKk4S>)t~;!p<~>mmo=MA&b-U|w`+dw84dQWJ{|-j(A>Xu%T -FYdM?F$X~zxE@}gm8~uH;$9e;)9c9!e>z+YI5B@#8ob3JU+r96veha^pKcjf>>d)cb=udrf4Jvy7u(A -|%W!``kNAFJ0U=W(T?+!kl@da##OmbJ5{ax^TXEpo`j#g5+`>=ATZbuQ!Z^PGS)TiOYwX9Z#ORAnVqu -p27|F|qVfw1LFcp-OEx5~6m-qZlDMKmtYaBzy16x)3_d_Y88=%T5Dx#szP{f$>31dT6Z8jHD1M3J&Mj -CtlZ)M`Qd>_aL{a~Td`x36fIrEXQa>P|hbhfyN1$f)Im+QdHaaGJHObhLE3kYPzGMq`412tBfSi)lJ` -4)iW5w8rKNy&o$SFdoN^-EC9-F4_^py8<{8FKHO6(Y&~97Y9$1Fu2(d?FcGGH~wz8;YxQm+Bvnyr(gr -`2OzQX8~jSue;FHA?1FUtU0SiS-F^ETfzZ3PW%e-D;-*F*gVpYzFnM)F*4KU->z2)^=#(hL7^c3Zp)l -Ny0jbM=(FVa?Q8pKe)JV#%^XqpnNlB#Ss7VbZ4k_~7bHA^`>qaU= -SWS7A)=X=vS5lyNRwO+B*I+eX#*ujG!sn^JypgK5jx27hBhSw;6__IH -E+-d@cbnK;%>R8RU59iO16z(4~U_r$=FgIGPs^(8G1j<63wb -|MbH74u~X9MD*5pjP*^Yzfgik?TGxTb_=Pm^!LODJM8r-OgG4l|^J|hnhV{koo0u0yK4#K-&NDH-*Av*fs*gbmP+JxEqEA0IHj78!LhsoIxv_2zT -f;ZIWdQ;%c3Ybwe0e8UrSX~h97q=Te)rqwHOSY1Sm`BwaVD3Bw4H%%PGQ!^m&;%mJ2dHK6q`Vis(csCLnmuv&uBbeh5@-)EM9R@5K2NkQd5)f@I}Jx7`eMc;JZ -649k^zLI%&rYKes!siDL(GY^U=V&~;x#(3;Rap*0m__L#65OG01TE|&yN -1?De!l)weT`)jZ-nuhBVZbIPFt(rEUGAO=)RA?)rN&J;G(yPnbs2NZWeZIPd;W%jr=WYUz{FKWf^_am -Srl0pq-~%9u(2xef&$3^Jqu2g5))%$54xpXq#=}z`_qq8eWn~D>@EdGHTY5flz`5#A>-`h09!c8X^ -TY>e9C43Y^`;c5Mn06>Uu#*|e26@nc9%Be-XF)L54HLPE)>8`**!s|Zn!griG>}$>%GxMK-Zk|1zTdtOjHouv+K^Hnv2ICPI-gRd?&!n(|vLmi;hK&AI -;zzar0Z>Z=1QY-O00;m`Rt8fb57#0+0000%0000W0001RX>c!JX>N37a&BR4FKusRWo&aVUtei%X>?y --E^v8MQc`kMC`e4sPE1c#D9K1HQAp0uD@n}ED^|$OPf5)wh6om=78Ioxr{FPD;%5-% -43P)h>@6aWAK2mnY{22;6sevW+s007Yg001EX003}la4%nJZggdGZeeUMZEs{{Y;!MTVQyq;WMOn=E^ -v9RQp;|`AP~G;@;_|3#Fi)@5Y;&}r>c)buT_OmypB*XSU{piQU1N)_z_30aw!K`v^%@Q43#xCG_qm*f -Vwo6HDa?9TdB9~fYwQ)LDr429vWdCf^e6BciA*alWOQ8wMVOkVzntzIi{rE_4v0C&(`j}45b%DU;K*4 -XW_71n>viccljgRQE9SK!Z~=+&I_f44;0oym$DQdvpH10OcMx;5b}wQMTgou5YQMOA}JJ*P2Ye(Wh}_ -6-fRHJ*)inYDdQdIP{0?_qDDf2bZW#fzL|XYDV}@Q&b~d=yY1hgUq`FeYqTgE$@6aWAK2mnY{22%#ppv$@j002@M001HY003}la4%nJZggdGZeeUMZEs{{Y;!MUX>w&_bYFFH -Y%XwlwHVuO+cxyQK>mRf`e1d6(Y_3r0e3Z)Y$(unMd0LNuBR{(9dpseBWbr@kbmDfq(qUF?OfLQA)yY ->{l-H^QA9qUekMP?c}=1yI(os&RV@_xTh^8R5X>&uqA2*)a7Bd#;6l_TQQH--u1SM1skR9@;h9Rvd&L -C3Dp*4PSSemtv`ENwyJF_=1r-T7uQ -j7P?#6`&i+oGnOt&D6kbsvOI;Lv5_`>HU;<%+m49F10Hl;sF95s?1NpO>I&i -=ljFDUMxy~F&hJc-4K3D;=$yzwE+UC7p;b;cOz_3lO2?F8L!E9&&KD@3RJ9_!0<8@ce}bvCs9K#2+(; -Rdd?d -?D{A2sein`Pq&P4CA#73`lin2|qk(5EBc`#R0?fOlhA!!5S4F+^Nyh7S+IBDw{BccffP1>WBsOIkf$8E8{XG%lIFp1V%-!r3A?5nb> -CqL)^HI(YT!<|`G~5K+i(9X3DTyPous-Z0&XAWO4ioueyJnn@VhHK0cD?ahd6bd+zv4veyqG~|kvauD -lOcGbRf8+LQBG~z2-VwpsaJDU1LdjP~$nmSIFtXL%7Cy<%a>_Bj=lt9Gua043vlURd-ZJ-6#l~c!n+E -%hhBI{!FzbKk!a)3<7Ca8Eca|p%(Cj1THeM9tt8Uh0<>lZ+_>mKJod(Ak2-AAJ>-bL7Sa6|u2XG6)2amwVkFDT!sz){^Gp%E0t-!o^m5bLDy-m)Wr?R@ -aa;IW)5oY_X?s;&!Q^cyYYy@6|~0KZ*6R{+}^=d*O@R{4InMQ=c0TZG8Y++*#aI4H316m_eQ?`4>m(4 -Zy@+7TL@uP^sAC&!aEJCb%vjo2-gwJt*=}ywXGxM`Lz}~SyBB6huM*nbyYC%0mtVKysVS}LmH=RRvR -wrs$>1(%r|()`oo}#B -wp2(-x1DJI04t61cZF|B>y`tYf#5cM4lqMw}l@!$W3EREiCVJTFP0?-x3q}oht4D`5J`P`J -`j2F@J_vu#IWlw(>{foRpPcN+5sN+?!S}A+z0KwUOeW^#&&(+a)EJf=JKu -`9SUym_)7LvgPe6;9B00HThtn2=Z<~_0qFy>9$(r`*30eyJecZ$?9>_34~v@Sav0|XQR000O8NLB_@J+r5MdjkLfQ3?P6CIA2caA|NaUukZ1WpZv|Y% -gtZWMyn~FJ^CYZDDj@V{dMBa&K%daCxm(O>g5i5WNS;f0(KV%c!hkuL80tuxQX;+CvXL1OdTFw9NAnj_0e^O+tdY6^-d+WCdi_=$F&>{v_Yvo^_N_Bt$+Oh2>H2i+MZYR8v&%IH-4?-2FXU`okJrh%YRCpfJd9VfQ(1t65*|XN -#cx`Z{66U>+&oCfW-E@8~ZjCWO@ga%p4wUdg05i(MLE{L0~tK?O?(bQRc#f3T+L{ezu~V)CAtcTBUXF -^?+6U{HuyQbKH39yz4m8TOTaZ##`Ga+x+upBQ&UIF-l`Hv^mb=rZQ5)E<{m<2l!0o+>;dNg_A8`m}|c -o9S%y;%S?zgzA6dl3tOUg|=xZ9d>REW{e(}RCUHIdwt7a-wJqr+h*m^QY)ruF!?Jqx)8+$sVVoDE|Zj ->QT~N9NUCm;4z`)SIPj3rDB7NSsRhpw-8bm-XQ_Lvf=30AbR4(}PF*t<>Nt#)%jun|0)miVpc^w>c -{nsXQjbY89NYvfa+u-B{W`!)_NmJ?(95YL52TUODve37BplYOc&us71C79=S(Gf}K{BZ;H+0o~NBg*i ->9r)h1K~E3Df#mTRq1x_nhfL%=?~lTDM4@GF4^b+C3<@lUBtgWo1W_z6DUr_w*d-yB)n6OU#SMjspzj -?xg2g+}>Wx(4tW-3uMUOqU)a7}S;z`L&=FkJGlP0uZ|$TmO>lF>$fF=kw4zp>8j0gh3K6xd%`17cf7H -TUa%}TFUgen!geF{He^t&-PN%#<*M(SfppXom+)31jo)Eu@U3jI8K+zb~GH@CicYi7a+DtG8=raiCMp -9^Q-7>?`q86k|s)_r{T1G*VcnFKu -c!JX>N37a&BR4FKusRWo&aVX>Md?crI{xjZ@2R+b|Hk8}L6Y+=C>*k?#iFdoG1hh4Xy;-l~Jb3LDdJd4HRJH~{Bo(c3Z1*RO( -zK58?yX}zxHCarcyAFkm1EB9?u!1{LWvLu0MJ_NY1siy-q?~FAl}C1=%MsaKbf^yJaUX4o3;61(1}mA -wAxTxL4?Asr_2a11;~-krTUM$jbi*?Dz6Rp7ggeOTrh$jA@GW>;pY>>rnChlIku?{0!rKb1^di4E=cT -D~b((q3rsyo!5;TXL8{l~c0-jECtcH+O)NJa*kgD54j??-BDqm;J8TAF8j3tn-)W#47*)n4`icWhlvT -qm(`@GN>Df11iC)UnUPTlUekC#-j*n{B1*v`oOqnH4K2mEAAUb{R8L3+0bkJ%_$Wb|y^#08!9mwZK$M -&UY9v%#IT_KtMZ`kjT!6z-f}+2d+H#UnX9TS5LWoRE;mOxl;=1A++ -DlerC>2+1zb>(IO9KQH0000807zB_Q`z4?+ZGJ -~0P`mR02}}S0B~t=FJEbHbY*gGVQepLZ)9a`b1!UZZfh=ZdBs|7bKAHP{+^lq2b7scR4cQwbLrfvReM -*TugP4_@z~C^9oJ=G5|VhP2nGNxtEvBccNZWDQk3lb(t7S35?m}6&%R>eY*k8S*t{wdBW13iKg;Y$E* -FceSTygl{ZvYw-Iv@fn-L|N$4cdSb`zCcX&9U0c-8`z$dN_CC|_` -;@OldRdjZn6M9}$z;Lv33CG<3wVG2%<(L5|D_Nnmx=#T+#7fu?^{u(B5wrzQEdL -gwMdWU3V;?rW%pUJXEKP=OhvuLMv{1_EPS@Q1QpJ^+L>Ar2l!@1D(<61=D7g7Q4MgHKfOQW3xUkgfP` -YR+LEG$Fz;zBjN<|{9miv&d;ToG_;_~q;r#OC`}pm57jI84U{V<9B|i)%4F5ek`pP}M{ht^y -csgpH}Icz%fj6t~J6%w+bHiO{$8o)S}h45zg_T#aD$piGAJw8g -kz3(Zzfxrfom#V5M$L!!wG;``fhN`SzrZAbW?B?MYlXGU40%X^+Qi*^Nh^~+_BU!jq0Hh1W^-8;skbrw0Y`&fqc3eOv4!dd5yH}i;hnh<>adq!e)h0pYeiGe|g2Z2T5XeTTqm33DerUcy4Slo<;s2CZaF6y!(l;A&{amVvY -)HV_jE_P1P;z0trXavtiA59l}l)&^0F?Z7<7qNHqof~DqyvwVQH8^N!rIL49irX|Ov0ln5Pf@kVP^?O -`sf~_Zh#p*|k8h5^SQT4Ig*t`D6-O6kyhw?MGm(Tww^cXfvEQ+I&e3AIK?o}h%aHzr^AibH0f}gp6+L --&{J=C2L^bZK;R&`R?trbWP;loc!jssw5RvR@#LhNn?-=DoM!D8fJc-#t6hiSl-+I>OOw6f9&593ig9U&XyHX3aU;bq?53}G -r&u+f(X7LsDWJdD3Qj3OJp!fl5es_(OvJ}3lgt&O&Hj-!vLn+}e -Tn2vYEwEOlm!~kCnp=Y-db?mXtDv_PFhpmVF0NYOOPlX$1Nmn~>nN2^#J|{8f#6# -0{7h3MrO|j=RJV6a$TTdDA!9nL8?^9=I?cKU;79C$5UhfZ8G1eopGT>2sv4V`hi@&vrN#mF(_k?|}gx -Y{#xXE=y@=$yPdzDv(Em^|7D~v`hFtJ!H8hIgpQ*D6Bq69Ar)#&QQ%WEK+g;)Q2dHtL5XfL83t9I+1W -3dMUSZvaS-M$!+7F;DuFVk$rSDHVZxVlw~8zlN@p=4Ethwc7#b(2Cq$6nFqF(7=}Cm}M({Fg$rOTzyh -M%aVgg2bCV3cn;vnZfbpVGOwNgZZn2Z?1nkZi*K7br$?5h<=t?5pFfs#!mQsXrdUu6g(&TBUtUh$%o` -w4hN^}s$|XHcu6l{M>Qt87<@reM -crP-x?vk)LLOkGRjY!P5qK(UbVOwW*|%+GdqZ*R!LhzIa4_INOW-Nee=HLFu{jOY~0O18s32uU -p~p=+|!pNJ3=+L=hZVV>_bv%VLj!Pugnt^a$k)hN;J$DDL|Ho&_3@8)EL{B^ubBTsx^J%wDs2OvXXxrD5iuO?Nj3giScWTM_?S=1Lu`P=OVx=Wp -ZORS1EvT*1#R^4ih8Txf5B~0n=_>bq2=5{t(t{_r-EcIdm3Af2kGKc_T?lPv&8NL+?k_`hhPi~`HzPdw7?LF5G#ui-;46tEC)J^lwtR>#N9JC#0*CfD1?V8 -4Ub}RCY?am_yYCj@|X{K$@sBTQUE*O;fI!lGZ{$eesu^n#9(U(4#i!5RMPG+gbHV_nq*e?O0uz6@~8* -c&vXOLpt0!B(|pC+yc8;WQVv4GDGU*61)0(Pfa01q!=AQ;=@r9GXYX!9KA0X~JehfN#T$HD`qZa_S)l -meMy*VH;prNEZ664Xj87J6C}9!BhYaC*W7@(At(&o!_Kw_$2li)2}33H2k_O2UFV!^;W|mZnfGu&u_p -Xb7O4&jpG==Oz3XvlPU1dvKay{~3J_eA5ZXvA<28imkhb9R^OVvzwgydW(uH4*W!|c+FhlZ{X)jU|J>2YUSK&1AvJYi2JHE*v-9=or{4|aljrh0q4%G1tC%reXv^D9wo8F?P0Hh!$OIv&A9 -{k(YS-yzR>4!^}pu>vv4= -js>Gdzxlho%N^*7BI&{e?81=e}n&$hlp-j@ZdPR2fNzW|yK-t)w>f{YG=NLerYS2`~|*VV^#A>iSQgP -=aPn3Srci)lQXYA+FI*jqyUFfpCXwD%V9Wc?!}wtFvHv2EdK;2$0X-!UTB43P>ylUqB9L=@fwIR-v$f -3yLie21V+bf&3ZO8X|H~ODL|#wX?%A)?1tktjEKA@R0(0_~-)|3Rb*myVIqRc%wskpeoCp8rA3+1%a= -P^J|EN97MFO-g#chO4~R|#@MiH0>%Wh&>AAhQc6wE1X&BQ`|U)W(-b3=TUHR}W$HDUuwjN-BusMH5ls!6DeCc2j2!%IUgKecM^S)fDgJ5eE!2R`})<_-%P-W-5uEyJpj~?b?cO^KsHDU6 -6^~E>yp&dBzbxTNF#L6aP?{$ubt7+ApMR%>(H%P({&Fx=okSB?>_g|wtvbIrQ)Vq -guy$sBLo87sa+YS|5^u={uQ_ZL+E!_?QNy9roRFOX6OgL?KH8Va=~(*DU2|Mi2BUjZ8V(2gmv>90Rba -}$^+sN+DkNewD0lhEZ*+wD)2u9*KnR{=efuh(jSMMC?&zJe-s;f>fe<0`1|$fE}Jd7Z@Mzx3!VDl_|!_svzv-!^|l7v-vo=@Knm@q3;9Tg9kE^v8eP{B$AF%Z2k>^}_kP=&fZcq=G~R0L6koff7mQ!Q)ukhkwmX5PHXWKvi6A%cAO#DL5}SrpQ+w_?D07IY591`n(ZZHb$@8lE6*$Wu -fIVMlRiX%C?T+@W>2c66)<^cuvFji7=T`jQziQC%64o)`1E4vL%pTTJjxh@1JkJ45s~Oqyi10rpOtxinf;n)F?Q8ANnYlQh?RL{GzTPo -iyXNFkphy3_Xfr*c+=1U?lkD6d7{f6V}KC+D1|mqD=vGAr5^oitSLz|DX|G4gsXb>H{~_{0`2RGHhFR -LAY(xawn@EWldcwvEEACo)1($Os<>#{gzA?z!FdCA)hf_vKrGRw=tbFJmoIn@&=xRKZba;(-aeFkAlY -f;3n$>8tKJW(hC~t#b4438tK_+67yA8KTt~p1QY-O00;m`Rt8fFHb2)?1^@u~5dZ)r0001RX>c!JX>N -37a&BR4FKusRWo&aVb7f(2V`yJ{QyPmc#jPMiyz@%CUcL~GX;dM!`cvkOsO8~i -)xh6IXkMFAYR6Sm%7=dM)%NPwN#S6D7p8{qy>KO5?&;Vk1jy}=xGiGHe3ZIM4S2-!j0R(w -U;7Q9adKCFa`pdAk$is2+d`WU=PYNxZW7ksHqPi|jE6-__;hD{5@yE|iAzIgI;iY4~l2BR*uS`R4I0> -9)%CW*UYqja%67z<+pphr4;?F#H+IW}eaPGrw4d8OEnp-!^*esw(M{u*7UjE16U@d)R%D7U>H7l%yH; -cGHPoZ5lybWs4L*zd=Z*P+CgQ4T^OZMysHcJ4RoevxLn9%bkIKf1U9y6;?vhYl-5yO4BC=m&`kAq_$` -3bF0*-xF)WpW12eqA%sFkv@cEgR3A7uGv=uYAS6WT+ihi!EEpREY>t(omx%(geX%caj1lSY>L-N@d}v -v0Kir4fA%JI-4qjcF~kft?8G109r0%os;1}`+O|fowN=)!PC9(E93?Kphnb6TA-!3lqXKwyXerf;Jw; -Z9{$srCHvGl4@XlyE8tM-!9{@HY<)$r1}x}DKtr%EoF^`<0Hx0-(}D8uCP^7%8Hpe_()1YwLf)){437 -aIi;MY}`En#hPb2Sx23R?)*#)gGk2gTIahxQ01bNY`m{LzquYM#e8YBDwC752l$D8z -Cm|FRz(w#7fIDqbN7*_t)>d{Bzy8eT?HgK9_(FRA}%#`&69!FvfMeHt -uif3Oa3663HU-H5JYBPLz05IxcY6YULNl_D>jrYATbBY|xrC+KX!LK-8hv?MQ$SYoterND`BnJK(!P7hFZ@3 -jBpkCwI+xSBs>DjFF?*pD~AyORW(Dm7mgvPlBz`84KH$5*=Dfwrb6@moHv^|7{k3e)sCdE8bfujdbAe -DP2O}i>-^~wm%`fAwIG+1K{AH3%km6m^-XcPEIM34~1+aUr|P&r%?{esBDr@iGV0nJVmo#i?IG@Zhc? -LSY;taXJ5M+l2q2NKWg?U1tQ}GU}>$nQzeaZ(NjLpCenB^jV21Q@3sFzLn!TDetsGIX=sA9MS`9F`g_ -hJS4^M)H|PA5L6e+tW4Syq*Ym;2;pV`X30sMGJ7!IM8$6jt`(*teu}jk2NBw7+(qHH}^FNxM)!_VcOt -J$QBbLo54SVT-l0n0HlN( -y+hW@baiyau;M*NWklK&fwOe~YVeAAsTPhfODB1ZeMKxNV<`FSKNns{=WI -?hLMLN0;hF8inOJ-cQ*tfoC36-PJ5!o7GBz7qXg20X6PHaXQ= -`aJ8&BW3M$xwA)k>VMR>Z2gJ3q7;9P(k5SL0|0Tdki>rww0wteJ=i@$7y#&!yxT!hBppI3Ao=bPST}t -h4LNs7e!D8b!j?^V3O?uwB8|zw0Oz+BAe)wU>!-yp(2;!yX`Q)V~#+&~AhC$>|U{`YZIx+fvI8LnN${ -q>?W6D2JO9KQH0000807zB_Q&wWVuiF9u0D}hr04D$d0B~t=FJEbHbY*gGVQepLZ)9a`b1!pcY-M9~X ->V>{aB^j4b1rasbyZDo+b|5h2grXQvO`)R^?(68EIZ0cT4YHR<)-=fqbxhIoy3R0 -miWj=@{uXMtsv~3GOwU2XMKS0E+}h+o=&EdGG067vRs*fo=>yN7N{vJt*=DLr8U7@-C>`a)BAK79ZV- -u3nKW58fEmm@>rrrBaxQV3Gg$U&C<)Gk-|}}ML>eEL6E`}s^Cwc4i4^!2j&2U-5G5~!3iWUi~(gR2(4 -pMrP4@QFH(BVbJ8|Yp2ICX&)L@Q^1U!yEanSnzxg-kaGqleLW&o|tmlj5Z1Btz!+fob@cRf-uf}@JJ^ -rheN6OtkY^<5TbX-2b1Ahi)Ep=TWX8?UdP+%!)9pFvq8X;Jy#Fk4^dju46!)4OC^F)fP#q>xO=m~Zk< -U)FAJ$0#oU~Cfuiwu5k6rX6a?5XD4&R5uoz`>=WSa^=RMh?vc@!e@9Rb<@uDb-rCG!`6FF{uq|cktxU -I*pNyVGd2R5|9CHZ#YSAiZUwX`PH$k-1xFr<$hh3u(np8T#mYythmchoFVqChpk*5WdA(S@CzfqSxHQd}a-^-&P*6cl(jJqn%4iVV(Up~w_F~w);gcsGQSbth6Gy}nX^idFkI%!YiBOHgmQXw!XY2q-ZX(HR<%TD-=EB@S9Qy*{zd4sl>J03QUn~?I -n{Faw}e$%11~YI-WH0i?hMQbXXUCf65g2-YgK7^OjCC7`47DDRWFWadfRN7O<|HaaHlPF&+jh6mgz!5 -da2v9rt*A8uXHqdeM_fTp+e`BB-?L|R2>qTo_RBTd^1DKs@BGVZSCz%VR -Qwqt))7G?ACvm)+O+zc2X-|Ch*kMrMSK6ZEIPx^i`-_8&>n|g&)zCIexSk|0jNot)+6pAQWqyEG^4)R -dXi~vXrh(L(ijdscmX{7kL7&!dT1!{R^EsohqGc_Xcn!ZFYfD+El!h|A;h1p}cNyvXWbiX&Q|8*t(Ne -TUrKu?(Xiom(MEWwQWl7gavmJP#awf<0O961#svb!KY9gfqy|O0TQh}FtXAi722SAM-_grtm7rJn(MP -FHOFlVm$4vv_nM}*)Xt_U>|oz5d5iQYk^Ho7qkY{afeAlI8!aFurKp5*oQ^d5s>Tgsf>rD=qF-5_2Tf -m*?cAT{W&QcGms}LMAE~5E)Ai_MMOg$8Ln_-rdwY`N-a7OAj5Pd#{D$^%Hi4HH>>f`h0mj&pFH!W)Ff -n<76WPb+8~E^x|GW)|xd@7$ZOsj@!ks=qiLpsh2#1nEaTyQ6;J2c~MxMCIPN+Nd8L>PCov28l+yOTNh -U$Ss>t&lY#$fVP>`qh+zTl!cON+Q?S(Y(gAyqyB&A5VtfI}loOjC8GaLFHSt;JYUF?hlZ#g+6Z5;~VH -L0yE8epDK{q@5p{j$MRr7ZOw2jaigB!wPEIoY$!$9u(;QxWJJph-lP>1tYL#EfPb04}-?x`r7WnfWWY -u5D+*GjTNvK?8x9NvdY4c`|YRauNxMlJ)N*A5RWJRDxehV=uYrs0v{7P>`!n$2}SMYRU#+zU3FT0Lnt -0!4u|1%9Dd$zS>3K|+-%nyC>oXdEpkGe=P@mWhdz`4FOjI0?%^+|QSl^5-xH_D@73kGJ!2W5Vy1yu+= -|$8YsC_utX$d}J+hdEMFJ*0z}LbIbxAv;k0|YbLo5%u^~7)!COm$J{wua(e`~4M6|dKLn#nZAe*5ux6 -Zw0lNRsGI|0dtWB0-yYVPZWtlHJ%;rZ!>1MykL8(orQd@vCM|2z0W -OT(O+!i)zB-b`(A%5SR}DneZzf!-+l8t|G|7;c_wi!=_QMNj?Bc)c*ecWc$%ZdCKT$R`az_FuCGb;&n -|J2>Uarx{QL+%ef$~xC79x4n?qJ&N>iK|0{e~yTZ>HM%>)VO -jlb6%Wj47xER2o!R?E9b6Ft}Z0zC_(D0W%=o%ZGwqQ}#|n+)ZvVRrrhWNtB(_AajU1yd^5-B7p-22`W -Fg=$S^ohbY`Q`64xF5Gcn*Hg>en|}dNO9KQH0000807zB_Q};K1R_Fu(05J{#0384T0B~t=FJEbHbY* -gGVQepLZ)9a`b1!#jWo2wGaCyyFYm3`P6#Z`Se;Aa4<<^#y(m*lIE-Br>LTQ(6NI&du#8?{H)5sbzGx -n~N=D+vc89i<7rY#g|Fj#XRbMCn>IS7JlQEFjCVGZN#ej`NAGMNj;iq2`Q_Nf0Buvu}dp7U*%%PewN0L -N0n+R%P8K9B2_vndGdj;$*<*WQ=7l#>%O)u;HuzxBpwn`TB(Xg_p;dYT&BNMq;C)?!6xJJD9Jfubb{r -0#P9*~*Bwq=AYS4QV>*nrV6PBYl&Ecq=g=$AN5kNKcz*Q*-LV(?tp0r#eRDpY(-WOWU!PB>tyLI0$!a -I_^z1ghc|X4+g>!dW9-KvO&R4R1D06PzQ|s$Cy5Hn~-bN|-oXa9p)31PO)`2LZcNf<`{`%X6KbzJ8rX -pi8c$7AdLnHER<|rWaOJ=N|viTYNMHOP%I&=Kg4@=FZLFo+fy(In$S4*{1CXpep$}*+vT71O0r=J1>_ -k=F$B_!H%n{2|`cZU#}u|nC7eFwhdgFp{r4*QDq$%0Sy6`u(|dFIT=&{hqJqo8lyLFCXkEWBz=jx;K1 -3p`qDwJXC32`1A>3#300;Uu2S*knHG-0+Oui%Fg{RQC=}f;e!^X;?51Sh^F`)*dc=QB#^^Bf0>dv2bH -;X_kw{TH4KSMYX;t4<%oq+ZGajg;~6K@$&g`Tqst9<{JbK+0(e42iFEMntjlRlb+bPCNZw*hm4#USDP -}IHk?E!_UNi%O9-B_qXvBBN=S|@yY#+BcBmOBOi;U$1@|+{kID_;P+1HVP3*?tEB2{hUl@qt!;Bqf?B -mq6(*v68n4G=|X&o9ZM*$suYz-;8*5-3}QmloIp^dh)B8?khZg99sK?D5;W8D-6@sZ*F8T~41rl0pNU*Z*jZ!5yc;OgRvefRB4e;?)wCQ0(4<$>`vmj(I61xlwv_lx -iz?BIB~n<@OXG}CXy10a4nopfs-_sUm^U%>%H}Q2QAzjVW&m@Gr-P@R11^gSyE5U%2jOa!3YzbgOgn8` -p!rHs7$8S{h2R?N6Q^*?SL}sJtmQSE{g&|5f-9nv4b%C5=)xl -xeHL!;eD`-7vuoIT9aMtBUtcb8c~eqSa?Z~yNzBYERwyVfO3kTM$V)9L&o9c>1#%KgQd1O4OEPmZOEOc7^?13Il$3b60 -8mQ<1QY-O00;m`Rt8h6YR5gk3;+PRE&u=>0001RX>c!JX>N37a&BR4FK%UYcW-iQFJX0bXfAMhty*7? -+cpw^UtqrjPr;#fPEk|fo))(Uv=sdbDX-~DDtiW*Xq*O%5sH?~9$hx7M -0LncY`n(Kp*ckEfOZ+WZhve30?*-yObxKx)Hmlw}PtBbl-tZp@z+oI%b_3ysX_4i^A&;M1Zy2ROQRloDlKXkM{h({omeinFbdmlvHB_jOgbJ61|w;aWw5L>Vj$!+`iF&BT_qjw8u`@43<{ySzw}1Uaeqos -gRKvT5o~))i9m%ZsfPd!~;a5_SWgwa1iwUza*%uWAKYKooGG7vr~Irk27~%=O7AM=7m|2PBfZ;{n!~1ohCeqrO3UMwWz;Qk$Bz=EcX`1-mAu -pJrFr~=ltQ|JZUhj0En4me{$Tz=Zz&XmXKu7*GdmQrg-K4h_(^_tbZW)aUEOuyBNe!a7T`II57e&MUs -aNh(}3|6yj;6S>v^8=zlv{-*|>K`2P=^Km3IJ?$4$z5g>v8X=*5~n`RDj#5dDqY7dYWtu6t=6R-<^C@ -fGlHRj5zH7v$Xhvxp4S=@`QHr8Y$F7E(0kc~uau5; --u%n(%QGFlT~EWQa&T^Tc7e{~nDQ7lJ|KkC>9v9dLu$-UfRgwqWMxFXN0y>^A^7CU&9rQ9*Wf&=6>cV -=fB3717L{*Cr)Y+!u9IY#NZrfwM#1K=|5jVLH%J#XZMG_8EJ*9ak$#)VxY58GQ>p+!u(F&|0|0`34LT -F5vgkG6!DDo^6p!ct+_s{9uBygK%7>mQv9)FhSjlzNySFI`QL2E4D9md5fCD_f8<7Sa_Au$o0G^Z{aaSp6U -qxU!z2h5NKO24P>Q~-xo(_fM~Hp_^V0AndbpW+#2nGr~kJHh2S^~fdVGp!($7EVMWY+PCd6M_S*uYxK -=(w88e(lXN$i8Za0z_)zKSU#1>LVijhUN!CsEmgg0P@ZQ1n5l|$t&z!)11wqTW^jD~F%A2ncCK0w^ui -oUHun8-ZjRnxvOx7g=7|796fUBWzmUK%_4K&O)3ZCtxAiA5erbB -Gp)N-@@=wae`D~^Bo)EHOzA>ub*Lc<5Jwf_W_q#(X3}ZYK -BWH5v%$*CJfX~;&VZo>~3&FRFFwFVY&!mBFMtOiuSo=I1AP?u3du(pSBLa

y{BxbzZ&r4ZOVARAgM -P`qWcez&2vFlquodf^BO_LzE@A-Rmm^{NeLEIjC -Ya6~v?~Ljr=YV;OcyADrp)+I;!Dp69lm*ns2r>kMF0!#`vKZZ)d^2TO5}cF?`R9!?>iDbOMCgtP*qMp -*E3x!?%kvoIDo02mMC<5J_Lvr1m2&R?iWV{x%DSl3jaVuLOAu&^tIl)Th*@mUOxi7`j;A$r;`Qt6Cn* -BOLIO%?&$*NkK5u8s-_%oF9%`VYur`X*SqZ%flC!7VwR7ObkVAciUPh0GGZ50G1aIu}PFjs}+Z;JqN# -9oJI;;5Ya%6dO@UjJHp${c;QLLcZCgcW$N)dnVXX^TA|=G*Uxpy@VH4ViL?}8Uel}b9s&C_J!n@WB)17T_+4GqO0M+(Bv)m{fdT{ALE#|SWhi5 -5X7~)%nF3EX;^#5^-w$EAuVaM4P8ro+dt7I4j*vY8F63BtTdd8T5!0;4eS5e -vwf|ACA1%w&K5O|@Ez_%~DnZ|QvVsN(Oox|AiFeOG(HVVvRs8jGMHSHk^qDXY}N6M>h@+&sPk=@UBsV -`S72`hWkcQ|!WapiMj9^Mn0;CqNURj2WPcuO_;hFT5P%(e4K+DR6>!SoB5UdO*k@j^Dn%0ZF9nLvn<_ -Nt@iP+4VJpUo?o0j^o3q>aP5Ki->5EobNyCAUs2AQ{QAZ!(wKQ}1Dz?)MHYT5`84}Z< -cPth7dW3!)vcmF7uabTzX!bI5><&z8Kkt^w~T+ -^m@_}=k$9rebey}XHJZf`{ZTMr%OnA5iF*iE7+XuICl4LdR7 -Zm54AvT!GuI3%@d}aonBdpbc^OCq0@*Puy3USQ-5kCi##3NH)O(~%^+MsfP6ati81e@| -N_X+1<@d&?u%x?1j~vQaH*0zU;S}Jd=4DTPu9yAkD-)%qYomH(8UFyocp5P_y&_4>1y36d6pybfj`=Q -`Y3vUnO3{mXj}2qd==e(AGAsUm+$wod)Q#c?bXi9sm -FUaA|NaUukZ1WpZv|Y%gwQba!uZYcFGAV`ybAaCyB|O>f*b5WO$3|6!mWDy1@Sy)59MNl>G?Bt?^(VF -;8ovS?GJLQ=cgf8QDEbNx~DlE?>h#hEwr<~>qLlKl1c>)%kxszp#;udzcDWKhRvnxSK0uX<4&(bU$7*a^cqtHsh51H6|W -Kk$qHmF4HO8>L@ObNFpQAH3*nje1G>2Yqji$IAv4QFPR{7=qGXG=%HVK43Se$@)Q7G`%8peZku~IP5j -O`wy5-`DzA0;|GUDtsGb0?`mv7`GRwcNGf$xXNRT746fcnX{|o&cR-KBFgOGENFoNeB;=5+Fi8$KQd9 -0&=8vc9aa}+3Jtcdr$D9J4v(Bfn-mK;ACu{I-s!V42*uV+NOy*abMpaQdgcc`v(aKEQ@G$rQ{!#UDk6 -j{74ZX9RGZPuL0ZFPGDsx4?Ttm6`r;6gtWabRbZI7*9lN~%dm6-KtzL$9B4K2QYyb3r)BZ1T6K|jAXFVRq5lk%NiJ~z%l+F(KZ2&rU7VO}*aHHZ44Z4)o<4L -;OUsblFc2udf3g_rb%9BT{YLYV=l}2K&`k~aS+Jbc$T00w(pH}*oym7tWKmtug7fs3}v#kXk+58%`@* -y3wZV$iTW$+u^jz90#;OTr@FL-L=!77tp4m^i95i#3Nn}$72_z^b-nXls8@*L3LU7U;1Qcn^3sZ<29Y -5$}s^405N1Gxm-9!<(fWI9(S86WZHN#KTSL-(|-(+fWS8J`@EQV(RFNaZE_{~${1t)0%Q(3&-l9J8hG -3-o6ni!u1MQ8a?@0!$;vXNc2hCT#?l%_Gx`anaWeDftV#II-OC{smA=0|XQR000O8NLB_ -@It@FJ>;?b;I2Zr`ApigXaA|NaUukZ1WpZv|Y%gwQba!uZYcFJPcW!KNVPr0FdEHoFZ`(Eye-DuFz^N -!8ZK{w0dothxTbeFKi!^B54OkEev_#unWKkpOBwo?)zB^K+C|R+WY)>N)M56AF_xE>4M^W@v+}D+$C0 -X!_DRR&CiZoIzB~yyTne!7^QUCi>+^Dh@4@~ij1pQYq8 -Q;n$AKn}0rJUApPDxNtL^Es7Xmh;7B`w{-%@si0=DeR$OMs3f2!Sub5x2K}6S%F{9q!i=K)`krH%N`v -2<@WOZKH`ekw~qEBJde`WR)?&h#fmvj!crN%gb!Z^h -dK7=Xp)nEYB09J3cDeg5>ZuUuoUsUO7A{#KXLnX`0Hi2Wy&^IEro0vuu -lR)i8SPB!Ow1j`2k2S0~tm%}j>BF>_fU%Vp;Gm*4*N~`r3spJRCZc8R9t<=XT!8??x{}evJ)MT>{)mtz(+S -#XX9SeF7be8+LaPompzkEPJ29Y;tbfpJ_HQ6xgu=c=-nBJC= -9c*^~H8^e*WV@CEsek(vSKXyNn3DD1_;2WUYssA*Di37{e57J4JSgYHMGP!xwurfR^BiUam55@lILFy -yGFR$0dxSa3L1lb*{xtB^a9-#Z9+xr06$w9wt8`Gsi+I)N&rRd=+Ve!=D?z-dj+XR}KW6woMWRUskj_Z2K%wn~^U}69kIJ7I`_$kHAHy8Txl{JDz~jE#(Vx4xxd}t%SHGRGYIN&thz3Ks;v}1_H8#DO|Of -x0`S+0J_n~=9wFR0=gjO#_Du5@J}lBlnk-~#=}WB!$Hh$FqhiFu}hun*Ec;_Mz&5Hcmpnf!^w;@a@b` -xPRa4(wj(|C+$c(tP8^)km*2Dahbb{LZC@LN6hG~d?^=Ju^NyMhKE08SvNQ5&N(>4rC>~QdSV4XQZEq -5j;1019)pWJk#EymAEHm>g2(>8I{)L%v*-i)rN*xMaC46Y|`Vhs$%9c -yG!QE2(D-7;72#&)>7aGmFIFetEUk%q6kuIRpwjo-L$JcM)pq%Szj-6hSNKO_i6V%-FW*)Ij(0eziAhe@76_{@oPQs)&x2f@4 -IHAy02M0k&8Qd>f=8za$FIJhoU4^9WP+UmB7I0eJ|7yHoFrAsRUMh0GGF|}4^y7ASPG&O>psZ}WNnc( -va0q6q3mmQh6A!hm9WUWm(_uS&_(SkIcG2nKX2<5o+ugfncT75xf5Fk_w}t~eRDketGr -*5PNl$0t#DdKLT5b-3i|V6`+6OO~J1qpYy7n_?7k+H4p9ev>o(w~{o&ZI-4#Sc0-62RCXL|&v#)+%$c -cgG7BR(CX7_NVVWRCwCXol;*Kr~#>MKz=TKSDO6?O}8a$)1I9xVD^CWovpoj&;ECH&9Ch1QY-O00;m` -Rt8ga<&<>Q2><|*9smF%0001RX>c!JX>N37a&BR4FK%UYcW-iQFKl6Yd0%&EWo2wGaCx0s-EZ4C5`Qn -y|AEjxth^@+$v*nli_4|yHMpWF(i8_Y2n1T9Z8ox`Bc&$pV*mG>8Ilqy%Wn4akjNJ2lQX~hNEAiy`S( -5ha{ZCj--KfC?(RNDQS|!N>sMLE%QDN@lHEu6^)0V9;#T~(6T1Ce>8@#N)rulYSX4;eW@}aNvZt*OW! -9-OdO#ld9a~8)@|MXR64*~!Db{V`J}9}_w)S*hSFLz%OSy6s_M08A_(mvutQEUvElc4Jec(G$+zI@^) -&4EKaR>K}tTyi0MYT`Z8<~Ub>sBb<)+%A|LH&f?G_9;FUMB3WYkKnUG7$4mUVJg%Bn%#m9DB5pO`3fZ -RZ*+7dE8`5=(G$We0Dp_~aCWqhmCU0sN>r@FlPaCi0LF1vj9`NO}nPuE|r5_T(eQ&)N&=aRq_0U?4PM@XdstFc}E$1q+!A0oK;6uF5@Ii#Fd9pQa|h^ -_o6eFCimL4=yVV@||dT!CRiNubpn0sOoOBW#Cn!saIby4}tYcAQfoa<>1BC@VQX!BH -PEOs0VFET$pg5+4CHU|p+bu(^fvmX!q(M$GTtM&p8ROcRWgU$_Ke4xalRFTnF!^+!ea20d5QRq -bw>A95^NG(y3-OrHZ@vN&UKM~JCCEnej5}-i{`!VBs&4DNF4KV=5FjH6SUQ<8sX0T=fG!YCa#Phx_!2 -MHkN^(3n1wDTo+SVcQKuM(J_UG=L#9^Wcqt1qlCAa(6REv5%e|ZyHfx5b^#thSKr!=q~wp8N@d-`dJ&7Rjs|gr>%t7z>3058^I90Yx899BRw9xhD{%&=u#A>g -#wi=sQoyqi%wAusbnkRdcJe-Mr^gDV*oi>hNrSD9_~wva{U9aNf=>hrsa1Gr>ccuJH&m%l7Q($T?sEw -wh-|^VmYVy(Igi>38j}7#%Ep>jqp6iquzT63jt`2-=^k7mP1`)%O(5u>@2h{&9t+_e6)#;kAq=@g5(X -~<}tfcR2#sHCAxwXORXXI(WMEH`FlDNJh0YB_i7Sto$gEkM?4?T>}Py= -)PkX*B9wQq%v2ytY^e4EmZXyfQ2$5J+@IMmowRdB`8%)8|N)=rkhD9AO;odCn51N-u=$R9HRig@M%`5 -yp-4cz{Ih->Ug$WIi05XYWkkODW2Fck=nB}3Zs@`>*OkXLD62s{Lf)G9h55>e`e$d4Q%1V8}uxvRjD< -sLP_>z|Z1M2E%RL6WNsgS1s$m!UXY^Z`IYph83|pu%&wHNa1YP^L=u=HIDqS{HobE0C7}ZiDnub_0h? -JkaB0$kQ{-@HuslbfP$A=zpw*P8b?usD9*DbIP|1D{*Y_&xf}8xsi=2G4?V5S=Zpb5@gVkp_#Hp2n)C -s58v+ks)Iil5Or8ZpzD&N${`vd`-m4-q)Im;mum^702+(=xz{GZv}46}P;pCkb@P_0h!F(VGxkWyl^nNXXzBoU -|m)FTb%f2J?nsJ6XlVmHjPL$w?VYx2m2chVwk6IzSrtHnyr;qVw6QpfVw3*oA@h7cug`F+fC%QryD6BRyiUtdLSGF^VcHqVIw(iOTqxyHS>F+*=^98%?l!973NSzar&4Ws -8NU4D8*9E%*V+W~*q|+Vb-@d0gmMMqvLDym2;O-!Z6v~J`N)9gMcJO*WvgSu{XL2o&Iao;c-5-?sQ2AVQ5M5jYm`uq4-qfI1mGQnl-KBhk4tMd<)t^-2dyv-QB#oS -+IX$UvjYbq17W)n!JVB$*C)zkameL<~ZuBx+JME4$tZMv4Y}uA2>{VO9;0Bv40a=-& -G&=!$w4*;fdso+kFa0awo(^L9KZ3(hWi0`sDlN|eV06FiYVGjg;jr51F)Yws$3Q*vdOJ){97Qb8kObk -%64<8fGV={pQK}~VGKY|M0*T6}#-rMVXi -UDa}b{ZPuavvhvkIEfI@6!MOW9->xm7GmQ>oWL1WjuIls_OP7KC$XroeaDTZw!c7{Fo}uJ-9D>tHQE# -wD9}X>A{|N;_%QkO*z3?MJUs5ZrK$ -80E|Ka03ZMW0B~t=FJEbHbY*gGVQepMWpsCMa%(ShWpi_BZ*DGddF@+ma~n63{+_D*2P|DzCKGBTJMm -?sDqfXVwzJ%GY?mb`A9Sh-ID|+*+wM!TFvp9RZ?d(Ak$P7x;Qe0O7x9RzWypx)qP&xicTI3g8&PeQNNAfX7i(>*GLKT7)ekZM(5sr@PG>?JVQzI% -s5QYWm8nxkS!WF5M(VUK)hQm*bNW+dnU|-c&T6C9;&HVv)Tz*$EHBk#puO9vta8(rHw>gMu%(havCG$ -Ws)Ssxf#ANtK66X}3T~M&+q_QcsK8{G->G#ZE|elr+o~$e>GAPKSKE3OVZm{x%M){K4|iPDX?pzhKYw -&P6HQLVy)3gMi|CQX&@5ic)F`5!-qH04wZjo3kRvtCm@a@KCbuKMn>=fNr1@q8+?(G!y;DSnc6#1^Em -B$C!g~CWu?GCc{vxaK -&83(Sr(S)Zwk78na)98@LQIEJumAb#Xs*eO-FU0!K6`qr@&LChwnJl%pGpu4W~wlOty;nz06a;?wrQX -?bz8`7Qk&}rH39#JH`0rf0IVJWpnZO%geW)0R#M|(gwoYQh|(W{mwp~i+9Qtc}8?S38>v2CC -uiBQPz9TuDEFqpEnVZX`57tg<^@=9!h{v9(NDQYp87`73-Mo$FLvBTMT@u?mgTqf*uej_XrB4?;ZOkt@`*-pVst#lQo`{O77EcX}xeL -l0`rW3YeILhQ3`!SpQCp>_Al_?=I`t-@uAEFcb@A$8y&reUE96xzFcm{eZzvXMNx_|Nr!m=g%FVlOuH -|{u*UxtT0M4QXK+$sYrj(Rs?a2N}TCQr^Hrr1f -w2Zd#+WnFXSUrwy50VME!V0#5JR%yN{O$en)$^D?m(M2+1O7v0w --BAqr11G!QT(Fzwxh&x&8;m-r=gSt}i-#iB2`D#qfsXSh -Z}+(}8-#0v#2wAR`5Wa4}o^oPMGo9G(D%U>N;-An)jueQ9g_;98UQ_+X#%RIqP_FiVw_Q}JO!nB&U?_e^@z`Ck|be6f%7V -0p0zQE7q?6Cyj}r%z|$Y#8-a5z{h_X~*^z=7_2VSaOXq255}% -ezq|f2T1}!!^n0$eX?Hi`#OcF~1?7RHWUy7R&ll45AA?JU3Cd|jrNmD)$Eg2?>s~@J4EgO}hFT*B%tC -%1#JsG`J#^Z1!kLuGEI{T^uxzsv9;QY6^HUjq%`kI=6MQPGbCAvLB4!iAFp{drU)KHZ4KfmPw^~c_a4 -H_Io?Op|6aLV})ZJU4`|wq-C)e|lL(Fhj1eim+E5?azz2qBSqmxNi4z -I2v`^ZFo|h3y1h9M1h57G2BoUT2dTdzQ_Nopi^$I=LRG?qIjpl3~T0i>@sjg%;Y679n;urnBBwkx`XP -G$794IoRRD$5|`&Ll|T5oqqn34cwCM9u1taO>oLBT-m`USCgcuyKtJR0UVbp=q&dM8p>86I>A4ohOof -%0?xZh<4|egcl74%i`N$yui{@`yt`PwdF>bC#C1`@A2lpun0z3eGo3~JBvcracJ*Y|@>UO|3oR&y9FQ -WI+d&w%ss|==&pV2iQ=-xRRwrOx$_pfu*@68ytIV!%wudh#4V2+;yhI!wIoQ8(-WoxYLF}7V>E7u~p&(Bl_mb;S4cpa3FPJz=dVG2moDNK7aH6axN;pQvkO(iJl$QGdA~!p -v9#C`)-E}ZJtVv>P-M)!xM$-VPz2(9UInCm?CKF%2U8Gq^|C(E4%Es)nhyLN%ZV#^h8X5TqS=^zJIz} -iKiz|pB$Y$J39Gs_CML<-^NxW#gRvywILq@6W+ -&1@|1^2Q$caRg`=}1&yuvJ2;LQDu;?r``CQyne1vB{nQ$l5x{G+0dpPzP5Z}pLk^ljj(KIb*G;KzN%S -FWGq_2RkP25Cn7zAynnW&c~py^>aObp2M^AzRKjPuKjAiyK#Gvyfj{l$xS@!3xl+40xsXP0Mz_Gy=YO -7AqY7`Nt^$HB##lMg(*iPf&J$j)4UJRXcY_PPEjK2XW$<0P_jFzs%qpt%eBh}QM4FjIaE1qyzp -`iogiCv#5GO=gtXDy#Tb?ahK{=^YIh)Fvs!TD+n};L8hF;+O`t4==D3{33{52Z$k1xe0J`C5+QS-6L4 -RWw}$%V}N|j?7?HFq)z+!-kUU+l`9zeANgZ=jR4nrJ9hv`e;6NO_Me->d(m@@StI2F -+a+2moF;Ci+cA(4itXFA*A0~yw^QNSSShji^+d3?*lJjMppqM)izK5EQG(&6^$zg>@rPkA4X*GBZ$vW -lo)t{@T|C>$<)k^Q^rYio$acx(oW?Liz&#&mBUxM`6x;FX&@7Mz)c9`gCOM|H(K`#-2}-Vi5woTK#)nor-FC5XG{?0T*Lw;5}hn+1M4R11adR8ehxRb@vQsRmH{2x}>0`6lYYsAVg_*$IQK*odLX>(1Igg(0a_SesXXVYR; -f~i7Qtkyg*P^`VEa0n%;)o?6DZ_^O&}bxM;ujwm*kwiff_meJ{*A2n!;4a@N7(g0lsnI)WxR?+9e5UX -_akya>PiB2!TY0CV? -jXZmIB4_!f-~{#h#--osyYpEa}M`Ygb3q- -YRI&>IM%_dLS(J4#I3_6OF|lx@&!))SFfR$MJ6wH|_Ujj?Ru2;+tys7kGEcLq_&wbF?9?_Pzn$_YTf7 -F_2LSaVjysRMv)fprvttG#f$kCPQ_ey6|*UkexlccUsiTsO@~&Z33@i7^OWZuzx+$M(GLERk(GunoD -cX&_vGPYuOX`FB^WoVl^+*d~_d`04%_+-(7S=$}%|w -Qd%6P=GqD#8PtcGS*V1HI@wm-I61xPpgp{rK(jq|m765hYYF@Jj)jWMW2r$KSbWBq~>{f%(J;j)uO3Z -^v9N_}>uS;(0ghv;SiV -lTfp>p&z0V+A$qxzQt3k?VDbFjM-NvyP?YbnF^EeV(O_Sn7ggIBp#wtG$%kKHSpGl7OLGR!Dno+wYc%q9#c9TF -<3%UiRWd=4?l$NmNXPcrUDy>hkrX -!22YuH;^blR_3%({&L?bM9D>BAx4h!~Gdi)2wyg1><~JD}M{yTvVn;#)DX3h$5toegfR+3)Jfbr01?; -%9bR;bpB8S+2QN+ImFnb`npxcJ9FmKMU8>Kf|>ZWQ~E?>19W;HuLCTeCalR2dCL>WS?5~$RHl0-rR0U>l2Q+;-Bt0ef`+)QV8g53xH&242Ump9*)+nzsDWrvx -^PVY-Hy%Ge$)wmUYRW0dkO)6LVJBp0OvSyv=i95ZiAKg+dI(!q9@b8X9rLBTbzQy)WW>-f~d -YPpT4^i&L0;Ejnn(c@mF+yg`19ApHXamt(CaYsb=IwXZS -ndR=c2xsL6-YZwseOf5$3UEi58W|qb9sN!S_qb(iH{kp$_tdg=2h_k=^{?eGi#~AszG!a@)1Ws->>5> -_bXKc=p=Vetq(6F-k-TL8N@E25<-Se>Nu3Q>`d3nWi{0=vphs`9t3UoijR#zU9PJiqTHGlQ26a|JK5T -3$+-`y!-0hItm7KCMU^anZI~bTd+>JW{YToWK(Qq}cXe2(OzkojD6X@Q8NfE!oF`Wfh91b6b5lnXXKA -bz&szZM*JA|VnL71h~ugVgb5eyy2a?}DT5-W&F>?Tu2KS<*R4ZsMPwt?!7O+ -pF$sb2e-PP40Fbx#Q3{1yY%hH5r8>>gJDLQ-5CIqxK@^FA#0cdD%SGCa)@$3G&eCpHTp%hT&Y?KWh1@1#yS!*Hji%d+AeeQ>3+FVU~XKCjuWuv1C>DY=HbLCs+bz5Jd%gFZkSjeTW$K6*rL59cCr01rEuHff9nT<3VG%xJa82QL9FYa7p`&yEV*qh>XS -Z?jsF%Nb9JQ8PoN~0=%Ge`>8JnM_VJ>0|XQR000O8NLB_@?+X9j$OQlZI}iW>9smFUaA|NaUukZ1WpZv|Y%gwQba!uZYcF+ -lX>4;YaCxOyT~FIc6n#hHKU}#F5GjdLXbVJTr7o}wT8Uj1s+G2?qOpCQ%*OV3XU3#y#ed&>XYBYRp=` -T(fZ*{xbME&c(JBMGE@VCjnH5S~xRj9{!i_~OtkU~?`+Et$RLEjHd%!$adaUuE5{)(EOvRX*+VbM}+x -x5A``N|yhuhy~cQ=1s4dFeSLgfa#I5H>rT%=?C9ARN4y-|bQqFpJyyij?L5uaRX?Po-TQj?ToJ -mtlBv^77qAFa -nivX$V}NT_U{alX-M;W1zJvnIhjJ%#t}LO1G+ -zUiazUWPtCCu@zK?36ab=nZ7aVHk3)7Aa<7Bgd1{;GtK#3lJx;$BDYTHGFqsr@+njqC)-7vrxbP5_0_ -w}tM_+PH#a{TtA{{8KEXMB4SItim_ktJBY5PIw!cTS0JM+>XGC^ptgxjya{|dDbRaaTg;7*o;o71ZQ~>;O!%JApjmds-^kN!kHW{5#bT#F+4wz}RL ->nMlC}mtwQWc3*esSd^HTX+84CFKou$#n>BlmY3!H*Yr=aA|W67H)|L`w#hMvYESU!RR$`t;M0;u>rN -)J1K^%~Pw_EkF5F@i~W9NXFjb!@%7h3>pi+lHfxw`GrgOn%hC&gW8a=d);0=1Ws~R6lL{b_ni;nW4@gO+XPp-yxCq_gsJ1dh4U>)K -3-XAP9b~M(IX9H1LI14>V6)bH&06f1eo#^+4#h!V9=7Fp?tmL$3;FD#PPe_wZ8(!&0O6X{^PHQbdW!d -iiTS9Ci;j;>dRdW!5dT^Irt@L01>8(2w6fz)DcaDu!Y>C`( -^iU24DMS5(Ls`RAK0wndqiT3hakd9^&9&~NCzt(T5whj3hpwsM^I4Zl}K_U&O?R(@MiZUg)miTT5%cU-qyx9lLi%eK+PtRCa|NkO -`8Tx-5>`|^xh-G=SU*JqUL?)Yy>*;>i&DpYt*)plO*TlWPocV(kpL}^tf$b0uc-)ie_lDybeyEH(l^0 -L-cF$9%Y;+>GI+)UQu -S=Zn7{ryF*o;$btQ2VD~yB^*F^-b3S$8$sW2>R(Vx0|XQR000O8NLB_@#3Ht$$N~TWI|l#&9{>OV -aA|NaUukZ1WpZv|Y%gwQba!uZYcF_hY;tg8E^v8$mBEhFFc60CmGTZ&B&0^lntP>kSuHFAR+Z=hgpk) -wrmexXgYE3LLcBX;J4u~vAcr=w$N!AKf8ykMem+UlR8s8d)^KGTZ5$D&M#2e{<4$OmE%H3i7TE%a{jA -i7gHVUzxi!)+Z@95A3`SXs!YGq1_C}wGyEM3tbP?OHn>%)Ue|P)g{lmMGY+KCfvxLw_G?WSDz$h*$oG -WO2DYjqy0Pb0vpSM~msQk>GG1|;7Rxy-XuoeS*g^g%F$C3Z8YMqcnR>Oq_w%3MPMAO;;Wk24@Dq9e|g -5(H7FT(D%b=yk=C1IbC*^x`hcX96?Ef})y8Pfx}k6~=dnBpg3tnhK!qLSQNzlkp)$Kc&^l=JFo(ba`k -Zj62sH4si7XUu<`xKEx0_n}u_k5NhQejs`}$oi`MZ4GjyLMamdrbKl_|<}SQ#{wlBlgIODx;T -hh)Z~3St^O8_XzbBZn>A)WlRw#T0R0T_4Y3WNzVD)&HDYcTs(60P4IGFw>0?2;GomNGEf_xI~%q1x?A -Oc>4@g@Au@r-cT%r^leGIelvud(s-KjSq9u>X~X;8@}yZS=^gq{i~)D7GA5r&i3wbk(i9|CtEH3H-F) -nieLr#iZ!TiL~r@F^LO1>Usb-*xgM5xYno`8bGsNY*3|!KPSrZT>i&ljJ@ImCeCyXgcGzE9S6iCkXA- -GQE@o~KEK~?Hv~eCSC%{~JrSl(`S2myFnWm$W6svSSh3l`Ew$35X7JmUyO9KQH0000807zB_Qvd -(}00IC20000003-ka0B~t=FJEbHbY*gGVQepNaAk5~bZKvHb1z?CX>MtBUtcb8c>@4YO9KQH0000807 -zB_Q)o00Iei8I07w-803iSX0B~t=FJEbHbY*gGVQepNaAk5~bZKvHb1!3PWn*hDaCx0rZExE)5dLn!| -ABB&LR1;6iU#qy`N!S#m*&C@a_j|{fVD%vu-8{Q=8Gk_8@>Ck|wM6y3yE?LEDt(@Jj!`i -E|t>$Gfl+jw$JcA(o&C(h`g@$>pnFMG_4yYyHwurPBuIPcK{!Us52{KB9?(r&n1qO(F8sY1=WK=B -%J?sZ&-zb1CZY$|hT?m{V}$A^FCnf`3j512Ft?K%Mwq_caJ3TzC;)=+%5i;Pck_-V0fo;O6%>xJVr)$ -;xpk0lz<)wJ0?=kfuvKH=kuCRf>G+D0l-NgWhN$&eB48?p(b(?LVIIS$$;)xc0o0n(?)pDvcp% -VfUZ4w4+SKCsNJ(?Bi4%z!3L>8t-Tn?36e=hHA`(dN)@CEGSE?&<aAON~R&7h -IrLB1e2qP~RkEvecQ=v{3M49T(25QyqliUX@jUnN7~t^y@5 -RMx=FXkpBNE7Bxy&|2_{-a*ZHrxvk^ZcNxX1Oow{WNQO0nQmq6hbQh2daOpS`=pKn0ks!xnWubL3&~d -ZqV7xH1-4vvMIxW-u8po;$6c?1KpUF_8%P -U~E$FK|Ng$0y>t!VYRk!X}v79M5`G6C;$IouQ6PhWQj8P9=N#u!ZE{G_Dyu*?J39grE;+g55cCrZm -Ddy7&Re`!eDq+u1k)Q`f%ai&$kyrG&OHOE>M^VR1P(LoH=dNZHH@#<)U1GvG5`{-?y#*I0724I}X}BR -M=&)*7#tRNUBM=G=DeB92Bf%~tsA6h`u^zL^!VhTed)zCst_O7X!!*)sx7I$RvDYY=*r56Qk})~3;|e -O@GEhE7HBAS%ea^^OgKsFP`W8*>D;*bo_egL@RHTJloK$%;eoe=7Thha!sxO=$AeoIV^E5M*8EV;)>? -CdWId!7E7Bd_M@?bo@7{!9E^DPkji5ra$q*Hj6zj(KCp)LzM!z4tP^|fD%rr1w|vc!r8&iZlmI?80AI6JP5$BU9y+nk!3dlgjP9_^sY-pFzw^^eEbW-su{<{)pC7Myaqi$?@BfXJcx^$OeQm>`XW{8wpE*UKV&1;1190ZV9tgl(b^cdsf!c5d5isHjCTTdC?&ywB%);&?5iF;u7ebMZIN00)YnkYx~osH7`L9z+1%b6Q=m=Hv1<{ -U-JE)mT5@dma?WrK@s4!5L`^Iv1c_+X-)eTBzpyd75T0~%#d8MI%efU5I+T05pUo~z7kLn<*;L{_h4z9TFxi69tV2qZ^Qn*X4!huE2+EFZ-e$v#)TpdIBbd -B^vGa3K=O#GNVz8h`}j}LBjnjgK?LFuE);cE+=I7k?>!r$(}{r|m%fI-s -6wMz{`+^)&?-=cQMp4oKaIlBKX$&4EG_C!OHluOqK{Q=|liM|O;`eO`l=!tVquk3sxKB5*Sa-Bc?4t)wa_>*0kK9-ET-3b(aGKuUP3jNC5%0nI{7 -jvkT@qz4$ROZRdW;YXu%*c&I>4n9!$y&1D0_Un**el=|M8cQSH^OKu?T?uv~BvdmJ9AtgX<%yiY;yhteu2Tl~kV4gPcnU{rb`P%gWR4)buQNs=t} -!nNf+I$Rm$J8Qt6iaO<2W>!okBp<%gbTBnArxe0dz#u)W_9k_QUItGYGc`cpR?J8%Nz`XusZ?DXX7&u -{PPso0HtJH5a5{3H;*c&1JMGa|R{N6V@ys>bNX)dqhQh<88f}{cx4IP4-8t^abbF#rhmbSKXPL8Tcc_ -E(m6h4}7=4L*G9{vf23_gcfD2Mwovse@D&M1bL)A!h&axW7T#lN%wjWjd&9FPe3Jj -~cFQ4AwExqM=x+D%jfNDqAFTo7-_gQxAmcm%<3`YwmIBI8E%W;2dQ=JN&I(;Eroe>7n5}M}DY`SJA#E -6{hVo^U^S`0d)z981=7Aj|22u9Pxf}6G;))kBwjzlgO7{NV*^XC0@r=9$|M;ri04;yV7%8!GKJBx0^k|xTc-%GB}}D -!z*RQpo2cP;%RaDRAJeD-S6NTgzk7#yS=V%0|llZH6=&~4IKe-5$d$I;9>A~)H17}ffI{N4d&{JraG| -NL+rDV{80C)R=Xu}__CM&u!_R~2!&O<6#13>G@9YHB&Kn?^NcL(APaI3u1v&4<{${HNmhSs+Fio$^)ZEK8fY0)r{c1 -Uj6VO!AsE~VstL++J%ML;AIzSFZ1tc(1-(;yK5n-UHtyrfjBk&DkKsFZ)Ra*d?y;(bW;k)i)0)uL -YGn>)_El4xDV`#w)gZwL5O%Zau$xE+$}+HoG;^l80itozZbO}(6>AeCLrsG_QXh}FhvQ*G-1g!!==M> -2;2hP=>k!x43*J`+JwTB)XCGEP9)<%$q*H1mcNuR=oFC#AH*J+{b_*7GbxnN4x%;{k!?|dN?|PABt25 -G(s$In*(|^#UJqD}G(1`>6X@L^qmT(ziK8Q+?R|3Z7n+J3!@vra5yboU!$2GT!b>_C`HG9wNH%O2=#| -rz0U!nFj4*|(63AgbMiX=!@Kp6bOV;b`W6^ds&en*NmPPQ@sI;%+8t{E1K-g{2IzWl5Ojef(XOlAcJ0 -*V1c!ReYNV4zOJNH_}A|Ai?{EcOI*@+Qnl%|}a4%-JT^y@D6Eae0%*h04&a4vuYoOF2Pgj@t}yEe@mO -3kyM6fD}n=@!DBHNSpwxh1VXhPFdjhn8g1~9S=sFk0Z?p#p0YorsUB(A5Oa2{r`(pCPwkAc{y2vX=SE -6T8bq%!}Fkt)-7A9b2=kjRWjY8$jFyZZ#PplAd=xdu=}VH#iKWbm~;`Xlm6U)GYUS_y{ZSLluEWhzS! -ef$harZ`bZ>sBN8<+f|7PvBKq(wX?L|!2EeMeU^u%zqB7e>RndET44X;)O87p}Q0}zby@*ttlP<{TuP*xdGf!HVmT%svE;kTXxA&i{O|)gk;pEnIiF~ZN>nXYRZT-plGkwzjaQL{ -x+^`;Z54VvH7+Xp^_saZI)ycT|Gk<|!i)vb#nSiTT{hJ- -(hYC(NDGy`1~e1u9Wjs>DR%Bi~z`A^gYJAIaZ;`jPY>en}vdN!T+aw1zkZ;SmE7c5$`4K>wK(P^U_!{ ->f;9(!ZLRp0uWS(q~skhO9mApn4mFPmIkhDPLS3ljlf$xcqi&5~Y~>Vx(toq4F8UZg33WVdQwE>H6*N -6C)L?z>{>SnhZo{b}_7yO)PN4-~@ur6n~kwhGGfsAH5MT-XEnNT;Ycoz7sP7@;8EU4%1U`iN6r~`Lq8 -3P)h>@6aWAK2mnY{22+hnZO^M3005t3001KZ003}la4%nJZggdGZeeUMZ*XODVRUJ4ZgVeia%FH~a%C -=XdF4I(kK8tTzZ>xXz?-cx8dNJ^QltTVm9EMB&%k*(4~id~_*w%GJtQCDJLx1y+YC(BaegZuXui^ctW_wSvEH|Gj|F3b9=s -LsT;J{(ll34LDoYo`>tNRQ_4ubghuxR=@9o?AAYc@3(ERiSR!POPPPKAVs#H9O)28A#vurBf^i4_ -Y(%hzKviwq2ySmL9xxJ9MhYW#h3ver|x+=D^EdEe=B@Ze#_2MiC{iWHh|Js4P&?AkHE*5McwP4`l5t0wC-sg9bNI+vt4~vm9-qm_7kG= -iFv5nRE&Qgg;UBuu5)i~L&RU+ym|RbR%hxJ@RQQrl!(YkIfCZ-dEb_^=(Njer8R05i^-yS%}=7UfR*w -8ENcfW`sxNox3jwz=rvN$nf8W%iOwbw&vvQ-UM3E-^X((GJ2G!yluBRgP8|j~8sAy0-{PoCeqay8etFD;#(K-cIdB4!`CNo -4=i>SB)qD6Qx3&pdC?B14ykEGx7kT(4wllICvv1iQQr(VG3Kg@+1WXW5y-APFY&3*1at?a2GirXm6Z$F!pvIEZpiyF>(7iH2M2sNo;G -0A6H%&esYi5oH6Xt`G>G@e+Gz;cPBiMvasY|p$`e37eIO+KFk^JeGl?3W7D|RC2P_$Vi|m%nY{<2=>; -x5ORo#MF&WV9!Nv2&Vy4?bGz}1{^HEEiungvVs7yzQHU?33#YO66vhZU?v2dWj&2s?w2tWecfAzpjXw -ubswO6ZHC5efqaP5v4}2G%`f5b7eoGdy5*Fu%y~5@WGzu?50+N~r8CV^F#V<=olLaJ<{J_1{7A1e+iv -CCgzpoW;m%d;Q4enZavx@MGA9;x7~GX0I6oNC^sg@VGu#O-A6}F-(_*1{vM;gb`Jsu+o;zR_oSX|;^;%?Oh-he2iDnv>O=n2RyVEQH-#lE6Foqlf& -XTUG%!eAo2XUz5D4u*L4>4%l5#{U=QHH!kth5&h`nsVh}~9}cytbqlTl~2CVi2aCy4>)jowJD(4BUM+ -ee8H(4Pl14W^kV(^;dF!gNhQm~o_@cS$gzGrA+gH^(OdF>e&QX7Ap+_IxrB&5&5H4T}V7@(6*9!Nmw><~spvutQ(T^TJJOd5TZ@^7DJZ!ET`4FP5hYcL{;lF?X{htF)HJJQYK;<&)>W| -A*EVBy!^|2T-({6=m^|@h+-WHBhf!>DDyV|3NiYdiy-*N_lRS&~JsRooxM417R@MD^6BO8Pd+~c4=S9Gcm%~l3I@jDV4j`LVNQxb9WqBSSFlgriO -U9c2ah~hz19||OTsh}Csf>MJQSNMg)F_)-E8j83pYGxq-`(r|N~agB>0gZjChFOwGROkCH6Rh1mJ6-# -mwCG6-qJ#svMhH0pB>%6mv!e+FiNb$!ySyDo|^Q*sZD@sFy0V~e&FvP@PYA6z?w -+VYGpBQgB=RyxCuj^*1Z+2KV7aP#!v)-3Ub0ApV#;(cqJ4FulMr>F -;ZxFyg+%#8fV0sw~i3;3*plUk}fWvS=0h^qpe889Hu3fVxsi4T7}|J_kVq4$pLIZcY(Lf*$L#PB0X_y -5@-c^HZact2=@w{%{?$@>bF{dg?9L$dn&ft51L%#Rw`%7Z0|_|ar=MZH1aKSeU5Q+h?-g2%5g=+NsA#q*tu{sh4PCuHGFJ|x271oR+VCU^Q)|rTUr7$HoZBC6x?8G8~1qfigBaVTPV2)eejWIhVO -cd4xB)HsTtUUqrJGqopx!#HEy2pe77y_$-uYScKdW&e40)V|Lg!_K9;AZpht>*0b!+G1k7+ --#e4E)^80GUmSv3&1$QB%nOG?#{(jl%yH`O9H6BssekVDa*W3((h14O4BR04Y{BX7JCD;+Rq7}P3=nR -cq$7C7D{ov7kFlE>9<^wU&T@5#x4|71Qdq=e>dk}-6cgDZby#$)RK&eMFpW|K}_1>Y$c9SyKm;xUB{? -h2%d8`Eu2dg*Rr9MS>Xx<%bXn;B6;F^2t#27{*9*FESUb7YK9$ZbZJ^i!UJuN0(f{$3YV;v-^^LJUM* -w;!oy=aE9!i3ipd{ivKi+eec9DO)caVX+(XgLM!owFcpQoh+XcmM|+jEf_q|%hW&PYTn`XQ>LRx#a!S -ROcH(OYuDEbU>;2i;%E7CV20C>86FTa#745Wmx*O${wsCr$ZEDsr(?YB`#-PzuQgWE$v2ui@`S9;gJ7 -MpcIeczO+ncPtqZS*Y*HRKU1M|zx8&%gE3o)De&qr$aqu*n@NnUei3l)3Z@0&Q-BfEI5q6g3XrFnzlY`v6#7$vwOTv&w$w@?j|=DW$q~8MI(Cm<+B6FV;4x^)@$yytR1qI{2Q -Q%T$1A`12%koHONC{fc{1yB@a1M+Z{tm{tjX`Uds=>J2b}X$eA;SSfu4wH9w8=nqm$0jF?gsUY3n6IZ -x*ZtPowha%;^ONBTgfnS(Sf6VYD~Me{!XjrRak?fbV^ef@dELH|e#LK=$wP9V3!g5K7?@)<1$D^oll>g6jQOKqK;|neP^p*@8A3Tv -8G!r&J_yY0!xflXU;6ihcZdLx&E(lH`Xb1d!llN3)@Q;ixjM(SKGoKJ=21QK{c6e?!^f@r3U3W-9kiH6Sk{+jhW>4Pf};ELY~nUnKab2k?iwEzSzCwzTJ*8U;-|=vIPU1wIsnyc(D -vuz(xeDoW3Sa}RoWAQ{4azAr====7t2Pn_kUk{~>sY~3Ke=;9^!PfoMASsKfb(kEDZ3Y_`ukOv3 -DBP&GqqUf7g!suk#|Tr>SMu6+m5iwmjqRb@_%N8QZ2QWk6|QEu6s&(f?j(sw^%%zZKgzzVdEu};i=Tk -Q*TMH#mWWTqsReXsFfGbaJ*WWeC+n*#OwI$_TqxCuvl<;UVNR&v;IK0Qp+^2mXpLffqGdgscn3Kvk+1ThoX#3w#e8nC8W~> -x=eB#j)lO4ENf;m5bS|}nZIPORE*<);;yicd`*LPF1@6otRN<&E%;+~`XJBH259V=;`1znTJUiay%9N3}u`uRd7~9yA8dD-U19Y1astuazfhH(!-mm<0L9GJ$(2OC4dereO??8wPe -&Jn2#-5YHns=mZkbF@@ajcf+EKWVW;m*)~4FAO!2;@t3bqXlhj|FyC9K7ls>sKGQw0Ga#x;Xc7sx(JH -@L>Yf$3bm%YNQoV{_B_nKnzA!A}J4N@#>YOuoOmy+E3SWZeBVu+`>l(0()T8ff0!lYb*PnuejA)W;0g -QoSDET0d%vik@5{_>9CSfRSN0|=k$?fulrf0!uH|F*?vHWe*87niCa<9Ey2i>W -BpsDEQ&&5Sj-fw1$rdKe1`WbojxanQqFWOO_|gRD9!K%9_^dY{hAMn>gX+=?bcsjE~gq=5H$>W$F -idq`jE|8Vb8nS_Xu5NW4IIBVkQ5KDt;PhM+Ar3b~maJzwfFqf4)+5~jMf8~eh7cT-RHy$8vQ8%g1%{M -%QRWkC1XvII6h`aUalg@LyOwuO=&q(Hez(yF#FVKM-l@6~xj{+(@j+tv;CUDm*cAjqDTg}BSOt%yEQw -Mrhu(xMVu(v1w06>oyT$IwP7n`Ykv4y4*6L-*OA@6C0J(hZfuj6X^_-ZSHjD{ -|oI@34Q`aA`n!ahLA5_>i_|uWo&rjDG>g4f%Pxm_Ftn+#B!Hw6tp)j?A4;Y#V>|>#x{eS#;?*Q;r5 -Osdl&Op`xk!0yd`AF&ZYnFBm!($vx|G$}JY`#m+7ubu1p#CyjaSNseWWJXOqndM_Aw!2sxoJD^+-R95_=gOx!(+Ji%OJwKfjZbq -Zr?~ha+Y3tdX{WS11r?TU2lb5Z<9nk{oa+cagh+{Rx<5);j(d|GYGGn_a!=S(vF^zf7<-}S)fc?oo8m -%>2&a&Wy$kF(it&S}K%YkEnCdffW2=(rXUt6_pLAR*r1S~%C|`=DTPTO(56LMrd^rzhI9a_KWfl4=Q6 -Kn!QZ+ILMg^(wq#=(u%*RTBR!5rJpXcb}b|@xipVL>4xIw&AinhhEG4$A^d*Wn`dqWX31a30~7wrMmG -+o;QKb)zlRp5}*eY8niW%dQ??53(De*V{0S_t(HN)10>r;Qx?&&%!bHoK9QmeB&rnMU9l5)y}C9l*~k -OO1`+sQ#z|Fig-+{KTOtR%2;js&wnWvz}1wmh^2M`Undj6@&M8&?O|eZDnOy0dj3$-q*JRUR;Ydn!K>zW(#}1>pUr -jDA{(47xpUKB<GceCi-C16@Htr*K06Cf`8!35NJZ(lu!KbKxf8 -@6l81V@h^(N~VW3Eu59F;#<^n&{bRP9Hx5>qKDP8BqyLON}Eov@v?FYgR -BdiALLH>-u?gJx3z{v}?l?<7aGB{f%>X1Qq=;Dx-v>_zrR(bz!7X#~3(Jtlr9Q|R#`aMS&sOwJz7@!v -|#-?2RPYdv07wQ1q_E01F3Dt=88zso?5V;}LIsoNH%yi>)*CH^`-j3NE^M_zf6ezc}M(`M*MpQVDm6c -}D;i`bO8ve^yy+UBmcI`3aeBIrn`dkoMTUdZ!0mT#Ku-HUsT*DK;T;HE*d6%|iG_`Xo;Dw^B8$@FMh= -;qvF6>WC)#zs|(ot26Oc*InV9nzKFI|4AeKySc&U%0H~VREc|5;jA(?WUyTt%~G?*1LHi7^cNgguaA1 -Ilb(|zL}fihdD2V=iBBMyg*_77k(=Z>1uqp+F5B#D`=ZJV01Upbz+WtE_C+UW?1*GR%BA&>_9^g44h0 -dlXtbr2JqL~Wpl>qhS^^#_PNn1(`!54v>Bsr1$Q9tKT~pP;ziNqoDqoJBm8RFHU{=|WY0SZ`S1pvd~* -$gj-u?ePjb(s^OhZK?ZURNDKPh#jz5x$@Vyheg1vowO&Go4(M+;$>%uj{olRdjF}x=1(`UDD)tluo`R -zJ09QuKVLJKaE2YMBDVK_%M(RR3UHtC?dLv7{OYVHQVhK}^w^-hd0Hn7U@9wlna;^wX*+LS}EY`eF8$ -;a4YWZ&K;-i(FBSui$#g0H7h4Y-A*cU5&+v~|T@6aWAK2mnY{22%h40006200000001fg003}la4%nJZggdGZeeUMZ*XODVRUJ4ZgVeUb!lv -5FJE72ZfSI1UoLQY0{~D<0|XQR000O8NLB_@$&Tsf6#@VNumk`ADgXcgaA|NaUukZ1WpZv|Y%gzcWpZ -J3X>V?GFJg6RY-BHOWprU=VRT_GaCwDPO^e$w5WNTT9|rHC4rC2IltLgqbi1^dmQeO?WNQ-7#+JlLPM -Uw;krg{1Tei9+`j|Iw-kWijWj`?}t%8Cb8e|p78ffi~YS>x^Z+os0H2J_(_3_ph^I4W<^VxhxowFRk` -ncJ$?ZA;M$^#m0xp3${ef(S;SviO7;rx0t9RIL(|D@U$`8JkJKsKr^s-9Y1qB)FlU*o~EIS^aZp$Y$t -5{9iWd|x@XHTo$j_eQEKj})5HI~q2f+^ZeFgA=fGr6wLxUS$7`80%p96nW2Q8n>fzD2PeRd?LSuO4WP -OW3iggK-L3Ryn*OI0KJIyQ*yQbq!fG7;8%2 -+*j5WV6=*wM+;}{e#NRdQTO#6i$g$Xvjk&oCE-Ugup*CTg3$-b*c#PPRr)mW}q3(A6QLlWs3_^QYp3H -)ku^HI8Q%|EA`@vlTK!9&n}GN|C1%ZMY;F$_I9$IhlZ5z$KY=9YRTl+Vappj680BRO9KQH0000807zB -_Q@!R7f$9PP0LKRa05Jdn0B~t=FJEbHbY*gGVQepNaAk5~bZKvHb1!0bX>4RKZDn*}WMOn+Uu_FgJU^xmYe_-Du;yS1DB)zP0tr!swbbv -Y|{W2S)LV?pj$12I_?jmY=-fM!iU*RSn9W^@3kHG+pM=?VGZWS5=4k#u#nR`XSoNQVXtaoYs|PUHUOb -&7XlqN+?ToEi~h%wC}}hca70G*nlQSC~OkHW6;g=+JQZW4)pofc_*@WoXkbfH9Nvm-t_lA38l2x3^d(#oivAn#Pq2g#f=ET4!q*cGZv9 -IkEAVhELVf5(ow%b;;hnXm6_N%+M7W4V3kpiuSLya?5^^W2KFFgl&A*_b(r(JLost+XEu2yyoh&*i$q -yaXHWgOr77Is&zk}>8nS56f0?eHT1S@h)KK?h1huv3PX`xj|B!Z -UPN=d-_vLHO*i>_4MJxV??Im3IMBzyD)$VJG-6;b-K3RvRfwB9GFiVSqIkj$HXtdIjyuB`v@Y^?Qk=D -r9e=)L36(orc+8!nErLBjEt3$*5YpUcxiLk?6?JiDGH7)LaQ9dC2j2wT_5DG>!`&!Lg`bX^?2TXoY@S^;2e-$6&oIuhgm`KJ;l)6wj!kC{0zKN|*^Q5zgAxA#P)h>@6aWAK2 -mnY{22(+?s+s)(004Ld001Wd003}la4%nJZggdGZeeUMZ*XODVRUJ4ZgVeUb!lv5FL!8VWo#~Rd3{n% -i`y^|y$A9ihLjQ;wt^l?A+SBP-O@toE_*GDP~x$pt}Usfann%x->b3gd~BBLVrypJXx^J=yWokT^-W` -4GoRUf_i;X}$#=l}km4|gZv$KJOgo>A>0pD>ztB~lRKW1&^;@+g69Q74Fn2@vv-gi5Oxq%zW36MP)KT -?p+o)o{4&*l&4{++8L()6TTOHFZa_LguG$@^9a3r{%7^nvM>kuoncBVtEOR1aBDy(7M+qTlXEn=(lxW -#-1=}6@jzzgAvD~L=vzBZf3#O@?@Nk{5BWK$V7y0U~D_OySl8)Fx$r-^cvlT)xzN|o^H-9hZ{sq7)wE -EbFRLIJ!(_~Ig`5$^G4pC0YdG4xTE#ao2Cn>$EzX2vjTsze9rbC2AUix3QNfjtb0fUP0+8!4>&w%rd{ -R&bm8(ay#s5RJHR>3ww=DgT%lG41P839u2I=K(b8K>LxjoV-F+;ks{%+b`1Ea#9Qizx2_m%e-t7$_y -V?GFJg6RY-BHYX -k}$=Uu-*4MC5Pmn{|ABKcSVA3Pdo`dwbV-T=!2)#HUeZ92rIXB6A_bC)YXtt^d;B4Z -l%2G|R=?Qh9glb4eczF^?YK~+;dM<}yVf9LG_*Dyph?ir%gF*Z}TsZ`Nk3x$qsvfCd)-FUklmqI>8H&V=m -EhLGW{T{~^2n_|M1dn@=0NQshmOP5y4R;-bw}R`9mXS!s?#ORS66(19T7fMHUDx-)B0ma)8rEHi$~MG -4hBkO0{?$|Vy-C*+OB9kvGV2dTtk=*4^0^~&=@7ffkuy@tgoNs^dcy|Y$rS*=#LCW#>uq0DB5{nYu5g -`j76WC^msLN9<3`F~=&OTkyAz1M%ZbI{hez?9sQXFufWGh1tX^d?#n#?`DySJN2uZA!+V&V&5P8LX`z -G#JIUMK|N7s-RHx3GUztnkXjk#tN@*-v9mKN1{LU63Ern6NnwhUy2jC=ZDAfKnY%yi!~&`N_n7aAFZ+ -6*mFN`s!73sGEc0UXZD#rhkH-Y9;Z(ut^#!EAB99%-*A3t0O~#F~UQw*g>$`5 -cw(>vf`MqTbcE4v`UVK4P=&!uS1=DFQ=#>R$<@n_8^JKu?&ICCQ1UC#SBKtx+R(;c0E~r`@;@R>ml^%tP_)80DT%ZV)DYPR#9fIdEM*OcEZ|6I_l?HhMbccOnu)NtT -m>d8a2~SBr<6y-7$7z(zjdi$cy}FG07!yhV7X&O4#*vw7#BloF?#={3_QQ%bYP$!zHwZx_9?yI)BE^M -orkP&AG8Sl&L3+a|c&Q>b_?lp7h~s0i7Z@<_pW3CG7SmmA*^%(F%m%Viku@4kKfW*0(v%w$e5|Y>a_v -Hv0AF!gSW3;mX3<(;zpo&}hIo1j%S5{ekB~5IMDvhtM*Nwt#*9HnVHC?oZkD#lD5pH+3%uZ_b}xS5yA -W#Wzq(0|XQR000O8NLB_@@jRomHvj+tH2?qrEC2uiaA|NaUukZ1WpZv|Y%gzcWpZJ3X>V?GFKKRbbYX -04FJE72ZfSI1UoLQYQ&LiL%P&&M%}*)KNi9|=O3g_uNlj5G$ydnCD=taQ$;r%1S13qK&Q45EE!N}ZQc -_al>&aG0HXx}05bpp0B~t=FJEbHbY*gGVQepNaAk5~bZKvHb1!Lbb -97;BY%gVGX>?&?Y-L|;WoKbyc`k5yeU!n9+b|G@?*_kva4G9RRu8b?9tu4a(k-;dQnZRaw#C{Stt4lg -x36Sbw&P@D2qgdfGnQt)NtR^?Xn1)hPzlSA9S|XnFyThd|E2-&1bt+6NetlSSW#SX&QJ^878UEb}_OU_S%Vdwq0=#9rjV8MGpF9k8Lws$JHy6T$K;;B0$T;An=`H(bFbWRoO%}vm9D95k^Qy(IYE;m_K -h}R52KbdCV3Bx?Yu8dDyZXNSe#UzCd55a#<8<*ROFNIJUopZ|6{EF8;nhdM}Er}C$aJ>4Yl~U^2E8VJ -T3Nc-!T|q?xUFzc5OYnP6mg+WQoCF)aEeO2vk(#kXOz*s{7fB?eMTl(l -GzdAy4wAX!XgF1p9C7+GAj3-F3d41;TK$h)xZ>K`JHgPvnEOsjx@Hv61kMq{t{*K+w@6(4hV>37Hc4^ -T@31QY-O00;m`Rt8fbjl%N81polK5dZ)x0001RX>c!JX>N37a&BR4FK=*Va$$67Z*FrhX>N0LVQg$KY --ML*V|gxcd97IMirh97{=cyAASRUYkXb#zf(tE8pb#2J0{xK&$73IRl(i*Ck~2GmynD})Y+1f^XrTkU -JNCKgT)uPB?smI3Q0K*!32AKJG`ST@vQDc4j5#vFfwRvBY~S%NFn#9tce~y0{_g%xw4KtHHL9+Kti!W -1;j6jg_e!glmBQHGipFsI%?5gL&SedmR>}^1_S&JYk^Tmyj_hqmhULwXy@#(o$O7ne$KHvKXF^)gNav -?sG-U?z+bI7ly?7zLO<+?Vv)b*zU6{8~EO9?u=2z$;9W{e(Mr04Z5- -z~HqSw3p{fX}}P4TV+uN;#$AfM)54DPDtp_B|?cSVz<=Yjq7g6ea*Y{6n-I)|6;xEIWH5tNU$n3=h7!uG5)GJ)f)Ix -qy;QnPymJ4LH9~@UbSVF5tp0Qys8|k<0rfKqe9cNQg%*zZ$dHDlV0z?mr=bH`y4p&*+@3d`MtLWUel3eTkoVU5fKHYqDd@L+mI^Y -9%ZB_ZC!%&EZ5F))U(o9sE%^#f&ezjOu(F4YdO={%l6(_t=i(vUy-R|~g?;y^{oTx9qC2O3to2xBu4M -Q(xFbB<4z1yHeEvfV;3m>xOC-pc06LeIvk{el#;lC1$N7W*4EqO}?Uh9T&g={qV@D0w7);Fy;-$BfOf -7)3(o!oa$TCPNHDf+bvhMlmWMKmF^ZQ+-i}sZAh>BX&iX%u_vK6`e{(iDim|rk4|Z40IDyu#o2+Wq*; -oQAR^Uf0G$T!lB0*lp;G1i!gA5(HPQVx%4V@gp|BDiGCUIo@0HX&d!tJx&4~nP?m_n<=tAtcqjLUAIg2f62W+Dp-GDFB!d#I^%F|GTBVSM)_fToZ3)mfS$2#)G6QM8^?dd>-$FFm^Dq$aa -Jwd=D@U7;`ugDZy>`Tof&jLVm)DVAGBNx)pi)aO{(7#VqbsCITq}uM$E;pP9ehCk0M!RC7S~JYG12CP+HNgYi>9$o_?kYifOJt1YyL%PrOQ% -VODqDCE}pj}u+majZflyapmZptHGRr;I(^;Z!&*&U!LDhu3QXtqxaOA1lM5v)QKzARHf$g3Hk~SX&J_ -k$2!-2zG3__j;Ek+TyLZS>Gk1BZa%1oNSjazitMlVWR~6H}A;AF?%KUL7Z_dUIbLdmFWg263BR-DpQl -|ghAl5Rgh~Y?%S4eoqj&G6$=$7M|KK@3)OE~p)vVZ3U+}vhA8K<&Ry)5^~C7=&$RWI0kQDawUR^fsLt -e}yo{jPNZTEgT$tXz%*XB#7@-K}O7SHHx*&T-L;-SyW=7H%O6r~XGP{GPRS2a4@^!G5u*2bcK{TOAHd -Jms8!qxG(!D_zw$%{AII=}1IkkLji9z~{RDq|MCYdp96auv9J$SZuhXUU6+HR7ns=_i!2Z>Ri4~P~^R -VSlQGt{Uypw+`Sft#)o*1b&v;Q!NQFjjmVR+;U!dH~x8-D3d%22e`_1QY-O00;m`Rt8g3tF8-^A^-qAb^rh=0001RX> -c!JX>N37a&BR4FK=*Va$$67Z*FrhX>N0LVQg$KcW7m0Y%Xwl-92k_+eVV#Q-D_ -8eQusy2R{C2z8)xL}YNN{B!J0YJ%&%lYlsk9h;6E<{%4V!kfQ9KZCJQcP|xr7S06UQ}7T5lyzZ$}S{!TV;Ln=_ixP^hvcYW$49swPD*+rF;LPQPAUWSkS) -;o2n+7SY+DD&$BH-`jMa&=0{`T@Xee&nyCx1D4{=ItkxZ0>s-x4cK<0nAbY+g$B^=Yx_)yESU-FZV_` -?^(Me<(WL@VUG>+cdh}iv}5(mFnxM{B;c!k>;!Jb+&E{?AH}^QJ)tX0iLO;{#Gf6moHx_B&26ePN%&NL -77Fk*RCetcg$&s#I@lH3FRkvxL6uWxv#Ix+*I8|Fvv8ct6^CCHpMT`b_uz78b%&AYNO{*9bHwXteOt+<86@43FZZNq|c7e9zT72_Beh1_}Os`B8qKax8*K?-QrTNjMSXMYIt^>{^j^@r!j~Dz8dXJEKE?|V -Bz<2rTb_3FWCYlAnjL8x+M8)WmCel9bi^Px3J>S^uW{{IGoq(-Y^;F9gEAXyHrq{tnG`f#A3MX3T1A% -{uk@EMI6_wth-W+sp!(1qQ5Mvlqp=dS`Bn0+I^cXdO!Bs<9hLdt*XYpg>aXGGDxZ0o*;O#*w-jLWR+1nPrGznZDuG{tt2!ldgqPf^{ABk{ -bhq!4=uRvwC1^zJ3?1iDWyyMDYi2(oPkD!RIm`JmCfw%9SarRcJ28FjK;y13z=?i9_${x<~3f8W6D5Z -I@m;07jJ7)|YD39PUm=vkDKc1hD2wzD%r%vdc)Q~Pv^8%YaIm70+GlhePxs&Ak*spE6olv>8Dna_cn^ -!?2n#s{a>N|f8Ep|*3-C|4cmx}yi;>#xPb`+BZsjsy+h&|G;idW2B9DcAz9B&?E3M7)LOAhZ|2k64tl -y67)wWNr|1)*XrkB0zfnGJE)kN70O|2?TYiyTHWE>IzYvaa$e(8crF^(Nugs+|DD*n#+W{L<+zx$t5+ -JqS~zu(YWzxzl$0u60h%-x3)xB+vIGau?x;}Q#pTWHV4a3zfNIE -r*)OSe0=ujNIe_KnD(8Jm2ZgM+POOSw#}y!II_a!2sFs5jnKTzT1mPCv?dNj{yF>Jp#POWo4A^@v(JT -bT9*QC91w<84e++WR@Pw+n@D>D9t+tsp}tkBOo2Fb)d3NdZ6HmB?}>wYy!nPUDBAwv!$!dJkvjMQ+PY -9%0P!7chxrC=Uf`h{cbZqVIT{@b|D7 -M8Zs2O||F~4F~_uE(UQE`oC9mlh<-57(TxE-)kp_*qahTABdHn;7^0aEEoG*0!F>ZHxOmt%g=Q7>3 -VR-9<{a1B#rp0NokG|59hxdO$s2*FXTL5q)m6v+;w-f#7HWjA%J}Rm};k^vH)pTlRxsBO#lNVm2_$gj ->Q!3J&-rVT~I=IluqLVT}YM?G6w-1PP=tF#Rt0hl?ut1vad3yujqwQs2u=hwH3zTZ%VPhU)B5gWS=RvucK&sHZ!vjP-qOn2J$i ->r8gN(iwR+1!Zs7FDgsftGcd5nUBy3{Ia|f!9DGG&kg*`lxGaZC-~R4vtF$l59QQEj;V_^8*(Ss5_le -mFK57F%B#Mxx{-6#8=zFSIl>$9{aUjkJ`<+}z}6i7T+C?NU*_)r#VA8`eJwu5PdIXKMGmKp9p%uZOfVg+VQK`xl5K$WhY{9Gw5V8zf{q -$#R@3QgxJY;tXV(?#mvfeos&0Ovu-i0x6*nSM0K1d51SlgV>EmJ?sVk#O71wC|1fPNJuLf{GkvMrJ^1 -XiN49@Cvr=o-_+C)V@u`D};kD0d%GG8LstJcBSY+n>HHmY`ntSM%$0f2o%j8Y^}}=e5}VS&<_4$zsHF -Q<%eQ;0Op2)BhsLY8U(3p>MEz`N+vke2-8xb0(Wi#tW7Ci9={Y{{P7WW$Io9r{G&22K?=)mmI&My31_ -4b!@(#Z&x#bna$PMr%8tzt9n3YL9K!!G>WYCv@Rs=-TJ30>feuslIfIw0rr)SH!=MPWtlZETX!3(8RK -m=va)Se*H-J=XBuC?7+Jj3-51hh9g%qn7u-rv|Q<(hIo@*nbS&T%aoM40LEg&pWx-BT+igqU^QA7kT -H;@ZML)cBj%9Z0)bSq@uX#vg}f%GQpGss~H;G!WdYS}_xl6c*Xq>7u;=j*yaHH|@CO6@Qm(4YmX7;>Q -m;l{^~qL^okD>MwN9E4ZO{e9i;vhSPj@ZjJAG~Ifh04ENbO_LooMRQPe-CA}BfB5RrSDso?_LEg)kxg -7hPN*I88yq$|Qc=K}N^@}NlU9)%PXe61?z%0CH*OxRoXnPB6q)MO*XgpOt}Ye>U1p=(q`XW-U(L?x>I -?yZ0lf20>4R2cxc3^Hh=S%GTNy=e(_2 -#?(3xh!iIoV-|qr6aZ2GQ6_B!1N?WbgsHlAAz>zyamV{;DlY>4O;y?v^__9I#Y821h%e9xaj`SX`IkA -trDrZYD?i^<7k2X5R2(S5O~L=a*zlyL0iRV&Pus_R-YGjxn5OUgViBF8wwkl6s`|tWMSNj=gbcbVv+z -C1KC2x+*WI{E_2f$4qO}K-)M(T_l*PZ&P@W@&#IS-q&t1k4;(bRkQM4vuVLU|mBpMLIzPoWAas%>*47 -BEkYMjR1TJPPJGDdc7>t32lZjcoxWsj$_GOMF)w(e&e}3n>;2=|B6iY)VGLxqoOmZAc(sF2BR34xF*e -SXW@N_1=5nlwWgtLH&vJyc|cphW~g2H4Arw9JP|5`9N^j>=?{=EZ1La0ta1~BlGqhl+ezVZFkO5Oy$3 -^9_XZlVBc91attH3De3!LxV;Gxzg=Fse#Ej_CgY=4`i*GaP>;tH&cV54C)CIfIwMr!Vrrvc -vQ!8u`eFsVr+L-NHdAej&WV;`yg`G@#64rO-P2@7cUfUc4xEb>rL4ihxM{)SOOWoCXf4KZF!Rp-F1iZ -^@ljTwYL&ZU(B_mkxyNWYN|czn_2$;#omjTJIK*O36oYx+kf3TO3{iWg!9Psy!{}z7*WmS1^4Wy?)tZ -v9Hi&LUR=D6}d~BY-EYMknajy-&;Et*JZ$p~h;f+fAb3Dh)Ugug3yve#M5K>l7n1>+4MIw{f1%j0WnP -M?|$ckwSgIN+Rl5gcA!|0;3$WT~lF`%%m(Z*-_5GmW0dZAnwZNJVy6JNW|tu9?apax%sZX!6wil;^on6Lsp3s}M0xdcDhILsaA1M&HS%2?1OYcXW3LcoBC24-pA8?1@bWnEv|c -fzdU)FzIb_d^5XgF+qXgmJXg|246d`bAOYie2?4?=WLuZ&kzVgQ;t$)HvxNpT9gKREmAz`M+XzsDFED -fibNDIw8?gw;yV1_WK0eec#Ml_r%#6Ezyph3p98#}8#UDLX0=}_NDU0fG+5j0cy -?>|tL%G9KdHeI5Y4Ul(PgU=HCSi2CsN!)qtB@Mi#PCA+qMs~;#j`i;h4{`>UUoR=eLZuRpQbmHhiq$d -l0j@-DoU_6qMW&5CiXSCFh6VU*h-CD09{rsBoX`F=`_sRH_*~7Lyq@XKFhh4pmKyH)mFndR?G`b0n+) -W2r2oHEa7RSOMM25*2v+|LDe;Ed59M@-+E#gr?}XvUikL@;aar?*Wufzjy;THV2+{t}Im;qTq6IZ3lf -l@x2&dMr-#g}pLCLdFl%K&#X=AHw^@$Ssu1D6YGdIyR;A3p0UzHr#RH}}X4}r2@$`$MXQ#9X#IU;i`U -01WD7$i)-=+l&{#pAGkJ+{T^F;(GHk&qW89>lp-MoyiY8L2bJk&yvVHScLPR&Sy*}P0=86p@5wqScv$yvo6hNq#GqOCsQJ?1j8NgN6ga!!c<9)3#wlC&AR -7#V&dT@CjBGdfe%H|5h|Vo+o@ew3tLXj(B^VkGXW_5F0fu#7hF~HhR^%KI#zxICPAsz5$n`DFR4N4L3 -Twk=f<8DI2Q7P%{VrnC|Fw7Sx%l>cL}rf@TuqMbBYKAC*inGv%#5mU5Sy^dVO&zump{daRHEZTb9NA3 -r`E%Tp$mip#t_RP%2ZjdIhHPfwMYJBr+F5w^_}>E5Ha^&qgz4xx+~%;&oLP)s?20ztHxuBmtw;nyB^C -qbWKaz#3|#A%N4ppc0tcqb>9(s-G`7KC+#d9^uO!JB!n4+a|MP2l;4K?&64jXIsZ|jsjjoK$aS>YF_aFmQf^;7HZki#?NdjSKpob~U)Qknfw%r-X --Wy~Sy(=klGN?R!2pI1`ci?^0gb=UhT6d%D3*QL4EEh>S4wMzP;lj-Ek@;c+P-!P<{8JfUH}i%s>~^o -!8vCUd6;d@_gZQ*>5c}cgabg<6QcG`f}eu|_%yMU4Kn|P@fKmiQVQxm^Ca(O(Ktt)Bj>X#Y*-_u4NVu -{SVdVnuc{#=MI4+!8_Sm9-^WmVXvQf~W>iO!beXF?2eR&!*rTlzW|;9gpZ56;<2UA|vXb2fycG<)^YL -Og39b$mQ2mfiM@4a3<{UqsOFHlC#~oE~COQ@=bUh!oSEszGq -|ca)+J1J5T|F>Bnv^peL_FXfmsqVkb`bfvp_-7=a~Q&n5lt(j=28gl@wSA{dT7sV_9<@iOFIexkt<+XQ_K9WQx -0<`6F&~DxHojqRb_#vDyjz%7S5I*zl>bUUclC>%vbhY$OV>-(A~)yOSYT#ula^8jNM|0eO>op#o7!25 -3=bePMH*?s0VmL49ZA-?_j=A4L;;pK)CY9>Aw4`^-YKfqM-P4*_qS=lQw~SEGV#a>aUEbY}NHJZ5s2L -L@R2`^Y)RvAZ5=tXzk;EW0%-`_vX!fzitMGw8EfF&=-WkP_?HyM+i=qdS?`l;gfcls1YTU~(HMn -jNCiBbjkNK{EJk{u9fYH10g?WpBzkl7Smbzw5n;O6g*naMUzAr3}Vq|En3i9G0_z{BP&OpIUBj<jpFZb0I5k3R^UNsN_ -n);ND0Gx@IE%i6DXYq}b#iM228PEvokeF%oZS@R1igZc75e}K*Kq`0H5cs=xkju*0ToHs)Y+CFBUOld -Bky7yi&&9Qp#v-`;4#KFb5oOMopxT%-Sr&P^(}AQ^}()58jd_x*?pVTepmQ52xfoVl{9e)_c-LBdfe~ -mMkaJOI$)DiJ)8qK=(uwkI5GW@=e)$cR6%rWHo%QM>AMKVi0QHzO`V-A=6Ac9%>K_u@L3JWyPUmq0RJ -c-BsZw=oQsT;SOW5Y;-+$uRS1 -EZv{q|1jGn0^{&p!El$7r_Bd+9~tH!m!z$`n8Q(jjo)=Q8v^*3Z)&0X3~gNJ^*_nhWeo -?0ZY&w-5xp@X3Rfo9iHuvBPH;|{nIpIlWFQ0!P)bUG|f5TH2nRDfn4WfCG@I9AA&>Js8u;uLT>Y;sSTSj-=eMlqc#^A9&Nop -6&6elpa29JWr3N-$6ez^aoV-(S~VO!u?D%=I?gZp;_I{|pGtUngb!O^v_hZpm@sOYLL!-RdyI&(jnZm -t!U1?ZIaVgA*94iXw1C;Es*I--1LyFj_yqoY(k{LM3^;s~<SU>8!3c`Boq1i0bu3onbrE%{RZw31}Na6BLVsbxU^Svh0k4Wo{Mb|sE=0XZQJW^&27gD+K -G*#GD0~S!6yF(Gv`7Wx}QO!8~hP(XC19Qq3MU0?ByHJO9Q!?ucPMWo{Y3qEwU>%ps`PwVQ<0}vNusI) -~Y4B=?uA}R~>dLQW>l{S(D=hhjcv=iZ6{{KBqVMU}ki-Kr(39rp1r -o0R%3$rMn2S?u&A$zHPdrhHUrd7OEV)9WQ)lwrtgxfFilviKcC2l5PJ;`@BfcS(K95zn>EA8@bU~Txi --x+vMGVwIw`KKf+D;4FRi-0usJWLJ)91Hp9rtg~WL>76cx!*`AyFR*##^0+=Ywmlce9`mjjwA_b)a31 -MWw5C*E{JPE-U35Gf;q%aZu#mX6=Oy5n{E?cw626?}-fRzb%iu^@3_KkHi+*+=3ELfeIHEx*7!tDf=V -7`}QLc0bx|QY~du02)tLiYjpK)?-^XItV%~Uyd52}iC=6;DX{Gw@Xt?>=~2e-65+JgHb^^O4YukSaRR*A-e-bj+3JShefcjo?15)So$tdn)B!ZU}nt)&2VpM# --YA=X1hLU#{$pY--%i5mBrXr!$e2s`fM2y{dDu`owZp+G6iLQQ?hHU>K+~(6!dqruW%d#eDeqv@TQkGW?R_EHVbxqkcaL;InJHdYQ} -eei(#qbFq03i|%_$v<>bMmeiHZ&}c2ICmolASh?Q{jd#m93HeW{!B19+w@2c@S({r|E*bex7I+$X7tGU=TiEVxI*R3(#`NW}haYQGV(0$f)_T1-e*l;^yTBWDW5 -crR%HX|9*XZdUpKO{h5%ZEiLx0cvjEuBw7aWG$a?D#PNZtlQ@GLWlWOMR!f@rMdJFJ90vR?ppPZgmTAQuWk#*iiZm)KQf=3w<_{;q%US0p~{iHjm@z%S( -O~wg1|rooZ?jUUD;s`YK(o$`xd5as%}>&o^^chp8tC|)0^px7K~~YEEc|R2)6;T+B8@_vcy~7ovS7FA -w+Yz4!zV@|G1DM{@tnMOEyf1%tLK(1nD~2sxbwAO_d?3YMF?y~^lnPR9qO^-Vup -07AxJBEA(+^_|AabPNmUOv= -X}NnzRl$P*`nX%GAVKRJ{_T0>Qxc^Ni3!3r-PeMu;jqWCS0n%!BT_21~3BKHrOc|;r?38d-V=Fx9k-y --ry&OCbYEXCaCxm((W=`x5Pc8iAGBGPYlE*pAmGBn?!!Xa -Lff}X5Q;rcv{fWml5-nM|9xj1$(9r6(uEZywxly>jz%++$Wv#mXSGoZYA=m;>y^B&DRVeTeORwrYfj8 -xI-Ibu_m>ANys-s)FP$&ghmLH8D%dCZ+Jmm4V4wR=!Fm?WKhi!d;4#+IgYWsPa1fIH6Op10R72;uCoC&N&)#&MNk@UNIb-Ic8I^%{~352;h5}WD -w->gFJ(#T}K8x@<*Wni|#^9$^-cK!&=6<7AN35C)|2fE8$!`nxL?M1lKFSy}E9oWgG(`J?EJN)fSA*x -6FB)v*&m0Z=)e#X%M6&1p1~2xtMq?bT;q|#z>ObTJXKqtliwJ$%w1^KC=H}f8?9%0S4x?P_hwz9;56^ -oi1&M1bev;^$sI9NQ$ZWGUVF}Dl8T*ezyy{TVu%qCfnT4bSexlU{2ufpuE8INj>Og-aPN&Ib0(&DZ`e -1$Jvj~#B-6LnuG@5rU2Zh!hbzHfg_6<$}i$E1QBphW-pTcSe+@x8iVR%1*bblLy5Dr(^+Wcx8=Q8VKs -NPl^xY`JtW1J?Tt|Z&|_)f$8sk<%yzmaTd0O`YQb~ ->E2nMs15bT#~O$y9j<0_im7mNGs_Tz#H4gb)2jx9cOR9d=sf-Ikrh)ER(Vx0|XQR000O8NLB_@(I|rmM-c!3tUmw%ApigXaA|NaUukZ1WpZv| -Y%g+UaW7+UZgX^Ubz^jIa&s9f9S8&Z9Zu)KxQZlCvUC(h5#&)#h~s|ud64e#KaVErcR;Xf`oBHQwUWo($vD88cvHPYJ;$q3^uprS<~aPE6(-;DB!i=x3urus^3%%+f_Rpmy5Crx7p;d -dRv~KO*akbgCM{)KnS?Ox?Qhf=fiU=hOZs)rtI1+>km66HhlfOIn3C%Ro>6oKXxdvamEYWE%TR!uOLdXsg6zwElUo3R~!PfdDlW>gKR1aK|kA979{G&V#6BfB7M-g#TllUgJdDAfl&^U -dMSYmfkF6Mj22t**c#)U5B}`zct^G+t}qf8m1{dUx1$?R%d08g!do^K^Kd?y`R4od`_Ae`#6OeAo%Hu -Q(#c$;?V}%wga|v-f=kyTesMw?~0iBF(ydQ{8Z)=)}}*C30hyq9R+>JS{4})a1l{R}ae}ThhKw;hlHJ -O>R;KP%{RvP?^#cR!dX1V3+4-3_gLPASG@BsuX-ykMsmH&miak45+D6UkCW}vn4KpjsZN^LVJj0&HL} -^U6iIxw&iIWpP#im-eu^Q0dTONBpqHS*Zd%&7!jVI6})6Ac=BqO@(+ENi3m9`XYeX!PrsJ_;}V`m&w@ -|OhkjEtL5^^)iVBlI3u3M5?rnUbAD(WE?-q8+bU%EAptaPIzVodb= -U59(X)62nhbua@q;Tqg-mL_1n79b?-~bYrf`qkfk=15yI!+L{+Zj{AXb6DrHA>jucqx4I)f&)tl)hVT -Z9+}5(T?D%lW3QAw~u4iNcc9?JdYUjuV$iTVEpm1+~kSrA7FRk!UsPns$gsWby(6FVo1F;XWa#^{ug~ -rx4xEVN^zIv|&HJ{oZ_|cVN8H>$K7V%dzJyd7B|h4P2cb4pMSopvkm_HrsFpke7#=0YTH% -TU9PfUmwyoZ6?g%T3Cm#t0u``CDqoJsl1tHo6%lRAffZU|z}i8DOy25|3--DM4v@=4eZmAt2eX2*0;b -iAYz;C2nO-Ql4)~{v2rJt52~e?K7j&!@39gt_0(KHvC}NXMpkq65|A0=2I4upyZ6jUFxSocNN*-v3HhJT>(#!hizN17a(3K -h6(r}AOf7<44Yq=x3-%6ka>|^0mI+x)P`R*yr>ut2;sDyf8z@tFehoxGT`?lC*skJG9=U{dHTkbsAS%pqILjLH!HB;*i_WRUR)*j#Eh9kz{pI{xutYj#xqo$ -zhYZ4v2uN)=1xM6BYpe}~xJcWsT<3t8IS;u7HS$)XJJoZ0ubWE4+8C?3!!cQE8Sh81YlwI+{J{ZXK%o -}eSbVX)fNCU*t9hoT2H4s%E8eE}rF3{rrmZn^0Mj+ui^7LaeovU?0#NJ7S_g7e1x#5LG#aa`1{;|v -oUeFd1Pr-ZKiJR__;)M_uAmOb!_%D?K92lg!EO5}#_9#g?KmnVYv;{hdn9_-@-JdcH!yII8Sny(>^As -B)<-ShACq`CU2!F@4?=4{!OhHpz0PD$dKUTRP+2YnZDrTk;u)eUC8kB91vZE0Y%3TM@OFYvrs -s+jRbWuK*H1=hQ+WdN#*n50XV{M-9V8M7HZg^Ok>G#|N(538LJl8SsIa!P6Iw}MGS2V2gX0rOqEKWtL -=pyI9iP{0 -Jrc?y^#odR`6om~z!6*UBan5s`xXJdlbr4zf29T_FDfqLmoKo@O5Viz!(R8|RN-%>78syZe8<+y{ -FEmnqP)U{1Xao$2kM>7mbP!s=h+D@gW!g8s&pfG?hO?Q0vr)PgQFsz` -sa^Nb_)_9IGXE+FBuQK4T4&|~FV_?8T2H6gL-W=RDB|owXrRKo~By}mC;?$LAJu-pm=H_Fr2eKM8{Hn9?qFDuUJr?+kqFx?N>Q(Ai^;!3K5s#*Yg}IO4#R#Km!UZ}OY$S8>*=InAzj- -L}^vtt)JJm-?2YO{a -Tn-Cmxb#QG6Kn)%isR~c0-~fWz{?P2Idw3K7Wkgi8y)pZCQ{@{l$z8_3&?{XhiZ>oP$6#iED0w9mV}Gu)c^yM+sf}#5 -yS-E_9Vh3G6DUJ7%oQM1$=MyTco*ez^e}TP+pmaCWj -+wNLA?&uvZnryOAoJYwY6xq!4t2)BI{eiP2vvyr@-)A_^z9kZ_&?91V_VIpJ`_VSCRNz#R^VwDDBs}G -{FV6Y;glOr9rJD{rMsD*=v$5l*3xSn#bGt9i{_R1;UB{4#|pPXQ-szqOv|<+!9hZSpRmBfn^Rj5dLEPsfH*b<_{fzHLxhUq=(%M|uyQB~$}e -MM#5ml()Ilaf&+J((VA<&z20)Jvt-7##UuFB2ksvbcKi1!>kdFGSnuY8Ic#BXBy>+zJ8OHP(W@B`7MWLr|i|K#91BXQ&eT*qOR)eb%7FE*W0obe8g8{|ytryVlWQ#_~xv;;BQ>Uv%~S|j7@HPfdV2@&5&;iJl6NC(OHP*k|6C -@WfVELt&D3il0?RD}Nimv1kg!xXK3_FWG#-qG{y%tb4iXj(74^xmL=!MaFK->f*nh70yB7W -#NcTibb7;=SwflJ6Xf4)6wFFPi(WZQ<1!o&YMZ1#!8v)#@PJo+>`A~QI{qq~)rnqwqIXXv%b4#zvR_Z -t&9njiKhUo~UXo2n|4n^;oQu6x_1lch*Qb~5&P_47vY6w+*^%>@^ESFPxd3jOEJl2DKi -o3AWWq+z{hloey$RB+kJ+2~8rByZ1Zm}q_{##AMLfT1+&Opm3bQ~UcpC2J8SIk|d2& -bZ@je-|5z~2i&Y4g7(}&K2Kh2-W3w-7kv}lM?YG6M7eb|4Czo<%sPV5NjqxgvzdFZBw{ut=|R|aeuE) -00DWFI3ziE@Z37D`Wec}QU%rxcbNdo%4*3G#oMT@USFM|fjB_3G33ZscVqyz%-$yaX@6aWAK2mnY{22-|9jQbfB000n10012T003}la4%nJZggdGZeeU -Ma%FKZa%FK}W@&6?E^v9>JZpE`#;t>NQj(MOOOZAqu+N#D_sr_alP8ZKec=CYbHUfVY$RLe1!r|CWL{oBe)I&}A3w_1btM{B)e -W}r?t`>HMfX*%3jWc)wW28Ud8`L6MYXo`Fx};cv}n21jm@@(rA^b>KTc-Jt3S_P{om31KTX)naywzK( -xOP`1)s3jdDcwWQNu;rRAR#3<`UkI>n5+tw3x87wk|jVKr`2Q9VdASy`eGAirg%ctrr!Ik-?t)W5!jp -8E{m}1~-8pXF}l8E)w4W4o?t3Y75S}t`@wIvE-@9R*B52+G69BzMbNy;Lwscn@ZfkSSewBGwdXx`z+f>Pd!^iM0)hIZ8yVx~v5_kt-SAZrWtEGRw)5nh(JbU -bY^?^670NBb#REsv_3;4;tiGLSA|5ncjpQ^IhGT1%R3}-NHc7r=?Dz;8xB>dk@2zz5$wXWgB=6R7fTe -iuY6|0H`7eMVzwqmzjNIK(c$xgP-s-pGO1OdV{TSPc)7as+Ax!@mx@Uxrr8nBG7!k(7;`i4H@97zHMl -_cztosWn)65&wP=o0$?jUj2h%}Xw!qoMnABJ*=tcfw>NE~zheA{rFX({RlBIks!Qz~2+iduq%n9K^d> -@?i!;1dkD6uv{cY|B6;kQ~!kjl0Tt@7*9tN>~b`I{OHy3yLYqqXMthSzka%qUyt|V-+VP1;{to^9pV~ -x&&%6fR3!q(Zc~xt?)GJ~1>ti`JHqoGef8 -Hdr4^6T-%=dr@t>0eJyjz65uUMI&VXGh2HPp2g4&h4qjaXhg?HCE#9@)Ai&(Pkip%?MIMPA+nM!{C*d6|msunA9oXJak+l8c?qdaKDQl|ZDy;lq! -OXeCIaWL1Ik8ML;*$tB+;OAZ2-hF>a9&>c`(%~9h@2{Z*SF1i9|4}|oWUv&PYxf1<8-0yW!&C@&D5j7 -nU#6$}&n-NMLL&qe-E99r(AX@72qpScFF%oGDN7-tf0ZhpfAkVx>l1 -P2RNAhAh>0TY&PI1FdQ!W!jic>bPs={dlp5-z@3Ev;p5&mG1M%dJvBj;$XD4`2x44u#Ws^rcPAaA$3`eq>X*+^>cuQe$HF3Uk5mJ>t1@j3?&~jYen^DF-W3W%uBDA13Ywd-iF7I -y6ub39aR>J*Z%S0DrGfAGsF3sifh^L36Q}zr7Z71|D6Y9HUbcup8+(KmBv6>4N^I|a+?u^t`nQ<8#LY~4#)3t*jcurEZlcc8av#h#{xXC0RVAPaGEI -c8O&K?;OYe{(-K^V(m2wlVeCm!XNTY_lvUH0_4p`~?z%c$FL*5~AZi%_1{!0G5HG -ndUdKGAHTbL(JXK(|331Gi72p+tm+D<8hdE^m=b9yZTw|9*yG_3!E#vEeegfnJ!nSO|29KW~=DAfLf&;Bh|m1c?LbVITBf*Y4~NduKW5XwK=dcW#q`pz0YU%H$&2?3+ -igb4h65tT@M5oe~BuihpqRn5=o0FLOZMyv;$L4J>@xnG*@XAY5X+Od69Ymol=)L%T<7YV2C4d#I9Vaq -Ahc(uSpVU2KPbv2!L#=YM?q?AZK3ROnvr^ef33?coE!H)HHB<0M&t=awWSXNRB9al~bBqTb$AA8pl#h -P#;XJ)z}DF|xyfpHXIi@;LPK=)aPj@iFS$L1(XrgRn#Ax6c+m$*yK{g?hln3z^|VpYcCzep`Fh_V0|= -zCzJ%I+fXxsWi%$?`l?|M -0$#)NgzmPH5p&e;OvdvW7FopcT6@Pebp0UEJ58fdLIM}L1e10HPHrfNYg&A~j%L0p2KxZ%784+=QYSh -gmN5E8+!oE#V2-icP^J;O!4dIPqKmd;o-S3gdq%I@V5acdp`^xai51pv3Wbt$=OK -G4Xc8G~C}arrPdr^L5_hSHQZ{pZ~Do_HNe|KE%)!U8ljx#JMVr{%vx}wWTkK -0_;lYP1D-Sfx?gsSk=7)B0mdrxBvXza$Ga{!JEp* -;Su;E>Tc=xf^jxAV0-k4slWPNu;y{aC&@L)6>3#;#+Hoex?*Ka1EVgU+h!liCO&0*eLV%Pcx!yd&Y&L -BZ6rN=nrA4!<+UpeqIR$WLR9J(+5JZY*v<1T#V|6ef>8ZPBEcm1kRe|ZTrWOu?ppEbXREA+gaoRz=jL -6mi;^;Q*qq^ZyLcbrk*y*d8$GX!2kFbkg1=_q&mU)6P;jqgoy#x$CL*S4r-Q;CBnEpkH%-uO41DTG-V -~Kz%0J<+JnHX_)I5e142S0V-ycuG#$*hPr+;f}<8Kh9!2>0u1eJ5vh4R&Nnb5595IF7E6u{W%HQ89R8 -R0W7ixM65m@T}dLjc~yVjOiWEeb74SzX#@}7G}zJ?KX@H+?zMS2bebC8>2)F@Ny>(+$ZWnRGvYgx29U -0f}fu25b_E3)M3F%>KOKpTtg3%@J0gjBb9 -_IDsKqqZsCS_^5;~n+1#|{b+x6~-`jCo0!Z_2Mj*EOZWg4E$H{b(g#(1vo5P!DlV6$wNLWZ_^_8MD0|0%%3mHPdtWxAy=6y!tW? -%k6_$@65Z;Jw?iY1a2>YA%#oQRxC6Pvrhwgt&(1`Gy``&(bVw!6N`KQ!*7M^9%L%dcH3{)>KmoI1QvjfUxltybL5(U7LXz(O(l)!x -`$|1(J2#!Hf0`BH!Lnm4zm57F0xJLgC(bm$p2{LJ;u!LaW@(DhDD(J)BiSw6zX@D5N@WB>rfs8%~*7vWXP -NM{G1Up@nNVsnF$d)v)uaZlDSX{Di_;wfV_y`W91}iNqTM(P)1(W@eP%04+TVrE}^&1=JwnMaQUV%AP -E@_2E?=J@t!A09s`e;2c0<_Pz6oI}dTF45FF2d^8R@ic0f>Ozwy(b@NU=5u&_ef -0Qd1wQRwyt4{h@olN2PTO(Dvdv9`!2{5{dQd;zJJa1q>U}VF?8J!s -8dG&)&ZCbf=H}892UMl@1LUXFz1qS1p&q(6G(9-D1_o^ -BSX6#c(*>&ooa-Q$612_1^WQ%Iy-O#AAS=EJCPKru1_`QSXdxLaIuZ}omifhNchubdFN~I^o=%%wcqi -$iyM%-W=51cJDq7AWZPIN}(y9wYbcqrtG<9p^SVfR=Z#L4M-f*G>oKmG?ZE{jb?Yj4QN#r1uw~1psc^ -Vn7oG4{OS4H$4f^$cpKHT!vUKMQv5TOO>#f1{F-Sw|{jhDNWDjvoq9@Ni}dX6{5Bxd3*=1AkD#U|Ziv -=ncV0s6oy5@CxH3*q3OuLEW>!eh`A2$tw3Bku#IJ3hMVEp!e}P3SIfDliOGgVqdY2Z2>hQ!f>d&%NH8 -ci4BTJAL4HASq0K&YM3Zgwq%;ms-)0BQ8M?DpE7Xhh!J3EqrWWdJbQPf3vHz@HG$u-H*QP7yaQ?UxH({mb~eZnj?7(~kNww$^my@TF|$(MZ>Rjt3o`L-UI@0yMId>I|mtDbR -f|x<2r_pwlRd;GI&F1OsDsPWdv>@wXs3Zu68~RTAAE7QuO6h!7w?)yR1}iN0zWJYLzh!?2 -+6HxcQ0Mgl4m!YY-(4kk6F*Q?BU_~ctTFIO5bxeaU~_j@t?%F6Ra4NSux8!PWn6(kx)xPi$CbD~fTM@ -Q#D;?xzkBiG#j_W`fAQh~)>qjyf!^3UZ%knrm7e%_jO`U;?Q^lK@ozEEqSMZ47ptOQQ})*nZ?U35%|o<(R~in=g?kYS!T>MwWLt584d){`Ym^;a5n7`FSf4Tyh7FTzA!nRr^*3OcIA -MC2VDAg%yKZ?TN-&FRZUS_79DF2E8YwGfc-`3R8<`iK52@dwT^a^q$oZt5;ii8QQtWIOc!q(y`yhPhe -%iiwGd`ql7{O$XIW@JQBNnW0pOF*jKUy=^}Ztp1b)$dQO99Emwt#(@6aWAK2mnY{22;YPhasUM00 -0Gl001BW003}la4%nJZggdGZeeUMa%FKZa%FK}X>N0LVQg$JaCyx=Ym?))k>6eA|G;Rnpt0bb*kD~2?QEIqtS1GXVIITh&F9qw>MR@ -jf!@^7tI(AyY^6*(WQubv2U+M8Rbye?nTtK6+Ew+XvBtx@z9Ip^Uuzr{job*) -C?`uwsM>*z%_!0(^bkk-*_@!tp06!7G214TGG0@YPrl3k0YYG7}`T$h+!QK)yHYwq|1w|9A -}m6^ZrWogKqs-`gyWN4`ZnS#ej3u?3FD$*>>neQEe*L;cH#;TAXf*m^Q77ylI=N$m{B7ku~{VoNRgx{ -Q=f=2^;lq|VF3I9YU{Xwd_0 -B$tP(E;G?w>oz}N!PDlt>e~hvWF7t3{?z%UL0IBrA&BP80G>C)2qVt1@M+(-eXw2K7P-@GE5>XncEVj -4Q-9x(;Bu|S9wi7jH73>MN&g!|1Ap!03VQ2ZpU+C9~>Pnbdl$XE@GAKRKW?v13N2mF4MR?7`N8nJyT9#e{`#f|R -%s>^C)zH=Xk*eCF5jx0*3igrYw_@;~9R}pDqgd;`IA$edgsON~l>*VEe)giw0dM&MMn#B|kHULIPRy` --&bCf+5!r4Odzz(g_6B}Gp=E1(5a#$8o@Q5o-BW7;ym&n1HDlfVp#jp{0!5ah&+PLckn6%MJA6gyfQu -{oDAg)U0`qx6WpPGQGRsz2@AJ<}v57K`*VwSLQcr@kqE&SMog;xRB&HXO#VY|yR1@W{wvq74prQ4oaK -S#jhNUWHW5Z8PUx|Urr~t8>M$>^MJ@(MW?T`$jquF4aGb#08K)7Z9s{3d!kprwFi9L7{jjaKiL>HhxU -R`L~1-XutYx*aQ!5~^BlyL{TOI?kze!B9elX|G&t7g+KR%%)Xp#>;U{uo{D!l@pbyZC6QPZd`0zIrd)fixGa$9#YtJO)RIWon2I9N}} -Q{LdJvTENBmLXKOr4WeW{g4jYgi)M?oNI{UP>77;3Y3VhMGctIIu+BIFT5@A3Ps333N{)r;|_ -V$xC47;pC8e}QSu3F98k?*%L7xSN4xwQAHvq#=N4D_WqTMS5Uahw4X_bou_I#ZMJ=v#u#K2bALR|~qk -3q86q_-Jo{*hX1@31@Ns(g`(U4aq2f+8U+R?~ufN@o0mN5hmqTVpv0f-A@^1Nf%dCw|=u_p%N@2oD_M -DKt?*3n{$+{JqiKxc3ZcX`KLBQ%_7hQO;w3&+c?k~hzA}4`HZu3fnD0?09u>91PkiLD;IlxHXJ( -GyEAAZF@?QP84!>Zpp+g)Xdw@TKCq)>c(UeJ>uQaaUD`zD5c-;yTOx$V_Q#}_#sJmQKfGE-(@za)dNr -g*o#~bDMLvKiwhIC=ba|u!v9)>G3oyGypTHbP9IiVu?6Do8R}dIO-dD8*; -Lp++1PNLRIE?{Ve+M>2c&5?0W|UeS1&jzy4473N)Cfq0b2Q6MpmKkZC`;d4BSr@x+t7h$pDjJgOCxL6?w4}n%}s)>!ngB^X3SId() -sP3giKFmDfP{=xyD>8eeJF*{JP?cK*UaLFI?-5h*V0=z#h3%oa>ujszT)%H8a&mAAf5JZC+18n+u<;>Q2KwU!hpy*m850ux`TTfd>eRB!s4 -e+gK*Vd)v#V0H$rS8Mnkk^HG0`WaXX;FTiSGC7A`2Bdll0Q?f59lr>-M)dBz2g+ -3q0g_h$fV`409Ih<_6z3dl`l@;FtP*#H+{ -QcqR$S`f^H)leUc$AHSRHMFnHB3n1ViHUsTAfA{;+4zmp22`gm_Pc%I;f4^2#sRxBO;b(oo^P_R-hRS -ZBgO;yCC&a(f|-lhXytLFNaJ*dktD80Y!JDa8=I&8B{YINbAjI-_i#S_Hu!aR4g%0op=yZJ;u2h`&aQ -as8rR%%3q9-Gc7FGUEu(R^auo2DE{S8PAnZ*jt1-NJl5f@nx3@t+}?kfc1h@gRl2Ew-vVZeE7~GP(o9 -Vy(>5F1j9Oe+6A`+7_kKEMMI(BtutOzUfQHSwauV@pO@?)*+Orw^5x4Nfzn7$V7*Gu9!AQrY%VYlRv? -2!O85F?bK(vV_l8T@t`?djIa-G*ziGP9I35m$%I6Txih*c%g4^lWH3>eZ{Y9ufe2_xQ%938~bg3yEeN -^J5&JuWyI5;s+bm*Hu$e=U3!e18tm5weZ8M@!FPbca!~W!;hxw5jtgi@T3#@L}8?QJ0rA`v9*}-Vn*C -)Q^Cw#JMx>`61fl(77lmc`hNybAD>X;fMP52(4QSdM+HAA7b -D*W5z}TJ&WaEv1wC_HLO-?_C@UXv9`|N3)0ZLkjp@FH&v27u;zz8elBHox0b)TTU^=)lO}ndmb7#anS -79w0X=Zo%}#YZMVW~I11Z -0AO|SS-G8!1OpDrJg3ksKmUtiv6KL6>BOYP!tn$ATW>NC@mC$bbg)pgY4HWMmL16hSu2rIEwy1k`=+}+JC5QQ-2R>@mS1eGq<(IWXrTQxE -L<~~{$%zA^N3Z*@usFQMwW(9f#MMP1B=jwtIt^Wp+2o`WWS~9@V*yVS&V3;jy8{XR{3Qew&r3wQM2-7 -WP2vGP)PcSe@lhR~I%5$2g`^i8yEl)tNhODca2FSobN1M^z2PztSqpWtYK`>T~t)znrlmKA;k;+<1IK -4h2|4P2^FzXCsP3Ov4m8Or9uMwXT(4U-#->GN7*XQ;V%k)yrj!oCYNL&k`D$`&UrD^oY^%@(p#n4_gB -DQV)l}arkOD(!xrs;AW!QXUw=dcyh@iXO|A%toJD>L>UWA#p4LhFyAB>)OU2{!>Xac{~sni+wk=q<2s2IqjX-M_%C;@rm#~TN-qvdiP5SYyMH6x77b#E7Ms~*3K=-3c;ba|NMClUXnyPulxTyAB*Mn$5T}GAnMD-DQc -jT0LCc_!jAZoangF^6LfRh{V$R8^fjOLG7@cioHG4Ge1jDm4$G@nYrUn5F=jT9{LnQW>qC^k7%Hy55R -@OwrSl2>gj(Jj#VCP}V(?=lP9@ydeIoY)Jz8%J>6F39hWCSE~^*S_lh6I=R7)gcnI9=da6A@S>H#w!} -XonJa9xy+XCYEwVHkMp)OG4F{MEmj^>F(ddo -Ek{_;tGw1i8JG%znzG*M9S#`Qxvdj;p5sVSvXpC#zx-I43wJcc9#SsQO=(vLZfAUS;2L~F>(!X7<_#> -SNlVpIlwY^uu?ljz<1Rf0LiO=%xZH9@&^Vg}RItBsLyuT}-Pdq#RAZ26`t5btGGkc>sCwQFxo^cbYag -3JzrznH=QFI3Y`nAX3#+4uj?&Rd>;w~W3F<{X49Jn8CG;SOy%`x!V9i-u5MM}8PFKU<6{NoI}W37u%Q -gfz%v2_|5fsaUlE%hikN>Uj~F6S|0k8)}uvC?>DXwe8cj@2AYO=rx`r8IGWz><5`;_1kgZAq&c(cu%` -rvRx2{o5KK`p#WatQ_Pvf3P_6K0Ck~xbJ%ys6$+LEa&9qkPxm6Pqv`Z0{wL=s%EWyZ#B1uNsRq#HAp* -uj^Z6<6-AdnJ24p(8gd6udZ9{YkqPUuf#pj8nM0jO*VFQ`PGPd~t1pHnW0@WkhhFgX0X*PcFxFULMz^ -yo^}xurVjipwPFH+_ACNhH(6U(AFikJeo{$_v@6>Z-Mb-9zu~6dYUi5O1ZZe}VR!H;`oE#@?jT_7ky+ -JxgsctQ^yVS_H --uc!6eE>Ji(Rj=xM*V$`H4s5q3YnyCe4cZ5kxjs^l^h_*TG3Oa}@6X5Oo->V%Zxp?CPDc~v=_#!BQ6{ -lt&=AD6r?5zV;L_c5n6FrZOhCb~mhxeV>Xx2;61`|a3J_Mv8%9~~757LgX0B>@tGxX8>HZ@fKsh;q(? -?6MN!PdKps9B!txhjQ$MRdMn~9NllEs~yG_49Ln+^q=OS79&UP(-*Dg}m_K8CsPP-{#J1`t#q -6mFfZPXDi0>tV|!NwE928)1Fm$PM~2&5u7Y95==UBrxRE_A`BP>NjBtJPeE{JJex}2oFweP|Iu3@75h -r4V@lac1^=GJUNE`p-QT(=vEmpSiiSxhB2}h9i36v!uNl)mlQK=O3Ki~lV^@*ij4s#=YA{@k16fzxbD38_I4SwFBg68hwsTk5{$Jj~B*uiATD`H15O~#yBf`nPjNQmc-G{&oNfJc9V= -S00>&W*FrE6_P7N7rZ4-0`#cJEl2FD@x8vnPZgNhhqT4q{uPr23@;Yd2s?77%x}oEg+>4$pAzKUf+OF -Z|`Kn!y+7)onX=3VC(?e+Iwa)Bf}A6M$NqX0IIH;+ls -TEjZ=1pBvYG8|x&(+{VtjOk(3UBu<%!iV=omzf@y3c%?YUT-J}Wvck5Pb9g|VxSt*9fD@S?=KKI47iYz6gUSl94<}YnbxsT_gF4ZhVbzqP}Uti*LcvY=?^U0EPia&IVQB(317EZ>yAgmRS&+sFH -_>?(6^43`i#=j@vWIPlu%Dh&Al7p*PEakQQ+!@d*TG*xVFFvyPA9Zs1GE^b=Iq8vDpK#~W%-BBLK6t -<_|tq;k5yX2p12U4X08C!>DOzW)x4Irmies@Vg*JzwdbZ;)o91#|6bi`{eP`rsvDPEv`6_SG|%PFwAD9+sNM}hH}10<=!WpHWi1#YQxy_4j@<_e@$Sij}~_&zc1%u -oaOBr!;t(;z@E&MrKS!nrLuN6Y%Tb(^_P|D}4ceD9!o>gwV&r+g)WTH$zV*aeTD{BQwWFH9xCi-kGui|qMv`78QQ#7oU~16=Zg}woQ0`qNf|i$?nv2nGI?E^%3UZb -eVsb9DgIvn{jh|=A_Q%jHN147F9lfqp79__C9(AlrO5~|J_QYhU*ui^|F&U%6Nc_+jrisl`p(F^CO<; -XB49tb(K^OC!As8ER@i}KcIroZ42jD$9XH%*P5Va+o)P4=r^Qb5FexKeK=IR}Oyqj% -%m~dpOJDao%8a*&C2s*A5k_5IHiBKk*WcPF#_I|9Np}h$I(tvFBNbn&%w$qhDOKOm8W=Pw?=AiHW=w7 -GuUsbki)SnRfCNG%`lI5ok%*GAi_xr^k6+49uv7UnJnQ9SXZcT}m7K<8hK~o@%;qQq0Y1CQ{8n4)A1% -LMKVI{on-3UbiZKjVTc05-&%piJR5~&Hbr#Jy=}~aUEQ9UCwQu -pn<%@g1Vt84e&Q7k>i*2xL!hjyL|%X7OR9AQEm8}W9|UW=^IBYs8Wmh`U+L>YCYh+X*E7mm>i3=`KnZ -x+4xS)k@`2w5=iJ`vWi@jf!UTJEu4IggLyz34Ho5*Y*OXXbFTpVE#z7xRrYp#?5v=dNEh`CuZh(OK!( -Zl-`S5|y`@;v^-RM$s;J*?wtCSpqlvrgTE3oZh#8Vh3w?2HJ;8QO))klDLZo!PZ!(bOcG7~g$D6*`gb -0GiieGll2#3V@zLUl@FH_$>I6Ht8n_ibx_G4CH+VT4=MB5$&vt4=~SsjL)h2V( -b|^QBO9H{zF&M(XU505-rVMe7o4n6X9LlVQTqEz;Gt~AmPp&z=XjA&IUb8Q8VDOiZf -^1w#9r5G{f^#5cE}t^LrZag2LVAnj9m5uo>vS4adiRhMQ)cIiP-wbx-k!$$fZDpQ`{7f4NcuUj8s~Jw -iEJZVDyb)RtAj#NA6u -D9tC0>+0a~NKK9IM=!LC7YLmld8fzQI -42_$Obkye&wV;_1o4I#s^D8(ix^7)sr*$3WeLKzYJz`9$Sw8$mKRy(uVIPc0L8&HILR85&k8hLP?dgv -r@U;!gn%OeVZ!%OBLmqlXS9H1LA3!-a-1JO76?Fp~(?4h&zu9448daBb0XFE;ZKHc_{OjWEXNkNi!Dd -WlO;_i`F!>7Y7x2h<_di)xbpsyd7&c{q1xL440$^3KaUC) -6bf<7r)m*Z8BfnEKd?lOHu!AKqdHsPUk;rGnfOoLRe6U{z^bHpPUb#sxD#++QlQjD3veDlpL07VqZO<&>tE`2P4u4N`q2?6C`VL>Z`b4Zn73#o+*3)L5BF4~IM`71RW};nr -gMLSckjEGN+0rnA2H##Vi(d|O)sSVYX2E~#Zo9)!+S4*8c&}(gYqgMqEh_hl_Qo@{Nt5BD3&e}o67$} -Vdp6UJmeBmo~1pxko2Bh)R`A51@^l~y@BoQ4lCrLo|*rBNXL(}SSObbKlVnaz~bZQ7o=J|I9=isGCpQ -y^QUEVtO8U&xoS6NR(X&@9DHF&?T$Y%rDo1)k$ezCh6qs~0u3U&AApvG -G*rrrC>qf5rW97QOlD$xnE5%Ta}3Zt&EQy7V&;I>Srcc=M;A`!%I{v&2Bo6y@l}fTec3Yi5p@_^R}lm -P4V)s7~df#2%B|XK$ei-UZ~uV182F*c+GRUGi>|2<)`JM+f@2Yu#I;Z9|oTgRdM_ce=jC`=|QFsSoWez=g4w>1FMKwrc133XIy1_C!qRy+P36dejR!}aa3w&8x^^x5YFEfRzVK~T44T`(xmmoSqITu^t?|}c*Ga~hez@)eup*$7&l16n(yP*t$ -%)SF4!*>D3^vbm9mCTd)*;(|MP7ZA7)Y36vOJiZSYw+O_iW)?9|P -4KppJu1q!@=V@$|OV;#&VV|+pn{`+hg{KvK##=2#K>9tU|QkuIX@L-8-#9yp9w`=BijME>^f-WG^)4) -Tg`IXcqaBb*HNOK=SDC5WE0_P?n(H>2Xexg(pT4m7Sus5a6L!TjN9Ue3q)fMh}6Xiuwm2`woM)UDLLs -|i;*HW@3!3`%Pm2E-iF7U+-Z)AS62f`-Vfy{ylz@i3W)ors?Z|(rfCFN<5C>jz!#Oix5_=c80G<#xiX -d}fk=S1dj=rb_r@LD2D_|wNXP2RSh0dOw53r}6-=K?vw5fnH0`q5V*FNwabSkmCy{ -eQB{3+>!L+3K+qxqk`#GZ1OhFMZDwgv6{+30+x_>>kdjSOl(#nn$yy@kK67SBi({)g!=&2pMYDhYY}c -tHtCW;b8KD}@gxm1CtD%GXM^Tw!lR33WF|N}>&R!bm_*O#Beia&@U$?}B%bdOITM5sf4YaLji}DVdT6 -IOst6NUOi{1!%7Fh8{HKO8D`~hXdj}ftGP!w`5;8O){pz6y;8!jcMmp^r#>XLLvRfE*U{Q*FZl<(;wx -x0hk=^wtZydzO>;P+m1aD>JrsYAomu|?gsLJDc}|Bi~;~1+l-MY_F#Us@3PXGUzRJ{_xxEUxz@}R -`4-HY78rhN*s&4?3saVv2D!^wb%5%&)O}0Rp)Re(dd;>tV&d{Fc2^4Xhm(`YaZUA3ER$7>|S -%!KP6%eMlg=Y21ubC@*fb>GFiHKA?Cnud-FdDXlpYr57fe^bI+#E<=qdGjGz$+w7o&p| -#{q}5iH?6OXu3^%cz>S!|)&D24~9hW`mY{kTmHOkP&0y6}3NqMx&Lw>h#+DLxf)|@u3r$s^n3;M!P=w -jj1uYA=_-!*K>mc>UUnhXugh74c%>iU|lLf3TA{zu=;`{MsK`tpF59l4>X5^!zU@|y=+Oho#~)b=A{- -q-A*Qhj3{eH${pTC)dyp&!3pPTUxsidkT3wd*MOhYOZAT_s6*dx@EC@lgixk={^M4e@ly4}a -yspbcy$l#Kz+P$nKdqeLh{E#*k+D6Nxi&%c -?&+uUO`UHuTYqVMb4w-E!zxS!a}sByjUqqatK`EhFWy8|$X7&~V0d%)_zF>e8CsPVhdVbNhope`;9gl -4_Qom;3leqq>)8g}fZ5okOcayzKOxQMlqcR&V^BAR#-P0sFta6r~f;X-#WkU5qF>sxj&%mMR*Dg>J96 -f%^exz)~y7Gc3K)f+8puUsF~jg+&ba_Zv)T -CYg1vN!KG@A_Wi`T9RUHsA_l@en1<;e}aT~@HALJ};IWWxPFs;^6TH0Z@z*wuOIa+03k_Ob4KgSVmRC -4*bUZSSWa!{0=RNwhwT;x+$F%IXE(w22Zw~F0v8~Y7nl!LT{BZq^73+#Cm%~{8(P%%Y;jvj?i`SxJT* --o#{*L;V0%yvTJA2J?Gm2J7UrI1Qj%t4oK}Mk;#@zk2U|3aVM>8LPgS|-bo)iBvH?uoSf*CbU6oP5g96*T{}pS;uJmmSX|f -;=T)4)HZN>!C+EvVKHHprcsv*WB|`=m*pT3Ai+pHgEEeg>apJr=AJJzOX6ic<&|qP*t+4okU@ql}wBd -L{Jh@EtqB}FQ5t^5007u}8+9|QNQv-{XU${;XfIri=3aF+J{EkkSj++Nokr}@wdMHC0i^dHu@I9wgZt -4l{-dpV0LQph>lWu^xv`}o+ct#)U(ekBP{wn<0K_YRanVY1;Q8q}c0dD+uFhw5Iog#7Y2}di`(@lNXr -YSmuk#1Bj>3Q;O==>DxZd%wcaI#r{MVa#`c-exzs;pGA!~QkyI!9>}=gmxhQHZYyovc#C{2h3(M(ePM -QRY=v#V}HAg28-zd!00?iO(guA!boHP#2hupKW6D%VP3$kGXoq+fms5KBO&vRQ)z=4{R^)04F8{x@;U -3u@WC1b34Lr9zN?HSBojD5$Zg<^1uc8wLBcm^=tY)4c(18^9Yo*FLh3ZKLH2|r_abk1l!gSLWGnw|3+ -X#KrzLKpdx3m;h!J_S_VsO8Qh(4@T`DZOvW^Zfs5zuG^QkunNH02TK7jgGIy|~o@Ea}%ZJD1nk5Q*Av^)h-Gq~!NYi(cE=`CnR#S@h -EX5@rXLmU9BA-P9E@m)c{A#CkOjR5b8k~>^LIMWv8I#+w+Kt9T6nqx$LU6cA!^5C&o0rgY9cIIR=2FA -oQ))6MC2nqBOw}EAL>SY3b(k-+V1&EUxuaRn{X8&Z>)0fjp?jWe=91TB38EGI(=JWBtDoxL_u=$d!?x -eYL*`pB#+@9;s{o_c_!J)w!v>SkDt%f0g1vEA6FA<7U&;_ZTpEn`IBtXqvEaoS4_z1W!ZpH~uhk5+(Y -@edIBAC$pYCc4^UvPC(eFE6q@TRM94cy}Q#_mbd{RGYq>=N9D^Ra+W-h4X(KTiAbn^XA4!|0E(%N)ed -cxYk%NCf&p*q_wUa3*4yXQ0GP2&Uoj}z76tmJpNvBeYH$-6Oj)pQno`Gscg9(Fy6`0TAb`+`a2lFk2g -gR1=nP)h>@6aWAK2mnY{22&!biK>_d007t!001BW003}la4%nJZggdGZeeUMa%FKZa%FK}baG*1Yh`j -SaCxm)TW{Mo6n+no|3Ek>EElRCiaiVlGOTOUA!yNdY4&6U0xcceY-Ca;sl;B<|Gslb(V}EI2!;s=Vv* -zma+~4A9M}Ulh;+-gL%C -0SFZk0~i=h_M-d6lxSfEUD$;WGm48J=sXefM%BgqHGQJqdQCTT=FgC`Hbk!&wlT4&f1?_E;&-3 -pOvs;OTl2guD6q8N;oiG+LLR<8`b5t$Aq5H|q(-@Rm=3eaF#dm=wwn1EY+LWxmyF=a|KRw -qpWPSo -e+H3#iK0ZGo9p#g`ZC1`LJ~n9^cR*C9j*M;D;1z%_Dtq -w8S)su&qsEjF$5-)$(yporC@}fSv4r!tj8D^Zrl5553Agg7A`K>pSX0;cw31INaUl&afKrchrpIoz!+ -a5G)RL@F>2hAvMv~|h(fis@d-+Mo#X;n)IEyhB{iJG5=2I1?0Ut7Wo`@_zYrk+OK{|lHf7wq9t%YCct -s?88o;$yYYoO=r6{ESsMLK^yQPB&H5UfT$c5vr#`QW?gG@SKT#sATBg578V~OTo;(bO|#OczmJ@3)GP -s+YmjV#CZpBlpyF&&TbEjonl9+gag{EQu50>Ma-V2AwibDH_+jSQv`jr3shU`jY>V!V=8>mYs@q({J+ -#x~faTv9WGHH7JiCgEy@tBj?fxj4D0;%&{wveFR?*>BZ-eK@m`_AsNKNXN0rrEK~*O_?ieWWSs=cJ=D -l$#_69g02b@>>`xD@gVJ4m{Cy^L2PQThflG5vGcqzgKEY7{e_-7*iMcQbWAxj`c*}aMkudbdG -mWfpwoLtZ0X$Ya&#!?oes0z*N0LVQg$JaCyZ%Yj5MWmfs8XKd>GYwx_nz -2XL{QMRr@v19x!S>BY=+XNydrku5q=BTK3%$MNRozwddF6iHD|rY*4gFylz%;o;$V^N_{1soPGh)y?O -h75sa%tJYmzm&(4W`=9FI{a)AArnvn4vrSuX1-~wfRkG`fQvWH|+4@SR*dSH)u3byrx;r#Qb!l4tP#q -THSyq -XbGv&8#uIz5M>+G4fCp?u&)1^B@5iM(A)LdACar79}b;Y9HDi?*%XXwR}w4Q{odNRx)$8X!zkhqAeOX^#I&_CoeuOs?C|gvythy8$9O=F-)Y|l&eg2t%CsWr8{*?p4 -QjM}II_bSuDNec6@8soWS{BuH3dmpScR`b?Zns%k{I7J|w6e;!QklQDT`O^z`4N;mxoy(Cu)Od?{#&+ -&nZASf&x=+9v$w!}-k-SKCDBEk^)#BLDUP0|bNv4KXSv*nRIS^h>F9%+;Z#pO##sob!Kr``3!LcXt~e -Ddkg~a0{wFc@IefY}<#|melV`2WIw`s<2?AM`2l4w3h_NYTE)bHaH~g(AfnnFwI2Wq}_rC+VR5b_=40 -EqBRAK}2fPF3t;Ck`#BO?3pW5QkD$ZppHH)4YlKHvZdoJLa?Exl5k!CKSQ=Nf-}kav;lXC5cd=6d~0C -66{{F|f^VB@qxB)G9%KNPeq}YNq>nMAlufkxIK7{<-*QF%Zr0a&@IWD22{k%BJh=%g4E0D -{FA#R+pH=!Qgv=$z(I3E|L&16mptdBIqY4C0cAfKn1R(2Lxg=D#@|)N?>jl$RHs&PpC?JuE9-Mm>K7N -p;Kv$hWWTp|C)u}IqX4kR1V__@JC@{y{iG2*n9lr_lz<>u3HktBpkz05$b~`y>^=DBQwvBsr!9u{?apd3<~MOn4a;8;Oi3p@hgoCfJ -nxDu)NGf3-U^EwU=dA2qhZmkOCQH@Z17qgzw^Pe1@xn8-dCU3QHsF>9@oOjCeLZb&Nh3@ngW8;uCaAua8u --c|WRv{|75OvIdP+k+$#O|4Y1qWNslToEnVy@7FGy?*=dhaZ1@@rLGXhrH^#MxCCVG}-z(Lt_j$0eP# -WZZA(%BiEqjwR3O+bFSMQ+AK95GGB5(sZN3g?%IRHkf=<-txLc((;`XKq`)aw^0phFoLvDsKS!EbkPRr*13g@r1Naith=3Dgi2u&Yog~7z%0v@y_VZij6!EsJ8x~4(1 -^Qm0a>-?bbi2DhJG;C0$dNQ{{TpyTspaPmQ(R}@Y7DkJCGC2&|;q{y9VgY0O+1 -I?BY1!c`YI`I)hQ>Jkv3zWhkie+Io+grVYG+(AOZ!8@GLdz0SYBaF97zW$2lA0s!V#p~9F=$-;(<58y -VHGoEV7qMPB*V2M#LL%U6Ne!BebVrbF) -79{c)OL3Z$bd0f)qqale<4blfnQly;GDxd?yjyN!~mp-Y^0g>dy;RvzOr$ercxp96vC -OwEP3mWQ)aRxURIyj_{6>bk(;vg$A!u4@9a(ss;_G(Np-(UoXslc$sUyr+iS?;OU8cQC&d3jYNvPdh> -L;4Exkno2+OzNPONqkeWK6bOw2fDFGQE!wB@hHyC&B7KztMkz;=pTeCcOv;EcHGg3|-H{$6N9YRT@k) -XQ0}cfJ%Y)?B{J%rhi@mqm0VuI9cX{vK6yS60uOxFB{0Z&>aJrJ<4pwU!@Vf4t3kiB%J67O-fTFri0^ -eW_f}3tLsTI>m?N%`0(PkVKwCsQ -A_KV)h2WsrI@|uYdOvxD`*)`yq$yvW}*kRE_&Lh!MgoZh34~97(jz(xbIM(K&v2dgf#e@jYY5fGvh9B -tcCA+a?C6FMy){z^Obe&7VAjyTqA@u@5Rr(M7z3n3iaB0w*APfwOK+l2ZF%0B_GPxZ$N-|%yDxF#Kh- -HsoxMKE0k{6qeY*Fo`nw%CuKt0RRq=-p?zCyM@dtjK-=wx6m5Pz#jk~9Us9mC-?T{u|H#lL#6Bib7R( -q`ACn5}{?<64}u!{>&-7nakbYQ4k8xM1HRt_pwcuL=lVZIlb@wJ9_5FE}@A)H?D5SVGq_DAy+J(UhS@ -$Ym)(RVEZ=(GZ#Ofpto?<>&~=391!W9@iFPiDe0@zI0TCj&O|!O&UW?pH8`}hSpIV@IhhW0c%xUR>kJ -PNFgg1-Bc0AvVs}o;LMD!%|f3Cn&kfMG*|btyF!y=9;B3!GeC{AWU`!_Glv=Wqe$lx#DSYnd&|TX<+Jz7)S&@P9<6a>b5M)ZR7M1N5$teJDP_u`)YRFx~?>I& -}j9oSQ8z(~^U|^T7PzYm2fFiMg`wToG-AU(2Lp~Xs&lB-plHMVu!R~ay+9eS`H(AlXh@OQ)+BXl*bzN3_XL)^$^msn$Yf@iY=jLDys&F8~h}nPn*8k6~v!_MVY7g%jw|x9ShPS&IHxuP(NU5f -Ibb;K7{xzDN~Tsy!mMqSjH7Z<20WwR%vc2z4Lpz6^gwsq{QjcvzTUN{G{Okf%i54d_C#@EK+PX7vVTB -OJ^2#amg$*rv{*p2gl5O+TE~3+oia5-9ky8IqHy=jWB^2VQv(ZZYY4CpCUvMAiY{wGxv0d$$QM~GrQw -C{9X9xznS$^`?&`lG+>m2*Frq;P3jk9}^*S?m#OzwA!H1k41>D#bdpQ8b$!mNYd@TIWdm{jmpwYmq=mVhm4 -iZ&I>_5`%1YYOp1jP8lJ!Rm%BKeHMQeHl7jI=IFKoRAca*n7^{YkKe)t~zP>4RegCpHpl@56xYZ-@IF -Zg!m@YCE4h94UR+sy0ACMKsK*hCe=jbzwbbyZXxnG68myFMWm1_kYJj@(Op{G3gZ6__}&k;YtRSj -cTcBvaxXPpt+G2NB(b|$E2`z-`87W!mf)&bL)Ff^F40ylQ|x{zR>aWvmsi5?8PbsXhuFL5-KBcIu?pEd!?Al -gGL=H6uWevxTO9t!KT;bsvoh1ZjLvFEE;w_cpWoqK#DuB0nj!-O_d)GhMURnZyM0PMxC5!nX!(WZS79 -s3pCZ8t?`)vndT1(@%sY>KPKl{ZO`Td)9)@Hzj6Y9FY?CpG~@d~h1VX6-%xO`Fa}E8yZHvbuI0cnpm2 -7*CtVSQzIozxgshzFMZ$u=dr0w)L-Ci$$Vz{psBFK~)yfa51Ff{fTxo^-pD#egwy3Bh91fo9((frE@I -pmP_&hSyDy|aUufM;n;xnZ-MpoJ)3|0$mODX7&cZja8RV1XZZNh#Rd8RW1@bYhxs>C8`E -2*abIw_I+JHvHFawglBLp4xaKTdR*h~r)2Fl&T)`?Nzx2+=@ -L9wAE6^VNkq{k9(cWW#jNj%2Y}u-9Z|wnCV{K -uh!&!zD;BUQR$GzLT8Tif;iI)pOwr&o6z7nxSc~g_eMpq-V#isN`FU)~-Ju7pq$gw6Bt$E=e-}ztPWCs|o5qSM@UaXteNQ~7iy)>8cZB(Pd! -(>NV`j_Hw^_BzP_St0eQu#45|4xhl&8EIRzcG7FoNRReBZl?ud*`&rs;s87%wx&2h`}?&xlhjlBw(2^ -q(yCV)pAvHUBRGkY>{Z{5!4ipXq##nQ!>xQ*%debQ@xk^;K3~0+RrSH$}Zuh<64gF{v|9bAIZ`^%Y!e -lDJ`f+<)M-!>9v+oherZ>hV9QcHcYlA@jf5VF=J;osHB%F(E{Hp9WZjly-c)Xx`5d#;!?F0{KYGLl(y -Y@hNFh?L*?GUEN|0J7ygP?W-D)oLjDHphAVmQ$e!KuCBlEkrfYfJCugm%I>Ppdn_q7L5j`Rr5a6;Ov1 -#%#F+_MN*$60VTgB#Vp#6&9TgrNDGe7t!kVvL7Su^dP^VwQOpNxB)lJdX6{dzL4>p8CNM6gs$S3zavi -qn5goS*1`w{#sfV?w()XAemPd(taJEt!D&K|g@vra_MiR$vQSWV^;e4@qw=d{-lyWd(tV; -C+^h*3E+la0vV;DT5~-RJxI#w8=W&u?AY#hna=Qd4ZM=)w|FQqE2(M95DNT-O&l&c7W%#KwxG`@m}0jr7f8Y~}GM`xCW2tTUb)jgChkafY)X;O{s0&fhU-9F`K-3Z -#Q#grbH*c_a#HM-z~=n{7!LsBDYJzBcQzwBy{RMr_S80kF9NRbUrtw%ly3hsP{aCAxg22W&ZA`kcDpae9wWl8(lg!x|dW0pnv0&lDP>EP`2#g -wrFhV>FKh&cN4Doh~N=RZKf#E3m%TVXt}(;-ENkTQ0Howv!py>H;Y4ivqbii#?_&&-4@qV-s2a=Ay2OpUp1%QujZndSyKBM4<&?4bqbdd8%!4j> -7nQ#i)ADQ`loS(FVFy0_43n5KCUOxg0R*mxzCJo%r=i+f95<5%l&G*mo_e0I~>DAb(J)+y-0PQ3D(P3 -FPJ)jxZH;>`&%IN9lcuW?Yxc{QPPsA(ou(G(pX4fHh0(`<}PIh#-Y0aQB)Bss0wLRqX7H-07B{3$6g6 -p_Eg&K2StJK?PwCjb(U)l~m3@64BPfVo%w4XVhh;4yk?ukq0L$q5}VzvYba+A3woeZo8|EWb|vw*KauWpns8`5QtMH!Aqtdfy*uq9ef> -(aV`8GVEZ_)bD)$&Bc-a%}^tRC5}G0$3{2$nc`^X#taPBL$Qs_p0?aVEWs~LPNpEl;q-^R^hsWzJ?As -vGB@oxdi6`pf*sM1A=d{E+>@IkwgE;FdtUX#~y;!q&U{`AC!&o9!Z^q{J~9dzeXwbp -Ml57J~c#6SR;pN0aGZVN+zWFzujr5WC>^zZ=+L>62KBXLz*xlv0H8L_&biFs0x|lvK&xTUdSH+L`$=$ -nFGgs&2*+Avdu1*l<-^-z1_f_?va}oGWltceJyE(b1dS+~@eMZtio$2Y%?bH}{DN!LcjgLe-%sIlSoY -PYptD-74#*F;38z@1=v~H*fq~=^R5D^mM}zDt^Ed)3eLA-Zf{_psg!-RMx3a9R|%XcQ%Y>hlnK@(pC9 -vc)j65up;AHi1}dlm%Cy(bLZvJNjdGtCge2v>n1~G7K74Q$}0`QJ#@PsmY>CTiGqglQb=1IbK0lmgPK -LJB51T+QI`Rk#=%#q2YIlZ5qBVRzE11ZUb}iu2jW(T4x+w`;DnD~fp@%IiN401g0R%*iTJq^?}5GQy& -BfAA(P*LgP`;|_pUXk^IZtId!kA@+mYy7Sg`V|Zn5})PYW_p^g%_53s3iFfdK6~4;EMXIQx;PIPJx3T -=8eph*Z+35E~q1A6(pEFmm5{j&QaFla}88I-PHAmRo1%T@PYvk48@qB3+mpx!pzTQg@uy8ynbdXq9_jwp<`W5y-G;BF<^_;%s}= -^Og?;2c%97$b(OVplHi?bMK0uRwr%J-6Kc@f79S>}_7Due^NHPwe;e~8T_3F2{;)#rY8sDKo%e4N~fA}`J4W^Hp63>|TVa*_;Hqfllp8ofUjyDahG#X%sO1|Er+9v+@N10zZF*ZK0Bi$2`d!@!Gmoy*x|*KL;nHW_SM*q(+O^!qC -@(%m=JER|+^UV0|fJV#Hj3}sB4E-E7k?U9GGDKKOC?lGPZW*m^84}tWTLOysBHO|ueF_s1%+_zwum@6aWAK2mnY{22%h40006200000001Na003}la4%nJZggdGZeeUMa -%FRGY;|;LZ*DJNUukY>bYEXCaCrj&P)h>@6aWAK2mnY{22<~be-QZq002J%001BW003}la4%nJZggdG -ZeeUMa%FRGY;|;LZ*DJQVRL0JaCwbTL2AQ547?ls2OSe|^8iD7Xz3wPN=c8Vn2jwbOV-v#QWE<6?%Fs -lwOcCK!;UnX(KJjg=!du69&GE06&{UqX6G=2XDgZ}Y0|_YZ~dyYog#O}tr$=71wb^+kKE1h-QwwN8C& -f1Pqv_r%x{!8>{X|`UYRboMuzpxWKoE6HlzDK3&y=^QaK|64@Pi{Lhgc`rwN3ru>l^S#el>TbWH|Kq- -8KId7n!$D_I?|I+k+w@g}Ux>jBXP#*WAh3zu+r|Kr&FONxyZgcs6H>s{Z+`iYr%v5dw?k9*WHd83xPk -~qXNwLCQbZKvHFKlIJVPknOa%FRGY<6XGE^v9BTwjmdIFf%4kng~Ckc$o28r<&P!x` -s2WG4wOKsM8u&D=a>8yZ@oZBEOgMwGha3-aBssz^#CMY%iIz+}=ASu7Uo&##K5EEbD5q7ii|>f*wF7F -tz(CsqCY+4E~p0Z9gn@Ze^3g-UN%T}C4-QjBnK -Rjcqt}gJ0V7d_n<2V@z0ZG=h>UU9eYnXWCZCMGenL4mS)rU$J9sJU=T6LKr1wX1giS|Ki!8lu#s^3?_ -Uv$C5mqIj#dCgi5BTF-RpD~yVeB6t+l_fCK?>E7=N7gg5uV91}df3q7AY0vm9QwLkvj;*%S8!5{A2-`j5vP_>;UzKc+TRH=uAZ&Q3&Vn^c!h1LlB!B3;z7- -kLIbWK~mg%kqVQm!cn^(JcywU;}lIKRX9jnyw2kDk<(5f@6TvZ@{n5LP1S&9SitF8o!c985u+b -LBILy8lZwSC!L8r*_?^TtemBk@e%!#oZLv}PZqhTng({H@tP1pNA`Zz|%F=zyMO`8|kQwOPZ9JAU-Yq -Ta}Z6s=B;zB}fqvwd5LfyFlxg|Z)Xe4GV>6fJO(6}$jp+VQ`hgs6VRC&{scRt*a*jWYaA=uA -Oybk8eU=HMwnyr7O<4w@)t1>+XeqD$}z`ZzPoxx#GE^{~Ug!QaV+f-6}kIK64ry_^#=kOLWm$u}Ury{ -u$+$vb`=6zeFud^q(h6s%FZX?Ut21bBL7&RObWuyfE$c%Szgb*cj^t--;AQ2$qeWs#b}>w~&NZepkAY -^*2Mc|$t8rY%Je(I#;Rpq@MDpE4Ntfu1e%yyj<-=PMis7F3|u7Udhy8N)o!+k6HsFn;Fq^gM2Fk<9aF -;M!Pjc%*bs*&6rt86>i1?vGnLP#!^)A|}6OdvKz_Ho0fiRJQpm`v`H-MoNkf_?I7 -%MF#N%gB`j2qXcKij1O>pV1RLI1X1uoLZIQqz2p0pjaUmS3%xNE77UE1#|UEHZ^20UIojWA_LohEd&G -bYn}cX7z|u9y6Hgquy0J%TV>3JR-&MOg%bNZyS~alRDWe-%u;84Wesw!nb_lID*~PdpZHLLjHCffKI! -|2V-U%b4mH{(=t06PmUw(CGofoQ+mW!;xp&yRw5ct}@rfnZ!3pm|BX@J`;wIpEf -j4_^Jnlc-69j@V%45;kbN0a78Z;#0Wnse)d)cxROy!6!i6V>6b<1Ar#hMg3v-ps_!5WvFFlzP*fT(sS -3ThAtYdbg49pR2GvPJegK&<7NH%sy)zHnBnk#JgLCo(9-zMn|oJx)g3IdBR1Al|n*Qii~@8DxdRKm?4 -~?`6AKha{&m3g6!kaN(L-JVB;pB(pZ+ZFD&1uYYR44J(mfIvl`-1B!L0{PmmL7>-?Jm|yU2`PdGJO~w -0|Y-44-eo=AADqOr?`oViOdS3fTgWHwG$(;bmUcgC#BLYw^9kTnOuZO?mJDVJ_e_F#mnVbZmA-o@e5_ -xFVca#;}IUnk$9q4I!eQ}HX9>n}Lx4Bb}n5Pp*69&I71dImdU<=H&HuA7Ru0@GYIA_tP1r$`L^a3~>gKeEq;ZHjMMx5@pV$vD4H;BK9Cx`r%-PonV&JAgTfr|Eg4-`h>hB| -T$`d(tmrN%+=`V(@>Dk2LleFg|`X)q`?KDux1=`xU1nI(`2#b01YQbg~k)_>XL?sYLJb=W6+73DZ~MoM=B8FU#C}W@n6ZUa;3i*M -n|coW_`%Cm?3MCPlI}OF~LxT`psPSGvPPKl#MG!d<~@#G7CTv(BU^Ix==Zk)gER18H%0g{|As|-Col-Dx=P -a|6lqGI+CCsO!D<#(&Qp)Fl;kSth)lc(msUx%oHp`Kfta-^rsSO(q0bWp9ii306@#}0*Y2HdoCnVN@E -7cj!gAA)CXx$tms)t5rNaD=BdQsKA+zz-r!&qmRe*3t7H9~*Pe3OSTU_cz1I&!hfME0eCAM#RPnS^vv -J6i?CSr4u;8bi>x|7Wa6Q>Bt9NUmBO^?chKtn17N^l#VoGF`{Am$PDuGNr{hR$uAh~NWKa~M~+`8F>{ -p$}Y}*yC!l;Os3`tKcI&Qq$p11DsoDl6_EE#duMu9u&#xL@O$B&*1?btFoaiz-WgK-e9OP6$8B047W$ -T(-rH91562y1QA5%Rrm0KydC;vqzh|yN97O0Ho*8qS7hvU?PVWy6KgB4#KK|&T=5K-nl>w=7)YrYjfykX_B9(!3v-l2xLR&DbEeaP~ -tU;JY38w@Z8~NzyapW%svq3dMSH{MPdXBEk<}r28%ObE{-G)K?7Qa71hpAwES6l|KMAem69g8`vTY+_ -lV{B4&o~e>6UalvQB3%LID2bP=}_Jhw>o -0r!@6RM?GWg9gIOVyCH1r(+J9%55l;nz=~QSeA6Ji7_Gvmg~MH~{srt(fttV4K(a2;z8?662u-75q+Q -7AlYp#O(xLyw35!Q`?WD28;F!j+S9$~zi&Jxmxp3OUME|xg1w7^sw{JE83?b8vwZJl!YD-9R^HBwNim -vGeP63_fA3XqLVwS)$=*0Vu!a<4@Hnvblj`frexX}mn_8T||`wR77!#az;|Wp77Ao%ftNNdki`Tr -$hSjU(*Q<*Lqq3`aXw{a0Y~NVhu5=;^WYBKr+~4;X@g#QCKFu;$b|_P)~A*d8NejcJr<%@SwF*j~vo^ -niGD(J}5-9_U4Z|yKdgzuz&xLKNDF|fJJjSVVf!&GI--Z(x9Yx7cEaF8?cBEG7!jx*LR6HMZs`qMwub -GeF&av@t-xqAG*fjQq<&d`}}8PI|eGz{vcE6ASuE$q2AB}BQc#Yp#`>}jXDDwV{i$&eOJR{W2 -Fw=4`&Ik7Dmj@O>NoNf#|n?)~N|UkC0_AP=xj@*;libZ_%WcyBQn^??NqETN&)k{~{+G-AcnjuM!!&Q -8dr0!@|%1Cy{(x>%O&U6*QL{6~`LUUKlTGW31F`JBnZSHtT81Dc9DO15l*JsCLQdh9psyqvxd -=geAcW0DxxuURK!Yh?&x5ZScl;=WN#l8P;KnO?5@DXw6JhBSoK5d;z;?@3Gf`5{w=xwCaH!u$U6n8qZ -RLk^*ZwWAFMFv!gROyLHGfc68b<8p9);wEz=6%Nl~L^!gjnpb0&dJs~ILl${mqNfx#MEzd$DN;W;@pqe0#QX+c6var@C-8JnaH2ja4V~#Hen)L2(}}cUqe|vFt3HCEyxwD4Rdh(v^<@~ -wy&g6`UP|5bR$?7S86T=aK_0OzQOb^o?M0(fM`mFElDj#N+<*in95`eu?g;d~bh`u(T|FpSU|R>YFk5 -10M93~uAV&5!XUnyda-KD64>aQ{1I98wBU#`}xQv+k_egCZJcY3yOOXtJg^UD?*m#d*L%A&xfqOtLDN -IO(L{jyD4J&cv#bp6P0=Fz7lZlgs5D;E2pAb@Vj=75CHT*Sbl79xuR4 -v^!=8n*dL2Kn<*S)fWE7HqsWCKu|>R~FWiXfZPZ1%}m|EMyJXu+`6|ReMnA3-&Uyq7u9oSQ15~%I$Xw -K=A;END_@I1eqDEaOz}G#AIT*I$1A;LmFAj?{=Mxa&3^3QoxIP;uV?3Z9f^U$EtifBm;<&hxY -y*dI@;aD9*3+ZsDX^-DVcNSBKKl(_eq&UN8Qv6o2xjW`C^xAH}F}4P^Jv{lj3N`k~P|dJ}xJR{)1Vd!EfTvZW-V@!beG-uG&`rsMEzX;c6Y8n8s -g%#%)}O5QIr>msUL#pWMW$cL*-Ye)V| -2Sw76@$>DK%KLy~98~j}z2Pl>EjNH9mTvO$Ls$sgW(#63yt}jO4Z^9`e4ox-m%jO^0cVDvHN>scp2|G -_eTTo}bicIek56_BMibJlY`ZJ{Z(%0krH^*(w?!gKZ231NjC7v5HjGr|i&&GtXz6OZXem&HgIw=MqytDOaWD}{{8>2u&PWD{Vmp`O|@m>rYulgEaman3l -F!Ys(m4PGh*O-ZY$86jiVP)z%q)L^kpq4PC=&DPKR%1HlDQ!&PdG|ABf&K=A4xFSpKi1qA+?B<~g03e -}6z?eJx|I{+o<>?@Qi-AXbLATy|7T%cFbbIHgMW>L1Gm-J1IeRLJHx*x<=mJQ78CLCRtv#Y!>USgqDm?D|gN^^5a!hQ8pzp|fwt=$q6-N2urargT~;_ -sUM%M~d-StKURp+tzb3-rqbgDEFLdkLcVG+ysgv=Y}BgD>`z3q)~#qjgUIEEGOwID -wAE)9PYwG=kCH3uxE!c=(C;1Rsq>z0Y7TX|tBBhaUUPzi8LI>f4xz=RMDOd0+) -Bq9c;=f^MmKqSg2aYpJsQ(8266EG+5Z7hO9KQH0000807zB_Qvd(}00IC200000051Rl0B~t=FJEbHb -Y*gGVQepQWpi(Ab#!TOZZC3Wb8l>RWo&6;FJE72ZfSI1UoLQY0{~D<0|XQR000O8NLB_@Vg84_V+8;J -Iu!r_D*ylhaA|NaUukZ1WpZv|Y%g+Ub8l>QbZKvHFLGsbZ)|pDY-wUIVqtS-E^v9(SnF!zI28V0=sO4 -xEDm`60D&$8!;~E;ou%#U{s_TU?c+u>j^&Z$cGF?reb13(Sx(Z-g>;t{`h+Gn-Dd_e` -uisSG<;@(J2&Fd2JiK=HcwoBg1R+M(BXmRPFst2@>z7EPR;GUP8Kiy)+{KYg9(PH2jZN8QjG -&*lY`zgrdb;f8#7x1|k54?fa?3GsVnf`G>8{Ra7hIj7g6-g^tKPPP=$X8siARzI({YB2c;cX=joBjrQlKCk#KLX00^Cy>5*@3QVtB<~6$YKzreCM<+Fc0#&+`5Gl;aGX_kwUir)^@rsi#Ul(7#E|c -8(Ke(Q;Buny-Qncx|wb{%CT{c{6_C_L(iX&OxX~LpF@`Ndhbc{noQ)es`!hBKz8FTE;J+D5kV#p}lmQ -I~T?ozfepQ<0ri~t#~x9;(2bmlE??OL8*+IejwU4vQ4YK#%qo!O*iqpds1h(of=-nf~@VW+dq2 -TWJBjaAd~?67I7kph$UGnvmAUCs9t(;>%(Ku4nsQey$Y)WmEIKN%K2#NHhW&q@XCoo^oV)Tmw?U)EsG -&N=Fxd8$LiE`2cLo=Afm+vawlc8i!80CQ}SmF^L<=*#*g6NyDGUP|+BjV+LFfhx-IxICuy@{98|-%~ZAVB+!_?mxurZnBNgPr`MoXniZ5Nj2 -s@_2G0e-n~4SiBS@+;-)g;OXxy#BQ)Mu6?YrYTR9AYIg5tJzNC1?u7KJlg+YD+*94NkfS?oq2BC2_$G&W?D%jdi}iXhTBeNQOZwbQ+WnXQM0*`RqpZFd24H?RjutpBu^^{HsJ=qqnWG6M@~{lI-oR0|@scc{arC4*^+}bS- -;aiE@PyBhEpIqsNO`z;ACCd7dwEuj2}5HcB;MEyaM>bjmf-N{}iF#U+7_FP}sn337qfr>*O)Qc|VKb$ -{pJ*DLFjM6#5qup+~l++|^k{&>!cAh+J3p4NzZL+Ab-(0t$uv~1Am_mL3u{|z!mZJrgxl*(*Ji6evZ{ -CPrN1leOW$!X&m_1=Rif|jDO$M=!4t#keShynSdI(`*k<(|otpEl&42)29n+&?mXA99#CV|&uFS0xl% -GtvXQ{Rp-_AY$q1;XhCkPV>RF7jJKrz@v*l)82yg|GBxn_laX?w@<2220$82l6B>dM+?S~Qdvwu( -P@lW~R*Ajl%F7{RbLIj`OpMC5&u0g1Tp%+>IioK}sjP}9{82dzj49hk&JUQbZKvHFLGsbZ)|pDY-wUIV_|M&X=Gt^WpgfYdF@>5Z`{Ta| -8Btl!-j^TJAh&11VxK$uc(_SjnLFqZKpwC2sCxv(=p+oo13OomogU5o35y<(`G}-DhLmm><$W^f}WUK6~C)HI}7Wq -rt5DWJeraee(*A=Cs^Q>;SK!6v7$$51&PhYtjN3TVm75`^(nilbAR7aeKX -L_4sEZS%>=u%{X2)r)?hf`f^#Lo;4zQR*4i8E(VgPV%+>iNnxE$W|<^uSkH?Z|T -`ACE95^$9{hT9vwr_oeclAo+El%wld52M&dGe9V4@$(Xo-`umyE6czTA@JrYl^>LM4QMC-CxbtuZ~qT -7gWBgN_d^h9V8OA(!tG^6Cj}YcUz|s -!#R9KSZ?hhYxbO2J=pFo6?nKb>_Y;{7%iqr+;ux@^v7yGqWL46up8qw7aS+wo+JMQm;kOJ%N6DKsar> -Dl?_PeJrgp;b(FKV&7-51*|RD1oM1uY;i3LMW$7)*rMYJzUB*0wUynjt%U2NTg=mEbtS!cx7npk$ISl -HtP;O2jKk{Wwkb*QV>V8EFl;bi1^hShj0BSW2pPO;Z*!U%IJ-$E^FR-h%T%y1uV}7Sc@{+5Gy+Zvvv`8S7Z68XMW%_D -L`;#(@kxB%jtkV;yT9Kk6jlHKn*494$%i!#fst7beq99E_2+3_)7C%A -l}0lZta}iCh7%^dmk&=L>6Q6NGM>TEb#%jLd?)@WZh|4G#qXj+ZoW@qxxCRU!Bio)aMIHFe;D{rHXgf -!iORY{K^mK<=X=;r-0%tSPM}GoL$ml3pj!sxW*%XB82QvAD*$8IU%-4>CEmOl5`6O}!3lBbs||pgRyK -fip+SkvVQI`zr0P7EabpmOP^DKx{)nH}|K?HLiv8{nafXg^_DIqPW+sog``TBh=CQzJ~y8nC~nEeO+9I%h(>4cs9CO -vg*GLMNOBSZ200(GTS*>O0y!dZ;S^s|s^_PrUsj~;$kCW_)(N -*(bP$qUY?Ym4FpwphJ_iJYNDBJ_Dun3>SCTaGq5`c8M{+3u)41^aLBd|V_FK$MVF?`rzlyjtZtRg@{bj9kE6X2@9VuhS}*EECQ1x*58B+Hl$x8=nbNvi@z7)qLXxhJbe>eF~(2-tK -ZR96_$3D{SG#sk-rO@OrY1*i?GS2#7p5yX+Z}x4P=ZugBJs{kh6KX)nGiZ)7XVX06&L$Da2-?p<}!L& -H^$ghu-p5deIHJ9v$dsHz=`B+IRCP(O#z)%Y5IZUWv}2(=@SlmtH_ZdP_tzego$`5QQ95xMCa^4r(!u -vD0i8P9HM`nfHhS9?>LYQG?C43oI2A`SZFi8U3(mKz%J;I}a}uFqZnoNVZxtsbOufn84uwh+ZG^n7wD -8DY6%fGbFU^v!R3r7I9z#4)pvCp;5CLOd-hB7BRe#O_<1Lh|zcN)?2y80(w`w>X4B(Gb-?`J&PY$-4I -?o!y3cb19{k*b($&?(NfAY+lsx17MN-WUd>N -CLeyc07DZa0(8!uhFq1;AVsUoySW@%>D^vSX}Ro`8bSjP^3daC1f0mE=SY>be4G}7R?8EG6Wve$>LIm~qj);3{ -iW0pK3EZh3YvNzBD$;(VIDl!+I?SiI6H*U0}_I9g@b$~BJI%5ziG+QQVeZ1(;6!9ptuWpaTX -^lngFWHw%pT67lOTRlXalDI}B$Y#%n8UE3Q+>9DBjg=iN#S`5PsGbQgheh^{7USsf1N(ax3= -XY>pcrOrpa)H+;0a7K5+jBb3X&kY#>A0?3jsP~x&@==|Dw%uI~U#cADQ6oLG(FRO=oK@Tivn1)Z{`F; -T|IR2d7UXHW53%ew6hZToIb@YGl%0f^$2rC9u{z+j4yk3Bp4N@u(rL29Xlf5Bw;xrfK6mWZYD#zQU5|Gic!+l^#BX2+I8bbl9_^cW&Blv?|R)(BY;kCkJE0a`MqOjs{3)ALjVE8g)x&SLB7i)d-N!N+$nb{9i#}5!K7yjvW8k*Q>k0zHDpaf!sE8w -Cm|haR04K{)}xOb0V2q^Fmbu3^j}dWPqAg6OR7o044j;joe0kAi|T+3LQbB4^?V^-;_Zq(u#_nP0(c= -Z7kHVpM)hc=y^xH-bJtw7SuXKl3Iuq;*QG9tCN(r5`87xEp0jAM>q8T8iaKEfF`wll&dOY2%TyQm_>V -ap<6ht{56L*)rDOR1j>$CA>0ak-1_vXU#Vc4p!gu4DADtxcmj+_dRZ!ocR|#Q!?alKO ->r)jo}|ZV{iLe1u^aSA6nf99y1*}>J~E>4Cm3mrgR0Wj_F89XiT+7YE@&ku6w9k-CG69-+MQ>`Yl8R_ -5L@#sKSm_(IZJCk7AHY4%S75^DGCwA#McUId{E@@kZB$=!zDW{M|7a-TmTYV~W(>Mi<#HO$1%n^=o3_ -ED;o!H8&8vtD{b2>$N?+HgtbweUQFK=Hiu+GbQuoJ{I7*?Rv~w0TtkdvdN{1?*T^O+ey@2(}P&P$*xE -smB`wzSQo1T2KIz)CTO!p5w8)3@W>0BU73@EvHJRy()W@&y85N0y(P7-%d)b9oyBmpbYHEp -r0il25;=m=s?{n4xg(Z15xx^{S#jo(*uYK12r5Y;<`Ohi^8AkdezbH|Rat_px5&BmaQ&l4;URUqP{R- -&Sl4h2^Zj#Q`&ZsKf?g4b{L?cGjYXO-S|T0k%q*}Ily>5}}O>t$fF -O*@G12jeErt=r18_e$9NfSG^8bR5}spY^;>n)J3?wLa@5WBwf2y54>uO(0mNubY|)2=B=qg9|$x2@SP -2+=W#nCk#`JnF2YS|K;o2Q)!#2p5A<)!Qv{;&kfCnJZj9Nj@XiUEAkpnwahIdGc8zzR`BnZEDV%)d~% -F>m{SLgkhQv-rNMUF0LeiWCF#Z5~G-q#fz#?(ymYMW9Huc8ea5!za$Gqxd`8>Vy)U+E&N-quOSMY-Ih -Yp_AEoa&@IOMEe+uh0NC38Td5ChEzHI#=7|Ee>1L6LV)0~n*cjcsdwuinjF%NPu_%s`AM3(^6wT3G&+ -+r2J94(X!G8g_$7a3D8~y)XLV23V38U9&rezDfJB&}$@ooL3AiY*Mi`nUygY;J6Y^&9~9-aFE^p3mth -1-YF``z7xvtZZ17&{y1G~C_0O%wc#cXK-oP5jWUFq&#WcaB~_ST|6&oy=!FjUHIbc;e!a+HIMO=Z25E -o2)3HZ3o@UT~C^1(hffHWa|-3gSPa9?o&E(Ja29^js7@btiEa!g6LOHv -obnW-f7YQI7pW7B@x9!f!-2XO+Z4p6c$T&(1+bP%X&2#qPPw%?F;KXCN!y@ZYUi5@HQSdr9dlPrSuX# -ME1I-0x)NX$-L20U;L6+c9M>ZY4rtxxW~SX_pGXyHsn+0B9j`Thw1yaJ$&PZv%3yaWFEPk+mbz0}A*+ -O}Aq`zSFyLcP~%i1BHl{W^0;eUDikTx2C?rhKeN^utudCOJot`rsR3!BxCRHk}Xl!sNvnFPu-*KQM3(E@BT% -vuLzkS|dgLV2iK2PCxJYC|in+n}|8)1nlA|~8c178J3ghZ?1bRupm3wBG%WHRHbj?Z^$p<8EuC!|Ygv -d=GYX1h&ouTgOKX3B$>gFFs_hXUq9lSHqllbT>TlabGl9;&HTZ-C!{S#120|XQR000O8NLB_@-^JqwV -jBPer)vNJE&u=kaA|NaUukZ1WpZv|Y%g+Ub8l>QbZKvHFLGsbZ)|pDY-wUIW?^G=Z*qAqaCz-KYj5Pn -k>3sYKlE|o6DJ;V?EnYd4KSB;*1Pe-&U)ch;xiP1re=CHv^eCL4{0Zg{(GvbAFO_GM!E#|;c$c>8nU~ -(y1U+0-Q{lIw7pn0buT~mReAmCC#8C|8R}KvG*xHcRL#vzS>Js6$);^~qCf26htS{BPd^dxT>SL@b^h -v`*RQ^P`|b~O_3rC()$2dsw9Q{-{Xv@FZ+qDm*OlZy`=-@DzbiY_@Q=kFN7KLF6+5}U81}Z~_xrwV>Y -~y=KgeGPS+Au1X~6J47l*z4b796>6*SiD(@*sD_T@gy?_|Ah+H7B}ZVQ}x)&k_Rl{;DYotgUE`mU(T^ -$+8xXMGSX#1G~TO#W!sp)V`j>s{0CU@m`^Yh2@nShuw88f!bQwuWVJUw$k)_g+E@`eS4UTAGcCg^dj0%eq2e~^Ufo{uYqRT@|s3 -}*Yt0ip$|dA7x*xi@tbU1D|v-0_=zW^ryNT_K1L7zd!Wbrv5 -W*0ssm>(~J~}MJ80%Yxz-ci_ACpvo%vw~6cx~o>Cz5$4bmeYkR!RPd^s#X^3gI+unuf1_myTwNnGxT=1=%;3tjCpJ8p{yS -hK7ZooKJK+Sh5!7-5^0Bt$9<`W<>E#fwJuWGt`9zv_C1GTZL-4)4shifKhzl8Sp!crJ_e6 -a`v;6@qB9dtUYtt~Si3Bc5z-3u>bp_P)uBna8n2GcMq~8m7FEV2VEcIS^pUnoq_r2AaE&#TO(2D)?8> -%UdvI$yG2)fjp=FA7>@3+#%XrKa6|D)g8*-2>c{0^4K-B?^F_l@5nzLC%`{=tZ<5y16OR_lCIl+^&u7 -Rq3~4D3qW;D<-QGZ`dyg$-#d5RRsacb8gqO@RnhTO5of^AOG`KPFY{1Zt!`CjgF(@nNiBeL)=a>T2#Q -;jyC`m9gYT)J-3GL<(WY(};rD>9_E84`Kt>bC)G-v5OK+XWw&7VT_rx)+9`Q-t!f@KznrI8 -N)*LT6jFj^pVGlZ2H98`K>&_gwt}JBK(>_da$u6Vg|1{IAgboO;y~00o<>)nP{}E9=&=_!;ACb|YC}EkA#ZjwGZXbNHuEEUtv+SU -h89#PnK&^{gSx~~k);B|IE{nDr*cU-z{PO>bQ3NTjx+7(A>;;0!NCD*9y_Iy -%}fwA*1n+&@{32Jq -pp+e23}7m^ExsWWVpn!#ouJsG;Rjd)$>153F<^#kcKHPprA60Cu+XhF01f6M8M7LK$PE2n%5;hyPWBp -*di`Gf+ZX@N++P$q%HwiV&nbtUX~+JQ*@<2`z38M9@xizZP68(zBLF>}Qs)T&hf{IbK>X{{!W$FzZey -L7GcDE6v~OVq?IX!P8XHox7k}f^B@iCl<3p^Ev5km#l0Lyi#wSUVKggcwWHdc-QR&UlViKl0oR4<1)( -{zV^li|$8*zS4L8bFCm7%F^D}T^(W!w}Ve#BXqePF ->ViHvh?}<9Z^N}jAeP=SdEbM7(WUOBGh;%a@NZ=$L1}f%i*}HH?Ct1W!x+;OA~EK{*Gm_zh()6~YN`G -g`EJD2a>5jw`Kx*1FcHvaA#UsDzUE4<><<~+#3f%8cZiuOpwaj#I%cS|*8drZNj!I92pepu>-(hvXf+lBb4sBeM$43%32qS6^_G1L_p!2%Nj;y`VEP_`>-ah0M!I3ltw>KmDf4 -~+^<08zm|8&n)~9~MemHHw~DEitOlAV%G7x!(u!5tDbi#}a>}*e^5Ddi{koETV^$h;U;o!gI@-=D@ly -+6wiho=c|;AtTRQiSMO{5+6;sSf^^(m>5<HFwnqJSPv^H4AP?-=tkR%oLls5YG58U>N -zlyu3&URoC{!rVi%hXFPG6u4+IZ_*Hxu$hU(E*7_1YP5Z(*`AFN{~wve;8#huhEkp*~|6+*qM?Plm!* -5n+4m8}r4ljp;oO;{Uz6vx6vxuo5UaQZH=s%dVAJrT%U30gJrGuIfh8vCN4r*tX`*mo35 -P!q{Q_KV9gj4_|V`k`%z(%&r7Xm*3S*DFOzg0tH;1F&&X-4}<>hXpeLgT{^1p&>puYL3kEGqifHhZ_p -X-Qyb%U0YU%D#x#~OWFLr#nF!3*j=Y&sQ^bLbz^3SV|uQMl1`^WD|*K!<10SLv+}MZp%%Nu3)~0xW$e -D-rIVqXeku+4kBb2|6Nld~C?nBIYME?c<&s#~q`5|pLjovz;$v7%bojyQSyiw-jFcM8+e52Fky?Vb2~ -y&iiUTJ`+?V}UG;MiPg6~Qi6n#i!Zqn*USkz=-#u<@r^;uL~s3&V2@XKsMR2+3oymXs+CiJ}4@hre`% -pEyiA)TtYsA(O8L}ox3mKjMk*2&lgtl-T&p%}BP5wW`zGe)!R};C~_m6wIvYqfIv#zES)_&!Be$oSa{j~2<>^MNnB@1LQJ3rd%T&VkwD+y!$$ph#WWh)_dHbw9EfcFRbWtO -BiIqUk9Ksb0jK8^Ywy~?gJn~88ub;jwm{bif-=d?1SB-6{$ -lG41-F5!me0L0d%~&MU)Pz%B)3tCq`6mQ946Z2bVbYNEjo)a$F44&Pds<+#szs9!Ml{4-2HwW1uU*2$ -MSH=Q1)SOUNPjIcBa_1PkYGJ+{^d3=~!q99A<|l3M}MxH03IBk5%eon%SWJvG+&vCu7R77gFxb1ItS@ -6<6tZK%#OM#6w3ZE$4GLi>SeLYJIyG(2Ax%oa9Ta6Rq*RdgQsR(# -7(p3wIdSx7F6;@W+yrKJ_E~o -Z3K&x|DsO&hhE}i>21$&@OzwK>n}&YeRf?u<`0S}LGukJ1*w5Ibe8-;R=GviHUmc=(mWylQc(V@tTb| -MO+B&My`!?mc+ByPbLC`M>L5YaJI^oK?#|xYgoF5Cj(4j6+b@#==$YYbgDa4K&}F4`$hJDr)e -9~_mU}Po7(ZrhsLoS-RYNzN&YGZ_6cZk%I>&viKoDR`#fNyWKnYpg;Fy_lOb`fqI0zA=egK^v4dqxza -HMlzPFPo2uJF6O*;4&UeKQxbq%zcNa2;TaSGOW{YH1a?U2(Wp3Jb7@-BP8iPL<5I=wXp*ArQHlKuJf3 -DheN3?5YAZJ8C@74AT!pwPi6XPmY)*G)}aP%#!(4lryK!+NQ@Smk}RVy>abo(LYJYZAxtD66@>+d4pZGL4st>-#*(9IN2U^-yf8|6$;lYBvSNnBL= -yI%tnC^pI*vZ}qxh_*j*K6Yo|;3XttzcC1y&L7FsulE3cMwY+-1rZLL(@$#S;Ul7#7o-Pc*KabqX~f1 -Mk>B%V?-LzVFqchS$^?UafY>FtyrNTfO7zddJ#NZHC+Y(!j+%DPz8Z>F0!jbX?BeE>iVTrlcogA_UE6?)d@x(ua!nONjgB!M7hgK -JFgcnw;1H}a&HDzNYkmYjt}k3R@J|ZI4l#b!N*%Sw-Nv)9vQr5ItnusAc>-D~r1am}qjJ9+K^?18rck -BDG~>mXu2ZaTK=A5P#!wvk!*&6jGZcQ%cj6c#RjjnOvRT!3{4E7W9uq<{(vYqNh83{X`{_f(`*NoTKd$XebjOq>k@ -^pb8{fb>nU+*|0_f6}B(g7cR6&jBNcBXVyqMs(3p?BAG>Mpf(MtGYg$0_D|^1cuRQQP5 -~Ed8i7KAYr6Os3Q$&zT~-amNkumc7cnR2Y7VIB=V!J77_3zva{m;2sFgwz$vr%@?(Pg<206^wERnhcq -X=T0OJSoZ~WpV$z^3K;Q;u87+Fm9*5cTvuufT6{lS8F}!X+9eF@WCPn08dbo4W~tSjZxItZ=9l?PiN3}uvVb50KtVTNMa&U7$su!{U*tp -@(dDo~kC}QTED^#atks66rlE4SzW>;KYGj3d6BFZrpSV -?g;w}7vnrprf4aV>Vh&czL7A{lX9mH-q-+_At>j*+gIU_5`0wl|KDQT&Goc~XNmKO{4xaJta}6VfIm! -}u&*{DU%F$?M&TbQo^meq9U`>UZX+9lSic~EiBZSJ$uVI)BLK#q3j$nw-KbE7V;+|G+Wlb`#xJC~NV} -6~WoDlLDn}9IW?%eV_1#fcRtLFSfQ+M3au1^zd>N=J#aLB~UoG4cO9 -s>*aWvA+jD5O -hq`v$MLQz7hjhn+T0YaoIZLQ*X+z^tYntN2+Mrlkc5rS(7)j1cavV!q#kTmE^~CV-_vTyLl)AY$8-rQ -^cgCp|V{4|iC%SGE+w&F71~2nOsLF69&A64-9<((JAW6I<>SLdiCdcEDCUJ}bUJ|wNN8}bBsar?)fUO -rbqScRb%xFcZhKutrVbsq>LXswdztnqp?H_Vp%MJ{rYng*GqpPBW%cZB#SD6cK4Kf|)BniSga+9S+Gs -k9ZS^i~m4ZsZLrsr~Lei}C=IVP>WVdjxE&yhp;XmEKDVwv3O)(-LNrS8Jh1iD_$vK~`KA@v-!_wjk5P -ASo8d#n`@ttXjvagLT1c#~R*ccoN^5SGSSA3`|g#Z6>@M<5eq=YcT`MaL5KkC_)1Fm3$x0dp6|8M#tB -52pF-xcj5KC&u`vG?_Ix9rH%riyC+r%G5RH>cb`&k -QQFp7lSc9LeYymZlpj-9;NpzDJiE9{F@~%*#*~s^QkbbS^c!Jgl2Pc}CsHjkr!~cGcQ>68rV4uinytg -NGgfDaSuHZ!m{ty#9;NW&)0+b_-CDT(m#d)~;cxf$FyM`+k37BDYh823?MX*!X_7Dmxw1Ph)n5QGCnR -ozLj}(J>Jk2fe(tSbO_Ln*d-dctOENykoK{b&#Qe$y5e^zP;tn)s -5VlOVeZTJ(FJIy{w)?}r$jauWtY2a&YS+J{e9g@Oj{Hl%;|tg;5MAd?jGc2a=1%tSP)h>@6aWAK2mnY -{22(s*1f>}U001);001`t003}la4%nJZggdGZeeUMa%FRGY;|;LZ*DJgWpi(Ac4cg7VlQTIb#7!|V_| -M&X=Gt^WpgfYdF@zDZyPrdy$jHPAe2L;KoQU$1vqFDw16*3fuuzM!&p -NvLidH^&#T^dkP~;!$N-b0Rl&nQi8?`RpA_sq(g$3 -txI+p&Y)xJdi!U6sd6@s!c@}yG*$emtLsyVDy39e3p|>_t?J{^x&;beR!^nr_w8_v2#}|o$(2U$!g7( -SW^gRYMatJ+CWz2M~KX4nR4E$UCk$ng1m%1G9C#>_hczImf&ceLOYzY0*2vVAou9>qTCdsW(P*TscVoSg{Aq+jp>E?lgjS={Xt3uEmFnBPI1(d? -ddXpXy2zD-7E!Rc(?3m6@@dN~U-6mJe-BX|yJ9rK8{C+L?V$J!}etRJZb}(V9{|)g^M53h{!?q^(f5B -~sHJzS%)g#+qL$sC3&dN>`@` -Ua!Qf*S$cmayy?1e2|v*Wx&|Y&Cgsuot(S538locpZ0*JYNhd9J0v~8fMF2>A8Lv*BQ>foJEDS|hkKN -5`rx>zFoaLB%?NhE*oAT|usUU-1z^|0*bHS8K-5?qADZ;KBozFXaWM+(HG=KPFIUZBu=&siobks8#Q; -VD{;0eIFy2m1=*9Sx8q|GRQ@`5N%0)P!J-JalVx9M>m9Hv1D$-fMuYWN%Y$LO5*(|Nj0wuXuexFp9Dq -x+mWz^JVX4_|GEuMj?`Rt!Vl_kdn4E6&f!pE@KVCz-qK~&X8n2GEChfhqCb#-fHMjISNz02clbbK52N -Dbn2G5iqCm32On;jqm-3Erq^f?#ePDOFy$J5^OfFFVk=Gj%h;eMH5?_2(4BAHB*({LlYOBbEjtL)QP> -E29HDu-YPdQYbA;56O54WocQluWd=$Gr>9i)a~qZ5$@nRAu%d^I(Qag3#72q6 -oUbWir1Z(1+JW&UXFkiZ>zc)V^|$455Yj7~q{74iC_wPRwyS@L?Kc288VzCluXP8=h^Flv`)(bEL8gZ3gMbJ%qo>N2L)Cc-Wkk@gT_@|`Y>jIubO!f(veiKN -i}?PlY?=RLgH2h!&WzZMH#B>T6#+h9V@U@XI@cjufQV0tAcA3H>!9ek!ecKH7NnLMST@p6o|@FfxBDF -hc1?F>g#Zood+BP&81<*Svclj}Z@XgzI0#HxyT2#erQb -d~A1)-s;whrRp>Gr19@iM-nI0(coZE;#bDsaj&Z@XC3GyK&6fOIJR)quXORJgsqH-2FHPu3c{#HGLd& -Wp^1qFt;eVC4xa#^x&{PsB@1`~(UU#%Av(IGAvDHw|5!-h&6aNJHBrV0o6t>4j-xRWl2YPIS}$@|5Oo --u$ZKhBudKm<3}0??ys&i)@*$+759Z>664^su|`Dc>d2J_{Z+&r;WCCl1g~BEaZbzU+Cid)i7Gjd&6+ -?_wnfU7$*gvp9FK0+D~>kgEWh>JjO#?o0Ft8%pFeNKFGs&ed-(xz`3q1>0|XQR000 -O8NLB_@WIXGpiVFY$sUZLWF8}}laA|NaUukZ1WpZv|Y%g+Ub8l>QbZKvHFLGsbZ)|pDY-wUIaB^>UX= -G(`E^v9JT3d7DwiSNgnf(tK<{?r_u}M39(NyU;j??vQcjJ1UX)_)V1&NS^ngUpWv{w1`{SE+ -z9>C;M~u5E?T*-w5i!zm!(+OQY-uRjr7mSHCpEq( -wJ>~Ditwq{CS@OZMfXznN&LGJYK@maDe!pvCeW>9mE|u&720G*SY5t|Qm(Sf=oeWCV_S|_D_a}BuJ6K -&jzG5JRA|9XT(MrveB`Mk2?EzU!Hg)Kkaj04wi5M02>+tBXX?HMSEUTx=>gH{T -<#v4UP!hsxwXP(I7J5^B63Vx##w=r>za&Rx*OhrdJ{xy{o)B_h=0qBE*)3guQe<18vb(UukLQ~FR$Z^ -;&TNCodowtJa?KacF^XT9b~;jiW2`?lt;#crC1W_kvPSYPS3N|x0&yENEVQsGg%{i51syV=+*+d -7l#(8@z&-UrJADelq2fbO1U87=?F8sN&h+YEq!r^vzyceoM8TwY7iFyz&ofNfs;Qa4N3i52G~DwFUX% -tOz4h?{hNQd1?}eAduj(S@3$_>aP8Vc;#VT%Uxo%31cvymQkt4R(&|~RDTuPf;IMHsTDDu^DNg@)BI4 -S}?A4AKnsPjTpNJZq4BtkAS`k?a1;~47j!aA`5MZ(~jAU$CDFRg#1c!|qv_*&Y%iypdR5oDr-MN%S1B -H$sMgr@~t9plI|?)6TT1v#0MQ7U2TV;i8YkpgM2r>&4g5^&9s_?|HN`d6Ll%@IgCT2`1Bxfa&DN88@- -6TZfC+v`i72;x>oz)8YPGs^O}Z(Ja-J6W~KKN+CIG(bj@BzKNfpP<8}ByA$3Y(Z-dW_<4=J(LAIXIB( -uuCBpS(Hmxwjgn%cwRB_2eDB54dUEtfQ4RNNCD*)^zX)d)Qk*HicW4qbmRqHb7=+NA{bMIWqI(t*!kMSzi(?IOYy9Zs%0OwlFnBON -{;c#tkqq^2;FV3OdHv+n>iWzKA;6omE^um6^8KpdbJufbQf;PjoFLIr7dFRA#GtMk^pwHsy(tnFSXJAlQ>I>@Mdc$?FOn-!3r9K203?4y!Z%{I=Z|C+1>~ -P%(YUof4w?;P=04oOMZ9^OZwsyeby1_L?9Rz_BC6@2JU8jh6)CX9Hsxi|BFXr*xuR{0C(BpH})l?Vfv -6{q`CB9WjQYNx(#wzV{8ED8=Pmxi#SIV`l*-!U>%VJiy8)|NNnFeKBrm;DR4ZMk73T$L1GE%4pPS}_Q -bpYgL)RDzvv0Sq7v8yFxh5&r(mt1$u5HCi5mV5e|xMWU3)9ecCK<}9Ay3|y~LZ3D&NCRVSq_Ootlpo3 -Tuigo@*!hS)9bF0T4!>$i7!74@wlP8^1F9n%G8DKH9WF|t66XwxF{WAXsL@(3zwHeB=Zkjr((*F*Vq+9=`)cU!p2=ON-BS7jfBKNN*Q{M%pET@=`py08`rK -jl`kbyB^8zTLStR`OtPSMHM3UuT#HV^CkV6yhm@I8stoyn=$fNT@umvxWbA$sKGcA_8y=)?3CVsv;wx -j*|9r*fF$7E#lVWKz0z^}0XjvkT{tdJ|ne&i{bIwP49&kvPV>a!}ElA`-1p6kxbXoy8Wwklyv_`i+lo6pN6opaLnWtJ8@_fPKdJbS{+277PvkoPJvK9 -=`Ja8AeSJ!gY@4Uuor{q>yg7;t+;K(1OGN5PHSwLP8$JhmP1*0*H)B!Gs1-4%Mr*(#GJL<;xG0U|7Iy -<nAQY2)W5ht -Z!%m`R(ay)^A$iJgTu34e(-`^u9I7k1&Zg{E)#M(n#z9etk{@Ycj(y;27lNF+!4OSjr{D(fwfSSmGT+A2**6S6EoTiZS>(0;yooJMN2^u>w*zZNc=J+34+0-jd -D9JvEC_3CXD29+U2gh97kwkJB5>B0=sr~gpOq7QOu{q6FsZ+^r|mZXI}Wql)i>B>8o&mhNiDsW12nK^ -e+Y@S?)TIZbl80*=X)@BSb%tN8l(ov4N?8k4NB>y5$Uga%@-_PQe1x1>&h~ybu|7=MvC^-=SN;z~`|* -6pNTaWD!$LK3;vedA#}O!~NB#C)W!Ah{HmR8(Mrdemz3<&+Q=n;?^%w+@8tA^sL@fl5A;DNkajmg^(j ---!&~{_`O+|NG|(rC4mXxH2||6bso=B71m)+rway0MS}W$&fU!&`_tEd^!uDNe&e3R6sxka4iR}+`i; -szDj3djOYx?XPmt`+1Cb$YfEw>U -={K1*Ts9=ua_w=Vl}@_3-w3Lf=y_;e(H46Cf_8^&oQ+kT&~I0v>25 -v8(MvIHs*g&c61QnHzNY(~-g4^T@31QY-O00;m` -Rt8hcBC#t&0{{SR3IG5v0001RX>c!JX>N37a&BR4FLGsbZ)|mRX>V>Xa%FRGY<6XAX<{#OWpHnDbY*f -baCzlc-)r1P5PmoKe;5RY6H#SMUy8tm)TR(9X$gHPCWt+0bXvUH-R_RgJwpEX&gi5&DN&EQV$R^`*Zcsyb}4jAJ$uY -F$b(bg{H0i!c}Gsk?J@B#nqb-)hoKx778aDUdgDNCz5EX!2hU -td*5#R$J?KT&Mvd}(og1$=P~pe(i3RF<2Frb*$uAK|^TIBt+j)>&8eOo9JmxjmGgZ`2Npc>tawg$%T% -kF0AJ+zl@cq84~%hcPllEESa}aJKw(-YC~y0h{HDTnPsmbmWY=XUT~o=$KA>gRtiq4|#SCd>VxgvH1+ --AXx#ckwemHi}2Fws+|yopmLp8q_>RwqNxQ(EysNgB%Cu8bNIa-jC)f9sb>Tw&<67_EYocH{KNms+q> -`A-5ucg$5`U7aaM|*T4kY+y)rrc;dU?nfgl9;HibS;T`-jWUPDi-aTF|Hy#P%!WY9>ltK5FN+TN&B-m2(5dOX -#yTY<3blRAT)+!z~SW@SOaX8XFoY4oH%aJmdMBA_Eu(+KX{dEcN_b#$3wh5H66$JLZUuTtt+!)ZZph_ -OdLE8sp34ZUN=RaP7t{i?niiY4|nr{!Ii}UzJCS8*;Y5BxplC*5imO%(eeXw&Kqt&Ej9p!1Dn<+T -X>Rj8#ZIXBIfBv`43YnddM9SEPs$VZh{o+zS -W!=O}4n-!SHEJI{M06==%&T6PysPD1jNS(>D4aAn|F)ng%PZqL68IY3@dFaq6#G#P;weBAl}%$A89DP -KO(|2^{p@+OQRm*_|0|4uf#cO;tQtNN(rJd;PR*-A10gvh|FFf3kd*>y21Y~ue>T=<$K{YC?1UCjdUs -Nn>-VCHW(`>jYPtgre022e`_1QY-O00;m`Rt8g6;y}*$1ONc_6#xJ;0001RX>c!JX>N37a&BR4FLGsb -Z)|mRX>V>Xa%FRGY<6XAX<{#OWpQ9FxM@XF5wxPclxmChxvhoMp^-dqeLznxCE!{ -NzxO6m4WCO+yX5a0hJE&3nxenf-#E5YUR*kKLVgo5`XVv{v-s+Nc)Wq2ON+M1iT5u#4dkFB*aa{%fUV1Z_=77<-*@f6%)~d~5j%(W4ZS_RQNA%&dz;hvlY&xG9m}2}+CAw(F0H -_%-QJYDlIrnCwRTKb?25vNXFAo?FpWHur_0T;np#T9?$Ez&cGsZ$ -hmHri6g`Dfe0qB;#jW*BCd-n}G*nb!<>ka5DFkv~@Fpg|#Ux3Rn4A-=Q1W}=Kn`2l -zdy*N3IthRd@nKSX;#OxEO!WG%|&eD?Y(B0rMA#Uj9`W*wI&>;Mh*^_e{#`?m!-?2BCsXcBzHG)3^f9 -XL_9u6+%*Vl5xrFxn>UlMD&QFx#Ql9l6zH+v(i}0|x4|>2KHWiKYec&7L4I1LYmE5h&o$Bq2T$%|r&| -!j0K*&O{E%hoamT!Nv~2+!@(aO%Fr3T(K;6!M&3;&s}blf^qZ!mglHwJi+d4+9s<-t4K_U@HW`iII-V8Fsc16 -(mWC>>vHEXbtbPV#8p-Eti`N8R;JK212>57pIO}74?dqvNc3v$3ujVJxfheLk)kWd8e$+knayWsh=LI -*bGq|kx(b3(WDLUV#Y`KFWJBpyJ1?sZ__uBIS;W2dOu0l7Wn?@Oue$+oSAA -SPObf8MlXxCg4>2GbNoiTe};VyP*6FEIJiu{+F2Y1^KFlKBrtG>OW9R0|XQR000O8NLB_@-=A2?-V6W -$D=Gj0F8}}laA|NaUukZ1WpZv|Y%g+Ub8l>QbZKvHFLGsbZ)|pDY-wUIa%FRGY<6XGE^v9ZTI-M7HWL -3HApZla;7}XqRg>O_I~b<|?IukZ4cf&fz2dO9P-uy^iIqi_q;}&5`QLAb4~e2Fx4nmeWGz01!+HE>I2 -1p0LTa+@+e!=3sHac3ZE3`A$J^cTE}&~G#ewK!2kpc)zx(I)tMc-@SC`*k{qTB4Uh+z>$Q!QU{~tTeM -N69%dCTDSUEeiqMJlTF(UY!E86g1S=rJ9OH7qaiROVdeB)<* -LlwJW_>;*MxxxM(xw(RFrTC`#ePnKIizHN$n>YUL?9^Oo*;jht|0S2K(yV?hX}6zloVUOo2q>>;wP$| -9&wIw2OKeGw!@VoR)6V%)dOqwwe3k$kn9)y2MtQort# -CS>}x>f>}NE4UykX$FY%ol&N-C>8e?Tije{hp0BEF<;&1)dNBB!d&w-i7_9 -{u2N?JH8^+bJ@v?KaQ(jr%E8;Cy|f2iJq&NEykvo?_^@4VYVnOoKDt;jE`m5YIp(g$K5L$MhT1wkQp* -l;zTntQxA+;QEWu%9d^)B^a7`WOWJjVVxZZu@>ZG#=!ezwj!Bmo8txFUbKwWti~2CE)-}@ZI2h&nSJt -`so9p4pe?S;(isXqiZ$ES`0Bh>u2YU0jI)5SoP8o*f(2z@(Z&RsC}K<}CN^Afyvea6RvX}w -}4{F9~P8W!0=SP6Rht`(A%V6$KWtgS$Fb7S1ntezVnEg!1vj(RWJlVMvSD;(tro%HwJPSTorEgsisFQ -L$nB^o5i2zc3wKwu`A-Ey?HJkRg$K>I(4mbtm!OpG3TfZWA0A5^>?`@qf^7<$YG;jK}Bo-i|SHQq!9A -1u841vWGqM6rzxAvCI@J2j+~0TgjVG(Iq{BKRGRn%GA%d5cCy`YWRMXmo5fMcj}c9~n`RZjL24wTvQq -4@NH|eI@K4beCw2=A9Txabh>o4A=rxwEWNRY0OY_o#vdYu&?pM?n^Lq6Ts@ -ysNQ+Ca|m+rRTSt07pVkj2XiD~EVSv|b(Ee9KV2;bzLp_Gy4YQWVLNsQOS%ZxiF8{*b_5ay=T^nQS{} -5f?I_e;F{kR-6(S85NmZZvk2KO?3K$DmoOYyb5CU^{eRW;lyn6fNn}58zDPO+&=BL*gLXJ>5Yah4-Ae -}Dg)0y=ot+rx5NoYcR11n%NwCwEEB%cSYgN*xZeD`^P4c9TkorI^5i>Zvp7cGww-_TNOQPKy&>vGKcp -iO{+SqDsf`P@A5N-k9iT@qgXF7s2*^UtW*(DYY;${)ZZ`nFcZZ*esxI@u!oP_a%Yk4Bhs#d>2>3K{z+ -q);ARO+s3lQK_xKp>L6;)|%1m9i&WbxjHA5d52s^Dxe$^TDt+0fU-~y{xniV__Ro)T9IxJmV_XMhgQ1 -}^ee0L{6ITAIOh+v0S8?yBLTz8zW@`%%uu)?_AR2_fkT_ATp3Vbr$p9j-u9DS)hGQdW8y2?taUN~S2kf$jn3 -FO(Y)8W%=q(1hCB!o&H!rAX#o$zqxyyIRXQ9!$##w$RvIH(`zTJYzTaAw5DgJNS9+`s^ -FRQtx2ytMX(SCf_8Qv>#K*i&5$v3^A^g8Y<%xv3dPpwys2v2G#KP-uP*<2L*(sfIlt -)3lC=Q7hfdUo?!(SH29fV(XNV+1Sj^2Hui9V0;+{~!GwhHu}A$J6Y)eW@=x|B6(ZhX4djvQ{Rnm5C?O -_dTXu$^OEzlDYEFJqDF+3Wn4SK%Nn6R8 -m@`m5yCyNA-S&mwEeSA2h;EmjBATgy<6V!17}De~+!%eS)oluRTI*Saf@&5>S8lS(*$OlY&9BBElzoY -xZ>FMH_~`HCPH5Qq5Ec$Ku~_sfu>F*}Ex%N8DxW-T7uM$kIQ4XmPOj5M?R_Aa$1AJNM`lb?bG7T(`Jx*wlrsZmWnqC -`I}|JB}Dks((W6r703M=Q)vDfGjn@j&&=&XKobRPdP);W#Z$vbve^$aI1K&Gb7zHP&MHQ96@=?PY%lT -VP}dF{Aw|kahK^*syqnE -7Ez^2GTqD8FBjI~PEOQ9PHR}MEN5q~PcF}l#IV>lSFH=YG|RHr457#5Zllo;8ArGe%+IHb<)HwrpX06 -=;sPL=b9MBefDV{5tc0OR;F%Kw6gBr(tgRIhLBh;+4n)EI_N?h3#cov()68&;O|DR7NW!3dEM;Ip09M -8(o2&%|(H-754)F{u?qY-YFzjR#RWEJwe&`y*v6V&z7ONR0pg9c6&<>#P0vP3L&@(*c6jf*g3 -JxF95 -HM%4^L?H6g^+X_Ng&c*z51qmGvW1vZR-%XS->`NuS=SY1mgLXm#auB^*+LKGVF%>MzAn;u6S_=pW-Q_ -=);&8G!{-(`;D+Y3S(J`~S*BF(!v(k7!u^d&NruSG3XK2ha<4<0TT>!JA1_y~T+~kX!wm!0V@>VuRQPLH6A;Rv6MiN#owUMUk4|8BUn|9T?O+ISXkxV56C_9Qf*PHeU~-;eoinqR3> -Z8(v;mLEix2dO2}cVFGCCUgpz$p4g4fi<@n -**+K5yP~pJmR&*%3c^a6tDzww6f^tQzS|h3~891tsh~1vfw$(9d0ZgK4K9CBdFd>(eIoOnG=iNUl{KL -Ps3B0A2FhhN2Pm^pgAo-CU)sdd*j|nCp2pG97P?W)S9*#He6xB1au8KnER*+F*{t -V4`&$XAy3V;AO`W#@}geTAf!B~>VSc6Cs;v!`C98Q&B1km7gY;*~EnBhLIljCsY(^wD!r -Yt=PJ3eCG%E1g-MoR$d3J5uFm9ev-N|*O7m{o~MTB|J_fryjq} -<80lx7;#8mYxUm0=v0A?{&kGB`bI^Vya$;+4T-{(Huu<=vHp$ucnF6Qj&Qe#&|R19FgCI@!d*pCY#uj -K5)VIg`UW@utedl?xsE&!hzq-QJ60HgrzSb|k-+cyT0A^xZsm<%Vy>DQDCRNn3LyJbrIw>Sb6V?Vq6H -&9Ch1QY-O00;m`Rt8f500002000000000V0001RX>c!JX>N37a&BR4FLiWjY;!MPUukY>bYEXCaCrj& -P)h>@6aWAK2mnY{22+E`Tvp%#0012X000{R003}la4%nJZggdGZeeUMb#!TLb1z?PZ)YxWd2NzSi`y^ -|hVKUdhrzwr!4dS(OP~wg-Lw>zEbP*~I!-)sL}kfH@-FGG??|#7yQxn4n0e>XJCkME!(goH_#XtJ+Lp -^UP158MPh6sbqkr@-sNpDTW8kDT*fYXD+_HDn2W2p4j1_z6(4JMpoCufPR-CNCxF80+Fc&AtKx-%a&yPoHZobq -;*JX|ru{%2a3eo%=QY`L*i|CY#gBX(+c!JX>N37a&BR4FLiWjY;!MRaByU4a&s;>o_7P`hl90`ew07iUes+89mhOrjc5_1ws -aH(_Liv}fq7>RWU~tI1OcOK;NL+^j2+CV0Afd%$AP=%Qvx!xx8Z1jF^#LrW$W*H -Ah`Ph%Lce?BrByI9S`l23~wmcNQeSMk;p}9ta;iT*x=mJ0JP<@yf+#4%ESB1DQg9(k6qLnz6C(MN}>{ -N0IoMPlj$x%^>>iWM6c)$o`bY=&sE2>jqJsPkvqefa#ajW>8zs`21ZGu{1XK=`ztubJa7)q4iXwS8+~ -QruL>y(Ao;)TyxyXMDV={!ST8*YaN>YAf~(0ogJ1kO{Hd*J5+x8wpu-pIo|Q{-!#6OdZNofPyOtM>j&6bxOcQc!JX>N37a -&BR4FLiWjY;!MTZ*6d4bS`jtWmVgb+cpq=U%>w`kRL1qj=aq_4eDYGq}Wa2z_1tV0B#TjT3Vtc!W5~J -lwBdszjua|96Qw$DRM67%$Z>nMO)Vv1-Obi$VE|bV?n5X$(4hr&Q)5$5f6k`7MRMRk<1m^)T5hRSZBn -(b##_QQ8c<4-H5u;#(~sjDO7phYkOYW&eFv+Wm2Xo+{5Rnm|ri#@(O{d{z&I_oRO`Wvy6kh!fd#&YSbOZP~)AcL*`rJ}$CBPVz{+lh}{m --{Q(N2^~8xE~%EzimCU}d;#je?J+<>4p)C*zHSrT6w|j5ZfB8fNWaT^LVa+Pb7v_>N2y9C*kL -pIB8`t)h@^tj$`SA$_6^2eiq^^(V!77M@OQ8<- -0!-yxV;A#zDO}a=lT6q1rfb+7G0mG+%K5K%Z^o#QthJ<_)V#U7eS3R*H-vbSEaN$9Pgp2gm63=@eCVh -lIkp^}K1(sfeDM6;@-Nb0@bJNla~9-lE8WT*II`(l6jleN26kfI8PmcrVbRTI8|nhPiU;t3DX;+}Xag -Bj69;>aWHTb=iZ$US#hf#-wkXa`y579stX7*{G`--b$Wfr$Cc5Fumtsb{P5S(>S+739zhO6+PA?3Fo%YgXh+WMLkPl*rm -KThHdu9oK;eYiy{-eWy*~152Uq5C5q+i5->yXS8|;LXo{PReDOrj%bWSwAYTp4+Xx%X -;lpR>f{rGhihcEzxv}@J{c7#IY62~vKO3fY1nPZ_^z5FSGJtv15ax9Q=Y_Umi$MZ=7q2VwD4m2k+-zk -~5MY-qPaZ?M0Mtg>%4oEy>pgEsNorS=0)4hJXc)=--F$&?QuOB)%Vn0tp;*&2gGY_kK{mbI|W>}_2W^ -6oJE&q6U+mUZN=W(OVsV2(H#aA+L)46H_eO#Uj`gZN}U3w|8UkQve|WWj^)DPgo~`o8MlB@BWXlOb=?r*W3V6-Vean$k>(FR#G; -Jw%xlk#~s-q*u%TRF0JLA5cpJ1QY-O00;m`Rt8ghJ2V%e1^@u|6#xJ!0001RX>c!JX>N37a&BR4FLiW -jY;!MTZ*6d4bZKH~Y-x0PUvyz-b1rasy;yB;+cpsX9w7hW#(bEBI?7Aiv^C%kTTyhuhBnxO0fT3#j6} -z3B~cKmI7X2FzB`JNC|P-HhvkDKQ^$vQ51%_8%^3S2a#3iC)3k`!jfP{1V>Dtl&DiNY -X@a;GAEoV0VWxw!5>tlVpV~HI!m^XIaV&^rlGiOR&S|f1kY%-~Iaj-EXHKKTP2FMCl29Ds&=qo=)JrD -pElxW@?cXL3kzdSe8M-qp$oDkphj&HE`bU4&WbpFsYv+>scy7vTH_*jb6#z9lE3llgJ%PaxKcD6!;nD -JQE|sSE5wts(q93C@fO0m$J+V#5eIT`$0}?+eZd;W*q&iUWVXycS5PILtaL!5F>*bG8<5oNh-XOdBHP -3^!|yvPaI%=Ju?5-J$H0kvp&Z-ClCa|!iW90pmb?H--Azix`9dws0z>$^h&@oDU} -AjmXKH31)>GDG163(IWQJ{kxA}lyzmfd(sN@zJzn^Zi(!vPk3yZ&`o<4Z$Q-{crVZyhS|JNPRsu6>X8 -Ly1mbImwMSo^XarBEsf3hT}e>~C^PYn)Yni;`mDXT(xem9f+vjL!$heUY>#-D(BCM@5vCpe+dbl#2CO -#YeVk$|;;6~DsdO4od&KoY$;Bl;?0Bo{ZC7;XqbCU~jU5Xs~tL(h;0HUYGR3slsam$BN9dijaViECYA -tOPs+swn^z_%gZ1fAT7c(T|Ib@d9_f#2_K!xcxY=X)T60N@hZ@DAm*Ct7u${Dy3x>vH(ss^0Dve3Nk<1mQ -K>QZMwC)`glL9IV&tpgxcSSzaE*;_9Ffg`$uBL-g%n?~Y8~r+D{!&h6LhbjvimVfPJ{e8ZB -H*C$vb*!Am^@Z<%%o%Us4Ya-wU@#Xb4?~uW>RuS!^f%YEo)?_Hc#p -oIjRAPVhRCrRY7uN-L;UP~`xfZd5-#$&-4tm})UUzXL$}lX -AOUtrlo+l>Z(C}!f&A^Y!gdBtSKaBK_1byXQBR$Swf5mH9Bs2tjit4iA1-XC*$f=Dt;;}IcCt5|?T_c -JbG5NIDZGZHf|@R_O(d;=NISS2B#O41AAgPap#B8{E+q#T-T@h$n@oki@NguhidHs -5}WHj5gG%LPW_j!S_jCqkOin)aRhdi7A$6o^?cU+HE>D+a4KLG7UOiVA%8Lj5>Js{FqI;&B76KK -7eyHY?faqX-bDDR|&ox}}G;x}?hJs1w%<0l~WwOl!jsM4sBV^EO%pMVqu%?|3d&fh+SUP$hRLQQ -6Z09?b_(9J1Vd+S|yE3;$-Hl~-XGtWA+hW(w?PN83%;DUvsY3fZl=%?>v5E5SI_H}PI4W3IJ=>X1+%4 -bD(KR?!ou9l0ueMp6^}kNG?MXv3`WSiFhB|Y940A1<<97VqdLS70$GVYV91dsB^ZyXWJ$?^=de}`R7>;LY~zfem91QY-O00;m`Rt8h#6w=$E0002}0000V0001RX>c!JX>N37a&BR4FLiWjY -;!MUVRU75X>DaLaCu#h!3u*g5Jc~R{KJrwLYof|>ao8escxH4O(d=r|Gr6-9=fMt=k3fYrS2hOv*ao-rr_D0I)O# -ixVCtNFg8*kO^Lwm7p}9=Wn0w;@^YW_@gGup&We&==ch6riPz}Q;P$wd;tNnq0|XQR000O8NLB_@5nz -oT_yhm|=nMb=A^-pYaA|NaUukZ1WpZv|Y%g_mX>4;ZWMy!2Wn*DV>WaCxm(TaOwy6n;nIKO9XS3h -H!L>LV(VR>`(qDNUjzRa!+WWM&MwG4|B?%%l^+{{y=--44yrSrR@SWvURc+L0RLg@u*;x;}O(Y7f9Rn8obBfgY0;;a&}AM(6WJ^ -cxw(Ny=hsK&?SA4U&8$xd>&d^(w_#;tT_s{s;w3~X&URQR@9#bTd8)^d2kK-TH(CRMFzrR(Q_^qBs|r -fa|n2NWQmt|Z{OX$xczYd=Jn!__rERh>(~3gXih~&nNbXNJgT+up5ChV$Cp6?KyGWNgSOJ -@qPdPq6dfRsKm2Pk98PJO*6$VWyY#YnpUQ4F{C>-7;oD(aWTErP+dTFgu>@ -Y|6eHcKdxwHd_ee%UehA^GP$glXLOf_lkFU32{`smVjCt;<>Q2d#lSGYkmz(Mo=9IwqHQr|<{w;_d}C -c}ZI?n{4|w4DUYTB$=ykq%=5nrnkh(^N(4{X4%OStA>1Tt(D7PkWY$sbS>Nxr@I<;q5!)sK`bs~2}-r -=aM?{qkp#P3qKs7>saqi-a?C?7bCRcGp?NQFZ+K-&9!f`CU&heRX-apZhf-HtRbSq>r`sv}vqVp<|Z?wac3L+!u%)&>@Cpt8=(ByU;zXILriIXpKeVUx^L=bh;t* -J7U<{9Y%~Y*<^Spl!v5r&N|Pv3S~bWH{sC=^sWJJ;6z~{5hjfMmqQQsq>Ig0c@>;U_xzhow_QR5^f5Z -YVP7YOz$dy1ympc|vEcYuou&voPqdRRMwM?83=7jBD$RMKM)|t)(OC>kYMtGw29i=XOV~Nq&aK{ygOB -Ss&uTfq9HpcC?8j$$*jv|-aO*DJLOfhC@EyQS3gJ9QQ}clKDhyfc&!04yUSOIA*VQNiG716p!>}3{IH -$lE|0SLs)&cBnMc~Nb#$KY!kq#9&Zcb*LfsuxsdApVIP8gKooB}bH1DsawXb`h8^hP}>($q-)oIah50qdM=HL4E2d>8(IZz9?-Kg@E$yvTZs?6Ro?49CR0VHzBlsc5|~{$OlDXHz_lL7 -9jc-dTs(-99na@FDS)tIYR2P$-(9?+NjxXeair&uhipl^rKZlaO>8UVd`^SbeX$G(msthBMD{U!ewfl+SGA;WKS+m=qWv)_mo~Pzk^(~e*IiNT^JW@o4-6hCgx9UZCnoZXDxS9&wqxl{{T=+0|XQR00 -0O8NLB_@?zJib!~*~T0So{DDF6TfaA|NaUukZ1WpZv|Y%g_mX>4;ZWNC6`V{~72a%^8{Wo&R|a&slDd4ipmW2nUJ(TWcS&U+jpVenet|TX2LjHSaWLvhJyex&?Tq2ETzM1(n -GjgR>%j}m<$Y&;s{T&QVILj9si{ -pw;W_23qy;0sEv>>6W(vQzNvdG%%p=$3Uj+Dp<;7LIX8I+-J3T*=c7}}~cZ@wSQ86K%C}Fl1n2s6Y4* -m0ByTr|0bnKBu>@6FyE6tzj(BSE(&x4F$jgZFjFws;j`QMG1t-U;EEIMBv&zHC7OO#ehx7^0F>M9|Eq -?<^V!k(C1D;273h0R4dW9^0|G+&8$QBrrJ4g;9gM0FKQ%}u=zbMi!{yz4-g>nNO!57@xMoEt-RaW8|h -_;>#+_%LwOABLUMUlz`<;*OSzS%l^C3dqiT@fdeX;(?H&AENYcC1mU^c2k+!UdyG?&3>dV&Z)V_f}-W -#b$G&z>U9CssCz$qK4B|;#>)O(Nl2V_E(}h9{8R%pdBKYsyY-+{gGwJbUdwjl8rOH|-X}@cDOzK(F4D -wZe&EFmGKUbjOP|3`k{qi)H|V2<*qIOO-PP4EQ06n&1;hv#3nh-8BUXr#3CjmhlZEq0?4U-@(JSw5z3 -MpUopesZ)~dJpbOBe*M8602L235!{h!Vbd-DWL0+ckaDuJ0I0z*%XmnHLknFcNM3fW;;5A3PJ$pv$o- -Yep24W?7FG{cy50OcCMfhSB@)&iGig*K7KP8>(0TpNqF?JYkvFlNE1NfV|JM4yBKf<39eDVbDsc!V{= -0YHwCrR+(fdv0-$rpQ^T=qR@cLg#fz}%BdDWUMt3nYt>W64XYNz?#ifTLn)2#YvUw_p2PfI;w6lJHCtYH%udF44Mby`wc!JX>N37a&BR4FLiWj -Y;!MUX>)XSbZKmJUtw}*b1rasg;Pz7+dvGx2mBv|b7%sNduS;%kitSgE~WHP=wS(FV$1fl_ROG>cjK1 -+_iF5TlTFjahsjuadU<-1OR_B#+H=Rc@hK8n@}OI1iQ)YezoY6y$V9X9IlfdT@3RWoI-aUNhS;Yebii -}(w5g7)IVbR0IHFlJ%LJya@vwpWXa@2uV%%fCa)hPcZ{h^LSc3_~@iLhJwQccoMjOwnX;wSsZy*ZA>N -=uERUrB6phoYm16-r{HmD=K3Gz8<$N$lD%`UQ*FK0TBbe7nLsYJ7Rm>T*T3n(ml^Mb)4wVL5u=Ni2CO -jDg)w{jwa>$$e(`*RA&6NFw?4RPPb$+?Z6UX{M$9?%2>itN`WOfMIKLh6jgo^j`grfLC$sw -t9Qe8jp9ORJvJK0@z+2Aj_iXjq$eruS~TnvAmolrSWsoa?tWm-z_ntim6r>S6s_XCJ}pdxw2-+oJ#^- -$v5)4Ml^Y(KDAFepOAWQOrNKm^8Tc^#^YHZqseLKxHpa+*UJ`~exw{sK@-0|XQR000O8NLB_@S -LZr?76JeOwFCeF9{>OVaA|NaUukZ1WpZv|Y%g_mX>4;ZWo~0{WNB_^E^v8`lu>WmFc8Pzk@yZL_a)gN -Dj=aM5_@Pzr%8;Wu6qg*a*_*J4R&N3A-?_2NeG}d)%@g~e|P`$KbMGoskDVuWtf_NPt=cvN_m0pqrPm --iKtwwJ=jwz -|ILtr#*h|#ng**wl$YM9_B;Nl7_I>E`fp(f*Q-RFufgh~ekP@kR8Mi!y%5fit-<;`T-3?>xX@}`M@cP&txtEwLO -(E(LtfE=a8dF=GAVW(VusZ~lbq`L@ReI({k#MR+3H7uDTePLd94R|H;~sGaeJI2`f+|sZJ}3#Rlievf -p?2zOPCrrmK`R47LN!D6xmzL!cd@`&uB|x=yYnc;zareyXb)OeWK@uxLm-TU#+q||zs|aY1zH1X<%zp -yF0`QwAL&v;l0V$IPFC~PcsjYX>dsue?x!q-^%Az0%#XrxeA}`^qx*0~LqCIr-7(-YgR6HP800$Lc@F -&dGUiZNnuad^7U#xb^|e-6!hlp3mP+C+)_Oc^&|s_8p){T!-M2c!JX>N37a&BR4FLiWjY;!MVZ -gg^aaBpdDbaO6nd0kUYYui8&y&L==249kZBcF1Jp@p=Erchi{3_YYFtfi4PbhW$8tmNw7cXn4v-57+$ -YUa)Rn58~=jv$jP7cKi9;uOf8fXewdlDLNNA(D5-E*EoApisS#i^zIf)t0K>kb7-P@2PaTXt0HsGn){ -QuMMAM`-b(Dpr0i2^D}&aop*Qxw;w@4x61|SZ?#%|Mi<#wm=U1$48~gUwt@6%3SR4_N~2QCqe6P7T5G -1n5jrFKG$1%)0=j4ddN*7WGPKOt>a9BqvenVzUP2zydO~tx8RVCy3OeqFnHX6ULcf??58AsA*FVBWuqEaSnWr1plQ6=by%s2W(K@(sfIKu~PYRm{7+OUQ*g7fFu(UMR* -YaaN0TA-QCfl9{EAy5y@S_8TU)m!}KC7CXJ+9pb-qzuaZ@-lEa15k%->46@y9P87T0Sk=DYgejPfHf_ -pEZSL;w@5}x+BdK|c`rl~!Gy4sLQ>}K&LQ?O$u_@=#Q!{7G{%AF$$q!Jg*dl%2N>vy;xVp{v^(wC#>S -a(hmw-IDyadU@lDwV%&AcgpjB1F>H#^^BJ^l+&O9KQH0000807zB_Q>k}dXZHvI0J|3e03iSX0B~t=F -JEbHbY*gGVQepTbZKmJFJ@_MWpjCRbY*QWaCwzjZI9bF68;__|AFUxh}?P=XLD(K3;1wtn&1{Kvc>KO -2@nJ-Em1btGN~h}^}2WW-|rccdhy$~w;vKqni&pfo|$<_xvsTwtW<06^5xSfGCXTL_?gz+^`8t^gCsTQr+4{A -GMKS~9e%c}{ybi#0_&4m3Tt(&lqN@_J>Ik#{v8mMKRX7>VHF{u-Z=hAIkb4EA=gVyOf<0Xt`g{U~*Y` -An;DIY|!Ye!-$M)4}8P}nrrYecNIwh%6(0A`IW9#L9Lo3|>ZHb_Ti09l?-{!+*+#HJtLKg_`MqEqzHgb+!3uLr!9-b#+(~?dV@#KLDJ`pw&V{uT5>c(W -jd)&F?5?qnaci5kz*lS#OTZIvtdIuAwArRXN0yZQw63_L&9K>wjW$xfIv+7@n9}5y<<6NzW33TlB;dt -p9Ctu}$UfGqDN#ZEuUK-hH)!V8*wjnW7&*-&`N}tny}4n_A?OSBQ=(DndA-$Bfp&Dw7J~EA -RuE^df>1Rtr;Yk68oa1$rCCKUrDvMS7@?8aU#j4{}5^f;W*G+Ibd!>_T -V9QEV{mEr#qQI0*P90sc#;@^vpk#}O)R7B-#vNiyqSB;_7D{}7qaFj_)Hsb3)+M(|?Gbna`tNby-Cp{ -A9gLPJ-;%VV}U6)T#>nxS+F6**T-E|exMcccVs0O(J_9Q|c?+o!6GOKJciA^Rvu%F%ECF8})*?SMz%j -JnR+srSI`1AB55#fl(SkltjMH#b*re@4qsD|!=3C$%nH>q3l!;eYHC16qj}cRWXL&D^^7`|DSnuy4Lu -ZMa$33*rIZftCP#X*t2yzILvIN8FdhStVB(V)HvdpVb;8nQ8{jl{2j5MVNv!^vV}~8;x63aUd!vHGl$ -z!>j-*M78zV#e1PFo(s~Q3qL79H0Y_2b`=L2u?yc4;;s=ejuCBv2QtuCW7s0vHU{xrcw_|AEoDj%xss -pvuxoS`>k+Y>uIIRL -(Xf$&FH^W;A%;=0Cm~Q#UJjh=gq_hekjIFzIRHup1nw(Qeamu1()K0{jusQ~&p)F#xQD+#$O3i>2!BNyaR>|~(1PoHE)fOh2~^E4LQ_Wxsf -uQnq-6}atepWr4h$ARO{dZL?5)AQHC*=QFQcbA}gjxV}RIkfAnB}W-D?~5Wkc%6Y1GHwX}wFIC&J$_$ -FHz6w?cC=64VCtCX=t~PD#F|(Z6)8=p;1h(_tWiXbK&~N(SfTzz8v4h;}=mfcCII#}-$fx`I!lVwAW?62J@nG@N)|A{D%sPOwVr+WLIYc`@`Q@ -+(@W4Q}Af>6>7qZJmhaD0t=f6MFMnprY*(nZQ`JS&q{jH$@f!$g6tE=fZi_d5&N#mhx^@t(C6-Wvpx -NHxJw2r!UW6{q^;CZ@&LqR3ny_5lb^1W|NoGA;h99ombxi@97<;Y!dDe(tN2=rb)Z@c;DQ2)!PXvC*zOy^0EkuG~5!h<6&}@UH|myn*AsIetZ4yhuiky-RHNz3=ao^CwivjkB7(j;x1W>D!&SYgS -|y#KBj`^PiOAj7Y>H+T;#k7t=$Ofc7t}%^+HRbq%EiW#(tzybI@DL#S(L(QABU5?NNI<<`^*uw2#TYA -+*(S{NM# -L?i3IuO?-2IKL^5YUP15K5Bn>M-g{yhushx4!kb*yfDDyu_GCMRPEu5=vpCZj{A|-UI28r3|;z0gQi8 -3!INS;WX1SN_e*`-qPws!csSs~go_Fv=?;j`t*#muj;NO2gvm7rE2JhJ3eFJIwelX=nhXe{r#1j4T{* -~n$^4a~Pw~eOm!Hq9+g5b=AP6ifJ#Sr1yD1nb(naqo%J$3GzSGb}$b@B+=#=!`f5WTQ!F2OW3%Ul1H= -D$}u$WJx?V>XtjuTJMz`;SglbtRTmMzEqnKYW;J@&U;vCj)e2;JfB%@2Pa`2}YU*sL_~jmHT+J8uc!JX>N37a&BR4FLiWjY;!MWX>4V5d2nTOE^v8$QeA7pFcf_+^gmp(mlj -=MJ_;MSQBfFfXxT&&jhbp8O-q_i*I&PzwbfaNc`5hnoO4evA*3%PH{U4-p`t{`%!ou$*CB+sj_X7^i2 -=((?Lfq7q78(3D*36Fij*#eGF&SrX>NqfXe_c#-JPXU7=AQ%;BycJughQ>2BXRFZ3K@%=wUCB=y}#T= -O@w?u_yBiS3h$N@=9$rLpp-6LXF6+)yAI$hL5>A!pW=%^{tdA6I*ysm+@hWh->;+> -B1PGab#H-$z45>M?}~E$`pfi98+zlH!SExvglY(ELBs48G}v2kVW<6buCwJ4h-}I9W-q?@GQz9z6pOj -vEe)$Rc__z+`zKf@iLAUNWXw&j6@)s+JBwgtCs&9E3^s|%#FlHm1%|PLiUKSJ{XIhqf+vK#)Ynu}&mR -_4CI_xPzidKi+b0xUJ5lMhPoLG4$tuxjGQ-RdP)h>@6aWAK2mnY{22;9sjD$x8006!W000~S003}la4 -%nJZggdGZeeUMb#!TLb1!FXX<}n8aCxm)O>f*b5WO4le;CLGRsyu#4>xe)!UY;94Gb)t!cKAtiUlQ6y -M!rGB`LeQ^tX40qU2qBouoi>aAb1$W;mSpW_$vlwgO76lzx!)26A0hqIO`nx>W^a0*t8iy(oa=qOJrq -TH?N}!O_9iwMMYxqZ6pQraK4gjLh9sH%{uBtBc>cvf}vY_()cbHV(8MKW&HKrO_3*t|8xH{bM+r!l$- -T{_ycpAxhXNndR$yVJz;i$y2?Flk?*vz<(!%BF-UBVEXHb@fEH9>kQ1VWwZj4(~^<+lhiJG!fNlUI7797H(7w*KSB -Ui1(@(KlI9j^;+3IxjxUTZ*W6nCXI6;!%tl^Ch7-+NALDHhg^Hs_hq(m+s(;{(vt}B!17O;+YZxOTTQM|J$L{}x0Qi+qkM!5CvqvF|TcH28a!v@mLj^QBgfNH+%5=Ac8U8$_L83uUWf -H|^c#zOrB|a?ad@kZ0?37~O)tG(1JHN3)lmkhG(W#h4Xupw%+-L#4uEVChJ6fjmXb -}$UGwxYHY`PM%SVFXyq;61}GhGkTB{t%V~20yk0;v3%Lgw6o`^Aq%aXvxlCn!_Zh#9;mlmLf7deimVz -B$FN@p79m7Qtb79VTxGO8$GIvx2ztF#oq6PZLA_(1xP4QjcZE*6R -Z2&cVZP_wTw8rRm?{Zkwea*o{}aK@+vuSv%Es3T&_TO<{CoRa_`*_{Fl6{41(*G_Dy+c|*pB>A`* -kSzp&>=lC!FC>Dhn(@Q{nA>8un(@q0VncmOH|tXnVR_h|zwW29lr(7!+pG5xS@v*A3QzlsMCI+q+X*- -?a_Sds108Mi!*wiG&`W#z&&>n^VU@DSO`i;wZxA6b;h|{;_b##)F~Z9w?sq7f?$B1QY-O00;m`Rt8g& -;B}rD2LJ%n6aWAn0001RX>c!JX>N37a&BR4FLiWjY;!MYVRL9@b1rasy;yB;+cpsX9w7gLa6eQA6aj1 -3V(^e*S(-J*)}%G|cw`5)t}mofWIDsDF8>zKWesf*dz3B#Q>G5b?mcYG9Nl(I~wQo&2b^F(||Md -_qgww8Jc8ed6UaF?#)`p$w{kf^NVdCqbDg)!RnimaT>ZBj^^)*_AIi)p&5)V)O*GHXL09Un3Hk*HvAy ->p8CaStwd#IE#>aFtOElo`FKQn7$b_B45(Jo!27fk#^983ks!E71k)K^RN^(HVQaaVt&w8j#yTsUafh4q(5zy}7=6NuV#@0PIPPJ0=UB{`6zGdiKMU!JRiI&AGM2T -VVsU27|#FTN_@MvokX1w*i?|EMm%tg!A(VEn^je)PwO+6Xo>#)w`~)@i -=QMySpJf`Gw(*-Fi||-;7Fbco9U8*cn@Z5Deo -sd`wYfOAWjaIRGAa)-R&K?!@75B|d-@;Fhxol-7JWWgkE7p31CtBJfvfN3ch2*_e`mEN1s&V=;04jzl -_9*l4)7+I!~}zlRj4fI;5bL?)iEIY_WR-6Jpx7$ul^UvWxeAG={!Ucf#96n9{N7Z4$w#$t?DGToWE^; -0vpK#^@|HIT&g2G!G$!ssts4nsEq{jsV7>mm{phlTszFuw3zX*Vu_u~;*9ki5=u#)L!}b!qXEn4Z5AD -QaS{Ng4sgQ4}S(DUyju00qUNDan>1m6-(VAtS*2VT}Ll0Q;(k`RtW>@jfo(sib2it?ai5UD#QV5Brys -q_*AH_-HMy@P$91q&zR7u7J_VwYkQ^PFU>$uu81=SiNOzAfF5Xw)8l_T}dhE1FYJF>S1}RF*z&IegkM -~o=zSJ$pZ?jk!1e1C7agY?ZgD1c^*U{a9Dfp*V1UHhHkUtw9oo!sw?G)*u9J$hNuGd8_h;mIKaYqB|0QDI -bJtluFF4+Ok%y48GaH>3U)*T-2~}fI`ZbmKKLBru3%w%3;!OLDO^(gkOiN{IgNiL!1@kiD7Nvp -K^40KDvV0K}okc0XH{a7f@r=-kbGFvNx*RUYmRlAZt%$aY5tj`&v?9lEl^hu4=1{Fpj?m;pA;RzI|=e -Qrg8Z4&Jv!v)_6t7(4Iv^~k<{Z}-ho=H7QzE2C<3whf;pYAnGZTwUuzT}y{ZUZ+)ZFqxtki3IAC+e1) -(C2qw(7sXF7g49@E84JUc);JbAq?FT4pZGjDOAnFB6iI{Lr!=3o`lBjusQ684>Y08YX{HIzS`V#sw${ -Fj0Kg2_~4fYwib_}A1=HUC_;3qkfq@6_Z5r`80$K6V@IDCDo0H=^wFtot8xaX6%+6aZ+FuNkfnQ>RmVU(m-Aon@huo6US;&t?q2oGjZ3{)oLs|LV%Hj6dK+Ew)E4fL -scNeHOTY4dB#p!t-*Fu)nd=f&8W@KXYNAWBP0(VWRS1dBV3gtHD`JV6))ghB24C*BDc51)X~|OtwA

@6aWAK2mnY{22&^}WXiJv002${001oj003}la4%nJ -ZggdGZeeUMb#!TLb1!LbYGq?|Uvp(+b#i5Na$#2L)CG;g+Ovy(P -Z_Ye02lD8e8Nwk^&nxYiE3h8;p}4T5xllJs#5dh49pX(G*p&J8o^C?Qte-s`kZGBqww&W~jScYE$to{aEQ4k$YGs~TAn(x>#Um)ks5T5NJ -7VUR0eLdp$6~)0A6X`fqETzHesp6N1~oRbOz9>xzo5m*O&9>LYw*V&Zy-+K!yRNis%1YPSqU}nrSWIR -Q&lyii0HNSjinB*ZXv2A9h8aYzT;xOfy@XpW}c3(Y745Us|l59kBFyLTiz -V^*=bLMgD!0ai#pZc`6?AtjvCV`@DIAyIV+K)@hpZ|Mfp%8?qhrsu$%RO>IdGq_x_85|uTc)b8x&?U3 -I%i(gq=L0(KjauMKND=|N#GTxT6dYqhI`O*uA!Cz2I0|XQR000O8NLB_@|AIvy2Mz!LzcBy+9smFUaA -|NaUukZ1WpZv|Y%g_mX>4;ZY;R|0X>MmOaCyxdX>Z#`_IrT*hXIYCq)XFHx>$6Dx>(0iS^X*ihHSItMM;)CFX=;>vBmReOg*ASk#l>O@w+>g-?i_f -b&{tUErfl+>r1hR>s7%w2Ab#>Z&_B-Lcc5bTj$l}Iwa@$J|q`OmL-dfhGYV;Ny&?lTyIOp^CSz&4G@c -EE7>af2Q$m**1z9uu}kJRFy0fQ49o_9ey59UtiD0A-SXFCD3IF>07wun{85>r5`3&Z>~Sg4#1 -~$ThL{KWST{9#_y-&i}Rbw^;P_C_G1ipZzumffMdhN(k!OAs0tdVtU&(CVn2HRjKH6MU9Jn7q*5>RVM -(_jKlx%@6ufAHrqyP%kL?1IhEa%PbLsye{}hn$OCVS8@elmNfd7v_RA5d7iqMCQQ( -ju$5l?o^7dOl`oeS$YuqX<(d*9vBD3Kydk?a%c%7*2dBE+0yT=TqYmCplCu>RpbD#pY!Bil9~dZZCs4 -*D=lO}g2kbzdwrfp3Xu!gUBq0mA2kM_nWr{W5k!p(;G@e}je11v5J=YXDfw$xLllNnbX@L -{O`<+mJNw19I{MS#X}!t3mWLN~NAsz62ei-J<3kIg$m<_%5=V$G?J>RgsgLF2Y1xVF3X=e!WIItYA49 -alWLu6r$ctgQD)>NhBjPD%F=)keo5)Or@&+w{-(r -aJ^J;VUDzJLfa)pE;1!pqj97Eu3EBKt7q)s$)j4R7E*|97G4Oc>$G-gJKJzEGrB?mLsyF=Jo$&kEP*b -r<3Q4tUcLN}~L2#^R%VMQ6W_C6wSWn{w$d?Jz+Ej5}tLPu&Jl`3Tzj-4lda1j3MGXj!PAa$C;zdfT_s -00EBO|L=DqmkwDwh1Ew-Vu3E;ixN*@pO7U9gv3I%yWIiyj3enBZMf -4X-iT@-fKN(cPNaf3hJ;KVRt8t73FDCq*gg#h6`{(nWmI~gQPQKXO4B%*p$02_Tat+fx=q0A8v$~Vj4 -25+H}vX$7#Mb$2Dxj!4Mw3x$Ak3&nXm4TqnI*V -zb?tOx&&hjMe93D1juAOW2`+Fg`yWkbvJ?DC4OgspHJ&2XhV?fx;4CTz=?XhDf|Q}lDB{pcb|x&XlY8oP?%IgV14k4W*O%A -R87Ow%4TVtJ=9H$w){M}{q>!IwkH2PjYcNDR^^vxZkkBH*^Qei=Z$z%Jp<^pcr~puuZ-O8kSgm8*q4m -FvFE6h@G*D=RaGIkg=eND}lnRHcTR+1JCWQ7$?JIA44ay9!=4y5Y28qQ-PZ89~`f4M`L8KGMW=o*cT) -N?+?(1da*rQ;JO3xk6YTG@B%KnB!Kltq{-vMb99B~DWDweu9yO2=5e1B$(he2Ks6|sSmd*CE7Qu`dJ4 -W7WQ&f+f9*hS{V;TOuwU+J=KrL~9>~kWU}FDm4P-A=$ut}R -m1B*j&vb~FDp^<4b~pc= -12wfu9Vn!7$vN{t?oxreXuId8-ZA`6*Xyw^_tS80YhbksF5_iyrdeXqxiHz;|AO$ygUJ~@BI_;mX!8u -N9&tNDvh*Mt5Y0X(&Lg89AZM6HV!oyMBl&W2JwMO)jzQL^aXy61ZBniyxXzP}&NquhP}~on1l -@+l7It#)24nA%hf53!>SWYcKMi`DwWo|Ay_A~~POGLw@>CtJ!%rjJs$IX(!<%J==Cu{{zIP~a`5r&uK -_FEpa2@6qR%fDZTu6baX&_Z7gx*r99wZ_9gwK~LN0221jI^M6&^=K5qeY-1FB*d(R51&|3Qt#fp6w44 ->!NDY?Z_B&s!eQ){)W%U@(@6`v8LL;r^SK`R_^PDC4>^27IJ6}IB4HlgX&c3<9FFlH)r4=%?qBd*d6$ -X(2)j&j=gAOcB8%_P-|4-uckl+{jGx5P>m1krZL1rM${f2k)wd_ldPg$4MHtTvCzRWgWSns|!k1A=cKM{ -qHn+)OUcFMFHifi;t>x7S8JHt^_oc;=3et}t@C>w{+T;uV~io^cLcNkaX$lw)_|L6Q_aqn_U2xXLps# -IZct%pfo0h{BpPm$O5hH%p6`cWCj(D&!{#G&bG<-C}G-uLK39~Z5>%*gM0_b)PbS;Km`4 -mEsCUI)SRlC7m{wvs@}}AvurG#<{lc47wVC;cdMESD;KlxY|RV&<{(ucQb3S}GO#|c)J>FteSUYQ2CD -4wM#Q5J<>>UZZmYep2?k|P2MnKSuutkoR~)J|qTSt)21L{MsgHHA-nn0c9#r*XXa>upev*;axpkt@`j -e{ng!`oaEC#gkwOfVGJ!8}GrpG0e?&i9RvJP%YUdpTiWz@1%3B*C|$We*_;+DXJ)Dd~vngV*MGU%8-F -oC@5?|THms)NfGyh@k&y0wXXt4oS_mlQe9MEb!bs2@D0lxAt?g#(DB^#iWIbC4GT3c%mfZ8 -PCWUaYLRD&DTF>K!FTVYQe8^&c+j7rqD`&8pZL|L0Qs$W9zf|UbhJ25p?==S^5aqWZZHBd*oJ -E?E5|;(B)`a~~s}Gs}3Kz<$#;2~j$c_%^_epX4@9$Gj*6%<{{Zo9%)=*FI9#sZ^wrphqd5CeUvt&;2OOBsdBUx3sI{9vptdwTSemK}G8oB~(r>rl@6S9fy&k;tZb+6Q?94FD3%g6St%g^6E=finc!JX>N37a&BR4FLiW -jY;!MdX>(&PaCyx6eA|1g2BLVy7wl9HTw<5grkRE|}$q>||PatsT`E@pROVu2L~;Bu|vf4} -aYH-IH&<#KgSioyajJv}}Bo}PKcE>@f^>awi2MYUw}dcEdV%fzbg%ACzOYxugp;W^9TWxeKXQy1{Ps9 -1{~yS8h1^5qwg*m}3wO_*q#V%{Fro3^N{ten2gO2NPU;>$0J^`>rGfM2!zwk?a9dBvNis?Dz@Z#S6`= -JzTSE4OuFo0j!*2{@bIwe7X3MRB{y+Ld`DR$W_^_Gg>5_Q%fl?3xmWOEy`9crTiI4MQ^Z@jcA0TAshr -A6nkDbzKVmeNmL~YJqc(SuSkGt2(v24L2PwnrzNz+5Gwf-r5GZ5~@Y`k`OXGO&u=Qj}lhpft$=H)qH?DV0ZZLPn)DnzRu->5ZJKQ9218Tg{x7zj -8O=kf2EhBeO!R)p+8Gu;%MB)#EPUN_0+dYLv{)Lk>T)KU{1W!SE;KwT@%9mfDe&P*KMJcKT#(G8X!ZbxJ(v-+|0Zo*oguz7s@6K-L=hdRd_b6DG`1 -SI;Oz<jXNG?+{f&V$$A+~QF@Xp&kQXWRCO=M|i*;9irV5I;R@ArU`&N?PZaz%t -4Ut8kPATXLAz_u)7EiHDvz*Yh%vH_(F1|Ka>#@9QoMu~~MOXYY?AcZGRR%^rXJL`>gk}&Wy)`HZhrtT7Z`hNG!&v@j_J=78pRl9Rt`R$A;c=|wftUM6c -z*8))Bc;w$&;&|$e`&C14pHRDE5c3ylquwh_X0fV(G#V?;@oPowN+Evuh5W1=|+DC0)zT&i?EC{Y7F( -31;4z5OmW$FDHcu$*xMS4h$`b5AUjvAbSaUcx}zHO2<%bUyNtH? -v0I)ED=1}W&Q0@Pcw*`bC#ng>xIL&*h;;3I9q)|;dMgut+e+__(+b681l -8j?cp>yu*YRgOBI08QMHC%ua1f>AXhcugyn=c)pT!Qh -6F_gJN5&=@m;~DCNHIcJ6Z^6Q_pU}3nb2Js;WrOl3&98fENNP+7ixm&YB=oC#!xvo%A28A_s*W2a2K)~*UyFTe3?khWp` -{3%U{ApwftY|yW4J1H8$71#I_K>76vHO()AOI+onM@dDm_o%73~42zz?3K~Ju!w&vZjiYEA=RG&Wjjv#CSyzZS}Az|^F$#%hNvZAenbAve485rZ)zb5U=Pb2*waz -y=r4j5=HbB6MRX$z2)_Y|n^qv>VRJAjFce6`9}G0XH@;q_v4SLkHu&Qb{RpRP#3oms;+44-O+OpTNfi -TO+cW?hbRCQll0<$$&6mXzoCb!Hf+R)bg>G90#BKPztwE^+&2S`A=Fmh^7~Ov@;9-{MNN5~7roX3vOg -oPZRV$e0i58U>92MlQDL%`W+f{+?q9+$PC!mXI?^3Qp2kpc$e?Cy?26GIn$Rl14o~0wizr=&78W;jqk -u5>B$b6a@r>4%}P+aEIl~_@V5U5O;7R2vG1CBH-Y#6*ff18rO@;?3c`-}58uhIMmpkgre4&7-2V>w_X -GUHZWHuI(nvl`CCPCA{h`1~5P3PrW)THSQ72zut>9hqd*w}LG;q{yJ{Po) -(FFeObT6+^=hyHXI!D~Ix7G29*2v%AQ0RF=T2>wPJ{h58}xIh>a_EF95&T*L{j{*MmMTgmbE3QdI6f8 -zbAY7Uoj&>3?gCjy(`M`pS4UEWzA()hh6NfDOmdn+<5(I&d>c`vWDj?g-?@=J -_n%mD_L;Y--^TiYpF2mfAW=;5Zk)RKMS>t>F)m$erm@cQU8u$3WK*bI>#Xx=)EWc4hBV=FASg9VH~{jcpF -98vicn4>qITi-qofd;nhTI~mmc9RZvv-6-K40MG-{j@7PR;pC7T``HR;1j2bkxok%sK^E}~#f=m#?l7 -0if|mZkOz_{j!oMfJHkFH|ZExuUqUIIm6oLi)!ATLI1^qrAgLJ&#v2$h}E`p+hfr?x$m~_!T!atw{0* -6VQ^l~`cwS1^|7iFEbJ~zWGs4aWWPL7X{*&+QiL^k+1Nlq4b?1%4+;*k9wQ-|bOJ-DeH3-}(eckJ4NM -D6E-jmE*OV8}{S8F1vNbaJhvM)|VhA{5D&|V3Ub{`TY5Fi}~f{!J@8bSp&j$3WNbvE{|_>hO!O5j8~9B}v2-{5}PZGCK$@(DqCrk(9r5q9s&fIc5|kjWXMNP*V&-FjXhZ55 -wIXie@GzK0uv4G4weXGEhO)?XFVzi3u9|bRSwkbI7e1mGrvo@2PQyHbZj>_U1T+|tohI -PPCB|CfbGU@r~I2&h8CRgcthVsEWUnK6}Vihf=>FcVPXJw4L5&Xy?kb~PZgK@i-n|&fJ?fbGR;OK)nz|D3yX(R&;ZwA98 -i3R~QDs2L0)H?Qhco`dy@dimA)xB=;1#it&ip7)umYHA$?(%+!ICz^G)ip2)P1Ed--8q0uNMtdw; -UY%NuB#Xb_R4hfHP*37K{(=M4nMEax``NT-##N9-KEgtdtXW;M8*ThOK?xGrR+LsuY!U}Qj3J1ikHEr -`0ICAK49g_`1nt8rCg2phSCb+^Fin-&0-|HtgLC6oSm4@%H>4@%Cce*RkFq3XpPOzi6K$xTaH5x!@DB -{b#z439dbC+F|1YS-CNG?U1W;F#d<6~u9i;x@*wTYiB12eR-59hb~0b4eVJK{iym2e(m-DJB|4Mt9(g -2(bBRRRfwp5@;~rXPry|k)L5Q+c52JtY+ -{1`4M-zsjmEzlOK?#O3~pbJsy1xU+luLf^Ws5(50@5WZBU -9YoE>jz(?Qm7O2pj%^6wzL<&`8a=Ec}f$Y6eJs=zxRiv;)F3< -$dUh-76n9w~wBj;8`yh9zw4}=B=5No>8YJJa*Q5*K1XC!ollXWj6)T1O)ZxpFQqP2IPo-{`vp2 -xc)n&lUU^*85|PH@Qe{}$!-JbRxDscMYsNO$hl6*qq23gjm%_@}R -&c!tQ~2qQLC9_)ItsiWYCvGn7eK%I88)HH3BsO_YqA0*_88{(ba>AX1>Gjz`sbPWdRxu;Q0i5gUCpy; -cDI)VeIB6?`QE(y*#?2v;DQ#3Z|`ixv<{%U$Y44Ut@5HgR&4{J%2H{Yh~j^-HqNhF5vdu^l7{#}0pl5 -s}0M13f3t18*aSQTqs^d={7or(s=T{G!=I_%8662aL@|oZrazejjjt@9}-rS5L=CrQ<~ueqi#TLK&t~ -|HfrC70%~K6UH#1EPDXk2Y^${KHj{OW*Hyi>;>LP9(UmQ(sH@TgdN`X?VPS!}j;1ZqW(5CF}=vr#7Z7Z^cs0obD~eGw@krqQ;mdJ#^8oD%i#_y9wNk|+g>_Uo>NNb{E5?B!k?F!5P0yBXX -~FDl(Qz(#~}3pSg)B1Y6A42;~QpBc}!3*$O{4|wVg8Nxb==_r)2+dUZNqh09^sHr(g&uO~b>?HU%(=k -CyXmuo%!fH0t6Jxlh1J7*(rB+M5Jh$$2iAJQ$Yn3OE%Lhrp0jc|>Pc=$i(#YTJ#NJbt_cp6X@@?6J&A -JjTE*?KUIen(c1Ih-b(e5m5^eCa=R@O>vV -1a=*iE_O-mV7>PdBfJ}{uN}qNgdq?gb!#_oZe|e+NI$$Yw%h5Rm_XSJw`KHX~DsL)wxG1#FhYrGrQkF -AwY}e|A>>Atx@=9M7v&W*_px6001^2XQ=^%vGYu~GbN-$pC*8z&kh_ZA?u|gUXqcL;Irp)x7&#}+Ji7 -N}v0J@aJPr1vTxd%pGU@5g%vArJ`cSNgSdh4_2V2Xdbcpo!-FJZ|#ZsIXC8w -vK6))qe*oUY7NN^$4~c>6|0NR32RyMf -pxtjk5U|h)K4R~SHPydJx3=om`k+_04i5!H(pctzTeF9U$VmAB{X?=nhlkqw(1}*8?@{Iy0HG6`7xOm -!wb+C%%m$CvVNHwkHi{xUn4Syn{^ADWM_SkkyXHG`{@~wO6@C>GeSuk)H7NZ%XZ*`Rfk@XtQP3E{71g -KGJC9yCsW3Q$PC?9&fvCT;oU^Vd^R%Mlwc)D9uo3xZe1p=&fmqM9$C3LE0b)o+Aa!*BLOzlg9%Mzo3! -N%x?ul}-w`m$o0wfN;^DOQgEHK#ui_s_L9f2Hy2+tbu>Ub;UnVW(}I)8ifmF-Slrfd;he#FPSE1&Haf -qXsrh=|?=efo7xDbH0aLdt(YWzAQ7&8GpG*WYl&z$Yah(_ufpd!>mfp^t5)$qx|nfqnrxMeO;Moswf3 -ya;pvtyYHKUiRL46g>w6h#?*Xj~SaGA(3b-%kzc{ArCPjy;a4JA+vMxP>m%iD}Rj8R+8xs{14s6p)g% -=;S=^#3JW}5y(ekmbLRadhGoWG|9h5PpZG?cb7<>c(viRqdI;gccb{eZ1aXn(O}#+8dc_saA^uOJiF0 -(mH=VaQ2%Td=Ua%*}7!JYE%f_-q3`F`=aj7U^EY0r}`05$Ris@+Vc=3Q6N5T#bQf@WSL1pXszDH6>v= -Cu%23D=9Lqi|zK)}jw2lQ75Ml={oU}7?F!PYg|daxQ86}&(dp$e&4C@a$N_$`P6m7DQgR=XLRQ~FEQh -?|pk=rGtp4}_i@X?RT+Bz9~CMbWsCoq$j=JJDRV9Rw{SnK`Q>5wa)HJ*t(Mh5fBWdw_705yEB547avD -^0~ld-Qa!_wk9}Ml(U_Y-(pD^oUN(}f%#ji^-?&!9IE4R#*vrw5RvOz`9A{L`wHn7R+Hr4-hTDcZ+t;_I<|YuQS{#9ziJ<8LKLlb+DwsHy^=^6?b0S#+F*!vno$ixDgE;A -1=#6xA#_fQ0UL=^bRk!l=;fDw&@#O6hol=4zkmg{Vs#KK}Pnql^{lVB9;1W+T&{tW(OOFs_;XPXPylA -o|u8B@#jL)H~%q-NXz9%M#o#ibe4*LZ@GOje>9^PkqVtUL6G?f|ZH`xR$M}B!~I0_~17x7Ab)TH&DQM -CA^t9Y4b!nez?*`haYC>t}hb|~Cs5*C$x-Qior*!Dq_j-pe7HCh#) -Sk2WJ{#@F27kF$et0q0y+n2`y_2ro?3Ax5$#kHnJkc|LaiDhy+|pp(>@hZDbU~8bWyjwjq_`^G%-piH -YU*yeVv90c3Jrn|E2%=nhR^F|MVl2W=Ok6JLzsuC2x30)fj*Zy)&p{mZ<-4a46)FZCjCUyD4w3=SXAZ -C!+#ce&MQp#E9^*QRT|DQy_n{6t6%sWhIDGF%p4>(I3k`L7=9n!aL_eYcGEpF5g29~(1XsO>>u`bAgDLIphSUM&-MVE -#dktI8Bchu7IbTNj7_frm&5H^LgPQ=(r3C=RNolF*KTPKG+mJLCA5HXrEF8chi$F|WD6iU8@aq&OXu1qGfVb&{lSRAYo?zM6vVUyYZ7O}|s5jO_GCv%r -$H*i4V;@E&<^~`A;9#_Az%if8O9Tnxy3UJ5AvZcx`2SX30Tj}EJWYp92e^;ie*_BXtpu+2yRiz1-*Oq -QyTd@7t#2CAoa5d-gtyF@duN!zgYFS^F3at(T*^qqTO; -K=k$5+^9bZMm9=%S7gI<$U)9uO%Hf|t{ZeVV*#{gLGUY?wO{WZxEWi0YS%sU~>6(Eu{Dg3j=%6DCoy% -u;`nWMhFg(d5!?lq<7dv7&E>to31gjGs)?8m^p#)WUwxxCaB7s9{g4DUq4L_b|NhKH8S=qLJC9O8RAd -hT8g+q;S)xTw`U5nphdN{&?%$TRKW5@vug`DgWUEXp+S^!Z!|`~6o=IO0}_6c4J@B~P7;7xwHqc{S?i -LI!54yL)fLU;4IQ?dcVjo6@1>G+&ZJWNo_(UFDRC6Ouq`tGgg0QzWl)W$Lc!M69yYXJ3W#)*uN2&++v?%P;C)$*I1OfSe!D6y^+SGYe?Xa^dhB4oown~EV%E0b=6jUG?7V3_H{kIU{=A>WV;P4jROfXIi9 -0JUwN@YBh@e?>gD2`#-Pa+79#3?*Ip{J+t^el=;jD|)YFW7-cI~i~0?s0$JB4$ooXDg^JoGXqtjprHL -^wPzZJhyx0qv5nQ)VsLvq=F=*(>8WH_UZZ~#j}VMT59si491xMp)39<)RlLp=vS1$!DBS)g|cvXnA&v ->?d(Ak>O9x`%_qkZAPd+Yvs3nzeZ~F+jS(h0VNcjI_DA-0pP^4;)}CU@hVwmZ;#?3PN;0>&?DDmKa|( -U_2T)4`1QY-O00;m`Rt8f|uidJR0RRAC1pojY0001RX>c!JX>N37a&BR4FLiWjY;!MdZ)9a`b1raswU -pm#gD@1v?*-rCklnQ4`T&IuwqA{~vWx9XB&7AIVKK)g*_dy?#A>Uxy=*Q5=KT47U+{!6_UWXOPNIc^4 -CGiyEp-Vs<)~~NF~;I3j%3}CaX<|k;mE{MVW+7d|^=)N$8uvG=JHXhIJQw;~Ey7;b1ep8EvMbp=~~EDXs%sEr?MkbGnt9PqHB^If27qx;an7NE{ZeJ^5#yZOwzRb^jns6K-mQ}S%9YSL`ZF&(EB6TrI{LQj(ly&z0{4u8 -nwfGFfd9u5YMNkw{$*9|4>T<1QY-O00;m`Rt8fl{pT+o1ONc73jhEh0001RX>c!JX>N37a&BR4FLiWj -Y;!MgVPk7yXK8L{E^v9JR!eW=HW0oC$bT4UQ9uH0UiM}n1&rOKHJTR^--1A5q>;@;B2|)3nt$IR^)Mw -livsmQk;r*`^UW)wZj`oAsohS<-T7ImRSj5kQL!40;X4G;irloHBawz{gSwZvLM-n6Nhf4K8#3Bo-!) -b!$*Toy4^2geI;lo9EPY2=sKHY6wo5e{b=A*K)-J;8MuPD&%zT${oJMEi4ZSc2HWEYTmhQEx2FJUzJ|gLi%T})quvTmMn;o?HFX{)3DIl)9U+kmK@<|v -{SUF*Sv|TTql*CBt0Szabir!uc010irOu$yFQMoIqj@p!tvm{W0->@?)!Ys2E(c^rXn!p3Y*4(fs7J+ -1dwD$;vM5a(vXcXCRrD6>uOp8y_}yNL}+w#xn2KUZ`a2X5k^R3xy;cAyciE#=HlHDz2msKEPMcLgg5B -K&~JO3tmfB*$XgkOG}7&IiWMQ9JB;rC`eV7dy}FA|Ss#KPr2ZEI6Shq|sM!bCl4emH-KwL>QXPmMD!A -WFv>1(e&oHZ0?z^fl*a;q&yCFNn`Mh&|h0P1B%i=VKRcJHRTbG)UVh`>F)Yr5{uG~5_01{4=TaRwNedmrc?_irecSBm;S8TaXQ@11Pdc`=WgceMQ`z -4OrGaJ@QTVL`Gru@N@&0_e!aJ0wvm`WL2MT+;@1_}uhL3z1t&$$S8v9J3@j(scD3&rl{oA)VL+4%TcN -{7{lcrga;W0|n(?+7s%Qtezh8Rnog@$@!`G?W@q;0owpP)h>@6aW -AK2mnY{22)5Q$YPxY008|A0018V003}la4%nJZggdGZeeUMb#!TLb1!gVa$#(2Wo#~RdEHmvYvV=`em -D4k7?g*zi{tiEC~Y96N9usNiH8rLnaaX;-(qN>2CJcV>5G%gQC(Ln);;7-=>0&ChQ}PLkwYt -4CB4m4iwcQ50CnFTzQ!KyM(I+Z+vOlhN;{Rw+NQ)8Sw^Sme?|sk6F3sEmG;8Cq~p8geYEuJi<+q{~56 -BvlzH9Kwd|tVQ}@L95~5rg1r$I{~3GIsn^PhoyyrB&6Dct*c5K2ODkZnM!k`RqJDkX)ctsr9EY*j-eF -Qs;mnq$y$om9-O({pvZ#vXfe8K;YphZDC7e|^ySAlmbIem991Sa8#Jg0Gg=~u1~RSQIM~*dI^__-tW8nG^L8Zn_(q+T?v6#>2venX{oVIj?Rb)X4SInD3_R9&uv?KH2|1L -fXok`*C&k7ybwGy%7&7HW1cC>O$P5gtWRqZbbl@(V&LDAVF0g!fUeA=PD7AXT!g)11ml1v4Q)lJt;XG -{cRcyhlv(>Mcc?Bnc;QwW20it>6rnNxx{x1d?9Sl6zL#7+sQaO7&+~$Ti5)cSbxZg%VqK#EW$S*`X+V -LrDZ-;U+xc+t(GU7bT`yU6xHBc;Wr+;JT*jz@1arocamOV-ez&(`EvTroul3UEC?j+=vjBtfnjCX{OE -8;HMg`vs00Y%5nQf6G;i4SVJ_mq-*OJdRbD7j6>#F6gFf=` -BnBe+&j6~a-25Jj0Dx^`f(TnBrDeYiQO-05XX4DbRG^gA>&_>eF^Pcqxa0E(!62 -k$0PO)+@_bM}Ew22^>@6O+^Zf94k>zmmJj=|JO;)TT*1TF+U3(?ILxs}Ov(L_2pSt3X1beIytXd)=AD -}DU)$uB?gylUqcMY5P*&93h_aVJ0c52FqTzx5lGhyiJ#Ik*v*VjMj?;%3297;(DBaQy48HI}hVEJY0Z -16^$tkv1Yjgl3wCnP~!B8Qq&AuJZuq(K7WEWTbuO`O`=&ve@r@zmbZXwJUK17c>~ym8m3xem4owesX` -*k{lwl3Ngd1tHjfUoiW~P%)SQy|z0P=$ -i9qnfl5}QS4SIAW@J<{=N?bz!RNfr&P46(DJe(+NHjq-($1Z!en#mAYFqe?|S-Wa&vBq8|JS_#0450|XQR000O8NLB_@R@Sdms{sH2dISIfBme -*aaA|NaUukZ1WpZv|Y%g_mX>4;ZaBF8@a%FRGb#h~6b1rasrIf*H+%OP^?*_la;9Pd8>jwy=r?e1gLN -7fni_lu*%}}i*X0)NE^xZ3Y*Is*@Ktpvg_GtcZX7tM)`vb&2klO=O+BvD@O50Zc)bUp3oX)$)V(=vS_Uq8AKm3YNMmREelAis;YL}nWRM{~>j;e62prBa -=*TAh0k6R%A@WXh-z0$y$XW(FP>LKyrB;HrtEcq!8JE{hZWV7~mCM;kZfUhzWZourkx0f(uJhB_IfZP>zj@n~hX{&i3@e-DDq;#>yt^}LR$1`N -rLg(}7Kv-7hHSga*EXt+0`1dFaJ<8lX5ZFMTx1Ma0;`vs?UK`AcS?Qi5~oHG_?wf*?&mV>x8LMh0;xv -x})rr2>Y`_Q>8$X9caE-L&48I@T%N%xsnQwL7m;iG{2DD?LdVG^YixL>2M5 -L+!X3mC8BdM(#Qq3_vxBb3b1x@1EM4F|dxM$yU~Ci}ag(HyK3DibF2yO~Dm6qI%pm3BOd&(D&@o9n+m -Twh(iTO^A=-u?-f5S*U@{Y;uuk$MK&&KSX24~QA<><*Rugs%tSUc$exelY*Nh9u#XNpk7`o-|Q&vRI) -L&Y7T%FoUTsQB5fkUBaMs4WadtIn@v|z%f1${`PdcThU1ESeGFkgy`qGrF)4dlLn{X(e)3803+gNK)bFssGMz@nOmOwy~NC$ -dm495A2Wy?a9#={HbboD)KOhmjykdl8xP!vNY3GxER$Z1nk8tKhHgVV=kPX%Yf}+SBo$&=poJ2Rt;4V -#c)QB9Tj+&)gm^ES$VeExTD3-C38=JH9Up0rA{2yvJVKs{MI8UgJiK@ -wMFP?vvPKfLyJ&AK|Ho^sig9*EIBg7x)8XD~VMvxz@F;Y5WqbSW+ZMlZ(FsimX-hoS&_=Mydi!W%zr+ -aW&$s#+=G$TEiswPX4Ni)uTYV%#d`>X3Wb9l2QZd9Tub~CugX+~p&xIzq~*47X$+7Xr)f}mUz6=wD5V -q=4CENOK?B`F$HzgEUjNRB5REJ-}?EPU9xH4SB{Xv!H*hiXgvTw*FJ)@j!UGFV9J5VEz>Vbh?wBsHLp -ASKYbpONh#E9BA$vjbwMl^J%tzvyL(2V{RvVGkVcNK?lr`&bycMSZkz+!#GNQHM;TjDC;Kbks}(a=d` -JX@Nq06Uv@SvhM@&8iyL|h1Kas@%a5T^h{gLvN{lf9{1@>kU3_L0Nnz?!n -I<@4`|DSHEBegNVSx-B%j66Z^B7(mj8gGM(M%eP@K~ohL6l9ze -utDO*awwut;5N6!}%|h<}qdBJrRg>~z~pJwX3R1YY-h^Cet%dpoI9aJ5RL%Jqv{W$!c`WCtku4EMj9A -dO0Xk}C&D(r#$dhrhqeBj}S!v=kQU1p3x5JA#&b--TEiOts1Cj~yijg0s(Uw02LQ`bly|UuSeA&obys -W$#o4-ZkHQ-&!}HH)VXkSAnhZJ~+fX1s*m@!#=N3o?Uc5qS@omkjT9pD(%?aLLs`hNw$^6$5d9J^u?h)^1wS9r&|F9hY)an^`+uOJ5Gh@sfTHfQ{<@6aWAK2mnY{22%@pd_0W|002}d001EX003}la4%nJZggdGZeeUMb#!TLb1!psVsLVAV` -X!5E^v9RT5WIJI1>I|p#OoVViEh!5%vx^91xrj=(g!@fbOP9)9#0C;H4!x=0+y9q+~ZJ`rmJ6NJ*0oS -8Pd3R$d@2O(*D<+Jwm~8B;rmXbb7S;0hqjTG&ApKVlaJ?DKU}^)Uqm)pA;}Rb9FLu}MPTrgEK8xT#is -`Kf2DUjuF99@&ax%h>xOJ|V;i%GXm4+k`uVfBmp`svUwpiHeSQV>+38n)GPk-E8@A*3VpX_pXMg3e@% --%hGX|d*=vHyYW|I|y;`)sooe@oI)PSr91(;qa%r$Eyt|{5=EO6YC217!5alvtT7Vf9#9TeDRe1b3;aJN6olxzhi -0o4`v*b=WewW|Mq6<gLm*8CnN+s@hUm;HtDb<+hNL6A* -VlR00e*t9oE`ivUQ#kgFMS0+XG|ceB0vt2IR|-;ZvKv^QTT#Hzud)j2o#=m?sV${ej -8~fzVsS5jsu>*=)O{;;fX1WOr6W!0enxXY8db2~Y~Wih>tgh?5c%1+jr(69;^Gq&h)ino5zu5nYmf!G -0A~K1eH!BN1d{dtS8ycO{giJ9;9h=|28QR39-rdk1f#kbJ>DAdtGu0d}TZ1-WdmWyvz1kV1HPC!}x7MRu -zXV1*KdTE5{GwmIGMwboUav6jDRB_2;(TCJR<2;XI9ICM=}w4}>HkbwHCP>9_1f~m>WoNx3`02u! -42PR|w|z6KXGwR!8ambmZD?n54pHt+Jwda&;#rZX1m2rlO;3(qSs3e|@*wa9N3R1^!%Kn|5+Fx+iQz4 -qRc+Jn~{n{|zPLW!&0FNI9cMip0Y5aPiBV%TOaQ+xDnD!EPC#ZLrKleGGBI4F%s>Xr-bi8yUVn|KY=r -@c6aZ@V3HkP%~1iOIA||I)hD^^lrc!gR>vDgn2coc&nY+Wxsmi-@tq*Xw6>S1HWG?3Jnwqw&Z7A{oVUA%It2@PX5$dxo`zU)eJ6CGbl4 -yuP0)lzL0Wd)A|ORh_6DQ{j$+{&DF0%un{Cd1#iB$DqLk=ocCY{v1uPQ?z}pxhLQa0$9Ongb`va6axB4O~CLVfemZ`hxwep&f!!QV8lrY -FSeNjIuIX7jR1xk3*icr>CAvV0MZ8vpWD6FXw>VwjI#7$p;5yLs_4gd=Bbbvpg -yLp)pc5@*wyDflA;N7?|W)%z&6}m@~KVa+;axY>&7n?vDPI&zIgh5jJRtC&`db$^8ts~zbI8ydv8}Vl -=EMR25Km#Zg8f}TKtIM^_YBCL2+0g808wmrL6*Q+s2I#RQookG~GZ=saxf8@+jnf1iZgmxj{-nKvW#^D$uhDr2nBlvT9B6x9L!qPXSa -Xm?$j2Q5!6GqqUFB**X!Et+3wMHoHZLigu0xMW5D1Knpr9!6AOXuu-o;v6hT_im8h062pddZim&z2GH -yFj}XL~So_G;3`IR`68EAnYC{ajbW4rVkLx`wkRr@RUS%qB-AeAhSX8c#Cq -(=Ir0gNUmO*ORQ5gx1u;c?!giVapFs$-*eh0femIyh>9)Wi#~sNp@Dli^9E@nma!U?Uc>g5sIV{uK|! -LpkDaI+gV#p~-)`m|`gN9FwMwCuVRZh^LN^}s^y38-Cg84Z?kiMY==xzcPwHgoY@))b_IX>EP?Ki^l6 -ikdj2#ZTeb^igS=73oA>D%1_lq0z5Rsuu1624nC_Suwr4=A|aAN4rx^0M*Rzcpa9{j;%a&kL$)`bRM4 -9Ot-NVSZGxp;RzrojyOBoP#WnCSiW>&p+v$ZK8A!k9@Qfk)9fHs$`L5gn`H3`bIf^LS^sS?&33jAK2pGSo2|G!w>o5z-1GYZD7`^s+1I@i -aa+VRqWRhszxW9y$3?5r`^j}!myN3nhnmjh(nvlEMQ95wYH&xjM0cErC2iNey)(#b(u6=@{OQw6tXqK -(oL2F4HlTX0)hwp;!Uw3BA7t`NPmH04c(M5dx{kzkWdR$L-+2T*&*{_h&zZW{0<(hWJ8B}v-D0efm&D -@i82Pc?yMa)1ckZ{;rlmi7*;;IArMW0fbx`kj_g)jUb?%DVBCJ(C6A}iFdd-46Vq`&7*B@KvC#48?j= -dfhz}`<4QaQtjA*jQFL2W}ICNxvYjbozcsDrCWJ?GeccM9t$w&IXN9&@)>h;9Yhd&yl<`ai98vO=6{} -iV%n>~p1P8vV%?&2$MwbDlR~wg~tma4Xymu=FI;corXi?xqnjQ{}t6 -up66~d>94Kd8I3nKgA37>+svIWV=}POp_AXNyA{O~e<(h5nN5X}PC)QSE$V;%{a+`Ry`wKbX?>59;6F -IH-r{{P{aXvSRd+th6?^&a!fg!`VzCw2JoDxR8}(YywK){R5zCSE@gb@E+M6)~>F|~*xt;bH`ig5ALd -E}dH8USHE6II^o3+DhvT*!w)j9;w(eY%TH+{!8pqR{v$Ft#3-NCO3>TrML|Bl0QfPUwu=g@6 -aWAK2mnY{22&Cr4Sxy>000so0018V003}la4%nJZggdGZeeUMb#!TLb1!sdZE#;?X>u-bdBs_6bKAxd -{;nDQhYK{BfKw2y`(96(iDEIarncqUO57PmgE;~R@*)t2-W?>d9{aa<_g;Vl2-0brw)h~CxV^o7eRlW -Aw~dgRFez(sdcy5Du9?(ARH}PZiS?S->+ZWyX+!m<`>xrxDS5?CPf97aBp0=2kGkS3;s}Ycn^oD9eB|`@5N~~yA?dH}&XLv7+ -GV$pNf#>V*E?-<^%U9noqE*YQV$SOOD6wnH*Uy(Pvv<#z%NN$X;;p -5y49J*+U3}nr(+3?ep^7N{=-A^Us$#r3*<%MkS|uIdILtJLo1my+%U4{_pCOD -5i2>Eq-R81E#_7%OtygkQMGT7-z_L_#1GY6PpNrGKcg9{I5_!RrV%SkzHTJ|MIa(6E4ntwL7iShm63D -O^8$HjTWNAFTXsk}$#g60DIF0NW9uYjFa`tZBJeO891PlH=rCsgDO@;qh*S2p6!*M<)SyJ=q5+dS1aW -7PP89>iIjtc?NUMNQ3rMA0Lzp>qaj_PldLLC}7)PC%$9UzBv#Vj|2R1!GJw|ATfSFL6$u%vCANbtN6x#bFRhFFzL2BB6=u@18u -qio3Nor_Ck(qsQ#WMcf*gh6#QJzdBlHcNXZaTb|*#a_ZWq6oDz_HP>>YyP<~Cn_V+q&k-T-Q=mHE4bW -(xPw3H%}T(R2ucaTHV_#(rK}kpmjh?x=806DD2~G#kPKb9K-fzra1XNKcI>W&kNjYRX<}~>{u5$(`J4 -#0BLFWV)FKMD!Vx`*ZyH_WP%OTol?o;6D@<63RNG+Nm3G>8PR0ie?~D%C^1_e$7@$EzAVn>-(P2b^&l -$Na$ph4BCVe%g7=%s5bFO>0K!?thsO~#&3uDkJhP8M|_uqFNiP3+!&fv|YY*&~!4;<}Euao?@^EkBaWpG3jh46E+0b5T^o11I@Q+C!!jb^K#c&m)EA~vw~~7svxT%S;3fGhg`T#Hq(*# -=4U=vGIxed2hR1ZC!A)M7Oo|*kYxIRL44R%M><3{yW}Bf&mCsDv&IP|ufGpZ}9W>9G>R`&8^OU^rjsD -?K3uj#sVi^{&Pd54kDILQy`m;MRGj%h|Qa>JlaI)ZOpUDqjj^NW8@yMCkwK+Arp44K*?6DhE5`c}|%? -t_At4ZGG4#EGKm>qaI2*JbP)x~H)-czs&80~dIhgj?prlUb2bs5&P-vg|U8CJeYtR8JJe1rNNSkQ;Cgf2@uK;}=Xu7Mk)TwBSK#Lu8qbnHF3PCk&HO!j>BBsl1wmpjvLG~9?K*Z|nd}~)lFt -?N4|vRMFXhIN;Unf>xf%ekzF}Koy)+pXzPH8jz=m4mWr}7KlXhP@Y@i2Wj+yH12DqTKihJ0bjl$om7p -QA40K*O8E;-)6@K604s&loXD;2~896c=>mHUV!m(jpNu*E7L5vmEZsj=rAjTC1@Q+( -KqCHUTRbY$|{DkLxvd+K?cX+rMgW1CFt{Q*OhOmq&X<*oVcaCaQ4Sy -*XcB##SC`Q>H*q40-4$XuE5D3O@M0@M+yvZ_$)=c-rzex8`E5R1{6-hhRz-Y;8f!Ea_X0xyLE;=aVw! -2Ad*6tipmwdECEq!b9)b7!qzY?AQ|SoE(Lt83V$1VX758Gp$qiw7xOQSc)W%Z$_uh(nif>Mf%e7n{Nn -P}x7oAj=WpIZ_C@oL>EiQWJ^A%-e*3%M|KX2+I(&hcbP<{Oc?aR)@U>nyE17G;LsyMmm@hj1sf7K!iK -Acs@Iw?p+1@bY#IXPR7S1H>)(o+ME^AifbrLh(jf(RMz#l&zEsEV0)NtN27kHMPxp89Vl4$UofH@@%D ->%j?t=6EW-fZ#8p`y7Pp1tpaP=#`eE6Ap2VH`d9L4jB&V@a`fG~kgy*|S6dsXY_BqoMg7H)Va)c~p({t^$59DM>otp?B%os*8+(r-97&=67QDbrf-T)IRB0}@D~Je -le1^(r&TL!AjCjZfA8=|qi0}l2n3E?%%CP|W)a=0o2ByTvi2MSyNq-c)jyuU_@DeF*_|x0{{aCj=i_a -E@aN-nv?A4qn9uA3ih~CmW?5n`Xh!*%$7*4Ics$7dCECq$upvJ*x7$YOgquKY&^1t@M&uRak-}e7$vn -++s7E6MTPc;>{vtPN0S3^5av6{MMSNfYV~r+PZ=B>4z=AAO5(Eug5amV -38rV{8&jQ1=$ux7c|_FiveHf{{-?L}sF(hY_W!>#0Q?hBO9KQH0000807zB_Q|BNLvn&b#0A(Zq03ZM -W0B~t=FJEbHbY*gGVQepTbZKmJFLiEkVPk7)Zf7oVdF@(lZ`?K#{%*kkft8U~x@_b)IV1<)IYoMP3Zr -cj#0d~24HT|K?XuR2I+C)z>Ggj5&5)Ety=}MG`;Y@pK${iG84l<58OlKrywSYinlnWtE2w4}p)y_bYo -_AEgCGbF4-OCbrV>(z@ -;Q8j=gXH|}>+|QA7cZV)F6`jzr?19?Z{Ll_-d()x4@Nsg*l?9LyR%Z&k|i0Jcv`dsljN*1NxWkE2QwB -XNl7;>Ng`Z#cyRgV<;xeZUY~#KZ3}dLImq3?36N6D?Wq;oiLm_ifRH0nihod?$C*j)ch3e&Iy|tZAQy -&_(Y#}A4-#i=S+BwXci4!mMhh$0NE3QZd4UcQM17f#$cwVrl3Ymga;w*(BoE_{pEh(~fqS;vTV -AunPJs^(GM1CHmXeh^sW((zg;9G1^siGAM&#ZT0=Boq5Od!#h?+HP=!l^sH*21*VcoSTAUesKUSr^BK -@=?KK*3O4DtWPuP2eIoLwN?F8r#k9M|Qj&!2h{1$#gACL(<8vDo77W!Dt4%q5p*y)$7q2l$Pcg7`E@> -<%6BawXi+@6BjVdt1vhYqW1SsKLu`co)egX<5?P7W=+K5V^;Pi4a=ODnPEu&<_{p(h=6MtDm06uvx=zW^(L=ybfMYNTN`QgM?Tje3o;mqHY+)4VeL716S0s7* -+8#)%9w^cH4b6=VnEHnZBqd||nSJZABNuxlnErc7E^cyLhyUA+X+SgM8G;utNPLJ_sjmWs_rlu0F7&T -ql&&wkmZajx{R63Sd^XTMrll -btjm9Y*iOjT8-fVEw`e9f{5>VQQ-dJRt8Gu4J|mQ32j;oHo`v&TC`b1jIm*8(fDu~}rpA!wXEAhd$4kG) -3@jzgBrv>C|Eoh$}*YGy^j=y3tD=y^=KrsWDWQY$Q7O*HuDgK)AzWC~*!Nb$f>9oh~X&AViS9Y}?_s$ -!+*CV^ZwK&Hc}Zau7aeM=0H^9=pVa9Lo97B?{V=+D-xIHPIk -pO>NfMsU1-fDP5p5bVjg9uZ_ -wa0uy_6<{tu23oAcoLuBHTVvi)yD8IzoIuo6nXF90uGvU+i{X$hL@DQHH-_kXLUBjr=@35nj~7xSa}AL41PS~%ar7hdtth|JSQ8 -*Y(JVB{lU@s+nb^WJf*lN0U2<)EBT}HQr#r1`J!sFHF3o>(7vix=3dYOFi~ -4E7e@qs&`2;Kz+(0HF;82+V^J<0$AA9ElXsOzwgkt$~h)KoLO-KN}5h!I&ioA-`LMRqaP~yY)!U&Uc{ -(jumddOI2lR7(5yW$NYG*`TL}Oy*1#LzQJRjJzBcuRgiV -wquRPMV{+9gd50HnDFig=6Uq*!KQgFKRwuwS?`W&n%C`~a>3cCoIYF2pqG-}z1IzuC75hb8H2ym5`8j -b8eOVn*chXOqHmdyGp=A<@{S4?gZkfuYd0KCo$XIfGK|c#=2AHx;4oYc0a2y`QO8+O>-^qdrjgk^#Cm -Vz#=tBixqU}41>53Xs|&0!`rwJWd*vWO8r0+M^T*K@h$<{1?H=lc#(2!ljpJdl(A;nF)*%~I)3oz@xy5@= -(tV2POLPc{m0q9tD}5X3ONC#TtPZ-KENQHfw5V!FU1CPhLm-sTMtnH9H2CUFH}-wb&5rWt2q{-s#wZ% -o+4a;`U=hec2n^3O3mPzof*x4f(v^!)_U$8W!_z=!<)Gzy`}}vPABr4|4ih%;p63m9jic_GqW?tMexe -YnhiZ}5_r$Mn1Qz>u2T|hEazq{Yr(a{`{H&sTp{Uo9}q`m4U%|U6@jyTGWY926oG=>rFLw5Dhi5=x -52PJ)LJ5P`%@-bMB7Qf4WNH-)7Ef?mxWwp6kKz$P*n{Mbj(Wf_3+kwsN)=19~ny*WroroNKfb96m!2@ -)k9J5a7Nsjyk(Ijt5O$BZY^9B%_7-64A_cJ%bnTz8LsfAu!F475f<4P!DD7Y$W>M+M^y-b1?{z%l#b6 -TZwT5&wgf3q%vCTb1V*!Qrv_g16xHUONP&oNVy|E6O4e{(?Y4*qNa2Kp_}ltOlO{ga){5qWm -;_Q&&6h{7@}*w+&?8@l2tQGjl!h772@HLf_M(CuPHnQ4SEZw7v>V;W<*thm{-!%u0^KrA+7Yy&uerdM-6c!JX>N37a&BR4FLiWjY;!Mla%^)haCv=IQEwYJ41PD@|G+9QcZhRtvpsYMQ -ebd5AV84-U9+I*0z*0TdfH^^D(PYv#s2$9Nq4>&S?|RXDUu(_kF?r#)&;PBK2z!FgHz_~capsi -^LQ$B_^n4D=Cj7x9fU(ihLE4!c0pMq^?a7qRc&{j41@mu`sV%Z{U5BJ&$igWR}35SyYY34J1po}uI4k -K?~GmJ3JQW&!o|DM_ZJd8q&KPou@Yb`1u%>++w$iy^v=MIHJF51K(8v_X%z}GUBH|2%j<_q+daCXJmM -nE?Iu{pR`B_MQPFSG2qDs8ZOs!>t};4-VCmE-O-6SgKU4spT1=X~(i$ESc5;g#AHCImpo7^$E1xpxZ@ -mq;P4B52!B;2IqUMTPS@Eed)^WYtVi1tuc#lbx$%c|5lWC7Dy8LaGDMUm{b$Q&S%ATyZM}$)7A)AjP|U-g+p~T9bCguD%2D{58ty8*A473@{NjoceBn}bq+fuBC^D{(jjA)Jby -1n`HMaQ=UFm@^f(fvy^o_1+X=C|o&e+lrXF~^LjpuC(&`@sv0Sf~cSK9SY^)X4; -O-M+t{uui_R4z#0t7$0xo}9yP;O0cYA&%)zLc#jHK8Epddpo3?l2CLg)IiGLtGcUyt@cXql|p@SLaoKopoJ+AQp2v- -ralm?krZdHV&j-EQDGN2O>OcyZdPP?xPhhdf1{(W%LT%w#Ij%J%1&v8^fF039XnM4u%7A&J9evTe1ar -ul!k>=ZdX(o{xru{N?M*S8soupDtd^Zu0Bdi`lQ}!tkunt6E5&4hMigCK0N -TP01%1kmIWf1v#l%@sTaK{oQ^&#ozRYtMAuLHvE}04gafR((+L<9E>Qu;h^Ld9uC)y3Ns?SHdGXPLsHh&QEEG*GPatl|pEB -N-&cR-0r!IXowFs@+|FbH9^T5;uUw!5=UoV&)T_=>NlfR$y=nG{dQkVN4m}+RZd-nYOFnG<-t7mx#8}TRnv~nIuW*FV=9<%_);TFP@2Ssl@D1_aBBhU0~I -#K|qrG21?cONOiO>aB1ZA%c!a3S4NH;d)23rmgMq*!dt3sG&yK9G4Mq?-r@

91-;Miyf1qF?@*QTs78 -tax>(BXQq}?Z~V+8hg8|8U8wYP-&8`%`VrLGUzDW?4JeUrI3+Qp4KqPODhT~R4_!;(>q6d{2)iyv|0l -XX7^2VKR)k*MYl>gIh*9w{TLy_`iYK1>I7T#*(Kahi(V&%}ZfOySeH?%hdOF243ht3R+YLVagdAgyM6 -7Up@ln?M3A;nqRwLc-faG!~9IgMe9pVWHY+cZ!|wTK2TE-I8^-|P!T|WmmrY;ePznLZAu=ZJCOjvN1F%{z)N}9QWi!xb(;8%3AJZBg~anU -Ij%q<^yuJuNA45i@jtc<3O!MJ68!DARpvgq1ceR9j>S&*la~y#db_uPtOQA(C2om=YJ9jvQ2k5pxIqR -G2T)^(>w6@>t2Ldbv;uL2bB7H}K60ETc_~aZ#_)-@;53U&UXp71=HCAODfN9{Od=poO -z4jIcOBi+g!j2UwRGNX|9=2bO9KQH0000807zB_Q{J;tf)5A)08beJ02}}S0B~t=FJEbHbY*gGVQepT -bZKmJFL!8VWo#~Rd97GmZ`(E$eh-lUz^NE20SepnF+&P;TecNz*P-h=U_l_z5^b~54J4J+GyLCo4sQ} -=yGe%`0b*I?xqRn47cxnbKZd^Vq$bOuEw$)cMV6f;_no{I?TXwBy(af-&TFz1HCOcXBuSFflhYH?m~C -~pTEW88lcnq$!W$-P+Hj@ViW9fwt$mD^^h_!){fghslUtxSJ!*EZeiWt7$%mn@y?}p2kEZwq-?Qp((f -DTSD!~aq&2 -E;BW)2G-B(P}PRR#X1D3!y%^%~*ZRlv2OtnpI3QRQmDi{U5L2{Z{<&?(OfdKD_?^ -%@w&M>3L3`XZZT`1cL_XU;60L71wXfZ)ssbCGw4hP=wc<-s06Ib!MXGqc%!88L64p54?ZeL#BkF<}2d*JbIaz -EpS2sCJA;oJ=*@xu<6A8^lePGfTo1AhW= -0x}>~Xn;6PP9dfBqvzfnP}pna&j9Gr3R5t6|mfRzn0i8qbDW6KL~J -B=6NXPH<_0yhF%uo7+O2=6Y)mhX~Sj-x9A9i>Q7O%k#Ic~($r#X%{tQOF?^N``BEJVGo&aWRDPk%{x% -ar0-c35)fUseZB&P*Grs(M~-(E(}s?52_0STUfiX$g4>T*i2b=;2qdh0Ow3SJ?vZN^>|ndQ^{e|b#D; -vK^6&{DDJ7j>NFz)(4IXMsB9Zr$Rvg=6N4TzJRRgPMb6;ljR<)KW9gLNp6j$}Xr@T_4uYr*?F=scB0KL^|r3dl4}r< -Rp~TgtO+FN9!vT$3X|Cv5f`U8y+Kv{JwL(tjCYzZ`2SRP|51)CRiCz$=$>Utr&t^2wx<>Ft&wZc?}jR -KNPHB`dWdJHmoVWQPQ(Ij+wH^f&-5&FBDKhjXpSf+p?cN(mlo4gvn9vzee&K&Tkgap>hK-@PPxg2@lYMtwDg?@JbIUS%}{;PLy4%nP?&MhuASv$`g!h6 -R|84Pe{HweeO%Ji>1!ZM_snE`L! -PkVeUE&FQR4n}GFjocYR8{I~moh0!^0C0aa95X*QYj61519?_D#)5IQ<@>5(`u&4d!wfTr%Do@TZT6t -HbT&aenVeZo@~n8vC7gN6PRgOT9r#zivDE_?G(stJXlg-MK9z)h>HW}Z(eQD34`((wz*lEbFf>E}Dux --YqPm|>56)g&9tq1H*$b9Q*$s7NVv7z#T>+0V?JzM83^?9)fb1fiUEaZFc@IwJM|_=ET~lf=;Rv&hjNd&o7JPMSw!mPwfl#Y24X6=YJ?Ud6+HGzmk -0n!c*5c`W6nN-#c$5G?|Vo(;4HP+xci@MtPoa@Is1fr0!ltWWNmu!%8T=NO%27EK@Io_lfSASD1)Z-`j6o#e=-hDIgD8Vl!bGYjHyGXlN -GaX)*xF=cXN5_s)sJeh?>3nM(Gbew~KHV4O;)wwrlI+voFvyWEkf915ZIc5%OyiOwd$xY}e(H5c1J<2 -0Gx^)QF`vMos53Cs{+NmOnXP7=c!hR19BAPa=PYtSWzaM*Ol4WrYd}Q@tx&Ij2`_VVD8%Xce%*x)wgY -TRhGd>);sKUZ$$4+}qfa4}`yftGO^vfFS9kyCCse9#6isoE#1q~{dTAOk%`4SQoujfPyExU%JLA=Ra@ -I8ey0A$}M90EB`Mph16V;~72AzBA1XO-IVLei$;EksB<~plcyN8v*$l -ezNL}#B=(>Nu)FWT!4%hXND2rTratTRJWpIztXqp51dC)hvNsv=OP>m?3K9bwRo*;P_ir;FD}`l8}!4 -MJm~C~gM%4ju8!tcKq2vPaDPem?|tF-uO8sGyQgZ7$99*Y5m=h%QPgXA;lnVyl}i9AAk^$U2w7*xWXw -u)?swa>*|==dvL3xW=;Fjbd#z28LJ-xtU#~|hnJWZFT7C~*Xy)p-DogU&*5d}}k-`50P)h>@6aWAK2m -nY{22<=pDjG8Z003hG0012T003}la4%nJZggdGZeeUMc4KodUtei%X>?y-E^v8$QBO}oF$}+x@Ew|P5 -EFgT#FJM8i5CxIxI)=0Fxl2e+Y#~8TM!e)gq^nh{r5x@CQd;w5P0|XQR000O8NLB_@VeDF`@&f<>@ -(Ta}8vphAl70Po9lSSu+bVVy%*{}XjR25hE{1JRq!Wqd9)G*(iS?;z%ah8>gjiTc) -Zr3p*>1OE3oYn!?!Zie2f79k&jODz)-f%YJ2kc|qWL+xg~yRqJK^{mfhK`A6+P=uTDtTC44GW*5P6Y2 -a&g`#!o&gAfnC7Kj^y%`I8=s25xA@4{G4sbVdsG}v8Ul#&4m@7NEjDXnHiZOqETVab?3>?qEDsjt}~~ZoD_ya`<-rk8{oOvmR{1=ZOzF%nHd<$WR`Bym6j+QMTMSx=QKu -ngAg5fjLes-%)0_E{Bi4VtoEVj`CZQJ8u`{=5-+H8h$o|jpe?ximbC63n_quO&=9Q)ZCX1ReYa2E^FW ->N0tLyf+^Lpqff5(_YE(<;m*{ZCokL!N4$ -pj7;}8Ei0Q~Ehm)D{mdp`@#mHckRoPad5mT1nGv1qd&n#&9&G&41T5f3NBEcM@%?87c6t+`Gw|(@*xP -xvlpoM?CeZS-~tv4o-h0st~xvy5Kt|8IRRLt|go#?1T(-ci7<@ts@2l|=X-UNA?+q+O++`0-DgO28ri!n+Jr5=JZkY~yt>i87LUX?oP7Cwmt>5v8U!B7Z1oOz3JMPi@}G3;_T@{MWmQFlAH4Pb -fFvEaup1oW=sE+MyeMW%!fFNwqDCJD$eH!Xi3X?diZ*BQAc;d~nQX^^a$Y<`cq4F?qF8PS% -yWC-F}$l*N!0jq}969!DvUuURH88pQ;dQY9NK#W!&m~FdCbN6J)|N=2I1!<4IQ@ -+j9!G$fC(s4ERd@l?R+zDF_Rb#BQ=XNmm8g@tCQ+1b$*E8dPiC0q$`6*Op;M1j=wp)~=j>u9jXtJ|6@ -lsc)n?up93$vdIEq*y(TsM&YkSD?^Qj;)P@v4{x)YZ?l~%AuixKOXaD489^BmIc1YS!1lyd$0XV4Bz) -t~Wh{zN-M5i^+ZZhiA=bG~?J6(%Y?6&2;*JC=4`ly|&mJuT@IaSNC{XgyMatE;QGa?cKqK;RBE4J9t! -RUN6c%J4=E#|{|&Qcpl6-X8IaYxx##MxbKx5()MH1W-!@1QY-O00;m`Rt8hKo4D-F6aWCdMF0R80001 -RX>c!JX>N37a&BR4FLq;dFK20VE^v9xJZq2JIFjE3fcJ#Un -`Zt8yK#1@1YXERYI4yZ!J}^VdZ`cYcMWhN~3)ab(s7PS;+Bg -XEqw@NJK=g18RFVg#Cdht*GYoY4r7g6)(DQufEAAY|LcQ4z6)qPVDRKE3*U>R0#He@#l?%VNQ!LC^cuu&4R}OMM5~AeK)FZaGv9y?BINn9C}s<;B6uF -$z6FqmmR6(D=!4m}N0UkmHSxd(W<+>#b^p=$2RHn^P`lQ+b+tgifhA;k{$V!1yg#1131@4h6Hc0HP){ -;R4trd3X62Yrj@UmdT{5r>pj}r09BA$U@oWn_uQo!-ge7aPcmfK_biuf0c~P>mU<;&JzN|D~WWoYqzk -t>hSDIGV4q7HZ2^Kt=&n(3PRw(>^0lzQscT{ix{KNe69`NQnAln4#2qOLCoA=MGkf&k^noxYwF~W@3T -(3jD<_!hFeu_B@b*aW|`ggV{ip&a~C@YoIgRl{kXoGS|AnXcB#=%^@kY(7m3T_G1IpA<$n2t|UsocY; -c}n)dJx{VC7xslt)?y&9?h3pTU@!)Eb=D?BwM82WB`JEm6jHDcoCt_UP -%WcZe;1{pHQOf5d0+o;?dJuE0uOWo69O3XJIv$@KEsnRNEU%UW&fOBxJ4& -jSq&Y%pS6Fr9?m(3U}4CgTQ(yfQUrH}S^#*Jd;$X#YLP7`XsW>tg10`j;Dq%h4?i)=@-8l{g -Fa;l4{bSm(AawwI=33apYgbXAeW?f-cX1fb{-nuzMk_8VcoyP*CSAbe4&*x| -QD7z&ije^U_%VfQoc`Y~ -yMbhd3VURJORpID2gsUnQ;+@m2_3*F6`@U<2zyM6ZXHDD2az#O;Q#-7p!mCCE#HEF>7wN)^>shsKTIoJZtIhRm1MB1`Bn$@B!AT0*h;QA_5+hmJJ^ -SK0h{XHoUE)vPl?0e=mC2=|Vb7Fdn~4g%}MzJU@_%#ex_r9P$MZ<$|Hm|LcQcQd>=Cwqyw#FguArK;<^9b -pb!Xd*mO5n;JP02Jl41#L{mn{~$ -1phMfj-1-Wk>edDLC38?(P|KZc&^_#P2bM^~{736s^TA(~XlR0qFhymomHio#Oz`>LVfX2j3ADsDAxg -Pcuh3txa;u;9UdZ!MzXEu5#bq*F7i=VjcLLu{ -SzrOd~~5kFq!+VA3vqq4~zxcqh?R&i%q|1af>2@ta8IY)34Kq9W+b{js48CN>IUQ -V1YZ}f3R2~NQ4WZS5Acs+9XYVm}#wxqNI}EatIiC8-Z&vNZb@F67bqO8rT>|Rc=rVmqC? -_&s$JYV5?IJLqhgD{__|0N6@msmOlF2(dLp$6+|$9oG~P^G3ZNUd5w+HvqH(0%xAxYeEbnKQ!sRFjfV -%i9@UJ4mCTwNL)WlbsU4c(Flh=6XuJ*tXvAmK)$x%fEN0^YhhYGaF}Nmb0}7!&#!FGUfb9#sMmrT8jM -iWi#zF3k{YP4YNcg_Mm<5-Xtocq*(3oZWmTmu$NQ!;|Ll)oy!+Z!S32KBzAqC>%!W^?tFMAPt9PY(2k -mqlV*#K+8vn##_fIBWTD*9LiSZIt6p$mo)tPWZTKpZusf%fqu79Xh?^6?`fXr2&R*>sBNe*Aba&@=?{ -BZv{nTF>a*VUG=_2C(&yBoc#?Wb%q$a?mX_4W`8}YW$7KUIJ}wF>J9wE6Pzn4G#}2Z`0b=`sf2;QJbu -XgVJUYcuMkMP=JXbAtW1=02s+>#N;N6571;-DIgFovYn_SDqkp(=Y|e^8V%H6AbuU*@8=wOzfmc1A&}NY%3fOp1f_&Ve#I=hs4xnW-g!<$5LG@?KGq7qrr;j5H=N{eUO(`c`mRi&S6=vM -UGDT%Y5{pfQ;GcDPiGPa7n@p|EZDj4ZXCnqP_&$a{?U+1XZ#x{K~2|Su$T1VekYZLnQNEeOIHlkVUGI -w6oji5X_c6fW2~aTi;D5uBGn|LO0Mn(r0lTg#=wBa!I90tK`_-sEt#PoxK)NFNiw8nKq!dcLNdNWvN1 -MJZ#V#13N`7^^4mX*_J ->IkH$~nwpvTepko+ti})E2KkiAV!)sD|lx|HT!(hqvdOEEGqwjw?^%*(Hz^=Gj*WVJ>iAfoo4%QGL8? -x<1X+!}yXwF}Bhn9*bpPJxs8Mw-UhpJye7+}=-Fb&&`S-{^ONPIM;7u$PLZJF%LB;V_(h#Gvv?a!5#KoD(wmm35B`#Gzl7 -Zd#c0MT-q6*QwqP8JZ67CW!SI!TfeelqkXJl$)@K=-8`7SZyMOc*^mwcR#rVZAr3j3y305iV9CmiFQTk9hT4NMU_M=vE=UwPU~cj?LWQBQ}KDI|73bV19Ij|nx8pm0lJ&as2RG6mworn9YRmO$Yp!j{1+dEbN&j#jm5tCl{Vr@k?*iFTDRSCW90s>FmlFrhB=B-m -iWDii6B)rPv-2%p=p0-&uKWO7xowc*Hft@^ZX&(;7Mh3;25cI?B2iLy<&E`4NwusGyuDU4L&UvycfU;}z)HlmMqv+VgaHM+RE54dp{C7!)6`T>p`i -~Jr?j~8kw^d)EX?R)!LG5u!2PQG`yAV-IWNezbA-+>rB5=+{)W!+q?xY -yhBy5ds-lA^=f_x#@G4Pk=6eji}{6C5N4Ts$$TUB-*P-?!=q1{f`2{yZQ!+$Mg9yUtn=J`Tq?*)33U< -K+`w1C*DK$Iv7#(gop>HWjdHv#t94FuZVI{}u(yejRfrt9Kja{#t)O(yld%tKOcZW&@WT2>28v9-Mxh -PRX+tqWaJ@tSU_;Xddpm2ty?@vOclJ_8>VnA)|(15NG(6VGfcL`RwM$@}*&%@1nEOFS`4C#V`&SB3iI -{Jjkf%pEOz3jT#GUsj88#D1*k02Za)+>Kclo(V-c$4i>*rNET?%EV2evfwuP3X80KSwbYhRjO^+LA=J --n%a!j;z-I5h~jZB%%L!f;agY_n=g2FU{S67v7v_G*4^NO6i+4)f3HA6F~3{Q%s0HF=x*Ci?R8tE`|R -Ye|M?#e9<;(Q-0TGQUV^yMbt+48FxN!CSStP=GO4Q&O>Yy+wU^I-Ccs^+A`RawqVjBjRNN{(C3-1=b@pb)V}ZG#Ya}O2bd*CIuzG!M -94un*Z`*_-I@zz)yxFb1f6aKNVmUH`0X5cd5t%-c=|n~`byF`;AGi8#HqRZ<7#9l$+RnCN@6I>LH;Bi8*vs8|o -xcJTdzYea(XO@E)i()c#1BXx0w({oNxA1=tQDP;rjTS;w1e^U|P)h>@6aWAK2mnY{22;qlI(fDQ0043 -n0015U003}la4%nJZggdGZeeUMc4KodZDn#}b#iH8Y%Xwl%~)TL+cpe;Kj6NDkfMl#<%~V->3|!$9X4 -!0*A~}eFV};h*i5X>mRw0r8VvjHBPA=5om_J3T5NuaEs+%e{78zCO{T7Q7Taig{4bS5{@YX8}jBI+Q44g%Z(xefNKt1)MP}DQG_jzxX|Hz7Q7BRckKH%4YZyZKCHHVH -vJjW}TU_tM5IS@A2bdPh-G!MzMQjeTe6g@FlpS;tDpIg?fnq1j+-1#GKJ_I>h&})8+&4?(yKYc!jP@6 -K-aoT&-i#{c9sMb*WNZ`nW9v8FO$gpBl-uQ?P%-KiZZX|~P>xUjQDimi -7y|y{|Isc%g%EFo64}CKFG%>|Aanp`9E%5oB*xdT>H~u@tjx*cqks~~1Za|b-qR#9nl?9hgNk^Z)=qJ -(DF2oS`3QVODA9}H3x&@WWM%K-A#)R#~aw-!ewUR?OMmoq6(&UWLcUboNt?w)Ip(9@Dw^&kR)A1)F!| -0?woi@Ty>STv%OmB5pmrQBbqheo9eE_X=+H6CvUHg0sP{E@{pi336?bzg^DLq&*oS%X3p{#@aiNfbQ< -PYE;j`-SeKhWxa+IDr_TlO%}?Mr**pLpbj@0!QDje$lxpo>9P)W}-v!ry96HXZ!k?;ynHLtFBvW0p0E9bM5uq4e2B~ -g5A{*<20kv272{Ff_g&a1tNe2x!UI#aSqJ+QxyO{Su8k_T!NPX-irc288rK7eFlEeb!cH100^ -~A#{<7S6ykv!e%?Q#w{e(H?kmupGF3^v@jlWgZpq^5I8WD94~uEPdpqY_W -xTQpA$-0bgOJq>}G-zu(LEWq%O|fn5>;D!O##M{~ekfDz|$k3n)Zqf#{K!M2aOVaA|NaUukZ1WpZv|Y%g|Wb1!psVs>S6b7^mGE^v9}T5WIKHWL0GApe2qAdt4%Ro0H -1*o!#5G)PbbX?qvDy*oI23N3MWRcl3+l-6Dx?!Vs*UnGjsu8p<_9B@X_Xen|yGn|)ahRW6@7Zu6*a+w -v&$B#1oo6F`=u*Z)Ug0D%nEnx~V!yhwQjmeK?mGOe+V{%!SIm|S3%dCvztf-iPmr-41xs2ACOzi6L@g -o9%-(_jaic5A^jrBm9$ug(gxTMv}3}rG-cp-VtG(nnF*@m?*vqDxh&*?QxNHbwx0GX_cX+4eRgh^@ne8<;oTBL8qQjW=*-Z0=rjSN!RBr@7CAwea;awT}~$@>=gIWHF6F!_nCdBuL< -)dyY|>3bo#Xx?nJYNZ+YS(AOI$(ljfPfPUp5gs5D*=xs?VvrCIczeKEsPY%dg-?h9d1=I>e#~Uc> -O4F#2lr`Z+!YO036^lAOY^UDVg+0K%@uMl-E4R0U8BV57jAoUnsYJ1SVoV>_O#SaQSb%Dj{Cd(9-gF~ -^F3Nb#AJt6;1jS5;NI&(i+DJlpjt8T*c-33wBY#mlSN95%k1_updV%8Ht4*$NKQ6p|6#9>afaLtD;L0s#|=b&23egciABp~KXuJB -tC4jLCR`3IOpi;zz&mtO&L6&PwnWGdmdd#70r=a&`x1C&QMsuO=*}7MvKJ&rsLK|2{Q5*1Isv0&dwUc8ekIqfkE2PJ3*FHV*bDj)}N}W*{RP+@H|jbO1fdn -*ae5R@XphJZj@&hg4MOZB8UT`lDAp4(o+0xE2>CI5mzh}OA?I~R7EPm;CSUtR+6mhQgQqP+%>d6TeXj -Ru?2j;nRib>#k10wAO`nTKtTr?0~Ab<-xX@c#Ks$id#==wezcHCg})Xdsh{)tjv#Wmf-?q(5h6<&Mk0 -PIm8Os}f`LPjTX;z%1t(#1oK!Jz(2}7D0sq)W|+a<&!a46q$j;keu8wRt{?-D+btht)VUf{fwfaqxMeObyB-}5 -I~xR4=^qh1U&1yFGD-lSfk{z6l>M=}t>Tu{hJ41lfxKS`}*33JUtWft-vJ-<=5%U3SZx=oUlv%L(TVdG~a$Z0vkN~ -xAS4`+MC3!6phPe(Ln;K}rl8TG%7?bo$4|0R_tlU=%3laLpovFht3Q=2=RhwEG3?I){dwG%9eF`%a<+`|v;qOl4qBP-y$g`BV^=(zhbMRyk9aIzS}zO< -si+akg=8alhOT!O+7$25%y^5%>jMz2W9nTGKz3(Om~mG^lyhTb6vJi~&qZW#b_hB&#CcTa*5@v)Vq+L -?Iz(20lBVB{;!u#dqF6dbN;iIx&6#zHd7hQB+!DK*&f!1QAebouG;9MD$ -TS2ZoMkV(G6ZZ}C1xSl;s)Yl#rk($1n%7MEO1KEVrD?t;8VOer50U7M{0sm2llZq^Bx^+}^3hW8x(p9TIBrz -TN-i@MU;#qz*5JBXtM#}>Jv!~dNaY4_c`f3A4y7N~DzP2RSUukvnuJXkFboQ%t;Ce%AQLDL^SCK=w9^ -#~+qx8_M8Gjb@R}tQz!v#}6&2PQUvTX;L*k+aNV24u`yuzK0<=v`1IZ7wE;u~aIt9~p8Xzy&oL)m_MX -0KPc@5CV>1mTSPX}3R_^3_M2MKar>ilR?9XOknpcxvX1?iFS0?elbRRK-{U2PSUx*jvFL;|RDql$=MY -X-q{Kt`}_lixr)wk^IR&tCGgKd4ccM0g(&XK4&JOHFN(GQ6cy?Z=&+oDQBD=#w8D9K6kM=~m+5*K3`-O@NZd%hfS=S|) -~lWxJMl1;60ffXz6REMKVd&b`(;L-h`_iaaUidg(W;v(9#0ths0gS&aG%y%G1&p6E{2nys%Pdc -c#7SP4y5T5}5qs)9iq;!S=}YJtGrCG`bE@s}?UV={OXxvwrtmO$vj%C2UpS5zvVM@Mx;D*|%`VK|jyw -%oEVEkfQyFx`?0(JdD5wj_a4LN+HId1_JjFjfZb7VT*@CZ!QGC~HijD4KV?#2b*8Mgd;f -Oth++*f*A?RiN+3^lTjT|tY#yZH3Uj>MgSd|2F#3{FPhaRST~aH>UBOL@9*duWwSo+*%Xi)H=G_uhtu -c<3B}>b@zLqg$*4P*U?*JNT&Cm$yCz3plcVY3>6jcI&yJ?E7pIVm$=%7z_~r40mayq0rQ$X#4qrvnXu -5abSJB}y?)&xe(cz2fo_)Wkf*hUTz9(ZcJ((S!&JJHV`- -@E_T?2mH4m>nO_zJBTKzs?fDC0|q%5Ip6#@?~_?QZw6|>rT@)Y`F@0GqGuj4!RqaU|-Bk4xoVTLyaD) -XxDcuOf)DPADq&l%d=l0n9LA%y3Q^0=IIIx6Q9uB)Ka4kw6?Rb3Tp{O=!+^ShQTDj6}AwI+zO!&!nJ2 -Pu}yipD(_T$akq0TIRhx#O64JPo5Aj$ZX85h|Hp(u=l=J1$HDW(5S`u{sPzFga^0olDvr=K7{TkYxTVhqAZ#z^-0D->sVO@v_1Djn>0#> -8-CS6#_($0Qzdo@e)n-&W_z*t{7<6(!}x=6J?g*`Kp3Qfl7{7rg*H@=45?sqQ3^Aj+NoQ -U{$J+i2VEc39(=M_~RJcla)VOmnopi9geCZGPtDSgkV<;L|8%d?>WU}Qt)E -pLUzqLdQ#&V1biUrM64;`iRifJG0u$FfB{ah7ox6c{Kf^j-l9p-I`^*w+An{6&Vnu=hMLxM0YCb8V8* -x2hGUma)iY}O^p&A_%@!^pNcUM2Xehb7{6|DClzx1*wqGl8-Bwix%l~qv3CQd{HOhbFdU85ig -hh3eae#wSZl&M%)rUB0{cK6S6eBs5qMj!;;riTnEniH+B;)icmG;vq7zaPe*u4lrr6V|)V+LvXYEj^A -e;*dGa|cmShS4Dr|;f>eEtsX^~VeHYK)g*+LWMt!Dc?*D5>kVqv_Exf~l;Os-4~`*VGoTv_{N#H_aC! -_z{DqW#>ic^ZYpQ0WdHTw -%H8c{s&M?0|XQR000O8NLB_@SLWJIMHm18zFhzSBLDyZaA|NaUukZ1WpZv|Y%g|Wb1!yfa&u{KZewq5 -baHQOE^v9pJnxU&HnQIXor*HzQbX0ykS9zPOW{K1 -Oq=0=n^{qIWlU*)E2MKS!`4X?VUD8wqR(?;^gkJe4KW$ms8I7~N)9zSC6d0Fn3>f5&>YxUPREpO6Q!R -?=I)##t!3uzkukk$xO|N2MW!gSI?|9s!oJ&5 -h~LLvraP}?8rZ6oG|FS{XNYus_ho&zGQDo*#hNLZ1AdSswM~n=_%u_keNrP??j&S@;(1(rk={%q)yvS -!ao8%q<*?ev)ista$$&-3t1QGj+*L68ZZ!L?5Ut -h@Upp)OO^rHWN5Qw+w_(vnQF2JEa2M%yx}e4pU7;(w;b7+BnUQP=j?KRm&y4RK79NLMVB}5RLgJ-J-? -@CQIeGDmL~~G!OO1QyeZcev?QUqG?H{F+vaM?oSzzY&eupOz#~FPi!()|Cn)Cpj789N!A`zmtEwv0D_ -U0g_}_HSgA@m5}UhRdS6Mu}=;AIxTQXT -2D-m5~#On+j_oa^jG4SwJ13Kh38l783Xdh#6#*N2VxK-;ce3J51nY>Wl2~@4X-PbHyH13$$<0!=2=Vh -UxLb6fqKFEOqz9T0La-KPuGCUn^# -e9l)h4*I6T%IDMn#p8DqOPu*(Cpo*ADkRlD&peiN^Tv$6dPtqoxO+ONOx7YR4o`n{0z7sH>?ZiZTukIaxYv@_dzli&$(8!`0c -0`u~q!<2ok+@Tu1}%fP{9cuyzGVk%9=&L^0VlHNnOKVqO`9NR8bnpEuq6mU1@hP14(OnHqZ+VEjno?? -@)1k$i21w4N2e%R|SXBL9`??SZudliwoIS6ahN96SqX^E=y>H<)C%ZQ@;E~MFtltFu1ZslR(MbF64F -U%j~Jv(^9xM^3ki5}Z#n%&-dg_we~gseM&skL4v#L9A59POmzE2Kz=F7TvW_R=$BoJqHh<8q`NGu%8! -m8!w8ON`9~H7*02Yn(=^##WBIWA5w}Ov#Q=16_#}k`5Ho7mL*$tt+q%I%iQCju|0*6Cf%EN|GhYIu(Xu?Bn+N}LgS@6tw8on&6N&IYCYU`s6Q> -|5MPEUK(Q-cGgyV9ezoxF62ZOqP?wy8=M?wwW63x8%bD; -pPO@d@Pw+$Pt2$Tu3r1IldS#8Qf8rJyjLEM3~tpyO!OI@uD|ha;BctbL_Y1plcDe&UPuRt#sw6jFG;##L(hktcwvw&IZ}v`rS4Ek -gf#x^IJ1Do_t;Y;Yz8*uq+fL8 -WfLkg6Lc}y*hykWS;B}Xpb`12g5WC=FCPw;(Wi{Li>7}>;LvRl48FL*gN01huh;Pz?>z3HJ8h5GR)st -Mo`3e40(|IMq}+PHBDWXxz_X^yEmqO>jB9xabm|9>j^bgqH+Ig08YozX)cBupvlt=!{BKn(yega(ltG -B`--Y3o7fdP~IkXTuYcOYhkea++|h>P>Sn!N$2#L6PW(V;8o|KDc1ur44B}+IOTNC641OGly-db&DWDfb=PhqHRX&KF(o#v9=d?kHTbF9{O!;P -Nvkf2bmBe8ubxP{)H=J}TsxcIV&<>rIOa**^Ye2Kq7BZvqaOX(v0%D>VK$mFNXi2Buc481GEw0MInh6 -@Ijv*XxT8YtKw4Q%5uG;6b`C>mQaRuAka*Bcv^Osyte=31wcD%gJ4z+z??|i9*Kwa7UQ5LLy`(N6$hI -)r+X{)no^4R;&CQ)Got;SSPvzJUx5@?DzeF6kpE5n(#mSp`FK|vW%=xdaFY>$wLCbOsQ&eq*>pPKuy( -|RNU`q6qCR5))&nXkOMFN-S8hpoB+iq1(DJJ*S}d~e&I-jkYo&>s8H@jaohY$qCH3>1M=ptZM5imfQp -#)$R0Dqz9FzUHfBfj^a$2Jrn89#Cjb$sGXG6V!m&() -vZle}hR~C|{t5Q!^M@L@;I;hfxx-_6@Id)KS+C1j(4y%?{sU9CX>coxv5UUkV4qXgq(Wkg_RSXD1jLBvx`J(>3l-U|w;xv!NZoV -HZ~8GJry)xb&0{m^~#_10=#*j{zYfM0;e>3vk*LNc1kVO^Sh^9f+wJrfW=98G0{qZ@3n~+!8%}&bfMTj+cV1FYr|tUiM>tWAn&JY?d;v*^CKT|9Y{z{En?(P2B;9FzDf;pfUb`w74Ca4*g{cgudETJE7*Tm+cJ{A-fo; -vXZ3dk2sr8bzsVJ-xBUu-srB`GX#=#*zwS8*~#{~wTIOB)_9N|@|J(C24FiATAMnqK)4`m((ZDz$*N7 -R;18HpchJIMIT+D-cTr|%(1F$krU%;{|j?#QWE+A*_omsVK{%nJk@eIE)S_Ae9#PpuWKP7;8(hmdaLE -EYwovoQKP>!EA7ywGi|I#GM3q6DpGwjSSgtA1;&&_QqoPa2V9eQBk9bDXHHI{O)8%^g}m@F?yC#)Eev -CAcRiKs1#KK+>L^V1#{NHMv>fHaOXGaCRwY+*IAo##Eq!k$sJ6Jqk-rBBTAl;vt|xO_SPElR)?v~e(1W;GCx -`s@XB%{ttElQ5r)#b^8`_cO6CWVRmu6FKd2y|edu_zTe5YN-l$qMYumOdNZom*Yv3i!pUwN7CAG9XSD -zfVUof^&RdizqdG@YqaNtjWX+GncN?}zMC}Vmj37w)~?c#fiicl7@+t;vEzj^jGtev*Xs^Xio)6=h^> -o?0_UrNKsyYd+pmqXL-4w-fePfmZ>y{u~roaoyuR%3W`$Irr+BPg8`SoIsybA2FC?QbYRDq?&@C9M$Htu(8{92TO=c7X=0oM0y#AQP -Kr}(#Id|S7>!SjifU-@DY;w1sO-w4oE!tsWA9s?Fx(dFEBqcp5ZP@p3l#mg5=9Tw7xZI2}2$9mM4b2> -|?D-}hfz3Xp2UyOZ;VWIazaUeMC-C+t01KQys{_k+&=j!3rUzP_vQ(kEwP0mcB21K%2frC{>hit*+Xh -X*6dE@u@L0)i*!&EGFZ=Gne&^;nbM!7|OJ@WDc6SGx3YPlAN9(1_De_CtvtWneTMZuK61+5;cPu0~H& -|V%i)ZU>uwkvDdHt;^I3=ev{evR!Xh%cuQSYhxuRs)J$)!2T77c7# -ID9>@UQ1Lhh4@tgIpn2G=SANdIO^OMxu&@Pnl?g$@>}g7kpIwCw8aWOpYlmS+tKNS(%LVE$%+D>N^r0 -?2Uex4>SzE?lK?ByHlmK^r-ybE6p}Q3*}H1b>Hn{OSEA-Z0cP!erLy}#7L~^WmX)n&LFtMcpg)nM%;+ -fu6S-KgdBd>={=n=bN@4m8e7?Z*CBau;Eu2D_HE*%Fxv##&RLYW#6vHGD!s_c#q55ka)i#V|?CipmrE -%*iRijE!bl?L|2S{rHTvoFfET*$zzbBBx$*Op4IJW}IQ$h2*>9+DKb7wjGm2#GpOf{HYvyM -?((VP(bhNYaIIenzmIdQIcV~z6KG#zCM^q`s0Yx)p^?TKb1H?(~#&KrbPo0?(T$68{?uSV(D!XwSjYe -ZDI2NMyar(6Eabm)I{V7|Inp{Qg@1s`}f7h=T0BC6D@MT8e8YA2@h#eaI{smXW>q4mkmwTu2^bz=d7c -qzfJtKOXZ2*F%ox3%HEjcP>q&xRDnDfDyhD$a;`U|v)lBB4;4!gtAc4o?Kr>+mYp~>Jp;p(ZVylrF;L -;nkN_U=i$~C`gTqc5f>M#9&$fl5REHS;k`DQq##>S`k>mTJqi2$y>Sln*-*v$cfgDWWgf{Wg3cAqM_2 -~4;3U$WF^o*?|7jEu?1{Tt;P#pFKLzo(cqxUX*T38#U)NK?iQ%lFeu|d&njgKCPr=1GNaL_t`N(Bt?z -rKQj96JoAv#P-@u(|4Obq45# ->9YxP5y{A);CcY6J(c^5Lyw*?eq2)SX=uspM5_R$`Vq7ZK5D(-hZoY1xy;9=*!4c_bI)z%5xM78p -=K>>1rJM2&w}3%U-4O-orcr%Nsb{&!D@eVj~CfPIH)`>lNx-0;y>5jq}E)gp*P*pYyJK_++ve8T8{kF -(R$8{m4kLOpp}Q=!-Cc31CCg_Iqar_Z1N&wo#oejmXHZ-Bx)KFt81_Cw3Pq@H666NIXy$Y?OqXoR0i+ -YXQAd5Vm#;5n%aS;GRyOtN?HPBi}~g=iJatG_Y!>GRwqEJJj={Lib!(tLk@5&LqV#I(9f>>RYz=7c^mOn5Eu`UnMYA -#e^Ow3WrA#lKmxS@kahq~u>*s`yTw|DT5uW>%Ab`|MO6}o8~B;cYYlQAh-ZR503-qECu_=L$EQ+!ufR^0OxSkIkLuia -vTt|wDjNOI(duA{dwfL)>^Z^JKMf^3m1D0a2<0vy1I=wOKk`i1Rts6q+t5P6kFqbrb*lkyc5M##(;aSRW%dUluny(~j5*s?oigR~5Dcfi4mr`0P)9w -XZ^M3k`To1V&BxUH5zk0VX)1H3X!r8s;?+B#-OwCNVJUd-wOZslcwS{E#2CJH&h6^g@6aWAK2mnY{22-1MVPrW5007Ps000*N003}la4%nWW -o~3|axY(BX>MtBUtcb8d97DXkJ~m7y&LdXsy -?|nl`ww(1YVxvCnTH?%b_~y+UI?J-@#44K?x71d~3FXBK|I(9c*Pyx(igKXU?!+S!=W0Js6)`8S34$-+ -DHEBreUSO&bX$tMFAVyI`Cbn_88%sO2pI!)4c28flu&9U|JFM`~|495#UyVDsWu>W=tafFrn$a`6|x- -YBi{tk!FCFa#=9r2@_^b@B${90`u4>^zBB1243?A(46YIqPG}Td8!y)yFDKCzn^R|Ni~*-PNUdCEg$< -N@sk%Mb0bP>97#mm>X0trC2FPB@VldoRI>jMD{3ZzNxiX#Y!g_HWU-*Xvmi{;MAA2R&C1^fe#>!7~?I -XA*&Fmv4K}%K9sB7#`7dFI2@;8+6a{IY&5FIHFgA)t9}6tW~JHWnP-*0?REL-H{6aUO4)vBOm;Q?XG>}&a@K^^ZsS=>l8-%qIh_c6hNXgE0cYQq$#ap75Q5OxmvD!QD9dhxfYD@GV{eZ4Y%dx3q1MP!#7DeW4xHE?C+cPaW`bA<4rP8IU={t5Bek4k93GEl89D&EeLN0@&P|98I^0rXCqdapd}pCkkf)?JL -#PAT)h$dr&oV_goa>Wl$a}fwW>5KUq8>-tHrU2N6TU59pf=yX;#&6SSaq3#Rn^ZljxbD$@kC6sj>^+6N3xN)~YfQ15#!-k$ly?6Pz0!2=RzisV~yK#0S3lY$ODrbjC-0<(;jTfhEg>9njm|H0?R@Nc -`IKa+spS9cVu*kS~P48V^v0G|tSLnqJz6c&TA~Tz9CX)#35OOQstOV9tMbv*#0}XSUmTA+pE3XEvXUA -9uck#*Q*iV$kD!P|opC%ny})mPusv*;ze -l|QD^YKRG$Ja4+!`(`jDjYdhFpWNP6&Q_x{{T=+0|XQR000O8NLB_@2~!GceG~uytY-iK761SMaA|Na -Uv_0~WN&gWVQ_F{X>xNeaCz-r>vG#Tvi_f{yaSd#Q<7XVWy`sGWA8e)GjUCPIgvBTRGd;M3X&L8gbqR -4(wy3TkA0)_Sf{%IkRWxj>?EFDrAcq?8UBJd_QYrs2mL|9s(y_%*ViAfHP<)R*{+`im%NpD31=vNabqp17*k{yeL%Pmp^J8JD8GZC??0fzx4g2_a{1(0K1FY#C} -2z6V=v;;C8jYOQd!@!S)1YM9YUEcH3FmXLO8vjH3L3jJ2^LHMtrSk8a8|%&Ik5)dk-kiPO+<5+Iqq(u -s+}r>?;RXD=u4VCjcG6-WwhX5(zvQ79@z_QEaK%UX>5xYW>8b%;PFf!tdm{4rC`rAr@$&Q)h}@dUgby -1*)a7G$kPJh`;luvV4Ao0odKayZGgdMIWqEN|y1kh5E|(XH7`YHgh)INA4rX{yB(xg6<_LjHVhyNmcSb4yHx|=`SpZm_^H#U>Zr)ah+NX**ts@3{n3~PGoj1B -;GjvZ4;=&@2<`Ag9IFVOian;Hf@6xN(bWhFI -G*mwd*^ay+lFJBSCmcz&_HpwQ$f0}pOxps7_b^-HN&*wM!W{jLeK>XM`M0O=g(v8BOn)TJG%&4P1<_` -+qVDi;4ihjK&A?dO0*YV|Kr|yMIdyy!MCllXYNgRh3ol-Q$-HdsPf=Q7EuJLk-^n15=v_{TotqAWuaS -VM?s6}zvrYXh5t -Pl_*FLYCglM=msb)7a8n$gltdw|N@ -9zKB324R%PZH$O*aQ`ZVBOL7Zv50sbgQb_kcw+rsJD>g*3lD;PfBTgO?2H4&5RTvSB#k51134KCbb#8 -x$wO9F62K@7JZY}UjI3Ni*}=@2qopF_LP9hjU=hU*%=#Smm=f|!3dVzdv?72Z%$kTNNGm2mdDkuSQe$ ->ll`I#e?qVX*6J09{0oO&|83i=~I;U5yOOtVt`EH#Krl?d8-qbBAqLdh9Irc -HxhDQ481QR-f>@mLBsz}$(l~k4rsc-6aY{}M$4$85yU6pYHLt?23Sx>h>&|xooN)IbYEjWC>9t?p0Kk -x<+)C{v9qECnj-QwexuA7ZNLNF0TZ+nxJ3IxPm^f0-fVIaPp(9Kf&9}E^)L)Zu^?omG)IJ#r(Ol%&7I -Qx%1Pu`$U8#O55SB8&=p%4bO*6=09;GhieOYD3_7tFPa3}e^vRP)&z@J`x7>~O8X>NoB00(nXtz34qE -!S^rd(zbLwk}Xx=|M5Q^+=3ImsND6+i!OywNi4=1$653LiFJz>mi;`#Tu6L7;y(U@%cH=;wFpXxZep@ -DGR~xJrwB4Dlf6|1Ju~W!{Rv8wwaiLk>V-o1tb2+2+3h^R@SP&vx6dPmT_VAsATz;Vh>QlMgt9Rgtxx -;TrPW+dALZa8rS4ozCU?3sf7L_RhII^nK9dIf}7Mk!|NZ6KR^6&4?|_>o62oWH1?$M@{J!NolTisL354aMmP?FwQ*VF;R^cOn9MS55W -U~^#mRq%Q=FcmC7I%U_#xRm+H1nNX#36PeAV7&SMu0$k}Th?!Rg8o}S`p95iM9)0>mM-TX#Qg|f{yqA -*G(5S|e{4XW)vPud`J8+6wNAWqzHAyE_`MJfqh9v9jSh2>Ja8Qi~!Agbb(g^lWlO|96S--4n=#-LI?J -qEIG&D9KGV$d*JW3{q4epQyy((-Z^hM9MR`Qg!JwNfzMN`02RC6jfQn#N@X%n6VMYH%@Mj}{@_RufWa -k(%f5Sq2He9eh@B2Z-GiK%}8f{>qMysy}-!OH+r!cvMk!|AHHp|vhoa_I@)%HO1Lvqb)`O)vdV --hZ2^8S!(I$XH-Wv&A>G-Kb^ZWwd~~<;dl@Y%O7juoE<`|uvu=tAe}%dAw4l{jUJ(8bkjB>eX)O9+Lr -6hc7aIg!Fng*W!7Q#?Ar3eZ6}MIt`>7^dBsW_ihJgJwu~5~ps~9GTOjZR&_SBt*gvz;b`K4-X+(Ljj| -5*7nb!pT4{qEc2!{eW~*uEg!$bv*3d})0~S_QoM(J -3i2)TJGsGZZ~`V}vB5D%=AOHMPSr#uYg=Rht^Q2(?ek+2=GaH6N2KOLL=tE~C^%!=QfSd_s$&W9v^gaI~ -jrp|NC|He@VWX845eY#L|VC-^CW?4s7b2Y{#gw<_P2;y$A94ApQpg@%J_G?DGfL!1FM3!z#F>kS -mK@gi95#%jIzTy->K`J2`%J`13WT>(v?L=LmJ%qN*jw^<~xauohHQLHdsxD%Y8#keu^rI%&<^el0-FL -aMn*(ajp#{IZ)G(qERKFHuo+1^k>Z-d9&X)Yy2sxw&H%_il*|?#p}k -$lx9s{3*(Nc>?@K1wI{Fmnre_#BYqdeY>=0s(D2!3+s6|O5r9$7Pcnl6!50RV`c$wN%t}MWHmq!T^wl -AxT+}>T)NqtcYIgT)^L2I(ZY2i;?RfLa`jh6PXU*q3HnFd+JXvyAY6aJ>e818WiaNfpA1zxyT2SACc* -SoF;lwD2@Efj9Z&BSrp7#*$9>V>A5KenWUfjv5Ia8{~sZ|Q3NZ%_mcJ|Oq9OFUw6hi)phVdOcgBH76t -H2J2#r~WEi1EZFz*By5h9r~MZGqwv8XH;wscI#@($3-a8=hZ#B<`HVo{gYxc^J-+R76j*K%u-AEk~yP -K9?jJ3=)5)r*FE#m&&^Vm(%VG0$dsm>x&FIV*AfC4uO3xR`?WD3(x^*YPHEkB3jeM5k;$=}Ix=>ZzjD6#Ow>B{}-RCAbap#9Lsi(2DV~Hyo+wjLd|%u6u -qYehxnVqSt>Z5ztC4RrxJVa`a^!+N=G~fK~;nE4R>8n&FSIs;mPrqj+$xY)08OhlVx9TF}dY0T1CuK1Jjy80v=jjGBJR%`K=2mlgOJ6h?~xq{QdCe6EqWe&DG#8z_+? -@VcFdHjRL~{Wu%vmbBU^Z$wNx#9Q&{WsZ2d|JDR^|W!Dmgu@ -kI -YLi2`nE#n)=*UZBEic~ek{^=so8CX|E4;>Ui4Yb{w#XWg6cxG7h2s~>$7CPR>Hj8yhy@gtGkuZtc@4R -XScbfbaQ2U_+VuXKFqw{EGxapB<=OgGQPAG*Tz$n?U?s*1v;tvGU$f%Hajcfn9W{~7LjTRiG{h~e*kC -!&gjcHd?w2&7WvAypL#K@=r~7QNSMkOF=9=~r}9cCHDJgT)>~C{P&PROX63IN%w8 -J^qXe#4AZx438Q4NM%^IlR<$#Bw(U8tt|7$JXimy%CVvYvzPJOCT>G@b_yC;T2$YS%m6t_jU5E&tCFL -n6W$9%G~b6yvGqIVc!H0}vt-e35{LX_st>t7CjYwx{#`}W}Yto^Qa@Ya$dcFc=M&yP&q^;~1=^SuvhCgUXp+hXMHV}bp|cgwd^bG3=E!LK6s% -^8D91_OadYu?t8c>DzTwAR2drd5+xl&bYJ}(RSpDNIu>A4p!c;g0L~gM -S3w?PrhIpFiKR$|M6%wvm1tiBE%gj1fK#7DS)kEEjPX-;}$k5sv3u|_zKWI|66J$97G+8BgOxn9I;ZCE)J&J#=k1pEHy>SE -&Tuz9R(0Q4lWJz(LA5BBHlHjJL^mH_A2yrM7DdWV+5Vt*ZYv=KMQ;Zcs6e^A(~ooUM>LlaGa -R3`@F9L1(zyAG!e}@BU+`gD4W3hW}>t=WW5)9#FxmM?+#uZn=(7)BT7YBl2*5&@AOR@{0uP21i{3io#oS-o2EEA@;(%>q6dv6i;;!{gT3?(yD%)n+O&Dmyp1( -ew{bI$uipQ8lz1Agx!Y?X%xb4-6(T?t=VOXhc;UduZrxB3hLHXi^iQl3}%0Gw1o8^L6L1;%ddTb!V=& -gel-hIaFp3zZm~28iZ!28qZ8!MBL&~8rav(a4};oD0UW8vvM?wAC_x%4G6?f$;%PH&d-E}G&?&hPh$g -6(D|!7`?|llp;T7Y|e}74N>n>1YO*i6P*w#41+Q4zS5CWtmtZ}lrI_;54~A}w{ -W-2rGpmsK~d^#?UhLrOO|=udGpbe&7Djmhdst4_4gz6dV06DcX&t~j$ZDyU_lNHvvaYu7ZeBm09XI-t -aV0ty-W`c8p1H3YK7?Hdw7s+rMA#$t%9{nRCv`8t4*0<)gaC&!<}{ZMu>}aL|>*4$(E3)^|(2eH?Z!( -@DCy|H9O?;ZOShAM-Ra1+wGwThT1lMpVyw9qY12{o$TkVAQtm?ws3}bhUhZ_=h1J&?s#drv+ZoS>!ur;C#s(wWy5K(S1L-3pX3&Zi?UX+MUFg>Wu1D}YGv8aqbcbH{zZhZ7{DJbaVE%hGT -*(R`KIaeQrcTkY9r~Ji~avlO9KQH0000807zB_Q(yR75Z5OF06MP#02KfL0B~t=FJE?LZe(wAFJx(Rb -aHPlaCz-L{de0olE3G@{0~^??nz2z=A+w>^VaRUvD^AJvGZ)FyL(AirbSq0Op#iG^2cWTzu$ZSAP9nz ->^RBoz0=*MCJ77%gTY{CFc>@#&x+Y~nNH3s@$~VNuZHl?*Z9vjVlOS>f!JiPsbukyy_*&#eCFV*3j8uu!G?PMJjpeKoX)eaabe5 -%YK9=G#tZ;)& -XH%;Z>eVr9>(JF;7eA?8&u=XMoT+J^?hd_)-+5h$p3lZ&iT^UzTZ==98gN#c6dJmlDAwsjABKWL`DsW -zd6Oy9Iz^aW2-j4#n=_n)q?+aQASCK>o6O^vnLMBk`B5gM+QTqurfDv40?*?eA^x9_{Y$!P8G-YwvI3 -*WJDCp^!i=Xh&YnO6&oknIa`+LS#FXvVp>B!6>Pj9H*!07`m2E=J7;|NpT^|9C{>XvYe(0M^piV34+P -eXjSj@*~A_lZ!B!Qb??C#&2!uY4TTrXvu&}cF)Vi$-9SX^l4b=sp2?N -&Hm*k&n#Ij0i3oxtC-EFMdEs;CbyudA~n?;+jONt(ym{d*g;>y6WSKHfNnq7?#-GQ@i1Vtp*I2>vw`@ -CG|!x-O>JiD`ixWeUYvT3ttC3rLYwFie2vg`|NdRG3O9avV>k$mJLqAug}!1#0lG4wmVgQdhzRr@dwnb}aZoZGg6sSD92``NGhR3 -QH2Rvbpr+$Y70?5XLV{DS#tv{etf15o2dIRJ5C5CS`L!6wFu!Sfo~6hNW5f_=?Eaz0HT7@{U=qxwc=F}br{X)5C<;W%$$X-s8GR?2LS?YX_s1jT2;esuIgguYazHcFSy5J^Q1(w8WBsSPu3 -x`Xgq8kqmdPvolob=;vx$9<%gHP*l>=vf0-S{1#wPFI8@<}w{VNEMpSE`o#3nQz$^0TM0WTQNe$V;Z8 -;af|S&e%GsI`AMI@o!>vvs&L0?D+qxAkHNYWE5S^C*)*OB;{%IgjBTb#j=0kb(RAb`3 -RY6190qs{U>D=tB%A@d9gn&3s~1f=7+^2(C@Q)3uqDi>H8jhzbS*-l^3RGnW9ubEsH6AB6To_ -^^3rPUZ=~tv-WP}LRZ7sXdG(Rh=fj&@sZedd-w3@V86++JXoP|iLPK|BP%n+OPKtiDG`ahvWGN4aV#ehmF9>VwNivg}ZKK3UTQ8P?|PP8#M%hnQ%-&}q%c)dP)+t -<+kr4_=#e;8bTY_w0>1n4E{1h^Xp?h;HT0b-*>EptK$uY}(2&oImzXnNa7 -hm(PkW>F%Xz4b^LCL7vHF}^%s&n`4fOQ90L`7S7?VrxGtnp@qgxNeQ=W?*YAW7rFKMrU)5Mgb8JTFV+ -OJ6x74ZfPskZuU%__&`Y)X322>qB7bMB=LfSQRt@Q|Ow)x~D}3vr}zg7qI$60HEt1AHz)EJrxhbeRzm -E|0$@Ra;Q~*HP3L~Fd)$uIFZ;#74$M~Rq@JF>ye9+?g^oEw4kOb*QjiIzqGb3XscuC6vh21STbxvJB9 -#K04E8I6^e0djMoMZ(cz{>j+)Ob$uolBdqoYwbRZ#~q^GBn7?sh{Xd{T0S)m9$5V#6nW0iPZ77C5Jt -V(B@?vX(ytr(QG{ra^%lfu%077|*6ZW~HOQ8chr+Jg4b0RXlYSPfeKFuv3R+psXy6?ZJSY%(ZbJMF41 -mA7ak4!DvRj(sg!<~6Nk3=oltMLwUN0D{11vtl;S;?k!Y4tYap@Mw#XMsQ^j37MZW~a0Z$%rB -s=8y!Drj6fCCWak`pS-U6T{OZ$E5~*FL@pR6J+%#89}bP_qR4SWW0#UoA}PjmwE6*zWmou;6jC!E@b^ -TIfaX3e+Lh_8i<&dvQe}NM(-=eq{7TkUC+Hc$RsK24cWxpUdCBFdWeX~Fp9>V|?$`*eHkNb!E+o?>zDzM*vqDTEr!BXrra`@_SN81ZdL -$3b5R?L7wK;G$E_=vUi*LWKLv#2|?MUM?kQFC!x+=9nuPqJd3&=jOn&+w5kvK^9FAc0N_17(LF8&D=l -4_iX~Ec2tHSt31|j%KJ-pI=O&-0qJr#7lhq^|u$g1bl!(76yDE34yNptoNr=JR`s{jQc -CCJPw-fOoTf>R8xp#}3;k#de89A40HF5aPQ+P!AyHIoSN=q5pVgXCYOuJEF5vn9^9*%wWU7Z#4EFs;4^> -Nf-^Xtp_dO(_Nr%S|v7+bZIjYLf+X1N*ID)3b%LvjWrVm>p<0C0S>B6*(_a6Hj*HZNy|s;!)6*_4cVT -s})Xq;@8A)8x_A5&`}OU<&P`p^z6a6k5GXbH`$0^-CFedM30~Ua>{oLvq1t?l`5}u&j2-HU|i$)X*r- -+pcZB#pf1V!oF?F2?q8zkqt0Gy@K~V_?N!zF=1*v -nFVg4Txz*uSU~OKU&7sRyjn|f8Q#18@Yyu+FIlN -T!yZLjASx^q-?NfrgL`*S<58>ie}C9HF2F3y}b&&vNt -l}99eG`8PFkJkoWfNQyC>!zs3AogccrR1hE!%H-_`fOc6Il@DWy>Bq!=tZ2)ih0r_Ik^G -xuN;fMwf8}8UM^d?L3a^NfgjjLRm -n6omVsA*uKm9=`C3s+Lxmal(<_)06Y38hCDg~I}@%y6%U*78N!H5Y;b7&pVwD) -PI#&I=T=qh{hST_6Q4R&nYy8j2Jk633Q+2gnL#n@Yi;YT+g4=Y|@^S!JDh$BIc`2MmVQ*_9shP$Q(q9 -CILg{eP@CKyb2{92CD{z4`%nlDU=(QpbP@S78K&mdfw{OdflHTHSr9M%-*}U0QL%GAiTx -U;GRO?D2Rng;N>ICFy4S%Y&;93fB3IgVJbT4+;h_<;lO(sI&<0jEXy>R~!_o;_O6z+A(Rgu -7?B^mNKEi&~D)WTz2j(11V?mSUSBz555zzgnJ5}?V!DFcJpPN6-s8;xbzy2>7qq1MgQR> -E)#NP^6o9g2O}&rbzv|kK%yy)mWle%k#wl?&NAOva+-7YC!7d}n4{=82p!du)ih(;Uv>k5aOov=IEVf -krZZ}zr&dKZJ0udc=SOBNTTJmCCdkG%4=E_)md?w8y9zNoNKdmX#Cu_0# -qq)qKpd|&^Gzh0Wu!Molk6YmM%zlk1qeP)#!3VD#J3~6`-z^~4qQPsfDE$H;wUH7n5uUY1IA0rfGSdQ -aaS_qpV$0FpUbKw2n2=cSE$LTj8!#MM9!MOxELAxF-GH8O5IN~*r&g=n8(l(@4U)o%N_3b8v9#Yzb%& -u`v-GDsSVR#pe;Tdsz5tq2{<)G9RXS&o%!>G|aivw+Ng;@Vye6Y#dhWMd2YzyLIqtbrF9 -u>N)2-s%ycyw1&Q616Qa(*ACiH8o~n7!7(;_JK)%wn)`?G$KDEj>ew -U&>p^+=;bBOQ~J=c>2zR!{_RZ)>jL46~Jf-)moHs^!j>*{IpaHxaV$7xezR%)@)v_Mno+_SD<8@Ts0} -V$mgMEDDvR8)C|D7LtYG0sV3qaCCZ?8_T ->!^!Qlx*=87Q;88OJ*T>8PiWOA+P4qE?2B?oHR-vggN7rE{2^9!K=vs^TCJmLH)ZSM=W3BgJU<&VzAW5n29GD& -B|gX%j&vcoV=6c${D{ccQ5JBrku{@LA6!wrHX{u&vk~6Av)~Fah9ptymCx@>m@{arex(nL5INcXoQ;7 -XmpHm*Qay#KM-K!2B4HANQhFdV>>$Bf)VuTf}A=6T_**QeI>Kgp*S_Y#2>zjMyKQ>+!XL99bOxaS|#w -S8F&Udku^*pAN+Hf%hCmo!Qr^;b@I;mTlb1w4n>d9e*e2pJCx>_iDxW(5wlI-L26J#gCWMGAt&!5L!; -MD!ME^DKjL6E>mh5ve_RHj_*C~mSDOX&G&1KQ+vkSk&bik(zs6@I(Cs~=tqKeSO6HkdpJc^JoZ0@{$Z -*CGUAC6qF}eeA7}GjrJT516_>N+G;>rZDYDX(qJ;vjoMV2PCfy0dCWXVw=IFS*LwS3YNCR9#y){ocF2 ->Gg3Ln_==chV{rZp)8i_tOYwnj#Rf=U8WDP=m>QON7Wn;-Tz;T -OUzI}F~=&c<~kGAC7m=dp=vgXkHAb;yj6*(gc}Y%hG%x%Xy}GrjhmP_#+KtBX^W3jXE~l^KS-3^LpH@ -$C_vxDQl|MuajruJ8DKyKbLC5yglS85JV}tv6FCBibT&U!#?jFcx6NM2G3@JM3rd^PWSR}27^BI>0><^p=M}>KGDidIhe#SkYMaPL^m8f@ -S^$<1Xv^C_?eoSpiSq#?&&dm%_YPK7;Q}*l_SI4geh?lg_tb`I4j+84Nkjh|`jiQcjSph+xCA82&Bi8 -dmwd$WiS6ic(iahD6AZdNo4VkfhIx>d+D}UdD(If`#)nU(=7qtrF<626dWAbJ=9HDIW4duo7uF3%xUn -KE5=~UV6GG0(H~e)=BSWqxkbvlE3{pr6F}rnf;^j5&oDJydT%TZ#cR6}VeYu^)7lvT9(28QBI(>f?rgdK|B6=~jgbCM2&3CjjvlK~k5&4% -7W)4d+1#hcIA{>CuM(gWvAMF8VGb(EWHUrpn=X^i1f9BqtwCeMNKh0IEG)(GcH2Zgog#3SEY+jX+mD& -re-??a>Yhw}HKXx9yyc<;MN-vPrlIN$qpUQ&k*#`kTichnnsd-=Mm|GKNTzkhA2`|rEz2X=1_h`^^VD -D|eOsa(H-I)gRioNHU!SbUS1&1J(trY!A$T%NM8#fb}3_xXMzvl`dQ3u-_lux+O774pUf)5X>Biqo!? -arkS62>XFRt>(Ifot}yw^=Y6ulo9oZFlB|zl+-dL=?{hh5GLY3_|XlQG#?rx4N$v9jpMGXGn_4o{l5t -TIeaZhFiP8Cvd8uHL`c!Hz*W!1l}elMwIolIi1Ll}2a(RS-tP&_OFilhnw9m~5Mat=?X+h99Jt+boAU -)DZCYS#rqfD#T36W!HXiJ%pY3@u4y|p_o*kp29NjfSoB(+-Mxm{^JEx3IZMzs3XGiH1p`a`GdhT4KiO -6y^l#iq}4Lb6Y+|>j$v53L8wW1PcaEitqv{bWlRbK3>8RVJ8jk!b1B^!gwboNGeVc)pMDBS9jZq|XEz -L+5cv7(kY+8|woZa{+@lEeJW-som?{m?8)OL@Cedg>g|4`HDDK>ztdfV72wb&b}vU~VqG>0uCQ&yY|& -KmNLAi+7Unt|p8VlpMrBe^)?;*MYUT#cK6Q^j>iBZgZGPtsE>K-yQnml1Ve*8zG# -QVd1^Q)|X7Y8#M3E7E9W?+}qaB;?)(shJZoF^k&2Zc5zsLuHDxG6H?VFp4y2jNcRP!+XshLv7I`vi1k -ximctz%lrVG!Qhu7HZGOI}L$x#sn-kr8}TbB&RHf-k -{G5G;Yo<=>?3S7xV&AHRuOq3JM%hU+2IFYth<3d~XW7FP&q%n>aKbvZ)@ui@Jd1giyD^OZ?%cjk&**Q -pV?jRf_f)-Gp792Jf}!u;ly4zl;9+C%+GD6o$=i?!jn>R#+L`62$t@J&WUyAb=^w0v2g46FRNVEo3v} -yi7umpo+izQ3v%22zRXO8e#f_D4NKt=A{659YFHM;7#-c{r3m^hrb-dP*E__W)oUO@B2>MZFNFd4KQJ -MvI=NNSBoZPF`ub^V5Qf5;X>iH+JmLnZ?9U9r0vjK+M5{zZo^T{#0lY3>A`586?mt0h$)DS?x4#wZd! -`hkKZhY6Cj~l1mZ`0vL2?uW5QUA2pt@`=&ZPPb)E<-+(V4oHq)F)6O0e -Le&)OoiR=k_e%rWn!5%RyTew+qIq{j_J5!xH}{9deJ!1)Hr(-=KRSe&N&Fbsx;ZfWW=5%#;`QVw(v*(5FZ_s5B^dP^k&#^jsrM|fGS9wiaFku%&ht_N1Ei_YuR>9J$O?IH; -HXmk|t#sVlbqjm$oLevwLS8mAFc#IbGty+U%ipSn!)Cy4)~6@K6UAlD0}CUI-{P*6~CP0l*ueK!2G>8YDev4+>#KR~&PnE8NXYK}%nfp#}JYWe|^%ymXJm1F@~Rs++~gLlhPe%Ed%(w5LKr1pI*5_TSZB -V_KBc7bl)T8b^9pyM3=ScGc`u8+)h+?|^ft`=wu==EpsNM21vf7&lzBz~4v$Jq!=GbiG_mD$Z73Ew-m -)v@@PP^!>T(-w~DsSQF)6*k-tg-7|`T8dr4EM(!*`hF1mBH-3*j0*3YI8e->Z~m0lQRc+_%80ip;WPh>Bg~=m|}vq6AZhbbI7 -AH>gkNttD~RRzvZAsI)hiq0IQ#T)N6VqJMc@hIpY&dgX84Qu*le3>u<@k| -Q<=lQe;LCy#pg#1cFFsckA$5FNlnI7^s$)uEMdQMoMF0=RDN{oi*fc)Z$?p-CR7 --}RMhjZER_~tl1z%1yx#M9_&+7x*jeZwaV7+a?zhK-pabOZDsh+e9S^>4rZ>c7^X^vvCyGTf`QzVe+m -DVn_Sz%YT1VvafVRp>Cms|*r_fw -*{V0mS(5EXL^+if}B7<%Qz~hd@GEwBtV31_$T3MGTd8r=1#htXLf{#6z!v=lLNrqrUqKoo{oL34M&3h -9iM4`SrAdR@0syLUlfsP4JxmAas$tb`QBm$^t%M-X&vGZI1@MnKI(*m~K4b`Hy))hk=1OC-L}PWwAOFQjOyo2I=7`zp-p>-#Yc__SSV0NcxH-JZ3!w#^cNE( -+rWz9P -a|%ujvm*wprEz<&s<+v*BNkZM&WGXxhMYb}B%=CIV_tbu)9?$0jWv`y(dHN~t -W9{UoaPN04G>M|_$&P*WdRpq^XK(sXo&YHz{0>;9x%^5NyAzs<*TJttbNqsXf-J+XcS9EDO1&h|%QSV1Xf9Qhph|bntJJLkSs*{_FHr;is9yG@R4x^^uwP@!$$1|iZU$eRjaS!QoE6 -N~pAxRd-bWaG%up}-MoqLpsOowuChdRT^3%i14&W$tHro~rhrB*e0$HQ_w)V;KX -W52!p!qBzZ9wF@B&lFY0Bo>rG4bkHgc#i39x>zKL~}TEvPWO -S@}TW2hQzhAVOn(XAj>V6w~cNAq6tT0`=BUOTDJzE7(LgbL6gI6m=iJ{)AQ$iV**_MtDQZ)oE+Ps6h4 -LA_oBlw&i7yY$E-_1Jm9CB!-w`z;D0j5Ca1d*5eTOs4Bs|rcL1-+JfO4pO2VseSkK^QnD;JH5MKiy?3 -{N$Xj>FWY0A1krZ?ow$qGrNnlh!lLVzIFyy1pC=Pfte%&o^%}flIv&vCBCPtSq3-a4K)^W)+?%*KJua&&2T%NIhrA_i_Ok_oujM4oX=9`PWQ@%H^PS -?NfA-(Fi@H$rGH0`lbWj=VOU&wv({igVGqcswaF9lKWaG*HEz*5FtVp@0cZ(F&cR`gOgAnhbC{t+*3k -Jmr9z1ARMxfMk1jd$5^2?nd;F&ve2veGY#{LH_J|z7F0SC$s38Lxz5KgVD>aqobXJJsmG@h#PRgS*d3R==ecq8mC%%SNV&pnKsjn18XXh*v<1m2nlHq#2&=! -4o+#ZWC~tL3a9}(~+FPvn*g}JTS~`bN>-H|4GpGynGk$Q0$lS7}Egm;B8!V%myV{*!N*&-7&B@aHjD> -9@D-|G1Ep>T4Ey5fL3qG5@9cWEnul0sx_u*d@YLccwX`hdnBu|$*pALLD6l;lCX#7S_qb+ys9=<^kHK -gPyvBZizcfRItRomQ?eREpa=yVv&PNK?3=q5#81>rq0_JE;cH0)h9+s}2YSSpM_;j6H)L-~^f8N_asMo*4jw5(s9 -|ZpHW<}MQb}d}gX_()XjBImJ%Ay7E@pm&l%{18otV<2(=m7p$`{Kb+=JG6kQ@F|RZ8S1{u&f){g8WMc -^X|$w)dl>He~?bI43TdA#{Df)Pn_>{h>qhh2@SVS$YTb5v4b{VYBF^?WK9bjP^6h$?{k`AZSAf0;8~i -`9DNuo7i{MO7qbRV{2i$5MN8wLr5o$ -;XzTwZ(npa<|UPGa?-T7>6ow!aGIr6R-oF}+WGflCBc*`r$C%EDGz+NdEh`M?p@RkR>`c!Q^dNhF{nV -;aX*hhI!(Ymz+yLI2d$7uOQ!=l(aE!L!>M6j@=nDD`uya=P}oSk=-7E^GepN$# -3$Z(s81#P%OosZM>~5*@QnA6?reL@WfK=?8)EQ!V`Ke^yW8Ac+FbWz=h()k@A5)seN$n3=f_t+H_OCH!bd(!Tk5a^Nj5ca(KD;}G^` -hsqy}OVmlOIs+S1`nBo)fOlSgE8&BR(4G;u&u7TMas1%yb9OhA;w`@Qw`cM7Ec(0%pJeLR!d3>wg>iS -41t+6d-}y5>}g$BY%_pdVG`TpDBm1DvWFCzg!(uHLu6tB2u5gjhLDp-D-uS^N|w^XW|W`EE75%>XwVH -vc#z$HoXREamu8-LB_SaiR70Fn~n-r|Jzk>6M#X$QJ@8-JO#+V_`<3Mnk{poJ8DK2wqonf$))jS1aaf -c! -Jc4cm4Z*nhid2nHJb7^j8E^vA5eQkH!#?k2aoRj~6(kCTpQ;Z}hX{%Vim2ElEt!?>QO4B}yNCl8`&FO -fHtuWf|x5WZa7;Ws*e2BpO}C=~=0z0e%V?IA6;voL=5d-s>j)@@j?R`?czy+ts$w#~jmreekE6J% -icuN^$Y@-Q7Skl3$8&6Ql4eO2b>>&tov3vpm0DeDYMjJbl;!|1iPWp;Hl1G;i+NNg)x1nc2&M;xM%iL -4Jy9jHbec*#2!W7NA>2g;L&4tm5Rd5u|0XoP+2SHgtE(P@8K>C5#bOT6D||jma;yjg`n)KkD#pyi=mMZTwgy*XPpUbPL<;jUD@tnDA9P>!)!M+5z2hrPucc(|szk7A?E_(ajySK+DhtP=^0Qt?)o0spPp~KgQZ%%Pk&^A1d4*v?jqmyqBUcI -6Q559w8yrW(|KYsi7cSqlRdm4Rv{OZLaJbZQt{X2N}>X2J|^LJXBuMUo0_o5dEuMfUCq>9G?=pB`mK7 -Rl0Aw7a758(gLPmhk@Aby@7zd3yeKM6ml$L~&c?eC9H4tvqTyQ33C&dYbl&;nu?DjgFXsQTuR0U_qG? -+8TC5tPE=e0Oqadi3J(;1z&7!TR=u@+5!y$zTBMcrb|eqaQx~q}6JD`ibU5iZyLT&ofx}KtM=-(*)M! -xZ+hkNpmL3+;^)bcH0jlg?SnCqJ(9VCGS69#-ovj*u#ZHj1JfjE}k;ETx4+xNSFaH!$k>TqVIuunU4 -0NWw8K$khftmC(IqPBrfw$KZ)VNZB#9RmA(hYP%>U^EMkMxcs{zqhgK^vHP~Be;?qymUQ!k}=@{n=IO -jzfm&D9RGKur6cut+c-Xn4V(7aqAd%`hEo4_Ui2g$k8xm0^7MDD;Se^Ci$$8vqs0t*iq-dM -1bah(KOVyJQNLfMFzazPWM-|N9^~U;lw=8RQ9y>cGwFBjN9`wXvCrip7w8WL(E4ETbQl%DTH|>ENGGa -EJb(uI&;w@2z^AlcSH%UG&%Dy3TAXDJgh*; -Rk<7{>nSE|+nwF=d|0g_{laxO!^V1;A-4p;9+kD^wu1^@aFf7eo=uW&k{nm4cfat0#?!Q_fxwYHwZc0 -ld)i5N}@BmBDC)yq~$2KMyX0(WqGCp4IF+KaZHMrUn$)b2&?9{xjb@XPPo=L$B{D6B=qtrkm!

s%a -DQ6BG(fR<9A9Lx!SgN*(?rw{vcO~u<|m7DB!VTcnkbK_NhQJnfRl9(WCVTqxlPa8|7aW9>8oC;xhHCS -msE>vUIC4`yOe36a~O?)$>A0c>uW6MM+tkc8IEO=rF}b9GA|bFm0&)>oiOZ&^MKzBKc -vqU)`ScT2B+cOkbO6bxAAMIb6xh!dKf=uc)7!LRw>VIP>OmnktzKS-t^4Lk3QaMoSrZ?2G4d57 -#SD3b0en!-x|FX`Gs57DO;%yBaf3f$d>7fwQa`EgWNDr`sCg?vSO|2L0oN4uQ$|6>z!w1OhgWCqo0CP -zBS6&~ar0WEZ6lmFcxL;Ia&#&`B&wXph8W6q#XfM>r%lw|4tq^#9PZ9-pSugkL@0j$XsAv%9^!9c^## -eepQ@?({ho1t|dr%BAQyFK7Aa$!tCyUH*B2?6P0MERGUb#g|DxPv%dlc@YM9jeq(HtO3tyYG54f8&|1dg1P8X9t%c~N8v;$)GJ=(nnKTgEf>5=MaA5D3GO9sxa>!Zv@2P(S@-UM}~PNF -}nwV@oj8?I{S86b~B{*p(7IQjC(>JUXIRhh)sp}3+dzk5|6R#!L4RV>+2Y -ONioHMRZtVx+1cA!EN#JMXHJuR)@Rg0JDUM8_WavZBMfAG`fOgyC=2i?uzdVKz|txE#X?XZ!+WD4dyr -^?St-3|tMn;EE`WZ3G)DHp0h`T^!iP8(?{XA<-&R4W7_u@<#Eo6$4-~*DJpVJij7==s_gBjkX^UtuIo -L8J4(=Ch6s(Bw-u*8owsK<^k(;?e~47cOb5ceK>&ayr`lG^kOCH^5}HU_ybvNOK`@CcQH2 -4Qz;bFZ{pi^eqzRVvZs07M$j$)!n%f*~(5K}h>B($g6|in~qb!t1Nsd%U4FM~J{z)q=hPi_oCpSq}%y -8RfkaV&DF&-7b>KH__6A|bD#OnbFAA@;uozSs=lErjr;YNXhu;$>XsuoG~;H$@s33v?sOJJV!q*zoDN -nH9^h`aJcO9vu6py&?cIUt>m-jx9%a>zjGBBdh7B?|CH{`neF8HuQZAHRV;`Z3qQL&&1ltJ -e(l$UVQtHp&SC~4rGBF~o81y~}JXgz|VBcY)$a-u;PE05SXibT(fOUKS<18Lu1#>MA2u&~#k4O1+Goc2ONRhwi|yg2fk*$h?Zur@|sJ783_?d -07Fn2gnE}>$*n5G;~XMC(TDiDe6Ex>I)x;R4XWqM$p7UPSDaB20j=ku=KH0Jms$bQgwvXX3`s~K$8e- -32!WtpB9=^;${WU>CjX=zu?-%Wh-1j*6!wuZl8(Pue%Y|Hq>n~{S4~ -t?oek!StNK%AV*?6>ki?3p0X@Tg=d5iVJW=uJ9XR=sI#}{A#ijWdccI-gG9`T4z_jtT(&79iS)z8vek -5ugdUOS}@urv`<@Ae{7WfsVQv8d$4f=~1^qYD~y53~`Y>7n#z4-N;;` -YY+>_=oh(ZRss=t7NQNGP@xDdQ;GE{yIO%sfgA9@sDhIoR9eXjPHTyds%A-InXn}(;-RLP!h}0Q(;So -Ij~d)#gFR+^*Ys$UdHn{vq}aU743?yazghI?U{Kh(Gee2Rx0h6GR5!l{$jI|7QP$b%=}YVE(+w^b=UTHz}M~aADLQHY|8Po~Ro6BFkRjZg?u6$;Tp1BNuh;oxrVRVA|EM2nvw3pN7ql@N-L9Tag)#-SNwaH!4bnI6t@W}fS1T -zzJl3(C6iEHX8uyH$~eE|mu6wQAS-u~l7^00ghA3GPe;W#F<=)nmy&RgKTuakegkO^xPx9j%Zkx8;k8 -UJQ{bJa$@@8Qdv4)UarYF?P49sN$EtOx7F&~uZIR`H-wrKY&BJM%e;v4HWnL`ob22oP -)~4PU(-Bgq&&#ls8p-F>KWH1&9M3c-&XpHH@_Ap6xw`@^Ak>cnoFSN@v^W(f&T_;Xu~H5=uOJeek!z( -VJ7Q(4WTdtMs2Dh~Q-r&nUi~m;4mRbydO>_}4svk=lg@3zXO8fzrX@Wjo&?;;9<(1(G-jGkgo5=2eeR -N22Xm$n7Iv{l`ifjIg-wL3#O1YNGH`EvCIFOY&Y+6(w1u!Fo>cMxiGcmxQ(+DiQFab%__RLz^lETccu^L!t&}d0ana!-CUIDm=8*%k6FPRl@V{fM+B& -~9$;a8UA046I1rOX@UcrDD6Vb}VX~x$yrh2R(9_I8fs^$>kaNJE5B$-JCjV>N@1LBF?#qe#7ns&MR{T -U8p_`5=IbatbwLe^6l7*q&J>gTB6??+Gj4w}r56px1~T?>q;Lp{}?jaixu>JxTDtFq0dJ0658NowEJ=2S1D-ecfCX&&w8r>tyl -tVjM^Fy{P@e4~us6C<1Ar1FNbt2mW-nySKG--tEHQ^KKAn7G&63@(Rs-#0&&VbU%#K6j_3nt5`rT2ZU -9A92Yw0ccLC245Y=uKpWw}s-LhrDUVvfw2)^B%hDW+`%e6dbe>36sHy;7g{-R8uVz^~@7PPBPVlw<_2 -U^xpyLh@0UBp?tlsswPu*^f9Q9rtB1O~^rMaj%FO!^woYUnDxg%Z_bUI5KF&TLgx9se6*<6R%B~0lcs -YWrB#A{zQAYcWD^fdZ?FM868p7x>^n&yzL1uNQRXM*X&iha2`<@t}NXhTc3gs{AE8ilOK%s9<$#-LhG -FYw-MKWhK}>66wE?Y3y(3+q*<{d=U=3jS+<-Dbv3(+3Sjm-8r_ljTPg&x%UVP1l-lYzb*@fVKXa&N_D -6J*zQ$MsZxwI1Nww-!YK7>h^(_1{T8c^AUu1Uexr*)hJB|a9B!86ti#;_6s~K(~D0(LFpBB&)Yk@kH7 -fxt3UklPk>O7=HWU0c@(t{o;`nY_%gm2!SuDHJt-n>Kcccg4;K}lC|FYH{Am|DY~)?ia`%5M(!4X`+Y -7{u^i3DTU0{Uf$JR?@$J1r~1=3MiqUua=XNOZ_e3|UyZ5B{D9((s$Z!D;uRw&;{F>FzPt*B|N7@=Gcw -Qyer8p5mdEu{(8O}F$7+hEQMAaKw|_|yl6=$_YwU{Jyvz+k6?xCFT!Mxj~TpXtt-pAd<_*k^GENC*U( -xlKH%QiIN46h#Kbb&1;M8K=0FNS~z`U_`el^fe>u;yb*$Mxvv?SqqqKjS@X@u8UKRj7;6ilyGpxTY6o -t(oz8V8z75E2>^IuPM!_7iDm8+M-Q`N{!lE((BQr*qU$7?(LS%h=<)?`=2PqdGKWcA(KRWo+A7tTzQm -V6pibw5K?kk%deIE(17?cR{x)GphzV^!>8p)ZtkH*}Fp2Q5Ga*Q6KvY=6XVqAV32~-{Xy@gO1!`MFvS -if&9Qd~xjN1smu~j)x1PA98LB%6-LyZoXRQ^m;%+}i$Dv4$3`R$C5;ms0HKDO|blO{HU*%^_2Bm+dLm -@Jpl$a!|}Ix$<5M -xTx0fYiZx+WTybu3#Db?Y5%N>f?YKwV*7N2TREerC5@^z%OKvsldI-xmW-X5uUAxB<%nDt1_m!@6BhVl&cOU4XO1HvVD+*7;Rg+~#Z-!G~b`)|cIl*s7b_`dZG$n{ -8Gfw@ZE0_H^fcNg;@g-i=EMt%KSboP1yKJk-_311*$rE|ap=bsSmnWYwx4zul=LY1Lq=DofH(4k+4YtY)|~ib)^jkp<~ -%X-^*aZE}FQg9)D-w-ouHcgl$W6%brG8ZStvp_=cI8y_9xV5lA`^yo~?%gmX0qtG&kD)IFoM_=7n)}z ->pt*+BanvAF;`a+x)cxV<@h8Bjfs2QE&rG`HU%jA8CN-TpzrvnhM#(;eZi5~jsB3>mmI0{2# -%%^-SU<#D8=TMm3(6-WyF41i!#hbfyl9FDBF#)ZS7m4H5dW`3^+mv06mfYe(IUb4Cqw-8p4Ip2ul*`C -8USbzV<#L8tf=19#z3*z;ndfxzI8JtlX1@ZV4d`3htv6mzh?#wkQqA0k4cOp?6F%wlJHAqaQ(wvU5zq -&`Ywx&%f~8Lu$kvqz@yq6&+ybN2zEFe2sk(Aqm1sxp=wUJ{DjWiUOL -r-ZsARk<~~aT*nbe5E+;v}sKrfxJRiTJ-Bp@jM<~CG94NG#gsG-_#}#6*nS4^qnDL<$gRK%b2?%ta7< -*qI9c7X}WxWk98?GD;+d -t%OKF+G!Q0M&TUPP=u1kw!$o&0FKPJ*XFwAs!pl*4lIzgAY`x@#D%2Gt;6!aY_Si`DTT@xIS->kO11vZcF>MV$_m1gRWU6adn$oj~`|Ik!L1Kc5bPsJ4ttJ_r-}I7Ry+ -5w1wE(xWAD2eDue90V0QQeb4RV ->DMeh$1jd$o@lChltbHU)3g-|+Bhgb2Ak9IFgfNEW>y#`ahbmi2TSUQ@QaYq~`X>;n*Hj^6ajlTDdvu -bpGrhQCiCF9-N*!mciz7ZUsF6FPOzdjzc}io&MTHV)DJTmK>~q!GzSmoQw2&UhEL1X7cGS2cVNC84Pp@qLFft~P*7Eh@jI}TF#BjcSkO=3P}t7ry=+5()Y2DTb#i{l -xPj-)dj;!TS*(H#!ERxzM=DulML@3E*9qXDV!JLkip6^X=D)#_KPX8%cPqA)xi4khBnMll<@D;1zhTe -xp2KFwQPoT7N|NJ$TTr?pJtvPGxP&%Mhd`|~Jjsy_t@vE`O}~N^!d*2=Z|;Xws0|_UohH!O!9qPa=uh7 -n&i(ajFiO8hf8-7z)Pp~HXdC12wT_t$-Lp+ -`Y5&gi>$>usr51X2&pHX82vrHHdD!J>l|#!Ihnb*<}{B6n`wRvq6y3py7wHjDo;#!erK*)tedl75t^jtP8pgwLm21K>h`KRVQ2X?td12DWh)KR0pYTg_;R=LQU$bP6K2*#;DL}`W;l?CXjM -kbRf_=s1V`HmO){(IN%P#ZJbQ$$x)Oz0s5Xx}yyV-!*3ZssR-<*4=ynX~Cf(Xv5)kOT_?i{oq1J5yX_ -amdF{$Ue>7e8s5Tpr1!hpu@22JV;1?ERJjwhhzRt?xyG_t0Dbqj{Zo|{fJV1W%7I)6!);%tQMMZO;4V -TQhMJWYB#-uUS05=q*lQwMCD7@oUs32mKI^(5=lY6IG^1#O@1Gn2r;YKvY?vm2;Sk8# -4a$(nJZ`M682IPDU7&}y>t1xT**|{0Mx8F6kN)l%m-=xNY-Q!F-)T5a3;hOHba<#uh=x(wk$WtG48{aX+Rd`lNQ#tY1fu_PO_gsyMIMGJ!{X)2`o7nCFN+ug9$ZPb#0S@Jo@I*a -hlg+Lyu|YP#!RgGsHv_=EYE*AFo6)?%hwBz-mdC|iMf-3kz@CxvjyGvZKF0jec~z+Um>MB}w6!?m`ihz{)VpfVT3w -j!+j0%yhG^Gq`f>+UUyDT)l(45dIfjeIO7N`9G7gpg1oImJ1)F9yG(px2yZ7d>20m#@QY@eL9e^*mbh -3LU!v{aYe3+E}DB$OI2zz+OHEjx3R|1KG<=DQ13F|&@|2u$uifxNn4a+I#P$otFZ|n?k@tgy8%?!?;k -%{0I5M0Hg8(3mNt3g(NnBc)NjKv#*T+aKy2qr{K#F^zKxeV0q3edctVSUPCxG2^DSzC{cN3PJW@~?x) -*Fk9UYAHJsF>M0|PAY8HbxS`YT~}ed9>-!6omv97d?QNzth!u&o|lu~?loZy)#HOD6)$opx$kNP%^vy -4$ea*L7G;$FJID>07TDkysj$1xHpC*X+2;CbX=YA(umR%U6EDP6S7Hlrlo{#a*$B%!-*v7Z1_X68=2AzQu2i*6{C -07UQfrYSf6i2)a$~Hex|R7l+D@I~oqNxS9`#UCX%jgzaA|=;ZtgOJEFi&MGh*Vo%{ml}s_O(}+kBDq -m@biaom-@Ju;cOA_V~94vO&Xcn{KOFe34{cP8+XZAd2F_4hwc#uMVCazM|{hU{6CsLI9o<(7`j)O}TW -d*$_UUOdK@HVVfhyg3HA5fFK+#M60Y!_uEmYSE6KEZ+J$C~S?lmnDIyR#vg}O#v7niLgzhU+X+m`l@Z5cxXb)+CIeaVZ{*$10ScT8WfiV621x -D9cE-4pnZ>|Kyd0@zWRLu8zR~-6bS@g(QXqTBcZ?1#2SmaeZkqItKu0z38n_4`rwEjBod(Quw&C(F!v -?xC7dH(HCEQvEdSv?i0<}6qUT6yA)L=KdmMzO8&qa9Yr$tOj>+U^zbKV%E0k1Oe#EJ&QH#FEs9!5G&6 -Z8$wqxj@eu$>2CEK^Z%Lh4u*kp^SWhv6T6NRYIg|Sv){bc|R-K33`jnTN_^3%^ji)q^th~N@w3SuY;~ -%4HoL&DoiL&d;l3C~#zrh#d>N=bJc%6-_AIH~K)^4B+?{=A~Xw9WNlV?h4epQv#*GnEn3wljeL)0V8< -Q&p`njg=x2q|w9D*%C~mu#pTxRtlf2fdAkJF_N)nIFNdZdqiDc4XvZ;figCl<82oqParg9x&p$b&B@p --I|$*L9?arY5!=StJIXXbWF2bNmn)lbVJV!w!FRUC-qfQ=VP)?UejRn%LACKU>rjYOaD>GD{hF=J1C{3#Cj -bP-OUmGkifw0abare{?c!p{K6nS_jWK-d^TQ_NPNRpR2HJQ>aE#PHRt&zGK5o;p}0o>5(VWFipDA29d_IBF!OA(ucMTLd??(jBKPFfujOo>jn{|L!sa^0IhrDtu=Vnz -+!kGE`2S7Y{~Y5z@%K8F9_BrH!lmL{rI1*sBM#u_H$CYuA>6ArO2;M3A=OV`QB-dJZuyMnt!#Sb!O~lwQl2Rd=z -oztq>U&7M5B*-BYDU_;EG*lD{*8RID$IfgT%>vami2Yi5XbjHy*9eJx?;(+~FdExD3{P>(M6)SIcEpL -7;)9g`36!B{M-zUd!VCj`99C`m~;(@FIuO~yb^Dm+5y{Pqg2Q~Xh%kTrSia%*B;P2hmFAWR0Za7F!(Q -bUAqp*6$Vj)+FS_NfcW*W?=QJe9^$ey+#@>iI$8^Dg<;kqc4Fw?h9V)li<{d}nJWy^ajptj8om6x33#+qh -we;c3@%i*i)els)lU5C~I89k@cI(suarL*?uSBLE7o&N6X}QggajGgzKF0|s_|7Sx@3&gLh=WDJrdRV -*c97b6fe{!fX<2u*YzZCdN0{~w!|RIRGG@gb+fAW-j?*B)K#8S=jn^9blA|?D>xbNWR6jMCfvagHtpH -lgQ)fEr;NNY&!C0j~a1{hr(L8xSe}y4Qj|j=M;nSB#Q40p*hF8FJt?>*MsEfIjqpZ_1D-y7Y194SpY1 -@*CF@~PMfY|`G?wdK*`&TQG$wOB=0CQS%XvPqVL~bjhz?r&SbTxOL*ks?JPGM-y@~GiO$_4yzofXl{0 -DY{i@F(W}w2n>>UprWnNRf1nnTaNTE(I7?QHP>Pu16#Qv)y3&1Z=^K0u+gxks4=ko -j$Fo6IZHQ*OwJz{?ZgBOuil<5#UatvG^T;QcgvR*aVt!pzP+##$f%5K> -;-?8K)9<}2JXv6U6nVKsk;*qN;-pSvxcuV;Cm*Lj{nmT+6vK|*~`g^6bG3uTaAEiPtQNMfYhz)WH)FVzfcrHyY@>d{7K6m%pW-&6Wrhh--A6SMs>3N#WQCWZb_kGhI+-LSq -T1o(IrcgyN{HutyE{)u3$zBZg8$u%(xa;K0k$3KRE@14#`wQ2{SW@n*XqG>xk?5c;9b>MdA2+42W`}h -=q7uSPW|SA!Pub#$z9i>MC+Xz1QF+U-kJpVi;;rP!+yzQbQ0072?aJ<*#h&CZ^4G6sEfK&H5f -)(N&u6?nXO1J6pTETaV!rJ=opddFJ=hR;e?*0FCp}o^;!af-yzsUYo5MI1HYt)?}ZI8SM6=-Q5~#z*D -QE%_Kmzcb+wC1)2p$*XPnbNRi9Fb9D16!$bdY=N}1DvaxHHA>n1;;b0ruEZcm<>2F8f)`sng>1gHL=a -Octu`KQ)oq$tmUpsDfF(K*>87HIB+tyA~yoyFp;1vk6q!r;SMastc|GRS9iTSpnH^eGkv|CmJ!DD*QFn5AlabQwy={uA)3(A7hZu?QIZ~--(yH{x_l_>`22<~*SPuE@a#Bg+gMi1KwNwL -1Vuu1gi+uT)A8O#vh_+B=FGL%nkEBdV3i|9^WNvEB5MA;^oZ*);X)Bvm&b!O8jPf)Q*hzxY}hUr}xp6 -VtsJ^aUGdiD>^{P+(A3RxkatU1Pb-C`QNX#%(gm<5O~UTSb8RpHWhuetGY%(A6N@}2+t`p>jh^Uue{sOrxsKtsPMFF$|$d6r(3ak>1QOZKnk)9mSR5OK~F>vBj7-(yaI4zjoM^?Xy -1~n%Ef}q(l8X_3MFC8GE^*Y%W(YmVH#SLIWPH5aKbr8^)|HN|?B@e^P}x!phv<&jd=TC)yp9Ka1KI^=D^oOa=@vE-(mbdxSs6_z!dy&07Fv^=pv!4!&$MigKvMmFw#( -(1d12zZ)?d;RTnDuCoNQ0L+U~k=a_)%VdseE|V33y4*XZ0O#>f@@y&_Vo{Egq!tg?Q=#CBY`XWT-Hop -(Ka+~aPw$G6BgoE+1GtOLxsEE{xX -*o?WHZ>`EST&qXQH7yR$UxwB@)5`rj?X8wY?8pmB3VGl1WO-xbmzYFo2A$Pio`iwjG7VKqM#jo>3P$e -NxFX8I`sTf#-XJ2ObK!g?3&c%cpQuUefwuY41eGzB9(ctWnV!h_l`xdWLPlJa7~T*E7)SaE$BaJbbmb --li%9)QU0fiCeIgfXq5)=T=)auaV|x7_OS(H3-=aajeB<2-@l!0>2TuzOEgyo3zaWqjPq1uIlPA`!-2 -9r}jYj^SV}7Ap*WC(8RZE3tSAEUN7d@k_@?DCYKoIs&v9o6SCQ^EQ>mv&wgHN{8$mh*jae4l5t~xt~A -#XmM~@KA}6gcusF;}N~@5Q>SFRJjMybsNT=vqj=_8sEF3joPwXgB&q|If;gghI`9*RS-=sw;+1HZyGY -WGaU#Kj+PIfT@c9Bdlw=HF@Qo$}1IN0#fP_!RKCkd~caLOD@(i*bQ41lEacx{A60qD_L~mC|!6Wn_-DhnrTcBgHt*Gjka9*H8ZmSou>%XQ!&KtiG724V4KY|o -3TBP>@N+eQ*p5GHKZcdCF5F$fV)c6sUDD$ky@ncDm!MRZ-K8_X*F)BF;=%Y^)?a~sS{cU<$NlhH!BWI -s$v>>rig!K9`lx6oBWAiH7Meu -AX>BDq*xnt&TB(F7uwZtw*zpTat=*JKpY()TS?hRilO(u(y;X06rvY~1^7%uaeXCs3_*5&fC>Otdpjc -Nb*(AMP+MJMMKp*1e|~36(nr9s-bIXb@XZ=`lXUn$As<+Z!#itwA8?)OLGdl2?+iuZl6Heej>)@)4qJ1@)^6g+IMJBQbjUlXYHz&_2zq2x1$V|p%7_pOokbFLfKposH0BqBk -85&Ep}&0-fP4W)SiLll)Al2vjkSFD<#5<@VSCVB5EUU_Ke`~od-mCe*kW>t2%Z{-$`AkP_;Z^f&kKqL -f*cbDAZ|~)*DU|*fy?-AW(+*C>SITGwC`8iDncsDNNa9On@OVC?Ha01;gD!`W}@v(U3X{%u8j)!m7czdelJ9RBT;o&%^C3NXHSe(>s5bb1`U{O-;3=;+PK5j67syMwoH58w5y?!3 -m9o*hQ7kKyOh;fvqFhruBG9FSnVA6%}xT|*hOcz`&d;scr!v@+EYD3FKw1?S2~rVEbFx^Y(xZPJAQ5BWq{-ELCWh4Vg+G49Dr);Eh)ZoK}2p3RC-So7c*j)0 -doGo1B+T|q}mB>VGz7rV?>X(e}r&f)$Dp0T6S0H3vuTZkv{ip<()RK{FV8T2cU%I-0=_D*yx}AE)@`H -ucn_D3{F@&TKwj{<_WP?87|aZ+KEHwvbw>Davq#1;G+CzOq;m9Vw;D)9^*6fbf6!Q+ykzNjFCzVx7 --o~I#s$(4PQ|@Yk1s~p)(`pRRT}+xowX?KCj~i#S9EusOz;o9$3IXc6o7>DshS -?11}QD;anw#;F*9$yLKh7CIS~h4(yhKf=M%m@SV$W5i@L-*zv#~|2B^dJMOQl9=(n{azd7Xul7Uw-Y$JFbNg -Tgs&@nR+I#q_lu2*Cdr^3dF2BgH^WqjZcv?_&@L{7dQx2p$Sku+wg3yJVM7jK2w&TSNM -LVwpFsttpa%OW|r9JAZv=qedqD@8|^Oy*l<0w+x5h#oLZF@K8JRJFwH>~V0J!_IN|eny=Mk^swg;p!D -`anp?K0>dR>FeY2Dj8_c>SPa@}Oz~KrXbrfd#IY#_Pt;6R@%RR>`Q-pjajCs#K?a#tmtL3#?hxA0C?k -(rf2MJH?OK%JzRl_4(FPxl$S?;QUG$Jq)@U(Zpf$=(f|nVX)F;b=DCA{C={Pvbi20Y;(+ETcIM&%(`> -ICoVKT>c^R`SF9knsVH${pDrein>#wbTB9VIa7xB4d8h4z9j1WwDPFD`BtndUWzFIFLGNW~hw(Zb?&(OyJx -wBQ>$e)@ip4C^muKNMp@KYFqQP=G}bqn+*DFK~y{UcRlr__CqEef=>_1Y3Gt--P`r<9c{Mn{Mc@o_PA -@U!aZc=&LWb{}Szf`PJ*zhJI^b?(A;&uxc;*>dP-5e+7Sczxv}BkH7rl%dZ^y{P3qmdJ|_zM=A%>aEP -~Yf)CC|LQ*?F$48CRZ{hQvP#IiBqZuwg>|oz4Ip?*vh5Ng@69yWKyX@ZI0i5E>w=KAFc|r<;cDBg1+h -a|R0T4EesVwjRdNgX+GnGXQ*X!Rn@AoKBx_#$~M@6&U0E@5UODI5bu{S+1SgYSnNcHTw7B;OYafd2j( -)W9v?Va7n{eHh2bugJ1AS~MM_V^-vZ-;Ka_xw!NF0UcPw1oazAJ_rKz&2~V9>HIPJ=ZJT+j4bdEs5dV -cZ;WNxEfy$2K^*Q%e4W`&Y;LinKB+&u@^$Nw{$>;3SJ!WP*7zk`p!s+7Cmu#_k%3s+yAOABd?^gGNEm -0#KDxEIIvDoOw>rF7mK+ye7OqLR}W4wFv~;Z&GG5s9+R_9iWxn`_4rW1&|6t}bCsBHU)%d1Ktt#0LU~ -drK=>)Cm*QNB>oIDf(vjL4dz=c2GJ{&P$duHRIQ5Kc$V$64f_BGaCt|FBgXn!vj)B -~7=0w>KA!n7|;6klAF$xTY}(NF;#zqiza!n<2osYOgZ=N?!L-=hd!)@8cndwmYAS=W!@BbIue++y*j90Ovs3(RU< -AtiTO4{MpqEyj4ZSG(kkZYyrTqOwk1-BEl&fg(tk$EJUM((w(4x&yFg;XR#TD2WU14m~*m&kG0IIIZ -w)Q@}%*G!508s{u7G<5JN|X6{i)VTxb?;d+)_<3i4J5^qPQEa%<>uN=c;$h!Q+q*I{}<>IH;AY|S22o14^4VbTEI_M;@E6ueiM5xlZQMg!JLR6P;1Yw9yXO|3))BA1d&Q< -<xlM6F0jZ3Og#A=hC~fH!W)Gpp``#$YeKD<6BJtP`cdIN>$qEK#xMERZY)1;)6VmS3y -N5XuaD-esthsqZm2+(^DXo2m*ou7hmYrIi_L -SX*0WSW^9c`n%BQ!~G1b6Qk?l!VLDl++65$f4(mCxd$hMJF5BC$-=&<>;L{0ukdWJoPW-tS$4g=p&Xz -n#G%)}YkjtE>~~dhems^QL?-jOssg+%8?y~SUfj}vSRfJ-y(^yanV@!OSH3*nX}TaJo1ALi0X|N#;?7 -8)@7q`fF52usS7G^vgu5*3s7)H$;3z(mTy~D2TVpM0x5HDXxcgotdgu3b#Z6a&m|fDcRPLEk`?DRqJ& -+vclvCJw*AlUQy$;7yuzrw$g()I!>B_|kvsu|#+9pAyQ>yRqPIo1^N&zgFFi#<#t?J-;a@cfEsp0+62 -O&O)^uR;(qrI1@cwXcjF=Ug8K=jAaMNze(JN>~)?jqy{JQ`R90LuJ*H$s&*GaMKseG2T-ZyD)|HK`>t@YzC+Hzi<_ -tW(e5_hFA2`~TjU9)0*WA{ib}9N0=TKg!?iX+-MVNR(9K0Gl^La9z(ftY# -F%G^4OhRCrSsWs_7~TTn;;QpkfRQ3Irr+OIGp -UeqDxeY_%r&TH+g^<cY>Pwnr+xj0goRzH3MNwke4JT2&%b|4hXr;Ci! -945BtOV%*AwyYdR5~pR4a&75KAx{H6#QvbmdJLxYGu=OG_?R+-dj6Uk -B@2$a#=&buuSo0pM@&&_I^Zfg&+3(H^RK`Z&adu7RstmB&~U6jJ*(6yFvrvcJPxq#{O-Ko$vM)mQ8Xf -+|s|GbfYctf=OV6V+q&o1cP4srS@7<8$%v=+CpVn4~Ie9IaLA^_${(Ji2OV<%4b{PT&2#7rj0>ef}-% -RR>2HZW#?}dXeSLXe=i7C8`-cAqj&MvPgqI(OB-~rO%pbzMKDM>z+v5@FnL(FKTi4fR>Dof(Ar)h#F8 -kT-Pk}&Hx!9*Qjto|9-?X%E3=Vz^92bB__z5ZN1mTEXu@M!I~|sV_hpexHLps9sXNZ7*jY1D8glfBMR -7fVu(Ek{?uFWcXB2(D@dCxnH6jhz)kiXq6~o(7H#^wqUq3)#>Tllww`SS6Ql}iy?H|JX`H@m6RO~$Q$ -c@2v-IlmCs>|qo^xkiAO~r3E^H`m4ap)lwfI-J-N;RxHchF!wB`8?hV^uJTF-Y_%ME1HyoT4W-+NfQ& -Fl6a*X*Y2^?uiC1HwOITn3m|UyBYQp~0;QBEzYwY~MI`)ZL+PL!!gcdCm|$wrJn4*^{_7FE!01l6Xgt -O7HH@;WrSNPs;-zL_|iz;P>OBJa#quCyjhT<9X$2z@tlKwA9A|AJhj>Vog_|gqlf1v#rGA#bm=~X+u{ -fPZFqov{}PkKMl+?qiL}bxzuA2>Y)3pW1r3E1>W);^T>lI;obS6L*o-_8$ -?XeEm{YpUwAv{Fwc}w*4c?VSEdR?nEXC1N&gH06+IA8sI13>fgY}KbWuJj(WD^N*gA+Ds8a6v)bJ3=Cq>tS0k_sznbO~Em150@$o -mzd#JJ!ho-Jz|5Vg0`oAl+6Dx>{hroi(DYLV+*9nlX;zoT|UU^l~3OPJ*q`)O0S9;dI=7_AD0Gkn_${ -05|8gV;w8MVt4$(cliY>V3RTH!Q3bsYV?j1wBLylR*c-Z@_Nv~bfE4)mGORZYn{6HIcF;sL|-R05!f0 -N!J;c8DA#jZ2*RywxIMmK2!SUEXHW)16H%!UG_sltqD8~#bD3agsK7ucQ*0h37734u(0oaOmoPAW)n^ --9G+ODvr2Mq;qyIefs}%y{oZru;lfE)|K!F#?`>oLKLAPTv-jZLuzv;`KIu%N07^uXQ -o9h*7?~m?vk>Jg7^a8WfMqmRDkc~#Q<=r6%+oQ&p)rUz2O>VM- -Ph&$w@0VF==IUbiQJl-H=MLw-Iv!|v7v^qJqT-V^o066HXLbIRC6n^+t9wnv$@~(lRTFsw?r&zbM*jA -S=Dc%t}{ehQ(Vesxl8reI(aKgh&wqe;>SLXKZ~ssEGgcaHj4*>Y&*1#Wh&OA`BTZzb=a>}+`iJ-??JP -D9kjCZ5Pp$C_2$}68dviTbG^Y1VV1(~^0%FHv6pRZm3NH52Heo_dYXXM)I<_qQYUP*XVlw`yBg_F8e{ -}}0HJ{^zNg(o9eP_6-_YjBR_9jWpuXF$N7&vuacK-HgFE-y3ig=j -x$$u*B-5y%oEc6Ptl7J1N&#m`{=TaF+O?KrA^5)wA3z-yne<^Fs^DANi>PavMnX=K?s;z`7}OBu<41E(a!_%TZ(kI!5l}so8a5wmG-;OOM$usU0fc}gQTdkkTaiC~@W}RlgvmtT$E}Exifh| -+y$Q_9;wBw?HnS0%|1&(A4-Ds~{rQLnxZ$r6uInI5E`GTOkAtm`6eyL5Z=rO5UvoYx7l_or!X7xNnoK -5m^tr+5l&Aq?A8)59=2WvJ8N&vS#=GQ;4v0>xxp-0{jYu3i-^Y$0I{>dxe5n9mTiiT4VZK!Hi2!zm`- -MV~w(zZV2T96wATEoAq_9$f1eQ_{K%W-Wl^b$9wNO7v$N{E@wcX1*84){%aohol27~8Yk@v!hsT`g#^ -i0fQgcnJrF>=u#3z>=ZpqXZ^tq9L&(E)|s8r1*0+X$IxAa7v6|NkDX0f8~2J^j4y) -oHE))!iS%?x>^lj24(L-2x_lH{D-!uJ#oBQmX6Z7oSZ8TNd@~lI{6b%Eb5N_JsXLD{&6BGVSZK?lxdg!-#MjW<=^w$QN<(_ -g@ZXcJXaiSKxYZ`hrPfsto2=wHbX2o9D@7>gV4GZ@-`oXbVVV#oov1VZy?&DNc;kk4O0x^PufKr;|0( -t>OhxXP!U8n$19+gzK7|@ETg0$Czes+bd$sfy!HP{+M>X5+~2Rt;S?S6vlJu^qSFIEL*QKNs*{+l -o|=pZ56&*0&fxDRNc>M}#%65=1s^4(=vopZ98_0P8t5^U->l{B(ZbBz4#m{- -aWn;T*hm0FeH8jcatOvPZFwbqA|V)c#y!4$NIB!95p`KS;UG(tvJHC_)WfLcDgc~vt7zpG=4Fu}*3CJ -sE%f!Bx|%S&K>4+TO(y!0V~W;nOfs(-0#&fnG)Rim_`M1hICy>Vx53eyQ;>pS?y`8cMtVHK{j0{5X{C -COtQeCZI*dsMBfnOT&ZL4q8IWFhQAus;MZ!VWrJkUEfy6qcpC@^xkf;L&@Nj4bYHbaaD-^`k8KH;*{m -}6&YUgd$bqc;hxuwwCbz;L5JaI&2%FKtcs6_gbmzbtpgHi{4mT0__`5PVmg>(xva(}$s8&w^?NIZ6tx -a;wfjLgv-7-_gJ+p;fqNRZP6Bru9-g$#1DXhRijv6OkBRb}HJCp){3vuga~kJppOUwjEqu78~T@ehB> -u79j1<3IiJ4=uMchuvlnexg3gP-)Q&<-)}c!_E}bw-*9~3Hq8~GwrDTkmul0)c!~NVF%!C(Swk}xL${ -QgMk}13GclLHryKjz)t{3m>d1$AA$1fBaMb%`Y_g&;(o6y^?^Y3hmo;bF>!ZkJ&_@}xw9#A*`XM{q8Z$41b -f-D;Mx1RhV)fzn){X%`D^Tr2T#d&K0Bz8%HBg#K=QnZvKT=#bLO4{(E0nH+lK2W8?Hp52ayT3v4ou52 -LlR*nxT+DKfy7uw(*aV2(UE*Pjjg=vc4}anme^6J@O=yFy@o??2t#OG$LmsRB}aV&6N6H}3z2kXbLk0 -p&yM-3`brvETbqXwxmi=?qf*p~vE&?AM-h^?Srdv!6%ulpC0dF`CQuV7R!6}_6iSwz3U$RGM_QM-ba@ --uVK;5XvLG(p)6!C8vx=DDs*)cVzw>si!ikBH>%U$ZU`%3v_2=n4OFH#9`7GB05Pu*o3P;IL -gU4jnfL1tf;@7#^WTq%!(4@-$s}go2|a+Ua(qFu;OJ=UiUXlg7XI2JgO)p(f8cu@gzEiHeZ-FUt^o!s -5Vcy&1Xx#t~h}sLwBpXE -DUKL6+jh86RLXPb@)^q&bnv7x8?7=oY*DhO4yKJomKWI%8R2Q^ES9Dj4SIYIFTwa{$?#0$pNq@--qyMb~?irM -iFNt5mf&il{+4GmF&}qW$x3PVEqW_omGwl&n+dZI~|?&7o%LJkEfdLzgg$DJgkG3kH(K0yAKbIGZ&J3 -_WNd%Zghl4!hkyld{l3dGV=T)C(X6Ee)szXHV}_18ATxzX?j?cCCQ)9m;57sydXq^603fWMTUEt0W%V -zrQKqM0mu}Uk}lhqQtA*a2_2}J1(Z3E??QFIbCb2Sgkne3CLvnE?hDe<4VjDhpp>e0`&nQ{9kcU8_6D -LXKie&ecp@C+SnF#6ulGLR`rZF(`F9V@AE^*l>oWhML -XCkQhMgP!E(33zbRJw_a@eI1BER=QKCwE|B`-+Zy;hy!Lj$jSvlo}7KkxgKEiwf0=fnW{5;wqs=o%ou -AK|CI7KT49v8kZ%;;v&|n50sB0G?Ai}x~26DN`gDc$HP8m2}rFJC$t+oeA>X5Od1s@=CNeKSDYb!SfO -|$D`zv>zAO`Rld}~T(CbzY^Jn@Gf9Ku*T_qq?;oaf4_@#&Cv$0=DVtQP05su_RtvW_C^m;RzcN$~s9D -0Q0+{1t94SxBZo1$bm?DzY?WZ3SI0!M2+8^mMrGNN{(|AA}d{ -D)}bD(8+^zrfd|&@d4ZQ>vrvIOC|>vWl^xYx+2>ipOauHhZ!6JgfsBgj1?qWK_BAveTh5Z`vnt@nhjD -B1t@LPRY@ZX#Yx+Gm+G9~HOKy^Ef43XNshbmC9s+CYoLMZ>T)Hz)E$@k`k~b_mOYYKGGbvSzi#t=&mZqd$aCa878VZVr(eRt8=eK#jpLs@{z%&E$`vZzuasp^4> -q+W@$3^aE?(dU}{6+`&x!$(|>m4MFJJ0z;YrV&)5Ul7TRVV0%0*~Fy-L~{dB_2iAACM?fw${-WNVKFh -;vnycD3r3&F^+b(bcP)TbH12iis1@Q&>4H142S=kra7ILenC-H!C=RVGPzt}K`X!mUI!x-OM=p!kfRa -+MI7Vt8ll+au_eQL*vUn4f;YFN{j|&0ltxnZC!cyv#dAQ*eASS6uoP%|<=73Jos~e2^TdY{lH&u&&>2%%8HLU)TK -kq-lx$S6tQM-+)3lc9Gl{2POZLO6mgqj*a+32sY>Wh)P8U;4Cxo>Olwveml;lTJ^~Ey?RTNepQprRk* -1NZ5YP+cUodC-FH&5Q(B|OECk$AkoJO2Ho@LgKJT{;TUle4{@bIixsQ7!bEczy>P(c9YD&fYnE=h1Y# -XM4NnYvsta&gp@32*a*=sA*F_P7YULD-X;s*^ugFJXm8H5C$VGRx7R@{2q^3_Ar=%Y2A3{r -`Uw%XgB^B{HNXB~wGCe|vnwQmF1=u)DVm~_PAk8G^VsO<}8oy= -qWVx{%H|sxCe5a0jspvyggW0G!7Zn*W?`rzm45NPO{x?`Ixp^3xwU9#@C5Tu}StW!ALPE$45`su6BXb -kuy;pHpmn^A?JtnY`}qC=aUwO!`=6$V8uw}d=u)wg~|^e1c22#CX7a7b*TGcZ8b3tYGXq<;S?@Y*Q~{&*+mm8T~s%CsD`)D~_-Dat#azP6>g^HFA%z_~S_6DPMD&~L=0A=A7&ku$R5$NGV$T1uig6s5zs>8fKCj2+>IHpIv-{hM{*Rk^#?3zhD;lQf&U60zRV -x~u(|?=UUwvi~&1)`d?`MX8Th;$@bI-W>ePC6mWM&k|VzOqw|GjEOzbWPi`LbzVbw{y~YnmZ_f~gDi= -mBdIQq>n-5)}#P4_l^VH0{2OM@x0rQ(*}De4fUcWhXxvTqbi&sz6ok28d|p2|**nNvv&Kruw>__Gday -nGiXFxX6+=OtPG=B-So`L%SNXDYb{II}?tA@8FJo0ng6q=4zb0M>`y7HJ*n|nY?fy7*HEp@_eJ!UBy{ -`zT%Q458iK_O?%PGYMp8AZpO6NL#wHC`w|MC)u8!{J0k0ZjkqX0d*#rLFOq>wl%uYiQ-PzQD- -|E#%7mM8iKx6wC(Avt5aof*AP>shDvK(LPF!B;X2Dz2kPsr;SfktBXPyGR`|xrKn+|ydHpr_O~xvX7N -yNO#9mW5SH$Hdu48t~@$PKvP6O^vM_DSM^C5L2yu+IhEaI#3fbU3R2=z#u1~j+w;90ODKcfWnNRnG%U -W?t;dti}g%V-Ce@va2oGZFU1W)R4w^RMk+{2JM}TV&OTHXyw_U~k19pxAa@bWuf<+RR^7NtHyb*SG&o@x?p$)&@JaC8Er~9?W&{4QSj27&ZqCL!#`8$( -|aM)9^C(%ChAj_0Jx0vVq@ibvEVl84T?1I4FS?Jf1N`%Aq!!{HcUBzWQnu~2{UTa}ERB@V20~~%C8R> -9{+Pud0vH4<}&gZzCIUhu&V=StXV*K^trtW8R$rq6{Zb+EFltQ8Id(n;@gmzlkK{6bqQu$(9p_TPkt6 -s7yMpZJ(3qNaSLrW__hhf#i_8_8~U1%IdvDa6uy5=s-s_jO;C#M-;4k(?h7Cuj;ltd~h7IWn8g)sH-k ->YDa*JMF=Oytk4Tp^Tuk^w);7U&E}jx;l4r_9YX*&!a!rfz0!^D -P7IP&Zprap42vq^pWrnd;p?53YHmXqgO(>9uZ?z<2)S8A%Z7DoGa -`}pz0sgU)SZI$`Cy26edS;A?k(lf*b$dF1y*-oglHR>CTK-ja7?C7@C-)v<`<9SpkJCay^StfE8*~Br -x|P5!#Msa{DWuW>V1)SxhN@Zw7h`dMFHdQq)p5q7d@O0;EqjLT{u43qLjTLWBom~qDH0OA)P0LsIY4NQB7Tj -08(0dC3w)hx>NO|tm1magnqo17C0rH^e|Ve~00ZIRd@i&1xs-GqWTOW^bX;~n@SxJp&CZ$xdY8 -vG1Zf?-Xe2DJBcq^-hh2MyBF<`$Olbap%T``p(vQ40rQcr&)>#wl;b7o%ur_i^-o`OoN&f7*6UotnHa -U$c+D!UkqS!q9iyot@rJH&7H0X}Yj**pVMdy#eTB0Q!Xo)C4&owa|D^M^HD_JDBzdcKzs!ZZGO!P|&> -{++MT2FGF3dH~a@^_>Y^729USmXm)lGN4|#sgT@23y#eh!-fToWUt;55eN^LL)*AoHA(>Ni5UZ|=+nm -FZ#gr&wycn?`ge^ofyHWWZwxSV;g~il+%+X6MMy0|!ONawYTVZc1!+!L(6rokpb~*6^oai^h;q4gsh! -N0w(oc^)LBSRy_z9N9qwZ6M;V1di&J)DW)7}$6&eLwo)|R3>KH{X0Sjtr(19m(n{-2DiUKHyFl5q<)t -J18h&G}GJL(=l6&S}lB*N+a+A0#g%w~SnbSg0cn58Lp&lW9}sbh)OJ -gF+m|%hp}hTt11blyiw-;-33q -~96WpeqTlc1gspHf#=Rya7x}_WqZF`eTi#08C}2QOt?iZq6sZCQFpxZ!phl6&k=y+%TotC_45>?zpU1wKF6lDD# -dcqA~NNCdN7*Bh|{W2Ple(qn5;XoGWZgd)X$$&mq@+gp1Ife9NZV=DJ7!8S2W(lzvRt-FL|jXZxHKv5 -i~L>)r6bG`3{GusF_^i@y+kEYu?xo#)a#ZMS_*l{C@U(XQ83Bdg2M^~TSN>=#9<424lFb8zeSV!pA$`LFi3uCHpNL -Nd{u<20^fz{!ey`xE?~`S44b+nd|yC+5Cpo?enw};6`gDs?d9p04_!*iK4&8*Pu3c?;}o(t#r}TeYG4 -=!9Qm%Ax43j1GE6B~&5G@HwXc1goa!InZ#5GPWDaw8;-?*4c`oN9^|TfJv`BHSB%F7YxG{%qiQ-Gtxu -U%mzEvvS=$k@nQUpqiw$eN!^u*4b|ep*%-O=mf$QhL#~ -cDA=0@9*lnLTx)>Y0aRnYtc$zZ?I_5;~-6&MtFhOmMtLb6!B!yZsn1!){F1AAGAaIFHB+gVlkabX;NI -sg`_;1#AyaH7q!Ha4iqaYj>1hsT@WtN=4y#=omhm%Vr9yvJ=UthlsIrILn29Hn-H-~&(5c*LNBoaWof -sBW5OIl|A$sA9kb$U8QsQ9$9xSC91L)!SF;MXR1tBi9&Wty@Yrqv;h=1ZH(FkFco9K7K_V1-NcnGCk5 -(h<62NT(sEnKN*hZR<(-9}q)_IoHjg7J~!Zv(L;^BSGJtg;Oqm|TM09xbgW~YOSvKz55#+N!rcg6Eyh -q`q#o?fXUf7Jt2OU6!FFt26Pyy&1t^^H&ZhIZ$~qFHeyuLv;>t(kaFP>q9XR=a2U4*+6seX -CWOc|+z7&i(gIA#mN-*c*3-?WH5P>mZk*zGfR!1oW$vPT)I#dEQv~h#8L5LvOJ)a6H#U0rOR?Di-Q|Z -R2ki5WqFtCo`uBUL;RUuE9oylu!YDr&6`M_yvMKxyUeedAul9(TMZaB0_hqXE+?DTZVQMCr--q>PSxC -Dqf*V%Bp(rDjc2j?Ic1KG&+8DxOVyU6?e+Ou_0AMPHep)o-EdS7g}+o7}3B1bKq7-L+9{N_PG2vyX6- -HjEu8fs3mB9E6t)1QaW57-@{%T89Y%L@aMlc3DAS1li -OCp}%weDvoFb~Ai*cb#S;=e)_r)fp!R5-no@H?=HKzcv7^C_O;sXY{NFS!Sc&;7W1~lA@ -RE@8!YKt8iLka})H~zXG4ah)}vW9XpV%f>p-1IyDb_cyT&+_6(93XebFNQf!y){tDw)I}Z&XNSifcET-&} -NI}_Kpcvj+q%%3q_DlNJ>2fG=8k1`zmv*L&Lrf_&ciEKjDRyD9Hm#OM0~*841o~+XGR3_a*9 -H%X(tQN|hqzbJ{HiU9%nlF-Cx0->5DoDy9#1 -v-8g+H89$XFGckygqd0f_WGNL>Cr;wPN-)3~|h$t~;r;_{jUnWJ@erk+Cy2U(_yH2?>%)2WX&w+cufwO^fe&S4v-tF_=0T}vCQpl<-#g3 -9<^-RB^wuV|tHJgO!4m2Ps?2#E4caBkx2 -u%Y8`yiOnw-`j)^a{WFfm(glVePbx@89fEM$T2Xiq_lHm?y35c8^>;2DJVr694jwEj>FHeRn&rXuCG$ -@;9*Dns@b$@SjSk?W+b*kT$<`l2E+oK5Mtn8< -y8N$pXoJ)MwtG6*Du2RxOyX>MUNut?q1~YiC;+t9Nz()Zq4|FD9c(1GAi;nIZr@YAfZ*6BL`!@UCOg2 -FYkoJq?7g0J|KDBs}4r+Tlu1R6~z`Zmz1))~$u*w>lE+M?)C@m4=1xQZe<2%U}!=A@+xHdFgERY(%3s -yG~1mddH{)AtO<~I777a>QLFMO;J`xD1Lg1X*I))wAE@IT%ay)G;i>_L|X`Y(WB!j8~mZc?7Wz!BJXL -xPRlP#pf@nSI)|f9)>vB=-z2EA5WZ-SiWwSJvqzIhXhOZ@T%vLv6lb^bvf^&up=;FATCOV`vqhzS`^R -a#YGDjGIfK2m@jjS2*n}STP>tmL@=cI0;0p|(EfVt~o*v -M#dts_lBm$g@cK1=7#+52!mSijM@Ls~W2sqd9J2B|T3sQ6Uvq$rhkjJ5ww6(Ib0*#fF|ku?*Om${E+U -VO%Fma{ADmr^E65>ET70#MerLk4H<+<%^otsW``o!ct^DyV<`mWD4x#cSXHhyQX^F&`C`#$_wn3(*CY -lU`#FhHn32MS3qO?6vo4D)s$?ov!d|Tv~tl$+ik`XTI4up7V7GVD)|EQp|PG@!e77&kTFwi10{?`Vou -#!<1V;)95FX&6^w~m3iGXY>$9qbk*olAXnr5>T`CBVMm;>3cV}?hnY$ny&Vv9kx)wV=mjgrkde}$jZk4; -Dp*k`jQ&=!mug3rpkm_j7ZE4ku-(xlY)Ity^S)IHPzHqgOx991RZqrte^L>f5>^ah9$)zRL}l9u(b*a -JNG^Cfpx9&=_js%ejxmzU07jFnDO2BTn;%WJ4w$=Ad}AZy<|F_CgU`oCjiT~S&QL}m~W|_NH3{=6g@A -dFk7&%f1Cyp~!&?2ivc4c=U -s;=V~pv(78qa9=+e+f!{q2dj}6X%Y9(NZDUz=FhWA8qWNuM*{KyddlaFCr4Fx!HcsO)c@K#l8G}$Li^(SEU{(y$0E#7zG9ww2IQzGMb?fW&NCU>3p&rY?xgnQ|N3y -8cbWF37JDwz@=&vIoQU=KTGioOT;k+DfN`t -hmY(c=z5CtM!~Wm*{_Fb}2T%Hszui4}1v^}!n^FCj*cHC3xT|(#mIRwfM`|XjlxcrgTfUn8LYk?;R$N -Y71-2D_yTQTz4`%CR+&5tB>M?aehAng!{iiuKr;J*07!ygpI%`Qi49%B%7g!bD1#7mJtUL3gT$sQ+rH -gdlG!M!?m^WlEoN<)R7Me|)|JV%hRmZCHnm2KNyU`4c73MvENH>=5Aw(Lx}dL`Fhjq^bDssIFZ+xz?)6t -&G~PvO>XFD>g{U*2Xr$ZI4PB3xGvbe$r&i))IOvCuRtTn!Gyf~OxGx00dYwJmqX!&g5ZTi-~HX<%&X$ -wE$y<2aHnJrPbcMzX}0uHC3Unpj2WJyNaM)7Kb>1q-_UY!(@|C_#{gTGjdBV5@+c_Ux82go>o%XiI4l -+BXmygXehKGkV)OXJj~_pK61O~FaxfW2@H~1v8TQs=9j^=?;a#Kkk2V%=KF+4|9D`eP8f)%^6XLbRQ? -@=(1?LT=#0v&aVQb;viC&^1SpGIuD~>NkL~^zK_-Xs`iWle4WqhB~sAEFCSTQ -*`g)BmGeIinn$YQL{EJe^KQkpeBW63h=eU*WD>v?7G=bxycsM`ts{-k&+x$y=SWArwVA6K&JDV$;@C7 -jH)}Ww@E&dj1AM0{zOOdA%oW_rf?du`Ym#Y(&%W*Z8pi6N0ST?*_bxa_Fvy1l)`Un#Ohw2L~{xoG_xH -|EfoO45?{KL6J$|rhdCkVPWgAwqz4o|x)U`|PL!)$5543{*@^X>Omsz7H?TN1$QIK%E4CbN;n4CgqmU -Fy*Fr -2gJqbaNxY>MJ9%L5nKqEOhg^mgzu-udo`)qp5^w=*ErNU0lW9GFB3*VqK1noFQ=(mJS@(-jF|YHgQz_ -wX_N_s#C^;Wyvx+SV_nV4|kz4^))NO!KJWJZ~JgqhA_kERD_R=;+I1c-l}n!$%FL-Nx~+D_j1-Z#i^H -=z)!zv{M%pa=vHHa;vr@%pFFtA3|XXb`C4Bb6AC)TF9|`L_|t4hH9%UB(A;zevNrY3T}}QM{`nhI%KF -nEL{i>+fn_su=2ps-o|d{dw~;2kG!rig55w!siwC4ijr2psHpXOH4An(cNXy7p}m5Ut!tM0(+)ITz71 -Zjh^o?P-2xj(0z4`tGt0`GYLB&|Qj6!N1PqC!WU0SK?c$4h#XSpryHntS7EWhVA?`~ -D>Uawt!gZxM@pnb#)FaDRd_TS_+y7`g4|(ahD1@u-j8Z4%TM6#0NkVQ>1A@_SUu<%8%GTILn{1~X=5w -(E7dLi-^pLu{(N$An@1YCwDwSNIX(^yN~#|j>ULa7A4+vB -N=dZ>bi&k8@{f))a68%@#ZP}}$Lx#t)aID4K*NG}jV%qSPRET!Jb9pQYQJKtW)n+luERwwj9Fr$l -4OE5NEgpI>yDTUJ^mcJw%-`%VBtJRSq-0W+fDO0g|?C_W){=h*tn(MVAt3bV)%NCL1jNc$juWX6UTVm=YMTTsd3wGWCr+BW(*EI+yAem&K=ObhBt;y~oLf^430qbi4wO>KMs^!TJi3#oEg$a=hu8z -WkxA+Tgw2C>q`9P-9D$v+QF=n8uZjX01T5G$$qHjvbtlc2E&rq+ -_%TSDFM|JUSd4qSlde6<`j|eo}glm)zy2`u@B8>LPu&q)ze0>1ciuaV+@LbPj9AO|G;1>hb=*tmEFs7 -oCkyKh?)hhjL3!Decr82891ECgWs5Pty57d!U(zvu<0q2EO^<0r>$V~;xwczeg?^GG)L_;F8QC+JVRKNM-b1;9QA6}Z44Lg6Cfu&fYQ#kBl%6Wn|> -cIvSQ8wxbO(FtzRUin(7w4l6}~*{5uo?xAnGT*#Q;2W`Ulwj~#lG;7J$a{eS-O^zoBtv5#+9D#miCYS9#J`>blTt+5V@x7vY}S~4qQa5ei -aiVP7~4IPmbcg2OylrNq7<5>bHy6s=gBp{ZiV}zn7Jj_Vn)>@z?!!0%NLd#~xQ -%Ve(4fbCSLUM8b7nrU!fjgX~`lk<{}~+)133I393TYUY2?%u?~#!teqNHaB`9oG#~cYEj?_B$6E|NQ4 -mGG}D}Ah&a&m(Uk41CZlOt2Z5sqp%Gq5t>oQmr0dfCXS+Z2_n#kn4KdfUsws=}505|!g!N)h*n6kI^= -+nBYN0e`LaRRY-5WFpUT_Q~oZYq-TCQYrfvZRxrQ;Nl{RO9QKs4gdKo+Xd>fa8u9MZM$)ug_@jgRgY$ -7`s^>!$@Ay6FLM1@8{gTYehfs(23} -1e(s*$Kv&~?cRJWYR%~NTVr5({Q6Yy9sPWbpZhw(aCi!-iont?GNURhf`%6k0#g;x*oEn)rl9Ier>w7 -x66LpVbmL=ktp^yEH*LO0*w|8ri<_2)69=$qz^7g9-%vFLM?+0v?h^`LzaByV -a^qkA{vsxE(okTop6h{nt_9dH^xI#Vh2RDxxmX367T^50_hX7Dt;8kI|_CqgIqlE{P1I00d&c1em5zeB!c-7VwFe0WT8ty|x -FdAK%cO|8WhA2a`K_|up&H=wno8a@mOXLToy>QpR7mBm$hz -jwfcMIf8@4D|w{j0}wuHX#K^5V_s+(zc%>qwb&w`|7Hp8@!VgjloEAdIzp&l;dQA9 -hhJqv+R6I&e4+bv6v6Xqtoc+)%*gAM<-}wMj7Ixt&915R&3tCKgg3HR%pCd$t*=MMK_g+1oTf8)uie$L{~Mz~n`6% --rAj?DGd-etG{QyX*|J4xpq%d!U29xgAn>cSxn(5fypSLHu-*jx6wwS>R_xt~R|Ifee^KV~izM!>*6D7;VT2-Z`MD~>8_6w8A6TEP9UEHx -}xx8O3f;XALfy9lQrxL(zJDSb9GEn@hX;|JkTJL;$+%Oj%%gzu9Uc?!q3)ZlIgZuNT4nTyD$Q&)0hwz -Y--iT>1>|%kaZ}xyh~?4-&pU0-OjPZt>aSE<}HL4bTKYZ|P|p%r7o^lW<%c0;WisLulKRVy -Jrv!~~OjU?<_g}MT<&HNcC^l~^F%)PsDU)aJ!^G!Q?ivsMhJDR7HqFLdeee?#+L*G^j>GR;cSgYWF_! -QZQFRFDJRcK=Gi2n^Js)d;wYFj-n?c=Fi?OMJn@F3N?Kod|_PR2U=KZS#0aViS}Wl(3{9R`)p36W3uF -a&0M4&20r7O0bf4pO8NJXq;3ODig2BNNWLCn7x@kJuxQ_l!MKZi%gH@auON3Tqflvz7VYCdr$$j}Ju@l5iVZ845$z-K4 -rZoe_N&9M9F^$lE-8;XQd;i2r79WGb~5N>H61(9FQY4i=~W16!)oPnK!bLJsXZ%7P?wJZ+qFohk&SVn -jzTjq{Tp5F-m+4xkvhJ22fCH1T@}7nFH2X0a$cw2Lh>0y*3EtI26?ECS&PYk^ZzuDJrIJk(_QN*)0{a -+Yv-)h2^V%JZ+$QCXP=|Dqz4%r#CA*YqAD+qSGuJr^(dL#Cv&>lID{!Lz+>{AZ9n9l9)-h&roVvyTQe -jV41wOOIi&(a|?1VRFph{I1FXTb>?L{{Ksu9GnG^BB6U}s3D8)^c@%B$U<&BeOJ=Lrz0*@k`1HND?A@ -c8F3c;L`(b3Pf1OD`IcdC}Q@}&~Hl=T5h;F5gs;C-5;u0i@I}^Lz`1RLv^9Dk&8^8Qw_ao+x{Q7I4E5%RaP&Z=ig ->3unMjSu@SFDKyCY^DtwsjoK2DGumErhaw9vwAGAREWWl?7zL%Zk|D(!G*S>3YkQ)Ow+}6%7_6ag8>y -8CUd36xRWUz@;FPg5FsJ5>ByV7nMDPNr8oNtMnoihHOFB_uu(s7UFTZEzXj|`muY|`SYi@ve>4qE8{ODuhSR6F?C9NiEh^-&HjEQw|5e#q?_HQMa1Sb?Yx28Ca5N1Yy}S8B8 -xr9(~V(kguBguc5)t3fJ1g(p?rn>U%%xSsMP;fpuW62V3U=XX7_k=rGM0LL5?QZ>>-4%Cws#xs{;2U24I^()UE!OYzR?;@vzMTuXB@uiLuR`gKm)vJC?te(Rv_ -N>CB{IY;4$GnWcRPU}Fl^&ZB{#~*MDI5AGrGH*t>WoUAttgdKsl2Mxui?jdSX~z55g_}r7!Y$Xl`$^4 -kJZhpS=U)H9atqJ9{iMN&FH#w(#M@}uZw_RD -Lq+P$oTgtG4;kUW06pg74;wE`CSi^I-h&XGj`e|anS!$eG=<_c*Z5#gLc{bml-Yo8urKY_H1pXdd;#* -;)F>Fqg42~rfibbQauu>~qfaI*e&_WauiUHAeX`a0up?aMR<;fx&;bSQGRK>Jy1#P<-h8J{dI4VkUtB -U`vp`TWSH_;)PFc47!2O3@>!TfZ%_Y{@%YJS0LdJ3BxaUhP$pcmHCgEA#Wtybof@rthKg+Ly@85iwwF -?{pmS-a?ML=PUe|KBHf+8ezG@e18+1FK?0Ag+zy7yy0)82Ar>Y1GiE!a!*-6_GZ=4kJAD)w!78jArI& -uHXw*2jI2(`mtjt1pLsPPppG0So2&Cu|Ov-ab$(7H`mlatoLIfJxRRZd@SS*0l=!$;V*6kM)oYJT!`SH)ri%$g@(CJUXirSTuN9npgiTLOl) -Ljh0j3}?x)RfmTfoxH^9>aw*aAg1ad<$sBVXhaHLQRJFlu2kop+T93o&vGLfe^JtQ@jQ!QfkN-2AT;F -U623b6y<1em#HvI)D9o8e{0gXm?y>5~SaXgGtO=+hM%gCC*E-5>jYI<&K9))>aE{q(=JTd#2JbfVU}J -`5I&0fN;C@>gA3t-inmHb-4S;droro*3+-O$0Q5H@Bj0~_j^zKul8Q<9_${zI4D)wSYK!0d(Zp-_-^ -+}s6dYkJgY3Qp&(G-LM0w35S1k!GK#-F*xT#8+&kzjEBh%U^2K)tD~o!xo>$wfS=*r1i3EQ&HHhm;Qw)2&RT_=WCTXE=852qO|Lo -fwyDJd5yUFgZ|C0$7%95HSJVIwbxBk(XJ*lN5Fx&eF?X>O#AGVshd#90R11z)_=TkMP`O>iQChosmC& -ZK%AkvoN`sLq2=TMBQVQ4yvR$*R72dF%d?fJSeZb%)$8WApzk`$7JS3!{r(NMd8MStqx&X1%pPas#bo -OBG?eHr8NN-#7}p9~J)r8SVl-*yzOo{9i&8K-C716!CHL-PkS8-hdYynD*?5|j5o>zB5~%=zj9UPXv+ -47c)=+5AdwU$}Hl4-N(jj;-A&n=ktPBz+P^mt%=|F>np-yH0(sDor(>|7_(6g1!OZc(3X?5VK?x>Knh -#eNLGf34rm*SXxbt}|$4kC)4Jg;xg{HTIERo$&aGU7v6xh7n!9E!ZW;}Q*?rk6Z9R+2mHLPvGR!HRcZ -yD8O=OQ_@L`T|Am)2AS$yh8d^u}#r0;hCf@!SzZ3x92*`7G{h4g`Di*7JMM%`&?N<72&Td{is4(gOswrWa1nMEJq<{ftkB?c*NeWQn+hT?SG$ -at^)INUg6g(fA{}B{qbY)gE4w5~xkZYH960l*{JWy`1-X*;xDz+AF#;Xv57HITNU5 -hr!Lx0!{cC$W0fx)x8fQOUOpv>VgDb#upp!&~-Ff<U|VY)LPuB*)%ED-#u0^5jG(lRr6e-1MwmGAAv{E|g9{Je{ZJm_IpreG0Ws(~IQo2- -8=c1;Un5<|tjkphTxZp)^g_8-OUe-3y)3Xl@wq5D>hxK5>IOx;a0a>owKp_W~*hC6x@+ -|A>87AT&WmSVgVLXao1ff){2cB*u*;Np#LcofZuQ{fu -XTk?IHbG5^7Q)R@>_HoC!$w59mvdL1tVZBdVnxpFJx#6r8+pTl8f$#C_}w(2iPYunXK_g|mdypeU{!t -VCJr0*T6#8C&8$wewI~s051N^!nsrlU5u)6%A^5^QgWytMS|NC(dmK+1ZHgbyL&S67&Yq5@3p#1l?ST -VX=JD(HK_&Dor`7kdyKFWuCH-6)^0R{LQ=*DY>Sz^K=6$(K8qEPX%qtCd2h -{8;H|$Cm)-PNAehw&Rg>y&1$y0%UM*%c_<&-KQ?5FBbC%vQEhX2|HGdh^$A`g-HA=fjN1fjB@?Ck;4% -X{j-Huhv-3^T?D^JJY#=GTip)DGl6_?L#%ix)j*$QJP7@}{Ur^y6)osw(KIE`mEGyEQ7G=8LjJ*%rusjD!v~Y0!2d&v2BaRsGkj!2#yczuy~~moCRfcdqqGxU5Lr?cx&Jw3 -Va+)4w%r{YYI8h#lU^driQ|5eH#izMNp)YN!)L?GKxsU=X`WE?wBg~0sl>L0Kqu^l0BV*gkGni7e9f_ -YNP(yhJA$xOP+gphT4+&Aw@wSg^mGyQymY8Mm*v53VxFEOYxKS27<1>?VvB=FpwgKh6|ZDY?-K&v7kTc?6LcS~6D*g!*|1@?ly^gfpL@OK{UEgv-QxV8 -z`aZu{uCWo?;jazwg=(0Iu>=OP`vIYj}1fSJon(AD9)c9 -LwNqn`DFC@mRENWx;ra?80!AoWrq-!4mq5DS1?-Lpo!JeU`yNLhj=cl@0>ueLbe8BtE&KC}&Z%cWRXn -xf|Qzm-SyaQQ<_MuTq=F9{tk$B>xr9v0pZRwe#?-@;;+ajH3l1v|#b`mj?nX#OlXgJfM?#Gp>!n)#)8 ->{GoaOXwc_Z5=EqCxUi4bn6n(}MX9kuaXbhTs->*1w~<0ysAa3hknQqdSqd@!a*+PC7?FnxNQ$hDR?Z -w=)sskhot$M0vW&AbIA!?|NH>EtRSL?iaEf6`#ith4;Fd=YS9q3`GB0psXx3{t)*2|-&RC~q)gfVcS; -dZBv5gH6E=ZltFbWX~DFiDj2j8%Pr5Z-Serq(Hr{}~(P@XqZnwz(@;z*sd9le;QFY;$7CQ(V!u@`PU8 -!3s?bR>YA@n{&g+6GcH#;^EDmq^ax_p!r8Q(VzBDMr9ZU*_m%ib-)cOHDbgz}Zx42A;X?Sj&aKijgm! -&adX#tVw6QO|%0V(0fUKUcf*1-dy6hl4g&VJ>a2h;Fi>%K8%2TCdR-p?}3*AEkkXMt*@A0s@o#7dwh> -)#vah=Swa3{QRwVp?&9dUd}fW>Ml;Cit>&WDtjM{^r3>9;#R-Kcom}9Hu+s@<)z-*+Gn&n_KHwbLAe9 -JcjYo4d!mIb=Ruwz#4OJ=GUIEO*tZ6{EnlYK{!nt&>6ee9`y*e8xe)x{TTrVh(Zm$Ye(2S;DhZi>*fjRk$_eK&At!>&JImq -VTZv4|s*zf623ki^vxHb_B~^afC~oVmFX-j)R)vTC9Ck@aiM#wZh?C8WzQx?G$!@=j>}G^&-H=R~^?A=?hbUSa5JkB#g?R=ta0xZWFxugj120cI>Za7#2mt7rSgvG?oG7 -v?II`pDTM2r{oNUS^HQXov3R#b@9SOOig)D-lb$%-@qkPK|+PS^W{=1GODyG(LP1g)@};a^Ebr3m}rbNw2CBbLq{uwry1^(I9WD -dTezv9BQ_@-c4P#wSl9+4c&wLms(E#68nA^2^7g)R>wR=nyY5xa)fx%31RRi_gdx@ia*9`k{-`5eRF- -F-x;^5ia_PwffAVFQy|)J>fFs)=^z;qA}&^3*eO};!>`$XLFH~7iHkRDdDEaCl48#O8dqq4LjmGmlr$ -}tc0}t%I5!Q3LBkUf)w`AYkx{{_k#4jv#&`3}%)WGI1G+Ywiy4)lN$#C;Dui)1Jx^73LpeBAX6pqUsN -Iz+lYcdo^`50SS)$jtV@XLba)AXS}COQ}8g820h% -M107!bUN2=AWt)F;cqd>g!t7>E&WRb!E;~zTv{bM@9(thSvT}@GfgT*rQeI0g=8bFQwfk3Xaq4ns=`z -+VG^Qnv>J^;a9U>IUhI*1oq)u5DvsxC&;9G(zP{eq11Pr5 -JS*&Bv{7P`1{z7>Hhs)cWM@$T1DGGj)VPxdGay>1>cq?2yJe!0jlqX{M*g9lfF6 -tO3vs0dvbkQ#0Q_-F#lx{U#h&r=Nj+gxuU`}sCSL63HMAo?^iM4A=^Cuf>PXN#P=2S?#>r0q^zLll@4 -84L-vsoa=pb9)zPGRD}%$$az{WA1PodlsR2#OhFI*A(?Qz^K7Hb+I6*03rA&r27y$scY1b7F-}|`5{? -s2S^4|I{?w+le1?c-Bw(yV%cbGTfv2XS8UxoN{axz=39)%N;M>u8!|~#?Y_>4!#JvMQDV4ctD#}FV5l -S&;j6AGMsHAdL=wJm$R8+0*C5_hr8WTDd$zN5$#a$hh>)yMx+#+S1py{Xg -F=CZ3K9nNCLyt6xL@2j+9T}208_wP%*3-VCfl4hd!E!_qQt`h?I@YOp1Yr -CIRAF;Y|5HI_1uwL*RXnN;S<7I7oGNOKWeevb~z{VvOYr+NU81FO{lzgLO)U$-k0tKt5!v>w(peVCC^ -6L;H6k*2((DZ`RuprlfjT6Q&TXQOwEQ8QQ_C|^!Nv*9@n5SEW`bQGf@2ifV$0!mQ#e?Csx3yL}l=kxA -#=<+P-29-TUzmaDMde^eC~^fLN78I3=QIy -t%So9g1&M -EWKdq_)+w{rs9D-=A8z57)xk6qA^hb71Q@ED@@JY?3LF)7v8T=!;%(p7ZGRJ%pd4uJ~g{@u!T7CZIFlkeXDDc}7m->J`^@|^(t9msb9uJgKb-d-}es3YNB*CnG -(-n1$%Et<-*TgLS~GPw3CneMOkWjfew6iFLs-;1+me6aT^y9ayG=AK=56SBJX?(YJd)?0 -)m&dGzA(A^vNFTJFxl4dEGpgqePAQpkVZfhIq-LC&&bs_Wnns`3qGXVtD1@5s}l(QerO7FQrhHK~dXk -Fci!(l3HY-@baC5*z%_3#^4#cxy_zYu^1DKpmB@j)B^0IY`XDc*5fwV!hb0=4b&b)t9FN%z^+rrYO^J5X~Q@g -WmsBZ4baYDKJ%Up`&;@$%iCi+%*|_i -}J|A0o8Y~v_S(gh*Yp#Ol_FqKCHkLfexX{t6M_VMj2HPL#R?cD?J$ -uuI53&;eG2%Q#A-Ypb+u6#T)QCUi;)2T36T501GW=N2E12J>cfG!)Mm)OrNvfU=8$I@)~qIE2k!`eY$ -;Jy^#jSR2bdV0?_Lm=rGjrfQ%a9RTC;uH`qRutJ3>)Ci7ZjXDt0oFdO}7r)kM|2xeycE$~MgMce8<=U -83e!fA_4%8}uOVMZgZnw3(v9;~MzycLYo7?k+nNMaT&lBcs!MCZ1+}&kVP^?6I;`;3rAbw-Udu^Gqc~^<%5Ur16 -IC?9J=dm-{;bBfj96J<*vUasSpI=Qi)_;cZ$2!irJFcanU>YI5Lj-|wGo -WtKsQn>CQVaOoNVPa#__3$cWXoWBdD(b`lsr;9H5vR-J4#}GQU=kVn_L>DxG}PXvKAd6+5H4S-|3D_d -!%zp`tSSZ98(Jw>uNXCexMoNujt6;j?fRB#8jb5K9sKxibFai%u0`)~s+I6}N{hkH%?-Z);F|Fcd+5Ji$@AoD#P*=$l9S{Gd466^z?Qilxn0es%Hkfl;<=1ld-s`PY)1=h0ONEf!z?G|S#37iltNfzrx1#r -N~fco>5VVY5$8ObZy-KLaWG9t{1S$qX&|;fPUJ$%XvvvYaMbu>m6qnEf`*M`t5t2u|LJoM9T6eT(TS* -}Un@MSfDFuHRt>kc=;rt3pr-m7^)zZLnDg3Bb`l*|#{BC{^BOrksO$i3LZIxW -J7ZyOX3Zqo6968x0fUB=*27@ZVZxcUK1BQJ%&t@;C+f)bh@6KPEDAUbG)F8Rr^#L|;blWWsPOYrDS6& -H2&w#-hr)TpRs)VeVy18{0Fu9VB9Ct&IwJ?i{DldMPolr&vXn1UvOm%0hPH^4*GksP`WowX_`%kX}(fhQczo%DBqm| -BuGXkP6o|Gfcv-v(RDy*&7Ncs-dePnaa1L8;vX=cl!U4cw~L{SZtbY)@3>MRQPZXuk5z>uGHPQDvPU=h(FIbwjTk3#Ib2H-p*yE)TaP>9Q`>+d&>@g|xVg561)NZz -@$N%Oy2>>+kE@I=^lF$_1prcQ*uHc8tfk?vusA7)Z#}KjKHC#BJ52*{t8GstJY|j2ywh}BwWJOp;=9x -OiXY&HhNB`u0m=v;%%ZFoKe(-HtAK7__^{e{k~s(DkKJ*Rwf(*`6b67KJ<8sa)SghdFw2j`uIOrz6n9 -)wBQ5tiY5coU)8AzG`IC0^;s8#B7l#xtYu0=W3w8{6&`f#^g`f-;iMz!N&XcCAHn|hclQ+;8&PGSU*e -1|ReD;Qc6dbr+vxYWziVvabe>bt2_t?;TY^tRk?@LOg(<}odPWwPpCs0v)F-Ro>=ynhAeiaS!#V}QsZ -5gFQ(c>1gS(X!*4%I>C1exKSP5rdB00U#hV#Ny>3A*}Uagy-S6c}%qNLxg+x+@#o>HV5zve?uJz){%6 -JYCj^YLEz^mwNoF#Kt94PtmK!g8AZmk)2oirx24eBbCcnz=O(eFh6=F?#nQy%7 -mD4tbD%N21RhJ?%tM!dRArnDMoc{WSVDf>G+HWyx7bp!yz%Y98beHK#$udGGdUTU?j4Eq-JWA;5scaT -hp3O`TZ&AkwqHwaM`y2uV42gcy^cWF%Z?_Wa5uWdCYX?mWCuO!(lE<5Y04S`tY92R3;__ajYfU|&l5B -xs6e^Zl{vL=>VW;LY2R9gLDfl|MyQT@(fMP3L_=yj#Bz(?vE96)_l^WXdh4TSiMpLnoVhUyz{Tr5sxz -pspKe6hnTizKg4clfB<(HSY}`M!Q^D$%89-@%g^zBO293am=yXditWeJ((4bM2l+qBnD+D>YHI%E6I} -lp;z<*h$WAfr|uQUwF&+x< -sw$l%Vdt5sB>mk7c>2|aNDzHdnGPn<|&Xuh!kybR|V028LD>#W)PZtAP9(0E7%uP-Q{bOlL2f`}XS=% -;sEDFp*Uei5c+g5xSAFOWyV4tuGx^=?*UUGq&JjQ6nah}fg3E$;ouR$yo`XUBXFa4P=^v`sm*Zh36bf -FbY*ma{)7()RUpc9#5md-~K@7nP+ac*H91qfGmE)Z!5b*>NX7UrXgW)nK?>-=rUW3@hWc!FmgSeYRI#8DG5GProxH&Eq>-6pmbpTqK-Vz+p-9D>lZK;aIR0xOch&5KEgx1cqnJ4yjC-e#j -AbpaO;w^B}MhRXrFbxZSc4RfEHV)u?4wJ~V46Ee^V8S{9E9nh9hDSAy(T2sdKF}fEud+pY;u38G5-?7 -kMEwf{K(b{6Wr9i8s#Y#nJ5g=THKSR}zOqHD`{>PBzs2EK~?lX%rj8~B56LT8!lP-6N}(XCoM+aBIt>n#y~1SayI1692>=G! -5O0a5q%Mj+?F>ifqj~i6Xa;ipcu|;^9?Gkq7RlJNMS{|yV9jkd4%_~e_yaW=jgAw(SrvNNviSgjxFo* -S9oX>+XSjim{rCP$8iiY?xAEZNr+%)BJ6L$_ArkM2U%a>8>#VP@_sVrfQ*v^^y6&qlzxe#KPdn~2=#ewGUi)BFXOx2=pdJ9IQEBQQ1)Drp2(&}$FQPv@fkctE@$3AsYM?5O -`OL*Qtb!ipqlM!wOJ&@7~xYjsUm=^~>-l3H*;2eIjo&e^TAfPP%fMgy{t_-T>h0mFpJv-iO0eiMoZ(- -JO=lk~ARI65Pn1f7pI3!_8#6z{bvWj^Vlsb*PtkOzhsdC+{>J(Q`^t}6z+#r!LrDOxy^?yGvjI4-UY7 ->n{sSClhR$w8K|d>~F{WQ|#3rd}-Ocnd&^q5Y!3KsX0nxD)lF{|`9BjrH|)pDT)xgLogk!nB1WIKJLT -PtszLkJzGa`R9EUJwbb_7c<|4xPzayj{aC*SAOiWUSEL&!sIB>QCwW`b$?2NJ8E>`;JGU1=_DHDNpTV -CtNMKAW8lk&lyaqj4L=$nGG^&`jA*2E_jo_?G&_gsZ#Kr+`TJ?36@c1%=tKSdOL+Zk1iObzzT)l`Xt# -HH0kjMFVhWft&(JB5{1$P#3JdDP&r3|HMWC0)41Tru65bf?-g{d;%j!m1eQ2OHf|aJU7Pu6y<|IHZW) -|@z#U_BY!D#y6Zga^oiTjI^mlH(!;B|bX|)g71r$z7n9ivFU|& -Re2R4|J0HJSZhd_DS;Gm`s=L2wZ~hJ~iOp&vVi(m@gE4=5_8UO{rlv`Dr@wqieHOX`-{X~pCB{I*4=X -!w6B*U}l`tzt@#VwvAf&7IAU^*R2SH?v^zn6x7zMrkymBNqVbde23%g=OpMO~z5%qhu%2YzD$WhPok> -335)WOU}g+7%@MoA>~qmX!3D(GWCKk5mTewmdHQ!*TqzQ~_}el8PmROc?i5gj|G -${V!_1u_@K37il%!(mV`e^o|e!*sSY{R;=?65MM?iTWQI=t!<6cuF+MO_N$eHg!M+fmQ!L0C_8M>Dx7jEdELyCUm&34dXiy96(7&wLez?d?M*Ti -If6u2-DaaeH{mr5oDF+uZ-@Vl*D27$OQIj__(q@VaCKT67FM#*|Te@hQUX`Rrj))&lx!MFpf4Qi|DUY -e+{s(JrIp={Wabq{>p7wQ)k`8VrK;KzQ!v -D#Dl61wpqYBYHAEPfuY{4A_|m2^_T~x~A`u<)iiIC{Er?vr8Qh0!9Snht)Kk|3`YRVgzZ=eal~KYb)T -e^&BL+P0O{47)}PyET;`yIbNZH5gkyKs6rmcxWUl~Oj?`dn5`!;D)rN|u+^!9R@|3!%#b# -IjIlCOvxw^Flwckgl@c%%)CwW-ABf@QAUPT^NSJ2KgnQR6EknAm%&&lf|vlEs2pS|>*r{rn1wHEgRF2tj7$^bJ!lQCM)+Hj9x4P5 -ffJTE0=HmxBje&?bT}{^>OC%MMXoGT(;g&0c&4wi^r&=)DEO(_GY1Y&XhMNsL*I8GM74c? -obUhh}9BXQYy&)>Ra9{zgS{7DK+=Mc72E?rdX1#tOP03oJR*n?&?;8ErC81hCnYCFrK#JOjHhb&q>-BEGZ -8$NuWf^Nz=7F)_Ne^LSc;Lt7#LMSRQV8i5f*Um$>K{Ww2Nqo&+&HF--hu6hnhpiYrr;TheJ^Ewm;({s -76KD!RYFXtaonoA6QLCV_Ood}#Z$8{y%+`15eoUrP?D*eL33nV}4|Al@)#>s=s&<7XWpn -AaVqr!ovU(|z`Zg$Uu26Ss) -_;g70Xa!c#45(PRAT8gCoFPX>xmV(ny9s0#`8=9An~MF{;p!R#t^n0cLCL2iItH9Ya(*1unU4U>(Pyq -w%2Id)WJ|(L%oybU0}|!0W0mrTN4c)`4|L#6`pi-mpzmz=mVs&+$Q=Q>D7yXl28tv6jqnLu0&E|S<;{os@HN&E`BlI)kCbltQgkDhLq?UrZ)lpLlF_W+ -Y2X*Myp6tp-wu7o4&Zyu}r+M0e{fPPziit!kLz;&t?m3NNQKjP{j%HQt7F8G4hWffn%nIBf8cf1_^TT -J$-Fzm#Y3s`T6;6k}!8)GG-2kYi{84a*E7Cty#h%CtHrfbZ0unJDdnpe96wqi&=%-$nxH*YCjOCm(gR -1VDZ@?N$o+<;fpA<9W|exR!P9S!{yw6*{3Imp!TMJ-qzTQBkzQez8D*D@?E?h89W-%S;ca~QLhLoJZ&K=UkQ-G=xZO6K9y~_K9{9eCynP=(W#B4DuihhhAX*UYw@?t5;lO0u5$q^-3`63uccaq93$y^I7DkxsqRv6KT{KTl7wDSEhByqO805)}gYL-%4#%b$Wa -GtTsyIWsA)+`pMO)qb@@ -GAw{(;o8%3_*~bL$Y9LJDCzZc~q{2&UN@&SoFm_>+lU8$L+Sat6cB~ftkLC9KXw~F2V|rN%Dhm5`?o+ -Ivx@Vai>PGGxJeeU|4p%Q=9R%8omm*pq${3t9p%JxBU>WZdY@%EVu?IEiM{^0Wn -p8@uXTZP1HAD~{=4Y17y*{Vis{b2g*>!rOG_m0$E1>Gh_M85-oKk480;O+6BL$Vl4MNcz>jYn-t04iQ -1hi4(efJfUmGfy$*Ri|f=)c2iT?Q9ep>CH*!hDTOYjcX$e=z#~yG=Vq`lek4^gyr(?L>j8}-sV%0Z>m -4|Am~B7uHPY^tCl@t}mNA}t}gbc7%u8dZh!PFF9@nuTOtsD+{Ldq`uO77p}l4-K3F -N4+%S(9)1)wQyv$7#i3rFT(4!0hr-tmP&pVGM>%CF6o|<&{SzVWPoN!YH+=@-%(0e%&4MYWJMvm+kmT -nkV!1EMNaySnB|Q@duTCFm({%E<*<)~=s|(Yp&KZ;(MHYM<*;<@syYsfz&-H!fb49Jz9&k2vZD!$3_D -!pN>@$yg7D@?)V$hiR)%$%Ttx}MV*{-YJMJiT703{jdI{=G$Wlk__5_d2XOxD$5g4{%D%-?VRwH0zDF -VVw2#I`cE%(v4f&MmhSPDx%9O$?FzKO>ri8ktpbR^W1pdRr<>y9b0UWj@u702QYabu(w4*I*uCKCA;SF|x|3y24o -tGHyAtzj9e}0OFiq=<04aeZz`Xo_{`}b*TwD&5>}}c~F3^4vSknH048RyK6&lk9%hf;?(X6qF>q$M5d -M)>?xE$i@HxlV(S=kWoM}RsPUN*(?o8gZ|RE&rCKl~Yv&+yNWXYq1!y|bg&Q3VcYNr6;T*#gk*^>)-e -k|HDmjfe6N{|ja1Unmaz%P+s$s>Q7>WrrH>LIh};Ll=f;KfW0kwx;JuJ@fU7XCB2nv$p=v&3m(CH$Qj -g6}Q~itRFqom+BT_U?PR-M5yXf=Yg&47tU0`Mmy01-`>iA7Xa(WVe=Kf>{I2f9$Xb5dJNM%?_yZHv>9 -7dcUMo-UBv%gpdokj*6S&yuvM_|-hK)s0?2nuXztPo%xsi$rm8irVNz3bOL -(^^cNSjz>1K!uEJKOg0Iix39^geFUoV-_lu_}snVs_55KQbUEgBi5T9r9avDL`WxcTnDf6@6kJ59#XM -LM2Q8jm}C&bVrL6*UK*ZO82xBlFN5m}|HI%l=yeV})l(3?#l%0dCO_h|m!VE?leL9tkJ&%#dB{mTU+J -lIWfbl~Yvly@N!k>P7NaZjs-nQ#VCRn=Q>H5(MkIEu#XikEZweXgEyCo(^%y7S(F-$PR?<38MWobpT0 -WELWh75u5pQRnH(oT|X)BOgCDF*jBLiT(Ofn2ah#=6+J@YuxBPUVnu6SLu#71fEe_I8dA*ZsuR&&OZL -&|CF4z!_UUPRfL`KqeUmU_&Ybzc=Gg;4FVc5(8>UujW3ypaD&5w*&F$`PK6{in&Q&~|dW*@t%d!-v=m6H}>Cx{m{w9u8Z7PeI{2q)@VEV!-q&wyqKl7*6}Tvz0 -#R9sLnPzuAR6L^;5)euiR%d_EPfEb2LCNh&_YBH$D87b}bb$esI*C?^Xl8X_Ja^!sHr2 -pEmkMBwhneE{==V7k5z6x~?6{3-dOTTBat2gP_sIj*P5fGTsdwlNbISpiVe45fp$+uR!(_!-nSJiQJF -Txz4AU4V67@DjGm>CsS47J^ign(79dShEOtVVw;Oy>+R`R16)sAr0_#WdKb7-YmPkPIEf1<}cVlut;l -c9>uB5#z8~P1Tz{$#eWmS68kvmwi|Hdv8d3>3tZ%5gpkeszm`x+>CIJlmlxP?ar?dm)opf8_t19j6e3x!n_d4#qNGil -mM?=29CV4_E5VXS(RsDb7X$-E&t;d1?MgxgHrnR$+aWPA`d$SG1_3{fQz#0k~3N>d?OzYG;U2`INL!E -szL*=q9SB<^kYV&o=~i$(1hJ=#DmN)$ax2MIeTjzk1d!Og5;j#XM=V|Z$eO@$(BjS9Dhh~^*b)DUG2$ -N6ICgkf4>)M`qk$2FDu)WHKCXx->ZCTSJ1r^IRkll~^>oZp3RoUI*)zA_S~u8IiGuIPT?Fgu{>P4f^5 -#JIQ>H-44ZXxJu@$9d_7sM3F4Hdr**Ar<{Hb1Z^o4Zgj3Y -S>gr#&SC=4v>eG{T8MMkhKX_8G=EHT!jE!QF|>4wBuaM%joNAP0f+Qf&@cBrDTF5mjJL0 -}V+#|wxdMamUJaAlpVBDKg02ME_yKH0W=7b1e8TaE@RVjB&I8=UzJU1%IjXv%L(mHKHhNM`8)NF?tLF -gLb1W-Eka4%CRtFa|05V6hqft7CI%6pq}G2vukRxAmv!>_ -R|4zzFz4Ms2|^3dbkPp;yG=#}}y#2+~-G85$?3$3#|hpqZlgQnCUCVdzb*6Tp3tFjutnwYB4y`6~DvZ -Gs;s%$5lQS~)IHM1T-R!Snggwz8VPJ1%?Ibm4`NxcSno=(YT3dX{a_`dloTiZxygDR+NhOy4oL0&>dh -hB)HUN&U8Ad3i*c7xK<1P5QgWg)acTif$0j_z?i=ZA8)T?)Jum=+V~p?k;@a>20jI3_Ln&JVLF{2wV0y(IrhUK_sSZ=lyh -6No7-Q4r!hNgc|oIX`Tj)kyJr)o$vlo~^@yS}Q+)m_zHl=JFpa+;0p*!k}A;!`!ev`k$r)h%W~w>677 -4#C;Swt-CzLm89H)?DAwdkFMa^1fv6(2Lis+Eh78s11}eP8`R>JIrzbizeHW1cl-vBLhOfjU} -#+0N?8tZYj#)DB2>8fs7Cj4qt6BSWv_WE^svR^ajXx{3u?Cu356K0YtdBS)GxU_J|6e1dUZ$l%j>J4f -98Y8?bZ5k3{nGAJY=0&DMm50&bW$ZBNQ|IZ7AmEq%Yr6}_uazltdW5)6pfLGcf8!))+lji+jF0XX$7pk)YF3Fc -;a*xdfDK?88eZ$Q@b30UVJc6%+>;M(+BX65y5P}0V=1D!Mdn`5D2g=^K#Kl|Zwz}{MfjGJJtY~AF1?V*)(TvSK?ev*z*~}^0h_Id1h_OQFqI$~M~s1)vt>Es{1*zfAa>PwdZ3 -i2gFBEu65gQ?1A^td#wa>O!H>zZ5`m~CWuvW_cytp1Wj$1i7*;fiR -7?d>w`4klPIf9VQOo`8-Y<4q-w$T3Wl~q8f=Wh7Fz#p)-f1vO -5cMX@pUrXw5I+23zt4O-m$@CTcHlz!9E9iW-Md3bll?0gk^CGun0>DI-C`$16XX -DR`{spXyF~J`*_r!M_Z>m5paaVXlt~CsM@+e+KIOA!_z6AB4fs%9siJGFHj_+W_*f*&ZrdR5)-SCv^m -ZSQaz$NA2--xa$Yo{wkIVZV}oi=k5DieWCb`65`)9TRK9so=!`&EuEG(9-9p2l<$ht6h;Ti^thXiGt8 -q4XMw}sxMefck?3D`T@wFM56b0#YXhYE7ohwDVkRKAs@`|!Ae|7n0+*c^>6QzrlRVV&q0k#Xm^Vn!>) -N-{Z9I$~A@(!6Tv<67SD~{$}uhq@SegyE3gUTs9IxN_gmzfwD786}UL$hqwY?TYgb1q_MjAwH`SqrLLsT!^QO6M2-j@e2eKYGxnN|Lg#X(dUBPtJ9X|7L>5iS81jtne2_0hl{Du -SoOZ|h9jNOS~V30;AV!PgCM%Obdg4OF5zcNfS=9@Tu#OXezh3{_(YqgxkJ -dY1CY`h0&ez9l@k+>x>1c3~HlGi*?fPBeLrp}-1ZPSQY_Lt>xfu(dzL0B?$Exl-eUDUeFOyWO{xsMmDyu_M5T2I -x%gj<13O}HJWbDmJW)Z3IHzS=t6%S(Hp@^jiDzu(mL?zl9IF~*pgg2e6)mcYp^i0pv!XH>s3$H_QQ0X -!G7@YbWqF=m!l6mJW|nVqobp-JI67`P0BtQQouj@~K>dtyVIIerP`0xZ#TX6s;isQ{{>7JZplH(h*%V -Dq2LSy1V)Wyi@no9Ke#(pa;_ceqb3Qs9jYspVU|+Mr9L}YsyZ>_nY70BA2D`g6noMvw+WGicLC=fsr4GHH -MCA#x7fHU_z>3q<&yMHBKdOGKUhRM~_QMR~pATZF~&VR#h>;DB`*+4a;(bua~i&V4CXr`_xEi-_bA4r -I75|pdI(DXseGBl)(h)3TH*?81r;a51m@B&t;b=~VnVPDLJq4W-Kqr|uzzae;+9J>KpT3sZR+H|w>j! -rk{n15pslim5_Y}}ldWeg58AptJrzQ~Dh!S^D0`qN^RTXtGX@02Llxq*rn=?EL5Lv!Yc(x{~Q=cWDyXzrv+YK@Os&DWfSl1&PfEE-ck|84~JXjJO;B -R{$m&>dEL2&pC-os?)m-Q==pA$k+P8rQ*_atCeEFc7}-q|6?xaZGTa7*v~?YkA8b4XA>?6%?ZUs>6B( -YPbn+0>W=!duFQ=$fd>)5)BvXEDmIFq#_y^_`FIkJ5_29%h;naFi4R;S_BWK!&SE2>;AuPr+5H}b5^6 -9#R#8)f1ebDT!$u8`;H+^AQL9r90yXb5@&n^`c@I7heDOuhkkDiPQ6r^F5H8hfI7WZ6N7o?XpNTrPS$ -g(d()rvs`gRn68)<+n3jnZ+&dK0ms)6)w~C!ar~&=&U+E3iq}6Wm#Br+5Ltk?#`<5IvXdkI7h@1WL3A -^0cu}LNb0M2Q)mVli^Sazt{&_PORvcvsuTuI%Cfcli86yjCJd1ndtzdD-(75aYpf!l_L?E1dOKY3I!O -lzH(p|!lZ%|__M4L2jyAJ(_94eJ7h*Jxkl_uExcVO3>iOej$VrvhXBamgOOP4iU&MerBEVOehC{btSR -!Sv6muI2I>YBa>iR@z-4gVd@(&ti+Ry(G#c*VxxOCtdeO#4lqAvDUq|anv_6b_iCd`AXgHVYboUvE>| -EJ5*vf3;YWL2JP{V62>FMMuLLflL-`~xLOpvfY{@!EPqoy(vUK5<-DS@ulIR7!sD>_IsDl8^ivG?4*x%ZAD=k{dKK=E -8qfX3~i+*b_u(G{! -0UjbaG@?QYA9IAxU&WCPPlz%=_J6u##MYH+d4;~O-tWn^K30R8)5W#9aPv?{jj|qQ61tw~&$OKiYCPA -ngRx+uT@`K%vLV!uFS>gmtQU%p`Wc;%PA1r2Q3923C^d2)8ArgDHWtq(blABL37apm-TTzII;=D;rxp -kT(HpIXdfkYb!i0`xHZI;_9CG_P`pBeP7-PMy=1gGqBT6+ML3HZYXz{!MfH~_b^dI;!bhnL6d;uubwc -JyvCF0CSEVb_0pxNY=>TX8w_m@fH^U2-RGS$xU9$}x1I85FI5quXtDPlakAvOh@9T@P4h8WMUzi6Fzi -CTd7wcK`q}i6>PwBVUCE>punBcV7(vDFy7;9Xm^zn~qzi&s>~s-7R)dpCp7rTDpUh4`0-80 -bG2u~wNqOgXCG^g!)<@+k-h^7#QrK( -He_d*{HCUr$b&a%wy20z7gv2)@R5^$JbFmvqo=$v179Qz{e4Usbg35-i5D->U7`i2(1x2|4sU!4E^iF -t@HkI#nEab$ty|FbP?vP*SXnK}KVo$#X;zFLDZO0e$`K;KyfBzg>TAaeVncUa>jP>nu^kx+A=-*rSlb -r~k!45f3x9&p|mXvkJLBBTf3`K1-&Jz~?ZAjKsh$HDnXTE^JnnDSX0F_cC)L81@cD+eTL~Nwz*VNHB;5uiLS9k!m6|~*J~)Y+N?i(jJ^6p-K|Qo;AMW -eC~evMju_zXHQRT=#C0WhDU&b@oT#5D216FdeXJDa3AG6&R4c*foQRo`fLtO&c

1aUiEP`WY{t`~$4d& -qY0$vI;H!;IZU9~hB3dWfjt?VF`STP -GXuz$whk1CqW87)H^Ak0gX`j@di0A>}jy4ngvk;7u-6=_!RVJ6q0#xu?!A$|3FE@Z^kJbG4+ -`Dj?S<~{^Z)AqbNA_Yd+0yGiohCiQ!nNdbRa7!TDOLyw>$2mS1`ZCn3PLWs`c&oJRc3?onG`XT910s` -quq25T|r9yMW^D2hj%n-)r}(D(sMgQj*nUT39teB)K9Z5Olm(c}{1AkTG#Rq%z6R*>K)4jbrmj| -fWjNumdHQTmRHkg&%+sq?xN8T3B3XW>3WWfvPZjHJk*cOe)6~&G{*;?#Oeu71S(|lu};hE>2GuyVPm=|L<*VWa3%|7h={*HqQ92TDQX(T`(3uC!V}){VxnsB+u~5$bU0&<5kSY|lp53L=XRrE@y4&vo`*t* -<8fJtJ)3>58vc)%B#XI}fL9689nLt_;ajia=k`e&#ve!WB -VujBbw@Z+!N^RLu_N{~LziE0&Hc@FaWFvs5?<^ZgFLh%6qJebM{6Rkj`H0Tw2w-BiUtq8R=Fgmk-kY% -YzH4atsB=CE`Xvmw9raZsWXtLREQDo?SK?Em#uAn2;l9%15dtVnaU1F?hcKbc_eCogRc(Y(b>hb~cKCC4;i$8HV?JV=M+q -H{5V60kI`K%9D^OS36?w7{q;0x4Gs4#-!(gAYi;!#va3U_?PQyAhvb+EUZXzpnX)L`+C^=bU64WN~1k -6>HO-h&3*m1Tsm?YGJp|#<7<9s9rkmmgZ6^&%X9gh -WqbETX@P)vv;GDvH6$NS$#OjnMz*;I@%zErfkgk~%#{hoGk%3RdXk?NOE|Te}n2=L;hPD`F<0?%~W;q -&wU!fI<;BRHnP}-@TNUdCqFKPS+^OQWlr*q}$KFN^pNQ%)w*}o~3uu)ckIIWB@0UB=vbXZhbd_=K;4x -(5$g=G<%D!!1>U`5|&bxyXzR}6u`qLRc)$AW5$Y(^W>bZ;>^O!EnJfEMvnSkkn^CE+@g?-pD4r+I1TM8aj}8V0DI -!3zt5Ar#_@pr-l(Sq~T1=vDh_{1V?2+oH$Z08W9L&8Fg0d$uve21T%V(6T_gbDOm -`qI&jdBnFU0n%c7coEht=80^|n(E@UE;!u55uK>qmp5h^)6GBq=t)-(EM_H$kULE?@?Ptr#b;u(l{$C&))u -uysj$o<)DbkHptiJ7(cd?TtRJ47_@MfZ`D+Azg&Q&yE;i#jz*AGg9ITVkF1>Dq&PpLuPeb`9hB- -g`?=}F-Peo`MwaZJ-a&##F3G@bgMUP$@5AYhXroAV%f85+>CT^xipm-Rks5-nS!Dr-c0q&Q_yY7^mqL -IQ>rd6k(dyX(T<&~m*B@ib@{rC_Z^P0V!Fj#{mw&4*U}0X)CO>JG#)`iat*;w#P=e6$5j0gGaHi&8O* -@Tl_J+ogoB@Xl~6*cm>ur^2U^d)h{&u8b5@luNW3R(ZwDCJ{ffZ8#&vh6K(vk4^H;!WckLLBeDk{&4X -)^z)u+qZ@_UmV+LT-PzuD2vb1!sn8k9{9{Ml!40C<+ghZMs$9&iSH?153YFrg+U#FPRO%b-L=aH4Av^5zpm&?%^p-W?4rzH`F`8YARc;FH}t~|yKgIWy)|&Rx{bQQbp1^kYj#!bI8r1;%^ -n=TtVM{L8!e7thjz~R`$5azbcDp}{Xty8H8;o|bQUlM3QrGI@>t|yG1L-W0S6bj=klzmtunf-iZCr}b -lX^G$|hUAd%0j&Vq+=VVpgPH{`%E#y>H8XT)uC0`CHq!HG5Fi@NMl|eGu4ts$!Z-pFq#+LjEl`YdM44 -ie^NnPkE0A1oqL~QEiWquPbkOI}Sn829X%gbxA52+Le{D*6z)cdibk^-~iAwh1s{7P92vY02VMn(k)( -5K{A{rf>Z?@Ex07QREU0QbZDMXR`#(0js<yazW*#Kw)tQ!)ta+=OB({yT&!AkaYW+F*@4h!Fj9p=f2L7yG7*#uFr_1L8DnW*IE5-w8X7P -US8ic;}iICngv2-eD6%$*a`*L|Disx**nQJ!jLR&>!V{R-5vyj+keJ#fQ}^EPM -NSsXfh=--r>SD7Dyx&=YGFfAk~m69Ncr}FanETSqz7Ua%8T4wzo>~>ZpA{$0K|kr!px9(g!yDB&k$#n -K;%Ye{_5R -zD*W+f4e=D38qeu;?8I#NJl43Ycdr~y5paiUdvKA^dTbPLcyrAPBaZ(LW<3d@bv_b=t7{yI@^iD9qY> -^MrJ{|S}+o}=8hVN&?Azmy*?^@9>0TD-%+`qfK(fZ1L{j1%U0thJX&$Ipout&7aFYs>=GHlEyy~PZOj -rB(K*S~UUOp4g}vJtFgcZnj95cm%5f_2yhUzMx;%KFt6zfnivaHbW6qoW4=!u|Em$%0{~&@Yb2!SaNqVCF^ -Pr?$nn(?TYRt|LN!_gS*%y$kOh;IpE1r -PhLlwlnLQ96dG2GE=)sPw&kSay>jjH9}2Gk0@N9eO=M{VV?+yIIPl867{aNMivCwpJ-e)sgS|NXc7hk -O0U-|il~vLno18-D#dl|kj$nY+vJdV`MROSEj(ta8+LmWytAN^W5`YD~ljK))e!tCIcwp0?J%Rg_{O5 -+4R6m=B{S5NkzUV^jT(c1U1y{zPsya_ee~OXsY1y40F#b@H;nq^87`vB@>qN;hA=nXj`imEx7f2yNb@ -PS~}`3Ke1jdruYLtFE=|z%DYaRRMD9x92rc-3AmiIT=NlKv(z%V+~-KTQNbogkT4c;_ -Q@$aiSi0L>H|DuSYSjK6B5jcH5>~ -lsjZt}UuI9+}nFFGu9z~V5vP(r|tC^=WM -*U!(EY-AvHSKEmJ&&kdY{$08j#rAD*a4xfx3xAd3IaeeE#)q}VqEhD{McFMQAr1Vw^Hj5!D(PZW1#9bAZ -*LtO@#TROE8|^lKb{Y6x$3~3O)vvGHkG_FNyBkgw_tyjS>yg{oqeso8ecB$lEk1hWG|2^bo4#CedYbe -~Pc}+Vtkxf!uTR{Lz~-Jb-?gtw*L0M3>HNI#u_7PTc6suvBQ#nYW;;5v6FL|3iAViC{S(y3C!;G^TOP55Lh5cQ^PMeW8CJzyk+7g0Oyu`ugZmu(Ju}G{rxIn%xFECHS8z!0@XuAf(da=SwKJpmxil0cdD3lPe}yS77PEdK^v)s(uwD)PBjp10E3Hk@aAQj=FBpLg14gD2{ogXCBC)k#OB8joZOEyq$HG#pdHyH6;)*X`V -)5;o!)U-yCp?;R+PlgGWY5cuutd7Slt!*3iIVI39b)v&&sjy~23fVP|V0Z!5%R~fmy<#h)%#q3g4KMo>#>l%p0WR4mw&!0MngOg><~IT?g7BT -{)G`QaeOUFsd+zpRq+~}6%f&=2o+J&H;whd#t=2}Y37VD^FjGUrSFBlCo^w)lL8D9NCfE?;CM?b0Y;3 -X9_ASB%#wd`Izs+W5_;wF(d -+ehgY^#l9e##?zQC_%`1Opxo*m!jBaPi-65ABqR68pQ8k4Q ->Dis7nK(DLxVt^w)m7D1{aIbrfuie>eSMEQy{Lcux^Pv=zV9f1oQBVX3I2&UHG`=#xWySq2W1Rr2RHD -qu}SCn__b(=_x)RA|DA*_84lPAll51ZD{dmB1~EY6FIXotAlKWV(R+us95DKLwRMR>D_82b=HgiRiJtrd=bYdHKWtp(0EOx*SMTUeOfg50 -kxA}Wl34B;{ChpdVS|F@akSp--lu_|wa5ib*2S%;Z}APsQ?)Pg0LFc%n%7n`L8#dB^_3!srsl*U6a;? -wwVMQO?P`dzN(IHt~yo`$_q$=e<0+r#7nk!LWaDoVj0tI-SQSzwjc1M+;U-;8cB@=CmWj&6(Se&_??q -GxWCNJJfms1W#5=a_QsT`E=VI*n?ufh;TUTccQ9c-OYBSqs%c@_OKJSTY`6A*E<1XU5R7f)x^Wxbb<1 -Zqn$7FYOtlFd(#0RuIC5H|(l%oANoJ4ks$0{E*+W=uO?9mKa?xW)c(4> -Wmma1Fx{EBtD#lKwIuSyOBnduh%y`%+!6mQd3LR()gSbE{H!4^vkDZkpl=fufo8x8Oj0Nt6$%`;ZN{C --Kf7464k@I3>b+kqdkhWKmSJ6pY|74lau3~$_eu)38DAFOJb^q1%1<$3i|;e6xv>le;1)m4Ye1d5@U4 -j>gQ>f%fL#vOV+<2dQXMqWtJh!T14-o0^k>*y$HJKmuz*Oan=EN{64{L;R5_N1;t>n*QfqFazVgB#S; -u3CAH>tL)o;r&%s|CHB2bT$hf=~^C>wbw=@n9N%%%*w>`k{rv<2^aC_(D@|T^kI-d*xA7%RTYqzyGV` -L5`4fqJFs&GBQ+C_b=<-T$fPV}QdWZcYJF|POgtYfEyv3%7WlYUw@yv$fLj^bJ7+{Z+VK9rr&bG8H<4 -m6_#-OQDKuTbJ}bjVq=ysh7n$tZ7cGKoD~qc$*56AWDc>9uk-(g}sLYI6eLAv94}xZR(D6;60AAm{=~anE?RxZiu~HvmiQ@*wEOuup;3Ed9z#d0E -UTe&L6shM6a>dGl9=EA4dt7)B9vla7I27IN(BY&HX4rOynVW_S0aBYM5q;$+eUZq5xqEkqDKv)f{DbZ -*NInc3O1oL9HPQVaqjoNW5=|$ZFIGQf9)E-H>u~6H)yxU$dZXz3$pAA1n%@l`#Zxw(MQk$;a9`q+*FO -(j`q8XGp&Tb6p#4WEy*fyTAoW>4Odr8qLlA^A)1EEpcPUt>l^H@vOh$I=8Y9i-p`BAzWOM8oBIMkEFy -fL`~?nq9Z*iEkOB*`!3T3J8F1H&3#-bFudu3#t3Vb&a+F)|oCYGsjFleLtqIr5O~Gq&5kZtNfB-A=ms#);Fta2IM^iyTvhqTg&S|!)s3(13ALp -g?H!S6*mxc$NZqPKgJ!qv~KWQ;Z?G6U_<;7=t=hBzFKJo -a6sWs-_sH7U^jbal^)vTnIu0M}h`f$)kf#$;+-g?yfHHnGc9q$J0@4Roequz|2S!J~FTvs1&bF2xWQ# -CHNQi47f%aU5(z^G4Ja3Th`A~o2)P4befu_Y)e)e}8`f1ge8;Xl^#v6*t9{oCKKNW4Sb0A%_z -*2O_NuweDC8dYo44pDOm4j4myClNjTD98(*U*3e#P^DG8d2d}8EC#}Z9Z8$45U){Zpv%EzdNux1)jL1 -sQU;igZkDEGIpaF@sSjQiFGxO&JUgJ^)R6!0bWkiMG+6qbSRd{l -;cc+pAcKY@n>0NtJg^m3nP^CxfAu<~@3}sr?TQk;oS|#0QGOp(yr8L0R)jp%8x=toD-@T@axpv_;c*s -{KxHe6e)yUhQ13cCKC0&BNs62OdWNzTxy`790Qw*E4FVC5{CG_@b|F@dioi)im8GK4Rt?-WUwc1Zyq=dL;Ohrtu>c(X2iwPOu_%$QR;iBjW^ -w+9J_gQF3pY-0YTe>9Fc8JI%hHZjG=RWcA$xeTwy?_7HG1eRCua`Q44%B2&Kb<#?jtJ8bu@Nl!&+hh~ -O)PM72p|-TN$z+dl0qpZwyLNHQ3-MwN+Dp3KME=6aYYgH$=uDc=bH9o4mxp5`s>S|(`A%7cn=N}~ZkY -u5!LD@9?n7KnDyvj|1L{P#P}N>c94 -d^1{M-XV}`a=AxC(ug)burnO%r%j0U}tWXvz{``V^>=Xz~4W~e%iVFP2GXTzA?${8jyj8)G1Bztm3 -1raMSvvMV$;gH{;gEAb- -WBBk!(HN?cE%Whkx*Ej%x*DR?o&pctaZIdTg>;$Yj(u5IHnxOKjwsvc;(=-XUG4-}T@0aUX5FZNaKuK -V8U;>ITGB5}N4WXi->2V@)PYUm)dUzS!Ygkx?^QzD+y=~SxH;6h@LeAFHA3NpwDS~>_x`i -Jo-L0@w~7q_-nFf6o)kezSc^mh&!xHPVM--?D2eY?pz>8PLa6exW-$X3>flbFAZpzUcZ_5r}wG-U0|% -lTG6K#qPI+PW2YFItvTIc^qX*g37e9ZSq6qv^hx4A4gya<$b8I8N?$Z@{Kua8H-tK^x(MmwnXgdu(D* -cdSkufXyN6mMF|N(vS`yIG_(|!*W$Bif7qgT(M5cw#}~+_+aP{`ZeW0Sa+z4LJgj40O{;Z@2JeLmUWU -Y%ijTCEI#L9kfaE%N_=-VUPbL(OvIm**oiy7YGR1AQ{%0njNr}!W$0Yo%;x8y?Sw5*&ID(KbY^VMMO? -f^?2F?KXvtGh_yHB@LxEZ@aFTpY3mv0^iVIBT4cAfPItCvabcIfX{I17eS!SK@aT@fZN4$tqEvn{K*h -Q$ja6_PXwZ0ZG!tAxW91nJ+hX|9Tt=6OnKtvYLM@z?DYQJ^hSnlhzLDY0ZgXPHtuvYHMr)rs|LtmfM}9>K0&t8fd -70<%leDwpI{)@n8uG><8c1m&L@ht-&H*ysq!Sy`f#6(&p>*%q^^!gz@Sd5A$!4A@YC4)bQze>!;O;Q^o -&g7&2vheB94<|JfV4eVM(LxGb=#UqLyl}N22H815CXxRieH^Xx1>XdcRL71lUWxd`B3|iG%33qStL;(LoS{Fa?6V_v -p7+M*>wHjQ-(pG;O}ezs^Q=4O9lBTU5H6 -7E{G8=GoucKv<3>8KOq -&AQ)AUTDt-PpzxnRxpML)LpMU(D?|=TcrK$rj(t%0=VE^{?lP`bxJtq*}!4!e={Fl$4{`x!5pFaN;`| -s(m|MdA!-4OXysR+ntKX~>l_TMj_{nN8gpZ)ULPn-a8_FM$oXCMCS&p!K$&pu{<|MIgRJ7JMR76JC<2 -OoX;qo4f8kN?UEN65r9NP+6N8OVS9@ZUfAU?MzHg_)p!@&4a^@&3QS-#_{OG}t7+vw?r_AHI11&%Su? -&%b!j&C-m{72)oG|KLae`SVZy>xVycg5)D)0XQ!{{qBpWAG~<_p%V@aT!o-K`Rf-SeecDSpTBtW@rx( -_{Nl+6FP{AL#Yf+90#%)9#l5Wn;a%-*1lJ}4ev4D(slj_VO3-wGRW-&avHI?%J_e9eEdAiK567-~=7> -A=ntN{^aZ4xkU;XefcGb&WNetQ$ol2d^vU)nn0gu?FPaA7&j?ub5;x`QR5N7aB#H4a=`UTFc_v2$YY1 -8r<*?43=VFMN&jR!S4gTk{rO84$rHV}^cv2V4QZnxyI -2M|2^6R@7|4RZoy5h{)I|vjp@!ySxG);0<*zgE&LF10!|(h;*T4>P%I&C?L`TBbbrY4x*%QsiX -RtIpMU$i4H2$=s_$bjvu_4Fd#$0@{JN#tx#!U2@cjwv6>p#WD;bqw6r6Pz;9BD1bg$^y+3^YjjII#XC -{5S0T@GjdBzRiDK>s$bL?TBRVq#;fUS^qs^u~I -2O69m`;Z~coxf)PP_|3*8SkYt;LzgMX+JZ)gdD*7oSpV(Cx;pF;>EqHY5cvZF;I~;LbA<8{yNDA!Ta@ -ID;zGfIUbh8PE^4FKhnJZyY6?iO*_jN9_e| -D)-ZUl60jhTl+0hT&u8wksKTWX%9OEjE@{ct8pm~h=Hvx+14=UC^7)wSry%DEOD${M8T%>su>20|3l< -@f_4E<5N%`Y#E2mqh@;6+z7D8Ovo#1!V&FhvZY+8yaOF4pJ38M}9FzQd8c_D4rd5BzM;T;*7R&ESwV6 -Svsov8ZJlc!A|B6|Ac4MM3KgthH&B=oCrz7qBKLh0e~ucd0 -kpn-X}X-Sh3nksm)Z4S~HV=c`fLOU>f?k6$&NgPFJttgfZ11?*_M`29e7X_#650A#4zzR~dg@#!LtR{ -#(c)eQ_N!dui{217Zl^(_>nbQP_fU}-2b8p6A9lqG^b}1ZHMjAK+9c@oG*1Uz=N4;U@=8nA@GJ6MiPv -B_Dg7ShQHmkglnEuww3#nJWycFqhe(U4~M+rwu=F7_)yJSkoiv{jCysH#*AR(u59)HSD>^N5gKM%E*7hHJh6p8B>trsdG2sFuuJ5cNDCpqi|C0 -5sySw(i24U*b~^IPz&0Gg=JnFTOxWr>BF8=mFG{@cFo`c%$mEN;t5!aw&032pA@s16O+%t-bC316Zl@ -Hl{bk5AL6oAy$1bY5?{6E3L{TmrK{{!6v22+Mg6#jcTd)BbnB!oTkE@tdKK9iL6@kYe4e3%NeAf4rV&#~Jqb2E3Q$SehKxhD)raTpOz;&z`(aVC~!P)%`R7 -cCiVPQC%Aygs{+(WP9!@~(mi6j$!3`;9ODt{`9(d9U -Cc3hm@vgj?MOoh*+ud&ex@6D3&9%_Y63e65we{w`a -wzuS40le~GagdWUI7pgYz(FrYf#*@o)1xM?t>}%?@qD1RRhs_bXfzWKbv0LPoF0rB9&-DnM(a1=s&U? -Cj(D=QUCbuYh$^KGZa1Ylf{nCIK#~)wwSmxV#q24?;h}5PR5V8#^MfNBbo0AuQ{)t$S#$`XPF5m#CWw -`}-aB*r0P0u54>mZhRe^zW1$HidnvTKWX^lF0mRUd`NQ$OsoV2i+p|oR~JH50+i>8#CBq5Up9G*GvVK -l-~?hv8@^rGWte0g#aS`U=^18wj@p?deF(c@A;J}>mON5yd@)*g_pJ?ly7J`u(`z(54@5){t0#T*8%{ -WQhI6$kfp97nFB5fTxYMLL8cJJaGT4-i-UP#r1q&nrQ5z#b8wC0bKAgSMCX4kbU@b1r4D%eB2b@bzvh -gpuZ=`Bp7fYz@ij&IKH`s&WXyaT0giWM+`Srl+{Mc+o3`VUNvx!muQ7NwGSZ6yxi5z@`R -46%?eZ|Gn5IWrX>T?Z6?$lNxwW_#&G9)4U#6j-6TmmQ<@}bBq@g`nMo&!u3Ra`rwLd!-2Q`C1(KS8@J -rGCHeT{q)N71EccVf=7EHXdm4O{xZ=e>YwEJD13;7Rl -HXI6|9~A=N*up2*Or{@t}9AKmgRW%>DrMTC+p{;I3z~Hh(k_zNSeIb|Gs?yBzVptZ>`GZA%X5jccam0 -90Z<;<9NABg4=l}EN>|GU%q5s%Lky6An;mzITR*pm#3pZMcB~cLZG;@O}h;D@|JSZ3G0dO`4N@+aH9^6C%yf54|jlIAHlERO@d?B -OE&9KN>5Xw|o*<6ajmBJVdsT^OrArb_ZFW=Y^7nGpbaVeTU*Iy(#&fhq*iNhK-L1J -Zd4q9DT~v55U(hQE^JTjtX+NarKr2S|OIXONg;q9-H70%`s=PDCn0Vh)G|AOHzn@jV#NW -R$1xX4MQ=NN_|i`DBG<{mLMBx2KErRp;*QVm0OqC)_i<85my)QuRk44PQ>_1Tuv^29ltwyCk97X@IDx -cPvh$k7ay+$KunI#uYVU8@5Ryi@8a*{^LHb0^4sO)BXM~&xgH;XJUyC-%a4=Gi>ni0;v -G;vAD_RUKtU&GC+F8T6bxzN{F#_~P>S$@rHK*W$y)>AMq1e0u`?9lbq0; -nG05c@zu#l98Jbo -sG0YZi!+iGwF^iWL$)3qmkIu#Op+$3p_ -oWR$)Hn{c6J=4c?`X;#n_Be72=cmRlqKTDtiIL<83@EJ_3BZ -9>Q(~}fH;a=ZAzhW3*=i|MBY*4k9HRJfs*-+Q66bcD-2OB`yn6ruvuDIt_NyQ4mm~~o=V -K~oc}S`NuodXRO;RZo3OJJ444f)9A8a|G!^_|IfedhHYqCK!i$A~oA`TD5KIR{E=O0l1>sEj_`(MOQh -r&7-iPuBY;7kB8_y_@i=+B~ChqQs{Su)~`09^g8Oo|+MS2zH+R^xM_=zfTm`3->V%{*vE*Bg0g-b2oKU$w?hdTF9jcS1I;3sW{jN>RD=+V5Lq#6w7)ge*94!yc& -uZ;+5jlP!H1`XM5nrWANeAP-3?*cfsSMF5{U+x)A?zsNXMFPKu9CHZ)2lHHqJ>n7S5ZyUfEsU(TR)h7 -xSuf=+H`3a0-O32iqLisLdrOI9^#pkw`J4Toi_eDvfp6Bl5)Gw97uk|a)QNY6l7FF;w<)b;9WQ5lo_; -q_+ZemJO;^JOT0D_hcQMVfpVdzUbn+Bx_`?Z?uk^c>80!r1j?QZ@2gCX{|2N0L1WY2NjH2O=a3o!$sz -C9Qw(o=1K?dctUo{Udr7ad13$$+R4E?8ZXwJDk6I^_$VGf#K>4V>U9N*6HKAd{qOnE`#o>!dOriJL^t~JA2%tz=j&Afst7-dXK_kW;Hh8DxMx$0 -Hz+ExFP+z=N`=**V$gQh+7Q1kP>Q$M(&Zsir2T4nxhXP|j@p+(-UthYhmG@RvqoEL!!}?GcTG+9W?<3Km8!l+ -%mXjs{zl{e(7)h4;5xM>WqiZ5P2>3*gG?ECHaj=si%H7XoWz2LD=|MhmVktwk73T>)?5j#{PPK&}F$Q -^5_cH}HFfr|R~68dS9q?XebyC$N>*GJMZf@OTE0mu@!autqjRiz0A25(|KZt}UCZNDgD1xQOb4M;qH% -N<&$Q<8e|%#WJ=gMx8nr4rrmoI1Rh_%ahB4m-}KCL>TfR0gnD`i05^qp5nyK0*c4Tp2^|pq8LKk-}5| -L7(y2vq%`1GgFl*!VYmZBs?J6YvM3!pePL7$tOj%!#Sf9nM{o1b|EZLSVXRS)G|e^=&taS#BC*sg6rH -5bKu1{swHa}x+|MPye-i_H0RL-b7%K}hbAu@i11n5v;FfN9yTZ(3u$tS88IgH4oFp_pQ~YMhH9Z&{Hr -Upqi3&3~>S$#J0%4rh&Au8-wc(9b7DugqExXQUb<~WgyKBv;BMq!#+`r3JTXdVaK`I4%49d3#)Uefv& -5yy}qc{^-jCNk8F;pToMA}6jn)UYFl;+-D5Dy8pi);+4wwART$#VyxLM5Xj49N@w3DO|KX<<)V)VPhX -ygp~ZgyH|zK(wX5B2Z;SMf_%Xpf;IxgRkkQ<^+P&S-Rexd)rqZMX!K=6Q+|TIhb+4v)+i{>&mBLoFZE -E1^D*~0Hsuu@6f%>W18Ft&4RB_5}et`79+S*O3C4u*vj)C*sle!DzO)N{k=IiQQ=ZaJ9pC}SnsGr3SY -7HL-<;;RRqSVuztl%nk|>L^k*I~ikoC=w#g1pf(b}3jq}7)gB -y|w38v`H+_XqDW%m;4X0qB+v2MD0hDy5zIJ?pEGn_MUOYC0S>jeaV8h3I -WnpQH<(OL2;&8CB{WXZ24~FLuszVI0adkdlRH$Eszolfb&$aXYNLyRcSTdT;|m-tRbGM^|1VO8qjmzb -AOyJyLC^K$%QS~{a66Py!lD{Bp}jWCb1{eZUrQ6bSu|X!ea -r%51q86(YRY^7Sp~1HB@~~Js4#Wb;9o<@8@0{-C~)m6E&TO^3nM-k2Atw2205b!gPG#tS)r38P=L)7s -|&}Chr1|s>FQu;xLpn>Dvn;ja|NNg8%q64dSn0P3uws_|rqf!Sxx*I_PmhHAwTdL -R`(NRX8z)Z3Xt?XcpWqaea~;=P|us@_PqHp>4;Vdi4sZzS;<(*UHSLNxdq0FjQ@&vl7d4m#ajo3SX`q -d~OBwrwivcVh;t+_zOQaCUwF`C7_0UNGA(v)7SGxtj5@hTWm~dA0~0T&>O&GA7Xb3c{Kq#V$a)sg!p1;ri_KvUnr>WslJ@|6u -@SXr?RDb51L&T)08#ECPs@a0wZ4D9Jt>pPjs|q#%$@K`6?1?jUY!Lw#E5i -P;j5su=hgEj=mUF0iB>q@|N^D5=*N(xaVpjJw#{twsJmsc{mXG>_NPz9&_+Dhd3mvI%Nk+7D;6^%%$N -Ns6r33-=+cgI13@wnutR*XM$nG?`|(L*atBA1CWcYJIIN@MR%W@*Vky7|u=33f5QHrXrnt_@bxtHAYBBnv6|V~c5WSb^)Mm<1H -IUGtB|$JBnb?2h2ok4A&nUNq?YX%}D0^;vnk1Q+Zm{N3A^%i2F_E*AP)mpQ=r`hW)j+9-#FP;>IxT~+zxCLC-Udl^vb&``fr;R| -eD?$?BG#-BoS9M}g~&KTkq%ZX6o`aXqs^bLzChV%H!P1_uniG$qaq_0rT3nkK*Z(Cnkuo7cx@5>Ml-4 -328AiZwH}mDuAVOqQMzCUJu5IrybFR8j=eS|9k^+3Do+xa;%_8)N&?T -Tw6Y>k|v(sxD9qbHS}N4u9^OuH4%e+xWk8RqE@$a%DDu?q8v1v^>n&_3=S68LVgSx4-t4jJJx%nsa9E -y7SLS?!9P6)k6L)V$J9Z-+}8?g-zkvK`P9+{PN*uW$Ze -Y9T>y|5A$&db_~3h{5d7dy(6F_+H*Bi-VO;d`(ZiCaTtIZvGA0V{kK7D|(Z_fdcHW7&vgiUJo27b&J5 -^8~Nd`)q%t&(kF(VO -o$htE_oGySMdP-arGotXu093vRs0Xc!(4K?Dp#r`4nVxRcjOJhKt>Z9!=9MalH&g47{T}n?G63uS1C{ -?dy=zBEAc7HT-p(kzuJv_sxQ4Gs;su?}V)1ktM_+YLT9a&v#yMk)a2yn?cb~MFx+*ki0H8HF`- -#W@oT5cIi6^y{xlMDb#Bj$@G0cufCf3yhliTBe6%)kj#7evgRGj* -G;4_Ad)zGJ;I|BT4jUaz@R)(jY!>HGsis|U+p6MNLDu3pg3Lxr_`xXt0^vGdofppyLw8C -?3h2jPJ~R*>4$#7Y8?7v~2Am;x1{h=9VYgN^1p0pcj=%bk=)f@|1o?|3E0R?w7->qb%1B8o1;@O-U!rZ;S$vP0~_ -1Asb`;U~KhHBcS7bf4Y03Z~0XpqIOotJK2tGoIf)w7N(j=Gz2CAQeN$T-tZC0SN`yP9&h6hHGgsSUU- -vcH4jigH=h~2l4?WG6O5c}OIl#LiQ_qRbck!q5%mbR`WCScalwpGLwj2h -auf|!6&Kbu#NhS;)-3Ye{`sQ_WD!YS$+fWhlTckiMIS|AMNgAGX%a)dq~FzqHQn|9QigqW{2q?CYbi4 -nII|J+B_0uJ>tY%pdGk_}3rTHCUO&&>XpzCv2v*3@e2LQ|Xf{88+4#U(t^>`04FnXyZ^{7Z+9#5osT=O_RbZQLg%>-WneH@{u++nt%X=unGj= -H3U9acnxBH)!$zuOl<2n&U=fBTR<=~(!ANA&#`$i -|2|g&74}|SL{!t$on=Q@LyG&#lr{WGBiCzv*_UD7rvT559;xr-1Sa|MLiD+fh8hHb@%$Nlco()wat$8 -eugDOOx8i#Gy+&Ssl;t4;fDIAfdjyl`a31d&a)K0=W0jxZeeD49?n^7)0*p-8>f|;h-q1{=cj$DLJ8m -Hdr-Fj71gQjuF@b*j(9UGOwJoi+k0w^iLdxH>08U&TJZvVH&0LY>S!beg!;_+!!PE@wAE^ydeNBD{qb`Cfpa*5Pv^87W$=Cg({-edd)U -YY!XuzqZAvJiKX~h0hmJ8|wz6xs4sdD_$gHMC~ks?v!0U(U3FY_MU2q#qoHIw)rPlhXVQ(3o0NNEa*o -<%NA#Wiiqs1$%L>!d{wHJ+}Myw>xP)2(aoEiT3MUIbQR3)k8or-h%(}^4-z($yNO*d%Y7;mt3>Q=Fl7e>X)%-!RnW>;NK=!^x&TtLzP6$-m -vxFiL_F1(sj{`DWK9!jo57)p`o&It5v>{_~-u&D{hQXZNrQ~HR`!B&8VQ2JF8lXaRW?Ob8EW`2D4Iw$ -K7mbE6XwVTvVq;YZ4VUf4JWEi@!nu{V*z+Q@=|4BzUXRDmk?&6v}Htmy>5S!Grf}(9Q@8pTMirP|4Wm -R&4pi47G`Z205-MaLdu3^0x_}JFaiiig7Y$8M+bOkM@SV)D*uy6M-*X>?R<>TDW&u3?194i4`S~iDQr -#%6l2o)wgPIkGca@-6%_2PibC0#rr^TD?@pHyK;{no?mV-&zVfGR7Y0X`>Jgaw|qP}j^%}^zJ~|Tk*8 -BFA;oVAAKK?D_~g}pYm4%f4)sly(B&pEo=)uJVe{hqA6{xXO&zz9A+=|TD?Ie>)&qL@1t^{RJ?a&4?P -DeQfLg!UkYhKAsS5&p7PQ#Zq>?$+V$*32a%=c1Frb%?IM@HY=Qwc^+%k&e?BQJk^t_SlY;fFysxKpeO -1Fxu;|wgUP}2f_CJphLcHJ(PV0SL=TWq(Dj@?99v~40Yo~cP=-;u4&uQ1b**vlj?#NY*)l(IJx){uO6 -ZNF@#q0^Ju%E|hD>BYR@jLnVqVyRoC*EDqXnA7Ct($XOdK2&( -UwAj<=2Tn^&x)_Zkv3(B9Xa9@h*DH9w0U}-}P%3vdfsM_hMETd|{MM$8{Qbx4Xm#=rV(or$1cDR>kvl -suqr{{qV_jn>{&$QTB;$;%gpQq2C>&@QAMX|+|AMcI%%0d?}#Elxn-iQ}JsX08l2IK}xx-r1;6+u*bg -XY1T7GRSeEv=dqIe}=Jc|}{Q8Scou{=p8yv5-#EW?MzDxITXE^VN -91a`Riqok()@k~@sEYsBdaM&Es}4P7vm_%7x`6TOBKS)MJn!*JRvk>nyp@MfHKpr>?4k~pHqoyE*}mG -w>#AvR_|n7PXCTO!ddI{I3I-#2?n5`DjTn*XQ5~~WU*=0r>e4k>N=xPeyw=&S;rOnvNy#H -hC+}6WvQoUQ4p~k9&ZBKJKd@;PUuV*)%^431!;y+<%8-YGY9JOwbYHNhC -(Vr9gJyyG!qZ>v<+JR9AqdjB*gD)mb7_B6QD8~mTKSGA9~Nmuz6r`TawtM~G4)-#iRz8MMyntLTq*CX+)dR@5iPdoXW}@<6Mr+ -QuJ^`sWsBRos6(+4itn|gT@Ek?ozvI!S$0%v5M>VZg(1Gp^j6*7!nG4Lo -@l9S%wH8cno1e184?D@Gx7!YV%f!`r_2$~1BC!w=%;iKOF;{Ue(HKbPyCGS6fMU8)lCBaKI55C-}6CRg*FTxzUAgo96$sSec~!tg3WN5#6Vz?+ -NwU>2#L)x(v4`C0+eV%gg@WrF9pks@f2XO5YaN71+d*rfkT>ks#F&jYQ&w1Xwo(D=60!kXNcE -r53fqQCwhFS>~u9m=5}x_#hLxmllPDFpR}ZO=X(C5l0d0W}qGYfK5%Zw%B?W!Rnr(R_`P{oG29(!eEkj`^=zW*F8;tT+T}mb_Fjz<gSPt6L+A};$q{0 -IylHtS=nBq6wD`(z;P|sXbij+IvRv3QU%2uMn;e4nsYv1WgKWf@zxONXx{J;|qpB7qzY-(8Y2T)4`1Q -Y-O00;m`Rt8hVnoZWR0000v0RR9b0001RX>c!Jc4cm4Z*nhVVPj}zV{dMBa&K%eUtei%X>?y-E^v8mk -4*}~Fc5|Jh2CMv0fM@4Cn&{*pl2vUoYr8P36s>~?M?r{MYr>P@9{<{RiSxN#Xbo;uw7tDaPx_zK|{JM -%Hn}<0-Jy^ej)KHHNqX3F>RLgVAG5H1de?R9y^L5cf?$xlq!q5#y$&D*Kh)L6>H#*64_6TI<#&^l+oF -;7dCIr(oXzC67y{~c6xu%M>VdSX6QjM1d?^z|5K}iPYh{Wxy)!amw(*0>_+hiP)h>@6aWAK2mnY{22* -``X$J`c002k@001BW003}la4%nWWo~3|axY_HV`yb#Z*FvQZ)`7LV{K$EaCwDOO>dkq5WTOo|G}XbBd -whKN*vOpN)PF(YBp!ff?3uo*seV!YJYwG2}_zZT!5K3Z=T-+IT~$|47%^7>bINi=4ACqj5LftgX**;G -C?f-n!urZ3&UE`o}twWtsa=@gh7}GZ$s}k^=?w@BZl}==I>;Sk>kUubRU-0;aFi?o)oq>!n&FH#`e<) -3crV9gl#t+oQMOQ49}j>dcWNeeJn-A~|1I>MQ_vQ1`eVs68p}MfYDUPy7v>?W>sZQ$^mFT+C$b4P!~sR`nxmay=g()Q7~~(Y%|R<)IKyP6L)pgn#FM2434UKmpFI -{yOPh^)Qb?;aqS;?xSG%I~9gKSox_~9I7fCh+cM)>c46uacu3HkJ-(Z#lQp2I_#o9wL=nNECOgX*` -W%i45q1${zH8F@jy@$w7-duDH&STD;1e1-m-v2)F`B)p&0F*!}JBOYf-#1d=-DO=o9%SegY9Cj-bi|W -5F4%928N`c#i0(@5kNDpX!3>7*uPu{P}73>cd~q;po1JzD&?N(x(6M-Pm%WsG{M4Wzjp5-o(qrf`fjE -OY(svriMKIkH6!Ya>ZZ#jqzF;0*(JdcU3Zj!NI?vgT{2Oj_hfbZgg^QY%gJCVQ_S1axQ -RrwOCPa+cpq>50L*rI2a}uhLECrD&U7LO}hcxP+%_lDA3Y5CPIrENyTx8{rBFH5+%`;6AYMuAQE{z-r -e`z@n~^ql(x*C8Zg&a!hh}By0l8kVdR?>+v}_AtDRN{)`%uAo}jLj&Nckqg0Uv&6>ltP!@3o}ZZ@BP_ -G4jTUaHz^B_-%y?2eavxC_HUkcNAi52CbAuAkir2}jMFW~@ibEiWHG;?!3^McZCqm697X*`~898(Fw~ -e|^R95%m+7qT*K655)oOUR8#z**}ZVUp9*sTYR|x{eE-5_?Hxud<8pJ6rvWkC^A1pj{&(`4WG`L^`EM -Sc(4G=AIy5A+sRZ2N8zlGmm1Il&HM&Bp4mgIg|VVc?#8zgdaq)EH(WoM@%Nj@qyOq-<92Q_u2~|OE9d -hv55e&IoSNk{Fdeq*0oH8E#Ex~48%CBfkOurvv^uzm8p3;Ohq1RPdp@Q#%NC#R5!hvqXB7P%$28C!4>jW~IUO%p4C{m!hjV5_phCC@&U^;o~n<#CWeHXI~H(i -$HY)m@+%15128kW>(?8Kwt_xXn<$L21FgsV}p^ozZT#h3ICbLQDmrK$)lj;0pw{1!1BV;Dx -g<~yX+a)l6_lz%L=j`8y|2p4i;LX8w4lzC@Qvsb!FZn11cf~ElNmKZ?{41)9Z^z)oJ;Gs2}&e8ki;23 -Dml~5l0-wJ@me))*XSPRsl-`-AM=?`=Sy%crECf=z)E0z9YG&Vdw}W^n8l6``o!&THaUl -dtC@7_Z@+oNHJyDks$PzDq8CW3S|&_MuyM?Sa^KdEP|cJC*ZCBE*&@+GLj8b9tw$k9%%_-5kGtt6( -rBt!wp{B`rDM*yTd#Dv;mXGa1`P)h>@6aWAK2mnY{ -22+OKx#&6p002w_001EX003}la4%nWWo~3|axY_HV`yb#Z*FvQZ)`7PVPj}zE^v9JQp;+?Fc7>O{11y -y4y68oKn{H!0wwg&yHVwJqDGdCv~CF@|K43YP3#^@+R9*IW_D&Ya+YOj^0GzHO7q*lzM&?#eO^KB1DK -|@*q|fhHUlFTAnXcj)mZ`)K>=+8swz#Qsu7I4X|VBO50%kmyi;Lcq)8?|b@0uJErP7>1HqHmyEKtUTN -NYRsfhRDl@DoV3&DUFyTS%3k7(;T>~Jp-oK{dKBCI{FzCvU57=jP^Y&;*w^K*Dtw!=TjRA`a#UrDs}a -Znf!w_L%vjR$UVXye?=w2-ni&QMvNvh*KP{c`Qy%mJD<7!~?jlnN -voE+$@tX_yFtoj79RZV^Mc49%`GG|igUIpf3;NN*)I#SLE@s~t(;%&H<)m!>2~bM|1QY-O00;m`Rt8f -n2Y-DQ0RRBh0ssIa0001RX>c!Jc4cm4Z*nhVVPj}zV{dMBa&K%eV{dJ6VRSBVd7V*BYr`-My%+i)1iR -<5+hE5*cNwMh9voX)ygHU^%U$~KC#T68#=fWp#+Ie`o}M|LAJ!|7)kf+eN9Sx)1r-y5?E^(Fxi_+Yy~ -06bV0a$WPcc&b()xW{3I3#+UiH@MgF{dW!g%@xerlQPO5DLlc_aPYA!sG6?;Xa=HR3U2;siaJEG39I8V%?zuCh)|PKVd<-%zO_`E{JB7q=b)Ju!52(M~&5ThH>6tLsg&98;aFTDaPr8dc{;tpz@Le`Kv3N -{eHWfa(_9xWcVN6jUqE!Hv`&Kx1rXK5}I2C{)|<;-eGW7D@L)km(33HHS!TwOkRp-9JuClKzM}gttNA -I>qYgrl(MW%EHEEXO9KQH0000807zB_Q`Y@W`7ICt0KGT>044wc0B~t=FJE?LZe(wAFJob2Xk}w>Zgg -^QY%gPPZgg^QY;0w6E^v9ZTWxdOHWL1xnfwPFJsDGtL_2ma*Yk|qOPyrKb4k-l()NST)j%X9q2}8Wpl -$W${`>7NKoTG+S#EopNg|QJ0{i~#0ttfP>60&O!PZ)rsa%{ep00{Y>UE}ASyWmiY*|#SR)XEZQ&x$8* -FtF(J$(}3T$$l0mKLj(%vbI2O0-{No{Bu-Rr^584BjrQB4Z-sGL332Q^oAtl2=M3T#LE>?dcOcu9Rgo -zXdWy6}3B1x~gMcSE8MJ!IikomB^LU@>aZ&v2IC3F^_>yI}%@A;DhF^5|!ks{H-1Fxp`0_iKkDHLs7B -whSg{#^m}?1&gVJL#C$%%aX)^#gh7>v;vy?$D#9xGB@C~AIXn9H;QIOGZ1Qb*bOgWg=T{T>b@dB<3;% -^*?X!b0!heH_SvwI+BbRwy$q@cb&YnJD@BtP4fX@}<3>U5y?2KvPvl1(D&sHFXoXMQME=!P}yl3CBV# -z+eyI`k(|N2#g#F_ns3dE6#DdV+XqX}%Lu&7>78OXbWAIplbGLh>E@aONQ-HiFNs*1W)FbcL5Wn9N=8 -Wox6p&ecc&|S_#^YrS)_0&$hI_nok -FeO0E%f^=rvnz=vtdS@60uv;Kr>fD~3~c6$6`(g^h*q`^#p#U+lI>nhEQDhuOOO_^iwRwduVJL9Zq>OX#Zk4lXz0Z -{`SLGh(vH)2D93kT3nTkHH&Y#l$K2rv|8NLjP#2s%3^Yv&TQ^!7d$rItk=1|Rcu!}vlKX|0imOYq?ew -x6cOok$|&8rFWM0``oVbshPeCC}}b2&Z@oYIgx++V9=40T0M~Z^QTqW(P-sJN|%Okgp`*M4Mdmd$xd> -o3Pw!gd=kpVvJ%g*+PI8gi8S9B1C)}rxLjW7mUEr1pJ9<`m5+9Izb|zb;4e~in`g>W9LRVq$|ergazL -Q(XWNf!z)LN*Ar9d@IK1EI2zl3gF*PY|q`LTmjgq)zR5)$;RoxoJURB5`$M!Yx1tHySQ -)Y#3sgtCgyh8b)qdu{C6bFx?I!1yB`;PlHJ>XxVV)PDPj~%dkI^c!F) -oycX`t_yL#GlrcRrX3cY8;>E-t-)-~U%)L6kZkFxS)>S_<(9=yhrHBKR5}?xe?S6bR)Ob@` -K&mSXs87*!qy{-lsADmD1ecG1+QW{NFRcgX_EIm;^)TnOlI!8)+84EAREVlCnucDEMjJ -m^|6&oO{N1=Nu`Y{K|VL8w7;Y;hD5P2~~*$XKD -f#$aX}7PQ>}vR)d^eh^R;=D=j+PJ~MD%>B*ws7PM470IjUrCXC6cvg@~Sd4U!as}=xVZsQSy~#d{4Lm -Fb*IlEG^zG82MyK^Y$V51@5e4v8s~Qk%C&`i%%GPMHp8_Af5CSl-$R;>ZdW* ->@M_}WS{-2|Ps4u@2NP&Ozpp^ganHMV^~Wmxf$2~Glk-eiY=!gj|^6F1>nW>+ALG-5*%OP3BDfuTn=b -HVrms$S?Rgjf4w2=oKw>49NJpFe{>G1-tbU;&&s?LwiGm(g@`aSOH&!J}4g(CEmaJZ;O6LJR~_kwn9h -evtd2u2zm>nYC+71MhIn7VU3abl;c*r2^t-nTZJha$8Nb_w%;PPw!V*=(h1gtDGy -N*=rYc$8}YKO=I2zDv$v~$b7imj3{pdEWw4D$8er$K|x%_8Gwr==Jt+m4|{z1_~zpo`vL)uTBx9L$gg -!qZ8|vGJ8aw<(rNcm!@LwT1Xg(XFU5MPy*`>M=eq&iIB-kA_^M3i!r-%9C?_ejkLIad3 -N!>*;CL)kql7J30?zp=;~wHbKD#2NIA`7l+rwNl|D27xT|?n|GKiwhR4`dI*AcANEikvD?EAW+25bk;u27R_q4$)ykXJhz;_^zPl1y85kxmZDMPxu7`|z02O+?v|Zd$Zs7IYpfJlsJG{pRWY*-@+QQM;jqe+J1QX5X{Aq3md4Aq4x6 -8d>(?Spx-DQk}H@kZ{rolE#4hUxwvy0{eD;8);2wrJPP% -1L-9KiytAjP;Bq;`BsKeh_X@Dn!rE7FzW}N0u|-m@^eih9xs*_7KW?=TcG~PSLO6fL_ei%H;4f_r!J# -&2C(awA^(|rA8uOGbie$6x&cN2T4p+kCHzZwNSZMa+~s5I$6bYiWmBTImAef?<1=?frI7^u* -^tDk>{&~iPFQ-&PPZ($vsyQ%<{O`(I)B(XY4LHePci)P7AqK$+q*=ZOmgbCjIevj8J_Y%+L*l;`3eu= -v6k|nzxN&kwK*1mfSRL$VDW8Wad$-rgDoy-HsVrq_C!~VK-)MNpdi>QBm@N!a7wkh$<0Y22!jJ5DCsc -$yVTT;EU{^1Y_qvwqkYuYQ!VYw!Oi|#x|R@ImQ!N6Em>UE3}^L6T=mIZM^Yt_fOI$+&X#$n*X@V -jGeuT(`L#2OAIy9{~#zTOFg*6?opks$17ZU-B)^YtON -cec3wCHa1a@E;-9$)C`R6uL=JW!%un@tqukHfFD3EsM;!*wX(}l(}{gV$v{cy5#S=8?zS$g!$Wpw41E -Vb0Op_82uuxYE&Sz4!HgUV4IMUE}S(H-Dtzt)_-pnPhn-vL0jx-qndw{?psB9{ -#?w2#QFMf$kU>-5xJ=MZFG+|;FsFDBsGdum9o>6hX`lSrm -sSS`p8kWhChLme)!V=4`6Bhk^^BDn>Tn9Cy%oT-giJ&N;;eKk=0nBqngUf%VKb9N&{>DBcf6N6iqlmu -FY+h=a)q1c6mZAnd6R>xYyj_oQC(-3&HraT>#21%WjPHE6XoV~1opI$tCotWdJHV*Q9gGU|89ygi3h` -Ieo=41MnJ|e)`Z?J#dXuH??>SMCe)0A*HDm`N9U_uJVbdus;|o04p#E3Sf7@;Jg=&vi9=6AWCRyU@y6u;@joWXqx9d*W>ty_!!NK@;CE~#& -$-&-~Kx)qF4;+<@`viXeOuxX-ps;N^zio>xZo9lwjD(rsxk8P)SI^-^pNefF;&3{A>9u_a?coPBYLzs -Ehi!v+pPN3OdWvPQdp)L!b{ti9`!8szPbp4~Ngugd<2CD7^dOH>{m4ncx~Cs5{N3mL`HcsU -&<;V2A3ZoO;PH(gHCyfO(MLFv>K<0#$ch#xA8Vaaao25+af`4>;(f!Li17MR8qwKj8xjS+O7j>xLeS~ -RS1wXIeC`>q)ErgSp?V=by49MgU3gYbn7NSSmU$bPSIYj4xMbff8e0pZ6{T%%+vBv5$GgSI+Ai?D2Y0 -1v_87HpVQe5q&nY=)y2Qq9VjGpBPnJ9*^-M~AGt0(M0Si&gg6N!4XpCPEXsu2U$elEim@uDSN_5w>*?YShaoypaj&Peh2GsUY3u?0LHkxhx$Oq_FC4=LQ -oX$^SN>2(b2-5o~R)TxnCZ!a<>*e4kVmGEZDZbyO*Hr())8;sipq!yX#*X-7wZ<_y|(R7FUY;ElTP5P -a96LB~@IXP)h>@6aWAK2mnY{22 -=N9hCBlV001=#001Wd003}la4%nWWo~3|axY_HV`yb#Z*FvQZ)`7SX>4V8a$#_AWpXZXdA(LmYve`{y -)W#4D8`4K0Y?sdG|a(qVhDsdWCMHH4WcELM!nPO7Tqn6=ild5_k2h*W(fo$gV9J;uU=KXs#fb=Puh|0 -2j?UGw2vHqeSZH={%WH_phsm)rRwdIHvHMEVPL;>)ii+#Z!nIf|^3A6nwzSJeq`Vt#LyFpgvIFf -pU3aw8u!_vYFYNcR({@9iRYTfFM=E1gW81R7B?X9G$ChHJBDEkvI#6v~U^v7K#;;tDkrAstu*LJ(!G| -+i?QCQl1GzQ>W%xqUl=lw+Q89X50VaSt)8O5!Mhs8_3?UWvW-nY5iJZ|1;IA&Rl7fu^2tD@|`;ciUYT -Q_v14yVH;Fo2&B7>|2aq!&gR|?2JWIXGlL{@dJ8xTiUdkURu+zu5vQ!OSP$hQr*RF>N6SeDDcroBb|Z -%=hO_Dn8$Ta+bALF;4Zm#eGyXx|zbSIm -NytH2V;&oVmKt5Yd<#o!_(npjO8B>gVNA>7~HHLecDfbn#;aDH?5@eU$I09*4Nze2Ggpgp1JVsCC#bo -~!Wsk+sW_!%^*=RjoMi{+wxW48$1#YBXjF7f50d8g93Q28KokhQ&{F;EC>Qf|1(eKXk5 -mzpLt$BzS4ZVOGF!EEMe-SLx{I7v-=rhx|F^ICHx3#Jv1PBd!u*Gc3o_~J6r-!D&g6SE;-fTomqL!j4 -u1fu+OyF606XC0}>h^LITrj?PyFBlk0_{v=v|O#OazdUM2pNl{bZJWBdJFm13fq+&QuI45k{9VGb)>^ -%ii8tImL@7%Z}+mzv4H!Kha}C+;~z=f;>aF)#($)XW5~FAJKHbExOvhJTMz6yXVUssbQ%p|ELF~@S~~ -BhNSH%dmu15S%Sg;zQ_v@lQOsv4S4dzRa?E{gW`ixu=dh;a{l(VA(g8?=Lp^>F1A(^A%i+8)zPHAw`j -^Jbp?uigs*h`VJrzKsqB;*Zgq`eRd3}aR&vzc%Y$;Bww?s4>;nkZ`$~v4W=AczdhkdN%w4@6aWAK2mnY{22=qUMF9DLFnmK1vFnB9dat{8CaTko}(UBE>Ssl8jJ}3qd-!q5 -N8@t7m1;>AL5U_7W2&v65ZBzB~_KT`tiX@_KlLdNJy)Q14&VyIAxt7rhVYugj&UB#)0`k|1)M(}ILJk -)-HrD@Cm8U~zne;HO@ILH);z$~7btWqjKo7^#BDvdE0ouc(U1_;EU+CsBBR;5F9=IU;7#N_6IFKV=XqZJ@ZN- -j(G6xaM$_9{X91be)rXRRX%Q84rQXX8f$~QiQd`0Cmr}@-WK#Gp81-9%s0#s6f%1ai(3r$Xa*i-#eCx -ak#OO6a)9I|%-bk4*f&gTh@F|gr&x>`iktqv`Bzk@_n?DhdKjqo@)Ias-XuBZ=L0f_{LgLzvHm~Afbld(`FsYT(4>aqIkRHl_vLVLsbD~q$bp&i}k}{e)DX-y~Vv|?^A>=iBZ~e|-F;d-`#k6vtlYT-K3i_;@QeNYkhX5$al|uOaHef|dAWj#x -Zi_Tr@08ujqw*cmqS*;a0s(~I0Tdbl|)FP*bXQLs!207{1vt5q@X;$zvN*^Gb+Q-7JE3n-Zl%Z`$^*o -iPYF?v7cHw50tI;GuR(hRYew$)nkM@*e@#N?|zK6WtuZpH^V+JO37jWKw<9ylxC;1Lb)e=R54RZ*Bgm -eKmnSc_L9&xdks9BReytpyyP)WD2cyQ_1AjZ7j{~?_2Re&vjT2*Ba}d}XoaI|#4~Mv?CcverEuGejdO -+6e$agVf!)B|Kk-kD7H~gc6qQVMG={{n;2B;qV)iu^lfHt86MhT93XWn9(JR`N8x@h>nMg&juxRUG1V -j^)8^Soe_EY|qGKO_fBpY9S2x1fL;D3YY0bUEuL_GBxUV2X*TG^Id)M8-vP8v?e{RX4xL -McQzYNwcV)=13+H!!^8BKdYT^SNyl#xb%dmQ@KNLs%|a8CGwTw7$>1^7ajEUNuEZhMEh~1+L-K%goFxvOLcifADvJWPwjo}tOjCT@pNzEpSi5gXI{ -wj7jrTxl1=mnZp!S=L2oW-xm_u&mC#9J=mZAWuhJi!L5Y3)VCWAH*_t^OTtQq^^53&1JA0<5vp -O8hOA#_J^b3*smsebENaPS?jYj(MHrD}P6^gmEb0|XQR000O8NLB_@UWf`JDhU7pZyW#sB>(^baA|Na -Uv_0~WN&gWV_{=xWn*t{baHQOFLPybX<=+>dSxzfd9_(vZ`?K(emCI%a4KVA$*XFcCMdQB=Aq4HHxHW -@t&u($#+Z^Q4`YeciquS|MgIGqLsED7g6;0W$Y@0Jd`zcia_(?0-|MFL -SoNzteZYEdWKJ(sy^z^_;Ou4dW&azoPaf45v4ooLgvnQ0rYyF;(>?)Or2sf7`H{zhb`zaz<1RWs9V{p -Z!y&%bb8E8HFbkYLw-n=Q&f-aA`L0SgH90lRjt -g;is#&m+<}fe*uk}2eZQ~@GnOQAbiFejFsgPWyuSLc&)}O*ALugEZcEnuu)}Fh>{-~R@b~qUL!<`*8UFP{pQ}?#_J%K;R -+=VOadx-Dw7TA`93$uHmk6cU{i6Yb3N%3CGM82L$sfddx}iXd%~9doV`l&r=FBPL087@H_Q&dK}vXm(1 -%x5;M`pyuHG9Kp%jq_FxSE~PSn5hVtWff5coz5<2_N2?r$GOv9a_4)g4l~jcc& -D1oTP(^F@9Ky=2vk1MXwklUK}Rcp?n1bQmpRqg859{iY>idLZ{^bu%hW3nj<9{j1gO=powf9>^aj -3|xDNrUoT5rHS6GZk{Hc@uBI;?C_W2=a;GfzsAG1ECJOvuxHH?ylkhoagFl8#o&gFWCVwa)31#6)1~5 -B9>slv=c7D5-{0So=(-dp4B}v>Te1eXneLkcUM?l(w{AvCajzmP<$BF@+=lI*l`Xe4+A^d!xjSw=Mr> -<^6$BK@1O#If1-q5X;(<6~omcNHKCHuhq;ufsdy117B<}=8f2s|t+8k{_RfWZv7#YcrUe4s__?epY8 -*X@035g++5`yyH#sCjp3mW!wCn4|MsHZSW#bp{o5+3iXP7xg{;Rsj)Fkl@EU8oz -J{I016$$dd=cJ2ErWeBBL!&;bPS7AZ&5<`X=IFK)oBT`wYOHj56U}#^u1S -!Ht%XaERrE3jZK=iGZc{}0&73CQD3%eY$yxks$(L9x~Btca%ypCvLI4{4s@J4dT?PAxns%ZI+t8x%=* -zYg6~^7L@MIo<5;5utv2JIKC`>*Xl2aN>f5d;xzHV|aHR^Ib`9=f~pme}R_3 -FVKH)t4Q5d}J9j{WN9Pmy#5h`SJ=2k4HiwdMUb0U87f^B*x>4Q9h@5zkdNP5JTujXVDzb&OwIe6@KWS -DItc`4$=c|in`VdTQLWgWAvEgvF`j!ItF3awt0*geOaK}axniF;T)#p+h?#Bjk<` -Zi&7t|V$FP`FY=}u%ce=%vfi%M;}K`N&)dM8#vZgg^QY%h0mVQ_F|axQRrby7`_gCG#SoA@6{Pnwwa-o(SEd -)`y;hT>RBP|VDD*j)9HNWrND-yDml40`xmEG~X|O4fzU7 -eT8xqvz{wL0ZokuQCJ@a(ETu#+G`ac>?y-E^v8EE6UGR&`ZnANsUiVOwLGE$ -jmLsFDg-R1By6<1r(GO^70E4dAZWSN{docGK*2w27!do6axTIO9KQH0000807zB_Q%696%NYg$0Lu^n -04)Fj0B~t=FJE?LZe(wAFJob2Xk}w>Zgg^QY%gPBV`yb_FJ@_MWnW`qV`ybAaCx0rZExE)5dIz@|ABK -qOzsRN=(Y|B5MXVV00Gh%NVBCyQ3#B5idf5}K+7W$##>a3 -EC0`jJEip)t2J?erZk=I@gXA4IhT#$0K-A_$s`oEX!FWi_%vt(n;@TOk*Qoai(>BH1 -v&B`As7iBe0x5b}ZXxYPL$bj8o;+ -8&!xny@jR%&g~g`Y9^ORg6^K^Vs*3(587Ijiq4uixE#e!-^S&|7>DwbBj}7n)k>K*a>a3R*xSav8Wnd -2{YKScQqY5IG&->?@IeXj#KjJ@(Zx^}KvKs%&;n+(S-hb{8YnMP$?MpfYYkF$0 -Us8|@Na>Q#}V=F6K@h_@jttuA*5Y%QGwQ8$DA$vc_(^vzz4|xO2&Y_8E!Z%(nF!oq?m2WbXzO<E2BjU4t8A4)ZdKF74a -%2q)MZP}hFZJ3GP3RELM-zqTrV$#6t*a`UWtLWp7pPl&}dodO|nMS^9cI%g0}|Jbu>pgIz3j$Z;y|MT -B6{OfdFAGP*@O}r`HHlBBQm!1(Hho075rNRS?8fE41HHt=Ex?5*)U9WB>4Wga?CDIMlk5pRq -0Mr0_oOik55<|^*OW1IiU*S6e^upGBxj@t7gCA&d_jKqhmu^#f+s7Y9B(PFX!yJ+grSzLjCd0++`R(} -$yF_a13a1b(8A=IN^p;v|qgK92HT-cDOz*igmgB^N#rzq!Q`ZVhbnQP1&N|VZj2*(Y?Y5|DxM#=V={{ -tWlw>{$1H1rPJhDBa)sAN=IWeIlM25SeMQuYK?&08$&VA~rHuG&o5|Z(Gv?o+3?g&p~d8ky{5FU4}gb -m?oBp>+NzeI2UMAR_RODqpn_5B89iK?=v>2C83Q*>?`{^reZ*;5|&PN#VTPnCE8W3%a?dDSv=-HN%}b -FodZ){K>wr#pUkdJw)$p1b9oUq2)&YT<_JqX*Z?r}O_9^rkbG4>-j -8-;QGNEovMbM*GtUJnHabh)_Pg~*bbfPNj<)+H0K`OF{qa`OAvDf@+e@vmR^-8db$P5w;@pNpOyGxpk -P9Hb1}RY=(aHfhGlm*^hlmBcS~v^D0yO&OWLA}1OzJIZL?>>+mWwr+A7Ub12J`L?z56*BJ8UIkT78jw -i?nz2Xf;XjTm1^5GB;7IQW8|Vuvd?CD)157>+)PP4!7J6M4N7Uc6Z4BBpr=G%QQNGK%Fmmk)b -Ht3_`Tx4r*NR)rCsrs?KV-Tb2p!dhE3ynoDpDu)Z>r><>%@DLq6=DRJ3Vd8=2mPCcqO0@KK>92 ->gh3DG2`Scct6Hs)BM+P;N3@n7O2ualE2Kcro30#%@17{r3}{VfQ$Vxn@Jczi+Pcm?_t=Dg}O2*$&)6 -gQw(ATMPaHvxUhU{WIYIS}4#taxerR%P=~dB>O*5O9KQH0000807zB_Q%S-UMQ#BA0C@ud04@Lk0B~t -=FJE?LZe(wAFJob2Xk}w>Zgg^QY%gPBV`yb_FLGsMX>(s=VPj}zE^v8$Qo(M+APl`%%0GBLB~r!*OzL -I3?6kwAoe=}4MWYa5(sqA8lcXiB+HnH=z2|4_E`~iw*$rukC?(i^A7TPy50-53)v8)`8DdnzWcPRh%< -nnf+g`{6dK041O7BnypJH&+<4k&0gl{>JWvi8TiU>Z@SQ?}CCEvW{Jn%8tu|4Z;lCmarT?;JjGXUn3q -ap`kGv=1mEvA|EgTG5sL~hs@uE@xYS+Z%#ZsDNZfGyyuw-IUc5j-v>Z3jN2b9#}uGAU>(G|M#whK}%t -HEVHW=iBq;=f#k;568Osrx2c|Qr4$>RuCy9 -c!Jc4cm4Z*nhVWpZ?BW@#^9UukY>bYEXCaCu8B%Fk8MOU^G!RmjXO$S*2UNY2kINzE%M)=?KXvk1tCtD$dN$i;q{ZRZucAFf!CLFx4|QP~znR08mQ<1QY-O00;m`Rt8hNa`9iI0000B0RR9W0001R -X>c!Jc4cm4Z*nhVWpZ?BW@#^9Uu|J&ZeL$6aCuda!3o1K3`Oq-?_hjNpz#2O9J)a_2*y!TL1P=qY1gm -f#)ax4r2qdD!YwB%#?zWTF=(aLLTNJ@vzuNJ=R__56AYPqDK@uoq*8p)qChpc!Jc4cm4Z*nhVWpZ?BW@#^DVPj=-bS`jZZ -OpydvZKhhrhCs*gjL<_GM&9d-^grV&boM0%JB1r~@2^7XbA59>>NyRlw+FM&(!9cKNgA*G9-5|sUW;O(}VbD -#2Y(i>7#2bv-FzF^lHZ-+CnGGE*x7o7D&({FQ!)U{h8#>&?_$I|SOuQk{4H|3$dcy=88rh_8cR-d~1^ -5PuH#E9oqPOdz1o`t7lh=h1c!R^61mA?=28=VJHaNP8m`#E$SB$X@k}TIe##bm<}%&k*v1mYxC>D=4<-HPqj(lxy*@(4rzo(8w?3W -4A?g5yn2{N<_>^bXe>-v)EFVG_xF~(GwiQ*ojYW8_G-pdG6B+-1wo$1iC-#xn{DXki9zX#W6mGC<7~^&S_>h%Eqf5+*^H}yq -pWYPL|Z+{jH2yCKehC%lzpspOg?243T3En`Lo@6GnD9zGEBkVH-jqJOUrOMC1jBSG#l=o&~N|!Rn@L* -W$g~*N$kM7+OA>cpcaCbB^a{uk2Q&UU+2CPBrTX!wq^)@M$8u$l9{o#)5a620IsfjbrgivpGAW5aIFU -DQtbHPV`M;a2a!Si$9!8eWuIp4MN=Z(lsUNTuM9~J-U#qa93i|4LRYVa@Fc}Nl%Y6Q>6CksH%9?hfyq -(mML$|3wQ-}SNo7ZGQa4ZKGYpty14}zWxK;+m{d+bM##w$ahsH>G12$#p7SOm#vf1gNoQrysgRA5#(e -FtcwdbsAr`i)xk*4i+fuA~E%SGbB;U)6>+|h7o2~VpZ@G}Ggj1GC1f$asQ%DW9YA5@~tV=>TvY7^+Wc -gxTz$3-tGI&yBVHCObXo$8t8dyDr1kq;%uFo^ -?GJbGplo1dC$v2W=5EUz|UA>*#i&0BrI}0UQ>}lVFg`N`+G55ENLg~ko5TMuKd^zMxEFc)1L2*dD@2+ -zdOv(bU|_})@44_RwF4~Jj4#^wjEmQnj2J!H!E)_3Xh^l&TxjS%nvX=N5(#qWV<3V5yEIat#sR&Oq08 -6W*obQBczO@9VYp*rgdtX2oDa?`!J`2d}a2zs`zS~RViOnQ+2!a=m)|7GETd(lkL5G=dUe;fn!tKfa-;4V5g2Ai$Il$dYa_coW7O9DoVlMCn3<7zT}B -;)^0S3A_oyg&zn&3$Z}}yQl>fFrXPAO1g>TO$_cpzi0$lh;LAEtK>KMih_ky@oNAS{yHCwhhBIUG8-7 -(VB`jkHYu}-0kzT%g)GDjkY&tB_`({%6uu$T4H0he1z8JK!71P0R#y!6omreih+GXE!-@x`(?{;3xN8qPe+DLrJr5hi1NY0ve -9pnIoB()($$H@L=6&t-LodaFtb!Rm%>rtxYahP#V?qE1;O8}meXC9QZy3We+W>)wufad$EMbhNX2e -)j9XaCGF)7@pQbH;L$-I7Prx^ttJvkl2l*^#etnrBCmWrG8E6?hJ+tv6w`HRuazLg --jf41Ni_DHnZ_tUtE+j!>(7#7IM%i+IHNX>j}SCn;v6EKQHi6&t4ZuIi4Q(7TbdNpQ*T41zQu2gl5>I -`V{iS6?%W#=H+SI*F+Wb%(Q$D_Ge|<*PxTYrmwr6G*K2fdtH%N}3A*(XQ$g6lvc}@48F~p{W5Qf*mlo7(bNGpCIZ -&|lpQ)K^8G}D-zRc!g)`NGZ>8`VH!+-7@yuk5|~P>nSOS=A_$Tq1WI!iP) -6Z@_*l;?fDCHRBLmEw>jSt48e>>sdEy!P#*>;H940GX1uFVZ3k`l7jhV;_Cqv_(IC`ww8G=>G-K_hV< -kzHuD?m3(hn^T*TwyLA0lT%)GF{p(veeQT5SU*GlLhWW(*9yp8JvVk2F2m8$etvNUozzf{rXtB0H2}Jbbuw(Qk48S$1zaqQ1TS)c%B)fQ!0Y`){ -<`po1_JU|@oFc!|a1WU-0Y_J7j(OtYpN*#>u&a0DY3o>w#S>A5S96NbI{ZG{3AUuCz&^qUp1VO|tq;+ -a1-4Knl&xC%1)lBX=Ph(AIGVUFaHV2jluy-SFCUI}%jcKfiG3cdl7JM^dBj^4i7?|4)(+4UZzub%@zi -Ga`5_s0<*)tpD!Q6LTh!IXJDaxZ*b*o0Vm$TP9(7B4bHf&kL9a#u2o -FmQG)0EN{48JNENUSE{Zy(^(SUw>P0{-)-q3vPauo3!ocSWuq9?DD+k7wSs%%a+<_XXR8a -@B)T&IuIUVFc?7VTv1rU)V!cA5S1Q_8HjlPg~kXW;PP)D2KD_g_02s58ZKRR^w~gZ~ad -v~ls-Y(h-E#oIF53CgGo*=>1{IOPv865nA&v&(Tl+r7Zl+Q|NH?&R)qzbI_vNVRc?cJN>hW52UJs?WA -TXZGZHEz{MeCOl3ahn>TeSrNSCWVyxOR_9*1$+e6FJ -VD#WkCSWT3<=F%a=UQ2h%NcR8dyRNRC&D;Q|szG{Adt5hSK#+Yo6k&wSfsP60utdHx%HlS+0SV(GdQ* -(t$ptj+2}?*p%6!FVu%oT(q>#Rkm~=XZ9@)doFU!3-S{4<@(GN>McGvU1v|+zL!IU^y*Zkf_^sHC5 -*~u}V76BE1xv&&XNiS0Tq%LB4k$Cwb(+bLo+rK^gM@(ZFLEt1peMM=&H{hCqRSk#@1F%LdREz;qUx8jGT(AbP3lJO -tbmL!A8qg7VYZP8gGBEHYxwu~f1NM4}>jH+;^kRJ}dJ~5mlwK|j3^p+06#g4ZBj9$xI#ZhfP@ddS
K(O2?43-ViN%e4-7Z9+&IOSo+P+&_}Ag%c?ln{J}J#+Ec ->v&qBIw1MmO?rAyio$RTVNV@uYF=2ewrMm{c&G_h1^YG*cTz<0B4x6B1XgqUw!U8ZfX5>j}_XFt*}>a -e)ID8KTNipvSBF5{!N^<86YT0;(Qt9r=}s&8I&cN6?L&JMG#PU5uYWyTq!BYzyZ{f_G%0Ulq$M0 ->-K;nF=)sWC-W5t%(Z-cJwcTnnrI?n&#t6>~_*BU0(r@)5bY$E;+Z%sEu#WH?CVW3XA0NOFNl*Uxhwg -fq|){shGlgV`lEPd?i{EUcPNx^;ZgWz9UskCVYI -u8-QRY%0I3WK*HCKiK2OkP?Fl^O -g{c{kn6qdhEoZgVQ~)Ztr98U&6;9;K#wsBDPqZrxOS(NW5LK1_m-@ekP2MCVf;SDNiXkl>nOB+=nSLhHe*l6 -jBoT3Y!OEx=th|Q|V+Y`3#lazQCV>USAacj^iGdl!llPD?NA^?TnArwl%aFz52!)Su14XbhO7B7 -pjz_KFg;%Tw;cUTRvcUu`!uVqwhSp=o=CHx!%@I^1{iEr?Dam3&S3A!;0TvO&ZSfyU8seq<9w!zaS79 -EkB7|=9cqSHjUfs^GZaMUQZfSLmLi#G|eGy)`pa~J$qdlbyYkvSsus?lVr-;C}P55(hh#$UH+x~2bq3@1Z%Yrlb>k=0Ltr7eMcFQS0O)&tN -4~_u{rtj-!3j|&0&EzS7x84sXZ_G}h^Zp|C8sB|TvHX7gGw@zPiv#|h0e*)$ssZDx&)_B(4c4j#v?-r -$kZ!#i$1G%jUI(rmOEbMuVn2*9^4$pYoEp~JLjytp(#Lo0F>}BRM-TsJ3pyAGX8{vDe;Q#hI&bl=JXZ -jh0+fO4SHKm6gZ6X#Ze*5ETPj{r0^p)q^oJn9=TByd(!Na35*<*#clcZf2l4`l9slN`68JCkP(%rdWu -O)63Qnx=3Ih5|39%2HzSQ|u=l8psQ82>P4o)Odolc0h)Ij(;l1yO1KjJI}OdShrFXGoeD&-R)8w!uJ&$S*bL^(V?1d&B*T@FF%JSb46f&SZC#+wicCG`oqX1cFlWt -kv)tfe}TO@9T;c_JibEM=e_7ATa*AQ5Z2D>Wp&!6k^;xkc|ab-lZ2T%mtZdtTynR&gxkx`6ISY3R-iT -{=?nQhRpsMudsr#XqECv1eq|nAhqlfjRCW~I$mF^*urnNIdd)qMvL5s8intvMh{1)@Pdiv2@msd#^mZ -=f{f$^VRbUG!W9iq!^7He4=Y-d5@2 -Ob|rd?P>n~ll6{2HY<8>l>(*W1pwGA)t)yY*yXfJpqrgx1ds34sdUDtW4HT-fGyP||6XE<17ISyFvyi=S@1imm0yuYwO)SQf8Qy&&h1HFqH3laDc8MSQJ3xu~SOo6qtyF>fawV$m1^h6on -T_I*5pGJ*8Cexs}&GpRm&;i-ayMDML%1QIq-f@~du5`GLk!Tyg>F~%M5>2=nIAvx}a~_rQq(^qrOm#1{bW97$x*4vv4Vj>ofdrrs7l@F#1t-xVw%Ez-BPGvT=i2y-l^MkJwl9YM0|;v!|v -W)r`A|w%o@F7_b!1)HIha2Vx3&95S+&p>77>N`4;uzGA{2AZM7QKQ1T$9(>*q_BY!=McY9yaQf)m?Mk -46Fd_1!DfxIfm=z_8ojojgW`*@()!#HfuLuMj11P}2!5`uYHk4=k-Rqk}wIw#g{YtVmN)UYi31GC?v) -kTzaKsxYE-NenZPW^RE{vV$DAs60{EoXn8(f;DQk*|~iKs3cH>(ao{CgCClfM*466{lWd=xA}VOA=SO -EIh|whs9%LITgj0%qcQnOgqpUbh?R|4N7cCd=mi?fGmH2TLwo#OH3~U0{@*d0FFNZf8b3TE_#JZ76pJ -IOC*2-H)EFUEIe6;w-|0}5iUf!#K9L?6D)y#&;b~Hpb3_kc(Ozhl3+tJ8wT{p|56!fudw+2Lm6=F*Jh -jg#cXelix@&0_a+m->~u1L3tfN}6`bw?E(bDzo9s+KBtUHiHnxDbt^xQ<&1^4zI=k9|HD@ -^){`7d0T_zCAN6_nZy2xv%vqOfeYT+{O2wn`kBE5dri#;p4`y<`P5DObQsD|$;KcaPwh(PRtJLJlQh} -Kw$iwo0VXr97o>>a>!%Z9d-Q~cbuRPB@jk(0Iqsj6^=O|`K*5gMocK;ByNjOT{atlZt#FUW1j4lSkl{ -gbQO)BOy-c;r$vK~H<92mAIHw#kt;Ag&aQ_r^F?o@I>_+5)}0f54b~vc!IQ`@S$2@3g#z2Wa_n{JfI -ke1C{0;u6*4sNY$*5rCeSb2#3zE|cX`Tiw)U%&suJOO>I$@5Z3vjZQJ$5p -xNed<}B*tuMb&(vdGZL0frv`=m(#*a%)RanPnOolXw0lo`#ZDrdF(ef45uIN}YxnYgbVtd(INDCJ(E2 -Supadta1!!`x<4cBtnX*Y?BU`0;O-->!R+*8svZf(jJ)!e5ko;S*;ol4PosbbN&BTv#ysh!XyEY=3BBP(n2k?jw+X}XD=)*%O5QSV&=Rj7cM -5&dB>oxJ{AlR!dY+LSy3`*s}`= -r`KI3jFZ?HK^2Vcaf*6?dk9;u{p!KuyYbgKSb3SPN$NoQY7^Ru7P)xj5k*RR8=PA8Jlapx4YEE82Cef -t@AdbKn=Z=P7qBsgRSg=qtN|)#~@aY)2#GG*ecyuw%=qvn9!wVq6-2m(vY%$g;^&1q^#KPhDwVn;|3( -g1jJft=$;4QI?6N{H2E$$m$vd*H{A)HtYd-_rW6!psZ#+HTbG+6=>z`{rPf?}HdD-=upGSL&Cv2UI;$ -}jWHOzUTZZj|s7`YBynl8_MbbAR!ZKVavltmx{8KGOHp=?qB!WgU3bUpZyQ^B@2_@Rk(~==s?;YqK6` -qW$THq4%_C{gC!V9(ovD$JOc~+kpBuxz&E847Wk=)_7dny<*qTd -zi;I!eh!1%1|*Gaje##Zj0!VS|@Sz71uI>n`>?5mDLcfA63_Gw+%A({&jutYg_62oy@ir6K -5lxSc3wiWvZ`NdS{CCDT=X>gW5LYgGM6nwkzP-xqdiHT5@tcZKaFy7|*_uI7K<67upZ_hdbg3lLX6J; -jxxT*t$V0)|~0bb#+z?jX58NfHGHeY({L+YllRhD&OvnCOsqJ!7!+}6W7}WOG9y`lxz5WMxe4gn22{* -U{&Za8B2;tts+0z3&xST?wL@!PbYNMu9EZAljItcx*?oTc1xIRs=loY$c{$R9-j)4k<1jDC|B)k(L6{ -|4IZNdE9ym;$;Q5kcTw7RmFo{2qQ=kbXb`!l6f<<}fm7;c~28UXX{HC-f#D+dA9|bkDcP2Gx6i@>I!>S^!W;9>q1|%3655bzOR!hKVr -Uld}6k;t<$}w3PwNK>m23Am@^3v_-dY4Z@P0i;>8v`w@@mruWEb5v>Wf)x`9Q`87&J5X9$N_4Oy=?aq -V0<>~@K94N(kthp#=4nu2ya$Xj9ux$bdy2~-yeqG6D{be^vqK6JY~XLqTMkRI)K6>QLOy%tV+v|Fjd$ -srZr4(z^yw?LZ1tDCLgjf-!}xJ8ZC5e6UA1v#v877xvblQ-EcGu|bEAEvinhD0LHWKb -LPo#|%_B(Tq#U&aNg@szdc3b5osLZhyrOv9T@4Hv#WO}TU3ZO3yU(4*IGT`UD?WD25!VSWs~}gCv>1f -8G@I>&1rHd8_g?K?vLGL4oIJu0nBdkNA>OyKzd9?f0M#Lj^TPUe9!i8;S*lkP=ah_%Dow~q9qP+n;hw -Qy4_KAc^BCb_&7UPS8&_BFw1<7D$wgas$tlnK=2&K!+!WZ^_miuZ4l1fB_)YZB`u?fJC@H}^zQSbAp5 -@zh?K57>Ob{L%tZg*y)T&Vrx^O^7l$BZ&zghRKrJ%c8?8wzx>BN0aJN%wy9qwij6x=ft$1X1(T3(Cb$GemlbWulERO@6c~dq*#{)HB-;hS -t2TgH0ue#FFvJqH0J17bmKBr;-h{7O1EAi}S1lVwEO8f__+3f@{R*i ->8!BCd7x9ve!Rv}ixHN*nz|``;1hs@(zz8vFLj+4!1s*T!C=|BnHZok+T9!*Cn9~US}*J`5-XLG>KA*35WGYK5ozZ#$xy&90zD{b3v*Cb$5yLGDYjQq<}p -&t4fIXWfl&cE+|*!67txCYblZ0b!K(A7AVzEY!~k>sP;#as{0_I4tfuS-BsHGGIWE~%1Iz}a!3-)b$v --FZM@xx;-cExK&_=zeaMQH<_Q$`sV~X6uc7tzfS=ToHZ8|I4@rY4gygkZ$TnIhnvf^1&k -2kp)vIsr;!EI-sY!YtmyY$>?g?1cO%FT+13=~1Kb5}d(hZ}vzqBbuNf)7Px-(~wt!=opwQ727KS2LW= -U3m(&MSCdlGk@H(Z8f_{V<$s!9G!JB1NDhK+jYgT5MJz+es7i*6OgH$t?qKEA=E>TqH2B!G<7{Wdvst -}@>7;6T(vBL`QmGB1^VOS3eVwh`5YOiY<*4Hy5O(HWo64{qR57X$Fku264_(sYcj+yE0s&2W>k0}_++ -_}1;Zr>W$VoTi5vWagM-)n@IA=+igC(7`CN4v3eF}1zN)h#OBWAy##mnBl6DrNUKY!FrAWU~UDI2H5& -9v-XoTqV=3!;FpT1ZIl(@-rb$E#$DUuE^qX=E+0mVE%?hQ}bjoz{vvjuY0Rou^T(ra}yIy*yLOJ#7@u -WywgZy}~Vs*g}Kv-|hetIw6IpORw04^aeC%$O;PDwwNw^N_Rtz$b89O@6Dhij~p4YO>4zS?9*COLOL= -Ut-rhWLcuGanVPjm|=tAImk;yf>>X -&X3(Xkqj^W7|PS~xxjfp!w4&s$WmEwuEQiFtk4yJ(Nw9oW?46XJmI<7}tBpVGY)!PoG=HubPs?31gN< -+UQH^(&wM{rc-3BE3Lv0|S|GueWDswN7|%IW&4;JJBF*OOoQC^0f-MLH)zL{!_i(POwOPUC27y}-A2? -HuK@MI2hRX70^7h;^tZaK622?4&mrc6A}hyn?-qx2H+ThTG}thAtnpq@SGcH@a*}dx+t6csmgHEM{x+ -2?-u2jsayUbDTbKhu#s&gWQr;0X}9tq_5$G#P{oCyUyD9w4M&kDJ;V)$A_0=r}+d0mGrip+%h;uTx%6 --Pu+XZibBJP#Fi}SQ;txr8Rs42XFN;_p5rxgZPrDzO-)TDJ80gXAKBU+z036&N@-!~JCh#?WXC;%VGR -eydb^9)9d$uvJUC^pk(o)vH<1z-M?8ctkUJr;q3(U}S?Upk+y+_Q4hIh2QTsLx2~MWYtl7D_()Fp;iA -~w#-lMngyM1RC&jfHmt+GlQFEi3yD+J#IduQoSoC>V4z57JIT>|`{wQ7g -a8#rCEeTdgWAyBVN;xGF9C?vQqk-Umz;$;U3a2lK};ZZP#5MRQXFuVxb0ACWAB5YB@$Sb-D6feeXP;` -;hFtV%(0_6=fJRU4Xut0eO0Zjg7s*vC=3xehD`-0$?X+oUw%cQ!q1<`{v&ij~Dk2dTG77S<34<#SkDH -_#}EZiqy`L2$<@=Q+Lvi{dYu}l0wpaoy1U|8aN<*POxEN#>TW2qS--YQ>zZiC#**F*ceBZGc7wBL>F* -Zmow-*3>s&)u3>!zlWso<8l6wicd)-5!3d{bR3DO*_(4MMF%we(WB?jSO$0&+me|rn^Jo-)zJ6)qZxi -^6mM&-I(nSi&J@)FLHc6T_`*XSzjef6%uxVGr$i`INqFE7(9~SJAKzTyrNkXVhG -8pS_9%iL;{EQ3@GI>sBS|QM|$=`u%wHRB$4(WpQTjk-Z92)#M8eDbpvXnk-%$^HK7cl3Z=&-1YBk9Wo -qD>0tQo*g?BxnglOd2Bi_^;qTb1kj8@Qm)Cd%6ZL72q1#0A&65;xjNMiHJHJ(-XS?ku`rvrFc%*mzxY -E~q>r8dXaBtBNSv$vFMV9O^ZJaOS*k@lW} -?;d?wB{GR@1N3;{#k7U&3xi*GjNT3x$D&t3%{PW&Ri~$p`SnN*a6(Gug5^OA=MQ2wAD^%+J+ -}5pl$EDWUtunkI+0eFr>7&rXS+u< -<~w^?cZ0Mg}m>8)hprw>=X6B%SrG+b1_Z6G)V6^pV{9Y(baqy~n?zr -v4=q^WS@?548P!7xoX8B?wF*FwMX;4PzvM5HLeBC_}>tilZ1t;RKA}4Dog039^CTmdUWC8U%rtI1PXb -01Oi^u!>*EV$dbOBu2i@kfj&I(B$SVA%=;T*8#EY+5qFriW~+nNKLT?gao>*q9w#q1(bso%;MDZ -*>uxHq+*-_l(j`&X<@zWvpR$2RHZVb;s*)Js?OUCT>!bYDtn&($WEFRTTA8qx@!<<*@>AnW8&Js&V<3 -Ec{LswGs@XTg5>RjUUTLGfIEb9X+=mYbyB)w`Uc-)QefttzmfFS`_=DGJx9>%|_Xng0X@zgBfZLH`C= ->iMCfI8dbt5L9LeHIBI2e`lU_Mks|e}CugL4WrC{?6Njetds_f7c}5Q#q26!V?K$bfVo(33_1r8%_C# -J3l@Y6NyZn&d+E35+8{qZOvUz2K|<#GA<8`8X0^aGuyMrAEBL($}&?&f}i(s&NlABthz0;tG9KEYuYn -y*tYj()(|=~?}dHSc&N9t98FPs)TInac!DR9h*Jxd0{UPPWiVW~)`KQBU?wIQP7kW$nbUzrC2^Kl+38 --}ornblS;EOx!J)gj)sCuRrpch(nhDFhVW-W5f3%YQ3Tsw*F<&Dl+BxL2te@AGVQG<9?j8G#eE(<$kb -2tbIzLTJoyB5}Sw)W9Xm>i^9?B(;9a0F9JASx=??yryd4IhZ=icy8p#m^Nk=xvEh{zHPy$5Pl&p#sf6HWyg-a6`RnL_x5p4!SrKLWW+b -2`|YPZ%1R$c<6UogViVsTOGiqEBIP=q6;*7}tICPtP(+lF4t60!06H67HgQ0O -Uno_5HCit2QoA{p?BtQ$kEbxmCpuZm)+lA_mRBT0 -~2owl`tqO_MnDht`Vs0i>9WUZ3k2kLc_5$%k7d(>vu>8kUR;^<=2KQ+VFW$4A?*w%iZ~4SQ6=`G%4KW -*kowRFL(PIIIG>XPLmiKJI*R!L4bg_lkMd7}_|5F#+pL(`RHK)H;1RfvMIoa3f@R&oH3FiW04()v4H% -AFn2zHH|ujhMJ+o9=Gq6ET8Rs6?EM<^mj1-*{}W|y5i@qPJcM%uYD_nEV-a -Cxul#1;R4C@g*${=l4iniX$P;-V5wOlsV@NzY%W8-5^u=GMnX&X@q0OkIPO2HIi`FYPMo+bl -9Vr}C`)rRvC}W{+us$Pz+jG=4wi^P%Zs-}RqeC!y>0a7Kl1l`3Tb1>lG#B1iF*y@eI(ncW{~K6jm%Ty ->5qb%#zg7Nl%>)K>^0D59${JrX~o~E1^Gi^{6`+D{+@@Lz2%|mWQ?qCXIZRscQu^Pa3PZ|6|Yy;;6G> -BcZ=D<4u0Bl71c`Ub#@vebYQeNZ@Vt|W@{c43{RXTD?P;pVRi3=^-f}MTH{LtI -ZX#9iAL-ZQ)s|kYj4<#Tc1=MAx1M-^TlLrR*+ZZ>7x|4HgY+NXB>~UGrp#rTdAzX_;5eVaP9bGaFn9PTk=Q6G)QUwH{Dy2Oo8y|Z?t;nL -M7=y0I4Ef6kS-)L^a7EL@=PR#Ge{}F` -$PhR#jnEc0c{u;%Ax_GeQE_{_=EU{$fwRc1E%6tf3WuEbp|9}Hre_d@FysAEsXh|at;f0q;y6~0+;Kd -dq0`MaE66%d#wWz@V0y>7o=bplU%$UHJ{g~3=l`erTF<{`=DROBEz`x;Ta|ec4N=FG|@!JXhic!BZEP -`NRGO*bZ`g%vylAeJgukw_1*|CD4{}RQ*lE^wFe}&@ai62|sIok)@ZqQFBiF)Uq^;r>=ziWv{NWUlq@WeAfF#2YRjq#_p%hyBy7&-Ls4*laC=${T9%y-%E -W6;LS?kewg7t^}Siag6Tr?|bqNhL-TIz?xKtVHW37^veeNFiD~gxV&#uMpqL9mEYW3HYB1qlLZhu -d|TPgk}*md6nt_-)NU1dkzav!#azI*3|iR|1}1^K2xbV_i&mIX6OWSgggaaxYr6X^IZ8>9&+In -c?U4P&EES%U!Fip-A!)BK=`95{JwiwV{IiJ1|(I%L*sNl&)LAL ->IRf-|_3ZEP4E=T+CDx6PcoD-<890I51?h2i<9o<@QD7m-tvQ$Kt{*UHPbtZ)#R-_Xg`AYn6kH<5Ya| -;^UJN+lJ=ojzxSD3{B-LBGvRBu=cC?=?s>nl3kOGvnkK(zuVF{;v(H7t}Ki)0VS>I4K-WO+!WxGtyk! -EEkII~Chz^(h34ZFoN5vILbLC*;xZ^50malgl$q@0E7BqfiL0g-|-xT48E%iT-{t&c|L0bgczKD$ -fZ(r;K#eZ_4pJLz?Lf{laF&K`ZFhNr^i6SILF*t+ZFoobK0n=ZWg3_-o?%{ALK>;=y;1p+;5O{(tF>2 -~n1PU;_Y{8FhDD+Eg!^A5)@&$ePwP}C+$~t^g0>Nu9Vjv9SbV2oUC1zRn#eovQeuHf+Szx^Md)w|mSy -TW{FPl%muL9L1SR(YxW=qLys|aKvI`HtoFM}J?%+e=)+q9oq7LGwTEM6oCkSWApul&C1Pi~*}Cx&oHG -r~+gb0Cj|E70iZhXQQ>5r~e)eWF}5obBksi~he5AR5tdHwtJ5o8NIMy$l6~YO -_F~}1w-*a}j*GA*TIT>xR^pGDlHWH;2Dal>{`s*<@+|(`cHycYM-BZu!~Sv9(7!Y6AGi63{$|9w7xMF -g5D)BmFK=lo&Q@pfbPK2mQg0{aK3E6l#1cCx&xB*aqW99NEHyvw-RDj@?SSk}`D_v-?0zhF(~iI@>nz -CPZt#v!EhuQ*%?V~rP4i&xt7$vg^)|gu!g;&eJ<$~Rd|f%Y$eM7u3>m~!Z>*3Au(jO@*$NuXLAVGR11J?aG3~bjAw}os7LSCMhk*cbI|`ku6?(s|dF&Zv ->&gs`H7UE~n5XhKer@v)EfH%E_{6XF`OkmZ=l`p1{vnPtC6e3?jJn@v7qPd!$MrVJF^yu1F#lmkg+KI -#e(3z$b>}7{X>7Ic>4QE+*sZMgYb>fmPkWd=6uY}ez8WSZz9vq4NM{YVcl%PWP%aY7r$^`-lfjkbsu2 ->H_r_e^+~>7!#Xi4go|QuBSkl!Yz|~^R1`C~c$`w1W=>oqc;&xS46rN@nEnQEc9+Q-!?jBuDor_g!(J -f6yHKe;pS{O2VavmvbxZ!<Jd{_p*^s!{SBIYO*LQ8(BLy82hEK)akRG4V7VR`Wi`;aM> -ATbS$snH0nir5M5{Gg)R1_un)2$KX6-$ic?6#I;ZGPWBdWiF`N-tVrf>?ZBW{Yd|l8p}^qy)V`N@5A%oxzHcL`SV47UN~lO08NHqXlD7%HZVrv41v% -X%8(d9Cr;oPPJRVVidl>zu#U@4NUtJEELeib0DBRn-jcchnS^|Dn0zTBOnm-S(kd_|avCCPsw>Fa3t+KvGX6%2c+GL4sR@h -e~stS{(;;Y(r_xMoBx2quxggl7AK=BL*+cwxw#8^@cioX2jfy8d>1`YJnA;PU@2XnyYd59kyBNT1L3( -~taB=>3=Ayp*~Q`BRp$8d_>aNt~}KqkPnqwWWoVoB-NLpa8-<0rpfvs*NemsyJQw0nifIxzVyu?0Tq&Zy125= -+HX2K!7IWWHbJ_wuHt))H<+m@cl!>@+9lwI2(j#tss9KLp*dnnTU@xpeDJb)vQFi5gmqhxhiKiaD)sG -~}?xp)7W(i<7N;b7)SdqKNe7$>|u@<>6$pw*yCB`qKqT`t#~iYKKAn$dE_15j+V8=nvZwd4KP>4X_Mh -=uT)t*1oUl-La6LgHTZl13UJ(9p8;HmyJ@xes=z<@9&+a_K0-yrif2vx9Sn`Dl(_;Xr*lieCD}Sn#u6 -iV%I_d`28b3Z`XsxZIR3VA)`@pwXQV}z!;t{(T>k&ds1rupp|E#xQ}!++zz)jdUOaj&LEgPtglX|(y@ -EMkt2MmkK~a|!(I+kuMS<IXI?_9O^{_AvfMXlTl5+^14#vId(F>u+7)C0_CqV#U$#^T|l# -l)xz-a_guA2RJn%1xuuG57xPdm_g!dSkj`gx5Tcj0L9 -ZC7Zr^az-ckI1Y6cKtIEEKIQkCA=UO8?y7grFr`vm-5`_;1vZ=XD#ZXz;mMn{T~3OROZD8u?uf;`Y+! -7KY*G4}2ohRzitSg6vR!@nD|BR1{+4UV%t*B -nC|MMm+Bk`ly*nJZmh&ywzqUFfc@fJ9q35bnzS3ApVL;(JA!*!q<5bi4eD;1IbD3;qd6=dHXrd^3(S> -0yqQwo^^zxh~na_r3O;T%8$?{udh3q7nT@t-<#UeR(=)SAH05kP!*iNGR`mc --T9YoQ^fr;Z@nunI<)gmagqNK6Pu^M{4l>VYvvbu{e7ou+v!W=)m>x14X~6yeFod>Z*25qf(Wo&{|9r -te;^&KMH+TJx4?n23Cso`+7M-!&mZ40*w|4ppT@J>aMrC`iQOnreP6TltfudZV*UQqFrIUF5XJF;v;F -{$lXY5nu*qM^sdqKoFokqbucT2I=i=-);^ClOM|df1bcz~Q;Wc1p3&zb}s@K(Sc9S|iqV -zbgsaMsZ7vX_u)>9wJxVD1fb{9cf5IX)rbPf*jr*?%5K(4XI_fy7n**10G3Q{yDm%2Q$28=K7`Os=$$ -P{56N@sKZK%DDIm_eu~-Q)S=gW1WOMT^0KFeU@*xygVTcheEETd3-=Xl>ihrWo -YLx*DSw!8(A4x{_-ZsP{e8Kp!I3Fh^kMQifT^cRX8E@xjwZz?_M#|e%&S*@RyRZPSz1){X09_*U&`z% -1~)uNYS_C+qHXr+v3fCu^sD86c4fV3?FSgW`m>_*%Wy3LESK -Ox(g}o#4|!v6EZJWeY7Ul&hyba4_m8kLw7|P^Z6-vbOUL`mV?q^n0vKaPy4|ADf@dhf+P;{VE9j4-fr -@nLi!&lSd5%QxvhHB!M9aMXf&&Y{f_z$0-~mSKhf|B=)H_-PT2nY;D6UUV+)}SOf0vZhP@^>qgoY=I*l&(~k}#Y^Qx0zGX(YxprhPWkTB+&C34}a&J=#_kO4N-_Y;Uvn$e)dw0}&Z!1!UyO-ViI- -$14vWiMJ**UBP&BR;) -mK4>p8_O(1b#?Kp1!6e6HyrD-B}JR63Kn95cXB&o{Qe-EG)G9P0fR=Eyw+VhRH&{e3!wm7mbrQ<SCaGxZM+| -03ZV7F3l9>LmG$dGo68^z&HTAY>v#07X?;ZKH!h14db09MdEhz?36#@QJIa^Vx$~$2+!suK!`J6g*9s -24+NVeTuF$2SkaXg2PpFAmrNdjCxN6Up1BzN_lv%fl+k;kT@B?6|4aQaybx~nDNDj!wGq|^LlKr$-eP -0?c?Gx*siYk_6W}l3d(>tZA(5qSyiL6r*Fqgw=c;i%jLIig1np(2n^Yt+di{okX?TC4~lR~EY*25EH1_MJB#Z9G;EkF1wXS%P!FZNq!e(G+FAyiCc)H>_BcC<@SKe`>{>n_*z9=sCWXSVSvJkL -O0~BS1}TrKqf;>EE~`?4qKJ4jNVJG6#g06Ss>|-HM}7ww5$OijB2%~23-duwrq}uz -k9?J9(JAszL=UsNb20xm^4L>3j=MXl*lj&Dn>(qviN}5a1ugypIe+(0Jw8WpGYkinL3;aIO8PVlm5`s|u=~u$@VSvgDl4gAglJ`Vu --~d0~ss&Sf2ZU+U51EhO>*vG%*7+;nvyLpVryX;iz8{=t){Qk+D9^#AA3|*sb+5$ldyy21!t(Ed4BV7 -8Iqa%vkXgPj!vj8&0D-R&DMPMYrgNH(toVc9c{E#DWGwcmS)GU{)s&B;8^6`bjWe!Q8jb=fx9b;pzz# -qZ4U8nMAj8rSe9`sdJn%3ikK}~jlId}O&HO9Am6`g;4_J{SUfI77Nnh5=$$b}x7{DWqJdv-3wv3}U9+ -`)^S&+g|>sik8#CjuqER|boRR&Y?^eNNnLk$J;a!K$*6%9O)wlukhi`nV0q)5&mqZ(;0a-=>^$A`sp! -n+wX_#xl3Q}x_Tso0@2`h*lN_r#swN&;x@aBWuJ43oDgbpoPr`qS*5l!NWuZr60Z9mL|i)$wk6W!N!!02-H?r>C6?oSq8BdRF%dy%$@lUt*$khk~ITal92KJWU#lOlrkT*JpZ5D!D>B5Pk# -NxcCBf*B>O--V%qpz7ABgpnZ}ihaOh^`}+d+7fCutlYY^5o4z?eqII-BlX!0dq4B+D5r3)uK(Mx|2S*rIUp9*CDj-m#Sl_# -mXAvuws0zb-AO3m*jvpz?fJl9L)~2BaOQx9zyiqpzQfFhwIu8|P8LTNKd}lJ<>Et5f_^%An*ZIO -~SDjJ?2v1F7)HvOqKq1V5IN{f@1Jg+69XJKi3TOlcoBY~v@=azsl8-62YkuLN(!C;n8khn&pW;dyw!0 -P%boE*Xs#O6o=;8cpvPpR56o6457xI%e00j4hx`ne{6h-%~orLGo@cc&E&L+Z{uIAWqX+IY<#B--9dd -UMfCRH0q_B&N&>uN8feLRN8DSX2qFBfHk02DmrW;?B6FmX*>`dyD|c3SAt*4L%q$(w8F^w;1hHqzC!GH_ -}@<6NJ{(~Jg-&-Xo`CU}$Tu?V+AYA+aKl(Zw~lKFzm)Q6e7egV~W;VsTF>!1=@jga?<*YBeBy4k|>Fa -d$aGq>mM)QN-7jYr=<%P%{sYV*mXx)p(M5j#_;;Nj{}y-MSCe?c$$K(ofez=z`T0L++V#UbHSy( -P9i1NY-`jk?jNu8MCRUph2em55hIOY(D&D|53p9r=$KFvi*F-k3kzofFMF5AcjB?fl(BOBcIyZ?tZi( -wDEc(*+};KB8xYw9fMoD6M^mJXmTs)CtEy?|%tg$)eLR+;MMfTRMbc@zD)4FV<_Zhh5x!2e -bTCWiOCT3fY!FQdx5Z+q9*03!Kw_JRLZ`04z-hGYlX0<51rPH_6I=F>!6txXrZRPZAOH+V*mw1|NH?f -9~YfQPuZ^@ryw%3-Z#lNZ3$8~x6C*F)*Twv78%rcKOODYZ4+SqGTQV{?*{lOsQc`0{t&lqA0qoTZkx}dluoX~UXgHF4=+O1m)#S)hEj|K%}H8<+Y_wnobVAG%<=m~-Ksg30GxJC1l-L9<SLP*XStgM<6C8&H(cv&&i@CDsAAdT){lKalsG0;`X#ND72LGaC`$>tG&B7E -GkhS69Td3*+~Jkj>$*tOrP$)&tlM_y4>D8-yaW&E2?vAcWWr83~!?1mX^EE5<|_)B@?EACFMh8Nr2=q -qh)lxj(T<|hGf1}hjgi*AjD15@sav!*!QpQW@cg}O6r^PEzlmD+bq~mTXZs@(uL>9AO(YxvedV6oHiP -Kx+2yrXNfLYw=Pd2hdEti5F&dw!(~8p7rN}9mUiA -+Qha*9aZG&t)C)<)$$af0@osybZDi=bj3XrfKLcY--8zjbBVbIZ?gkGjN6cjMK9IYdUDcs)+ziDH0!LhUDN$H!oKz0J7I@Vpgq& -ECKxj4V6G$DJ$ve(zU0+<{0$m;sk<^t}`CJg585)Ne?W~I;>X~=ggP=&Nh30`K7JOYvAQTMta84-sh7pF -M?y}@*}Jc?9&J3@Rg+I)p|~|aA5GM_Z9vK7+QbjX_(U3qtvGX)9J&L@zbz7SxvNM2jmui>IOC`#z{L5 -Iu`VI!4!-DzlVO~AAo``T5vSsEQ}BQ`7NWmO=BiY4KLkb1|1JyO&LEm#W_49F6S#UI1rh>#1SK2l}LR -94^g{-xjzKxo1tUkWi>d&5r~zF07p-R;-F?e8DL-C8{_~tZ^KK!Z=RiFo?jPc0R;gRb&$_BeojI8f;<2)|apbNFcTKwx_!$@Y -YlS|4w>_BsPJwc#ot&bW3g_d&MPzx9E?8w-;;tg```Mh@xAP4?(wl9`w7kTLx|24$+=%TSLQe55_hT9 -Auwa-;I!?cq`+q7eK}Ri8UfksjX(Ui4bqv!+$L7Jhvjnz<%$$KeNV_&b>Z_ -*zCyNmAMGO&qwIw&pIFSH3IvZ^tyhLS!uqPRla!(ZbLjX@MD#SYd*AF0{6qg@Rvr0X%mFm+USiBMqOJCL7S9b(e2Ql(_on4UJ@&S;KEBN^+>NuH?BM|>GK4|UG(bO -r%KYt2!!h6%0NkrwPO@977C}XDk!(NumPVrV*_OU(l5v?u}ioDQrNRf?CC4D3|=XX9-zt9QU_(xPH`yI1IKE`F`CQ_rcLjrLM@GtgxVYdL;smucLQ6w^pZAsd2l#Uy5E?gre%G -qg<{%?YGiBs4rEJ`C=B_w2P3?uUqgw+W@;_9UkIpcHk$9OAg1_f5Ro5S{yw^1}Y&B89eIh(L4t#B?cn -X*ezMfC;#nFA@;HWMBc0hMGW#(vl}=tm|XPaX<;-u-a!kr4jX2juyxEXR4G8m>0Wd%17wMc|NHHPAL# -UhK-xb;!oPXo&sg~Vpr6_th^>1b-v-YR2*e-^LtzAlAPOZR6vHWk#Hdf(09VY)c5RdmZP1PSukeUtTf -qmVHhA2iCj57l?G>fZ`{|KzgE(T(UaZiy$&Z4Yz43-s_=ZO4#}wEu(H5gy-$S<7qoCjAGf;RNHrq;1= -(b->Zuqv%n@3wi#tNyM_t7q(kAYjw3#N7trf7Q$P`ssQHXy|}#nMem7257B*|B(YcKUOd!)pga`x_WC -kYD!3%67X(r=^X*T-qPQ>qaVf2fIrNRy>y%K@8ax+W-w!x-mQzm8P=x4I##pKl?qUr=l+%Usnuu-A}o;itPsoYSbP -x*=v^<4Mo1amAz6OFwZ1B(AbnM27Qda+BdIY2j)L?EwaAPHi&S*+X^y3L5w$0J#-L+g-mYN%Y*G!=VB -3%eE30+oc2?EkSc{k&#tKl~WI^g)i6wii`CycZfpSvkuc~srQ^S?1hqEvZvFy`O&M>T(2I$I`!~XH=8 -q2xKfYe^G`sfX$tHy1RQ@!tp9Cuj`>xCKGcO_1w3B2<|Qdwi!yK!)|9LhW@th7gNIs`BZ%jI@DmsbX< -hKmASZ?8*oATd|HD{PTReBUT4TBt{tDZ%UcRv|t2UF-~;fIR5_mfG1r>*706JfkU0R+k(Mq8R;L#zMN -c%h;|Y&ipENw%K7%z$v6}9qWlQ{Il9w{N;)JVgvml%MR(%`XD`hL>aa1cI{DIqbifhtJq!tyIBs=zi< -6xDlsqUEVRF=?Efgjhz#hJbp0z4kr>e={l6UJRRnJ(AMkXQHowZ -^W8+tmOhurh*|Nt$eEx8f8Lr6qDqx?F~9)CZ!qESVD>;v38LhG>y^4;8UMQrH=N)jg%PfQ*4H2NnI1P -Y&aQ)l1Aco-Py@UM)BPUuOngTKbhjXk>AZ%lHtKBZjcP{=x$(p(7tCbsj%CEWbQtEEnZy(2}bi&4cR- -H{miIbTg}=tLN)TJqh~Q-@HW#<5_Y;d7{WU1~O9RT4ugGMM&dFj|La7q?zHh#>;NNS@KgkVPs^Pr%XA -^^D&H0Q)U@bA|r+6k+Ju;0g*K{gERhvAnDf~erLz~KRUrTQ{Ml0@XzySD1xmpiQp&+qtptO6uQz$5(C -Ng2Z^94j$*{81pqAGM!k~F!EZ~ZZxY$@mc^$&ym;eX!35eEAqoDQ_`EF;$G6_S6;r9*O&8r?MEJ(?5^ -QT<-xSpLZop^waUQ&pyFA#GaR=|YCK}%?`Y=kRdx=lMMvG%s%LoWTu-i!TlCuwZ-x8rQR9kV~(8U&1&6~!*k$#qVb -|CxcdlMk}BOrZJ~{b~KlXYW+aQLh?NOc88EUlU8%dcdv>OG>ec@74vi?tuKkTo4{QpNz_!Zax=E;5ncnDufF9oek7^b%2^7a2K<`Wo(BP32jFi -H~ZhELPO$W}97L3pLWo0@mHq2^|IPwgff$(G0b8 -i}{EKaOq^Yn!SmwyTV%zf)7gHmKeliNWo>D~%<>{XXNZU33#RB{l;P2;A-}+^6N%kb&5z;wfU|_~3rA -&Gchu(_6o2vbzLt;l>{sF}8JOj`%l#cgb;yNF^4Yfg}`JRdYgzex4pKKV!r{i8nf}3nnY&4Bw0s!85e -0i`}%`VKGguwI{F*fU94p$=`_)TrFfp!n-W2Ymwyc>rVXsi+lYyc{1R;w3@$3P0c?^vaFPOXUvrb8O{ -Y;8FTsT9RvULmVdot;Gf>|ulnJCpwwLbl5krS5fPTrJ4>tq)RVq74p&ItHeB4hL=4`B| -kS*vgEg8o=;KR2&Pzu3X-_R)w;!ePCnQ{;jUI@>WZA>xAPe=*hy6K29IAEe&JMf>d#IX%GFYf^I|xzv -_w`}-O)-smx9prgo!vA{OX?cxpClo1GJ*v+q8F3U*z(5wpY))p~2ifYgqIw=IX?E`uGxiir|Z56&v^A -#@{b+!(0{{8r7QsF!`My`730)(6hX_#Mv3!YK=XyM76R=wxILF*UD3vYq$7lE`0`}TtlJ+&DfHH&?qq -Y*mHa*a4SeTlWN5<-`&EN$y4No!syY%*(Sn;J*%M4c6VNrpPciZQpX#mHh*TrEI+-oH39%}AMVoO^k8 -r5U7)ov(LR%I0hr%uw+QkV>TIbRUr!d!2pw;T<}W(oz~&PZ!_*if`uGKlzkMGr>-J<1>agW!xjy%&@4 -^Si{wV)7?p;rT2-_Qvs_Du+>L19w8czR9 -c1-93ky?DZQxqmb4s3abp#5Cj`I~bQSL;)a9XvzrxwImDGD#IoWsugPw1%%k)%)qw3Me`^k8}_#j#k>G1-lQ!0~3N>Xo=u@7tr(%# -q_vOsPrrLcCsAIN9z^Y6(G*?j%P-v5+J^DO({)9HVHl3ytGe>lO9sEa}vLBiyUumni101U5SyCN9{Ll -{XBAVDD{NPRjALF{&~S+)z7CL24(kWDcKCpT%+l@t@?)-wmC8*7Gt(^j`1jiy^$-R6ar?8@T%@ZNg9l -^$c@E**+*nP@WIp?pW^-_~ST2E6so!5h}D&<&y65Z{WXD{l^yZ89C+HByn?XExi9r$nMz{?#gWI -eXKaY-p2~zNwnS5%J;X!i9dlZTW+j6|E`55f$3{#WjYp^i$jZP3md_yqEAeoub^8Q=PgOLuuSo*b@o4 -H)E|9${{u$7Rl&YZ>&f34wP1qU-_$Tzk{N>LjGfaND=cY-^xn9yMj9bX~O5&Ck{40^9wgm_e`|kHQ=-kLEGhz%a9j>U^)n^7|7-NlUJ5 -Xt+B~MZZKOpJp^ty09Kf>kgSHb`)K%7}8iY?5?8J8syJw`0~V%;X{-BH!BTRAPTa`3v5AXJBWw$)Aqe --RRc;xJx=la{;%$Y5TwtkEnv!ER3aHyXWwA3D8$epDyD+hqIbil>Q5kJ90dq;&s&pjCDxTv4Fw(_!FR -ATuj*UFj+DR4gw$I{EZFS^73xpy{j`;z8h~fv)HarD&ub#!K2WqDAOcW*L!lPhNn?rS#=UB(gz6Z53J -bBx2ZONysCas9fi{RBIcF|Mv;gz8L1WaGOvr%J$to%JJ8=_w!x8t*l>u{S#{;w}d1JuWSVdDFlZh;?v -ROa8Ki{6a|a+{*v8o585Rg6LJ%egz-(s8QUGMv(GKEH!ibM7-Un9M6umD3Eh&0P`Gh~m6Lq*3u7O%Xy -`^X)|2gq+`sb-M79NR>zRqRQzyH;B}#5eUF$lzE}`3?8oaqP#l$wNws9(STU1v{ltsJZ7POTOHz$aF0 -BwC=8Md`Yha2zuBSjguqFv8^9~?UqF*@<*_oX_1IylCezYdNC_WE3J)%ZQP#?cKQip?YSC@{QgGw*za -ZtFv?v0u|@Fjj2MDFC+>;yx@BAkEPx{bL0A*KL#jOLL0V$TPn#3c#1{6pg)DUFbnrgjjvN@Ya{2%o;s -T@|Wf17PbG#@{g0lv!pJDc@GW5plAnrY#snx}vQq6USojvt#jJ{6{UZIyt1HxgloW --OdU>!IqLG)07}LlfvBgqjI&Zq=Es68(4diBgHWWGlXX#Mfo%iNxAoY=+i;H0_qVss2a`4o;{0(l}al -XH0%PT9R$KJAgnWG6RW8dY2&n855#pV~nS5;w-t~Z4E4WDInYTwk+d?O7CzKR*WUX*Cb(Xs+z6 -Mzu#EvlNTio>z0$P4e+Id_XM4+p-ma)u}t;f^g$6CydBSoe9VP~V^9=Dc9M%tSDtjCpg<-P6NJD)nq= -LZct9=g|`Lim}>LCf}=h>YyGuceqDK**9_!O;aA#6YzIhT*W7HFrC(XuvYNOrT69G3RKf!2*Xc6K!0g -*6~M_u>Hn~^SQsZ0{_!#1o?_sC`WWYVO&=di1<>YEvCrfuLLa=StzSUaV?~=5#RI=RTsyC!ndL8HXy3 -DZg{h_WO@htgSah(M;>R=19ZwCU4=(ly4Aj2xxq -XGcjU6FLrVxiKqy|!rXz+3P7iE(KLA&{dZ&&Y@JT5jNTGuikA -JV3LZ*oeMEm+4l$T)pf9=4{2%>v&ex> -fBVyIBGZZv-Nax5)mtUV#+8TN7rxYaz0=TdqGp27tC|9JSTewn6HZI_wSxNw{Ge6>n)bJl#!=pzV_DT -iDzKk*(im1$KnmYIxzF8#cR*9CYnhxKr0Ntc9hE-NyS5QmO5{ci5tXj9eIKtD`pT}V;@ytN -VG1S!CbyQeOcKB-E&~u+h=we?#VcZ@nl?>YE_#AnO0& -`;wfY3X^)@UOZHw&s!Fzh(yn>Er@??%p{{$zQr7zE5a-CJ$as=T@275 -o`@w=98ex11cGF1?+zW}tDCSn-m+2uimFN&`za4{K>;5P`0nf3OZ?bmu3+T>o(g%Ir5Jpi7pSUPwRep -kr%*OD%>BDYKWy>5<;4{K%SoFw?%GWy>i_=Niu$`BPkKJdUsR(0j=j%+f3mM|_{V*JL`ImTFdQVw6%+ -{sgGdU;Fc1N;b+yCR4KRU&DDi14C$!V96^&LX+XSL^)x-@;lFhbAjw=-<)jIkXk0R@efQt! -I)*w=CKEb7h$;zg#hQWr!=zVtWxQ-ldk;)30zGZ<1KQbL0beyB~D#D@8VXxY50Rau(Z7hTy%?WyQ$N1 -0mcRYLfIz`wX&Y*j5g>LOZr+;nJPquKR$yj@I88O&vE@h<&%z72=W#E=hbR$}24pHS;);x6fNS(_af$ -7kA;SHD>{8!UYtyNteKU?uzahcw0Vx7p__tuo(mb7M)KO-F*=s)@08$ZLt0(AN8k36JYN&;rRF -FkMdEZN_JV~U$7ZTRN_rw=rl?{bJOMv|jBKD$>a) -1qQ{lZZm(^up&$xk!Gj>#ZbBBC-X937ZSQpheYtS7;~$3OCyhOFd1=o}3?TYlEyP?De{)-BY;ic10M4OhMfV@5Am_H<=f -?qW*_?|@*@5RI+D*W8yOz+rArlvdJsF5o0vp ->L%PmM}HlcibnX@s?>^CQE~AcLn7+t7h(12+ehh45n1HoR!Juxm_sN&7p&%nZtV$D$%roO@rwguOSCQ -ZQ{o7R8}-nYKHPa4!K#dxeehaQ2HhNT;q_th=4hXfeOv$JdK0LN&RG!~=DF#0U=8dh&5ZhNJQpFp#d4 -J)oD*(;Dkww{+3UyM!u!6MJ|6RWZ~fwe8!bt+;}_mO%$qT -koOsaR|tN1PLIJZF9sAPV8d_oKorY(S^~*n^9ZB6t|e8=pY`iAx>rrl!b)zkGz?Vukm&V%0%@WNRKcmc#7D -(@Y<@&h|X+}fOQBtdJW(vqu07}a|`OJ>X45Yj{t-&!YF9#^{&g+}$9pQN~4;)bF=0TRPh+TpA+Zi0#ywUMaLiynDTPtt+*|sd -|TS)fpwPhI2zgYU`aPAL#evQ?B{ngJ}+b{&eFae_!gnimO1ntfeYsiz}TS5Q{w?WK|+8hxO# -+O6!-2J4wga;r+tXOp@*yZ336KZI*DP403tDLqkOy?crHRPY=-vl}Xv$#Y*+Wvq5A~vpv$;=#ccHU%3 -=14S%$r!r;XpZG9=GM1=*PIw1&+I2u+DbrlhLE^2_4m{O)B~E6pHBuD4lGgPrYgAj-Lbqxw -(v8=BJ>K(-n**6eqPSiNor4$arC --|GLMN__x}w*siul{`q-1iMj9dA8n;R*%r47$gM-=_RGA>JilwW!kpsgtIBePf`JKu|PqVf2XkzXg8C -zMf7|FUl(d7oEi;kS4pb4;aoR9;6X0&15Ct>OmUspqFOtfT_3)C<#<3Z!LZ}yu@%JDE2JXN!EOko5zcBDh>^wWH -=sXoK}{TE`uo-1x9K=;=?Ph^$94Cw>89?oZ*JsEtEL*v7e@%H?*vc0to4wsz|SdzBpa(1{9tq1yjl@= -7xdG(Ojbg)Dxe)8dEI6@~_~D`zJlFY8Ti4qVM7D{jdM)!(Vrk@cdu@68`rSgfQq4-v0NTh2#I8)8z45 -e?qq}9jg0*r|hv)f9I3k>M~5$jYz$o_$Q9PV#lkD)A4`(wL$j(=ezl#yY_!@CqLpM31TP;ZwY(|hdy; -}im`nrlh`|akS#5q>~MmhTSa(9&6UfqNQuN-vVtT(w>rePBmt7`x(a(TV?8B^Zq2SZwHL2m4X`rC-9!WNVoLI3X>GNLGh;4nryfpliS4UiiqnyZE -Zs629W4JcS`-)p;*{5_^)qf6QX_LM{H#Tzb+)~wBn*H-hTB7lwIe0d6?PC!#B6~uS^po=8yVS8pmTz! -p|=s9&;NGz?J7CfW}?E68)zu3eSn?mkEc!WHgHC*4#r+s3$_d%WU!2G=;Dm4Q?CU<+N3|IqhqadfZxL -9g(WSH^XeU4yjFdCOj80qJ0rGt#fPiEFk&IRloHB&Dw4Sb(suKoxTsI&K>W1D|;+oYpm)IpT2ojwzrv|zW6F{HubMaG<%tkg!=l|tNy9N0sL6vm{}{02~3SFhw -Cz@YB1)x6_TZDc?MKdqs(y1$ZmRf=StS3isJ4L&ixyXBO=ztNVcYHa$f*CpsOQ~PQ#Tb6!?52Jd^CyO3~o+LFl>TisKZ7SM;P<97{y57lx_(plb1erTTj8uorM;xk;B^yG}az74!#)@`TB7u9iP~s%g&*FXUhJnoH))E0(O{Q#FQd@s -|7b3=zgBhY@>=jaY_1*_Uv^?P;wgMHjw;_|k9&h13Ka&yaQ?4|_0HZwahYOR?oFl1y1KmTEMH#Bw>p8gQWw9EAD5#);}T!H -3i1NEDMd1QU5N*?eMnnF-SXYe}XQtOAH$A|{@o(>=o(lQk~t@d0Hl+1apM=f12`o-|7$j`~h@&$GVlo -JZ(Cj7tzZ1=hkWaA3(MR^>t&h4;leXsTxLwWfy^aX(Y1r0LVA4`!n<)&V5g`VgURrODg`1!#7%78Z!s -oAq4S^p%V`UyYcbOaRORl`KRCfg7ts@sIQp(nvvcf>xfy1v+~55ujv4I}@KKlgRoz&YGh$zgC~f-8ouFt`FPy4y%>nnT$pwy>f%o^IV@7`gpiN -g_u6PTh#w2qdv9nXj;mL0g?-<+AZ^LvCefYdU{;LwC&5tu6RP^PW6y&9NMQw7AU~J_<%xi<%pN#|m^7|b4ZWck$Ukc{S3cnj -lY<*#~{!uXhx((DF`E9t}x4Qv;yq*8a-2gw{&QEvqHw);Sx)FUplj!5wv~+!|y1P@<=Z3D38;0H??3k -Y@qO@(vR$;hv-(f~v&(rOK1R_NDiwRWjy>MgQEbeu$tdIbQ+#H%(w_ZSyOUUb&$E9)o(zD2Q`6u(U2b -cOCtvXeBJ|g}GoR`L7)8QUI3ve8j<|^aIOw-XqgHz$PKx$3qr@YLP<5`eKJG``hY70cg)8Sd}s{#moG -`iY)YY=6lHIiHmLoo!{G3gz)Z{LWSaqgS;QS4!A=u0CU5i%>y<`j~53ZbTe+sy?ZkDR?$gPD#DtKZZy -tdW=?O&Xas--XCF)hds@HOT9jz8*-3_2!coAkf6yV*w1<#k#^E*+H|OL$CKZx2Iel)#B^0=i8qY?yvC -j1zkAcGkBRl^Y#4Fc*WI`dp;3mK{aXak1Wvgyj<~b5`Mg%%KT(8xEBZ}R2|gINkW-k?%+Mg{u!m1Si; -2ZRN~$^*9%VA*`Ue@K&;5o5dQPg#y98`D94q?2G=k(%VR9J@6b6aq2RQ0oW%D_T0A6W4chEG*!cCQDv5V27IrP9zeIR!22hiS0Bnfy8!XFma{apE&fW_hqr%yPSEy_s$YjH|BKW -7tReK%DSiT#&k$uLQrOOIQg|ad>$3a*Quk&{j%r)7=sRDrAI~vv6@9nO&I5=>AQ~Y$NpJKB0g?dGef? -z;nYl7^MefX9RmZN~hqWR?fdDBL(}#~a+?_?YEFm1sI;AAQl9kJ?KLX=C`g4n*2rwgVOOnr6&{bS%;L -6;%c++$wnklo^meieiSTA&$dldgP>OF^r3MImg{iU6?LatPPkW4R6R7=VH+h^-K^l -1OUvN?w74%m7jXgS^eIFAM=jV)Q?;-y=!{$XoTz@j&1|-$TCqw1s@|M5%?oCgSZ1CpyTeuK5g~t -&6CMr`1H}-Al8V*AVz>3vN76YT}wMV7Jo`nKnl}k4pq_HG&;y-{o291?0W7wa+?o^{x%@|lZVjP9nW7m*+KkaS6ITe)?Z1mpOsh`9tj -iOZw!daY=fjL -U1eAPxxy?@>MPVpE>FKx&y%Eo|sadGP?_t=jrkM+S70!(^NKv_d{@tH3!iniyZ^^|yBz{E)xoAy(BX3 -{%>SOlr_VcBFX`H&#oEk>rCkO1sjCz+{5D4)~k$7<}zYpHXaP3ukU%0qLt2MdB0VoHN+UDCl{7&K0?` -_V8>QMR7{1yBG0D%g8Wa?tL+5ExA5&Msq_=YM+XCl*Xz&)enLdl|pSowv%YK#iZ2Dl&oYf)IOwnME!G -!GH!AE=+gKf>3=xO3J;HOtOG|;ZiSg|2Y?BvpMdG#e)3m1`qxkV0hve?BN+^57#ia!h9$|*?Ri!lA-P -TNPJqc^k_4QBC4iC63O)2@+7D)PNziYMeqrv)fqo>=@TUMOz{#?0{21M!g#fx3W)rWhEQ!NFz#fVLIA -MRK-X~&UdIz$Q(tm~&*inmEphyIQ{A?pTn^G~%!1i0pg5KlG*RsuwXXRkwHlCbP;KJC4#}Bdj@kJYw{ -=U<=1M2 -;d3n&kdVPQL@}Ph9`u^nQLCL?9g=;lriI`=ZycGP9<@PWfp?gBt+Hku*19NPzEAo{lp9Odjy(H^oF@; -3oo?RWn;T*`xZhnXb?)JrvDA(^7q>rIEYC`77JhBIJ*C%{_?Snn8rv>E>$J%=;sA^oZcvncp>_=XU;z -nAzuJJD1icij@2W2Y17CYkJ4pQ==3Wa~Tc5Z>>jZN<9xTXy_gGbqW==_0yP7T)dlkbhzIUN%fp&AA<$ -;W+?8^aTXvV6UsO1qPkM?{^O_v9(`9kp8nJInBTwiW$-H@a!rJP$RtpOUtZcF@XXD#6}g8Gl72$E1*B -t7@v{vyA`p?7f|E(NlWuDdllw^5RW(T81Y1WwFsZN5(e>!L9erb2b+R_?Kw+sdNV23b!w#&aN)9QD)z -d#xZ_l&dw^7=2ais4h=;<+c4NMBt_(d{JUeJPY#Yg_@X4qD|gIK!ZWI`gS~$8;xB(#dR<_D^N|35=O5 -dXqK4X3s`qE3BSv^eMh+R#M|Cx%Sx3Uj!&H#*f(21wZ3?mj4Irl+A*R4qJ*FGpbWR+f$RwLb$ -mbG_MXhz>Qtm@_uh%wSw$?PVaTLQl{=Iq@0_e`uZte>A+#@CaiAZC?U9Rw&60@pFfS)nChX;AhIQo5I -R5Rdx?|RmS;sIG)X&msS>I{D*)@`;rpn?7`xhQ7ogp19bazQEsW6zC^~mM}BFhErajm)E`=rB#G!sMk -vBni#8+Qwe&z?RTeL`Q-$iWw4t?wGG=9Vas+;gZrx%F{VT7MWv|y@ -eoG+}A&Qx!Re7`fbLYGdoy&rI=W{ -UeW@Zy@SiB+^N&%rMwP`u=O_q;sn{Gt9jkJ8e-3@dFuSSuht#^q7wi<1=us8!Y9KrZ82JVpE6t(N=)+;4jcM;!AW6{lD9XR1_9=FU^6EK@Yd%Vehf -U@=Xb1-L+6MIkprr1&a!rdMIwzPxZ|LBSzR;|#NDUpT4#SclR%P8QBB~ -M1J>6FWR?(?tF^~o0_*y%fl_W^UdBRK1mT_79$Dmps+@Dj? -8Uw$F9KmG1U$bx>vIxv$)VmwgPQcP-ut8K3G}&WremTwUl>Z2JWc{xBq~BBMjV4@kdz_x6t2aBYP*j=2% -1H~U!?`bAfx+vdP~hZdgsW#Fi*2c5i{sd8Sk!+HH+hRT7Dm$@G5M6YRnhrgeE>vGwC63G`5U+qZsKj2*Jft -#6aZ`*~ehS@Y~fOrhT}_M#4=?Mtpo5f-;-ZN)2(I*mKXm{{7H&rWd{Eo+{Y)Tj!5a%iUS{fL7lCigTq -LLc~Ew@_TOuP3IxKU2|2>ZOmLdngdO?2qAzfA^2}mW0ValJu`$V+?wY@~y4IXZy&~Zv7EBldJMScp9e -(5~bOnQ0l*Pp08l_Up~k8a0XN~I78wbgM-izf@MF|)G!3-EHWQSx-r;w0;Z}ombDRKPHt8wwX+<|^Vz%hE@KkHiapd|XwH2WQpDKc1hk@;KPn+J~!GrVU<{S%w6=S5MhfPV`RamN3+bwJXdef&#T=R+lJkTZG#GI8&+Tw4^{oP=%HlTP{qhSXW(y9^!k -K@`a)FsieBuwm0bKa&&8A+v?nQ@p3lHfhu#r(l-eDseq}Vd<>-iaq7?mXG!lv1wgJUq$9ZS+C~#aU_{ -(#kPQ&QbyHR&TFA{~L{_aim8P9{Pn>l%ZF^E{~GwvmeXqRRRq;qN?Trhffr-RT}cds(MFvo?KRl_hRM -7x&>f{{{B#STS^B#P7-daR=pik$cbqi&GNbE8m_xgxg~N2rk&%x)q$?t`!<@%7qEJM(&;d0FwYK3u_6 ->YfQ=UfS-dvZ{d;(3xiQ;U(Z15mk)vQZB9mQ^XrR()_V}9jLH|sbXH4P%x{{O60=Y(7CG-C{umx-gpG -nY;AM4WDwJx6Bm+H+51qA%ZVSz$WN{os-kR*!gm&-heL13&H1iA;*};vPCRS78M-3&MSdDIB4ro!d<% ->dOdrN6J74SmLRO)+6L8!_xED&->g$!9-S7^=q9-^GV^@^9|QvD`V4RqF`b7E@ -m!V-kPxM^%ahg84pj5ydUm*_8#{Uw?|y)pt4io5AJLq>R#3l(KBOg)>E|_K5+WLHS_HyCcey02E9*8K -2arZ=PR3 -mUG-Is8hFlnjRGVYe=4#;?U)s@67$V6o<-42zV0piNgAORbFPrnk%Ep& -LryKqaeL<{mwyQO|dm+^@wo{9`N;kI4>vC&C~ogAQ~PF@O1H~9W@nJfFa21eqyk@(GIwFac&x_W00zg -J89xi>z|MRz8~yEuSw+fQqzm9N(1`BySuUwcKY%LznDuZbsgt;qa^wm9$k{fpyM1YRx*``r_ic0B6)> -oRrC02HT+E6%lUyv(bylvD!kTDimXKVt{aqG?W$J9ecOSE5E0#+%(RL$3EeUoGZ12van?T$nZ+lI^Co -Sr)=vnh>YBG!qm?2}_rs9$?h)NncgRWInV|Kq^A`S45KXVk)uVG*_FAH^hTmTphs4X?fbaaxkh{}!;A -OG9?0EFn7SFc~5y_CyFAdN4CdXYzX_5kyV(#&cVqO?=KE>@mO+2@;8{+2UJx6FYd%PGA`muA%*f*eSE -RT7VlZa$Y-Ea|2DV^J6cN4lUB~HnHFLU)fF~UdxICY`Js%&!~9vSk!Iyfw&Ipp-GjAF1yil1ls#5mUL --qT6ZYKQq8NT+@4-!H5qSL^#?nab{AANR}g;EIQxWgxeBfoyb_%gfTz<$H`@Vfpr+`nkBOoPJYmG|>T>HJ&BdS-uhImZ^DQa5h2)U$pZCh*Jf-gqEKHFcC4@^IAfKh$!srJ}l|%`^Q^puD -#Jk9w8Nqx28wKlz{c9{$B)Ukk>+4*4N62V*FjKxvBPP=e)f5~DbZB0zE+$6+M8)`g#Lhp(kygl;mKO{ -1KIV2=RA(2$@uBsfq{;Tfp2Xy%{H=OrQV!(u@nAB4AU1JEI}>2j!TY-@|J!DFy7z{Q~30hHSr*wn_jU -zCLFiPmZ^j)7#G+e*LnIVcW#EeQvnyq2hIod{Yl(KZylbz<=C8?d`Ufga0R-g4WfII(#o0v!_xL_pYY -OG23i?P>0t8;Q;9J0e&=H)jSZW+c$Dsj0KSZIO2}FY@HiGHcmeB<~Au0GYM!_)pob1X-1hmFE7?#xQp -GiiWNMHC~-9SL;h3BL)-13+VS-;+JHc<;!DYKAVe*1tm}ZyvOlxU-|2WA#i0-+Wlc=r=di95GT5OlF> -u1{TI~5YIJh7sY)7Hk_V%O(<-%<<1IcO*vg+cB83ymUE-JBoy=Q$e|Dbr+BcfUA9ht}K~s{~m9@V*me -e2n$06?VvOb-|JUr~VegD>)R0|G7K#%impPx%q6H(d}0&U+^siF6fUSCcZeDdIBPU3FI>I1UtIn+$v2 -8|&p8tU|oOD!SlWF^9IlavU>mjg{HjcM1)XXqVThuS!H*5b;QCqJ|1ygTkh`4T-(Cz{XinpNDTVR4&v -ZStKEwY}Poc9?rYm!Y#oXx{nkcoriIu{GVd8|N?%WbAauuGH`M$+g_LWK2VVQ(iksn0YnCLiAsIwViu -~KEjaJdOk~MY#}sH=AfwkS`QcMak(WjD!dwF$3;8hmdf5PI>=0^rH>@gg@>@OXIP?98)|j$&bhbKBf0 -AMpfG4p?fXn&^Xz&JS0M1<+LYt|Fw@m=vb@NSk)n8I2UK}wgEX6vP@3W6ajx!SkYB1Xa0jt`3=dIh?J -kbYi@pNFj_X1Z9#ZwhD#>^eJEIxuY~kM?t3$=DgweKnk=&~q(c~$;#b^bI>kY=3*o=4B8{aFtyc2dOB -Y{uqt!NdCYCVx{=_FAF$d+Gb8o~O44#!s!303O!uKIvwYVUP{UghtA7Y??VJ#YkX;G0M#N6|D)n9EMo -S%aayQ4k3B4n-z?3tm*QVIDA2dYAvI?C`a+Th{t&{JQgyhbyxQ13|>AH*~EzK0H6Gs1d5op*VDeySo$ -0Qr;Vq_w|np{^^ekGz&$?yW~K!HyMjTtc-5deQo6dTB%pp=LbcU`V%gLfQ)B)6Fg&Od8Q*ME62*cC7< -j?5WaZn-3{w5<5xvmS)0F-F|4{O6}p~mz64Yi&4LV0cv+d{Gfe>?j;2<4h -_$bKNgNbzy$M0g*X~tZTi99e5Tj-M@m;Fs>S?78RgGrW;0C$z-c}F409?7Ukhxn%jGR+%ujkEID%N -ve)hYmh&j2Xeb=(*K}*%p;R@7%HPvc3M{{e+0*zYf>CQTbs8_4^^OK=XxUfcBD{St=pdV}&N4nA&3vQ -sIe3eg8?84-e(-O5%F|~WW8V9cztwR^ps`&1;>PwSIXb$Z<~Td#1m3F67TcTG&S_bThqaikA?%vT?p?%>LCBsY0d8k` -4t$6$YKfJarvQ?|t7rCOkdK>0P-)dSOK-Pt_?}w^uE*Pn}6MXU)FQ;mQ(1&QXYqbumX;JdZ-6yawwS& -Ak4~j`$Amvg -TuDd2EGLV1AJ^xJQ`{!A&uJj2H)W5k4;1FjZIkQ6MsG6?_lstwrwnuM{ey?0CNx-gudhq1lViq6YAoX -mPx|JV&9hfXS6G0{cw($CwBUq9>TmzYYxGlfZC0!d(13$bMi#UvBNFVgC0nZST1;|V@D#BPeWENV6zLQ+DuLM@{>7*}*%By1P?&?Vs}@WWkj6N7(W$};!R4)U%qa -LL6VmYCq=$rfd@XI_+KX$U1`+EuW=2ChBGJ$C -qPmoRL0+~c!mk5-EBsf+k^0D7t}=f<(4F-VG@Cg!;|z(J!C!B>S_V~bKE{)xXKq(ac`ueU|5z-P!xVv -A8SA@GGNWK&hHpLEan@qtq}hG}DR)OGck|PxE+s*abbftUhuDi>X_f5TFl|cyV8zUIQ$@zX2*Y^K^5t -$+Ca(qBsGOi)?8igNy}R@l-*}m8IG4gPv%hFKqFc%3#T40TSgc9t#3SFdjw{EZ7cQjqu^k8f+gkRYDi -TN*UtwX#_I1AD3=(pJC%;ug@$ei;f4v>IyW$u|VOf2Kf*=+znG9RwWl9{pP*v)9y`(5dhw)&RPn{E^; -LRKpby|9{*x|X)z`TaNk9gH3=^NtuER|TGC8rOkUOB^U{60)dd)N6UKQ@mBYo8_sx0K0s9qFALm$+&Y -N8R0Xa30+j%2lhabG7eJB8qF`Uf7#Fb5^Uzq0ShMZbRX4_1W+!l@INyV-jLte3MloN<5T|TRtFMaTk4 -0ddP~|4ND*bo}cmgU|TzkE)&^fgQh$$$3t3T%G~2nA6LYq1?g*9;~og2OEb%*OQ}Ymp3w -P7mUyZNt1;4$=k+zETyF>6-Oxmdz@PXVUAa~@H!l?;-to!R&H;s$tQ9 -bh8uLK7FbEo|#IQY|3{uWL_xFH8-C}VolBcxy-j^;Lpl^9H!&@_;Tp%hReaG%Q%qRrw2rNIaXm_>V37;Nap5kS;z)5(DmQ4F+RxJ{?N!Z(fq!P|PzF#&XPz!WwH -7fVubH#ECVc4D9|0Lf6;Hdq>M+kn5dw-X5fr(N({I4%FD;8b(@@*AA)WfQ%ewK@#^?z#h}a^@qdxh}$ -!=k;u?oU3|YW)dj3$FFlI2mi0Uyd^Lm$6q}a -gnuY^K{8X|>j*4Oiw0K!#Aga2AiR6jiFXSjuahqu3jTj&FCiGH+?EcZZIzLkf7;#B;KQRM4D@VFc(hP -m(i>~M6w_su&JkD!i-$0I~eMh-RlNlO;>=?^%?s7s;_&zaaIMFlf>@Nm1RsHvN?#DzTg$+2(GY@j_)f -^+k(KBpHLw70GZB|C2iDg3yKcS@F@W4~$lw|t+hQ0?ec*B_mGcQo%NQ9GkGDdz?$BHuJFFT{lQV_&|P -R{|pw#cM^87;K&2g_32oIV|obuqPFpvtc4{{T9pD^#+hLV`f)ZB%e%TLP_;VlZr$~>lXOW`p_W)@-%R -c5Y;JL`8FxDCs=vE9Dh00SNHUIn`JOoc<*0tq}QX+{u+5&Z>xgb*fmdDRL`&@JZAT!wEGk580dF+EAL -0cDBuQn1!US|j|YBuJYu>Pu&x1c3w@5a{3*yDl{=b4rQMmjfOm!4cu5|3=eP8@*_1AHvuBQ3yPt#^U#lME06lfYu15bbSdYtrKiGqRB6p5Fp`6U^lY7t|s^XaN2Y#os6EWz!;3V& -sp3k#{%S0W6YU6n+8}!9Ig=>tvl-Zn8E!<<*+s7-N7}*h&CHkVp(Pbt{amL=wOz2TWX6dYEpGDeI3R{&`pv4yYuX0YVIf5DA!QNzu(qWwUspL!kWz!< -y{II9ae)0%YykFOZm`!MWCgV66bcZ7PRl0B;RR5WcwL@ruD53Q7cEU7G-{A@{NAf`W@-1Sl+4B*r-a_ -$#90o9P(=SnbM)e~ZKnnC|S;-y(4>{(p(Y*1}U?k$7bzKOpgUa>IWgm7#yddcUFaHUA|lL;s5P{s}5W --^23fsN4bL%@0&wv>#C!_h%?sU+4N}{o9QA&jwUY&#*fC1$)emi^yw*!PZT-ru~BG3&rLVjy@r)%a57 -65Fv3PFWeo!9B$FM8u?sThv1Ch1#+)!GHSw8@6=DRh|}Xmw=pY1BGpN19Ac+u(B9s7BDn2>bTv7>=>7 -Hb4$J;hsny;e*y^E~qemXYVsCpRo~DA5(*#NJL4h40x8uaSJ2ZZO;bWtBn5O62vTX)&Po1)8cQIHuu+ -=sD|pGKyn)nig3#9-SpvFy_4<>4)C8LJGjKPF?8&cZ!`ZjyM+yi0;i%$ -|%HMCAqreqg@)y6-47KAlPiMIwwjI3e>2Sd(?H>#w&oWF!|jtex61Bv!{F; -JN@+VAAHbglqD#NV;GJmF)&j4sTmskA)^n0)*#&!e{2YlE!>oS)TUo&NnrDt02i~*O+vS@uW0j4At?Z -vAXp>?GpZD`X$?_exDG-|Qh=`@aSPx4V1AX}g%X=~BKi``6@T2u7E_#VvB4{-qg%9ax|zbK8}?J%pej -KFd=5A4=e8a<&|0FKI3fdg6aF^qP;|jkSvuclN)sYh*4qEsoySjw5hwAdnNonG@)z@rEk_HL>veUXBm -W~jIX)dp(g2dI5}Y`YWaXGH&Z?*#gKD -}TF_f5)MPEBfPgjN8ZQj0rbg-;c^n5~eKNPnxdxns#!7rL&0FJRPU|%1q^qmR?CDz7I!eKhcU3rmxcM+N1k>|d$dueu%oG0BdT8PrG=spmDywK?^rmbGQobT9dn|+G9aE -bEE>q$g0B^9OPh7>2E$2zdi!D=jXFrEa(2&^V5MNJL17GK7$~$%-` -eigLjGvn4m_qMXP7vcPi!EWlHe)I_!koS=6X~-vQOt1i$Kjp9;s{X4?7pHRQBKM&Vr9Q^r`umeCs&gw -w9PTk+J14{Sln!noIH9HIN#o7f`}Iv(36*E6~|HD#eY2V@9nr4|ZQsBpsfwR=vhvm(T`Ezcm?*gqiLn -znIHYUc3xbEasF8-PJ6iAzH}GWf!jW-Lf0;_Bx}Ac1D{=Mh%Q^q?);6IOc`C*kQdmTrmtCk&EQsvbE5 -<4Lx*a9c%Wi`K)yQ%|5V~VY1lPTVAa;pyTW2Sx4N0^Y_WnqicD48rW5312i&7)GS3VhfIoa=Nf~7hf7 -0f_-%S;@qjs|C(HcvGVJw37^C;1^Q!&HOHl@Ypi*3!bvIpm?y`fL>S-{;I?|9q?RdjR+nNxv?je+)7I;whg&%wLE905KfJ5G>B(3=SsO7>4>(wg8;ID9{sKAz@v#x -lLU_ZX0!M3=$ZDE-%>zyjCLjc|hdKgVuE&-&&b$v_;e>;QNdMB<&;1F~K&c>jV(1k3C3W>-8&!hK8Vh -3m_^42)ME@W>ev0oD8+V)FUJ2<&@^*&h3!hnOGlOx$09@e{Dh}v -_lz{|Bp_k)vky>QKSU9CxMB%JIr)TATrZ^R5;G<0;kSt?SsTP8Y1%CI$v7(1CcRuvD6FXm;Q;CU* -ToAB6>%+O%-C98^qB&gzh`Dt=m*h)Y#ZpFxA`$`h^)Sq4)UlX|C(&&Dg)xa&Mkqt#hDjTY5*qSs!kv+ -ILPmWJ}JZa9J@v&OA}@$T7vqwS1mb>=+MtaE`c!viFLaMYxX{H2jdsM&%gp+4HrS^G}FgCWRHTd{{Ue -?Z?{ol~fkjxAb6+KAlGejP`Idyi2|T>Q3y2X -W#G$Aq9BcXp*}5~P6>occSDJP7zXdVhY*=`;I(NmDei=H4^>tJ)?yk}8S(fnTX(HY5N?}+!Mt3)}pk7 -qpp6rFDN8vUhQxA7-Yv=o)X#|)k)~&tN*;+pUWGvFX)8BF-lkW0<&cr!y -WP}Hs+k-1LJj~b4c^rR(L`QO7lfkfma;!`=DMk`Mgj4E2QTSBr?krmwH;SOe+;@bJ@f9Nq`f9b`6Pua -QK6W*60l$m-PNFqdZenxtbpSqbJ|cqk41gR8n_YG-J6THGCytY?=$plS7>;iG(|SZG8^8%0u2N@J>5M -vXo7aGTWc7BnwSMI$RGomq4!1oYZpmzH$}|3wha*_re9g=Ti*7!hYbo{~E*`+qAyD>p#YqUmgD$xO_S -Gdt_l)j$i<$pbSBRqyy~J-d{|D^%>pVR6yEq45ViS3i1HZZP*2L09oKt!md2zbMlg~8`mKKF-cLNfLm -EYgn@zTmGpo-;tZ&+=`D19#W8%NIqP-sUy&DP^GG2wpkgB!;NHBl4|H?9T<;Tr3k8N{)@xuSkixB~2m -HfQ&@NRBA-AbXr{j*OLQ5%Q>)awH~BNN7yw!9p9OKhU(f$?) -Di{rZ^&ZDwcm$lzyBMmxcu@#TRq$cLDu5s(gMI&=*ws>n?tg1@&1J)FkK`^zsqdPKboN!Uqxw -JJOxVx?L{po}(Y4@gh_-4`{NF;MB$4>loJMv8K$krnpjD%vB -}4%)FqcDKSFbZ%E6=<9T0ZdY>-Uyqb(uMk|8=}C@#D!Uo8S*c`>2HJ$Cvuep&l+v%t7Z%>QIWvALS4g -{sTs^@Ja)9q_Yqk#5vBx6RW)0pyc)w>*|LS)z^Sl$mK_^DACib^w7lt+SeqA1>(eqc@F!JXBql$Y?DQ -Iul(}DA|K{gzjny>y`)d?;Yh8@2(uTGSs{$}TXD)oT2>_khDWze4oTezUTP9zM(pcZ1TD2X4dA*>NBo{H8 -(s#wTL(V=r$vY}a9c4StR2^7X;XUj?ul-eNB&|BW>~yqaF}Pp)x0WqE7tFr1AKv|B@LI;mn%5W%^03i -FLG#;Hu6d?z7zd)>C`rFZVP8(Ff4{H)03*R`v?_MOLIzw-pS8Uqk~U>`;(UGXcx92RJylFsC$O2QAVq~p7WOa4&hd2nn -U+y5SV_w9QyC*%$+fB2#J%Gt0$ek6sD@@1|drW%KNro6zD$g9Va~+?qxpq -V{_xk>S3(>tEX5Izq_}CkD1S0eRfgS8cZ3OA#v=bsW(NCrubU<%Qb$R6}Eus-;b>1-)~)DlvqX)v}Ybw6;SupioeX@8{ra_*(98zf=vyWKRQ~qDM^|8>%vo)agXx~Q*{zDFk@H}ekm6&3YQ3-LWgvRzxnE+oW_g&?~Db1R@g|p-M?K7efFGxQ4oRSf1ukWis3lPp$to7>l -ggtJ{K@CL%`PItcftoA^P -B{lR+rXKj;gJhGSt*m^#|Fz^|xGgP|-Bf5Ppw+ej_bTG`_+zo?)nT1s?XKaKI^{U`fO+zLl`HG4VdXOnIis_@K(R -1O&OQ0{!?ivdVQTfMLiFKnx54LxPZ2@jr1rnDM1cW{b;a1$k2L -w(uLIUu*8lOE+miN=A0{(4RVuLK`trm-2qFHzdX=xs;4iQ6Ln<-DG32LKU+YSjZey7w3i@;y`(-ARqy -fESIbg!Pt~h80+?APMMEfvX+71r>k8cJj>r+9-4+oaQl?1NbFWelOi4Z&(e#~Uj|Kxr(mI)-eEVu{uV -@HhwG>_aCHHO^gNO3T$8Ep+q3I^uWO$u -NG|_r+}-}?*j~Ya3`ZT+Zxj8MAJr9oJ)ee^XI2-yct`j&T=5EwX}J1bdK*qWYW7z%E=q*J+(HtdpIJ( -OKf^Gs6fOTc45E13tOr=7zVJE4zpEg+W}ggk-2pqVztVX`bp|tz=3)?EJi?|eiTKN7P*4i+PpV$q6{V -Z8R_tGFz^;BkJ=5Apqxo;+DmmoMl%SVVW9+=I0ek88a`s?J|4kAx5Gkl%$1kT!{Q7=;tjMS8`dtGQc& -B~V0EK?#Lro$*_aF}RIEb38W>`4N78y{yz&v{m!w?SZ`VMRNkmtkgQ#{m{ONvK1te_>o63_A+`e~tvR -T9=GYRctnD~^*>7A%^(jx(1JRc0B1)(yx#A0w8gjuRI7!7B}JS-ZUO(o@OnRbyFAW9BYu4&q)EW&+;b -=tM7)y>}g)SDH?~2MNM(wwJp1ol+)?7sDCiy)6sPU?;q|veYR#+?zpNf4e6$%kDEI=+1B#G>p`vQENb -VPb1vjS-XqHfFq&-lVn<9cNhxj}6cbRG`11$`9@!wwiQ=E+Fik>&_+{9o%< -enDG4h*Sdj%w!Keff^o1b*fZ;wx#ubRT6tq(5O=|~={up#M@huy6g{Bq3*8i`Se28xI8 -{7t$#6QVjCGkWVn5bOuD#ZZsVcT|Kn1VS+76oF&wfbL43q^w&Pc#MK4m>0_I+ -i3g7%G|1~;(1-s2a!Vu%x6paP?aFXD^pq+K6%TdUh4wp-cC*-^97x-L123+ZvC4>hme@jZ74uvEad0=f`EA}2Z(^gt)f{%lWVC@Wh$J>&dOy06c4quw}pC2N -E$+>2=o=4=3JWUs#d7TvUzUNmi$n(kvh59@U?oWX2^s?lxE)!Z02JM(uj;Nf>eIBU@~uEOyPyi}-h6nc8|-T@K0~Y2NNo$7WrHV6H#{Fk}+nBV6wS;#Lavu&|ALD=PA2iq035{u8w|2mqnp2^z5;dwzT7 -jG@WHoBEuxAcR#WF_K%xa*8g#&on?IRsed^0N~-GaA3N(m{~z5IH)ghF@Bj<~Q-ts4E3kaz@!&tEmjA -cU^+WK_FAx0f$Uhx#EujSTpH@&ykga!x#w$^Ykw~?$o>vPj1YO|eWV}OAx$N<(wY)vN?G@ -9aVcoEx_yEtVw!%PROcBmYA3Nd`~_89U=E6^cF77hUu#L9ug>r~v=!SB59LGugTFN&1-$ -L0__ewrO-5=lbaEzrO>AuUSCf>E^t7^TZVS#qu9#NOaYo9~{p=HR7C#|3PT5mrdD5IdkQrGXxrOs%%n -#Q$;Ilvr+cFGEndILn1=w?klsp5dKEaR-7B60K-;NTS8yi+ct0y0PqhbZy)pYyboFaVe(pwp8R?@$(Y -lYPw{#Y^a(ixgW2H~7uHvGew+uf+!YH!P%-Dw41P|>qW6>*TA~V0o-ho%ByJvfX3Q>=v;yya!OppHrf -%2fK!yDa)6b!OjYW)HN&zHkzXI9>ETh)mwRSq1#<-c!<(tjx$2xXxgKLvT~0}<}MD -Cto!BmmdwB8*Ey+#Yr)#;o)oFLgRG-;V8rG4uK@4w?ZLlF73imddc%5|Qma>T7pHF4<@)ZfXIJYHGgZ -~?^p|$V+k^8A()7XZr{pO^@k5)$vUL^(Zu)~%zLCqlVY@T(nCqp}9h{v_WWQ(mxe+26T~_$VukKrmrU -Flo=NNk2^GtDJ>kbbSTx9RXV@g5LeC&O`6Illf=jFEd8Rf~$XBW?DF1^2ZcMET^B)-%I3-t(I-X2cgD -hK#5)_e0Py!hxH9sJ8$HSokTn;q-Xuf91cQazuT()Ahbb)rxQzKiklNSm2;;D-&us4Z1{ -8Djd6-79zXTlL<@PJJ3e2TgOFs|WwAj{IId#R%k-%}Ma?`jfd3dFUtQ;jx?_(jz-0oCbG%`#_05CSua -=KlqQmlRRzWTlkM%*oRfvgg=`u|KoqHYr#M4|3Fz3!x;KM)c^f~OYM-}x_=zsQFV*EpPz*IX`a6SQS| -+@`zL~oc(KGVd}ViH|o~!piAVV -zUqYoRi|)L=CYS!K~zu!na_gO)LjOW@8|QU(W%$r!+X~zuF_7}0K;BgWR -0j2mhw3>ji(KG`npKTGaV1p_Gq?g9Q0MUAl^us)x1GfcSake2Oj{EKSj=#c=AbuO)v6)-P(VSfnh4Z+ -)Mv3JJ>2sdC6Cm~{Wj*k={!3-|aE-g%Tmz~M18Ie68NCEk5!KS>ByDf1v+taw)m>o$3pCF`SKbK%i(* -{&?oY#6Ipnvz1#VO7U4v>-WdVaO_4K?D##{5KuBxppjaFKB --<)RkGvo_4^`jv?|*1kITG8KzvJiU(1iqsr~tK)}|z=3P_dw_j*-yJ;|afKq&ZKhc+;u(OSn`K)Sgiz -prOw5*P4hel(tiyDzS+SpK?8H*WNL<=gAm(GZ0X-){HIW2Hx#ZWV6+bKg}}&=>PY#t^?HE6(=%TBF*0 -UYx(KzJC9SyEvOe2Z;h+-6!4USGF%r=5pyB=RO@ozW!FnU|ZH<6#|Xm-oHgkRjwu4c0%ZnWK{qOBd`!+5M`uAv(T3+P=Yk3x5NDM}~1&HOV`vk==)~gBmndff0!so5ElYKw`BzV=8(ES(}Mi>7w80X -A=5X=T-|&!P@Y0ca(?0a444GftEk}W<-0w%i894aqa-hmezFBn&d$s0-Jkrjyv4bD7csOx;~ZFTXqlc -9^lqETFlwqT}>`FZ|Zd+l=HB}yIZXnn4yJ!m4(;n$;c0h=ma=KA6zOC_)Qe1>WWTQR;~x{6Xr} -9cKTLe>Sbhr-7*-c*r#}&>GxQ@xEuN;IKtgzwHC#FiXnM^Z^4+S8V=qNxkX-6YQi1XZAqGvBhZRkkz@ -&EYUsJY_^O!H514KtyW@C#I&0ieg8RVgJH4Vj=ECl2n?Z%^l&|!Pzyp<%GZ$UG+0^>zPn8wwG#0?V=Epk)2ddM+Dio`sbr*jg-FHcO#} --{06v8iC5t{?UMQ2T{os8D*R$MeKwEhR2^|7yGNR6=T&kdGbOHOI>Mv%9sczG -1fjQ}rgtE>tP-_ZB8q+FXw*Fb80xt8Cc7N{H2o|0#-y)2cIOc$Wb>EwyYOSW)qCBkcQiedh|BWDn~60 -IRJ&0F-IuopgrQ^NLITn0j8$yLvZb_Fjj&?#_xQGDF*&JY+6a`LvO@O+o82uF9fjl=kVpfD-rZJT#>` -Y(F-F!KBUBJQ$(Ir)&sueAD?+zmS@nvST%@HH&)FBtqN9RHIu4>H}0SnmJw{(l*sA&^h| -&5n|iBXY9CAL65dddbj;Mv7&}nsj?r@Hh}k3`#mybWfgf=%nE22fe)tY!>PWw1)PV -;NHBap5mfgonK!2%vsUO@(%l*HEXTCtV_NSPK1IY{Ea18qm!kJ*zCgRc_F$+iG_{*XF -t&!~z5IAtn52O*EKff<>x^oxp>Yq;R{0w-)m@ZD$3YFDtu!iy024t7J;pZM_P^wz<5GK7+7x4 -|$eLP)k%w)(u-ORe>jii*Qdzl3(i24PqE1W32P)h-de1`}pFwQYBIwfXi3bfU?J$AdWZv)5g;3g5Hdr ->-Xi3vy&RO%E)`LIf*7N>kS07<#Y_a--}GY?<*;jYPQ4oc0&*;LaD{EQa2m$JwbY(6PbR4;>YLyCl$$ -dz&I_Q?SRX5z6EEteiH?%th!BpIkZ-u_~bgm&g+c6?B|{fuwR+NzSW-F!3dDPaeYF7}LE3lMltLJWMc -LuVM7dqUrhQ4w9s(c~5%uq>mOMsHW6I{l%JS$ix~{WjS_4_}eVuTe?g3+&l3Dz`RsR<(No%Sw-7t;u% -%+4+J>a%Ml(deWp$hb+BfUE0t>S?ark;m^!IW3+p4%RE{v%L7~^O1B@#d_U0sb|C-9fwnz;Iqp9Tb%3 -vIOa+0o`)_QVEJD?*CS%mkTwjk{nYI>RlGRL`QB?&Zrv)`0C4Ws25pO^BSh<0{a1E`0iw7(MV$y1IHY;d}Rf)68=#>f!9G#vAaxsbJ -feGT%y+9pv=EROed~N|R5Y5eIrmbIn06nAa+YHc)IO*Bg85=@1G?Igz^vK;xB^b#*~y!>R8FneH`C)- -&x$c*9MuvjxqBSZ_(X1rp-s7)y&qU-KE|^P>iC6rid|SwF#g6s~RaxcUudaB7BPPFFWNYvNnMP&`!7Q -KoV+Sm}#86{XN8<_l5!RXzhHn{MHZBXzlC%$CY4yt(-;tsO2BHhrF&5quI!MqNv&xCDG1IPb=ptj5Y{ -=+eIu;I(*ih)a6yy!UT4As@<6lyN3Wv-f&zcbDl;SCBY+_>HnVraQHdG`GYEek|qwsatTg -IF>)F;+^nHD%#md6eS&Dhi?uFWq$giah8IX(wqr4uEb~Nr#iTXC0+8fn%NJ@S-js?0pAjxk%kI+S*Ne -D5n$DuO?JQbvkqn+%n9J--np}`aeGh5{s$6nF6;3nGQNl)^-go#+REB|seeixMF5gW!IrC4;?Jd+{rC -Rrc%I8rVHg%}r=j&*o0`SIlu_J3}%k2VMQjv?EK_>V{%)EAtFxFQE8c`)IXUvv@8T7FiD4dA8z{Zn?4 -oL?TJH+(KkTwMR5n8nCOMIkjuX`?R23SEGykk7+MKyVTrE?vUzET)GX&w`y+n8%sBd{af+VFF>VXm~s{#wC|6#Yz}pii^&Mog+Z7 -S>#w%V8YBH{#qeKqPVGRJ)_@#QrCDU}uD{BmdC6)k^{;$=hlNt*Zlq^qBqU|t$TX5%de{@nKtgP^>Bf -N$SQ8-73`V2X#(fa;Q$i#(zqRG_DTB(@fcz2fx)?Mov~|;P|BRViR-Wrv4Z{<~onpA)HXwYYReE8J^+ -coh?L?d=diK(j2*SQCI*rrL>Y^eF8>?&i_OTeQ>T`_M3~0geyF~-Q)j>x{I$8}@5SJUoYT{{xHA=c`c -`B8*#8(OYT5qP-cSPWyqP8d?+MqpIyn#2W0s6URS;r%3wPQ=ku(W}pVMicbv&ZRy^YFD~l(qurl-V&f -?6n1m70K{K&oPUxYXn5#j-Ia`ey-OBmM-zc!>h@kl2ZlA7wL9K-xl@E*cg{s%Z*+kmVhcZ4kL-eXZ&Q -|fFgZMZ6rP5r$H{MhGvS)i)cLbtm4^PJe+R}yqzasA84pUF6U$l?c~Ycm8Xho8sPvc8c{vm$WzI`hHw -F;q}tlNm_{;fNt)4VO*xI_q)C=V`wH4lIV~g2^?u&+7EDGTxU!p~5P^2?X4S#p|2N*Jsw@=Xi-roQR~eqWFNe4vw<=NX{=#{NlDvs4~G4o-Pxe=Q4+f3ura%VmmLLde7p;B -a~~vrzb<&?-j%zpmo;sT36`ifc_h2Ep5e7?Ln-9{L=9xAW!g`acWex9;t#D5za(72Klv{B-(R9AJL=i7&knkF9E5!o!H%E`c?2-_7x1qGFer7 -j&=VhK&FoY3xxYn;59}ik)~y}wrJv^ZJUI$lc9;dhM?V7fJ5ewy{)nf8N7Q6TdPI7JbauRkWrr|q{*7 --e-H|5piTRMn{Sy3WoH&Ym(vKE8bo7M9=uu$`=10>R^m#y({7c9d9$q;p{tC$k1@TC&j -6hnzEw~9b{Al&C~OBr@mCNtIepm|=}m9aMds-InOT+KWv);ulW&zc{g&AJUaQ-lP2(g+|3U3(e%nq_b!{h$;i>42K=c(jm@HVzC^|m7a2Z(Ir%%!q3pW@|WmEc|kigRz$ODTDvmjV-R#x!M63283?ua-*iYeKRMwNddIQQ{0 -AjPmw~SyeLApiIs#?9CkeK-?s1w|OCnx1dglK3@wf05sHui^=M!EB?Azokw0_HyG~fJmj%dMTHY63~r_VmUXL=qqKQBFIX>jh%zrer_3U8|@!oC9bJ*%UxC -?9P!jAPpil#jnaZ*+$+$D~JBm;nUgFHOmdBA#Cf2g08BtjjGLCbGRTK>SLLX`f`pV?f2NxwCD4wQ{t= -RSV*nB&$y|*!1&LqUk_Dp+`w6bGMZ8<_HfcZC`*tAiVQ9r(S832s1e7Gsq>D|y8khSZ1$j=`lC0EK)~Ki#E*9`(VeH>fi`VaTc4F$=LxY@t+kokv= -`)3+4;;jPliB*u#pUCf@U#z+6+k7=*=%J@Q`9-3IfWq6l9-dV?TNmZoO50!Mov1fZr@B4S}|g=2WctAuYwVYJ)RrK{%ivwdE)OU89K{h -Yp@ip;DtmY&Hjf7z?7E~g0wIN4=2nR(flhdi588&jt%KTIkV;QL1^l}cH{t{&kg!$apa!r__*gX?kWZ5zc72c7 -r?V~OLkzVx9Gh1(Buo4jB9mHV=di@Q#Jz;#wchxr9Ss( -)%)63;@n&NDs;9hou@ziq>={bqbQV -FSrvl~nT)kT?#=CEFvo_!YL2+oxZ*)O!&n&UokHk}>g#2&7(%(4w*I)_x+h -A!&9f$t>M^ftG{{A4PoIG+4#-?wf`DO$nL8PhjcGw*S|`lKy`QmeeR_dq4C|Gay?$%bMM*?w$$hFz`gP@fgVP<~q` -#kQd;ptugg}1$kE6m)l%x6pC6|Qa;UFsu?57@6J>#@Ig8ho4)&v4*}F7lZlx1F;gkR0|t^lJg0WB*E# -Ut(4s~32_qA}o~&7=-(c3)RgGrB&^)}emY$R?H|5EEcro?jYV(RH?%BH%B& -8j^yE%te7&RR4fI~2<_44v{0UbyVNx}(V^kO_nAuchtbadA_$uo4jSp%61=1sM9q&JenZ_^pJtzo -0JYjZNd5J|&(Q0+;&HdaY*Ko@Uy7dQ!QxpWNaRGZQha?8#I0Q3IrUKU;2anC+Vw8LCeL7E%8f?dT(K6 -h;3~XXOu$5Y9c{VPQd7aflDNctO_Y_6@j}zX>_b{AEeVac3z(2^JF_2LVdW%>=G|#Xg=_6KdXdJZdvp -ZKJz%QUnD&8$b!4-Qf5~u5XKu`h6uQz4wePuX^jTf-sbAL+bi^Ds_Gmrt -9h}(%mY;sdvKC0#u4y;A-2~$wqZUWn2xWxr|WBLG`o2MUshw`(q%J?4|NoP0-Ciqjl{yH~hd3T8#X2u -*B!+R-D`9M4-bozX7i#FePD4OMG+x6fDs!-2k@d^EX|gFL&;ZHh~UprvYtTds2mW_I`xI(~*sJ>uIy=3$t-{NYx?*!nR^nHRky2i))`xy&*<~bK2!GNQyRN_60%I8i1Y^+#mBK1{$%mZm8X-vCnbo~@VrgwTfi2j|K0&oK#DIyph!nEjc-=ZRY@@KBy!@um;%r5ip` -!cei@chS3Sojr$7NZIcp8E34z5_nFqby~B1r5C=hvvPq!!;&7N1inRvxlU^U!-;n)O7u4R5%QONyUlS -alN!9vhzQf@(wX3CQk-n%|iAh8C#wVD)MWMd(4AXF(q>W*J_bXKmdKV)NQE5ML1axZUZn=3G_YaQ(&u -w?uXfhCksW!-)>b-7s1|Lp&9n9VVG1?V%B`HMEQ*-EJo?e#Xkak_2#+^0qOSCGmf?fm4;}by7B{5Np0m0ttC&c~v9An&*Cg!zl@5QLu{wz(`^dIyX{~s@Jb2 -m@_CAN>?G*8zNJnM(A4h#hs+X4HptGC$~%i2SG_-)~HOXoU| -V{Ol-Ihj)DUmspIOKlB~be`!+wDpL9r=y7;|0o0A|zo8zvwZ}g-a|uc3v}wnzab&cz@Tn&5FL1B}oou -}9#!%Ym>?`xopbI~q{GA^DNYGs)`A>aWx-JR!7>L1e4UG1v9Fh`|sxRU44a|LmQGcTFII3po)%1M$OH -;G{l^^Ly6@I#!fBk%a=kb95_I!Wm@qqvKeE;q7zI8zZf7J#}+boq`t@%RF-q@&?d&zv)te -O4E@@UVP*&gk5~2=WKUh^0H!xW5ireI^MJHw)#}W3A~E})iZ+Yb->`Kz6C~yr_~FQD?hCj;Z?v%JHt< -UV7(1NuR?8s*8&M8X*n(8+;567VZb$~hd{4N5WYm#Nzwz(*lxCr_Z>xK&Apbe7&cWLS``D7t~fTDLD{ -)f2Lvg=)NK75F&FiwVAbLAj61@`9q^j59<o3 -3r_$S@MEHz{6KPv{@=7R4mT!f&=_I3HwX10A^}D>~VuQuQB8DAT=7vs!-|88ssMkd+f5zSvoZRqn@tbW``sYp@Fz|5VX?x{ -Pb)L_smZ~Q5J-+5l5A9doRS}uAV))1{0V9tbX%Va;X}X$`gi&_ifIp%xO_K>9DA|0U*)HD9{j1O)DZy -P@n?Si#-F$F+E*68Z)V|-X5oFMzwIl%paeejhgK$#eBv4O5fEUG%*i1rYI6bsbNR})%2(mEp{BqH$Mc|Z3lt8Pi!$<27#LkijkcC%1ZrRU)@G@v-e!oa@$f>|G -F_>0M49!NUJy;UdcA#)>LaH;JE%v*LtK+9DEBGrC2mg(!{rVrPVcvbdEAXae^cx=vCsnYz!;e -&ljlkgio*aby&nf2U_77v_@~=-_p5v$GaYTim7si|OAY_f2@*dR6~RIsp6gv4i!*o{g0y%LqBoyTGI!@~{%f9XkENG#}Xp&MxRb}-f~*4J -e<6x0&=-!K}o4EUwcqhMr7(`8B4Ws!bJcv;9-JQ1BLEe&u_uS -n)Lpk<$1vO&K&6!!5b$dxSJNPfR_?y3XIa%j2m2dn|Wzkuk)wG*Ofag;fAgSvz~V~5U0hK8bc{u5}Pa -7(~B0MO2hyIVg9Vmf}YZ1N`Bsg|m#a@4~*x)ZMwm|=Li>)^FD?>Sp8Nys_Y9lFZ&K?n^K`F#%x_>yI*$0;vyYW%-3{Pk)|){H#bu+RTxgx6;u3aB=zM6K -gyGulop%mAb@xlbQz^;bGn|WD$5h<39X2b6NVrhOMKGp%atJ-olv1V%1ll>Ut4kTT9|YnXZ#90ZBG~S -rHr{`WTgqAl9NY-m!(8EG4))@tBU6fot(y5LOVul140q9Lav|-8XDX>Ku=)z{_()o7b1x-sS+&qWL7Y -?LDLeyad7Z2<>Ni%Cc?dMSVc9G8InWvt|E3+-Gl_B(mqKlcj3sP-mgr&X% -kO=wokQJ9t3eYHYXuohkt`Qu-(e}X?6L8r5-%Fs -%WAl#LAU_#7?z&a46Vr-!A+|??P_*|-KNNq5D$Nx!%<6_f>cXelmJc8Xbb~rJ5?_&R|9Vj*>9yf|csQ -*f-?5Awo_a!94;Zl$u=e%a^^GB-{!n9H^iqi|4FO=?Nz9_Hh~PG&jd6n2>nh(ydw0h#!FWPMi{fmEo$ -{MQkW%YFpicFa$$)20@rW)4mOd9jS>rHX8P6}SzVfK4Oc`ykF~rJU#EM2^vKb^b)-!oFS%55rF!@nGV25#}5|ymvJIs1IeI^gj6Mn8i -NUANr7Nf`_?3D8i_Nt}`nRz7eSSc-J2#R2(@%-aGmr<0HC#Xr_`!#}4?HGMD+xzRvR9dG`yLG?K!u*XOnc-}g`F6mUh^ioer -48fv#VK9PgFejjw=cTh_U?oHxN-J>3KaX`@S}G5O<9k{D&5zZ?9MO1A3GoW&SOX0?d$H8uIM6qbo7lK -gg=Zl|8@UYDonqT53?Zuj_#8E66ckVIPamBQa?zWX0up`Txb-mgq;yH2aHr%f(U0$_$c}&#}s^vV$Tr -^xh*~;bJ|gLM0e#W26-O$Me1GZ!@fwquZH`IVnYI~&`t2Lj+bFhEaG_@9s@|%_$6>UvJp?ui0bw226A -$2UBJfmfS(qL_KVZF36c*D-yGLQ?uYEFzXdACv!3`i7x&8Bi-5-aRD@6wJ-Rbjk<@wTj!QassJ3#s^Ol*ns -pYMe8}q?;z=I>OhDiWR^vF8uBB=+zK15y+-CvCU>qtxK16A-m4^YdOAno*24&^}5H`8~eZ(X)J -x81M2g&3-g9yDv?6c6HVW!)|RT&fjIeox)f#fzBy`@RM%IHw69<}-*88~Y8a>Zh3O1Hr|G8UgQCOu&2mV$hv@uy81iYRB8z3{xUlt-7Y_7X3SoaGu>|ZG?9 -H0jHZv-FXwL@P7>r=U2LgjPZZdlmw&b&Q=|ABPB3eN5;5_{QQNv^wkmR#P6YsaLxi1hcNl;E5j`=~xY -&me)Rx_MFWf)0$V?baPM?n@ogX_1P()?7g`T}Wro!mMOQ(w7WbDKz#I -GKh^~71;OA*!qYa7W-hE!^g8MYhN={|K0Ssjv7LcrM6;XZ%uy -hrlL|4{^Gd`4-r?4tWf-lT*k-si1Z?vlih2 -x$r#-Nrj=0Xp|RGR0MN@NJwe&NolmK=jw-#u%p5UT~b?-tB7&+!+6;}y6}`d_!C5OFF?dfE8RV@;qlUE*}ves-5kz -Y{IK)$(^p**rt9`(`}_OE>k_)@5UOV*$vGis2{8v?)6EtSNww+6c5Yc=jLp(tG(EUv6^V)y&tI#zZ&# -BpQ<+Yk6fVLgIyLVbSg#Yg02;au{0n*8Y(uJHUJR9CU2Bi`m#&xUTR@zy;~4`Pqw^^s<`RQY)MbBFMMJ@R`8@VBFW2v?9WiGe#VLJ5?_DVzjZm>{&nmEIZh?wqkIy=KCzJEsH5E9!o?A(pr9k7fPF+154zR#kQKtw -9f|$EbL8L)0gn!o{KHqCeIQPfAJ___j;hEVYVEiuBR(?1pL$LhK5*U+fS}K?;V-%%pZ?$sI=YsRa>{) -ue+iEyaAR2}`5wEFqrpV_n{n<<`j=9@cJl|_HbBp_a`0LOt-`p$WBG}0+jha0u|Xr$ZE$A4M-rT`+lC -qVQ+cJ}f71^7kfi#v>FJ2RWnWmyzGw%1-=_2O!Z)-He2a{*2dx=&b#1?mcPwLnU9ov~o+Y0jzl^fsjj -wzNNBJgyYy*Oy6Ys&1+Wy;!Cjp-EbiVk{=(V1rYu|$r#a-JsV(q^Eomj}i*(}ykt>QkS#Ta;*5G}po2 -=9q3_2&M#0Mb}nuoII!U&4{aGy}%O5o;q5ZiVaIE>poX>BF6iY&1$8Awl@8oQx;TJv7(3gbzT3>xY#$ -pd+r-Bh@sTz;&zA>B^u~SLYhJd_8b4??irGSQ~7Dj^w@U7FA5$u0~G-tz^Bn5{oR_WXv8^A3?^&@e(D -`-OkPM&>p|M`PEQWv3uY-PT$ZLbe|Iuqn!MzUVu!KvnsejapI<}?C)JB&{~MrFAR)l+rNVMGfnnqG$( -Y{evkIk0ms`+Hcv8PI7~YOpehGcpew1fogK&IvHF^yOjefY7b(2rM>@wSDVjX}`1IR77euhnLN-;w?LuPQfBO4A`x(VEo(809c)vERc7LgHF9XXW=e1g=6 -i`{snXs}Tp?FWd}b-_xC_2le9lun~Rs%{?xY1H51aW~SUZtM%1LS4Y(Cf`=!Tx~YdxM6RKmn^9=`}NG -jD_rx`g3opfm3^G|Rtrr25ZUx;8DAZQ+|DVgnS;6P-iPd{HjH0oo$gcnMPI)mo_#v6N9b}$=fb|ofI4 -3e3Jz)it@EkJymkIhjAI-9i-3pFT#(B_H2A*W+X1+S!Yv8gNdph6nySz4)TaG8DH1yGbfwly*y5MaXt -IW%E{Fo^4Eebc@bykiRTUWoi8>hh(r@f+`|J21P7W{o8X(k6=>(EXe^~oM?i14#fj?2S -vBwU9!CBg&Y1?KXTC(Y6W>#9f(bxScY0;)-nz_-UfBfZ+zd%|t;OBsn>1k1?FZPZ!_xI$?Of*Z=ez~7 -$f^=Te<#BcVACMYU1*)A7n -?FWNHh-5R7ppO!z(Azpt<7{R( -9|sVf$=KiA_-$A)8hs?Z0dPAzqfm&l1NF02bC1X=okva#T_&3FdV&sG&{Z&1$uWp#-y0#Z;v(@5tCLt_p~VO&}BBQETV#_c2#ukeE`M|A3MmN -<ytp&_ct*8dy+N8flJJ8V*J&gqO3h5|82@E$}p6B2gL7_xbwjrBac)^?6jdCf -jKdfDAcZ6zs7^?yIRxLb!{UcU#l@uc+Y^DxXgUaV=8B?od(_gv#mGlQwVVh)lHwJzxpwtsu0Q_^Mg%E -qK}BB=X3bDwmR($`+T%@PhPwkvJSU1_pn5*64-!XG%t23UdF{QT2DVi~jD3Kd2S`c+#JJ5d_A6*@;zr -c>aj|5WLF|IlZIjn?SxcKT#hI^+V3DIO=Ap-y}}cBP@!Nhf8tr5uqQwQRMJ8_SZRiG(qjJ4+T^3&_XS -+Pd|C_Zyfs_(-3vAI)Ax)@zLEoB -I=-}vV&F#k7{{AFzR(_yrJ=M7{z?LSo9KMX_uPrQMFkS+lKQTO~B*bJQA0m&GzhB*7r@PE;zKiZl2RA -(OFDDievFJwnN_G^Xf{HMOBuZ~DV!+Mj>MkAy8X8hR^Sq#s|fDb>i!2hHx=g?BPD*;~fZjZYqria;@=lXz8v -l$i)&wo?iLfWXCc{7$oZ72+Fb5K{&0IiaX*H6o5uwAOMvc{N9(!r=8C#BbHS4&J2BymTAg4FGAa@U3g -`f-mNJVx$X8zVzk>`OV`|o-0BaE|*EvLT3$~?M+|#8$4dlk!K-6p%!cf=*;|lDD_=Pkm>B)VA50_8$I -Lec(E0*)d>n=$V)Ka$=CBK^xRp5#RRc>0}T6p-Ist(t{~|(4$S+M#2XqBqWDasO_X8{ar0X+dRzDiC5 -SIlAz2WLPl$bf6s(%;%YL1t0E(-RTlgsEUJzBOv6zA|k`Yz(&*6XTk=aq63J>28gl&066SiYC9y`&naeLNY6_ZaR -_g^+|>#V>h5MrLOJbqM>++^|HylXF -(q2JAitEQ+Qg+ePw5Utokf_Uw$nAAuad?kb7SWn*Dv!^9*p_e&1;oZ7!2dr%=kGcFb<<1+~LD#>-R?I -|^JRBP}%mT1%>qr0cUW7`(ERgx#^1xUgb`7jZC@_IRqn@x>QPrZoxo*ys7whd2IiKi&R0bbwa%Mwy&= -NTTzXU!2bVGt*DpI;D=lvb+l4+df5PSU0M-p~frviYz -YP)ygqp^UT+?=U#%_bu}p{#ip5cS~v -8DTp6U*N;D|k&Nj&mBThh9w>d=$&V@PWa5=476e2cQd)WDkEe|Ivg|=+11-;88d4r_UR%i)^)ic&yZfKC>%Yxf -k78Dj1R4U06TOMveEK0Uh$GsdVy_OHtavG8CdBI0p-#jF7Flh1V0MT;GQ#kEx@eef8T;tK2`Rn|=ue& -3j*o+STgHEfwtz-Am<*)cVlzAVa)IaU`8U6gdQ@-P#UmpHLnwp|O6rymPKp~IIJhXs6@k{6v-Nf)CZ4KjJ5ljjnUEp7vr?7vczwT2!N07K6k6LhoIIajIN6a|>2wEL);X^@VM^NwwejSQe`GNOh;&_Tf -J{kE`sl!Je{SatI{!RY1ScZ9o6jt^dI&x?wJPA(@(Qe6-Z+A9*Keg@pOQF>nFgD)T8TnhVQ#)FE;!yA -sc=uE9{Ga-RbX{njHWAy(hpFk{c|YI=@D*>AS@TVeI9+!1gMPS;Ie-4r$|V1|t)Y=`3huyH33vY*F8w -7i-pQe3;qk@S_|3tH82&V>KOmUPz<~an{_|h9pX=%gUyE6etu1!1LD3@u5IC_DS;$*XD6f}_3q5njg;a9Q^!j>H! -j<3=alSmyBZ0jnm^(rEewkAQTnS8T9?*?}QZxu}pwWPyYf=_E8h7dGS>h|pjmGjvI;KQgqB7L6X+DA) -0eQ&8astjxR1pC~JU!MBGhJ!!RTm{B*)Ekgt!=%eeVz`I)Q(=F#VjbnH;yo0wQupdWw8T5Li$KD8$^U -NW=1A043)e4rv}OqDdH{CLmQxaQZKPQov?&jiBZG*9CV3dy@=}V4rJr}a2L9i4C5?x=}3epngZ{{{%s -Rc*hr9GK|*sL>oVtxCDS&z}1lCguw#haq*)#xD(bGdR~QOn9zoRLhoi2?%+c -Tk`&Goth_Fe4{f?nP4T&cvYVk&y?RL^x@fpJTjY+8lY=1$Np-_JNoPtKFdqQ;A{#hL(3*NbkeZoB4`M -y;&vrUVdLj`yBfQ$z=%{N--IC*_3H{1{UhfB<6HZdwb9h -?O7D)u32?M;{knC_n;Ync(wYS|*fZpe=ymF*r*JAg{!g7-zz+hJJ0f~dPP&`08?~=4=QHPVVspEJx7q -^jE+NJdc^LQY+2~xcLH9CgfoyRd9D|q~+plOw=QArYQNi6LC`YpRUPZHfKU0N7fkf_|8${w0I^Qp^u` -)z5_XPmOvC}m6f$ooGY!O@uON!zYn_GCd+K`QxFrU4z4uKlp(!I`HdsVatg+t|bS0JweJi9N`yJp<%B -J7j1d=KB_!gTj1c*N&|x1KALo0jM7@&AzbW=oG+TesjnPqFWbI-+lU2ckzHdI3>4w4xURB$}r`ptN(_ -=}dR~-=`|7BGS$;`Osp4q&dgz#$Z}z4SI}=5xQg@Y)NOG%~Bvh?pXwGoD)PCzcFv$4fOrFdLq$>+|VS -I8OnoiOForT+8$Bz;6;*6BEwir#}bwVOzdVZK_4uwt7byJE~RELX??e8%m8s!NbNpJFnG%LU}t^d!f+ -2S%;?|>!qw^}H=xHuXXSN=n0I$2AKlea#%kd7pe-+Zu%dw^@b -=zA>ZAQxCPZyr@N{naKIo_sJ(~p@8PKYd=19=VJl>UZFxw5DrP3O=AVr>5b^|7g((Cu@DynT@r($+$S -w1O6T+Glj?MTbjE#>-b!5$k;+uOk+%c`&Wt9o7f+0>E_kS-_QYYZYle3M${tMK-QqA7GycWN#mn$CM! -s1(%h9;vDCcR1lI48LL%$?jpfcne^w2ue&vSn9U>YB!$bM6clIx-+}dpV{EP -WtpVP9BF6b{8vcFuYj>dJrkd_T~ww2#%r2W5TQ(qO&{&+*bMt9_a>o5|52ogdO97A#Zdq^(+$XFb$e( -2F)AEyUGB0uxtRCMT0>=+G=K5}C84*0%5(gz=f^+UnpqgJ-VCn7r%P4uTvA5T8~i0Mc94E+q|<;MU#z -9YFG(K8-9$qz_~eC7nxPsifEw|&L^IG!Fw_T)2V7<~X-0(}M?u#Z664ieErts{#*gNgKq4jezmANDiz -gS_$2kep~AMRxArjM`Cq2RlKGSNL~n`%k{>9{;Wf(Xus@I!^xdAaYE|#_d!bNN#ru;4fq1I^<5CTPu48q8)%OA>GF|yMwXm6(h?#YMXI~dc7=#jm#H)*1}CHE;|UT@1{)(U5PD9#neCVVALe{SlR -17DD7)0W8VS#;jY&A#fH%Df32U!aV#xdJPQWG&vt$@9Q9En{f$z`moCUnkNe{2|1e`dZ+yG#)>nnfK6iwS|M0l0Cw -YYuCxuvxgBQ#&0%-UC{mTc&q7G{bR)Oxz$p0-IyXT*yHaCk9;@+wH3eXUz4Hgz%N;t7t&vXAhADLC=H -*2ZNw;}EgK-)I(N*u>Sd+Q)Tg3xG*qnc*qQH-gxRhP()Uk6Kz;(2e!jCcd?bPq}1-PJRgRv|P`R4>ZFp?LsPxE5t$t$6o3@5ZLo!*?P9`5D_|6(%w0iBq)Osi;$YMC -*ix2Z#rk5#&zg%>q5LmcdtqJhX?WG*ArMn`qp|*94?|k`tkbqU)WPpPb9VXqmaEXDr{ucT~39%OPe^+ -=dCG+>E^N=*;GrdG$Tf?Fvl;rjlqJqs9|1d^h9c#qpN6Bm?1_YK78aT?x;PF`xZp_L6Wqy=#|wR!>2^ -R$_o#5(R9RN%3|_{Yu%QZRsYy#@xE$u$>b|530&?%l*y`9H$bH>uPUZAvDEvI*|+Nf|soW2BA-;-6#8 -kfAwOsOuQ*RpEv_m*&@6?dlN12fPpT^$B(4+l{!^wI{DGTpw_$7aHF2)-ftPbypK#lzD;NACr -Qg$qFGA1yUAw$Ls{4tOL05q)qU+`&UW9FE1k=>(1_g)a|DzneAUZ&Xu@J%?p#wxm#c9`Y-r)_j4HE)g(z2dd)P0wjk?U!qPuuK_&egA@313*Xbr+P2a7u -!t1b1z~?H6#X3V%jNVUnAge0wc=D=ef1dt;_TlUK2-MzxY4k24_P1#qEC(S>Oc_g(jc%5sIhN6!aK$T -WTKdGEYgKdT8Um8oB$-LpDhX^Jxdcuri)KE1Gzr#YI~zWEWu(I>G>U{S!d}*-C(smnE`s`*`k7;x0k} -804T;%rZ9|P6PLl`VRz0R5mLTD7o*rU*3XPLZ(My!2c&_Jq-BDrb!p{(MHeoIZz}Ls+-SD%xWm#M)Js -s(wCc-?DTB0Aq&p{R^VCe3dsP*?I_c?T=ehX21-7T9MpLnj5F4jF!skRDPpUNu&7_}#C$=Bq0A0Wtvq<0dpK{9spo(d -Ga;(1c%nri^>tz+G>$-&APZ-+T}sj4om5zzq?5pkGd)j3+2mb%bH=A6e3 -guf%nT;W?eU-3VebM4DluFn@zm;t!~fkpE-UP5%Q|`U})e$e&U-9VOZLsM%)NF~342$7~7&9YjoU^iz -@?*pVbZBP{t(MD%@7`;h@g(ofx#I@(4Lw(#tzo08d)N!)=fiX0O=JJd|_`kca<}a~wXHF?S?NQX -f_e>X@U=K6p;$FQ-RSDgIHTp+0m?NqP(bVfaz1jXw&)@P}0s!am8@5617e&ic=iPw2UA%zz(ZVE6@du!otlOE5vuA&r|Ttb`eUQuvTWMeL#_ar1^ -HW@@;@I7_{og0(e_mkX^SwQN~h&yo`+SZiJPx}F!&yIm!QL*o#bWth6>`kE;C`&2xyh)2Q8pu -BZy1#NyugH`7v3XF9nP?6N8C=OuqC#Mcs4)ZZ?B3Qo92IWvFz24N?`mXs@&V2h>fPc`XBT%+o^vR -Ug9%bdd}!)dv;`w~a!`4tx%^RbvCuQ-X_b)AOqLxqYQ;yYIn!(L@l)>`=Zmm^1KtFNF*STf4DDw1s6x -K)j4uL6}`)6&pIm)6k&N^SAzBgR(9AGF|ZMQRbuYmO^g^Wd3m^n4hQR#^CYbXHyZU{w!o=Bjxq^p;5GGL*4VDkvCKPJ+G&ZeWjZIjv%&vJ*#a2x9bk#9DT4F17Pj!$` -itC{yX9u%=Gx#XJzTfC;hB~dK~|DLgJ54{W>D?z0-a(EmqLEX -SBM_f!8rTW(y-(8(Pv~dMvuMW=;7k%&#VMR{H(mTyF2PbRe^rmn2s{uhokWD)zrbKm}7?|9%#4=jKJKnB*(BlHdwZjB0o93#UvI{@hsfMcMP4@rYxm-)f`n&h4xF_zT{{E1Z`fuM -hH4y^a2@^?<&AIYo5_pHqi95d(^KhQE~|r}kjXsPjkG$7e;xU|OxUlYF7$L|B6|qlxxC;Mkx69!Hq21 -~RbXlf>nAhFM3LcB`#;c|3X?GKy?{^ZS0AuV_3Y;9BADRJuH$74u9G6$I>1D0b%va(C@XBab`E$R6im -Ui99o`zXRo2-oM^THV6Cq)CwxXrTxsU7Aw81&?*ei~4k{8|E6 -m{If7+p-enr^Q3p#CQ=eNK^GwDk=?upQsYn$?u`nmOFM99N7LDSRd?0e&{${}+)I@OlVfSV&-o4Q3EBol2!vY^DxY$c-vyx`H@WMw=MB%*02LV_V?yaPNGlv=hvGX!& -n~+jlF*%XObDy+Wpq?xxaiy2N-d_m>R!-_P^t|#NWizz&Er8ZMr#e!<(|L%x -5I8-4OTcgR`8V!sS0?9`4++3n|#AeKY>L}@M`hg-m=c(Oblc6(gn(n+xA_xui_TXYn~uHWo&x@d%|l2 -;Cf+5t+TBs=><- -+(RpxPk~FQ;jCoV;!w4181pMqMAt;~D(s)|nJuisZjR*%cZ9yb~s9@&1APPQ?m`aO6a_nj`vpBiUUaE -BNc$xsMsMjy?lAt2mvZq(B8d;-cf -kJ=5Axiv$1l6%-kr)fZs~8l>=zgH-Ix4!qK|~IqkDuv2!fyy93s&}(i1{S0wQo6BM=NCDH4GobT<{>t -wcm0=}tWU3C)iN4)jBXkbjZNgg%i|bi_J`$mj0e;_v#eJtEp&M;0A?2Q+bv*&XrTrwFhgjH#pLm4c6h -1fNk7AeByms)?g1eFMHLkJknrM1Tgras?mn|mV0X|ZAjh9Qay*2);iG| -N_k9OX5q6X?_B|a=`A_|q5F9-dQ2C4haxnGy) -HY7X&zl!y-I{G5MvBZw(aQ%#R!TWm?Y>ykDL4@7~tCX0wvEeeJ$IbhMW}WI=V#I{X_1e0xyi@88fCDf -+J{7gT;>t@K9Uf}3@yZfZbugZsnnY8JMe&|i2NykDR6Rh2>J_`9`ff2-s6{%#nvdUb2epCMLRg_k3#= -ozi~sOAlJ@_;!@cM}WMlV-e&l+Z3$i8WI2jMv~~Vd+Q;lQO%5_rgwNK`f_x{}f3M;#yB;q3V_agFehI -)wG6gkIY?)_B$q@j3N$%nP8`4yGapB-wBh8{duD{0!%^;Pp-T9ed@ygbpZ&<&tEf<%rYWj*c~fwIbn? -1fU(zvwaQ?_4R{Py=yW!mjrMs3>h4{&#%Famf%c;SFk{A_jS=Pk?#u6u^A;e1)xg4jfS2?k>yNy$m&H -PFID@d57#sJPa2vc@qJTL){T^_O$(}+PPwtu$49M;~!dE{*&3xBeG}m~@Srdymf<`+@~MQ?vq=DS^zr(6sf2666Ajyo>Ph5Qx`#HK^Mie9B!gtr2fZnd4aJt63^15l~;TPlwO##$s)Tl^>A=1(t8Y(0k;mZ@ix((!O|6FWa%BjEuX7FaLN0w@&c4U(0XG? -;0!`^B-jPu8v66D*cb9}vuYglSH3*Y6d%;(c2)c{gM6EygK2zT(6m(ziY2mCTD|tEQhmQIK5V(3)!(Z=i_F_nhR*dmna}GP(40u#vW{FB`)11{yI>Hz!Q;mE`+M4%sRN?yG -_(+Rle7RO{Y#f=O))=Zq!MSz6UoYPA%`cg+l;}KQYk`9y3Fiwsl(A%((8^fNl$tvkS9JRPQk)tsg -YIC8HbLr~9(;v^0+L>3Fy38_97&oVQ6UpQZu)gT`ektVu(r#mNSI-9VARc?v+iX&L77Z@7Y#a#A_vwa -Icj4Kz_fog$Y;q7zj5DxBJNG@5Y;1rYgq3wYS0K6&O9!RPV-b0{^ThcL#E6e08#>C_lF^2JSzEU8bYT -e%2k)O(R@;It$+hFRarX5cdGfof={E3r(J56pj>glgYc4P1%qg23>%!Lfb_HlEZz#Rr(Ib|b3cMPfJ=nYPzThRkg7$Zn&*&~dE -ELGch!HnFKGavKN}&=r)ZR_`qX_o>g=-bQ~=rPy8DH9keH@N`!19nj -V0J;Vrs`+F?QfGnA-30Z=)(pNFYUcv1K^I)JS0JHpTrKU?e*#sNzeiP9&c(G&`7NsY<=}rARmp!F -RTV>dTN$fLJnVk5UT=H=FN2IqWjhH)SPD7td{Uj8c`tE^-HQ*KqoAX2|4sx~rQX9ss_5T0@j*`C|Zv#%&%u1XluMR_F95h)W&)J$$|kKhG=f%M -t}2`-vJ6mY_sTX8I_N)?$N@^7C)_1(CGYUvT&wGeE3kZt{DfeV8;aS{2m)8~iNP4df`mWZNJ -H>j=BY*Jw+`O#*B*Rm<-EU(bqe9c)sGjgy^@0179=TLTf#D7;6b1CyRy4ZV@zm6JlR7L;3W_#|^qj4&X+idBK^Z2*; --=4jtuaHx_z#cLSXMbmD@r)b=RXt}sz8jNpJo|VGu#mRDRL2GS!>W+R449yDQt-F?p?s#&p?xy+Xh-J -T9)eMnH9R^VD+$I>9$72-E4*rJZ^Lvfu<#D>lRYAKe+5lu&Zq03nu%{ZPbx>Yz3|x;a6TDKwioJql5J8j{+kpmhd@M_HM0f#*+B?LAF@I`I6qnJ|c~@oFrb_L5lZbizo3x8zE -_b=n2FA?+<&8O?;m2)LcXPzAu07@YE`v;7-6tbugBe$Naj7CwH?a -`9MuOOzhPdg4oE0zTjn^-+$1(4T1XAn*KiuYQ02i8@f%m!{SoUPaWWcJpbU& -B&in=%a%1Nn>T7+3_U*j4fsRm4Ae)s6zniP>;$EhR*%e{ptrG!jGT#&E(XPO(T(`C-+E_<;UgW{6nby -q4PYrvd|AtCw-KCQtHT=5%e(vg%N)nRbAe2t~+?Z2_mHIrYhNBnKVo{Gl(G*AQ(|4BjWlQBOi|^|& -GT+KJe5CB?5uAg^c0$=2zm4XXYEgoj4z?mGazaD(beIN2~MsaZ3|t%O2F5(c -T(+wOLNwd<$^N>q3q6;Couil3GZ?-x;uoyd-Z;4yo$V)7mB- -SNFL>*-A#KSOMJaV9xR=gQ!#A)6cgc|)TocMdj;T^X!wZ&36~x`sM4S`k -JBidky|jP|qCQoLo2oJp_6f*!n!$$C=?^-_eMFFvOsH7DM%_=h1)#RRHG2%Q>|TeLuCd%)Z78RNZlFR -LV!;-TJSP&s&6SWKwSkr3)ldAvx8*H6_h^m$%H{WXYWNKp-=P2~;mnmPmBW3Xi -sEV@+#EW45k$O&wRJtRGFT#|PVabEr<$!YAf^tJkP>CbVAwRcws}6zp0bymvJ;6B<6 -f2UDOh+7iw)!yOWNw4J2hpR>s4i7c_S`_#ajzp<~elL5hHi?zGl5_Pku6O-U_&{G=ujzq(p?6WG|#3+ -A6!K8KP^!?Ue6?5BEy;wTa!Ef(3@L2pObHbbwacYQ?Y(jQOJLOHsZ(4#FXj+CAsbkzB-Li1ecZ=c`?@ -J!me!7T(a0gx|HrTCXaz15-+_>G$k8JF`LM}Da7SX#4&Aqs!Z{Lb#^iOm;UGZuVl2d5=#`uT~0Ai}sO -A6e0A{zx>2Zz{rGf+E^ -zX%d6trm>;XpdF(UVGbhlPCw?k$1dd_+`*DjBjO-TCt%$_uD2T(+{ -Bw#xsFAnG^p&5V|Z{d3$2LJFN>$tynTWLFsz`zE>BY4%VQMiU(9}N$kKnw+!xp*e&H?u`L}YH96guwJ -pZqBKbGvr{#Wv7zZEO_PZ#?tUGn3Fe$%;$qZE!}6ih%A2JMiGMkxYAArvK$9eiOlgkv!MJ@j<|Ch9<6 -2cAKXR1k$6MYv-Gh&<%Pvd;+k4uq)uCp!Hu`r5%7_TlE)fzOVN4vNv}$S7gZL9c`52PDg&5AK2vl295 -wn9cF@Cp7;7`q}~E4xf(174ex;M-L_*DmmJ2_E#PkppU`!{e*pQd301A@y}E`jD6(Nk)t$-(Vsu~F~} -5sgw+p~(fvm7KkamB4x+n`_yv8LXIx9JQ-Fuy9%7IuZomh~{vPE9$2Pz>(&?VN@t($NUwTUlO|!(Ni` -=92(Y)I?y!sUmy6iXz1wM*M$4R%(Nv{B*C(S-+xPHMw6Cd5u-aJNa&McdtI-Im#E%Ockb$s30es1M-w -E6mJ$92 -Is$gh*ppB^dcZ2kT;f{YP@gU%k5-JKlJE2IR$TwQT~DG5vuw{WZ*$Rk1CypKNr1RiJneS#->K$91zuA -0`xy&o&A?2p89{WNjr-ang}~2onW7VOVeMQ6t@y%YJT3JAf3Fzk!X)Y*HK!! -)~7CMnX!=`#_$fS|hWHdR3_Vd(DWgX$skmBsfHds&i)oEIWNTh)k;7h}LqEjnMjb@xM7*Er&5Ive;ib -@1czH0s;#m|HQ*#CqYKgo}d>B%yQVcsF -RH0Ty4&*Hp7fvu#cyrQE?VWW88CuwCd4@?QNS4?)(O>I{kjDS5UQ??u -j}lepN8EPi@a4xXCl`3`o3Yp1z?~uFWX;WX~B1p&1rTqn|7D1CR@Si#4jHgGZ15Epg2sx*zm^(kcGM# -s1tW{#J<^$MA!doTgw1qHr7~QJ6+3l)`9y$DKHa5afq#?sra+{PcV7UJ!*p6`wE3i1aA#pxI9}eRR+q -qqym3IQRSQGdX??6ht2}utSH0I_7$lkDuKSLeN2uvOBdj`6L9W!{P2u3WW}Glpi?7FBP0m(FjWpV(i@ -uLSJ4+90epe{<))bcdhYJyE!r``|3wciuka=;77$OhClNg@NtjWhtnH9(iVT_6wlV-6cgm%PLU8Iut4 -+2#ZxTxq$?^rk{qM5_xt{x-oL%O&1beRo(1?%9OB_wfd9lH9-aj_G6etBAs)L1{u76I>>BuI4pE!a57 -}Sx1im~~nPu#Z{+2>IoGK2c_>fN;<#IS_VOj;C{M`SoSfL -g(Bgx^G_gSggyKWJAvT{%59vfUg)njU7|30ZAjJ2bLh^*FEa+bzN|c>_ -crR#EE-b?>s%-YPWt(q4^($7yo3T-&xV$F7j&&iXk*gV!Ne;AdH~N-GY9i43fqn6oC)~-+%SpoN -k64mWYau!ZnT^P3<^xXdPk1r%Ih3dDA0j`)Q%au0 -yGg~PkFs(66Q2KRR8f7Ris-8WWwv3#pNaL1&ZH{Zi)3~L{@p<`w)k&F70fJswMOZ$tNOJJ^GASK#V|(%rV*5^fY -AkA<}S%Xr0WbV~i+8eEuadoU8{0x%_(~pr2_2%nxk<`=JfkA?It$bzNV`h-%kJIZt-ypRD0gobRPhTa -CNsFBw2i*B4bimD*Vd{5gtZ`!ovK)Gt}ZHKlTxBh0$}%sw4vQDc6aLE(>Mq;IQyuMs+ -H_q1EDh?W<}Lrr)R7DK9$BO@|v#NFPUF=r~SqNJrfWl1zU4?OBPd#`4&QoFhnr}xi{xVQ+1b4#Yq`wS -W+t_ypU7!B7IlBilGndA|RyGqdjq(rn{h)sd}N1RXGh&Q(-VqcsXS>vn#QZX$ijQl1xQl;-a{Yuu`$I -J1~G6#A_P~Z=Mv`BqwBbEDZk4dhkhet<1k$hVv|Ncdcg`#}-{2(rzPI^LqKJR8&>#E0-$W0eq9u -myeh)&S-47x(OcHw>fgU1+6owKQjD0tFIOuWGBiV(27#s8WBZre6gIYTlhtk7W(ZrEm!}oyT`vcSDXC -`@fK@@#BnLX&(eIJp2dcufFga0}``r_&A2flB2cF|{kZFjr*XIlDbq^FLCu>JoB! -BBSW8AU!4iRe*0JvzpsqvpA982V@f9nlW`(;gimpGkl$Kbp+;mD4}%5<45m>{xR9>ibyFyS)u1>p2&m -3Dbb1Nl2>S1rNo4D|q%qD>9e2LBesZ#9{jtgl`EE-YHj5~&zz|!}HgdR=q>W~4p -tp4Z+vx;67+|m!oen7ZmfZYJ__e1&nLr|9zwR -^GNH@b_)9stmZ#j>33%Hn^k^eH!&Q>AqdAQnj}#YB1w`)ce{D0lR+>+z!-vlKj}h!=6sSv>Ga_6&yRF -{j2%h-W9sM&u><;P+Q5Iro|dMEy**^j(3iXv3P!e026qo=8VTXlZ<_-yqI%LmYfH -yHj@TxJ#DWgbH>sE&qC2|&cG&NMhau}zP^=>LPniu^U?2Hvdd*#Em{xGa!)9)0C#?&4w1}=7r)kSN-+ -Xe9GGnMELm3i>G;!ntuQW{dND8+7N5~dng)rVZja!~XeLmlm8%oxi}ewi4rGv5g!u{I&Zcwmk=feRma -rIqE*#yahGOJW55~f&CN$TMH0XQ+&UzZzk#okM?LDNCS|QiM*;<(Q?moR*iS?jsniBd_ih{I)L*G@90 -&D%q?`7(GE&;xn+O~64v>r2j#;f5KyCkmK*B+x$hN~_6rc8a$i}nQ0iVZ=nFcF&(E-8Is8BPOoYxQRA -gvznH@^MDyr;Arf%xK=u&+(=Omf}WftAO<5JcD3S_myFlW?sDGyfq0k0A6Z{G8u0)%v?yZ;;Q=<$r|r4lMr5R(SNBO-{F|krE8ZDkMzkuHa1ixvK&Jh>k>oNJh> -!H~1@jk$k7q(G85ylY@osn{jSd}$pTb^k<4(zh-82ZN8ZXS=yN?K9doUk>=c!YIAS}j;b6}jf!2{el7 -*uVn37ub($HDGF&$=%$h5?vEk)O-jiIp;o{Seam9?oNROm -v1dLVSX7_kiF15mYoPWNESm{4`84=EEcB{5XzME-ob)pjzWmJ@l<2!7-y1cL$4y^;p`6_b!klfRYru8 -<@nRlgG7Gu8RgDjad^kQ(GJqxnsvgd2zX%oKKY5fpjR>uci2O$48LfSx@al!S`;LNkfJL`^C>QiD6?a`SBtWt&e{Tq3%65CgVnDRUNx)r -fnYaNO%iu5*;q1%nthRWC>(Y`uBfU;02hrzPtJU`v=fJ98`lQg6rwaq8 -ph@4dS4z&sew-(l410f0-vqBw;e<`9h*9iRW}XX{NO^oVEpS)4n>1W0Zl;~oZl6S -J -`(3Jc{&0o?#W#vi79=m?#)MzOzq`ZN=^EaIgW~J%+=LyK70p3tl2l*BpMcK`5A`QR7{iucLynIQ=8B& -|lx0G+?m(9DX`cO6@9!_nUBD4!%C&AdF1;HD)^;KOZvINcZ~yxsc4brFdc>&Gr&9eh%wrBnhXV(m`v& -J>2XWXhykUQKi@=}VR(Jx2MypFhD2VT_yIh5btPtswUTQrbPbNxq; -zpq4`3%sk1%ffj_a$xQcypTarQ1VRnq#L`|CxSYGc&5KjdilT=xkhSz2!_G~PT9b|#T6+} -+O-OYx$ -BPL$7CZGZOm!eACM9Le9X`I6*HJ?e)`(cp2v9`tBYkBxhw>^6O$ONc=9!+Zn6Q#cg2Cv}1-Y$=(JxLG -&|>3c$YXrjP((&Q`RU61yIH#Zjj56DQPoRBg**n8Fh- -XCjG55`6y10O(QPNoSBx$ -1{4+~w{alVNS!tzxwgH8X*zyOgS+@Vtx;b-fn->Gdr~f4JesEqtC^WUNe-N;3X*IWaC6gVXMs2Vn_>8 -`P!Bk;-ix3?rb3DS%~OR;Ok`CCq+YMu^dkn@f0u)S-_(P@0}Ma7kQo-(jrfVctrxPcj?24@qHCS@Zh% ->EjK}$QW!@bW+gH}zTGwtzKier$ -Ud7|d&$rQfhQRq%I2UE#pjij0xinAdeUZr|n#)p{m-h)ePbEoM;VLt%BgGmt59>`b-=8ig}*J4HD)optxW -gcNt!^p}C5Ywy4RFtq+LtaFO&U!QX=*LMD;XVd%`>TmGjf4bH$F!3*~^V^9p4Bz1)Nnj)eLpViJBu>K -=3Gc@V0w<~c#~PKafj6AxL6Z!zKNPY}yMbXg@kbTIA(2u$m^`W`lPoO@yl)#RP3yJ+iCr -5dP`W%Vj;|P%+a56!U-hd?D0qvjSMD%D0pnla7ki(N^tkv3x50PAIu5!7{k8oo7&4`!hX$!wG)-NFHT -;ol;vTEonTjr|U2q%A-v4%GeqT&V-$^?zmx>v` -;zY&s9LrOFVQ2kYSnmgs6ZoV1{4017_!%%VeCzu9o#c?Y+#q%FIX|8 -@J9iuvHt&d3K1)_V+i-nOw`&=mG$ZOpdOWcJYDmtQhNQmUEfvb6YZ6h{qJ?}SqVo``0!T&Dx7uIVmjz -yxH*}qEvcf3F>+(poIshg`a)Z{1b3zlT;2uOhQyP~I-!zSxX^w*1fP+EO5OYd}${fjF -s&K2t5?MJ@KkXQ5TNI8q#AC4wBoVcW(c%5`?zR=w;0ugLt!H084NhO{dcpbP)7%i4nllQ5j!k!ijLL9 -MYs6Y*gk@HD6_D=rA%81J=4GtW$?hyXkitw?TKy%mgwvZPXorq+icdXI-Nt9V+qcpra#k`l-;Kq*iZ} -l__3Vf*9?+F%1%HL!3{WVuyorO-aId58U^8-Ko635D@HCs4kI-g9BW}dFa(@NKQSe5}UOZ%RB2T#6LT}Z(U&9 -1%i^2=O$Z8Dg~f;)m`2?yQ*g58|iaU#I%l2hU07ps@?fOMxT_|=rJDa<{aeEM4O*gu-hHNIa}qFWs$N -!X3j-M2rHD|qI7%HCm90Z -_NNP|fg#&bF;Z(@hhw|J$Zmom*v2`NnsYTt+k@2!1vv@2Im>puwA1zVm<#7%mhx_@MIp6^Tvi#Q?C1G -}zMt3T;@J;T7GWQqPh9%z~(CrgE -cXkg6;zq5|P&oBW;L)H5kyrFA_C)d*0AC7eoiBUbPVO^pzkKHDJRBkfe9#Aak5DVmhYg!WcA{z}Za0#*;LtRe)Ri1Uzjtf0_H2E6k$F@uL~Z<^p>5s)AM3n@$wuU5xx -`V?m6$OjcM>lWm6nljd`uY%Lb>{8hi1s)ydxbRN3btt_BIy~PvGNgR{sbWkHHce$zmo4GgJb`x#31@C -!^ysR3kvqj(hcl1IC5TfUfz7dTiI>FNyu)LhM)6Q=1Q>Q#UyksOkKCz^T84)vPDB{%7W7hBscTz(Vg= -^>r1`Ke)W%fy_y=ue3> -!NyxCQ;ZAiQ%kqhP1R!}}DhVCVMlv>BY(>cA`BOu>!Fxvd& -)Bza=J4)_bih^8CE9tXFz&~OKV_zpDFZL8_tHV45QtrXoSb$#eqBKx!GPEifx4P>rot*^m@t*{)!o04 -;|Wi|hjNKPlTy#s@ZzeE8MH>#(2D -H68Qof~M&B7{^UD)5LF;h5T-blF@ZSG;k4X|CGwQoYU2J}jwuJ{F}} -ChixSKLdXF=@06@j-z@lLJH|m4@Mm%koh4*WR5{J8w^k)70b>!zej8uoGCVb$ecO$>9 -g@B`{746rQ2Q_qEadxkAdmu`vuCQj+&J|w84zqDh~N$0n=+&c?o6`gy?wQwqhvuuE<7hOXKxT*d?c^V -$t1$9;{$IxEmTRw}Kmp`?8czgQ2Iy`Xhv%gPu{NNNCMb@ka_1phg-~Mm2pP#ZS|LeCK`h&s#*N -c2w>OXnaclH@YZ~{U}m_jKSrf?J`K@y`t7>0HoJc=Mlia?2k#rilSl<8CcWO4=golvN-+@DD0Q9)o&%d!CO10&{=TRthQn|BEJubru+5EpmI|tUjO74K2E -@wxhH1e#KSjFa@&*NJ@+wka9-`_#%$besv@*5z?sTUbJR?FQA~YOp?2Te-`yGTtF8UrodJq)-}(f;r7 -wQos5RV(I6b5JLGdvVrMk0@rkIsP5J<1i2iU;Z8PIjv4<6~*lxY9>5nRIpz8$~;kQ -I6e;`?Ig!SG=@_2v<&l$|~#c0{E+Z_IIP!zMa)37*m2n0x)Q2Iz4uBI1UGeypt_z+6vu@Ec+A<1*LXd -2xhdxTdbsW(fuiAJRV+Yf~()G=mPg^YuPi%5!(8NgbDd6zTr{6B*P?SXS@*3ixb*iP?Go5=wURZGunO -DNiF!N7Vyevo)eYl7)s7Ed;Fh@hMCTjA~|g_Ukp#1z}{C$x1v#rvq%0Nb*cDZa5Lw -|YCc_pegxUjGtUp0-qEV0<-Oo=}}p)*A-M#n>j1qqLG?ar%*5`>)Iv^#5P8^@pwfeY5ow*7dif>l9?-n>-RxqZYdP1~Erubk?bwrV>hcMB#rQHUZREs -ea2s{sLR0dd0J%2antN^Jm~rB`r(o1U+Ss*e`f<**zWgOm^NcYLpF;ysM>_+-d7zwvF2)I<8af15A4FA*&eFPtn5>4$uZP<^&>r^?G3p=VJGD24D~to7uoMLJ!LUeLfe$)61kOie -;#TmZx?Q)(@rA#=b<%!a^Ausm83_vf6ogTa5<1r;YHAH*TT)_tdG}|0(@g+uMzqRp;qj*8ZMaH*N(TB{Sv03yYMgtZH*{sv=xU|q=xT=oYit -|ZI?$YrNT~Sz~`0NDI+M(Sg1)t9kldIOWf~FTEdV$r@ -mOGunvFCfh=8x##McFWU1K6K+34Q5e>rgJRsL^B49p$1-Lt3OTTvocqpgsqOXWx$_+C?mK99v%TMq<> -$1cZL-lek69Q-1Fs&1NR!Ly_L^#_}?N)nG#xvFQ-HzN3)Xo{b(G=!`r~B&e^vin>*xB`0gQ8lpg~PD-y$hCkCA<9isY -mtRXSrACHXZL8Unz!tfSN=i%@Ib5d`wjgY?mN2aSM;)b=QE9Yh?)$iA%b791JQR16N@dxlq)g*AOTI4 -WBo`oaP_AxUBu}RQ-DrCa*OFW3j3xrg_E#j_2$FQ`;`UcBi -0z5T4BWWGo(J(j7%Xg(sEEdn)HQw5Xg=3OsRLoq^B#c^WpH?~zu+p7iGkx6KJ>;(On27-!yM#Vu3Mv)@-Da@Mmy}9{rPkin;e>$Gda_pix4z<{ISCSY1^uS??v$j5^mHn|F -FsL3%t8ZQ|ne=^j05pDBcQX5-$#Mh1TLUsvGqrs#UY7x6@SrZ)@urrd`44Hj9oKa$SHhg#2@sIexJ9@UE}#Z*e^`$h+wr+#_LAjRj>(9`GbrZN -`w1LCjp5}J;1C#Bjr_i$p~A}XNq}65Zwvc93FZ6Y$lMZJ^0xUjx}Dq8c;w^$P!+e!=pt80FG15Vbb<# -)I$UoCkz|qu&8riAbtLr3{1`)ttbdh+p0`V^Lbh@NiawMi5U* ->PN6(`9=1*ST-=DbC})L(@BlrsuWQYR7HhJ=bT!{%O5fx)0uX6AgkV*Pr1z&XHErn6T^tTwE-~rxz5wMX2w?zKPrDD(%8j~W?Y219CrRWHUh>xe|)Z$ -kdOAL#9`6qKAr4`nE8C~4gb@Gae&z9VMJeKzR3x2>@|LDX|RQ2a4eTS(Km?B9S0uhu#aRh~tHPnPxn6 --_NBq*FjC=~u_FI$LgoM&Rs8?D$V*%M`$rb<;`v?mR-2Sd{@_GSc -k89V9ttYO~Yu&^~q6W7FU4m_8m>~J5n#MYt32a8Me=Mt~%W(mxXg;~4p8y=;cU(4U0gv#~;yu)58 -$tAdKLy7JF3?Twu`6b5{Zebh4@ruxvaXAiEvX`0<9UVW)F=vz?%R?HP#mD2K2XwWC%yMrYo|I-}-KW^ -#o?C77gqBR!NBv$Ry<%2YcH7H~-Nh#i(=t;%B*YM_NtT7Fn#tP9eai!>E{=ekwOTjT|%ABhS((rcXc) -N7G+BC-cyfE9W@t69Nb$U1J}S&<8feOt5`L1CjE>8hL_DpGZ_R43glQ=gVEj4st54#O4XARx3`{urU) -T$oYJDxqtxzn2Q(X~TsT6=Yrim_b%T^;#FUVShH_B6X(AQVjb2uH6d21dq%M?X;LlTF{lHplKN+n!#J -shyrm6Y6d+y=>w8HyFz@%S;pb@aM<{LMlkEeUVza{v2yN8woqa17%gaYr%AZM4E&OrulM1;)NAA%^U; -YoFwm>&g5@SE%d95$+0aWFu)8~Tm`E@6I%2wAS<^e7%?U;D+ac%bSLzkSMb-UVVl2|xEWyKlXbO9dz( -G+p&zFJtwAhZ9vR4pQT;T#<)7Z$y)3e3bfY{Un`KmGn*P6soCP(ZZyTt2)GsHaDOg3>R6NnD(I6k>vn -fevj(b-#!JCe@0q;lvK^tI}lf~S(msXjZSrh1p*tE*IadWaZ;L-G-*h}o>iI^rJ;nzZamh~s%HK*p!y -Jq*GS(FShfD;iW(;<%iqXaT8;eZEo?zm=y8L)Wpva*Y~YxmhMmLbz<6ac$|iVK18* -x6q?$2f1+tj!^54sz>j-R-cFwH-Oxr>pv2b5YSa|ze!V{+9BWxkv}mCmF9mk6AX(|F=>*_yf!AKIS8B -p$DwVT3YrgdLE71`QSteF;VbbQJ6%kQf8DBvc4?J|2l9-gkn;fPdxZFmCke@+^Ke8%*g#Zm5wo?#!t}WX{)Wl~W>krSSZAKpj~14jCc`0zI#&{Iw>$VS0eTucH)cy)+uw8 -G2H#>GkmP(D=&qe(7FM!o`2&*DmkxkUMuYZWG{@%HNgjc^f -@2?RSL=h{v#Yq&Q5Co^lpCK%S*mGLg#>-9j6gRc&Gj80BaBB^N_Gzb4yzw-Ck<(gVzU7jj4a#gYy~$l -u1>Fmc=_W?7$vG%V0u;1&l3`mBG2Z8buLmJ;%bS -t-p1}(Cd0)|gh`o?NVH?*uMz;;Eh>Y6g5dIQj`CASj#D9vg7SJdE1YxQF5Mi~G{5h6k7QRPV*2ykHu_ -`4&tvuv5M#Z0@tO!yTW!_L0u)(bF4wj7iPj&_TY+HYKR~yp$mF)13NDG!8Ci&ot5$EFT3?PiV)7%~)=g4v-csyMKS9(Q*Ey?;@7Glp -C3{}LQuOAyPY2^76-p8yCNAE?4{VE$4O|~3L_rXG6U3ndEaT+gz*P&IiZre9 -*4uvRxUHYLOeAu?Dx>4UnqX<*JeH;tUdiuq2pk8W4a+;c+b0)C7tNwmJ4vzr>Md7( -bj|*(g`fXhaa020Ev-csJ^YpZWDzG#zNSWWJ!KLZwve-&Q;ub=Oqt!rAW4*v0IbaG;a|GY)W$h#) -^XIGQz{XF3M^he!+fRS^h9PFd3zjovq5a7fgWySNk}W&IWq#KoMFVhgq5MkDH=2=FHb$Xty9h@@?Fau83 -Mc0Us1uCe!T$xAjI;*|d^UpKW_<5+f1dg7y(dG&q7OShip^xLVQb~u7z<%GR%THpSH6M~QsmyS6cW!szXp^8$ -4Nn1a^Zu>)pz)0oU`J*&nF^Czz)itH`pxc``ogo@FqnBHSZ|_weIk?a~co>J$@Xki@u~$AUv+iVPyT2 -ne>e7Q^L&>3o?SR_-&tA4K~==n)~AuJr;P$k`|Ya0BI#q>P{V_z1t?doo@^WM)xlAwUor_K}Vd53Q~} -^pAPc61bt7o2Rb=Ke;aA>P5;qFwWFM0&};wKheqp{*Zx17;L?9>%m^b%e%n-+l8-0;t4aD}m1IHnzxw -1=cgO!L`oDjJL6G|G`!oO7Z|RDwf{*2wB>rvalHb~|`}&?wjIM}~LNNGes1OaeGG -RpRQzr0D!5fS=00kyHB15+MU>nyf*vgF|{8Lm&?q|TnE>pV;Y$L&j*l>L39LIYJbst*4qO>sFR$U<-v -7)+Pi4ma4&Vt+7B`aLrGK1-MGPX}{1>WUdRt-oL= -fNVm2e}xM9>xK&FuT5sWQE7_&2hFH%Zz>zh@9DF^#-9~R+WMRu###0de?Y2E;;X@%(f7Jo{V8B~g4D` -4z6dcn7zlh&V6nk>^)VFf)yz+Qyp=~?Wg}}KpC>A8UdjeND;$kU{O=b5zFZ}{7)%`^QnrS>U?5U+;65 -s!WuOSQvJl3)WTS;}AIOk?E05cH_3h$Yt@RV>RZ(+W-Ah$^?(Gr6Xr_N%?1o7!`1{xl?mnptjjT{~22 -|4mKhl8oru4TRg!W_QA8**t?icV+ZrIQ67w}JR*w5}4@K0{o&+ZrSXE$t{*zs2bJAjXg9W0(-{29hjB -{;}FZqm#H37^WVu=U&P4A+9@oG#bn7_do5EuQYl43~_`23pz -yCQFkwz|9J7}Y>H1FI5;()0KJQ=%a7?_6h=J;Edk=t)fEF`5T++Si -q%!E6?)ny-n=+ePG8Q)ti{|SK7PZX|dm)QQ_ktLyTz>5rKWOLJ3aq%(;FpvMJ<>+mpv)XsZ2?NuQCaHc@%MKJ98Yksza5lSfAENS-VH1Y#t$Ae=)X2$0f;x;<9I%_M$cOBq(Z -#N>hp`cqOaBp8i!p*6#?w=xeB5C}eF#355Jh(NfuRsI^H&8)^Unayu@b+M1nL=BtDkZk!A{lHv(2YI6 -UW)hyIsxJBa^QxC_PiOobu*#ZrlN^OTfq<~HaJD>-AwpCfGZ|8TKxLd`bNTC_7d9pwB$Y|b$w-mZN&O -@f9YS&+F}nIUB3M)m88;ga7m2&o~p7`_I5D;*vvF8A5IteGq3x1oG$QZUiZ(PE1XVS$h7^*p4M)}mJJdQd?=kF6+WJ2qt@`4e4YZxZN@^|>=$At7u&(rA|tUE)D8vg -w?CYHL!a?^s#9;*?AM_2v#?y@HDi{H}ah=q~O?6N47TT*1?)DCa`A-h9vYPXB`W!$r2Y18fRT(i-x{V -m?N7h5L@4tuLx1ks89&ePjB*KU=Hh``4@gPTt*=kORkmc(Abkqy~xqx)_*j#9rR!6qA9s%po&>aPT)$ -KVuBc>NE?0h9#PjbaRebJhTJ?trs1K?9|Vs;C#J>g;SkSqGZ$bG}E1vwpTxdyiOE7|7yLN9$;p@X#)< -0tjPDQH#I+$25)qQfDaCvVkL26V)Y3%F;1Kt_if*}XW>D7N+oIm$<+y97DAEaFC3$P(SHE!9HUEIV(( -X6CU@ykIov~Io)#}uymdbR(0{Ct}+XlC++XK-rlJlDg{XUFk3#s>ci)%;`cyEMHU(o;;gl^feDCpKd4B^+x!U5-gXJH$_*Xjw{%VVVwL@Ur;@?-M<6PGnRh}bL#%^rJ0 -ui9oiLPb`O}HWW9qin!5Zt8P6FzBN(R+!r^eG@O-| -58N|A6&Q@kmh|=kJ#Nh{+!Pt@7DvvKG|AzKu7p8p|<|*3p(#?9rSNhPL*_dO -AcTr-&bHxd#F13NHeC;bzNz`kL9`sB@NhX%j>&>oT=l+>n*1QJ(bwp(i1%lTx?=w3aTrMoL5#ynJ1R` -hs(B>>QS^Swmq|{#o^oV&v`8h)dR;Crbq662?y_=7k-?AC*#fLVg7?E$=5;$K(nqm)Z;5B$0RFj=bAG710MKjx+aa$Ux$J@j;CT?u -w)XkWr2|UKv@M0j-6X*p$R1AvA5n=9WAJ55_PmRm-VS!;gDDJQ{!J%F6e#os_A+lz0-7nnI{Tm{n5G} -%;)+m14?b_t(u)5boexf5e(i9g&(Z|Wvyr3FDKm$k@=(xIak|S>|HcmZw}dNcNhX?R!9W!M%L2D<7mM -i{jge4sD1LN*Z0>0Ys8vjShy2;Y?Hy@g`PdAh2t%<>sxhxLeIzN3|z5Owq#&PE_Cn;$-=#j<~Un|nTU -qi9Q3r2?QtC3?i&H8I;;ImR#1I9%rB3BN(j>6w -ObrS@lA##5uQ2*#svl2H1iiS}@YCfmbG-$Gp*_p -8$(_U3(DQ!7E*Fca2`9p?$C$RQ>Et1Y(Fd?596?qiG`zw(%3|dRKDU^6HA=TJ?-x3bz|(T@IvnYSzYV -`M$uRlf9LY%JWd44B4)f90^!eNxvwyr;Xon{LfKq%Dx3BIGa>xH;i+;khzgY15F`)#3li2$EfN+c?Q3 -yq07{Vx+ASoOtuoch|82(cdO0Z9-2-hGU+9qLLkV#Tz&bcF>jliiCpisw5z}6)NyOB2S4eh>!NBR2oS&cd6UMzOUtQ5zPoqk$=Si`6v(UZa -buJ_C4%E<;R)3^F+4WkQ%r9WFceRDl-^Hv7jY6=SL+o!;Wus$9)Ne`dnTZQ#LnHgs%%4AESSOZ)g -AL#qV8M>fVLLztv5NWI2C~|1m$0tr%|+0!0Mh!1rBPs-)b$1ay0t9lM6DRt9WiiXlxB{TW_Y*Y&t{GZ -+yF5qt2(&p>v2OwAE&-@l2+*K1OrCwyJ-a}*HpJBc`EzjSCZzwFTZVGJJ3BnWWg+q>KcZWq0Z)7Vp*c -JQcB!fGCE21bYzN~$WUU*48u&l00q8zcN}_*C>avyih(}~7! -W_13w`-Q!1y3vcz>k10zV^PsQOV-Yc)Zi*Y05UwGd%9YtU|W32x2DXL<4%h89`%Z85+Ht%LscY&@P(4 -rnsho~Wk}MCdMby?8kxFR~iGvK)x)!c7Ad5oGd!9g_fU5IFJ+pOGJ2d@4#5tnzE4DW-2`2lvGHxu;o3 -mO@YYbeSX!$c)v^za399xr2PB=~6xA^YM|)R|MsGk7%2mz29Qc)?bMw#;V_o&GCr%)5U39^rZp*XkB# -@Ze%DXJkWnW3(SD8W{)~>FZ&E?Twb|^Kg%MSp(hs7JwFsDKS`4DJm{xW3Itc7G9zpSqLk?ebwyr8mpR -e)Ez>+mm5=tt$ea^ogw(@1*B1*`hqL045y@Uy5SAi9jUXks*_QZVJ!I$-mwX^^a?q}p`e@D%4`g)$dG -~bHpwP=ZoyrcT~Ln3-A5V;GWH -19U-=l)?5F=yE;TdY|a_k^Y-ihDRjFewrekJI%3Jz9|NM>G^aS({C2bv3;xnUMq53;dVV@c>)JkI=J2 -+`@?!S~4R)u~>k=<_Xwd)g)dkk??qvO-o^SEfH`(o0If4D`Igc@h`OI)1g=eh(0C{wQqvC+?V2==qb4 -gGJ-9X=42=&?b%Ry?OTmIQ97{df9Yj+-B#=h=8&b&{6y6B6te9XW5JotG`5q_M1$0*;pEtzAe3lP=9b -Ke19;cHB@d0TvAW+t^gtUeD}w`*SR{Gi;jNyt8v9+c_a1<|mj46yFh)!rMV|6c9+OX(RIIZS`@qYCI3 -SM!p@nO{Z@XH(H#pHPB$bc{}y1%cbVn`$f3v#Vz*P*s-LQGbeOBme`nCWhVwkgK6XxhivKnw*Yi0Jf- -lFJDm?o{np9!VLwKW|uoVTF+RV4&X#y7=OCP2s1?2P@4cGqmw6hI}Ol>L&s&Xo9?8{^r^#XTx -K6()8WAhi$e@xj83gUX1ZRUU2H!i$bw@!dl?4S*9PdF1lZ{tc$R2&DvE^5eRU0%I05s_nV9b<6>!Ctp -1BDvt781V_Waj#z_+9}uxGWut3B(3@T_F<;$D`ky;^>ybdPzA;mb7t1TX@hwddZwqBQmPoi_yIf$~f+ -y6x@=t$>GT{W`7wQE!fT?bHz_q9R0^vV=Zpf7+xr89tegHxxWZZHj3}_#V!^No(9u3#%tH5wFv2f!jv -bXH=qiPriV!A(fwGj@6n7H16FejtRkWjy|EU-kgrm!d(0ZhZF5}$|{?>o(u9Op{f?^(RIYeThAa5o;D -A2&0c}_KBKSbnBVE6`pRA>*BuZ`y;xrQvW0kb8#KPz+EAf~@tg;AC2=WHcBrCCW`32#8HhoQdw6-8*G -Ya&0?-vj_}Y($elCSJONKsr$)(X61eW$w$=+w`h|xJMdM`T-> -e5gDp!U2a&4>EyY``z#kz4q-`6R0;mZWcgGm|K9+N#Zpq}#pG7Seq=^>60x|2JOeYkL3J*Z3~mzrs?A -+JrYYJxhc{Kx*q_AaHc`o)`pU6i)rT7W^RYR?>ZXW>!YpMK*7I~PTPgj(!C-a2irp1gv4k&6W=A!Q+yktzD+ -XR9Wb(ozA3s-M1;54G7R0}(%xuvv0}&h7h_4A8d)b^JuzADtvbwC#BJq7s%0r>SaDQ50G(Tj9f -G@FSxGO!L>|PQ+YMom-)2wYUhN(H2cNL_0J;CD^Y1)O1I2u;CYymXWf}K2D?H&!PTit;3CXG`tb%m~q -B+@@b$GXXV69wmr57?`7U)?Ae&Wz$RtMQPE2hw|Ao -~2s6l=@M&-bOJ$n@N*zvQ%S}Fk+{;Y0fxutTWl2B458hI`(pbAA@=G+1G&wjPaNrUs{S&b%LI=l92sZ -{PvzOIrrLozUS0ij3Cta>Rhl7hMwJJLhr-LOE{)opc-f)1Qaz~nmy3H8MUu87ON!aI5@}BjK(B3?7>+u*CrrPyfN`R4ie -4gEDbwKngeLQO@tB?m~VA{_c0~A4}PfRyWHE%ExTvOLeBcCo62xLbE@k`*WzT2NI>B4+a*gDz#IvkjU -N+%mAF0lJxtiHK`qsVwe0zf4hc`7@cIkPi$%7NN`OU$QM{jQ)x5Y-pba31GtIdN7j5Y3LvcO#FP0ha6 -8*TA>sz3QH+2@N!O`LrnU_nW=g_DyIg<^j0`(Bq0LVS!rQ&zUl78>#r8 -v>40#2SGf}DhR-E18P#_*tJm+LLsux)UX$w+3!ukMjk4RV=UQ5&{XHM_zijfr*g)jxUDhlQc#&k3R53zS-Z<-^p$E41oV6 -a0?HJ_7AMe#hLhyal)bQ?-N!qvk6O(KyvGYVb -mLWj5=VmgSa6)dEtLY^Nqc#gM51+j5ODWsntG&Bug{i)Dr0brOIQw{ASZV!u(#^el0@veE)+4qk&53O -~e@4AWdp@4-9AWaNZ0Gl5;qr9!R9NRRMEQHrsCHqY1C=lb4wYLVBmz8?R4yiA`JN|vQ}w7&LIPT#4wgW=MeUAF5YG7*YBQNbc -9_CZ>P$x0?|aGnjWtJrlCh3J`FI{_Ib*wuLnGfbR|rfoJV;|-iRP$=jHuYF)pCct!bdQq%QCKWqrD+cWzcHUlASg@FI$%nj)M*Ds;w -|EWEE!q9(t{cj;E_%rmmCR0D;M6Djy|pwZJiSvdotbhRj| -E1Vr$Gzwp0!rY+5DoJ|_~}vqwn!ALK6!7b3e!s~@#b^vTe_=#hB*K>5Ex(i`BG?ZqE5;>>*oiK0D3i@ -+#v1>J8M~7wvv~yh*SDl5nmf*v_L`Z8tLEimDzfG~3Z;G=Ct_%lC@m@73!ZzDldBU -|xmdy9!qbx5CrX+d5;N_3@@d$1*DvQY+6rm%+xoYgBNBb>4p!Pygn&9fL==-`CR`Bg4E?TuVTgy3yml@JX9t4?!ORV#)XGiwpl~2ua%a^b8-2uPSx} -QKGfEtG;mB~iEbdS^@;ALtgELP;Blvlp1%g9NITm_=L+hX;tp_l@94J5pE0)jn*I199;8w*!GJrZXG@ -}lusW7L^Vn|IgM*x(-gDK25&QW5jv`)1`O5801OILZZFlETskD0U%XmoZGFKu2?W6`12u;q?|MWG0+2 -#TAZCad08k<9(HiZtNwl$6l3}R&{Ca#Q|BGxicogZY-AY$qG@gYw+eF=_w?LdeEP-N}F8fgoI9-*@}U -MqGAZ(TYslzsrWeHVg5xn87=3rLbOqGc_jM7B^ew;vV%075ySDWz6__s(I;);mKtC^i<1?V9^pg2AAq8u^r1vmH3YUX9(Uejvh -lHLwh;45X$o>S%0)Lk?^KE@9y4lUFl;_d4V<76+GsI_1BK+N^yI*o<=#xW)_U-b_8Shq_v)4zCT7eSa -_I5W*3DvWhNR}rw)gEl`D~=t{ImgHuTnh&d%Do7_&F@1ll>Pi53-9=DYNfLk2~bdRvUBZ#RYC-xJJ|$ ->$gUI?w~jF9a8J`Z+xTe;CF5j@E2@o;GJ3xX?fX~-$Fc1J>T*0&mK82#rpsj_CxHf{Q`O~OU>?!hIU@ -yA!fAPHZdTdf)gU>`6c2&)@i4~+*amzoy?2rG8sWCYRl`E>dh2z!3p#QhT2wEwVGd_eG!u~Il)_SPhW -@HvH!*lo@(Pm!pd`gk?CgewNe~<#i-#_w@M7Bs?>!G%XAmbDB#zlDZQsTu4ZMB5kJmx9pX$5r;wA@Ns -#r?l4myGHGU1sxy~{8TMsLP0YQ^O_mqp?U>_z^{+hYq0F4xO4DqtLOdo*CB0~LrMT;<2p*?z9^8YjZ# -nKE9{4SOECju6gCiPJ28sihRDp&hbXx*B_Z|DP>eYxI+bhhaY|~TahpS{0_Z; -t6F*r+vUp6NhNQgp&U-Gp!(U_k=gHH(SdE_2~>#>-|rO$#+99R^5o_*ZUk@~W)hLgjm71X-EBZI(LQ_ -siI>huAeU!j*bFP!|}0%bo{&;L)u+5hQ%{2NI7!yf(;){@XZJQCfM+>>zQL#NorxL%Ph7;n9^E1=!v@ -8At6Ch1RMEtPI9xCFFy`cnJEAZi~yLB#vaM`Bw(j5gr8Vq~1$@MainC>Q?~tVKWiZ?Jvp&nC~e5vs9Z -YwcZeID~CU*{$6;+6s-E+IzI&+mPA|p23E&acs-9hS2unP3k?`lD^w}A^(FQf7xI&ZLs$K{1(=J-%zt -cxaUtGE%(vx_wOO?hTwpI3gK=X!+s(-ZAEavzlF3nOXb!bj6jIoJ~FObkIYBY45V<;3T-#iPV`pxo*8 -{hwr-s{pU0*wX!lws@H?3&HWYoQer|ct6F>P(EUqB4QNG!ByKnp3T?7AQ+j~Zq{XY2$D3(6ypV`-?mw -e~lZFO94W*83^?!E(UkMpqJdSdLwcZAu4v&?X?WnCBq;ytB{En6RqK7X)-bdcY>a@0TRi`m;^&Tw&An+o8yKaxJ7+Q#?T)Y$LX^T|LM^AJ&iT{T`kO=Jr%s;8)tae@lAzq89**%Kn+=wdOM3xe-1duqeA -@_vatxa(wNJNj0IC(DwN*Zb9+@D#N73B8il8T!SD7e -#ZjJ1T(rob9UoLL&_3>>-(bJ@fZCit$D3uIU5IF6q2gUq -p4t~Ce__Wdd^7yXp7Vfr9o4N?hU|lXKLo^rt;z=Pot?qXx7;dm$gYvUi+e%A){CmGfQIXytxh^dA2;|*fIgdtaY)2Gc^b`MEpq&=UmpunX|j -iE1l&LSWuh^VJX^e(-JtLD4ysYK#PE{>!93`dVP=Q2d|a88yy-?jkSRE{?|K#v0B9=Ya4#Xm -ZPJb?kNn8z^?hWD)_(`qqxS3hnwIZr#KDJ@g$t%|btV&qfgX_B#Vvrwj^+)E$=b?F>yV+ZJ1K{#GJsa -)mJ$Q@eLI3&p(c|$Nw*#%OPV~ihXIKn*UeYg}+cp7RM{Fcb8UQ+FB8qk|O;>Q#|?s=9a}iMx2luztAL1zEpiT1Ryv`G2Wuktx -NQtr|>H?7HL?e(uz#V-f`bIQQU!ctNcBa$6?SJn&=TwAq#WF%4d@O0sF}pDklhgV4gwjNTE -}+Hj3*pfq_z6_tj(U%v)W3La~yNysq-yibDkNgH&7!mTbDtOj_Uh-2`OmX5|>q}~5&lmzNC$+g*zZDV -lW&;U~p(ebeDt~!z0x_}11zpZB^uDe2qXvqMV)sWi!~D2ty&+D+jvDwy8Zn8it{&}5UEZt}w<#T+&PL -EQ>e=wcC!1V?xesQb6IVfp{N~Pe5-R$B)KiJyS+wAudi|!o&>`*5M$?>5Nq}WG2Xl%c!)UfU92ZA93F -s}dLfnB^MyR%)0$x_@a_wsq;L3WBd~#K0doAkqtCo3z^n> -)P>W!sA*vM0YZ$tI+o~MQ+m(y*f{YgFv?V#q<$$`P@-Q=wPJ|WJjd)8-sqwv;-i?jcOgnrt!=MSp<5+52i?X3d;eIGOv~=;)0+KlZSB!D@v|BQ4Ogs2J+^*1g4vw0hw2a-R2*sW#nS*EH)|&nb9cL|Yw|6& -@_X6F6KMX?l+lIf2>|=0jC4x} -U}oA4es*^4_d}#-vT%Y`iE}NAC`UzR+B%Ko3h~K_UUNveV3_A)J&!0F9l`M9#sHNmOtmGlVg0(^bYU>;RVb*+k#*Dp% -mkF=#qK;1gJ6xYG5`U(^p`M2y=Q$4Egv*yenm-X -rHIhtwJGqZdG(2v9|>mOJDAprg7S3fQe{OhEDfPj>CNyS#pD*ObjtTxW7M~e*S6zi-?lb+*Oy -;_GOHC^=TqCZQ)#%#b-MqU-qE!awc#zbmGZX3d9a>TIE~g1iw98*fz9(85TFo{u=FnoQv#|uXh(FGw1;*i4~e<#Z0+@qn`) -W-SM5bn$KGe<6JXAl$$KV+AZeNF@}9rXoa8s6p~B0Y9omQq~zs}a{xcu^4(oW)ryOo#TI--r8swAP2#UA2lj7GG<5n(#;K;)oS+Yd{@4gN;M$uNyV-}kp2dw}Y(k@GT?NAZkc4_ldm3sy0#+x&|tn@GATpa{5fJF4d|*h*pyR6Sd>I=h$sjp+`idX;+#95)DzVe#y4aQF -;vBGH`noO&PhDS%QP&34A*RrnZjcp0wrD-^U%*?v-Q{tB&FoV}tawRpVGXQ1Z!vcl)Q*@0!2XxsHUYN -u4pJ7X!BfVz0ZGphI#&6qcWl-rze18}UAd+=HDSs?&MFRRP7;ARDn_I8Y)9yO8bEEo3B=3y?><*G=>6i$vPIdz##XmsrfMhD|v> -+3Lhgr_2N(Nogyyi#t-~jw*_*As!)^6*xrBk7_FkP3a#-@+Q=#>Be;uIHWr33aRBeri52S1LRhj#J9y ->=iYh{`!SD&_*o3v~Yu^v~zRMtOQo@-wx$75ow+&8?f$ql2Q|*nsidX -!wz40s58iy9sZWQw^8v+aejQ!mDnc3gK?N*zR5Qk8t8U4SrHRi`XMlX4FeJBYihZbMpes?jrSc;G1Uk -gn2c3VkS#<3uiM?f<3#TytBd1S2R+A}9pm7>-gXv74x$ipO -H;r?DmZ)sK%{P!b>QGDz}ilp%hlsG}x;emLnv>era~ImKx7A@8J*#Qp)c;!pDbL$d`XNAjPD5Bjd;BV -`zdN9O9F(~5tE|E$J9#YeMC{J8-vIk?2A5476h)DF}955H)L9+%ksFP87pyz}hc -ie7mEsH3lR79Yj00fpK1Y$UR1~kV<`h8a(_+fAQ1T>Q7|Re^E*lz7Gxt_P8FP8}j5K -DWo*H{>ICKv~>l^mnput^DMSk;CfYu2~qC$|^5_mLg?EcJWbd2$+NF&!HUZ+Mv+StC@lgVRAO^<9qL| -PYCn}sWSmo&5xrhT-7c_ce72yK)v6p!rI^J5Ruxvr%vt4U=F=wtTc3&<7 -xBBcouD|K6$cul{j(2a>5In6%kxQ)Ar?ARAq!U}JA-`~bwdYHE%iF*umaF1A39ZiB3g@ExBS|d3>MID -Qh7?j5{9v@^C%`H(ivYxiFQv0$Da1j-X*=vpuQRvP^7!5kb9|1p}&;u`xyiPjxpTtFo0yZn`A+xGOML -*OdMZ@3n>|ow2^)mF965X8DnrRRYbnwahWjeUh+B16+PV=j^%*XBJ1 -eC=SJIwP^wwF97{?dFK3N@NQ}6tt(}d#i@9VRa1NTZ&az5hNS -QzoEv6*mCM&6vtpq=mVidpl>+Ef!Di>#d^#LH%- -Zj2~)Vu3jauXY9c&M}jqG3v$}1gyiKkJ}#i-i`NL!2i1r1^Jr}1^F8e1^J0Xp%99~X#&M@n1U%3+uaL -9;1rGE5VX6S{dW{We;TnLZUR55&0%~5*4Rhs_Rs@?j_L&-{z`_&cn$J#I>gT%3ho~Pb(|bk=7{{-j){ -K?6y)b6DmZw?jtT~T=!=BOkp#ek-7Wl?8hP*$S3y2S>+oH?VuXJ* -215Vz_N6q -ip=$vH!F~DgH^#0(sUe65e0S6-b@Ztm5^$B4cWqI`w!$!bxGIB7(e&(2H_9!-&ehC20>w6(Pus+xbb4 -S3)hYml$}!6FLY -UGt>%vY(Wg~2^@T)UJu1?@Mz6g6x==UrN^qD*_W)u!kLkoF83<9zxe}1#6qBNC6KJ)Yw0D#!93iSCg} -x{_8mJp6riov8rkO|C6RcujJ8`+~z?AH^Z-spD8)i(`6Qo%tJAg11yx9?4e2lD^%kp|tiha8KLti?C| -9+pHzyv6rgto@7F@bDHp~_ICMpVjcl{S3T-BTR+&`2MNY>_&docufFZH92W--EF`KM1b?Dr+r4n0!l5 -laP3N@FdG#x1@D<|9Z`Wkhx@ -!eAjm?wmFE9rL>f>o1Ka8{bSO!YtXRX2@VMWbgZ?3@PyQ%#vMy7JSl2wMkyJhJ*rLh9?yeJkFGY8S*O -4lx%=$cm(GRkM`k@k34kVeN-F9E@|l`ocn&FECh`{j5kyW-xQ3JE0$^H0jjRq%bX6nQMm%rdDq5lHT`PJgKXb0vWNLo` -L#nD;c@IorWr?G#T@r;NUU%SyYkdo*?;WgNTt1&SMm7b0;)|#3xuidi8sUR$fHGXdIJSjGaxGipsd(P -;3%1TBKu(LQ)-hBseS3$YbcuRel)~rox;3yeRMpF#o$jS*@GUp%p+3c|Ks6P*U9QNwrWFv3Rk=QT$uP -B)hB=k@i8U}ATPPz8Z>0`-K8>`X2c`q3OVQM2;a=bc$x}gZtCLs)Q*Tnd!s=^qNg|%Y=u+&eQ!_M~Xm -xj}7GBS#CuKb}Q093Fp1u(%7IlbCj_hXfAdpz|EfHlrE^EzsHF_^kZ6#`WqCB8YsW5h4*BzW-3j#`w$ -JO+;$KOau&}?J78G!;diP6KodV9p>PL-)4*y>qjCroH+q*f4z!H9xO)F@xYWzlO9ce+Ye$>puG#T2p8TDSHBv{eq*{ialv6WnY>8EStUO@3JzhpIZdx$)lI3@ygVVA9@UhVe@<`Hu -si8Pn3>M@QK!_%#sl<2gW(+ov?BAI6qOmt#5?=?#~3p^wb0J{ycE6o4xz#9FVI0*e4I0*e24%+|G5Dk -$8fzTMagCBGcr}y9*qW2)1+F!?Th(qiR-lN-}&!j{L%! -#4{vY_Et8MysFoI1ut2<&+4ml+o%K2|+uRnVg(Li`z5$Y=iL7=BJZoLC9`(c<{fUdQMGq5|sZ;D|qQ{ -~kJ{@GJ(&x!X;yjMh+j=j4 -Z0ck1pDDWiZ47ikAmDcxX#1xa=nwqd{}clq5D55SppD&6Qon0Z`_{0vhjJnVNes(XPD^=gLNQtermO% -50##mjtCJ(^Wh(B;@vPUKd22&k&zjwCBUx_R5pD8mG;B%f%|-8xL;?I0N{gR(r5+ -f^x5Ks=+MhXr#rb)`w~G+)*!*K3W~#}|nH8A)vWJn+d$Yu7k-U0+7+3y=Lx`(#tlSe>xbk2T8!J-cv@qP~WY2OWhUiM6ggEN7`jPXuiu@im -##6EH09(RSGp}FLvynQr~A;&b^VHZDi|NBPB4~fHH84v0(9!~zf@t_3qa+zBLwD-@~Fsy9Po_{nR+ke -=2K>yzv5AFOH-L2ZS&x>dWL8^8dglh~R8OR_mY=TLym*&;;}LkK!u$E_UGu -|$HQJIfb$>KqbzK%+d4I-onfUBbRe$U0P9oUi?ThwYA0aFrQ5IK2A>nzOIUojPj*aw?0Z<@BBfHMvK7 -LCv{=|fi-$qtn^^6zg+!l`sJ?va=$CTT$|TnMGiWbmp|mc{Eyu(^;7jJ3_Pa(m9OzHY+mNo5SPEa<6j -=}>tKZ`^4Bj+?+;_%SN<>8<1N$v-fvgXt^f7qBEPM??xstP`&Yaj*Z6t|KUl&4Ki=Or>-&%H?K{)_Gj -kh-2iyA&ruJWsQQPE0L6dw~PlFFhO!N_4gFl?|Kj(GZk?S^VO%LFNesCa_9D^G%c -Hpahu^rgO@vq^Z<*cv|v3`giQ0xm4e)O53z&^xrJKoyOJLZ3=XrhnY?kBHB1xIdehjg)j)I<>axXeLK -M;xug`#J|~B#+X|UzppAdvuvV)4v8S{=ii8Wqug?Q8J8|7T{krY~kY!MWtJ}<)MvnN9e+R+Jpb#4=eG -_{NlD~uRc=Z-ks(A=h6a!qm=>2BKrZ$dyZ3pEN{Omd+EZju5%0-$fJ8_mB^9dz_AXY63ez^*}m|KdWU -A<`c1K8H5K;>!$%wNS5EqVUjRRh`r~a?%ENWrR`dNathkZ22K&Qt -4~MnAZ;v^cem+|U_B}7kgXzC<2+7|b(lOQ{l$HM+_XR%Gw3@eH)pOeR%b)qna{?ZR{_)xP=F~=;x4FA -*viFt!_E*vNe~$-uY-jj>VdRwp`#v9^zwuEB`v=6YJ!;J=(UE{p>z=|&Xm;?7;xPjuWPQR%qkIrXX?q -;Jl$6}uwb#30#Yc0)Dgzs_l_I19&(|IBD%}m%K$9u5w2WO17Pt2)xEB0U2H2=0SM#d(!DXYw=p2$rPH -*77+up2A6A}bVS`TRG9L{e7X28YS`V|^OXJi=qu{#!xzEEm)EAP}|pD;))D>C8$t -{)l`|1^>r8|5v7P%xp97k0-W$d*z?!t^tBCXg#km6oN>v-qiu0o-dkC6*BG&<8p7xV0yq2$7qTt#0-`IjI0S*OtxUW-1zT@YrmV9^&TfNZvx?_L6pt -UFnI1qD_umurqX{T1M@SY$S)+XTyw&b%UX0~R`HAC40JD6jSS`2_A*4Vjl!E<-I+}69yn9s7Zpjad6E -H)7=w2;g*!<|a3vj9htda4Rx}vxrpQv9;!e||+Rh+U@!kS*yncO3sBvG5WDaf#Al+^_2C6%HU&B(%^a -rK&Jei>3l#gDa!?LaS*ez2#52dLTA^N`dy20x~Pbd3s!hmv{&qCjxm)6HkN5Tdo&dLHYW0YhhTT?R-T -{-w}Ti(rqC@o&;Ig2iaUFK2!K@w+8 -{InL5e>EZsu>HqWpQ6A?XSzrGn3w}cfKVR(kFo1@jJv^fc93n9YMj-g-3O9Q+6ov<%$RSaR9X+J@XI2 -tNk2vONPNk061*3k2lcNmuCyeOFYz}pFE>NGLnImLE51fF0(l69!a5AQkD-gu7-hRzPTlLQbScBxq^z -2|_kH8MO9rQCl86D9f=I!wcQvOODc*t>TBLjL+SW`h9raXA7sSbeCAW`7OZ9@4fS-`(& -F*6rrITmJEmfq#0-Ki)C$w{KaJxS#pEFHE87$Ki1whnHR$#8;n`nn95m2jr$|`s{&rvcj%JBUvVMiS1 -RlCg(^;E`W1ODCol&n36Z=rKX?u{jw%}KS1leTP4AH6hhO5)5VU7G<)W?M2~}9Ub(l@=MGx{kGkIR!b -CSEvQV!JcO{Tk?`}hE^uzAtic<_Sw<`oyOV{U|N7~($%d%6ixz#y=!3nrp7(G_x&=2A)C -mM6IM0k>56DHK&V+^6I4kx=c_HyXyRsB8it&x!lc< -hauD4ia#s28`wCgGaRX{wgOa3Om3$)&rVb@)|hV=0qO}ViES@e0;4)IA9iHNca20qKN~9RCLwa_8;ir -Ro&Y0&Hwh+!VB#zYjM7V!f-Q4PU&x!Ho47zA%XyrsYQ2|pt(hp~&NrQ`)6+92FmWuK8?dE=Y7$9#>vK -8@<3RJ-tlU~QG86TRd+4>5GI6ZzC}(S5rL=c+dWv(|Rgz!McWF9+FZIH6>5VJ -U1Mr(e^bi-tm2y8)p9~vsO6=>0l(@GSi{wKvZCt4z43*5todGQ}&%;7dmS)jBaN(=UrZk`3SALw0?2G -?;Bgb%L3?%y#L{}ZOZ+|*>2~8E|+^H`B`cH9y9=dnZW!>W6MEvv%hTK?IZLNtRr-CR@ZXvMb`By;A}=T&sqVjziAQg5vPsXacRny>9*H{PPA@SNIq -_EQ_SXB=IE{s2`@z??BU^HCmi7P>K;ibY|__Wrvow;JYB0%obZ&E)kymOyiq|iSfQuY3KU((9l?ruyM --5be#8B`e-5e=bD*f`RDURf!>e%eO~$wcu*}Ez91!(*6 -OZIRbxI5V!lgd-lr~|9=^}CvelLA`i}C-75O@~ZS)e5H(ShZdc1q4h=3jH)yH@0l%Q(R+?w+>M~&w!q -5(u@ZTN=%iGJ<}1946Ng?1wDk5u*l_~dH7y>MTLF|H0u;a{To7xRBAA7bI(Uj7%gaQvq<9RJ5I@>{a! -rx*A^^ae*T41;K#f?)_EFzV+t#XH)VNmjzXU6cK=hc&A4C!c3C6D% -@kUH`{JFG%K$PgipOv|A`=zpYcKIxhr`R#xY`m;n&gdKXdba=dTUv~#~@rR2egpV<7g8nqmen^RZ@&J -a3e~20GCsWwL)DdDwY2eTd_^{1=VKCk|cqk1VbjN?0=ur@KNKxDvlJR~zMkEQZZ+Qyf8+ -Whq_+37onFUMWr#-;WRMVI*U$`E`Gcy|Q6VHO@B{h&QOvAuIHT+dfF!)Npdp;CrEwtPs!5+hveJDBm@ -^(<9yyi*0hx_Hec;v-zuZ9i6UEYSXes`>J}41cP!<-ujakM85L!_Y6=W#?J>_KXfp`?*E=%;eudu>k+ -;7A0Q84_e~j!+VUSo?xX`j;r7JkAbgaQt|H}pz&KOMa!c74c`keeg~Ytdx&4yG(Nl?N3{d`TWJ^ITi) -f35oj4JoSezMy40eanfOqsis1@Bb;X4@0KC8c?6iF!mb{!3oAC9i((UUyAiLR&& -Fn*6=CVU}MhcR~c>ZCl0lNA?~33dD(qM^FWCDW=)VPD;-`>3&@BM;zhv2)w@nsa -3>)+J`E?mDZCAmFGB~nRSeKF3C<$U=~Jkb_RSxWRDWGIGCYH~d%jxK8bmHqwWXFCkHHo>ne&7t(x&G! -kqBo47Z=M?{t09?6UZ6~UZtj -ogl;~GU5+X;es0F{Jb$Md_+8qCtVa1JHYea5>kAje*Y!GhHL7lw9?s&ILd@?<>)`-qcF1eqRr1*GBC7kB=NdZ;(M<)ZSl38Ci;1JGFuW$fD+bM+OhWSM=NpDsI=Lo#s-!XvJ -u8*7VWxZGlHf<40oO8{Q2dqt9t7U_TXM*ea?(rT1!;=MMqbo#EPeC%uWkUp)A`6!} -8Nq0LKeAYJhdLsnVjKVkWZ(w};%{QPPU#`}ti -&8nBfoQG8((CcU=O7;f!DdEWRISJ>CT>HLxZH=O@};v)a0^Z%}886jbqpfMbVV4B{45cJR0?T}*}B>4 -!^e_^>gx{L8&L-MF+BmSqwg*@n0v7@)W4zG{JhdV~GW8p(#2l -=Q9|Jf)pL>|ec_#>IOU;SwD2|iVS^vDbCcm<`8qPrh|>gd67kpAfOV4uqeAF2DJdjApS3%}?j#K*P6V -;<)(Nn(|a<5)KSEtezvVzTb>!qfOelkO*%bHu;jCWwKrk~r+|Sfq9v<$d$<3x8(rUyDF02Y>Z}clP{^ -fgg~5)6p5N-+7=%{81TzKRO1IV3zxBPY>=pIRjPPT{!TYgZy4_xcouSAo<$Gvd5V7^Y=ay_)3g=3@{! -I%HwbHK*hnZWgNbKRSWHlI?y4Rw;l5~5~6P9Az|?Pv9I7C;~?N05c==pAmAGi`tRbPe?7!M;Gn;!c>s -JBJ*Xvtb@ -!!NNe%qjoG~B0&m}KO?~>MD=G(NoXeMk9TCRA-QRAxvV31xIC0$wtCuAl$8~J(7$NRqXv9w>y0N*CWw -OdglAFdzVQGH~g8?(TTyXa9Twg9qrrGD!5;YNdgUeNNgNkjZ%t9dIg4A$s_Ek=zboj(jBGiR4$rC -Zl@vc}DA>;A0Wpkn6jTrvk5Ymdkc!Mi)2eUa(Q9$#&k)Xedns?gLmU!LfE>xeDQu%l3-r$q>Lf`yg+~ -RwhxeUVdHR{;sVtJJTJw7xQNa@YF$h2|_1I*|VA`w*%yV3M!zccu{WHFrB_j(Lq$#!KJIf2}m_E)CrG -b58J4+W}1XKp+$+)l}P@O43@g2qV^T)VHGIS4#cKbb}!Uf}ZVa3MMcb$Ftg`&B^~5?i7SpfpJC?q}(p -Rxe1zFEc64_ag7Qcy@O$%w6dTtJ!=+CRX5y?dE(h#QeQpGLm4KArMyGuffe*=!#=J+?{8)m;L~%zMTv -F?Bss}s(?Rbm6dV6PG@qQPMJPr6l5^;1}YufKUcjUggcTE5T`ppbPWfJDcsoZoo92uBJ6dC{Uz;O;Cb -;KyaS&_?$!~L^aGmI?W;|K;o@-=t>sIlEf -{oq;#1kQI751GWUdw9pv2+NNv7YN%{4t2SN1QDF%Kfz471K3fSygfg%n-@7_S+MyHGP -qAbbpi!S6_P+xW{u%T$p$ud|9fmA#Fh0$mfN6en+s-S}zjwABp}bZwZw#!zts~{R5+2mZ%%wOwR($K* -hNC@F)xqkjpmL@sjc6V5y~{GI{k7+p9p=r#FsE{JE^7%19^W-GvOVJeH^10{9NG&8wkbrOQJL9V9>=l -@UH{g_VSqg8yrIr{e4Ny^Q{0GbM(L_s)Jw$M -6^YsT5)x+qe=ONzk3H~yI}?_wnCwssu`z|`mowrtcF$s{T3b1?-Hsm=f`c<8GvnMhET-3g@syl)ygN{ -F_^{Xl`e#yC6+pSv9K3cM2esbZzVFi-8s!h#Pwxo5Q78gBjYcQV^m!TVaiEcc`2H9*mVwaa!EHNgu~~ -v#?LR4w)MdqP3GR!*D7qGRpv2$0-D*3t%g&?Oe!yC?VLrJRxOhy#_2t<+dGYzVey)*+R)J`Mnirp!&d -VdTS=LH!B4>KL140SYN`$$B1icusoTpz=B8|RkDij-O)7`|=_uf$ExWhkoxUE+J(5m5>0Wp|;Ei{p;t -TfMSev`C*$?b`m-z>y!T=IduRg;Ag~t*-wZUzR72@4 --9r#d#;MWP6+q9Jnp(=@N0Hu$57YX!>UAUtBzX?l747weoX4+LOD -b$AAsjGaWXXLI{}y`3sAK(A{Y!1sqLMkuRKoNFrQ3x3AY!O>ff+YpiAsT&OQKo)X5zCLedG&|I`CPGE -b>!e24sZ`xl^Kzfc6R8PA6gHU2Q0qFv_DdhSixpBzi9^89NO|kP4-s;P9S73*Dm@96ZM3lvC~N=FpA{ -U7L{s$pxVugvdj&^{!C%z{DSe8SfT!%Wk7yPPUU)Pkn4C96ag{q)_>J_a_7B_br9jg;z47nZ5ihkID% -Jknl?#8{@!vBCM)~C6|D^VGzbpSUY^tvl5{?XV& -l1G*b-rXtmVLtJX0#gwE>VGtxG5YB9+0ERaP^jQXGZEn*c`776sE332s7u8kfzA*?B93A -e86U?F>7nRoC&H7D$dP}PoQ}EohW_;D9u6oJ==G}x3QKVi}X{&X<^_PU|I+9%=L -xW383!=4qsV!>1=8FqTUTYV$$C1L^#ABp~wp*|X{CvSh3apL$EQ@lZYmNMp~n4{a%Y31J#zf|pv&IUB;dJIRf|Ip9aEE3p!S;)6(gh<)D7V!GGNX;3mNCvek01Llag1SwqSFrkOMdz5$v -Z(#|N>~4A2F+yk%+dVJJ -=Q|$YhgFcy`-KnQ+_zzN$GjOJ)>U27WUB9kH|^SVXj>DK~2bYE0wM$>U>2kE1>)N_9QB{AsXwcRTEE` -Bs0+H1(3Csxi&l-cm}xYXF1(JCv{1j63UXQtK=#dc@H1Ux6Vb%qd7x2mlrW9qlj$NN5>8U>yCw2l=8# -8s2RmEBQ2I$+;^1FLEahBiacDqvYxYk -?#v_YrW-#c!}DR>#Z8~0YJtd?HLP`gWgJL#_q0M&M>Q1Edo%sRUe9&uW?n0alX(pGI9i~@S=h0f9zPI -^eP`Q%>M5L}4m6oMfabUC1cyEFb%1oMbk<|Q_7n@DW=acQqMS>%jtAl38nrv$@aT9BmKa8=f4cn!L6M -x4`5OIxLSf3?n}OH6t8J?{W8z~4qN>4lNl)GWE0lv^kiGkkUv!3M%sTjVR;yx?3{J1Q7Z=Da`5K9Zis -&B;1isg%|W$iEEcry<{V1{ynb@@!{jHTf``7% -#Hhntuu7Y{lwqKwXF&v}sN{`DY;@aFojwH&s10^#Dp=45A`(S|oCNy?VUEV{TiARwHWLPn!-Y|mYm+e -`;i+nJh@v?p@u_D04#gs5IxdB?UFZ?xSLO;st2)H -?#<*Q3?!21ValtVUmzfB>|DFlfHIS3Wz9~+1^W$BH~e}J&AXk{N8=RX^POHW8spt#?(z6?|w#+mSJkD -yl-dasyQ3Hn?D!0(g`eAo6HvXCqK3G(`?q*c`0L)ozAc<-2!?*uJT10d3{7>7s6hTGQlt1sc`aToPb) -HhlYRKe#*U_Ey>`dF*rOAvni|!ikwM-xZ3l?U=Xp+SGI6Hj^(V>?= -z+e-@K^)EK4LrAhgvu|I)8T5xT7)}Kl;35Q8eXd=hbn16J>@2?)}5MS=#(5(2hM19DO|GMVL6$jYJ?!Q69C=Qa9;+rRt&RptB2LRa -$=rEJt!NLO-0{;#yJWwI<@4&(X6#_qjg}ec&KfuCt(ay~FJuLik4ET3o;eiT)e+L#Gs1W#Du<%GhZ9k -tj27VhizSvV|pD%5$B6UeMyB|=>Tz=i?g(xyquHnfcgD0KUQ?oQQ*VvTx-VTQKZ*92tHp>Xk>&6eLiTw9~+JTOnB#16Y$Gyh4ak~xMvJP -Jb0%bz$@BDJXs8X;RUl-L&;$Ci6qZBSZFL><7Z=x!h*bXsWgk^N^qbw%eRpVT-N5=7YL*bwBb*`7zmw -gqo-2Luc0kr5PLHsCuAd3FKtks68zbg|JXQR?7xn9Dt1$ge~fAJG1PlF4S$hci*}p)Q**rs%eyT<((cHS_l}@nQRHB(Pq4#w96!MPeNh$0n|s3XE)&S7eYJYu-oK^;GTewDIfpSH?jx(d#sKmN6a66r -izZ(K0fGZb{9ayM^gT;+e3Ncm;P4#eWcVe^2CCEbAO^N=wJrVdvJJ4elbG@ik**_EdzKV=!hON_; -y#ihnLZ}fFzI1wm4?=7xH~ -8zR+hvWqA>V)*Lj#uO(#4zcZC``r_}JO%Q3MKp$qVLTt1`k7U#4z%ghz6VW{WBFq!j1ak+cF>0*q!FIIAE7xV1@C1gP -jhOCNpMf6+k3J&S7cddyib62e&swDC_^!B5pRnuTCuvH&KKxWvQjsdnOYhth+EV>IH~AM)G!L{-cR<` -Bp%_rfXZ%>vVT_u*>=1kI62bzq@C~^LGA|&{7Jt>@+Ff0trqdXUFB_Iv<1<90kaKLw&*P|tE#DgkO2m -t90}_;Tf6xfKpQ?I`_YC#UfapoKO8z@pTK~T3fIDN(Sxr=7Dz7(dCSXS5VZHWvx_P7L3Ff!y}d#6>e5 -9{=TK)GJH8_xS$@KSdxeV5+jhXP-JjqUG-nD~BDx#t5uRURnUMA3p0Y-z0XT5qD9^MOb -Ubwb6J7}4Z9?kQiN7lTPTG4U7l1>sq`n(PU1c;XRosyVVtrX5$R61$cce -*AfHc!Rl4-%!YEQ-&2GNBcZeGl}^Wr>xh(99rRaWx|K -%T}B?89M-P5_)-DagcPhwAO`1ln&&mdpG#MsDQkT(&(eKtPrn)*Xvtm(YUUE5V+G9-Qt{RomG{msx!l6x@IBQ97JcPH7n&}o ->ttd%Pbzb2RDrM#R;0hp|e?rIfw+RtGz(5@j#yE?SC`(X3K7xYq#(@SFz5izeL}xs_%eCq6djq=#0Jx -Nr?99H^`oj?M%nXT3_vdCypHpf@6#f}+#Oa+SBFI~R1$_@#!#j11pgkzw9)|SWAvfCX8foZL-iSrJPzw -(4;dKn}{T|4hI>Oja=ptfoy+GfMB6|k~{BBz&_O*#$^>A$W6CisQn@wcvW{FW5N-j%47e&;U8o!TN_+#spnhWYhgGRVIf^-3z&MBW^}*qig`Fn|5O5$12v_ -wp^whyMukP1pb16`;>UeOvlds1Ljkmh9pGMg<7cc~$tx8`vqhrP7{Han=wKdFM$K8jUZaTh7c>WNu(qC9Dw9Oy=&|sTPTfg#Kn*s -eHC=Cqo0`GOE3XE?YuSJu5Rg)YX?ZcS5_}TwpGM_6Tob4h9&3=jZYKdju1Z*gw=?i7fsvoXeUG{)cuZ -PZ@YEk1TsdKQi|)e}z^h-)75^OWe^ny8a0*^=vJQ@S*gW5Ww^^I&d67nfd<55Ifvc}eK8Ia>z(~uG@KA#@FuBNDwglsR3&~356L9=*d9d71Q|tKrj2{IRVUi>W0w!q^#W0NCmFPE6hEND5 -U>ZlsPrXgj9a6WTIKlRid&lQ@CU%SQp|?TFE>0ipX#2JY`P|zC+J`uZ_k?EnM!o=k`<%b~;^6ly?567 -JuI;fWUD3A}$`<&;zk=mxPugy;n}Ozz+vYR?{qI60@&TUvn&m0 -$uptYzJQaO*wHFPE;+{(#xa0y@lh4>X`DwTiBlbc#fHWe(sO*IPhEDdf5>P@vPj&wm)fi@_deT?kqs& -rSG$+DFO5F3eO6`562BWW~&O(!(HiDp_lUK90oEJ1z?PsK#w>N6epYh<25YbwiPg(|fKmpCh -^&4EDl$y^u`Kd1Ub|-oKdS43$q>?cv{Q_y#ci;m&|LFUUEJCr%GoZw2Eq+5dx_NKBY<^{rcpeico6o| -C5I2jEkBhs3dfCEV;3dVFPwd~nUjIiMmq3RjXB-LnmDip$?mXyl(S*sR6W0C^`pP|#BKX$Iy3MgY6C@ -rf}22G@8YQ9-M497<&N -#C_AY@x;rKcA)>6Cs!1Fe9=CvO9F1lS$)_e -xMH{k_Hb4H`d -X))yhs$G&vFyfZ5H~t9Uu05fw2I->ckzJn3`Pr-v*k7`|OVZZO*z==hA#K-^HcaTy$ECx#s}pLGOpJaXPF67MU}iSd2jg4GmLC2_=kVac8kVR>B}lwo6;e1QXVC>->VDPf?@+%-B6bhJj)iG`tZBg?IEBUzmu* -rq|ytdp%%BNAxu_~N~KG&N7+qG%hFk9zCqEQr=5r-W)HaD{DY^wJ)_RZ*hnf~xB176JKMZHVx#it(6s9d8C-GM}oZdpEkHDJ^<2HId`yOpCx(El+ -}n0eF6&!w1(nY9w$wJ2L*~1-m_4>}_w1ASCyMsJw&(|K`^|zsxc_1hg`pTuATWedI7Y!3v1@cd+aVl72^dFk{L=z@K=0bsTlkE;U -FqmI|4FI6pOT<=9!9?v@CjwXg3Z46NEG-k6y+`cj|$AjheQ{u?VIze6Z=?f5zP -nHyV=|EUDeENXc!0^^P}2u+WvoxTD{)jveP*KgFK}l7kpdLV!tx8>6?L&IUl~~AtI4o08y -7Xd=%bb&$DHk$9%usevw^TKeU}hWj#GTKT)nmscf$y2l9&%(Sf97!j%l$%h`IxC6Fy>lcerfMoX&zPfa)R#%~&rx1b$XOtItSx}V -d6cI|{B$`xbkf6vW~yqM`l6*?4;fQfK319MDps*14@+^qm7*6@@px$-vMOCM54a=71u9#o_halj7ak8 -Yp>9X#pbsO&)b+bWTy!v?y;U$f_%b==kMoAWhe_-&lI1_-zbz?pp2nGP?`&qgQl&^p8+iH)dNG#&~Yf&b7^*mf=;up3NgeH55J$nqTI%`A!{ -ovTPzQCHf&y5LPm(|G^amgLu#v)4kf2k_>b42{Nulg1S|8d2Sp)Y|`BuwJ;_8Wmi+i&m&rZkC@6bvE6 -o|S~?Pvc(-*G;(u~C!1uTFySw>p` -XBgt{Qv9pKXSY%syG;VjQ1p}g3kGwxOa%5x)kBSE3~kkJkw*K0qJ4v5ORK~_vG4PvkF=x(xJ*GEpVl{8=tn`{qvcviT*&?9 -A2>3tITQM$T3fP|M3|R@r($+vN)u-76XlxTA!2ZKNp0xx;{4_oVzo#e&z8PT&~@+du?|HSI4rUb_i2T -Hy$1qDjoYGGLhcims=k_MQ;2J}Rfb11sB9+D56B@l=~S!>x~}VTJaiMHjw5vLp@}&pWb|C5p&dde`ph -!7cl~eAnzDI#qgL>7lQ=>-hJwBxtjIl;R`gr3}= -XD{$RPLKFBKXMd=fo!ly=>BYfyiEW&X9*?vmT_TlSub^_|l4^q~jnyCNP{s??*khnrU<@OjTP}b%aZQ -Y7>q@>D@Z0xgS+LwWTzVHBU!04CkCsz=RTc%&zWz3clwaTnZFITHhmB$e_u8TPMs8cEtN1t*rq`E1*9 -TnS!ffz5ARBz~5S(Lyq?%JigGakEQP)s>Qaj}YYwCE(Qz=YF#A_$m;!>NOFWN+hjB5uI-?5EKc9Z9qw -)1gD)dpvRTb%5d73reHLpbF#FoCY!EbXQNe>u5f(7|H3zJU)k;31rKune!t^QMgFnr%qh1!GV~YI)-2 -#UPp1`l9D7g~+7W-i`ayb_b1m_XI%p6jwLV{(`Oo_gE8`*R3=3-oz&ap*w$$emKdD>wAd2ytBbG -T&yA4@ZY7`}w-0kiEGFXNyWJu0twJ0LgWp%16dLQnFE_dBD6;`RPG%SpgQ-tqamjv4@3j+Z6J`AP_7n -g>8X0lS<6G{zrVSnw(D-Bo|nmQW`FK{exzdU<*UZCEjJUyp0yt&|~YK^cn7B5O&oE`q -L^bW*4t)cL;U2ar)g=e*?hV9kTjZr{vi&u!=`{*EOr%yq$v!CGYn*OENjtV~|P8;FcbN -R%c*WW46yCZKSU)w?Si!nL57b5nG#CvugrS{-7jsA`Os-C;&|Kq(CaDUOa3Kc=_va-p{_6 -_)J7dnC2nL~Z13H=)Ddwz=3o@0YwasDoojq5q6H)sGcl_>(4ghv1|x;V1sJ|2K$}^#2rb -`dl{Y7sQD-&=F}saP3e0w)IT6AUw6GU|(aJ5@I)a+N(WO6{?N^H{M@u8cw;-hMkjJ?b@DRAl5yNgBmx -PGsNJF@s^uNT?+Ab0HZd|)YCBHjCHV4B?E-g@(I4~NZF|qG|2I$!SgMsFZ>mJCR;So8q@(h7YmBAP>( -A;2A$gOC0F!;^=Nhgt|K#O9KjvV59-B6ie-3GLwR996Vvj%@Ra_9DmAZf=Qy$zv`d>?(!>cim81l*Mh -rX?vNErO?52q#BC?gU$~slt6~nsJ#Dyk4JuOf@l?uyY{nTJ?8#7%I_(>Fk=yDx^^WbGEZRR|DQqMf7A -;W2k^^yw|5uYyWy-Vc706SEig+ox0TGeHfeS6UM^pcv+f`LXkyC8aIT||tP(+xfngjf!d=3J^v?C07j -p?I>cj#Oo-@>-t(`8xJdzect!JPB9`u9)(0s^y&mJ($dT<0+$A;D!AfQ^gM;4K>@S4qNg3poB*0 -0>pg=@3mU8TmJt-!%RanaH5(u3nF!s&d59GNkeoHi=pHT^FUr{Qo=%ECx(yj2iT?(PrAmFFlyE`LFs) -Y~1PlpA`ulLLndFD&Bj^Pz%8hvOcge|+f&m7bwwKu!Q -TzuzlXgE^71mwOZnakK$x;E&WPelZ8B7AwklY1+$sBrS&G%IXirFrBmMEuD+%AkM3>14L=@
qL5(O -Ajb97jjgDrSk1l=@R)g4BzpN*j*2IY^7~n1!7B&eU^XNFTqsTcvy|_}_D-*a4U%YYZ#V#--ydUMOWNn -{z#*LR5lv^^Gk7Eej=NrnBydEd{a(M-AE+ayAP^(IVWRtd32IT{<_xa0czjQ*K1ekTKiS%tE>%}$5wAWce*WNaATxF@;AXu>+)XXw(JKK^VsnwG0uu;C5YCy$$e8A#^6UruCp@2C>L7 --CoXId+x!_!U$L%H2l!pqM@#hGcuh`~i13oDg2kln#2+R{&Ht!gMouM^{+$k*9tg^#d|j1(OfttUFg4 -dd)&yLKL_QqsG$NCX>zxJC1Jn33KCnK+@J5+@kjs1u4p8%rXgjV#eHM4==^?t -Ye^XPn?*HyOjjJtqTU?-7V-CoR!iw;DzF5wpFeA=nc*$mba+^lhArV0+>mB6p{gIDA{L(fdT&MsRkqO -nMhL*!WHo?!0C&2hb_5YYO?JNcOHBHfeOPcn -_z<)!U_PYW89%<61xMVJD7JdC0NGzK<&+Kwx04dW8hPkBnYKYp>D4lO73l-(wQILr`h!to!%{i>ei+kNo(Kx=l)tKfC8n`h6qL&7SMdPD2Hx+?lBZr -$<#n4i^LOXt-uha#97W)LvyMt2H$ZYG(BEY)%Bs -LK+Jfj^1h8<-5T!0ws8O5T=z&V3K}#)|erW{{#5K{v-JM-Bo{vFYHtJLJ%6oA#B4cn80BgBPbf7$-S8 -uCXr9$zFqI^t(mgn00He^{~d7Sw&Cxqja>O>_*$gFc@4$(x!ET-Rkr#60lqH(Pr=vackpGev1qh`^va% -IOoncYxX5Z#jbuu6>}p{KKJf}k}q-jXZUJ2_^OzaeK;o>0yxc -_P#M3(oY0(tAC;O=%UsI1 -scuhJ7?-(NJY`p5~x?Xv{K^Lkb$I}X7nDxAmFE3khuzTj}oM>m6jd;u8af1I{>W6@8b^}BOFpz6=({e -V~qMv^o^Z%hj%F&N(<3#MTVM{ttDA&4Xh6h_ET4Na)G+IRY9F4&i`)97u${Vw$F#k6400|oCAUP^tAS -k%tOwzJ?jH`>U}#<^f>N0#mP;L8BOTN)~O&ogYVu%RRtZ7A~##G>E*t?;{aND}+S5WJg}6WG4Wu0uua -oNI5Oz~1ev?|zDnXKk+?#yi$h)Q)x=NK(kgu-*4n=I)#^6See_$K*6!zB^y~0_~>&mSLw@C0sl=>d>=0T+P%ttX>s -@>DgN!4#zQmk!*FS(8=Cobr0qT1kh@`1f01P5kD*(y>r2u?wQxLVUUAg~c{ButHClI3RC} -&RFVaEz-4l0v2x8_kTQ=y2yBbWv?@&Vfmv$Nb4>eQYVDONxfSNz8A+JXkEX2`k;DboI7_e5xx{MC)q> -Pq+YX--^%6cf9XsPdU%0fT}dtn)9m9iC>Phlgct09SlC6W6(v*63RlOv;9M4Gd{MGyZBmZ_Y6YYITtv -rOtHbqRwFMnm1%+z*m9@=)nZsE*pjNp&R7D9TQgE-o2F*Bbm3@Sr%SQYn$yTp`z;F#>6I!hdo^_6r7s -Gm?Dpl0Pf&c6NU4m0MA3LCNexIgkB2I;dDzQs#9$bt6e{!LfN;-$kM5t>Ook|3_%A=sRUjPh+48E^^R -%e{zNeKB~xke;6fB>+?gDvj*aeKGE$2UCb*8?lU9>nco}nixeBTe@X$*^xseE;^IG+2Kf`=?xrNuq6@ -MW{6_?lp9^Aqjs)waavv=_MCwFEO#lu38Sw^754fz=lbcbX4(p5K72jOXcK2IZ#>DB6mF9tl#%jJah% -`m36fF7^`R?V<@6?4PR?c~U78GgQUcOv#MP{ECBW*Mf`SE+6ncUWo1MH)kS%o?+< -V*)6oq9TM-bU{GX$|0aMzcTaMu^8!TVb5%5BJL?U9rgpZp#T`;zRoDkxs_GSt? -u>!^<>m^+47g-W!a?L&xOMm4J#qU;68@eX3CezmxS9F3!suEnSq?uLp*mZ6`cGC-Rlqm+@T7^le1*$U -$EHK!Mwj8-NotWl6|&bSf4MVgEJ0J*WZ&{)Oxx8!1b%R$~}9I!GM)%8QmfcXTyUQqF;Ot;T8d%Vso^j6Ca86 -!b%g_fcnwur8c&m5o1p$`5~ElHxW;(#XxfOFx3Ului%x)YIx<>6;V)P5MGCw_q$gnxkY{HTa~#+7rS`6nso5Z^CtvyK{Vy=Ui(auqHeeiOREE9g-)ox9Vf_FbK=5y1+kNaTk2C(ya>TM+WekBl$hSbT -q$`LYa)^SvedH_EdFfNn;bM{r&;MP_Bc3p7_9xIi9ge -^p`LJ=`DikY`I(+kyvjG3b&tZz&=DdKL>OEP!7K8+>z%+SvA$D$6uKwWdj(4uesUq|x;Uoi4Zg5f>>{ -uN*WmM`$CZ3~uSz9S*O6!-5Jph47TO6U6*OPIR1KNgF5ezucfMzP5$_o*n(YtG?$+zq;ZF#sm>C1R*4 -e;{--+AsxL%_ykRFf!_uT`1SxIA?R}(7Vy~uuEA)+ke8!mmT-*Cg# -w73k-Cr4#czQFY6Of2z9d0|ujblCEoA2M+GrvSvU*kMy+L+S%W1N@0&Dj2`w)eO02KfGVes?$jq$%po -U83$dDI2X|x1Su&pW6G{Z^3kI6CF5c7$ZLW!s|A8!NyZB_bUTGgt;yRI1)|+bP(Djt1nM-2yOxP^p8{ -1E*6{gCk4MtkeVasdnifjXaW6MI3vn@GDq-nLpUf#@rSrh!N%f_=SxK87vu=BG{TMXz_% -x3T|2*|~?omdENfu{p5nRp0>1I_q9NBiK5^eEE!L%KfB?_pj`q4-WAcD4+oJ#WyiWG-itDMl({gs+e{ -BWr6Pq?}cK8L1GI%Fc$C~$4JC3QHx_zACb>0Sb^<}t5#G{?w~0pbWPHDW0L{Nf+7a9@*t3vXCZ3Qfh&B%~Y;;$xa4mMp^xdq^=VRjKmzbfV-3 -KclH3-13zv-v-m_F^|c$x73P+vw#Er-2#-TyO)h4=mGHExjt8r0ZLzIbHw|mG@*E5nfPO|?-;KSLI83 -Mdm3sn(IP6hHl<8TUe!%CHwAwy&Guh(y@|f#<$*v2ebz-Ijy59pZSdR)VE9~t|wGI8e9YBe4h&piYmO -fn{a~|kWZ`~kYdKzR0$7yUjZn-W@8sqAP2htyFdp|S+Bi9RoZ&4DTMiwgK0ehnoU4EjNdHGiF1O8L*x -GzmnfezHv%$>Z;UB~-I)kE@`yLVOS17VEQ*I0@6seNpGKpFy48w#92H6HFclrab}jTpxSf;&~))A1e| -=bAUfhu5x=6^^V}JXqSisnK1Ox>CR&uP4=-hxO_(-0?6QA`>e8Y+V4Cjc&*MIg50p1@04xt|e59h{<7 -OU!5#t6u{h8Mk*F;I=Vfv%O%Ozn^>LYXV$C|4n#!%fW1~qa@rrU3XVuU6OmzHm2WvFC2mEL%76=bzjkAV#LVMv{s;`-hxls&C01+HaSu@zNj -t1XQgU;#^w_3&T2mq1Jp&l;!R6}6*ZEvI%<4Qv4mRDXXpI+k -z_kKm&@(q#0W(Z5P9z}xx!e|{U%;L)c#lCiU^Z#NNsLI)7QMmH-b!AuqkEciYL%F`gOcg<$4ov1@G2f -m2b|dC0WSI=SD^}y%?w1%>%K0^kwc{OQ?G7}Y!z|2I_mBDVrA^bHqu3hr6|8jp$uNNxfFXHoJ;T4tKv -1(fV5PCVvFJQS|QQ)mc~^rKd&Htv$$o6j?XyHkroc-zs;oH!V_5=d>eH({)f+tX6arv9BFSHj2-)<{pxaYkhdZ$i!u=7Fs-CGsB2fVix-lIYPCVs1 -cA$YsF-tn7qn#pL-yMVQ`d(rd`ys=?qm-pdMl*BM=X+FMF%wLosILGV)55_~(yhrOX(%4 -S;Y6EM3NqiR!Wbj8wFSW_w-#MmLFON5kjXqLFm#+$9ZP*;YDPVkzrMxJ*Jh;)d|eB5GZW3lb(c1`^vrIQy@8qFe}dYBW6)hEVOJ-Z -A7$W9;bvf8exmE7kh&%iqc=l&}}2jZHA}(xalR!CaAvxQkRs|T@k{up2!Cw=C~8i;)B-GvjYv@?LguZ -DPG}(_2YZXv*|j8-AyG|Dx=`uvjMIIlCzQYY8fXlc5Aob*D}BESX%fc_q7X02R?B -niMv&z%)u2PdqX36O&Gjj$o7V7QVH~9PVtJ3rE(2%HNKt@ka*;d%Yr>bnBl3z%bV8V?3LsU9LT4Vo0) -d5G5?_)(IVFPV3yVp1(o~+w}yPGAuYZi4mSHj;x!Kjk-B~`F-&3sVGq&FU$#|!+Jg0catk=Ih3F3K5Q -A8y+p`hjT?!9kkzBFopXAIxIT!eL^6~QJWadI^d_Nf%|G2$M#_-Hra+c$IVfz-I*bVl!$f1ixbBfk(1 -XMKM{*4Cz57ZfMtu*>q7kXFi7j*~hD;Whf`l#Hi%^#ScHn&AZ{&*bi -P$uZxaeWE5yXy8ueE$gqq6tNOH*O~{A%|DrA=6u3@h=v6$G*U4a_zNRB=&(X>q}PP6x?0XC~{+$Vhrh -Jbafo?+2~l3YIUdz5aBC6KVQ)~Ja&h{v|aOj?ru!TAqVWRYu~$dbMVTMU6s8_fm#yp33(W{?OUD!eqo#_^XM&(|mxS|OOvt&7l)p -d;=IG+&eJ{VMeb{fg*9>CQK!3o)&V3!pSE7LRsX!EQ{dA0bj*%$jmJOFSp(IFal{ -174#(fcG}1gLjXFkX`!&Dp -dS^gqrnbfLqiN62%2ZROWbZWXGHUv|_e6d2(q&HO_jR9I=Hx&DnMPCe8885U}9jla=)DGS%)GERYIRe -7jDbC9ISx^!Jm0N%NC7kFbw4CfX3^&){En66I}IcUiGFXcSHHO5&Y{e!c3fNI&t{|Apl~$m}Oe{lI5Y -oJL`aAP9;=VS1y(8!LvePo;n9Xm6t5hs4P}T^EIWr&&Pm&GqzKUneB?ykY$A`3gR_;iH1R(QTJXf4BJ -u(Vmfu-a2a}zO%{TZSI%86M9j)>%nbLQOUol=obWbKbzRa-XV1FTnp&Eb#50RiuWcH9N+or_8QyGM{k -zBy?pw1qux%2-kf(^VegcC>(XsRIHLAn@mpSqAb&?-`L~2yyL=E>MN6-hpUu5zpdRvhIqI$Fcud@CUgc5 -zxLeS%YWZl587k{iE`_{&-9iqMwLtZ2+37O~N;9jZ6oUY?pA5$Gzs5^%=JGO{NUae^OBCyy#4Umy6*Q297bxT -%4q@A}A+}E@Fi8gCvH~fhV}WYxYI}lVywBzex{vCu^Q9*$-R_?5KG*oUk*wSEP{B9#?p8u~(;y{=JY9 -4Rfa(Nj#&5>ctX!vhf@hJ1BMli9qIa88qaIH~ee^JYNUx9Re0Z(%k*qb`(DKlhAm#zYq%oeEV;>sGO_ -j!*-86nbCg)4YEQug`ynEomhs;zt9G$@1bS|%L_e?o|P@Z=_*MOH@!6Df3LD~_nP@KXzTvTYI2=@)WU -Zop6EDtg@N)_`9!9Of0k3HOWf(tu=rM12QBc?e_(%D!C%QaF2|Co0eQmHP(sknH%OBWco%Zqf)ZEjTs -^clxgBt5s~zVI*Lvs4%eQhI(TCX7bzLwekHDGEHCSyY+3Kk3B*e^r6}JQcQaxKn$ex)sh*cm~dakqYo -=B4cT{LXV8M;qE76aw=x%d?TAUeqM)1LS6E-J>SG9ensQ+eVtca>BD2G0aGCz0((5Ya%b$;s}O8^kxN -iGiJ=!g(tKX*88=_`Vy+?diJgxFe|bEP2d1>tdSemCZ)wu^iBPNgjTDcB -u!bJ&S|gpeETq(-(D=hy&3wz6cQMtE@1Vc}2ILE05ipE$K>XrS7wA>8(c{9at6P^2<><5pji;Ns&7g# -EwYYd0Dss=4H5m4>BKdba~bhbq|Qe9WC|d@b`l)ux23x)0M}mpDn0_of=X+lSD-XK~w?wtW?+-hJ5A?iss}#1VV9V)RSR6=L -7`l6OZFMD1JNE~g*wlX+pX=WkGKujj$pXtK9SqHn=~y@{K8?~?JJtishS^Q`qAy3?FyyX_ -UHOhM$`8#@cU!skGH?yJ@DV${(kqse{=i$-2=bsul(8_UfwSYrkX0OoQ=7Ep#_sGOk38e*6koX7F85aPn&_3QD9mo<(Em3?u7MA8E6W9Rc^L-4#o;`ocw -eYT1LkiI7*(!k6~SAH7kj>&6a_w5=8Qfd$q)iqxV?+GD<*{Ex<_-XAdFv-a?D)bn+cE~00-ESdRXSDa -W27fdN98v+UQFD#t@3kNm~gy_AXzr_Xk+aV-=8+oJT --an4RdqlE9;0CAAuMl##2qpGaf_L}#27nvj2FTts8NS;(DP(V|+!i9<2)W%kk?zf%@!P9(gZk}R9NS+ -Hd$$g3z@5C~1p?Yan%@Qs(Jm}ne-jo}8HGGE>hrj+Ds~~IPqW%cXpa0MX?QO1cUta}AFBV -jN=Ud&`9OCM+XLeC@%mB;7%fH92wGUTqOyi}E|8IY;d%FDe_WM}BKe!$Hc8kBeL*RF}_`5p1u<~ah~P=g-lgbp`O14E>5}>b>FM?yZ7>-Zol%3!a5>rWQ`}$>K>7ae-t|XMogT&=qUlJu -8mDYysgsF;7BrlYljxtp0pZBVe|)2fa>tsBTmlB2UIsU3FHaP>czzz;+(DE4neOr0bf#)`l*Shp} -j!cJ8ZK$8`B>|E*Eci -qs|Vme}KbiwQDq!~-p&%)%Nd|r4e^oIRZ!+{#o8x#o~D&uO|%I%oDAvz!L2jXRe>c}Px*taKRbV;}?d -HAj!xU%E)(m>2ss;n1$6;-#mV?g!L&&TqJ=)>;mz#lt=Im-l+_0j{@+q>0;P)l=6>kqkJa~B(Dx+7sP -Pqoi^&Up%ef3a)JHbIE8CHit;9z#R8Cvx?d*V%@7=kTn_#-HekBPgaA?fJ-8MHbECeKh2IWdqz^NCT;zzQp64aHL5M_9+x$}>S(l2ZyX`05kmXdVaX20goLMgE9PVk3&@qlFwOT~ -0~5h;ejpGuz1TMv(WiD7mZur_ -`>f6~6Zkn0&+kJ~sKeTlG69wKvecJ+8K8wk64U&s8PqPN{c8fpq`1S6A^}ZF^5eZ5s*ki@hs+Pe<)y+ -u?ozOuY-S)LydPRlwrCH!pqr5RkjE;d{z7-U9;S&F%yIJ*fFkrfny0S3$|XtwHhL(HEk>W%tUycZJ_( -oRkC=kgN`{W4lC;KePMbXLi3&6a5uE{x&$Y(PQ;HdMt;HHUk^TBp+hfC*<3Pw_6STymzhtXz%*DhWy{ -{U4JNTZ+ln#ZSOK2odnV1Np0?-sppe14L9eJ+phJs+Vd=dwox<_zT-UP -l&+%l|iZ)ixA=D}q{D0M~w`4cYvQ?fu(bdbmW(ZQ86r1-C`nbrh|R{-QX1P!{pSD?g0FE?f?+NQCyKCh%G3@1;XrHRN&_ei -U9N#!00JBdq*}m+ns};9*Xo|qhi4p3 -kQSpUNw6&JOb*95v>RdEBb%MeKWP3HyEdz~|NeFE`qwuM+TrVmXMO^`zkk&S(EZ|yAB1EHn1uFzUy7n -h7^QHWq7Vw+n^p*fCTSESDH26V7@-h|`V{|Qc&FPN*$v~j77w&Hbx^@Bm4l}5)?jL<%hB6cHT^uhv7N -H<>KNM75y;!=Z->C}?X`mLNV@w4yq)^?0syk3()Ms4*+hPUe_QZ?q`U0@E(R3s$@&e6X=u-g>`9cjy5 -fHQdopUH>_qg||0i~&MB^P7cbUXwNA3;F;rGlIneJ(tUH*~yZU67O;~$xP;Ge^>x3s91nq+vng7|dSf -?*?zk@vWK%2%fFCj%Gj*niipvVD@Bd<>f?vk-c?tw(FehWEL%CIgnR9b8y7MDSKK{prMf=()nuek?%V -&tF1Rhkin#_w&H_Cwz}Y8xDS`%Ocu4%OT-9fBR6E{dNr44{8GSQw1PbKU!IKU%%s2zh6x{zV^5B-P?< -7;HUTJY3$_#@AdcFL*5r>3|H#)?t1@XqtE33i#f -kXv=V>KRR654xA0x^PY&6s!!#>vIvZgug(JnX4t#m_<=3J}|1bz%eCu2y*Qv&j=GjwS9NE|)FFdV%%}2=(M3XGgQk{kzrl5PRqQBds7Haz~(YeNnpqLX)FQDn_U-t9& -lTDzL{xRCu%A-9lhS>1P2uq18K?ZzID3^Et;qz+R%ui>poCsiGPdMu)~QlfJt+0(YSFgsT1ITvJyNsF -9AX6`k@hCsxXefKFBp+4bC}P!5LMUx=Y*Oh*rOaj8{>NmQjg7C}0aw@Oe+UjgjnA?*4I6&|#hTZnR{E -|7kln1fl^xA|=9;7xi-y)e5mDfqsUL_M>(%6J(mv;>6`5ZjJ+lvl|Pk-G&Rh-oK|PM$!jD*2Rh;ln-A -O`i(x^L4$S=uu^HG9Vi_+@+YDRdKrY@|%IF8AJtFXZ)B=n-}xvKdz`;%2=pLKOg#m8n>FC8(~PCgPt%EI# -RDHhBcnx~Oq`#OL}&9|zAeeN@N>wNd?GFeh$-GKb?TK)YW}M&7ir^BNx&d+U2lwAb`9A0XQ!pdpWigNV{OcEW=UTKPjaf~2{lBzY4TGBw`Yn_jh$H@ZFhOkRB -YYwj0k3JYeJvic+-!C&IhlD;peA|ggTJNrx&@S|h>L=sTf>paA?L(Ctz*x%za=T1)s~pF@RgO6b(K30 -#O%o5#(}@g+!u1{#@^lrZaN0ah&=+<)p1QivxPJRC5KRPMao5(u#59?R7%H-zbekM-g1JauqTAi{#D% -!a?DL|K7AwV0#z9Pr_bIcwnPG13XtA`wU6V1^9CJ*h_0sT?@{eb8elpL8#SmKBQ!Lxu0 -uyYwLz@>TK*Nr=Y!oi)G+dsmWc7DSx@+=vxrDeU6#N-9Zu8l{(qPTt;3yM&){1Jbde$B -H#o?vdns*0pVmEc#=zE^;CItkzm&k3{rxMi!6TYLWoCatK7yk@`f7|sh+ -oUUmsFwSM|QV`(Jt*e%{jXtvCUJuNw=H&UuTm^0V&l8`S&0f{y5}{61#9H?6zZXZH*ECpYY~`vv@y8} -`}#0{+Pj`|N%J|Kx^!W~u=E%2i>=UxW1|uAs{u?~x**SA=`EPLQMzgiHMBm7KI*EF%C`4}9V>uOJ{+Z -B*Pgmkts{M2<>jJc=YoSYO>tr|HMa9}He(6&pLtosV4G^;jT0;2y3$+HYJgg^w|)FG$vaymmt4Xps|o(&|gHHaW+f+vlR_fU`v8$h>&A@DO~T%5qjE~vacbO_L --;H5}HKV}VM)vh9~11$7tG+GjU^%(R6Z{?IMoF5nZ*2T9M#)@?8f$T2_w$ -1GBxyBp2ieC9a6H`^aQ1MVUIaTKHh*zbG%cIxiiuh7Pl!x_cAFg`sta`PJGp -~?b@B?;#7=0P-VebgEE)t$2w!wF7zK8w^MDLQT}#RWM~ -H@<{}`?=yCHL3^!31sKwK|gibU>kLQ>JM!-OSm`1yR8Ptkbb}yn?*5|I!#Izv>B*f7TI2EFgVCdue=( --Ko`8F+29JcXK4bPYrm%Oc*!ymYljoXBRC(<4@}n9+{;f_->Il04`JE4fWS*_R6q*WKe{UXL)|&>%~e -4m(OC$q*Lv$ZNf>a!)-kihhlINQ3sVILz&y3h(c#3Iws=pX(vovs3Gnf`;pHc9VYs>Gso|uo7Kt$` -D)d_Cog3lg#n2X|`q9=r&8L+mnkbxTxG^|J59l(CXA^qL0G<1!$`9PZYq>&Gj)i#|t6n&Uf@%5@WEqT -n8nKK>~A0!s3QHjYdvo-s9+k{2LhT8%%>4hRc2zu}QP)f6*yOeNe%D^)nOM4p3CG(`<6HCJwA5qD -#PxW?PTz4V#`kPw{bN#qrRsD>`#mXf_3R#DLb`x{sZ?Q5z`%(}LBT0Pt1W&2Qh>pItypgW!Ui7ps-=In8%t26`Nm@;A+X^rN7Y}aiAxOdD7DAhafIY$3>_H<^h_rkzr@LR% -7lPxdD86%Kg%m08UY<4B^4v27ZpV{cT?W*@3cVMd+&aCBaMvOy-{ds9EUqZ!BE?~l{)y3)eoY_U&=uo -%xt(w5G5-!bZn%`#Fzuh?f88(pe`?MTZ2OPq`@x|B!AXPyQ5ZuJf&y`vz(E41a2$bAd;_=JFNpx*Pw{ -Q`PVDSbGkn*0QSau|8>&o-HyWgNl$a*Ft5m*Qpnr;Qskc&k_nSiYeb55k(^FKjcV4C5FnKQ|q;^kH=n -K-!cL%L)aQZ6~(LK48?c2M1V(PuHT~Y?^@EgbX+Q#&qo63qeT+a8GHVj?F`~ELX?7$j-x0=m}JvX(%^ -=$_Hout|YZGYRghCS~+zp_7jenpc^JyV|UVb&rOxK)SAH2zTr5f -H)g{*UvSUcT<>coAIC3{5uc4EL5wN7S?|2hx6Rfs6+P|t`Xv*+A3IBP@(a-2^sD}ChhIFZSNhASEa;2 -=Onz;HSq5&`}VTZACs9n$L1an9U%TKm`z|X#ZUtLM%1#6a6koAKZABNHnROfNBF5GCi`?c2(rsR1#lo3F%` -1j28U;X|%nqwNeVnVV;dhXN|!4oUhbim1RI_sSkosiWBG*X>c#e90&py)#)5&@wYcgw-VtHAVf0PFB{GZM -F*D(AW^Zk%811SPS34){u7)L1z2e+6^At;4II0}E+aX>zG7ThHP#k=W6v1`({=vI(#ALn>aQ|;{ioo( -NagT)q2KaIkB5e)VqL>Y2bj9ev%Kh(ELUGiAdXb1lpWFh)wO^|m2`OP_$b9iPfu1ktM$i|ygSH5P92bdxe -cG|QH(xV*L;=XLCAEoQYm0D&mu^u)gDP0Tc8x(O6*_HgO ->_q8N(Y8g>ueFW?UkarN4|yZ&!-snw@;eY8G65<>Cc&cOnDfJZTD0@hu?;qp_T*o9n%trbnRT?bUMKbrJ<8E*B6@U+R -mEWKoUn8R~5E#JwdDc-YAAcJQ<2#E_rycfHPKNGhK?Wcs_C!NZ&uYk$uvx^P6wZcPt$ERl80$9isw`m -sBR>jdfQq<945j(HO4!58XO}@7s0$vfGBbOs586`6yPZ{&cIyI1rN3?fQrXv{EyK(vK9fD{-wyapp0& -@ip*!tg#63L@T4S`oTsCn=z~xjq^uRtDR#xvnLWVS)kO7lR0Eh-aWSH9NU-EI9?9jV`PhuZa%`QVku|8EcqnSU)#f2JBOKIHHdPm52oP@E{rCruHG4qi9` -R1!0zl}w+rChye$BDC(KAv`Y1%Ad6BM(5}fZ2+-GH=&Y6M*iT3j2$gJ}1o$8^EL>J8{y<0OFaAUDJh+ -r;dC!9Drp@!5dubf-xRziUL^g2D~SHR*J0|yJG;3rC}9 -(Ij6b2@|d6{iw;`y`HV*5-wW&wYH>kC_$HDa}i6OZe -uhf7!M&6~9B&LS5nSb`DD}BEM;@OF0C?Otf_e?dco#}-q4rh(Tbmk!T);3rh+G{nQ)f4U>^t>8#?vU$ -GJ=&0HK>?Ym$?j?_Xk=kY0y+-@)!iFIitxc0R@F^G>zw2jNF7+eln>{?z1EaE$ -SXf-xNnbV6r^@LmRXI^|PY$H_!Q|;rwj;4>%2iHku6Yo`yKN+wDLYvODk)(5E7%?48>w@ZBVbM0d~>6 -K_v?=-tucU0byg-t67>n)*Biv~l0v9|w8Y7QgLwHpYySy9je{9`<%H+y=zdo}t-r)NVYO?r)p@Dg~6} -dlm^yb~v@oOC|fijZ?$vp6bcbwWR*J=}LADXcZ -smjQ1W8S})VD14&F{aP~$Ix$jmJ(~g3GZ=$6=wehELX$NR~#sbm*6fXU6?B -g=NYm5EwT?VjU$A5AeKd3;zTm}>AjQ)cP^y4?MJ-8$qlxapu(o^^d2Wgyu`I;YWg`Ec|+yDp0DH0f8g -xfQOugl!v63F -#t$Z^m-#^w;u3Mww9?z1{aJVN=UCvA!9P;v(oi-!AktT!9{nPN(7VsB$>mbJIAk;(P$g9=qrJ*y)>P# -8mCz_7QA<{~IPIQT&f%FuxK17F*pRaxmec}&Y8W9NDI4MfvC~ -s*vc0NZEd$^&tufK2@dwb4P$Q~;5FUDZxzB!k?J-yJk;X_Wn1?bsZAOEF&;>HhurQ6)zcMFO|zNfIal -ab2;S;BQHOynEk+f7@C}uy@_&@@-d8 -;Vl{*YeF=xApBWwMdyDGd5vYjoeN*4Db(5mj -BNYp*K_QeF3;*=yPht0;C66QlD)aX=_U%-b1sv5`EtS2X}!?H31@BY+Mh4I8pB3tYL*WYp&bW9?whzS -Uey6e@99y7+GKII8*gQ&RXSdMvU5`H*+zwN&(0>*6hqRGNZqSP81(QC4)3#~gYYR?&cJ*UhCU{m^#wg -udSk1PK=pzV6?DDSkmE)*g9{(sD9GwBw^FOZ=J+r+()5(H?o>f1;K440)+N^tiBDLh_bYyWEW%`Eq>}pDYe{hir3zt`hG%h)<3b)++lz1($j^4E+WMh8LZ`It -AL!^dPuBJ|-qx<&g}>=N4=x=+m)jGJ{#tDO-O~;DoyXgEPd8R}pmrYf5@mwNTE7$^Bkl6m*iZVi))-& -Cu0jKipJuUyvgXsP$tZ}hx!PxK;ec(z`*~E?x{W--^{%f$b+#!;2T7G(!1kW>ZV~XdZZ$xEWo -ejgeCoh3M>=eeL=97(?$L0BqP950SEjH_2BlfCkxIG?gUi&@JX2vH*iJ_fFcpq?8seIkiIV0qGY7Yk# -UqTo=-Ta+W!!D3Yr>XcG%ApW6>~GAu}bV}DSCx_{h_hE>@if4zDH|A7#B{gjn!`p>LyM%da~K7!kDYd -d5fnX1&PNV#MO*EO;O|+5W(qb3Cf)aMl; ->ES26Oo51~bSMXsxNO*M(I}YY~-)ZSEMEbzckV6ld^c&-Oz7XK*Xymh`0Ol?4 -6=FBBwD?cyRBSQ)#|1=Jd=j)G=qpquIgE1H{fe0BMcmOA66k1AP*2l_R1CsOK9I@B0H|I*3gaAx1*I9 -m0gXpykn`uHn%bnJkA0Jpe45$&@XYU;Ipw%k=lN0dGh8S3Kn({d#^S=rg|?Ds@e^p@QLyXz(Yl_&+n_ -2b}ud*?!2ylIVu9NCYNe0z(K4-5xJ6Ou;aO!=FK|g4``p_YOeWTblQ!jQvZwUAp^U?JigEo{YPiFaI2 -B6}t--@~&9lQ=#Mz%g{H~!>Apo#n`@kzfsPO^WoIa2sd=Lm#q9M0lS@#y;0r<&-T*9Y)4W^y3a+Ddro -3wlp7vIv3(c{?gzj82!d}9edzrSzDo|buiI5X@qfd~+ktEM#rj*Q1@F*;{AQ7_Gev4%#=Am-A*4O}g+TBt4uf22`dc!-Q(e2ye5lqg2?0%sfyYs8~wL@733vlExastowHo+}jU -hhJ^jl#Ws7{8jlcK#P}osEP+)a(s{zV-+D*D^Qvdj_h{fa&U>?ke9=P<{S5_Hmv6>N0`fxz2xenZWN{ -=fAp4;PdPJeZ&aRT9bLsMLTi11BRM8*}EbfMthP}PfsDkvZZH}CZH>#4PmJu%L5zYctzp!3I^*97+%k -brD^3H91Yd!j=sBe(whw?z{z7J0q8uySk21NZJ2^r&}kxQlZSkn?h5Z3YH&XhPT -C0^gROVoC7|nkj|!XW&IZWS><0Eo&|Hgq8D&PBrc@nHwImtREuut?wTO0A2>QAlYswqamrb0M)8o>k& -!Q^>Cbzor1SoxQFbBCz9uq2bgu$sTD8e($n?jg-;lbB&x))N#Sn8y;%@e0rXN_42CNJg2g&M#f*XMe^ -UES~?sXPj@D{&HxmOzroYI_KQnA;h?^zy=^iGl>-P*(G!(_c@UH`lOu0T&tc)7x?($aT4jB2I}d!O1T -z^HcuGqrJeQ6gR(ey^pTO6Km0{iZUKk@vOG$GXw%@*A0|g-#cT&+$hUysYjt8JRj}*^lUxJgsQ=+z4k -y=u@Y!JRkE{uYbg|&qpN4uFHnZpSJy&Q9A -sqpGjs#S*EMua&lY2hEsd3^>A*V(oH{+7aVAv{n&S++f7u5~xs~EMHNtU(2dblu? -3);gaS&;lCqct9&hDyigz*#nehGKVI#(W`84Uvt*zQ-3V4t<~7UcyD5~9I@KS0>0rPF}yH9%m$t@=e$ -r1Ogb(;(#Wl>lr4HoAO$|+G&ibYRvQZ>y6Oa;nR|Sbv95Bqx0{lL2L?^>))5=57(7P^ksRI1c)AyJ7= -&`czyN`+dETmv(otX&P4#(39FBrRNg1Q3b8-PaX4~UhW$VJ6aQ|{P+kyj&IBFvpHy$yqp%=+T>G -{&Xr{qg7bUd4Br!ZdCbP}Yy|VpfYs#F-$L9)qG<9+UM7ML3%4<%r -viSn|*Hnyif3ZTz9ZON^SQ1Zfw}V-+M=M{Yu)=MJEFwLK*h7($;o;R*lCBqam*M?|1TJ{RD#&`#LH@L -oN0L_QYpG!B9VY347d8y7sWD#(R?JWx6dG=7jN>$=*THe6zGt_drv}y`@qog -*Z2bOSU=V0n{G_)pY^>lGwmD35Pgu7(ADzM}%d^2xm8c2D|Tq{|AV1SIV7s`0_sw9sjebe~BUgZr -UF+75fey2%->55qs$hLV^?lK^vaLKJBTS?65C?Z>C|{jtIY$oaE&0&H!S&SJH+EV`5JkVCd(56X-4wA ->keLp>I2hB!8y}l09#La?``q$yHaNRy08Cj>Kc>(o&0UTB{qDcif{GSI(NPoEJt<$huKX=Wq(Ok$fEt -TvFeWqi_w1tB;B6@7VzQl@Ebr9*SYeePx)qZCqu^d_dq4^fhsou3F$8LGpKwY`~I4LzGU -E^Uh~hF4E)n;{`r!D-@oS1b0EMENf3!35;Lq&L|<6_USf@zK5vd8Y7ANnDvh`m?OYJM*BAG$q@t;J1| -Xa@u`2mKir^ku9b4-p2IEXePhE<2`}Tyxm9;X=uW}&3S24lYT_TU8U#Up{WOLMky!cR<5%eC9EcR7iY -1bhZHD^jUT2qGd4w}~r+;ISBzv!1u%O!J&Jh;Tm^Fw{|(LtJ%3cCR9Nhqr;M-fld5}Q5hl8|F5F*zdiN8j>`XH+8@dZ2@s_yf`V}jL`Vd -}35Xy`62c+!(|#>^yvHj1-8Xo5(0nI7_7-yB&hj^^oxkmOU}DdfWS@6B&xt*|5hHI?>0m5YzBS}R90G-tE!d;q9H8`E;e^q# -O`avFM=^XP4>7P>Aw%>=20uKB#*_D>48$=(f+bzM_`j-vcX#}7nHLz{v(4F+d!>;jkL_kl`IsSq1U`; -W1c}Z{fp`r%W!NAfx)_8J{gy1oRNctF9Ko`@7eeinl#P1=dOjtx~$2Pn!bwOP#2`P^lKF#bwWQV*uhI -i?1M+Ayq405zv)qeucKPjX!XrH$~qUOJ>!ZyE-WjseVc*ptUq|vTm+WK2}{d1uIpPct2%K!G9-$!=}g -bq~b7Phl=SC{XdQr~W>+dJ( -Jq|ke-x7ZW#+pBQAZzSh$p*Z*k;_16f>NY;k_B1+??5?I83D_PKyGz{PXV1HROBe0GxgODx^^$s7LyA -DqmwvWDdp;PEZCcgF)cq5yelJp^pgLqFd6ulTefcbGC2=5xc83j`t{hNuO4Q&O{|Oc&yD6sM|Z-FRDW$W&p;omV -13_E+}d}&g|S>-@a&p$T!-O+1W{gFXkK)V{@8`RyR~q(eYv#Zc?w%$_*~)LOv#mDfGn`Pcjq6e{w$@bQ0Y_^J(B}^$#v$5>GUrwPJ$;=r7Q1Y|ht4yF+p55anduf;$`x^|=z7eoh0>)p6LCQj3cv03ov -;ccT0p-VyY0k#8J-K2*3pqz|P#sKt5}-0mgAx;{GeGl=yD;pRNSh>Ij$$%Y4{&T&P)2X6<@iNu?wbpD -l25{16NhY}Krz<8jKEfBXw?)aw^JRjO4er*|kwB0(2SD^ME+40V->S=h{k3ePVLP`ToiAEi4jRg}UI8N_}AY~tSPdWvH@k;epzF!e9hK1E*cR9F)6(T7=&~Ejg7{bt?iZ{l -+=o3y|c~B+5>`pJ_^>F07^+9ExcW#54pA3chv+e3vR$@3m3uj!oTEHX#TdYaO4`z2n^ -4CX%JagirBdbz?w7(lkjGT)ox^x(Ue`PBVVc>My1=$aoo{(m!NW>X#t*D43^CfiiF6$fucdxvX;kkk8UX*vT$7;ak0UD%$na& -y$=0X?OS~;WE5KqWt$+bS%@=9P%4<^hjecs)YN6-s)f3OSbvyo=yKqC#Zl3wOj&IBI~+}qMz<<7917a -cZ8*0+kL6e2Sq@Ju;R`{n9t{$vmYnNp9+)S8a3}l3vCJI>g1RUaSH!x?zqJZ(aKOc8I3x4 -s*eSyOudomyhr#2#r07u&Ou7KDt7rpdLa?TlQm -YBr!T?vZmYOL{*iL3vBAo)h-Hpga-5As}Wh4I#E7e#O}KN;*LqyKEwV(h@pStuM|8A=s`7s>;lJCYKfH_Bf`nde6dBUYW43T?3P -JBQV*!kNll5lwyf`~VaTyvpYF96A&2Ah*#J}!>oBQM}G*0?*5m}>VG)=_7LJsn|HQvMb -9>!4W)g1)%5m0s`>B};`{e!`M`I-F~g5#(h!Ei8(ZHH9fBdy?q5m3BtoDYe}_N}gSP*{&kOXZeKVCx- -#d}Wo~X~>EjyBAcLhq*eY14uzwn+9Pd$c -MeVdMChjhg^8z3v3!X+^S9)&Nd2y5Am#k0o!OPMtKbCzECfyS3F*{(6eXCcP|!I`VJaQn4~DdQPU+WM -<*moGqg>lf_{w>_;lj3;;tWb0MA7}dtF_-@uXy8jSP%b>8=Av2EOl^>ID^mU_Cpzru~!*BR-n}Bg`FY -~>ca=$tMy7CUVFnvu|9r|kg`}G*`_24V#e(D~(JO8?0NaMSEEFYP!Z;f7U7`lbNIQpxT5l8zw%52h=4 -|OK|(1D+J9r!lM=(#egSK&+NY*lw&FSYzYtp>BV?EoyViRJHRmjy%cnndXsA^1-Q -eu{A)I>}2v6-Iq`8a436IMuMm-x3l -`$N{wPHew=$-6!{m*DTO -97Rb9t3cEAhC7VSh7KQj4yA^wMp38k7yzfJYIfq&4hQ@`&kA2AUQ6oZb0SS%B&A4^&fM`0StkHEa~$; -^cQnZ_|Gb@lV0_w@>5X)BvE{$#2|(e6h@LbfkDXL2M{B%4Hlv>Mtr&@x^dWz%p%|( -ZZ=Mdo)e^;Qu=)U2&h27owxA@!`717tjXR9dnd8 -mDHQmt4uHkJ!@31=JbQOLiuX>`Ta@2sA-}Z$EB4Jz;%y_bz1c2`hjx#OZRGaqUK$PVbU%;xSd1fYj|y -tnO`#is{@a=w;k?IF@SEz%;WL$ZW@#lV7#+O&Ov|`JIT!ZN#Eqjp8qoRhCr4dH(Czvqd~2Kc!Eomgps&Q-F}Uzk0t@_t!440}T5!#1u;ejXOPJle+OU)Ee$~`kI-fF-LX8Gt~z#MT_~u$#x>Sg4^~ye2>ZB3H5K#A*k+AA^dOlJk*Z$!wC$vI}~E(b;Eg0CE@9_r}i2A -A}}jxzdkcwm7Lcoh3JDrWZ9@U6UX+R1jYGKU(WWKLr11W{R?Dru@zlFbgbyNE~O9B-Gc$!7srgA#3@B -O8}8D9U=^-tF^2i`lU-&xnhx(~T^%6(dB)cxZ;bq@WQLIfp`Ua}w5&2M*~D4l)6GhB_>5qwdQ!3GB>z -pdytub+TcNhupqgZjfA$IVk#BZDj?kdgoSNSp$%d-7QUT#as(u$0KlUC#l`dg?iTKbHMAccx1;)p$>; -A^YG{(6bq3Bb4HvhSeVxVnBgH>js`)pgLKcDA@^-KQNZ-xq9z{Hde0htN0EuniN)Y=kBIi6Mg1d-)(8*QB;5++)T*WUn##VzMXuA*Cha{IK!5Cp^0)QLKb -I#1A9R<7mPd+;Qm-$s`*`-yDn2^}DYP4&_$7grW)vV!A**R)QrzXoM$OV`EVHhbSGTxLceW#JvCbbxB -Xl52-l?+o62+4g!<yq;vO3+5m(#2mD(pCSFg4}8i{yKy*>vxlJIgINgm`Iu|^7a -lL(Z4yaI5oBhEn+$NapMbB)i`DRCoI&ZpCJU9sx{U%OCW?HL!+5)61dT~`4fyv4HE(GRALJwHG2ZGUa_=M|zezV;Ere~`-+l+t*8h-$1TL1+6a#fg`{ePUCF>OEblekhq3B7G!WX$_UmnF#j`(z)Wp=snd^-W?REKlYt+&~! -7y-u8VhaRD1?!{`zg$Nvlqsv%$BoC8R~Q|p>M(_K5TH7oc$t{ufPv&GM!_|QL|oL}Ir4raI9@?RO1g3 -|ML;S~WlAoLV2N2-SRM@;AC8YMAszL3;}Kx$p1}~5vrC+AW2w7q<7AJkAFUDz1+NORcyG?xJN|D&DE{ -ApP`^CsR}hN-970hbf{+xlp%H|FFcL*z5=Jo!#}I;mP_Vgz}2H!JpDFUgx>lE3tfd5_ot)81j`O(pl1k -oj&5gMm9RLZDsWLlyg~P->^k8Szeq!27$V_`aZx3vcV+{!wq31-;$Gu${2}EhT058ofyT5kghQ6VldJ -5i5ZUt*kXK++VWG8+ro%6Zo{FC*W7`$#(x9KJ7mP{|S8B(G&0+@JZO=)35qF0$+@_oRoV=r}1#jy;}w -ur@pcKeAF-XGSc~7A$#xnS{?SnNpRP`n%Df|Uo}&WRS(#Q{xEd(V=Z1Cmpz9`bwuL;y;z!o@Vl<%3+C -Kdqmy3|M=0{-p>A>j)9o>SDH<`$fFBamYOL^MrT%wp>;sc7&iZSzN(|Iv20>)34{%<>PhO{AaW**`q@TUh()ydPp3NI^JAQ7DYUAPG|tiDD>)Vleh;4Exf=9e?{ -BY@929Z>4PvZ7)84H)h$mA^6U0W_#lF(-^jwv=F-$6@=_DWe*(bUKqR`-{+3^jW&eX;|}!JLZWZ4Dq; -&mzf#6*Q3s~>Gj~^n_cmXKzBP*QzCz;NjEhSCn?U!R>=qTbm&62e}YoT+CV* -n2K>@8%*UXGPxQ9q={aaeKgXd5X2X+4CCT_1V3ySblwpWAbiUHUAXHw(qwn`aKPFf6CeZ&Z>aVmi4!* -`pzI4_)8DRpA4cOSM2<-hm<(ReuXoLxJ+({9(dO~Upb6Q06QL|9OA)4zG&B5B_QYLG^K7)gI+#iJj&v -zDLgYKJyyw+5>YSbv~nF+Q^b&KNku@oB*uMtnEvUBq60(PBvuyOVM&h~Ehe#AcPYe0bk{vCpAq%Lvp+ -ryfza>WXbn|`0M_}Wt`l{y;L>c|q*=9AXVbfexT4hzl`b8jb5pq+3|)Io!v(E9WqsfJ;1Rqx_UQ#I%G -HG(@N8qWUE(q>_j2ds+T%E|x~j5mk*B>?J=sz;n{XyKEVV3AU$NT<8c7by0bm*_vO}xj2ekHDM_|D#? -RNPrU*%W-d_Jcq&7wTl4ZKRzkl2qB-rGjTg@t*I=U4%p*s1R9Q>6zRrNpcH%5B_u2$P6~Nd~qCq}O8F -9Z%ljlnSU$waA=4d1+&clgNl9cIjV}c(jhqOO^`N00qqVm8$Xw=SKS7c9XKlNqzx6kym<@-5wzsaPTUn2e59$Ni -MO6)mE9psLxp#E`#IMV~C!TanU}@lkq~$-tSn+3GqFKm3JV0|+SyGh8J7G)wHb7Vz4qpqh$H)Yz$@a2kF27C=!f>Fh9XA?$yelp}bvbo?nr=?Ur*@7r1wNDc;Im~rrwqm3U*V -;+%{IK)Q2`v}qe|PHsiY??WS-?56&$!MvL36HZmt%n(+-*P7lz36$hZfczCy_rsHe0WY6 -VHJ#%*3nTS&AG%bX9}Z=YZvhwZUn9MAme)WUgL(m5=p{g~u;h7Zs&Q%(f%dMpRea|Hq}8wKU6MddvHx -kh(4%?xA#>+}&rns_dAstcsha$@Rmck}JDH#?JSGJq=|G2|RXf)1;SUxDaw=I&N&LE_5`37T{Z=I(Mbt;I>;qh>sG7%r8NA*0&KrBq%D{J -Orf@5gcs@8{|o!k9At5Azgu)~5b>8brA4x9*z)w9MTPeI=3QY8?kDf&TyNaBtvP-7?@O^AC+?i -|Z6LEzU+|rK*y(e&OPljzuSj`&V7({&`(1ltr<~Nc@)DWLPSqr?SWNJrLbWoqzO}R4T?Jj%OJRMLQDg -NsMD^EHqO#J>2VjzF!L+XolYPNRH4vVyGTJ>nzf*jLa5E*QbFA>Ysk@JHduX_8Pel@WH-n~j*BjeWL+YQTWg?nD{*X@z{A!3f+lL|%? -BL1>X=5CY0Q6PWU4E!I|Cez0Bh?l921jjG$Yz1ssDxxDeWl^C>!4|*c>&oyL(UjA`=S*_HY}k;JjdFf -Ho(h^3wYP*cDd9mD7I&%#7Ev(AYr?oPa&%1+94=G?YYj@p@I6g#lM9vEJ;Oj*$uGqDq9b=XaERq`gwO -G98YKYsvxR)Mm&YyQc^FSM&%&nDO)_yiJb5BD>Wb2lr2*d4iGh8GRc}I+)xYHJ?qg{fJ -51e~j>Q9j9plq#jm6>?q==%7AXO~O{il`|IBRRQJcBN4&DGY1EcQ{`mxOF?QJLAe2%p*vxw>m+*8qHul0i4pxfUR!+Ln#!lp^2+SK&Yr1Q;3g;&XaKj{zCZk~qj|t4IrKMc5=-!5pjXB& -@?IO8ASN>r?yaRsN*=rc^=WV%s{pU<~jiJ8W7*QoXdj6=vo=#WekP%WA$ke$*zvz1n`pddggY;#>h8b -a0ou8L}#@UvO^-bRPN1%_a>fW(aYksL9@K>FZd@d7}v{V{8Z%_y?JaPwSY0ouauH9J>y2*>co|B5!ou -%!=2qnhHUvsY|{uJ4JnDCD8?ksJlHlPb1e816|yM22e7S<+&F`1PGN+Z8^ypbzT$g+|jgJXr{WXbA{h -WCNhR}$j&%LS@KdfwoOyGm{-8#h4~ytE8&yU&ano2M~OCaYkD~jl{=KVaZTcAcjcg3rY3P?#vM=|^F% -MLy33NNz+D)7;VL>vV3fBD9U|4j;LkFAA&Ww89Pji1H}v9hJr_~>OBfs`2(AhnF?yhHOc4a8lVcI~>5 -6v~SK<1~k^J3d3=_Wi=QJ>uvf<#iGRW>Bc4B3Nk-wT?{(N``IxdZ>2h93bD;1ky_M-M`?dx3})n#YNQ -0Sni#B@!Sn8v43-*hIrQrFW%SrpKN2@g7>SRMh#wS!K*?>UVUIWU(H6Nd5ur6P=tgVCSlCD>y-#+BmV10TD1;A^0)P(Es|F(7|+lpdKbk0}g-1VM^9)=(&p!A(GLpr6EUikV4WM;k0TY0N -nHH3vg=yIPOCnEMH_{)RqQcDG6pY#QHDcUy@!onk?yBz0xYbRF0l6r$!n)gq;VL_1HrdWh_+THW_qbW -N#aXc!A2A_2qB`J1b-UcJvl#|v}Q7N@?ni7&co|*+v^D?Ng1Sat}0?FxHVV@WE7+u4%dum8Wns2VmkC ->pTeB8v?qjQZRE`ew_C8^aHw(!CVZSY;KMO6iL9qGtU;wJe}_wO8LO4*;X#1}nPKU9SEIES=4$+xU3l -GGpnI)PldTVH(P5C7R_&NhD6woy=h;r!13Voq%r73~-Ezs!HXHNLHve=@!Bfkgh>_x?^KKi>DJeLn&q -_`)0sgd!;t#%UC%F>+N@g)xLiX&lf9Mo_=3V|=BJ=xTUJtdnDF1BMT;gbv%BJ@af2~4<@TyBMOQaBrY)xwv5ItRJw*I52(DA4y<{%I(`dHj7A%4ZdnZ%!pV -bQX!`w5$U|foBS$Wpgw&>JZD-JyDaaygr^qTzS@nAuLviM~uzTiIghUK@MC=S_O2RD8Gfl!NsyvlSP9 -y>+;FUHwr%RFbTlr5J^tFU!XjWUk|E!YpgwzIn}{xM^NV!`lwp>sRW4#PF|^JVcN{kIHKSN7GiTpLHv -=veBuTCNd<-B91|({+Mt7% -Xs`RKj8x^f4KY4wj>k@Pzu0Heve=&);Dh`s -rlK5`Q-&=vPb5-w6r&7}H+~>BoLS=uiAijLVH6yZK(ZHI>=dORoFIc;8|t(Fvqbv)Vq$=l9Xhi54DN -91&ECv2hAVSu?*J#JokNX)hu(ZegPE&}&E;dr_0?k(Sd#{#taa?US#<1ViNIH-_z#4;A$jQ|^_l4ibNw4k -At2IXt5$Y{ohC7Vq9_1KTq$doe|tZHKup -FSjp-20O(wdZ0nIA4kcl^Xnu+PC-vOd-W<_E4ej0p!I|QLW0hc&0Cq?q_FUcJzMRG>|qNRY#eT^4h`r -8&k2WcC&9xfom-MyHqi+h5pD3iAd^x*$Sbp?rs6@q?~?&Gg|lGH`i?T;2h9_Z)rLrCIb!$o#M>WsNPJ -7<<=y)YLj!ZMN`UpIQsTFxS-&rew)>SKihldJH>Rw6W6-uC#y_91&Ri}Xvme;m=^R56@>fHv3%}tR6q -83gB1>tPx^QSjmY+DUhc_$MJI5gRU9c1)??wv0r+a(2CP##ysg}8vN}h|j=>pzruP+X}DOg<3S4=c1t -5Ln=mMMp!f@ZlX{csY>Km;&a8UT&3I?r$W7bte=^Q66y^8+!ixDgQ8P$+#Q&yjr6kxLqOm|{SR -pJLTB00n>?aEQ^gmnI%*p0R5c)P@uhGAx=xa;T}pZK~CW5)+((+cK|1r?|AvENKIWAJ2ES&rY!`jIXo -}+}Ar3-?w*UlSp}4>rY1k<@NVdLSkmpRiD8!FNW|)W0_-7?V=zK>P{v6xQEGYZrl81 -4POJj*sdz+j}B(BZNh<#HG1ltge??RXa!aL#vCiu48b};RdIbH3A{%pxmEqS!3wV9h$- -2K#I?>^ylyg?nZn9puuEliQ4nt@D;RuGk=Dd4Y+Df^q(b%Etn8U#esskqVB$NPEedQ7+O3#u69gV+ri -u#KaeiEV?qsuyGnq#S`8h6g{Dj$uQ9difH0gpUWzZM!qlv7Rm_3(y>C<*nk1F2Y4ZT9e^OFv7@JuIJM -GACScV0Z>Z=1QY-O00;m`Rt8htO%QRh1ONbJ3jhEc0001RX>c!Jc4cm4Z*nhVWpZ?BW@#^DZ*pZWaCv -=J!EWO=5WO4lKMa(^I)$xE4=onhLy!h&fMVC!254_uS{&I-C{iVPs8( -qQfrybN*Ds%h@eQ0*S@|*Q)y()@gy{gd#)u^&NuUG$$4=+EQl!w;JUL!aRy)z!d2|*bjgw`S`Ye3sN{ -;&D?849U=n(^>h{*MKM!QQu!xnC>Q}0vynnugV3oCzN=1j9k|{YB8GCxc*214ma;<$hhAw3Xr7g`rlmw -6Sm-^Lu%}q~+-}F$@@r;hx+A0URnnpdV*|Wc_XKpTWjA*+C|AwyKRH+*w-`|vk$@OflCzu(_H{5~$krRCJFV -30cf_gWoKfrt<2oH}USk_M=72rnX5U!oRgpeUTE11o^*&T_kiQ-(WM2DIpjVwdLpoXC*G -Nj@llChG*fFAgan~Ev;M>=-o9g(zM9pysRFTgv&RR;X=J0g?Tz}qdhH%>SljGFy!HEd!lKM*9s$!L%v -XJ6sGT(o4~g)g9AIn0CzHzJys+&gqY(+#nOrFn<84_Ye-i)0vA*@MT8&KGsd{+dOkTvd*L$h267-|V< -nT4@hlZfnDZF)xRd^V=AxBwZ{~1AmbPteR4Hf5?qm>oMo_2$nLG(7jI -8t7$DtuL;s>tLN(_!q+cI6Ch4*nN{&_w--lOb`REZH&f7~M8jVNNXd1=fO0dJdMekoHZTnKEt(UMI65 -#}V$pVyLawSkoBb>iKTo+u1q7X*g`SQ)@}XrVrOE9H#C&_B|WKY482eaCgpGH%{fDK^y9kgQ%Y(Rm1e-S-d}o6Df -l@_oNUHom2Fdiu!Z;OJq^=A>uKkEwyy|FkusPs1?1jQHG>5KRENZ!P~w;LsONtn9JUywZQK-nt#?gw|?#%ZbEI3s?K;k(ul&ANsqJ6PL7Za -fqkIuO)}YGx=ZD#zx28MzuDZx&l^5a(g7n{++@O+^qluTT4grP4~@hB_@ew_I^LCzPt_`xn{T0P>(zf -yO9KQH0000807zB_Q{`sUSbzio02&Pd03QGV0B~t=FJE?LZe(wAFJow7a%5$6FJE72ZfSI1UoLQY?N( -cF;zksHUupltQSxArh#R(AX-kw!Bn!bRmxxQFD2mL0k72rI#+@05pw<5Op78|}AWbUurBa6%d**!Kxq -WBw>FMzWSFIbb4_)uN)gQIssyn#;4PLQ5{rKS&#!Idt;xon62Iw(Vh@fR?)=c3AY-9p+CO~1pwNZSQ7 -zA#BiQp%xEWt_!Jlxp5LTROBqv -YOQNJ?*F1_~hLC6slc;7X$QbUtac3|YL$iMmcg^9j*&p9ukg-`xI>jfLq0^EctM#_fA#tuG)iXfDc%+N`@2 -Sz6f{X%KvL~d5&yhb-hz#a3-u$y>Mp7)&qzO}&^#XVZLYf+^6(<=PdDv!4Q+B!ro|wBe_*^F|CcZ_~i -4o!3JS6URB&DjsmDI+X_L>%a{;6I+Kdb+IUI&#Fgp*pV^8FbaR~9#JC58>C|rM>C{d|_F{);Go9{*nu&~NmX1kT`<)LCLdp2%}80-@$G>HLfDSUY(ESuKhENm7LMP8Q&4KKVLGX(fHY!-m3zIksY`TvYAT -}^1v#sQiWejlAhQ1dXt_%?hIR_&Y=6XaoCi?k686I2>LJ4^Oh{jMTm*8h%j- -O)vKmDeSc!R~!P%EDpMSCWu4$gw+I~G9qr+#TSV4HENvu4iPmWZchxSBwn1f4=R7TrxhKj?rOg%gMld -(flHfzbWzvjYE-Ms=hQtT}O<>}vfeZSYdwGFKt23Pz0ae8a*QXOeWE=`xkF^Zt_{kSuy=#$fccf{tDv -LwJOa(xXOF|kP4Vh36596|i3zPRcl6qP(9I}YdjcU$(~q3J`1<~}#9!8hDoMr<_;SYD0>oMjIWyO}(0 -uY#QCVcW&bnr8biP)h>@6aWAK2mnY{22;Ixy5{FO005YK0018V003}la4%nWWo~3|axY_OVRB?;bT49 -QXEkPWWpOTWd6k`Ak7d=7rtdBJKWxbwjgb=A>w9l|+!A1Lmj(k<6l!^HP*IhbR2P+WR$)Z{`ibX>o%T -qLr5P@gtdr-gy*^?^yz$1n*7?nEe)+%c!;k;;2-rb^`Z@0Ji+ZR8-{qFwt-{&DF?bY2k56>TdX8yi?xV_!p+<*J_r|91Ax1a -BS++I9?y*=E%ynB;RhzWVSJ%9c3{rd+R`2POo-M2sU+K;ba#;EA~+uMil-#kv{pFaC)`}For^mqHy?d -#iz7}FO&e)H4!Vp$#@Kl$E2nTLN2_vLo?+J?W2Rfu1r$r$WUVP)Glx7&|zZomEU -)eTL=o40>^^6Xzf|LWQH!DoNj{_TUOPe1tV*ggAsfBEry+xF${?c+o{rN1 -=Sf1l`Yqs{N{V?JNrzI}f8>doW${}K!RCOY}*<@Vk4zum@yzqq{%1KXa*w)x@b|G&k2b^rRW4mv*bk7 -@n=cK7Y}`u^?B_S3^%m{FMGe_3Xl`NvA%#4dR8-pw{jyzBYve}5G#@nwAele=%D?N46a-#^@JAKt%t% -Ul2a0UzFLDf_#n?Pc4(`jVIa*?-%|pZ)Rw(c8of(e{UTe;sU)|M>Ct^^364=ij`t!(p$_p5OiS{Plki -{}Vgo`9t*ci--H~?-@kw%^zRCxO>Gr|HpT4-~RBs_uv2Nr=Q-tefi^iZ-4sTQQrSPKJ)PYzg#O(>alI -_zWXoR{$8(j7GA4kKE5{AF??;5`uN)F*K1|3{d(;<+tK~(-jD0GbB&{2k9qR)7Vq+C=5+KalfM1ovBC -F$Ti(5XeP{baeJ_2})9CE|_rLJL*YU~d)BC?2eJ}6EZ}0qJf3NK0afAK*L-@>JeB$$O*c^5IH>@oCb^ -kgx@SC@6vhRO<@!j@axILXq_@bwOe9C%!_~cLH>t}!Y;>kxJeERhtpM3f3>5~t?diLb=&%S>8LHsYrF -Bs-;>(8J5@#ClQj^FAT^~24w{jC6{J4p~p7G^B?Uy2NwaQF?r -;wVPH~{1(d}|6K8it@oQSZT?!~qi2sFi-^PB^>B- -jP(Y2Owvo-!X≥tCzf;aob8~;{5Fo8XmV#LXZ*F*Y`7mx#cc7qe=PC*R-#YSey(V^)_8A;-o+E!P3 -`=(AHF%dGGgA^eiq)>nUAaC8HOA4$Dz -k=^bO7F=b~=SuAqNhAWF#R=mESVL{GpVE}tfYB{E9mSTtpD-(ThF`jMFi^BAbSb^FW!#lM(rYEe&hG#5ZOfOaumReU#U}-Ta+ngFn4B -(`9`x(s*#vZE|HrE*$#x%lk3m=OPIDj;_!j3Po?=jLIZAMFB1(*?=I}9ZHgyHTCrC>`f9uOjO&W+bzv)@n!~4?cT8Ay0dtT-gWy# -CuVdkW{hFST9y)X9Lux#6mRKnH74(fMvhqI*uOZDSo5&-nGM%iycjzT*O=K=W7su5P_XS-e7a3@)4dg -2I{sSdVwhn38r^2K8UsCw`#;UC_E@|aPM9#8Ha^gpyI8Ff3l&||<{RtIYcajiS#~o$o@~Uhbv}j(#>2 -{iqov^yix-}w(QtHZotW^9N3-c-_r-z^w)Al9mFM(^*NEQ^I$PL7PU8{w-Z4QNUhKTi-dy;qla(zK`; -0Y;hhfYoLkx3iOmu7{>^)wKcWC|xD;Pr=(QqvM)$kFE7w;f$xTA1K=ix@wM@LJs`j|`Mqc{xqWn+WQ$ -*SUACYJB^sWqpf?JVAmF2*2OUWV9|Od9B6bMaMK@0tLRR#}H$A4H^0X_8`p>?xF(+vrUx -MZEn$l^CX~DLtyT_HYz=CyiQn-4I3_@Ix~7AU8z%vcN}>8PMgcO#BZa!L5w+JLi@F)W5mv}>mI9cteC -bDj|hW^ZkO;M;fe=+r(w*s5OhaON_Z#YSS(}wv+=`+T@3@)nCf^S9XqO?2>-{U`+;AW#A{;v!gZ{Jhp -}nGq?weH;I8kAo~rh)(;Se{Lbku272v2GJ%WL2B~hwvXE -B!&`WjJ_9~l~9WKf_I@|0ZWUSZG@rNpoKtT(BE;T*qlhF+h%m2O`RnHi2#iWS2xmN8TA@83}6YPCZMs -h^T4IxBBw5abtfVNnJ_XOJ!aYQ75JaZ!-57&M#o|nPW%@enNDPYK6DetB0K -~xvNx>vu+70Aa!YprON3x7i1@Y+wi;f%IpwU|05stI1Ak!Z?3{roS+rgzUO0LY-boCQ<~9T@6?8W6WQ -BEK)7E2jGeT4NUL0erU^GVzkJW10#~F(k7!lLxggZleOYAlPER9Zd+((4M#*P3>N4GnhJDx)b7FPfzS -IkzY$I%>kEDX0WjnNC8z}4ff+jLuW`w55wk9H;+(`XaGFd9ROFIvb5s~VCn4qSS_+9y@45yfsbg@>2bx2wy>q>BEWgq=J -0p~K5$l`WyUyiDkgv>OokZ)Qmmn~9eheR0SsoB6qfcZM#Pid#Pl|MK}r!1iyeti8M&qBFjW}#&i86$_ -+tP|p^M~2gP0hvVV5G`B;*GK@Q6%-s~CpKb<*SoABnJrmWP -M;KA7V2wm%0TfASR|k5u+|mbtWy6&hk(dx`Ev<^x(gN^_#^H5pBxXqXLjw;{g)A<-Q*>ospzvre9smI -oj^7yAB0a__o0^kQ2mUgDBGDydI~mU!qP^$R>Vr!Z0Kqbz-v;6vS(oAfkEMZN#uj%p(0LtC{P7{A>33lwkpw%LwjP+@5=gP%f5F}EixL6Z^I0J%VH{lW@JAzfW!=onpbjj%CPjwdmC}9vEOu{>=NkH0%(XfF|Csw(U}y<1d+C;O6o#@3*@19V=sa>qs -I+kS9J8?Id99mjl3NiQ&EJ=;a5sO(x~svta;BbcgMG;-*eEli4nx+O?D|7N4Y{>XVv83 -PytK*+_@Ny}Iz`KO-9ku*9c`uZ@`{btC;K0u~%j{3tXmgNEyYM`&_>SX$Z5CKkT|^vc!aVV)QLjI@)8 -4qpPK=~V{MNdYcPj^H+?)A187VvN@xtXz_T~H*kr5^JUft -Y!wJQF;IaCd4Fg!h_+ois*9-hjKn3Umc3ErAHmL$5p5!o{w}2ty6aL_z=CaZ(!wo`uAB%UM47TfpByq -54CmMIwg-)mO%_)OsF*dWHuncu2&VkA8xp)P@Qiz!qLNT@_K@Q)`&Tl-i8;b_67;<&MLl#)lM(R@V#} -ydcmh54M|9BHIZzFHkogFgCQ&x|(llShs^q7xedVmz$Tp)tnjrj1 -HTqmr0bq$w@ltHHL0AuW&OV|Tv+uG8-~zIl$g!A3yfvYXazll*+${J29omJ2$RG%&SWBx88-S35h1CO -QkZ)`hZ5l-TFg`(hhY#8DIv729>oqe+HY{K%l1&Cl=4pXP$=^2X8`Inq_r6R8rR4}X!L@a1!&@;nh7!VL#^$aV*pF(z -HVN_qZdR9p1r{cjAAYh58!LV)gtm|{*`Y5fRqwL}Q)b=(n%x|8WQ -d_^(QwJJDQE?xt$6yrVCTfn%(3>=3Qo=h4JAb?Mj#y@uIWc-!tREK>W#XXSyNq^h`ECpXP;OIO2)AsRA$uhNYT-Qkg5(9E#f<8jjRB61z -#8ViFnal?_j0US|*hxN#a@=mgM(a3Gb$f5`t{Y;3UzJfx$oY83NCtQWUgPP -;wa5ui9}TFD}ucX7Yy_JCNKOCPyGnt%l&H>Lu_2AqQMDJ>~oQoJhH%K(OZ5NtjrT+qVRg-8^73h!&ExXwLtKLm2J3~`Xh6Q2?;xk(EZDd1O|J-S0IUlAk0O!TL -tHWDJL?`Jb~hU+AOlFT%4CiSK^YY;U(sb)3PWs`WlS; -k%oaJVR8$R$r4<7ZLTBzvXcA1l3F}Y!liVO3z|vTN0oEz*T(Dasjuvq1aKqP3J884)F|o)=q*=K4EK@ -VaaZQB`%WyMUKAzfw$)X7pTWvUE3f7cmD3AnL(*m4XlX>zAfG-e-hR5#Co4S-qM0d41KmrmQN~BDqiq -6iVVC5!-Q-%akhu=M{vi3B$VM(aC?lKxs{!}^&1X{H$yA`WBI1KF_5M}9`G^Y|(n!9N?wq7uHG>frhv -H1SBJE?@6DYhqTTJn3O9|Vv1E8cBcLC_%ltgFu)T~25KSZWvIk>cTEV}mmRu))(%kK2UaDiAJ>x!=5h0B{s)k%b;d6fyc;4Fgy@DwDojE|o{X*)4p))Kc-*RC -#NWV<$*aA87h$fMyJZst=jvUap2^SY+2JkqrqnvgKHOkUH4Sk~C&8ic~3%tpaxu(Uh~ArbxobVdl=8Q -+kYicBLKTHsNomX$|Xf4K~FR>>wfEEX56X6OU**JEIo?<+vJ74GYeJQc-gwpCUFK8z0zYZlS`fwIbPr -2}=O8)so9^#wT#jOk6PmEQNAuI~2f{jLFl2auc+ -C=Omy&f-@frdSAS+6qLG&C|6nDBCu7;P~X7L>Y5zsDtYc;>$*(xUqBx8rz?kIs8?m;Iqm7q;v)IU_AI2bQ(O&Pvp)!1S|+DD*B3Up^-SM{1>H7q3l)d<8>2h|t62z_EV%UM!VQpiFfrYG;dd<#r6IGl1pzv>|2y+E6F`Fdk1h) -*c1EW#i1&tNy=eZy-E?6AXAZw--!D!0ipQdo~4+2hlaP*c7K$+%8?Y{ND}!yqX*)JnHE_IjDA@(2#R*`kgq+wV#;p@l-$wuiy9_aL2aJfNHHxVXif6E2D&^y9DrZGvUNP^KVIduByO1PRa)syP -Yj9^8Nmu7+8GxeTF8v7}Qy_-R9jsg5FI;iTun^^&o>Z?<#IjJjFkS;byjXiXVcS^CDmlBdi$I5^frA? -#r$P-278JY3jB&9>tQH2<Eu7p}*$Xi6ilhEsG~)#l -gv*jnS8`;JrhX8+~gn<))Wd<6U&VP3LE;tO_pPm^}*Y(9Ew$Zr-y(9D#g^>{x}sfEYKqHDN+D(Ee*IFmxUs_3?0=^eFZ1<+E9qh!Dbh#P9B>2Z_dhW@Boh@ON7g?)Af$T^bct%`2jAt -NCvXGMfkkAT`eXc?4@trU$6V^-U7K>p*H23dYB>Kl%$VMVt9o^3HYwFhk4j_RjZYx*vuk|*ll^6pN+A -!?AYA=03uh){WE!vL1HbUnLU)z)$9Mw?7U@ywLXz)#&ph7PW~IGhR-@Nk$$V@x)zh6M$De1LVM=268Z -r=-5s95y2R5>B}dvws{0&}W#Jr~;~q26FKf-S%qXSLGbw0=BKv?c$~-FDVGm1{quQU7LXqL-8Xe(sVY -;|1Wb>blbshg$+jDhe1MiQC3;PA%Hs--GYm2FdxHG4Jl1Woj9uUHSm-aH4Q7eMJdv!^lj7T@rgjWsT| -n~0FV`)yhFH*YPxRq6E(hYa_s%EhWlwS8PP-WMW?5b>q_>D~PxjPllyS#h-G($S8z4MA?F)Z -UCN6*f2Hk< -dJT~ppJol{I2C_Pgc*Rj>CHPsZ|l4ez$U`K{J@M#U~R%N1U^oh!GUBP^SlH*jA)?vSmk6%z-Kbz5y7y4R>C@rUJmyr5pHs -k$1ynstQmLP9?T(5X*%r8`azo?tFJ|sGPMIyajw|!vL0!`eW-#{Tch>sRtFNQ-`D5q_dQ7s(I_7F3!q -{x;P5kAo{vrR-x#2YgTlvMG&{pku(;+;VfIzqFosX2HZ)7UaLh;xvDYpuV94>u=Fem5t`s-Iv*{0f+j -^tU}oYQG=Ar!fE;2Gd+79s@Jx>>Uzu~P=(aXb#bA&ud8`Z!uNfa8hHWugiXA=tV!@j1-AE@AN%fd&g{ -xsjw;p7G+Z-)DrWrI#aj;99f3O6?NvuP_BDV-kXzpf6OBNXbWy8s^Fbk@!L?gRZZ;}R20~|SbuGT?6V -H)Y3-NtZ6vlt3Da3=3o72S4{u-a8oVo>@Tw%@ScyGv`HO0LLovUL)2t0WcNNC9kujz-q=s-oLEmHw&z -0L3|T#J -jVwS(#;_nJrmibKUQ>G4t2pr*M(n!u`=1*tx6K0>D_1^+mML?dqI;71j7ySW+SWZ`-LkM-F9|Fm3{@E -7xqgd5kU^eM~R5t*5R%d*djwv%D7S6pyJkcN1MD`Rdibre|2@ZsEe8&d(YDJBy&Jb3^Hu-*a-MZu`b1(HJyMOqkM9l8US%<~8PV~;Hf;m-&B -lODFqDiqyrGo7um2slM9&MI^;S=ZwpsRh+i*m**5wjYx -^WM`I1Ve)QO(d}qy-&lpTL}j8ok6?p((wO5ZL$`}^wh~n~gRaM0Pf0#=kfhS9qT9;o8eV7M*ai#Lh06 -%Kdh+(fgOK-q(_&0tAo{#~}t3Q -TLGE?%u+au)d?o(PK<1WLid_+|r6}M{}2w5@A&hq`VE!f2O4YG|BjunUwpQ4WEkm!+os@u~)~{uo@PR -%_?Xo?i5+YB7=tz*RzeDis7(FfgP$)x|I@WDatU(4AqrfXKt#Z+ajSynW`bGELGQ`#)(3bbvlYmtz@^ -g59Vk(<BOVO<&4~~;IIJQFEDM-P~k_=DG1V}!eQjLbnjG{)I-9YZfG@Xuq5*>OWzD2At$XQ1=$qccEun@7EUO1PgfAf%b`faT--yo9@1m -OFX3hP%na*u_ycx0y<1as8-vBZ*?yZc_Ub+WPURC_GC#^5f~WQ<#&pW8E1Qg~DBG_d%dn6XSBTg;%p+ -WK6bz^p+Awp`m5P{PB%5cI2;WC$yW}tC5ZB@1nHb05YYNR{}N#-yTJ+t*s`Iqz+ -if*fHaK?MnkJB6m;&5rMEWV`yc_LaWDFS4oB_lbI;z1KjR5a|dW(B?;pM)r@MLFVO@0@5dlUW(@37cPVF(!IV;-*)Ab)SLLQ4le%!pVA@)igshsec<#6EZ -8+YDU{uPiIyQ11{KH5%S~ECY&?ukunFh)nKQ;_tsg?|SQNF_FrXthzn8n|0llbKM;AIEM-n-W8exu3@ -yxWuUZYjF;G{T-22-zJ=#Uxi`mI)a#qwc8#52Ycc^wgyUlG0(qT5t7g*i%Ahp7F({0B(+StURLHx`QP -u6^pTod!c@zS@IYy#7x)J^R!!2bXyrtwFpKTqF9}`I7NkMz~IM6T?T&4&?B>{bgcD0HpgSqu{$k`O74$~hIn`eSr0BMYa}(fFy6A{=K{P^c|9Gd2JknAaR1?mTaQGBu}Y%|V7%+-lT -?&|NM`C$wr=H_Br1g{AZ3oXbv1!fveO(yu`*av!=XxR!z~xj?m&_6wq)uBN+9TW^8j~*bw -jeyA)!}I)>sQbvS(b+yz8bZy6xoH&7-);AcpuF4e#dUpGlvf@PkG}0J)ulY@L-dDi695q}GM#72S?*5 -#Mtn#j=b?N5R+D=}&Ki00pWK>mF7oQsGmSka_jiF!jk?x+%JC)8miqBN&ag+_Vad6mKn|3&lsBs<)y{ -gOsCyrP!6!L8Dy_&%B3)vtzqPM%-D+A7RnehjF$LhcS%9ZZ%5E7W^NtlQ03WY@S+3p|)cr=Hw~*mZDqO%LcAMya;KFH&MCbZD*-lP!UT6(s{#TtG^*@>7- -rVMB*`mr08}^A)t+$8ZIZNy9k4XtLIeunk(RM%(j={kW+b^Ro9~CH5HbGK+vNrx~-nF_S6Ii<*Kq+){ -Std_{sZ8HgwY7FF*=kC{m1^kD2DC=ypi4bE0|hqaX_@MMW)@P6;1w@hHn;24q0uaIcE-bOU^YNOxR$o -}$~$yY;;H=#2q?rocn) -h0UkT&g_Y{OSMYomUHM~lVw6Vgx7Ox0PCJ0Ifn9@;k7yY^Hb~n$;(Yhdlh-)g;uqaCCUJsC=$sV)#hh -ALtOvA;AayR-2;l2)PUc2hHU*b-@YH}922Uxsz^1uyW)bPNw6jwZf&r=ZhQ^n$5uYAL$Sn --V;0R -tveoh855XU#{02h0Sg>mr3lt^r>OC&#|6PUy_inrC;(uDFl?dDyi$g(@0lnosu#pkblW`d2&df;434h -G01Tl_85~}l+C`9q``W5?Q&R}808kF4zvD{B6y0uzBG>9<$(WNAFNGt}Rwk;@EEIyewE%3P6)y#`7J1 -kvdZd=XThVQ$)Z7k9q`a&Um@>S11{0<(1S2pAP2GFOtbU{-jhZ?_r9nd6%hh8=w_C=YA>(Z<5lXUTWO -t~j2dQ93l+>HT_2J08ehMjc^(_ZKa)T(kt;;hvURVLEr+A|0^L-*&Ip9Kp>`+xokmB->-lV80iwyP97 -mQVO+dWNAr2<(5@9Wo#)FNhddZ9_BW56lavUuu1oen@?D1@b9MYn+LT0PF*wMBe^8=Q)h8|STyYI8*vBd>wu)VP%_Z?l0XI`nDK3S1yIIKkUIY=tzdU(&yxqTAgHxtXz)2t -LU}Ho%Ww%*ni%hogC9Qk7G2oBSSp`WT{03!nQn$CiYK$JAk75fN5O3q@wEx<*x}&W#AWcL4M3ELhoDx -W&WCBe}^9(o=M+$MrHQkI~SbD&ysCX=ffu@F=WGQ%+NB%&^7=cTV|Kq0}Wc>56U}Gu};0rn&_qkjxsS -XO{9v8h|9lL(i;0V|qJUy&)!PCWWcG>56XKa*mk_#TQDSJ+-AA=+FsKAtKTZ_H|P=GnLxr40_)jfaS8 -|6y1{g_2xM-BXafd9NGcGzt_hgi7QCJdK2hbXQ!oU0S(KC+3qWOx31{6A}Sw4kKHvbwyKlrUAAl=_|8 -)DIlfr~)f2I_UPGitAR|aubUU~kVt88#)w!Ws%L+I6r%Ugvg^=YC>X-cCY5~t=1V~v|7GrzfbUQpUhX -RAlrRTBe<--E8c{9;waS8WoL2-DiBw%ZZ6=*%f$hhV>H7uUbF{5A~dFL+vye{>}KrHk-o!U(8dHoa+3 -COAtSG@@O%-XZ|-xb|9%Zn&ihS&O9Bk-_SH-Z$0NCbeZrD!|6KSD&W)C2CPOsgs7YPfn$v2l0^ec-vg -mv3nc7&yLr%Ql?_C>7Vjin|A#k?C5_9;uD(if#*lg|ZXxrPkfl`-=u>Nk6G4LsjK%pn1^NWk60`^9B; -acP8mw(QR+pJ9xLIxf6@nd6cd;b+D)L8Woe07HFpdFVdm$28rrWU`A=dhSjjB6jMs2az^3DvdU8Yr&E -bj?Gl1y3FI4!c+R|qnb=metu!}9x3%ZnNE_WM?t`UMXBM3bs@d>}wHr9S>xyiX1sR;19UPhM>vBRVy2 -Z_GM6khe)GosV;oC_&%jxv$jvyleTf?KRTSd!ktqdT@fM7%+;l~^MFx?Pl&%`MsxPCSM*^5${P0RYJc*~2Wv9uHJx4gw=z;p>nhHxo9)j?O -^r8iEcGlxEs&QdRT80sQr)4HP>k)VF^zxwW(nn_mQFL3Wi+4{1v|Iqv(^HM5H5}Is%uTK(zV_U{jI-& --^qj;p8^~a)=ypgQAxx^IqP3b5;lI49%Hntzqv8$nCL9?>x`^xG5Hrsvn57`Jr|1?Aq%YN;CZ(2Jmv@ -kR52k}kLsQ;l%*7{{uTXS5nENW;K+jan1oKuC@5BH-OX_<$F#L0;1UkHvVtL^xuv -`vvB-I -iXY`{ze{xsLo7SFCW{cWhM%zGi#<@(QTpV+|}>!fq_WAqV^st*q0X|5{4)=4n^jGH59wN#yKsb4>+r? -axI?6nu|D3;;}0tQnBPk4xVGcMCCj9;7R}ZAki>w}^1-&IT_#)LAR^q_*3 -y*X(gbnklB?%4y|I4jICB%*!ei-8QN;9d5IFRX8DhP`zl&`}Q!hUHJ;E+_Kz2wn~5;l9pcE0~8BM%s!flR7Tq{V9+q6h}0px_>+(?LfyO5BgTksIQqo%(+W+;HdpH$Y%{d+!Rpjudo7w}aGc$Uee34*0=tX#txZ>f45i|1U&cmw|;Ts4UBH*bo+C8N2#P54yFzIRa=H8K&^seZ3D7H4w)Rw$ -(YvgY(IYTt?bcv!v0-=pwQ098g*XGfOMy?01_?3H -$TR=cO8S9H6{UeKojiW_P+IP=rJ3qW1nFsyoof|Lr?Pq0SgHksyyN~dbvJnhyM-EQi4bYk3XRRF|8LA -lHtHTA04$0OB6ICH4=^L8+>Q+^o(x}w|WHI$yUB8TbA`|*htkAhlUBZTYCZ#g+UwQ$-g3M^iPmwZK6blW98eEu%v_2lC8Yb)#` -SVii^drM4j*&roH=31&e1Ls`cP0?-P4At-y3VBWU-Vsw~Kjn9173X26UdLUMk01;T1G($&T}W -1<94IKx*71E_u|va$xBlszNS*Q;e^@;VPQ9B3;|SnoHZ)u9^saM4)2Z|q>XyAe{B{ON6dG1^+dQ!84Q -_1p?p^8K2;{d|6z|N1{`62h2d*T$z5G67o{L0T;*#@pMYjV$-g@4O%cGZoI-ajQ;WQVQ{#@=CTx9d6T -Z*=%!QwH+3)g)@UD0jH=nIhXzE1BTZr(&lX%i6C(8~1U-HFQoC6K0lCuf%Khh^z2G{ -r5ec3i`Tp6O_RVBX)9~*N&&jx@B*Ke-&c|`FGaUACxFdhamg853fjHu%7c5Z8}q*WD?5~gY09yawP4Y -$J}#aY$02kWQ~1%99>RPWw0+{?cQpXp{N@w%0DjZZ)H?}nb?8j~TGv$gT|#Ii#>@{OGRqrN@!eIw!d` -D4oWUYJ?Cv+3ERS<)$E0%Z%PWE?x~(bH6pE7ZApmHnL6WM%vb5lZj^6Fkd?N0Ms<$O}4@-Ep?95yLx} -w`AA?VrWE*pD_uN}7E`l6)(eVj7bex(s!zBrN>_39e0=D!-2VcEqsUeN1_MAyhNf`qTdA;W4)f&n%vX -~0?L3z9_?v1_{=y`tO3+--(2uRw6qOS-Bvnu0Blr*x+Rsz9@JH~S?plusy-j(PbCMYoL_L-8vaR3UZG -{88>C-)NS&l;5iL^GXP2b}W4-$rh2fn?aiEcnGBFj46om--W-$PFNEKp?kIM>>@+qj>4~2jdBxY -^XZ@kC7%944Y2+ubV+NF3IKkJwLoY8philQ604Kw1ZVoSWgi`gU{-R9gv0)h&17>vi26)P$CKsH&fZ&WfM5 -Na)lb(D6qMoPgkhWU+&2c=tdB+g=`1G48$b`H?C9gCe*G;$XS3{E$5Ga -TteGA{<0g}V(r(`*C32-H2xdIxK;m&g(39*Kv+s!gLe8pIP`vCD^x#S*#z}J{idw;vv;CqJhbaf`PlEda--UX?wO}Y=$Y8-SOAnNYLU=qVAg-)h$D7r0sem{~s4`Y_T@GcTr! -P6gDm1&a1wri=-sry*`A%Xl%?=}?Oc5jL@$2OrxM>foimrL$8=jeFJM?|*|WvOZ|^bi&gy%iv<3PaIt -@ffg|#I3AWdX<@{dR4Sxvp$=&%@}UImjg?~6pQSxO)pqk*Hm~)$T>dpE5{&)^w{F#-7iD2?~I*vjQnd -XU9nOVf<&Glhm~7-$>dOU+n_c2p(8O9Bw;#IGH!F;G)F`|Y>vlH8v*^YzK7Sdq9VHV6+_W&KYR(40Bh -V4lXbs8!XwZq#d;AgLxqWdgg)MYf2dF~Qjt`yqHer8WxF%;cy$~8pav_8_Wkbij<2-s_gj=+P}BSn5^DY|`!Z#?}!P)h>@6aWAK2mnY{22-+RPJ>4 -S000aJ001EX003}la4%nWWo~3|axY_OVRB?;bT49QXEktgZ(?O~E^v93R84Q&Mi9Ll@P8P@7a34gD}{ -k3Mu1YZDVoDH3di$g45R5H{0 -lDR-dtbZz-ouEuyQN4P!O6NK{}Y3pHeA7-(^{AnF((!WJ;p;kWtQnkR3SE(o4cV;tMKMp#@WbKf}s^I -eM3g3g0kGqaA(P%GmaUxnXJSK9E@y9&^|Vus>ia)z-=qJ_42L!5dgMerNR22Qp2`jTN?G{|bu;&J_NY%6ovu)Q|}c7IW$ -LH;^G7gwB66mI+Fe%c9}4TIZySYxihN*O~b=U&9m~)eBFk(UPWRy-_k_^i*c39fELB@uAzD9Gh?{$)O -aO7~*ejegKpdZ*PA=>*xqR4Tjx)2g*KB<9ouh1Zr%>$Xlwr0Yz=G9ddBNhm+hKq;83K)CGDWN)r1@Qw -AG^+F?*cdX5%>gMv!0>O{3K_E -0{#9`8Y{nvWOvoWe~5Ta6JuTSgzycA{h?=62#8v*3xrcAB`@Evoz#qj$TORI{nYoXh%h=9CqRbso@z) -8ZZ#_+f>c}Yo;=K+lnU4$<_yu1!&{@@M_7tP?)E^uT!j_#d|oIdpwhSX08F++;gp9s0_e4Y@#_o$?g5)oAZG7RO5I@9Sd}>JZ48v_h~XqXN$-2lv -P|`WlA{L((H@uov)pj2<;G>lLFFI(l$!doY_w>O-3`I0A0p -0|XQR000O8NLB_@kN4KcO9=n~tR(;dCjbBdaA|NaUv_0~WN&gWV`yP=WMyt0vs=ja;uSL>;`(q*lc$@4EyV^s%?X9YzWLnyQj -;HlF(iKRCiT9Rn?t?gX}N3uHQ9V@X)-ew|aHBerVr(f*jd{AAdN2{)9nW@G*By2W~u@0hjRT{lOi_#L -v^I?{dpjo&d|?%vE5aOc_^3i<>T29M|5m7v^{~Ccqnk%0Q(BEvBSp&R7hYd#=QfV&)0`fv}DUw%@(L^qM&e7gzCk`IbmeVm!al3&?R9BT_%}$VRm$!8_!jO4}CmsK^8A*2;k8aU!lXD -vEWlU1l*5Bm1L=*_9Jlu#7M>55>4IQ3mw^T}hyv5Kk32yDQ_tq31&#T -xji;i$D<-BgGUi=t01r&!e&LR}OyHS1{?OqTt$yGZb0q^)!i)yxWM#1iZKW4(1sWdWYcszG#&KS2e_= -x65FD4Qk-iYJ1nBsJsptsk*cq)X;=UK)pj$+=vYcaw)p2d$t_Gf<7w{K^#KX=p%3#RAmu%!aC4xXxQ>vn6c{_}ejMvLPtx-x*`(;0@O4R|tPx@v)YCxpj(_vRj#)UKNk&Hgi;pwaBN>b)K`+ -FhtYr`GK^Zw3#wE_4RnPPmhwB@BgxC$o^F#@*J*i0 -au||t4$JJ`(uzFId0t|XIl=lVo*6k~^4O-~OA4bBPLYeuNnj=YmCm#}_3iZKF|H(kVb&Y=8XmsoUGTP -nSdbb3@40`jSZuFY}u49xy&Q~b<+-cs_9*o;&uitH65Bkk^%jnkdM=_@Vt4Qnr)Xme6Gq2T8qTBV4hs -P(?6yEkrY{hHCg@78d%OL8A+h`3IB=WfYM5)>3(b -0T9FHeK6rtFFF(M)*cZ+XOBGCp=T(;VIyaz=!Y9eAKTn^e^ODOskyr5Udp+M9New|JHS*%4L9JjF-m9< -Ij4I;%tY&6`9OrjT)1X{4`GmGm%Wr3L)CggSUV%*wqW>Zw1h)7Qv%=P^7#Gt -UsXgHdRsD*b7j0p?V9$n^8-!jPX&PFR~%ogT6me$L0m2u1g;Gi43cci`m`A7AsZ`mQIKd{mzoJ2~olrr2O -bL_K%&_*90NV>&BrjXr~Da>b?mly}5*`?o%X~0Z0Omafmo+{?DfW_f-A}p`j_plmoko6rZ -vqR2nog-^*Y-6QALpS7tm$XNV<>mUg$OJj9A?~v%&X|^U -T+YZE>D>xY#kyH@;--ALpOC-x=q_%Kv7ZU#DB$O>ur*`ESK}@E-J5fu4`PXQbyogKZ4;wHLBoVtwn2* -?z$uz`i=zcZu~sCDcoy+Kjj_#UnLAg2Flriux&_5C_vUwQ6x^g2X}gCCD`&pS=}5^04gF -)yHm3FvDteoO6FnjNy+TLTx?`y@{bz35OVY1IrihD{1UsP?#IXTkW&{UO)<7hgSMh)36@aaUyGh=MeM -v97O~g_J&1j~Xryac6erd5^9;%$P@ElEy6Tl2UG*Jx)ho!(lj`Q@+87AWpXZXdEHfQYa=%h{vODG -7zoEX)Y;ls3Qco?I*y$)b!_7oj!?=X@6OudWNDGK3BF%{qkZvi>~$K`FQp<7uV&`aJkN|q7Z>#l?s^Y -{5ex_2-e}f?yWzO|Cmiv;I6u39`5IxY`HD*>psPXzZs1XU=Rz?0-fR-d17?+mKyZ{60`l=FvIrhXZaK -x?<1-2sqXrd$twD7GBeW)9F;EYtaSR}uwkNfW(YJgiy(*w*fz}N?`{j=k?C(R;bNuv2Cjh8v|trXwsx)LP6rZA@TF#Y>-38>A -{Z6f7fSC2wkm;uNzfQ_lbt|q?^2oNsX$*5ek$_~ASZiz`ZH=nTky$i7w6@WO`yUzm~|AWu(6B0q`bEvs4TjO^p5C -I(hY&j6nITlpdSQDWM8PuV2O|zj1tjw5abMB2lFrE#T+`LC-~Z#PCKLd(+xS3;$)>#W>9<+Q%i`Y;@m`=vCo(C{PEQC%at--kw%Wq2wwhO);gcH^3v1$~NIeb7~`M#e*_Cn6lDMx&?vPg -kRg_#pE|Zm6%a{pGSn<7fR_S+$m$7>tn|Sw?4Jot*iDgtv0}7=C+P4=#B2*Ic-Rx^Rq~+4R|OMYHg~Y -yG#?UmRzo8mO83%2-Zv+v@w}Tq};Jfn=`bNbkl*Ip9O*$Qy3n!O5)7gc;)M^GTmgVRs_D!X(sr7!=Q+ -o)W&kd#fBn55xI|<9RYE -P}=aSrl%hpLy5YsfwY|82s4q4Q@Gj)w$6h*$uyK<&m)TEhVZ{MxVaCr2dJX^5lFWCkU#(Hq2F=O%3RKOtSPs -a}x?G0gA%a%<72$EnKml;(B>j^<0$EtmUE`zk8$?so?pHyx>Y^XQbxjzhh?F5;Br@*{3v4P>uBUX1Sj -!Mq0P_!W!u5nUfqaH&1#X!X-rlRXkuGm4|RkH&NVv3Gm|?Iuj03G<#2bMI5f_7JX5h5pJAg8E?UQ`&77W44*b9ZsUMaGz6;8d0jXb^rd&pgHMjDL -d`pD(!MQKl=etO9KQH0000807zB_Q}TkMAkPN?0EZL+03-ka0B~t=FJE?LZe(wAFJow7a%5$6FJow7a -&u*LaB^>AWpXZXd6iddZ`;Zd{cgbjVGw_?)JUwAi;K3(qg50s7OpHCl8hjAT$&=6($>_HU6QtWe|^s^ -Ns)RPiGT#=a&{hPX3h-H&JO?R^Wf`fLgP_?FqsYL^Z2^|2OW_;J3Tq0`AX2WmP@Iefcl{)NXB#({wag -Np<5-NgpTpXT{$`y33(zBZW3y8A!ML!ZA%nEcBD`%5eIjO0-<02( -uA4yL?1+<>*Jck-<{SHMI$DCX|G9lO?NAU^i?RK;lWM12&Bum$I=xl7UaYf -@nO8GFdechv%(b`hR|;k@t%aldt;r80Y~)C>Xh~hl`RBJ4JY9ckot&kHsNnM=WjL5X3k_^7HhO5 -D}e~Bx-&!h2Z{+%Njj^>lWY(~TDDfQ^4H=U3Ax8vTFZf>VH*Rz3zEDKQrZ6G~_^#*7kI@claMBg|vh| -BoDBhfLO3_MynPXY;d1zOD`2h|c~zn07(R7(>y?o_b8C+U+4lNLQ|i84a5?xmU4RGDs}Ph6`-zjq+zs -K)@AnBo3V`p`WL!ce#9a~LNqde!607wrAY|a -|Ct(>*6?PlFa4Gv3;gU8*eLu7p!%m@AXX!5nx@~=oUGbUN3v><(BZ%?-tNvc&5V|B+D!YhDUq+1svq~ -jH1#>-^0TkN}l`lP^+@qH-tc#6ZRw3QB07G~+r%ej%73P7x$P!_PD##i;{^JoKYGK9cqOmw{- -2HgDxM=@)`P=Zm`Su*)p3`|A^qvPe{5cP#!vD&2qZ8QAq4wfkH{QH?Q$2iRX7QzBO5(;&vPhUwz){4t -TTT$IoP|ibB-E0Le{&Mkozwoa*Z%i?CB5ZFcl*&)h2!D`H-EhRogo+wYnRuUltOozel?~eDvm?|p1S) -_Zl`{yy2U$$R1s(!@%kuzo`VaHD@=K$gT9bykf;Jjf)HgMr-29<1ab|M^J>}33P)lqpEiD~T#kURJjS -fAXhR31C0Apn&BjVnDGP)XCxl8r21UM4@Kw1?!!(A6|4X?hjgy5VwQOjn{3vkTeEuRLz!YE=h;W4Q>` -GZvzKs*dQg|NmTr;t75V5OegnT})q`M+7WcKHYNrNKgRpzWC^^_}yQy)zQ@x06$&AR+!fQi=oJrGp?}M& -|4Xfi-&Tiv#rn_lR;BU4FK_%Bloy4%-Fs4el5z}*JR+;!WX`z|#;Mjl?L -T9GF&FTKVFH(e3Q&E6c2`%wiW&=U6q-d@hoNEzUtgvKX2hFq4_0MKyVQ%Fud&qmgpQ)geYM*CJ20)LE -i9vAdcKCM&dssf6Oft{&{dre{#mO>6rl2X1rVNTR{1-Ra(Mi{#5rC27gnFkGW)Jg78$08w*R&%68Stl -MEae?4Ox>8*?vlwS(}9Pe|Q?1Gu?KqTBsuM+>%Scz-<;==>vA0G0K)4Xotwdq7Ik}Wn6H^*(r^%~zj81X??<8k5h{v5h)s`Vy9)hhHV%O^GWzah7;HbTCh -Aiy5X9)1T#8({tOd56Zi;rFXvZdLfm`pURmU3{dB0Gk0HiCtPHz4KD -?@9u2XT4nv49`nK?FnQkG6TFCDHXJ}x^!x|U@f4{JkIn~UYEirWtOdq&X8H*#$Gp4pl9AS~>eBz?+@s -5F$vd_Z|_;1409`g-U19JHBEDpc+5u#Zg5Gb36-QK5HOewTc?$k=C7WcSTuMy}I@cS@%id8qGVSH$-Q -7z$+YEa*{0$xm9vP&i<#=)khxxA&!ye;^fGnJ;G7LDYX0?HyQml^sF(D7yEr&$j;qP)h>@6aWAK2mnY -{2271L=TQ#k`u`PFW%u7U9!hWM0rDs+Z^o9_oCvWIx>F1_g^8k{xnp$C -(%vWxuBxiE}i11EmX(~!ZNmgdc#S=h?CsAg<8p{BM$yC1NwW`dJ702$SEnH3Jr@<{BgDNVjk -4I+&{m)><;PXc6f6=>Lo-YDQltwrTe&E -6P*LIFyJ$jUMTJA{O?d`hah!EbMYWi@Kh=^7zvEcV)_4ysZBWxNyDe1^@LPTrSWZgvE4eiVC9eZ|Gqf3shsEB6F5? -YlWZVKp3+fI=J5Bv7IoQ;nMANVu)4>)Pv9&LwIcnmbw>ZdQzfNIeWA* -mhvz0sSMUnkNmf!42+$yeec81a{jYor`iNL6vu#cvInUG-ep%L0Zl*3S0GwSX)m -^C16I-gU~7q*AYY+AsvNUf*%XIF2a>mo_xQgxW7cuS$J@eJ9u@_Nl -ZI5EyB}MWUFGTqQEW1spBNYZHra+h?Dbr9Jb?I&%>JB-f#$=-KzWsy+2|W$LppE_SAlBYy;8FxHcK>O -J@&QiIbir7^!P8Ki0DzaOL+@SD6e(d+^p336h3lIOG;TYT{BTX1Fccd@WX)%xN-F_*9upT2AV`O|GaV -EoQCrWP)!5sp%AZPj}MF+6gl@LCs+CcCP{V-$Y{`o->GbIi&%V=!pUAH5fXrg*%x^e;L+VlSwHGIhh< -iae+Wc-#V(Bf|HC(yt|v-Rs@?DKoW#x6Q-2keKcLMm2ScvggQ2o{U~V`rVbyIe2Z*a;wp{Pm@Dg|Xt& -uxXlH^~KmcbmKX3d3)A2?+-K@>m!>~B2Pf_3xi8V)@Is?zgz(KI -Of`6l@i#&W?!c6h&MsKWDlgY&0-w%s{f;2U9cIo5XfKOUghr_^aIt -n`&Fch1^uNYD{>AY`Ec;CZLZcVX(1>>vdZiKk3fD*0o$Rk}Qf%we?pV`2Fp9=~kRH9j3GG5a~R+L#gl -1yD-^1QY-O00;m`Rt8f_;Wf`=0ssKi1ONaX0001RX>c!Jc4cm4Z*nhVXkl_>WppoNZ*6d4bS`jtl~YY -`8Zi*PN8&#`i3^do6cY7P+QUL1S(N}{7e$;Rvpbu$YHVa1(*5@x^AY+Hq}C_To0&InX6$D3{e%ASKAB -*g42F|*i2isw_=XFy&Bj#|1Eal_tF1S-<*q*m2)Gj(eI;~W30oYXgrR}4g>boHB!F2Z9h6*IVQcWUv_ -x>G^smBF54G7M=PXNwbcY%Q=^=FS(bzz+HiazffNga_7QP~QvTFxZ?v4A&0%LNHefOlv3WeErrDPtm$ -1*4F2*P0#Kvz+LRlQFf1u5xK3Py(cg_lP6K$89Y>N~QIA>6dPr+P=q2*#o%d}zVKY(nNW>#m^$>pNw( -FU;ZGZUL$H#Fg1_YZX&+v#(MqtO#32C6bCNrjD3F^?{eR0;M!)Qv=A83bdyplx@ey9F(XUvJ2;NTI4 -F|I>mA#>k;0~%Mv6@Jt3OU;9bv#38ctZGj#3h+A$7`ablUWi28(Dq6L~s_R{}yH4c(`a5f5pf^ypeuDWpGjq=DTwR_1U>H7*XD}HD;VcPZIGG1ea3=QZ^5 -O~>8-%&$Yc839K;;PBK&gImA(*H18ZxqZ6xjujCAXYnAMgc*+M)(kfIWfY5@u*k#VpD-xg!qfo*Flwz1F)u3>O@_pie^8SjBF1jH`bK#T_U3+CN8fs$79Rb`d# -nd{Ha1Tba#2Si+~H80@?s7(u2K~&p~l6xMAB*9mj>DuvCXhblou&>nKJ=Cg#j7iX#bJJEJLM$+uzgOA -;lq%;%?QE6IX)4#dMO~VX%*WXhCTOT%ctnYsW{Rqn;F-&w@C>CvUGQkIL(AC>P_CaarG3!PkVYe>xn){b7&iwl8{iG8KtBkQhJB^2f)zq#u&6}eK~ -OM!A1}VmmkaP`&+y%kV}G`IzNcVfoV+Au3&qQ=;Dk(*X(nw=y*q?y7zf`d#UG9*kKVFQ3<;0I6TE@{l2|a)Wu_L;n^c2^7q6@+-74ey)Wn7qU{$~=}P?I8u4SPWnJVQN{2w*!D>;!Nj02xkv}cwLC0%Zoy*61;4~^nN$o=8=@{U4_fwDSkL|_;f#N<8H?;k=}`18%xVqvTV -a8cBw(*Nt|cedb*r)<;oefTdh_^`7U8v3CoAI#elpC+Nkj!B^guh!K1rRcWE+Br}Kw!;^w%#$OJQ{^| -YzI(}?bl&>5jsDIiTb9i%kv85Bk5aG$B@Hua9c`p|@U`;6ren;YeIQ6N0LH#LBNRt{Mv~JS`k#tg@f}0 -$W)z~a{)*M=O#+hVGUg -l_E&9f)Iz+Si0?euwNma6Q-h)Wm})#G=}% -u&DF0s5SsT_npw0}?$bab2QDX|&^$7xOumv;}SbHE^h8@e@nU1rSjRrb@_&*dszAdvD@S?x%k0#Y4v6 -D;(FD9}l|koW|h?lTX#TvU{YaUl$rA7C$}DTA$x|6VDpd;CT(+MpNGlYv@Z2g;AIeZ*CoS(j? -Cd>R2b^S9cNi4yl*-s5E{qZtMNBP>u0Ng)+mSctTMumCFB{u-LlV5yRc|;2HHd% -#{%8nTqD@$mwUHDh*2FTk4^IDXEK`Smab>frk -9wmXV%^Kc?4gN73oUMO(MfPY3jzZynl2@qA75Dw}q$&egjZT0|XQR000O8NL -B_@#N|auAOHXWaA|NaUv_0~WN&gWV`yP=WMyC#-JBLo_^yvZi2a;KBE*kf4L?9$yOIr{5w)-TwAY17u9%+AcSGtWFT`0}#;fxG@YcML!%nZXF=+Z6NoGNvrpdP|or4K#X9=v-g_VKHj`9q1+rc-C -2ihZ@y0MnyS2DU9OtjghLMn{VwAz=)|&Fy+ZY@fExQO4ERmFx{G^6gwV>q=e5EQ(MbdtPnxV*t}4BH? -Wl(2$=wd5!cxbM2G<|ydagYNhVK6X8?JDxq=kTWq(R%&Gi#aHWu6Ean%m@r$)-6D+ -oUhjcIx_9o-ojutK2JUR!_k9>lJm|u->&@KWj*@sQ- -x?ttrVQf+c%KYIum81O|-8X1)EsW+qZB(xNG*r1b`P3__X~yeLjGA}JoV*}{~aZqXEkP78kTkQWo566 -%Cc@dF+c_8^f`wct)_V_ipG8{EF?blPt^zqLC6kG?%R^+11o|H|z`44t3FO0K{OmrQ9iYbEEz0rk-iR -gVsRG}H8O=ShPh7TS>7RxDg{fjjrq;#j-|k&aQo;DZSck+Q7 -y2MO=kyGg{ZtYD?k*GODmvW-@-rtmPVSd)LsdNUk-HS^d4N=DE+{9N7JD@aQpXf_q)D-g+pyX5jBoQT -NPNd`GXk8x~xLIs-XAXY1dZtqh%bA!FQ+dVdC|>NI3Wsi0pi{2ff;Zb!XTH?8}95)T;8{!ieP**+nC7;&+|eM_Y)DX~=KOr3T -*O7lcd5)_U7gb!nWzD1emU$h#DShFqp&jAC$R(R9~g=V9~i5$KHT3r81z{0(%iv{IGU5M>&4Ud6}`8v -w#pqcrFZRh&BG+?6flwZ4D%_2sO@;yD@8tR%+)htroS-lm;1Jv)+WnR~wHtnC#-a)RPn$S#qb-K+g89 -+XqC7!_lOm^G|o3#n;hu-deLpXiUn|LR)IhvONBkt?HYp3JQEp+PL3k4iT{CNxQ6Z!0J+0jt_IC935S -upCK4y}q;XCF|9F7#>e4Zhr&PnVoX@GHp;CXeI$z@2?9ux3k?EyxC{%q+-1FB>&YuYs&=loGQX+*k5d -zX@{V|4>T<1QY-O00;m`Rt8hTMpy(J1^@sADgXc+0001RX>c!Jc4cm4Z*nhVXkl_>WppoPb7OODE^vA -6nQd?4I1tC*SL$~dZC|vN2uH&6R`-Ikv}Mba5~@}AO=W^pq6-OfLRZ}BzWdDp0aEN13hZ`I4XtQB^B> -z|d-79qaw5OrvUXi>L8D%+wX7OkHrmx&Q23r4ADuvVz@aVNN7rW_RD(VTH-usEx9fQ<9f(J;u`P|Bv2 -)#bBNu(Y@F(sCBQ79tAd*BOL5oMB%|;yChQqP%+AMMdKg55SPeaA?z$E7oOdfLa#QX7ds(~K~w>ORgaTcC`rY3+U6MsR+^&W*g1PySQ5kvuW -Cea}97kR)Wd2UZIF`;}pf^!H1C;EZIyMReB2AlaHc;5|YJzzp2V1ECPKu~~T(082)wT=Bg&Wgq!aWM? -zWL~%Kpus~NFI;n<3!GDD-1A(U)D73>e#n7^FrvnAu*}#M4aJ%d1+D^&KTY!ma2M^<-k-P#u?dW{9`` -p7nSwyT8H;ENxUeHqp5wSD;Nh}}SeaJjVL9DCxc)To09OJ3z>qlEAGoWa$6*|DXY8dY1UkdFdiSP%*M -&;!9==sfv(oC`U!XH)9Id#Nvrz7EpcKp;iA!mYTr%oJw1(kVOzb~*)l9lew^(?2YE*9EUqN!$@ -Z4*P_l})|oyjjyMq@;-|g+_H^Gxs+%)w|Y1v$j(kRV=5FeeS1w{fX~`$ -PRGpMGs<>*Gxh46f_LFvEWHh5F??jf^BX0+@fQU2}oh|5W~q-ED -j-|JkL1iY1^sph-{5v`+?g8Is8&m{b<7Va0KKSx2;q}3r}Fhr$BQmxvOkm06)__gx}K#Xr)dj!Oy3=p -%DuzLW+!W<7vazHGn@*jZs0f_G#5b@mp)`0k{m~j_C{E5%E_Kk-JLCcqDagJvPVAPkOaJTLXZ_0(*ZO -@2!h#k3SMm!9~&KU81Agi?I0FZ$b|OWHNx=F?YKnnn%8jCHJAR^E$D8^w%w -F=0V;#!iVoCQQP!45UV@9o>a4MwYd7y5Awjxko? -P(|e<4fk{gf@{fEsTQ)M&acc8z?8_(uwe08vIH&w)6}2^EHb?jywm|jirGpMnHjwzNhv51=`WbxHDn@ -%fN+pBWNH@y1<^ow_@|HtAQ2&pGP9QQ5LubrHI<3li+MX+!h|Z!7j7x15;-l>Rm=k8Jz)XmiULuvHH& -IOb+@;VS3p`IBy@;26tJ*c<9UvGXAomq1t?G=`63?{2>Ipg+5ZkA27K&%FCXl6;X1?I4Z_rR2 -6yPvzZp-)-o0Tk8hbO_bzwAjpbv|_D -w{}GE2dlU;HEw~X%8`EjuIA6Z*^)4@ZZ!UWPOV=!&dcd9ye{#B@LeHN?QY6r&JjK?=`kBMDkYdI7+SS --mm;ebjjMMyWZ=S4z4UvlKEt;Zeh2u1hHM_|)9pJ7@^&;QhJK>x{RAq3I9p>I|kniLXifE+|0+l^$PD -J5hF9+`z!^%b<=US%BOxrpBw+*=dS~EApgnre>mdHh^q-N>6Q-3-i+7lzt^JhU!l-lj=7#FPeZ&XTf#A -$7gf>`rD5)2;SHdvkCIn?&E#Tc7ULv9=$P_OX;!r}4_?FfZ$4a=IA)@g{0+>+%}_W|Zhm49`97W*j>8 -2fRAF1k+;^90DJ*ThwH;^f98oFD8H@EAix|>Xy6(JssQ~|qsj|TfiA -sqA;pLRGe5qbpO`PVlV^OKPRRk+4XaPGvkx!{abqaQ8bI+gJO_vpZ4SlXJ)A&bvj6D~@P6^VUz-Ydl4 -gInAn^JH+ymDJIFq-+;gUwD@qmn@?CFS@ZtxTh~Xo!KCiFVlnexQg0b%*k)_kf|w*1CLn!mDxc%ac_B -v`Pvs$(2y8Q}NgFXsqZ{Jliuq93=dD?OieW19}fX)zyqW4fW#>UC*%YLo -3|IqgAfj6GrUNuHfr(No`&_3lNU2lB+>LMNUksLPI?VR)87Cd4h3>z -c)!1D*kwsBh=*j8_gqg0M>nmtWpayX;M)Q{*K+>3Uoxwp5-X^bNMgnaE(v$1O6X#X8hO9KQH0000807 -zB_Q};P(w|f`>0If9u03ZMW0B~t=FJE?LZe(wAFJow7a%5$6FJ*OOYjS3CWpOTWd6k-5Zyv{yhVKL9K -Q!PQ8=#fxnw~?iu?xtuln{|6EhQoF-WZhh$s$6L%16ps?XTZ@o~G;oae!R|9`T#$uCA`bTZis1zWD9` -%C`^yc>1I~K7H`;$@7Qh+s98I{JH##v0wcDcVCnj?+)eZ@#3e8tMkk9;QGy>T-=oJum9)b^71@?zkmP -n>f-hJ?e(#|zPvbG-Imum=3dVHJo)tM;`Soves}o!aC!aVa4gqv%k6JaWx|ug?ak}+4~KuCd~tnslRu -9iu8;nJc6oMv93NgE59hasH|5nQY5wzK=SPTr_>_yiyDeWn_^Q<2cWC_P_ym8VmfP#{?9=VL>#JYnkV3n>cy&BKenNh4k -B39Kxqf^5_hj#z^6C0xd3}CWj)ylFH)Dkq$Za{ldh>_tBLv=Gzqxq(iFY5b-sG;}{q}HtfAd+Ge|++? -JU-kczvYjItHUw(^z7rS%Zt~{ethxzaCLJi=Qrg8FK^!cDzQhf^8AjK^5{D0E9P&?;Ud4g`p<{sO};8 -|uYO+dj^s&6#eaEz%NA0xADH=7^8Kk?rdp1lXWsi4a`<(-Z_34$gx{qW@{c5$oBexQS$TCRA8!tCKVF -_dA_tehoWA(e)0Z#G{U<+^zuZ4NyZ_|H58veAlz4tkRSr@Y??0qTzA3r07y<=L~R&mZ0^<@w?8SH9SI|Gq8nv8r^~n>3f#mmd>1E_0I!3?Eb2=`Jb8_a8oDdAE -nx@2;*duYdY9$ky0P`TFbsDAT>I^CFh@^NSw5SZe(8VqcvzMf?1w_tu;?wf)z3z29l}^v&VCeD~R$ah -5ZLTmF4eTjuhI@@4({?#Ea8ew*)w6wi|H-0440zRFQBl`~^rrmyqwuOt{-|HY#|eMpeJ{EgXc`{Bz6e -?I&1#ShO;AKZWZ<9DaeU!0wO`|`!<(Ee|&WI@IQZidiLGJvz-6s?|)ZHolo-rDIYPN)VZ%GrS0{kZnftl-<3J`ld?| -zq(lwg)swPKTaKIZYjnrONh$l5>m`Ye7m%G=8tuHE)LQdhOfw%^{`R@Xi2g3mW#oDzF2Zl%i(>3v(0yKG3UE&%WXuH?9 -PT$2s0AfcH}fz>QJmTU-Xnf+4FnShP^#UmW^#9iOQl|V}XW%8^UZ1VeSqOtAa^kCdEyuw8q1UEU>Pu& -0eJ_158Z)B#BUsNpaoSfqXZHEE96v7MMa6+Y+q9parEYtg^7mk_)Wko#P;}Kw^dO6~5P;yXUy%ahAQ6 -;j4c^0v^lW5m&C)Y6@!vK!*sSZY&IzDtUWdfiw+JK3P -UIk&s(9UE4gx&O2jtpbzg5pI3QqBe~n>0ku8wd8E?%-A5iW8w9VVv2YkZyN@|uG5;6VrP|x{&V=E;IN -c+hAj3U6GBIWTb*Ej8x)h3jw$X{ewf%NhBFe0E;z&nKU)tz_!Dt-W^{Py(C$)fI$L*8#|vk+-r-F4a( -GQ0=3fX7_V(OMol;nJ$FFCEwNE~<$NXpJ@5Td0$ETIY#$!iioxeJ?-C;_nZLY_VDqLU=U7y)OfW0Oiu -&1z2PTYBiiLp(cNtv_>m9c}pIt^F}c&O4ADRvpa<##^;OY?Y_DqA{ugfs1lLIpaxb&<&-en8Zl9;~jX -fC~^Qs$^jgx7&fDeP)%JAu|i$Jz}9Usmz^L$K`tK(9DjSJ0f0&kXRPPX&MCh&?*qSC=Os(zPmi+hmNh -Ije?(`>na0?0hB5;R)|$JplVj4yqj^R?lyCk(iV_nWhu;W0an57)XaikPl3(g8arNEu)Q7Fol`TV5i_ -vSgq~n2c8KpycuE638e401b=RQX4%#)Gc1EI8$Rk2X^DRT0xpD!oixv!ebnI?@dMigA9wH($=4k?+>>_l7~)XZN}0%Bm&rXKBrG?o9~xE$oy`w06(HQE -W@I0FmC -h;F%aaHkuzqic-LbLCm-Z7uZn{_xdDy!lRhU2c2mKB*bvQB=Zp{_F2u~AI8dp&D2#C((2g__PAn&9hi -$vIzDm-wF=b!+*xJl8k}7rt8;g3hIAvhj{Bl0mD>W^9bpnP78f0^k9m%*qwDJ09p!d>VIp3er4UIgp{ -lB3_FrAE%=)!*#MgJ(%U$=Xt~>71z&OA-HAkq%>N^n90o&Nb8OY+&8aEk0%85*gpLI8n&Ani^nIMHE;fknh{rHJ~L()b!!94_0IpRS+LKssQ)%FLVvDKASr -E6~W;D-Hfyn{3~&|5|I*JHOdB%;Tqkql3+Hj(VNi64lvo?5X`Qh?8C3|aiUZZ5F485=%WMfX22$1y`g -X>R*-V34o1{CMh8Os$R9f?K?g89AlVl!7lo@M^2g@BTxBt*a0cSXm^z_o0`R6)T}SvGrLnnbGT7if!Y -&@yfQxQA*)=O{6tWe}>TTrMO?TmPZJ`$_JJrEw{xvy}kVWX@}Xea=~3{r+ZQ;2&7OwC;r21r#Rgk9e40xO`Tk+4*V`W -Z}O04GslH$e|;*98!nN%W{g>VzHD-GHdJ>N^@*~4s -9fR$Ael>ZveY_3f5FJ^WzjHPDju(En3pG_Z@zu31Q8vF;j=%j3dq!6SW@OI+X -$!=qxG?^G<_SUliN5fmIofbdgT$7m%rdmxRh_1C;9Ej}wu%g3}0^0l~lcs? -X#<$aFzf0Ca(YZl9|9j;wL^FCdmj9aV!eajsQ7<;|}3G~EgNXd2t%g9L3wgyUgph3Sj+lso~NRhL?QP -?l7YqBX2%^Ddg0NC?*!Hhb1h#>yadDe(Ub8he}yzBybm9onzmKuw?nO`5lRG2tjSi4>6U*Dk$KBk|?NGg2JNgcbeIuxHDVl7D)yG@xgA%DpEpGR-}j -}REq2o@IsVXr3m6$?=)=zbP=@cC|1FJ4PHaG?%C0BhldUiU9pj8H{(o8R-;;9gUuD`0W6h}pC1tG;$B -g%1rwH80gh^m#%X5mON?$IK7(@UXy$|5)fM5))B!8Z58zSvuZ@T6K^y3+>6B52U*jbCfLLXC0$EgZN* -4gR?4^Y18(v7yC0DU((kPh$u2D5Z5oDvD396W4<94%lAa7*})@FkeV{+v+q?pLUe34CR=EY+NH1`>GhXbwRVJF+p23E1Cm~E5m5B$wpQ%n<=u -M-RmH$uFj@?nzNCfB^o|c?Zg6pRjk`AP}mDF$6ia*M9i+&c~B(tBfp#{KOrt4ttw2=th&R&vhSb>T2+ -@{Sy=#Tn-qydKwc0UqKZ8vy6bqyHf3sq#0H5?Irba2gyND$_0g2kUED69BDupg~0usP2+m@C$ljO5H0|Tz&!)^gW}9=Qzr%D9I})l8qZ=dyBVVlK*B -P~lOg)Jg;Rjw+#nxg*W@M(ZG^U)&%yxsK#Y$N6#y-oiy2)RjQ)Y5LI*89Q;c%jIOj5wYqMxTPrwy7gBAomKG%!H}{LIC$5&xnv^oR<@geCUNiz$j$RM -8z^p!`#H`lc*qi#$u&qk!gRC4S|ogAUGq-AtSo#_qu!`B?hHtWb0YOq_zZT6$RiGvqBJs5K=(yGAwEx -njx#&>;k)g?G+TBZS@cugA{AmNX)L9t87qYuX+bM*zS4&*hlp=r3no-jhVCA17Z%5i!Nu@bNJEdKDaf -A>FcDWB$4!c2$wokJl|c}D;^S!Rx5xokArsbZ(%7C^cmA9>f8BnkWA~e02Cbr9iC2Pcq% -*l(-x(TFi$0Et&ouyaeFlu=3BWyAV9vRID_%CJW3H@<%A_@!UPx=_+Wf-q%In^G?XmSRS6V2wuy3ovKHd!<0CSK3Vhb+yrI8#*`+-YTeSgkq5C?U=C1w`4bk -Y;zY>e70J9VFs|WRaesb2eYI4z-0TKG0lmmMS*f?=(Y{@{&Uv4DhMiiS(xrxaCl&b^o#&W)(sV2Z=FT -mW~{kI9%wLrj@cekaE^lNq*+dkVlrHU3VL$$rO#LI_aLkrAO-XIH|yAV)%>_MIfHB4^z}Nc1ggL1~2o --u`3QtXc1QS;n#FaX7F+L0NvfF9`Fc*h*@!rg2{HZGvExg;=V|5ryIGnyHNn-{ -_Hde}VWTrs7i{u|qL8b6WA;_Zjv&^bK13Jd&dh#?PM4Yqu!?t0~cxtP9Ijlh16hilZUcH%0{rRoJ6Vn -qd;D!ry^pC5n|IrfNn>TKKWZ$L^lxS4Y%b>%`gV@Gn=V6x{nT!I}J -e(8A;M_4rx6~siY)`l(H?LL*o}AgDU4ePdv4SI|pg;@GJ4%ddm}8IN#3PJ~cELDE2p}!!k%mn#Q-091 -aPz2GVtB-7PgWmrlYa|7DbRKZNJmC)u~yNS`fai0a$yHwj}(?=9G!@CS2OgwxhdEql4r|2xU~FVct -V28&smj2FBfah}8!bn+e+L@;07GUv&&mQ;G=+-D>M{}7oWCqvtW^5J8UGGi$JE3aEQg(m^4LS@zjNFETad&hGwmvapPQp%UhYEl9 -7(g7uvIK2OY{}yX9Q93@&E`ov3_37GzqKw`T<7=GErS%*oo-b5IK*ypZJ2W<@cRvZdZEY6-xL#H?a%+ -p=ggBlTL9Ip<>CNUE}q3s&sE+2wFJoDmv{W|dY>9s9SQ_4Ibs*Y^I`$)2U(nY};^6Y_YSs8GBDvw9Rn -qtL^pg#@hHPzDKF8+T{GS$gBaMXliaRX*(Pc^D{dmICWMB`qE~dlcr`udPluIcir9Rbx?U_$Hmf;7VU -CqYLgkDB{iBZwc>#a9gpe@Rf!F_sz(4;ip5 -(^v6v>AI(l+q{zwKeYk=~&t6{*zmQnMPi*&FF&s`_azL#+uhnV9%%3=)!D}+wk-i2m&+3hcQB_&KY^< -l@MaKer#LySf-`3kqk!ux;Cd$fyHE -=^i&BD^A|IP3v>dD&^;I>!jevHRU^g09}`A?M-(Vu+6bTq^J7If1>FTA^+=shWH%YHcKg5!jDf)`H -#n?G4<+;yE?5lG{*b*zG@l}|U4G7@ohc??a>8UD0%h9zXneOq|Mn>h@PRaU~Xg~V&s;bB?9dBPxuQ#$ -Nk&cMsOfv|GyIoaDQtJj6Q6#dQ~fWg&95Rqc_Aaxwb+1q3GB5igBNUq~A4DpM*bNXfd{qMfwhW-BnP) -h>@6aWAK2mnY{22Vv3FdNU&Y9V{ygdFv -KYSQYU^EQENgP6dGz}i%MC|4H*(J=^2vf~hTrvTH$`H7LLcMSyn5Xm#QnGmz*#-|Kx13_{af3pYs6pj -mkD$1O30jk~63JE+mE=v>8&Hx$Sh{CtQ*Yt#h7+rWlhD_7CONd^lopzIEF1dSOt+X^Iz1tzl(N;`l;WjwE)t&$nBa=lyBg=xinm@Hs~hWdpEl&Fc*tXc}5y6h28Q5pnhp -mavFJ}5SDt;D-lV4w)Uk@*gglfS9HL2bwcAH7~%ZwJ{0rJ=*Dqd@6aWAK2mnY{22;{Hh>tot000Pm001BW003}la4%nWWo~3|axY_OVRB?;bT4IfV{ -~_Ba%FKYaCw!TYp-R+k*2@5)c;{g)@W?$7_YqNYEQR>F?6HBz!adC=ZjUq!IZkFqE8h@^sk?Ip3H?uY -PU4QheMsS_s*4;$h#uJ%0J#ua0zGlQI70``w7uxy?*uf>BW~n#A<)}=2 -!o~pN``X&!7J7`1HlgKR>j=kK0bZ-=HASI{`iaIqsKQf --{YSjUp+p>nm+yE%a<>{;?p0!`0DZ1o5$n%o8x=__~zTc?$`%R<+DAN_Uzq{KmX%ze5^6u|G{OH5a|HukH`0(?O-~a5hK78hs&R?f;rsMeHGye2n{dc_o@$dg1txfC@W555!d!PR+8uITyJihuWg!K8BFCV -w|g*YK9-#oqk?)dV>pWE@{>!*KHDtI7^hI1=TEVSPvdQ`Sz&zihgV;{c*#5e$G30ae* -X`@`0>Xd-+BD{hj-ro_zyGv=DYaF({KK1O(5lY9KZhcKON^gHRqoATWt>as1;w-fw=He!c(stK%Q@JIiW4i>b!y|MLf5#V2D*zxidW -XZm&g>sSAHzLU;&tKLuFhc$iqx1RX?OVlQ}|AzcAt(V8^SE1T(-lBfr{qWVd$G2e+H9KLYp8ftA8|69 -u>GMB+`r&);e)Ol`fB4zw&p!O!7oUIl$;W?s_HO)dEu^hIeec`nPl#fO;lF?Kqy^(xkB6VfdG~i8z5l -1rKK$SBvy3wOUmp?5`s`1ifAXgfp1uFS{`ASS-@pGX-tx=8|GTig=^@SYd`Ru=53zvukZMT}Vd3XPyn -4ltnfX_L7$u$Y!Wi+sGe4A`;>~fY4|$&P=ESQ@+hcY`4&;6m)Gv3^5*(0|&zr@tyE%Ck*qtvs@k^h -jeoWIQ1j(tc$K9(@~G@ayg6RT{D_a0G#*kqBX=iREPCIajvi+9O| -Q>_$(l{BY6nzByvY>)_$}df@4?{MfKOTV_`A**W6PVIJ7O_*=?O$f>n8@;u{&V=?0)pDl)JCnpmF9DV -w}cx2+U7fVPntJni~oC7V+IX%Q8nN^QhyF0|lIZkk}{9Lb?+7%}gKL*Q>Gr!o~UK>AR6Z`3QPEITSR? -1+*;u&?lpbTxddrCLw^RvA84R4e1f>BlKvob*1y**L*8; -)U~yX}G&7_9~yT)DSRN$uwGs$~6$>cp+vM&rsk-{2Fg=Jcy!X&Pg;x`k#8kzbb7}Fk!cqr&pYxWwt -H%k(io(oc|Kbzq2TGEfwu#N2h0~8?49$t@DtZ@cib{se^D*`+_AkwA?2%`jU}pbfWR8~obJ16beCQ#H -gLXHD3Oj>kEm)9v+C;(<%H&SYko#KBEze^2cyD}Sgb0K&LQ^_&8big?m>M#PJq>()Pgile>!r!H%_o2vkfO?ekJ#yg$drUIc5z|#BYkW -4g4yzY39?zKUh7V`?r=wtL@NZ|hBAh#7!HUM%BiD|t%PKKiJ2=ajMl36S?JUMYXGLD(K_L~KTc~{+Au -l10uFZqzX({iKdz@fQO;JWQP^%iNj6c4|eB#{Qu$;i%#neUCgQb1uGs_7u!R9 -8^Vi!z@*n;3^p^#4#SuzlQsVS*mJE!3%{Tom;z0*je}4(;pbdIIYIRu@NESy5q*|)pK+(=2!GR*Qsk8 -{HlOlJZ*U^)B_KTz0#^68wnG1uE@%SKocEI+>{JV^~Li+zb -t^e}i~9epz{l_O(WvFj=XW)pkgRNYYQf^&_-I`_yTnV#KyhDV8UCvjqkUh&A{g$tpc*ploaBY$B_c@> -8ytOz$2N?iBIAek5xUBK^S9%7M*N<1heOl9X8p(z492I@ZV{87x;!TwP7L4z -U10Y2g>9R-ILhSGu+nqmSFZVg@<4IE6O!0b4c_NG7Cv@`=Lmhz}OCW3-Y0NKCV24a*O{!oL*^a!%Sh^ -eD$h#J{#YXOK(?tNMXgo9uH{)i7U}G=S!DdB{_f5yuGXOC6V5@$u($P+v%UWRMI88G?kR;oM^DVu7ey -My-wpn8_JMnPfkC9;Yz)=JBwrj9E7}}YCw&^x0B)HR6ABLFbTrN0SFBcq*2tA3jpb -EXbLW{PuU}bWa53E5pX7qN2o?@2?(@`!bcog48Y;xb;rb(BwSXQpa6Wx6%+46n6h;+53Q*B5s0yh04h -!nZ%|l5!6{|%a{)jmq3IQpQ<~ -ecYS;T`e-`*;Y2_ys5I4;dUSfysd7GxJ65FiGCG5IWDk%z}(Vq^gjr(adIsrJ&+if -iM{-hNtli5H07%W``xc0P48K*mfcvqNmB<1X=q8i%2GS;L&8J4MTws;77_D>11ex;)E%UCs)YfK6VyYnodEhP9vKIPybyh&AEA@8r%nqeMlTffnroI -jttD&GeEB6x4IryDY;k&Ci3>Mbs?EfSPIfAdM2<%LW+4I_R4TLF(}p+c^0!7zDv+dX58FU8;ipf)r(4pn?V -4d^O*sI>oUvD-4`fpc<6%XwCHEMps;S~=Z^YP|Cy0G+jpG)p2tKpspEv+ZeO^Xcz7LbzF|L$Xkw|=iEU -uu|S0e=m(l>@guy68ij&oL?x3@Lpm$Ql1xWvMa&+Z39|&UoCw$4QrAH;p}#l>U=$cB=7X`s`gqbqF(Z -4FloAy7EMgiB6xO>K5D^>9?X9{wnan{YHNFwKRsjZ%3bAc$w!q;uQX1|CLDKL5+&c9f5ZE_lEq)|^xCF8!pp4`2g~En$cm`PHi}AIj8?d&HOhoYWZh&Nl?kNC%jCUy|Sj>c`kUcVVGhK -OHqTG&URW&j%m<#tULN;T*VmaZ9p>PwJW_))TMv%wPvH_AAfS -oX0VG8h}1DPCk0cOJRj#0phj%2K>SJS+jQo(&9B{)}-X=~&Ok_jQK425k6o+r~qxLE?!YQ_~2IJyxjZ -<*PL`!T~qe2R&gwoh<^WHPzoth1it&VtB;RR|T1x}0l9nMiaCA@ta%XpT@nK2|{CX(c!r86=a;23#vE -PRt1|!3xA4V7^e@7D}8+Ob>ukBD)%!8>_@~X241ON@D9q1ydw*5MvKLakDmII?&89KTfPvsBY -n06_xvMGVUiV}pX%xUuL2$%KxG;K8;<5N%+B{t=lj6q2d7xT6RM3oFdtj)OM!j5m*m>`*IBH& -U837wXbw7H}5HnD)KNg@spY3k^CBdbeFC3Zt0?99)9v8SD_ -Gv|Txvc@uZZ6b_ZCBK0jT&Edkg$uE@D#MvyL;WB`&L&{-;wO<8p#q_KEk=vU^1!yw7f2>X0Wl_RvH22 -2UW7u3H!Zy#SWFNFu|`b89d`)>#{wiF0h_no2%Frs8;(ctgQg4|6$#GR9FJ#ms-&oi-U&ShC^Eb~c^` -mMB?mx&KkBZvg^ee(oz}_t7Wb41Epv^;QmSZ(R9X_o{FaR4iUbY>Fb2zg=S9O)po3LhM{;>+cgX|}3! -BOGo#}U6el~`{z94!O!)jTdaJpNnY!OdSHqM8rJw;#9SA` -gu2oCm8xxJ#Nfv#uJydYvlAZhMPQ6vT~8scw&gUig1M7O{}7D-E*G$!Rm8CQ0C#Lzq0KvwdorTE-(*G -B{6$MY>KX~Q?qF$ObC(9BXy9Iii3!bY0;KXY~LLo4J#61>a3LSIctI1K{t3d^p -+|LKB;Ck8E`*TV?|ZR;n%O6sn=Mp#Lfa!vKT_;@6DSX?>_UFw_FV*plm(y0nlCaDk%PflQJfWO%YiP1 -$vyu^`l9Fa>2PHYqr~eFoSJ4m5sjO-WXl0D*aD@-d}m7p!$;H`b|XjL2vfmqj9;U~ge+;3Y*VLf1X=L -NeXFsO7HC5A;o#M~0OB3-<{~MSCXsaS&cD>ntr^4c>>nx|W9x|4@ysjAC?h29!i?IOdClX(csDI_5x% -5A9l&5im3(L>4x44<%eBn>DYo7`6&Wshuisakj -GzJL=!S631ynexVNGLIe0NETP(^oFTckl5?QYj(gNO%1BMB4bb; -9)hWd5;!EgwkAgjEr5D^|N0B{PtKta@`!NQ#GcQz$JK%$rcxD3y#b)uo#BTPq2}Ze$-xX)EK2Cqg)-B -lv6EBZFjeHxuZQF&-g6LONql(FH1E7SSgtt?ASaOVPn=%0Ezb#dTYrOVx^kh8Ou^3WeMfY#qr~g5U#< -PbkDesCrn|p|F|AX(htk)Yh);eJ)m)%w@!Q00qOPk3M?zmSA{OYXn682Rd_HZZSEY)2cMb!zkGTR5uL{@+CQy4W-Z9ch|hED67N@7= -OT&sHQNBaRqTtYv>^Gypcqx`krnoqOkV_p2n+n??x5LjPA*R$F+{^6)C+$!KmPR4@}FT!j`G}&!awAlL*Bn7`PXA(qkm8nawyL7E@^_qseac+tyW(OzyHkNFbg-t8Dnt -Igi0UZpN -?#G$tqd1Le3+v%WNZwUrWyF7GgWB@vZVG$@zH8uyBK;PZaN~^$$m0)g`qXwK@gImxvZXkX1j5%G5)P` -7pL_$WSX1UJzjNgxPJ+_ik8SvdF4WA;u{LoTGs4UyQ9Q<{g`PF5oX3P^9$ -X{A*hKx8=E8T~Y(mA{>P8<}3#WUG2Sx2(?xAJw!5Fx0nzYa(xFgYMel;R#(h_qxSd$w3^xJL%b6cAa) -Sf(s)2Uf_j>6i0^me+j-prcxigx(c*j)}(Ko1ZmUdb_r&Rs!$gJsd9>#fmrYI;1Ta@dn*~g18!b?j1-bJW|M5xLz`JE%GLPVY~W-`(lQ6JRk;?IQ) -0Bk?-P{qJ1C%(EbdIQP7BMDL}aA~;O{D%8b#?>=fzA(Z-*!&ju~H3?~y?=X%RN$eE|`Tf18akW74nXhK4#L92WVAe~exvcG{s8C32 -Y>LPiBT<)N%Kgd64fKp9m+l|Heosv+iNi0MP5w-N8&2E;Vr&fjXGNp=zl_`6+MI*s{trYMcS;lW6OIN -^u+01)eG#m%OV(PYKaH79dR+7Z5QwV`BU|L3#Msni~8NZo4Ql+Re*rw4mbC~c+3{jPA;#%l-1rbd|h8 -g!6FR1av28Pn@9@(5sTIxr>&Z?mND~2blktmSG$`Kl(C$iX?G-O$%d2$p*%i7H(Y^js+TPg4)ii8QoS -l|t36XIj>WW<={z93U1{WL-P3Z}BZ;$jE}>UHn4j9)mP1QxsxOi2EjoJ;}*l_q_U=R%jQNf=7LbJJI# -P>`)?X0hA08!~>6Ljo`Ut|$ZsUmWc-rmAZ{dHC7xc<1T{lS$(d%6+%0Px^2oSk8cBO9Jy=S?P+{ -+p&BEl9uFqzVm%xG*tK|cY|%C-6YO -~!A6S5+?22oi?oQY7ex$x&2tm_6!}`>=^L){tN?M5%+C%^ErD2QQ5 -!d(Zpiu4bZCGlo*?&06Uy0ZMu3(6B!FvO@t4b(?mjrpfqCP<>L?G4rpc_X*m&M8Og-fGF#?&~x+DlCZF%mM%$KXX_9obqcbUM9mjCC)-D`` -Jzq6FNHCXubmOPS&~UubP6q{*f&O^qDfi8EjG)>T3geL_=SG@@NGBpsxCGEM)IP$8=&E8(Gfh9OzrwA -!hm+8!~@pV=qA(g-BUonk$IExn~hCJ(lV&x%!*<}HziLxhCZsq@W+r)tPYaLlms{zSIx}qmW{>u)kTw -W7}gDFAW39}5{g~%=Y!lZbUZ31ME=Q96cu-fH&@NgxteusH{n%wlGOZ34A|KofqMprIR>C|sREO|yXdBwAOE$JRj^znNe(>C{j2W=!%j -hJY<%la!@oqgkMRURggN3H><9beqKJviYJ-#&03=8hw$QMcl|=GB-l%UL-^HLGYd|f)t}H%(Z256+*9 -ZYl@8DLq1{7aK>qMsLw@mHL1;35N4Kg_oj3xA?W8Obi*fJms!$ -t2OJ-}aFLo>u$sP3VRIp=7w`|DxP16*x(uwU%2JZF?Wf7j5%#M?=x{NBTO(jf&khTaaPvvFHhK%2uR! -s?t44>#$rKeQt%x5VLl7oUXTdb+Gr-%H>ST}D`kXZD+&oX`!vQ}4Ln@tf0P7DREOB~AR`m)Q!3>paDEp|ob_151wWMNb@h_h(Rgf{1-$@neA3x$GA7BS{EHKGK{j~I$70Egq6C$6yDa)$@TC}k(E=;5)!8>1T;UhFP4W_dx^u3I%3zu6{C*gFFP&4A4^%;2 -t|kZxnNc2KAv79ycy7WuYBSwjxEO)BMdW}*p0I1h4iA@rK>+{}* -(Ca-3eK=x6b=pgNhb_*>jTqw?ass|<9FEXaCw5V-?K|_WME1)6~^9^t*}tq?JfkSToT5!DR12Ij_8|= --wZpUWPLYCkTARg49CjRt~O9`q8wN4J;c;5`&fm=7*S6-#;&zB8NbEY`P9N$_$QreNLFQ0+X28_szqf -ygj@{}R7Niko0+Ho+WERB+o?H@A<8t4KqpDd`38$B)4>Aghlcv4RyIR^7<5%5MyD# -geavavgv6BEVnJ|}uwrohk2Qd;^HD<`KAh+G8*<}2VZbgjau~@fhDcWM9EPM(K=OTeiin+;9eiPU`6EYUVTy${QVL7x&_ -C8o*vi@PJY4`#mvQ5v(^J*~N)ukrmw^oajI-4##hSRtHMkH*wq!}jYKk~|)5F<)^yCmF0MQZNa)|AEg -1&R;mQig=Y%L(x}(uC>0_>zT8CtKfv!>=a)o@ -yUB2mV?qX8mp*T#R4)t-2OzN(Y2PHO-5{=CjO!LALPP1@B&5qpa09yxT{8m#8!-76}B>TH@% -!#WM3NcRg@MM4yZf1xbSqA6yc&1bHEn7BZ{KD!d*&sVhBLmz*!YswpreCY(mE4HE|1?MEu0~zj1FEH` -J;qzRW&9S(Nf{rXDe$Cq@F(7-`7vaJ+$Ke-x=s}X%CBj4$e3(3%oz8`!+5Zx3j#D!{HHKQNi?hi{dZF -WNp>{PHMz$Nkklfpj)CPrt7aQr@$la|oSfdUhuX#6~4ynU(9dqB4GmE~d -*VQZ;~iB)Z`_#v>6f-6s^<1Y0=U*TD=5tl~7~%iDvndrO;)-y#nWubbs~EsKOQ*^h0vtUOiN+ZDRqp= -nOCfPo8`jAB#Hb>}x^{AQ3_rqQ#)!yBe(obyVt5(Y8nQY9#}_qJ5xE9we3teYB2Z(c#WRu?vMK*FV9H -*zxHiC#k5tJQdw5LBL)-3X^Kgb+tK<0S*S{IM;+jNb%gk6HPHOz(OIaft(JduvqMa%JR3!W$oQApc=AZeDz|N$c&2jdtmT1vwA= -Fcb5)l#JcQg3ItSIcME*Xn=u_qenlikoXKe|4YI~EJHY+B>w~Re9NG1aUhndQ5kp_b-oFUsY$Y2aY^I -`+BnUiAr4*MsW7V=loNMGAN_r>@%%stnINDNAlWE|zK8+0R-ECs3=tBKNl8pUD|kB%9VQ%##?(a*(`S -q;gSm+2T`bE;=VfCYOSst(p0|0^>%nJ+;lhmy$YLwTsX52(xd%@7!}w**Pc!{HXV$pc#QfXPwlhAw7T -mk@g4i`)R!fcVYq<=sWnW&9@M_(D}H4hpYE=u5(-N-UQaN{e7;f*F8S-~kHPW+nnQKnEsMtXE-D%rp{1%F$2SzJ-zm -E(**sh5jN&%cC13;J(nFME+o+KhO>8TM+Yjf^7TV2X(6anfmuFxWZc!qf&wG3O=Y(Uh$SobR$1yr2)* -Jky(@pG5)n=Q8*@*wwRO5?;WUN(w(>4@a@q;R=S4$t9LW@S96A=}x@o)?kh!f^VF28Ny9wQ%7i2ymoU%pMpB5K#fH+Gm)m9h7O!Q -wte;;l5H6=#9LiI}l1A}gWU`nag`i|xxP3NKEcK1oZ8v26R*ASE#v~KQE|+e9nNHol^2?3DY?`|Ab{I -G@mj!qV9>qIX_N^~n#_t$15iXllEbw@d8ljs}8(Jaqu&w#@_9aVpyL%mv^z4NV=RGK<3Uu^s?@g5zQ^2scHb2!BSaDkc*Kzq<1D$Nyab@^#ezL8 -kafo&Ase0ev|neDU7yIc^d?!=*AIp8qV$m(Y3s1?>TY)e+TPp~W`gEW~wrtmt3P{Ud;QKgczd?T{km3Bh-MG;&VK$$rAg?r> -n9n_AS^yDb6)x$xNa3vNzJeNwYN?p*xnR@ot2vVX$i*(x!8NWlu2Zuaha-?P-l`%F-M~xs!%^uzzV*< -MLGmard&H^%8`iA4Lr8>H-p*61f{+!4)$ndNhbeiz%Z@a=jNd^9x0)4~L* -)$z?lYFAOqoOg0s`$Z1T4BS;i?hPFmNJQuq(X1ZY0At*-_wCWM*8E(=4o*UfSZnI5%=t>!uKV6!qFMR -+BQiaBW;C<2R{2ww#zwfag}tfM*#;Wb#-3@AU3AXKI8-C5~0DZfF~(f8OVHpN!cB+YZep^J`jjA*dG9 -;L0@_cI^X14mkPglIWmMv9ojEpweah7E<@wgsyiT09~@TC@hu~##icJT|e}-<{qG9iDQSK)gSE>l<`Y -J9a~}^jwBJG2fYeoCN{A+=-789dwuiqxoO!5D<`Tm49!$yjZ -|eo>$l5_^QQr30#{K*k$}4_`&4OeP%h=g*2DX5K$t;OUSqlgDsa -X(s2|8$GyEGoYK#Xn4MPjNALQ;!uB+p9I_T4gmxrdO0^2RoBiM()m@MLwTHDQ+EEg6Q_*_J@7bL$R2O -@UZ++l|He)pOEyc@V%9D{RDwc_-uW<#iV#x+Q=^hza&sK4GX$K -UtQnZBG2N^SQJU8ZFj9)-6?P8p?schuHJ9P+0hV8|2cHoWGG~O+VKyr!wY$T1ZOnnjS6J^R^+PYb>)_~Rp5ldT$g2XHru}FOXh$K67#2|`ONVsF -VxlY+}WNk<2MljCFoAM*|7wU7#5I8Y$ek`x@b3y{CIZdJY2Ly6GJAcUG6(@x{Ti}U?G<=Rx=e#kZ=#1 -c}!Wm8Zr_yQUK@|FNFV9L`IF79t_;)wi_~jvyFRlx8}OU&MP#*=T)%VO(}zFCn;=7B -3kmY?3IR$l7@}4`&O>L7{8R>YPNAjHI;ww?QzYa8dI|d?rE_l&Ff{%Q~Ng@{ZOOsk;lravAfk}p$6=l -H?~!8@#V%Uw8aAmnG|&QlqTXqRY}SN4z9 -+ED_&qKiv+G?o2TOS;cHmn<}&iu~&OwU{kFU>)5T915}Uc -5-SCL_5RlzP%TAdjHyHqIMa-RrPB&YI~WIr4$&+-WElUvGB2K7Zd$QWho*-zl4LSI1XRkctghTu-anb -5Q|i;x{c*)5q_E4GH!Aqy77A013s~%wjtv;+on2gDt7t)kfew%WM7@mk4&4O!}dutxN5- -k2ljb;*s&PDW|*7KfnXHeK1c`Fb&G<+fXkv7OXD`b`et)MmaGtg=B|}J^12xh=epSHRMMBb6U40DHNf -|pKisT^SF@LZ?P-+YA*(Yz?UB2;Q+h{*J??-L?=ti9ilVIP^6fV*&RJ(o0)mW(_$zl3|$GO53MN1rFT~l#$x%heNUV8Xj+l6rJd&eerMxE}B6uOAKFD$&lu|N)w4 -8Pl(wpJ+6gQh?$oQ?^;k=03Rkjl6c6lW`?#^4Fh7Tgy3RNH(bV2Z;S9N${=c!QdJ8*`K-{Mu~IJDwj3 -?y5}Wv37ANCZxmO8>Z&gXF)^eG1%GR<5-<7yr6P7RlIQ)C7DOeLVZnX?lwSfHcFXt?Y9i>uFdn;!yM` -c?psI*w`H+l{?S#%dLG#cX3HDY!vysnYyZ0Z%#GCXKwv#3EN!+nNxVrfwaS@mo*(FTIl3sKd* -S%~r?@_Zm#E_h|A#yxvH40s67oUSMggQFq35hZbS5DTEDV@m9NkPy$bFrlN5+;k=j;u2oFGR#C9=pBS{Lt02GAIR -RB`X#x0%)bjdI6g{Cdf}H`S1>9dM(D{afUHsx6v!JP^Cow(N^~#L3_hhd0Td_G@f;E~~mE#nKzXh?EF -wl3%z$_+PzOaS5vTxJ0=W1)5(gv2L2eMSBIGy|2^`MBO@tghbADb*lotD*KMkY&g -kWFiFc8ZNKWaO$oUdi@q)^$bi>F|4G8NV3>n%9O6&jVwmN}AU6J9EG}&AtwKJT^XBzLkOueZYJ8uFVV -?GJdN)yvAyNSA{e%x&|wxkl}S$w)lHlpf^=}?F6*$1phvBo57%vJ8u5QXbZ`BqlkD?Qy_%k^d;~c+>- -aner*F+H&wqGL%(XCP%5xjh?LDa88UuTU$-`)*pj-uPt_Y2&H8nv4sW$?{iD2+6bt|6=HT*m1iMFU$o -MU%Uvz^>vvch-o9tDfe$xxZY}sgfre?Q0O6)y5_PeNR@PX5r?%j~_OAUNjCni$QRaNuri<)9fS_xMg!Jbz=c#~ -6>?-=i!>&9p~;1*T7^eN02UYDdD;GW&3EOxoTt%EXtv%Qwqwm~h`%r-Kf?Z&6aWS(AUB6*n9MwN1tIG -)6KW~V#*va^>%#_v20(s6uVJK^`^RPWD`v}|)*h|~lC&C{Dpm)&q=?H}ODm}&P)4;jDHqpj<+Y@#g=! -wMydqqPJ->%Pc)Wv?ipkXoB2U@3OaGv9MAo}jr>@-I;D=K_!*P>9wQ0_OB;(X`$IP>OS#fS6=VJWYATXW$3Dx2#IeCC_j2hb*ie1thVicXnZ^Yu=f_A>((hyGn2;#mhb&zW9T^??&o -8$jfU@;9!xeM^*ZVjqE4GB~#OMau1M$7&;q4UIeR0lQd>~mc-XE~A1>RXVjb-$U7qxZueKOjs=E`B1dVw!bBWGSAOV3lQM@)kGpQhU=4OR(jQ^t`U -8JjOU)*Zj(uBW$kOKx7>qhxC-mQ=e3rnl6aA-&iGrC4=oZni&cioHknW;{}flc0JUMNdW9&{yZ>o-Uy -#*`QTk6)bbZ*6I8L8^5G!+YK4NHOpcU_+K`FAp%Kb@XIm%ZH<= -|_-^t*X7;vm_z;R^!8wuFcEjCZR)zeg6y2sBOe86sC1V3G#B*V%(o%+^g}n2gKeIZG{E_WQx8b8gnqknwvEJ|t6mh9e9x_ZMn-u -d{RJd_C#OI1N1g)WBP)fgC^uoW=9@+0*B97-WZ@4MsEo{aOM>;K4m^~*)F})|%dv?53A68DO>)v={-N9S#Iop -NZm-QinY+fPkg{*)q3>2~H^jgxqKI;#M=Xj=H^;G#A7-{D>ri|ZX$_5e|;FQw3AH=T|^lP@5Zt~6_U8 -OViqIh5MN8txyLA`fFBm*Vw$P1x3aUfIj>khDWmye`aBGb;>*hM^?40klnwRIq#w6pP3#_zBA3fcbyP -)h>@6aWAK2mnY{22<>?$tXSp00038001HY003}la4%nWWo~3|axY_OVRB?;bT4IfV{~_La&KZ~axQRr -l~mhqn?MkKkJNt{H7}0j&^T44wo#>Gf)lI039zC(p*0NlD$6d~T@ul+?<_WU+Spag6U^nzoHN6mpC5l -<7~YL%Fc}BoEDm8fnFl}MMC|#yvvWu`2y@NXTrvTH$`QDMQvKvYFi+_PqSM!(qch>8&Hv$SmftYFf;<#h7+rRYS!#7J9)248DB%>@beTd* -BNJkqb5up+WtOc}FKu(rUh{tc}4O1w&Zb?(lLDn1K1xRK4@S-`b5v}5zF*}&Ur2F(2WL_UW4JeAqCqa{lD -SyNZ!X62wbRUMwSQk3=UGmlSU~qLg_;@t{SjNtD>Va@}`;XU!6nb}7XjOt&uCfi&25qI)id3LUy5DMA -3(JR%#elpq+C}T_lIZYoxi*#-uVmSVOYHK3))PC=bnDsY5YT=J-HPur!ex*=+`e-7bf_BRj?}(GW6Iy -c(|DRr=eOa+@yG--W^3Pe**o66yCQT%Xi*ACQ%>h7O?w7K(K*~>YPw9lS73c;L%e;)#j9ZQ?6gR!!*5 -5}_kQp9&*ayFq|6cjNi+C%T9h~CH62dttXunc8Y3~V&4KG~zNus-zTvCU)>^`QDtMVZy#EV~U~*lv^= -XKN@fRiu;ula$0|XQR000O8NLB_@^37`}iYEX722ub3ApigXaA|NaUv_0~WN&gWV`yP=WMyY0p=1P}7lW3LBO(;3kW>QY*H3+4Q*nSe -z>FVcl4oD~QnhN;s_OI6N5A}E`uy?lo;*!oKl$SE)8~)V=U+ej;=j_rxb~x8|LUXk;`J##yS@D5<@Lo -?`r_u*DP7*BZ*Kl}d3ALWzrT6&?)viO#r@4~dUCx3yI_KiMbbh)!-TvkD>ce!txVgT+z5MZA%=Y8EPyU@hrS#3k?Vr-Omsfwhy?m2CO -)<>-bbph+eSiP@=KAmJ5Q}zo`Qz=y?R(bmr`yvh-QE0j|JNAaZ`1pmcj@KDb-F#hy1ZL&hy}S%7uT^IhiOrqgA7?%V%zy1k1(rSe(+@VD|>CkBE!YAD+DU{j=|0q(@J`Pk(rHe*Wm`i| ->CM7sranr?HjmQI~JthDp9kF|*r?>-+aHcAoIfEq|m(^t>V)1&n5q -w^O}zWDCzN9XC=@6Nw{_Wbc@DLp@(J}k6L`b%s5_l5o`p84h`*7Mcr{^IiL?!)}QkBz>IL0-K|uP^>` -iVc5xx(owL7vVN<-~azM^XlgMk4`%7`FUA?n=XG!*EjcP>94n!VMbw!|Fq3K=I5P03om&2*;(p2uDZD -X(^c%m^SJ-3%b()eUtQhY+@7V+Z|?57^qWWAyp^1{PjlUJO5Z)_Pygz_^!VwQ|3|cm72?^y`@Ga#V)^ -dw@smHl3sAXwj|sd=FJE8WUcAJx?k|44I(=}<_$%{_IsW`VZfkYyZv1` -O}9VKZ(EAhmo9z+sCl~`OfROhza~AeOzbn0XFg5Cq6It`N75BzYWy<#TQ@vhEb)la`+k<%jAzfdJRNa&&7;KM+IH5qv7O~3?kUF@@lTs)we -MTJfS-0~aOfH)HSs%q4<5fo=F@tzj3#-AWVzm8Wc>8{qW8i0HFEN+49r46e8 -dvhsjF0j@V_sXlHqY6(CnmS&dX{29XF0CnVKLe*9-DiNtnIwCw0OaY(Xftn#N={JZr@|VWgjun9*^iT -vQkS-$qAQuPR%WrWAK8!_ZZZSH`ftU+k1SuUe5B^<7K_Zm9xg=dXJw{XUOsFa+G*!ENab2R{dmrZwT+G1V#uAXkC( -<6b6g&7RAOhaBMhg-Rg9vu*W;`;UQjbrkL4=NFr`?t8b8K_$`Qk>Ebv^`6C2%m5f3!{0FtY(2LlX4u0X!%gB5ISjCl?jm4ES -nJw|><(tuvBz^#Wy1rA;>NfqPZnW|ImE8V3=4)F?>cL-ooq9k7b_8lP`J0UPT^p&{#wt@bF|@jcHUxp -8iR^G8W>=_o6Ri`J{lKi4X|M0tWGRc+#9b73uk9yE7-#t1IVn|I9QO0FW|W&mZl!@QynF2qQ(c|TQQB -Dl{jJv!$#wMx!@g{Cl+=oRtjrAn9Xo_F^6`5s=*L9u~59>I_7Iu`z8Y8wD_zOzYg8^vq!N!faC(D&PtG -Ds`x#R!w`WEZP&g}7d*a8saR>UHu8oSWqxo3UD)>*;|QUs31$i`p{7(DRQH(;lSM}^^OkNIFz!luHwS -iK#`is7XMW^OFk2-C=0IBIwm?iu3=fWhcM+=OKwc+b|0evP-su7CiOF~&a)5AT>*1zq!W|6?Vp5SlS2 -UjVM{U=OQY`a-joSz`9}i1~-9hd0;VFcAM7VP|0#Op_tw^%?LFNaGQ^I}>2Cv6suQBm7l%f!S0nE}j_ -9hHEg_8H*Wq<8v~Y*?1pFzzZhkFuTuYpncOGL8;DMJHFY&#PSha5f+z;T=BP-g%IJ3rHwsj;O2T9t5$X<*2i4`v0W!m0&^SRjw!RCJJJgBA#5H2|z&{`~%oXo}8Vry*K8;yd=#3$U&kM-i;8ellFwcWn2wa5w -#9YHBvIZ7$hlPp15iSBV1nRP4A>jmQfbABHKP&?h(cDrjeC=k&JTb~$-UAB9oAZHz6~a>>m3|HQ0iAI -XCRT*6n9X5Wj-g~AE&NaNia2+uhVNQJ9q<2s?Z)- -xxAYAgqFsBWuVy~fX6^NNc -H(rVS$V8#f3*yA}$`BS??V#)OYO>o9bZ@u_u$nggG!*0%8>bz`|0+YpgZW6bzo*;%~8-{1mf_t<-wh$ -i#9*lwgcT4YQLesb$CqWPC9HFuS;!xeiSY+DSywTeI=H>hd5-V(K}|XW3H7Z)Qzm24Jcb3->)XSRp1t -u9O=n6W4@2u6(8gbRFa_z|z_yJafabqy{7QI`PC};208S$VPK*W9wUyM@+_;`Cl*sJYYA_!EDU0812B -$0uew3A_>+rjTyodW(=CgxOl97UBJ{r-jKL5h!pWW>#AU{^I|JB^8o`e#Owp0BCZ`IbsG_-xQ>}*E<< -m^rzRF2+q_roniwzmA2PRTrpaiDT)i`OxUg}3Gi%xw_K?h0R#!%z*@Yv}ETSUua|147KY|OAOBNE3Zo -+^A#vKu_VVqqY5yQpL(M%`_^bl%E-N9~c?gIZ{*Ree$%yCB>Of!=K>?|u>pl))r2mnSvvQsc6!*Qx<; -z0s~+mYymKgO>@jQ$}3*|5hseYWq*W=O0(5ulJO6z)k=HoRfi@YNM!u-46_o>h+6K&FLZFwit4n~bqR -^a4W)9EVhH0_iXS8Cm=YpV=TI3~zJ8D?t)EA$1;7L*jK=vG5?vRZGyC7k|LxKOiU -hvoA0RB10(s`dns+X)6RZdSb}nwJGpUFG=r~>Kw6qkM8GcRPT8gaii#fqi|qVxh@17xx7Y%XsmIZTIKz^Spo7#Mk9E5^c#FC;S7$i`)?NCI+2 -vmpZA1_hn4A_!3!B~DrJ2_+E{_(2+kLI6^rI)H_-tz5*?bd&73u|hX9ww_dM_849xKxGg$%S{`GLzWt -zXuKZmQZFth`JP}y(8?qNP{O(yVu-?xq(5dvlC?o(1_?Z#*)a26G#i;HO_(5xXBHtmfI-2e+U_=^T>w -Q|A%VPbTb46rXz2vfrd}9PlRO;)gN_r}T*#o9H8fzCb7e3?)34eDp?a{uhxrOKz#U**=oALJ;yMzgv( -y@Ug>z}Gn?V8v5gD<%)TDAP6Dd*1(r#L+7X~(|Ffvf?Ve0WzpRMRmNtRXsn<j*(Vqi} -({aKj=zxoJP2Zv7@&R%8ifCO-W{3j#bNdK^V&DVunyAD30tC}I>I7Quf0T9bSS=+LNV(iE`Q>J8$*;L -rY6dKX-Dxm?o8T+sD0rv2!y-QzXZ4X>ux`gK?5)>?)l(3RZ;v@+VC`;BuJluA5EEi#dVZ;agqgT9)`D ->I}f-X`N#O_2)sZ)}v$_4uXI3ibX&_tsUYf?=UOi*gP58gLS>JWWrQ%jlnJ(^WQ%!nJw@(&pjDRVQQh -wZ7LHRig6IrGAbIbgRX4Gkg%4=cJQ8hVD_UW&`H-BviPaaxIBhq?VGcFbCL7E{k?Z%ZTfUtScLy>OIPA8PP{1QTs--4cnV|7s#db3|t -Y --t#D>`cn01Q;6_K9=AFs}^UhIaHUl0CS1O%5@1LV0ZxmD*}1E2Z9FpDI_08g@aw63Pmhe -tWMYkzzNnL$o1p`@f6&+Sp`TeHhj0BAr_WB!hU$}GQ|zL4H?_2$+3nC8B@%r6t*jq8ULCVZqZ2n2^5O -?8@>U5BGTYWOtzq#1bwq`hXES7cV!a(L2elPQSVVA6V{W4piL6d2| -&}VdHEgylTFsa9@RNju7v&=p#kp_mPu-=76;A{SW{LF8p_Q4O3XM=)ev(NY&TifI2>an6tGx{FwvFTP -k^6cN!-6})-5IB@|2qA~g4evQ%yHtUKQ^9rW -;<)Owj1hayyJ4Bp9{BnWayO_N@v}nt8l1W!j#TMw!NO~dyXS=zAo=}QvVZn$Bj3tw&MYN;%G8DU+Fc#Gj;Yr5>JxTeXm}IsAbxJEx-f9AC#fSKjDQ84DLAb -*V=FneJko+5tV>OBBlJlyK5`~LWhIN%#J0b=7wF>*h_aLyWcrFT@!}J$1cS*+3TU>+mrfX4kNdkZb_T -QG4(h(O6#W@8Y3eAO}9Y(3*&-{TRkg4h}U{9g`kP;vXe-2~@LdBlEnRDQA!+=R`jE^$PXgD`99{&)&j -6&1{TGLvQqo<`%@aAD1vsF|qps_TG#JpQdRxK2~y_KncsFrfAoMP6?{j0=TdxXT+ -h3gH;5aaDs?=Euy-Kcb`J_<6r -?h!SXt2kD%j_s{=%j-Vg`gLBOX@>Dth>#?HNQQ!W4GEFpATqh^dOu;m8dSuNZH}Nis=RMW;?QY=n=xj -?k83A!V~CgwFwl*h6_J?G?BS+_WKoHTXjX5DSzy2q@u#A+1?Agro=^OpfJhEC`u@v4CEyQWs_TY1pyv -0C$*x2_U(XmH{vU@$K@NcG&H5GE|AKdXnEfXi%hhT#lOvooH5Zi8ru -^9unN|UK^reT}ML{GLNp(jWwVMmO}c!sRAoz58WK^;fYrFBksC0mZ{AZ$P3(SQnbpxhOet8# -{y54AN5emkO*ZJd&~%!O}r`Qg^9)P>__gdp6x&=D9V+lzXQ^;>>48gnX{!r8An;U0NRB$&CGanw&4lE -rRlz_K4YaH=e7rFDr@17#he1`F{{S>=4RcXtnLRQ67+sG;xM^=SLGtrB{{+=vnmIwTI59rNdf|OwN2% -ds>}9(J0Z|v(Am@RIsTcD8&pV$I!cC5~T(}*r_(y+39DhVxS_kU)^CecV$xIIv3xEL~iP8LI_$r -iWS`knbyBf8&`opm(3cPf$FeftuHjQM+--f5Zf)?QgTUDPHVOd3#scSFsLd5Cs|`K7v~q&gE&~B0q{p -HWtlHqYUCmt#LNq9KU3$;77{^-Z_F*dtSwk -(Bc+C5RZ{o~Q8P2$Owozp#)9TizXptMf1qa;4-fBu{4cUGIHcu4~U?2_1`$H$78MHYU<%6zVYYT*Ay( -p9z3)o>oak2YJAU7qPWGR{Rb -VbIcRMsN>itcvw=I5+bW96f80cZi8gjrd1fe4%>=s>9uHPoeQuzY^&73!0@$sV6<6WwVyz0jf9bg4Nd -moU=Zqo(&=GK8nlE~qij*o@`#GnVI$VA7w#4nZ5x<&BS=O_9Vp^8^L@mFh5>eaUM$VZ8j<7F66vDLE4 -pUrZJ4~pVC5)87y@)PG2Lw?uxFGWl(@KA@w63Lw4#+FyD)?myK!JPHt!i?4Lddg4ULlU1-RROr}UhVU -a4s0xoSwPx30MK9*n5bbk>TJnJw0piaB*2LPw#IxsZn?Djo?PBD*u2!W7f6ckEcTVFex?VzsocMkLq= -49KPvB5s?u-`S&??7Sl7*;LDw^3+_k@I^r_kPw1a$#uy{h7&#@MMXQ -Xm3Y>ygYr{Fw&9cz#2W#F1imV%tKFcwtB{~R)kF3ASbZr}$qq~Do1%z}oG8uIcY7k6-Qx$o2Q?&hYKN -8M8Go~3rdR(xO&1>r4MC4sSc&#+b}Plaxg%#)Es9%6Q8++ -$}To=rj3RiZwIvd4@sj3Ea3zFbpfrYS*wc1vU -#bo1kvTw`$!fHE>?3wCL*(_Z6Y*k0*vYHr37|C`LT5Hm;`>@z8vu~?0278soWqV$%ZV)=K=I}8Ll_-T -S&`f>^jY+*vjDmI+bFTQSBDGgSbld>YLqfDpMZllP5R;lT)#Oy{Z)5ATaunjw;*VKXw%UG_D2uBw7TY -TbM$#Y;5m*_)Q;1Bl60|85r3?^d7);H%^5Hb0E!g$8DUT_*;~I7&xg6Rsl6kS5i3DRa08Uw`_@pThFJ -@vkMrb#Y|J00sXS%z%~Zw8u^GFTVsnN -f1nO0rcAT!l9)WHu(OAwkix;RQe*`U%039Yltf?2W%~lBy>*VN0xNl+B1+}z6JJPXo9AJ)@9t@P4U0d -zR*~12T^?Y~^g9rfF7URt7y*2oO;R^1=M|8SIcYU@kgv_qO8uM=8R5#0{)?IZMj7uoq*(%Vqc8)ztHW -Y+asg^J~_^)&U6Zq*X~w -U}SnSZt%3O^0fUh$r;-30nH&T*Lf0g2fXpfp-sws4u|CSACxhdb0KwKnM-!LS@$-z=wqX&ase}H4sbXV@-y)&QLD`sLs6C5unK689$>5dOGK&GY#(+;h(*Gw7=NPCATh>D9ki}9N65@ -(Y&KY7vU$qQi5Wz=V%h6~hc}^do#(++?Ms=~bV1ThyoNt{3`oP_rDe5^nNt!oA+mXKGa93koiJ??3)a -yyH$WbilJ`}H!}bUvMnxO-B#w{*9h7+r`eS3p{8c>fTHMJOp2HT@lI4zN?($J=R)kkBIHR9r{1G$* -pF$klUTq%-NR_vOtY;X6{R3`175ohu*gl+4Xq5oS4=0UgF{~mC5)gdcn5C0_+yns!I~2!D;>(!)uVi> -MYg_r+=jPI9rYn0Tz!~=$S<|xhg_naYQq;twif*;s9 -seY+h6ET|Mm7!SZ3Js1g>?N$4o{7I{{X8;f1>Oeht#67}%aQA-O96l>4x)Q~-KcJr-F!xntAA>s_cVS -^#Xo{D5%^mW(K)PdfqE_Egu!FpB+7#$bPph{c`ow*2KyY??RB)Zx_WrHE{3Uw}<=+N+6hW+6=YsiLt( -w1b;EL;dWU1%IHHV%3$r>uqr*3nGrut-bIVv}~-Csmigf!0>s84JYbb7<|pMY`z@dYWOF7sC6kjFF&& -QK@gMgU!ArFkJl&dra7Mw&J(i?lC6&avURsIq&wZZXO9VZS??--49q{L0n3xyU8vZ*k0M}@YRG4=jvf -K%>`r1HkH9}mQP4z)|oR);P|V;{jey&&RCMC6RLGjWT;Q8NqW+7^XMd^r_J5A2wFqRRHd>awaN34mRh -}7@NJw?%(BS|zBX;&Mwo|ZBW0E8xkvl<^6G1~p=Z_nSrFVn-N0Ex{wuv~jVwMXOyxzkg>>N%MP?~+ZS -zzmXCRq~JxG#cE2rk1`>LUt7h+bcW!d&Kumxb)Jq_8`S%B5cWwV4TxD3E~slV7!M_5+JweD_pi?#Kv6 -lPq}Qt~cR6teeZE23vp4kdmlareX)l-G0I#LNOKN_}_+N`EI{iRk+<%uk9!_wOBPY3_{J` -gEgyr6aq4B7uUCdIZL4kL37(yy~Sy;*VXgTlvi@ -mXKbejj}W*ji&Xk5(?iQFc6$28k|Kghv0UkK!hLnHdA4)f1Or^i-6XZ>FI@^!^(ec(?$mI7VLBn)RT=_-OA8cPFJswyIEkuGNQGCH7FCJ=0_?=+ -D(`h+=1c&~6yA^_f)#n5x^wv;Ruv0J%)U697|M!tvNCn^DL1=$xuM+>AQkzG&C#ld|b#+LlZjjpZJ8! -e#SWpxWX*Nj9y|ZL>qoV`BC+V8J%0jIuBsIYMdP&{>w=L!d|R+13d`^J0P|n>Rd>V`pabGz$vaD$?b} -QWPn{RD+GD*H@w4c%|lm!E?N4vulN2KtU?IhYT09_vC_+i(_30kSN(UUu)xvFy@yw@4#1hY{f9jTt~0 -9aDd9ginbw`yJk!2aKOTbCyD|k+YHeaS3SGKOZC019A{%BWAwB%1Z6G4@)^HAVfT#q`pyPolg0U=zyt -a1b}*4TDyS%_AD&$D1Pnph`uv!yLn9-FB3yu1Ruf>-jb95ISQdq-2&Uby2T+}Zs-@w97=;I{b@i~*B9 -l3HpX{xq&{|DAJzXPhmHvp<~-KvWp>@K4 -A_KS1imGSc?v@`vzLhz8yN*DuS%|8*RX^l;-lw=EgJfqtjgin9w<@Mx7|G&wa!ZMT8Kwk3Nut~ag%8a -Ei=p>dIK7F0g*0}YQjWG1)ixc*6hbEDjMnVV4CHAr3X6-=>ss0oF0TzxU^fc?`8tW8W_dGCpT3#g%J4G!J*>q!x7tLYXh3x5dc<-k3LQ8ESx2tokZXA0`>3gPBk -f?cPYu=V~nnzTtJWI+8KN2%N<-U%kS-pUkuew6Bl^+6QXQs!jP5Nl?~VRs -mdK#Pc{uB(MDIi(bwHv`3OopIA{$wRlXz8i;VPc0?^O9`|~)aSV7% -i~QRdS`e_YrE~)D#Hr0$PwKW))LgscIkDrmSe_1i0%9E&_bxr$Lg`5UhX&Np!{ul^>Xc2$!N~7&Si&+ --&p~|k%HC-NCVQH2Kcx-E2<=k`K@qa_OZUT!qOdcP%_K*$+<`LR?=Wq=Q?CdR%z1}4!=pp@z&K=daRn -}LKiF4em9COl$JRBavr8+M20`2n-|V|7YnV$b@Yfjr@~gBeYRUkHGS2FnJ}F|>iRCEfjgl3l9eVKs -9qY~538mKm*m)D;zMweX8HumBWEQ>uz5Br!hJ&Ctj(X4?PJ-X?N$u(J(J9PU2ouehTrvTHN)fn$T)lE3n5X -m-5{h|L*%S{Xx14J4aE(G0s6l0551_b)FrGK(oJsv7g-VN -5%)qN2lA7Fxj>bgr*|IE;h!9{55)=!y-5Xi%>)ZR7+>TFn=wRk~%)e!39Ai0NmTad?1qqUudQ)=U1i?!Klo>5WO3yR0#=_pfTlUa{?J+fywln(heY3DbFewD`iTm9CwR4H;tM1<2ek` -5MQ`QiJCM`%Z1>H>mKq1r9of@3Kul1y<>exCE8Mfz9RhE<{Lmx`TF!VYC|Eo^g7LXTgWyj4J~G!1R8A -NI?srA1%k$+n@;Z&ANF!n;Ial@(G=)~AW7^C-6~ihlm@d>v>gN$!{cD~FqzN5A3wpPABO&T_H;wVh!7j2Yf -BG#y)!x^%v_P5DO$#bY4ktQpbe1}DXiEUY2XQRx?sTQw<)Us8>UclS&OEgy{$LEGmy%*;YD-0MsyWFj -M>5LC*7vMAo1Gpy+c(@J`0*eME!l95q4iFrQ6U|#=6px@0u?zJDrR3&ecT+U>>>9XAktocmKFu$f4t- -OsgEce37h}HfRg27UTj=(*0JWQdr)tEC!T~&`#@Y(?pAh%cZe&@p6`|xWuL}s56nvj5e8F4*~5ip}XS -Sj{ENARp;{VO~$89RT;OXb`*`t|E`atQ9PR5^@dJKBA7AT#D-|=Fn_m5Xphic$smq7ZKODE85CKQaE~ -czIkn!RwV|%@b}eUbswuPeBPNo!2OMa+Vi08mQ<1QY-O00;m`Rt8fAjO2*35&!@)Hvj-50001RX>c!Jc -4cm4Z*nhVXkl_>WppoSWnyw=cW`oVVr6nJaCyC3ZFAemk^Y{l{D(RDgQyD0NZvTvc;oERvShPXqEwO` -mrLhT4S^wv2n4toKs58~@9FLtU_gShH@P}hB`X0lJ^kKK_rNb+bpNQgXYa=obum6Yo7|qMw-;BZzo$up~>!syb(YPw+(yR>y-KyS4H?M112r$_4L@$oC7(Yb!8Mr -o>UXt7l{#+u^E#Gd=pJS&T2T0yFwJ$fztUFzadT_@?hNS11#R^UvPxw_tzi#)5vhN{wJTIga!TALNdD -4Wm9HQ4(}ZSqP*I#Y#-6Dub`{!-~I{$pMcfn^>ivkg6~vKUek@1-f0*6Z&5K6jY?s -b!tWgJ(L*C{tdfigFJJ}y0+JAR4c}5zqbh4=RoW*KSgbyc?>=08yi=peXZ2}xb2FOUef|lHp>e#0DTP -$BT%`#pL$X3=(+}7(dON-t-+d+t&c}C?v)fyBes!Zp>Uwl@H$MG%F}hLLA8)R&ZqJ7BKV -!V2S*2aNt`$84&1DXKA_#PnS}*@+7}|o#G*%1!WMJ^fAZ}u%5hbh5Z!>0^XLA-Bdm6R=q>`D+^0KeiM -FKa1EAE(?$TXJjBMPEnU%fiPDxE#1u*5C)pC>cWK2P(!=&QH6EotfHh&CU;JUKZYocwTnqSVJ*dbICH -olV|-XO4k}e*e2!kuTNI<&ag8PoV?Yk%Hs-m* -eX}Tfp=kqN27jy}C&E}P!8}bJ2a~PRTjZ5-WtrjMweBy|ag-NgQOmDRhW?Gmvg{n#2GRs^*3*L-LY_# -3l;1i}}hfJa*&n~B5WvLgaGHEgYoUv;Kv_d{dMr;0kY6P5(^pK0)D?vvN&Jc!O6>4uV -}?ZK2M_dl7_@!yl2VR!BR(q1wWuAKmWY73Qrv4Z*zDL(L884CvB0dBQQ}NU;^kPD|tI<0D7TffgGA-r -G*D0|3F_I{3A1NGehaCT<6Fsvl+H!CE0*1W-I(ZA20C_)q{=TprHzhBW7nwW?=F-W@EUT2DbqjpQaEf -bB?3quRk6Sj=%o(oU*IUmqslU8zIkTy5RiENkuoBhx|s<^<^4njt3e1d5dhE&8gwPmwQqcbohwZes?Fj_|j&R8w<)RfI>Bn -RuuYS`dOrxjEJ()9l2U;I9&TO!v>vM8-$I%&q>#JxKTAx)ew@eVHMRTdePt#WOo5|O)k384f$Nsx{b1 -iTm^DK~7d0}0!Mt#@h(QLP9nh5sw(q`UwWpyFXE=d%+SLI;#GnRk={rMa#nvb1_Tem8bYNF1Hcb694v -9I_1cUTchP&VeJcYZiKKsU&mSP0frA!k|jF3sa>v>5SqwtGUa_T{+)^WrQ=6o9gHhjK#3y2rfrTBOY6 -6OU)%|Vkc_QBUQLZLQRtI?o*8VCb*QzNfETlH(AM$y)_Pso1PAw= -dLDx`(91iM=tT4Z;;l~=>zP?<71R0n)|%2#S>H3kB)kSb-wg-ijXXRgI4DdU0R -^Fo@JH3c%HFR|D>QMv=KV`MkNg|xL#xF{q7t$PS -FOstV}b_%@LQYg4E)!G)BVd*ciRD?%lZQjsudOwAH}ITTENgQF!u+d+r3{x;+p?4qkIFP1v(2O;TWC- -kZ<#KkbvR#OLsTA+k<=mBhI#L1^#ksd=xmgVv}OQdbxMoDxAC5L7e1C!t=3M?N6;oe%!a7d)GlFBR}3 -`OjsoxIqp{4T1g9Ye5s#t8^vZ=L}`P!kvcE%ZriE>l+hiXz?69yX{R_5<8PR`4E0xUQf80jeytJ)8{~ -+F;JY6o5G|Z}`@YDlmC$#Ppo$1ZdX>_e2g_lnz_5Y;4-P_sAs;0H8E7zxIPfndN8^@9gkbF8ZNafl*}3pWrTvMU*Ose!&jWUvkfvi -!jZg{Kur~e=P{606n3c*dP6U)!+0~vTt;J`_hKoNqzyGEbp-CcqDIFhBcilGtcw^m;ZFVcT21&7atU{ -b9`@JGJ}=|S_9@9I`CZb3nzjJGE$W0Z1j@)ElIjU`iGFfFHQU}t>ATPHtDZZAdAE;x4U1YiW -R|RgyZW?V#i~eF9i{%KBaEM-g|WlVXt1oHr94g3{2j(|TJIAuQ({i&ZPKZ31(fulNOGqJOMtxF@dSVQ -6dkA(@xxw`y40E}KiQYp?EBND=}-`{I-MW{Xvs(;}=%tF)NpqL|?v5=L;1uxvG-Qyp=v`LrWr&TZxpd -?Fdq`{0X2V*g3qr*U|?aRTRQeGhS~wA>o=__5Us9^4s8xYEL=#zNsO>2~p#11ADQnK%WL+8`N4Pf7 -g;p}Fev=gumCG*MDEJu=#SgB;|Ra2#C3~m7^{J<@v)0}3#kOAaTV|nEcMXD+Y;}Gm=gltLE-;s~baxj -(-p*p!oO<}0D>kz4X$NGIwq^?%JD1}{ALv7$^Jg(%>XoGNzw&umc#E!C>GJHG@7hj%T%G0>DxPENH#gmT{c{*z?_K#=B;o|EvdH6$Xt$+HbaOvIc2;C|_f7MzYy!bO| -P_%OiFtS7w=UT3(y2)#ep~Tw3*lFnZyEq62Qt*PQ0S@5e(nsQ?UZS8Wtj$yUk843f=VU89>rF2|D -xk?r)u=;q|@X4JiQuHZGpddpF;n)3Mr+v$O#^}!Xd2T|r5H9 ->`WX1P?hXIHNZ^R(yH)F647=T>-jTsrMuh-pfV%?b`5+C$)Be%cVlvA!~^h`#X- -J@LVaBDk59lGugV}NJtLrn$r3k^&zl)>nB)seb(B -atnQW|i6h|ZUkl0~rqD5Ys@=*2Yf(1SKk)Q4e@KzdVtt|2t!HHSvzdfLnrAcV{XR}r=d)!z@`a?}l -qcfvXCg{w$5hZ1~E4=2AYrfhB=jb%@H8l(ljW)EVCNs07bUDN}Vgv4Pa|>Wrm1~23+`5Fb)bkcK=}v@ -@I3MMXUn}}3fs{9VF6J6I=i;S-Y|lnn1J>I6uFqOgHZvx6(KX$a<^fLI4zgARY5cyiiS!^Y0S#Q=TjT -w3_l4_4o8Ge?cGX{exPi#N1~epB_oBWL-FDAeo~AM^C6^XOM+*}@nz$v^$&ngKgwVGm9Lk8D6DMb%94 -GPLl;{=?^z(pLfZ|6}6^woVwlmU8brO@Kv~G-Q$JnCP!kvYYnFq#m4%Ht{LPH47YpLYrZxVAi4 -#(LRXD;3PL8N$dNCjclSC?klSCcC1yIAAw+}|SQzW$-aP={$d!8M&3-4Z#L&b~&5Kd#y~0Jn?O-&Luf -DP**cT12|=p^!=}s59~2QEf<=Zj01+88VmoRr&J&MfzeQB(;4MEP74RKWOFt{pc1ik`Qy&JZ*%^p&2YiUYUuv{mjV;0^Ch=^A -nx-1LrGp)<*4H_yQ#Uh9(wUn`eM9H%@nkVv3=2pVZ|V7Kco-4$__br_|UE;vI<^4pp1@6_Rt?kA|HD) -Xf--JREr5e1uw`oO;orb!E~_X;C7!Z>W{E}$B6GWkBD8y%iml9x{T^SEN;K4T?z@%+)ckBZXGP~BgSu -IsA8E;N&xW9j=d_2y0Mdo)y{JCv{2?ds(|liHf#Xd2ob)<9)BB)ia;P~@CBb|U|NOB`r`7QEpmV(VRPI_kvvcHBe4fyZtCtSqNRKd0Fuz1yt -(*S>?~unaylDDy$xz0ok;fn_-wCJ&k;@1^_b`EiJDc>1`8{-l1v -jl>^lQob{MdZ8};9f0o!Ub{QzowD|GxXn#CJLkDFu9VX1zAZEvfq=eDJn8NrtdC5@R@2%ldxL-Qyy;u -ztfu;RM|RK1_jP9_;vF3$((WVv_C^i<%`c!Jc4cm4Z*nhVXkl_>Wppo -UX>(?BWpOTWd6k@PZ(qle<=-3dcWA&^z(#1#t*U<9U>A@bIiswfMv^h`zA1s>)Xql^2Ocjt8)ENzP|fE*Ectp`SY*8zP-JEb@_OAUtZl@U)?^ISNS)erR96$XSdgn*J=BQtG`^`+ -`YNFFLyte$KRM0gKw@LA6{L)x%z)*zP`JC$RF?D+}-O3<}Tme-S7YK>i+8T@#=N?>7C~M`wzRkXRB6nm#f$BU+0Uv+sFIspWf!%e*Eysf9F@Fe0_QUZ{@q -|n?K)Q|5`pR`IwL8@veOL?(vtq+y7jLT(q0(pYAX3-?4r_-(Ovohr6F2|C*2Y`||GYZFzNhTkfx3Uq9 -?m$OU;Um$$F~>F%Bhe!Y8r{qsA1_xAR6z7@~@cy<5l!~4bj<2T=zudW{QdCMQKZm;h1oxXef)6MlOti -QT`b#?o2RW2XO8-Drl%imV)OCIIL`6%VfyPRLk{QGiso&Q~*{+Fx!hx}FX&+Pr@ol{{(!zb4AcPgmvb!`07kZ!VZ3|G50?vzPz;?e{Os -lW%?~|N7+l^C#cD{NeZc$GPJ9Uvn$>RM)@0Nl3mf`DXW*w~z1g*_q+%r_aCm=QMfp`LnN{z5IbU`10A -yZ=Sw*QNH~4d3jR4d-D9{voF5?>dEu+-S^MG`}W1t&q{f5b@hIswWPnb*8jQCKj)mk-sO6}zIwd8zIk -~6{y*eKKjcH+ye_|7{^cq+{MFTU0<2u-v3c|E|8FyI?r#6Amrk3%E$i>g_0Q$@?(w4h_5M0xlu-P;ZD -yLk?es;Sf>)nilxF!?m$(0RlRNPu?Z3SKIp_ZJ=I-wPqI`b$@W`Kj{RHE~&5lnk4lCvR7yRlU{jWUz< -`4fxZ<8y;+%GQKwtTgp@9%ysmp`$ketey9|BuJ=E2zo?`;c&Xb@Mj;#!bFtI)=Bo*m+!X8Gn8A7UVr% -z53<$?&j{#@6NUV)8(7X+bcHb{_5Y~UfsS*{9pcblMudqvvHD3_0wIx@{3RZ^z4OZd;0wspZ@8))04f -EFL}uGz0rDipC|FN{m|yKlutkXpXK;$jAK=P=dHj0-E6}Se%H+3|89AYCfmd7``?XRQ`sJMzW?2-Vdp -zMdwqqodVgv-lh4`1@;}~BSpKPeY@eP#e3HL6|E$T~JIe}I?o-lR|dtw*@X_x*1G_}L$xvnIKOKfe6oyJufK`Rd0%JbUr-`LoZzfBEd&Z+?9KB>yj`jn9s~c -3=E*dC%G>MF0KUdwDnZrCgkoJo)^qr$4@U_P?K|QH?&|&z^_)`HwHZ{qf7^Pygk|Z=e6+>GS-9k3amN -lzLpGV>X6@(VlivvNqQ{3XL;s0_IPHG&~$I&$4i_B?wTbMO}Vj^ -4C9ZBN`2-EN20DW9q5M_bQ{^96#TGBgG)%3zomxpDf}O0!(lcH~~f;zd`!iYA^3i2S|wqq6|K=Q?tEb -G5CqsHRDBL%pTFPtX4lN4~c4>?87dYQB{Bm9xY+pLpfwnSSN@I{7A@VelmRvNfTRf18^EQaq0!4?Dra -;_rB~$(v2yZ1QHaYhp9k6YH7uXYBFf?efENU{@EW3)6+^Vo??r3ya*<#Mr@L48AA!+`RlL_*G?S44q* -xOa@F@N;6CoDOD4jVP=>aW`>!KJ#no}Y}gz2j=f`_u+9Nf$J8+e)_^ewEF6o#BCrT7Ko1jlHqQdnz%( -!oOas%vv|?H@t(aCmtYT5Is901i0F!}ICLW!M8>S7@+^yU<>>KtC`-XkPzG2_6Z+v3MtYgLrvyMftd* -a3BamsVRv}4*a?U)Ws2c`p4ux()5hQOE`)i`;b!##5ub1666{K(DAWde)&oHp}u47laInu!nNSlHmh@ -C!Jm9Qd$=ps_p#EOS5daPa_|*mLvp1T;>$Fpo<}eB}}+a92KJS-Eds4^DIEPVOsdK!2fA -F3_8v>S26Hpxp!&Lbb(`PmZvFzYHnb|9c^FXBR4M%nRqSN>b8$iq65m=>D< -pkuK#u@R*?7OZSO3uc@bT&c<9ov08w$e+^G@u`ka_4KJZ1Vd$L46L>mT48Z8aUQiiE-VVqiN`8@geIP -Bo)f+0mkOIo_%C?EGCI#$H7BdhhIW=L|4XhBv*X_L6?t|o%G_|Phc=H$7i=`HIDH+HBWR4Edamc1&UUS<3sSsiCHoZ2r(<4NBv248da|C*Y -9EUUdh^HN{2xubKNvPDDug9};`fA0CtNxa#EFzVSPr1VAquL6=8A0r4ug2 -0-bOPJIeu6km`g>Xj=|^B2khJ&7tED^&@6+J~4zPf5M)ai5JfSdt#<%%ygJcqS|<3=uEy@D86`tBp{m -kFJ{Mii-vy0y5{Dk!GKhXUh)tbZY%h#>}6$nV?ysZuhn#X2m{cO%9iDvJQ*R`+lE^cVe!V_5|*8?3~g -*cBM07&u5RTeNFd8(v!9W|7p -ov}*78^U**n!5n=YR#!2-_#GiLeB8F2HAi&j6nRJ_!mrUU$NfMo#70G0tP16aoCD>{TFf5H@e -2KWr{8L+qjngNRo5E&pcKxBZ(0FeQU3s_vh;^Kr`hp^;Nm{v@IOu*s-qy$I_kP;vzKuUm=04V`daB(? -c0aBvx&Fc`BhR4hSQy>!%xBw{uQUas|NC}VkRXZ5kb`5(hf41XxrpuEx(LhS(5=w#d7LRO%flurYu7e{$N-T6A_GJQhzt;ki_3wRT0 -5Bbsm%kL0W!X|RS6lezLwSveBA}ffjAQGaOLu2R+gJC9mEI?!hk+tpcKOijm6Q)430?i6EE6}V!v*N@mh^!#8g2)OYD~PNhvVus -`*j7(QKSWq6(5yfcc9jFBK(hkPiW93Kvf{)lPOL)4D@dszrGk_SQtCW6Z))>^Oa(G<{v0p`DHWttkWx -WP1t}GzK>Aw)DGj7FkkUX(I~o0iu;fpTUv-ATFc~lfDaa%Z<)T6Lo8p@yO#>+nq%@GyKuSA__k^(IPn -ZIk24osetbr8RY7Ur!lm=27NNFIYffP7R4p@Mc7JKt1ge8B%6v#9n({N%9q%@GyKuQBC4Wu-X0{6-R3 -y{)4N&_ja?aiAImi!4*Ak%R&R8jxu~rU99T6Kf!) -fs_VP8c1m%rGbf5c*3~GEWxQl(vb0!D*OyNnwGoG*LED@FtWIB)`b7`o0IbaG>B;Fy4HS+jIrrk)An2Cy<#`uz3h|IbaH82F_)GlmSu(NEskyfRq7J21pqoWq_0cQU*vFTY^N1XJQ~ -TfXo0g1Lrb8$^adIpqzsTUYTXlyunZtGfXo0g1LuOml7|^nkTO8Z04W2c43I -KF$^alV -KD5?GZB^vWG0ZAKxX1xCPhyM|xOHLCORv -6QoR#GC|4&DHEhjkTOBa+=RtUgk=Jm31lXanK+jTQb@>iz!aoRkTOBa1Su1wOpr1`$^-%K|A2q%4rKK*|Cs3#2TNLJ_M`ziOz)4c#pH%DH(Emi)>1l`{lGWoQhYVK7VvOcN=c>@Ei^3=6 -};u-Jsf0>Y9%VQQEfrjDs&>Xmz%(!oOe>}p)5?ccEG -iZii;6|XViOh%2unw!Pp*b(!?a=AFm0GNOdF;R)5eE2EIJk)i;hLdViT5hZU+;0Ogp9>(~fD!bYMC#9 -heSG2Ol=D7+4G}1{MR0O;{|3Hg94&F`bxBOedxj(~0TCbYi;ru!Y6KVqvkcSXiuc^OiPmVY)B{GDw&m -d8{LabyTp93f3vgbp+B*QLa;z>xkMNfwNPT>vj^B3SsFK<~oHrXFr^^tI*i8i>xTTq=IHDVIZL6YXX6 -yQ_Aa<@(NOg*%|XHgr%YtIaJaiCxJ`p)M0{PSYWk*@K{J647df1El8-H!x^Ymj*3-n7qP5DSPGHF@kC -B~TTmIC+`>us3z-zT@df8JKReOmB&tQlSe06onnUG`bVd_HSPC@ONjnWXWN2(g#uqxEl<15cq7eN|Iu -!|=u~3C6mSF3ITZ -6C!sZIq(1*O1(Pbk_VlQ^uBiMvWd3ekorW|X;2E9)xY9jfN&Agk`jspUwKo_gJ7 -w|pd(gea&|cC)Hp3M9}&rK@}rZ>m4-&*}7Bu+aDl^4>y%P@2?GSDAYIiVk53c#(0+457auv$#slWR^y -3HMCJ{D(kX?WI{%=XHsn`#1xcExATB>2#Y}*9UV2A&YKRHJdEROTxZJwBj{~Zt%aHGyYM9ZF;aTr_-J -AXOW`4$j)MaKLV*HH_#gI?^^8NsdS;@c5jxi-^NtsET(-IVTJ!j5BfIiAQ-xtVdF%(CG|*NJMsHMZtnM}&@CBWr1lxguk(siNbQ|bg3w;xfd~e=>u -(%4uY9*l2q4W(>dVAqwiHQAjrOYf~Q?*{+cdlsIYZR1XV;%hduGihc)SEEk|ccpR}RsFD~(A4B6e8i49%Lbx*&R-?RUI) -hBC9u_)$yyg_a;_}|SsUDW5_JlaGO`*18#FC(@5XWwV$e6FqV`Ygph4N%k*A2nLn~oJe4TYp2RTM<=GUc5pBB5A2y)H%> -u^?q>Vi6YdZbObT8j!4uFzt?z$r|JQo6a!YuPVx`qeH$g`G-Q-2IJTfWI|Y+Zmoi7QA5r}ZGse-3EF& -mA{7MCq~Y2;R8B*%HH8)wT7wLG+dYN3Csoag_zIF$lqjdlYlthpNz9=$%&s0VgxvfH#dUgm6sk$F909 -zbz-eL#i;;>t^~C6#ifUyS$3kZ#{{yVY`etz)q#+WLA2xMN)sPiBT<65A^Fou9_Cg5=3DSMF~;TdtI&`88{O -$=c%qI4jo8+~Y%0sHPIGVan^n)T#1-zIPi14v2a*LcL&r|>BA5Np(E?q6RYW#0#QIULYYUX=?!v00}7L9|TiV9~q!G%Bta;?C{uCJ~sBmYP -uzD4ZOIcBN(4*)SsLj)lrA6s&%*$Mrb0W6~HMJc6D#TZwp$UM?cpX!s4d^UPnmdwMjOO{JKyrFvP0hB -OJ082&qL(mo`pE(kO&5_v2h+2un<5GvuD=>86wj=HYaNnAoaPFH}mW@?sD`-H|dK;9Y+gm7hT%e=0p+k!}GNCQDl-Z&esd=$N-kS!Z^5T{k -nX=yRkl%k2rY7Ng?=wK*wM-W%jZE%o_Qa=SwKGo@Nv`~+y4lR8zrl-m{aVcGS4Lw%;t0?Bx?S+Xd@HY#a0L5V^+-PD5i_3pefiOBCT(Jy>gL;PBl@rtL3YJF#)YMMXU5L -%sU$z>Z_YlyKocKCpEDMizp(TE+`}!OX*!HvwDRWKA!b}Q$>?3pw>Ng*hxP*L -~X^6Hr&*7TR@dB$!5~>LTa1tS?E59QfB!t7z(Kd4G{%tzvA+X5*DGfox${Mx@7^VZw9K5%Q?8%2!8HR -Ld?5tFTjzkd9Bb@GV1y}7E-u!Fd;pIl@oY#8psN%n6kF^e2~$)7)=aFXTUVq+GcZb5p>T8g5{=IuBKb3YtV>!29v6&zLlfqRV}^DNkk6fZAYtdop4FIRJbcRbeh%*$$ -=(@u!QnN^6qfOc8)5AMxzFV#?1RjG18w%$x)9s`QXw;0>yPnUgr}-Sd6x(0%MCqFS|rJD?@_{a=C!ce -O+^)j2Ki(@igoJ{6#rpm8!N+o|2x)OGNX`Fr -u>KUS;7GP$(ro9*u>%F9nmEU4H2d8Vyvs_)}~^fJfXVHbsx@gf^_8L_e0mtxb|U7cjZC ->d-D9yP9rGD7A+a(&#|po`}ld5-3QHY^o1+DVJ`LI^ZHV4$>5~>D6^RQK6<=qeaosudOPT)pJ5~lr&J -wEX1O+q~Ex5TzP8=;DmHtqmw_~5~Qo?mfjmQ6gWE%CULgve$LL%NqM0ZI3ZV60T<<*K?|LK5x7H#X0N -fDZjHsNv9m+;W26D8Ms%bF3XACs>xtoGrnAavU_= -P2;p)Ma%^#J{nd)L_zm^a+ibn8n<3&|R~a|p?vs@Fh1c`%w;oxz4`Qu5nN`!=8{y738tJBhcNZi`FJ- -7CxMh)J3FB+rDen7VF58r~%H5&?9dgNlmNR$oZc%}=+frdvld2n6_`PoOA+)`hL5^ft7pWEo9&$GBGz -Vx@%trJH5iTF&oDyw!9Yx)di5(R5Xat#Bzcy1%JirDA4Vqlc^H@&?DphA1!z55CW6I?==s7H`U{lriG -PrxJ20q6mT}7(lkFN;(~FRIpa+bVw2bGknCU6#CeN1?fhjg`y`3b)iYM5O@ujUr0DtfFw?Tj5b#lSh@b&7Xn-`;s%QcV1*Ae4S*i?@O|Y^?isW@yAYDzjCPe}l9Ydv233 -~G92l9nv7NsxvQAyIgzy<5shMaFqp+W8F4&W=-TQqyhd4g!wVT>0pdLL+vB6VfF=)}4x5RiH -pVH64qoh6c3wtrMLoubOTtaN@PJJ^bw!tGG%A@Wcm<X!mZm^LK4HYRB(&6iHwBq{~y{qZgRFYDClx -szXvvuV)aA~A2Vi9UCbIRjV<}Oni8_AvuL7RlM?T^)TYoZ_U4Rckv4m|`6gXNXjM5r}xaydx@Z;F7$n -~~h`*{){kv%S*QbZbLmm#M%^%|tv;86)&kj61QjivS*t@`>(M+O9RZnr;hyY^Es9znqS?E*)}L$K>~svbf-AFlFybo_Ap!e@u| -ltg2H}mcl|Y)^wvfbZr(G(Tw -J#G}iaT(8~e$+Nn7)9Hep6H&l3_X5n&COe}?k?9#N+`{J>dqN&>f->tHW%8Q%`a)W@P1q9Bf^b@UiQ^ -s{Zu}VTT2bQ*L8G0v{SG_Was#{Vnh#M$IUB&*X@*LDu=@_r9w;gs)EW$!DCeV72eTklIk9r5VbkxdP1!xoMz6Tx&Y`w(Zsse>>{8fb~rKH*JE)Lp>hMBEc8A -K-}0rJvELl^6S*hmH6U67%s+bWe*ky7?+SboUa(e7b5m(VwMKm-B~VVXUpr76>%>WbKFtfpHN$>wVrI -)kG*xJgt8JZFW85~?fz(rMDfxI$thUBBU~;nZ{DT@vb&5fL+_UWUYSbq67uPGtmyK;D89tgHMZQEEze --%COC*$HH*>DIQ}R93&4x*V{WvWnnRXjB){?RJ8pzKf*ms6Yv{jZj5U?SxLL*m!N@)`OWigf4+sB?D0Kp>K`QHo{=Lnqaiuu_u -PGbd`k(jY0cfVS8M#mKR5>4X(^NvDJ0L;c4blZK~Ft$jfT`Cf=c@TSKaK_>+TPr$4^5?R!O3amrg3RW -}`7jJp#@A)UqFzau-^sY0mf)>JBDD3qiN5<;Qv+L!J-OQ%u=psALrrZ)#Jh4<+nF=`~=`y8^;Nr3hkZdxfP@Z -w^0+_yxWfK-P-4;%s(XecECshKPA6w5?ZH67RQObvDx%8S%Ot8 -Zjb=N(JIh17gm4j74Mk&FiWjb{z)jF!?&CbtYPv0|=W$8cmgtc3doT;| -L*J@Ir$nL4&8ogjKouTBm>z{I5@xDioQ_^ix2}35eGjfyU6uW~A6V3;thM8d98CR;+*$|~whkq_cnIk -dDj(OKj>T@e-5Tt`VW_ja>%8haN~9Eu1*#v46V9OHt1mQJYAXu~;CkY{6l%JyA-Qv?m3skUys$)5>e9 -&jj$-W;GdenV<@G9wKu5ZD9DOKC&iyS@p{83mea+U;zC&r4xQjmtS{uiJ6dzB$HkKO9(8KhVR)~DAZ` -bN)%u~~??RY=PLQ#E?FM{g>Ha0PXDeKERh#=|~M;GbpR#FvD8U}5#aqI*#)O2f<9EzHy>D?~sY3^bp6 -RAOkzN#>yxS^g46_RtIrbMl-Q%e$a(pWX!8X8*}a`d<}bwF@lW9V4majW`_roc@0&K&^tz)1vlbqEW6 -Cn|Q+t+aEoe@U3qdT5^ueeZ}=WA0>m(-#eOEg3JhJFO%YNSCG5d!9Ts-5M8Fd@2=HAxL${E(eVB->v> -?`Gn=Gc|l+M(^M@~e-{VARct>eR!L~-&=0K>2$E_P>MUUMKoE*k;2}b3EK*o33FTZ5(O1=RY0=twq}6 -n5OI?HVH6p}He-r|7z{K#13>T2kf~0H2M&ElO#YnzfE$GL&#t@d6n;L7&IKB#Z3OSRnTXLx!IL4vge& -lFCKlDvnReoFFwIxk?!)-U+y2L*bK)xFW;Jf;l>Cma_xloItWD?yLAp@=dI5eT@Pzqi0C$T{FR;}QfgY2f;CFutzhVbahwP;(S=l~#8)0f0eFDREngl&r3 -6}+3ehE*nByPg-j>9*?24x9V}_>d?+m3eS1U`J{rwcQ?|+Yuzxs)VZ-L7$_F=-e?+O}B=S8%s?u!jk& -Pz&yk|&_OE?TZTGpT(<$pkh(BO4k6ixIos}R3N_u9sb)4>CiG=xB-D=3?`T4fbW@h{C-vZpC^q>dev~ -LKJ&Vgcw!3aZO}9oNJhq!sx{uVUZWt(hRjWyrXVof77}~{0ePxl(iy|tu)mX@uUH@tyHqe2=19@-6%bmN+() -|ayE9?QL+Egl&xxw<#*I+Ztsm;)kP^fhspk$&J46av$ln35(djn& -#AuuWzm)Ln2@BLz~ydMV0?Z`GnLFP*6ic{lEGqueOU=p{85fh1er#3Z=xVK1FryxQd5lce<0I5`E~~@ -KkR>zoFAXUq7YJ4~cY4ya~$=S!j9unVNRT7LnD=hGHat-nDNK4uIQK<=`OGF=RvH#OdACbW7&T+o?}T -Bw2kN>I+tCt{WQ?P1XB|ciI{%2{jF_9K`6VFt788MOaV@4S7Elnv`cs6;xiM`;sCDq0nR!{?tt?eo9G -)b}x=umkRX}{f@fgg-=vxlbS!fBmfn>P&8E!q;H`hWf`o+bQe!#da0!2D$q*hj6Jak3zN9YsA|4|AjH -;SS)Q)GJe5$0MQXReYXrG$?OJyj2AOGT>zo+E;=1}Ca_?#;QK(nbzv7^AX}GBXpHaZSjC)Goh-cThj*6y&5zeR^3NaYX?mMt -}Ayc%c{B8RqxfrD6FO$GPyK;PZ3*IsA{@3T7QhxtE(AJb#YYZq8mXj$xH=-Lq`BQGewQ1i>UESND~iV -d*UTwTIz$Vz@y$+_3-Lmr6?B8f2qq&ucAj}YXxv+SL#{kAf08ms;1jg)%PIDO;=W=;qJz2Vx}sCiYmH -v*j1Y))DMZsYBYe;phCCZpkLK=>jX4YnR|%F5|L5cT#C86qt~Ww;`aJdMZrxadQKC7Xwout>Z>6YErp_}{o5(>I%t~d;ZRq6J+kEZmYt5 -b^{q^rLayz1Ll_xHP1+dVAm(Ng#)ZH(;>byotvz{M{0$CsrolZ%6(DEHa&Ot&{<0|4VB-NVQakjvKPP6+fs+w*?MKHdA$P}AZ>D1Legw(2h1tr_{utJ3z#dX_5 -%wOkC6x#baF@(jXa=03$ls8N9hSpQ&jwZ)8UcS7!Ca+id)<=T$Y`x>9?ps#QIOVnXy -ehB7f-$56BNv9)4d{L?poix_F+Suzo@bxth8!u2C3DfN9%W2j|9FaSnu)R0<6MBFtPq9^suFx`JreN$ -Jwc7uN1-*k)bFQofbR}Iv;OY@X*)yN4*K9szw6Oal3T?C>2UnK}SQnq!#?S%F>-O`p4y0s-udn(tFp1 --qtYMCnf%9C|9Pw_SB(!G>ANvH~)+C8zFZcQDJs(a#pY|{)DKy*w!^ZF)JwZ%gFOns9mcrKNal*WKno -Zrq<)pYCd8do9QcbcWXE2#(2KDCy*_L5SK3P!GVLn_#f{Hh*k_cz@3H{H?!W=O5B_FHn?5K9n)RneDw -O$N#BCZ)0K6CokH+^J+w+55Q^>R}<$2Ko=*W=Wt>1X2z}kCTF_E}`?;^sAX@7nf&4?L}P;dlKa1oVd? -YKDxPlc--IV`3YZ&|KSJ!7f?$B1QY-O00;m`Rt8hEKTH^66953DO#lEL0001RX>c!Jc4cm4Z*nhVXkl -_>WppoUaAR(CcrI{x)m&|J+{Tgq?kfL>IqSob3CLguKw`&n>edt~(UC|NNtI8fQf+~|ST3w3zyMg$yk -DOg%skUQ0G5{GxazFclDojX^mIS{bWa1|vuD%)#P`Q9PS3=v)1%|Ft7Gx~tMj9Oh#hU8efh;RalJ0Yc -~jn&RlX5N^|BCUD_+A#q<#YNrN6N{$EyJ9JB9{VxJljV&W?EX2rzTRVeRNGI}Y`KP)u1Kicia`kAAZL6hTm65$Gn!6Utd~xj}N`1bc{bSLz`jAkE67#tsBcTnym -v?3f+OYSg=f0NvQEaqX8uUEep$A&-Qj}Fc@LF3zf6znf#Xe}1iJL-f+hVodL}m!xSp0Z;{qp?HwV0i~ -6+g}{FK1`hZ@<-zwZ`>XZAv>-d3UcNxfFV3O*LF#m%7XB`_osa*Kf@VPEN1Sj<2r7$@!( -2iHq6g_36=@SF=lT@#ga4{Ob5nh^wN2qI;E2>DnuLrN_LhwLX_cmzSFs>wl{a-D)8>OR>&B7TVy8qSO -ErxptfT$Imn7rmk-LMe9DK)^A0*5>?$r;-M)uj5HKSW;Vl+r6cVHi^E7{Qn$*h4;yWXE8YL3TYdB#s@Nqr4Vnf%%NTX#PQklPh=adA@g!5(f`+Fli%i5F4Vzdoj0N_{<$rxg#DYQH(E_v-#-wAM1+Sx_SKai=Xb*ksi`Gbn$a1z7u<2ez6xv -=B1+eKk|~lvfp%nxv#xoPerNzY~G3go%SztCh5N=`m_CHe<%Gp>CVe2>p$V0^&=(yQPqEv{m;bzl>L# -E9Z8+GOfUPgQrVtqFX^w*#IM!lr@oYv)JUJXw_Qor>(pu|>vaZ=L2u9=+GSoF_?EigvbTV>RP3~De%e -u0-=1`8N6h-SJ!*cEPXFJ(oTP+Le9oNS#=0Y|rtXz7U1v@kS&!k2AyIlfrv6CgX2>G$CuB8?QyJj&*S ->yhoW=~Nq|eyvNcCt^{i>wbv0brr+Q8b)PgsI9Z_y@u1lpg(N*ISE8zYbVJ^<#v5PRO@M%<3&prEf_+xaYv86@dAb=NIA{ -JDzf@iam0aUzJ6OwROzA64LajaysQ)I`luRnEO2GGe -G_uklPMbz@s}&>YYO%NQ6-g-n&Qb&^iWqGVmNd*bkwIE*2xO4nYw@l$`~DeGs<`o#Q-Nom)u9Fvi+(p -&nKlAe<&VdoO(3Gnt%vq?mjOZ?oipNYq)#L1JmtPjUvYtHV{Syu*L201d1XESFOac%(WVvi8we_)5!$ -eACx4X~01IwdW|o+p75=u<_+Fw%{oJk}sDxI_B!B*Q6>4d7s|S3()ZGQz2hDD$&ANWItFpWI7Rhd4qR -WRxu5lTi|QFzlW>3CQz8ohD4HII6$x#A)Kkjh*FyAb5TfC9Iu_5T#SkN05;GowP}e1>R7;9TVZ{$(j*A)94`<6fw^p*N==+FH+%sUYGB|9 -f0icpBAJnl=63eIW3XX>>@dPFa1bC_>)-=~NX?*51=V1+FB1b$0Ld`jNQ_n#Oan1LS2>c~&+jM5#IPC -{6LYZ&YU{--?#&j^s8CP6giabI~K=5qsClt-%wyAS%EI+R<>AUY8nNssX`Mo}(>%pvwi6PBTnq|(pKV --Imb5>ezK?@k@gDeI^B0lt>r2Q2?%wINGMj~nUQ^(_Z{O43q}7D@$sft88tE$*PJG|(699!7vTqFkIj -iguAa2Osij%p?tcoNz}z49nm=#qrefrSh{+?>Ur5MCc{>kHVU=2ss|dqU^0|v7NC|C_@5X!~L> -ySf?08JHEt!PJC+~qm=jkIM8XBDG{f0ACumTv3kXT`4RJ>}B;CaxUozT-P -->;TZg|h3Jd*M0km+IsqI49aXhoz`%4lUY<{Rv@c-BT3p$N(~MW`ZH;RUva|C!XafrQJ-(oGKU<9^6NR0rO{3>}|vI{MfO79FhHaeidfYR8h>LG$IU#IX^|tB% -)nt98p|JJ%+)j;f`+{P3f(eo}mrwo+$=oZiOo1b$;?6;(v_AC51h)cE?2wr+j}HUI!z&6tlkc+JpW$P -QhHL6Hv|rrsp|7M#N`|5kAH-mKx{XumjI?k^9FHs#oB0L@~^W%!>ABU@wjVWTauGiAEUaQnWvo9vzfh -AlsvSj$&xa*2C-RgvQj*hpbsL39w%e`4s(Gb~vzp=KU}8@x%5)ZZ)i&15t!Hx*nBy98jLZvpyM3@oC0 -dAnVIUd`e8gF-kcO$07KZXHST!v`W4TimKAD3%x_;$Bq~tr6%)J>HLG&DtQ&1u8xE?MUG7FN3@^fKdJ -Jff|+8rX3lT?8eh08L$p?dW5fIqs3m{pdzF9ho`J;MmLb)96!{-GWSIAWt?0TR7@t>Mc>YAp#P_;9`- -E*d=VB)VUsQodg*&ccrI+{*KY7)X_T_{NUT5LH&fiv29_=KXnY`bPzVm7%Wvb)j!|yZ?NwGUee#+`G) -A8V3z^A+h8CsvCfGWE(&?3Bpm>+%^vynq2*uG)ylkzt5sF3-&|Ah5Zs!1b%qe>I^eHlrQ4W8!>H5^7Q -6|93x%2|W^ewfjZcUJf=N5||~;|lrbz4+Y8Xq2HxQN5phM=@-Wr3s^`K!w+V__a#-CFPBh_2H;P+_&) -%b#1Ow$y!>w+Pq16X2abGsqanKA1F6R4TIvoipbVu?WGat8(wKjy*}(r$-w&Dn!_FUZh!sdR-gA8R~6 -z>)<;#BlxYR}qzsE}iTsFs*k&g&J4#;9SBM-7*Z#<>$sfskh8{(D#k!~xL1;>X);JDnP$|bMNXD_o5$ -|9{Z)?vf=+7nPOaa^v(L46mAzMT5Q|$EV2*FrP_Q5`i^2G2;2ESs4eU9?B=2v_89SFP{z~g%ykq3r#e -(dmZ^&LCOsahYg6tem78Y#~^XeT7uT84XTiYStOwqAh!B4JATo_vkzNK)c^&Wg0}P!TG&Kr@d~(1>K8 -5m&>!gfvUO3C0So;iK-v)yQy;VfIH=)!11(@#j=TJC!V=3ied>9Cvk&uX$1hgmzs?aBokzkK&mJMIV0 -8q@9P3(;Yy#;{#XC5g)=kOK6WWwL5`6u-_lvFU2DouXKe`2h0N7jjx4JJ%aY5#0Uw~72QV#-r<#b;G3Of||L|E4+-D361uLRnoeIC$)SWKKtnx&m3p%1%AWDMg>dRRlJp+MDv+W~g&DYQb}U# -3*0|yhC}M)v*jLfGgrzgt!l6QseQ4w96gw6-Ckw_`>n-gih_qsL+Fz_&t$ -a&!jWdb~APq&kyjL0Ip#na`L<6lZe-D<0$s+!2E+#RPZDQB67XRX>XRbO%7}*2C -|10rJ9{bQWYN;q~a$ua{Rf$kTXDh<1a-<<^7Jh(FDNSdYw}uKR@Xk=JLH)9ml_$pgNNmdvWs#mVrBbL -Li0*$UrzliyKw9Wj;mEOCT;D4{)M@pcBPOvq2TOFoP^be))TP25evV=Cbf?MgYHhWjYa -QsH$el7nIau7QA|z=>dG;*YSpHq4}PHInDR7Gu5j_sz3;i%s6P;)nb`uZp&CPtVP&eDm0r?OuKJQ?cm -GbFo7IJA3nbett4Pnq42iIKO-=z7v18C!U|5UC;kdcvYXHM+G4YUl;)rLemL*yF5k?XVx#+=)m1S(ug -}ce{O*2J>}XIG#Zr$lZ$FgxbMwIByxQLFXsh+u**0}!p68uzwbaL^PnqW%yS;tBJbUPu*A@%$O!Nonf -l54wO8uVshb6_L-fBBHZDb#@EcKULEpmUjr7_B?f7+6sv3x>(@8b935B9_WCR~DYC5)cL&12UOzt}d7 -dBXf=yIPrNK3nsgYyT7|HLF+VSz4{we4%BI_;3$}FeWlj#D1vi2eH=gJM*Zr>DZdX#&Tw&$~+TlXZch -k$G>dh18Jl%kHp&}TGacd_*mB4wwIX8db+X?^{zJgty!oxtr76L*%py`s95`%c_7<7LTxaTS4(Y=YO& -e&&uOpomJfDQ6qR1-au>c%@=aTCD6RA&dn84@Zsu**MCM7`d9NuBFKr?kiXAuqnxfk_6~?uqnAJP;X> -;6a^XVm6!!_ow2NcVwUktOMmi$q)nsJO}`iH8!wf++L#4|T&dnisdPV%-OSeP}|jp!a~4U$LU} -!*WCO~fK7c{E_#Xev8Mi5i2I^h)s5EX!u*{Gk0cGmCtQpgKCDa4A*J{mA#wn`-o2t;rujxg-wk|Qbk- -O50P1(;UrX^vq2BL@1L%X_`R;>LD}DCwJEtb!+C>zlIH2CUI!}>D*tXCvJ2AHwZ_jr5FVkngSNz`ept -i-tAS4IH4XqG4-O^J4HU7IjG78!|=A!u=AsL$6-Snm@@()i*O`+yp_?-W{NkzPWXMerlvB+H}>3?(D) -O0p4s(O37o-gw*AH`xzh`Y2kl>!B$Yxru8UzJPam7~Gw&nEn|b*%TGiPLaYzFBO|pW_hJUGroo9_r>p -YZ;~ggB5{0?zZY=vNg&5Kpu^8Fg8*Aeqa1)I2nyL0d%fMpG*!_Wj#F%ViU$Vkdd)DQroK^POpY(?T&O -8gFT&EZZ+HOO^h1#;_n~&o{WO5E)3Rm*q>MVo$-mUu3ny=T+j7LUty{Lqxn=1-#wBbywlV8<1If|clI -xg_*2v7ahfH3u1d{C<`1+Wk250tw+sK8Xm7hUHD8sD^EbVA&)4z$K#0Bg=dY#s+jqRR{uclI&B=cMhi -T%UkK?KHCr3lxW5Gg=7=MpTWBPyn7mR;0`?T?Q+x6(;n?!x}B;c8FGR&u(u1(@?Y01Q=j{otLKw)|eA -N=;UL(9QLtxi9xH+0r6`M%3CMw{iH0+i8Bij_D2I}$#j+w>o3&cjYFo0RecyZzpP=DK;F -F}Q(6_!1-T3IP=_;Tx)APsHMX|cJzPPxzy87zxU4LeC(?#b(_dX$+qmxJUA>K^{@}XJ6YBqM_6O@5YbW{}wdK?6Ya4^w -@wkeW{tf2_{e$tx$NPiBYfJqVRg=0*V_)sZYn#i1<$L<-Kf`^sL(6yfSI(*b2=>)(TU{~#S>IPX(m&N -372Un-hT9I^eBjtE2aYTrI&kFX#luH$yy;MFf9?G4UA6eH9ant5R=c{kr@v=}01bYSft#&;wfYFY<7{ -t&u~`F2ORF0^&fr6@Gik0@lmc5{xPp6Ap8?P`UHQB9A~Y6l;boA!=LbW(lQ=C#=FI?`#2v8zr`R8Gn*D*N*&ld{{Q;-hA9$Mmf#+m@;A!>;o@RgGY4!)6Vt>FX_6MA1f8Z(h2VbSwA8?BO0q13Z; -A!>;o|pZBr`aEPn*D+MVt?R;*d(vlD4&=6Q9jN6z|-6hJk9;U)7+2irnw*G^Kw7%H1`8fb3gDj_v5-nxgYhXxF2wu`*GP6_XAFIKkzj -7123rjQB6+nNAWcG15a~*L*RatPjNqr=j49WlH&ewGWP>caX;WR_d^M%xgX{8Du3WbmA`N9cc%OmH=o -Z^^Okf!W;o6L!1L;UTkc1BU)*o2`+*nbe&9uQ|GaR&r2A1m&HZRkn)^{cC-;NLJn4SH^}$sO>VAwtQQ -ePvis^oIDyQxjxL5zXWHBky -r}16tNT$;QSO%9mZza#D!(q4) -C?R3AT-*2n?ef#}V+FLsASDbo2OQ}=ge&2pS@Vwk#Hr+3IK9b*W>-pH~ep~K$<@vbM{cb!T$?vz!dL` -}$o^z*pV_q*|Y=A8Ro>3)>=r~8|R`#E)PiTizLy^`*?_4{pgzm)Z&{l2nZTfe_-Sue^L&3 -Yx>?(XQlfk?zi=PP=9gV -Po58_!kK2hu5^Fd{C->AZ=3bn`u(<^kHr0w?w?iGYpMG!vtCEK-x2rYs=oI5*!lf{b9z1%_ish_yW{@ -4;eJkeQ`z6|iu-4^zu(sL0q%?YU3osZQ}g=$w%k7}&qvtjgX(i~KfWsR?(Y|LKj6IFkIQ;`vUd(VA8D -TtIIpPZ1H9}{_B!K!#ck)a)aLZLUdi(TUKY;>cv-SuSDufp?w7dVmFMFs>-FsSJMw&h7vz3H_e`%%xd_xI0=`z76PyU)j!?)UBYyVCu(+%M>U%dFQC -_m}Ls-Z|F&^Rma&HtY4i$5V0A`79;Pbbr5Z&u3QLZ|nK^KGVUK?w35DInR3idOnW0-_`zp%QGF^=zcd -@@4Rq->Gt-DVr9dSQupHJ?0qx&tn-%j^~^UAW%$JX-!p4a -b}xF2|N&xg+OKA*BZ+hxoBxZ}&R&qv^Xz@EbhIjmzQ`)Q9Sr;M3$zm)abdOow_ev~iEc|NYPUf-V2jI!R@`2F+!T(2AM7d#(< -`z600-ymi8`=zW`(*54KKcuXeQ^S__`C#Vr`u(mvAK!kz#Qn4K`(5qvbmjR-x?l2qd}qCmxF5v}KG!R -FJ~Q(BCC|t5-7S{f54_M>Zj$FC>3-n8p6#;bepl!ByVL!2mK&#lnP$CMw`D)Szie5rE6>Lj_e;9pH}_ -lm{g&JhxE%X@TzNjgr<(N&p3e^3=VPn;on^f(%6j>&zOB!6u+4gB<@e*dzRvTRmoptC?zhc)1;1a)dj -0Bt+h@CktXJZG+pJgOej)1>_IOJB`%z22J)T0=EBXDvr~U30Tfg7d^O3S%;Kld(kmtj1=~BM83%IW{9 -m@7>7x1z?*NgU-#q)8*{g%&mZBM`7a(};|`z@dCvh#c--EYhNW%K)OJs)@6PgyU&b!U2pv#suT#r?Lr -A9z{b*(h;8+L`wZXG!-<+%M_=?aBR)JfD(rzoqUk6Zg-%=QA_zZ_#-^{1z?c`Tb?n{jU6e)SuV$0bW% -1OWa@S{wch-%a;2sJs(@{2VP9~qmk7a&JH{u?^$n)_V@E!v6S!Yb;bR&^7~zRJ`(o>uio9_llvWcJ~M -h>udVL)>iM|g{&~^;ww@2_@u&M~pAWy~rlR||EBB*(#r@ln`)8#49dW2oy=zf%*D)$2~JNE-G%^uG-`ThJ>naWvi -lJ2+N=VQzLlJ0lK{jU6eiTfqpFJ-+F_gA|AirkN3%el|T@+>!r`%z8Ktk+ie`}KSz?zi)N0O#D_Z_E9 -tXUB7Yi_UQ7x5P|!zbo#y^?ZDDzboBu>-k9BZ~JUl#r;>}e&7YUU()@S+z-4c_X}q_2+wv&+%KHtIp5 -rmdVF!e_dT9u`S7KGh2wkzYuS$lQFgoEmimGFvin_8Kk!QSPo#b+t`d7O`QlpF9g^#e~+Kkzj515Z;w@HF)U_eK4vzc}^NW4(NhZ -|NvEN%s5Z{#nWXiu<<(_gfz0DRI9f`z?=fmbQ2bvfuV7H%aze9_1!*zjU0BVENc_Ke(;vF`n2KRP-n} -N%l+JZ+ny*+Ubq^>8W16mbWDPZ5^MA`sa)KF^@Zh`US@awd8gCEoHw%{g$#{qJCT1?}qvX$H$HAx830 ->Q9tm!vLEHs)DJ2zJ@to_^zudP)a|ci|MuYi9VYt)?zcV3&C#1%W+eNCq}QwL7fx~moLBaPQ+>U;1?A -`V1m}S4e!e&>%LnyT+&^m1&f|WNc23Jj(*2g)FWLR5X3DzX&hEE7z28pvOG&RS_uJ}z+fzJU>3;8aKO -N@77vYu;aIUDoqJC4){7}F2V3*&dS9-9^GU=5b>YYu}>y`R#EuXR_y|xc_d8hu6xSy}K%JM-y759(Yv -wgW=lKler+gd)BcE4o#0QdCLF3ZjRmb-ksZtiz=po4AFYis$~zPJUrKg*|OxSy}8%JM-y759(YQ*pog -^S{H>^DdulsQYJS`PfFit`2Z^_R_A@GKQES -#tM@g!vwY~8UcO8!%LnyTvVYW`?JN7G2fKu%*U>H?+jHE6q}TR52Z{TocXrwB@U*mig!i^saz8k-=zH -3IC%v|IzkkbzbU$AXQ?Y!c^BiWy{b*0c{X2^LEq8d@?(z}NbFj7h9qsa&;|IH3Sw0f?OS<3HyLw&i?s -v!iw7Z{A`%FEbO82|ve(5ZqiuEV*BJvdfL`m$+Zj{j;+BCGJN(Y3@gPe+N3ydt1h)c -PqMoR)_gi++XQ_gU^inEzfbAQPeAK^O1DFnjw~cyz%YN_FPpY5KSM^{Q>X{?zuT=jWJ=nD^clpfZ2+w) -h4W+9~ZL7`k5hc`50BYAN5q+KWfj;<9;FN1)MkN#Z}9Ff~V#F -PQW>JKU!00Yrhoq+MeL)>ZL8VkMv4M`AE9oKlhX8!^fi1{ivtn{!x1>?pJ?T(EX@A=O!Q9qkJ5BKGJa -xZjSPCv&l!W`)xP*_~w3;_jP)+f9^L&`Hc0s(*3BX;{H*4D(+W*bF;zIR`*+;+%M?$4r6Vtx -F7XY+&^kh#r^8<3R$nj{g%4lGxtk=Kgy@MA9%5cdIjBY$Nj!_zvTHyy5E-jT^-%;%<~CI_wzPYSug6T -xPR21?aTe3!@1n!iN=>>kEfeQyBzKDbhW=<+T$rb+9e(418&aC{nGw^XS%;dSuekK#r>$K;{H*4wlDV -s&Z+wW7u5YA?Si@=@RW7Gn?0Ujt74uHikDsY+j75m&!7mjq0JRi&FdL{ -0+Jil4e{k8|WS!TV0=Yy*jJHOd-f4{Bnw>`*B(*3skd|Y`x&h~f)=Is8lx~c=5QBTGFqxNiH?w54Gqc -a^WJs)YGk0tld#`BT5-|H*8Y`I@L$xY&Z+dZDrbG^2@-#hoW=qR_be^crHq@IfVNA1~p-0#=(0X${T2 -Y5lx2XKn}0ekU$0Q>TMfS1Mdk+>gt@mF>k&xbzKct!q6Jr((n+EbCg`m4ylR*`>g8<78fyLav0b#*)* -@qpa6y41gOd9}Y(J9$@cqjz%9-`K1T?&=L{OUp~O)wMybe|C9uP+MND4K{kqtIMmWYJ>jS!Ki|`#|L{ -G8_T^@{p*kQ2WK``M|eE#o99lSSX-%Gvwmjv~Y-f-KYn-3hj<-n1}gF -iZOZ1L8ki${;$c+;`k{@VFusMHVlRtw*3^*V+y7{>$P;W!=wZ;ay&;LUNo3A{Cqw}7|D@iy>VdS2WBF|@ty}=^FgZTJ@Y}T=Vms-RL{+9gsGkzebz|z+{{N -K)pIi+4c+s^BB>d)!O-s+w8_w`4BBGo)dp=d^iK@Bz|cQ6XosPHX3#F7SM9k9_g9^jy~f;i0Yk4fDDT -_%4a)oW=LY3{`+-4u-}V}m_w71^^1fYfP~Er0A~K7;*=49%>8(0L%`$HV3^i+99})zVSf;^Hv$|VNhM -J|_YBAKT>sFhgW>L2m7;08@i_hCWgR*(s^B0Ea_`Ln4LHWGxHz=RCzcMJFx4$+hpSQm;Xxz7jg%Nnbf -N|Hl$#>)p28?^w?T)~M22@Xd){~+)8Z_?MLNW$78J<>8eAbf+erQl-Bi54!+-y+g-_{d5??(oW`?Zi% -aEk$zx!OtY*S|Gr+^tUX@Bhw#$|9^M?K))8xL*tH5qQ{ualg6=i61dw+^tUX&ySj~8P%;I8G#=gRCTM -9)cW@Z)!pih&|?OTyVXtFdfb3zrVLq9XiTk&Z%>5dnYDor373&164&r+MNpRdj+-oFll!WOfz1}2Lkx0@C -l36-8Rj)zU;I_mcKfYqOio%2|TdO$UlPN3dF*;Hdv1n6J+B1oP$j-vsmZc^|=if&LG -{{2T6$vkSCx!Va7DJI;1U)#+fSYlKIKWL=}q1}FZ6bX_B0;}d_~=$+tTT^obe(aBBQXhdxnbP&Z@H>Cz|a+ptb!(4$Y(H)5T}faJDTGj$pRx|_A4snZzH9j#SOoy -LIfYOQSQGzK(3THOR@47xNwTHyp{47xNwTIB?047xNwTImF447xNwTI~d847xNwTJZ#C47xNwTJ;2G4 -7xNwTKNQK47xNwTKxoO47xNwS^))S47xNwS_OqP1~flf357HUG(TDmg){~p6v1(Co9L`DwF4!lOjDjAIPPl`L+~uYaaZw6jU4Sj>8U0vd5 -++?pUsS)9VkuJ!gRktu<9im_#(k^FPj+Lmk3t9#8ACVu-X)X(#FaTl(cGM1YaRoZHdSj*?|&Q4K(mog -4O!PC0`?0?M%Q>y-u*|B`)~}!ErB}sN_w8RWEVLw+N1Vi7z#BumdHsS{Va7R4NNT2>I8cl36Xx&f5el -orMOzL$KHY5rkGt7ME$Cq3mFYRf3|pi`)iHN&d^oM5)KLrSB|0+CH-$=UC9_D5cc`>hGSFmrhe~QC-6p>~)Z0yx@h7`G)P@k?iv;Um+zD(rJk(}TW|K>(t) -R>vmrxr)X!WB6tEHOsoQ&>Ji7I?Elg}M0MYVvI{FGqT$;^?)q1IBMjN$(h9(S{uc>*d_G736@Jn>Lzs -CH7CWt*W^P^OwE30EBjOAntST=x`ReVXvNt1V32GX(3K5`BG^aPs(=?^?vy1jW->t?XMkQUOlz -azv0}Vuk8Ed{lVe2rT)q_%G=-U4;EK@r~CWL?yHSBHeNs?;Yzm?wVsWZJ(aa}i@Svl3)SnjQEwJO -!L#lhO*+Qw3UWASuveg7ZN77Dg{@w6J0{Z#p(14nKi4dE7R9-LcWKG|DYTwmK<9xUI}U))f6%>Mdy-F -CMT|6t!*t#|kP>x;e3lgrDCEB%2=X7>NEx3byaVs*Wh^}Bi}`h)$k*ovNvo{FB1o{64~ei1zvJs-Ugy -%@a|y&U~AdL{Z*^lJ24^m_D0^k(!{^y}z1(Ql)-qj#crqxYisqYt7FqmQDGqfeqwqtBwxqc5T_qpzZ` -qi>>bqwk{M4=)VwA3iXAaCmX}(D32mBg03BKN&tYe0=ys%pcdP1$_H0M{YcN`|-v2mvB&}MS@8EvwTm -7wXG3y{Ct(tNvs4`@PL0gERtUm#Ci3!B9BIIUGN6}?MV=%eNmLqn@>`Dr`x?^@F#aTKQ%EoX?HBE@&bS#vO;goKg5W^|qG$Dr5u -~0UK)3H!ChEwV(8^h^XC>z6#Vxde7r(>aP45wqEYz(JUp==DNQ=x1Or$eD^45ve(Yz(JEp==DNQ=x1O -r&FP945wqEYz(Jkp==DNW1(yer*olf45xFU2{D`!QWIi0rKBdra7sx{h~Y*S5O9j&l$4qf!-f2(G>hS -smYNX5DJ?Z2hGVBiuozCCQIU<|l$6TGa9T-aV>rDDCmX|s-AOT=)==3PPH(-*#&8XGiU`GUT0LcBIGq -h;V>qRpCd6=BH)UfurJAxaoKA)klwvp?3}s_DC6}@>oDxgf7*0v0Yz)_IOpM{QPRhn`BfBSoDTdR2Pd -0`dZK6qFis7{5la1j(^b -aA|NaUv_0~WN&gWV`yP=WMyw_awu8K)Ln`rJGSd6^)0a-U+a77OYFps?^$ae`WEmz_>%;O#J&L3R&WLY3Ct -Y7B>LmbCiXc8KmNJT0kG>^`!1{v_nq$b_xb&c*6QWaxj}#Dj$PKCZ|||r43>NSv-_s-2j{KT-s;}YMZdp1816lDt~*@zM|;;!tN*v=k5-3+)Be!vonIXcN7l(O#EO6W<&l3NJbcn09UUzDD -=L!unEHO}`-8RKsCUs<|8(|SM|$`9E0@(j?ETi={T2LYZNGKQKii!)-MQoNi9?6(>>Ro6*x}C6;|C8N -v6ig$oja`Xzed<{-LiIByZzl$1ytwO8QJspTlQ2QaJhx8M@+6au=U38c<}ICYg0XVnCWhV^hbDjm-NS -Zd=}>k-k#}C^7wVqpW-@e|1^)!KKB{kzDD{l_~$yLKg-)UNq>&(EdKL64m;0Z^7Cnt{sNEFCjCVohv_ -fzI81+;>mKQ^@c8U=U*+vtUaxVTo&W1R4vYT=KTkI9Z*skc^Cx(V>+EyiVY`ap2^ge<10+20UZB`p9@79Kge{N2jd^}o+0@vkHYkacysot98(T;{P-t4B^HO{%VB5v -DF0lREXSHdT{-?K*I8QEBK?6|r~j+KygtL_26cXt;*O!Xq4>1@94HRDp?LWz4&S&Hq_|yminoB`9KiZ -s+`c}=Ylh;6;t*#J6n6~8tK!80`emSa)xEev?fP{{E1U7!^)X&E7&jP?bYsRRy1{s5%y`u?u8_JuOH_ -k#%U~Si8;nnNeT;+SOkx~^pXxHk0eDG_gI;bo4r -iGW<8=Y!5GEbQf!EnE4qpZdj6;;P7>D*rjMqzsafQhBSwb3&TL$A8-(Y;I>$`E#%Z+heHx7CN;~-~q; -{wJ3U@0*UQ4$yj{AP9I5WXxJuTxQlld$p_hbfiBIOs`?!>`}07>D>tjDw!UIOs`?gPz1V=t+!&p2Rrh -l@{X=Cy8;;lNbj*iE+@A7zaIxanQFI#uwzqVbn9aaj@4ZF`kbb2ht`m4ssIX0Mv9C2Mi`L4$;%Pafnk -C#^G~QyK%xeCthVR4pXEkHx3s>662t!b>q-Jts95-MY(b4x2@*JrJX9ECov9sN{mDEg4{TSFUXBU_;S -?7A$qzcPE#AdVQsvQ80TcG48{R>X)!LjaS7wlJ}bs0Hx6;;jd6&d7UPl|*TuNx#wCnPH~&DKqTD#d-% -=O{yIc^)^C_wrjBf_xP_^qJZ?Epc*ERR-g_MHR`7gI?4Ur>Tu^&W%I+v=|3cWp(2aCnLroOv(+1Fj@uG -#-*YPoMoA7te -jvqDq-CUUX4K7vs7+RTN^@X9-hzi~}yxx^bzfQZ&YkE~?~(@x0tP#Lv3nu;?XD0pocsaSBD1lDTnBjB -C1az1p}Y#)YB^xafH=al+>ow!}%baZZxTV_esbOZ&#l=EmVX=k3OIcdEd7X044&7>D>p)yB7^8#fyc% -jU-6bF(gSdbHt?6Jy(9yy&8e?oJiSjW4RG0(x3EE)`Ys!nowdb@z=+7~hf`4&l4697UBv-S`&8xa7v` -_?+4p87hx)(5s4Z$&E`zmAo)6EpbX1m)y97ajB@Hi*eA4y8UM{7&jXZ#hohK3**{Fl{R9W6W|8V8?Oe -&tM0}njF-)gOBmO!jpyaYp?x*ocwQS01&o7SYK$+$je|b#+IU_V_Xy+sO0SF?2fge!)7sf%~Qbm<=VI1V`fN{xLbefZhXE_&Yk#O2Io-3a*V8yi-LJ&D@8vldmLeMOfzt5H(95#nFei*xd&6N~ZoJTb~sennIUD*rjDw!UIOy|s<2LOZ=QDiEx^aVXgK^Mvd{C{l;ZXA>ZW -6|!c}9#&ZhSEq7j~)`jBf(t4!!+{&*a=NZX1jnj64q+V|;`0sh*!3 )-Tq_Tcup9Xo~fdXacEx{#*yNDW}4EtWhjpEw*bX;@BRVA -%(pZyZB&sc4(s44DK0%3YcUiTHmWRy;?hl=x-}JDGp>90k62To2ORP#Xw0}}FplvngmLK|ZW6|!eL** -ILYR!DajB-Fc@wAZTO%ZlL;HEbc&M<; -Ha}4tiRQ(}S`2)G?)T%TOHSSBT=08He^6OXJc#oCTN0bJ}iLE;GKJO5+m6rJ9OFaq;;sA&l!j-!P}g)K -<2ku;yZ#@~h*FL< -AdCdPHmIADLiE1db5am|{Fo*CC&;gm40`v$k7&A3hPjNpT1Fm4%)V|;`0sV-w2ezc{%`3KsU1LM#_^HWl5cV&U7{V*O(%ZW)SWd_(c6E>p -bVx3?|Gi)-Hbqv^%4<_TqU_Tzi)amQ-RLVM;2N!8pdR5XPmF3g~mb4`0)agPip~e8 -G%^T#mvx$Ypq(3g|@@#z8OYKKv$9oF{C|xMe7g@he1e-G^c=Xs=;4%(&(|I5jC==w8DG6~>D;_8JzvO9k|8{4^Eam$ykJ714~-0w+IJgK^7X9OG9A<6F~>OEnb<N(^i=gd>{38s;ErW54Um=VGmeX!Gl- -}M3?Ne?y%&9gG;R|~0k1obFmpC=uILKA3jqAE`(2K&jO}B9JPzK|c!8pdR5XM2D^R97ezoCS2&=VMkF -QKeUoI+7$K}(#FRf%uJ*TuN*5@*pEcktncu|F{ww+zNHzQOoZmy0Tr8!z}t!%ztmeBS-rkB8g_gAUjM8$@-L010m2hK&>a -qY-Lw9_6aMJJus_wqgx4;gKRsBnZeG36KQp?}9rXtNTcW@Ne{B-^w7)V?;Re?IgW>Y@FIAUVd#v{KU* -S|cFzAnlVIVra>DeEEe_KbptE=j??&_Xi@o!$cW&h3{_uO&p;PHD-cI@y}I)_gjI&^2}!1r!D(Yfn*= -lF?(hfY{a)_T-W$~Ac2w3kj@s@0(X?6_`&?!G0=peQfMejq2ie9!aN>E -}I0{ZYZySffiI205P@?Eg6pfs+TM&;oz2u+Q02LO8&#g$U!ux$yA@TQ+a -6STZhKMXx$Q%Bl3Vnhg_GTFGZkmLS7RzpbI)cf&T-FSDp97+RGi(O%T%1&lY2Zt#d+;Dn2M9yYcdsQw -8zJ7KdNlpcK;P}j*r`4qsqr^2~|FBe}gI?x9_0J$L()X4RdQnr+XWUYO`!D`i8t6RkhMqi^z5W)iAYo -BpyUD%&gs-iiZ%?%D~j3@B8nfs(y;wjj4JVRkg}qi_YtNs4Bl;M-lEoRlUZj)tst-hpKu%wjHT=q8et -_j=~;6F-)u#o$XN+m1nV|?mC8Qm{==}YiazQjieXxf==| -?OagtTk-FKs^#>N{r&&&r%=2P>(Nao*er!F;V&cs~GHxIr`2bfDaHt73kCAmrY<_c -Ce?3hXU|0hXzVt?=w9jM0+yh#V#*nwB*fEPRPDjjGDC)Hnpl0r9bZiVoPZ15eWdA#E=<)>qj_2zh()yg#Qu5Qf@o3 -c4`To-n^-R_D~EF8#!r*qu6*K^`JK%(($okcUa;*Yn0}r1J}U<8{*c6}|BW>HL!3psS?8uj!4qNawz8 -<89Kpv)jPRn%!gx^NwipFV&6zqxSr3b%TJRj8N0Xext9jW-Q_NN#_ZFbLAO25X+b@+GZ@{4@r+@{1NG -~jIl^(D{thu5toCjq{lM;nDki2pOCJWW}>eMDuLU|B)O4Hm2O+vq$W(0M@bHoZNj8_jO19ZUyvT=3cu -v3TyD2wsbY!Fp7^C&^qm)6BVBzpIqWAzh^kC;tS=VX7X;gnVV2TnJ9oP`=59*2D~Doa -&Gg%>ree+R*yvB!`*0Gxd2#xhMFEL*;o#*(V(7=SU9Ibm1ePCppX#I+1Ggj&e|S=))ICR#`@#hAQ)p@ -=zYgFOjUW1o>r>Rq->z9F^rA<)U2pNc^62rWK)D@>+E!t96j(Yt&rTL?NHoNevN|5?@a8}%qp(KxAY)aoXPF_Gh1;SWu)Lo9@YMxsgH`}Pf1pDHc~ -$$Rpkih@j1yVMHu2QNS^$*j^r;%4s(RYUy-V2EHwU_WHnI*EvQ1IvQOVy?rYRals`xv~GQrPCD) ->9fF-0?h>iv$(R!^^zs`8t8m60>?O7MXXldQ&YX6KEge3Cn}V(Uy?5}Y3L+fg2=0rF!chbcCraT)(N$ -tp+akjF_@ULopgS{0a->>bGc8p&Sr8+)=yaGg5((c=dX9kG_IlfC}g7610jBVSeGPx_;ygJpl^W>uzN -^GBV2_q@Nf`~F^kd2s*Q9`*OTqXlHW|5m#FvlqH&!&rxhzJK55f~b?~j0T;-aM>Sr&UaUr{?r0NrgQC -_S6#6*4SVFaV~3}mwyBt-%d5RJ-IdPjV68XmUGzIcwUn|{+uLqAt?+wtGcoV;{nbu)?M$!NS@B0|NoD -D~-IX{n1irRD(x?M}x%;LG5v;OpS`<16DIjUOEUc -zkvI(D>o;PsWdoA00nF{%JUsZ&4HWj+4hbt(MpBG|jS)S@to@KG6ZQ>|>UF%(4%NX4%Iq`J7$%cUc6lh*R+NZh5h8gwLX(^^eB68CAX79EKjwN{& -sB>JFBM-qKNR@+VV0bR##q7Ud=b`yO-*Rz}G0~#MU-Un?OA2;3yZ5kgp-Un?OA2;3yZ5kgp-Un?OA2; -3yZ5kgh-Un?OA1~eqZ5kgh-Un?OA1~eqZ5kgh(FZg>UZM|Ze7r;-(D-{1Wj3}@^v#1G(1AIw6z%>4Ey)$KQWRT?D&aX`SH?zKz!xGW#0?~~Z5;B}+ev3o-FAe3mFjTH(p+5ppO9KQH00008 -07zB_Q(OU(CN38M0QZss044wc0B~t=FJE?LZe(wAFJow7a%5$6FKl6MXJ}<&a%FdIZ)9a`E^vA6omrO -~$92cwc@DorTTDX95y`H`&V)(C#iA1~4k?9Mh$Mq^DWl)@Ipc_+ok@!cU(6_4k*Z;Y-;K0|8+}s)+x!fNd=?!iLn|H_8hlBn54g`n3ek -iyyT<;IA9Sv@duO4b^W&ghY`>u|LH-gRn=Hazly}|l$bok2k?r6O?KD>2V|KC<`yg3?P?u~-}jm_a`9 -9&GQ*ytUZwC1DPaVH->eAYor_MdScJ}!S?=rLGo%OMYn_CKya{oaH4=3J~<^f6Io5nIO+-5tEZAup}4^oW-a9@klqyw7!3&-Z!#tm!}C0 -So4OvdPe9BsJURJq6QR#B-k^`n3H{Io^wn(WhqIxtWwP2u@!}?? -f(~zVgryJoL@gknEwqc<93ex1!LGmI-~0;O%Jw%g~QpIQ`Jd=?l=ebNWu8FFSqZq3@xeR^y@Xoqqaqo -YTiQ=7v7LF$Mi5KtF?8Yo{+jKbj5w$ja#p=^er8hqIwCq<54f=zFK{p+Bj{L*GL`eU*12S3`AsimA?^ -Ut~_-3H1F$u7|$)R-e=N(4V{(0R5$=cQie>r{P&D=sU^jd#CTAKY4kl@1bw%*{e<;SMP92HYj;tNP4F -{t9Lx~J@n1Ddgy!TPhKnU^l>7W2vNC4Si -uEcL|%b?3}(|vYF~0`hkaj;Gu6`m2>({bov}{<;v*`PCvAQzOZCdfPUzmzK8zg<)QDPZ;G$VlFb@A{X -EHBZORR;xF1?^zsOaa0{0`&{h(6Zk7jcpR^H^f4|<;apwG8}2jo2WLC`O0D7MLpcl123(C)V{0_)-9=`)}fhRFIVux6KFE3MgZbU%Y% -Y|~Qy=s^^+BJP`cQse>O=WF^+C^3ALKmsLC;Yi+wH(p;_!(-|7p -_*N0cqHlzUfU$9+?1#fdO4^sd3{%Fcx+d0N?u>c ->sxyLYOUO?;Wn-NE535G;?#HL^`V}kGCWXzx73GvidnH>gbH97)myP<%^7<0>K`)B>j=a8QUfat+UFW_Tp854z9rxTAhVYk2s5>ZxBg>MzUdgFdg;q=vuP;zv%J4Yy`UPirEcfP0)c0$6%1iwkQa^JadFq#q`asRydVQ#8x6}uH-n_n);jyK@8?O&?G3W -3|)Q92=-kS@0xzFLT_4=Uub9n5jU&p+D=6>JWxIlebDDk@Id)I -^g+)-ALKmrLC--S1qMbDnh^D1dn9(tC7{0pf643RwJt~CU_QM^&<)Tx -I-&5ME8!hH0sTnYNNQ@Nm*9QuoJ`ZDzENPRvQ_YU=4<#)<9mn-ei -lCt_`TdQBJ)t7c?Nm+eihn6Mvp_YP9S$1UgE$4D=Ph%*0hgQM)9bsQ?DR*dz`5i^n=VQ)O-<8)dn)=I -1@T}&t&6S+XEmu}w^7_(RecQR*a;@N5>Rhh8f`>9Zd~A8@+fu*kbGfcEJWzhOULW*wWOx8c#dv)w!?P -Uf3tnG3jiGFFxl&qR^7^39Nqyloh6T*!y7c-8eg5qp`mU^gRnq#B)pwQF_X~J@THmMjP5Gs#_31DMK3 -F{UXH#EJ>sQ6bpSJ1 -fGzRIkO(DSpa;f&^ifMg1jDh#2hyHBn%lVzME!Ou|f6rNc=`eiFG0T=R==EC{fJIu;N9k_@5< -`CTEXM3{xYq;ux!)P>cce_^n&#Ey?P;+M)&eVy%8TSMVrWtj|B=sc-A`i%#%V-RqZYW3Ko5mG -S!3PU|n#>*E_!)TiH5;oab=Z|n7|p5c+UXxUQVc8eC&Q;tKHi>1Dl)-Mm7#}j$;dFtCzf3IbDpnNs+`qF`$lGiWxz|Bf -zc%(ykmX+7{UO%nsk@EVwowlc&$y2{<)c0P$I$j^-dA&a9r9O`VR0{jwQ_lVDX(Abc?`C*xsDFp6f!(Zn$4A{U-TLtN3*#C^((f9hrB)y+f#ow^;dTdk3Vs*4{YZemt0g?P&!VzZ~ipy6B%D -y&n3mpf6c{(953R@jG*uw}Qtqt6z(nvH$svA+`72f5U{v_N0%%1w~{FKNxfKFC#GxhZ15-XiShe^o`mzFIu?1-GxPu&-ugUwQ1WGW -LZd8J6SrrKOva+XuapZXe2*-R-;CoLe#MHwpWD^Ji5A?E557uoBpJl;p8<`ydzO_N#&YvblXnNgl!Ng -Io>lH`;`Kf7mjFSG^dzdd)iNgj}^ihaWTC5j?(mb8u -yRvpen&2Tz!ahrO+|=F7c}p{{Ni+#ZhBC!f^q5*!LTlYb?hc49afkCKY$@+Mb*0{$JG?QU-B%X+4Jd8 -7CE))Pnf@4NKPb0^PVy11s27}rjpI)35QrL_~MpSrO2%=xwR7fznK5F87(O-t!kYBYfAAyQpsbp?8q) -g#brS-l2&J*(G2Z)Eib=*_I&1ih8jTcEeIdK>f(*YV+|(s1iW#^*D0nxfhv#f>!|YBeiv09+mopB*bbq}V>^s0kL?JmX>10}IN0kQrs7C%giOU@-c -U@%G2V!nN|dQF6-RfY&Qu)Q>CRJ7aa=c=OvORnXfYK>bc6TXQB+yK9sE7y9PhW^N0s;6F;scK{Q;`H- -~JF)-fw?|Y7$$sGZCLcF$t|>9;(MtOd@NUk|$710&AP6>`4@pxH_f@P9dg~u-fM1-#{^ms?(Z?PotOw -)iHIRMlp%0*`A2sL{WP+WiIrOQPrkHneYD-RFjz6Mm&R}j>$C1Srn6)ItBpeP)uTK8}U3oVv?9z=Ayo -ZqV}PYxu`!yH3_QSoQM}tOoD2ek{3}-f@+#Jc?LxtQ)n*#SyZ+62~F8QLp2GiZ5}|EP}IIq8THRm)qe -+srUCu}pOD(jDHH5pqRL0$U!lrJ;B(KR%!lB&QRPGMuTkabSVNVg<8M$+Vr%5HuAL;dmI)0X37sUgW< -C+C!X&h2{tt2$CZW|$ZA@oU2d(AZO-;$h!)-i>jCpC$!V -J>2WR2`hD;Rbn?Bsg#$%)#j3%#AlBH3_b1>fIz&|K+Akbbm*35?v#oJW$%X)XfENk(xwTHy1(fN_&>3 -DSMMtO%GG=EmD)-X>6jH>5~e&<>Q)TO`3F+JqNW=ubu6kjt? -NEEoXhCClMT}{dJ=LQ+xm67o+RQ1{+0L!=}E-(7U*x2o&;RSmV1YEJ(#f`{0m-b2UA1+71H$+5eCb>S -4mIfHDB->`rb5Us33rUVPB92+?onFJv+(tO!5u?Lm$w6tlHBb(0#0?yE64OQ8=yZE{>*qQu~@3{9VMd -geuLELTEcQ=u&eN!I2*nS-R59THqxf4IrZy-k#eoN2zauul#^y{Y-`a`jBKjW?^W4L~?2&jQlalI!Gw}3Ca4; -Hluz@YWgrWGCoTq?U$fYKO;5$n{>)+L_Ft{(RD`xah|)G(5**x>G9fRZ(XIg*q;KE>e8u#S=scn=TDw -G6C4XJ_6OHCddKgMdpaS1u{Si>uCw)9z46+hd!u*k;O+ikeRzB8kgnjMnRm8)ZFC3MZg#IFm7V -Tg9`$ZNVm11@*2crN;b^@#TD#HRJof)i73}VM*KX+cIA$t7^VGSgCr$TgwT|y@_OEm|);5P*{c--JMDUyII~Bp^!Z+IbFI5|rQcuM=#BLZ%du~CH@13@R$F&t^LqDkZ+tAFVf<43a{NmCYW$t}y -YXxB>+u`$oAF!m+wnW`yYctp_u}{C@5dj+AI2ZWAIG1>pT<9kKZ`$)zet`MPw0X7e^5&U1QY-O00;m` -Rt8hLBc!Jc4cm4Z*nhVXkl_>WppoWVQyz=b#7;2a%o|1ZEs{{Y%Xwl?VW9 -x9LH71-|HNGhlvfy4v}5ez4IgxAWM#yTkPs -gS2aLmuot;D#+IPhacxpYHbW)VA*pZw -~rLk33#G{^{ej>x0c+|Hg^h?cqzuTPAY!$k8J&?F??!wtL%8ZQSYhHwQaUUBB7c+3XIV+P!A}-)?ufy -)(Gh-Kq6%Z4Y*awJS*zTis{w4ZEk4!&kb)i-XPXmTAd+OnjpD++epi?A_^_e?}*27kV#ux9*vL=o7W8 -{Vn@Xb)vT3z0sMRdi2P-tLtY^T|R$medEHZ^|KonFP(YzLhWSj{?Q|~dJ=xd3D?(b__TX={X{LAgwHtPII?Fy>o$UIf7WfJZ5ui3Hqx?ZpL4@__IbDM*q;44_w0r}`}6 -KcY8$@bo{d>vbi&wTZ7)5PRdUdv?Qq>w9iEX*-^TzwCZJ -{K(O3ZilSdRz_cSKh!z@Yi>K(SED!GcpKy2blXuFf6I->7=PRS`p)-x$Box9{;u1>PWwM`yVyDZeK+p -3|AE_%#`uTs`A%LRx&4OM+xQK)A8=I0?`82#w(T#HDqX_9 -N29!W^9NRn%sE0W}jCV5PgT+t*~G|4qhawQ`<#HS@W#ET?{c#-4~FOnSMMUqDh$st}OIkZzGImC-3hj@|X5 -HFG(;zg2chU5@0lH5@E{s9O_*rTP8oYCYml6%qQGLkczT!}Qf7LlCMgktWykCOM51Kq$UXqus$;&2r*_xaqx#8;l16W;_HBE9KK6& -gxlhf{sCP`kNPcCv-B9i1QNM5!kuUnto<>x1mT!}Qf@)LviD;73KDm;R+=EZ9Ns^c6lSeek6-{!+CzrV^+K(pp<*rCcUbauZsI@Bwa`z7~?h{DP_~c -&P6`3YqR(FNb4=C8?1^T~a&v`HT!}Qfgyf7SS3XECt9XJB9Nzv$lf3kbr`#GtqxuQv~O4Q`4G9+ -g-IYV+Unp}}2KU6ztl~(aQOg=e7a-mONwkDTWJbn4(9LYI%rEHSd?Rs+edR}IC<&bIeGD*&8@`xn4_C -azVnp{M3Mw8FkUC|;eqG*sS8sv%wIb*IU8sv%wxuQX? -Xpk!!)}Ec}#;mra>N)AZN^#hz2?H^0$}-IrFf7OoBWnK_1f}k4ccnB*+Ga^aOY`emkD>TVzNzN2J8IsG)6-|@eQ^9jlBge2LUP7j2_&B@$(con%+i%;?j#p!a(d|sO>z%QS7aooAMvC$IrFeSvk1`($)n{axwPQPk-T!6+ -%7_NudblU1Iee<`I6h@9LSg5CXcKncQ2Sg@<8$_B{^fR_^`>Df@gU)xt2(B59W% -JkX(}_XKeB^%@uVxNzO@fDakoW&XJsxU@X_B -v)xw13`PX#1*FM&YvK=M*Fxss4vi8Q&$CZ`LY71899)#PO^U18jn71QLLP0sCvC?z@Pu1Ga`8$h0$>j -C5e7X!C&@XRTncg}mE_i3ac6ZPc_4WyD_2A$_ -px$?dBC&MtI6p#h_ob^kz6Lp6;1LLGgqV}=WKF_mt~XNdZ#;m1IPo&OL56dTud(VRy;^@8syb>$s-ZS -8E<999t)CsE7E!=oIfkb?NdSSL|q+_YabxjD-3c*kypiAsm2mS2IP#lB6%t(lsgv%^0L>G$3l>6`??@ -^O0EvcgCq}b`tw7`yd1SYYa> -BF7j3?UGFSUl4}vkW%bS_cgcawWo>5*pF6Ef4(HGOh6%gliaWf4nx -_;$*f%QVy*;DUdeiA!|u4^j$$wegBB*~dg5E)IbL?l-<$< -=a`oLhrfwkC&oX`0+VsqYS0AbBA9;x&1R1y2uqXD#DnK{B75A^DQKD^+_e$k+3o+WO?~$OMuHl2>*Y# -KW_6MYIcISh}(plKWb^QuYI$bxZQx5PSm4HH~sjqg;znu4$A6;DPv*c0mxlq(YDN`i8cDpwL!t`3qKH5wK)G54lvmtfq1Pgc3>FWn -Tx76RrtGN#$}5R-yZcHmWjV@KQ01$Ma>ig`P+nr$(}OCfQC^6A*R?{f=v9~R=|H_>Aw$(Js%iDiN_Pz-Q<(fwMlCLWV?|#iiO^QT -2QoIf+l?dG<*6avZv%4b8lXe%uS1HNhH^%gdwJONkfI#o^H$})P#&XKp8Ki+&+Q*pgC#;$p8HAx8MxNoIit$GtYBGkgQaR-xi^Ca9}#k!3Mda -KFJ-rKT9tb#d(s9AgK`h5oJP41ubh5FNc7$bMwNRpSe6{+oGM>-l&{(MPUQY1pgf>_wwJ+`h;n9Kxk# -1MD5tk8_n^udue>~z2UYG3)lZ+BSh^=reOP -OsnV->40{cZZV(k_1k7c6NH58{MZbcZauk`jdFlp}Y5PT^nrGp4h(KzdpR(8TJPKC$okJ-QBe1Yu&AZ -X>L$^Ww5h3`Ad^Z?Rc#{`B%~rrw9GvPSOy5y~(#f4gaoP>}+qFul0QA+E(|8-6u~RJ@Uf&^)r`VxU!+ -6y4pB*b^YwA%jZw6Z=61N>hi|(mo_e4KJ)D5+R57etgnn9s@Eqy_2ONnpbvFEt|1=f;}OK;d_0EuT0X -u8@p?X9hj=3&Z$P}6k2fLS%Ewy}Z@Y1O(Wm;azLte8dvqaN%V=Fl*HSuN&S4v}0MdnYEvR)NUyEv;Pg -vssmA6qQ7dREhqYGHrmGM -W5*tY>q|N3K4Gsq?L?onQ8%|w+o+q{uiL1b+h=Ul&F#32y16}Nqi$|b+i03w_RDA|d%CSRMD0wkD<^8 -Fd0jhEJICvh6Gh6zPSnos`kE89Q@dVwqIO=VuP}nBoz(TF6SXtC?vC3D8+FF**l$?Qx#RYmHtLSsNgH -*??YC^y9k<`MQFq*a$3{(Vt-^guBS~$oc$d;hG6SyJdz40!*jl}Chte=h3ZlaONi#{SUc5VLCRweu3- -=~XV;i>$cP346NYgA{sTb}>nn^}$&BDD%E6HfBQ -MeOnB^fod+<(^wlZ@7~?`dyNS|+0`Xm3qg#+A-K$ljQ=l8owE(B77`Oh#ER*_)D9l2Iee=mi^0GHPUJ -{+Q{it&+5|&w3eyX1p -fBEex7lkK)=QZB$D(+>T^P(#pDJfI*X1@yRW1#7ZOk0)K*0Q$x+tLIGohN;YA3G1xe`)<~xUrRap|^i -DVHmpd3u@@izwzJlT^$*Ym|)?JL6@ydGU9!AZ*XmQU49k~NH=74CNVnW++LXVAe_&E>w&B3H@qo#>WpjQT4EY|nCzz~T&`UU;M!)Emof;qF0h4trn;PTqU_4DaOK -$ux7*C0ta954(8!4mP8ZML$-om7>=xJw3fBaV%H#xVniSaRxkC8OG4HM%vjGL6(S;~7jV -T`QN?JVW}*D-D~Zf6S{S@PdU<$_me=wdT46|_$uUI2}A_WP*hjAlRRn|WrfGVru_yF>X|Q)(m=*QL3CkI_-Z8<7RB(9%J-37 -&l`ZL0`Uw@g!UL4Ml4+N)=QL+5R2IO}24%{=O48*}`qe{?{>XvIXHi{&O2o9U!oO`Lbg75e)hE1Ybc>miNP7(zzG5Rrv&D9E5(|0gz?m -`bZJ*&kpy9Z|TFet~gwp@IuA#%`QgKQQh7!^Vw}g6kbi0jV!uhfLqYu*nn#<0A~Gi9##C#JKAK -jsF?r?j6F%=1Zmp1IAOoc7ja#OBPGa*HPOY -Dvbmk+sJ-oNwyWZK_*dFZmhP^x8jU7{VIjNp%uQlW3?&ne4eYxA+-stRJ@AWpex>*}2voo;-HynbT*U{p{Iu=Rf!P3m4ZfJ$L!a^H;y{#m=?so86ag-0Xen<*i%&!S>GX@b;ZAk6s&nb -@a8-o1<@z-Wt6Evy`wBON@_c4|k-5fsytS`hXDUb& -NM5cUCHy_0$n_5ohPlZp`b0glh4CS?1djpH+^3fVqrRD4jpLKPPoQc0ppD}*DG -k{^Xyf>#@9AmTK4|0k}2%Vv$qkoT^wfE~i)o;pvJ+0IX0fN}CDAqGGWKe!J& -fECQ%aS1f|?l*J;*v`{Pp-b`66f<5zRD;7cHg<=uZc?!iMXnVS15loCiu?UJn^DP#^gbBqWEEbU#yr@ -)^v~b+Ca6Ed{+K$IE(ZM3o|6gO6@mu>Z5S3FN@>?7#yEOEFP)h>@6aWAK2mnY{22-JO51Ar14Mmdly+tgyqmOaI+<4&J%Gv|HwWk`Fu5LZCzIO1yp~m5N9d4Xozp%1)@krz -H*5ij44RY|n!2^$PtUuYfv~ubGrKfsp7uGlKKmWw?#)aP2{hQ~^|J&?sUD{Yb*V|~UJb7t-W2hFZ5Q;NakZ&M;aek-(1;Rd8%jrvw5U(V&x;f)vM+|vLlU0*H-O+&K+r->RnvUcR -hIE%%f+|9)IxE(uoI8y?5#4>4zUV(Ky<;cJM%B_}5xE(zw=W9BSOt|MWdM1bFV&Z)XXO4Z# -$T2DcNqVy#52ZsB)-V_4S~1CI5#CO#`&Bar^)!|1>Tus{0s8<#rUtuak`9uQSL8}^GgyR9#6Bt|5xJT -yuB{*HsfEGpDXaM$o)lKUzPidy1pjQkJ$g~5*OF&8xj|v`%Q_9dcP%c@wwlY_yXhKk>_80?sp~L>PEyjN)$LFK}xrD`C@(YQJv;3 -Blk#)L{ --2WLbQpi7z@K?{{=bIGuX&hUJh@fo$MqeT`7zF@%#Z!6%ny82=Ewe3<_A75^8+81`SH1WFFjeLUUSWP -5eUOlp`{KnC91*KTPwt;%I)2`N4!$<_BJ7evDsbe(XOg^JD)i^P}8xnP1cV8uJ@!zUDIXoixAZ_ -TXllRpy_R<_~55y{h?Rxjh>510PfKYs{}{euen~Pq*eru@&YAoHT!ZZjZ+Nn%kpke%0;CEb~hSj_LMj -%&)mUxC=-1`6s3MG0twgJ(}jPoB2b1{#b5L&6*!{H7fIKKEKBNz(-_$9L|V7e`5YvntxKvkK@^Gx5rT -JHJ54cM)RkHH*Ugv4M&=EuQQnIF4Xm>--pn%k -o>KkzE^WAwV1UvqoF%ylKaz{l16ZFYMkqu!0?pOo7Z%KV{j5AfaA{J@jj6NmW&-5$;7$1tP%{7S+b%K -Y`ZJ%C5l{Mfz1{5Y5qHNV3A$?dr-=Er#$nfcl6k<7Upb9<7{pXT;hd>7mvh50qNM`Qj_w`V4NeiS<*^ -D7DOM3^6=%qsJ1Zcixl10UJ#X++wH;l(>GjJF%}`GHTn&mW8VaXx2tKK~wN{?N -HSI1M$;?U{_*6WGb6B)oCv_C)I8)tEn4!dti71AN@MJsR^HYP;rPw!2_{P4jDRPbl+iZjYw --PC$F@LDfuQ7it&95=Prunh|F3;z$nfU`XKaPGX65c?~uOz&H_sQIzSUtR&=2w}Y=k}DCY8N!W=JUsL -dvN^YGC%g8_D-(4nLk#-8%y&~8S@9aJ(1S!iNySIeEvAhAE^1koO@04gW<>R;Z>QRS8OXW(k`sk31*) -5PA(khv~+S!o95S;ANZ7aaseK7Zja{k&-7ZIfjzvS_-RbgDJTAdhY>J#3!Wq!##yV1 -!tZEg?n-Cn(6Qp_LA=dauC3HA8{nZNF}I_q_NW;x-7S|82r0X(YPqcMLhw+G`-i{{suALBR)FEf9MVe -a7e#M1nl+Y@Wuo>*>AET3PS+cPP*M`Qk2ZjYw<>vns9*W~tSnm-crYns1a=AU7=XV!gwZIxzC^M|@U8 -uPcflS?wmG_Ko|65cyAKS&@ke-zD+-AC=@!v15f(j4gagff4i+Y{EwrOoXLb9)rck6#GmYJSb<*W4c9 -<1#bxRXmV#w6G3+^ft#E1Eyl?a`QjQVDM)%^%AAlSz0(nIBb+H>)#_<_}~3S<(EVKL4cV_Ow~ -^OJ=copVP32(HwF$Q*WDa^0<{9v|e*ZiSAzs -CHbnqNzJRp#e}S3c>JbbEkLJM+iV{2KEEAD8(=ZD+=JtRg_Y3oD32!j-a}Te4q -W9yhPR;GX{=2RDV=@1%XnxJ-ubKHZw?|`s?7yd&AMkjZAMmcO-Z1OTuO+&E<@R(q;gwI~eq?^&b-6v7=C7OifzK-Q*R1 -(N-JVFAUz^)gGxIB&AMmbfesI$Mc6&mZKbGe2@T^Yx#NExCSwd%Z*3JCDr)5^B#{9D~s}uOB%&*ProH -ET1c$b+U@LqZ|3*hu-mRVqaUaM0+Sus~^(=>nReEzyMf2hwtskuEG^M`7Fj8m89pA_?J^Z9`%=1-`zEpK2CWPVNaYs{}{evSEo?=JIenm0<3X7g*BKXj31{MH -zE*&g8IGCw}oVSe`c<*k{RzZfSme~#}z=GQd8=JRWsKa$&{EYCj^nqOJGVY)QG=JRXJuem*1z+1QG4| -RLEgIC^yiTI0g67lEw-X;Fo4tTZo+9ne4PQ>idR_)oV0dF+opSR2}@3qAI#W;!ibA0bIf2icw=5$7~` -6mg*s=Q_|t6uMEt<_*KGb|_RP|3e$IF0O_C&kF;0^FIlgz9KXlQ -aNM=vy;{1x_$I;Ye_JrlTam=1T=GPYO(U@PG*`v+r)R;ds-;Krmp^_iR>CEimJ}!APB<3&1Nz9+)dzb -k`=X7eCKXB=W37I{Cb2`Ip{y1jOl+ET3?c>tS9*z0yp3|w>{QM4HdC?Q`7vm)2&++|7{Gn}Jn%NULrB -gF|_TZFGWz8Oi_(NTOP4b5}@YXH)V@>G{HG49i(@0rHMVUCiaBJyR$yACu7MkuS;V7Vw}YMIlgz9KQ!LOFk`-lQDc7WKH@u -BW+L7VTezX-C40cAv+DK4n#*t3YAc=pMEu1#iTHDT{}F%aiaj+;{>gYfaU_2flRuW%6Ds**t -LJN&e7<8|?dcODB4kh##sX5q~27DO{>;CQSYr_Im0j{#f&RVlCAc%j@Y_;+JQ1mWV$o{zUxtbEl8^11 -EIWJgsM%CUk}o|Fli(2~BtFCjL;xpV@UA%BL^~jxuJYpbz!{x@Ynjm*81IHo>;a>W`r>u1dpFh_S#X@AcJGExsSXl_{MVy&lbvgBfk%22j`iD|Kp`Kh_&~L)Y!8d-Vp5`L%U>H0IB^hxZlv5sCTpaT4?A_}*pyP`9V% -r8;MM-JUp_Ka$U{F@LDfKW)qpd{pN5`TWluJaF*9p2cVq>d!Wh)lnv!10GpE_OOgXC6I!_V|ORmX5ve!81!AJiT=K%)^hIX&h}_E6$OTRPA}jKeyxy`T}Iz|&pYva&53>QwNG6p(EBVZYkQYPWo>_HQCZu&Eh=j}Y*AU;{T7wAJz!C)t) -OIkv(I-0YVY*+oIveu-p&MS@9}n1pv*EYf!e#9mJbDLZ|!zlp!U9QcLZv0>h^*_?H%2g*X@W!#dW*qu -Po2W>-N_cmDla4Mdfw-8;i>8_O}+5*X{2tYAm|>;&>mlsQFnmU+nvkMU8znUr^gIiyDuAzIb3Bwy2RA -^PL=h#B#Oyc{ab0qwle(`DHx6n4|BtsPO>iyE*zki<+PA?c$66xJ8ZFX&18Q?=5O-!?k$7MTfO56h)k -{peYR}=cGl4r7aYdowA^*3O12_8ZgG)+uWHXN$@^@?R_}@5sja6{H+xB$5iOuuwvsXWRXWa5X4DJ5RMFX*;G-W+V*0FW586jD`V)vt^VS5wn0nzQ?d39vt@@3=gZscLw`N -nb9%$qGlT@GeQR6M(iSGM#(@fu!)p)ggNsjqvngliH$R(WilN0PZ&1jgHQY^!-icQ|0wGSOXcT`ngnZ}1aDLZ`cc4g3s|*6A){0} -~F(oo*K!n4pZ}Y0k}I13!00^fc#C`3Dtw#YzPZgChLsm}4+LtoV}U-)sQHE}(B~MXAEO2QQHG7!z{ujzO|cln+S^TXfr`Upce_a*kYjE)a -|ft^`FxQDgpYiIVI!$i%Qa*$6KSwc_+gU>Ne-^Tcc<)bHC2=Z+3I^(8TDBN3bGH$LZG|KJk{2-D -$1d)5|Eym4dh2*?_oyjb>i14^Qf0H-R&w`@lTTBimpXl~YrmS|^(_A(_79|Q5)BWV>haWl7INCV7vUY -K`_t4d?p0VuD_O?#0U+AsgYyAAp-qzCE@{_%z_vHWfo+6eW{cm-7?c(L-i^CDlT;AMVSzZet!W_ub*8 -0-=#)aO-(v!=Vj@~Ifxa%WadeW4A6oa04@YH+rQxrVn*40ZZ=a*NPF0F5_Y^^-iTiP(`%F(&|y9=GpP -$q_FrV2>{vJpFEdVVEL`)K7$-9p(bOx9lNSqrg*|f;HP*b{=H!cXjWut#Ir}1M -W6j%bk!O(=3nOn^BwA#}+M?MrCyisx+ikw6By+5JyUkuRDV@T+J+;2pvp6}ixY*B&k02)&b#oOYc&v5 -1%`pdQ9$2>nzW+$|z_}f8)uel1+z!}BC*@-uHxBGb`!wyNvdq7ENdGh)6NyqJYumDkL@|h5;N`l*Wi=Pw9lHkYf -`UK--Iiq5JY8S|^L&coqEs$M@ia*Xc*>$+aBJv@(uBiBrB -EKQG4i$5lw@CIRD&{nAk?cv>gdFD?#pJr2d7xz7!{^2EkUfciz)ut9Nzk9SIMky!2?}(;oIq)k4bQFT -oQFwJp#x61O8SZIQi_s1lLU-{@=Ovi63R14z-TDXBmpC$Jd*^BitX0( -3A@-yv=CWH%WkUAUAX~qR9>2jAU{{HzSxlp_|c5p3sftk{h~_SaL%*l1gsqmfJuD%%K~}BsX-Uc{Oh6 -*3P`4Tf6BE-Hbl+gl?pc+|aGvu7qySsMdN=>htu<+J*I}HxHW;!h@UqFG2#8|G7EPpUw`(Jmz?rQ2rM -?8Or~ndVn)0EP4>fAaheR$>&WAWRD&< -2m29oiR%#)g4t27UX;3u$$oo7S%=_`7S+9ER&9(JA#VSLeiv>*~A;gsgN5Ppb@t|ZEZT!%T2g6GFYBC5j>;)XVWzo(Q2{k -+M)AgnBs!%kv=A%h^bt2ccfhQt~(m^>Qkc$3du41XjzL0UkgsQG(P!0A6y)h%(p!l<-Z;q|Plu7; -GAE(q_)(Mqd0Mnc>UbKD7Q9Y+M=TvC`jNU`f8D4Z*G8l0$J1FxddF>yGJ?nB^i%2s3ryxmbS>RfgHj* -cdr@g9;@*o&LlO60R2qu7_oC8J#Jv}lh9cKEq~yobOJ{_T+plGWkf%qHVjphnsPqwWTSujjh}$|UeMH ->WQRyRcTg8kl^0Y^iF0xG^)gB_-1XArGvP~e>9wKf6sq_$W6G)|p$Topgdx&fkNTr9!)9_~0k}toZIM -bfhO8<~;8L9RU*_M%N{}3Jzr+;YPHp^7{hwxB3{X@7poceOevMO|rzIPQvb|_eHq*7HKFq1t2?U-d^%br_j8;&Seyoo9T@WiJ}LFVhLrlG)F-7r7EP%Sp( -*t-e<}3=no^&X`ZQ`veWXWMihZQ9TJ8&CC#M|zNUyQn7$m&La%0erSnRFT7$hvka$}Hib<2%GJ6dCq@ -H0z|LDGaQcLuRzRPGECj#RldNO)M~-XO84O}RNpENWBk4wBY*xjjf&IRz0BQUr4Av{JyPlry2Z=Al{$n(7e}c ->=nrDCHrXL0Jl=AHko5CQ9YSI?CW?nV>1W;{WG!sIczKJEYhf2XLe|3OfQOodc)cf1H1jSYYhiQ7khc -k03!5Lmyidql*nA)4jY9T>@O_YX3fU9F@nYU8WKRe`$$6)ct(*gnyj93n&Pih4D`YF@$dFPaHt+d<&b -x(d<$UAh?LuzjRNgLR3m0q3QNNHaTqHZxFyt=rRdfv5!bPG)iGnSh!@qLV5U(#*ZW8 -xkvdmHURo+F#|yA(2{?JBLIs8L2EckL|X6Q7Wk{H!~%f<%XkOe+t^=mo136v+G@xiy|XW(*{LGZr6a( -T5iKdo)#4_H(VI4z1^>fpx*t?tzd2D(zj9fpS>>}5AH*(9<%wgn~uf3@4n+uS~LQd#Uv5=>?%4j -V&#;07!4eTix^0agLSLDruA-BtmR^)a2%#l{)b<;(osysO&t;p+!c} -7ur!a1X-JTV-t$m<4fv?8w?tr;cd$FvpgxpkY-XDL>`&-zer(CY -BE#pqH`W^`z#GPW*F_Jb&J4G)Vi5rBSVwE)tbdYsc*L|~5r&yDZ@*G5+qPLIY93-8h7m(5%8+5)Pk`{ -_BaYu2}AB8!#t4*}+P-tmiuOLDmifhqIR9X1Vrko;Aq$tOxoFY%8EC)WlToR5VOI+p3(r<_z&tWUKrxOr=EV|k6jtKqW131~>jugkzUK6sBCz(L(V`1Tx#)#E6mblOw%cL&+*k{900-yLMLOI~< -0e|L~=JlYn`K9o_~szqZDWt0dnw?$J9Wt4VtPw}=P%6f{b{~!VxiYP6EmD_=Ab}3%FlJ^6lY_UHjv$( -lMdPP4zadV629{Txd8I0}uru=m+UO&_Hb{kXb<7*O1%fvO(GI6uLOq{g`^JS5r(VX?5%;)6t`D0f%R# -sP6&fn$gZn0L0b0eTX85@juz>$}Tt7V0_xC_KhV>WdB?CGV&#ddcotr16fiiT1&l%k;&4FOHjP>!Z(h -|m-bnZFbb0Zq|RiiR3BbqhUqWsxObsaE?=Kg`_OO;U!PL{&~OW1pHc(Sa0_3bQU}p+3tyj73(;^3U!PJB(Qpf2pHdUia0_3bQWw -#13tyj78_{qJU!O`JQJ1ezsgG#5g|APkk!ZMuuTQC!Xt;&1PpO$`xJCRxlI=vpE#eo_h_4(Hukw)%MI -xaozjBBJm(nYTL@H5w<&bdoORpS~5tDr7kVq@auN)GuI+Cv(5@|*Gl|!6LlwLU`mK`j;a!4#MIN~dZ! -~%omR}S$)f<{hx;%y_SJn^?+UQp+>(pPGf-o)n|CJUtRdYq?nl#Yt|KL1N3(y_0#f45PL@Sq3>s1e -I%d2Bm>d7LzyS01#sR<(#gI-j^kDmPI$~ja7(fYUl@aOzmSbi2Vx~UN<2{)XRsug@X&LdPbm^7r`(K1 -VhI#30_of}a^8wK+DdXFnJq<0l)yft`0!y%$(=oY*!=s$cd?wD`HK`Id6t#?69L0mM;kXosv|;*njlS -Mfb{=RO9KQH0000807zB_Q_Xl`)3F->0I#G003-ka0B~t=FJE?LZe(wAFJow7a%5$6FKl6MXLM*`X>D -(0Wo#~RdF@?Um)yp6e&;#-53m@Ak|UB0^v+}wQ>l?tX)=s*65H`2OR_A>k| -H_r7Td8C?{=*5i~ov$N~+MnR~H!GIk=5N0q6!_q`9}NfLq&Fcg2Yhow>U|KXYR;Ju{x(^Y$JrZqKI2k -Dc&NedLsPbG9>?-a6~uUA%Z|pee_X9Y6Nse0Im%o9vz5zBiuk%;u+W-X6_&#*5SYH}wDQj~9FM*^Tks -o7~x(%@^KP)y3}ksRxVkdBwguUR<2*jCXZU`Z4XZ-X~`Jlf~rTSpONE^)5_a8t*>PfB0v;7pA-Tvvt< -HG`=-j{`B~=n=*j=%bZbt(fse`fT+GKW4l_Tlj?WCBo?RNmsAY7V53qG2?a0=##hlGVN+ex_X1QXc -NX)D5FalZ_=*X3D~>7?2k4($OUi{+;&JCxiPQeOtOl-lshcN -sF%&MlT?Y|DY}C1pX%-Ln_}ls2E++;+upqBro+XDn^eq_%;=T4DEO5%lf3J|Drv0NsI4N2JPzm^koCm -)qhh)kF@v!?TYT2AJVs_Z}mU4E7H@Cs2FV`_fKd~^re1EpWPx|{fsgQ{pWP{s1(1Tk7yIdFKJJd@hd7 -ti_G``(XQye{55?z72^ZSpey8nKAa5U!N1UFkU>A7hhB#)&x6FFM^^g5XXwMpZaSc+VYfwEe2%v0n;| -)%=Oh{21A0u--zQEQq>%%UNFxUrY2*MSGjf2DLJrW=$N~9M$N?$R$ -bp{H$N@$gIq--ya-c;TIlxFG2i_`;9AIQc4m=`_9AM-|4)l~p4lvTlfsslh2cD5e4#=HG4lvTlfrqD& -1Lt8HIlxFG2N;==11-|X0Y(}*&{YaK00dc)105BJ9QweIks~1?8TQP`A=Ww2Q-d7gkQ}9RI6w~U*)(# -XK`oGj)j2riV08`_IpjKrMdUz>6mmek%*Y|uInW@#&cPxFt8<{MG;)BEMh-k9jT|^yGb0C1=`?bnMRC -X>);Yi^5IF`0IOyxr&5_wyg%-JuRoFCX;6RJ~#;Q_*1C0E@0m;+Af$2yC2U=tW4m>-vu?mdL#wxUMZ> -&Ot%)o&bnN<$fScR8L0|#a!4IE(P1`bx`z)R&;Iq*_x;J_m?1BXSG11D>KV-;FtHdf)`Y2d&iol)h$@ -6*5mMv*E<&mc$Q_&&nTfr&~Z2PP^ja$q5DoXR0b4vczc{e$ -{3-|Q=HQG~a^!&E#ko1;$RRgYSyVZ|$ZxCyBeTjOMGnx*Kn{IO$H+mSzmlKveF);Z83zs>M>X>~#03xK$ie22bI4&aw -yIPQdA)MTE2(n?q*N|FtE?7T$9gNU$ojhI91t*n-70bQ5jLMg9+eA5fjWn{ZWY#H33aRF$RRGWZqd&n -E_et={vzuTBXd57y!wd6BJ1+HRbZr%1B{IM9Ho}Z^@)d^9!V?JtpX#f&LJ)}R9uyHxy~W4vd$p~t8;MHDpuz}PnnT}wN~L7nX9Zjs6OK0lYlI8u+}QH$ggwA>sGnQA!m`pT -HPuqItR%ir{{>(*s4-19@Y#wSe*lmrf!vIS?7@ZIl$Pk*ece~!Rj0qKPC%CW}O2qHY~Qvg@>GkR?*|a ->W7_J;IQZ*2ctmXz%vR24vb;uuaL8D4)()NoXWwvIV^tINv?8W)N?z?xi12;z`?22ijUA^VI}0?LaXG)DljUA94=H2i=kC4a&RgKYph~F&tV -ZcST~0lIm87IEjq|8eoI!29IUa5MGjWwu;(CWjaBlX+;s`95*w>3`C+GkBm&aizf!@&G9Bb{xPXt61c)7h1&{tK^|oV3hDlKzqo+euZ4_AZOhi4n7Hpp0Xkb8svA7TQpYTt@5XHu*e~IbI6ecI -z%0cthY%}F5Tqo^I@l&=^SOcIpoMuNjC?J9GtZZ9py(3i*63FgIwIauUib&h%=2WPD+6*=1ElYogWyGl? -lXRT_2at|Q~B+qZHVv&PQAxBrmeN5IxBA_*$gSA$nK^ZCJtj-~}Rypuwev(_q$iGXrzl{} -q;^K+mdNatXY!=lbn#Y8~4&ViT8|9KA9S|#^$us -VkvIUML59CDQEA@2|mIo*IOA&1yQ-dL-Ov{s2@t4c+VTBVS$yS2)m&cPxFS`=9DkkvWrWv$|n1N1UH< -itTv_nFmthoILyox_E(ip?OmSntrDvC3iwIUZhIy+bs}n$BU-SjDDuu%T6K)haNurgN~sAr7swXsnWl -R>{*jSO>X0C>MsT4ksm -nFRes<=SD9^99B{}p$nl8Gd4Oy-hrJAPyi{)gxZKOZ0tZ^8fdh;ZGRWDFbCjuau#r_3RSq_T9E|+HA@ -`4S*&N~wau>kSBau~fdsNjwzPVlw7CBfi2di>a(#rvc`#eC<%kXlr$Wf-31B~Kga$R^iz}PS^2N*>ft -B8M`?t-J-96<7{{&804kjLb%ePopjV-<%SY&M4rH-{WK#I;AbLb-DPIBTquXOP=7R-=&BY~tBAFVF7}nIRbu359OM>CtlO(SB6pCxaC5NMDo*EMtyLUylv;a4jvV5uRb{$4+;Yl)>`GD_6T -dO;<7m`I>=dT6Qf77L -fyt{GnA~6o(wF&S4KZz{sBmC`S%f=U_9)aZuLU&*8*cMLz39SLjNWayjH+(>XS`_6VzU$iL3P##Z4OC -0MImAP3$mtF?+t=a5^gSU-ow+9ND-h-0f9SgS04ox??J73=3X?GaYzU~7+nQIFUvYf-r_kb@M -hqU+5~9$*t%m0ji7*gQac=^XYPUjj&f!4iU_-0qd4Mc%$W;#3Sj9TXUE~3ZGsw|Xm5NsBh4t -_e>uLks9Mwb)FiI$~4thP@9GuDldU5F-EOMYly^B_X(WG;DHFR^hK#qWfR?+2SRp(%hRq~)*ywtiPhu -qD<>Kyh`$XT7kVmb$#Le3(GwG?u>gIun2$dN-_wTcbOWmCvmW7WDNhsB^=xz4d3$f1|X!$+)=mE0WSb -Pg~Iv{vC6`H@2&T7`#a4y}?S2di_469Fw+tK>R|9630hLu{?GsB_4RkI0du(K$9u=McL&oFIn*4!Rgt -$^%4;;(&uyIoLeFYWl}50*74Xz>wqy4!O#~R;|J_>fq*J{o``rK#LMo4mN{)-GQT2l|!5dSV@(mO|m) -Yq#qTN%NnaVkyT}8kfWzs6v`D>t+HsWvY0{6<^giZfd-Ar;Z+$q*27p85C=J(TQ{Lq7Ih -95IjX61l1m+OS0Z(AP3IF#zDTawW@EBgHA|Q(>c~&=O`07XRT^HXu|{gGb6}t<^>q%h&H;LZ9NwzPA@`7Ps?O -n?e2&B@9)%oW#}K4!O0;Uhxq&6VRfy%3i5lHnz$Ea-cNki((QF*L|QMPKQ=PF&e47CBsG -0fIPgN?1?KF`r0M}r*hkfUod0TY5$HJ<~Fb=5h*Xfgpk+d2n_9M#l0z-V -Ht8sw-RaVT4m8g&gvW-ax@4KZPXw~gB(#$4RSQdv1ByJQFr734rE3SID` -)Q$4N{sJ(3#aXpkf7sX>kgIhKqDIqHraa-9QRQRH~}__5>1PN)+=jqwZ9o$-s4>3GMxd3!V;-CT_4`` -+UAXyNTlcD(6q;f?Q4_7~n{>MiD@$#gQk<1<&ri@WpblCH*Y|G}Lbvt94;y -}Q$!i@T%6WHx;w>UcKZ4|~2b-ks_0X5Ob}^POc&y&k+%-f;Psnz{3{>0+)rGOxFM`}6VN-o?@0o_?)s -qZ_;9$M>H&d;Hk7=dW(}g4Xu6=gvL9eg3&~SGKQR-oAY0>1VEZTi(NHh_rK|+g%RO_4}<>Jam4N?#J{ -XNe^OrJ4tWH^iGoAiRs-Wy&KbeNqR4)_mlK~OdllagP1;~^aZ2}#qC7oDaa{lZ-9{!_a+!^+R+^3l(= -IsQu4kCMp9tkOh8g%A2Z-5MfNcT{xHeF90bWp_Av=TQf?o!5G3XHF%3a-o_)+ikd)lVLt0X38@I>WKpJ3~UnO7FG^70W!V -?;2CF#=8Nbnp37ts94=$er-&}((ZN%73(@goS2G5-R%=9R&e$Z(E?!dHZ8 -f>Ad|3sC3>w3aa)_4x;xx2ddV?TD>LpDNwa*x7A-#&x5LckF5wvp9WRK?jU;FGdQcYoo^5wjvoV6`^y -H=mU|Xd?H+AK(ES{!O15Ft!Sf($x9=c&-H(GBiWa@@pMn~SHdsI%$nj5TcY0>r8L|>EUOl^pswb}%iFn6cV3dgcXjzhLjgm0l^)o|N5)LCt_6$`|UM$Hc4Oy?u=#|YiM_*_9(IV -bAR3%@$?ah@d3>9fbL`x6--VZ!_~cO>bHNL5E%Aw1wL -C0|Pc{2c`YZzMccvmP+&v3NxJ}yUtzTs&3<6WRQ1H;in5HDiI85)ir0^hvB$Z*0TFoR>R-Qle!FoR?E -au{_%dNbQOyxjz5*vys=Z#aP&HZwipEhoUR4bAj~H=O{ZGc?nqZ#zT0^w7+XzVHk%YC|(Q`pz>j4>5B -SUV8%5#7s_j^$9T0Lo+$y^(VkU56$F+SD*kxGc=PEUV{Sj&SrALt56#QJv5UOUWeKk&Y_u{@JiIia1P -Dngx8|Bkb523?In^m}61_4O^O4Qt7#4P6W0?#GPJ7>1U;6V -pFy=%M6;nDK9hp#<;a$)7WHJ@GO5^M9ya44g%FIzsI`dvd0cQBs&J;Ts9lEc -}!fxdNh4u9w%(ATaG-tz~Bu9q`r>xYJ}_wV88#z0@a`sn9>4PD8L(fpAiYkBeW9~-*9Tw*o+#L%_8c> -SLmdUyeg>98#aK8=C?xgqPwdOY?QhOQ55JocA{uGcc?zcO^amJgeigV3;qMf+<**U5Bv{SORXCz)e<4 --8#n6yEbUhOUq2=)vR=4nmt!$3INh@DxpZg0AI_4uJ$+&#u|jzr};Y(DB3B!$Ej6iTp);S!H -8H9JUc-a~Qcc5=(F;o%zb`ajnuA7^j8d -B-?TyhlA-JQ#W1{T=t|rn#Cpxp^>W6xJ9ynNLV587oc@8ngZ1!)Hw;}LSLo;~hOXr8VxZqNbR}>Pzv`fqnMy>)kVOLuU4G?BK}uduzCZO`UApx0JMpscr-#^b&1(f-ZJWP5kK(4LvCkBxTs$HHz#yL-1sH^z%CeWg{ -mS9MQSS5kHPRQF7Er&QNRbyHNALUsRBH$8Q!Q};J@Ra3Vzbpca%Ep@F@Hz;*kQuiWt1yZ*ib+b{I7VQ*cnL4)A38fArb?m4EMx7<<*ia{gIttE9#z{>Z9Kijp3ocM{{c`-0|XQR000O8NLB_@th0iGY8(In>4yOTCjbBdaA|NaUv_0~WN&gWV`yP= -WMy(|8Z)9a`E^vA6o%xp=$8pDh=X?AgU@-|LM6iJJ;cqlxa*m1G}xgZH -~32d-fn)F6_iE}uo^Kv8d+otmXLxe+mi>R5o#Doyf2%X7bRTT=2gAzs{1EG%7ak8gXY-e@cZQeyYn^p_B>OSh>B`If&F--Ku -w(x;rz@Ab_dDy4?H~GdxVUb=Yw!s?|nS6*DbeD&P+j -K4#FCa{Ze>rIKfNddBZ_2hwp}iTnWRF&ebs7^x>DoaMg#eg~>yf*Tb;(;TvJ{5WX3{8$R+g;h4Y){zi -BvFoK^Aj}2LVE*!zrm25ZK4o3=3(d8(s_F?GN1v-wemN6TUgW0`+eAZWyll@V#(Ee6 -$n_;RjJ)^h6^MMO? -^mh3E;C$W-vxTu4eHgwU&hyC|;rzq#pS%-(E`;9=-wucQ==JbpA+3+x;a`1z_kS %~l&v7HcaWi| -4>)CT$vpB9LIIdY7*Bp);7RL?FaV5ZUg>zh?99JxkE0p7E)*M$T#}&$Pg>&3Q{#yOrz>G781c!{+KhU3ZW@zi~lhT!zW#&bM`YHW^coa1Wt9M4!B*Ag68OU3cj{c)V*gg>r19M3o$&v1^b={YXpk825z8=T`xMvqHz -+{F{|$EEbR#pm`OdOn5Y8t1siIj&h8=lSCX=eTBZobXk694CAgjdR@K94CAg!XMW-$2HDzp08p!99KB -UHO_I3b6lewS2)MDfF3sj99KBUaeq9Xuae9LajuXC$VR4-2kMq_!367go^f+#P3<EEUI7S?475x -DwzvzRsywdK~9CUU#Taj;n|qC-it+jxWkOrvvjoIqvM1X*pi=_2VJ<4$eBKh#prs$CU)f6^r8v=eUZ; -@q@e0$*NZ&I8Nws+*iT%IE&+Rs5=zmxZ~!u9Ovrs1*toAD7@bvChf -jIHAWC%JF#h|$HxP*&Pj1x5gd2%NseppkB2CW&GBqOIc}2SxJiZMgdWdW9M4dWYn< -a5&hZTAc!qL3!#PgWk7v_!oL8@c`zjgA@eJj7#^QJ;!EvHqMQEKfHI6%7pGf_9)z=-Cm=&4hhQ)D>bD -Z$U)6wH*LG?JR4~Wp?JdWdahY|I7M1LITIImuXc`X3<3!!z?DaUY&S?bnc*Olx2#yna9N%As@W&T!{EPNH6g$MJOP4q19UnR*pgACO{k9M|KT!|`}}9Ot--$Z?|Xkf7p_s8@-}abDdaPmhcA0r5D_>jRR|;}RTCyk3RXG(S18BT^c+vWUd8z&u{a -*PUWM{i9I&VC%O^SBbQ}-4lGc8Qi>k*(>c@E;Cw!HN96t#A9mcC4H;c$|6O-doeLzxrJaRv$lkZda0a -YExLxAu(9j2`tfDb<1)UA<74W5K#|uuxq3YF{hT2w( -&BhbJx*|(@Kr?W$76C_#8+8Ne|+W~C;V}o -J|LoAh3BiJ(+8AH{kTZI3f>1qaNOV=Hyn-=eLx!L_{{5749aoN{^LZw3c+!Wb6n#bC)PO^qh5vUtGM` -n^|%nn6~S>A-_w`xIUauZ(^}^w^tgzxqFEd#d=*~3O7ePKg5!i9XZb2TJzv`2{3-S0MBSl?ufp56R)pg`e>{`W;{?ZvdX?qk_+t7hilfKVSmz{sm6-M8Y1 -JLN_oq^?LU3HlSE>8D!|>a@guV*FaV4S0=isXl9G|_fqF5X!d=;GIDs7G{oa2haaYBzz&v8PJtJ&*u# -pAf+W9q&N#c@S&+{Gj9uTu5<9fn`qIjwW@^fy{cw{|Jah$zxt?%ayzn_PC{7{eY;kZFLPSlSRb%!iH9+BfjUp~QcmLAtA$0h1jG|F+!;rJZ -<@g>#cLhGDV9}riM`(@737ZGGd6gke@?l5NAArIq(JwAtJ&Wwd|5qq44af$5?35-YF?l8kK&f4w}x5t -Tc6{37RLoqI}-60{ziR}&z3*#9J<9bdQr^?4&e7|zsl`qb?T!oV3#&f*%l}k#Fi<9PYFfF9R4 -#|c}7C?6;EIB)xLDLqcv<6K*X(&JQHzKc)!SU0X7ceeQ+Tg8{Fl)gmEw{5M#IX;K7L!KTdI381v6TXU -s9w*AjS$dq{ILlWd>~X?Z!P|f&^f=+Ga5&D=G_<#tA -vj>jH{tkMpX>W7^{qw#uPBJ`Ki~$sSJ(<6K)MF?*a`<@B~n>3flsJsy+ei)xRj-j&a*R$<9;qAOqH9L -Mc(jdPq;br{he$K^O~k4xAph9$=djuTx#OKOiNR;^;c0o!}O00)NSbJ*>04z|kdtH*g9*Bp*3oa2N&j -&pqGwu(eoKEAsOZmaP0IL}rQ;rOE4DlVRit>Sk(46pQq!*P)=pgHJqmAD>PERN&LoFY#H!k0OD9FJG7 -Lij2;$2qNmQ$d$Z?*nB2qoh!g$20L&8>B$g0C -c>~S8(lUn8ER;zF~SD`S@wa1BS6)`#PA0iQ6yh|v@)2SX8=>nQVwTk9&oUm0Ss#PTHab7d0z^1kFY?X -*|oUm2QBFpi_>~XPWPUScrUZqROal%&N>G5=yIp@&L$>KOqkF#u*h}GkS9*IF-}w+&H>|UK{1|8@wmbU$zGy(Cd4ka*-+bSBzxE8>8v?d^;n -Ny@%*LfR@UjL*DyoQH8@t -3v|g^D0)ESMfN3ajD{QzqLwu9i-)s6Rye})cApR$0ceGCERfy#?x-)Bru*x50D7Pi5{SNsc|Wc˜ -TI6gwjE6J6gr -HNyu?xk(1!KNGs=p)HHR#YtEHFY2IsiKInFCqS@a#UC|4zN3lPQe% -bPaFH|44p|bmio!XrP>w5{;}Sd8vTDZ(j^i!)c(F<{I~}Tp(Bo3Jii;;wbXfDNoZ)O89FFt!xJsSlF; -_Wpj%x{yD~=xLaU3sJAvmr$94GX+LOHHk99JmE70PkESViF+Cw3lJ5_+7+@kQ6;Ld7aBJT=GtGG{m~u -{o}1&v6l7>m#S8=6R^E^{F5qI -iOKOr^;Kf-twQ+Y5vvX*b{>~l=VWbl7;&AGv(+K4$CKY8YhD~*(sfSb{qb<1pR)D1!8uMea~hoE#5yN -YJ#KK08=T|3W=@_S=dE)Zoa4M^PK|S%Sm!i2#|?|)hQo2fSK*Z%;vDDgtrBsoL)JPc%O5A2IiuC95PC -f39$7>)rzTw@m>?&%R}rZ^B -tTBAbn-SIClomg8S}QuDA}6esn2MaRR(K$1St~>@5MiybHaz6j9nIibi|9y!Ze;ecE%8_ -4IS$X$HK%|O&*rvv<+rcS@uS<3A2$!<8v)2Tk>?XnV4kt-bJyzYFKwL)~~6N;SGolk(ARkfl}kV{k_; -?@eQt5e}17xBmstH|eAeOUKZ#f6gg2w&Qj!QSSy4g=e2bnBt`DPoQNXlf;@w& -mGDfT0&Kjc~vVskQ4ntngw!Vv6HA;5ve05`hi3iJ6Ry-^#c(eIbO9Au^&j|AZPV;8XV; -D9twnm9IqoMJaUnKAOhqX2RTtkPJ!G3HP%CcxcjV7i=7n6nRVn8$X&hoem!#S_gN{O(VU*{7E_TEjh# -G?JRNH#W@D!W$a#vK1#+Tlg#bCO$O({3GgTJ)*%Lu#>;vQ`L1F7;#}|G4GSk)E>E3c+z -DA;<}ii&P&P2|-S5wL)+_rnAB;TH!e>tgTjN|AaSUs}&ZX8 -ymXGN-LrRtrP(mzQ{knGg+|&ZF+;u+r^ShJ$vu*X`Y{3_Fj8y9dbgJ=-1(y6wB -2Q`b7ftwC=$o{!t+;|I6;>y>9WwtBaRTkT=D-+OL+;C^SbIP$H|dfy(dU-?3Ru(taz?Zs6&QEBb|m5; -;Oes4I)4+N*Td-iAD-<8YljSYKRH`=$>JI`)Dclzj&i`TENHk-B9YHRhz&1)}RynbQz?1eMeR&QKgy? -X83`D>Mx%Jz7i?4?qx?T*stA1UR=PnYA`#Z5VGTs$ksGZ(Lx<5d^0mE$!Rub1O>7jKl~4Hs{g<4qTDg ->nD2)}?ekUGzk@9>aPfT@PYi%GV=CPo(QvtS9pIG}h&WHB3M`W9?@^ms8e$3UsUdf}aCZo@DJO!IbmX -eilqQZ|$eSl;>Idc`)V7wVw!6&RnJ&N5kCw#a<03&|m4bFgJgh*TUTVHC_vI1ImQC`K!AY=H@T$T9})^u4`d#{-Umhx%n%)7U -p)^N5kBH$#X8u?U#Kt%x%R-!`yzwN5kBH)knkJe$7X1Zj+Cpu3J6dn7BWw=b2R-6L%+d>j$(Z?oH}8u -hzt!Nh43IHhEvtu)4QCaaYpFld9Gx?nxSXPPJ^}j--*NRG+*bX;`gVpST-o*P-oh;O8<{4F+6Zas^Jfr&fgMQryZAR7Ipua6?T8TSO)8CXdt+br8dJf8mkq-E!5oV&j}X@ytbZ~18Hci{6r9A0|A?W5tP_d7lseyvu0H2h -lqu8+cWz -!m80SrZv6-??W_CY<$#p2wKfLc}t|NY#ARl&@5IZj}Op?sGYI#X0$# -sjkn!91_=;?F@Udbam! -bSF@Udc;SAMb4B$IlcrSGr1DKz}AFBH?Xu9y% -uli4ScB1l`6<>MYmiTH%VWnt!MO$ZJa!Cfe%#tHKZUj6e!_RY0dYG5?q_)CO^Dn4onG1bCd6&_?gxJ7 -TM)OoJK3@G?+~|{yC3hJZ$rF5w=-Yfg1F7v{j%*H1zAKOt_B?h<|n!g<1uY&-8lIM27`()}TXi=QhuoImpMW^s|b_>U -oO)6Lwc{siJhy6*VzLEQdsx$yfCE^>9F{8NY*xw=vQFNoXO&0JPLgSeetr(t(KfViDqr!RIsgt$%D35 -1>h_VHFBJlq)n55#S{PCD%TFT`!SPA8215aM=rm5cuo#O)8YThsm$g!6P;y0QG4j~80Zo#bl}&U3BqF=L -HYV-8zjx*99Tnr;N%fN-8^(@n?MA)IIG6vXHo5Y97oKb_!58!N}0ej0rf!g-!fpp3o+;XKWz%ieR|SQ -XZE2l+OH?H%f#=d~HDznm}|eFwspN-oRqLfB^MCg^(*wu0In`}+_s=F?^W1Blx+-8}pUgzcrf$8fliS~pf@IgvGb7sB?!Rc^$82=P2mrzA%|g0Rig9p%Rmw(wPM$bSNHdkgE1@*afqJXrjS6vBm;a1-arZmgPe0(tZ^2j{YEe);OT^Oq_smFwN!-Sy53kB1#=+F$PsFZb6v>(5$8f3q`O?X@3tR*vWY{)GMaCtAnHYt6j>*4w -?iTkX5~k#1}a?sqrueZ0filUg12SNnst&S3RHdt>GQTT7VgY*!!Hp;&PTzI5iwi@U@2v5q=?ywSbgUS -HklZ+3^>hn>}dU3XbgCtD4b|H^-yL*DOnHdfo4x4Yfd_0G^PzpUICY;``?vD)h!_u98Q!LaPiYGUAlbb>dV)z-?;gi&wj3b>-Jjb&fR<6SMIMr==C=So5QV#kH0wj(&)>huZ+Gr`r7EV(VL^U -MsJVa8+|bP@X6~>-gxrPlXpLQJ-Z=1QY-O00;m`Rt8gER+z@E1^@ty6#xJu0001RX>c! -Jc4cm4Z*nhVXkl_>WppoWVRUJ3F>rEkVr6nJaCx0rZExC05dI!1|6x?Vkd{ykNl2PI>A=A)I)XV2t)i -&19J9bGi?H)I6W!AV9LN&e8 -K}yfGI}|cnJ6MKQ4p^!+^gq72=FP^;F0-jF@J=mI{1?mQg{XqaAR~5qQU5n2>X(K#oCgQBDF~rbFMGG -aQ@E76JD?&1Dect(r>}-H>kRNfl4{ig}ui;At7@+$8f9DVr~mY^tGXoI--K%c-N^jXN% -3mYZwm@?3cKP}MBVtDqAh5+t8^$a~OCW_DC9MDV+T0(EBr!t5k&UA@CPe=mD)a@u#X{0c^fnY$z4L8N$!dBO`+iO#-aIl>czMaaerQ6d!xhF|T$4|_O(M)v`JHTwNVckpnFV9W{5VzOgZd -^Q&xHKS+B3-l6gCk^+lzWD=18qId6J$N7wtoESWavZSiJ~W`$=nvZFu+!*6Z`kkIPOFSrW-JMG6w+<6 -P6ItgoimB?#C79w5hngWV4_1bQjB2gy)aC;&v2=Yz{6^pFF%${A%jWeG|FUQy#+poKFzMrB;}4adZhDvfxd&p9s8IoFs8!L*J64gzW!Ae?z3H*NkT%4pihjOkRti+p8*05$?Hw -*XQLNW)bQ5Hlq54$0RyrdQHt2Mt^~eoY`PNw+UNtgDbB(ZTEohD%``NR!49T0A|$M;c%}N{5_CaixOK -y-NKE!D|wG{8#_AD_HDatC!B`{4TAmS0`MnbfUJ&EOitzxMOpq8atd9# -`6657|#=SmX6658%kIs8161*bDtCaCwnM{xvudI&?)`_vcopG;^bz-dNeZ)ssDe>0cEqG0g*Bh0C&zt -;Jq%6CN1c~u_#h8)3Uvf9Zc(civS{Yr%jC2*zMuNn6bHwUs5M$$r)zKiv#u1E7Vr(A4*d)egQaR?&(! -NtZI3_Wg^}_^{QzS@?X3A)%ig(DQrrr_b-TRF8TT}0d@h)8*1loPFS0@r|5o4=1c|YgGTN!)9 -Wtqp7BO1yGum%WwTRI|#xr_(;@bM?( -8u-dYRd`+VZ=BH)9)SDyA1IfKP45KEJ-cyg4^M?NKGXV6yNgyVZQk2WHIJC_9 -L8K=09@+3Toz2InReqne^^ZAGjZw!ed=wKxtwY`)}p?-BY*UNuj45TDKdLH^1Qv_GjCmo5h>mBzdM|mHbF3Ogco -Gpdy%H<@qug^AQXD&B8&?Gdc2qi+67#vZAY$>2p*z6?b7+ON&`?)77&z${71cq~mSbq_$EsTdriYOoV -J7xVVM(vGyC^ZCl0-TH{sJzqfe4#+I%dpCgStIM{yAfUPh2^aq;*Y2521{|4@He`{FwzC;Dw4(nr -X>CS$Y9z@0r0|ajCdomNVFz8M&L!Xj8qmQ9K#q^yGg~O9KQH0000807zB_Q~lfVzU%}50I&@J044wc0 -B~t=FJE?LZe(wAFJow7a%5$6FKuFDXkl`5Wpr?IZ(?O~E^v9RR%>tKMil)XDgWVWqiR8ADQwj*8*NoW -OoB=P8KYISiY#Ma!)VP68jq8*zrJT|9ws*XsA_>^&)j?Fo^v1e)m8mPH_qK~Orv4n8P6QL8BO|s(;3^ -V%Zn@WR!kEumO=&z^;N_qQhHEdMUn(Gm*Saqik)y3=#&jbY&bMZQwY;G0QML|DU5*OEkARjHmpg-WNN -^z!Bq -7%tr{r?V`kA9WoxYMri$w;SjkNi}E)hKh`U_1(veaTt?+9TUGK!{Kvr@7!nXR_?2Z^!<>Oeb}s<4=9r -Q(ee(zFm$c+?M?Ct{%ky|wbknwe4+n-|c!rme~-3?yleL|Q}!Aq@pG`b}vIuvU?Xw{|U)5!A4p4eNEf -Pr}`JP9sjilkQluMqJZuk%-WGk3`5aWeQT-*u`{pRC-`Tne9TMfdYP>o@-)({rq%WB3PpL?e6}(9b^k -KP$Mvw0t#YdJ)4MoO9|4c_nzl;IMR(s$Q*cu?BNEGAp3$Mr3F)#a-1bC3jt&LH1zH#bB}uCNBY!r-QL -)HyoNC{gP(i5dI{A_n##QA)SyMy1A@KJ=_}=Y6-^dDs2D(>%Hd-y90rF^@v5&4NhaAl -y$fZBeAh9AkE{mK+`3v&7Cx_;Y-T*kM#!2ah>i#ktbo*Gltcd -QOhNg6!9WkHs1b{5`Mc0vBJB8Ep@_s!yb>lx2-Bp^(t7Da@N`%wo|=DqIo8sgA(Pj(;iPe|G}xcEbxK -z<#d^o@98o0W&k@UNPPf<$$Wh4554~>gqer8VNC>9GavO*t%N0%3^T1!ka^eGqN>pl2Mc>zrw05;@z8 -spyH7akP+GPJ&wAB&_n{R^sI3E!ng}^b`CGw#-FcJ@7=o&9 -!9s7(Q{<{osut2M>d(3CEn$!_$rjjWG(rgA^(cY<;A~HO9KQH0000807zB_Qvsv0ka+_D01^lQ044wc -0B~t=FJE?LZe(wAFJow7a%5$6FKuFDb7yjIb#QQUZ(?O~E^v93Rnd;xIuL!Y)PERhUqGT1=&jUt)rXJ -*rDY*Xf>x{Q3YlaA?ixF?on570-!W`9WW!4L1|fmx%<;@QW9RDX@&n_^Y`%oW+@CC?35*vj|0leHy?X -oR3gSJ&O7k6;On|Ra1a9C){oz6|SWEtZ+E66fGi}g9iWU>AG$aJ=6G6o>m)vp!e!~Y8Dn|_}1ABqoB` -ndJgyl$UheIKG!Yo(P&|jS^ef;CNAyE1hNHj8wDQwFlXL~cI9a&z|W_t@AzYC+mVCXn5;``tU0igpM2 -+^Q^z_e<|SJG;}EvU_o>3(rb05?qEL%_vO^8>sCD${~h5R`VWJw%tQBz$(u@yXV*$bYaGziQX?Hh|m&@`on6!C(0hl03Bvs3p5 -b9%j{C!B?z)pSDCNrP`8@`mq+3~xko>UlA3*_A%!hMVK6I1&ruK4CUqjGgBzJJ2p)@wXD~`Gmwhr?@@CaBO2kB -&5ova`ZTFM_&6jKllOw0h$w%`Gvb~KrF0L*%2)@z@m%s?G#n1z4L=Nq0PDytz4pLl`RzYmR;19|H<_l -x)qlE-c3KsAuGN-=AT!;G^eGadow-PGj8r*=%|11;>v;O9i7~&qX=0)u^QeizBKiGd)5+TZ5j0V|?dZ -dB)P&8(Zmq?3uUl+C!zL=pKmYUjMWX>NHBno>``84HX{EKFeQfO)-&QF1Ndz@6aWAK2mnY{22(zm6sHFb -006~h0012T003}la4%nWWo~3|axY_OVRB?;bT4gUV{>zDE^vA6TwQOYNEUq`Y5v2N{LtN!$>MK3t$9c -?PEV$t57~}d{S;wbPS_=o1)NNFwf}wVQef9L7lNIS_Do_Y0vD$aR8iD9T&k$m_zxTmz8s&z@c3|WIv& -8m@a*s_6kuyV|5Ss?wScqGy>flqgTr7Zz>VN0_>b#(_FfQPfg{uQBr*dZ`)=$?>~G>uc)_g*A(%tVuw -aH$5l4=FD`eWu&BAvbJ9YyQb74+&>}XLg8Ww-0h>*D-uN`~;1D-$D)+z -X$uC2O|VWFcOgn@5C%C&SBukp*vl~LHIHH^a~~doY>*N;N11DLiYv?kcSyV9KiWQd>#19dXSamxzo@N -AF#gWp%4%S^Y~sK-e-6S7U0-Egkt7KY7eqPVzB+$KY|bmZi1ORf55bbKa-`xV~<666J?e8<@5rEB9g} -oUxY70S*G*F)N>uoJ#-!6M*{2!ZZR>sUe(wU9?Cd96gUbbe^Sk#LAY{zviCa?MluPSdyQ;=DP@M9`^%y^0b6m&b@+qSQU2$uAdNJ%d;R?B&96uy=+x56|jiJeBsrRLW1Gj@#OcjiwW$Xeu -r=SqtX89H^4O8#WH37XU1r%oI36BPzGDfFjwh#s@feQIMz9a(` -=iP6;l*%&1m_o{^Rw|_4`3`rR?$h7a&^6|=(*&)31ofFL~OfWl$HOxJkgOnNN)z$_MMO?+!3y9U|`G3 -=JsK;lj#NiRZ?h~XH~7A!JUI2#C5n2UD=FeQ_P)aq*~Tyh_IK@is -AAc$gwp6p|0v)O2vMx$jm04~OuRP=$t>2DQ#7g<9;|1=MS8`u;6LN;xA{_tWtv7Kwz7vosAD1^v9>-b -9t*Km1xI2^;T@bTxL+Xl%d4|kini81E$C@En%1< -!?c9KK?bLU!9fP6gkgpZvl50GGR#UC1Tu&c27wHsgkg>hbC$tOwj;q@5`0?rC*#SgJJGwIy}@X7HmZ} -P@kB}mmjr5mkLBMasb-pn*{gP3Ow#dWe0ef>*|h9HEhFnMx30jKO{$@K_4KnY9l_{wI5@qOwqQ8G79e -~7M)D_n7E@~;CzmH@zYT^G^4|}RXGhUxY)?J$;TOo{sIJORJ}Go=JJLK#Y=;F!c!-p5JmKlC?eNkQ{@ -Tt-DcFp@eS`212kuqp!~c|?9-jBxeOyge5=AYMR8}O-GLd9O(JT|iVwKz^hf>95jzb7cYMpyW` -+{1~eJIsi?xVxy&=Qs^m*&U;xP2&9OLLg@F8M-tJz=S0X^tF#%b`?jnWIO(uv)c}?@Fc89KGTkX~I&K -m>hkS@22dO*Y#YfP?6ws4nV2SCOMSKRLfy%s*==wTR+frMdLfF6e703-~<0 -`xFUu>mb%AYm8|K*BIAKo7%k01}2_0eTpQ1CTHb3(&(boJl5O7=2?Sy|X7_7>CV-c+wVYO`qs -D^dQU2+1F=qZhDYqJ3Csfrk+}#X`p4>`h4Q<(}uzxm}O*I0L8FZH;=WZX*7G}LdZLeW@af`iM=rOtES -jhES0#DtLRoS71@nJVk*U@8vs&!lOMxO3)0AedxfNm=|0I?M;K(`effY=Hapx -X)#Kx_pI&}{`LM8sCG0Nqw_0AedxfNm?y>b9cb>CUUz3MTOOytbk^?pDG;Yy}4(wt{ZP=o{lJWT&zD^ -PQwidftaQn>^onnWr?{${1wML#xuVdtklhOSMV$=ZqYzD^r`p|G5DUkM?=u7R<)GPWG; -v+6RUVM}7rH6udV1o3T8W&M+?2mb2gJtuiw3Kt4D4tY-2oL3UMXQ94u}H~2gCw&2gCu017ZQX1L6S00 -kHtx0dWB0fLMU;fH(kgKrBFaKpcQLAi9}zKxwD(ETb;Bf2yml;dh(#((wfHJODqeH+_A#q+6p69xXhV -fhrkHTjY&)XCw>tMm3lOIAzCnoJA-x^d>=sM`c5*lMP*(@VwTLqnTO)v3*kEtVEeZB5Xo(U?>*FUb`{ -)_VuS -q(?VyC$BSnPw7N^TKyhH=>m7m==;Mz&-HnKR?4@?^GgeC^KT%Ri3C_;W0me@EZQ0p6$TY%^77<-HNm% -KJvnq7&c90f=v80lIIjnSV-~C@*~1Q!~e0AEJNC-?DcJX0r3BC$kfy;6}i$eI+881tLoGI)NYCm|-D1 -m+6D-JmH&=-J9&Cl8!^o7ZhQLT~-iYxpxAmO%~POTO6CRLBwtq+T1o`mqbrL5x=_Zss5%@gnr22l^^g -3tE#QhCkZKqDxV~jJ?&C$q*%ieg+Ul=%AK}Hj%r=AnIbURGPPdnb0*jqhvTMkFu)(UdN81Z%{_ -M@f^8;JYbKAXSi$BPh+wPa76s^n%`p(cHtX~P&j~iiKm?lw=z`4wh+wk-U9dR-5o{Kq3pNKJg3SVS!R -7!&uvx(FjlReOh;Xt1T{t-a5l$AM3nvF4!pQ=3;p6~BI9b3C9MsvyL7llkPugin?OY$%*-={9%N9j<+ -slEUo2%hpMh+|MVFK>*i>fh?wOC9M9mmQZMSf6a8DoXhu17yeTd^K5F}vd|RPpE$KBL`$TFW$AJ$f0G -4C*x13b|;C&BRKJs|5u3ah>b7VtKJv4G6HsdL$rlF*!0C-Gc#f7{jH*7`{7w$iN_umrHi}?c~Z4(X+nmjCZxG$LWY -l;kYS+-sboPI12QZ!AiVv^6{z(6C(3*bSLQ?hwvy6Lj;sw{Dz^4YG5gKFREz_>#c3y5_?kS3&}|7fAN -HAFD#lHB&5iNR0d!l!0f;SO0qeHpM~`sHURPsjudN}rWVNZk0_e7+A+Ndy^Ov(Hjb^>k%KqB*MhCBT+ ->moA*uOmS3BnV-2BZh9%10~>e)=h(K@^m#Ye#oat&QIK^`nvshv@FqF&2zN*}<2`6b?<<$zxqvu5BzE -T~s`mspHz|_SUkD)>E(Br_@o~G}^mfM{Ub!Z{Bu#{G#GMJEqau^?K=8M&||k{H^M%YZ~2Mudl9UbT@B -DeST4KpFPv)?RvfRETi{2-eI%4vrNO<^}4ex!`iq_DeISCRNQCZH2S+*t=eLwq@ -8)Z&Tave`*@jU9Y35WlXnkU$63xyP9Jf&TiKu)Evuj$enS~7%NlzQ*XXef60q{A$f5w-kWx{d+d^UWg -6qF60K}h3RkL|`ijBId^sNtRazLQ{6A1j0|XQR000O8NLB_@V!lkZ{|5j7i5LI?CIA2caA|NaUv_0~W -N&gWV`yP=WMy!HA$V~P$nVZ!SViL3jB3^bU -7v(HtH_(c4Gi^IL?$_T_e!&JCmgvq>LTFc2*XvVNIXf$V=-RmL4XEGi7=y7v*ZpDVH#$Ij_VL3RO_qX -&S}vq#xztgPAnDV+`j2#7i>97@723xedueH31muW7*n!eygR}twsf?Z{0|~+#@hV)k7Mj$Yf)e4(Fc5 -)nTWf){)hhI)Z3R+!KECR;($N=|O%F=PFKjKWKsYqpL^6w)S(=5dH@IvWP_H7VD -`(o$8+PvB -p3u>JXNW`aUr%tN=%B0x-k^d@)1>4e&YNBW~Z8np+L$FCqpOz; --Ljz!7U+Le$D%e3VM8|cmw?u}9B4lM2KUcWbaWDB~z$-o$osXH7|n;zPuNv|{Qw@36a9X$-kMgvh6B6 -W1+(lTFf9X*H4m4ZJ}Hxm3#GJ3oFHgTxirn?NL&+@r!>`j%6!S}7;0Ab076=c$qyWwOjuxv1h=-Xg -RX@8IBj%s`n+15eDAwSNC)=ITABQ6<={0r{@ERz7g~RhSXvpU(dx#M-ocTT0Uv0Rrfs&TF~rr8N^l<+ -&CI({?T2r$V&iys7Sd<6gi*#_juuzG04g|1=QvUp^$pF1<cB0O4^0F4hAC7$trjd9N|#1l3wTJL01#gzt^`R$Aui=<3)D=w9rT=qLi%qa -M4sy!;b~JvE=XY6@uFSTH_@E7OhvTnfLKf;*mV9(8MT-=0W$Kb}J77Df;xB+oa##S;a(F52YcXe64c! -~cQYfn$SB=Knmx7s7zrD5T-lF34#SgxV{THS&Tp7J*_vCLyY_J>G-5r_ld@)jJjXUY#?(Ou;!&C4s#e -ve?9YnO74CG`tyJVXS|_lqOxo86bw=o)rUz`G)-TiCYbiRo=qq;77NnEo8@NOjN+5XRN#JevfbWWyZuX8`T25cRq3uNzvqi6#8w!T3i_2!6w~Bpn(NnxXmdncv&O -?C11`<92AQd+?EGpC)4kn{vzf>Oj-HKBWyN&HC9`KX-e7iStB6vX~TCSA`=~(>cLNfxEN@R1Ff;Tl@W -H>pXMg*eZTuAJ>*dlR&-B!7Ibek((Dlm_Y>kx~%FL-~+Qz8rF;QhVCL5cZ$!RDs`y?@1ww68;4pIvMK ->WxAs!wyx!dLt|+G6g$hY#wZyONSj3WgEjU8bx^=OB~QBC*(bE83b$p>iit;TZXfStybsPkH0JFoTmz -%<7_2^^UKTG=lR8_FMn$}vtL>Vy%brV8~+YEC+i_a-y|{%t@I@E`~Hs_WBDD)JsGm41J(ht{J2pwMlt -W=!PCC7&rk73xug=BI=&-j;i6jk$=_AzC%?|<75!_(0 -#JLN&?m2WJ8`Jz1echUg*J)7ZV0+VbQ!ZZDKcUL-SI|Jdq>u@|IHgS!7%8Fg~baqRZjIq#a}8N*kOR? -f}wr6RIUSomHMuiPIm29uajB+%rEbc%3wG#?~Q!rmCQTYB)FH@`va?v_vTiyEO!g6xj$opuUc(2npjO -rprmA5NlWFqM&~6)7w$aYfspcln$(I)>8(Op6FD#R+ybU(`W2|x*f%qC(U&g;heOJL0Z>Z=1QY-O00; -m`Rt8fK>r@eo1pojj5dZ)t0001RX>c!Jc4cm4Z*nhVXkl_>WppodVqa&L8TaB^>AWpXZXdBs;-Z{ -j!iglNhjSY-Bqi_Sf%mLfRxi3;VJjja2M&KA)@4m#eGe3 -);?;JA}U5afZGF?f$6q3@2o-zJI%d$&$iIu>})^Lq|pwn1+G;hjC6|D%gf9jVIxfC`}DS)X>mK1tE&o -5Fo>F1v3l3FhHtL|L% -)4li38sC2HOS+6%N#!>kiv^WRP3TyDFrfNf@%$<%DMzL9pZdUa5FS`XWAnFaqj4u>h!406928@L9&Mc -)!Mf~Ls{}V2)fP8m53DtX~FuI)06j3`H=((a4w49qQI`9BH8AC_}C>k-H+JGT5Kt%MrR2E<*BR1dJy; -wx(xAo3YwbEI*pN3QDQ;i<)aG;1f~@ZoL*OeDZd%oF~Bkm&3d%MoT2Vom2UuUZHch8K6z -8%-zB8ot6y%kx^p$?F3OV@~iClbu4b)tWOzM$Z%xW{0+0gn{FAdZ^NByM1@^YCY(>lcD4L&>eZuf^o~ -6xSeUg<-vIBjYqyy!z@#p1v&}ou~@$cdXAVYiSfj~A&l$H|5r@3Mk9FyOR}Mu@Q`AwML@7x*1OA+$)# -8%PNU98SRa7RK}b`DtzuY4SgZ$WwlE)=u412rwJO{;P>P5*j+yXLzsu%`-Q`lMDzv3GR&>y^%JpWWQN -L;Ys5bznzTG;tz!^TC`7B|CzJHr5Y@^!#*;yzVuh&Y>Fc6qb+j|{6@u_*TC*$NK(^=A)qT8Z$FWD=~a -UvG8m@kN8L||W0o=I0+e-zx`-~J44gZ8xl)biZcFc^#;oj#Txe6?QO;p6DV4;szeMp^$lfBOP+@m9F` -{o+4@C(m)7_m}1&f8^rpj76t2DuL;m)98KDpd6>EKXdwXz -?R(n(5|F{?I?%iE!_sg8*@>#-r9=Z2{cPZYW)#n0p -heH+;>H*V4~mGWDKazgN`Lvwe3JTg7K$!D)ME=)T3WuCf0@PP7KU-SKmcS2^rOJ2kDh5uHO2FdV-@P| -=jnvje+yjFY%h0;@tIR(sdF{!mCOJlNa&XQ8X}a$GKuQt+TGf5NrO$u>Es+fS@6;dUw(OvsstBXIOM` -jt!*e5YfLrrC_$*o@uW?_Gm5p$)GCn=6%#6|g#=Hb%C%x@YBvg)AWT!P|894*3;fP*Yo*`qTsE1g4?tqMFjYNlu{cun0!7Nsj%eF -L=3z0)JYwC);;qf6}>WIC6MRHX(qai`cwWnd)vbY_B#R5fc@YWb<^~Qb%WO%lBYx^`|Mg3LG$r%M!ei -N(bAsl@!?8(lF{9Ss26n@ehO9}o3P)h>@6aWAK2mnY{22=b_1ivZ;000^f001EX003}la4%nWWo~3 -|axY_OVRB?;bT4yiX>)LLZ(?O~E^v9RR&8(FHW2<^p#R~}V5oyBUfg29njpg*za;Mb21!N{6oEiXXPc -`;8YGq0{q;M_){AX9O@|2qVv%>x-Sgb>sI#;B2X1?JgE0&To!;2%!R>I;`5R8yp1po`2L1|RqWF>v7D -Goy2wX!VzwndR3H~%YEZ1h7>y3u8fh&_Qo%!JxD=XR)mp0T#bU!$s -_jOokQt0%zR56;gE3{n)*A}8GSKLpL+itbKP*PAeG}So46ZfS;G#zLgi%hXBZX0Xo*Jnd`uxf+0gRaX -0#hC@6;I#-C`|)K!gOO+QWQFnNHL!)rZ!fug+c@^7v?LacMThvLdXOtjJV!LAVCZ;5&b5W1xRGX7aO~ -liilX*+zqNk=VIQCXD~!f`NACvRK#hT&SM^0?;#ISXauHVZ5Q>bRIG1P@ph>|UlM*M^EDu+{Ve(uDos -o9uGz}t?I0bH3L4B<3RKv&^*pD%HxN@ -km4!VcUi2%$-iWUK7AW%!SS*t<$;?dO?_pBt0WEjK@0X|3HP-lw=&iiaj9}JVZ_n28@o)dh>I|jHOs+ -q{*k0^&0pBgftF(Rh-(0TJfmN7N)GUL#H5YI`DgoteE%`Qzbm|@ACy=_hTuQ1GiEeYdUIM=gW7k*5yU -({bdVa=GmoF5A?>}7fu&a==H0Gk_j}EdAMRqqgg9CCl#oY_E?S5*zntp!4B6Sy?b1utC;*<#<}l7*)VYLb -Hf7jdO9z4_cobcsNtHN(UG;n>K+ME4Wy_P`Z$7d$6O`whsu~N#DD!aWN-!8uDXPA9lyN(pX*3XYjG|G -PRqgDP_lIo?D$jn;G==4q?G*^0`Q!OM1P!l!l$*Un(CoSH#61XG6eX6+CCL@xJY6>4{-S~Yb`xYpw+S -jmWawtG;c4%!bBuHRY*|z);Ov6!)OLWMpU9_BqI#;EQ>9SQf3mVoRihyV<~G`84R}eB2I3awbL){p6|Hso_>9-l5i3qX7 -4RK>&*dzx9$(ZgwF=a5D>A8_i?!)E&*5RL@j035376*(euY+*tzCHk(}atsM0$KS?U%?k%Uq;fFOD`mgj>!XX-W7U|NGP5tv!rsy9_WWMQAB^v=j>cM}z79)i0u(Y`t^)cTV-5TD937F{I%nr -biUp5Qgh-};ZgcVOC$8U_`GJ4$_UL8UJsQm=&mWA0`YTE2Um$kF-Wms~9NsuNO>0t~|3m5rbV~PKH|) -9BcgSgsUHS?8)~IIV?17X0zfem91QY-O00;m`Rt8hr`Nc!Jc4cm4Z*nhVXk -l_>WppofZfSO9a&uv9WMy<^V{~tFE^v9xT5WUNxDo!InfwPdo~z`k#FOMCmvfq%v1Q3oPnJEFJZYL_B -#MM2oGDTzNISY~`rEq;5F|)~lI?3d$HX%fxx2u=J=g_!aA3a3Y43b6BEvzqHyZcI>F~1qGpV3Gc>e5w -OjeX!hHS}v+auk;rG#;E5&X(L&n7oMyQ3k8H_plqIgN-*BkDv!NE{%wK!B1l@L9xw@QmJ3FWAtK1Pc- -wgd@XL4mhq8^px1eG*caaXAMtSww8#{XPg$z&dc*VvEmW-vzxTo0!~@5LiqopFL#D1vm@fpcz)x@kB0<@E2uCufB<6Gxdkqu;#N@+Z^8WH>LQX~ ->$%m8c>yy#s<69sGpTJviwiLzI8;^lx&@8n5XbW>k2^YQV?t5T4IUNiKlaHuDe=r&K#$(dIye22)>g0 -Md=-v!ZuF2KS_0{FLXMvX~RfZNOHQ72f^a5nA1F$FLjm^Zj3Xk(iUuOx5pAo__vp5yHHz1j(0S5N|eNFb8 -WSR9$#8rqMaRxe{*_5A|a}n1pQLZ{lbiL0UJ+(Ds+Hy`+8SL6$cNvcbUOZOY7@{5U=CBtzv#0iHZxx)?9zc}rV4Rhya>T!`8|H&9BMOZzU{{lC-6adT1%|PItb|*Zh_K`Ifx2Sy&S0*?0+F?#)UESiO{eoMXjXdfcmbzHHfbfm#CJduQXYG -e8a@esyuBEV1{XIM)5-hm-uV6H@C?XXR;MN3z8{>wpPqi4^rmOMNv}HrSbqoEU^&5h!#rA_*FJsz`li -+V{I%czQcEV#8+R+o>z`XkNB{cwZ-qBc$aisa1=PRQ7!R6n-n{y;*{&Uv+6U&l!9 -8!bJFhymM&2gLm2q?m9Id?^uL>OPy&SI#9Iy9s{7~RH+RO2#!0~D?$BzY$mwP$dM+KH2YTr~CxpYCMQ -$+abw9cuwXh7lOFQ*FuZ13_oXPpd(3JmZ;uG62^6*uTX -U`k^|Vu>)Dp=1nTRTwxciWvcN?`$uoY7nS3AU0;ROpqO^wiVKcL#qM)Kp{!=i=u@2AOS~6O8Si3TujL -Z3W7{DnG91Ex+YH6whP@4=tHsMNy{j_>PZtho5@@NDe24(bDBeG15J`BZ8ZOB{h96E+gq99Si)hY0@C -hRkfWej4X1|rq4Z(mahQ{qI*lz-lOb%tz#u-Pwu`_q31fI(mDnn-k-HFVA&uhD*Oii;AMvPPHwD>FCd -Qc$sR;Ox^2$)f=6PEbqew6f6-_p#E*?5f7V;<-8vsh<&|K&ucyUUbSZDm02z%mL#Gym2$>=ec17rHLhZk+m*+Eej+}f#prnB68ebpPZhO -(>_75%{S?wW!fEx{X+0I$Aj}1=GsQT^1$8(VBgQ80e`LbEl*Fq3jGTPIOqnEU;VbIz7K+4i~NsPjki!Mp|?OAou2&tF?D{Hs-1QCLA)u{& -1gl`MN2@H&MtR%~aAv(p>#sg{hLT5n;F2RG -s$Aqu*^R6!J$hm7dv<(|WS*NmG$#?bj+n$?gQzQWJR~HFq-XOU?G{|C13-^`lk*;{skh7{wyvpmhSnPb{5!D&gDNrFr4sP*dv3O5wcT~0_SeJ>a8XJ^_4ePsDlyy}t;h{Ecdn4HsN|2$CMxgLSRBd;XH{9jWIm|uA5x))1bFz2h4!D#;Uc8y8%Ao@#Wv+H#&Z9 -Gdf)&_8?>_#N=Eq9Y#)Cqg@z0Oj?HD!l?~kb7KKuAZ#LOY*G0u#G$mrMkjh>d0?k=5Uljet`mQ(@RLH -ut_x}*)MQH4_I-PW%QmYArq$b4qiTF)v#Q9KRZiL6qDjUvvRG6lQE=OrrZ0_wWGw&Gpgo-w<7xz{U%_ -(B)RYg0QMiy$LZ^2vr%bU^JbTFx!pb=H~0%PTD)KA>vc_bu1eb6P`W|HcMj{^3m536K+dklIP6H$ZMI -HLWGT+R@u(LT$ad!kUBLtFVN`GJ2C`Mgy=M>4)ZwwnMh3)ooEG^r7BD5#thhy>cK)zok -tJTYC*@yG;EreW#J29A9>azRPcd^DJN(CUz`EW3bW_a0FeU4{+e!eLe!BEFP`so=s8K)0jIp&n><|Ms -&Es{$iS{ws@9R?s(n|6DlnvqqPrDafzLBcpnjz1cvyS1+8v)eo!c=_&#G*1kMX_f7MI7=1US&-s2hrGQtFJ7f{vWJ&<#XV#>ezv75PY-vV0gR(yBe&FlRo@XfahTguP -mW*Ll*Ai}zcyLm0e&VW+iA>gAs)+GoFA(b;qsniLqC{JKGmS)mTtMxkTVr8vj&-E?uB1C$(iz1o6iY!_aq|sZq#X~MwUzG@v>g?1G#IbK8^WPt+1VVMi(~ -b7px?*OqV;uOdgzTi>z#N9trT34a<(yuG!pStl}I}U5{);cQm01-penDgr -@AuwMK(TQ#TL!lQeiKl1vb;uX8YNCNQ@GmifHk9tV98wM~MqtI3Yn|wnZwqTAd{*B>Mwt&7@mwwh@+|5ix7}n1n9Z$j7f?4}i1&vlO -PwK&2|N94h+=lA!Xg2kapB}XhsD+SLFzJvy3}l~`WKlK{m*@jau$Lmg4KJA1%qM -4znyHIy7(RBa$|I#!rjIVk+O5tG>wd?{cRY_!-|;=ggW-B|KT(#ULi(xvMN~C}2VT_URZARR{~J@~eD --8x<)l2xTsa9l3}&jf{{v7<0|XQR000O8NLB_@)KZ>MQ3L=0APWEhApigXaA|NaUv_0~WN&gWV`yP=W -MyAWpXZXd97AkZ|X)6em~Or52NG-QsP3YQ{~cBCB!7CU?bb;C{LEL$FRzJ7wxW-Lw|i| -4d$NqoT}yp&*j^1zL_03KR^AzgZnh_U^wWxUg*NZ(C_^TAH<%2{&Wt}9Kly?#zexQCo=@5p^$$u&J#z -f8Kh)$D6$S72xb_?KH?j4xj+Rn2Xg|&CU|IcnkD4x1Zj^qSDQxw*C&C*vLHat?tF))1gZ^@dqpPEQJ>*t9fKHFWdVngB+LdWA9LGsOzH1fprcNE -k28T#AhjBob#+m8hlFD_4l1Wp3Vy-W@Du327ogVaD|81QNtRBC?;QvH*q5SiZEjQe;$>SYseNz1&zem -5~#5Yo7p7ZOW@QNRcAUM=&&s}112iqIdy@)5F{1*PE!R_gi>Q(@|K05VE8(Sp8ZJ#UGD|Hc7venMK5< -0Op242TDgK^#ey?JrpiId=#5$*#rdk(u+$8E>$Kfa*`H$|hf);sJa751b#CsUn6bqC(?c2&%NIpea8&~KR7sSD{6h-?%i=bKZ-~0amti_Z -D04z$p7v9K@<|$j}hqm6Ynt|ME?_oFrt-yf&t|n=scsLNlT?rm}<~CibfNDzlW<6>DwaqM)Rk8=+uL; -d&-8}Ua606G*ITx`^L;?%@J^J1vsbL -v+Re>z@%s|}2EQJ#U8i5HCx3reUR<02+0S27?>KGx6Se}|1|ZjXdosR`{2Ne90|XQR000O8NLB_@&2z -cHzyJUM`v3p{9smFUaA|NaUv_0~WN&gWV`yP=WMyV>WaCuFSKT8BL6vX>LzQd5_&L&)8bs -&g%g^hxW?ULPnyLp(rEctV~-`@2&!E$DP12e`Lt=>Hs#5A@*pl>dgZbaDIf9Z1P{T<1;l=IV*5XN -KS#&G4k_MfWqzk?)pge`U57iETYIpFE%-RSzCFD>Z`MD+mhDX4@9b{t{{T=+0|XQR000O8NLB_@tc9W -!1ONa40ssI2BLDyZaA|NaUv_0~WN&gWV`yP=WMy?y-E^v9{f&c5W -O4le;BwZB<;#X6QCCXI_z%uqd>PCbhC#d4HR0UY$6gVkW^eF$ba7%QnF898Vs&8`T;Gf6r>wsml&K>UGJbax&`YnBt~Z!MAm%fSBs+VU2jBDfNY5n;47<}-iac-rwA>TLo- -!6sZ|QSl1Psz8tH`LjVEb5Yt|h%R_qt-&hD@3WXFmJflL@SFgV^>;JUGhUKHnzS*cqLcsz6U_3{;4bd -n%>6Y_*LFdX}D-1snTkbm=8C2A}H>nn)-&~@BMC2R_cw<3=`dr^{wOnC6mVo0Sy~SeD|*C4Q -dU-ch1D@u6zCd_eZkPp1kp(AXgMHQHkMh2O!5}I7a3e5ntueRVU5fY`~;N^hup3cKm{dOlFC-t$WWN(a~t#5j~ba2yAcesi}KIEd@(#7UN{uH{3Kk=&h*x24oG}V2f$_^`F1l;SSvDS%m -^J@s@row7wsrW@V$T7~?d;_Km}6dKMnTG6G?(PEd$Mw4#5k64XmE_6ftRQWo&hiFQnFoTL!RwL$@ll0 -9C4zllbx=yn2cLQO`GPZ>NuJrj_}r-)%jTJB=$*PeU{AkEbZZ#JKH5DQhXJ -VP1^4E$KG)0$(W5s -pxG*BDzahfx_}X?mf~qy5Tx7Y36&dK=?VS|@g@1C#Na40lshSVV&h{vSDEeIF)c?~tOQm!%?H#|-gujHc=$0vCwICx;TwukL*pxKxpKZLQ*wIh@HwpIlFYxUMe18BAJQ$1nM}06$H^B -+jVG8F!$A#^(W0OQ{9Ma(h>C)=u_&T}U9XgA`#(@i0|XQR000O8NLB_@000000ssI200000C;$KeaA| -NaUv_0~WN&gWV`yP=WMy>~Y-ZmvyM`?fEu~WTLDoFY%v<08U8Sga)as+t=luFC-KVwcZ(pmj^mUXIzD7bXlj>IzqOfwsDyHGT8km?E=Y;MiMpe2RHqtv -QSA6x=S1VVvB882!3d^ujQB@e86}nZn8_A3+qc{`oXGB$El42b3j3Tj|07NJ)#B_-gZCkmb9d7YxYrl -e;6RgyZlr~9>B1vv!m}XJsfe3Pl**%m5k{BfcePo6c;4h%0DyoDUSFTvOq9eh{4te;0l%>5y=b-{)Ot -Qdmmn0_bCN&1{jU$CgN#YR{QySf&*$+e_4*5ug;gTs)QedF6$g2v9IKRWtjT01jOo%BQ6`0#oRwO#uL -N7VSaS=U(L>8uk-VRFQONloFpf -U5vqYEW=(@LT&AUcFSCB_riRrF*TtknS>~cVP+eQzZY#~!ZXYM3utTx>0>)ru3@bP=h{4!-u^VJ-k6l -(63CSSr3MNbZR51#aBDPkVn1cyq69oD|n%UCc+|t6hx?zbY)$^N7?J5qR -5wXLh&afMRqh%_{H=grjHdAMiCiVO*tqM;!I3Jtb!N^!=hC2k`g6Qmcoc#)q`gFRDz8nrSvK`W{;Aqo -F*Z;_-G^3(#8B#WdA3SsQ0LU>X20QQ<&)&RhV^rKO-QJ6>!f2z`>S)=BRYtH#tHEW-A6z;;)MFKCXw0 -$OYI=n5X^vocTEw*8=g#8DT -R5Fn&PB6Tw2yTbOY*}O*-=)7{V>HaLrcr%q`xTsC1*@O9lwA}vHjM=vf_JUpjBP7-BF3xMpP<>;Ozxu -K#p{3Eb2Age$t6B<-Lu=vBswawLfk%peS3Ofi`sU(LOHY9EDhV}J3IN)RV3{wPLKE}fo2yN4`C~9i(I -53*uruP}{S?g$@BrWexOcL=indFVDAk2pRlo?H$1pL9^npl8P~ft5u)t8LS`TIHghGu+L{6xqW)8&xQ -A%B*wZ6W-TqyR~7>a-@YSkzKs@1m&PQpR2gi?}=-f}QW2>hbJgns^|?&n|XLya(LlB{As29UCSS0n;| -QTRk63t05BD->qj!2!w5KmSeorAV_U%=FeTN}zPn`AhpyTjTN*=VAcyMovLVxh@DTSI<3-wtVD1PD#{ --A|a5rUfZ7Th5L(3p=1+6tmNnUlF_ii%VDSoMO>3{}6)UrD5a7b(_kX -+_T*C+>6|7?q%*(?se`>?rrW}?tM_PrS?rnYmIC&JYf4t1y&!5h{hJTMjKh{^14Q)j{E2%O>!}I4+S({JkmgZ -9w`Rx;YPSMK?6zi%$u{szi=oPY2X``!^jWzd69M6L(@q-U~6){q$hO7(Ln03(_w=P+itpV$bb=4ZOCa -o!J+PY?4w{BQBty|WNb=$gQowM#*_pJNY1M8vn#CmEyvz}WoLP2?lSI$~5tyk7->y7m`GiJTB-e;~@Y -3qaa(fVY4w!T=uW{zbBGJ~1pnH!lCnUk5J%y4ETb0%{(GnzS -TV$9MOz*q@kr!uDjV}LNf`0|9;b->cF4KaY14K9GzEd0Zv{0yTfC@YKa>s*BREbpd0HGA*tN8e!o3Si|@55 -T3v%YmEhVh?303k(WYtA_(<8EUtS$m_mGc`sGu|lEiu!zr&yKO?(1h!PjaPY;oEPd}+QiUz=~tx8^(Zy{VaL^Mm=({A7MMznH(y9h)1NJ3co -!cVh13+|b>~oHnnS*UcN|P4kvHW8Q -)P?wa?^`{o1lq4~%hGDpl)=4tb+dCv6Zj=T_H-kKYQQN3?6r-11J801SY0J!V8^C3`Z@MBQQVBjwh3O -v=8ajtnvtCi)1NE=<~^pcUBLf|(P(L+kbrl9d3^4nz_VR*OHX74U#Zgzcem$Yz0v3 -jcXkTjHjK4mlDWzy7p6S(nnBNiq)@+UdU)qEf6*o8UoH9`LCWmHHQwhOuTY0_Y%+GNB9|jjX!|58^Z( -m6duLnc*>v8Tg2(Li4xrk^PbF#D0t>_#TH+JDAStauSYF&&`WXOR4Q(5&@`@Ga~ph4=T%H|nAs6#j9c -N7IXV<(4#Ta_3@f<{h+U%Oj~XwsLZ2wbeXRdgnvyMBw{73KtL59mWbZi8i7&gcQZO-4vlK_&3GPV27% -6Hme(S_vK5d5=3b)G~j}nR(_I7ZBx49@Z1Tz<1+<%O@I7w9uiQs3*I6y&=Fn(DEGqGJ!Wv*BCRF#ATu -e{v7A1M9k3b=6pe={F6#_=tD8$ZAg!LUEaFK`-v#E*@O_!u6yS4*YeJc)Hfds?)^YmNCZqp{kjS-Fl?-fkNqv&m8mp)Av>1 -6m>thv%3jW1$zIJ)WGAyz+3D=H?Dg!8?9J@0>`eA{_D=S0_FndW_CfYx_EGk6b~gJm`>IwI1HBvYw($ -rMy8z@SJr~U+kySjMc(Em*6HoY>qZQHkp_1P#)+50`#B~dd?c02894%i|P}8a$Ge1rr)raHy7{uyjj? -tI_*LW06Zcqid&^G-71nOm8+qeaO`>^qO32t^LUD9Kn6+JHI8S3p)g@xAbOHD!ZwuBlyZ(AOuE -MF2=D^{w(60d{_1xYcie`k!*(B61iQ);)Z5-$`j#T4O+ae<}@#_UoOyzkJ_xG~1FDKFr(C@k*@n?ggd -IF0j{ApC!b(~jAG{w%%-dYXiIfW`t(@hiYXy5@MTjqT=OrWYN(=Nip!PD!Y&cVbu87I>4G_nF)+=O!^ -t>8i4{8g_|G>7w7Q;ey4Y%S_+bw9HhQs_7@F`QNr(pU|(+>8w9LRN(=PSH@%83k2UrX7!WQSH+P&sb8 -f=NPp2^;jWC=#uM9REoHYDkO!cPbC8=wQmPErf|EVL$11(v$a5Ql*$cimpuO-7xIYDLfuZK@8L3kYvM -f*uwPP;SF7DW=-v+2X{`Ncl-ERG3>mK7|5pOl1jY4g}h1z&mw|)np_T)&9{+`!AB?V)sh_?V}^MYEtK -G35k0b!nzOe-5h@dcKx%Gv^3x1^s<9!C!Ut4d(X3tz%P%Muo$-xvUceS9w-rzU -%<2@$`h=6YID`}&U>9}IuXynnog*se$-M5o=xAb#Dq5LhHd?N -*VDyZ}>d3l=1#{&SLw0X&G0LuxS$sl{nK1-yhWLkc*9Z{s_VWITW*gmTl<*v%!)xd>@U^7Yb -x1zI5;r3F)pOAeZaDR3AZ@5$!958qf5Ia=_PV)+ReHK|3OL>C^;vUt?{)$LT^~yDe=kTss7;7CO#h&Np=F-BU6OZa?{WC4~#Fv -aqPO+!YQqMoA^_-zA!+1vM@$|@4{z&j}$AyMq7DV>9`Lx_C!pmflYV-p0HV)#;v1#D$8Ejk1e!*hf1s -;f4#k3l7R~@Hm}F1al4SoW&V30B8$mLDPiNJUV7d9|u|BHA#~Mu>KbXs3yGhG=JrHcGT}L_1Hk3q%_u+C`#`6YU -bwE)(qv(XJA0f@qUOnnHuID8rIg_(_UM550Z(A5 -Qjh0qNueQ_TZiW8qt2nef3}GW!F}u(3_T!LHk@~ukz3Mfn9)mGoin9eKdYYz4T2*#h-f -nkJ2;_2U}=yoHZV{t8j1ZYSCvMhmEgLmwlt-0KV3F=rGL+@pSE;dkeVjcDBFEGmz`#kV3KKwX{;!7I< -O2*I#KJQ|rR`D)9C~T3!I485+ljA%a>nTPiG-5d*a8$s)r4$#BB0;9#(y--GK2ZC66HfR9liM#rwwL92Hp-*MA6EZpe -={U0LiFScomz>`7WyR;zx3)lnmhL}>o%-j)3kcirnU89rn9ZxF*@ZMZv0{GkG_#XLrV91C;$uz{X^v> -6o;r!jV0*EZTb?($0>J*7)VdGPs~e*jk8gX=ahaL)TVfres~4_Q(;g;5@h0AC1olod=kgbWx8m%Y@^T -5R{|VbY%B)J4rLD_*;5EI&JB-3JA2y#h`)yZfM=Jy|q64!#BQF0h0 -#eaG2xtBT4{5#M$2k>ZPSaz*j>b7gzlF5Sy4BOQ0lT5}?62it+SwK}=j?laLU^Sl-?N<$1Ah(eKifvx -gWqE~e~nDFA!!>?(ZY>Yym`6ozr%0z8PKK5ayqiz{0000W0001RX>c!Jc4cm4Z*nhVZ)|UJVQpbAUtei%X>?y-E^v8 -GjX`U|KoEuRf&7O74_?wGHC}tDF;b=U5~0UsNXI(3*^${%n}6Sk4fOPQAMfMMpqBHX{CzaoNklthgf~ -+@4~`=nW8iVj{aMuDP73&We1P|6`LI$7(S-uOr&a=N;u)o_T*IO)SxSc!7E8mTo!EvtLk40|XQR0 -00O8NLB_@`0@oYmjeI*Knef=8~^|SaA|NaUv_0~WN&gWV{dG4a$#*@FJW$TX)bViwN_D&+C~t5N8&%M -bPwiK%Gux~%2hlVaPCMrh=9{IYAb8c9`H71?d+~g`1hS%+nj+|%{|l)#yj86H{+Ra)?ATsnjHk&#)^D -QIaM*`~)r1Uw9VaxGKoS-Lm(V2=fXt?2f4=g`h9%Hzw=BzQx7IO}WS2&H0%Qvu1XU -o3H(yOj7*jz*1%iZWghrK;Ofaq(-=ZZ+g)t$%W1J=u8CL+eBvvZBy}1G2+q17MgNV^yDz-Ozb)$&`kR -i<=(5z(^?ba9r4vF=rJsA9fhQ(@JE&syh$e)=dHGA8w2sS3EK&63BQ+D*~`nKI7cnMIs;6zjYLZlJ}h -|ku}s=OtrKrt*^$K20cb$Hy~|INZ5vjKlGiDT>ps0d^z0C)$h2g812@Ld)Bqjl<@Fb+TM{Hc8NFrgCr -!zCN*rgYNhzadnWza|d?#+eF&j)Y`W0s6WkDh49+XTyOFjR2nnkb;vcCD?PW+rN)l7!wWgeD@4O_x6S -5F-tjNTq=rMpo-yY4>~lyPiYUKM%S(JnGEO->U>lh^F_nQcAHRVb;+J62$w@6^{nG|2(Aw*{qBGmKs1e0{lDUTo@~$<)wYUtjbx7cvz;Xy -)VRifriA)4LD~H!AV07uU(+Y5pqbQO)_oV)^7PC$I7!*ZfD`_|vPLCpG8Ki&g3Sedu(_;XeothQN%fU -Vb;r`-^$`kP7G=2d82j%`nqi3x{N27s%3|oHQ2^r$FwOzCS-j`UUdEpUoCeC&-|R^XQ+kxdrmz-TCvi -S4Z9y$oPvlKl6E8AW!$xwSS7dtFm7C>r>>tu7iHQBI_9Nqo4i5KLUHU1rL5E;`O#sr)XpVgVVX=Ij&&~IX1-WHc(c;fuQes`X8LcAtz+ra%Ir8EUHH+^0 -zDdyTG427sf9kHYsVwUfCr)x>JL9Id%Yi9 -K;)No31QWXiKm9xqptyyYpCE1HrwG?xk6kmJLn7b9|dbw* -wcrwJ_tBS{>wRImXNjFF4;>FmSRj4a}Wjh;S<*BQ?x$yxa*Hllpy@c8t}BIj!|qN#|9`TGQ(f8;qp;? -pUOzUZebxk=!U=GW=$!U{jesbu-u%HPE4HM|b+VagMpt0yJqNW3_<^WkNlBm?|SvpAGYNL1|U6N@`0A -9#v3EX-UI3zBlF{(SQE34x#OT(f-8*C0_sg#e{vd`E2_`gf`nn5#xe{8!IA}FDr4sZ5?N_$F#a46u<0 -RT!y=utTtu+ngu%3pT%n1udX~dG7>5pAF##TyE0WSRJo1GLRGJC{DUmB?m$r`7?jCJrP{C0c+G%4eP@ -7>?2gi=LX5g-FZC)~o3Y2D}hOVJGlSQ5qGcBktZKhWd8Aeix_l)LC0l%JodBmrx4@JhJm?m~d6VAUB8 -F|=b5Od%TN4w|cvvO4!s)Tj1R#Il-h;OGknQx^$;97TNn{Fee!BIc=hesuij7sr43>z|%Kt~SFt -XCjqD13P@=`IjMX(vW?NrHd?Ag-~H2**BTQ4`fZ3ab%Q+$b_xOY{DpxVLQIY)YZJ^%Bl-TTZj3s^4$8 -(3C<3$wyvV(yB5(2rB^^(U06S&MtZWE=3>MG%-$%FintEtv8UH|0+3Vhr_a+jlgszvn~zu5v$Gy#E0F -AnrC;Nmrw*8zZ!jG)BQ%`@@05QBx`wqh|AZldJZKnWIXJ)X!8@M3&I>2dWWMpHYRFI6{^2u0v&yE<-5lyJf3zkgfm=2n&-Y25F!Qu}pVW3WbE^ -BXK}Z58Hxoh57y`GOUsF$FZ4kUVxx1VH=Vkv{Ke(mCe@}-0yzj$|<5#^tL0W>UCUc&UD`NyX$M<;=S?kn7AFrmJ3*85||GK -01u*e;C;I}^q4z4)ji#XIcP@Fu~+lg?qIyT-U2$kn(&D{@kd{)j -6#)TE9US_dT|1sE?K6v*JYpQNxH*15|}xOW;O>L9|FP$QIZ%sJc!J;rWY{X23G#b9JEz^oK?Uqf2)>N -*(kkbSNgqjFldEnV!}DtMsl)XLm84hL1Y-K?t}L%QG2|NiUT>SEU;abRjXuQ7y=q$xr75OCTi81B+B^ -jQtDF01sh}+vb&v1cPh30U1&V)!Y&6BcT;d0GUdns%#JJD>BusZkKaW0ybKX$aJ#=?a8$P=#L)} -)qM%PKdxAiJ06U~JRZpvwYF=4L=RBV?;dD^o?>`(jAa@|fgwHBCIaHS0x(U5r==|A_7fhZP;u+r*O$5c|q79OAu7K%?(#^%r>lJf;wAQcZVcl1d_hj6W5P$dvI3euh~7Er3y -SpZ^GjX1%9Gh!hM#a4U^53vCz+DY3cP`nBHPmUj}P%h}cJI-FcwoRGkvjFd_t#fydhpiB7l^8EFiYe!P(3l4i{VJ38goS -nb#K=|E=-h+(zEai3=Uf|&^G#4~gDg~X8S#KQ^uf~oM_wHcqg(eO^ -WMph5%qIo~EQUF!5^29sHN(uX9<%xHal>(@dm50zxR>lJrvZ^_tovf62ovb{B9b~0IJhJi-y2wh2`(# -yjV=GyiJ*<+ImhTj4BdezP*&_^_$*LYr`$9F4Ra0#33)e(ejghu5V4bWQ;%;BCMzU&-!hIp@WYrLp`+ -_x)RYQa}qy1KEhVk$f?0w;ETij~5Y#LtwcG`Ydvo6>U?C9~EQ1Nh}&j~?q-5ZeLaL}(93>fZt8XVbv#NO>1@3i1qQulxJ##YWrHz=fzn#&lk -n{cxEcIRCHn%hHlXr$>z-AcGe=#HCQd-j8qqft%W=-R7WeO`4gh@4y7n!-_$3-vwi(77Z>rN@=s3b}~ -Tq9MSz*7ICylAb-P={Sy0DNu0p^`@M49Rk7k9t)99h!m -v!2c-5_L#rIEPEo}n_w8Kvmq5f-N&?;**?%I|DJP}WQ4__P5xJuOkGX-O|_h!*+vq2VF!U9OAAnT(TZ -Ztgo0TM+KFF8{2pCOL37=&>W%b@qN=f~LNDo&V&(dNKDA2)oZJ1DQ~8wN}D%)=i^a5U&H3C$Mm(A~4x -GsO-XJH{~M_Zs4D#M^gke -7AN4^)kg5fIGw&R5=)`x8H7!Irq&DGtQ#(p9>)aT&dGhO*Ip{q2_L|r76;%t^Y4gk?GD<`9D!I_fQAa -EA|cdP4r(a=_R~vhidfhu-NJBqJyJM<%oCzb>)YbKd5SOw2OZ0MF&Njg$|(L4)H%aq)X_5W0~mx6%)f -&z$uRDPboabUf7w_3U;&wDVX?F3s~w??5`JoH{&iD@pj{X0k%HY;xpwb*4t)Mn8S>Ur< -W}1QY-O00;m`Rt8f#!e@Vs0ssKZ2LJ#f0001RX>c!Jc4cm4Z*nhVZ)|UJVQpbAX>MtBX<=+>b7d}Yd5 -u)xixV*reqY%CVc;HaTk4{Bf^e{))`}-`FL&sJN=duZHkwUJlC}1~H_85*Y^`>oG?|%9zVDlvT)|xJk -D70H7CtJ;?2bwJz_b;3gq!CtZgY71_zrHL%>}Csg5YbE24`Rp;nV$m@$k5S4HuZF39t4_TVNJ{bK7s% -N;-oTeAS!G(WFV5Y_zH%XVP%14qV>eK;emS(Fj>0aG5gx5?3 -1;5zIXKfrx|yB@R^Ak7g{TwU5ESug+I4(E#g=oxZU}*pzIDcFue^Bt|uLYtxzi_ATHPp;z~uKM41_o@ -^=~IE^$qkH=Eeo)W7wT(@v7%h_7s@>cIOLik+DNc`l8v?tu&Z&`ASwt`{!3;=s{F%uZwdeIu -)U@%>qi&*3j$MG-1zv(WDk&Mis4YbBIs6c!Jc4cm4Z*nhVZ -)|UJVQpbAcWG`jGA?j=%~)S=+cpq?50LLbq}VKVijbsl!Sawe&g#Ln3(G}X423{Tr%0PD8YET6`}8}C -vP{X6+yuo?!Vse4@BZrUc+49zWa}+Yo?=P -N84pKOZ$zRb1^4vi^yCeRI9riTk}atKH$FY_7WcDH3vxrwFE5L?(R^OKT`9ce+w0R4f-70A8J8rG+cg -MHDnx0*ZhMj}Ipy04qakpOLS12+qR85wrTN^)B)gwX>`sBmU225q0M?RNw^H(CnM)XP&bULy1+aLruN -x|-ECWsQKn__ZSPBbxmX!>|q;$0mDS7K(8*r3B*NHDd$TkS10fe2Oco@z7@$_M4RT_4Vt95pECJH)9G9@`+ -nH#%E-9!8+fix68s{U(FRm(aHH(v5DoH^P!+d14H=3FrTk%>emEbB&YswfKtRX#qpf(6G+2-(I&dLM2 -l6MsG$F51laK%bLUzS3-6HhRh#<9$yZ=iQ&%SUc)1Mm-qf3AUzqrr&z_H%L -B{V{Remk>ANe}+-~7;DSy)SSWE9Jt?pF@mO1jZjh|!HBhoC)_qWsg$;dRY>?U5o0kXS1ihz%^h_##B0 -X{12m@C>WBj3vgV|6zT`_S_)E8`LD(#09!T%A -v*Ob&E!728!zh4xP4$fo2nS2~RdW(5yC(uHU*jvmE#yn`n#VKKq4}n-F$lf!l*?X|ag8+mwxu^Fw#tW -^|(UYa6)Y*o_a&lQRmRhBB+qB*^-ZZ=9quJJ~J7|-LaT4PId3e_2vTDbrrEd_nLk`Gzm9XuaDLo$JWC -nEQC*e&g(6BV#jRJKQ6^s3|eG5f4{q8t^_8vHdB2m23=~8RgDQE3$);ih^s~;SuW$TiL{NdlZkT(mS* -Ybb8KNO2@V!ho_3>)8&aYSScdvqcQ%OznE;WT?f^Fl^4CgUV~a`${mRB^ap$nQ7gf?#r1q|XJZb(S}E --xih^d95c5?U&QRL!W-I_5Xn;0+D^9i0TmsK)2&7`Qo}H~-W5mn4AlBA --whcxdU -hOP^h|v9D{x?q3U*GMs^M&UjZfxUr{uhGgZMD;vZBvjWVbzr)giUin=EWvySxt08+@FWQ^A$Nx6J&lS -4@e)B}>G9xmWTKLpF{MOu@2t`$eQrRfGR%UAw}CsIOoh`y-R@RZ?%BV#J@fvJx_R34ry-C>bgMQ&T)1 -d0j4#x99Rird<8d&aMhmfI4*T^}}FXlcjBuKSIqIrM(K&i35%@dkrIpCA&K8%}XFm{)dedmG$TH)7mm -jEB0)9P(?RA|f8kFJq&QS7i&WkEZ+a&{8`;dBW@}v?sXj$x?a!eHqhwR;vNglIqzqHyuopCGzy-KTt~ -p1QY-O00;m`Rt8g%r)VAg1polg82|tu0001RX>c!Jc4cm4Z*nhVZ)|UJVQpbAcWG{PWpZsUaCz+*+in -_1^xcyG;Ydg^BzOyUnnsm~WMk|&b)W)AiJ#D32D8aBgJx%gsiJ;+&s=tySy&8B-1edC2k)La_xn(TE} -JiTd_NWNj!|DseF|@VE)ueYlUDoGgY(e^oE~=*KT8QDaY$%NnvfC#H`m=>f7F9XoDlEuV8Yo9Jcws=# -sw^5dU|qrApdHhjt~+u>P-(1!o*Kg_!!eJOBk=S;4=wDi^J -cK@FmK27)|@rg{tf@XI}C8I6o}!|SWJw;M=bBWa)`^BDE`99?!b9DL|s80y!qV8h3zwk*0Od}bM>IY( -py<8e%5F&@`bl1y@21l&^vEqY6=)ULeYkD#TQVx4=|iE7TfXQ(!zI90UV0%MxG6I*>8weS(-uP -eg2yHeo>^V4SlBh$+dVtk`)rzY)W8U#xh9vLsUQY2*+=#DFpZVZwp{#S=fA0z=lkX|qGAf=g5JWQI1( -eU2I?ODtH-WLwn~*jK_AJQjjb2$pb(-uvm?@l4HDW1T`(0xBGl)GNC)Q3r;zVSeT5*I -IR;=JTv|k~lZUqIt*^(Nz7&nQU@YPQ;vYx&scho67lV$Ioo0O?*gg0;CWn&Xso-jF|dfp>E` -D1=*@}JJV}h+j3RT)HQwnnx^BRZwIb0%U6yr)-q~JS8zU!uWwes7N}(nw)Xt@!$ceDhRsn2vW6eOOkR --HDjxS125>szBtPaPb2O^{y%tCvmG -s}|v00@^$A2*`a*sZ9TBPA4uWEn37pM{cS9-|SrcJYLu!LvdKCXbFu$HV-*;u%)p7%(*3w+A@#=i7>uUuxwrQW$O1S -x~%3<@#Cnqj4VWESodwIjggc_?Mvl3Y~omRREHdaL;X-eKZ-eiuwoLS1Ww<)7@p*t81FX~unt;SA@>> -~E$$BQlO-@1m@FctAG7)MH#?PH}Te>+Ro%T%w^LE_UdX}RlNB891(K_=#z=;j$&^t~fEYL<*>S`Kh3i -?W5B=(@wGqB%;{o}_=D0Y41Ya&n(6AJt@i;VN%}JF2xMjyT6NVRy%c8vT@zh(s>xj#C2LAG8}AhCvcj -@}#3c3iuI&V2w}p7$~9s_j>)4wlSyM9zWhw|8^s*=;M#}nY|R+r^S7rLfT{hx4kE7d+yyz#G<&Dt9QH -0tle`JvPL^R_zO@=0|XQR000O8NLB_@Fy##4WdQ&HTmk?99{>OVaA|NaUv_0~WN&gWWNCABY-wUIUte -i%X>?y-E^v8;kwH&`KoEuRB>aa-dMFsXsr8~HUaU1XX{wRxm8>w(RoErNRPDca7Qyu9W&^u#znysxCN -MjjLGB7;s{{^Q&aS)?1{0aEbnTH$wP%QyF)Zd6i8_{He1X@~JCi8Y+C%cLe8?@XPOA%qSUaq$3O7S;?wgoI7x4Y-{?aS`*IrXCI4VtEP#8A7c -68m8g23hur)JdN#gBzI6)umcY{Xt&qu7f+%ac$mK-#ND4P4u^llP~}otze#KIu1%nt{Gdv&~baH>j&{ -wBZUF>HDKKzt%w{YFoBkI)#wDQlc=Ab^TmE`oLrBF%4*n;KKv-KgnchZ9oFSJ5ay1GI2l}?a@ZLDpUM -d}@6aWAK2mnY{22 -;+Gz0Y+k001DS0012T003}la4%nWWo~3|axY|Qb98KJVlQKFZE#_9E^vA6eQS5yMzY}doRk01ml|J!H -U(SuOdi@{b{turXveX9Ejh_vMZ-V|Z_e4jv43xW$=0L0(cNf}v@^43?md?$#}SF{>guZM -dUbVUPwd~{7jcAu1+NOkW*HxM>)1o0@XK5;4oE#m$JUb -4Xca4aOL>!&IJb!)i^_%n4*Jt=+NC+;faw+EXMccGhI-iSdxhgB@a8;Li+oW^;{^=*5ej=Zgwf?h8^` -G^+#x_m0KK%3(0Uz~yoqzgC`YujajX0s7j;pGy4u#kgt17x)Mu(y(VJ2_WiaSCNF%vJ#BBenW2s(tPH -OzdT6^ruX(WUsKc(MTm&FKtCQ(T{%DooUOISPH7H|tee!*Ewoo$^mpe%_?-8hQ#3+ad$zrUq>8CILUs -^7I^AMzvVL-_*?_!hC+!W_gnpKwoGiztmQnqq10J*RP_gM%LEITll`B@5adC{3?oXsfVKQP1|I-(WI? -%>ZTf~?^FD%ExNydF0+FEs8@N`$j9`z4K2^E6s!QgRw)oFeG4#tY0HMDJ*U3_LZSYs^2e*FxhbM$Dk< -vws3wo0{S-;ifB>JD<=KrAl&K(ukfalo2ke!k3m!VCCx;zy5S6S3vNll>!=tIlbn|-<+Sn;y;IpLXEzT>MVZRHaFkE( -#=!Z^;J~YcV(4)d%YEa)$ethWK|kB>c` --CzH$OK`$Db^J(~K(8Ect?1ZB+{WJIp7D!K!;v1%J&yZ+k%o;7LJlx42ha|VmJ;YG- -Q?a+7;<#pQipsz}B<}IMPs>*Av)|3#FXyeo1rmP!NPDi6r_i&8=UL3BF`N`#psT3iMzw{%a84pZp2``Q2ErBm69*Ccc5jx? -@PcFc~b2==VdlDCt{xU6t)BIGBpZ{bh?tPX)rk@ls&JHan4(J6Q<$>M;%Qs~6Ncv^hEbzKT{WElD23; -I#yO&A&m@!x{=LZ69n=_gbu^`rf1q=ws^io}sYSvx`{8n$Sdz6{2NDOnteF(NG`Dcx-R}o3*L|=VO(t -{CuE}b?MkwwPxcK&5PMonx4)G`Rr^@Wrv`ip%KciPlG#{K`YBJT6*39q~d>Wnp_4^5sah=N -k;|a&~)?ibkQtJR6A9=j53O-X50w^jH&$V;PBFfsR;&66#y`IZ2{2lk8R7b82Dt`R6 -K+UP3J>YFri;jGF$i`ODrmN3xS*$b5IoI*>AK5MW;NeSF8Yo2JQFWZ&qdTg%N3EFy{8D2Mp{EFW -JQ8HZ;_$CEX3VS7T=fEuda} -TF84O(&w8W!4`y0SWN>q%rx;79U9R9S9qg5IxI!`PH)NT;5Cr(k!?lSaCQ9!g16q@p}QkMR%+1}JD}VMa+pv}6l_dQ}No4bpjCfRYuK@-f`Al2t3NH*G);cR><+*@!?pJ -8%N5pN>(RjeiWsA^PnB!kX|;|2{^W6`uV0<>~9=qo-%b{U``p8xa*UaALa#wx1H9LhYOb#~1i6t+K@$ -wL&BAW6S#@fLSLgCQuTj1VBUIiwB3FuGSp@Fd%1Te494mb=rU$t`I^nnP{#f1MaJ#?}M4bHTL+6gD)s -)sTQ0u#WqJ-0oE+a9QAE71&10us#nNQSVOgZj9MJr7x1!$47heM2oevH|u!Bedr=@dKgaH% -uZ!v`QL7q#0R&tzeFhU!TuUU!9+vzI^%uA<+-7kN@q>$?M~1BSRvk59)ezHE5g}O$p^97=!-&88qtCy -m<+&LBa!5iy-%I)AdxmMcUw+gZ^%AVu4M_8i7yX+9TP*afu0>U+^uy5M%q#)ZEk}CvcM~c?#S~P}7qU20_kHq(t)a3`rwEJ5_5J5>mvXpxprJ2hWx7WRaX{?U}iU=DH)@-NJi4kItc=6yXcIK&AXonyYcFHglaW}IOC#i|P}a#A(RHg7UOj8}V27DdK)%B~N9rBuTl{HJC<57@K6fB*I_ -s;=wa)(boh=kp|sp>5c%5+HjZn|dk7DNjW@8Q6RfjrOpe5xz29xw-m8B_MDP1U-nC;7=^Uvze83_|X$hK(8ZX)2K3W#W5{hEfL!jM`#w=2aP0EaC&N-h#WH+_Yk^Zi7+Wkw6ntNr -%94=kfW?EgZ&BN{ltXCK{%;fR$u@lw9Vps@bSyL+JvRrVDb_3Z!|Jch0$T?p|eu>*_@sQi-KjvT_{pa -0)R!7N#A94Q$zC!36&nA1K>AG*chjy;AAzRj9{Ed=mf++9al==A}O5AGEE6eicLjcmbVzZw=4Mw2w6o -ahj!8-!q8}e0>B;tEd+yPAvi!8CUoMwO;SlNY+I!{tkt)v6g?Aa+yYx6ls33SA!7Kjj;m~C$Y-|Dvxd -eT<}4GJ(3#5-z5ac^fMg4_@v=)5Ef~Owj{eOwdNlJdqAC6i;(~4Z4kiBT7np8;(HMbfz&TJ!kvd&X97 -M6o0%GO{)elv3wVm#{~0DUbjK0H9y#nU6w0%!(QV#z)hxi-kI4g -+x34;ha`)irkD4sZy@*L1b_QjD7rE0D!=V(P-i$o;^O++psP+m6Ms+DEVpn4t!t?NQpNvc3NOzi;LJE -FO9n_&qah$F8IMXpZbP&2(v0~vxW^fk2hM8MFT~Vj(V_Qbwg|PuNb8%hZ+s;+>q|0P190kWk3~(n@BF -deyl<5JZyzo;_6X3P@reR$uyXy`f)-I2a;T}9scyj9$C&IBLKX#AA9^ew}*H@L-dC-K=~6>g-n5}l~9 -Xy*#hOzFJ+QoWM7LsyG^ywA(>KO6g2JU>!OBbp>7w8?43+a0GHwx6YxOxx)eWStV8yrB;^7IXFqc(?2 -yC=rPCB+=^Dh=37LnNR{?Xwr!%c1@fS>s2fV->-r|x~eJ~J&Aw4|6pTj6g0@>7Kln^bTFp(tVW#Y!g8 -b@@oI|M000iaXWf57DRG`igH8c^x#BNb?2g`|#N$I7~Y&sNU~`C1m>p@f0c7hQAm{c-p?=cABh^!+pJ -NM7gPvK3F9-B|?++>5V)^75;!db^40sA;Oecmi?Se2y97YCa!NHu$^>@XUt0OEp9v#p8F4gQfgM$sk7 -|-S2_j%p|%eRKUu+ox%icsDHFf07I38A+Q7P6h88Fd}l^35L{4|p%CSL;{nF{$USV%9Go+|>1zS>eva_~+wj%_K>T0#|4-)gb!WlbQ=$*?_8V>KX6dsAv35&+BQ!Mdj%ZsTHnV`0~p`^jzu -^)R*G6_O#kQwn>jPOUSru)DD`~Oh<1K}>lKMJ6g5%01n7! -4HpJdcWNRKdZ~>9garI}e4CsH3Q -Ax#(?CiMFc0;fQCF*|O`5c>at|T%*6y4OjUCFIlfUmHIkYzxVs8&w4+6zZlaBhL6io^}_OuH%Wl5@s$ -0ctCcB0ru3@&F4;$w|CdkHo!U#}q$^Yey;Yf@lk)^MaV7ypBJJqPtRJ7pm^UolxTVPfbxbdtctBMfNx -C6DMf{!_F1{A7Orw1hL)_`1O4evn5FY7b!r7hjK;;`?DEI@esHn><6U_9U^2 -3VV-Ct-j!{{Z(@cZ1%C2z=jwf=m%)q+uYv!}FkiIHt|RkjW9k7pG`wFi&80u?i&g` -v^>NGvW64<29Y#DOZ_7|k*LvOlsDVAOLaMx??<$ana~bUXM7bn}a%?AU_|GYm##8ukxx+^jD5zxd)0U -v}TrLsFqXTEHC?G@yMO(!K)yhZ>OUBf{8r0(?nM_pmA&EX*6!d=__R= -C~Z{Vlx=RLLgjWX_aP4>Qod_lwpE<+mV^)|DA>QWS%nK1tQ~mnEjqTiKf-7mRn!@8eAFn0chMRHQT(p -N5s;>Bt*9w0YX{*(h9KxtX}EyVGJ2OS+a+b>?y^`q8OFwpo+M7DgBL`#cF`wtZzs>{hU=%+0>OjdgGE -Sm%8S$?20}Mf8xtik6Bj`yZEX*`P`(RSgkd%nMvw;!uizOT_bWuFfD}Mh5jeQqX~$Z!Lafr&{-ejAJw -d`R001TR5f0Bm^{Ui>jX`|OWF%Qlrwf5l;%p5L-8-(6A?o7(AQj6nbZa6KGNwujlb_%|Wn8#cr^s_s> -=tYQ_7cyQk(g!n>;W8Ywi;NnKeJzF*Hmt(HY{ywV-~B!Ei;HjDJAB;-1S0=ODCzDW(U=~pgOamKFYq3 -#%B2gOM`Lid>%Sx)$4l?g0u7dK$SU>1fD$aD%S~a=M&m})I?{tGbkSszVou0*G;(!TpiV)DSqS%QZse -42XcmI0Pv*2<=T%<4JcRRv70eiWJNM(kqTVRHjLGtcqUa*Ex^iRY;c^(GS`&WEX!v{DNtQ`#Q1s6a_s -2}TdpF`lo~`4S+%f;o}L|@oRBAv1+KD;g@*P)!y0YH3x$HG-UShz%k;pEzA0C#e}d7V_8UF|$t3W}6n ->U9!W^k}35YMVn##<5H1X6$WQ$HV<^HK>zsnwO{Qg%;2EYH8>eq3|MT7x7nrcv<{4Q$>Lr-9j-gc1Mc -A0fPQ;5O?b|5h5=+AP?&cl*vFC(ILx5j#YmIQ}2D!WK4d4|Yf@&p3~+0Wb;)M$vSatrAyy@}ptV10q9 -%Pg*~gc4>FLFYGap|PZg$<(b39ks=6QQmb6i7WE^R!Yypzmc;6q86A#@&4D55*i(WZ1(sEXo;WQ#41~ -Kiq>CUNZjKz+P`SMI#@CH+t?$A+>u2cQOBB?tE#-p)1|zzVC?U>fk_)+8jND#F0TgmZiX1q!%B_!00t -+s?{%U(+3Oy2STb`AoD~gF6Vshn5n3-ZZP?xOs&$JlmaG3J(k2djX#+g-rlNRGfO#_oW?JAnb36F1zc_r1_g@50rsDTXAlrgF0J*w@k`PI&-{s!l0Crug --Xx67wa!}KL|O4|wEC#LM-SS!ybTWUR>nfLjU)BNx>VyLiYkp;pvhY_?khTBJ-2_7>B%92%N6MMLIss -mc6T-o!?3q)F&;ab20beZJ^3WhZAw{cz(@zuT?UK+lWvT<3E1#3SoI9qQymmwSCq(}tDyo+MC)(<`lV -GhuiB!JSz<03=(nSCNItyo-DXrDD!&$4!i}bsHKNTc*ZEf;S+Y%sW;#^1Z_8`y4cH9>7!@GEAOjfq{j -LsB%{tj4B~Q=a3)B-<5^jWPAP2EDo+R3Upbn$B+|uXR9Yt7=0w}VS(OFw$R~<|QRfAroafFXcbXm#<{ -M~2;9zxxwbswH&G(@J$GHG+X1Zakwr1Arc4pe}k8o3dN4Js+)EpVvCW+0rC-3W!7Yz7k*V2b$c>K15L -%kdPvOrN*N43h9&4ryD`Tb}k-zfz-ttpUxI1}k4Y)eQw*dr^0V+E@uuivY9<*DNg=LOlUh1XHxiF|ia -5Of}xtBQUbVViK;apxw>4S$bzBOE5V|w@l@<39Ud=k_b$F#fc@(e}&jQYB(1LZs@AL%Cne~OR<^v(KW -h&F^`=HKFv%=z+jB}KAwx@1PDRxDw}zVH72JmL^%ekWj!%L^5HE{Zh^YZ*U$iK$|Kf9GMQwA+$RNJtQ -DaPa93qbS}S7JoGVPyJY_3Jb#&zl(;2!#o1BLZoW#Mxdfd-$xE1tB4v+OYfkqjf&x8qR(YRWpE+@Z4( -$TITmt=7A3Y-zMcnkjfTTtN1RLhBwhjKHLVJxeZnc>it{GM&3N)kkeG8T0c(43I{7w><)?Aq;#D8Gx= -fB^_m8r4*fh` -ziAY^OmX=XA9&`D%bV`x_o;Zlz8#UPhB=}|s4_dO$sv|0r!A7rcS6m;_UXk9S1Dg>ht{0d(GdjCO#xh -z>+^L#J@AQO&4wI;J6Yw_*LKT2MFCn7bTn&{|u~0+)Fk18bnwOJ_oMx4_I5nx-Zld}|orA#|?h>YG)M -<1>XIm?=u*KlueSorFqTVRrvRbHE2TEdCSS>O200&nf-;6E7^h5ZQ>nKlL=;Y>Xgg$=%2&9d~Xg=5G{ -nz0A!LJjYA?S-R6T){&%^;zOV3Xe56dKRyYC^p6p&oL<@M1z0ngyLgC$syxX;?IbvDSB`1DVrGAh -c>m&o9goG2g{GB`_91C?6=hd2AF8srt72r0HZ?arQ4~H(_)n|{Zt)KlI71!mM&%0qs`KqmN+&IG~h(Q -Eml{zqv_A;X4#1wOHHIZR}T@DT2|7uRzmO89;Osi&XPjeOFS&4efBsWacPOS82NrI;su-hy)FpU>;-M -5eO9I&@sR0;(v@0pO1nhO-%rfo*oZ%LtJe;jX0e1j!){DLw3#ThnA;AMvIrY!KGy*YvC_DBWX!8!R?= -j(J?zD>>T<%lf85`-eF493BF60a@%(92Q_mhSZcC(PyT#%(xju_`S6`v@OEw3j7vt=>SiaO|UzDMo%> -D`|Bfn%uW2W0Eg}fQN*uPp*aRD$DNG%zq2X0t4ND4rz&@hSw$zf;xl;N5vOsuTDwVzY~g_0ut(!GoRPM~pXOU&`cC1{Nh91>h#hVZZ02+wO274>vuY1yyW -O(HrxgU@Y4VK1mR%FYdwb&j`}gV&IowSPL1w|_Q{`mv`^VyUtgi+V5)~hvLqWy~F9c~Rz!6?&_xw_37*6LXim(>arJ$SGS -JPN8Qh^Up!7=(kO-P~|d5ED$NPAQkIzwMC5CSXasT(0Lkf*eF?9$g_X6#!6L^>W0x%?XPdvrV(wh`>H3_?Vly)Ff1zs+Pa=lB|oGv -o=QJd+3sfsVBR&d5?AZXQt*~SPAQa*(yDlQUc^`3fxa_LpKFj%_A#f0Huhm7 -A-R)PPEXyVQl(?5Xs{H{Nkq&fPD~sx(s;jK25XY@qK6xb!c}br8YzTL!a(k>#K}QYW40O<8KNZ(l!kv -u8y$@9x -rV^mj@wjvHOtNZA#Lk8q6pQVYKgwaG98ogKR3+6Y?=_w7un@(?T7-NgXb(X2i+9vaDJqgKhb*R^ -0{j~j~=PI;zXU0XI0_?#x=`Yx9MqaBQGtt74$72I3&#fA@96m)YU(?ek)ybnLYE#FH6FpeBmdLY9%z_ -OZ%T+99(uyI)K1*6**tzwClj4(vNaY_Vpw4og!{21M-QI0o~9q105VC02q>k5UkzI5tdux<_O9Fo(u) -HQ34$$fm5uVpo7)H;ttJqDHmDq>QAc9ttddG+zqi=Z5(OCB`c;Ay8nSnq!YF8Ll@{Jsk;GUQo_hd*o_ -eW95Y2z{fpes(5jzGqYX;@U+68SuAv?4@x*Qr(^@kCCWaR$;5T*x5zUd;#Gor;D{jbDCZkMRH --L6^DLS*UXDc#FCKf=gB*jNA6)ilTA}f;(`4gpjYe|D>X+X*Yj*|zBWC@mH|q`IJxo`I=VJdWG9q|Wr -pzy)$4-YX$%%)iJ7qlAJXZ1gVNnzmiYtlE5xZR}DM=JQ?6dw(B{w4XusP1(IE -sqh)r`FVUjAi7SnA%}un(8`l(m-kDg0s}i37&_Z$lU~73?8NCCRe?n>PM)7C2W`RT27N|A2NVC#t*3N --{Z6hM7wP$}o|D3|O)X_4-IT{R-b=(igOUE@};Ngik!MaI&3Nu1% -Ztz;Mw1IR~v1H4QW4mNJ~qFZxp%0!YC7e){06Fyvtgux1phw_A>`lyTQZ5U3A;m^5#^fSbKV&l=a~7{ -L~t~r!h8T!p${4lU)$1Hd0?VAhdWFgUcQvaW;)FSuiyI1`g5mH~9B#w3%LB+H7SQ -w;06D;vYBtcs$XxNL+iQ^oEFDYb9GAW2@(;Q}Ko#0CF<12zuh7+MyQ5WXYcQOv}jv9?_LZluA>l!>4r -Vn7Qexr+9pb@xv`DxMQMv58MqUYt+JL_2L5Tz{z%-pq`R#JeKFZ^qfk$AUoIu75L@g>DY;rLS3_q2f^ -?RAzo%!o4d@19g-5{a6W?M*Hojo2($#-=Dg1^N<8`}S@ty@AS|3r3p>w>A> -kena^*Jq;%w}GmsJ?`o>kZhqC{R-l%{N@dO-ch>4*2Dr1)6a?-$r?ETrMVu#mcj~SL^N@Sgo?(GQR)% -zTRcyyH3ovR``)pIZq32rZ@$t9`vw^J2)bce!`rOu&ux-Yk0l?5HU;Z63QQkE67dLtV!GS6G1P}3?kFOxJY8st -gwT@;?-u6TFsWu3m}T)&NSg$Euxb@tBi>U36SWUP?l+vB7`PkNw$u}&NLWY=;@SGaRhPHZ1R -_re0ZRnVc4kJ*xmAhIp6js##qAo+z7|#sNY8V38d%kXQ!zJ>Obn7hchae!l`q*PZIK1@(EjR4x#KyUx -qG~2K6t(*TXa2uhVw0_TU0?L9x<|?T0JimOeE{UE;*ge5xqI|JQUu@$O^8iq5I!K6|J)PHpd!khl}Ky&&0(==VD*lUb$<$ -686(Kz$N}e`+F3OUK9i&&vpVPGSYPUNvtcQ7cr+COySpIJy0>3r4RzeTJ{8lJL<;#`aqZiyz8AOd&U -N^myk21w>ch}qA`Xq*ef}7S7&QAVB-`O^n;D)>2b9vL~WH!S;nIOEkWN0`H0oXy7Klo|Qn{7S%_E}J* -n^~Z4E0(%m55HrMj%rfy=n`Gmlo=IKpL_Chcsgt_J2b+CnQEYxdD`q#F*Cchva*Kvg|RJW1!3uP@yW< -LGgW#tkidf{8!|=;Co_?U6&PEv;pTpPx&o+SjE1vB3Lzu4_W@L*UVgN6Emnt>Q=6BU*VkB<%eR~AJLj -T0J)&P)N>!19%o0@~_8}*`Po5pWJU@AUa{StT`}ak(|F`)i{`+YE%lYN~-^mx(Iq#w~Mh>iG)e-=9(B -%v5%u-x+WsCO&nDH95@k@H62VZZaF4xfSSUeQ>D)ePc$dbH#se?k6%ao4v9RT>sD-{6ZijpTn@e5V?q -Pj`&6^(L8eHm)4Z!eVv4QqPID_yuRuNa^k#jwzj&u8k~CWmSg4!%G`-x10k@tObyqvorV>73}4a>-nk -)wC?QURi03sa^wErE2&NqVbZYd@ZBOJ@t^vv?S@&RZ4W -#ek9+7&Jx<43>7zJo~YgbC~m;W8Z_uS;AOBiAGh!D)V4yuJ4rIrTaGvyjh>p9KA2vBJYGy!fVt{>hvS -9TK8(MIyW)+IH#BD&N(_6i8zZ8~OW8D2y31>mY(dx6;!PJwaM}>Y4J<4~>={tqjVsF#nJt+VUuZ3X(e -<1Bd_p%b+KiYQjCp~TKidu|AEIJEm83I`!8Aek0=WpG -I*{W3~$T&WZ)zCzZ2K~A>7!36T5L?m;+wwyBZ$R4bTd1((tt7YUy^>@`E)y6;A(`X8%vKn(8b&ftoIr7- -MO0&^j%=AJEhyfODu2XOB?Y-UCqtln);ajX9KJLxyDG-Gi{|5pvij#!T4#Wl5o|NGkfYG<;(PsK93z5&x5ff&ljF6!(Yzrl`PIik<18om$xL ->sNRACSeI2MgwNe&T(fly%gH<<0-9Bu=c%+*nd}8SG&x3%#;zEMU2m`P)C7qIxc_6w0Tm{w+s&oryxMf6nA9XEXkvI*O%EH{PdA?8)QzU1xf1+#8TI -jgNWSri{xx>@5a!_ew2Y|Ir*n>wPpj0Am|Eb>rXrS*oRFS}2)d#a?}HW -x3(-dN1EPdQ(u^(nx3Ct46?UpDQ#_5G0Yu|6MHcpnWj$iCJR1UeJ`U$pf)`bm?iow*t-Bh-6BT`_Fk7 -3ZD(EP)$0+P!Chiq~L}nkF!X&;*Otf_c1H%ERSG2emmeuO%l8&z`}D&hprwWv>XkI5(Y(E#>5ZP2O4h -~ZVPqPXS0SkKlox*kQc%e5297{`jMi=BkA(`j)3YaaU&-my3*4>onp&mXhN)(b*FK&hgwOl-Q)<(p?fm}9ar&c>)ruAXVTZBofmxJExmxpbvxA?<<`dDio11#zM#2%qq`*KHaAeNb7PZT^ -2Tm_YN+m2#p8}^?K2~~x!xw!a*qE$(B&W=@%?dNIrV$@QYypq;2g}~ -V#(Dfo5{Aioz1nAO)3?a2a$0eN+OR{+IvT6?YNtKTI@9}^Z?3^=+sv9KJwhqJaR&p6g>rR_ -O1a)H%V8(wBVdi3|;shPm@{)yoh2Dwsqh2jTvDKvoYu#2fcFxa!u*?t;RmlixoeWHy=AtP{G&ESmD^q;yrPM+L_#Uu0-fc5S(MF{3 ->I)8x&k%^`CTaZ`ENgjCEB>hh0K(J8@q%qjQvTFz}jWyyO&TGIUCq-tVZ3>8a_4YI^+CQqFknsR_a_I -R0FFRL@CEZ864gnk>(nb$98$d_j|{gJ6S;1rKCz`|{#dOxx6aGpH2p#qj?CP)h>@6aWAK2mnY{22+TW -cse;S006Gc0018V003}la4%nWWo~3|axY|Qb98KJVlQN2bYWs)b7d}YdF_2`bK}O9=yzB7KOm!;0;o_ -Nzmw9v%8fE3d#83@J2Q^GB~MWh*_2>`01beWnC$-dJ&%5)8zkjfZ&G(rPKE-yPj{a_eO`U~^g(iTc$C -cQc~M;*C+lu;^hbR2=_d#9U-GnGZJOfhx=XUBqvVUvKL6qf{_hXT`)iTB*>u-+mAtDL-Cf>@?m7ow)DH;!?l5&f9DI -@3OwS0*vUtYg2nwx5fP`@2>Tmc4NN&tyu9d-SLU)@3W%CHqY*7VuiySCyi+9bu$yKDmtr|09jRd*EP_ -G=dab*ThX*oPkp`;-L#!u1HQ(|_f@-I;af5PE0;QJnz~Unm!ivIZgN#MdnsRxlb2`jPoJH>Kb?O2{Ke -U;)0b!CcQM`|kAVzxQj5RQv0$D0SPbylKU>5x=a9h9-NQ%yJmVe7b7tm1w%nIN ->r?z7$g+oT(gnxCf2M=TmWyz}ss$CP8v6MIer!fKH=lkoo#tf;Up)Ohw9qj-T*GVNh+McOuwLa*_3fIr6HXC_~!N7 -_wO{ip+>se%mM0=9RK9!7MlI^lc%p=zC3;PELaq1ZV5QnWk3Do+4FbrspLB-mZi^My?cN9;>Fq9G)OJ -!+q0*y-#$y}*S~##_U`@Jv$Qu;@a^5}@83Q>dj|#mjziUV|8n{k>Wx(U&tHA}dV2Qbd+g|h`dI)rQ%2 -CN%-c4ZK1Hg@>dT+StQ#G3i^MYU$7#|MH(}aJmicN0s7w%jEioelHNn-~CS9G(tr=-OfOD|`CR9{KH= -Sm!C>N?prxZTVp-hpNMJu48q(BO(W@3U|6ZmA&CRN=mfoL{KU5R8-H;I5gCO$b#BH*#@362AB^Y{Ps- -s4b0@2^A!OcK}weEb%er9eEYVa-aBH^XCkibay{THK1JF&I%6K-@A=zrwX -;1KfpoCYwaIgAeDbUsgVXPUA1dRSJkkAVf{ODcLy^3JaWEye~}ET}Y3MpXktugvI<-KC-5pX(|gV1W2 -XpdeumP!B`S*JYPcof`oh^ZdhT0yHkFIlUa&E5)a**qV7ORv?mqBf|>82~O&TyCj&Hk=+65LKzxh)@@ -eBjOZC8A&p=(*|vDbRQKc+tbj2p$Q^Z`Drg>wDhLBW4eJ)hkt5z<-AlwZfaAI;L_0~IFNhA>m6#QaLd;{bR3Q+#1 -c03Po3?Ouj9}k4YiPN9dp2LFP(2OJGmE1G?&vkj~P -H4vO+kLo3xQo{{1vA~z98b0%{Avodr&u8)S>x6Mq{)h5&O_u31|XnDxL>d-u1f7>Y1#*kOuR{;^Ymj>+#g>A5%_2bO8zNN!{q0>sCaJ2{dNM=tsXYHlz({qKaknOUI|arn@?|y}p@PDH?0{fEh;o2rh(%C`P -q;GJH6)!+QdX6G7N8zB(I<0pxxUI$a(yL_TQF^TaYbt3dYho7GFXaa5Qu_1T3J(4;bjdo`zPwhK4c9X -`h=uezm6z->l)Rbz_QL#lx=K|@3p4=zs0Pd*YXC_Sw}p&|e(I2}DJ!GhCAW2iTMP+aHFM9RP$uI -srWVC);NSLkGe5+j?H?U-C)U=FZrHA>HDZMLSdQkibHQ2kQ#h74nrt~-Ikwi -wG{hL9xVJu@|rve_?L3DSL@{^upoQJkM*#r&M|74X6Wb^LjPAa&zrgHF`^bOH*!d{w-6#bdJrSc8kj| -mYFl*#I`;|&xn7EnI&aA?HuVe`Ie>f2&YZ -uErq-e5c|tkCDwMueV3fi+~}RmT@W#tw_S=@$)bs$6KdS8H79$O&Mcfu5G`>Xlg5y@o2K_K#16-TZ}BJ7{$N -Pbe&T{kGI!G<8#REJ$hvq>uM%Tl^eARsQjX6U~pjm13O|Jk6g%Aoh<7{uv~M57L6BKvAACW7ZG#iSiY -v6m{tL~xIo7Th(3754U#9hzYd0Je>_O%eVhY&RLc=O%CVl1VUhabG`aNN?1V6VDJ=XA&XvLpsRoPXwdE(YwqK&!Om_Gnp`540}j6j!qs=1Pi{*y_}>jCPIUy -RXFCK^oLhob(D;7J(E;H;D9Ry5D3Mq{3^-cUWe*rTZ4TD6F=k;|-TfL0dN5K-mf2F6D8yzm_k6+A$Lj -YcSwY+A%96rP*N)9qn8yorCtCHB8l}TC_1mSF1I-(e>m;mX!N|&tgVMx76oh?MlXfKsP|aLTi9jao&r -?KM5*y?akSnqc6Yu8d=JY+Uu|?=FkeXGP@=pv&)cRZRlVdMp?j<+%=oPaxft6t)Gc}ou!Z4BzxSB(&T -ZHxfYmbpGs}^uQ;(3%oAFBIR+W{fkjzbR6q}fT*|dIgO8gr{0|!6)p67Bqh-|j47aaG`rMXwIj&*FY(oXK;CX>me&r)j&_QFEauaK&mX --G7d|+2yZ4#XuydPx?t45T0SKRWKsI+>^(y+5a339#RMQ)R -r-%tAdf(tM6_64MZ6PaV?BB+?|VWBV4NL~aMdJ1SFf#O=iD3PWsX6rI;tGz(24a-MqcX<^Uuq50VYsafIOHBj1CjkY-0lGoZ-C_6w8PHWb(jcYd2MWN8xU -lf@wHskVgnIu|Q_%%Vju73*5^jUvvf^6x2QH_YqY=(K>;BvIHQ!u1i7wT}RDSn8uZUaiQZ*!Q|C@e8@ -Y2G8vYPYlB`^(#?2RH*;&sm;ujj@+;w~9+w+b>l>%5IIpPoyE+O+e;JI7Ce{!G@o%c5`-YMB*o^|j%t -{A=S*|U$*?9r|XlFpM?Dj4!mS9uzV0?|WhpK*hC8Ra4zD`_6Clw(>+lpwEMn8T(V4{X~b_7EaRa>CoN -GLMCDcaihAQAwjs9P=e3=k?<)-&??`N}?hoEKN3?RzHZo4D_qyp`Yh{Q-u5794AsEJThc6Iw&a9ss$8 -Z9_P)!(~8YX>NcB(PC{_BXm0lYp|^I`E=csZ9kaC8bB*!fBEB|Rh*U~LMfF2(6EmeNl7XpDDZF!R4uOm -+E@w6de)UzL`!swu$OKbn#;+~PFs;)mN*#q)Q#2cGyf5eep -v*Vda{Nw)%iDliHP8$d>~fF_^GR2Ol!FEC^z|27+R!z!T$gjJKY?}DL5WFk90X;YFgrW3SljMl94dlD -v9!?;xi;%cb)ZkOP84getEpW#9cl#8_uy8X%7e|Y9`(?6+}eW;fp*h9xE-hRU^8=Z``}jWx^DC`Ti&f -*-mIQ@$V|S$W$ebVOHfI+SeKy6mFM -$8YIq5QlChz3#U)4Voxwhp9N$y7PNXgIgF9C9SD?AEGr7A~*s%I)d_6X<5z7`g4Md%LGMHXkRr)?n%b -)3bGBI#fw`_rse#^*-#GXI!#~*)`68&gd&js716$Pt`d>;2FOZEyHL4_fK>8xIt9KJ;Llze{N0NU5BI -{HO6%$Be<7m4^tjTSykKo=;0H~02aqG*zS5>r~K$I?lKsxacg*LdwJdW*%fj_}b=LJpyp;?x&_5AzTj -*V^x*&c1MvaM&-d#}M+)^@|65f_o7bjU1LxkE!+dou;saR?W6Ueagd>px9f3*59bZQaSJ9cnoYDfupw -FjCSkq4z3rA;vN;D{nL=HHI^XVkjN=$AIg#?gF4RLh0x -sH(MStcsasO1Q8gtveZEew!)Nf=D&*+NN%Ee&6u^{VcHpC9$hnVd%iI1lju_oB6cy5=8v~|T4eHirl0 -y2kC0DG$?;=|efzXqTQLP+q^vb7Np6@Wj2+)fzYUUrE>5Ly`?!<=f8sMsyg^x0? -E1TOLDQla}AC1!Z!Aym)#SV{jRqQ#BAw2zVUe9HYFxqAVnbqp&8x?*IF4!gey#NJp#Q=9$lq7hN6p8E -ik#a+-erICP@6{h_o#6w*$=TK=wx6k>}Z#o#$4iX+zr|8;{G5QlthuW9wImO}!Nh$7Meg+iyTT*)6ju -WPAUJJuy{T=$xuO*+U7wpaF>a2k}`%hFVFR$tbgcrs_FRU)Ajib=!l=1Zvsj+XK`sW-MCL@Q-UT!+u% -Oc_MkQfr{#u((nOw!52f*OF-xX@K3bEU+UXe$nElAPV=2#n%xIViyjRk^rG+w1)E^x`58jmv!T#aCEL -{`KV_`7iiC{Py)X>f3VuwG8>*0`Ke3zrcWKj-OMU4(Qa{vg38gp9Yqki8qjIcS}I2S{+e<>gcx$-!Yw -=V>r&TsMs#N6dKLrG%Gqh`#*TLokO8`kCW -l5m?_YrLA!*va#vIsNV266yhUB&rU4OTdXo0cd(X7@l_`VMz^0{^d&DXHKI~juu9FGSq-T-Qh&>fOpq -gn&%I&9Cp8PV3fqmSbXtTlZzTW8I4;isdxqD!5D(G^YOKE~z5BWk&FTeRpRG3gH;}WAugVepsE@2t~k -f3jA-p-056rTRLecY0{!QCCph8(3RtPn-TK~Fp4ED;t(9U`Ycj0jgFF||XSy)Fz)@2}QiFFa@W0xu*j -?bR9JIftytf6tArg -VEvzP7*SOY)w7FEW%mIzgJ8Q^UIznn4yOZkqy5y6)AG}Zc4EO$rxwjqU=BO1D9+#!E_`1q(^Pz{krqx?nAWabu)Ihx!L_#^ -TUoa`&#yX8n$KQIj{!Tlh=1^p{TS?4y;}x29sCJSMcr7k;aZgGUZkYe5*On44;hR5u{zcnwH{Ll$eSz -b$Np-FYW;;ZMO0qEHr!dN&ql`)Lf=CQ;Sd#6;BX$HJ@ijKvJqj|9H8_PT5C~9_JFIOPh^$a$9O=UvOs -8BmNkpWZ?(<{Q_MGdI6O|<@EwU$2;)|ntI$m+GW4n+IyX0Y|gMxN7-5`+mi8ma88nt@f+~SooWExT3I -Pf9&DbWORxBwm;g<6@<6uw5MT#bG+9!E(xt -R)`hiMddSkVClPdaP$R>cw0`CuiSGnLfOqR(H+u&BDu#+Y##$)>0lPy4i??}3GMK)$ksqIjhHm?JMxf -x~&TlJLxnfYES(n(S29H%vjDinb|y=gRqIOWKR`JpcfSpsDXD)^f{8@mUrvxeQ>|Ua2gB1y#vmIoP0ToQt=7EfpS3@jX7-Z&$F}rh<=$u|uMW0iBl8zBhD`FAoc2$Q -7`kVczBQ`R~BMXgu6muu*==(o=Nk|P>lJT=U?GJIbDn7u1grdWccaO2b=no7m10AZ?jgNH(%Ul -6<;*xW!7Qm0?Ej^=ZXPC~zJ~iva1PThW1S@ErmjP(9Wy#3+==P1+@c1Z{Z;%UlnJKq0AwNy1E290C2=901Y+mN;``nogi9kuf -b`zArD85g!@^rW%!h^gkcnYg5AccO9kN6r3rZ*Xb{$TUH_mgKx1+yUCIpQ?1yzp08UeOGbajnq7e>@l -t&=(yBZt6l2jgS=49*U5=DsqraNN3cwr7COo6@vmZId>#Rk)2-6nfuWd2TT2V;=mVOO@grWyZKk>`t@ -14r);+?l&Um0f0@jo|L}ld^!Kj?Ilh5ViA~R;3)BvR=MhQaDo({?8*3Avl2NLNqPdf>l!VR2cTh>>c` -2bQ(;DnIH8Za<2?Kf{W(`H?5NtjI1sP%D(VAZCi*`jVSV+4*KJ*V0mJxNY0%Q_{G2-fq!(dHRudBVLQ -oHrawCn^Waa*IN3NMXixwWY;=a(Hvc^3!G`@wjre<>C5wB!-*>o)jgqo6Sd-$C{kex&eGQfms1rLRs+ -mLma*~VZ3fg+fU^`4$HuR^)164u}qfEaDM~mfb-!Qklv9`rjVYVOl-n+k}1~57bIjhNJ;@suLJoul#` -rhDV$luSdoBpwjvW*(@840+RQMg5&T=nlL8(j^O|ha)w*Mg7TEx=Pwfsl`tlFogsW4u5NA<2Q3i1uU~ -)rw;bg7H#P!tRU=Hy^C?TzbVs;s_|51AlR|8Dl?Xe;k3Qt(9q)#!N@0I#xQ7jT8VLt2A_t1WM`0=63^ -$^YT>KgbUEcBMon3hgp3`}$r{-?gnEN09YF_yhsnGR)ui6TR?wob*RMYw>uYdW -y&*Xj(v+A*$S~2RoJ`v2;n+{IJ|(9JJ2G`_L96|otx^beVrPrXJ87XgZce&2RC&y|1QrSt1#Dau5=$?88Ug;t*3@0x6C=P4XGyRVE -(6xO=d)=2a@A{tdj0K!}R9S3)~Enj6d?(V^Tz$nqzG9*xx*bjrkHAn{68842?lMH17?n20mD@jSSD2( -*U^9mV1Mi%x4fLFLY0ID7dMW4^$k3sBuMKx(ocOXOzJpfsvi8hLQLR-r0NDPmMC>zr6PIf~WKJob^#^E9uGS!hi%aD5D=CaB{F25lGi{2lQLhGudtgoa;Bgv55kkZuv!$brLB| -6%xwCz?VDR78r~~_jw(mi3@nUTGOe$(Ik0ZxxnzmkrI^_8WOrrh`N18XR1ipDwm;am${;X+&p#Na -o$=5P^DFn_eAu!KwPwQ@-rF}71pP*al>;q6KIu=rAMh0w|Uh$`z?iY;wPV*q`rK^m=l@p?ig|q*k1l_ -N$??&rRA`5xtX=LJyBqR3I-eS9flL)MOIm4NhyY7@D+|HDy|^LqbQKTjz@6A3+$p4zEf~cWhxK=N3^2 -M6LP9Jyg4YJWR^vXCvm9)$l -n2f1@DR{(BQYFt2B89o6l!sbkC;ethANFmPx=c@^x-r%08RoATtT0ImTBdR1%J5DS@Ln1g(bzeqP|`< -3m}5$v(#@_?@BDT0Tt&H-nOy-XkKY*A~_*5+}s;lhBK%CvM#QYpnO(ParVl43ryuy)~FqVk@`+jq!t! -C?A3?5bLA7*{N#<7grF;@WT!bV;1_+JV-SS<8H!WIYFg+kh@B+o@W|xZlDE?{;N`3%0&U1P!3^tQ^Ifqdz8vVkvS^N<(k2G)_5*Q0>UYXjo8AKa6I6qx1aQJ!(m?>ex0kkE+)Nc+#ahNvNCr -I*zFJSdkPXnwg+gX-BAK!LU+R^EzOS|CfM6}=-asA84AR4wCZw0;)KA?$XzxVJ#M)?EEYt0QOsFk<#3 -N|;8D6&-n+~3pvsf<;^IhNRUjk@*jstSr`)1(?sO@jtIGYK0XV?uWdMEA_A1(`ITLcA4M5TxoAD5QB+ -CH^xpN}TCM3>wox2D1_!Jal)XVj-?Ucv?JIl;@-QLJ$_5!?oO*#O_?0LjQOg#p`L@HyUl0Tg!pY?JfP -{uXCng8dO^6&B(J8@U6eaS}7kG?qWvwt4|xdzk<^8tMRVfU=F;aN*vW`()Cn^)W>nXfVWgYZYNdz3aKcEa0*Il4>DC#dnp#R+*TnpTju+y=%?FZJ(*>6{l)2dPD))=0;(0b2vYud2ljk2-M4^S+uS -R_L9HRK$`x(ED0M25Ae3@w(6rLk#C%d83{6bw0O-Pe -rNB~fHyBo-kXbqzjBngJxe}wN;6lgV$k_=ix}RcjoK)lF)?Xp5N{U(e?>Q4@Wo5wJCjlnIFc~m!ZH~9 -^33zMi?|n2*-^sGe@i<*LdPI&p8N#oVa6$@xKkuiVjH>SlvbtngvwG0=mF^rJ`3kV9y$*coqdFRGVZ%x#i3@D9P&!LHe_1;vKz>GCd^Cf!Z&z1&c2 -NP5@z)9xp661j(_Ki12>$R`@yCv`FjCqBa}WFxaMSsECgwqSUcY>A&o91T2Os6{2^{CLi|yiXrSHnqO -2@9lK2}*k%kK0%c)J0C^b)CkU#V?tf^wVy5_-8SlXjNVbrL&X0g8|!TV0Xt|KS985jg64;~j_iin7Gb ->Z__~RpMr=6&}}6p9gP8Ze&)?9XmsX-MpX_Dr(Ul?tblPJJ3~0DqBbB_F9Fi3F`+S{<~ODk(`xlj&ni -n=W3s^jHRe9(l+(s{~60T8mQfo=mDQ!Y$v2i58FsiiXi+QY3!OfSC$b3{2k^zwvEsW6I9L)o1pgG6rJ$SWU!sYHZps7oQ0*Q0a-YABIJyux -hgIQBX_|Oq=GZ>_{l_#EK{IrsU;ewxq=#2LJ`#AWuiGesfa}E;gW?g#@R4`*#0f_0g+8E=G}^{pyrx` -!K>MW4x -=rbX6-)YtQnd;9$md#Dqi(tCwP(Dp(^spj&Y{K&D4{o(;jJ|;p!}*T2L ->6AUTmW*79vv<>n02B5bkD}!S)0fQuCBmJb(s}t-b`P!W5LhA{LdGN<$XzIUkMh!FB^}%d8PFp#P!sY -W#1c`2Ww5;^8w3y*L<69!E4s+q2@>r-UMBgT~1e{@X8FTsEd$`onSE_zYU(d&GBp1h!|4cQju1RoJB>9Vt=jR&`=Fvcu&ESJs#3%`Pu%vok?%w!v*$+fsQSrNT -~nGpPNych1DcX`J};3rjZH*P=1lGHJ&_G;g2od&!B_JO3mLQ8G`WlUe#$$yEDZE9meVp4Tucp^_-G{4 -NF$&*KXV>90YNA5m(S%+(}sLQn%OeKg4=n_TT2W8+oS!vCE6J>yCysAp#XhXN%f0X#!6~mi -ZXk}{E7@|f}`T2E-vU#fJ%1`_pb<3`Qsb%rnPGjJ(#OrMM;e&$!XcvV`5cHjN=fCMKLSry0|7sPjoZJAi+hx6X2>uvz&%CV)(zdEaf4pyLiXq4qCps#&Jc>9-+#c12Tm&<9Z4e(c#asW`*?;=mvqH -(UP;dkm*sf{6+@QbJpI+iP4npNTH=gT0w(f5Y&;6MxR5n*lqTP(>XANVq-kP^9GtCfs&R)@0IZhb+1H -R_r}=(npNjQDuz8LZuGPy*?h>$naF25Ynpp{bH#s=nFfsJ{+TBwZg#=>zWUo(UK8i!T%%O_Zqvh+WSA -2PgRrpxPz2jTFs8vC1>P*o -NOc$3fR~&J|Tah93w<$QC>hlyn?m8DpD -K#t+RS&FbvHhgOwCeFmE&bzNTb&&6Jj)eWsCBumms1TF4m%a2=)A&TURqdCm+?IXu-UF+*T%ds*M3_~uzlbbMN^N#n+?o>H6kG*^3?5^nM4IGezyjXQiqP=t28-etR=sv# -40pguNq)X<3}!Ug?xnx3Bf<&4mDBT*8tRU_@64@!!5sy`;IOqhkECqAAjh(q|6yruHg_xS5N1)qBHmp -O;hYGiW&Km4i_#HL2pm5J#zbCgfxIK-XGfSLLZ@{)EQ8 -u6y~fGYBjY>$PftWgRHGW+bjQuG~yeJWAx}_7i1(PbOncSadA`@Hv+dFn%wIG*X)f4`3^dJqKwBb?5H -F7sB^}T<^?0xQNjQIQ}xI@L&TH}3#*N+vI&4&1`{k{MtH0^Li6}DvY?bR!yQp@P3g~St0(ttvso&jG+utPspKBG3xj9hh0Cj1UDkZid(P$hGfoV*sFE!-!33imPIVnWP?p8Gstpi{n#adNvKpCm}6TOOe?6p8l!n -l_8tCRHPq@ZTA|xlI3=1N6@7>Grf(4V5#;L>%NKjo9DnC6asqUgCesOq+kf{4}gQT1 -tzv2e!!EG7365@@EFvHsoy6G^#sm&93*cUQ#whLO9Dt3#An+$8uNka#>blS^9+o>X2fi5jQ2%V2m{uP -GWRqF{1ZHmdGQj|BHm_W8t2W}0SR^P99ozwRo`3`O+9iu5Z=<1>Y^?d+rk{%Av|m0p<0Zqt$T{Mucr^G$De+JV_X8KnNqi@a%;j*rEQm54)&Lnk1gO;*QCi-b=bLXZHH1*cF; -^f=QZ{>l=LrS*uyUqPTRY$*==rokiC++n7JCy6TL?t<9}lJRzz>!O@nW(`Fq6c`f=WP8W#%so2oDLl@}DAo&lzF(;*yDMO&0 -8Au&UrA;TU=HqbV0Z7>s2|_q@*(mn*Ln!ZhQ{)L>DX;TV#w#u*)OF)t(13`^1s_v+8Z?KBXG%{lsiu}|0evBkltGY;pY3n_?}C-Mb)fWn8HzOVE -VyuUK`V#g6U^#h&l?vD5x*M-v8=;(ZJb1Og&I!tIr`5JXyMP84a}I`-1vv!{c0+-IJoa$a1Kh!My6Isz!U+Z&=fAqHFlkI1QJrq@QEL^(cQC#Mg -L~~L+bXkHwF2PNlb(b;>ELAZUBy9bF`7dvRol%93cv)6FN;pyj(yRlsc${5a^)knDU`>-%O9BNluwCxcdPUP+cQgw&uk62z7=4#U5Sd~wqk;u^#by-w};w+r4%g7gGEISJxyUZEx{B$_BO~dcfj&e -P>_-8178h|7UG?d`EvQD9wpqgn3hSPl+xSd(UEgEeFX?Pi#m0udbIuAO)51?9D2x8pp*n(f3p-=jKN` -tGhGRx@g2ZoSI=wINQioRn~qdp%>n9}lvAX=CPoUJ2cz;;vuq^p84brT%=A==P-GIdue4?;Z6k{M_1OrADXmhPdfx67t1(4JbbLz_suIu}&Zvu9>li>-tAG!Ez0 -k^CTT+(Jf0L!98pBwD|6N%hePy9~g!UYhi$wLdMHSiy`nb!=(J)Z+h^(xY3||TNE3mexf}AXXyJc-*X -$w{AP`YPv(hirWd>Tb6iq>Ls$DTJu!j&jAtHm)@sm}k>DpD%yzw8 -VsOq$!i^FRQ~4Gnz~A82tk-p^vTUkP5}V7peR@-OU47K4jNl*r&PqXKE35Fu^hW){Q&q7pIJmW~)NF~ -U|1VHW0|XQR000O8NLB_@)>bN%@)Q6708;<}8~^|SaA|NaUv_0~WN&gWWNCABY-wUIX>Md?crI{x?L2 -Fb+qkvg1LQyOCJiL-dX&fBE_&TgfiyeY9Uz+xCX@CSX<*9|ZEHuCREiqMz36}Md5{wI9A^{YZrc?Gi7 -b(a=f(3PsfXh1i!%}BaguEpqSBkQ-{6z`_a4HZc##)Jm27uf_%CMS*^{SVi9aP-coc8KACn@$CNGmnW -~GdU&V}Ad@%pHDc_!ZE8+{0s6yN4m7Kb{4XK*8x2w}8Lt7Kj29DZ$;lzW+J0`^8q@$&M;#j7_Lf&QRH -n8o7753jDTF8}cM`iHAG_%I;cl6{dYEp}nKOOti|JI%LSprrntm-TJAt8|h!KdW`2@<^6V3oZA>CQ0S -}ds-bA_wNa~HY(o(T}p(^mf9�bzg2U_r*~BYI!Ih34K)>!Msdeq0=jB*@j4ZoH=9)y4Cd-(y4b{QkWt1^UG6FuDo1@)DHlgP*T|l#!kp?mu|& -fN!pMNh!Fwl7*5bC|U^`Sa4sFU}wP$PS&XuheYo{gU%?y_9 -MpZ-n)+epAm8g&UBUd7?nUzWe}ER0xg#1dX7db#vVnQrDNr}I~NCM{_#^6A{k -hacr8HE;T}OPfFn}8y?QC~4G~DF1mbcdvK;0_A){oI$e5|eb{m+Z$PbZ}!bXL|ONGex?!5KAB)bKP#He$5nShx)F2tkK6OY6ILiDIGGj_S-2@OP`)H|)p -GF`%)LlKR%*cRK-7t37^q;=nt#^dbw^D>C#ZC0fz5Pa}vA}mFjWH%k6ABwj?G!C>rqQ-_*s(}-rFbcE -=bP!%Wn`39ZL5&3d0JpO)7%;zkU>F!iR5Htfj+)`Cl4SwlP!tHYCkeb7qusq!1Y|b`KL8;|H_IqYQ~w -<(4@_6!Y6+tA-lGMK^Gcs1De62M?hN{e=$wluBghh%MwTPf4zD%Ln4A7<5nv4V*HS`aqFx^OGNv5R=Ba&`yQ$=fXmyXp~D5)!zEeN84GiFr!E -@=RFRKI8+H@$cOeCE$wx(AHTB-vNc-na%JD2z~_+H}#hsS3mlq9U9lmO}yiqarV=G}O|O>}myORH2t# -t>*B{P6qx3IHvp6ilQNCsZzYx974&`hA7UQZsGG0d`xp-1~bwDwm~&?-!X@}X5J70ZJ`Hxf8VpuyfJg -B|Sh>KoLO?5%M=qV{3zdsz5Kr-!bjd4>lhF}LGgVOb)141u>H?k-7)?+L1hG+djCRz3Zo1=H=^Px>Xv1 -=`5hCG|odv>y+<36PIv}jDhRgbX)-nLZ}7>Le~9DPd-&5IM=dkqiKt6`A1*CcFLCks^FPEhVjWZ8r?% -lhw*7^c_`FN8+gv4D(GeinO-M3F7o`#1oH6g5ASK~&K>jFYmS!VRj77oDvgFgVtlUjsMD2sts4o?8?MyjDnf -+(=6L1LbOGodFo|6|mIk69cIX|i{ilj(65^q_HjhG+W1_=Gp&W+I$JlBPm~>p<&FR3zwjjX4b%8YL0k%EWmy2TaGDim#^L#(~H`2!9{CYul$(rb$#%N?r$q}N7;@GVTM=Ty?S?p8@Hp@B;hU87;aeNgjxdp3>>=X5LG<@ifZJFGVPihbD3491fy -QtF9j%uwTxI#h&J58WLqe809C5Fg^vV*mu2`JX@dL@K*w(Q_Wwis=hp};qWqps2FfRoaNJi%*~8S}p= -2DT?QE^rLUYpiyx#w-D3h%iIn*$kYj13-|j%Ck+3Nyjsfo@M!&)<^GsE8MhF83`!s*XQk`%pi39V2G^|Z;?1; -C7ugi734Xn$VhREG2iuc_aI#ao}jy(Tlg~ZRz{gL%^!@u;_rHYBbG{FTUUbojL -YU{27uk2=O&K5mMVKLuUnXjo3k|1zHq^`060VK0HD~OrF4n05OklNC21KWGJDdhS~Z!ITX6*4C6=Q=y;2%TTqlDE;i@0Z_DN0JxnSzP1K<)*s+hDHGfz3l0i0BERV}8 -*bK#D*4qROxnafWs})PvHQqa&?4X)p0y4afyh?r4xJpD?-Qfe6Jygi(CL@Z^Zz6Cw1bYUNH($M1guYs -I>U9Dr`W!ht0M@Y3@wc1EkuPB>kS}792zaua)gj@l)&jSYkvxCY{w8(R_U8y>PR9eM -GyVf3&+?zuSkN-Qv3%bkryY8L!|F2z*GRx)>otmTNgb*JTBApW%tu2 -l{m7VlcbuO-T(CZ0=hNjaUS_m^$iXhRSdR}n@`xLAYm=RyW9Qr!z;Sp){Q7HC+l*7#!yc2cIT=+@9ut -2Gm2^#bTI8^;(8F5I#D!vF2n(*C9MKzs|s)2!}p=fQM{fty_AkXLCu1rBrxsG?bi(SDA58xClVAd#TX -*aEo%&Atkr4bl1U?IeFbs}`pCYO4y6>y^4}Y6>U%6a=xs4P3T{S_5eMf6DrZ-@VQM^pcZv5XtnO8pQQ2TR+B?BQzvmvP&$Wv?HkF@ -DvicL71ITyTxthJ;S|9TlGTVC=pTSWtS=-1t5!A^eQCM|jG!e_t!y5E{ey~+at>O9J6vsY=_Kkc=$ZUNrf+a91}1EId}Hfp#8t(qUbf`ZEvtSh*`-Kv7S-2m{yBE~!4LqiAi* -PE&U&Kr5o-ghSnDPKqYjjq@R6S_izg=VAbQe$jaTxiePvX1nJaJS>mrqte!I_nI^Tap8{*Gfv?!Uh-7 -2HgrzPh7zyI)3URripapJgRVOcC#nO4SC@$ZUnw73~d4Vc}Af<6erj8$D>Tck>NOX%JENxX)bCev@3T -u1Zl&?h;1BFE6`Z2SOPn}$IWDejQE%H{RzaO${$cm8f?PzJ5d?x$PL{$>!RC|Hr0G7lYI|4MYULd}OP)v@Qgz4hNSh(YoFRH95UfA_qJP&hXb>HdU*-hd -uwsigXr+IGY`jmy1-qMIYi}qwLo}L;yGG(8zN^;lwh&jUK+N?M~WZealN~OR44gmg$+iKF}hI75erplrPo&W+ds -6^gM$lc%(pM}WU76Q#d94g%Vx>g~cjx-0usIrgSgwixWltw62HLr$K;26(L#1-x6vD8pLO#SB-7xY%EnK` -6GgSc0@1yxJN^(O(GvAz4sW(zSr%J9jN-KCgj0JpC%buHlvu*{n&4F(^63`;;q%(gy9=7HPy&(iMGf{BI3i7j+^6lKoV<-i7&&6I2_%R|dI*HnPAL7%O=<-aKxH$KTb -m~wHvDS9WJ!x+5ECdVU%X15f7y#jItuxMF`UpxSN`7HR*?FncfBp+u(vcXGhb$q-@GIT(lD)6QlJm6w -J>EPqpua1m{k2>#Yn;0E1*c1UG-jyw0>okvU%H;2uRsH7a|2!KilGDqxr$aTn5JRXZBVe;?Kl~P^#RF -5hIRjnT>fHmJ@&@CPGs*^!B-6fW`0l|A1LP$Gc|SlPhE0w283x@n@Gau=hBI>-dI0q3F_9J*i~wkPp@ -unr930h(noS%CA35sHq<~1iJQu)L9&KbK&~LM$Z>m*oJbO!$Em)?BUFVvDSStqLIG|Bx&^sl@q<*y2% -#0ga3Icu%>|A_kVmoVewmC;Ohh3gZvmpZTWpmVWI;5_@2leM;t0C>R@%Bl!PCJ6L|8e4o6N)5Q)2w$~p1UoSLd#uyqY5L+W0Zl}upQb`Sbjn_io0QSDuu^s4 -0=IJ<&h<6BrIZBg&WOm%(FIF}WACqBncI!no2qMdSuUFjJL(*XgF?rgywfFYizEgdy0M*aYz*!Idaos -ETh=Dc#**-&l|es|9`cXZA6t`FD^^_lg-x}RY=1*F^F0mq+Q!tVt+UtsdTups(LH@65VfI->2>d{%_u --l>Cm5wo0xuC9gDTnF>wA?~pWy$$i1s1tX-c-_epN98EBLo(;fo2rKsYQde;uRRPMs-3uGjQgUFtj73 -@`QozEaK4C1G1ts9(GLW9*XC2SZKTE$={L!Ce2Ol4^tTw7naRJr=<%4zbCYK{1_P@;Ii4R#G1LpZ+$& -h5Na2)eEjskzy9jU*R5Ukq0(JlcfLDC%4UBzEl`d(hST&Z9V4fnX{Jh3le}<;6OtDL8Svt}_b$#BgIg -+b()$4rM42tY54b|2)H^%##FsV2Ba-wz8zX`Tp>KcCZbQIfe}*-Q-_pY2`GZI01F-ue+Hf=LZdo1~ZS -9SnHoNU@dY*M;B9HFIVd4#oC++d*F8-Xrn~&hjZ)>zB*yOkHpPj<6VP>%jnDrFBCbvr*-r}P<0&I6&= -P`eQ?XT*unOSimU~UyyQ;U6->IC0Cc35DCICsZ${7s!58T${h7=9cL9EJ*Yu6lLWcCo^=ZhZl;qlVN3spsYU1wU{xE}~_Dp9F+ -P&IbY=)OE6#_=XEOi*5zqht9{>OVaA|NaUv_0~WN&gWWNCABY-wUIY;R*>bZ>HVE^vA6eQT53Mv~xnNBBR$-K -zy?vmvSdxEYSyUX3h|wc)X~l055+wuTK7Ac<)bpaHO3^vM5x^HqhaLIGq;o;zQ}A#61XR%N}i@>Q8xr -@`5WXTiKo^I|y(cFp4K5BTQ&_fFxz;BmR#SNU?)1kvMBaQ@)o`5FB4Y4EqaNcO>tyO*A&R=hnW~JX$+57J`)qe8+djUN1vRPGGk`j#U^*q})!BhI-NmZ5ABnVD}ZIvuH$s{OB80 -}3~S=H0sX0xAaAVE@_5T(#B>wJd8q>;s{>Q{N)zzXLUimnj} ->fp~wojI?^L6g01rp+Ee_W*mIL09T#Oi*dQ$H5QJzokzjH5-6$$qc}ovqlI9Gd8xqJ%h22gH3XsO;dQ -S0Bo`*K_CjiU*-E)e|lQnBK&i>!jr&#LnE-VduNs|^g{7p|=5P5`KJV83b@3H -I>^7{M0bX6fI!lr{X@RhH@T|2KXa2YEeZ)XZn=4AB`kAFTg{+J!MR@GZTIraX%22+Mu*=*2fro=@=)6 -s|JDaG0&A3jZGcboy>YDQmf*4X%0PriQi!?!P|Prv)>$&XM -wTs6(Mp4`8`-EZ@_td{g4#DS&Rf+jUtuLzHdz06mfoZum*?5~wq5m7rV@p|*-u1bq@b3f2G|i(o?xwcA|m^etat3$WM$c74*K8@ -{~=tl8lo=j$A>7k)F)6vqw}Am3!=uDSR)elX&)E&0WVdny28?Co@$%&(IrOrBI&0E=3$%}QK43g_#x& -cabdC^mslenC*&Y7kpo2d6mycaqtwDF!;7)WDQopT@)8Ol{u^f0&zc?&0(W -9&}hD{gIP9Dc1Sv#picHRb%zN+5QYi>tn{p0?&@&>n;wvI-t2J3snV+4ts=O{KK%HzKYk{Yg*yiK(=>#clx7Ca6m -Ujbgk@huKzRvcz@KLyy#(^}2yDAUOQOG`%veLUrm$K`2q{t=Ic-1X719{`ReGQPMqT0m$QjEP5t<4V9 -rm3NAC3Zv%bYwN8%Ef|K7eFsVXC!(QBFRLs*2pTRiyhESco~hxK?k@ruuAHrX{tzO04B4_w(De`P5Dh -{Uh$E_v0XHR+3RU2Ti01X9GZ6MKUeLLFAtT8kHzsG$!PFV+XCqxeK*^Bh}dGj_}G2%zuXt+Ediw+Q&v -$qL*d0kD~XtKS;Y1=m#>2}paCEOAc;vDew|s&rb8|3a#z9906PX@3JXBDqA+ffDqjAAn}$BlemPg4=` -Sb<{9Toq{SwMr&VW-?`wqZtxulZW>x};1uGXps$ouPE3WA+mXPYj&lcD -j;d84)*0PxJ`f+0x#Jl&3qLTp9Y$j07+87K-L7R2(WN#aycM8$uh}{x*<|ZjkKaxaGN(PCcwL*AiaVi -F_|Uy&}lj-p+d!t!L9+3iF-LE;6M`-wRoBjK=Vm4&k#h?4tNKY6bS8he}gi8GRxtgYQ7rD(7R)1ct&H -2ObQ18F=SnW+zlhMC%%gjAK_x)g0+i*3}iaZ3lO-cvaOi(T!b>u7DdqLhR;)|m4lcJC`_UikJq5t9!vAg! -v9wAN1halV@kpnQ{YK1fa8mct(u->MC4k%VfR}udaHb<%~h9kD?mD1_3NUG`Ds#V$ZYvv!`*-G~=qoQ -_`7WRsZ>`^NZpX(oK^os|g3Z0|Bbm;+IIdD<-bg0rNc&`36>HQ;$txw;7EekSajQm-X79N@!mInJR*R ->|hmlH4YHyIu?kXzDlJFOE->OF>^FB+kLt)6~JhOTzC!=6-+JZR!kg`=V9M@|5q9tO-P6cuy3iBlD|Y -(1XZyXLydyRqL-4n{(yLDO~-1FG#dK?$_330@Lz?I?!Z;IToH$UB*uX|mMjVJf8oE8wL@_NxD@Tt-W{ -nFp<*8hP^K!YmxfFP^?_m*Wn*?V&Nka-AB~O>glq*xJ%p|XJQ!c}bpk@es9 -To16@z*SyD@T0h>ghv_5?fUX%tOsd9lmvU(A|KQeRI~SfFTRP7BQ`cf(wiIjAkwQOoieOLkXflk9nAW -*I07r2Y3U&S~(UxVvDY2z3Px+5nqX#T0N8B)7@l!7T%GM%~U6QR(#EAUH9Vv#U;9yGN(0Ocp~>1j(pc -+f~QRP`iz5qDH?f5c;jM97R*p24g_)c39C5ZkEhCearPV+FpZYegmr_)yN11FF{a2nhk;xtloA@7Rnp -Y4Uzk5&V@w4G^804zECBU-rBd!qF6VakzsC4L<#5-QtaJ~1VpD2kVTUUCYo+3wQ_7zp4)uAM(9WZQ6g -y}sS--_G|3_|FOZt*1xWfN0o~@T|0-}u&Uy(-f`z{;o2TuF$SM|v&q(EOhpLo&HQ2C2{yg@eqevli69 -MPqqCUj)_0Z8&gLDJ?vQGAZR3*;vwr^HJPBNvNyXe=#t -GK#3sbaBJC9^f^?`V+73$wAwAV4Z|iPc`2pgLMDm9`kc=xsZy!I_PdwYApT4nyqWNA--d5QnL*W5!RE8A2=%S~x=k=|5W7hWOk)^asX;Y2zR-&cpQMPOwj%wRM6|1+F?LVRefk?GE63X4Gd|h -b-Cd050kwqP~ab;2ui3Y_*)&N=a7)6``k9D8NMmNWL7AykBs9@vSLq0d_7l0UxP(eo>R&LcY$MeGmaw84R0>j70d$nAu31 -MClF+__$WC+3}%E*&ZsQ)zTF#=2EP4Z?W^Pbv`zW(+qUnCZ -_(7lSSJ@?SuWgzNN=1Lpz^E&|Tr_t8Yrfi`0q*I-84vGYing;bRlFbktV7!8W+g_1jhNw0MB8wa&$g6 -%VVG-W$X-^+5m7**Fbb}}`ZAwjGrg^a_TT*f4AW8Se&5UOvIm;D79fav9`1;f&(L;|KKF({wto8Z`3e{t_Um9@x7Krc&PlHWC;vvhC=dSr)R?|Mv<{Bg99iAV~N9OqT=5!1fqH_t0Ax8;1a8EWh`a)zC -XbcOG;rh8fEH4&_*X1o5ePR$tt426$JiI_J$kR6Xp9FTltgiC1L^mK_G_=nF0k;D`)+i01LH8 -x-C3=QoI)_7jWhqrdRdMEah9Nw0f5&cEAgmov6A^pqaZlF;&_GjqqyKYYkH8aRLx4&~9}ZNI9jWUmKb!;A6us2-G!HsZ5 -y%YGX`Q;F$fZ_l^W6Qs(4lZ)I2s-5&X(BjSvw1KZbm1!hnv3)V=0R#NYTyZ`Q+7TMEvdssTohH2+ ->dCM6PhvLJzH;bvc8uPQkL#A$Fl(+ZH#avJmKI+Q4?Ij=16quTO&DF#Tk-D@5> -e$CeeEB`kS&uUjT%=14i8p&{@Gslfa{Ekx6uI`M{N4eb2EZ6(2=bk05YVyd@{ckyEN -$NdPE_$Z4aK<)ePWTU)~NUoig-bX5V{X;J4BZ|BDZ>Y#V=i&k9Ir)>xa;FI1&h -+%M#%3(YF<_KMM%4T&eE$SI+YW*fdF*=h>DrXLcLNwdcaXwk0vET`ptWS(Wru51Rlbkr?X>$c0!!c0?K9mR^vjt~uG>bjN<8IIak?y?s=F$15pN-jy^4G6EJ!m+wMQ~^ -}lu?qw4X4jpDft;Ke(>X^F7D7~QeR<2?CMsp66h9637hm&uR|7U#!_4$_D~|-b8EutOG1_&;_7jKBby -3Bn!H=T(L)b3kq+K^M=0)mo>}c19nCR1mmN2<{++SgqM<=KjFZ#3_Bq4C2e!%&R2|S&I%sSYGEI;ZuK -JO-l6f#NVuONV@H6VOp+o#x<}Ht7<9%!5Se5Ivre1=6Z(C58>nthSb3-lDkgKMcQVMNQRAyGwsM@zrL -^Q%y<88T(n5P+wp>%VzjG~dY9<5#N3qR&zcl6=NrIdDd)g~o!ST{OmVNmH7kUHQYa>NMni!z*UM#r~D -ueCz2KeVSpLWl{k+G_0R$+QEx@GF-n86@Qr3iucRS|!q0yulFQ2NuMMI|#F=^w6;RTfg%mlb<=kFVLy -D&Khwfi`tpYnrJkNlQeZqLNrTq5-V+Y2CUXv=Gxr1as;luLybs~DpPLe7wl-#d*GV0S>5tUvrZJ0^9D -N_Vo^H(GCQhUw%C}s!x=wgP=R^eZn48fSq9O=_`xW|t+~yrRkH1OV55iYd~p##wQ=xyaE^aIz^@;V!c -IqwNtvLX^Xdxi6jxVcJm)QM@%J++pwE+s+iyxdJLF|Zag)KKmw7*wQ;IpIi=@!6(z)m;w0$q&H|bz_}330M)g5bR!sOxEAF -_NQ??db;GzabjyfNtlAXh^pA%lCAtnY1H$A=w3Yv#|q*YSy&dyw^3}wJt%r2_ -Ks?I3*A~=UxhG|CfMDn!~(MTReqytn1h2BvXPsu|P190kb+XXBx<`27gy=G=|>9C}m`MPfBPg%mIgv4 -FZ>KfUfYRoSNUbE;$#CF_@qkWpG-v9|9DRIhN<2=lD+QQ=VGrjQFZ>Q^%Sy -t0A-0#=`&NK8e&g*IW>j7<@)=c>s_Vosz(?fmYLiXtE>zsXbOiCCI!*Bp9Q3lKF&$4V+Dua8~J(R{rZLOMuExGI%ckhMJBKYVzea2!3&v+RoIqQoN -io4RS*GjTf;?g=QQIBR1Y7ct^RjurIG3Kx|ku -$r|L!K}Y67N6!@EUf%ecpCl3`j@XwBl?zI)ku5#@`Ja;g%=CGwqtsUX>sT^OVD2V4`;O0k=&m9ocKch -lwa#$awW29UMTz{#1wBIX@m7rQ6Q$@4<^zxo5M*FZM?Y-_?1#HFGmDnZUL;WD)#o&G8S72e!gToiEF)3C0ka*g|$( -+r~I0;j!1c?$nq}i>kaVC+paZnHtdlvz>UxvhzT#Z=WI1*glg``AITD0xHHmk& -HVx9yl|#qe5C%znj3n`Eq7eYOhqD4RuVt#C^qM$?$`qHoCf95D>;)E!4*bkb+B8L-v(ARM$sb=YUiJp -c2>_ut)}dt%M74zM!JPLoxO1lSMoOn394CYMNx#japGDmqm%Kys2%Ve80K0pWp}QV`p_@W__$7 -{huS#$#qikp=jDag_eJ2r^0NfCP!UYaxdJS~g>c$XnAo#uJG9nD+=xBb2v?o$-xz=&Hle{8nu&4qT)^ -o?RhK0V~9qx+offet|LS(FnxX1*xdFUBMbV6r&_uM;?ku#^vMrjPxPB3~}Rkctv^y|4EPLJn5ZyPWl$ -yCVgiL*kF-Ql_#rK$H!ZR%=D*NS4sg4%*Qk!54aY!ZH0g1(I -@0aZcsKr_f?pWue!z6b-AmTEv-d%2X@}}5@3>o~j@p#+$zP`3l= -8__%(nx|&KA%`j}~KER4)%pGqfP@CeD<1LVBad+hM*j)VDgm^1(S8{ZISmQKZ6Cw*~j4&YI0m>Enc4e ->E39I;D>3Eip^eqzOr~ra&woWQ#M@!2cimN0QVxkuqul~xX3+l_6j0IRtigC6I9!|tME0zFE&U3TZxClnj%@ -ju)Sef)_4I=3NPn3%flkt5yIf=e}_Bp(J_{HVlPhNdEI(ZYyn{#**!kh4oy!aSid;!&dD&Xx1K72I#^ -8NR)oen?@S+W6Q_>u(>Uf2MkZwRxef1h;v_o>^z&n$4*HyAOe84TXwpBMb+M?wB6rAD$d7DA2B@ilaW -2F6JXFT;~pUq;Z}$rrCa8o5x1GTm_6%Aq(}zj?FGAoN3#qhL>)sl|SY%wtQZmBeO_3?5aX!DKH=c(*) -AT+NWad#sZiP1>+9&`$K^i8S2da22-^iC2jp>S>%}v~w}7+_ecW|DK%v^5E=`|Mu@6jqgwXbn)eX#Ha -VBKmGLP>{Xjil41OZlK`|`Afyq;DX=oXwaUjxyAEq}GA3G(rUdHF$q!(?yv|U`tlW`(J+EBiG3F@Ltj -VfPUbNY%K;omY`UWIG&~OczR0%4K0d{H1?LrV2yNWtR)VQ@XbOx%@bg+u)EY!)%9Hh_P7SR%>AwF@|@ -!i9-@Dc7afEu7;ztS)FEDo)ERccUu2+{jZf8tJSGp*4HO7j9 -lOom}9)_=w(DRpb^UKHd#XCwa@QGRaQ}fGbp{vvK24khLZ4xQ5`Q>9*G#<2TbXQP{OHyLb5*x%sZ*5S -vXVE&@%+drXL=fJ)cklc)+Dbq_j}%FGFdFr{f00ne$00CyJE7BmXLNQexklKXa#hmVIQkD&^uck!>be -Y_sskaQrbXk!AU+>fE#LvM45^s}&EQ&nz8mS>TB9pAz)DdZxteNuOBvp>pA2WkIds1*_bsaw~DH%yi -k+s{60lu(w`u3T4T6-ho$mwO*v%^w3B_#E;mck>8fO32_GPIZ=!&<3Wx<3A}?E~kg?uS!uaO421M~1h -pRIG$IoGUuOo|%7}@zg`E-Km301nq8S#~z59n`Ih73iF0WXk3nV^u&Nn>M9{7hsE_J(8ui5ELy2|%cj -d4cvAHni*7&YIAGuu{eV+LZGWcxGO3c2mrqNQYGD{;yE`jCx06;v6N)PS?o{?erHj0ml42>|vIZh|qT#Jo;n|5Apa -)sQ=3w4^jtteH#p|mi+muD*$R_eLrb=*AOvtBgb&q2YDepX=~D&?z|eahpc<7G-|NnI@a`vrk5EHp#rKUr -)dMDg9{l)66v%5$>ZOcc*(td9ABWlK;Zv&uAlsoa#Fz(gy*u^o@7jbxp`Lue}`LC5MtOTM`+nmW$Y -p4UjR^`#i3E0%2v>4Yx(C`&X%wD73vp&XKqaDzex?+`!kcx-CoT4p=^dR+ab9J>n+CA}gF*CCRsk*g~P^HG;C+H;9EQUFXgzMlA<9yfe( -cwyJW@IqTbCcrdUi>$#&g@>T}pCN3${{inBlqFxg?9Xj;5rBcJcqNyp-AB;ln#rhR&~EiQU(tyBKbw6 -9`c?bY*SLGfknXP())kKv;Mddmls-3uAI`N4$0JNgiEmz -eJ~}R?^6ag$`XcZ@*3Z|*Uk*}qo*%c6*~u(6L(_}1|1d1TiPIjidOXA#AlKbZ1tFoj4XN$>q4CRLd

eU0Zm^lz9{>R^Av!4nC)%(deiH(0WG91vySHJmz&v#yEkRgQeOf{^n23~tz4QJqA3gyO*P2^WgL(lGQM!nR~ -?`J&_{e0+Cc${2d2?P_Xt|3;ow7JKtdW?Rpmf%V1KZs`52lH9;Z0$W1vrwzOSJxfD#m2J3pciCgbL5Y -R`6#7zsYTYLwdNdWZL;fxmZ_qIJY9iDQrNy2^=0E0xvkxL|dBww)N>cgeDL2hXB@6%qXuZ}FzOl)bsh -(4X9tFfO1K%Q~2x9o9;{w_@NUyxYIYPwn-7q0B>w&UgTvH)s-#-IG{+Buz_8qcwpztUdk3B*Bu(1PJ# -S^R?AEdikq-uX%B{$u=dZK5RBHN$QV3{usRc{;TgvlbNV{UL-|*fv1M83Pa`w%yvLA2Y>^+4VtS!`)T -2kr#(7#+?J^RAfEt12Z*kugGSed1x1&025W7rRt_h)qg!xAhI?8ppViJt(!vKGQ>ou;;XGBzs<$xHag -(j-wxeBi(0Y-ao}&tkpv -!#rX8IRC^F#XF7Vl*M28c=neOvO9$0)uX#Mz1IN=kkcR_}%QUDU5;7+A6cwj4Vhw@5*^=WU)Oq_$Opr -%;^?IeN&ON`9=fMO&#Oa9#$$2LAd5KuR?&~!^-7uN{vI-6QMyNar`bH?DRA3H>EaHfumS6cLT&n7?0w -kg6v#WR@WuH3$RGj)4m@mYqXTTv{KR;kxMUOwZ;#nCYtz{dW64wK8pd+R;U|;dWlC9y~sKTOD8$0*GjM&SyUz< -)3wd(66E(tyK_WV24xw05%D3ct_lBP*0s32BT>kxwS08>6UH<*^S09Z&|NY(4)#ExY6)XP}cP*~8KX_kup?9#2+d+FOTKvOoA7S`7zF!><*H^3d|K|KeA4%_gWkN5xrl9rjPGoh -wVps+1~l=n9>6odP}1a;z8pX8v#p&Txp6a0|O%bWaL##dk|F((iC4^a574pZ_-AwDUV{NUG%Di(%Jw0)<(mJCslNwYZj95y%7vl`woAqVzs19z)w}*3Awtca;j@$+ZawJ})9pq+0(Hc*lZ=eq;)+% -?)6&r$T4#P6RD2(ku)(-CEqUe#3v}r^~aIl>P)xo2)wJYn(IjVH-W`w4XN!QL#$PH7D_Z}hkPN(aKZ -awME9gR=_>2}Y-wt&^WV;mx0jlqp7YDo_E>6`qs2l}69L{8*#hdNJ94CIcZd&0yJ@<=b~5Ul*@oo0hBm3tG4xXgd(q7S^j0^|gwNK=J -j1&ZWb`_t&{3T^CaufRr2uW2J7lXn<&#OiyQGs~O+D@1B>HL+CWpo~B;HI!_}IBZBD&6F>{Rs*HMYo} --10!nWTXZ6=7rVGX0Nwp)!3EgU0*%P@IloFvoRTkJ*h>^`c`rgV>ynovDD2o5DD(Y-_Yt)vz-G&VtmF -H5;rgxY|d3OUQnYxP -^FEw$$y_=vN;Aqq80uIB2M7*ZXx~E2_=d#s6bWo^<;K$D9Hh&Q}SAL8tf8a+_7?RZJPeQIJ$p;Ssy)L -sj-S-Bt=HTS47!{a$RJJZ)t6Q)cb{3u$x>05^%94Uz^2#z@>TRikV0U -DTL7JLMl%3%o789uTuGK5G(dQ+Z)9j>$*Om=8eRN~re&$3!(bYy+`1?Xn(PC1OPimDr;dxvQBuwtEJ2 -rfVopBNg?b0dE)f*afj7R{16NUUrN{K==^4xd*<&o&}$re-_;5PoH3RA;z5$Ur%`m>L56e7Cv@3(neR?GW*6VUy;SwziCYkDe*xijQ -RVk5p}FS~Ff4;Y0qQy2eAn~^!wSYPtmZzUm`X-T9|IqOy=qf)QNEq$S+Tz6Ep$9x5Z8S{?!g1IcX@6M -(n)vv`4^@*}fTGQuL>Ak1X)>kZTBS}-+rqtT@dgtO%nmYa?I>{a_SgjAxH0u)o>6((;f|qhNkZH3Tb -t@qHZq=D$tfs;tbJlIcfx1AH`~pEbRqhGV)}K~dCIMHl(X&myrepa(9NSHFCPoiU)i#aeT-7j&M>ZG> -_o{3IO4^;#?>SX-F;GX^9>hVzU}|K%_ziH7$8#JSQrUMyM4h(9gN%Kp{FwNE0|jLjY1!T$50#BvL2yS -;g<@V94=$R;l<$H^tk84lHe-u!>ULYk;VS#NABQsTr{8xr>)oaA;ih{QG{P1HexH5JUN>SM4+Up{Uh0E#bWf>&6r7fAVBW -I7I=Or7!=gsL-=l|8qgn|*0|8?nabOscuB9PCiHpoo45w2@YPp41q7TBG}CliygEa`w3W%dU2biNPoq -+!{MiFs-t2!MbBcEv8wXNrs2G^oK&R)#t*wQdv=LkAZ7=y9_rXYP;9eOJ#cM8;)UW*gf{VW3^zI5cFW -HvMqXDsE7c8J!WGIy_kVI*nc?osA;mzwqeFhpfG!8yEdHfryy{#&W-`-p3im8sTLX~rX(kp8_U^+)DG -lfI@vNGV%Cx&^pV1OLobc~9DH#R7g8-G>9z8m+QegW#G -LZY?2;NDsFJ#zj_v%zvY?|2Bf&uO@A!u)FJ?4m_6UQjPaT<1%v*b9?Q(SAVH+ZjdmNB*W4cZaMC=(ef -)b{3Si#qU+-48#aD|?$lO_Ws7zdNtE?DT?ST&k!CS^%8AQdUE!)CeIrL7{QXP{v}RvQBR<@m -Vp72w?-V@08jGb^FvVzk7}l;>g9JdA1tH^P7N1Z;8RbW9Evz~mP^`n}QP+CY@j0t1Y{|z=hU|1=uKJ+ -|+NMXOHBuQq@p`Zu%E@iaJtkG0TnVD3S7wsMtl`@Nco~qe5)eE_GdO`V`&?Za*b2qB+F$AFiuT=zmXc -ZNKvxKhrfBD$wjRwx{W8|XuxMi1@v?5t#95PVOqSFr(t^|P&Kzq&rJYqJZ%~9^%_-v<7>gV&fUB!;SJ -cpWjfUwEdaGm!b8D*@K9LS^-Bgtp6yBRAC*pel8YfFx-@%e&4>feH&J6^7(9-vVGI03{5UrOV3{|ovA -|gVVZ-5+G7s#S3^yI?{`9YiH#}O{tUzAyiYB`+YG?-vXqDCNG?Le|Zl)xjGe4gV~c@o8x_JYTwGIDDS -nZjWtkkB~#m}WN<@-()FVEC(AEXLgNox6`%6jRrMdJRkXIB95kgWbbqR%RXOTKI9Ocn_DD4&Jo!Bh#+Yfts}{GpF;H%v8y`o -5nL=SY(QPvvN)qW+9np?Bx8B?KwX#QZ=Mx)DKF#o85Hs7dV;&mItFpNmJQQy&miB>fhjV0 -S%dIit*1qrbEW{tsAfo3Zku+C5rzm6>ZAY|wn|Rp)Ql;WeQFnF97K+i*SQq9SL<$`h>6taNUCMu>QdXOaKtJ-_Z8| -*HvkY|Qa6%?o$H#n>!Q$F}c>Sc)ra{4!4Y6WR%>#~K1-hwT=s_U;Z>e}o`LT}E&yJuWh%BM -i?naz^)KD`0+bB5Ay6^;~h%=cPH<~~<0Q|ipW6DrV3 -3XV=JVuV^$3n{%)wja#FbfWhpYdO_EqvW?nC(vg$KDY;{`2n1_TO?0k%w)_=(I=vd;f4m=uEG27{SQz -}0|XQR000O8NLB_@{~v!|ix2<+WIF%=9{>OVaA|NaUv_0~WN&gWWNCABY-wUIZDDR{W@U49E^v9x8*6 -Xdw)T60{s*?Xg`~_@*A%$-!fRUOrs-X<=7A)8TqKz*OSG*;7Bx|dV_-l2o^wb_)WeC}Y{k5xkwxHuLJ`I3Y{bf9I{Y`jdHQ4v{%89lTjlX=UNCpxV>{oz+8M$>ui5FUn2VI1i)pb8a?U=8GL3>F7 -O9WR&N*iv5BCp_&ky|Ku3$kLvHg?di?hT3{CIJ4c8)K7+T!{1=TD#PCxMhK=UL7rPYb|=6?4v#SQbo7 -*)&eLWO2#@7Qw4Lo|Jm0r%w)kFXP)FfmN&!Gz?>j^l=TYA265<5bgki6bsI>Tuc(akiOnKUSuMN8R;S -@!g=*Q5wjWKQGFM(ddzwCC|44ZnC4=^e5PN%hi#L1a&Q;&4DmGMp;%-=VP;Kb#DVMFj3U}*EEMT2&x< -ikpCkOIPsZaQNycNg%PyUxAdRP77S1(}Afh~n0gbUg=@0kq4;y|a-+XH{=Y~!U;8`E_kGwtmISMUHsNfNixMpW6wq4w+W#jLDJXv=l_rl -*|9A2I$?^E7gR}F)6XYCdhYxa;pabJLor=rR4v8!zbvI&k#pE|07T)OT69ykp%DtB6Ps%tckapOX-(` -u&jfK$oN)~)UWWd(~$VEOWU_q88E1Y~A` -I8ArxWpn*E}V<5g4VQlpgCod(41Ofe- -m*^00*?H16JwG-mQouunKfzN)90~Q?lWZ{Z^v8NI6@^pc|1GfXIXNhOI>TtP6_P((d@=8ic&=%mu_J# -mWNaju#ZJ+LPj`(F7MKcs(@Z#|U1F#5M7+-oFO{2;ozsUJ5!Xc`6E{YxnMns$kPs+gK1q+MUJVJlA@% -y$H;WjKkQ`LVN8#Z-$_hH#4?{t6(c1UP53A!5cz6$vK3r__hLx`o7NSfP5qtA)~bNLM~(QWR|OH(~eW -yx>cE#Cb!R5`N)!v%cSXT&W(WyD~o;d0sb|k*@ldiO-@RSm5?NU2`|w)i92AOYKJE0l&b79dDkbzIJ}GCeqoE))K; -(sV5L8QNrYvI5Ece@EPaqk{qXukjDVNNWxae$;A4qT@fz^wY3a89K3Cs#@0YgDMr&0kzgz5 -68AZnQkD&LEfCLo;8fe2&;#6b#S&vP)VkUtlF@L5lvJLE8rWdsXJ}EF^%{iyR@lI5b4Kd!%(;Jaa@#H -0-g?0slNkGJ+53SW>X&cSg)>W@vd#14ig^aeL2QH4p5R2La_kKYSh>7W?roSVr)q#30#`AE_c#H`w%0`!YI-$XwrIilV;68oQZwHta=6oS;dEat9tItzacqngGqXqs*)2W -@moQpDv&}UI03*vz~rax>kRVl_$r!sW+by*9@9PJ$+emFS4@Z%K7A=E~F2?KrRMUjnOzKlc&8bWo8FY -?*T3f@a8$~@%w-JchWWD9l%#~jHu0)Wgl$ie%n>O2LiN#($uvN9VeGn8enCaAtaS}rCa8F2qg@OaXO1 -ze%BV?aS&8w9Q73BLu)RZD!voFK$X+QB73vJ6%YIG|L3OEdyB9I5M~T&mT$vB4Gq{Y=`T-wE8^22{** -4t@mi*C639CMyyvFUq0`jqh+Hun&->(mNZ5sjvpjC9eyVnO7d^8NSwUJS$Ww&;x5dK!&Mg7y6~ikjEK -H!7`xQbZk}FVkbX9N-36D<=x=l0!zM{5M<{q6lxKn36ti*Ey>P?(JMy75M(R48iK5$LPjc~ylg}eT; -#hKdAT;J)X^0x{}d2*omAM>6Qk|~mfSCLr;=tvER@t*q(MsmIMUR{MmIFL`)TVbFf@Y*SkER~YiNfo^ -cGtS$!e&%YO)4=JfFf6740rNR>L)z0c2M(O1?m#iPHIirJi3 -wAhT@6v`I}0Niq!OK{9zOHEZ#xT|8v*V9wgiK>em+lWmh+mKOTOIe$o`g?0@AA2_g_Bk?`<-xRQ^Zj1 -6!^UUDNh`1EVOI~Q3_Wpw@O)77tPSrYE6dBYqfQO7+B)($vicODOX|ahP$zQA34Y29oJ^*vOq(VNY6Hg^4pp -d=LUwYc*d3*~SuIZO|vf)k3$)6AdglpB4Rsy;~iFd0Z*sD|>Gh%y8)$L+>e{OHIZe7i#^6gyT%~S9{2XRoF0B%+Nbe^qH3;DcL8{#nEh&WeZ4LS5d(X)wNL -pT;>_zml{26MZ@-8?l@fKB1FX3A9?8s|hnV?*xiy*gZ1>OAr-0!#0`Tl_EDL&j53`zvwvJ=1puSOHg} -fX4I_bS(l-8@}+D3t>5nJ0CpNg%0J%uV^qU`A&9~#SX&S(6t_WIR?K}q(cch6$c3m=a6iKuqDVu6{gSikbN2`8D?JCJ07a -eB#8Q4o(`X^WISN8{a^B#_;S`$@C~RuN79e -ouT9L~mRZ>ksqw9)Fn7t5r<3t~2OPD|3_OsPKc5Og@9^3d@*Q8ioCG<(^bwC5kd4q3b!osRqA -=}U$t}1YT9mHRQdwq@Q1M7pAW~b`7@fLe5>8!9v#ti_#s%sjXqd^)iI*T7Yf+_#^gT#d1?BZIo?#YC& -Mm0`4vT?}d6Uj~mI}P#6Q}C3Qm76*o5UFlt3)-ZVUP|Q>QT8hMA8(Cw+3fwxl6D?*i_wzGG{GXkm%5g -Aja|s-qF6;<_>Jsks#6&< -?oqPiF)@irBP#@Kz6T{G$a}tW_<6Ua;~j|fQTo-3Yd_Hfb$McQ6uX%h2vOtgCcUW$2Dm6BQIeh5M}v*n)-L=1>ezNhCyblLHY=<#eKXZSs!X$?#3y8wRI+jmBc#A~xI(!&? -Qo9wF+pV;b?=3_dfN!F`1GL_jG|;Y?kG!@C`LF_m$D<};ED-kL-;J>Ne9 -4?R(*?KBMGF}2Mlyb18)D^q8gjW+qZn)1XgnklJXqy^@_C5rKA4aYx$kuj*t`{8{s!?20ztz0UNCV5lSjhxga -?@bvDt^5(dbgf>?EXnL-wGRWy}mogE#$d+vc5l)I`EOLNDzR!+dCPkposSa-C$Jw;+`w*;}4w+aP~M* -9NvTjstVu$^u%B#JT9qr}SON>={ciZeKCz{UfbWvmkO_HiMAA+9raJU_!6O;tqWW>2KHtQHzQwr)Y~= -gQ_p;-|U;RU5W-gAX4)`+5LQz`F)C3=i!t?>*={j!m+@4vpYs7-ZaCcNfrcyk-+oUw+0r@Q``;M13PW -l!d4`TMO?&cD>nM&o92nij`F;cSYTIb4=m9PK@e`>-t|TrzX|yDqBo1zNxm9iBltcns^?3 -jNkJP?zoQ!Q*pOZzuojt;XZr51eW6`TOTDH;ldG%tiAlXW$I(ZLx~aXtI_w*!uiC>7N>6KQzMvnAAII -NDxb;@;n|bRbZsS&e>2kXUyq?`1fVuNRs{j0L{1^K*u6Art8DB(vy(78J?s*aQqqVg|K?V^NTU -$EJvuP5{I^tDh{pZr3Bl-?U8se`SmIobDIZJn -!d8TDx4v^c~3uiQg;`vnxXTvDM`g_2E4Q!vFx|$Km5#XT)+Lr0RYQsvOyh8E4$}})7oWbP -+%0OCQOjamqub)#gok)v)A98*zn*t?Fi^KcZFq-A-=AQBTjl~72fA->fY*+lf*L|Xszgt5Lp9H0)nOa -h@Tk4E0+|&&rIH19Ug^VBgr(P)YgnpI_L~4#*n4B_T;RlX#_29D_6k)vk3dv~tck3#grzp5Y8(2|NY- -sgC>)p@mO0+HPF5rROA-nLwjBGT#zPTfi!Hf>zu=N~Z-~%Mu%dN -6#gF|@4%)gWUY>nwkuW`b%8B&umD9GH0dxP3sgp;Z8j3AkyK)1Sf738@M2w^O>k3*{LcNt!{_Aqhhvh --oQu_r)Mk174p$Bjp2Lrv%4)0lYHi5mG$yZ4UcEksKR=P*xu9EeMZfVXLEJ~4F`-#bj3j2w$mQ0or65 -;wX&$L!B8N(9T8*4%(jVg-)Q`Etn=x`S4gk~CWa9xV~MRI((AGm``?#7?YIv#pp8h}!TX>~oPmKqRKl*3<<8nWZT$iZms2aub2EOjU}R=oY -siEF|SREjTRGVj|<&;Q@h%FNu)AQ*)sW6&ahzX-9*YK=2VFJq13%w^o9j(Lyt~>R05=$t^l8`ZGF;P; -gdIt;ynn7BxD2BJaMj%mnE+G4SPj%{6gYcnQH|j*R(aBWzQl`=!uHi{8Dukm4TL|97KmG@nN^Qqb})r -(`oF+ZowFjLCM|!Tb-<_dOVN(1v{If}f3mpY<5N2S^|Dz6Y6)U>c!4^oJ2}Pp=P8Gwh+E9)@OMk#tZ} -4MD)IgW+O`fjsG8Y$A@}-1-jtPY5|Cbx4tkX2o)f83GlL{f}*SS=Pxkd=??EXe+anOD&(tkbrkv+i+& -fT4b}YuGkd&tLDn~)2|IbMA!xlS|W+ASjLwecz8{cJ&Hi}wJOgk-zmP91s;!}c9HcE_<$vKVW12w_SN -k8)omBVplnCzJon&luloql3ZWbt?bTKox>+a%r5)AcUdTs59;o6JdiIRG&=GlInZ{43=>^>&uBGXSme -3!VGDDx`9C}I@Dy!gtNLJD9z>l!+?ZnJUn)Wf~P-`n3Ugu?1*x<9=+Z@<58^LN>#eJ`@^-d>v?<>VrY -hMlbdAEhP_{6p*hntp3KZo`Nj|(UYp1UJgaV-TJ;(ln(1l6B{Ra2{I9EU0lkF(A?b61p(CX{0rug37| -34BPGUc7E(bvv&R2re4G(I0yIeOr|DX)^Lcz;DF6w!o^ay9q89Vi|B<;?9Vy}aY;$ -PNk~Tb&PD4T=9`vg_Z-Izx2IUaC|CreO3~>H76d0o1oIRv`eh#UcsaK~YzQy0b2vqyNH{HqzVK8bav) -_*H8ns6^T`yNbjV`s*{E%JcPnlDFy=MjmUIaczZLK0C}_zrxIFEoQ53we%d7U#Fh -T_9(#Yy`KatmGNar^?N2m@mq)z&L!@vlmUbcqm8c<;=@k^6kHL;*V>{%0b7%MppEfk(Pxa8>pIrI}WXHcO#g%nFog@men>RJ(u}~6l^e?p9jKbT*BkV>rO) -f<*Z@?uetRLZQvzT%o0BF@uqRH`l|czthf-N;8~)c36mShsQv3$IgGa`vYEDZLt?p-q%%!?+A -SfH#ktfXS-3`R>N__2H1=3qJ8`FF7@4wZ8BCFvatVQM}o^`yKjx0zF!0mOdUrA=V*(=!#GS9O#tI~*U -7C`E-u>Od4Olf^XO@@wZJP?X7IWN+XY51r-tHK6nsA-7exfo!RK>3giU%0+~_xSd81jFlItqBQ$QaYc -dBKV=dHP+Gxi@I{0mS^0|XQR000O8NLB_@*aqv(C?x;@=bQil9{>OVaA|NaUv_0~WN&gWWNCABY-wUI -ZDn*}WMOn+E^vA6J^gpvHj=;hz5Wke`|?Pol47fA_tv}KT{lr$UmYjUcG`3um!U=2=9(f^lCtA%^S|H -B;DZ1NP_o;*-TTmMV~GR?gTY`hGnfH3gVEzrFe}rnxZDYr&Bf^7@yVy3Y{GxRvvP4)WtUe?5Iq|Nldb -JZaB{_h*LTfTSp>)BMRS`}EO=2ai!^DnvKV8nW5$Am{b$p|!Ts>frVCbq)1D{p5JLSd>*$2T7g>bFIoefrrudc -xxDJkGJuk3I6l>lgW6S(7DZ;tF%gPi(oR|8jJ~(Pd~Y+%6SmS7t3Z@u{aL0If4(CMFs?7ah^4-O7a?; -7O(L6tQIxdJjrrdY0l~zu#NFee39i$)%kl}7V1Y{US0y})$fWSbOCTIfj!UaCeO~NA7*TUWEujNH>|4 -RYaGkMvvR&j8d>GIsQ~W&t6@;nx45}muzDCY>_bD}Wwm)yT>~gtFDsyvi;6Y!{jzC01$C=r*2L#`@in -^}2A8af>6s+KSYRb9V1ase1p_?9VSD;?EB=d(q4>0_$||zSGuZj`lK?(2sCz)spO#t0(w0H8I+*k7H0oX8&&uK=&t}bP=uN}sizaAFXeLPmV -Ak6TxI|;djOA$!JPjj*Q)MPVFOz)iY5h%6u~~UpWdC64cbuFn5qVQw7bS4BYFCa!v7Dc?%GcC>ag*d( -x&{?nz)8MjNWzTQ6_7WB#qu0F7VN#==aU$zT&7E8{5XaQ3iD|iPc -R*T%!wN7EP6qoe6_$ui*?Z)sX^c@->c7*>=JC^Del2ZWavW_zAFO$dH3#@a9|aOKYdjKsxW!F9lzM09y~vWa*-nbNbnWX`w%7>{?#76&XWeEXgK5?p -nbyQRFW$ueeHn%kFN=Dy^~TH|3m-79bDt$KDd;dDVU!k>GTJILKzKs98uNApU&&>2KZ{ -F?OT2)IX_dI -CEL1wJS-6R2o__JaZ*X2FupGkwd_>w`vW7N%-O6hY=LqGlXH5UjW{s>Mhf0)h$IA;q72pb#QD^!AmiZ -#dwb9d=WL0Ah;0`vi`{-(aXj0h$#YJ|VHoON&rBiQcW8+}imFNw)3WAmrXriD{ZEkOUxdRpz=vf(<4w^J3d!-fBK{=Z(QOzuiO -VCrYf>e{MR^=QA`^79@rVO9Xp#Z%Fd~y~D3kDRMyu3w)2J|xg0tFFFgt`>ykpnX0o@Wh|z(BUw -C_mkTg7Ft$YBNutho1pGwK*~ZwHo^0j84G%aFNZ;J@zuyu3vlvv3Y$2{VnqHdj|(Cx;1N}f$?y>TmTh -Wq^VAx0-$M8n4xo -@Qq*8VfNb7Mz_DK%>8Hp!S>(4Hf4Y5la>sGka4jI^o%c=-8BJp=D@6_9N)oW?ztv7MjQzUiN16Gfq;^ -)XEVCaVf4ZvoQ+>}`wBq>=A)a?N6%Nl!{O#;Y2{?-QOzkG|i;wf+ofVwy945fOP>gsG;Y^_&a+!a -Z|PB3;wQ3vYM^759J7I!+g%_MvisFZBfmvdk)iR){uO_f(o^iEm%QxD!KF!RxH|E+>}HB)WB6z$J~Pu -U9-D-7zlTQPJ5&je~e@i1$NB&4}@upAf%nHd=TV0sg~U_dXeNcxlZsI)<?uFKC)1BdIpU2=J4CYSKl83PaT#88(3(8Ip1W3jt{myP8LW&q{u+xv?yUQKF^sP4MLEn)sWAUA!m -B}BUpG#a`KskvI(eHFj61@!#ZfHI~3w1l7Wc@SA$K89JolT1}$;GT6)z)(*{)>^afb?Lb9=DL()=&IO -B^>k1X1B-j6FbFK<{x5C&#p?gtvD?0k6{f$YbEDcIXvK?%KKI;y(4Eu)WK|k3+8r -rvFsE)-8!SDFK|;L_?@=$`r&SAaLsPMT5=&uEP(p&()P513c16(F4k8KMPuDIy~<(7Web2pjdWbZ3)z -lBd|6~a0ioqGS@RwWs@3s!ye(ae&Y>sH=&skge`ufqn*_T(qR9)a^&_;vCLA;Gyz~LnG(x#MH{1yVXzTz40h-}X{YoBm -$%k3{`8ZN0F}N^5H><3{@w|arm3hJei=$#7;7sWq{9D^904#^&-b70olJGVVaI3F^m0mmBi$)|ndGq>Us?$wxpL>0 -#2h*3+!;@pli;?D@IU*79$1nB|rpJ3PEZ0qV`s3c{Z^` -H%TcbaW&ptCeG`Mw68{i=AlnIXyhEii1BD+&;0Y2U(6IiqEkGKH9iJoQ{1OO77wuEt7(IO!CJ*CLlzc -3)uS^&oOP|A`dkgrD2?_|MuU+1k$ATt3NlKBNp&GQmkCD16srA~+~~0UE&&0jFNnDl@!Z4t3YH!t -#BObfM!<-1|eX~0`8~_36hF+Ex>(!SdYR{I1YlnG|jNn3GV4aJ35?t0o7{hAeG4QXo=vQ!5A^KX+nHA -P-8i+m*)|*Go&|~-ltqVuCkKoQu2iXGSWC43{1KGs2+h<89WNiK{uiy4%lTfyOX*{#5qo50Swm3sZ6V -8mgp&{Sk97~sgYNaG)j%Kf@f$cFH#jm6D7;09HrzyV(DNUpr$iR#PSacev=eUmNY_zA#7=YT6Y9!O-X -gR#MqxYh{*HYI#@=*W6+ka9uKKLekHX;53IZ@WrmPM3OEJF{82^8g}8g%mN`Kur;XVgvZr{^tEpafD>IGE6#mMrrI*Iqd)BnRTG$ -eK8gYL;INi4wc$i5do?)8dx^%YQk1>m145P&5--UawOGtY9i|XCSJUp!$;UEBI3|vGpHPe$l-y6kY=i -^-uN}=PLU!%a=8bk#1XJ$HuX6F~WNO(Rw8Ucxn)#{@ -_B1t1Gs3A^9rR?e&^{E4qs9?j9WLg17>XI!(xI2=fmrMq3D85oy}7rHbQk~bzUSp#>?7|@L& -Lz8v)N*9n)osjz&21?x97w4ea#uyHleGqtc7(Tn;gJR1Kx#_01G3*@@NhC+;8rO;5;U>GBIf`9Dm0bg -n8;B(m&>r-%t-&m69NkSLgi~u?@tL#NaP^uw=Fg^71zxKFN%aD4YC_dmz7|!v03N@K$Oh0~4g(ZW#v` -M@SRUgSwb?<7W^!Sf2l#oAiGZK|3kCK5CW1bcP7{Zy%wu)VhMeZgNIq-(WAr<#jpfB2WN2L5J8Z|Cls -F7xZB;|iz6?~?7R;JJ>G&)RMCTv_vR-r_+-55=^fpO#X_hLprkf8bX-VcVUMv7h9 -sxfFjx8by9z+2e%1p%R?uxM6-et_zk``L&i;N67tH#A*Jj=_PnaWKILRU2&(qXRpn_ZsQm(b@Id;y(7!YM}CB>+59<<=tHR~XuJAuf%z@ho|=}xn!JhX#;kLv~KZBaM`yPR -mM!UA~lvo0*93=&>qIjSwx9Sa*LlyF-hX*`q>EJM&8&9|WoZI4?*&^D*k0X&3oc3@!gBL=>I@#UA&rO -rfZ1BH;3=^cj58&Ub%2I>${)IlXTNtP$)xz=9-(T@Kjxx%x@N;n?QDR)C@N+(Xe0`f#m$fAtj&-4}D| -09<&?^jVfU(cG{r;Zdy{E~>ff?q_R}8e3tfUYN@&Ug`cd+ohz28CeM?&EH?eE{?e(C%7h`?2uYTj2Ub -w`fRye!ca0%Nr@F?y^q>3#{m`*FU|gai<`T& -YNsV`lY{)6U74lZLBq&=RhYcVfU3JxVqOa}_!_HpWAHjdnO{6&h~tNG#I^Z)Ks6s}QKeNWus -tm+~Sa42XUf$W8tfX-aAn^qqHCxV@O=zgoa>S^isK1#~n-1PEp_vP4JHP|PLvlS+-TOyrVAoL++QPp{ -AVJtG7adaMBVK)kU@!Y4ovL@`6Uv9f;9!pYq4LIozl@cgPIbEY7*%Vxsy{cLfgV^QRGnJH%)E-Pw7dV -uU^_KioF@U5(wFbjr3gj&FmM}ZFp4o>b?(G##;1eDtS>CG66E+Qd+m0Z<~5liv+tTqbbnZ>1%%e&a=` -9G!a_~rh+GlpDf^;tbFQ0%2I$|{n1<=^ie9qu1~ZR4=up#r)CUOJ!b^-gUewMp%fwzt&P>=dm#ktVHK -)^DDgY~WEVa7UcYu3JM)EPuG}kax?gE@8_Yd7xQLWn)?mSQXt!ru$J_}K` --oZ7+d?ND}}yWqHfOfLo-E3$+1Q3KJ^*?{L{d9nZY<&_E!mXghzn`#cO6+UuN? -*1ca4vS7}XFG!W@~Jszyyot@jp#l;&jfR90rJOov6SYx<`RVkX2Nl*aTVaoQH$rz}bVC*}c -{nLi>t!xRKf~AUP?dkTJ?UxXgsaUPgA#;TK{3G`mr2FeZI{RqqURzL)IItRTr#dMDVzOh4v&QL1dq(; -~c47J#GmMIwL(@sojM2*F5b!x|n~|2z_d9h*ZczrPFQHofoeby$&11piHq(dr;5LJ|Z{G&>6$WxE<%Y -GfX^}vke0{eVgI*@kltwLazRxfaiv?%?p`|j)XkqRlvX2KCP$rN%KIr^Tp8C=mZi1l+Imh@4ge0qC4S -PWmbSq#G?wyrz48m)4|AFFwRqgCOSURmQJp-3>>z=Z$K2G*pm -trD9gzQl;#=YU3K}4wHmbv`+ytT9)V&xbUQTQzDu#d6ouCxP8=LgJ&j_y~xHJz3E{%@nSn>n+NH$27G -WB@L6hU5|fqdn)Tx>3}zZien257yJaB3t2Jui7d-`@XIJy2fR!u4{aigVw1C;m25LF5CS$3c_^qgnQ! -;f3&03uUkt-mveFBdpux507kUAvi+#uz!*HkZEG<6stJS>qAAg#DwiqT{t(6cVpPQLS0cl64VUH%EuC -MT+{G1Bkc=QBmNnluS{9hJIV&qRqHwNRf_sI{oxTZ)OE(?nb`f0NEnv|b&9e^xhRR0Sn2m!g5P>m@K) -tY%iv!ISN;x;=-whU+HF~cE8lOvb-K{JcQhT3mEJJ#sz~vFS4p|UOt;wg+lcdsyH|W&tu?X;kPGO3nm -+3z4*hZ~Mnb0e(xMh|5wu`WHa+vqBZIRS~CXpPnIhM`*e@Hx2HHepc -!L_XGOSJyknUo+b>-g1i5Hp!nX70ytO)VhrrPaCKNltp4dy9ngP&rnqk|D`H9|iQ}<69h5gaCfCNw#h -Qwmi8L>#CwtHLPWC8M=Wy>OW@v?rI}C>$<4LXIr=NWP&2)MYI}55qmqgKn>DPPDesGtS4@1{UoZZ|V{ -^dls(2Ud_v9y@S=fXNyQ?5?*AIGl_g|eXP)7g|Nr -s;_>M0v3xlA%fE#vK*#$ERu=>3A+=ca_|40gdq+QbS|0zrJ)CSk{r$%lPrI8kYhAwodU`lL+BH%`QalEg9w|Dp)i~kURJN@CfO{c|Ai0lvQS){AEp$sXspVuOP5uS%UJ1iW^0&1z>KYTuYE1 -Qa_0p(WB`Jr=x0A!w$K?Y$Ey5?fYU&j2P}ZKsM1MYgJq5%MpZ(CH& -JQTY3`4n~0?T6Niu!fF%<{DT>19WTobE+>{zv?WtO`8in?F3c0!%J4MD -rw3}R#Z!|qsB*@d`>%1onE5+{)nJ<+P=^4BDzXCWXdplH|mDx%8z@Bb?An==or_=ny~N$DtcyS3#n&v -imCSC4Fj)brD`=+_($_W{L>X=rCEW`We1N#-Dz+B5ciIVA_u-fjP$Sn -cz+(cmP(wv~;B?xhNW6Wjm$Mo9u<1ey#*;e&F(9Z)F>GLnuWpmV3xueCFlrN+_P)p(!)d4Ext;0gfwg0;8kN^ -IZaFI5|71SoL=8(sC%RY}sK?PF4Gk8@~hm{iAoMsTO5u5m&=)g`@*q0RaV8A__J5Z9Fnzs|uc9n|>s4 -qjN~j-@j;{H>7!EMFt__1DM_FgN_~TO)xmHjc>YU|W~VYR0%n5RVBq&%-9w%_f(vUb{{e*DHQ(RnlDR -af`h(HhrH9RU+w=XEy_?c0)FK -+|2+MXCkF;eJCZ^cso04Q`*j)U0m(Z<+EUHKthT{WvqyZ)BbPNONz`YiW$eoZ2Hde+M+ZC`rxV%%uUI -j|aSoI>lM?qZI6H}+paqwGRf!8?TngZH$f;JYHuG@-&5hEAA+sNBCSm}kxs$~W$biKenLyjkTYZx=$-=!E&39O9MC9=@KnfvTB3?eucq^Jl`Chzvw$Q4+`Ts?{u -pG#*N5ZdS!h)=Ok&e`r?k<&!Fz{dvm;vO&lV#7D43lSdW2C7|FvShP@DM<|yNKa{%3H3TgRFm22qS@IjZlJfb8W9M9oxC1zpGdJbeiD(3AUwPd>%L2GY9=q&Wki-pj -yVhk+JtXNtvS%@(4Jb~vQOjc^;IjNqALsUEj|*r8(kl=*L8Qtrg;x=B+s~Y#R;NYPHTp{BQar&r!LVm -F`G+D?LhH64nBe&qQH=$993<)*uN5AWmJsT`@rYL>+2>Y-`$-@c6jG_v2$W&9*Ky{U2*RR@_|6R47Ad ->IKe(6Tv=b=R>-1BWvW|B~Wdi6?nilXp -b`{5cfgDgG$aB9VN%F?NJ++eQZa9!r?G`RJR*RoEVnE;2#&6(_k)y<`O8__2KRTTs@JC)=?@fC8JGYV -`&%0m4XQ?4E!kr(jgR9{+|fJ&(uLy>odD6ebw-)^F& -`^Xxr2DWk7S(~Bu8eYl|=SHAuUKL09mx`Q_5F~$ToD^n} -Kd`VCV~m-KC_iVQDY}cw~B?zLa$EwBqL;8aKCIyqp#%m(Nq1Uv(l=nN7+JYkAc;5LO+NwJQ9lZg1jAd -oN=T42Q5QU76Yg%-tgI+H#Znyrji-V7XK8W!zBp>+U-~q^AY>(gDfSYfbcD-|~liDbjA8H&ik@>I-{u -8isaCIYBTFji>fn$0fFVeXF&}gQB8HY1wfqZiq61qg)|mQCMT>Q{1U(1xXDo`CNjOEv`NH14H*pIfOJ -jkV@sX-O~;+Pk#=zm?%-{qk|NNYlnDSKG9|>&wViOFqx~nqpTNBX&@7b_Fli{w@5j%Jj6)_+KYBVxA% -#)udRKCuH#-!sQ~~ukkdXoyrzdeUZXQVGncC7iS)2krxpPVbx1Cc&22Jt -A=OVy|BTi&9uLU?cv(8*paDo84z{%#AGbCO8h~qp_AWrEet>?$Q~nG3lhKP#G70yVo{I)337+fOC=Cx -xA{&R>l<)S4zXn;V4(!Xr=mH43!AvWV&VFEr!_9$plp1??l4Y6PuSSDdE@~Zvg}uCutg058D?}9+l9a -6GSeA6^NLy1f_R_jYstcs>Jl5zk%Xrm3L-MFOG={?hX(+#kFP7j=TnRe!K;WzE9~pOug|N8xVB}AYkjvEOF>`bXOt(Sck+K!798<*%so&3r2$DXYEY?t5n)sktxsU>m9);dLVQ1|0cuLL53M41}i -LL{U+A*`EbSSxo72zKBvS+ZD9bWyRv8o@E -(v@DM~Y?wRdQdObrp1u3d+*Ws}8piW7H`ehc{MHVtat}h4D?7_ovcjDj5frp*avPLYzxC7aM+3%>*7X -ojvhhe8X_HUB>Ho5EGrimZ20ASIeEi@gDZ&TT^f6VLi?PX&-mtJ^ARpCU1++`fgEuKclYx-jx73iM>- -6Nn=-OdHIX*~x03Y5kO>_ZN1Jyx$UM1xyeyqd9f8T>+TJfm-7uUFKTKB#X6$a+p*(GPYl#F>s^RFwSu -Tg_}~FF4l2f2cT=mfncYI@%uTLZL+c=en%62k@h`9Nn?0&YV|aN&g8@O9KQH0000807zB_Qxb&k&&Ue -^0IDkh03ZMW0B~t=FJE?LZe(wAFJx(RbZlv2FLGsbZ*_8GWpgfYd97OiZ`-;N|2;td2d=?`B#8%`r8M_vOy?guW_517Bas5y;o~P{9hxea8zJ2-m(}$1O -_%J31S5>iPNwV72yGkSpliRYWYG^`2heVReT2wq!rzfW;=G8(fv8QqA5ztsT)ci*iV_21-=k$Kv*gQ-NRzTEN>SDO30sRgp@+$WD=}fO@H^ -T@Zy}6V*6kQ1-_f%uNpil0XpB+r^n}zw@O_aB2A?ywtOT!NtnN1=XSoomNR4R5m0}--Dt6UUP+JlGKc -1eRpl&Kw5N?^vI!PiWveks4Usq_`%HT(?=sA;$nswf24?e@Y9N=&#m;w;wYs3w|D`W~PY9|x}p!^U&O -qmi5n9cxsKVHPXEo$Zp1}iRky@_uMnMZ!mqVWV9iAI&_*Ezi#jmNDewS#y^UdKTR`Ztc7?xHOUsSSiw -iK=-fOdzcJ2}4iZXgquNto`v;QG)1EA$_)j48Uh=h)3So`I~JEKhu&|eA~R6vQHpCrSY16v3`GH3xTo -JD2hAU=$F>SZ>(5RtJWrydFz?0TnWgo92Bdaz>#g;hvB6j!~=aj(|85TcRZ6O|3Qhf4X;uLFkfV1%ck -efQ0UgEF*n#Sra_zsBm7SRCByBOsY&GXG@h#VkI9mWB|riH(p7sl5 -vYAII`+QvYxfyyqc!8Eqez7m-ll=N~5V;<|;Ltk}cNnIqVtRnquY#{I3gZC7c)}VP3>6QX<= -ty4FjjU8?-)M{jSMdXaTYf7*LN#IsEs6&yz{)n>V^JsLm4Tl7rYBmi0tKe220>q29`+eW)c(sf#_^Dd+^!511QwHLCyw@Bm(LtsGXEH`LoNFdIu~cgu6|MtK7t2f -YEPA$j65r*ORih9g=Oy@U<{=Smegu>}aqg#;e7cZ(@UtO5zx(y$yXq#gh%C|Wai>!=A1#f3A=UJ$RCq -D(>(F79Np!*1~!e``FUxm?^ElTLL4gtJ<12g{~`qXQc%m2Ri3e}4}+RT~8y*aUO56NPnFEO@39%`3Id -wAWKCZBmAUX?D#kk0!R39%SwI~#~N;Bd%2>;V{aY?fF&Yv6j+B{x0pOSFo8l}Cv+w -TRjk3Cl``dtSQ|nJR|BetP~jDXEE> -h-emR0t4u1>!OTLc`zJeL*7#kj!4eIo^NOxJcLhHw1N`DF7W(C*v8^Xbq)0>^D+l21&aDxon3e<{>q|H3-*ut{qTC!uCgcH{p@OfCTu(Lm2Olc{FMUUo~3 -f4BbHpE$6)9u_YWME_}xvXykb^(Y0Yb)rQoj*kvg+1hdkH0|0Uswx%OqLaY~~ -Ka39YK`rJoN8T){ -853f0lJ%n>B5Nn$4PBM){gCH{GU-z(uo-gkK0w-E6PWHpDdeKD(4-Pa|C$a@)8Zr-RUs3IQZF+XQrN6 -J6M-l0c%_B@{o!G?AU)^-rsynz2NjNyLmO;1U3Pq<{j5=s(r`&#f9v|;m>!anygB6yjH0m_iOvQ)&H$ -VpsQt%q@*z~8ze#1l^v#humX|(F%jarRX>~~jKs9~z1EJ{YSe+P&iT6%~))pH@Cusd~)`-(vw%~pB}# -&tIIHG_11b6H5Jlwxo4q$hPPxvX)A5l*R(;DV5x!ejU{b}SaZ+&lYs}fWmD;5nIziKJYp;FOq -M`(WD!(8hkEx_E&iq8GlurSF43H7J0bq6KlvM8gAaaV3H1x!s=y8GVoG%mc-gsxTrpk1=Bup$F0s@vC(W5c?F%jYm!#e;n -+M4$gtUB%YeRJu}k)Q2Hzqh>X+rtV!3q==poTJ!8 -UPM9ToK`RoJ7`5Hb-H_w*&;+^ZTVAKEf_t<;Kl8fv;`()J$wpxK&+}=IRy4oM -&aIN-C&fTSMk10WiVeBnRzpkpHuk192X`ib@gZ1k`PoIv(saWjR(TIkTtvEzJowDyL_&3r$n|QD_yV( -Z^pwIGsQQbb#@>i&&uUneoqyqq*`itb{uQ&{?fv14vR~1cyv{7Q(pA;6Z -$CdYy@PRI2CBCX9{6pfajyp&>PWmq+R?(#s!zdejprr0Q{RQjzI?nW#igSSIX6t?v~H`fW3;gaw5LkU -l=Zrojj8N@TgN@eDWN8qJQogfp!%o;T-}TFJ+#Jrnxn*S2ZXqB(c$S;7$FoeK=kT81;DW>zoF#SVI?? -<2T(5dvv@ZJ~S3!5%`|edgv)if^Gkf?U}*$ZWmt`g;{Rt3834(KIzJAX$!OoEDHb@0B@u2zhg2pbjf8 -8_rgsIjnH>gQlAb*?VSzZ~9Iw8cN@P;etaw?OgVXM*qkwCBHxdQr~S0Ze9rlTHkkCC1`qJSr`dO`JGc$9+;+Rm?ta{9rbQEqw$+_u(%p8uPZ|i(CBO -Jz^z#$OfG(6JMl3N$QEq-G;C<4bEZ=1QY-O00;m`Rt8hkHF`V96aWARMF0RE0001RX>c!Jc4cm4 -Z*nhWX>)XJX<{#PV{&P5baO6nd9_^ca@$6d|L!Wk!W4 -H!ic)>!LGL=Oq~0`gf8om$0n*cP8qu1+TvfS(K4%er{ouCLKiCIu9jlZUNVecsXEmE_o!UJXMk#uz!v7 -vpC_^g9R5^Swvh^&n{wIcXhjzaZ=s!@wv;K7a@pZz?K}y-s2shE{p8|C3VN)CvdVFJbl92AN356N*T@ -)K45V=z2oU!9~Xi`0D+GyX#_C%oUZxPX&SEibV}oGMOOViYWa+ -!mxBczbfK8Fo`7>_VrWJFfen@?|8xz{CC_7#U#DUZh6sTWqcCh`p3ORmPD5 -ke*zl_z(wNRCo?%@Nx=Ex2a0VG7Xq9wPC47eas}652$(eZ1ZwQ*le5XY>znEM8~-EwBtHk=^ndYjCA -T{|Z$hVt+{}h0KBKreys)6}TzoEkKW9c9Ii!zP+!tcW!azOku=L>MUzm=KfhNt_@*S_Wkxb@&qoU-QL -aT7ESz{PGk6W|wY!x<3-y(P-vn@5m96biV9^WK>R77(!ceYnnH)Tk82Xcng<7{hv_d0Z%!i#!BFq&r_ -ol|7R}oPsrmbEMs~C_I)x2FwegIE -XbsBb^mh}(P`cdRs%<~56%UW)-@!kpea6bxgP#}1kAvS%>C!O@RfJmKWOWA19==Bj$4;1Ez#>oP`!f8 -jhQ`^l0yMOhXWxZyJ&Z6(b%{Q(OFjsUBJSO7a}!b6A=uw7ux{sMuTl>+>h#qt?!MQuw*g|sf>>`?-di -d~bdy#>=Q{A`BwszvsC+Hy{q8VU#{0#w6*v#8)9n7{HV@Rb1r#p32q-^2NQnuHKMK+a-(QA_Od!xZ -m$C#Y%M}TG_YO(Mq}FI%uAMuqt%3o5Qzlal%mER_TgGJ%+rBrQR^+e97Ys?Qt9fr>T4Jm3VwzmAQ71Wh0T@m|M8`*9yLKtNJ>|KJ -(n#r^{`LORs3cM)L7a-NzB!VPDUcZ@bfy2wFe;oN`OCksA!=DA9Wcn%5L<@IS%U~V?Kq%U0?s7kW}$a -YiM$9(TBj1!d)BWLVTc$RG21T;@NsyRwp#P?H$gZ8`+)B_Qc- -hYyebowS;O~+9`T`O3fN@@^9S@aiAk(9l(g1PA)u-$-Em`6uGm(L0+fRlsaYr_p@YKa$asu%>Ee`5Yz -d7G6fiXimaz(Kh(@uV!fsY!dP~6a&tVaQd@r(MzAQK`jbZW|r+JAbtA+~JxWLo1W44kqKOT)Xn@td>! -!lV1b3Xcybtov$9w89ON-@&w7#$=$UCLFLGaw}aq*lvdo&6RAY7MetInv*U5tfs}WP~tbB;$Ov4x`l$ -JHh=_Z~4z^jN*8QQe|b3u#F+&+?$vju#@?my&|z-w1usSLu6Cw65mk8K$Hu( --=l!(Q{u^XdAnIJ%%k+z -_WrtX#)nHKc_`ok&|(dX34)GsNW@dA4#Wov^k%quQ1`3pDhg2@aj1Zr!4qf^Y*}JAeQwO7L8&yKTVt* -$jR_QiLU)0!uoko^-XKu5AYZ78GbzJC5I~m6+Vwm1n>2P}YTL{~;vWqH96ohBurJult@((7k?lMZErK -0Iqgcn~?fCg$V0=ryowO)Qar)_wd~2YWL*7OfKF`-gPad=3epd@22tV>AUO6<;8>Y*vp8LLf8)m+x=Pr#dYl1yV?)J7a -{Yf?p6eaF*&hvGkQu!j6b2oWc6o3UJPhqtj+(7`IEg0pjWaP;!qfSn|;+H$#K$OXcVdI -jkBOP<0ENwTE{4gs9;RKybS(!eALKxm8OQ%?d!*@U1PcGlE<2Y|DXe1-6k^^pDVfBz@*YcLp^^v+LiC -Kv4W$<^fM -=@{XFUl9Ym1M;)2Nw1cXV0gB37s6giJ1{L1L68V+Q<agJemo -MEiBHY6@j-Dx~N{8lG2}131>bop-j;hti;21R=pqWbJqQ*2-Yf9EGYe7g$qYHHu3@t(!3ab7VgvQ$BM*sK$fz6ckpCeKr%xhPPl05 -x+=Q!N4dEr=K;v8r}?!w<)2^kfau3@BhrydGaB$?j(!6W1)LgV>2RY_zkSD)ia8;;t;wl%LLd@~}XoR -w0;@BRr_73OHI_bmj}jDC5LZfkZe!Q -x9eFt+Cr&t^$#Oa^JAR4Ybv@Fpif@|umADI=dYuQC+QZk8uC?*CJ-@OjW4EzP(an#r -shVi0fu~Lxbrmd4}anizZ%*t$(n~lB48;7!x-19(en}z8L(Q_S`jmBdQ#_jdITuaWDXp+K545q2>Ue7 -IUs2s#Xu~0u9l{M?B0Z{Oj3JYU1HS_x_M;f3$Ux{5iL?C>+aLW>Ty*SG3&-x=W|pnmg-z?+f^2F1xX% -MUGzQKI_K#w5IsPqbzCGQ?8AUZsunljxlc$@x1jlI@PHv11hu~{Iym@k5s;0+V83o@31HE-VL9{s7U$ -D>C`06%X2BHl4nv>Ik)xk_!Osm2bjwAf!1P#U -c!pnvsrk95f*-g+-xuoh;bvN!tUOo8F#EOu -Vd$ZHWUn&tqiX16HvB#oQuvC_E?dA4JW%j8m|``y7V1SN)#-(jzyf5!u%Bj!T_GLXf@xEk}MOPJTl_IfDh8#n#qF>FN*_yLMNUk?u-^O{4S|^(L19S -1K~N?bhSxjX$z~b{?am?GLY8?Dr$<{gtVUGL$wEy_Wy=;RBiB_~?jBZXEGeX-(dl$5zic~)W=M6)?P^ -YIRceu6$UQdu&r<7gW(|;5X(x`&5?YC4D`m8d6kB9%BW*op@*d8=l$1=nEt{1J+Hl?MVm04z(M+4Z^j -Os2%D>yBsvNaxGqtv`Dw?Mp+k~nmSK--Ff{kv}5kpQW^iVLr%!e`?LVCmdbxzfH0~f{!`)J{WPFz&en -0lE4E16Xxz}%~zC5M+@|Z2C`wxG($*X3f8U09vS#+BQe%7Iku$9DmfhM4-vwXS;Es`q% --Thy=?bD|7#d8l`8R=bZ1NG!@Zyi(*%Gg21F`7Zpq&r4U89&h^vQ6c3@f{|_Wr4e78#Z6=5se6NZb7> -AUIbOagxq`y+Roi`o*#%nsv7NyK@{TCg#_U-JQ%{AS?d{%cIAgKzP6k4%lf^bEr#_`W!eg$DKFD@j@S_Rqd6tSkB7mmP_i -cyu&x41A%Wsk90F#MR?R|wund%&_VecvZIwtiocBxEeRVa3->(l-Sh}-G)ofR9Xg@#-%cE-YCHLHL -*eXj#uxL19mB}F+)?apPk1-Ch=@qO);+D*$j&M0102;gXFE1J*ro}#`+y?-=WnH@VcA*YCU0SttfOgf -(q*E^xmt+11#JDt!BL=xEOgq}4cfj%x#gAUkLIZNV*om@@WBBP#ZGdsWx -w#o|3*Wq^OtyXg}zNS~V6j+@#$C#V1ZKB7jbHJXbZVb|W+aU~eawJ36{Ql(E?)nGd>In~W)^4H@>tCOu^jNGO -T%#mog3n@!J^E0qaX{T0$Yqqo#sZ&+aY9}QKK_iV^T+P&QRL_0Z>Z=1QY-O00;m`Rt8hBfYt(+xc~qFdI10%0001R -X>c!Jc4cm4Z*nhWX>)XJX<{#QGcqn^cxCLpe|!|x)i^x+E14vl%mN99-w}eML5waaaS3irHbf=37_&= -+1g#L)EwvbC04sr{leL))tJrE=pQp4^v=6O)o`<&b!yn)-i`k&40TI(eHMUgmIy@RmNEQ+@?>Tp7Hwo -H4eZQa2`@a9YXm;-0d+x7u&pr2?d+#|@dH*)X#4wB*{#2D=_A}Z)C-cAm>w&+lX|H85ucWQuyawUXyhk3*E4!yE?>paJwR%owW_rF}#@62*UEk69%bAJ4< -v+h|<`H;)P?1Oz`>77JuVA#ko7REr+6HlhoK#_OrpaJmcY^Hz+n|vl8^j~4Nfmwio2Mo- -M?r%V9$iTFwK{L)V%;bN9dpBnoJx0*ZWrlwYKZjqvk%#BR6MBQNujbJ(dC;mk4XYmHAB1t8t@nKn{QY -S(9MtQaqk%DpZ^4WPtxVQ%C0uAu!@7otAWZuTeP-^3XYSYFoO2phulX(jewL--fR^X~8r&WKxQGA$zy -Fhe)$-Zqvu2iIcC<_{VeD^7u0gSpWdv8yWpk^7H5eG|S5==1Ji>?c;wBFRS&E0VwFI|sL3#;8{2auEo -NjU;0~4)&gPOziI2pNe(Ecv@4os~h5v?ZkKdWhAbWOkXBx)MKnl@rhOroYkIp0u|DN&PL$$IT-uzb+X -9khhzlrZk4q}fJu1Va3zS20RXbFhL@jt46YvWqPU2g?cvmG|Z7%33TzJUiRt_5Bp;47vvGs_y{@6e2Y -aN{v0_5vay~#1ZA54f|dIh^1tjs;YjYR}}`yxkx(%6_e!Z!9u1@fsC% -6nw51&v~jh1{Bu-+wf9Lvocs+)zorIgVv5J-D=yJU&jZOGHHQVdf)u`7dCco$GLRB_-9Qa)l0QkqB1Q -1?l&-QJL&BXwSKR%k4Iq&cl)Mo|xd``5x_quZZWrREfBn6ZkR@@;Dc3lyrrsQGfC=Wa4?P*t0^=C>ky -DMakjoV=FP3ORlADVzec+Fw@ZfyB99H@Uf%qEX`WXUX#x0GPi|J?VzTRiqclB5KZGMzg&F*`Uk|TB47 -9q$Tn+@h4hhua>xmyrv~?qlw?s5)Hl&$2pm3S^f%K!_}NJs0)B|F~@AT*9+w4^{PBHO3krBnj&{eD*z8_z`_TRAyckp#dcO6h`kH#hZn!qHy6t!53)Fa10mpZRX(>B8Qm?=mf#b)+`d%ta4uFb -4$Cgl%jOfLQ004;Ha(SMz$!+KkORT95PWQ+DWBJiw=;4-KY`nqf(aLGdIB`aSYMPPe6A;S>j^w-57kR -4km@Bj0-aU$clnM&O_NkVv#j}ZoNmC)+~nzt6!Z0>W4dq+WDyrmui~B!`It;>)nkyVl><#{H;NG>G|< -oaDl)Ox-%d@e6VvL&C#Fv4a}xyspY+iJ3Tg3HXdL$G8f@XhL<@6i$qMc0b&1Ffs78YpK9^lqsSuW#y5 -;(!SeQC;QG|h2bIdTz_2T^LyxE_pSp3t)khx~5o7`$njA1lzBCe|0KxRsQaIH}pgVnvpeM5E99)#4G@ -BP<#Uj&53_aBY@hWbZF_@(USQ|$_7tYzyr;^~`eK) -HUd^RE&K|O#a-7FJgEY_Y`?cX~5inCtO>hrB>x;JIBS}mDnUx?JN=s9P&*?DE@Xg8sB6${w#82z?8&_ -(BwJDJy-PDiBb3_C}vs~?4mdJ7|&7#3C{s#D9pbPNe_DI|DNveQEanTB>*!rzm*!tc+Y<&?0^zF~m3H -D=%^>fRsyp#yZ=VqkAd>Fs=RPqQ0&Z2OH*maXeP4v;?fUhq;hhw>A>U5#NZ(AN*l;@xBCRR{Z5OoyUU -Y+na_95M7Qwj~5SGx5gf`Ky^X-RG@ste06aWULPy5iS%QIu@6EWZLRr1*F($%5g{uAB#(Y -P9zCRJzr0iJ7h|&w8UJRa!M=F)L{x@PQNk8-^6-I88$jeSiKZqhcAFEL}^&1RI2X5Hh6urI3Q(D6}c% -5u~Aq>u7PGBjr|5t?#RU1BpA;}V%J>-f|b>0vjI|_Q-L;Bsqu_G1YFMX3Dg0+J)3+05<-+256q9OhoC -*AJOL1bl}bh+f_)75Dq5(8kCPuyM2U-qoSEc#niB*)MmYkqVSSN9$RjPu;`~EFSC89=jUj)SMh8vV0n -4`yn*HOe@ZBc4&O}`(_NXKcxv%RC`55v?fS;2GL8PmR$SM^B1Qyu!IC3o{`p4Hvh2$NO!{v4*-`B*TF -k%A{nvA7lqg6@)sx(7CQb|8TF(4DrVqkf%m#eJ`Tkm+A9}6SF?PGCxd+Lj9Jh1KB2;iy^ag|LG0kzsy -9SuSb`OV}cqAF1f=unlrfs`Aq8g4$3K*k~Skw*bCJY;MhjwXutAP!kQ#BeoY?hJJP**xt0*oWS5S8m86R>wZ+T!dcM#1r9{F5*xfLsWh-{n>tuJTgiZxP}T;Y?JnB^=-rmvuc;m69EdDnrURk2n`CD -(#RETzchW`||gEJz$LL#AXpOP-vA<(MJ1&$-qpWQ!GRjZld}NtanD*=fc^km3%R84UqvZLpqti(EFY< -*2qm!}OU*rc6o>MhHl9KOk~T>}3RKv<6iE6A)svgOxp`P(^{hN8Fgr2qgudaQn;-F<#P;DaP;L0Mk2< -+t&kZxd&Hth|a+16dE0ZMNzG^@n!WOB-~!_=;0&Ed?aXYpUF*bxQ$^TtM;A>{Qove&)QlF*&sikjyWx -uvxD0Q|F;)}n;Hk1IzCmdjEfJhy}WX{j%%^l4MWR#gvWuNu&2$~5lZt{5&OhsPft$Jd#XGnS6Tx{_`e -jKgC1pF(W6f2Q75<0@U48f1iAvU -MTM#Hr-u0?=1gY};o=bUir5o8<^d^Pr>-lk6&7$l?K2xW;d-E3&*Y9|$9}ifn^2a5?`q%+yNg8cgeQ` -atnO$*v;bMF4X11Vn(9!6~`CHnN||D`6r>j~?9-^5AlwT?a*^?#JyZCB@O+m@2pL#1y|71ScmpYUhjP -s0RpB{br9e57S6=RD#7naamo&e*9G|TCwcFXvu06!+GK%bMwU};9#4+@DJ4igbg6P@}Y3tBAWwEAkfN -}#LuUNKTna(KtU?cI@)elcp`)~*drN6{E$^BUc`I2g@?v)5I6V(-y-z>e`QUd;KOG6M47Y_1VTP5k;4f& -gugG3Anf1dbo)DRszXDYO&7&;s{MT&z)u;2p_%WN?-~T?88<8ZgmBCTK`R7}O2^9J9qRH(@Q$IC_*U9Z5s_~OxT@o+i+`Wi%H=I{5QAwmISNNMf6#ENcrmD)Xdfr404s^$#;vjc`Mj}0wPmVH2f%__B+$4r-Bt)e}8N`PeVu72)xOch1MUTv>T -?oq77jm^2f29}?5RU`o1r$%lMu09Jog0``BJ;o%JW3k{9&f=__4U)MM&H -}=E=0OhFdZCD{T_A>mmS8-vnA9wt5eVQEZ7kcHek}5|q5GgpMWYBfT(Y3)SM;xxf4a))PaS!>^-9XNu -65W+h8lONWxXR#)7j#|c8dUN)Z -Shb31nriGL1$04q#L#ty?Bh(UWo*XRzw%sq-Vl7&XO*soPoEv30_c+wWB;ibvVB>Er60-U0i-cU^23k -6YA{iF`+TB{=?~Y9lwR}Xk;Ic=^uog{{Q)spwmy$d^na!_a#``H9W> -axli?RG6F@+A8ypCF;wD=y+xP7qFO3+M)=cGBkLuRi`c^2!M;USr|?}bDZ5KY` -6Mwu1R_{x_>u(}#HZ83pQf0s&*8GASYF)-!dqWS{ubdn1f77O*)m;bx~GM^Q%vTd2DqOBI`f#6FD4PSbU&WL)fc%~0R;FXu+|& -2*L5IKxj>LSdjn{U`^+WE6qIcJhMmgdt)K>VO~Ci$#o7Im -j;nj>zqs4+;q8%;EOkgqhm`_7K1t^~|?10%pcc!U=`$_ZZ+Ex&YkKHCPbt@0t{v;Tl|7mt=_6Dqv5rn -mPu6WGur?-^FPpvl?*d@sb-WaDaf2<3%gYjV5WO*>9-wkiS;b2>{ENBf@PRz`^mtqKt=G0$Z@i9GeLt -IaR)gmAeZ5DAo4%9Wp^*P9jNVQ&JK?n-=~orLXK}a}&_oF-PY*o7~fMTe@H%T}FtRyhO;&PXxGYV3oQ2e%+6UB+x -*EP*k89sID8)yz^trOQFF9Alvw2ls`zb%j5jDZaGg58$`In1ovw;Q-!&SYQsnNh2R5P+6xjP2<$snTS -l0Ri8!5Ve2XW=F4I*aFwl0YP(yBS)c-o8F9>N-R9j+CJJc4(g}Ob)ubHHPR`t68ebXFJaG9!F%;9cty -7jp?$hyERvJbt_{4(p^Ow7ogySoMt+vr_%I9;seP<3oHVP4LRJIdZ}#l5Vt)f5@X%4ssw8E-**oPO=NDnm=8rB|nFdG+((-&h_emz9HN##BE_|@#Z0fpCC2@&%cT^=((;XKFpP?Oa)S#Vn0$ZW -g(c2EVU*UHqx6xI|EWgZDQ%jy+TO2ptY!WSY43It-C}hCoS18q^^g>?ysN)2C3XCWO>N@Ah#JnQeSOj -YCPngc|Z^4)|!^k{2r$a{T?T&aE|$;wH4?j!8ZFPoiJ(>NAw8vZrGI59Zi?g1aa`q|3kOToI=YV -SMxy_7#uY@rAtO0V6SbZxx63#Cm -3`@*H4sF>cs^ci-j>>Jc1%`)g@#ePHZ>JDNxjLl>cC0Qi5e0jY=<|r4!N8o(|$|Dj~N(K`4<7YRmi(F -5&I4E-g(@=n5CoaN?a&c!A3#(50QE^RFsdq93S%^R*_54h~Qd--{>JJUuqajwX2RO -kljF9LKr7KX{ZDME|p1D9yf6?8kdX;S7R+vtVL=}B6^&T==-2q5ikBD8ELc!mGeez$$5t-RSwyjmgqz -w*49oDK^I;NsyUy?Ckr}pzYXz_o -P0WGse&EcUXJAZ~-8UMBlCfXUCXdgbLL$T!B2t}4Ws7Iuc`!T|AAU9z*fwDoXUW8FQaJugF!H-*=w*o -hh<}HI?G9#w5gYF{XjF93c?_UQ<>VqF;j_f)svvQhLdD^{{ynwS6@VlDGuG0W6HlAS+ehS9KF*1AcH>U@Gr<}##dAMmK6`z6M`mH&(LVRSJ>0?SajkKJmk -C|Qcal;9C{OoB93m~$K**SP4KFvFsLOf1qcUmz%&^@TCQA-7+8Q{Min7DHgFc`J;z;BwF2}Lcvb4uu) -E4tet1-c;1j#e5x4M8=h6$iixMF3KtTZPDF)SMPPMSbI(6M{{6MqZ2nAl3oQV+iBJvb6(tx0ZG -pj$B6xV?SPnA_EAAQgyFX9ha(m6cZjOi3{_1JoXXe5Aua#yn&w~#y9X+ktZ$5$#R{AO3n|$8uGdUaH? -e5Pl=U-1|{wFGy~4GL8B%%+mDoZL5k*DPC|6>@hz|6Rj0rau4S?Th3=3Tui~Em5pEJ~5lJ4`(ueGeWb -pS^@TDTj47#lH^0$|$~L%!oq&V|dOWHpUr&PnMgfJSvj=`1?hY#k(p1574L_k)&{e2>{R^VM2gxSH_=|MW|s5 -j^@>a>YFgsu3pTq+(ct%rd1CnVy5YN#x%c!+jR=JpDO-cyxD$4F=lin)eJ6hn(E0t4A=4k9<}7H)W)S -~As_dfJify)=;Xir`U=Gb@H&Fno-zysBUmg5$t)J%QOMyT-_hn7%zDsi(xDk33n(Ri*4IUomyArdVX~ -1?ru$QUXKC_{$>d35dln`em=W}1SFy6OTRZBNsTB -;nBDy(v)RoZBl=1Ut{Y2#$6!bUe;{5D@9a>`{URHo@k7tr~-8}U@6b`aOyZU^1`<$`bHM8b{Npm}#uF -25Z2-%y0A_%)(kC<&Hd7UQ-JV}s>3H~H=yx=YQqJe$a+&fV=H+rGfFQ2H*LclSAAEwZ{jq2rx#ICuySyv{oUo{g}-P!k+A+Ayb747$8RKWQGwj*8O2EJbn$&&Ha!7( -R=YA}s#UwM+(!CuXwFf4$c_I3CIr0~k?xil3Sn_=;UiOeT;3*Z>Y5Vqxf4* -%+PG*%l4=*>#W%)K~O};G%e+AuD9xtVtn_PqTx7^Zd0-7~2QJn%MS3KzIS+x`MMdZq!RZ=DfYgXbG@8 -4>dCMwYvpIo}>Dz9Vh^RP^>oYL-68J$Z8pRnOpRi?beYPMH78<;72C2g{xW{j~>01B#oA9$NREZs9ty_@}6`@OeIbk`GoR!^8btPOgUa`Cc^ -#YSG4NmaiS}Z{LsE>sX**k~@dRHy`a@Dm~b*&B092V;P{S*eeAsP4MsZyjGiecsJ)W;^PkL9Y5%_2EE;2|?p?eSL0 -U*Me^`*C}pT~&`Qr<%+c@;NySj8k2WQVpaYfpk^<49`bBUO#iM&$GbEEF}m3gJG!lUM;W5XYXCA^7+| -h&yZd|%Oo`$5Bd3A)KofG>-T6jk?DU0uuz_(hbpif8B5=t@cw{35D5pQQ+M=? -Rjt0FJYz|}4l=J>c^dA8pum9tXHGO0XQDmN>c^6k=QR$3_4N^*(WIO-xay ->2D|f?WMn6^mjk~JpsRDA= -PdqVKwwmuK>!IJKJF}`dA$L$Mq2b*RwFiPDVVwpSGa;O4c{i)%&`F<(z0^|YF_Xl~9OU(~VxD)TFib3 -oewEw3R3$$+m+UEf6ZGd7SfW3`kHC>^XQ%qlk{RL9kxDc)c)NjGDE9khcs<2e2&xm6QC#CHB)ni7i9jpSJbep>%HFkzg6yskJ>;j -KD8p&zRUviGr^gU2v~n@EBS!#X`(Ni|oCkNPLfd!D^k4-^qK$xQ{Ov<7@a_&_uYv`)s0941{7K7Asu1 -M!3p!UXKRS*2XNhlTCEP7W+vuoEMX6@xWAX5vJ9Pn~igYT(RA(XKzYoUxiuXb`9oc4dx|;!P9UZ#z|p -TaV@vfz$0AC92)p8*D{j^1Wgpim$vs%n!~BU1% -C)JQ91<3iDPHswVx7YA!01h!3^UNRj%PQAyto;>FfmwOR(Un>=qz{J_?mLf*P<&uBG3MXP-jGj_w;!- -Ni`prLz<#d+;T2ihIfi-Dyi{0Uw@*mo{l-Ddq+ -1LlTCXTNc4WDJ#9G|cpH9-pfrq%RDD1NY{lLB --7NTQvB*G7fNwk*4Qixja4$G%0X=%T=2|KwdYdze_yM^#5tNclu1&1|xGx?h=f4RmWbVbp#zu6e&~g* -N*o_(S#hyhzcoJ)73S&X8;vP8n4nNC=l9`f)M--GVT2H_qx4Rqy%@E!-dlJt&~3GOX9_%%_*iJBB3>F -iEQl%aX_unW*{t6lk~ -e~4wrQuM;`tPo2Fgmtc`I0T?tzLxj>&_Cr_I*zr?!l6aI@{@mtTIB$uFU12<4Lt-g^@>wq+YyZO(gy{@{~S;PoIw<5-AWBJ{7U -OQ=4REu(hVyg)jaaA8<)R&!o}F4IeWxLgj>uC=yMvp}aK+R)n;`0^5p78sG&65Bh8sX>ewTSCG~7_RkbX$qO3J~z~jpl-CQBNJERwrLf_L+oXoEQw?Q(1lmP`@)2)aU06+D*uZBsEl!zYYujqUVwEv{VI!Y|QF#~z1+{KXL4+x(tv{my?C -YD#y&4)}y@6tWq2l5Cbu=tLhrhv=EKD|a2Jg=k2PSMtZ(5u+#THzer(}wkCTy_cYhG|^cdJb?wKGhK< -Nb#A#3tUU_mIZ%o*3>I&-x#jGtZ-v5#K@YsV`a!%kP#o41blp!3V_2`t!(d(6&f!Cr$v4_%q4m3Ahuw -dXNDSNjT$}M=!hI66oV6deod<8tHP)Lr5ijs)yXziMzQ7BrWpE6dJMt=!*b4>Xh&)SvUg~{N<`)8-TO -6Di|5O^Y|?&Mw*h3TK~|HFg0qyAhK#TXEziyzjly!>6ags1>(?UVeCkd-vWqoN*o###^N@R(>$E09LB -to!>7!@jGyn`3bYM&RSGWx -F>PWG&Oz+MSg%>U-+smtK|sS(vITF-g1~JM`FKbMiukg4BQ_)1I2v%NTDQj2Y=_(#zrYuL-yN=tt -5L5{TP}benG#e7xGRG7s&9KN3U;l;Nhz3?o3mKsk22OQ#i|wq~*lmUq8e(!3+7>OPjseIc$of;HQfsi -(7L?{fLHF0oH`PmpVi-@v?-I_*=gCJXGQEOVSr?n8n4OOB`aUdvGp^%k$`CA_`sxsNl4YHD3K!*4GZ} -;Ha;a6SVil9Lj@5aV#;Tq`R;Bz$(L5YyE^r^pUme5D{`fm|B4qp4;zXGC1*BGXt7K~mP6ny*G{IeQd8 -H4=oIHkG^)A*?YUWzJI23s>>B((q%ZRssxt4N>d=<}`U`ogX=U)3bj&`T-|sMg##oDr`7eo< -SZE@m-~vfdEzFi@8ZFEov%tR#+jjh)K|XN$OXPY0n~!C)4&D(j0aws}IGtJFudJ>Q`t?%0)YG^9$CMM%3nd$P1GY8)v3RoJA#E_e)8E7YMUcJi5)GTg=m>n^iymTw&po -6aNE6@L=GIG#-W>&NZg_!ag3Y_jmUsT0M-5!fr?fR@?+&i=HcjOj25F5r%?}Sz}Hb@j3!nN%`{@JM=o -^q^Rv9teB#Hc4r|~f5BU%fq}nNFVv4$Bt)89*>)K)5F36+>#CC%$ -;b(ojvF|URQB~jK3wT4L1IrcIX!(lWYzf_8x2ub!&DqlCwe3&hmRf21lXs&oA1(JG{{XJ?V_TyC$WKR -#5(|+>T8UuOtP#=Zx_k}Z<=KIVg0Q-N4S5|koJ5WsB$@}IIT5H9+5yGaq0obPuI4mh1Z}g?*ifB^J(T -0*FlOzf=vv~-Hlh~~vL=JxGe$bN&7(o8^D0K*2d%{YjEBUBs9}FjC*o#_S(Q?hG!L;vA=cgpH64X`^a -OzwlPxH5^iVpmk;y5P4(cL!F#*xI>aUPWFKxBNafK<*N9Ed0_O~O&mCx4Rextq3)!u%ly)Dq*p3>f&+ -FO(MR;Il*Xm1tT+bZpCMKKN&MpR)0po`@a3({sEnu&Nv2!g7{@xA1l_7OPuYNPZ%no>g?)wwsXfxI)k -K#dJXpxsj=3Yk -0ZDj{tl -d3w1^!z8=@9kbd{5lD0S@ArVviZo%+n-TEZwj(rF0n9ECv2TVKN4BJ(i2JP+rwdQyYY8>>;9-dJsF>W -!s!kk2yc8uO4`jP&RWRXg?4)Q{B8orzgpmZ0aKu}OL^98J$3QCgmav^;z8N?Jx&5UEt2vxn+dYMhf=H -;8Am(V~HC`2k%c(f3c~S<-qKDfq0sB-?(<@s5xK%r#i?X1#cE!Ul7_X1=N1P0bquKG^%Vp9`Y=DmLY9_Rv~UiErzq`uW32{p1q&8ux| -KrDV~7hO$<2;6nmq3Ol&th1Z%_D-(=CLk#M)`dRBgY->>o_?TiZKEkkD47r4d=w-XR)4@b^IhBhR7_vCaa&JW(PSKOO40#e -9Tw?_~>I0^jUH-U1tYC2}PC`6u?{1{9$Jk1lwG;U!onT*k}d0`~^zpt$3-2ZY+Z&)Fst+22SxlbzTeJ -I68^)_z9`@wA9!oer1NRW1!(~a`Q!1ElTD82VNGcw_-Lj4Wgt}^#iRuj7k(yRC`*m6uG+iEG(zCQ*w3 -DQsvrC<>jdB%qGA=bK{v-c&r;EyUxgrjtJKov+`Ng)xDJhbZ^rEx`zR}DS*b0^6>Ph(Z&eZMQN{*s{u -OjNDqmH96-qc(s{fXI)E#Bgv5X>62^L((bsawY4qz7-mBf+Xn__Y_nyM}cA}7BoY1NT>#z5aD7*yCE@Y2#N5Ol3)3J- -b!%#rMAFJHt4=ePGcftYR8xVOAo8^IJYlVK5PtQb)1qfV7cmnuvU -n8u{HJFkWpduzpw@;qu?6>mMnVnhd9DqiwT3dV#o{>YKk00NOXku@g}4 -EanTg4uJPM%w!i~hNRArx6Vauj1=I3^tu#lfBfRb=y-nf+CZ_3uX-(n-c1CL-{N|-Y<8EYR4w__o4;t -k-)^HrSq*leIUn(gw4cT!oz5%aH(S>vcUP|)9aJ8l3ZeV3!m=!VrW!)Nbi{*atvuScP9Jho&OEJyWjO -sD7lp?zZ+nCmJGrcbvEVm}_NpdZyS*hi$=!%;csjflCz^13{r{wck1VtO(g;MzptUIM?iMdI6ti9aa9 -5^Ld{C&%m^kAuqhIC@+f?FrexQIu&AbTzJCfjD8iIgHO6yrt#OK~b`V%#K{A;^BMP5f+VkCKjHQ9Nc- -OT_^bx7CLhRCLVMoYT|=*~;a0MGoK1N7JV!`>CdjM#1@O-2dZ?knH17*d-=0{PQ>M`lYmRSEiE;khR)n!)Ktb%7p8GLCwXCdK3^v@6rmp -IM(Y7&qxR!>NY#T0T*?*JzOcyOSX9jlW8CB}RY&?%K)N!asF4-2@e}~Y<3>G6Fr~RbwizUNEM2a&*g+ -WX9=>e-46P)R7=W=<#9$3D2)s#lohHBjP#Xz6>#M;4nvZE3tG(~d5YUpi;KCaPxDHGSnlJ1}9e6&S!D -^ux%}q{WD=bd=n?3+8zp^eO=2JjCUpgnNRq_-h4$nc1gMkE2F;3iUHt?BV^#dHgFVjYdHw9Yefm%BtQn+Ih)8Hfo*yLGo -1d{o`~SJ4OvPl18l)9Os1`Vi^Y8rGY8mrmhPl*BM8Ag9&h%G+xy$T~#4l5{MhfeWWGpJV#{HH(09fHH -@-U<*21<>xzZyKQL4kjwjobtF`B!7^?n;8EvRKKbe^tNt0Rd{tbqz1BXGEIWTOfx`?R9;AQ@Fp@v+5k -ThR$Q$tk>_^bxlUbawWMw+R{A9!NUiI~f`E=@@O+w63>zITYs0zGm(k(h(%|BJwxC1&lrx1V9mxpS#O{9 -tT~z9^sfpM!h}C=nAhCb~iguPRD_X$r`abmi{Z8y0k}_qwKwCG$IPY@undFtuM8B24R@qPOGVtT2I`b -}@roYQeSh0IZ$^wQBg`vf5hY`X60Tb)j^rr4?a@RinUN3JY3-=}N^k$;hlH*01n40P#xA~Dlms@eQ@N -z9pbRUbA7X~W~QkJ|Vw;+C}w8ZQf*gVBc9iGg-KVi79REiyWP%9Gq<8q}{yojD3E~4j$u-H9KJ{G=Yp -$;9M8|Bc!oX2PTja5}k$%j6MnQ;jHR{>qmgj(Aw*;ZB=54^{V9u}~=12u{2iW&!jp=o$h&;p)HNmQyC -xi;mH$KOxV{$vQoF3~PocZpofR}7+;3w(}GBgkpA1Jpf$*nuX?8t!0yoAC&)Zx$JEGOO!z)%C20tV*R -z=ff#llh6+e*Mg?pbkpejcvw_!{l2gikeaG{!YK5RIa+v#&j$_eYIp&W(-T}k1x_*sUB7fst3f=a)~w -W#)aEqje}BREg;aF71d46*W@-~H3x@G{?ogO%!;oWuLNw_utciub$p=RqJ$Ni3tWc&71dh#d2MBd`NmLZywx?t -9Sl|Y%{Bal3L#5A)Zd9yLj22+RBe-Mt?117ds?h8fwXBgt$jC12;(5A+#(-3Mx;ucBivw;Ti?X9fLIkg-JYSchyrVBGE=rssBk%DF?Kmp98fn -AgCXM&YvDRj#%r>b*P)SO;jYuRYR(`FJl!nJ+}#oS68_k&d!mujf&4VI;t`>DV_j~r -#DLB)(8CBMwVTov0r0PUM|Ii!^t>HCs;Hw|Eu?Fk{tyD}5WtR{+6PUo;Io?=)pY*Vc2lOD+E%HyE>5v -1Gaa=(petd*3ouTq=JDpMhv=;<8f^ynQfLr5y8C`PUaQKHQ?XN3A!}1wDrE5ETHdgN^2V@bFKGf%`8QgFY$IwX+f7Vw!iCnzu{hL>5!xK3?!g}+ -MZ(sS!ITkdoFAW -K|#{u@r6n|&_qVP_|J)g8r1-f(U%yI#UF73UCiXi)JqxYrZ8lLk&o@6l+!DQhd}$Eiq1>LqI4mX?j_j -#>D2EH5>X50cG-+Nl^D^3_dlYN<&;XQ6I3#*UTln~^S}3JE~}SJNGWlo6bxL1z)U%{y)5OLbme-aoKy -`sKuKqaULSanB3O%0(+Yw1CkSXF63_&g(|ne>F9iuG%c!K)%ZvsFg90oq_Cpj^Y5V+^I!8OK_Pk0ML_J6zy?46HuO#8wQ^lM!6lK=EuviF^QHsXN3WVAsFx(Af1e9V6NGUZm7h8(9b43~8810 -y>y~xXMfjD#zsru;~PgKCijakyE*YWrb$3+rYPLF1K8^Ng*e!rVI6AW^^QP3+$^R2OdfsI;Eml8UwEj -VO8XZ7ZV;dl&i>>(PZ6yQCbdqI!MUyR$YewRtIjw*0NQ^vTCG#DD{Kzax}@rmqc|*R(9Hk71C^2^wDt -XLF#>d9QhtVX&xb_LP%~`Dk#Ss57KVK7!PeGOVV%Gb_=6PcVDv@8be`U2iSF4q!3HeeM9`-KYm%#Dp9 -^K--IxGxY6Dp(nTUvs3dgql1(&N6(ydZ&3~hCHU#s2cF5kQEllrEaqI0 -;*-2ZkrNOQxZGMO~xzCYpvRGN7DA`#Sx~lXv8W7UZKA|^tXfl68d|T{=Pwf(NLD$@f$qwZpZg$;T;B~ -fSi9TIc`6G3$K9gzN}vXrQZ+Q9lUNeTbp^Fu5l@WT8I9_E1UED8Ee|i2eI -W2V&?w?4o6a12Lm~2)&1Kfyd}AKF1%qmWLtKHcqz)4pNKY;C}dReeNsxZ8^@hJeAHcrS?8)J6ir0?Lk -0p>*Hu!bw~FCw5&RK=xdf$;iP3%jTG1lIUM1nWmWZNCnE+CZGhWWieZYkJrtjNC?@w%4DUfq#$sq!b@ -0#?c2yM>x?R=V)IbU0+1SBk*c|(PGHi(birQ6S7|AjAlVp-HCPTRCQo^o^S}LQ#3%12E#0A$3m)K7Yp -=0+`BPa}_5!AuAH6tjRbUW%Yd$4D*xq7kJj4qbw#pcjrDGp+3v_Nu2fwYt_SuEvFzPjm>k1uPww1&@Z -y0n1{oMaRIp(a&P1aqtr#+T}mXi!CmEB0G9(SBR(g=9D{_AG?kObc!irZzocKx?XqQP10y%)1s~7T77 -o%^Ji@2%(}al?Jf{Ay#oM<@kJrYgvfT?{Y1-;8V~ns}^kJTCTz8GOlGR?r!fvdbpa7Z7_f{%+2jRGPnUx@?}C)xNbVp|si{<}7LAK`<8`=^5Pf)E?_jD%DrkMRms-&*OITmM1_RG8rq)+LI{ -EO&R#b3-mqEO4I+Pa;v|iS3+G}(l^H4)7?5<`=^>bzv#-CWebL`x3sQn2pWJ{Z6$?j}z? -s9Qeq)1s7Z(W|H9+7=DA1~fbVEZ!vs*)j)_7_PwMHKqG=+LV3}C -8RrVn}TAo;jJ6J^njtX6_%4}}z^+e1;lm@sP2(gQPd0m$Xr4CkpSJIk2 -+-tyg>OYk`G$T;1h3)DSly0)1`-nhqNdfo1i;rU -spxoWmQ>h}s#ur~Injq)3gQ~ATu&{j9tAc5)1+nDNK2{&kszFAPeo}*8%NEa>Slm%qX6cm?E&* -zkmkbm3ANBz)(CT|>`~@aSp5HLPL%+f7&yLVJT<4X^>>XsiPlt!9_n*ygf-P@@<ab?yBd(vU)hG=>;#kY8TLg3v>zY1zMt2m?_7VDI*t{-Ff$rA5zOFd{e27&?hQIt$Y9_ -Jb60>rj-DjrHfK%QG&YAtZI%HG(+JBupVWCRyekU-t9SqzC8LcGF9brHACvcJsQBq+YJH> -zG2r&6(C{nHwv -wkYo=BB!fd)(?-YNX-l?x)ZAI@DSQ8H*C!&^B7$Dn!j+Rw4u12OSe4DA2iUBPlew-ZKN?VTerL8m8aN -!#TXN^%OZz704qqb9D2~OtAbxvj~?_@T?UkChs0Dlu8{?7HzkuD&9T&-_dZ6o8b -K;5fY1}7AB^KpfJgst*1$ab>879#^Kiwz2rb-6UH)`JHOsHgV~m+XD@AF8L3R}<=KeRWbjUD{V_b$a9;ITf@iK2v-Gbk9`TWi_N -IrQ)^pg4O1Epu=+e7`4*smLufO15ksDHHr(>8i5mUzaB7sJH+2~0C5TMTRQQcrA2lPN~wuW?JIp&fZm -p^>ut~@xzQR7zCvv~sd@NzG|-a*za1F%)}VQApr*i@Ukhr1r};)8Z9qBXuKfw06;y9?>`&@#AMZo*3n -fhV-WV9x+x`bX#@FW<;@{`?T_sVwLd|4Zq6UQ09_mTsIkXR~cbw!}UZid-YD^cU186x|M00RkH)@(y! -fVALZg11>w4`n&)3UxDO5^sn6m~+qpA8dpon|ZTXxH4wi1AeJ2br3-^_Kh%ek^v6z{BYgn4#Vwx~U%v -s&7@GzBRX?ozE`_^VxI(-HSdc_E4V``$l-NczJ{ui(icPVzCW#(AQXiI-3Bss6aM}5p!a2x~KstC)JO -1VnI!o@1wd=*MRPELf4IGQqc$}7B?iyojI!9UcKC`5k4%8qkUMsJ;H~@=d9N8_?`Sx^kLx~_F-{!v=5 -5|)Q83GYlJbTi^D!FV!s;Uz2e_Sc&~Vh)w~zPZxJTci(8Cyg|Q$k412GLeMk3OK~rzmQj>lwV)rCGR+ -J|^Rum^ZR?JO!tSCr$teBqgSTTWmtf2O)GPP5_H{r3OQ#UFmZ^JCEiS?xF-3F!UCMtEmnNXV0?H{`OL -zfj{{(kslLHP)LiY_Y-jdWQ-samEe)_ny84-9*(I56z7B5;J0o*M15;^QlPRvcl5F?WFZW}g+*s2tg_ -v!E1In|KK_~0ig%}ta9V*g`G0jz&G`!%N(pI_FTRy>OOTK<(zD?oC@dcQToVTC8zSQtgJV5+8}ZKN97l^!chNskq#C}nE2+5 -ICuR$%$*Nh;Dbv**!V^<%j-E>{i4KE%__vA{hZ7Q7>T6x{9T*v#ra2|AiDYF;XWzthyJ_x^~+uUIswR -l5eh!AnJal$Q#Vu2w}7UMfnHUMlFIC%jY~(mhnr?vL_N;T@?~ZBKZp_-jI~N_wcE#d)vrP=O6az3S9R -h!J|#?V~(YEYjwyH#T7iyVFZ~2Cko}h!@R6#S?>+#9Mxr(5v2~2Eqt6%0mU#tZ7u6uJBNSpd&m~1aTR -Pc~PYbB={*8!1v*~%}>?>P7Ob(UX@bysua|#tMoKLZ9>JOPl};le+qmtG(HCZ`p&LtjH#`jwsfSUiB-h^kf?Aa^{2%N>oYk*Sy|(^&!1h`mn=XtHQKkWpvsu?r}J -qPzg2JN12$$^{G;zERx0!c#@g)2M9)?_^epPG&{3lX(jMV(>Tb`%b0={(b;|n?+~xJ92pK3TQLc9*U( -H=mkPXm`G0iHYsLrfS~pvxz8AMDUP280f^rZLsTar(4(-IiUE#K*5{C?hGA}kAl<6fzd-k2+cd9>PE? -KWlB?N*liWV@%~yQ0twS-&9n{&_72j-YH{Ok3Y&(KqZ0q3P;`ViN`@#i>lv}GjXkP6z*zk7e(#5)kk1 -&}Sf2(~7No&urQGZmiiJ>7(8U6xY-Ibr9;{teJK*!Dgmy^9({&J${E%eA3zdrZLL5wI8Z0oa0a2T}kW -qR7T611cLM?OzCd-Uh&=vN(wztrhskHssJALl|FWOONxmxTxA6g2#G%f)yok6+MoS5>JW;Z^wvU*b2q -$?uM9wxfd(QK$-Ww_jCnK^S0q*9SrAa}#E+Qs#Mx0rH^_=bG -R~13%qw^pf6VwDD*nUE=Y&N%ac}XUuoPY8ITk8NW;;yrt42$j^h2IunD8ID?5=nv!g*K;^Aoa(b7(zhcxr?clfhI&d51{H_t(C@=2P_D7^ -$BezjnuG~gx)WN=$1S6JR|JpXnN2OP6qgboRhx)f-6pq-2EB=OUldZcF+a@=bjrx8Ay^F_B-No_~)%7 -fqWmRpixAqU%ER>!&l8=8Vav7YoBSQ5{R1(9 -H*@O0`~fnMX-twuy`3Lc7{e6G-EqpR8?}_1JaTQKmidivRnYKXZZ7Ls-iGf -}i}x7y_aMG!6~BV-sql_hZ`Adx{H%JsM%uheNyQE>#h1DVmecFEwMhpN7IN%>imc{LlGWrQ4I(dJpfQ -?ew3QF?DF)Ozg)b|aQ3-av -osFab<@J>0)8{dHTZ|=+_Rx_yc4@XO@(!YZA)o2-XT?6+op1RBkpoC?oQ2mbDWxrTYVs3R9f3oRF}2Y -P!1J9buFj(o9Xwee%&;X$6J~P(u7|?N#^!DR0gLYbdzg|F{r#R$m7im(u9<9<@^%muQZ`kUp=9LF0Fw -!)nGqWiVpnCOPUt0;4flpufdy`)945Btif_a)BNdzS?*CX(X}vi13CeHI2MCNcI=(Ba^s3SphHK5bJ! -OcLB5){k%cDQy&#QW6gb5fa|c6i0G>hSRA`;dY)gUeX`NG3hkL4Ik_;Wh1PPE-Z7q*^P>Mg!r?wjz#2 -99<#j@zPGT6H12n*axHH`S~nEjN;TQmhp5Ge4T*Y!_yAGFKi^GmeVg*(L3q2~<3XuG6?y>*r3MsO2FcA&Y9A1+(w97-&NMxo_+X^!+0WQYn1lG^{YE -=v>Osu2pG7G4pF`;%@W8!ladn&$ZI$=UC7(H8e;rtg3M*q~Ai}5hckaY5h$yQ)h(k3e7x5ts+J(59lM -P{ek7mz~PaA!w-`dQvBAlz&?&`7kIQoUugZDtmiY;(nu*&V3V-_(?xZ9S|BT?V&{U@b)SPM0b5NEE%3 -t5RK&IJPMbJ?0aa*tGdy0vyls*OioM>T7cPCiYlJ<;w`ZAyC7b%NfKs8xfm({9qWNc$o~;NujA*^j#` -0hdkqzu0>hfT*hNe|!%NFe*BjTKGy-R0^M=29D++pg@o)3Yrf@83aP0VFtA;f)149i0Q3c+T*5KH@kJ -amYTf-F(0X^*~8RIOY0Ec#5Bc3_kVr%IcGQ^kafG?@9+2j-2-d(KKr@W-fQo@_T#L5)1@dsX7*wD#`( -BSUmVYiT~U6H6Q049Z&KuPoW&@%MMT?zqHO_E%{rV+cC_Qt;dSaUwfXBHxK@27&OBbI?n<~(M}uS;C3 -{9z<8H3@bWXnDit3oS0>%IL=93xK_n%_(nMIp8zY9xVFO}C7~{M$BZ6r*J919nBp%1kDaMK6|%$RaWrGm3dpz@eiUl?X-M -Zo5rt=ce%7Gb)9Dc?J{;mZPXb-a*=}~VokT6?(xKk*{v~@B_$YUz&{X`UCGpV -XrC$<%0k?ZN;?L+`6k5VPTNT!946wD5{SDP^Hu~9okPFnOa!O_o}kq7sE@!$(&fE(n|9lSsmgS=K1(bYFf$R+DH -g@OKH{CO;mvKCT~kl$e)U&;1NGWpff=>;s&qXNIiY?ZYLEQYG@$ul&0mF@gcFJsdeQz5Ddn%A8+Ra7u -aiG6jpy!&*+|?&1>|AN%koI1^z*+}z7sWFv3HifdYZ()P)I$t1oAAPBCO)#DC`l2W8p{OI_iKrspyjKC_K` -|-odqN?L_!|94>#ySZUiXPUjDoI({p{lFO!xQJnG*qWs@S6Ma+M@Kfk#H@c#Z_uggqY8CHS?b#~IkC? -FcE>ndqauk@$b{k2OWb_(^duGI&hy12zLdw)L`>i{puIZ}%X{dSwmkbFmXiaV&)q476O5-(_ysU$2N5 -aGGEIef_eOf+SEjotY6{FCuW#uBHL@#l_slr&gQ2D}om+`?IvBK<8KvP+LL9nCN%UC)MOV95`T?^sS# -*$lcFv?gu4(pLor}#DOu~pp!1ppq&$y5|)hl&N9Hrs9cl7+)pLzORXOqIrxl~|?pEQ>mYay+(QDK%qB -fjE)uVap=EFqUFTXi4Fzvv0r8>{CFs_*zCmaKAX9(M%0~>pr}{ui$*61eWA8%Ya(+S^c;!i@3vt?Ot5S%tQ6SRZH95)DQf*;ap6_A%wX>+dh@P`C7)1LBFeG!#fE?eJ;`FxlPqvITeUCA@CWz&gz&UVd}Zy -3FUiT+*9Xox`e9%ciB5gZJtnj`G2kz3ouiu?%wCz6vYsW}^nzu}={eypMD(H`_jR7S?IM+XD} -}c1qK0m79%EXthJRsNdX0LLiMOVNVD>QIvmJ;VD~CSm6n|WZjnsEA-S;yrur?K%vS*dkc=#lWV^g6v{ -*NLdgOIasw8HIvKa=pzyYBy2-_hr-Eb&jx&b(3v+5iK1guij^ngQROYZ{;Ql`8c2P9Yb2o|b8X)fUlYJ6| -k3np%nFA}N9+zk!(5ctkY3|sOFQE~)^ZCceFg8O -?wDEl`cZjQEqU%C-OZJ80J{CV$LeNB4Lf}NHBl@TvhU>0l!6h@1fqs({sG!X28{aKMT}7Z?E*lCJgu7 -*Ms|>e|a4ZV!&u!i&TVVf!0cArAT)vx~ae=;A@VoAY}yA5b7)G8Otgp{Yb#Q -Tzkdf;I9b4~DdP4o?$V6b}$(kc@tyj?SZ#N{@M#f7}?HaH{n&ii~PPe_8@#O^-5;1F -g~(@6j)~$>qH~Zq$Wk23I -@fQ_OZ$grhDbB}l(iDqm#Sc8@a^)+{=hPIXir;25jFwxF%69Tt+EI)}GMbzA7kq6kl!gvv*C$6-T(a` -{(s2Pi -;l{k3)C1c-CO+HwZ)zX9W^{;yQ6|+ZJln3O>%|TQOr9^PT2xqB$1TaIzX*0w|P|WFAL|$CAgxpEc}|= -cGYdGQ*7>C5&7mFnoV~Ko8f2k3%wQEfej?JdEts;Lr6Jh3(8)`H}l0_M%a{&_FLsZ-p1G4Q7EnUU}!$ -ui;6P7?wue(&!srbP>4;CWsqVVmvxK#gvI+U3JCc)Yz7Ta+b2>5Pe{sY#q;#?Cv&Cc6q*`gyq`%#u?B -?B)KTwSj2FtxSduP!IkAgTbuWgfHjk*^^=Xm8Dws+1a3ZI2e6&YNXXzT|W-J|ny|T9yZBzA|4WG)J4f -U;0=xeKyjuhau28|T)H7+MUO2n=7eJ~eou)(sY(w(9~XpO?1uJz+X61vMa<@O+|6x_1q8}jj`bFL%kA -<3+9RbEOX_ua0YFg*`dk0bkZa=~X$6y{LXp<{=BICP}V9{Yt$=Up`vsw0J<&h*lEo`oFZ(+=B!N*M~8o{x*ZzwAX& -ov4^|12UkR!wioKm&M1GH!iUWWw6_t<#V)hn85QUnHdL&1gv|&_Or&w2Y60w|{{Y=8)kmPL-K>UYAz0 -9zNY0BRWVP{^NT#*kSr$3kFbY%T`5mOzU0FOvgZywHZ>pGovy|{YVP0ptV$0a&1I!(}4Aor{q_qW&k(YNTDBx&ruca(%G`Uba>Xn!nHY32U -PfV=#=Jo)gNuf455tMbpQWa5T7~01M-4a36Zjq9 -bZoQ0_Ae|Pc>I0i%?+Ft$V-grea6vaM7j&!Vf&g$qN5KVt^<2;mTtF;ji3IopBe|D|t;6)=?`8D^ -L_xqhhKS9Y(jNiYZA^Q98#HEBkt>3sNaCNH+=7S86RxKgmOw9i?CJ!CZmA^b^eCQnh#ukiHdWpr}S(5 -F{NIW`Aj~Fb7MO!W=5SEzEAxW?_a(F9~y`wBdeWXyyfGX^n7-lvW8dT3RN|IH_2e3DN>#PLlG3IYr74 -=5%S6FlR|qgqbEK2s1;97G}0&7G|ClDomR+SeOf>AYm?&0u&Tp$9j`=6I@@%ev0HHtk5DZ)#bsu0@ic -Fid`D%J7L8UW$Bo(u7UNSus#Lr2g14z*0+T9IavQGtQ%o{PFRIz=C#6F4(m!`#b6~lgcW_dv_M#)Ra2 -Umr=W}#eknzGV7e$x5?0K`r5Is74(naQie5$v5mszVNkPI2;Y#W*tY-xM!YZ^j`v_}|pg$MZ3xa-Otr -heOt59WkOjxlxCLI)3EWS%02rHC`NN?pTC_|Tq^s?~qgLS>Ic7*jYVfBaAC9F7oDHRKA0IYUl4TLpIS -c70q5!U{&P7>C^u*L}MP+0F0)=*eOgmomWLBeW=wY#uJ!g`aiM#Ji(q8x{}%Q^5!fb~aVodoN*!a4=k -Bf>fz*8Rdd3)by9VmdjqfvzmuRF}8OOX&ReNsyk&5lVdZCa;l-OPTCKvbkAt`IGE2*yNR=xMT{Kf}y5 -i*#l*j*2!>bn31sr+Ui|neNA4GO1vR*N`5A59t-vP-DRD^GFREW3=PS%>1XUUo5?ycQ@f56do*Ca*<`OQGx%ZSpEsT<#Mt1#zZfB? -|RZ=gHK&L3L>)%A@7%f$Ldh`0sDu3zR+{f+CV;F{%zWxn3#l07!h@%Hl+rTtD1CjGpu{?qZD@*ci+ -em*HskIO(WZ5JZ=NSDV5oqZr7)ptay&fcf>DO>jn$!|oshrKg7wjYt|Y4;;3+_7EX`jq`+7fF?stGbp -SI^ihSRbJXIX2AZ-J&0CH=6fQLA|1c99gFt1=h9tRv>=a<$aN>u|A5ke*HPh7y-ZVn$&klM?sXL!Tot -ZEo;yv~3Jj)Nuu+s=Y -fA=ui>=CTkv#L>8-ww6P}*Cd0=VBS7}}!SmsCGtH^wmURMRuPXd9Bp!cEW-phQJkJT+3r&~VOgOXh~& -cm_O)3Hk=zR#UF)u}tI2&HrE^lj-P^AOGT{`$K)24BW@;pUwoZu6JeFQrQ-XYjR;EG&% -${G3aDKaH8B{I*Dd4|jyGHb}ZK;{K9Yssu7vyRNVGCg+KnP-h>ty&r!MEes25`@Af$}lr!Pvt6LsI|+ -~D=y$^ZHZ8EsA0=&L+Z*Fh1Dr_5LjOaZLgkxzK-&JYBTb^^aYi4+-5IjyP_3V9U**H(fkD~O>iqd;clQeKs!qnH*j}%hW!ZJlh;$XWL`kB<;_AT|G{dS -&X_f;Y|_2~G&)_Su$39+EoNo)U_+28oYkwL?N4tT2IFTaenL%dt+WuP+s3sDXGviRdYjR8?!Jq@p46L -``?P+`>k7dxX ->qJEAl?@1F7rrvn%S9JSh-}JEKm7lsgJf=!_+wi3!*VyHA#YISESOjqF%N8u@`wq{ZQbox{ZzlLbFcSWf)7jluO?)RW)FP3Cs;@eM4mZt2oj4sJK-{QSdFR_lCmoI+{Y&n9duQ;;54ATJV*!ae7Cs-fB;jN`u -Me2)$1=9m$V=LnsqIlJDWF^sF>hT8#-frodlR^rPQg7U4&(cL~=j#nm>bf_o&C4Shr5T9G-mjZs1a|L -0C`$4-3`|9pc$Cdwcmn3In-Wa+a4q{$*3+@nz+Uj#0_X!pwUpE9%3(U;)_A(UT&PggCWV&1qO8<2Hk` -J_%c@YY!K3kaBO^gh5pI* -v5b)!Qm*mPeRoKRbwMAIl=mb2KQYZcg>5l-ijM=;<s|egl-t0)hwSd!RsEqtD~^(x_7>D%7U`F7ltyS$uMRix^#hQZbbRJ_(#Ts;QdB?FfaG -7{T#G<}ut7koY`i+O&XC>`4>mVfXKw5qK1jZVD~&u2bstiqBq~-M9Qd=Iu?Q{@ -sqUJkOOyj8NP{$Cpf?hdUY1u``~~V9%gPXDLIU3kvXt2J0;+r_c@z{)vNAz!LK1Lvm4YZ2qoR|qAV7( -?#;1-Vva1Z-;#uJ=1@DAyMMUF@i})n*UC@sY6`3YYoT;f#bZ69swha<~RYXKcopHq`tQeLeeJ)b3!ZD -qZI-7o^hrOq9TS&+r$2BVH3Mlpy$apxnf<9*%a#jLPYObdx9~V`&WX5s7*zc-n5uYC9#tDg -33P27$W?JVFH?z=mevVIn`{(#ux~Edz8}wp-po4zp~Maj2`EGtwAZb(Xj(WDi&~6s)K?|@{SA?h#wX0rqdW+A8FR2KvYiR -!BaGWRcz)&ik&M5C@b9AA3jDL$PD^+CyM(jnPTf`{A^)a3{XBOrc^B4epzMv`N?E4vddgCDjVK!j%I+ -2+<+k2mCCM&Sp5Rp>OheXXg)EcnFM`>(-J}y-@A(l(YbO)cEIAvgL$j8LTue&JnA{d0K-W}LgDfjUvc -VNXiBp2BA|Xjpq$yhF5z|-3lE;-+Bxolxb|#dS3`69m3c%*;xfKCTUlr}G_LWB1*i8ty1R}wrQB0HXyPYXjCyN_W{4$n_`Coz -N)0HZ_JlcF@Z&3rtb|u&g?qE`^{l-3B>DInE4InwS8Vw-v^(jxbH>&}p!mfVGlGa{m`uEG&2%6IDZkj -qs9t~(&-;kD@q;GBRoE{`=_0eW&@D?TJ1Muhk?~qm6R@OaDP_ -lo!#VDB386?jYw@S+|s|91^;P>UC1S)>`QQ(rTo1Hq=PjP-{vV5|Op07_?eb;0&!PXL0V+XR1a^rSXu -gH$~P{DRfw>CAwQv#x?FTuKK=SPi4K{l;~(hZ^|B_HwD4}U@et2t#STlEtQVvg(9}9kml7?BHfM}HI; -_u)l~kg88wxkHdIr&vw1a@FKN_NKBG}n`N$2Zsm%RVHI?y-n#w3eP30&>P315}P2~VZO=TZNO=WkXIz -?z2b38AUaFq!~Q?jDU!Y_qn+_a*~+!q@us{Bi1MV0XsqUvppqRMSTbH?OfQB=86Ra6O1)F`S<{GU-&d -F2KaRqjzWqIAR&pyLzLFDi>a-sB)yN_hi@&DXJW*XKK|~1vS=GS@8wb=CoHe -RSp+Ab9$+oD!HopWHXaBRW5+$liP*nlW!Yqs+9YE&*YAV-VZK$RaIo-ILO3_Za&@p?xn#wg-f2*2Gkz7k^D%AkLuBLK_phn -sl2CAQHgNPsHhw!R8%5B^C~LaYgAO;^7~a(Hl;hIc^#EX>HS6}m8CbVq;ldBA_ -R(4WX5nSPC-%px{}H{^-3zIT&JYc93%9hC|W9i`u$oe(GLHES}NCEZ9z-rnP;2PQVGegDJ_*wA@B`uZEI4QJL3dNMFmP#m)6;L_(DcEYhXBF~<~c*K4UX$_+N;;_`!4X+OL5ltPmVEI!84vI|X$*p2j7?u}7 -2sXV^h%pTooW;+Rb?J~0*f(Ho734S6!ao>_Ycz4(GO9y-JcJ1iHYDkjZZEfwUnEI%TIrV{+1JLeES#_ -0iFi=@pbw<^?qWqGRXpSLa@yBt1Pc`kbx0fc*Ri{O+U9QioW5q$^x(VVlTA}z72QqirJE*ry*jgn>U7pn*N_XQ>={hXW80$~zcae4|;a+rylj6u)e -Mo%pQZ`adEL=6p%#kJnaYOWulQjEHkZ$#8H2dw=;F_$@<GbC#pM3h|=aFAMKTUgU&6+ZAqbr0SVdSHJ0 -)luTtXRW5`43G$~_HR4JknOq~$>KNIM+lMJPtYYqHzttfz5+O-?w0B6%x=?LM%=)?7GcoHT?=%z(I6l -s9-XZ1Fs&AI2Tim3kS=0p#_pOnHxP0Px@1kj@wgQJlR|V?(T%&7^9CB8A79{g$$szKJs3NYmCeQ6|K((_HOv6&`WfPf+?Zp~I(AMEGte1# -`6H!7`o|*Sx7PPk4FOIPIq#xKeQ8xT^kC*y4uWtmU#Ap%c{bQp8(OF`{H;LQ*agO_@DD`_5V=0aor@Nv$zKPrH(oGcw!%gRHMoPX-a$=J7=e1(7QhI)t`jv_F1 -kzGIHqoflqF8-RSLO#u47*6#%=lq(3N#7Hr+c5om=GbnQLdT7vfaZdR#h!bn4%$Yh -=+Q*;N}-?mAG)ZE;~fwpNY`z1b1Q?3a?vS^5NN=Yv9t2-I?vUbGvsT1mT>V8DbrjZVSW5~ST&C%~Z=m -;O$)wSPJKLURWWk*S=BQ4-hWUNG&Xa&XObuWSySDeniP%_O?~lc|F;ePy#`jY^dA!{wc7(>2><)7Q2M -A?4{|^F4&Zh}!j_z~q&OdtO^h!>M{U2$!Aq1?!&eZSu`EoM+6as79?8> -<2gWj7UKM7qrN$5C5Kq&OlyQe?Q$AB7KP#5e0CW;)wJ5YdHP1O@Z6Jfcz=o)$e^O~{@y{kU|eff}7><)tsW?zwcR_wEVFywh~K&o?^aFL0@Dy4p~arB}_A8 -kK^r9n#)l7AhvD5_M4*s*Zw|d-UU+?FjuaZ~J-CYm7EJ?m-`f?!OjR)1C|NsUUg&Y@ ->#}hkrd`GrrIg|*IgJN!VSScfN#jh3{F(etV@WDz4V|s%U^B3WB<|kR;nPBDIHi11>mt4ByjAb2toCs2O -b}dTkbJ*V4*=MPuSM<)yo(M~b3fq1M^&{5f~ym89c>+vuA(ptA1WOaw+l+U@1-O{z3gqIm+n<{b~rxb -)aa||Nm`LoI81G(!KS -kWt`rGYj67n$2Cd~I`b2SCKCyXuKh`y)feKnI>A5kRpiQEj+iEub(AIM){0>H(em&>kMd;W>kIY9_sZ -oZs6(|&u82Fs6UZb7+ZZyThNCY`4`#a+rk>eH702j{U9HRFh6FBeU;NFI;tzGp+E@2$=(@D{Lyu~yI8 -|R%-L~GRxMy)G1Z=yH(AzVk5{1!+l`|6b%uI9UQCv9}I@R5!9-D$8dHkIzXY5Pmo(cFEn -Z@RF%@AdtqLYB~clBC&CpizIXuYczf^-zfW{b=CJM_u`HcgZyu}*tb(6jtEV -VuGG}Ch;0D!onc6K`d4?yv70(%=ei=CX4FZ?POAChhTk^sVypIXRSKmb@=b^y($fz>vP^dE6hfu36dy -~v4mnO1Rs7&%vs8PRJt<3;x!wf#kYt&gM3QChOh}eK1mhuWCPUavA*bAQ5;k*lNZ8CRAYn6iaUOZhg# -elh0dzhD(4xFD@u^tZ`}mEuZz$bkiy`uVz|DWRX!9%bDJ$?REAorApLLux+5&0PSmj}B>$=%_OId-wt -VkbYKabr*Pg^S-;vYLM#(rta%#<0GZ()Hm_+apd6I|QX05>nYMFgmj8YB^IKR>k!X9T1tKNf?oA?s%8 -Y3L5U=(UapWe;2XEL}z?#>`os(hHMBsgmuEg{oFNaXPP)G&RZ1-gT3e(|Zk0;w9AIi9NwFY7-@W&F&@ -P^Re}KLB}C~0Z-M!uxtWB(J+Df8MD}xwta&y+?C#)=F?#_4C44ecv3R@k9Yr05@wz*%OgqJ6XsS0Wa~ -kGNy$>DI8_Y8ZSuadCK8Xy;z~?a&xQD2CD9e{*Jh6`9(_%r@3!#G_r4y0bM$>%pIYu?>({#6*4wdD=h -&qi@x9f1#JBT3JiZ&Ti)@u-+d1Ndy$$YQJQT8L#0gs~YzlF!$E7b^71JPUi6dK{^q)aQn=|^iMzKKO$ -_5lbrCJO&Uu^gKD2hJoPx%W~6LEolZFWOjgS{25ZoG7IyB|xubW-`uIxVoHr))dvd3YLm@jh!PjsHIX -FFZR)g!q`?6v0mfzBlXGtps-vL=&VD6chZJU?ahM1V;&K2=uq;SVw|Df{_IG5d73t$4(F&BzT=*Be`u -MC?_~VP($G1Pw@zDC%B8?UV;S#D+sm_>>&7r-~_>s1iuj6)S1E)3?(oVOeB~|kWKIaK?%Vcf{g_45ga -5qPVgf^9YMP;I@Xt9Ai-S(u>{iz3J6va{Egrpg3k!PBd8;|neY!J7)mgPU?M>p!2*J11kVv%>#7swSW -I+f5v;gHcU>93+r!MBNiefH+sy2#&&@1jwb|`g{;iqi1emXjqkW3{U7ZdS>y+^XYm7weWyWf#=|>L=X -LIN;pWG+2No*_|z(O_lA#6B{V^JcV$?P5$!y?#t7Aah!>2Cy^M}H$Ie!d8kru_A10hE{g7vOeTsQfYE -K1jF^Qd}5I5ZEymu9%U`LYP@7{n_+u6>j&iTvpJ?Z9Ijtk-O@WNM;_nXhYHLjLjv;CwDxtWY1Reg*}J -D$$95d_)PKxj;Umy13f}i78Xj&N+IE<#!IDm^)52LDvl~%Dn2R>YTjzTay|>)d8_%Vd8+v!om5KCPJU -@h41@u;_3x7iTZG8hxFu6MX@bIf*GUvg`yNj?=V;<23f#2sse%?cKQ$jUZ8beL9W_4A5R8~NZ$!Rejx ->7u2gK780LwypSbY4Tw6sABMJ5SU?coHGmN}Mrvn`@>@5wE2+sDtb<-(e1$+M}B;r6-qd>bU1Y>`H+J -x5ezc%C&=)M2W1j;KG&Y^y!hDu+qU5mw3v=_6gFiL{Uo(x7+?kp|);F5E>JfJ9p{Yt^2J#0($o99oVODzo6T05AH -u;;Gn@n?g$w=Z1|m_VIxcT99c=u;$LOp!VkxugxLeuo9P8h_WZSS(u7;ONOPVDn?aQ1lPy*Bh;k2veg=J@U9_DX>H`AkH&swwAX2DL3;vnHCzax -5vImrKXjQF6tCQ2u6sRvJ(#sa%Wy(@T&T2Ug5VWBz(Wj!X2w*|f=g*-xE4xjU9ynl*8z*gfrZ!npIRZy;j@ -<8C1uoVGF(U;|=t(mLosH}J4tIU$Pz;;kjT}*0bBWdf${~;9&Qa=DPCc7UnOe1`WS@DO5^bE%kYC}e> -+9R1DenkMXOdDcR=1B_!nvZ<(3buae9@SW!EQQKoYZn_ih{I8@$Vp+LXB@1H9A`<#g<9|WdQutw6y8n -`8(@xzM!z>cGgsW!+%G9;L^0;ncpyXetDv%kZu8mw+aaWX*AVx)V5fkqMF{&-+_OMNY%m?2+Rj593{V -@=G0oe9{(XMti}4yrQ9qE#&UbkRs7Kl76@)^I^BkR1Z?tz)MZop7L{k3>g%=X-1#f%%u{-~Owr=3BGo -i^A8_BVrvH2RrD0BKqP$a;)YWwB+aby{SMWoS=tncem=ho*UP}XRxV}9O*3{39O)>vE{vE98uhT^x$gM{naq{RrQ^X7qqf?%6v5I#U3pq|&gR;PbInk_ZX6z?31DROv+ -;r6}LS&GMH7!3f+rz!i%x;1^nH}IxCNyuayJBXY$xI-#3z;W=F|)2@=8=i-O9IHe74DbKtOuF?WJ0>x -RBOhSEv)>anfQ;=ArrD=37HQdA2Ok*Xcn2+QZ}; -}n<6lQ*$~?W9w}+oTDk{ng&#=Li4gv;*CQR`$usa72PEPQlLJdHbF~h8kS@bZrAa4OZ1`5G^n884Xf& -P39?7t75fb0H(+<({mUH=zNHPg~xNfUn!LoCt!>2B~(8-J8psWA$xWT`A4)}NfevN+ob)-M-o7V4!Nml4?_Pl$1XB&@$(8*NU>053gGN -=SLp>%VUqPS^LD3Pd)wDXV$HMcEfYe|Luj1FaG_dm;dp~KR3Pl+U6}=U*Gn|n{U1S&b#luUtY1ja>oZ -dckSNu;og1wKRR&m(8q^A`Si2Tk9=|T*zqsF`ufDlZ@xWs`n&I?svoM){OiZFHRpahf8pngmufHna;5 -I-HU4ieOfRij1+y%*OGD{RIjg8kB@pu;(KUln^m;^D;2a6wETHMjgizKnq(o!n8 -!GntvikFd871S>@A-S03EE2{N5}<1|AgFj*F~wpej%8$I7z{oO^77{ADJtN6k0@Qy?bKMBAlp+rt -+LZCSxY09Ak556JG9W3b@~Hu`bNanH!KU5W3Dk-(s_Ayji|2jmS!~=VfQkkwd6H!Y|iuYuc0is8E`T2 -%4Lijn7eLoi^bn&jIF$wWE9{uY9UAt$tJk+4SB|sf}#0>r-FGb1gP1;!In>oZK`^KyG?Kp1S@!P|UIA -J(fWtO)HtRMaqMenI)d61$o5aa%ys|P+IfmrIL+m1|>wr(r+NuV?WsPGc2=H$uT=K$3k_Vo!?{{^D{D -Smi)ZbIhKIbbeqK*&~K1E-#Tb^X3ii>PC-94Vk3U2=N05c0W+<+IrA(zHg`r1^0HXxW#*)cN~G$cSOf -02=h`d*RL6~yY6|I**YSIbSUa-PTnn3blQhZ8>CVrzWq=LxZK+m`^NnSvsWU;V5~hi=Q|Xf1nKrEkVb -d(4%C-Ih_I#im -ICT2GSdSr^YUy9Z)-W9*~C%`)1+emC6%f`Wmr)N^DOgntqWN%rM2{Ox0`?_+_0zm`yVJFs4<3%F=b+6 -Wa7m0<$v3jH6VIP?W9S=-)3(?0E`$h9pgy;^dzd(h0|%Q!GMxKJwJ0^UbZDg?MJ7lW#-$a+d}Rbn3pz -No5!j!#x_wWXI|el4md~;^Ap8X-`8|Cx9I=pZY}#y>D#jZl721w|Ks+S{ofqWvVZ?UE&JyTZs@;H|shPI -1xz9O%24WjyH?#2k{LHyIN(z&5>$7Atbz=o0%KV1%{2F -F3+~*HEdXQ^;Zkj#YGL|Htds62i?DL)zAeT2u&0NoTd$uie%tD)GQf_i)nk6D5)yn>&(C7{q&R81KPP -C;(Q;A__;NhXn$f7VkVQc_OOhc9&&dMYfsfg(oCF(>Lk)4~bzTF))@t&wS8iUiavl(+Sl>bB$Ckg}!i -6n$1vnXAn%}W0Z!rb4{Wk`|LQ$7-1;xV2jAP6?~-8HgJmk-*rUD8unl@vyfhI+6(EG{ -LRJ!R!P5B==dKU9h{)`0U1;`}EIFyon0+ujg%vzeB*5GAP$bFh5S3)M#daOryrxggwpjAm0MEFHcw!B~Kj|v#sfI~7H?HQMwN^N7dHPyP1aQs;C)I^J1$xq1bNA4YnBVN -|L6CqSG$-1%G_WTSaHpZTwPSQJL523U)eU6^^NWm=EI@W@dY8JI!q%mrqd8t;5yWEozTT^~Xsn$$PW0 -F~-?2|S=U9Oc_kNOoUU`-N$+`6fak)$Ydi-K)()5G?EpZ^~}skjeQ-ousm2<1INi8E1gPgKlgCH<*N-r0)#JjTQ>HqMdbOo>&&)msT)tl+#vF_$X-4#mG -jNoO?yPG0;~d0(&K^PH033yS+T1;39J|IZbFe;>Il)H3_eK7P$UvVTCc&wm`X|B@r{es#uVr)n^Rl_*nG@pfZu8<|VQ!@G6&sFj2xunRCD&xrte -9JGFnqXTzE0r}JbUWdF6{KP(zDZ=Pk-@xVVgh$$b_Raj|Q-mqghAqxIX;hBVV1k%-E2{a!jm)q0f*0* -~}sd%mgC|LJ5Wv3?>L72q5q$@FidbwHM6n41q*&ir@snae^ZRpAZ}**hjFNUBGpzbG1li)bP!Jp*tJIH*4U?ah!1SJG{1k(v75yTOM68I6+oihu3Taq -vTohR_N@IUlj$F9c}S1YQ|MqM}?>>bWF`Gm6|io5FeaK@GAWlz~&+?xGckFJsVTiu)U|E=Mh^Z)Pj?? -1nG&dj6H81|vlztug_iGcU$54Q}Y)YTrz24c=@wTV --9Uv0YQ9gzv|5(!DtSm?1I&8z$(mUG6?K?mrR-m{HbuT_KBvcL{-fQdtr%${2JP*q)o2U=nw9N-K@u$2$@z>MeXGQOyeLwxaTvkL?l>R>FMekRq -5GUMM^yAMdual+ducxPRekHwd&*{mNC%>N_H}oYkQ|^nse>~?~Q}|+MzxSt2PGLoS!~0t&BfU3QBK;! -H|8?ooCMLM}PmC?@(S!T>^x(`>0oDSjVSE%Y%H@PIGK+F*d8MdNpFS)&IG7C{JeZ9dHHw9YhqIWN7*T -c;CQM*SNl9$#)TwO7j2Uck+E_Ms?p&6YmBr@Go5!qHtLQ%p3k%tL`)Kyk1EbjH#U|#M8^u=K7r`FQ4Q -EeU&Ft+ZBiKKRW7rc*X0vT;^4QLY?`8)#+{c36<{e -Q%beBJ)UZpJE(u=2<1vWFhXlsFiD?Y07;8;@(}o&*J8HlI{3bSv4`I{z1h$ah&(`qOY%712eZmi^{VD -56@q1DH!4!WK#gC)-Qz`yjiobxjXUi%6QxyLdieFCgKc@JnH1YdVd^5$rm*U$f{z{7fBE{cM@efh_BN -YEDivKOeucG*8DgH%G{6T#gOQ5Mw9!lvYh9#a~GAms9+wDgHkxeg(z0divJwN-%Rn}qxichKIOUkIK@9r@oU`i`%?;cQwo`s!b6n8^OV94O5r -4>P}82XpN4RDVFG6t@8|5&YR)dd%Gs4e+#SCw#UDWNM^pTX6n_rIFQE9#DE?ZC|2K-ih2n3g_y;Kdaf -)B9iEmI!pcBRKO7VMA{Js>wKgGX`;!mOY_fz~86#s7&|9y&oR1?49lOjJ_r-+C#;bX$Z`aX-hJ*ZD$u -U>t}xqZXO#Ky!#M#e^r9vvQ;G9aj5zdnKE#`RWHh>Rg``i~(?WMoS4Z3r-KT!7*q8y^uBJDQS@iU=P) -COoA-0`%$AtEb{06K@WW4UdS7p!mRRVE^FYyHe_rjE#>~pRry2Z%G+AP);GRSI>an;}D@RQ(>=i&r#<C~}9hr36K0Kpq!17w -M0QkBp6qkBlFCYnM(+0Qlb)G$4-2=|_kx)KW_si2zFZiS&n<;;D$^qhjL)5h4e*{0aY*$RTE+5KC!v8 -9TN^hYl3L?VmE-JH_u$3zU$>ssHVc%ZCeBHb%BF)3k#{91YIbnT-FL!cNRJDM1&-aq`#VS__jc^YntA1 -@&{$pL3S8IKH_3PPl&pjt(h0U8c3wiLZx84%6!l&gguqR30*hI3zjvYJL -M<0D8WP?-Re9gZ3<{NhE)G1b7UCqv%Im3QBcUH&-KmYtQyL$C1TYZVMSLyxG6-_@o2p_E6Ndq0V%T;q -|pj$`--NQ7{{f)KfTi6i(9-F{-v-|mBwwfPjukzD0e%EN?(}0*jGx|IlY*+QC_`@l_nc~M%{Am>bev1 -DP#ebUOzee%*Q2hFF?!R)%f8~__Tji84N*~arOBbAg$O-u?Pf*!F%s1_ciaX5D(-9yF+X>p|@)K)beWZ|&BzPtc$?t%Gh=90CG@Z -XaYY_y$p&+iq&twu}EQw-0J#Ftl#v<>h;u(bz@r-R1V~Z49m9Fvzb*Cm)?puR(aaxAH>zH~V{Zptm-? -TeoTzOzo>@pRS(W$d{sYr+3OfxLe15y@Ll03dT)Ul>hC)!GXcSJ%a^(-RQv{YR{hXPF<0av5{DW^HiX -@#d@7448r4}L=Sm=2-j%L5}PM_QIB+ZYrsp%^?%~|JzEvP7e^>M_2|(9g$lrDkbPUVYDGPZP^L -^JB~*t{Pa%$Bs3rbKJ)TOszBd>i<%;1E>>u#VGtVT`xbybevuD5i@y8#(r?KaofBoxUr^)>K!i5WGX< -mBj`0?Yf?%K7>rPJwxM~)mhNTJDJNe4$#P!7MP{7}~zm~ZOaw{LGUQC974Fs}c!Y12jzr-$raKmYvmh -iM+o-+%vo{{8pga~eNye(2C45e{)kMu7V%iu25?ufAHiZQHg&64|004#)Vsyu8SjD_16vTn*fCJSg -~TH?Dal&18{FTe1ge){SBr=NcM=C|K|`!(ft8R3Y|N2t9GBOF#D? -r+7Pv(Xix!lq5|+&=}_$|G^Rxb!r2W}=Wfut1AY(wm6eq%s2+O}Pn3X$?c28t{J|ebj~*3u -aPs6y@eUl(Ca4Vy^YG!r0?;;4A23mGXgi3rckf<-KkAU$KSw=WyLOFhA9}w+?sf2|Hhjl#!T;jLi=2i -b!T+J5p?$%}0N}rW|9<}V+i!EKb51g|Xu~Lf)W@DZdjtUY-Me>-wsPdi5n%@n=mWrSXeX#6;P(2DoLi -1^KKdihhwkBg&Z`8=z>YFUc>`bY0cZi$+4Ldl$ooML$F6X`8;(XQeo6j{^KnNwkNA|zA2d)M4ByN79YjOU=bT@x<2?Nk=Y!vKZ%y0~ -{+BLY0xz!!2?^;%yifufs2;AP1-O8ZfMZj1pxjaBs3Y(V_#gc)&DjJ(;|c$}kI6KQ`GoVk2-gur!!Y8 -TydyIHnTI(Kd`E5*H;O-v8C>oE!T&TKaX{lbQTZI@in;(_fj3k-(8j@M;Cr+S)kM3%lX#Nzdx(Zu;{U -Oq%QTES$a&a)nTEmC7W!}JJm~%3jz9IqtNZlnGmPqCCE6MKmZsCY~9ow&y)^dq$ts_dU5i4|qpz)70bcYYu;^=M_VT4(&z#c?s|bpERZed=I{EOovJf -cpZH7^}a3qh4~}-2Ky-f*ZjK#4R~f$aXwX{A>nJz;|QndFEs5LG$`$PAo?WgQ~OY#)RSoF@rK;D(zB! -~{CoB4<>r4H<1x-(S08A<7!TCCKzqQuN(1nxevg+wp2lBVIFkQu{wV$|(eO0UfG3su&*?v&a7Rh|n6#mrT3;w6Jwi5CX+MG&$;e5baz3k?XplHhJ}tLr^hvSD>f1ADP}?(TP}?*5q@cG&GM5_Tk9LOfh2$(ZfCd#B) -6rBLQE9=mttgDYwrB)@qG8(iM1!V1$13eP{IJ|7h3=QfXSGl2M>O<) -yUBh@;7{`XiebZs^&%Oi1o)$0gbAJj4Ul~v!}#lq!}zO2!#{|IjYPvcYjgR -9vsE|L*;Emo^QcZj)%L8&82#RB8h`W`D*uldF`_T(LIt!};0@e>yGjfCe)RX4*P!3TScS0-&wEQl`I| -(;*2N?ErbQ5hd=fAg8vDhmB -1T#!30jg8|?vjt961tUMnAC`~{8R|H@@|@pp-aH;9HUg+v3j1+-_-@T@|^T7`yHpdo7ve<*`!NRQ-;) -1m|oc+e+}(8w6WK4_Z%(Pv-`gB$_axN#$Y>7|!A=Ag*+1Gv8ivCod-&-XeV`avf>H;!HNj}z9W>st+eOYH0}90g@z{;8vaatwDP`i?# -z^Fz$0V~8lU3`p8j5pzkAvBPiNFQjlZiWOqdXxlauoya7BAW8(6$}v7kZAU%yr-Fwv$O&#{_%KHu?*T -gE_pE>qfbqo+mr2l%7zqoboy5B$X!Ulg(zWErQ^$qNb!+%&XAM@w~r2Yu3(#W&ENiH0WnndY9(D5q7c -R#i~n$@}%|$5T>L`18*{&oM6N=jU^q&Bj-(SRvZ=mtTG<`W?tZP0<3pF*cyDf-D4i6!QT*XwL`!X6JR -k(0pS^ihEi=J&uCG+->iIHA&kISgn(e+oXtScp7!xFY$-F983G{KMx8>Sc@qS;jznMxXS=f_R|+tM -jjsBS$*pJK!3Q4*egN*k6?LTYm0BO554?wY4 -&*x21=<7Jv}n&%58C$pVx#uFZ`(7F1E0JR<_QZ6dvxvEwPGCvc`I$17Z(@ff=S-HcW-{%ZMSiftpzT? -18qYKph1Pkv;e?UYTD>q_dh+Gzf)?a@mZEJFh0Lj7{RwaGM69Q`#Qh)^UsH=zHfN_Va=K~yriV${OZ- -K`O>9Jf4=wLdwF(twkUU+R|;MN4QLmj6S#qn#0F9%D4x3f3bqkAxd!B-9;fY2qRBFMowH`mO -6fh)ivFU0z<^*MIucpRNJVe`M<2k-^{>Y6X+1~Abc&_>W68n<_h+1 -j}W=FjXmuD_vef&Yn@)-PGIP}tXAe^w>cBA_j0)L`=#qi<7dr=vdpgq6)?z@5pln>SoseK3>P -5PT-HSMw!D7ywMKO|G*uxDfkDnHrfH&0NMo7MITJKU!!zN{QdpSRPWF3*s%jQ4`R>9=SJ~IzFPT5Emr -{Mi@=BKmXmCOQ^le^P;t@0t-0oo<%1bl)zK -%cCYhhRs#s3X(|#&e<1KSLJ^y?-J0U_KQu?f$~NlL}Ry@CxE9g);6)GFYrg*s4@ihb-?%FC6qb -Z&>9@(|Lx`80Dmq2qmO7j#x|w}Cf3-ePoK^ofBbR5-`a9l0pY+);B~xX3;^!x{s_snPyZXZ3;eb7UmA -N>f-f-!fev-OAN>dVI*dnJI#9N+zy3OZ;)y2&KdWsR0J_z+dB{z82hXVc2h?Z2;OXi4@8IsnUpp>pWf --k&(^8!P)~#D7;)5=P2W`L?yoJ6Kw5Yg~eEPTF$?wE)YdQkV|P --p0iu$O>6D9{4jDUaXN&$NiYcKt`4OSM!dknbV?;2ryN0Pq&fojZ4meivnc_6mLn{%8lpkI(&qxC{KX ->z~w5xYvI`1IA9sFX;ck2N;hqcA|_i=S10~9@O<+)C1np=cBJhKSpy3v9Cci|IxS${K2~|@p*InuI-E -9udZ95oIxXao%rY)$p{kF6~@&re=zQNppN9`|1cmAoO}2~RQK>=8eHC=KfjLo@N1*z&p*M~=o;B1+aG -LtDyB{`*&k%;8l|tvw^%XD{|Nkx6qC!QPBA?d(?>ClirGUkM=NHLVshEk!EE^5P5}EI56<`aDB#6fkQ -K4sN3e(BVx##Y-m#<7cs;PW2YLCE>^qpo{8)>{GJ)j%Nb2)(3>(MJAai$O8a_qZU)FM7@D1nDpUHb{S -PRCU!X1^IPydMX&wdiPw1fj_?dIj>btld3?x!|gi~fvc&Y!8jt)hPE4E0M#Nj`s;WZNu~f$cclsp0(QjboH!>x_++6{MQK1Q=fa7`pvhHF!oH -b--vxK?5|)=9BZ+kUf}%TPdBvJ+XMad(xppNAAR)EB;Wwq3G)YxkLcGi7NM_(EDJdWez4=2Ce`m3Vvh -&=omkVx{tnjUvB&mn`C|@1bI=@`FJ!6nd(3l@FXU*Hi8|+j+@yW5Uv}^J@_rxo%C^)rwRF+oIopUIME -=^d4~@?}piD4+{p<8m{(>V(tYfZJ)&OV!i}REpHdtgkV`D-f4x -k=h{7^r{9z`zCL&)aL~i8U~+2V+fM%^xuH2YKHU`)z_BkH~v%*y8~|Vvh=Yo!BRwx>rQqt>%w$oaXyE -g@uJ#+Wl@-o`nh7`jy2IVl5HtxmZWk=8wHs>>npL;zzTxM}xgS>@k5KgWr|=2Q`1lKia+0#{2KU1<@g&xrR7^ACnsK<7j2iG(_RYM*DOkf0`$yu3ft}Ns9;a2A{*kgZ(zFsbYTtYr?NTp7* -PJhClqmxs`Akbx7W8Lz}>Ur#64c6$=+G%qc1=%F^z=0tc*{pe*oUeI0vE|4{b(u+N0`Q1B!6n6S6uQ1 -+J=&5_};rI`W;!H);)_r4qF-*_*$@g6Yhzv7|MV!sP}MOf3s+PKP(SQp3s3ic+%9+#4TVcJ-c*EkJ7j -@s9-{vne&ozB#!o_Z>Fag3hSybDQnx$DEkX&6WAZYUSY8%(p?64w0$)8 -ZngZ6w)MaR59Cn)pQY{(U|xW^9m)iK56a?#^acO$kp!_%fc5E3%KG|qnl^!bCYQ2LR;1v7NAM%%JDuS -8rH1Waou8o{{(tRVdt6mj_P;2TWSTT;>12TDt1Q -b0h-i+XA*Q6$keXTAl$K7`q!T4gRz8@tu`&DH-&zL`p_5sCe)FIE^Etrfp0n3JYp?ZPuYLAGpTA+9rD -5$3`E;$C(V^WhxHT56)y;%4dYd?tp=wnZtHf{W4k3E)&d|0?}p^JNnyJ-6m|4|l@A1I4RyJ5}g^e2adr#^WPbm9tm%!sM4 -mHilfv?-Y9z??4f7~?C@#rjF?m?vVI|HF^5*P`zX#u5JubL?MvS`_z>~+4DSd+#OD6=stT`GCUd8{BQYt --r_MC$Ek)NNRHG1^u*9jrPapT6hdEf;L7Pz?!FZMy6<8S1@x3&@aaivYhhJC_$?}BXosQ=fkTel&g_i -h}BwjS#;SX%-=EBL?z54iVzwOsR+bK}`@Z*3)XkL#X)`~iR9Khg&O;|r`MV%|7DKHkm0;ut1Qoapi$@ -xZH*crxJSkUe<-J8>~1BV#Pcat`=N_+U52{MU-9B9K?W`$g&L>3gxpgE{&kLxu!#F0j4^cDcS@fPDAl -&|4$o{RUfg0r>ex=&K0g^HaXMM>ek2BD@?w_JO_~@*8uxD1(?w$GQgUN5eV-&H>^AUWa2rULbBGX5u( -sdF7RbzMod3aP_~iurPV`>eWNNm>cIA$1ry6*kG3~U4jD!3~)8Z+tzo{J56;N^JHU&fjW`t5KJD}Dy;diq!9uo~th&>m%HXS ->*dYgN6xBF-1`8t)r1`Ou+5>wYF}mp;+~ta0)GhsNRgz?(O34z66e(#;hkHe$}nt113M+Ae*hXJAHlrgMvVE(DHveH{8_)BTm-~Ug^fg;Wz_TfC2mzSgbodRCW_0{E1erdyJO~QZSf%W(Y-U-=o&?M7a8oL~vKq|7C{1hGQFI6Y3F;)qB3<;LD}K#aVT}Valc03FAkMUolp|ScO2W^bCv(YpocQ*TuHsl}96WSne -4eFm~_i_C#^!L!$LthhpU5q!%R?Kz#z?dTr#)0!UY}hcj&W#v`e5l^DI=HRCcH>F(-O+EyxB+9Q>1q9 -38iPIx2G;{$mM>rK`h&Pe1nX)zmnbh+`r-$7mAiib^ptv^8*g?i@(=8Si(6Qe!}SB6EycDuUk1OZKIH -NfW2jjHm;O0#{!#W2>rqZ|E(Z=A=<*bC8t3vKyGw!!(fPEt_gYAE~;q{2qIBx6*d4aVeyeG8Tm`}oMG0sNYy -=Tv!%dW+i-=r)i91dUOONZ}A4)2^MmyQTS-auVnUU@;YfXGsa!yWK=ID$mk&`ns#^=~kdD-JdPD*-OW^zuq%s@( -ZR!-KK+-@mZnIbtSv->0(6`7elJ}@RNCwFLCc1|E`yd6cmlPKA|X=J38o1K^AzJ28<_NLTb2Uq5#rQ~ -G?a;IGS4FAbao0tbw(oz$%1Cs(7X=BrJ>c4FGbszU-doYlMv`J|hks0{Yj!MpnA3rH;Tv~QiWL_X91z -#g!M~z9&$VrQmR*$P({5|m=SEp|ExNNLekNTU2&sGnQpE5BfF(x)Pen7vZq)UHX|NQ^=8IAD!pl3}<4 -7s1=lIO`DQbW#@2-=y(&@h(Hrm#0zGo_u!(nyU^b@lh^1T{~6S}jxessB{J -RvT*(T4$}VcAqw0%hmF=dD=7DDy>|r(q7eW(|@ZE(_hu!*3an84PwkSo;IqCGsZVY&}e1$FngO*%~j? -m^Q_sCXYhyl626A-;V1abVujctj)>1hs=uYR$$HV+YxT6_>=AalJy$X(*%|9ha<)2E&il@1&N;{DIu^ -J9(?`O|ZKNY%#33mpkIW#;NC|m^d`p_rmeinQXdiY&dsP3o{+%9SbTl>_`-~XAl@AejSbeSj_I~?a`? -!6^ZX%Nx`aMWSJ6`1mPN2=)`d}KFv&ys?2mgzF@WN2BkT0`vdhR?YCOIR;C@${-s^inBGgz(5LJ3^u_vWeT)8* -9%lT;xL|~ux0v^sL(LR3V6HQFo1dEBn3NCTC48Eg30$ibH~Tezj6VUmw$qw!kCAy2_pZPKQ7-)2NNbr -;A5k}|2h>u%Ex&`e=h3_~@5U+Dcq~ukPw^Fe9rugLVxb87!>#_-eO9uSWlgpowYFKitT(M1>$DYON87 -{g#dfLPN>VvhelEkD>CRkdg|o@o=e*;5;M6+!(u6p`+#5+W=}uH)lV0RrGMTIfUhXBorpfeA^gFtfon -~W{0%ftXU%8-!sLj=uAZO8PcQC=W8n51?-lvXG18SB!O`WY4s!ypesc)%gRYl`kiWbnav{~9pkTqK$r -9Y&X=o|F2`hWBmMk}M85oL5XdKkK48L`Iij6@^JNH#K!Y~v5cbmI}@F{98}0us5-c-h!(>^BY=M~tIJ -jq$lr3-TFiHZ@zCipkA;&2WAzkKi479RCY{jla*2gN$C_q2fjnEqaJPB2hdf^2BuUxOhU8ien(R&Hb( -X-C-t1`5RfSt-G!9)@*B$^}Myk+HSpWeQSl;ci02$adxHssohMrl@T&tX2Dz)$r|~k^f~>Ud!1>{lTL -;6o`ah(6vEuyK-!SLBtWvrGa%EO$fx8qxj+{ix+1zD8RO-WRWlz%Fxl= -I4sYNX56`_z%@AJqBkV)a>&gLl+hv^3!1UeM9`My+|?{FP`YD#US-Zry2jvX9zd+M{7?vCaVJG;ZbLz -Voyz8A)c7YC46rQ-m@~*{K{*zEFbt*T!7_SN;ueE57p&k;CK&(4#aNkePC#Tqn24L-Lf2fV;z>0>r~d -Njs{79wn=5wQBt?;~rz8aX){}zt8`c{~iC|{2%y_`9JnI11_BhSzaS6)@eQeCO}Q2SW>PK(wjf|eD6mR0DL`Z3*SG&k -BB?LlrdW27+#Msqt~&TkNHg(>=r5h6>xAP$I9d#@d|JIcN?QI3^`@&!2@$534NzK?X0NggIE$!1bXy3 -)mTC2h@mFcXk<1>44su>Y`L%6!FAd#Q11lA59})f($}8eWF+ -vS_`m^>pxoR&_sV<5e9i0k0j4sw!&(whL^+R%115|Am2K2D#c%jgPP4A``umeF#0f%;e|3uDb#Hk;0t -u_9K=*0VD97CX;6D@0KhQ?ZnuN~{v6Bq&cQE0kiTR9Ua|R;Q{3>MZpMb(y+SEm14fkJZoAGpernwLER -A_J}rHdt6(h6>A}SQ$1W?rauRqtkU=Dy5R@C8)Qr}{%90{p4A#H%{$EwrV2XM-yCQrnWN2gGuxbOK5E -W4pE8%5rC?G=~4O>RoFmwhP -7AXl~+O9o2$LSQZ>;wXm4nzwSj;Pi}dxpNDwQ>DgtC&gP3^G=flNrEr4^k(c5VRy^G#WyU-%w*K71Rj -bQyig6>jurJs_aJO_60UF9pKkD3WMR08;U5&GA(-dciI2o~?}T2O1ItNIvyyk4dk8*7bi=3#R*p9`4r -7GEfqiq&F+_=~tG!u+@S@AALxkG6yruohT__7ipsc`MBHDtS_Fb$r!z1@L|3AQ{M>ftlLKcCZgvxw1| -9v$6|DajS~&;Y2-5rRg+-PN2E8fX<{Z)17pW{Hr`Hj{=UIl;`9{8R|51S~=~U4o+7`bu1^=NpJ=`!<| -$o17!$&T3no4=qz%4;UT^x_`4H{Bk5!gSr2ye1PP-ZXeU6JbUFtl=?y@bT6&ST0eMbhsbJZP*-lo?d| -<;OUHKUWSY8ZxP_6g?Z@OYuG&02JzDAUUkxphO-jx%sa+6!UCs>>~o&Z*7Fi+yc`6!;s)4>y%z;pRzK -8+XfnS2f}PoKVqVJE^D| -k)ng>B)SSBRM2Eg^c1loP9y+w4;D#cxELi;MY_lk6GSdpzGc!Jc4cm4Z*nhWX>)XJX<{#QHZ -(3}cxCLpd3+RA)-c?iPA5$ks#zMs5@@ASFrvY@BsOS@bW62#Br0gsAZRe6pu|uuFd`&Y_e`2QJ;Tg1j -?UufjN?2y`i!%ZfHRN~$ikKo6{EOBajB+214t6K)O*gk)tzQ>=6T>2=HBUiZ297cuFA|za~XBKeB+`gzq)VewnSpjz`LuV12Q^mUvC3#otdcJ$?DvvRGP==~7dAQkuzh7#{w_(^{{GA3L7{v&pzmGM -TLSV;a1g>`63fflw06UtvwGQ0#Ky^EtPsm##9KX3&k<^!pOHZZMn1rzg&Cl4%)qAlCxv|BJO4{AV`RC -w=$ZtK^4P$#DJpkkKI=d-Az?oF>zvtEv`1AU^0efLcK|Nrn`s4eiApMB^ -H-)S!n7iATP=QyRB!;%dqomu}o&uo(NwoBolD;HAyZ0Ba2XJ4c!%M+QUOA)^-R|$l1)wDBoVuZT1PC_kDV!F9$Mv3 -eIR95|dr|5^IuJ8MLo#cP?xiY$ro&i}S?!;$7n15<3j-7W!G#AF*BzorJzt-hr3md~e?8{_sQj ->LS<^BHJBmfOi>?Mfh2x+A*N(5`#Q2#-zMX)$YVuD$ZAzkLNf3@*Xj=7pQ=@#ZzK_tfY_90L| -x<1%kaHeO|;CH?}eoU(A0EYA@G)IcFuy>F5t&D&GQhk<50fzY= -)6&?q2;(;+C|GuZAEM!O!?u*bXB*YSXQ3C+y2RcV>k)sb`( -LHzv0Tmo^gu0!si9#oZx2mJUW3JZSjy>#HqTDrZTeZWj|Qnu8ch=k4Q29%u$AvaE22>6HC4E+!y!3fE -oNV66-Y+f?%N78rau}L_7XoT-9!$c~$lX^VG%Zqp3dBl^Oq+c -N^+BE{Zo<6*U6$DXyf(};MG7x-Id#XifY)K%!5~cMR@@5O(*SrAu=A05t|hpQO4ZX7aBc9B!6WNZKZY -F~IuN*no;4S*-p?+q{#^~L4~)&jz2L%)_x2Fjcn{)YLwd7jrADb9bp!Sq_DD(JC(^hEY0?hZE4d5r9~ -^6ZUlvO21Bso~9TBKsQYM*NU}qyW+k&-GM_T=Cm&D$K5>u4LE+=g9Hpt7mpw$fB@jq~{^rr}(k8yLB^ -1WFC?G@tQR1Qx8+%ueIrrcu&%qQFOI(5f2P^6wZt8Aarg#EGONVDckkvCk`eE^y@hpUGWZhG!212=^# -2|=FB>&$D@9aA)1S8untX#t9c0ey#C5C$ytqVt`F_B8y}GW$lvOSv-1j^cn2(dD{tS0|#1Y_yzXy -dkoq)``V+GIDikX)4OqD#-e9ZJMWx9=L>cC95@=Qy4rrcBbl=)jo+>GOC@xFoFg6_yU#DTrk4>Ky^j8 -u9NhCHr92^KEjgul5a_?f~1_`SR~=(>}m?NF59%d0yML`_CkKoON3B0a1juhSFuBRKk9&P~Y3=#JG1tu=OW$l6XUj2*$G1(7kk2eQUc?M(yX6JrQwQL -ogdSifcqVU-(?6ifb{PMe18`b7>ON%QeUSc@c?+9rr|dIT-;(aAOt|cBh<~YRR9>~R46Ael_!gAzq)A -zje87~{VSG@%(3Z?o$Rn{QwkGz_HlJLk&sf0)7UJ=718&VK**L?{{`cfD|MM1u7jm#a;QiZy -9NohzH>h|HD`y~Kn_8G$ceaem`PUs--K^VL3R-7WFo`| -g;{1V%ldE5s8-62C=*Qs!;rNhmqa3d*)U|J)Uz*kp@;cM?|w$>JyO(p6im^C2B5y$3~L;{%Gi*Ti2WV(&RKrZ+ZwKovD%sK66O)!#8(X+V0+W{9$p -;|fm{O1>d4W6wX`8 -P#PDUX76TuY{6S#!Bc6$p~NLr;&G$Iti%$T7b$^A1HhvlkwKyQ$!TNGDpCws@5WxA0i^0@Yg~nFZ!yi -sN@G3_!i%>Elp~o3VDQ96y`yfh(gs@t1bn81NFlNaCT26vjyfaD6id(@?Xa|wJ4XQjG0!z2aD@+ugEM -mP*Xn&qIC;>}P07@cVgOV|6ZpipIDt1v;yjwE|@#}B?ljQR>Db00*4$aNv -b&ZrjO}T-#&jtgw!^AJ_FB^-sZP7#!?2(OMypUq|BBIaH4KbBJA~+)c~jdLgCqFzz`oFhuHyyn(v1>% -=Jey_gN7q!R~q+Cf1Kkh(8RJUoA-Ed)^1QifFs~)ET(D*uRPjVPcTv9m$=!?=oQihDnW$_KLnnT@NH3 -Z;~3@?9n|SHS9L%zk$l7+d -JhwuQ1@e2O5SKTm?<8y%Q65P+3>h)Ad7V-mIA?HquPo0+I -&$abE9D!P^!@RHcZZ79qEVyyZgVw+in>>f~bpi#sLuK8z#aQ0oBqyoF7Lv(zHEXHCHS)mKxaBodLF5V -j!IN`|&m)ez=Fj>&mn({61@g?pPkOi~(QADD3;d;vEJ!-ZM?u;jdxxLYT(P -z~|9bf{Nd8lTIzfLT^rb!`r2FedU7DFQoO?FM+wr~g7PBB@XJDOr&kV$PMRtj8Xu#AW*Np8nk;6U -Y3thyDcwskAek$_E|aU;G51Z(}%RM<=fMK*by#ER^!ma=6&kJ*N(-sx1g4PW(A4M~BK3gt;^F3K_k(X -l5T7uJ~*`xvKbOJMyfL8x8j6z3tQ4&027seDg}YZ8#}S108wMrhn(?+JOlQ~ngWR -)E2M>Zt+5gk`Y33d%CPSZX&Qa-ps%r_qxSJSpIESfyO$w>T$fx#$3--q=Qfv6rA -EA(o*&0q{*8Y@$v-d%wVXOFqo-N|*!rd&c-D4vv3S^;peN?@zi`M5!2@=JoA1Gl(xvU}wkE{=uTB*A+U!2Pis%( -PNY^{ZLH1Wv$?K3xcRI^H$me6dXF2F^vpws_%VOzA=BzOumj)l7iGp@?iw%pw|?slBdNO~4@|rcxh{- -vX1Q4OiPCmwHD$5jQJpOh|pg)h58AS)a%@o0|BZVAjtUm`!hu*j23fo}w(k#JfIx>f}RQE~x{gjbEOop{-ge?&G*4NiX3WUa{-G%d!wxgur@e0y5bL4)@XJ$V}xGBZJUfl>(wbp7w!{c}+|j3HxrI2+R-gAe&LP^`PznnG>h_J3lZ;<=p -^VH>*`xxMdYF -PU)O8T?9rM{z*(w|gSItLJ_U8*^W!tl!JQbZIacjL-5slG?2f3SYtJ?cx)J1M6ddE;DQyydAask?W>1 -{k64KaG07ek4vpi|M0}a9LXHnguzwkRGtBuZ)dt*67s;$uJYf6u^WSv#=P&?=>(Bzn()#U^t0#`w=bt -ArlF+mZ2^f8=n*@GPkFu0NV;!)u(}HLzb=>mS~UqFbWY2R*=C8GFU+dD;RmmjykaghECN`51m8}5hou -V>RV6?QeP+M4b`vC>U#AWSH9_Dh@9(yU}Hz$(2?qVNP1`GaK0~6G{qM#>hUS%s!3%w(gfujI%DVjyY7 -z5al|b|{p={J9hLxO7qgSa$QT}z!t-2}2(M#{0bCr#q29pd>Y_1mB5))thW1vGylANVPzffnf4Yd(f) -yGH>kLefukTyGyYqI4FgP*HXA>+#l8T(g0>ti4Kgf~Cwo1K+Gf|w?!c-UN*mLigF1 -XU%Aq|gB&SPHL=T;gUVO7i{w@|8Aks8=o#YEk*(bARm-W}Wb|y?%F_@Pk97cLRofAI|6!_4B)+x~VH| -B5U>o{$3*GsFFDq-&J~0o#MCjNI9+1-%>Gn?`4fXw_3Ht3)A9+VYm-HnJ%(zUUp3EJE{S~-Qi&;e0@E -hoMT!V-ntKYh1tiTdW7iZ#NR`cUZXi5+Yh|hxcP(1O{HI#mjYJKQKL`l2uAH{(9e@gsaweDT`tzrgaG -mP>CGUK(2U?7UV=*rd5%OsArcA`o*AF;xd7PeFGu4l(r&yCvM6)2oKnt5F#jN&^?e(i!qe>9As=grjv -YW*IrrWK-aSjL8Wr!W?jYVh`UxlYaXH8zS?pS*UV{Daot;%EguZX6Z7SyR6}v*|ACM@L)Mq$tJ2UGoM-it^EhNO25N7>X2Aa33SHTmf@wBbr)|N9 -jV{2Nmwt018ardPJGd3&c8SBKr!n8A+DIDl@lZ51A1m8386nRnC;Jz;9ciqHoQ*L-UYV1!doy#&hnzH=5aRwBL^&|N2p7x -@IqaOfh>(hrAAzs+XK_6<(yy6e6ex?DhGFC0__^={l?%k>||d!%_n%8h(*1)Okt37r$M5#)Jq44^yUZ --Pxm5`zVQxtc*=%!_vvJ%+y-Ks$aZ@ov&`zl_v1Q+8di0(JG1(>*&ur$EoX&|HAg4n*^wJSB}X)y*f% -*#?Y-M9@(d)q(3?0**MNZ1>#^CY0f0bG($cE)(*jBQ4heWUx25VRz{xnaBiaGo3U;nKs;(Ik>t*y_*g -C!2%tG)@6YpUlHSb9Dckqz&l)ac8E@t0ap0fEG2dtv<#l$%*xu%{&s=Mqh*X7~@KvBfLK`JicH9!?^H1R=xHFA}iQ8sn9cyo$%m -+>n9BEe^6%O2QQ>}q4Uxbgz|2nxkzFo#a$jC)rgu;0>9Ux{@F`Z6JVuxSiEV4Hy!}!&h?#7VG9GhqQRRkP2$4MUiAz*xTi2#gd3PPnM{g -?TCMFF#|%q8lZ^5*gURPezphoQ&aGv5|vDJ;%ol{f!6 -+f!97v`g)|TQu!#4Dju6%72I55T{P`wnRLl}tKS>X-D!?4q##=-fe^lxIChtfX@+kf0zz}r;Dt*ra8w -8;Kn*!8j-Y$)&jw9o-LO*w6rt;*@7z(;EEDC}1cu=)Fu#(j;O -whQl)k8y^*>>_O^=o^%oJ7*FHnq7W566d2rP$7^z5Xh4XvTuS!IiQ|?gyiy)OF%}iTY{Kt^$_*The_D -K8_HgeWuaqpaO>TI`py4&*wAmLBRiL;zJSl}mM6zRN`*3G^~`|4r4RL+3KB+AK*F+V?Gm#{5znfm7%O -y+(&0P#wBneucT+0P)$iRv^79VB@I$?PDo3cn%s~Oto{3roDLer=bBh$7$eIB2aGqyBvS#m*noC7-Yc -3w=d{Tj1Zjl*P;3)a2f6`FDnu1D-k?PdUxFTf&%25C?z~%YaJ6P1uRU)IPDS!BK-ovCDNongKuF#v;2 -6O?Brq#}LVphJJ1vGR3-n>pfYs0A>iaf&*#3I?S--fBb&KMl$lniWzb0NN*R#B)k0UAp-`;>;H3glKK -ePA3v+c(F9rFchHY3_zhg`Z`Y$FiQt=2??4D -_Z-h&&RWVJOzH*mIHvO7plgLOV?B%!H- -`dN-~s;n-WN?S1%R%}lWQUmKvlguW6*n0CM#0?H7Tv+BP_*G|qiF1lH0Wbv?Sd0~~gdc4*>sQve3QYk -UB;NxmyVd3JyMZsTM7AW{wnJUIoLg~3pF}ZiH!ZhRbGVkDsQn}x5B_s@(h=+$)DA&=rKIVbhw5E4Re8 -68pE#CC&}NBA7Nr)CE1wRIA|7ZgOqOP7!$9OCVx5uA>j7EJk9*65L -`PW4fU2-oLRr7TC59E(FgfA@cfG)wZ(cpBo0Y7HMCfB;f`C?STi$tvrFK9h;d)3JFag-#pp|rkFUVc< -^0TdR2$8}!dE1Rx~$(rU23Cj!t-zYPMr%0j|kj?>?I^yfn)fUg1RBy+pl8 -VKG~6D`wM~nCxS#^NVx(irJ@rc1U8;S1W|j5yW%lPe{J-oYvxS5wKRx?i&Q921$hl=D(~ZgBA7r-95r -HuR>NXhAiodu(xyiSVDwJ{OK)=-to%y4-!LkF?D(e56-B1`)ML~u(3^ -S9UmFQ%|%Eg71{13Vtgo5VhL->_o7q&G>82a_esC#>jOn4ziyK5HwcdqYQLtH+%qPsbbg(lhcD#ccv6 -5MXf?Fn513i_mw;12bD}X%Y2~Sl6rmQO^ZXGD}07w54!ek!X{)uqn~bB@2nYGjZ*6*>w}9no-FL9H}? -5mYWB@mV1Rd3!i(X{{cBy>93L}Dg7(u(dx96I1=7$CDyel2@TjRu$3}JHXx -?=Xtu3G%qX)bVSOU&;N}@ZunAI;wfz>cW?idt^3HXu*cY7Vx5WQD!sJ>h`O9}Yl6JK$o6zbRbF2CQ=>az -d+!|G5Z!8+>eT-hs#*v-xbTtfe -Qz>o>b_G__O4hN~-(XeYjDF;Q=HtoA=9dJ-|~kA8Lc_vbxuL5uf}dQCGeUCT@GhP$C^z|gEGo|)F4LQaM@ -3jNmP%O2-*y5%p?j=_etCW7VV@C%!?1WJ&@BXO$Z5cUZ+_9Gi>p%*KxE}DMh>>Wf$AIp&=4)-QlH?yk -aAZmU)QUP@$*x*7Fnj8w?XfhSoX}RE~$ytQ?JE(ej%t3!z4|lR^C`5c7>tQX4O^kPZ7A4)K~}Pp{I-( -i04^5&%Y)!rp4#@k%2SVAiiY{;SbM1CVq_btA2gJ){RRl+!veNW0XuslS^tpL7P-`(Fnblw8furND1|tn21Q;PnpPb%!Q9DI4Y(c$B=B;DQFyHU{kfl8a{81x -HpSxmbIeT!rF7YEv;}6dR>eq3;nuyjpE>b(y`*q^IP|halIzb#+IjCIrM=~FQJa8le*;=AmPY7TdyJyl*qFMz=S+2%ygCq^4WbYjZW)-jnQmIo(+SUdHo5vYmLiJx_K0C)R8kuQu^299Q8a$ -yni=Ne?zY1?jo)92=)6sWf7*VB#6?je;j5u^%c<(QJ~x(nS9M?GPm<7GtQU-Idq<+rd$SK8BRWf6P6` -KikxJ#61I@%QMkwzF0yH3d@SP(sx?qqQ)I)76rKaQ(re~qB@Hu-t`h|FHC&1!RpV|zXxGrv^v%kmqU- -}1w%<;54u~y)k8}{dlyX-L71?99NH`Z+iD!0zX`E*W({ytOlTK3%({xz)q1^j8>8qsh{A$?r8+@#zm> -tD)krG$|*~7ZwQbxiFE(vkkC^)DyKh$+~4Uiv@o?*AwqmtuFbtxnm98CWie0RW;zu;9lU1Hvsl$Yo{6 -4jFv(hxy;tMM3UmshBpBC=y1SoT6MJ0-GCe|Y|%D}bpJf}fG;`GR`F{^BN75_ux`w4%)I2NV7Jl -$*)kiqe9GSs&F^1bO6zJwevJ#i{I9*d@5)bk?oYqw@Kw~QUs4ttVxhV*fKJy@l-OjyNvBb-f0|iwQWL -h(hz>#Ydk+?Tq}(0SmWBCLf6n#qYIlBLoeNp!jEmxPa){CAd4po!Di&x`iq31L^oa`_;& -SIE%Ae;Lh$hyP3#@CaM;ai&Y7VZz$kk7SyOC3&C{ZL~Z6tY3Rf?AwkWPXUWJ{UAt!9^J<#kP(mI> -5sSV4IUJNB*TObz_Lk#Cp(+!IvUgpUkC0`HHldR+`7|l9AyWq{08SS}FXbC*NmTT1@YK$8J>oB -~#@+1)U^kpWiaXSz$BZ7X9*Q0Wv^SG0!rl%kvY3(ZPUXz+sf`j%EFF@bRm2Ptev -lQ6tMDRv{jer2LvIH@(k|No$0Y%^?U8btBn}C+P;{%EL(5@-*izi>B56s)f8jRs2 -0vf@q!{rzE0l)YBe!?r@!lew(g(G2k<=fU<2EC6`WKqd$8L%Phx)-%V?u@CSHS9cBlkLSDXbOY8?>bG -4Y5g%uD9?>6gQ>Cn?_s4dStmgp>BCdF^6}p0Kp-nss|sisxj0MLW`VQENs1{UmFjY1TGFrODQgg`(!V ->rGGGECLo;EHeX*Cj@t&+2hw=07B6cE>8n$@vrxLIeBLLz&x*p_vjCzp+C4>HXh&G@>l)WKX(!Bu#M< -@tP}@2y;;@N$EYsiv?9zAC&l)1LK&mTPn`CLO1%ThBy+bcL;KZthm<0+6}g_!H<^zZzFsIJ0!9* -HDBSuhdj;;AT|mrtsa7krqAlgX9iV;Wtx;J$+ -n6usNcvQVFcbpkvtihj-$ljITg&RAk()u)Ilv>`BLiIP1~O_?7!w^iPpK2J^`l*kASr?Y3)TFiE!GsK -Kph!X?##)&jQJiNf;8Z>uWF^iCsO&$lo$pHst+LTNB4k|q$B1J8Ltr!66rLTQJVy8vchnR~e?CTw3d|uJCq(pqnN%X(~884m2w5o5vt?LLhm<@b8hL?BRG6Uo?$lNnhfbx_&?+}7+AHtC7(rT -$`tSBe}FCR7NV87x-#O-_iC`?@eC`V#68;Uqen~?<0? -nb^+_d=yMZ5~#w`QX>A72zVJYBS&=NxL2f;R(;L#g10uPZ|D5UiKLdgP06$I06q$+cM<#IR8dJ+Ldc1p@AgiL<=&q2Wi-hd@?!Fk;|m+SoJqjBiC>rSb3` -MxF1qxq^uYV_-84klH;_v30>#W$T$CQiJp+V6V7XVcnEk3wG7#VmWb|_6@t3v7_z(Es#jYe32&a{HH3 -5^#QkXXs&}uy=WzQc75_hBvn9{_6Ckik -w`YW*dU;;PcEo6qZ^aH6JA{G1eTv8#%)>VOOaPsapgueS8go)))ey_B^l%>^CcVZg&+O}U8~JpO2c>v -cpTw(Ro0sI258jXRCQv#$8}dTa0^Z}=8CLc--4ojuLZ#0yW$k@h77jsQIr>^_MQP=1f| -j8f*x>&2GscRR=CLiY>Y9mShm``RPTd5&(s?;@mUSskS{zx|Tu{WMg+_Kw7>O@m7Y*xYPXL2W2JCdu~dAx -?3<$9Ax`1}95PZLZ-*A$p?^{Q>n|fmZEigw5NsVIE!-BZW?-f6Pi7R1=xy)G|bT8Va=l@SazPz6~e(? -Wz{oag~Pt<=tIe|5DBMFIhge0ye=@Q+({;f~NQxpHqE}e31HMo)%Y~1YjN^DfJB~o1;DX^XR;xE!%{O -4E4TjI*xsjJ9OX-xwB9ALB?4K=Hq(wbYKl4*81bz+Xr5^%2xIEJ-GX=oqbs72UM0>xA*abs@xu(Zw%h -T$#ML!-4>bSR7>q~om~8UlJp&gXjYDTtxk0nRIW^ZC>1gC>4CuH7VBN9{FF&|lmJ@g=CpSvn$v1t<@D -LW@D}Tp@thMNr}mC=`b=OXYJ!|CR=e?z6((zM#cgt-zlID<=g5WkH6_aH+``v7{iv~95SrLA)rZF_2U -tIPN}(-)85qLos3a6%rtN{vi~iu64~Y6dvB83TA$S=QQOjsi60MMmS5(&OrDlsYL=%6 -8}o&YlG%N7r6Z>u>bxNvI#ivO?6bV%%h??`ff7l6R^V+Za?6BG15iP=&E~Ugr+4hOxbhdqdwV&o)PuK;3<4dh9_KM(=6fpZBk^d9WdP{6vP0{ktJq9_ByNCB!u -eGh^JMLzI*<_7CCWF=RF2L*~?A<;5UAj{4XR9b0eNB>^{~i=4Z*%^Y1asR|*@42^&STyJO`T*x=V>i| -Z|-c3bB?}c{Gq&Q(c?V=W0F5eiif=$*&Bt9Vv~s#x&1qU;j9@1EHJxw! -!A^?G9$oDqFS;Jpj-m+r4emN1QCr~2!@Au?$wDvyQ?|*OgnFLgn71oWC&uwXqCP+8`?OW8r!3YASRXe -AxL~_g+gYqdrQ;9E{3Fclk4)bBjmgxb4+#u2l6>ynxc}SGIE1>;qg#5vPYzo`=oDOft#1KoG4lh~Er< -bN5>8~{>3C6c*!nU+J1eqO6Do6=FCjt-1#UlWp2(>^ -*#6a|%J@=@F1+y=Tn$S+zlP`8hRrK8vGat#g!qJ#ZP!L*3Vy@k1G1dDJ@~uj)7y)2eCKJea(1(7*EE*|i`~q|BU;I-|hIO?XD6 -4gt7tvEDp}BPMdlnbOpwn($jI5zjs|ihNy@5 -z!hI#S!K4N!`m+EK)*u7jqgSKrZ4+7OJx8o;o8IFw4@u}*GCbQ7x)yuRI`296oae;e{rs5Gy9}dum?e -#OFEiFXBaQcOXRLo7b1nG>v&IYk%W9_3oAQK+%`rbA#}{M-#IRCzWsT&pN);pf|vQ2P!mPus%G;1sD0c@*dV7}J-LI@O -3eK65P!sK)Q|anDIM}ymmom`Qao1KgwufidgLMM3uaLNf|(;vm2Tk^ZJmbM3ugDo!zCt=WfG3Xs)jM2 -vaTOF1UA=}@Mbx^X>lU&xdp}8b1l`Pb9azmbKGAGS4zb4GyH6r-`y!+Ero}na{MX)^kR59(FYIzgIW^ -hM)Y-#SQi6q`rRF{_im(^KTV`~=Q?v7z+A3Vo0K< -^Z}$5~%%Kvt**g+Ap0yQxJ)%NA2h4GshEnrl$dEo!dm!wVEBJwyc%p>nRNX$0|Q3P-U<;-8>FK8WAb> -+o9*T(AiY1-vHXUJomL;52^qFTnF};3cYtpC_&)^jmk>UI9FvdE;?3%GMpHUNOZShoy*Q-rS1xVsd6I -QO;wT0x^Ugx??}(-36(mfOqSmGrtcoO_^iU!xk-7bu|&Q1pLe9SK{2C(G6prpU`7LpI})eyE;83VOa< -VO*M1=bkK*C`SKCotm^h{Sa^=apEmNRQvUQRe_Fzye#xII`O^>i(<=V7mYx{xL`ry!C%nXW(0g0>hO? -^kA$@BmC%)OkX_Xk~o{>FN0Y4Lqul&kqUGgB=3;t$j -i=M%~I7}XNc8_`)T8HkpoK1be?=rD%`C?@Q*aB#oa2SjxXp| -o*HQiTrSkj2ia(A1xiNbYFzy^;3iZ;^cbAJP`6F16zYoYo4NbS&J~kMT2zPcAp?&Tq0Vd9W?~N5J&0U -|jmb9cN;YRCNR3XB#z}E{{CGxB66SJ>7J~)lWcaVu+v{dQN!{wNAnmWM|h2REZy -)HEi9a?Pe(jCHY35SsGKDt-H2Y$b8DBc_E_z*cqw!+e=LsR&QU;hav?NaZ0lt15MTt -A>w`(4yx6m67uOE5{(E_ -C8?kNM=`vdj|Z%Nw<`bB&yM4;r%3#o8*kI-i} -p)c66LqFB#Ysq){)thqnal@fl0rIqz&HC=d!?O#|{_?9s`%PShM^2r0^Gg>8LwxSDVgYpe3LKV}FBS$ -;t*Tp9&K!pU5;LT0!=*a1YC7j+PE!XtBIDR47H~(5u~smdL}lMGFSv{^_u{{u__0cBzFXibF@H#aM|t -f|mnPSn6T}7>coLR;c-7%?M3|Fe**9A%h@6A>z8u+CH9`W`w`k~7u4H*0P2O}8~%h{dk2Q0j-jjp( -NEEYFeR0z0Ks#N$7bs7PCPK(qkaiuDj7hYUu_txJwH)SOyo%qV3H9uZp^Rwc7tw$WDUe`F56FM2kX0e}rH}9?c);^7+VCX1?(;KnMto2psA%*mK-g{=u_Gcn!2?`xGRcros3OEVJ -Vj5~gFn;xx!kXL)G%K4{=FXqyt#S+8+r89t9Shd1y=#$kD3&Nk!mK;+R@SdR%7TnYg34&v5OYqKsEqGgtDO7n!PEO2+VDXn?dbbOlasjVu4%`_PcDBDV<$gO?68 -jRAlgJpi3YBp7P3S`%VLhxE*_|b9z_ZKSF{N>KKOc)6^vLw0K@F)$(qb;<|y9xI&a7CA`Dc4_;k;PN#Fz5;~lEVQ1TzV>Z^JwAkEluc_5iSoRGV3yuw -h4y;|{Q)akyc?n(yN9NM6peGC|^uOk5Fmpky6QWWuu -QJyD*A`xZaCwl)ct#(;eUbf@=pKK_<_ep||+-9X@5d&3$@J(96E`v5zG-b88Bjh`MzQjx@tPAg5LP-L -~pzh>)bmg*G6zn!c`jjN3S_O=&y|T!P_ -gMpw~Q8vy^C&VOE2tHp}&n0%I|3s`aCq(y&z*~ua!iLo^_JdIE`L@)0WUg6Vh(Ws|3oUpAZWPZa+2FpF%V0prG#NIu}6OXEw{he%_ -e_$mW=i?^5N&7Juwz`pJXt}^V`GUC6Viqpi`!36jq`=L6VixWT`Fd86v)Ufg*G^Oai3$yNryU(MTh-y -qOeS|rKww2#!G_g>(tS2ul%=IAbF!SuUX*w3Xfw?NMdnN4^mBRlK^hWjLt}XqBCf^GK1?jRY()o6C;D -##cZL4wyVRK@$gJ~w&~9JXxQ0REa-I)0(H5G04~ypY!V=tORzFN4KSmLc-f0!qjYN}nl*0Yx2Qe-s@H -Mw8GrCRkl3Urx?%r9j68A%^Z`YCQoAqjZ&oa7ciSk6{tT`}Ty&er=-7WGYy&0N!Y2&=1BY{znB?(q>4 -1XyK9-X2GGlyouI!1m5)t*7QtSMTFmSMC=ZnB0rYZg2Me630-iZ6ouBEw=Iu?}U9rg1yt^T$m=S|XF@ -eTES;^A7mf8D*W#9Jov>Z{|3$S&C#-gQ$NEDpevGtx_0R`^i5e#CnuAAVqiNVSdWf9yoY$M_{t;v|_wE$kI=4L`YHuKw4t2wYaK8+53T?u#1$_jS-ooAzWp5W%Oh00W!QnAGq7RHP7&!t6# -g!aOfZLD<_B4?vI?YFKp%1{JXJ00i;C0_m2)zyd=H7Ie+3ExSzrU&Iyo4w{vFK~w?scsVbs!27ho(J# -3AP6)QqO{WlSF!87Y#p>b?0vp?L&5VEoueHY)@cMRI!0(8Rk -&CF{V(|oC9E>Mm_*dijKk&0QQ90Nz_L`FYY@a+rWQDfk@{;7fF27};RNm^Jw9i-G1jx}&p+6*>WSL{@ -6)l3CA#4;aN_UU+yx-F5&)ex^ZJb<8d)b@wM?Z{5=nAMV4Uek2yv>mxPkufMJ*)c{qp;W;ui8S&aL#t?KLJ7dS_p>mQ*Uw)? -{)UFf`HE6zLM2T3o>pVLt+%zFDFKN~+8?Qx6UZ?70tA=Z3m>M4%=$^=MBY_?!(pvTXkEW`0B+wF0<2A -Ey~FkR^kOEEp%PFMhS0Oh4QSyFjVZ{st7@wV*2rAD`9BH18bq0H0USSV+zzuOasiO=%%-bS-LCj6AGx -6v*Hx#4(`UHNoC3R}W+vVi`>JEi*@r8NmSfY-=*;%fEsH{%W$@=$fmn}g04>A((OGLtYM9diCpl?k0L -hzk!!P~V+{Tt?1P*ygj$&8;@+Tj_VpfDZmn4x^)G@Z3{M1E*$# -CaHSIntgmyqqVIykWcw~rWgRsGQoD0^QHTsl(Th*Py#!lZRv+>U-ytxmO3#%qbeeWxurphV)oJJ{Zmn -^NttktJ<-|TCQrUVN3Ln=I2;J>ftBz{I`MK0zK- -wwOsb~}_SgliZ4bwhc$sPNYVfBk_j?PrERj?gp={-6Z>@FH;2g+EjXt}6cY;7@;`qo+ED^*=niKhS(69LrCcus* -H8y+^>C9%8hz#;ahnoQx@wwMl-mKB6YQ}67oX95c;ewB?Ajv4sy1w9PNSK~t$ecYg3id;8y3K|SbO8pNSiJN=soygGV=dJm$zIIdKmA;YsJ?AYv@- -EnV-KZhO@%1eZbHn$t+cpB$||2Q@4?~ -IRus1E@zg%HNN&GM_t!2v%zrY$m_pWmm6?k-W7)ddJ6*n^S|1!Ntk_O-@XCpClmK!+ -OL81uMT%Il=qSnbPDZIhW%i{-lJupkWy&~9#F?7_$Oi}lE}^?Gsv-h;n_+x7n3A>xg#Lhwf>(zgdOWS -dw!G*(7bcIu+#17GAWvp2G+&r|Ek9pVihkspj@fC>tr0{QmP0lBy~End#@fuwJPBK=sTK&%E?;;Mu)H -)5G=C^KfT3@>mJiei}?W6R=?6o2SJAv9w;Y4CNy)-)S@+C`TP%oHK|>bOu`4vbhQw?4vlN8&n5}MA10wcxtu9h-;{=GmRwu1X02YFYdh^L-|k}{7qhQ@mS!pJRVi4(I22y -~iD#9lD4H==2x8PF@y6|PCK;Cc^c~UNgaN&(q__Ir>Wb06h}VpHBn7QSkJK@&hogso&T2#6d~&*y^WC)8vVs+DWmR*LzEAJ=2G1ZlC+(Ksvq-Se -q?rS`Gk=XfO{ub@i8znoRf-YJEGT>#~45-r5ScP#28J?|w`bp2>i1piN9{vXIYLk~ReAf`;#52faC8R -zJPSEQIzY(cy&<#KTZY-_>iW4xqb3^e-mE9#s>RQ_1T_L+`4FLk4}Du+cIr|DUGH+s!8Vb75opEMZH~ -j87Der*{WJJ;oVTcInXo)T%eQw?Uod+aybuw&2|9a6?nI0N2W?q&36VTViv9sh;Tt$|+0Wg47$arkpN -q1k6w02gVGQcdDzAxAlJRXOESLIUny+J#1GoYerTuuamxH;OF1VIU7WLfPrEiy2BPCA-)DWjosY|mAR -YPf^HDr9t-OFtwv`Hg=bs5me0d$a;4}W&_cL#Gj2{fvqCHw^=|=k5dq{wg8)figHZYbCa=Pi3(>t@wi -{7s5%QwkA;SwocEbPy=2!sCq>2K2UpU|8vLy0 -LqygfT5srK9IU;bQJ~jyW~Rr6vujRSF9}r)%D)@6CMjo8T`Ho!1W^G8Dws>OD_u78GK6l6mrmp1w=3?cAt=KKH$%O`CC}t(*vU -5`H(ef_vnsc3es3B;Op5B-X407X~jeMY=ou8N>|M~UHUMI>*Br1F!BjV4YoqOhI-ym)L34y>@e% -6Np4E>Rr2fsmG&F8=id|o<-CHKLG^gC_Jr)K#P)+E;Sle6T{d1$4T+fa~GOSZ+0`0fTa<0IHR8>ncn$ -7wUm!#w!8t#{$gXbi2{r8(3I@ouSkR0r%Act7V+3U@V@-b2Os83!X1pn|Hbr6K6Vm1#6BooALXw4h3og|yVL@V7k9HRCx;HK`|3Nw#a+ -}#I(L8^7CQJ@>z|s8v(`|nIl)J|61gvQ7p>+_(&%35VJdn<$Ni(xy}bbhFi5c7|IiTg*-X^ -2mI*VdSS^z-B&y&=IrdUGm*SG(R@lvN09%lvg9XM|ocakGmX_$R3Bdm)dzMV^A3>m+}917y5%9Y(8e6 -_xIZ7(ljoX+vqTCD?`=Si{J=kY&g^be1d3Ul*8)r6*wNF%)xl8wQ#sNeP3^{;ZL<{jB_I`AYR?TjSln -1D+>@|nXi({2Ec|!{iKE -;dTNHw5P)SbQ@0tuJ?#s-E6L&V<+$qcCz`fs`=)j$6HXOL$K=gu+%Z39to@-ql^WDBo*ouyCU!<=X{) --j>AEdD8wjJ%YaObmm(ZlEt#j-cGb13-BHBjBV=snxFgZ!YaQ2t1|k4+HWI&0a)-L)IBCCFj7;aG-{k -?4U~1L!PV#jA^cX1buJ!IJXjUZL)`e)^gk2Jt9nO)5GubD!=pP+u8mTg3IZ^urT|S&>vnB!%sKkV>Oyb220SMB15{hDihD%Afz~O#JDiE`&@ -_Y5N^*zZW4J@Jc`m=<2(1QE5k4|j#QmYKq6NZQM#69033@blg0@pyf)g}7C;C4hv0<%gRO^NQ&tLS3? -$e?$_cY+n#oYfH-wpad`~M&OpRtCx|1(CD@P;%YINHoVRaNcI6@ugv04y)OY_{Y^Por+$E>@p;I8cO8 -LftDcx`tKN=qNI*y=>6+dC6yJpG1DFu$t)htYKUL&&zaO^I5~|c>?+SddR2w2fI;8AN?NIGryYbAgJRppXY`2zAf>6wR;-5J0F -R;J0G|z?n_D$%L?YX%7hU5qSE?J$JMf}NJWsF2FujD!z|nJAtx3a!LJR2)Fhd*I5m|)l81Z)pxR1L&S -I!E=PSq(^L>UfitL@gIMogK(L3gSDen7R0f3o*E$(Oce8 -<71QRQ@1BNKwp9#md6d&%t!k>{Gc13Xv67Q7SQ4Ov!4^iMkZ(RURY2QxzRdXAQ6Tpw_V)vL_c#(k@g2+>l=Fe8t@xF-JMgg~m&8Hx0VwryyaEoLh} -TuHE%6HEOh6F=Nh?CFC~VwK`uivfyV=m%TV3a)TFO~Fd#4{1SA8qC@2D7f8J -Low5U-)(0>N8gaoQB_Y%v*W`eKuF;@iY_+d4cZITeipDrI%9%!(IBpST*AeZ)xPt&_~*bFO)sWeO;P> -VJgWv8fxLr(WTL;yr5GS;dc^jwCXcC@}=-QO&$Tixk4zF*IVq+f5D^O~_9kgc^QcL6Ai~bn3Xl<)jxMwopH&!f_*e8DWjj!=6h*Z~YfF$MML}}>(l&HQ2fhvmxD -ldMQpo|MkU-x>l3|R@bF}yfHA)2*O>aoAag`ia4Fc+34EFfWNoO<-{ygO}!8Snagg0vJ5^}g`_m`!`{ -tgJ#G>%z|ge9w+-k#2&PT3r}JmaNMg16Czn*OK(um(l){ydu;Y@`_N0^2)QwxBPG9m5bT6027~8NP+# -Jb`P86V=6o5XHhxBr>vsxnulpc$|MtXssIG`ViPxg(f6v^_)!~WM-sFha47C80wXuwOcE}>S9Lro?p? -PVLugu1C2&E=GiS`G@IS|!dT^uZ|03R0C67177c?k)^~i1acp~>-5|1?1Db)5~B+}IS9~qIRHl7n{s!@t$06)|ySuohtL -qEd6OB*xHVq-KJPZpPm%1N6L{D!_(+vden-{GDHT0N6c7&?@aG7_kblCgFFqe#oxd#wDOPC&waIMHeD9Oo#_nAiJ -dRj9GOjmx7F#RgX|@D2n_D&2>EaqlBOxKO$wsu6oUN@z_=SqlX60Z8R2yN~8lrib6vpiM1?W3j)I8SR -AT{&Wl5}nBq{OHiXBaO2@Lx27^#}+1cpR0~bc1qSyklFjTAuNoLtOQK+Qo3o)rGe_${QRZBbyRhrq5u -C|*JqEP+Lkgy&g3G4O5C{(BjjYpw6k%U20-qa+RQa*B=)p3p3_%h_1|7{?u*Uw%Mh>FWrhzzz+XsO5} -$ZV}%gK?_|L{FTK$D_L0h)4Attf9M~hocha_G4}5MWcH6ow!IQ1eYX6qmmM$QC+>&^c~Tto_);p{~C?z*c -KGJ=1~RT8I5WOWx6^s)5W7v&EUX` -_(`6kz_U)m8vX3GW)2Hnz=|+Dx>t0J`9e0*T?vC`fHAEY+PxSgILeE^r!>8jx$uW<;m -DE{T7A&4_8GHU7s?Rm0+;s#3ozRMppJBUIHFW*(}l%lw~0Rc$o?n^0B1FrO2uYQ6cKP*qQv&k0q9*y- -F*RSV4tp{njM$3j)1;>|-^>hnWYk>*5oouEaC?v013nsTu)RT5GWbOK=mkRp)*#<@|dq-d8Z9;Hf(?l -S$`C{-kZq5d--rK&WF$18C`EFPt*l)j?#e-)+bZi-TMJ4LCwg`!jy@+egW6s0OJ7NTldq7e2O9~oyV> -KDO(8?8$9y&C6O_y70BIab!J{pq4Ho=WhuM{(=K -hCpgwLsT`HjIR!V^WX8B*T60R>aby)D1YkXhf*uMj4uf6Q=j@i|NL;S$mU?s{n=8^X`wE8;`v`27V6T -^|5UF;QHS>8XL%d&v%HORGkwynA*WHB?O}UClGtpvQ#j};^i>x1H+RyR=;f*}-pjGjP5jjm(?WSaWLhP$cKU>l+KVBQ!uVMZj5gtCKvMT$Zn8P&A8mN*A=0tlNFHW+ -ood}3_`GTYIkZxvfgf>KRSD-e9@iQP4nTee#$tziwMhZQyF=UmZ@!HUGHkY7k5uGypvNetWz&%sq6np -bCVp`ZN$LA^id9x*1o00XjQk(=o&+qaBk3L(V7MGmP`u)(cqDkBprWW@WY9M{L{vNyHG(h*iZB`8c*O -$*vf`5sNzBG1CNan6+Rd(;%Oe+f02)*@CLw0ClKYV{5pw`W!~3hc`watvaj*aQ{vCW)_1#@v-CccE&( -P4PjfJ#oIs62B&9TI*&)e)C)teCOP5W`&o;Vm4GQBJB!al4pc1o#DBaRZ%zN56jGv!~`& -GSjtCl!jk+Am6L`JqxV}5Uw2)BFDqTfb8j=*ijsIcOxrzAgNTm=EmSlP-?*avsCK~N7kk;!zbP(7Ble -PCn8|PQAHiu{=`?tP=QyN?DsTV=K1U?*Q!$iTXnL=_78m=`l}nyt8Ax?` -kiUD1ry7_QME<}Y4|O*z7MSfm^B{Rb#5q__<)-o-d%KN6ih62v)hVxa|t=`N1f5e0Cf@I6hwrC2 -Zz-7gnn#-*o(FRFESUHz*uj{Inb4aKl~6b70sNm%aE(fB2`!1!4+$liwO}KZP`WgnZDne|I@8VA$-4) -IQ>L6E^cm_8Uc)Y=|2r?^aZv22`y$C-1;@#*ZhB@2PKuUzYPNe8l{>z6@1(a>shzZyKP&;6=zkZ)mLE -%Rv%M<^grK3Vi`MWi+EnH0qVw9i=naEthcQd-qCM*%BF8?6wBO6DgEno#L*zpOUZzz(j8u6oIN4Pf%| -@_}k1)Lb80(#1-iPmZZKTotp1xm1s2p;gw^>p3Zc3tb$t<-P3$4h-pFzttR%tX`#`3Y0c;GGAsBiOQ2 -RVYH%8S2^dwr08XF1FsB^l&VC4uT*@!9UV%|}qG^sh&u%SkzPHXWUNbo2nOaYapHUzokU6qny>5WV4l -U&oW^$G38ZLYz36k7@!k>5D!mNNa=Wl^^Tt@PeSuOVl1^bG(70GnY&b$LtvuZ?4b4iQbfo{MaR86J~j -Q(Q!xr;wG`1P#Ukvj~V2kFR=I{>57}698%-y24}Ex4Ab|n^jQK~#4Llf -4p{_SeH=r(#c2ue{dcH54JA!*q#ATOrVpKjGEhtZDGKsnrSJ5~ovhj8x=AqpyZ`a<+F7lwy}Pw!uQw3 -Ut%Oq~K_{b@Cf^*??YrH?5~-d6P)VAu9xrPpmBgb^k5>QZ{vVq6V&J5!#0jV>4>Wr@R6fUyf-L!)z7c -KKhOtKRrMx9VnguTfTvqbt2&EyHgxJ$|0Tougb=dU~eT=14+t?Pb;5Kt!K^5j< -K})7MU&YSg-KcU?N&k-lcY3zH_$e}xWZ8A@H^nKTy_Ztaj3uitdV!7LAPO185dHwsU`LY+yMRJXj1W< -WFj6>ug-W8P(pj3QVGt;LukE)0gI2)K~BreIpZRUP@@yVt&$134L`jy;We2`dA4Ka>I9`7w{dUTHL)D` -|M-USCGu{H5!F9s^D4v`p_Pj-Jf_m!z-EJ5{o8JTM!fy4-5|jE0hXhs;*PAQIClv?SLybDo6E%{g -36llS>ZtO9iS%v8fP?I9#yMfo`hPfFV@WekrgN<`7EfGOi3@>Q@*?k{Z#_;W)b$3XagV54Xhvlho+!9oJN;6LpXzfh4~*;sMn-r)PrHC?%$t -N*v|Jx2T-n5G0Po{|4iKz41SN;pI3-Q9^8^^r3#|A!o2rI_(TFO7A;;jM7=BhxDOTd4S+WnfXTsR~YF -V?c#J}Y`Hjb3a)&Mw@e|Zh4rQ>cy~n{F$K@*io>T6Z`6kebKm|A;i&yV`qJ6M_$Hp=b^06M#Csi>yH5 -{bVM-EfjKz&&&+T5ffb`N-J18OZ`TSC2f!e|?>PfCq^_fcFCjIrCOX!xOi+2g*SYsWkrTcPM&eEz2JRDv^d=bWWZSXOa?*2vTBF71Pd}P=hD7B -blP+MA;~PU}C-5h(*}(C)CpmVZ{=PVYF(c%E1+}6^?j%0zR&&QJe^IsF6Y;ng(f2K -n!lxV+@pu-r7*WUYB1lZ#C`WxCG>Ce=}Gy8PzJd>79^(OQ7xZbbzjJ3B^pig^`d!*MuYmieuq>@tXD# -J&&TU5ju+%N9z;^%DS78^W9(6fw=w@zoYNQ8X=nk}3DW#}$zM*1#oirL`sR?D62Arj=_UBJU~-tOY1> -8}$Zr0fW+o=zxVmvgxe+>2W&0@0C%w>1-cIkdQXN8vOU2&aQbKf!J}VmS6lEQ>^d`3re#v2=#zti -#~v=28zFT1WE~YgAX~h{+FB{{*6%Shk)JVr=X-M-V9SJ0E58fL7PJy0KCkoC3L!_C64~4Z3&BQ+dgzYJKq&XdzWmP8(b?1v!izADu#b6C3Wf;lePzJ7Py9_RBR -v#=@)GH6!7FFMToYx9HzaTx62I#x3Gd4cj7~4zMbrT4@C-w;SHJLrMcJ4o+ZVdyPt*7bd88An#L2T+Q -B2l(!zEbki5%`-s3PVqfHu)Phab7vFe?I08+jajjTvs%u%lFQIx$D-2MMK2Qe_Tm=4|`+%$8ldd$J#Z -qB@90O?D&@0J7pYRkyTk(R;>P2))re^K?zfxD{6x0H?4oa@Sr#o)?Lh1FtX{EVkh5B+lEtJ0K2WCk_* -N*3>Wu`Wub}=9Z=Gyp{Cr!beb_Bu-rO95^2@yx+*qix{!5t`gdDbVyUf6QZsl|FyufF)3wp$nRW|05I -mTUOjq=Wy3v>qJ}RZ9Vt5_kxX*-{|~mDl^|Ou;d6F`H@~2HMH@>Ac}sbUFj?eyWg}^u-V2I8oFHIi%7 -Xw&>$?Xn&^mMXqiLI;G|T*cai`kyu=#^q~@JnaAldP6=H%hxRg;?o$*?T3@qtm@dgc25>C~GcYYbJxt -dM73miP3}i?BfLOBQv}BjnlARPvw0=@m!^q2Yp}?goYa>Xo<}#dgsd82vm6K4G+Zb-ctp@r8b(lQ*zP -6$9jWQe>>4Bj_z1vIG;zxxW!`Bg*Dm7PZfeOZfmVj&mF7MDQ+jt1yV3Ll5RDm)yN?h_eJnM(M4$%-e5 -{5E-)K5s$1Fb2cOG886X7_~gjktW*@&Do)%ore`_EC{^IbK}v#DYXR{B -Xij+qPm7u)sIxO>n7Ar!cj9s3J`5xw{XPvYBX`e;^>75z3*&5c+3^*)==b?WRIs(4!pp6WK)HLFx}4; -kR(x#TsMtW^Ekg2!(qr(UxW3q)bFditw@o@-VSSvlyZqk0uGOfNd%5b&;jZ~ncDR8rq`}0)>(BQSRRe -t_9)S|1pY{7L>5Gf$TFh~IA1=<8jx2kOYVH2$P1eJX!@IM)Pf%S3c$o8)d@o(ZJ*D2D%|C(D7}pKjM9 -+SIb$VK)PmJ5+W5Tyg_F#P-23&B0_0cp+vwM`2+ebO_`cZ21MF$Cs(vwFy1`SO$EJ}RCNp7fV7v(uHN -;2xeTJ`NBv*(DvHYMP_NP6eJG&ww+YAQ47_nl-l)kDqaY?vg^HiZUJ3L&Oty|Yq -ko0&DP$Nh_`qy=+9-zd>*$p~s+;f$Ma!9cn_5Qwv?{6H9h0q(T^!qBEaYEW`Jht9iGFu0AJ{01~C>i4 -n71CzlQHoZ2!+9OBu}?+`OiFw_Fpxhg)Yx}YK48R>qxQI{8dFXN(;Cb2U@V=3FUBw}A0RhkHY7o-guXP3O-g+ -6>glso2gR|5eCT4@y>B5uvXbqr0l&Wfu^?>&xrI#A@6+Bs1Sc}CXDQm=wqTD^)Li>cM$$hV(>3}Jgyx -Tg7x0{qsLv?d9t5qS=#04Rc^}6Q=KV@5{cSeCL6~NQ0znE&#K&CAbr#R#Lh~7O)M@kJ_e5Ecl3F0#oT -4UihEVZM5a1I5AIO2a-2}I6 -h4Olv&AInB)6AhCwUa)d7ZR0B}z$@E+t4UCG%mt*nEpgde1CX7?tC3F)>sh2tJP8h?m7-bd5NqRL34J -U8LFQA=Q~A>pH0!Rhjw-lEx&ZXqz9yi4(g?+xLu7s=-~n!q1p`R^^Zqx)=9PaHWNA|Kbx`=KYOqML=I -%zWGk}M3K4qCm7&8?6YT;T1Ey51($IWxAqpH)TkF?E7p4A38KRKMtQ>L<`BjlmK0%40DhT~-W4WV?h>$@OTg#zWUwfEYBeT#GgAOtfH-O -&^&ORi)ogDhUE<8O*@ko2S}-eZin#DO_t7TESQLCI=tlB893g~ZnKyQ7I^F_Q71&5kcX#Jwbn3919M8 -ioTb(vbrE6dHFr5}s21=vz20G#@HDwBVr)g>`zhD$4lgHc=_$zs;o?wHFF5XHJz=B(IPN)E*xKZ9Fz% -t@s-zF-S|#e;h3+7ecLyoFJD@LBo2A7;W+^YsEPYPj;&E?daoENpJG8N(+toHkBu8eHk{~rC;u-Uwi< -=zY&|D;&wt1-y$PX=~?-|O0&`_|A?3j*iq@K5t-tS_ONUZk1x -Y*;q6)yJByRipd9tMxw5~U+_WjN8ZT=qJM>m(=CHY1&+E2o@e>JykQTMMq|K&!-8QcfwM#_4!+za1k? -hnmJC+8{STy+LHl~Nm(iYOOsPiOMhn%-^P;&x#uUs2EmQ$b -A!d?k>N(I#v)iHk@RgZ8t2CSBG}BkS|(8SbcMX(4OXuRS;Hl@b&8FAWj=`Jp2Nt?rl1k%{qBf3R6-gk6}odJe(m0c> -qI(%RLzqDF;%-U-n`aaq`t=>>UgF2Zkic-!Np6{3%0H?bKoXzmPbbiWk9FOE=hU1td3k=8JMxM-Yd=6WVWH_Ejl*1X05`i4X -a6BI;2Qa)5al-Hx#DBb#;yRPtXLP9NK;WjH>~BOhTnKI9|sXE=R?=Z|-`y`Hm&;dotK-pOz -jm*s5?$0M5ZMuy|#JF<=8_!yv^&TzadEiYntKH?UJ(Hj^Sm9M>BjE;=>u9iFiMTKaY42!}lVtWjM -}^lt2)_*sVULA;vbcUf!x1+z9AEg9V;CNT_y~rhI&|5yw7YxVe8 -09*KuS2|s;rWP{GkhE3uQI$0@#h)73-R3y--CD=!=FdIh~aw?U&nA%9wTQjq02+`;SQV)XSB6-Um-Ry -0UDAB<39~CO9wWw%qE)I1cA*MW;2M{ECQPq%qEE0q=3y*X4AS@O^x;~$o+18OBi^(a4+@v{$kdpfX!# -j<}kAv4mNen<}b`95^PQ~nlDHl@ra4r~rGo4c8f05*G>O%}7s1e>>+%|d2l1DjWwO#-u72R1 -J($(a*F^BR{mUZC!HkM!IE3gI -J_vi4oPt?IeDiR%3>FY`N%#&!m0}!5!VU1dFr0;GbbV4lu%NFN^v6KpXQ_9opA$3fV3pKX30T$vth%5eP-6@6Oz>?`XEW70`?Nzvop -!6Jqcm@YvaYSd)&ygHLACMfs&EDfZdAYVy4r@p_`bUA{~&VwwpzNLbWGGLr=3KeI+}3JsQe7zX?g}QV -iKF1hPmij+QzLgm*fQBBh6!f!mdj*f3U -#O3&3BL26i@EcEYUg0-daa7?q-eOPXxHwK8xZZVo`%mi>#TjQQ9r6i2G9d+i0H6W4KEUc6vw9DJb0e4 -!G4mT}&X$WFQ1~$vcAU`O?%1Lw&1*t3Aro)c;;Xe4LAWMTQLhy|58(+$xt%f33%z+n9kZ0C>Jp_9;ZD -@EZDOfS0ia%ZOi@C=ilGX_%%~w8=bu+8Cw=SiGnOWL$~zxcl$v5i)I}YWg=ZC|tni9X3@*IlF9sA|(T -YA638u5o5fds$DZDFi -;#AlYQ?^X7QHaNT1S*aRJ(29aPZ`OPhNeWqL@px;duNEa`vZZ6y+T}=@)z65h(qRo<}@oRNi-bN$&!P -Juh~{Ec-&1^~GTdo^q!7jXlqnB~2wXmkqzPvXy7oiTy}7byUb>H$Q@JKXSXUp~T*zQbJ2 -6P!8SjECs8crHiBvuhRH1r#EU4@A%G$*#4andVcSctn6e8wWFTJV_s7xU`5q~xi2-3oInplnPZRWw?0 -aFq{SR@)l!-Z?e!O(ekSO5Js;`)`>09+!JJ>MoDt?kmP -&ZPtN<*DkiPJqWzt&b%w3<*L71$5B$&Jp_CYb49OH53$2uUX>4F1pTWXVrRFOTY$@#(jXx;Y~V}u!G% -U8R6C9_PH_{|AtW?G`2fK!bidI^-^;_xS21*%&saL=CwvQ6Ig7^}n@r(x8i%+3;J2YpsJ1{OP3@Ezt% -Uw5n((LUYx&C30PrxJd+4ErmU0g|dPR{vxpnz>NQ6A@5@e#wOlCY#3trfNr;8c%17-B9xJMaidshN&c2-ksMb`V7x&6Md*gC11K}2?Eb06nMNd5=w%dC(Ixb>GzS0X(b>N(fco4 -Dr!JaLFh@Io~O!1&x2g_lItx9R54$RD(1Qg?7uS(19%vXIqO9gY@?%BMoDj{Or1&f%7b)A9O!+CCY^5>I?g9o=vRLi9rU;R~wq4&3_UdG+ -EPsyG3n^v@_+GN;v88kgiO!(8Oqd660%3fDvR;8hjt&N3_TMjvly+5DKr3DD8y=={-Cv`eCa&xQjhepJ1> -Mab745@WBEfmhXE8T`N1+U1I2SJ)UPl -@wrimPpn%Ww6d=e;!!U!zn>bs#@tY%=L}1~D+|jPx$mTHf4)zCU;NJXWH<=s4bwE%i!(L}p6bdhqUpy -VtMKIq!DbmzO4oF9E5LE%STzeGKKF5X^~L3ef9!9#%qUk70W_n@|Jr$D(gsQIoz1r^HI=2yg-lEHX=< -;C1GNVsJ_Hz@u8Vg_Lg+T81aiIYW$g)9==Gw!wVHIYz(&$+}=)N60s}J5{R=B@)bzAqg}+TY)Ys%kGqo4cou2&J -Mcn;VhT4YRn85_Gn8{Y95?Crc_u`Ckx|&j&a%8ff!+%>(ro#gjuPYVXyb&$9tUx=mpA-fzK^1Ss2CBcj(iBmSo8C$IHt55&rYor8CX -~==g<$mvLg|C(UkS|}$*KhvYI))lRV*SQqESc#sY-~g)b9wu(~i=SgOr*ybNa2*!GFUKKo6_~eQ}*yC -|tp!9=j^mSiHB2S2{eff*tydlAcDWFx0Qc&J$I5WR!SQW5MNCEaBmU-&9;bYY|l1q$MYctse-DZemLS -#)EQJbQmy8gHSYc+kP0nWBoz1Y?JJY3d8eHeN_PgL?*yp|2-NrxBM^P>gwaI`(3v7Cl~6|n-NN(t#4F -{oty}gxL1H)Df*g&;P@{B}6&U&fV{EH_t0zvFkjBM|z8I5+es)RW6)(pu`R0|blUh?(qJH0o{g-iue) -?v5hw>QKiU57Efo36r%6dxZ54W(IdF3kC#P_lD85kG(K@1J+F0;cMSj!Q#5ZVelGQ^4g#{5mBkG^Ouc -#;2{g(>&Ll#gW5ONx}WU)(S`g2Sf!q4lnGgIU~kgQc_h<;hu{=myLE --8H(w#NTzT8*FFLHM+sfR5w_U7OorYgG?7motbXB!90SwZm{>6t^87($4Qx8=?3fM?kO!*keuTRPPH4 -L5^20I7(3;$2cblpaA#O*=J!sYdeBuOe(#i(2vtKL(!1`RVu>QaDpt=YF9&Z{FV&V0Q!mv5^MuO5nN% -6{H!EECQknj&A@@bcYeCLYm+(+$1=h+ZtrfyxJAbD)l35tjQ^$MpBhv|DCremu^>+9*J0_~sES2 -mUDD~mR6cT-ok9HnmMC~7O~j@rtCnaf{pmGQ;K;-)R9Z$MSq4d{J-J&W9c-sj8L*ZVvKT8EsT(LwL?y -bPCESa0oG@AJo0@AFAj@AJ|j?s}hZMTr*X&m!u5u573GIeN&i>U|C#;->ex@&@%j@3y+KeRCJt2HCVB -oaue0Y9CRauQF{P)K2en0%Sqe`}{>az0azONYwlM#jPG2;go}{Zz!2U3eD|p_)wWdXL_yf298;83&EaHlw!~c5}LHn5Ts_Q?d2zsxBvBmRs(8qVC2zm -evHSUU_tFEgEI*UcusUqmAc8Z{9w^szcSKp~3=o$al6hWtmlmP!uMbNh*Ddl(0($0ZO9sisnXv#jQ2) -e4HBIp@R5%dfK@T5D{z*m9o9!qp*BeL|il7%z_i}glY -ZO7BIqT9-{NJqz`Zu^b-IXHfn_4KxcA*H`^7!Aa2>LGnze5r99;QT0RRrB+0tusQMbLJxa_qW_pdWs$ -b4Ab}O>U$LouVrcs$CPZIPG4vFw7+8f6_OM;;NyCa@Ei`an; -a0xoYTcTs5>eR}GE#t~yZ-z2>x{bfy~mk)N>4H>4Um_a|4aG!(e0hNeBJsv3F=)%@IwOkirTccL2lPI -uMNbKF!z(~eVBOcwJis-eSvRW)?eFI+YBx2kIBFI3ggAG=gTpH@{vS6@#xG%F1o=$}B<(7l(qM6hQUb -JfsyH@V-Z;%cFhoH5XI1R+PETplccvRIY*1=OLl5J((@B%X|Y8_p)K_M^jC40`XOgs$$(I$+d;4ndvA -T*{$;*hV^44vq85nD*~F-_ZPTF`xgrGT3lGoByqW`5&Z}m(za!x2^N}A70?u>CtZf*WES$`GBSJ-~!_I#48D=lP*yeQtJsff!{m_cnMpPLoeMBGjlP?zFcoQFlT}WWztT0_wd^k -Eddw@YJl*Svtg05VmCwxFNO~Xz#GcAA(O)^{=zZWvyeSfJ;3ouL2b$=f|5}{C(~u?oe4@%>qWseBuEHO>olTTou -Ml2GFE!07JMu -ADZD`pr`?!3eEAAMXnqNb(Ujw&7a?+3zffF#OnEwE1)wGvOXp@um$Goc{dAbr-jl$EzP?7#0VEnnoL2 -Eb8kR{fMfRXnAWvr!D|uc7`lgZ?OiC=7Jxby>2ur!0M34-*p0KJzoMge;l`){;)pJt?JEzv2M-8Pa~~ -Lrqk{PR(RpF?3G_3Ae^yLU0qm*iD@8CFRz&?QDc~#c+dD`Jz0ga2_ucKqXk4ll7(df`q$TcN+*yesnx -G&-8S=+oBePCjUDlow&wHQhf1(R2=KNL~nB)m|G)0avbJf+_}Q -|i}9uU}juES1QalD1LsBL2AXS*I^V9fnQuI*q>g4@jN6ff$onk#!g`wHPRr&Qgi9pchjpVk*tl(90=K -PbHoc>4QS14K*G8E1~c9WKoL&%zPNkP611Vo^GuKC!r(?-$yGXWL5-ZbpO-RsDtuT(kP+X30)dgqt*; -HT_N9U@vN7sD(byVp7r$BzZ3PTEW)^;;4ee?27Fq<6#JFF7~d09sv2--{@@~d*r8gE+^kS7evwowl92 -Wxq`DD8nM<^_g2w53R#RJbGo2ohqPwkb#$NaTkrY_@_a(&8ciA&yE7r`! -t@rMD87Yu%apHd96Cm%)-z2NI?Bw%+=5J~t5}{&PqwA)^?(lp%Bpykj>y;2wBtBk#v-}c-C|x!PG8CJ -PL+z#(eUY`pT|UUQvdx>`JFN1=){05!i$bY4*NwggFPw>5hZCbT3%dRUs_Q0(EmT`d6Jpd2C#IrN#Kq -{cP^JW`aMN%oaTL{h^0D}2iKp{1CG@=>IG^31FYZh2uPOV}zk#xUH;->ZLjg9-V};ijJ=5AgXFKUt=jb~gcUw^hs9VmiFy%0K0il;U#!oc1YM#xCGv(E#P?hgV7H6_QHne -WO&vFN%3UX`Q_y>Zo>sQlV8ZR8W0`&<~g@uA^;{ujAo6xbACtkjuIF-u4HFQpvA+SY+M;NHaQG*Swq$^PaC+W$C;;9Xq3J~4&5P0-iZ+x1gX`0`WJi%) -Rvg`EqYCO8%dvtIxB0j0%Bi;;r$pS-WzW+Pn#H>sV{mG=|62^KqkAC$Ebt);v6uVjq}1(B3kkERP%Wl -cVIHGjh+XbxEdIKE3JTLL9+ZrqG|<@BSAQfo1&g+Jh#LmVsMxJ_`>*4CC+fY -wYm+I`6(UJEct^h)!f1`WC^(N`CIrh9Dy`P{@tOD!7Oo0lJVHeBE=DyC4<;#g+8{_5hmro_Cx_*ShQw -qMHb5eeQX7#Z^>>HsyR->5x9GIN**Dp=L9gz3I)BTrNA(^gbuz2Z5dM;B5%??B{ROqV+&F2MN&`}h}5 -IMt@kbHL{KM>SC5H&TS2eym=k(+7c<6Mz9Q$3aq2q>ReaIwGt`VH7u(5($K-`bcd1-v_LyGau>UH|$L -jn1RoSnxUaY$pBNwZ_vw7yOKBe8fcn!B)f@UZ}WdI6@C18W3uULztFt(dhC))_iwbemaRM05gfvI3qj -QZ>9Dg&M+`(bX%N3s(S#sYhv;fia&Pv(A8O|-q?JuZ}|{XPKXy~0xML<=N~vM^^#{=T*K0bvlN9sd+P -L)yza;a`e@wsa?rU|n7YXbgRdYRhxwo!vmNSSUYL;9*mP*Cqqp2L%eCV-E6l*OP~a9t)1f#qP(DXp>0 -!J2D5dF;M(ka3x31|>kiLkDWjGD}tQBUVCG*0h_%LuQtiM=T?NJgR_5xnQc8r#nVWTW8j|5p<>?Y4)r -W7za{GtACe}ncYI;uapQBj)X!*q1N1UqCYLXhSKMXU-EN~d{1B2s*Kp$u{Biof05+aw)@@FzZ{8g&;I -9ydT18YZLM)T)Ss3tL;ooA8{cR4J5(=B;B2T2$>Oo&krPJ}_EeZV&2BSCs=FqzdN~S+XaN(jAAIqMeN6_gt5 -D%h3Y1YjB2H=pUZS&LK?1<7YVVfdqblsMMc|njh)+ndpQ*#%(^&`{qb0%O4Xha^%x6I -5FA@8jxmWWteM-86}i1&`<@g)$-oSlo7lHsmd94jo#Ji0uW2*9;>6?P8Eu+u- -977E*aVBAMjEt^d+9G&-Q}X-OxqeYTS*>3l&Bb9C -lJd)i;b&YbAr@>!=&G*p$FQ+tZApwD#{wD2wLZDCf$B*DVY{0M1@2Aq0Ip)G5WIYW-i{t+G0YL^@>Ur -eV_NrB-DkZp$o@vd>jiko=x+L$}muO{kPL5vq6<@%i!68v?nnZiwxM2vz7sI72QG(r7PethZ-^Y9<@T ->7DK2F>(C`N7CdjCyC#6R!elzVqj-6F(>c5E-R2u=fASIxs(6=I{bEx -(NOp-hx<9KY1y%V0kaV>nFaFoVO59Ny32pEx|iVI7AuhbU9^~*v4$C;)$o*~ -Oa3_a<h~IFrLWIb6r#4h|pT@DPV*IQ)#m77o3~F&M(3fx}xk9M7S^;Q|iRIn3 -d3Glx4l+{59^99D98hQlv7{GLPYcwS!|hI1IrVH}5ZIn3tp9u9YN_%eqz9R8KV?>P+M_0fmJTR4p2P~ -h+m4s$r%%wZje>Mxns&r}XmqT0K6^(z~M$|)hf1q_xQW3c6M20Q-Bo0+|BaOduw{WcBzWeGwQ2@>JkG -e|@Bbm#45o`%MgpUhwy{6W`A=96SHos1+gJPy@7hKwf`lHiJaKDmvUNj#ZNOw?9@ze!{@{7r&*@?8GX -`QHd)fIP52gUe<;|0C3XG_@biZ3s!CxrVtJhxjuQE9BG)=`4r;?JoPdUbrXz<|ywPUQ!a7JywWqo2*}B~BNVU5NHZwJc8X;Xw3**PQF;0vR -hV|BAgb}&<7ZVt7a=io3^#CR|~hCzSm2i<8 -njfbb!%iBli>*pU3*i9c4+`UIgXwP0@z5Dd-*Z-yghJk|yhYuM#Z1~N$M2r|YYINk7u~E_E#!rZuI4O -4Wl&QDI8K=dY5~j}(%rj?M5^tNGG-vL-jnxhy4hd0M(PV?}1x%2nB`b8>BW+4Drlnz -ifJZ@7Eorp;SOe6BrVU6z<+&rP#p?XCu1N`tz$0~c7yDBy`~%I|i{2O{vyYOpuZ7Hg;e47419#EuRvgqh|EE3gTsX$8urr>@+3pvCvO0l-xk$%cl -NW$x>;`DxF5svLP+8PsKjLK!(FukOn3@xtUTAIU&uJCwF?Lc1o!nnn&ayHU`*fUhM5cnrNP|_spW@>{ -#DpUG<#Ih0x}psWT+!3JT|c>S{2vjMWwsx`%2R=ZKuo%h_+8}lptb#1*{-RK?<@g(#5vAbLtr -E@9uux^v3@K -=^@vq|AXm`bERjaHHPu70snR?1z;SVwIsD|w#BH%7yS?9e;JL{O4iYwkLH}kOjvVjEnb`dF=XO(>pK@ -xv+^9X_MOY!u~%F}xzc(KFS*Cxo}VyRHY$OMyw6d2r>k+IV|){SCBD_X7tEq9(N1Gecl8mgx=crn{~z -I>_9>-P`log%g&KcbJ4IUOQa%|@``b)9HW{dtY;DISUANarxB9#B{Gt!Wqgbb_safnazmabBcjNJ+WQ -?-C8gpJJHLAwn*57B)I%2JjjaW7?XVDl8bab;(8#^_txnW__uc46#hbcj9zNJ$gxY?H*_vo2f4VlEvL -EPNfjhTbFxs02;b8{Rw_u%IGKxPi(W*ay6=4Jyo_u=Nf0nFT2jgOoAsp29W$>}>A}saJR8T&8`S)9^HpvR<7S1MTYQ)~k+yw1l}k|Gz`9sK$2hguizgBAXMmb+FHu?m!5v6=#K -*;l|IdGhYyO72{;qYq_D_JCx!zwu`0}f-<%VyZ7ry=OV&kRnfB5mIrskH*KVP -}}ORMrvFVJ+o0CPhNH2>4(|DR6(-@ZWBwfp}H`s4nqzgv6g4`!{K`F9=6_{^@mEb-e8=6gGs%Q~3v>t -MdWgZY6DW_*U%-TYbyGagMqnYtW4+#jD|Ro5C9X62;kuAL{QidnfiXg@#CYM;G)r8P}7=VavCS5t?DJ -RWejq~?jnG%;(9H7VETu(|A+9gB`6Ld>ZvtkZJWv5@o0JdpY3(iNmp!~{~Ng}DE`^Yib?FUSXh&hwu9 -d$#6>czJ=s$Vtnz+9w%?ZQwB-!r-bp5Oh=re|BqXx*@}!yB -b2UXa*0&y&)r%OaK}$0!T$>n8Vz?jtoHR;IV%hqG-KDe=UGM3&6(th=}^3Mhb=oRjrmYr* -bm%u9b(rWz#WKmod{Gqbh5gU#%Jv!wPW**G`c32N7%};IujiRwUZ6zVZ5fYT{~`V^j~2Wf&5vbAuTuE -YRJtn*wnRl{Eeb(6>a-jqiOthfXitrqxq~{{UxlkK?7kivzmi=SFcV53~CQ42xJ>J3hH|pVtJX?<*8t -qot0w+9?8z@GM=@WS)w)1mYQZYq-Ka#yJ6U9N1lE3@~oWE)|@rN)W9A1rj4&KHSm~a&&^qF%@I}qZRu -F;tFv-aX(dC|L5PueIdVm-0eGN8G@WI7@-=N^8C{#R!#r<^TYV13gVvhQYepCa%Bv*V9`Ltj3us6*3CV)aqhpN|e>s)wz62ZxC-?gIw**(1{() -_ve}BN!o8;KA*nL^w`foXqPSDx)lY=_(@A}e92p~04izy5*UMUpvha3m$llKZC$4Jqf64W^28>KKM43qH*;_wE$K71r!6!kBof15di~~cVzF8f#U`o(UZPnH_|IT5Yh`E`Y1oUcfGdOBZ-hBcfpuN{cDL|v>yQ%o5o*5{G -lY85I+(UttTO4gBrWl2h{qN>uf$L-bul|{YdX4{-n1EFx{8*j@FUhb3<#@yzIZ35LBepN6l|PFVb&XS -UJlvA*#Q1w-7QuqODw-{sE-F=ui5m`;q?1zNA0I+kb5D`d+o6<-vL_(MS6b{a8jP43EQ2E_}DC;lun$ -7|=8<*`I_#S;FRq)OIfqvIU2DlaO>Bl*I?j;tC%+mXPqVZsEN>i1%EN>y{7e=jJGoP2kJq;Z6enxtp2 -M(i`b->nz`+#}P7dTwA)n)W0wBo9pfJqa9Dk)8p|v5`&rm4-%jWCK^KkF{B3*Lo&?!qPr1;yR`j8+ff6&-~a*eMC@g3_G**nso42XV~4AAT*?YW7?T -?+zf@6o>GCh;|LQ~Imqrs!A5O`5$Vh`ZY$?O;kLA4*p>|MoeA9E0yoHU9&2kT%Ro?QJPwcIGEv{hXhp`^6HWq&eA-BW#q3Z5d&nj>DEhZ!czVEr8n*mRPulr>lriT{VpbzOWR__Y47Y3tGmb8V -r2>8&YZDBOswWND=AnAU;f0BmhNkjR{oAOm~KR;IQzz_ZGZFR2Z`-v1nUP>ioB#*E6NPp5deGciHoJ9 -IY&nA5}GYJd9XpIj%X!`k+eqtE#QZI8`4n(`azrOo$Ld2^d`N>hL*GT2OqTEFr -aPN*z5CN&PqZ)TiM2Yw0^_@h!^Sz+Aq{iBc`a*>6UB=1K%88j!UZu`3;y0R62#~NT>*3x(^A3JcW)8F -4u(USlfquhJYQme@?@s;A{Q6cwt2jA-{)jw;Fd}Kj=e)fNs#20-gKbPs^61=}eET?rFf-0%1cSY{*=m2GqMA!ndUn2x$O6By)bS1CP-*r=xAo7w -J5$Z9MtSbC3pn^_Lmcg!_^3=-wp!`#z0f^*w7t%DdZwQ-YF$-NrgK?1?`U(g>dir$g_7I?_E^5ACiS> -29aJV2W$3#5&?*YF`*r`vRSSA6VP8d*J&t(8dB228i9kJs9dfi1di>cE4YvuHL&=Tdt0~f~)?5q1-`4 -f5zWN$7{}Ky&&x#QQhnv!$rEn=^m-@l5iFRB6$BygwNdeV6 -ADO@?P@V}zkEq<0-&KK3CYS3Ydx<*xYg(K_Jyx;B1fV^cbeO?PxUHdTB4O1fVX^2?VU+GKKDn`Gk-&< -FaO-s!IXvR)1UtV~E1e7oAwv>W&Z{s-OyzOQ%h2ah%oasj?qxc_Xx1D%Atr=}kYeHrjm=*!(~fhhq=v -|k1@$U}|Y>w{_;H~S@ZA#XLJyruE-AYRcL7<;fC_(3}WIF^Of_-csna^BBvRe6!OT|4mb2oKUnQ^I%^ -$8~D<)ljnz%n?4Mj~K1#6CI`Lqlwh0@`cS8~?vyTViha`_K7y2LE%uox% -Sr=i3Kp+>ddVYGzo)cs7-`z)X4}iO|lo;=*21s+hTuYzCA2D(lSLzYakpUJ&7?dFKa~(k0Cj?ElHBDnNBmp* -KQ%ruP{w4P<(E>)pa(tj|bQ$=B7Kct<$rzt+%DFM!(N_&cU_CPD_*JndrzCv!<;Vt;x9yv(l~cnW=X2 -ATOiKpOKJN823CeT>y&V>ZZ7pOX9P0^HkHUgt@mRSfa*`O3w! -ARw79Mxz^RWYiJSX*{o>`NrGmcXor7hD9t451FCL0tu``Guq-qtnQ8D3Jp^m2ZMxkG`FoGzMqD-_-;; -zK(Q1#kXNi!J?0HZkTv8{oo)&BB8tXOoHdaX_O1HTx_Nv*n))<*x&wDWT^X|d81)}>i(7# -oyA#KYRJAbq-Y_V6_4nXJnlD^^(TNp@=+}u?T+jK_`%`OxTm -w>|1B|g}!+MWQ~u)#}h;>o$Lc28bl{X>$~POCE~jTIA;egtDl&PrRw%UyMCPY2}9r -{!OtCt6o0XF)o7lrn&kdwD;C77K~d(~_GCt!KGC)xI9`c#iVOTq~=XJ*|MtrdN^(P%-cJqs6A7m`%wl0G|wQGSj`+uj@I48|Cj#XiDDe -VbF`3j^~<-hb6y?I?RM>h$gloT_U&2<>)gM`uloAW??1o){I2&?+uYcv&X0UJf{+tS4QDdWDvG;1>Q_ -+PnTP2k -LT|scmI&PhxssCs5JZc{(`#vF?U0kzkhqy{#$-sAFg8VT_67WpUwBb^7sFp2Ri)zkF!Kl0++Wuw6yzp -20G}Jt?RcAh7}=fQu))90QxbP<0+D}!+yzIKEDjU2uX{!cyi#Z!IAmru! -0E$%x0%}-Kn4h$%B&fR&=K$e|bd2Z~r{@<(n8}0#&*~~(=DvA>C<}UDi2PO{VIGoI342RJiMshfuLj# -9l9O^i1@n-M>hxHu(mBTs?&vIDHVGW1X93J7YoWnOc+|S{w9PZ`tc@B4RxP!x@4)Jf~P~UN!>gVQ{>WiHhx<9)!{OgE2l{7z -MKjya+y1w?{~9eC=XM@GC4|>^7_X;3ydHUaNs0WPlEP%%^q%eG;aVk?{A;fk{!4!y^Zsk~{;&4`_lEy ->$N%?+|IhFL=I__;k9c(WdGenczNI_w$2nBn`*Plnhc}UbDICQ=wZEz7a9!HJ25#ZMFL=Bg)BZ82=Cx -zHQP;>?dA~+xd3pa!DpLKytig^mhfx|L0{jZT#*rE#1Dp*L-X%9{ND{#NdVmZDes%)f6aw-F;Q0WZ@Y -RF=3jl*cLCyhtgj0Kg8SprOmfj%00FJO4ChIo95uWMC{5JyB_Xq!jAuPae;R^x05n%jH5Pq13qyzj3z -9g`30XS{|$V!0609-$S`Pm4tzk%Tffa3>(oOlcP0a!bbrG@aGL9AS5gQ(so>L1}lgPEUQ0IzWSs{lua -Gkib5r-wqFLAuWXya?Yjm>+ct3#iZU(sk@MM5j;Hw4vD!|^ifV?*Z`~aL80W=Q>ngDz`f|cb -}fO#WW9z=k*07DE1KO+DZ!Dj*-;p3x04jrx`djNhLNk}HxHv;T7hQ%KQ@DO|(!OszZQ$Y;R2S0HDuZ( -47zY4H53i1s0B$|*_(X5Qw0KbB-5$t7vw~YhY2k<0-RpUV}g7~Weo*U2d`B#8LV<2x}k7po;OoDh22k -12g@&>pL;IgSu2Ea1`zH%!ee+2whfM4Fq;*kL^i~}Bk`dS2VO&lvrIl%fj<_94z93hTyx{>8M1z-_;b ->P1Y;Pdd+1HKpFU*P)!;{jL!pA7gBfDcZCxd7n10G@*HD&VyMk0cVJ9jc+Q&uuKNegI#;jnQO3K+|kS -TZGYbppL*l!tdY{0B;1CKNr%1vLO5^8RU7eZvpth0z$R{UI!2tw=n+5MTER?JFAyJ0`$Ctl}ih7J$(D -Y|2BXx-NF3t1!#q-SRL4B0=%%8h1AOdGm{$S52jE9{GW)**{GQ_h%b@ -KqV|Wt4LimyaF9P`1GL}|3z}ysu+W;!5(3gXsnB|1rxtxXF0k9z*WH-Ps032;)`Hum(%F6i-;M7c*Hv -t|8@NM{N0WSv_pT%$!z+)V*0hqiJXbU*PR`>|i1z82OTE%F%5n%NyUS5E&W`h^-Qx4Fy8h8@x4&b}1S -v`IM@OTd74e%O(LAk742%Bni|Gfa;+XQ_e;Aa6|+zkCK;Ee!#Zej6<0eoT$^S=k+CHS%d{}JGx?eLA -zP&i&2Vfk3&5Z!_&5Tveh-TWVbD{oe?WNtY1TK^1N -`6_=t{x94q(miS)Y$k`z%Wr;be{@ya=BK+vao7C&0G|@FM`T|BUC}H55+W3w#TB96v;Q%51B7i;s&mDw% -2mG%9?|1|F9&j7LXWj-L1{~r2halg8?*vE=vvCBW-w|dX0C4pYM(2Ehkw>A7U>^t2rxN%9a09^i;oAm -y9l$H_?Ew5Lz}{7?ycU3)j{y&WeHp;_j(_kM1Q2L7ZR{$q|&G>CHz^~wI1V1vsB{It=LQMmd4P>4X0Hd8iQ@|0nTmX3jaD)NhGM+*B^ -0%yAyb3V)63`s{*Z?{&G1-ZH4{`qhAK(ZxegwV(JQLtUKXUp29M(k0o0t|rv5B`qfG=@;FF@aBNDKS~ -04!)`{ZA3Vci^i7`*MJvHFF+rVfR4Fzz;&a>+w9$2jOkp9$_ZO5f*Yk2%qHk2;by5!Vfu)@OzFU47|* -6JUc&<;|S+)9N~J7xn$;WoCN=H}0b&Qtb)JeRUW1bzRuYo!H|#Yzx@yo`QY_i1!7*?A`c`hKez&I -qX>td0y9MF8>p>Kd(0P@K?coNSnF#BQOWGnb&;-{AWn~eE!@(*lKOg?(lU=)Zk>{R!jvP2}fRvY)lMg@qkhHe8624@YPd$U75lsQ)-kSU -XqOV%J_7pXqQZ8Q254gH^?Z%Dh;i6J=^^{W649-ZK$hgYPThM>asf>(MRor})xo3m@RWw8VSHT^B;AabqpP93pssEaqQ#4_C7xelUBzc`W4S-8HA62pLEpUENCsJ -ub4f0KA%``=xknu%+e{_}GEu(p`PwkufpM12wmtIQ7h+Kh{vc_<{We<7A};g3~=~$p6WwlWSV8p2{z$ -{!b~&FZ17Nxk{bUKhU>fcZ))uDg7}DnK`3>s&u`MIn(%Q-k3AdZR0=YOs)@C{Iq&x1Ix{~Di1M@N&y#6&W0-aN8l!-jS|URG8{UVQOI^6I -OvQXc={gAd4;Uw-N0a~mEH09nztcb^Z|#ND>LmDe-gAzR+L_)f;ET(SkKDB~SP+47Ea8F0d?E#LjL>~ -%o4JpSckMY)o(>DZU^=g)s9!xH@mfXi0Rylb|iytYi)Tr%vP#q*buEy~mHyfz=>JMdeKe~Y4g+uXdDP -%ge3WVHbUlpvo03i0G0xz4Bh@!_AI(Fti3N9lC^lMO?L3?UH_5hOA)l1!O0g&2)SVm6y8?dHsxLl!Jp -KyJVNcCvKoQnERHI$5z|1zEXrC0V_CHL=_6wEx(&X%l(UaVz=5hAHHg&9S6#MFQEeDxU1jHIhf|apaA -HN#vz`GkK(7IoY?%Mk?=}MQWd3MTWnvkP(LzGNw`?w;oZ*xZ?_$d{QAxPADY)tU_j;Q^=h23dw_S{$~ -nV{Ix>T>J_s5fC@!w*|X%_xpU-`Pd*_RzpNwgeXo#DKmC;QMMFaa`SId64pH&CSh}SMcXC8pektLcD=#bY&pB1K;>VWA6qH*r0SLQ5kQ%3sJ?<+R$Lk`M?# -2*O7~_$d(H0^x6m@GBtvIwhEFhw!^0{GT9vIfOq0;lFSTKNP~pLHIi$ya?fc3*ldY@P{D$X$W5j;r|B -VKZo!Q5dI>BZ*mJidMF`DM&R|uAUDCBcJFTqIrRdJX)q5_&IA*sZVXXAnL`wq6f57{N0i3D5T(g2d%$fVsZ19>Q;j@Q*?GKSTHm2!95`f9Vz;gpVX>$~F)-%6uWbAA}D;oqiDB(48n#A^ -Z{uzX8HO^k3~=34Bf0)<2Iyy+JN9^)*%6cbgIfi4a4yL=3Me4SDs{P?g-En -tPMROevvho9bYQsi>(`N|l>^;JNMjk*4}GgYwvaL3Bzw>_yan4rKZwH -smnI&qs&+Q*=*Y@dsy?YC=m+P9-vU`1cmy(t`IM9DQ&GnYYG(FcTxxM&G79Rz9+-K!thB9pUUtn7=9h -YZ)f<=7@p@$JI?Uu82*YAz6FoagGY$v5oYoTD|v)`9^o{PaHTdWS6h>Ey)P*@N0ahP8Y#c7A?4OSa>7 -5w@GTkM!0`PTeh|ZtXZTqRznI}yG5mUl-^K8I82&iJU(~@@(>U-X!#~CFJ`CT4;af0#2*dYh_|XhMm* -H12{0@dcs)H}ttZLJLWio{s!;EI}xo2~~#*KV^n{;ztHHKLtBFtus$zU*=tu6hUHf`LfTepUC1akym= -6@0V!ECnrH^U9xx_N8YEs>^hi-Cs^HyI6KMr#Y)(73U$k9IvGGSp}>n#?AK2VSjO`1^-g?;>f5w8+-= -DUZ6=R;|<#8u|KoH|z#@9^Yb#Fj%Y&>eTb#>wJTsc0&^@!yAkMHd(As)u~fYy)JNU!&?o;$X*spxW(#;0qS|wt^2pfAAh`lPt1Vpk)rYVo+W -Ouf(^KC3XhDiSR%tCy-M7`*PAvME#Z;o$gWR&KB?V+>&^UH_EgmIO=1ekHES?#(D*0DZ{0bPSs -WQ|i4;VL86^K1f2+B5C{VEQ7@l3b)~Qp6Z*X3>wtv(b8W7GC^y2GJckL=rsPDXPs#T>{P|d(_i#d|H+ -|^4E(V(lQ9)?av<1>|ORS7g$Bdw7U;To3Czibd;Y8z$>c*LznFYN+&6=60yuUk6?xL1GF&8>EK#thj`MDRsZ80&J|wkFfv>sD)+v3KX1Rjah;k0vWdk1*ez-)h1wy*ocqscI;$n+&Y -37Uk}B@P`#F^s(ACds|JBhR&>OilQH1ZQb2#cZ@VLA0u>^F}_(`=I=YSF?Eh8d0EvT9^cH07!lsClgn -k@_{^FJV<(r(iltJ2%is2L|5_u0NpPN!jFEy7-Q4B8mT={v5%;);`>nHM&goPzya_rs(_ol$d!Bt9-&xKLTTbg8mz*)k;~BSTrSVui>R)~#D7^1%;3{ -7~cy2lL)jmU6z4%eg{+e!lYc*I$d=;Ov=`%9%4~l(T2gDi<$aRDS&NN9F3zmql)Hjn^9OODo5+D~9tXNrN^M%Nw5IJ!Un)>WQ=yVZ$CWj7j^p`ruekyr|jJqj5k$0RFhEr?; -o4ho?_-FZY@?pJqL)=j+$Fanr^DwcTqqdxFnBeHu1x%J=hH3VfnooFo)NLN{ShZ?3s#mG8J -A?d(K?Cbm<%)PhP)%{W7mh&mKR1e9dQ{eKyC<&CNeJI5-Mn(4HHAe(Lby!}E9@O*?k%p!4U?6US3Jbm$N^sOaR$lf>(9!gZ#BIL>}sR8;f>(|UUU{{8Rn+ -_`f~SXfvaMU@kNGE!Gjf6@V5AlDjN$7lHy7W`DC0q%{9i)&L{T#UCkw73ua>oLFguno4w7#%uvXaf8g -FMWb*oulu+|DN{l-AnuS?GyI_hI0gbf0kjEuUWHZ@}^CjCUeRbK7IQ1-U$f -_=G4^GKAcwrH~gH%zi!>SZD!A&J>Z#Vo&oPX%x1G6#=T$suU)%FoXey&Y}l|J^DyLUSFc{ZcJScAE#H0j-ASJ7SK -P;RzQy*|j&Vo@?ET`;`4r}IcHl2NXpkK;ksbI;I^<{BU1^b>advi=xwGrPM}H9fKmPdRxhzLt)`=OQV -b`u*0)Obo(W6I&3{IauEzW@>Y=UiA919BzMTc!b9ymg7upPjB@x>Pcf5?#SpCE_df0s|2sg2KX@%OiJ -oo)D;`@#R_&6~twNa%l1P*4--F*@-7>Z`A4>(;HrGAGWNg$;xMkjLkre=a(3FDNJwwsPdi5%C!`zz0C -zU?-3faNGD3QOr>y!`DP@KPL+Kgvfs;moC(?q?P1`F$ -d*TX6eUG@@n{7R)EkZqyGE+W4j_m4mO;q5Ew`yQ%^tV3zfLUhXF1Pp+qSJQ`|}yVA9~_S2lO6#?MjEF1-cGBI -{D>#dT&B7Wsd7Y?QasChTfc+vKNLj!ha4u;8{_OWC@9n{4pBPN5CUhYi)3A(bK#OMo`6AQMpYizn8I=ZU&!9otGkj9 -(&zSEY6Ey=3%zy7KZ2tvfn6FF2pZ&eif3~$$GEAK!<-*X|OU41J5%JI(xQg_G~OveNxa@YJ8SHsVURYaBHc4N#M`<{oHo#+WB&hG -6VR-FX9ND0S(A`BrW(3u~z0~xQ2L(oB{2_l#aA9xg)J%8nT&&)l9>-#iQu@V`roNjrzVhv?66nh4cvgcqy@eo{vPWZ_)Wwr#5T0;(}HLV)371A6Xj0oOb({O)t>*&J}E8 -ENOMPo(X3b#O&@BaDTB>4XWRffad@wwL7!u^(sGQl@MnK7^q=ub1>V35N8kj!VGqDt$^<@MpC2Rsf=1 -~7$FoA{Bc@?9)3AOr)4;X>dj<_QjfTY<4f8?6@GzP=jApy%3Vi@uW^w -q0ZlihA78&{vY^D{qNkla}(eI{ASIX<)p!tj`C=^bLTd -l-noQ6nQNjQ(}QTMX3uMN_Pj!)VW~#LzgUk_M;K{#tV#o#$T2uR_vF6pyokSFD1U7AAajntX?^?lwZz -BA?*^{0N7z7ea8dsdC3+rRO8BXhjdo@I`)ShMH(Yzz0of7`ZgwK&)LyTrd`%a-kj -3>gwXc<|th>_>$hY&IM9?%kW7efC*;^UXJD;lhQqV8H@`57zg<7c?LiAWld+u!aE*@Tbs2#6rxGKgUe -_-vj;85dHf(UP4HI9Zq@*Nbn;@L`=+Q -&u2%miNiO>h&4qPE4saH}Spbxr-bq?}6$O85Nn-=!Wa?soJ`!4qU<)-Dx1D94rc{+CNxM1<(#bO@>b8 -EItDJdxw6%|Dd8#bh7&6*MC)&dvc0o%}b&>*`jE$GlGIW~OjSIb_ZZT}4A_^jp_h|l)PCffAYP&)R-M -!I?9Mj^|)!ut=47A>L~GiF>%OG~3^)27`RFkk?U963_(o!6B@mp}vT0(1g5(BVo8_8<_4q4$W%9?kRw5Mprw??RWn06Vo2(V^74BzW@~=jX8ns`)e*HYGAsz&O=q5UJ3H#0X4tQbDdEB^h!hTIA6N -QF`Qma<2gdA`kFs^izrd!fB-_2Cix<^IpHzI#S{saHd_Lz!u*c*<(1@eZ?vYv`uA}%gY_*S-c5#Qizpx;stVF$ -2F$OL)<8Nes&^C5i3xR4R#fq2gJ;te?Pn^h`^yAyxCuIhDIuiL;4bU}w;3o~cVB=%V%PU{yUc(1APXTE2Wa_88MERjPEqxI6Ke`9Je}2569eu{1isZ}=dN-C~^pokFZFWlvw=5822Z0(BkeJ -#+~?hYc;l!~FNp_Y(N)^&dXMHO9Kqf+P0WUwrXJdi(9Sg?{V#E<5gnEaMA9pLT8jT>pnk|jc)r46HlZn-y)yb0&f8CgGIpZQ+p%9Z~c+@1LA0lz7w=a+&Mp8^?>^R2mFBx+n3OPj^8un`l~!z&*BOW*ar2-oGl1 -^5gaq3f(izjKaI#IizM^?b;?O0hmR@IKRw4;}HG-$^u+L6?w8;&J^x8tomK*RGrRkdD4DJNI -NejoSGx!-hIFX9{(71#a1vKr>{;M_NmW4#vlyby1>ScF_khzy8?=*JmE -U6U47e=Z?~Q)1$;bW~#Oa_{t?B>jkxL`s^9C?kk@k(CZ`WL#Q(b^YLIwo%BLX;q_}Y=ebe(=P)3D{HVR6e*CN#iu&0Xp0``PAzMXK-n&E}th{iB3UG}N9 -HrNE}o%;EaS4^BZF@DOFDZ}-(SKxqs6Yv5J`|GGRWoz|5)S0j!3VlS43AK&sT77BKAhj=?7AtTN`ndO -Q?b~&J*IKY^4H)v@InyBOU8ogdPZN9NQXjD|j`|8}6QahY%|Cf?S20&Noj!K?vZVZxlg*wzJNlh>-id --OV!e<29CQO0@BqjCnX#g7hoeFPa(;cCMPIuEp -YByND%|yfsIj0{H-m9V)@qHq_6Prm`RB};6aDVH??$0EgnS%$$aS@RZV-5Y7w|{8hKBlW&Z~EAqBMQf -=~}7&A364EXAaP%Gl$qFT=a3I(OD}iZ+^rS>~mm -G7d*!Lifz%km+o2%ld^#f_Sn7chOP@t?=9B|MyU4|t9v_%EMr1V3D3G8)F@`}VVLm7D*yY}xWTwtKM-M65?$2DK&5vuNPJf -r9R`_L^N~BjdPywvva(bI;}fz@Pb#xjFy1fLbE=ujVE9_%Q}@JMbHOxzIuErK7F^`_R`BAOrXXzyTNV0)87l6L{{}v16W6u^NT2|G9JLMrUMXM9D -Qb0SOk^TbDC9Yk&HbYU@3KeO>|H1!EpFVv!#>1XGVm^EhY6~yD^p -dDC!!B?y8h9Z0c#$uorh>ekX?W*8=625Sx`(CTlR!KgGiHqN4R}^n?khrG;5F!mPcAGhTy>vwi}^7R` -x@c@OT$Cvz-!j5p=HaKiM?X@M(jDsn&Jb_E#}8OGX6rBK(EZfVSBPJ2^^qfsBvKbY15`n@;Si=o!d!& -MfO19XW;uF=iJ;}=-(yg#cW00KY7rG-E=SMK9 -?yWVBu$??#utZS@~rsd0*ueaH3H`z!1v~uOjf2~@zs)XNhI2@OGj8R!xS>k)X=aJ0J%!u^#^zGT%*+Q -N&hC$A3(}(o%sHg4RxfA=Ww|ISD*qU4u>2ty8OX?bU)73wO;TzmH!Z*Q=fUEp{$KGu#C~cIQ8xGRePFO!;{ -fe~$)+&L#R$9z>q1K8uIdF&mW8U|ZBSemKjn`mHud8EVEsnJp)_z#`Vci+T>rUh_$fp$+7@|VvfVJyT+%#V14bppnQU*_09MGp@@4ZJZ9c!63GX -hO`!eiC4@&PMFc&(ALbi96@95gH -@E;_MgTBZ^QGCVT;GJ-O?XY|h)mXVY(D`Qc{>Ws}91sO*& -iZY5bs@Xhjc;o&77;UZ%;nD1ERNO!DurZIn%zBnbM -}$!;%twcpq!+f`8kVn(sNel|FGbuAAv#c!U&-Q2gzia;iP)h>@6aWAK2mnY{22*@G&+iCH005H@0RS5S -003}la4%nWWo~3|axY|Qb98KJVlQ=cX>2ZVdBuJEciT3y@b5jR{{w5^TvCZl=h3uXZ`H2XbsOI%u|L~ -syVv%zv_#unQ=~#te)O?_`!^4~2}*L>Jy)lVB@!3_gTY{CFf&;H_@nh;r<&c@`Q=p`L_34v`O|05H=a -Lz{wz4Y%7TOY_Npp_qw1o)P3tW9wwjldw9TtB#;QkI7QEiu*?oJo8@G3Dkd~8RXaDW-;ojfh9q%6=;X -^F=@kjY|R@H4Vt|r;I`S_!Yx|+g|qR7SwtO>;XN%nr88KuiMyK9U5Tt8}VMD5F>I+xXQ`jIw4(@qllp -(^B+`ueY?D%Fpoy1dNGOZB^I)YsX4GOnhxywE+V_1C5vUuW&dAGP)U*2f+6$IkG4AZ8n`b5ANFAI-Py|k*A0 -4Rh^|18uf$vDJN$>o!%!32;$p-DBH-V88%LH6w9jLaF14EDH1K=GbK1&MQPb7{D{1d%Su>=u(Dz -}`T+Q3O7zTBEo8;we-VTE!D!aEoOLO-=eSZU$g3OdHG -vewWrOKyp&+}yPd4+({u55`|UTK*FX&F{aYCB(ZTl4u3IWPJyIh)0v7r9yJY9pySLwW%AK4xh>~A_j| -PvQtZ)5wxcT)b|Ni-J|Mlpf|2_Kc%dbvPPR|foAx+@NA5F3gnzbyMru8*UF#kz-F%1L@SX*1;F9%pON -CPeva4F*4b=J=75?)Pm;>u}#Pb?THm5RtJ+1;!L2F05I1I4|p_;ofa` -#mMt+fJJW{)py8IMKMz5%NnzrLB1F|ldL)%+6-vErxixvP(1>8%RJ|YgORb1HZoWe -%@`EeHZ=XV6vy9J{DUav^4|A&Fg$TO4XYa_ce}H1YvIhc@Y4?3Fgvhm -p&3It?Pvgp3bC%fU9tYc@fyR5!glj!_aQe(?hVnzermAKSFxnXu3GB>OYKf@zSd)x$0D -{)ne%2`(90|w$$gQVV!~042B$ohAmVprTH_6+p7vev{3APjw*&!no$2iC8L@*LQDif86O&rxvGXe8}D -O_WxIkpN{H$Q6vZ}fL8Oer_0Xh2fiN~wNitfhe0a#nvrVDG6i98LZ*Q99O-lv6?0F>$%2H7aTLt!T-o77@0aZMC+0?+n{CGzIW!%f0i`~(HL*PSGI+X*eq`+3)bmBVcH`{S`I$L&KHTKNl -b~lumuNaUb9qYR;Uyg+aOJlJyu>r^XPxXg$wCQ>o{ZET+?w^I3 -(bEuTLd^4AwHpT3MG^huR9W!Qm}7Pskr!<$r~aq${=kGckOEAE30n8u*Fs^-OnG3Wxxq$$23E1X_^2* -^7*Q5!eoE7*Bx)NNd5ZBdN}t4-OS?xviwF0z*}^L{1727^2JW!5H=!$+eE<1q?)>YjMi8T{~m -a9q#(OfUFZMVT_%Ow5V5elJq4nTC_8opB~kFwchq`H0I}nmW(snKR^T^zC#zGq4ptkps`HzyP)}{i(826vfR*a-{q7(8&k -)SWwvW8a2Av88)T0G(kClhARvIAY+<3E#Kx=))~3k$|_1f4s1PKY|b!FHWB3o0-B_)SAVz6Bp$|J<2*>yhp=M -UD}qXdj~W3yl7)u>8p-%n^JR|F;4&#$rk>oGvlg>u}}U>S2%)DF*&V!LP!wikLi48+65*UtHvOLn?@rM6+O^YgT9Q -9;(V-6D7KHhp>zeBKY*YN$@cOB_FZrwLhKcG2N;vI#=4YC;0@sN?SSU1n~dFD%C^2I8K(_yVe3YFgMTHNa}&?1S!DHaNYEd)mCE6`qtm!tFfIvz1~;PK^^< -H|o3yrUbSKux&WP=chMpie_*eGTVqYc<%}nwVWR3DBl9LR$zDgUkx<}1D9V28Z03&J(?WKQ{*X=xoHF -Fan2$_b^Fdb1KIfiF`8_AB%hR{4A;xeFw`do1obuZ4k!zDut)yRE0#_wDa?zNay7kolvG( -ibobHIjhFHePybuaHBvlW_8$!_K$*}@G(yc4YEjEv_z40a+21!c^MMdjY7{5LQ#3?2Npb#BuqnIS0!V -`oeZPEiMOpYQAEQ16}`tKyFZ2P6NXm1GCNcth0GfH%Et^Qf;^RGB=e0?q -C72y;5W9>Iut{<=V`2`h(x$?o1EV#*V%mpD;zyE4c=%_2)-Exrdzg2BIMaQqCYYDM@KFln&JZ#3xqqU -twD$v6R!i!3A{!AKcO!@w1>k&M|2b~E0BTEkvvPM#+YzH2ssr9=AuHG{;N^&!j|)Za)sL{2zR(D0tRF -d9sP#>a3lk|Rb#^$ivR7!#uwp0wk?LNFGS!q^Pygp=|Lrii0O~;X;5;2)BOffX%XEB?XaX%(2x6 -c)AfXYo7#oq;Reg{y@DY|3FSXM@e*Pt(VCX}PU9fv+%@vhB31QS(N%DMnb`s9$BqA1g#V6{kExnP(J0 -xKyN0Ydmo;Yu_X%o5f6%hnzm}F((Iz1(6#6r~>No5DC`Xn6^rAA^G#C|69$ZHi4qO%ac8e$KAqnha8$ -u$xpmG6kwCVLmL6)Min8nI=`eUYFm(~4U@j4jXT!iIVnN7KaKQp0)j$a;bg?#`#p-2u&OH*L -sBkgUrMbX(M%1pO6k-l{Anymo{cN)98Ht4+3*;Nv`hb*=I2`B|ttgI4>EI6C{4$g23KEx*FEI!$=&@m -}30=Eq(Jbuqa+U_TYeXPZ)ZIcQ2a`)fgOFfY!@fz2c_zT|Qh&wuWIUmM#9eWdEP#-PDCX-n|;-Tbzu?;NfJj5A1)l4^ngn44;Z)J#lh`lV_+0F# -qWUXpu=Ox_0zrF;8W16LZZD%S1VXCW{qerFi-oD;H(u!kN+qzQd22EkS{1{h`%xS2E(a7e#vM6Nw~op -FC>L2y|l_vy8g#nHMd<7Iy_M#EYU)^BB`So1E?AkN&2k3uEzhnwIG$+S!phF|=-y*9y7qgqRG++r`uC -34ZspzxzBZCQv~T2u8LP=6jB2i|Z-$CyUz2V3q!iudp{0*`4w2gw+C|V)*Xw2)vfnoZj_yP1OLHD2JmM3o8t7;B$QPq1m@qD3{9pVxB$n}wnFdE2*D-@Rxq<`IJ_smESHd-SJ32`F@# -9>n?y_`2yF>kXq*Z~!hb{p7u_F*kx&>i6jYC25_;|n}!#1RC(5URa4+_E(WcZzupq{*kxP{%w3z~3<& -xg%9_(7|fcMX4%n$&Qw#|1njy*f+*X?+gE|<-B`R-zW9F9DSRDgwtW-;w>5-_?z<{)Z=-bO^ErlrY1s -fxg}VzRXvGpUTnU>vYnRs9RQ||xqAz)o&+TsP|$lC2edWG7^Ixm?4PM(VgpI4;0T1cXI?0E>khd(NT) -X_uSVjOKsQ!qXddGRWC%ViSm1bOQ?NLXGhnMZ`?qreQbVvh@?F8s2!i6T_&F2@aczx?6EFxa1MJ}rv= -lb=0iY@JCKw4DxM9O3e>{S$VTIgqNTHKGuw)tOnCb1z1x_78IIm!lQEj_2dWYh8a905-3fsG{=H;d7; -6bC7U5J@i1_!WXq!`SP#LnE(>?n3hxCuj>R^Q%Mt=PeobE;JIfW6-X#~x$$f^3UfbRa26?j(xC@${nv -#(N=e6>>CdFr2m6np%sbusyku8Lbg_-c?|jjk!r9qBS~*3m?_)V1bWywF%EhHV!P7WB}26*VEeRWtVE -Hm&}^@{Kv<~V0&t18}K8UqVO4frCtfJ>Xo^8#?|azSZ`7g8lh*toNrFrN!-fEOGKgsw -&{c_P&J8_3m=7Gbv@!*-0SRNr(NoGw9qKw<>GuMi+D_To~LWjq^`~ -%CmA@VSbs8#v+VXHhzgv{eAiqNLkpAEQ)qI{2-bpdk7D2fr$nnE5j9LuZa|H!rOCqqIxVgCJbTxazTX -#uH_d8xUHf0&<4m}k%g9y@fkl|MZMG2uA%n4gW`)NvPf078U+CrEg-VB^BfJp)3 -muBvLxc#D4Li<0f9lzswTe+QF@BZ$Nx%iQdY9zY2uW2Cjc{;wIbJy@>#%60L)uT&m@ku5FY6L#bgjvr -3(WnS*y1?;KPaXKqC;kqHr<)ezkz2;rL#Au5lWHNe~h-D$Dzh_Faf$ps4}`1ChI#vu4_ -nv)Of5HZUNyEUYzJ>EZLc!c+nF2)5L%cCU`y)Dw|`2_Z80J{~SN-yZ>Y4!5u%VF@e`W!xt3QcXs68Eb -;!WGID6P=YQv~Zbl#?lGhJ%7RKH|v=Slv!p1LohnTnz*N&%fTkjdwV}a>7He?P#6IG;do2P5qdSf#@7 -50`V~mkV^dxA>yYR7z*%H&ER!Wwpb|{;UozI=hb+>{AAA@g989j#1}(e7<(PcKx{CiqOnoP7oM2@%r= -rO|IpOcn*A4EgBl!w;*rlW8+X##5nDz>bu}W=%^D`2%uMiS?7X2hoFU631&b<2>Mvu>_<({^nJ>`We- -8&r@c`@6`^)0AJ?s2IYpJz^m>5@;!bqYt=G!O2_dq%-Gz$ZF8LAT+P(1cFhB}Bus1|53<$2+ffcfQ~K -CV91e^vZ6+s3-~An8=|*(U3ICVet5|-JtViA?&9LMyN}OYKtJ!J`b -3O4diiVqs0P^Z8{I9%8>piB*JD$n}F;%+o|6>0#VqaSK8?y6muDD(s7>>gc -I_ -K(Wx=xC#YZj*OXgbD}vVz~h?;n%>?>*S__$0Dpupxt3N>Qh8vN*H()!ZJ{zMxOMxc`pVh{P>sR><3q1 ->G`V?NAwE?*_R{xGxU_w#{8gQ#b|fb4$9iDBNcn6Z@Y*XP#N@(#o*A$Q}Oe9vv*jL|qjHo+EZ}v3x}- -bp)f^qi%0|1Ph1uF8bJuUZ}1%vW`r=k+}&_cRGjNY&vVv_xyG!-NR;CeU;8AgvYI)B(r;#(-O>=jNsf -Nb%qW@8K+}NTUiVp-Ltfo=arze<+Y$Y2LzQyrv*Ixj5-rHlr69Uwu@S_onsB3qF%5M72pWJ`Q&whZ7R -7~3KPIa0s5>fyo7yWhZ8qy1~m)>(VuP*r*cX4j(*xPt9al*bPD-65W?%FPrqL&l@lI!1ttQ?^Wa>`?j -67$J!+{5oboT&&Ly=n%BY>Wob}1yhnFt1MUCQe~lHUK)bKc{n$7id%e=K0p58_ZJ`qm{*~PFZ;pSD?mu~mbQq{c29cxDsiD~i$JeILX0^b?U_m~ -0qk-^C1G|B6?A#)e=__`DlZYCcnCT0(T<|e^Jv0#Ij39fjorTcF!n3Iu;Q>@+Xc9>GjLa|PctlK9G%| -=|#NFUuphNVH+oBp-N&H?`O_GzWCVnrgCg@DolGxP4@od^jf|_fB5%9`Eil6X;+kJa{_>bhUlRG>Nqp -uIXL?nC_o!m7~)WQJqHh)ye7Y#@Ul-g -cZMzhVTx)iJt%of1eG$?gI$D$Ne(?VfXOw`$xNq*LNM0*>pN4ZCX+io>@q=#0~7;802piR6Mzpa!yi| -ZQ{T~^OKPF3=<9-S;DjK^A*pgWriagrYEb9=d*?mI_Qk!8?!FqTr{K6UwY-$^b&dhBuN -P%(vsJ;AmgkhQ`&rgl%Xmv`tmA(5RD#!)EpZ%+Nu)XTfWrpNxWMy(gD{E~=NJd*P_$9&I5hjGN} -lio#WNk@HB9m9;!hME`45X8r9Mx590H0H{3 -Z&TejR;1xFo&_|N+^QJbM#G8u#_Xvei{6jmy_xiv|uRsdVgp8_4dKRH`~YC*e8G}uRGwVbc%$<%nU<( -P%>oEgQl5J*(sF5Ep!k0q%3Ext|cE>G6-n2s63_=9j3Z=uz$4o6IZWPM}7T7WQx90$I#2P4x8Yrl2W8 -@YeRU{Vr1{#3}9o~DExOgfLBX;$*`=h@}pz*2)pyIdDA)*Z%#<*2cI@l=;Ay@cye?O0wQ^z(Wx(c7Xv -?6=ZXCM=bxEYe*W3x+}a!Op_rKNo2q1}N+Y3N<6w|-7AvK*`aveR8(djrO%X3Kn8Cgn~OoVK)07*nTOheh*w8SMOYfF`tQa(}=Omd+~Ncbk6&y_o$G&*jv&D9Foc5vTy -=fDHK^g2Vcg&pkO8IsOtHTuc9g6?6yxQytEkouU7`f{%1@>T^$)V=+`jnO3^JO4>?nL+WhA-F|l1={`VLdf^Ms0vzDX;I+&iaHp7a(v+0%2jj(`a)fBqQ+o1cG{Tx(KeYy%LMNa~?DP`I(N5h?}*fVQD>HRhOwF`fJW{4+b+BQ -!4nt3Eu5sqZ0|=LCn!g+gDZGo%Q3>o}Zx8F`QF4Qq`fKu=Vn5*YC?paF@}lsv%9W5Ov+bOCvW7CeEnP -XgIy(6gvidriY!s+0ho*Ymi@`C+`!@A -h@*2o({68Tt~}LOT0fH>WjVPr5;PkDJZjIF=lboG42V&8~AjEqLobK>M -y7`|nZQ%%Zx@{v99-CjzR*}|r{$1jHX#@!YZ!bMB!jS;b*w%3F%Eu&={oNQ8+V3!aJc_JyF16p+wC{I$@bfC5|Q}NHj -sqTNxJdN(~Z9*XHTM&c;gIzCTHs5hUdi6|IyH5x|NQt7ke-p2md&Jwg1-NhdSJt-AAXB)A;Mt$ -=BBHY(%?>4A6??7s}LuMj$dR`&E%$PSznq#5oEYDsqBoD|=+BLcoHktOAwCL0R~OTGIgqUs3SVvtZmP -&@rHJaf_5>t9s$cM+41fDUet3P&De;$dslXRaLE3)1o6=7Y2~XWJg9nr|=3)AMi`I0Nzw3O^+cin2lWEGa#v@=QZLDLLn;m`628t)M -uX0AapoQHdd~)?@b~Ihc!~`u<{Ib*QtfLGGs%r?6R%IbxA!LyG1gK!}Ve6B2NX{5lKPj&I=y2oXC~od -JPT?`0m)uE|sxOixa419d0m5*`3^775EIbpET8f1Wl2tU36vaA5Di6p0GdBeR%Bv(DPx4$!G2Z|{R?2 -FrEAA{Yp97~rI+&soFb#t^w?zs09nd>O;51J>x94Yc;~xrHjXg>j+NV73LVszeegC6o!mi>eBuXYtd4 -82%Q|#}-M5osLkK`T3ayL;U(oU5ZkM(chpeOPORe=(v^l!5i%1@6&PL( -5|SmK~~CJ)lX$DV`1-$uGIy|dSSK#?<$qQBw4u8f>8Yoi&y;?KGtW~1XgH!o3pyb{wU^ghbKr1Jx~_K@cXqTA0$WKb`whmw) -7`7cZNxRbbe<$vyj>C -UVQeK&*I?Q{Elacl;_%PYzw#QD6N8GGp(ug5rcQ3mr -;V5AQaLD_B`gK+B{f6$$Z}XfA?}?{4~*Rbgt7LH8NuXY6=s`pyONdZEoJ)-U2Qr8xvpzC_ik@?q~U?kmj1r(9!8g#-pWVW{(gsA2plsp -C}a*QOG1sm@sfYoAHihh*w-w+(;hv^p}P?aF%V)>RzBU(hw+$IMYK=x`2NyTzunEvt&3L%mW=v)U8M}0%3Xyq2&@W10%@wh55M%0;64rtIgoioQ9A@q -%=V=z?j7BQT=&KlFE?gYPGVYS3!t;A}BM@Fqm?{&S#LnDaWmzGfn-ZB2in=a1lv}yaF>((|=CDuTwR2 -@46?-dMT*#6LhDAjC6bd`U&T|5(!r|*&9FSR&PgdK1%s$T$9$=%#j}y<$wt7a;V*eccnD%fdVKu;20a -Nr!#Z3J-1s@IYOxryu?>FSLuq*8$vpT;4JcgY#+2nUZv(XJwGBd=|1FCDe_pm7qEzm{?R42!_<3~%j= -!UL2WRjK{zJ1ncv3{f-+6&T1o#Gh7WdMop@wmv+dWokm7FpgZ;8lh0#VC2BV84xa9$$W4IP5(!b5RD;mf|De{4 -@CsL!ifoPoY%a6X1hFASx;x-g47g*9BRVYDMo-Nt$NTf -vW4oV^NJ0X;$@hGk4&+fJ|2vbSmC{uE@dYmjHN^n`HHU?;19O48@voK%Zn^T=e-CKPhxG2zh(6{38@D -3C`d8ra!lk-T|N{-_E>M{^W7>tdjJFBgq&Y_*6VRkO%0TD!KUW5FkSNV%7K5BY+E|3dkQQj{eDDEReR&$B8zOB^xzmNbR7 -R6lOtA(ZG>2n044R_ZVXsF{)8SGxiPsfGY##akur2E5=ofocL5cXYn~VLpaQiE+$lk8_{VGvxDApS#( -liGYdYPqjEv=J)Q%~1bGB6^xUoG>6gcy!GM+QKlIqa9hyFHJ6+YJAs^$S!t6p`}TV8MK?I(l+o23L?{l2wi>z!&7n0kD8&zIod9IC -Qo38k;AneuM_T>d!~Z6!6TND#F;Q%`L`|wts`+zyfi^xS5SgIed2~nwPS5csrHQ;j -7gR2Sx=9cm$%`t>h!V^O(diLEB2#H;W{c1}o(lpP(d05~x}pE1B2F?z>I~Z5-i<~D!!PY*7P#AB1D-g -$8N(J~c8pBopWH8GpT6Cl;|n>yRG^^?yRl&tG9Lz;3%aXsT}l8LyOn26w`H01S_cq{k%{cr3sMu@^r# -|}tS|}g*W%cXD53)XR_M)Cm@k676B3}=S^eRj`&g3ApsUGeM@AHby4Ue+|IG}GMUsgxgoHeDF}ml<;IhPjysdtG~uhqbu7Z?nve0!A&;;g^Gvy6wKQ_895K7DEDL3% -6iZpW`ofN7k2{6@Sb0}om(^`41#YgjL{@35N##6hGGA^~ET}9K4rGqE#}Y2fM{JC^E{9rnbUKYNZ{C1 -)()+j++K1Bu4@K^&xM%ZUCj&B`uSppXuf1w2x)=_f)kXBOxRuohfK+@DnoN%LOc{e9j$?8Y#_18dgs( -m!hdPY+eu<>l(z=URA@IpuCn%e1qi38)B9(~xWW?}$xUhX9OC-Lqpj4W>1^d+HOk}F{Y3r)IOkgrfdFO~Lv#sON*4E}G4EHv_&S%*qPvfe-+{9m-$ -7%hqw0!jZbMhbrSjD}BhSyb9(-}y?pm8M1ci33q#`@8qbiMY;)rULDS>U*8P;W1l -B+TrzMx~B9og;D$Xu)*bb1(HhXcuv_ZC9)qi19!Rw>F2J;?L4tnI*y>CU1R7$OdC%a>V)+tK49ufE9B -vZo;=i>j9QQJD9enIC)4G~wAMC8=Q(Q|Y=@(d*@l+r#KRnYZnbd(Rd+sk+&N^zIW*a^7>k3x0KPxkI! -&0``ZgOBZ}lG7*sz9WY(oh5@FB*!T+m{VS;ohITjbBfH<6;Q>uR9V3HN?Dw!MxrC=>Xofuvlqu?6i4N -U4qexbtf7huviNr{mqX=xTa|c_G3WD#Vw+(4A2D_57FT@; -m(npuJW#EGDa-^IvFByYBihr`1yU?5#nLEk -L}d}Y%}0;W)GGHrUcWO-MljF;$>e+~ZQ#Bq2uV?8368H$u8PulLVJjt6MFfP!M>Ct~?TzcL<5%WgUqV -ML&FRhCs@q<~wGuun~+2_w*zR)=xP#q+$hWFp4z`F6yEab&Q7m~oCykwaIJJP&p&=w3l&+)w_f5|@f6*W^VS7}DU?ZYm~)@SrCt4N!Q4 -@gy#XVIls=@m)_S55RwAZ+D{;Fhnw|-VINF%;HR(>SzB(C_5+651PEWU2wVX-2Kya-B?!jZZbkujm*}vLP9CzIMAtHw64*UJ*cUub@ -^9DJ7xEtuH*@ZqwqrI}Wp^T$+7}>o4X-;X1`}YtAZ_pE|?xSmXqU=LU?>u(PJ^z|4wXkiW>=53n;Vu= -P1Yo9CpU8(hMhCOA)PA$q=hyLZgeCT^SG<3DfkpYOt9cntp^$jDAUR6P(7oHNzA*oJ@`y?gup+x;Kkh -6_A)r<7`X^c3$txWjMHo<8*)+3-s#)1YuBo_sYDAPi$1%Kq?Bsv_fg9rTq-(G|Mp -efhs|$TFsx&ra$J)WySgD~TzfEvkC6!6c`)!zqkqBxtQ$BeJl1>aZ`OwC=<0s>#)e -hRe5q*7*^=?zKCD;`re-R6ld8=7wmix`RLrOIXsLyavH$pm1$I?`!kXi%Ib45z5jxOKdKPAC||G3 -0^FRt~pG=@~4BYNIu8q`;@cA`_{N#$0OC>UL1Y>^%nhSplO}3tQ)i9y4UUM8yj2n-(oE5L^H@inzp_m -E)qU^we{%D)}tfXI_S+M-SDQyIq0sYrDm($goULgE!$`6jj=;u#~v`rm-XIqJGFx3q_ -s{U1)Qm3;Sl|L<;Mg4184lYjnx_IPkg_SA%K3 -`q`mcitTyq0Q4*=j5N8r>DbT&rTnoKK>2=;RnB;84%v=9lhB;hDMKekKOwJJo)FZXOB;R|LycwYWu&; -^d$KujDhTs34SwF85L=a&(BRmu1u>w!==&$j~^4u{70^>Ma-?kWPbU3wpHn`0-jW#Y}uMo-QqbyV%~YzH1Qq_9JfC?Wl>*5A5bNZzw+k1vX?Tz}MHH@rS -?Cy=CF=;fM54#!0%rC09YvI(8aT|}jd$?+@r?T!&=;mAL+i@}0Q}7bHHhB?H -@hvVm&4<30e6`}Ir*3&kEMy$<*hab$k_t_!bzPi_yzIG~Mh6-SBCxC*+y&8HFFoRiN#ml#rH&hOBfY6 -8>XCNfXd0^!K#M%x7qC0QQtzRSj8Z7p0ZoffdeqfSEf9enXoe!Q4?EN#bVNo2< -sfrA;u_Rhvy}5gtyeDH=D$Ziy|hLB)X;p)XUBpU2K~6G7uN8E1T-0x1g8+b37i5;A=vIYUrUveHKJEH -kerWdk$!OlX<_tSXCpkv{Q4w`JunGnI%EW|MDSCY$ep5VN-Fz+M;Rn{0%mi6e61r>V%93jYAB<6N1B* -H^?66waKy833kyAikrnQO(_B{ro~*{=nK;n6z^MSP%gKr|9^`tIm*pLiebrgaD`SoHtrVWXbEB}Gy>8GYvk@Ghyd_jDfL6!FgP;W5Y`|L@)2;qEuxDhsZ?@jb9f=J|_<_D9Uf$eJ -IYf9CSTJ%YysB57f_^}$0e{aMGE028DFI`h+ -GqaO(ULx^b!N%(5Pcy&eJ^iTU16bg1|lHHytz#@PO;w$iNNTrVoEecueOhpqqlpD*pZEelMtj&= -z`kD=$=N!9v3fBIgai!?FmbBk*jT0=I-IMKzLm)@ndhok?J0vv4KinV>^*#?O3eWAI}U&dsShUINpON -B3aHN2*Rz?-RD$?$yT>ka3WwI -l--+tSj|(}r1LmBq+oF$=YR6Z~mN?9xu9q`y{s|@|k=yrzkXrm$$|Zg%T@7Ze;d}r(1$P=~!9wSR0ok -TTXXyLjzM6-QiI8GZt$I8kc#2#l=t3~$yyPuign%~^q~mr@;AoWHAcB-Z@Ff70SDzDRQ9I(=k~r9IfX -*?cPlH;+d3KfFWLz2}ENqC-I}rQlc(N(N7_jt^)D4xiX8(IS=!cG?6TZCsPhK5o1B8l?(a!K#jh}mbn -}tQ8uvrH0$|k+YT(Ou6I{-;irtX8x+Sn2(;F4INa^oco)8z*ghdk`wQ8d1)D$JcjU{Mw}!iL4X#7n3| -+2~wJd~vw$3Y(5_Cp1=uRinRxy+}F>$L+tzoQ@w{M3nT4&>+@OZKpiOkDpPS=SKpQBK%OVO9tl%JIq$ -!9lj=Z>SjJO&=(qd5;N|5avsShd=m`pkQrueYpUK{E^I<_S-6>WU%=%Z)6~pdYyFZ>$Vu2JjbZk_cTe -dTsV!ciV>@LN#{038>zDdiCy>jFDD%+3{-{g}CpY --3|3x5{^g-%vkNsc+BEPwjx3%Y-TvSML$$P@~|q@wai*lHxiSI2K&OXnO;E+*n_?(TmH&~=%^uz;axC -L@#0L6N~w0s^)QjEypibK0>Alj0&sk?2sd7h2B9M>%wma_5=|i5)cVVc1rE-B4nL@(SjhlBn9m;JO>3rwY=ra7*r!2hi?^luidYG_y~GX_mqoKmw#!Px+>M^X4Ob?lFB4AWy;s5vB#qa%QkcMr -uN1jM!#@5RASGbCT$%wre@GWt)TC5&l60{nE -MGo!$It3qj5HN{d04Ua}ypqXaR;hnX~cKRt-T&uVLpOZMEld_)rZ0gA2W64Or?u=aVK`*%72a)NJMl; -RZ?sWG;U(XI29Qg~4vbAqhl!;x_{6)w)RBE4tt_6~inqv=82W@oW%*^hqz!1bU3jgLIR>1Y!@$0Hc#f -G(8JKxd%Lv#4F^jN>ojFC1!LbM?>O#6;V+i`(}ZLzDBR-35U -Q%Ug(`I@)|O*GVt{4CdDix#?wS|l(80>y>s+~?J^T9)0DaaQ{|7RfC;|oaopU9Jjkd -vg_sXtC?_%=BMx3ww`j&88;?xwJjv36g?3SlZau>M%7?o<`-k7~nQv?+&WEO08@VVs@};|;aITlemyl -8Y3DAPPaM77qIb~&rL9cAN4o!zeMa%lG$R@~27==>k=$=Iw`nMHk=M_N_CJ2s5k#zteWN;Paj1q0cgAvhEN@5bu=ED=|4;2W6@~Icz8XLvf5Eol+cD5C#n8zJ4E932h9GdBj1YUxWGnj7&WGQc7F*|;c{!@# -D5{6Umc(iv%|tdL67+t|9LVZkJIqvpg7a?-U)Un1AN3Dtn@#DuXE*3wuo26>WG{uE60+#3MqHU1_E4m -e4~$gRckV@>%@moE-vZM`Cuha#|ic-x@@ic*qPz&}=}0xnpJSLG<9|0Ps$?a65#r0@8L5?A -jPE77Seaq2=z;58o=VN_DW$owHKSQ!V6+Vi5Zl={vyAeixj#ZCtX1XMlm`=G#}{De#-utaP(x$stMgg -<<^MZf&+j3lQ1vGyr04s`C?I=*qB=3YXPkL0tq2=yp6-`2%q;3v{c6RU6K?R3eX=;LJ#b7d^?FO+8Yb -NFao-j$Lf-+?2EBPmB$8Y5K%P@qJr*4r_3Z?uQwfFfg*o3h)yK%oUf73$yv|MszV_Ic2hW6J!~nA27J -r)LI$MHo?KK^4?OyCFJ5v#l;?6$e>9Yn>ofLZV0^>R)%5nxh{Sv?(N5)yF*gcmV4X1<`0h&*hqlq!Mf -+GbjF(CjH&{X!z`%sYfgk&{(H(h?9I)SYPIuyhc4=n25_T06*vVPwq-vuG;Er4)s&dwx6OAKkQUpU^H -YUO;2Ptyb=z6Fog`38i8R(hihuARnJ)yow*8_tsE1M8;83NtO&4MFaa4^f)UCw+-X-knumEOzbsa^vm -JLkyohf)vhW@!`?^Dtm12w$+IeumKclc1j?LQ<1p5;>Yz=HLi--I*spKUXz|TQ3pPLWCH8Hi%HzX)uapyS(&62DnMfEP$_ -{Uxl^N6<-(OAx;K7ZEJBzvYt7Ha#mEb<{GgW{w>~dRaWRCbn6b~*IGwd~nV>4KG2_fk+MD_>0ikQE&O -uG$M9@PO0^Z$E5q+XCj8lAb-m3uekpg6=<5gn*Fpv_Sa5-C${y)WArclwBmx8LXhhmsg<3U7ZIVtke% -_B8>B0)+{97Oqrw!u+;ACjGPAUsNq7&AsOJ{1X+O$%e_y(PfFfQ1oVLgUaxsX>f=dDR-FlaZc+C~-Z* -r1^QZh%aV`VxYaYMsrknW?B!cr_twXvkkIjJ40?z0tDw`s} -S9&OcK-)w|+|QQZRu!Ej`NkOh=}b*%RyV8SMUnMbEe<)7 -^}y)dcQWrRs5yAgRuhQgth=B+5c34VE=GIu!TrIWQnlEbTKd`OYn#bR$xvcXleB55_CUI+GZ_(t*D%- -l`5XcF7H7efD`0;PcXqfjSp)M{n2;nbu1i!}wW7(uNS8uyC}WM@`MLHtyWeiVdyRhQ2m42R$NPu>2#i -}gK?VmIBSw_d?DGBKo1t5G`}G^FhUFG%(if%h1)0}HXXnRkQe{twdiVY}`6IiV!DulDb`<^_P0L}-1k -$kqnK#v!&O3E&rYlDDTl4h2Wuo)CM|h=TWVPA#g`it)Fj3J+_dupv=+227*(1nBDp+)?R>z0wEgK>Z= -(oFT3uR0VEB0JD&luqh*IIv*Pdsu!sA!noB}GZEX}QSSu%Vk}aV^PPh1e<5m%*H}GK<%`Gjt-TTOFbu -2MTV8g1#-?0CK`#<#pwpUzFW4edz#t`y*pLPrX;$I7o8Z#B6DCCJw;<-j~If{ZmkS&9tyO!nDnY -r*i}AKuo!xbgcoALE}1tU61k#h2n&QK3)2ePQd0{qH4$opXFl|$$AF_No#2sit)fy4%3%ONG^#)+Y|i -|w2ON)-76Dxs)qnL98yT|up+Y^3GKxaI)MX?{cXKuV!(_-3%2#ojxfT0qD7hg$p&!Xrb{N&Ow8D -FL7*DaiP7_*L@q31zs%n-s^3}ykb^|vHuXYr(?8!rfy)f^;-Syo}vva6JG>aOYeTvPUhHCzsBi -vTv#LFYo~&4Pnd$Sg<5k~eJx;s@RBc(vf##z4gW4$v*PzZ7Qp5esf4H|K8bLKj#-R!4D`uuF>J8gX`&!1!c7ndF;s4MbWj5qPhgxe(9E26%&!O$!7!PxpQE8_l^G -LXpXf1q|XpXe9Y2>@gSz(6?9gabd6#^RL#7%mhko-UZ^>qAAow@3&6n0mNCk{;?4%v4;8ukmWQi%D_E -C!^cYI5)PE8y!$1zty1pb>DFf4kCC>{LJS4?U7Z^*V*4@SOC__`VSVfUwJMPH_7sNa4oPwRk@RA~aXA -+9W&XO9&R;jS)Sa_|2XrC2Vz!j-82g?14qIy|-iAdP&7--2ziJJv!tSKcouoYKqPbBr=8#=X)>A&Ead^MKaqm6yMwMUIWzn9xI>Y&GV69)YYM>)1~6g+gmifkL=ge|)# -{951JoRW^hbc+BBHDqn3btn2=Atp+HS{{|a}sTfmeXI_qr`9ySc|47(v0G`Y^obt`k42SaTw$Lud=0t -*Cik!(M1T}U}W}*RV(`f@vomuk&&)+zGFNBCCNNXGtF{9MD@_1K7oS_V*uAt>BY4!Rlu%V6oj+&XUS)u4uie2%?kXo -`{uJxkB33l8b_}H>&0^@53P}NAZD4C^N-UzB)gv^4J0=?e5JZz&JK1g#H`i0vHqlJsToSj1+-GkD_3t -|S2Ey+3ejfzFrWsunSc~hwxMmV2?+x%iqd*I_z+n2^u==ztj|9EKxkIaq@$ -OCC>1>!9A%v9eq2|W%ota6gVEEJ5WKioNL)(}{&D3xqiknp{+Fu39gpQAYvcdvr=K`>FFi+pa9pJ(kN7%xdyG^^M2tYUaV-r^2yfCc@ -*ODj=Cd!ZvCP524v~4hA}){Fd|@)p8(5yz9JbFQy#YQ?3;$i2tMsriAl_Rz{-Dl^jE`M;wlU2TCV|Ta -Y&#TOO*gs2=fW1#gf0+~j0qCoiWh{Np^*cgBjw3K8%B{yXw3{Hr6!1wAl42L24V%>^P8(RvDmr8)E&y -GF6a?qOcnb)e)G}(CLa|4LF2kS(u)w29EHZ$?Oh>xq0r2n_iY8B%ou0p -PoV-LnTz0D=)$*iBLINr!I)|s%k+dNM|@d=S2o0$&ciiO{wt5tuzSYef1c<>()opBnnNy7TXm$ -12#^&0@&e7K5hQ>`Lj5I?4c=_q)pTGR#DZHe8F?4ifNz>? -@FEA%ypCDhDrgu&Li+T0kdT@aoV|!Jz7*b*G>~fOU6ERI20>>K?bd7N-4JL`!B8o*iFPL=F+*%DJUMB -D`kvZ{%K7@}nzjEl-d?~datFh0xvGM&SY%gYen#jaE6Lyi*Szu-p4KN+)>4cBS;4xhuVUX06N@KN{!V -DxS+B(&=v-3$pp2nAe;Mt-f0M4Bu2m~cnqmVW<^bMF$R!!VN8@yWcI1@^2Y6bWrTHU1SX`jIH*910|C -VGg8w6DvGE$M8)8}wgj@-T0$k3UL|w-3MDJx-4IX*1WBju0fqFxVnt1jL%5e2QY$mMJ{RHz2U+HzW$d -o8R@>udQF{AR1F#umw9Y9*?@jWk}jdm@a9FC43ssyR48{_>|^{qn$V3Brw$E_`Bl-uNRYh8=9>8;E2? -o4vrqsLz%1925{2XAaI-i4^T@31QY-O00;m`Rt8hd&^q#}82|vcUH||d0001RX>c!Jc4cm4Z*nhWX>) -XJX<{#SWpZ17bIaWGpd~>@I+7z_r3d0~Kk)_v4vVLFYH`H-!OS@#PpxqojT{;}8Ta+5{#tAe?&JvQj|2 -VMB}l)by+>}*q9r3pJvXT^1parSk(N~S>(rHPMC&pBt`zIlCedVb;;Hw6olDSQ3>>ASaYzWU+a_ixX! -(5G(p_V(`Id$U-^e8H1~Ah2}C0yc~JO*Dx)Tk|Z3Qb3XA;T2S4%Pd_-Qz}?3muXh8S(>r4le6y8QLl6 -VUe1fvvPjc7?}q7O2|y7J;*j%2kQ7m90QDsf_wPjuf)%IpIh5=7jN`{ymM)ktz%ltHFEXe&E;dV^s~W -2!iq-dJkmY=w@t;>wM#Dou<8ctj<1ssC7tU##ErK}ug-?GJ_&6PA6n+;JFyPFAA+hqu`IgUvaAUL(1u -eDD<&cf~s;H&K4~ZnJM(ZTY(hOV9c`+7~;EZrENGqPfSR~PWsPHY7x#MvXEckfrVZHnJ!Z^rt)&ko7F -^E^39=)MJ2Il15Rg^RM7bI*|wo_B*)2w0DB|tVik&xYV@)HjW1#rq|Y&?#Vs2GpkoX4{c%hfmh!6JVw -rW6L0$~ikt3%!K+RFKqx_W-^{>H~`sSXTLJLR4}*6aE|Ey=M){&Tx8up@|K_-w0Sz^!Lv4AGu?Jg7E-lc?vLlN)1O_#euuHb!V!1KET7Fy`4D3-&=kEdyv`%6+o|P@}{2LlHv~37cWTVS=ZkjH4i=MXz}6iWcGz;r*088TLk& -7F8Y{i9D?LAMtOb%KMBM5?ch#@JKW?vYSG!ZaeKy(PTnDST=rF@DI)1@k9Qy{q4V=d -(~+UCtIulX%05RNHbvT<|Ob+|~wLkztr?o`?dL0^4L{1yc{FOtCN;>Q>fOyR86Pkk*yWxiBbX- -9|N78aR5%UR#o=*M)fBE1DjG-< -VUY=bQ@kp02t0=Cv!Bn&D^JJP|g9LIN|B+KQb&Q(nlBf(|U0lB%S{-fmo9TZEU0gZ@1|%JjZ%X(&?J# -OT4j5O)pl}k?rPmAq9lcdNWfO3b$fAvcShJ+d{kbo?AK<{*^;HyJwE?;Y|3bPwVAGbI4TMhFd(M|ED# -Qn+kecAEp*|?1S#*PpbTRA>MjiGpTk*DT|7!)T0uqFbDG)H=p{)}kV~CFx8qMwNE7@Hq4YcBMUR~QI3 -g=fu!qxscayMAq3MCL8GlNLtnb|qBnwnrj9}rvgW_5P -AVd{c$gS`0YLNTsOF#+=jPV=wZ3%z1(f1Wezl -VmnrB^*#_UIeEo4C4%~~N`^&5D|6Wc-E-y#y$qDaV@#vgFG#ju7U?)e^kHn^-_mjTpYv?Xr%PhKp -Kwpe?pb{zSzR8_K1qfX=gYwM2v#zIap^C96egc7VKf*B&XuHA*j06$Fx>FXN~H)7(+A9?VqmY*88_1d -OK&DTr?u-Tnv{Ue6eU?1w%NyZw>kCplW#Q*UH6;mZ`PjAIPc(yMJAs;`K%ZY_}mm4O;llpYN~mjV@;q -AY(pd^S=%y)KLUyabv)M$;-F=@o#r3etYTrr_;|MZD>-$*O=ZLJ;M!;AqVVe@*tA*8y -eN6kHVW`l{|&MDdiukMe0WhcPvoI5c*kSYOT~yjHEP7Pm>Y>~-j|(uioSoRi9THBCY$DCHtC#>EQkYI -L}-0*4b0vxN=^@5(r52Mvr_lmIwcLNX$l6+ElOO^9#tGq6)_YU{8o;}Hwa3BcIu_PvrJkn*Z^&@;qGo -oWikFHXlRdsZ+AX^a<`Na%oBl3oMd()TPV$gu+3zMz&cL=QxcF+-gA(Y-Y(R-+45sxxepc#>_?ZCP}+TJTTdapp -iVfe8Oi)d%`n>3vo1MT|*gDEf$2U-t<;xJ2l@X_z>S(W{s^&0f;uZO{)QZT932&)DDQCaZr`~UoY2n- -HPK~8YG(l+{6frYohX8UXrCDCHFV8wNcq@KW-Z8XcOYT3km&11H}ILuYBM(Lxz8QvwnvvCBh?u!i2WlDd -iS3r0o@t!0d=-X(Oxd>87{ec7JxltH1<^jmKoc|D;60wbJ$ZZb?fBiRZ_dg0EZhqco6ZD(h4?F@->~S -Nk@x9)TB7qH*|>%DhG}eO{}hI+#8${-HH~W`>R8OLd(&YX)eFVsip;%{L*B^uO{uPKkbO3FtjcJo6sR -{~sAKOGg5ETY!-z6qR0%ELjV(NHE)p_(VG^1ppxT|2f7`d`DkAd_+^eIVC`XdG^tl~t7tW{>7fy8-Pk -ox(pPrkLD-d6p-{$tWWAhvT*{N^DsgFT6i9q~h8>hBcrm7?w_HUL08%%$Kl{qGjW(QSw#h!%e4}}%uf -!w^YGM$_QN9|IS;K&S63QmT5x@NGa!6pIACoQg8fUqFr)#^3o(ZSW+uhxAtGXYOgd?V6Q!HBUSPkhGv`UAfnb -jKMwC{9OwEf4?OvR*OrKnv$916Z$Xw>>k{#;i2xXF3&36rx$7JSkK)wZJkbg6v2TPoXG52i%Ft3cmxo -3Z_!-F=b{kb98!XNteq(5yhW3uF{t)&AY8Wrtb;@A&N7SFcaLJ2`!aey1w{xW+b+bKxI!N1r(!_@4Ny -=?5bsixlir9d}r+lCa3@&@$&A7yih-oO%c=b9(+|zY2Aq`KK5e>%pG@j~jro*?<=S>W;ReRpJFyn(jd -B(slhu-lg}MK&%NZ2@J#530TrP&{%=AcBM#rd6_?=?JWs%AVJp9(k&X{WiDU0!unWvFrA}c2c6%DaDF -r8FhUX+5ysK8Rg$CQO5SrFx66qe#IxWwSY8F*<%EC+F}!HN7+1^lC66(y3qG_!!RRf0zlA4y5a8^^gF -g;b@a;Yt27u1hG{~lrTBMa8-3c!OIoS?A-)*+VqB;NJ>#yJZ{Vr?g9~Z+9{utKJ!4^inGnYCSokx3~d -vSR=+QRr6+$y;aD4`_03bICUABG2GCKpi)FA%t89E6-jam?rFe71r6mvWZBUF6UvfRZ)@L(I+T58s`< -ee-&J_VxtksJf$V?PFVe#rbMJ=b+ToQK>Qs#R!Ruhj*Dw+@%(n)u)bEfm~jYa4wTu@y$pc)cqJ?Tb&1 -sxpbIG2>8P6Eg43=Fj7}si33{}7G<7_+RRotr{cTVqXS)x(}%jk;@74?Gt~C;)x^aH9a(H|F^RIKwjj -viKc|d|ovN)D#6#`*2{qJ_=^&WRR&dOXOjiZNb7ZQqh*jr>9P|Fp1XqmvR;FG?eVc}1ZsO}SLOlZYC1 -1_N7iC*vVSUqB)G1@e7dQ+l)3og9%(QtlhT_3a^1%2M6`Px+cgmawp%vtLFc(oZ3A_AU -UuX^bp^cXIniIudB@3g5cDZ7S1dW^t%L}R3br1?|8i*q*)GyY>XlN@)m^=h`MSjye$40~j62TsvH(8F6&Msz{+J=oZOO -dXBp6@aX9gbHC{Oy(8VhHBQtj7qbquEL-WF8PWVpk!zi^Ux9SLu~!L;vf4~(CZiUD({oneIM?KdsTa9 -D(X3SWQ(o|F5hX}wURCo&X6}=1+Y44P6_Qv%3}*CnqcM>(;wI$FqAg|3O8UulQf4MH=CpC4lr*KX(4+ -z#X)wepi{L#65vmTgPzrYz%}epwhM6YUu*RlSSn)lB8^ER}rL_lDKHCGZ_|U@##gKM204S=#gRW*E0iBR!E|DS0x;N<#_7Ic3z=sE! -!~=LrS)w55u!a=mc)DT&6R}~)A06R%b{H>0)gtDY=AeQW0CXDUSJ=}uEt&@4UIdeHgc+|Fm)%PWU>ta -2NSFP~L3KzVa=I|oZg%*zkC6;`_u(DhRE?hB7d4(f6QPbiR(SfXsdL#SCd-P)m)T1L0lx`@*T9*{kPV ->Yz(4HJ!=&GVj-L6w4=R18(vSaP^iqt}yYyem(X~Kc_Ymy5ukt_ekXml;);nvbfgdmW!%+p6c6*&3%n -1lfnS7&+f053!O2BM}sR!+!M^oPAvl*uF;jH6Xtq$7*RdeX~p7_0IdkQ}4EK2&yhwSN7=6)D}A^@Jyi -EcIlE+@SMBCPxJ!R6H3MgSH(o;(i4a!FFXx5-ZM+}IvaCD_AxrKjGW&(8JT93TQ`I<;t@5_J3~dsIv0j%d{Z7ri>PHJU6EDp?O0j?6Uq{lD@qd~9;TRwwMU1|!1NNP!W2_8Q%0Do{Ilx1@-Mrzu5J -l{F|-;5Yu$ciU%*kKJ5S5Po&Atx7XuV}MfWNM*R-)CYIQ3b(1`Y`ec-V%Cv(UPC(h^+OXQfiAQB!`78 -{nTRt#jvQPB6ZeoroG;BQ%mjru*a<}?5Bu-kt+7!1mqSSG4sd98M)s<+p!vuJkPz3tYR6PvZjL>f6JU -x3h|@DsU4D|GLMRg?~zP=fju{9%n_;o#7qi1$|^NYslq<= -pY%Ww9&HzdV)5Sswzq)Eoz}jju8-Cfa}8&W+!sj;xf?q@<=L%Erj_n=rgzHf4)OQ03iVCt%Q8rwd7R@(s%Hpw%o$_@w@jZ3Uju%yxCKyT%*ihY>Oa!uN6 -bZ%&IYWMJsLh60}uzXZt_P8+~~43HHS%nz(&QdpKZng*+$6%AH2&?@U$&H!h;`sO9~8Ix+L?)!TQq_$ -(gi86DihaBo3gg1B_hX!YNCMnf4_DRbs^ -8Gg>m=O~(?1M)50WXfCTq(CXx3_kvg5pOeg=8#I`(M@L2pHw5Qie{sE<3Dx^c}P0nh*Me>4jMw%Zp)u -gb&U$r{&By_P6wZ!R%`Hi;p`lP64S$4m)7WdIdoeefGht5=(t?9tnqM*A{q<#G1S>Kr~41vm{SF&Zdjkt2C%XC@2xnURJp8RQo+zhpu;F6XiuUW^=%d}bR61M80fgSnmVnf -yfeUAO$FXpjMb|j!eN#E;P1L=qasrmtDSKmZL-SE+iDmOO4wH-r@3-)=P4qkFDO)q7=x -b#fPouC

i$jUbX54<{^)8(bhAO6=1ouGtPMJ@Myzco0{9-nVa${2_dR

Ju?n5**vcJfg@>t|8vK -->c8Uk4dpsOUPc%fr{8`pm0_MC_5y2S~gh<~uGn5$3s(eDg4O8VTezj@o88`&5IKYa7uHEUlP^oZZ~d -^j=miO?P{WiCEmySU9g=K&i}u^ONsDeKnmvCZp%lH~(y*85j>;v>tlhXZmO`Ja0)4AgImYQ}zsKlRr_TO -}Oi&NeufVYu|ja!nIx!4n+>rfBrwwKvzI>+6RDx}GVf*f5m8R!U*+zh5u6FIibqs1zwD`G0AL+dxd=+ -O#dU6iJXP~iI1rr6_JmTI2{-jE?>n++%)%<0v^t&cnWz4L(gBKQff?f_38|13#9G;9salSISA(MZQwu -2S0cLdX49NC`Bm@>Jdcr1o&=oT5DG8cV%O5#7luil>ND$#b%s!%+uedYy)EPw?9#$2Jq(hGBReqZ?C; -Rc>VcB;%p7f`0EQDD#SsK3xv-;20^;g!UcPZ)KDX7qp(!MY6lEX@wzn$@$9&IEZn$$j81u -4<+43ZH$7FpYp}FyE}uupE;@9CSmFv5^r95` -7UEX%m&}6h*c;-1Cv7lT6YBBpALU1Q!izbO@3if`iECXS*kJhcfAuB7RK*#apN4fRIpWHJ)@%O7e7v|4{_YDudK0k-P)%oA -0?>FX`!F%C(r@%-$sT>VGJ}q@n-fKDDnRN1p_2InkgW{Cf~^y{b%WCn1vLjfqBmL4Mcs`z!as!>jcA0{R -gz)@WmB<1ogbz@a^z7@awnm@P6-4dWEp9=F4I70mTgs>+a$20g$hS6eOWWB1Y;;}rxLCs -~bTGhk0H%Tpw{SFhnzjBvRwB)YwP-P>ij^9_4n1eIbBYP -KuzJexp|vhRIXVdVK#pk71scoFrwK*0exc)hjvU_GqI?YK#M99D#fqu+I!5&u?&(?YRu&mitHvC0o8d -%3me-6-G?XxIg9TnqcFp^UniH`AcQnVHmPz4|$bi7|Gc$Lpd-(4Ap$Sh!m{|4^T?zC)0B=)DK0RhHA- -uwvc_0dn)8R3(b&(UKgpyXlHMsv)`Wr#nu4u)1&2*b_)`5u3X(?s_ynP*H#l%fd9kd2Mqa-$+V;+*cd -Oi<_|fPPVG}dhZ)7e40d^3Bo*-2%b5qKLIhBy9{M0fs_j!&$~vhYG}=Ob#)VbCT|-E5tp{9k9I6|g5~ -7F>U7}&6W1X$oJNZ~7#AA5cI3UWff3%J2W+9zvNqy%0<`6|agA}k3yc0uAg(hqDAH5Y85*do? -!tLg&2>Rp0Gx+8=DNIIU^lN<<)Kn)ZVsf`qe7`hV(-h?mCJ)W3kbAr#d4R|hx4YII|os;6m&D#(R@Lk -uM>HIgfAkCS}{g0FDP*D#_mva3jiA8fV``*nX2|ZRjY>8r3L3Ap$dAj-tSz*dPB5TlXb_T|CU2H$)&C -n4(63A0CEFQsP7^>@QZ>KEQnI>08r{? -K6dIAd9$YrkmRt^5y>>YxOXsYIvY(ZALL-gbMmOpYQM3>NnC8^TdpL@uBH6`Md-Ikdv(x!D5Qu0+quy -U4u3JnA2;RM=>k3p>HN4Gocs_TKH6UTBIVFX6n}Hb6`>0*f|h7R?Rg-H`j{`X7Xl#zLMgfDTd57%Uxu -FInjsFz^S;Z&I2}63W6Jq$~Y{p?wg8}_93Juln>)9=7Bjrw}=){is6|&EA2ZAFiKW5fNwuUio_^Cg#l -Yf@R@FS*Grb$+O(;Zybocy%N7cpL6US)lH34sH9--Ju?^J7Z`ivw=I$8RbTNy!G+oT#(-zy?8@^DC@; -S&hfZ6(Jw!uNfS<8PvM3MZiooHNk!Ot}l58U -rAnCo}FMB%1hIQPiZ&K@>Ky6-~|_Xh?ea)uGKm#KanBBG>F8rM+8E%TgwUgXXm^9YrwEbAe)74VZ$5Fd#>RE@QpSiXm -ftphNho@aT!S+$Ymo2df~(N>ffkO87)v3Une%Q11D9s@yJ9ZlxIWXv!H4qp95##GHO(kiUubkmrEEM; -R;U3#{{>zXDx|@~}#|RNaSl@cODC)#GuKkLYkMa+7PI+Q-RnfaJ&RSvZ^o*&6y{7Df`P&NhzLO?@GlluXrCL*g -;4-i<8*As{g$o&)Rq#|-7e93J}fv<@{ZNv&HGZ|0yMvIgRY-xseq>(iU#eh;k(ZKv(FR!vFY`y(;emr -yqcYwwI?W-@b@*uZ$FyHYLXh__zP4l_FS0U)qtOpeGIN5aSpjgj#D76M7wdu*vl5;b$=J3JI)SBQS`( -`6UddMbtdkC3=&o%VBfWdW%--u5=HT6sc6c2;YUH@RZ6hbA0UD#)DMroqk%n_( -X*ZU$wvM0T!!Pnvy(EhtH8UU=#v%#*`92r2ThTP=Dwg~WI=)6+Ka9FpNs5(&DXOIlx@@-vK6f~+zhvP -pHd+`i@GSOZ@hQL~7jHl<;k4W()piEX@IJM;6QUs^E;XK#YR^iIUE&vJ__hx<+(A|sFic4r|91#1Qg6 -X*#0gPSn);5052F$&N@~vvDJ9M>J{$4Wc1q4JidC-dRDK(E_Ot*Enj3qbgxAJ#z>qSd6T;bJRz8V3yL -VE6?w{)b-J<~A6hLF=d}xf=Xk~Tyye)Z9<&EwJ!MNeBud-J&cx_c8XW?qORcu@<@KP1-db<(< -0Hxfl$YEAlZ*VRm|-BR7EW`K-xO1Esp)Ev4f69Dm@@@)wsQyIe_LU=sd1R8i%9)zhETiT2bp(6DvvS3oOrDyW=mMY(ut1TdKJ}x{5Ey}*4MV-*1PVRu=Yb^@X7D2sEV!b-~2(8! -A!mu*IughrU6p`|$HNi=4)WC+u~7k^GA%q(9Czsw+{pKteX{nQaEOXPYZk+mG-s4+tf9Y;B6yo@p*|p -hvAtRR#4yZB4L{sy#GE_37BU*CNLm6%vh11rSl8mQ3lkkiGe=GmQWLz<@ -9{}~i`nUNhipzvKQw}EQOPl0JvynwuL0eK;uUoTP3sU%PMn=KUk7%1a*`&G{o6oO#ux&f!$4)dH;9k; -&$EVyqX_P}-6&A*w56L##s;k%@o-8haGN_L_eGc#5TylH=9TbaMxc5?OLIWcZ*xFuMg&X%HKx_JVrM# -RVL5q@fvIS!*)8RsHTqmm3!=}`vhA%<8O9dZ{8@+?w1G12qNBeYq|v6^0WLk{`0JynEZVRsO1)D}&hg)Um=p=*&Zw7ji}i(&MSLlC{aA06&Z-3mC_ZRv@laI}EaFve=lz@HwF8Tt)84O%C?Yad|34?J!x -$15siT+g01i!NC$|&ZeuyA(gkd{b2LPOErUVfDexXY~IKHzAJ5-p%oc*Am2d<%VKPUDo%Cbg_%445s -b9QtgMNU4PfV2h;kcmBkP|Ga&a7dP)Q>Oa -nbvfeKkv}{k*^#p+U`LXa9I7|xk+20PYNTb}W!&;ET{6rWqjINcDz`$jU9u$A?PNB;iW$F0`7kFTK@Q -^1U44m@6+p-Ch#bUGjlqpDD>-2@K9&VK-U0JsWg2P+enZg7x^SU-tEO0(uEymV{HwOi3hO+-Ty|PG5m19IbfKo21sL#Y@(j8%@$$v)|zMkQcNe2qN1a;T{{ -pUh~34#6l*4Evz)hX2X}9Cf~`*U4?&Mwx>H;794Y4TFK}P~Lxo-5Rj!cI!*&$$=#H=DWSNGk%ymYl4kEQf>G7-SkQ$TGlsqLwk%D -0Vh&xAx`tQ%D~VZH%sewdxC`@`9^?zIt^ov?wd7v^6psGrsn!6J-@!HW|<4DvLpUJF+8%Vg%5j2M2Fj -S9(BtvU9gP1nf_%G@5`G9UEgPqoc3F+L(JA@^cY3uX$nWG#G23zU^|o>vF-jo^wNF5OB?w~ZkDBrw5L -kR~=g*LTRZm@7}24y-oK)=@8IBbb$p&rS$)vM-A^24>FWB0%016Z2PEjcP~jc)7x|M+7{tXC>N&-1P& -o`wOUnL8`C_*&gyXs0aq9MO<%XYCPoq3gCwdOHE7YL00S@1{h`H9s@sq56fr2fXptWMJw`fAZP`9$cx -2vcKb;QE?nd4Zd~P_3I`XfplSot??tA6I_nCiUywDb|68c!7sSWR?WPlgDRI)XC@kPE(2H3C?V*?n}VwShw|ydPFxa`EJkhRlQ-Qde2xpa!YNe4voQZms` -o0djus)ltwKNMkk2!cob*%p%#14K0~HpLU*I9*%CYC;Zby;)ms>})hPG&VK<#YExfu%#RW>1F78qu=0{7uDnsMpEGXK+XHgVDs81m};vvtQ5nHz)^kv~MNmf2`E!?=+lqUQ10}`n!0|$+$KyA -6)Z7+`JXrlbRF+cEy@XFeHk!X{A$&I<#29oJ5IOP7PT8CoEF@z$8cj -yu6I#NOh5G0G?FCL%BhA_ -R6fBE>)j(EhkfPd!%AaBVSgJO-S)iUR?)9%FBpXN!f+bC=bH>u3IvI)KOr2(NrJ98ZzW0o3^9i{hs? -K-rro%WoC7hcBdvVe4|z3IeHlnT2VB7AP5FTRsf4UjSLgEclD@oW_Y_$m$|%P{KMb%~cvaiav`N%6Dm -5Msv`XgBm)clopuRe78m2uBwG$XedQgl0ma;d7mAVx0*$i7jhaW=y_-*Grk2J?DbvqrYvS`C*7#?fp# -yg>X%ln__#!dhz|RunoB6BABPmH~cWnwaeeQt{f5iX;LCLb65vzv{O8P751{ -9UUM$PWAbu9LR8N{`mhUnmf+y8|AZGjH1WvT(KrjQtSb5Hy$u54`=Nj}#yfb$Q@97ZjYC?Va3W@go@ZS18^{L=caW}Dbn#|ehhog^O4^BB;4C%n`xveTw|zk6%m|>Z>erwME)umKI1`S -ZT{tsme-Miu_hz5l(e(KxsQecN0N48PJVLsvSnfsoPGa3Kx7Gr5}#ypm}de9=`?`4N(WKdI8BUEDly& -664m*rCP3KXCjw6Z?A{kf-9FbG%TC<4md!Wu(&+raT;Br{1i8CdX(?`7Z6f~%3v0iR^~t -0Bm6Sovz(3!vTB3xIl2Nt=^52)k-t6W;kN;9OjQ^h -;2i3y5iB1cEbHY4ugP_m30RenLN?5+aZ>O)_fwZ^Q(%C(?I4XJ#Zn@q%(h|l9B!}ym513mEJ2X$$~b? -E+w(b{wp3>00`v`IRpNP%t$O2M=Ee5wnd&z!>NzD|4|I*v{Pk3AKquV62IJ=0EKfn)Ube2Bh&_bR-8@ -kF5S63)8jV6|BaqH95vmWMN*6d;(kWLOIJ;0JI@5bGsZTOo$lr8har`58H`&1^whZI?E;;hrX_l@`6x -S65>9RS&PVy}5=g{773q1-0q$RWRdu{6_Mcwx{K}Z1&UlN!4N`t(v<*+n_bos@+$vebF5+TgZj~NK{+ -TO7@Jc!)|^PCpLb6F%$r%qi`_}Eod=a_2Z=IBdpEYZ7N&0WK%M|3i=1m-oiX8b}f<-~0hCpbGV|%6SjLThUXus9es4{$koO*c`uG6dFp;h=UnM|wDueC0M3(nL -B0jS$t^8JlJ>=v#SOP{?4Rf~KdzR6#y<0h^@bMh+Cr&hpB4DsSI7PuE;$W8-Q4oX&A`0+lCDDTMaZYZ2ORUnizB?*{^h0{g7Y>7@A{)v&V(9^51AR^x -X*yCC}WB7PKJ3I`xpZ`5K#86djjnq+(iIlMgXmOaIqQW7IP5ccpH?*LW6AW -Mf&~(g@I;B#)G&E7Fh*oSovD@$5YiG=czxQLvnS%qh@B6$Lp3qL!TzwN!x%;RZpy;R_JH)IXMh6bL}! -zXdtx%(pB{n+#mFK{mcqq#Uk{;d;BqULRf=doc9;7E0(K#K@Qoc?}r~{8IT%Y+rSYQ2n2EAS7tNXZqt -J1uNe4}7SK6CEfS-7iOGPsREQ%5Ti>yT9Bb<$VgUt2ADDBp>XxVN1t8C1jPuHi0xCa2+-5fLSzh%WFL -|XKO1%bTbsO6}lAi*q?O6)B7S|d0bc7U4F7=(!^iS$Wcj?r5uOVv*~@D06{wr&Z8ABna-Q#sPaR99{F%FT@|qp2^^^fWQm2<_g3j~DT=cf# -T^n!TKLia>vsxXd61&fPa)F$pXPXnR{j?|mH>Q#D&>4{uDtWaoNzkt0#)wojlR9-%eb=rjwW#VCM=q`LH8Hcf{yYLZp_TbocX%z>X+7=QUyA7cFo|OvXt1REY~v)k`YaGs_TD9xk7HHmS>=6#`vy{KqAPQC95d9->)h(9?iyth5L0gKLi?X*{R} -yUI$ngPU0$tmvNKVqRN2`nRj#vz2n)0sWrBm3_4@8tFAs)BgKBYT!Whkgqpn>EPu|)Hb!XD~ETZNfgc -tQ2@uUe2jZ5sJ#q(dL0PoI=K@6jEOHkTl#Z-TJ~g); -5F|Qd5gIoZVn+a}aTq;xEAGc3y9@nq;9K2vKluXJ6~}fT*$LH&K(SB{Kwp6F4lr~*R#{V+_sdV+QC61D;q5ukkaiCDZin&_oeJwOk3%#v{7HXle7I -J8zKWd?JE%dw=s?tLLM+@Cmirs_}k6;9l>#d7=Z^+wxxJM67IHd_Y^4$r -}1s~L*7|l@)0`k+DoasR8F(noe6J?cq=0SlDe@SH=V)tR|DcDr@m5EWM|ra>o3q=gKrC|(Y{shSY|`_ -nshSn61wlMjd@s8$viBck3gEYY8*BhJ<-s>S?qk_ac{WKMn0J#_V$O9_m!6!RV -FMxJ|FDHZ=9h(lW@4z~s=C-bAPCAt-dAh_GoU9-h>aM=D~zpFdaPYjk>A$Adsov+98H-=TCD>(0+rX1vCag*2zl;QLe?Yf0RX` -L_Q9^2DwOJ;gZX_9<}g0I-{{G@mdc2Oa}a9I{{rO&74*OyD#@`a(xdnd5TZJ#;ghv>$z?x%S>J#wDNu ->U3r*qX1#~t43)@M3J-;fC+j&$zdYOY+QZcDoXlmyUEY5LzxC1{!9&x0AH@{4Vu9hS=0$5L24r -&uzzl4l*IXsS05cQAkjxPk#pbG6nEk^e5o?Pfg!Mthfb5_N4IF5+x{8y9ha(&0*t^n5M^UaHi{K0_zF -Fwr+meV9h@tSf#^p%Xo*UG#7nYF}q@GY!vSJr&-K29X?2j=MkyNL0-k(C)Ns%@aI+cC6PZROM!|6dgtxeyWFj`juv^oTR&=d}`8o%95+CP*`fzfDvH2T>l*O06$YCX8t -OXWbu|N-ee0!4&sU4$ieaSiN}T`2gjMIQ#V-pebf-ggSk_^F7oU|#LOLNm&4LFv$Tzswpqd-Su?}IZP -wrZ_O~yi5`gDiDy9~`bp$i+$T7599d`oGKrg}7zHU_ux*_fAc@Y-o6c0df(S-8Pxk+-_(x^ -}@vIahNu(wS}HLb=ac~{W}7m187?SBl259d{OY3FCc>3-_Gqf+1ocyEDSqb!JS!{?$2LA-q()e>?kvc -5o1e8I1Syk2~RFVCMeGZWh1DIdZk;I;F7T$;vp8)2yZgk3z^*H2<6*y9bkAYfR8#kAke>4paP`ZV@@n -)AZ*~Xo0g_dv+j5-1<@+w2Es-@7o+kq3J|qEmWl*Z(prB(Kd`Mwloc8oqk$ek^Is^GIBQ>wq# -?nsWbS!d~s;f=8UGL+0(4S<@rjMcyZEZ3kLIp%ez~xim45F+5UDzTVet8q2rYIEj|ZMZ{O)f+x06HO} -nV0dgTUwnz;RbhQCVQ?4w$0K5=zYEtTBbi#Bx@`R~4jez@5u2|e~=>g_%sri96!F{+7J8rn{)?p1F7{g8&@LF3D|4U!mUo%a*|{RFso-nj{~P&<8`vmLud(!#Hi -kaPtWoW($=ZY)Z$oBtONHojqcxs1$DqY525RC6`c!^8neb#^|??ZgNGzw(6yn<61np4dx`kdvs7>)Ga -9Vai9gurg~h2LAT12x8VZ&LuP5CrDPT19>Fow)c84|da8zs+WqyFuHTxE}WCkQynw*68au5HBB=+?BPuV -h<=;OZ~;8a5G}#UyQHb(y7!s)tZiDZef$#(w4kD{&#NT}@5`4IOk -K+&B=;aAIFMM!#KD4Zem0macC7mWuK?J=E`iaMuhz4AuX4i -T!p#Fs!tP(NQzlp-_4*i#c7C(h^1ZVlO>GzUm_lyc%vy8VW2aEemVoJ5Tq3PuY#o~KZ;fr?y|TraByt -krLlp~Xdt-O6?L+>sNDQeoCg~7>9R>r6CWA|MGq*P2uG}HH7fvuQvjdx5?#nTJ?d+R)j-d35fZR!r>K -GS|53F-amD*G5_AF^=@H!h#xoTW{zs(?(5=lUKY~?*h`N$I;d}BU2er^u5Srj3n_h=*+>g0PW(BpI9( -n09fK{Ua%}xYR_fxyJbTt0v*Xe5TBOxtgIb?Lmj~s*0^*EGWWE=pLrM#OP)8dM?^DuL@C2vo9mm>(}!nn$CX -Fj|aKnnpe3#~8eb9LH+9e2I -^Tq9p&7%PO6-ulYI?8SAP6Bopj6wB|o@oc!l2(T*a<%Ehk?Y^ph(H$eYpCenD*<51I7iv|Tr5=KU7m< -ZJ$#TyyUDm=njxL_I_>yTV*k8J%0 -hvVNGE^|2MsKasVU5nIj@i+d_Xnn?O_4x<>#=l`M_cy*dnVI^!lbN_%`*nX~=YIk}9UApFt|S*eg1~~ -ALJj!>zN7_;i~1W=z?~XkTlpfD8S8EQnx1Dic?I+2DN_TX2dA{9GMcaPuRg-MP+#LEAJK;VBVXeSm-! -k4r2?UCnRv>YOlGLOpsjEvGpM~M3;V9c~P*+AZ5$T@(SZiq-AFN(6(t_dO+(3s}qMVlxnd(A4)|Ie^9Qrh!<3Tig;m!pD2g -L?iuol@WqsHcdE%uk6I`x2ivn2GXoBDKA+<^y4}l3F_350Q9Qp1%sd-P-BHc9vdTo8TIt2pF<4yOn<% -cNahOln>7?N4h1qBruU(TkO`;!$&n4SFOfvk{@EN;En`GG|axGslNM0`RDZY(-rq%#@v_ou1cXN$)=^ -nCjHTuq_K&7NqbyJ?YiS>|mY1EJW2dP?>@Z1*Hf^PV9o%LbVl`1R`3(Gy^yJ`AisUk2zwC@qV!0RDbL -m(Va@dOuA&pwbdSOFiB24fJoYB;j(ZIWCuw&os_+wSSKNO&`(w;#sg-YbP~tU2bV%FPAboyg -Ti`c_FS1Wy*04dTqQ^NpX^wY(sUt%Z=k2x?^mm>O^qW=Yo^Qv%M7|NNn3e#N(S$exgAThXCtta0^i!o -%A7;XfuKeWbasX?n}S}0ppz+RP68CbOd8lV8Ga^MO_oEmTymN^FICO$*G;%BCN#E4po44uA$;1at=yy -QFfPqd-5)GZH4iXNTnlcGLdiz11y}6@9ehTUJwr%oV$F)FDSt?=?Zd-D5vdmDr+#}EC!S!algkdn!pU -6A?;)@-i?_6z$`%8SV?U*f)BRQU_KkVL#Rfdcgr~zGsm+w32ta@3hpN-+r{*S}hEp%EwUD9hlff5IhX -8ftv;nAU6`#}8sAljlx0$l!v>nxI>(bN|WwyPxPe`Q+&q6<`+6lco@1U;qG};XCWl$kJ=>2d7u$_`Cr -)h0>U?Yu6$_@imUXBzx`>+F`kzAmY(H4bp@9>TtnJpb#Qp;kGP&>c@R;|K`ar5>GP1D3q}gSyD{o2>&ooeWn$b -UBtqAe6?Q4(2fLp38&=>=UqrZ_woG>R6xQ~gASf!q=(fo43F5u8>i#tFk(rDkR^u9km}E%XBLr(S}?cMYSg*Jh&QBt8<(u1T(T;`C3EV<#&`z*K -mM%M^^yrWC61he9~aU$Pd^&x< -zUKJxCuK&=biR*vs8Y`~%Bd4C(!rG@%Sv{HT(7}E*TI6{6R8Gnf5Yq_}eO@~PDW`FV%Ztonw}EfdjtD -!gQ$h}yP0MsNbGnko@&PwdJ^FzWBzKY7!0VcqoBZrT;`Ebp6*>QIvh1OEDIPqflCTggjJALEFI~8ERm --|brFX1rC_Tfn_uZrrcfYHvud>5BdWI|qCVlkOy@%dzH-T&iDD5=QEclY!lqxDQCxVLGFwR4($rAsy+ -OmH%c|3UzLt`lHD*(GOn-n7^{anxg_$RJTIwZ;~3oPgp7C6b@YYXitFJN0j!o=o_s5~`fi=|sT?X$PXOI@Zgg;f$gTJPU#eGKe}Br8+go2!{R!8SO@}wJhq)FLe&*3JJ8X&^Mo7G9@`J5L`GXS5g^ -l+ec@AD!L$Z6SzKyzEOu@ALU@Og$1`^;Vy-woYCZ_4`8BOBdHb$!-Jo7W4ayP5)*Ub%XBM>;NsR}X|)0rdaeVa=zdR2~G*m!mKgfc;JLw9$Z>rBvBD -yn|`2FjH5sV1*^=BF(kn!h%}Ciq5#XQgsg7hqgX$J0qV*6qIb}3#o!$31z1?Ei*SMKW?iqH-m1G;vZP -8WCY9TrmPtH%BAly#YI)+Zv(S_kvCa48`W&3MKB)-h{d6#<78llPxfnd;^#trlnexm;x(FTnK)$P9`o -VpSK8-lZX9=tG=YM;^FUHv_K>$$Xo@PRLY1e+h!dsS3vu+y1t^I*q1P16Bot@3l7Jg`E^^B$oK+yh6s -rB{Ctft662ueE`Iq#gYF1weMOo3QF{12~cQoPh#yew0+0H9P*%2M=xg;2=eCMALWp3hG@oj=?U}TJ-x -_uP$ig&(MP`&(4LQwtZilm?#a9A9Cs2tJ;v#?{qyblIn!UgPor||hq4?Y7g(r27LyXdo@KF`wUUi$1rr^Mw4;4$$ehJOKJkid -l`?PO9=|K^0MHXRB<3a%CgUWE_b-oU>7JKi2SU?1V%<_=sX?IW}fz4UpEKJl_n>8Wmb*4s~WEzjZcO= -FGef^_Ivh%2EvxW~5OnZnz;>&5u$%^Y{&D7U|9Z_ELv6o;%SQ(X6j(z*RDMV%1uXT!u?Cj~It-lq8-i -}5t>(Ja8D76d-uh$BP{VsoKQKOfWHt}zsdCn*r?PRFg2qaw-Yt3+br=M}c`1%+Wg2LfDRKcuGbL-5!E -yooM|pXS(ali!Bef5CS%{l-}%_9W(@!B_x3>&1)L357D~66QqbU`0R#N%f-$2cN;n*h+|zY5IMk4DP_ -|!E&}!gO8OU@blO#CU$)S@9fL)_Um}FDPBr}n2}=azXBtMW1q5G!{bXplE;0#LyX_g=ZW#nT;MpHXc9 -{H*dZ3nyY+ryoaurd4c2PxS8SsG*4V!%zw={{Q^aXve7-QLUfgb+CyWOvuV(}r#eRsuahsNUvzGcirs -9#Z*qtBknXWhVVt&9zLzkLQsspuIR0Rs<=BMQJb7{iCbUEh*NQr -Z;;X_ry&`+&nvCL>zAJ2|Ox>$HNx$R$zedX|AqZ;3F_*#iRLA%1ww#<7%0bSZlN+cnI&ir3VwGLw&S6 -a4dkKCOvM%O<07*Rpi(Q5FDfoScG&6bTFfoJH(7l6Vmi}`4BA$q;|>?Bog%b0ENoex?Wy0EIosTaxE9 -kC~<|%UC(CYSxk%+pYNqq*@uCE$~`^~+Os3I1t!5X_|n7&w?DMpMRwkEDWJPx7jxbUX^YG)JE<8HQAF*>LW -T8$v#6HF2OQSS&kze9Xhp|osiErSZ_#1Axw!Dc;(ed@%V~1({54gua#Z~+Gz5D}W`~kiInKtlCNYlvC -B<(}S;r~S+3wVmvldLTCB6+h?vr@O<&c8-N-cm0Ikdwh6QCRI$GDWFSqtzZXCm6^P4IuuEBp2am<654 -^ZT=7BvbgLXj{O;z#m0m5_<`WnxRUN(-(hdx#%h8=Zg0MTu2b7?3I3rLuWcds;}$RF`5Gy(N29BCEZy -a}lA$5PjIv4d>k}h@@kvZB8}2Jha-tQd{o`npJWe+?WG`?!|PIu9Vyf&uv2~pn<5^Y+Wc1(u> -3TU4hKfa(b0L;;-xxlO-;Rc2rK#nArFSZ7>KGQMANO;3*+=2faXIERZqpTEmw1vHd~dYHdXY~;PhFI -|1fxyWDcWcm!x583Dv}4an`mhKwp5)%BAHPk^=dko2KNo&5jh&K2DK?@dn!Wk*UOY3Pp@!!!J4c9E)5 -q+&pd_*y5x)Eg_3QlrXUigHG7$IC>TIQg>4mj^-z)qG<|{&);e@JmfM;Z6!C7Aj$fH_peCo43mJL|;-44-NW2UOvFAx*~HZ4rTZ2nQ5&!X7k+XchK2_`(;EV7%FXy^_7h0PjL2b&rwH@ -#ojnOTpt5{aGEod_#P@qiLCMAEqHY?ppc6^0p;JIUNDv41QcqJmAhPkx3@OlP*;BU8q|Ob{m|@N;w -w-a*`D+AX$$$7siHD^T}6M=49IM~fq&epNLcLV%jUneBU(8^j}r0;ukX@S -Vm53}1btx~mD@q|-;^uhHovxP%GZ2X@=N4(0&-jrTj4I{5R$-(L9pHKdK%H?OeB?M)w6KD51}iLhCZ5mnkaeHqly*HH#2xIanG!-(8!fvWUpHEIp0?x>ptF7hF}tu$WUiLsU{sk8!YiuWPlU5BU&L_)NmVvOy-&nGW6~?*9?bPA{1ADp(R@H -j2Zq$LdUE(j%amSlv=UMXZYq-O0AV2J&$2JV~GM_R2U~ -;V$#6_Ad6iYSGtc)<3WWAQOeD)p#b&g(&`U!(qyWkaV0HGX9LOh;?z>5LAR5P=GxG9%JM`8T%8GAz87 -)JNAk6+MEP&)8Vn%m`7Y~g9{fcfSt?jLPejB-1@7vYNgN85~d;O(Owc>8EO{~C9olRFSDJgVH{_MoSb -&tOGwh#M;P4RT>Bu^-cJVbtm~>Yo->tYT;cQ$}x7t-JC%RW9&TCP|xfkz}iOMiMP=q07H`lj?_uF``7 -UZptBTqoDUj=*rz%V9x(nu3DXY`Bkg*0_@RS&7JItcvbRZP;{rko0x28q}pLQ6@6G-aw#sb!mtMYPj|ltqqXKkwrlfY5AHahL4I -nUT6h&5{0(kwC*M^4nWVE86VbHXSm-2>65B*t~njl}1xX14kx8GdpB{!$jt*shq8oeXxj6lcpdJUIS> ->&oohgUJw1h*LYnSP^}sPuPFB=q)K?D4wDoBI=YDl7p7BRFpx-Vi9frcxB-LPBBm+YLNt?GUyv1wkfTP^NPxKo}=vL -h2ljG#Tt@L`=C^|p?7QbEE&vJ}zIDqa78jy#i-Ky_+9xpEwBT=8_zHy*3t!LQdf7c%b -YGpHzK7)}tD9JIbGQNhpvVIi>k2|2m1!Exj6F*`+h_ -l~&3)p2pjy&K*NcctYCu@lPE3T|fyRJP-L@yLO_DYq=TquVr_EY?Q;^5-ZHkAxrRO^v|(J8@^}`)35M -Gvv#9BRSI2f;3O60Uty~+rU(}CZWcH8Vm&m%pxww0g32w|-7PJ<8*D=H0?P$(tHobXBX7G)Tvx(^erj -pHfcUrmU1sEM>q;MIn2?YjtyqV%owBX;$wU~BB`FV-{xlKB{#EKq|1}ZDt6Y_3rNKlPT?&*%rB5Wnxb -djmQ2Mh(cn5~3m+mv_;UI>yOJBlp8ia8hP2IH4&#EVDq;2a!6MzOT$3WfPYpDNBt$v)RgnB#z!40@)Q -hZE5mUQ^WZU-3s3-dR#Eg}8}VCaH{Glg_pM?mFvhUE)j|GP+cxpw6}SpUj90Gd{T%LKw#^xR>>l`@6= -`m~CYEGH?+@{q-Gs#vJWu}v^~L5`&wX!g&j5c{E-j`kX<6h$zU|AvOat=K%o2^pGDeyv9NWpI;Q=`W# -3cx35T4@la{GZJS$D#fVTbROM>+f|ByXiA_jB# -_$9P(<6XBwgF1wB*cRwPeif}F3stydVLD$KIK!86heIv^o<&}~O>1P+E(18~aHH{T;M8@Kh;YF1qn{+{C`1ZoEy7hd(t2&73{lFyBQQ4D -`68{XBoIp4~L!^&oHemliyBD&)#HP=TMf%KGB=mXZQY+q{< -na_nJSXA~m)ql!oc)?s(#9`vk-ws5k19zUf1SsJN{K4;0~9JHs1FU3wEx11Kp1xGGb(Ury8fL!#i(D+ -g*yu3`Z#4YxA(}hPaLnjg1=e{lVw&Q!lw^*?#2t1YA?@&;fLXBy&I=Z~Eo&Sor{QjEW}if_W*Iy!6=NyX*-@O`g!`@foZz($poaJIv$(#5YQl -F)Qi`CPH_ZTo7T{0WJVMY1MvFwU%YA4!ysm9iC6Oer8~-(W31g4_^SB~c;LG_F_%hJD!Z;c#d_C4&Gh>6l`$6AJQ%?PPHU4#?vrZIw$_eF -wehI)xONRkC!a3Wo@#TdRwX0qJcWX{wN?!}&$>w8V(sFrzz3=LbGl8SM>(y+_(7+YailT$Lnmi>b5ph -2Bs;BQx2Z7lGGq?n&$2f0WmWu~Dn6eqIe=bdVzx@=9!R(pbnZvPB=!OIPw7{tK;1ynBU%Q~_G(w|I24 -n#s$X{I_^o*P#Vzo69sEs$KdVR_!t*7o`ltx=hL-xR>|CB<p&)yt$7my3%yAcONRI_+v`sd8`@}yIT|Za_O8 -C4(gEC7u6102_)z|4zjHm#2bzfkbvEQZ375tJY5i))oyPW3Zcsk{OsoS{b+g8?2rrcem&zY^89bx)E- -HARo$`=Pm*NPnt{NL)tj**-HE+?q5OZvfj@tA?j`zLN!_}YF(CYo9DE7ejYol%XEjHFYBlKyP_42EJ) -flA4Be6{cZ%IJMsGDoZ_=6_z}y{%)}==C*U}+5SZ*w6%5Q3|zSOk-QdMiUDr_GJH*qa{jCgaY)yQw~8 -{L5a#D}`@vkwWA$SqK(<^`zL@-9gHw=Y#Src$@1E(Trrx-j;qe@+;Ulk3ICuF1j#Ir{VpO!-Xvc>&>c2-nKNw2mlrgWzjm~d9q9_GtSk-7M5OYsMd`I)7 -79Uu)EwUC*iR)m=mrnfmq3`!p83J38nNXi8n5NA}(@MQGC%eA~nPoY9R98zNs7kEbVgQJ3BR=5<$wRU -$xDU}jGwuiaEgSt0NlzZd>x~XH_lr6^1n+nBv3Kv*|yFG`UBQ~{)Yncv#DlSloTL8`;bp*GyW8?8GgV -E~+QtX~d*Gw~y^2fb2;%75;?`V63Yk3?u224R`57P0*Q##eSmQB=q%*gwJFSr1%!ZtVdeDTT=Mp%ulr -k>4u1@U(r0hD{>Ub^{h<{tH`^!I78u-S>yxfWbx(`sPVB4-_ik^*Q;#L}q#(=!`=8%jsuAxs9i$MH}m -N&6pNgh)a>wiX&zij5Sec>P9zX?;Ig=cAwlQSvXMr97aeDE|&*!J7L`Yvf2_)Dz}I-=scZ?-kp&!%d~GP$!QNaw()7{xBKF%L&}r2gj#)z=r8RxLJ>&JJ#!E~qD_l*b`4r -5Bu*r;CE^`x`f0-oNMkUFXXk+D@5Rh1rGCx81r7$p82UlmU1$M@rIs~O#6FTasNZbm^1hZ!ZfmtKPd<(D+}@N-HUyEV$< -9ksM0^!ALl`1Tu0R#T&r3D6n|A^Qckz1R}Wu8HM4 -?E`-o-Pg{jT$k!^ER{;NniDJy$U;%B;)UFl;)&-$o3xan;@{{oHf#8!oJf4NWWAHcY1Q_0FJ1PvVm4+P^MnKzIX%y -Q`Vw563od7gP@=9!r@GoG0B5gt_@7j$!}|o}lY8L)i@WAgm2#!SA)p!RS`2>|B=?+OJm%o -^vguba+ntV7k^#hPNN)lNH^Svr912!uQN*@5=cCw}3@%j&kh3AFevs&+tK*r5geahSTj$zMJikqe=$v -bd-~RkE_`fXJj?S>{WEq7Vs>o!Bmm4>tEX3E8j1Tl*lEpd{=4YWtZ)e%T}$~v~gcR&6kU~eVn=(XN+G -`atVzS=fA9eC+`>#LZezzx)uAJDd82E9DWVzG;fOcM-w@K&*BQIz)jen;`vnBlP=iO5 -g!?#J)puJrU+|`NWkG#usSc|s?B0)yS?~xTU -TBTYF!%t#fVJ5()g+onQjU42+mbGA9K;oPQxQoNX?=$cpY#Fi&1R1^2uGc4)PF<84-7#Me{MKKE4>cz -*F{Ndf?{IJ?BZNC-CI&BK5WCpBB1qV!PrtjEHA+CE?qr)uAADh&blOu3dHarSlV9_GI&>4)#v_Iil)x -;9+#WC7z9O{}bln^!qV(;(m-Dp04?h{yB9eV6-oPkgD!K{m||oI-2*N@`g^#@TthOP+oajM<$7psr*u -1eoZfNuRLVH%DwU<=T67(q%t^v#)=`3X{I65g^;Q2;QT4@XVX?cZ|xF3oLY0I&EpPxC0538qYd`Y7ti -8Tn2?aaGu|&VA-yCz?(&!loV!7pC>?7ksmPStT?>5R&di$~zq-%$bNuRIZ@CV4V@%k^MoClkMNyt|RZ -Hhn`aTBZq?#)1qg(NuW!RCq?MV-Fz8f3T%I0ecd(VE}v0plO29^&E+d0S0QWDduWWvSJ2?6#dysCm5J -Yxc!eL{G7By>X8#6;o+X?0jZ_IyV@_|hJr-V|F!gE_2wj3j6M*1!wet$`7)TLW)=hv=(wYv82Py0-@6 -YCDgT3Fks5oU?6A=J7MMHYjib>Tz?&xzbhfdZ`+KHOWtS(NsO2jwd&YNr$`D8DoayMxmaizjVEdcspZ -6-W}web204qxq}SI_XYA{lb~Eo7zL=Z{%C5(hD^ZZFtSRN8`#I&oQl8o!TWUS&y7922xb}^QzF5s~xd?lxyOzdOAt -f!{8dWzzImHK<2h>_-*Dr)K-ct!dVJT>5l!A6OQecJ@v}7spuaSawkOC3`Oeq)44WB2gum`iZvFzLKy -0YviJFj3LHMO=kOFbhJGDV_t`T%Qw;14K)1hiu|Hpf2eL>>ms=51*g6P3w}b!OFE4>`W59%h|h2xbK^ -v+A&^k{9vY)yJkJ?I6oZ9#{bLRJtIQ>Ap&PHvN&v63=F?62qoV8NlXDr4O64m2MgeTcBYp?curw%Z^G*w&L6vr4d_keywu(0a&q^sh -nji_F^asTUWsPC0kd+`XO7_!n&8O8(@8#taEg;tqQESvGseVpRIgOM@zO=G5u^k$MhG&dXed8D<8wA -uoaVx%9m`#B9ihUTk%bnvbR`68QaH|H`oIzi1H#^Tf(}Yt*u~P!B%`Xu9ULX4C{Qh2EaOltzBWwVk<7 -5RZ`g+1Zxsod&7DMTSH*Aur(akK5VtXdK+7#VQtUWp|G~pQ67djZ}v!l_4guJaU`=+#nv&fo?`2GSdX -#w9#{_+@u>XnS|5|y#yY*jy!ezCp9E!N5g+yH8RiwPxjd@6_=b5|G?#^{OHi2C6wPHiyG-vL)+ei(dW -cCHTxw@zD#H0h&cS|RUeQ{-foe+rVO~Qum)ljBmSJAQG?zB2ORF%i1kJ@)b!ivoHA-_i?_d{mnAaH1< -)rEo5au;rbNNtp2?_Jc)m+L{m+&wzo96PO>S77=nyI<0R$ZdQyk=`Ii&U4PVP1ur%S?8eJ}j(Hkw$&G -L#5s|o=(zMqUmvt_QQC=y)jN#-|1$0-ZP-`Ct?sO4CGGQ{337m+T&(g?-`K)qqE$x+w8h;e6%lVVFr! -M@|do1om|5jSFm~&n&(3I%5O-ys#@f`(9hda#FwB^9kDmx<1UoOkJYGnd(`h-jOTBT3h>0?_u6&P;ZF -DdZuahkROkMwZuU-%PugxOSN!`&y4zcmWApy09(I2kRXBEfHa=ym$dI-aR8aV?JKnjAC6(M-<_n~MC#etH*wAdmJZuuujCEReU20DomJ(Ry~< -B`d-!eU6GPmc@1BngD6p?WxYh{QQlBy9b45zEP&?0C0t!vV)1bSb5BthgG?{FRT9j<&OJ6qgr7xS`=H -IpSyYQhi^jq|yspyr)LPV9U!38g&9N4tDMBP{xj%{Vz>uxJ6MI!39GGF7iGB{&f*%{2z`-}}MH!U!$8 -_UK%r*13*Ly2pP4IJHP;Bl3U#}%isv21&tjb%fJY8%V;^Tsj+uh`D}wP5wEc*SLRt9XhxmcfoLzv2;> -mwSbi?1jJGX20FB*HbNgXF+wzHef=7pOUPa6ff`{I2CvCKCpe4)O}#vwS8dh6~Q~pK$oZp*3#`k(&5=gSY8h5M@2e -BwU-7uhZm#$z*%x_)_qE?#c)we3dn?B-cP(zAD{c;j2@mEFz0?p-B7`i!P7@9hj}U35q8OOk{<82KQ& -At7c2iL|m@`d9onVeJ72U*p%OD%rVg{qM7?m%!L^>V?JXElx -)@M>V2~Tg5D7=i`!UiXN_R4C|xj?b;ZI(6*K<19u+2XdtDxr_hVOqN}HCYuIr{X~Fl{SBPV9d23i--c -;DZUE3Na^{rvA^0HlqZ6>yc-NswPzU8f9T*FmfsBN4rODh&^5WB}w3?EM?8_wKn<(cN{Cb2l)B*qnkH -;F-`^zI{r)-C8kXm=CBZNu4K-;&}&cn_&ADK0`CQ|qbRj9S7Q&JrOXD -l>oA*wsh`cU{q9KdtLo?_gL7PPSVV~&Nc2|86p^UGY&yxHu=%Ut!&mz!;^REC@{w_uam5Z+`qqNN${rJIg@0y0a|AU)x!x3WjTE -8Caq2EQ>kI+sgDRRZ^@f5?s|M@fXA&6ov-b#z?OHPX68F7G$Zk#PWtQA4i#c@qYWyfh>WCFIINtrf+S -XrmxZ`wva-5S$OY(Dy^KAV;kxr@f-_vYIOq}`%qC}A5bH;xVlxg!TA>2TVSOhHpDbn-^^+u^0zzOYX@ -?|ftuE_f>ZRfcXD2=yvf+RY%<@ewBo&Bc$2(q>T9_fv7FnW`8n5cV9tcvSniS9{Gzuj*l5;WwR%$G+m -KIXYc*-oV1w>d-a1!1@oyd5xRq23$Yw7tn>)?9S!KmC)WNOZvJ{qtOz+Z|bCl&myg2r_E6$s>mfhYrl -wEDz<>rNTG37XnWfDh`NGn-<++(HODqI -M7-Aw7G;ecd(GHwtdqO|N=6^AY^{91#FfLj -CF+N5jB@R57GF3=A6JqH8NMPuyqW83h}TcHp_tg_Yg`pmj|2~<8q)g|I;Rl+4Wi%BIsQDq|Drc`KiJz -V1xs)Qr(#{=8mjp&QIG9&dh6R)E+>|@Q@4+JsJ9g_8Ws}ZzW>m#C2ImG&4r~A^jr9=yUnZcS2ueXXT1 -M~!}vt}Cgm2DB*nWX`DaT>dAfhFQXqgUd>aZ -wFIi{7nyZ^g=ssIfXtCkw~>Jo=nZ-q9)GG0UWsS*T(oXv$)+Ue4yj8*D;gY=Ia+F^j -97A?4q4EyX_VNVfP$Ts#_5RLM47Kt6r9qbf5-F>()yw#BU0Hm(=Aa -Al%NC|!r;h3Oj2ZemBybNk?B@iiZCOneF9lpY;_?*-2yWJXB3kD3ThLQfTOb*L^%bqPQ8W#9B&MrmLo -e$AuS%|CB=}P(9MWwT6`Xw=QhxfqY8u}O?={4ljxq9b4_a{{4z&GNH^2sO_+HvM*5OdufSJ>;chn1aC -iGHrmexj`yH2w)8#l5j*)RM*$nzhN|Cb`aHM26Wp^uLa(Wmu$y6MRd^k~e4Nu#xnN7zel(4_@NUgx_7 ->^Lf1K3b=70UUU=Kp#L<53)g*lbY?HO#_MrryqGCDEpkiZdil!TTYaArQ@V^jf$LGDF(Fnl$FPRY?nt -C)v6LNq#T*d>{)#Y4K3{4U6~B@4To*RAk8-6k6eLjqOcTJobpDmca}CEraJ>mMw(H``B5fMhUC}zq_h -s$S(C4V-&LEaBhrx*dEj3Fu3gsy1S|P{n|(m#dzaM@PlwyF^9+^+q;2$lxb@VkFP -vFQ1N#V{%zbg1OLpXq5h_q_WHOCwv77dc@l=8W`pq -fMNXOMPD?;2;7&Ox-4%iu>{~d%}x^@mu=*ZTBQ)*o(XkoqnPIgxpL;k8?tMUZ_dv%@=ACda+JIk6n?_d5dSEZ32JWdM?uomw+W -Gy|2?JjC}aS`pOBxq*qnV4U)q>XI|$d?P$Qcg}%;a+PTZkh=l{rB_$|LH)s?8wtYjw=2Xo-l#aXL%#O -jHmuEJ0Hp5Qy5;uppdu3CcLr)QIyN<6n&{g+jDFcU(9V&>uMtU^jbyH;dfaSr8HL7YGyY*5CC?mkx0|i4vk)(onW-opU(BfM^c8oZ -l6>UQ&%`w%gZdoC-{EjhWjIuilFoFiotvq+KN`I^)enXZoBKajweJarPYLjum9lyY4y=mtb;egYOR(r -{+UgnE3G-L=eL|p~3W_<+v14oBCU@XK51R&BQf(lu^auEPf0uP;IeU*Hz@7ryV{d3^YwPzwLy(qGW7$d_hyd^YsxqzI?FM@ -_^Hmp;A-32*AX5hZ9)3IXEz1DXY-G>`NlSYg~QLAW)sCxq}@-=t9Ka5G*NmMt0%gY%sJ|i7E@^$G_Bs-kSxX@*eO$DKkoEo7 -cV|Jw#wvq7!!|!J>Bf%9CLkzJ%lh+ka+OtQN#&$YkMUtyl8}6>4BqGsUubo=biI~u-{mEw_l=4H`27V -O;ibS?6FijoO6yk?Z+wom#|vCizEDN4+V2HlYuIp<(IvQna906s!Hr99k_{O){u(Zu@44k)XH~US0>p -~OZ_+owbtr+wa(`Ab}~&n^KaZ^@e~eUxyRzw7+dNcWfqE5`DOWOuaY?@RY^GLIMKfRgkD~IAUMei=HS -3pPot`!Z-5+EfDMpMl%M7U`*hQpvJr{6Nx?)B3YOE4Kd)PAV=Lt8)R&T_@mW~%fkjpg{IvHnBt=N;deZ0(#ogFi3-&fVr)(z-O(GtPd|aooe^y|8uUQ -2TG=#_Vz)z3{nXmw(`q;Ifg1^Sv>*V&DJwfIfLV+aMbQ$7OEziwoCe(r^9+ -u@U7adm3!u(UpiUht3=JY+9?=7O4a2auXa^2^#tmwfcvSSrrIaKA0X{TK`(n@)r-Ec!4?r?`wlHt -;kXu_=W2ImKX`|Mts?qe#O1eX=>H?1ryjTUY-U%T*8DwP4re7@|`*Yyo{{!VY|!)D?jn49sXYimAGhC -DuT?g{ilobrqA7mgyGn)k{obq+7tc`>-md9Ya8hK2gr8ac{6EsjuOzmR0f^h{9B?Zn9%W3efmF9B+#y -mJo}Rh+GGec<5wl!OrIGPMI? -U)ijg14v7r!27nxhF!Le4*S|RBDgF)bcQ?cmc6(R6oh$I)33d;(wB;6J-h6&&s>Ki8ba-Uw&1WmwjRm -`>bKYPAvN1y#{$5tWTiV>Y{Qil7ar&`a42%9{UX&d?5y2mZ=30m=Twqqqhq0D}J3-VgQUTU -tk9VJ0dK3s>8e>D)>q^b{7^I4?~zRW~~T{bPggf=|bRD?4|N_)R0`zota_;3__-pU*HNcAgeh5>+E@O -e-$Bh!6cA~xlxZl%0Db|olN%3VCUi#*^LqxmH(x8}I6Up>WgS{1y%)N=?ac%;vG?7Hw-+x-^~cicB3S -zbRyyB^UIe@-f6?$dRzWW_fH*HPIo+L|Hl-|pu9wPT68m~$1!K+AB?AtlWS{ZMcF*?IUVCBozwj;ijN -tR3@nce##6Q6IfvDgwzy$=V6?Iqny}E*;_?w%4?{m{J^|rg0x%gXyWI(MC-JUs9wZ*U{Cbey^7_FPY{ -E_ViTK{0!H*;!%E{iBChTl{go^!DSVJm$k35Yd#^}a5w9He$M!Fi$=FB8s&BqX*)RP{kmG3V82m+A -K-R%tG}5wwoN6k57LuNtuFo<>{FOM>o!`Pq#NJj2fBc{+E|Sa4 -4QS1@12p)f5#t?x?YKGVD42$kPKC%zKDh#-fBdXH2!ZsXNZu;I(=&-sQBrO^yrXXRyYqI^GH-^=azKv -H{Hxh?GXf@!lU+x&YIYX&ZB|0ShW$t*SC+(7b=+Ap`W!wmyHzQ5C9ga*y -{7D`(Ct+n?dKeqDK(sSp2$1g6(riHR#u+Yc5+2Dq0co3_mIG;J?a -7rPH%ocBAQ5|}_HIoJk~iS5~)VY&<3%`iQMeL!KXXQ8uk>9C#wi<%dHGq3Pnw}s6syVQ1_U-+(jrBay -cSy0)u#;5R>!eXfSb{{^^VZtsjqmw8Tq-t7(sL}lS+K5?pS8vnKjxQR=P=KcQ&{!Jd;|aTxoqJfbG8J -P3g7dKBL_zs?J~nHmcj+osy~^<>7*6U{P7cgloaZ(=n+@KE5pBb+<+05>eWkpq+~wUQWWKRdPp^M!S$6OyT# -g`KrG5Bq(3Q+1-iy`&X22KTEk9;EMb(_b*Xh0@lheB@($9{rUDFy3sS7kVZYBXD^KR*BU9uWOE!cn)}{>j-tL9o+Wd -xk90X4}giH0j9faX~T;u&lBqk?ix|PPa9FbTu!H*{t{CRh_t!3y0KT|R9>xuUbd(XD5#I5oTwJtd>-e -)StRqxdJ6y;04ME!w#$pk4stYT6s#_3G0a~0h`c|xM4exjgbz$WU*F5A5nE56ml3+k~t&$NFRZgHx{d -QZIX2&(o&S#`C2gLx!<6Nq}7+{cfi71eK(YppzxXS_|0Q>z%@rrjr(k>|Qk?!+^0wi|H}C~lL(2E{tJ -$>Gv49PX3p?l^vCT$5d{Yte33p31DbQtr{rT35yohDQ(t19$-ak*R*7uz -a*oVz-~Qggc;^_kQe@>F(YQZh<)=L;lGxo(;6Ns4=t>y!*zd-6+4R{mktm2^+)di~T*`j%Y2*$2I2t@ -$M0AD!ro_iwV_7LRs!j^EbESMSprwauJK=F;9C^u38!3(dJlFC(L!*N&1p5d+A*dp_OyGZBhya5 -A1W5#W1Vsdo5^N$kK=2L0c>?bXLfk;ml^}#5fnXxRkJRygMR15<3&Gpuc8K6O!S@6g2^wD%q8&jmf@p -#<1U7e?!wJR{WD?j2789%{c!l6yf=>ue5>yfVM&SLM5UmKh67(h*Of -ZTd{WpC5OSBPeBG^N4oS=%poA5RhbS3CZFo<9zK^lRLU>U&%0#U8<^Fg9%F2ULhSMqvnutj`1#3Gg@T -Equ$TSUP97MEY)yB5*7x8=%6^vvjTX*^6U!^9K3eum&{A)<2fVrFL867q5;S@ZLSm@4wcB#|TXgq8lf -i!_l%e}q4cMrRUCqCW~IMvGBmu;?a24ECO)uNWp`IKRkgFP}UD`yhI<_WvV7B-PVm|BIIAdmilubIhU4@p;+-El0($zk7p#&8AMbBvuigBM*|=Fvl33ZWSR+b=+{o10*>*V<1n&;vuW&>&go9&uv3Vde6 -pp|Z$76ok$66fT+%3wJo3#Jlj$v+LV)t=oI*`n@XuhMREn1&?$g5Mkb7g|gq}XarP1#s_P1(znkhFsr -w@NK<(tE~!Y`NpvRpCL6uXm8EK{kbI+a}W`5hterF2!?K^L&gCA$j{VzIhD;gLV6}~>Etmkd9`9jGfwdoH-qWa%Umz-Uas=arWiJ -sk8I}FWTMqfIpk8@Nm}`;sb`U?QmdDg>NC~A(YpEc`~$hVvb?PZen(L{qqK6#bNQ$o&S9>hUjIAfqAn -dlE;@9abiUO`L0X;oy{K)`|u*TlY>?6<#w^VsGgoi#dm7}Y{&c2lty~7zxI9iZ&D93n`-kcO6?v(hQyTL-RZCq@x27I~r#UPS -UAY~d!hH^Ey4A&7RT{3Wk3oj=xpw>zLX|<3*;IbF)xs~xP(Ih5ZYupwrVx6H`B%tqkfFU!=Q2=hkJ{t -p(t8HSG;{Bi%Px8Ru4AFbNvp*RU58qB%)+-ThmeUe>+#Pl9AX8Tn9Q({*&OaiEdtjxtRS-m+{wggkcU -3Ch}L8ll8GDL{mE=g=Gspz{E<-tnK#3o%=Tms{n)}9&hd{d;ubQiKD3bhkq%AfEHXEdc^{b%k_k0(F` -1aS$RabI>qZ{;)98OeTN1bZdaDp60_o38oU5%}4I|q`iV1GdV%i&PeCW=9LWC3Fkn&^>HC5|-)!0buU -gqWu`W>j1P3;_FTs7hrPCKDiYWiJRm&+{ePq2FrcJHCN5N}xn#)`da -MsqDz^)A#2=)h)N}{kC6UZrt$)_tB3Wwf+>Yak<2GTI%Z_$K%{!MhyDY{L{GB8)x*bgZ6IoB -G;dvbQ-Zd^NzB-ONUOGNH4tm~tzG^UrwFDvXyRQG#sr~a=IMV33-5gJk8J1b}i1_#(X=y!XaV7~=?2 -!b~)=Ac>6Rljh!*iy)>~~JG<-nR~&9&){k@m^f`evp9`7do~wjWNuytmtkt&BrZSe#5{Xyo*E`Ko -2`@&(nq>T6KNqGq(Sj!Aq~VwT*MKHsWy9FS}Lb8I4^^3qo&yN@-??)Yg)Eddl_X{ZSgtT?2u^J%v2lV -A|Apc9Kyg~xVd|HdU^Z!Hfr3&uW2)rfAi~Fw7mX?8(Xz*)3)7BH@7$6(xGEOr_Nov-g;Z$?cKWf2<(SQkpe=@|29sd$X -oy=j2Yy%eUF5&zL#uzWZm-nOh+KuRrE1{<^yUuJpU|Zz%OJSNkif=dX5%d4@l?Yy30DpKthczs5g3uK -9nO{r?M|E6a4sf42m<)%;!SQ%eHeYX01>@vlY#{;Pj~L_hvo(x36o=y%N|YjoFszgBu{=&tL+w`_>Qd -Gj4b#Sbi4ShC2uxOBmPWA6>P2&0~+RUH8QL4NpGx^fS*s_x#2eUVLfO%dfop+U6}= -Uw`Axx8B~ieMedO&Rx6T*|T@w{&(Ly@cst}4;}vS$VVT4^6Amfj(z^cmtTE-{KPlko;>xh(@Mp6mEZs -H_vL;%KcoW$@HT%N`J1! -IQ)$B_Q_N4~YkQGN^}ihMrBO3=GbkK^|&QtY@p6^WYro!>hq -Mt$VZ*ynxc)#2B+Fmv&=Dhc{zFJjBN9;RD1TMDOSXr$n*|Q&B(H*nQb}doLpkfpCaEEGANC_=)$d7u*1Wt1B7)|6X5S`hvrIO2Q^)+1cx0C^ -)Rhi>W~GbhL^1Qp#OPhM8+kn0Y9khB*vyl1(yZp3baSr0_SBu{)YS2D4^A_W%!!UhqjYEkerH4H~ugA -oU>>k$a>0R`Qb>yK&R*(|~%*e~ho@&juxiYGimo;x{Ms_L}A{7tC>Nd@uW3!s6jO!#-AJXB(%i6M?!g -IxWVxYj{-Y7%zYPvHrY*Qcx`L@(NgY&gzXDBnKRSQ!O?{vD<`ejV3R@gKv7rD{jY|jT;qel(y7II~}T -{?C#r)tWIyKie>(;C1Gm%6} -6Pi@4W2RCO=mN`3m};GxlQ&Cr&}vHuSG_UU)WEGBK>et*ejM;sI?R -tWQ-8m;ou!t4Ssi~ggYesO -^8$;NQby5y6(L^RL~YhU3HhFv?QHD}%jmxCdiu{MH)mb@7cJ+HiiAu@o=%>hu=hS=;|W9slIStH=L5> -FWIUoOE^n7bagl|D|@-AI~_urNMNby6@`wGecx)_|4k>`|9{NdAo+rA#XKI -=f-UoG4z}(sK~|lD~G6F{!-(%3E%b{7WF>=`Htw{`yEkhH{+*13*2a25~X%S!>AWZ7B_h&TA|b?q}rw -=i)r*`9NmyMs*ZTXL^ph{Gc03b9%i?n5mBV}+N}CeiP{}b*`Ak2U8SDeub#=N8MeVWd5P3DXIZtBCR5 -04YaYdp%E`{p$+AY-^0H#6Yqe1+ipc!@jLF$r3Zrsr5D<5}4Q8~o(E;W8HSz>`QKVwHzGiCaPOkAeY4 -$AZVA5rVr%pxKCp|_$)2^4c$sY0cEL+B)SvKpaoaBr&Yt)p~Jn@i5qbnSZOwy2cqAhJG@ejJbySp~_< -ADZg0PfoOF)}SJkFg2&7?zWortytZ=mriO2v<|e6N-q|RCBAA_(&0zm6NZ(-4Qc#c+4<;)Z`Q>uaTre -OlKk!N%2S)F>Z;rJo=9%di!$-D(Z<`%p!5uSdQMRhC^!V?0ww -Vzc-OGEM{Ityb)tRpWNTgmF&_f;qlf`DQF$3QVr^C;l_KL3>M_ikI^BAO`?v0~+2oX(m2qEP&&cew#N -3SRs2n?``yHigB(+`v+Vg(kj)@_dOB(HSTCn)nVXttb(KakQZ#TaDK#$x!<1z4A!9bustRPH8ZPb5bhYH-+-v5=5 -RUq0RcbVRlk4x?|MUF+_QCfsxJdcs);pr{Ue-BM=%%{Tp*{Zf$922Xxt72C--YOZp8pdMokD-Et-2D?LAU^kJ8=~v^XO -*_e9N1*3uuV<(;LuPZfe!&+&~9z7fmQaP`*07iu`q)6DsrzeDpc($ZN@fTe`TwD)xyJ{z?Bp4QyAYWR -Ji`G2bUxAIYWq4P}VxzQAV(!C-7KO4Rw|NqHHYL9K1MO+K~dmsM>AJyO7;PY=r?7!)0cu`vQZ+Ox4e- -`h*^ZCCn1KRWdxF{rek$&aw>AQhCxO?W$ntzMt{?ym1x$a5TocH)~o)NOlEoAc<3SYkd*m`pV>CU^Xn -ikF6e2w8FHFFDvKlsGSC)$WpPbg1}YdHP6>)1AeI^+?@?mlJ~DaSI8^|~_rk)vN7|5b>dbJdubZ$uxu -@oS5ChF}B1T7uOCD+nGWSWHkvFqMo>i1$g`$TnoaLEf-HhGg7E~S2!YiC{H>jo=;vJp -Zn~)YdriZ+&+YSK^9$y!0pN1krek%K9|%h~ge^5-ECrYxzsK|8IK!==(MII**6;=<&gqUc?9JD20u$m -eaL8X0Ly?Hon&#zjfCjh{|SI+dqZ^?deV76WTTmC~G$@ZKE8dRZ#sR&>wxh!u8zY<^5l$`ah5Q&6Wp` -x4P1Bq?zEcN+HHv3)SI?A)F7F(OPnce7sI3;vFIr{tB6Vb+el&MB%g|6JxO;x4P-L@fRaQ>v2c=_tfK -#XQn|wjP45?a9`1Y`!fx=zutiRz6RWnHsG$*}&d#k~2;u+tX_p; -$`Vv1MId)HCq->K&P&@6iQuX&%jh{Ai;ydPiU#(Pxs_n}MO#9fB`aLl2Zz`|JSU+~rcbno6>3>h*+Bq -t|}jEoFnx7*c%DlDY`La}1S3i0&QPm4F+ctezxm5EP3{Zw4Od|7B!w~zzV3vR%qf#}i$g?_@ccgBo^{ -CZHHsV?-Zo-t$gYy>zX4^$tN2QHBJUV8VXmopTX-e=6fyK?Zrfdl-GCQ#sns57!Uo&9IbuJZk!BFjD6 -`;3FW7ZE=_y;^-QK==a()6);`)!wUBe;i+4jdx1Fn*8xlm;yC@^*!qXhd*%O;2zcC0;m5q@>ky}e<_^ -@vFHmo;8%U{*RSdAJp38|`PGXKR3A8xH1K|Tsm`v*64*m!`$0?7UQ$Z&a)qVpU8;s3$MeX1YLDtIs@seMNhoabV?WfQfbo3{F(B<|0>Uv5d?AqsY!*^z#4jwqlaO5Y)6!H&ull7xE;e*7h63t0*tJ2g(q-_z& -pKQ(&v=pE_9dOuHQ%Dr*Z?v!$Kikw^0WyiSDDWX8G-?4c#(tBeG(l3zmhYJ@r36|pfg_zsEz4Z5KFNK -E&;wqqr@zKDf@(Db$FrR!IW)eM}I&~6(fq^0@C`b$#FhE2`MvBOHd -suaJXvIBW{Rm(r;5D1JZ?Yc%$XzB*(1dB_YDxQ&J7ce$uVN_y;0)9oJg@M&m!KM*I&F)7%Lu~H&JX|k -t_Bry+a&Yf3N7eU5eXxO3`zV6cM|n=<}`=;U7pb{(UK;K9b^&V^WOxT8eyv(cefh?z9w>j!QA|dnxA4 -n>ZmyKvlJ&zoM5@AsHhO<&U`1n{Z)#psw#2e!UdKUJnlWHe@G -C*n}o)9nGlUhZkkYKZ$=f^EUyy-WKS_pju5ltG_gW17n|kF;v;!jZ%;)_ir<0a2T}Y16n_}SA4~BkQ~ -a5-xmZN;S5y2KDSjEn|B&LJG{o;r@huepE{boX_)94MvlM?P#Xn5(k5c@vDE_w;zk=eQq4?(w@q2Wp@ -hqw8xinl{W)ou55*kB3OMTids)Qdl7xHLNA-^0UlvY&+ -#h*p-7g78*6#pfPUrzBqr1+-{@k#kepsJip%Eq!r6rc3qgVg?1krE@#*9ke0;*Y2J_fh;uDE=0T|B)f -SXeJWGjZ|lE5z9m%RolMeAW43eh!wK=T|)NE6>`J_LQY#PmjJ1G7!L;TuLiuxFxqM`;x4vOUUB{A%_uAKrpbm%<90LpAr!nKRhljCN8B75@ -_A(#v5<&^Yd#r3^~9*o*zoTO|1YaU<3T4V&Y@t;^JfC+t&&}{#|b4^asU9$Hl})#}B@_&GlLU_}|*K+ -c2S~AH`YdTuTW@0F8f~e$TLYVsU&-Ts#xOIq3W+{8OTPT7W_vrO{^a;1(@fPym;IN?-33OOF`JU^w~T -Ja{mp(9Y!_W%4qGGz*G}i;gEQ4{pyy+%#AdkBI(}k-a=jUO^El@hS1KF&dWfx^%@x^&S+}!_%$taLog -}ij8*7EX1aS_V91y?dH~eC}9W`<9}z~fCWJA4^%?5lJTyL%_!w*OM*7k0P4 -4}Iqrzfqd#mz8=|__w#>VvNU&q^!KCvb?vVR?K5m)<(uj4IcS;0k9VZ?D#B+C9CeXgJ$s8^RO6cKgwx -vT3bx;{5@=30libdRTJ4ipPBV#JEPDDm3-7_sTmxuV}b(kZB&8~UjfN#CeC!%Q+Ce)wUrYSk*S -X3ZM0ZrwVuVZ#R26<&SyRn`aJeDh7#6+SL|TC5^{V-x8LyLayvAAIlu>jo#k`C5GQ%{SuY$&;e8vQm8 -i{rBSMpU$vu@XIg1h)b6)iRBlhc$wZ0|88h!dtgIKKkDeHUM`zN9o;PI=$2AP_mpTZUlTp$b}>Tk6Vv -1ov0Q#3UY4h*|E@B`rw%cJM)bMV*)F@C;`gQa7K$H7@yAj8X%v3}#a~15U!nN>DSk~q_a8mwKYGglt9 -nWstqo|?rVTH(wB}jPHmy4K=+Ofwz_u~BY169BEw{DzZ`SN)lC#zwx_0W+rBjdQ{-#@-(tDd*I(F$oV -VnE6?-AG|P_*lCTh|^pHSW=z0yJyd^yYTAbn4opN#m|JYYt{}*V}sd`ucUHIJaKctZAE8H{RBxiLYHR;&6QKLYrU$=B>>(P#UDauXsPWcD -6YuTk^V2>VwxL=p@zb!B@ATaQjK&G!9Jy`R*4=r84YY -Y#*qI-n+n;(Dt@nq_E-a2#U%)fs8@yFBD_k8oi4?mnD^Xqfx&Yhug>B%p?_~PZgd-pos+}r}g!^3-MG -_}&w!6zx;!=K?F${HQ>b)7qR?nowh)$AJMwi-8XTtr`b$lmtTPd{Bs<7l~K#}0Y=^l3@`sr=-VPcT6x -zyA7bN#kz`f1*KBKl`PkC>2EOi4Q;g@Uimp@`6Ew1_cYXobUtFKFp+oZU;lm -sbaY#pi`$>xP_{%T9JZJ0Ht#e3ai*Yy{cjo5iMlV^iB!Tp5;D*nG0&l$W#^92YlDm5K>IL4lijI!%ig -f=h{%6mgm88oo@7S?pAL8MX@4ov^mX(#c_=>89i4!OI9XO&+P#tFT$dMxqs2eB -`m?$^Y9mIL>z4sV@lp)oBiE_An`LZ-V^!_`!SHqv`aIZgu|M~OhC3QnA{~;kEogv2n;Q#*n@5{H|dP` -E7OVXLS4uk(FkNx}iGXVE}`}T2NIePRc+d%``0LUBa3Cak#ZTV43>oF-KK9I8aekpsrgUd0c>|Q42$a -kfD?v#|joIihr>Povmga7vJ+m{Cf1oR;tehIagC=aFq_=4x)E9gO40C(6?_FsMV6$9+xIrt5HAqSuZc -!U2a<0rnCGWruKEgwo5c2LTG2c!(%M>On~@;0KO^EN3vyeZ|9FQlxlu3r6T@Ta!k1;Aeiy)1P2EA<5R -0P>Rjm6St{N*VPr@gFo$8T5Tm%3ef6_NP*wua+|Xu#`dDT}upG0(wL1Ax|8s~<8zgUK_5vukZ|o!H1r|4$vvv#pK(OWfVb5;ajp1MpCR@3AM# -KAkp$E&6J5^1SCj?h3bLWofjSO3gWRKD=qBm~p2QPU4ksGoNd5nH&hY?OgKQq*4(4f`l?r4*!P3=T&(k(@ItZ@0%i~;fqqG1iufG3sO&+$aV7{X)JH!2N!eFhDBeMXzqb1(6Imz1}H2I9Z@4X -Xe9IGGRX!=KuFmVc^iOP~*-&gpdMw15Wm2Mx&<@JBnjd0wP^@%}LR9MSM3(Xh^@;-7y;%6lq_21Ux`Q -)+!in-uqXO??IpdVK~BdVNNl)b%Y+rtYcptx?a=zmT5g0??pCT{`NkBRVa3wiblSS7!H@FWwg>pPflG -OdlYBsrpWS`kP8a3ehm`G|^zF&v9CPjy$5aNg?m6{j=UCbs-u$zEy9##Q2kbzqn7IJ{?F$DFXgz7hyt -XKm&9hoff#EuhsQ3_@Tdr&Vc95!ce(oZm4{jXn28Wc!p?rdu5J1cc$W+8k-8Db1Icdh+dyH9iz+k`te -75q04{&{{1_nEObD91>V37xa+i_?MHi$aShr{^i}BF@NAzSBHthyHqY%ZH_Z-{8;ORx_4y%cla^17l# -A~jBo}5xNyp?US&$Yjo%XxrSDzkY8jLzdcTLA=2!CqtS^f#1CBPea!30jg8}$Kr>t%vA-l!j={{@YZ| -6L0Q%56l$>qNtAbBG423#iYa;R%g~l^PApKttvrxnK&>kRC1Pro}J~c+e*GH|Q9B-l<>y(Pp3zgB}5R -=9y>Y^Upsop%>|3ER(C%lS`K_$wQB&%5q0P`Sv`bf$GAmM8iv3eMXzK&OT7C$r~tFI>y~c>TiF5Kgj~iKgo3wXnEj)2js?$8=0PKp+lzyah1cb%AH01WEs)$7SX`0yjod*`w#qe`40;V>kJ%#-@=6pT{P6C<7 -%{Ax>PMsls_upSsW#II6~xGT77=SP@gwwG_2BS_y@_+l6xa%Nrp-T9@a6ae;!7#<}~-e?};m))+lr8f -0vIKF(NKIJNsSWiu#B;Fn8`;rokv*e^e$gQK#yTvFdw1-Tk6V$3T59)#`Jd=c@V-@JHDX9Xb@{AfJ8q -S=POv%aoLq$m!FkyJ)x?9ak$8JZO_%n|lrQnP{k|ooVQ44L&Vfwyd1mPT8eP7nzchBA!{<>Z1jCqi;Z41ziaGD8>VLP@fMzWtY{z(RgG1bXR@Wb&Qo-eO^X&;g9ft`|Y -<)r0a~*@$c5HTi^8b^z5{>v`T76xg4H&;t6@@op;K_#6($IS}GrY_+k0rgAX!37~cb5(15-G{e(^j#x -S4(?J49CeIfGL?TnTmJ`McO%Xc?SuhB84t2zeiGuos_XT}5lKOBFBhliKM$H&iu{E)0Kr*VIu&6_uGq -&h6gPtKe3)JIY&cy;YKK&A0#$)D0tm1|90s0)R~EX`^j@f6YYscCm% -}XH~~Q|NQ)%D7p2YljY~{ZIS1H`Q-?e_chNytXQ!^78MnpUA}y|oIij5FL&K_m(0q_V!qS3l4S`rpk9 -DZ;08MC(t{b2-2taq7}hpKR%MLpLEuXb&J)Xpd2L`uqmrgypttUB6) -biSEUH`}XZXJS;+e-nMNU(*XWp-jM1C(~z2)Du)dl#7orL+%Ho)MXg%3vQW7{v3vJ!MW|~&KG%vr@-^x|I$r@8F9IJbTS>YFzAEPWK;#$|xPdOn5bDB$1q&p#S=>(>AK<0~;-H;DTZ9MlgE0{RxPz|8AAcNkjBDN9-Ty4^F8p=ws{OCCED7(FXu`eSL)V+BN?L+!=r4_?P;gC6G(>L7+pQ???NAwhsM~kq+>7%a$$j(MKO;dD -iPN0Cekf^U#~{4w=!{52($2+QY-+zk<69e`CLB)M1Re&DF{Tuy*ZQjt{yJ9<%{p$QIg8(4yl``sq`DQ -Qoh>AGlEcV)>{3yGS2@U5yrf&Qo8%L)pL$<)E+0q0G=0VJ!h`P@o04Qyzb%ow+Lh#`zz8EOoUqfqoDD -2k%&y13l#G!-;F!t581t%oHr!z#qQpBuAG?M^LD&(66@nn{mg3<4A7!Hv{ -s(cMpHdQ9ZJdI+qgCwc{yUnjN?K?RH-J}{$|rdGu<>({7t4?o%9X)7HVeM-+_ODW=hp`(@YP|^w -CU{X13SN2+b_eOsSe~Fl+DIF^j+O;QJmQ4ZOrvbVbbf5$q>8UuV3CcdV$?oeym2L0+v$_YI;xKhA2kj -v#$Mn%aDPhKL~Zzb%JZUeJzf9SM4vy`bpFc(XQ|CSLha_8NEmCTSZ~BS7uHuWCyu$;kIzYY=;v!%>uryAdj9pa0qx>-jpfPARjTbWY@jb@5$Q -ODvc%qMapf?#Gte4$&T3zqMTG?w=^-W#Wdd}352hQL4?L*yf9>5dyUq75WCZBdB@jT`dZ4Pka4^pOlr ->>hOext7Y>fa9-%=8e#kjJDt@))75nFed}SZA -G%^QUoA>dKWXlZ<#EZ^$`JJXmkToGR8AFekj_k=#FAGyLv1Df0-I0f*JKHq;5McN+7DUNLLdtn7kd48`tF#^Ws=v!P*3`acTL_NgK?04Kc{$fCIJ5A39k{NlEJJ)vJ?G7ct(4eh#{U3wQwY!}S@w -Ziw|N%&R`H&22xftuLTXV0{E@g@x8=7Z30l+i0xa8s#5#>%RN$%ck}}Q(qszxBz22@C0oScyUhoOuqZ -i1YRe={PZSmetm5tZoj_iDi*I2MtS42 -3>)z%sf&lT+-@^?C&sgFJOSQ6HTppOF&eO#@7HwZky3$#b@!-MtP7w@a76ZOfXLDuSR|Dj{go;^Ez!G -Z--!H1 -#l|AWrMPKXL*9GI{A@2^X(@!@@T7($5nI3BKvy#e@fq7&p#VY3n?4We+CX57;LdvW`T~mbLZwvoH%iBP*9M(_uhM -X9(c);B|LYbkA1*%nBc$uZ6o+mw@=1{G%4JNBwJV2|GIVSHk#@^j|0)yV_gPoOQdJXapT4@-3`q(*DV -{pAJ@OFq~!74^VK)_6aSGn=^x)=EfMp^v9Yl{{|X$YO`FDiM|+^Jk?1m@&mrsbK>b8@R#w(zlI48Tk+ -88FWBxxHQ?&=Li1*8;OqsF=Ydn~vA3b`sL|I^cjrwKRdI9*Z%c1^_h;C9}^&9c?eoE_c8lV3l)GZr-^ -t9LK_>l&5JMbHGxsXB3rDI(K^~1Q1fHFY4fOxfCu^_yj}U%ox?KDNuWQ<%gf`o0pF_X^NJ`h@EUZZO+Iqu$WwnZZ_Xe2P+P -<8e|>o9I`GRczbx0RS;KS1Xd5x-q^~Ld#k@Ix)@z+`nn`=fQ(^{1M^Q?w{F$H6a1@ryX -e1`IZ(7SX!}skn>KBN{QW?@C=u%X$zOf2*TnxX0_xWvwQmhR)$I!-j=R;`dkgrZJ-f!eyRLXbg}Udj{ -E2i=X{hiV{PV#pS^$=rY$m@$V21)!}{SGRE^y^jMa8g_K_y`M`h7PC -eGkTpuTb5Fxj+vmJen@If@4dD3V}U*xd7-Z9VQY;IjU -|rNgF$1{D|=@#tIm#1kqS&CE2-J!Q*+<>vu9P1FyBk^k~pCP`iTD6MxL3|^Ebv2YF-}>k -xpZz2yBYkWeu3L9tjXc~0lhE9^YYw*^1I_ln4cI!6=!h%uA6uuduZz+rzp#jBS$h%(N3c*zuNhPd}aO -+{{C~#%sb?}Z$6FqoAvnHw{K@%P5&MT?KX5Sln2^VBQCI`FE`3R!t3R)f0Kl?&`%~Bjv$FFCb -g<`T_s^d+#X2=LzuVM|NqIT>Iq9};lX9l^PtBj&eR|Ih=BcUK8R^!1Taq;|KO-l5K!={)gE|as+SqIk -x8>RM`PP+dOf6WAM=|rQlk9mJwprRcx#U@=*(n!mT0&mN^o%U)WNW_5)94+;m+28A!>rS-S>`PK4(O1 -YADcZr=U!`G2eUmRauP0%7|NOTG8>{<62|u4Iw*1 -j)XK0?H)QX)DgNRv^vz(zeE4v{-gTO?EhH*+r#3*ri9H5`z7q@@E5|jgl`M~I(*cC@dI)O+&7?L!14j -B2CNuFIQYhXr}|y$XAi9iE$KfZ{J!wH11=Bn9(d!xj+E9z0|l>C_!2L}gI){zEJz8e3c3{3sO -R-P+xG0%vrkV8ac*(XhkKs>|Jpm>r>c%Kj$f5pN^Fb{$xuhCWiYXZ>e-)X&+eXGG&I44CdQ&gs{xWAm -r4w@YOa<>OsFB2OsT<2lqO(|;RUu>F))S_uuj6HXsHr^phUEcAt~yOK?VtN`drfKi~a|l;h8&gU)_85 -`+1({yJye6vx`>XOq_$);zIl!ejfiCm*H3OZd`+FaXoIrt+)e!gu8Js{tSPCZ{rv;mCPcEWFB$IgXBj -fovbA5$%~|XjQk;Tl$;>vf&DZ(3nnQ;pQgL$exQGfPGr;A2_A4~xyG$=kGWUe&)xfkE3(DUf$KK$dr> -P6h_A#{@49!(n=Di0BQiriA@|5e*)6Zi?O%m+80lZ9T_FzBYNLz-%^U=1p_ZG@5R6$&8pgZL -E#Aj!m}}w%40-f>!-Z=e{If)=ACXc=0CveC1s6P-gBQ7+yHJ -a*tp+=yH7hqx18z?bpA@aK30PbO1HESW*>B}v3150J&=$7BQ9PU=aR43XLNUYbM~(Ur8Aj?j3hxlESJ ->e)N2gZ+b@V;9*KHo(4Mx7Y+8&A-j>=HKP>_ySJ3t@xA6~ -nClB)>ey59E;U>HF?qRpZJ?@6xo9>7^P2`B5iQkBFaag=7+C~p$nO>-0(y!=UI?2!Ti~X>fV3kd^OKq0Tv%j!!+dtc8`;on9Z`i=t!4r`)B<_Lge8 -JfXBookD)QxVTb$By=1;2rh;G;n95)iuw>Shj^PY78=^2iSICTS#-=u*0yUZV$r$WM47e}TWt+r(#Lo -7XEpkvCyHd-W-u0U3?69rnD9Z1@1Lz)~mEp~#?*(MzUmpYXqB(`?A@j_3g~A$WTcT_ZOjk0azZnMfzo7}`er=yf`sWwUl -(;~sJoM5b6L4vJ>+zBnT;i`znaLGLZ^Pu>S!*h`QP%Q@IS-N7H>Yk9Kwq_@XA>Rt8*yh(B{^wqE|QkT?Km7}-lQhh|n_}WkRf9gNw2mO4%z<|4qaDitLzm!V8eFM4oA3_ -f4x=0n-q|((I@Y?OFO8rr_s*|cu4XJ27Lq85TrIO@j?9 -zK$U?b6UYDctZbj6yYL}X)Uxp4y1Bb~mEhe&eW(9mc$(f8!qi^DP`~?0Lo}OEibCLQYgDDGh7LTb&*)3~4*z~X+ -h6N{=_i=wW{sI^=UZtXu*>aETVv~?17R?&U!UKb3l4V5nTYN~H_?|cHiMVrWbzRCEBTPjf&Qwdd92ud -9o*q7cc!48@(Sce`AfM~?vSTtU~Hr0$oJ%<0+>%jkdIQxM<41(gTNz7O;NExI#DGlsx&x78Zcj_o>uv -4y(&^As!UY?{lHiONB&4#2jdHb17qitr#eBW)Twpap_ZdjBAN?%526ydLM>#u3x&}r61 -oUSBfh=GU1PTSfAp|6ffki3MCN;Jo -8+4Oy)~)_AUl?tYO^Qi1Y5(oGpvi}sZoLVaB2#QiOsT1cyM_NbD^Gwl$YX!3)2p0G=3_++7_`d?-fB&b!U%yf7` -w8!+?zpPP6xeaqtVQ2n>ReL##P>=U{?J*x@JBy-LUBIwn6otaBj@*jHOgnk3KdbGc(N8B7g%u --B!bE&oYZBg=4$m@^us5wwh7ObPD0HCUTR|A{e^`s&a)QvD^xer5l*d*m@Z9o2tV1|<%f)$|g0Nsh>7 -xskg@W+aZM;q)5B}OO&Q}2cC-7`S6$FG_=#}?W6H1qs7Q;Ku3CxXfZ ->-+S@;$cr3CLK0zzcIlV|eDWe3QR>CjS3__^+}>tlSLG0Q<-vnrSZz6=oHMraEWdFPEQ?ZGs>(>(Nmr -L3VGELlv%E8|K`$9%tJhF3gg{0ava!JlSv?a>(m)YPVbkMZ%e#=K-5I@{VBncBtadMNma$UGRFj@{n@ -39Clndk4deDBLnkV_AGSK9)U!OU5!ZK9+*RG?sq_`i^D8C$X{I`+pnD#n!htkHlS($Ten9zlN*+hVyt~=@^s5)Gf=W~A+2tAgkEr2~N -vF(+0koF>E5nrs=R`eK#%pgzL>q>I((W0Ypa*Fb_`$zDXKyil@-gq9eRT`2gpZB@z*nVyIC>#S8Tj?@ -ww3x8s{eHH?%Nn)pp|C(~hs@fvFR1o*9O@|O$q{U25GFVn)Lv}(b1ul{bCI9IOl|-)WMQpZ(*WKsGzy -5~TqTt6=xz6bSi4@<;Ai_`-n4hJF#k@h6vqPNgVF6fE8vns)8b3@+KU&U7tp%QK9Fh<-)X;GL(OBkoF -3?b_M|8XGz{kJpy_benSCeZoG7&U`AFVofHnGQkeVlpCK4KYi8q9;On_D-vDzn;c&xvH=%BTTeXf^aZ -Q)K75Lc}KYJ+G&z8dLQ?j2OljchgOY@|;^BT5q=P)$;J_OWU*gWi1`2Gn9O$)SNq#@vp|CK~LLK!d -B;%Hfa3|=i0Pz0Y&G*bA+?;c?V?BzRh(_?>a0Guan1Yg}stH|KZ-TCiZ24%n -r(|+i-k-5Q?Z{1lZHLNPRb&gjh$K1FThM`=P`*^--4-cKD6Z7uF7~W*81DysOb<(fbK*&N+N}dEfy_-&MoUgX -lZh{Xp5tU!Mq6Jvs`mv8bj6x?=nH=SK2vrE-)P3vDZ23HW=#CcnJ5&bi<*x)2y%L!;N5d0gN9A@xAc7 -7=Z?m{{4XO??VD3v*S?eM_mLah9i6sx9MlnMq3O*02I7p^;BC4fMHIF+C5qsE3tjr?+4PjheFw#uxxm -$&2UUV7%vmtjzluuZwB!0itG}oYeONURFgp!@6vvr5yw}F_;fDk -G+^D?*aiPKD&U2RN?WzWFuR^B&FW}lRJ^RHHhiq+{De{ulDr^#wV5+sZXei=*HO9_gt#2XreiAWBd=i -)RVsf%z0v<4IeacLO#T8Vn+=-{;_s%JFMl-WgO5WDmvOpe#2HYH*AAcvbqFUCgyd^$DhEK#2xIa(RoT -hYx}(Mwd(Sf~hkh~uI;AJ4lv6f4(7h!LxswJaW)fvt(v<`Nj-=W=Ks;W5BcivgrrBjOlDE>1w+bLRuD -0n{)DpkWCB!-}k4+8=&1ubc45>nVgs4m;v_WNk7+?ye63Nsophl;r0r*6_3*Jw>eEC98E7v3fV|x!(Z -LyF0z%5*q?RY9Ktm<6F)KElSb{N^CE7`LX`g<$iv3YZ51PkoOpjeNMg!rU0NtH)tl!%NIa$3i#X*Jy1UXA-7sV_?>R9ETmZclITK?Pn0KRIFTPJ&5i+?MsK0+5CL8s#r@8bi-36?unz?2nFE3UnB^K7yv`5A!5Mz=EA62qoIGe~s0&h%Yq)hIsZ{m>oc$Qi+(0;U#u>y(u)98hi -47nV5(ok1*Jh;iJ?{rxMYLUe3b?WDSNc~{B95vc`Aqg?E*xMIg8k+CdV5J%y%~NV1U1mz8c?oey!*_sugBgOQzRW?H5<^=U3PA=O?je={1~9!xkextWfrB -TRNTy`~94hpT(JCH2fs&TZ2vZ94CJ;>gVh`boVt8n)VRE3U2O)eXq-w{fbs98>!e8 -cQc+)OSpvFYt$lNUwY;?o%H;BhET|vgRdjW*`Mj<)}3_R=;cF@bZX-%}BA+)NKI!BuXlUQMbrkbpuVg -M4oRb%(VYvm!aaxXzz=D2Cdnf+!L20Cze6GJHm;FQdN-h(xd-WAhGWWG${0T2#&z71Lf9!+^Kz`n&{kCXW` -H_>LSFZyp_Nk;9aB@y7ERg+Nb7{Q}5G3pJ7TI;L)OcD9)EExk#VdZDRtDCI5ui}%!6Yd{_2xOPma2}b -ZUBG|uK(K@*Sb{rx1D8>mqX~ijq(OqJ-lm6N8Ftfo -9H4Fto$-AwqFzvz&bQr)zh^8=$&^kPTHU7uNyXs!_^W1*9~;(54KRS)rX(QMSyvm@QR%@+PX=hDn`NLsD>%N_mnR3$skX -pxKkY6`wZs?PG%fTLctjNfz*cPH7fx3ioGzfES`465CRQP`wR13fOlT=}ck-?CV)glGN>UOQ^c9gdolj5b)u#^=`Z3m`DtZvAu_vV5827C{!Qm*=YoRbS&%m%hNMs -k3=Swv7e7bXU2vl|G`o&YtTnE#E$xasL(#q9zxEZWzL06C~?BJh-~8s40W3M)+ZoA>4$`-atz_tO#LmbBpZjELFE& -#AW-N7wE2)ryDJeH$GoI!j1df+yNta4iVc`+7;f;izpI@TEA>EYXCp2qRZ4gZ2}Ys6d!>ZxKsNHR(Tz-@<$_(ZHSC8Ad1j}!f!;&a_>X)aKds+j`j4mqbe@_Q-<={{EP_h_Yyd@wCe7>4KgvUG`U_OWlIu2X -ud%(i;j8Gl!YH|HBY4PQOSed3gFpn8PpCva7F`+!`>n)9=LKzIM>?N$1!QA2s0)j>ZZ%M1jgU0TLO9z -BP;g;f0-sfs295WU}M1WAo%1o!YFTuR7uGIE&EB}{l`V#1MTXn)AURixc`3uIBJWjW=Xk752nXze;38 -OP)7`f)#NiVQBV4(i4O5345sswauGlb(^6 -T7(_G>{I{1tnvM988a(0`s}GiVnu919`DzdaKxip&CDu8EO_10kR$FBKYErZXV22jap_P}_8;+(e$dA -E*tztDKh}HFCb?cb=I75MS)8{@^#M(euDN){vb{Hxz5<=S!kk|B_OUs$AR4z#6;B9DdmyY_qp%@0p^oP>?qPKy_>y`PT7 -83Z*!n`QNnl^+JZ|sYY*r>B8G+u^N3H77QGRBrlOJ!H)9JO@$`l9kczRk{URp58*eV-!vd3I -{3J}$BwlxC6rckkG#VPGwN4%Gj2LTj1H-kL$j=*~uOmUx#`~d8Y;5EHoa_3-NGmAC%L&eYC@?_Q8ItL6ZrIG0|2iyyF%f`!gSrz4af0UClNBV5$(1=544rW^Q| -Hf_Uu_5%_TX{IbU%9tX!O!?e)d!@9{j}){jPA1K&a8@KIvx>Kd_T@G6slItT;tOhNZv_G! -)fLm7fr+7&*=vSFvIz#|mP_R^*{PZOf)>-wZ(fbC(IE(G37a494bltq8CkD8G)wz!Fp@(NX=qh`ggc! -6n*zP)f}kEml5k)J@U2tWC-%8Q4@%WBT>0~0mwRldgC-y);^Twt2p#znxq~(?+rbar4N%j8%)X|__Z -nhBys(*w9=HOLKkjZEY$xFEYw7l`>M$VHU;8KTf;sh#_}&l^@4)uWt{Kt)lK$pPKmW+hr2J@p(%-uYc -JY)@5h4_m!_UGDOUAdQt)FTh7nk36V-rn=*?GIBfk*f@YqHnCr<@?WTK4Yj8i5t;Vv@v8lNA?m|6g_l%exlT>DIErMZB)3Tuu -Q=(3Ma#B#_+_dJILCkeBDzo%msN4#BS0u$r`$YoNck&%Yaiwl;3eMFLfUvdhLoocxPCk_bwfDqcfk=j -TeVH5@iJYcc4vk_BfO)u9cOSAE`$W7S%@1;#;HhcG4qFmUux$Y8VMEb_q;&n -Z1yNppwhm9l;y$F`C>L9YZG)bho67Uhd@^{vHa!W?;^eI0VfP`m2HEz0%Tn`SjtY1l)DU{b^-t{P$`J -$$qt!`UGfjdC#Kfy1rWVZ@wfBa`6%l(h!_cw^$Fu$>mh~J+nzd+{s6C&^`WMXl39yoDwTZXW6sOe=$A -sfLp7!Uhr)^uF58L+92k3ng)TS+%6U$3V%8ig$E1DgPLMsLBEr=pMSGzWX^0|@%i}*{-_g7fhPOodRN -vsBeP^v|%MX%`F7QmBy#5)tez{y5p0Vo8EU4zALhaY_yi>mL@Ob9_6qzr|~?b;3SyA~J!6&LCJ%D3Q3 -#Bu*P?RO7wi;l>>q{JkUfaR*ofQWS-( -xkP=#wP&wm=~ZnAEJ$W)6^*JRz2&K1T`;Q21zPY}GV;n@2U!|@xKmXP&kD94v%@&o+*_a`+p1Bce*Nz -7vqP$%`vAP$=68}f;GmM>u2_}2Mhiv}P<5~XDQYYF5UUUXf#GbSju^X9W@v|rMi -gLP&*wFwxF0;s+C1T}C#D&E_mi?ir%|)R?V80qYw~1;wk`pt`|JcvS(gap`9^chhh}pIX -V#P1;4djxci1T6N`PqklbCc1Ad~pcURx9PJgyN+?JQ4)DKk0vN#RHC!Fyg<$n>J!FKO|qzCvS)0_yt6 ->sTPTBfT*rr+Aq`a6_%FGv;>NaXiCRn#5lise*ls6j@Y^MESM+lSCAdVXSKnOBdJCqAs;ppFk}d|MND -$KPXZ%Xl+*O4Q}MX>&a1W#23%w=aq4)M*v0<5`W?09Lk2^O%fSK!->0$+d)0wQ+SP}1SIN3j+G2}^E5=G5>5lMl7~jh5j1P#@7gjz^{lLfN -G2QN~oP+R!<47IiE35|PW%FB0b{G97S^z^-}@l->c8^g3=vPy6zlPz_h}*5Bygb#l&bx$C%Gf7UFsZE -}6&&Tyc=U3(NjNL>GTmKbX~Je5e=L$Wcp`&~guv~f`F9<*v8fQfd~r6ul8lxTXF+a`q_VLb5nY%2wDv --YR%G%vqaT>oPzm9wo+pSmKKbSUxxTDYn8xlmmhREN!Git9_WL})v*4im9KV{Gxe7u!K)A(QCriw|j)^s#+DvM0JdVL;?jI>l-;-;Zi^p^~dcOO-Kdbh$D_8=u^(|FDwCQ<#J -Xj%I+BOo{bK=^eUlQz{fycP3$d5^Lk;J7Prx#G*)a8mVh_v)VoL=_i#RNIAR2irv^$Bwd+ev?zC|ku2 -pJHIk+bRl6<0=X@w%p_J)kZR#$26nzO)6nq3KkZfPNa%MnIQ5VJaUuG<|N^GBQfrvh)OJb!3s`a6wb0h95OYckr$R2$cEvU?d4?oaec$hQ{mCuu` -)R5dabBXGiBvvlxDTxXkZ&C$Tf%9(tzM!*cT+KA-#sK{uw8Nz=wpbSZ^F$UqWa+QxK$bO>B_)=nnX-t -LX}qz1kj;KkSG@UdvGN2RvIbC{x*bF*z}{#=i0%;DujcV_9Dpo_)tUxK9!O*;m=*Gk@P>l6Kqv?eZH0 -#&{>E`-BZypy6V}{|ao$DpPpF6xTQi -HR*3bF){o`Zq#lnZLqzT6(3X4lHBTy6VL8oT2F+SIc_-vC#Xd>#dg?50tO%`D$y9jL-@gQUkHNw>-fZ -AMe%Nf>199NZSgGq~jgT2EVlhE;_!qR2PT#@)RBbrGrix_=U~9to)IacV82TO0f-we=9TrMk`ux(g~O -;;B(AYdD_xC(8QSdDNW|=aBtI@h!W&m_~(4I^fIgWVy>3^r<6a3}FTN3pDhRQP2h$&oDB747jzSSGJu -ExC2dZ?dQm3uER=9&f8xJF_XC?7CamWF&$X@ZUb=g_ooYJM!JO9aK*hxs(BGxyvfB$*%CSIv&-QkJ2y -l{hR$%j^bU^XPd2i6nuX*JPe8O`zvHLSx5Z3U8Cr9N@sI%6$6PX+M$Z7UJcSz3jtcd}z~CKx4ffRtnN -`}bzoANAb3F7Wtt^FLh)V!q6glK8GaP6BflL{T8jfTC;Btg)INJU}t7ES;f*I;L1Gwl`tzsJ15XQmF? -(Nzwhwy~w6&KD9kZRyfmXbDU?tHGl9>>w=`XRuD+ -NjAZJAMm3n^o`*-_jlAu{X#eHOHJQkfme+fsU=1m1y8B7uU3Cre%M$a}TlidPIVrTP!Bn -7ve>}wzV4aYdgXhU&Ihp0&N1dHomTF4DV_O@cEJ9 -{V~@aHso_pPg5qwwZ!g%f*cxK{U$Yj4~MLCl-`aG63R5!%_Y=vCdZmHUQmJrLcD|qb6N;J6`7)tA(v9P%XFk3Thf!DFvC37^J*sbCN8@Xq|q^C$k8lt_OAqe -4nvNdm7T$q0F0G=_9A?=yHDT`}YCiyi6hGV7=a3|5aQ$I -!I+7B{d#g1G!6kcTJqmhIFt{h_%R1U*@s3rTCyF6V13wC8UCoa&VpC81}&KQ=fyJn0q0tL8&Ms16Ik{ -@R%yqRh6i++X|n5DqNkaIby^=4$cZa5`YmJVXe+s*P)$6^pT37qn;Y<3cyzcfechCij79eOi+&}D}#+~$}QUG=Wrs4k1T~(y#Thujo2Q`ybd0b=SU73JAp@C0}p*Aga`Amh~dTB-lT+~hYgP+N=Y -NSmNY_aTcFt5+8_w|4_K6eDA$oVas&jn&1evIG9U1sLG-bQ*9nm?njb%-VT?#_g4cVgqz)hs9j0p0g?a)pO|zkP?fMf_BH_^y>p`Bhn|&8S^ULW(5+rnu47_8%RIRmw(4%AdCdAbyqlXnyH{N&7jL88^ehcseYDvo7@LtAu*~-$ -lm3DBKFZc1iwk;|0zF#>%*!U^20e#^ne3O?7TYBmAL>@t3J=d=r5|=V6}l`|W}#U^i2Ca}ELNsM&>Ny -&MlO*5+FVq909n11X#;Rtl|;P7#m`=Ojb$!QLPgNkf8og6j*d2MsJN<$Ip@Sg!R>&Yjj=!d3#XL;+br -`BCz0G3N~YoX6~wEVYaxORiz4DVZZ~(S32E4RvJQ7bInI;1&@MDdBgko{9PKgit+8BzM`2@m7e1iCD< -`P{s<>*A*lC{gwAodR=`doES3`rfq)8q@$)OE(0zWhB2fR}a8q9}Oied~O^uK6%zI+39H7&>a5vEMb%h~s^FR{iqvdq66kFD`9-yoJ?B07M8%fxvIXzmdl!`}=H=%8e=YZdCJ -39-XnNBPN6{bnD6teUXZpnmr_Vo`)z{()N=d#=F}s10FP10D=4N+Yc|M()WUS|BCNr|c7wf)l*d8dBC -V~Wk#--+ZNvtjy7EK7GKs46u3- -KW_Rb+V{0+KOj>>Wpq(ay`OtSR3TDA6G2wss@Fz!wW&u;F;YRiO(1N2>1{5%w1M2xk5r3xH9ENT6t?# -=^2N+sXN%)n`z3lakO`&}Yhhh?SctpV7oZPMxAr>fl{@)X6f3?mAvbE)dS>C4HHj6$Sj5R$#5rcFlYR -hIK*C%|C^wK-5G!g(HXUDn4g~4<2APr5vF`mlvD)Z3wfh(}(So{@K_*NazXmgs|5!=rmdXpHB{v+Uze -6kWm98(Lo$H{6N1z7oEWP#^&6uNCvZJwSkDdauh#3an42|KeL?SrL~k?Fulpi=MBYX8## -)m|F;df!MM6~?HTqwK2J`1v(-6C?;gqSM$uvUy*VE>+n|^4&^*V>9WR8^v485MQ9m6plwG-?)0tHk86jf_9pON7(j}K{!_od4VXK7($8*;jj*SpAF?s1Qz_n8ifvo*=rCPj71P -!BKeyy*kbzeTikH!aQkw#|sTJ(CFmWtZMjy}@TJXw6Fo7Yfj$f7rjd(JqrJPX=8)B}(|-4VKNdSf~Cs3?%cwW#`D3%Byntfe|u`Y%~#{-|9tkNUgO$LJna5Rdy*n -H5pJ)gEurUBM_QrDf#v-z?=tLx%y?)6^6R&9IGl|xe8}^yvE)~o&`r|V1_@UZTDko~!iH| -P9DZ{JSB{l&<=D>;#g$`ANGdzU{Fa#e^2As1>IM^6Fitd)wJrLLSD63^je1W*>6tZN*L{s%*AgchMBk -@hE3UiW+iB)+rlPz3bydEc@4e -ntaj!!8L!5@Q#O79zzou44KjuTo`JoL9HzdQivgoLi0}Cw=Q?qQJlX7X$T%6ne0YbE9vlpeqkOav`)S -p(w__XDM?S|wKc%wFI*UTEo*-ioQ1TYuM*|k%$ZX-MPVK$c1Z$G8iy+>v0A(H2i|*09P`NtRcaG%Cp5 -WLf>#gUwsAD+(`5QstX6ZBgnx*SL_1uNvfF^53BIjzzsqay;}Az|AN{Z(J5N -=Qa1c!=gQD`ugJc43H8MDfNZ-8A&@)PAx}R;8-opm-^Tdj)(M;UD --ETf2t97|*x3x4b$wGtCjJ2b4Yqkn? -n!VlW-4=)|q>lrwwvwjFa+2=n6z_0(*@;(xWX<_emc0X&D^ -0Jg0^ByoM*Nf}=i|Ztlr)~LA*x)y1OKZ%Md9P$MVQi6kyQgj02{bv*8yei@SLS>qi#Vscf5$$mR!IEu$=Ghx$m=f%OSi-Wm+gJEfoRFh0Q$*~ -27Bj-==P|{^)NBcdL -N!ka&XpPCy>C$ltNEzSF5F6*8mvLvK*5?&^~o`w=fFy})IRYSw&1%OANdq)Y%(O~VMKWZk*juq -@-P{qHW4<+*`;meannsaxQ++08trfVeGUm?*61f(g)~g9#c9BP{fkT@DTB5OGl!p=vyo4<^?l5qKczz -%ATyCHB5^EMZ8qjppN=Ajz^2*yqf+ep)J}zl=dWhikF!`4 -SnLFypFA$Ja+uH^xU8nJpd@ -N=6=keefy(y~=BpRnJGI%3?3SiMi$Rh&vgx -V_*3T5f5wHJ=kMOcgO?duM)sINOjZ)F~+tkFBl5c+yU+{^0?x;6PIo^UwzYb)!X9M_m4aA$~{j^dido -FT>@O)TL59H9mL4zHeEJc_-NFU0S9eIa7D;W++-0oEd^$D&fFU=JYmSmf3o@(oq%%YM3teIIo(jmVbFgFL>+x)DB->DH=AG@EWh)K|oZRpG%!UOw0s(?%FYy8F -aen1sx*(qOT%WBvPZAhx|?o{-qq}#j}z}&{}07H&?zn3+mKK1dR3BqMoCj4FmR)>gfK#4cs1VjpzFzB -zK{?(Ng$Z0DQCx7r*fQ=Z7rqxBB50(xtk;*?6I*P)-1$t{pjb -@Aub_5udWjHoz -Cg*;MjuYV!>4Yev)-f(4LxP+thb95AwrjhcJ*kF95RQdX0gI7NK=n|tu`lx3bX!7huJr1Zaf?S2}bs` -1O6S$Lkl1jOvgKA9wiMCF-h6*-c^`|RxM&h82P{)na#B4JPuoYvI!btg)XBxRA{R_xq7IVZH3}##dv0 -<->}+DX@=RKpi?In^PI$-otj1zg!Rv>j9 -036<-sHnF<2DE4Rv|4}RYi6RdI}E8D95{1I&0b3v@!3OU7fXsFFSS{C=hMPJo(pY>)S@JDT>GsSg#{I -#aoKfn0SZip@@9VvGmP>-f4$$^}DIb@g3%|)!)uO7M6Umr;h=JP-b1k6hRl9H0OYmsoO^)|FCJ&mrdX -;uAWUi+O5;-~@vGr@m3oYw!P~w=9^-OR+7Wl@-iN- -_>d`^KLU_>C$PM0r&)O*W6=qj*wx&EA0+ib%I+5vlwDti3ToPc@6CwdAxilvndYfRo4`9o+Phu(OVzFeu~C4o4Aftb0JY5gl8-25xZJvPo0vbe$N*7K)d*E21G`7V -mW5^agZnCJV!3Bmsop~?+6~Yh30*Rczvk$lS3d=8lgOG#-aFTk8A~2&uswNs(J(7Jl4&4L74h-G95?- -STqpMeBoDy;jcHW>KCJ?vgf*;51Rz}@yH|9A#eFPB;d=2XhWc8XrSX@d|e~+lX0@XM2pZ -nl5r`;%3I06X^*noyJqo?c~T7u=DwtpQriVd+_=MA^}_{5i!un{IGr_gwY_Ol-c*nE1lTwFf>`+F-MZ -vym&D2KfG|E9hjfr^BZh0s55|?a+H>?u7d9OMb_6&L_a5@;HD;rTn)%)@(F(DBDyyI&0ou(ihzI;^pH -zcKN}b+ZfcFYKyjv5Zb~|fyJ{w0=A@TrG=cXJZ<7ne{7-Ckbk`dY=HSws6C3+;GoOIid)e9vFt*USn(WkjeC?#sqBulU`km -a*JjbJWsm0C&iRYC_}M2#>?^;yQ4aYua-bNFN-MmI6?TJ9m^e(VKyOj$_AN>#DW?6#*2s3kfIdw&ngb -qf=@5U|XF{LkWV};QUmajt1a~WpEE*pfuy}KDXfgi@V{2@T`m_92NW<~tN_s2FU-gl)5XN=jMZ@SjC| -Ma+wrWnAGRj*uCSLOz-<&G%jj6iF@A)K{j>$o5qd85_0f3QWjKelV+cr}WFcE51p;kr29dBI$uTU3^D -d72`CO(q^+dv=Hx5)xNUrBl@&IJwM%Z~YSz9?I@z$8}gPNIvM#0oqBmyOm=a~Y69qapGyA*RpPMfI%Z -=^@a&(gBdc*etFyPtJQ!SRk1M4Ak=Eqc{W3x#hYbwyFTyY>F_{ -PRRGuO*`$^I*O=pTg0bEk^VPHF;AOG5V@)~j`aqbUu7j}|D&C|075Q40?GE -1cV!T%K?7Z5-`)(enyTcsKWn4Ew@mE_r?*kiZBAml~(?H#@az@GFVU=9PoOe)E@2U8*068XD8CQ*@(F -Ne)`4x8kF2{pxl^PUO<$$o}o?=##?{FkV}T=fxWZUBaE{>7z0>Y>q<9muAV9O$GaXfKBasLIcUQIA{Z2T&L}oN@Ml-Q3(I@1M-sgsfwcaB;ba+?(ghTOei* -c{!}@;!K8`|CR;A?0b!jgyikGT->c1NE;vCi> -mohmUc^`+6a0uxDO$1d==h2lm7e_(#Gcr1ilQgF1&al5T5kHSE%Ru40wUh=1gUlF4&L(r%gR-Qohd`r -1B_|M)8;2CA8}U6ymhD4-!hi`+?2)aK0d{rJ|i)r_H4F_u_TnA419yyal*jcWAGDkQnX1sSemLkY2ce -+;oRgI#j&8H=E^ygtV6MT6gv_S|htj;=(2;dZX>y!)0_clScGCJMHD&{Ai#J67g9Ohv_Dg`*huUwyf6b)R$6UOSxf6Xd -ptXF!JI)YAai=$jD!K{MN-O}+{bOgmAeiyKZpoW4DxeIsBb2!lL!P#!K3UzIDyw&Q86{1V4I -#}NDmBB~4MJMut*-RFcEfd56m$xuNW$ -PUoie>2S*Boo!)`{W=}5+B_eutkRQNHrk3wtf%tO>Xm+VqRUVg;iE@cD0TV-lky-wY{7nhmf3YmlMVLQ%3Lmf2SI^O%fv5@f9FLAbWK@CGm>f9T0j<+B-%*H?44KX)P;yGK(m}S( -M2jY7e!lc*J#ea_D-G8cjkZ=CKv%X=>CQwBoxBK*?i|Sw(lR;@#YgT6eD}L(in_a+3x1D(EdVM>4j^< ->yFReNILM^>yY|Oj3DF#O=Dl9Fi!N!Q -A*HNF`4jWOtd_3ihNO5GF<{NNpq##)l&}pb|3;uj?xiTlycEkGwb?Gj-P$jfE#`9BA}(3PFs7G%8pD` -b+VxPq>I6KK=w9UK$Qie+Sn8Sd6g0N9f$@p0v01L93c>=t)NWhRMo3s{>cE*YLA$K#J_3SRLW+Dq{5xqg8teH4%3jily?<(_enaR -U6-RAB$7!EXXP#XECVV%f|Sb#=Z%#h?3z~S5S9N{q;h13~)oM^MME#3Doq5#!f98-AsW8fwqGV)pK2N -Q0<*WwJ=>X(DJ_X>FwyMYeq7EnH!C>*RHwuOq<^?{xjkW -Lf*!er6^|@&{I$s$QoK~M$Jx*eKeC(``Z3~2E{}Tk|f)ZclNwMN8{Hg_;SEueY!uLGj4L^Jp-ZT*i`N -~i*il!2SxV1#eX@JFF?f}fT>?Iy2t_#?Xs7FQJEU|4MUd!Q(IzK$j&A_Y9cnR+qSeIdv>LV7^6fTm~Z -kt%~HCD)4e5e(^8xX$%&!SZRjK;!$iapoHp1#=gniP6gPLFk}_EF?P>cyWANJ7onEu`p{#ER|cff_9o -D`wD(Ppnu^FH^*df6>cKv7(;z9&^Nsr;_mHL1mg6T_{$(Lg~d~#b^`q!HQj2|CvoxJ1zXHH*@1|0)dEw3`;<6Yqa5YZg|hMk}tD4HnarEr5dqt`qIJTCcztiV(+iL0PN -nJ&AX#s7S*5kiktF$?6?#z><2@HQ3 -adb)lt>9!0#LhvMiOsXxw*>gdK4gYt+#5H>#;y_Sq51(7Oh2v;iGt@p{3s&YwgK&EW22@l!Sb3a(G^w -k6nnY!gF0;6;$Tq#@Uw17$X;$Qz)Y+I#u1u}F`JU}uS0p&znaRh-ABKh1(bVmpxgN-;eU-<59^OhbO -Q*c&!F7i^e;fhVRs}}T>Jg>*o=x5WiTapm4Yw)pcB^vgr5{WDU{NL*MT5?T5IN0$!`Ur3Z?gRQO7*X6 -{tbSQg7uECAEk{v!0J|n^D?<0jzH*wTOE{NhuOH-4)eG0Iq?DgW{5lis9YjV|PV+GiCxxdeY|aYR3t% -LG{5jUaQ&1>MD&VQ}`!yQbB;|^7M$)de8@E3A*frU)_a(+|@q3Wz06fDFL?2*j3r`v=xyYUgXFC0kz0 -orvj`lJULg5=C3wO=0;R8wCW!O2$hE`u?_?hSP|4bM7@}dU37sTzIJ&T)kmm{7XkpM?5>QT-i+~C7l9l5^#EKDgT!GazDPm1dZ0paBoaK>8 -%D@_DJTkljZAk)pDhxe9(YTx>ey#B3ba`{SphQM+0Nu`rS3Wl4XF>jqpZ;OKn%JF<0oPneh@aqn+(pg -Ul;QAe2|6fKZ7z{>D!r%+9qvyCfx;Q97s~9MgdUE*wH)!_C7T=($!tHc25X8qQZ3dh>sF7Yi#qT|$OZ -hm?9YIe_M0!@e(HRBJ#||jPY-n)8rc-+V-g*u=J&@xJEYyxMWh@3m@D_Jn2()R9^jpI_I7qdCn{YLU% -K~58=QRW0rL@qotb2e-mIPeBd~n{J=jwq;6Sc18!r&KC5hi`I-Q4gG{)bmM*YfkHM&SCtX)i)OUWWHb -v3$Ntn8n}5m0(0C5b+oWur8ZWdLDeLPiAb+W|G$BcHSO}x`$1s?Jvp`>HU6|`n -B_#J@Yykr^RIzx*P*@?H{N$Q2`g1`w8vZMji&cpqSR0NH%Sr5d>bf^-}*o5;KUMaT`QNb@pO6)AQCP! -MSt61Ol5=V}G>H~fb)-Lq6Kr?9RYR8xes!Z@+qHsnT)$4_NF}{pz;kHVi2IUSlI!3vvHis|RnA-9DWe -|b4r=Bm;{ZOe*pMh2DcfqeoFTnXv0raeHPtx7q(CjMgSux -WdXP&RS)Qk_=p1N^p`lZ#Hq5MX$$fBG_h`g^|5QOT4kKa7(;gG;t{3LU#o8xl33(Q=i~ipQ*nx$I2S@ -e_ST}F)0gG6$f1AiAljbyCgaRRc>YZIZxVQV~^JYXb{V0+VLX4W^FKD>Dd$%Sz%U1-IJnvzbX?@Q$`^tgS@e0j^wMZQ~&Elta`R((EHYFfq5xnx- -_hZH)%27X86fSR%-88jZTlzbG4S%i#s|htsk#o+8)s|70-nx%pn7ZW3dirveu@kSSufyx<>y<{j9=I; -2UZ3J+J3$g$Z?e-B5##8FKP_n*>8Y>LZb|gAAP+=Bv0@fkK>?o -#K8O^RL)M4i=X%Qbpw>0-llF5A8rj1hLmH%dCWV)nlnHY2S2P!>+I)*EGO-k0;>tcmlE3xuWYjhTHIj -01qZ}SlNS}Cn7b?E-eJ&Ax{9E+T9y|JdBt6$OS&Je<+yeHyZIXKZs`$s8F -nwCrM^VJV>tft19HFQ4p)Ja{87pP0-yY>U|0O*tDGiylZ!PRrH@n%cr2~-56~6iILd1VW9%m~n&r<#P ->H)De}`TurWWkRdkd#76|T0 -sOR)u#A6wb#}~!VP4gGg#{!bjMOqto7qVA}(d?nV+lodGa@g_Chgc|M8`?WeZuAbd2_W2Oz>?gxfgcz -oUG(7|(i_F~hcV42I%Q;Oo$I-pZs+=h*07vw4IlGl`=FJj^YDrb_N`2ZD`RhkDD}%x^5e!FKeL<`HwN --ZYj_*9{TlRiEyi|w^K2$19lse%cS7s^v>zqv2bu#3!=}&$oWr$XtOG@f4BElkgr1OVzxwJ3f#3k0R7 -S&#O&K9Gzg@fU*M?DEoYi%XO!Px${4@-H!6oJ|jOQxMRGvo{1LmkJvMj-|tiU-5uTN1Nldi%?ze%IZ_Z5A`*f*?O`=2`GHCp2Cn$Ho#AHN_XKVPxS;b-bFq}JO} -|9>JL_B1cGK)Tsax3zL+Gr%MpeLBWxLXjW>o -r5%JX076NhI5dP#YHxKG?O7@MoWJJo0&ghXOEF88~TI59yYjt{~f&NZ8;g)jROh$d^CK#Z^E1Og@?dm+4I|EFW=w+CUMmpqtas5GOR6NkE&@I+?p`E>+t*9cA43CF&RJaFoH>7`H;{=+H5PuAgG6TG -?~Vs#OLc%c9Cje!8vy`YGl^0TO -CP2HRh@m*=Q2ixiMv@=D(X3b>O8LAhn>PQyC5{@81i`dYno!{H6wfk9krXrx=2ciXe9Yx<-bb}qG4A|Y{)Hf8l6d=N^C!b1H)p-`wp?yq!RXDo@U7$7im*`y6q>-tbhDyM;bZL=2bVcxE9Y1r0_r12=e% -DZv>@R09>qV)R)n;ENY0_~I!GY1^lxOWfh-@tTCw#5)baDnX7;r%>v`_$L33FN4uq$Ec;X6`jfXcb+% -h^oPUaf1QJ5un9z&F2LE=cVDBs*ZD=;UoMDQA{dUn3&`rz?>=NWoPFNkUBK-R^5PM{U4Z+4E{qEp#u~ -oX5HqG-u5rhj3wRC(0HFs$*>^x|{;m(;ZQ^Tjb8?QM)v-6CkzB)ft(TKcdcGdUeG)(Qrf$bi*lRDokh -sKV9PAGlUTtYq4I;pk90ny*Mp-PNT!pf1ir)JgdbEXQMJZjt-Xryn-4JTJdI4#OinOi#U_#VJPz*9(hW8@Mm;)=kHpP3v_)e04e!7SD|D8x5{-V7du3dJd -NkP{96*UFE&;#KY>ahw;}zfOk$^GcCg8(;n!)s;qRG3tJ({yR?U$^t2%rYI}}@JRaC0B>nYyQV^QxK1 -Kp0aq$%90?%EVQDucQzJA(GEMxh`DP0pZ7e^@w_2)eb6GQ)->RNi45hgdFla|32%y$^H(}jRuQf$WB%HDjA{2@#1&~<;%R -rox@IrmyY$=aGkco7J<`tZ)4TLYk|D`6COR~h<_)xXnmx80bG5tH^mo2aYl?CWqn`ov(}R8t73b63m6 -p_I&pU=qyS>pS&tY$b$@7*s#N;{Z4e-3<*|(F?;q_U22h^GPeNV1Qrqo*3*zxq`%5}|nMv~Qi#?yIn* -U<5FcFr|qJnKX3B* -%<>HeXkB>Y_OD`&AWj~A_*0h=L$yn0N9?M><$CkZcNZeZv(w1V9P`+SOOrE#RVnoTA$3HkVav_Z>4^6 -{)(R%g`s7tMLr}I;(X_d{cvB04rMJCSnZ5JVBNR0{iL+ZZHnn(APZ{NoSHT>j8u-@E9=VmUcF#$L7)2 -r!pa^cdSk&%?9`-9}-y5J@`U*%{VKZfSTxr7F*^b3C`F4!8?m$j+2u8itGpo@PuIwF6BP^xV$(NEmnv3)-VJ(y#C2L-{LXY`#c)P@;l$+M?kGHO~G#ILADQ2lu -4b_j)x0A~6Ty9Ue#q$asg`P}j{4Mpwr5?&45V$6VLc44rWb&7)+C)M#o^Wf;tfPX4g6fq=726@cztg> --V&&1E?kH>Cta^lhFHMME>;-n3E-9ZM7oE~GA}S}LKk4?M7QK_UqpQAlM|v#B2JChRg@5G@2yaHA??! -b`A5XJ=*VR~31N4V2fH#LUfPSzAF}~amV(#ANb(Xo_?mJ1Bx2!Q?=5pdq87d>;IG*<=4*FV7A9nb8Zqm?bNjLUjIj5zvubB=_uuj=yCVuX`@$Cvfq^{#9X37?@Q+ -LCAmi0Na5=pPqz-2A?JoWyU-3ia&P$MB~Go#)S7snDMRHq!jZ==ikGL|u5Y5-jKK_|+VuB8ow~=@9J=6G8w9VMdL(eGbrRUXll`}k`VV?a>!_M=KBA==$x;}LD{*l6~=%I|l6htIN=?c${^5V{jmOrAP^FQ$bqH#`nD58-u$G>e)&D6=COp4a%9I4Pq_A8 -ukt)$S2@6}q|=^VFrW$L2v -ic9IDzsw#y^`-XcdV~D%k!=^;jm%tgJQ!?@60`07vdU2;+Ns;gTg=wSLSrKF2H3d@W7!$36NSu&ejFF -B85{BcL^eK!Mdhk_cUP$#Ci_?R_@6~2AfHmkg~2v4de2HNP{OpS^kC`3&f+*=O<5SWUO=|A&dk_i%Tv3DPxU7DP*i^;R -1RUM5K^p+7hO@4X#G^^?|Q9dY(a{poyVi31L)!SoF@~9Uo=ES}7u}_h -nIH{LDZW`CM%Ri?yOmTV18(Q4P^-)%}w(^K;!PXG)e}{UBKdUlcWI~d6jnxxnBjx -wC`mDfLt>=zpj5?e#;7u3WM0N|}O{+ZXnryB6JPPKqFegfLKbX4<{I_LK+KgF#r?#=+3qD@MG&NLKlL!2#W5mj)CrIMOI=1(Wr}$2jp-QMxiu|UKwz*=aYP&Rs% -KNzXkeF8s<>WT{204b`u9GhB+`vO@<{>cD1Yg=lNEDm&-!A-feEy$u|9Z{;H^SfO^M8Z;Z`J&l-9Q!U -7(8CtCMHGw5&Yf7JUGTnE!fpHatS8*#nHE}s$za<9w@^Ls^?F;WU5Ka_HHC9254Doa;s9mMAd; -ZW5xM^Rgo3v1Kn47f=S<`x1T3?BVcvp`Um+H@7@P|T~OHrntHKZt@`ewXttF?M1wby -IbQ+s^{Yf-)D=A2Qg&GVJT(^5SPbDdS!m_2W1c{jbj_tebQtqAZOGk -ff1o^zOwyF;uVo!OHUbnXG_v4v!29Ni8~ClD%5=!LA}ZZ#%0lMdu4^61K0ntAvxw6CgN^$VdgGvnNMn -4AVUr%tKK8Wv^60E1QUGBgmAfvyY>q|>Vvjm^q6e@CTEXe4EiX|(zE;-dC$~!WIG)@*jt?p+1=Gdqnem-|Tnn^2wW(rB?+D$u%I!jfH>spV -^L0>rOFl6dihP#7=sOMsumipqGsQ2Mp&l@sHa-30`s}^axLeKJy&qZG_CMqMfe%WX((_vO0qj=tjza; -Zc+hH_EC9%)_fm;4oYMZ34&RYKWL~*^&Rqwfq{i*RC(NSYAWXMar$9XIcl9J$?&TnwdFX)?SpIm4uLC -55c6v|*Mi+OgyN)aDDdd-yPHDf7F`qptfee0Oo>To+8=+u}^ZyoizlH%qni_n*$a(YlXYwS_l2H4G4$ -S*l)JNPj5li3*_l4Mf05w=QxZKBz;CBBx4t@3O$;-!&RM0nC?Q+~lA%>1SR@oi%WtPe4HZ!Q1UvFDJv(@=X`2&bm9Hxp*8 -w=Wcd@{b(U^M|cfHL!mZ8=O?oA8f6=K6(p=$e9^)+9i$tp=t$l~on4NU1dCO%LVQrb%y| -pna_q5V~q}+3S<(?+4?@@M?(PybGygX5kn`ODDQMo6HiYe}!6!-gh-WFf8ESGo*&y^*d?RTuqcUe{rU -)NDPK8bZy>-`EDdgbM1LRpLQoG`>HPYQ!k`GYVFQGO>3NyFJ|%X_x4hr+kWyVm5#};7zc0-E+O-B@CT -SUEuP|>U^A2I&Oy(zrc`=zE66URB-XzT1$h=ONX`!yH5awDkJA}EO%=yCHK<2r^{1BP5gqhBYD`~>qN -akc=R>(X=n48JmOPE{893{-Om9GQ|v!2W?F2QFqpBCm=GB*k{SHgKzn1_(LUYJQ!w(^oNr;vG@Fp~;z -$ebCg3QgOd`im|?9nW-ptY@sT2muGxQ}0x`6`bwMGu!Zh06}%5(Sq7!sT({G8ZnYaM> -hWa^Uiva9Qh1jrT27`~CWsSOlyT0dEvhjc~bLxJ(u*MDYyz=l=AdX~NpYXq#1~`mX&uTi@*s`j|{dkxk&OjwVpdq&mLCdx*vya!_uK0q$W<7h!H%?6mmg)s<=a}V9JAS1U!Ki? -JVPg&?zuyMWax}Y%kP_d&1H}@BEtH<4!B)Sa3KSJ)fePspexLQKI5rG0+*CIdGRD_sk^_WoI&0%_X7T -0cL`Znf7F5p6ZpTMY*=VG*f!SUyCwTNF}jA -y8iXisC{>P-1gvxpf1|EK@79kJ}W~VZVZUh0|7{=vxbHX*87=icJ<*oj1bj$Mv6IR_iF5Z#~+c?Ds%5 -Q(qQo^#rWbTh#!=^L1Xm;pGF$Gu!y54R=szpr0uCPs)O)t(UUkY3oTAyz1XB3x2(j1y44u_Y(#0%x@f -ig(ShdkR*7t@Of&2@~sd9Km0Sqz}uArPon*{HK!ZI{UJ;5kb6v3G+_GVz#UdDtyE(x=YrtpG0n?2dla -7xxLL}8&&NAcS%WpW^6Xuj4ERGr2K*0q`PR`%cWDweo4G{IMn4(w_d-bi=neI3dTd%&P2>lev}S#biN -k@07ipanlTw2)sry_*NWoW<0E@{P5We(oRF6)wEczN$c!}A;TwOH$3A+%m=4XmGJc)l{U5x%B -6C5Q?k$ArGhP&tXd*?H62$=ae$OoPtl -~+X|It>s}Ito)q4wRb(f1vs=uuhlIq>LqO$k9HaUPOEM?q<~M-w(5WY|R_d#A!nyZm-P>J -zPpNX)$HY@iUEo7r?akRRU5-XN;Qkk3`M=`E59KKBZj^A1M*GvOJYzNXYmp8Y$8e0d$Egb-1B%1fvaF -V_+vY3NXauIU830#j>D*I0hj|cTN7Th9zO3iij&E`nTIpL8>ZHqQ=;j-W*tI(o$wmE0BaLz9ng -fp&j=xK>IZ}%xTW&U^7%p2_L<|elSuG;ojHD*cd91$eP(%@CEV*x&G1YhRw~bQ@kx8%e~}vHD@GFYzS -bL1eXYj9CI=VueqD-r`^k1I?hvXU5v8FvQGL9_c>xiYZuk{)-IH6q-BDBkQQWPQEpIZH>z>@g?fxR&X -Y_`BA<>P}Bx!E1o}yAXG(D> -)(zcR5OM-cZmoExI?j353bqp=^ZRKXqAtB4165^a4=`NnM6-q~97t6KgE#bfzGS$@<9D%ZIDU&rZ{@{h?v1=d_Ewi)SLBYw&`H*are*w)%Ii^0#lm20vc -s@GfOl2n#<;tc->yq`ccyRu+^LC1$Z?~%`$(VrcZR0n6KqhaP`OUFjrUnCK;;Ea^3!~>zmF9Lr~L6VbC?bM+PuGr0KA53TUeTL2#{%e&+j2e1E -RxMhx`7M?j^p(l-S=TcN6HDelcpcbxS<>mpTd5j#`Ra~w0sb2rh-uu4rnjJ_Rv=YYj2#Nu((x6yaQ4I -}w5mO{b1sxjXsi4GXmeD~JFf%f%ok$&U(hRgJBb>VskHN9IT-_cze=u1YqPNZxVnz!n?y0<;vUP^yS(S^0Xpub!zzqwzj -dy8*Pw^>UxoKn>tNpVz8kBCiiPjGyRwxTfhq!YpxuCTEm^(T4nTIBZoDWOW(-B)=4DfUZImag>`dEi= -cJ5U{6o9_8O%kzn~Civ4WbQ{pcU{l3seMz94WDl}!x2khZ>s^Kvx}`WLE#Pcg!=<$HO95P_M&}O2Je} -(u{+;Qp*`PPNBGECv#x;dMgKCC)^HPZTH1#UK`zv_O7Lqg%YDDl5(xm$g?PqPO=HJ_EP;afCb>dS<@S -H7lZ*w=IB*PP7Fl^eR#@wGIkgX)GyYIO|(<;vzDrx&ojVXf{I50QE^8qcIESULM+5+gP>sdopC3=GO; -iGEH&xaW{)zZQW37oy33%xg*DpqvQW-hvVtb5kFtoU4^sdOEm`RBun2+Q$i(1Le(IIqgd8R&Hr_GAQN -RoI@s6CJ)SE)cxMusm}146X5P+*dAyZb+ -VwMC5-gLq?rtx_HsR`sC8L%-!*_=@asqwOPVsKCn=vpaQC8${Q-2KvY*sm>p56JQPY&Jz92}F66RT2p-f^?~SpzWXgG+mFngFs(BivQRBgnD(1PviZlN`SDpz=XuQb?>+^clf%igpMtK4`JQ -9PGnqjUhT@5^9^gi`7}GMGIE{a`^*Wo)JJApYa$bW%S*bB6aks(W^rC1R6JHpjwn3Z%}`M+i5Ou6Nqj ->fvL-ZJ^DqsxrtULrh@iQGXYUJ~o18eqS{l)tz5zd|3=CDrv`o=%IS<%Twnma(0uq}GpaOOq3aYO%p} -=TrCe91i1r$_w;?_0iFHsKnbeu!m=AX_XX-c6S+AejR!)tU`<}j6V7_F1}a`3O>k@B0IW7Lt>93@_!q -X^VCop$t*UU|OIy5_=Gr0d-0-=e8CI}+;o^^DYxXCVbo9asJQ+l1Ytj*vpIdW~YyxC;}A3oU##NA3Tt -V1{Uld2d*2Hbqisi)TL=H1s!uLHvFZ!52@2-kh*cjd}PQ-eH9YlFFCVORINy^=eH1)l{R&8e{TY6d6W -8fQ7wbZ6ICrPCUj`sEU$CKRdtT`(XDJW%LT)AeOm;bm}(kI8Rd8F&v%u0F{areXx;}VBzO+)R?~4h?0 -5cqMXFP=Y5p+7l5Iuj9-u~N_o+*DHB0;d}K&-g`3J(vYv*@kqDx^cn782i&Ad5gO8|9=-MK6cb>T2$I^4R` -|0kyGeqj{{8+duJ6i)zy8Xv>cdEf#%88Zl@{1Idclgb6=~1)Iz;)TbAtOZAT<}p8%jgMW1^6+Cnic)8&e1 -Qp+Pe_y_$nrahGM+3om!n(-t4ASS!MC27n-Mtl{j(MtU-*487;odbMrW*j-!Sc<34zkNE7!%1RU*Gxt -BC@RMPIt=dOF<^uTIsMU1jwcNXNd;>IpGCucvEwszbb;4KLeB_nC5fGbu2tIIp_?PV(`uq$2i;{f6!P -ylK|FskF0osd}m&Wj+Xa3aUqVW2||TNu}W>etSq6R<)6Psb^KKPo_6kT)b7{9v_a_E=31JLxVq97QD<{XfA>K89v6hJxu1}E&7o -b1#r(8B%>v5A?Ok-`7-pn;R`-^SZeQ@Jomd&m$v&<`jDi-;HjTyU~1h|WDjS3wYpf -2qHT8Qk$KF%qfd>E -~AG#5D|vTG5p-V?+&siT0<*OF4b-_xPnre)d%pM>b+v-C}=R%&>8Uk^59b=C&Ob6Qe#X5gpgn;UC;11 -zoY3uQ#l6F%kGd>0%nVj8ujk^_b^ANBMK8SAl^8Twhw(*zqZ~VD=vOLc;#KRJ7)cJnA+FxaU7L$QEKG -ijp&FLpbtl<(03#8_8e(Osk;K)qPkNn#($VgH*F83>j%{Xu5k5$y9d8F+#9j;I|9Kw&vM --&*OK53k6GOd>nU{Bqus6JpIda+zT0Ph+98*2_P&!>Dxk1dL&I2G9T{*zHIItmd)>+}QDjxB%P_?g@hQUgh*D$X`;q1wKONu -bDAK5-u!?b&mm|;dt2OQA7-*uRtm?p%M#kFH^){OiXI#DBr^nYZmMHAyRLknl72N&?Pix=2LhzCeSEQqeXK2_kB?ztdt`PG+`gStkt8kYJ&f?fw3tGA -autcJi}j59`Ovfp7UZ_g<=fKKuOmr6S4vuJ^Sk#gUx}BT(Z1nQi3YO6I8noGZr02<#|6)IT_5C%%0CE@Xl~zkg1gSt!)MuKAZ{V8SUtI;xo%A<*d -UuqkMqRC=KgKCr|45LJykON;<*lIVW{H-Q@Ard#T$=%qrOWjV?RV2VEm0w_7ug0wJt0}H3@2 -x4W!nhWr{MNxQ!EpL$5cAAFKk(})x+*vNJd{sM+SB>e@jZ}vbnAuZbF=4Tx+bu*l}=&TD^VNyHW{tHI -FE9wYULGzhm>#c25aAQ8BvnGXh`Bm9rt#(K$Mt>Z!{Xb0xHAJJ$gzsJ-4 -U;g`OqzK@Q=R%g}E6)ewPL9Ho*8R_7tVHOd8wseAN|+bM^Upa4l}9salAv&z4m#1AmD(t@h8K) -o9ANc~E-Rsh+7Bkfrv28`(N5UhC8QPQ3sfx9>*Bo$t6V)MTw^=Czf)^{YJh6#1UP9%;Ma5MYpkKlS2q -5IgiAEUSrfjb?*${IMmYMQ>j_Gvu*#@2*6KuLy3ATV`g}1B@n^Nq`N8kPj$ST$cm6yrOlJf21Uo$4yc8e8- -obM;1#{vA;1)cyR-Pc;qy>OSu2R?z8aN=ryXO@pE0Ue5GL*Am(`;Q9WJ@{L^F;dO$Nd99Rip|Py${O_ -2pdboGKg_hU!^|4A_9&qlXn#lpF`wbghmq?Pewl$Tk)LKIYeQyx;hV+<-1Pql{+K0|NlvN#H5BAmTff -fvJDk3fQm|?rz#Ju5P-phP(R}<06^R|-tqNsJCa2EM@hQE!vvqRRJZk?2QH%m=}^fgO3PR4Bd8f)O&A -UMNd!Fs-=hq$&09f&fZNSlaKv%YbPU}iXB&VmIbdG<6t@`JxvEx+qZ`S2E1JxIX@ieOE@`$7Bm;5$2= -M#@6@*=elN&tsXcte7I^jzehfXsTQh*xTI~RVjwgC;jJ=1NOb8|>AA-nWzun#Uc&Bbj@UQl -J;x=7}`bAXg;I$~174jYaJ%sBlx{B^AinbzAaC+&x0MrOux=KVtcvr#rwlBl%Y=j7;mY@mHC+|fibE>h-|~iXA15{RDjIjt*VWS$J^?oGtmQXzok4 -FQQ1MBTNug^N4%5DsBmJ=$n&MjHRO`8qtn|@aRow%XdwmHhPb`*|U}+3#8leE4`JU?Hj52!V*`GiIdv*G0i)8PwiE^w{La{=M%BB@wXJ -TZh|0CO1$1~IpFVtJNMUyga~YZJ@!S;`vNS&Gh^)W&@+cMtH!!lu)&_C{&`5#+B+DYsO;=MLc~SiA<) -x#MxQ16eI&!9)ZVs9vsZsL6I$mM&`j{skkyO3NGO34VSV_@ndRkJ1;AKt6qm6FUw$T!qosV!OdDwi~D -^1oVpr*VglPe!vx25voenyh~#g{i4=mz?%yAEGysYnU%)xJAY=9*m*F~h3AGU`b1*bZb{jxGJdzt(o7 -m5yO7XVB=0(?oqe_r{lU`(T8FDV0VCZ}?rD2Vxo;fL;d`FIltdSfU#++iqh>*W5ENKIpL|!g7%J^;_7 -|`^SJ!podm;M+dEbd743#lFm~WS%DVR<~*@rNbXG)N@#=>=yrHIY$tQt#-_R&hH@paLRZgV%Gtgm9_5 -af6iS5x<%>tXa)52!J3cA*`-+YME5-2IBYdw+?%KW~@kqmhA$c9D5Q<)fD_r)-mubxx5tY!B147w{|S -#UY^@)wP5LnzmbXc7y9Z@ -IgWo2-d#$^N(wy&qo3z-mqoaRkchh~+NAi95NjHvC&+eA@N$-v_RPt&@+p{P5ebO^Jx=;F(d8*%i(r* -cy?>^~apYsu(-zWWgldAgelcouh|9#Q{;y&pLCE&6PrFSY^i|m|=SB)T{X`I^bh0^!0YX3s%Hy2)Up> -%ws)(M^FC7B*oK-aGK`g?%f@3ivkr1{4^t8yJro-UPsnT}5ww(s?I-2Q8o%XNSWW$vyl#rPN|QUb44h -cQd}Y@%;EG~8MsZ&5#A*ScI=eG%yBx2_%Su%E#e{A?9DI?qBr8qn3$fA;v-)%4 -Znz=msPQe)ddXE3hF$;uq&(xV)nZ!hjnKK9-3=XE)UxRAPXM|)9~vE$psYKOnNQ3uwf1T$7^*i`4iU; -F9DwM!aLnziRe#YVb@u4F}?%}84mo){~?xUbu*%DEe_q_PcHw=8U@q$*Y>G1n*zL5_-*$&9qfgvrg1t -eW7@Z}(}Dp*;|xMJ7y9Pq$O9Vy7sjZ5pj!y%%=KeZGhCLvFh)NK-bRZuMaQg{Qoqj>Eeod`QB-N?0%9 -+Y%}gUX-v)e*uR}m?`0W37rzIlkiaqUy$$(2|twZ3klf(0iz@wBH?us9vm#-OA`K7!c7{K;kHV+L&Ci -hHb{6v!fz$)6fa;;3CBn{Q^Lg(u8{E868=fT9TGN3s7M$!P(Y)EDH2*GoGoF#gvAoBl5mrR4@vl>gu5 -kdknlqZKbP=Z3E3c7UJ~|~aJYnN65b$Tj)b>MxJkl4Nmwi4aS1<{kV*dcl(4^qNfM5eFiXN;NLVc4S_ -watP -*bOX$rL(Eb%w3(#&5D_e6(U7DGvamPkJ2^r@R2Nx!vaHOFnQo;ak -iW!B&hAl>4O|Ln|)wFXTSCh*!vNm*Gm_9tLh`_$gdIe)G7$U8ZS7YHp67{EbMrgr`b=4*V7QVhD`G;g -i90DX=bqYbm!=$XkI|&`$Xx>YO|!H(V)9336`a_=3xzwFr4NA_WKH=E?FE*oy!~ -ZncsUK1=*K>R4Y*t+ZcJm;CWxUZ036!kEV?%= -fE19gP!h@m>29_?F0Cu#mSzC&!-e>mzRMFdYs5KU04$Pbr`CKetUTH2kgYlz3gj>&Xz_-!A536ZHgkA -J0WC>A1Zn`IX<#rMBuu*~=3{zkZ~R`^L#4f3+O?QT(jF!4n2&LLw6r^#fwboaP_?uj_o;FYrMb=kbjbOMe@GK=iEciI(UZyhzvVtWnX;c`zVHq{+bxoI8!v}Ev}N&3 -LfD0T4%b>f0uRk1yc^o?JeHI(dKEO2;HleXASItSD4zn{ab -@k5J5KSpGgU5!&C)#{0n55HmQP{`Op+FOja6o`zq;r{U4!qh49BTe9T3QeTD2$1~Ju!($}Fay)|nw#5 -AWL}AHBbuq~*W47nnmn^jVD#Q&XOE0re&2yEIb%x#H(mYJ=Meb4%o9Qm%_%hwayx>g^XCak=E!UanD` -)#cr#si_V_0TxF}EUJN{jFlZo*0U2p8fnCtQSw;!_+pBiH42=I3%elbnUp1imbGJ4<~w@XMZGZ1;1R= -@vFyNilbv;g&GhMR+Ja#i4K%hWwfTqYDTO3hor54-E^Ci0o{Litf_2Tg+A6V|((#qYUt_=i1L6k` -8a(9cYZ8VI8=janV&tgg(POSn8GBvoxbfFdNHa}LH(Mr6wq|5b$+F!rHGA6h88c_io-_Bxo94~G`4nSWYb$8`WNss|5|InfA#OD@=t%=@aJ#y_xssdmi -fNi{&Vx&n(wwQ{Bk+pQ@&E4!-`zp@zdp-aPu&+wUBE_xOA7 -fAHZ)jUS)*_za{j{i7k{{<{+9=YjywFHH6Z*?=l_2?{eSy_+_C@ -v3jWjg%5cB-&>Qw3Kl`uS*y)N;y`TNAHuk&Q*f+MZ-_yo^ZyWo4ZR~V~sK5QWHg@`qPHW;?yz~)uvR( -W3FsHCMzhv1ASFWoN^Dwy2Dz!VOF1*E_=gKH9C~+>~9&;of_-Eyox=eYl!lm}?5{KL2a~Ey`9kT&*?j -rldk}?r<7G};Ctm0?~csN!US@@%82w!#3F38owUhFO^g0U0*>u8-G*ok!thzhb;EWz}QPQv<&0vc1Y= -Z5InwMj{HvO_Rj8F_Z~Ig4}fU_tCC!=pzC7Q*y;J#7)_S%}7yPUYoymai#C0)cmy-?_HDTW~N^sH&<$ -K_?}ZXP2)-=plnsvgec|J`%~!ChdmCA?54J5sM+2#ful~^&w>r$1;cG3jFlNiMn78|p2-Nku}?G$gJz?W -NCWY0IcN{l5Ad$G}8X3ulGau*h9E6G{KWFh|o6sR$`*qG};zk!s1270#4W!{-t)8%g>vYy7G~&e7B>hFi(Wge8dBPFt6hP@ -V7gi9sAE}XSXy@?gF~Fo7lg|IVz6H`V -obP?MuIm#yekb5Uo=T$J<~j;6!(+GjU;IaiYC=>0m8#oBGmPpC~m1EOeF>FR>T9wD7Iz*quuXi*tG5qR0 -?q*lq3-m)(f6Z-b^iqQ`-^m)HFTe6Qchu4nUE>oe0Y8G(OUp=&W!ky2N#)6egzTaTvv8bqI86l?F?U8k5ypDO&LH%GT$&s>#Zf3qsL6?Y_#)nX<&bq(p9Q^p~xxzptGc+i_!T`V8}oyZ`dL -8C3_8CO)4rc1Of2%U@}Nn||GV8t+Qy&qg6FpN}z-2ENkyrG-lzMfL?nvfrGaUs&pzzidqMa7X?^_A?& -B9o<#Wy5>i)uF2u7>vTgyWNoodQ^=kpW3MLl840cVdQ-;g0BDVXR -laf%Qu6%z8Ovo3Co@*3hLkisPj8x}v}B*PpSlk0p*CVXTKMlJx)$J!Xcp9?7sfV`_U0iyYl|uYtw6I< -xNik)SVv8AgRUJ2eJ11YmHD&BGW-@xy{x7~;Ukp$pfsaO7OqEsS+bHn46ZqnbN6Ml^)g>K!3DowB1Tt --VOY1(+X-wDhdU^q2;Xw(Pol||hs#^xq7woryIfcXwTyWm477B;ezqdmI!k7n%f=+^W?BZFC -Fa(5P~>&7}^ex!x_+Zgmi*D|*9V*zy$0W3ln&2+{HX3URf#+g`mqHK-MUd=rlV;ioj?dH(+iV$T!6J? -Ha>NUN!+@lSs7s!tR`7umyrRVDjjCH|$;(kd_kKv)Lcm7`1J9!W5t$Ueuu8nYn%W`fEmU#>bU?IBud3 -@g+qh~QLy!jz42KkQ}8C@HFrJJveQztRD9PjfQAE=xrw&wpl{C=1u%Nj7cdl>2;>R@st>ps0}b97^C8 -=)}wSQ+b^!Prr)9R12cE4zYB#vFLRmSL)3eiCn&6EaTMAk^;=)^()87bgN!&#_spai+k$Hp?##Z#RB* -Wn@fa*M{g?jjr`J%xi97Y}kqR^SOU2V;AsdpAfLeuy7WaKaIuB%w}=PQ(2rYlZg@(Wk5>QdnAUkKCb6 -jpZsT8pX6s)AKf+0ZH#U()J8fYa>A3s5IdUiq92GuKN>f(d$TAFgD?LLB`8;5*{adhE1dOm#iGr0N1M5d_ -0n}=A`Wm-{RJM>TUpz}ax^@LU05f%Tk-Tr3TJ(jA7_1aTiE5johX-vAg!*Tf6bTu>vYgB>k8Gi&)1^Q -t3V$kaXtn6WZ1vbXzhmn3vHm=%t-WO5v<$2=-;Sa&kRGm4(07y^y9#v4>;3TX0_4Lome!|j2?M;K0>M -)OThc*PyEwBzm2%v5VzZOq|rNq^#;z~aPJNG-f-_dvPWb0hL~EOKJsG#Zk|4`b9!Fq1TCNe{cew$A)u -ubwU1iSSK|e)ScHuo`Qv@mRh!U`HnsLqy7({_pWK7Rf8Db=w(+WlZna$;(K%7syxvdO>b)3?G#pQDLE -nHkLgrJeM;h$W2Wj3L-Wb{tQXA|D$_dO4NTPDHlHagMOJ7$P)T?OJ!zk7@z4N_c&HBbp4MDZq7)ap+F -QP$z6f+zNckr=O*75GB<6TE}cD9X|{AU-DP+M!n$3%-G`vEXYg_zE66 -L>5ZE3*W89D9tEp#fSG^y;etOnrrU89GXV%5ZN0uB -P52)SBc}5)O8F8rJ=o3VlIx)B5^%5`g+YR}pFCTSGoQP~)sE&owT&oN5HVnK494S)JwP{bhUtO!!w^qLCB08}M&=4_Qlx~laL -CmPDW<4CSybUCw?-FjII-i?fn{!>(jvJ{R_ecm~JzdGVp2?$hJ#|SsZT{d0MV!77tgkDY_05k$UG2>J -w$4qndt4jI2DvV>LHXaaLCF``Al$g=-PXZv>({Kq=RfDx1^my -sbpijco?Gv$^FJP5qnm7ZrHdtS7FNJ>SVGVYJ8i^e=eicpVXI*C->uCoStxdJ*<#%!r`?`axX?*o|F^ -Pqrya{_ZR?k@eH^pf>BLf9OHCguy|3CU1C~-ki~WMfORBMfMwVmr&Rz0;kc=V7qxM479n6T -!j;tyX-Sd<`m}J(--GD*{@_Cec`YYx|MLxaOGRUKiZqr2grSFzCnu83y}Naru=*-r{?;=tdiV($v0p~ -B@X*#Twrpt)66Wl5bYBAbe3LJQmWaeSf<}#$Ql7~f4tw4lX3@=XIq{!?{9eaHpr{w -}VrDa}S#wO;89aKQRt^d5@PCa?bPyX$3X5H!=bZqnJ=Z~H&e)sWY@#g`<`5ikqC{sdcTmg?ZR(VX-6F -!|I$drDF?b%^W^g_WqEc7l?n1fiL+;jOC5R#1ZI?)?F-$D7TKNIU^7*nK|#}9MY -9W$WNy){;$?-!`KbHkmQ_-6tJ^WjU7SZ4EX6L`@QEd#^jwF_?W9`hvX{BoKynjNEoJO$W+6VLI}2SXl -%g4S9v$Tum}SphYQMtW8<0^9r`)2#+uM4Yit}eU3X9WA+@SLd;PvP85%9gp?z#e@$-mx!%QxvJ6_tXm -vvZ5wb~cY}Gc?hCakAv#IY^mTBK96H=gWHl^lVg`v+d4OZhMP -|5iJ9~4ac8N;aM@6P3ahmucsJOEjBVopsYY;VLor8XtyjeFe}}LWOyAy&h`XO2VI;1wu0yvbyBd4T_C -LFNwtl+$e(N)``9AhFIieQh6P@9Ngwmxp&bv_j@v1gA7^IgItyu|bPhYtQ=e`Zl_OV#%b!{xN@rR?>(@RC -$Ji)Qdn8SB*p-iVzINmz9}S~@yVq|v9w|7gYR5!bT8@xMYHPpj)Ib#b$%oR>{bZ=i!w39isQ*0wdH(b -K*u(c=SZjLH?;>Av?_5UmgA*jsNe)|BuH1|MekNX8!iPxKQ|aeE98umhOM$^Z$DtX!HCZuM*AI%K3gk5Fg$i#RMW}?eew#r2pd|3Hb110@{ykG)Fa9x^E$@A>S1o0h6&HK}QNqxm%jX2K(m -hH-y@X85Ka=^EP?7MMg!K~cknkZ1*GX6=VUC1zCCrx4Dq)(0DH0}0I7C9Dgs~DvNvLPqx>?exit+cDg -!K~ckWjLqNvB-4}dziZwVKmPK4ga2**KgEm2i5kiKOK`Ux%^BzRR0cR3ImuqRM3+J7(Ps-6#=*#6{oQW!UOh7#F#*M0LLUTmK>{NDRlMU2*xVmz7Fv55d!B{z?(4T$?v6 -O^8w$+`zYLx0p2%C(7y@r*U6}-aNi6VI9lXA2yoSC!NYREPw~dWtN^aLma%a#R|5X}T0!S#z!ND*i+B -$B@pYIp!F>8Uu3L-aB=}9L2>&hMoN;MxSD8gxNq{r)HUno4U>V*P$}iv=ycc2K2zU=(b`^L97;8cK!c6e@7Qx#cf -DcZBAKV`TJUL0$J;0F3sM~PY0}h-lXqXGQJ_B*#{wUx(8G@dZfT5YP+yU$GZbF#7fYvDjC&8jAB0Rz0 -XQ8j6bOHO>gnK;TB57U>=)3`WK^PaH=LUg)1K{2p1Wtk%rJ3N!slr?fsLMt_&>g%2teMVO7R(y~-<&S -+90j~)hAL|Q3;zr -wp2X*B@$$;Vs~c#MF5v7?>BTnqT80)&V8Nx(~sWdFICu>mEFx!_Lskxp%ml|($@&S{`%cDIz}*Nq>z9IWa{)j2r6|)zz%A=USrc4PjdqGKIe@>Z7HMq;e79QQd>`; -zX(qVWBk&L$zd_(h19a4gwoGus-J;)1101uF#ubzc;Lv+SpG@#0yb;K|0$6Y_+91q}0lm_E8t}IJgxL -jn@jk&Tf{)X^Y%tUPY}s3oHp~S3KY)4(b3EYe2Sh!o1l;?8puZ8Y+rya4BMd>?!@}JG82bpuMYt0*K8 -iRn6MXDZ!IQ0k%N`TvGQb^=$$kuQ?N;O$;VS`q{t@*V<=YGJ_CEnH%qsvd;7x=1BH-tL1>G>82AumhF -?JAKxJ|g{1HQ6Nq}2$x@hOZQaDNDJ(bFh*n9Bi2KLZ+IP61r?j2veH4?iR7*ipd3X9eGi08@9NKEZt) -;Ne}O?2ZC%uf-S%_Z@(-^{BTn6Fi6aBFrs-Qw|9HS%7~&AjeZOzlJ(V^#O3~>*z0FHUn0_F8YTJfNx6 -kQNT5Ci273rIQ$U$ZkUq*A3Y>+63l1-op5&nt~df-!%T3-o9O4MUjn@Frl{K&0k^+{GDCaW0XXWInCD -mlxU|svlwOrZA0+xf -?~FQwI19-mNe{3;1@Uz)5l>BnPq)eIvo)(oB%#6xN}P2riWF1XoITg7-^zg3n7c!K2bl@M~!%7hlF+DBs%=ovpa{5NNPJB-D3m3w~o(e0cb=M9+iic)ZPW}oY7dJt-L5mg)SLO8WFiF=IkB&<|THA3 -Kdq`Kh(^KYG#QyH;%4hiS;cW8c$! -yM?Ijpd-kh$G%QBdXO_%COhH*aQ7Jn;nExpOD0t*vG6yz>sbbmT7Qya5SRTO)`{# -I1+aFE5ryTwJzn#R>}WrF!tAqxie~+3L{|4n -`?5p&7K&d`a8cM-Q}~023JMPGm-dUozX(Cz9i2M-|&1;iiyvA?Y8`lZ+tXd( -L#RU@Ob4jw{?4a6?}#XtUTM2ZN&?Jch#dbIzO2YFa};eOgQPHjPS{>>Wnzww8e2U{*4DzD|?52@-8vv -##y{B7FOqH=G}e?p-MZwk-#mLC(|96zT`cr*Pv`3P@zv2X3_#=!Ckr~-Zc-ax#%awa;O4qlxM= -O1rE2k&aUYB|&44a6IQ*MPULO7%QS*7cvN=gG;*%x1H(88c?E+i$=9vO2zT<3{$UKmCb4`|Pv4j=%l( -+w9b-Q@(ocpyL6UV>z~M522E{!*PfDe8DcZde@h`3T`c7t5HM+yHs`cF7E==gj-jC@!f*wVOag(sd=j -UeZk5Dr)JHXwW}a2`Okn0Zq2-Hs;WM>KwVWmc-OpH3)pJ)54)b5Mfi5!Mfg{%>X~!rwlQ9d@4&pRZ(l -Vkq_4^X<;#BL)xw0x*C6;rJWAty(s#@xJOc*~WC;lgEGa38jUPXrnM@{@k&(f9H*MN9HhcDLcH@mVvY -T(dnXSs7#1<`D#BRCe7Pe%`66SO|dH=C;=qt5R9TA`9DaYdYIhVq*6@)7Xn^u48{G& -tSh>vyg4y>|p!up28aba4Q?~vdV_;R@sPsDx0uZWusqJ*|;}UHve^%r5{zPNK`oy^U>F?_tlWPqCxwVXZ%9-4MS&;w -K^gc*M^_{2LK}5#pDr(QG~9Z$bROB7QC6A3^++e(?t(ej4K6g!nGRzYFpIi1@n^|1jboL;MdB{}aS-L -i{fg|Eyp9#6ehJm{8ZTHs45V)w>uwgmp^u9yG!u(M&xyf~g-&W9rG8I{(8iJ0P+8Z_;rYX1o2P##mD3$8%^1P$;QS|#1BJ!^gqp*#HhwDOuZiQ=Og~@i2ob -Je;)CV`o(9RSvKpAHrtPFWC>`tW7r|o{AQNH)aaX-I>N!!X?HU9wk=G(=V_)sRnOGJANj>MBK{b}&qD -l#h+l^IcOm|xi2n@Yzl`|%5g%#Z^FHFALi}c5{Gq@w1sDo};g`Vh7%=PwhL3@vIa+03k5JjS(^Pi$Hk -F;bM`h=qQrY*1RbTu##2<$E6A*to;^!g$Qp8_}_`gN`#}WTo#NUnhhYAbuR;_e1sN3twd(pGPP$?Tx|CR!-oqD@%{T52TZ2;z@M3!F(Gq7@2)*!;g0}AWPm{n5PyP+BBy6Ai0j -(5hw$e##`iaZ$P6F;1u@;acAYYw2T0%n`WY#Hx|w`UfEVfAx@ISxn$h= -SgT>TQH6SNd9sBBT{W(vCWcc{tFgNG)+zI91=VR#`Fb*J;U6Z{(^ -K0GBq_aAS8|a(On^6%nETgY$J~%!ghosxYX3F!xz+8w?at-O*@QOpxgVdWX!E)0) -2H+K$SV6}-`wMgvg_HpLJQmMOlQxowXki!Tg9%e$D9KFob?@*%|0RK3}t}7{`Iff{rBI`9(dpZ_VB|G -vqv9&l+P8OdFB~DAAI437x-M^t=cEp{g`iT!(3tS-o5ONH{RfLgOevdVkb_VU?)$WWL~eAoj!ee|4Us>1prTvu -8hoJ-8zGp0NWH6BFr<$ezZYJ!5 -VM6U#NJ_v(Fo8vGO|yveglUjhKCL5BOQ#!A=f18^$|l5=jtw;)4~3}VtmKD_S-M9E_%u}qyLn0K!hkt~BRMs>wc -NsKj&;UTH+J5u7b?u3hS9pM9ocJXPO*`)%5wQa}3WBNgj!mHd$h731s& -ilQ_juOA;da^%6fy1La9Cr%v2L^+YjNOvYgI*1l3*D(2#SrcI)QIXyhcFB?@qgq;8=vJ?x{{a0x!0$t -7gUN*B+H0>JMD&3!PXDW~zN+rrxl;vw>W&>dINhgCol-yj^i#E=p+P--_%IJgaWF?9_mhb8`=_3IYUT -Fr+gD=BW~r#CnCfsi%y->&S2pI=L>q~-By{iIeN=UI^-Uv3jwIg2n$6}Rg!dn%|C?{VQ8AafXTX2~qr -tW)?lGXOW4hr~^b13=r}FR6taeHUz|m009C?2nh*6Ap}SZNDQ -DTZ%I->K$5D6yp*?sf{I2_j4wo5$B2!f0-_*$_V3g^;ijlOpy@SVJZqiYdfj{W|LphPw<-c3E?ls8od -t$IKc}ys=Y7@T+b@UyGiT0-x*;R~k&%%%BF9YVKXBlHY~8w5l;@%`v(aJpAAaoLzu!z~-?wj{(Uq#ID -)Sf&*Z|}WJ%LBiw&{D3q)$X*-VwQDzexMNBDd}qX}3${p*KZd_*&%jnKK7fSN_x>i&a4dC=)Ck=qqR+D9U1&Wn -tEPb6YTO>3f2^#AA&~W0EX@#h( -s%`T@*t{m7Dac0R71aMOtrj?#FB-{pvHs+JEF<{gE((d1B?9eT5gu6|!M*pyS9Ha*tlvBYMH;|E0+Ni -lL9n|J@%2Fm$UF>3kr7AwqTGe_j=7v-9%lS6e*)h8u3^sC+0y&#*0_a3Je-$rt<2`}hUU!_K%z{8y@@ -VEA05w_>SLET -pi9C2j8mvL`q-tJ4g>{#!A$+7hs>I;Mr9KR -i6VM*h{u8>hvI@A0nkf?`;u7>XwZ -=+8VMGW0veP%Sdx>wrFEllpvmQJ=wJ^%)FSpRq}8wwlZQ985oYhJVpGt7d}1&R`s&bi`s|Y@XU#)=%y -tzQ?-C+8o7@-AzuPJSHFg8o)3_F+B2(VsPnmA4i|#4hC#eF_bHYHHu-|;&F27#J7zyHs31FROLye)n_NhxM -@dd`mq;Q{=0PPawEL36McnlXoGf(1>29kC$GV7;;Zm&j2+V>aNF}I6UOztXWiXm8^pH-VQKQ&GY# -&(xk$vtGos2(zPL{FKMHAoJBRB14{V~loAj8PZ;YVVEwD?NqK4P6|e3A)h-=(aq;#=GNV{4W@h|JP(;F -k;vzfUJgHAle*5h=seC?BcF(v|woOwEstYeE2EU`v*rejDXjz^SEsN4)WI -Js;27gC2SeK*=vP@V@~?8850)pMctXm`$_$>y;ILRYxB9)8usu+wuD+X+m)#oC$Ny{=~WM -O)&Jfj#26~mK?;jb!3(~^1`La|A4t{CH`??T&u=(qCUwQJWKp#l14&6-t%As9z}SbqEMynMNPiR>-tA -v(M8VqjvYKSKs(W&4ZE7bUCkFO@iK%bv-^f_qM8~;E*yzkYk7krSlYuB3Ci&$p%?Ael?on3>WJ{=kklP4-RtzEROkLxT?9;q?^LDH4l$&n4Nrns=BCA%d68v&zW~NM-FhL3m3XEQV{`u#|?hp%w!UE -m+25c3v5b-Ga00Vt~cXgJW|5fu1Z+4A7+Zbc9qtEkH7aF2}+qP}jX{_^SOMlz8Z99z|IWld;h!NkZ9W -{I?DJhW$9(X|d_wO%HJ@u44_uO-`V8H@I5BWXxf&pKEpRhQ{VZeYrMGoI*(1*(u7elo13GQ=S^41B=e0rl{PyM*#DPm2BRriucV4h~@nTa4VQoj3B`+^e;^X7x`s=T -kn{U2ZG`2RhKnJ?vo?x&u7z-1bve(A89#}q1w*56${c|A3z(22>(nB^sGfF;vYm=NgefpsCyV3QBMT- -_met!N>^XJc(>C>m59yDl>q@<*neb>Cw$PyUP3vfakID)ZIgTN0X_xNaZg?a>eB(D)8!8@>o7z+QF!| -c)J)_*uzb+;%zJ^hQvAAkG;bPgCWz)W=7Vz}j&TV&$IiG~mO3|rf=IG`8$ZOxb5fFt^Vj-U_0`i{?b= -N{zGp3AJipLTAK7FgOVpcr4Z5f~XJus>{q51Chs4IlO1pOL3?F!(bAoY%k}azn_J|x -|50ESDF}$<&4W)^8TVwkdhJM9e(5X|WaNWav^m+UC?FIw;L)}pI!(d2EOq9NT`x@C=xpJkUpS@8*LK -iGfO$3mW?ZyccoextK0rzVz2O-(hnRdwC?H*5{^ZRHR>Kri75asm&q$?kZF$6Oa4!4Leo;^h}cu$#>q -NqY_bZdrB9uv@mF4P3|&x-fI*Oi`O<{Iq*Oo1L74oxv6{kRNg)CbWZV#flZw7>lmC=9@hHlP4fk_}UOPeM3LIu`vXF9poNaV$ac`McmAP`TJgrez*K%BZ7TwFcyx~*ar_DEDI -MdH1h4z+vnC*bi(S{>Y7kz1_5FlPp=X#K^PNVJ -5h3ZJxM^=g5rhAE?bNZQ8WyKSFyA{cgYLj$z!fO?^CJ78Mnl^TEaE!3Mp^7Pb>CmUfL#S6`vLUqU~$s -D2swSO1-F^RN1_*qW#9-@zMRgAcYR2hXrY^b+Vnfd$%ijVrM;_0sRI|JYorKAsTY6aVm>z8n+T;`sXO -uN%9|9-yztJM^OmDvv9#BJGBLcl}fCL{0q%4ERps7wjK$fIq@_vd83{>^*$2^7@=BugRfhCoOs -^TTrR{+oOs0Ji8&cK>Z7ZCZ0a1FI7iP_IyMQqzH8k)=eX-?&_C5VO5oVUIW~2U&7I?Q&astqjB$=rou -dSfO*q#6-cFe33I_N0Ga~n3do -e^{YyT>J`T>JC0BH2epdL0V%*r)~5Q@H&#k-_hX9Qx7FQXdUq{Zq4M&F<9PZoKOBS?rm{oTt^^eyeur -?`oGm(fGVXW7{zr1M?k*+jNF&ym4aGSAjkmwNUzeU7cF)2S16t`-4c#9<%=U^{oG2YQw#{=2>??-QH_ -r>*r3)e?jL@YI6^&-F$@$(=(;tNS}-T3N>+Ru^*lisr<1~z1~*X>FLv_CoWj9ARZcsoyZ^XkJxp55w@ -CGmN7v#+5hM?0efPZ&!S_6{C-|@9UwVZAKoe0=+hRJjf$GDtevt2?xGqPTgnM -$B%2ipEhO6lrippw~c2x5?lLndze}x^<3(R?)B-t(mx&$B#*I9kA_|!JtpMw*6jiNVAm)9ara7t`|r@ -gsBrod-t0g<_SA`EGVO=jG$4=hLGl>m^h`TA@)*>oGwW-fl(=~D;&?Y5tc{#=WYBM;rb>T-n((HD=?( -S_kNql=p|o^+FVJg4C+K&&*C(!+G-*=W)TvX)xO=bAK;4ABU{GJD*HrHG`{*-K4@Dm7G11$Y;q;d#4- -d@erY9R3j67Ce?0pBXAKVKL?g7L9-7{lMzl&ZGHBD;cRvxK~(_f)CVR~H7`cp>SZPvQSC6C?SuFZd9v -e~m|CoWsIEFN7X-zPo?H?*(^9N+gQo4z6aD(b51oZ9vZr@w$s&>x{!n3vSEW)B!{8%^)lE&u4&V~;(S -ruKh~?GKO_klV2**dF%cRQ1R5<}>|FpMd&wg;QT&>Cy@MOmmz**;I!HhLJ~Icd*XSey*+mHa|lTiTT} -q7I*KCeQKy@bnsQb>9NqO%U2q5onE7BTw?!Nf6kmaiO)a(d_27&;&JG(d9}T75IWck>=ExV=->JtyQm -YPmhrpq3aU#TwE)Y5}{VU{=WV(Hqcm*Vy&r~)L?U7g+ur*{W59%k*r=+ -BeQd!Q_7>O@-lk+!}Q?+8RbnoYl9zFVXdOXzVAAa~@ffw}G)Gycc3)punhxQ&3dsJWbtM2FHdaV_jpC -9)GzOvEKXk}~sT!Yw-{ic?S3{p#{uYrEJ`v~v=yTEzS!d_svv6;}hbLY;vp2qbkjQ$rC6eJcG7suP28 -$LtBs8OTj)?06t`|rQs&}Qp?wm-z@kQ-|+xG!=2`t`-0K(5f3VeB9FXU2>fW4InQd3-)Lhu*@Yk3MR8 -%;*K5Wv~af#!I|RPldQ$F)X``wQJT7u3@=r68NKxj0|HNxL4KI72y|q4Q_1m!Gi}^U*_6oeb!N1W9)w -@I&2L5;)^fJ^5x4-tr*)#&B^u@uW)U%KI>Tji!6cH#^C6l?Mp%fGDeSs`qSpko9%sqSGsl${>Icmu`} -2{_*_v@f&3lUy_oF@)K9K-@LiJ@S2)qHhU{CN<9w^Um?KSUefO5x(06v--`%Y_&l8xzzrS)B-`fqVlT -P)At?GJD<*~<#6)QHBl$4xN8}(xc{5o9+307MUi7v+<18DQwx0Zv#0K -@#*^-*4*(%t@zl34`wZN&E`bzSTON;AP3(3<0WqRw9ZY~CiDne?e{w>x2=@<;{vhaa3^;ne_+xa{erPu^yIjI!1_|gi -@DKq?8rg0pX5+~O*ZSFviwK(u=U6(ynN`Phs>U0r{U${S4(95^n1+xpUZRZl{a50<@}BI{2e=Xm{`r; -kAvMN=7JyCQ#UO<#+SS0pU+$V+k29@7JicT@kitdTpPQrzJIFweC#xIa~<}AUJ;n^+0>IbmpmKay=Tv -!TIVuyo0rA4(CKOFOiw-2ex|uIujBP5p5~sguomXmp7_PJCj5sI^NinHyGGv&{Bi)lw${|ce<|S^zqR -%UPeeq(I`KrA!LTNli)1>=vGtk=7-1_~@k6#LTv-$-^_oWs -Vy;q3!T-sa+B?Q`=?V79N(Gn3g;;DbxP%#%|%awTlRk{VOhy>!}-^O --NHvErer3CM@O}<F1NJ(| -c$&#}rExawgv%K@XYs$8i?JKJ)t1dfRc5Qjf@;2p><-N)i%14*yl+P+(RKBKsOZmR?s`Bdcv*rA-W2I -grtSF+WsB}$fMd_B(U8VaJ^XZHB -WL?-?hFLzLvf)UmIV9FVYw5>*ed`OYjZ#jrOJca(sEdMZO~68efHPi*J{2pRdwahCI;$Fr5iW7>5mW(c`DzQ7}@m}j?*TTGQypi5mZ!d2@Z-RHIceFQM_i>T8uIT0 -W@%#AyAO8nXO9KQH0000807zB_Q_cT$)om#N09LF302}}S0B~t=FJE?LZe(wAFJx(RbZlv2FL!8VWo# -~RdF_4ubK5wQ=e)mV1$mMOuo9S7lyxCA>GQ>MBdUvus)|<3f1Pvqd_Is|4P`2T^!2G?`XKGFns_e7h`! -n2WR`U}r*jFHWDHygEAxtIw4erxWk#>sRmIo<4d1?)BRImg(;}ODQ8Zmti$X+^m(265sGx}iIwYc -5Qi&p-m3Qyly(51b#ijV+k^YLs#-;uWD2ghX3kg}w<7B3Q&P7?qmmV{y4F=(Ud@t`{tkci=TB -vp>MyhG@)F3bzh`yJc~&N$^SHXwZ;HBs@@i2fv-<0*u2+e9-azI{BEQQ%gbM#Cx)DVQBM?PH?^#k-fb -z-bvB+^$RN-+p2PC|@AsD4;ayj(=mgLU??9iK*Krx`&5Ssp6Mb#?Dm&pt$t$+X(W2CbJbDEY_Je!FLw -n{^8v^W=4j1^Sj;H7*q^j@C4JAQWj?l^jW`r_o(@ynB;_uDTgCoiJ*4|nf)?&rnH&&N;y+O9EB?IUG% -+t|g|Iq(cHij0-APeo1u_TnBFw`h#grj5@q* -q3QIy7Wm`(#MM+if)S6M0$lO1micmqIhc_mUW6=EVLG{L4g5#p*U0^pmW=jW?@rFkw%r!_w?nP=*`=c=cj*x#{4|@@7@tJfC;cd)$W0FLG+H`r|~TDH --?iiW~DfE{W`{9@80?K3jFuRSyp?u&p;IZ@eEK?R&wbh^N(n;TTtBb=`T>ioC3ihEChTRi@@LYf!8A6coWJuRQbti?+~25h7ywQSQghB_}k#LaZan*E^r$YfPr -E$-KH)xBqkVyWe%$kVmCP7yJ&FCL`=O1|Z&uN>lPB+g_D -!f7av0~iNGE|m@dq0M{O$DJFVUO7zC3>M;`P%tQ0E&%1vKBkI(_>3*-3PE`nMB*fD`diFYtv4yb!SBr -=IVJpRyzksN}#LoCbjv-Dl=&?>Fh=50eM@ ->OQ;*=-tS8H~4p1Fke0XuzUdTgAXBp7~EGtMhX6=zQqN8<6>0iL%6(}{ps!_Rps -viRSLd6|NFNW55E2H4`&YsgAe6{AiO{LlL_L@U*G-m`W4h4`8(h6-1F^Ue{1}_^yMm*m0>AzlKc;S$# -PW|kp_nAVLTsAVlO-Nvc|M^7ts=cp$-uy(FIn{SzMOhOVE5lQwXxrCo!%DrVIcPnN(2}lwvkDCl-DWV -Npk&78Y5+0owep|FH^y`ljC3FyqODzzscAT5uU3dZ4C(ZVn>3>~G{;Rk;ALbtOl$;UY&(IWQobNEBiY -OO%C&*>+tIWpfLWFwgQp*Q=|6SoZ?n4t+YOd3bXkFx7RlVrN+-w7tm^H -&t#0hK?PDy(uy%dCe8jofIcab;_^(fQWvyP!V*MT;$Qb;73te{vj4(jo%$6WWv2_=jogdhsoQrZKCk6 -NV_l(3MiJ!&5NgBDR{LM>6=V{hL@3Ds;KkFRl)iS1GiQXV>4AiB!3YbdIOOhfYghLg#XJKui$Eq{1QM -S#wuMKYU^+LQ1$&7;i)RmOdtD7^p`!bb-`4nhM6f20YklvqF{*slqI+v4aNhY=)gc@-ag|ATMxZA1Ri -9#SANX@bF6C70>ZbJ)DYXMmqfSNzT7Y26!qP61c~`yXJbIOWcyW8p1I*xY!r7u>*alYwp~>;OYNf{o+ -I!yo&Xt86iwM2ry>;SW|JqUjCou5kTr{FblyhjY@3FRWidFCpzO1seFRAB*u7{TipM){n4tql> -(BuNZGEw_lk}=%Dbj26VBsmd=;qb?P)c4%p -}}(0H}F*S!A$EC1aSC{-9mX>@Dq7{B&;8R6RT1TS2^32{LTWvT;1~6cu2_kI7ij(LhZtZsR8PFX}x*g -qwxkPV5XW;@YFsh2f?|?;t!rl6UGk$XtZWo!rNC3<5qla)ut=KWa2Yyu)>k9zMJ(*aoV=KTT-{dxRgX -2EMy`$Kxx64!wH?EhD`MN{V!#*q(4is(4i5-$4G-HLm7Zxrd36_{xmj$&X)w`;<)Mg0RcK2=#*4g)&P -z2|C%R28%zg5*Jn#uJnJEwarxMn8YnLyCL?U=w(nYvT;2bXhFou4_ntHTa+GdSU`ZLusiJlhnruMiWV -c83&bwkL>h&A1!c$DqJ{v7!CT^bU<`UP(VJ!9omqm3Y!!i*MwuN?iZE~2Lko!)d2tB@TPquD_A|M$ZO -Uoy^Y4|rXk*${|KSE1XK|p}f2g1jHHo^d!tIABHADgpJ=xt(juM|iIF&7a!ntoqgPMF=yf!3ryO*kFQ -eqj}0rjC##g}a)P)}xFP|7!bvzQ1=Aup&h@Yx~is1)*pE(TvZMB*wDFn??+YV0jrc-;wQ{&!N-lCN7( -lnmH%Mi9f;%wjU2sV0GNi2yp+gLcYlmrU1CUBRqNFAFqIVPW8nK!7@sF;6(j><3Syk)jlF -r=QCg<1{Aal#a4^k|H>K_Wd6!Ga;r{8I&pVxdo(mhr4i)GY=vbiF)!z`qj@>`C0HmMd)&|>h^r0$N9k -WxhfvI|Ek0Z}3#rdEFrj8XDAL8II(-7ux8ni$X7msW%Zq%P5U-Fy@MmEYq59(-4VqNT9j6x&|EGsMg>$|1V%f81kG+a^j#D!nK1H|)$(wni-R(=hTw$Y{KlaaKSfHt$b0BK5cws^Rik$cuM7@Y6!Uu=Z724Gv1^ -nh6%dq7p1g_WKp>pXCbeDBt3Tu8@q7rB+r#a%GIKl!Hg(NL=g -3tqO1Z}IgW1&7safMry?5t@JOV%ss&tP5EdAMl>_G<`2dJQxdJ~f$4TPYcWab}4#B>}5U8jC5QTC&@| -RM5kdae}lR28Q6gpCYOo9A50C_u)uLXq$=BpvDN%I97UX2mVaX%s*v4L6x3o#?RTf5Ogt5FqB5TL6Tw -IqLFFOfRB%LGVEB=y*}moBm;%6Qp^V@7e!kpE=M0RBJdqGc(Gi7LPlNHiiX2e;E0xq!%&Zfc$zvKAFA -24HAj_^~e1&HK&yV|id>pj?iz8luK!ui?z-tTP_T5F@3Gkod4P1boW -mi>V+%QG65REl*#QAFx~8+>k&F^!O;gYp7f`ef_s5PhY=%X3ieMu`xaL#K_f%nl?8lSKC^yYQ{3w=@D -r3Bp)=`i!5T%7nt{Ua6l(pb!m%Bm^3oRH2mA?8_*k`zc_w(^31J6Zp<+Fa7ZEurP1Ot@P8|^O2Bpoos -{q|S{zXQ^ofSCJ)HP_kwgzv0gC`e=P}+gzAUA$vEjvREj}(gF;`*BFgr<6#mmJwnI<6MWfN#lUX-jo) -<0sy2AwgAa)JuvJW0`2iE1VLIHvTOTI#VgBe;$=k$y5mM2O1C=vu6l@a4$ez=&wUo=E%yAEPp$0t!lu -y~B@#!Jy%kM*p@1c~qCOBLm6^LE%iEq8HazDa15})g{u-QH~3|aF>!!(&HzmT?M406e9=ML@d;JRmEa -0TDH&DfmO?O>q1OZ`>Rmfx!c&D^DqS^+7tD`PQ?xk>>@!01pS@Cj9z7g -uB{DDh)C2Gy!6TTzl2lLXZy@GkL(2O^SmVHy3TSAhx7RJTCaZUZ0>dks2_`9+phxXKmfu$Ed-eHqWLJ -1eTn((;(JBZeC2;#w|`2sD>6ZhV>!9Fki-g}KfuwJv9o-BYb+0ag4p#1R0!H1BJE&3f8ZO%5-LKg9tg -`f4j;!u1RE#9!7%{3?c>D8n<3bWX;EHn0>yqXi2ZK+?$CTP$05&23%RjH=@P{TZdKDwkRL~62hErQ6SQ6ad~A-YbNE9QA}^ktUYV@$RW{FwK4~4lLe$ceRcNk_{EEpxA^7 -km*cl5^ji8F93#-Z^40w3Ui~)O|8-Q|WCw^(%bR@O1lIHqAA0vD;k^mzaLo`;ASUl_&9?)~Gwc5>Qa( -g?NW%<*SNf&QLx@(Lx4@FSr{(S&-f|qu8d5_yN?$a`){Z&Q(F&;E_WIQI(UN!ZB{sKPE3U0@5QFx8wg -9&)s$MAF>!ex}(H6`gn}{~{{2LhyBp%z^3h>$SN;+5y>y*F~x-i8?D^;B)e+cupk|+P@H@UsV$QzhPl -?m%wh`c0V3c`%2bxA83PdBehCW*18ue>D&+44%iOv=V0KLWY%zT{v`SlLEU4>roQ!k6Nb{WBm)uw7Hc -%brvj?02pjp+UT+Qh9_~FA%JW#EKLXL-L?W0jUH#=gO7^JV1>tGCsJz#(6l#NbP_RiI_iw95NSEGMD5 -IDU*5+@NgeIwmFLown1vyM(k}6VLb^NuSqvP;{Lc)G9bY$#?2BBS7;V^LvR6GAS#ZrXmCpD?V@bG!tu -u4HyLs+D!{8cxE;su3#d$dE?SlSea_T6V2{jdT?RGNOiKf#3Yx|#)a -N4P(3P}M0Sx>2M#Jj!Oqz?xI7I4jtgUOr>M$QEP94`%gr2M8x*V>an2s>i6*=-BPXTwdxZ}M8B4Rvzj -7RN>lrT$EzrrS9_?b0Y(`qT8i&Sj9C<;Jrwvyi`8OjZ24HA+~x$zq?(yYu_*H!a4LH$22m5i`kH|vW8 -=@Mct0fUM=W|6C^%FDxt4=U8RniG$KwYecrH -{?iVneJvBtt5RummGnLHLXdk;mzHrHaW~X2kD1Y;6ovZ-mE8Sb-%LpcN5G0*KOT#7;qcE0jmj1Y{5rB -wU1>LL#O2u2=wW_?>W&*4T&A$SM`!xGR7d(| -oNDjguAK=j?bKr!US~nP##e;rG$EFTHI@48rG)@$yKy`!7KYq;Qh`I)k{1(XL<5+4fcFP|>qV?h9M_c -w9>PE4OiUn#AG=)R?-Ow^=`oZr!v)QQ2FHJ>5;b#?8uR)~n5i4W7#;zf@>i2Pj0rP7uz5jHkW*uR+E> -f*08HparhT^{#Vtd0Oeb#F$)?Q1a@lE2Ht-Z}Q5zS^;o};52n74FU5u2f-&LGf@1M&#oO&(%}NtZTo)DShoD_=*uZOG8?P{GOZC;-X8ROH#Lh35OSb9w(f+{AqPkkOrE~DYMzD@yFps%Y -mrb5Ac)L5=SjBK~vYwzs4xS&4rc{HuxyQ?)BRP7?;e(qzDBIfRIeK-TUvOc&*Tnew^mBWj)?SO&nJ=2 -c&PvAQwkz?Nk8bejob@0eLY)`6)H=|lxA&Aei1)fb$#U-q4Hv -$yk7uk)Nt-i6rWgsi1Y4ZGnsv>7eTL(g>{g+J}EW-mpWP~ygRV1Ty&@{Gf_$;&HnkSe_0~XG&C-~WR{ -{THi~UZi6fT~cA?QEc9Q*%hUx^+HxKbo~V@b7ch+s#%LwnKD}xVx-I$1UAQM -ivjdKf>T4ZAvXJKk?X~ei!|Fr4+sS|riq9i0_%y%{AxSQ?<@vz{yS1t!sL38t5Ed?zT%-r3u8>QL1e+ -%%1vC>gY<0x6}Ka$0js&V8{HO!~63@TLC9=O3rn)^rV-NMnZj<;(^*$q7_7S -KTgSsliVdbtL(u3?i7z_eN|&*gH9DNsXRH$M$Dv?%mdfiS#o?4@Hy-y+Mnb4ZGzV`A8MB^_}v&wWyN -H9BMxitL?#PI#eC$8T=jZl+12B`;UG+^m4R~m$bv&0x$)^QKY*I1NEk}t+Z6x|ZK%3*Mc -{T~;Xb(N93t$SUB8_JehNydwAA9>h47~s2?S0;V{(QYW(4Njsm`E!4puxgsfqj9r5~)C3HfCCGBnSO) -rYMsgWt3Q_8Q@bpiZumv^w-*%gU{v*y?Q|A!d~w8todfAH6&R6`O^kSn -1BCZohhk>@RP8U>)rE>ndq*wZ+f+4c!HER^n`%%KYl2NI;(Rh*Y(izBfBJ6uPkp8ZI5P&$PI|A`ABG4 -Zz_Dj*Q$+C4(s$L%zlX=-Q*=zpPnISmbAjedX+E{86wzTDOKBo?6BUt4WZ=ya;9_)O4rYWAMh&Gj?eV -U?ITV){%R5t&l^aPZ%tmm;!Xu&PF&caIkpdQ36VqtMy4%1u^4N}@Pv)M?i;_COuv?%L3>I}3L-XqM?R -H=q;6X}Q6thdp;Z8A~RV`?6~|cf5D(PDB$|zQP7W%)W0}0#O6gj^2i&vk3?twHV9^^SxwD?@wkq+Ghc0HqXZ_OHkSHSW@h-K|l**Kup})iJWIo0K*?tWBX&fa1Nn -2(!fp+)HMY2{az~`EslaW4fa1X(4q^VJQT<+qA8k*|YxsNV5nLQrQqM+22@`CfN$iPhrZ3`48=Qp9sy4jBaR --n5eT?_lY?5U`7cEZp#Tvo_zkO&J&`eCR8u`TK~EX_aA4kUwIA2*^*IgK3l^$o6$@PUL{3a3m?OTrBJ`mD=(L7XG!`(zsxAR^7O4+WYw4qpSY~wbYa9 -;-%uIq?HL$ABB!Qw0v&0FIUCY6|Pwq9woJS|(G=3y-_Y|eZ5$Urz$2}qMUW -QY6)>VZjeqs=YIjnD5QIib-<_Mz(E7Qk*j2CY*j%5bm4;d?h)&LGAh?`&?zqnsxmpLFU#NuD8~RAwCC -F6+t=@2fby6qF#3bJ1bJ4lKoNO-PZeWF0=#iQc&{gPK~WJsU--7qCI(IFIrQHiMH0^Vib&1~OpU9dn` -{m>sSY8tQ48y4KR(j$&_+p~hB+_)=_Jsf-onP}7O@VgF)#TT*w2br!qQ8qt=T(0yB#`ABs^)aG8aS%g{{=Q1kUPNzp~(%$SB(z=g%UDuhtRszxw -CkO=iqH~O0h&3`#?eMnHS$=$%MnmVe!Z4<>W0!vL? -Q?ss2P0s+FZZ&DuP%$DTk!%)!BiKJEF`I9k+;@}|G&%xTnFKFTQ^Sr^6umn-feK!I3T!94q=_<%S`pO -Z5Xb5)3m+)b+dG?jk|stTcHjkmt-MMm2c0yj!G=?kcL=F8U&(>DDS#SsMTQPnn4VV?`mX_{oe7W&RoO -o(_WwsY8ZIJ-K^1J+rtC@GE#t!V>fR?+CW*Fu&b}#O?f3{GeUwJS(Ez0?77U0j;*Xy*`$A6#%%U%L;E -cNL>4qy;f -Mqh($KVpa_<`%oGirF8XOWT>AC^a$eq9GBB~}g`EEMN>KsdfNhMe*O)Njn5s6gQ%Z43j^2jBaVq&?e? -N-yH=)`!C;@Btkk@18s}(WZvf*;N|Q_FYYmRb1Vdvhk{JF3&7@*uBvpsx5ftC8m#M?*}H5!)onu1k$m -B72*P4pVDoxtUFKv8t6u>9?o@m0S5CJ1B!6y=z<(o^(&yHsV}d7b7ZJ#`u6~#c*f_bWy&hwxXZ7u>An -SynZTuNuhiJfO_6(T?n-W~YQtUuxIEZ%qC@~%Hw@ZZX8U|j=aqu;cfM>*WeCH|@dU;-x^w*~baffkV} -jz4i}XIk`x|Q&uH$~iMOsg|KX!^~h(@nBVI3pW*~V<62UlJn*)g&fGc(y5*GD==gG;RijA(BLP_x6WS -V1D9SfL(SKA!(ivIF|pdC7mBm(=k7(dQ+1ymzmkz1C;-X<{U7p8MC~LDk;IXPY)Z*L2%6O>O>eKxM!ruUF37k2jdzd!WKY%cRXlpLcShBAQzh$oo@hyu1I_tgbBu0Q-n_x&Eq7EqA<)?-ZvO_jpaB -_IC1#wcRaoznKDA))hskx8Wkfi5k{6YFIiSk$0-O06)1I3NGXH5?9p8zwlaEC=8ORVTRLTl(kg$wd6v -bA<<{rTx(_*Qe$MPGoH6^O&X;X)wrt(GvfG|1yIr*9W+CRk;~d#mXUP88^J5)n$4LL?+s}EwJI^NQjx -N}Efy#nRD!w+&&U*sGq68S7GM8n>W*!ezQ@BGi_LlJ~q_icfIe8GJhStcdBU6rWVoOeFGe+XXMSYFUA -(;fO#mdScBlAe@vP_VkFuETaigUOY=lL3y*=$j}RB -s)_kBVGwgvJd}H}t#&;4v -=fRWQVv;JH}&Q}f8ITP_53yE)RgTxf%XHGol+$n8OfVO&=>e&jUzIEtF5N3#dB69mCyu>+9Sbipa-K- -)*c7NGMi@$xS_ImbPd+^$*;{uTx+v;q|oKtpxk$PBM0MkP+f|z#uG;A!9EU;lRo(L=+8NxwnfJvZmmk -*T2Wp`3G6)a9(enQ=AFr%VH5xfFYcmDlbax|0&!(ahsjov2lZ9MpqrVSLPDg&8(`d~BnPU?IncCCJ>@ -7u#vkTSN@s9p37+SrEMt!z?G4sy3%=s-dw4g4n?n-Ct}Zj^eBz!Ou9C*3-4dXqlN`>=^Rhl;wxKkU?Z -~@R6f#2z^@#sC>NH6!$3gQ3-HmdupzB)ubVrc>zY?VMCP*>r9+?At>+~qbR$ars#SZ6pZrkzc-nzR=x6i}ZaZ;}GQcG|j1Kck2fYvnXO}>ilnteWXnS4(U;d$)w+Hgg3QPpHPonWi6IfSV9|~xuwTL?vdP~i0d~CO$pmBHXgwEYdY8#omO3K{DXPA!saCtSm#c -^PKI9Tb3=lCuYVfU7>(4f&j*)es)EGtDYb(wW~#IrMON)fSdZRnDVn3g`St*c79X^?J+^;k5s`pa6~i -iLXY9P6}#s+psLvK;lgZbi|OvTx3Dy>^!Lc2P%m^@a@Z&RO1oP$xT=1Y2Kk^En}daPbT`IiPeC4ri_0 -DJt2B%YY6ey#$6B>-nyDC_!^eQTn1|Wdh# -|pd;k3T>0cz>=JBTtDP8}d{a#43d6H5FdYIH8$b(jpG3-Nkz5Sv5XWyizPRXtA@sJzIb83>~oeBKlqE -1=`9X0PtrC}q9J4C~EgqQ%kkj#d_IYbWzx7`dQOfPc}sZV2OpLX22t=~ -V*Cql{scWl(9L)f`|fbw56I!7p^|sF92u90TdEZC3*Kd0$-%XLN4&Ue2&sKtp1LCj)adVi`hjk?%*W0 -%*AkSb=`?PgNbiIPe?I^8L-fO=O(B2R3mQNIsI7rw$qf+R0w~(jXWIaUPh6)a40mRe))r}klRR#tiR8D8o{HcFI~ -2i;08Lk2bt4u;ZBnh*DHP)jY|P^TG*riVODCjxsY((#H@Db^h{eyYV+GBj^+sc*Mbv@i#G3mPK*SmwZAyq? -(#g-vjh+w060@Z}J-noyJhnwYhaK1w40QB?5rmH)@|zX7?w=W_Q_imKk#;QyY!e);D3-RYATC(*m(pU -*g@LUT*Qd!3p61J`e#_>hiceeb*89je@>+EOh`QkbJjNHzc+@ef>Tz@rz_6_#F7`50}{w2Eu>o4nP!& -5nE9<(=(T_v?XgUv_BSbIAKtzIO%MtBUtcb8c_oj -*Zo@DPL+=6d4}{NKhOM{#K@S7=2ZLiPjW$OvEO|x#zG`zL1(DzjA$--`3n@~)GG#2SZus79t%4KOqU6 -{z3ePPzCVjzD8(55*#DcDbDrKL>VI0nq`JZ$5dn!@YTRo1YOERwFu93&P-&l}8rk^>cziVwaZLDbm&f -Y7T@;G#j7XmA+B9>d+6}&xOVJpi;;R$td3_eZohp;sowkOi38ybhXbFo*JH?`~(sPiu+Q{1=|%=94eI -m@xjF+vFAa0gIJ0|XQR000O8NLB_@O-%0I*8u(^baA|NaUv_0~WN&gWWNCABY-wUIUt(cn -YjAIJbT4gbb7L-Wd4*HairX*{d^h+X79WS5HZkozm4iI=ObUULE0^@C6rsrLM6DtjY2C(uU&*n3ZbGR -rSYFMHW>)eYEZ!_Ym{RJ)BQ#VkK7>jf-T4O!Q@2(gjs#gTgNJwTA7FPx_|nqRXxN&HeshcP$uzp;B#q -7kYl{e<*TrhHUFCEp;JSq3d9!<2KYiUjzidM>?{-L%pBRmVN3DzB8Wv#J2x5VlepVcj^q{6vh-ZzIOW8IsvSg|Dfp(OCVj^dQuxvJ)?&R=Vk4u -NJYwJt$EWvZ_kL3~}+yw7o4%!ghy9Dn4CSMQoGOvxw84GWJ-{R;GP)h>@6aWAK2mnY{22*|C|E+@@00 -3ua001Wd003}la4%nWWo~3|axY|Qb98KJVlQ7}VPk7>Z*p`mb7*yRX>2ZVdEGo~kK0C)-vi`7bTlwTd -1bCWcL?qr%pDv*aK>(8!;eiagMo&US{i03Qp<eWw@nz6GVZf_98lGt5cU0v_0=81Z6|AAUn ->%81PR$aS!@Nf9b*I%8$f9h$qKh*j5s#VF;nL2&==v2MC((3i0y{by}w%W8eS*_KJsw>x7n^$Fuv)*d -0{`&Ii^B>JR+vmC@7uh{+k@J4S!e37~4>X|0>8t5+JAxmK`L1;5s6r`rs+kS -W;L57~+U0(SUMzS~!ItE$F+Y!2S%Hfz8BYExG`7?JL?_Dac#r32(X>@n6 -q+$kv*pT6f0`9Vwk-75U+Ir4y>Hb^`u%xbSM|vB{#5xv*L7J5mZ=%lW;GHNx9BjEXUk8g{C)BLFQ<#Q -?_a-u_2%94XX;G7tGi<;^~S%*iY8iv(AeLs&0<^K?r+L$cLb~%0sw!k${~2$dhfy8*0;i=As)QN0;sl -Fz%S<$yY|^9vz{AKvcuD$j}+u$253f_e -T?uk7GmcC8mI8w3TmWWFwdw}IE1cz&(7dDH4T8i%vHa`a&c1DEN_eYU!Gt9X!uNAX;5k!Tz~qaVBt<= -e8V^#WuFCX~(O0#9jGWKE-p2+8yELtaxAz -}CJpEU1Yh+-^f{;4Gxeto`S}TA6>RBNWWTyTDfJ+-dK)^)69FHD5xmk7_Kn-W7NbrOan7IM@hR?d&JP -xEyEn)n%`w7=cZ|c0&35=bYjV>A>3L=%zE@6<_)Cn5GylkuHYOdaw`NvdD#713Z4M=63h{c<$sev+`d -04pPFn_gfySg-%GVQPJhRd0~dh4H91jiZ|#`j54h&kUES&O=*d8}4fdUZ`s1+J!WT@*Umi~uq_NkQf8 -R#~I%4`Rg;!`V!oorQSZIt}+Uo5ft!qct$V(~yCLU3})qkDV562E|L13z3A;u+m~6_s9^i>Wg{*cJ%tvV`VDA;kGqSS&2+|!6XO(Ut!>RY+q5J -pKRfc|7)wRM0zRqp_6E<9}u65hMzVwHD1&(8y&O$&yWZX*ncJcDJbmZ%`lzegY1^%tiqAsXj=t;isVm&rLM{K&62S1}~ -OEkSuVSWuJ#h&+Gw`o~xAFo*y&(R{~32cS|KtiCzp*d}#zMy1qeq2me|N#kT8nXLB2BFG=J)QB&Jnrq -#(dC9KJE<2!Cl)2c{4)w*y7>K-qaY>}W*M{wA$gfo{LT`Rqf{8(W!q$lA^=*p#J(PBz0H?Q8Ad)1c!h -?TSLWC;A5F&~&lKbY9N0S$lO#tf&qyX<1_tv2o3p{P&x@0D>z);nI767q(el0NB8Z`Rvoi0}zLy2usE -gv-Pp&+k>2JsYH3N1FR1DXk>sp!^hxEo7Ea^K=Tus?>hX?%k6u=Ro-V2pd=d4?dMG9L}U0ToND4oe{s -!Bds7St+R3qaJGvOo*%P7097{-`hbf&Y(Yj!5JWiu7=Vur+ad`rL3}Trik#b=2{V)t7oNY=80vq>n_Q0CDcd>6HKa -f;Lm+aR41(7)+&4#!&5DKr!j^G3nje&Rry$I>SlzImQV;$kRDou~+Z>O?w*+?MwNo7;2m;t}q8KP1U6 -q`bRyu?Icsd3TD{q`6w6Y600V6HU!mQkD4d;xh8e}C)^$1>bg;^q(t6Ew~8$A6$p^h*C12!^-rc10@# -R5XxLiwdFm~k!}_Z=EzS3RC`QA2KA4a5kkjaKT2apvzn_lZsmP4L;989OZ7_eT^#K?oQ`|ktUMG0;B#O_S_qABFup -$=^8lil2Y?BMWkkZT=Vmtp;096_=I_KXhp`COpyguo#C#h)K7cARl_3RLzD983IB(44j9`R+{ZkEbru -@ncCO-->a3tj9yfmB^KV>236bTw)PR0(e=IIx6Dr5B2MK63fa_+wG7(jJCr12gj$FaBU;1QmvpS)f6Q -b8nPUFm885nay%QNuKpTPIO>~!KFp8Yogu~js3;;#Zv5JjEHOW{0WsGkC59BG!9z@#1+>8L6la -YDNox%nL63(?FE=4*q%)YVxiL=Y^^3jv&Z(I>Y5UUCA!Ztf8{$WRhQETdDmdFsqa|!Iu7XNXz$6^xod -RPlFv)>MJZu@j0is31Iu#8EuauxsS3QbH8I?*3}^np94uUcYPu6+kX7q -7egCeVS-l}5(|gOWuTguImChxwKSk6m)%yKJo@(Ae;+`>XpLm@lnbE9Zz3;J-u0v8$)L*d6SlJHa1V1 -~$nc;ez0d6|qPI1~T%Kg8tE##-;X#~z2|ZQg0fuB9@MDRt!FJ%G9^a1@nIn5S=5}tnq8RcCU1sa3Qz$ -8VM1*Tn0&Zrq^gW|AupJN3!+_^(ZRpv{H_1>@NK~jMguiyK-A{rYN%{b4-YE+`oYU2fMK9e9!u~1$kvJy2!9{4TrX`HOw~ow -i5_#y9S-1thmVz4K@RD?jUPWvUYpGyKGHzM@$6D8FHgDi`p&6u88w&HqX$vp}W6MPe35`F1OHt=7I8Oi#eN1GRs$>BZE^9QWP~uyE9ci>Ma8Cf%xML?rGc#|zva<7p1jvJW;!JxB5RVB2axtO9O+JcpaaDTx1SvJw%kuyEQShG -5m6*QH*f|$9@E6}EEbgMy=EG*J+>8CU}H+#+hjC$)I}KzvSVcNESXi|;pk!Zwk1B4C^x5PXm{9h1R~q -$VnaWqy;c<;Zde*Jd-Li;*svNO>dwqKZic-=X+$)Sv|VX3Nv@}AoFpjhXUcCXlI$iil;1UEg^5}T>s1 -PRs=-huFeZNI1%UpOV@h}$fWY>z+dv=|Lm)XFu0#sTx{1BWK~UnJy*|%N_3F%mOgw){SpF~i5c9m9=HTWVTM8RY-U=c-=KS;`pqSrMNF?fxk -f>ChPb07v^&pA36Z#)YA_Dn;fJD^P3>>zE=qf>7x?tCoK9UEC{uuyj&L-PW`F=82V3(Fvqt70KoYjX# --IegMuYW*RZ@?Xu0x|KQd@ic(R`)U*PeI}-i;?WX0Om`o{_@g#J;UaCcFHL4hOwY4Yq=QG-Zl4gh}5AMYpW`zt=A -Npxazj-@}i}p9-ijDu0DVxx0V`~csdR+fn{)h^(U+(b?v@u9ofu4?v9(IJgMnpAp583oY`DWr -@!-fGj;)p1cLz?9Akwgyd>dwTZJp0Pl*Ml7XS@Do=)9Jf309x%HvF^Lw#9trN-?9=(nvia8aoyr`g}b -fQKrHwoL9SeHL{CrI#GF5Aaur>U{)z$;ZECMQ1uCm)ROZI`~dlI_aR(^O5Ge0tA0DB;WEkajEvl>bHl -#Pg0(k7+9{^)!cNDY=dP&;K3=fATp!Bj}$be1v7_(pM`Kh&ONUXzLC@AuQKzvV4!B>0g60kR#GGS75{ -iZN+I=Rg~|&B`5xZR@Sz4k$t_@=*>Cc*)x&VQVJy1@#oVm1?beQB>ti~7YQcbJkd>x(8L)>yP-{3z<; -WJc?h(2jq=W1{ZfxgS^cbL1f;S{8!WgHh%t?7A`2Wab;T}&53i$3$;CYYT82HYl!f@|BlPaSkuIisDQ -uoZ<_)4jp*k?;@EB+t!z3=r@kokOZH0cJj(rmp>oSo*5urvP@JP2T&fM157tRUXhu8b}F^pUmB0;XV5 -EH%hku>ck5Ef3!oMz1>`L5dj0PY7DQxPu(?z(BhCg)e2O(_gs#mCNvqk*eb3DA_KMKpBnTvKN;8MP4EcccAUU6~E9LNs31|p=;fN>yhW=t7Id3 -thFh){f(zyYJ5C-w@^5zOmPJ5%l^_@^U1Jm5VCToAbJ%cG)R+Gq@kO9IyP(eknCtj2l*?k2k@+vC@x~hLGSdNQua@P -T6ujWBN&i;HuWMy`wvFnSEi_?Rsa@K46oziKO!I;?Yc|h0C{H*8E!$!4mW(bu2lJBwmB?+NUZjNE#{y -g8~%tCzmdhzV}i@!dBXeq!7|D-6xWg3x}W^RKz>Q@GCyvd4ddn`i*e2`FJ8QQ^TU&O -Z!t)gl*aZG##@h75~P6U>OAoyLXN0s7jsUTOflJ!)ep#?%;qNLayL*MGZQTSI0%eEsat@Ny}h7Y>@G= -UlN}Bk=L0M>;ctM3bJ5NP!zpDjmM(~Cc`p0LB*0yFe!Dylk;XVF11}s%1~b2=J=yDlO5UG~tS-@6MXE}a-j%m&T)ESs>a92<-H>Xqx~l8ULli(pa!mNX_gYB1phDL!6mZ^wMAz^r5# -jG@U*lR=iZgo-^sY`zP&9I0OKp=-wxL+kY#y7M>hb?M*ves|bQK5dHb`n|@yT|kt+Ar40PQG08DL5J5 -|C3FgNlHu9Wb-mq`TCeF`=o+9oW|J+WD-I&fdFfFhYCVsT;u$eU7$|^&F^^~Jo3qowg6c4)GL758z+} -LW3!e#HDypY%aTqDvA^D7z56k)JOICuC&{`KGtJ%g8@6|7UbZGdvuBsN@9MKZS>yfW6avaeAUM%@#^% -76r@Ow_SDfx#O&}FsD!}~GgkP^!M7=5mGdD)>dJIE#<(9Qmhxi4l@|KF)853o=}?e|zw&1|D2&Oh=~Wo-w1|PR4dS%{3GrI^9A-5T*9kfN2T1S^Kf%Jp;DDwW?6y%ED^d -yZBIjHPDg=bVEJMAoP^$0}a2x^FU&=he-c0|PJ>@Hufx)(~Ut4$$3WzO` -OEF)v -cjf#e+`r6L)RQOzV5G3$sKb2gJr7-SFHUvwP57p>F9~n#TdTe}oC$nmYv_6|hTt_8-v}?thkprz9KLf -f5a7K3@%59ZfBD1l&4S*+WQZvxhQ!~>kPqcM7dRiU>tytHzs5#P5(|_H33%#ElVjwOTMU>Vk_D3x_c(tKXem2V@*0Td1sX5xQB)=MrD==`VQ>A5m%zlX`HZ>mm1AAR=cv8q -@?OFzftqw1MwFV|YbMih8f(w+HE;;(o^pqMrzGGp8t})9S)2*~V-b_TITQDq_8fP`dFu755 -5LNAKupKu_oJk^TWrsZ$Duu4jlVn=++R8jGV^PFT?k)&du9OMb(gTHv!)?HXx?jlsCP7_sxe}cXH1*!?^-Gg$8D_S!cLR<_+sp1 -r4onE3nRjpHWdKafL|uf?9@rSJoeMBCmXrGr?~2s_0t2;?&T!))It)uFIyW#PhqJvres&UK{xI&-9u$ -HBHm0xz9Iv58u2{AbbXZ@B&tJo5JH82sC)feUZ1cTK|=eNPPzM87ucCl|c-HCmd`8J)$xAG62WD{vW+ -mjn1Cm;u@UOK=lsa`AS_{jFG(du|ID3q98$#A|b9kw7_5kmYZw~dP9#<2O`|DxG$;*`Wi)A(C(^HVEC -W0D{T9T{#kxH{bB_J^Q+~raTi>42BLAykat;qo7xE}6et6)6i9*KP-!sK6JuDXvPdIaIyqn2Z(( -gn7GMXpF}TmC>C=|a2VXc7}grpMiCFgtJXwid_nY(=~u{L32Q8{3B^T1p1I<+x-ZGVWY;FP^Y6J`lt7 -M*BKoXo8p+??x!6#yw!-2{a}*u)gK?!%bDwtH_<#=I(czJzF$vfyNIdeE1D(l4BtV4?RXHFc@6aWAK2mnY{22=gq|CZ*p`mb9r-PZ*FF3XD(xAXYH0vkDEXYhVMxH2TOZxgS7XadaBezrEO19ga$BSv}BCN!!{_ -|{`Ptn8j|o4=-#ScqKwC{-|>S7v8{;pF|I7;`nU^&2lz}T*ZbNkr^!I3EvAmFM&1BC(E)*Sa0N0#>R0 -Tn()+>z)vnv}Rno4CB&1eXPQ>2}Y(PmQCky&em3TnowAp(Nko;J9QC6#@ME(GV960i|5`>yD>&{X(pb -cy-GSxQ4xTN&$sJz>Rfwz@3_yiHUGz>E3RJX3#MqG%07?e7>2+Ar9*eQoyP!8d3f3O_rkIflGBXV&pC -Gl6ZdHWlkGA$T%Qu}jkj5^?J82Fl*)Rx3kq8MMjQB*aqAakmk_ysLXddvk`C;3&WT(9t}MJhqO*d$`@ -@MERYXSGLeEm!&77SJXw>kNDME-+c(q!OK%YR_H67X|tgtSRCj@Y&u&-?jr?$ZYQB9>Fc}k^O13SLlY -Dcd!gvA5Us84)+O(He(GNH`3@=Kh$F#wi~ytNpxm7CUXWod}#v{9iDdwtv$7YvG#}`|MmWc(<<*fyZ) -uISk>cMCYfRPcLgrc^#$(T`zx-!?CM&a!`;=0eP9CZw}FqLjOMV;D8`UZr7yy{R6L4uQam=Iy=*Y1*E -ri(>kQHV!}^Y4B|gTvm5+y?WS^H&Uc&S)!Iiw$&{+xLH&9Ch1QY-O00;m`Rt8gOD*N5s9smINYXAT$0 -001RX>c!Jc4cm4Z*nhWX>)XJX<{#5Vqs%zaBp&SFLQZwV{dL|X=g5QdEGtzciT3SzvsRD4_GOAq!Niv -oYa?d>-IU0)A}}v{VX@lp6yd839=YdB$pulvAy2kelr7r1V~VJ+V0(ZtEP!e0)qiC-!p*wZ1iNrX6Za -iF1A@&EJm;J$-@VI_`~+n>^6@smId?o25j@$^G$ZL_0K1V$76gL&x%n2fkl0}-YBy?#1@WI0e(J -D*x0ZQT>?KUvpl46}Rwsk*6zoA7o*%Wa>p0=JO~YLfbIL=MNtg`R(?@2Mj*d0Eh@Q6g+?UfZxn`R -z0IG#+{4m*`Sy$fDUWV^|7vWQ}yge&e1+i$PJyyLO3p0C17j&R(- -aGtFP6Kp10j~h?ou)uw=AJUFZu6QnBcdS=pw&W|`08MLA%@-e^%Y~Wq1)GR)!6$k*eEe&m7P#IR{N%h -S^Mu(gJ)>HjDwF!DF -Fe^&3O5S(vaXXMB|vw+t`{^NXv~XXk7Q)H3BfVY6kJT<|$@jAF7#XkcYRK!8(VHhILa;5#rQ;=-~#y~ -x8ALmb@`X&?^sf^C{z&wWIi)&m}4ceb;`dP&hEBzoCwT1N4_2W)7AJRQB-J`dvbn&wG9YnL^oC6R6sNN=?hOnclCvcgB7x#%Ek?cf>AZ}&0EmlZV8Su@@gy%5xvB? -mLtq~gl}CR&`RVY(4w^~}`$d$@QLO8B({Of)FFqWL31?um1@ -v&)5wvU_;6J_xQbx+u09trPk5GW>DXNY`W;X?K30p3_y2Et@`cXFzLNO5qtjEe9pgt3gJ)Dg9e%gP(K -Mruo7MU*w7Ohx2*yxJHCp82SpqHg0x|w7-sID7WB=z$$1@+aW9BX933tz&4PEj(8%Q?sXzlwYYeDK@G -fqFK$FA&soCLj>3U-+z;hJydL5qLy)=7wnUlax$Eso=sx(*g*N!)wz*Knk9G+&!Kg?;pK`wmA=G=_*6 -E%DuB+{nP*Y_58^XgR|e{n3Ae*GLSD5NyNgJ;4A6TqWOxr)s`=DLt!$Yt9?%avDQ~Tt1u6ug0F0OPjp#r=LqgE6ZK0zZfQYRyX%Gc~hh5XML_^EdrVO$cSsossw_5#UHz8 -Z9>fVilzJ*avrXIeC2C`8oMRlA(8(kt%R7QKjl5KY%i?mXD&jN~#v$|JM}1Ovi|5-=HHdT0$GTO;$T& -dz0SZH6(q8t@LAN3+7WC_!}@SZqL~nRDQr8IUzt>a%4!{nA`9sU?|y9bDvTnfcELt-YXzfMtb=W9gN) -sG6K&r*pfVYSS3-nT5KON}Mxp6I|ymS6m&4a_Uzrqqm-wI@`)?0E8P;(Eo-|&$zMD+z`(xpImK!B3&XIp9OXSra2sK~$~{6_dh -qlGeZeR_S|ui3EqtV#{{3p|xQ6Zpa#u1-};b?X{@vCnYEev9`aUsYDrhXjCOd%c_%5YZ)P@T%w(1Dor -(8y-+QQV#))>T(nR&MFE6*b!BjALanVn+y4}v>*h8WpZzfg(JNOG5)m3-gk`J)G!+5cuB_TC1JORoC) -HWo?no5W5{b>U;afAXEqn`oHLQ&$?mXJu6@DN=Cip<^x{@at!ti_2&p;)CIs*JnB>ReR5hD7hL`zSA* -@U@wH4aU(vwU0G&#=j^mtn!eX<8P{OT{K%5n<;Mcvqk}e{iiSh6jw1J0`Pxbo6HTWVbh9u(rMb=~+ai -7r{+H`mHIZyV_POf*rtFm%*l9HA591(@{Ude;(%7QDV+vk;B}s)BF-9Vv7#FD{qf?-|zo&c>LF%%??% -1wk_T<$+Z*hn5=8Uu%s2fr`XJI7Oio_Dk6EbhYL_(0}FZ -d<~AQTH2gdq1M6w(Ug0Dg|K&vL~RP|s0O1vyLER21k`rvRHJ{MrE6G>H1_m|uVi3APpIbLdMF38ssv> -*+EdgK{ETMR5pz&@IdjdJHuLvis6_u2zMjU$i!2poW`hKVy>LG(7d5e;SVdu{-+DbM^1D(Z5g5pAOE% -lO6cq51tG(G`=`(yfSjv;3DT3nSqs3X6Tq(>{eQEV`hJ$d9Nro~CTU?jk-l`CNw4IitP -#62PNzyUWpN6Yj8Gp!)DQLuqus9{X8#T=yhRS4n?@j_T=hZJa%C|Jc3=Ts{_KhF3pf+d} -W$|sd_vq+f?A4)LQq{$#cEyqwrf``Dbc%orNR2zH)ujt*$BpQ-hmrgbXn-8@&?0m@3^WuLmL -8G%A(RBCGGf>%@?x8z_3iar~oKYdwH!{sOTZC~;i5N-F)EiBVwQFHUC(fI))5fVqxm~NgU_Q3Av=OrU -0Mmor#wGSSeX)J+9Lp7fZcIfMN4Of$9Hg{)dY`SuPh+dP0Cx&h1F?$UDiqFJYU&PXwRm1TS#&KB?+z& -8qM&3O@#pCZb{^S`E4iKi;2b7ENIaGBI*CB3U23#uku2#`hksm6?^y0`wcMN&sc46gvIe -`Sy4IieB;0n+S4_waw!3}BEh?`4sED^(R#oPBNHQPsHdlEiE>QVK39w~U7pX}+$u-(G3e_+&z#fYpY^om1;xSDw7=px76CAPER=FU7=g#6F!!OyV9knVw>s;u#?y6)b}(~!$C{EWM-dR+p%vA@k6rrcFa9rf+dcR+ROwH2H?P6Sz95lA^}e_raggti4-5ucLU}z9$~m7EX%%K%BOWPP1Fq`$r`_ZIH=fi}_~>>0tSKy#H2H%9zT^$Lv%yg4}b%-rC;3wKq?dsa?kSkv9313^#p9yS>`TOVuJvgKbV)_(u!F;yhBg -4Dgfe8DJCZAGb{4j4wt&k}7(fCtAHZ3r8uPtIANUb>;c`;9XrjU~fH7%pi9nK8zkRY7LcLs7M$__!ey -r_lV;5X)F0rKkEQMu^=`TvuH6K292vMKkb)x#mW^*Wn7_9Q9tfr`R#gYLGgdg`+*Y!>o1a+_h$Ht;6q -S)UHj)QiEiMhMyrmoQChwo|(>ctXmDo>gu#x>$bMMZOBlU`Kr2N*=n^Arjgn_h~ZexP{v42F(fr4_7W -tL4AWF0A;YR7%?m#FjXGLgPdI4cP@ginKL%3OH^%R?o0}VuY83b1yXr+HNA3b5$ENtw5BsxrhJ=S*h^LIm-?b}^ -HB>Wf5|l(x<2KN#28ZyYm9z>~0QN8FWh7~($;D6)6q+^ws&PQiIzU(1M=IL_mNUOXzF9*RvJY7BKPS- -*n(#3H6%P}E`5zdk3JV$4$JOz@w$u7;1@D(AnWxu+j>)_aXY6ncH0)uzFz0C -T1aO9W{+nb5=aGD>C1b6LW}TO{3Oc*VapVZq!MAyz(0uPMyAs(*zZVQvgSHsC51wE1+pC8-NuB`iD@R -2ESzHkD%%xF>Y#DXA)Lbt?MpYH7?wHa7}|JE7lJ=L{R(z}-D2VhOs+?M2+9caqN2R&PAF_tbi@dENyJ ->wWICF35p(+xsj^eL6+MZ(1ApX`7Tbm?}<(Fw97sVdO|VbGIn+2%KxDt=YHwf(E=Lbv3QU1ZE0BK50o -Kf_r1-d1mCgSz4MDm@ZDmW~;EY>3W+(44eR+<&QO}wP5h0y83k+Xdzj&7u+^HMwfYtQL|0ZxW@9HjdDzO+xd{`_+9 -6cGHH7Oht-C?k4!*mcg*%>aPp+`gM7~A`D@7|UoQgCCBA2ED<^l?g#c=d<6OQNAYsDY|N$DNmN(Z|Yo -uV^~Mtq5}pVDhor9(C^@lb-blUyJP4M{=sn{bt3gchvb6`jNfcFM~{8kDf)$;b?8q6#))ks?GBVL|De -q7~y(duSiGL~Ua_N<{NbUr80PcI+H}+@9?0dM^Ddeg4?#(6*0o+x_J^5c4@@^3uXMqYB&DMF#HV9!=> -lJ2-?Z-QKV0#Moh6t81xa75$T{#igs(+678QXzCbLz;=ZI+r)T;11W$+K`uDeAcP4<*)^7$ii37H)uQ -3%%39z~#%TiS#3g -_TCCGKzZ2q$iTbO4VWAVh6`w_t^=W?{%#g#l?x9P=?SU5M^$nRSmelP&p|VEUAk^RwfZH1X#jSwoxz! -rH=yxb#_FmYNNahC5Ep1YWFf0f+gi@3T^=mGUquAJU7z6cAXq7`8rS;#;~AanIQvS^Eh_kt3O6j8kl+ -Y4|R;ct0+erKsz>z;GvcE&0+uW2uJP_g`A0}XV*{91P;mIFEjUf2L!JoEOz=|?5sF{avvZqY%xk|n}P -W0EE(91wSj}S0wtq>M)GJb-4C1-xcajK%M2yLL`_cGPs{?YYPX%_{o(Lre_Il{tUC-*Y8E+oD>K;Y=` -GvMGAiH%ru>8i{*7Dw_mN4+C4xQz)pHoDToIkT4U>y9yudTJkx*vvobrDzP~?t+5I}bus_gffcIM^IOr_2o2a#hK%6br~&=Db!WzzP1@_~`&TN(he5_b -7A5kC#AY@n81^(`R7SJ1@EgwAAbI*_@kBhdJ$-LtHq!}0I>i5nfUKVgZqj@{ -M;$tAI+J&Q+Fyz$v6jGqD7<*fpq2 --PHM@F9&41u6vjrY3SgCySXO;T0?(@~qFEz^5|PqUHk`Y0QJZP#-2^c1Z5GXBlt$)OC7xiU)z_w>?$j -Qh)}xl;>f=pFB^Z>E6y9F#j(P(nSHc)izFaJohab)g^AOKvS6h=UaN7@(g2(t}|NYj>lOf~9Y+%8PLMNyLSf!| -3S#4iz0&KvH>dgcjF-@^Zl|wrsVif;W!HBnbUk%l&Vc<{Jk5<9-q2@T)d#bsX-38tHRl)TfbvCRTsZhtrpmDhmD@Q&#jv?sT+K8!R`%uLlzmZF& -}6*JdK{>Q8I*v%ggFS#$urhxf@eK|ZyU3$M6M|0N3if{M)g`t$I@%-F2=0YH*z9>r=A&xFQhhKCuF^6m -fr9yG*(DXS3SgOvVyM09p_W&}%H=TQgY|Ga&~M0l9G7^I(4%B%{j&QNfh@i8rd!IS|UM*`$$P_5IF!O1>e&(5m}yMMg*oj8krEH7q7OOB+;ThNm^`tw0 -kV+=Z6;ku-;=ak_FAaCIW>+Rb$eg5@?Q8m{W=tnrJX{`#m)IrnhY{VxNu61W4l>>^_z{h;7=;TJ2p=D -XCtQnP~uQfLBRKoH5c|k30aO|DvMb)6H!&vfh_R81?C0Ai64LFNYqfej~lzu*uRXH%dLM<#;KV12v^J -T_*ki5^Sm|m+!Y;_WsgZeaGS}99)b4LXH;N*&+*6(12Dk@EWjN671~uqHzI9y&>wIIcPk|dE=f0@APa -QoIf?4Ug_*&TUFp_IUiw02?F;N8ABrEl&zDfKdES($?%=K^zm9*{vO(?MifQ%;G3@|A^#sXY -@+RjA>y44PzEjdw*UB;vRCyL*S@Pm?$MNAC{*_J04v$>e1B_{V*c^nw>Aq#_NZjgHwQWy`0S$%&>>92 -K`fm6UHH9lyc^hX^UZJqt0o)5vO9u^_=NQdMlFHiX0{9sxj~Sf*L8t8?|TcNf}*P?;?*R0VR&r7^ZSo -L$k;Pt{t+LAs#Zw0^B+IkpOb^m-O -)3nOgwBgeoN&}W#07d*dLG4uk}Cmy-+HpVpehPuyZV-Kit%=4=VRFZo4QO%QP)(m&qCvTitjbC)2HAG -Vzj|>t!vuS!Ww2zz{m6y)oB437AVBzGB$WOaO`>Su>Xh!Y6yX3duA5j*h_*wA$Van!FL<#Ck+1tvQpG_T>;Q6_%&TQvS1dcg1b%!-!q12(YzOUGK*cu6wQpTyq~EFp -)Z%Ya~tbDYsdq{OmbPXVqVLc8o5SSXSemdTdO&En~Iy((RZwU@Qvkoipw#eLLUr72cA3OCG#7UdU8jD -tU$3oFn_RO;~9!$q;$zc4{b~v?ZH<;<@>iQLT9$LrUQh`}?ae-)!9F>mD&$RA0hRHa`@qGUed4cxjOc#V0D$<5d%y>{0P -kxdTQP%sqW(KZsu{sGTIVee@_cB0Jjw4=H@!D0h8!>Px@$eIx@A`doW#!KoO}oRVb~^EnstRU?krBbt -4as+dh*64*#TvM8G&b|Og4ZmBn>^wu&qJ8*c_oDOp$#&V~1BH)psLRwOoxDt_u?O*m`L~b221GR94}Q -zyqTo;y0f>d9iu-2CA)IyJnO!qrk<{9%Y{J>!gZdIO(L%jv`Q;p>zUh$@IyBqocj9NMYR@e_N2;C^l< -d>iCCdEUEmf$kpy$EtciMcKE|)RKiN1SidBvN}}ilQ@b9$zT^>XtU}#q92HmuIuDD``~@EPTOhy+_3N -8?2e^kk0lPcLyCjs9$A0>j3rl~a(}ggQTb?!6gogLM$6}k&tqg>NY3Hd1XT@VdArH}`b_O!$g$bDGF; -hryA~4TDKcneoW=EiRgZ>!N1*jWqh#j*tMH(6Ub^S_rCLc=+Id0Z>Z=1QY-O00;m`Rt8heD>i}r -SpWb7bO8V;0001RX>c!Jc4cm4Z*nhWX>)XJX<{#5Vqs%zaBp&SFLYsYW@&6?E^v9>ef@XaHnQmNJ*WQ -zSH8KH5?O0GA5H!0zUw4T>Ql$gv7Jr2X`V_+w9Ji6>XKA!cf0@ln=gR)A|Vi^@lnG~Os=>VSNt2aq;m6m0iXHk@vQFNIU$@n&!6>(N2(|#0P6iE_A`9(CjjEh+UPpUkM; -_NnBBt@BL2qYg@ahj#sEQ+IO0$5`CsJaAzWqwgz$3=owrcqp$`6P`2ax~2+%c~@-;wohzI9z~0x4MMF -oinM|=}C*xG>PYcV}^jC#F+*hU8mJ$zN`=kbgwGX3Bv4S;mLeCMZ8p*Xr5lB+@`>hals~*Wzt6=*n@s -_l~27t8THEie1gG{q*y%L*Qr_;8YBP!aq0*Sv_zWIh)lDfWj)!a%ssLxBx0aPX^0MzZ9NUSH --{SObC7oy57hSQZ(e0E0&br|@5y1319qAIYTRr_|O(KA-2;&~e5jo2J;~a#tq(9LmJw{BuHGWs-`ryn -?PUZa8y{9g~Kxpb0y8|K{}I>?}GtjSgSG -IXXOe(T@&~pC7$_ad`YHik?B`PXHVsgG -Cu_1oG~O1AYt$>;n$_&(9A}j;WW=Pma$|;ddWK;`F=*@$T^K0J^+?dUysMKp-zqPoOOve5i+`dyJKj4 -;U6sj6H!+1b@Fh!>=@`gu{!2{Ud;QhV{+zOavDN5d3I#v8vw>GZlts|2YYxGm6paTQllTud(0&q+C;@>p#&`V8v}U;ymBsPiAE$>$V*{s+C4cM*Qz?e^f?!FC5 -L#Y^BA1=PXEn$P~c+}=(eA+POvytYU6roi5?7S;QY7w~Hrc=d3&wY{^o^EeuQv-@agcY7E;*ai+Bbzc -@~KZ55klQ9+RMgKuyCZEf6N^lU&;dIy7Qlh6%A3uF!L4C|n{~lez0BphFz!IA$SL0E*`uJ_`bg>_urpWcD(RqFiJT99KXvj9KUFndftF#}>9G17G{+`!gq3uflNQxrM^{*W~F}=38GRJx4_hJu;uZrSOBlSo__sRax+O5m7sS}6nP;fp$H5Cl!1Sb^NirY9##&@+pBq+ -eTsk@-lf?zzb=sofuR9~JsE6AMVywv;g0hPfWqJ=xJ44=ufLMIBW@K5YA@>USF%%3p?;`l&+Nm7YL{L -`-QmOGqaJKsz+J})HxKNV8R-OgZc@M|02l##jxO{0l(!9rbe23X5+J^_+pBR7o753t_ohfc0|m_z>=% -FI;y(5d0DTjgeov3+aeS4Sf3j>>|gnX*rT=@`B)ZJ| -bA?FObndt>F}^eAxaNeHT5nXMQvqFVlII;xdoRNPYljK-Y;~w0;N3<%Le -X4NI`+>0WgBp?caBsHGrlTU!~>A~}p(-%^|hIJpfl2^S*CV4T1O0SOJj$q$9d`|cx4=SR_Kzjq&*DRe -xvusHNgpw8tF|fxTzISW>e6tOoj#+P!m+6gF^XspU4vt@)|1dh;fBn_ISs -_3gZuz6*A9e9z5I!--F07Gsny6(CY~k#u*Sg|Puwp4Zh#-9Z)$<=tb%lq)3Ytu#a*<3>j-0}#JxP#iY -b+lH>k@%_^Gm7k)zc)7;b? -)GmMg(3Iqk%r!GNMLq7BV)se10TU~!P&&M#Ps`lB*5z3<@6N~p9v-VjIGz{$7YxwK0-kzQBpN>Fue!Y -JVHQkkKG(G(G>C>o7Y^5iXBy%fWc^JZ64VkL(X8(O%!)K{(U%QL=rf%-V!OQ)(N9Q$wy8S<7yP;kA58 -84-H9%<9?E=J)>JsE`)j+vikUR)G?%CTnZ$QB~crn7MJ41;`cv3&w*WZNi^m&JNKEhi--{JM!kJQ=>m -sd-$9|@D`N5V0}<=xfSkKDD@UXNE(kHsH%NR;4KksyZF57-z?raK_6j;dta2n7(RySWx3XhDEQU8$|b -Cffm1y2jw{W72>GY+R)%Yta0SEKEiz2YIf*eI$-V4vbly!9BIl&v^kpp^aoFOE3)mH4^2WE(<+Q+!sZ1)t5J#s*6P|a&sJe~Yt)u-U*mkzO8iU -l^C-X`U6IZY_fNPfu7=*?0PN@)k`}*0zX^q-Hd2~84jn!^+G0)>lhO9FQJ-iA%#39`UeD#Bw`+z2eo_ -zh)zkWa0dIkzBn&rsIgp_-gPZJ)5e)Kt>FB2NRd{V{p!S8GAY;^eYh_=%0e7J*>WzDo5`2~x@;^d;+c -2QfV!jiy$sO0t&yClmgN_N1Kz~i{&BfF#_nP4&CY+TI2vKE?5pujG<^w2Ji5)4kz`PtjU7g0oI9&MY_ -?FLeGgl|C~Om33Nk_|EEXRmaPoj{FOff|21e=jwLP7P&{CS2a09_+u+xI}ijm=Jvk-A+~^lbryE6@CBU`1uLhfcJoTRT -o=NJC-@Xc#S58SyIs<#BEujiDr`H(LuNO`}=&B1BSrHE|&9188m;V0QU7))8qoUe%6KkffdJoq;T$|Q -7tb@H4L3j=XsvNjtl#W>=bCzipeIhRiT|fi+Pi)(1cIN2?JeMY(zLp18O4adM$C8BB_=|7L^}%8KsZW -gQzQN?G~chEqlG_esuiyNOb{3QS8E6sJEfZ9pcWps4ochi!_^dNfj1sfqWLxU-qJ{;chKGP&Ys9Ej;ns8-6pJY8|Ph%v0U6%mw2i|FI;5lcm^d8+~BWsv}u&-7z8@ibcu4C1Gf*HSDXG)po$&{p7Z ->ApnF=P(F{5}xh%TGGJ8g+YZIjUph*mN@vclyCoU&xN@5qCuXTEO(9_w5Cr^8IO|cOE4R>bKM5sPw!i -)|x*t*l{4}bW -U`QSkjO8qlC0JQPxNiD<$`|9yQpr-w1;AHOx=-)l?=q0BVXwC}9B9QsYLy_AV9N@(8Oft0!Db2yNwYw -IS%MbCxVRle`@jieI+o?V8_|JjoTihwB9#U3LUkpbpeUsP)hiDLL4Cp*DGY@hkkB5D)7e%65NkY&WPz -fF95@ePk%fC7b$1>=aXYS8(RKuc1mqMwjqcx%q>xK;CFv~pw(sYi=$=`qA7#CsVxh96dO&-`4g>TK4a -%w3UrcKNF1;-JelG${ThOQ%T)iH<9aOwPsK3T_V-h2)L`KWl%WVhTM)dyu`{*6W;pr8K!$J<5C6MH0{ -5j2+1s$}*WY1ujKi4XZ3x?)+k}rWHGKwdH7GXK?c@ZB44VKv=o_y+dj)3vVBYrUN(BJ}-GrNH^fn*UE -MSR=sHL{N80W1e;1_El;-3Iv4e*(om{N|gUi{JO(TkOTG#JtwtOcZOG#Pi8$a`~xTUX|VP^1@^y@Cv9 -Ok2mqK=Q5dKDdGHA363fZyJ(ECvf$!2FUX|Q52&(WLwR^VA==}CLd4JxcQQ)o$PTW8`%b+prKn;WORC -bkV3d(r_OIpsvWYZ)aT`7z(s!)bNYAE>pGM#}`3mrpk9t5=LIx!HzeOHY+?0(BkumPm&{?H?rhpVD8t -r0KM2RJ`nhlYobo<0Mr1q?sz!uOBJ37jGiA3sq=hL4}@J|6CT>SX2uQ82+2C#>f6n0dd?TO -C_#fn)-8((Y?@`Iq|-e-YPELB#jQH=V9rfe7^xmXb)+cu69Cmr;qXFLOiMb!?X%Mn&MQzuT9BEug0Jr -Eq`Kzbp2gg_n{FWiZTm!hPEFNY#q|yUzh=L0OI9Y7Kg2vOD=Y3g#ES*2+Af0Y`9&O#>j>X25L|xNp4 -jOO{*k9y7YotwPv&t+ZX(Pu4wN&EF$>RP;3(S5W>60o`Oq+cgPRIvHU^@g88BWYSyF(0S3B$AxFuXm% -o1V9=snj6_P_$S%#eA~jFG~pyy}8*pXXPoT%mu?+Ti2QaXKgXle#uYwxBUj8=5&o>GW#t7UU!nh&6{P -ip32zLvjZ&Tl4f&qG-6GLDNDJXwaTaYE=aCwn;d+T2!|tWaE2dZxXB|&>P@_P?DhnJ-sXJN>yx!e{k~ -h&R82eW-IJ~MQ9!Pw$Z4GYL??N`R^r2gLef_-p}aNo=tUAj+cSgX1i6F4d9@TWw3sk4*B;*jOR7&Rk= -H(qx||P`JBv=Zo6#zG8N!Rw(kyd0ScG$pSeunTJ}++=>IlJs ->|Tfe=s7%43S%{1tbm(Fkq-qfxg^<`6xQ4ndfCfLt-`qb?X-Z&ZZ)0iOvxsC8GlZQQlZymo90 -gRWJlpOTnc?Ab=#!lT!WlHAi)OdefDd*KnP>_yJPK6XqOage7$J)LrAh|Yn;f|9HZCoE*&zJ6|6tQD# -DNQB}hFm4uDKT->P_#$T@D5RFi>W)si_tY>;;lH)5+Wty~-*&1B}ccU+5o>M;6_^p)~Wh5?t*SfXS*0 --&pKvW|{)yVlwm0Si@X{T`{())G{&eBB#Abw!&G8qCD8-}z0xj6u+IjGd~}C{J$Q-}KC$2N{b(pctcj -9NL^r!k8viGO0Jz%fzkk^ZJHf@i@LI@|)YPJa&3iqpIrR!KHfIwamEGdpaM*&mPS)9o)E+LM)BT;8*9 -Z(WLt7GCb))jg(VBNGKvtYx?RJhy;VNhaRjt^>W+A4cX+BUU?JiA8R>N-I@K`3Fr=fJzbw2$bX%uW4} -P-jRW_?h6PV*?jTqk|0U{4?AEWvRt@3x{`=9pXNTu!cLZV -KFnWFPdUSN~w}YcQLfJMb0R0ThD(0@6CwkxE86UbJV2J_#)9v+o&XA2pVsh>Ly#4T-pLd22f8HK$ -}YM%4N~v*~!+^r;oqg8tNmsm*nqnx&nCpGLhp`gIwt_6V -W^Ka4EM=AZRwQ(62t@W)Hh`M|3`JQ#=2Isc8!6C>zPIG6&>SeHYfus$0-E(chIp|Ypr{H~J0Dl;uA~j -Z3mPX!F#wsqw#G%}rKm|35>pWS(N34bzIp-j@^xHH%aueK;_3D|nOR(K$k!d(8`dK-b9NN5UCfu|r7g -jg#pR|XG@AyxiuC!oiog%}=ss!`NB -Mq|#g_i~i)F3!ifcNJ-oknT#iCh?f95eR9D>zU?^b7A>zlcys9%8PF$G}n=2dh;=4E-7Mo1_e25TXum -o74mJpV9Wsg?xHV8pB%9kRdB*FX7Yk{DW4@e_`1#tiUPB&y~ECma$s!(xy#Y>H^pbg}Vq})5H|NLZXw -qxtP+sDH2rirzB%)LBs~H;2*Mqv7ZalR6MWL35Cx_Ml=T9ogVU~TF`Mnee^A-OD$Mz<>n8&k7oGqMh&7{gO=u;QPxNepZvdw)lP^5XaY7@ca_ZNp+$Yl7VKKa+T^>kz%a>rC -XBOLl~PW2!oc -w)pPYmHU<)=uE5Q=IA^0So2gL8HAzLg+e|x0aF9>4)fTyBZC%=VY?y0PMc8JOWEX7Ei>sHfmqIEJ|Sh -WLs2>9@tR+lK4(GICn7&Hsw5afyJ?0ou>>#LwfP3Zg#p6?!7jxICokLNS7{?)?yd|M3iWAS=Z5G$S~Z ->0e6vRy0rb7n2r=aq;R~sZf^v?i+9|}x*T&P;4MTo#2*i>bTF%F6x}Z^CMFgw$-+-E6lI_UqRb39XW3 -A6k?OyQ&PonRlfM#b7*vc8ctG{8`o@z9S3QsK<1twqFR!^Gjs-Bdh4%Q8EZ5mgxYe=mntOt8M;pW>(m -_7{5r>y#-${QBj>QYM2)hLIl?90eZNDO(4b_5U~WsG5flx1r)biXgo`1&v38C{cJEgJhW5>tZnA5Cbc -CjAAI**KT3<)URKHzMmq+dJasBRKDz`|JwY{sLbL0Mc#~Iv*^X4hS_0-a%n>=9~;hL9;n@vv5fe|NZPWEAE@l)u) -L$Je;3CVloZ(k39p4RUtpy~$N`V7&IVJ$I)~8Ve-Bw4UL6FSqR7C9T^Cx=Zt%<<#rWTc~Gjh)s*rJE*(nJq{3P^u9!WHKiy3(=>j -t5n^4(>Y?^Wd}T?Mf4~;`B?7mtRy({KVST5;hGt*Uy!DVK!PazFn-5wPM)QP+#?4*qMxSL|10*7or>D -*-8L+PMxuBsGNmmSJURx!7emP*nDvh%|%?4P=iS3m2s0@+St3> -T7?bZ%~PdfeS~2VvX$oKDfRPzN)@OPjQ~*x3;85JQor?0~waAJAa+j*wqml<10w3#88*3x=NbEDdYz6 -buYamGs4VD;rk8DN5P8n5SFxqA_YP9n|mlq7QfxmH604+ca&u@Lk0Vwn+1U!mRw76uE4v?)fwn9-#r~ -Cg72UfNZk`kVWO~Ot8Y|{LmPp`ZY=z<{XfOq59-|qsRz(!=xk%q!Agap`+{v~F$pU6gx+?QsO*kQr+SW;3vF@kM$x)OHF(?W$Yq-}K0*$KXNzi;>+&=X{%94 -HFk`QHth=bcsKqgx^oV;%f(ZyTmJG?#9M$~ZvzoWsMsXl8Y5?pV_$OcJW -xJ=B%?F#iee|K=AR!101Yu9pcLelqcGOk=c{QH}o-qs;)WSo}lMPuIo`wwm4Xs!l8b9i~v^jOq%fPHT -DB)4RZO?ToE!lMIis0KwqN_obTwn%&w9zq3$%;1{w?O`cqYG+tl#!zU* -sqWJO>zO!x?SSQ_?x|k;+A&jd$rJ!Kn)s$O;IA~qVx -DW@MQST=x!1Q!3+r##>uzFk6eigFI?tl5^pKX|Uq(IVKUKA-d6xXh|_j%Re@tcMr-zs%jt3 -$}Ck*Av6t4gN25p!_jfcRIsbdEvz-Xy2=Ahz5iPW^9v>`MQO1T7W%6Lm0kU!}cXy-JwQ~zxsGFSWP4k -W#RC>k{sT?(hkCs?m6(+!;^QS+%8LsW<}8=rbB%fO=ycA!mzNB++Gs%G)v57u{8`W3iOkdcqdq)Wktv -eum*=+;5RB;+65(e0!i_Uc8gjH}fj?9yaar(EfBSWKPQqy7oGIEk0S~yT?-}z -z#?a*0r&7+DI3db>T-81<0O^TZEWVwV6#sq0OX`?HO*e%kG8xQdBFd$Al4TE#1f$}jijkFg@C@cewA& -bjCdvL=w)_`jP)wC57FrQ&Tk$_>;=Tm4&2v|qU;+UAAbac%D*Lvg$Bn8#&qFLZq6_I%>I`yN)7_1 -WGftSKC;L(}d02_-Z$#xNwWg!hps6{&Sf>Q#b$9SjgR!eq@13Hc9sKa&UHV@Z;$0;QSA<0sLwG1HgtonQ(t~zLsp2rcuhmI&eDqnjkP3}P*;NR?$D)!;}@$246xQ -M5%cm|v3todU|aL?+`C6>A{3@Do?FN4m=TQS&u -LP{>Ab|8k4qd_-2>Zt5Y6Cw#&KdX=#Ppni6Toq*eYEEW5NMfL#BpVQZd+WuWweiUzT0IoN2reJy>4EM -XfF`OL9qwCK9ExEy}@YRL*lrch^-%?j2OnDI7-Fx}ak+qTY-E$efI|$ -VOn3Q0$kH~IM3M5Cb*)wb{vk#e9mF7_j9E;t%@&yL{K=z7x;V=dI-P0h)B$3Moa{gwsJsXoF3Re8-)hET)fm$}AV4V(#qaKw(Y*pKIQKSgzNc8^gv@9}V!~(y-w>10sISMepR%FCJ{J -arDDmbB{Y~})pm3ebiQ_;;Q_jha;oqCo9d=c41Ah_G?b`G0M*pHs-6$jBA-D5y;NuqN97c6v`0W;%IY -nlE5y^9;iv*4sbPA=&Wbtkxkt=p1i>14zNaiq_qxeit8NEbzZIbf_pdQkiYkNcB6qZ14RO=K9;gf6*;I-${{F}?V-+BvZr#$ -sDvPUopK3ZW+0#@k;KblzpU -&kOMhd93{DKs?Jrgx}jON{L*IXbc?H-sdq)EnY$|B>cR@6VN1`Uv12l7=vpHyRj$rR7@Q|Jtd02;@u5 -SxaB<;8M&4Y9EYNVtr8VF9h(RTcY_}^%LT_p)?&mq(;P*^Tbwgew82%)q*8gZo3NwZPVnP8nzdG%T1-Dli9JsTO_$9Xn~(S#UC7 -TG+kUqmA7V->=P6I!-nR9o=T1+S5GY96;9;TQ}kL^xl}3g{|X1=4s%2Sc`=t+U=>j7YrMaUI|G@i-7o -_mXzf32Cco&;rD<3YH7WUT-Q9U&M@5AzN8-^_KzWb+EUzjp#f8{XmXOohcCq3OcLs`B#YF -kwF?<16W%znhAGXW{j=wXhk9m={$V>DYVwl*s6-K&isx^BYO|9h0yT)b*N?iE3CYM8YOKg!z_`<`%}w -gd!ySS*bIefq9O=q4abBvNdB#`=%$*!4#!wyciq4`)^CGQo11Eiy-a1<*Zi@h?pa@7D#7f;=Bp0TVN8 -5oGzKKc{g{XgYk|-H@$?RHkAN6gPV(|m2)O0n~7>f@yKuEN8lk0caWNB0t85&c{mo)3qzL~aZ9oolRT -9Gbgf};xLUB=<5FrgP`|Dn9ELCTk0Nl5Ztv7NCEJMRmw@DRx!-=?Ul;(H}vJ(LTlKQOT_Wv{{d+ -@8sAvnJ{QAWFW@{lokw21`>ne$fspWX}2dy7fSVcbVF{LCNU^vfwHky==Q$TCv$3_)2`FN;;npa)?VB -^3FggnV@sQ1HiC4bwl<@FKa!;F>&n`}_&ICt#Pr>{zvVE{8PH>Or1oR5}WDfl>Ih;>yPoPBOYT+aQf6S=6jNI*ph~4)K~`d1L9&tQA*PIVKPFUQH#&8NjSG=j?QVgD&EX#>K -)e#7 -_92K1b1(jSAD%Hq%%1bz>W09t|^pT;$7Q`OS-}3z{1(OYDw%!lhZx+U+}SyI(>(EVY -}3bVUbkgXGI40qP6qW0JJI%9p(0!25BoPsDN_-Z(VmeWo-FLFWJvto*~>(5Nx3(^$&rk>E=-qLLB;m+ -!|?CP_-R<{S;IM2Pq?A9m0?X_%F#UP@__3`6YE7?ci7+?kYyEiTIFhIw7=;NL%xr}i2nO83K5u=-{^2 -3&{zx$E%ZrV-K4dktdPaaVc=+3?EC;89Y*e(MJ+?o}R=A{mitSQSlX-=N -BGv{tQ^dO4jBAO(UDUM~h3yYY|7aRyV}EbVQLZxWdKUD5{>!ymXp3WK@Ylg#|LX`ke+1mkvu>y(3g_& -cUlJ$(C_b+wDBRJIw;^(=C%-@7{(8p)0r~MR=1ze7b3ik)q)}d6(wlXNCm_JOLbXdqP2@v6!(h0zv%U -Sa9uuGpTh3?%xx#z -CJGnOS;K)}>Uo<69FRMU*Y0%V|Nfcv9_g-XY5S4sw2xPjH~SJx*K&T6}|rZk&=Z=Uqg?YR*vDD)}I-6 -5#x<(i%3@5CF~KNiq3DOf(vMKT80;cD=@n1hW&D0c$uz^8EhaEI9;ZJpEFCx{nEjgI?z4&W)HdV+8FFL_gpM=MM5?p)@X|qdK+_;Lnnbc_Wu_`bu$hdQ1??J -S=NB{nuZQ3yC8n`9-T7ed!%dnKHeGh=&?dCD!k~Nbp%0AMjHm8t?)`>8)f}%Wpu!j$LI3 -Mth6nhVQM~SIW$&8CB4)auY)i?1Cr{U{}*#QlabigsqZ9AorjgAO2OPHQ$Lm<4buFws@v}LWiwbw{|` -Q9!A*Rs7g9K>ofonhB}AoK8hclUq|Z2kSc?orzoj~C9+Q-bz$__9(EY<3*w%WJVAQ*&h1RtIx4jdS3p -5?fxpe48CJnWhsJTZ8+{UM-FX!3NW9cHCT=4tNYaH_4Y-)x~5Th;w@*PR`AapHS0gR$5!js+5$p;iIR -!!^clP+Gt2I_N4JNJ1-0#r@{79bauwDB$XM#Mue|^16`Q@^?30>$>|jkHsrTF7g^~X^C@i -!ms0*2?H8Z;=hy8{JR4%^bHxbx)k?#{PsRGhgLzx`(S;m)_KD;j>fYE+=!?!$-QxT9jY=IW9Up_NCE& -62grSTKS2yN{bl#$>D~AhiAM8*;J|v!oVa*suvK4kVphHrPvsQ%mI5A^Kws>zU3e{|m6eOZ&v6p2fXr -U-?y|7_Z2^)j`dm0daD34*YPtgRY>bh&TXCck;<(xk!OWQU(Fp8JF48%x=kE!;?haHmChoncx{@_W8auBhHTrXcK~a3q`^7eKTA!H{%ViNNqERsZbG{^^;^@%R?!!>3PNLm1s!i2O -jSYmov9!XYOSUgaSCmvCA{`DBV()4%dkKVV?m41ZGB?MCG28@<}SzHgr}qRft03e*+tQSgT#H-jEU5K -fX7$xuX^JNcoaWwmE0v4d|399A1fl@ha@hQkJkwniysxNrOB*GR$eEfiyuMQ7zdUJ21;rqfl<}3xw(E -4+F$glb=#%e#l2{&7N|nQI$%yE_tMm;>01yj>9_Cr5rD+LFLF$6K+Y~jqB7jG{!(9~fO*BWO_l|oG9o -TazpY@&WhsIQyBKU;l$rt$>a1?{G%(D#}5$?> -&rOgQ}qbVY(;w39HP`s@M8XvhpX`h=zj*Q*C%xWyH3wuh3qj9gHt9;%nB2*aXv8uy|dP#S906;o#6RB -8p*bL_6H5q8lNk<|b*y@Q7}fN;kVs=X0ZFLPfXma1fo={-$V_RAJlMVc5ATXIM(j*|Xv+x$4tpuCCt# -AHA&1ZCGZ;BqPWEDI|r=3u!J&+w`jXvKTu0_#Tw5)xIHiwm9r!|7O_|nX0ksR9W)sHg2b_5EOjSB6+N -Yj9t+_DcW)3?BrUf#XD@=>wu%4O>REah^c*D~Uo0XInW>Ihkw@+DqEsu -y3SV$oWBU`BC4y`Hvu8v7)-)svrVS{5^;q{EVKB=W8;J}&N>-mzc_3Z7NHz%j(2QPvfEC{Ke(uK`@Oo -riD6jiu6<;p~b>O1-d_71D4gSVQp!y9eCbaq#Em<929DyI`>E&nE-mjD!Gz4CMc -0q*hQ=M9z>rfpj63mN<)8ajI@nu(1lQrZyOH*`fwEeN3*ON%Z^Q2}x{qgqZQBWqU;42gfJn%D)bqrfhY -oMUCQHVTpKJy$97rcpqiY8B;I)(&1((rzG?eRsj|LvcL~Bm)mpc^NHBcj)x#d9HwBjDR{?0Gs@A>GO8 -aPA8amyTIH*W^yqCSZco%v_-r+U}Q`>I}Tv@%t4u89HZ{I==?l=U^-iLKm4DcvyTsYKW7~}pR`ZG7=k2s48 -$BY?_zXnsC1r7bq5r#q&w_UHkYvb00^a$=!*`E#t8`^*9m4h-^5#cI9d{x=@wICz|4}(fSm6;>@L!=Z -1Qv@kj-x+ZCqH&aX9ovLg>L;H3#EcajyWPhznpZ7EN^y&rY@uPov@XlSfY?nBQ$4Z;C3(4P28`06jJE -Fz9yAa#bORRb#m9K{u=I>Haw*uZeum6W&@EsZo!o!j+jgJA!ov?8Mt%%QtlB>d(;`()taXQDvj8p9 -+y>)Q8T1Kpc~zr$ieoKWR~)zpRM)Qeyd?ZFz_Gbhp$vKrl3>SYQo4Coh2K{Yn9h@;Pb~Tx*-C|{ayWdLZCosb<);C19~V+`6C>G?4Uf)8zuSw3gPn&+tYSJ+ -Y#WyzZX;!V!`OwUm~~RKYT@&W!FQLq%qrNKU{m9JB*gDrNS>FREYse=E%^>HD=;W=p_m(vSztGBD!gZ72wzhSAoQ76Vvs$Eu*Lt_ -LCRK7n~Z5Zqo1! -EGNwC0{yNdV-NPs(5>dyudm`j-1w7oURRV@oiUPTC01*^}066ZvdV5wJDq!H8E-=c -On$DV{H_*q4`A2~>T%)D8dS%9J-i5ZNZc}O36Vv;0Jqz~Jw8iVp#oVko==v%<)SLU=-MZjAsANJ!hoN -3ZRM&*VdSTulx=9>hIBKe% -=OZx(!6%55S!#9%a7hcaYR5cXZOjb$JHGK*xjfCNK*eJFsx$0FjbPi6s61oH$KqBE5?$88gGW|1}5tX -)4n+<5cZ(lz@B^Q{Mo|zPe_)wYo*^xp1tMe$p%Jkf -Zr@8RXj~bE9)%YB3j&M*QK9f$MX^$=8Wu2HOPf}!KiMJ<@^Fc%-n>8PT}!pEq%uB1< -vaj*jqX~*Sf9A{Bf1*ovOY?XyHE1HZd(`s~&t!@5OVNN%Neo*uk<3+g88872TSy0k$M{l%<<-sCGA-7{`$)K$ydtF@} -0{q)+cI?q0>RrTojN4M(aay^8f|KK4!p0C&Hvm>w7i!=}oJXH7P;mZ?mplUywrs~Q(RiDmTlazd3i!! ->>>AvbhU*prm6f9P5l{zJ>IK}(PR?gX8K_2szwZ%wEpK&^p3zSpPtvD`JdKIN?Tbbv_OFX8sGD*m1BY -Ms0^yo|&+1_^4&GP7~oRvKU{V?jH#hQNC0E^@T{-Z2Ke7WBMh!zOSS5BVZIpCR5@B=(ImK;&y3f;VS) -zB*O6z!9dm(QvI&_Lmm&a%8nMi@k;bdfP|DL-X0qb2B6bGhdeG`aR2AFY!0tf3MWOiV))>!)RP+ktV9^+VrRR -AaJupvH_)Z#cxHzezMQTuz6bM5ptwn;fKzQqEY=^2A(L@<>Oa4}fb5M{j9fx-lSG1ye7YP&VEZP%M#Zx=Tv*StLlPJ -(Jr-zu+ir4x(Rh2sV+0vlmdbS!}`>T3AvhUKZ`pKME8}z9&PF`q5^*N%vDoosHBb5u>ODj8l?9JJ(ce -q9R~s$+f%#s=_SCLixJA9FNZ#T??Sl0?j-iZ`({^W&a{mOP!?TS$#YxP0?{DnOdp3;j3yHyCG4VEr4= -gXPQ))sVGBl&3XupTRb59>4r<9GaE4rE8IOf1sf+S)Y}*OiqP{Fm+KKe1~?o>6j)}e?Yo^KzIHVfKh` -1DP+@am40%p@l1!1iPTa9atvGK+^6H-*%p%b##&|dw)7J;|{Tjbtk30YRfF(n58)Z~{9o=Yp4}t0|6L -~p6HEck1Qg+>_nd+m1IAlOaSX8C3B+p!-U4NRqZbKg$3XF7#u~Vc@vp$|z*(hH~q^Z79(KQj#i{z%N> -pHQ30!OzxOfP3=rXjkFOVTY>GIvSV5*i|L$yVki?}`9<26^BpOk)U~H7E+GO*IWYwc`fqj55)lp6qyB -QbHdN?5X-qf{tUYOy*{qd--M`xE^L0R8{A~u}@fKUv73l;}+EZ&R;ADYExVRqTV~@n+3#_99ICcg-qj -@1<(@zRzP$_Mf0ZxQwt?4;2FY;?=i+DluV)|GOHca0%9~p^lnW@OY)I+Q%dVH3sn85n;VD4%at?5`h_ -FG;z-sq@v5;jrRVxbfWmP{3kDG21S~28sKaKM_i+|TGWu(vDmI&X8JEr}v75nfgh6ZSHW1 -)zeL=qdu*Xxr~mv33Zu@8VIJ{5?wQDlW$utL}c}7hG4EKbqXY4+RfK?q@flZzoggrX}GRppkTC5x^4> -+EN9}K2Np9iP?>XC0Y4Top~&h>th!4z3o#QFhoH5)dr)8NQ2A;O8w1R{AjQ<)Fp}2jqe785>F2$|wS$ -G9tDXlwAnN6nCp$f=X1375fKrlyO -hE#g`R^qn4wc7tRa8G?il?4V=ytbK*l}xGmTFtM0ybg9YanI(hKQ -IMPvbH&$voB#0t%46v6u(Aj77`Zmo)E{ -NH$n@u1Hli9E7q78-duREJ<^~X?urx}3QBVz1|2A~JOUmHtx+Ius7iVf>pY#SCVHK%GpG-7fc8Va-ai -lMj;4TV)dFci*c{&ru_XwI}+VyK8KlCWZRh4(Hb@|!~<6r-Z1hA@0%5?yf47{&IWGyrsgI0F?sBeNEi ->ot33%z_JG-M+MdSi2`d7#%y?j%@z=5@EC9ERfbD=lg5GbP*FT6Qq*Dy2L>{zI7|@hx9WUQ&_b8C(+h2iYu2jOhoXXv_zu --7Ewfo+kn>K&TTFiD&SY#resvMJyIO$mN6+i!OHX=jBKVzpOM`3a3#$7KVr!j=%j&Kp@^^?6^Svrgd` -J|5ALz=^O=!f#(p3BUcDC_z@5eeM!eVpku%7^g0dmd5+TUNkzRZ{AocG>uUek=Gf5Ft@5W@Sg{k+im1jLG85 -0H>`2$p>PmuKk=Yi5-rgqlNRfN5s@2a&p3TqhX(x_TY|({PCye)QQhO?k9IXhwQ6K!X;M%F`$`p2o2}gJ|MCg=g7FVBkAUs?YJvJa_S -=4ePX@2xpO=;qTuCB_R8M4)eRW{Ql1LC&e+!|p2DF!ReU7D#1CAJAa)N*$)7HVdqSYgV_%OaJ9!Xn-q -N&Jbm=Y6pUGCwG+u=#bTq{Dn(M=TP*OS;<&3U%m*8m~FeLdNYCWluC0`z@v|6M(Dkaf3-`iIAHs&<9~ -TG^k%Q9R}De>_VWtjSYgM1A_N*~Xe&0-&tNB-YY#YDyVB`}@wDBEPw<{TCeHi-1IIcyIi=GXMwHnZ#@-3adllU~=_~nVvW3aQ^@1+u*e)L -Z=*Q%iPq6X43Yp-PK*b6?X6-0S%Ft&)qi|n&R;TLF5HXKDNEn>(qtJd@Aag9Qc+HFx&vXAO$4Enqtt# -J|qQSIwr#42z;J~)y!KfZeH*KZmbQahVnenSpU@IMoCHFWy5sey}bR58n$twr7z_gYjK4j!LP_8bvD+ -mX;Rvtx;8xfu2S{oLQLz)(6&4i|i -YBQ1?{mvkuUeioTr#>im4J}D)YL_0Hz&<+tma_g`0O+0Z%as1zT~)cP2l$gX(d$D<;ZAw|$Qm4}Sv!M -w`N%&n2N#$?8Dm``Yav)1d~{KPlsAZe%9qIV9DXuQFK(?=LxSRFX*jqlAFEpcfme;viX9E??S48XS0= -t4BX0A*$QW%#(6sUyzeXEs}KCPRyzu@$pKuo1%CvB_ -ik?ZMN}jna*`oKq@U$AbUz<*P&`WK?#4V6Y5aL5xQPe@#X;oY8J5KgYJ*Ze7>wW$|%>BWkqpl<~%R-( -(bfOX2Tw#-g3I;`rWkn+&5k-k8CozPYYpn|u4PlDR -!e#&hq2P%kR`+-^?B?ghG$uAAUVl>3M(-``v)D&k%LRU&&s!q6K2Ywn(l&s33x*<1fvkq}XrL~jnndO%Moe@ -*sJ}fV*D~kEY(4g^=eFp)@7~T!eMu%so2d}zV-ir~D@rhB_fCA6@Ce&&2IUFj}bIK<-^}1q4ITz4ggD -(Q9KWhxs{w7YwSY9oazwDW>KG2_!;XqduCz2DrQqz1{OMH(*HH2reE$@H(CFGpUy7p{-jJfe~T#J5KG -nPRp**}_H`0y$NY>;#-HJIZVBl}*b*~1<2;fv?j@ogEoLDr0ZNP0m3J+_4?eAo_+EPnj%)jZ53c9ZB{ -9G(V=&P_NNu8lXP+p60)yZ!nwX>HZ5Tkz^*%qJ{OBpZC&+gC(7?o$DhGW -M;4h*GJbvw{KNxEusU3?VSJb4D~?9J+>L1^l$)x*WLYguYI+g1asa{OISQAb!@!@zcpQSZUZcK8t+T9 -v9CfQ`4nEu?0Jo8-G4DV4?*>LF6IVrC#U`#nhc)DVic5D185$qFh0rg@u?UvR9;maZ9zW`R-AS91$3{ -5{jHEy-uGHhyiX-E5nnNLUj0CMm{wne3re%8Q+bY5LIV7mxMx3l)KZ9L&pGY;u|}E4Dca9J;(qhVVY^ -MxNr!VVNyOfF<+=wkBpL-j~if^g|Z?GB2a8`Q{c{7Hws5SuK`Sc2VTh<)rx}$T4ZuF9OQ4Kl{?T5Lp! -*g^hhfx+XL0;XU{1-e$BJ%0@!>H#b8#yxEnJjvpnVD|g+uq@SBK&7p|I^aHdz3C=FwZCP9K -Urf_TT%k`{bk9whe|`w)V>h5h{5098um_zS-O9^qRr7(yav%0|2d<;;rvHeQy(5o2)QQ(252`?!H4ST -+xb31yZnK#c~Z;MS?bL5Zm{dvyh+v)G%*VNfEMc?N6tk`N}!+QID@U0#2OW>O82Pg{!M`cw?g%s59MO -jdMKV!Y%_|)npJhGFfoeGB~X;GQsCXou!y_ppYh^#|jjR@vVv|AxT~&;zRs7PbuGu&E?CaBFFt-Gz=O -p+7w`*WYlS+h->dqx^z@tqF<~9O*S!{F*Ya0lS>`nUrrGOB@n%T7H#`^C>U^T2^RIkb?qqY6pQ_P-@bw8~ouI4|{ucmC$jd-!VjQ(bg}&Pc@`rU)3;s -+-Uh%blh%3G)^BZj_s0j`{A91WZm7j8OB=8*|%`2nsJQr=a;=Ho -IEmQpEw9CF#obo9y%p{~{l53wWSsOitC3GEb0#RNt5>Ch~L7lM(MA#r*XZ8AY-LZ@~0#b-X9Oxle0@< --b{&;vbm9k5f1Js|el_thww%Apx_aAwxx_<#;oAp@8p5C;}&KgB6zi82g|2QKPj@99hge64jEBjg+Yd -!u`0+Pc6ev!JqwB*E~vJe!R$Fit!gm-q8Qh~Qp-lJJuX{1j0$hn}3tK}S}%Z*}#5jlB#PO|7-noaS>u -sW0gRli1`Wfo;bt*`TtvCIqZvssKeG#JWGQCbu!=bw{gYFc8$Zhz61H|kMXCSZ^igx@73KDe`Bln!vF^fq--!j&|>*5DB3LYU7R -X$3H%J?E_iZN#tUmX&ro$WQ0R%Z^|`8V56X!DKeMJ{KR)d&r|rHM};op#XU301jiE@|491$nx_R*?l( -qtHn$+Hm4i4S$cb;90}z@X6Bz{o!D9K>f-bo*+34uo$Lr+ndK%<7phlyHPxFBto-%!QkCwuxAP0k}t5 -FUUGVw)i(yS28^yJdm4Vp@;C`C -N?tuca>255vY`#u^rU843ct59>z*3bqWiLK8`h|dd?=cTWheaEEOz?p&O_R7g;O;%s?S6lvN>5Lq{mU -Hn_iVl_kmwEV@mI`rNTam`FC3 -mvd?LeXJ{a64^+) -gSeAiIEWtH8P#gaENF-XO@97bnz#1%{rm338}%<4rlqqtmHt?%T+#b;Z51B8tL6#t4v+5jj%@QCYb7O -)zGj;Ljt$gwi0jJ(i2;271|bv~y-8s}&{A>*ovoK^5#^l-l`@pOx$?W2yNk|>bcP8zGLwaA^NU8>pb^ -&{~OO3d#i{-78m>{H+dRrw#p*H>BtO*ec|eiJQggbWpyac})ZjT`3m6{He!_9!EX*r5WRS7a1ofx!h} -()r+z?1gM!_Bng#5Z0bg+j=2EFTyIoTs(=D0IfSXOT+88H-WnMT6@%fqw&g}2%KaL|rUe0M1Eo%8F7~ -?+ss=r{Y{UKmZR%{2Yr_ti_woE7S+}nIO>&Vn-u}MHSGh_$ut>9x0OJqCQu^;*v? ->0~w;Qv*cu@0inOx4v3Yd6?%?<`eQYMZVWX|;S}=)PV_~^r0HsN4g_asl^XSIs -0&N*Vm7dGz^3qH@G#~xGe*M+`9FBmIeqDBcYkCFg3v4&L4g-kR -QQHNwf~yESl^`PVw_9a>ml+|f;le6zBZFfpy50*k0L9}fX?EN?+11deU@Z1P15+1whT>I#lYFVLAkJ$ -iF(6{77)6au=zd&}3_c*FXf#tMMDnf5pZjY4pQ+vt -!}LZQEL4*?&HqB{Tj-X2}~Kj*4~DFa|_=QGY$vzeryOh_>-`Kci -bSm)0R+t2h2q3img>q12`QYH-{o$FLa|1tCFmW~Zp%eI3gMT;ir_7hdL|;Ji!Ugebj(n+Br;&Ww6E`d -;4|5nX`A_gBejrz(>p6n=10@0k`2nPvQ#tHukLCbEyfM1Jc{4eZVCqr@Q3z9r -!zpA!h7bcgcD8NIqeG@4g6eBPH#uwRf|oY+5%lg2jcLU}`70@hx84sFJIW*Ljth^bUQm^C#w_!~?X?> -EsSPNOpf`P_lg5A*srL$C!E}7V1AKRIooVPUY&Mz>gdVo9Dv~f^WO3l-Eho_!{y=BOd1g}Br3rQY$HF_O2VfvH(%g#^CxNGD)3YB83rbB?AyVaCY|KvF)O8u&n -esOitFYZPE5%XBIiN`ZppL6>~|-NW0B=v|@$BazaV=M;5mnuE+fSZ7{m=G9uD -jrwXWQQC){J72Dy83bqDxo$>cXuWWB2i+Avp(R$QESSj62wV>Cno^Pb)?HI1*jv7uzh`-w6SqmoY7D0 -Tikb0E$mrHpKkD~CmNti?cVxpU{LAsPg&o}btGvE>4S5l~rW;*yg-IaOrKiyzZbM;2bswJdhbJ7Q0&6 -K6IXc&=*mlP+$T@PLKVb;_CKmFq1VPwTOD(`8!T_bvG#EA8xHx7(Ozvo*BE9aCfmlU%NHAT^T_uk@(G -%VXO&_ueayBs=VC(wfh)zF%NmD+rYiXU0*nurrEO^#5T8sgrYswaU`#OLXefm>o1QY6qCvq&@TLmp9z -u46|;$YoqydF;d=T+Wy!9IKyic|Gk90U=0-30xX$cL-w9kDW_Lvu5CQLZOq;p4&L%7oK_vBRRx^vGMV -Fnzw%eJd^itg}&*o`JT_YRPr8V8^guM&&Z*UR0@Ky}Pcxh66dUqR1bqou{V8>6Pi`E}@?M}zWY!!xP};-PS% -J+n@TTZlMeIXBWmps2+`L5@U?B45rfB~W^m7Ip@8(k$nB{z(gFo_m~{&IZD57CCI;LS-m-I&V-|g9o> -h>$-(Q(P*#$D4xo>1X6J$17jI%-H=bq3a?F}l-gG@Ju6O1T#!h8=>k%@$g?ROWD7JY`DGFJX-| --J5g3VyPSvR-$_d>05gnb6M(_=ZWi+xyU3KOLNR^I1*crb~V+Re+cA(9i -pqRTk`DofiueG{0;^=Gi-8lLI!*(;@9irsgHzF{AH98N5Rj+4IQYLF|a5cWY`5@B^s*>1%FtVAg -SEnQW#S1YO_yg((d)>S!kdh!mhfJ5o=ayFwV$Q<0RjqblU=}pY!5sE#ur{ -tESdYQsc7o_Roj0!#3!Iy@5-|OU6ES|q#7ce4z&uID@#K>UUWa6C4)Wrq)(9@#{VdXlJ1YIebbxkqx` -s`bAe8$Anp(szm=td(qUlJEA?c1j1|!?bFSayCklZkM9fT9O`$vLnBoNU(Y)wyO>}GmH-iWO9^*96i0 -TCmw1~t$?Hiv4RJa?0>J9l*jWOpzaIBdLJ!cgb{Mn*DbS+1Em@oe941p{@XM~qwKN6@-%mElApi_16X -JxRiK1lCpDCx8_uUqE7ECBFFd!fx~`Hh4pq-v`P90GLTX&8d^M4W&& -Lk&Rr|?l1BS-(vEzw^EfGY`dz$w7c0=^$7DzaYb_O?CE@-Vlj+NYq8;){7EgK8t0!z!0GLo7Rm+Iw3( -E*iyN6J43U8DO&b?7x9+3R}ZDA=K#8eanc#>8nMPxueH(EM`Ju9;#hwAr -Y#)bF`&CM7UwMtBUtcb8d3{t(Z=5g?y(94-M)ZN6|n{euwravnJGju%XMG87)W$Ejrn2O6v{O2#pyhN>VF?MfxF4@I^Y$A_7lmX5E5}3Kpqa5 -FC$_!V$H1u%J>`Eq0PqqP50?#m4NAwz8LQtcutFqjGTMKbPSc40N>Worm;Ua1=q6@;`L)p!`DYt)ugxlDWNU{C@&-YgJtUb -aSC7gSU<7WK~+w)xPsGg~BT+$x>hT_jL{uj6i^?ZVR4B -RGZv&SmNIka*o9Sv>{vz84FL8YWeE0jBAId!+@IhxGlK)-(0`m9$^O|N&)y`LgqUB3ZF^DFLXdxafNS -aDSerO59c{K}3ZdCG#m!)6uA2j_ya{5XZQvNIJ7Kk#Kw%=j*j-#`N#-?8vv^7t7k+@Z=zA;Mr5`uce) -rhTlH3l}Lt318@;TUpQi7XtKPxg((Gv8Lv-r`Mz4E4wLfsKtK)P)h>@6aWAK2mnY{22+!UygEu0004P -H001EX003}la4%nWWo~3|axZ9fZEQ7cX<{#5X=q_|Wq56DE^vA6TWfP1x3T@MD*cDaDlYF@BsH`11aF -jNo>i%`om@XEu1nIqm>GdH~EmNXd33`4U#C7icsZ-3N_E&(5mbtZ$v`>+Zh4-- -zpLXK{PC-t-Qyx9jD7FRrP7;*b;s8@}8=fA;*@Fl!@B^F80J7OOWH?bI4)& -3d)%`KsUQH45JI&)3`SUrAI+)_g1S8@_Q~JCn)e`Ll}`53U<{r|Kh2ubdwpa3bQwmXo{S6p`T+2{@JF -42r6ORcRs5#Wc_N495?MQyLB}?*)lb4QSKW~UVu}%hEtL1Dzu6!D4Kh*7Mh1pG*1)5$ue+ -q*eF|m66yJV0+0M8HDmcO%}+`UrN%Ws^})$Yv%X(oHJ@NZE7gr$H_D+=x>`{=$E?aXiUJoP1#Yfa3tX -%p1P1INB$?34gd~%ARuO|mK^_>PJSI+JIT>-RBJv|BGpnd1-9Vd!X#0bTX-??FqA=9%hauDRLyEC5F% -cEgB4KHwF06=C%{3>QV^-v+#*m2OCko88C?-y3c0I~c;+TMnD4?U!W<|7qRQQ9nQ4wnCGQ?16jAbr3% -x8lz^9!wrg#dy@CNx+=(n)SP6*$aJnS!FmW -Ig+}mJvPl#pAPD2I`MJ-yT9*Rk09N75;WSV4JIw`a -?A(}Gl8X=mF5KRfuG_z)Bv`A*n&S;HHZ*7_tLqi==Qj`&FnLUsh!IpVObw;RV7PX8}%X|xMMzCcTw#< -)+qu0-T?PC^VkF(J3aTe0DHrO)4C`(ey!CB30uw{%^Wj0r4j1f!cx{T#UdYEr=O-8vcOYPQVX+kW!Y) -aEIlOnP#CXU(uoN&y6BPq%$v*i}Z+=I2b1u`cfbBkI|!IlHHK~aQY&n+}LL6h5am=iR)g(fFx@=?^}6 -g9bxk(^>AH!+eII%@NhRxNGPEy&5j21`Lc7S_jtd@QVw1^HNvJSxbe!g^HF#Zb=6!I09|*GNf`Rr>ZC -DFe(e1G6J#Li3Zko}UC}D5jyr45dmDS~?<2hD*0(CfAk}N2LvxGNm)QZyB2&E*H*=YrFjBA; -3jSg*@k!xrgizu^~_J*s->neyX2R2rbf!330?^J!{8XC_nh*J%>mnW;4VaRjU`trj-E88KlVk6CrbVf -sZ`(?8P$D34^B -=Tw9dp*rOtrnE{U@^691(>o*&Ice7~d8AXZ(wB4*qhbZ^uqlsR4POHqB*3hhP>xFvWQO`NNkInCG6En9)DUokBT^;i_^G#6o4<% -hX9qM{&3+zQr54qh`A<%GGAZ!%*W-#0$q}^Kqps5&loH;i?L`<#jd?&7 -~Lr>(fOWbxo(uYp`l@vu32s?2}VyO%s!DYdLm)DhL#oj-eB~w#7ezb>dps`Qh!)B9dfE{=w(y76Vkvu -TBJctoKdw%Ta%hxAZt;Y7TY3|oK20hX_lM$8Gua9og$mGNN($2axKlx8X0X(X169YTa(e&WPz;~$?Pn -!MJ8FD1>+)-O3KjOfLTHXU}6=Ku~}{q$#R;NTST&)3Rtrdnc0Y(%+B3WNk+9*V7E38B4XJ}j-K^%i*X -)OZ55j1my@x1Vq+{PYjb-=km|xdkrXb~UDoV^%q}d(1zBBKs|&Ka7%*1NFxCZ_X9 -_T?jeJuPm$X@BU`ra$)Mgn;+k{e5LMbzI{L4I{+QxW9cbfcQ+K|ep%UL#J-C(*=>V`fC6+J6giQS_ri -HKz?v5LMlsMwHyWh*vAR7s^a*s6?FX0evehT>vQC6)Zp_l;Y6CXuI<$g9B-d6}>w+p~1Y?d{^tqTl)M -%BSz8?DJ$q={$-ohn{&O`@IB<=;1lCS(KH;Doxdzl29614#}ieCL@__q$s20n^~cpgmSAWCq=oHDM+R -mDJtoksxq|kKwnUlh2c>7B0tRSCmwpSYVDn;z{!R+60a-TG$z`C{8o6=OR)C)XOi(pD~YvFOF^*;WeQ -O=nKG-Z+ZkELITPo^9`zi+&0>XIC_T^G?khI{Pz7@wo-DTi>tRFL>YF$XOL%ZpC1Np -F5g4=c-R-y?6w$0Rbf;?l*{!ncW31Jq*qfzyx>g{^di`GgUk1#bf@ -^0`%82tcA@%jk8X=hnZjw;t54NCBEDSyzq7r+!%Lt>=fJJQ>-9UKa;lSk@fYW -O`uy1~f4ClAH%WUI@}NvA`6qLz7mZTS?P9x?d56-#0j|5d(OI`78o!ZybAAl(3-@F!sANwa?`j+#Cni -F~>i$-2crWZWovSl>T(gcE3I540#@_xqV{3gZY6|BC -Q{eg*y3z+XwNctrpvc-w9e-F1wiyb7!+rzzdnme}M*xfV_U4m&eniRC{!$XV)H(np}Lcy_z_m$l8VOU -!)<8oyq31aV>8*gBeX;*pa>X-C2H%J5lr}*$eJ9GjUlqni_iZ%fTnnuyiL#M-(E~1VSp37$&^%1B!bI#DIxuOl0nKu||sne;BA3%X0q7z}nPe -RZdv{jVP6~%PFjUm)BPzbdUYB4N4MLSp=xGty~4nnj;w39g~GzE#87c?O{O$5rQ!$Di>Kuk2~2&f_N1 -3(#cTy;WUEfa=N9fk=gjYJrsMMH)T{0f0lSPMlP@Eac#CWTly6g4^moz7RCXs(1KA0v^kMxu~LfM*n8 -;V43<#_mKl0|g73qc%`ffG-4uuu4Q8F@VTiCB=MV`3iOxK$rno7KYSOSg;82vq)_ui(PaQh$T>yw8T; -_Glqa-Oku&eGK19~D12cxwA8e6jg@N!KO=k?wv5r1F>D!Y$g&nAZ9*N)Y_X&u`vf$1h&t|ipgwg1(3( -1G4)EpfCu4aR -9~v7_T8iNO2&=0S*T$oKWF7CtQ#_fPi<{q8dA0!}r>4iKUjR$@dz**YLfD@3jvgYd-|#)KLr90gb@zn -%u78c1>>AA?Ab$bucHyVw44HU{F)=)CpDt26a*sO956h3@{wTnkAsn#W2iiI?h?mL+Zq!q=iGQhLr?d -jo_*qY+K#HiUuwdel?=1rl_g~I)q;X{2JibAn7!oGOqz*4dSFBkQ&5B6NI1`CRmyfQj|X$9OH%nX#hw -=fHVN40U!;KXn;h6aA*(+4f)f+p9YRJaHJte8XWwF@@az{+8{O>K?@=_8uG2h@o3>&3*TD!*21@zylU -Z9OIzQ%B&F^|J80SE=hJdOpCphZnOkU9n66ip0D1IVVLg>ju1gAN@v(#@%ZFzEaUGyxq36nI?#7G>@(R -yKCH54!|6Plwy8W0(#{I*#SL8nQK5*m+N;Hbt8Vod%sQMn_$~o~QOy(f~98<)E#io;m@N)}Ubdm=<^# -2rv*}AizLK1ECKZQ3ralW%5HP8qGnmY!rb)C?cV#0qxLS -D(%t=Y_Lc|Bb7P+7{0E((vi(dB1Z0_Z7^#5{@tb>Gd#%|1Fj9N0zq$ISQzQy!fGtwuMcRpz;=r?NzZ2 -=upK{;R+yrb(OkPYm!QMW@^n}S6&{e7-Pulit%UHiV&?2>%(7P3^t%c$#+=g{Yy%^k1NS`imi{TtPX3 -Y4;4t`nrFAn@j!!du@n8P%N*EHlMM)o{hEjB6jUIiI^{ow#(xTp4;31}teiM3Bv3@}l@Pj6_*Ess3+L -;_?cGvroc@OXqlPRR{&HV0TD%B5QZ7s`zQ25sRz0|d{Fn06zo)1Fl<6D8Te0eoExVa~dvV#~wPSb^{xmV)BdV`Xudf%YM -Sp!g-HK&*>>JN^v%Zt1&}#eny5XpZUgL$}ld@^wZ@%0(LF -Rr~ma0hMaKxvhj~?RT%Q)yugjmiSuk=2HCk{kj*}PFg~NJ^IpCqIGr%jRgLX`PeK1X*`8E2kShFmYn< -O*dsdj;2UY!8#%DzQ9KcCkBmL$%Ra`|j{T9x?8td@qwxOWr*SwpYq4pB!f{dG_kyC@Q7`|AZtvvO*Xq -UcZ1+XWV;id80;-8;+n#Uw?fXT4Go3srne)m1dv5(-w$4;zIx$vkorbT}o8DTyS*#qT!-0y)$^QT0+I -vkseABP&9lyho_D+w+5?A}S8`Q>Y^$uxr)Ax7huU@@>|NiW~f41Jdc{O)k_Z6&p^-CO5Z#UEn2dTj>^ --KLad^a_`=}^A*>*0xPs@9nu?s~aI3LNeE&I`n!qiQ$?gQ`~gax7dPJ$w5w;w|&!^mL-oQreFE&R`E~ -bHoRvoAs*aayD<@N`P0rRI|MiAC4gSB_&jvkss#mlCnme2kP=a+hCcdg9cs8``r;Lxn^)q8V!W9O6EM*#7Sc|U -emG{7@9xd*&kQ%E=G^&YtA33@^}*8!n`I5mPr`Z3$|D!tp;p5g7d{%Z9Vx{aZy1$D>IZ-@uAd%x`)^L -DRxsZ4@!=k;`zIs&>yGrJ(EN;}Jp}vyX1v_fH9i85Sx5&0cJAIo=BFV0HS9sjbAZNJ8oy1tdNQVtXrL -d+C@c3N)IVXebH-k(-;+Fj)W<(zQZY9+*glZ%gx$dRNfdBv`0001RX>c!Jc4cm4Z*nhabZu-kY-wUIUukY|b#!xda%Ev{E^vA6J!@|pN0Q$I -s~v`Cz?njdN@vmTz&8b;NMkq$V29Oy(g<+1vkqRn?E_*HDx;$sO*NKpe5BySlo%-d#P -Mm-&)SCiA9lNiwr7`&^evws -`+3gq`ZV;!~ahOz7CIVjSmLRYzH^aXR^QI%HK5#r)_hDx(;dT@6`O#Yysk*T%OmMZwEBs(2@;$Rq--`5~Zw&1-}iq{n}mQ%!q -sdqXzuz3Cwo;=1f6N|V_{aeS6fs-`USMO1SD*}M4K?Ck99j_7}{=-)&7_k@~uPx0TEr}X7Dd^tTn-Wl -QlPVmd==?VRN`t=J!q3`N1(YB}C_H^4*-S$+sJ=1N^blY>?_FT8U&}}bt+e_W{Qn$U*ZLf6OYu)x*x4 -qMC?{wRtZadU%N4o7uw;k)YW8HS5+fH=bsct(}ZM!?Fjs7~l>@l{*vi#SGHf=72Xk0Y~%2YK;^NhDUS -M7iM4P!Xu3y2OpVxXYPh*dQ&P`r|CmXth3>10thV{yrGzuWO_mDE=X1_u@ygQ(UZh@eM64wK3PvC5lt -1}$}&&zhJ6NS352Uqq<_p=4YtR6vOpX;cH3FDqD9&E!H5eAUEP4A-Luw`h$;Q&fTc*K8f{UW|4x*#R& -xP!3nPt}p1YCae3C66K-9&dVZ6d4KKf`#Aj*0qDLDlDEIz`}(yxezgO_1OJB|?`;p*6I^ -|9mjY$?XGs-JQ+|NGN1zaAn*ql~eftehE584aFN<_WmS>acvY4oj*sI8sj8xFyc5X?^hfMr&iht~>mO -a%%5d9@*4uhf9o3dC#G@=mq9+YqlqHQ-QzI8rS~s -^xe?ypGj?69wW#wVbM!(+%+wDrl(wI{iCtKAECP(PVMmL@4_n|457RT3C!@{C97MzU+~$c>0dMJlny4 -pC8e`ht%|fnqG=8FHeYZ(MLFnVlez@5M!`y)t3x3Umu>e-+tzclUwAzzYC)lr=TI&VKblelFz_R;?c6 -7Pk#Y*HIQP^>-EHQ)Hn#cqFxm!x2R^boRrd4bi>(HcLT)W5;Kpq*w -&{uByqOxoWcO3e_GuF@RmOB;Sap6OeuZ8NykXQFe#epvMMkI8E6UG;^A-7${#*u1SqEed=dF{IECBi& -6N@IM@b|&7_`8`V~*-L%A}waQtBVSTv*CKz}$-<(dxI#ijG4$g6}#<6_^M`eNtua^L1)1oh;Ar9A5sfPp;=JhCC|8p|p<1O^%QGcm3> -zm^n)Cnnm`{2<&n67FOwnT?#TzA?KX1uT=mtJcI`_v#8nhmbcHom>vs8wtQ!u7o-|2o18kCb;t3 -7xzP_zxS3l0#uSZwtcVi2)oF(qF{q#jlLL_Lh>H;$?j3woc;_$_l~f5+?hNeOAUk`N+lf_)QYQWw?lK -+qi~lKR8x_|{YiEoyvrY;2_DY6A@|wCa=0UC3|5hM4dMY-BBc-<2&UD14s(4EsYC-UR9Q_OyzD;?Sn@ -6BG2M4JsgVJ}&ny=Aqbm@Gb)w7#nZ1KYq#^B|0XY3yZ>QXfSY -ixWT{#D@A$Q>y6QA>6bS$nScWQm-C-Kyw8fJR@y0V%9sz?4?kS5qH>|7dW-!vFRxitLhLnTXLt1#?98 --Tu&q4|)c1t}+8MAo%`0A!-xTLrCPL1!0)ol3{U3jXfz`MmAmhAT{Fs1;#R-s%dce#i;6GtfDdrj}BN -aFP%lY})&%7$~tl|Tfm+gAD*t@jK!7<_SHL2%lHcPTOz)0Du1PY?tW)5$Mh9(s$KTyV^^BAB_Bb?JVa -o))ByjX*=W#tm^i$%bFz)qu7VMONkDypKoE;TwmBy_K9w2y_{mtmXq94P3P?5>4kkJfvn#~5&Q`V!^# -mgs+rwo$MXj=CKK3s;!2==Ub7d(V_&=%m58G7u#dXXk*(2}HSNzjqX6!nvt2kD-Q9LIfOomB>ht#fQ} -E`?ANrZ{deT1%*PcY^`hr32DGMOtPrFy9Y!Y0d-94MM7s~ev{02Wvov|2Nb%fgd(eR5<>)go?r7U`3- -!AHWGrcM9f=9*8nVzAT~4sw8WHl5@yA)s)WCbG>YMi%2C95iOD5We4~p0+Q3l655`3(i-p2C&eLWol2 -~byaaLnG6aZLp6Vca{4gmNbdL$9Vc2X}nI&W-pK$kweP{aTyf -Ap4p%*!P}{0#y}NqS0}i{5sCgxT=v9cY4O`WzLBIh*JYq|Y#F;QsmkorrFo_y0B4@!Zij>cGgO)%bt+X50o -I5fPp{1`%e?3Q1Ax-Q*lzxE^!eG^=;<*K_ss3tVjpBeWd)4Qfjlb`d*F*WZVZ!6z~JczdI*MN$MTc)T -qlb24p=|U^XsNiE&X0o&quF%VCZ@=xa;5z_1u^UgPG4dje;#XcvF_354>r??(@1ouw!j(a>GN3BxXYn -7_zDVKq|4F&@njm0y~o+ZmM!cNd~#cFmz$gxU==x4G -L)oQdO*N-AI`6tJn-H`U$jfx5eAvJ1MeLJL{IET!i{FG*0Q$9Vf~*8SOxPD6p;IYl5x<}C0JoS -Tqy&Yqq106k5;6x`NC9mft8SEfkle>P1I5KhtOt}VZig!)@dbiZ4pG719!CHxS!EYl%#kpH)dkR_CB0 -^Iz>a3(H~&FVLTY{*|<|sY5IuFn&59eImH_a1@uxlD3%I>0gJyp?f>?`u@(-en3-G@d2)^WuG||$g_W -2BY+D+4db3|tS{*KoZte+#4b=Sh1QRdbMk8=HbuAVml!spY0qSulk=@!+*dToFtlhM;f(6|u!n5$E?i -hw_S0^hYINxLVeSCm$X1H}>L|`9A<6iqZEioQsQC#Mg?;$A8^lhs{Y!kD9A$}s$$L5gxjJE1WelPMmg -76&pzjEQPgUh|l!Lh_nn1<#f_|H2bGk8yCS8Oe>vfu2j=TxKq#awk>iZnYNPf{|+Qm=*sw7HI+wp-cHS>w#n -b)$++Zy0#rV~tIpja`hGD+eAm?>b*jY%m`ejr@)SP62k` -!7umJ0PWVYi`}z*GA4i(Nztt5LK -%v(TXh&IwnF>llR}4FN=*#>y0;r9h~Le5cwa -qgpOmauxvbdCR@5?fsAr}+G^gsAdiC|(0sn_)(=u6sm+AVX~cM+nC|I%4ed)4@(OvqM$fGsSPXAPUAY?ruM>ONtl!Bjd -JuO7yP!Mv^VM_nzZD7Vjtk5eaB9%`QcDd67;>Wj{Juii^!*>A -rdycyeRcUnL$Uh;Y3AiY!wkExsC?GHUq-6z_zBP#nI7VdDE7o1!@4da9Nm-$%~-!_ack$?ujqeX9`N=dLx|(Y7PxB9_h -KJ*IcvkMy~Rd%Sc(TUwUR7bif^vCIm#NFG@K^cz=V6{*oC|i~t2!kEm_BVCQIE#Jn!~_ThQR%;F~y#P -P7@3R0Ko)Y3>C=g&kIma;Gw(cH0g;i6{XdCH@@NHBcHZ)-Ofin3@9L?ZyRkq0M8slG(F09cUA@$IlnUJPbz)&?yEDl}3c0kJ< -gH1G*^QNSHZ;UhtsDzZ0sEBB4BpFa4;1hcs~yy^%K(KeBdgjhImxq)LgIl>mP6K)62O|6gH1=e -hroT*(pu>berjAr28-R-rHIJP0W0Dq8YMUM7nqn}D?e{&Rt)$u&sc{g7nlvF+Gffl|*`)o6F``Ce~`d -K=R&GhQE{=km|8h5yrK3+fA4$7sdmLG(xvTS}`SUL}eL2u*R(kW37oZ;M1Ow+xldz1~qdUTi2p&WbXD -bvTK$GFm<4L_Dm4#;!10kewu=#_N5C)fbVQlKQAmpQ(zHR*nuaI=Xn|uP%THvMXvE7vKaKz1c}<8c}c -1EU8-ZCr)`tEG^m;5pl5&7=+F}KYb0nsTMk+aA_x^|@1!-nr^o9-42R@6(s&a5*K2p -yq6ST%U}7cHnOZ4as?@yk^lG{$uKe1aS26OdyIZJGpSbe1c<939<5>Y4gbTIaYlv{qV%{S|HZ -do8|=UuOZ>Q1kb8+=TuXz>R~)d(!hQ5ccVF~6?&@`~yC*z=-s2YRxDS8MR{d*(AptR%REI;Wn8=%V=3 -UV8^*(;QchAVdV+aTE?J7|!*t2~-%op|GSUzxa6~a)wr_P~+2>cY5UqZt=ZgG)0QI)6eQ;phzk5woWE -E4oo(II<{XW=|~JGYWj?aGYxHCNZ0?nuk3S5LGTS_EWuXE8iVW;%m+Wi2fIM6N?T`<_|HbebS@&ewF+ --RO!{h{n8Adh}SZu;5N#Y^$!@p@g|^--CAIl_@$%U3Ax$T~^q|8cs)jU4_QWpN4 -tz%)YZn(N%jcBNN>6a!%w35hFl=7afG^Zg)l4!6GD${o3jX+1eWEnB#5T*gt!@JtATuYvKG1uSFN3*3wYjJ!}>ivhv2}OFmK;e;zS$~cP!Xsn}HjY2v0vy`}?l0`Ld`9y -y%F>IT%PpwXA%=qe6LpCPOQ5=MC;Rt_#W-REI&cwt@mdN|B^9H3~xss#+ -CoyJ!{$>-Fg86C;(@nmdpT62>+r+5b!*$(uUraun$gU^~+e5#@VcTKK*Moby*MfVx7XSwx4%-d@u7&n -@$7{;PX&d;anXFHtSX>`af;c~O-wPmfykWEd%umjk7gcF!Yu8hTaoyIT=c4v>&lPgQ@0s1Y9> -)!6vWGO;3ZiSw>Rc52%xhV&gLwgU*T78>V2HAc@GXN)HXF9mW{L}aaucKP1o4UsT~TGAOc_^$AMG&49; -z(mH>`(kN@4&RmZ6Mv-N(d~b?PKW2`nVD^M{;S4`7tvU+SAo3|SF}bL4678YxbBYco~-g1&v^_X!WG> -_C0*1L?-dkPcvA1m!jtxXPemC#wxE{`QYBwzs75TgT)<>hd4wiZc>pj_03;7#rg=!5)`F4O=R-G9YG) -IDPN6P7qo`L|VDmTtbc|&lW#4uqoYN_9cJG~iO@=3fqo`aowp`d3K^Wc$b0z|U$%#U54uWR8KNjc&`W -N1%6Tjh!S#E&2Q>>*`Z@BT&GUT*z`fp_J(S1Y%yLD#YqEzslD^Sj4k6opYv!-H;)WSjPk3l5}$s@kWDgKUk -zx~U!p5}7Pya26p*EiNUGzwN=bNfE>IRm>Qx6VIFa!yj2CaYOcBco4S6shV`hd7vn*8(RYm(;?Dt -Vg8~aHSdM{cBqz*p}_ropUuYxMd=hxqdI{#ZKLzSxSYxDxIhy%{kM>!EwrD1Kkg&W1|V_)U4IH4mJsZ -m&9-t`iNX0sdgDQquCh6f0QMRVcj7-59CQN%vE;XK{N5LId%@AOzOqtp%dsZd=U)wE|Pg!s_r3p-y{- -h^U>R*A@Ws)e1S^2XeVUz%lco^P@Vx?tGf3tccDu|dv9=|J*DmSy!Tsll2(dmjuS -A4$bSc{Zx8DO{O?Aip5zV)Xl5xt%9m89H}v}wE>>p>Z38`jw7Y@pP$dvToMf}}Xb~FlojrgQOsL<#Y} -hY6|7X-Th=H+1`UYzkaj!Wqka5Kh`gixjhnO1LSgIOC%Dqn~M9q?=(1D|WoQ6nW^ShzCI0oq3n;ih7y -h%dJFhl?+bXlQ$X<@>M`9sHVYu52VN`z)36}SW>$xQLGmpOEAR{<<%Yv>hASu}*PuzP-mO*IYw|9T -Vm3g~n6_c46r79~Pm7uxE8LB~PPaDg*xr(Z@GFmJnp9}DK8L&BVb+3B9=3*Qjvl^Er$@=T*Terx22aF -8}M<`Padj6dP;ED*=OkmgU8*)J+;-{lRK|+-8pq}>dZJQ&!@p;qh5Gs?9G;~)E#ha_J#1X#YvKJmJss -`n7bOBw`-+u&-AJX_YUee -aqxeLm0v^~2eC==iyqJhp(ca>5ZpuKVm|HU-;iPej7j1-gqBVu;eAQqbKjjPkPboqjayyr<-)#A6M-TWELdBuhXL)oawSGCbh=;Ac}0L-;z%$ylSSHUZf2$ -{=$u*GawY*g9^lHD~bXmH)^(-)!l3|TuDP+M!~@8d?|?-IWCPQdZw{@#FE<^YHEx_} -0LcdP3*mAiirK(Zbdqi)piWF?ETW==kEk_IMc7SF`E)w&S+F8t- --SaL~ZNY%Cb5H))Ca;N|(ccOw^nfgBSbJgS4lT|a_tbA!@~QFZ@EF&@#?SgKY -1>GP;EoPWaM?s -YUz91^Lwz`UC(xpQNtUt)gPjVJ;JvKFn*kFpTTT!Y~mLqske&;eu&F>hox1sLeaeI*!fxJEp|j#@e&a -bky|Qi&MGF;H|_wp!q|Qua6MHTC{*DsOp9@@xZBk!^etr1E33I-hF@8K%#Mtt$C=b*kWHY!gwZX{(cXtbRQJid}V~}Zh6ihM!C(8mbT>UB -fU3{A!~Qg>Ru%Mw;`@W#W~3pKStJ7N8KKv8+ePK50j}$QkwL#A^d$Unc=ZSSVq25)e3;}czl*~x`@?| -r@`{bMi&F?pqYO8N?V8aKATrw;d6_TQsNZ*m;~0Jk#%03rYY0B~t=FJE?LZe(wAFKBdaY&C -3YVlQ8GZ);_4X?kUHE^vA6U3+ueHn#tNXZjsbdZw0JNp;%YKGNDdNo-Fu+efx>?`E&-@uf*fVoi}MLE -2HE0}vQQ;h5aq43apB=*&ho~0kpf4V3w9*1`{xSUQXl#A`*W%g%jjfhTs7~&WPpbk@(2mVZwn8gvb$Fj -}62E@Uzg7yzkw;~zOZbdGNzUNk4F*0dJ5K201+;ozJ`E%cG|s{Efh4$3XTLROknL0t -8$xPU|&qpnUAL=@9JH5()~fPn=LQsuBwmrU%4(dgvIFaV4 -D_~W|=I~p=%tZa>_T>$xLZFVG~tgcp3GyoOF2bJ&vc}?SF!kK}c^K4&=3u@$;m=dGRu_yGxw}(LR0x( -A}016Oagh_<9z@W_4bzvMp6@K7N1Wb9z|g?9B~qyU -7)>zi*y6>K!M&p1$B;9iy^3u5ePHlMW!D0UB!SNMu7aF00{$HN=pggh|kLf^lhw@gt0{E30TZ6Oc|@j -WM1#z2~ALB+$*!URBxwQd=Nr*_T2+F07HwH+7;^2O5`6qbHh%zur8=L5pm*Cue7J_2}tB(Mxt#2#>PAx5^Nbu!=1 -Ysn30W2ipn|C3Y0Xd4IjdtSfC?~5d;(tq{_~{I*iE6=?|8B#$JNzoZv4V%j*9IzPy -w5>!>T_p*IQb*)U9{ogvLaKR{-%4ich;u$)57+CzDm0!0IZpl`;aR~fbIe5Ga0AOoi&x|kjdaFq^izl -U><35GzuK^XM{;CAFWJsy%yt!_nP*z!Ge2Kx7>m5mJk%09n)rzi*Yft{Vs@!PYnj*rQ=Ckkuf5BM5z= -?H*EZ@n`scM8Rx9A98T9r#nWTfZg07@(z(^2?9Ir1> -%pB3~h@2&9=AFv$`1tsVL5A@4S0)*P6#0+m#yU@oa!>1gd10*cb$OkOvon)^U7Vel)XCX6OymB5P>;r -)E8gYjU95X?ai0Erf&V_?UsMw$KB5M%`kAElnf&JS+QdGWRsSxD{at?ZkJ`lkA*+5NiG3lz`LZ^#FJ; -xQB(bmLH(%E#_O-0~OcHx0zjV -2w(db~oD$d~n?2KwO>M^i(WVYV4fKc#OSI*DP5L|u$=82RPJ>)vPN)ifSK$a|Z3zRM0pb`AVU7{F}qA -&l;ri5`Xu9*>jB^B-RI&3Hl(f1;W1()ybA=YMQJ5%Mwg{GO;7*5hgc&)oJ>@A?<%+>_H&h;EOL$S3lb -7xI^n1cn@GG18fc-ucMBQNwrg69z^P9;00{NdP8em@a@15wivIJD)Z};FzD_VQelk7JP(QTI4SjmSKc -NK0Lws!qe^e?7WWlP`F_d_ZS^}PUwe$rK_15+$Ip8$2;c}C=H0H(tG0h%f67iW#=AH -0avx)%+p8l -9(>D#mG}UZewa3XsvaRu`KtapDSNp<6|1M)MbEwX&eY -yu79V3hJnWPHeQu86}=XUusb_*)_OmgBxu_o4)f@z|`>y(faj)?4K68_VQAMBA8iF$2ls=5>bT+h-!= -ycOZ(z>8R#!7s*<*cCqA)CZ8wvyaHHW-|uPc2FxyNr?Hri2(=XSxkItL%&d^ctNn5ByhVB6iYkhy?+> -mFg*@<)}_P|mnawX;;2|7GdhviG$eIkJi4bS#`R(pKZfZbMd!B}C=iRjolvj>S9ke3crM@@PpIiCp5q -)~1~|0htUqtchN;lASj>KSbV5@9on|x1*c*;wk(CW>Og)J1_sMy-rj@6L2^toM5fn{H4gK)e_6fu+o_ -z~iW61>`ON$T=bXqbQq@*UeN{8bKHX~qO;Jr;)ato}(Oc1WijHpg5g?t?0&`^GTS -%|uEFr^$+BbaK4>*q#aoV!BEQKraU|D9Uf(Wod3;JBy{b#4-Wz0ndF4YAAUdVklgO(+Ps~KLSR3+~0e -As_sxteCB{yH2EVa2$)k&PHCq~C3N)^Va;Hjg5>u!7y`#m09=F4tQB+Q`!6~zi+gh&6stW2-=UOI;sd -ij&dPHAHAb8A*-+FeAB&?+_1H5VQO7tWjvBcDG9Qzxk0Ml6c-(cW%k;+Zj6ZV-q;9EpRSdXJtWq3U#& -6(L!FT9YN}O(vnlzoOnJ})`((zADiha&;?x`MYlyrZC%B=(hiiU3|8~}sKS%qnipsq1riP2u8XwIymk~DJ^N-NipdG=9R^AtmRms^ZXgC-HNz6>(H7ALi)b;)$cM!G)2 -(wP**QRv7-(4-RO84|v~z?!>$ou6K-6KmzOKEK9UP;O`dyzvV~6-=81)KPf2DP>3l40$1v2wWdxDI5q -AibX&{aTgMst&uXSt{-L_1kl?HuEX5P!DW6PTpZ$N1pbfAT@7%uneH8cHW?IGSNwU)<%|7sx{IQ8;|> -p!Tvu+}36%_w*k!|)t<_WlI;2<_4p%Df19CgBbVN@}BQ!will@@a(kedWnoo1 -0PN!nKg2yQJ2MV!ujhzP^#;B@?1kpxlyr=LqZcdN$0dp#kmnSTlTURK18`;=CQRR5#(1I}w~i!oogR@ -iBUgaX)TZWbOYjD1DemCSIX$K8!fBipH=^;JUPkHL#gu@XKLNkylKC~kEPP|>>WXP8?(khh5J0-Od-1{w8BM<2m()knmWqN5lfFb4HLp(rU -mnBzJ`%{I7{GRo)!~vhe#U0L|-Hg^dvXmtiw0_+W0G{HzkHSd+M4&LKCPQQ-9iDUUYiQST{=N{QRU~h -U^#26LqvPc6q}1NLMwUgyg{+a8dXmlHWaw`zX5vP|H#C!JInJbm;U%HpYkUxKke35Wxe{M4mR^P>I=Kxde$U4`)4Nq4@MFsB2cB$qH!E6^t?OB>-*Lgal@g_GKm$nq= -UZ5}8K&}@jLtNM%uEl18K9YU6``&sT6e;NGj@gHSu-IqV4>5fkH{vv^;Jaw9D!{i$Tm^|6_Js9KaR022IgvMs%Y(G$HGkG(tN -g989nHi)68yy=DC?Pk8H~sz!so1qK6YY4p*NRiV;Xj4f>6&*1J-|N*2q$T3hOz@zXtUJK$_O -o358+`vlX7l$lnO?kU8yY{buB3taJT+Q4S%8*8|8-o;}!rXtK8*nu-$JVh>93te@#Y*wk5;;NY)O`j) -&0Y3)IGHr4-tTTuR#5f0TK26bJ+*fOr#5B@1M}N9RjJi8tC`PDVi%?2Kf=x-K+_}MUqHq#tkG -ag5u=aWnn8kSIVP#d-y8C!;@#U>hgY5z)W{W?hPRP}hJ)LS+pI}0!>ePfdt|R0w78WvahD9H%4;U2QBn&Crk=Eb&@3 -SAN0wjowL-GLO8#NRv^s=Jr6MX0vtA1NEKF{F`W`G5tfrLPT{x({ZlHF0ua^&+kXpN#uutjVb}^w{Ol -Xcx?P3Di&SJunz-di%R^yQ~bZnlx;07ufVoH})jn#C{muTK{V%%JGT -RE<+Y-U?l>i1;{AvdNaGm~qYBP{N3oAlhw8pY;b{uP3reQNAg`Q{<49$f5EYShf;IpbQm6R^J|BSbD4rAN6822Isoy!#&JvPai-8e!suP}>G(Ofo$+Kj -QChEPkRNnt6W?Q6+p0ons#5(rF@pu*tzvcdWHjmm_ZrR>r7s?-iBBEP)q;TryWR%i|olVVN*B1V)9NBOK-@Q!8Zp`7Y%5L=S7+Hy_@FYw*@z -=r2ZI-7p3QK*>UM-m9wRr|Sv(&wyNXE^I+QVS4g1R=qt}7p?~x(buGo^Eyb_k=avke&5ZbsY)mcR7p! -RlA-^|C|RI;c-tgxy@Rf$&CYf#XI)}R_0UNZ*8xQgwCK^?AaPdV?lv{=u?H4{w@X-h2k)a -ZhxH79X=^ClQC%>D1M-7?M~O`W`am2}GTl~zyV8cC1P$F}~D}KiNqfj_ufUfV6re?*Z=s-*D%}{e^~`dii{0otDLa`VpP@;4C}Rk9V`EN~utyLU -{q1-yRUWGrc;Xj_KTv^ZX;O7lAI}?vw$)s~CRdV#}oQF!G!c-{j)Kj}fs|dU$*f?pX+smwjy@CAe0}z -DhJ|Y)5y=Z%DhhKJI{e$JJ~%rW%d# -rhm?XEp=e%^G){kL8@kFdCi|KgwO;t)x7$F)#HPoI;dhLn<)>i3G(KN64QDiz1kxD^-9U%&$&~Z!)iu -OU7Xg>t)I`=6W9;;me`_w2CzXxS&(w8)Kf~e=f66SC(m?UPD#{xEG-RedY(=(I0+{?kr^UEJ)m3YunTTyJqIzA -y1Iquy6kO!Zc$=xtJ^}nAcgW?DvYWp9TbMU;vtDUke%EP2dbwqt1kXK%i8^#4`DHN()6DH`(yRJ*6dr -eZ^G=sqS6D~*JS(~w)w~F?RVkjv3=0^bdj#kR)VrisOBrbs*SDRTbJLP%Zz<+5BwDboYL*I)vVV~G;z -vNov^3jVB#(NsTaeu={ux%h(td8rjadi=HD_aWFWzIc#< -v3+k#RJCjl9bD%*XE_LZK&D?SQk)W8&``gzL~9i83wZ4_NHd)w%WS@L-r(6jC8I0-ZQkKhi`cLch@UM_|n)fo(-UVI_8-2N+*VnB|G4saFXWLWh+{r2vTm*boc#RdGd7CWpDQW7w#fwphMd6QB96{} -tbZ{4Y9v2qV);P4Y2r2*yV{NrxdnUpFQ1DN_5dkd&m1pJTDlwxYZ#mOd9X$N2e&$1CsGe1~~WdFP89k -Y|OriJ-jgrc-HO)swt)ol3e$>heO{*$6yUTBgwJ_Pjl*kjZBW3U#LE`4!4g6O9af>i6*sXuewxLoKQa!E>)W2x6o*2X*)@+GfAz5rjKolK{;IS -AU19dh@eX?5Vb(GA`s1A+ur6fV8JNbWxyqP(?%=XT?SkrsVd8WMiRTd4EX3h^G+n6*5q;8?9&eMtc`3 -Iy&Jj+R5ra1SlM^)X_8(6+BQkw!sKr7tV)tTuef#A0T)II8(s%&A*O|x7GmBHh*@aYk1adg>ST4E?al -09)#Vhu#-5(^WYleb#uqvN;pOGB>8Z`>R~|3QPUhmYlnW2aq;;iSmLskgKvG(hShnmY2zfiwwWVJPQK -i;tp%(sH;qA8ct_kxJ4L*i<(+teS2lz>&I3ovrDwavLhhGWV`|PQ>ROI@)%vfdF^xOwt?P>3`Yjf$6* -XT;RE9pztV!w~nw~$QiYL^5DfI -5+uG)Ml_-%viVg}@yHJ3>u=)Pl37J8{31+(I30f9!9TL=vGRB@D|||hwc+CHmN(c+WP|Z_vZAIpBi9^ -F<5MG|PG!JHU+H?VRKZs8C9?pd_7nmCQAbb-nsUhV|4>T<1QY-O00;m`Rt8f(ni>Z01^@u!6951n000 -1RX>c!Jc4cm4Z*nhabZu-kY-wUIUv+e8Y;!Jfd7W2#Z`(Ey|35&!!$Cn&DN~e3i(w1q0c#p#?a-}2Qx -t<6sI)}eY-Capsn~AO@4h=yZ`)})CxC46?sxA8XN6iq9M4Kq7CeqYEOS*DU{kHK((u^*4j~oyLJK8BD -5XeL%HvEJUa(9b9vmLb2*qr2u4{ldDlId9gRkh^6r0P#1Hg}^OjMTf#2}oG*feQ)Se^?xKRn>;gy#lc -+1J-ap^81+Tbz|DxyYmVp377fkrwNk%<#2|NzD-6{`-um#f-jH=oQs^nMK?boJZFgUvg<~@H;RKDW9= -2GqF8HEi=t4&ep!2ILX66#Ix7r|DhQD#WBk=jOPd@Uhmio!F$8aLZvT-&Y4LTyr6eNzbjGfoEiR>34G -Ox$B(DGhd1g9Gay$&8e(1ASdUp^RI#ZZ+x$7%pyNzQ9ye&(yLI{=!P|_PnJShVq%u&^V^D!OpydGnWB -Kxzv$GR?jK|{u^g@+c3R6xf2`lFd1Jezd1;=-pT4C6=iQtulIhT~OcqBBeDlTAh19>H!AWBVA-`|W+& -VMHF3ZsEb%z1jPW_1C8HU+-XA?lVakdSy^Z_u+cf*X>6|5J_%XqEP1kEQfMqU1+%iCGvGR5IdAygPaSpZE?#3Q@Ozf|PrZ-Mf!@;q;0W?fhH<=1g=W)?kBH_ -36-uj`nAvb(?MrQ#Ot>Gf!?uuuPL>|Q2M&_+wDPYo3n)FW@c~-6Febk|J)M?w9esALQpNmKXkGG)vuD -4yU>$wSA5xe;Olw{|pmft=uI&RmNoB^qEJa<$*y{R4{{Zn#QC4-BWT*@b3(ikPVrt)cp7#=eI)`0=&U -qp*N%KPGXocYVl7NWv9|=MVBbc$B_>ONh`kG<8#{9^HHk6DU(^VB<$~;3|=p<3{9+4<8$^k909SA&k5 -Ly9C60U9DQ#DY*VYDbUvB_ga3YVv<5OX0}=0Hf`Nha>_{q!?7WGFZe5veWdk_;t0jE?h#m7Ah-ww&?R -_hw2_Cz-Os3oh~T#rqc2EE9Wr3!@R(lN#)gy6-s|uv!SL!-PpHYIFnYQ7G&NR-c-b8LZkVPPV9VevOA -DI0?zYaqLr_hR*ttA9T|^rr2Fegt4KX+_p#9K|r!4ju)p9y3Hb7_Ie@JR3|kZgHPTJUDQIFb6>bb8*D -s#;=8g4oP-d>4w9j^5l%^*iM~&Km5xEs=j-J6cVRlFc43G#8aT4cA8ZwB#-*hTD8}?-4>{39btFgdH| -A+Scyn&Zwni+bch`3=L7jp~+7g95=wJ)9O^7OLA*dD3k`bw}L&6JH%5*EwTV`u)w?XV?sMeZJqxev;9 -E*CZhC-MMX$KTdt4a$S8BK%YQ!V#zN3In`Rn)qGIBOYBOqsamSy9kfrQtzdA{TaO=oOQVm9z>lm{Oo -{3X}V{!agv6f=1m&-2`g9*GsWMD%M%pT>xivM5R6uF(}oJ9#(jJx}&b^YH;EPT@ZKsO6MKvO{e}qlR? -p774PS->wP~vjx58_S>LJT-A<`D%6DpsyOj}mQ`t08we^s49I$rYuDB>tiL(zUr48--t9KW0uj%=mKw -R3vv=mut?>eO5U|IGl32XH#)qFD2zNe;kL5p19{i;aq`Q+?2fZs=Owx%7&E_}VC-|W$g@%RCV^9JH-2 -yxy((6a1YLniE7=zF%{u35y`MzE0mv-SBIe&8qYd-|PJng?)<-<}i2_WbaB`kYjn)>ET$SuM>)&)p!Q -x=%DuU#ie8m_o~^241s!7Q!pIlWG+Z-=DNBV~n*?xg(r%YK$q4R*^7TgYaqu3Rfb#8Q|)l&^AyzX4h@ -TpSfr47e{l&Fx${IU%z#ex5w|(p6@IP;g}V4T{u3zThX^cfp=Dd_VSF~gQjd8hxU5yd*0SEK@6aWAK2mnY{22&)jG;6a+004?n0RSN -Y003}la4%nWWo~3|axZ9fZEQ7cX<{#9Z*FsRVQzGDE^v9xeS32oIg;o96EWX`>%BSKx0cPf#OBWIsU_ -Lgv@Cff+3oJ>zCN%DB&$`dqUxcCcjvnwP_O(YfFh}$zKETeXp5N%AdyHU5{U$Ap2VxpFTc$5EKlSwzj -T7tI!>~Vn5A);XY!Zw_p6Q{+y!Y6N3S}06nL>Oe+h$3CL&D#_=i9Kp(>STNf0eG;N;?M=g*z*5;p1M})SePU;O8l;>#BrxUc7nPfg+uXJ5_Ne7LHo -?ykswu_hAspJsD*|_GqwJ(RGe4I~850q%-?|_7yP@b>Q4$#Cr|52s)C&;U(J --bUtk5Qy}3+eENw%j-$t3VxEuELBigzXQJoKaIS!X6YRcXaS7Q;|KgVHZ(h(7(>pI -&I9!}K)DUUm;2UfSJmsQ2b^@&vAwKogm&A8AKKjVzklzF|CBj1V8Z#XT+AIM4P{xl+?4jH69F_(35T8 -C4_leEOU!mJe&C3rYoz7G|pUMV#%)c)qFby7=qPySQv3o_FR!D3yMunH2ukmUgMVqqylrYMOWEaUMaP -kyxn;cN2;xeWFO9_V&8C2sD>emB^H>Qq0SAFNjo4{+^n%#(eShJk~0k2_-XS_?li*>88f#sSM|PUKpp -!1n$j4vDk~7il6UVF;>#il{h-D$`%4>G$9EV%WQ9^=F*MiR_~;)SGT9jl%jb4m**R_z^eZ?muaSK|K3 -U@H#^n;A5?$m#rx|IXB|J5sUBFIRcXF1mW_21donG$tV<=ir&~*3zij7i7cSCxC9|cjRfcJ!_I921nC -ZHoAkuo2w5_+K+BscBv0e;2&;R|+UtB8eYSo<5?zTRWy1=yFu?cO(p4J9g>F0lX;fqYXOrM*xT`{hwk -#lt1>=vu!Qqqvw>^GB)YojTo7IAb=tjSt5X9`kenR16x$|gr;_w-e%>khV!|+&6OLh2RM& -z^Vreu^OkP?S&wpEh+1rFriFnk(o@@ETGig3Lu@m;L@%o7y!h$a%dPEbd-~6|^L%?VQCv2W{@xPdwPOzbn@ -z1XZTTWyDo;;s5d7H79@j1Y!}Gnp=h}QdKfXA+{^8@v^Vez%o0*Fp^kF8{@>;TA>6C6scfpHSD{1UOp -&S2FvA?&c`LBr`Eu?F;>-$Yj6eTw{0~=FERkR(gu$CTfVZcy{EwvOYknY;ks_VSid+Cx}A*A0Tw&zL( -N}(0nP>lU9>_aP0?!lft$5AS!4y2jb*^2BU>q2+`sY;E>yn}GrLR9zP+&M~1?d>Uh9y9%}Vo_B93g)l -F6qL2?x`P7d|3d78wW*qFb7Gy%J=xP~X`~!fY+}cu+@-#!RpsbLpaKi1Dw!&)PRC-;_zQd -(@mFKz}*A}-99o|wC(_y>!r3`~8lF2e#g{+n@U%qq-OtB?aORUp!ZEn79vD{%woH%NSuAAIT;+QM3hI -aJ4N_E(6CX1cdJV;Ut?sn8`#o9q_Pd2G7O8X{??^_fgN#aPxdAdQROpf$ew0b>S9;GrhLzZr0u -C&uI(hL;^(MMs9xSYmi^ -ZkPDRR=eluaMNCPAMY*IMl9VEiS~h&g^`)=X|@#6o>Halqos@MSu7udG}8;ml43W~?eYDF5!zH;qgs1 -9KB{cT>apn5Q#4JDj!;gTi1f@>y(v5KA->zz=9AR9sc97yp*p7|K9snP<7SjkH&u{2YjDc1)XsF<0I| -LmKh7&DVq~(a4Ev$}Jl}~CeWq0G&07r<;~`e7V-Sh3uDo+ymhXtPqxvrIO9VCQ>w^nVRMF7wZPWsM-8 -qhR1UA>P(ClBfNVC-0r_^q#c~fm%oOk)m6bLn8m&W;@dmbt3MmEnj>snph8mPMUEROf2NJ8^u%rbkal -xkZU$DM*2EKEI8-W`D$S7VPVW^P -skK^t7l~LeJG~+*s1}pDiB8!>M}!MC5whiK6Bqs8iHrU}#l_%v;$rYma4~#6d>R+SHZF!w;KE)8cQAI -K%1<_RQS3D5*UKQS{SWN&Qq>d1_T&V#W$4_yYb&IGwWy|{TQa)(6qev(ytL>~}-_6M~@O`PbMe97>`6FOyrIGg;r~l#P|QKF;P`)koHqr+`XmEnM0?Tr+B;wV8`LS8W3m+f2;Xjy9EN@r|;GjeMPru`chhr`_Iu`?&IkH#Jr&Pqli -xI=|I=mpW9h|82GwxN0nY`yg%0@fumyWE<-n)3`^UJUAS~b>}HDx$M(` -}nno}vU#kqOMUZ7gh>amYrggHK_?oQk`v$S$+tDV*?Gx$B_(|K&o@=H1nlEI_4ws*EF_P#@Q{rpE1lm -asVw4;%SS!B-ULZ))|)QR^qQSSSB&SRdWteb{(74y(8OB6f|{`r20IE}Cpt+URU6r(P1QGy3a^JQro! -c~eJc#trBuQ+V+X~kyaGe*Kj`O9tccZUpsClx~7fJLX*F1QTeq -qi3p|2Nd=@x9IaL=e5YyEGw{^re_`}_OX_k-7QvUt;*OeSw03Vd@WC9>rP@`E=Y6hZNy4`)rG^lsrU( -eHMvgEC=gU`{h&)jQlDAM5e{3dMiR3nyatl>F`&BO!n~BQBX$y_NjbP~}sI;eGIoM7TZzpL -H9+ITnNeWZ4jY>qyDv9E7;h}9rv@UDf%3xn?ka$h%%hcOUkp)>bBtO5@N~wdgBFlc8UTzt=**1Kz*rw -F6zfFJSY74Wt?9_PaRY|}%v_sF)c0=umho ->B+7tvxT^rqzmKk;M6WE7@u#w#w4qN+2`kGH+8#KiJkUKe*dQv906&HuaIKncUW&c_2eS-8zBh!6Hw# ->DN4tw-2aZ5Vn!%o!Krl+xcGhwh{EV5e&8w47U-Cwh@fC5$N2p?Ic@ezuZc&-F*xA==`g`OCif-wO}O -{vZK8FDhFKeA@i&WlB;zb$$HZppL|_hZPSG_;oZDa+tf~wHMdT+V;9B1T`Mj5J$m)uaMxdV -RQSK -qQArVcI`c^5_1_=#-wiSh)@#+_JPNWR=A{8272s0=XvoU&V`&C!#w*}e0c6bAolZ-xjr3&Hx1SR-sFwylnj-|Cc%TIDt~_{e{&*TQz)Z_G -Qka@uI#LY5%FX3W=~pDJ$@{I06Jak$CPUPRrL!9vS8JquZzEHWZ8Z>jWj{|`>_1o5CyA1J6cL1q|kT1 -3(5+pR6-sWz?xjYqau@~)c4{vW%>Jk`I{3p!YqGsQI@d#z%K<<{`|i9NhIk_rN&TIdUI65%=*$BM#a% -lzKXp}+?A42zb>j@HG!U$G+z3bF;eTo506ZSDzKBM3deM?g4rrqAcz4;K -0>qJJc`epD*ClOkL%ML|*l4hw)qruRBovHURN0(@D3sYszucanNnLwNtxbS}E4{{4c$#|roZ0M}AvUY -wUEto(UY{NyBlo)E#Y`a$T@Bxzd}>G$E%lCFfF5Y#L%R~6-z<*H$CYgkRJrI3drK|5Q+EJIr(QqQT1P!OeBTH!%Zuywofp-Sp!SF>;H -wTgbS3)dm#=sQiI>EoSwRKdrGjdyhtdUPm!fvVJGYuHb*eBHEg-uTE!}ojwgl}|xOC&NY~jRhF1iZ8D -dO@)L48JC#p#V=+TCV_^t{AE#qVu}%2Qk@RRXpYE3E7b{krC>`nOd=!HhEB)W^^-nlg=KT!pL2kw+W! -`$d$#>V&Z}Q!l^i-0E6%(nzj6jRYaq)k45aF`Bg+0nqNzNeJ-QsMCt{>S$r=OPiISFE9H -9@uM3J_!kXk|Rp!%ry{$}MlhkF-iaXNjhE_@fMehfTAahcd7)7#_567)k3fT}M$Ni$OT6^Nef8i;`Dg -J$3^zX&XmxTs-)%&cDt`r*ZubuZwoaN(w)$r&C4yyMJRE1JG6q><;2!`-QH2}+AGZxD}{W+jNhxF%&{ -v4}uD>|eTs5YubX*HVdWqGL7?ELPE^!H+82ipip11W;3O|!I^&FD`Zj&3R}f~MpM>ri8}f7g*P;)L>E -%4l`tUvO?R{a{C*+s|Lszlwc%^YdY~ZvHM$6Plk@lo)= -O@n8T{mDL@X#cI70?)6z2MPTh&p!U?-fzl465|TDNUaVFQGN@&+lb0%Jd?3=pV^o~3#2P3>?iY?f(uh -2Z*P(cP_Noj(sAU#S`CZ`4Cl;xbx>y-sKk!@l59wp%0d;+D$;nmMA|z7dx<~@wpjzc&7Oacq`I#T2+B -Tv<>Pf&0mDl@N5#5ia^lr*O6{|v33>7UCqYgFNYLAX1R2)~>VoLLw+A{%NbF68I2UyWtgE$Hwp;UQSc -9$|u_?$^Xl`oH?pVVq~q~2ae_i!G2IgWlg$9Lnj2|uyA_-L3qT&L;o)Bvlr(H4+Pp6$pjbg(>UG$x}I -t5D~J6m->+QM?Nr$n^X2rR(CMYkg_BTr_^ER*heZY{TZcoTa#v#S_u`%YN}a$4hG}ltByX*>^>ZHJL76hr_e8&e -_TJ^~q)DZRh*b>-U}a7Z=~vjrRLZqrRVi#zB|1Bba~RbIB_W7ajWtT4tiAkNm={;aZ4Y6wEDw)r9FO=1$JlM7Vn25H<66Qq7p2;^gE55bY00fhW~mIab{(O~du+*>R;T2g3uZt -(+A-&DQnh;qghqKARQ;s6iOdqxcQ -$DO9|+p6$E%Y^!&EPi}?cyf7CSj@uJRXg~TYW*=h^)Q=iKYdaDBUbD3-*uc8f9Tx6Y3002s-bq14^P6 -N$a(+i!5cUGgaSIX!5=s+b)fLkt4xQTI)MH{9PCUS+!J=uRKLY-;AoOd24Gi$qhUev#2L&85;M9VCtM;U6D -AHxqY;O$6Wp)fDCK8^viZrb$w2o5q49tZQ{V=`Hw{%*J -)j(|?>rXN9|6v#O8M1pg`1B~>8T5a|X@YDfsjDfD_01$B$L>Y}WP0J%c&Zr25P>ysHVKvYXGpMUbR6e -dtJMTpI=`0^LPALuock%<12(i -T|Xk6x^XNP3)!f>+K~Y!q3IwHo-VM1L -EDJcKUbv=Cb7;@lu?X}Lt*M~6ug-#5L1Sy7Ul$$4gwn4D;mOPzmX&V5gu;`a18=fA=M6CLX@K@kA -sgX;E^-B$c9@QqWJ+8nk+g_7MQ`S}P+*@%V@6bujoH}TrZQUddTk`ExqU{(v|wnWxMT${Dq828wQvFR -`oiE%W5QwSJUM^YfQO|0C)e-GIS;c{!KOA4_mL9=JhkC`E$Kmvu#YsLQwJCvY8vhnbQ)oEa$+tpH1SS -we`$iJHoQDgqvZ`yY=_zF17e*$Ug@i!SIQ(O&B%}DGftx>u9Hpx9ov@npml5QpvB;1od)FMsil|ZDqA -GPzJb71PWd%`#0Ft7OM-kw69F2;EfP5OCuy*v#z=Kf&@Ui$KcT(pi~*-MR6iq5UUe7huJX_H?N(ZJsg -bv+N;DPUnkqv&{8oRl(svH1XArfHD5>&WYv6pqC5IvSQeD90Nuca}LeBDl4AEOAe}cbb&Lzp{-L(e(1 -%6KrfLN_yhz1-&O3APNZjuheQvWNRj6`@~ifto(fG5FM{qfK6ETFCJ2xiuMoI6 -+}Uqbt|y1dU!b7mJF`6-4Qr+L9ogP-Hz -t~-DvdC`syW@dP!JjQULORO-=Ln20nseVa|WDR(7&=t -Js1K4^oh9qt7*1LUH@uznpEPimdP3cPA1q7>fm2_2Z_1wShSX^`i?E0q$uBs^%{gu8u=Yx=LTcIK>wk -D*?$`J@2vilrhI4hpISO&Op~b3iWUFg;rG-4@PIP}#?QoR=0k^PfQg#bbsy5+&P4G6b#zw1JwC&D6a? -GO_*MbjqBBFVzyS&tz&a?PuK|5qeh7=0Jm55ZTimsgu&3)m{Gq`+;s9_ir^$|F@t9kU9&|Yi|!6b7TPHX1RVz8IJ&V>3K7@#c=5GkBc@#ig*Of -mz>)M*)BZLlVA(&p0DxV8-O7XV5sttZR^%v5dJB&&G=@kXeD}z_Q|8Afhc+r;)|iWkPH{L -?+Zrb@PfyTz%0Md(dhpQ(PKE5^XoGT!}EpSo7NXZPpra0;8|$P3wpW=n0o}Zxx~%S!cO;tC1IL(AJ}dm%H*_26ZhxLBOn=^^93J9@S -HEi5IZ^N3o#sVoulYz0-no-(6=UCB80tGO?JHuyqjI9qOC+a60?Oc&7|+%gyVL%q%-XhYSX#Ar_Ci@e ->pdYp0x5j{#G@3)361r!g(AOIOQ?`>kk4cV5?3l+8N(RqtVrpEVY&V9 -S~xTGsI?d}Z8Vt?@*5)38o;>&%bD2kIY?X)8=I9@t!X9YF`S8m!WqVCt!-n$qrbU$QDM<(&?PSTmlDUwOi2>CLQ_1{KHe+Uzl6gFR-k%Gmo=K1*pw)jx1_7zvFE`!2e*?l -q(dIhf?6Mx_HrY4F$A3xVIaNq8j(yt&--^yLXc_grW`_A?jX6{TzJomCpz?vk!4uY-ZBi!MnWFav2U4 -Lu8I*s!5RU|V%`YAPb58ODNh`Ga<>hzyj5{7g9CKgaw`go6`DT77YX(P7xaT|g8V&W0~A3XE`y0>eh` -0;0eS3_cwh;0u2i3JUYVA^wHw@c^F?3-(R$)P}RD@6ZE;^6wf6ftW8=ftTQ!CpiEYmM=|?%f(to?P+z -MO=nP$#$S*@hwR)7OEU!EbaHLg_X7hwwc)5pBLh5j!6DKtAkFWhiRk)c2AtYZW#~cYyKqcapb~Jd2fm -GjnAQLyC>s4y=+vmCOewn;j}t%Yr+*=Dst>twA5k%BoIjfCM|%GeQ$MMD9|1~gtoLM)@%b>L*{Pp9Qo -AF$R%Q~;p@41XoRfNfB<+~Z0BS7V`@+JR>$XMUFxmT_MP=A)2?R<{Xn;XxM*d|Nn~v9U!cId#zX%H~! -KUz|H77tKDGUkezP?scfS)nY)P$KDKq~h)HZUaSzgf(X>@L5BQ1t}1?w2R;s%@D>*whB{O*R;YOBOqy -0UWb6y9}O%#0)9%CEuM*GE_ejy#|d(rK`LZSLO8qHtx2SX7_Z4!Q|!*e>xn5!hJ9q#86O%RrJ -d*gr9dc(keSz_M`v$U$HSwjklNAhY8A1{W;>|9z9n74aYWHkBFj@3)b#Ah6LlBj`WlSQfDFTR0bwp(O)1k3BCa5@cFwEFiUHhzV7ZW!2%CRjK_6#GcPWJuLszrVOVueL -psL#H-aU$JiH5#%vmGlK#^zd7W1RtrcK&eceQg*j#4tkzA$?{e0c_eM63})1#s>NGLquYh(E -%W=OZ#K|nDU?*_=DMVIPdtu>NySP56yhm9FV&Hh@K+Mk{|g77E%O$u2^jJ9y!RTnToa9={m=4~G^xCL}-gBua!!!p9uSP%jDS8#4G(7!@>DCg-T1#IE{6@^+a-3WYj2k -f5UukJ8J*u+Ey3V)>^W`u`|M3uAx5V&3suc;`oz_)xxhyl2V@HC9qbfX-W5rw125FmU6VfsEq$`!b&W -&+za9?0YcRw?wOXJCY&>JCiYjBpbZ=MherI10Og>rmlvNLTM}-LIE)Axh&u{;%%q7T -{wIu&l+>~h8(fX4-!AY_9Ts0n#M_E`v7U#8olPHtRsemThjf3Z=yhK9wL)F@X%)r!( -QMT85lBL3^z-fd{o>JYk06dI5dth(v*HaflEKKpI9~^wNqvXDG1?Q@d(9+n@^C1M7 -sbeD0hZDA0asbUVF|>VvU@2h3;>apnYlL8oSy{?56lM~)@ckmt^JYYg&-&j0SASNeb869)~Zo!2t^23 -j5UsDhjbYu=`FM;;4YxXLG*fz`V%a&>IhEn;hTP-ViE~eKbo=b-UR8wfGNp}KV!(GvSx1>N<^`xqAwWRIf#snOAaDqZ08^{jv$fs7~6L -wGA8^xP%oyzcc5NOA@6`G*2Oy-mI0IH9dX;|OaZr0qTSDHdtP*w+$q1TbY3BMrUXxIxaE+;bWi0fXc~ -tQ-K@>SOo3bGU8Zr>@t+usHlnb<(uieBr`P*vVRL%VrVCp&4W|cjn^XT%!tLRlQqp~Kpn2^R@ --S9`OWK~t}*m@->ot{Pt!tVxBd0}sVgWz~t>sQ$!c%V!5O5LQxX+0x;8#DWD~#H}b=BVf;_Fe#qZgFo -+u`K(d?G59|PA`dbru6eWf8x8}WhX&@>jjCU$dBtI6v;P}`WC~&PsNr+k_re;kF=mc%&%i#wn>?_Z^F -YFg!Ot}_D`z~T0D`lK8;M56CArTUkCBftk2%~uT{O~@Ou-0=BC@iW1Ua8P<3 -Sz_gxkAvQ0-0hO4h2B&8A!K}`kVWzCzNjvSG!6SsWvz{UM|=041`2PN|VyZc0wkxv4Np``rx);Gz4CR -Qed?d43`V46IJURJNgsss(Je+c6P_vZZfkY) -q>Gv9c1y9=0*MGg-DgZW+11}se7UYEfsgaS#rz8T$`0}Ar8@WpH2@a>=o#%yU^=_CzbuJ+B2_YejBgE -w4#HJMUclmxtF=*#Lr0%EudHgy2;NpT3b`KDtB49$a-)NKOUslMr~L7}A}>xb_sX@v8(g&zpoW5J~mz -x{#m3dPs_F+-MRY3ZqG#>Y!0fzQIeTb4vNVO3hI(2~Ahe}|)CGMo*L%-}fa1aDtYlMBbo -HP0K0bwi)fTA20*jY-)A -+@RUpuno( -l@j6eyo8!&L@IUz^TXLSUmQp(#qL)_4O!X`J21DeqZjsyG57jTxcMZXJ(7O|m+3R5Yoo_d&f5jM4fl; -JXCz^Mb8P(B5uamfd-r2ZEG1t58xE)Q$zWdg6=;oHuVp3`?)(YesC-z~UrkJfaKwwmVkT$vWCaSU__HNTssn7ysSC5>)9?W?6w5Rs}o*JaxlIRMCiI#)O% -0%mHC$4ATd;h8zR!j2UK7Gb|18)D4G<_BjUF;+-5qnFEFyK_>;rKy6(1`+#A*kxlI4luIBDWdL5y+;X -`|mQ)9h;!G(jOA2B -Dq>eB=yn#x20=G3wh}r{Jn(lh!i{xU>aKu{{A{=mlGv1U&mzVq!w|O%x2@5OLT?BYLT^z#-grUYJG}P -!!gOyp6@e`BjcZup%M%;6<4Q3lzWz!mVVWrVqaeu&;|ykQ8C0!e0ptj7OmOz+!}2DHt4+aXF4+?~pXL -fD;-Me(P=plTDeH%ZP@ZPm;%YL%xGpw*z$!Jg=!m;JDFsLqL}mbj;X -MLU9w0w>HSg!32u}GV8XfW11!ZV2q`cG2lGpjU`%<4HDLsN$l&aP^8rJ_ZBl3-ZX;qid&xgALt3$v%K -w3|s)=F2SVSsEkK_V(`Ij>BU}pv4s-5h*{(~=z+h>9Ar$&yxfL*M?8DM*;EeC?&}>*fvTP!F5McSZUQ#YL9-agk>+%io)P^@k2|wNvK-5Zd -=+prQXM+?tz?c;rnFe~VR#pPR-=NvSaqyh(+rgX-Og$rg2{1I}8Q`f6Z(^VLF`YpD4>t@*&(7dMkU=! -3Glz+fMd+I~YNJhx6#UA*fCS>_p8%R6f_ycM?rKB`-+RJO;AouQ0=1ND&g{DQA+=!D?Ag=|-v{`*IhX -9>c|V-Dzz09d#{)_0ksid=hZBzi0qM&V@Q{NjMi&v3ggW*YAMq0sX^@UF-XaqZY7%>#N0 -q{^(fuQKve84bw&h{x65YnOpWenM$H*;YC(VHpMM$w0!$yZ`KxKRNOgY2iHL7Y{%Yv~ -Y4@+zI00|`yHMaD|H^w#Qomu}c>kZdf8AiTQ@@l1SZ -eESUk$lo?!}2@lcNfEQ{)<~w46Oav5;h4Y}0y`%~6(}dunjsZ&NEC)~v%fcYF4vlYD0jI*u3m5`UErJ -yD>|uTEi&qd03E8Wi2Mi9EReKCUVNPBIHj*O%-{x_(@Xt7O>Hwo7-DU75a}2**RUqc{^dCe|Gzu|3!; -pnX&rxH-HDNesYe*mCWnfb?flW=w-ZTZ*cF8{rl%et;11+IyxtSen -x}^TlLJfgza#L5mT^>Tg-AnEA9&QRMCF8no*17?gE?hbArCPmF8mT%=vA49&hXnHJQa~IC`7Z8mF$?Nctb3Q3V?wm&&LB<}ge1*$d2=`J!@0dpfoWkdQpc=NE;`}V~(I^K7GtxrVk -qHF3!w^%6;QMMJ|56+reTJ(zr-0>PW@3c5luj&0`d~`1VD*H-xqc!JBE95=tg$E-c?2<-&4G`iL< -;{s2=VzQ^k`Jru+J%z8~RjK4N247r2G#d!lo&&NQnLRk0k1p`s+c!D;RCCcL}mzYx#?0fzgif!nPq<5;xhznjF7F{ndxn&%pW`82=K>XrqQHQCxN~5-AM9|)#I7(Uv=94X9Z4;~5AZ+}g;zNg({uU=r_UC^g$E6n^im5)!5(ppV6eG1hI!m@ -Mp$CGu^k#%aK+)QS6`+i+cAP$hbs@i+%CYYS>Zm2EcS|D*MRn=Nb^Mc#!Fyi4OXTH1;eu>aX>Vz__R? -uKoDXspi>7JUKtx8*nY1`0dampBuin`1g$FHH^5T|9JAjclu{t*i7$9_puoU;dSZmtpeAc)U6$|a97bysEgkF1}}G&YdZ(G(BVGdDsMqV?=YX@C; -ln6=pB6bbM_Pe1e-$MF)S}?e<2zk35Z%g5e@gYBK9R^t9JZ2ugTaMGG>0AF>-wV0&ayx#=E(Q;SaL{t -71k8B7JxgATmCbI|K}S9MJ3mz7sb=Fg_G#cFcJG%|^@mS?Xc$o{bOn!rfI6AqA5tiWClD#I{ -v)@Ci@?BxPpp@c_f93>NGJwV@BbO>I6DG>A^@?c=q$kGTW*2Ht2!eI4mIvEI%4U8>3djaPT3e1GbFeF -UtOU;qB(*XA()nEH+o4y5dqe8L8yvN|+qYXLY){SZ9qD|G)TYS?5zrS6ez)O_aWB6p&!H~hp$M!5!!J -0bYh>hRmt_Yylc4=4|oK1Tz3ZXxxb-QWg;n5Qa5NkN})mn>~>>$ps5gR|wT@hektm923|0NudF&iSk=o7s#4Yk@fq8+nA5)9GIkBI&+f4?g~&Fqm@<>(d?I$U^mZ -?^&t>X#X8XSt+%SI1I!KtkHK0532SkH7+%!wAbTX -yGtu{Kn+9Wd&$np}r?0gX|hWuv83yd+pnZeypr{QylDVOJh8b0g~}i~74LV%kYo)zt{ -9W78Jy0%;FKuFs|*u}=*G)hFWDFGoV*a8Q3}(o>j3wCfWD`hui!qHFKmQ)X!5!ob#w=GG-e!nba -zQC|aCj3JacsEfK1UP`>KNhdAzQ$hyA%ktup?H8UB_z)&x}F-aLnJtg#iH{29%RO?gcWWvqu5Pw+c*W -5j{AfEfAD%ZlLDXu1YZA)CFCYz!?Wl9nfHb`RyRj1af0W2sb{Y0^&^IJ1QUqymN*Ipw1{@NNgR?lv5 -Ufm}q5Q^a#n-C}44l%97=~=aKCf(5y(tJUB9!2%6OQWKA2U>TPdR{eTGZ(WKK9#i5QNTeFo2BH>O -o+c>*g0Bpt1-2olH#ULt}$#yXEY+@2EV*0jpR!EMWp!CPy#k#KJLSc6k>YjI7c;5HYTO!TLB;b~!?q1 -nvGl67v-e{dMSWHSd;73Y4&KvM&j@M|+OKp?yiaDIz{gq84XGsH^5Zo-gF#?K!22W5D(hgdwxhG$k1; -nUUEKIDWY)&-gY;4qPM!r*Wjrq2-Y?A?eV@RkhL)m(=Gk2-8XVhYl`7oD8L=3N__{G-$EL23fDCxujizJ=RjWkA_w#@WEtYnQV4nApfkpOjGlqv_b~t)vCl$)PV>tTJ|gh) -1D0TyAHZ7hD+6Oh7#`LDaqP+fwqslwfc2(s=p_R|6ccW$C2R9!88n?|^@F+?Y4tGFmg5H!Km!NDuan_ -_Mi83M2}dMOjFE>9x?<=nFw5Q!o-jC`JTL@2Dty2Yn7c87)E{M&c;Yw|Yc^#)@IF$*?IUxU&X`=NCva -*FDf6iZ+o~aeaaVPKa9mztTg^|u!LswiZv?aDcn%nRb6|uu;T~{|aO4)d%=ds3z?dpM036$aA!D%iL( -lO91GZioPN5mW3y@6Ul0eGy20`pb-r$H~z(M9kn3+bDS10%EGvL$#t-d}s1(1HqhozByG%cQE38nEoLv@CN)fvkhguti&h76A9956 -PP7Xqc$!Y9tga7I^R*b{6F={!40Z}F>raEq`&z$wqblmLF`xDQTDfq;TTt02ofnsWrHB;0o{Ff8F_Zs -A}a86|;B&IKg*z?P!GU}I(}qcJQ=9}mS<$oLSlfgv9T)$%rX!`s3%spac|g>7FG+NX>DRy7@KLdcMR# -G1qBga8%G5>X@onO}LgN$@zzXXtu6g}3aO9`zB732X>Q^9<=mJg05U;8+BgjeMqW8xg99C~%+P5~fB# -I|32RzySkJT~N -{q2F3(RgtNIO8HT9?4j-ml?lU->hC@UxA**5En{X61#46;Mo>9Tpd|oqY;k@=30vKnNv3c#G#u*u;1_ -r0#zJ3(B|fpv`+VY@3tMQncrv*l|TRDn|XoL>Q*T -41$oEodYLusUXfl2bwFG6*W+XVfxd%RT}O+k!((i8+y^YIwoF3#VY24B^On00;4zxr-y4k}YK-o3Ft1 -A%CdA%wzb57DwXKkOv%*K2lzt-{ZJDHzx3I%!`%>9Nn_7QaJYgnF(NSFkcs|Yp*O$sw@hK6c*5_4aO% -Q`|uEJ5yq-iX`e%B&%Jvw959@0wTZ)#}=Rg<0XY{sgH;Z-%x?~>#}4mzXs&F4B)CsW^F(whyybRdd6Zx5L?aoY -bx-#U3MQ(7^@G*O4)t9l)`shTa+e^>*6BKuAD7ir208a8z800F^gOn;Hd+S3msHHV{fcVMBq0&-~pZ- -63k~DI(2|y2!MP3#nBNUSb{m+|IPV9D{yKYIwHncok(wT%>SMk;HeE~-xh_rowG~5;Be;rfioCr<4c* -Ifx(B87><2>5jfy)mXZCLZ+^g3yc)X!-^Q$Cu&Q_yXs6q}qd+ch1hPP+2XT2zG#fL= -)7KzcUSq3^_X@8!6Ip=4~20jD<9{NN_p;yY$3iJ!Y~!J~nEKn~@)xKrSVkv%`u$!#P4UMuZiqFjnIt -v$u>JsBrISlkp9M&wAv%Z#e6_NceR^2tnLoQau#qck%!MN6_F6D=>K6eMo^*7A -8Q7vBr$d=L4SlfPs0yZ=jCg`vebo+5=mr2mZ}xQl$s8>m>XKe3)e)eB%f7;qaBw2l&b>O}>Ya)pGy{R -u8lcZ-C)Dr4Q^W7gFs9yfi65=N_!ln;;JNT<~$shnVfG;KI;D!ny*L@h?}?s`FrtF36r8&IvfAdB{0$ -L%^_sgb_wN3dbA|e5OEb^AUGMz5$-P;IK6zm3!oqcOMWyPlNR+tGEs%M?cnIfnY#WHAy~?_yr=!Tz$0 -0o3!@P8VOR-N4D)kc;kT08E|Srzw!(uxTf-z2OMF)ggDMD -xj_w*oI<16ev_!iGsOS&|wUoGi^XzrWO4|XA0`s;lJ@S>al_~Re`_y^@Nsx7Tt$tXKgmPUB`3*enUcm -A_1*L~;~W!}DhdtBG0V1C(^ZWn+D-KzG(BLMa)N_v_?0s9qY?+}24Y7FQAR{@7L$RaKy3Y>Y^Z;P#U~Zz0E-{i`wawsTT@N|cvMl2kon`f?%-C1lt@^sSc?Hfo -xRS9;zl(6|PDR67fKqPFk)Ro(rXb+Ncc?&pbqEn96rUi_VU^>FXeqtMtXoe^80PKU-$m`kOaz?(gqk-w$5L$>L3KG -C6qjLAhwfe?FW&`&rfdOn;*3S=pQyiZtyUi%guwY5Kj|ovN+ri%+Rcs=r@;Qwi+Zvr7@A((l|aWznprC)fIl%8TZ&nt`& -&{{v7<0|XQR000O8NLB_@n2}4JMMVGrt<(VkBLDyZaA|NaUv_0~WN&gWXmo9CHEd~OFKBdaY&CFUa&u -*JE^vA6eQR^uII`&Xsha=5k!x?{T}g?P*?IWHIVbP&J(EYp-ba;>%S(%p%r!-7NXm+4YX190Hy#8)fC -MSoNzNTrDwar~0W=zo?na|~mS>CL;$pTcS2?-32;#*u%gZ3VEV5)(k_+~G6h!e&T*O&A3RY=6%_4G<# -3jkYr1<))8NgV^%gMzJNuw;E6!Av^XdRbV7YkB`(&~i2g&T -Wlq9H?OmB&lQjO7T{I}(jAZR{jlwdle&+gb1_j4_3dkA-WjH -^rezNyzxFFag@!+alB*$q<=6P7sse7NrX<4ALdO8uA%zS84ukTFRFG)7C2OM@qy|PA83U(00EjCJZ+%5l1Wf^Im8}>!gz^+p4sE9y_DdF -IgD1SG1eO!Z8d6#n2M}qaefcq5EE94lem{BgB)}yDr1#e(zMS9}teK0&gTJcsY%1?PhLTSnUuMzf$>Z -gd)2o=SHb54|;p6+uCy(#5SNE~py?qAYF&|m5y7${vSuPLn-(RoSll7xXme21W{P^RK_dh~~-{HS|L0 -AS4K7KzV;q==dAN&|yK6oN}PKki8vdiE|;~|qdDNpI|XYBV-dB;1kq%{C{NJX^3rHlToPdN~V=3qHdN -Lx~>LHMuoa1M1@DaxJ7FiwH|DVHAH#)_En2De`k5>l@fA&1I<$)EU*afSU?_5{(i)CpE>M)j= -B$|7VFQ1fhc?l%Z^<`UCFWx=>+nbkfPcL45c={T?Xp88FZ!aJG_}MNZ*D{gctSgKPD_2=`5s_&|_rxr -(q?h4rl}=$R66*w?1}|7i5)DC;5%1sw;4Uswvc9+&0+bP}0V5a%AchqD$%}Yesukfgqofpy-SI6}kv} -O#R~08z5L*;Ovp#&{8J*-9g_kKA%IYH~b4_0H@thj{RzFpnM}ZiB1!-SQz50w^>RD2F!0-9=)Q%G-+nk5nVKMR#2TUx$ZO;cgRN}I2%I=5PzN} -39wt_eH7;~9vp9Z6@ti~B*CS1hDbCCUcQh2gUG -o802Bh_9h}^L&mN{&ihH8)3rmn8%d|xif#-!qY4e!uK2hFh;w5DK+^CsA?$sypsEus6Hl*#B%2o$Pjn -(QU?%T}kC$9k5xZWIm(tklzHO-od%;|;0A369w*X~`fKOOE@O#NeDr`x*2GZSk1Bb!_HpdK|I#yT3fw -G)fUq95zfd0dcKhBGilYvG9qB1PO32TCOz1~*L*8}YcEK!3s;;ZKUjf-9TMw3d-VbeY)E8rLkTIK9q? -H|5dUI9a-?|uVNhje`xoVUof_Hh?s?32DmLC8Au0iB%kJpvpeq3(-a<#&yTG2xWAg1m40j0xh13UqdleMz=?7{EF< -LLCi@(%Av--%6wzc5SCofPXC-`%b@~-5p!Mrwbhp`HA1eYkClf4>h2+_r4A2Y;c7Z5!@N8V0h2g~O?0 -ZgpSS-VmQ;k+kTi10Wvtd>i0L -szGjSgrH4Ac~SYM@a@Q_VOQ0ZXSq%8^2pvy8{g8gv3Lbr2-6wwmv#*>DXym1nz0N5Q>iLQw>D?)7d|g -0MDQn3KgwhQSIGx=5o9Fl`t=dulE2)e{HK;j^TIl!a)JAqzl^JD&|M31z|LC%Rn^&RumV8Yx>Tp%9-n ->!QZxd5lFVLjcm%7)KpDHB!c<3n*A_r~p_VMsWeM$r0Tg$&6BWG`t -{R)L+gR)C@B!}Avu+l>XOp1OeXzx!`m0z?W?;=h)8wxlT8RD4dD-CokYAMC6(mPcg?&`4131v`Q;;i9 -wy4@S(cfQD(g{bkCob4ay}!+$~l|AjIH0HNdvf?z}_`~~1R*pRwlBYx0YP?}-_R3 -*OC-jh^$&s5X6_QOzSJgm_cP2V&{WFe;}`(j6W~I{L~UzUZMrIZRslPwyJ46X30?a`r@U0N_3t~S -tKk3`8X7LCFf<64%Osv6a+q=QFMy)`=A|r#T*KK&LnCye(eAI$G&9WG&H&u=-K8h(XAEk8q|jn6*XoD -`MKX|}<>ANKpn9uv*c1J1##YfNqSfZ&jSXqGHwBl9epxrd6I(q`hU5Un -R}bT_F`@b~ZjZmm*s2EiO3Aa17{gD?X(@R`?ffLG6t{SPR4kV0Cb4#Zj7~F_k0=%I<#qeShB$RwWiYk{kjbAH*;r>Cir*`!Ki%+Sc4M0doJT08*9|u9C8P -+XRkvq>-a4E$+K_CI)RNW=Lm5&9(Ru@!0^#XK;>di!SI{p8ZNv(Cp}rI!`vsE7*k=VG_^NMVMdH{dK= -_Y@EC(sG-47M^-kw-vV#w!o6+pZy9rK9r+3$`q(;RTE{cAS=`JAEu-cXVwJ8s(1x4~t-~X8lXOmvV?n -{EF5J7MC+E7fgFzjEy9qppqdK<7IhVGW6QlPHZK}+K=~PrL09$kgqT*W)hJDUQ%ih -H%r0d#9tk!Jcd%Bpv3QWc7NO*5eDE%uQgh;3b|RiBH^43V6i+;vH}$lHwyrs?x^;3dYxwLg -hX=^)paKLm>c;Zr7ZF$i=#1@+{a*-8&mBkhV!9uktK1oqPuwGrh}i~7&AQ7I>-3q@B6yl{vU8w1A25q -W&L0lr*Uybb+x#>R|GHLy;3y|j%TUyi#O8rt(qH|bSW#Dk}Fo3Q00rH(Xe7o2A!yFDh3)s+3#MNmYI0 -wY!W_U0p=RjcEWdM)*n^!kQZg)d#po2Df -{P(?V>Cg1;o(ZNVh?Q(7oPgLRlx))ZQnk^&f57OSGfgF?{&vyr3`XvD;@szHka#v}-iXUvms7L#biD# -{l4p(UDYM&^{x!#ql0PO}+ZS)1V5yEiaIQ1Ejw>?9%Ei|HP{nqGlNN(`roZ~|>wAelNmsUuSyFB}50Y -0uJ(J(3582zD0yUn&@%us2{{VyCJ>mTC~2d_&-KH)n*lB9pD$wcxWemo2^s3_GDXqT&mPA2_jtc5^j3 -EM_45Q#IxVUr_oPitbs`d$lUQN!HaW3)Co0@qtPe8zv_+3g})==s?O+tXazm8hnJ=l&QsdQq8c$^&WU -|FN$yO{lPeP$2h(mzESfn+Y#&N;D!dDzOHC|%{4Oz?)}(_E6D!WxdIcaxZxDO!->Js;Gh5e=XjNh0~U -Ni6>wo9K_4KMQ|tw_0xpL*A|YUhE}KPoO)8l5XBvTT+Ge8J;RQ^G--3L76#VwPff;syE5xIr{pesx&I~Yq#nsa*3W -;7UYsiYgRv_YD+I2-7vm8M;P56QgR#VFY_ -?@J)yMOKu_CZG=~p;IQGOoHJt=m>O2&)BhCjCzC$kF$Apx-wDd5e_2jz6(@wgO1^f&`A^&E4rakg=P? -^C+xeiJq*f-y?##j?)uBCrk6Q;`5{}^-+|!7UZ27QJcFNg=p>9<3(c~uY%4Skant3U56mXvqw10lp$Zdl}G+F&EZGvbUr>ojQ -j4>v`Tr3b&@=&d$qRN?obADd0d`b7>Yg4?WZNu<7v?Z39y9JZgb0896O#otU93Pn9kh;MzpFpth8J^~ -Q%;!3u2DI+e)2H`8JpIS%%YUAtZ~)?Yn9M2nFRvELUdX0gfygL`R|Rrmzy|xZG2j$4ZyVuhQ#ahf!J7 -gc%=-ei&B3OpBbCcvr<*&NF+Pf`c}z8^_ZCaOV>&gOfPON|{MTRo7rO*GS&&6W8)mm7OgGWPiUg8uUb -`UyA1a3boXzKOw+7fp4vzX!!Cie>FSz}TZp2iSzhX3_N$+4oy}%Uq;!QBMfhl>lCn!GH)S~?u?&JXb5CV)dp1QR?79$1#6FeF16%I50@;&hh5 -AlV7-p)&L{W>&oiPwt(c|8A)}3$!wb5A~|3>ok?NSsiBy81Va^^_WH#{phsoY6E|6(6PjwhcVgK470; -tT;MGRIs<*dZ3Ur52p#GIj%`QbT*;JoYwSd6@_Xw6Tvt%MJYNnfJEzP1jlA|mWo`8exBPkm4H>RrT3N -dfQ^N%-19T&^RPGFkp8M%8>>dnqv7vrFeW(o^8Qciintp0Z8PhXhS_}>_pevFr;mQZIfic4r*jc!9Nh -tXo)p9tu&>YbSC&nNC9X@c$<~S0@)-&dx8UwI3sjuzKnvXDvheAIAg;5Bw3PV -YY<0bxImTDEv%ftIaW^Cu@#=_IBrhu1=$VB^Eiq~I&t8VizK3hTxN2+GS#NoIFM`@p~h2{qrg>4K2qh -GqHr8>zcN=V%4v36L(1U5CuXR*4Y}Z(N9MQFh&UNLh%BPBy`;r!D`8FQG`Je&r ->vdsMZ+<6!(Qxc~1t=@13gW?7hyS!xH&4xXl`St2F!vf-=N0`SqO25QaEkLd)2a5IyvadzmO#FX2@aXVOx5`8@N -Q`?lQX*QN+*;`>l64J6!`V2rB_;Bpdtx&{E@#-f!=?TegO)xB70^LaxC6pL`W!HmYzgZL5$>|mrMtFv -?O2I_{Wx}Ekj2)m$uR5cDAkfNpM)&rEKL-bs1BZ0E$4z_THRq?~CPo1zSY}B)-OzQEM%e;x@4epyk13 -gckF@^k_|?1M$r1dv1GaT@vdosl6xaa7r?HR36vGs`$)XMd(~#pW7f#EmpsTFZn5=$%3fFMWdyLtun& -oWMZv*O#bFlF3n=1zn5Z)3J0aHOU4lWkTObSBSy##Sb62}GP!1WTch)cL|6&EHW}IhnwTn%MZ@0 -^kjO?&|EmvFV9>?WW2m7Xa`4c1V|Cd6;EG8e9NtRPh0(eBXk$8jL6)g1O@!0@cp*` -CDU?1&pu#dV7mewq$;S!=wE*29ICYF;<1m*_77lkLB>|Rb{&^19iq#}Gajll!D^Ip;p2c?0CL{#V6F~ -FQ8;YV-4Fo(aaLW(H*Wla@u4l*m@=#I%%-%TDI9>VQ`2j4w7I6SNb88B#I>}N+2u2`i3TPCPw6dGA)<-fz5(3dQIKy@SZ^`ogO5P;D9*YSf#jNuS}(v -C=X{oET~@7SMI6R>{F-c*-=V+fpCxPRT(v^*n6kb0l?v59)p@siI7gzcMrZl=stW63e}Lledr^iNEqu -!{-l*@RXk59@NK%ScnNX-}64u|XS7ibH6lVBKiQEt+~Ugx1gX0Z#~jeN`!@#%_vu5t?RGF$`!}JlTkSe}z` -I&dJounr=+GbgI_9xsutob|-chrTbvrJ*P{>yFu`PAj>~!5`$_Q#`HJ_XtsvOU=atu+;3iBisp=h|U8|8UmA-g@@!%w7hZ;{ByWjOcZuFCED -+Qs@^54Zh*vh!f6Q2Tif)!|mweSq1lFXgF$4B0u*Gr5HN9R=+PZ$##1S?EKr2by$ZK(XL|$g*+>9*r@ -PfkB1?5zkJ>Lo<)OI&uxT>T#|QC4(c^?vvLVPSb*Y1O8nefbHnW&Y!XR;%8gFDBaP!`ns4d74^GJI~z -wk!>f&gyPpi@?IgUkCT=Og@4VxooMbJWSB}||7&Cxgd=ox?ywl+-;D=EcRyF2D(X#b9cH;tHiOa~5XUdghT1!Q2NZKEGe(NxhoI|gs)n+~d$QaCWs6|iFf$%V`5K@K(bz;et!g3VQv2%}W*543r -$3a|{1T!hP`-S1ZF!C0O_#rVJNhlW~TDyBoCJ7DBEQzAY3P}J&ntx+oeA}QUkYGSi>f$?Yzxc#FdkB)7; -)3yMDsbX2h8BjAccmPvp&5q*EFHY|QWMMwVb9zTM|R8XEe~nrqSa)#j@BY##c2Yq!+eO=`I3zEbN%t6 -n28;MQ+WS~1jl=d%X{F#4&y#U8w{r{7Vl*n?dt!|ta6RxvPa`0>+r`ih8L0@ -HfmJ$2EnQ+y;fo$%A=T27f9B!Jk|aj(o9+%AH-M=7XiuFbK8JZX2t;_0+n34)Pj!=$`&Zamu{gRrLKk -RccGvP?S=*!PJVuJw$fq3iMOJrU1&Nb+@RuAp%_vMm7FiFI+2nVlOxxK$cikbm`w2-MaDnynvfaEVvY -^Bk(n$+R4C#;L=~}T>^hAr9+@Ed?D5W(W{E+Y2e -20dPcWA4wV{pf5t}5koR`ge<#Q7AkOa$F^#85{`U3`7&4)5cei`@W|wXiEgf=5H@NLdF`{Fwa-)>+zXzENg@KCvk*tvI?rc~N -8{f(MMz1DH8HYc-*+iW4qbv6N?(wNiiuIpqGX#eR-JcLqa0Z|om%x%iC@a{)hDekKcW;S)|;#Eou#d( -LMOXjLF=dYe9mH0(lj6D%knw+oUoP_~(Nd(;-Nwk1F}o*WMqY%t&J{fPwA987sHIDzz6EWRBM -QXv0|O@@sPScf9niS_N0M3SOLm3~) -NV~<+us!k`Oa#+uH!>JK3B^aDPidmYw(YFhsLRvII@| -egSf$^c*a`wyvVcVTe7BNQHvYQNk&Dc7}8b@ -S*X=)7Cc_&CAQfBeHay6s(wP%ZOx3`a`K+_mmU1y?a5~s<7*e25!-7`6CV(ljAmQoNhk~*xC2bs8JS>{ -5V(@LW?1M)OFhm;<4Dlf*W>9dE2biX#$czrrYZ_hss82sug1v)HmT0^ARR7o -r^R0bKYW40P6-6Wk!xD@~99Q70iTTqBCgGuR3<79WFH(>vD1f*Na^HfFs*TWwro;M6~N;tH5l9dWZ=( -3QX#f&4PayR(9T5a##pi$a4=C_+0lUUCcSCY#|PjG`PeUBVp2H_UWpRb7;x-4@&JjA+X -e*3r9@%_j+A4S)2yV)RAqJ-)YgmSW_!#I)vd{pYwdyM<8IBz47lFW&8Ni)(Ze(WkFXnCwTmPn)JBoRO -z5Ee9%ccAWNtL1mRG?7FHp4M_-8e$hj8vjo;$)4 -8yZjR&wN(q$mrPw71M-o~K;N`MP6Ue_tAThMQgQjnh}0y0fX~9nvS8KkPf*Vvv^Vy7!yspgw{DqfVFh<>eDg8HB4*uI*uQ6SbXP*krwd%v1}^>3;g|*+S}@!YM)s+lak* -_OTCp=${k$oS9rLKiyz$nhu*cGj1_0@Zl?$Sb6zRP(VBuo|*MJ+5uU2wcIYL_GBwOWE&!gqfD6ZE}jg -t14VVe2uR^%d_x5Wd>xa;s_GHKwSZQ>^cM}j9|;e8E9M2QhHW(=K0Cw8)~p3Q4Qr*>>291Ci*2{qL#2 -Yvj)s{`pHjY;%@rA+rxodO2u`_6s;xHwKD^0Ch;cSM$SBf^O>k8WbxEQM-2-u68gO -dkyv=#KgaK{%nC?!8#Mw&P~s`>P;Ua!SkyfQc2Zg`wf@2{#@lA*JRp&B;h4#j{nY-?4Pq~n8d$g3caA -V`eCkUQ;TKkHCL=?eRenqzogg_$N=5MFw$N@!kliJmv~S@33d{^#Irc|Jh&#Cb(Tj3rD!*<6py@mqrb -5opPPD5>32$Q$}NaR6{$h8&lN@qJ4hU5+Xu;#WH%aV~ -~h;xzwt!x5bTJgLG*&Y~9`Z!gn=~yv)6eoN^D{PZ>ZipGHl=9iPzyHM+Vm^6&HWc`G<1J37{rJiZ+r3_(^VqgJDF#zTMV9=EQXbaQIJ3ov!972Lh -m@Sbz_c$1@EoKht)@)Xtk0DQ}&h~@c9C$0-`!t&~NIR@`|7(w7{XztC=Po-Sg$~;&#+7yZBX-hrD4+QU&phPTxQM#esy<*w*x* -$$1Tg7Ic6BdJ64KJ0)^Q#g)=im*5VuskwIfe?iou2IlR~W>*x-|^mV&s<<-Zn5UGIj5CYDlnWOaF*o6V<|rhL_@x#3g#{T -I*kU6I0ds`kWPROG1eXiN{vP18p+xJzA4yh;OxA;C#>BBw5R~`$QBLPM&YEA6 -5R^7NOm}YvP+gz2413MA_W>n)NuoJ5My)ytN0dKO2l%P@h!p>g@86B{5GJ4rDq+V6#Qq|7Y)WiLM^UGP*4)fd6t-m#J=gAcXyt< -t?V}k5?=j(0a2Zao@sJEc)1YWgId#b;WsFq?W7i{a@iA-i3|bK(xQ3H=?kXqV~vHB4fhp+ -=fh96Vcy3@f|RxHsn%f=+kla2S~j>bXmYWr>*mUmk=0&cq@S_7;c_qzmM{W>J2tvX4I09x=e$ns`k0m -E7K^L_5)>D=ey>dq~5F!3<%uA!AoQm*u)PMdBE7W5%EgoL$`oX>4nE7yZNto43yl_xl2!G;E2^Ho)Hk -Y@uqY8|UoF8+60Lft_g@FqGWAE(JGB1cWEn7J2h?+PyyoDzSyGga;o+d{A9eDcgIxb<5VU-L<=u%@$DzMz&Z@uf{VvEs!%bV%lmDQi_^ -xf-sq9d0bvCY6d_V|F*bE)%dq-a>)YUW{`%mBoj~x_XOOh3~Wwr;sToa{)g|rH{pU$+cV6998@$EET} -|GJ5>Y}dJebjDMy}|v;v_9$uc<5pJpox>*p+6KF?NM;CbMv`A~n#Cbw4qaqz>T2|xkzsQ#t~;x9+gOD -BkL9q@nVhX6Ao*CA0b`A=Tf+v)B?njz!*tZ5XWG?DCKW90sT_u8%n)Nwszz|R%{WvtCX#$2$LdfBL+rOa%yd0a80uLfaPrxkWMX3J$3CQ+ -&K@kjr&qZA6By^iF`Zxwlj%%PN2oBAElfScMjqfQfV)VP95xdOXH1 -EIf!1;$KsvfCC6?(9X9Vv*xpf`9mEgr~1xC@dZ#58MsVrB9J1g1X>sM-k;=rmswfTuUsg1l3aaTk`Pq>6s(rudE^i`; -uI`lK&>v~#UWMVjCDkHo~#Kwl^Wz%yI@OZ26rBljn}3J{7j<(ZdP~DjOb>6djzR?W^Fw+5b8D!`^!_L -w-klM|9$-pBpuJvr|Fa;IBSUSD0$F0sAnfpn)t!0_nsp4XV;*(GU08x%nIh62kBSf2r-UmL-A}Q{P5s -bE^{ujOZKp|F!UjqE&e)z!&r1SqZLWYPsu5#UlR$3SHgo|7n{bFbxG*dv%SWtxgv381?hi -pZ`e}bLMRfZp&XCX&uT-Vhct^sEojh68a~LiYXxlY}HGp`ZhaL|DM~LReT^iLf~^Jba9jS}b_+&OsDNIxIS -sS9v+^g9r8k#xBsXh1ekM1+S@N+X_xvH+X4m)eZAu{gt+H&>3gwc+T%P3=wc6Ov~Yw4 -pSX@JGgJ_uXbyA^f;~tHut2-RrUq3E^3t7~IlrW2=sZJH|3>I!o72vHq92 -5AF~ReKl%Ljql{v(znH`^faL;YPv&Xqb-l**r!J)-&>n?q*B6ND?#mu=K|1*$wO)+ -cVb*zX53*f2web$@$gxd!ZMU9%;?tDJh|OM$k0^ZViJZj8nVq)j;G{Jx#iv1)GM=iy_KDmvAGN$GXHD -ncntUBZyU>=0-5iNb#qOVbUCY9ECzeO)g7TE00nY@Ljz!pB)b;vR`hyq?FN~sqQm10kA -%LVBqp0l;V$cA8iJ+XMOk4R$0B1{stAoBRyHt+OB#*@op-IY3~YKyIRlgFx8WB6MZkce`whjF*93lx4 -Ct)T#n^o2sO+9QjMTyOQ`VyQIw&&9G{L}&33r8T-jHUm`fD7TMHNjEAUG3bN>#7DS7b#R{(ZBMV${vt -ExBW+Ohy>&=*67WDD}SnL8lW7jHXc^s>HD|EjF@~cXo-~&qw^46#dcKN|p)DjXvsr1e|0El{`mVy{8m -SPahLMe4}W1}_C&<3_31kUTNjiC!z@B+2>A|8Yyi>R`uA$CltSRJksRGHMc1FEFLJ^#DQDSSB9-A2oz -VWLcRUvt}Cy-NKc_V@axF1CBv*ux~7vu}5>(<|A=n>T$c?1pV$z3%DUeJlTX%Qhpws%SiA5plE|>LiF6)3+oKdkY1Hv-foKR(`xA8IhHYKASKSzJZ7gX9QphX0r>p?30*BdJb&@@^yz&bOA>E$4}w2&C -H5Ym;-2Fw{Yh&`&(7D^c;_{9%fK3eXA3Md&y}1M{3=CU1Pk1^@Hi_;D2i6I8FMtr(qt1{p^cwnYi0t9 -vgryflHl!0f_0W(7d;JBw?<&S%nQB515u&3a3Ez&mB9A5;)pz&qJt^QTU+b(TD`ReCZYoFZjIUHE#{# -&hWWj}7pG&?X1sap9=b!3oRe9h(+8TDPrz^RG{e3=&#H``_1FvpEU!36W0VH)8Dyuf=;{HwuU^qF#kk -D8Di1SR1QV=?2=U|J{f>VFGrTCt)?j}7QRU+y)*sE;C^Ao$s@3UsljJ2mBsu%V~G#L}@6sAej9 -U_yMsB0Ms#xd`X+^qXc8_f?)P5PhwwY$|lKSVRrj@NKX$z&nr4+$vu<_ZnwM`e)PY5%#*7a%BK&Cln{McN}jhyL3PEi9e&e|( -XNQ^X`brE$`Fg=n=Fg6%-hrAlL&Y<4&mFJRlH+X4etcG))&S3u0qz_ZP6V(`cPB1z%9*^OL0gJeDwL^jSqtmsEN6(W>mjNq16Md~wIk*9UpwWm6r29uH`0xdTjE -vchDw_5?G9se`Kro%DwhO-9A&q)d4cg+Yj)@0G^o36m~74A#UUnC4pK3cZ7`~*eXnD#(J%S#UelIlJph+{9cFDU{|5c --aP8B2?caS0N6u=K_F1pHmN?dB}}T>0yUwwjn|x9UmH{ValO?D;p6LYdtI`55Og|zsDc@D(gs_?|EwO -+k4-kU<+ZR)q_7${9*}f6K!Q^^QkEN*Kw(Wp4x^OZ&^;h0;q=N9li#Oj3_Aa)J{7J`3&rmO`cWC?8=5T#tG2IxJ)WZ~qv9LK&OeG?iO7}J%Q7*xo*4^%?vC#n9dVbYl(iTRl?mAITqX -BE-PdpGzM5i!@h+9FDQPn08k!5Bv#9dvLJfa}_I6^S1wK_pyoeKUc*#@&9i*Xw$dr1gmMk%&U2R!ANU&pkG{ctUIiIm< -%LjG0Y25O=&1_}XY*uT#>(X?WrEVk9jUqO|;xn)vRRh* -GN4Eve)5zp$S?Y+y+p#Pu{w%wez|zbndEpM)TjKf>>GO^bPHP98pMeZkNl7~HUEPsX!Q-uDhMAuJq1F450#Gh;4s&J@ML&+~X?!f9SjsQK(&K(YL8g*Nv$y>N()1`TT+jqMcP~%Fx -6HoaM+1l+R&m8wj(rZIj7T=VDkSlK7A(6VDqZ9T(!Ft`*ygAIAw{L!{z`zbDo}LCz(+$MD4~rm6gR5) -}X6u3y4$tn6ZqAAc;6H18Vdy?q671DHRI(;QYXHL;s~4CSP~7-nf^s^ScA2Mjr<=vu$D#ZWK2)pp2Oqi{&+8pa48 -1G>U6|&lJ#=A0P9+63`3#%qC?Mi(af)O5FB=n87ok4Av7piY+Ooj6KFIO&7LME}IJbCkLkGEIb48x5d -)q34A;{3H6tYEC!ZJEW@S6;J`F(w1*H}6o-7ak#d7~|23rhqbt`HQHXzaEQ1jKe#`v -6raXQ;jQC0t*pBVm_U1JjaJevLd7-;e%pz_Y3*o56&dZO2~+H2Mg%Y#gxr}KoSIoEqGTOzq${JyZ>kG -?bz8z`;bGWI!)%@lhj$^&fw#c#reU4BZb5An@hMagpQTXWt|#8fs`x-e>_RnS7kc+{N8eoJvk%r`p^$ -y_c`vX}Z%*kn6ZPS!Z@L*j?o^HR7qI@n)gtdoNo)&M{WGlZEhQ6RzbvHv -VHiI-Ba>XaBo4TYPxo$f$V(;NrTey9+G)F-z`d<`1DB&1|Fl1&cdg2tZ)Nwol~@lPxq{1J+#ByzIw#n -IXnj7FF<#`$?{3B(O~$KJ3o!yEr%|$1u5eNDO!1TH?``ID@L8K7=0!>h_06z8{2luf_bcDQC&PUT94E -vxI5M21d~7YOJ~wo_b9N1wQF6m~3ib5f`p(fi?E0Wz2!d*Zf+W2s@{h~dE&T$!pNs-B+RRjNo`@>%FYz4b|c?D^C -NMfo^p8<`rQM#zCeXH6X1Mg*VVYZyg*aD(0Z^L0N>D7!nBVTAR;+@6=zJ+bzZoE@v_FY|=w-z+x>2CnN~?1Ei)wVw+5`OB|YW=a6h?Spu(%VlQ&{j-^Lnns&b-TYxB+N`22H}b~~qHZQt2RmDyakv#K -pw26K7f8-q=fRIb2wxo4*`HD5vh_PxtYRQsO{?G(*5KHVM3x8~i`ZOYoFZ5IaR+H%~zNm;WKd)hG@y( -jd@>7Shc?|gi!6U)wc{;Mn}@jOLG%e1E@7mw$%l`!={Ea+LD{Yt1jSPsv${NP5`caDq84sjJ_g7_-gI -L~vg=75hn2>(1;Iayp17R}%Q|9^=8Kk5MI>RYVxSN#7w{9gn}!2V(y^mx(XBp1@QkMsoeJn{U3l$d;- -WmWfv#}n1#e>oyAUtQuHG^J&Cf}_OG65GpU?Medo)g}A0>;SM@Cp_sp{D*y}9Mxif4x@jsit^;|uPJ> -)e9RV!V3~wdNu$3F!laxho8=Ygef0Zl{NB=8S&25U)_Xx(^P9`65G-D;dknu@E2r@yEXg!WvK%Y3-_P -;4XXQo4j6m|io6IL9sVI$^%rHYl1>saaYXdS(;w5F4h;8`(KC~VA8I@*)5=0t7of&zCU)!r7j%erd_# ->-`NP5E__*7pkvy@T^8!yQP5dQd7JoW@t(D_zC;7^~b=}ng05Pcl%nfFklcs5(nB@xfBkb@wU7wqBB; --L?iLN1*}xD;Tjhi}5xRnEYaR4T&WNEq-0yW#<0mSh>Hg;)61qsl6shP(>>`qZ<^WmV;wXO($X<+W#( -ysGlSqsly76$Oo2ubx%FrleGRi+go@)hu6L(ZxF7@VeF -S_R868MkNkb@g4i#UTF!5_Y{i6M0~#V2xrx+B+T{ob;6%^SYX96Q#)}&fBN=;N~0Xnr*V7YG^nu3FIS -Y4PDQoqcWY%PEoPVhMr)#c@QyubtB#vr&h}0G{=s9@OyZP;`8*G!m@*ou%AULyPuc)LxiC=yuqWOCz# -1hsF8Gcc*YBz*0-x#to+*KFLq(N1EGnR0{zxl+roD8gR=Ew|0HZ7vef8?q3nPd-I!O;z^>LPi1V+kt| -Lr;efmAw>)uSns4!$>YuDV@t>ut-FWop^?j*RCj*0#tS!o3yVHW||EDLeszHJZW7HI>Td$!yexNu5zW -&UO3*+L(sa$u-#&!~Ol>|4><&$(2;lo`q8;zsJ8qD&f9qY0E_-Z7*>;=8R%IWs2rb0;iZI*}+HKK^;p -u|ILxJ166&lLBEx?oacH$P|uBAz!AkU9WG@(m_r42mWJN#cLYy`z^gYugOg5|Mr`w`kJ{(($7O$lk1M -S4OkE|)R8YE=KZ>&fm3OZeiI>+j)BYG9o>FN&zFd{0uwG?m9rNu&aWil3Kwa;2HEQoOt?AL>dOdEg@u -;h;7916Fa_it7?RH3IT0!p00fcArNa8R$l -bjhp)XA#Pg%N3 -hfwW(BVjC`aNyuA6MaOj1bvX6E7Lw7a!P!ff0c -O6(RjLN#BcE!2Zida;x=%j>;3aHxC3a6^)|N9HVwVIYIc{r^wtn`H|+HDW_@*CY?mzW_RWvmnHar|dQmoA@tnlgw -ssY5+K}gWA8gvGK+07|HA#`U9(eH|_QbAOldSygjil7d&o(JEaP6l-BVU$KK*R*ci(Z&f>#{^BwY6N;Z>_6_- -=GJ?S+0iVI2(A*b1lRsSLfSP4F`lD8kQ#>@-@cwPaFO-XN;z6xEsx%zrQ}Nvb6<0SvlQOjW9{h>vTku -D*)MWw44+Hg1wxz@=19DvbvXp$zZzDoE{@qq8OIC~YHH-5BC9B`A*5v^849j{+h<$raiIL(CUxm@Stz=P=E+tKno_hbCDckkH9O$$g+GPvPKtV#v<>5PsqJoUA7OntJA7CmAg7`V*)q)z_q$UmU+7y_Ja|2?`Xg_D$1o -RR33rbm1Cz-{2-6e)m`A2qNaiX_Id!KAV+z56#VwP&YTC(7qMTR((lC?JUNF;rfer;U1rYXhYB#Go0= -2oq1szcJ4`TsU+uRqKTZjYj=?)S7!2?YAQt!KC=gO7eZ|T!Y4`sDP)h>@6aWAK2mnY{22($dQ!daD00 -1aI001HY003}la4%nWWo~3|axZ9fZEQ7cX<{#PWpZg@Y-xIBaxQRr%^PcT+cxrhX7V2pdJ<8sEL%>Kr -n2RmT%ukxlQfywx#q_9&=3hpsQD^E%2safzuztZzClTLJ99^mWQkntE_N6D0yIyefH=-POS6PI4&gx@ -B`KjZ5&2ol9QA!bJig+BN8x~EA$KE>IX+KWLVfZ0(HwEaJRUkL7J5-K6#Onnl(M_jN!KxZ{OIu`eJ_z -;Mrb8oo}`gwJ -3)a7)C1=M7+`E>IGkh!WSMDJ@aKJ5M=c0IsI`OFp`oZNk_s^=|<2fH+yo3-Q39p`ds8lDG2_Ot@4D$N -3|RQdY2f7Bd&w6l6jyYxsM_L%YFypL|cOORG0IIlZ=w2w-f&U~WOoeP&x17L4em1IVtdehbfgwxI6%e -wZFVBHJ(P^6u~uUL$xN!RtA^et_2tc)f(zkMMeRnO=t0&gf?FaxW8jXYiU|-i?632ndXTzz7J8fWYX* -&Im`q#|Zcsy@JEUHIdie_9UjeuHKEKS44i67^MTfv6`F^$M@IZQ{|lr(S_O2;8r(%K1V3`X_u|G)z-oXi -zJz*nDzwsrXhCU*EUTvnewcX3uZtOC0-3oa)Ofp;Te>Gq8)PKN4G4o`we`1BnI~j5`5;T$0SDG}4DV_y#eCQ*BxGaKTdBjr%RRn|K8q% -$Wc;VVHacfEgYGT3pu*btGho{R=3$&cW{Wx7#A5i*!ZZ)`$-~9u*C=E -I^4)g@eBwlLDstgkmUWgt5hPtQBGHjFx?v#^fQ<$u15dS(4+Z2#e9oCyNfD7FL^Y<#LX93v*cys7Dmk -tVKs*}0z=+V9sKezGQn2|q6J%qiWAO270-qr37YH9yA^!uOQh(!kJ$8L~GQLLPzwr5NSRxw!a{l3cA* -bXT#?q9)3K7JG>7~poI8cTl$|;rnc!UZ@w=VdS? -Hs%!`Fw~}j-!<`Q3&nc2_iW?nML0E^dvt0g+Dnth)+)r)QtoAwAU}Oltx&^Hy}~KQ%8xM`c6t0Vj?4e -9-7lxGU_2(`EN7PTs&Z}d4lxy>(?Y~J#T>MQzXj__8s~Pla=kWD6`PIfJnkS5vbuHW -NMWaCVS{K6v+yTHT+-e>6%cZ9mtF)>nY85v6h1T~7&C3sh)d-rlHdzHAOB4rzoE7ym8S^b)mNXU)pP` -+(Q2UbEnt*?xkT_OHqE~_;J*%hg!lH3zOr%cju?kK(OQ1I*)?rHT>b$hITZ?NDa3P`k2KZIg>J(F}!y -yZ4Lb(rGT7eU=lu8WQ8c7OLtyJ$<*rtbc6Ad7U@fzO&|sA+ -$8QEpum-INYPFS)gE#2fgv6wBM6*%RCPZzmBAS{m@kUdFCR81o!r=z}m@qWeBxj_Rql!iZ!=UW|yC6o -#7R;YxRKB@|h$X6-4mh}XI8-`{hTF(d;iaQ(i@`DZZOI_^Bv=n&QU#Gtfys!3phSZXtN8GGtNezHj@Q ->{hu7D`7SWbXl_X)Dd|L5l+FQwh=|y3$k;o_PkBld!(~AL%a%*IkM7J38W^74U9A;x*U*|6G`WhVV?U -IE?Y#us6nXW*2<jVc$ZL6uw(K?FtXq)NPd(s%JLnv@s^|CM)mp{X -3E_qx#hl(UK8Y)&3rW;M4N>^g9uaLZ4}Zde_3czC^sSfs1C+@NF#SCAjUkeL`;(gE}-qTr`}$RCL2^x -FrO2c4^Z92uGk_H>F!Kgs5yX|S!(iyDzrt03{%+%Y^+g6NN~t2pcVmU!zc-;4>`Z;qUN`C&?s(;3c*J_nDJFGLQaVd)OG-sN(d9=0KdAX;Ji6VOn4aeobN4*W0LvS?_d#4#lHId -X=*V34FhgNOB1iMD{7=1W4}Y1qh}%i=V*h3jj;0=)MhsOb%nRA#wJ%3%5Ghoq8G09tf5b)vs#LiziKB -OXW>#B|LuZt_aVi7Nj*E+}{jZ(`-2tkWj&jDhHYyX{z7LwD1}*?~449cIue=CBWxQAe6O2F*kXRG|%*Fk@2Zl|e*;Jz%;;$&FVQvb$Kib_X+8C^A47-@rAo)Yi!?* -{|HgM0cnwl6os2w+|ZFa4X`l(Y*shgOzx`j#ca1wu&6OPZp3`fHN$ykQ=tXg?WO&7a6W((t9d;*y;n2 -)W)6O7R`R0tzMbQ^-zRrQVpi$tjr~}p}CHlK~z;)v=F8UrRxIxIM9@3A6DI1w18^NOZ2Kw*zEh`6O5s -5+AJ2aDp9>(jaGH1suc+=B$j~i%IyjTGblI38!}X!0jBxT$rbyPe9hHzH!$Tb^hD+a$GqRbH>F-m~IfA!&rv6VqJuyE4lXA`9fg) -@23A9+HeIG6cg7JSYOy6bSV^3~#`FxM0dVV`5SgIwo9ID56=S?CG$tviLltK`bu{mm-tF91TMyd`J=y -nZIsZa#w8Gq=4#}s%##rgPP=jE0S;pM}%tgLR7;VG@t!P9a7KfqDgR1dftHE@gNHbo6ot+K^~AW$;=Q -`h+G%iXv?Hka%>VtrD*so1W@ph=S7=nm+Jp3NgL9eO-$sFGUfR*eAFYS+Csu=wSZ}`fzBCQ{0Mkq;Wz -854goV#KoerUja&(0*dg@PBW$amJbC-^&H2ARP03S%xr0WIWwv$IE_M_N1ruj8pS$lo>#Ae(GAHx>g! -IU#FMogk?hUbkOs}L<;%K8_eo0HL!EFb-(XzIeIbTlm%W*o4P;m?st8Hdv$`s8cN -w+40ZK>EvL$JsEB3OIb;r9N+}synTKCy30OVqO)tv7)EWdlQuFH${RSh>EjHmPl$)8jVbmt@Uuw`=*> -#Unftb_TxsjDPLy%txQ_E2h`;EO=I2kP%CIA>P}bVD9r`YF%=XclLI7KgW}C9zCHIS*NhV=R^Z6~41z ->!#9aV=pQV#mF>bPUjs+p!f;Mc+79y$N`_T!kmhNKXYsboTAu?(e{Zkos4fLsa=%pj{AL^8Ic^=Uo#N -YCh1HjTOIST6dIj~uXRj~L{7*}ZPrk{Tl~E4hC$rdRcE6AIwjri$!DU$`rY^;8l7uzc6k76B -%doXSA^ENpN~1hzxh+7Js5+NRe#vFCfxg@=yAL_TDQZ}9G;x>6JS5yGYAi}0&XeAM`x9KLL*V!4Yh!r -FOSP%~iM(p}(w;(qO?fC`RB<>ayB$9+FRQ1FqBkHtR8LRtWcHL)dYeoQUBGIndntHC52AzIyxGM*4f} -hW8E;TKk<|Qj8?jPgJ1JPFQx$W;JDW%5Q!=#fw$Rk0Ap=Brv668NGP&G;tacdQV!bmHtX^_WAfY)wkG}`?%^e}&ZaQfVt2X9YyJ5J31ud?0lLg3)3 -IIWZdo5cAh3M770`$f&VmNFaViH~%dx4*x+%rnYC^H4Sk5X*h$`(%Irso38?t#pQpdT+BW;eN)$ZRv* -LkJlvZ_ry9jcXAL&$A;p_$UTIkcqC6%Qj{<^T7-CTd2^{JQMC?BqK~PtQ~9-FSG!7?K#t%71{*tIojy -S$u%7AT{pOOWv*7`w4JtHJGYQXZ3%FgQj|tynucmz}U!T;LUDw88c^;~RDz$AQyo&Snx^rqcW#2lJUy -Q4tw^zu!j@`>awS(`KGw(>S3fMgGj#ujtd+ngR-1#g|ZEqN6IQ!l_L0KKU{Sdr7jBYypo}(z5+4Y0vJ -^4F~CUAwj)?xE4N9Nlo8mG^zbE)oDcAvFx&#iOUzp`a#-lLr5Kb4U`YOF60^F~{h$L_t)-O%>?edG41 -T9|6x;kukyU%!4O)6btjekLELXJ@bfF(toFr*Efkt@=(Wg5h~M?lFobBA9zXZ6a)SuW>dGZV_rSdBt`9z&Es4cxhkNC5f$B+ICP)h>@6aWAK2mnY{22* -Ygg4SLD0043T001Tc003}la4%nWWo~3|axZ9fZEQ7cX<{#5baH8BFJE72ZfSI1UoLQYHH<+DfG`Ze?t -}fI>@5DkUw9KKQ#&YBE8QmedmZ92fh3vkfS78jMu@=ssa7B^S)~@jk2~1-;>>zpBNQ%VQL=a5r -FQAh`_D&XY929)yw?Gy&|H|kdjL>N0|XQR000O8NLB_@4Xmkbt^oi59RvUXBLDyZaA|NaUv_0~WN&gW -Xmo9CHEd~OFJE+WX=N{8VqtS-E^v8;Q%#H8Fc7^5@*jrm#i8E7_EHGs&_fqWY3X5a%OYfZlnkp#MkBW -|rT@Je%Wj=)LdPddZ{Ej9GQl4~DbvL+pi)4`)`tkXVsE>MD*uW_SvO#kjs6t* -ln7j}^zD>j;%*gbX!4KumB>`$8bl1`WJo&jq73CA0wzop#^6!--7l4%*(5i`#}+R~C0V?7Jhn$oCByg -W(@k$Y2NDwHOL9SAtNlH-pN0(v>1J>H#r`ujupm_mY5r08mQ<1QY-O00;m`Rt8fBInW^`0ssIq2LJ#d0001RX>c!Jc4cm4Z*nhabZu-kY-wUIUv -zS5WiN1fE^v9hRZWZAFc7^5@*jqrY-&t@n)zZ1xeY>{`=1OBavN)w53$1So7xT& -C?TUy*q$X?J1r-Dg|^nIv+vrf-|Rxs{byap;rpzYyl@rwQEoris-co>s2cpM>>}36>Z~u8R$F`MLb6p --;cOn4Zs}*tm9bkzm&l?UJ#|)>3}0*>j^;zc>MfDehO;6s*MhzD`mre{;*yFuLfJ5hb%>ufiTIYd>uw8Tc1K&fIryR1pX7R9P{8#Ut&o+<7fI#7J3OpJ@h@R|A*yN -&lY!gwX5?-h}`gy6Ns37q4*kq}IIkMLE9{CVPZ#Ij?qaz!IE&Eu2LEF*g7d^dOwX;#P5f{h!xO7;LoD -M6y;>cD1l!e&`f`wi=`r0@(-+T1f(z*KXEY9-MSAYUY5jY&fP -9@IEwtC;Gszj6fDeDm -H<@ruHG7ax<{tQ}BqN@6aWAK2mn -Y{22%h40006200000001Ze003}la4%nWWo~3|axZ9fZEQ7cX<{#CX>4?5a&s?VUukY>bYEXCaCrj&P) -h>@6aWAK2mnY{22)=uo>t2N006WD001@s003}la4%nWWo~3|axZ9fZEQ7cX<{#CX>4?5a&s?XY;b5{V -r6t`V_|GzbaZlQVs&(7b1rasbyC5K+b|Hl2mB9%FLA(__FCA(Lfc~tZJ~z{l(9Wd#LAM9##!92?~J`p -v(4@xgEW3`=IM>P7a|x}z*kpq*Vf3~MEg5H-BD$1qvQ4K|s+C-0qHDG -Z&QZfcP3!;fv871uXWOvCvQ0}J7-Wv-iKap~yHD8$B=S7}K_blq${L0khG>xq1PEP-b6W7W7O`_8NeA -msT2>1@u0Io;@j`&$v8Oa(L%?TbXrw|-K$g!G;duNOJROgqr6CE|pDOrGOEJN2g%SDzqtfMj4#IA5O! -Il#O1`ySC-?IVJPnjekp#~qG=HJUOQmZc4tfRZ2cBNqL1$y)YQ2Csux#Su!)(v~!$Fpc+-`Rztf`NO# -m~lJO7PV>nNXqAsFwYWtB-CtV@+)Th%@-lB(;zn^&&rAThH?`I&Wi&M6O#4X()rk6M3*6Zkko^GBj+r -koLKnlpmB_=XD&Q)K0E^;J}JFCGu{86th_R7;07ha>{UR`^xPAh1>xBp-@R4pl+uQGXEamNsX#}0|ax>A4;?J -pynNiH&9Ch1QY-O00;m`Rt8f-4y!#O0{{TZ3jhE!0001RX>c!Jc4cm4Z*nhabZu-kY-wUIW@&76WpZ; -bX>Mv|V{~6_WprU*V`yP=b7gccaCxOxO;g)25WQz6|3Tvp6MH74J%`c@g$@^bC^shK2zwo?*pjhiXol -gxS1ZYmojAsTPX5@B_x7z;N=lKFFia{{l@Nx6<%K8}q4!c`m4eW|&q>Ulm}G*_NyS+tVhA&)pro0cPN -tItqbzFYdny6HPA5@Dr6gA@)22RtUfAbgIh_!_JkPu4e<4zmtk>UjP?SU|EhVV)%bSbeKd*0o{aCMwq -8q}v5+ns06OoWuL{$!4X@46ihD5VqoT)JMC1lB*NKus$%n5J}m+?)V)8)M=fhv%MI(P`T{=KB-#`!Oa -O2Iu7B_4niskCc;U|;949`&2{A(~Fxx&e)=Rg^_9fnaBgpBGKw^Cm|f+!aBGaxvPJrP6e@lUHb+v5qY -eSokmz6_2%n-%Z0Lxe>e#qX6yz+^yQY5>dJeF}}~M9}_OMEfAJ*yz}tQTXij1;*2!-KZ=&>mTtVgD7B -r9!fCFfEHd$|+b%GUhH;Nmr!GnEn=sfuPTrTctSD# -KK%B810^J%y3rO7D%(RrX5nQRsI>#e4)R3yNC>AA>o0qFDtfqN5U1jeE7wBIeTH*Kdz~6Ac@O3uT&Tz -y%iqX1qEA5|<+dC`jq6^|iiZ)z3?UTp)QC7ER3|V(bSYbH -Pf^>qcn`P5ap<7?Wmx2)$cWoV(dWc-KfK_encgSaemInDrr@9YnyNfIYtD=lIU^^Z6!Xx*?*8G)VrXN -#?;;-E=!{D!t))HH00)XW+xlI$46>NK*x|Tr4MANK18C_`%m>-paxS~YeI1vwnR%_0W}J;n`O-*emGX -jRSEkpoIC$Jg{D}9+y}Fw}gJa*O{?Nf=+QXfjE2z`Pxl6{Pxr@j$})JPvhS~e17t&oqA<&S24t4nNj -u9+@LO^c*TZC)e9eJidXYsQr~ty=diJiw1iUcvJgi9rMTLn?~DYJkuH!2!E;dpq4{%7T1f=}2ahv5T; -^-RrgJpy@mu)r4X_y59({eM(YlpLYGF3X~Dn8AnWaoA%5_x^j$=(8-Z-lFfat1c=CAykqVc+w>74tw6 -*Yup7&@z2%Q=3G6B_?9Q!+obKC~NlU)p8cJyJedrj9`;_dE3j<%2L>ECw$2wPu)TA2IE -fnwIGOu&+S>YrTh2DFyTx{dngSBI6mIo)Io?NvD>#sV%JfwN{@9X*oSb;4 -4%lcPoGh%4q;yF=~|kQ+N+X~7xXg;x=G=dixJPd5<0+9o99{S{nm?5NL7`aU@ZANroU0DjxtWq=kH&|tQ+AgnYj4=ZybNqIR0e=_(Zc5Y0SRS4XA619xyl7U_v0MB3b!=1s4I;<-#zyfZxo -z2z!~YV_k#HIJ>ls>kJg`eu)>V2#zOoeQ$kO-pBLwQsqv>SfaWv&?a8h6HZA1hdixN{EOSpg6_?|>5q -q_Pw(3)HgU%bn9j|%jSrMPo@tIXq?t|>2Sc!DW5*-)QN@0GnP@3zwTL6#;Uovul8W*n6Y+JzHg7~|c8 -1=Zvj~qjVJqxz%wvd{0z8MZjE3HblSgf{otL0+B@^YiJWqfH=v9)sH?o%f6``qNJO4+u`GbQ -Ar$gR}8FxOYtS1aT)Zw4>9k@)obDl51#>|^7NVUoZ3m`qro$n=XnV>y32G8>7%A6~OwJyyITs6b=VH+@D4MDnSF4h;O8&5|>6|BS -gW2tFBOB4b&hT#btz%wC^p4FwS+4D8em9HQ7U*tjHiBC|`^J>+QZ+v`2FaD1MFXmZLG}%kikBcu>Zyh -L+=dDqnla);S@;@!s6@Z~QK4idLXk+2)8#PzkgVxjPj}6Nf~6RDC`HFC9_QMn98T+GR_yTm0rL1gX7|DbqS;=>7DVZvBYo#E5kP%k7Ht>F(S9c+^yfOeqqVkzGA;Ov2@J -zC7%{9*e?kF>7nJSTLe#lKr$cU9w83%(3H?#MSbd~~Ok=6T#lbPMN!yPVa)d3pGT5=Ilo#FG#Ywj^c& -3V<_&BIY&zI=JZ9wdV-u4po1(27yd8*-H8#_r;wOjg>*GMMQD(&BXt)wPX3>#dv?Sv3QPLl;9d0wtae -IAp2BF6Iz?esPEROvgbn4Y|o5ncUdOv_td29GT8HHe?1f8M`awo)$wH8C0;W!x~;nk#j4H9cF?IZeW^ -*e@8HXx&xd%td)T&kTuwE%?;QO*4x^G^8xq_1zA4^J_3jbQ8cu|w4opr`KM6oJL4`MS}VwVbPj`H0m= -&QH0cxL7dqqsO(0f|PgbfZ)C1sYx!Zdyy0$&T*S^o@<6@ynT#4hIq%0ve$?d2WBpRQcV9Hc+r`2{73# -jJZ#e*tj><|b~n+GYuy5?Cw>+o~I*oA!U5_q`=A9v;=YC8w9MIAw?Ekq?qaL -O2L30{7=f!$8+f(S0sj8UVJf3atJRV1KG8V@$ywYOqU1791ARO=R|TfH(wLfEg_U8uHHz9;P3v8MmrY -q1Y;@FI!HmHCFSV?bx-=L`u^q1dm9EqVs&yx92`E4Zw+vB5^M}ExgEH1`+>ABj?=m(3#}B}AT-#CN1{ -(WBHsr~@YC-P$QDJ8769A3g)}7xM{L20e6%52(nuERH9?)Yy}@7u$5G2@I%1{LxP(-ermEbM1mRrSo@ -#}h+9*3(pJu>733^PcaL!JheW>eH<-DYRRI8SBf|vZo%@toL9VwPETbLl#avlSQQ!F`HW9&n@PT9 -TnH_VfwEECJS$**=2&QUe7Y=D_Whr&vOt0D(>t9D?C0}B-QmBc=02Q?6v|jx2qU||z!F9R3Xaz)H2{!m4F@Q+?XamhOr&6<4Ye6zry?^;UllB0q6*-pExbO=Y9W`4;B!)^s*Bdz3kc -cT4|Iv1NYXB!zF*RMiO^sBiLS|0Cou!3x{>$vM`c#yTDm50p2QLzPu1FUI=`UvZ*+c1=T~%oeG*fL7a -B-s#0>reOsF0zPU1#&6QGK^91d4hNg=ZEVq2Wn_L#UDVMcIObhO*;UY%0)0Qq?}k2haW#_w$K!({UoK -l%OM)K71JrQ05!VWe*sWS0|XQR000O8NLB_@4Ub>JGZ+8>rECBIDF6TfaA|NaU -v_0~WN&gWXmo9CHEd~OFJ@_MbY*gLFLPmTX>@6NWpXZXd9^+Lm)o|HzvsRD53C$llD*P8Y1(^dd+p~q -Zkt!9_Vc<)d%GJMA|VM`ilhNhyYlV*?>7T}fy6+N(>uL%O%4XYU@)Hmh>k|1?|C74%rsA;mCU!%MsL$ -UreYa=J^yny*CL>B1{j~LKmkf2|vYRH8KS5Zv?G+kz@6q-SQNPo1?OBrRHC(7_;G#Y*Rg<;uZu -_|>b`C<`?ZIMe2qf>cWYQCu6PohNZgo2(Lh|WT!~w5hO=0(GzDgyMHiz#ixkE=x8wFv5FMSgchH;#7Rh6`Fs -*75XDjSu&wc1q%mSy5*3|TbnUeQa+D0f6Ts$AJX -2gxYMx9w249SEMB}TIXw1gblY`~Ur3|6OGSBwg5LS{%u2cw1@*qW0i#X*WEG3d4PML^2fU^vhi**Pi& -ExBjWv)Zy1R1?7wa&8uQp~a)3$Yor8$~FD1){`5M8zUFFtkuXlr)U7mU&qO(Y9OA$pBWuG+Rq?3|cCb -4xt6x;i1tbTr;r5A*@ws$`ZlSJS35c2u&(Dm=H#AL?N#6kj3EOar8`qjf_L$vl2W_z}5xP*2hUcAc6- -DA?0~kJyv-Zqzb~A0Lq55B-qvF>kz^>A%s7K5WWo|{4s>^rw~GDm?BiZ4avXAiZV1QA`2078NafZ)iq6xYGdG(^ZDtE9?Mt -f_+HXHtt0&N5H-A)FA8HE7-uvAP!9AUWtpLpYlt0yxMJPH47uh>Vc!D?`$|V<8%LkhOSHk}cDl)>0o( -x*nd7b2bu}GWXDBqpc*1!&n|CWTP1KuVN_*?J+<$_7S5zf?@g2r|dRX0ZA(N$Wae(!!n(F{AmvnjP$V -sm0msQW8H+24D1NBkMf8fmEQYoN)OFvz6MBMBi6?|0_lLU>!BSnp=i#Iz&b*Nz&#x!X$I{mq0I8kGf1 -^tA6mj`i!%Yuh1#f)UgoLK6bvwb%>5QoAnZmNghW1# -(oNBTVjQE3d9OXfrH57FWptiJpL>El&4EfSH?XE(3Fzii|V)7s(RAeVMF{dl+NOh}K*w)JGV#@ztpm>1dup2Zv7;-HI_y5@VLq;D`Aa4Oa -mlxVutd7N*Hl-tJKDqQ7psoauV;R2T|zQ%Oc&ZXL-lx4Bo!*U(>okI(UWVGN?3r_Tt%bq*zfj#YYWeH -e|L*>A_jmxKHt|2zVP)^u6S6v!|VLw!c;zpKj2oOjg&(#a>u -sWqYZ)iSm_p&L$W@&=M&+NeQE!d(H}Kr=2-a#y_&2zJh;d^5`v*bAVjFT7pymMN*0P-;LaIk@rqngnp -u1#T9G`>nae-$_gf+|!gw|xtdTcGp!a!}x&~4bLN0m1nVwMs&=e69SfA4&;2%pN33Ds?&V`{F@+p`EK -_!8dE0kqQghMLM30bBi@v{-g8`Vms#LphR3Ur3J9jEHe$+5blwX4qs<3T58#y(x7YO(36h`3GTIL5Fk(PU{BP8kW -{w(S@WDS#c`i!j&Mp8!Wk@Lnb;>^Tb!kNWBs9bw=rJO3NTFO&&-ev6xOJu*B#A5lS2`yCqE?cmWcg>k -Z-Hfbq0U{iXt11S@CYbsnUjpqX548l-$j_{Yk8QELf`7fdou@Lp-jb-Z!K*<(EV(4O^xppqu!O~gS5h!du|?`?D*|UZS_SR4Yzi?{Bu)Hm#kPV7noSvL`l^yj*L{UPhcffoUsL -FHH#xCd;LgIz9mV=<7xaw_!sY!LnS`zD1@wPpLK7s$!_KnUzNchXpktTRsj+YnG -h>BgjsP{G_U#oEhcR4AfV*DpnVM#y%$@efLsTt_FZO_)Ye5?Viw(=>zZT9B@}#qh^l5FX@;&s?=24K4y-(~BVmElil5 -ak=9!Q~~kBJN$;g4M$uEU;UE;{)+%&a{iKBDyqu9Ck$zmpTD{VPk`UF5Mfn~@@HtGlvLcsX%UsVrh)- -UEG!WDY)aT?DfVkQhhYPT;bufYicA2o+V6en3ROuvk*MWQ)8 -f9$3)g_75|zOT2q&A@zbSLz&}2W1B}9AI)+tyoR!yL4NFFB(RddhZuN|1@rIZ*?dpqmk2W+VT-Cky2B7ARlr2bz8pm# -k03A=Wjiy;k(R)#k%yKoUzbkEOXz^_UGkG$Fy@)PUYWf_at8A5)tMkhcWum28BTCEieD8*eXR-aj@`-mtlHLOJY@YNt1wLCGhqGU -CS?$(~mec0kg<3!xhqxWc7iWbh-;GPDsJ%%~f<^Ioc+%+jkoHh0Ob5`)jp;3?YjF>mwn%dbZWo&X>sY -G)(m&eN6bz5^_2Dncc*ApOuU|@>(+kW8|6xn{R?n39j*@i|ExE(xJ1%8;Y*NHDsp^E!Hz$gQ2Z~~)7T -v)XYNp2Qlh~HfaowDy)^*g^7MLR|v+7_9T?W9E;dw(B?jqwhFkNCcu;`*L7;Orwb0FZ> -YwTXn-QCk|cvQ*B=?Fp;8JD=wlMA{QM9*?W~hkn0=QOtpXcoVUx?kqB$J!M4!#>cpgXQxjQ_AK1kGb&#q(#x)u-3sY -j%xH?^g=1{qUJ6lTn;sN-GC^BtDejsgps}qqkv$Y1hGI8e|q)qyEo^rYH>CDj8S#1&jcAVub!umtF}g -?(RqD;kBT%Hxh%r)g>9pJ75x)W^*^i*t~@mR#xS`67v_jaWI{)4FWFqNgpDSUdMy?Lnq4d=il-}z@ai -jKs$_WC&e;%fs8UDHnF~5pv7eBf(cn-6O|*1I0S{H~`@%CCe5ire1)VvNgGAdV_Kbv*)%z<#XM=ZgzU -k$SGY{O`#308%qkxTc;}4|rB?vTrxx#8iK*eZ^A2YdjB<`^>WgzM8eNQ^CkY+OuanfFIz`Q}J;?WHRA -bnbwyuRrx@pjaSWZRYXg-z2LC|bYeh8&s->=-vKibFm3<+<(s<@tGJ#bVTOhopRNuZ2ua(gmK{cG~8^e6$X75)wYF>+GKlAOn2=PJpL`s_(9aQ{YB&>W~dYv<}&97 -m8MQ!u@T79Q=oMk0 -ol>KX0@7c+e*Na>SKlvQy?*uMtG~ZLKf!>uX|D1pSQW22#p;$S3>tXx{{6cjzWc}fSLgHSd=LdU?V)K -f_jD$v8*|ku_JLm_pydHmQ1Do+1iUWyZPVZs7jNIadHd?!`yXDN+XUJee|z<>pWnRu9!CJ(G`^uet1! -1IN2-C^#ZNC@FMc>*fPuFO1a4(nLm_@aVmv@)*_B10HFhBG{hOC>UY}zFZCe!u^ZLC3NA2aH3!I1kawo_4jPvuDxoQ~ktS3k#cy{!W=O+GnF**^X7nVEfDX8qD(a$>`ZjN -T{zPb7w9}`d42+di3;^IfOiAKFm&q24ZeUMBVvZj|M%8|fif%Rna_SQNim6g9FC=1R -+?r1JU45(kta`Z^;TzuEI@G5M4Q6mMI>&9f_iQ~niAJxoq7fQGn -0&!pQ2Ju!8sNEhv~@CxFg9q6iK{*Bv9oq~7})rGmMc61f$a5@}4{v_9>98~aIFpL!gjo{a*2ixIkf8N -f{qR~rpWwIU(+Abiqw<|iG*B$rlCQ50af`O1)(>21ta%8SxCJZwg8P(0Z!M$=(7G^4pAJ7w1XAVwXO{ -Tr51%LOVcP5lV-CCLtP#v?{{3?&Ms6sCz+g4XIUqnOAaKh962rk-ouUzb|mwAOVX|esov8?fp(3_}}0 -kF2OBP!0u@nN;$(0)$_6x6stHaK2wT{mJF?_%AHegLDIjoY9;23o)lp@oBF2=D7&^V{8}nqU*@dGkfx_MY_A~S0s%lu=2Y9~o4kaWV4s( -mm_dvvYe#Cxt}YojKAUwHR6mdY1rry&sjd_^-?6~BGjxB$9KPzrv}KaNB##U?%!EGJ=8`|aR3Sq?n1* -fy=7~rXK`u^JGvK6JFjnPqGP?M1dHd+m?DF=TN0+z%v4RKo=<-rsJp{9S%yM7zYuc{#>jM8?O{a5|F> -rCz$m)?;x362XRZVn9a90u@TJL>cw?7$Og1=rR=xs&>JzDMw5jG<;;c|23`Mi0U^tvHhbx@tatz{qsUBQ -T;LpV`_rMTb{4%|I`22GE8MYvb#?fb?)5gP%-FjhQpEbi=lMKoZo|9`CW;6*I!kGlgljC1nX3QUa*0> -J+s-YgF=!y&oJIOg**=1jQaLs%mbVxwz_WKpCoJ=}aYC@w9Ca)LX)Qb<6CHF;%PN?b$6hA)~!I-vAKd -3bWi`3E6)BEb#D7x=ULb`CdsWpsJt2pRjCe-FXbbxzt<(h{{rs{;^B-*tRazn#hXugFI*EhLyR^ZJZl -W}xkosI6R5j<4-VeF`Cvm3Me3bsi`wbte4eO0rwugw^3%<;rSB~a5|KH{Vm -RI`WXsF|Vp8Zv+pO3}+S$IIoMgmc((KQMnh`}!(+7>!P!jckkE6FDU3WgD*a@T^FGNTE*!db(DLztJ( -9?t87GV3=Yr{h5WK!RdgWg}+qBy2JYv{*0%_3!wF`d+DzjtXY}ql)!pUI?DFPrd~vBRZ>}DW??(00=kM$v)rU5`flvaxufE;py?kFO -Q#GJ(xU!=ew^=^Wnz30z5#O4HOWS4;OY%s=NtR54vB8EP*)y0_x6@p^ptMhJvZD-+Bb5Ekau{s1RAno -k~bT6JNWbNPmxwXch<77y-ltu^vAL$NjJ#6}&zfJF5##zp6-uo{VSX>BXZfn~Dqj==(`~JzRCZdfgpp -`kddmx&32kS)19Ym*}y7LwrphW&CR9H8sdE&fW{aSm5$7$wT>@+`9mYXS3Cd*`Kc--pTb6lr4F9|M|& -f@&NumH~(BtpWj_3|NZFXoBz3-Kd+xA@%E0xf46rcyW4K>iukV3cg5}9{kxO9OFSro;#(6peT+Jp@6aWAK2mnY{22-!+5=8w00086!00 -1fg003}la4%nWWo~3|axZ9fZEQ7cX<{#CX>4?5a&s?tXlZn1b8ul}WiD`em6T0y+b|4{i{)ax<&ifHBa1{jsDSCLsGJQ^*%*@5SG9_&GWsbIGsz6@q3Wb>1WWaalMY{33LR>>93zX`~Q;0Z>Z=1QY-O00;m`Rt8 -gNQb7!G0RRBS0ssIl0001RX>c!Jc4cm4Z*nhabZu-kY-wUIbaG{7VPs)&bY*gLFJE72ZfSI1UoLQYZB -k2112GW37xq7l@z5=3Jb5W?4?>}Wf(OBaNXYJvHZ+@wNw&2A-aNLYLQgxH`CgeUW9;1_g6yOX=sai)a -HIiRGJA9Zz8&>I1|cMv4{m6~;Np=$8VXx<)ufuN53;u!=c(pAk~_R_G_||=9PBY{$)pKDk+aHju}9O9 -1JzrKHrvqaN3EKxAby(i6yh9pr2e4sTQ%x;)WQ;`i^Nzh8tRU#jk;MpI- -6m%rcEJR!#Cwh4>!Q>j`mMo@_knA)qMdJLuG2c}3<92BXqD3a#R{rS?fGtMC)q%R_1kA+?T@OZa55#l -BKAxZ^x0hX0%r6yO#N{mN>BhZb#s=R93IM{cB9>7ylTk7HxB;nLdpSJbR1v3SKlP)h>@6aWAK2mnY{2 -2-D6%T-?j008L*001ih003}la4%nWWo~3|axZ9fZEQ7cX<{#Qa%E*H -Yuhjo{vODGI5Y}2cwzk-D5Inv^h48a4Xh;?quO$#)s~DTcMD_xeLBfb{F3hF;|w8sdG5Kp=T28BSwWf ->jcF81Q{YuCl>z#wW!V^(`h5gBf8m--5kVt(CUcgS+%QE;J)g~I1+qLbp?7?dNyR#vPitDS2ri9L`gP -RZ=JN9jKvp}dXl4tdNd)AsrWxxUg+0s$q0i -V-dcC$$C>_lrU{%uFtv;NT!ZAj0GhqdJg^+1D0aJrxULVjfqMi&FBAk|CiuU7mjKtcTMVFj&a1yTPpq -Ubv}{;7jiUEq51~N|MllC9UD$V8=^z~E=L;FMkFSjq^RaGS3X_V4(^|L=z33I}gko(QlUU@4IMo0b$L -s&3;HR{718kt<_(hDLSC{)rRuvOwoV=$!48uWL|DOCxW^Q(zByR_7G?1&ORNXw5JiE^A(Qmu3!|T1a? -S}Y2q(9NRrdk8Mfe+XBH}Mj_?5M%Ho6Gl|;dCJV!!Y^@6aWAK2mnY{22*hwr(jV6001Hf001Ze -003}la4%nWWo~3|axZ9fZEQ7cX<{#Qa%E*vT~R->j* -M&7FK8#L8U~hGfbp#Xt=b?#d48*luIFF%P%p_26=|21ABDNh&`d%&Gt)C%042FQ?0Dy%GsVc`&C)@tP -P5Tx(0gM8IwmV4d&vK6uc~jI=}<`{zDYnKx2qN>Xge3FE9c{zqaHlf>3jG@tMmCZ4j=O3!owL772s}r -5$Xv!q(=;nE$0&?np;Z=2b2i8Rp=0LRku4xjdnX;K)@b(R56Vu{D$ECJc@Q? -nVL3)M7$+~LYgJq`e*^oi_Ws&92RDFWC(6?~eM03a+H71Q-CK!Np4#Ds`4!t;tyJ#D;Q<&Oqc#tM{qS -WGs>16o$}Wru1Ge>Izw-l&fIStZd-LDn1clR$v!rACLV{LU#vNz7XdE;Lgx`peGgDU%g!%U77-Ya;mP-S=YeWbR3>#8r}`p6AWsaIQn6}O&mu -r08Q;a(^RIQ`k2g&~$*moRSe!lqYkk*wrhgJ@&g_ReDgCP2r(3_g;fwyi20~T1*FM5=_ad)h -@A?Z+O9KQH0000807zB_Q$!N^kY5D=0ALOP04)Fj0B~t=FJE?LZe(wAFKBdaY&C3YVlQ-ZWo2S@X>4R -=a&s?VUukY>bYEXCaCx0p+ioK_41Eufe;~YAtQ|N5^!8#P0n%*HF3?SZ-E?1y!j@-fj~b2SN*X(9(SI -*V&3G`KY@SQ3-4V -DPUpxT4=9yXQuQ(D2vbJ5DT -L6@2&&cOHH(BOoJ%D|GAy(@9PUp -$Yy&Ox5QsIg4GMDkNbR{TyvEw#^~%pOExugIwdC>(U|jIu-J5C5HI-P$eDJY}={8Vi3={(COmdcajkM9bOC?;%?C7!aRXG=UfWFB`cC?M*w -PobB#$|qo!uXl--g*j;sc832b!-6dKiu9o*lGl8ys{jWog87O*yT1%)F5rEC?T38VgCGRn<{hGHzri9 -JNY=Bp@LLv_VI`$5{rS6KFHZly_D+T2|P1k1K`8X1-@R{{^iXu;cA>4ec#(gW6n%7ZHK()1bWklQ+uV2TAS1 -foy*XJ_rWkCL#8Ppu|H2a=m%wvU~?KiwlGY~=t?&M_E}Kn+5BC2n#G=EhGz?yUe}&?r=bP6+Zm0aZPY -g598;=&>Xr6BQR|GiR(j-g(2~1>2r=7c&nKqCqi~RnkQd|W@lIlVH*2qH#+@X!>1c9l|ILg$k -kc#~=uKxsf+FR@cyukgAp6!A7paVkzG#|fLUx>st{NV{;fEcK=Uo~{vk(Ov!UhGjEJYkBh-uME#JWH&6k@`kjq%72NLxX|1Y%<6tP9gV##Z`qB*-xdLE* -rMaUMJtoZ7q7)^&9dZRykq6z+>8J9$cz<<_6)Usr|q1CwVzqYu)Q7Ss8|4Ssb`^!vTU)(448g1cMR!z -KLs9TyURJj|@#%pUA#!-2t>BabkSLTiP&QGb8f3Y5Ox3!vwdH<0$c^f9&>+trN_@+}DlH-Ch-)YbEA5 -cpJ1QY-O00;m`Rt8hAgdm6u4*&p$IsgDE0001RX>c!Jc4cm4Z*nhabZu-kY-wUIbaG{7Vs&Y3WMy)5F -JfVHWiD`e-5YCf8@cg&fcyuZg5ac9R^mJK5u>`|l1o|xO%NnTdw|b1=oKaLvRW!jZWP@$|GhIqa+lNi>Uk+P0v=D9;Wwo?ue7MmOTg8=sQ5 -Glbq~fNT`o)&lr7Y^mxEHwG{uK;m&!3jPirjDQqaNss_SN&tcM6wL15dr3U7IeVol5?Cp<@yx&ET -X^&9{d){PxZsS90ogACm^I@>gp(lN)dBNH{;eq%tGDkLY{lx9tct7LCW1b!YIyWej>VrR5=PFqq?TQFfTTD7FTMN`vPgu%wDCc -{FDrnd`KG#meVlHhQFys^euKJc;;c_e(hEhPvI{Q@{gdaB726l!CQH^F3q^$~p!UK!lUT9pfQZ^ZP;c -MkWKOYnxs3HYX3f(Zi_M^Hv$!6I-npJFs<<+!(4%W~le&hRz^)}>~f23E_eC>vmxmt_dcyFLb}U=REg -pw*h!vfMKT0Bb8Hj2P$X2#+;{xp85xwAsPu=6E0#0Ad(cJTV;9}&1{ -D*VjArn)!Ra#W0^3EyPoZm7(iX1QEmc(Up}DEe!FTQOrVZ+^dG| -ARFv9+Hi!tb+jiw3qR;GDfA9Nk&wnNA@#dG$lT$`EcJn=O+itYuf9a(rk+g)$em~hE#rP?>juaqZ$e$uUyH$lEBu4! -OsU@B0$;l*C%J>9~>Fdz6+dqYk8iKmPb5J7IdQ8aNQzz7b}v(6>SP1mHJF|4LL?kp8vXi9yt!B9NV=5 -J|M^#1{q>TArq3y)>jd;GzVVONn&McYto@9TawqNbZ-Z!KZh(|<$PZl`9ZvBOK@Lzj?rm)BD*| -cz;lTA4KJUmhVuExQL;pAd^KmbHczw$70jiyUd1lY&Q4CRl64N2UpgNE=RY@4SG~(ZusIN(<#Qx?>>& -0z3O@mNzn`3Vfl@&SUtGW7qkKCSlAuh%~z= -?mhM?@$3WAEI!~wrZF4c#1p+|@`kn0s^#Gk=gO-YZtacS8@9jdXcA{0gfhd92n}r>lDtRtokT<1y)uN -bV|IcjC9zELacC+2LGgYr1oj!T;x3pj~$LF$$!p_EoDaFcESH12fR0)HUp!P ->!aI0*&lGb#wmm`1<}XiCx6f-j!?h=Ofx_a(uP%U&yqZS_36xHVmnEU^{B3rNu~sLej_dr>Q2Z_e}hJ -LzvMQKu^B)myv}a0(2C?n)T!qSO+~!?vgng>k-QJ8YO~?UOEu5-a*|xHMn*?>>nhNR -+CZspgt?zL7?>?Q>L5Y6*sRvG*zn&1ICgr5_3xIJcFfStA%-TbQh~BH#$Ird3pMK*=Rv2OO&K#}d_$^+3_|vezQ*?G -+VT(lU3+slV{a9cD6^B(kQ}r#*Hsv#X99jdC;{M6z4y*_XwRj*ikNnrd=-Py+dlGTc4)813gD03lO0r -y!hvi{FOrXahC)9A6*@1jt# -(zw@rfArNo5awpOTAN}R{hhm^_?9no2ql0T(1+tM(*_RpV7PPmJDBe08h&$>>@1kt?YvMTp@02rG%wq -v69NLPXlkoY8Zw<63MY_{P@8~-}O*f=_4qqk^d7ko9k(?v8zYS>OZ*o%=nZ>P8$!JsF11BCtd7DgwcP -m=*5oj#5q-*$j_T0R5J13c|nT+rh<3_jl_apn}Z)WANDj!j3Y=4`9B<4I~Nhg0j$`3&`f?u0s%wI1X# -fBn7|#XGvtt6H&(kKjHuxE8Y$HiCusIF_s^<8s)#n^_ut@d3w9)yyzOme?)EDHfN9NJ#%g8Fug73+nD -sjTWbNe%Ro!TIAYi513^Yp}1hMl(okDp@KK|0!W&#F*SFu9kJNlUUTd_rvPpL)SJw#r^ZC=p*~&4?^B -M48{PbY9Y7e)4^-ffg(#Ot@S_OV)YHU{@s4#t7uHVm#3a+Rx-mOjP{J}OPhD -ddT8T97Uzp@g?|#R(tF5~HsLD&WE4d}*Bc2c$F^1CuH!xQX$$ix?j58I_s?u!C**$WT -JgQ>T+kKQq?g*xbH$3%&X@E~3|(g+wEne)RfC|%Gj!zQJA~1vjqMeur6e -)T23k>Q&G?p(QiO0mea;oaS3ClR*mz`*iN8tKnVo>`Nr6o^>YSkUC~S?RnhI7@B3U6DCRPBZ8&#u>9m -md?Ih5I4Ep&uxzS=>L@>)=uRX!Eq@&v2p+v}Nja#y^4~~Z360ZLcK8urVLZ6u;C=ZDlC*Igr~e7t$~w4#cr&sD+13<_i8n2L?s^+pIr3qEuG+YLtrmIPb>fbw3h -A6I0x5Ff`aa=Hw-I_R-(Mg6#6C53xpzYx0xoYyk~$GfChJg*iPeC69+;v@b2Kre2&-1!)PZgS{VFU%2D_CH{qZ0!0+^^g;Bs*Ob~}rK}^OCtz-P -p7Xy@O9KQH0000807zB_Q{5yS1rG=S0L&u*04M+e0B~t=FJE?LZe(wAFKBdaY&C3YVlQ-ZWo2S@X>4R -=a&s?aZ*4AcdCeMaPuw>6I}-oF4MODB5OsW+gm#rE(5>2ls=ZE|D2hztfY)4dvmM~3{rEk0?8Hu-+`* -SERqsgry!m=5Nf2GGDkc!VS``IJ1t9Pk-=>D_MJ@1cK`!uWMa#S09rBctl|UcV>N#T-J4R>^eO!zCszgWe4}Owkab=#Gf9YWc3FMMhW%e}YO1vLvOza>p~RTUbDIG+35Y{rS~=&Hxike6h -cB%m3QBq1k79wE}uv!UcA7h}B!to2`pp+yUvLDTA!U<7=tL=qyj$;B81rMKW^JpM-3Je7}!CYfKL*W{x)XZ2772-wcnSM)#yI2x$}6y$|;+l83H2)#T9{%LgwziCXm74)4B;{xD$KbY&Dq$fVxX&%415{RZc=8a_n<=K06h(=9Z0pTFl)9b;l_0 -k+awjDQTQP0OAe}7kSC#8XIS7!KYmB@ijlbzx+jeQjBQRwNm&{+lyql9m$vwLJkcRDH7JT5md_XQjRvj>OmTu9bRPbWEK!ea|GPtJ}@L+2W+h;NhNkU$~xdCKwFrnOP0zqDX)wrNJ -C7Dbapz6?&c#VSN06x|I_ctEPnrr0vnBt;|jw3m4W?Sd-b0gu=P2^IIHsqXDTe|$o12K7pDc-TV;}ofUrvuX9pejduV6Lu%48sNd;w6DW>R89YCHamZn=s&-T)!c|)%&O(- -ApYR$jvK(B*)u`Gg{sH5@hGPR}V5OHfJC4SFn?Y3raA-G_~Ed;FxGu8C3)&+$ulTj|4)_GmloMeX&m{ -ED}>MzrU#Hpn1RiF|&GwpIL`|GO0_wP0EWixDQ_Wn+C;b!Flt5e -B|2k6CoS4RsyWVvm7yAg%*|-W*QGS5Zq;eBJ)rdMrNg#!Co^bh!@yhU>cry&sO$nXAClv`P!X{ygiBR -#wc=^jo;OnYW(Ok?JV{4q5FOQ;=*FW`6^(-fw_5h~rE2&sPu@Chb^ipZN_-}8eiig@E!b#xt2fd^8KbPmh5FFil#)E|4(P2qCeZumbUeU|J>B#~=h)Qs-cXVN@@ -#>xL5%5c;Z@_<9=9I|I>~>#P})O3pPc@3jBrs@k4;Nks;V6Grg;ETr~)J3lQtbGh#@JOy8{F@jy^~fl -|-T>^049uV>Rv|H$vtSBo&YzaSHjKkJi$vfn1#bzDO>w&dyb7Ogp!T2O?}L`n*VBwr)=6g_x+J$B}fL -h3+0aq`ZOII|bZPgA-5GNqheBx`EZ{+U{CCf$jyoL!xMxj4UEB#S>jo-0*)jBOKut&TTo?YO{HC(!w|9f3~z6V7B6H9kr~FySy=mD6Xq36(tOaiapf -LNi)Z7-XPd#B;n7-uXg>Z2Gogkz+}UVg$cD-0``e)^b~(wkHxd)7hnf# -mN%w1XWViA~V -uO=L+s?T015Y38bNQKh&TaVB$ZF;{$^jx6nKPYdl?+@K9KmuH^KD+YCEI6fn`ugBy@f>0>u9XP)h>@6aWAK2mnY{2 -2-J=tITZ*004V4001fg003}la4%nWWo~3|axZ9fZEQ7cX<{#Qa%E*=b!lv5WpZ;bWpr|7WiD`e?HgTh -+_>>QK>hfFoZCM1gxpz{W`^_ -4nGwBen=L7d)n4pdRurV%?wVE*ddr(?FIb^|&&aa8D|y+}8QIt6qFJ({Dg|q4#UDR9A-h9W*5bvo;^Ih8rwh(N2Mi&dl0p#(c6)vSfdBy!>KT6YPs9#9_w}P(N!~hqY*S2Lp=t-HY5jy``L)XW -hf1+)$vrtp;xvP0a^gTwJw`z1o-6lC|kY#kQ;#_~>%GQ@>Clb-&tI6+WN80mZY~ -i^q=$TowYX8ATrepEp~13yOE~a{VSvC|@SC9ArXf5q(in&JApede7g2HyBp%LYa!9tV>Z8DQDFxliJL -BozCAjwS$5eLgod+05kX__F9tAF!DYG$P|a3T!wE2V-$Zy*Qw;tCG>4q$JK1+k}FsJJ5q9jI(RW$QL= -`BS9>s?EhfKCHey>PH<_gjmjDB=m_pN2W}KjWzN4*DC9)h+_F@B`i*CRH==vrEva0CXy!BkgHbc-|d{ -3FENhW}30lpjbr--U-q~y0#{`Hh6hX~d -hdAhxzPgIZqWm1CLzo3SSt>xp_FxU4j0oeBrBE{g7*EkP=8RR^n4!GjONQ#k70bEBke?idm6UTh9zv0;l}G5X<#f{p=#)(93_L=%Hekib8B2ZhTz0Jv&e@+&)Jaw@`16OGSr|8xx;(N#B8IL_c8!oX04l|`-KH1Y_u -<}=GS9JsUVPr|49C5=-$g`~G-@(C_kk -26NWn=Yyj{TW=TZcJ2P|FB8YxLn$fX370V+vCe9C)TR-{pZ3mukFL2I(mG^wx8ez?hz&=ko#;3?Agz! -41u_oJb(w@N?wJKwQIxhmOG`q2=%OIpF`3n)Z~s=?FoY1?HKeWfY9B+ueI{7~fz>5PnPeyC6nFJgq_c -tLxN*d!*%Si}st7>k++aL1>cAr=+H31+6?zSj5fI2%$RY1hkUeOqg)Xiv&e^%`pVG=K+*&eZGWP$-3{5gAgte>m>rC;N2z10@26mFLkV0|cNE#h -mWrDDioVgoq_c&)Hq5&BMb~UD?ETO(^0`1QU`P^ -dZ)P}c`v00gsLvr{(nF_szm8Unq%Fe^ap`#LM8G_z0=!j4Yeg*$pmNRAz&kbHTi@lkyPV@zp)pq;as$ -5(yA-^3s^qiMVpW_RYuw3-y$M0UhJHPtd`-_*!XmO`yj7|IW`Y5fw4L}**usqebArrpW6sDUIkkZ5~o -PbnGaG2x}j#w5_i*Dpcvx&Pt_tsaGZ5C_=+3xVZGn~y}ur2;YtL&a?F`AC6#UcFQYO&TIs>SjMM=ge> -%waGREt4W;YCJ$ReEj+1?N#yN-MgzKvf`VTuK#l@zxnXfpYf(&9cc>2#V@QaX;uD{wcXsnBHrEwvm!T -0=0k=?&1Cgji}|xiFSVf@E0-QV5p)Ucuzas=fXJ}Iaz?LnCj*76iExz9NI!A$JUuo)vx0DhX0$ -@>eKoS|7ANpOsZ|9c5<$Z5QuR#$3g$dD8D$cJ(CAX(1V4r1<#~(AK(3 -oe+?e*_p%c-B^Ton%Hq3>CeN|+4A9&mVJo1r8sXXcx5p7svSx#{z1NF<@)57NZCQF+OwNXI3i67?fV| -a5N`9d{ZV%UrLu=*>U_N&xFH^pesm+%Uhoi{DyiZuQe)V_Lmegf`%%ICPlKZ)%|)=I}VqxcNv!S+7`I -495D7pN39WbUIN*adhMr^GS!=2%4-oQ6)6>&%r4XxVbbtKesj59mfJ`BW$QKbo>m+dH=mZ(n{jI|h5qa&H)xIn8%oq-&eylD%kY!3!RR_`+GMAf3ybLpt08A{l`~-xjg@W>kxiVgDwH|v&3wAD^qUMF3Xy>hoj#~kA4I4xi%r8@^OwQfd9I!?u+=RkbuMD@;~n0T19;;H@{4s+J{XZaT);Dn -(+4N1Mf@&Md_15ir?1QY-O00;m`Rt8fJ-WPN{4gdf)I{*ML0001RX>c!Jc4cm4Z*nhabZu-kY-wUIba -G{7Vs&Y3WMy)5FJ*LcWo2J%cx`MhaCyBO{cq#8_4fezA6Nx}<kk9E`hdG6w+6er26ySYLz)S+M -8|4m$rGjIysrQI-s6Wvk(BIY-3+wnNRRJ}@0)ZG1nv_4Nd9@9N35&|y-pk!g-1BW -_sBiBd{c0t>BF=Vh|pfLy2!Qj`RxL`*-gKr&iv)hZwa!U!x$(o{2)hOM)jP;yRd`W8g^nN|fr93BKgf -Ebn)XfKYJP2E&1j!Cx0Z6$QU%e<*sEdQR7G<(Q+Ru(hT6j@THEY7o^2S;SH1?KDT(u`9Oa}Lth -EU8&~LX(7Xj)WBAM@gTz4=UDvC(F$|`EtrVT5~LPiJ(97td2z0r%|t^R63Xrut4zxp`d#jV3rtXx*9_kCH|yv4~1cKkhf -5C?#pTO_J+gDJumo*{rzhC*l30S0Si+a?#?!CpYr2&Ww^Mrr|{6=Mq`bY&fZLX#MNHdK1B$v{NYw16- -cDts;CsVPqk6wX?49gS5Cf==P6MPukG3PQ?;RrNOPsGEaFM7W{cz?&R1cA~wJ3UV6EY!Rl295p`HH-l&a_IV9y}N)ba=pwp?L6wEB$#~VU=g -DLumBItZX1aVYP-PhT(N!n=GQkxb~sG2R+CC&GkA62wgpkUlD7qr7Q>2B3Xf6+n~EMVos>n4Ms{<0OXhR(Vl)bYas3kDe};icopm|T5#Q^h5d0MPPl -$adT4G-i#3b6chC=i72O5LeO}*og22f{at!0tw>+bt6PEIiVoSeKIR$v4v&e5VbxzsevgDEr?slic}d -!&8Z778rWp3u%7j#!wiHRFr6(lFN*d`;_QrAyMbu#URoHWCn_p=4JX8qK)J7g&-g(CDrzn@#wQ$8y9r -T5!Gq0MTd(Mf<$#8Y20K@tcC*?o#{ru=6Uyub}DWMyY6iL?95|$pg(BX2gL=uEjcf?H17b)0wDalZbX8Gwf}Y9U0j~*{0 -`BcI_g$U|8299OCE6CagcGIjkITa5BfziKr?=*)AC&yrWF(qkfiXolR(i4h^iz5M0y4kH=a#^yDlJJE -TLF()rIslwETyDJMgG-t3d#O#05lRm96^eljX -J%x?_bUoIS^>}Au#k`&Ewr|nX?3 -dSVfKd!-fNr9z9MyfHdr3dRY`u{fDV|2?cBMBpb?4!HLlgGH^}Dx9O;F+KA^!Xg1@|%Iv+8`@P6&d~1 -ul`tc%gV}Aktq96SfDXVpRKwO;0>6Zc9{hI9e^;e3EV_AdJF`k!NxxNufcoavH<24jl-@qTgV`4&rK{? -*NmuD$e;8t0y$>izhG*-9qx&L*^^H0;XmyUrJZ*-`Sy!LFmGx7nc|oRkIySTenj!ITlrlX2#G|ex%Y5 -@9r3V4+R|Izzp%d9I8{AJ1npr>jl;!*E1Askm54;WscH}uUvvh_~;V4Zfl}YqDD|TZCpl2XYaz?9Ns7 -KL862;VwS~}~g5FK6kBhla~X&W4Utc|#GJD2o#z7{*tIPH1I#gOs#Mk_|B7FzZ0C~z!#^N!-MYdl}j{ -343WlsU~o>+QE><;74%L?-wW2XCI@-4w_}%)cY8UsaTdmr(AKjH -f!@SE4BdIu2u!m{p)Lt^gJ6xBP0BsBb==P^X}l_gd;&}H>_iC*MCnXDe$Ak6XLGC#y%82b2MqUYMJt- -%v3!V7dpPMHj10s#;0_Pd2e-c~e=ti*u&^!KW>)>?KSu6*+Fe-a^9ng^kvpYDwKf059G#M8LFj -o3f@5HPAsZrj|BZR^&}U_+($e&CXhi4pf&U%#@|0f9t!srH<~ur1y3_ij6lj>LAZHg7BRSk1|81C-TSyNmCh^Avs|17{T(4ccYf6pO`z#86+krI+ilKO9Y+5q&c2TYf{Eim-nn -NHK%GB@%$#hzXC&n#@#*zp`Vyg#{E78rJn@721T`pNW>CWUsR3oOBmqQOXp@VVe3u3)ib1EX5R{Rro$ -dr8nH?lqSNSMHDwoJH8dFWUiTc;U3&&#+g3l+^(vtat> -BGQjHwF;@-0rq5dbf;bWeJ5!C5&RH8i#z5w|^4FcX_2(mR?J`^W=(9xB%7^FDJp0vSm1JEGpr$v3yY6 -AC-c?`20c{S`7HUeM7gXTi2*kvbRO`KU|r2C9S5NRF}+o%WMnXe!I2-47_=KqNXMubI5RuWsc((k=c@ -0i=3C9?R+;T7;|yV`RLTpdqleI!oz(El`^1s2G`|6IW|F{}n%CsKqZ5q;1nBg5VQze{)4qJFGwfI7=f -F+co~M0_%Fb=U*^+kkfF94{MhCBvT73@l%9~K>WP!IJ#rDoa-Cw-B&h?SxbR=?d6%g4> -}>oelqG44uazKO%0_Q@GNAs-!L$}qoJWH(*9d)y=k93SlXSXoNz{$mFNf)6*A!nhamX@rgZl -Q@FK>iN3-iFbs9R?GVkG6@FV?PcKjljCt%PxPv^=N1+^_KBZ2QIclMB@+ouP=Uy -0Cx+4eHiO3X50@X~k3anQ)7$g-{l(udKE$uCt}b4Eh^2qN{q(gds34(#(}I&XbwNX7>{T~M;1qwoM$YV9!ydw$05e=*pIW0V_$!U}rgNf)3wF~b#W|D7q1CimGl&#`Z! -V152DT-$`|Ea*Rd`6Y?T*!7GtDLIs`S9E2rX9sfJZK3F+Q3nV%+n^7*pmEa_8^hpAw9Qx|Rgqf94f5}uA$ -6DR^|mh+kl0JkoVoDKaAeQ(UP7qin1@Cv32Fn0it?Ci*r*JI;TbbRZo%v_m2Yzj3G|vQ!(a~p -+a114a!%l=dFl^6tX^3giD#p)jn>z<&G#+K#g95?HS{IjZvY8qg -V)A>JM0=Z3G{-%~t|d!f -AaDZt9GAQ}EI>6ViAq5;WD$H4E`n7x3*nt&c~D2`yEhWS4k)Q>Ze`DDR86O5)=4=lcWZPfzCK5#WOfd -Clo48|M|qOgnzwvrMR5TRP~H4{#7>2Y0!M%}hwpc}n4tHv~9GbkHV)(vi6(qGX996p@lZEWrZk#x!ecFTx8yiG$h$$fJWiu -z}Ic=ch?@}WYtemLnc&*e@!4UOMpb~@E_A8wfXG!bu+VN6mT%o$h7@^hyOu@ejczrYQI-@gXSEf#rKcz@H0-e5N -Ch1Gaagmv=r;3#iYaA^9#i^FHGmacehp%Ez%rdU0kNrNq%z1E=oI_B_OB_tSQMOZatFXQo~q-hq`lq2 -zAfQa=pfZh9a62w{Iyk>C+tE-h90I4MKZQAiJ^U(|4*^G!vm2%dx5)bbjZmyA9@O?qmYIU~VWQZ>*r-cB*lu^wL -(KbdpYZ)ipJ#?=ieTL%gje{=43>jD^@fm-gcJ-ThtOSt*wh22=@Yx1boao~d=F-T6Gy@02);S*=g@J~8p2gC_ -@adLdw`SgeZ+J5Y+JR_RGsUbxBuPCk``_d@?CRoj4khxUFHaOw|QL`UA%0;%VL6TbZcSfw9s9zX#+;v -!ce(Mb3?-lK{fBX_Pyf_&4;mDmjQh#Q0vU%cuzCz0)8A|?wML>C*qN;{$N;UmTXIhaFe9wNZ-3;eu`u -F)=q3af)+MtPg6;FE1SfD$-3gZOb23b^R>v7z5V3l@Xs>h@&z4(kDpS=@wDo(4*s;8iN -yqSfueLL#6j&f|O`p(d)I%du+GrO}_1t6mV^@~)mRYH?XSGQkGPi8YrKFnrAHPyb?$nMJNXV05Bc^04M+e0B~t=FJE?LZe(wA -FKBdaY&C3YVlQ-ZWo36^Y-?q5b1!0Hb7d}YdEFVyZreuiZovPrWe$=WMQ9Jb5Ve6oRuZGJ9K=e~)G(w -Kxso=fNP)Yw;|Bis&g_F+KBYK06y-(xnD@-i%&t~xvL*BRDwA2t=5xZgyCju_E=3Y$lFjveNJ4(c1yA -B3$zmQPA)7~BvXn;R_~`g(g;c(5qfrRIhQt(r%+6>OB(ab*mcs7Fbj!q!222deUBbgj#I_9fheWN8H# -DUIFi_;@a~ee;+zGk%&MwCvE+*5NHzYWoeR?;+;cW7kTAI9_*xm8vg&o4r`Ro&pK1~0ZUVfZ?4hCS&Bf@B!16=EEW8YIXgEfi{%f(poSwmpHDB(CTbf+s_o*U0YOpiK90?@k=*W>so6BT*iAFF -m`b}GQO(SjQ5W{S-=CSuvr`Whsn{7oywT@`$NkFA0HKeMf`|%13Ul<6Ta?4`nMg*Iw8KEhIkP09kGa@tgr@loH8mIid?8=N#W$5;68c2-RXnC!bzGYsf*2U!6>s8>xwR~Sq#TfX%lNuZ5wjWon96LeRtfnSV)LLrXC -a{!2l8A**u2{-x#Q$NFf={bKG#2^lq3=AOcx7xnZy}Wwc0h#3lET}ae3;R-(K$~UdN?Fh$`lgDhKliq -M`6n1lUI&1%zC@mSpDr5?X)kZP}1&hqIYirO-4-Jk(zRXbAG7_N -}rg&s(=#KtAx!*9rN(s0nP9#RFI*5R4%}ynxaqYMz3uq=-DHQ@!4yO_g^nqZt?;%^}fl*HS -QOVTxF=Xcz@(Dp*s#EsKOya#t7-9SLZG>L8Gwy3LvEAQNq&n(g)cNA$a%3SEotr} -m;EcC#lBFi-M+hy-|6WoQBCkhZlm8KzEsV@z3Mf@Xi1^&o0iz^L8=s!$mdK*A`;x --y2IwEV4Z+w2tA3@z+K-A>VOd!vag{>%3r%6ZW|l{hfI_irxHwqwh^?dnzV;&)_tp6)F9?n`t%2iksMd(lSf-t7QD*0Kl -8F3R(?IiS(;?lbL(12iTnR^Rzbv?3-6MLV)Ecwgv?!)ewu8bhrQjghV#PQl3sW-Iz%7-n2uVY^L_7$|wr1L)>6s?gQN#V(s%2H*v0VLTi=fF`8FpL6pgpB -LTX6xz4x7NN>;Ptml_p7Y`QX^RyE8)IF01M`MuXu(v&A|{?dxU`t8%+2>668`adID9g_4lX0Joyl8_1 -dwsAPZ@n0kv4P3+x^#D^*d2t}S3eB8H{=4YpVF|<;l+-oNBx#x^Y$|K>3|IP0TK6J%n0cT)@nhKBV;g(WU^n2Wzkr7<7<$rN&HBNywpgf+bXOjYFf-4`DnE9c(kY{ -^cfLz5dm&G(yfb7EsiKN44jKx}lQG$q6yV5l}5!PO|}} -5TkaiYh2BHXakkTTerTp4lC9&vean+qdq#vOAiR!oVZkndx9ZJ%^_%{$O+jEv?wS( -JYOh+19t~$i&eCon)m1lb=V>us&ZIc!J -c4cm4Z*nhabZu-kY-wUIbaG{7cVTR6WpZ;bWN&RQaCwzf+lt#T5PdiJAM|L0@COv~5FBp_?b=J$>9&+ -&6nnfYR=yy~VMFP^SCZw+I-4}rgD*2@j?P@9k~bB~va*vMhb%+1Y8x&QIf#aJ60-guqky(=1tzto;-j*U(pwSl$)&mj7>N+_iLZFlbJQ4N^+|#ZgZt5N69T)Tnlh6O;I!LVoO7 -sj;Q*S^L%7iC?l^E5^GJy1=r7;Eik)B#WtCbNHY?5$)AH`{w{&(p;^KD^&#Ysr0wuMe>-~o1~f!4?~BGTx4YWBvxsBp7R*V$tfrrRVo4*!ZO9gQdIZ-jO5kDZ6?qpy)k -{)4=Ulw6<{`u*p=^18ip$9b}B6x+9@cgCVfl@J=0M)hi5Tm7d+UcLiDCyc`iY;1_!+y8 -@fO=H?(>sIXo`E$vVX?CNzmy1LI`*Yn5&;u%eGfI2fG1&B8Evcjakd4YP0*xrY>^g;uk3H3FGPedloh -&sy5cwXJWTE{^?W{67WSWmHIDRnu4ZFB+U|Di&!h9gXnVtnGa-19-C2X?()aO~IC+Zkdu;=Oy)*787t -+-4!j)ke4M#bG7c4Qn$w#UVfBk#|O+BF(JP(9JZSJufXxb6%I)4FBO9KQH0000807zB_Q+X3t_xS_>0 -7?=704V?f0B~t=FJE?LZe(wAFKBdaY&C3YVlQ-ZWo36^Y-?q5b1!9da%E*MaCzNWQE%He5PlDk|G=s* -Ql|(_x2LQg&?Qb$ph=3%!!{V1z({AC2rUXE<;EEL-*-n*wrop|6JWqLA%HCE?z`_k-jR$ZTFqISPAXe -zNK+=}rP7x1d!uA!A+4WdmWzcjLKQKq3X!QCQYkEGF3s`L@zI1(G9@Ks7L7~;bE9+6kY9+*9v}HJ4J( -gQlu5dPB3C*w;<52ER*Pbq+GPoA^rU%v&kZzVNm^MUSK;O=uOwXZ%qqR~Hv+JHnrfKBW61^>Kgra*6c -WPVuWp6=66R1?8u~OZ>jzG$MrX%I46l{}#^^QQF+Nvw_ -Y-s7^h^AkFyJN+q6Bjwa^#*#ZVV%%-?)50b|gu1t%_U7Ds999*6*S-#$K~>DMew=a$)$rgh5qQ2J({y -*MgpFRJwv7_=xTWvol~N*H&be*tSI#r{nmJyDlCRMYqX&2G+`sOMr4hz7}QMK7Vl~cQRMK*)Wm^%GvpzW^a6;gu!h -p!^8P+yAFwES_CUV8$iQG_H2|h<`U9CxB%iXt!lMmhymKJ~hW0o?b&w(#8MjEMCerXG9T;lK*Ki~t!n -jvIGC*BGJ0CZSm;~M=w3R;#Pos^QT|f8=zedyxAP5s0kdxTOX)3z8kR^70f%#+NAz8%rMAfDB3ENIgX -V{nESZJkeQ!kr9bb-XRBz1pIrGX2%YllJIdr`1(Q^{?5%~h9^TOE?o@b^(n8FFiN=wcFD)Wyd@51^Zl -0Woe*uqRh28_u|K__ZX+ZW=^g>^uc_K!hviD91K|S{uNq}{`fNdDL4R@3}X*~vlDkq*kn&>he280OObuT#Vl@(nx(NYr_rZLcCVZLbRF -CCn=7Zmn(c0!&LY4?7I0J9Dt_V;Z){PR4&7I8JId@eEu=l^HhdRFcNo|)?*`f01{oW)cb~ZbZAys)IIK)$b;kLK}NN!}HS1Hj}QRa~%=02Ux~_Up9L-jvn=%hKX4 -%>G&@8CA`D>8M~1eezzBT_#wKd=(OFxzx5-VKhfo>6Mb+N6xO6W9drE -slu-#J%X7-D~t)rO!%L=Q9x2IF14gAz}&-;IBW)ARamolA9d6CyTyc+n1d0};vYfp8fDSPjf^!DSE)4 -PbBu+#mqTGnI2_>P_4xxn=6pDX7t4wsJJ|GR3&Lva)SplN=Isy)dbT%olG>eBR8smiW{#&gnX{$qSbH -vVks&Mxh;O)^y#%}_*wpB@l8?f`QC>o!0;O4XnqM5>HS6Z+2|&8Lqm_c4Xeh8T8zW=Easr;44QHH=v)1j{t&QZ3V4nKQ}q8=mQoO&s^4r86xVYn~?w{#e&sfQ(8EsWV2msbpJrt -U5JGOIuTQ@*(LSr+i1j$Gt$>`B~03gcS<0P+CSRzC1r8@ZlQ*-YRlm7OZ)MAISi=!aTJPnE*}zs!*C1 -8H?2Xgg`tLRIQW>XjMth5b0<}RmS;jPG;Z}U^I)Zvzeeuk@sb(qjLQ>VA@*1Q=};`xK7hZF|nBggsyp -fmN3Egtk4F)D`4=**$yCAYj1KkO&DoB~=rpyo_>+4 -Wv^5cZdaY6zrX+ifa{yzGudM$XC^87pLQ%_2>eOgNq$MH!cJ7%oXjCE0z+OG{q&rl|$bwW=tX;3Dfv{yjsMX`GZqX;V!xK34jq -EIe6id##djAOjoa{9!cLgnnb`3O8KS4-;0KwqaZwHpgAV_$8U4IMimbRc&Go3& -Q~>KO$Qr0V6+WN2{<09mSVi`BDF);$ -F-t>(pPkN)de)D3PC^_mDI<410`f+XyaEmt!E?O+nX{049vt61!x7`s2s)K`A -xMSDy;`!{DlgWSD8u3|lSUX3&pW3|~5}ia-IG8xw&sh;$e;ftk}%Id3*iWo7?;4{0o#dd)bJ-R^9UByIUKH#4cs#tFxJz-@&ygY}Om*F`WcjEOW)+6<{|xe+`I;WjIQ@AC%PnS2IxYz=DeWti8Pn$zTlqfYzL)rdOwkvN72A9x{bZ=0S7m -{fvYqoi>hdbC5o_E#$+qYx>9}@3Y@2>W3cs3Wg8jPbeI56s9QzmcD?M-S_@88vrYDmxfQCQUOHuq};Doc?6k(F49G= -}Ko1T+?0%jCC#oIyNbhf3CeE(u)u53;fybZxHvsn_|EFDa{~Hq++%;CO8f*f|`+__? -JY15`jAXRHc-IP=CYhO4+J?&xC<7SU#T=iJtOOKfox$9KjuO(lW*J3gt>~U_cbYJ)3D}3QJ>O9Xkik^ -<;va6*&4Ic!8mUA-!ajYXhzD{{1rA3>gG-fq520gz{J -&a5!+FmE+AxrWwX-T^kX`QMHxp1Tw#*VN_S55oh=QB_sz?%96|2Thl-{(72ADu-UDBxZQpWcgyY -O=6bo>_^`fO1;4IsC)nHuuONiG8wcXP<;-fm43_0&)xG}e!|H0g-Ry#wi03uT1Jl^dS`ShiCXKGwkBY -||ff?F4AEYIv4=h5*eL9H*(;9*t@h1~0<{rV#oAK=PbON@;m{_SvwlMTGilknk_71)jNrE|;M+7{QC( -sI>5F#ewKpwbsi-{6KJ#o1QC9wfG0zyXl7jXG;3-y3qiM^nncB@?CPMPqm#k25&Xt|1DY@SAh3_7hgc-{uMa -?x>J*8QV%?hWQXSEL)+I1uPb25}!CXZ0`dzCg%?%5y5l~C@t-RwVMkSF(F;;om#lWt;}A=T{D~hN6Zb -zVdL)4-@byW4@VNPvKkP}QnI&(E2aoNYws?EvCQcCz4Ov0Mjz6K*X-WLbnL^R&_g*pf=*{_VQa8nMYQ -xf{m -JdN>GI}+9yyHC-f3VHBRA)1Fl(O=idL~$VxI>qflB0@QgC)7wb03ei@_`)naLsP{(2&`*rSXGxQ`R9p -05+o7GR_@a_bSHaTt10U%wCS(U&;q-GMzX)dM~rY^);ld_eERf1?r>#1DIITtA1UFLwi3B&fY!S;_&V6YY4Ove9k=Z*LO- -h(=T<1|pnm92xKw}!Y{oBL(+ZaqeDh5fRA55^M&ahjwFfKUn`d(J+msfR$%;kcm@iCo+)W=X!EH2JuS -ijY?o@mN+=?@f2YJeidFI7##IYDvBs!oeG*o`q8Pv5xRoY*Ynm|GTd=`2$c(0|XQR000O8NLB_@E^_Z -5HUj_v@(ln082|tPaA|NaUv_0~WN&gWX=H9;FJo_HWn(UIdF@wSZ__XoeV?@daOobBXj#;O#KWW@!M2 -Bi1QIauuuhfR+_Xln6WNZSApSeoA6e5T9U2b^H1d$N_PJl@+9yt_sug7ON+Ix7T`2=7=T(6z6zHE!uo -;RJn((~3c>D5FsY)Fl1PhCs>$|@S4-ZP~)~stT7p>oqO)bdXyV~$dGI4ltcra}wx5m?=GI~lWEM6%`NH?y@todTEUc4NTH;0~VT(0c4Rw3lLB+V6lGvcmU(q^6g+(9HvS+!T&KzvIcZsG@a@s4&*@kJpkd@tGdlzg9v#JvRUK -e_6*6EEVP1u!*OxJ>&wizwlP{KADiz1^a+KTO+?L-ba`MH~u)7zc-A-7r7#}p_!PPXS!geb0)0|AcU4 -Pp&-WoVgjCd3*VNnoy*M6`2D1BMGQO9Y8uNpK1Euq^Il;l4_{dqOwDj^A`#YyQoO_INWwD9xlO7)aN}J3 -anaYH)c4!>zQj%VGeRv>D!>6^btR_rnNQ+;!*Gz%oif|i$B$1UPcIh59L>~tXj-Do$#6AGb-Dxfo -Wi%k*WD|S~hZSzYko;gEF=k2lmww!%E(g=A5>8TF^E+F`QLbxww}k;i6#fKIO9KQH0000807zB_Q_15HA<_T<0C)ia -02%-Q0B~t=FJE?LZe(wAFKJ|MVJ~BEZE#_9E^v8ekFjpTKn#ZWNO=cK41|hSs8hv&6ahmPmeL7zI1;B -i>CQg+%#gS5YpI}@+=_ZF$jh#KC -#nlnR8&m31n=<)NA8|Lyx4`?L}Csd9ypz@V;7oK*tz?SmC19jr%tR1YzZt-8|cW0Z>Z=1QY-O00;m`R -t8gR%LZAo3jhGKGXMY>0001RX>c!Jc4cm4Z*nhbWNu+EV{dY0E^v9(8f$OcIP!ae{s(UQK{gs2&U3Fp -vp_dZx7|zAMVl6jOAUjTX-ADL=}0M$EB3$N3`t3R`IT;QJp-{Lik$ZhXNH{ed`|i#nHM=PNixakgqHO -2BRw!q1dGe&vC5J-pD=3*XOACE5lVSqB-yM6^)XBGY@56*O8BLzp3_gVlGAL)M1!&(7{z&3(j}MhAPT^O=uCvaCX+-VZP1$-Pa9;nS1bdqOcD-yk&*>W|E}P1&azSv3S4J-Ndzqu -F-?Gg#dxzDnkJJIV6n(S4QrvMWReKrHopbXz<8D6Lo8X1Ye*y!q!OFpJ^|gcyY)yYub7Pr`IX?nnDko --jU-DcnXoBwEvyq4HRdO1(CmnG085wjenCrBZ*IV@3{U7cFgo!SM+jXtFPY-hV=~YX^%#c6<~3xeuv!#e^F)kNMuKZuquT2B@-4#(U%Sd&RZ{!T8I@$G61dC7eKXOMIWDjJ -sRx)`B&5jmz`5w+ggG&ppl9!Da&T%RYyK};ALRDl%z^g4INp5hGD&4OnxDUdxlOmDX(ZMm_^(Lub4{= -07t_#so5r=fh5IYh;gfF+m?i_ps=%hu#bZ#Xu^O(vU{-C-JJUPipAF>3{o}GY9uZBv0NKAy8xw62nI& -Ns}wd2ag|po1f49sCu2rvQKT5(fN&)!qK#6J_ZMfae`te3a+G?(dkqdSdUuk^9S~V`(U(|O%^8P)Ruj -Ktil7O+P7JU@GP;E2^2VxT5=D-aKOr9!18H*2fH{aKz^>dcDaqI^`1lR*fy?tL(YsP8PS`t16DkbKlJ -XvTRC4(G7ojC7a*;^VzP66RS;4h^pljcC7qJ7dE~EF+Hi=%G$?x-M=x}EVUKxrJ2#vQio5-QYSbWQ?? -aZ+avZIF9Q;x)TIT*H4dI3KsC%m-DXQ`*wv&fro*ctkh`97quR|yxTxwjdbnpf}&%-&Jv**1BP`!J9j -P+qrNOG`x*mdV`2A`HxZ%=idB5ni0<8EYN0&fYFDmV9r2u}lo)=Xpu1?_K+qwxy+J3E!vc`vZQT$nVn -&{C+3Lf0f_oAKrQvyii{{i!l(RbXxt{-i1_A!jsum*(>v2%BH1KZ=*TK(_F6iJgygWtauH$W55_%tFA -web^mm%1hX2HVOJpz_E&MxC@Ms@R@#n(!xgJ4-YzV-{0mHp6sGvIRcSa;EF0Hc4};mJmx< -_XSjcqx^akUKH88NBfHCUT+Pmuc$DKT!mNq>K>oSEM*_~sVzI|I>@wqdJ%5RYN)qUkFCZo_jy^tmz0+ -X1587UP}8!8u(D~qLQJ^P2UVV-Gp5OZpyoP%bpkG>>jdx!`QMr>K&k=~JJ-OdbgEbIL{1{F>eBW4mpX -$0*@jDmy0mL`92cV-td7AEu@+VGhV{d);gannD8}!02ZQ*?NjG2x6hea|FT{8a0t*Z2k)2_;i*OgTtU -|HW&t>tGU;Fzf#?u7lD9i2+VC?N|6ZPk|3clnDt={#Tg4`Sz{TV9_7LuVGaDinTkdkY35xMxJ^g(e+= -7v%i1_oydV~4Ulz|_c@iXR(UOQStH_5NvmWfrQZYtlWAltS${y&uQ`)`-ABgy=FnJZ0x -7*|?m06K|UJSh;4aw8mVxBcE_EewcH!9K>f~z0rN2Y~QYz5!O?Ly=LH7w-2CfZ!j -Gn*}*CpvCWKVaCdkJ27la&1V8K*E(S2$KWNddT=gIj8qSK -WR(^B=;rF;->S{aaUOzXx#&pzx@eQef_GO_Wofe(QO!Tj!wL6^K@Qd2dplbb*OdnUvtzgAV!9Q -g#6E?-t1K8M*g}=iD-uWgFQg*&V*((&?jBKRqjm68K)a?h9c}~(in*~xJ1DM`hmD|-0dVoURfokqQ)V -HGaEeRUOkd@+pkdl17_^^M7chq7gz>8=7=AM+gt|tk{G@-t(*9@pxc~wGCC3va9%#>B43>4UzvSQszm -GQQo+HG~R42!zULWLxN=eKyCT+?!CfWbPreR@uI4-Tcx1iD@FZew5ljPPKp(?Em})e8J7`+o`vAYRT}=XBk4Eb#UktgMChf+e8|zM*1w*kVa$SZEH`DrDZwUI;Oi0AVehvjz~;W-mb@PkmB{2)snKLw45b__5f -!ZG#*O62{m@=Tz10lR6zB&%l74Zd9aVLy$gmn -x=iD=(=Zj3}%})(FGPG9)uTd$HO`bnOO;Sd}wjkO^#D8j@tmnQiVl!erEDv0K*>#@)YT`--2aQXIP+H -u#i4-K0g)D2gk`mL8Ca~|fug&epl1kgV -oYn+2y*=TGpN11p6rR^YMgjL}Q9#nu5o=YgF0=@6aWAK2mnY{22;B65n{e0003~U000~S003}la4%nWWo~3|axZCQZecHJWNu+(VRT_GaCw!TTd -yX$l9umV>iqyApM -|L*(me*E$O%wK=|{L9Zj{`l!%e)_?zsf0!{2=Rr~CT -(cm2If*V{jr{6Bl82hlU=RrCq^z3KUSrDrdC06mJHK+mE#(7WgZ^ttKPzS67P^a=VF^IB59(9N)K0Bs+-!~%33X-aqCw1{lc(j_xWmHjj*=(rp47l?U#8o=hfz$oGMN=w5&^(_0frcr -S^w^Uw`HsY3Ej=o#nNo7NKp%{i-V~yRu7Xuf~2|Z#Y(aFp?N}y_YgJ!&Wd{-VFEJAI|HAqP6?|VqWFG -Utig~Y{p&VtNGkDi7{ZJ@!kfv+SiwGt9C)JalGEl>Snej_i7J|;x{Mbbz79T8`?fGoGglT-==}`)m?Y -R-JE1|#`$)1{A|C@|I5A)&7k6_BjNOf^9b`-~ZZLKSuhx>`#Nf -ky+>CG?us{D=|5$&nha0-Q?5@BcTxD!V#p~Xlmu>xT#^6!_ -dow>eibrYf4?67H=jOS_j7GukCvNhqTW%o^PM$+pn%2u05^;t|RWBz|Y_p@GJNY -*B#db*Av(G>;2t@YlCaxckcCm&f_}Z8u(qpHSoKFYv6al?||O{zXN`Ezh3*N|I=6327HTa;P=4qf!_n -a2Y#Pl_3MG(1Ahdb2s{b>m(YI+_M7njB-n3?xQ6{E^k0Jf3GyfOUqb&S^j`wr1iTsVZ$|%R^j}8*W%O -T0|7G-FM*n5>U&i~JE3O-^JFW+=C$91S7QDX&{a?`k1^r(zeiih8LH`%@e*yji{004A(EkPfU(o*r{a -?`k75!h){}ugT(f<|wU(x>+{a?}l74~0Y{}uQv@K@lkz+ZvC0)GSk2K){98}K*aZ@}MxzX5*({s#OF_ -#5yy;BUa+fWHBMhy8cp@4(+-{~h+}T3z5?_WpsxUZ1?Ve4Ujh0G&{u%ILdG@hB|u --H;TrZ5psxV@0r(^EN8pdZAAvste+2#r{1Nyg@JHB7#QPF~Kf+!j@FTuWh;LH@e#E;e0YBp1lsvA1KL -LLN{)G1>q5l!@Cd9i5@oqxAn-K3N#Jj2E{vG#+KS>?;hd)Uj_lG}8@F!_NzXSF)U|$3J9nkN9eh2Jpz -`h3X58xlbKY)J#{{a38{1f;m@K4~Mz(0Y10{;a53H%fIC-A@d-!Jpm>|gz7#(XwoKASP0&6v+-%xANY -xPQWR#@`q4EBFo99oGZb6W6c(m*F2W{6mI+$nXz2yp9hU{vik855ON@$A^sZI>*=brHt`9W4z87uQSH -${EXKx_k%nbuX99y#8-cnF`vqqPi4%fGUihm^QnyaRK|QNV?LEJpURj|F=1&>(r;Pbi#{4N`{**C)${lzyf6ACY5qi(p8wBsda034w%20wu-b?jjTtDhZ8*PQoBzl5m6Is1HYdIO@YuACCHP)Q6)!9 -QEO-4@Z4C>cdeVj{0!ahoe3m_2H=xPkngm!&4ug`ta0;r#?LO;i(T#eR%4_Qy-rC@YIK=K0NgisE -1nMJDAA$M^)JLE`0`(E7k3f9{>LXAef%*v4N1#3e^%1F$NPR@=BT^rc`iRs=q&_0`5vh+zeMIUbQXi4 -}h}1`y3)JLU0D)mvRk4 -k-1>I0tz>~-}QD_n%}66M(IZRPCizd-1}2#JJDLU|!ndcsOiSm_BXJz=FMtn`GHp0LsrR(irpPgv;*D -?MSQC#>{@m7cKD6IOb{N>5nn2`fEer6;WPgq5DK(i2vC!b(qA=?N=6VWlUm^n{h3u+kG&dcsOiSm_BX -Jz=FMtn`GHp0LsrR(irpPgv;*D?MSQC#>{@m7cKD6IOb{N>5ndJYkAo6X0;JiaFOqF$cvS6n9YkL3#c -9@lfLN^mP19KK`a0e^U=iJATy<%6L)6Lz%~YZc@f|P|QKG2j$SuIP`FzwuD0pO$I!Eg$+}e(E7%J`!&=6ZsrT|;jEkezxY&c^; -#)Z`zLn$RTRATF;NU9IqOb?Y#kX=??7?xd2ggMV9~bpAF6w7od@F}x4-Rwa#~k`GhkneVA9Lu(9QrYb -e$1gCbLht$`Z0%o%%LB1=*JxTF^7J*D7Pqwek@1z!F9Ro=3>^O@IE(}vlfLT$;}0=MWLQ=E@>?a^?Y+ -tYf-4@o6A~@LOtJH*jg0o`R3BrqEOE_7q=GW&<~fl7Uj@07q}KBU`)8VPP8b;ow-u9C>+D@cF5cepVf -{#x8u(3yfeMS-Qqz>$Fq(;Z5(^=#0B@b5QI-aROpA-r5}`WQ076oN -ul3altVxCJBxDYhkj>K4*k&YEXtuD`kh5N^h3Y1D2IONcNXQ)5B<)f9QvW(S(HOR{2a6>hkp1$Xi*OR -@RQJ@9Qxr$p+!0L!_PvCa_EO2h8E?}4?hhp%Ap_n(?vP-Lw~v`hkoc!7v<0o{pq3{`k_BvltVxCr;Bp -vhyHX?4*k%dF3O=F`qM=@^h1BTD2INY^{Tg3C6$*-LoXIJCebtKMRZi-T}^aUW?n;dR3 -u#+*76>&bR+o<m|m- -%5UzVj3&?E##LC8rYywedto_E8R(c2l<`kbdXcE;>H!wtLUhMc3t!V`V<{?dtTLf9#wnZi;lY9U1qrG -33R7m|1dW$eAT)hMd|G!DQI8wnQ))dMkR53f`ll`xo55sJ{yOr3hC6t}6YbM%rl01y -g~m>bVuqt-@7-t4jYB@>JPL{Z_>*>s>W&a5I9Yaid|}XwpN&bDN&qfvZbD9r{ryV8*vL0zkhE$vGhBk -emZ@4(V+`Z$o+;+>b(bf(m(~aKlWzUsL^ytuxG2|4!&(s(&Z?ck2C`c)zCfJTX2@jSmz0pVI$?{3?Do -H}w3m1qS!b&~tBYfT8E!$4(QXbC-+#Tvm5m#bXxnm{mMx5sz8LV;1q4RXk=9k6FcI7V(%>JZ2G(S;b= -(@t9RSW)Y8B#bXxnm{mMx5sz8LV;1q4RXk=9k6FcI7V((X3v3aOS-nV>yEG^svxvv6;xUVO%qkwUh{v -qrF^hQ2Dju_l$E@Npi+Ic`9@+>$%w1#>?P5;%%> -Z+auoginl%DZLfISBi{Ckw>{!*uXx)d-u8;OJ>qSzc-tf1_KLSX?A*)FJ?z}e&OPkhE8g~qx4rD&!~T -7e{0Z{wz3>V0C&`cZ#cK;Pk1fc2mi!s=D-QP=@?(9_#*kS!;V*+?-A#F#rYm_zE_;@5$AjD#N;dFuadt){wnzq|9i#%9`V1gk -{|xXH_6{1f0O(T@;AxfAb*qm4f4x>`3Cu$p`MLwbh4_CtEc)^2`C&)BWZ%YS+JFE9V);lI56mxurI@?ReQ%gcZH$&Jb+Km3=M|MKu(UjEC -&e|h;Y5C7%mzdZbxm;dtcUta#p!+&}CFAx9aZ^@6n(Y*YchhOuWA9>7={4M!!$gg>m$GpkQ4|>d-yyi -_F^Cqu(Q^33_Xx11m4sL|hu<9?xTX^&?U7Sj4y;HEzc-K;Lr4`Kr%2w||Kkuj0Mw3FAO -||0w2PaV5;F -a1EtnUSy%pe95T6$*u3$a6Xg#@L%iN-PwP0RZ6qgpP#}=)}7Obz9W<__POHRZ^rR@$Yh+B%@i-P#1^d -|c2Jhv!LD2Nlv`-Y?N*JVl`_{VZf9?av)Jw<pWH8#VWpw)u87FJXiKyF;A?TuT|J{l|5I?zpCuH -VxCoH&lUDuWzQA%TxHJ{^Ma~*L4`e6*>lA>UuDm=FHcP2WQs#?>Y}Y#3 -LY#?^*(4{Z|sXSNxCT3KO? -1RLP4mr$al2_=*oy#C%f#Y(|$Bx?ue^po=<%N==%W!b~R*I19mcGCj)jeWG4gP7e?3 -t=)ib2G+qtZgU%he2JB%dZ((5lbI6|#*vXKc3~aeQitdAWduZKkU|nnI#U7Y9>9g}SupTwk?*r>jqYE -#-gAaWNAFzj^@8ARLIYa$E(C!&_-blv`-!}!srkZ0KWbU%nwW=9>3?S2UlWgsqcNr?9u -t0KD&J#b-F0f+bzLU^q93OQpo#Za%U9RLdfn9fJJDZCdR$S50lkU-Y -HvC$kT8Eq}rD -IdnY7b;s9n=8jc#JXi6|ogjab{8$ILHJ;qaU%D0l+_2kQc6%f5=q|cHzF*vmbMC_PA*3ICceoYL+!gv -!JaglF!L7jhZqQE?u7>Bz&TrVcmL;BiS|-B2C)9Ee{*O#p92sDAWPmwxd1brCGHKCnuVMIA{Yy3}%w- -X>7`#=`t(Yiim1ty{VP>;_!4$KP)KunN**%F`Et6cEq-w~PvdT`foww?`Rp+g`ZpFkXyFG$&@YIW7#b -8RS4&HHrxvM(+#xZ$PlWXG&8Sh!JOgr-1znF;kaS?Q?2^{t!=ogp)7`@phPBL!&0^h2&r2OPiGHG!~H -6|Hkoh4ZKW_4>7W3^=LIMWp7&FXvcYSDv5;udCB>Wi@{Sh6tsWV~8 -1v<7M_ljy5()WED!SxII3Y~A1OP0f6U2ANvO*pba@(dYVdyxK{Ip20!pBX^WZ;hN;E77uSbt->_gZj* -K!;!C5r%5(%8Mjr}RTglj?Pv-$!{XG?xIi!6jk(y4A^O1~7yBb!fl(8&exF!aFu>%*w3Cwc>+Ga45dh -AaLW^f?;NJ(Wb=GY$<&7^}=l)hSKrS8v!t7Tg1cF(J2Uh4i(xLPKr?k|O_WoGL2E)`Q#x2In%b5r*s+ -LKEQh7k@{y-Xt*%e2D5 -0+?xqgB38-3I~mPTH#;~%#^iHTKjau!77;Pgu@Ys6AsqLOeY+C&!-a(M;v<9CSSGbgu@Ys6An)tUN}5 -)c;WEG;e~@|3r;T_o;bX4aJ-scI5>(<4P=wi>-56G;+h$RgVi-N2nWND8H9uNH8ThY3v8y2LgY++5rl -&!HdEo?WavC~6yju@IHPc|%4SC4V42N~!ofP58HIy|HZuwbD{ZC*#~=>P2Pfx)a|j2gGIIzAPnw-NX?Ai3Ifrl@l~Y -qVj?$?q97pZc6po{KY6{0uJvD{nD4&|banw&u;W!GYrf~2m-Kph-c@xJi9Gv6KTR1r3owsn@#BmD;rv -USP3cz}-sl~I&f~=|IVQ&WX`qJ}{9Ju^(5Ga44*)|u2&8@lGc@pzC4_wxS_omxcp5RGqSyj9k%5ENN`TwZM?BZ-m8C}LDHniz*vLySqry%`9K7C|@)aTMVw#8HH!5JwS?LL5ancr16rFTsaWvs*#L!x#!YOBwXzP^%eeMoP23)?C#iC#)*BzOqk&aRlKA#1Vue5=Rt{NE}f(B5_3Fh{O?vBN9gxj -z}C)I3jUG;YbvB&v8~ufJp!|e~|?+6JQoVW{}4$fSCZZ0A>Qr0+niP6azVoWl -2e>m)8KE|QbDj^a9r%UX=&B(9^lPU1R>>m;tHb~WxMj=M?YZsNF`H0~yjyGi42;<%eM?k0 -}AN#kzfxT~tI)e?us-NbP>Y1~a5caz3lCY~&UaB$pB8g~=N-K23haokNBcN53mq;WTK+)WyH6UW`8aW -`??O&WI-$K9lHH*wre8g~=N-K23haokNBcN53mq;WSz;)ue*0XZe%z!K6TR52PEU5r77p1~nJX$Vgo! -jp#Z#34Ls2u~cslZNn=DQ=cjjD6Bhh_8tQa?*gDI3Ont$cf`_(zu&A?k0`9iQ{h4xSKfcrlO82?5H9o -R*G9CZl$87!G(My087#C)O}c8-RgwbwJAmTBhKTTE!4y+X(dl7I;-*OkRNa?|(c8FOxUxJ7$5nntR=(HhKZx!L9 -063-iFlJmYjwPQ}%qHGDAKYsJJY1`8>2VdD(m*WSm%Smc?q~|+H?f7|oQFbplexkm-`iI*mJ!Jv=Zrs -SoJX_gp4nJjnR1R>n409>X=?csby7WEqN{+Up&x02O;YEq!@FV2)zNvUVwgb;s7N;DXx;adJTa+Zu@f -%rh<~GoavaL5CQfEn>`C0SI>eI|kX|F7M%P8x6C|(>s=Y50o!tcY^PRCv?Q}(VR2?`TF7G-V@(=;xn? -H^kQJd_{~k=ASLtuh~UQS=+;eJ)DboTGpCrT|aNx1_2UDl-bNs$MuUwy!E3)MGr@?%?gvx`QLxCXv2x -C*KaKo9wzB7NSqjSL3JhOLZn!V}jJBoa3W_cTprYOG3XC@^Ec`QS_dU!$PJcI5L>7ox=3A)SGfQt|KG -qee?Y5HvG+P_d9naFhcn$y}N6)!Yzb8HlDb}7r#5~=EhjG^8ZrHC^Q&fFYs$ZU50`_u9_%1 -bfag!iGi&0%KBqD*maawN6Q#ADwEQgfDkspiX^HD8Oe`_$3{E{ZtZ%3Eg@tdUj4HLE>j3%VQgja0Mt -yb_1hdQTlIv~;G!(^6{XJFVA%T?ZE -Wm@vd)HlI;kWg?@_Me*WLJId8I{D5Ojlx(rFw|7F%)ABd(2bd&7T_>~ql*`&iryV>k@21GkWcqrY7_e -IA4w`)L_opxpS(G9Ue^YjZV#;w)OW6_1YLB~_-3x`jeo>M*)LYS;Ran8G6AhmBkgbZt^kTEOvsx`v&7 -LB+&0+TDqBwDA2a4=WJ;vUux4s_!M=8-~UE87zacHB8t4w8qr>e`I_T+3lo%4mK5^Zx1i&uK^YAIV!d -rV~V)k6{I(DlwWS}ijKKaScNhrNwG`&ca{7}vIgao`!QibIPZd-kzfYIN+l*Nmfolv=#nLxLy{OEeZG -iNjtPQL<%Ph!T=lOM4r|iF4ddc0Cwdnw`&Lo`hR)6!Wc?71r181?y;u*1y+~^PSTs*UM#D9^dnROiyH --7&Rir%6B{NWxmz2Tr_I-v05G@qjdjRna>=R@4s5SryobpG}=zo9AmXS_C_iH@hAa}?d?m>YFWv$C}V -T@mc%JMM`gg~)$?k}a!%n&nLntodJ_L -qZNSpD1-ldsm16aD6J1*56_v01LJXmxY7NUB{F{ibtH+q9{`YALk}AR042AIcDi6|wI}v2b1cp|s6mE -H>&};ndSca^5}=JS~risYQ3A9W093oTK(hpV6U9Lk-i@FC=@ -BG{wwaR;PNdla?4I3070DeIk?^SLh-S=?RXIfn9$Q;sUfj|wY}6t^mOZZ4Z^=)LSR10)A -(+aBAv1H+>1MD><=B#QQ=vz?V$i?XvXXTv(|$MG1?EJU2YQv1Wd{@efZhkyIu|L`A=V-Byqin7}Ijo< -t&f1~ZwFRYh29TVVS?Lj3N0b{s!y}Focq~Y_5(6G~5$CHuwm8gID{=5GNP)h>@6aWAK2mnY{22<>-*j -P6M0074a0012T003}la4%nWWo~3|axZCQZecHJZgg^CZf9k4E^v8;RKafJI1If9$UhJ%FtAa_hU> -0A~wmjwnG^cDoJ5;KVaS@KHqb_(prFDc2fo$2o6kVGQ+$oEKUwOTC~-{jw@L4cCZgE@iJ9?xi90j+2d -`i?KNi|O#xEA^g}t80Z)p!@cKmaWR@GuU3c<$_K}qa7Z5Pq-7XqiMU|BSl;6EIQO)cxg1p`wPO!*mk+ -dGUtW$RRO4*DlZ_OAHw+|hq5g55?(G`v375io@4*&(FLs4n{e@_b+8*N&r%B&IDT0HU&|KZd#2 -1ey9=e~dAVGySP%+pJ7YZ@B=I1WlQk{)_f8VaWcrhU3V7)|g&fde(9H^cMpv_c&8af}s`JO?0_bzc82 -AVo2k*#zpTqh&g7C3mcKhf{h5Q&~`k*&JG^q_p#Pt!`5>uy4NyT~-WUDt<9qTA;&C0Tr1-SlrA&rEe2 -^C?+Y!(53ilbNW!*M(xt-t)X)H??h~a*O5+j&Cng$!D;Yd|A4oWH%o}S?I1N_5i -RHZhaeLYL%%Bw^JvZIz@6C{UiIwkF+LsW-syQHrYWPG!d267AQDqeEUl7}O>X9{&TLC%Lh25G1l_Z6| -db(;7jzln7x_psg0Z|G+NGSQh;|*yRd)2^!ifdbJr0_@&fw-V( -xGE7NVA|Siu=E#5ontCBzY?K!X*;-@XV^>@fNLQ&<@v(PeAC-d;*Nr7GV|Fwau|chBr*PGtx~IB?66g -L^x*v`zXM*RZbo)d#gSYpK0X2S=8rV$|Do^^fo&x4yTa4OSD_r;{0mS^0|XQR000O8NLB_@q2U%u82| -tP7XSbNAOHXWaA|NaUv_0~WN&gWX=H9;FK}UFYhh<)Uu0o)VJ>iai;pi$Eh^5;&x?;&uvJhu)-zJ)<> -KW608mQ<1QY-O00;m`Rt8hVOvxmHm;eB8H3I-00001RX>c!Jc4cm4Z*nhbWNu+Eb#!wyHe_LRVJ>iaw -7uDn9m$pE`CdT%53H*0R;o)?74FyXrfyZW`}ONU0n_s`)q?_58a0(Gm8&wTwWkMUtlXF6z66=v_a!2@ -$C7|@BNI|Gx#Ysk7Y3OTHzK71^e2olDB5@I`~31P3PcKJKldBv=a?NkcFgS9-z@o;mzKS?T@gOa6~#Z!Q1cl7IR68?QY7y(RzSwPmlr_UOUC{_DT~=luUnm;CpoZ!A3gFH -3*o{@%jt|Knf&ucY?(?tw?o{pDZ$_{YC^{>``CYd`++k{>MjPE`5(p1<$;&R_n;bI-r9D)QFyH-Gf!>iB}kr9b-7<6n96`Q<-< -^R*>EeEk1C)AOsI?=AUGC}Tp|%nB$A0lG?BQGkL -2^;zvKS1G$@Xr6#pbBt~@DzHYiS>6h9XfSDzF=9~9S~6u%G@*Pj%>7!)_26u%S{H=h(Q3yRYx#Xk*-v -nRzb2gR)?#jga#`IF*TgW~p+;@5)W;z{xAffep~Qv60x?B)HlpxDd%&7j!J`>mkZ%X@iH?B)IQpxDd% -7eTR?_b-EDFYjLk#a`aO4vM|Je-ji-3$98Fu1X88N(-(^3$95Eu1OECNe{1uJ^V+HMt?ubM~gkm*TkC -C#G2H^n$*Oa)Wn+9#G2GnDaoXyB_(2QYhrC{1((#t+SWxEbAwh2ZzA7NW~zfVvy2D0{iEnL<~||peFqmWMY>x5n1L3+&C!q18z9kN${su2EY%wpG*Yh -BFRi7nHfnQ3xFSMqoCM}GjKFA5ohMzn&`pG{v<%TMd7D=_ogCmiRo{7@8-RCf^zTPymufd_u_u$4he&FY~#gMhdkhR73x5f6i#rC(w_P51iwMCw7a -j@EA^xNWKwZ%ZS#oo8Y0d0%DZ;KTwL_UScrx5uRBA-I!Q;2*DkxwD=DMUVn$fpqb6e6EO@74`To`~E-(L~c=!@2>9;g+SyN_4p3^{^}5j9HSoJS>In90+DCb<2&m -6>q8)Nje2}1eSc#JRK5}9yEz0Z-w5*E5(1TP1o>_Yfyy_6e0PLE79mFaL4OEjl#39d{a`QzGTKFm&wj8f1TyMHh|YdI@mffHtN$Rh+KE~f -gl9hpt#+a<5y9CHLaUu8(M7*t41}*H?-OsUX5 -yyZ)mkO%o^1o-_Vk3xHYOlzM&=6uxnI@d`Ci{@~uO@VDOq$+sp(aDBeY#jRb>;Z3~fx)tMbP25cpp6Aqh~eQqx`R`kruOGz8icn$TF-{Zp^ -84?}ydk?1HzR|sXI5$PyJR|xI7My8|G%kSeAAwX9M<(Fz#Na2=*{WMj3lX{VU7#i=H~){LbAy7{bf$9%0g+M*M%!~Bnup?$@l2=2ZO%g%q4<|#Q@93O>-L&KO++qd$MLc^iq%&6_#%SWN%(6DCI_J-r5&=J(| -X4LlW`=iiEYnU@?`v&+?=m=`KGiv+3@KI<>H0&9*A>YuHYxpxNe4BjkHz9z4LQ}4B&8YAK`Y@ce6tJw -J+g3nKp&8I#IW`@{JJ%y}mXCBHtKM(Ce5_hfY&-EhcP+cP8dVNa>RF{ajUf -&i1)g>aX*LQ?Kb%}`U^<5!QT_WOoeNPBfmx#Dt9}a=a7ZKO%`$M4eMa1>PeIZc!BI0`ePzY4Mh`3%q5 -(1SkBCgkug+S$ti0kzeAyD}u;(Gm52voj^f?hup0+lbKpx4iZK;?@l==G5hsC*Fwy*?HKm2bs=+k=r% -z=&2}p9p~r?lGd3AMOr88$W+EB>IhrR^I3hfw)RBqLm-62!U@fABRQ|G0TtFg#c5m(8MO%Y_O~J2K~A -=8-y%xgeF!)mN7z>H`a$hn+-yiH$t_|~6?ty9#tep}2@+~KPeIm%Bm+4fk`_of+~+w+sP$a;p~KG&0|9Z{tLK%l+-v8pu-t3sS7 -A9iLpVCA!&^ywWq!9J1imui9;S+R%L=;X@3w@%*W`Dr_-C*e>S_pdr~E<_5B7Ies=9X{fzIELgg|%oB -hdN#u@LC)egrx{4r{7`&I$sZzrP%U(5i%fRBf^Ss7hTnD^}|00i=PtSgOjOH?X?@{FkuY&xvn_a@5_d -l}5L1ag|0Dgxd+CnxC8wfj1oC@>iwdEypKkLf|L4pPUVWx7nYZ3xVv`tTepMzPT<0vTL(~aOchSA%NI -|utTM(%^HEuPr_#1^lkW)(Gd9V_(`Y~gdjh;5CU|@iy?sYFNMHM|C3Pq2tDUrKYm^xRQEJ-0Ta1*Tl{K5O_`890-Be#L -dAFcum|K3W3+e%~c`rnz*?-1YQ$2*Mz`p;^x{Ah*wxy*u0sSd~-`pD?(~FgSk-!y9lXmBd|uz3;PI3a -0staC&W%d`X~h1NYvO%NNqwl6IQUB@aC=%=$S6;B)qvN1Zs(~i}2=f2*hWsAo_N5e+a~9tiUU|c_0Kj -dcq;Oc_;*`VmKo=kAy%+Pek8t9t(lW7tyzyCqkg|MfC0FsSv1q5q-NEjvg9)t04MzGaNTG`c^5>qC+c -Jbh9S~q#Sl6-I7>A2#>l&(ao~!4#f&WcsJ=s^k8Dq>{dC*IyBlE!mAYCT>qY)^@9Cxfhua8g1Lg4lB> -4gw@eSCT`1YRGXUJ8NN$ETM=;Pvt8l@NG+e0ntmULT)c3xU_ir{f{;`uKDr1YRGXhCK`Mz)z<_;Pvro -;5sFU3f@`~0`$d|AwXa34FUQ`UkK1Y`a^*JF%SaukHHY2e+-2H{bN-K&_7m(0R3Z42+%*)h5-FzT?o) -W)`tN7V?zkgKY|ERqUYQbY`VI2AOtenC)jj#>re<}97?e1>ei7E$Y`Hn)77nGA&}8N!KSNQCqf{jeS% -F_w@!sXMxX?nu5O(PfsFPEHeKC17XlgW6T~8Jg_cKS5eZ@uw?dnvv4{k*h+Cnx(O5)+Sj4T+&giDA1e ->mIg%(E7#3psfH?%DpH%RJ`Z)jEOD&IQf8`_h)%D3U=dpoow4V5ou_qW5o*Um#4{I#CABOnA?a;SqsxA>3xE -A5yjgr)9;COy|?ih$Ie(4=cXDnUT%PH56KAeA5>btg3G8jwm5kh&9^bPY%)2uR%t&8!Bb5(K2~gl1L) -QV9Z5cS19(0jUH5sXL*W)qqrjfYhDP%xXX?K|tzGXl6Aal^`H>Cp5DfkV+7cx)YjN4M-&jNZkp|tOle -K1f=eSW>!zdCJ05{3C*mAq7sCn?u2GmcatU9O?D?VvwB)K!9KD(p_$cvWC?;$cS19(L8t`#$nJz@R`- -!5h)dlG&8+Stt0E$GcV!4fzE#Ac?qZr7`asRa_JOLpXRV4T)ZKv)h%T#$KiwS)f#|Y|$kW}`ArM_w5p -%k`HUy%}Dxyty*M~rKSw)=b?#2+PE)ik6yEz1^OT?D$ZV7?P7g43V+d`o7MLg;5ju5DP5lOncD+DTE# -E|ap34zKN(WAS=AyD}uZgh8l2voj^7~MS(0+lafMRyN{K;?@l(cL2YRKAD|-8~Tkl`mpK -cTa^t<%?+0-7_Ij`63Q<_gn~6z7=u#sul0@eHMxw`^Y{!7y|G3eHIEHr))nv90KqDeHMxzXKg<_8UpV -GeikaB;wAps@ep`d@Uu`A*yHxu$q;yl@Uu`M6)*kIPKUs|g`b6L!A7^w&W6Cp;yw$NgZ(z2oeu%@F%k -mkV>ATN$5;rUj|(AyJ}!m;`nVJV=;Lw-ppPpdfIhB<0Q$HV0_bBr1klGs2%wM25I`SOA%H%DfxC*+y` -QfLf!D|9;qZ+!zMuDo!0Y4lz7TkQeBK`duaD2e;T7k7KOYQ%q#>*7vEC}S#(Z{!Dyc{Qs=CRgs?n~hr -eCXS?5f(5eMVJ19aC-VUsMORT1Z;9T94*Ej3j+pEea=Vl)rJ&(=^xWUaemqyBGAp8e+2dRx$EQ`+A6x -?`-$hFw&fkxokwL=`O^2kEE2VN1CBA5lz)~Z)!c0oiFv4{#K#Cr7m_O)>MGHe$l8%`nyJ=PgOPbU{xg -1sOoRk^tWo7*f7#4)6A6GRGL{y21$uqHCvj&vL -#+?v!%6fi4WRrY35ChCN*=-eu+TP{i6r&9}U%qBxm=J9u%nQEpxPmqv!Z}&2-jmYg^D9WzC`_Yo_MM? -2+F}b-tVSh(Sno=9os(7E+xDrm<)yjip_s75yzuPoBa}zkhu6{_%+r>ZfTcoD}Z){o_~UC&UFwHF0@b -k#?Kv36iuTeKXZeH)$e0CDlV3X`(XJBNu5RO)b?tE@@RvZ)!~G@$D=VV@i+j5C~Ixe6NM%m@Il`>9nd -EsHz5xjXr)#K1O?xCZkU4+D3F?HdXtbs{KwiH*l)F|4Q`?*MNUP1%_GW5(Gqt^$+T -KiUZ>F|4Q`?)VdCkSdZ`Dyzzvo*7T?^nv@Q!>q-|(>r}oV9B3U7 -1dN=YECjey^=Ll_-alvH7A+QcC&^IIhneHndX(rG);J>`y(<<`JFXY-J0|})2u65s+~x85@e}19nEi& -rCKjdo1Liv%QAhcB|~(kOT3vnpqVb%W@^APHDH+4Opf#(^ilC#g-bKR*y)crADU}g)N7 -M{l(8Htro7O7OtgMsa28bc}uNQOAqX|)GD6TI -!dyv|G0d)uXO$w+b;`xpw|sJAba7KiAHmN22Xq`%tcZDAzueYahz1@{M^__Tl8(?sIMTxt`g~)oagnn -9X&V&Go*Fys5R(Y2ou#dt@!D$s+v=~ia~YP}CSZ8&)ct -F_LYN2eKnOM6zjmNP&3J(gBKIfOhD3AbV}bSlWbgf{%OTWT01|OF3r!GGVDa+)}q~+;TR! -NoGZ)m_!&ZCW}}{x%#%IX&p6$;mr%+53L4Oj$}(@q>W)US`lC^-le#F@WG${t#uitmi7Df1$=|J({9T -PVMX}BRqgXGob7dvJr(x$P*6bWntij?a)@X6`H~|trSMt4?>LblBn -qwQ6vvf4HNdg>sg)~{eq<#osk}xBT$y%?N?q(iR4GaEUD5mfqKfVch#nudr{}Prd3xh{LQS9%LMhNFp -$uq@5NyK63xskYx+9~|E|8Siy_(J&U0F%;ehqO(wGwI73hkoxlD}KmIeApqNqJO{#MzDNamnxL%4Ss8 -T_sVyDszdbUSewM>iM{`lKR!POV#xzR99B=cS~AjUE@TqO!EWRb=f_tYp}(YX)CYmWm>LGpKFxpt)gE+sl|)U~ZO%98nOusmv%q~&gu^z>$l44RRe`DRJ|nz78Mqo(eMa%C -mYm9*VvqHV2Na@9+-rgCoT4Zf~S`&P3=e$BL`ekJm2>KbR%Eb(%hB|ceGXN6I!+XG!$$#W%cP+HQb(~ -^-P)$_?wsyE|CX^H!gmW&{2iA_vX)kj()zqG_H$V%E@mZ)5^5;rX?`QEHVzgeL+C)11RqEeGFj2t`1f3B^Ef6RH4hA(Q}ZB~%64MyLj~olqTU2O;=deLD%k-|E{%2>w>zZbI<4`t}g&ItOcEB0k+ -WOsEaCk5B;=Cem-EMqlp`GWt3|$mr`JA)_y9N~zJ;VM0bT_ -t4nb&Ze?@vY2gW0H{323gw7Xd}%3-zu3}w@Lyttr8!krP~IglBL5a$EmKR1aR~3Q6m0henLQfjT~9Rp -CjPg)AIyyea0{m-Qm%6-}O2HuZJ)-y(3-^ -ZxHZJ>dg?~fY)*YUKu|p;Fa-90$vx?Zg9Zs2Hix16J9qq6G5lG&`ZecgBlwSc~Qf{AunoJCj0p=BHsG -aMP9kdf=>6zV5x)}qb`%UGOrP8RXE~BjR!}(=yu5*Yc6OhHD)XsQJcl#5^A&94LyBv@ma|Bh9W~nRflk5_^f2urMW{BYJgD4tMwlU3mp>_*nwDZ -*ChAuiW>}6T!W6WG&zbzd!)j9?&IJ@Pcm~AcDR}EfPL3UBQ>b1*Tj3a(KWuP7;Abb#a`K7yrl9#o+(m -I70;P)TIGJUOykR6kvcyh(JN42Kc^oRbUR+_Xf3Cc)mBNUz&?4E)s!;t`PAW`k2Nuc)fISUvBQTJ4FQ -dQ>-R}`|Z{cfyaA++9Et&x`i)?!y8^m;)qw!ZwPq(d`!bV+~JRDxQ91PxANt1hCd;RmiWSXNlZ5{xs0 -ogY$wxKRuU??z6}Xarmyr7D!IW8c}S+O3=k^0#0{xPrmqYUD!IoE*+{0ZtR_@)l^YV0OkY_`s7x{#+^ -(!ARC1vk(vnPH*+{75&b-LTeKVmFxkpCsTL_iNJu-6NMyN#Yk&*ijLM3vKjNEq-Dv^6+QQz#qERy4j;J|OT$xcaU6810Qe2r)GTo7=nNnPtQ8HbVsL4`X -nNc#`l&JYqT$xcaU6!aRQ(T!*GToP0GO=z~jFLwPmB_tfCcMDAvWdX)x~lKms?s*yVlCVB`iYS)b1>FV2(tyt}vkvrLUP08)bj -NHk-YgTSoX5>!xT@!P=G9!1g@0y$2l^MB{eJ`1UwrfW2WZyMIw<|MpC;P5Rx}$d8$erxFZc%k*M($+a -HC4AOGjb>UuGzX>nUOo$cRhXN%8cB}zL(6-+jS#%vhSL<+m#u)lYQ6B-LA~Yo$Pzb;&>bDsMFWTzL)G -9YGVm?`Wo5yMv2_9dOCd#_MKd_MNcUmwe?g?)W-Vl^fekx8f7<3L&?`@Flm%18JW(fuhC$lxz3|DlAT -XqqrpTIK)Es~`5Fx-dLTb)n|0)CG?-}OC|72bOoNFYT_4-CA0M7DMDBlWaF#HbX}R3!d -q_IFcEW2h7cV(vWk!9E9;jYXyK -Cw!#HX5>zmUDJuXG9!1g?3z*Bl^MB{ -W!I$QuFS}tEV~}6i`r&Y^%_}rO)VZhK5F#%@o}>3trEGnAop>y?0Q?AD}&s}$#ZX&$h`%*kCU<0>>AP -IqfLK)oQ!R&MD8ufeVmM~X60~Yko!0p+g6F(Taf!W8CyMx7`1aFcQUq`j@*?Qxs$QgL}aea$eoO>9`t -o(M(*Uf>k)ldX5>zuyQU_O+PRTCdG4B>JTiyOrpL*1*97HJJ2!GC&s}qrNA0$eJK1+lQ|`))+{wOcYB -yJAF)_!9+8ryE3C>8cZ~4x+^nErolvW^tdvkWExD$qWjC1;J=g^@cACYnG! -Dok8{Vg(_rKToVAgio00B?MP*qK^>1WTKxC_8d(N5W)vd3=+bgqls|vDN6RM7bPcH3KJin*hI*D|7Jq -w``;#HzJCiL^Zi>1neX35NOvU{CA-)Q69k@khmiS_1BA?%93*7E$79~ -6J3ln&qI8VrY>j)w9t)qm@w~i4q-+F{f+8ttwI%>MNxc@^hNdT}*P1x!B= -uVC9Gae_UTeaklhkXmcW8Q&dTq%O#iC^Id!hNTT$%X<>UdRMDlMv}?$qNnQ$kc!O{J-;m7H%Zu+e3DG -IX?xlCuki3Dr$fFRYo*qF!hsc9YZ#Yv${y7n;D`B=y3Y`AF)8CVn?by|8A!m3m>xxs=C8%oiRHuZ?#^ -Pga@J=i!y{QOVKs$ecY7?~#ulA3W!$v4iIv5j~-34w#46%SRn`UfK(Gc*uG|23I0vIBhWOS0|HIsIVjLHoJ -I#)}N&U{o)4sF$wC_xx_MO?&zO(hT@64a}o$aT6XYrKpEIB$@m>}rnd3gaN-}y)vl}BvJ@5q@$m{eXWy1uj!EPafAPd@KLu=LMwtrBP -yb%FmLu4nw@vM?y>tgsSAX-X(p21UIqV}c2xPSPv}S2nVXWdf;_G>O68jqGV5oLcgkR!_g9Imkj_)kB -(vw5+mN>?KEliX76W8G5bh6#dB(iAR-%*fx&OJ*Fok=0g~Ro=FcWR)9PZD -m=Nq!B3EkQH^uc8Qa1qLc5^WTkE7LX#B}q@27)sH?ARLY42*grsf6vx>#jZd*v=X?yYf&k$%1KUZdY^ -aMBO!prUE>h3=AqGykH74hcd<_4)`iTNl>ntNf)huC=&tem_;sO!AQge)f~2tnmE;X&Xskm+M)bWTbw -Y=i!W;LaGl)$lR6H@X|&1k7zxl`ap>|76NYzpY&IMMMUD>uFN!>0YVb@j(ZZXnt% -EyA`MUI&n|@49#@Fpk+?zJQ>}{_MUt9~%awK0H{rCF{z3Ye -@+B*+Z3pZz?qcUSf3u-exrjc#G8}kUkOO-xBcV>cOhF3HkQ+0|MSyJww2^x$hG2^Mcnx(C8*}1bZR^e -%Oi$_)c6Q&`l$aZW?KH(@3M6MjG8T(&(m(}}+IWe8*T%~Pyf$7T;I;880j~{ehlq^4LBMO{EdqWtUrs=>*Tg-VUB{LAO1?=ytvj9Ko|br -UaY-h|xTjD97{Mi2`VY?%ihxiHa`P7bwg6WT-;lV1z9IegJR|YoU0LI9Bvv6@8>0D{^ICSkDpg5+Utj>6<8Cz^1pgxQ317 -s`f-LzBhs-1dw?bN$!r`}CF^{(2fch^q+DcY%b)lR)cJLF$3`UMrP7G0Y{y?axrcWVmuZcU-yttr&IH -3iLU>B{7$5?5B@+hK0mqxMtti@P!j#>bH+2#sSn91m8Va{q|tA=L-e`-tIvJXm$s{R?TOC#3p-j+Kuy -tyie5?76l+r`vbp3U&oPT(OE!3bdM#Y*CGqSdu!&iEd?cWs=M-PGGqs0^T;n1iWde5b%Z}A>i#om4LS -kH3Hr&)CqW_&>-L~LX!Xn*&ZTZ$`OA%hFAW0-&7<1df!YV{(Rp{BmRC2sU!fH?1&@)n;nq|V6!8V0Ze -vGGFUL#k0UwJcM18q?K3eWKev6R!pH}9pGg?`$nG;$Mn1IrOpTEbTs>1~lzG%(_tGnUDMS^hI)p)`!zSSk(ZEn=}Wpty+T(tze-mPe7FEfH*UtxqU@hT&9iPspROT5kqUE&Q!(AUox -L0@k&g1+8j1brHZl&6Sv!0Y3e1iU_eMZoLh*95#i!VqDScUf~ua<30+_Ia03d4hdG&k^wYpq -7|>eNaopX-aB|xz`7^#Jo!wD#^Qqp_05yAT+^dB5H{^R!J=p_x4ds#K}r(iMiJYwL~1Qq?XwB`kU6;CgIZ$S>w{V%wlYym#6~7+iP*+OE~%chjME;PA(l)7Q_VCNr*Ln-|NS2j -@?*mfnAAWRX*fPbGkI`o_;*(bYNay0UCG96=)$Z;e+$%31P#``4K`f&?q77PdPtE2%A& -RUm#Qkx=0ASQ_f!^gl!t-jbk?<(>V4JGL2&|A=5a937N*RkC5(OX_aj3Yv~P3ajRxp&jCUjJ!~PmcHGe`#yL%P=E_V -5q*1J7_--Mb|5F0~lYc?LfAMu1G7!(dK_dosv^^N55kvEg#pbG}2ctApXr8gy+|u-5l*R~6{S}+5n;w -kP;Gn6$VsmTLgHak4H1(G&gE1JT;XqS=xiVORQ5pv{^_MF{_aCJJKvRFk<_f6?qttLU^;c}}j(RXkCS -Oy3#pcqe2cz2vmB_tmW+QJOSpwz1e;+w@?RW(%5a%#|6r(=)+gNP -waC$HbD^G6RqTjp{w=}g`+(NYO!59rDn%c~jLCIq@m}qJO4NpyV+cOfHJZ!9-J=xiTYn8cZ~`nJY7Lr@^Eow9?9r+-We;)Mjz3ZRAdaiKaGlWk&8am}qJHB7Doka_!fFaGSEfOymS)F_^H_sUdC4Z!yyOs6uIcFG$G5!Eb0t%!$5;K(bMW&YTnyEd -mu#rW^^R#*rdrRNx?LhK*)jk4-Wq;RCrFQPgQ4g2@Ok|BmKA=k9zN+tmOAf_VVX ->$?xSQzn7Q%o*sscA16o;pKF)wKWgj!z;V08v1}uI!|b`x2DeMp*T$LB`KkScv@;ZlqJDE_1)&J&IH4 -Hm5}^vvyM(+&{w7T1?vS5kesgVrPz`7up*qkzgc?BC2>F@)Oh4Dqo9UT>BZM-bQ-r*=o*C>Vlml%i)C -S@o^eUejqVGZ!b!O-yA+N8QRZu0lSc`sfiK~Zi95ZY7P!)aSm|1(3kZ&9_>$VZ90_`SL1G+-UH;$S0D -+x7#_7XzlSbu^L8pj4wGeWjA8>l}ZWIMBQ6(KZ^jfV)KaqQVa2#sTJ*ue{gY-bKplS0UL<}g(rA={b5 -YY0JKhe;_2+0Gn3MhN;kGDZmcIKcsAq0J -0rZ$f~nKPHkreH(n%w_sP92c3nJVgllx;jb-`npP14<|=vu9DTm*^!y?3xuGrajpjRHL;cu^c7~Kj7_ -4%nMrB@NR&7eW~z%#qQsd=YEd{yGV^X9A+N95Rn+y6C~}+Gt?`Q* -m3p@e;4$1mKs1}{3FsA&fCnM+e!%fI!7HAXKiNLq~M^kLIqG5u_&-;)Y(GgGWKP6wj3qo_0`$ -BlTZbS#!4(6b+%IL#s2KhR_YGeq21X|jScHdo$YTEg1&ZTB`r1t+5muWzyGhH~s@>VcZ$V -%CNtIZ2>g=apiRox(KXpB!>s95~g}2~*O>1&-QurpRf-S)0xjH7P94&8;Ax7|U~WD`=X91-iKv)UvTcH@AX58 -B26?E2)hl?ZjL!nEin-O)Hn5mCw`)Bi=xY}ZDp=E-J3yW^QhUxFpijoq-rNC_JTgj@ -?$4j(8bV*E$koH{{rOW|L+I-?&3v$ffBrPh=&&j{f0`^dcJa@jrZEMJgY#!7R)wAX^J7#EtP##%r4Eb -T{PR3-$5P?^HU2^9>l)1vuwpnrP7`MA>YpE{;RXwb^W)SVu(N-Docb5m59i0p6~XTQ`H2mLpf3&|V2A -(w1Whclnm9i}pNw7p^OIy?v8XsdNrO~wBIzUztS!z@ks-ov|M@Adp)4|0x+M~HKvv>hnXl~McXM+W{f --@13t4BYm_&RJLl?2qqgNPLdQ5;QjLkY^0}-;N*lu6o$JCZxKqQ|T$p8)Faqf>=!Daq_8ur7~INu0)lR=MZX~?q5L&*-QIZ62iXB -!IOlL-n+k-5R!Wjo+gCU-h*cdA+>0KA0Z?b?e8aqWU~DOgpgTu@H`W5FzNRpBj(3HoN}-A?T}rH6iG$e+?m{ueF4XzSa>k`dUv2`s&|62>R -;ZNC^7s-$V%d>fcNV`s#n15cD-bf-)Cu4;&-}eGMEU1bq!0CIo$jOOX|m(Pw(#C?V);;20t3Yv4E`=x -g8vA?Ry>y1BV9CtMM&m@Gci1JupUy*UHa&CONZ17`_AUjyd|L0<#Zm(49Y1Jswz#oPnbmup5})R)cu+ -ym5?%|7)3>dQ4*cdwYtJ=6VL37L+yjSv(yME%=b0W?JY+gt%OM19U&0W?G%%Ul68w1p59HMD~e6g9Mq -km*=^2|-aq!yz&^c@OO;WDFs{WenjyLdFojL&z9H>cn-UFY3hRdhdSfb9G|~sbiU2zWb^7)Quse-eWH -N?x)^UH-?aUkGb=^pL$Q-7((g?=IZbMON30vBA3BjE;N898hWXfMZf09)x-2+YV_t7qaiX2<_@DF5{J -3LXn-2Mxl(9gCm~~XsXv(Oga*lVF_#GqlIvow5*nm_ZY~lUq(RMGBQ!{Znz=-1kSvk8LTHeBk-0!>};img3uvtb -8;xd4>D>2k*kf+;ml#OA_yJM?4`jEQw-VxRf$UG7g4)pkSg@K7!%fK+;ri)1S11`8O8?oF{~Ikz%Vgz -kYUxpA%-;rS2L^|xRznVz;z6p25w-O8n}^RX5c1S%)e8)v&wuY@@kP+*zpv -w#5J8{+zD;Bceg5%~h!6Vwd`CXDZTY|N5w2!7j-gCvQ|W~m%5+whVQk*yjuJze&ayI0%+Io>V< ->ZG;0(i>`I~GI;<|bB6hkQUo2$bNq0E`}D;YwWvwOMG#!zNwrTk4ObM`zppg1=_%S|taCg+E^TjL6iX -J+>9Cs=_#XLlT72z}1JbCO|fD#ZG%K%bq%Qw*WcnN8~%LZ6-0R~bT|bE5|sLZ6)@tg;I9IkSdkTY)~m -89&4j`kdL!U919q&YU^Q5c=%wk)MS=znS1RgiAl3nH%E~r(*QEp1VWRV}!unAu;`Pf}2SKea;OTWs_s -Q=ywIVnp8|p#<-f;Ww>o4A$Vt3CkSEJTDU{bA#9vD%ReZa^eZvKFmEh>o)9uSMnrJgMN9-41S>?4RXH -Kzzca29K|bXg5&xBOorrfq;|3A$fyPZD-T|%j5b^$Jg=K*3$t(l!eO6co-ubMs47~4IAsLvs3k92F6L -+Doactr)6abD*+=ZgNam`HU2ML+!JheC*epyYZYg{v~b&YGrCj3Id%h-fpD0ms0@CyYmV-tR%;AL#WF -BH6t5q@zVA|bCX=O2a$;TPu}67u?Tz9Av6FXtH&^7{HixP{UouP^5n67u?TJ|Q8mFXs^w^7?ZAAR(_W -=M56_`f|P?A+Imz2@>-9a(*D87OHXO+p%|udX+gJ@sGp&uGiWhcb_LDhrB8=qAxtBju8;yId$AHGjVG -22#D~UIz~Xm`F(_7>nX?^H_S|&x-tSHbi~FX%*3w_6EX{iD+!q$%G3-I5TQM}4q=D#d1@L6h|rd2hp= -cpM4htH?ZieU#-=OUlw2Ai&&_eKaOHU@VQ!jAGYh -X|QS*BU}NE=Mt|I5qu?#wcvMnz?+G5cIW?#EVT=Gwa3)VL|@v4nok^8U9;lhcbV14jG~^laIUT7bUrR -U`O5O33x -Y&aQ-9KWywu$o0d%u7qXaTSUS#@C_ni8F&>XECa8hD#-v_x*{16u%|0l1|2Cw`gdi>0Iv*5;FTc{yfU -PMSB7lx%1lCdg(fGwLX#F=p;z5YFB0*pd;U#EUU$#`f{54ME6bk?5%zaI>^(>*0wO0B`@0_Yk{!bSu7 -|y3=CQx)VK0pv*x&WAmmCMAka*ZjRv8&xANHOj)BqYGgu4=Y$tokE#KYc;gfbu+MUhwHVK0sI$nN^Em -&`oUOFZnIBxH6ay&EEAnRwVoei^d7KI|iJ9?2#i_R*XTnO=GOQ;b}%5Bq4SM7Gz5eKZ~--|NFZ@`#b~ -^LXXQF#4h?N@4U -xK44+=MZK~x`l4Q07=2N%ER4RWR~ANJqc7^Ph0zyHI18gM>dS@E7xm@B=!=}n!sv^-d13 -T5N(hU1oz!^hCikr(7F**n5DUiGydx9`@~K8(ZnA1kX&cFe^RAW*&BZ?a -}Y_o~LK3!82oQ87e)-gdTm^d%`_K4;Vvw+!--vP8TY(njUM|$J_(G?!zbO8Dm{fF4XoaJ&*X9;uM3tb%PH-#qnI!m~GeoN)b&YjFL!{%VMvwI!c-+mT14MOx@?4p|Bhxg?|6)@fSom|K^2oH -#bB`p@JF(CN`7^WNu`>&mUr*1NW;(LaTc{^Qrj3p*NP7)E&<-AOe`1&(Fb(wLqk1mXIeaGWvCk}6hq7 -K5o5p&1p>3$4iA@t4FEcc8g&!a_#b$_FQ6`hv3{*qxX;oq~R;|`AHN%x^HZ~*H8g?@51zLR@${LutMy -qe*LX+sH2h0GrFlKa-K#Lxe-!VhlriBMi>zA6bZR?|v!IW>hM{V~5H{(~4;o+aLXiYk|GT^escC+(csWdEoWVPR>2b%V; -JnFWj!ActZf)0U|EO@{*l`HgsX(YQA9(b1?FpXsR$*9j#HH~ENLOuBb(>(TwFq0npCm#JiX*P+1*Hz9 -*%n$INFl}Ss6Z1uuHc99i`72fXz@rwpkshc851it;VkM~u4~#7sz++ll(=hfwG5h>X(>}wFOOl54NeA -aIGR@FDdu|`h}`#Ax9tkxb%Q&AtxUjRsE4Tc;*CA(?U)?vQg}fRF -mL=i3J0~f5Nno(=zZ?YXN=Kj~@1p>bICiQtE+VO}VGT9o}5dtIRiwSQ%E9l_9*R3>Wh%^Lno-^D3_k! -y0o#nOAgE8Ez6(!C;*^QpsSYIa1MJtvOQJV6{0?;b6TvQt4pDIa2YM>mN(xgJ@rgfDr8~k&xG9Tp}T_ -%D6;AUYBu+guF6il@L~-W0errpkI1pDIu@T=a_g^F8w(Xug9M(eUp&a;_HZ6(%fj#?>lqV@a^S|XQ_g -|u{`%Gkp@Ui2$#6MS|Q|H$ugD_)^@Ir&92%+6w9YO&q&CkZuT-C<0Y>OR=a0+ZkP?zP&Awj*!`>^uO=Zi{3%9WO|L#!we2l} -jR0~jy|&ndV7>cgL0(<23c`hxg1o-oT>2cLwm~JIP!Oh%z*_Vh^d^>~Ut?nIAR}mwiC5ekzaZlE_8OB -K{tzSRjS0FJlV;aqIp*aL-z*0lYH7mzgo@J1HF`-Z -Y*WL#l$y-x2Vr!A^VpsQ{NPR;Tkq;*0+YG3fpGm2<_9Ww9Up5VP@lqFtc$)nAtcY%xoMHW;TupGaE;Q -nT;dD?8Xs+cH@XZyKzLIS71~k8?VEtL^xiJQHgZC8Y2}CmbfF84;Hy26%dxWBb5*qx?`0Pmbzn=5Ei> -*l@OM@W0epVyknIRmb_z?5Ei}T5(y#1Qz9X+&$vWF2o01-2xkaNB!puGB@*)be37O&NspXPZ59iEC@^ -zrk3N?s4Sg=rGsB`Vsc9WITn>5o}(B@|f$x7)>ny$>qovf55&U0l(?qsF(!XsDa<$h}o5${IaT1P~#3QKE+OnK6Ji7!ycUXgG29w -MZotz%=zw|kEeQqk725#-yw#|Wut>)8A8?cNiFRJ3*M_4s!0DMBjRI<|CtyY~zsZPImY-uQO!IYQc`> -lGu&F+wGRtQbLFBvc~EiV@^xLM4K%7(reoR3gZV5#%_b5=MthZal|fGT0@aW8HX;!(^~aJjc569EZtZmw1kK<2eqK!7lL}>*kF2Fbp<1W{ -Z9WoU2EPlIuNXb$g6Tl#G?>Z-=iDN=qKk@c0BFxpmZ);hg+M8Xf9JhGeVt#C2LX&iX#G)g{h)-8k#}$ -X1s)>viL-?;~4X;;h$=v%ZgPwcbSU${@6T>j;$y4U51xs2?@d{i+)WcOMzk5(l?#9Nc|mOiLWxy75@| -k##KbSnI}P-AC53#AB@+k98ke#}bdV4v+QQePkUq`LioS3)@H5QSW|F>!}eWSx3G5-IWO2jwS8+(a(;oo5CpuL_Z;x%yNB#{yYU@i6IeMEfB_+# -pBSWEqwS_GC-zdb_@Ju|u>k67=6cV$KwBWXn!K++PWrilt8t(H7j)%vAX^)=F -#+@hVPxtg7{(E4S1b%rY|drqxh)}wOCqLSZ>N`5ca@6F<}=hQr8amn8;>13Iih*3Bx!&d5VPhTd4@$M -86zrObEnYTk!EBW)-SN!pMB5FCZny!jvCZG3)cL*T?*oFgykN|AMK|)9Xw&4&VBmmoRm=F?xZ8$;*Hh -;rWLP!9%fuwKpd2cvQ2noP8oFIe*U>i;nLISW2q%@Pyd&6l$nAmJMLkKCGH=HGeeBK+vxmjlNd2cvR$ -mnZ?kkQvDA)~J`LPlQ~2pN4{BxLk;iICA3bqSMVd&3n%MqgJ68GT(NWb`#o$mnZ=kkQv9A)~J;LPlSq -_mpAUHN9~KA?R!4No(>Q3b%uM5;!7?+Ag9gjYG!7apGt)R|u*^*3pusXTje`cu%rp)fEHl$MXt2yov8e4~OLGPwXLb#AJynV_c=6WYjVlj*t-nYJ`a0cD2>M#ZpNtE7cb*9m(pk)3p-)B%iz^(b;p15cCyZ#O@F-z}`vUg)It3>=NDwi9hTlT} -x=bboNg+B1*AYT)&m&}`kO-o4=^a8yx4Ds;C^A3HuOp>kmjvC6>k#bWsqKW2i}esSY$SP@nc%w>I5li!W|+Oan-GraPGH -~&UDjmL@Az`{z+icSnlH9;bgq!3kn3SS+^p;n8pqnV3BmaG@>@u(JVf0R2_0sJsH1;bs2%UKy4Mo@x(m6Cv2p;DY*%a&xnVBM|4S5>Axk3Xowuj7)Q3F6Mb#@zhX4oatxj;P@`59)y -aEwE6ZVu4chTIIDy)@on&&b?nGQP;mFn5y1Y=m)V&(iRKFz(zGDFtEN*->(r5yqWeODzgv+_|;n>m!U -iyMgR7!nmDn{1)_e?JOZUHv^<)gmGtvNKgpl&K@N3B8=M^qc)E)?%ZlJUv<;Js5>BxJ3mAnwr-povH% -F<&TOW>j4&>xR(A;YaQrkO=xYZ}R1n6UeV0^;FmC5CwJ3yf=eLt5jWF)~34ROC%{A)g2;MHqMHDovOX#+@A`-_cwQu!=0UxftMW8ko(+027A@!5JN(){8K1= -WRyN*D-Qa5XS9Xrtd-+cWxy$Y=m*=CXN#F`kLE9y%J&E`4#+KUSIR;xrVTZtEg?5iviZ~4?03PVg#Q>LR;6NC6b_IDv2;+7(&>RL~+|FjQ*r^GoP)|V^cWxzhbA)l{S5d=875C8jYW^f(Z>oyXFkU@L} -xxvP8-6wv)d^mg)pvox5&)U8KRK`nHf5}_$@@*won)Y2^!{CGJ?LQ$aloHq}ko1W$a6u-$~NIzNDEoW -K)o*VRo1d2ev28?k6XpWg<7^+#prM>^17K$kou<#MMA&-bPA6wua6Dihi}sWRC_*r;41=12l -6J&?V!JftO@hG$&o_Ng!vI_hsc;Pe~p50$d@p?kKcklyiDDpFp+F(8_1N=9ceJEJrKL -ym;bT5`>iA)(Vt76ADX=FYHq5y>9sAH?K*9W5duGs4WOP$?;v?`BpF5rRFuc9anM*V-+FFnJi;P6+n! ->;NINQnZf{?BVVUgp55LCxrfWU>zY7{8~>4!LOrh388VY13gg*>D@W>HD=z&K!62b^KOpO?8f1S -}OLa>-qlZ0gRaFNDlk@jsuCCbKX-`uGygi4f+wY>Qi{5U+qKB}jlGj?SdbPk;(gc?5N%W?C&!;ngf<+yLA&JuzV>pMmWGwK1d16Yomp@q;C%W*T|EvF8lf34q42od4!!-U|3( -;{Aq<+zz$BttC6%^V=Zg5|iGgZ!3R-r>r_h>frevAol}l@KOP1N^s4#42>pQY^>K4vi9mQ@4#eC6?o6 -$p=fZ95=h0B#-5|*@HCbU^#B~BDE-U&GZ#A#8{4-o#1M~9uANUu^iV~b&3#7)F%ExvwX_mg-O$4vO`# -o>l~rhi{-cuZ9+-S3fYm+-%HI3*%2~_SRtc}JsrY|%TelISRv~irM7_;vd#%=*jOR!oLor=HaB#J5F*0im8uS5S!HwR;-**zn>$SU!ZO(0QPLNd!R -AiWcVQW9?le^c%V2Y3m1|~@Do{6L5ZOY8NW2ge8@uyCZG5GFoHXyh`hTqmd+W|iwSltOOpqF-+ -1>S03uFF|Nlk`-bJzC3JA}|z*)uRpY7} -cv&0X6YsRdw3ZFbXMLU2$vlX%UN+BPzvW=W0bT=uSQGS*m9o87yI5F8YqYhX!j_6%8MEUEFLdWt1A4# -K8bQkxy;YCvD(H1)-jns_`|QtPZBe;rF|;tXL)t+S7u@}}88Nw(4~sjZ=T2$s}j`idpB&gKz9a8S0A= -Zz(`&Q=;uu%y=6Nd^&1YMq_?3Bf_(S+rSF+e1phl3Is$P^VZ@>kRV`!a*6PF#t|L29wGkE+^mUQG3rlL^lVM4%GeLeWmej<%!YbF?dg{wq<(k__%?7JnbHmiXu*x-eggOycx#o^iv%xB -tI9^!gnmb9p3s$*gW{*{_If_W8SmhE=F6+AGD#a?-+$kCYu*xO=A6B{M&QfE;Dwp_wW|eD#zRRw1k)1 -cIT!S>UVU=rsH93@Km1`G8BCyIO4kcE(B+k<^z9zL^ta6DPidC-pcSv7Y{&Z*~`EBM7?6YLtu+a6*3i1%J(Dls(JxwMTY423oj7yLV95t5ig<_ULjJ!uklL>5WnRm^wx4BaxACFa1i6O3!hygmKb(~ -SkV*E5{J_+s?)FyfOT8vDgTBEBhnv5AO -p3SVp?;??xURw7Qb=M( -Z~9#DR_4dIGP3d6zyBtyv8u?b>O*k)l++1tXPv@OD*wynaTxNX9qy6wVB`Zq$pU+k3Uy>WBRof&kuTN -re=M;LUsSD0isab?igK6zdeQxq9Oyer!%ZBF -TbO@sKte3M)Vy;G^k;2D2KP7A!)uc=kQQT>`)5;k6aO&Z4Ls;`Ick-LN4RbPkmjto1fz8)arb^P^eB9 -J|~JlMB%kKggK|MKXU$B4DSzTQTx4R(*d7`utwdn7^Z8FCCVB(HVR?<8^+NlZof18RnmD6wzIeK-jdT -Y$a}O+%~4h~&%D#3IAa5HsSsH$be?wI;0|^L6*u5c7`Dm&c_pHN&_rb;HgQYk)~Tn}%^cQ^UBPzDs?1 -QtH_j#`Q$AJt_4p45NBti;rVePn^yF@)Xw-dwsq<#eWZzLdW>;C5G|egZ@tQw_{THr?to$bQHzvQC8^*ucHjH$OdE%F2{P!?V{PH6ICT5CXUX=Hsze`+C%oZKv-%J -dndSb@-mqhr*MFmb%s%XPuT@m{a|y{cjS_iBdm-}Cyr*GEHb3lm7kNM@KoI>z-(4P%*QVE6iowG89$% -MIi2Ya7Pj2mST)H()~P7<~gKl#bCiVE53yey%4bmX1+9F|l-v>WK|R_Xeb%HN&``b;G!x(BFX6vuPOD -Gc}Cs3H=R9JzIuxJ#)jjp3vW*)Uz;*>S-pJgIrH+Cb~Do^)%DZA^v;VPUIN>y~Hs7d(ht+`Fl0PNG{k -?YhjnupKG -##tGTex>CbSZz!-3ozzX1I7ER5#ykCwGs~R>+%sBh3dTe-dY>-&PFlrVxJ4v8sQ8O;D)H5@T>xm{KE; -e>OImY#D8^-l445ND1jmyjR#NH^!sGf+>sEdu=QI1hPu{}!NZ|sj!_Zx8^=YDfN>xOYXp+9lWu}8`=u -4if(*E2JW>j{%BZc5#_O!6K~wzwPEDW&cPwo0kHfxS}d8X)qet^qbMscV3^n7Rho!lc7EqGmdbV-u4O -;|(+9%J -KO^(qwG|iC9-_SHeu6%>BpFC7Ijs4`Ix@qhu57kW*v664d3>zY5?5EVl*iWg8v7b^GYd@(jh>V?VhrskNV67i&McF2;V!d(fYR8nDYrLk-yGq@e~xdo|RMnvj9K2mMJnA+;d`e$R#s_! -~^ffaQq@vxXBg6Efi6#C|8o_&1?H2{mLkWI*4LnUI0}y_#YC_nq@#V}^}aI=9EpE1lb8=atUwvGYou3GBSmIXV`YbdHX -_S2{<><|}nHu=&a{`gSZ^={y{puXG-cMJ>n3(a6pGR(>-xjK8mC7=Iu1Cr$_!#2n-AgRz!@zirl6_&s -DC&_NoDX*x)^?PP`Dvx6Fn$kOye99ZhVgqCa ->wL7v&tgxVaUB8@3jr%_s|Q^(0jRAT5=Ii)|CRZi&-!73-eXQn -Ljo>}FT_so<<-h=+6KbTcc=?`X=)Ak2)u^0WKHCK_w_qukz*mid6C}v4jI-glmmCk3DRHgI9`BQ}1eu -^-QQeiGIEUD`EVM$fojT}p=;!@;TQk5m@980P)N6)dODs%K4OR6$Q&nxxra;Y@B%catMid@pCd;|2y^ -Wq#!s$U+vx0aZ0YtIw8@v_LPHs;PzmAq=BMjThkt2Q>ok(In^99D^+vs&1VIkz_rv7V>TqQ2HXXB6L-Iidhr7TJp<{fYKM$ts}1QrUB -(zWdY@1HY-3Sva;(uDl5CvBeiM-+be`d0i`;d^`3s!uUYZwcm0T3yIt4OFA7#~5Lw3{GA=Vnc2P$gtmWd>ENSeJPew -vu<70p)ki`kD5CW)@I>*Mx;iz9?8}kzY33Gu6VS;mApUH&}0xUk+AW#Hmh$Fp#_(th&g%W~*k&yJoYd ->d3CWl>D-p%9PX@HteGIk2IK$3WW{3R6M7jZ9MZUWub+JtK -)sL%_%pL*M-6T%X7r7B>H73F*oto5$9&FqUd!V#9;d+YMdhudvBF{pQG5hiN#)&O)2?8G`0e|SZ+p?MsI%5a*yF*9t%PErErh%*eoVlB@-qbdCx4e -f{R#MA1R77k|0d9cB)G~c&^AID&?Z7Hpv{DGpf!ZrKx+vVK;b#7Hg<(ST(O#vX^-m&A=|}@^@J)w8we -#p8wpjlc_dyFKP2Ea@goBMfc}!-4G_w^w2*4I?pW>K9jhhXvD&TIReckrep>C;>#F|4sh=W}Bb}q_Kb -;zS)tgFc=v8kDsi7}Kb;=rg)igf-^QQ4pL&uirzX<_$DE}t{es}VJCg67_|1AOE=>Cp?*UEn-;I;CP1 -iV&$(8W2fF8-~1?V4sdXxDtR|F?f5;+6j&2zcfHM*?2?|BZm&RNStct>k1`5M8>rLYUb{PWGd&d6(Pu -1do$VscRmBcD;tj$Ai;m^otbHlf12Mhqd -SFAosG7>oN6RuHWP-#?Bt?B)$FUo9T$wxh`&~!BIg*_zU%%td1f -4u1NWAR@R@YemW33y-pZwPn;{~rkWvG_j{@HYNG5%3<;zkP>@x9`so@MGk633$`~p9%Oe@^1-vtNuL# -zM1?T0q-9DJpu0={X+<_52S~HZ&ncj?~}&_ycw+!@cwv0z&Fq;0YB@n5%A5nPQbgY4FbL~Hwk!se4l{ -V$A2N<_3>W`c&Gmd1pEN|j|99vLZ7^dy$|%?2zY%gCE)e(69Qfz&vx@L7yo*@0vku3qw0C(KTp6b{{; -eG`7aXi%72M~SN<{re!~1y0^Yv8Ou$c;Um@T-S6)I!Lu! -2dQ@JAk}Uiq}r{6RJ(PMYPSwj?bbo6-8x9O@JfO3%KuBi_mBTg!1s^;kAT<5gQKCBTi}w52b62M!0s7 -xMrtOiw~mmB>a8baqIxR{dCffR8z)o)8YP6FbMFB{2s-y3B7`Vx?-4?X!uB2`geYw92||d%_VM3BAgq -u776M^?{I?K=?F;8I1rB;Y?3*BjFl6sRLeN+5VM5SX?@>a~SMPB`&{ywCLeN+5DMChHX9yX6og-xQHA -2YfYmAW5*F{3mSMOy)&{ywOLeN()HBp3G9`=T}eHDnbJnVg!5cJhY-2vNt9`^MUg1-8wyW&vyL%I;VX -qf)BhLGuBYY9PLedy-ofiC{#a|KS1KkOr$f;iH{z72%XIQljcLgVOrn~>?u+X$J?ypxdW%zFr#&K%y~ -P&7?v-cQIhj&}%|#z9uEX&MKafTn32WCEI|agYgUn#MsUplKQh8N{a17g>j<(HB{VrqS1FLPlR?IGRR -ZWH_2eUt}GcrZev%WIA(rLr#&Fggp=vobF#iC3;GUuqA1F@I0Xmh-@`BBTWy|IF4}V^dKn;+mNQ|zVia1&}q8!slc9~>3-5-X7ok&Gc -)=cA_RTWEj&eL^hMnff!FE&)r6q0elp0J(H9xy%;<~!uFU9*Y$SI5O!t$G#Fn4wezK9+?=#)Mi4gSFz -nKv9)lZf+)7;esHt0+bknpfOXL^8a8Mfw350Jx!81(c2nK^9AnI0ft3_EhB2gm}JY{w~ZPDERaMnFAb>o*p2Bi8IpE17r^J5=)gES(Ay#jjYcSGO{N7nj2Y@9mtKW$qwX3)?^3 -r5?SX))?^!UBWtn^xsf&5hFoLZ1x_UYmYNz?2YyQ}4X2TROTup>^VRRjs^Tc}Z>gPOvEjGWIB^X50na -?zy7*h*^znnOG=5;&;=v$wX`DTNFi2e*M~@#2QkTZb;|GKPe{WyX97mEK`&Z`3u_qg=%&dsaJiJ3zWu -}?_fv%$&Nu#ATOV4PeIdLbr69mcT-XK8&1e-g!Z+&@(cVb`JIu1~U;tfAR38Fha+T-)XJK&jh9~d5}i -i*#_SllBc7YOPp{nrb$fWdRefBlLExF#ASlEGjQoe0`4jO^#_!k?bDqLu2dzfZ1fK^jG5yRa~Rz-L{I -Yktb;n)d(5mUI?sHbn!m8OC?M$qYB%l49sAlxK;+o=wVklG@_YV49Rk0r-r;CIFu^*aqMW0+TSFFBuHu`HI0Xp061UK|JRVG8n{j{t$yfJm(KH7{qh_2!Ux3&-pn9gLuv#WiW{6{4oZD -c+MYZFo@^;2?m3B&Yxs3i0Aw%27`FcpJvb)v4++tIJ9PfVHLe5tt%V_eYbFt!JzLJE-@JN-NI!CgT7n -1!eG#M3s)Ho`flMGgF)XdTxT%oyM?bA402&%k-;Dr7H%*Y%9*9!VR?z+2y*$1i{D3WrurXRJ1JZ`Jh1FDk5WF9ybE76YR{i$U}h -%ywaA)Xc2UwDwI!W__l$yDZ{Y&}|nQJzrS8R5ltX|rAM}mv+&wJ27_66Z9jv-E -WCDr!C+Ojc96kfRke1A!C+Ojc9_9nRke16!C+OjHpgJFs#-hBV6duMJH}wJs#-hFV6duMJHcSEs#-hA -V6duMJH=qIs#>FMTX0Ex2cBUtjORRqVLZ<=7{+sf!7!fZ7!2cip20Al7Z?oV`4xjDogJC?cG8o458iQdxuQM3NleUt4C6_=yKyLitUY2djOSwp!+1Vn(3tSX))YRrmY6&Dxl -+yA+St_A#-_Fwj*Yd{*m+=&Yg!A(#uAWro+gWG8lqG)vOaTUO!locSGLw~Z>`_HbL5q4THn6ojdM+F8 -_*hyr^Ipy6Uz+S-jW(MjV)zY7%wrq^-H|a=?bF@1G~cbEw){uVKQ}HAFn;OyWXhT#{HRCR$P)~(Q~ld -h2E$+jH8((#-ce%a--)HgP%##82y=icG9_KYqT@9eo;ynThPLB*I$#h-Gb;*V{l1QBWaVgiFam6Y7sZJh-*2SU17Y}>;vWVm2^-QI^ -DxYgcGQGfR!0&r+l3v&{O;%otoU!|Uz}tzTqJ6nmNM^^1n)XBrH#oZ+s}`t61e)D -;?oOXgx9(m3b@fxz*12GJtNlvsgED@$}Ob8toiw6Aab?c#^>;08cU42Hdp34k|<#opPCX|L*)fF0xlyYc&yER#r)?`&0$1%D>W1=oAW6@W}=aaV!t(uK7s -aDo>QCa&h%d|+U%3z3PMI=>g^rxkJcZFt6;}?w$Gc_3-hE1~bT5hgs{i3n8Oc+~Bxp913^LC-J+#Xxe -92-_dvh%(@s##mTR9hKW8&+;oTN$_W))=m7_2-UQ6xB4AGqqvmCbe-;xGOZqklJEhZN;dz@~E~JeLFY -eM>UOn-?{%js%iap+AynidH#rNT3Ot-#xH7(86n -NexSgrB(Mg9s?$2~+WL#Gmk6@{_(MjDfo;xy2k;{f@{Ov=lokMSo^WIu+`^uO*d}SQ+@Rj@Nx6=Y=*I -!c8wZKT5t}qT>R~So*zA|J=Ul}_}Up4VS;44F!=?ded^_CayN5-)3N5+uR6&k;2!8`z07%T$t4ufR?t}<8! -;9Uks0r(Ar;{d$JU>$(>8EgXZ0fTJ-J|xhE@qEN!7|+KHhVgvDU>MIe2E%whWiX8AGX}$WK4&nD=L-h -Ic)nyXjOQx`!+5@CFpTFL2E%y1WiX8AI|jpezGpCu=eGn}BV$v>3mZ{v0r)&y9LjVEOaYZ+VA#$tbDefua$;)!}>nL=G*yeSzaK0cM#6~ -@14lo(5ok@eiu$lAV)#y*bw$l5@3h4EHnG&Ytqqp{(>jK;>2b2K)VU89|Y5M1*!m;ROu<8@PQg`*xAl -XPwQesy9ze%KYpyPrAjjaM7rMi-Ufw(Ea~_DN&Dm~&#nNjI6R~j0Xo^Yj~ ->Ke2V-1QflbS*H>;B|%Z3aL&4@#@;)S4I>90qfe~*H(p^Kfwr7AZGpWDORP{_#}>H@F)U4DXJ8E!F6K -z;I-ui*Qv1-t*u8W>$Ej;%rYM99si1J8q-p@aW~o-Jev4RM*0l+dq#TN|B8{G>%V5CC-^@w(yu`Nk&% -A+@lTBOYmeVB(l0#znUQ|g@h^<@OOAhKq-XKJG1Alb3r2e0{yQT*S%1q&&(Plyf=3O1&qyDiKQPkA=S -xQV`23NPK0be9q>s;kFw)28&y4i(`A6(;%ZaoDDF08j^c7t<|uAAWsc%{Q|2h{H)W3Ef>Y)wZa8I*;)+w|C|=RR9K{= -2n4@?>3v(3jXJL-w^(@R$2pr5&s2j{tNE^&i=o-vXh#JgMC>qRB$QjI0Xc^2=2pP;#s2I#qNEpmf=oi -dUh!@OJC>P98$QH~|Xco*-2o}sys1@MoPnV>A*Iy&D-He_LoDdL2I3b{ja6-6vOWYOqJm6e_2Ew@j0f -ch_>Idfnqz}#o=pLL45Ir~-pm=aDU<<{$fV~sv0ya&Y3)m@fE?|4axqv+p=K?lDoC~;Wm2&|%t#U5lq -E*fX+_TELfNNGc7jVle=K?NS@%}altB&*SKGmIg0C5nWMN}l{t#bRhgr>Ta`JA -t5un!xLK7sii=g5qqtXl{tz_Rhgr>Qg;If@6bn4@^=iaCl$u9%~E-ikSjhpm{Sc+!eFipQ*&qj<)OIf@ -6Yn4@^QiaCl$tC*vBu8KK|hpL#Pc%q6qipQy#qj;8zIf@6Vn4@@#iaCl$sFw@@p&Q*H+4}t(0F|CBM3Xl3(3G$**ppUfn<`uWq1}S2u`H0Ca^)T6F^@t-67dR$Zc`RhKAf)g?+=b%~NzU81B_ml$fA -OO&eW5~ZrTM5(GSQL3s-l&b0yrK-9_sj4pd>3W=2oV)%mk?j^J_0}ayy>+QlZ(VArw?80CP<5#iR9&h -BRR?$KH;gD%)ul>Rb*WNSU8+=7mnv1&rAk$GsZv#4s#H~%Dpl2`N>z24QdM21R8^NLRn=umRdtzCRb8 -f3RhKDM)n!Umb(vCCU8Yo3XFNUJ6)Hj1WlB(WnG#f8rUX@IJO*F8q0&;_P-&@dsI*i!R9dPVDlOF+&$ -f1jN=9|Ysq?N-siAJD)KE86YN#73HPj828tR5h4Rubbq0V?lyDL;esB=mPbxsMP&M6_(IVFTTr-V@Fl -o0Bi5<;C*La1{}2z5>gq0T8G)Hx-DI;VtC=amrZyb?m4S3;=sN(gmc38Bs_A=G&#ggUQ;Q0J8p>bw#{ -omWDr^GXPHUJ0QNMh|n;D>c-4rG`2fJiFh^nZFh_GGwYpq -Mtu9wmtIL(t>R|LRM{}jOx?Jh4u26cbE0o^q3Z=KY!q8i3?YaAJ2kDxj#9db?an}_}+;xQ#cU@tKyFV -aGZ*_2$I3Wrpx;nT@oDhXlUR|M-S63+I)s;$lb)`~XU8$5;S1RSz!BygfD3$!`N+rL#QpvBbRPw7UmH -g^TCBM2-$*-MA9_x=P8fu2S-=tCaleDkZ-l>F){C -BM2#$*-PAX_bt5Iex{;D!-AKu=ZlvT_H&XJe8!7qK -jgIkeKD8<$flw#`#O0o3=rP%s`Is)qxCENN$$+kXG -vaL^)Z0i#x+xkQuf%S>fZhfMT!1_cTf%Sk}pV`b3GoK2@TxPt_4vpDN| -or%L(tsZxG@s+3=!D&^OwO8NDvQht4^lwY4J<=3Z5`Sqz%etoKxU!N-F*QZMP^_fzBeWsLOpDE?nXG; -0?nNogzrj%cwDdpE^O8NDfQht4=lwY4I<=1CQ`SqDneto8tU!N)E*Jn!k^+Ton`k_*O{ZJ{teyEgRKU -B)EA1dY750&!khf4YNL#6!sp;CVRP$|EDXeht5DBbzz`5y;I7s_e%NoUMaucE9KXFrTluY -lwa?a^6R})e!W-9ulGv%^vN_ -2`dlf$K3B@G&z17)bEW+HTq(akSIV!?mGbLzrTqF_DZf5f%C9e!^6Lww{Q5#EzrIk)uP>DH>kFm)`a& -tczEH}qFO>4@3#I(}LMgw#P|B|_l=ABfrTqFrDZjo@%C9e#^6N{b{Q6QUzrIw;uP>GI>r18l`cf&szE -sMuFO~A^OQrn!QYpW_RLZX}mGbLLrTqF*DZjo{%CE1K^6M+5{Q62MzrIq+uZOese;zZ`2k8I4V8}Rn> -tSAfh(4;1!G|Xd^+EWs#!w%H4^J8D!|>r5Lwy`RJZGp6#E0k?^^y4Sk|3B^A8^?nElqd-JuqE6`oMp9 -%}wkh|KSZoeds^DWvGw+hj$G1vH$R%p*}l5e9KUup5N_ds3*sF`xq*9*Z1W3?f^qQIleo{P*0BU4l&e -|bjbM=hc+EVYQf@YEvu!c>ds3s)`TD9p2nqj1k6j>0~RI12wP;wTKXh@ -)`OB96jB`|I3(#`G8q7cF7{Y_urM@X?|l1|u!%-$qBJ(OJ~!ENXNXH9CtLokfk#qDE&?qqC^dS=8t(Y -IGJgI*S^eMUBp)R%cPGI7?p1dBcq0b}~Y`HJWZ>nox! -yf3D24)crYo5THL`sT2|n7;Wy1}ujG#`MkMfH8e@SYS-w93B|cH-`zv^v&UdF@1B`U`*c}J{Z$ChY`l -~&EbSGM{^in%+VZ<7jra+<;5J$;dwDfbC_Pt(HyQ9b2NwT6-@$pVhww=_}%??^mOe21(Xc1&%BDJHQ=PJ@PT5qaY^qZ>)hV0mc%?dJQ@Mu8;l -4%Loa$`ObT(%?n=_rwna<`+XLA;0bM%P_7}FO%Ttr_OaS?st#6|Rl6&KMLUR*?9m~jz(GaWG4aS?st$ -3^soAs5jXj$A}vSaK14;mJkxg((-&7p`1HU)XXHec{VR9EJTBaTNYr#8DV<5l3N)MI41I7I74|Sj18I -V)2aQ^sonOEMfq>u_(+i$D$twcP#2(r=#L@7CD_oPG^zRS>$vUIh{pLXOYucEe7Fs~EL>jd*U!F-Tl{E4v6BKpERi|7mUETS*mvxvU1&m#K5Ka1 -!K11+L&t^)=OEut?xw1~bi(IWc7MGNRlYv0{}eN)#CWHaXqOuHyo;MzsG0^2Uil|l+JIgGm~A>hwN2? -2vHN(eY~Q9{6?ixL7JU6c?o>7s;yOBc^Lg&t#J)J1fIQx|cnkScQyuP*Li9hFk2Y^hVW)G1r)lr442m -O5oiowB7)*;1!$sZ+MpDO*}8`vau2sMJ|h>MSaCyegeVm0rWZzl##A(g{}S1gms{RXV{conVztuqsHf -=o1kzrf=Z!F?|D%kLeqDd`#cK<74^;9v{;;@c5X%BOS27c4PVmwj0wou-%xxf$hfh4Qw~2FKoAnzOda -Q`oeaL=sVKdNMO4$M+0w-IU0Ct%+ZlF1@gdKV@APSi#Q5vE#fGwwRjR3>tQeO)|df-x5i-}OO-hvOEW -Yd>!`q6`|cV;#wC3ck5r0?({BYl56M*80NjP#wIGt&2U!ARfLB_oCE1Ndc8A5 -^jrMzRmavJYz62aW85R`mgVGVTM|WZVaE$+!<-lA#Z1ef$66tyDP-Iqq=yaopjs4_CYQCppkvhiaxMjn^;$cF;rKj@d~!ex;MM3j5nB7qqt^cz0t2LjBlFi3gb75H-jX8+gMi -^x3d|f@yjKI10e~42}cv0fTh_K4h>7z()+W0r;4}B#h@12E%x+F&M`4DT84=p -D`H5^ErcIJYO&v#`7hEVLV?k7{>E8gJC@1Fc`-3ErVe^-!T}*^F4!MJilcyi0AFS3C@{xvu21DNW`xru`o-x!%>ihi+AySVS>W8|IPZ{dt_3VVchWdDY&umYPwM~=ioJw_0rSW@Wy23t2-ydPf7 -!#UQr%W2ZH@qv<$&%`1Np-TMI$2VkEU8YGR3}TOlO@y1lIdj0tPo^6O){M(nNE{Tr%7hTDANgI+*RBa ->eR@LDYF@BP7bXO8ETFVt@aN!$E=M>Gt}&|ru=58c{S9$8fsoyo1n&NMmfzWXLX>{j56N$*cEERIIF{ -*CXBTbYMdsFvpU@AQPf$>52wdZZ*{fT%ltLsg>*0%B^_kI<;~=Sm%1M&UNnPR_^6G_j0|O$#n+idNq?9Qc;uZbxa;#F5fhT-W -wD;4-1`#h29$!IvWeULn!nPq0s4C=yWY~x)#>>Sm+6<&>2+d3@UU66*_}Tok69}pi*a0srLq@&ZAQ2Q -K|E&)Ol3uy+Nt7snpq2>TD{l`K;1BuQbmq&GX9I16P{im1cOQ8D43ISDN9K#qdfqywVJ>G{Y;+@Jcg$ -q!~Wa3?FHRk2J$an&BhO@R4TtNHct-89vesA8Ce*k@coOZPjG5m -KDywD{Pe$!v6iZs|U>vUzyF#mGZPl!;nr-~Rf17;P!m{mN9sCVL>5otnLD`Q`8bQM!p)7*jkI*oJ{Ev -`}p!`S3M^N!2lmnuL=I*~1s%uC2V>^ndiPeu#89}iT*CwCEu+R1P{PO3F^|9LX_Yu|yYtOGDtdG{7Uq -@IUu08({VST*z{9}am0o(IW5!Od+&u=2E580l7jQAchGM_AO(3iNk`ZwgRfmYHs5(SkMb#nVDyj|=S>Jb@;huo&``5bv7)}8{V=R_)+7x!!^ -eBH9{IJRWuNdpUXma`lV?E*54;*2vr~Jn2=4i&-^+cK+J;_*~0h9O9Z|_rJaya_C7T@=XFgX5`xoeE|@!Nd1pRqoEo9Dh}tdHO93Hp;(y1V} -ps;(hDStd)-4+mM!yke{;%k=Fz#(J_$kDX_%C(HC?g!N?Ec)6Fc3fNJ`da``lcZ@NR<;5~%H9qq`V<5 -|E9s%IyO;2$0Vcju%#{G$v$Mom|V<5}&KE`^oY_7g$4DmZN$51*y!tU;z%xj(TAnO==Pvyb2AIq -ny%L?%a{FxJO!a^X2+h~FVjOvCJJQ!F03wdeHey=e8BViD2R=on+vNW&VhPZ%|_pvL5Z^%=vU#^(N4M -hzFX^yq?7!-t=7!F&t_3b-P#B$BTs#zNynOp7LIdD!jtrMeNp;a@nY8uvbTUcwf!thAj!irH -*Sf5#1HLVp^F|ulo42G1}Z!dGBKg-W16W25zr|Alfm1E_MXjay5ue|Y#s@$rX$3|;c7@yJZ3S*P9tt> -88MST9Zt*oA}Dx;SwtLLkc^_j-m=dRFLt5&sD(>SNxj;v^oO5-y}pXF4pIW~G}gl8uPjP%1%!bm@kr; -PODcg9FRZVwsh$7{z(KTdl_`tdnuq#u_HM*67|&nM98Z};E!)HNd-CA!T~9NDzmxk2!!H7jE*O-DOd- -TWOD#wYsIQIW)-IV#e)=6J`!`a3F&`JXnUCVJI%`opOE!$R*JV+pXAjP=~wc(so)9Kc>Yc#}bF!QL%0 -)>CZb{R754us4ih3$}MZV?EI(`(87KRoVVajA2!FV1=;}u+xn7tLpW$*BQgP>&1&vW3a6L=~8bSYk{3 -3414Iwp<9e$sdDHAV>m;@5y1ia#q-A*L_65x^5nm|$mnGHNH{cXFOF#P8%~#*l(1*9gPTc5;#jQ -S59dC% -rx)nvlleKu5Q+Iagkk$TImCl@#lP|PP -6n1#^HCtvX_2+@3U^#Wsv(M66QWb?^Y&NArclS`aQ(9I{8o)Q-9t><`z3HH`YyaK>6+{xFc7(j+GHvELIiLL!#S;scm0J^+YJF*ZZ -TVMaF`_YZ47L=#hHl%#FN{M;kvf18<#oVaguoJ#+ADaf-fr^2i(~%E!yWCib{t)qb$m6 -5;NrCI51Cy!6FhkqwG^>?#9ofwI49_HT04QuN+qK?5x{F>KgI4(SS&B=iC!jsp${J??X$s1nJ;l%LP-BV`?gcCe@!$ -ScM4R75%!IKou2G8a=DR4M=@|L>|M}XItc=E;>;H{-&yrRP?;H~8&JUQST@Z??ejYy|=OkkV@USHzn7 -w%7+ypO&QvG|r#6gQ|%zU3tku27qN%iChyp*G#mJ&F^^>$i9Vgd@o7w|EY#e;Dqw@=rzU=zhj)bIHNp0&T+>f<>|?&Ey%!|_c%y6r#wBuLo5 -y|Pml9xh?C0GlRRwWy++ehJi_AgwdrXNAZ}mVy7@5r^@!jZ9x8AF+w?SR3All6dWz=>T*0<}2lFQ_u6 -O;FS=$W(UFM@kf-dts)Z@mt=~<={u6&!$vk-(k-_}=oiHu9%rsrAY#I0}B^U>eo&WfeIJelF8O4F}+z -{XpZrdN3Oz-yJJmsruky>aXJcrT5c<0glBKE@4llf$g6;SRa!RbDgV -7P;wVo&<1@+-(1S#`*wmoaWz-yX2Khja?@+9li*glt)5l8=rZ+f9xL|I2Gx|Gt7fbWp+qn2`dXr}>T>Um(WZ4auzfEuPh>h#t)*o -={;sUtoZB}$}1>AI*GYOZ#O;>nVjBDVgcX`0ZMQ~e7m!l6w3Vy?s!EJEsk9ePl`{1Vcm`-ptx0Y`5&J -xDv^gj0*tj+bu90{14)B8M+!`_@e;3&c1oIYTx!Qz}gV1>R7mc4g*H3^?{>&8=7m|%5oEqxPxC4w0LL -~J9Mp74~6>*A(Qcw>zV3hZy!)GrTLmEEY#~5PxY?U#@@Yzeo5X0w( -7=!<`^z=G|SU5d>${5n{-HO7#JZ;msD0KPfGSTK;jnP(6YeDR7gMDQIqG`NUs=^gh ->a1qzi`%?@ehTk4$3}^H9a%<;2RmJbH#P%!0Qr&M}DC9ox$oVt4F3W5 -~Z-SJlh8@?C#9*LF)VV&7Uk$IS#)PQGRgR5`_28$9*%`W|B={2em|X65>89?oD$ZqD;a07G(fo{0iOa -&!JMW8lPDW@d2Ic7am}M{U>Na$3U3+&p)SF(O%tJ^qmAjx31Mld}vWO6MOj7D{_xGl-17$h3!( -xpnLP4F<;n$bo{FxpjNrK?bop`t~hjeH1tLa-zY^+`Phb63oo4+Xr}Zft%TZPZ&gQ-#&PW!C?SKAB*I -^%7Zq}>TX`;E{CDHd5u{GLvtgVBw%Q6vN>16(A?O^6Aui{jr}}H41++OxyB&U?FP?ua5Oh>l6X?W(cD -~$FdU*fz+=4&;&gGDK}?^w`B%6gOqVY+h=jX+g)yt~4nHA%un+?d94 -=&=yu|>v^WNW+(fSI_t#vFv1xcM|{3&z9S@1tLj70$EhL-F{?30~U6Xxx0ka~h1s&6gY|7>%2+nAI>E -H%{ImIa(mWXxv&p%B{g=LmMY~poHPLwR}7R5yN-9gn;9?wS0o7JXnsK?|JzI%W?DD=tKJ;&h|! -qgCH(1@K^!MaclV;M-iUmY#-ANmgCm)g{W6s{2@=yMX=X6$uk8^$Bonc`(ZlH_Vb(u({Xn20Aq;a8J< -O8I?fJqECSQo#%_6P3h*7AG)iLghvRu1s01^(#9dG0s(qq9rA8-qVOyTl=eKRUa_RD? -e|yTsZd{L$Iv2ty1n^HvP@=IeIxosb*5Vho=1(c-QcwWoXXh^9$(;8ZmmR-gH<_O;z0yfu29E7 -G&Q|7EEDPZmrzru^wLK#${eqz^mN2!plu~m9x9trSK|e-|%n_uX6T)hY5IU_dBOyQSvh;c -1cX^RTVu`yX5~{>iC|XFA~OJH<<`nu-eAJ5+*(}Z^$qOG*$ZACz^|BVfpC*56kc?KON*%75vJrJ6D5rVB4d3FKON;b!La;vnnxiRmY>crz2R4G-Fe8F55w})1ttv)%Z+9JP#Bhr)*6{{DXGl;}qy2)4{sEvDTj3KdaMPGb8cz -QEzP;5Ikz4_V{N;$a{Yf<*8a`Ue({T6bi?!i08mQ<1QY-O00;m`Rt8gUZ+z -P60RRA$1ONaZ0001RX>c!Jc4cm4Z*nhfb7yd2V{0#8UukY>bYEXCaCx0m-)q}25PmoKe>mJ1J9zHc(+ -K3DY+)N?TWHgVGD8J*J9|NSIOPSzH-buondrBB~?cRGVwHC%4zus7|S_i@x})j_d&Kuugp; -9ak@f#6PQe5|oIHb7Is?36N7Z24%`LytMEd52_J*T+#Dg`}dRNdvir^;;V*P(E<2WU)n)Cf}|;tu8)% --K?%Jm#drg=O5pb43u_fia=_^WvhO^y@kaB-p%6(?9X#)nGhALcN3wNwNdA=m%X*B9Ii(LbsV7}3}=l -Vf^|aL)E#a6e}i(Te1qW2SiIC)=@*c%Am_dYTX24=av-CTbvevty93i($^v+jB;IgXpsIVU4V0<`CL1 -_tZVA8f7>4~TxNcz{N`*~TG6X$WxQ>%-K<|X5V1f_i)ntf!3m2kL2c`URKQX0nX(?VC_H -5M-=PV4bUk&VT-a|#o&e@&V_ksr1#b%noa^Xkul3C?J|pjKVa46nH0W^g-1c5emVlal8h({#tgdC%*e -K+8cW*4S%3xOeI3S7T%MU2h{k?;HxA&He&VO9KQH0000807zB_QFJE?La&u{KZZ2?nD@!dZ&dkqKuvO47)KM_dQ83cvFJ*XRWpH$9Z*FrgaCwzeO>d(x5WOSuA4b^=k+ -S&#k$S00q+T|an)DjEcwDSCcI1zw`S&}<0UTD5b~%9Yym|9@el&_X2M2v(&F}iV!IPIpSL15ADGQ)$u -~e>>V3~Bt;nGTl5PCkTzt&}u2!8GM_2#w@9lIv{L;%LOXu-EkgA1Q&juEMOCT|V! -D&T4YT$uLY4K&O*Eik13tu=O)Hd6E022wkZjIYN}isH&5&3X<(pxp+gs@b@~gA>8>j$QCO@xna&*M_a -J9rJZmSbZ=Ruufthw3EPBeP&8>=-gLtoah;5%HMtL{two@F`$vW;3Lxyc)^oJvJE-ed!VD4xCZ0OB5` -Jwrwo>Bs=vKunKu(E(=mcTX8A!4F$x$rsV)`82soj}EbUt=P05k7@ENVHbi<#nH6AKWH|H&~j)<0tA? -5Hs2yw|#!0{-x^v7f6P>IzIihM;ANzNcYUJSV>RoFV!?D)-O(Nu=vGDCf24gVnG|eAVZYb{dpt8 -j`qrHy)qdUx}anB4e2c8_k{m)wet`Bzat?(!+y~#oZaLQ06k!@7~Me4^T@31QY-O00;m`Rt8hRk*VAc -2LJ$x7ytko0001RX>c!Jc4cm4Z*nhfb7yd2V{0#Ecyumsd8JrwZ`(Ey{$3#e;pSq4lsc;H1Zi!=!-lj -SI&49TC0mE0P-vO9waJt#QfZv7`|Z1b9W>kLzv7Wu^2<9=10#D9?jEag==xlLlq -@LLbO^ZsRF@Pe5SH>%nu$FOEadpidNNv+{o&)O0!TMJfeS>e-2?nZ@pWdN|YKzVxGM7-@{}AL!yZ0fJ -EbiM}SWxRG>C%E|JN>FMWs;v2gR3L8d}nzeoh?<+0=)O!zrpROzO8ZLyYSd-Urb<#@QBQ}MfyuNC~LR -2oe)#b2grlI|hFsjbX-teE4wZti^;Gb!Qaow`EvoGOk^uUPB#p@&)EB$xGEw@}#Yl?0ITb;>0dN}`Dh -$WL?{^asyhWlQl97;#iI6)v9Y)S3qbFsN5%Qi*+hFqe+R>7okD+San@f3xqLtDzpMNa5fN2)R3O+_^3FjNNOhmt=gG?gg&t -b)Jd4}Q>(92BBAQSrIjZt^w<>E5T&H~n1%8xF!xLj2svJc~VCc^QJN&=mO8!fF^r1oHzQ%?G44{0rZx -mrdN@~}nJS5}!~)0mIpMWQpCV0TC(OqS$fBG4O>Czwcz@16;5DKQ9SoG2LtSd{O21sRo-#npRXuZ>7V -3X>{%Jnxs9`nH;hZvz#zy+)3R#nC+nW+g9Axbcpj@tUP9TCSU-A(K8?O9*Ims%-On>;Cgixzp@PhUGN1{(JkL*pXKmY8!Z~jF`MaB-xNzX^ku -;n%u}Xk1&cxVz@|NS(JEU}%15J7Q2h4*Uhp}~VrmxP*Q~rq6oTTSa6rqH;7s{ENt=;!H3&_8Ar_f5uA -3M?fpsDyy(FYp%k8e#Wx!!(%Yz-P)L6C~%p5ZFbivczZPE($m*}%I)X>?j($VeHW;=s{4~K^^>Q-iT( -)w#1z)t!<}Dq&$BZ;7=YkW+{aLG1t!e-he!$ezC)F|14=g`wTucLt_KyP!9UmIEzod-&eTR1Ij; -T_7>xfQk)Qees0-s@v7Fp31elX0^=P1n(97%w-#>3#DHZY`!Ro?Ge+^)}>JFL_*3^t_>nHj}3(9eUn$ ->#1}UoZo?e=jYGytK!*ZTEX`H_i%i&)ylzeyj4bjM{r($&{o@W&Ec$k_8BQv{xw)a92kj+^`0h7Ia4J -Nj)#3XJ;7p6VRU*ljg$se0UEh|vJ@5BYT>o^T`TT#BiuDXE(wc@HnuI?>N3=f``2A()fJ_o(`S_)ig@ -|(kUB3~W# -PWWdx3vHH?EDR$F&+jgYS8o6oaVT01Xch2~9GADs0EYwk&-3D#BHOh&(!g?8(-<9)svzKTh~>UvTRB= -M-_8~@Zic_zH?*uRVJh!Z?AGz5UFsM$KH3*Q0deMW6!QOLsD6#mc_J=!bONb;3t`9Pq3uR1$A` -1%c9qOZxB3PbU5U;kuz$9Rhn9A_y)EGlrnaxOE%=u -(=`8bQcivPA51%#fK61U6%mFJ@tE -Y+_+!Yc6nk?LBLA<3^6(QbVu8-?R*wpgZ|y}!$^l9)yF#f;B+oQHV?x5<>vv&#jPYPDKlfA# -fO(=?g0Ntp9InsY3jq`)Yq$8{1mGXR<#%$6n-**HSe -3o%f8}M5^T*lEjnQ+83PsO9#G>k9t3H`kf3T5*^q|E{L6KijG*;7^dTXudqyJJ_-3B6uVJUiv%CDk}e -(c@-*t^Q(=dY$?=ki&x#0k5m&$yfvE(K;A?+`t*@UM>r7V}dNlFz2giD~5D& -{w{D9eK@5=BukPwzD9jB34+fS#%P`*+ZSY7!LFz(D{(RxfgPLKR4K8bkL$JO6O<_HV(5vs3u9e}3}%@ -aPl-Q}G^4jAvn%70hcVqu=>B*ZYh56uKeGgP@)9*%U--IBK=@GNh@XHP$1%u!h1Enl^B3qfBR=PJOLj -xLELb0tL--nw4nWU}2mTWjAOR6j>gUG@Sy`ob!2--hGPrja`&lMuXJLlM(iE+rid>hULOE4ezRe2|za -8RlG3?yX5(&aJCe**$qe?G$7Gmj|KLN5DZiq*EA(c3>gPC3`?m}xasNxFlOO=GznQ2{gdyq-#&_#30h -BR0qB3JI?L&lr^n0Ltjpdl^LJAi)50!0y3Ny2{5($5c_>r{tpS+k!tyGhxq=4O&R|sOG8`45N9GIB`q -3}JhkrYH56JcD=HT61p#1#cjFH8KC#Oeyhr!E5rwEBHyw*ec(=*?V6;-$syUzrH^TPTssZIy~7sI -}(uT837S+=^m;ISaf%~_p^XNcl#%A;qHmNJNgCjd5X{vkB;}wU!Ota2j{0Bj)K=GZ%*jtU?3W$=)YVi_!a$7!qDu9nmj#aaL=52|O6(h8sor)NWt{yx>H^6_yEP8uILX0_Kp#qo?|eDSqfOK|CM= -*D=_KaZLW!@aIcnqoe9~nb8`n29Fw17iFC*O%O@y(8DjK^G^)7l!FHRA~j9pw5(tL5jZmxLDHbl`4Hc -r6(1LFbX0~8UKp=Z@DX>_UszoU4Zpd*=cyPl>vzKX~zFeTAMxt(_XQrD`{&XWYx9|qWoto<&(0{g7#I -rIt}anW59Hd&(Sker5J1+PAE&UR_g+Px6$<>>{Rg2R;vKs~Duma-7Yk1F4O3!VvB^YB*6T7ZHx#L-9~ --qHHhgwmUWBcw|C8~_j)XsIY3h+k?nkfVEHz-r}GO3yTmW_+@%bs+p)EDI5pFfI2J%&)G2(Q3!6L_#; -7#+yRpO8PF7JRq4w{cU#~f(nst182H=MQ&6y^$q^i`r=z%_PooUbxhAw04F2ThVgvVWy!FwqXa^6bi0 -^E<0vO%1VWePBs?>I8IJE{EY#Bg6>_AHn@%Zejz;Sd$WG#pqB?FOZm}SU8p0bZZW@Tfg_wlU~$J#iGhbJ4L{9VN*O5JJFNzH5*S9mN&3$^bI*+Q6o%2py|woFdzH1JYkqEQ`` -0s-ud|xEG%^ylH?6l+vK<V>Zo4PBezZ$@+=`0Cz#@ZhM*BGRYqzg!6NAKSqyt4e`EvSI#vG&_APO>IdwxNoeFz -FRDC#-#bcF=(+QZj5yiEg%BpchGFncHu|!wTl%BDm&vZWoqJ1xpdn$mp;n6@3Sy#aTE;iw**hmI>fM4 -S?8T04}qe9EY;3`S3wKjjo;aF2!P|55nSC8ef%=3hyk6g@Y%wKcleCr}3 -5{)hK%%&7(Y{SPuCsS_`9G8>%Kf)blwHp~0<p8rIk~j%?34#n92GF{k*h5@Z=SA`7LI^$ZgU -xIsIX##goSt7iISosoyG|-{4^oRQ_BzBHAZG%=v4S$nnj}M3!{H -k!HOytX)@+n)=t*ME=vGd1DsqQsM28YpcQnnER>))y5Z0O_>tpJZL%^OTb5q{(FczAP}nm=Hv+t`&Bt -bx2-Pfjs~F{H)+0?16hY_z$=Ly{CD+67r!i|?GMOfNHNjQFJfs-`JqZZWcsR>37cEinq4POj8?u)|sy -RW3Rc3(*ATE6I*vm7S5D4|I4uC1p=p&@IDj%n$Z27ndvQ2~c0&;wL<6i2nNQt-=NppXVdxvXt7n)R&% -h*=b5x11HSB47yA!4uK_;FfQ_prmA2QdLikoZ>GFeY-0IUmWczSebHt$PxgAG|ANqDz7hv0F0l}31y2 -Ui-eN~m@m^5{4(%eX)?hFF^I&>xdur@1%<1R;ia4;2+`}~DKeuAoXKxE6vWt1gabJmo7=qI>FUt%y~J -IbwHDZ?4C0+hiz(wcyX%q>=hBzNDWmXO4?VtRCt@t`O3!lwVuMSSi$yfMgQ5E@0Xc?#$Z&=KMw&Ejd4 -q+yjn+5;{y_LOPiTUti`B@v2THCvhxj^07azI>!)|Kp4$Iu|)I{xgnWABxCn+$7Y_UnTHpSS^uR_Fsm -uB^ecNy1V6{rKZi=m~1k7E!aL@iC^W(KVhc&t&R!vkZP6ILi4*ym!^Vv&d`A*eCQe8Q#|vqVH{TXoce -m-QBxVA#e6+s1i^fdNZ1a<~G&Iq*O#-rH~;NYW}+LMq;`gjAT(N?2NnmC&T+t%Oy)cR2UskGOhefs^* -S5?t}#Ma=GOx2Ni8DTZ+N(qG>@^{vmpmk^YR&E{Z0P>LaZw;R{Zu4u2UKh&_nDV->8dr|7L!81ATy3j -&g0>c@mHvDv6o1TR#X+Cu-Ipd)Dz$q^MA1o+;I?C4Wv!90A)F0ez`&SusR+r@!tNXp)w#(A8oYsb2sB -ndFjamJ+3u(R<6w~f13YMN%S-gB^S5mGLlvO`{(rj7_dFK^-(-??5UqM^bi+f*TQFSG-M#d@YC|MF#lYk2*ARxa0;pp~Duif;O?@-4%)w -B+ERRA_8JY$MHZ^?{yr^ -qs9vUCkFYQjWsJ23PPOxKzT#@LN7!=6tB{-PP?2jN~{^YwXD_-^M}`)h&3a@Bn?@DoZ@jI6ktCsZL{+ -J^f*5O)`zxUs!)M=!*-dO>DsxSdH{~=Ca;kP}VE%yZ|E6$-A{c(GyJBw2fj(*QT_z8vWP14A{x0jZXsmIdc6@x$oq$R%40J9CHq>#UU&{sB_`QM;zIE}&oG2 ->$cu~A;NbJfkuP64+-uo4#x(oA-36)iSWXe}Akx19=fnO&~RW~YZc`IngAe}7vspRt*^_3~A#YjCt{@ -U8P(e+5^!{;XVmc5kjeS^=JBY#pI}-Su#Ie^k%mb%pk|!CrT#Q)BkZ -ss(#rcU`zE+55VRy*mYa2hZ-y-|Z&+efjD^4Bq~;GWbQo;O(vZGWcmD2A@2L!B79J4Bqp`OI4;-z_mC -xeLUl8ptfI&+D;SHCJ#hyrvkNuTGVVWN$-sZ`AG&2hqXA^R@=*-M|3s})Q%o5RF61f8>k&WT&Vv3d4% -fF4i%aRm5JI46Sfkw3Q;?>_fyW -lS1FfWf1MzjC*l$ -@N8{14xTr)iO(Ly$iedpPQIv~#&IU)|G2ruFKzZ;@Xn6Kn)A*c3EOeEv$nhcu!+SllcjbH*_@@e>*#0 -ciZJD2vx;9POYPXVe!=OBlhZ$B!Ao$?j@Z}X+!r8@e<0`TCltN_sruhqTeQT+SoAbFRzJ`21xVAE!7= -CHoM>D-i;C%yuH)n;W@7)xE^zm|TlCLH?zS{&s4HDAPr{()TSvO3-&UGrwE;!ew>Qkl$JqbA^l|P1LF -CFey8UU?7e}`XKE{j$q_p-KK*@)A6=r4nx_Z2z+I7LwHgrvaEb(y7B-~@xLemmS?_TUe%(KPH^hyJ#dHFg*t?E!IJC -0dW8!cFEB2SFQI)AiI^-rENOD3{Ev|(BsqJK6s=LzCvXJ|*Etv>ffb$a)b$({!K+3VyABbRa;o=4VDy -Ar&U#dlSXR*TU;pjz?Vw3-i<5cPH27;3+_%p7p$JO2x -W4k<);D!aO4I2+66)t#Nbs;Cj!SDpA!3%CPu)m-WbQ#BKAiqd_#!e}lIl*X##d0~*M_Y|WPc3 -iGFLpw}8*X>DwEwM-a9)2<1VzKfAxPF-?$DIJ_BldP(%LN!Ds_`gTFta!V%%%{OltJGKhSgD_K^35u! -*gtveCEJUqRrlzZGfxr*c^;Wg*!%O&;g#dY@FFi=Pn_TqX&#G)>x4x+t~&It#%QGEm^vCcb!(@N7L4} -;^({|$fd+9HC+k4Am&v@4RjxcgV6UtgFq#_P^5l;?yoVdIyqzF-$?GEE+3BqdofZ(#hXQ1t^NPbqW_d -cu=ax5f!b%8hm>f~gbJj>h#xNB%iDg&AlSyBb#R)oH=yN%M&Fr$?;LJ?9jn9!e7`{p_>72{1qlLq@6& -{L1LR{^!*Q1#~UeN1%)v@85jRXS4bgys)oom8YZ1iZ|gY##LD -qU(R?yiCQ&u@T9GH#V`e4MBfw<*<1-3bRg+gPaUWZUb-!XOJEd-?$??)#d~!=PUP|AAto3Snb#*uh%l -QTCLE*mr5U@R!Q;Zo#A_uyR!Jd&i&M(*MG5>a03@cAW_DF9h+0>cIMxcTy!IkQBuf(-YI$R$uwG-hge1(^c9|6mph5fODw+9a}z

  • !`2YW_t+s%qfhXV)K)*RC$jy?%ino2Ca@fj)?JAL%o_(`2@v@VT`W|U_izL_0((WF}*0RMStZgmzGdSL9a{1DG8M&hYBM@ODIaHR1y4QQ+bC<8sO? -!KJKZ`7ZcC*{a5OUP|kK1wI1CV$pKIDa3;}ccUZ2cr$Rg ->FxlMU)@)uUN_%(DVlN*#!N0`}kT_X -~W}AD=6G~JPKdZNm4uwQ%~vfF|?%-`cP6|?!OYW9~N5U8)(T6e}fYmF9`Yt0`%d;M*E^9< -KlT7Frdiqi9dn@zoK=ZzfSPU4(jf{Q4=$dWAS<2kg*U2o~d`k4NSQ=iF?Wri<5U1DpRO2=He(B< -2e7Kun^7N&qG`>y=(WG@KfaL$9k)1KfpZL~v&Sx$rd_6t-?i%W^g7wND1m{G2w(!_*VL)~n+hWh!qDM -AC2qxH;7!<)~;y!x;2>g2NxVx;;c=;LwYjh6qhIY&O5I8l^X;Y?ZKGFi -2I#huOTsOm1Qf4mLHGb98?%nk<<+(C{F_K*PQXHS>KioAO!rmvKcog8(wa{H?gq?^F%f&U7Z*Xuh&vv -taOp;qErbryA~=!fXNe|F3=u>*LC|9s=z(12j@FkSO@M|JviSXyE<^s>%n=Co7KVFsexA?IjmMY88bZ -Zve!QKHCuT=JJMg@scffGYa08+FDhU+3Dao!ZC1BJGb%PnY6hsBh*;n2(S{9UKY(xGXuQj`1d6Tx7Jc -mMlO3DPKI7MnO!_G0s<{lJ1h*B?zR!v+hKd~mCT+r@v0FYgadkl$Tka*E*32Th;2P?|A-uqGqN7rg_s -Vsy8qZwja5Hy=6`P>^J!<*p9{fwE+&d}xpje`L9I+0b`cr2<^gw)Hy<9ZGbUw7)?zUbpu6gnLrWS@eqw;FPI( -5(ahkOoAEb$Dns;97t^`V^!+3ug1X!BF-H+}`=T+&=o;+&*5(?L&x*8Zle<5M$}`bysc|sBt4begejw -?dvZ4)WP7Bny7ZxuUEvHTG3CQqBf1%>~gI@4H}p^k0k9mlBAuFF}BvwN4uIEYwv8#;ft=Pv1-9>EU|k -l;NANSGOQx^5ni6ET`3;tk;q2u6{pVzdzSqXnuB|Zrz -XKnrQrvYr^A}zOzqy6yXZ6AVJ-YuvHR8d)|HPgJqRhA7u)c?&EpOma5h>4kvRWw^7e1RhqF`ovwwc_`tax!H^sgG) -d>>?+;T}xoVu2a9V^7Z-vg2esQW)qO9KQH0000807zB_Q$rLBMCq58A#4F3Xe?=!CNtRP>je -l^#ki;A{t}eK5iyD{&%49x@i5+~qGq(_A-P8|*lA0wO&=20+CZt>P9h^z$bzKJ(Ts=qbKr*_=dT&cdONzxN)c4w`tY&oml<9A{ed(2Ge$vuSfk-WRUk-30c9B -U0rj0K~fd{P#lO-D>ig;{!s>mu@}KuMdO2w#+>w+``Vij;|F26UGAiC7Qt6F4A62LNhUpugzL@C(*JH -@ZZnv}A84BV0#Hi>1QY-O00;m`Rt8gKc3QFg0000A0ssIZ0001RX>c!Jc4cm4Z*nhiVPk7yXK8L{FJE -72ZfSI1UoLQYO^{1##4rqm?}7XWv3qGDgwlHtee9vI^pes`DaK8djlqtBY!~wH>o^bOiQd)(;ivvCF=f=506C&>&`beSf`tG -?#7Sm>Cm=H9W1rIFUDjcwPc~Vra=t76U?uK^yDqvM7t5$w94@{-qd{0^=s)0C!~p=_MY+K&(`?gO;Y5 -&20#Rp-Xu}Z_Neq(K*etAi)GH9g&Stf9owWxnK57o7gl0p5S}+oQ{Z7b&z9>U^!UmBU-S%r9fLJL5@~ -}iEAwMr!4*fP)h>@6aWAK2mnY{22MmPUu| -J-d2DHJb$BjtdF@(RbK6D|es`7s!z^4$z$^qFq9j`tIgw?_W-TQ-mYt)tD%21dk`v(y4pU6Z|9!jX05 -AY0(VOhs(uqv~J>T^7-3{_6O|pXcNfT6zPrC-#S>zZmsvzW&Vx -G~R?h!pD-u84X#xpc^D?iUW36fC1fk~!ppMlASHrXh34Ws3aJ&>`Z+({^DDYFx=iKKkF32LIaT(H#7i&@^2nGw|g3sY{$q3E-B`-h>WyVM{7x%I<#uE^ -B$NaLOvycHk$&-i?pXMxg;5%6{#0nT3BjPbo6eL*3G~zxD!!?<$L0mLI7=&!{C&g0lgE(*?pXIqrJ}h -}ok{A$ZnueU=1)1`=ymQEE$^9iMfdjGpbb3Z4s{8bbAJRN09^5bH^~-#yy~A;$Mk3%c(B>6xHuEo&k)aB3P6dcwwlDBXvhO&NBbulmh3dklB}n8$B$)M^~G@v( -hy7K31Bgi@L)PQoT!Wgx3yMY0=aj7{AP0EU3@%$b^4whk-^=;*?4b!GTyI9PNv6KSGyy4I5h9=kKx{^ -y7&6{!|`Z(^~xX=H_ydQO?mF^KHrDy-Rk;k_r(ASYKr6c=Wt^@sBZl7eBTrM?Q5blB=U}5P0o+6{v|j -+I~#~ko51_&^!=Wo80_6caW=g?{@}eme*aq1;b)9=k}_a(;(0vgh3DBh3+Ijy^C7t3^=w_R{H8~CUXq -I>W(_UjsxnTge{0X9;t+jYkny-^P~oS@)~!2YJuN7(gFCrs`?d@cE;xjr^FJ7(_IllQ8OzHM_7fg|4Z -AtSb=@0)QUEnmj@YDy!R~yP>X76zG`ZCBP{S4EH-|5XwB^ErG!L?ya?1ghxlDEj_|Qkd5{7t<}Ne0&DW -+Sd%W+?*i+`FUR_^ie<=hcN9Drps -hL--a;XmT(@@MZOh}OAPVb96VjZdA28x%V-t?NK4C#KGN0TKpq2?Sd5^(5oWJ7D-bVve#x@xl -ysl%%Ce?EJ>2G*oH#dt;evVDUca-6?H*MvtVZ)CQzzFIRjO7OlC|J(|*B%x|RNk&w*haR4hm_dju5^@_SE -9mJV24Y|X4Ht+M@wlePj#y0_WRNU*7zlC{YY6d@ggh@WIMOiGt8y2CpnZp;c;%2q2@$g1Xvr5#25ZcX -BDh;X5OyHh8F$7xN{Wtr17 -0IWcq*Yse=Y767jvnDGbi&2;kW#5|%4a -7($-~+8gh{6~p_M}fSJx;EbzSFm)Tl1hJg`|fI@ohOhp(+H4|jBGuZA7(G9JOnar70k2)s~^e-dRXEn -rgS_;-@KY6rIk_pI>@1Iq6u2PsoB15M4rc);!oush;ov6{QDr&E_qif=$eAsA4IHW2b#7OpiMm>_6&m -L<0gxXM5Vc`lSIW>ByTXmPQ|t;!rM7W@Ns2dOm(Bl9Fc=JWXY=uVFdPj0J}9uSLEUuyY&tyH+nElZ?{2D~n!>TIlPmAd#YayV6y%w!$>jx9QPSB -#9z;nT#X&6Tw0ds+yry(!wRxNiduz^a|amNJ^&&o -pAbycmmc@k&HsfSwMa2CNQ{X}^vW}h}tftf*fDIB)vx^5@DcIrZPmPfrw80!|!1c@@7K>_|{-lTk?g= -LzKnoLVlL)a7X7KJSHhKU4D~h9uSh(?yuMV%t%y1(h;#pF)N};%6tx~0O#re&N6wsIeC|ELp4% -!$S$}J8r155c(TOzfx#6@O4ZyJLI@CzY>kt -LBE|X-qcJNgM(C38?p5mBbvdD{2W2O$Mfnbw3f$p=wu|KY;kUyZb5SHoiMYBbTjv&J`@B@CW-^&>Yy%xQcl<)&m|im3npK!fXNHN7Zp?3tpP@WbNWn*ipFbk7za`h579_)f2=_&p+$^Buw7M_h -)NOm!UA2=%wR1Z6ita11&h+c-Q=Rm%sljh9NKVf@;e@9xUM?+!)|MCvWQDj%QvG5?956{VM_e -I2eoeIrE*Op28$XW=r+OVoCZb1dPMs0_b$5e?V*^Jt5e?xso|(B6>P0kO+oH -M8xz*EBGBXuYK9a2-OjGZbKxH|h?ME(jFwvrd^pRvllA5g2lI~OSlI7176$$~z36grUZi>hjY*x<%4zE`DL0wuBr)z2l6c++ZX -GOzq(G}svphGTa)w0bVNVj!gD&hFmx=k00(2aOOlBV@_WEc^R+--+(y<@I3a#mzr^|8~VKJe0K(PX{JSrCTt}94Gc2Y9jYrBaI6*xStP|F`6{=_S51~2lk9yN7d&D=OLi -I$dz~<~Gj!m8!{EW-?8seYNtxP~V8-h8oYrmR&gv=K{-OGrf*WR~=TlHN+I=;RH7))D3paztJzihQze -#=XNXM2(G$#y?d16lw63#G5zdL_E^=Ftw404~mxO@~qWGhvuCeX6rr51Pv>0fAHoAz*n85QsK9L=D@({aoK6^Xd5I$WZ$kvtOe0yvs5V -n8Sg816DW(mGA|^@^{&p{0x21sjR?8cO1U8i6I|$p@&y^2%2vjJtNNM)Ja=9q7LCx)%{B;BVrn5>Z*% -f7YV4FtLSm`vk(T37w{tj6;LCsKHJyVB)_-%?!-fx9q*snTTn;dV~)c8Y?)?)cCCBYtjqa|whGhGf+# -GvVNZ8mfj+>(HJTB)ybT2Y_Z2yOM%%BW`-o7JEsXR5*kf>?{c$f>KIKR?5NmMee#V1H|D)LP3sl`5dg -XziFBw%NzenzIn!EntGo7zBUl`Ymw@u@HcIZPmQ3hlwG?Wq(cTRN@dLH<_1Xgv;Fy^QI6%6C3mH2G-^ -Fo|N6jMb`%QO&6joyBc(B5k4x$8WW`XA5cpJ1QY-O00;m`Rt8g|7jY^-2LJ$~5dZ)q0001RX>c!Jc4c -m4Z*nhiVPk7yXK8L{FJEnSb8KvBZgqGraCx0qTXWks7Jm1P|HCQsP_mKX*s+~dv+A^+I%`d{iL>$Si> -#p`5|mJrAQu1=DVhBDJqO@bcHPc0&WHqX?%%l}2!iX&Yq&VS08>|0sVzG^I6S!7NCQQg*0}&#RJkaGv -Ig>UEfcUMq{52Cg3Q2f1SGZAxS#Jp*GfsXhU=Z(lnSIdJjkWG7b);Hm&#ZuYLicZs}w$Oxc`JtLL2Fh -Lv2Kg8U#T=YM^M;2$E7+v9-BebxT>T5?hwJ=~l{0Xl_g0FZ6p_bg#zhIRq+IU5N17x|kZ?K)s~r$;@()3v3Aosbq_%vO3kM_O@+-%XLaC;(v9>bPyU;yHEizMy#4rR~z0Jy6rA|v$ ->h&?&d%Wf=dG`D`*_<)qiP^>$d1t48$(Rx1K70}RPpfy0C+LwWLL6ofVmg7~Sp21vw;<-$r;Fx|BP^Bd=uqXI7mh8hLxVoAL(F9 -H+V*Bx4R**?daRfTTxZue~D&e!U$;mE^V`n@A5j*_8DRqHqoRu0dkJg$OO>o%oaP{D@L0A!t9z876E# -gz9h$chTCX=X86?-kKxXdymtXC5`qXFj2fP>R);$==eHw@d?{s28EQwW1OK37*)0funiJop~IKnG3WE -J8=2IxkO;R?@OD`6-cq`0$}8|KOg6{B#264f(~{9{IP0kNDYgIfBgZVt4sha1pr?gZ(OA3xZ@@`k1t$ -z$GkF;SbL6s14sUctcL4RK+4AbcMV{9|m$|BTZtRcLi6qT8~2?Pte2F27@r6cmGE#)FBXL{zKKpqq*X -O^Z(@v!A7F?pt)L$u$A&0(L5k)kl(0?y93qW2ar*JbZnP*=sw0;e4#PU+u=i#9MGZx->2<*)HZss7I^ -to2wu9xe}|cVeG|{$-CX|rdJlpWBdm7ff$6RC1C53uN4OZ4nN%cYiVef}k=D#8VyL#P!r=Br5RG&Ts0 -jqF_+ShM9RH4OEw*~9QG@e`>0gp_V<7$)%KDG5Kw;l$+c+2e4|FMUYrduGzV|wxYkN&C3(MM8^`Pl?O ->Zc#?S9xwu=>nkp&ar^c?ebGo~U2*Oqr>2X&p@%MdUBF>`HttROq%M_y?Qp*JKc$lv -4C`mI33bpY3*l}0Ji2A>2aAvAd$No=*%YthDaOsh$mPz#GxTRzu(dAhDm?I82C>u(A*j`j(qy@h?S#X=p*UlKXaQp`k%$66cd%q3`kRPVo -W{gtr^U-Au)~IZaSv5hWK+?=P9gE)v -^$FL*jCIFQ(JhK8KBNJPWt4FXD@{LFTqVIbo;lv|s+MG4Z--+Hai-d-Kp|oY4luH@nk%`F6gR=uOmKM{I`|{hZ~nmkJ&)Btp>Iq^=9|x`7oF%{6bTX_aYfJaM9R#Y% -d@1X6T|vNPAGyaFg|r?g7^kp@jr8*Vvou5`nQPHay4c^CNfV2UC7O47qaL4@9jX=GG^0bVC1!v(Zip3 -~3g0R>og@A}aac;;)Vve+dQO0uM>FB92i@5yvpYW);T;Dj3Isv!&8}UGOOygP#1<7LookjY*%$bsGhW -7-d(x&d8B%7{kVGhyc!Jc4cm4Z*nhiVPk7yXK8L{FJE(Xa&=>Lb#i5ME^v9}lsjv~Fc5(EK> -owwEDkuPbPTl6M+$+EC84WO?X#_-NUkIo^6x9j4)v>pLx)1;K}f#)PC9>h0mp)A$QVbkb6QajoFynUr -cj9#6_^6SpgL)gnO{7VG_ljJ4vXLwm1a`RXA8KEZz7-~^>L4f=Sxrw2SmTQ+dggfhfPya_&p`1sp0kr -3QMV(k?QP#nN*O-Q_0aFq-ZGPI-bwmlW?jvY(>TdGw0*E#PxgzcBGgAA(o>E2{rO;39Eb1Mm6unJ~j-7ZkcOb=@6aWAK2mnY{22(sD_+OX`0 -037a001BW003}la4%nWWo~3|axZXUV{2h&X>MmPZDDe2WpZ;aaCxm-UvJ#F5q}Sm@4zSzmS9E5U3+M- -$OhQt_6|lJ+qE5|=wcx-64$GXR@70H9oKO`duRAZA|%bUXq`a*D;}0uIS!h{A!63a>1AyJU;rcJh@ -n!6)QC+IG0*Ds32I)n?iDNhXOZTkc{u@l1WB#CTUSN$@6E=pB1~B3*f4mpg`OYG~HueQVIOKZlJk?$& -KJUBJb*=x+Z3PQQgJl11(GXxdeNDEixH{<_-KlttFU7%a~lYHBNr2l&MBeUDQc>!>XK%q`s>uIHDID6 -7rH%{7*U~CvSfG+w*4xetzTPmWn*qZ@&xP*5>)R05604X+w_9&>0A1%dZ(zTDXJftZ7Txn4y2PT(bN^ -3Rv9?{fh~HDn4?-%s``NmsRe)Uq~t>j6|JDNmH||*c7m-){vv>hL%NsVJBkJJtAA0g6q#!2v1j$#HIt`kb1W0EO(Pu2x`fj5e -=h@|p8e5k7yGm9%Myr*3#f%a$#L;3Art)q+4jEGh_DMN4*ynB2l{Z8#j1n6wSLtl9Fm%pr<5cyu^9Tb -_|$UcX5kN&UhT9{JAYb=*TxC=IBTY*#}F5E!8321USWqLSpCHPr!xep{=pEaVfK4E+D7I-~-MfdXLiX -NJDWdj;SSNW#9tfdc)TB4;L(Xfe(fPV08Ub7s~CB}tkVRUy+fY*@L8wXrii!x4G)4u~sDtfCxf677$< -CPlfuD2NCnNpZug!z`F=MTLW5FDLQ^K)QNb!X|iouOy_YGAT{r37waw58;8DdN_#Q1+Hj_rUJJ5-)yg -JS~Lvol}DH!(S5LcxKXa}t{|%L0EFnoX!gH|_l=Kyso;no7P&bHw8_DNEA+Jfe<^vjI6qpvKVHI?hbF -g%L1De5jtwMjb!i2WCisRV_QFW(JGliKpT#2`NW;DKMQI6}7Bb_bO9@so+OX-#M>%(J3&V+>o`kCoPU -MtIQ!;@%wXEI*Z^owaCedSfy+L|=^_Rc?;>${US<^IjKIxQsg08dm3A#NSw})##F(h=Jwfam!6w0=ia -A`E8WY;vib7ZiuQqX<@$n@$iT^t`RE|wP%fcGY)S+C7V=Tv)_c^;b)e>W`A$YnD!j*}6w^_xp<$411{ -{%~2RDLO$v&i~LK+63IKAkHGg*|4O$&p9PcOaO$*S)b92kCSUAL%Dhl7d!rrB9#QLmgg5orzh!$k7r& -Mn9t|1Ti^7feR|hDz3rY}bWi{3={hnz5Ne%|i}SxP&(l*}#a&a8;k8#(mZ?x@u48!0PDqE^9%q@W#ql -T1YA)Ujg9EjKH+B#lL_XKkZpD<|ulWA-^jKL1nggJ>MsN}M3Z0|jHs5|D?vf7O(dF_Z5GuGEI=qLZci ->^qd>(n6Pw6fZnmf85pDoUpCtCL~h!O-pf;CMDv**rSG??oaUHVUq_u&CWy8i&42@$QCKf7FjmOPF*DuyMrN4& -$s)$=5%!o;nBx_p|Yzon+GpDP)l`0Xy)t3SRqXRs&e1Izq!F2Bhy<$wlQk9KT7mL6Xb$Ib5x!^k{iyZ -*sTSm6@h5=Rwk~Ra=7?j;#7+I}Qtu?vb7TFdna-e_>#abEebAr;XwA(Ecx~6t1fTfU#h2YNtlaVo -IRM(SSSyw1Mm2(hACgFGX$TsY;wReI>qWD|OyT!!;{#-Wah|K5YCx3P%L#2P$_mPn|5r~6`=>&8e<;Sg!Y3#tYLK`_=rQ3-#Drk?WP;R@`<~>;$Iok^6VS_4kIvj4;>#GM#fqsko^49b< -^cAM)yG788Zr23eh+<;WE43$^DXEUAXuoTRoghEuY=V1S5?woL@eqvXR=1~IJ%e7va0j~9jB_GD0y9~ -)F{ug;Lx)CU@`zuD=j9qPn&no%)D@4OT&>n?tBp!*y0h11x5jbN4_*A@UD$W0^qQ_-{j^SKU9&0=_c_ -CJK;+#J-!BD!5{T#nyVX4~7mv5zbFIL2GEWTdjvjjaGLdEz1z$qCwvZI97(!$ -zTTAxLqtj6&tRb6p0;6aV!|-FFgk?4(?wkJNgHQ%!^M&)jef`KLm+hMF}>Z`chPwRdFOS4YHEmu(Hc& -ir@u^hD=3E*9&&p!?_{?T&JrdCEnaLk)L|(=PPUV#J7b|8Rw@MTMgYP7&zrB^pW4|u-zMb&5gT=Sl^A -=aK=;mzPEU?7de}f9q(uAyGm$}OK7`QfM0YA%bgrGm1bnvdjixk#bEoM4ucum!(cj^4!s`PL*5%S?3@ -i4CK|O4kKZ)iv(~=G*W;bFNj;qIUScrZ9$ix1^@vuppVyuwuYEWpZg}L%(84$ulw|`tKomvj!0Zj=^`L@A=R)s3bi{{@`aPogDm9S&fFx^$!09t}YDq14#+oMayw$%LYWL0oM^D -~F9;h5Bf+&1&K=(*b+B(ObcOj%}r47ju_Vl7Mo)Qgm{tHk`0|XQR000O8NLB_@NOWJj1_uBD))D{!B> -(^baA|NaUv_0~WN&gWaA9L>VP|P>XD@PPadl~OWo>0{baO6nd5u?XbJI8w{@$7X2jPCGJqaGT;bxd{r -I^%k8S-{c%FAVfM~#)#oMRhFq3xCa_uG~HB0B*t{ZLEVeRlWJYPC8c^XpiUb(}B)|DzpEND{ADDp*8z -X~Z~@*NjNUw}NDAHSlt}f`3CT)+O&57jc#zADxij+$UW^(@4p^o?VneE}1c=CWnK*Kc4x8#Z=AlERz} ->T;MFvL@YCYhk)yhlU26O6DApnn51zc+~cF;qj;NVT!M7v_-!x)Iu*u!F~GN -Ff4bkDzCF*RLG25iG_i|-E^kBZN~8P6tsl<^WiJ((T5fCed;%fLh@cQrkIVcWoYhgLA*yTBALfEh#G**|b)#20&{IOoM+nUCj(^~6KMk7 -xzbz4g_e>CV%hLb|`MQhnBJbBfcKR%jXj{EaVZ$40}iUaF$=vuHixbVmG!J7f@{`dk`E3&>5yUse>fN -+4TQmTOf+Qk{LE0m6rx^~l;qkJ2CBOes&CEH5rmZ5L{$9dp2)==Rx7{Hu5CpNbhpUJXgIkp979(68*A -qFuA!yt(A3S|}!2Q%bHV>Z0fjCb@>X?6y(cD4VV>g?JE91>9`0eAo>kyBx*sNVa*45$hrBcDBcQu$jQ -4>#mE5kk&&A%9(ve?5WH_#Fp>x8q6R_r00#)JQ}Bt=IolA+-+S|HrElCu1bO<>_bAG+2v|yzwVvhxHj -Vu?~`I2smBxC5zLUI%a2(-Edt*UnpD>^6U*wuv7z!A*VMX79AuqEY)XIzYoT%U9gMeRU1(5!G5TD2Ld --2+EA`wQk7qCg@ATKw^tD*qD!Fu%N~(#ghYdRV;R@%1owzVzll5dLz1YVkfT!L$ZC^D)!xCzm<+Q!TW!oB$f9jxk8xe9Z8Vjc6cFun5w~M9D?xBdGV^ItLj)_Z4*OF)VP{;aNx5<{{#WU60%F|R@c}8VMT{g)hB2;U|M&Kx^lWCps`?wngx -=jVD^ee$=zdU3%9J%7?{0I^X|vb6X@+OCOy)pDH14|fKK9?LG#Ih(=B}HZGc`gg&s2n?3)-TnGcSEEigpRifry6bL2(Wd-64f{2O%~cYZL&6ez;X(QP+ctZ7!m^OBs1tw|VSs)eB~ShDV#F^8Jd9&+oD$1lk^OIeXB%4>dSjPM7_ct!mn -1^1zyTAis*xYZRS4XkYgv*b`m*%ZUy`c$VZ!#0xuf!6(j_!i7fvK3T1{l7z=FCXy-t4HpcyA_*<(I(#A`JP4N5BzMNJgK0_d4<7L-*VcA@Ar6#=oq5w{&gn;j6R+g)3bpMo~7Yz~`*(l!>ONl_j!RI -xW1a2=^L~HN3u!p~A03+Zej|nBnRMqKsItm;MwZ<&O@~tUVA@QF>H`fuTWkj|~K -v0&PWHxg%s+x>N0*&rQqr1^)v<`x|^Rx=4X(j^rf3k|QAWLJBS0V{kc_PZ7o{OLs<)R9TDSdgmjAHoT -3vMm25*F*hc8Z_J%9P;xg0U4XJt{;3>;7>#j>cTr8HEs6~*7I!d!DynE;FopiA*$~uT9vHp9y%Hz5yvPwTm0dMLsHd%Id{U~e}|@nfW5{X -K{N@b>`8CRD>!4Qx=T#!+76X&hzg&*I`r%>_4hQTr_D}mr&;~$B99*lYHGu_VWe -}4DQ-}B`j9fm+<@ZUw1XvSWEWYhC82z2=LyJ!Cc4-^`I!DrC~=!oJPTF#4vUnF80TwK8Oi;I3Gvgsf=Ize -(}KZ^wX{2=O8nOC&tpcyW;QdA=DR0`V`<+P5Mm7vCH)*nU@nmSq9!zuq(?0S=`Ad@4~jQlm8R8R>wVNOEuoh(`)!5Fy3uIZ#Zv -g2pM$!QdHVdUUI(>eu`a#jGJLk_qqFl680jUtOYfRXkE&TRX2z6-q!m8k -9l)5VFm(Irl3t}#K~i)^UK1!J^H+b@Eufd5C}W#!pMwpq{9c-}xmX}E!Rmc*nuZkwCRzFnN=NqUu{L) -n-)%jltbV|bg|AzR?uz(lRkcujY=^SA4bZ7I%8kL)Mja()>@w-(j;^MqSxD5@|?A`i0XI_@ -5zEO2C!hGGM@KwfI-s|WD(aIbua+nr;O4{wEc}~@6`1vM#24$_~q06-ayf&1TMT_lE_iCIMla?BNW0} -S*(`*p5kn85JKy8*&htIw3hCox3PuLLGT8EingM+Y_0SWqBs`I+MEHGGUFA{V>L7<7;Q|qs{`HI%$V9 -!KmJGq8c*((pL%u|n8`L)Ko=6&tXTCC8O*J@DlI;hWK@FQLFKqVj<5K>?{%!0hrr*;{Z?SqNYHc_b$CqUCh}Z5G*}z5h -f{EldqgHF+E5HX+TRIAr2b%USFe(H7zy)j6#)O|0%kxjRK6J=y4R4VZ7ov=9y#X#Te;WmEC;%z7_WQP -YIkR-7Vgh}CBxK;u*p&`!(697kYk?B_}^RRL)jCfVGT4FF1;}jOd+}(}|jk!IPu#$oliv(mrflXG9O~6Dlxj~$k@hYuNXjw5! -W8S^OfI3EtJ9Bg8IGW7jM3`2_lA!&b-0Euq^xB@kMp-3nPCbol*rdU>Fezv|&5Av(0412k#N;F4+uCT -Gz|4JPvk_uwf^=elL*LiKG2)6#eNCQWps$G@pyxJq -b-R%VuFT5e`?Kk@~%8th84KKD8*IWmbW6Y8mFB<@B|x%mQ``*>z(#CZ -m8L5}Wnge$r4_87hzJynwfPXe51w&g;b7MKQWrJZQ@>(6L#R=RYwh-%BZ0S2TH5oyom;|e(vyRE!ty2 -)z83_1XLt9qMBt2KKlVCf2g!%{~l+|=C5SrwjS@1=1(eBnwXKuM9m3yvn1RuH!Twfo);^ebR|P;sWlA2>V_w`(>N*XIml(TjAGP$paB-?QCwt2PA?Zxd5N(=c9w?S0HYwzii*}B -xVzv!5%rR;N+B+CY(??sZcu1Um^Bf)GmA(9OY8f{M)@A^Jxtcot>vA26r -A;DIR~4?sNN>7RN-Z2IH#AHI9_=6P_9Urzt_^3@N|pFMr^Tw9`M*Ni6H7*cKts~i=&=RG?(cS2Z$H^vv9Az_2l0VbItUx!0M-I#nRk`j5#k??;p#m@3Q -*1>dlQ2pMzRh-1^|vp(UM9;?FO>v1d4m5Sb!c*l-rYw4|o9ZQ-LSzgjCNF_wOZK80;Nm=nJslG7MtTv -RfF$>e3ziu$obTO_}5y10j+Y4i%BGNm7<&fm4Vn1EW@&h!UACJ9nc$Mkc+EUpqRiFwraMD`0bPZ)}`3 -`xS6{yf;p5Ez#N;?Sx=E;IReGliRcIYcTC|c=i?WIk^F!yLSki5@stc^?QY#oW5y3GE${_+Svikye)6 -a3Mud0PbDzv%)D@2M$4){Rn9yjjE|NgA%=l{F(F&rbBEc+y|&IXKsDjstuYek>C`i&jD;2k*-{c@x|? -6z(fnn6?f9DTeQfIEZWpuv#Ji_`i#zuOGkEGv&^RWvXC+S#957ME(GoWZ=q2*L1Z<-ZT2fH^4^dnz*O -PrqnIERC%cfWXjA~Ay1)Qub^K7sVI8BudF-|NPV>W=8xFYlH)b0fwMQoxsMBcp~Y;M3$jeyuVScnKsF ->m!!ndzoEKxwgQ6~lf%nwh()2HFI?Xz(wy74Bq^fnfeOlxbsg%tKiJ$>T9j9D;d;xf#qPPF(ZMM;n5* -uTY;ea7|$gLD;>M-oESF5B)BDmsice*pFUw@(?AHKsR!x5DHE-%(ueYq1V~KU+*lH{T$XR*`O}b1i?s -P;!F0|vLcSWLa8?s97|W*s07nv)V`Nuo>SaN!vs{6xaI@ZU?F!AIOWh+dM^mw>7@N>;iRZ-R3$%39ol5^L{d&a1b9j^iR>vA9;F -*+VX5Fel5{Vym?sp3``opWSA0_nZNs244Q?yvxCl8YH9?||@A{triGF@g_Jt_j*Ax)l7lkUKT6P -8o~i5o8CqU4+!C#nEC#}S#kdDU-Q_P1J9Pr)Ks;HBRsBkhmn`;gzX2 -0t2UBWqEuN-`On-QgugeqZ^gFoPoe!`1mitF)nhF|G1##Q1-qXnbRFtx)@K>;ORGOyHw(lGbHZZd#`U -f9Z-%d17e|Uwo0YU1C8EW(UEu#;?%_n(~wrcUS3El!5Pr?$0F6^=-J5F*(8GF@^*pD}^VmIQ;R;_)+) ->zZp7QrHWBDp -L1YCrhikuP^+DHQ1u{9M|wgT2Z{8K@S5heANNfA_j2&cnQ#$cXgn#s!9 -v7)-zCj@p^xJ~UNOWh#uL2$}KM_Dq()CFfcEK=y$OY?7_taBz6I5y`dT&^Zr8V_77-k@~xRa;Et#*_9 -5I*heUy#TaoL5KJ3jFxl(Kcc(Z0ME=AWPk|MkIpF~`2! -tr^8L*+N;701?u)x=HQA*?ygQKY0<<}C3({SH+c;rQvCELUG-rFz$|3{mG0#)vo%FNUPm&NVK-xq;!w -^fQg`lpG>%mFE6vl--m3W2%&KARk<(&{W9g}#$REWgkM~g>iBP5~UNYUWD&6C$?qE=*xD2!31i -KsZX^s@k1nnv3DOu*J~lvA_G1;|`;7iW|tfUwL3;4jW>!c%=x*7hnJB8Gkjw0ubWfjXu03_UinYkGN7 -#n3&;0Y~N*txI`glICXCwJWUDlN5r}b#`U0*`#-gk${DbV -aH024NNo7dgJ-h!sbhLl^oLmB9%-a~st;q%ZoMKA!IDwQ;eoa%{eGs`1wmT#r>}%j(em4qUn2`^8BE% -jno*cb=^)^_dQmgAGf2I|yJ}?vAK%A^-3V4|lSWGG}Y?Y_@fLRplklzjJG$Q7gWW;2@tny)Ron$UexprsQZz`+FR!Hofy -9{^^wlZBn+99#uneeSvB@>XZT%fKg+Ois6SM20Z9WP#;iQSllZbvo#;wC|<8ZN1A?&YOx3>-+C*@6lZ;x+QJPg6nlX3&XN5BIGU;ISkeaL_?b@j-_2tSe=r)+PF^Ymca -VO<>^i=LyIvCOkQrbvIS(@oU%4(gi%;i=w#1G#tF%s^a?15ezC3Hzv2C{S@idDz)#u>+?T-<*sS(_D$ -$oO2aNo-)d|<7pe8#5Pb>Owtnfz92VY -(wvAzO_1wZeGHS>U}P>=>sQfX7_k_RUHYXBZq&CJrh)zV#RYKMhOdUliH)1uM%+*auZ|rqa6Y=1bj>R -xX%^JMys4EWFpI&8{f2)u%Qj*Hjh8V@ossiuE_{-nroLbI0j3K`lgf8 -YFJVC%qTxqifWbBqvpB12aoSir>NscB`gfK7g~a%%DY)Kr~+@YsDv?N-r{bAM+m+jUR5@#sa1V58{ZT -5l|AJpXJa%urTpIDkadpPmtj+{-Zuh=QNFQaOB`zjKfbJa@i6HFVwyZj0JimeuscM35aB-){HKiZUv! -sLg${H2%s6`{rsm8HgEF1X%_l}#F{73KQ_V5LVR?`s_zTVS(5QNF5d2N>@soQlR9N@)D;KO{e&^Y77A -+=86nq#3A7Ft}E@po)BnSgFy#{8tg-0L;&DoMkP_;W1@Z=1SW|~)L$H42+c{ir?h&mZBn_dc?)4WpKL -Oj*br?LhTDK+Uogo)`L_s)YuSS}y>$HTw}{3vMS>Eq{CpbnWwzL6T9$~EE6O+1g%ynooh8sPkT+ZdoF -+}8D;H==GAxm220-(7WMy^U|N-$hv?{3~^~=`Zl1ESNv?>L=jYUIrq<4S>FZWNs33s_g-;ZL#KJs$>K -$e->*(N)WOlkTm0fCCbEqXg{F2PGar&)nS`-q+lIas?sFiA3@b)WSmH)J?st0&r@yBZ9+NF(M=l=!sS -cono3$$O|l~H^=+PM6OIK5z>ZU1OT;mV$SoUSrl$}RBP_ss=DXu{PL5gKH*5k?Y)n9lK|7Vf_ZB3j! -3|f1>wt5bD*CLrgMdlrQYub)BNH0laB7t;Z6BQfUdoqR3a(wq^t0=g4rNMLg-7rS12k1aBM1Wr{JynA -8Hf!7B+)He$-iUJGwJT})m9qCesPPEma2HA#aJ#|X*!Lag(l5@dzYDPl#YYIz|+RJ0L_JYZ5F7st1xt -lB9)rLtPEb`yk6KlwuOuqYDg3O7+!E4CO_mCDB}i`7iu! -!hLN%ZFJ{Wi?H_{iAD+H9n&*qi422ryvH`k{r9C3C)QgHxdQfOkZ1PP?veJ*7Yon+Hg*|^{CtNQ)f)g ->~_g>?i^UWLWy0YK9(i^_+XQ3BpSbGVFsMrXK!Y`K&$rx4~`hJ5iyh+f`%pS-9CfBKv8A7mVWo^TdeW -xtA_NOsP}6g`Qgq*l~(O8w5!kH+p=irTi(9!TI5<**5!Eg&82kjm-NF*F;~zsl#Ep*_r9!rDO;NGa6# -%{W`a@cG+t#l3 -KD9^ieNp<8q@$~G8m_`4>=p@VX)R`{}c1qXix_g__I8YB=LuS((7a_fkcxym=|jj7C>XI%02@O)n)>1 -h9}1|1*)}>tis!P4%Di*ymQLNJ2XAu&up-S%#y3-6z;sSGed`^&Lvv+n(~3P4aNy}>nD5UnWa-t*W&z -&kE@|&f577!bAcYjVp(t0W$DHawK-4qc%p0_Z7SQ^=$e&=I|5sQbcRbIPW|bgh)-o}XFK{~R{Ps-oxZ -tx&VOjp&(WfWuj{&q&P4?(zNKs_7om1bXB;RN@$Y@cDZvH?|s$a%xSXjw5-N;e{2N -{-8NvzDfFM^+j_Qrt(GI{ -EDWm{_vohIU~P+)I{NM?n$G-mvdz%E2H94k -266bW5oIJ!J9bnPo<$+mi(5WN8walvepxsMzJGrAllutL>INJVNQzc%mDN2p=!Hcp|M9GF_8F$sV-pm -Vvvc#LWD7u&aoodK$uhuOgk-<}o(%%X{o%Q1Pml!pg1Ho==@6aWAK2mnY{22+2`$jr47002fm0012T003}la -4%nWWo~3|axZXUV{2h&X>MmPbYW+6E^v9>8*6Xe#__uW|Az&I!aU=SmUOP;3YJ^hmJ0;==cV_m%U6OZ_(xgQz*mpc~c6N5&GrQbiCznF9xyU$!@3cuWmWdh9B~MwCr@UhIC1*9 -S7LpZn`mt9gGx++Tz{c!HUP)2pj~{KY?Pzn%k~}52H^=V`P{fWor<)%R-tK=q-q$ncbgwFkS|JA#Dqa ->+)J3&Kg!7_evtm(Zyyh(Bbs{nuJ%04~kyw;PRkN(PxDfe;{at2B4PzGehFnVbdRF9f0pRnhSTJ=v6X -($aRwQy>E%iON|MwFh^WgAfeEjMC`-8vlAL}vovV{2zSoru6gTHrTR*%)?`>Obr=f~XqJ^Wr>vRB)Qnpn1euF?4br%T=Kk5P@=|a>g -0mel>j!8QYY;ClJksonG_?Jbpp(lEU7rCd@cnT9~hxnESefMNZVDTATASmiFYHm{|gwcsFw_ka`rPB1 -0n=dN-|k6*_5acJdGSe)ny#Ztf*xi!&*;+7zD>FARRt|`$3$X3;H%TML%%f;LKo1`5dr_T-0$KN}kP0 -{07SoBPjzOePuAw&k>uvW*>{3YYyTcqKI5VfHLP-loi*YrK9cum;nIca}|J@7@*8$A9MqJA&2GQ5`iZ -mH-3dKK>|;K{XF9f5Gp#Y1Z<%`1>v8uYmsH_9G+e!S(5;p83$j&YO&xh=K3VaOevMSOB)m4g%T+9Vb4-U5EJZ(yv)Ww+=*Pz}NP -Zp%v%>w*J)Rhsk9pr;wVc1iIaVzR^N2sHbQOCalRVA!97LYM!o#oCpq|&UL!7 -(L(2*|%ogYmdm=$yd8Zdu=#!8~Br8OuBQH;1yxHWq)II5sUQpbr2!Gq^ -7aEO4ankU6Cq`BNY=#r;|$Z7+g#U|64zA(<1UM-I#fVgCw~au#zi?d@04tkVh90`&=%klNB -jj!YZf;H}(W8Q|1FX!bwX{L?2U?f%iU>&QwC7a0xBqEFj|jhghpeMP>K37wdQ%Wf5fIQp9BA~0{?lC+PRDH9Wq>X#kP*m$6^mb~n^?qQJ!AB-#ehbxsc0#{JQMs^2Kgr -$q=7{j18N09P%jqA!OZ+jtGUH#aDjrPMeQIz-Pt}H8MhDGi|Ouifm6-kvYE-}@MTztxnOL-x)vE6E#r -6lZ$5n+sAX%c5WOIj%x6Ud*&gL;NnJx?wFK7|0E)V(lgt1ZpSHn%5;>%R67oPU^Cva=Vlx34bYV*uVu -)52bn8SOC7~k2{6nGRH#N8wOS*>e&=KcsnZu26K*ub(4|&6};w_weT<8H$s}!WzALo(ZkP4)6 -weOBCsOBQmJypm0)!dR8PU3zW|f`Z^xD7=GgIxI|(>1*tvz^!9i{>$Q^5*$(QoGoF$JaQHk=!+9_(zi -Qds8jB?WNT;A&aagxGZm-=@UulK6U(KwyUy%>DHgWX%q(|*u8LvvCcj^T)~zeh8EK<9L$>kAvh|KPFAIE -E4|f0(`}oWfO}# -TqXDyel`-hf+Ps606?wMAUd2qz1vcCuPy6Bo;u`xY4JiM_79)_*N%Rgn)dw~{!F4>r2bk!YE)a}L-HD -$dSHAOxh4G$(v4Evh9-7hp_x1|EuvDfhsrMUJ$h$HJms7cJ-fLQos1n=k3wzheQdMR -ho&dY>lE5c#~o)WR&x@6VwtXpOy>o49x>Ke4s5n5z`0A5GxNip;L#bajf<&EVW&y+FaizJ}45OiTaFz -(PX2wt0*eCo^oU2MPS5xZ&!IFS@17>DC#z&8;#1n{3^`(jQ1$`u1!Sg5el${!A?I7=4 -%0&9kw;rqQU6Z{XGnjp+;3>nzZY5wbhuN7U3n!0_gHViUSo1VUF7PTZlpvMJkc$8uSi3-@ -zMp>cSB_IZnwDdZ7qm!|0g_kW*&EtpLu#X6fR8^^mPBsSwLU(9=>Vv{%}DSb<(v~rMU579Qa^i=BG+Ppr?8wWQ8co -pfVP(*{qu6z0j*aF)v9Dl@i!=!eb>Lj$#=R=UhqUbL{E!_e(pMhHXXfQPn!*iZYb=9!O378eE7OTk47 -E1M(!2|HR@^s9`@fZF7F!=9^&R7m&>QCia$RPn5 -`bnxT7dS1^Mg%d`1u0aqkXx82HE3KEK(Wx=mit;8m_^T}JpoA88#;KV7vf8IFLfQZ9`r0PY6A&$8A~Y -i6;|e33v--xxu|UxGjN8dvq@q%!1c(M7}G%l^lo(uKO;L9JA* -uw*E~q?93QZQ!))t0~BmDm!Di -_HlJlae*>rmXn!=8b-YPr9q2ME{qPe(aTbt4LUk4ZTS}o|$Bjy;%Z&;NS1+bA>Ul$Vr&}!RJN9?6JzNPTlHfNy_ -Qq=$nYM+EiO@?di%!Jt99(|(a!+bMfE58@QHwB~;7L~-)DM^#n<|GElt}4n(;Ap)Yu0>0aXH8Y%5j@K -hkDDfBQ+SBSj)Am?{!r3a?Xf?{PWok4n-JhB+c0S54+^OEbr(q)(xC)rZs#b4%8W4 -tGU*)N#w87AN101Av#3^WKq=#=Ax1v7%41>trd>%igO!))oY-iUF002&+D1)jbr*!vxF!|JI+*YLzN&{&DJ -K6@~$fN(s;}b}Lhw5I6FuXKyWR|w~NtC!}ty4>F# -7M)OW=-9wt|=;)d_IKteFG>wl?n_X#C~`mW!5ZeW#eGX` -B_9STtNp7|mSaj<;Tn*>uQ=@b96X82^4RYcg~{+@kRB_p~bfQl{3m?geI@fSsXR;~ZYzY|;&O_Wd$&P`3K2qvWBMmey}dE}qQc1OAN9K^Vs0>koD`wMZo|y0 -fy4`Hm6)eg-F6WrXvueCfz -BlfQ%f#(=(0Xy2wBe@V{kSf9uchB--VwHw+ZFXxmUn-KtS{+q2JtMA(UGXXKAH$mc!`^9pv%8C30%}S)#~%!Oph%hKYT>Ni%W=ij+04z=-d&Jokz=Q- -fE-v96}~B>pfzqSH+Ro~{NtjK)ZD=wxz?{HC%O0Xj63wMt#`X`p#kZ%it7s;*X$ht?P^#@VVq&!xeZ& -axOh9;e*p6@P)h>@6aWAK2mnY{22+Dh1Z(33008h10015U003}la4%nWWo~3|axZXUV{2h&X>MmPb#! -TLb1rastygVt+DH)oj>LbMI+d^+W6@lylaO*!Us5Sj#8sEH{XjY7*b8iHyuRHvghcu8H?v;92HHe-s1 -2~5*Joy*8IIt3#T6`g!T{gnJWL?r5la<|Ax~o_L9ZBSCf5qY!hCs~g%Q487GgepVN!9C_IpQg5{!HZ) -7Z$pyZTTH1#rcfIlR1he?GZ7w;oe-CWX+2aSTDSOen5}+>ybBkPwM=mN3mAW;*1F3i`c%kFPT!HA?q; -3n|v1cNtHYV2?jaamUgtrhS;O?e#9hFt2m8;=|_@WAz~ll_onzInd!!mAcpA(uXXRip}x3l-LwWmO>Z -lCQNv2Q*U6<@4d@;5~C3~D|}6jDUe{?qag2sX4*I<)36& -~i__|^&`G|0)DCT|%lboGPDWo^<_W)mx;}jp>V)TUyY)Qw|fRtbxVhac?w-33(OhBzfp2Udmf*L@;r} -Iy6dh&bFu=psBtC%bO%s3S3JR=V37VN$s;gX6?GO)~f%({Wiqc9aIj|_fu$(HOEp_MG4UP5oKbf&|3F -gtcU>N1<&7%u~Z8>%0q`T7Q}uXBt~=@3i4<$47n#C*v$`kNa$YLWf+-EZ-+=LWAl#}+MS3uuL9aH2nB -Q(74Q0qvSw;EswrivM)@gQZ{^l0tqn`pqW3A+#}qJ$VNzzj2)*_7A!8f<$bYbiG1PGM&rRTn4x8+b?V -$irroZ*S?Q!t5^4dy4z%gAG-A~vq9Y*D8A-NXo_oMlVse)Em!a{|rY`JEs4mx4*1qQ)WEG}9r6De+)jhJ3q?i%0dWvC%Wu)nl1@M8w0Cg7Zv7s|t)lGhlQGFV0}pw -yISSW*JLkcj4SOWglJ?9bVY{s||X2Jb5=R>W=X84C^D2$>|Ocg3&-x^{bp4@s=L(Vo?{ya22!76Fs5ieXZ2;b1CrlmyOk~aP28ELQnE_eBab*xUzj-B5l+fOjHbKGsEWP>~I -Us@~fd#zuz+)R7~A2zg1jS4s5?(8>aYmHXB#DQ7)zF0E1V=JFXLKSBcYP3+!s_{k?;^eUlf?#r{$3vR -jQC69H^y53<34+zh-i+?P@hPHn9Mtuk>|eVmSmr?cW|9I6#ljb}Kj@>J7g@TxSe5M_%E?VkGZ=6}v^D -+OM9J6y%0=!jpYR+3j0yUG%-i>YQ~9>R&ug9PTJfeJ=(I+~RoOk1cO_U7W6F_F{2K)jiXLbF7gEkla$ -EYikWg^x3zJA_Q_0&O5UtwSBHke>dYe%pSFgZb>$OFM6klut6BCl~Mk{BZ8k)#zM{pWs>}*$k+KS0io -Ac>jiB!mxtn{jCRBfzs>QqeeJ8gEx&hi;brR?a8eB*kD1cNM}E?Ak{V+^AbHal^-MYtnO=fU~`>A+-m -<1RLMaNB7ZD-faXPETzaZ_qFHw@c8(|%po$@8QG=vaw#)EM$YP=Ahtfksz8<=O= -W$kHWy>ZH|meb(k$9FS+;2M*Bsek!hI}=>v6EWYY`!d;Tp%*EjEH7erhPpN<0o2zT??5tQzUrUWi-0) -Bd4yh`BmHP4@C~k;i~oU_kDXq@Aw4Ur^f-d}RI@E}3F3YOcDX(+|Zy@P}Ya)l%fFSp%`7~q?VcBJ`|IA;_G=6qP@Y%mmO9KQ -H0000807zB_QyzBeM-~tO06{wd03ZMW0B~t=FJE?LZe(wAFK}UFYhh<;Zf7rcWpZgtJY45Jp#7@)1*YRA=@x;0GgX~iv5|UX{Bnwiul{o+Xb{7B%fRt=EnYqrXotOd_4; -G7k!vfl3@6OYT&C*OT_?s+w#}j+!W -IRuZ?&p(NhA3huLQv!D!(#J%dbcW}=aHE6I=vL_d%p$g5PC8J<|Y%i$Hq -a)WhH_k3$*C*@ip{|S60Jee#x^mv0C0AygfO5b2K@A@$TKh+oRwNarHO?$Eg6F<}%*QCALE6V=0b{s( -vLdvBB@F5VefPAd(@hcYOx^PL|WxMa;8Jy;2k}bOQ1&?ZXEQK7Cvb)hjiodd834&3tSwhVCoX-60@ed -dYg(aM103_Hz_P`Wv>wOkXa_e~J}M)8;>I6m3k8(Cci-T-o3Lyjuwm%HDV8En5FN%zXFY?bl>+0890EH&IA-5}zt -g;@K{5h2ZIL&xTCPT|-s&l6PK?+>MIf$YQKG}My-&BZGZ_m4|D*YO2!r=LTZ#iI3mN)Se*tq;#Lb+pI -0Ur<0@#o(D`;cYd9ln;`ZEk^g%N^1(RS#`&!9mr>yrzy8f{Wy?2Uw|PLs(wug)ivK_#*oX%g60R|ZH# -BoU&A24RaGlM1s7Axc`$1k^r_c?~i7Lt3SIRr5R+9~gw;_`-D3!L&-RDPk&Htr%#Tpg?ZumU$*%j;mq -`K^PR0gRoX85`I~L1bL#A2_$(gc*17OoGg%m)llqhCz;iHibGbQHjlt2Ey)EmbF^%0>Y$-HMEiCY1L` -_-WFC%ON2}#^RMdx<3M@npqA=pJ2pUs$$?sKio|9{Bs-g<85e_k2yZ{YgRtI -qptna(?+{+}zxBVWYEt-3zHZ%{QSOrx4vb%OFykqe7QHLmgddr0O*q?U@*mQ7Two5YI}8U_wPXwS^-6 -(W2XxMB%jN&#sf26cB{=+)U&K>UTsEQRvg82GQ!EQ1#;@PMRPfU`}E|IWpA%@+JOh{{bW4P-ZrWt*(%@DL8h*lt&+WcyLK~}w6ZlqFgR1rArp$sHP -P3W9k`EH1L);{usDh*z6x$A1)NilT&67Yh7xe&1ht$FG`8q}tkYNNeogfOlxEL2Xxc{Z_I%9|NX!i`c -4|aB+e)s)f|MvGEe)M~90bxQ@&6f)y)7Z+{UCLD|VBdnU(Z?BtkiidDSQDT~qdxlJn}9u`UhS?zxR)zoVIsIqn3+b1w=@h#6O(b=E^hp@TLR?zVhI;lPeZ;o-8%9Nb8vf_8FVZwH1CsMUdio0Sq!$QKP0F-iBt5T#Lw1x)n>O -2L8VAEKst(Tbb7|<|bN`P+|BAufo04Qw}A~sz?V5yfS6&@QfN(D%u(7~UV*-R-B>{-ENOL1Po{%%2a* -_vNKLP6EV@?sA9Top?hiz;&L%i;jSMq1!Tx7i)mk1N>Q6;#JGmE4lY7krLMOqNb1mn+Q?+3AQ%pJbU> -bUf>^&OYll6@;v~5^@lRqmFq*AWNXUO6&6h=&7G@ZZVY+q2p{5|HR>(ESYzbijaqTLZd_I^Ld~MrY66Mm@qL+aK_o=}mki;~R3~H|WG~;MI)| --eGtTxZFt3dT&1y9i&NjpV=1Wo2++cAmMF;ILUX-*dD_-olae)@12y*FbE3&+<;7OWcWt_@~1tr!B4n -eRFDSUO9z0yUs7uq4SK-T;NQEhGIrRs%3)((r%#Zc67_vdGL2Cv=%xj1qp`FtmDjUoH{}&l*X{Mym=M -S2;@VGh|8rVV^5Q#%C*Ty|)nA;17t&z(a`?;9o3{rqU+4rFvF}kyXl1g+-eVORb0KtSCah|IT%k+DeP -F@LR6z7?J1%%lAzbY(XM@2U8MplL`^BE{6g!7+7^ -P^bKmjEA8I2hMCy=OdY@At7w40S*+o&>$SLPHWzS32tBwXxDGJfaHO?<0!ueB7u4Kym=aUR_${H#(bA -ql9T9+PM)AUOS0ew6~FX@s&g}^yQg};h@6rJNY}8^rZQ<$_FAGY;`&yF#Jbs<+MM1^xGXyQ8L7l&6NO -fojWn?4o8QBVY$O12ZhTMjT3?yFYiVsmQSA;TK9x|a^xa;n12-80%O&R3R^-th+wmNelTFToPc8N5N4 -^JoyDm#|K){Hj--7tM^Q0{xxGeDbO7da&@abrR8@)$E6TKSrz;hjkmrdFM>huwUpYDfg8+aZ{Hyxh4nuTh`_k0-Dzf*am|o&DEWG_V^Veq -Itx2qn+*Dut#a{H*H1br5$+wY!?wGl>ldihrE?v=^LL$lkKx0?D{RI3ZasxrfS!Cq4s{YeYa9uSOy+Hs3nB;(7D54D4P!*dudl-A2CO1m85e ->uym0O#jDS1?C$Q7_!{ZzRLxHm!!@f!;&!Sn?M`ZF`t)yZ^y|&L3_}D8bvqSg1-BDvJ@Ck!i}pxLO42 -=cMq{}W`j{O{RK_y2B!{-&G*qA+6jku_RuxYTo_E@(FL6ceqyU`9K)$ThAPBGAZ$`f)Ngx#vTp -2)MCTa1Od7WmOUkaBPCcxH#ActK#5)HKjz@s+$6^*EB14dC)jSN$m^7uk&Inu=ic>EY|Hze9o>C-x3m -voofmQ_1dyfA<&h#^B)@36q9&BN?q!Mc6b*E}Qxocf^oT~35DpaaiA#uw9sv+EJ$+7KXihHalFO- -)&*${&_W$Y24LgyMW6zlW{zj`Lc+Q&kN}VS!Qo-%xns_g;X5~XzYz@=EGd*Tovy%FwC)sBZM}17eDef -vBTO1?(LD{EmAB|*1u^KBJ-K9!7O_K$0d%Q>lKYts;ii(Ti!-l(^%Dwe!i`Rav0PK)XQ2rbA;=RN^bBDl3c?y!tN3JMz#~HcG$-~iFYmYS`mES$ -vJmezl~)C+e1iuZ(yRQH$?AT6!Cr6fX3F5!v5h{zs`D0dwg`5P(BCUp=r@)Y~Tc%%RpX==9w)-@Z*Ey -_LnD$ZkxTpq`J8vqTwrNzW&R*17zYljf=VD<#~!f<5;;}k9s?4s4n@*IlKlnGS`?KCbJ@++wZPal1hG -bmR<{oYjbcat~vTFe+7FY3VsGD?y-E^ -v7@jIj#BFc=2+K;GfwcPNO21QkJW)H$1Dh+5lFn?EM0;@fKnms^fIB06WEQkx4Z<1&TE4fa!ej!6DG_ -^vION{Aio(PC?M=$VHi1rbRhg>$c88#p?L0~)Q2QM#GUJ@W|l{@=rxI9Duz1tLHF9;b~qtC?#lzEDd8 -1QY-O00;m`Rt8fKnOFcn1pojH4gdff0001RX>c!Jc4cm4Z*nhiWpFhyH!os!X>4RJaCxm)TW{Mo6n;1 -0|3GLcBo(%TJq#O+`JwC5Zdh03Vc1I$2((DsY$Q@8DSJkc|Gsm0(Jf7uhouje#B<|!zVneylH`|8)Qn -KlYW0OzmUKqQ1G%}rAwPWoBRMK{Z;It2Ns{G4G_BH>PAm`JFL4xuH{K+B^xenv^#6swp^QNcf(t#>^CUvJ*{i5qa734DpmJ(mNzYYTao4-e#$o5RjO&Jj -aDB-%|9#qL3NT{YpuZEs-`Y$MH$u#8zS4dt>VD#CwSyKD@#cmUY0o;Ef6k#y#%5c*yel=aK8*lC{qAYj>Q)xS!@BE0BxHR-vSR=CFpuO603mbt -IF&@{SVQpkg+wDEnW$jw*u0lkUq&DYukCY;@|OIcio@2kZ^*(Q{NkSSZv}mL9M@LB2B8hKtH(1k8`9B -8qyr#@Gb$Ty>831eexTK*ETeJ$T$ZsI+>XMbHk^-~*XiAqNj}8Dn3Ac|rOuq>BWq79;DZ4IGj43$H87 -%#xts*T=F`bX&;}o=d_ecdG^)khx3#KhZL&On8Vka}D^O3z0-j{*H}ExB_siMCV^{>CE`;2xEd2=7@W -hQ)8}bJ6Kz}DNuHW)hw4yDAG!|Hzg~e&8-~A#;A-g~!q6&c-he>BJ-U4v%Lpm73 -+gP4nGg2{jxOnI^tf9#(n=3$MErFC_kK^&9m0)lari<8&jrg?q{r4V&+EiY9MLTLj*Z=kUo`5(!=$aI -en_n0(~cS!A?risql3T~G?w9koZHVzLTt}z_Y&#a4`_G*EqQVNG1^Pg@75tmipit!hYN<=PEUhpZUcV -NH39O>?=smOX`j{m-p&N%E-v7;Bum5RH5MK#o04*V!}9Ee5g5^PJ`gc=uP=9_2LGpM`1ZNmqK56pn`7 -}#A3Chy#;s&|v?(ZKB@K%KjC4RE%HWaL?KXLb#}%A1N?+i>la>mJ^E5qu5^#Ar{Cd3;lIjae<$4!W(8 ->xWx2b{fytKOGaV1FZ7EU$8UlHAx@1mRkKf3Dd+93lkYKqUV&;i&PWhr5yiL9D?Dz -p2qZAOIJ~uK{#3NN?g~p^lxYM#!_Ybv!P@ecqrlLTB8eOw#Es(bfH4Nh26=!T>R=W01k4wXNA)T|oy$ -q4eP@H1f*Dy&5F;J4j%;ZiM7vTgW-nOKE`8eS-rZeo<4vBlAKrK9r4{WW0Xh?uq~aj5yvc+$T>D!l5C -=`H#H)+1h&t)3J95IQI_P=2REVu?TFEt9dh1?`#xkEPd`X5FqFm{)0l||4hgh&WWc!Jc4cm4Z*nhiWpFhyH!ovoWn*hDaC -z-m-EZ4A5PuJl|AEsGNXA@c*)VL#;D;_twqofTU;*}!6#^sDHXE5#Nh*n3^nc$SMe56zlXY$PuOYtTo9|sbtMW$DubUFrx)bAqwmR5sT-5-??q9x -zb96u(jY`HN~#TSCWLB+g<33tzxh^Xe{ZhU3I=IO?UDo*GZzJ)l2=MdLJcW#&~TY$WkumRO?3_G=iHd -Ud_s$Yvx|E2RBNSM&b4XAmTKI@i$P2AGYDDTFq~?r--xoN_Vj743Z=oGz`!NFE_jC1m7Z5crYc)jwk2 -PIfr0q)#q;x@d9E0D`b`1fRgo2nvOv$}Z4J2R_z6Ew<*m?4uDERE-f3EvTsOvF@Dd#JEBM91piyDeau -%>p7u=r1kn1GNBwg_=n;_Bt9^-S8V?<wk*d-Wc-6F!>TN=tG^3*#bY909P?fN$zN0?#ytXLF@{et7$C6pLS!^-2ZqV{%~Psgu45!l`=+C3o9 -iX-Ec1b}0p0fXocFm|g0Mzc&oSKo}@K=6be<0RA+-f816(t!Ch8UsjS1PixqvUiWIP!x(+woN3u)7lf -NL_+ZV#ByVD@8&Z}{$wpZ9RqBv?!vK~84eA8R1NH}EtS`M2W{;1mT^Qpd=0rk51pT0rGJ`cLiBl-~>E -ca18BwZs{^lA!(OE$9z!0Xmk+CI9ddrEI3OZXZ4VWB_g7c8-t_9BOZs)u+A_q*YJ7j_!W9B%FqZh6XI -Z3EGzXya3sOUHcz5|tZLNgSGI5@DK)a^na;V$2aQ(-bc{D*c41BV!3bzjlHvP#qjjf>l5&s<2T6~jEN -k1MHOS+7F+*@c*t0JI8;NE?kGyqq}ge$S3H+ZljOah3}Td11)$ -*vjyhQo%X#ut^bR~PV0y7(`kYALw4FRal7pKpq(}`@XMa_j0qi(DA(amBm_xIGbM4eoZ^prs6Cxv3F} ->CI~k`c$;fsg0}wmq@VPMV@?|^U7+U>`S_;TCw- -(8~qs5oxR2nQOcFD<#N+4ExO&m{7p~!H8Je;*GuI|8z1JUkna#h#9C$I(;JAT=f5IFEq0A;vde1ePd*4}aM>>BfIU6hlJ%b(x)+Kq<6;*;i?yrqR0N{zeFrQW --VgQS+8a3S!O$d;J8Wd?2BeH$6Aey`u9IxC^v<*$mL`p`Fof*}pxjX{AyAX}5BF2*#6qaLqr#8G17AEw(2!ZuIi72EE!MvZ7EQs9xO8epiwQFZKkN4))YZ#>xjr7tM2OIZH{rS@z --+1r3gIO|WU^OMf6)T3edq!$XJ!kt)47^Z{|`U_ESAr6nL9E@IQCdQsu;zy*HkaO$CDN*T+jU+nz%#% -)Z*({_5vi*gn{B`^(pVoK*qTCjbyD1}lE!ZGMzE2jx=W*kzDrX$y;Nkh;E4>FpxQ>!}x({pL51=vFY! -6ZJZeOXdtz?V?E7tk7HJlS4tw{ZF>08Wj;&`C3_3($^ja^x>ikuSr%Mw{Q(gurFEjgLwE*ZtA;)z_62x#XLHE}w0{FoO9KQH0000807zB_Q$x -peGMNSd0Cf-m03HAU0B~t=FJE?LZe(wAFK}gWH8D3YV{dG4a%^vBE^v8;S8Z?GHW21>CZP -KPvSvPSNaLu!l;fxW7e+fD~qW@DJBUC;IGm6x(6KD!hQHtsVM?(slIY8NmC`)g)nrY1|3XMF@>KN;7rii=B(>1b~CXb--6S#3#5KLcxN{h@z-TnFP{;?HHZe>+O9p|R$bm0%^x8R -yl%yq?gvw^A`_koAeT39k;{D?+ZwDc&Rxg^I)xKqnpUpcsr!a>E`kvd8&3U|92gD2f6F%W3qTKX^7H@ -Cz4yZPd3ayOaI(DCP;YxO>(@$F;)7d?Pi@E+4h9-5%u$D{H40lafopLm|D^`Y6#bUK+1;H@*7^7PQ+Y -Kn<+HM}DuKl?%~&=;qng^g9{|Z -tp$|$m|X}zpre2S)0Gm>Gu^NrS>!y=;gS0qMzZ1 -I;it%X*EJ6hPUkejWxCjn)|wsX`Aeh};n3=7eWZ&2aX0w_ -gF^+&S2R`4z@QhuD%aBKs(#xGVBM@YS=7Dm;t(L5g>B4!e@?_&66j*V}na;k2E7{h{^iKhhuKRh&$;u -yaAhL^0cc=B|Bij6OJ2E#Pv#IIWzxDFoDyIxiWm)0~O_tbTenQ=?7wMfHfqu$Vb>`#MYI|7Z& -kw3-{k$SU)z!05X@#v23n+FxWEiPGf81E7dYM)30w81?pxoG%lJ8<{uvX+Xal}`QSzah(F%QrrHKA;^ -0o)cnK+&VNa_q{9tAhUEQSu{fqG>9qAogI5mj@;-il_~vDqA81ir4UZ@$RBgOVG!NI4hB?+7N4{{|## -@DM*YvFNi1Xz<6H}D0Y_T=7{u+r9@I>+_H%5JUxS)GY;+NxX}=4PO -ZSu*3}ECdaf=I2~Pd{y(kuz7v@0N^fYtjbHMr%95_x$O-6}l*6@+G?>1dM+(l9<=K=hX)1~fry5A1gB -t%SDMwI{u+P4h14;9X}NKv4dv?#_63ih;lin^cQemQz;!Lq&=UjsAane38{K> -;91pNCMq85K|AUY1){ecX&sBqSlD7v}Fgxcm}$gVbyW!moYy_tslI4#L;FDu(sUXtH;dT+BP#MxdD;m -*7-4W!5i{dy1QbyFy>cc8mpDcs!$7yiuer@co@ -_YCC`Veavt(1+iL)Jh6;g}VI-jRdeO|@6aWAK2mnY{22(i}EzyMm003D8000~S003}la4%nW -Wo~3|axZXYa5XVEFJo_QaA9;VaCxm$O;5r=5WSP|A139%M@mI%3?br4i5dkH@nj4sbQTudow{Ab{(Cz -u5Q2c1Fum+dciwyRI<+k8IWbdG&^&WtOkw01Ig)`iiDg;Ef(#?l24*p-brL6WvA|CW?mXoO2pT%%vC+lB=#D=Rqntu);Ir_R6rMa+! -UPAY^|90%&0MQoK|r2g5g8>0F>agEJdG)%V?Ef`e*#zbaPKjJm#!-V?2+lxT=}-_YeSb}}b7kQQDy|Ket3idP5DbL@EdLlDfQRJTFiX-;sOZycL-(R_zNc%Do^LQUJQv6 -SgZ|UwW@!s%V?{EwNJh@^3zbjWVPyG#L3<(okn#giO9KQH0000807zB_Q@HPtnb-jU0F?v)03HAU0B~ -t=FJE?LZe(wAFK}gWH8D3YWNC7AZ*OdKE^v9xQo(N9Fbus1$UmsL#K|)4J|MubA_EEx=%G6dyQE4?H( -YGVpctgt*N?Om+s*m`vk#`J_a6C3Vbca;6XJA&Da6o+``{T~xyD_eVrbe5Yv>d4aAK_cUm)^>z#q(De -ZLHHHiwP#?geN%DWU45OQd4)c{(xj%x1HD0>@xncNWOe#RvlS93(<72U*BuB`c)F=F+VDZf$ccH7*wU -kS@81J{N?#6hg{W=v`fp&yz(<4HH1YyjfVp9f)#s@a -!Fp4>E;B^lzWAFxL3SCCP&V$1?Z@!=qc)ZZyBhzWmY8(B>1{yUeXrpjbX)}ZKVV%2ERRPILG1#vchW -PM!U8az?9eI7dZ}u0q-?VySt<3y9&tNT}J*~8e%thf*uaXSx?CRs2hOdOy@j)?4xp7~`ZFjm>0gdeMf -WAm2^nYkH?*rqdnOd~OhqsB!OTC+#o~PNe$$=9|Do#-8@7B8}P8mh)79uVbN&W}6o#GHt>%71=%8*cCC)H8YZh%Y -2BBibAPBN>$Ae%MgnDprnowgv)A{m3*d2er$(J#Hu^pJ&`C1;1h8ZL-K6GFGzN`qurEVKTB!@y*F_2<5w8etB0?|& -(lD{l5GV-1BWfX{u!|FIW}>;4z#*mME638M#|#YfkW$p`&%#fVH)Tc9+3l!ovx>-FxzeFt(wv@6TQm8 -UW@{25LYW+6_HT)&KoW`Ghk)FeP-Hfk3$PHn)wm{P|F;Ai5kcr_{T1Fx -SEQ@8dC(DF}wk1{|Yqq?C>8(q_-q3Ct^DrelV+pIKY-q^6fir2NL_|;y7DeekZZN7=rD7+_{RqWc&?d -9JhFZkhVLOCHLVvl{HQ#Sip|?&2MTt>~&E8;6)0{mbhm`vshp0LH0zd-FSOXlm+BMj$LdwbJrnI7E@w -BC6)l?7WOAsU=z+-Cz33J+w$x9nxB$dcCl~0tZkq%=)YU;DjL6d`o8~MnswuK92(m;!X9UWMHaE5Y9Z ->_u6M^hLWl*sKH3M*oU*vO2)Sy8Se4qZcxyPU3Fwq9KMcaxRNyfs^{7QcFz?j`F@*7)6X*qsOWz4aMZ -tR{2+6I)!d$@~-ht2e)_PsaV*a^^Oz!-CX#Sg -Z=p3G);<1!+N?R2sHwDLY)`|Nr#yL2&l;Z|rfZ*nnni;bc1bT;vB9CkUmnS6Au@B&~fyR77TckS9CY& -*gKsqZc36&lPoUCjLzMjcpS<<|&z-r9B8WaX{NSXZkBb|H&HVqvi$H+NfLbSUk!!%F&nyLJ!EF5Srtk -ZZzdE*@72k#aLC#$0B+8nRU}Ku$41fb^9nh|QFT**-t_)t(Otm56a?tndTwfG}M#ev5f6{&Du*t9@Rd21sM;?^>qmY-fMd?~j{A); -)S%yc&UXaqVw}d~zx#n$%14voE0*$U}$06R&OrME_4S+-K2|F*wh77$RM=K$!f4+v-ZXZTYfGM;R{eJ{6 -AL>m*zQsw1EydWVU|;7C+#)1!RkOTe*C%cq%r8)YY4eXQw(WFjgJc8(8lu@pbX8Dt~VSbls-G^sN)B{ -ro+H9{iomTGRYGnPVG$`#B!pws~k}lS|t)a}s*AptM7o;L!2vW^O{W=ap?H8cZ~?XxOR7iVSUlEz_Vu -7qqCnol)CYbfNX_scslctD>6QeL5-?9FJwUX#=~__u9N>2_J-_T?`X^ZX;78&YyX-H{m8lBIu8HeY%> -6oc@$>^f?-d`%Ef6D#v)-@8*Nis7yeOluGV~?#v9jWa{f;=eh)z9b9cOCoUwOXv2V#7{NdTvxV{u~A7CFjN0W0;mho2Ex(oX5IR>N={mDBh$8Az;(zGs4To*R^2Csh9 -?i2wX2~=^+_((B-Qb&;!ZzSJA?bf;CLN;m5qrWQF}A&#<|SjDv#fscRP9etGVY}Sskgn-^#6>OOEHI> -dCS -6TKO(esp3;Q#s83PQW-rE)nuR9%Vc>We-cQ0YM&j;vW?8xcn4wS69#pHx_g0#mvzV3;%HO9KQH0000807zB_Q;MJ94⪚0Q(6502%-Q0B~t=FJE?LZe(wAFK}gWH8D3YZDn*}E^v8$ -R$YtZHWYmiddZH)GRa13zC!ESjm=}6;I-%1%H*W -rP=gF&no*pONdSiMt*lxVNzT0jX{?cw7dUdF0Y|_!Hp!s$K-&+_x`y9+3tTpxr{^E82Wy+&91N%pfN7 -Y02f0X|GMwaX{uI;y*uu+4)90IXvH?aJmFUlG{fcDw$*~)PQ>*gphBGbPk(Z9*Q2V1dklL9Z?bikUl; -GD3N)?jmhPT9a=4&Y%Jajjy*6Aogm7!BTtbiC}hLU)n9LWV%NtHS^l7EyNdq&34ReVWn{vBa#&g|1KF -|G-bMTnH@(5TYcb?WThx6QhO5I1lQn7&3#H!1*#UY2lm0a8Xh=*6R=GfGt!qmV -38o$|PFr*=FjhSzm@Mh7+Cv^dhPh4sfbi;?v*ei?X%pB?c!(z!3RQZMqNu_?}QK~YyX%?N&AhZoETYN$$YMb2mF#0_s)c|Xa-5rU)d&QF`T -z(1T7AoM#ZZ1-YjRi;!zoZIPx!k)(DGl0`n^3(B-qEW!^><_%MKH!&D49v4R?{sbB2CwcJCLZY>oC(X -}WjEYx*x!do%Pqba^}ceve|>hv+yl>l`0ZluFA`YP`Om&#FDs&FU?RN7&P)h>@6aWAK2mnY{22)hJyoAL -J002ET0015U003}la4%nWWo~3|axZXYa5XVEFL!cbaByXEb1ras?Hg%t8#ng50sjZC^FgDR+{Kl#c0mO^7v>`$u --HO(CmXQ_%-2ng&SE@L6@vLK61lSxgAm^CDkjxoL(#Z8I$*t3qlns@k_H!t!m8+w^h~GWhFDFRD*2Av -YRxcMG?F2vesp-WAggq*~>Q@Pc^|>zf>hj*r}Y(lW9J%KRu7X%BbmhEkPPywoYOfl$&E -$VpQ&Czr=Z1U{1|G`nFUeTlNB`;T6tEdN=DdogGYdfHz_Al%G<9Ru&duUy$61 -lXIy(3ycgYDVP2T63xQ$g3P{ -bjvu4g7%)2gHYafd263o|VRl=N<69l@1r0h5Z%^Be3vKk%SavZC4vr9o7-9Fr;_btifrb0BvljoF>iY -c3Y2;W&&7gzK6_=x#lQWztUa6)HVF5d6B0o=SmN>Epnbw%@mAMnAK>$6aB|qC&JkqKcZ}%Lu}pV^A}Q -pIYAhxXv)NfS5lay-q>EeM8ZR2(w5t!N1n3PO3y4*&(?AU`Xz*4BIiO*l#sc;0b|5Uch9j>MC73a(T!Yw{?x23%)3hC)@cj -4wFMK-EBDVF7-(VP@VXHN*yjmBj|VNW!W@X2v^7Er2zHVF{ZAu{;pup`qm!({%+!iNGpF7PV$%!zzW_ -<)TNOW5O}qsK-@130D9j8psAeCK!RN(gtj| -Si)M=-z{)FXfrq+upze{kkSi%j8KhYQ*-#{{r2y+)@DF4mD{{UA(--7H^2ilX{F)bB?-KG_k}dOKL}L -*dRR$W}NSzZOPHP|Yy0Qu~GWao^X4kU%6h&5n!8m!+Zs%A?om4 -TW=YNN{lecXe6H6{O;hxFaSAh=LGXQ9QmrcpVQ4ap2MRlmxM(2eyHw!p(8!)pomP5glX4H^(`z{nsO7^`C+K!7$NFJw{3EvRPZH{U0aK4utPv5JAnsB{ -JM3XBoc8WY-QKy(j`$>v|Rtk*Dyf!Qm;(#(uJx3WeBqNylHKTDPgnFQi!6Z<4-XxSQCEDb{vwz9gx?} -0I++?{WELX5;PoEiIU5t65}0(hkqx$@@gMHSe1Lrgb216feg0W#1l(%{BX3S -e44A~j^e_tDqFn%`c2LhY13lzp8wO)uk%OxV97Jm$mhkq3WPgNKWpbVaLmV9ITnsM>z%Pp(kx=+mJoi -z=A97kOLHafrk`96(%Tx>t`aNR)96fX|S@2^nTH2xEP0L{fNTQc7igF1jA}l5#VyYAblUl3at{5wvR6 -%?TzDyx3VW3r=6Oj|aS&mV7v4eP?-GGc0aWHM5H84@Ulo-IFr`kGP1sNu1C73P~+0GvWY+0{jlO$%da -65i3PYhJ@?>YG)dGPQgCMQ5_U1}){b#fIhzgR(Z$t4ho=FLS`)H(CS+Kkm6J-`7+(>#98v@6GyJ1ZzO -nckrg!9t`5uwZ2v`*V92g_oh>TO; -C)SnFt(rZjJnAs%~u2WU)K13IvHYmyBg)7Cw%oXr5|Pg%z~xS>bI>~0%N+RYzcf${RPUF17 -7z1S1#ts|NFT;X=@X#SRVZAFIb@%js213$mUq3xNBT=tuj!1##Vd00+3J@Q -wAa3M*$-&Dpfu%7?%$HgFRIhAq^C`(ZuVL3l2+N6$+epVT!72#>MclVUnJan_0;X>e$P#eQmjWWf4CxZ2!{RVo!%SK@Zl&i@L4o5j7 -@@s$e>WYGq_-T_}mC*Up${&4PM5AgNZp5`My^)V4e3!Hqn8L68sp&ZzBW<+9iA@b$+!+QrPC!e^DJ@+3oV{{2Fc;h})dt=U&O!Hg9zt=+! -m*S;Y?B1R1ugAlf7lk01q4|!qOxMf)%HI==>FedC;oexMNY@cp7yM1Zn2a_p*q&L>sY(Uv64EJA7?2i;AJ -Glxw#(t5@C9B@rUZkk`|38uo^DSr`vtM4ppqGoX)hHz;FPUq`v^5$=A=i54+AJ08mQ<1QY-O00;m`Rt8h&R=40S0RR9*0ssIh0001RX>c!Jc4cm4Z -*nhiWpFhyH!o>!UvP47V`X!5FJE72ZfSI1UoLQYjgh}@#2^gDcO>4y%5sTxx(Ddgr9=1I5lNg2ZNSJT -?d9zYIePu04n;@-$DjT4N7FRt*$L!rLDoLn;niLcdK~O32x&$b9pjLQw~|ExWRp|0X@-dyj0+|*4JbL -dX{FUUOTJZ-nbu_lNp=G(fIg=E5J|-KOKw46-^k^Z*^cz?!Ua5y>w=QI+oV-t=yNp;BY1b26F47<(@C -qQX|$S{JWyr2{VL4CdOU*drNoc$LN4rm%b|(}3JI@ias8*RM!XG~oy$0hw+F2tubOiEWX*|DXyrV5se -8W^QArB1qC~a5kmBpA=4qxJZh}M|uo-s!_{IvMcX@%DTV}j?Mc!Jc4cm4Z*nhiWpFhy -H!o>!UvP47V`X!5FJEbHUvP47V`X!5E^v9>T6u5V$QA$JfWN~)!GcsOGn*`mF5GGXXCpUm5-0FFShR} -ErNognG09;$q-AZ8@80+3;_%Sn#7&C|K`fDP-uZjS3^^DKE|*LY{FmMG8ydr35)o0&@`BH)5TxW}9wi -AWmz2yZmc(Qh&2MNHlO^XjA~-xaJUA-}z02vm6vu}LN91RorV$V%ETbeUuEnvW4YMevBQob%S@0x`S% -Jip?3NWgOKDb;+o)jCETPDT$j`gUyFWhtQ~3P-+3OeK^OK)nP0nA8fwWi$IcHgUEI@3VSdoSAPA*@L^ -Qc@3;tQHbMO1=)D^@NE7lFJ%^C9ZssPu$oc~u4<1<#}sN95DsW`#x!j>)GW2tI#Ci!Z3C5^b)#npdS+ -ZdMnxtconWjS}F13=R(lgTdj!qTngHPWX(lH0MPrzw68DO2X_t^(RbuTqX4IKwnj2^banauhKltO#d> -hK5`7PAUS@qONyGSSXL!V>YwYHaalxjit$GuJR%Z13zkp>P*F*?0G@fl@^VBF0>9~nbDn|@zad@5OY% -F*k3_TpGzd;s6nU|1o>Vad=}RC39gvV^*K!eZ!S8?jQQ&vCTWz3cMBAJ7nC<&X$g685AHE@6gXtNB0C=v`w=VdPHhu!2!5bz7#Bhf~k?b6(ORDHqc4J$ivXam{I?=Gq%zu>Gz~MisC{M9>XmVB}-LRILy?1~g4xtR34gsVJ4@rm!Y_ZaWv0GPLuW-O{XH9$0$~Z%{**{ -UGB-I*$bP&4p+t@UPWlsEx7g_E}u3u2<_+F?3L*Q=a7oU9dZU+GFz7kc`Lm&)Qd^oH9ZUL*H@DDTCO{ -!2(jTJCIl>JR&DC4l+k&L2Eo4QH;u=M#2RK59pSv{7bbJ1HB}aZBsgfswpM7rls%o%o(2c0tC)o?0}2 -jL3+xIP$5$RY+b@YLsJ^J8JUVl^MkPSODyzG6XjM(AM8j -2C!qg;aO|s8LxKbr+T#TDdy=Sf?E<2n+hJ3bI6mAXca0YDsD0gC7^{Iux|TQY)OCJd@i7nN3`l@hI8K -N>)c>^M%wykm;3aKBn5E&p;~-U0`K3k`rufSBgHcN`^Mqf^DibpnC$&W3#HH9rP;SO?4(Y^N@2FrFNX -Q)7La+rA&keakt_2zv*$K-M4c(^dd+B8m5pLaa2YfkkoTq6}X$TdOuFhaaMns2RJ=v!NR)PF0rR-o2$FhWRuC-(ewHE!liYu(!M8nB2(8>FYs3u-gOspg -@=TmQ}s=*qtz)D!*DLptmq1l2Ok^!5*<6cAys`%H?{;M5y(erz>{UhpwgxyFdL3ZApv$tlA@0Y>oPFW -J_H%_D&e+71FOyp{AbFGO0&P<38o~QLtZry=U{9j6FxQ7X0zk&UdTn -J=5Gtr~9P(ebX904^SQO^B=4bzrLJIUdw&OW%%ag;??8=Tx+%)C$BFiColf4Z%b0o+1tfTl=6U0&f!A -3>vxvB)PT;q_zvI6b*q@$ -0h1mO~XPF)Te#sZ~{-hdja2t_E4WpI#J8<2#Y)-m%M^DkVeG~28Gpa3B4<|sn1b1N^~PJboA90_=cA} -oGval%EE0-&9kKk7ciwW|RNEcpr2Ch8_k`l-^D` -`l6B2PDoORJ=0FvdB|{|rMIKG$OlMxj#BWpvAURRqLqcS7%1mL%%=q%*?@8?`g%gOfW*gJezMVlB6Ub -E|v<+3rR`;cwf_+r>%a$hoFj=St1&P$$ERaMyOr&dMWLW5(8%bS2N%gq6^V -fLQ@|BWzE0oJK`Wjc;UHu81%z6Rbw}sQ?x@8 -n-1|>yy*_9{%x<$D7-e>s)pJJlpg6Of9~^35wUPRw!>3K#q1H70^*OLT5571T?wt?L0=YN%5)ke_?i4 -sn{NEofODn(4DW`h48osE~bX{*E`W~>Jb9|I|4RGQW4CC|`5>UY$lT<4TOQdIN)_>*Y`%F|h&e$}5n^ -VZ$O(IS?Zq`a#VAv`_)ds+LSPB!QkK2Pk2d}HDLY(}6zrD_u{w%quy7`6p(E)9irae_`0Lnb;(VSrN> -+>sYTwBl>c8c7l0B?CRcX;sf?b}!3`N^BfFJSm5#nRiBsGjbX-mW>t682r&@nB&eAsyNcm$#*MYpuQZ -xdvYv!FX<*t%qZLs2dg6w?pz5`<9UeGhC;4u&WxJQyPn{ug?uM4BVFw4BzQfT}2#v_x7_Zt4_UKzL=7 -cI-tFZz0YnkzEYLwn0zM&xtVda1~}L6#6&B(iICSdnjHtyDGuZ)bFsvu=t78UIyvl -%C;XyDYeu3-Jxd9zUS++4rVvsJR8rP!Ucbo&mEBYQ)w*sO#bqpvsJJ$c_KQie{yIkZ)#rU@-fwd^`Kp -q({d?7{WU+ir%{i1Y#2c`ei%jv&YIkaPS@7f^c!Jc4cm4Z*nhiYiD0_Wpi(Ja${w4FJE72ZfSI1UoLQY)V=F^8%L5 -L`rqH@cc>=E2Y>{YB)dJ+BQM>nmek$au_dk~+tWjFfdWtqk4^d8G3SCvKS;c`1;xd-j -`y>9Gh@R^%-*GVXDl&6`D4Up~%u+vUk0KKustjJc)Wi>BW*|J)d0KVQ9Rb4K!n`(Pi)$n}7(8pQRy4Ih5((Pu8sx9Z+rrl@TtFkSdWu9ekuS)ZVH -=eBguz|*%`>`(8W%ubP+a|jz-j@iXYT?!G75t}#hFuB&7F!ugHl040PRH53y4l{#Zm!_L`?AHiU`R9| -dR1P6p;jG?=2??L`)t>hS<~gzqS=(tpla$agRa*_U2S$NfMy5w=_fR@Y*xZT!&tfwhEUbe7(0Wh0Brh*7`O!El>P5Dz@gab44`4bkw%NRZJy~@Em^N -rttt(olVoyB*w4bUCzeK>O`}wZhHtX!{`C0bG!_Q&SibdJN8o)|s-EOmK+AU3RI=w8nlSQ#DhNJ29(@ -)mr_NrOrf@+_BvTOm$WU}0CcWpVDWYwBpEoNP_+HK1Tf5(>c1SV_$Zrq<$WB=S%>(YK{-Jje2rgSgBo -N!9|yXi}QxhdKj_RPJ~Z438wxvK$Lo0WUKxxU7DDY2KbOKEG@@JUs^AE -669YM7{y@a!-`w7}*r`fAF@`jmMwaF*%%X)!_T=u#85I@Y}*L>Z)heIIEcI^uGX$*&cGsfc~OK}W`YJ -=E}_z#ouaEnW58x4CSy3ytE#@{mOs3H@%H)T&39*KuU@}}3 -BGN2<-wJ&;k37a5ayhYvrXH~irH!paN!hZe|hpe4f@YODoVR@Zgha@HSSZ>P4G|qoJpkF%Z{ed0fKLn -D8v82lIH7T4wpp)B+E+kS(K|{k5pIIvYcN5o$l6MuKV| -T$R`tA>B;24N+w=|HG0|9Zi#Z!=Vt%KBS!Onv@13nSfQ@J0TXyapNX8l$z(XtNNStpaGiBPSO%lJG)7 -WTEh~8CZtdIh#~s|(>$2Y7@r`xSUJH2qzsUqHf?~dcV*y0}lxQIlP^=2NEs$Mqm6F -&QLBsff!@#Q;FYio7yf_+3CwQFC{`R>&6>qN^fHm8}IfiSHH=VBa0#0&M! -{JzzOJZfbdzq|mc`mWn6JvB-fbq -fLG;Q5kT?D@00U#0z}?gqbn8usK1A;jrAUH87RvmNSK0&+u-#8K4J<-pL^!=9D7-B3e8*2px-9JPFsY -7-3l0}{g18*}lvq1J@^S(cWwGjcW*9TI^SGdRB>?~Q``~#af>0eKvDyY|Gn!QGb=fF!%@E5EU*7o9IhAa#TeuIuIo2g$%Jd5i{E(mj8#-PK5X@1g3U0m*m;Z|^# -k%A2JXu;~>;*?^s$S6f;UzJ80WE^mP9Ci)so -DI(HSl3eb(T;VD~$`6W{<>+m1omHhigeV}?vZEw=5h%x=-%EMP-`*=}0Y7OnRB#xT&3asaL%1Eo=t8z -2J!Omfo+;eJEC0#mr1Uk$Obv;)3ujT?tI7NR`q8;}dM<2^mijuu6GQ`JX`0QvWl8q$Dz{c!SG2mc#np -Jl^AKFI$L{K9a;kLZ#cj?N!{elY@BF28J>-Ddd3Xyo9@_4R$R+IhmI`5e=D%_axqfLq=pCO9y|0|R~$ -_j_)b&_5MjHFpXiBj3OxXg=ftaXlGvJ@{Y_QmGM&27-ozG5oo!C*8cQHe38gC%J9jSHQxU?;7f0ED%t -aqZupHn12Fk*Z%<-bNg<@l-VZ%8%N{wnMCg=!=c6R3sdK{X0FZqiI_-y+pO*L`hC?lHOef-iZqjLvl8 -HjNw7Q{f>Qi5e(hnM?EsNE^cIxHlVEu9=ZKxQU}#&)WwBdrCv%W1OFf6PwgN$Fj{@O}q%RsvM!aMxcs -5WI#jbwfX}sZCyp|5XEovZTZuHMQOu%+l!o#o6aZAq_8`P3oDM_Fp^cBINbAoTmiGSMEOQ4hlO!o!y( -VrU-)9paMtC1|$&vDJDXS;X;(sloXRnXC!9xv^!8n7aGKN#x9CrZQ#yjy^n+SOyu*AsBZ=2s(AsEg7p%C=Dl1Wp~Z(GwQ3@s|>Q*de=NesZg -!G{)iF;SxqItX0G#B);*hpGv`92S{&YcC>+a%0*ev%OgBoz~t0hi;;i%%jDUMH*XQ%pI*Ft^7?P~>zh -~Ky?*-Ketr7a=THCb)pu|056_-||NNU*XY$>3esm_J>?k7vcnOCVZZZF0i1xcJFL9{!(}PvhT<nI~Lr>!PBg_~d<2tqM3-&wS$h=_eOj)DCFV&=N1jHb0qlL~XKJ(UrtjEy@kDKlOZ1*D?b@^?TE -HA~EB;ELH(i+#-Wtu9l-%n8lw#5)h@A)i8p{gzwQ?Idc0WJ?emb4ue@lI)W!?&w<-?u|KKs5Uy6hx)} -~|E>JpV4UxS>LRWTM*T{04Z!8N4?ESVP8nAFLI_Mr9!1Lz8Wnk($@zo9Z=LGE+D;AEAex`N6d-NCN1Y -I}KLBP{d*v@-0+iU0+2k`S^shcrRU7rx`8JlqwTGl|&EDNDp$pL!GUGIujfQorf&%nbYJFI#S -*k!c}?g1_$Y`DiqXvxdJ64kNi~cRR9w?h)1$J9mIiJyA4Av&$gSv*5Qx06nuF9-* -at;OM~M0F3O&M?A(=q)>`@L`&6@?)#Uc(QhRQw-FWY>|;pFAvieb2$q~he|qWTI6y=!HmJ^^8+s6p2= -7`Joqc$t|0K#c!71Hxol1A!Vb>DG0X+1stwmFI^V=7DCka_UKJf}fN_5 -!(X?2c5#ZE2cBsr8*IQZ{emS?VN}uW1q1(Y3*&DVpkpU{nJ*YiBhdZL)I1gdk>zgo__BDr#7R1V-k-1 -3egR1FKfM(QMI0+wnigtcA6vvamUiI_fthp)Mv!{c{*$1Ro3BeZs)cS(=Uf;z|ZjSq7m#c(oF!W$Yxg@^00S;OI+ -Z@%zb$u>eOIDtF78-Paq{sOtBRROgBC_5TwN0X!AH9?;vV>4OgpDj*4>yFTDk~p;W*5EH7=xFTy@Cbg -0UrFL_(C(w`F1XUL#b_x)mY$7wXn_M+7q^&KJ!5sJ*tp2C21#THYCx!`3YG@ZIA6=v_|#oDB1OBit4q_`%n?iT8R4<(SS@piTSq6OFS;vz~%7{IK#|DOb{6}-fUJGZoZFeQ^by@ia&I-u_Ue0*>r8_%JGUx*AVwGzu^ -O6XIuUI4ta!4ZBn7XU04|^aLWfzhP7>}754us5=ju-NNv+Yh#?Q@08$5~l)Fp8opBi@U>IgO6g8m)<% -q8Y2Ob{_zYj}I7H?QYo#@H=WKIMQ37n8}RvwRX(pnz(O#Uo^#kj6_lCAUes0FClT8!D275Dq%|6K7rC@LGHjNBlzRX7sW>V_I{XCC+ZVboy -<C(qR733+DGnJ$#pUD*O$@$cBo9c-by=|0HiQ*^%UBXI+{dpn_eu_m2Ho7k_V@Lx&8SZderXd?XhHx -67OT?lcQlyl090H@}GA{37Io`{y9clO;w#GttP8m*iA|68putR2xO0v0-=n_RhyfULZ#CPw_ssa+n2~z&jaj-*`x6gaGqAihl -H0{1WoG_Jp~FmsK13li+B2S3R^3U_klMKVqr8SVA56Jg6Q~*+n3N+N5(@(bDRZ;E}JxEl42XC3cv`A4Z2t8#nD`M+O7ALptNhxox5--_VN$(K_;i -9In}2Z){(iBo^IX!Xz(yk->mxM0mW{rrj`H -sL&ngXj~lWmIE4h_pNLkX045{Wf5NblU>m5zL&FRycY;)#*F#e6yU!l%#iJ>XqW(IX5_f92RGLn(dYAYgVUL> -JVku0yq8=DC}z1#2NUCK++nb>U8KICWAizt)EFeO!6kDE!Y27Jka$9fg7F~Q?IvVU?6$`K&>4SDO>gvTvwcQ(Boo_-w+Z?AWqwPGqvsbRy<|V)@3GhW(5 -{0o9b;?S>#kY7$9w2USThxJFx2`(@}Na*tXOajk1_y)gKQ*hPYJhJ5DHUZHO$OV4P&4Smcb(%=5f%OP -^LYL@Q5aPn!vb`B}t6z7KNTQn?0#ikh6l|g&+x4=EtK;DwffVk*%z4CyznJi()VKU1Q5K2NMW -HA$4xyi?Hs)E7!NTIxMMAh>XK)rXd>FDyqEG(4}l2o>m10AkO;F^-oe&4zi~G(c&ty2Ii9zmK+hd4dJ -t(zO4z`MPZqbcoR8KV$|T>4eNXgGqP$KpT{L3U!@`}15`wot+Aokf7jkaE_jC9%LX(5ho|*BHJCpUQ4 -u7Cp8>YwNQ>3N~(eImy?|?6JVl#C(tq$=V)fEk%Y5KMN$kalsAr`N4+K6c%V4oxwmoh+Z%i-$F$@eQ# -Cz!TDVj4hv)AUu_Rlq&_^iug3NaNuo5K0mDNY*3d1Tk5%jWv;_)agThhBrQoyD38thBR*ZQ{U=q -6JiZ$wBi|^A&j)lzaL*n0q?H(9N~;knK}X&RJPkwwFT9ZCe6*wx#Mx$EsXUg^|-_4K&%}UfvW?E5!ACm)YPQhUZ0`3^I0=%Y+hM!Ct3EGi0w;a2fiu^lDX!7<4^mwQ -nq;3ofxhA4h{79(<+kAfbHLt(mbsKv~v$5=1u1N+T+}M@$vPK5&s)EfE9-&Dp&GZs!N?_#PU`Z;SG^cbJSuiPet|SXh&1mVDWizRmcPf;Qnp}XLXP2FGN -~J96k3(ke3N1ynMeO(MPF_{<#3NqcEhpCk3+T_rT;?7Mw~-1#jfH6DH6{@2uN`}>%xS!+uX^uVmkTs3D+4?D}C?7MC@iw$KEVrLQ~c6 -n`=X%$aJkmN-}BAiy9{~BZV+3AGLlY4n5by`wAy5D`!KHr&I0nf;-S^%@j*?-WBkjPli1dBa%F3p$a_ -*!r)z-*HQ1Q8h@ZPC)t5xNyS~6ST9-#lV+NAUI3d|SeS;=lH*>qD6yMB54cT@EJJ&N*yFZ`+y{(py0S -SS)mUYJ0AZS$)mfPV1ev4s)*&U78)^Aotv7{f~)NKKVMhz-A@sNOa3>W0E12kqHnj2ZAxD*#zh-h2nO@K!g4*+)_xTnx#) -=8Z!%@9{OSP)%Gh53(#u0TM@U%A;AckQpOfDG^W_h7kRY2lpo<#=i<(VFjHhS4m0MEgauGA#AiLCy9-?|ql0X#$> -ux3_!mS;bE&5S_4=TS;tg@DN8=`a8?9S{2jvNqo)*s!;i-2a65U%6F%=nDCSaH`l=9dz -`r2+JZ(B2W*Y`O?X>X7o9bLItEC*LPMc{0}sy{^+ygzu`$N{dE4q^4JwkDuf0RkP_h%gYh&(NWel*|L -c6u~4a_5(Gz{p(EOl{)!+XT*PnOW+%wKL_r?>QAm2>irRHoHoVE>Ga6HxBw$AH1C1vEQ$ix9(XJA~l$ -#*rO%x9B6~~E1hat?wU~Tq^S{U@&-c5fY0>2pWmGnf_5Mt)MAOoki7Z1 -AZh`V)enMa<4Z+=EE1sp&k^2V%W-a?+^Z#U@pKNzPW*%q5skd}fv~=L9qG+4x2zSl -1x&_T+1xjcsM2%8J?+i4_NZyuoq7iGyfXJV>vrQ4yZC^UM?XO8+3kQ{b&5?sm#Qr-I6Lc;+@TEm35iP6dSYGPz7tj -$&wE^dbuaXzMFX3a|0|GZdju8LW?CAoW1w!P5v&ZaH%mVwLM_^K9vc};FH^Ayg3Az!_QnvW3iu<`vs*7mh+e`EbM$NvqL2;C_YFrEsTX2rY6psrEqlwmSt{pSGRi1cEMlK&o7nR@$c2Y={e4f -zSYrst1s~1WX~_b%I7`z-X7zo#C8DX^2?vBkc7kTQ{$cBrf6;6Hor>1=0dUHu7D+UL2$+!^&&ue2scUef#P~Nd -t@)A*5b3<36U>pHxgEl?z$mPzltr_;Kz{j9FkKtQT&7tg(Uk{b0b^l;-4JiGD_~4Xf -1wpA#z{7{?0h>yixVQQUyn*eK-853x6g8QCphLl?}Txq%;hJScC7w1+xEzVmDk^rK5i^(3`Ts9+4EcK --Nc9Qnm?QLM3NxscxyknETNmU|o~-Sr0vxH-9=%qCtulyxJ*L5wr*c%12|KzS?Jb{G8TW|e4SLlV^_g -Jw21(VKN2mZ5>qo4kwvR0hgLDg*ep#U|kj(Rg-ox;e^qL6Is|BE>z$&1<8Xb+0+(52F-dQqRKx5liQf -S#gQljxCRnt>l4|n>Q@?`)idq#|YC1@QMuP+zs6?%c9bbx>8w$oEelagG%nxM>A-26MP@HV;G+1AH}M -eo7yGAp9fs<-7mKwh>7jdP@-)Vx&eST8nC8Air6wT5ccUTO^`PdSWvQ(| -gEl8w8%*mPG-!jRoi1Ua=Ncapw9;gmL(U!zhiqI5OMl1}@I!Ucq2L#0bkO={`@@NfY~M)IUEQZ9j_f -yQYd4ktmiY@#a5hnk+if9y6-UXyys<_E^P&~D32lm<7L63oFem}N%}7E0=pYPZ8OzszC%24Cd=JeW>L -$^qlRXu`50`1xD2Baa_dJr8vQYUPJOc^+WQflOe;@qg?MhU9AB>>NBGL06oIe3RV+GJh|W5b$XK9T#~ -^RepnY_SI1)i>S>q3B!;TaC1>dCb)7ah7Jdkh?-YPH)BlU7TnRP9Mj+_DxHSvPt!G6mkdSfaik2VT>2v-Q?&p;o*fqn(FyF -5N^dt{`aYrV1|_)SvnUKC)P#xew8@it*wu*Uo>rTLwcZBFh=N4ZtpPxU?t#+tc*GKS{PEIM(VhrJ1-8 -pbM(*m)q2IdlbgHMSqqK7b0X^hxslJhZiG&lrvOXu(lEuzGh_;&jjC-tcOiRC)?%(^@-iqH=BFmTT>0 -svp|1`{=}Gt5`CMoSS>}S`tAAbwpE9AJ>U^{w5tWHNEAV`w$TvVjeW+oAm##41h!tZE?(&53bVT7s3d -<_MbS~-T^j|v+G^%3KIs|c1aBCVD31=&K0x{fP9lVNEfD>Tk4cbl3^+m}BOrSAIBY1fmZO{zE)d -<56Avj5X430W?fgqSe$y7BDaSt2VkQF=GF!IFBRlghf4iTtSCSUyhfD4jqL%L7s>l6$A6x*iFu{;8-J -SMOiz%;Jr>&<|Y_u_mw7|Gj!UI#KIdMa;(*qx&{gd^qJ;c*4zhw14~Ib>AmIr1K==c&(Oh>nGvZA8$7 -Kh%T2RJps-BQ2ZK!l=Sw2QCr!_6OkfXqvLoku61Lx3xpvuXt$O$0(1e|L8j>pt^!@ioH(N=++oZKRag -trVcz{li9U!BMnF*`r8q(kgkZVfnZX>kL_rj{F^sV}PTVx3IyioO{+;q0`4MXRY^A)=d{k6J@mbJBYJ -zlHCEu+-)R`wZ2NpGVjXwo7IObaPjK%QQ4piEyL4{foTij4cdD -(t8|&Atz-k&}X;%FfddCg4zfiGS#*%4q0)Me3!o7ii0}s~l-fn(V~2A%kk6m{?W+v>CrW@jCJ=4!ksF -G~|5HvI6nSeRmnMAYEas4m+HzfN8*UJoBnh;|IAF@#$fI70T$-n4RQO9l^zcDgDV(j8A8t2dW8JR#Ph -4%N?=viGWz~V!HKAq}TA{5&_`2c69~fLf{i37ebHwnK$Y%wB2$bWXlbi72$Kv6UP-l9Hp4BMLaQj<#+s;u!u-d!F!{|`)%<9=YbgWKz=O_)cD4bb=9JuRqi -j(&Sd&kN3$1d(uctfmwFK)Cg2^0f4R_4wiIUA?W=WmJ-?SG4UOb5ft4s&WDt3M*_X -HD`cQFZFO1I#cD!J;zLTf^+{APd5Ah-Es*j -9FiLhV`O0(>H)_FN;rF@-e9C!?qrk!{^$ej}M2FY>>@E=ndhr9v==`Kh4frP*Za{B)IY4l|Lt)1_H%l --SSCl!n~yt38kJe_J{x;AZ=SPBd;RMtO({9Tt^>NeQVjcFDz5O%_dW3F7*b@IM?mg% -r|*8m^kJuSdE=*9E#Oj^i*g+P;wl`Ya~<&JE@PX|Cb+GjPb%-h>P4>g>H9lw*P9i*jUjzEEr@IT10V|BSm8ih(zn2^4G -Yn0~XC8*9cu#EPbCXz-l#xIY36h%Naag0lffNFUh9)?^y86fIaMW{M&B)muV`w;46pALiNo48KuvEIp -F3?6}#uq7QWkax*N=-?g0=NP;SC<5caY{49F(qOtO9t^w=%V2d#MvLWhH*EnfOM>Nw)0iP*|Fi&3|Xg -xDr|{-3cXWY`=6=}Lj9d~4q|6q%9{aH{wN2SM;Qg_O6D3_pRuld>4oKK=Gs|KX?18A8?1Jl9qnqk299 -_{mzRT1bNObodV{s3I|@OxnbA1-S8gI#hu%6edzMv6oI`AD)GzC(3HnkJZFcOGj5%d$ACkO3mVCVU<( -gUK%d$qRjj1rh*GnU(7ZX|5yG;gSb=e+tmYZ*X)%{^$Y>Sp|UIt-maQq!;%20#%&sBCm8=L@b7>u)fH -28xh4JNZax-(9=aKOYKlA-E5R*^qf60n9A&XO;2??z<(#7)uGlU>~v%W@K|iZ`|RRW0$It3d`yA5GA- -YhX(XpmS_Bk7^1W8WIhq&$aV~_~1*qVTF{&MBluJh2Xq&h@B>32Fc)<4^5E-hsWIxhyftx1K3M)7i%^ -p8kslj(uQt=yV_J%#p`8@@&2f0X!J6eM0#di7+G2wzbP_;6+2jow)zP(F&BGOb?4a+h15UWby}@~cC+ -ldZf@Mr6?snh;=L(V%7-#L{^DQ0r14T<%A(w&Yw7`42S9m~DtAzC2d?-wo&!~UyTQ!-bOWCcZZKB09b -AO!#beBa`2##`FyF?eY^gGVgfz&3Us1{@94;IAfGo+jhOjt?e7WA}0B8>0gz+ISLM*_{M0(;nV$$9w0 ->lT9Q;or@W3kzkn%n)h#^TIG4iJ+WH*+)x5A|~DYpnKv!eto@)t`zaQVrS5_O(Eg)~S6OQ@bN*woAWDZIdo@%-t&AIwp}pODyTcgOGtlqfvx!Fk$TnA2%U+osbbbsIC~#IMaxry-1pjENCO?@GM<+2+C1M~As)PWIlyCZ%6{CE -yK9FiMdFzF+k|pw(L6zc#`Z*NvyT+j#yqH4DtxJH`sv=Deu#eWofTEuryrC!P&KrPRIj`L&MStC8L^#j-UvE_X#+fNWC+aYKFG*<1{AL$fQegb;dN -dZ;~o*=)39QDWP8!`4_dHN~X4zYW$GI0eF(PR -M{vMAPD_Rmf0qg5z0fNboWy74JKqeC~7qM&;Tf?;ALNNl-WSO$TdiSKFcVC_{ZuuK+iMEWHJOS;2GGS -qSd#*h9Aa!4PukEeSO}U3mZX?WWqb_JcJMF_oe8+NE^Gf>4Jxaw6=t7t098=2!HqJ#*YFt`k2hB0`fv -VxgxTz%swZa`}btdh^K>A(nFnKjmfehKGRcX?F#a=d^Yq_6qh{y6(Kq0EFj;J9cuOv?6+Ce%3XgV#nn -AIOnv|Td}tFh5EQVh_jE65S#;QWa3wo!R=lXWPGO=RY0o3O1f?_WV-9Hy$OedmjZ-{cYi=B}}U=_pe< -wXKzdHOP@TyyzGwhU`TP$u9GCmOL`EFbD#(d_P5zU*IkZ75p^e8KHz66+cQv|n>STSa?&- -BkuWGg{*)cYX*%t!+R_appD{lOStiK@iYJdM}3{2QUi-REqab@^cc##eD2!`$J%UsXTxJ( -Y-MVw>RB*tJmpHeq7l2Sb(}6eU>P{zVN;S+$VY)G%yJk&Qr;1s@JFT(f)-dk`I7VKby)k?G*F2JKg&l -LYME8I$gcN0Wgls!i!V@ew8mYw{|zkr0cIz_=4$kjX%TutzQc!Ys?Sai;jbQ)b=H8kekw#GY+Kx^x5J -r0nL!hH2zlFAr=vUfXr?TDIm_3)FJsiJ(M-xg6U$*?9d!3z&NsTanG02Jc#vEzg(^B_7?Nd>jmC;1J`fSEn*b2Ph9eZ;0i}Sx% ->uMu-Rj_6d1w)CFI@emR*x>P8C&?Oa=M3(LSnm4nzL?NTdNKB=TEHPvGx<8!o`m+#>9D_7XTpBb~Vod -&^$xb|sWVfz$^0u>y`n!TfZ828oJ1IiKT2vh_anc1o737@HXw3dv#$fEfj)>s -ZinZ7!p|m1*#bvRdX-y-mLXt0h|VS8;jtoUgTcttmZY7QWZW#L9dI!5!poLYqeu-de6_b{&&lb|{Z>u ->r~S6ww1-FA8M2hD~G3IDFHu)#BG=I-nd^GFf=f|G%9038X`B4>M!TBx)`Qe7?gA%Jb$>_FxNNxs3ml -eOTcnmXxPYzUe4V&3jIWneFZhrmV^9X!2%nhkImKmQ_n3N{@+h93sTb%wRb!5Y&taqw0eK_%>vND{<->P(1(O<#Vs -_WK`Idft`zR{E-^bHT;X9n}T_802L=0~>7SAl -KxszB3(u{Gh(7NkEKh0~vqsB@adCrqa1WU6=VyBb*__-{WL_f5ap`F -u83@k}g(-!ux#Vx{gWIgLb(kvuNKGR1SY&Y_8vyhI7YI2_X$RRraHFbZjIIUgbfg{c~8)wL2wT~U|~l -1Zs3OZCQ#*Q+-~{OLRx(M8%-VddsclFK-IIQBNTgF9$Dq)m-x*^6>&JQ3~OZhJ|tk8M>zs$gvCI}i$lm~7-CMfS -kr{g3PVjDxj%Dhx9eSqnU%X22=VchdxGw0*MAaQfe3db4s`P20b`=BeGQ(tL+0(_+-ukUstDob*>Yv$ -TIakbrUy2lS5bTGutwrN&f&K28AYFIT7%K8DiY(wz#shXddA5Yj>TZ-|J` -PU;Bnb+?KDoR^XF@7wZO^PdWEqT3u)U~VISXq53kumgiU}4&=@w(br(^c#a4%S{g2`A{}RFzX$#yKMEwfXXOSEnb<1vhYeF;qbu>MgylZ{{n*0^#da7C -Y|QXgq?jbdxKh6ZZ%)1oATSQ1g;qj7x6V!55HbI8+@u&Jtm4ZKZ#Wu+9Ob8<7|zoe43O^}a!~Ks<0t& -w$CsDp_o3IwSyjwW&SS91-dF8*SFDt?YhUW)KD&p{;Urs!>@V?i6F?1MxQ6~-dym3U(PK{9EQ#nlY2&Q~pZarrgpc!k77Q-TTAlY|c5x4=mMXULjVY{w!r(=ZEalVqk -&cFuc$cvs#wn!MdonivCnGXf<=NCgTcq29bb9ho23S0yLjQKhPKV3fbrbk8hXq7AJyjDqOO*>F6p8cK -UEt%h}0yT?W&b6R;Si6joQ?DNc(=hqVKs&%z0TBCu1L5Q-}`jEQUNm+}xXkfc+Q6#*r7Wp>#XXE2-j)wPm<0HVD8>F#}>9`s*z{G5_!arDVBP<#-Cad8NLV-tnqKq>nmMNa1o3 -%E-9BMb&L!xx5?$wz`obO0@HtCoIfzKppSPheGomKlVQb>35I;T_VYq6rt|ph -3ACM9go8&({0(zU9u|4jNbe@`;21!rF^edIrw9=sXERms#(;zvh`>boZY{eIgO8nywI|6DDHvi@2IC1 -PeuJM!m@xsJgUvzgb~B#|KQ{TGO%0CJg`iS)pzOr~`B@|q@o=#gDgBYRoCHNEpoh$+X>xtij2~X`5d< -ATt{1*X3&1a(uMAIXTdR~otOa<|b+F1kR&xoVCbg1TQoIyD>nNcl_cHb{!PkGOZKr%3vftG9z>WvID4 -R?9dN87*pm=wBf>0^eC)bcRUAbE{C(AC7#O%g-xO?A@=PnCxr9y+;ciaN=9@dI_^!P%AzX)gk!MkF6O ->E152mWpY-R#{i$=U2H7{~IFM|X024F$;k4|LoNJ=s#0!aJ(8X#L`mj5zShRs*Spt%YVQT-utz`X2t#infmdTK2*1Fm(w;}8qXIL -L@Ye8Q$p-jgm?kHR^$@i?EYE3xGO-?aquU_a5#MIn6@_FuflGDL!SzU!#m1iT8e?uwGxLZX`>D0w<^6 -hbweIfUEDDff_w?U|4l<-}gwwH*+>iIO;X`ulICj4D{5xM?<3 -B?SJ6=Eg$~fa`s3nP3H8_WwI(xWdvD9Xb20^6!5T%ROxZ<@tHxN?kkI@)p5jh%TTCA{R_7r@k7whdCz -83s+Y*)<-W%h$alSDprW+#J|ms8K*2k)TzXlbq_s&8%AX%uV$QllSUzj*t6^5(mrL5jH(a7(Wr&*WQywH*>!Bcq#v6hW5UGd|2g2; -q`gu+yuxV(=lIA^vUA3)4(9Ld(sZA)G1L}3w*Qit7r0$sfp9GOY%MpG6T~0&Pv7H`pBBU{NIb}8(@?e -to9!JlkcQGj&zZ*Q;5lP{>jkBRbT>EDT&g`nr{$c>Q>4b}zEDF?)=qb!mRT2 -I>b-+(jbbL=9_XXPBJpUIxWw|^z&<*v&4HI~zwHSfzFWeJ1BSaDiaPyCM8EkxNgG@DFnQLe~JVPoL|L -c34DMtSjryjBO6fGNvR?_K|}d$;@7&(w2*r|}=e6(sv4{}mLSeX?w;vR(ii7^EV{k3sdr`QrNMhZssM -YKhcaS?fXy!8}FFYgh5s)X%lAtCXd#sA4SA_+@8)`@Lj9$*mL|IXk)@@hEWXLS9KJh}_#=Kg3aWTN)U -ufaqUT56SOVH)N-Gr_PW0RI=*dOFvB2R(v+yK0CdI_PW=c{YP!NH3EgT!>NtxWf^%u%PjoSocb?Du~V -T~5Q=yjvT1ar`YeF{i@Q$JNEled5!x+$|-l~A`V@Vkd{!)Ae ->XvJry`h^kPLZ#|N$vczVulFHH412Hy`IKM8BR`6T@Kdpbnarp|z=*$hV)35>D3 -2yNlteL%f?!a!)z?3_|cKag%i6~HMw)?;iFX6^9Exw -P9=VL%#40_dL)MIqa;73P&a19_~cSLW)KMk4yvDr=Czn~nhym+wBz@c$Qs{xE9_*9l%%fs?_)Nj-_9pY0y};^$an`vdwTQ->6U`Q6 -(;pZp=vwX-{PPYD6PX_T|J7ft_>LD7b$p1~X~X$!oQQdHFvH!>JpUg~sq2Z-r$_6!}1n+;_UK})gsSo -u9F^2)w}FVSxU&1l#_Ei-y1PS{&1R7@Fgqa-!=rfi^$v&2i7{VVk2BxV#?_hIDNX#tGRA71!C;C)??j -e4a{b#>`e+nqZ>r|L}V)%>nT&&hHTZb7uFLa39gdh)((Pd0n}Z@HaQL4(^D%m57(*!E}Tq&hmd2sy^3 -I(wFbo0_|z;Vsvc+Qjg}@_pWXHAContFvJ!mu|ZRnm@Vih#*{MH4YEoa6f@MJ#yM>2w(eYAySQ3t59Kt&s$(#TmLJaS@*uDMJPbNUTS0Fr*xeG20bhv -`6b>h`*#{$M6L7)Eo%gE)qvRo`bweul%cAO;uc-}LTZE~7uH)X$&pi(%wLt_mkmW|LS%)YnP#x -E#PG1gK}N|TD|=!LO?Dt2Go_ePvo$LWpLMH -vdjCqVr?BH=M50HqZRnw>$&noYysQ`O`7+3Fu2ut|1HHK_fvP0Th~i -;|336qt-Aj~6pHl8~u3XE`8Eib@EKt!oG#Cs?aAtQ4$FZ%D{kV!WkqHaM`*HXYNW;1#OX$==3hH;_!YMxK()iOPJ_@qQsk|82m_72Au-so -0Uqj!gc|jzh{9bAX_G`j+?6hwM8!RWFaduWwCZs(+ne;ez*=;3*iP)59Ht`5_ZLdq&e^{4em1AmCId% -;LkGu!f(zXerPgE7Dv -9n?hrS1qUkaUMR8Hs=$;E*Kld!Hqhh2Reke!my4;_t6~Z%zf0n0crVfdSscv$2=H?bIkD`1n>m8SbwcwGFvzfKo{b=FweD=1+D|08x -03?X2)yJ>~J{?an3Z4=mzU%bL^juH9;j8Hc1b&VIKu#(_a>|LgbzG&tCLEkE0pKidNLd)f1SF=8f{x8 -A-Mpo`7}5!O)1!AS(6UYu6r`w%M@ZD^6471tuX_<*q`SGyI7hQ@Klz4I(|zvfx62Y60mb%Zt -l$xhWL2(>NeUYL#Zpqj(Wy7V5+;Y!96>b25^K9(@Ex;T%Rh+`_OB9JS>#XA!^dwghHOh8Z(2neIb2N; -75VwBMz-@E*5WsrAcJn8lrAii>gEZ{H@)4^>V0%w<(41YkxV9v1a}xGpwBdTg1*aRzLn*;>kOuXskox -y6+iJZzoN>33Rvg?y&_((^ZoC0_3(@}|K9gY)&cc;4aw8cG7I_a(JL|Eqpj{?ujS_{t!J`LcOdN%W9C -88)#sKMS|e=997S%FAAiE4Ct|uWdCPm}+ZQ$9bN-iYEv?5w#lo^dytcPT&rxe=6H%GQs01(0nB#Dr2k -?F@^KSypQbtaHOudh>k`m{$z`;qEt+ixK(XnWOXZ+VnQhz^RxhcUF)PIhZCarhREYXF`Nz0Y!ykeu3@ -h3?UQGQlF@H*Ft7sf>P<2W{&Du=vTjGL=C+sjwaU%rjpzl||X1=mtQ2W3^5m7>jCuu|iu*k_N!L_@8Od -50_V=mtaGVXclNAv&5>KmTV{9xisDvvW+DM3Zurp|w49$iqTOV-cEm6qa~Svmp{o1B_(~ag65nF!HRV -0CK09f#zRj-F3AICKpxe75a-})l6($8L7g&t?^x5<8pMUe -}Z1U{Io3~?+jN-=C=s-$A_H12Dk_={mv5W~XCpBeLh0YKiyya(`h)mj)wg>C`;q@LSalqeC>7P6*>~4 -^tio62d+O4Wu6|x9#rt~b03{UJ0$NAZdX>4Gm_(LR=;!wsZ7?&j$+@jLJu){$&?lIk^$fG4U!L+7sU0 -c8Gl4HP2ky@Vao`j{DZ`HUV(wl`blPWAvUz4FVqX!9((UafHBO%eDgqoDqoM{$Q&iN73{f&T -2g4-l`9EfUN{q`lKCLRMi&}NQqXAK>-lY)<-Vi~uB)%-9%xMr|&0M-OU#N#a_Jw=OS=r5IlEaCTW -fn#|4?#K4Z`@1@g)tch&o1MUf&5DhH<7Gq@?#ku|`;A7Kk()7`3^05@Q^dKyx~#4(CZc2OIpq2*sDWT ->qje2i7srCs){Qxbbbu86ZVF-YVAmw;_qt0Q`W46E4%ESPS$e_*s!6Lf5wFE+dGDtYOadEpO&jHje0<1by#WjZuufh(S2dM9FFxUq!MZj_wms -WHQ1iT^n}SquoVJ6SVsT3@tTi~Z4#`4|DWv1rS+Pl=ahi!=fThIqHL{-)1{@I%vH7cKc}An4;SKYvK~&+(U!zUWK9(;sjmJ?FY-* -HUD9m6bRNWeJ$F9S*8`>E|B8%&+7HQPp;ihqI-tf~u4my;vFZ2(7VA+=(R&4RpP>Jz!~Z?-Ji)9i2>5 -hj{rM)*NP;4=6W>2JYZaOoWRDq_e5WvL|*uMxH2gM#VJL<&6yoVQY&zFKBT|t^Fu^_ZE~jEicryQgy~ -L4c-Z^oa1g=2o2{Y`mqk9(8hb;hAvM;>yGf#Xz+kFn=3y+=`Px-XSmMz!fW -_Jgu;rsuor@ZTY@xcHL@!BByGR5a5jz<3{bIth><{-W4MfCHI&4b*2-;QNJfsyrTYU>bD%9nK)U!D=4 -p6zHRg?H^>uE@6IB-oqF1=H<+#-PF>xdnDsMD!FEHJ^jKmdNoSgH@4np^Op|5tvH*&#;!*8gyGS}4_> -4FX&-(NEw_@PI7XhN3M2)-aFxWp81shzz$JwizDm+_8%&09YJm6YIfyI;KqQxF-e?WECqgeDdeRL2)u -b)~7<2ULj`*d4}RF&}%M5Di3t$qtu2Rey^>tkH#f<8U_g25bO&BM}bfc-CRt$98w4>0*6uYZr;3)1h%J5&E=9 -ozB_yM=Ec8fpFe!~2lP0|o)XM4>Wt<$i){GC$f)5uBkZlw-r$_Kx;*<1D^l}gGm~OQVaUT#b_2p1UWF -vCkzH_Att+lZ+6BaI14$5>JQ~bA2ZEQ -{N>)d!VpVo&2;H&7)5F4KH~K1o|Rj)NY|8a<&tbvL@$v&D_XPqoRqR>;c3+qZpr9vIP%95d7b_G -@$6JIThG9hF)LmO)H%54LHO^%LJDIQ*=u|`^gR2OdotNTIuGt!xoSCrP$g-w0&JMI!e**~x3#eCT6AK -xPe>;wQGK7vQ%%eZ6WzAjO*t^(KES_##!%oUn{&ymBh{5C)A5fxG!J@l8BQ=q@MH3B;a5ms@8$fbfC1 -8+KvP~l9$CaVqEwbP^B$9}KATZ(DSG>X47&3hA_1}GfI6Kkb#RMb03uIbKKV9iEhoor$ncM6{|!;&>+}D0a&dp85 -7P-ggNrHgh#qhD*nomWdzx4%NRz+L?}yHve{|o?-{xN!;Mkn<{QKvx|Mcq3^Xz})mluC|`Reuar%&EI -hX!`GDjXA)gJ*C)whnP$u?ej$#mbK83B;vXV2a)fm37SEkol1Lk;5^WTE#2+UOal;>2NgWq>KC~8m~R -UOz;dbj5l+rfZSSc>ga_O2NN3xzI5b`BaG%30^@sZ>tIP~puPp|XkKU%p``BgE$oCRY}@eHu#v?18uv -=Kuy8&Sj&KMLa|556Ou%+J<7oW81CkqcL?f^&`D3iqY-y-#oB+ZTNkYlaKkF_AFs{K^LyD$uqz!+{h= -~2pe@705#i9MPc7$utNdYZSd#y6(W8M%D(8*(coZTzhOCYcJ?p@#DUk8-g^p;Zt*tBbI9AlKCYU{sJZ -F{TNF>cF9sMH(ujsNl}g2g;k;EZ6O6)kM=wq%}wiXEWFW+4^J%0&*WGU|77Gd9W$nt+s>F-i4`a<4;&_dz|rNJyf&nwfro1_1u({UF?8o5YNQ1I_8OV{zI$FlU5X0m+zN@e6=B9p*?+m46o#}dHE7KL82i -XxXMxYx0OSu(C5PF;V9e1?#=941;o}r3T4w=ygYGHT!F$yiuekeKUl}dHNy*uSMrx_+wx@46zzk#=H* -ZANhHz5k1^cV(<6Yp4;ErYm0{{!fr8C`YK#65C10jmD*|k_~ -vLO%VVny3Yd?m{6yd?Ut{%BJw;<(KD?s{$sQ?f<|jIxD2gAHuT4j^JTAIH?8e7>jJZ>nME^2txx(bt9|6Y^NFCAmdy~M=6@=mrtc#_AX9xKh4R7 -lnN+$_k?h+IG+h&3TJEYut>rAfd3xo;6uX?({ubXxKLuf6oEHSSn-rdcMAP+4>)JM6X^@j9ly%O#{Dz -S-h$@-=n38V?+F&~O2{ATY5MN}AUmx)3R#{Ue~paF;l`zuTt5nByTkEj2VtHy{W) -ey|JKu9d*_^9P4TlLtI_kjOKH^H2x9We4y-uoeX -sdh&*2$}aussedV!AY>I%rvXb#ZN4fK*ZVvcxp-HyWN8@EX|BaiO?*Xv -#BY~YBf_C|lL;Lz5u#X(t*9V7I{@4%AgzP)Hh?c`BWqJ$>~b3tK2bYX`Bs!c&JJ#@mJ+#G2i!& -|C{fvyO2(5_6@!DeaQBK5W?^<;8Ho&Bt|j@(1|P^2EeTmAII4bS6pFDa$zV=cU#V{>S|6XUSu*N^E@y -k*+RdpAH(?X-~axhV@>$Ltl-#T^|fm>xNJSckv&XvJUpzHhrduRL`^s@LJ23c!pX7Up#gJMY`u|e34{ -o#olT;LidUSXMAmIYy=1F(hZ7=?d2C$S)D2X?IeXJME7DClSgo>4)L=-`6|yC3K)9AH0;{Dpxr8!_2* -k2fjW)gOTEa$jy=^b0kO6YHHy{k=3*;ZRLr+hJpTW=i(EgGQf0iD88Bsveti+LtN&_v1viAXRP{UMYp -VIX&HZ>MGxgZ55=}Qj33q}R&I5Kj1F7+jbgLgIZ$(bMc6H*$nqqs3efHMb6ODT`m?pH!0`rQ+OkibDfP(epODs3Kh*1oRtxP>q%+a@)mX#A5W}uoQ -&Ck+GyuDNoI$f!fNChz}?H%VPN60c#iHN$wJS4hW_!9z073FM1BpgVcxa4!#X-+2;<*4Xxl7TZ;5U<4 -q5Y_I^2F2i*@hXn{+?`b3;C{OJj1RR4N!72f|xLVR}e2uynRsg!+BeHZ}Rzu8a1XvW3(O(L!eA2~zJp -IPPUKzoJZUc1a-gZILbWj`tXO5QwsqbuTcK&9cxj -ox`};3{=lV49Qul_angLq|0GT*->zASs#Po+dZ>L&;PjAERt;W^u+pSnLed4&m!bXH)9mUOVO3S6q*_ -P}x|H&f*k_FCi?zp>`X?hKB#U*zVr6WJ1LM_V%3?Ai^4EmNvy70I0{xSc5;AX~HsKI3*v@;Yd$U) -|>Lkro33w;mtnqbA^%c-%(hvvOmhjE^_SC)^jO;)=`3^y2-lT{7MMXvMeZx&1bFk0H#ez9NxsvmYcY4 ->|vfFE}hkv^}(cf!@oIvW$jzJVB2j$x4U18$LLj8m&}WDcIZ^$yiwNFx@@1x5fuXCs~y863sihCC%nC -Co86_@dU$Xuv!BEQPXBoRJACBKv7Kq(7J9tMF`?}2It+_1;gnb9WLJChn*i$s6rWL7S1XjbNzIbt -*h=t+i7$CSV<;;gmDZiz5;6{>Kgv`2D2YV?BK&rR=X_GNJHYQQZ@5QVoFgM@a#M4BdXvA@KiQG^|?9j -v`ZqPlLnVsLMCiAi+m4X;m@Fs9H1z3$`7ov6@jR!%HhLW_dM$`Q*{VJ|TaiKOMHUB{1$gxAP|h^s?BY -A&%e1$LM(l~ZF39fb}gCY@12jOk5`K?_sW9kB0{#)O)gAWA0#{4t@#F!?O~#Y+KH0va3;jby-uYhRtras^;_#Nz5c-=23CLkep$A&jn@@op|Qrd{LYN!D6OMZ --=|^WhVY)fjQ|n1Csn1o~7*&?rxCC0&5dO$PK)(KGFZC_hQOKe%6#)1OKoT(Xl87UXu8c5<9VQy+Wd$ -dtjn4xeo@?Ur?277vqFJq1;eDO5cIR4b$jYWT8?X&1#+W0-=Tz>6NS!`9o58$xc#5?y<=&@@1eY{ -WVJ0Bnb3V3Sw4isxk3QF`f#GgykHIGmU=J-%;xi-Q#Fyw*$vPS`yhgN|~K(mEJKztdGEL71|<+o7Jw} -XUwO~n@(}q)2X**S{vQJf?C2n$5(Ntc1=68}c4d~XP+$A4YLfzWxZx5?s -Z6LS*sFY~UM^Jp(37#v(^l5Ib%}QFVI8Kqm8o*2xl@`-TK*R-?-BY{;x_$BFfQg}ipj2{^m|Y(jt`BXZt!0?$#$m-49-^8)Z4o&kgznMon2TQIiTNDcJakh2V@yh7L`(&P0*CQD1qIl -ANZ-Bu=J}g9#xsVg#SAObQSMGebnCW{1N8`Wa^r?-Sw_50h_9GN7onVQ9$)lqQEIsa=q>6h^Pyz~q@7 -<|Mc}-tm#ZKu(|jc5Gt!UYhAy;3qdI6+r<(;BnZU%mP2(e`aPXAqQ9n%0t>>(4R7&*trIhQ|##G?wHn -8)2z1)1Af8}b87Ty1HCQjM&k*&$3Hjk^O33Z|w`Ta$VE{gmhxM>awVI -SK>D6Hk5W}z9r!uMv=6&_Nsq%UIDt-f;4q~%0IkwfS4O&ajMI0vzbsXkffp+X_WyWshyR!IrG88EYl> -%Zvwnu;Q++&)}hBl`>;B9)B5sYVy5>Es*%g+w*I_y8t_+qCyQ(q@lJtpHO*FboxYlze!zP -kDHCyIHrbwmb5Kr2;>DAb3T62|EKcUdDv;tc6ad&z -7qFy#y5$nV+KL6LUC_Nu?^? -V}FN4Z3T_|>_|oft2knL1?R@60=_v%oK!8(1?DEKdFs5 -pDEV(f2<=u>wP0j6Zx(yS+E5myUlp=+%o?p>2FijO%(4I~WHcb2?`EPKa%XefM}~ZtsGc$C;~+49mV> -MFHhH+WFh(Z=XDS^7e@kr|19k`Tq>la1PJk4aXOl;%NA8k>8{INW=5-yV1qy=n!o%u^PxuSZ!lZwvt6 -gLVp%TW)m75cCt0_qdV%LzE@QvjhsskI%4~sqFd*>s8*~TZgZLtM&HwSGzS}?>ANnRLjP*^xibErbU~ -hTM*oTS%dHdqq5JHR| -}lWhW@B*tv=clX2F#+9EkO)JHeAbAnn$9sFT3)9QO7cd4?_V?(E3t&$=|WMar2br@;V{d0~W7oeP6iE?3PA*!gr>m17Q#;w!xEww!VlP@^!(4B^<{1FXCUOSM -4hRKH8Qb}g!Arp%zKR!Zp-!>}|~_TV*&d;oPfq_L0kchDAp7n_Wcoq{CL7OB -N@^3OiMPj7`=f^WsE)H|aARjC|9W?`hEVGQtIH -@8R8ow|MFV$VsUXbdQH!HoGoyq)s}@8*0^%C6Z+K?WN%FLi>r(9?p>t&@rHKt`9(TKR$7rt@7|ZJLOR -=!`N$c2vu!pnXkTN-+#$L9oi87Stei5b=WGp~n~OdJxoYB{G%snodS$}+96GnX%3i*Dn>~H<%{STGzr -J{refRR&tEb<6`~2nG=g%@=!T_C6=v>ESl!@_0++fcFNX9<}ostbFy-m`zi -jofN>ypUNuC_^t46o*=Xzxu~WZOpRgkpyv4%GJ_9FEwh*C??gGKKyu$yX>xzFde4el^ZUT>1c=l?)3a -l(1|s0`NgrdE)6Umoe6DqGdyh@)VOtB-5(IX;FBs+g0jkJHFtd<6HDdLI}neQliMLF+f;HN)H-js|qK ->DO0l3AUDd>C^yQXEFbACGjY-neUklP_jqx2W{#)pjW+{5uHTZRgCUsmMi!1P%uN&VJoLCcRZ4H5+e0 -J5{NJ5gwCE+6M%NlZAu};U3ZfP8bDTZFG{C6ZlmdpI1+0uBuXC2_zRze~<8L^3H*YGGoLNTB3BprTQ%V`flZni-dSj~%^T|O$&k3#K_s*Mm+{ -=VV}J;A%;&*;Pcacnbw_{?20FRe(jUYT$%+lHm*nwgrFajr!#1ZtQq3w8w}XSZfHW$Vq8-B;&XMo9&Vh?Ss*C~1R>HCqR -6#my>`^O&rVv>{iG#OUStO$kJT_~kPk8U@n6`&FN1BM+frrh%eEDU}8De3@=d{}?MInp1X0yW3XT3l8 -$Sa~1%65R%aBB?Z?J-F$bX{)>z!XFMo}-jGok}YZK}pOZiDLu%pf;UcL%5kqgfToimtQVSl3!fnl3_} -R2Byg*VPUhJ2+JbMK~;Inu@oW#o-|m-lb+?7lgX$!alPkYV19E}E{$u1C_#9H42}m*Wgqqf%7Kr^o3j --c@`7FsJfY%%8xmKu7CID2rmQreeYv{3fGr`hP+8ND&Z7iWk??qQ5w($aW^7c{l7@6psTkr&+}2H&#L -`EPIoEJPE=@0kJp^etoc`SC8sh*-jyQ+z;UEX;-nu^-Nfn+ifzqD-by-w;@04TMSD(*VkBCc -azf9!CgE7S*B)^jen&zbohSL7Hx%fFp1cJFh-=-Q>h6If;Mr`XsyJF8~`C<%Tt3A+>1&SAG6I6Yp!f| -TXZy>fuNe~R_4RAKhEAD4W0A3^70IEEl#qGk8L76)PaEf4a^IBYodAb3VYi_p9rpnaWrdKgTJ%tYF_L -(R(nr!yQhbw8Zubmg`(Y^f~DPIuBBu9wv>SZ^3$$>4Q2Ckvy?O_Mr}wwzi3MhT`W1{Jf_$}jg8eZ`fm -@9*!2qV5Ix>5;chtfmSZd<)c5W&b2)!6+G5`1wp3B}DF4Ege}#RT6kW9_hs)lIT+5!aPbP+wJNxenm? -^bcS7_+0ekzBTr&fb(FOxU0IdC5ML1va6t?I=k68S~Bs%9ng{(MaX(^Z~y#rtwG5@Ki?pJt{g*0=nNA -rF`5gNZa6{C|yIO>e?54E-xe99AT>A24YLcH_oj(oPcr+DZ}7O=W=g?`J>TsgnZQ4f>I$Y2vTg?|lM` -1;6#=vv9~ex3dx@Y6hNOu2mI9`k19!vHH~u$0&9PP~5D;oBdSWzDI1LEtbP-@GSw8S1jWWlCs!3dsSzV< -M>c8q4Ff(yBY`u-Arh7k~LUm*36M73q-(E5g3?zrMllXExNbvy=jQkP;ENAhH@WMaqDzSOa9xM|LO$U -mB|hSVgZY;$aFHRKqA>PdVC@&;TpukLqJ3P$->GArSznv?)?aurC$#iR53hBY}!f<_Pl?N0seuulBVo -J6(jqa~2^=WfmazkkXer4y#iSbSf(uHE40BAJE1Lo-M6!#M$AbmKxH5>OzVC$zX?lav|(?ytP6Cz)td -^#?@s-)PS=&`YkZ=tC3MmZT2RMB>#5A|=04W|D5h`ousUfZ%s+4i=T0N@vUBm&(`M7=nj{3Z=1QY-O00;m`Rt8fdwy#T70RR9=0ssIf0001RX>c!Jc4cm4Z -*nhiYiD0_Wpi(Ja${w4FK~G?F=KCSaA9;VaCucx!EVAZ482$CKX~E-5^L9WLkPiCf>*2plm%bcF8cQe|bwW*^i#(e -;6{)du^I(om^6ApN!D{g89g}Q-oiZqlt<8_WP -&os8gMtBUtcb8d9_ztPuoZoen;X -z9F>PS)J>sMUsk1CHyC1Vuvyz_Rc$59*pp-y-*#p~l7GKv#+NwG1*mod0%zu&?_B4b<1-lM#hTICT!0 -q!;lst{2e_pQxG8q#DC<>}|slQaB`9GBT8_Ty%&l?~H*bbQAOxp)0-E++L;7Kxw`1$pw1=kDb(DhdxF|UBDg_-3*Yc!MXX00hauh7W*k%c;vM=+2z9=tD7 -ZY)3DBzpzYGCzGPo^wSAqb`mv0x+!fTl&x1orV0mE9xTk7fe*vq<3gMkUIVgs3In=#YOFq}q-{K?F@n -y(gbzl8CU{PebheYA+%*sh0V=LE|DOjGdkcw*Kw(1n{FI+MsEUy`5(?Iz1t)h!g@WwP7-rvqMViIpl3 -+`4a?q@MXl9gDdD=4nFqe@(7PXFr2s^<`S2Gt}Y+``u)Sl1UJ2r^L@|OyjKE7Nys@^*_38f5G{ZB8`I -UVy`l+0r8-8r#M3ZX(k#xGxN&&__2&#c^c=lk6d7OWkNrqQ^jpHLChd7D2Agku`#7!8 -meEys%8vxO`zcH$HI{J?uwW_I+ToW5L?{HS5>~7A ->!facSkf4~dpFi9$1+RhQ(KizOCi-7lE=%8b6M6MS8Cx_i8~VVqmHiDYGEBn7ON6VD_4!Z{u)#Q3@HIK+w>f!upJl%g)3!cxx5s$UeN1C&Il4!26mp2%|^92+bxikYrOb^S1DeMV!d -&SBw@ixtW?^jDnyxwR!76T?dE#{av%6aCwUoshKo+R*^b<+7^FPoy`N0oTYvP9obZk1C8JdoI`CgMjg3HR8m}qwE$~6|_kvfnQ&Q+&T0)n5C@w)>!%7V -)5%9CHth1#nNx;Ng}271V8Ifvldf6z2XeR$2y)S94P)P9v$2k3MYJ>{YDzHw -$VACUxKyt<=MMpmNc)vGOvIKp?aD35u=H9NCNi?mC+-aE}?^$^#r*Hc#O%Uj6yf^U}?yRyFg=+@<+-Z -bS#rxbGhS;@JFiakYIQ=>vzy -x*R`?^!-$$T37jP*25KS^~;NkqZ5Rh3=YmE -^0i58?ymFF6eDSfPGz(HGswR%mx%BfCVq`bwtIWEPiIjj5WU6NkAc-?JAjtbOuN+EC**yT>SIne={X2 -o-wv{7?^*_QxadEBRUbT>GbE7uXiB&(3eF<=f>y@Sw%Nf|Cr%2#?9gvsocA=Ny!2?Bk*XJHA5U8Q^|} -7EXAt@MKN;m;P)h>@6aWAK2mnY{22)CW{k{FY1L&sNiqZKZhvuvWC&v#@ -U_etgPdS_sd=Y#`Ied7jettY(1~l%>(&b~s3iz0?CFPu^3FIjhoM;#*TWPSwa1q)d2_d9BXY``T3FHf -;<7t#%1&lzHGIUr8qO4$9$_ZT2d;z#EY+B?H5dsKV5JoOmFlRxMlTd?_fhzVLu7+uEl2#(bvqX+yPAdOuc_^1_H#~0TA`f%4 -&A1_=a;;_KXhYuG|1O6TP_DM4$21WN8;#DVDNUNsN|l-dt#3#ZIyDuk_ENEGYrgGAIh@yWsglRA`r@Q -1!nf*`)m;Q^jw4=F82(kaS1%?UfHRWht?=-0cOmVpquph6d-KayA>F>ZY19SvaUb<~pBFgmxsX+pSjp -QWef8_#NZ;-v?NT<2?@Rjn_ifVGFE&WcWX8x6GZVyH*`twY?M@a4Iex5`9i9g)=i=kkY+TW#QSXs#5p -cqhzgb|;G$>H~%hKL7%6lX+Cp$3`f}TGp^Sv_PDf3d9ZVItDvjU=42VuIB@=i{%AjkVYVJGrTyym5P$A#)fl3hH0UU@(?XSHkR(lg*TW>u9~imhOfqrQu|I_ -3RepIFY`zVeb#<>E@X?qYqwd!7}naBt2F1L;8Y?W!?7$D95DA8WcYPx9&6Rf+wzvnK&{sQJK4%G)rfn -?MBAEu|9ZrY={1oZy4kQ*o!6S__RSZvJKlV$%vZ{MEzR4~{HDww%KX{bh~+JUaCNU(W#j&+%umYvTx- -t108mQ<1QY-O00;m`Rt8gHiufM;0ssJo1poja0001RX>c!Jc4cm4Z*nhia&KpHWpi^cV{dhCbY*fbaC -x1S&u-f|5XSET@(zRM5W7%}ZBL7$yC@^mHUU}kl5&coC=A7-Y@)U(kW{ic?!UG`55)rQ=KcC49a46@K -?*FeI(S5KzTbQ^HhltTkI!JKOI5F)LF=lsAN|hp(ecp<#JagLYPELITlV4U4^N)LSZTA;7A_l}uQdwuzW$PrkHR7zU+;w3jRN7#|jR!T -YX|$Dat=t-L+eh6xsH6mxtfi5cH?T5A?PM82WAv3OWr@JT;fI9cQeR0=THbY3Yp0enSO|5SgW3I2)5y -Yrs-f6yyi!R!*tM2VD2Qy7za*Rj6ENf11sl>KJR$Ddq75cgQ(QSpF)MAF({8LJW`rX$JIyra6d-=lsjrI -faCg^Mt}E;~quQS0H9IW+aKwH>YtPA!7fAk~m8R{bi0g%z+`9lCd|!gLJnHjZH`{GOWw7Juy#m-^Pe% -Q%Ex5ox@yEtU+?()i^`6EF#oVG|0Vgk_Jn0&a%`CuyoFe_mR?Z!p1a>sn=#fkY^kd=VB*_fN&;!(QKa -Y29*UYVp7^c!}R?;&`WSZISyh<0(f-)+Zgz3Q5n63#iD9mYvf`9YTIbzpsf|&BDvToCrz=jyTrl%oYj -@8@hpOw(JLdZ^|0fk<)*L}Z(57LUDMlV^`9Ld0Y0Uypl!;+$)1&)YQOCtzaCs0<&T^R#{*TD^4EU<0l -C!Ib#Gtyf3l6l`(5MT#C^VS#q#X~cC#+5wD1%3PT@3y)35*h)`j1@@JAQ^?80ANc-MvZUHEVs>imb(` -mWMO)}7IAr+>&%c)C?}Z=ZVxPa?e5ZkN8Z4v+V+e*gQEIKW@4H}{4xQ?eHZ@tyv^-hK=X-G1)E-(C39 -g-^cAZ%|7E1QY-O00;m`Rt8hwo8(au0{{Sz1poja0001RX>c!Jc4cm4Z*nhia&KpHWpi^cb8u;HZe?; -VaCwcB-;UEp6vppY+IKhtRoS3yTDYnZRLnY)WF*H9Gm}LKP~?rr$*7LU8r%Cv>NB90UT|4K9)KI5QYr -1b@FbiWC+x1cSzq|GXU_LK-;qcBOEKI74<$Y-C?C@u|vcI>#cN+pzURb?c)o`%r!o8pF-h+`gc4 -;a&R=AP;sw;SK+CDy7t`nX27iRqndYyf$>{?fqHU-oMno9MsQF+mWHMYx8lOlywSGCnAO|76_A+9o6e -U?}SnXy=K;Xq|$OH(O0)Ab5)*{Nx2$dm%KtdvzJ7qGNRQLD5Er8TEIRVf0K8gB}c6LYE@Y4L5M!qj@9 -d<5UOybQbBDod4E&;=xU?wndx{q1OSOhLp$`Gjx^Ou&@K$810caEl0hzXc>3_#!fssbVN8>Vss(zk{t!%Y`~(CH?qkzWZ2~r0P)Zp+Wb&zRKV&kZLiCXVQ4I -8$MiRu>ajqmgq7X826jB(*+@VPH6vUJUjD$VR&1oQeh}b=$C5R(IAI}hnH83C(GIBwIm`sb9z+u7#xumoqK7_;0lCXfA|EM`ERLK3TT4z{j);yzHlk5Loj3Ld8FMV0i -LIdrgfroq#xuD+sMuo>6VVpxPv4yfX7MQ~$Ag#<4<26sHTv$e$gEkze4aIRW7T{PdR-b@LsMw{iqt&U -wX#WGZ43LmeO6?;z&(f9-&^EKRe>mVQ7C(`+w0!n-vhkLRZ^)69>PKAu+xLi^XKmVo4ftk>9#d1{D;p -Mjjix|cnH!qp6qr~l|fUcNv#elm1jGsyEK-%wZ1M=bq+s3t_ok&Z(DXROa1DZ)mzH8;F*5Wy*j~EtKA -S={ceV5oiDHdcG17Q{@BWgR^E4BTt!WcDQ?30qjkS(<@Z+pyv_=Bag$sx|MBjZpIZ61mCx7SK3ykI^| -{J#fZqJ)?VEP;&AV3q^77_?FK=7fwB0wKU8Ap1O9KQH0000807zB_Q;K8$goFnG0Fx8|03ZMW0B~t=F -JE?LZe(wAFLGsZb!BsOb1z?CX>MtBUtcb8d9_$=Z`(K${vIIzVOITM`JgDVv%9x2ngG3SdM&P-7D;Y{ -Ls4jHiLtqrMJ-7s>s|DI`#ls%S+O^Nb9eNET{%2BJa|S#S=N3 -ZXW1Ap?LTsVGs=$bm)$?67?1H0#mDWxBeLY!&c;rR{~TMfQ4}2>T=Cx;u8pSGH#hI;t(YsO)`tiG9{O -0Oj$UYDmE$TMS3(a;7{eU>pINcc>HPeh#HyCckn -)Fg>x$00#dN_)G+~!^1;bw`ZkNEk@%FOR5bsjm`imZ&#-$C*AIR

    bppjyd=VyhJtq>@#O2 -5OD06)MeT1&d6}c%vF_l}*!>VAlJ0*EfCTYql;WE1+s2aua{z>&e;Zo|O%sj1t1@)W1&qYW6LwrS6$# -zvrU0>)7rl~^pzjN*KZ3!eOy=4<)~uPUfPS6rAsKshT#&MVDl^rB`t^qrs!ZTk -I9!zX>PI#x5P^E2Uj>xY4F28E@jpFol)zVyMkSB)cNq!mw>)f9j45oVv4;>Kcc|qtr(ZjM98_3mxM(XY^rI@cYq6qG$9 -oSK@9Rh!E=42nbck3uOtXY(ZQIllmA2$F+q2iWS#M$0e(BjR>_s;VSVzoCRDb-=`BFVB(HSUhSeWrn5 -7e&br9jvy0W%8RF52H7scH(!$&+V1087a)08A{VG*LNLuy_+xc=II4iD_zp)v;`e8D8iqWQ!c4wTpXS -?m6TbglDFDQ0?Mw4_pNhb+CZy&$kx|>#*wSTg`Y~@Cid^Suxv4>^sn-poqI&|LcK2Z1@g+&(%K6P -CtH$`)gry_UwiiU^q=r(kT$6@9=Q4A@;DurwJihO~)3Rct8hiQ2bp>bmGtArH5fS>b?q*Vb=dUI6K#D --NeEI8&8MfnR?5ggy(bz9?g3gC?+(gi;%D5=wGs-iX%aweAv1+pqEtCW!#WYqH#!*na`7IT^rk2)XR0 -;f7wlcFuk`6g(vB0`mNjBu -XP;C}nD$LlL0)Ed1ji!NQtZ6Or@`FRYtSyRp$;IB*hP{@ZW9i_HYVP+Vyy<>E0A7cNOJYHqTu9J2d#g -$21aS_M_*MmuAgZ~r7FYVRa|E>Ubr8s`kIyBbWyGVNX65M3l;wYry7Ra7M+V|rDpKa+1$=fQpY9o~OT -C`{b?dB7CJ->;DFFgtXKghBZ*gRUh+_cMz}RZ-<;u6?e$$>z6my2K6oxdm=K{=0Tsif -(!t3bz71+XH$ -Gs24mj$P3vG*$a9hXl$3a+w>vKxvE&1HpVuq&L>0fcl+k@$9K2aUFcS_TieTey#_FjAew??Jp)E_NnCvJl(Kp!*q8Mqv$8L;NAL47U)cNrbS!ObPc?DLhmt -!V5~0uR^Y=dz4N?7+=gbrlXa(D0T -KUlc;HLRHA*I$HrABJX7Ghg*h`d)5+xJmhTThn;&>^$#XH$lMYO5L-A@3X+rtoK`OV9wEMGeb_FTVff -6ID{N5n^#Rcrc!Jc4cm4Z*nhkWpQ<7b98erUte}*a&u{KZeL$6aCv2qO>4t -242JK4{0Bh~*(I*$K|2P6ja>@6l+oP^iR-A1X%c7t80+YdpFh%lFvN?bR}Yds15%P70r}gPB+q7Wz5+ -OxUgQihd|msoFGCJU;iE2tYLar2w?odeJgX`zZHH9__fTkjb7-t7g5RJKT8>t#Ax+mO+o}Opo6Q>bO2 -f+ad@v-!PIn1vtsTwXe12I)H1fu_*eGF$R1tnhZN9fM!WM)^f9GV^M3;V0#uk(Ympgw}C-@nM0c{H}D -D7wQYl=OW(+hfhI3`R7iYR@EWG4jc!Jc4cm4Z*nhkWpQ<7b98erUukZ -1WpZv|Y+rSBX>4;YaCv1?v2NQi5Zwjn9}eyiyRbE6Dg9Y= -#Dp5MEBeD6NM?&A)mX_bDi!Be;U6e?v=7OT~&EG+)@=*U%#(u7uvq4A^!R~G-?Jc00F&5LT$K|m;)q4 -QdjGTH(4f$NMp+4&@0(PixcV=j0Suqiz70u!$UYNEa-8V&^lN<&v4J0DgGd -H->8v5TRi9zfsZ_EItd{4(J>hZahyIYUC~3A^2;u=undg1~DSGTYO55l;$Hs)RT*`PgVnhO=>Y64n10 -oeKblQEbLstW3PCi3$8o3{rUO+9=u*;kr~)xo?#ElVRgJv{7@bHrL-fVB_4e^vo2c@9^(malEzrY!Qm -NT=@#5St6dVSB`UQEc!Jc4cm4Z*nhkWpQ<7b98erVPs)&bY*gLE^vA6JZp2?$dTV&<^M1 -zeIU7^5Zn79Db~_evaG#TooqRhoK&6Tf``OVoCpMXcu3Z6ZGL;Ydmfk>3@FKVa+ST~*2*N%)6>(_?`d -G49ej7dmSrZ3s~KyX)xjU}%F`!LpX}}JJ$+J%|7k_t)Cte{wh>kR^vU1D4+3AVWz9Ba*5(4R6%Cg~&6 ->4fO~s3PTUHG-7~nE**ttf`+FHP+l4W8g3-R;`FEX});fMlJ6=K=QvZxbH(bFe#L-@)%+45#>f7j*mS -~Li-s>%)9%59R~h$1Viq^5aNHW!tL!e3#1<$^i^A{JV9qH!BBd1 -r&@c5CZ<&xutKl8jb!!?2g42;NobC|o!asvjz+=UrP#ine*!NfEbSU3ZTnqkq5UmyQ?`2O@VJvvNZy? -^`q^f-NYc=^+miO*oXmQDJz+-^mdqOqx`PoJ>J=SnoGD3lph_G1nF2V;jeMQmZsX}w&FjY#DxEriHKw -gVGyo3*t!TQ=|(}G>H+6SvX0qzvFY~+o2EtgHlsPbBNkY=6wa@v&X --?-Vd$PSGIy_g1?K6Qm}YK3WF!Sw0WW6C;xowAeShUYT7K;Citlc3+9pYFn_K>^D02-#=Wkb+RirQ$U -34n+)RohgKa(u$s~l8XdgO{XkpNB?y}BxyhL^oimbJ0SpCipC84*oPl~$Ez!ll<&T~zQu2oS+}l=OYk -xt8^(KYWL<-x0XCE@kUQMW6{strW_7#8d6T^fF3U*wyR);?SEm5L=IlqFquRK)E>8aY816iO)?Ge7zC -1rUzJROGeAx8zy<8tvg5DK#zaNd^?4lz|sJ*GYP4~YLeIy6BiFie?~Z_Ob0Rm-&BHc=EQ<2Ym}7EaUD~3BPzMNn_pI~2xV(2Dg%X@ -2OOtgE^)Ak3z)D5X%=95M5bdLrWlc+WVaRQkuhB6h9Mb0GZ@J?hTIuLp3R82vri%3AA$=nKe2^C!GLu -m)&Qqk`HYQA(r2De*k9HHg0u?bFLjqGG6PSNdfw#rKm`-NVJ%_^~)eH!a<(99p~5zwERTNCz!{#FB5ns%EDcNxvyR&=YNnQ$V4># -bHvg}2yaNo)h!AujR(4q2Az*a?Qhp=BPoe#GX+lg3jO$@;k@aOmYlnvvg;-x_ -nIzA_Au2@@x7(b)IC7VGDizwow`Bu%H3we`!kO6s!KnNa1J<7106a&yPmpeGO(MeTtytosfRkcVCl8; -?7&{C}jj?lVQeg2Gt<0MP*gFI_29LDExD`YHJH>Jo{wq<4isuJvr(yPL#g~Fc*~|%|nwtDFu#a-CrHY -vuH)@8zE^wNfEhq_4OF=b5e)r69H&enWqf_g=m3giZwsp&M*f0=)C8!%P1raxnjk-`ou^;po&_0C(#8 -8kyP?(k_NPKOVZiENaDRq)QW&etHvw*SX%5cod3u%aA0SEV(^wDkj=UV3H|@qj>C8qpir*l^X --zoXM+n1H%&17f*)Wx4Dr%# -YCG2Fy?#h;7?8~k|?%JGJ#zwO8Mu`Sq$fQ~e$xDY!8NOSg=i;41@8W$F4KSjgK2Zqy$w(e@WeZgC1CM8&b5w-60%tanAW19zN`=DtzJ~B_HtXE`%a<<=xn?8WTQvk!w&0@m2LqZ8g1Zo=pp -v+D$dSuT-JQNaz*XIO5aAADBTDDJ2-@{5a^+%X^EnHU&wS*#z{DG&5}xt1DFrYpFr9RR -AmJ4c#F0?W2sYf60tXe1Q@aR5e)%=HqpDw~KBfS|(AyEU;n3S+?8ymW4KGE9=xsFM`ezhWso>n%upSv -ipHurAhcryRX{Ji8=N-n0FRPHF*9|zoNP<#Ph|hjOHJV{Ek6*M@_M3t7RTLog%2Qv#p~y{S|oiescc -Z?R6SqFRVpA-aGKYZv5zb-3wd3OZJFj0yW;r(1jZDV8LEgFw;2_D$kM2cM22UXgtwh7=IdRYLe78$@C -J1|p|Gd)#M2 -jmpg-J}Kg5j3Ex2ot=B_M{VS@-kJ&&o-{Gpl~s4)GdS`lQcsvZ>RoU7BGkxPMnCXB)BG>`zI+Nx?oot -ipzL0dt&k~bhdgyc7)yR@2_tqk0$rD -k~p~6uW|PkP-#d1x*=|Esf>)(WY5i)2ux=g20VO!h_MAa3Yn$^M!Y{i?ZcV+`){o1jw_GU))l!!@tUO2HfrjztOKT=#6+{q-9 -nNhlx9#5=itu0z0VGFz)V)-Kv&0MQ*ac^^|5^74*`1ATqv0+#~3Tk`pW0bZ1$sv2!|WE-6&!w^8?5Dl -Y1t@&BoulnVCFsQ1+zve_e)O5_8J!1=_l~R%uOzS@B&U@PM)M?CAPnvXE5Vquy*^t1vnSP=FA3QU -vg5r3bbZ5{jyMjw~FU!c5W -ek+B1-dVBWvcoc)|$Wtp%?t&*~bA$2wXkD=N})z*kG -3Xr|5G>u0mXBOJdsLK|Nka=7Qtk!IZO -i^$BD5>f-eApp6m+bAsfd99c=C+H(ueV<9m@4^3s%wocW)AnR|}up~Tys|2q- -2XB|?j8Taq6jU1E>SpwWP&n>T;b(|Jpd1Sp&n=zx+B0X1)*&GaY%ciOfB -n_(q%e#vxgg2%?JL(xF_vjol=c>iY&S`cJ7!kX>U`U2aq#IpB`%p6O5`+9UU!v_vJrk!-KBn% -0?B6oqcAHmkH1JDR>sTNjUIMScwr^P7m-bTYjM+s}V->SvQRSb{F4saCA=VJ$$1wr${`ZtlSUI(pU`LO;LKXbK+q&(uGt?8cL$*^xFiM)q3k5{uj$j4Uw2TK+;K$j!EV)93&&Tlvgy$ -7I*3dIa2>PIAw%4*oBT%F2@ZwJOZGoQYLsA#@QCn4_X!1MVV?;P>dq8BW>$uN|2@E+}W4Cte)Y5b%M4 ->=%T&QrHj_RSxMV~JqtCh<{I(Hhbk|*kTs(1FQir*Gn$31O6h~YsKuu*)Ut7i*(=%`VVo37p{`?}%RM -(`od2S#_csY7u>ffn0{8XJF5P{p(k-B*R{#@)EG@UQSY|BOax>z@t-FQiOHjWr?j6?lp2clg93Jr9lk -N`Q>@Iqrq$Fe1G^fT)I}FN%yL(416X1WYJqyB&Y^gSF{S{}BOyF2qbaU*l{PAMnlB2%%&89A& -Nco0kVU^H=0+I4yhQ!^xAgTHerY418!a<&y;z`p3DvvtZ$8auyEQp7cB(?xmc+leQdt0WTwH;3g|~Pj -c#}7+(zFoR_y;%W(W@iU@y%+#-e3&c#W9*N7pv(LLQliD8`c^FRS`oJJItG3!S!v!5qf7h!p8r;%P1T -4~V8wBQ&wDgcvWU+_KtjSkrZ_j)P2!wBc8BiMSxaR|oPOeWbX? -|y18b`%`Y@sh^xzN>m6iON&YnhiY#ltgH{Q`D@TiYjLCl_OqQ2FmW&i&$nTzQ+{V*Bp9`mtJ@T-mL@! -{J%X6CQL9)Ew$iMNl^KmPu0JZARLD!k+8sxVA+)Bm81cu%OWpBC;v_>Q96E8V(z(?&Ndp|Gv?8yWUfwFje(5S>Xz%axTew#dTYz)MVV1Q0-b&U -8%IaV_8gpw;;LDXP{IvtSJ@w`##bx;M -K}EJ`#z+9um))gTH`JDNP)Xgy;78yEk#O`_iVSFgtprdzuWGZeio$)u~ -ISEGTo+)>RxU|5oz|rkLpS@W+YKR2jVKgG)LnRzl$0;chzwK&NLAQ+Bg6W!HL9dKu1_{AlL%5b|?%f7 -H)O|Zz};3m!*$Jx-*d7FGo-+#{)EWQ}tYIIh*Xe`jo4VVe@6GTt&?*ALvgS3Np(;P1pAo{kY_Ch$ -e6(jH0qVd*lJJw4x2X%A8b@feRK) -we8Iaj>-p=eo(*_<{x1*-ra#X7wkpyhbdM17wu{#$Z -12CPsa#m&UzRXx^BBRP)OS}WU(0$j*Zp<#wEnZ?u%@OX;yDxk_(y3=1$do^fJCrzW?19kU7YG?bzIRu -c;?svCIn@*MOI!p*xfwjT;4CJ7Buter{;qh4B$y20t-R6Nip$n%b~|ZQ92(Do6^~vQfu(Rk_H)_%Q4b -g0LHtOngN~P-PxM1_>AC5-OIeOI5|Y#j06ho<~JgeA%=-XZBT60|@Q*t8>o*iKNL~nb0CS_Fk4|UX+k -fOgo{lxC*6L(H*?b3IoC2IhCH!d$(LH?)D={(+w29E{lf8j6d-A?Dg3UY|N%469e(PL^XPrJez@S5p4 -g(AD=&udikJPwVS*DTDu{?<1t6mdSAA=Yt`N>;f6aaJC=UUWX=oshNtRazG^D-g0q1=#BEztFbJQPcH -jHLZk{JEUQj7H=Z%OZUW!gL!9%DV5a|aAbnvpr;qt?mp?CIV7`3}6F(hNl?y2)m$jJlL@2hqS;wF0BR -q!g8=FEZi@5?sLg%49r;k`ibUUjjM51A>N74$5sE_+k@5_B5dijMB%`v*`<0|XQR000O8NLB_@nebf} -b_M_dp&0-G8vpunrY19ouXq(IcsN?y&v#okLQV<#x|?dTfW%m -hKoMRbhB%dn?5;1XtQQX;WzzN}Y9KXXj=v^u%y&4d;?cm+}T>n!Go6gXcO5`!AO#e^af$3G5+aonZF#pUqy;{3}0I2jxs`_<*eRXA{YT`dlWM<=` -_4RL%tI2#NHF`Khu40##B^{cbTn9;oHz72t;W|kr;vJM=}#4Yur3z?)Ks4>`*a5rqiXklq#l?#~{#UE -KXy`)JmfFeswTN<-&NYjE;Sn){xU9a7RVk|S<&EyT%HhBLk+bWYrDqT1c4_flpsG?!XA-uf0I45aZic -G!}Bg%lw1>s%%XI)biDe8X;Jj*y44lm)vA6x2~OG=`Lr6)?=NW3eZ19#;1UJAYL!y{#L;P10Lj$4Juu -@%)2?Rrfnj_De+_>aaB2kxJ7-0^u|W>%6a3t0G)1+=e3+N+U{ditpa*eixF`Se3sCcsmp3Q`9V=I=btQk{^;wkWZdkD^)dFa18MYM^$#ljijN?9B?Rgzo*DM93*s6b~y!pjwDDm|1HD{JM%4ccC2GAn7aL6mmd%$br|Zip6558ZVI$AM^)N}%o8<-TohDTknB!fI?RQ%OS>pTZ&5Fq%q6AvVT5CDB@`ylr7 -j4L^O!hgyB^d?<2Z`jB)o7L;ce(rHxVl}EVl=#cp -;U&V=)u4Rub)cef=IoiAKFHr`$V5wMBjCXzV8Zs?jukMC22i4#<8G$auJK;p)Rp*9nRQ0hKxvivqNb0 -`=(kFGCmix8ON25S(T`aH8CXIjRHYg!lH>Xp(V$QhRgw#A7n5_-v2Ha)%jE=Q_62cqlYK0R+-@pa);* -_B-J1}pq7+q85o{jL4w-Ku}p-;fVj`H4LWjSr!OWmVW(?yDI4JE5JqK@dVZG%?+>zfm$aeC8}3T3ls| -~fAeRKTSfiQIR8lATTxJ=YBJ-T^A=|SBq-tJpF~oGO;**E#@~?uA?1;+^lR=V67R|?f$!Paxn0I<`I) -)+BvI8ol+Ldc -!tWo(=8uOMWBCh-yb#`z?UeH)d^YenW-0%&>>0$zkuF+ScbMMM8+8r*7;b~O!-XmUZ^qTYa{>qrW-yF -5;k(|Qcc6)x-+&@)^vYtw|AX -bWX|0=Sha*FsshHG}TmBQ!y1icSKfS~ykR;#jyWl2Xz}5}#s8b)QyE=8en@?sHp~Ej15ir?1QY-O00;m`Rt8 -gXih?hW3jhERDF6T*0001RX>c!Jc4cm4Z*nhkWpQ<7b98erVRdw9E^v9}8f$OcM)JD>|A##p0m(+9A5 -GH0h)}qRdkxw;f#c$G$OXhoT1gvITy}S9*)4j%{bu$-E=kF9t~dmDrxp&yotd5Y%+Bh7jJ_I?shII%a -Y`yZA3eu6`+NI)gTY{bPqJStrnE|FrI-7A{|r9}bhYG)ti-I!8Bi%S<%J@8$q2%;Lh~urTohzUi&@U3 -B6A_hr6=k(+27-CUBCkqK4o*%RWHC(oX+0t9C -DdO8)Wl4=i7$-Jaeu^~}f4h=Rum>oR0xaLfGcy_BLo$AcJ&a}urQR#s*UT7u@nrD^fd5r`>1!(4mWo_ -CmAj3vB<3M}~LNbXgzkG9Xb$)S`UH$#-dG`IA%b&AfE`K_|c=_hl`71Ie5iQHyY5nkav|g`Apz_rSq_ -Seqq7IFpfBEU^b@uk`@(R&cRjxT~tPc&^jA|O;w)=ZCHYXWqgHJOwE;1fh3T0b?u1c!ZTF6;)y1z%@1 -BSh1x{}}ylzfL+_@ttybVi1bj$~l88CsXmqMQvZ8m& -ynsL8ixak_H(XSbz?WIInve<5TQgEHHZ$ZU1Ez17#|Lr~Hl-j5DVZq2kEvwfe)%2niQ96W4m>b?M&zg -JnkwpE`IW0BkTs}F27i>ufdcNgf{?(l07sf$gKy3hvHr#n(6TrX#3BYkl&aW8(ER_-yUu&M{z$7 -rW5;q_P5c@hkg8wWopOZp>`znY%O^YcD%+h$THw=D!h@|)sH}8$%E<`c1D8$ooEEIy|qF6AA%&4kFC$ -;SOh$e#$G0P`;n=@bpGsF!uLCc7kd}32g?nD*cFylU!RQ&s2*5FIcwE~eLRjv-%}uvZ*M$!3y`S9C} -QEc?f;Br!z;I;M1+eIxR?S9JoHs>@_l+GPkuwQg6ReRzkS1k+E${oYo5m++9B83eM}Y%>;R?cL@k{R+ae}Co@Ce2-b!(MXB@5Nc3Zv8z;Ez2`aoZ -Mkkn?A(SKa_S9}4iJ}k;C?0-X;d58n@BV#3Gbf{BU2umhM_Ur<+8q5GILefQ-W@ceB3o~wxJE?gSx8l -Hv1cW`3*~~~7N^<~pO=0bIyeNamY0iIx%Kiznp@1?JaM<9w76uMsCQ$nM(pQYZk#bhMj^YLz`XIyOPpAT{QiR6L)-@eWsH@;^E)`&fxRs9ZNX3ZkU3A!1ay;XCc?o&##^aPRMd~FL?c&LN5+RPQqZ -!>1r~ga7tFHg6v}5!HrauIZ)bZ0K_J>9XXzZb9Te>mH^?7jzes~`>#ju&fmR@I{czPu4Ye-g5uk5^tv -sA9`&}@oQ9uU5c;-mP0ds(G==}TO5jF1DeMnhL*2QxN{Blsp#?p!p%MB@c=yBECPCGbeo;YT|KkTs>Y -3ds>FDI?vn|rX%9j=xSoj=~J;%GHetLYeMQT|2(ozEppCh&BILu8y;#AKj38IE%cG@7tgGcK0ks6RkB -*vvA=_Iv={N|+Q81AOS1M>d;dpoOW4o>8b>A)I=28nu=u*}TN5?dfYMvbwE1+-70Il>d3B5t-ksw78~ -@xsk0zJEzho*h3U>m{EqK`o-nXNDU%q_I`$M`mU}BsH$LP0e@6dV|A3OA$2y>?rR#S};hD!JWRvGjba -=RLj{hrhcPx_&+jQZ@0XroNn)Y&rWIr2HTf;WT0ibAIw&bozISwaPg$Qc+xeyE8-hVWYbCQ?$E+63iN -Y)Z^hf$g$3xv^oHi9h)0i(p5LM}?ne*0VmGh3A3oV0tO`XjpgUmj+993d-*^`}q0&myVkTDc^OiBDzM -qO)xnH$X!iUr2XCIT61s_2eGTG4H=s-s(z70lsI8_@rNbddp5hdXGp*9DI)*q={iD -Pi9%WEdy<|r0p_xyS8&^@ZBO1&sbLnA@6fH+``E9WoAm8OYLJ>v{ia3A7O?Gftd?sc7Q98FA2$IyERF -~0A*k%>_>uBX+NiPPy-EAvW}GN;a}F2KNWXR9x1N|uHsg{_wV&e*$yZ$~;lXV20mbzIr_3x2lsu;W8)B*q_VQn_ENiuGRnRYmUm*TKwF6@ -V>raYj1q(5|tyQaOw(f*mDWDbMJL7;MmboL@8NmJi+_XRFrpJpv^z!h!HpSFNX~c^GMelc1rONmCPfx -N%WLyR`0oGFjm|&F6_5PhE#p9z%T9d7k)BnG||{4#pp9U2C2AVsP9r*mIyBU5Z-)avvXHUmwz( -3qc6HAjdfGlu3HR9-}P)e9J!m(cTgod{A?biC!MmehD=Xypag-3;?FW%2c)ifY5W#s*p+Cvp2qIIblU -0;vbMbJm|gcyy<2D7(xzC=@;nro-A-Al$(e>~JE=4?7pc9<@Y-JSPcaEV325KzK+B3h3owyAvz6PI2r -=*F25fmH!{74MqXJVdsHr(4^CKC1xiiE9gvTI6>e6W!C|8zh!bVhoA;NW}2zE$Xbg5kQ^Unh>2QVrY5 -INvYc;6h?4Rz!O1x-Jcd_I=%$&$~Fs9iDje|jbSFHlPZ1QY-O00;m`Rt8hlppMr&0RRBw0RR9U0001R -X>c!Jc4cm4Z*nhkWpQ<7b98erV`Xx5b1rasRgk|<4@-GR;3+E~O6DY3>Vua`3)a-NuqGKu@ -^+!NUeI=4jAKQIXymbRuOuO9^DV~1m^7csvm8e_ -Cw?I3aDR_W=LXN>+~u7$sAp7`e6MN}7|$qtd7yXs(m=9%Z3S7 -j(-^fi6HAjje2uCa{PrY-2n-&<5eEl8!xs^&4jBEQ)R5EJR3XXStFom!+z)>n_FQ@hu%@Q(Y|yJPl6Y -UVn$PGg!`s(A6HgdIDWVD11~7*Km!e_XyOTe2WDrPgPJg0&gruv0m4OaTyvw9m|=w2;6}-NZoLCU2%E -6F)YllAAo+>oSODvlYn%lTDKl;&-P$uA$$V>A9K_WrWZBny)nwno0iqWtP3;gM<^7{RVvpd-gRR+4_U -jdp;UnNL+t~#<*5?n+HR~mC(^4vbLkY5RLaFlsCu4a`tLh!6@#W -Y&Ny7M%gIe6J@>QAbLx1F+;j6fNZoWlm4HtLb1o$n(BO_gSqW|q)>DMfkDjgmW>W8b;2pAD1M%!KjBb -X&R3!OQ*rMsZnhtft1*y8=tYHqR1-C8&yUVL?ITE_(eqQTZ#HAu{(KBB;Lqxpz)B;*L -LMHG5QNt&?y#|YSJa2EDUG{2?=Mmfy -75RU4IWycuKo@w9bA-;uq;lwx3W-0|XQR000O8NLB_@I37uVOVaA|NaUv_0~WN&gWa -%FLKWpi|MFJo_SYiVV3E^v9>T>p>TxRw7sK>i2b1Ov%AkGAdo(z-D2cDLZopiBC2evG6Jj%$D -OG@Jyi@m?S?+Zzhlg*5Yxg!e2G~-FGOJ*ZF==#GXIv)N%3rnShU-@lMISq -*nQ{ko!)&qJ}>z)vB;-+3$A8l^Y;(?T^O)iaOUCW-spFvS8D8^FbEf%n$;3eXsJp7P(kE(VMPo+`C=1 -s|sudZh*hvxJKG7ByoKwdDE-r#4gK^dzcc}R)Jhm%(r<#{aaN^h0_$RQqZS9GRE%FAnL(6V1wy7uLe;-*6_BlK7(*L^baARi9zd6KU|oxc3S_&L-3lJA%)@lHre%?+_D -bSt9JmvpHmcpLD(@st{X^R`Rd~7qy*i3R4$B~V%#R_tMxot;#7dA(-5xTx`<7p57AvrUs#~p6P}SSH< -=UzWey|~1DY3MTag)adbo%k9sJ%PxB|Nt_k{Ws$JeXy=02ZacAmjswP(ObiAd_A-1I>8QT??9iV$k&D -jqK{Si0QBftbp0GB#DxncNS9tKLuVz)uZ7r#CM=VmI`YnsgF#wc=z^OQL(Oq16ATKFPo%8)uw0Pw7&F -T7=;?1z|f}c?2ct-Q*f1Of@2eZAu%s36`%YoTFFtARY^;zI#dvFiShv~nav0+7}nmYzThRY-Gk1t=?& -yiOrQp_Z%w1czUPJB%!Oz=l(HBfp1u#o#q%1aofAuQ`w -$|-o%ciKJMDgg*{I`ulGd%tw>$77L*q@LOO;;r&4X0cZG}PPlr~=Cv83vp_z1S%wR^m&dty$ZLOE@Odssp=iKLL@l=!zyt8A -gjLXQQ>@xSbZN`qBVp9>OW%}+r|2!wi*< -Z$*LHq;IaT-@KMu1K62DTN&(h)!er5YrtDsmL2Z$?mxv>xvl`m)} -Z6yz*e*(Bzx7)VYm=~y{!ArvFrMH&YA_lZF;nGm}=hc7O5Biof_P4>v%8aTtd7KApJr%J15nZ+*QHRr=kRwZPH)W$Kr^yPH*q8>rKi55EF{oePha`V8`YLQq=k^dd1;Oa;-+ArXzB|Zb1vf9=B|+Ef -Hy#-F=(^G1Yv0XhROHVjCZzvQg^B2%A@(c+yaE*8dgBae#i+ -fEd$ic@!}Z@7^F$82}1tck`^0f9stWB#qDJpF#6%?(=}GrL=OLVht -`FQ4iE;wUz2MVs_FoerTw>f1vPz6yJe6LlYq3X4-tInxgJYX?M>FK37{E)PXkWpR#)T@NCmlA_6y4z0RpS{U_A0dLcO42b -~}fw1vVm871!%Ry39?pv>iVkATenQe_)t=Hdv|Hf;heORymRMpaZ>ICwxsVf4qN^biaHrCS-$`@HX;m -f`%?!it$`8?PTAX_z9Xb9JPiEYYMHEBs53rys;tq+;% -u;IYv;+jXrzO{?jCi2utQpj?tsf*V3!^sHLMzsBf}_30r|5|XH$t&%AhiQNDoCYmBn#4mK%`ENHiFGb -Wl@6Ji3DIMz1vR!?J>n)HSMbG0kIWezB=_|Gz-(KFqvxo|H`9Zs*gyUz45nCN83mF_*}evd4E9Bp4=( -@|9z(>h5o|%9nbcei=Ls4by46f!JMjXgLM?N>$NB-EICR%DPIsM?Jq4)s{*HWT(gM}k4VhtxERDqzRlRHG+C$ud@s -5oH63Vx21s(C=o7sBHLm}Fjn1$9$=J9YjU4}p -dpoLiK1B#81mHG!#QUf2aLD&3@2_3oXos2DqZ@4IeAIZa*v)nj4?oNP+I4?!;X1h`6ZiIcrAEkTQoA0L_@sIni3H -k(Jys^tPs#IL$7r8VP>^#HAaYL$gsDrIED{A4ti!esrG`(?hoR@c&ih+b3|0mFDD -OwzUsI&~!-q!jyZCjtv@XxDRaWyGwJ*RWQVeQXXMivJbp%p=3yp=*weOSc@zUXAP3u~6-ffxioDM7r> -@3EXfaRESOPnaCOpUyStLV$Ij`#QJ)(1OE$6S_0cv64UY!)Z{B@<~B>7W;+6ONWuiRID=YU1pH2-qTJG@Ks8;K(5H6R#}f?!6Zm@vt|HjFB=8!@?szEP}1tA_Qv$hGwDh1gmf4VNFW1W|RSI%5I}W|#4i=`XE`Jf#9M3&pG_#5{2UA(FNm^|@q?_ -1hYckdMRR2$c#!wzjrz!-^I9K#-(=Lg;#0=#%oZ8MdE_NAfCV{is^XT6WSq<>9-GxltKDyjf4)wp=Hk -nAYp*>c@<#nkN+Ce7R&6m9A_lfqU?exp;|%hv^ztMK_Y@c-D7DbCKvSSDnVq=cC!cS!F|Onp{kEfM_{ -1j}CE$j*%D4l!WM1$Ta!e-!2kZMlz1FkGL_vqH;n2zSR1C3ASV;Mo1P8s -k($=X-2qhTeAhS`k@R40~M7zt_IM5q~+l-m6jrJyg|)${m>pjqzQ7eyj0FM@GDuyrAox5m^#iF8(9PZKH22HYVm@`n()< -%1D`u-gGcba;7k~#a@#kAKo@+D*vR0Bp~s7D=tB-1@EdnT`LCwsxQ}``Ng9;YW}LTe@23xT#1vRQk!+ -93wD{pfEAI*hr?g9!1Mp!{j`#EIvTHe&hcJxV@~>^MD0|DVS1edy#(s8RyqtHRYt1(<>^+Rr^WlfRz| -<9x&pX8DT>i(~$N*jeYX{75z^K7~o31C_aW6SkR7R*wzvgO0&2ZfoFQfjpwH;h35Bc+}leY##_mK;#!|ae44r8y3!l!>aNdF$jwd{2$=G4$#I23vbm -$Vt8Ax)jl@)Dd`NF7axidxZH`EHBNL<>By}&u_c8%LR?57_Sjz8DG{eear$)jb%}E#PJWHFV3PNna?G -|3LWvAg`D0bv+DTeIlgS!N6TJ04}ei#P3@Y19m@Pw?&+jmps<&AjCwSeJ1oVlNG*26bG8obWxuKN+D! -PhPasP&b*%QiR17!{oqu5mU4@My|4#{zyW)4W{cs?$lr)c6J*-t%ZMYN(@o=`!uir8>OyhBp{B0Y+F< -E-om2_n0(W9dwd_!^!X|1bX) -x9*T4E*wAP=jE^P9W?iMYnR%Y}|T+uJyg_$#K)7R5?snB$iP-kaii#HA%_Y&c~JRVwAy3+@}5SKcM1O -N4L&sSViqgX*WY;x~P`)`@}$q)Jfgw*$6Jdo?i -yi1Kn{eujlva5KX?DCIS`Bo-3XHOsoBCv)O9Y=zAX*?<_50>!EJuqdw@HmZYqs&NHvK@qWwLVH#|2$69llk3_OGe|s&IAn -?cxUl<))C{3_5*?9a`Z~)85nW8UU2A!9&kyp1S3^KC8e8e0gjLRzaOlmlNGO4y -ap#QV?WbKi4gjM}F+lGaYG4#-OBIk&xtoRDQSCI$}LbDDqLH`W-)H^@XWeWE)i?@}dGL922DkOnao7# -m-m^$Hh69*`H0`+<;;5VLU(*ZDm&pWBM(!JZ}I#_BxcK)&~J?-%}BD?@W6wA|ZTYB2+9qDikeS)5v=W -H(a%>p$^%D!^`bj71h8BUN!;y8JV#8GkxqG|F&+ta_%LYGuXCXo#%zOIfY)pK$ivlE&><-tPLabyNx= -CLz4G%{~LMo%r}5$?y3WKddzJgqv7fXA1R`c|91n*<+&2?Agw8+Dd8b<=3tRQ&O0EaD$fO9KQH00008 -07zB_Q$GY))>i}o05J^!03rYY0B~t=FJE?LZe(wAFLGsZb!BsOb1!9hV`Xr3X>V?GE^v9BS50% -9&g37Nhf9I9)XgoSQI~$KI{#&8*F2R=+ORtP}O8JYHF0Uz#IiXN?gIigVM@BJWL$ss~KDf -yLR+-@wDNm7)|4NOQuTX>N_694;$q(cx<>HDP+lSuB6J~Bbensm{OYpdqj*s!yi!7C8a4R=W+Rb2A_? -_>CS;;Ogdii@xUSkaR3`u4^h<$CM_t9h&Dc$gdF%~50n;nuJMxzC%m^U%nVw(X}5+0A@1cA*E(`Tm4KulYh>?d=4XafYzD0x4>qAVSeLiCC$u4z;>XIBI#gv0_xgmO@l$MKM~r__y -p=#YhJcBV2@xAuVk|mQ1khxlR%oSPT(w5fu{1u5~Tee_bPZYmp~3l+^pBarx|Z-&oWk%ZB(8^%0Ix;_ -^dX(B7wMi{4t=6Ns~hp%j0gAkNDi9kgY?Yb^A)vYh_HdSFc&Dz^Q~A9rJb@k~J*V48)HI-D+?V1Fq -7y8pz1E1H+%lOHxPo3lRI#)UH}#1pZ#65k&>W9}%ldz55P@_Tgp45LvVHd^=5?v!)XlX;q9AqFJrZ;@ -9xaEOJtUGRblChG(;?@OSb@VA?CPDPE~r);F_*C^+Re6)!wryR;Htca;DU>(FkVhsz0`Kwvcpgk+ehc -BJd&J>uL4b4D+dxhmA4cMTfzefkR$(Xc@fvw+qk#j%lihnf#y;D>cXfjKAV^%o&XJ6OyE{l)10U$Wwl--qLwaP>vF=DTeb@5eeQdfsgw1+uAHaKDQlWS2f10R6jmY6zT9Yw8>OXK=J?LY)6lJ|a-T@Ykb5W -M>AT5LcXYbOCNWwPbWG(9d=plag&Vm1y5_e@^W9a;RQ(>DTB3<#|Vqj8Hx38NA1m)J$+@hcs -_t#fJ?y!<49b?kOdF@%%r5ZgD)8Z4o3=0SXnY=yj>Iuv^GcuYGpdy4s1@>3pE_ZC?p+{~l5Qg&+di`h -hg)^f^To&Urpv@TDYuCM()gj&DO&=yh|r{0C4=0|XQR000O8NLB_@uKT))p9BB^2oL}O8~^|SaA|NaU -v_0~WN&gWa%FLKWpi|MFKA_Ka4v9pwO4I#+cpsXZovQH<{^*`c>2&`7!bf;R%Atj)iIKGUxq=DE!t)x -lNw1SQ49a~-ANQhz1a1DE@%^*yqAY}5ATkX$>gI<@|3|w3KMg|#SYf_4iw9zGO%Z9#?(~L!pUSZ9&MF -8Koo6rlPeZQzz?NVrnoS;DmI2oF&>RacH>FY*IFu#%~q;|ThN7WKI@e9N(ULw!svyGM5@{YPegorH&< -!O*FQT0VZ9Ndpwfs5vBnw?^-s>U(e)}RZ1%Cz%tQi_#VP;76f9sV1*1))itF(R@aL3kQcsu}kJ#IWWd -?4`vYJ-nBCDZ2Nl4jHeC+~U$c%|HMkoC^8Rv;s?{V$%@sHNpMirTnI~8a9!fmirGi%8@wW_T(U -zLtB9wlrG5$>k!z>q;ifa%N{Le4xeq>6wT6239;%FQ0kp24axdnur;2eC-NrY0oYWMie|3r`rVrBxO2 -ft8Z<#Y%(Ro;GU_ohyYaX#px1MDq}S$279Hn1ttmYVWQ3yYScW7vKapO_4Nog38F(fV>CS5Lnq@4uQo -$tEFaebl^YjxrX{)z^hcx8rH}_-y0oeRji6@-~zH(8NSKWSj`DQrsO(ar$uEgkxYxgly(4b65Lf5@YA -i5qOym_DsLxRdqGcpSA|yZWu7MJ9IezmFtRcwb5lldBQZpnCB2U`R)=&WG5F*RjcevEu?}5|9YOq5E} -UeTmAHBwsbj>qJ>5kUU(2Mvhx!f=c(Oa>g7jEA?1F-Rk^SIGhvmNju3(B)3ms*JD=l1XWq636q?$LzF -8n!RjEnDSY@_7NJLdL;pkgVDHU4^GDg1!P-f|JAeuU0PDF~k=7t_D`xQBJ-7vN~y`uiIhz55QF0r(N# -OHwloK481h=Y2Le@Bi}a>hk&Ue-_U|zKWo}S5@6=N>*F5RkwzX9-9JBdGV|I2PT+`4J$XWZY7*$kCO$cAT -xdfyzk2b`)@+ynNMDf;ZkAn_;6p%?#;N$M+O)I{AhaQonE6i{NE$`%(iZu&xkO$NmYFcB^BlGZGDCws -TM~T|uqnHTF844M;m3`7}D?t>e)u`=Gm&8US(iMh&RerT_PWITed4HH;qxGD1U=hTGj!iH2x&?_lyw(@bzs#+ -)iYmL53dT9D11h>Z+O4rcI6vPDBC%mFPCc^WFtpBg5X{O-eLMG{j1nqCDQC_Wrd}k@1hTPc7 -^jk7_CL1Y80lCNJ*$!>+jWXMBG1pf4dJ!|Hk=DuDa&|-_?HiTp^20@l*L~E@y1&nSL -k5r|R9~{jzDGrRbDi(_xYyGCi#tGEPv~XQO9U=*1_M<12=X1WC1cH=9-Nk>6270{}jNX4qH5WNTT9|k={MRP8J9ts``g$7!0BFUOe;$qxQcQ+Oh``bIaNi>QB`FgYS-kX;(EM^PHWX?qy -L1T)=i$#3T_eP_U?qHlW8ZQ&@@WG8ILGT1nZ6S?!JHvaFiEIF@{yVjH8#l$bKZrC`b`5Lj~Z1vSTvbV-PqLbthPXd`~@p0vdI@}v=#XsoAc+vCMGf -9T3WOfzHDq_Z6)Nye%wNrLI%+>mHK9smFUaA|NaUv_0~WN&gWa%FLKWpi|MFKusRWo&a -UaCz-L{d3$lcE5YZ{{w1`yIkFhcI+hQDyQ7}{L$zxi9MFwo2l#BrIuKUCoZ`qxsugP`nUIe0R%vBC0% -c(?MyY3SR#Q3;NjtYKX6YS>>sFQofp;lq1twvUJFwSCauwD@{Y9 -rNG1;@PUIzMiSBR@qfubSnW)lS)7D&2`aT6ctRS(OC`?&u-K*+qPQ$Sl5@^&6}pF8+Co5 -E7f*cm1j+^%HpiSg}^$YXQux3`27q)x7+1~%IM*n^_k9dovZgZ-9=rc>O^aG(RG{l@X3>N7;<}-F6;G -^O}lzxkou%(TlnS4^KX9pBDD)P3vAOOuQFWws;Sp%Q*6@tm9Fx-Nw-Z2Q+l4R3SGhyq@&>UEk4}Ysnn -agwfLa%^nAT7yJC|y-F#IyYuJWt2aIi3l%_xQY4sf5>}apQEcK=<>dHRfkoelfoQ -9B5c7{Jps`523jMH;PFdT+s9r&=nBS$?`(4vza=suClVoKYsXere0lat4p1~5gOwT4B!Ey&fb!s^gLAWn$L)3vfcT*d@u!n_Kbvjg>COuP+EiINN0PB~?&^7!Au{KHZWwH)wpBr7ShVx3T^5 -A_;B}Lwo&%Y;bEM-cTWdxi?gOI~Xl|zPh}9jEWg*LJY2Ndk2yPDByMZM@10EMS$^25^%wZk#vS?vbn6 -7z0;8Ati3Zw#7G;e{Y=yoP^`DuRO|{mV-OfbdgvH`AUj)|;#gR`x0@%j~R#>HL&!H -i#I0&U64r2@utk+luB!zqi2LI{J;z@eCI_Q)f4ww)1W0o114iAK+yg8lP|E -pO*Ry{@I_EtlPG89M>Um_=7n1p*jU2(CSXrDy&es3hmSx1d4 -6*IuW#VRS5MVG{O{S<4<8(#zWLz4{N}4?2=(EEWtp|Dkq+kM|5SV_s)Qx;^pNNI2f#PXvb*6wfjz<@f -MW&3m9)BCnRfUCQu~iUMmY<5Xr+L^pg0Cenu5=u7JBjnrrmDV3T`(!bV#cXzFSz*A8 -y*BbPOyvO`pMVGsR$Dk^BKutsr1)%rU_h -0DL!T*>Pzp4nOd(qYxIMgQ2i+D}LYu00z*rhok6@jk{z2b@$H!;3r|ke7s8d;UR&;o3JhVGg$r_F96e -z@ -8JR-UiJ3y_cP3ZqK6=4cJQ$DNn8``H#S>65#>h=e8FvSSD8-t+n?!_DK$r=8xd;!%C0f^S!neG`+(rb -7x)|lW~Ayf}oMOFa){YzGE+3ZOky`>#l18 -iI$2=1!_tk3k(G+;&pj_7cOTL*cK`$S{l%wU{MaaS6r?_KHZx!9sUH?t38Tnw@J%db0P -J4JnBLJ_=O5{d7Ua+p$BJbbO}Rb9 -A>Q9S2TMd@oAVkEXH&zzjPha})8}g}6nC)YD_A5Bf8`!<6l>F?K7v$x~yd%a3-j@%yu -IpMp?gTuqsJfX)Jh>?v_3P+R>)d`afa2m6oG9CtQ&d=Y&-m}Wv8WkyVKpsh#`7#21}9UZA>BU`ru({q -LD_0{k_v4kGP^PM1Oyq+kSfg~Gto$OGmqpcR>JAP=!wXz#*C6A)&)l_K+&oQ$_g+==766d3JBFAKl{utoG-8_2MA>e1u -&(L_B~2|e>Un|~T`@R{{4h1A>6?-N1#Y&MT@Fk;;>$ZO<928_@EZ(q(P(s2g$QK*Io5*JXeTL4mQ$)bUCz8#8j#?|EQ0Ef${=(3nX -L29xviVu6S?M!`&x)n@}|*I?y2)C&AvZOUvJAQSz(hwS{t^Lp!qRf6)(XzIqoLk?&;*wi0^JzKnEj(L -Xz5c@F$!2ADkY+!idP+?pL7+{r`z*SIn#FH~4lX%Lb`@JOg;}cM$UeV(}WerZ+#D@aBlErK+beD=rj0 -6;kmcm)KyyUmELS+Ika7?mu?HpS8>+rDWSKojCy>Z=}xTO0Eo`Hn6VPL~hCjb2AbOP+(L^$!^v!Y7t= -KRUI?t0&-z(|Ej^jcBK6VxXF`T2XxmR#NsLZ&LZ`J9=)&-$1j9HCA{VG#Mvs5JZ+(WU%OS`hsjx{r|@ -r4jD8{3;t{;39_QcRU>Q>-5m&|6spyU{UGyrn{lNYH3f%U&7-!;zKmKPoG`a2!dsk#rH588<|`4UtV* -1)VDY6?Ffu#>|y@)`pCn+7thgll0UsZ{LC4MBCB>7j=EY)N-Pt$M$R9v$QqVir&@! -rb_^JZQTvUMZuOr`_rRE}2j+E==m>K3&F{Ly=}Rl$zXJK1x8Z|Mzj+#|(dHt&tylo0jwmI -Bd7M7Y5l!(omLDf>qYj$tE5%f+RMSp3eO&&TcO?@8TsaOSCK=8Q*TMHnxpzlU3~+W7-&q1 -i8?NqE>XN=R!lXFaY6F(#A5OCtXRDuxn*SBA~F1Q9f0-qTY=@S50>rHSAraTrS$afap4M$mwm -m?e(jrD1C>iG+(IUe_N}=k;_zC>vMr40j^GaoKlid)}uC|zhuC -K$tl1gXjA~ux4AJSi%lmQf9t0S1gQ$hf}>$%mrFWv?{jmXkPqQK -=<_D)npWdY3#zwR%k-Y{?2VSQ%g#x4rS%M7dC^{8FUyk;&yyf%UkhuC+*kA-fc?9-XTFahn43V&MF

    gb~THN3(xX|PUn8^!}MLLx|4L{az-amz`Ms>OUhSCi}$P~VYd3O%pu<`SbtnFvoACXa@Dky*e&{^{e%sXDKNla -7O@Wbw)r>IO5nPQ5y5faQ58=6QaJ_7d -9wO@bBNhD#|w1*&`Vd{PS`sbHX?=XcKK60ijH5lwLju_iylln)@%(C6PZ8Q4qygde~`f^Fr^(q1`vMV -il1q%6tMopYpo~!mi=fCJlgL*JAM__hmWl`nj4F}34k@pDz0^V1Vg3x;1vzGm8r0^8gvfSpZ5A~sSla -Go%hqKAV*9hRaY$&;3Jx{;*GrKL(e*?_;$+KtAUw9<#ggpqm(TKeDKDadClfW=SD4iH3lx@i4VInZ|A -q?yf<?aVN*+2R|70f4kzeo!quU -(0T~Ug5$jfxX-aBfi#kq1CQ>}`74aGMr_D#xiIZO-I|fJtBvcgTYiSmky6T>WNQ{Ya$ZFk8F$Y1oGwM -6zd{)q4n(TaymhMqsxFLjK>4{m&u-F1m&>(}2cuQYmknHO;YtH?6t>mBZ6axU7ARnpZkpLl5`Q_<9G` -}7Khv!b2P54UHd)-`Qn^xV_TaXiAJ=5uf!}rV6Uw{8-8i!8*rs(<4x?~_0==90C8YH{$3cZ?&MBCbvV -2OzL+c4xU^l?M0Bq3nd_z3i!;n_T{#Pa}iz1HeF6L$p|LCE;~!YGbgwjITYC5|cV&6H=kaPbtrJb86| -Oa%hjk~DSJ41urK*Db{dIY8lN=wsOh!Cux4X0y{QT)<}MG4vYgV> -38tBF9#sys;KX@UfFff&GCR{{>Wc^R$Aj+gu&(W7f0&PaKltu`yaM^p1_w}rarF|uE8P*dE` -^))z2FTz6qhxI#U>MfC+K}JN9pvNBQ^QMWB>~uvm)bwK^`~`1bF>#NETwVU{QZWXCHH7a{M8+*@N2-$ ->z=_304&EOjI-s9h280)WENi*65co32ql;UjHa$yD|LBeIT=_8G&mGI^duCz!bqX0@Rdn(7*QqYXspa -WJgk(Ux)C=^f~dz@2o$t@tlD?vfd5n6j#f+?ZE8CFAy1cL@*1iC|(|Lyk7ymw~(ORwtyhP2?S+>Zf3%Kv3bjP2?P1#WNGm!7^4%Wy9ZG;|?=VfV;QlqY(Odm)c{OuYMlNI+@v>)Z$WC=Op}Xc{JCtMRzGV1v-(!@|Uo@0w~V>9jon+;nxlro+ -k(SZq=2uGSJ!ysl0=ePM76`MbGq>;tlklfHB0uzvULJqKYd8`jC;BBn>-QB8*vl^5ml;ng;6&4WUMZ3 -4?BTf=BmPXwH6(!H~$5t(Xp5#CHjQ;=wASQ^Z7=)$VTF@jKb1cPD%az-WC7Eio@vD~%|^=(jj;Br;_T -HeNb#3fGC_g93zPfRS7+czO%I`GafKV3}n1S@fAK#`~_#V8L~vpoF?0*cgAlr%>18*YVoj8@=oiN6uc4Ab>l9v0_}LOTgvdz_PtBRvH -KI%8e$E1lx>*arpAh*mr~X^p -bT%`c!rXR3vuF?UJR9dZ}x-pf&z#rI;<`6x;ZjDrp*SpV7-B|viif% -`XY=eyZ5ffGSLhJ7Rlc5ok%d%=j?N7~!2I6`%kn7^lP$bK-7oz6Q(BI(miR(R4F=1A%09@j}^<-rn;J -f8bv*<*LuUgqxIIhE|w5D|_`nq($PB3RM~*lyA3UY+Yu@HXO;O`@jGp8B}KOWKIkShZS}TD-k9LL4f~ -OuF!DK2NsuQ#Ck2Z!qJ^2f62Semj;|6#H>X%=^*cy2wsVudtY6Mkm>d@I2cP8vmHc_I0 -Ei-qCxhVFYnJeElg*|r?Lkz1fr^?FMYaQg%-dCU$y2TPd3KY@pa%n8XkZFHZ&%7Qm5QQx?+>>Q(N94~ -Pe<9IBxiX%4wjFSN2&!x6yLcnb4{uysQ_s-r;)ywJz#MD`fFDfpFcbpWk`o$vHN|7-o+8nRC$`rKU55;jbX8=}Cd<%Qq9p@ij34@d+DL=xBuBgv#+(U1l4g4}MRx6U+6pOQECrxsMlVSwIzoi1_|lV`7Pazk*&#nxL8;YU~DqG6`u`@mb^1hMgSlVF_8Oev9S89^)f(jOItk1 -cw+oW7{;Hs&Dmzk4)V`>bi;TF-KCUYA+OIluYBrb;bTivUo4vJnr12cWSCY0SZMTG3S9;FPiCmxfAjolk8qnTD^0%uFoX0>-f&UEih3YHEt86cQ<@j>4FF5jmq9M?V8;yv3}zN5};pz5DZ{0TD2u5iEO!$ -*)XdvMtZx5-Bw4L$JG*lHl4VxfnEC!%VquyI5m(G%;g17u~hS%a;N9CTT|y=Yhz?otrgHffq8#zV^qJ -ZU#fpxh}hG8aZ0#x=T}`&S_1c{kB`9Y0%WLD7*?MHXtxES1IDt&xLhd_VHFldqL$RS<~7yEn%kW*k4> -hqcv>zEmLwqGAeJ)4P -H2Y{++`FIc<)2EHfc4vde?=jz)WJF&XO&iO?ilW%)1OesZ -u5t`|05lUKyl-u_sbBQ#TpVpJfOuBdWdtJV)8X|shqQ$Y2Nd0dAto@WZP6O$*aHLL#P`01f2r2bq@p&Mx{7CeSr$mroS{pXNQ#uo$}WurBhH)zf9D<@&Sr -JaNvrnvffn}naT=5n;!V-zsyQuhvA|K@{dut%a|JluCB?cZch9Q2`VZaI|G#bjx3;Z_%MrXXiSwc{1D -)?7azvGqd|8u9G&&rC7gm#e_3TAoh%~&0TkgC1JCM%c6084_4Sh3JjNfKFXl7{p -5T3X_K=b)c@NeL104-HIrtsgy4ySPghR?=EWKl!YTDo%ILTWVQeWO&1eJ@SAtjA4#4L-K#^m}IuW8Ni -Z^qaeCLXbwt4TMjd`kw&zhNSVIC9OG`zNu0%h@LgW=bqx8|4;Zu2$x5pf{xei!wCL%l-s9*w5IsgO!6 -poJ&s!M#=&PA{OU$Q8B!SUi+Hoh*Bl0|ZOp0PqO8teuSY%yHe6^l&Fu4n%{SsbDA5UscK3ZUxa9F3PF -l4CL=%QG8*RFx7)XxKqSh4|WX$qGnR;;SF>oZL*1-^Bq=;Rg@cT!pI4wQ;Cl1M|P=`$crQSuH-`T;=H -cwrja3E@t$+dr3&*-${hyW7nPkJ!Dib@+ImDKCW$>Ypk6{<1fuDVpG49A{&GHmwcjn(K{tF~rShAs8# -%HEf-|6A=bT;ly7;8hJW2eH7ptn6W003{KnIUs?`llcC!QdgOF_o`5Ifn%Qf{9Axz%KoY~8OW8{gS;w -n@S`i3N*=A$e`$V{1F0o6>yz_iG*;Q81J)eE$noV|b34HvbO*~vCmN_sJ_tXi;(-pp`zqw5RIPQ=X_nG5grQNPu6@pHe?Wngrk+!IKxP@qLD@mgdsx$o* -DWh)0i1LNU-o=o#EVXz`6%?ttTaYKs1Q*a0p0Y&}4>9d7qm)EJq420=u9a!0nxQCU=d9!{?s1>dxaD@ -ypZEY=7oRwHza;xr@u9mhv~hvNmJOvNR$r&ZmmOgS62TdNuwD+WaXn-7u8_WeW*lVdZ`2T{v#xpt)B;7*|v{9)?-QDr`8LcohS;Xea$LRP*g`o1_vu6vEuvKQGFuk$BhlE7)V)pbb((Xj{}cO$NoT|_J#G -PJ5}x`j1{WIt!Ud1Ndr`c8_mta>Pm#n7{{Sl}k`n_PF~z;r#nj`0s0W0n&`E&t5@KT4=r~ -TNxYHPmASU4*9dFGwnR1cK0sF8}H!>5MFxU1V_G&Y(F<~g8pD;EE4IXvNk!=qdW%Kf9_V{h1MGldBSj{oKM$y9L%sjeHUB5i%F5MRwy>{134{)c$>jiX0S+w@v27{^fO;e9<_5 -Xv8=+KQI^gEPF1SxjdGNI6OWl-%j|q{eP1&4%IulF(E5$_KQu^qtbFJNCfVHd*SK{hlJ&pvwk%-#WHc -nJ93De&10l|9f73o4KbSW_u>kv?I*9lg>LLtO0$p5<8PRO8PuQ2&KYpIl*|ITzN!C@%*gph&E4j~L;J -J2=RBUJrsF7sc6p~gA2z~btuv|A@%;Mg`@x6O@REoAm;uXA6>b6vyRW}}_FH(w-r(n)%F^NqldHe=my -KR_A-s>LZx3F~)By-eIMN5tVM(uvKMOmN{BR^%wkNBW^s!?Uu^Ok{N?hd)%La=>Jrh~S)v3S#n#gdD@GAcsD5GAG!?#w_W_mk(UgE!F}SdJw_qn6U)(5{_wX|9%{@_j|5 -EJzLG=j!TDE8OB8v#gm!F{TXXzY~_ulAdj~8C;;Vyr^rgfx#GmDUrIOG1=U5 -A!2IyIsZLS8L23q#|Sd5X0DDu;fH*_5Op}d;ZPy7r~~+8LZ72cQ7} -8Au;~khZpXI-mmYL3vXjkf+K|)NxwT9I#Pb8zIpmI05>3~?c{N*UU9~fC^wH=6I8_Cqq&nfyC#;NY=zPOQ4F%T&EXH%{lc!A -(lEV`8&<$hUpw_`yz8ElgF8B%XU;wO*RsrE}0nJMMKp6+|gi>sk`O -3}usVvv2#^iBxFt`(Pbh5>B1MW3AP%)@6aWAK2mnY{22-WK$1QOI0074V001BW -003}la4%nWWo~3|axZdaadl;LbaO9oVPk7yXJvCPaCv1?O^@O*480@qAFSC!+F6v#-jL9oclSCsG^#> -ls6|M+b_&yfKMpM;SbT~6@t*DH(5X+HK}K0FmWvD@t55h^oq2($rp8kUZm1fS@nm2aucK& -?XOjv&9gicftBny%SG?Q9o0Ofc903ZMW0B~t=FJE?LZe( -wAFLGsZb!BsOb1!pcb8~5LZgVbhdF?%Ea~rvp-(BVZfQ&zooTXa!*qb=4p{rzBlhLlPmE`QE92eOlL8 -(X0ZcZPPnJMSD@4JA;(Ujy#_NtAN8k20`0eJU&ctAf=d*AM7;e55D>4n}-i7{ -d249rcP>I*I8NA4$FHOv`UMm+UTmz>PFSN -X<&G0zo^Q(?gmxEMOj{Dx*n^vZ7#5` -%d{O2(Ob{1nn!Kx)y3)&6*`mP(QnLi7VH(WN(>hzs@TXbbRHn(ITyN6GG~xy1+4)#y^=z|!I#z9!|5R -oLeb}T`t;gz3y4e5*IuNvK17rB`fr3B&^{2F&VXN5^CN@_3b5o^@W+q)`O*w-WV|5}ZJfz?M1%F!W>O -z}_BQqAzOy_ne={8pHD-CngOZ&sCqaO}Fygr+q9KAX|IXXO>y*_?(d}g3r0#plRsaI*6H#7Qitd>~~2 -w7axchg~(6^*WnG@rFi){PI-FVZHv)`(FDBVnT}y`5b{=RCu?*#UJ5G^@MGzJGUec4}bg&kMcrNGymw -E6X=&u|3httO6#0{>KFX&z7f)OTA9V>hQ8HuJrP#U^zLesuJ*dSi%yD=9PAS9d)b%3uqTjTXl3iOly5 -y)VioMTq1Lp@YOQi06uKfAJ5L-AMkG-L=OovcNCSf(X+P7#_B>hGhJL~RawkLRQSh2Hx+a0Sk;$hn=f -bQ+f7>6wi!diw#3iGVZfhb7~m!=pn196K78OUFKyZy*lF16D4m@e@M)?pfCvR@j7G0Pqhu@moNV&6!P%?nR1IM5Prn;X7&}e1ohSt(ZktO0@HBb$Py7J?Hf9<#nueN^ -j!8hrtpG`FL6pRX%!cZq0R}&B8%=yeaF5a|&vd1l%e3eQxpN5m^6&wmNy|icG-Q2<{{y0kIuPAE6qRe -f1Dmks?tVah1Mq-prjBYH$&jFqUujt58i);wd;@&7sWL>h03cc$oL5GxH0c#S17%PmaS%^}>q`xo+T_ -_HvjzgG2DoXu?r24@rD>2A@|EVEsN=kj5>BT)p_eKd5!lGm9aNjUc|KU_eqdpKxyFniy>Ku$e8g&>w(d+VBD`;Lb -+krhqK0+@BiIb=!Hon|sl~px8ORvjpsnQ&zfmX!OkS`sYEZd6c42@F!O~kwaxHAGbRUfZNW`>~Bu1Cn -)!HS^ox*m>@me+=1J~0^V2T-t+h3McORB8b1BeeKrmM*06TZD>(jJrjjn0iABYx(a`8Sg<$kd+{qwK^ -}sy|UgPO1D5%1Tir)BySV`U+4uqM|_^^McURHbbhB^cp9k3e;I%o-hk!TgNge1=?jUy!zSvy(kV1Obw -^WR+`%Epw}~V4fyj&B!^l^Fb?-p}YGl|AJ;JGc{IpvLs8f$th(_@q+;Q-6(;ZrCyl=uIO@a6F(PI@M-&S7AeFGAn1+CbqbaW;PmkLSS>D7v?1jC -7v%SwDJ3D4Wfes)&>ciO&&!ra(MV<@!kUXgf4rxzPmpJC4tcbkCDdc6X7@)>*2PSOkuxnm -trK-#Pnz?MOZjdqdxHr+k0?2ku33!2nd1=o|bH=q!i`fk)635h)I!BWQ!axJVSxD1;Tc8B1fiSQKEso(jVeDOa!rJea(}Q0 -Cz*1Sb@?Gt=~>uLB9ud)*Z2TC3ko9SHX4NiTlSs@4*96?39Mmg`-QElOx6`b=RQ9dOT -?glJ2@#+R4a2=UF^0YvKoEfNR~fAAe5+1=I8?v;?&&|XbV8dejH!(C^PE%GiyK4WO)Q+08y?n -A%*#Y(%N2MFOnCCD?`0sY#m!6TE9jtBHnyWH*}C)V^Tp=bctvgkX>+|Q=kiyGJO7cOdL6ig#x=cgbF~ -`gRp^x`Rv(K0XpiZ>JKS|kwyl1)jzTckt7RI28f4AJW?HK0+vKdPy;j(XYHWf3Unf=(==M9&u{os+|? -{j#W?i4^N+5V%UK~Ad*~&F$Z3io3T`62BMC8H3g)zfa_+!)(yp)5{b_S5q9amQl_k4EYj6j^$~TM4NX -dC50hh^NldJxKwy4&veXboh4gdQyxP}dg*Lq4b8&j5{Y?~=!Zyc|@`{P)2iYjER7P^uyCci7+wwVUx8 -bLIJeEY2=%VsFf7xmXUj2F7Vhzr&YGHx2whzFA~O`PB!|1L2_jUF}P`%3GL!l3VpJV=uv(2}sUz$X@77X30DrQ3 -}*gu8X0IjFEaFY_?86cM{q+UYdc29_F}*gCkg*M*r@YFAkjt3Fbaij>vr2qp@}Pr$VZbD^3`T#00RUg -11!2^m2|5A8g7pPkP9_$V=e*9;jk~tZ#&=T`=09X~f_tm@Q~ObPAq4fBYOmQEv5Y6yXtM22#p5lNV*?@5_IZaJ6?65QMwevI5t2c%e=5p4l|>RItyq(Pqjg=Cy`yF`x-hKNRMD62I -voyWu+if8mh{VsWud>2eKb`9gj04y<0ol=5@u}={xtev=nK?DqN&?Zk8dT9DgBPhWXbRJKlZ=fFS8T9 -fyF^#0j1=@tXkKcYs7w8(IY6P`FL{weSsq8KjhP&bnb}nfgZgKi`un#`x<$hD{qgidMg&ru(n*uP@wB -)!=_V<_NI?alt$(M2aQ3&}E9N9dB5T2b_n8DNEKmRR7U>glR;DHl{A>&1)Mz2N?Qs@R2*@I^*1jN}!2 -FC8*6Y)_*#X1ZfI%r|vkP4wCOSoGkRegO)byfPj&A@%&{LL_gC&{Lm_~bwXAua%;?K$q|?r-YVzVSl# -v$}>4`%fM}e-0D9RceM;%xlY9E?_m6wTrKNnXurGS -V1F>LxuXSIHou&0HyXd6RcTSLbhT$}U&w{{hv{aCYhktiI6dp=rLRdYY|71$KktlwqQ1B}3F~ -pgck|b+cGrl#?P(eV-aH@JiG;jj^8XkLnmzj(rB0$jn;#R)XLs;>vQ3nm)HWlTsFxojjQ*oT@*6z06opPuJ>Znr}@J|i240X}#fFaZ0 -LX%PhzMF-*~OiSEh$HrlxX>vZDcNn>X1_)}XdkDXe1KJe=txG#4(N-n?MOqJ~&!`DdWIZa+X%SGgk5U -clc}hm{T5zoxcP!NkD7c5ITS=J5=D1sZZ{%Q0F(St4naDecva4*_ACg5_|G7s+_QWB6Ox`m|YJl*1oq -_&v$jDWVQDDElK>gDHL{bp^&yF@GF(Lo%XeC(*{%1!UN><>1c04y348N`>{3DU-A}dL4^tTQ39dWCO_ -V~9$g}W+t91+}8;e8H>K(9MzAisv{tQ#q8$UngXi`p1^)Co*aF8bYcT7Q_ -Yg9*O4w!@2v^92vE;XhzG4W4U0=I%?AA;(V?DjGKnJkCh`_Coiya3SH6R0c7SauV!_$|+~3*M{Z9RP> -0Xp(@NH{jf3BFi8DhAO8(-_;o^Njqpa7@)p(GdA8%!q+%N5-;_*;x2ap^#|S_ho@0_6CZ^;+DtK|NgT -iw5{J$&?QsHaaIedu7A~E9CQP_f)FZnpOgGFA09%Hj0(ACoYGH+h-EZ_4_sP$|CRAIe*4f2nL!OmXnx -Sif^3c-W0J?2vrp{292d0+OpiGbA8ZI;d)HPLGQ)M5iQRQ26iv0zQWBl&O3|jw*Ml%3pLq8NSG -2`v{BIYtYZU~~o0X}TaNg(pLz%s6~i32qLhMR2V1}6j>T -)l}_J>jyNl*)L}CshN1-h^s8b|{R__cfm|Ib%LL-WK -uZFJJ!ts>ZajJ3(IdD%$s<&6RM{HV1B7l{2PY*M#b5%Q*rT_GcF0@8(tm0`_}fTT3T~VDjfodw=Wo=2geeI -@f19?%dVia$UX}oS+xHOCyVzVNt=n9gHVyPClZ7hh_(by4b&L*7<(5T41vGQO!Z@-fxp<$up0b*1K^Ng43yF{A#UdC6$LDtz}-nnX1 -8$M+dJ40nP2S2Y)y^8~BraRf48Z8^V~Np;pTh4@K0Qtm&#N>Ll^X#(uzh)v+S#KYjdN%^Nf@Kpj_U?O -w;KY;j}aZ(GBu2E)7LI6}RDcY20)MJfx}o>P81g?T=a8E1_YjpK~Hb&Nv~Atr48@{g=Cg^`L3TgF#K@u&=h#DWg5Go7cAV-HiC&oW7v^|ISTlo($5a9zXu{!c5^^#f68ohx)mZ6J}L7M`EFPCfK(#EFdHF@2{Veki?8Vn_=-|J)2<(LB|9GQRA3mmuM -V6qSD5HMHAykD!QfL(kflkCr(fdoP5CmH6j6!b42)=Ga~rO`Ws#!Z*$i?`Q&Q<*(@uvW;P?eKl0Kyk0 -$DX9NfLEJJIA8xMRLg{67%Wb8QpjSmo-$nGml}=EB2>Q~K~?&V3}{&g$M?reynj`S4=y$TN9cof{gQ6 -Z7}}0Ol(xaXRor#HQWkRCe8+Vw9cOro87$!Z}IM7y1A=hYp2nK0JZGQd2I<9H(GEqnu(iY4#Q{=n%t6 -zLf`*w;+Gvg0qPltjaPuPpiq(C*M6MCgaUVicZm2aN9h4{N%gAmr=M@plB=RnCh1AzxK|N#bCh$dUTC ->SzC!}ivE3aa#6p3$}lFS$B8hLYRfx@coa1CNcc4ziD?{<%_)msn}TXQQbK{C2M!cISQTU_7=8_N&Zy -Utr=>`+@$6KzR2KO@M4ggscN{Sj4);rAFwCmSTqbKDr1^9FEMv3n=>2c -EKeB2GMeeM-(6!`6!ZlmI#FvcY|br9U1-_5vuY&8eF?O8dZpDCoexUo33jjB981tRcjo~F!v)%O52m)a -&X!p6GJKOYZ$`|jo+Lo)cSXKs#Gu2|VTbb&fE_#|6!3vybSlNW5gRP>47tc9nJ@!6XQw1V7)UfEICY& -%7Y`D4r@am}Og4HwqBPAJD$%hTT2pnUA;tz!SryKb`u8fwH|ghW-L6&9uFrMlRj8R#3>wS{A1FZ6%R0 -6odA82*451bGutsXG?2%z|NO9vU;8JonmyT#y2ZIl;CjG~z4Vwfrdipp-g=eDyC%aBz`;$U*?`6#F3H -ueBkTBI{k5GGXf=nr8asg*~8d0oEX!NqyfwITYNmGFnj!FY4rWW?ZM%gwLs!-zGZl=p#dVnZU&El87qm}yqHsUc_5;Ea0XNjM{o1FJ>j3&p7Xh_G0%JU`rJJjHSIgsKm6s(CipRJ!cR^NtYy^Ju -wJP`Yt9JbKXmM8O$sGp0#;!iq}Upo>X+;X744}N$t_lwC7I~-uqTvhxT1*hjF_SNSOb;4h&@IW~L6cIp0v6z6M{1^%2N -M^YUqEFA{*QWDmY^)EbkivoKZ>WqtL|K~-SF%Y)^M}wcERi`DtV;d&>>R7mN~F04MSSbI`Dp3Oqf1!p -GB%^I0}ko%*w)voodez0L3Uf7^-%`m^pCIj)j9!30Dkd@auiD+P1z1zu34Zz<2-tm$L!jEeUG{0)}!m -+s5o`Mfk+j%G6J}B<*H{$}8A-hasoV@WE5`Yij$Pz6C8Xz_1PQOYr=sx-9H-{1QBu=yck9CO5Iwr*3T -P9kuScW+Yr92NpX<;D=*31PS{iiGtp8xriZh*hAQJ>Ptbmat!6BJ?G04dlK0MfG+&_AYV`>;93VJJ#9 -1hBZaf`L`42*=)vF2LiihVL(h2^!VtIdPQ^r}A6#SQ9en9S3U`)T7ycsUDl)C^5DoDcRV?1a0>+lc=J -(O6$@YD*Boo(xGY4uqFcOH`gcz7C>-a=gh>0*US<*d|Wr>#*NUi~3;U|AIO6u>w%J3-r{vlr?K%_u0@o1vUya9hKZ&Y -6L0nnQibcPWG&aW8!#zqoEYlZoii|m?L$VV#F3Rc<>$Ag}#^lCC6O4y_N3;6IPm3cH$-^-^OR1o38T? -YE5-707#9EjS*xb=0lx9U?)Num12d{Ue<A498Suv*L|z4zB}@Y -`uo*rwv{>uqa@8EjrTE2(x=oA}2KhKP*Sy-x8l{R|M1kFUZw-EMU -o72Jx0eVkmQpW{+eiMm1F?VLjr7~oL1488lhBSi9lrFAYVKPzOZQ^5pyD6#fam(1?tLXnVflA=ZxrG1 -+i&Ch04k8FQ;J@wPNX|rwJUzPEok}M0**g_`)8TpM7hd -w^&CqBk?zn1(5XNN!jg8}|GG5}KMzAUiRxhAjs-gf`h(d(nLqyJx)zZcJph+EA#MJryBK|g*4z4p5EV -8gQa1lIi%1DJX2N{&qJKbJ+~ZC3c20K7VgGQN1apU4>5WjSu7V6`)-uB9}5jSh{Q%T2hB{ -=};VO_Bc|u_Sh*u9NpT(6g9hrYPa{0e2Xm^yS;T+Qr&xngQcfiqB;r!?ql3Q?@rz#>RUQ*!KXjd1>XB -vG~h*US?{DKMH4gsBlU+CFYZe(QY=$oXmZEpf-ZYN%3&(fuWX2KTemO!h^`H!n;QOzwWf47X*l>(*%F -JCg_&W%nsqYhsUT=K-I+^s(bS5rp$;wxq_m@X--p~KE7wgMh=Gf(riNH_^Q#?>nb1AS=r#l#(BD-OQUhJ{^Y{Bcb!eAp6RMRUWzlZq-$D)_tCl@5G?!>!jj+!Kxg5%njk(1p*P7~|0`DZusc7w&(BI5fq!qDxR`*eg1NTs!>UUBD -CGOj`AsuaW#n*mltlus^w69o<~!bPg^6IK6CFE52f#-eFbIiMWh-qtak7q^pmYekub`0nb*fnD -~VfLvwS>$V#JF{6M;#Stc1l89oN2M3=@Hy_e%P^akWQT?QU>CD&~tI8@Ey#hk&doWV7yBpi-esOZ8eJ -_@=jnNcv?ZEg(hZjvwD9S@?By~Y)<6&a3vJW`q2tvt5lZqQ^#x0FojvXbFFxGK1fmg{ybtA%&p@u}d` -rraExSA6tdl~{XLNfspgu_4A~XSFXi?s}=W>_0eh!L3^kfiv5EIlR=1D}FhTQ(n&JA+ZE9ldA~pa&6z -rQ}_D2x7;`YJj$2YFX(KIt&Rm>mV^tL$Qj;e2)`6DlCQWR(i~FvTi$&=z^&IH#20SCpuhGAzYE5HBa8 -#oybh-Kp3LYNK0$~r+H27Mq8DX1+9k7pTL%&y--2Na-9uo+2nz@c<7=+ElRZ>FQC7|`J(ri@pFO%VEb -ByO#Uwd7`nL~9r)Q_L!-Lt&4{u++J_6#DRScs03qc&hEZy$C<-K@Z0ohPI&#pm7R=*^&6EQcY=<#L!Z -bl&cLnn&|zmt*P{^&_g)c9TK7Ar4&iuB4aCM=s+^FpH;D!Rd{p?Z;QXc)9{s?9}jtms(gehF0v2og799SvT -FEFfu*h&n(b4GCvUJYjC(WaAwQy5}4a{f>nRcsPE7IsiWi#qgtCxymmMgzt8N_B{QUNLdk3 -e+sofg)z5rXJQ5z%YB%cz}aC=>zy{`yYILr3;dD`Th9`UE{U+RR!Vb<|6aNWNO9KQH0000807zB_Q) -Ot1(wqhW0M`%z03-ka0B~t=FJE?LZe(wAFLGsZb!BsOb1!prVRUtKUt@1%WpgfYd3{&SZW}icz8mm65 -D5ZFiLJ=8>^KIJOPiuai?(QTivyb4r6k6?-G(+z^pYv<{BZ_pUz%=ZP_$v)wsaZi< -675tG{wDdwuiS3@v=`YR$(M8+EHi-BrPW{p>byg)PO>g^lQ%M*CwLSMClz3)O0It9=VT0GF)5p_{l&D -6fU85LZscci=9~UODQ6H+47H*J6&jLY>1M4>Nnz#K2lG`4;J#IRutB1%F>hB>{5(Jg|orfPLGZzNBzVJPPBI>6dTAo*?1R -R;i@*r%n<`Klu>q_Po0w9jV^8)XKcu(=CrEwMh53(<#3%C#c0YMdB0}PX1W_hqVw=Scu%r~zmjzAT#4 -UTm=f^+-+%tfRMEi-uT{`xGHcF>ES*g0Pao#{^%&nFN{E6BhpNXE%_Fb?ViO$x!N9MCLoP -uELkY)u7G6m=4ZRLYeRgR0I4EYL?l!HZCT1$sSN6AAU2@!)5 -WDUH$GJ0n@g$0g;$$!7iXU?%5Ay@a9kLCY0XQ<~m^2_nbI|+ -HQh>V+lL*76$sVe4Z-a5*&1r&p>S$kFLonnZx40`b(^LC5pvD}+e@?# -nSQ4>etK|MBcKfT)UrUJ-@%#9`3R`{ -C>v#4mUIH;W{W=f=G=J+;V^X(p_EgRqF4-fHUp@SX~Ai5Yl>{m1o=pu!pSSvUR7n`CRPH{uY|Q%v``3 -n1*Qu#V%?}RGQ`~sW%}sGTz*|@Ozd)#rbTenX>ysQ8fAfEhDTnNj_nOn6m>vBiA-x^O_{4 -cL;u|7AB1RL0!ZTFBO~ZuoHeDjDZTr~lVKlThG#8ZLC{#KLbMwUBOinzsS&-42K8*0Z>Z=1QY-O00;m`Rt8flV+b;d1ONag3;+N -k0001RX>c!Jc4cm4Z*nhkWpQ<7b98erb98cbV{~LHHA@4owe$8%U*ETGV(tTva>xb@;E{xY3RCue78(} -}^y2CcK1b*3p?W6(|~Ur!$vcq^QM9tUnK9MpP`2L9}5TH5JkZS;=xDusoUy0Rd5wKfiZHzgV@-^#)rV -OgPfHF33&kD{*0+&O$~oLDJr-x)rg6iQeNH^Sok%3@`ulTXNO=@31;oKAoqGUpl!f-hu`hdeJyB+nO0 -J|O7T7qT*AdKP)Vs}=6Bau$SAutT@iCH-HOpldWD_@mbWo##Wvc@DzD9!ZjZSxsUIROtGU=NViptAk) -|^ph-+4;2S-DIM-CVLCgmiQ)kdq}d?gKQ-BiB{&T$^m9DAAn-#n6e -{5H}`JkIq5bjMaYS&z*(NpJLlMdls^Q}E`BlnVb5{|1%|yOFA7~bA*+ywJ_{_K!EfaJ6Ph_t37G?V<; -hwR8(16_7oSKQ{E2dTdD+Fwdn-%0dbT`f1JGS^T@+ZmO!0R2@P%B$dVzAohN@8Lexhszm4+8)O5Yk>PIlhAy+Q&>(n0mmR3)xu<&A3_zO#}JV7Z -i)bjxLGQLX1d_KB-cx}tzzTs-WB+1PGU@WY^N>7Avzh-Ot>K6348SUEFA;$A5qUBSQqjaWl$Qa+A!4^ -5?px63f8J|A!{BfXg&xPbFhF=nuZ7sA&>EjvS)*FN -9ZmU+%ain+0cc}sSB~~Z2`YTefQ)2kgi1a8XX# -k^c&-m(|c=8gUFnqaAP}PBs037gaQ0LxT6xZT*ruRzeu6z6r)Y4(l}aBHl~-L*7vAXF~|b;siFrjH1$ -7*JDQE!N+4NHPxJny`;X9w%b9eKc2&Aop+BvePPlE;vSF6j+?X%$tUfO%O1>g -|tT3^s{hVqnpi^_Nk#gV|5smmdQk;9N)g!?fBj@n2Sq}?{b-u+AwH+kYbbgBw7(I@kuaWXKkg3_#045 -0|XQR000O8NLB_@ulMP3S|-*Zm>19nuG9A`wm9Ird^I8|ghQR~>Q9?7P@S#Vt>2Kfr06>7`NJ_W6XIH0&L1{AzD!E7$m2SdVp-(ZNi -0i&t&{3b%N2WCR7g>mG8Q*Ub(v)1P(lCvGxIu1%N*Ox>r~A1Lde@n7Fm?S9J8`sED>6uC -inSg$zquo70zGIO6zM@LBBManny`)KITosLYj|dKD&}t^R+7Knf3Lq=~T(Za-O73*PE!w0DVo1pA*$! -UgQgyO`1xD1=Zkv5z9ixuM-@C8ZDD$5MIkH&WoTfQkeP_{ -tPgX!iBL$_K+MF|V6s%4laC6GcXLVku{)yn(3`k#L$;P0n8uVCtcJn9FFxT|D2!kvVtnRk@0L+nQtvv`{i9Oylt%)Wb|H(fx?3X5qzspLJ3SCWnO!GEo-Jfn*@L;yzmJwn06T2flV3q2v -rqK(Q&fcbI*c1C379PFqG`MbvpmR3nUx75*&?Yx-p=IGp*w}DgX}s=llbKD?MQ$Aju1Q&Z-8#Uhtu>U -)AUH3WQDv*vN)Qi@|!%q+b@c|7$OP2+dn?s3*Q{P-9Hi&;d?$m&ihu!1vpaW53aD&w4J1sxFKRiZ=zj#Ov-dMcY1eo}_gfGvY?fiX1E5Ue95^abG173A!=A -`e7T3s;RuMggR3xf|vVi0`FlT4wkkU_ZwYWIu5=& -XDSuk91*M>9k<>@suG$#GH3;pu=Muj|Kyb66;?6yP?xbrXbvKp$v@DH9@-|!FS$dulCPVW@&OMpHu -+}AQK1Sf4!mKA9DH3E$2X?$7q>qJUHV1MkY&ff`uok?|PVz}CbE+>ZSWPZX -T>I*oxO#o_+9;nCj&uvz@{`p5T&uSX&S%7D}PGx6xkg|oDvOmMw=MSrPfarZ-%)^h*WZ{wk7b@%^y)@ -;4u>E?O=a^3?~7D%jc2%~h7BMVP&qC5B|G~e&c-gGjX^RJz|p1mH2=HDT=_eT$tntlo=BFifW_poE;k -sj!gWV=R81TZwal(Q>wjq4U9{)mBBms04{DuBd*$l*J1j2Uu0X~Xeerui&NUwI1IApEF1J;j60{Y8|; -^n8{B(U!|Ri=CZW6SFAGvjjSEhoE`a-ZAI9VvgQdHnpz-Vs6yh0C6`GmRrp(fpG!W=I-)n?WHvwDjXo -cLCRiosbh7@7?&uSA@qp7mhor_? -!kYC6v@qwGS8i!`5#5>?}D_Lxb0&2SW$7999obT9_ejJCo@KqErO2p=8{d$7`rkv@`ciy9?im=J!7n$ -DoSA2vWow1+?pM5pDY=7tuGePIf_ -bYOK8(Rt~s}w@UhsA%oaA$S`Z3F%V!J&~sMYtcl0X^vZe(3UewmKi9phyaMY09$i$I0OTDo0)8=L85%Bg)M7! -gnTXAv`Q)fuV*fC7X4HbqW9t5(_qh<@^?kkb06wnljCNg?d-v;2+=yWDN8jFcmO4ouoPYwmWFrfdk|M -&Dw;&+_+)FU+$(O;rtfI>2afe_qgk|!xBX#g^O?(GBFvtl~n5he@&9MYhStJ?B7g~m3&?DsDnIz@94G -FC6c~UG`5wFl2Kpk&D!OKC{fqcIq1%;1R!6U@ryrxoS8auFL^i~jJgr5X5F#0^g -Ld>j$mqr)VAKGE}VIbHY6WzhaMPv#Q2OxPrt5yPX5fgw_XnZqbCjk3PQ7X(VO_4bla*ZW -Ao#layTA{?X?9OhZ;R=3G$uxc7IQDRtJivZE$I@5YAQ;B)+0-4k>76hPdJ;@y2|I`jEb|2ryiAH1D5I -+BB%|x025krJoJ*M*QfY%jg&9oxC{6EBS4KGnyqYK_mgTHSmKESKO+ZmBD^S;HbC7B~fHFA7z~1Ss#( -Cyd;tCb88$Or%D8qm-vmAvd*c3=1Kg$BiByIytC3?sd70fQ{>;Wbr*Gxo1c0- -uH66*8Z1LUU@@SY+DmpG5DG|A|3hQJ@xtq-9+&DGP(u~12pn}W#oh;1)o`I7fzSZnh^*NpjN^Fz$Uu; -uK)4?oBD9Vwuk*KI^s!F?!9B9uMQ`mFf9zG;h8$itNJgaqDqJy3uGZU_jMw_eEJD^NO|u1 -UE2Z=Sk$q>_**R#_Z7~IIbLDzRcBe=dGAe)jlv)K~t_026TVZwAAA?xpV7?cXvm~+oH)M}b08N2fF*|v5M|P&&r+6`+1 -Q7JE-)zw^K+XpYHi0t=JhN>Xs|9iY-Xo^`2dF3mIbFc1-ymb@CNFx<5w!?$yZy}uFwCELoY?9SP)a=b -s;Po-KGJ=+&wG@|7VEl4i9FEcjAl|q;V(2XNQ4Ly2un0v%96u3crr;GYdeJabQ|c6^guiRRHGZ^3P_j -HPeP{7Ko>7zqOf_hq(WV@yy9312`?VG>}qwkXzOzh;cHC=aAKEBv7cR_1$hY?2>e@Wm>NfxcYh>yL5) -j5-;y0PvE^%oE-7e=H3Itf>M_hVbVE?2niZRO!>Pv -Xu_@6KAjtWXz-kVna65F-XKV1z-miy*bDzG#14|BBw*VMHt6sfKf5K1Pt^z09`)|#<~@wa68#s**pQqxktCfzeYJY(d=e_$wNvTQ19>azBg@Ts3S2TA3&SQ}O?mgL3fL=x2D@ -pGIM+9P2OlvbHEwh58YT_aHkUN*cTGL@l&(AKuPK;5$g+6kL`Ux=Fm)DB_>*LkA+W=P9;T7aKdq{gHe -_9jn5o`EpAiL$DZOWd;*iz`?Xh=>_>onf#Ec}6oVu@g`L7Rf9`XIOiNcyJJ42s|N9Wn0;{Uj;O4-|Q! -@#b*=^hmOJLj=@~@k4?r2Rz5!R^KPad?GnD|-=w=lrm_9rK3%IGnXv@=OXb{x4sDZ?bg!+_kKfi!WIK%B6`rMlp0>~=%{;7HSDqz;Ca8#WTa -8-kJMJ>#*hZohiZFAFjtLj%^+s!!eTNXYwiDU&tA18M6p<&@^&$OTaj -4zHoe>tY<_H;)X3J?O|$?1@YbXIyp&5Eto~M*qHgseTY2yuweD61)$ZN;r?4>ikHz%UX|2NOWfz`aBdCqn~8AMzK4$6uk -Hu5l6Za_nEw;U#3g8)*Z*fq?j2rdP+G(BiYEN;itw~W=X?&<#2fVJERw3MFO#c$<3<)&Kg;?;_$E);v -c!i0ADvESYUl8f6M)7m1;rszXifp*^iCYU*%RBF&tHfmP74;>CdJ_(WB2>4P9wlCjf2^?i)g)+@GZgv -#!xA9l5-tWiRlF;oFgT}FI5^5#sQOTmezo7N`Q^mnLx`xh+X#)r=l?c)PW*YUU+P343^|NcMx_5R)*< -Csf-hbu}ESN_t5n({0?_mM-8JIRH6vIKNR(vV_K$ifi$S7(6m-fZt~))WP^2#IpyPzyalDyJMfV$OCl -!Pd^HQe0EX$JLM-aEO3>?GB@3Jn@Us~x7DDIFV!nD(n$*!I@8p>5Ga?{!Y%r@0AVfth#xpp^<@h6F{G -;Jm$Q`<5;#K*T%tm6MFiG$Rnq8doYh*U|d(XJpj&oMUQQ2gOO~#8e4G~?y{*6ejH#?#*7uTqaDWvHHe -Y4mxQrUtB9-HJnrK&Skao<3*8N$ri9sfZV1W1PMfa7|qI4XKZao>=Jx|!eZ`O<6wnxBrhNIRy_>sw>` -;tkpTP!`W4mZ7~_Y)jxFe=D -MLmZQ@hhqmMrX9M)44>}oym_8a21NVwq`VxU>#LXyFupC*)DSU=Mc8&f9^yfXjUv?~kYSUO@?LzCNTi -Q|?*UXi0Sc}+1Yv_i<1;fj31Y=3n!o`1co;t%Qv-yd(xGz}KB83XJE6`hQJ$;(3nmb~uwQy!jY(4e`d -iK?4)#BGJ`wl>=aa^F&u83KcFpCIm9W>>0GNF|7sSodOCCmMO({m$hm+`Jjs+qHgw2pkr4hNrYV(CiX25z -Tz8OXF^TpIFsThtrL74bfU+@(Tb1Q-3FnIxMbix -C4TX=LSf-soBY@^W5hq~L$b-G{88Fc^V6H)RTMe{p4asMP4$TzrhD -0d}tGw(@kVR*egGy8oL15A``q*I7CemPoiNwjfJ>{3jIAA9#z!TAFa7@dv?h~DdX9LqI@g}`>D%1Q1u -g5gQP|_Xg%JVrIvt)6$GR@Xhk`&`E&TCBmDS>HTYI%vHn`dg#nGFC=j;`X -_l~znrFA{sy`A<>NKJ2qk`qXwICCKYTu*#5wY$U2oeo-nIReesVI0@k*-pFa(=~F&sosag^fub5xvXGWGeCL(3hv3L%|Qn&gDE~D{ywA@&c*goja1n>$TU3QD -SD$;SuE9z_dYSpR})x*-IZWppp`Uu^T9Ic=>bXe#V#0L9&mg4E#;CWCGwRJ#W#0$|Iy&D8iB+UdB} -N#oB&OHbyLGyl`}&|e5Z`(r>^n{o>C3P2|VS|0Y>N_~6Z60$aTW#+0cU#ou~D=fY{KK>y1zB|dnwzyE ->#x{-jh>Jem#5GB}WNnDQF99&c0w?T+_*=vSPadsvG7%pTWM+|TPh6eb@6pP!nxnj8k+*R+!O{Em7caj2!}^wIcL$M`CM=jXK9zZPAE-64%h@z1$8XkOP*xTSJ~GRmJ>UNKu}Ocuxw -#1vS&hGE{D9g+36&vVu!Rj!>6|`gb5h*gX68rKN -pL6B33ap9rMx0Al-CX0*xni4zc&z%joJ%o?r-803Q~Zvo(j?^prfGZLX@i4elwAwuTtJUWnO4jPHHz_ -80no)agBEf8J^BRrS>k1Ev|dlP+TkC(F0}bp?;8LQOY$K8uZz)8aR6EaFSsO)Fw+`7yY2G>P~>QVF$D -xFwL$3SKNg&w3PN~RL5mr@`VF61sk5;Lp1Q5=P#j$HB;vuUu{&$hDtr9d@da6rTwzAR(^g84aeB{3kR -?j)TEaa=dH_v6)`gh)+FxtX(#MUAqANd16hNhNGMQ+g41TcpphIZpq5z(1Dm914M?$H?ORS{Y&^SLfj -PaZ0#Czcxy5!M<`{sb*`Pk7oe22QjAXnR?U-uU_4FIfgkCKEzqJx7#C~J?sHhIVTZ6s1duTfhXPew3= -8HfJdW$RSruSX|RQwut4S=Z8N2Y5xkNbpor|*JCYpFUwWWmzQexvD2Uw(F`b^nw`Vg+MW6FdgYwP&Zj -&KjC_JY)2-&U8>yoE#q5?l~Xjz#i%SFHW -1q_*CkEnNFN36v(yU%|suJ{Hc*1KLv&#aDtoWBBvGsh|(%%)SSy?DuAe`dSl#}uY>hr378Vm19=?%ma -aoM@S2#cB_T3j;h8C4?%R{+FiaI`%>Z!Mv}5Rug%cEy5VF@kQ-2YP9pP~|%Fb~a>=B7n%eNLuuLC^@a -dx~BkSY$YGyg?beQq+1cPbeqDrBCjvdBdt%<21A_P%_t#NGuftI7T)7Uu#|q0k#sKkmH<59+=E9@c^S -GR4O2n9su)!`<^ -vVXsp>oWMnMw^S#`Wmr9U?v)QD2sz5=Dw~OfrGQ5n1krh8#j_|sZoxbQC9ANTTDD5t<=~lF^Nd!mc-~$DWP;a3ikAetGo@TPrhhU# -WZDTd#lH5AvnnBOf)*rTmt>-U-tze4uq0sGP0c~z7Q0~dZ{JYlCOqPfwyyiz00|T -sTIJ@$_$y;xvYF!2iKo7w(%K&@BrZg5j#lAo~3CS?{Zrw64ZK%@GBjLw+g$ehn7s(t1J{-Ek65byPQq -7V8h~Mi8xvpG=1oM`}rLPBS9$RrQccS#RA*nsip((k_6X~)Wx3_}TaipHx+uOkUe}{PR{t0#k%G`d|5 -T~Yv?JvI!^#3;>X1{8GHgD(ZPyAi@TjJ$Qv9m4K1+RErY&l4=5t&taCw>~vlDN=AsO|5}{Rc^PT_~W={6SsE!p?e+@pgG -0a`ma}s7SCtL`P8e9mlzFhX*aa&iF(jQEuI9zo?^z$EF3vy8W}&b0Kx5^0ulXohHziVhiOQeSQVx^vL -ersju4To&{|7EMUd{_tQX2X?p~bJaq4;Bx95cEr5x49a;%Uwg*pE?V4kTIE1JBdB`91XH-Vs1MTX|$Nek+>SS$q1wzUYc(`3}{~d(00ktuuu{=*7;tb9KY4TZY1c!I6+pmDal8v&;}-ENUD|SXJJ&Jn@fK+$H$&WyI4zZaA5G^d-|zX$t -c(puc~N~sC?r%z)}l*)vzX{d*$9L>mZ{21%k~K4?b -GpzL*GaY?WZLI(PhQeI(pZJ*_DMUyVx~lgqRS1*e%ttHH``JZ28c`NVw4G0&9?F<7%AcZMlqhj+_YK} -3svxm3O&BkZ_79u5^eV)M8O@d#VrYZ&avVczb&`8GAH`;dIqfWp;S9>i1vRCmPL!Ka~gwPq!~CvG|2H -izhF%f5*V7=!sDN@QOJ8Z&~U!^7V5i>?}NkTzYOSB#%;| -CT(5HT8~Z~>bE1B8o<6~8PL=3#H7}I?Eu88THL(>*jV9JJRG7n2In;LO2KT8PR>5Q3XVlzGH=g -UrdFe%XCCKnLJ|9=|j)IO2*cJ@&1+dAD4fNV~CN)~w%X)*uJ^}#EPJKVOX6W2+X(Tz_Ps*%CxVB5D5p -J$~j5T!i_SAG~Stm|$HM_{P<@%EIs7|X8%hiQo0%sM~9hwaIme{%uVh>iIV3k{IE`#f0RSLAAN_YhN5 -y1r=P~r521EE-P`3K -2iaFKU+A&o=SaGp@S^(Dji;XdW-re&zV?T2(EwWq4e(m(M!#CvQopvt7k<(tyDB?(56!0P8~Vz=z}7m -6t;3$Fc=20kF%~b;wi|B*L9j6gZe9hSmh$4&SAfZMLJz*8WYWnXSpaS}@a}1tL{FS~1LKx)uaa|eo72NBv%@!+Iy{X=wX;p39ff_(uO*Dc)0bY$pM-y1g@7fCPV -9pYP4=vN@$DhUUk4BxF1Dsf`-?xm11*7&;J*q1-pf~nq~Wi2^PVhPE3x-ck?3yHY;&vcpNL6!>PYHUQ -5I_7W}ZK=)h=>O&If+!78p=_j+qzlYRmw^%z>}$>SKjecSM0TVwO`TWCYqF6@<`5>_SX;4C`wC`DbB< -VDRS8?dGPZYD}7Hji`f~>>23I=?Zq4Nd;jW6G92pQ?ad{?O4xtEJeJ -*!qgo!Fe}ykn&2y``dFo%BO!RNtkiI1RAQMzL9TKwOK`fZzUZ5^Nzs&}<5+gB4TiN=MSG2@K(A9d|HqAJfG0x&SU34?9C`pZ6?m>v_+@;Nj|pZ9QMTFx*7iC -XDvcuqqxx)M#+0MZ2YrpMkQ+j#0zKNpy?J-SotK{-FJ4MWeNZ^&rKiq|_Po>ufd#eL{O>AdW -+gCh87t~{5r#9?0@jBrWeTr7MRdqSca^89_hzqP!B2g#*p^cB7ethgSGj9LRmrJLsSN&)R_pdFo*0!_ -Vzcz>4>Ku5b)BxWGz8tdh9wze;IWFa2paCdv)EkSJeM<=x5jiEu$BT&(6!*HLiK#+=jUhrKSh*McM)8 -Z+`kJ&!Ce;i@wQK5UV&<4y?C5ztmngJc}MCZElb~#_z8bQYXs~ux>#_6jcuMem}p$%x{ -1EonR;=y;d^d&4bHpouW#gIGXM3tMcd~@5@zc+s1s%}(Lcp`MNllDyM!H4D -tH;qG5&1UF^_kFki@2E*^9rldov6sEIN%&T4T;Ef5p}ek2{EagF;RT&yVai#8_Qe+j1=c~hBee_Ep}n -{JyYIs9_IF?JABKnf-|qiM_|0FB_uVUnQ}6F*XGf>-pW^H+JAeAS|NQ&!a6Wy#kB$#J_YtXYVfWNTLL -m^V0z(of)m``E-w(3DAF)zr&nc6TlvXhir>eNR#-~gnb-f*$fL^*pE(QEf-@oAFy%_wcts7X!$Y$ -bKkTFb2CDQMVu2@T@9Kyv05MW*W(X_={sAtje>XlbTvO|-Zqy5#YlW`D4o=^qf7(GS?f{A(lJmOZoldu9(DZug)Ad}17CgY*UE -cAVtCsh#kTrIPytUz@4)ga0p3O9KQH0000807zB_Q!+YQ{onuq05bvr03rYY0B~t=FJE?LZe(wAFLGs -bZ)|pDY-wUIUtei%X>?y-E^v8mkTGk+Fc5`zf&PQ=)Ic!F)Tu*~cF0ytwo-&*UqB%1+&jg;KQdNrCAK -!b_wKm&X>FX-T79S=DO7xg);$ng^ja6&q#dpt$kgGRu(u7+!l;1J^_g)r3>9=pArsHOM$eW5_;515v5 -g5Zxr-eY{M{`<8`FG3e{;4D&^+hwAzu1LgtVfc+YXuS)xnB+LHq>h2Ip4_DYD*?MzJg3%Y88zQrrkzR -d%U7E87mm)GL*(dd2ZSN{PfYn&X*6UYRO9KQH00008 -07zB_Q>pxk(EUX=G(`b1ras)mY1p+cp& -42gpAVvx#Tm_yeX00;5gZSu`k`pjld!bY-(ckt#`zu^_u`D&(Neq2a0(EvlO>n5_6!Jb_|7T~2%5Xz;0;g$giUzi_)*C4D}fgk|_QT4>3E* -@RLa?2bEjJ^`AKKAd&>)<$vmq(|AZ6Mq8oR2XIlXoB{E8)sP$<_PUB^C12(Tv%Wqw0r0W>4ii4&KPY{ -n2z8MgMkhVs0JpmqMO@*@92b9cFPvn@Vih5LC@(;0U`#u9Wg|lS#2D9go{V(=&?=NAW@0DcYDlmMS<ktD<*vt~rsm6I2SFDE-ub#B&Df$SYe)f8?7D65t&{%pO`0b(AN>~digm*pM$b -zzNGofM5@XW>p+sj$xIo^Xqqh`_Dj^fefJpNhQ0P$V*|YUx)t?|>9 -iXGD#;hbUm9q{Ns~Ep=21>z)Ocv>~>oBA4ZlJ8?J95z97nw5jLZmWiCTXoRw=K4=9foH{uQY)Bybp|w -lbeyw3Oz6gU>YI7WeW`rJnp$coq&_^3NwuHn+>BN5p4OolovHFAxT}K<7owo(*4>r7&^ur;sIygCE&tj%L+>%Q5(Wt#`qYV`^yfzoGe1 -&tfIl$YIYX+h7`WvW6Uh4YDH{P3gynpsRx+g(;2|1AQqZEgf*Y6oW~p<5<`6p!G|Ep6Pg2X@40*bJ2Y -qMPg@_k9HLq5Z#EH!2Uiqw))N9In||o~?mujLYT-K1THlRZt1xJ -g8H}AQ$SdF*;iR~bHXb;n{yvlXraPfty`vFsKPR4@fyhmXSZM`-(Lg$(DH839xEsU)v5Me>vP{ -_6UHTg_{%%XCu5_I~}F6ewaZOFwHV=pHLzBbXC==!ypT*SBVEfnNx6~4+1DTu`P&>&UBE%9fqH`p_c% -SgKRQWjEHJMReZI|?#IQ-A&Zaf_TA%RAt} -O>@G+D5{QR;gETaD_(0Qr<7%BiqGj4#89j`yYV#TCZFOY3yT!KY_NE*9Sf)=aTJE*8Z`%c(xCjTmald -C)!5ID5OF~IgHR&NPw-I3ktqC>a}hrdVk?bwW)h3xg)p~vscOR9Gv?YO80Ae(zS9yxY -Z4nIJCbmHx#=fNbq^bZk!@4m)=<6WHh1d9kD~Ulmero?t#UL_I~1{{^n_L6P -PdOG-+h!*GkozxRG}*1$pHs76-_sq~Ou17)`bDvMQMyJehxf#@ -NvNk!CE1Bw=XlK<;CMh_vG>-7HDnv%sy1Q@|fLwXL8Hhyt2{$<-#eVSxaTwa;Xtd^nhRL+O=U;|l?WR -h3VSJS7ntf6ZzaNk33e{{m1;0|XQR000O8NLB_@+((i9?*RY+c?AFfBLDyZaA|NaUv_0~WN&gWa%FRG -Y<6XAX<{#OWpHnDbY*gLE^v9Bl+AA2Fc5_A0rCzDpB%u|1NhkXoB}~|j#lK#W=oSQN!fLtzC%%tWY^_J(jR7K`siwxQt@klgg;{jja_;jQ}DOrBB8?VwHN_KNdoKi~AgW@AN=lk#So7yelHCwl -tKGZ|8EO%1I($k7#Hhl8N*p!GCFBoUYFB^Pa@%s~xQ}J;~=91N5>jw1e0Ek4I94VcJXgauspHGIkEwi -k_lSU3#o19BPlgrvtl`XI&;st#NG43ujpMStmvh{(tyu&BtCTM6Kt~>Nsh#2A?BX%_%UeSr*q6~cSL -6~=2SXrgWrMmaC$h5elG9o`t9&EtbV0{w<$ue=X+a>Z{xA+;@B+Ro67M8d%qg*RPm**Y%W_L&smgdj0CayE7?z-aWFKazS*H4|_5 -2vKoG*qH7*0Hx1$KSPiz>N5+9Tt^df&{+K_>7aZ{Qs~_qAj?nK++u^ -o7bo^Z6^vK4aYtfcxS`TC2(B49vwtYyP? -yA-rJtVzXjE4?=Oh!MnTnWw%c*l|@@I*x)z0Gbr`1ImH;#Fneo+R+L`?6!rG1rq}_`wsS&)vz%yW3lOVmD|~IQfB -99#e6qykniUAue~=vD0r#e2;|E*{41$DDoEQ6M1U@f!!*BJ;au1Mg01|{bXs=%zXK|H5b-07LIreJz| -|c{-wDC?jn>XlzJ{M;1F{I8OHkkHR6aPI_=MVi?3x;tno~;3Vc={(4piKjHt)!eIiTAShU)Dw5()3}p -tyta7#D?E+V^F3l&=&Gj{&GDYG4GJq0>-h*1jgda)cd2$!*|pEC-_PhCwDvw(wR^b>|*twPy_*7!}!d -ARM0B?$V+(ydS#vmyVy@V8RR!69g!3#+njokE9mVXmoIQ?Vzq>IvOsx1OwX8G70z?eZABBTG<(%aM -T$RA}1RAgMK%auRCbm6gk)z#X7Bo)Uj@#tVM17BB}@8MXrF{Tb%h0wX7I3C`nC?$La`d-t(JI`7^QeC -Gp7*-kijhODxS(R)Iz$ZFH|6h?|Q@ib(evOGY}078V1cOq)V0=LBbD`^*vCtFAF!i6A0Ws%a8p^b-V5 -z;LYH`nBml^guEvTz9m)rwZ&?}$x8k1(S*HEFl+BGHT5^%w243zLRlzPL%^B;8MN1vk2)6eJ1X -K?MKcDB%f*cRq>h3laTpulEl`a@M}VQt5$vHgPJGwW_ub*38!KC@yagYc0D@1fI^p8@pvc(>K@A4>xu -QZSGj7}sYF(4^01LX5ynY_;nkW%Am16iud4jLo9yn^+#ost?lkORRlN*H6cXw}Q@Si{jgk+f9gk-Bk^ -9MfNgqWwXz$bn8{@Z)kNE_N)FlC>m1jhu>q>>NDLMdoiNJ@(Uk+%IPj@y=Aw)wdMM}L48u&2<*iXrSA ->^nrtlNAIj46faUsVH$2%HHAz&Ul!(t1TE~M+>ZwbWXIid-HLB$Vhi{g-t^1h!o_=7HPHEAdy1EC#TE|3Wc>!c#@`2Uzes3~VHrCWSY9R -9Mzz&RZ%hSHlFDIYiw&Pptd-&8n24rHcvUs4w(v9M^W(U_HlH{C^g7#tQMMa6*+$q -t!>rAlNfYK0NJc{MoJ`%%riegHw>_r^3Vf}oMr!o -8GCsUPji}EoZXlTiF^riM8%a)D4`Zid1LZdDX}$EQy;McrIEijvlZt=poVql#={N?V -=3!^ydgoylOP-kL|rn2cbz?vPsQy!{uQvaXwwp+A&>1Bqk-+~+cjXsCr=1*7$LKZOo}mvh*7v&}`?7- -U>aIL>htWqs^%ggWtO%-B8~O`DKok#psm>nwncw^^uVHATb)Edv}`dTY&%?6?-YUsoM3k65xTreo;bf -qm*fogauzsKiOy|Meur~R@nk%Y#uy~VHqNccm`_^dK-;$M -06p80`W(UM4f*a!A*fUl#ig0v1M}M;cVAY+C{uozr4@w=TU16frlqrtvU&x92)M>AqD@08#;frRTLi! -^uuwRtA{bRUN|hPSp)Usflqcb_n1Zo2Ly6df$d>g*2)3n;Lp-IQV=@G_Q&#BddT* -DsYR{7ctfS$bgT!b)7$xP{@?8}b3Pz)NipoMG)1w)==v_tiA4C;-rwwND7xwkDW~0$!oW`HU%2*tVHM -d?`WOcF1NzC`V@_rs~@K6$>91+&!2iIfCD}mK+Bz0VKhU8+M{{Uv6$<*4*iA#n0qE|KX>(4}Xh46z~v -Q@&;photXj~Mi^NBhCY_<5X}190=5?gLP%DFI3nwQ21a&RY_V0&WBEw278pp*zZK-KfMY-tMGWhTgPk -wD7+WRbDust0Qi$w~kX;*2Q>rXEV1ia -NlcM+rD13y*Bj1v-34Qky?IWEq}r?S{6xBjQM-iZHR7UcGz -%d^UHf$^Y~IqD$IVM}#o&L|iuA4(86^5^n|6O8;8W#U0&aIO!k8+Hfi?}6{$=zBeSyb#R(s6|!{En8$ -MK*$_y1j)zCku@L-RQYoz*|#G9u_3>^i2?dYdhWD5DrU=+IN;pFgOtCS0r9D6lgV(V10ZPXAtb;%lcK -cl>AJ3Z_PjgMc570nK_(OJL1YDVq~smL@Co>q1oY?}_f96WMfuq(66o5dMt*r(tE|jpCh<4pc|ey()b -U_y)?VYpL_D($k3Td3i06`f&SjRTQ}KdD8gEzI**nY0`_-&_;!DenkCHgW@{CoW@Ag=L6c@P=dvpP;y -@vpaV0*&0)eC%ZVJ`vNM?(==G -X9%7@yB8(0{l`mAoidpi^Sm&x?LW^;`S{O2lKM8!wQs*9$^9#>=;e8E|M_xyMk@R{T*#m&KEa`rxvcP -2eVa`^_)k9Z6;Mk|7oOi~>u1)2{3oxCR}$lShB(X>S0&3OL$4GRUL>2>(&zq@S-)oVC!S_cG)#mw;W+ -LaD=f+buMz}L?au9>!nbe8pXl&b1sLdH4ne6nHkb!9NG`~qpZyyhJ=lmvjwVkDC_{!$@$qngsJzdHva$MW#43SD2bZYr_F{eHeZO)r`kh%r{|GbqY@Zh8k^2c+_@^z3A0Q_t!|78RAz -n;uk^&;3R<5$Ro7zlK$aDBHe!|Vh5KjmKXt{akli;qF5lDjFg`-fEio7d -Mm|HHmAK63c5~=VxJ~Y6@*BS>g=vaVnX^^2$g6$G>rVlLF=rskM{}-5rh!@v2s#z^F%GVqJcNl(K7f& -odwqJMLvyJ!Ku$d24~FN_WaKE5EAg-p3o^8^lTS@2#^m6SjAI^^EU@3g91%8Y&&S2bJ8{u_^00!(A;Qkv*^i+rqcqEq@(`lNJP`?;t#n+VJX7WkN4rkwtKEh-%4IR -Q%J()O6}DJyxPOl5R1%cCUWEK?|*%Ai2ljZJG%fN!!H*MwKII>!qz#9F#)t*^BYUJ|>@x!xrI@w+__(4MQ?)Lfd$dFL;B4jN>`bV21+bG-s`zA%XQ<`=ptlRNlzI(^u_@ -9#8%S#1*)(XHhnLKL5-nXTqjhuOw$U1v}mHW!wVR2=X<~P9Z`U!AS+PkE!8QFsUQvBtEu7m{HwlN&294~{qA{`R*~t@aaEjN*HGcrXA~#bkHUgXaTU5 -??w{*b^OWr)K9K%VwnJ9%68haxgJj8!|xCBe!0GQuded2)@Ezv0hf|)NRUs+(Vd2RGHA-sKn0H{mIz*Qx#s>iwZ~T83bHeY!goZaV&lw}sY+U2c^AL -yY~dGHC52Y5X%~R)4uoBuvvCYJA*cn{2``byX(Ze=kgI`Jy8bN<1YSEe98@(9ifp3wgExR6?=HvbU9> -EOZ=g0dC3oSjEaBpn&bolPi=I|^Py@$>7;p~@V33XahwQc;qf&9=H-P89C|D%@Rg%f0``; -9O34wM1VXWlDmr%7KU>i0`p8;6toHId5NbaGr#OWXTcWLd3PIJMTg14afw$C0DRhk;E>%|LR>!R*wV4 -;1*o=VD}m)qSauQ=R)m&rS9sg)z~Pwm|=T<1QY-O00;m`Rt8hgWJVxj1pokF6951q00 -01RX>c!Jc4cm4Z*nhkWpi(Ac4cg7VlQ)aa&=>Lb1raswODO$+cpsX9w7hW=6#VcRm1i%SPE?2It;^#p -((lmMWD#iDP}E^8cEsFg8cU#Nl6wZ*>Km+FalXTKKJ(A@fcRsLTX?dr52)8mlu~8g%lOUnW*ZNR-8a4 -$`Uip1XoGA&WzaQMOLOt!Ou+63g*AcwB7__{gHl!SC9o4k7}wZ~=$j0^^gwjgc}@w=*LsA8+0M6x1dyOR -=|tAPUeMrd(28+WI|0Z%|V7d_sg1fm!xuPEN$f$=qJqExQotEo>v$9enHMVhVhvg7A5UDMd`Enji4dgk+k>ehWoA?M?P!w?~h^$!7*a*;CkurtwJ}n#kMM@!qRfmj^Olh^6l|+vd8#|4K -$7<#SE#4g~tRXNHsY4hfR$_-oBk|TQQ!qMnZLb+Z5m8%E#A|L^4SxXQo$C))?pul)(|))n&UM;-|4e? -11)kKR4ki{Zd0N~Zht*4*If*-jSx;cc1!)6-J)h{S7Ye&r&`qe2@_cO9ps=`GP;x{C#rTyI0KFHER3; -%qpnE9uc|)~e7B^{KBUgsPCZj`{r_}S)Qev972j5~(na6((T<9|^;CE~t|MhV~Qvwa?=Mv+vS&_oagK -h7YezW#yDHTDsVP!6nA8$evqX*9PJ16Vr(=se`n~|9@{jQS@e{}A6H9hyOrp$1y&PDT!KOD~hzmZg`h -5UmkKvW1O<3ilM@9}3xd<2z~h#<`<*GfowGIYw-^&7!)J_B?cs0VdVQ-L0cB>Kmhh|^#sx+fBUdiKv* -iS>z7el>Od=_~mh!QpSXiYX0Ms)MC=(7U~~Hbi1^(HT5in~Vo*8t0CiZB_$6kmR}tJ>Vq?7yKWTB1tG -xJ+hgQZf|d|;LlcX1c&eA&mT`lrg-l=i+lwSs7;X_@W<#{wv*D@+0$yI<->L~1L9+bwI15ZwAajPp|g -lE!o`xY!*rZ&C<1|>O`13&->sND31|Qb!Z18*z^nvy)N2T~ZgiQ&$qo^I6YYFH*Vv&NjjFSz*3Kr?RK -a&&z^udc+l#!#OB(KwqDzCLAxGwQM!~OgM@)u1ObSPR+O`$^Jc6F-g3bJnDzF<5jT{_!PyASUNG -QXl3#8C3yCO^CfqPiV`oe6ud+|NwMa#lO%$YhLXTjHm{%~U2xtWI6lt7X8q -wti`q4O%Gh#~c%7CCXAZrS4SrrfJ$>1nSngHHO_$YAC=-(M%EPaY!LoOz5a>%RBVsWsl@>lW$}qc@;< -4@TIisRDP|Wa~q;@Pf_fbb|1Vzauev%R749$%S?w88^{w#9#%I54G%(xzezBoU9P5@8P;jzaE9&UF#b5T9raEDs}oe~)_$)HR%jVxa5{k`}AWDgrfQ;1HeihSgfss=)X`)0|XQR000O8NLB_@000000ssI200000DF6TfaA|NaUv_0~WN&g -Wa%FRGY<6XAX<{#9Z*6d4bT40DX>MtBUtcb8c>@4YO9KQH0000807zB_Q&u@VjAsA<0HOc@05AXm0B~ -t=FJE?LZe(wAFLGsbZ)|pDY-wUIV{dJ6VRSEJZ)|L3V{~b6ZgXE@Vq-3Fd5e!v%*lz5SFlxxR`N|OD9 -Fr9SJF{X3QjF7P0dSARf^^1;^itSs@6aWAK2mnY{22;Zqo?8bL0034=001BW003}la4%nWWo~3| -axZjcZee3-ba^jdUukY>bYEXCaCy}{?Q-16jsIQccjz1aIF5GAm7P@XZW8USY|Fb!962Rv*R|(TF+H3 -fP1_uDmLD3;sq_GOuDsX*=nr-`$SmMu-Brjc-jN;$D&#`oc+kltk`tMe}i27mR;~I`? -1L8q67#8dM{IvS7OeZ9A2_|DcH%Hr|^#+nXsRMqAYUuDn4Qn0*v&~X#9Ibu`L?50=#)qv!)V&Lso1dG -r`1ND%LfVIZKPxI+Hw41>4AaNpv)p7;*ffaTK$f12~5XYj|3?fQ;9g>1AE7r{8|N*=%A?%*I7|^KGWU -s&C()y*WLj^*QnW!pOieDR9!eVDz#@E15%4fi4#y6}e8NVq7jMW7)yeVZZ^P35)ibcKQr9d= -uS=FVSHMJ)%!yc^K1ptZhoQ+N{+1cfYy*{}-yPP1Bk7rjue)#E%eLT6iI61#MJH2EdF4&t7=Woxh&OV -&O(>r!@{tNrl+4 -;d|6)-qQG?`q0cm{d$v|fpNS;w}(E&SC<2=jQ -tdUv$0=B&rb-86ov=%o~R3uTsD+w}bDiCC>iNp$0)1ZfB#$gNC0T{xsd{cQh7SBr_@WkN!s}YB)}4JDfS!wtcT~Fz+qI@HOxHv@Fuj`6f!ZuZuB -4SzVh@RJxUBb*7y(+RDC;C$;z1bj(}gNlGjME=!om4bUi+y*H5ckB$%>Asdf~t~EIqLfF+_&47e5M8lTr57 -!%Yv=KYx@IpiScAUm*{F??~Q6;Aj;X2m-82CF$bMLM>VYq2xNH8)^g3 -}1x6JI6xtf+1@R$8xkZ`tdBM;bFu7o;auvfUjRKRLLMV~n%CgAOOekJETiAI33|8?1NlsWTa-Pb13p{ -~H9ZKR(q!3L4Q!BxcNyI|z!F-@p!J2N786tP9BlW_PnXt`Lrc0RGWDxd3eD(zwhFE}Sh)*FGu+uPXFC -hK{Rt=ZON+uvwJP@Z$-sA5 -(0KHf0qMGKo^kz%*$wGUymkihP)rw@f%P}jO)kGpCuQf{+VZ2{v`8uG*-C3uVajkvw}m2ITs6cNJoo& -$}Ijdd+}ZSq?fwpRkahv;hdK@)f9-I7#dT2`BZLnOpmozEWB2)vPj; -_aAE$|NzHl@xdqHznNAVgM)sSy$W;cjj~zR}__oil&vav*lAYD}u5#l*=$#sMh)nM5nbA5nLljBxZr; -pH+0J&W!aagwAN2s=sOSI$==NghaEMhtdSCTui>pGpJdiC;GP6q;TR&ohOACqC@f9D^Pi_^=W-lLyamLH8>qHl{6b)A)7s?pOpmxw9E} -~;#~s}Vlmyi0x$Z3&595)~J-i!c-kvM%p0p}TcB^zWYSq;!w8JY(bwqLVXyQm01w#85aHMoj%Y&xTKB ->dBdPi1+tm00%g2u(Gi2az6ZAJ8?c}|)fbLh}yiR40-6{Xk_{hHb!Mh7`+3PdcGz{uVYci@-iLQ6{l; -VD4aFwoV+(Fv-T9XXzsWl{FJsna|Kf7fK3Y-NcBfP|k+*1M%{q1zzel==%G62VAbLlY -&C#HAU2u@3`{+P6Yf(ny*phO=#x66ZAlKR|->8ny@i+k~jvU$`$qxB=!DS}q!I47vdVp00FLI5>LO$I -bc39e{`wsDk>yf+L`fT_!&ml=I+ig}a?7o5u)#9#xWdBt3M8*x~FDQ7GLZLtQ%t;u#bYxi -~L_}2n}!5^^G!y35E;}Alt@!u&)gWHKCtBb1b^?iw*2fUcWIy@|1W`VXW706G!8cC5HUu-a%Q2ES}0V -!9@W1JXnNH>oKfu3$G3!Rt5mj76=f~77?TI#54YKJ9QJ5mbwJ@D#%4@Y3)vArCEjo5&`3cWh6!OV7C#LijDPuN+lzt}lT`wTO!^&LBBwH~9p> -LJtIiO{-^e-OUVi5Rp`b0&{SPWu&u9sSGWvi3cV;Vbkw`{Qxk&Qlku-OnH`74dqtAICRA+=m@Cs=Y<$ -w^Rb9+B_90A&W07mSRauP`Z%|F*k(@XEiD(apTpXB1ijp>|{aeG7Sh#wtD6s5`GMnrPNIVVLd?9ILUW5{o9on&7usLCitkE3R*azKE@ -=7E%&c5yK8kngyxb)HZx;&`^UR_}{rFjW{+JAJZv_MkxGrIqQq*@KAAoc!CG5GLR)PNUQsvVX_$1{^sTr}0Pdlp@roD15OL&Hrl0urNv05UTkl^W()VB|v -+Vo#cRs*i&R?e}30d*bZ#BXj&af9_Dy71>E+Fu_YhXcA -?rv)fcjbqQzxCNVSSiW_U*H?t;;D8wH{^3b9Td%6FophCcpL^4uOKf#*qcp -|SVtwrlcu!hr*Z?9LPV=PMK7MceWt}TBGiX)-OeTxyFu21HukhQNc8{3w`uEV>)CCuHwof3zV6}&i^J -3?Pv%4*nB03c5X1w)(%R0fMc -7%xn{)krvIJP2}>CTzDV4UR5Y9>mW{c;Dm1c#b{J`v!NyCexQ#$IJ*x68xcbxzE+rVTIrjt=|-XXDqM -B^w?WJt|{tL1{cuAl`igMcXeSc+T2()?j49n&M7?&3$z6aWVu7rsG&9iail`$6k1hD_51=eUYJ -!HmQ10`BF656%N|ga-c-J;Dz2~To3dMf5d1FHt|m;mB9MHyJH$=$`uL#&o<(gSqmZ@_rVd`*X-CQWHk -(RWJrw}61RNif^v>G`gXRc7h4DqCb~+b#pa$x6JN7P+%~fsREaS7-H$!FGUjMcSbjNvqL*BD1Gru8px -1G4KgXUr#kLm?!Z>n)nUy=mZaCQ8H$UznAqWt9FBC3j-uB(OTkUFYD;?6~&@83;?lOHRbc-S7Jw^HZs -@%@9dOPeKrc!hUUfgq@vlgP`!X$)wS7PjL)v7OZV<-QiAE%iqDlGu|H^-XnX(N^>}J2}b-St!J6q+^L -v=l0|X=e5-Wps-&<6gAD-+&=swsZ|d2P4*fXdqb>q^v%*StfUhQ(1%rrF6y8EH>Rvz{Je0@NVV8R`WwPnJq~sIaHat<`U8Wk$EH6-s17&E( -HR6xH=?$A<0CyI{+TyrGVgDv3fp+XB*e#q_mVOw#6rUKTtVxZftNBPyx)2yVh`g9>@6C3n8+Q+ML(nn!n5g%>;;zwT>)r}tWQYd=92+4Qg$a(@<6qzg9gFsZRcPrv4V?O2s>-oi#(V{%jdz3eohx$*QuP?rugxWM9qJFr6! -GWq9YbT~Dm=C_Yy^USRM}ELBx&Y4i*rTbFex?sDbmG?f##n5fH>qL2T~d^?ZLqK;9N3ZT*$4iL0Naeg0OX;e7fZItYJ=UG -XGHluIyDsaNAKauX5J*p7YDbO(^((JcE_gYB=tbxuTxU2KzwE3_8m$aBc7TIku;A?frdxCLGySk>-Z@ -iLPy#258`%eZ*VRtPs18RRS@rPeg9Zm$7}jVBOortFI3~bSxE?3;r6rl*ms;MMHDoxw9j`$%>4f!ntp -4warCo#J{?p6re~5(q9)MvZ8Z;f9&Wz~e?yabu;D}NH7fF9}cpF0=`_Nv!te5Iyq)WWfecO23*O$-^K -a4#NJE4_>Te$$he($km3bqg4Ef08HYQ9%rIF$GmYUDZE347(HTM#oMb7sw5rn}+X=nwaL7A(j#S3FE@ -Z~DP~k2XF0UbBXUx_kNwujuqq3z@Qe_2c0?-4IU&%e7p`$*sueMH!n9ljDTrCvdW`|Mx8J7jZT(J^k& -`tI65Rqa*W$u=*ZN3wjv4hTDjl!5@6d_WarZ08mQ<1QY-O00;m`Rt8fWV|?wv1ONa|4FCWj0001RX>c -!Jc4cm4Z*nhmWo}_(X>@rnUtx23ZewY0E^v9pSKDsmHV}O`;C~o6FH)c=X<8Jh3m0`Ri*>toir7i82m -*nYM>e+#sU@j6ZqX0uclF0Qq%M|iCC#D_)q^8yZf6b;FFAm7nXMIHEDfBVeDy8-{g>e=1i~3A&Ejt7V -AtcPJS7jfVB(X^+w4*=a|Z93O66+L{`C?4d;`~P4ew<-M@1gi=>v~ZXq-bX=p&dV!Z2eo{V6R0+!7)# -1)PQ_;8}-WY3ljk+Z1b=!z1Mt(m<|}a&Qd^PZ97r#>@a05X;9buGE{_Os8E_*~)EX3i&bgvyXKP>?0gBm-V5V#ZQUO -~iB%6^I@JeyR#UcPL6SHCpZJIgPM)6s0w)m>xQP)ieVvGss4JR;~^x$kb8BGG4{CWu=Q5?Mgf8OA)}F|{TZIa?qs< -P$1E9YKcbk!w4nngGsinv_3s!;Jg1*B2G)cBrUS29jLFM#@yzU-WwOZq^wU=ynn%AA#w$h`EHyFGb93 -CTGle7Di7f=2C?Q1&g^^SDr&-@G&#LFhRK08v@Rl#%nZcy(#{h`-LnkyvcV`;Qm)n2jHBg>4bTH&NtiOp~CPmp<&2zrRmX$;?Ag8HOuH3L(n_!ErGG93K8g3uB?{=%HBqaP$L=rNFYHeRNKe^Z -c-`Tm||K9|9A)yj6bNm$f(@mB?d)NAUm$wj}m}FN9QR$LC8@Itib?Fq6|aH)F1}b=|HMY=(*0Z$1pe{ -l@Pr(jOig;fK2fG;J;Xlx9a$m9W1Z!_`Gv>4+?Mzra+|cwj5DXgc{&o;gXcy#yOtjN`a~W(_o4=FaK9r{AYtgXIQ$q-t<)8Z -T4vRiov{OChX=80W6+>sxII`I+_M?7NfGmx|T>gc?nRRkTODTSy}kZX!Lut!AosiF+w)(UMpE*-3 -?I8*^^&Y2&S#n$Crcj;DyW{z%}niCDq6*MhbnbFS2H-hH+e*4@B8jJR!|KHZjUYGl;hN9{Eu(NU2Z -81(~`^3o1(L192?y!D~hF)2HC0pBle-ZF6l2hxoBy%CU$qt3NZGwbMV+~~e+IpLG;fAGM3p4HvfVa -2{grkxR8RIwUfy^04$cZ)=%$;POGNSds$b;(IoLS6@yB{hY<6t~G`yO7Ef}?~>C -O@e1`LmM)yRw^-!4)$?Z4c}(PU+_*T(b(Ul*rH!!h>G(6s5%sN=cjGHVBbsDgCvU0sMu=awTCLj-clO -L2C;7KX{5tl~53`R1Qju#KA4Bxj?{&6tx2`AytJIoXHen%iX5-)3St~<88~KR*n&z(E&}X^*#`oYejF -I)05$FyWNJY78@#)4@CpB!`Jb}bhenDlHm5h8!6CQF!-_LhJsyHz%&U;*@|QewgqK?Tn!SbJrxcpZOO_+#>K=`xh(Mz$xb+paB -rx+df*0H|S8pA}MUI|7Bd5wZu$BGt?kY`m-smaF5*F;i@_%sR*O8txKxH9 -WKu?{tN!>!0dI)8><#$|T##!A(el?uRTyVSb9B7!ZC-a8bZ>;D#G*o;Its^);hf(XmKL%ZCsQ7LZG@B -^8;IkuO>z)9QkAP+N1o*`fu<3wb!jI=)PSET4Ka^WMv>(ehdit)agCO_~ogXzV6Rb-is?(1pqb$)41J7J{zlX{~}eOp_f&5OmnKG3)5B%)kQ6F~8EQE!i$PInzOeyPu)l4L-H(Wj -dcYbmsGq(B8w6%~*;?G?cQdI|6P?ZFQ_mz`QGC0jS<9ee(_sIXw$X@J07=#}bm%W`cBK;RoO9KQH000 -0807zB_Q}ar@^ZEh+00ssC0384T0B~t=FJE?LZe(wAFLY&YVPk1@c`spRbY*fbaCwzf(N5by5PXl6e^ -?nIh!hNkst>7JDGi~dMWISU5kkni*lXun`_8>vVRO2>nvT{Np=a_>RU( -t>8F3f_(=Fd@Ja@cN9xqLBYIA6I2$NLt02>j(`s_mIP8ktcx<2Ld6KRq(!sGvxJW0#&hU735E+EDETS -f1cD$hdO=k74iD?P4n-q2)FwO3S1@~cF&YfV)8PRN_5)WcM{B|0uSyy=J70n*Sx_wIEHf81XagcM$UV -|daBU<>m36`Dlxktn(InE6k@JeS@>yJJ(`_gUd`aTKbiE$v(a!0ml -GIVj!#Fk(dC$*&Y(ZOfv=w;yw6K8s~szN|z)iO>9%dEeWY!NwOuzGL^H}!<6>OAd1@RF`MB6xgG8FpcFj2l`dHnNi6Pp)R@Y -2S9bubG-xTP@6aWAK -2mnY{22-xn60F4n004;v0015U003}la4%nWWo~3|axZjcZee3-ba^jgWoB=3WiD`el~i4C+CUI|N8&% -MoQDL-G3kf;K&48A&_WwQg-N3*imbz4n``Ym_wF3Ws`B5vXCEqrhqe|1d3SbpW_;!ZCbDc4&$b3$U%Y -w;pR1gsfGZ}x%c|cyIqFNjtr*Oh%4L1je{)V>Z(+q6n8`drMFiLV73V3lEw7nIzD_urM -VRFI=Fx{3-Daa8@#s^jjW&`ULg%s8i|8zNO_KcPcfDTxPVv|WzLz15o&I>?HA!jfR!XDW*d^3vl^rVmMNs3 -kydc6xZxu6LCe(COrfPoxHgJ!Dszz6P9C}52T)>6fHw|d9(r&&4(Fk7Np9!s+45!$x8v1nyjahtAuLx -gSuU>T>-lm)cOPNAxPveA#gz|8Y0(~hDwTCWGPz9>lQy;x@jyZ$! -t0yZ=Xi}9?<3Bxy&+0ZL5E!U!hUWgynfi!qJZPdkLnnLCOFlI*VJPJ5v@GX^RX-xT^-s|?I)DCQJ@tr8*;lDkO%hLkb!Q{U&_uS -lVeyYhumbn>1gRK2pZegvc!Jc4cm4Z*nhmWo}_(X>@rnVr6D;a%Eq0Y- -MF|E^v93RZ(x-HV}R{;Qw$?USdFDx^CEmiwSnq|xx2y@K-qh`LZTdJ`yWQ^JmTwee6oBo65ylL`SJ5-dDO4T;$mN(!A -IRMKyoeL5BvIPN+Qv+;u9f)WaP%lbeNz7xImz8GI#R#nABBbFJPU#b@7E^p@3*7~wNa3=GWuo!4k>AaPj(jV39NglcG1E^v`Lo`{zd=$v}< -RO-82hPdJ*3T1f5W|ycIp;=X?5fGB|$Vb -O65=0yu2;I*`WZ3PHzTf4b_(Zd$fUr!G7`D#$n&Oz87fQJ3d~|+NKHP=&>CXEJx2ngKk9fcXLktE@PP -@6aWAK2mnY{22*W&T)pK2005E&000{R003}la4%nWWo~3|axZjcZee3-ba^jsVQ?;Rd2LkfZrU&u{g -1>uT%~`YqM`fHelT?srEIWOVIp)@HBHDkH^H5;GuvsJN7!@i#de*fAGAb>VBdSsJ?Hr1BbeyCG9ueLc -zgQh1N{5z1S*Aaj>ab#W-J?Y3YrV@B%oRs7uveZ7Yzt6-*Of`&4D(xu?2EGAGW -+61>n80U=BtBnlc2Qd;_!Q1c@dOjg&LqY$ehp2P`JHl1kL1B?FgoRW{1ia^%I}i%E-sMs-#Su#3wsoH -tCG;3KEr#AWM(KgNgM7*i08W0=PQoR8yqJn$gb^V -Mu|wSw#MaygDx^Jxr=B}^94#e6kiM6~)0aAD0s8P2=O|^00#15YpRZe(yG;J5*>gM}&J(*1>#Qw{u -+W~qW(zga#(pGdk38r8rV&1dJwMy&=QmL8i!^tOzw8FMJ2!iHE?301~We&57;FyC1C95pCgS_zcYXcZ -$;*S0)s@QEv3Jp=)p;qFdR(?Y1<5dz5R!H{=6Wyc862H6TI}*KfWSt;L -n=EePGU{d<6Ca$%xUzQ7>}uIFmo?WBYXo{|KVRYTDb@SJEx(kD9x|n|n;R#W67M3hGhSdYkEOx;)2d? -F7->1`S_=AupgO@Cg%dk-Pe^kUCcV@Q~8bx9YWR&e}H})qhY+0|XQR000O8NLB_@^aoX(!UX^T${GLw -9RL6TaA|NaUv_0~WN&gWbY*T~V`+4GFLGsca(OOrdF@%|$$-N`m|3pJqIiUHZ -86l?FcfFFAjWT@D+tV3qi4p%os*NrV&SpeSWoHcNmPg>CocxQ{&3VkMuY8wmonl>0-C=|g+^z`8L$`) -3fLIUjMxH{1~%0k=ZqqQ7g`u0r)@}7XckO!f|-cKXfaMrEncO0=(Q_=5n~b>-4P5%4S3QW4MuGOc{R8 -?zj%2Cuez6)-Qm@sKZ1)(=v@q-4z30lL;Us(y2ESueK36529D7}J^Vwg$pbV~P$c;z58H_InhBvQOiE -%Nh)@LRnw+L=%3-SBb1l&$h`FANgcwcGzzM-bVlE6b`OunQsAzu=l`3t3jf3i$LSi3H79(;l7uql0)% -72Jzjxm6p&!3>_V)lkp;mKO{k{g}%SQL%W98Q4ydqKo<>Tt#%vxGO%2(SC3* -Rr6EMx#5%u(QAb%|o$(LXj^5nlpSVc;cZfLDI5c35MB)b8cp8QcO&E2)-Yn5x(C{coep+@`P;aK%;JC -qXoymz*wos+C!fhEhrTgco^vlP7$RDwDhR}u>*+QaIkPN)e@>X7o=5JqV&!>WVT(0%+_?2H28&x-%@eewUx -L4G=gz;*!!T5mJ7FLwuR=nakt -+_DNh&vVzl#{8(J?fBNDTCp6Lu8cVHX-vn5SA`>D^YMfMW|v5WMAos*X=3BFg3#K$EwOF77o)bh`p)W -SXO$Y;J2RW+E$6+MO{Ec0omlKGzf=0{PIO*9%cvB*v8>QuVS+-a!5u`H`sHF6@R=OEB{>s_G? -4U^cK0Zk{=f3}Uvjv8|r8cQ}fpTcE4=EmpIrw2a=XZ>^+(vcU)8_!gVB9=hH?iZ&m+`c7ekg-xMMno} -)o)XBt|Ukqg|jodjV+N{t2*6XF4Eki7ju~Z&0K0tL+%yLe5y}0+a#@C4%e(Z*1Fx -b(tz7{*PU`Be*-3`@Ob%7km+eU=hAFUm3o4#H5Qe*yR`V*H+MO;TTl3n?(?=03or7*s> -LUH%ID+^exrJwtz>-cH+0;=;-Ytf3z*3gW6n^dC->dtLpFQmEXtu1bVrp%66d`4V0XS@_zE3MPl-icH -zjb>^Sdpw>AZ(ma|gdXLzBOJMIRoRlGQ+p8#AVHpMK8J|43u+7d8^ceigdV&wL25&IudO9KQH000080 -7zB_Qv^4C2D1YI07eS{02}}S0B~t=FJE?LZe(wAFLY&YVPk1@c`tKxZ*VSfdDT|Iaw0bny}Qc)&^3E8 -DLnQ%sT@doD=cPXHd{CaY_@!w5;HxZl#nKp#=tHAkUz|qq+2uK!GPDP#D{ROk^1%P*RM4i-ayY3Yb$4 -S4_B9OzyIrxKd&yY-onRHNz`y7^lzp-J$ds41|N-^mjZ5uRc5&t|Mr~zdC1#HMn!`-JAh@7}f>wDG2*TH*=iV2ci;LxQ8H*q`HgW*PBj^KTFJQ%l` -^%xsYD?u(j706{3>HdJxle``xb#B0D{yjl5pOllx!#N$< -AbBk4bNPEUY78~EI!$m$H<&#hTNA&WS9K%E&Id(!8fJi-X94b7U!a2Ypk28rbCg?`VkIW+KyaoEX$*MqxIV4F+5|ZT1p~~BIfJjv0SWyR}U -5QZ(&fme*7*)&RPeB4Ug(^O>d`o9|wnVh;sN$&B#2Yo3sB~#HY(hjpfN&j{d8YE50Qj1st%5hxD99N*(Zro=J=UH;1Uxf9OyWRBNP5>7YqNjs(H`F8n8&KM3XOTjfy-dDIlPKhx -zLbwV-i6Nmozco`RlJCg*4kijRPlD;z40Hsd07iQe&o#^OrEAHzm@fD1EED}o>x;}8!bB{I=-s7Tpi7 -WIjdyuB2vtFgZyK8#;uQm){v8aJebh()F4JWlf>d-zOt`CsBf_II)_=y7Q_=vb8?q;aOGk5ORTQ3(_y -eyOK_#q#u*KXZ?@6aWAK2mnY{22&UX -RF$>^005i_001HY003}la4%nWWo~3|axZjcZee3-ba^jyZ*p#7WN&w6VlHrbl~!$U+cpsX9w7hWpnQ= -6Rmt*Ymv5qioQFpw1p68CFFJLN*O7U!C;O6?5Uty -MWjTQXO#8-KKc0nKb%wrT96DUQ33d{y!Qm~kQT8j@)s5F-XZh~uYt%K8=9Pf7e>BqXag_a~ngh4I_6(3ksU0eMexX1-&t*7+qcMcDsPpU<0YLtGsd3S -D)w8*&>|1Bf#x~N0Fn}pzvGC6_H(6zzPBsvo*oY*$$)vmMJ8gkrwbyal=LCgO;h;F@-iv!nIL+U791k -I(Wpo??8$%0nQ|ZdFa6HB%Fu74f18a{CNMkgfEkahsk0&pM`M$0Mq-$-F!K}U(oD5Ocu}ZX}-Ag0ZA> -&gRh0M3_7Z~%D$3#tJCCd;p`5l!YMo^&Ia&0TB31DKw -?#eHc|46$x}?@|y51a_FWqjrC8PF_ub}w6CzwBqp>J4dB8 -8z!C6FNQHJj-BABhJJTCx2{g*rK&BeloKcA${o*a&WayT18RvOS+bqlvIv?b2Bp(2O=qDqU|VXRc3$`%%<}lH2^8gu;AC -x%yNb(ybqw?v#SAwur8cNZ_l9SfjT)fVL6yu)itK8z6&x6r(>K^?5_RS1Qpg{1;G50|XQR000O8NLB_ -@yrCrHqX+;1;u-(|8~^|SaA|NaUv_0~WN&gWbY*T~V`+4GFLz;SbS`jtwOP$_8@Um_yUOo?q7NZuYDm -c|ACyvRxw0I~*_Bd~9LMEyvA`in!kPhQ0gNf`Y2P7lm?z2C!2Ey|MR~LK9AwU*(dce;fBoZU>{J&kBj -*dp4u=OX|NHxY4u^*a>}{Dzq1Y>~KI`)7lV=-b?5(zolCwA5WO{jT{lz~1{J^gGioMaHU>htaQn8@KxHe(hBg9md#`)n7B(t;h0n`)p?Og -u2R94(k=Ws6_n7dFvmKF9)@9sGQLdUkPrwhw`;4ewM -YtYt?0T1o?DCo9Ga2$b>(#LW1TX~X#32&_3x0xykpQqB9!>X}<|BZ$pZT4&^>bZhpi#e>!{0W8K9>x{ -11`E`f=G`c>&?h}*u=QnRI-`%kHqpPdY#m)KIHM_iGru>N5dr;T&;S7} -5Y@O0uMwdb3>%u_nSy2a#+cQaO_;R8#Yk&jp+7FTyBj#0p_@Y3W8S1e_9^Oy<&Y=Re)k3kN-Yf6LTqS0#af~yM81 -tyxNxwx6sqDFcmX49;XmtJnmYN&H8XM2sO4O(J||+i`eP0{lBqUrn#%+p{IZZ^+|ytpH3Tonj8R}8kG -W*@Q%2eNF_QEH=JJ@#p30dQ*Zqw^A$%`SM*N7K|ZdZ+mDGqMN&LNINu^B94j=Ojlv9pMevZ9nUe+HX` -^l7U{cD=?IZMTnX_4`Qu4=^Aza0a$4*YzFghqwnUuI^2l|-Q7HuuC<|s3HC#Ky-k;qrxM?SHFnA}xjb -LKZOp6gOMk5n>;62dJ7P+9<$f+xgo6ihA^&Z$jK+>V1scw1j+B_i#-^sS8S#BW&V_b0tCwo`l3JsT+q -)@|2!+i0qVReuS#0&Fu#0Mj7IL=ceNX_sBLnxX`9b$dxeIJ|$60h9jdO@>_$U1cuSAm?|F+#{%t*8@c -=*AK@2glijugx~EXIcT+}_)+>-zReMWv|}8IJ@~tehTjnlzx%!p6G`-(b;DayT}6-WvF=vE_P28A-M` -ct#J1h)X;=d*q&J@V4V2`z!}yka+iNM0+pO_OC<2@;4BKw~F7_?+?p-(9eiHre`HXc(mCA-(TkN+$Nw -wX2w8Gp{Q(ci$bZ)URMfLWDXQl8S5})t8o@$MpDdrg1b!iLw4D>Lm-$5Z=7RbAyMW7PSYKVlZkU7dU&# -ag1_OW&E=|`_5?;}|=DgbL$b|=wcyyvl$8#l1{q?-NBLE<{_kH}kvDS!*_2%~m&G*X77 -NvFT*(BrhD*3ijAss&)MCA8zyi|@)kvH@;PB$FVZ}ixbuhFZ*W^g&4eQhP?n{mKNv=!Z1daGx%HvjlC -QZEA%a+V_P=v@AWs<>(?BorVIMmX__%&1X>!`A*x&Kx)ek0wg6t9{$vb8aGl%B`a}qTC=X;7G#Yb4Y` -sI`7IvBmsUY?EyzVOW4=+Xp9i%B2iilyljcqo7yANYQoX5rxbZ~M?S~SkuQ)=Gwf37iY*s{#v{!n1KR -1*q@v+hD*lDbtYHablc=!QVksy?P!bPx_K*%PKC9iz74zJu{ -a5PXDe&R1zvo=^{gTz7c?y8e$?=P0ZDuRyRqS$Ap1+|YL$tZz%FmBQGEdkUA*&KqHpP#nHn)CAOHiF^13|!N>Y> -~Zs$ZArSl)UJ?jU>2wSg^j__IwRq@en!?n`jmB-3*mSGlGQp+U1f9t`->COqfAX_cTG9T1@%aFZ^i6D -fQ{3?dEoD-HG`)qY3-gPP%4GZ$hyO-o}#eeEIkeu6x@^W|?8LS?6)!64KYztnAKCp`W|}zKS?H -(e#J}}60o_1ds*{O;`Kt#7X+)#*sbFCaPPALm(?JsR1(I>2{nl&=>7*#O9KQH0000807zB_Q@TM;e6I -ii0PFw&0384T0B~t=FJE?LZe(wAFLZBhY-ulFUukY>bYEXCaCu#hJqyAx6h-$!|HI`us8E6*vqPZ;1F -;>9L#I$}g+SVbSM~R6tdq;TZ@7nhh$x4%ZV6qV6hg~W&w_~3Bu$KIoihdptjPJcn<&Hgi5dGvfAd{mG -JB?V?7w=RtRKG&ZN*0H30R=0QPmn{AvN?-o}pw_;*?jHT&YGtl^WOQ5OzNv7cG_4O$4QmDtGn+f(_y` -F?OEC!w=31GYi8G!Se%uP8p)?e5W*d15ir?1QY-O00;m`Rt8g{E102U6#xKES^xkX0001RX>c!Jc4cm -4Z*nhmZ*6R8FJEwBa&u*JE^v9(JZp2?IFjE}mH&XDKS-L$8ryMhcU0%CavWt>wT_dDm3`SNE=55$Cls -k6sn}kx|NC_}01^N}N=hbscdANckwCw@(cJ(UEmvt)u)N5k}o5XZqR=JMy8C@kckZ?p7YJh|lR_qgDhHuC+dh -|(m8<D}wm$Lja{vx)q%42tm9FH(OV6ugL*+`b;CVGz4+BJY(sC!FS -FXi~*}i!gxLB?ALW#1gI7uKl{u8^ehNJ=W&qV4%pO<2qs)-8BdD%f!zklJmzy2?d|&r2w{vb#*;BJBVk#@5Z^W=L$g(K7;o#fF8XZ~3a9 -hH5QfKlVlR@E6F%kQp4&wI1951FboNeB`PkhK3U!5nltgh+@vt*)KdS1Zo_Kye?LQj05(bxFobi1m)e -_pyEXPyJyl4Lx+s$_&UN-ze)OQFl1*x9~`!@Astc*4~OkxbY}UAhYS>*-sLPzlP^3ga5?v`Gca>jqzp -qqpK(}6F*>XCKmdp%T%Y57z|MKm$w6x@PjONXi&7jd9*8BxE5(+Dz)TKuTgBjYU4f;~WSGGrE3%^lIl -jQ9;e=h{cehtjF8E6mE{2e$fS>|~tEn2)#nc2=SXgnEJVl@V^BDX2gVlMiX4LS9LDrL=036AT%g~ -&pv~+21lWFHr+#tYxlx*iPEZF|I8nL`hxBWDvPq(Z3wRjbq>~t`i-L;QYcu)*)sjY@d}3dBv=Ze^y+B -ARX~+Af6I9!^#X!IY)Tyd1X~1xVo)xGr$IHT$R0FF;RiK=TFJsI(8RR5$?rqHD%d!g^LvU&*2EbQ{JF -XWK}mo*A!D@$qv~IrutN)Xnt(5@c^wMaUu`9HfILC1_@osdZA7yuGJ7Lp^jz~dSYs)SSm*D`X0I+*{N -xbWlQ}^jmYF#%6_vnY5L9JIV`M_ -oL~tOkA&Y@43$|(uz-b*R#7Eg6J*a6r-%hcUO+Pk>AD!8?dVAoEpCzrObdKJN}|H|yE%^+wC1A&7%RZ -LbwO1z!vthMP2z{@F3v(c=r}wFzA$6x_N)PmIJiNzzs2varRVW-sUu(*ukW%*Pc#Y0E!^apUxx1?6Uk -w>r}IZBstk*M!s-Ug^)guD5eaSk3(eeySr>&f-u?Z -@~37+qAkMF|u14vQHPbPE;fjKk`}?{RgBuviryFN6>R0ST;rDU{8b0y6`PfyEJqtTEN0h1x|}f0NVd{D$=oN+4YfQF?FmEf2n{0Js|NA5JZA17G}189EF>IF86^*D)GO{JQ!)z48(=Rc~q%HCUyqE+PiJeWJRj^N1V*eSXGcC}6& -DABIYH(KLONbi*-b~*^=P;kND+pU@|b|3MNr{A1k!!9hV*K|&mR*8AYW@#E%c2Lz*rw0cwx3daN(jbO$gpGd#K} -(Ulk;BkMv|zVW$*KPzED4EH{58`i0LXE_4S6QWtJ-{|th`31$XxbXSxA)o%@#t|fMzi?SVxZQ?jx7?w -*evr<0(^yEKS9N0t<#^F#nNwD@d{?Ckd?ArlM=$ksyR#4Xz8^rb$!ba-{!vK+^77v1ifZLVZV -*@;t8iaSAvH -t+$h$bFPu-1P14;#W->z$Ags1^So?XC1nF0bAtx*rm05@|eUQk9lfQ&1zPSEzQ$J_H0>7dsmR&C!%Y$NY^0M7U7mO4 -um|rk55LCUdwY#Mu4-c$ERu4<~6H-+3kfYamYSk{YiI*!gTc89GWH#Ltoug$RpjeSiug)Z_QlWLRzTihTw1w$Iarh%dPP*(L`l*L~T$$ihK{taSx -?)w|F*uXY}s5MrL7a(adx8zgPli;)l^ndp>l1@BQ%^+WdLb;>Mc7Kr8*VpoWO3EV#8wCUNE8XiiR$^n -6}a;`>|x(479eqVI4Gv6%-_Il<>TW)HgF1a>7B@E>AE%{R<+fN822(ek>Ju0Azam~aePqvd(?I+7kS` -DGK13BI70JS!w-V8O`aH^MM`-J+at`fFA`)cPzD)+>>iQ6}&w3M}_w8S|<8;orHUj3qwjP -6v$jXB^gK?jvjv2;tLiZ|G#|+sQrm#Cm&Cb2l1zV$dsc} -Te>7xMA4F`PK4b>#kMuI0V$^(U=i{eD-UXk4UFbc4^z^X!J?a`uY|4b;e~fbt*Zj^1jtq)(Rc)4Ppr6 -$Lar7+9UazVO|)s{voP46%PXsfr#q=IP@nM(N2lUjoqRYDT}TUxlu7xemkYM^3> -aw5-reAJ=}!E%w6`61JQz%LZ?mkPR*wgY0a38&5Exu<|ECR|5vQ}s|^&}y9IaldC6v#e)k}c;GCpgjY -!fv(aDVpfD6lMjt%A@5lJ9lu8Ied1%kmW2ZKS~@T$Zg#8r+uHVS?K -!jJT7qZG(!5_{pm&a*v%sg%?B#9&M8+6xEgkNU^xZeW6aFZ3Nv#a1n -KS!CfZhm2w)EV^aj*J7!qzJfz^a11`4pj2%E~@(72nwim1Lia}i2MMQ2q_tLd%c{)SOut$~a-~&0xH~l5RP~u!vlWIOUl>aTUa(asG<&6PPj_V8S#G*dhio#5 -O=jUV4cj~hwG$(nkPDQTmO0fGz7y}e3tI|YH6PWmhKjo7prIWC6tWFgf^z@QwpqZ{%roF-f}0hxUA1j -L!UR@tn~T$0Kz9jzSaG2DemaickC3N4_zH12v-PI|=y;tb03ZY(S15lLGSH6!jj2ukwgMy(3j`pjjGqbO -}ysT>_(`?+f(p4L1tsJFEsJS1LNdl-5>TGh>=xI;t{jM<=XvyMg0!A_m<4ZbunEC1IT6b|}H~oPqf3n -ARxUMx!k}nnoZy*b$#m(to1`VH`lhwf55iA#rMB7GHWpM;ge?`@X0dhNtm(8qN=z@zaFy~N73gZ0NXe+ -F*4fFl@w0V|d)nmxZi_Erd`q~~MPo^S`*IXN&hBDsVW|ZA6fb&c2FHaqBa)S0!?@ -baN~sc%+9X-Eu+?m3Xvcj02ZgMhTsy7iu%kGkt^V+vAU4dj4)zj=Qc=LCsa($Y^SkqwB2}0P!XWwmNg -_CIyGVPltC(09ECRYLdfANpb+jq9A$bhU!S2d>9mN%LlZvXbi={b}@VFhO8%uRIEhuFle -DD?X$!Gs(eBm`|{UGgpUpTAn!QHWN9R)Z%^Dv+D#Re<>SNw`y>!BfxskPcOrZjg2HQS*Xjc7UPG5_3w -0v!;gJAt6i|l1de^y6?dqG9Ou%wyvtY`rbe0B*QBEL*svXR4m -Ep@x^^3XK*cBu?jYL=tn)5iqq5?#yCD}=NY^v?}Pi-x-u6UgeD8{^2(^AX(A{wTa%B$}~3N7X!`znMC -B{x%3GAAXMFO*=d^Nvb19j{|d?N=za=>?U+5~uI6)A^jy^I-SUa=m25T?)%lkp-G9tB<5St)mmgXw9rM!&K+R=s|t@!cw#i4b*S`OND^Qd_N^#^*r&jR=*HrRkQhcW_1B9kwyPYTx3UGN -{I`v%D#K7Ikgbtx|;f($<>##&m1FXxiLp=PF97!_+%Yl_(nE*Zb!_s+mVcZST9FQM{U!V10Q3K*s- -1N!A?xRbr&y{&USs1np(u38tYe2(A^ux;M!%O5vcx?Xi_QBZq>DN0|{7Dk8dk(tghKM+k&M=V8O)~(bUN=wjlplkPq -lvdz8n0?GZd3$6^Z{uLKTMSSylO{p$HQ!P}bvlQZnD;VXC~i|WO9zH)l)4SS8QZ%%4mYs;bO>=%Gud* -NQ!gjH{uJ0A-nZnr9W5j-ZG3XS6#Et3KjeRRUbl=5AGx~$6A4K@nPnpV#q-0;j{!w0&>m~U`#nc9)rez)J}a_?wq_O)J!wIZp%Oep&Dw^k-VX9htk0_m+5lK=iUah -G+nRtO`b0(rqsJoYbx8_^oW>+6$Z)=tnFm5Y5oa(BvC0rhyaBi0>xMOWk$pQYc5xl*n-HPQB5-&W3B5 -XojT|^lkMZd*E`t{c3%c^Oq52XE=C|Te>OcI#eFm~0Tk7nOWa1aEdRbxvOu9%4kitrEBGnnqY!?Rw=q;=-V!o|~!VY*JlTTA=wKsd5 -^yhcMOhC_K%dyF?;FB4IUnUkE){Az>u33nzQr8JP&%w^#b`bYf#sjt91itndVlImRw*84LT-XrMyiFJ -bl=jf6a_?~*Y@ig_(@d`a1<9ywP#N9n$|BVl6%c1z=)vKeQU(u6k-B-VRd3;2JX)j-LWiD`etyWua+cp$_H{kz3u -rFdG2~x5(jR4O`J#`J%Bt_;9+cZJeEIQF3ivmRjvzPt%@v5tfV!-rZlSkhWGTZe-(!&P -D?*vv+pW|F-EW2qma65EltOsS%N?1|v?j&#*-n^bhbk{0jluP=pTcDIAzb}Zh_#+L{*1Ox3ZJz|ZeOKj`n>^z(Bh+PNU*v95rL@M>sC*K;_XSCr(0c_!_t6#q4)D -C-;ymy?_ewrP;e3{?Z*IfnAxwT+KY#_G(26`ijy&foemUoV7cmOB$oW>uh8yd5S1!)b5{h%VnGfMF!V -Gq|WMAb4wkQ;kYv+CH>|$#fB+K3&y@p7ty}P-as`&=*cfkAA`h@+<*79Wsz59IoE_@iG6{lS1%!!v=$ -9su<9zg3C*G3S4S0FDLe#BJa&jc^aKu0?OFD07jRP$`5TfO87VgvOEhp{~Ot5)z|6|cRLX&Wk>kN2zV -k0M*ci24as!0)fu;S^^gx8#|BfAbG=EKdgi;&ah?JlyN_^S=wpzjRQw4d%54{HwQb9iQu64q}AeE?R@ -Q-S)j4C|JLt7fY~$zEXIaBiY4dx2tiFTv>idRN#D;;T_nE21*!7Oov-i5&$S$3nJirr0u;!BF#iGFB^tO!WwTUuq`F^NO)|DCXxJhG -L^j~%f|=l7bjfMZzi4~UgMHK_mPsOsx74CB79p#EE0R*Fy7FXVFlT8+cKi}nhkA(r^k2#@*3Rnjtn}F -C}s^UWh$)kY1)9$wl#aUAWVBI|l7{E>fS$n42)4&t64JwE4h}7-=CwQ -ohx~*Q~g2&z#ZO{+27na+wt-;qg5Ob*@TRyl&IXD6}QWV9b2XI$6axjf+$DWprtut!wA`5mrHS44YUm -AA3XxjGbH+I|4{pva0TmM@@YAU45|D`XCkEci|oBbb{ju^0kyeuU1QY-O00;m`Rt8fvc>Wb+1ONaa3jhEg0001RX>c!J -c4cm4Z*nhna%^mAVlyvaUukY>bYEXCaCwzhS#RSw41N!g|3J7X#u;S&vTp?nYWmuh%P3&BjPGz`k)ia65yt`oYQ?q10W6rEAEr*IG -5*b_sQ(kWSWt^?k36TY|S}pf(M5l^T{Hy9!!ua6Zd8Qf+h#Le$=QgF-;lvKPpW)yg{*@jRc+XIJoy4l -1mrR}PfkZYd({2v1P}r$N5zrh@EAPr_RJuF7C9O-Hu2n9oM|(R(^4i!q-BK5C!5Quh&(6A30oQsVa#d -nO?{7vdF-WmZNDkpw~{lLK|kTry<3KTVnyX_i6ud@ek=3&s=PsD#V~2>hq?x>8ptTH>tfrE#Lxrmdut -$$=ASWhb}9*XYAR9;0XpE2F;;)2ZjvMNosbCj#*JB40*Xvhl7_WcbbFA-Pt*px9AE5kF^kjyi6%`of1 -3wQE|`eu7!Yv4?Szn?TH8>k-9mQPRR#xGQ2_l4xeUjm567SEPX49$MTc&Yv7>5Ar29 -nA$A@(gPL(C$Nu5I|rGg@#&w&22%lc-^Bh~Xex}$O&WJgsw0ZFt^!oc2i8mXGjvZ{o2#J>^T^haQC^w -^}U8Y?#nMS3=q;@xhWEK)Hh!Ep~v!qYZm@q#HG-(^7{pF_5}5S?tPCX0e@GQQFL=)LBP;5eVr+<=SA< -_cd?-6q&ye*O9D?~9u;2cAy+;~rHXW{H7szA0bSz(716Bs@DBhwc4g2Du$V#4g~g#o8-&j6fA`dlO=p8wnpv`T{69u$Tyd7o6|8rSg%+ucE9ej_%W*gK_Bz5Ll@LwWI3bFDU=48<@Do!sJdB~jCOBe -%CRGi@Gfny*fe=Vi(S)wT$R}9YX+kj2%kqU9ZcHg&liK?qsuC^J)efd7yyd56g+=!pwT*O+D>Ql>B-w -Q?ZOJ2GVc|NKki&&ji`G(#3!5z#$7vq7#~9~SPeDI3Qp7veg~H|8T~!e$5@HLzwSl7j4O~+v!x;%C)H -+$mro4ipDBzPq*@5p1?oxHWZP@BgskEYa!x9S?KDOSvk6d`!_f#-S&3B5f4}p)0N0k+9EFO -(woK&f5hAgTB^MqENnICx`xe=_BokPTiVjxRv7P@XVHWBJS^Jc40kzFaJx1h7a_3U{7F52r`!|O;1E9 -EJB8PrEWhoz9o|V`%@=6p*GXPVhg)ri+aokyZX?cr8PO3lOlf*NX}BGI37!DFbF -F6E(Hx{(rGzNyzX4E70|XQR000O8NLB_@)CoTm91Q>fj4J>DBLDyZaA|NaUv_0~WN&gWb#iQMX<{=kU -t@1V?GE^v9RT5E6HMi%`ZApc% -`<^=wayX=9d%OBzOXAF(`@ZMi(Yh)&Y`I)Fs;R_s$>gRiD#iG!F0w|6rTP5)+4E&!35XB1*;H>t)|pRZ$(G_8_Hz5p`Dyp5lqy`0>XgxgR}{u`~ -7|<7!=0n?+rUM6P9W&VDW|k(%)>ml>T#64Mb$#_QUUw1?6w6>BI>yB*H(7>_ -#p-v+70t}IR{dk7qP|}^eN844^X5ZUY-I|OxV7%0=4-)HoVm#4y?_cWCAPbh$sOC^1AS4mrevxxRBmo -Id|%5y#LW#OiD_*nh+?rLpW{1zz$d{n!E3dsET@YGteOogaVYY1KrMFOabEI@ZP%!}ga0*{#8<>}NGz3gS=0hyohKf}@3*1?w{jyG&&hNfCTk|PPzkuT(c~#+-fg|P@o7fdSat`*uMib1!JDnl4_wocE->__@f1A2YN(UfSg#Z -{GzAd=gmXfApi*5bGS~!hGXPKpxv$o*`vmp-vsfojZ}B71Dky6&%Iq{R|$zfFlZo8X1JvLUi~uWjRH5 -r>{kxl2_=rWJ5$b%fL?DQQAp$*Rd0%6zu>Pp>T0olo2u1UmUEu!isBbCK~;P@W`gh?E_!vdMNaq8AtL -Mv)*X(Ar8=a;gJF%yBBpWSJ}akF{;_iT9M)mMJQ~Flc)Wi;i;icV6aH@tJ!&+YBVk1iwukJ*K9{=D9x -wJvWZ~qb2+Ca8+m)D*d5;rGI%RcNKYpo<`NIniAP(ujpvoPm3dCYt+#Y?1rD(WwLA*snXxzhXbQAWuc -cPbLt2Dq5oZySy1IDBvs%o2{owdvP;xkVpDt2PUMORU^ASt*5>;<&5QVA8PDSBKS34o14W83-J;?YN! -!XVW+&Ianjm9yv23d9-%T!#}0tiU~N13uCQVph}{yCHP*w1weDo|zMW>gt;^~Refr-}>jgd?wnLt7}v -@uVZuV<>@JS5Fi53>Bq3u(FVZ%XD=_;W3s1Qi0>=AW#Y&0vm@W2S%k@lpz?S4%!St1CrCdnr4urO48S(L%{(RmXt;NN*JImJz -mTG9}@RW--h8hQMblCYd=YHaHN8FyXbSqU;&gm_IqC~|_nR -4Yry0`WT@KJy?$;P!RDoVzrL1t7~w_D$JGBHS?7efxpf+vI`e&}%~d7cPuYD4bhyG!=%>u+Ahtc%am0 -b`1THKbC8VoQ(w2c7~w61##YmRNYM)=A6xuQdsEbK@0y$X_2I`d;URU4?IJqf|PaD<={YUmBi`A7X?n -2pp2i9Y}9AJcXW08MAj_)gx_*`Sj7OnOvt37f|8hS`R1Vb7e=U4@ERg=Kpkd}^iZZ)?>97sUoiB6}8a`=<+i@Mkd1GZO|R#w!iW%A9NH!k -jw*@Cd04c3sv(e#s0i_4<8mts0+({)i?tavp&wi*UsB<<=I|Ks9Iv)_*_znW4gpolC`kZ#r8lyK7Y+v -&){Pv3ubG_TEL$HttsCyea7vuf8(Lq1RS4C0ftE7Uw#x&f=C>*b4MI2 -d~fZ7otEoD_MX;OoWJijfdpL6y}j#KM#x=P7ZuF%EOXiq1zhNF#$w&Y_r%yt?9@{@HEJw;V!Gk$Mpll -F0KcyQNDIC!Hitz%I&%K5Q`~gr*=N683Xkp&I`x|XVa7;{v9}kYV*~r^XsPpPdt7C`*uxzjGE=iBS4u -fpx-AczO=*&Lpr25U7H=T_@al$MR>Jk~8*8j!J5Qj4qFWR -A_R6_Yb<}4q%}L*Y$|+#}?#=9(B-Aj5b}p?8O}QcwWlFR~#td!YRY2gL3no=?Smq>Gg~)-mvW)@^1i$ -n4LhIL7@&Cs~FRxSCs(D&(n4);C1WoHOP0BVqE|cfD!s^NYD&m&2E7>a_d$*>f`<)4!U{M3#qe9;~uZ -RiVdD4R{CzhsOiu^GL;of4vnw5gl5x5xXDym$t@u)qmXz=7I+TUst!7=NI`5@G|;x#Q(t3-Uev`A3OB -H*fi`-CJ{52vH6@8xczstC7PTH(c16H*>gj0eK%ML^zPob2L;m|HJ>%%sxG*vqyya4#3O$VAOItZ+YrNyOvX%YUuq -iprFdKB%ntg;5&%Lf5u0?A`mzZtD(NX3-Bh}i^Mj|Q0C_OK^Jx!5g4nOD;!gFyl{V;@{;Z{;8V4pMXk -dkX1c0gPiZIZq*s5C(9TQXCT;6jtX<@{@b!oj*kP)cl)YiELg1qZYo8(1*f>p7v&x$>#qVhxpx6eD9e -YKVb|Z?($UYp|m5OE9{k{8dX>(X;hB$uy5V`T94fjol(x%-*`eMMRC?6G9_0ME$Kn)^-ifWlPj|nw(H8PHDvn)MnOhN?hs -r@7D>AQ^}c)T`LP-O{LZWPF#2i1kd)~YDp8JJUf6d0MIF7UXA|~mmvhtG4coqcGtv!Djx -=izseI -vHp^$%mY|`~I|ER7igy$iA&2U?ot0(dk{AHBs06R?Lo!Ms%$KtaIs0-k$zVQy~B@do?<^4lkBt5Q)Xm0YF7j(_WK7A9vj{joqCi7GWAK@6SbA66E -6a8bOj!~o-wLe@TZ=z;zD~qOf{36-gpID(m23a+!A_Gqk06_o%03QGV0B~t=FJE?LZe(wAFL -iQkY-wUMFJE?La&u{KZZ2?nQ&tGc$ShV!%gjkt0MZ3T`6a2zC8;S2WtoWz&i*d0{^5SELBYIS@$qG;M -a7xc!Jc4cm4Z*nhn -a%^mAVlyveZ*Fd7V{~b6ZZ2?n%{={c+qjj#XD0sxDqqgjuFQO1n^n)#Dz>umtk+I$XEVJtr704UxTXj -#L0Zvmw|{%zdjLoPq#P&HnLF*wh6I6!hxh#+0MARYVo@}&tGeV-#In^|log9-Qsi~TBlZ69!NUjoOBz -?a%2vE-$i-rj6^rIw$mX$Zdr6Vp@Tz&;#AN}4pz9nFP+!gDyevh@V#zM4d5W*S9T5*vS8dlT)qvGEv}6k=yj;;HIAvz9wjFj}_vVc+6hEc -=FT$s;evy*QNNhHG`6p1JNUDi=@n>L=+YOM9Zwo?HJ)4iPbvGdCE3fwPcrC7JBOGAy}SoOo-8oJ^*wLaAjb8f38Q0@5`s0K`j{~w6;h;8_O$yuDHAW*DYW|CC`{^hKQS6l*LIEW -3)fR1s&W?YkmryA3im4+l@EU*$~mc;o8j0kE|%CdspJ{vaBZh0wDhcu+fG(?fh^BA=;GjI#MQF(dgj=@E#zI+J}S-UY)`tFM}w;rAHBULVTkc*uG@Rfo_ -NF*8$qr!I-^#GGg>B;pN4P=f7e1J@$Ud3(^Jw+Cgpt^`%~;^HS<_8|O7ga~^}BqSu-O?u$B)OQ1dwff -sR+aD)|PFoa87W&)NxA{YQ+9%nh=JTzcoI+)|1zh^6;)KY>Lf_>zqq)AML`9DEla{O{!8e?AU|N)46ny51}ByxE8e5_F@;gTbKn8Yu&P8xxrEH4;5k&MkCdTr=<$47}BCmIC# -`Ac5SJG0LQ@$~vjg+#t*u=mrD=sXV}S#8ox}idI{e$6HHkp$Itp|62Wkr(LDQ~Rd0lU72C4uR>z8 -o}L(A|J#&S&>yy1R9XfN9>!pTuAumo12Xthh~X -oFhVucaLf!j?qeCoA-0ob7hlNV@+R5p?G&~x(P9fD(q{TX1cK_IuSxS^QR2wS?E00 -DpB^9uYV18=z$C8lAq*{pcI?uNUztnNAG%OVu`B6qSqIjcP){-3DR!;yyV@9!_B2Esr(ei!}GA}uZ2Dp|5 -0Fs!#Suo9-wP#b20=m@JhoD7SahvBQ2GL}NQHS{_@Vk{FY{Jn2b(V?0iYcn*vDjm{3?go83f&t$G83~X8DFxO>Krlox7TOkChYb`kgXRQcWT -_BWpzY-aS;)a35`Pp8k+OPi7+}Z>BOOVrXd%Z*1p-QOhvh!vq!d!>U`f>m76cOjNe-Bz!ULs$sR67Uh -CB4N?t{mZZ?=!|K@}ZJ$~ -H_AI#VfzL)=qmBsFG8{2jQ+nwGqf#Z{{3G8-zg0^&Men<=$XVF9#Iog)Mi=-I_(++=iG=N59sGoHm8e -OPC*ahQwV_j);D%KvNVBo->^wg<(&?5!xHV>?-HCTm5stf`td=2I=&2FrgauL^jNa -TuFj9o$Lw|XiK#BSs*G#H04U{a^e&>XW&>6<35$bEGmAgTk8yd^$%tY_ypq?H=k>sg>q>y0b5!9cHgz -zTF191pI!3w)|DT`rLZ3a5+tTl!zlnNBMp(9u{xL31(LMOOOq -X$1K)RMSBu48eT;$%@ARJ5XG8J7_IVD$T_WWk)`FL2K}xa$g0zX6gGOl~_ -vZNgiJy5+sX9^1LmJpq)L%I}X5;F*_K?k>BdaH6sk-#lGJhY4d6jR;O-be>L{(9DRCw7(*&(UmTpF&< -p+!_WH0@XW&cnAOthlDIl-PwQm3VATKQQD@k7f9iotk>voCEI@__xm|N*dMX|LHIL-!NDqC2Y@d)s|r -hblD5Kv4w}Q^aI{M{kd=2xz)YmuLp0Ndgp%I8x{LmVii%%7vY4-K+{JV0cidx>Tal$~CDLrZRXc#Z8I -I*Q+8zVH7#fs^yQb1lVItPsz*Xe|RwoW($g-<}VQt_^z)j11l)M}4qe1$jr<*?v-XYitfyJmT0^b*zS -_)1X(Ugu|t|2i9{GACh@68Ik?7;uE>@ZmMFf>Y*bpd($S2EU7*+~vIssNLE%S{D15vvs#aXncBUL|Xo -ok=&v!zoqztnp&JNJOeis;ROF818dMmEs+UbXW{2tRq;eIlAFnNlvi}KHQ(VA8qd3Wa}uV?UAU#^pFi -y(}8Ikw8Lpq4}eaU1{Ct_?nwAk0*L -WMvQg7RC+!R{pK%ao1KKLgDM6s1yWx1-iFail59Yt_n^--6Y3IdxSPR&NngGz-5e;Y4{+}eIir+Tna( -Y22XH$LZP#derau_yWXm^fBqxZ!1Z3UwWCZfLnT6HZ=5zywNuv~#oCCyygXF^b$w^H1uGaAw2wVrZ^! -exNZOs|=Fo?A^5Xid_Tpr_8P}ZoXbyN$YfOhhdK;rOEBo8yDt10t=SH0N?kN@LbCt^|D{Jw;Z2X2 -Zli_n8^Q(IgEN6j-B0tJ9ms!K?tccGD}eZj2hgnnwYh%)F_vsBJN`8N3TaiPc(4m -xd)0Nt%hV?ePwPbqz*l{hbY~CF1aXDa#~y)b77>-6tl@yv}GbyC1Ov*@4_cK0;B@-CZqiVEKA$q$fz` -RdsP30VETkBehXQEr%X31PgOEHL(b(n9fwN5rPv3(oP#EK?r2xleGm7uTT7|~p=Q5$!}s&t?1 -UUmFRr4C>0jQRTuhJ6xt0w$uUrZnqVi}3`iLVf>gqHXMlDMCaEnR<$HG$vLPjSHwh<(kb`>x4u8ReLFO?@Nh@=WW+wO&T+(`vj_ffv^w_8>1VCQs&}v)9t!-*tuEMjz+aJvWb-T?!el -<7yf5PiuI^tRyhsecR$XbNlUXK-gs`EENFQulK3!?%}CF`v`zOP?LBy($7|a9XqdgIxIijgcW`?Vaxw -#%j%|MPn6Op*EY_Y05pb9c?1Syy#de@I@?HJm9>L&!vJTaz%Mr)fq9b}19TZUCp!B8H@rkkDNuKRs9p -J2IsT02V)K8tKhQ!w2N5Z=v^{Oo9$CQJirPiju9prMplIUhMGtphWZZq8oq-poT^)sPOsLoQj=Z=hKI -sB*#8gHYi$!8S_fH##l}I708?ygq)|q4nJ!`awiMhfP;zQrIX@AZ-P{-xfp=?+uk^~rC;Q -2AbScw`0)-?E+zkl^J!rbG!31=&_WT_ch`!-gT=T#2i|TC~5RiNC&s{SF*A7JLsmmPyOV9=PZ<(pCyA -6OaYYoc$a~0Aa#3!Vby=w_lsXXHFceZIZ>WK9AfZM*ZNFwXpm3#LoTq0{V7s+g$Fj=Uzb2z}5|YENG+ -4u8Vhl@tr%;R^;z3sME)eLwX|%Z(3IduF5USBA$I_=am;a(fdF#7C4j7}kNzgS5 -QQid1YQ3$&+@`rP~T@Wr=oRnMb5o%OUmzWdo!lzoqWpI+pg{cb&y)a|s4C2e<`OC+GRK%u4>N_g5OE8 -l|}-gHL=-5^i9Hm~gAkqH|Q(Y<(L1A!W4IZn9f^}&hTPEC~9h1BLhotV%EX%Zrbb^Vtb;L^YlSdKrGhm5Bd%^xg_rMMO|^a%jFnf+|A59-gGmR)l0= -fXM;_QIU*v8DG*%-D^T0Sb5#MOwvvI^=<2W&@f|h@b#si0{Kgy8sHHkAZGSIvY`kRW!&Mowwm3yA)`2 -XrXw#7t4FQ;GHUX3^EK*5&&9&%crBl4LSxv>7^aWaQn=oBM99cutLX}`VNM3eHFL>65f+~e$GtbZ$~r -!2G&hhGOrNJqq)O-8`mxh*CRFuLr;gGVxSw|&LaZiuy|LjPm^4${dIyu-3v%BRl+cb$P};l(Iqd0ZSD -@^E=l||^qqlckaRDw=(S+YES8~z!56QO*t3^UU+VfR6;{WOA1}bP)HA$=`B=+d^KXVFTKV|JcYnBZ8p -J;ZrO9#`4hJSLF*4AT-Q%y%IN|TEOUll8x5>Mf9H7{Y`t=d8^@4+L_~l+&x`$~wv`mYsa=N2v+Wyj)l -_~cG7_{lrt)aA=7*-`^R~gtoo{c(e)g<)xoVvlIq8I(Hs$ZkH#d@6g!P?B*4Xb&a~%I@LOP>v{QAJ0%Q&hGokN%5vD6?bHmmh@v29 -=L+kl2|J|GPcK!s1pH+BKU?ZdIUB7)zy!UsjVwT -jh5-Vl8L%KhU6vAs0=2D8#f03l*YX4eaE!J4r(ClJK*vp5|MXIN~xusV}RmUrqvYFDc$7!T+x^zI&v4{c59+M39~BbtB4T^R#ss+7h|9GwwN74bb-s{J)#wUoyzWBGeI$# -}g+|Ni!9@s$f9%`V*+r(7s2@Cv@8 -Ka?hu+~XCq#Ke=>+<>KP?R240U+T6JfiS{wGSYD-{$oix;$g9R*GV=_eXSS+b))^j#6;?5hVz$N+VeE -W^=h@X&eL@M4#hitAO^xE+|rEc4{$(JJLV`ixA{Wra7+7lXv|G$nQN%t86H@+hlTYQnqEGAs-XO&gPZ -PPujS!`e*sWS0|XQR000O8NLB_@HjA%?Rww`fHkAMXB>(^baA|NaUv_0~WN&gWb#iQMX<{=kV{dM5Wn -*+{Z*FjJZ)`4bdF?%EZyU*#-v^lg&`ZG(>7`nhon$6LG=bOF%n0j4YsoPdlL6Uc7s*~VyO};DF+ujX? ->p+QYFbVPK^6#MSY&r~9j{)!`@LQ^^(L9kmVMVZVm3>P&9-j3B)e(rvhT!g#^9*}c-;$g4kIUtdNqo}E -G>7i+N*aB-rRBUJCLx13jH-HQCOu1kCF=bLS}^Dq7=vRpKmS<}J>I5+CHd$rE0mB{VO7gZ}3fDa$UpL -)@DpLplw%{TQT!}_~G1EG(a}c6u@fIH>JA$u_>p?OjL_H7qc#FR${ -Q}tg4$$Ru+F2w9iOn+$%#5LZ5Vhn&5K83~nJodT8)yC1;67vy?C4O(30cM-tE!dUyk0MKhkw5Wi-#2{ -xL&7R#(JJ7`(o{15Elm@a?))j@)XTwVl(T9g3R#GEy}JLbESQ$8o7(Z~?OgdbQU)h$a4KY$d~WjjsUe -z67s@Dr!h`gESUL=Xp=Cs~!d4X(TvDNY!>NmGDlCr;&rkcc@g5v282RO3mK*8+jxnGHx_s$0=4MAaSf -ZYI2&$;S^Dt?u!DUBJYPHtAcj>|uwN$*%4j)fQ0iPBhegbqGKEEp4FNajtu_Mo29v@>eF-ur=@MO7JB -*DzC~GE?Ost@8x0%oVKWnZZ;dYqFhcBi8C;RGwfqx0E6?!1d -)xrwPNLDYZEBaed5F;U%3>L;gPT9-k3inaN)8Pg>UZfVX}_g6mnL#0LX`wreB+?DfK#@0%(aJ!xqwXH -Oalm?zC-lsrks-EJ%RsZ<@2saes~3_5X#gKZUi2E@zW0}s{?0sEcd$o%atE9IpdyDJ)cf&AEp!U2*l9 -OC<|gbnLz81jfWFROO2xDKXPWMyJld@wtD)Se!X;;%&?Z8}rfgibXcWszHlyQRaL7j1S^!i?5}nxq3A -ZQ)2OYID7YBL)Au3)8pgyD&6jYtyO8=td1A_{TSK7@i$p^lYR62MBFT%9lt4Vj#-w2_6Oz -jUq1)(c2mL?pno$GEAiO;g}$ZdFMoJ>@ot*PU!UH8eDnH0-n@VHpMT{UG5HF~(b)Yt^*C=p3$ND=@S& -qNTMC~D5^;o6$w;m?;S?x*w(-v;3Q|aMa(bvkVBy>>`j(7Ex=ND~EI2Fi>Ct3L5Qb-ps;f<3ik2dL0j -mnY5|8fA{n;SeTeG>uqxYHFAicp2MQH%g8U{fO{q~ujl|_nRdVkBT;Gh=^dtR?Hm{be=C%@{lu5aHI6 -`hM4!9*=bs)tzF((Re3Cvx9&wVM*w6n0K*mqVy72S9DtF0!-Q2?2 -sFF)U{p5Mdr-gtZfcPMoixtpYnuTii!UvZWYpfAi!_hiVfz%3+G-tjoGGugBUfdOVpV>TIP5>Zh`T_u -E$+E1o4uJ%~5Fl(!CA$Oxt|h>$p%`xjqm7jIrlvEL8bB1S0M69{IP+4&6F7KT+`M23NlIpOIm)U)K^w -SnvH@6_-j=XUM=QX9iiuU%pk#w=TFIGmT5X!VTp~bmYS0i6tY366nRV9MD+LP0$TDT*hksdlpY0G~24 -={jlD{RJ?4bn?X>G~7escp8fEC+R6>zxC?vSDacmeE$(E?9kn!JUz;*BafF=B~*xRMPBctuBq2mk;Qb -WfZeR(r8b=5wNv^Ep1;3Oc346{a2(?fKjnK>cA33+S_hK5t-40cJbCfpP`h#2M#6;15j9w?CS`>GVcL2CeEqdFn*;w -iQ0hIrVP#iHoSoj)>aX@#&yCRGhrvMg48Lm*KrzuBSqLaGc+Mok3qpU$WhM4S;=*0dQLo$7>D+m9dKf -Yi6H`!ZK3O$e2PcDsQ2PKiLl%1|~GA?a6yfXohWvkEl*W*(ivECljP7>0H$Yj(UMo|J64e`5COH#7XA -iT&}9PoE;n%x>@PS>-wD-@pwt_u*Zo3BX=3MZkmAu7d$B4&w2`=`i@bhb-l9t~ta$-TCS9Ct%I}%>vSt6%(}(`%o&qg>)bNaIFrmHeSQA@%a3oaXV({R&)R)!9H-@-ClF|E5MJzGUkbo{B!G!A@*CV9VUWBRs!QGi7k2xrDyh_oX&mv< -jofaucS?{4?>iWF^U*sRk)3Ei;mU)WZ{R2nlUu2M8Zu@0NGZn9iwf50+s@?v!Q9xo`TB-+~@U`#9t8% -Azoqxa6zZgig>{GC#j3B1&g+^J6y^y68sw0?1W=`D^qM#v$_r|F#D|NWMpojQp9+iTyTdYnG4l8rT?` -%*K-h4VsMd4F_*`G~m*0-;s7RaVK=W7N{0C$c0;=!Ytzgn&NCoEfzOD8RL> -|-)upLZc}gdRlk|peEKYT7HOebTX-eVpb6Bnt(J?;2@i;J}LWFA`$^ -~vbdQPlePv*g4yDeF~A=s9-RHUd4mAq0krva)7LyW=PMlU*f`%oKz0X3s3$;x}G{r%!E!ah9gOO4}SZagYVQ02*1QdUn2 -L*V+6Z;7DbT>i(%9IbC8@V8X*wDor<95ppaQ7sx7yl_oaVBbhy&GxH$Lay}=CWIiXQ3P!dFFd?-)gI3 -PZQV;PnXve_Mm9$&{g}ToQ6pEKMYa58Zz#ed3Xayo?ko}}Da2j)I>Uulpih>dUMB5hL#*V!XBdbU4bv -}4RB`O;`KVe_vQ)wIHi4`G}V|mZ;YJ(UtDTEi7yzBrsL2GBr{wdN?BN<5X#FI|Qu{n@FW|wY5~FnmoGN`CL!GzQ9~IP0>m!S{Qzr!G9Xyt9kq{{XqT3OV -UJH|`CjAPiq2y`CN5#^T;Sd&1SKeBuylMqWoZ-tx{U~C4sN5cc+WPMl9&?N``olKH55NRR^a9~+cSQN -=!K!Vh#O)s0iW1G}2){$+GmCk7p6A?^O($JQ*WDKMNL=Kc6QPqz121`L2KsM$bZ9kC*rT=0xDLyCKh66%E~6KGJr&YI}Muv_bh}bDp{hp4sBzNEM|z0ge=2VTlmyj76K1TB`Tsia3`7_5F;P -}FwY!D-%UZYsze$Pc8{0%@_E2l(vWHnFpKYDe}n#r6e#PLxFcNx2vp^=5hNwZb3+0rojO3oTl?o&>(Hc>${q5VcV{Ef0u0>Y1dJJ1)HnPjIyfBL+@Ar6knN7S&TTe5H2mDU}TY05Yx5afuQ -a2`NxUeuc{DDgK%S#-Op-=TInVUSUtlzFe#j#%FNs?7!SSQ*f{=z2i -xopkKLGryPm4TnM45q=ck12C~{#Nl?(9Gt+9KXNc4j`E^tJtJ&RGt3i&PBL!P1(egDv=o8jtlI -6*BQ{rpgDbKd*bdw}G{N96SS1HGIDX*d!uXDn>#Z}}6?Z`1MULoM5HJ@QiHLF!@|R&X4m1w -fF!NT?&|jVPpI#6lH(Pw6*K$dAVOCxq-PTKcwb+X8i2yR()-QBi2{)f)x_`%qDCbSzVNV$g#Mr$U3T2 -HIOxS(&0)tP<=l$!nJQl}u7E9U>`1U_c^o?I4(978oc8&?RcSO&4CQZ+;0dx!YjbaMLL)XZdDE7YJ+oa4|@ -_-`Z$*m+62D1Oy;lEQSuVRAKHxzg-ch8v!wM_glY%tV)2f>q4fGC~`A|Gd=lyYW+ -*Vn4B8yBe5T9K;>#hA2?ZQ`lAJ5}68(l5YlyCa3h`Y2wYpxf56OC*aJDv8u}aYz0zb71!F7b+x75hDf -}d-^lkZ0yk282R+T5)obfz8}@64USLjfot!{Y=`=Vmx7awWyI&@#pU@VVG|F5gafyW*6ywps{-~E5Ef --jifOH-_U38ptT?rzBDGP)4XV_H)R`kjb4acaqF4b`V=Bq%LKG-pn~VlP(~j-+SuQQ{-f8jH7daX%1w -KOQzIcDG(xhTXObU=lbT`@J{nhcCqUs;~b_7^zbbj^Y$LrVcKfR+Z@%N!NGU=3?Uw(Lh{r>vD;b~ZQ# -devx;<5Zu5D{9Cj6_o`Zo3qAY2DwXMSTn+=IZ$Qvy)#PpPU?@{PsA@F}kS-h#nQyk#@lzWk)(b`lxOn -j&4O$iSh_;9|z|^ND-DI1ghjOA-ttco5A -j`I2ab?mfW|(s}E)pve=6Y84F3Gzeq@*+F907iT%sPYwvj2okchyFsC?gx`YYBWoT*0W^nCP)eZ?8B9G(=--I{9L54)bb@wpXJ4p{cU?-&?nMNud&ORL?4Ysz0#Skc>t~PiAkg-%s3_(-If#gEt^NZ6e -E0abns6?Jz;eWo%|Sq=V=%r4a7j+W~&>Rho2$7|Vnwpd{Hg5|X{t?DwLu^%r8rsd1NgFnQ3kSbvi+|2 -JQ{GUv5(lXcfEi8{uDDEWGHG@>MU+#%0?ccx=PuPIuz!{ -;8o|juJ_nEtRG&uwe&FUXx9|ihi7Fh9($~mJ>)&(zB<>=yKu4JRq1e#pJt%&(s*$FN$`XbsCrjldj~c -(W#;6x29y9cD`Kon?)GI$*nealgWn@wF&&R -B=h^;--PZ3>JFlnHFKY&dm=K#Qcb^+Kz=BKMpQH#<`f!_9=5>#`auph_-qFxS}Wcy4d|ob4?*X|_`e6 -67DY6ln+~!F_ZK&(RAM~qFCBe3OltCdA5VU6e9)e_RIn|peoSz4g@#E -d}<7CkF?n6r8Z=&;QPb*^)$JBe}(^lg#SdhNGFk=fe?7zUc<6Jet1Jtq{L;*0+Uc0MbHf%F0Y^0S(g! -_iYix%o$3Ue!<-6AzEsEp$_pTf`gODGL_7C{Npzfbq9GB;O1j1;kG%)k!htrlBT_KE1ZQjRVR9o)-=s -I9ajb8+d7-RyGG^WPtE%nz-$>ZHQz>h1*(3d2mrIoJ=5vG=2 -xC-11Z}09*^KT_>5?E)DU~sP=yS6%b(T_^%G{0|jV0u}{gFR4FVK8Ml_Nl{Yb_w9k!5g{6S|lcQ1yB& -hQd)B91ym_-9!%P>$RB9Uez*pS&yv(K4>(yr`9sqj~D7gm$K{KvI`Bb3$vveHZ)G;mpw11(!^^5WUa6#jeet@g#U7kK#_{O{XInw(>S3%&eB4QMZ2$2@OmEjni2(Qid?jg9N;>(;FyGYDwZRBlkM!f -Bx4i8GWom0L}F{Q#p%exgo##B1_@c$f>nFQav2AX;kYbs;I?_RiK3fv{qwm!CeUvco})6I{G1uiat`p -s3Y<4tTqs#dp#ld$QKhJ(=~%YV7%p6%eI4K~RVk~g2B&vYAD&a)TX+yi&9y}gYvRN)=|dkQ5ofHIoqH -my-dOH>v1+rJk=F%RWN2V9-jACM{KV)3e;=l;2 -OWa5G(T#5^fYOkTXX(l6phX;UwO?Na=6f3XTFo=mxNM8wqT6qca%1EQJ7w0X%$F_Pn+*(D{ydKQMl44 -T-jCTEFH1V$ba7)c`FMP-u#nG2*^!}}7IHcir;9V4}8o~D^ag`u$(pAcI$7D{ksGSubo#i5lt%2_Q~b -4V7ONc^&&k26s->Y+zg(3t3c9J`ffX<_@*L884_D9Q-!8rdTjRSX109suW=)S@{XiST5%s>YrydL=bi -`&s5N0GVT{r5ra{0lFoc`*E8y%>a2qL*aCrsAtrf!Zk#^s?s%ClFY$lH;TY2DQQ3JpUX=hIi -ZYF&o)vd{{*w7augB|I@Ic40;BYql1(lHE9qm9#0xWC6`G<$CY9pcsd|6Sq*l3FHn7mUL48rJmbk==rxU4&ar`kjU`siXH^I~m+=>S%0 -qj;R#P%#YJHdGGo}%mYaaK`>RSPa#N^~^V+|Kp%yrBd5)J0*T*vbLyLacWt}#=??v0F~C~no;9jjxKR -AZ?wQ?De!VxO2sLu7^P&vX(S>(+JkTTuZg*+G0b+CxZhZKSLD`|S(#!<-R_AAWsA?|wWQ+QOTT52t3r9nniJim%Dyl)r>HLX_(9wk02z -|dR1xzj(>RihFvhEHa-C0Y3Z0ui$Z|&SQ2fnWWV7N~k2c!YijfW_z(}@|mEG166-(z* -WNzWlyd7;+zJ8s#Wj8R6kKZD_i>ws`&hE*$(&tB8REzn&y~_8(i?-_-M7fq2h(yj?^^VXjivQ7`_+|k -E1-|q~k|b(6$qBWs-%zhi}okX|R5Wst_8 -bhoDMmO;9F#a={WAE0@aQlTdU+mm|t?_YD>qXyjRl53P=XRYB6xH6y3NKSdEVL^5|aP} -j!n`W_3u8A^WHLr^t@qV>8Fo4PeYhxG=n -)KVxPQ`^zDC0^t?lkj5O;s$S+br@<8TE<1&_{i&s9En$>}@vc6M5~B?l6AYf2WKcuNhDNdCe6ud^#r6 -OIkZGfei0~QpDXzFDj@;eWMI$m3Zi^(q^0sm+slT$hLSn{L^IYh9mn6p7@$Je(?CJN5(<0dKr#kZ&&0 -+L=(<{A1t}3#x!pw8joIa4I-7_O68g1ZVIx)7thGSw80fSnB~+&0q)XtRQM_p!TAqrjHXoY2I~++sGO -6uLe9{>ZeT>I>M(i1*n}72r1YwV}Bz7~R!rt -h-l{#Kx)4(bjq#jLK$z&IFWB%2KW(LiLh`b7A{YmbE+<;bn4Q8GGx1}K6I7{du)r82L`ceg-Xpgx -Xd2H!34|F37M@-kI6%wRYZv0AghG24m^;myF^+ZWqHA#&CRH_N8mRO)6C~OW -Pf>yv?lC3g7o8>c+^JI9&X^o#?Xg(#&+VG_0P>gIle9|1sQcK!8tqQ|@jt=PRJ7K)0`h209v0rx>ma? -LEq-8z4<=e48ukQ?qiL;n$9G#05-f92%Vl7Aki2^^>m%l@{JV<_YLpy$N+adYVtdy^&BJLxjH#q)4I( -QKEgVtj=;5xV;Qgko*1p|j)JbMwL5mH|{OGZDOUypo36VFuJ$3Y!_sb--ie4BH|bLyP|<1a-*B6w%NSI~Ql={S7XVDK`*E6g ->+YBOPx~mG7Vr}cQo+!)OkYh%ag^z=5x7upyIAXvjsJxo2v`~eN(-lc+M|oozL+CX7b6v#k$Ek^! -g58NNvYnD|7M1GTIwFD}x0q`EVh{JS;$Kryybm#e9A%cI3rE`}usn;E6jw8}X-B{>)~0rL~qLFUrGKu0zaY!^Q&p4@&V)6Rz -s(~}hU3wa&s>zD|WffH+bSgOwzW%7)^Zp|XAO7`%qkS(pQV16$#3|H^-asUb^`tN>cu1mZ07`?N{w?n -;4cxX)^}v{T79R29CUY|+KWPMQX!fE1V&G*Q(f4WiX$w(qAaTXd<)C*Wctc0IVw@8)PDC%x;{A9a!%z -4wDuqmN2-R1wg+?nheW~xUHi%)W4StV|q>xRHrhfXpNz}v6K_Ri;q`T`4Bno9M1>9}?Fumw>M?ct~r{XocPE;bUcB452iC4M<1}v{ -2Wm52V##R_vp7T{&S%rv;zWwA~L3?Xbwt7L>`A=1y~i6v@}h0ae1gIQAro2V@(xpbkKFUArUkmafhW? -O+aI~IsBMSSO>5)j2&=hOWWig8SfMYQl%Yu_votY4xXPYw4@4V5-lxZLq<`$5pgzRUI&lhD{*wMfcRN -M$-}a=v93&{LQK5ZY7`qCFN;10jLbciq*{Bz4%_77@)Y^R@PW}-FM|tJP>g!5yp`qe#23aw-JEx(rAn -yMQdR7{b!7`YaE5=Z2uR-p!9EOArPbQWzw4b~{`;nFY5yPcg0QQ9^c%u{^{W?yuL!eiOt`YIdeMq|6% -hD!zuD}})o9STb`ys*0bRIGk?Bp@3=*&XzUz7#5=%)D)D6i^F`p-{#9nXCt*Arv%_bul!k2 -2grW$&tuNdOY>?bRV| -59EFvF@`W*o($BBHXR%!-`CAT>&TMh=nVRvG80rEexzJLCiaymb*sv42o@BAjj?jcoXR=QJ(P)(cxya -rP_(lQp)+%SX;o$bRX?O~dX20FtGEKHv>5j25q2F^=et*} -6Hepiq${7Q(^!5&o_g2~a!a@d)?UbI-iS5(I*>GR*D4_LYvMc(|VZ?lz1*WIQZ>hl0Zr6UC|EE-Cn4G -9%~VrADZsut5TgbZx{#686#KEM8o>X?~)1`6<#iD6ix`u09B+xmpK~iOwxH}mVgGoa2Xw#YHch-J>ivAnb-Et={WvMyhen?g+<_jw? -VE%x5dAylonp`3aK`Wvxz2*0h>4Hv{AjXRddX;P>QBbDdP-0NiFS=S68M6xTn7)Qqn_~G9OyQ;aUtAZ -6mxAa<^)&NA#%q!cmIEh-%`9p@qMcf)Z-+lL;9qi&`*r9wK$f~YaASPe}&*8*3bWRRH$k59i -m1)8tUM)L8l00%cZFFM5T}P-U)Z^6fME2#OecL}hsdVn%SQpdicVbfEZAFSpI=<&mAJ)4Q*VT5x#Zsk -U6sz$=@^$@Wy?2qScu^F`i9FQuq`1FNP7T0c@j-;~^op+XokbT9P5xoPMn%#;Rlae4O}JO!W(=yJUW$ -(8k5pQ-d^22Z2EfMUYU3k-3uO-#C((W1%zTu|l|hK9HJT2(r|f9la`zrsvLN=ufN>7;GPkY39SpZ4(z9`knQ&!cV5>-kQ%C6h@&YkDq{`$plHI5T -qwo^ENl5aht8=}hP<)59*PKgTm=ckj?qZ1k4s7iMd&-y=5O9KQH0000807zB_Q$nV<`Tq$309+ve03i -SX0B~t=FJE?LZe(wAFLiQkY-wUMFJ*XRWpH$9Z*FrgaCyC1TW=e?5q=Ml|3D}(A{UAhobwV0#{qH_r3 -v6Tfn~RkGPO%dtar&R$(1Y=?QieQkldSAvfPInuq`dgxqLI6+pdhx*8 -_fR`mQl(cROj>SrVVqpa1h8W(E;Gx}Hx;?joF!T*ks$UbFND!g`}0`3jc5>MPUAhm -!LA`+d7^Hk=g(>ZrC0gd1 -kT6@WH74)BKGt5%)5_+vfN6_TV8yNlUmeL6KlszFa3=U!Gj -g18wVXf6yv&&@^QACMukcnGDZtAu#TAi?bR3nQ6x{Hf?(>A*wLP^CvJ;2K@|z|k+vMRta1$Z_{XVWwP -;^Hd)v99zd1$e+APgGF1ct#R7{+4g2|KGGXvY;ku$^12{LxaS!eo0SSGj9I<-AbniCs}R>4rnU23GSQ -B0>BKHwxAUV4@1&2ri{Nui%Ac!zqu+_QG6JDr)e)Y|?F7xIf~y0(dL+YwM;PuGS(w+gl*yi6?0t1!K& -sYvC*er(h9sZ;pS3Tr0K#4(BJCfXUVGOkgvmOKg<>3XMUI!Q`ns~bJ#E};-erJdihlUW9}7% -Z@*25cwbs*?w-SDOM@PvDR4^G^?;Um6aDtKB-s{^)u7>0x|u8@uXvISrd%M(i9P?qcH6fJK>MY)ORNA -{Z%m;AB|v!wF%w!t_Ueh%10v8{kxf!zdl=E-begcaA3;kOGlWaP2LcT&j&Q(s@P@jFBKFzPdtXoAvrO+G6`l}ann8h@zC?l;JE6i6#zv9&3cgWxrmq -`lAD065Cq)001lJm_Er|a&o|Pdc)gMRfjM@`41&^*Pqn*+C7eg#(Yq^D8=+IIXr8`HGU)XTs|L9>NcwcLd2ud|!k?f2XvgE${jZUd~+&Td{?A`2pRlk(&YRx)KsN{`~}Qm#W&|6yq;n`-$OHzWBz&>S4 --z8u~NV+ZRj5Xk)`lq^9+rDW!#||UuXaT8T_2xUC-ash(fECT$jcN8|ljrzJG+M>9EzQk63^B4#(>958Nd21TZ3LlVZ}>7_H!e!-z)9CkGyX>U0l+eDl-gX_zT -wqBl_b4|s%GFiw`D2(dxO0rl8Vv8gGK@;~^d+rgs{$c6a#_MPhiVc!1wV|l%==Q^%xx)p&#g10i6l82Ag9&uHHIu3~XqsIZqrcUDK{84TME622_K6$h3JsQ2fKf5G?4}7V -Ylopym$`P*6C@vj@L#tD)aZ01t|sP}D%G)f9y-UQz2{35Q6CSdSm}b@!uFj8;c=;RtkKz!JxHGorw-pA9L1CfCA$gLEJlyX`}f#};ztXg2Q^)h+2d?FUQWKy=6u+%L2p$_ -fw-S$AAb&;v2aT&$m%yf=XYnlzF!GE?5%LViZDuym7oRBNd&%yG`d`G!gG9?72Yp2FgW#|nyxPn5`g% -#v(M!o-*v*3SomwdDEz?@y^Gn=*bCYOhb0zuFPUDC<9lwJ#^#vlPe*%rglT&O8qjq}7dSCI(o0`7_R( -Z<0-=#YVIYGR9t5ilx-`3nJVfIxL*6SRc2cEShGPYI9LMmYhCw~7OPov5*fNfWX-s7Hq4)DN0mLPcJT -T#Z0Z>Z=1QY-O00;m`Rt8hrcP2(N3IG6=A^-p#0001RX>c!Jc4cm4Z*nhna%^mAVlyvhX=Q9=b1ras- -C65y+sGCEA0Y2AU=WDRN@H8zpn+Ny^*YXOfH)13EZV|0s1Z4m7*iydGmNdK>9hBoxsbzKHdz!~phAF< -!#Ur%UuL{1^F0Z}O(m<6hapM!MP5q6)*??U$wU4A@WI0e<_q7mB&C&1QciCA_rRAcD4Pm`z-L%QeJ(J;%v -zV8m(kd)B(R_Y-;%i@hWNF2F?)ZtP1uw~_$|7_gs-mF?%VP3Nl}iq8K@+B&Xmp~`xr8TeTd=zZ1D`X= -w+9q2$#_hXjJ$nuPEd;4t8Z8-lc-8rnH~UuZ>kho_P_?(N=!+ -b-0FxRsH~t6A&CIkG|lgXCR!;;PMf9pc9UJX8Lep?_xD?I={0B~c!8BkVvxC*XD=Sr&0$i8IBLLDxyf%7cpGz~P|Lc-Pn0<#jd*T3IA8{g$MfJQhpuvG6A3F=@qnvsso0hqNK5JkugE -5haP|Q1JVR7n1ltYkOR%eHUe!gSpMxb6&3n9rS_;;b5hL_t>jc)>1fzKwG}~$9zG^Bl6}TcMz%bQF~h -9JNA4;^aoo52#Zh`0Two2VjGK?=UNo?Ras$X_E<2p75rcYBI`;zpbbPjc!Wc9s?n_cPM@M}VQo+~O1X -64<|j*Vb>Gv!&4MElX}qKM=rSAr^#1bI)9~%Zn^$M&7nc{W-@gNpPkMXhU027)^SQTx$H(yh)Y|SXFH -#mkXS(*tT_ShzaP3i->gl=ENr$Ru~{#DkTco^{Wd!Wa-|69w#=)-KMroJ?+dJ -hK(_<{8s+-}8jJ6sdjIn1hdjyrEBMYu#Gq?y9)U8AenyqYIMZ8x5PooDjNwF`sc1$7Dyp?__3K7@uYi -n?0@%);{(ggiioALp_#d`@)g@P2oWJGeElT;kWE(S0HIu-}F`dupA6B7KSH%U_)N8(D9}|!gdTvyeso -nr315Cdzfd|N2Ye*>x2e|baIYDYCkh{}}ZlOR_YntSG0D-|n^<_cv^^r~vFrr$VK`OKVqgkZWI;QIXq -5v4=06DsbOv*u-rV9Qpvx(g_TB8OEZ8t~1G@$4*{{qajhJ)B0D`PRkq64R?b&@6$9Wjv8Akk>1YtSf# -5d`|rFOVnlMZ(kA&(|No*}ddHBN$6I)36MHG^Hja>pVU^+|G>!#M%uicL5sBvY-Ck&%Rw9}W$kIWkVQSK!|QYyDz18bqz5Y}0MS5VZ?Kry&ZSZl=wv3U -7xoc+h#ZPFcRrGk2R2dU(09&~j8>L*(W+3PwW}0!t-U_fs7q%UZ6^7L^!FqHAsIi}g3mfS+3vPd{`9X -fT3&^BN2yH#)=i?vnM$UsRGqX72L1@evM(p{$@r2|r4qNvhCu%Fgr~?CKh{t{5sp$wF~oto{vsF-_K| -RPhnitvM^QfnuGP2R*XpX*?71fU%774HXvry{ihmixOCqpbu2gKJgak>-Yhm2B{fRAV*>BGR4H6PtIO -HSF7lLB@qR^>KDut$M5dd7e+O?e0h06R97+T-0gVDRT9>p5W{9NZLqN5^Lw@js>Q-p9e{jtNOzo9LodjM03Sx+objQlR&x-w~t)%~Hd -K(AKytD%JpMtIXbWKCEP(7vnD(tQcq;+qqegVgGUCC^N?l)mbMWZ;a2zgEos^&>CKBvu`LH-7FKJ8gZ -buj8bEL-$}GQKNT5IXuAO@4sxOxB6tYMg+Bk-GY3f|hvOi*pj+zH(24y+#q&e}O@bm#i0O_4K6h2@IOYs22;mOZ5c&GIU^ -Ua+1Rmj7-Gp(1S-E?x1=@Ic2E094dLK``Ka$%yJj~&NQo0%|$x13H7FRb;nFc4Sd|9?+AFJc;o~fF(d -ewXwkShE7ttz0dbej0VdmT&NZxLpTP?ugqIc8wfCWYK*9`jhcgJkHyr1e#BAneuYn8Iy}p*s8PI*v-*R;~ -kpe~j^hf!I_ZbaX0`R&;i{aOVhF&lzzOD*8Ownm{^BsR@{6GnR}-{3Y-g1Mv+uhVsQoEm|-9-CGHu)+ -a8K>rM`sUlr!q8yv}cA@ANHxEB^p>mR7)u4x9E?8KE|(!C0C?o#CnQmFG?StG$xl9ct~*heW}=@}|yJ1RRB6*-p3hr+Q2e`dHoLl2aOo?+zUO -Rp7a{#5nmiqNWHtgf0O|<<03QGV0B~t=FJE?LZe(wAFLiQ -kY-wUMFJ@_MWpHnEbS`jtl~zrU+cprr8}NS^C|E!$Y!zvMpm4F5ASvKOnxg5YNCKIXMr(E{Q6;I}^(D -VOGZgi)vb)&`Fd&h`H#2YE3|$#rLzY#Y>kMWY$hy_Wfyk{^ox`mEUa!`xu#?M1*h0#2q0l83cKp=zS} -~~91K69BL%aXLAbuyUB&yO5+kfGI9a{H0FAf&1C~n0Kjy6_4EVoix8@6-CzBkgLf$I=asBBdnFpjXG^DIa3G*TO|stv2jpo1GTKt -X{~I!08JN=!#YJckeD9vLCNYAYnygPG^MWNm#>qgKOie;w9h^L^PgWrgiEBs8Kq2V$C1a40)jy*Ycm> -6`7=|QFGHsDf3a{j?u&9p#GWjLL(q4`ZEuq@3h#aFTBhHEl9no8L43P`y98WEL|LGGpp=BY@vm%T$*M -oQD-S3K|3JfuCyq9D~kR)c9Hcpd%^_X36g398;nk^@zevhl`mq -0ck=LgP%*gTT)JQjXV9;NCPJ}fSxnC#|ADT_Yq35|d92+5@~{%`%#6iRFj7F5J?w}Y4I>mk3VO8fT_L -6oI*Qa4=LXO#83+(RtkPw_ -K2K_)#o_?Un&CH=%tZx`>U!efOox4)vEk;<>P|V?3ga@eu1n#>7}n6@*MH~+&qVOfp9kTir=sxeAR-Q -j{`lcQ)u16ql|vYv{LD_a>;>NM-@oGsYvD#(cVr{#5bKPPw~t(eQBTQD?Bi+kyiz7hXG4}Vcl$6TTP! -4DkgzC;hEnav=`<_vrBaY1++gEnU-mgqNI{HKKnh!J-EyoS&gXi`lQ`UR@ie?g*VGPNmdg|T>?*oEe! -e%bhe%R?4aRvKZMRqUv-#Xaa0T%IpG*Ser@u2}KA41)9yT@Dl;rV9t%}CR!sC0KOC{aud+6L{4j)|RPAx9|T*%M+dvXfTXbi@eDULk5E^v9hJZq2JMv~tR_&@Y12uAYBbZi -HExd9ZwH|r!uY{&38yI6P)iXvO1&QPS5P0oz6$bY|jbh95MXU5*!6JT3ncUM=}yQ+)cHuYYl>9%XTMy -9Dy`$OHdBHQS?>{^-f?}rZ_J}@JBU6wL$RbA=+*|w|lwysO}q^vJ4RCR&twzxx*dh6^a?`1Blwmkl-W -pP$lZKf*O*adlARXqOyknNJ6K74q0){ne{ktIDlk00XfbaPB~zLR@tfy$d)9s(TZ4<88lysq;MpZ_H* -JNdF{>SoCUZ?c>BvTct3vv*B>b37-&zgCx3eO-+W=nKe>-^g}X7urthT2&?o#98#rwNy+If@-8rcWrw}+YScGU}1 -w~aT~yoU>FdxgM?@b4^SM^G%HIGw3YZcLsq@XDmY#MSmmns?CvbS}o@6OLbPu#H(<|9%AX7XkE -mRZC1B$ltrtP0028T@R>$)jsECLT7d?j9#r68#gFagIz)?9RZP!BEIU51?L%0g_U0HR!}LKdQ}VFZ4o -cI=sGOQBkg;P9bdin^gGT~)}YJOa5q2J1w8*eQ@WEjrEMU{JSBmxKBrdd -&d=ED*=Zr7W4_t9v13a_Tm#aw+PqfWZV*>5Rvb%4~a{vyS6hZ` -^~r&u+B(U5>GOCo>R7bCLpB4OnuZ@$4-;mCXSLM->d_ -fGk8XX$o7KQ_y-TaHt@ZnJObD0Dx(+H5SB~4KfS~0YaOVce(|W50eEO11&d$)t>{X@q-5$W9C-@m2ul)ETacItGW(FL{vqyBMfYqL%3hl3$!5LFH&~?@nKtudWzD>^n3b~#$f^Z -uSZWiJ(vhRX@R3Wz_g}<_{Yzf_}ZuVIT8qv&2Cz0q&VZ5|Oa&c-HIh*m9vqomE^sKP}Gl=4u*`>lPCD -8(Wvj#0TuYQr|H60Zh`~HVB@%+EP`_mExtlbe;m|-HT3W4GR9tRkmY55o|fULA?)s;*b6v#{?fnajU9 -Hf8`rJ+BUX1E)g<-~|~H(rWC;VDq8vWf#Ydy+)F+KOY{iEE{IB#OHXB%Sx$$X#}&z&0N)1$!d5Qbc^gfjjV5wM@~>2z-wh_yU-~0wrZQ}`wx2<-Q3=vy;egufb+Za=3=72 -lynhGp}Z&-L6U^7sM%u5C*jV*}@F&GMNbqY~5YkH&$Ux{;tUg=tjeb*w(5p{ROB?Lj2l6E+NgsDawQ) -^GRiVuJomnonc~qGw52UxNn6ODNb07Vr}{-5vo145SJbjkKl59%31ii%PN?29mW+R%ze}& -=VbKEg%m59n?~`#>*hLP?>;<^O8@ng1ihyo`)F~*JDvktQ*im;RpEFZ2#PeoL?1~IquH -9KAFU}Ukx;}%jw=3Owbms!3OUZPB9PFp(%u>c8;hr1>zJ6Z%dJm~-)fx9T{4IJVq(4$j^sH#GNNA2io -%~EM|06-!3q(It#8qP3G=aJ&kA1o6 -b2zZpAhgFn8vXQa9pNPs+0P|;-hCGe8rIPH&|CBudoDUM~TZlB -TwPbuDZ`wd772*>~m23H_e(nf2A(s^bgMR;1u%=%7N93B}ea6Ev_7?K}om+RxQ -Px=FYe0h`Y!BC%`+6Vag{`>E3sRjhp7p1#l+|OVrFmjcF^`$5ol_HwE~bQ*l -W05*~X&6@I>=DmGeih{0TK(AY)_sL17jgJ6~O1d#ld530VBO`|w}w@FEW|ESF!ABa|uc$D~2ADa7|22 -#n!FvMq^@$UFIT5#hrP~PMzCK&wfDl5&SjSq@>3I?zb@|ha%d5a&iQd1<*$j42lFqE&*nYVx%I4$9>7 -Y5kT(g3|mUK5)QethsHrQ&>jF{lraAp7X{t_MGTu>b&nuKn6%Xbr(Z_`6$-KychHc;L)4swR*LOV)`m -mXOx3*U?EJOoX7tma?&I?f=G1aRAc+^b6mvdSx>5J*lr>)z0#kV;f`XVQmodhQ4tJr$th9t=JsJDS|s -)dkSrDBi12V!1x`q3c>7+{SdF{OpvO`s_3&iqgI8i$d_~ZO#M!GPss#hjZ&e(xJCOu@;{$~z&Rp2A~c -f6#j{pZwk=Xi){Pe>9JssK1*L=?uu#HTj}VWLOp*mQ)Cw#nVu|=G)^#90e(~;=tuw*CS&r&!;(JWgBbx~PYb0L56&|aCG`znMnVAca8C`fRZYQ`+t -d_)_fV`NV8Y8)~0e1+C_P@sM{X4H{(&VPsBYPT)WyNmp+k{7t;+myz)7Wyx_Bjydm-|DDWlSt^W9$j> -DJvebuYk0N3RH4Wp&|+kI=aA~keXjB7{-J!+ir1*svd7kb+PlWFu{Lrx|Wlne*Q-K2Yt+isV(MasKTY -ZO%a{%c0R&8d}Jh$Y&Ll4DQIF5=IM$Vx)eseP&RM3@jpr|6@IC4M^*5di6l4vc3`k^23ct=Gf+HER+{ -JtdH}HyJS$vo?-e*Z-CtbbXFY{yctyWnCwAwa7=(al2qS;7m(2y>&=*;46n>%s%+PwR*ACQG)+kbRq( -PJlP+10iXyh9xH3#MdC}D*vFb7^RYxEbT4yhj70E!=meFyW|+nVd~`XF<)RRDe#>F21qPKg|;N4~lDe -KEN{D0v!V12%z7Qc+xve=)If|}JambWUk -UBh}kaewn~P}}IbC(zfi=xX0#3AN>1J}CBkic0rzApgpbuK043)>ARo__nbt6?au^)oIdl+CcwKiHO1 -;D%sicSlw7zALI)tZTxjHBC;od)`Eb~b%L@6| -_rxwVLaD2?Bwah;W-J|n}}B8B%q8~>V(FSa1Ad*R)rp_3pnrXqPL`pfwqidcd#!pVw*u+gBgj -|F|!F=B7{!i`F25jI?ymbR2FF!K(V-)$1Y`Q#EuX0z!Z^+*%$WSUT3PJWMUe5jGZ`FhHKv{e6O%*I5p -eVayu_8Db{Z=Vq`o~ykovj(G^Q%tKS^>{4B9g7OX*o^IKpSFW9VbLU_dbf8$!tL%lKq1EyO$Kh`GAzU -?s{eaM01&RvGfiXRrROV#h0!9jqHXP4RwD7(T(`)Qlw#0U#ZIXDtE5R5P3Qmgn`a%c7}fDe7w -U$DN^Q+SSI0o0{44wNgN9SA?)Ui7Whpq**oS&zL8HbA3RM;xBihF29x1l=~Pt+gIEe7%UEP4SH?802* -!nxMoIgIXh{gZwEGz%IO5EsuTc0mWLJ)pGX}+aHWgOvjcu`{nK1muDY5TTIR2Q*w$WEb@iiXg*Pa92U -vF=ZM1{t?7{|b2~1*@8%xKCwLNHQH0hDc&-W{yWu2HCO!gGM#uSOGd#(|zZhVqr5o}c$u+DNRO`^1PQ -9WQA6}m$&+s2F_ygWJSnrPQuCAV8JV}P8bMG5qArM>dONoW^jN2GLhdHLt*Iv*3$Ev?BALCkFuI#}jU -$$P|B=7$AjQf9pI0Nn_Q+=GHIo(6ABHur(qv8+xG;$(L#L&6`^ -5#}td(?eSF%l@q_ncxYJ_+K+Y~ca8E>=!Wc)Nf4+yxL!xT+Oz=JQFnLm3KPbRf_iuPjui?FRCWN?92x -~$=HPv13Tqo@;FRW?MzvoOeQ`>09}8lGtDs(hSdRE~7rfmkTnivxUVogKE^>{p%Jfw;V|V>|mb?CVpr -?Jyq3z2G`YtROJL!`>iFq(`lVokj-A=O`-lymTD5*4e?^cHAfx3`>xOF1|z@1=h0|eltdVs#SVw$C;s -p?V=YP5u7O5Ol-@pLeIJ}g}g=8XGI3pc!&J7-%1qh*G@+!zXQz-+y^(r`j5rmEI0>rJiw5}o`U<{kPLrhV32@+~%a?4%&ghA+wRrqJ{5^|8sd3A8$MO6sOYAZRfIYX-x0rgbz0SR!tU-h -6|KM9NAPK)=3`B2q*vQ6PwdPxIj>7zYOB=#6EH2J&Rb^kXTbe8n2W<3e>@X?~$Gzx5;vP(P*KqLYMH) -;zYd=@zl9;JwjerQT_o*GriE{00KUg!ctEFy@nwX9xbIXS7NtyU! -~)o-8g$DQarIV!VMfef<$3(jqTIo%-(8HF%bz#s5xL+2W!E4_dZ~RFy4D?5sjI!nD2QVKDKNMN60oMy --fvE!(`GB$_vX05@q}>2SK6}<8_Y|Y;N8Spb9VrkP9rpQfne)xRA0i=d5FNV#+L}{bT%Cg!aIFykf$) -!pf}`vbx363S6$x -@yUS~&bG4^OzyEpfkClV7i5*$Y@dLu#OC7siC+Y#+xVTZ8o__euNU<_@8F&fX3dMKVhefHh3$@wW}VW -je3&>{WouEqGzMpa4OT#Pn2^WwO@`DwJx^INykckI)Ad*|{N3>d^flYQ9ZXg(k5!VVg%!+drbX(ZZx? -^)1)?H&h>*fE4#2R+jlPnfbnD>63T#IeS29$lP938f;UK=hDA1Ro$!Ih8<|T(lE%;ICh|c>jYGjnX&Qv -9hcZJxVs!-n3b62so~zg;dlg5QXN14OkN@+J(G{M+_N%;Sqig!N8@%_+=YyroNr@knjY3)fXkH0*MVR -Qo(@WAp{U&&PFA#jX7y>^HSkfIZ{`KrXm+lwtRSfUV2!p}IYaRa&eVN0~+==@3EeE^Doh*LFn)2_wg~ -iWk|IxpKjaS@fq`U_PzqtJW*%!tTA%?=|H$M2zV!GHZA&j)DYVNW&M;ptY+Qv$1Dd(&B7u5Mp5ztSyA -KKY+rTB$Q+dg2w^CC;LrRavYa{8$*-y5< -YnKL#$BQ3!b@6aWAK2mnY{22&zs#9Ffl000XZ0015U003}la4%nWWo~3|axZmqY;0*_GcR&wadl;LbS`jt# -aLT!+eQ|C50L+Gz&=QF73QID0*t~)ytRQkHX0ZE5Cqal99dJ79F`nfRs;X{{mxv-5hXP#7Mm3eOPo1# -=3KsW0Ng?d&cK}ND1WJBAHW*Kr>$P#+ftN^#!0`llemJ2E@^C>m$YUB8chG -zD(rGh3urC0a&cetj+^-7m_TIUNAW#;II#JqhYN*JYHq^t}R-PQU@WsqknH{wY_Ko+tPkE(p2l`aZhl -G#-t&}-uBsCLSG0h|85Os*`a?MAIO_7I;5O5FX<|1R#|U7b{+6We=Olsm$YEb`Qpl%cK4bIP -@Tq_$!aJp!w$)>W;9k-aBbI$;`~IC3~Grb!j8;VcUXbfak1wXY2Jx@T`HqQuKtoW!2|*aW!=m=ZR -{Ftq{!Sd`OlSG;R{r`%G*pr1q1s)jo_InwPh|5z8W{zfeE{a9uy+A=O&-4T&WO9wnr=aP4K5k^bo(5UYKfrpENG;w?gP`Y~$nf8nJ$628jQ3AY -`$wNm`URYbo*0ex@@OrVDOw&T-t+sqjraSEywq)(iTZ%?+1caPJxyjrKhVXpF|}Bko}v~CNcy17bx4p -hyR2(nM+#cEyz|LaJ{uo~`>7eyxRT-1Y%(|xAgG%3wxmUuc|+<=BjQPHY>y}Jx{#;Ypg!uI!utk<*8Y -O|<2H72S1$N-gWy0d*v|*U%3y(QUGaj>Gbi$4C`Z;&DICy@Q4`e -o^H7?IA>sTx*iR=E@qR21;F;kYkE*@`@Z%NqH?q;zd)B}!Bodn2d8f~$F>Oe?r{Av#eva!HNh)Wfxit -3=2={LvK?a)@V8n=*DAClrkUZhZadGR<})OF~^lyaR%+j3Qh1+`Ltf)RyUqJ)8C;93u)P4CKt9x9qSS -3;EDt=?Q0ho1O=}wN)kS@g#Oe51CI%kOphXXPm-!Osdv_A#7{&#*s`l+sA(`(S3R9LqiOLtrvM8?Cz_ -FyZ_!t{64Emgpa(D-!2uq;D0LCL6pb#_`e5y6wiG>(KBNb97?+wMyRdZ+}8VH*On_>e9-z#Nt)FuyaH -jN0D(6vIdEKGsN%X6gA{qX7O;n{n0`N*g@Z4Lga`^W^>Q4UasYZ~k%1&2rytKL`8lB<`xbxfX!kh8U< -*}r&%p^VwY=?9WTnLpoZHHo`q7n<+gK+&gO&|ZZJ(dxb}Ak=KaADu0e}xOXu6?H%F#~ -(f;kR(Qdi{qw5-MpA?F-t(`n<+x8ws8CjFtdu2uq93>iEieWmqD@Tcg1QIS2aWl;1iL9QB&Kw8eRFB8Iw3~}gVh6EbTrH(NSM;UxM_G6+>p*@u|j85NMLn7x+eW0aoS+#qE&oof9ama{f;y6(0nfk`2;>iNZaw)Vqr>^eM{1>Fh?4*pVz8J -Vrf?^ZCgxXiM&sZSMXV7vD);Iypuwm}WpgFeP0=^AlVzs16r31FTF*{0>ZATyi -qX!Oq6;mtifGV&G0&i2vhhjAT&xviA}DIQnChjAw1E8x)&4cQJ_L%*f)$`Ic#@MRS`G&riR-J)u=-= -DU{W(A!4^jvtRq8YksDA;v)`c_MEmU#-r`k&_1o4#@iC5W+(r|2Rbyu=m*_F%EseF;?*97<{Aiq3QMu -lSAUKwB`S-ss0a8O9KQH0000807zB_QyEVH*P0yw0AO(d03QGV0B~t=FJE?LZe(wAFLiQkY-wUMFLGs -baBpsNWiD`e?LBLA8#j{QUFH9PqbnscrY4e{OZK$UCblfEwP#x{NjdM8<06L~kep~Z!<~m{?uYyB*AH -L@z+i^*ZZ3Bpj+Myb4A4L~8jXHJi#%J4$z)NLRW2tJ5wAB{UW#y5WJy)Z34ee5=})n1)N4t7b(uzmuhIBJ(`UMOcU%dVGOjy$#EFEwid@n%?pQoMxHtP -9HxK@KKFtc?R=%{78PD%S|aR=_$ch?YMzB6YsKAA_y8Wn9Q>zk@GUn(n7;}eS7==6q)VE#RhPYFk^x(^?)_{j~|UR&YN(42di -IWT*ROCtE!BXAXmWj`?#1aHj{ah6#y2$=?0TBo2+0$xLUx4uy%?UgQYCrz^^hNP9|x%29_RSqsNctNm -vv>y+sn1l8KlPv)Qk(a3jSCkzBx5h|{>7OooL_7WxH#@Ov;>#CcIpfX86S+q{zQ`zS0!cr_ag+&3^3y -ud9IL=qPWa4F#7kmlD64+w;1nX4I$1tMY2BbTsKQ=ys-Yv8J-39K1M!NS>@u;PVCvyvVgPmNLVjfQA+ -aA@K0ThGkEcStiZAsS?RdZxzH@7kanNHPLy_6=cnix*Z;2dIB_Uxi5_yBexxW`W_On=x9`KuI9t0ci- -JFPg+2ZaSoAZ=e5l^5Mnh?Ttf-Hbvb9b9jbPb)YQbG)xj7BoB3(z4zz8#~ZcrZh(2EvHKX(tIO+~+sW -IDw=XWPq5ly-y}EsUajl--z~f^jUp_p4^XBTq>D{!Tmu&N-L0w6I;+L#5?%u0i*9Bxkauo5~uz>PwMb -OD~@qNGe>b(i!zo&FQ|cE67dqY7$NNUK#4rlm`f2HdM`r?bCS`7Orp`Gz&3s2dD>W+H -`0Gj(~vE^b0|4@@!6UZ2T8VRjjzVXta!x^UT99jYu?xWz%bALVf%5%`Kc^ -smyVYhT7W1!!`iCH7VL?TAWKAHGa?&zvH<#z+-99?riFJX1}&TCb -3q7o8=y0wvevDske^7Xc?1ecx(H27-zxd725r+4T#NZJDFHGjA0)HdZZU1-M3*L6^HZM*caOv&Vy4L= -XAO%%T2(ib6^fS6|<_O9Z*}&)9EaWcGD>kfuScEY^R9m!0QyjzCVoQ8lP-el6TN_it7s9K;CU+Uha^H -s3@QX69_m=G(1Kf-zG&S+!-UR_q%eH0V9_%0-y!k7Y>wscTk8^Sc%hVoJ|=Ne5(>Urn$}G_=3sIQS^Y -yB7x=+`gc(9gb^t#EZ_8=SN`oxd<0YDYwHwBm!w2T1*xnUln}g&<*<94ZKN95e2_Hc120X9*Si~ie5 -axR?Q*4e%f*zDq3QIjhmVa_qEybqFH(3F~SX@G110w3ZTToa9tE4Wnu>bQ|76yv9w2<^v?_xfc0E@Cl -=D(^u0givBJz8Md1lRa;YVaw3w!qyuuwHuRlfPB6DBZcp6!4kXOFv1-foDwZf*aK5BR3GB#Le%}D@IO -5CDLHT8R(2Mhl4?^E13E^EX`B%K1?c!`%0hD>@QSIF;*rDZka$_X)2Cc`)8Y|eaxO;y}P}5cRP7`aen -oZ?f8!@-AU6U89VsYBghS8Td+cTfov<_QLA$v&r7SJBWKQNzndzlDH`0jt$phbx -XH4_ebzX&-8buE={{21!hP)L+cWZNS-pwtCm^9$S=5HjZ((1#ufnR#*gb5b+&GjJH^pEp;b}CNL$zFE -$CK~1U{qV+9`&1nSlf_ry4djbxURp5*#r#^`o(#xI0jy;-<CBlKv#c-+LSg|$4d{FaV5|EtBO<3($0K)cqnHna&jA||MsG>*!;0c;R>3P0 -VB1}hUO>u(Oj5+8JvsH#$s5+pJ`>&<)qwgByciKW#qTP6-n@)HZ^hA!%O_fePu+n&J0Q5OjFyrJh -cH*qh;Y5^mk|RL_7z}Yzqf)q0hfLhma17a+lB%1j<`lEMUpCZt|luRn?>ID{tNc(=E!@`j`0xU}{@m? -N1CJ4F`JAS|P$iYA_0tY%4AA#S`%|OAkq^OH1pCB3ipsPi$aul4`DmK(m6tGH^K3>b4io3TKiyR8b9A3 -VP?}m#FZwDx2Xy5ft%Z0ZUZFd|ap15kM20z-w7F3Bpg0P?rDamjgZ2*bi7?A6=$@c;$Hk_n8_{eYf-z_r2%{ -ckn?>w*Q?^wD>GE17GhS%V$B(=F!W}VdntuJh?Ez3OdJOqECKy1)u_A`7g;^wh-Zc7$@kO>zZ+G2DGKP_BnAATb2W8 -)zj|)Fj-$IGM>1~6LMNM6DQ}`0%pwHGfbUCDY6txbVPziH}eLA;mDKmJv%1VzyXiKqy_LvQq(d|d*X1 -3tPn>7(UQY6xxi2iI#Nh)Ohug}7PLDj*)jmBgF=4TeoJd{t>>FJL;%z&*628QP%;fVz}#wmSO;r>^rb -=^{*#}HbCVr1$}El|&~dv!!8W>nbuPX?d3FRq=HglKEI0``%8r1)U{;E{WIAL*#pxPMVToGvKJ5giSJ -U&}7wG1lXr9>m<4@hJ%dPj&!@lY#S<&Kaj=p{$*dax{|+xtW1XfpwkiB0TSP*B_O -H{wGTD?~ozG)CV(QFKHpR1QDF?1s>k%_{f>3CK;%aGht-St<<`xRLmiIQFbGu?KlVt;EWX9g3fUvuZj -(6g4c-!L`)8O38hT+dxrl_*F3)h_8g}YcW3_{AyvXFbp=?#*IQNb?ZNHpo@+Sn;K3#JFX-C-pKnO#8C -%L9jK-Xc8=kIytYLsBv8`wk~)^hmTwG9PB=reHEcA{4U4f@aiXo-)EIG6fItlxOn!d%@9(ZYyzAFYwH -FV0%dmCYdTJ-(Y7j>bZs@@$T(n>-cv}@@W-8|c#XmyjU@@rLm|Vk?qi@mS{p|=%oa3V-@q>0c0?|+4I -}Ks#2^2AXeewL|z?o~k6h|HdOf#LUkmwk3zwIo`!)il2yY}^=hbf*_r6g-jqL2^sU6;o31o)$rr&@^C -9vr2~Fx60Y;^H61K+m)QjprWZ35Kb(lr{n0)B^jYd93}JHT*suXP+CXR^v6!AkX|NPit6hO}jCX?%d4 -Ug=&TFUBK?XPnvkX+tf3Z>B{=(-_KIJxBRck=j9vC5YqmhFwq)zCwbakKXnTH8W~^m&Obs}hN7l2xwy -W*x}KcBd49u@s^R68vR0csMuqCWz?dK8Q-GjdRaYKgL<2s_8z^=eIemXMM+fv%yWuDcvvK95*x-(*wP^ad8+Jn;L?&9B6au5MX+c3&PJ -i11gCE$*8D!#&qLRI=yjsY4^oDQZE3*s_BMZ-nOqtZ#|nJxV+2J>Ym)k(ls%c0K$XfgsZxZS1q{CR~< -mA0#wUpsWO6gZa-4)QL<3$qnx%aj$ecLR=HUn;r4JK!FkoK=fHcAO1dA*iziq2E)dpOZyqwr;}oKe<& -}H5Ey8Oy;O+?xW&4HUg!83&#DuOvHxsftrG+vB0Pnn%ucO)Yh)@sx)BkL30bilo+G$hVuYxkVf$o+6O -2k5*gmHxUrI3R`GJBI)$6q@^4<@oZ@nZW^O~2hF8 -})W;#6Elk|gX_9$?r34_wLmpF%M -U^}7uyLM`=|~%+yuv6DG=hy+fs`3_P{#D{`lPK*okAf4sKr+IZ{*4c0l|XQ|x9ayR?QU2%pns&})%UW)#c?Q`lfXeDn7CIZ>B0sMy1wOQK*T5Q{$BQ%`*;TZH? -cS%;zJTDP3=qwaNK4-&Iy;ke^E*~cnQ9HRAHZ`eG$lPR2GIi5-|{WkU#a0Di<1qd>BxyrLGOnO@z2;q -GeN6hIYn>H?#D%GY)oa~&bTJpdy67*M2(WGGTC?nxL6a3Ba&A`TE+8wEW4=T>hP`B0nK{o-9%uV!^7 -j7%9^!T$h}l<|gCuLp%OPT0*xQBwoi!m?Nqx=G2uT%h4v**g5}tn~5-rVx(7Sr1dlj(5IN|ZOw2xCHh -RK)*Po(OIcExsDPzIrPr{X*VTMwFlVV49VZtcYiKWb#B?CXMInm27*94w<(2c0<%x(gS)e>zgJOri?t --)#nk3>wajH5Mgq8M1l_WO2dYL`Q^xBpGWKuPL_9s>wld*{3JC_0_0?Ql~oFp5mz(uIVDZ0xM`6?+}^ -0es(#EDC(myYY_)Rzh?dXgQk)grF5?*pR}K!0M&V+PXW4%}rGXjN&cstN+PtN>RKaE#LmOwcU9YsJO5 -$P)AOVPpWn5&!8_)m<7h8D4?B%sJi!BTuKmoJQe;{$Q+X)UnfyWF^CY0V@S`%Aj^Mwop}$g+?)?_<0w+m!PmyqR8>Tj>XB*@rfAXbWXqdW>zhWfPn>BzWgRGib@`Tck*w4 -7{TaW@VImc#TqDib01mJ^$GHt;!ISJOLlZOJdk?%nv3=n0TD8QpvoW|p<`KV?yU7QU#tCFMSrw_>PYL -ZwW(J6r!stdqMb(`=b-*L+5P6H%ZkQN!+4l65iL2m!$+YG?lrEVpHS7<%eB)mNw#P^HkI_2XusbT9`4Q?|b<7b>twZmn$v<}*w_A$blqb(Uj-W*@!Vuufjmbh>*h}Wa(H -55=;%Whnw!^_RwV3;B&;_I))@poQpq|@+tu8Z`tysq5CNE|DhbTo5pIDn?eZmN(Gvp+#$EMr6Y*6J81 -zcoeWw4lmaXh};Lhd|hRwB;61#^Y~fn4q)6z!x!5)WsOIBligs$FB0Kg>1=SEs|_y2mgs8GNB93Vd&kRfP7+^puoUWAjEQ9k!(nUj~qOPHnNg?e+DWyT8_%^smmDaG$6xx*9DH+;Dv= -7@I$b4kF2XJ3M@b~INZ@tsjfG7bWdH{s~5-7Q@Fx6SGiu!TV3p%>mp9)y(;|8RSjngHWdK#Kh8T36FM -!djoZ9xU*&<#^x8b}Tth)xt~&Ag;)Jfv-G~%e3q`Nq%7MC~*3;9t2MtBzBCL|O-qKYbWc3<(u(Ne|1F -I~%i{-DO5%iA1{P_|ro(ScU!mE=|!>R8CX<)L2)>nwcCrO7^?DN3y_vb&vk8e()sljyxkVYsl@aU@}@ -z;SoXe?bUVh?f3}5PKU)e-HGaVObm9#o_7)AhLKhOt)8J -v|-EcN`+M|DGi9AdxE^LI_R%PB1RuP0CR4>7jrfLQ9th1T-ztp;8yvH56SHNFQB<3+FG?+ggkzWn0%X9yDi0KAK?G3r@e1E+ILUs`*=LXaAqkC`2q -h{#W`O10zwwA{ZTjmIBt}dY;}2>>u1VL9SpPIc2G2QEVUec05hku8lPdq5oSfZIqGWKN4-2d`*_+w`2 -+*vFJ3rxE6c$5TSWbdSeQIs=u|Z)pkr-~1P;GKIqMCxaj#0RLopvxpM54T)v1sc5J9#i!`T$yK?ef#R?eA{U=u!udWHefu-iM~FduBCHoKk*h& -jA9>PWm&vLj~-r2-jvOUJoUQv-|WrZ@Sb1gk*Kq%__A|Pfv9nvLAQTP$By)OGLVf3h6-ZfV^hqkX84c -Fv7Qb72omFX^zq0@j_#<-wJut~G6;kNoxl5n8i*&lWJcH4;UZJ2PaVYt%WMX_An?t==lZrPag4jql_b -GQ+6%vel}gmYH{P_i{wEc`waQ$2qhz{Ey%v)qT*yhCMPQK8o7icLO8<7~hz8V?5sApG;Q09Y^_y2hMT -lkEB$Oa9FHyVi&!BT2QT@Sf>LAUP7k;FXw)=*4pB&<-d#FQWdggl80{72P_IIQB!!U(|hawMv?Vntbd -tiMzTmHTTsLfV$-maohp92p_%lU!~oZhUPFzrve@#Wn7e|F99?QQN)_NcRjujMw!q?ppsE9n+dBvg!+ -4_|@FE3Y$&*>_l>;+bU2cy6EGjdAZSSJ(Nt?w``|S8_DQ3uScbI&_}}!%jJI(7Ms+RQEeTIO~{Vly3F -&$dAJVo%4)T*IzU7p+=V!HYIvpYA5Nbeta)=VI;c`*@u`~dMDoz>`^a0*f$RzoF${Lgqrca>Z(T7LCyCMXH&BKh?K{&M`_f$94(&uFM)Gn&w*WP)sIxV4eH)GI!r*>%0hadctk*KajQdswwc -)J@Ivp0>)9d^z0}Tm$3ckPQyLBkF?LYmQ0rGe4SN8F0X_#%50zdkmUMJk_ACv&?2_ZQ_>9dYpCqDtyZ -2Ch@+{P2^?mY$Y^91W~&Xw~Y8Rz}({m#tA=g_83f3Ir?eUR#!tvYlHF#p1!0pQo`c)2RS*03;f!UrXh -Wr6AhmImKrkQPi^l>6y!8@il|A9uN0HEKOX?MUnTOJ5RKFUhfF9NA4D-Jo)*qw1IZm-Mv0Br0|VPw%F -ApbcptNF`aZchmATZ?FWvh%q@pr_7^zNK-w)xgK<&-?7WkNkg;5zrKY1-LiG3ze~0coZ?_4;s4Rd>LT -~$;K8!`9}&Hc8oNZPw&(t%Yju9%!`V(-rKlBIg|`8d&KMV_mZrO3F3kIexp#9xv(>A<>#wssp`NQc)rG;J`+5Ef# -;l?nrq0Ai!*xP8Qqbnq=?W@q$8&qHC-MtiopJ#_!tiCZny!J`hx1G7tCVLMG8+tnU$ZzJ@_a|)DR=&O -^a*~YzU{7v#^-t-ACFIgw!MeL=WbY-4MkA8VKk(yTY75sJ3`bp0H?y-E^v7R08mQ<1QY-O00;m`Rt8g|aKs+I0RRBu0{{Rq0001RX>c!Jc4cm4Z*nhna%^mAVlyveZ* -FvQX<{#5VQ_F|Zf9w3WnX1(c4=~NZZ2?n#gjp6+%OP@?*{*eL6>e|v7whjAcuuGA%|{*vuzKh7)P45M -P!YT#%}lDSK91uz1z@he3LZ#=IOn$5F*buy$&#t8V!Q;G--u#jjav91PU1?1NR6k=b*Bkwg_k^?a2;k -xyUn-FnOj2N1lN~TI89+E$Gm+&f)&j;_5ojAbuWs^fsLtlC7Cn0Qs~ZWvKb~+rTEYRz1`26FBOqF=+^ -(w|mL4HeLZgTB~gb+U|F^+6RUXE&7%qY4(pw$nn;it!#w2)qBrV -~2WYGMIOa6|s2ZJGM!N6Wi))Ouv(4j%X>}Z70(`c0az+e$o3PAQKUtpVzNnR&jK!l#zh3m4EhDKF%M4 -iDx(oml4DHX|329AnaugatPlU0{t%wvdmVvfZj<{x79_*kv)AJ$b5i&w&4`cqYZtLo<>^&0|XQR000O8NLB_@P-{}3hztM#R4f1hC;$KeaA|N -aUv_0~WN&gWb#iQMX<{=kV{dMBa%o~OVQ_F|Zf9w3WiD`ewOZ?M%}4V!BO@B^g~czk=@ -Pi1Ya4pc__^dP{54NOC8m8zU(PS*d}Ao6f=Lsomj3cAX`3?niG_VET$DYCz3 --E+))^hz-QO$Nw1kAN%|f8MvmBgo1tUAU4+M&fgG3nCpsz-4(y3P=+vz%mFDxHi!a2WXTe~-YcN3MF! -kZe=x1G_stE68|`VH-P|0qn2OY57w>4r!C*{!A&bw)v-9}t^?7{#`Q2a6m)G%+%jMPO#anVpj_RsmN6 -6<*L@w62h=QX6AGtX|jeN-1JqO<7(UVQNHd9W(LUYC1B0!}EfK*DWbUd;!Xn7w2C7PNj42ojSH%+A+K -p-}hkpMuTG_ORFv!W(Wc`)$=>(F?ll64%fn;MK8$2KF=l@wW1vsiyeO7n&b_c0TjjS4{X{f<@ze3y=I -6tVk+nSeD!Q*C#&?|D^;YJT|svz~88KGFLxtgiMx)m0^Gk%-J6yS~2kzb<*sz$kWT=0quJatn5ok>vM -LE_U!q#}vG&q^m_R_N(B9n`Sbtef>p${lviZsr0C12}(LHsLmHN=7^e_XFv%$9k{`l_WN4PZz+sAmc| -Zy<&Tn{DlDx)UrB%?Gh$DI9G`_b+~zSo-LkjkJ)Jo{`ldYC<>;slQulon&Owi -*D%rqTgEuQ(nPZ8Th}DHKQpJYm-N8RUj;HKw*}uIuGca>(VJ9`>lS3$(R5g-&RhS1iHus8Z4NM07h;o -g{K4LoCY(2&Js6RS~cCb_KwKoC&=V0)D1EL&oWX`j+LzF*4vg#Z=j*`lJWO`)m6O$-BF%l+KPNCn~Ce -1<)yNU&YCa@RO`vgbF|R90l{=l@$PkSvS1(D2k(BB21udEgn-Vc718p);%yraIuql&zsa@P -gNIJUxggS+<^gT`QoORdRuu!W+hH$6051M>C!R%HxDpHD6;mvBeVVtVd%Z7F!MePR%)x+D}k9R85cGpMN;}dbw-|5kQ7jMgkGqh -@Ne7|UBAE5PD-Ezf_Z6@B6Qq&-X>I+?G){#R^^#uV#2&e+X(XVq+J9xcsE0ONQ6!5%+Q8A6pLvLdpKQ({nPL38*4{euy^sXef)EXiBv)Owoevupe! --BkQy{Vy?Wkr(eqk+anW&R=rZ#c!Tzs*_s~(LJZzf^jI(s1@YF*W -T4~WAh-j9Ow1-;?Qo%-;Ee`H;yBGtLsrftWnciEH26IZlz)M4>opv62Z^Sx>ah9@FRURzZthZA6+ZP- -6EwF|BFA60er1U|~P$4I^5G143hE1@L!OncjW~W^%JhNQlb10d%GjVIp{jvrnXfnXTG&j<6fTCDp>U# -AuUny~+Z|c+&XON!pS)XZJo5$(HR(&t-3JjG8ZMpb{c!GSF=! -Qoi_dA*+mx=~mZC%>q@`;^o-TdbDBW~^qw_)wCuP@&n0`(Ey?cu>A7BxYpdy)UWIa9%Ow`unwIt8DS? -*LKX+3HHz16IJUE%qvePJ&)8HMOr6af>vN%MQ<7A$Fy&r+{{(ctL)IYz@7ujfg*YOL&|Ky?YLeVoR<_ -m)~H@)Qb&>z|Q-?Auq_gElY0IhTbhzxnmih6u1pnA6Kr?!LcZuV9yV7m576+5d?g2q2Ni_wvdEvd;_h -;g1mY8re^{^W|O!elaJ@iiSH`=beorh!-DQM;zd$1-1rQXg2Rd~rD<6gEy?F3#+$B%?sxl`%zAQw4#} -2b2LxBhc)G`&zTfOQ&vMvDx0LR)y_HgCjFmB|qHO_QL?3-Eo+|15^Xa(mp}b)L9B(d -k6dWt!Ofxa`X)co_M-I^3I61RBE`ybPd}|aNY`nYTC)7+Bk?5pglfA+Q}@;qb9x$$EgkCzJxOmR}Nd9 -hw{cVvqJ#57Va@|Ik1O4lOI?QhSSsVJBZzWxT^i`0A7PlR1d}Dczp_1AIIqf7@Y+hujt5NI#3D^44Ic>nS29Ds?<2cCnk@eG}?A`vNOM%vUOhZL5;)^tB7tEN^xSI7 -=qFaWC9>FYN)UHd9(ljC6*Kst6*i?)7|@i4~VbYiHFE%js;76eea%MuE=QD)Lpxl)$(ule`xdcU+!EN -CIuta_sGmb@kX!E8S>d$FsI*R4~Jq*Z9{Q%l$}u=)tEOK#1b?j7Dt6h~-$)&7d60>JF_WqPu0id&Wv* -n-ojg^(UCz+Q$vw3ns9ywsT($ui@h=)BX5*;$ds#niD62nXEIwcIb*jLj#JDzlD#3k{;;fOnet{k(sn -I1O=ofj7RXxw%T2F$V0c?nHGvNAu?`2Np}wz{C64P|EN_5FN@B|Gwq<#dhZFEPUQ -9+t$hvSuC65+IFIdi3TSFP>qX?f#|s7je)CABa@u5d6qE+M%)p=9*b}|ET`{Z?2eG0UZ!+w?j#?9<#l -1}QJ+S}2C*wYJsbil9_VpV`2TexZve0+b*t$bgHFP#su^paf=y+DA!bAnRGRxu6#p*G1O7?`?7Y_wJP -O=LG2h;7h9sJk>bPb#CF?#nN&-1M#SIypVo2hSH@Fx#3haR)D%ArlNc3b$@H?yGeu+5`IggQL1=k<7j -=6~!;1JY*j+Tf`fp^MARCR_3-F5r812+;Sttd3HSke0s@-+s*3W)HYeq%sAiW@`=+G?RfNGP)h>@6aWAK2mnY{22ccFF3;lROH;XC6Y_d?&CMl_a78PuL2lBlnWg -9LL=ZH?=ZnS1>rFMd!jgmH1R(~m_9t?vy}`qAFv0nhGtK?&D7wle(TQ%21YH&uu -P{(3S#Xs;LX4qo{Go|L2Qt@?3QfD?4mNmIkTphmElg4_ZGfBb_QHI8{OfVB^?9*^M_B?>92k_EE08NN -2_mbHTUgAPby;R9&2g3kJtLI_fxHHuU-^4iGlO$qDvEJpOpIeHz^u)HQ5fbd!<@2{`+HH!vXJYap$KOT;?QHi#0ZEZPTt4AFr=oVpnmfr1n%vV?yA{QnMN1CTA-%{ -s8vGMKBxPcF^m|AQ6dv(8|rv`NgIsNJdlno59hGR_a&z~+qR#c;7M30ZmkO^jnLCjV0(@}%glZ_wR(6 -TQA9c^?2Ovxpt*<%yGcOTxLTwLAW(k#URR#IimIKGNar)1@FRn8H-3rUG50!i>DzThE81{x--pLrP}Ox|_*efQ5*s=o>p5)}}{y -JriVYhSYTuCFh%vGRnbHN2B{#CxA<+jx`ma?01o0-pbq -qbZq(vO+wU?-q&B<8o04m%#!Uq1mvBb?5hL@r*JhmC+J)%@s|}6&$ -ZHpW476BUOS@0Jr@C;3ypeOHlp*)+LHmPfAvmJoin_EYmTiZ=WA(1rD+-08k^tXoHs50J3?mTf~3QNZ -LvXwO$2*44To3rvk!}llf^uIKfk^{Ih&7m&|BA9huvXXc%P~)YhX-iPrrE^cgYCqlpJ|y^M&Vk!w6T{ -S$3_YN|;sav5`;!Fj4rZYmvkhk61)zgl}Y6I~t9j!d>|RZI~%7?g~0Bug0q9s`)C>7vfW2+*zI!R~n~vT;*G^2&Yj1=4f2*DUktFU`=6@}bgN8pTXCJ+;rC%ZyB9`V(ax1|K;3g6KSL@V{ -w!^lt!?@G4I}=R27hqyjvW01P)h>@6aWAK2mnY{22*AUDo*7^Of|TsL5BE@#3JLV|^n3a-?Dcv_&+aa#Y!eqNHockz$9b7$QWb0=6}# -CME19xaKD&@fA~&p9iCnNa%?nkAMJ&^t#S6BTCELg{iH@En@x5S$WDi2ci!DRcp-@Gz&t=$01YI-(;xg3|D;bq -q1tAJTq>Tewg|V5(|BF3*{T29|9-$0O0HS9m4GPE6TKvkQtpDj@=pw)i>!}Syp8~J^AWjPz7^s=n4%(A7Yo!0^*<6782 -(r+*Sc1{7Ic~<@-re1hn80XqpONjMkmewBnWASg&StYbE<{-7gSiKp%&9Vd;1V7L_=d8?e=h@8CJR4Xyh21;Ft_5ucU#RU+f5N|bP0?Ymm}x~b5b=(lZB`;BqqO$Rw77 -G|m8iX+tolsb5=s=sXCT3Kz?)WFhmcHy{=hw09!KChiv=*tFwIF?TR6TLW0z$H -5ocw^cSKJ`01*vKT7mgt|haE?x{&GQ`MkSOdsfz+a4r}UVJ?*znXD9geM3wgVNlM15a`Z&)-h{7CJPU -gt6i6&UUsVL_dqdMhw81HM1*FnNYkm;nt+0XawnMo#qsB<5V2!V@Si^30qec_mLB9{=`m(_O)y!P`pu -LKPKWCL~)C)L9`wJ}TL&(%8w^wE6n%bVNlyX*7o%K#!)aDF)%U)>@8Ab_X{ZZ~2ddmRD2H()*SxlnNU -28g+O{s|Xq|_Ks&-WM(;LbvHKs!rUQ)z%~b=Wn4k5D}*|Rqz{f -)z!z9Ygh-fEt~z4>&{`lSUB-rPbin@}UcC<9jql!GzZvKy9b$NV5&E>d@Zq$%h91>R{z)oc;7J1ES$V -J=#8@G~9bWhPbdp&R2OEGAgu&Odj<+L+j}5YD%_open;DDfFj1O?(}QFgm@g#EtZI|iMD`ToUOj=hS6 -@Zkt8U_6ImCe-=0yay8-Q~-II%pc>=99)k8kgStLv+A(?otA-%c)mp%;S|@b%5zronUIys%K^=ZesS0 -z)lqN)&HQMUj@7e4;ur+R=3p|mAP(B9`3cbFCAubwxRk$mjD!3N6hkeiz5yYn(Qz4#PW{u_?`buE;Bmq+NdPFBL{K-|n0_dq_Jz%5t30X7ZgXoWKq>e>ohtQ -9I8@+aP^}Lj@&%MCLso>TU?0w`ObnWf_%fOo))cF@Gh*8jNb85k0b91xHKx7W6};{Fk&*3FOJDcw7@C+P#V}U -K*u29Wm8u>*3cO4~38e@+)#UBcrP+HUikRqA|5K@^~Ht|HT* --D({Pwgeni+rp^Jw~9D-ts+w(q)@ozaQsrHG4`Hd2c?@T5KcDm1`GY;NZ`B3QUBTWd@=#jpj!0V2T}E -Z2^_))a#9z^VhpwX@S~;iA?ED;-No^b%tPk2^i7P-fwi0Mdkq -;}0IgG^;4F=%@o$3Ku0`F8MX0<+*sp{(q0q-rrP$xX_%#~(W*>Ff24E;_6qb~4a;g+7ykVu!7(=2`(DXJWS;;1^czkL5X~UO=j%S>h8F&>6#5uquBnVepEzeTVsM`F$&RIk$l@`;j^Yr3=2QdDTGDq~ -kkBLYvG#h^EhBp?X!Hn#@9?!!#hLY$z=7?0Qx{1atKLBOABLopjCH%>otFw07)^iw#_ -Ct4?o~hj?GZYDwHgjdQ^ZYnciOcRXpzvdnjV0#|_(h8+>ZFF*4h+>IxG9besS##l&j@!1*@!O`L<=aU -roE=Di-U6IW%9ntbi*Uau?`$3OPWt}QZkV8@gphX@_;q@W_g%Y=Zu0fNv@aQ`zoG*8`LNZlZV{(A6{DLwo_3I_}l4jTt)NXSDaa}tw_O$o?eIiw<0=g7=hYH=? -yu|zp%n)^2M4mWNi*K0M02M({4lQ=0C9B&&W0#vYoJc@KOJ-cF6Ug@*5{Jt4u0XC5|;DP|@#l`d7Vq5 -SW6$SAx1rV8`Y^sq%ziZT^>lh-fPKEtFnJpz&es_k^_o*k>nD7vIl`>z+;zE`*1+2AjCBbaL#H!r})^ -Si0Vx1LR$Vc+R-*MWHpBj5Pxf^Z!rqn|+QSCpdA-bB`gBAh@=FcJ(iYLhC-8K^qM3f6qG&GOA)dOQtiknkxPHWRSE{sPHJmnFa^VCSwh{a -ghP!xLp5h96nZI+z}xw)?Pkz%y3mz?HsS+$s52C8$`HH~mhN>2N& -rwn|xXhIn(P&nZoCGY<{H%k-&rQ+Xb`I=<5>DJnVSST!No8aopKR67M78n$Af{c}At=M^G@z_;J0JW4 -1@XK${iI-FO8n52=}q><|Y0zTv~5K~eEg>Tgj0IumY|2NgmI6p -`t;_b>D)7Ox-Fa)VO>9ok&wAe?x5IvSzm+^Pi=SO(RnGFHJAG;Ql%azR}jwcW^p+29j836`vgHbeN4im%_;nGv)?_f);f0(r*xXkeG=z -S3^y8z&J^WnaSyC-Um2Ipg7ROHcyYRoCE~Ux??+ci77B`Xn}HX4At!*C___0HhoO!t3n4a{|s3*+zKE -^1tO6}Ldjd&sH-HjY&o) -{5@=Nxk=&%<_oL=)?RI=Vp8Pz16HMQ}zk752;p)GMuY){%fD`9d@MsSQ7|f}^zTpsBF!Cw@_8c!7G+Y -WeG`AGIey3hY&=#b3N4JuAgm+4mzSV{ABJ7;>`cGrg@#{Ud*(jtgr+7sXFEJIzP%A|F3OtVS5|f9bx< -_AIALq}tpXRmDw4<7Dk7OdwGP|IW*@BIft4BmkgL@kY+v)E&>|*lQcVjd*oP@hq+JwD9nO7}Kc!) -)>?jFSLs=zhUD)72g=66@~Rd3YSI2tC>?MqcU?!xYiL3>^FV8XD!Y^db|E`@DaY*HBeoX -06wTXe_uh$<*oU}nPHb>LOqT-)z$gk$6GxV}3D`RvTG%>sv#?lsMcxF414tU*ER{l(;ReD}-EI5?YLL -3YvTIXhVY(Q3Y#0YY!cJkRUlk2YkAO^%*M;oIp2z<7QC{Hi~|f4Y&JB?T=VcFa789%tP@T|Jq0{K49_ -tq>&(8OrJ!pWdZ;dgwkw8)=u}eAhA@-LCj*hiaCjUund2|IxW_{P?}+ntqGXSp6DmckJ*j^7uC~IzD} -xI9gh8Na;d5&{0TtRW$v?@RM#;S9hdG-PfZVy(`~=c7bf8t9`F+x7VdVOc-A?UbVUOV%vzSCqlEC!84 -mNjmg(bA<54mh+|CG2x+b2X`a|$l3*LJ5Ng3gVf*|$S1x9=n$&6wjgT78NrFFBbMHq#sSRcwWJlNb1x -~Pb?!wxapV|fz7N1*JVy$!=Nc-(|(wua=tt|SbR^1|Rb+rDZM{vcqX3(HI7$xj}6&mxMGEJenkqsDiS -a-dmCf*rzHDrQ#EtsdV9N<7-g$>Ye_HnWI((T83PwELfsQT56<4?}x9hTd>?`7Nar5AX6@AQ78^`8dJ -QiH~d{@X4M0`ogi3kR9dYFCfV%{!OuAP(bf1-5HjzxrD%X2&`G)+-H#X8;EH%LpH>mm2ErjMG4216Y5 -mu2?jt{kt@4@BoLGcB=-(iR6)Gh{m~&35Fcw*a#;G_yzf`zFJ6*={~ri>X@#nmo&QD{my)s4Kglwx?`jev9O3WRJ8(zNk7bQ@VyqLwcx_3!JM#((De$y31xF6v -2XU#pBeP0zA<2xEEW;D)3iU8>yllQ>ZzIgvU)1HCj5kJ&U!eb&K%bmd-bL+jhLvIfs5DV+sUi(z57-FUKD?^s_Px+T_l65aTGuXZ8B`i;9L~ -@W@o$G*uz}gtA5?M29$Or5hknmDskwsUAw??%&)cEPBec~%DIPhs{a~Kc8#@F5j58yh@Yv}bOCArT5* -N0T3RR?JJ>}=IdB&5RG(ki{z8nd>Yq@iAL_6gG3@KIqB)X2zoNg@1Czj;A$$9&#LiPYUQcLsHKY2R<4 -?p-3=CmDT?pU?`Sw=Hy(m?tiyHF}frT%{ejI8VxsQ^vUO3!Sifw2(}DfWK?P)h>@6 -aWAK2mnY{22-T}$l3WN0010{001rk003}la4%nWWo~3|axZmqY;0*_GcRLrZgg^KVlQ)LV|8+6baG*C -b8v5RbS`jt<$Y~)+c?tT_f+LSV3pd6oRPV4JTuRfZ@jyTEGMdQET5%pZfYoCHPmAjR}*B7%n?ii24!MUj>uHo44lktWbD98bhHDwgS{5XDlyd;#x7x) -3l%x>`rE%sfFuz<)s^q7~v3B!H3(3P4rNWEfx{=qzq_04NbRL3khB0jyCnmtV2xDt(BOJ46ARrz;8I0 -l9}0@7-~l9WSH1rOX5%^&qnz3^ONabGZmMaUsTQnM@{EFJBbP07$Zo);Xc9um|u-T8J=M(=-A1d5VLn -0T6w7n#4P?4R(k^Ci66YkO+_G1<&q~UJQ?k19J`HLS~AT&|_0XFgIw6xUI7k23u)lgW~0jvI#>(npCT -qBiU%ZzDRn-D=1*zCJCWy31+p)3z}Ib|JNqUq_ZSJ@j8F`LU&z9YfXqCj?=B2^Gw~ILIU9cK*>3(Q2YH^y}9Rnp+4iTWIqJoF8q*$hFNt4HAx*6Vx@4h{Sg^FV#A7oN&0I{7Q(hEiTd? -T5)b0B0Pw#z77zI?HU<%2(fMz9E(EN}+YAxx7Zi)O%0^Gz&0@qUAd(|Y7f+$M-+4|^t(rb3JIz`O~Z3 -o|4xM1Tv13ZnvG#kcU^ryw-81H8JAV1d)c%NOq8lhpG(T0R&r$Rv}L*PVKD!=A`tWSBVb9O9QK`MV5Z -;Nt8II|=wvZ`B6%)L>pt3{+?a;J#Xu -AQ_b67J;EBsLQ+qv=L7pZ(z4~)n=S@6E7KPd8(H!Wnc{WTR=&xA{qG7hvWWrq%N1;q$U6AXC; -EFH!9JeFX?R~P$sk?tGLTG#=!Qq)-P@Dzj^Y2luO=^kMCShMb_TzDi7fuCd)@#W0&^=_fII?&-og45a -^4e*Op=remqB(1`~lbp$xf_+;7IRT5kv`6CSYJ8puwv^!eLQtgN$bqayWlIuY_0#}6ys0WS0cte{;zmB6-#KS0X0E4KcgvycA*mJixkBs&J-AH9^nM@k`++81vB6;nj13(NKHUp$$ylE)uO9c`4S`^awbzz;?_~qG^Up!CO -N9q2v!9*Fb?fb+bdD|I24od<@8Jcb|^*@adSKV+vs9=Av*mD{N3q^FQe(l@#m?47PtND>Ca+(Df-txi -=Rf<7dkr~RbiN)>#ntH3XbO<0V;WV#8x1E2@zd~j@Dcv( -zaL$Vra!CoyBtlg5&Gr$R`kV9|8_bWe7@@6ikr{3H{;0=5V-)@*Q4vpTNrBiX?Q*LU}$(IhJS-U#N=c -D>I%nWfc?)fnOj6x48}J<-;O?foQjX*tBWB#d_M#n`|q!YJRZz(aMd4u>WPc~r~Zc_^%?^xHC1fO$ci -r?hxi;v?!$kB>1ce7vl@)Ar?>ED4<>y(E&G2NO@=+uza32gX*JW^F${!shHhhm1f8#k3<}r4UMgsUe} -A3~9jq>f{VRYvK?r6KSn&>8go_Ng+V>Y5w6=V|)FU&}#?t4%kv-HKR15NJ0kW@pM8-z>r_8b>E&ob$Z -yglN^6z{JNd)MGRb-p6dQ~hzUZb!mpKN7tpUDLxN7Dc+#q+@ym;={q7}3}AH3(v@2MGi9 -5dZLC+;Z-~^V9KQeC2~G^9R7b*Hhitca`BRBBh_}zJoNAm#D`AmT+XEMa8cAZ2;S^XoUwt!jHk8i8a7 -3FQX6ASZ0Nvq&|>0&D4hQXPYRV`$e4lo8&%8w}~GHegKwOp<9I5Ey%K9=i`|E8q7-l3J3~I94=5~CU@ -LQzl_sh?uT&%VxM7vLWvUnwvdP(sAK -BV=K(dd$O;2{vba3#*0NYJ>I{SPZ0EVMl=-9LG3i)KzRBfU&j&&BI -KfC(OgDxi93%C<((${f}(B>(~WpMI<(c|b|!ta&orQOMVwYj^CrHhP%0YL+6J1o!&R#p -d5A(1rgTe+~2AbqOwV-EtCM2ryB-A3l<`M$zGzLciEK;sSUa57QZRwC(yE-J!}65O6S4+IwbJWXB~Xb -VI%E&@YZ=YQIQ3;?~X5Y?p5*^Oj_6sb&>|6K|#gIpO8XfF^}@N)vxE3|X9PQflvG(&*sZKXDNAS+_v{kkYF9BLNdigYK-lggMOhgM@m}O8cr@IL7{xul88Tctt$nGT29kAaf2#y?cnW69 -rkUZLIM(ZAi^uv`SGfyf5(Y--37}FUonN%jER%390i+(Ro+!fPJf1;tDNeq1XpzaPs~A`)c ->8AO<*0WI<~_e2tbM_yOs0h@lPufL;uOl)yu -u$JVM04==MHsCquCqasc;;rEs{n!(`9NPO-I6S}<0fJY)-lEvDAd3R_><2tp$STRW$&Bn+e6D>IJo#Y -#Q&f4eKg4Y{&3>I`|f-H!{Cz-b|y@}cTnGxcR%R90Opatx6dB+_Ss_^_=0f`|Gj(b-;A$*J~@5+-GNv -i-2b_A{-@1Yk2!chc-HC~eGg{~)$w42jlPHS)05}f*7Hy{eDWOIdLG6*PZ;i5vwQB`o;9-rHo^hC|D1 -jHoIO^~5}N*SNaI8Ce**cRvt$SJ#-8<6Zo>N@SEh&7Srp%uXQZ%8&lFVd!@E;d)nI`psMpEn3k2FL7* -2l0=Mx;r6Lb5+yxCCI}WoF!H4)&So+H|^yhc^nuiQ_igFW>2yV}rx~d%^xEMLZT@F6Kc|WL>aP -z`?WW-#I!{9%sXpe}NvJ-Tqe~gL3EV>~RlGGz#x}hqO9+4AIjA5j}k}qNh(n^zPib;5cgO3X0B>C%F_ZJ>*zw -2c#DPQt);m`6$#Ys<$qmMdb%e+UvZtY@Z& -N_3PTK<8*C`RPCkeBONM|)uLqW)ZN##k$jf{Xu>BETD8=a_R(ecb -tIu{IQG%JC+0yB__NJof%ymY2ROiY#nPv0^jbqV{Ndfn!luJf)f;0mHUO9n4rPphKa92`Rb-X{i;NOVpNOjtvmlo -hJ~n($2Mep_idfKu7X$hFQ5(Mn=4q6QyktKM~uc~Y$2q9TusypnDbg!9${Z_$|Oyu`q?(c{ -M&;!Y1mUyZ3EES?1FM}LM<8#<|u7-S>n-v$wgjx;0Q?i$qXX-G#cP-v1tl$Tsabm-E-kT>jq=#Q>JM< -Eaj?R1Vz8dOwTsiW%i`dS?uB&m1ht%eFrWio|$dXb4Y70@G(gkmtCXEM*b&GRt!t@vi|h)4BD;c}DQ` -+4*a35Xcf^D-GekT~sXkx*gPM22$dzd1L6HZD2^NXsVs*SG?_Zx!1&;2=(OIsX6(MlLpSGl&@sa&K%0 -KGNx$TycaEZWmR(Z=|OV6YbY918$)r;KbnQ>hRM)oC}lH8m8C0(TUO8*SH+@yo8TuvbV#@aEjZ@eR(s -w8Mcu2QL^@DWj>D84>y%bjVDdSlDh^!{h_|Go-TjC;Bn1+3|ZSkl{&oTCu+Ti^be*kI7{8A2K0iug3y -+?zAS+P!D|TY*BGVNrf~YdPHhwT=j&}S-8ica6nIV%b3U+0WPt}({~zn_*{+Z|dN54kcFk?>6KJN?fj -;jpy4DigP>=rUdY{(ti5j2U{^+3eFW2-m%D-CGyWN$-V&a&J5+2QIg&I0h^GYE~Th8epb@l|lF`&2N1 -ELu8JtbP{b5=fU8ogc-LGlfslV%cA`|1E!8*oD(@GuY04^t39t0*s14T;Y%-^FWII*L_)sn9+%xb**i -{m6uNoBvyBMweFrd15A@%HG}f|FAB!G9B)vT;m47bJHzmgrNJM12B-0G6^vyA&wp-9jMdUJ%~W@Veop -+l8X;%Ri3g;YC18bG>@Rb45Fe;SqKCM8#w!0WlaMR%w?q{fR$XOnEH!(>0+xAMLf^jEaCrV!Q2x+%V6 -1~zOQr65=k?7{2t!Dd|`X%njLf~2S|gVh+AlL2}pG9)_6{Dn+YxbzhENa+N5& -v}eOQ)ou`yu&_fq)mwAJG=bMiZI8V6=TVcE=kcA)xw2i=lD1tQJYXuxLe+i92d;}a#ypqkZbJ#^N}H? -7l>~;MTn@~Ls9^m=W@%+&&Qav+{D&HQa0c_Wm~ -Uo_ylU~bGztG&Wx;AjT?Gkjlg!uzq>_9vpV=frpynPZcRTHPomVRq9G)YVsLUj%>|qKzY;+=`-MqEhFRyQSJvWhNytKSkVfGX{Pe+)*wV+tyET5wX1?fAz6GZg0L{wg4i>_ -^~94+OasC!t8JjO?8}rvL3 -CNlJ(}n93yEB$&(??@Vx1oW#pz5?X8nroQS*)ge{pAf_Zy4kVMt1Q?n0Bs3gb#-3uk6=5uToi5Iko+I -Q+ViLW(j)Be&LD|_-4X~el&fLoPZ;6Qnt7Ai^NLh5II)Yx`mGygE4TTG&IRT}kA%6BGnZcrfPy^2!9f -a~o8zc)IY1`7&*c6+*NLM6B=c&wby$C_9xk>J*xJIFck^^g1@`Aj0RZJITIi;~{cv_F^gf{X{Rpw$@* -N7$(M$_;?g86qVuG?s&ouU&)Kur^6K#wPwFel!?%#*H_?RIq3ePcf`ZOI&oZJRu>M8gErb>{=MqD>sa -BBZC0>NN~pbu)f-bKbj*!%>Z$f_R;j=bE`PI?BJF#9;lao9n8J)@cg$HYzI@y6o2IFjUXVc9>{SQJ1F -t`)-B!z9>Q4df-HEEK*bpU?Jda*>+;<7KVjJSAju+S|EN2&mZ6&tdfuB#w*#7#?W>fWx-UZHMBouLqOvG0k$@xTKtKLzKeZ*8Gg}r_V))LmikBekT4n?}$H&t_i$n1_>XD2=EGDq!lNiT%rM5N7t}m@Qen -Ry(8Paas6@BU>x|8m@9^L>BvM0Rt_$~0ig7Ehdm8G0z(W%S$iE4%OI6Z);(&qvO$8xF-V>8$i$Y+i`w -Q`t>hdlQ*BEt23s2)sdI7C!`ONBfQBg+t;o!7$IsAh?5X$UYrF-N(j=T4_HVi_kmtGBgKCGmoha(`aE -Q0<9s~XcU3DODf|*t0!B4}fc81}Rk9B#&+a8VKf~uKSD#n^qngvOXZU=WeRzTr2c_V|l4MsHxr9bAl` -pg)%@OAbD%icDbOV%*iq7=M@oxzb9su95oF?2&WYg?|Uia#&P(L?XH!Nwm-<4M8%v0C*+C!2LB@VRK% -fM!!zn}tW`(-xaoMQ=6toHvrGH%rm8uz}PC%`5Q%ol`Nm>=SJE(LlX|x5~CB4vcjqL^LM`Y$4TDm*)y -8ckuCjPZcns#>?htNfutYM0n2x``*Hs6C*j9Vi4Q~$Oedx_3#x4YLoS_APXZCn@kM)Ip>#REl7dI({y -a*LW}MatTA%(N|8fQBILa)ei7vN$S9F=a8Y*XdUOLhjGCDBWwQ>+hK-%Lr>dAEIGyYK76{1Dd4Spb`c-&!%T^+>LaGGO?j&^^3FKCMu -YDWYn0X#a~GIa(<2=irdFAdX=^oIE-UasRW!P8BGl{DTcv)&QFTGCgKF&9-?3Fgz_Yr|6`xLSXDFL#X -({WYxQdYJ{eIjrqF>J-)1Fr7Y;S9O3a^zkC3l17!p$~GYBHsA#Wx}0!k*eiC>o`oaVz+yaMR>tA^EG2 -U#p5q5xDi=oiIvA0P=*EXxROBo$OY;fr6HwXakq_$u6J8)nG0DN^oFk1Of0ZE5m8vlSmjcWUzJ_-0td -`9*s!H{Ayb5IRT9!VY0pfB_qIu)nNdX{NC>R<&hc=&iG{$3_{lSaoBcz_2LZV+hE1UpAi1EVrma8CDqS-O0~-dL3AL&aRSMFJ^#%=E9@&CRwYn@GB*YD{scM>l7 -K5;yz5MA&8m`W9y_oh4f|gr(+Nf;cVw% -i`QM{LstxBwN`MR#CZN&T;3&iRi*SaZW#N#*z>`gkTaS9(xf5ybVu?T?@rWwS!!>exUS6f1xnH;Gz2| -A^_Aoiw4%J@+Ps;x0du~N8@^A=3h;y8ydjmIv{0FY2o;_g1iGjFRlcv=ia|EPk2%J;+&Vv^QQik07Lh -Fw+5av5LI6^qB<^%c7ANnaG@eFqD&$wIz((g=>uWr(IILyXe;33YkEZYLo9xt3?qUG~BUjOuui-*#0uqZeg8Qi+*5JgHZx)HSq0y&xX;d -_Pgax@bb%`)$JVxn$(L;I$uQiN~_R|5B(-nAm7o=$=;-(08HDd@7D%~8)3`PFeO#c&kiDEUeemZIO}a -bx-qnQsAU08{{;3+-dNm2_pbx~v$Z`z{J}S{Z@u$M<^b1MxS2!y6YKZE;!`+>$+YS+F7~9f}(sCG105RcM(%dIuHeE}u@tXsgN#D%j4?EqeBTwa4s3ED ->O5ng5uPw=L07Dt9)uQBZi6R>q69P-xY&Mk&$KH+SzA)aQ*zlbpJ(wfXJj-pQIQrw ->{kVCC9{y*X1x8eTGX0_n^f7@y3*?xqwARo=Nr**&ET&NCz$Q+LLZvZa#LV3OKmefox`o;3ldTpFzsi=aor;Q%cK6skK&}!|0t^<>Om6?N#TCTS)wy%x8L6K4Qm -p$K*7OSJQ`~-Y0*}Z(TJN4oiw0i9xnf+nq5eAy}Neb23#JQ&YqrpakiJOz;1S%V{EB);zlvc6UtZcr@ -^~^in?z1c`coWrcbCd!@&87@RSM5PgmzutYhz&&)MA)MP8C(!KNX|UYV^vawHGs-nKjxJ8Nlt;!*yna -PvcS2F)^!=ek@%<=ydh(mGGZ1SUjtV%#gd2A79XDF`2|$XUPO&)4wn!T8%-GlK`1Vqrl$1^HgR9$fdh -eg=RWKyf;QbhS$9WW-c(g1;hT;mvUYG%h(5jh365HeHVlh9QNXK@(f3d~2aH>0ethQ!-aql4H&R9zcr -~<^_cmp89&`AQ4nlawbAI=H@0**h)~<@=gSve=w1BJi3_h*BAP6fpqYkb~8_WBFAiorWZ;7!nr4#+|! -+vQq{lC9WTvds`9eoEX{KdV-{#Ys=vr6c9Qw!RxCjdplN-T4*0Gn6X4$!M`m&@sWM8_loPt#vPw`PZ} -b`NJbi;-kP$2E93WlGETFSmFgG?Um2+xTDwJQ>**cy&-eYYsJ)Qxnr|NK;IUuQ$7&!L5!wclEVM9cBcab|go*^kBmtLCCrlkmgRl6A8aull}t5q?)iIF4AFQ7#i2Wv({194F?iueJ3&2~blFzYL7(A7YW8e -o(`+cp^QVQM!;)(XVfz56c_F;IR=j-Vdz&|JO-9RE2PhdQ>SCu|yTI*Z@+YIN>_BZ~Cly_Lt_B(s42* -YYkc=xbBXk^laZGABwv9S^N0Gw7#5RAGQU7h0Y+svJAfx4qgzeR>g7FiyPFTFmkwOx`sgdvw%&zn$L$ -+jT5$*eAaW_CC-D12%7*Z2`=;;rBvg7|~!jFE1XfM|1ovf -oz+(3VvbEfN?AiK-qpEvhg{H<1lqbmHWevLQaRzd#iJ1P7zQxhDOo0o8Oc?e0SNL>p9mK&ff)i*R>ot -%7kN{%Wzaz};%P=T?cfQr7g?&5x3LW5 -rd9EZxlT^S{F!PcI^p#71mQCYu!oap*>j@*|#;D?O1~l#jnQ&F-p>=4{lbYE^)XS2!Pb}2D?(#;o8C4lNvN)G#3Vx(LY^>>W{&82DJJiS7n*OVR$ybwo;R38PyZ>iQ2rz`noopm*E -1&cEu)l}=jE7);^;qBDF9sc*vqub#{WlAYwNVSh;v+MEoupH5VUz@f&cEi*inTxv`M=#CSI&OqZd1JX -A3Ny*oB`OM5uOwr}LUW9FDf^$++f@s->OU9DRk2T1 -%q7DvSj}a~&8a4B>eM2dn8*&e*I+7YjjS*RsOIroK#S$Ng(95pHEl8 -#m*wraVO+BI0W%qM+&iRLwS)J8~J*ydtQ)I>u(oOa7i?ugrwk-=n9a0!3QuP8}zaTV0a#hx7I;f)0)< ->kEOjf3NNVv9I>&9Mx#(GO(U_fZ9zt31NW5D*wO`P(!xl_$Q)>{-R=BMY&ZU68;R>Aqc_Wm-7Fl>09v -)GU@pHoWM>p?>I>fbQ=l}PS$-1Kz@yKH}jsG?70`SyiS0dHf4mH9E?AWHmVv4Z}JG-^i@v5uX69zLcs -&<(-UBU8f%8b;Z>Big=#W|du~l?xH5?kj!@{K(U9?-)kXa#r3#Y12nSQxMt -C-eW}cjvSK`nBk;P8!SK+8YzWxf14&n4DHsjul)Tw1I5f?V#(U7=QRDs>aLH-LB*=eit4|bi;CW?N?qSmsBP!Tsxr7dnoB->H{Q)tzdX#qlo)l)P4N&D -1WX^lq2Oo1-JP8KGF{}gHg>fg?+t!kH#D~DYC}HA=X4mVZzhXE>N5jMWL3snBy;1Y2ooSmT&lCC+?sq -Dt$KXmjX9B#x)xgBJsa>{t2&R;{)mu55Uk~!;f?t2+tV^&fKnD#ATaM&Qb_W}Iwg&3?^|eGYu7~NrYy -+U^x5E)Y?-?h57)NlK`s{ri27HQh5qVx1(1ro@zhaNw-lOb0qfW)>UD3Gx39Xz$Byh*$f4U&5}^&A*K -`R%18eo%x0S8j_^RbLf~rCDy#&Vl#v2N%_sw?|)ZW{-7BszXzQ3Sq*?5xy{#d6kocwB$_T`KJ0#Hi>1 -QY-O00;m`Rt8hVZy9}Z2mk<)8~^|$0001RX>c!Jc4cm4Z*nhna%^mAVlyveZ*FvQX<{#PZ)0n7E^v9R -8EcQ*MDTm0{D+mRisY2|C|nV;8U*S?RETmSR|-OvZ(~m`RvoYLt}l%c|DBnA*y~3^Tj~!Ndw1S5JCD5 -wYEvdYNwybhodd!Yif4snWhL%2nTdkuOx9&7D#f;7=gmJllL7GM}Kul?L%@VSj&MGhQ%wub?0%Ol?Gj2RrxPm+35qMgZf_+4-rkY~6%VHqvI1D;vVEDu9?%fPs?~rnw ->1*2cyR|LvelSvfvdU#8M2p(@mz}Oq>Cl;TpZB&mV<+ji1D&D$?Yu}_824G)fZaCD;`~5hGBSnJ8vOJ -0f%spjlvb|g#z~M)p`u?@$MvIE)sP9DZCEaYYA1s_ZSiAJXUfk528w?ju_P#R?{Gr!;lpyQ-u06MmEE -EsUQ)1w0a6DQ-am9ag!DieTB5_ina=_$Yck^l%fv_9Yswbji?BrD10Q^8pYsBD}#0yd97WGY*SHy31g -De*h&*ajqYu10Z+->NuFU)EM=BrDD9x2!%_goBl;EjaHO@zv%|;`I;5<(noxLoeSf75fry -{iO@S=%GEa>kyivcCg^UauGRuF9%djM+dF|-j;wr9}nc?O(L4jD%L1`jgo&bai@vy@x_iH~d?UBO>9N -EKOMW8#732E*xH6tVKCcA}siG%{<$Dri0X#8Ch4d%e5d38{kfx;;Ln8`%gIvH{sDJDrSa%f^&-)Gi$r -&9}y_LS+f3aA{nqX?=p)I>etiPTxgO9It^5bjH^48pqq3vPc|L#-jYpH#)K*Hs1uUs-rn%4o0(^PT+k -4rD8Aj;`6E!RTu2Qs{&0doxqx77#cLRpLBrFprkWfB*!-f#bG!KA-&AZ8a>`CJ%NcBS7I=hT~ehW%J8 -si!`gh#U95@HlmQm>$fZsmEKd=WB_!Dvy_DxzE^K`W8GC`bWG^bBiz#Za$u7|AFrc?ns+8y)SKKO01} -IP}5*cRV5{k=5;aA^;?=PuxR@o-pseS%HTX|`#q(^eTXx|5xvwL&%Q}Ij!8B?2{2!e7(2XYw2=UOjo| -BV8wY!9MVE$EF|Xy}HaJ5Q7j4bqP{H`h;_)rJ0Ew+kbfr4acz_BHMdD9~aJv; -aKd>^#j6=_JJoB48lRMNMF?{ooL3)ivc! -G*<@#1#})bH;GN6O!40(ou59TxQ*L?kJ5Ivwp5t%J@(CI2?im7ATF7x^+8IT(Iox2`j}fqo3l~e>y}2JUHlcNDK`(}M-5JZlBjKad%y2n -)>g6%P9!jkP_RzHo*~|uHqt`<@4~8@z4r9|I^uu#ZL30AG$>h&nt%RPU56qmJ(G<(?GMo<)Xa_mgs|} -XSOi@3um!!c4bg~gee#E}!NK3XncL`zy;ecq$GtsIb?1ErU0C%DhDjMo-O8cq3tn&x5#9U4$+8ro@&W1qra$=raZiZ)k -z#&|h(k)JGlh4CD9oS1mIl;&{Bl<=awqCMWjGEc$Wvdufb2*AM`-o`HR@gkhVb=^4#km$`%^dVAo7Y}0-B3rEhxx%bBxVx8MVP)r%dy05S?i_C{#Xl$GzP^J#!&KwncwU -34!oh3vj~1$hprG1gim@5SiJ-4iOt~FD4Q7aRTNK0Yy#v*|clf(2S#O$*x_0RGf&SnaIn(O)aTHEZhz -%Tl_2HT^Flx_DpOhQ)qUJ#LLG(BmX=iv_-u=Tc3H{l>b9w7rJ~sV(w=jPF7~I2jnS@Bsh -Z=1QY-O00;m`Rt8f500002000000000u0001RX>c!Jc4cm4Z*nhna%^mAVlyve -Z*FvQX<{#5b7f<7a%FUKVQzD9Z*p`mUtei%X>?y-E^v7R08mQ<1QY-O00;m`Rt8hI&O6T-5dZ-AMgRa -f0001RX>c!Jc4cm4Z*nhna%^mAVlyveZ*FvQX<{#5b7f<7a%FUKVQzD9Z*p`mVrgzMn8E^v9xTzh -ZZI1>NAK)(aei$!gm>)1(?rp4uOj%+u^I<{du%@&J=ASd+73tYEIBXSmj_Kn`phIg~^J4Tu%Kc<@ii$i{ZJ#3WC926darwf2PV$PRu9ZRQ5VglY?Z2~9T)$j)bnw -{MozihR2AO*inEA9l!UPssx_9kQoBB{moA`Rvi&QW8R)!=Bzd^pQHGKOaM7v50^Y6WD1GP&c$q$9dt* -hGZ?l)W*-ZZ-DaU9dLU-4Z|1m;In|kcw+u{@??km&f7QA5fIWbltw*h#XvZQ -@WxM3wb{ule-0i!7u)y+PJT$_wH@@k=bV%PN)MfsGMFH8;O^DLj69@$Wd;0)#e6n%O|Jv>Y2uJ_;rtR -?JDCm$8^U(k^BtA6*=C%b9hY;*p|rrQ3!tG;J~aCX!3x9i$RPHX2@uZaq?j1y$78fO1FtX-m?SJ3Q>t+;I>`lyP#ae#g> -5^x$b{cE5s6%zhe&cL9`U2XlwIsl!OBIUULJ%#BCEn;j$2*3pCg?UfSrgD%e90#V{0Jq}WfSnTmNnBH -`nsZW=NK^(dxdx7?Sal%onq-Wp^c(qQJ -RP*j@YnfbxLlIiLdYB6&L`s`RE(#_CXCWHQM|I3hb%|Mhi6=?-na(^?#a@5?1zs71jo1# -_5Y`R*&XB&)OtP=kF@p9NE{l$0*prxgY87M+O1KW&C0_N#Zh{86|n+izq`))bRpc)MO6Og(@2`UG)cm -qc!98k!5y^BH^4%Ta8A23EB90TS+Ct8bd3=di3Ic5lX^B`H}Kqf1jGPeyT6WL_O=x%DPzRid7dp;XaS -Hp$;vep~Mob=-*q{#;+u(g+b+HQDuntVCTeMmk6`@eJ@CZCZ`8fmnT%-(XTEzN*V6vB8Qt=Pekyq04N -TF&V_+v}_!sk>!@4>WYOH46A=|Bqb{ATO7?(Yc!cx}gkDvUgbHV>xP1mCpdp|%rvjvY -1|okpwG;#f7de~@Oc+a{MS4J33k4p5Zg9|09`{z`h?&Lz)TE`6dtpG_pl+nBh>&q3$sppi2FOq!}v0N ->V7{MP%uC8)XKZ{KX`4yH5ac5Q7Pr|Fsp$k|{!3wqsk?_%wl;XVco0X_jroM>P~;y^6ucaR}57jK~bF -hhTL*^^6I#rqSvwjanc^7$-_T6@>F_)MwSgV|e1p7;b$$ROK@#sh%lQUz^j -2s0pxKpb;J9g1VF;OwMy*;e`Im1vgUMN5H&e>ncDtTR#?>IAfyMGbiF(w3$l+YKo*%vwC4L53OO(1q> -qQ(nt0dZ)zoyHo_s6JgxsEz?BlZFJn4`o7DqR(=#?pwAZd!dQ(0A?;{Qt>fTmDs6#igSNIEF*0M+G$7 -!(fo(EnE|oFGC&M<(TCbGQk}(w5!O+(@S@JG?G7;iWMm~tb32tx_lXZ4+SyI&C$;Mzl9pQ9VOri=j=@ -bo_vZ|Eo9E$3^C~4_6q+4pDdXaho*J$i+=`%0EOo=5+m_oS^Ll-8%7@b#1QpL)F31NGcq|%f=Q`q-?^ -CeSu8-?b^p+!{#F)74W(18X(*#$-8fxs&4h)WlcF|Oi)rzy%>93jlfEHh-jph%^?eKT7wVHygn -iK}?%5%SRZtUN4hrEbVpi_%u&l59OMY-PQZrBdr!y1#OGlA2Vh0Xga#vRzQ>^*iwp| -$%N=CIFyr-@uEoiQ&mr|)(}8u@0Tx|qd?~eKi29_VmHP1(m#5)Nl?LRMS>YLfjvVtL$O+02feYp)_94 -)(8wbQt2{RJgE!Vo7%zYLzi#fWY<;1W(Sf(u_JEXZP2FteRu*w!lhCu}Zm*G<0L~$T1MoR7=a>62K^6 -Hs~%mqG5O49yvEa`YkY3!<8xV5T@; -;2)}$^xobQe{|W#41r$AS}%oG28EzKEuVeXo)y~#p^niLFuGlXejcg=I#O|g*>UcIQi@R%WU3rFj -ioln(b!fEp#49c^dM>}{d&z;y2{{5LmZ3UEno+18==msp3tb- -8L!vus2;z8bCrPykLa`hbMbgu&A}w{MVpM5Dky8Y{U+V5E>F4PFc&kPkA1WBJtcA1J*OG&jgm*u65`ZS1&)xI{9WSRO=xMxsh)5>;8b7Y(=j>1tT*GHB_*paBv -La_u(D(hA8FklDBAyb&G{aJCLNUVqC#&oyA-uzyHpg>#7RZk1{tk;=X(8UXIaJls$@c#T)U=V`qfiN5 -vyw1~tqn>n_WKN^Q1{Z&F8&s?XEBjj=6UznH23844nGI>+3T6b_`nG6wmDo`>5*EX$-EW63ZjJn9W@H -W+ihFtn!z-hs*n&SA8b6BZFZSo_!s3S=OCMOskFN!5oer15T;kiT;2(e#@2Y&22QfeF;#g3%56czT%# -pA#!=a3C7S(cOx@%SBMO|LKnL4M1j@EZAm{}-OjUc;Bh&5NvpDG3ZQABtkhNyyKSY?x_qat5{Yxrn7Q -EqyvqR6*ZyhoUCvaHZo0QsWL3k?>zVHu_}wM8P-O#yy@Q4>Hvmjkh -ipBe@71}hdFZyNpJ6)K_)ypw!2Qx@>LOS(kK_wNH)nzwDQv(*#bYLQ5BGC6TkdKGPe>!`#}FD>N0l=j -M0MP)zQphhuj$Yy_zR`z@l`g0u~q{GAr^LdIVFd2yb_k>L@-YI;y44iBXP8w3o8`Uy!V7jQRz;``LRM -`eoI(s<+eYDaD-0F;3;#T4}e`Zxt!0Jx4 -2xf~@#9P6>&A7w1Ss=Iqp>K|RZ=;VN)7SDtMo?MRFqO{WC{Uo%jMdrg0Ss}(hjeuwIauT@~GLGjGGjz -#ji*J};?GqJ}IR1-2c)T%A%dmeSSMUj#blbfR-msfM3=X{ulbK4HNh0YP)`iU&&<3NkH8&cIr(|4h)+ -Uf1P5+?(?GhyZ|0#ON`{47!zf^*5d7=7BBSBu@M^xk1Tm3a|$lpej$SYLUusMmogy)XGAFmz$rxqL2m -WNOoMX?c{zq-ozSq*d>@YV*Y-DL&@NjWu$gps8;Zw8|ewi2J~{YvYS1n?LCjZ#WwAj{5TsO12C#ExuZik5342l3wSG&`0Xxi-r(iO}@j2A+hP)A$C}x2?6)I`HEZfIo-j!BA-5eQ -oUd}HuzoMnpNBY%}&kuTC?IeYKbk1`S5m0{}WNyqEc^4q3nQ+-A4%it&mYr4+*BHv>H{VbjtK0(N2L_z57Z2! -Wng!)AY;mfdKsy8dc_IA>mH|$N@}iJ(h5-;iEch7vnEJlHt@i#C^hveu9^V3A!&vxT)}E=g{9? -fNix2&47sdSNd5S5Uve4eW2#VfCo}$0Os1*V(ba=nw@q&R{Y-tQ2*+)$Ze{C#lKB+ZhS8Rw$-I{eMdH -C$vK9xdyAF|Z|{2QN+#Cm(0eRnQ@O0{5&pOQ$DQCRvW4=)%>fggG*8AhzXodN02VNa4m -i!W+@r9QO%NIXjdii?kz-Ak2V%Hm_d5Jm=^HM~DPKfO3pX>eB$+JcWng5XSzR3H$+Q7GwD+5h8P!H_3 -yJohB`RP4ojHa?8o;}d6` -zgnsgdPc9OXId9?{f0y^Og)K&MXC04pyPrlC9 -0isE$FN3g8P`UpwLTnetvt_VeNB?3+pnueGW0$i@t7n}?Z3FL$05nja*bIKav3FH`q|Nt%kzA!uPJs{ -d88FH^v;fiOWs`{>v6>HQWVsP-a!dYsijC&yNe1q-qu^F$0kVrUO= -p5_n<7rPxabrDEz_|kvZy7cxZcJ6@Ao`NijwU#nb|KJpp8V4hv)qwGa8K!58mnZvr^ruQY=+jD`Uk%8 -__J4n5w)r>e|T4*4i{;R#fw%y0Piu!QsL6QduRWQR3sKS?WqG+A41fU0GNw8~Re|M$8MN@}}Gfqe|JR -xo9*2Ulun@x9{o43wwAlYuzH1D{H0M;LID<;OrGXueG^N1?;;KMU|KB9JUwhr7o42!QM-u7ozmU93Gr -$qu%PanoGn=tN$w89k5FL6ilrf~`s -rnO&6`cFY)GL5+GtS1pK3S2bmrY)rr>RWA46d)291?ov7Zj79XkLT|NK#&4?3c{2$0--x%P=_?UMm+2F&^#ht1E`EJTY}^!jnra}AlmVX+4vts&GnjRI_V%yW;$M4NRf6uL#GNbQ*&Wv^G!LB@uG^X2F(`%RkaH^eCp3Qc;xZxV3MgW8haH5m34u=j@{dE?{PNrk-9OeF}n#j<~l6Qq%m@nl(u=O7uhL-fh&36HgZ;~Q-mD}h4y-gOnAwaEU -ZGGf#EcrPT!py17?m%kt|Bcp|+&AKypAXA9SU72y%$yo<;D4Ex{40EH{UIB(q1$4S$XX?@py=8>1FON -8+r8k?^)MjsT3i$6`SVAd_<3-@_os#Cyt-T^(|L*BVNOYb9%(wOIo3hd$QU -or~7t**%7A9w^;voGL9_kSp3~7t9j&qF(oOmcBnLjYRCls*%sv1OWknML-m3$gfPFQ0nAcM^=;?`h>A?w3~ -Pq0j-0u)4bwRBLmw|MK3tz)CBfbEnsEr)j?}%L{%6%V7yl9Lq7&NyiOKz*yXUw;XWXtpBRaB3cV_Kkq -2l<&&fJNTzb4O*Uc8JoNLg@B4zXRSv!2TN{UGm( -9YqioqnQ%=J6MV+4A>f$@YEZziA)IsAJl|dr883Vg#Mp6_W+E}@)D+;;FjCAwN&8 -fDfW3wMFYbuxmg;$rr;MKAssLk>g9qz5R)1mTh?F$Si!SSPQ=l1tQ5GL*K+U%G%E{?@Reo?4`(0+lE- -^&AlxXYERIg1i@`ufU$+g1i5>1`u!~!CpDP?p4qEs!nc8UrEg -m7UotZ-=&y44(X2=XxBEC7Qk=A2ODOaZBHQ4PK86W|JLRbm;4YTLCEo?6HhK^iJ_vv7V#67Z{gNkLmn -nX6FlSM&P0Lee3{-D-PXzT@tC3wjUi)tosD#XU6uy?W5i{ -K{52>6b=LgWvAOJs!XLCS8dDyaTP%v4f~2ig4lionkO|d?027T^?trQnk -TciDCbN$=X#NJ_u{jiln13^5+6fQKlKi2cSK3A3$-wcy%d|@Oo7(%Ko?VI?F`7n^wMB#O$VTK1v%_mR -t>_NYj&K##1MXU4jN#Og~ruuVBaJvWn*A=sas$l;*{<+@jkiCreO!E`x1qd!jkoHX*LWVSBm4pwP_V0 -FK#HDbp0z#C}K}Gbo=TXI5w>9_o_UkkqGSKP14Vowg~Jd60R7tJ@h_3#T<)>X7fjAf}F`gc_2j>Zu)< -i9Ble)gI%{6R?jK*jJL#-ijZR3#@i2imK5!SX~oT#@(#^Kb(_>ss#u-hDt83LEJVH_FktrI-At60?+T%P3> -rcccQA#iDUMM7Jpl0r%!bsquN{*6!I=HHqqlfZ&a;vFX6es|0_iRhp>sAocH)#tR}Cz-c)GBa8GWk2z -cg(Haw|8Jcr%U%zyK(14RPLYDFeG$L>|^kN!W$Oiw+wlyt=iB9WKLH(0ElTQ{)42rQ!nWG9~8|4{WWT -g4}MjJ539H({5cyCMy8Ksjw^W_M);Q_3&6z{gic4mMFPb5I(9o6lfgNK{MbLWJ!sr%iK_9Kpi!?Xb;Y -6fYMtF3%o`?tBr0*#g>t3F-1fOouL54wes+!y`}u(JxMva*4-@&^B#(D0zA0Y(0>65;D%`KdF -i`&UpEk<5yqDyQ{@uP~QXb>iFvzk$&&=pR#ZPHS{xAM5B;8@tlP7!*q2!$LA!(2hW|1l#58ir}Q@ve9 -{9m2_%kFhg65YXCnquy$-?8X-!WIMPpUDNc-ClJZfZc-j`Y~#CFfyItA&G#m8lyyW>e<^hCS`#Zp|5P -WlpfH -v5WM9$JO?=o<@Qw^`XR04#!5SWqL>cl{U++7WWn^^SnqkTV`gTD#4+fZb7=bNN+P__nu(iSWx6Yv;`f -N665N$)A82redWuLjf3pxt+>ccc89fc(uo9pT+wknL;17Qsio?3sD%<6y7x+7ZTZdxo#d1Lp$1uFo9G -jfF|=9oyj%Q0x|_0oV-4|}#?AcJi>qosHm`Ajf6NFb1#Xn=#NGWJ@rfX4*qibm{Cb=dM|yu4SSJrSp& -ALKfrcM5`vyDUSo9u0)3ZIoH5c@Z)p24EE4GXX<%S5heO(gmZCUZ`)4kuG3+pW~cm49O*5)u2kF6oG~ -3%eY&mYO&N%Jb`}T8TWDLQ5aTWt}M}hH;{~S7wk`4_L75*?CgdUTd*096Z*{Ww=D|DYQCZDA&%duB!) -X4)YNpOcF$f^5uY{}2(h>2gm)Ph?+h+J&%mMKMWOCq!d7`+>?sxFpB*JB=DfR3{YYmcZ=Fgi^mk2FWp -Phg_Xqax!orT-w-5OMi{9nJKB5qUK!L`7V6F$m2{2%N`6~p=@CipMG-Jc37w ->VlX&P!2c~naEW1g**;$mE0BW(olBu|yj`7&8>5h$nrX>aE%7PwtdB6e!oud8$aRG{HqR9iq`&>f~P= -bXKe#!CP6C9H}VEmMm<64(R4o=$P1i_(^w<@Hoq>`jX*spg*2VG5w?}$AS=MrzHR;~g?mFZ<5-+3z*@T`aJ6Hk~w=k6B*&t;% -6k+qGMNdXcpu%6o^==4y2yG}OKza$hgpyCrjvZ_+=_L?+8QPXnvj7o7fpqzOY=6mmSpee^DQjEq5rBK -qt-;i9G46^9F2$Qc_CqFxiN-E{a%~pa?x~IL6nS_%c=?&}MStTw>`q73)j@>Fu?Sa$o(%Em`LAc%JR{ -B7>$<49Fk`xbIQ}wgE9nMZr$H8`O~~VjF*G(dL&!z0fE+xD_*qSrpFvnIS&ob -xZ1FAgT0#RM8g*;ZzClKUqQ#lJyo1;(VpnSsaJ)-JdspuL=*qhuK+|h(HRAiAaB!9VbX3Z;BQW8iTYQ -1Dbai3R8A+;@nmJXREBc7juj!6v3@@z3;z)zlgy>5a{(U=$bfsNy-lTR`20OXBO@ZsiSN^b2oe1>w~% -!e|9#7{QT%fWyiK1=W3mlV)lMH`a0+c#V8K&7`*Q9677+_OF{=b^rvq%*9<3(90yEsgK29_!UVISHLe -k8o$<+%6Dih8p(*Wu?mb-!%2(?;IT{aC&LQY)Fh2W}DBIwc$W>!qW{2K2LW4##-x&NazIPd4kqmzZl5 -$?YH>E!w%4v8UN?9C5EUt1eA4O*3PH5lM+kh%YO@@$WDwnP`@5>x91J2yCqxTwxVVTY*(UDu{!&l$al -dV(RNQ@KV3aq%crobCb+E;!d7a?x`5hm_cYJlr%sOxvr?Bmtt_2t>+yX+t5SJR8j4^vRTf4fovqTSt# -(XmL5CgO#cH;w*?qd!i>Q5XeSchBAE^Zsb+$6pM_U%2rfas2ycYEodsRJIA91Y(mloc^ZDk86UrShY^zG;cf0` -?sn}TmPbrjH)ACGv-%DS6$ZQi6c7*sO)>+9E}$pGwR53F&3l9j4*e`*46;TRT4&(NlsZ?yOG|B1iu*# -7k|^k+zewUaFlP5j1V@fUpTRqnk0@ZkReP)h>@6aWAK2mnY{22-0nr^r+Q0040S001Ze003}la4%nWW -o~3|axZmqY;0*_GcRyqV{2h&WpgiIUukY>bYEXCaCu8B%Fk7Zk54NtDJ@Ekk5|adEyyn_QAkWG&d(_= -NsWi_dAWGG(m*QpUVP|D?FLP;lE^v9pJ!^B@IFj -GDYX1XHsi~2&3NNuUb9brn);Nwc(XC%6JCm8qrf7s7c!S=mc)Pl(=+%7ujw+(vM`B7n2Ci<$ym&2EL_s98+zaC{z7d}ApKawn-;-2QQr1J}$7w# -ce#X_b{NyeJYgsl*3`gRs4N%~E6|%RwJPFA}RHrE;4!b~GO!j>YBq`>Rif(_=BY6c^L;pC|8*--*HDC -A<&D;?v~n!}-T60T9!}v#Vdl`FnAA_N(~Y1POm0MA5RXa;^O1<;{5U -$n0N=2&n9Q@r%=%G>G9c>0|i5xIQ|)4#N~&>lM^fr$sK-#YD|$)addw1>vZzdhb!^n{N&v+B)&Zc{tn --s9CK+~_UJ3Kx7>6oz2fe=*^A(>6_>BBLmVyTDl@91iBeuniqIzPLb!s{5SJH0BgKTR%=$K -r50xkSmlpPrvmO;NglbWU^t_3W4lq2%ig1R(hS@$$H&Dc&6)o&dQ^L{@dx@X*MA{?lME_?U+gs2^y@9 -Mt1Jg=bRAK!Q$qV3`Ff2zZ(`m|`sUNCo!+5%K3K7=Y`}i@Zps>xyuRIt9v`B@tMg%kK!Oa^^+s=SdP} -Wl9JRte%p9ZhLu>mI>Lq%FNd*nIS>f^$Or9g;Ed1pyd$74>OhYj~0E3SZ@Q3~^zHvz!fIfux@rbiRaP~Jct@0p2=lKyh?_w&@{|*2Ve -F-AojhCTEPKp4J^bZz^54gb_oercg@4FD|4Bxf?BH?cWs=i+Srt(d-}LayD&QPp))hQj_%GrR71&k>s -+uZ&POPsYFNgMCI^Y-6Ji{($IQY%G^9CbT5&U~5{*w*Bi|)O3hP_TE_V<8#o;ej*B^9X3aQI66@PpWY -H4-nxE5)ZFAf`LXzXf-mfG?j#61#_m2c93LnaqbI3-K=p`u$?w2C(*-@qb2qr#c`1iIWG7$N?<-+h<}Pm4r6aAjUpyo3CiPs$UbB47v_pJ(mnD1Sih5*pEgvJRT84jT{(0yUL~#> -A910O9^l!quOTr+-o>Yk)!EPYf29Me#lgedsS3(6SyKn`aq0_YKNV5-0!EVwuD$+L2!(4^HHtSpgz9~ -IwS{8-bo~IC#2B)lKRoiZ8RA`_G1|PA!KR~;vwQ&Jm{m`JwH5fT1nMPe|eV~yD#8LK0-{RabS1Xa3PS -OJ9#Y}nM>u(HDs7*~5wQ@CGtCC{FHZ`G9OP{elOTpobNlc;lY4n{J6$qe64P9;UM60d&RY7CM9kqC;< -d#7z1>kO&U#K5`gl$v18^kuXJ6F1Ne(F`Jz0RmhGze2me}~n@P~!7IA;BO99Q# -bt3b@7f7Cx`^Qr%upgDU&b-fC(10Y`Z(!|z;%52pZm;pGbsXQUZYl%Wnk9Ev5tLZ_B5R0M~yO;Sd4;e -&$~meEia;&+@BQ8A38iBWgXg#%h7F+Ri2{o?py|K*;ThcSkFNPwe02jX~b(lea6Swis`(K9(5Rg^<$= -R2N9iz4Wp!;A*pYVb#MF$}kF)T+~{p)N|sZeIY^0BZo<#>suG^3m7)F?==Jk*3+k;yH|yBP5oY -g`$hp8R#ZUAe$1`%KcpN`xh~A2JpW|hOx3BH8+^T0IMbwzV(T0^32!U}{H~(rZHHJ0AsyMRxjqJMHwNX2k?rt@sjWn=|ZvQ6NwzxL+!b}SG7?eL8kYT -HlT9AOg$4M@*811}FWvE4Ih_p+6Xx7{JGMan$pn6EiUS(r2_2|0RV|eZ$RG?%ugi$j?LBcGIaa!1yLo -#k7ByY|ZFk$%L8iZQ!8+=1P4JQz0?#lCTy_>%FD0>C`n=+j|EkKP!p7lnAKsP=O; -1p5EoCf&>fKsZ-cj#Ug2~F;UWWm>`DbDPp#R%?{GIID8w(|V@&T9dzO6)~me`n4~)VNf&U3gg;sCP6X -1+QrR5WLoO6@hUItY0wGw&k*velNllSByea$S9n$FO)%zzQp}Pf_0`a -ZYK0^-^k-gHrkS<(Q|aZhZmZZjU428%vH{L%*}i-LZ`kYv8`i-FNORL=)Nx=BUG#{f9^{bKO>()+%&} -1|z`M!GJE4(+Ryre8&{{zw2Nc)ROK(wJsx1|twt)r{XpArh{w2-aPR?<_RC@^%{J%^YjqL>HVF -WcN1U=)AFS7#D!TC@|1*4uih#5-EfO8N0PK$Q^r2%QaGQBR&!+2HXJWf>H^03ilJ@xM05{@6b$w9fXg -&ugqPNb!`>KB~?z@IJ}U@886fKW+R{m-dI^|%3lW+zZR&H4x=MXrPd5%LnEU?KtW_bN?%nRN>w_2L`3 -p%ETRAb!}aJ=_;7!?sW_r-KJ-DEpdvILe@M2!DhAfF~_{8})KAth3hHB9ag8??sXm{wiEa78s`E17~% -in`YWD*)EiinM~h>J~ff~>?ctqX-c}ATZBJ>@r=gR&)ecMiyFIn+XnyPD=Ns~k8p#vDFFQ0tYiS?;yR -9GY4o_L2Bi6FQ86_SSL4jAycO6_;(2(p!c|Rjv`6%Q!S6N!PRX207Q?GOGkC -b&;h;>wEwN9ndk=5G8XDeVZTe>$fJ2`m9U-)q_sS`e~05v=%Z4i%@+`Z1T|4~X4Fxv68eDz^ -dDM44Jy_;Eb@E>kx_CR%HO<{WrQ#2&EN&Ioho}1iHwy69~;y6sH8~rc!C^ -hpW?*i}H=|SKX?s_>V#;Lo;2gJ?B_a<0Ot}ZTRddHg4PN4 -?R_|;0}=%+~?qm{6c#3hZ6>PWVW`0hpe*rkWu8_1)B -9x)v!yQ*gX&2qS~2olih&XCNT<<&(;DR9-JW?n|s_yoa|o9RsG9R_3SJIR#o}FV(wNS -WT}6*H4i&q~eb?rp;juu9spSQfzp|KN=rX`_b}Sf>%Ep4PJZEAflihg&DVJ?Nt-068jrE4w#5~C>uHM -*CgN}N>YE3B&uh~Z;vqL$V}0k7?2xiE|<79vucMUN@=%D4YFUvw{>02Z=a@(^CVVU_r82m6q2rX%hq9az?&^w!UUfB?Y413|8OCNBBJl#}L48uOrHD9bZ0C-$HG6~F -JSA7qf6tzT9PNY+Krqx -wy_;RJe@nu6S6ma}(a0GJeOKfnep1;*ynE^8OkL^xAA#qtq9WS?xrlcyR$=Z~urX%Tg!06tP2xSo#-h -e>6S03P6)4FVS9^A-EVU|(lhXCB$a!f=k47zO{r2NwM)O~)zW?#ofD~exM~S~XK7e@3-P -|AHn@zR@dWt(`!@JGy;7cP!=h(GysI7) -a<3lSdD~Twl?rv~aYNz*i@I3#xXjv0k5dVLE6cy4CM$|9T~_Ij&}KkPRx-Bhqb{a<`5J~iQRE^8*`d> -$Xy6)E@FWVjy8+vG58$o#u!#VG?P(%A5x9~0Doq~3j$mgK`c&obRQq$1+`ACB9d-GYO*GIgy_0hf#x> -+sK6r5u?b;kjY$^j{=*fh5mFa>v1ngQpKz~?2i4|HycxqiPz(?FCX>fY;b%=Zl^Mz`)sq~`dZbT1fS) -O`+4pj{O!y;cixt?E#5;fY_A*HMMF2v>YuTsaaM2af;71??+fy*aRzzOW95qM%1jy!)MpGxFoOgoLAE -K72wPjp=XmP&Y&cf0jW0Om*1i;LAx=n(5Rd*;WqrWgC`r;)&Jb?wg9xSw)20yHe5#s4VWwU1>YxAOP9 -Es1o*-Cg0?mXWtY-!=AD=)KW*7l*sX-(~3A8G$!tUys3ct~ClbGPjJwvsDs*)p==6(h`Yt#v?*;5USo -@Vo`HdPM3-TvL7XxTtL9IGX>mU^d#i&2;9K$G>#65ZEYQlzq@%b{s#N#U~+c@(K^{0sxYW>!{)XXFL+Cz9P4Wv(dvX$rSql{!Gmoxmv5x@J<-{e$KkNSQBp{N$s*RCjU;|mzu4 -5>Z@2E)WH5!G}RBdYFiOVqNT)yV7@w#L>zNTF8^w=D%zTekT;UwxGGc~DN%mzy!ljvpVjf2-U7m&VsO -+iQQf#t-ltt6D;-vRDx=;EvbJ8^^kMF&=KU#LvVk%`Cr~vTij%80A2SU{w&E3&LGc^L&>nWpP<_h>fM -R`d5ki^pINF##e!xjtpsk@wI+~o$%UplK&OX#YL`L25VN>9At4)@8p_`L(3?M8WX?yHsziY&veKvQ>eRZmZlMx{`W>aw6djNtO0uXM>X1h|>jOaOtJu=%jc -RDh)pet&x+01$!tj7rJku+-P}wo|-~m7r$?%umh#IJgT)EM1Tm{qZC(zT~%5^rx(>b2s-dkNIkP94wB -9Kv&0Bttef`o#z6A5X%;YJz^W+#DjZd;IGusVsmP~Kw=O=+?wq3#3P0CNX5c&<)22Itpti2ZI9%0`Tq -``eYth6FP#OHoq)w%&4#v)Gjn -)@-*AB2w&EAB>I28Zj-)~G;MWC)9`L`akUH}zPYXZSU}2o^;dVnl4;C_a&U~Vi;PNCd` -F}`z&4c$8$&tjm*u&(fqbC-j3yueA#5dR4S~-!Zo@=#s=wMssKn84oc9*db(VUm*hU)o?BZ#2X?_I#b -AJ4L;YAp$H`7#1Z~5}{^Q$l7hXe7-+|JI}Q##0FDsSXNMbb!I4caITU;;b!a(_|o{4}7?k|u&qY2Y*t -o!OGV?bv$^TLX))@6d7$@=Sb6(pxX(=n2nf&%HSCB8U^k4Ad}#@Nlu&0MvoU!^}zLD)M|eOb37e`(P~ -a2OdVW)s|pfnfcyIR%TV&3_r9igwl)(DH9mZY>Xsn02!ZOeyR5sr9BL1#e6KnF3e*7Ijm4k8!699!2N -`Hdi}8cbRNH#U5$~zsAff#wX|%hG98`Ru&o}eq3IISY9471+uOop?4b1HGm6=kia%x4Yq25glv4`V!mszF-w$cIjuIr*%1ly}RuldOk44G67;MG7;;Wa&nOnz -zRpgRySil=Ps`Uq_cBED~*EBmMJWti(j?iV}96Y@bUo}LbX&f-TGuH#jR)a9lJy`*&z!PL6lA6M)^rhm1vs&)3Z -fAIjPAuC0W8HJUtJ~jv1q?H3XO*nz1T$Q6!sg8KASv?t8HxaJS8jIhx&pcq -c+-j;243zpC-w07VsL`S*QE$G7S;V3wi_G}hQ~8Zv<~r1O!%}ztOTAch{HM>Y2kGo{3LZ4$*0wZxzpl -n*e=&#a}KtG^ha$dI%&6AAyr%l_~B3)AjndBLs3kdfwoWqs8^_430D8jQt92+ -xb5K-I)W&SjjMr%gTKdvh6VCY5d%cj^sIfdZABHS*@*!Wn-N+RkPVseY-(%4VAWS#7#$ZhOE}goBV%a -g)XPcynWe7@ZR$;)2smnph|__Pko9oqj|4lWSQmg`8*}PA^)k>z(Z{(3b8tep9+h=%|#^=+9m~Jz-ua#xh97t89U_Ai2+l5;o -bZa7RVT?67%}`J>G+i1)RDgiZ!-Pj0?ly(oT^&5 -+S{BtyFHK$`JFo;Gy8)F-usZr47rklE!7+2MFnVRj=8qCUC8uov#PsXN>`iyI1%wDh1ShIUjiCJ^2AI -2p=>bIg;M!X~hs{m^`#*9pf)rPKS<7mbRuLYqE7ejmk|4u_HV=G;`l@v47-V7QHd7{LvMv2PrrhHtwz -WOV{nW0tW#dMw98}e2&{H9HWf%LG$fOu=^-C{9x@TVqLmOu)RAzvi#WJEXis%=B+>Q;3TE^TS0>HZ9_ -F~MCD)v@!+P5OB3y1_hWGQCP1xp9A!)<)b(a__oBKg#swL3sE*9ft`ifhCl%&vfwNuK#9>_>=_o^_tN -2rU@RF9N-E0;=Au(>ROr-wvi#B=cy-r^zp-c^z%y)IrV&_Yjg2w(YYQ{T{W(Xjw-2La^0mZco2&05I3uy!nWL=js_&x_is~CLi;X6Wijx}}BpXuRC9e@@g -i3MPazU#mj3zdp-jHpYLkwq39b8Atw2j?xodl=iLa&Ci#it39oNc#X9SD4fdZq4eJlt0(uzLd>VCANC -NN{bkj!Nv+v+3L6|qp8J4kie=bW7<&6H_{HXaXABbFevi*i+>;JxuF9+xnyc>BJmcC=g+g}&-I>i<8I -sXwvzY8+-50_7vfqCYp=zNzpD8@y20ccO1d_{@D)K+dW+`%8w;>Wk5+6=ikv_+&AhT3ZK&?pys_85c5 -cNgF97b_RnjpD*P1LrD}!Df4W^$H7icN?%1Z;^Rg-aU)!-sq-r|!mhF;^Q -0N@SuFLQb74*EvTV!=0ned(=J|>lJLUPJBRMJGx24wqM8*kcfOd~(B)oG3nFX(QQ-JpUFi=&rtbMh0q -s*>4y0qwPu$7*6-U=6*@Y4`9`6cb%d$@`-ew0yBCTb1{}teubbFxxcmBh*l1)q=ODxg5UJ-rdvloo;p -E;PAE)?(oB*ifgK{heB&07RGeRv8LpbIk@P~;F%-9OcZqAVYz0;G(Vb&`+5ooHGcthsP0n4&v;g}Cr1 -;YGWKNEoQX25h^{4>+t7>_ -6jN1-D>3L>m0q(@x+BV;UJq;ywiRwX7u#pc3C?0OWf`Ce2wgB_hT1aO9w-XpWl^4gMKHlm@HX{Gd!Da -&1snfB(JsaVqIl3);zu-2)R5 -q3FAe#Nk7q)CD+mS(h6`@pa#Jdf8^V~rnU!n7YPU)gAh66F)gE4q#1U -<8You*xiZBMxJh%|Lti0jrv1X|eV!!<$8JQUn{GL&bOiNt-!QQcw)A2;S_Tj2Ot|VeMyR*`Li)E@ -7n5LFV5@nI)-jqZfql|b6~TxkUA)O+6XGRAoU5}J7X51j!}8 -l=(8~V-P)h>@6aWAK2mnY{22%h40006200000001%o003}la4%nWWo~3|axZmqY;0*_GcRyqV{2h&Wp -giLVPk7>Z*p{VFJE72ZfSI1UoLQY0{~D<0|XQR000O8NLB_@SR2nERRRD2yafONG5`PoaA|NaUv_0~W -N&gWb#iQMX<{=kaA9L>VP|D?FJfV1YjAIJbaO9lVQXb(X>4UKaCvo9U5nc=5PUcIKP)N-cAJ=%QYgpy -p`i%`O7FOj2Kti7@w!oCONS)a4W<3P -A3#nC7(LENd#4z~xVuV2$%sM3K9m3r~?*xbUu-PcF-J|aFHyfzX1al~agjyjqOz(hllVK#7Y^uYcq1- -YF*h-`tfdVNE0RhJbBKwJ3op_b3vXy~}Fes#`I*?y}XlKh?t1=97ETG%fx)T+J0hpn%EGAHi98)661h -Tp)P#RU~SHW=t$emB!R7xS0pKxqS#<87+L455PTY2`Uvj;>m>Pf4+b1nIhoTak@xX?zRj;y>GZc_NuY -9x*QWaO`}XosZC`1*~OHO{TZh%o+(mMm}g23Hay!OH{42{dMxK+94zn8yUJpyi*$v14l_)Am$STL&0# -30%k=OzuOn4}m#TE7a#XBvlH{&btHyISFTsQ+cpF*?9@tw4^3<^ug1dY}diwv{HJYFLD9ckiLfD?|LM -1E#QIiu`QCmSJn~>WhvhEmHIvbrocA9pyn}_!gMU<2HswPGm(6rFFrked0fw)7K{1)`eFHfK0=YECmg -<6oUeoR@z$uhBf=b%Hs)3es#=+J^b8~(IEcEI-1>8V9_9w;BbGaEx0#u*bHBQyOh$&Jb$W2md?hSL&v -}%~pwM%@q*23@@NIa~dzWZe26TzmT7Pb>_r*covc})qkv^Kg=e*h3N(pK -M;7RBT -9IOJyojrB0;oQtO=UQ+f4wqCM+nLIw$ug(m^?E>_J$qUc0(N21~&W#?!1t#7bnviJTXh(%72u0o&&s? -{{E#U;OlOsy;pL=78gIN)YjV%I2$c?6%pr#advT$ZB?^Co9=54k&ijj$3%&ETMiO7ffx$5ltZZD&jPu -zZG@inrIernfE!G&%!)may>=ye>fATLN|5>E$hCaOWRc2&z-&yW#wwdv(Rm%2xCVtFb6BnE*SCL`M53 -LVqO(@=hs(FUe@_4&~98AC`wV;P)jzPSL2Q8-g`=u2mIgwOQcEX*!My9u<9eU>>7r+*Yclqj!#C%jVe -o-dRantBwO=kIkH>ExC#FNP)h>@6aWAK2mnY{22(2rFrdQ-007Sx002S&003}la4%nWWo~3|axZmqY; -0*_GcRyqV{2h&Wpgicb8KI2VRU0?UubW0bZ%j7WiMZ8ZE$R5ZDnqBVRUJ4ZZ2?ntypbO+(;7sj>LZ`8 -AW)=U;^A`bE9J=M93~u7Pye?MVHNudh9mS!PBu6h+%x+gm$ySz0-v_j6? -^SA`_}Ug}KNWTET&<_#4pmD)%W#=T0*jQ?9ml)QXSN&`Tpp!6aqW!VCyjTJ?KO>hMeI% -sQSd~to+Xt|N~S6QDH&a;MM%U)SQHDExNawd9X_K%YvMpQy}y;6`^>S9eZv(m#$G$(1n1AIW4+(@Yy -S#@iNWdQ8E-G5m5rU8y2VMV*Ao}V=~e+{AKdDY&b3KDg7I+i%V_+5&LP-uU#n@lZ~>w3O)v75~)IE^AG1L}6smxX|I+Gpw`}(pdIhi{V7Kw%gk*!9m -fIP3o?E=LKS#nBdiOgHGK#9zq70S$I)|XM0s2gh%i_#Y`CVwIMyx<5MGV^l9*L*? -s2<&yW9dqOEBi9vPKs9nCao*JH;B6fsNwAZ3|aGJ6SC~yO&%s5>ZuBXL0oDKgs9kA)92;LzaNSNXeD5 -^EkTK`}+|ZMcoDG;qt(UZ-(kP>2Lo_;pz**fKbb);suAw#Z0<3$jA|91nP9ZiQPcZhwwJ%Jqjvo?UGa -!>c2Rjm0Y}Bt~}w~S|-w@qLOj&>8N$IkppjCg$_J+fp3GW+n{15sZo_M3nl2ttJP}nyOk!$;zFbnHTn -0wXiP5XD51T?LR)n{^A(w^Um%VF+io>VAq~ogKbV)k0CK*x#eDKDV0@xejycZ=6n=-iK`^onfRt1h&t-Ebz4rCTJh``m$NT{upqrMZr0MNTNtymM -=&_!aVrV)h0=LR|DgDI+^0JB1Ak8}LZtBwC!R#Yq)Gv?0xYVoM!k?l^;9U9xV38 -jq`i3x*gM)s2A7N9F`^t4i1?}@*bTzRo0Do(&$~x2{KojLyPI|wycp73l~%#8U5)vr0*fdwjsp8QvI4t8NIKKK6mlCfIuV!n17%sdi(>rOCTWQg0Yd#HhZE@gy-3u!B5+CTJSBI}0aYNJ_W0nP%6 -J&8-@)$3(G0hOiK4IK4H)>3;7{5KbzJ@@k%^`!!svAGtJtar1m&j1M(g-m`8I%yl8ZLN!_Zn8{E*Tp% -YGwwuxj!zrA*Y+(H^&>_27ySI{h?;O5iamhX52cXjq^-f$^LOv3SJ&? -^t}ajC@arx0)H{ -a7pQ4kWt?;r1Je=8^zZT%u|rs7s -oBX)u^;9h|c8iviQ^j2=ePs+5D@xlRc${n$@BPn=3zbbV9gab=ZtkKN)iJF>DUsaPZ(Cms9>#bL;KjC -k-5N;&O@0P#g`5Hac5dFS%IU$@Q4NGLzV6I6E1j#zV-~kb+Q&qY;L -|dB@Z|BqU?*9n$3TneSZ|(@birz7gEPz%ZPrW!w3EETbKN{%{_bAtHR*tuTxD!!!-BIMD&c}?k -gAH6a4VK5LL|I0md!z(P;QVfPXc2$3AxW`8&W5;11zEt2aOe*`Ho~e&Q!}-pWXog0JH=E03-ka0B~t=FJE?LZe(wAFLiQk -Y-wUMFLiWjY%gD5X>MtBUtcb8d2N%yj+-zLhVPN`4pw?;CA4p_2bxlC)F?r~9(o!%Fl?*<_Kr=`efyd -O4`j2PJl{Wz?SIBK=~e*Lz3T}9gldf@C*;BErgsRpc)3_EzKP$O#6gy)i=@hmQnyArbx@6RACWMm&#J -<)fEDg2o#-uA!fA0paYVwW<)R+;dn$F;Vd<3a!iLJi1fe2r3|1kX@V!UtLT>(Nlfp|9|4Opx8l>^hZ8 -DNP60JNT98p$Cb}C_w?kvvss|}Qmw)1TqeT0N;2!dj5!`6IXE`1w!$ -szr_Pm^7qZzq%|>(?wPvUr!L`>Ys+Pzeey=Kosj&fz~d0%YmLmZeb+Ko(MY!gC25wYC_&CHIaBj2S;svwvl8J`T<(wC&ZtctPB5 -Lq~Z;RHPo8?!DSUq;f0jLVekNC)A-SR4%V+mn^)syR&%50@RQXnP0li!`_J&c$BeI|!O>_C$KD8DKX# -0zxt$EZd~GoB=z}Wd0r)KFrL6GMgIKX1$!){VXxRYwRPv_IGN@^rr9F-P2y(=JY>MO9KQH00 -00807zB_Q$DWBHnRr+0L~Kt044wc0B~t=FJE?LZe(wAFLiQkY-wUMFLiWjY%gPPZf<2`bZKvHE^v9BS -Xpl)HxhmyVE#ivM&OpAwC7qU5HJtU#FH31v5m2ueF%aU)lEr^DYBPjOQV0kRXqBT}68A- -yj20f4vHZpuZCU|&UTWoxSfsNBt81=SLh*vDtuR`(Cu>$dvlVZ}TJbII?U-DFs(9|8+Kd_|z(xg -I@fFKemGIwBu7i=b?_4TaeIXE4pN$$KyNfxZp3pw!6 -@N$o)sTDZGltn+#O1TF-4vozZ!bKQ@kFes7IcI#FCorPb(FDBqaX5&f^k>mhzkE6w)6T6fYS9~i?MT? -2RzX%5LyQ7pVjpt?nQh87Fbj)4P~;KW%zLV2(}?A;oVy~}?9>k -u!@R3rq$Xqef9;}+|;5sv3@T~#Q?X$*wLnqDbJWJDUYLJZA=>_P`lndcMnoyO;riR;x?G;#Vw%k~fQwdvY`~?j_!+*YeOyz6$*6|Hgnp<`55b|3dE~f}EDcn8}{83_F -kSx1`$U-R5Lc^_{M2N(U#aI=;e7XPW`b+Wi&FAZq)qJ6}{IXsCG -`T~g*j%8bgf>r!%Ga_A$E`?rWCMg1Z$4m7B9s+^GHG#`4B1J8*nj9axj7%aj2r&-f4 -Z?_Bd;X(;gmfY;7V(o1n4+;^&ne^`SR<`nDiit2cTh8ZgQY5^^;hm6Ne9~Re~bS0$vyno*@+|{ -4QMHtHgn9Aads!%Ivf2l8uy6PTktWRGNQ%~lTnMA7fY{aD0J6;tlCWP -qLMJOFnMMtTFK5WT}Br}Q%u24`<_?JR5Y(zegSkJoR*+^81jfTzQNeS8u{o#oJalpzA6P6bg)~ws7&+ -$-~HKX(I?D+&FTW|?fcYBJ4(->c^RwMY%8#JE8BqmX<@q}nY1D=AekW!9%1u%)Rn51Km_n-b*JkGw}T ->sXG6I+H8ZeL^Pt&Mhi0wq%zedHC~V;D_T*xiV;$<1sbCXM)G8m!Dez`7Yz1*J7%maP!7}AZ>N&idz=)m#heC|2W%gN&R_(;)^-(HeLq?HYij*p| -A$53RJ9qcBs;-S8?5#iB0P5>opYU -ng;3dOTjq4COeSUdy_`o`Vt0{`pTbBeaQvE^vKtT+vWVK -nsYd&J6!-XAU#c5*Pn~0yT^x{Phm7{TNh0zL4=>0T*B$kNH+NNp#{m$4XIFGjE5SZsT-#j -{_cTic|*C2O;HVztt!eKp{zL&4x>P9Pv@2&)cR`+jMH)vdK@SmMU?EZ$vO0AX){+*H3W&`0()keob~pkDINx_W&v`f+OAy!iXLGef~2ejam6&x$aK<60au~-TP8b>PiB56A0qb -_!^<(mJC|=JE6n|O*I@&!dhppaFPUF6PzHNz$NAtFHAe`MqQq1mk1|5+UuXFkd}j)C&oK5_ -Aao(X(0k(;>jJh!m3*buZW6`-eij{ydHQDLNuz_RA(8If?)N*2~4`0RJ*!z1oPy*C}+1LFRP1VnjhaL -hvM2e@h(o3o=!=kVRk=J649qxVoW$^@`QvEvR;d}j%UO9KQH0000 -807zB_Q?>_aSp)$900;sA03iSX0B~t=FJE?LZe(wAFLiQkY-wUMFLiWjY%g(jWp!mPaCvP|PfNov6u% -ex9Ukn`fdnmH9PH{zLD@k(mC(G5hiP8g*QogEP1??NxIiHM{uAl~4Jt=BM -Q*068iqfsRXKyKhLT@V#J(6HapbId%Y_QNM{4DnFBg$(SYS4sSE;In-&PLhvx&lkvIG$3J#d{l3bg*e -o%AJ(ln=OfhPJWXqt{qblA*zs`K3I9X#IO-sL@I(K;;xPh@$LRMS*7y|>FogBBX{G**Jn-avCA^2v~z -Ot4@7nKGErYMVR$LVBSeTv8nReY)$c0mnG_%v9&t%Y+b5D`>>-`VgfYSTA&Kc}B(z7bapm;Q`qSxwyf&&Pcz4yFn~sk;z*;`luBStJNwvaTAi -_wS|BGM(c@B&)6NLG5G|Mb(eX6~!YdorR?~Kw8lV&q;${OSG=x*O*=81Cv4+kq2(oi2R%`iAh(cM9-@ -4(krSY$rdIZ^N*5nE2&Dm&a{b~+`}+f7__v-FK*?*>XLwsE@3ScIc -LjcMH<@EQL%9=twyEEGP(He`HS)EsH3$dLl`}s(J6~8!kvM&DUsuZ*}v8%t%K-E(Bs3}$Zw)bn@6NJI -PSH8Eb>4OyPW)GGd$4f{~5DW1V3Rai;Re`&gg7H&12+O?ooAiC-Nf0$)s7}=gpfpyTu=rJ*ydpWgQ(0 -mkag$<@iN3XfeJA#nPKVFDREG^jd=OUW?HC@rV`OHp8auXzVm;hTf@?ADwp5+%`w>z21_`N2-=KrIpG -$p%Uy`GvsU!0%?A#cHF#S_7end0$qrX5ML(4Xv}5ZJwFIFS^OzZ=W1xh>#*Fv^gh$64o*WG@@#L1*kX -mZB*C=80m9xkyhUjF6h^s7&T3Tv0YwXb-C7i>Yh8_|&|>O{1CZ@_*F3EL2pD0^=lfx;R%HHhk&MOz2?#`{eX}Nm#n%F0+xazPBU_4#vHgY8d$GTvDy9t*L6(%Rqk!x=S(m?b_h -fJEm`h|m;aCVab+52*c-s2{3;+pC3^-FHD1G)H9e$A_~od{7pcn8Hx7>KUNUL`8 -~yEl*t>cr{Rj0^*4wm;^R#hff&n11t1p`OWQ{1;G50|XQR000O8NLB_@`+e)$Zv_AVAr1flBme*aaA|NaUv_0~WN&gWb#iQMX<{ -=kb#!TLFLGsbaBpsNWiD`etyfKN8#fTW8}NT1l!GO}UI+ChRbdov;?zDQH5xZ4P!uw?J1eo?B^8n@MJ -W2;`-bFxSw@Tk-HWwL&IjMTc|(`h)MBwH8{b%3EQG2z#(E)_&Qy)3MSMR#IzB3SC)H9_8Ch$rYxjO=D -z7%u`dht~R!QwYD^p3YjDANY<^EKB@>u@KG`f&>|IzsO{4*|guCt83=Con6&h-t+g6y5NPU+P(N9{Im -Wd0~u!ZZwSQ2sNy;V!_A=F@y-b -On2?ZmfA3cx5#S*l#gs)yn%L9vtj?Ac^uD*sm^s*HJbwUZ(@+DoNT?0Y?XF@%G@AbV0j*Rh`)64-aocqAo0iLpm{kRNvNaCX@i#_F -Or6a7Mu11Mez6Wsw%Eijo5ojn&=pr<_nu1G%Cz#ZFFSi -qL5y~xbHwfGO(LJ>G&=lD@X1d$pnw%u#V?#&z%i+|1k8jqZ2T~Fo9Lzzhl%=l@s%kgz_gY6i14>9jzk -8=-s6Pw(WtT)@_~+%N4a_09BjXw1Z^ea=?eQ?Nm&cdrv^sc{_XR`8hjCtQq8QDj6s -l0u{6a#tZjiWE87UhHFV~QJP6_m9adV`0cS_LaHGIszX++K_e17M0o`;KyE2x7`)_F3k`!{&m!-`(G% -J5mc~eO{n!2Be<{>LLKR;h7ziyUUZtC+SFx_9pquHImdHs4=7}y(D1hvuz>|v^urmD=2PyZaWXWzPQj -dt?Gmy^7bsshET4@q96o9y%(;GVt=%53a;@cL(4^uA*RQXe(ffeIfEq-nCfOn* -2FImfoW9DdIl7+T06)+Y=D4*V}rO9KQH0000807zB_Q{mdEx%n0V0O?f#03iSX0B~t=FJE?LZe(wAFLiQk -Y-wUMFLiWjY%g+UbaHtvaCzlCYjfL1lHXnB|1d>gN}xl*l$>lftmP%LM8~SNBbP+4@5<)`hvZPi8U%Q -Fh*DhM-+tXa56lbz%9~QY?DB&I0y90+kLfqK%CilNqE%H^xribbZ?;)pGCnV|q$))uzdwHT_>p=dHat -$uw>_ZR -MSZ7PP>{WS!{{*6n7e&d-s=%vUEaM!Q5GC1yBa?a`i4+o(>BZT_2)My+j@eGI1y5m1o9srwR^x(6gha -x4x+IJi2`>t^i_0}zBE|qxELkSG4|qgpV#N`=G0WzEhh+n`l$;n5gWmw4puF3P{z&5X^ES`6AZT~;>r -$-P+2rNPyVuj`&1CxO;w*aq>U=tReSS3!7D=I};YZ7Kh!;V9pGfwuKyDn+qG1=r0|tm%$RMgc56~`75 -;hl#HcRB)&2cyk*}Fpc@K0X9zIZ=5Q|nv-__QcNLVE)j=$Tp)DED3>VGZclmmnflo-)9@YYC(;k+BQK -un;927$>}tDH90w(TwX;lUZ0%)^uf_Hy#(;%^h -P&c&~0?LR`6yH{(7bvFq*1$;k89z@jtB^dK{9I=nW<3~S(*$nw|85zS6)cU=zRX*Jbq%qKh?)7?f8(f -fd6<=35Z7|dfpYX+6T1Li!t(z^lE=ZN@Q5$R$M|2G;PLks#n)xIg --LG#;2WND^fMHwvHI_v8|lix1e_Nthax!mWimY&umij~diG4*@(p+l;Ue2SJLv0OUgQk))uEch0&w4e -z94OR9xp{f-inPSen&j}KBE8p9tN5`V@aH&VZYx+^tj;j1gJj0V_Og$JZZDpOP&;BHhajO5J>uD;CGq^Z<>rQtt2$#t0T;$Tvlxvq6<4Kb3LN*0=y(s;uybCe+97e!Ut0yyw+oM$tlS -(K%bIcsV{8yVFRwFvnt+p!H#@AM;J2b`CL)QON1LZl#-lR7(`uEFgmZmWTkeZWXKOOn<4j -4Afa6@*5Ka;YSJzc;g^`)kd&2=%F-&X?cv{2*AeKavH({e`EpTXD{`8=#BzJTt?5ljclmS+GvI`rb8b -ZsmRenD@7+HnW7b6l_GaYwc{?W6p=uu<5yc1$nhI~2Xq2CEkLCmiq#63_`9UY&FmJLL^$VC72(HbP8d{QNTX*XxW)zALXRoHyx3v-^+lS#OMtmT^OTnHGj|TAP82>!SKR ->X{I-Adje||X9{9&h5BJ_0vHwSsM2+$^VByLJSZa5H$<;MwFUYpl;LvBPQgOS5oua*1UJEkw1<8KnyyMo~Gp<<=#FIw -`ZMPu5dYvupBY>y_S{3*xIWDo3xQ1C=Q1XKkZf%~72W_v^b)+5L*T} -0u4b7=4=A+4O5VW?w2*V)9++g#klSycd)NE8evB;S;(g9RnsA|P9-w8May;lip4@b$gG5QDy>@c2*Rk -VK{{ChU?IUoDMn(@{u~0lgx?d64pAt4d#92#U^3O1Y_l$(yiw6y{j&edQc@C5kizXyS?TY*s@}MB&FYGA`j@e -WA`?(GnNC|4Q_=O#^qdGpL6G>YtLR6WEp-V5M_Aop`(gQ(8t14ZLW+ClqX6?__lpluS5bW(RJf^?j!Q -U_pKN`BK&A^f>>Q4pwxo{kkEWNfv3=rJZRS_>vPXBuG@@4eqs~HZ4MfQ-gaO@INQcW;*r)-EFsarz>02wUh1G@_}F>OB`TyOwAY4SK@De)!eXfE<4lzkwwAS -$5qd59i*yTWg#}SDnsYL4%POZjnqeBJh#iCws53$xHk$oIidvj5Ks|%qn}q}&cdfJ*LeKK0E2@@N%od -9(hvh<<=#n!*nc#HToJ^bP?1NkNX{a&DTc9#lct|@(q>rLCRn{!#DS?#&M&o6|>hOg0mmH7Q(J>BnDy -)X&9J$NM^zy%>lb6%UWpp(?nZCPFSqup~zcem}?~6*J%&COAmnKZvt>B -tz7hn9_D7TxcAFsivQleqkm_U*OTc4uP)wB&o6$x!prI9$>{`ZemJw=vRBs`@HgB%nJRnN!FOlNAHF+ -+@bkOl9|!FF;q#Aet6N-k7w(o1pJ;pY)z)TuClwGqkAG8TP-+OQyuRaefnD<_=-5)vvlN?};qm6435J~PZ -y3{%(-1U=;766J<{%O5z+2^@tq^4<9{5-sfCyhp+o86n;Dwzq&Sf!5#+4NovivQy%{8*TV*sJ)+*`&Ee<6Iz+POL7%*zHL9R)Kp*SLecKsH#V#Q41H$}IJG-lad~YNcxWWF~( -m|J5;dO??Dg=UWa;tKfT+Jg=rjfPGXNzD~OscTKag -^lo}nv{z({aD%R$e$PE}*Z|b&YTa`z1}$=kAJbNdCJ9C2j$Ow$5SoEhqhw+N0lk9Vnq$IUK7#+|LVq;wugS-|O!fo-Akf@Ng!pg --?(2A;Y!nhYLa7b2nap7!9Vc&2pLU3BzJyBS;=L7E%bzmsalN=ilob|lvceX%-k;LvOLLCuBExzY{E* -X9v&MhNo59gZU=d0Yae)E=8pC6i3`>5TQPP2#~(X{+FRG)F(Kz)TC%9f`9l)W7gQSuF|UStjW!PBR5x -H+Uh(*clRYx9BW6bNTa*%_y@ZdUga1ztLjN&%Z~VtT#a3s9aQ8q4Bvk!`j>=6RgN<(+9N%91*nhox~| -hLk?hAmX}%1tbI)X!uLI*Gl&*!4z{TgA<%a6t{cYJWnkyP*8Zf5P?CHB(vXK5NW9fxjjh6sACQ;(BJz -c&bWzsEZF6!-a2e6XcE`Vucsy1b+{Ds>N@D1X6X&+BT>_js#+uVP0kMg6aMxrhFQxs#lm`MyABZGMcV -dZ?n6qB%ifp3vMS-kPGoRpdfh3XnVNEnO{Y5691kPYTtj^*lTdzw@+6NZlJj-uvJGDV}~99{%| -8Te$d-Ugz@oQPnP>8frm%U_Guym&<{uh$C5c7|Zu_LLe+`p6DQ-{?-B1Y}*6Wt_5jLN&`7>(F8s9wI# -0)iUJ&hZ`ePz{D&VunjIj2-rj+|NZE07H&57!Y*l+VJw-@qMhVp4P!&@L2sn`ODz>xe_0)@0K|T(D7% --b!O7i3uR0FPo3ql8RR2#rpXP;JV=2RS3mbMGn4xPMNnxm`zL{y$2(n(|*_&Ue -^G2u!4&bIO*Rg>gS|ym8Lb579Hn2lVVaju2!Rh(P+Os>I5X4TJ_!gu=LpD{Pd+=(4P=OpHR5{usNW;l -;aig_-k{V)mq2-}Ne5Y;fQBDdu^Z;9Mb`n!m6_IEu+tBbObdklv!0|oYt?SWX0DbwB>(}=zT-2;4vF{ -@>NYfQ{RoD#)=0ya*vk*i?b-YldqAROhHM&7`JDXYJhIMUSyZ5t4=r_uK4vH()OA)$Uji~9;Bc|S|A% -h#QSG|0QEo?PJ+ES$p^sp+v&Bqf>(a>w35q{4Lws+vRECM$XCJC^5Swe@D4OOx~&nCQ@rmLhs{6yG!=$7Mu00vj?-i^md2xWHWgh3?(H0eTh4a$x;$DK)MmA!f -eoWo=&E80Anv6@`dZAusF^z3L-7Oke;SOwcV7)-=dqD6Q%}Snww-sNZrV$&`$wi*=r)OX8DyF0SD?sGfNYVB)fibRD<`jrWb+*OdDW%vIii_=L?53V( -UqBf;rfEIt)f&QZB9yT!9+z6|1)tlDDJ%~EVdx+HW~7VlL{$|9+jGI@f8=*(4kL77bAy`(;l9fV)F?RTT~E7ZM;S8*5u!n* -ZS8iGu~TAB$9OVs3pqjfUze>)l!jEuaU!bNIlF!UuP-1d!F&*IvUz3*jQb7je|}zrg?{JU^3TbW}_} -04RaWsaL<~92q@zk7qy$1y3_Gg8iZGJ -Te9dBGEKXm+w7Q@?}wlW$33lk%NF&>WpK@ymMMHOH=U+kLt}7E1S@+3l^KVA@j&S29HMf*GUpPQKiMiDM!R;?{8FC^hi{y`P|hD+!L8ktKtaU)M=jrCgjsBBsm9B}W)6C5`j=;Bjm=KX+rC6o*t5E -7=|i@?-huN1AATq&WnR9}jpDq}F~kzB4EngMDoNazYDW@NBp5P4MW_&)N~-ONB&@z0)8vABMk3>G@Ci -G!UVo`splvXW&X0Fe40?|SQD~|0z9|OcL+(}gI4zb_k+B_JA -^ltW$hlX_1rh&YC^Rxr|%UC}5yJ5i)kpq@+zZER6zv6D4*1K(bPs9|!8_9Jr^%PjL=3HKt -xwljDiLY~iJ8sPLatu^+>aZlK}Hm}qnEaaZEl}TDEnNQ+R_=?i^!y%||A4aS1j0#<*ES$Fh_vRdIsyR -Q{7XC8%b#i%r8ci-QFD_en)g}pzcgC$5j-K7m;hMZ^c$3rJ`@VWRIX!==Hy+AH2ip-Jd)sYkIQbgh)} -4(`qvN-}ckRAG6zFgm92cV`luz6g%6?aimu@34%VY0hizOZJYbo5*O}MX-@SYw*i*Kz>gl+wUy5FwZY -UkI74C0{^7Byl|QqIoneE~VlHsMkGJF*jyM7ghET3sOLmR~HrW~_+@=*S;@Qylb1vJr$9F#GJc1Qq6? -`zj0mhG7&nLcI1sw)YwPYxGYeehDPIKi6*8mw{pQXWMIn`~Ht$5z9Xt@9B%x7xUTin!adRRrlqWFMSJ -OU!OSG-nedp8jzS$N28mbjX>Gr3vCMV0lkW6qmK!6d^>MEZb>gTl&egdURpnzV`m1Fm>13VKK%S!}fFRl!q$~+@|6YOlVX)@__WuD;O9KQH0000807zB_Qy#XCZ^jk?00>0@03ZMW0B~t=FJE?LZe(wAF -LiQkY-wUMFLiWjY%g+|*P?1RIS;qu&i?UgRqlMe|L$DMS=8xmxE%$@om=>82Ese*X5GZ@)2 -bmMb1t54oy-s$Kni%Zp5A3mBLq`kBnQilwy3m*P2<^IgC;nfYk|ms~AVIkRx9Ef9iFrA>8Gn*W0kl79GP -xcVMP9&TuOeX0<43*_)$&R{+jpBHwWB}W4~C=b(PR>h@BaIJG`PCD|5J273K%?Izz^IJpdaR0DV|Gq$ -!_vY(9lD{GetP;;K#uv0utf*15XtUj3?3Em)pD14S;*2lhN?={pjI-a5K5Py??0R4X*EQqPzRshuh)p -^#sQM+*y|8`s6e`?feC4IbxsqTCs8|SSqqbxn%jAah6EfY01hQey?+2(JU2oT5P__Vmt=6F7jj(1Jhu -#RAvSd{qe)+n_={6a0l!Ce16u~=X&w3Z_f7pMc -i;g+U8IE<1>eCGU_|u<^9)ZM{QtNl6zqRA4!bt)pd#Utz0<63Wjm0#5G60mqKn!eu#W$}6TEU;W<2#!zbKf}`P4nkuVGDmB|jb%H1RVmP{g0Hyh_&*S^iRlv3dUq>pB9|i168w55cNK#kBiZxf -tuHTNsYNtEax)rv%6in1U)+s-?#6=s&({mJ+VSvjR7 -G~XXkK`KGZ>q>dn2lltBwjYg_$mC_tElRJ@J=9?xDrTo*bTUXMpN4=?Py1$vLrc}WiM>yq}q3=@tlasA{l;JA> -yG&Ca=EdSw1Et5mmbV(B|TG677SYp9Das_TJ)XUu5K8*S# -ho|9r<6toAfGtBjn7|;8E%UpjHZ} -aWA_H$@+U4+1OW1`Mjr;BuOFh}`0nHA9*ttB-wFSk%ghADf3EFmhXmm*FcMhb3HDwLKMvsU**ovmff) -zk5mozyLkr`03#d1AKN+-5H^bi8?>I_>KP2{tKsx*Z5E47^7mD^@GWAa24o3A;o(Kr3VDM1%ps~a$cz -b7VH=m)^>Am9j&uTI$K8|E2%P8t9k?ainSEstVRK!k1cp*@J)B!m>r?$3wG -bD4_6^B=|TWdLg>EP#I`Y0eWOF^ZQQR8OCbT{d6_ee2OU#Mz%O5@>$4l3>`H=Gq1-O9;mqmqz%E>Vr$x~1%qX4SYYh4 -ye|0kBkS-)mI=8}}Fxwb99g!rSo&y -mgmBK(bTEts}KmXo!2fhYyWz+*pwBU7x?f^1Wyshpi_3jvAXTrR+YW(&&j_!?}@x{%<$(;fM?72h%K; -@gm+q=EL(T)>rySSxjzvpLWdvM>1tre|!kUKAWG2NfkUv4xXs!)FW}=JLjp!UUD4Pl5^+A^Xr0aUzS` -$+NMa*>ecyFaejG7y)9~zl_>JY+E!S<{*R!J!1EtCG|jRB0)m6SRH2SxU2vM$PB_FnV7O-pZ)yqmrkhdheuZBM2^@`0?ZUJM`SU`dAA2l1gnD?$9i{u_HS&P7a#>#O5L5 -2pemJNBlkrk|_?xT-{ZR8oD&I>0(^Qd>p7(!n|T#Xd$e{b?0I+ -Y0H_z>ck9;Z}nsIeMT4s6}d!G+c%P_FNaVt1>w_V|X^!0*IiMriL5_;tOVg@!1SQ1WDf0EZd#rY-gOc -PG@#(TG58NcL~lDmzy3UTb6Gi9uX2Vb~eS}XA06%)En6fvkSYW6dm$TZ$=-5Q3Jc1`Z#px2|BWI;NgaxI?pDg -UN1pI@L&Wr!0N(He}r<#V<1mSJ)n=wjSpuPO^3$o)NtjMeAOgmBIwkzmsqqXfG6P#Y%b!HA8Iw8!>nIX6T!j -K7oK)o~X0tUQ5E4X_d~PKOs;x#@*NK0cy&-Me2|N=JI$+XC6fWgri2+cx4pq`;dAY2S5p%Q{p!8q?pL -`TgQ`3c*v)i@EFflb%13!eWw9wh)PfJ0*3-$wVHnPz4H~~DP+{e_b&4!cOx!0(sEe?L_Q((lwS$|^6h -!y1q1Q!xcjSuM4_?^bnbQ&~Qcft0Zk;JTwzGmPA`-}ZpODuragJt9ovMe3w6+L*ei -hUoH(4XOElp<@d{g$YYAr80c6$gu6--z#%g&g#f-Lei0e8pXV9w9!uAd4aW~2^cuJkC%R%(beoa(YOyVn2=-GY{_Q~_Cyc7l__fc-4>6^~kUFpCM$PizI1cF2!pxf8OY1-JKzXnCtBZq?VyGz9 -_`fbqXf;7tlAbf~y$E#SVRZmk9%X+MGBf-8x^Uy(mzXbkd7jin3=1!$9&yjaaQDZNQJW*GTK?W6z4rQ -57+u5^wW7f9+8HTl5&fX!VgyIKY^{k5piUDU?wdDa^=!c^(l@P7Ph#2`4~SXV%sZPouYeD~Hx)RhoD3 -wCt=?q7Q^5a1}cI~zps=`=ip^G$al`<#IvR^(B|^E#EWgy1?rzk{NW=8x_WNem%uVZh))qldDiPd;40lvRD` -$KK!!1&ur?`*SB;aXFLcME8O0}e!V9gEgx($LiJRA{ytVWFA*$0h5+X?-8Ci=OWJ+I(U!%!BL#&p)cp -Kf)901Wuc(cc2AgMXY5$7)HFmWqOelldqu8H-h8#+A-oeIpW*PYJ%<*1GZHU-1 -8e4BZv9e`xT=_Wy)oV!&fV>(2U0o;>lVzi_}STxD2`vg+^HXqnB^iY%2)sMWuc9O|{W&$G^jFQPjlHG -6{pp>zANG+-rr;8QIhT?X`=i+#=;YH#$k;%2}sF21C -fZFnk5xBa6qYet}bnC@ocg;C3{5Qwl&dj+pQ{!(q{t0{KR4dJ)tNmZ{R`xVY^#`p@M+CtZGzqaDGd$5 -jtaX!@RJrD!izhExO{jr5p7MQk4U0q9HI;>3=QoSFPLd1!=xmm@+(CWo7(7IiV-XDKLvsQc931yc;C4 -Ct2hf6)B&1ArXtk`36|_$I+MT+aEuSuSahJ>-WsXO!A(#7s$GmQvTs>4|L^Gu9;Y^%bmF+P%|CGv0)T -|JRm&6_7Pcyo*&`r*QUFjtI*I)h5L?2W5=)3cys&h%Gy|4hn@ATW83_O^K!L-nHy`_ -$E+s2$SjTtn3GIy-C>wBR1W3V_i9tYBFrDeS+k%c=9TZpg-3LY|P1-CZ@%y^k9@M97DqdU-nS6R|O{Q -8o)5~FWedHV}oT21Yyrjinhx?J9@PT_qh^ao&TGB74M+NV|yC7*89YOgHeQ{iXr8D0ZM>90Q$pyh>aP -*kShmdl%gh*SJ9TXR+zprt-0o7$%fLH%iMyQa27hXtq%<0|UF=TDHC02w%d*0aV2X4G0hj|1(6q*rtB -fz#--Y2j9wG8k@E$BJlTTI(S7*?CCqRgWEM7?*T{!-2~=g`wdJvPubF1r7)ig0)9QQkY{pCZoEyG27X -Y^NnK1!vWnxnWub#?u5wIS5urmjZ+_~9Y*`znV!ElS52JF-L6d-ZQoflYH#egIm!WUVGpMTqdAI~S#~ -%2#B_U%Y9?f?;kibKbkz!DugwqzqSWP-*ID7wT^j(0>d(6ESAV-=8Y)J0AofQh+Pf=$5j1w|F6hP0+x -!~=ywdMJc@9TmT0EUJx(RQvd-Appeg{V0P7ulfjdAEoEX3hWt$65)WLs)$9PwgtZxATki -<{3Np^-zwI%rCS~TU>Bk#eA{2T>r~DL5W_>Hgli|DaWUQH-QxZ4lB9Ey=X2~tg0qvkO&aWEYejUmqB1 -1J1DkGh^+;)tHhOj@>iv3Ia9}QmhEz2X#Y&=Op(2!N!U|+Nfb2F+NY<>@+$Y -~#WgXP1h7(60ZrpG{A+T7u0SW9o(;Q6&0?GF2AET!3+V0)q->aySmC#hz~Y&U6U(*YUkfE%IX$a3k%F -V2kpKjE(Q`(-W*z)h+~=j{H&@cg@r_iUoC3u5J6BLUDzWzx; -mo1~x|BVrI`xi;i<8$i9fG=!J&Y6l1S)&AzP!yO(Q;b#fb1>|)1NJN6nH)%aI-%i1$<>O9-ZV+H(^Wc>#jrfXz0gl? -K+;U-7UTB(iadvNO&S!`hxBFCY@8G2`84MXOH!cx?(!;U2!K7Oe{!e#;4q?WVjUGY~%vXlbD)7U%fg8 -$cQ-@z+#tfiV33vGrPO6RExC`rBP;{VlJvzI>JS(6`k_P%HVeiqYtQVaN!&5;anB{5(Bvh!*ALb?LN@ -Q}=IEx2lb!It`=$Dj^4#?s)|Ui>IzIc&4YaIdwjLMMhLr1vTnvTea19yR1QdxV^%DLE}YguDoKfKbQ>1W2#t!Ld;S(9(TM$W%3e1Hz_;xzb@$bCpgRVv}-=$59#V+eQL=51E2jjL7 -nS|hXbj|jiek|koaLfhE013rm3Tb6)Wj@a|jeGd=Og{9g4)~?svZUxjEkB00%a2#2H8II?o>oQx63BI34>Gc-rtR)iU2HQPu5D7q~cYQ?wH7>N@`UUeD!6*9y3-ME`=tZ<5tPX!+o}8C3`P)UExEPKLJtE>;v7f7C`ey -yz>73Iz7L>dH2Kp)h`!hL0-*p~4P+Z;woE1D%D@E`RfcDEK~-@ewPx$OAbf2B1!FmoJG@p93%KWI%LRUI#Y -dAk!+ED@Qc7)5WVo&|$J^U0A}gk>Iywo=>b`!fQPZph5oPWk0tF -7Ur;a5VD{>o^TRca&@N!bljQ>L_icEi(WP0aBNg6?>GqT_EYzqcKyG};Xj=q8TcX>fx4-n6~k65AE|D`^3M|lC|03!q3CB6_4@H-YD4l5 -TV0|Y!bX&T6@S+Sn`9GjDl<26$|rqV6sqM#*P{3HdN+Z+WwbgJlP!}65LwO%Y$%^c=v{=8ERvd~wtWB -H>>)==ntlGhpw;8-5T@f+%paFNLpxfjTi{K!hF4(C@l(^*6)YqOCfgc0eGuE;jb3FEbz?`pc~^Yc)fP@J(?ZH>8VH}{GHscnFoS9Z -GNhI~j0nX{t%Svm7#?k0x@i0?4SDR9Ss^u>c5Yeof(iN572XSpr|fV;H0J&~I9$9sd;Qg%tm^feDI4f -xkg0VNn#3XiZ^IVBXS*K!x}Y1qI18bngxaU%9}998RUKDx{zZ$LT_`2hbb?9$2UF7XV9B;^9NUk8E>j -fPrS0XD*>mOZ$qhxqNH4roZBE4MV3_tL;IGuf3KJ>=H#wo~fHZZ2VQY-Nh97^rKqpLFH#MiMz`oZ37~ -@9=4ja^((a{Y?f`*wA6!P|jNre7&2K0A_=F6bmVqH2rKEjaFu(yHKxi6jzem -VQ*tAc%~5wbnn!~7nXt7N8}Rqbx~04HJ;{N -LF0n(z!t02Ck!fdjTAGt>htl#&G1HTk$#!{^BPX_LI)N?bwyLeHUgsmk^#Oo(MfLW}{*-;Q{2Ufrf*2 -7;Y2C^9A{0jP*^gwuEe4Cf{9LzI}haOwZq6US8a#_;z6gYSFJ#KKz_dM%R}x*lN)xrZ(V|64JKTc1?9 -Clc>lxC5Y~a{OQtm&{e))TP4r^op%qnl&dL#S+@iwDsIrj@iK@Bl+0re!}T^hALhN-9=qZJi}Mp#pqq -wV;BDtvjz@NVw-+qo+ttkj3}+SKH)B^*r<)SpR_9q4Bk`#gXS}@>3BrC+3!DLagY(l}$uV^%8#j{=!u -X6DnA$hYRE((%tlo^6)?WBZrd(W7aM9>A?<5Hk0^ZIoumNc<#na1ygKJ2;s_|+IZg>W}r;J9v0$K$uh -P0?e3Y)BvnJk`zHo`fKF8(aI7{}gH2=de^rJn`b<>*>bmUd5mrYA!3NMmDo$zbR8A+y6WHWqXNwWEu| -FNFHY;uuhO7u=j>&?!+`bRFzrVH(0tfxLT0(V -W2~;8>u?2bR^y2RB<}SUsxwI`{^u@_gQ*v^j;rj?6nYRy;F6~pVz0@8+alEMI1VP=7f@SS7rDI_itzDenAZ`WxnVk()$A4&@I~r*Ba`D0KJNYFEv -W3&=^DX3&%cq6aiD;?ZrXM9!`q*h>D|TK@8)FS;Nk9Sc@eMS&F2#mFrz__ECk93h*{YRH764P(4g%@k -Rlm|b2AO=A2!zWiiC#84}^cSg*EPVYkXw2ZdGw>Jn+t9JT#fTad|Z7vS+7NwV3tschAtni8%s-WnenA)53W2KTt~p1QY-O00;m`Rt8fJ;{v+Z3jhEgC;$K ->0001RX>c!Jc4cm4Z*nhna%^mAVlyvwbZKlabZKp6Z*_DoaCy~QTaVkg6@Cve|ACmnAU2?ArkkeQsyo -G|Nj43T-2}*F`)Jb=ZL^U@tw@dIKJ>TuoWqMqS)NRGTcGtrVp-(jxqRo!S$As37K?Rn`c5nsOzv9M8O -B#y)x8l5`+WB3?2&t8~;`A8(N>TAkr)30sg@-_;=N)3Zm5mrgA=Os)PQN;8||ak%EA7DO-KsYV& -q$dbu5<9A%vd{vA5>`~cw9q_ckRX|`PfMwIo@G)cOVcU6T>EJ((dRcR=y`(dH^1L{E#Ncy&e(qkdQZ; -M2={t@J%5ftuaBnp$dBav@Sx`&GKxQ7yyjC4NwMx~6-sPmrGxivNEUvD^X -TEDeyQSJ)J)V2!-gT@M-4nNm&GuVaZkf6hT_-D{$-J@T_>8j8A1?f_;V<(lyYUM9-SvEa(oRw%a0riD -7{Ky|@w&Fm@{aF>5uHX{FPA^5Ml6>P=e|*k)7C>`&V2awH`!zmc{tL68Yvbe2*_Y~U4(NW07+1T+N}V -n)>@7?#+!;b^JF0mG@t=s^Ut&{emBtDOVAsrRAVGlw2+*z7Hfm3U=&@FbBqzY*5vF>gTD`?#2vV>4In -FJw%{~=i&rSJ$gN0>cVY-E86zh{76*C{*oA!QEyOxtG(;>X5pN+1iz<(7%Up~iXrKYZ%fcL5;gpSf%h -RzHlSYEQt3G!yywzK6-P%R0zD(;za?XBr&i!q2e!nwn;M=1!DFMKOq8JV_AtEt&f$E!$*p7Ms@q(Z -_WRXZ*5c|9*H2f!ub%zs>9^1Rc=cAUt^%2h`q|TGe_1Z_fgY;fN{09Z=a&%18)-z~1NAs)(JN1n4D0R -n0MjA{e}i3D!t8};@I-jm8+jL5f?QBR{N*-JuN~@L>^#s)4gSAo=aD_hNcR -~N!aURrq9|hThs=6lYhD`F*;K;UYjTXO@Zlx3FxtlzIH=7|K*1P$YQz3^d;2~ZFbOq3z+M;bGxnYo^H -{T&KYhUEsz$G_6ohbK6AC7A2%#6X9zxtePc_z>R*UQ%Jaj=A3c9gGB#lqNn6?8~k!ypo%muj&v+%fn0405M?N?YACS`VV14V2`MFE_udO%mKL|SS1r$}=ePX+bwWCL9oUF;GWyFnp2Hs=^Eu*hpeUS_eoBMV?AJZW9og{#7VK@GFwAFg%$*uGn_R{~y=W4?{6G;% -K3ackHh0{|kx^wjNOC5TE%g(6^zgUf4cJp&~$!5bof)!*cOE6z78pz#?MV78e6g&BjR5J0x$~(LWtozSy!vdEH@EVGQDFr8LWd1Afc0dj^t7AW{YQKY9ihXFw3C*snW5Y>KgaQI< -j@AM%qIwoYLmJN7&Q;M0x?nzr;NE8JjbXbUQqB3qc3j^?C2G*^XmJ -#)Om`UZNjt3|(Kv-tM8X`Qz)ebc?13kDk35rIe@Qb=JN~OPb+GhE85gdzU{C+wj -6UVU)7b{Q;)QhtN;7^`HcBy&DGj=4Bldo5XB%p0Tf~N!hctgAx#l>#jAr@JwW8haz)fRL@ypd{2w<{0xsE<#4`rJdLJ9ARC-;OXn -WDU)e9e*DzY(y*!Qg!;l3J38|_#wjJ#yuP-z5=9+*AQbYa*DbA#7vNFFJ=#jLm4n!AR9*UE`cVGHgIA -9@Xb&23R0_r*D-{4@R91LyBUrgNP>DgGY9yK(=adJjz-mb_PRRvRuqM#Ipc@B8KXmD;~xf5%p{d2G;`=!CoyqNSsTj+eVukk?u{hj30jK -L3IW*%M7q#_UB#7&76Z+Fs-Y1jd!o1z6hn;Sb$sIeg|P0puZ*R_(SIh^lqh6AWc~f~}+znZnoyT#y)o -x>a|*SoNLlO+%dVBhS>bwuE%EtLSPlKe`hvFxx^uJvdkbK?&yS{{L39+eB(HqAK83jQ*6bJ2tO|>cdIyM%-23*(;!LIyhS5IiCPLbim9 -nAC@|?2%jCS}w6nf)MBGr%k6!X)N2LJ#UjhXvfO)~)7(2xW`h8-OuZG4~z+$32c|nn9GmHXLc1K{Q37 -f~x$@<*)HVJgtll#E(y^H;aD7!e^_}+OMHUy8*>0+$hZ)p_gZad>kkMWEgKU83Zt1#9oE%7d5sMtcD9 -u7*=@vISd!?oHxw2 -o@fOACBzSIp7!P$*>jBcUV*>D^60K+|9EZD+e;Dqj6J44vH~vpnMwg&D9ylROhz6_VvH_|xzN)3(;-x -c`>kvDO<-Z;hNtfOUBfHbof7)Swjy?W_$^N4*^mSPQls1{FQq+4L9)!yQnC1XJWG}Fwt?cf}2%~_W0> -hUK=^AXdj@M1O=!t!HHvMJ#$-4XLk4G^VcnOBLFH?v-)>;I*JSFs1Ns}NK$G!BgETY#t{&{wt4FSoj( -&e|wl4qVpH0SZ$qCN`8Uawzas_AIz*nB9930L~wj9@kMZ%|7E1QY-O00;m`Rt8hFJ!Y}M5&!^?H~;`2 -0001RX>c!Jc4cm4Z*nhna%^mAVlyvwbZKlab#iPjaCxmedtci~lK^L5KIB@1ADeosqoD{%wZ~WQ2

    6iw-r%Awf3O@)}h~+pv^Bl;mqe -raL0W{`U3#O>Lio#)-Nx2J8TyFdB`0SA$5AaTM#rK+2eTDn=e4-Xnnev^Q0#cot{mj{<;l^T)5AV{z=y-ri-Y51c -u8w=boTqUdvElIr>-)8BecSq8J_C>U{eMbW1IIyophJASjcH&lp!99Z@4t(`58s0M --S&6OuqSAjnF)h?l317FyFDcb2<4{v2sg$z1HcT26@W&VZf(MVV)Pwg@4O`N#BPMGBxbzA9{KE=Z2Dr -C8IHj$h6Du;O1z44S*c@v+x@<3;yWu=?n$c?I$I*_G=urTRHsvLZ_ -s0*jmm(C%eCl-Bvrh%_ZzMe~jI?jqc|6Wh^(_S#B+1DK%=)&qrBq=`7WYR$kl7d6l0>d2LsDweZ;a5g -stUl*LZVbSfNn+c_*HxT_OHN)&l6PX_(-{^0liVc|p$UcWi)zkT=q=x_gZ{Nd#E?C*o~i_72t@y~yK^ -hRT!Pj08dzdwhwD4ze3q*;FV<$m#Xf4W}(Z-X4uuI5b)w#JMH!~S<1MCR2!TV=vc -fJ0&T5WJY?35FH|qp$pUdeV1~4mCQfn>!Dy7CJhlSQ8(xh7YyCV67=(4h|0oAB$;T6M;g?HQ_#SOlOM -2*8cSnXbk%A+>--{FS@t=bbWO_Ty@ajHyHm6NEZi#cm1~T^~vnXkWh^T7y!WkgZnStdmY>OBt_p=vnF -Vo%Tn0gCah4%BN(N|6yEE>!JGbZ|NPwjlN7Eto%PLOK}YGhfois{!1Yk-!+n2xe&L>-4ld*}05fwneW -3rNDj`yn{&5FU6t%$AWGL5HP;Moq#PU&-S;Sb4WnJ2;G~Fek+Ny1|H}4Mym}#XvlY;%9_Z;mw%z!Rmy -NCVbqYo7(#!r9wYsa*HUhDqn9wj><$kEB$(*md=+ykpqdVp~57!a{xqVG$@DkTJZg{fl?A^(2aAN;ET -eLFaK_W@HmHJ}kfynRH$|BXX0g*-M1%`$yA4R{8^Mc!>$j#Ql?UEZOWLAskI`4}q)@+%3SCy=2=SrFZ -->=_een_Z@mqIxML$O#AVh~0T%PDp~7Gs&Z|b2G<+zy+o^HhUdI3JwXaN~yibXH!asfm@NT6IFm(;IN -=ILd3C`^7SABVbUOj1etl`ah&)l7$oI`w{IBcyS6qb@zZtFFwRmaguv7-H3}91ZzBH1b)^O2XB?*8@= -1ufhsnD(iUmr23};av!@{L8<~4Dtps5e4;zl1=>xG|SLbOPQQJm3(on~H=rC7O`U_Lsy;*AlYhwcF%D -%9kX1Sye2t~GQCu%`;AFot3U^{D`)8KgN>A12sZ7qw~GO(iQuOG;hRXqR-@C9QQyyspqpx6nmNp;*ON -^CSj#*`i!jB!gCOraYYJIslV+3l=?sa`cOr_~|;jAc&TuAPlmFs1LzT$zW}$COc@9!I-l!_{_l|z059 -liauXpVC++b~$6lz)VwV<(lX_3 -+zSjIkDMv0-5l9L6q8^$9BR@kLEyDUPuU`KfPUcq*2mTO -zd>=MO9v*g)G9%7-^`bjR@^1At&6;Cwtp($#e_1#P1Pq{*h!I1hcO+`*z?l|l~AIf?VgUx#I#3(J%4( -$@Xu#gx})0NxSav6;7^#T;?Q@4ayrE`(q8(5sU7B(NZw=UE0gSzHooa_X{Cp0OZPf+E#F@&Ft<>^e3Q -w9&zu+`hFbgrp@saj?Qhp%;CoMTC(sWK$1Zv;$(#;ydnJwyvK3y*HcVA%^4V!}$5_x8K+$*mWVD*};< -zJm`qy+mI56-pmWaUdL*|v}qyq;ic#;*os@H%Q|_=6Z9j_9AYULuaARhI!FS3zuf3nDcH8nIz8Nq2uV -8#e<<(Ov6jo$;Ppx|a$ar_$$g@?QV?5Wnt#%xO8=qzln};pqvA&BXbnVUhUP*H_Jzx%wkd4m6l3tzo6 -mV941&+*netmHGr{aPSZz=KNYp`r)>O;^@01&$uBwl~xjs#Spb-C66`S18li0##XlP{TPom`pRYRZ!v -pIL+?4Kgh2-HtIbIF>#xpd?jezEpHKwTG|Y6=q -4W&kUSGHABLO`a8e-%LP9N=CZR)Ji|4gnDUn)q0CWoC<_FlGtrFkRF -JdX!odg>*4~9&IDxGJZVM4LTu7-$t6a`rzo -E73zcL1{@pn&N-dZmnNQbN-=fFz6St~gZ8zGHV(A~S{!i=ci085)p-@&de6a2p}z0Gv!f?wF2+CSe}u -X~kp}C$LV#HkJnAlJ!Bfpo&8{H9VJzKpYzqlCpZGI>e{Cmt<5EENm^*IRAv48>|J2Ehw21*3tzz!c~E -p;kl$f4IvCL5T3e=-%_-BJSTZVPcJ7{KptK_;35Hq2<>tKB~yz^N0ZV*#3`W2z#!=>l2&OPAhD>;;zU -bLg_Ba`s5FSy39g8)ZAXkm+{BDmQU{{q*VV>QcMVc(JibjbbgG8&L*j#-0ZI6VA0jlPIz8WKm>bcFiY -DcXssnJ30F1}71ZsU8>8OHV%>PYi@24N2!-WWH!2g`clrDve_d@k!**~Uru9nvaY`?iQ7S=2>}=2LB~-W3yIP`0Y4)T#*rc&- -Tm&~KY`kIYdc-)t@j+(1;GH_9$K8NI)5)!D9?tv} -INNggS4QzCovthklwvh&qbqy$jt^)K+-J&NB-o<4=A}Q=xQtYaK_|G_D=ca~^zj`OLfv9BtZtKPtrMo{vwgNw%ShMO)T(T# -OEF=b?Oh}}#|MAQO@Mbw16D&HMCa)6TGsV}V^|@?PF#(E69QM3$(ICi*4lR=oL@PLp`dd3-2ES8W+K`)6@)z}Ds&=+ywYS -7U36f=#TVg35?MU*7TkD)##r}Hi>{QB9^ue@~Q>l0XQL4CXQNVwVQ%iL+nPVrks1OOqXAX7fog4cy32 -(GJwl;eWOR&x-6LG#QRSTIjBorc_727I^u#^dTCT_Rd>}|k9UrcPC#CHK^zto3;bQotUi+^fN5s3u#p -t|N%k%xgt$0`bvE5IvOp0axcnwRmryK5+eWJt*uR$r}TziA2`|Iwex4tKA9^mjOD -GP#610)>8f@4d>;?60U;kGM+Cty4v-F$GP<;alAkBlBXHTnKULPj-SQV20VnW%uheFLxaUN*UO=PnbB -+84+SW)+BD9=f4Q<>rTS`;UU7+8<(b<4#E-x-dUO*)>tR%5i{49%lOS6xZ=#8-&(hT)vznj7PgxSk#( -mNHQpdd2ixtaK_13)pNAGG>P>YGxutoFG6)Wsg=CD@++X=QY0^I(l@yf88xDpzt)Qn|iPZB-2elJW*= -ZI;W5;e)?)fY{vEjgeRr#(`Lc~=#d)H^D2ae?talbAKH`}h -?AJX33g5dsJ6k)gi83ZMt(gm0vM!daHXp5SYtyJ&JzevFJ=A_P>4}54cAP(xI4qTkc63ds|7Di3l!tN -`ja0M;(NO(j5WBL2=+kX*l=BQ_(;c|7wVGBy1S58_?)YdGB)N=?QA5O -q89XF<`^1al|C+W=!{*?J;S6)wwLi03r3O0*VeWgc`SLpZ6$d*#t!{I&HwI9mZjHP>K8e6 -5FD`Tw>otII%=q2@ud4T+L%|PO3tfs-&2R65v%R?rw*kC6`)q^L0KYPaa$pBSlpeUOS{dBxeTp=dw#v -6I)CT|nwG{vWAOHXWaA| -NaUv_0~WN&gWb#iQMX<{=kb#!TLFLz;SbS`jt)mT|?8%Gj;7oh)8OFfA6QnWTkuz=UxzyTb@*hDgH1% -3z&qB&DTcG%NB?(WfuKz@9x`j{Egl;XT)30pk6>g&3Xk#%FN2eek3^D`O0IaFBq;p^U=pHP_?@7# -wZ8rs1epnq0Z0F&%E8gJU;_^1yV0-%v80}#v3h*^D}%Xu<`IV9K5mC*vFW{XW_=o=Vz;xP-?Y;CHy+M -F(1YLj{ZphgRvh>vBQWsnZu-`Ussi}D~qB$_@T4Xgou3s-I0ug+P2U7@rO~q_W<&Im^#Xo09k{J -&RS6veUjRmf3+(PYqF|!CEn3op{`<~=-#6&MRPg%UTL*j7LLoG?4uM1q5K?bOC@;Zp=}hQi&tSDF(bA -z89;;SG6eV{E*chdr?>@KK;v9r71EWzyAITMxqCGu>MK3>R#s!Oc1j{1VhW=nx$wH#`&}~r%p||3mbO -L2OD-*z?yxisYfov -egARvYf&s2nhNYm>G<3D2=}KJ==kdQSmvk2BRIBi|rr^-%{WuAB=6XfDa~mKLWE3(Xi7QkW1OR)7c^g -!;R_Yu%)mm15>dzhUnMmJ48M3vAmJ-JGj*>XDK-dg@RwSd_XrJ{72+l$`aC_$n=IlNl*@=!svSvkl08 -oGDj_T6nbPWr&tP-trAiN^C)jNNUGa;2*a)1Y_D`%uPJg%s3cjnL|0hZcw=3RmBvU?m~0p21Q}dk$p; -4H`+_;??j$g)+gPmd*d(OiN2yEG5seSILQvXd+$qUJ!YdTc!@IrT5@c!6u`?TM?q$h=*jdpuXc>yCF&amQ5lWQgTcmzcDI@%JLPnX)2BMKvCwThSMArXjzKWH}wB44I=gz -jrAVaepzfRd^d`^b>5c*Px@)z)G3C*6X;VXEt_%_G$0(+8lx`b~Q|2~9DeR!Gx4|!+YcaKGm0$k!k*p -2)3`qL%FAJuazmRw>|2GE^r?8GthmyqP69uoesjFZUX&D)#1_a_7hRua5i#qpmqm_vzu=!WksD8d72`Kpk@{#7$ -L*uDXq^_(k_k`)YhkQ2BiF0r!b;!&m(8c0|0f%sFbLCIO>$tT9OefO^!=6KAZKYuZSr5rtb`*MEvgvmraUQ~rPEMlIZKC@^2{$j8wHVWPXy63ZeeqH_H5Vjr!032g2(sEiO%!f6@G -5zy->VoiF=yNxnxX6*RFUtU2&hKq>JVmhPKxYWgfB8dKAo_>r`6QMvjaF9gqHwON%qSJjGR%4A5tG++ --x>E=nHDp=>b>pLr-Yx{{mL#_rGMB#vs-Rd={=gfF-@WVo>0Q(dtljFE9;^WQ~$~^D9_B6@TYJh3%NrTFX2{ojDVm=%#5&@^@;GVAxhzqXXB`UFx+aH%{ni7jGKlV^q -V;-oI2e^Ew_z*x^m!67rcxn40%mX==p(_;OSp@BtGAzKO2Pt_SA`j7)QPYAK7sAvc%;2h$iW9E~oNgR -ST%0ys{5#3dIVc#8e0&gGqVi}nR1h;sK@!HFH_EK3a~_$iuT)P&IlqqBxZ|8C>Dg<9N4v2gmrrvin#2 -#2r$J9oQKMjB_1-Dr>9D?v1zi>|ISo;7;u`ok`l$kPP?7#DmQF++w}VuQPc^K`WWv=ac7CP}@6aWAK2mnY{22)Z%hR8(=005~f001Na003}la4%nWWo~3|axZsfVr6b)Z)9n1 -XLB!KUukY>bYEXCaCz-o{chVv68}Fy-eE6BK?#)@C%N`qA`W0XN@JYk1d-F?E)J*_xw2SOOM$zztSb` -aH4eCYxjf0u><790kgX&=peQONvCN&Bot^p3#}2bYqAX7MML-HU8}8k`bMM~0yLay1A@EtTDdT!s=qD -eXkEJ@BCxXBqN?xtyJmVx;EK{~%TvD09ui1>qIU|#wpC6q4{396|i9|@sW17cW%Hz3|%i#WfyP+?ZEb ->=#DpwbNmS5a|GV#fnG4gtJ@btxq%(9%sOwuG3zSSg%vgJBYF6J^INA@duxclHCnXbt=S%5ZUx=gqsP -m_po!2)tPemWomgr6KAjZVjH>BcCtJX?@3oE5UjSs3C;vs{vbC!jP7(?qhIrUFUL5+$i+Q?gIIUH?1(fu|quka4zPgwq8BHeQ*J=I}I=p -nRc9~~c)lu0nYATlG0lSC9fdocVbViSz9WHBz%;lC=pENM;`MDGE#oV?MVG>?2kmNW1-7eGNcTeXSma -Zm`@2>~?GnxP`Y1aQVhB9kk&CEjnCzDVMSWp?w5eN`pRtVAX@~uLkBjBbY#VAchrc@jd3h@B! -0FoS#fh?PevuF>_3sc6STJ#a$5MleEu+NAY{qiP2}H#KCWK(Y)TN(0RXc)D -PLRTw`{o;vL2WqofqH$ik0Pcty1a?W#k>*FCx -6**3frF7?z%~FElK4y{Ia7xrEpHNLSm>)8JSTb6*?%lSv>R4_PoAT+=n#iJ -g$O0&9cj4*;Bx^VP0x=0*eZbuziVfNacwX8tQ%>W$09lqfa0IEy(18NtbckxQj9#v85bZiXq4WNCW6D -vOJOVh1qmmEHQ~gu$!cg897Y^KEaq`%{-&XFo|?$m&&)0h=M2u?*(ykY3BZYXF2@)KUHDW#EP=33RP|7@khv07lC;IyjUYatxIrS!hX -BKbv)FT}R2EbP`#MCL(9jUKtcMAoWfc!VfHg!cRaFkn(cLOsDm@^M>h`k(5Lnl^RgT3tlms|cnL~&XG -0%!L#!yv#fM1tWsR`TbR>U^}=LmN;cWi5sXSA$DIpoUzZ;{{~aMT0M_^o`np) -5r!jSi7HfXCeR^)5mAS|i8o6Z+!RpAO%0wmRsGG}B`r;$?FvZ1t|KUE@Gqzg&9CrJl(|QFp5@yHD?oH -k1(h;yTW0{>Q|Sq>-;R?OhZXO*)UnR>dFpLQK)%U6@=aT#{tW<8cCN6et?WSJHGm -#^A&J+Gvffu4ivqg?LEfA_8}6AdKm|<%W``gtdoxvz6oxA9(i6T<(E7==kSqvPfV%C$5rv*3iD;@biM -ijn=jagPW{gS{wrFsK0%UdHnyl18#X|w7ahgm^P<}9xeS|-bVTT4f@q;&~U{-KIr=iZ-1=gy3(gvW4Q -qVP#Vb~Kao#`Z1O9Boekis`PPTQ)s(oRA(Gw987w#?0D9ia9em)D+e#1jNnxu>}$1%968?6mG)4Y=o{CY%a=l9?4z8iFP4K0P-qM)|ubsVKXAS-Abz-()T8)&o0t}qqYTd1P)-P)_4 -2uX7(kheGW&aa<6gTJG$f@_n5+3@Yd;N2~vMksExsKf0=jX^+1Om&tUrt -;_q80Goea^$_xf<8nx}kFp+U?&U0B{OsAUjp<_pF_VVNO&=!9ZeF4&+n+q6q8XVSt3xz&EH3Q8TNm4$Rft`nBVopvm*SP(geN;?fMXT>EK>MmCIRo8Vxt?!q)MgKIV&om@>pjsz_7=%r -DbcwG;n)%0QVP*C-r8ByK@X|Dmk&T(DT2oG$(`-3x3f)`yt=Gfk^QR9>C -?ymV1@nk@xP|VYH1s4Y_qhs!^>g$<2F*FWr)rmz2pIcj=gZ?oPxm@%X=~2sM247Gk+Grs{Ie&!J$7!N@qNbK;EN*)KWcUte)+_rlA+Z@XsR#G -Zp-nFOMqfpHXO3Tp$3Z%w!U!Vy3yY<7+*&a4&o}3@QB;+yXr?!E`%w?QYy*UO~A?&$6=(}6n4!MT;Z|!WyQf)utGYa1D3dm5Tj2lMsm^@PRO+1QrnnjlZa7-m_K)!~}D -pnhMH>}|XvN{$v&3Z4ye4Eb!{f4~L<+rYBWm1(b>k~H%^=sFb>R^@777UtE+1BVb40M!K+n;P(Qa3c4 -f3VI`OY?p6|BHg4G3<0x+YRYz!`RZH{9UE2n@5cuEx>j+mquJ|m{oS+oZTK<%=XufuKIsaO9KQH0000 -807zB_Q+e`6jSmI@0Qw^U03rYY0B~t=FJE?LZe(wAFLz~PWo~0{WNB_^b1!URVr6V|E^v8`n!$3TMi7 -SYTea^naSpodxHKRnq^caUyFR4K$;CPBjY4QFjfFr3D3+5-o;`q&n3?_u;XSO?d}{vb?irdcKRi5q{` -C11tAF0*T4qVUQQ5Y9Oyjjo%gcrT=+E^#zsE;*{Sv!;hgCVNc2X5Aix2YgO0JUp_))0su3E8g*I$`86 -&_oEuord6Gxic6Ro3CDN@P~b75n<~{R=ClWY52Sd-~($iM{3p+sG&z&mSt4bxS|Bp{qeuyiT#A*7$wlb4NT**x%;IO}_e>{FP&Ypk$`tZ-X2$H%SB7IlneHza(Iy -dCl>*LI9_vOnkJ@{sezG<4~- -o(PR?F5&J#q#8rEdDj&qQYMGE-bK!upVPe0aXb;pwI$sl)qS$5C2uj}?o{RwNuKMFj7G1$Bk?m1<*gpxJc9b3wAXaAcE^i~DQ8OsQ$?}v%@)TKNMdW -Q4hj_n-ph9+XUC4KP7x$!o9jz#&ISTRG5s7zkNV4gV@kwt!L^>-uq&XUM_m0Hpd{6$R%2S+U0n_NsOlG4bFkuiyspK{2Cx=&n_JOH -ARK1y%*r^Lf~##(AHHr8YqeiSC=bLQ@F$eK(8l)5hx`GQQ_+L1Zd6f3rLrD$^|XUv0?P5^gdT%VeiAn -$cr0Qe?-#;N}<68ptyZQNJXP4e!|pATjL>4R95BXP7gEwp;TXm_2jk8M7@ZhBOGIL0}ES)*# -#(dN$5V6`lRZ85hg>Z9nO3Kl6#pMA4mz*;WCaBsthn(BsCz-i}*Xjt1Kd3#nrVdnX{?Vl_*jE)Yp`dGkZnmiZPHlOS -_F<-2gmf%RS$I9Hw#Cx)a@|4bjJZq^2X`y*rtA$pnkP!UU08|t;rwZF>4rMJfY@A+$BvZ{H5KY2ob -ov28Z#)4qsRrfyB2i%xbblcls4IN7fE+L5zed%m!bQxmE8V-Q}r@cIZe5afd(5nvF)L-R3fB6R9zA>C -nTMc+Wq9QmE27|>>1;Pn*o#hbov3Z6Og3BWeZd-9Urq-I}eR9%?Cd@8h-l2YAAR16w*Ye>vyz@qkf -A&nPXOqEd*HM+PiY>-;Isdj~TB2iNj#cb-Dr=_t-8r81gjiB{aYz6IVyMs1=%pvA$>*VjvCPyNCF{d_ -{Vt*QU=BH8?d?R1$2hT=(m>K4p{`d2z{{c`-0|XQR000O8NLB_@sY-ZDN&)}?R0RM4Bme*aaA|NaUv_ -0~WN&gWcV%K_Zewp`X>Mn8FKugVVPa)$b1rasy;H%C+At8kuf#u0sgRwDhIWrg9J;$4R-!$W9*|fRnP -dQO9ow~y09D;@uN}vvh*f*5BPEXg=8fk)Pru*q-Slq2j{~kzma5`%YxDZMU~3dMZoRxVQruVEqGX0S1 -h>OWnn(h*s`di&6frK9J{i8v=<*!!^@UTb9>JX_@{oH>mn(Z;A6_C^T4h8E)gltz!jV~N_qW3xOpMw#oN+~AKrT6Yy3o(ea>tVQD -rp$=%Mb;fIuwKQ=H;v!5Y?JSSjEP@QWy^-x!N9*;)pfB|a6Q5?rS(w0*5b|^`{L06FxR_!-GYu&STGN -~gesTkn)&J4Ex3E|&;6Z^@4zS|xO<4Q3;}$ktAowraJ5@8sOD4qWtWFgUknU}+Pl0Uq>25lkdzpUrZo -E*dc&N5OFJAl)gBsL^UKrTGvMd+D4^7FQWWz21nt&wQk_45=>H?j0=um9w54lz51Y9;((|gYW=qbmh|W%VqC~nRXVX)e3EtEZu-##!0%X-9Yj!LIO0S5YQ9o;I@4|=8EeIqrH2dQg -=6G}{E81lx;We=1f%Wg-kQaY-9g7W;{BpeO= -YQG_leMNu;@i-M%S@~!9Sx#P&rIXxbYl61M%SmuWvbBArN%y!hZTClXS>NikJ0|XQR000O8NLB_@LI9 -vP#RUKWJQ@H1ApigXaA|NaUv_0~WN&gWcV%K_Zewp`X>Mn8FLY&dbaO6nd9_!|Zrer_-5c;f3=#yS0! -ffuB(Vf|VZ{<)KyeDlSy=`#q(=5MG${;+w!G=0{gG}96lnL|rTvnAN$mN;yHxn4z&|=^D9V5U(B? -y}9K>^wHd+qh9|A`HyHu@8Sr}@QOxSJfs1M5;8=i*;yMUgrMp9$MMB%Ea?}7V;UxsU7NpT@g4HKWy(` -VJP*;kRm?a_BMO!fF9gdN4wFo@Yb4w-j=!d>HkzJ}#?x6F$OWQ}q$l7ike*qT5BiNV)%u)A0V8)L;y6 -5$@~myINvDXlFPD?!maydTU_q7$CkbKPW0)o+amhL$D^BC6jh1N?sJpkA-6U{%`}INGwT4PJXOF|&3M -1~8rIm;xMj5|_WCXmXT~9*ccJvyp7{0l~LlngjG53U7;=)pND$NF>F=H`voin-sS+3u{NxBYtlWVi~D -`Le9u@9PDvlHb5q|U;1WN13AZiMd$Iypglp;q?GF0z-Ct!3fWcM?Tg%Az@&M*=YC+p>chh$iSFj)*wJ -A0PQGWR`Sxx7pL*ek;P@+BuzlJU>Sdw<4vJ6%I(2%VnR=l&o#y1C18(L(=IVy*sM6lqPZK`1swR)87p -jVoswSG1Jq_^NW4-2;+=jnwbCn>!M%up7cg1j>1P2U`PcDg)B-ar}vaUc1wAH!?2tSqQc1~K)~SFOx$*{XtHSvU8uq_y4CC6|%m}*2A(U_xjEKjv6^=4-AQlqBT@{gCkWQgpwOZBK)Bz|! -dCrMzDfVe3RjT+ewF1))r;dslD&)3I2;WSf>Rq6Tfmp}6Alf7#_Nl}sBiz+{V)rl2}JlJB3-pn9pvuE -HPoCK6+Cj9!%CeiO2S?XiD$XH{P$Z0v*pa;rt(dhH1QmeL9Ovdm9`d)9oCY$Ly{r5hxRP^6>Mq^7&gO -Z6-L9#7CJvW%I^zPnO6Q}U*45YP -1-L==-Y(Z6tIynk2XoDgUIkV1)NqSBeN#p)}9dew0IVCO6LLz=usQ24B+d}*M0nXzFrJoLp6h^-V(0h -5Z~u;0}uEZuGleCi{YqHq{|P21TLCJ+zrHkK_wpK63~fzLuea?YqVr*#lcp?8j{h~1o>=R@nGFlm!WD -&waUYT{{c`-0|XQR000O8NLB_@#d)xMn8FL+ -;db7gX0WMyV)Ze?UHaCxPdTX)+;6h_~(R{q1_5NuP&SWc5zrUuenAW%xE3kBLDMl)w(fh-$ICJC4Rc6 -2-A`D*;og`W1A>)B^UT1$IEEp(LJjKwN92czAcR;#tUv%4dT=axcB>h7$67pyW$15GAMNY?}2Y=3x-( -?mq`WlVEQa+ybqL@bQRXC&?p%JmMK^#pI!=ZRyrSl*}6%`6{_Ge$8Scta81i)l13mYT|Clr+QRNKul} -SUjGd_e4e{o?M+>Je^($vq*)eTt;zLt=<@#bTJn}U{?7mr64HNT%@^JB~g(H1#y&9D&wpi+H{res%qH -X+1uMI(kfzcdVN*3saR%N-PWl`_N$;fW~IWl_M}cmvFV8@S+4S)pfp{i*`%H2X{7RYIYBf}N=0@_vvX -g~WIC72pjiZ__iPD+T!t}q-Cc{>|9{tJk+*iOT5(sd#Z{ux`rzY>D&v$3v)RMjZ>v#pOJqE`EDnU;wL -axK{Vhd$Ie5J#<8#`Uans{w{9pBbr;M?-knvjuekY -jb*e|Lw;?%olnUQ~4@XOP31-QDPQiBHUNus%YxeDb4yF3{Ty2X}wXNps3s@{HeHyE_n>^V -Gi_|V~p4j(yu?C^=hBg?s^#OV(mR+dwzl^ix}_MFT;Cv(rq+;cMboXkBZbI-}#b29fv4*L#Ehn?&_<* -;_x$=|d23x@X?S`2#(?=$Q(e9%Cv-D+Ao+|_0Hkl_JCkKur!&+rk0EvBucEu*cWEugKQEuF2KEt;*^n -BilFM+_5&PZ&OB_>AF{;W5J*!#TqR!zIJ#3|}x@F?`AJ6~hyTuNj^)e8X_f@GZkLhAG2yhVK}@XL!Nz -1H+FDKQX+t_v97RYlfd00)}50>~*wv(OyJ*3+)xO_wR;b#tEem? -m5;OB#%4}L!Q`QYb+pAUXM`1#=HgP#w6KKS|I=YyXQeiHm7_(|}S;3vUPf}aFG34Rj%B=|}2li(-8Pl -BHWKM8&z_=VsXf?o)JA^3&h7lL01ej)gU;1_~l2!0{>h2R&0UkH8*{1o^p@KfNYz)yjn0zU?y-E^v8JO928D02BZK00;m`Rt8htjO)#E0ssKb1ONaJ00000000000002Cfh_?50B~t=FJ -E76VQFq(UoLQYP)h*<6aW+e000O8NLB_@0yoD{#Q*>RA^`vZ3;+NC0000000000wt>t8003}la4&FqE -_8WtWn@rG0Rj{N6aWAK2mnY{22%jagHc-n002+|000>P0000000000006duy959LaA|NaUukZ1WpZv| -Y%gD5X>MtBUtcb8c~DCM0u%rg0000807zB_Qyla~{9p_K0Iw(j02%-Q00000000000Jecm1^@tXX>c! -JX>N37a&BR4FJg6RY-C?$Zgwtkc~DCM0u%rg0000807zB_Qz+I#U0MqO00k%j02TlM00000000000Je -eU5&!^jX>c!JX>N37a&BR4FJob2Xk{*Nc~DCM0u%rg0000807zB_Q=ZdihZYb305CTI03HAU0000000 -0000Jed19smGvX>c!JX>N37a&BR4FJo_RW@%@2a$$67Z*DGdc~DCM0u%rg0000807zB_Q#!PI#WfHB0 -RJ=q02=@R00000000000Jed}E&u>c!JX>N37a&BR4FJ*XRWpH$9Z*FrgaCuNm0Rj{N6aWAK2mnY{ -22;P&Z;SN+003+O000#L0000000000006duGd}KlXc~DCM0u%rg0000 -807zB_Q<<9bBQXg808ShL02%-Q00000000000Jec!KmY)6X>c!JX>N37a&BR4FK~Hqa&Ky7V{|TXc~D -CM0u%rg0000807zB_Qy_77@&E|{01p}f03-ka00000000000Jed|NdN$FX>c!JX>N37a&BR4FLPyVW? -yf0bYx+4Wn^DtXk}w-E^v8JO928D02BZK00;m`Rt8f%eSwlQ3;+N`F8}}@00000000000002Cfd*3m0 -B~t=FJEbHbY*gGVQepVXk}$=Ut)D>Y-D9}E^v8JO928D02BZK00;m`Rt8fLM#&m&0001p0000T00000 -000000002CfpuR10B~t=FJEbHbY*gGVQepBY-ulFUukY>bYEXCaCuNm0Rj{N6aWAK2mnY{22-;6EjQ^ -0005#H001KZ0000000000006du9bf<|s9smF#00000000000002Cfk$Wn0B~t=FJEbHbY*gGVQepBY-ulIVR -L0)V{dJ3VQyqDaCuNm0Rj{N6aWAK2mnY{22-wOBb90%003-q0018V0000000000006duVR8TfaA|NaU -ukZ1WpZv|Y%gPMX)j}KWN&bEX>V?GE^v8JO928D02BZK00;m`Rt8gxBrwS`0RR9K0{{Rd0000000000 -0002Cfe4WR0B~t=FJEbHbY*gGVQepBY-ulJZ*6U1Ze(9$Z*FvDcyumsc~DCM0u%rg0000807zB_Q!wL -7pqm5$0PYC@02u%P00000000000JedAk^lg3X>c!JX>N37a&BR4FJo+JFKuCIZZ2?nP)h*<6aW+e000 -O8NLB_@(CXWN76bqQjS2t&AOHXW0000000000wt-HU003}la4%nJZggdGZeeUMV{Bc!JX>N37a&BR4FJo+JFLQ8dZf<3Ab1rasP)h*<6a -W+e000O8NLB_@pj-@HU;qFBdH?_bApigX0000000000wt?}?003}la4%nJZggdGZeeUMV{B?y-E^v8JO928D02BZK00;m`Rt8fE?fN-e2mk;b9RL6y000000000 -00002Cfs)by0B~t=FJEbHbY*gGVQepBZ*6U1Ze(*WV_{=xWiD`eP)h*<6aW+e000O8NLB_@lGm=-GXe -krQ3e129{>OV0000000000wt*_!003}la4%nJZggdGZeeUMV{dJ3VQyq|FJowBV{0yOc~DCM0u%rg00 -00807zB_Q$Ahdd*}lI0KE$U03-ka00000000000Jede-2eb^X>c!JX>N37a&BR4FJo_QZDDR?b1!3WZ -E$R5bZKvHE^v8JO928D02BZK00;m`Rt8h0VV`vG2><{LBme*>00000000000002CfyChe0B~t=FJEbH -bY*gGVQepBZ*6U1Ze(*WV{dL|X=inEVRUJ4ZZ2?nP)h*<6aW+e000O8NLB_@b+&m5y9fXP!x{hp9{>O -V0000000000wt@KT003}la4%nJZggdGZeeUMV{dJ3VQyq|FJxt6b!RScc~DCM0u%rg0000807zB_Qxa -O-e5(Zj0N@h<03rYY00000000000Jeef^Z)>GX>c!JX>N37a&BR4FJo_QZDDR?b1!6XcW!KNVPr0Fc~ -DCM0u%rg0000807zB_Qz$V>TfYMU05uB$03ZMW00000000000JeeK`TziMX>c!JX>N37a&BR4FJo_QZ -DDR?b1!CcWo3G0E^v8JO928D02BZK00;m`Rt8hD-HR{m0ssKF1^@sa00000000000002Cf!O{40B~t= -FJEbHbY*gGVQepBZ*6U1Ze(*WXkl|`E^v8JO928D02BZK00;m`Rt8g!SO_%p0RRA%1ONaY000000000 -00002CfdB#l0B~t=FJEbHbY*gGVQepBZ*6U1Ze(*WXk~10E^v8JO928D02BZK00;m`Rt8f$EO;R51po -jz6951o00000000000002CfiDCB0B~t=FJEbHbY*gGVQepBZ*6U1Ze(*WX>Md?crI{xP)h*<6aW+e00 -0O8NLB_@K9;td1RDSVQ*HnNApigX0000000000wt-d(0RV7ma4%nJZggdGZeeUMV{dJ3VQyq|FKKRbb -YX04E^v8JO928D02BZK00;m`Rt8fCPxGfu3;+N+F8}}@00000000000002Cfte)%0B~t=FJEbHbY*gG -VQepBZ*6U1Ze(*WY-w|JE^v8JO928D02BZK00;m`Rt8f=TOmqc2LJ#|761Ss00000000000002Cfg&; -i0B~t=FJEbHbY*gGVQepBZ*6U1Ze(*Wb7f(2V`wgLc~DCM0u%rg0000807zB_Q^^?GN&X1{01zMm03H -AU00000000000Jed@IROB0X>c!JX>N37a&BR4FJo_QZDDR?b1!pfZ+9+mc~DCM0u%rg0000807zB_Q? -bp7Kcxf!0Q?OA03!eZ00000000000JeeoLjeGAX>c!JX>N37a&BR4FJo_QZDDR?b1!vnX>N0LVQg$Ja -CuNm0Rj{N6aWAK2mnY{22(vy9CjlI007+>0018V0000000000006du-$(%faA|NaUukZ1WpZv|Y%gPP -ZEaz0WOFZfXk}$=E^v8JO928D02BZK00;m`Rt8hNYU{N`0RRAR0{{Rg00000000000002Cfj>|I0B~t -=FJEbHbY*gGVQepCX>)XPX<~JBX>V?GFJE72ZfSI1UoLQYP)h*<6aW+e000O8NLB_@E6!b_8v+0T+yn -psBLDyZ0000000000wt>h|0RV7ma4%nJZggdGZeeUMWNCABa%p09bZKvHb1!0Hb7d}Yc~DCM0u%rg00 -00807zB_Q(_W8_(}l)0Gk2;04M+e00000000000Jec7Q~>~RX>c!JX>N37a&BR4FJx(RbaH88b#!TOZ -gVebZgX^DY;0v@E^v8JO928D02BZK00;m`Rt8hI5bZDj1ONba4*&op00000000000002CfwWZt0B~t= -FJEbHbY*gGVQepCX>)XPX<~JBX>V?GFLPvRb963nc~DCM0u%rg0000807zB_Q>-@D5Agv20Ko(R03-k -a00000000000JeekS^)rXX>c!JX>N37a&BR4FJx(RbaH88b#!TOZgVepXk}$=E^v8JO928D02BZK00; -m`Rt8g%)Rti)0000W0000V00000000000002Cfhb)80B~t=FJEbHbY*gGVQepHZe(S6FJE72ZfSI1Uo -LQYP)h*<6aW+e000O8NLB_@$_gbhC>8(!14jS=AOHXW0000000000wtMd?crRmbY;0v?bZ>GlaCuNm0Rj{N6aWAK2mnY{22;p8u$!170001y001Qb0000000000006du?Q;PD -aA|NaUukZ1WpZv|Y%ghUWMz0SaA9L>VP|DuW@&C@WpXZXc~DCM0u%rg0000807zB_QyT{9*8K$l0DT$ -&03HAU00000000000Jee1mH_~8X>c!JX>N37a&BR4FKKRMWq2=hZ*_8GWpgfYc~DCM0u%rg0000807z -B_Q`GLVv!)FI06;AO03!eZ00000000000JebvodE!FX>c!JX>N37a&BR4FKlmPVRUJ4ZgVeRUukY>bY -EXCaCuNm0Rj{N6aWAK2mnY{22&~baixTY;!Jfc~DCM0u%rg0000807zB_Q|5qZ7%d6_0LdQ!03`qb0000000000 -0Jed&vjG5bX>c!JX>N37a&BR4FKlmPVRUJ4ZgVeRb9r-PZ*FF3XD)DgP)h*<6aW+e000O8NLB_@uH!H -G8v_6UUj_gG9{>OV0000000000wt*zR0RV7ma4%nJZggdGZeeUMY;R*>bZKvHb1!0Hb7d}Yc~DCM0u% -rg0000807zB_Q^N(mt0@8i09Xb903rYY00000000000JedA!2tkpX>c!JX>N37a&BR4FKuOXVPs)+VJ -}}_X>MtBUtcb8c~DCM0u%rg0000807zB_Q_Tu%cm4c!JX ->N37a&BR4FKuOXVPs)+VJ~7~b7d}Yc~DCM0u%rg0000807zB_Q?V|toOK2O0O=F}04D$d0000000000 -0Jec2%>e*#X>c!JX>N37a&BR4FKuOXVPs)+VJ~oNXJ2wbaHQOE^v8JO928D02BZK00;m -`Rt8g?y@0RV7ma4%nJZggdGZeeUMZEs{{Y;!MjWnpq-XkT+004sr001Wd0000000000006duWB368aA|NaUukZ1WpZv|Y%gtZWMyn~FLPyVWn*+{Z*E_3a%E<7E^v -8JO928D02BZK00;m`Rt8fBM~Gq71ONby4*&oq00000000000002CfrI-20B~t=FJEbHbY*gGVQepLZ) -9a`b1!sZa%W|9UvPPJXm4&VaCuNm0Rj{N6aWAK2mnY{22=MpepcuN001!#0012T0000000000006dun -*ag;aA|NaUukZ1WpZv|Y%gtZWMyn~FL!8VWo#~Rc~DCM0u%rg0000807zB_Q`c!JX>N37a&BR4FK%UYcW-iQFJE72ZfSI1UoLQYP)h*<6aW+e000O8NLB_ -@t7^wRz6<~Wxh?03HAU00000000000Jeb!J^}!6X>c!JX>N37a&BR4FK%UYcW-iQFL -iWjY;!Jfc~DCM0u%rg0000807zB_Q^X>+qR0XO06PZ&03QGV00000000000Jeb&L;?VCX>c!JX>N37a -&BR4FK%UYcW-iQFL-Tia&TiVaCuNm0Rj{N6aWAK2mnY{22%h40006200000001Na0000000000006du -4@Uw3aA|NaUukZ1WpZv|Y%gzcWpZJ3X>V?GFJE72ZfSI1UoLQYP)h*<6aW+e000O8NLB_@XfzNxeFgv -kNEHA8ApigX0000000000wt-Ve0swGna4%nJZggdGZeeUMZ*XODVRUJ4ZgVeVXk}w-E^v8JO928D02B -ZK00;m`Rt8g2$BnNQ3jhF7DgXc?00000000000002Cfe%gs0B~t=FJEbHbY*gGVQepNaAk5~bZKvHb1 -!CcWo3G0E^v8JO928D02BZK00;m`Rt8gzN^Q@p8UO&FV*mgn00000000000002Cfn-?%0B~t=FJEbHb -Y*gGVQepNaAk5~bZKvHb1!gmWpH6~WiD`eP)h*<6aW+e000O8NLB_@000000ssI200000DgXcg00000 -00000wt-M|0swGna4%nJZggdGZeeUMZ*XODVRUJ4ZgVeUb!lv5FJE72ZfSI1UoLQYP)h*<6aW+e000O -8NLB_@$&Tsf6#@VNumk`ADgXcg0000000000wt<>-0swGna4%nJZggdGZeeUMZ*XODVRUJ4ZgVeUb!l -v5FKuOXVPs)+VJ>iaP)h*<6aW+e000O8NLB_@z2*;r>H+`&#|HoaF#rGn0000000000wt@F{0swGna4 -%nJZggdGZeeUMZ*XODVRUJ4ZgVeUb!lv5FKuOXVPs)+VP9-zXJKP`E^v8JO928D02BZK00;m`Rt8f+v -8tK<0RRAa1ONah00000000000002CfiQXk0B~t=FJEbHbY*gGVQepNaAk5~bZKvHb1!0bX>4RKcW7m0 -Y%XwlP)h*<6aW+e000O8NLB_@(U02hCbYEXCaCuNm0R -j{N6aWAK2mnY{22%)=2<#yO005%}001)p0000000000006duXMq9$aA|NaUukZ1WpZv|Y%gzcWpZJ3X ->V?GFKKRbbYX04FJ)wDbYWs_WnXM%XJKP`E^v8JO928D02BZK00;m`Rt8fbjl%N81polK5dZ)x00000 -000000002Cf!Tus0B~t=FJEbHbY*gGVQepNaAk5~bZKvHb1!Lbb97;BY%gqOXJKP`E^v8JO928D02BZ -K00;m`Rt8g3tF8-^A^-qAb^rh=00000000000002Cf#rz;0B~t=FJEbHbY*gGVQepNaAk5~bZKvHb1! -Lbb97;BY%h0cWo2wGaCuNm0Rj{N6aWAK2mnY{22&8EDdeOB003MtBUtcb8c~DCM0u%rg0000807zB_Q_(1c2uBeB0IWX%03iSX000000 -00000JediumS*ZX>c!JX>N37a&BR4FLGsZFJo_Rb98cbV{~tFb1rasP)h*<6aW+e000O8NLB_@woZ)u -8595j5Jmt19RL6T0000000000wt*zV0swGna4%nJZggdGZeeUMa%FKZa%FK}W@&6?E^v8JO928D02BZ -K00;m`Rt8hTr-vb-Apigce*gd=00000000000002Cfq2#e0B~t=FJEbHbY*gGVQepQWpOWZWpQ6=ZgX -^DY-}!Yc~DCM0u%rg0000807zB_Q(}4IOLqtW08$c!JX>N37a& -BR4FLGsZFLGsZUvp)2E^v8JO928D02BZK00;m`Rt8fdsfntX1polp5C8xm00000000000002Cfd~Nu0 -B~t=FJEbHbY*gGVQepQWpOWZWpQ70a$#d@WpXZXc~DCM0u%rg0000807zB_Q)siK(astG0D@lt03rYY -00000000000JeeN1_Jc!JX>N37a&BR4FLGsZFLGsZUv+M2ZgX^DY-}!Yc~DCM0u%rg0000807zB -_Qvd(}00IC20000003-ka00000000000JeebAp-z#X>c!JX>N37a&BR4FLGsbZ)|mRX>V>XUtei%X>? -y-E^v8JO928D02BZK00;m`Rt8h=hJO(G0000#0ssIY00000000000002CfiNNi0B~t=FJEbHbY*gGVQ -epQWpi(Ab#!TOZZBeCb7d}Yc~DCM0u%rg0000807zB_Qvd(}00IC20000004o3h00000000000Jec=B -Le_%X>c!JX>N37a&BR4FLGsbZ)|mRX>V>XY-ML*V|g!MUukY>bYEXCaCuNm0Rj{N6aWAK2mnY{22-h( -nQbZKvHFKlIJVPknOa%FR -GY<6XGE^v8JO928D02BZK00;m`Rt8f500002000000000l00000000000002Cfh#xz0B~t=FJEbHbY* -gGVQepQWpi(Ab#!TOZZC3Wb8l>RWo&6;FJE72ZfSI1UoLQYP)h*<6aW+e000O8NLB_@Vg84_V+8;JIu -!r_D*ylh0000000000wt;#$0|0Poa4%nJZggdGZeeUMa%FRGY;|;LZ*DJgWpi(Ac4cg7VlQH0b7d}Yc -~DCM0u%rg0000807zB_Q=1;U%RLbQ0L4oH05Jdn00000000000Jec9J_7)7X>c!JX>N37a&BR4FLGsb -Z)|mRX>V>Xa%FRGY<6XAX<{#9VQyq;WMOn=b1rasP)h*<6aW+e000O8NLB_@-^JqwVjBPer)vNJE&u= -k0000000000wt=!w0|0Poa4%nJZggdGZeeUMa%FRGY;|;LZ*DJgWpi(Ac4cg7VlQT4V{~tFc`k5yP)h -*<6aW+e000O8NLB_@JX!>$83q6VGZg>;Hvj+t0000000000wt--40|0Poa4%nJZggdGZeeUMa%FRGY; -|;LZ*DJgWpi(Ac4cg7VlQTIb#7!|V_|M&X=Gt^WpgfYc~DCM0u%rg0000807zB_Q)E2rriu#y0I4AW0 -51Rl00000000000Jee7aRUHwX>c!JX>N37a&BR4FLGsbZ)|mRX>V>Xa%FRGY<6XAX<{#Ma&LBNWMy(L -aCuNm0Rj{N6aWAK2mnY{22;x-u`5FZ003QbZKvHFLGsbZ)|pDY-wUIa%FIDa&%>KE^v8JO928D02BZK00;m`Rt8g6;y}*$1ONc_6#xJ;000 -00000000002Cfi-~x0B~t=FJEbHbY*gGVQepQWpi(Ab#!TOZZC3Wb8l>RWo&6;FLGsZb!l>CZDnqBb1 -rasP)h*<6aW+e000O8NLB_@-=A2?-V6W$D=Gj0F8}}l0000000000wt;?z0|0Poa4%nJZggdGZeeUMa -%FRGY;|;LZ*DJgWpi(Ac4cg7VlQ%Kb8l>RWpXZXc~DCM0u%rg0000807zB_Qvd(}00IC20000003QGV -00000000000JedtlLG*7X>c!JX>N37a&BR4FLiWjY;!MPUukY>bYEXCaCuNm0Rj{N6aWAK2mnY{22+E -`Tvp%#0012X000{R0000000000006du=#v8gaA|NaUukZ1WpZv|Y%g_mX>4;ZUu4;ZV{dJ6VRUI?X>4h9d0%v4XLBxac~DCM0u%rg0000807zB_Q{)uV+n@j -d0Q~>}03QGV00000000000JedJqXPhNX>c!JX>N37a&BR4FLiWjY;!MUVRU75X>DaLaCuNm0Rj{N6aW -AK2mnY{22&AWjUM;}008I=001HY0000000000006duVx$8AaA|NaUukZ1WpZv|Y%g_mX>4;ZWMy!2Wn -*DV>WaCuNm0Rj{N6aWAK2mnY{22<{}Dgnd;0003D001cf0000000000006dunyCW-aA|NaUukZ1W -pZv|Y%g_mX>4;ZWNC6`V{~72a%^8{Wo&R|a&sc!JX>N37a&BR4FLiWjY;!MUX>)XSbZKmJUtw}*b1rasP)h*<6aW+e000O -8NLB_@SLZr?76JeOwFCeF9{>OV0000000000wt@by0|0Poa4%nJZggdGZeeUMb#!TLb1!9XV{c?>Zf7 -oVc~DCM0u%rg0000807zB_Q*QaK?@9sy06GK!03rYY00000000000JecqvI78cX>c!JX>N37a&BR4FL -iWjY;!MVZgg^aaBpdDbaO6nc~DCM0u%rg0000807zB_Q>k}dXZHvI0J|3e03iSX00000000000JeeKv -;zQeX>c!JX>N37a&BR4FLiWjY;!MWX>4V4d2@7SZ7y(mP)h*<6aW+e000O8NLB_@a{NbJX#oHL6$1bO -AOHXW0000000000wt*480|0Poa4%nJZggdGZeeUMb#!TLb1!CTY-MzLaAk8YaCuNm0Rj{N6aWAK2mnY -{22;9sjD$x8006!W000~S0000000000006duxW5AcaA|NaUukZ1WpZv|Y%g_mX>4;ZXKZO=V=i!cP)h -*<6aW+e000O8NLB_@lHhfo7zY3V)D!>!9RL6T0000000000wt+dt0|0Poa4%nJZggdGZeeUMb#!TLb1 -!INb7*CAE^v8JO928D02BZK00;m`Rt8fjCuGXA0RR9_0{{Rm00000000000002CfsD)p0B~t=FJEbHb -Y*gGVQepTbZKmJFKKRSWn*+-b7f<7a%FUKVQzD9Z*p`laCuNm0Rj{N6aWAK2mnY{22=lnMIQ$a006%+ -0015U0000000000006duip~Q7aA|NaUukZ1WpZv|Y%g_mX>4;ZY;R|0X>MmOaCuNm0Rj{N6aWAK2mnY -{22-r@2-nvg005X@000{R0000000000006du&D;Y3aA|NaUukZ1WpZv|Y%g_mX>4;ZZE163E^v8JO92 -8D02BZK00;m`Rt8f|uidJR0RRAC1pojY00000000000002Cf!+E80B~t=FJEbHbY*gGVQepTbZKmJFK -usRWo&aUaCuNm0Rj{N6aWAK2mnY{22(2i=Pw-u006BE001BW0000000000006durThZ`aA|NaUukZ1W -pZv|Y%g_mX>4;ZaA9L>VP|P>XD)DgP)h*<6aW+e000O8NLB_@NF&H%odf^?{R{vA9{>OV0000000000 -wt)Zv1ORYpa4%nJZggdGZeeUMb#!TLb1!gVa$#(2Wo#~Rc~DCM0u%rg0000807zB_Q&!fmQ>y_00D1% -f03-ka00000000000JeeJ1q1+aX>c!JX>N37a&BR4FLiWjY;!MgYiD0_Wpi(Ja${w4E^v8JO928D02B -ZK00;m`Rt8hWgk&#R1pokK6aWAx00000000000002CfyV~~0B~t=FJEbHbY*gGVQepTbZKmJFLPydb# -QcVZ)|g4Vs&Y3WG--dP)h*<6aW+e000O8NLB_@3weAzjSK()R44!dApigX0000000000wt-{~1ORYpa -4%nJZggdGZeeUMb#!TLb1!psVsLVAV`X!5E^v8JO928D02BZK00;m`Rt8fN9}RyB3IG5SAOHX#00000 -000000002CfiM~b0B~t=FJEbHbY*gGVQepTbZKmJFLY&Xa9?C;axQRrP)h*<6aW+e000O8NLB_@=O7Q -WED8VsWh4LqAOHXW0000000000wt;sf1ORYpa4%nJZggdGZeeUMb#!TLb1!vnaA9L>X>MmOaCuNm0Rj -{N6aWAK2mnY{22+=5rsGWm002h^000{R0000000000006du;VuLKaA|NaUukZ1WpZv|Y%g_mX>4;Zb# -iQTE^v8JO928D02BZK00;m`Rt8g4;ZcW7m0Y%XwlP)h*<6aW+e000O8NLB_@>_RFUGXVeqV*&sG9RL6 -T0000000000wt+A}1ORYpa4%nJZggdGZeeUMc4KodUtei%X>?y-E^v8JO928D02BZK00;m`Rt8gH>{_ -St0{{T>3jhEc00000000000002Cfu2DG0B~t=FJEbHbY*gGVQepUV{k-1ORYpa4%nJZggdGZeeUMc4KodXK8dUaCuNm0 -Rj{N6aWAK2mnY{22;qlI(fDQ0043n0015U0000000000006du%vuBhaA|NaUukZ1WpZv|Y%g|Wb1!XW -a$|LJX<=+GaCuNm0Rj{N6aWAK2mnY{22)+-S6b7^mGE^v8JO928D02BZK00;m`Rt8g7=Gsn07ytmiT>tMtBUtcb8c~DCM0u%rg0000807zB_Q -wdWFYJC&{0IX*K02TlM00000000000JeczjsyU3X>c!Jc4cm4Z*nhTaByU4a&sc!Jc4cm4Z*nhWX>)XPZ!U0oP)h*<6aW+ -e000O8NLB_@bQ{R#fBgUewMPU17ytkO0000000000wt*GP1ORYpa4%nWWo~3|axZXsaA9(DX>MmOaCu -Nm0Rj{N6aWAK2mnY{22*wqSNb&}007&H000sI0000000000006du%E$!(aA|NaUv_0~WN&gWb7^=kaC -uNm0Rj{N6aWAK2mnY{22(py{zK{j004pk000&M0000000000006duFX{yVaA|NaUv_0~WN&gWc4cm4Z -*nelcyv%p0Rj{N6aWAK2mnY{22;eEP1dmh0021w001Na0000000000006duP3r{!aA|NaUv_0~WN&gW -V_{=xWn*t{baHQOFJE72ZfSI1UoLQYP)h*<6aW+e000O8NLB_@eR*jI2?78BNCf}@AOHXW000000000 -0wt+zG1pshqa4%nWWo~3|axY_HV`yb#Z*FvQZ)`7LV{K$EaCuNm0Rj{N6aWAK2mnY{22)tEZ$Y31005 -U0001KZ0000000000006duhwcRcaA|NaUv_0~WN&gWV_{=xWn*t{baHQOFJWY1aCBvIE^v8JO928D02 -BZK00;m`Rt8gs-nr;H0RR9@0{{Ra00000000000002CfoSvv0B~t=FJE?LZe(wAFJob2Xk}w>Zgg^QY -%gPBV`ybAaCuNm0Rj{N6aWAK2mnY{22(5te|;7K007hi001HY0000000000006du;q?UoaA|NaUv_0~ -WN&gWV_{=xWn*t{baHQOFJo_QaA9;VaCuNm0Rj{N6aWAK2mnY{22001Tc000000000 -0006duH}?eqaA|NaUv_0~WN&gWV_{=xWn*t{baHQOFJo_RbaHQOY-MsTaCuNm0Rj{N6aWAK2mnY{22= -N9hCBlV001=#001Wd0000000000006dus0RiBaA|NaUv_0~WN&gWV_{=xWn*t{baHQOFJ@_MWp{F6aB -yXEE^v8JO928D02BZK00;m`Rt8hywf*A01pokT5C8xs00000000000002Cf$$3k0B~t=FJE?LZe(wAF -Job2Xk}w>Zgg^QY%geKb#iHQbZKLAE^v8JO928D02BZK00;m`Rt8gEhzcSq2><|Z8~^|%0000000000 -0002Cf$|Xs0B~t=FJE?LZe(wAFJob2Xk}w>Zgg^QY%gZgg^QY%gPBV`yb_FJE72ZfSI1UoLQYP)h*<6aW+e000O8NLB_@M?iqf83q6V%MbtnEdT%j000000 -0000wt*KN1^{qra4%nWWo~3|axY_HV`yb#Z*FvQZ)`7PVPj}zb1!CTY-L|#VPj}zE^v8JO928D02BZK -00;m`Rt8f^!W2br0RRAb0{{Rn00000000000002CfqNqc0B~t=FJE?LZe(wAFJob2Xk}w>Zgg^QY%gP -BV`yb_FLGsMX>(s=VPj}zE^v8JO928D02BZK00;m`Rt8gk2OV0000000000wt=-J1^{qra4%nWWo~3|axY_La&&2CX)j-2ZDDC{Utcb8c~DCM0u%rg0000807zB_Q -x_bfz0f5B0EzVj03HAU00000000000JedZCI$d-X>c!Jc4cm4Z*nhVWpZ?BW@#^DVPj=-bS`jZZBR=A -0u%rg0000807zB_Q`}7uaj^sd0AvdQ02=@R00000000000JedlOb7sQX>c!Jc4cm4Z*nhVWpZ?BW@#^ -DZ*pZWaCuNm0Rj{N6aWAK2mnY{22?y-E^v8JO928D02BZK00;m`Rt8hOdAjE3IRF5ddjJ3*00000000000002Cfk -;*e0B~t=FJE?LZe(wAFJow7a%5$6FJftDHD+>UaV~IqP)h*<6aW+e000O8NLB_@vSdz!M*{!=3<}BB>(^?00000000000002Cf%20G0B~t=FJE?LZe(wAFJow7a%5$6FJow7a%5?9baH8 -8b#!TOZZ2?nP)h*<6aW+e000O8NLB_@$#=vmh6DfrY7YPaDF6Tf0000000000wt<432mo+ta4%nWWo~ -3|axY_OVRB?;bT4CQVRCb2bZ2sJb#QQUZ(?O~E^v8JO928D02BZK00;m`Rt8h@f}$YL2LJ$v6aWAu00 -000000000002Cfls0c0B~t=FJE?LZe(wAFJow7a%5$6FJow7a&u*LaB^>AWpXZXc~DCM0u%rg000080 -7zB_Q{!<=II;x*0A3CN04V?f00000000000Jec(st5pZX>c!Jc4cm4Z*nhVXkl_>WppoNZ)9n1XLEF6 -bY*Q}V`yn^WiD`eP)h*<6aW+e000O8NLB_@O5runV*&sG)C2$k9RL6T0000000000wt-o&2mo+ta4%n -WWo~3|axY_OVRB?;bT4CXZE#_9E^v8JO928D02BZK00;m`Rt8hGLZGB@0{{SU2LJ#f0000000000000 -2Cf%mcq0B~t=FJE?LZe(wAFJow7a%5$6FJo{yG&yi`Z(?O~E^v8JO928D02BZK00;m`Rt8gF`{91g0s -sKX1^@sY00000000000002Cfv2_z0B~t=FJE?LZe(wAFJow7a%5$6FJ*3ZZF4Sgc~DCM0u%rg000080 -7zB_Q^e&_WkCf10Micu03ZMW00000000000Jedyxd;GoX>c!Jc4cm4Z*nhVXkl_>WppoPb7OFFZ(?O~ -E^v8JO928D02BZK00;m`Rt8hTMpy(J1^@sADgXc+00000000000002Cfi1rX0B~t=FJE?LZe(wAFJow -7a%5$6FJ*IMb8Rkgc~DCM0u%rg0000807zB_Q~5N<5H$q=009pG03rYY00000000000JedG#Rvd!X>c -!Jc4cm4Z*nhVXkl_>WppoPbz^F9aB^>AWpXZXc~DCM0u%rg0000807zB_Q};P(w|f`>0If9u03ZMW00 -000000000Jeem$_M~(X>c!Jc4cm4Z*nhVXkl_>WppoPbz^ICW^!e5E^v8JO928D02BZK00;m`Rt8htz -2vw+0{{R62LJ#f00000000000002Cfw1EU0B~t=FJE?LZe(wAFJow7a%5$6FJ*OOYjSXMZ(?O~E^v8J -O928D02BZK00;m`Rt8hjI*5-tIsgC&eEc -!Jc4cm4Z*nhVXkl_>WppoPbz^jQaB^>AWpXZXc~DCM0u%rg0000807zB_Q}WGgCyFNk00vS303iSX00 -000000000Jec9B?$mc!Jc4cm4Z*nhVXkl_>WppoRVlp!^GG=mRaV~IqP)h*<6aW+e000O8NLB_@G -%6+4Jp%v$2nPTFBLDyZ0000000000wt??V2>@_ua4%nWWo~3|axY_OVRB?;bT4OOGBYtUaB^>AWpXZX -c~DCM0u%rg0000807zB_Qw5CVh_ey^05UfK03!eZ00000000000Jec`PzeBVX>c!Jc4cm4Z*nhVXkl_ ->WppoSWnyw=cW`oVVr6nJaCuNm0Rj{N6aWAK2mnY{22+3#-w-S?008!70015U0000000000006duVPg -pZaA|NaUv_0~WN&gWV`yP=WMyc!Jc4cm4Z*nhVXkl_>WppoWVQyz)b!=y0a%o|1ZEs{{ -Y%XwlP)h*<6aW+e000O8NLB_@L{oCOf*1e*A(jCEB>(^b0000000000wt@D=2>@_ua4%nWWo~3|axY_ -OVRB?;bT4dSZf9q5Wo2t^Z)9a`E^v8JO928D02BZK00;m`Rt8gC0g@&z7XSeFk^ulF0000000000000 -2CfxF%b0B~t=FJE?LZe(wAFJow7a%5$6FKl6MXJ}<&a%FdIZ)9a`E^v8JO928D02BZK00;m`Rt8hLB< -Jst8vp=|q5%LY00000000000002Cfi3n40B~t=FJE?LZe(wAFJow7a%5$6FKl6MXJ~b9XJK+_VQy`2W -MynFaCuNm0Rj{N6aWAK2mnY{22-JO5caX<=?{Z)9a`E^v8JO928D02BZK00;m`Rt8hecwy7A8vp>WqyYdV000000000 -00002Cftx!D0B~t=FJE?LZe(wAFJow7a%5$6FKl6MXLM*`X>D(0Wo#~Rc~DCM0u%rg0000807zB_Q>? -Rsf@&N90O^MT04D$d00000000000JedSR|)`dX>c!Jc4cm4Z*nhVXkl_>WppoWVQy!1b#iNIb7*aEWM -ynFaCuNm0Rj{N6aWAK2mnY{22);En8vLJ004^>001KZ0000000000006duJ#-2HaA|NaUv_0~WN&gWV -`yP=WMyaA|NaU -v_0~WN&gWV`yP=WMy001Zv001Tc -0000000000006duotX*%aA|NaUv_0~WN&gWV`yP=WMyAWpXZXc~DCM0u%rg0000807zB_Q`-5-6pIZ20QE5d04M+e00000000000JeeEqzV9VX>c!Jc4cm4Z* -nhVXkl_>WppofZfSO9a&uv9WMy<^V{~tFE^v8JO928D02BZK00;m`Rt8hlQl3yz1ONaa3jhEi000000 -00000002Cfu^zw0B~t=FJE?LZe(wAFJow7a%5$6FLiWgIB;@rVr6nJaCuNm0Rj{N6aWAK2mnY{22;&* -xxl~x008>{0015U0000000000006duHn$1@aA|NaUv_0~WN&gWV`yP=WMyV>WaCuNm0Rj{ -N6aWAK2mnY{22-qsq7(!G00062001KZ0000000000006duGPnu=aA|NaUv_0~WN&gWV`yP=WMy?y-E^v8JO928D02BZK00;m`Rt8he=YS}f1ONaJ3jhEm00000000000002Cfp@qH0B~t=FJ -E?LZe(wAFJow7a%5$6FJo+JFJow7a%5$6Wn*+MaCuNm0Rj{N6aWAK2mnY{22%h40006200000001Ze0 -000000000006duQoRZQaA|NaUv_0~WN&gWV`yP=WMy0000W00000000000002Cfwj;I0B~ -t=FJE?LZe(wAFJo_PZ*pO6VJ}}_X>MtBUtcb8c~DCM0u%rg0000807zB_Q~2@)F_!}X06+==02}}S00 -000000000Jedu(Fy=?X>c!Jc4cm4Z*nhVZ)|UJVQpbAVQzD2E^v8JO928D02BZK00;m`Rt8f;f}y;D3 -jhEYDgXc@00000000000002CfqT^o0B~t=FJE?LZe(wAFJo_PZ*pO6VJ~5Bb7^#McWG`jGA?j=P)h*< -6aW+e000O8NLB_@I>Kjvi~;}v%Lf1eA^-pY0000000000wt+q23IK3va4%nWWo~3|axY_VY;SU5ZDB8 -IZfSIBVQgu0WiD`eP)h*<6aW+e000O8NLB_@QuSTsT?GIDv=smV9RL6T0000000000wt)%c3IK3va4% -nWWo~3|axY_VY;SU5ZDB8WX>KzzE^v8JO928D02BZK00;m`Rt8g%r)VAg1polg82|tu000000000000 -02CfuZRN0B~t=FJE?LZe(wAFJo_PZ*pO6VJ~-SZggdGZ7y(mP)h*<6aW+e000O8NLB_@Fy##4WdQ&HT -mk?99{>OV0000000000wt?F33IK3va4%nWWo~3|axY|Qb98KJVlQ7`X>MtBUtcb8c~DCM0u%rg00008 -07zB_Q_hmT&vh#R03fCS0384T00000000000JedA@d^NNX>c!Jc4cm4Z*nhWX>)XJX<{#9Z*6d4bS`j -tP)h*<6aW+e000O8NLB_@h?96aIWPbKuFL=c9{>OV0000000000wt*}i3jlCwa4%nWWo~3|axY|Qb98 -KJVlQN2bYWs)b7d}Yc~DCM0u%rg0000807zB_Q`S~0l=2h+002_}02}}S00000000000JedmO$z{UX> -c!Jc4cm4Z*nhWX>)XJX<{#FZe(S6E^v8JO928D02BZK00;m`Rt8g4JBQt8GXMY)&;S4*00000000000 -002CfzDzJ0B~t=FJE?LZe(wAFJx(RbZlv2FKlmPVRUbDb1rasP)h*<6aW+e000O8NLB_@{~v!|ix2<+ -WIF%=9{>OV0000000000wt;e%3jlCwa4%nWWo~3|axY|Qb98KJVlQoBZfRy^b963nc~DCM0u%rg0000 -807zB_Q-*j{lK=()0D2Js03HAU00000000000JecTrwagZX>c!Jc4cm4Z*nhWX>)XJX<{#JVRCC_a&s -c!Jc4cm4Z*nhWX> -)XJX<{#JWprU=VRT_GaCuNm0Rj{N6aWAK2mnY{22&D*?$5{z0062h001BW0000000000006du+tLdFa -A|NaUv_0~WN&gWWNCABY-wUIa%FRGb#h~6b1rasP)h*<6aW+e000O8NLB_@(=~cK$P@qo2Soq?9smFU -0000000000wt?Z^3jlCwa4%nWWo~3|axY|Qb98KJVlQ)Ja%pgMb1rasP)h*<6aW+e000O8NLB_@uz=P -Am$?7{0D1uc8vp005o=02=@R00000000000Jed(tqcHgX>c!Jc4cm4Z*nhWX>)XJX<{#QHZ(3}cx -6ya0Rj{N6aWAK2mnY{22*@G&+iCH005H@0RS5S0000000000006dufOic5aA|NaUv_0~WN&gWWNCABY --wUIb#!TLE^v8JO928D02BZK00;m`Rt8hd&^q#}82|vcUH||d00000000000002Cfx*BH0B~t=FJE?L -Ze(wAFJx(RbZlv2FLq^eb7^mGE^v8JO928D02BZK00;m`Rt8fX7!JlaumAu6U;zLd00000000000002 -Cfv4IH0B~t=FJE?LZe(wAFJx(RbZlv2FLyICE@gOSP)h*<6aW+e000O8NLB_@`x>(RXTSge0EPho8vp -c!Jc4cm4Z*nhWX>)XJX<{#TXk}$=E^v8JO928D02BZK0 -0;m`Rt8gC*JL`$0000O0RR9g00000000000002CfnIeF0B~t=FJE?LZe(wAFJx(RbZlv2FJEF|V{344 -a&#|WUukY>bYEXCaCuNm0Rj{N6aWAK2mnY{22)K;?%vk{008s@001Qb0000000000006duZgvjc!Jc4cm4Z*nhWX>)XJX<{#5Vqs%zaBp&SFLP*hbZKlZaCuNm0Rj{N6a -WAK2mnY{22=gq|Ci} -rSpWb7bO8V;00000000000002Cfx)&90B~t=FJE?LZe(wAFJx(RbZlv2FJEF|V{344a&#|rVRB|^Y-K -KRc~DCM0u%rg0000807zB_Q@A(TBu@eW0ILK503ZMW00000000000Jebx5fA`yX>c!Jc4cm4Z*nhabZ -u-kY-wUIUtei%X>?y-E^v8JO928D02BZK00;m`Rt8g(hP*mT6aWBuLI40E00000000000002Cfshjr0 -B~t=FJE?LZe(wAFKBdaY&C3YVlQ85Xkm0^cx`MhaCuNm0Rj{N6aWAK2mnY{22+w+$+9#b008%a001Na -0000000000006du87L3{aA|NaUv_0~WN&gWXmo9CHEd~OFJEbHaCLNZbaG{3Z7y(mP)h*<6aW+e000O -8NLB_@r#U!pavcBww=)3%A^-pY0000000000wt;u8P>9smFU0000000000wt+!q5CCv#a4%nWWo~3|ax -Z9fZEQ7cX<{#5b#!TLb1rasP)h*<6aW+e000O8NLB_@B(F4Uvq%5{ictXoApigX0000000000wt;MH5 -CCv#a4%nWWo~3|axZ9fZEQ7cX<{#9Z*FsRVQzGDE^v8JO928D02BZK00;m`Rt8g;kxQLLMF0S;)Byk^ -00000000000002CfnK!`0B~t=FJE?LZe(wAFKBdaY&C3YVlQZPZEQ7gVRCb2axQRrP)h*<6aW+e000O -8NLB_@KaNu_&=3FsC_exIA^-pY0000000000wt?jO5CCv#a4%nWWo~3|axZ9fZEQ7cX<{#PWpZg@Y-x -IBaxQRrP)h*<6aW+e000O8NLB_@ZViIgUH||9asU7TCIA2c0000000000wt@5u5dd&$a4%nWWo~3|ax -Z9fZEQ7cX<{#5baH8BFJE72ZfSI1UoLQYP)h*<6aW+e000O8NLB_@4Xmkbt^oi59RvUXBLDyZ000000 -0000wtc!Jc4cm4Z*nhabZu-kY-wUIUvzS5WiN1fE^v8JO928 -D02BZK00;m`Rt8f500002000000000e00000000000002Cf#?ts0B~t=FJE?LZe(wAFKBdaY&C3YVlQ -TCY;MtBUtcb8c~DCM0u%rg0000807zB_Q(r2cR?7hZ0JH-D05$*s00000000000JecJ5f -K1zX>c!Jc4cm4Z*nhabZu-kY-wUIW@&76WpZ;bVQg?{VPa);X=7n*VRUqIX<~JBWpgfYc~DCM0u%rg0 -000807zB_Q(1xew449{04f0h03-ka00000000000Jeco6A=J#X>c!Jc4cm4Z*nhabZu-kY-wUIW@&76 -WpZ;bVqtS-E^v8JO928D02BZK00;m`Rt8f-4y!#O0{{TZ3jhE!00000000000002Cfh`mf0B~t=FJE? -LZe(wAFKBdaY&C3YVlQTCY;4?5a&s?iX>N2baC -uNm0Rj{N6aWAK2mnY{22*N;ilXrb001j0001li0000000000006duTN@DoaA|NaUv_0~WN&gWXmo9CH -Ed~OFJ@_MbY*gLFK=*kX>V>}Y;<8~b1rasP)h*<6aW+e000O8NLB_@4Ub>JGZ+8>rECBIDF6Tf00000 -00000wt4?5a&s?pVQy)3X?kUHE^v8JO928D02BZK00;m -`Rt8hA=MqHy0RRBx1ONak00000000000002Cfe?_CaA9L*E^v8JO928D02BZK00;m`Rt8gNQb7!G0RRBS0ssIl00000000000002CfmJ;b0B~t=FJ -E?LZe(wAFKBdaY&C3YVlQ-ZWo2PxVQ_S1a&s?VUukY>bYEXCaCuNm0Rj{N6aWAK2mnY{22-D6%T-?j0 -08L*001ih0000000000006du5I+$BaA|NaUv_0~WN&gWXmo9CHEd~OFLZKcWnpAtaCBvIb1!FQZgXg9 -E^v8JO928D02BZK00;m`Rt8gX8mC}U0ssIa2LJ#l00000000000002Cfw(~t0B~t=FJE?LZe(wAFKBd -aY&C3YVlQ-ZWo2PxVQ_S1a&s?pVR$ZZc~DCM0u%rg0000807zB_Q$!N^kY5D=0ALOP04)Fj00000000 -000JecoL=gaRX>c!Jc4cm4Z*nhabZu-kY-wUIbaG{7Vs&Y3WMy)5FJE72ZfSI1UoLQYP)h*<6aW+e00 -0O8NLB_@uY@3o3l9JQhB^QMDF6Tf0000000000wt@Lc5dd&$a4%nWWo~3|axZ9fZEQ7cX<{#Qa%E*=b -!lv5WpZ;bVqtS-E^v8JO928D02BZK00;m`Rt8huBpd|~2mk=gBLDy>00000000000002CflFBt0B~t= -FJE?LZe(wAFKBdaY&C3YVlQ-ZWo2S@X>4R=a&s?aZ*4Acc~DCM0u%rg0000807zB_Q=z1*%xww)0DCh -404e|g00000000000JedkVG#guX>c!Jc4cm4Z*nhabZu-kY-wUIbaG{7Vs&Y3WMy)5FJ*LcWo0gKc~D -CM0u%rg0000807zB_Qx4u2bUY3K05&@S051Rl00000000000JecuY!Lu(X>c!Jc4cm4Z*nhabZu-kY- -wUIbaG{7Vs&Y3WMy)5FJ*LcWo2J%cx`MhaCuNm0Rj{N6aWAK2mnY{22)c)c2Tni008k8001li000000 -0000006du-g*%LaA|NaUv_0~WN&gWXmo9CHEd~OFLZKcWp`n0Yh`kCFJE72ZfSI1UoLQYP)h*<6aW+e -000O8NLB_@tiQ%ZCn0068R001rk0000000000006du&yW!SaA|NaUv_0~WN&gWXmo9CHEd~O -FLZKcWp`n0Yh`kCFJ*LcWo2J%cx`MhaCuNm0Rj{N6aWAK2mnY{22&=1Z>`e;002q}001fg000000000 -0006dur00000000000002Cft8>U0B~t -=FJE?LZe(wAFKJ|MVJ~BEa%C=Xc~DCM0u%rg0000807zB_Q@ZgHV!k5)0C24U02}}S00000000000Je -dAtPuckX>c!Jc4cm4Z*nhbWNu+EX=H9;WMOn+E^v8JO928D02BZK00;m`Rt8h-tJqjK0{{TW2LJ#a00 -000000000002CfppLj0B~t=FJE?LZe(wAFKJ|MVJ~TJbaG*CXJvCPaCuNm0Rj{N6aWAK2mnY{22-Ko7 -D*WZ000*N001BW0000000000006du=F<@XaA|NaUv_0~WN&gWX=H9;FK}UFYhh<)Uu0o)VJ>iaP)h*< -6aW+e000O8NLB_@#7xN~ftUaQZ#4q|9RL6T0000000000wt+p=5dd&$a4%nWWo~3|axZCQZecHVbaON -|WMOn+E^v8JO928D02BZK00;m`Rt8gUZ+zP60RRA$1ONaZ00000000000002Cf%$9_0B~t=FJE?LZe( -wAFKu&YaA9L>FJE72ZfSI1UoLQYP)h*<6aW+e000O8NLB_@mOqay7XSbN6#xJL9{>OV0000000000wt -*jS5&&>%a4%nWWo~3|axZOjXK-O-YcF4RWpZc!Jc4cm4Z*nhfb7yd2V{0#Ecw=R7bZKvHb1rasP)h*<6aW+e000O8 -NLB_@z>%rk4hH}Li5LI?8UO$Q0000000000wt;DJ5&&>%a4%nWWo~3|axZOjXK-O-YcFMZbS`jtP)h* -<6aW+e000O8NLB_@{SZ=%Zyf*t$(R5D9{>OV0000000000wt=sB5&&>%a4%nWWo~3|axZOjXK-O-YcF -PDY;0m-V{0yOc~DCM0u%rg0000807zB_Qc!Jc4 -cm4Z*nhiVPk7yXK8L{FJE6_VsCYHUtcb8c~DCM0u%rg0000807zB_Q)G5pvHSo4015&C03iSX000000 -00000Jeb%m=XYRX>c!Jc4cm4Z*nhiVPk7yXK8L{FJE72ZfSI1UoLQYP)h*<6aW+e000O8NLB_@=i+68 -pbh{44K4rxBLDyZ0000000000wt+;M5&&>%a4%nWWo~3|axZXUV{2h&X>MmPUu|J-d2DHJb$Bjtc~DC -M0u%rg0000807zB_Q=%7fDnADR0HP5903!eZ00000000000Jec8s1g8hX>c!Jc4cm4Z*nhiVPk7yXK8 -L{FJEnSb8KvBZgqGraCuNm0Rj{N6aWAK2mnY{22)w+ZdGvs005u{001Na0000000000006durLPhIaA -|NaUv_0~WN&gWaA9L>VP|P>XD?rKbaHiLbairNb1rasP)h*<6aW+e000O8NLB_@JR%a4%nWWo~3|axZXUV{2h&X>MmPZDDe2WpZ;aaCuNm0Rj{N6aWAK2mnY{ -22)6MU%Lhe007n!001Qb0000000000006duF1!)|aA|NaUv_0~WN&gWaA9L>VP|P>XD@PPadl~OWo>0 -{baO6nc~DCM0u%rg0000807zB_Q?nzWg+Lns05E(203!eZ00000000000Jed5!x8{+X>c!Jc4cm4Z*n -hiVPk7yXK8L{FLQ8ZV`*k-WpZ;aaCuNm0Rj{N6aWAK2mnY{22+2`$jr47002fm0012T000000000000 -6du_}&r#aA|NaUv_0~WN&gWaA9L>VP|P>XD@VNXLBxac~DCM0u%rg0000807zB_Q-e+fYvTm~0Pqk10 -3HAU00000000000JeeX@Dc!UX>c!Jc4cm4Z*nhiVPk7yXK8L{FLiWjY;!Jfc~DCM0u%rg0000807zB_ -QyzBeM-~tO06{wd03ZMW00000000000Jeb#_YwebX>c!Jc4cm4Z*nhiVPk7yXK8L{FLq^eb7^mGE^v8 -JO928D02BZK00;m`Rt8gg(Kls!0001p0000U00000000000002Cfm;U?0B~t=FJE?LZe(wAFK}gWH8D -3YUtei%X>?y-E^v8JO928D02BZK00;m`Rt8fKnOFcn1pojH4gdff00000000000002Cfe{E30B~t=FJ -E?LZe(wAFK}gWH8D3YVs&Y3WG--dP)h*<6aW+e000O8NLB_@dIZ&2-30&upBMlD8vpc!Jc4cm4Z*nhiWpFhyH!ovvY;SUGZ)YxWc~DCM0u%rg0000807zB_Q#lq -b(S-p309gb802}}S00000000000Jed28WR9;X>c!Jc4cm4Z*nhiWpFhyH!ovvZE#_9E^v8JO928D02B -ZK00;m`Rt8hJ?~s|;0RRA%1ONaY00000000000002CfioNv0B~t=FJE?LZe(wAFK}gWH8D3YWNC7AZ* -OdKE^v8JO928D02BZK00;m`Rt8f~K8=Pn2mk<{Z00000000000002Cfwv|T -0B~t=FJE?LZe(wAFK}gWH8D3YZDn*}E^v8JO928D02BZK00;m`Rt8g4y1azN3;+NMO|a&Kd0b8|0WUukY>bYEXCaC -uNm0Rj{N6aWAK2mnY{22;4qG*b2o006El001li0000000000006duML81yaA|NaUv_0~WN&gWaAj~cF -*h%1ZeMV6Z)0V1b1z?MZeMV6Z)0V1b1rasP)h*<6aW+e000O8NLB_@R}TwErE~xQ)w2NrB>(^b00000 -00000wt?y-E^v8JO928D02BZK00;m`Rt8f -dwy#T70RR9=0ssIf00000000000002Cfo-`H0B~t=FJE?LZe(wAFK}yTUvg!0Z*_8GWpgiZc{4F%Z*6 -d4bS`jtP)h*<6aW+e000O8NLB_@*su60e+B>msuKVJAOHXW0000000000wt)w`698~&a4%nWWo~3|ax -ZXlZ)b94b8|0WUukY>bYEXCaCuNm0Rj{N6aWAK2mnY{22)Fa%FRKFJfVGE^v8JO928D02BZK00;m`Rt8gHiufM;0ssJo1poja00000 -000000002Cfvv_90B~t=FJE?LZe(wAFK}{iXL4n8b1!3Wb#8QJaxQRrP)h*<6aW+e000O8NLB_@-<#x -75d#1Kj|Bh#9{>OV0000000000wt?lz698~&a4%nWWo~3|axZXlZ)b94b8|0qaA|ICWpXZXc~DCM0u% -rg0000807zB_Q;K8$goFnG0Fx8|03ZMW00000000000JecM%@Y7{X>c!Jc4cm4Z*nhkWpQ<7b98erUt -ei%X>?y-E^v8JO928D02BZK00;m`Rt8i0zGSrv0RRBU0RR9a00000000000002Cf%ViA0B~t=FJE?LZ -e(wAFLGsZb!BsOb1z?Cc4cyNX>V>{UoLQYP)h*<6aW+e000O8NLB_@b?5!69|8aXas&VXCjbBd00000 -00000wt+#`698~&a4%nWWo~3|axZdaadl;LbaO9XX>N37a&BR4Uv+e8Y;!Jfc~DCM0u%rg0000807zB -_Q;MzcpSKhM06|s&03ZMW00000000000Jedp*b@M7X>c!Jc4cm4Z*nhkWpQ<7b98erVPs)&bY*gLE^v -8JO928D02BZK00;m`Rt8g<@Ld*m1^@t|82|tq00000000000002Cftu|T0B~t=FJE?LZe(wAFLGsZb! -BsOb1z|VX)bViP)h*<6aW+e000O8NLB_@af*U3jtc+)5Geov8~^|S0000000000wt-3X698~&a4%nWW -o~3|axZdaadl;LbaO9Zb#!PhaCuNm0Rj{N6aWAK2mnY{22<3aj@LT@0083w0012T0000000000006du -5dahbaA|NaUv_0~WN&gWa%FLKWpi|MFJonLbaO6nc~DCM0u%rg0000807zB_Qz3Pr2lD~|07(b{03HA -U00000000000JedL0TcjmX>c!Jc4cm4Z*nhkWpQ<7b98erV{dJ6VRSBVc~DCM0u%rg0000807zB_Q#c -+;f8-MY03%8O03QGV00000000000Jed)1QY;pX>c!Jc4cm4Z*nhkWpQ<7b98erV{dP3X=QURaCuNm0R -j{N6aWAK2mnY{22(!-Sk_kr001!!001HY0000000000006du*BBH4aA|NaUv_0~WN&gWa%FLKWpi|MF -J*XRWpH$9Z*FrgaCuNm0Rj{N6aWAK2mnY{22-y4x{03z000OO000~S0000000000006duZXFZ=aA|Na -Uv_0~WN&gWa%FLKWpi|MFKA_Ka4v9pP)h*<6aW+e000O8NLB_@Ox`k*fB^si7XttQ9RL6T000000000 -0wt+_?6aa8(a4%nWWo~3|axZdaadl;LbaO9gZ*OaJE^v8JO928D02BZK00;m`Rt8h9SbGB^CjbC4i~s -;000000000000002CfdV8H0B~t=FJE?LZe(wAFLGsZb!BsOb1!XgWMyn~E^v8JO928D02BZK00;m`Rt -8h0zsD_c0RRBU0ssIY00000000000002CfnZA%0B~t=FJE?LZe(wAFLGsZb!BsOb1!gVV{2h&WpgfYc -~DCM0u%rg0000807zB_Q)w+5O>Q9o0Ofc903ZMW00000000000Jeb-O%wodX>c!Jc4cm4Z*nhkWpQ<7 -b98erb7gaLX>V?GE^v8JO928D02BZK00;m`Rt8gLXo}LD1^@up5C8xq00000000000002CfxB)L0B~t -=FJE?LZe(wAFLGsZb!BsOb1!prVRUtKUt@1%WpgfYc~DCM0u%rg0000807zB_Qz~N!GKmBL0459o03r -YY00000000000Jeddbrb+_X>c!Jc4cm4Z*nhkWpQ<7b98erb98cbV{~c!Jc4cm4Z*nhkWpQ<7b98erb#!TLb1rasP -)h*<6aW+e000O8NLB_@GCErQ-~a#sGXekrA^-pY0000000000wt@Gd6aa8(a4%nWWo~3|axZdab8l>R -Wo&6;FJE72ZfSI1UoLQYP)h*<6aW+e000O8NLB_@sr-r20tWy9f))S(BLDyZ0000000000wt*L;6aa8 -(a4%nWWo~3|axZdab8l>RWo&6;FK}{ic4=f~a&sc!Jc4cm4Z*nhkWpi(Ac4cg7VlQ%KaBp&SWpZ;aaCuNm0Rj{N6aWAK2m -nY{22=N|ddVIV001II001KZ0000000000006duimVg>aA|NaUv_0~WN&gWa%FRGY<6XAX<{#OWpi(Ac -4cyNE^v8JO928D02BZK00;m`Rt8hgWJVxj1pokF6951q00000000000002Cf$6>!0B~t=FJE?LZe(wA -FLGsbZ)|pDY-wUIb98cbV{~&aaCuNm0Rj{N6aWAK2mnY{22%h40006200000001cf0000000000006d -uio_HEaA|NaUv_0~WN&gWa%FRGY<6XAX<{#9Z*6d4bT40DX>MtBUtcb8c~DCM0u%rg0000807zB_Q&u -@VjAsA<0HOc@05AXm00000000000JeeC#1sHc!Jc4cm4Z*nhkWpi(Ac4cg7VlQKFZE#_9FJo_PY- -M9~X>V?GUtwZnE^v8JO928D02BZK00;m`Rt8hU7oJ-O6aWBLNdN#K00000000000002Cfr!Nv0B~t=F -JE?LZe(wAFLY&YVPk1@c`sjIX>MtBUtcb8c~DCM0u%rg0000807zB_QyXJ^?Z5;808R}603ZMW00000 -000000Jee6*%Sb9X>c!Jc4cm4Z*nhmWo}_(X>@rnUtx23ZewY0E^v8JO928D02BZK00;m`Rt8g-BHST -_0{{Tr2LJ#b00000000000002Cfy>?$0B~t=FJE?LZe(wAFLY&YVPk1@c`sjebZKmJE^v8JO928D02B -ZK00;m`Rt8h^O1ty=0ssI81^@sZ00000000000002Cfs5i40B~t=FJE?LZe(wAFLY&YVPk1@c`spRbY -*fbaCuNm0Rj{N6aWAK2mnY{22-xn60F4n004;v0015U0000000000006duz~vMGaA|NaUv_0~WN&gWb -Y*T~V`+4GFJfh8Z*pZWaCuNm0Rj{N6aWAK2mnY{22-qvMZRqV006EB001Na0000000000006du!RQnK -aA|NaUv_0~WN&gWbY*T~V`+4GFJfh8Z*pZ{b8Ka0a4v9pP)h*<6aW+e000O8NLB_@ZF^k3c!Jc4cm4Z*nhmWo}_(X>@rna%FUKc`k5yP)h*<6a -W+e000O8NLB_@1UG#KvjYGCMhgG{8~^|S0000000000wtAjaCuNm0Rj{N6aWAK2mnY{22&UXRF$>^005i_001HY0000000000006duc=;3naA|NaUv_0~WN&gW -bY*T~V`+4GFLZBmZee6^cV%KOaCuNm0Rj{N6aWAK2mnY{22;GDB;%t90080|000~S0000000000006d -uZv7MhaA|NaUv_0~WN&gWbY*T~V`+4GFLz;SbS`jtP)h*<6aW+e000O8NLB_@x;M1&9RL -6T0000000000wt-6q6##H)a4%nWWo~3|axZjmZER^TUtei%X>?y-E^v8JO928D02BZK00;m`Rt8g{E1 -02U6#xKES^xkX00000000000002Cfi(ve0B~t=FJE?LZe(wAFLZBhY-ulFaA9(DWpXZXc~DCM0u%rg0 -000807zB_Q&Po5OWgwi0L%&i02lxO00000000000JeeB92Ed?X>c!Jc4cm4Z*nhmZ*6R8FJE$HE^v8J -O928D02BZK00;m`Rt8fvc>Wb+1ONaa3jhEg00000000000002Cf#o0-0B~t=FJE?LZe(wAFLiQkY-wU -MFJE72ZfSI1UoLQYP)h*<6aW+e000O8NLB_@)CoTm91Q>fj4J>DBLDyZ0000000000wt_Gqk06_o%03QGV00 -000000000JeeSG8F)DX>c!Jc4cm4Z*nhna%^mAVlyvac4cyNX>V>WaCuNm0Rj{N6aWAK2mnY{22;jfW -uB@Q003P}001EX0000000000006duVKWr~aA|NaUv_0~WN&gWb#iQMX<{=kV{dM5Wn*+{Z*DGdc~DCM -0u%rg0000807zB_Q#OmQg;pp405+8X03`qb00000000000JecjN)-TbX>c!Jc4cm4Z*nhna%^mAVlyv -eZ*Fd7V{~b6Zg6jJY%XwlP)h*<6aW+e000O8NLB_@LZ-L*{|Nv9Tp<7eApigX0000000000wt?ev6## -H)a4%nWWo~3|axZmqY;0*_GcRR$V`Xr3X>V?GE^v8JO928D02BZK00;m`Rt8hrcP2(N3IG6=A^-p#00 -000000000002Cfgybr0B~t=FJE?LZe(wAFLiQkY-wUMFJ@_FY-DpTaCuNm0Rj{N6aWAK2mnY{22(g-# -tx4I008O<0018V0000000000006dukB1ciaA|NaUv_0~WN&gWb#iQMX<{=kW@&6?aBp*TE^v8JO928D -02BZK00;m`Rt8hgPR;g>761TCPXGWS00000000000002Cfm@3e0B~t=FJE?LZe(wAFLiQkY-wUMFK}; -fY;9p~VP|D>E^v8JO928D02BZK00;m`Rt8fdWyD&u2LJ#I7ytks00000000000002CfheLC0B~t=FJE -?LZe(wAFLiQkY-wUMFLGsZb!BsOE^v8JO928D02BZK00;m`Rt8fUPXO1N9RL7eaR2}x000000000000 -02CffuS30B~t=FJE?LZe(wAFLiQkY-wUMFLGsbaBpsNWiD`eP)h*<6aW+e000O8NLB_@000000ssI20 -0000CjbBd0000000000wt?=)6##H)a4%nWWo~3|axZmqY;0*_GcRLrZgg^KVlQ7`X>MtBUtcb8c~DCM -0u%rg0000807zB_Q=)Lh9=-tp0O11w05Jdn00000000000JecO$Q1x^X>c!Jc4cm4Z*nhna%^mAVlyv -eZ*FvQX<{#5VQ_F|Zf9w3WnX1(c4=~NZZ2?nP)h*<6aW+e000O8NLB_@P-{}3hztM#R4f1hC;$Ke000 -0000000wt+&*6##H)a4%nWWo~3|axZmqY;0*_GcRLrZgg^KVlQEEaAj_1X>MgMaCuNm0Rj{N6aWAK2m -nY{226dM+4&^^033<{04@L -k00000000000Jedg@)ZDZX>c!Jc4cm4Z*nhna%^mAVlyveZ*FvQX<{#PWn*=6Wpr|3ZgX&Na&#_mc~D -CM0u%rg0000807zB_Q^ao>eR2o@0FfL303-ka00000000000JeeQ7#09c!Jc4cm4Z*nhna%^mAVl -yveZ*FvQX<{#PZ)0n7E^v8JO928D02BZK00;m`Rt8f500002000000000u00000000000002Cft4W^0 -B~t=FJE?LZe(wAFLiQkY-wUMFJo_RbaH88FJE(IV|8+6baG*Cb8v5RbT40DX>MtBUtcb8c~DCM0u%rg -0000807zB_Q@74L&lnK^0Qg1#05|{u00000000000JeecAr=5|X>c!Jc4cm4Z*nhna%^mAVlyveZ*Fv -QX<{#5b7f<7a%FUKVQzD9Z*p`mVrgzMn8E^v8JO928D02BZK00;m`Rt8gGl43A^5dZ+-Hvj-R000 -00000000002Cfm<^c0B~t=FJE?LZe(wAFLiQkY-wUMFJo_RbaH88FJE(IV|8+6baG*Cb8v5RbT4dgcV -BE}c4cfXaCuNm0Rj{N6aWAK2mnY{22-0nr^r+Q0040S001Ze0000000000006duFhv#saA|NaUv_0~W -N&gWb#iQMX<{=kaA9L>VP|D?FJE72ZfSI1UoLQYP)h*<6aW+e000O8NLB_@3%-|iVIcqjpNjwhBLDyZ -0000000000wt>n;765Q*a4%nWWo~3|axZmqY;0*_GcRyqV{2h&WpgicX?QMhc~DCM0u%rg0000807zB -_Qvd(}00IC20000005Sjo00000000000Jec_XBGf(X>c!Jc4cm4Z*nhna%^mAVlyvrVPk7yXJvCQVqs -%zaBp&Sb1z?CX>MtBUtcb8c~DCM0u%rg0000807zB_Q&=0%AXNeY0K5eN05Sjo00000000000Jed?XB -Gf(X>c!Jc4cm4Z*nhna%^mAVlyvrVPk7yXJvCQVqs%zaBp&Sb1!XSYh`9>Y-KKRc~DCM0u%rg000080 -7zB_Q&L-(TC4#80Jj4G06PEx00000000000Jec+Y8C)+X>c!Jc4cm4Z*nhna%^mAVlyvrVPk7yXJvCQ -b8~E8ZDDj{XkTb=b98QDZDlWCUukY>bYEXCaCuNm0Rj{N6aWAK2mnY{22(2rFrdQ-007Sx002S&0000 -000000006duXlxb$aA|NaUv_0~WN&gWb#iQMX<{=kaA9L>VP|D?FLQHjUu|J@V`yJ!Z*z2RVQpnEUuk -V{Y-Md_ZggREX>V>WaCuNm0Rj{N6aWAK2mnY{22-m$4WHft006WE001Na0000000000006dui**(NaA -|NaUv_0~WN&gWb#iQMX<{=kb#!TLFJE72ZfSI1UoLQYP)h*<6aW+e000O8NLB_@KCa3(vj+eG&JzFtC -IA2c0000000000wt=g6765Q*a4%nWWo~3|axZmqY;0*_GcR>?X>2cJZ*Fd7V{~b6ZZ2?nP)h*<6aW+e -000O8NLB_@=4V`_W&!{Jd?X>2c -Wa&LHfE^v8JO928D02BZK00;m`Rt8hH2WVLY0RR990ssIZ00000000000002Cfk%QC0B~t=FJE?LZe( -wAFLiQkY-wUMFLiWjY%g(jWp!mPaCuNm0Rj{N6aWAK2mnY{22=j+oD2H}0062G001KZ000000000000 -6duih~vaaA|NaUv_0~WN&gWb#iQMX<{=kb#!TLFLGsZb!BsOE^v8JO928D02BZK00;m`Rt8i1ee2q91 -pojc4gdfo00000000000002CfyRjz0B~t=FJE?LZe(wAFLiQkY-wUMFLiWjY%g+Ub8v5Nb7d}Yc~DCM -0u%rg0000807zB_Q{mdEx%n0V0O?f#03iSX00000000000Jed5j}`!MX>c!Jc4cm4Z*nhna%^mAVlyv -wbZKlaa%FUKc`k5yP)h*<6aW+e000O8NLB_@9=48e#ufko2t@z@AOHXW0000000000wt=sv765Q*a4% -nWWo~3|axZmqY;0*_GcR>?X>2cZb8KHOaCuNm0Rj{N6aWAK2mnY{22+TDQfMFu008hC001Ze0000000 -000006duv%MAoaA|NaUv_0~WN&gWb#iQMX<{=kb#!TLFLQHjbaG*Cb8v5RbS`jtP)h*<6aW+e000O8N -LB_@4&ws4*9!muA1D9-BLDyZ0000000000wt*SO765Q*a4%nWWo~3|axZmqY;0*_GcR>?X>2caX>Db1 -b#yLpc~DCM0u%rg0000807zB_Q?xy1vA_}l0FO8T03QGV00000000000JecK(iQ-4X>c!Jc4cm4Z*nh -na%^mAVlyvwbZKlab#iPjaCuNm0Rj{N6aWAK2mnY{22;BBd3DqW006ZW001BW0000000000006duF69 -;gaA|NaUv_0~WN&gWb#iQMX<{=kb#!TLFLz;SbS`jtP)h*<6aW+e000O8NLB_@Qb2~tMGF7`sVV>fBm -e*a0000000000wt+zH765Q*a4%nWWo~3|axZsfVr6b)Z)9n1XLB!KUukY>bYEXCaCuNm0Rj{N6aWAK2 -mnY{22*+RMvV^!008Mn8FKl6A -Wo&aUaCuNm0Rj{N6aWAK2mnY{22-g@cuPtG002}4001Na0000000000006du7XKCiaA|NaUv_0~WN&g -WcV%K_Zewp`X>Mn8FKugVVPa)$b1rasP)h*<6aW+e000O8NLB_@LI9vP#RUKWJQ@H1ApigX00000000 -00wt=Dn7XWZ+a4%nWWo~3|axZsfVr6b)Z)9n1XLB!fWpi|ME^v8JO928D02BZK00;m`Rt8hWd9bdq1O -NaS5&!@y00000000000002Cfu;u+0B~t=FJE?LZe(wAFLz~PWo~0{WNB_^b1!&bb#rBMUu0!wX>Mg?E -^v8JO9ci10001t0gM45d;kER3>N?Z00 -""" - - -if __name__ == "__main__": - main() diff --git a/scripts/build-windows/install-rust-std.go b/scripts/build-windows/install-rust-std.go deleted file mode 100644 index 2fe583ca4..000000000 --- a/scripts/build-windows/install-rust-std.go +++ /dev/null @@ -1,101 +0,0 @@ -// Copyright 2022 The KCL Authors. All rights reserved. - -//go:build ingore -// +build ingore - -package main - -import ( - "flag" - "fmt" - "io" - "log" - "os" - "os/exec" - "path/filepath" - "strings" -) - -var ( - flagOutDir = flag.String("outdir", "./_output/kclvm-windows", "set output dir") -) - -func main() { - flag.Parse() - if *flagOutDir == "" { - panic("-outdir missing") - } - - // copy {root}/libs/rust-libstd-name.txt - err := os.WriteFile( - filepath.Join(*flagOutDir, "libs", "rust-libstd-name.txt"), - []byte(getRustStdDllName()), - 0666, - ) - if err != nil { - panic(err) - } - - // copy {root}/std-***.dll - cpFile( - filepath.Join(*flagOutDir, getRustStdDllName()), - filepath.Join(getRustWinX64LibDir(), getRustStdDllName()), - ) - // copy {root}/libs/std-***.dll.lib - cpFile( - filepath.Join(*flagOutDir, "libs", getRustStdDllLibName()), - filepath.Join(getRustWinX64LibDir(), getRustStdDllLibName()), - ) -} - -func getRustSysRoot() string { - // rustc --print sysroot - out, err := exec.Command("rustc", "--print", "sysroot").Output() - if err != nil { - panic(err) - } - return strings.TrimSpace(string(out)) -} - -func getRustWinX64LibDir() string { - return filepath.Join( - getRustSysRoot(), "lib", "rustlib", "x86_64-pc-windows-msvc", "lib", - ) -} - -func getRustStdDllName() string { - matches, err := filepath.Glob(getRustWinX64LibDir() + "/std-*.dll.lib") - if err != nil { - panic(err) - } - if len(matches) != 1 { - panic(fmt.Sprintf("glob(\"%s/std-*.dll.lib\") failed", getRustWinX64LibDir())) - } - dllLib := filepath.Base(matches[0]) - return strings.TrimSuffix(dllLib, ".lib") -} - -func getRustStdDllLibName() string { - return getRustStdDllName() + ".lib" -} - -func cpFile(dst, src string) { - err := os.MkdirAll(filepath.Dir(dst), 0777) - if err != nil && !os.IsExist(err) { - log.Fatal("cpFile: ", err) - } - fsrc, err := os.Open(src) - if err != nil { - log.Fatal("cpFile: ", err) - } - defer fsrc.Close() - - fdst, err := os.Create(dst) - if err != nil { - log.Fatal("cpFile: ", err) - } - defer fdst.Close() - if _, err = io.Copy(fdst, fsrc); err != nil { - log.Fatal("cpFile: ", err) - } -} diff --git a/scripts/build-windows/kcl-doc.go b/scripts/build-windows/kcl-doc.go deleted file mode 100644 index 6e0296fa4..000000000 --- a/scripts/build-windows/kcl-doc.go +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright 2021 The KCL Authors. All rights reserved. - -//go:build ingore && windows -// +build ingore,windows - -package main - -import ( - "os" - "path/filepath" - "syscall" - "unsafe" -) - -func main() { - // kclvm -m kclvm ... - var args []string - args = append(args, os.Args[0]) - args = append(args, "-m", "kclvm.tools.docs") - args = append(args, os.Args[1:]...) - os.Exit(Py_Main(args)) -} - -var ( - python39_dll = syscall.NewLazyDLL(findKclvm_dllPath()) - proc_Py_Main = python39_dll.NewProc("Py_Main") -) - -// int Py_Main(int argc, wchar_t **argv) -func Py_Main(args []string) int { - c_args := make([]*uint16, len(args)+1) - for i, s := range args { - c_args[i] = syscall.StringToUTF16Ptr(s) - } - ret, _, _ := proc_Py_Main.Call(uintptr(len(args)), uintptr(unsafe.Pointer(&c_args[0]))) - return int(ret) -} - -func findKclvm_dllPath() string { - kclvmName := "python39.dll" - - if exePath, _ := os.Executable(); exePath != "" { - exeDir := filepath.Dir(exePath) - if fi, _ := os.Stat(filepath.Join(exeDir, kclvmName)); fi != nil && !fi.IsDir() { - return filepath.Join(exeDir, kclvmName) - } - } - if wd, _ := os.Getwd(); wd != "" { - if fi, _ := os.Stat(filepath.Join(wd, kclvmName)); fi != nil && !fi.IsDir() { - return filepath.Join(wd, kclvmName) - } - wd = filepath.Join(wd, "_output/kclvm-windows") - if fi, _ := os.Stat(filepath.Join(wd, kclvmName)); fi != nil && !fi.IsDir() { - return filepath.Join(wd, kclvmName) - } - } - - return kclvmName -} diff --git a/scripts/build-windows/kcl-fmt.go b/scripts/build-windows/kcl-fmt.go deleted file mode 100644 index d221e5c65..000000000 --- a/scripts/build-windows/kcl-fmt.go +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright 2021 The KCL Authors. All rights reserved. - -//go:build ingore && windows -// +build ingore,windows - -package main - -import ( - "os" - "path/filepath" - "syscall" - "unsafe" -) - -func main() { - // kclvm -m kclvm ... - var args []string - args = append(args, os.Args[0]) - args = append(args, "-m", "kclvm.tools.format") - args = append(args, os.Args[1:]...) - os.Exit(Py_Main(args)) -} - -var ( - python39_dll = syscall.NewLazyDLL(findKclvm_dllPath()) - proc_Py_Main = python39_dll.NewProc("Py_Main") -) - -// int Py_Main(int argc, wchar_t **argv) -func Py_Main(args []string) int { - c_args := make([]*uint16, len(args)+1) - for i, s := range args { - c_args[i] = syscall.StringToUTF16Ptr(s) - } - ret, _, _ := proc_Py_Main.Call(uintptr(len(args)), uintptr(unsafe.Pointer(&c_args[0]))) - return int(ret) -} - -func findKclvm_dllPath() string { - kclvmName := "python39.dll" - - if exePath, _ := os.Executable(); exePath != "" { - exeDir := filepath.Dir(exePath) - if fi, _ := os.Stat(filepath.Join(exeDir, kclvmName)); fi != nil && !fi.IsDir() { - return filepath.Join(exeDir, kclvmName) - } - } - if wd, _ := os.Getwd(); wd != "" { - if fi, _ := os.Stat(filepath.Join(wd, kclvmName)); fi != nil && !fi.IsDir() { - return filepath.Join(wd, kclvmName) - } - wd = filepath.Join(wd, "_output/kclvm-windows") - if fi, _ := os.Stat(filepath.Join(wd, kclvmName)); fi != nil && !fi.IsDir() { - return filepath.Join(wd, kclvmName) - } - } - - return kclvmName -} diff --git a/scripts/build-windows/kcl-lint.go b/scripts/build-windows/kcl-lint.go deleted file mode 100644 index 652cecd60..000000000 --- a/scripts/build-windows/kcl-lint.go +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright 2021 The KCL Authors. All rights reserved. - -//go:build ingore && windows -// +build ingore,windows - -package main - -import ( - "os" - "path/filepath" - "syscall" - "unsafe" -) - -func main() { - // kclvm -m kclvm ... - var args []string - args = append(args, os.Args[0]) - args = append(args, "-m", "kclvm.tools.lint.lint") - args = append(args, os.Args[1:]...) - os.Exit(Py_Main(args)) -} - -var ( - python39_dll = syscall.NewLazyDLL(findKclvm_dllPath()) - proc_Py_Main = python39_dll.NewProc("Py_Main") -) - -// int Py_Main(int argc, wchar_t **argv) -func Py_Main(args []string) int { - c_args := make([]*uint16, len(args)+1) - for i, s := range args { - c_args[i] = syscall.StringToUTF16Ptr(s) - } - ret, _, _ := proc_Py_Main.Call(uintptr(len(args)), uintptr(unsafe.Pointer(&c_args[0]))) - return int(ret) -} - -func findKclvm_dllPath() string { - kclvmName := "python39.dll" - - if exePath, _ := os.Executable(); exePath != "" { - exeDir := filepath.Dir(exePath) - if fi, _ := os.Stat(filepath.Join(exeDir, kclvmName)); fi != nil && !fi.IsDir() { - return filepath.Join(exeDir, kclvmName) - } - } - if wd, _ := os.Getwd(); wd != "" { - if fi, _ := os.Stat(filepath.Join(wd, kclvmName)); fi != nil && !fi.IsDir() { - return filepath.Join(wd, kclvmName) - } - wd = filepath.Join(wd, "_output/kclvm-windows") - if fi, _ := os.Stat(filepath.Join(wd, kclvmName)); fi != nil && !fi.IsDir() { - return filepath.Join(wd, kclvmName) - } - } - - return kclvmName -} diff --git a/scripts/build-windows/kcl-plugin.go b/scripts/build-windows/kcl-plugin.go deleted file mode 100644 index 39b228de5..000000000 --- a/scripts/build-windows/kcl-plugin.go +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright 2021 The KCL Authors. All rights reserved. - -//go:build ingore && windows -// +build ingore,windows - -package main - -import ( - "os" - "path/filepath" - "syscall" - "unsafe" -) - -func main() { - // kclvm -m kclvm ... - var args []string - args = append(args, os.Args[0]) - args = append(args, "-m", "kclvm.tools.plugin") - args = append(args, os.Args[1:]...) - os.Exit(Py_Main(args)) -} - -var ( - python39_dll = syscall.NewLazyDLL(findKclvm_dllPath()) - proc_Py_Main = python39_dll.NewProc("Py_Main") -) - -// int Py_Main(int argc, wchar_t **argv) -func Py_Main(args []string) int { - c_args := make([]*uint16, len(args)+1) - for i, s := range args { - c_args[i] = syscall.StringToUTF16Ptr(s) - } - ret, _, _ := proc_Py_Main.Call(uintptr(len(args)), uintptr(unsafe.Pointer(&c_args[0]))) - return int(ret) -} - -func findKclvm_dllPath() string { - kclvmName := "python39.dll" - - if exePath, _ := os.Executable(); exePath != "" { - exeDir := filepath.Dir(exePath) - if fi, _ := os.Stat(filepath.Join(exeDir, kclvmName)); fi != nil && !fi.IsDir() { - return filepath.Join(exeDir, kclvmName) - } - } - if wd, _ := os.Getwd(); wd != "" { - if fi, _ := os.Stat(filepath.Join(wd, kclvmName)); fi != nil && !fi.IsDir() { - return filepath.Join(wd, kclvmName) - } - wd = filepath.Join(wd, "_output/kclvm-windows") - if fi, _ := os.Stat(filepath.Join(wd, kclvmName)); fi != nil && !fi.IsDir() { - return filepath.Join(wd, kclvmName) - } - } - - return kclvmName -} diff --git a/scripts/build-windows/kcl-vet.go b/scripts/build-windows/kcl-vet.go deleted file mode 100644 index e823e1f2d..000000000 --- a/scripts/build-windows/kcl-vet.go +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright 2021 The KCL Authors. All rights reserved. - -//go:build ingore && windows -// +build ingore,windows - -package main - -import ( - "os" - "path/filepath" - "syscall" - "unsafe" -) - -func main() { - // kclvm -m kclvm ... - var args []string - args = append(args, os.Args[0]) - args = append(args, "-m", "kclvm.tools.validation") - args = append(args, os.Args[1:]...) - os.Exit(Py_Main(args)) -} - -var ( - python39_dll = syscall.NewLazyDLL(findKclvm_dllPath()) - proc_Py_Main = python39_dll.NewProc("Py_Main") -) - -// int Py_Main(int argc, wchar_t **argv) -func Py_Main(args []string) int { - c_args := make([]*uint16, len(args)+1) - for i, s := range args { - c_args[i] = syscall.StringToUTF16Ptr(s) - } - ret, _, _ := proc_Py_Main.Call(uintptr(len(args)), uintptr(unsafe.Pointer(&c_args[0]))) - return int(ret) -} - -func findKclvm_dllPath() string { - kclvmName := "python39.dll" - - if exePath, _ := os.Executable(); exePath != "" { - exeDir := filepath.Dir(exePath) - if fi, _ := os.Stat(filepath.Join(exeDir, kclvmName)); fi != nil && !fi.IsDir() { - return filepath.Join(exeDir, kclvmName) - } - } - if wd, _ := os.Getwd(); wd != "" { - if fi, _ := os.Stat(filepath.Join(wd, kclvmName)); fi != nil && !fi.IsDir() { - return filepath.Join(wd, kclvmName) - } - wd = filepath.Join(wd, "_output/kclvm-windows") - if fi, _ := os.Stat(filepath.Join(wd, kclvmName)); fi != nil && !fi.IsDir() { - return filepath.Join(wd, kclvmName) - } - } - - return kclvmName -} diff --git a/scripts/build-windows/kcl.go b/scripts/build-windows/kcl.go deleted file mode 100644 index 6ad9d3b65..000000000 --- a/scripts/build-windows/kcl.go +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright 2021 The KCL Authors. All rights reserved. - -//go:build ingore && windows -// +build ingore,windows - -package main - -import ( - "os" - "path/filepath" - "syscall" - "unsafe" -) - -func main() { - // kclvm -m kclvm ... - var args []string - args = append(args, os.Args[0]) - args = append(args, "-m", "kclvm") - args = append(args, os.Args[1:]...) - os.Exit(Py_Main(args)) -} - -var ( - python39_dll = syscall.NewLazyDLL(findKclvm_dllPath()) - proc_Py_Main = python39_dll.NewProc("Py_Main") -) - -// int Py_Main(int argc, wchar_t **argv) -func Py_Main(args []string) int { - c_args := make([]*uint16, len(args)+1) - for i, s := range args { - c_args[i] = syscall.StringToUTF16Ptr(s) - } - ret, _, _ := proc_Py_Main.Call(uintptr(len(args)), uintptr(unsafe.Pointer(&c_args[0]))) - return int(ret) -} - -func findKclvm_dllPath() string { - kclvmName := "python39.dll" - - if exePath, _ := os.Executable(); exePath != "" { - exeDir := filepath.Dir(exePath) - if fi, _ := os.Stat(filepath.Join(exeDir, kclvmName)); fi != nil && !fi.IsDir() { - return filepath.Join(exeDir, kclvmName) - } - } - if wd, _ := os.Getwd(); wd != "" { - if fi, _ := os.Stat(filepath.Join(wd, kclvmName)); fi != nil && !fi.IsDir() { - return filepath.Join(wd, kclvmName) - } - wd = filepath.Join(wd, "_output/kclvm-windows") - if fi, _ := os.Stat(filepath.Join(wd, kclvmName)); fi != nil && !fi.IsDir() { - return filepath.Join(wd, kclvmName) - } - } - - return kclvmName -} diff --git a/scripts/build-windows/py39-libs/include/Python-ast.h b/scripts/build-windows/py39-libs/include/Python-ast.h deleted file mode 100644 index dfa0b1aaf..000000000 --- a/scripts/build-windows/py39-libs/include/Python-ast.h +++ /dev/null @@ -1,697 +0,0 @@ -/* File automatically generated by Parser/asdl_c.py. */ - -#ifndef Py_PYTHON_AST_H -#define Py_PYTHON_AST_H -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef Py_LIMITED_API -#include "asdl.h" - -#undef Yield /* undefine macro conflicting with */ - -typedef struct _mod *mod_ty; - -typedef struct _stmt *stmt_ty; - -typedef struct _expr *expr_ty; - -typedef enum _expr_context { Load=1, Store=2, Del=3 } expr_context_ty; - -typedef enum _boolop { And=1, Or=2 } boolop_ty; - -typedef enum _operator { Add=1, Sub=2, Mult=3, MatMult=4, Div=5, Mod=6, Pow=7, - LShift=8, RShift=9, BitOr=10, BitXor=11, BitAnd=12, - FloorDiv=13 } operator_ty; - -typedef enum _unaryop { Invert=1, Not=2, UAdd=3, USub=4 } unaryop_ty; - -typedef enum _cmpop { Eq=1, NotEq=2, Lt=3, LtE=4, Gt=5, GtE=6, Is=7, IsNot=8, - In=9, NotIn=10 } cmpop_ty; - -typedef struct _comprehension *comprehension_ty; - -typedef struct _excepthandler *excepthandler_ty; - -typedef struct _arguments *arguments_ty; - -typedef struct _arg *arg_ty; - -typedef struct _keyword *keyword_ty; - -typedef struct _alias *alias_ty; - -typedef struct _withitem *withitem_ty; - -typedef struct _type_ignore *type_ignore_ty; - - -enum _mod_kind {Module_kind=1, Interactive_kind=2, Expression_kind=3, - FunctionType_kind=4}; -struct _mod { - enum _mod_kind kind; - union { - struct { - asdl_seq *body; - asdl_seq *type_ignores; - } Module; - - struct { - asdl_seq *body; - } Interactive; - - struct { - expr_ty body; - } Expression; - - struct { - asdl_seq *argtypes; - expr_ty returns; - } FunctionType; - - } v; -}; - -enum _stmt_kind {FunctionDef_kind=1, AsyncFunctionDef_kind=2, ClassDef_kind=3, - Return_kind=4, Delete_kind=5, Assign_kind=6, - AugAssign_kind=7, AnnAssign_kind=8, For_kind=9, - AsyncFor_kind=10, While_kind=11, If_kind=12, With_kind=13, - AsyncWith_kind=14, Raise_kind=15, Try_kind=16, - Assert_kind=17, Import_kind=18, ImportFrom_kind=19, - Global_kind=20, Nonlocal_kind=21, Expr_kind=22, Pass_kind=23, - Break_kind=24, Continue_kind=25}; -struct _stmt { - enum _stmt_kind kind; - union { - struct { - identifier name; - arguments_ty args; - asdl_seq *body; - asdl_seq *decorator_list; - expr_ty returns; - string type_comment; - } FunctionDef; - - struct { - identifier name; - arguments_ty args; - asdl_seq *body; - asdl_seq *decorator_list; - expr_ty returns; - string type_comment; - } AsyncFunctionDef; - - struct { - identifier name; - asdl_seq *bases; - asdl_seq *keywords; - asdl_seq *body; - asdl_seq *decorator_list; - } ClassDef; - - struct { - expr_ty value; - } Return; - - struct { - asdl_seq *targets; - } Delete; - - struct { - asdl_seq *targets; - expr_ty value; - string type_comment; - } Assign; - - struct { - expr_ty target; - operator_ty op; - expr_ty value; - } AugAssign; - - struct { - expr_ty target; - expr_ty annotation; - expr_ty value; - int simple; - } AnnAssign; - - struct { - expr_ty target; - expr_ty iter; - asdl_seq *body; - asdl_seq *orelse; - string type_comment; - } For; - - struct { - expr_ty target; - expr_ty iter; - asdl_seq *body; - asdl_seq *orelse; - string type_comment; - } AsyncFor; - - struct { - expr_ty test; - asdl_seq *body; - asdl_seq *orelse; - } While; - - struct { - expr_ty test; - asdl_seq *body; - asdl_seq *orelse; - } If; - - struct { - asdl_seq *items; - asdl_seq *body; - string type_comment; - } With; - - struct { - asdl_seq *items; - asdl_seq *body; - string type_comment; - } AsyncWith; - - struct { - expr_ty exc; - expr_ty cause; - } Raise; - - struct { - asdl_seq *body; - asdl_seq *handlers; - asdl_seq *orelse; - asdl_seq *finalbody; - } Try; - - struct { - expr_ty test; - expr_ty msg; - } Assert; - - struct { - asdl_seq *names; - } Import; - - struct { - identifier module; - asdl_seq *names; - int level; - } ImportFrom; - - struct { - asdl_seq *names; - } Global; - - struct { - asdl_seq *names; - } Nonlocal; - - struct { - expr_ty value; - } Expr; - - } v; - int lineno; - int col_offset; - int end_lineno; - int end_col_offset; -}; - -enum _expr_kind {BoolOp_kind=1, NamedExpr_kind=2, BinOp_kind=3, UnaryOp_kind=4, - Lambda_kind=5, IfExp_kind=6, Dict_kind=7, Set_kind=8, - ListComp_kind=9, SetComp_kind=10, DictComp_kind=11, - GeneratorExp_kind=12, Await_kind=13, Yield_kind=14, - YieldFrom_kind=15, Compare_kind=16, Call_kind=17, - FormattedValue_kind=18, JoinedStr_kind=19, Constant_kind=20, - Attribute_kind=21, Subscript_kind=22, Starred_kind=23, - Name_kind=24, List_kind=25, Tuple_kind=26, Slice_kind=27}; -struct _expr { - enum _expr_kind kind; - union { - struct { - boolop_ty op; - asdl_seq *values; - } BoolOp; - - struct { - expr_ty target; - expr_ty value; - } NamedExpr; - - struct { - expr_ty left; - operator_ty op; - expr_ty right; - } BinOp; - - struct { - unaryop_ty op; - expr_ty operand; - } UnaryOp; - - struct { - arguments_ty args; - expr_ty body; - } Lambda; - - struct { - expr_ty test; - expr_ty body; - expr_ty orelse; - } IfExp; - - struct { - asdl_seq *keys; - asdl_seq *values; - } Dict; - - struct { - asdl_seq *elts; - } Set; - - struct { - expr_ty elt; - asdl_seq *generators; - } ListComp; - - struct { - expr_ty elt; - asdl_seq *generators; - } SetComp; - - struct { - expr_ty key; - expr_ty value; - asdl_seq *generators; - } DictComp; - - struct { - expr_ty elt; - asdl_seq *generators; - } GeneratorExp; - - struct { - expr_ty value; - } Await; - - struct { - expr_ty value; - } Yield; - - struct { - expr_ty value; - } YieldFrom; - - struct { - expr_ty left; - asdl_int_seq *ops; - asdl_seq *comparators; - } Compare; - - struct { - expr_ty func; - asdl_seq *args; - asdl_seq *keywords; - } Call; - - struct { - expr_ty value; - int conversion; - expr_ty format_spec; - } FormattedValue; - - struct { - asdl_seq *values; - } JoinedStr; - - struct { - constant value; - string kind; - } Constant; - - struct { - expr_ty value; - identifier attr; - expr_context_ty ctx; - } Attribute; - - struct { - expr_ty value; - expr_ty slice; - expr_context_ty ctx; - } Subscript; - - struct { - expr_ty value; - expr_context_ty ctx; - } Starred; - - struct { - identifier id; - expr_context_ty ctx; - } Name; - - struct { - asdl_seq *elts; - expr_context_ty ctx; - } List; - - struct { - asdl_seq *elts; - expr_context_ty ctx; - } Tuple; - - struct { - expr_ty lower; - expr_ty upper; - expr_ty step; - } Slice; - - } v; - int lineno; - int col_offset; - int end_lineno; - int end_col_offset; -}; - -struct _comprehension { - expr_ty target; - expr_ty iter; - asdl_seq *ifs; - int is_async; -}; - -enum _excepthandler_kind {ExceptHandler_kind=1}; -struct _excepthandler { - enum _excepthandler_kind kind; - union { - struct { - expr_ty type; - identifier name; - asdl_seq *body; - } ExceptHandler; - - } v; - int lineno; - int col_offset; - int end_lineno; - int end_col_offset; -}; - -struct _arguments { - asdl_seq *posonlyargs; - asdl_seq *args; - arg_ty vararg; - asdl_seq *kwonlyargs; - asdl_seq *kw_defaults; - arg_ty kwarg; - asdl_seq *defaults; -}; - -struct _arg { - identifier arg; - expr_ty annotation; - string type_comment; - int lineno; - int col_offset; - int end_lineno; - int end_col_offset; -}; - -struct _keyword { - identifier arg; - expr_ty value; - int lineno; - int col_offset; - int end_lineno; - int end_col_offset; -}; - -struct _alias { - identifier name; - identifier asname; -}; - -struct _withitem { - expr_ty context_expr; - expr_ty optional_vars; -}; - -enum _type_ignore_kind {TypeIgnore_kind=1}; -struct _type_ignore { - enum _type_ignore_kind kind; - union { - struct { - int lineno; - string tag; - } TypeIgnore; - - } v; -}; - - -// Note: these macros affect function definitions, not only call sites. -#define Module(a0, a1, a2) _Py_Module(a0, a1, a2) -mod_ty _Py_Module(asdl_seq * body, asdl_seq * type_ignores, PyArena *arena); -#define Interactive(a0, a1) _Py_Interactive(a0, a1) -mod_ty _Py_Interactive(asdl_seq * body, PyArena *arena); -#define Expression(a0, a1) _Py_Expression(a0, a1) -mod_ty _Py_Expression(expr_ty body, PyArena *arena); -#define FunctionType(a0, a1, a2) _Py_FunctionType(a0, a1, a2) -mod_ty _Py_FunctionType(asdl_seq * argtypes, expr_ty returns, PyArena *arena); -#define FunctionDef(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10) _Py_FunctionDef(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10) -stmt_ty _Py_FunctionDef(identifier name, arguments_ty args, asdl_seq * body, - asdl_seq * decorator_list, expr_ty returns, string - type_comment, int lineno, int col_offset, int - end_lineno, int end_col_offset, PyArena *arena); -#define AsyncFunctionDef(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10) _Py_AsyncFunctionDef(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10) -stmt_ty _Py_AsyncFunctionDef(identifier name, arguments_ty args, asdl_seq * - body, asdl_seq * decorator_list, expr_ty returns, - string type_comment, int lineno, int col_offset, - int end_lineno, int end_col_offset, PyArena - *arena); -#define ClassDef(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9) _Py_ClassDef(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9) -stmt_ty _Py_ClassDef(identifier name, asdl_seq * bases, asdl_seq * keywords, - asdl_seq * body, asdl_seq * decorator_list, int lineno, - int col_offset, int end_lineno, int end_col_offset, - PyArena *arena); -#define Return(a0, a1, a2, a3, a4, a5) _Py_Return(a0, a1, a2, a3, a4, a5) -stmt_ty _Py_Return(expr_ty value, int lineno, int col_offset, int end_lineno, - int end_col_offset, PyArena *arena); -#define Delete(a0, a1, a2, a3, a4, a5) _Py_Delete(a0, a1, a2, a3, a4, a5) -stmt_ty _Py_Delete(asdl_seq * targets, int lineno, int col_offset, int - end_lineno, int end_col_offset, PyArena *arena); -#define Assign(a0, a1, a2, a3, a4, a5, a6, a7) _Py_Assign(a0, a1, a2, a3, a4, a5, a6, a7) -stmt_ty _Py_Assign(asdl_seq * targets, expr_ty value, string type_comment, int - lineno, int col_offset, int end_lineno, int end_col_offset, - PyArena *arena); -#define AugAssign(a0, a1, a2, a3, a4, a5, a6, a7) _Py_AugAssign(a0, a1, a2, a3, a4, a5, a6, a7) -stmt_ty _Py_AugAssign(expr_ty target, operator_ty op, expr_ty value, int - lineno, int col_offset, int end_lineno, int - end_col_offset, PyArena *arena); -#define AnnAssign(a0, a1, a2, a3, a4, a5, a6, a7, a8) _Py_AnnAssign(a0, a1, a2, a3, a4, a5, a6, a7, a8) -stmt_ty _Py_AnnAssign(expr_ty target, expr_ty annotation, expr_ty value, int - simple, int lineno, int col_offset, int end_lineno, int - end_col_offset, PyArena *arena); -#define For(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9) _Py_For(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9) -stmt_ty _Py_For(expr_ty target, expr_ty iter, asdl_seq * body, asdl_seq * - orelse, string type_comment, int lineno, int col_offset, int - end_lineno, int end_col_offset, PyArena *arena); -#define AsyncFor(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9) _Py_AsyncFor(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9) -stmt_ty _Py_AsyncFor(expr_ty target, expr_ty iter, asdl_seq * body, asdl_seq * - orelse, string type_comment, int lineno, int col_offset, - int end_lineno, int end_col_offset, PyArena *arena); -#define While(a0, a1, a2, a3, a4, a5, a6, a7) _Py_While(a0, a1, a2, a3, a4, a5, a6, a7) -stmt_ty _Py_While(expr_ty test, asdl_seq * body, asdl_seq * orelse, int lineno, - int col_offset, int end_lineno, int end_col_offset, PyArena - *arena); -#define If(a0, a1, a2, a3, a4, a5, a6, a7) _Py_If(a0, a1, a2, a3, a4, a5, a6, a7) -stmt_ty _Py_If(expr_ty test, asdl_seq * body, asdl_seq * orelse, int lineno, - int col_offset, int end_lineno, int end_col_offset, PyArena - *arena); -#define With(a0, a1, a2, a3, a4, a5, a6, a7) _Py_With(a0, a1, a2, a3, a4, a5, a6, a7) -stmt_ty _Py_With(asdl_seq * items, asdl_seq * body, string type_comment, int - lineno, int col_offset, int end_lineno, int end_col_offset, - PyArena *arena); -#define AsyncWith(a0, a1, a2, a3, a4, a5, a6, a7) _Py_AsyncWith(a0, a1, a2, a3, a4, a5, a6, a7) -stmt_ty _Py_AsyncWith(asdl_seq * items, asdl_seq * body, string type_comment, - int lineno, int col_offset, int end_lineno, int - end_col_offset, PyArena *arena); -#define Raise(a0, a1, a2, a3, a4, a5, a6) _Py_Raise(a0, a1, a2, a3, a4, a5, a6) -stmt_ty _Py_Raise(expr_ty exc, expr_ty cause, int lineno, int col_offset, int - end_lineno, int end_col_offset, PyArena *arena); -#define Try(a0, a1, a2, a3, a4, a5, a6, a7, a8) _Py_Try(a0, a1, a2, a3, a4, a5, a6, a7, a8) -stmt_ty _Py_Try(asdl_seq * body, asdl_seq * handlers, asdl_seq * orelse, - asdl_seq * finalbody, int lineno, int col_offset, int - end_lineno, int end_col_offset, PyArena *arena); -#define Assert(a0, a1, a2, a3, a4, a5, a6) _Py_Assert(a0, a1, a2, a3, a4, a5, a6) -stmt_ty _Py_Assert(expr_ty test, expr_ty msg, int lineno, int col_offset, int - end_lineno, int end_col_offset, PyArena *arena); -#define Import(a0, a1, a2, a3, a4, a5) _Py_Import(a0, a1, a2, a3, a4, a5) -stmt_ty _Py_Import(asdl_seq * names, int lineno, int col_offset, int - end_lineno, int end_col_offset, PyArena *arena); -#define ImportFrom(a0, a1, a2, a3, a4, a5, a6, a7) _Py_ImportFrom(a0, a1, a2, a3, a4, a5, a6, a7) -stmt_ty _Py_ImportFrom(identifier module, asdl_seq * names, int level, int - lineno, int col_offset, int end_lineno, int - end_col_offset, PyArena *arena); -#define Global(a0, a1, a2, a3, a4, a5) _Py_Global(a0, a1, a2, a3, a4, a5) -stmt_ty _Py_Global(asdl_seq * names, int lineno, int col_offset, int - end_lineno, int end_col_offset, PyArena *arena); -#define Nonlocal(a0, a1, a2, a3, a4, a5) _Py_Nonlocal(a0, a1, a2, a3, a4, a5) -stmt_ty _Py_Nonlocal(asdl_seq * names, int lineno, int col_offset, int - end_lineno, int end_col_offset, PyArena *arena); -#define Expr(a0, a1, a2, a3, a4, a5) _Py_Expr(a0, a1, a2, a3, a4, a5) -stmt_ty _Py_Expr(expr_ty value, int lineno, int col_offset, int end_lineno, int - end_col_offset, PyArena *arena); -#define Pass(a0, a1, a2, a3, a4) _Py_Pass(a0, a1, a2, a3, a4) -stmt_ty _Py_Pass(int lineno, int col_offset, int end_lineno, int - end_col_offset, PyArena *arena); -#define Break(a0, a1, a2, a3, a4) _Py_Break(a0, a1, a2, a3, a4) -stmt_ty _Py_Break(int lineno, int col_offset, int end_lineno, int - end_col_offset, PyArena *arena); -#define Continue(a0, a1, a2, a3, a4) _Py_Continue(a0, a1, a2, a3, a4) -stmt_ty _Py_Continue(int lineno, int col_offset, int end_lineno, int - end_col_offset, PyArena *arena); -#define BoolOp(a0, a1, a2, a3, a4, a5, a6) _Py_BoolOp(a0, a1, a2, a3, a4, a5, a6) -expr_ty _Py_BoolOp(boolop_ty op, asdl_seq * values, int lineno, int col_offset, - int end_lineno, int end_col_offset, PyArena *arena); -#define NamedExpr(a0, a1, a2, a3, a4, a5, a6) _Py_NamedExpr(a0, a1, a2, a3, a4, a5, a6) -expr_ty _Py_NamedExpr(expr_ty target, expr_ty value, int lineno, int - col_offset, int end_lineno, int end_col_offset, PyArena - *arena); -#define BinOp(a0, a1, a2, a3, a4, a5, a6, a7) _Py_BinOp(a0, a1, a2, a3, a4, a5, a6, a7) -expr_ty _Py_BinOp(expr_ty left, operator_ty op, expr_ty right, int lineno, int - col_offset, int end_lineno, int end_col_offset, PyArena - *arena); -#define UnaryOp(a0, a1, a2, a3, a4, a5, a6) _Py_UnaryOp(a0, a1, a2, a3, a4, a5, a6) -expr_ty _Py_UnaryOp(unaryop_ty op, expr_ty operand, int lineno, int col_offset, - int end_lineno, int end_col_offset, PyArena *arena); -#define Lambda(a0, a1, a2, a3, a4, a5, a6) _Py_Lambda(a0, a1, a2, a3, a4, a5, a6) -expr_ty _Py_Lambda(arguments_ty args, expr_ty body, int lineno, int col_offset, - int end_lineno, int end_col_offset, PyArena *arena); -#define IfExp(a0, a1, a2, a3, a4, a5, a6, a7) _Py_IfExp(a0, a1, a2, a3, a4, a5, a6, a7) -expr_ty _Py_IfExp(expr_ty test, expr_ty body, expr_ty orelse, int lineno, int - col_offset, int end_lineno, int end_col_offset, PyArena - *arena); -#define Dict(a0, a1, a2, a3, a4, a5, a6) _Py_Dict(a0, a1, a2, a3, a4, a5, a6) -expr_ty _Py_Dict(asdl_seq * keys, asdl_seq * values, int lineno, int - col_offset, int end_lineno, int end_col_offset, PyArena - *arena); -#define Set(a0, a1, a2, a3, a4, a5) _Py_Set(a0, a1, a2, a3, a4, a5) -expr_ty _Py_Set(asdl_seq * elts, int lineno, int col_offset, int end_lineno, - int end_col_offset, PyArena *arena); -#define ListComp(a0, a1, a2, a3, a4, a5, a6) _Py_ListComp(a0, a1, a2, a3, a4, a5, a6) -expr_ty _Py_ListComp(expr_ty elt, asdl_seq * generators, int lineno, int - col_offset, int end_lineno, int end_col_offset, PyArena - *arena); -#define SetComp(a0, a1, a2, a3, a4, a5, a6) _Py_SetComp(a0, a1, a2, a3, a4, a5, a6) -expr_ty _Py_SetComp(expr_ty elt, asdl_seq * generators, int lineno, int - col_offset, int end_lineno, int end_col_offset, PyArena - *arena); -#define DictComp(a0, a1, a2, a3, a4, a5, a6, a7) _Py_DictComp(a0, a1, a2, a3, a4, a5, a6, a7) -expr_ty _Py_DictComp(expr_ty key, expr_ty value, asdl_seq * generators, int - lineno, int col_offset, int end_lineno, int - end_col_offset, PyArena *arena); -#define GeneratorExp(a0, a1, a2, a3, a4, a5, a6) _Py_GeneratorExp(a0, a1, a2, a3, a4, a5, a6) -expr_ty _Py_GeneratorExp(expr_ty elt, asdl_seq * generators, int lineno, int - col_offset, int end_lineno, int end_col_offset, - PyArena *arena); -#define Await(a0, a1, a2, a3, a4, a5) _Py_Await(a0, a1, a2, a3, a4, a5) -expr_ty _Py_Await(expr_ty value, int lineno, int col_offset, int end_lineno, - int end_col_offset, PyArena *arena); -#define Yield(a0, a1, a2, a3, a4, a5) _Py_Yield(a0, a1, a2, a3, a4, a5) -expr_ty _Py_Yield(expr_ty value, int lineno, int col_offset, int end_lineno, - int end_col_offset, PyArena *arena); -#define YieldFrom(a0, a1, a2, a3, a4, a5) _Py_YieldFrom(a0, a1, a2, a3, a4, a5) -expr_ty _Py_YieldFrom(expr_ty value, int lineno, int col_offset, int - end_lineno, int end_col_offset, PyArena *arena); -#define Compare(a0, a1, a2, a3, a4, a5, a6, a7) _Py_Compare(a0, a1, a2, a3, a4, a5, a6, a7) -expr_ty _Py_Compare(expr_ty left, asdl_int_seq * ops, asdl_seq * comparators, - int lineno, int col_offset, int end_lineno, int - end_col_offset, PyArena *arena); -#define Call(a0, a1, a2, a3, a4, a5, a6, a7) _Py_Call(a0, a1, a2, a3, a4, a5, a6, a7) -expr_ty _Py_Call(expr_ty func, asdl_seq * args, asdl_seq * keywords, int - lineno, int col_offset, int end_lineno, int end_col_offset, - PyArena *arena); -#define FormattedValue(a0, a1, a2, a3, a4, a5, a6, a7) _Py_FormattedValue(a0, a1, a2, a3, a4, a5, a6, a7) -expr_ty _Py_FormattedValue(expr_ty value, int conversion, expr_ty format_spec, - int lineno, int col_offset, int end_lineno, int - end_col_offset, PyArena *arena); -#define JoinedStr(a0, a1, a2, a3, a4, a5) _Py_JoinedStr(a0, a1, a2, a3, a4, a5) -expr_ty _Py_JoinedStr(asdl_seq * values, int lineno, int col_offset, int - end_lineno, int end_col_offset, PyArena *arena); -#define Constant(a0, a1, a2, a3, a4, a5, a6) _Py_Constant(a0, a1, a2, a3, a4, a5, a6) -expr_ty _Py_Constant(constant value, string kind, int lineno, int col_offset, - int end_lineno, int end_col_offset, PyArena *arena); -#define Attribute(a0, a1, a2, a3, a4, a5, a6, a7) _Py_Attribute(a0, a1, a2, a3, a4, a5, a6, a7) -expr_ty _Py_Attribute(expr_ty value, identifier attr, expr_context_ty ctx, int - lineno, int col_offset, int end_lineno, int - end_col_offset, PyArena *arena); -#define Subscript(a0, a1, a2, a3, a4, a5, a6, a7) _Py_Subscript(a0, a1, a2, a3, a4, a5, a6, a7) -expr_ty _Py_Subscript(expr_ty value, expr_ty slice, expr_context_ty ctx, int - lineno, int col_offset, int end_lineno, int - end_col_offset, PyArena *arena); -#define Starred(a0, a1, a2, a3, a4, a5, a6) _Py_Starred(a0, a1, a2, a3, a4, a5, a6) -expr_ty _Py_Starred(expr_ty value, expr_context_ty ctx, int lineno, int - col_offset, int end_lineno, int end_col_offset, PyArena - *arena); -#define Name(a0, a1, a2, a3, a4, a5, a6) _Py_Name(a0, a1, a2, a3, a4, a5, a6) -expr_ty _Py_Name(identifier id, expr_context_ty ctx, int lineno, int - col_offset, int end_lineno, int end_col_offset, PyArena - *arena); -#define List(a0, a1, a2, a3, a4, a5, a6) _Py_List(a0, a1, a2, a3, a4, a5, a6) -expr_ty _Py_List(asdl_seq * elts, expr_context_ty ctx, int lineno, int - col_offset, int end_lineno, int end_col_offset, PyArena - *arena); -#define Tuple(a0, a1, a2, a3, a4, a5, a6) _Py_Tuple(a0, a1, a2, a3, a4, a5, a6) -expr_ty _Py_Tuple(asdl_seq * elts, expr_context_ty ctx, int lineno, int - col_offset, int end_lineno, int end_col_offset, PyArena - *arena); -#define Slice(a0, a1, a2, a3, a4, a5, a6, a7) _Py_Slice(a0, a1, a2, a3, a4, a5, a6, a7) -expr_ty _Py_Slice(expr_ty lower, expr_ty upper, expr_ty step, int lineno, int - col_offset, int end_lineno, int end_col_offset, PyArena - *arena); -#define comprehension(a0, a1, a2, a3, a4) _Py_comprehension(a0, a1, a2, a3, a4) -comprehension_ty _Py_comprehension(expr_ty target, expr_ty iter, asdl_seq * - ifs, int is_async, PyArena *arena); -#define ExceptHandler(a0, a1, a2, a3, a4, a5, a6, a7) _Py_ExceptHandler(a0, a1, a2, a3, a4, a5, a6, a7) -excepthandler_ty _Py_ExceptHandler(expr_ty type, identifier name, asdl_seq * - body, int lineno, int col_offset, int - end_lineno, int end_col_offset, PyArena - *arena); -#define arguments(a0, a1, a2, a3, a4, a5, a6, a7) _Py_arguments(a0, a1, a2, a3, a4, a5, a6, a7) -arguments_ty _Py_arguments(asdl_seq * posonlyargs, asdl_seq * args, arg_ty - vararg, asdl_seq * kwonlyargs, asdl_seq * - kw_defaults, arg_ty kwarg, asdl_seq * defaults, - PyArena *arena); -#define arg(a0, a1, a2, a3, a4, a5, a6, a7) _Py_arg(a0, a1, a2, a3, a4, a5, a6, a7) -arg_ty _Py_arg(identifier arg, expr_ty annotation, string type_comment, int - lineno, int col_offset, int end_lineno, int end_col_offset, - PyArena *arena); -#define keyword(a0, a1, a2, a3, a4, a5, a6) _Py_keyword(a0, a1, a2, a3, a4, a5, a6) -keyword_ty _Py_keyword(identifier arg, expr_ty value, int lineno, int - col_offset, int end_lineno, int end_col_offset, PyArena - *arena); -#define alias(a0, a1, a2) _Py_alias(a0, a1, a2) -alias_ty _Py_alias(identifier name, identifier asname, PyArena *arena); -#define withitem(a0, a1, a2) _Py_withitem(a0, a1, a2) -withitem_ty _Py_withitem(expr_ty context_expr, expr_ty optional_vars, PyArena - *arena); -#define TypeIgnore(a0, a1, a2) _Py_TypeIgnore(a0, a1, a2) -type_ignore_ty _Py_TypeIgnore(int lineno, string tag, PyArena *arena); - -PyObject* PyAST_mod2obj(mod_ty t); -mod_ty PyAST_obj2mod(PyObject* ast, PyArena* arena, int mode); -int PyAST_Check(PyObject* obj); -#endif /* !Py_LIMITED_API */ - -#ifdef __cplusplus -} -#endif -#endif /* !Py_PYTHON_AST_H */ diff --git a/scripts/build-windows/py39-libs/include/Python.h b/scripts/build-windows/py39-libs/include/Python.h deleted file mode 100644 index 613453db4..000000000 --- a/scripts/build-windows/py39-libs/include/Python.h +++ /dev/null @@ -1,172 +0,0 @@ -#ifndef Py_PYTHON_H -#define Py_PYTHON_H -/* Since this is a "meta-include" file, no #ifdef __cplusplus / extern "C" { */ - -/* Include nearly all Python header files */ - -#include "patchlevel.h" -#include "pyconfig.h" -#include "pymacconfig.h" - -#include - -#ifndef UCHAR_MAX -#error "Something's broken. UCHAR_MAX should be defined in limits.h." -#endif - -#if UCHAR_MAX != 255 -#error "Python's source code assumes C's unsigned char is an 8-bit type." -#endif - -#if defined(__sgi) && !defined(_SGI_MP_SOURCE) -#define _SGI_MP_SOURCE -#endif - -#include -#ifndef NULL -# error "Python.h requires that stdio.h define NULL." -#endif - -#include -#ifdef HAVE_ERRNO_H -#include -#endif -#include -#ifndef MS_WINDOWS -#include -#endif -#ifdef HAVE_CRYPT_H -#if defined(HAVE_CRYPT_R) && !defined(_GNU_SOURCE) -/* Required for glibc to expose the crypt_r() function prototype. */ -# define _GNU_SOURCE -# define _Py_GNU_SOURCE_FOR_CRYPT -#endif -#include -#ifdef _Py_GNU_SOURCE_FOR_CRYPT -/* Don't leak the _GNU_SOURCE define to other headers. */ -# undef _GNU_SOURCE -# undef _Py_GNU_SOURCE_FOR_CRYPT -#endif -#endif - -/* For size_t? */ -#ifdef HAVE_STDDEF_H -#include -#endif - -/* CAUTION: Build setups should ensure that NDEBUG is defined on the - * compiler command line when building Python in release mode; else - * assert() calls won't be removed. - */ -#include - -#include "pyport.h" -#include "pymacro.h" - -/* A convenient way for code to know if sanitizers are enabled. */ -#if defined(__has_feature) -# if __has_feature(memory_sanitizer) -# if !defined(_Py_MEMORY_SANITIZER) -# define _Py_MEMORY_SANITIZER -# endif -# endif -# if __has_feature(address_sanitizer) -# if !defined(_Py_ADDRESS_SANITIZER) -# define _Py_ADDRESS_SANITIZER -# endif -# endif -#elif defined(__GNUC__) -# if defined(__SANITIZE_ADDRESS__) -# define _Py_ADDRESS_SANITIZER -# endif -#endif - -/* Debug-mode build with pymalloc implies PYMALLOC_DEBUG. - * PYMALLOC_DEBUG is in error if pymalloc is not in use. - */ -#if defined(Py_DEBUG) && defined(WITH_PYMALLOC) && !defined(PYMALLOC_DEBUG) -#define PYMALLOC_DEBUG -#endif -#if defined(PYMALLOC_DEBUG) && !defined(WITH_PYMALLOC) -#error "PYMALLOC_DEBUG requires WITH_PYMALLOC" -#endif -#include "pymath.h" -#include "pytime.h" -#include "pymem.h" - -#include "object.h" -#include "objimpl.h" -#include "typeslots.h" -#include "pyhash.h" - -#include "pydebug.h" - -#include "bytearrayobject.h" -#include "bytesobject.h" -#include "unicodeobject.h" -#include "longobject.h" -#include "longintrepr.h" -#include "boolobject.h" -#include "floatobject.h" -#include "complexobject.h" -#include "rangeobject.h" -#include "memoryobject.h" -#include "tupleobject.h" -#include "listobject.h" -#include "dictobject.h" -#include "odictobject.h" -#include "enumobject.h" -#include "setobject.h" -#include "methodobject.h" -#include "moduleobject.h" -#include "funcobject.h" -#include "classobject.h" -#include "fileobject.h" -#include "pycapsule.h" -#include "code.h" -#include "pyframe.h" -#include "traceback.h" -#include "sliceobject.h" -#include "cellobject.h" -#include "iterobject.h" -#include "genobject.h" -#include "descrobject.h" -#include "genericaliasobject.h" -#include "warnings.h" -#include "weakrefobject.h" -#include "structseq.h" -#include "namespaceobject.h" -#include "picklebufobject.h" - -#include "codecs.h" -#include "pyerrors.h" - -#include "cpython/initconfig.h" -#include "pythread.h" -#include "pystate.h" -#include "context.h" - -#include "pyarena.h" -#include "modsupport.h" -#include "compile.h" -#include "pythonrun.h" -#include "pylifecycle.h" -#include "ceval.h" -#include "sysmodule.h" -#include "osmodule.h" -#include "intrcheck.h" -#include "import.h" - -#include "abstract.h" -#include "bltinmodule.h" - -#include "eval.h" - -#include "pyctype.h" -#include "pystrtod.h" -#include "pystrcmp.h" -#include "fileutils.h" -#include "pyfpe.h" -#include "tracemalloc.h" - -#endif /* !Py_PYTHON_H */ diff --git a/scripts/build-windows/py39-libs/include/abstract.h b/scripts/build-windows/py39-libs/include/abstract.h deleted file mode 100644 index bb51c668a..000000000 --- a/scripts/build-windows/py39-libs/include/abstract.h +++ /dev/null @@ -1,850 +0,0 @@ -/* Abstract Object Interface (many thanks to Jim Fulton) */ - -#ifndef Py_ABSTRACTOBJECT_H -#define Py_ABSTRACTOBJECT_H -#ifdef __cplusplus -extern "C" { -#endif - -/* === Object Protocol ================================================== */ - -/* Implemented elsewhere: - - int PyObject_Print(PyObject *o, FILE *fp, int flags); - - Print an object 'o' on file 'fp'. Returns -1 on error. The flags argument - is used to enable certain printing options. The only option currently - supported is Py_Print_RAW. - - (What should be said about Py_Print_RAW?). */ - - -/* Implemented elsewhere: - - int PyObject_HasAttrString(PyObject *o, const char *attr_name); - - Returns 1 if object 'o' has the attribute attr_name, and 0 otherwise. - - This is equivalent to the Python expression: hasattr(o,attr_name). - - This function always succeeds. */ - - -/* Implemented elsewhere: - - PyObject* PyObject_GetAttrString(PyObject *o, const char *attr_name); - - Retrieve an attributed named attr_name form object o. - Returns the attribute value on success, or NULL on failure. - - This is the equivalent of the Python expression: o.attr_name. */ - - -/* Implemented elsewhere: - - int PyObject_HasAttr(PyObject *o, PyObject *attr_name); - - Returns 1 if o has the attribute attr_name, and 0 otherwise. - - This is equivalent to the Python expression: hasattr(o,attr_name). - - This function always succeeds. */ - -/* Implemented elsewhere: - - PyObject* PyObject_GetAttr(PyObject *o, PyObject *attr_name); - - Retrieve an attributed named 'attr_name' form object 'o'. - Returns the attribute value on success, or NULL on failure. - - This is the equivalent of the Python expression: o.attr_name. */ - - -/* Implemented elsewhere: - - int PyObject_SetAttrString(PyObject *o, const char *attr_name, PyObject *v); - - Set the value of the attribute named attr_name, for object 'o', - to the value 'v'. Raise an exception and return -1 on failure; return 0 on - success. - - This is the equivalent of the Python statement o.attr_name=v. */ - - -/* Implemented elsewhere: - - int PyObject_SetAttr(PyObject *o, PyObject *attr_name, PyObject *v); - - Set the value of the attribute named attr_name, for object 'o', to the value - 'v'. an exception and return -1 on failure; return 0 on success. - - This is the equivalent of the Python statement o.attr_name=v. */ - -/* Implemented as a macro: - - int PyObject_DelAttrString(PyObject *o, const char *attr_name); - - Delete attribute named attr_name, for object o. Returns - -1 on failure. - - This is the equivalent of the Python statement: del o.attr_name. */ -#define PyObject_DelAttrString(O,A) PyObject_SetAttrString((O),(A), NULL) - - -/* Implemented as a macro: - - int PyObject_DelAttr(PyObject *o, PyObject *attr_name); - - Delete attribute named attr_name, for object o. Returns -1 - on failure. This is the equivalent of the Python - statement: del o.attr_name. */ -#define PyObject_DelAttr(O,A) PyObject_SetAttr((O),(A), NULL) - - -/* Implemented elsewhere: - - PyObject *PyObject_Repr(PyObject *o); - - Compute the string representation of object 'o'. Returns the - string representation on success, NULL on failure. - - This is the equivalent of the Python expression: repr(o). - - Called by the repr() built-in function. */ - - -/* Implemented elsewhere: - - PyObject *PyObject_Str(PyObject *o); - - Compute the string representation of object, o. Returns the - string representation on success, NULL on failure. - - This is the equivalent of the Python expression: str(o). - - Called by the str() and print() built-in functions. */ - - -/* Declared elsewhere - - PyAPI_FUNC(int) PyCallable_Check(PyObject *o); - - Determine if the object, o, is callable. Return 1 if the object is callable - and 0 otherwise. - - This function always succeeds. */ - - -#ifdef PY_SSIZE_T_CLEAN -# define PyObject_CallFunction _PyObject_CallFunction_SizeT -# define PyObject_CallMethod _PyObject_CallMethod_SizeT -#endif - - -#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03090000 -/* Call a callable Python object without any arguments */ -PyAPI_FUNC(PyObject *) PyObject_CallNoArgs(PyObject *func); -#endif - - -/* Call a callable Python object 'callable' with arguments given by the - tuple 'args' and keywords arguments given by the dictionary 'kwargs'. - - 'args' must not be NULL, use an empty tuple if no arguments are - needed. If no named arguments are needed, 'kwargs' can be NULL. - - This is the equivalent of the Python expression: - callable(*args, **kwargs). */ -PyAPI_FUNC(PyObject *) PyObject_Call(PyObject *callable, - PyObject *args, PyObject *kwargs); - - -/* Call a callable Python object 'callable', with arguments given by the - tuple 'args'. If no arguments are needed, then 'args' can be NULL. - - Returns the result of the call on success, or NULL on failure. - - This is the equivalent of the Python expression: - callable(*args). */ -PyAPI_FUNC(PyObject *) PyObject_CallObject(PyObject *callable, - PyObject *args); - -/* Call a callable Python object, callable, with a variable number of C - arguments. The C arguments are described using a mkvalue-style format - string. - - The format may be NULL, indicating that no arguments are provided. - - Returns the result of the call on success, or NULL on failure. - - This is the equivalent of the Python expression: - callable(arg1, arg2, ...). */ -PyAPI_FUNC(PyObject *) PyObject_CallFunction(PyObject *callable, - const char *format, ...); - -/* Call the method named 'name' of object 'obj' with a variable number of - C arguments. The C arguments are described by a mkvalue format string. - - The format can be NULL, indicating that no arguments are provided. - - Returns the result of the call on success, or NULL on failure. - - This is the equivalent of the Python expression: - obj.name(arg1, arg2, ...). */ -PyAPI_FUNC(PyObject *) PyObject_CallMethod(PyObject *obj, - const char *name, - const char *format, ...); - -PyAPI_FUNC(PyObject *) _PyObject_CallFunction_SizeT(PyObject *callable, - const char *format, - ...); - -PyAPI_FUNC(PyObject *) _PyObject_CallMethod_SizeT(PyObject *obj, - const char *name, - const char *format, - ...); - -/* Call a callable Python object 'callable' with a variable number of C - arguments. The C arguments are provided as PyObject* values, terminated - by a NULL. - - Returns the result of the call on success, or NULL on failure. - - This is the equivalent of the Python expression: - callable(arg1, arg2, ...). */ -PyAPI_FUNC(PyObject *) PyObject_CallFunctionObjArgs(PyObject *callable, - ...); - -/* Call the method named 'name' of object 'obj' with a variable number of - C arguments. The C arguments are provided as PyObject* values, terminated - by NULL. - - Returns the result of the call on success, or NULL on failure. - - This is the equivalent of the Python expression: obj.name(*args). */ - -PyAPI_FUNC(PyObject *) PyObject_CallMethodObjArgs( - PyObject *obj, - PyObject *name, - ...); - - -/* Implemented elsewhere: - - Py_hash_t PyObject_Hash(PyObject *o); - - Compute and return the hash, hash_value, of an object, o. On - failure, return -1. - - This is the equivalent of the Python expression: hash(o). */ - - -/* Implemented elsewhere: - - int PyObject_IsTrue(PyObject *o); - - Returns 1 if the object, o, is considered to be true, 0 if o is - considered to be false and -1 on failure. - - This is equivalent to the Python expression: not not o. */ - - -/* Implemented elsewhere: - - int PyObject_Not(PyObject *o); - - Returns 0 if the object, o, is considered to be true, 1 if o is - considered to be false and -1 on failure. - - This is equivalent to the Python expression: not o. */ - - -/* Get the type of an object. - - On success, returns a type object corresponding to the object type of object - 'o'. On failure, returns NULL. - - This is equivalent to the Python expression: type(o) */ -PyAPI_FUNC(PyObject *) PyObject_Type(PyObject *o); - - -/* Return the size of object 'o'. If the object 'o' provides both sequence and - mapping protocols, the sequence size is returned. - - On error, -1 is returned. - - This is the equivalent to the Python expression: len(o) */ -PyAPI_FUNC(Py_ssize_t) PyObject_Size(PyObject *o); - - -/* For DLL compatibility */ -#undef PyObject_Length -PyAPI_FUNC(Py_ssize_t) PyObject_Length(PyObject *o); -#define PyObject_Length PyObject_Size - -/* Return element of 'o' corresponding to the object 'key'. Return NULL - on failure. - - This is the equivalent of the Python expression: o[key] */ -PyAPI_FUNC(PyObject *) PyObject_GetItem(PyObject *o, PyObject *key); - - -/* Map the object 'key' to the value 'v' into 'o'. - - Raise an exception and return -1 on failure; return 0 on success. - - This is the equivalent of the Python statement: o[key]=v. */ -PyAPI_FUNC(int) PyObject_SetItem(PyObject *o, PyObject *key, PyObject *v); - -/* Remove the mapping for the string 'key' from the object 'o'. - Returns -1 on failure. - - This is equivalent to the Python statement: del o[key]. */ -PyAPI_FUNC(int) PyObject_DelItemString(PyObject *o, const char *key); - -/* Delete the mapping for the object 'key' from the object 'o'. - Returns -1 on failure. - - This is the equivalent of the Python statement: del o[key]. */ -PyAPI_FUNC(int) PyObject_DelItem(PyObject *o, PyObject *key); - - -/* === Old Buffer API ============================================ */ - -/* FIXME: usage of these should all be replaced in Python itself - but for backwards compatibility we will implement them. - Their usage without a corresponding "unlock" mechanism - may create issues (but they would already be there). */ - -/* Takes an arbitrary object which must support the (character, single segment) - buffer interface and returns a pointer to a read-only memory location - useable as character based input for subsequent processing. - - Return 0 on success. buffer and buffer_len are only set in case no error - occurs. Otherwise, -1 is returned and an exception set. */ -Py_DEPRECATED(3.0) -PyAPI_FUNC(int) PyObject_AsCharBuffer(PyObject *obj, - const char **buffer, - Py_ssize_t *buffer_len); - -/* Checks whether an arbitrary object supports the (character, single segment) - buffer interface. - - Returns 1 on success, 0 on failure. */ -Py_DEPRECATED(3.0) PyAPI_FUNC(int) PyObject_CheckReadBuffer(PyObject *obj); - -/* Same as PyObject_AsCharBuffer() except that this API expects (readable, - single segment) buffer interface and returns a pointer to a read-only memory - location which can contain arbitrary data. - - 0 is returned on success. buffer and buffer_len are only set in case no - error occurs. Otherwise, -1 is returned and an exception set. */ -Py_DEPRECATED(3.0) -PyAPI_FUNC(int) PyObject_AsReadBuffer(PyObject *obj, - const void **buffer, - Py_ssize_t *buffer_len); - -/* Takes an arbitrary object which must support the (writable, single segment) - buffer interface and returns a pointer to a writable memory location in - buffer of size 'buffer_len'. - - Return 0 on success. buffer and buffer_len are only set in case no error - occurs. Otherwise, -1 is returned and an exception set. */ -Py_DEPRECATED(3.0) -PyAPI_FUNC(int) PyObject_AsWriteBuffer(PyObject *obj, - void **buffer, - Py_ssize_t *buffer_len); - - -/* === New Buffer API ============================================ */ - -/* Takes an arbitrary object and returns the result of calling - obj.__format__(format_spec). */ -PyAPI_FUNC(PyObject *) PyObject_Format(PyObject *obj, - PyObject *format_spec); - - -/* ==== Iterators ================================================ */ - -/* Takes an object and returns an iterator for it. - This is typically a new iterator but if the argument is an iterator, this - returns itself. */ -PyAPI_FUNC(PyObject *) PyObject_GetIter(PyObject *); - -/* Returns 1 if the object 'obj' provides iterator protocols, and 0 otherwise. - - This function always succeeds. */ -PyAPI_FUNC(int) PyIter_Check(PyObject *); - -/* Takes an iterator object and calls its tp_iternext slot, - returning the next value. - - If the iterator is exhausted, this returns NULL without setting an - exception. - - NULL with an exception means an error occurred. */ -PyAPI_FUNC(PyObject *) PyIter_Next(PyObject *); - - -/* === Number Protocol ================================================== */ - -/* Returns 1 if the object 'o' provides numeric protocols, and 0 otherwise. - - This function always succeeds. */ -PyAPI_FUNC(int) PyNumber_Check(PyObject *o); - -/* Returns the result of adding o1 and o2, or NULL on failure. - - This is the equivalent of the Python expression: o1 + o2. */ -PyAPI_FUNC(PyObject *) PyNumber_Add(PyObject *o1, PyObject *o2); - -/* Returns the result of subtracting o2 from o1, or NULL on failure. - - This is the equivalent of the Python expression: o1 - o2. */ -PyAPI_FUNC(PyObject *) PyNumber_Subtract(PyObject *o1, PyObject *o2); - -/* Returns the result of multiplying o1 and o2, or NULL on failure. - - This is the equivalent of the Python expression: o1 * o2. */ -PyAPI_FUNC(PyObject *) PyNumber_Multiply(PyObject *o1, PyObject *o2); - -#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03050000 -/* This is the equivalent of the Python expression: o1 @ o2. */ -PyAPI_FUNC(PyObject *) PyNumber_MatrixMultiply(PyObject *o1, PyObject *o2); -#endif - -/* Returns the result of dividing o1 by o2 giving an integral result, - or NULL on failure. - - This is the equivalent of the Python expression: o1 // o2. */ -PyAPI_FUNC(PyObject *) PyNumber_FloorDivide(PyObject *o1, PyObject *o2); - -/* Returns the result of dividing o1 by o2 giving a float result, or NULL on - failure. - - This is the equivalent of the Python expression: o1 / o2. */ -PyAPI_FUNC(PyObject *) PyNumber_TrueDivide(PyObject *o1, PyObject *o2); - -/* Returns the remainder of dividing o1 by o2, or NULL on failure. - - This is the equivalent of the Python expression: o1 % o2. */ -PyAPI_FUNC(PyObject *) PyNumber_Remainder(PyObject *o1, PyObject *o2); - -/* See the built-in function divmod. - - Returns NULL on failure. - - This is the equivalent of the Python expression: divmod(o1, o2). */ -PyAPI_FUNC(PyObject *) PyNumber_Divmod(PyObject *o1, PyObject *o2); - -/* See the built-in function pow. Returns NULL on failure. - - This is the equivalent of the Python expression: pow(o1, o2, o3), - where o3 is optional. */ -PyAPI_FUNC(PyObject *) PyNumber_Power(PyObject *o1, PyObject *o2, - PyObject *o3); - -/* Returns the negation of o on success, or NULL on failure. - - This is the equivalent of the Python expression: -o. */ -PyAPI_FUNC(PyObject *) PyNumber_Negative(PyObject *o); - -/* Returns the positive of o on success, or NULL on failure. - - This is the equivalent of the Python expression: +o. */ -PyAPI_FUNC(PyObject *) PyNumber_Positive(PyObject *o); - -/* Returns the absolute value of 'o', or NULL on failure. - - This is the equivalent of the Python expression: abs(o). */ -PyAPI_FUNC(PyObject *) PyNumber_Absolute(PyObject *o); - -/* Returns the bitwise negation of 'o' on success, or NULL on failure. - - This is the equivalent of the Python expression: ~o. */ -PyAPI_FUNC(PyObject *) PyNumber_Invert(PyObject *o); - -/* Returns the result of left shifting o1 by o2 on success, or NULL on failure. - - This is the equivalent of the Python expression: o1 << o2. */ -PyAPI_FUNC(PyObject *) PyNumber_Lshift(PyObject *o1, PyObject *o2); - -/* Returns the result of right shifting o1 by o2 on success, or NULL on - failure. - - This is the equivalent of the Python expression: o1 >> o2. */ -PyAPI_FUNC(PyObject *) PyNumber_Rshift(PyObject *o1, PyObject *o2); - -/* Returns the result of bitwise and of o1 and o2 on success, or NULL on - failure. - - This is the equivalent of the Python expression: o1 & o2. */ -PyAPI_FUNC(PyObject *) PyNumber_And(PyObject *o1, PyObject *o2); - -/* Returns the bitwise exclusive or of o1 by o2 on success, or NULL on failure. - - This is the equivalent of the Python expression: o1 ^ o2. */ -PyAPI_FUNC(PyObject *) PyNumber_Xor(PyObject *o1, PyObject *o2); - -/* Returns the result of bitwise or on o1 and o2 on success, or NULL on - failure. - - This is the equivalent of the Python expression: o1 | o2. */ -PyAPI_FUNC(PyObject *) PyNumber_Or(PyObject *o1, PyObject *o2); - -/* Returns 1 if obj is an index integer (has the nb_index slot of the - tp_as_number structure filled in), and 0 otherwise. */ -PyAPI_FUNC(int) PyIndex_Check(PyObject *); - -/* Returns the object 'o' converted to a Python int, or NULL with an exception - raised on failure. */ -PyAPI_FUNC(PyObject *) PyNumber_Index(PyObject *o); - -/* Returns the object 'o' converted to Py_ssize_t by going through - PyNumber_Index() first. - - If an overflow error occurs while converting the int to Py_ssize_t, then the - second argument 'exc' is the error-type to return. If it is NULL, then the - overflow error is cleared and the value is clipped. */ -PyAPI_FUNC(Py_ssize_t) PyNumber_AsSsize_t(PyObject *o, PyObject *exc); - -/* Returns the object 'o' converted to an integer object on success, or NULL - on failure. - - This is the equivalent of the Python expression: int(o). */ -PyAPI_FUNC(PyObject *) PyNumber_Long(PyObject *o); - -/* Returns the object 'o' converted to a float object on success, or NULL - on failure. - - This is the equivalent of the Python expression: float(o). */ -PyAPI_FUNC(PyObject *) PyNumber_Float(PyObject *o); - - -/* --- In-place variants of (some of) the above number protocol functions -- */ - -/* Returns the result of adding o2 to o1, possibly in-place, or NULL - on failure. - - This is the equivalent of the Python expression: o1 += o2. */ -PyAPI_FUNC(PyObject *) PyNumber_InPlaceAdd(PyObject *o1, PyObject *o2); - -/* Returns the result of subtracting o2 from o1, possibly in-place or - NULL on failure. - - This is the equivalent of the Python expression: o1 -= o2. */ -PyAPI_FUNC(PyObject *) PyNumber_InPlaceSubtract(PyObject *o1, PyObject *o2); - -/* Returns the result of multiplying o1 by o2, possibly in-place, or NULL on - failure. - - This is the equivalent of the Python expression: o1 *= o2. */ -PyAPI_FUNC(PyObject *) PyNumber_InPlaceMultiply(PyObject *o1, PyObject *o2); - -#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03050000 -/* This is the equivalent of the Python expression: o1 @= o2. */ -PyAPI_FUNC(PyObject *) PyNumber_InPlaceMatrixMultiply(PyObject *o1, PyObject *o2); -#endif - -/* Returns the result of dividing o1 by o2 giving an integral result, possibly - in-place, or NULL on failure. - - This is the equivalent of the Python expression: o1 /= o2. */ -PyAPI_FUNC(PyObject *) PyNumber_InPlaceFloorDivide(PyObject *o1, - PyObject *o2); - -/* Returns the result of dividing o1 by o2 giving a float result, possibly - in-place, or null on failure. - - This is the equivalent of the Python expression: o1 /= o2. */ -PyAPI_FUNC(PyObject *) PyNumber_InPlaceTrueDivide(PyObject *o1, - PyObject *o2); - -/* Returns the remainder of dividing o1 by o2, possibly in-place, or NULL on - failure. - - This is the equivalent of the Python expression: o1 %= o2. */ -PyAPI_FUNC(PyObject *) PyNumber_InPlaceRemainder(PyObject *o1, PyObject *o2); - -/* Returns the result of raising o1 to the power of o2, possibly in-place, - or NULL on failure. - - This is the equivalent of the Python expression: o1 **= o2, - or o1 = pow(o1, o2, o3) if o3 is present. */ -PyAPI_FUNC(PyObject *) PyNumber_InPlacePower(PyObject *o1, PyObject *o2, - PyObject *o3); - -/* Returns the result of left shifting o1 by o2, possibly in-place, or NULL - on failure. - - This is the equivalent of the Python expression: o1 <<= o2. */ -PyAPI_FUNC(PyObject *) PyNumber_InPlaceLshift(PyObject *o1, PyObject *o2); - -/* Returns the result of right shifting o1 by o2, possibly in-place or NULL - on failure. - - This is the equivalent of the Python expression: o1 >>= o2. */ -PyAPI_FUNC(PyObject *) PyNumber_InPlaceRshift(PyObject *o1, PyObject *o2); - -/* Returns the result of bitwise and of o1 and o2, possibly in-place, or NULL - on failure. - - This is the equivalent of the Python expression: o1 &= o2. */ -PyAPI_FUNC(PyObject *) PyNumber_InPlaceAnd(PyObject *o1, PyObject *o2); - -/* Returns the bitwise exclusive or of o1 by o2, possibly in-place, or NULL - on failure. - - This is the equivalent of the Python expression: o1 ^= o2. */ -PyAPI_FUNC(PyObject *) PyNumber_InPlaceXor(PyObject *o1, PyObject *o2); - -/* Returns the result of bitwise or of o1 and o2, possibly in-place, - or NULL on failure. - - This is the equivalent of the Python expression: o1 |= o2. */ -PyAPI_FUNC(PyObject *) PyNumber_InPlaceOr(PyObject *o1, PyObject *o2); - -/* Returns the integer n converted to a string with a base, with a base - marker of 0b, 0o or 0x prefixed if applicable. - - If n is not an int object, it is converted with PyNumber_Index first. */ -PyAPI_FUNC(PyObject *) PyNumber_ToBase(PyObject *n, int base); - - -/* === Sequence protocol ================================================ */ - -/* Return 1 if the object provides sequence protocol, and zero - otherwise. - - This function always succeeds. */ -PyAPI_FUNC(int) PySequence_Check(PyObject *o); - -/* Return the size of sequence object o, or -1 on failure. */ -PyAPI_FUNC(Py_ssize_t) PySequence_Size(PyObject *o); - -/* For DLL compatibility */ -#undef PySequence_Length -PyAPI_FUNC(Py_ssize_t) PySequence_Length(PyObject *o); -#define PySequence_Length PySequence_Size - - -/* Return the concatenation of o1 and o2 on success, and NULL on failure. - - This is the equivalent of the Python expression: o1 + o2. */ -PyAPI_FUNC(PyObject *) PySequence_Concat(PyObject *o1, PyObject *o2); - -/* Return the result of repeating sequence object 'o' 'count' times, - or NULL on failure. - - This is the equivalent of the Python expression: o * count. */ -PyAPI_FUNC(PyObject *) PySequence_Repeat(PyObject *o, Py_ssize_t count); - -/* Return the ith element of o, or NULL on failure. - - This is the equivalent of the Python expression: o[i]. */ -PyAPI_FUNC(PyObject *) PySequence_GetItem(PyObject *o, Py_ssize_t i); - -/* Return the slice of sequence object o between i1 and i2, or NULL on failure. - - This is the equivalent of the Python expression: o[i1:i2]. */ -PyAPI_FUNC(PyObject *) PySequence_GetSlice(PyObject *o, Py_ssize_t i1, Py_ssize_t i2); - -/* Assign object 'v' to the ith element of the sequence 'o'. Raise an exception - and return -1 on failure; return 0 on success. - - This is the equivalent of the Python statement o[i] = v. */ -PyAPI_FUNC(int) PySequence_SetItem(PyObject *o, Py_ssize_t i, PyObject *v); - -/* Delete the 'i'-th element of the sequence 'v'. Returns -1 on failure. - - This is the equivalent of the Python statement: del o[i]. */ -PyAPI_FUNC(int) PySequence_DelItem(PyObject *o, Py_ssize_t i); - -/* Assign the sequence object 'v' to the slice in sequence object 'o', - from 'i1' to 'i2'. Returns -1 on failure. - - This is the equivalent of the Python statement: o[i1:i2] = v. */ -PyAPI_FUNC(int) PySequence_SetSlice(PyObject *o, Py_ssize_t i1, Py_ssize_t i2, - PyObject *v); - -/* Delete the slice in sequence object 'o' from 'i1' to 'i2'. - Returns -1 on failure. - - This is the equivalent of the Python statement: del o[i1:i2]. */ -PyAPI_FUNC(int) PySequence_DelSlice(PyObject *o, Py_ssize_t i1, Py_ssize_t i2); - -/* Returns the sequence 'o' as a tuple on success, and NULL on failure. - - This is equivalent to the Python expression: tuple(o). */ -PyAPI_FUNC(PyObject *) PySequence_Tuple(PyObject *o); - -/* Returns the sequence 'o' as a list on success, and NULL on failure. - This is equivalent to the Python expression: list(o) */ -PyAPI_FUNC(PyObject *) PySequence_List(PyObject *o); - -/* Return the sequence 'o' as a list, unless it's already a tuple or list. - - Use PySequence_Fast_GET_ITEM to access the members of this list, and - PySequence_Fast_GET_SIZE to get its length. - - Returns NULL on failure. If the object does not support iteration, raises a - TypeError exception with 'm' as the message text. */ -PyAPI_FUNC(PyObject *) PySequence_Fast(PyObject *o, const char* m); - -/* Return the size of the sequence 'o', assuming that 'o' was returned by - PySequence_Fast and is not NULL. */ -#define PySequence_Fast_GET_SIZE(o) \ - (PyList_Check(o) ? PyList_GET_SIZE(o) : PyTuple_GET_SIZE(o)) - -/* Return the 'i'-th element of the sequence 'o', assuming that o was returned - by PySequence_Fast, and that i is within bounds. */ -#define PySequence_Fast_GET_ITEM(o, i)\ - (PyList_Check(o) ? PyList_GET_ITEM(o, i) : PyTuple_GET_ITEM(o, i)) - -/* Return a pointer to the underlying item array for - an object returned by PySequence_Fast */ -#define PySequence_Fast_ITEMS(sf) \ - (PyList_Check(sf) ? ((PyListObject *)(sf))->ob_item \ - : ((PyTupleObject *)(sf))->ob_item) - -/* Return the number of occurrences on value on 'o', that is, return - the number of keys for which o[key] == value. - - On failure, return -1. This is equivalent to the Python expression: - o.count(value). */ -PyAPI_FUNC(Py_ssize_t) PySequence_Count(PyObject *o, PyObject *value); - -/* Return 1 if 'ob' is in the sequence 'seq'; 0 if 'ob' is not in the sequence - 'seq'; -1 on error. - - Use __contains__ if possible, else _PySequence_IterSearch(). */ -PyAPI_FUNC(int) PySequence_Contains(PyObject *seq, PyObject *ob); - -/* For DLL-level backwards compatibility */ -#undef PySequence_In -/* Determine if the sequence 'o' contains 'value'. If an item in 'o' is equal - to 'value', return 1, otherwise return 0. On error, return -1. - - This is equivalent to the Python expression: value in o. */ -PyAPI_FUNC(int) PySequence_In(PyObject *o, PyObject *value); - -/* For source-level backwards compatibility */ -#define PySequence_In PySequence_Contains - - -/* Return the first index for which o[i] == value. - On error, return -1. - - This is equivalent to the Python expression: o.index(value). */ -PyAPI_FUNC(Py_ssize_t) PySequence_Index(PyObject *o, PyObject *value); - - -/* --- In-place versions of some of the above Sequence functions --- */ - -/* Append sequence 'o2' to sequence 'o1', in-place when possible. Return the - resulting object, which could be 'o1', or NULL on failure. - - This is the equivalent of the Python expression: o1 += o2. */ -PyAPI_FUNC(PyObject *) PySequence_InPlaceConcat(PyObject *o1, PyObject *o2); - -/* Repeat sequence 'o' by 'count', in-place when possible. Return the resulting - object, which could be 'o', or NULL on failure. - - This is the equivalent of the Python expression: o1 *= count. */ -PyAPI_FUNC(PyObject *) PySequence_InPlaceRepeat(PyObject *o, Py_ssize_t count); - - -/* === Mapping protocol ================================================= */ - -/* Return 1 if the object provides mapping protocol, and 0 otherwise. - - This function always succeeds. */ -PyAPI_FUNC(int) PyMapping_Check(PyObject *o); - -/* Returns the number of keys in mapping object 'o' on success, and -1 on - failure. This is equivalent to the Python expression: len(o). */ -PyAPI_FUNC(Py_ssize_t) PyMapping_Size(PyObject *o); - -/* For DLL compatibility */ -#undef PyMapping_Length -PyAPI_FUNC(Py_ssize_t) PyMapping_Length(PyObject *o); -#define PyMapping_Length PyMapping_Size - - -/* Implemented as a macro: - - int PyMapping_DelItemString(PyObject *o, const char *key); - - Remove the mapping for the string 'key' from the mapping 'o'. Returns -1 on - failure. - - This is equivalent to the Python statement: del o[key]. */ -#define PyMapping_DelItemString(O,K) PyObject_DelItemString((O),(K)) - -/* Implemented as a macro: - - int PyMapping_DelItem(PyObject *o, PyObject *key); - - Remove the mapping for the object 'key' from the mapping object 'o'. - Returns -1 on failure. - - This is equivalent to the Python statement: del o[key]. */ -#define PyMapping_DelItem(O,K) PyObject_DelItem((O),(K)) - -/* On success, return 1 if the mapping object 'o' has the key 'key', - and 0 otherwise. - - This is equivalent to the Python expression: key in o. - - This function always succeeds. */ -PyAPI_FUNC(int) PyMapping_HasKeyString(PyObject *o, const char *key); - -/* Return 1 if the mapping object has the key 'key', and 0 otherwise. - - This is equivalent to the Python expression: key in o. - - This function always succeeds. */ -PyAPI_FUNC(int) PyMapping_HasKey(PyObject *o, PyObject *key); - -/* On success, return a list or tuple of the keys in mapping object 'o'. - On failure, return NULL. */ -PyAPI_FUNC(PyObject *) PyMapping_Keys(PyObject *o); - -/* On success, return a list or tuple of the values in mapping object 'o'. - On failure, return NULL. */ -PyAPI_FUNC(PyObject *) PyMapping_Values(PyObject *o); - -/* On success, return a list or tuple of the items in mapping object 'o', - where each item is a tuple containing a key-value pair. On failure, return - NULL. */ -PyAPI_FUNC(PyObject *) PyMapping_Items(PyObject *o); - -/* Return element of 'o' corresponding to the string 'key' or NULL on failure. - - This is the equivalent of the Python expression: o[key]. */ -PyAPI_FUNC(PyObject *) PyMapping_GetItemString(PyObject *o, - const char *key); - -/* Map the string 'key' to the value 'v' in the mapping 'o'. - Returns -1 on failure. - - This is the equivalent of the Python statement: o[key]=v. */ -PyAPI_FUNC(int) PyMapping_SetItemString(PyObject *o, const char *key, - PyObject *value); - -/* isinstance(object, typeorclass) */ -PyAPI_FUNC(int) PyObject_IsInstance(PyObject *object, PyObject *typeorclass); - -/* issubclass(object, typeorclass) */ -PyAPI_FUNC(int) PyObject_IsSubclass(PyObject *object, PyObject *typeorclass); - -#ifndef Py_LIMITED_API -# define Py_CPYTHON_ABSTRACTOBJECT_H -# include "cpython/abstract.h" -# undef Py_CPYTHON_ABSTRACTOBJECT_H -#endif - -#ifdef __cplusplus -} -#endif -#endif /* Py_ABSTRACTOBJECT_H */ diff --git a/scripts/build-windows/py39-libs/include/asdl.h b/scripts/build-windows/py39-libs/include/asdl.h deleted file mode 100644 index e962560bc..000000000 --- a/scripts/build-windows/py39-libs/include/asdl.h +++ /dev/null @@ -1,46 +0,0 @@ -#ifndef Py_LIMITED_API -#ifndef Py_ASDL_H -#define Py_ASDL_H - -typedef PyObject * identifier; -typedef PyObject * string; -typedef PyObject * object; -typedef PyObject * constant; - -/* It would be nice if the code generated by asdl_c.py was completely - independent of Python, but it is a goal the requires too much work - at this stage. So, for example, I'll represent identifiers as - interned Python strings. -*/ - -/* XXX A sequence should be typed so that its use can be typechecked. */ - -typedef struct { - Py_ssize_t size; - void *elements[1]; -} asdl_seq; - -typedef struct { - Py_ssize_t size; - int elements[1]; -} asdl_int_seq; - -asdl_seq *_Py_asdl_seq_new(Py_ssize_t size, PyArena *arena); -asdl_int_seq *_Py_asdl_int_seq_new(Py_ssize_t size, PyArena *arena); - -#define asdl_seq_GET(S, I) (S)->elements[(I)] -#define asdl_seq_LEN(S) ((S) == NULL ? 0 : (S)->size) -#ifdef Py_DEBUG -#define asdl_seq_SET(S, I, V) \ - do { \ - Py_ssize_t _asdl_i = (I); \ - assert((S) != NULL); \ - assert(0 <= _asdl_i && _asdl_i < (S)->size); \ - (S)->elements[_asdl_i] = (V); \ - } while (0) -#else -#define asdl_seq_SET(S, I, V) (S)->elements[I] = (V) -#endif - -#endif /* !Py_ASDL_H */ -#endif /* Py_LIMITED_API */ diff --git a/scripts/build-windows/py39-libs/include/ast.h b/scripts/build-windows/py39-libs/include/ast.h deleted file mode 100644 index a8c52af78..000000000 --- a/scripts/build-windows/py39-libs/include/ast.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef Py_LIMITED_API -#ifndef Py_AST_H -#define Py_AST_H -#ifdef __cplusplus -extern "C" { -#endif - -#include "Python-ast.h" /* mod_ty */ -#include "node.h" /* node */ - -PyAPI_FUNC(int) PyAST_Validate(mod_ty); -PyAPI_FUNC(mod_ty) PyAST_FromNode( - const node *n, - PyCompilerFlags *flags, - const char *filename, /* decoded from the filesystem encoding */ - PyArena *arena); -PyAPI_FUNC(mod_ty) PyAST_FromNodeObject( - const node *n, - PyCompilerFlags *flags, - PyObject *filename, - PyArena *arena); - -/* _PyAST_ExprAsUnicode is defined in ast_unparse.c */ -PyAPI_FUNC(PyObject *) _PyAST_ExprAsUnicode(expr_ty); - -/* Return the borrowed reference to the first literal string in the - sequence of statements or NULL if it doesn't start from a literal string. - Doesn't set exception. */ -PyAPI_FUNC(PyObject *) _PyAST_GetDocString(asdl_seq *); - -#ifdef __cplusplus -} -#endif -#endif /* !Py_AST_H */ -#endif /* !Py_LIMITED_API */ diff --git a/scripts/build-windows/py39-libs/include/bitset.h b/scripts/build-windows/py39-libs/include/bitset.h deleted file mode 100644 index 6a2ac9787..000000000 --- a/scripts/build-windows/py39-libs/include/bitset.h +++ /dev/null @@ -1,23 +0,0 @@ - -#ifndef Py_BITSET_H -#define Py_BITSET_H -#ifdef __cplusplus -extern "C" { -#endif - -/* Bitset interface */ - -#define BYTE char -typedef BYTE *bitset; - -#define testbit(ss, ibit) (((ss)[BIT2BYTE(ibit)] & BIT2MASK(ibit)) != 0) - -#define BITSPERBYTE (8*sizeof(BYTE)) -#define BIT2BYTE(ibit) ((ibit) / BITSPERBYTE) -#define BIT2SHIFT(ibit) ((ibit) % BITSPERBYTE) -#define BIT2MASK(ibit) (1 << BIT2SHIFT(ibit)) - -#ifdef __cplusplus -} -#endif -#endif /* !Py_BITSET_H */ diff --git a/scripts/build-windows/py39-libs/include/bltinmodule.h b/scripts/build-windows/py39-libs/include/bltinmodule.h deleted file mode 100644 index 868c9e644..000000000 --- a/scripts/build-windows/py39-libs/include/bltinmodule.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef Py_BLTINMODULE_H -#define Py_BLTINMODULE_H -#ifdef __cplusplus -extern "C" { -#endif - -PyAPI_DATA(PyTypeObject) PyFilter_Type; -PyAPI_DATA(PyTypeObject) PyMap_Type; -PyAPI_DATA(PyTypeObject) PyZip_Type; - -#ifdef __cplusplus -} -#endif -#endif /* !Py_BLTINMODULE_H */ diff --git a/scripts/build-windows/py39-libs/include/boolobject.h b/scripts/build-windows/py39-libs/include/boolobject.h deleted file mode 100644 index bb8044a2b..000000000 --- a/scripts/build-windows/py39-libs/include/boolobject.h +++ /dev/null @@ -1,34 +0,0 @@ -/* Boolean object interface */ - -#ifndef Py_BOOLOBJECT_H -#define Py_BOOLOBJECT_H -#ifdef __cplusplus -extern "C" { -#endif - - -PyAPI_DATA(PyTypeObject) PyBool_Type; - -#define PyBool_Check(x) Py_IS_TYPE(x, &PyBool_Type) - -/* Py_False and Py_True are the only two bools in existence. -Don't forget to apply Py_INCREF() when returning either!!! */ - -/* Don't use these directly */ -PyAPI_DATA(struct _longobject) _Py_FalseStruct, _Py_TrueStruct; - -/* Use these macros */ -#define Py_False ((PyObject *) &_Py_FalseStruct) -#define Py_True ((PyObject *) &_Py_TrueStruct) - -/* Macros for returning Py_True or Py_False, respectively */ -#define Py_RETURN_TRUE return Py_INCREF(Py_True), Py_True -#define Py_RETURN_FALSE return Py_INCREF(Py_False), Py_False - -/* Function to return a bool from a C long */ -PyAPI_FUNC(PyObject *) PyBool_FromLong(long); - -#ifdef __cplusplus -} -#endif -#endif /* !Py_BOOLOBJECT_H */ diff --git a/scripts/build-windows/py39-libs/include/bytearrayobject.h b/scripts/build-windows/py39-libs/include/bytearrayobject.h deleted file mode 100644 index 9e95433f0..000000000 --- a/scripts/build-windows/py39-libs/include/bytearrayobject.h +++ /dev/null @@ -1,46 +0,0 @@ -/* ByteArray object interface */ - -#ifndef Py_BYTEARRAYOBJECT_H -#define Py_BYTEARRAYOBJECT_H -#ifdef __cplusplus -extern "C" { -#endif - -#include - -/* Type PyByteArrayObject represents a mutable array of bytes. - * The Python API is that of a sequence; - * the bytes are mapped to ints in [0, 256). - * Bytes are not characters; they may be used to encode characters. - * The only way to go between bytes and str/unicode is via encoding - * and decoding. - * For the convenience of C programmers, the bytes type is considered - * to contain a char pointer, not an unsigned char pointer. - */ - -/* Type object */ -PyAPI_DATA(PyTypeObject) PyByteArray_Type; -PyAPI_DATA(PyTypeObject) PyByteArrayIter_Type; - -/* Type check macros */ -#define PyByteArray_Check(self) PyObject_TypeCheck(self, &PyByteArray_Type) -#define PyByteArray_CheckExact(self) Py_IS_TYPE(self, &PyByteArray_Type) - -/* Direct API functions */ -PyAPI_FUNC(PyObject *) PyByteArray_FromObject(PyObject *); -PyAPI_FUNC(PyObject *) PyByteArray_Concat(PyObject *, PyObject *); -PyAPI_FUNC(PyObject *) PyByteArray_FromStringAndSize(const char *, Py_ssize_t); -PyAPI_FUNC(Py_ssize_t) PyByteArray_Size(PyObject *); -PyAPI_FUNC(char *) PyByteArray_AsString(PyObject *); -PyAPI_FUNC(int) PyByteArray_Resize(PyObject *, Py_ssize_t); - -#ifndef Py_LIMITED_API -# define Py_CPYTHON_BYTEARRAYOBJECT_H -# include "cpython/bytearrayobject.h" -# undef Py_CPYTHON_BYTEARRAYOBJECT_H -#endif - -#ifdef __cplusplus -} -#endif -#endif /* !Py_BYTEARRAYOBJECT_H */ diff --git a/scripts/build-windows/py39-libs/include/bytesobject.h b/scripts/build-windows/py39-libs/include/bytesobject.h deleted file mode 100644 index 5062d8d12..000000000 --- a/scripts/build-windows/py39-libs/include/bytesobject.h +++ /dev/null @@ -1,82 +0,0 @@ - -/* Bytes (String) object interface */ - -#ifndef Py_BYTESOBJECT_H -#define Py_BYTESOBJECT_H -#ifdef __cplusplus -extern "C" { -#endif - -#include - -/* -Type PyBytesObject represents a character string. An extra zero byte is -reserved at the end to ensure it is zero-terminated, but a size is -present so strings with null bytes in them can be represented. This -is an immutable object type. - -There are functions to create new string objects, to test -an object for string-ness, and to get the -string value. The latter function returns a null pointer -if the object is not of the proper type. -There is a variant that takes an explicit size as well as a -variant that assumes a zero-terminated string. Note that none of the -functions should be applied to nil objects. -*/ - -/* Caching the hash (ob_shash) saves recalculation of a string's hash value. - This significantly speeds up dict lookups. */ - -PyAPI_DATA(PyTypeObject) PyBytes_Type; -PyAPI_DATA(PyTypeObject) PyBytesIter_Type; - -#define PyBytes_Check(op) \ - PyType_FastSubclass(Py_TYPE(op), Py_TPFLAGS_BYTES_SUBCLASS) -#define PyBytes_CheckExact(op) Py_IS_TYPE(op, &PyBytes_Type) - -PyAPI_FUNC(PyObject *) PyBytes_FromStringAndSize(const char *, Py_ssize_t); -PyAPI_FUNC(PyObject *) PyBytes_FromString(const char *); -PyAPI_FUNC(PyObject *) PyBytes_FromObject(PyObject *); -PyAPI_FUNC(PyObject *) PyBytes_FromFormatV(const char*, va_list) - Py_GCC_ATTRIBUTE((format(printf, 1, 0))); -PyAPI_FUNC(PyObject *) PyBytes_FromFormat(const char*, ...) - Py_GCC_ATTRIBUTE((format(printf, 1, 2))); -PyAPI_FUNC(Py_ssize_t) PyBytes_Size(PyObject *); -PyAPI_FUNC(char *) PyBytes_AsString(PyObject *); -PyAPI_FUNC(PyObject *) PyBytes_Repr(PyObject *, int); -PyAPI_FUNC(void) PyBytes_Concat(PyObject **, PyObject *); -PyAPI_FUNC(void) PyBytes_ConcatAndDel(PyObject **, PyObject *); -PyAPI_FUNC(PyObject *) PyBytes_DecodeEscape(const char *, Py_ssize_t, - const char *, Py_ssize_t, - const char *); - -/* Provides access to the internal data buffer and size of a string - object or the default encoded version of a Unicode object. Passing - NULL as *len parameter will force the string buffer to be - 0-terminated (passing a string with embedded NULL characters will - cause an exception). */ -PyAPI_FUNC(int) PyBytes_AsStringAndSize( - PyObject *obj, /* string or Unicode object */ - char **s, /* pointer to buffer variable */ - Py_ssize_t *len /* pointer to length variable or NULL - (only possible for 0-terminated - strings) */ - ); - -/* Flags used by string formatting */ -#define F_LJUST (1<<0) -#define F_SIGN (1<<1) -#define F_BLANK (1<<2) -#define F_ALT (1<<3) -#define F_ZERO (1<<4) - -#ifndef Py_LIMITED_API -# define Py_CPYTHON_BYTESOBJECT_H -# include "cpython/bytesobject.h" -# undef Py_CPYTHON_BYTESOBJECT_H -#endif - -#ifdef __cplusplus -} -#endif -#endif /* !Py_BYTESOBJECT_H */ diff --git a/scripts/build-windows/py39-libs/include/cellobject.h b/scripts/build-windows/py39-libs/include/cellobject.h deleted file mode 100644 index f12aa90a4..000000000 --- a/scripts/build-windows/py39-libs/include/cellobject.h +++ /dev/null @@ -1,29 +0,0 @@ -/* Cell object interface */ -#ifndef Py_LIMITED_API -#ifndef Py_CELLOBJECT_H -#define Py_CELLOBJECT_H -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct { - PyObject_HEAD - PyObject *ob_ref; /* Content of the cell or NULL when empty */ -} PyCellObject; - -PyAPI_DATA(PyTypeObject) PyCell_Type; - -#define PyCell_Check(op) Py_IS_TYPE(op, &PyCell_Type) - -PyAPI_FUNC(PyObject *) PyCell_New(PyObject *); -PyAPI_FUNC(PyObject *) PyCell_Get(PyObject *); -PyAPI_FUNC(int) PyCell_Set(PyObject *, PyObject *); - -#define PyCell_GET(op) (((PyCellObject *)(op))->ob_ref) -#define PyCell_SET(op, v) (((PyCellObject *)(op))->ob_ref = v) - -#ifdef __cplusplus -} -#endif -#endif /* !Py_TUPLEOBJECT_H */ -#endif /* Py_LIMITED_API */ diff --git a/scripts/build-windows/py39-libs/include/ceval.h b/scripts/build-windows/py39-libs/include/ceval.h deleted file mode 100644 index 0f372e204..000000000 --- a/scripts/build-windows/py39-libs/include/ceval.h +++ /dev/null @@ -1,166 +0,0 @@ -#ifndef Py_CEVAL_H -#define Py_CEVAL_H -#ifdef __cplusplus -extern "C" { -#endif - - -/* Interface to random parts in ceval.c */ - -/* PyEval_CallObjectWithKeywords(), PyEval_CallObject(), PyEval_CallFunction - * and PyEval_CallMethod are deprecated. Since they are officially part of the - * stable ABI (PEP 384), they must be kept for backward compatibility. - * PyObject_Call(), PyObject_CallFunction() and PyObject_CallMethod() are - * recommended to call a callable object. - */ - -Py_DEPRECATED(3.9) PyAPI_FUNC(PyObject *) PyEval_CallObjectWithKeywords( - PyObject *callable, - PyObject *args, - PyObject *kwargs); - -/* Deprecated since PyEval_CallObjectWithKeywords is deprecated */ -#define PyEval_CallObject(callable, arg) \ - PyEval_CallObjectWithKeywords(callable, arg, (PyObject *)NULL) - -Py_DEPRECATED(3.9) PyAPI_FUNC(PyObject *) PyEval_CallFunction( - PyObject *callable, const char *format, ...); -Py_DEPRECATED(3.9) PyAPI_FUNC(PyObject *) PyEval_CallMethod( - PyObject *obj, const char *name, const char *format, ...); - -PyAPI_FUNC(PyObject *) PyEval_GetBuiltins(void); -PyAPI_FUNC(PyObject *) PyEval_GetGlobals(void); -PyAPI_FUNC(PyObject *) PyEval_GetLocals(void); -PyAPI_FUNC(PyFrameObject *) PyEval_GetFrame(void); - -PyAPI_FUNC(int) Py_AddPendingCall(int (*func)(void *), void *arg); -PyAPI_FUNC(int) Py_MakePendingCalls(void); - -/* Protection against deeply nested recursive calls - - In Python 3.0, this protection has two levels: - * normal anti-recursion protection is triggered when the recursion level - exceeds the current recursion limit. It raises a RecursionError, and sets - the "overflowed" flag in the thread state structure. This flag - temporarily *disables* the normal protection; this allows cleanup code - to potentially outgrow the recursion limit while processing the - RecursionError. - * "last chance" anti-recursion protection is triggered when the recursion - level exceeds "current recursion limit + 50". By construction, this - protection can only be triggered when the "overflowed" flag is set. It - means the cleanup code has itself gone into an infinite loop, or the - RecursionError has been mistakingly ignored. When this protection is - triggered, the interpreter aborts with a Fatal Error. - - In addition, the "overflowed" flag is automatically reset when the - recursion level drops below "current recursion limit - 50". This heuristic - is meant to ensure that the normal anti-recursion protection doesn't get - disabled too long. - - Please note: this scheme has its own limitations. See: - http://mail.python.org/pipermail/python-dev/2008-August/082106.html - for some observations. -*/ -PyAPI_FUNC(void) Py_SetRecursionLimit(int); -PyAPI_FUNC(int) Py_GetRecursionLimit(void); - -PyAPI_FUNC(int) Py_EnterRecursiveCall(const char *where); -PyAPI_FUNC(void) Py_LeaveRecursiveCall(void); - -#define Py_ALLOW_RECURSION \ - do { unsigned char _old = PyThreadState_GET()->recursion_critical;\ - PyThreadState_GET()->recursion_critical = 1; - -#define Py_END_ALLOW_RECURSION \ - PyThreadState_GET()->recursion_critical = _old; \ - } while(0); - -PyAPI_FUNC(const char *) PyEval_GetFuncName(PyObject *); -PyAPI_FUNC(const char *) PyEval_GetFuncDesc(PyObject *); - -PyAPI_FUNC(PyObject *) PyEval_EvalFrame(PyFrameObject *); -PyAPI_FUNC(PyObject *) PyEval_EvalFrameEx(PyFrameObject *f, int exc); - -/* Interface for threads. - - A module that plans to do a blocking system call (or something else - that lasts a long time and doesn't touch Python data) can allow other - threads to run as follows: - - ...preparations here... - Py_BEGIN_ALLOW_THREADS - ...blocking system call here... - Py_END_ALLOW_THREADS - ...interpret result here... - - The Py_BEGIN_ALLOW_THREADS/Py_END_ALLOW_THREADS pair expands to a - {}-surrounded block. - To leave the block in the middle (e.g., with return), you must insert - a line containing Py_BLOCK_THREADS before the return, e.g. - - if (...premature_exit...) { - Py_BLOCK_THREADS - PyErr_SetFromErrno(PyExc_OSError); - return NULL; - } - - An alternative is: - - Py_BLOCK_THREADS - if (...premature_exit...) { - PyErr_SetFromErrno(PyExc_OSError); - return NULL; - } - Py_UNBLOCK_THREADS - - For convenience, that the value of 'errno' is restored across - Py_END_ALLOW_THREADS and Py_BLOCK_THREADS. - - WARNING: NEVER NEST CALLS TO Py_BEGIN_ALLOW_THREADS AND - Py_END_ALLOW_THREADS!!! - - Note that not yet all candidates have been converted to use this - mechanism! -*/ - -PyAPI_FUNC(PyThreadState *) PyEval_SaveThread(void); -PyAPI_FUNC(void) PyEval_RestoreThread(PyThreadState *); - -Py_DEPRECATED(3.9) PyAPI_FUNC(int) PyEval_ThreadsInitialized(void); -Py_DEPRECATED(3.9) PyAPI_FUNC(void) PyEval_InitThreads(void); -/* PyEval_AcquireLock() and PyEval_ReleaseLock() are part of stable ABI. - * They will be removed from this header file in the future version. - * But they will be remained in ABI until Python 4.0. - */ -Py_DEPRECATED(3.2) PyAPI_FUNC(void) PyEval_AcquireLock(void); -Py_DEPRECATED(3.2) PyAPI_FUNC(void) PyEval_ReleaseLock(void); -PyAPI_FUNC(void) PyEval_AcquireThread(PyThreadState *tstate); -PyAPI_FUNC(void) PyEval_ReleaseThread(PyThreadState *tstate); - -#define Py_BEGIN_ALLOW_THREADS { \ - PyThreadState *_save; \ - _save = PyEval_SaveThread(); -#define Py_BLOCK_THREADS PyEval_RestoreThread(_save); -#define Py_UNBLOCK_THREADS _save = PyEval_SaveThread(); -#define Py_END_ALLOW_THREADS PyEval_RestoreThread(_save); \ - } - -/* Masks and values used by FORMAT_VALUE opcode. */ -#define FVC_MASK 0x3 -#define FVC_NONE 0x0 -#define FVC_STR 0x1 -#define FVC_REPR 0x2 -#define FVC_ASCII 0x3 -#define FVS_MASK 0x4 -#define FVS_HAVE_SPEC 0x4 - -#ifndef Py_LIMITED_API -# define Py_CPYTHON_CEVAL_H -# include "cpython/ceval.h" -# undef Py_CPYTHON_CEVAL_H -#endif - -#ifdef __cplusplus -} -#endif -#endif /* !Py_CEVAL_H */ diff --git a/scripts/build-windows/py39-libs/include/classobject.h b/scripts/build-windows/py39-libs/include/classobject.h deleted file mode 100644 index 1952f673b..000000000 --- a/scripts/build-windows/py39-libs/include/classobject.h +++ /dev/null @@ -1,57 +0,0 @@ -/* Former class object interface -- now only bound methods are here */ - -/* Revealing some structures (not for general use) */ - -#ifndef Py_LIMITED_API -#ifndef Py_CLASSOBJECT_H -#define Py_CLASSOBJECT_H -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct { - PyObject_HEAD - PyObject *im_func; /* The callable object implementing the method */ - PyObject *im_self; /* The instance it is bound to */ - PyObject *im_weakreflist; /* List of weak references */ - vectorcallfunc vectorcall; -} PyMethodObject; - -PyAPI_DATA(PyTypeObject) PyMethod_Type; - -#define PyMethod_Check(op) Py_IS_TYPE(op, &PyMethod_Type) - -PyAPI_FUNC(PyObject *) PyMethod_New(PyObject *, PyObject *); - -PyAPI_FUNC(PyObject *) PyMethod_Function(PyObject *); -PyAPI_FUNC(PyObject *) PyMethod_Self(PyObject *); - -/* Macros for direct access to these values. Type checks are *not* - done, so use with care. */ -#define PyMethod_GET_FUNCTION(meth) \ - (((PyMethodObject *)meth) -> im_func) -#define PyMethod_GET_SELF(meth) \ - (((PyMethodObject *)meth) -> im_self) - -typedef struct { - PyObject_HEAD - PyObject *func; -} PyInstanceMethodObject; - -PyAPI_DATA(PyTypeObject) PyInstanceMethod_Type; - -#define PyInstanceMethod_Check(op) Py_IS_TYPE(op, &PyInstanceMethod_Type) - -PyAPI_FUNC(PyObject *) PyInstanceMethod_New(PyObject *); -PyAPI_FUNC(PyObject *) PyInstanceMethod_Function(PyObject *); - -/* Macros for direct access to these values. Type checks are *not* - done, so use with care. */ -#define PyInstanceMethod_GET_FUNCTION(meth) \ - (((PyInstanceMethodObject *)meth) -> func) - -#ifdef __cplusplus -} -#endif -#endif /* !Py_CLASSOBJECT_H */ -#endif /* Py_LIMITED_API */ diff --git a/scripts/build-windows/py39-libs/include/code.h b/scripts/build-windows/py39-libs/include/code.h deleted file mode 100644 index b9e23eb81..000000000 --- a/scripts/build-windows/py39-libs/include/code.h +++ /dev/null @@ -1,20 +0,0 @@ -/* Definitions for bytecode */ - -#ifndef Py_CODE_H -#define Py_CODE_H -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct PyCodeObject PyCodeObject; - -#ifndef Py_LIMITED_API -# define Py_CPYTHON_CODE_H -# include "cpython/code.h" -# undef Py_CPYTHON_CODE_H -#endif - -#ifdef __cplusplus -} -#endif -#endif /* !Py_CODE_H */ diff --git a/scripts/build-windows/py39-libs/include/codecs.h b/scripts/build-windows/py39-libs/include/codecs.h deleted file mode 100644 index 3ad0f2b5a..000000000 --- a/scripts/build-windows/py39-libs/include/codecs.h +++ /dev/null @@ -1,240 +0,0 @@ -#ifndef Py_CODECREGISTRY_H -#define Py_CODECREGISTRY_H -#ifdef __cplusplus -extern "C" { -#endif - -/* ------------------------------------------------------------------------ - - Python Codec Registry and support functions - - -Written by Marc-Andre Lemburg (mal@lemburg.com). - -Copyright (c) Corporation for National Research Initiatives. - - ------------------------------------------------------------------------ */ - -/* Register a new codec search function. - - As side effect, this tries to load the encodings package, if not - yet done, to make sure that it is always first in the list of - search functions. - - The search_function's refcount is incremented by this function. */ - -PyAPI_FUNC(int) PyCodec_Register( - PyObject *search_function - ); - -/* Codec registry lookup API. - - Looks up the given encoding and returns a CodecInfo object with - function attributes which implement the different aspects of - processing the encoding. - - The encoding string is looked up converted to all lower-case - characters. This makes encodings looked up through this mechanism - effectively case-insensitive. - - If no codec is found, a KeyError is set and NULL returned. - - As side effect, this tries to load the encodings package, if not - yet done. This is part of the lazy load strategy for the encodings - package. - - */ - -#ifndef Py_LIMITED_API -PyAPI_FUNC(PyObject *) _PyCodec_Lookup( - const char *encoding - ); - -PyAPI_FUNC(int) _PyCodec_Forget( - const char *encoding - ); -#endif - -/* Codec registry encoding check API. - - Returns 1/0 depending on whether there is a registered codec for - the given encoding. - -*/ - -PyAPI_FUNC(int) PyCodec_KnownEncoding( - const char *encoding - ); - -/* Generic codec based encoding API. - - object is passed through the encoder function found for the given - encoding using the error handling method defined by errors. errors - may be NULL to use the default method defined for the codec. - - Raises a LookupError in case no encoder can be found. - - */ - -PyAPI_FUNC(PyObject *) PyCodec_Encode( - PyObject *object, - const char *encoding, - const char *errors - ); - -/* Generic codec based decoding API. - - object is passed through the decoder function found for the given - encoding using the error handling method defined by errors. errors - may be NULL to use the default method defined for the codec. - - Raises a LookupError in case no encoder can be found. - - */ - -PyAPI_FUNC(PyObject *) PyCodec_Decode( - PyObject *object, - const char *encoding, - const char *errors - ); - -#ifndef Py_LIMITED_API -/* Text codec specific encoding and decoding API. - - Checks the encoding against a list of codecs which do not - implement a str<->bytes encoding before attempting the - operation. - - Please note that these APIs are internal and should not - be used in Python C extensions. - - XXX (ncoghlan): should we make these, or something like them, public - in Python 3.5+? - - */ -PyAPI_FUNC(PyObject *) _PyCodec_LookupTextEncoding( - const char *encoding, - const char *alternate_command - ); - -PyAPI_FUNC(PyObject *) _PyCodec_EncodeText( - PyObject *object, - const char *encoding, - const char *errors - ); - -PyAPI_FUNC(PyObject *) _PyCodec_DecodeText( - PyObject *object, - const char *encoding, - const char *errors - ); - -/* These two aren't actually text encoding specific, but _io.TextIOWrapper - * is the only current API consumer. - */ -PyAPI_FUNC(PyObject *) _PyCodecInfo_GetIncrementalDecoder( - PyObject *codec_info, - const char *errors - ); - -PyAPI_FUNC(PyObject *) _PyCodecInfo_GetIncrementalEncoder( - PyObject *codec_info, - const char *errors - ); -#endif - - - -/* --- Codec Lookup APIs -------------------------------------------------- - - All APIs return a codec object with incremented refcount and are - based on _PyCodec_Lookup(). The same comments w/r to the encoding - name also apply to these APIs. - -*/ - -/* Get an encoder function for the given encoding. */ - -PyAPI_FUNC(PyObject *) PyCodec_Encoder( - const char *encoding - ); - -/* Get a decoder function for the given encoding. */ - -PyAPI_FUNC(PyObject *) PyCodec_Decoder( - const char *encoding - ); - -/* Get an IncrementalEncoder object for the given encoding. */ - -PyAPI_FUNC(PyObject *) PyCodec_IncrementalEncoder( - const char *encoding, - const char *errors - ); - -/* Get an IncrementalDecoder object function for the given encoding. */ - -PyAPI_FUNC(PyObject *) PyCodec_IncrementalDecoder( - const char *encoding, - const char *errors - ); - -/* Get a StreamReader factory function for the given encoding. */ - -PyAPI_FUNC(PyObject *) PyCodec_StreamReader( - const char *encoding, - PyObject *stream, - const char *errors - ); - -/* Get a StreamWriter factory function for the given encoding. */ - -PyAPI_FUNC(PyObject *) PyCodec_StreamWriter( - const char *encoding, - PyObject *stream, - const char *errors - ); - -/* Unicode encoding error handling callback registry API */ - -/* Register the error handling callback function error under the given - name. This function will be called by the codec when it encounters - unencodable characters/undecodable bytes and doesn't know the - callback name, when name is specified as the error parameter - in the call to the encode/decode function. - Return 0 on success, -1 on error */ -PyAPI_FUNC(int) PyCodec_RegisterError(const char *name, PyObject *error); - -/* Lookup the error handling callback function registered under the given - name. As a special case NULL can be passed, in which case - the error handling callback for "strict" will be returned. */ -PyAPI_FUNC(PyObject *) PyCodec_LookupError(const char *name); - -/* raise exc as an exception */ -PyAPI_FUNC(PyObject *) PyCodec_StrictErrors(PyObject *exc); - -/* ignore the unicode error, skipping the faulty input */ -PyAPI_FUNC(PyObject *) PyCodec_IgnoreErrors(PyObject *exc); - -/* replace the unicode encode error with ? or U+FFFD */ -PyAPI_FUNC(PyObject *) PyCodec_ReplaceErrors(PyObject *exc); - -/* replace the unicode encode error with XML character references */ -PyAPI_FUNC(PyObject *) PyCodec_XMLCharRefReplaceErrors(PyObject *exc); - -/* replace the unicode encode error with backslash escapes (\x, \u and \U) */ -PyAPI_FUNC(PyObject *) PyCodec_BackslashReplaceErrors(PyObject *exc); - -#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03050000 -/* replace the unicode encode error with backslash escapes (\N, \x, \u and \U) */ -PyAPI_FUNC(PyObject *) PyCodec_NameReplaceErrors(PyObject *exc); -#endif - -#ifndef Py_LIMITED_API -PyAPI_DATA(const char *) Py_hexdigits; -#endif - -#ifdef __cplusplus -} -#endif -#endif /* !Py_CODECREGISTRY_H */ diff --git a/scripts/build-windows/py39-libs/include/compile.h b/scripts/build-windows/py39-libs/include/compile.h deleted file mode 100644 index 98adee3d1..000000000 --- a/scripts/build-windows/py39-libs/include/compile.h +++ /dev/null @@ -1,116 +0,0 @@ -#ifndef Py_COMPILE_H -#define Py_COMPILE_H - -#ifndef Py_LIMITED_API - -#ifdef __cplusplus -extern "C" { -#endif - -/* Public interface */ -struct _node; /* Declare the existence of this type */ -#ifndef Py_BUILD_CORE -Py_DEPRECATED(3.9) -#endif -PyAPI_FUNC(PyCodeObject *) PyNode_Compile(struct _node *, const char *); -/* XXX (ncoghlan): Unprefixed type name in a public API! */ - -#define PyCF_MASK (CO_FUTURE_DIVISION | CO_FUTURE_ABSOLUTE_IMPORT | \ - CO_FUTURE_WITH_STATEMENT | CO_FUTURE_PRINT_FUNCTION | \ - CO_FUTURE_UNICODE_LITERALS | CO_FUTURE_BARRY_AS_BDFL | \ - CO_FUTURE_GENERATOR_STOP | CO_FUTURE_ANNOTATIONS) -#define PyCF_MASK_OBSOLETE (CO_NESTED) - -/* bpo-39562: CO_FUTURE_ and PyCF_ constants must be kept unique. - PyCF_ constants can use bits from 0x0100 to 0x10000. - CO_FUTURE_ constants use bits starting at 0x20000. */ -#define PyCF_SOURCE_IS_UTF8 0x0100 -#define PyCF_DONT_IMPLY_DEDENT 0x0200 -#define PyCF_ONLY_AST 0x0400 -#define PyCF_IGNORE_COOKIE 0x0800 -#define PyCF_TYPE_COMMENTS 0x1000 -#define PyCF_ALLOW_TOP_LEVEL_AWAIT 0x2000 -#define PyCF_COMPILE_MASK (PyCF_ONLY_AST | PyCF_ALLOW_TOP_LEVEL_AWAIT | \ - PyCF_TYPE_COMMENTS | PyCF_DONT_IMPLY_DEDENT) - -#ifndef Py_LIMITED_API -typedef struct { - int cf_flags; /* bitmask of CO_xxx flags relevant to future */ - int cf_feature_version; /* minor Python version (PyCF_ONLY_AST) */ -} PyCompilerFlags; - -#define _PyCompilerFlags_INIT \ - (PyCompilerFlags){.cf_flags = 0, .cf_feature_version = PY_MINOR_VERSION} -#endif - -/* Future feature support */ - -typedef struct { - int ff_features; /* flags set by future statements */ - int ff_lineno; /* line number of last future statement */ -} PyFutureFeatures; - -#define FUTURE_NESTED_SCOPES "nested_scopes" -#define FUTURE_GENERATORS "generators" -#define FUTURE_DIVISION "division" -#define FUTURE_ABSOLUTE_IMPORT "absolute_import" -#define FUTURE_WITH_STATEMENT "with_statement" -#define FUTURE_PRINT_FUNCTION "print_function" -#define FUTURE_UNICODE_LITERALS "unicode_literals" -#define FUTURE_BARRY_AS_BDFL "barry_as_FLUFL" -#define FUTURE_GENERATOR_STOP "generator_stop" -#define FUTURE_ANNOTATIONS "annotations" - -struct _mod; /* Declare the existence of this type */ -#define PyAST_Compile(mod, s, f, ar) PyAST_CompileEx(mod, s, f, -1, ar) -PyAPI_FUNC(PyCodeObject *) PyAST_CompileEx( - struct _mod *mod, - const char *filename, /* decoded from the filesystem encoding */ - PyCompilerFlags *flags, - int optimize, - PyArena *arena); -PyAPI_FUNC(PyCodeObject *) PyAST_CompileObject( - struct _mod *mod, - PyObject *filename, - PyCompilerFlags *flags, - int optimize, - PyArena *arena); -PyAPI_FUNC(PyFutureFeatures *) PyFuture_FromAST( - struct _mod * mod, - const char *filename /* decoded from the filesystem encoding */ - ); -PyAPI_FUNC(PyFutureFeatures *) PyFuture_FromASTObject( - struct _mod * mod, - PyObject *filename - ); - -/* _Py_Mangle is defined in compile.c */ -PyAPI_FUNC(PyObject*) _Py_Mangle(PyObject *p, PyObject *name); - -#define PY_INVALID_STACK_EFFECT INT_MAX -PyAPI_FUNC(int) PyCompile_OpcodeStackEffect(int opcode, int oparg); -PyAPI_FUNC(int) PyCompile_OpcodeStackEffectWithJump(int opcode, int oparg, int jump); - -typedef struct { - int optimize; - int ff_features; -} _PyASTOptimizeState; - -PyAPI_FUNC(int) _PyAST_Optimize(struct _mod *, PyArena *arena, _PyASTOptimizeState *state); - -#ifdef __cplusplus -} -#endif - -#endif /* !Py_LIMITED_API */ - -/* These definitions must match corresponding definitions in graminit.h. */ -#define Py_single_input 256 -#define Py_file_input 257 -#define Py_eval_input 258 -#define Py_func_type_input 345 - -/* This doesn't need to match anything */ -#define Py_fstring_input 800 - -#endif /* !Py_COMPILE_H */ diff --git a/scripts/build-windows/py39-libs/include/complexobject.h b/scripts/build-windows/py39-libs/include/complexobject.h deleted file mode 100644 index 9221f9c51..000000000 --- a/scripts/build-windows/py39-libs/include/complexobject.h +++ /dev/null @@ -1,69 +0,0 @@ -/* Complex number structure */ - -#ifndef Py_COMPLEXOBJECT_H -#define Py_COMPLEXOBJECT_H -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef Py_LIMITED_API -typedef struct { - double real; - double imag; -} Py_complex; - -/* Operations on complex numbers from complexmodule.c */ - -PyAPI_FUNC(Py_complex) _Py_c_sum(Py_complex, Py_complex); -PyAPI_FUNC(Py_complex) _Py_c_diff(Py_complex, Py_complex); -PyAPI_FUNC(Py_complex) _Py_c_neg(Py_complex); -PyAPI_FUNC(Py_complex) _Py_c_prod(Py_complex, Py_complex); -PyAPI_FUNC(Py_complex) _Py_c_quot(Py_complex, Py_complex); -PyAPI_FUNC(Py_complex) _Py_c_pow(Py_complex, Py_complex); -PyAPI_FUNC(double) _Py_c_abs(Py_complex); -#endif - -/* Complex object interface */ - -/* -PyComplexObject represents a complex number with double-precision -real and imaginary parts. -*/ -#ifndef Py_LIMITED_API -typedef struct { - PyObject_HEAD - Py_complex cval; -} PyComplexObject; -#endif - -PyAPI_DATA(PyTypeObject) PyComplex_Type; - -#define PyComplex_Check(op) PyObject_TypeCheck(op, &PyComplex_Type) -#define PyComplex_CheckExact(op) Py_IS_TYPE(op, &PyComplex_Type) - -#ifndef Py_LIMITED_API -PyAPI_FUNC(PyObject *) PyComplex_FromCComplex(Py_complex); -#endif -PyAPI_FUNC(PyObject *) PyComplex_FromDoubles(double real, double imag); - -PyAPI_FUNC(double) PyComplex_RealAsDouble(PyObject *op); -PyAPI_FUNC(double) PyComplex_ImagAsDouble(PyObject *op); -#ifndef Py_LIMITED_API -PyAPI_FUNC(Py_complex) PyComplex_AsCComplex(PyObject *op); -#endif - -/* Format the object based on the format_spec, as defined in PEP 3101 - (Advanced String Formatting). */ -#ifndef Py_LIMITED_API -PyAPI_FUNC(int) _PyComplex_FormatAdvancedWriter( - _PyUnicodeWriter *writer, - PyObject *obj, - PyObject *format_spec, - Py_ssize_t start, - Py_ssize_t end); -#endif - -#ifdef __cplusplus -} -#endif -#endif /* !Py_COMPLEXOBJECT_H */ diff --git a/scripts/build-windows/py39-libs/include/context.h b/scripts/build-windows/py39-libs/include/context.h deleted file mode 100644 index 4e5007089..000000000 --- a/scripts/build-windows/py39-libs/include/context.h +++ /dev/null @@ -1,81 +0,0 @@ -#ifndef Py_CONTEXT_H -#define Py_CONTEXT_H -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef Py_LIMITED_API - - -PyAPI_DATA(PyTypeObject) PyContext_Type; -typedef struct _pycontextobject PyContext; - -PyAPI_DATA(PyTypeObject) PyContextVar_Type; -typedef struct _pycontextvarobject PyContextVar; - -PyAPI_DATA(PyTypeObject) PyContextToken_Type; -typedef struct _pycontexttokenobject PyContextToken; - - -#define PyContext_CheckExact(o) Py_IS_TYPE(o, &PyContext_Type) -#define PyContextVar_CheckExact(o) Py_IS_TYPE(o, &PyContextVar_Type) -#define PyContextToken_CheckExact(o) Py_IS_TYPE(o, &PyContextToken_Type) - - -PyAPI_FUNC(PyObject *) PyContext_New(void); -PyAPI_FUNC(PyObject *) PyContext_Copy(PyObject *); -PyAPI_FUNC(PyObject *) PyContext_CopyCurrent(void); - -PyAPI_FUNC(int) PyContext_Enter(PyObject *); -PyAPI_FUNC(int) PyContext_Exit(PyObject *); - - -/* Create a new context variable. - - default_value can be NULL. -*/ -PyAPI_FUNC(PyObject *) PyContextVar_New( - const char *name, PyObject *default_value); - - -/* Get a value for the variable. - - Returns -1 if an error occurred during lookup. - - Returns 0 if value either was or was not found. - - If value was found, *value will point to it. - If not, it will point to: - - - default_value, if not NULL; - - the default value of "var", if not NULL; - - NULL. - - '*value' will be a new ref, if not NULL. -*/ -PyAPI_FUNC(int) PyContextVar_Get( - PyObject *var, PyObject *default_value, PyObject **value); - - -/* Set a new value for the variable. - Returns NULL if an error occurs. -*/ -PyAPI_FUNC(PyObject *) PyContextVar_Set(PyObject *var, PyObject *value); - - -/* Reset a variable to its previous value. - Returns 0 on success, -1 on error. -*/ -PyAPI_FUNC(int) PyContextVar_Reset(PyObject *var, PyObject *token); - - -/* This method is exposed only for CPython tests. Don not use it. */ -PyAPI_FUNC(PyObject *) _PyContext_NewHamtForTests(void); - - -#endif /* !Py_LIMITED_API */ - -#ifdef __cplusplus -} -#endif -#endif /* !Py_CONTEXT_H */ diff --git a/scripts/build-windows/py39-libs/include/cpython/abstract.h b/scripts/build-windows/py39-libs/include/cpython/abstract.h deleted file mode 100644 index 0f1304d26..000000000 --- a/scripts/build-windows/py39-libs/include/cpython/abstract.h +++ /dev/null @@ -1,384 +0,0 @@ -#ifndef Py_CPYTHON_ABSTRACTOBJECT_H -# error "this header file must not be included directly" -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -/* === Object Protocol ================================================== */ - -#ifdef PY_SSIZE_T_CLEAN -# define _PyObject_CallMethodId _PyObject_CallMethodId_SizeT -#endif - -/* Convert keyword arguments from the FASTCALL (stack: C array, kwnames: tuple) - format to a Python dictionary ("kwargs" dict). - - The type of kwnames keys is not checked. The final function getting - arguments is responsible to check if all keys are strings, for example using - PyArg_ParseTupleAndKeywords() or PyArg_ValidateKeywordArguments(). - - Duplicate keys are merged using the last value. If duplicate keys must raise - an exception, the caller is responsible to implement an explicit keys on - kwnames. */ -PyAPI_FUNC(PyObject *) _PyStack_AsDict( - PyObject *const *values, - PyObject *kwnames); - -/* Suggested size (number of positional arguments) for arrays of PyObject* - allocated on a C stack to avoid allocating memory on the heap memory. Such - array is used to pass positional arguments to call functions of the - PyObject_Vectorcall() family. - - The size is chosen to not abuse the C stack and so limit the risk of stack - overflow. The size is also chosen to allow using the small stack for most - function calls of the Python standard library. On 64-bit CPU, it allocates - 40 bytes on the stack. */ -#define _PY_FASTCALL_SMALL_STACK 5 - -PyAPI_FUNC(PyObject *) _Py_CheckFunctionResult( - PyThreadState *tstate, - PyObject *callable, - PyObject *result, - const char *where); - -/* === Vectorcall protocol (PEP 590) ============================= */ - -/* Call callable using tp_call. Arguments are like PyObject_Vectorcall() - or PyObject_FastCallDict() (both forms are supported), - except that nargs is plainly the number of arguments without flags. */ -PyAPI_FUNC(PyObject *) _PyObject_MakeTpCall( - PyThreadState *tstate, - PyObject *callable, - PyObject *const *args, Py_ssize_t nargs, - PyObject *keywords); - -#define PY_VECTORCALL_ARGUMENTS_OFFSET ((size_t)1 << (8 * sizeof(size_t) - 1)) - -static inline Py_ssize_t -PyVectorcall_NARGS(size_t n) -{ - return n & ~PY_VECTORCALL_ARGUMENTS_OFFSET; -} - -static inline vectorcallfunc -PyVectorcall_Function(PyObject *callable) -{ - PyTypeObject *tp; - Py_ssize_t offset; - vectorcallfunc ptr; - - assert(callable != NULL); - tp = Py_TYPE(callable); - if (!PyType_HasFeature(tp, Py_TPFLAGS_HAVE_VECTORCALL)) { - return NULL; - } - assert(PyCallable_Check(callable)); - offset = tp->tp_vectorcall_offset; - assert(offset > 0); - memcpy(&ptr, (char *) callable + offset, sizeof(ptr)); - return ptr; -} - -/* Call the callable object 'callable' with the "vectorcall" calling - convention. - - args is a C array for positional arguments. - - nargsf is the number of positional arguments plus optionally the flag - PY_VECTORCALL_ARGUMENTS_OFFSET which means that the caller is allowed to - modify args[-1]. - - kwnames is a tuple of keyword names. The values of the keyword arguments - are stored in "args" after the positional arguments (note that the number - of keyword arguments does not change nargsf). kwnames can also be NULL if - there are no keyword arguments. - - keywords must only contain strings and all keys must be unique. - - Return the result on success. Raise an exception and return NULL on - error. */ -static inline PyObject * -_PyObject_VectorcallTstate(PyThreadState *tstate, PyObject *callable, - PyObject *const *args, size_t nargsf, - PyObject *kwnames) -{ - vectorcallfunc func; - PyObject *res; - - assert(kwnames == NULL || PyTuple_Check(kwnames)); - assert(args != NULL || PyVectorcall_NARGS(nargsf) == 0); - - func = PyVectorcall_Function(callable); - if (func == NULL) { - Py_ssize_t nargs = PyVectorcall_NARGS(nargsf); - return _PyObject_MakeTpCall(tstate, callable, args, nargs, kwnames); - } - res = func(callable, args, nargsf, kwnames); - return _Py_CheckFunctionResult(tstate, callable, res, NULL); -} - -static inline PyObject * -PyObject_Vectorcall(PyObject *callable, PyObject *const *args, - size_t nargsf, PyObject *kwnames) -{ - PyThreadState *tstate = PyThreadState_GET(); - return _PyObject_VectorcallTstate(tstate, callable, - args, nargsf, kwnames); -} - -// Backwards compatibility aliases for API that was provisional in Python 3.8 -#define _PyObject_Vectorcall PyObject_Vectorcall -#define _PyObject_VectorcallMethod PyObject_VectorcallMethod -#define _PyObject_FastCallDict PyObject_VectorcallDict -#define _PyVectorcall_Function PyVectorcall_Function -#define _PyObject_CallOneArg PyObject_CallOneArg -#define _PyObject_CallMethodNoArgs PyObject_CallMethodNoArgs -#define _PyObject_CallMethodOneArg PyObject_CallMethodOneArg - -/* Same as PyObject_Vectorcall except that keyword arguments are passed as - dict, which may be NULL if there are no keyword arguments. */ -PyAPI_FUNC(PyObject *) PyObject_VectorcallDict( - PyObject *callable, - PyObject *const *args, - size_t nargsf, - PyObject *kwargs); - -/* Call "callable" (which must support vectorcall) with positional arguments - "tuple" and keyword arguments "dict". "dict" may also be NULL */ -PyAPI_FUNC(PyObject *) PyVectorcall_Call(PyObject *callable, PyObject *tuple, PyObject *dict); - -static inline PyObject * -_PyObject_FastCallTstate(PyThreadState *tstate, PyObject *func, PyObject *const *args, Py_ssize_t nargs) -{ - return _PyObject_VectorcallTstate(tstate, func, args, (size_t)nargs, NULL); -} - -/* Same as PyObject_Vectorcall except without keyword arguments */ -static inline PyObject * -_PyObject_FastCall(PyObject *func, PyObject *const *args, Py_ssize_t nargs) -{ - PyThreadState *tstate = PyThreadState_GET(); - return _PyObject_FastCallTstate(tstate, func, args, nargs); -} - -/* Call a callable without any arguments - Private static inline function variant of public function - PyObject_CallNoArgs(). */ -static inline PyObject * -_PyObject_CallNoArg(PyObject *func) { - PyThreadState *tstate = PyThreadState_GET(); - return _PyObject_VectorcallTstate(tstate, func, NULL, 0, NULL); -} - -static inline PyObject * -PyObject_CallOneArg(PyObject *func, PyObject *arg) -{ - PyObject *_args[2]; - PyObject **args; - PyThreadState *tstate; - size_t nargsf; - - assert(arg != NULL); - args = _args + 1; // For PY_VECTORCALL_ARGUMENTS_OFFSET - args[0] = arg; - tstate = PyThreadState_GET(); - nargsf = 1 | PY_VECTORCALL_ARGUMENTS_OFFSET; - return _PyObject_VectorcallTstate(tstate, func, args, nargsf, NULL); -} - -PyAPI_FUNC(PyObject *) PyObject_VectorcallMethod( - PyObject *name, PyObject *const *args, - size_t nargsf, PyObject *kwnames); - -static inline PyObject * -PyObject_CallMethodNoArgs(PyObject *self, PyObject *name) -{ - return PyObject_VectorcallMethod(name, &self, - 1 | PY_VECTORCALL_ARGUMENTS_OFFSET, NULL); -} - -static inline PyObject * -PyObject_CallMethodOneArg(PyObject *self, PyObject *name, PyObject *arg) -{ - PyObject *args[2] = {self, arg}; - - assert(arg != NULL); - return PyObject_VectorcallMethod(name, args, - 2 | PY_VECTORCALL_ARGUMENTS_OFFSET, NULL); -} - -/* Like PyObject_CallMethod(), but expect a _Py_Identifier* - as the method name. */ -PyAPI_FUNC(PyObject *) _PyObject_CallMethodId(PyObject *obj, - _Py_Identifier *name, - const char *format, ...); - -PyAPI_FUNC(PyObject *) _PyObject_CallMethodId_SizeT(PyObject *obj, - _Py_Identifier *name, - const char *format, - ...); - -PyAPI_FUNC(PyObject *) _PyObject_CallMethodIdObjArgs( - PyObject *obj, - struct _Py_Identifier *name, - ...); - -static inline PyObject * -_PyObject_VectorcallMethodId( - _Py_Identifier *name, PyObject *const *args, - size_t nargsf, PyObject *kwnames) -{ - PyObject *oname = _PyUnicode_FromId(name); /* borrowed */ - if (!oname) { - return NULL; - } - return PyObject_VectorcallMethod(oname, args, nargsf, kwnames); -} - -static inline PyObject * -_PyObject_CallMethodIdNoArgs(PyObject *self, _Py_Identifier *name) -{ - return _PyObject_VectorcallMethodId(name, &self, - 1 | PY_VECTORCALL_ARGUMENTS_OFFSET, NULL); -} - -static inline PyObject * -_PyObject_CallMethodIdOneArg(PyObject *self, _Py_Identifier *name, PyObject *arg) -{ - PyObject *args[2] = {self, arg}; - - assert(arg != NULL); - return _PyObject_VectorcallMethodId(name, args, - 2 | PY_VECTORCALL_ARGUMENTS_OFFSET, NULL); -} - -PyAPI_FUNC(int) _PyObject_HasLen(PyObject *o); - -/* Guess the size of object 'o' using len(o) or o.__length_hint__(). - If neither of those return a non-negative value, then return the default - value. If one of the calls fails, this function returns -1. */ -PyAPI_FUNC(Py_ssize_t) PyObject_LengthHint(PyObject *o, Py_ssize_t); - -/* === New Buffer API ============================================ */ - -/* Return 1 if the getbuffer function is available, otherwise return 0. */ -PyAPI_FUNC(int) PyObject_CheckBuffer(PyObject *obj); - -/* This is a C-API version of the getbuffer function call. It checks - to make sure object has the required function pointer and issues the - call. - - Returns -1 and raises an error on failure and returns 0 on success. */ -PyAPI_FUNC(int) PyObject_GetBuffer(PyObject *obj, Py_buffer *view, - int flags); - -/* Get the memory area pointed to by the indices for the buffer given. - Note that view->ndim is the assumed size of indices. */ -PyAPI_FUNC(void *) PyBuffer_GetPointer(Py_buffer *view, Py_ssize_t *indices); - -/* Return the implied itemsize of the data-format area from a - struct-style description. */ -PyAPI_FUNC(Py_ssize_t) PyBuffer_SizeFromFormat(const char *format); - -/* Implementation in memoryobject.c */ -PyAPI_FUNC(int) PyBuffer_ToContiguous(void *buf, Py_buffer *view, - Py_ssize_t len, char order); - -PyAPI_FUNC(int) PyBuffer_FromContiguous(Py_buffer *view, void *buf, - Py_ssize_t len, char order); - -/* Copy len bytes of data from the contiguous chunk of memory - pointed to by buf into the buffer exported by obj. Return - 0 on success and return -1 and raise a PyBuffer_Error on - error (i.e. the object does not have a buffer interface or - it is not working). - - If fort is 'F', then if the object is multi-dimensional, - then the data will be copied into the array in - Fortran-style (first dimension varies the fastest). If - fort is 'C', then the data will be copied into the array - in C-style (last dimension varies the fastest). If fort - is 'A', then it does not matter and the copy will be made - in whatever way is more efficient. */ -PyAPI_FUNC(int) PyObject_CopyData(PyObject *dest, PyObject *src); - -/* Copy the data from the src buffer to the buffer of destination. */ -PyAPI_FUNC(int) PyBuffer_IsContiguous(const Py_buffer *view, char fort); - -/*Fill the strides array with byte-strides of a contiguous - (Fortran-style if fort is 'F' or C-style otherwise) - array of the given shape with the given number of bytes - per element. */ -PyAPI_FUNC(void) PyBuffer_FillContiguousStrides(int ndims, - Py_ssize_t *shape, - Py_ssize_t *strides, - int itemsize, - char fort); - -/* Fills in a buffer-info structure correctly for an exporter - that can only share a contiguous chunk of memory of - "unsigned bytes" of the given length. - - Returns 0 on success and -1 (with raising an error) on error. */ -PyAPI_FUNC(int) PyBuffer_FillInfo(Py_buffer *view, PyObject *o, void *buf, - Py_ssize_t len, int readonly, - int flags); - -/* Releases a Py_buffer obtained from getbuffer ParseTuple's "s*". */ -PyAPI_FUNC(void) PyBuffer_Release(Py_buffer *view); - -/* ==== Iterators ================================================ */ - -#define PyIter_Check(obj) \ - (Py_TYPE(obj)->tp_iternext != NULL && \ - Py_TYPE(obj)->tp_iternext != &_PyObject_NextNotImplemented) - -/* === Sequence protocol ================================================ */ - -/* Assume tp_as_sequence and sq_item exist and that 'i' does not - need to be corrected for a negative index. */ -#define PySequence_ITEM(o, i)\ - ( Py_TYPE(o)->tp_as_sequence->sq_item(o, i) ) - -#define PY_ITERSEARCH_COUNT 1 -#define PY_ITERSEARCH_INDEX 2 -#define PY_ITERSEARCH_CONTAINS 3 - -/* Iterate over seq. - - Result depends on the operation: - - PY_ITERSEARCH_COUNT: return # of times obj appears in seq; -1 if - error. - PY_ITERSEARCH_INDEX: return 0-based index of first occurrence of - obj in seq; set ValueError and return -1 if none found; - also return -1 on error. - PY_ITERSEARCH_CONTAINS: return 1 if obj in seq, else 0; -1 on - error. */ -PyAPI_FUNC(Py_ssize_t) _PySequence_IterSearch(PyObject *seq, - PyObject *obj, int operation); - -/* === Mapping protocol ================================================= */ - -PyAPI_FUNC(int) _PyObject_RealIsInstance(PyObject *inst, PyObject *cls); - -PyAPI_FUNC(int) _PyObject_RealIsSubclass(PyObject *derived, PyObject *cls); - -PyAPI_FUNC(char *const *) _PySequence_BytesToCharpArray(PyObject* self); - -PyAPI_FUNC(void) _Py_FreeCharPArray(char *const array[]); - -/* For internal use by buffer API functions */ -PyAPI_FUNC(void) _Py_add_one_to_index_F(int nd, Py_ssize_t *index, - const Py_ssize_t *shape); -PyAPI_FUNC(void) _Py_add_one_to_index_C(int nd, Py_ssize_t *index, - const Py_ssize_t *shape); - -/* Convert Python int to Py_ssize_t. Do nothing if the argument is None. */ -PyAPI_FUNC(int) _Py_convert_optional_to_ssize_t(PyObject *, void *); - -#ifdef __cplusplus -} -#endif diff --git a/scripts/build-windows/py39-libs/include/cpython/bytearrayobject.h b/scripts/build-windows/py39-libs/include/cpython/bytearrayobject.h deleted file mode 100644 index 569b0cd03..000000000 --- a/scripts/build-windows/py39-libs/include/cpython/bytearrayobject.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef Py_CPYTHON_BYTEARRAYOBJECT_H -# error "this header file must not be included directly" -#endif - -/* Object layout */ -typedef struct { - PyObject_VAR_HEAD - Py_ssize_t ob_alloc; /* How many bytes allocated in ob_bytes */ - char *ob_bytes; /* Physical backing buffer */ - char *ob_start; /* Logical start inside ob_bytes */ - Py_ssize_t ob_exports; /* How many buffer exports */ -} PyByteArrayObject; - -/* Macros, trading safety for speed */ -#define PyByteArray_AS_STRING(self) \ - (assert(PyByteArray_Check(self)), \ - Py_SIZE(self) ? ((PyByteArrayObject *)(self))->ob_start : _PyByteArray_empty_string) -#define PyByteArray_GET_SIZE(self) (assert(PyByteArray_Check(self)), Py_SIZE(self)) - -PyAPI_DATA(char) _PyByteArray_empty_string[]; diff --git a/scripts/build-windows/py39-libs/include/cpython/bytesobject.h b/scripts/build-windows/py39-libs/include/cpython/bytesobject.h deleted file mode 100644 index f284c5835..000000000 --- a/scripts/build-windows/py39-libs/include/cpython/bytesobject.h +++ /dev/null @@ -1,118 +0,0 @@ -#ifndef Py_CPYTHON_BYTESOBJECT_H -# error "this header file must not be included directly" -#endif - -typedef struct { - PyObject_VAR_HEAD - Py_hash_t ob_shash; - char ob_sval[1]; - - /* Invariants: - * ob_sval contains space for 'ob_size+1' elements. - * ob_sval[ob_size] == 0. - * ob_shash is the hash of the string or -1 if not computed yet. - */ -} PyBytesObject; - -PyAPI_FUNC(int) _PyBytes_Resize(PyObject **, Py_ssize_t); -PyAPI_FUNC(PyObject*) _PyBytes_FormatEx( - const char *format, - Py_ssize_t format_len, - PyObject *args, - int use_bytearray); -PyAPI_FUNC(PyObject*) _PyBytes_FromHex( - PyObject *string, - int use_bytearray); - -/* Helper for PyBytes_DecodeEscape that detects invalid escape chars. */ -PyAPI_FUNC(PyObject *) _PyBytes_DecodeEscape(const char *, Py_ssize_t, - const char *, const char **); - -/* Macro, trading safety for speed */ -#define PyBytes_AS_STRING(op) (assert(PyBytes_Check(op)), \ - (((PyBytesObject *)(op))->ob_sval)) -#define PyBytes_GET_SIZE(op) (assert(PyBytes_Check(op)),Py_SIZE(op)) - -/* _PyBytes_Join(sep, x) is like sep.join(x). sep must be PyBytesObject*, - x must be an iterable object. */ -PyAPI_FUNC(PyObject *) _PyBytes_Join(PyObject *sep, PyObject *x); - - -/* The _PyBytesWriter structure is big: it contains an embedded "stack buffer". - A _PyBytesWriter variable must be declared at the end of variables in a - function to optimize the memory allocation on the stack. */ -typedef struct { - /* bytes, bytearray or NULL (when the small buffer is used) */ - PyObject *buffer; - - /* Number of allocated size. */ - Py_ssize_t allocated; - - /* Minimum number of allocated bytes, - incremented by _PyBytesWriter_Prepare() */ - Py_ssize_t min_size; - - /* If non-zero, use a bytearray instead of a bytes object for buffer. */ - int use_bytearray; - - /* If non-zero, overallocate the buffer (default: 0). - This flag must be zero if use_bytearray is non-zero. */ - int overallocate; - - /* Stack buffer */ - int use_small_buffer; - char small_buffer[512]; -} _PyBytesWriter; - -/* Initialize a bytes writer - - By default, the overallocation is disabled. Set the overallocate attribute - to control the allocation of the buffer. */ -PyAPI_FUNC(void) _PyBytesWriter_Init(_PyBytesWriter *writer); - -/* Get the buffer content and reset the writer. - Return a bytes object, or a bytearray object if use_bytearray is non-zero. - Raise an exception and return NULL on error. */ -PyAPI_FUNC(PyObject *) _PyBytesWriter_Finish(_PyBytesWriter *writer, - void *str); - -/* Deallocate memory of a writer (clear its internal buffer). */ -PyAPI_FUNC(void) _PyBytesWriter_Dealloc(_PyBytesWriter *writer); - -/* Allocate the buffer to write size bytes. - Return the pointer to the beginning of buffer data. - Raise an exception and return NULL on error. */ -PyAPI_FUNC(void*) _PyBytesWriter_Alloc(_PyBytesWriter *writer, - Py_ssize_t size); - -/* Ensure that the buffer is large enough to write *size* bytes. - Add size to the writer minimum size (min_size attribute). - - str is the current pointer inside the buffer. - Return the updated current pointer inside the buffer. - Raise an exception and return NULL on error. */ -PyAPI_FUNC(void*) _PyBytesWriter_Prepare(_PyBytesWriter *writer, - void *str, - Py_ssize_t size); - -/* Resize the buffer to make it larger. - The new buffer may be larger than size bytes because of overallocation. - Return the updated current pointer inside the buffer. - Raise an exception and return NULL on error. - - Note: size must be greater than the number of allocated bytes in the writer. - - This function doesn't use the writer minimum size (min_size attribute). - - See also _PyBytesWriter_Prepare(). - */ -PyAPI_FUNC(void*) _PyBytesWriter_Resize(_PyBytesWriter *writer, - void *str, - Py_ssize_t size); - -/* Write bytes. - Raise an exception and return NULL on error. */ -PyAPI_FUNC(void*) _PyBytesWriter_WriteBytes(_PyBytesWriter *writer, - void *str, - const void *bytes, - Py_ssize_t size); diff --git a/scripts/build-windows/py39-libs/include/cpython/ceval.h b/scripts/build-windows/py39-libs/include/cpython/ceval.h deleted file mode 100644 index e1922a677..000000000 --- a/scripts/build-windows/py39-libs/include/cpython/ceval.h +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef Py_CPYTHON_CEVAL_H -# error "this header file must not be included directly" -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -PyAPI_FUNC(void) PyEval_SetProfile(Py_tracefunc, PyObject *); -PyAPI_DATA(int) _PyEval_SetProfile(PyThreadState *tstate, Py_tracefunc func, PyObject *arg); -PyAPI_FUNC(void) PyEval_SetTrace(Py_tracefunc, PyObject *); -PyAPI_FUNC(int) _PyEval_SetTrace(PyThreadState *tstate, Py_tracefunc func, PyObject *arg); -PyAPI_FUNC(int) _PyEval_GetCoroutineOriginTrackingDepth(void); -PyAPI_FUNC(int) _PyEval_SetAsyncGenFirstiter(PyObject *); -PyAPI_FUNC(PyObject *) _PyEval_GetAsyncGenFirstiter(void); -PyAPI_FUNC(int) _PyEval_SetAsyncGenFinalizer(PyObject *); -PyAPI_FUNC(PyObject *) _PyEval_GetAsyncGenFinalizer(void); - -/* Helper to look up a builtin object */ -PyAPI_FUNC(PyObject *) _PyEval_GetBuiltinId(_Py_Identifier *); -/* Look at the current frame's (if any) code's co_flags, and turn on - the corresponding compiler flags in cf->cf_flags. Return 1 if any - flag was set, else return 0. */ -PyAPI_FUNC(int) PyEval_MergeCompilerFlags(PyCompilerFlags *cf); - -PyAPI_FUNC(PyObject *) _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int exc); - -PyAPI_FUNC(void) _PyEval_SetSwitchInterval(unsigned long microseconds); -PyAPI_FUNC(unsigned long) _PyEval_GetSwitchInterval(void); - -PyAPI_FUNC(Py_ssize_t) _PyEval_RequestCodeExtraIndex(freefunc); - -PyAPI_FUNC(int) _PyEval_SliceIndex(PyObject *, Py_ssize_t *); -PyAPI_FUNC(int) _PyEval_SliceIndexNotNone(PyObject *, Py_ssize_t *); - -#ifdef __cplusplus -} -#endif diff --git a/scripts/build-windows/py39-libs/include/cpython/code.h b/scripts/build-windows/py39-libs/include/cpython/code.h deleted file mode 100644 index cda28ac6e..000000000 --- a/scripts/build-windows/py39-libs/include/cpython/code.h +++ /dev/null @@ -1,165 +0,0 @@ -#ifndef Py_CPYTHON_CODE_H -# error "this header file must not be included directly" -#endif - -typedef uint16_t _Py_CODEUNIT; - -#ifdef WORDS_BIGENDIAN -# define _Py_OPCODE(word) ((word) >> 8) -# define _Py_OPARG(word) ((word) & 255) -#else -# define _Py_OPCODE(word) ((word) & 255) -# define _Py_OPARG(word) ((word) >> 8) -#endif - -typedef struct _PyOpcache _PyOpcache; - -/* Bytecode object */ -struct PyCodeObject { - PyObject_HEAD - int co_argcount; /* #arguments, except *args */ - int co_posonlyargcount; /* #positional only arguments */ - int co_kwonlyargcount; /* #keyword only arguments */ - int co_nlocals; /* #local variables */ - int co_stacksize; /* #entries needed for evaluation stack */ - int co_flags; /* CO_..., see below */ - int co_firstlineno; /* first source line number */ - PyObject *co_code; /* instruction opcodes */ - PyObject *co_consts; /* list (constants used) */ - PyObject *co_names; /* list of strings (names used) */ - PyObject *co_varnames; /* tuple of strings (local variable names) */ - PyObject *co_freevars; /* tuple of strings (free variable names) */ - PyObject *co_cellvars; /* tuple of strings (cell variable names) */ - /* The rest aren't used in either hash or comparisons, except for co_name, - used in both. This is done to preserve the name and line number - for tracebacks and debuggers; otherwise, constant de-duplication - would collapse identical functions/lambdas defined on different lines. - */ - Py_ssize_t *co_cell2arg; /* Maps cell vars which are arguments. */ - PyObject *co_filename; /* unicode (where it was loaded from) */ - PyObject *co_name; /* unicode (name, for reference) */ - PyObject *co_lnotab; /* string (encoding addr<->lineno mapping) See - Objects/lnotab_notes.txt for details. */ - void *co_zombieframe; /* for optimization only (see frameobject.c) */ - PyObject *co_weakreflist; /* to support weakrefs to code objects */ - /* Scratch space for extra data relating to the code object. - Type is a void* to keep the format private in codeobject.c to force - people to go through the proper APIs. */ - void *co_extra; - - /* Per opcodes just-in-time cache - * - * To reduce cache size, we use indirect mapping from opcode index to - * cache object: - * cache = co_opcache[co_opcache_map[next_instr - first_instr] - 1] - */ - - // co_opcache_map is indexed by (next_instr - first_instr). - // * 0 means there is no cache for this opcode. - // * n > 0 means there is cache in co_opcache[n-1]. - unsigned char *co_opcache_map; - _PyOpcache *co_opcache; - int co_opcache_flag; // used to determine when create a cache. - unsigned char co_opcache_size; // length of co_opcache. -}; - -/* Masks for co_flags above */ -#define CO_OPTIMIZED 0x0001 -#define CO_NEWLOCALS 0x0002 -#define CO_VARARGS 0x0004 -#define CO_VARKEYWORDS 0x0008 -#define CO_NESTED 0x0010 -#define CO_GENERATOR 0x0020 -/* The CO_NOFREE flag is set if there are no free or cell variables. - This information is redundant, but it allows a single flag test - to determine whether there is any extra work to be done when the - call frame it setup. -*/ -#define CO_NOFREE 0x0040 - -/* The CO_COROUTINE flag is set for coroutine functions (defined with - ``async def`` keywords) */ -#define CO_COROUTINE 0x0080 -#define CO_ITERABLE_COROUTINE 0x0100 -#define CO_ASYNC_GENERATOR 0x0200 - -/* bpo-39562: These constant values are changed in Python 3.9 - to prevent collision with compiler flags. CO_FUTURE_ and PyCF_ - constants must be kept unique. PyCF_ constants can use bits from - 0x0100 to 0x10000. CO_FUTURE_ constants use bits starting at 0x20000. */ -#define CO_FUTURE_DIVISION 0x20000 -#define CO_FUTURE_ABSOLUTE_IMPORT 0x40000 /* do absolute imports by default */ -#define CO_FUTURE_WITH_STATEMENT 0x80000 -#define CO_FUTURE_PRINT_FUNCTION 0x100000 -#define CO_FUTURE_UNICODE_LITERALS 0x200000 - -#define CO_FUTURE_BARRY_AS_BDFL 0x400000 -#define CO_FUTURE_GENERATOR_STOP 0x800000 -#define CO_FUTURE_ANNOTATIONS 0x1000000 - -/* This value is found in the co_cell2arg array when the associated cell - variable does not correspond to an argument. */ -#define CO_CELL_NOT_AN_ARG (-1) - -/* This should be defined if a future statement modifies the syntax. - For example, when a keyword is added. -*/ -#define PY_PARSER_REQUIRES_FUTURE_KEYWORD - -#define CO_MAXBLOCKS 20 /* Max static block nesting within a function */ - -PyAPI_DATA(PyTypeObject) PyCode_Type; - -#define PyCode_Check(op) Py_IS_TYPE(op, &PyCode_Type) -#define PyCode_GetNumFree(op) (PyTuple_GET_SIZE((op)->co_freevars)) - -/* Public interface */ -PyAPI_FUNC(PyCodeObject *) PyCode_New( - int, int, int, int, int, PyObject *, PyObject *, - PyObject *, PyObject *, PyObject *, PyObject *, - PyObject *, PyObject *, int, PyObject *); - -PyAPI_FUNC(PyCodeObject *) PyCode_NewWithPosOnlyArgs( - int, int, int, int, int, int, PyObject *, PyObject *, - PyObject *, PyObject *, PyObject *, PyObject *, - PyObject *, PyObject *, int, PyObject *); - /* same as struct above */ - -/* Creates a new empty code object with the specified source location. */ -PyAPI_FUNC(PyCodeObject *) -PyCode_NewEmpty(const char *filename, const char *funcname, int firstlineno); - -/* Return the line number associated with the specified bytecode index - in this code object. If you just need the line number of a frame, - use PyFrame_GetLineNumber() instead. */ -PyAPI_FUNC(int) PyCode_Addr2Line(PyCodeObject *, int); - -/* for internal use only */ -typedef struct _addr_pair { - int ap_lower; - int ap_upper; -} PyAddrPair; - -/* Update *bounds to describe the first and one-past-the-last instructions in the - same line as lasti. Return the number of that line. -*/ -PyAPI_FUNC(int) _PyCode_CheckLineNumber(PyCodeObject* co, - int lasti, PyAddrPair *bounds); - -/* Create a comparable key used to compare constants taking in account the - * object type. It is used to make sure types are not coerced (e.g., float and - * complex) _and_ to distinguish 0.0 from -0.0 e.g. on IEEE platforms - * - * Return (type(obj), obj, ...): a tuple with variable size (at least 2 items) - * depending on the type and the value. The type is the first item to not - * compare bytes and str which can raise a BytesWarning exception. */ -PyAPI_FUNC(PyObject*) _PyCode_ConstantKey(PyObject *obj); - -PyAPI_FUNC(PyObject*) PyCode_Optimize(PyObject *code, PyObject* consts, - PyObject *names, PyObject *lnotab); - - -PyAPI_FUNC(int) _PyCode_GetExtra(PyObject *code, Py_ssize_t index, - void **extra); -PyAPI_FUNC(int) _PyCode_SetExtra(PyObject *code, Py_ssize_t index, - void *extra); diff --git a/scripts/build-windows/py39-libs/include/cpython/dictobject.h b/scripts/build-windows/py39-libs/include/cpython/dictobject.h deleted file mode 100644 index e33a0d156..000000000 --- a/scripts/build-windows/py39-libs/include/cpython/dictobject.h +++ /dev/null @@ -1,92 +0,0 @@ -#ifndef Py_CPYTHON_DICTOBJECT_H -# error "this header file must not be included directly" -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct _dictkeysobject PyDictKeysObject; - -/* The ma_values pointer is NULL for a combined table - * or points to an array of PyObject* for a split table - */ -typedef struct { - PyObject_HEAD - - /* Number of items in the dictionary */ - Py_ssize_t ma_used; - - /* Dictionary version: globally unique, value change each time - the dictionary is modified */ - uint64_t ma_version_tag; - - PyDictKeysObject *ma_keys; - - /* If ma_values is NULL, the table is "combined": keys and values - are stored in ma_keys. - - If ma_values is not NULL, the table is splitted: - keys are stored in ma_keys and values are stored in ma_values */ - PyObject **ma_values; -} PyDictObject; - -PyAPI_FUNC(PyObject *) _PyDict_GetItem_KnownHash(PyObject *mp, PyObject *key, - Py_hash_t hash); -PyAPI_FUNC(PyObject *) _PyDict_GetItemIdWithError(PyObject *dp, - struct _Py_Identifier *key); -PyAPI_FUNC(PyObject *) _PyDict_GetItemStringWithError(PyObject *, const char *); -PyAPI_FUNC(PyObject *) PyDict_SetDefault( - PyObject *mp, PyObject *key, PyObject *defaultobj); -PyAPI_FUNC(int) _PyDict_SetItem_KnownHash(PyObject *mp, PyObject *key, - PyObject *item, Py_hash_t hash); -PyAPI_FUNC(int) _PyDict_DelItem_KnownHash(PyObject *mp, PyObject *key, - Py_hash_t hash); -PyAPI_FUNC(int) _PyDict_DelItemIf(PyObject *mp, PyObject *key, - int (*predicate)(PyObject *value)); -PyDictKeysObject *_PyDict_NewKeysForClass(void); -PyAPI_FUNC(PyObject *) PyObject_GenericGetDict(PyObject *, void *); -PyAPI_FUNC(int) _PyDict_Next( - PyObject *mp, Py_ssize_t *pos, PyObject **key, PyObject **value, Py_hash_t *hash); - -/* Get the number of items of a dictionary. */ -#define PyDict_GET_SIZE(mp) (assert(PyDict_Check(mp)),((PyDictObject *)mp)->ma_used) -PyAPI_FUNC(int) _PyDict_Contains(PyObject *mp, PyObject *key, Py_hash_t hash); -PyAPI_FUNC(PyObject *) _PyDict_NewPresized(Py_ssize_t minused); -PyAPI_FUNC(void) _PyDict_MaybeUntrack(PyObject *mp); -PyAPI_FUNC(int) _PyDict_HasOnlyStringKeys(PyObject *mp); -Py_ssize_t _PyDict_KeysSize(PyDictKeysObject *keys); -PyAPI_FUNC(Py_ssize_t) _PyDict_SizeOf(PyDictObject *); -PyAPI_FUNC(PyObject *) _PyDict_Pop(PyObject *, PyObject *, PyObject *); -PyObject *_PyDict_Pop_KnownHash(PyObject *, PyObject *, Py_hash_t, PyObject *); -PyObject *_PyDict_FromKeys(PyObject *, PyObject *, PyObject *); -#define _PyDict_HasSplitTable(d) ((d)->ma_values != NULL) - -/* Like PyDict_Merge, but override can be 0, 1 or 2. If override is 0, - the first occurrence of a key wins, if override is 1, the last occurrence - of a key wins, if override is 2, a KeyError with conflicting key as - argument is raised. -*/ -PyAPI_FUNC(int) _PyDict_MergeEx(PyObject *mp, PyObject *other, int override); -PyAPI_FUNC(PyObject *) _PyDict_GetItemId(PyObject *dp, struct _Py_Identifier *key); -PyAPI_FUNC(int) _PyDict_SetItemId(PyObject *dp, struct _Py_Identifier *key, PyObject *item); - -PyAPI_FUNC(int) _PyDict_DelItemId(PyObject *mp, struct _Py_Identifier *key); -PyAPI_FUNC(void) _PyDict_DebugMallocStats(FILE *out); - -int _PyObjectDict_SetItem(PyTypeObject *tp, PyObject **dictptr, PyObject *name, PyObject *value); -PyObject *_PyDict_LoadGlobal(PyDictObject *, PyDictObject *, PyObject *); - -/* _PyDictView */ - -typedef struct { - PyObject_HEAD - PyDictObject *dv_dict; -} _PyDictViewObject; - -PyAPI_FUNC(PyObject *) _PyDictView_New(PyObject *, PyTypeObject *); -PyAPI_FUNC(PyObject *) _PyDictView_Intersect(PyObject* self, PyObject *other); - -#ifdef __cplusplus -} -#endif diff --git a/scripts/build-windows/py39-libs/include/cpython/fileobject.h b/scripts/build-windows/py39-libs/include/cpython/fileobject.h deleted file mode 100644 index 3005ce1f0..000000000 --- a/scripts/build-windows/py39-libs/include/cpython/fileobject.h +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef Py_CPYTHON_FILEOBJECT_H -# error "this header file must not be included directly" -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -PyAPI_FUNC(char *) Py_UniversalNewlineFgets(char *, int, FILE*, PyObject *); - -/* The std printer acts as a preliminary sys.stderr until the new io - infrastructure is in place. */ -PyAPI_FUNC(PyObject *) PyFile_NewStdPrinter(int); -PyAPI_DATA(PyTypeObject) PyStdPrinter_Type; - -typedef PyObject * (*Py_OpenCodeHookFunction)(PyObject *, void *); - -PyAPI_FUNC(PyObject *) PyFile_OpenCode(const char *utf8path); -PyAPI_FUNC(PyObject *) PyFile_OpenCodeObject(PyObject *path); -PyAPI_FUNC(int) PyFile_SetOpenCodeHook(Py_OpenCodeHookFunction hook, void *userData); - -#ifdef __cplusplus -} -#endif diff --git a/scripts/build-windows/py39-libs/include/cpython/fileutils.h b/scripts/build-windows/py39-libs/include/cpython/fileutils.h deleted file mode 100644 index e79d03e24..000000000 --- a/scripts/build-windows/py39-libs/include/cpython/fileutils.h +++ /dev/null @@ -1,165 +0,0 @@ -#ifndef Py_CPYTHON_FILEUTILS_H -# error "this header file must not be included directly" -#endif - -typedef enum { - _Py_ERROR_UNKNOWN=0, - _Py_ERROR_STRICT, - _Py_ERROR_SURROGATEESCAPE, - _Py_ERROR_REPLACE, - _Py_ERROR_IGNORE, - _Py_ERROR_BACKSLASHREPLACE, - _Py_ERROR_SURROGATEPASS, - _Py_ERROR_XMLCHARREFREPLACE, - _Py_ERROR_OTHER -} _Py_error_handler; - -PyAPI_FUNC(_Py_error_handler) _Py_GetErrorHandler(const char *errors); - -PyAPI_FUNC(int) _Py_DecodeLocaleEx( - const char *arg, - wchar_t **wstr, - size_t *wlen, - const char **reason, - int current_locale, - _Py_error_handler errors); - -PyAPI_FUNC(int) _Py_EncodeLocaleEx( - const wchar_t *text, - char **str, - size_t *error_pos, - const char **reason, - int current_locale, - _Py_error_handler errors); - - -PyAPI_FUNC(PyObject *) _Py_device_encoding(int); - -#if defined(MS_WINDOWS) || defined(__APPLE__) - /* On Windows, the count parameter of read() is an int (bpo-9015, bpo-9611). - On macOS 10.13, read() and write() with more than INT_MAX bytes - fail with EINVAL (bpo-24658). */ -# define _PY_READ_MAX INT_MAX -# define _PY_WRITE_MAX INT_MAX -#else - /* write() should truncate the input to PY_SSIZE_T_MAX bytes, - but it's safer to do it ourself to have a portable behaviour */ -# define _PY_READ_MAX PY_SSIZE_T_MAX -# define _PY_WRITE_MAX PY_SSIZE_T_MAX -#endif - -#ifdef MS_WINDOWS -struct _Py_stat_struct { - unsigned long st_dev; - uint64_t st_ino; - unsigned short st_mode; - int st_nlink; - int st_uid; - int st_gid; - unsigned long st_rdev; - __int64 st_size; - time_t st_atime; - int st_atime_nsec; - time_t st_mtime; - int st_mtime_nsec; - time_t st_ctime; - int st_ctime_nsec; - unsigned long st_file_attributes; - unsigned long st_reparse_tag; -}; -#else -# define _Py_stat_struct stat -#endif - -PyAPI_FUNC(int) _Py_fstat( - int fd, - struct _Py_stat_struct *status); - -PyAPI_FUNC(int) _Py_fstat_noraise( - int fd, - struct _Py_stat_struct *status); - -PyAPI_FUNC(int) _Py_stat( - PyObject *path, - struct stat *status); - -PyAPI_FUNC(int) _Py_open( - const char *pathname, - int flags); - -PyAPI_FUNC(int) _Py_open_noraise( - const char *pathname, - int flags); - -PyAPI_FUNC(FILE *) _Py_wfopen( - const wchar_t *path, - const wchar_t *mode); - -PyAPI_FUNC(FILE*) _Py_fopen( - const char *pathname, - const char *mode); - -PyAPI_FUNC(FILE*) _Py_fopen_obj( - PyObject *path, - const char *mode); - -PyAPI_FUNC(Py_ssize_t) _Py_read( - int fd, - void *buf, - size_t count); - -PyAPI_FUNC(Py_ssize_t) _Py_write( - int fd, - const void *buf, - size_t count); - -PyAPI_FUNC(Py_ssize_t) _Py_write_noraise( - int fd, - const void *buf, - size_t count); - -#ifdef HAVE_READLINK -PyAPI_FUNC(int) _Py_wreadlink( - const wchar_t *path, - wchar_t *buf, - /* Number of characters of 'buf' buffer - including the trailing NUL character */ - size_t buflen); -#endif - -#ifdef HAVE_REALPATH -PyAPI_FUNC(wchar_t*) _Py_wrealpath( - const wchar_t *path, - wchar_t *resolved_path, - /* Number of characters of 'resolved_path' buffer - including the trailing NUL character */ - size_t resolved_path_len); -#endif - -#ifndef MS_WINDOWS -PyAPI_FUNC(int) _Py_isabs(const wchar_t *path); -#endif - -PyAPI_FUNC(int) _Py_abspath(const wchar_t *path, wchar_t **abspath_p); - -PyAPI_FUNC(wchar_t*) _Py_wgetcwd( - wchar_t *buf, - /* Number of characters of 'buf' buffer - including the trailing NUL character */ - size_t buflen); - -PyAPI_FUNC(int) _Py_get_inheritable(int fd); - -PyAPI_FUNC(int) _Py_set_inheritable(int fd, int inheritable, - int *atomic_flag_works); - -PyAPI_FUNC(int) _Py_set_inheritable_async_safe(int fd, int inheritable, - int *atomic_flag_works); - -PyAPI_FUNC(int) _Py_dup(int fd); - -#ifndef MS_WINDOWS -PyAPI_FUNC(int) _Py_get_blocking(int fd); - -PyAPI_FUNC(int) _Py_set_blocking(int fd, int blocking); -#endif /* !MS_WINDOWS */ diff --git a/scripts/build-windows/py39-libs/include/cpython/frameobject.h b/scripts/build-windows/py39-libs/include/cpython/frameobject.h deleted file mode 100644 index 36a51baae..000000000 --- a/scripts/build-windows/py39-libs/include/cpython/frameobject.h +++ /dev/null @@ -1,84 +0,0 @@ -/* Frame object interface */ - -#ifndef Py_CPYTHON_FRAMEOBJECT_H -# error "this header file must not be included directly" -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct { - int b_type; /* what kind of block this is */ - int b_handler; /* where to jump to find handler */ - int b_level; /* value stack level to pop to */ -} PyTryBlock; - -struct _frame { - PyObject_VAR_HEAD - struct _frame *f_back; /* previous frame, or NULL */ - PyCodeObject *f_code; /* code segment */ - PyObject *f_builtins; /* builtin symbol table (PyDictObject) */ - PyObject *f_globals; /* global symbol table (PyDictObject) */ - PyObject *f_locals; /* local symbol table (any mapping) */ - PyObject **f_valuestack; /* points after the last local */ - /* Next free slot in f_valuestack. Frame creation sets to f_valuestack. - Frame evaluation usually NULLs it, but a frame that yields sets it - to the current stack top. */ - PyObject **f_stacktop; - PyObject *f_trace; /* Trace function */ - char f_trace_lines; /* Emit per-line trace events? */ - char f_trace_opcodes; /* Emit per-opcode trace events? */ - - /* Borrowed reference to a generator, or NULL */ - PyObject *f_gen; - - int f_lasti; /* Last instruction if called */ - /* Call PyFrame_GetLineNumber() instead of reading this field - directly. As of 2.3 f_lineno is only valid when tracing is - active (i.e. when f_trace is set). At other times we use - PyCode_Addr2Line to calculate the line from the current - bytecode index. */ - int f_lineno; /* Current line number */ - int f_iblock; /* index in f_blockstack */ - char f_executing; /* whether the frame is still executing */ - PyTryBlock f_blockstack[CO_MAXBLOCKS]; /* for try and loop blocks */ - PyObject *f_localsplus[1]; /* locals+stack, dynamically sized */ -}; - - -/* Standard object interface */ - -PyAPI_DATA(PyTypeObject) PyFrame_Type; - -#define PyFrame_Check(op) Py_IS_TYPE(op, &PyFrame_Type) - -PyAPI_FUNC(PyFrameObject *) PyFrame_New(PyThreadState *, PyCodeObject *, - PyObject *, PyObject *); - -/* only internal use */ -PyFrameObject* _PyFrame_New_NoTrack(PyThreadState *, PyCodeObject *, - PyObject *, PyObject *); - - -/* The rest of the interface is specific for frame objects */ - -/* Block management functions */ - -PyAPI_FUNC(void) PyFrame_BlockSetup(PyFrameObject *, int, int, int); -PyAPI_FUNC(PyTryBlock *) PyFrame_BlockPop(PyFrameObject *); - -/* Conversions between "fast locals" and locals in dictionary */ - -PyAPI_FUNC(void) PyFrame_LocalsToFast(PyFrameObject *, int); - -PyAPI_FUNC(int) PyFrame_FastToLocalsWithError(PyFrameObject *f); -PyAPI_FUNC(void) PyFrame_FastToLocals(PyFrameObject *); - -PyAPI_FUNC(void) _PyFrame_DebugMallocStats(FILE *out); - -PyAPI_FUNC(PyFrameObject *) PyFrame_GetBack(PyFrameObject *frame); - -#ifdef __cplusplus -} -#endif diff --git a/scripts/build-windows/py39-libs/include/cpython/import.h b/scripts/build-windows/py39-libs/include/cpython/import.h deleted file mode 100644 index c1b47121f..000000000 --- a/scripts/build-windows/py39-libs/include/cpython/import.h +++ /dev/null @@ -1,50 +0,0 @@ -#ifndef Py_CPYTHON_IMPORT_H -# error "this header file must not be included directly" -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -PyMODINIT_FUNC PyInit__imp(void); - -PyAPI_FUNC(int) _PyImport_IsInitialized(PyInterpreterState *); - -PyAPI_FUNC(PyObject *) _PyImport_GetModuleId(struct _Py_Identifier *name); -PyAPI_FUNC(int) _PyImport_SetModule(PyObject *name, PyObject *module); -PyAPI_FUNC(int) _PyImport_SetModuleString(const char *name, PyObject* module); - -PyAPI_FUNC(void) _PyImport_AcquireLock(void); -PyAPI_FUNC(int) _PyImport_ReleaseLock(void); - -PyAPI_FUNC(PyObject *) _PyImport_FindExtensionObject(PyObject *, PyObject *); - -PyAPI_FUNC(int) _PyImport_FixupBuiltin( - PyObject *mod, - const char *name, /* UTF-8 encoded string */ - PyObject *modules - ); -PyAPI_FUNC(int) _PyImport_FixupExtensionObject(PyObject*, PyObject *, - PyObject *, PyObject *); - -struct _inittab { - const char *name; /* ASCII encoded string */ - PyObject* (*initfunc)(void); -}; -PyAPI_DATA(struct _inittab *) PyImport_Inittab; -PyAPI_FUNC(int) PyImport_ExtendInittab(struct _inittab *newtab); - -struct _frozen { - const char *name; /* ASCII encoded string */ - const unsigned char *code; - int size; -}; - -/* Embedding apps may change this pointer to point to their favorite - collection of frozen modules: */ - -PyAPI_DATA(const struct _frozen *) PyImport_FrozenModules; - -#ifdef __cplusplus -} -#endif diff --git a/scripts/build-windows/py39-libs/include/cpython/initconfig.h b/scripts/build-windows/py39-libs/include/cpython/initconfig.h deleted file mode 100644 index 0a256d4b5..000000000 --- a/scripts/build-windows/py39-libs/include/cpython/initconfig.h +++ /dev/null @@ -1,462 +0,0 @@ -#ifndef Py_PYCORECONFIG_H -#define Py_PYCORECONFIG_H -#ifndef Py_LIMITED_API -#ifdef __cplusplus -extern "C" { -#endif - -/* --- PyStatus ----------------------------------------------- */ - -typedef struct { - enum { - _PyStatus_TYPE_OK=0, - _PyStatus_TYPE_ERROR=1, - _PyStatus_TYPE_EXIT=2 - } _type; - const char *func; - const char *err_msg; - int exitcode; -} PyStatus; - -PyAPI_FUNC(PyStatus) PyStatus_Ok(void); -PyAPI_FUNC(PyStatus) PyStatus_Error(const char *err_msg); -PyAPI_FUNC(PyStatus) PyStatus_NoMemory(void); -PyAPI_FUNC(PyStatus) PyStatus_Exit(int exitcode); -PyAPI_FUNC(int) PyStatus_IsError(PyStatus err); -PyAPI_FUNC(int) PyStatus_IsExit(PyStatus err); -PyAPI_FUNC(int) PyStatus_Exception(PyStatus err); - -/* --- PyWideStringList ------------------------------------------------ */ - -typedef struct { - /* If length is greater than zero, items must be non-NULL - and all items strings must be non-NULL */ - Py_ssize_t length; - wchar_t **items; -} PyWideStringList; - -PyAPI_FUNC(PyStatus) PyWideStringList_Append(PyWideStringList *list, - const wchar_t *item); -PyAPI_FUNC(PyStatus) PyWideStringList_Insert(PyWideStringList *list, - Py_ssize_t index, - const wchar_t *item); - - -/* --- PyPreConfig ----------------------------------------------- */ - -typedef struct { - int _config_init; /* _PyConfigInitEnum value */ - - /* Parse Py_PreInitializeFromBytesArgs() arguments? - See PyConfig.parse_argv */ - int parse_argv; - - /* If greater than 0, enable isolated mode: sys.path contains - neither the script's directory nor the user's site-packages directory. - - Set to 1 by the -I command line option. If set to -1 (default), inherit - Py_IsolatedFlag value. */ - int isolated; - - /* If greater than 0: use environment variables. - Set to 0 by -E command line option. If set to -1 (default), it is - set to !Py_IgnoreEnvironmentFlag. */ - int use_environment; - - /* Set the LC_CTYPE locale to the user preferred locale? If equals to 0, - set coerce_c_locale and coerce_c_locale_warn to 0. */ - int configure_locale; - - /* Coerce the LC_CTYPE locale if it's equal to "C"? (PEP 538) - - Set to 0 by PYTHONCOERCECLOCALE=0. Set to 1 by PYTHONCOERCECLOCALE=1. - Set to 2 if the user preferred LC_CTYPE locale is "C". - - If it is equal to 1, LC_CTYPE locale is read to decide if it should be - coerced or not (ex: PYTHONCOERCECLOCALE=1). Internally, it is set to 2 - if the LC_CTYPE locale must be coerced. - - Disable by default (set to 0). Set it to -1 to let Python decide if it - should be enabled or not. */ - int coerce_c_locale; - - /* Emit a warning if the LC_CTYPE locale is coerced? - - Set to 1 by PYTHONCOERCECLOCALE=warn. - - Disable by default (set to 0). Set it to -1 to let Python decide if it - should be enabled or not. */ - int coerce_c_locale_warn; - -#ifdef MS_WINDOWS - /* If greater than 1, use the "mbcs" encoding instead of the UTF-8 - encoding for the filesystem encoding. - - Set to 1 if the PYTHONLEGACYWINDOWSFSENCODING environment variable is - set to a non-empty string. If set to -1 (default), inherit - Py_LegacyWindowsFSEncodingFlag value. - - See PEP 529 for more details. */ - int legacy_windows_fs_encoding; -#endif - - /* Enable UTF-8 mode? (PEP 540) - - Disabled by default (equals to 0). - - Set to 1 by "-X utf8" and "-X utf8=1" command line options. - Set to 1 by PYTHONUTF8=1 environment variable. - - Set to 0 by "-X utf8=0" and PYTHONUTF8=0. - - If equals to -1, it is set to 1 if the LC_CTYPE locale is "C" or - "POSIX", otherwise it is set to 0. Inherit Py_UTF8Mode value value. */ - int utf8_mode; - - /* If non-zero, enable the Python Development Mode. - - Set to 1 by the -X dev command line option. Set by the PYTHONDEVMODE - environment variable. */ - int dev_mode; - - /* Memory allocator: PYTHONMALLOC env var. - See PyMemAllocatorName for valid values. */ - int allocator; -} PyPreConfig; - -PyAPI_FUNC(void) PyPreConfig_InitPythonConfig(PyPreConfig *config); -PyAPI_FUNC(void) PyPreConfig_InitIsolatedConfig(PyPreConfig *config); - - -/* --- PyConfig ---------------------------------------------- */ - -typedef struct { - int _config_init; /* _PyConfigInitEnum value */ - - int isolated; /* Isolated mode? see PyPreConfig.isolated */ - int use_environment; /* Use environment variables? see PyPreConfig.use_environment */ - int dev_mode; /* Python Development Mode? See PyPreConfig.dev_mode */ - - /* Install signal handlers? Yes by default. */ - int install_signal_handlers; - - int use_hash_seed; /* PYTHONHASHSEED=x */ - unsigned long hash_seed; - - /* Enable faulthandler? - Set to 1 by -X faulthandler and PYTHONFAULTHANDLER. -1 means unset. */ - int faulthandler; - - /* Enable PEG parser? - 1 by default, set to 0 by -X oldparser and PYTHONOLDPARSER */ - int _use_peg_parser; - - /* Enable tracemalloc? - Set by -X tracemalloc=N and PYTHONTRACEMALLOC. -1 means unset */ - int tracemalloc; - - int import_time; /* PYTHONPROFILEIMPORTTIME, -X importtime */ - int show_ref_count; /* -X showrefcount */ - int dump_refs; /* PYTHONDUMPREFS */ - int malloc_stats; /* PYTHONMALLOCSTATS */ - - /* Python filesystem encoding and error handler: - sys.getfilesystemencoding() and sys.getfilesystemencodeerrors(). - - Default encoding and error handler: - - * if Py_SetStandardStreamEncoding() has been called: they have the - highest priority; - * PYTHONIOENCODING environment variable; - * The UTF-8 Mode uses UTF-8/surrogateescape; - * If Python forces the usage of the ASCII encoding (ex: C locale - or POSIX locale on FreeBSD or HP-UX), use ASCII/surrogateescape; - * locale encoding: ANSI code page on Windows, UTF-8 on Android and - VxWorks, LC_CTYPE locale encoding on other platforms; - * On Windows, "surrogateescape" error handler; - * "surrogateescape" error handler if the LC_CTYPE locale is "C" or "POSIX"; - * "surrogateescape" error handler if the LC_CTYPE locale has been coerced - (PEP 538); - * "strict" error handler. - - Supported error handlers: "strict", "surrogateescape" and - "surrogatepass". The surrogatepass error handler is only supported - if Py_DecodeLocale() and Py_EncodeLocale() use directly the UTF-8 codec; - it's only used on Windows. - - initfsencoding() updates the encoding to the Python codec name. - For example, "ANSI_X3.4-1968" is replaced with "ascii". - - On Windows, sys._enablelegacywindowsfsencoding() sets the - encoding/errors to mbcs/replace at runtime. - - - See Py_FileSystemDefaultEncoding and Py_FileSystemDefaultEncodeErrors. - */ - wchar_t *filesystem_encoding; - wchar_t *filesystem_errors; - - wchar_t *pycache_prefix; /* PYTHONPYCACHEPREFIX, -X pycache_prefix=PATH */ - int parse_argv; /* Parse argv command line arguments? */ - - /* Command line arguments (sys.argv). - - Set parse_argv to 1 to parse argv as Python command line arguments - and then strip Python arguments from argv. - - If argv is empty, an empty string is added to ensure that sys.argv - always exists and is never empty. */ - PyWideStringList argv; - - /* Program name: - - - If Py_SetProgramName() was called, use its value. - - On macOS, use PYTHONEXECUTABLE environment variable if set. - - If WITH_NEXT_FRAMEWORK macro is defined, use __PYVENV_LAUNCHER__ - environment variable is set. - - Use argv[0] if available and non-empty. - - Use "python" on Windows, or "python3 on other platforms. */ - wchar_t *program_name; - - PyWideStringList xoptions; /* Command line -X options */ - - /* Warnings options: lowest to highest priority. warnings.filters - is built in the reverse order (highest to lowest priority). */ - PyWideStringList warnoptions; - - /* If equal to zero, disable the import of the module site and the - site-dependent manipulations of sys.path that it entails. Also disable - these manipulations if site is explicitly imported later (call - site.main() if you want them to be triggered). - - Set to 0 by the -S command line option. If set to -1 (default), it is - set to !Py_NoSiteFlag. */ - int site_import; - - /* Bytes warnings: - - * If equal to 1, issue a warning when comparing bytes or bytearray with - str or bytes with int. - * If equal or greater to 2, issue an error. - - Incremented by the -b command line option. If set to -1 (default), inherit - Py_BytesWarningFlag value. */ - int bytes_warning; - - /* If greater than 0, enable inspect: when a script is passed as first - argument or the -c option is used, enter interactive mode after - executing the script or the command, even when sys.stdin does not appear - to be a terminal. - - Incremented by the -i command line option. Set to 1 if the PYTHONINSPECT - environment variable is non-empty. If set to -1 (default), inherit - Py_InspectFlag value. */ - int inspect; - - /* If greater than 0: enable the interactive mode (REPL). - - Incremented by the -i command line option. If set to -1 (default), - inherit Py_InteractiveFlag value. */ - int interactive; - - /* Optimization level. - - Incremented by the -O command line option. Set by the PYTHONOPTIMIZE - environment variable. If set to -1 (default), inherit Py_OptimizeFlag - value. */ - int optimization_level; - - /* If greater than 0, enable the debug mode: turn on parser debugging - output (for expert only, depending on compilation options). - - Incremented by the -d command line option. Set by the PYTHONDEBUG - environment variable. If set to -1 (default), inherit Py_DebugFlag - value. */ - int parser_debug; - - /* If equal to 0, Python won't try to write ``.pyc`` files on the - import of source modules. - - Set to 0 by the -B command line option and the PYTHONDONTWRITEBYTECODE - environment variable. If set to -1 (default), it is set to - !Py_DontWriteBytecodeFlag. */ - int write_bytecode; - - /* If greater than 0, enable the verbose mode: print a message each time a - module is initialized, showing the place (filename or built-in module) - from which it is loaded. - - If greater or equal to 2, print a message for each file that is checked - for when searching for a module. Also provides information on module - cleanup at exit. - - Incremented by the -v option. Set by the PYTHONVERBOSE environment - variable. If set to -1 (default), inherit Py_VerboseFlag value. */ - int verbose; - - /* If greater than 0, enable the quiet mode: Don't display the copyright - and version messages even in interactive mode. - - Incremented by the -q option. If set to -1 (default), inherit - Py_QuietFlag value. */ - int quiet; - - /* If greater than 0, don't add the user site-packages directory to - sys.path. - - Set to 0 by the -s and -I command line options , and the PYTHONNOUSERSITE - environment variable. If set to -1 (default), it is set to - !Py_NoUserSiteDirectory. */ - int user_site_directory; - - /* If non-zero, configure C standard steams (stdio, stdout, - stderr): - - - Set O_BINARY mode on Windows. - - If buffered_stdio is equal to zero, make streams unbuffered. - Otherwise, enable streams buffering if interactive is non-zero. */ - int configure_c_stdio; - - /* If equal to 0, enable unbuffered mode: force the stdout and stderr - streams to be unbuffered. - - Set to 0 by the -u option. Set by the PYTHONUNBUFFERED environment - variable. - If set to -1 (default), it is set to !Py_UnbufferedStdioFlag. */ - int buffered_stdio; - - /* Encoding of sys.stdin, sys.stdout and sys.stderr. - Value set from PYTHONIOENCODING environment variable and - Py_SetStandardStreamEncoding() function. - See also 'stdio_errors' attribute. */ - wchar_t *stdio_encoding; - - /* Error handler of sys.stdin and sys.stdout. - Value set from PYTHONIOENCODING environment variable and - Py_SetStandardStreamEncoding() function. - See also 'stdio_encoding' attribute. */ - wchar_t *stdio_errors; - -#ifdef MS_WINDOWS - /* If greater than zero, use io.FileIO instead of WindowsConsoleIO for sys - standard streams. - - Set to 1 if the PYTHONLEGACYWINDOWSSTDIO environment variable is set to - a non-empty string. If set to -1 (default), inherit - Py_LegacyWindowsStdioFlag value. - - See PEP 528 for more details. */ - int legacy_windows_stdio; -#endif - - /* Value of the --check-hash-based-pycs command line option: - - - "default" means the 'check_source' flag in hash-based pycs - determines invalidation - - "always" causes the interpreter to hash the source file for - invalidation regardless of value of 'check_source' bit - - "never" causes the interpreter to always assume hash-based pycs are - valid - - The default value is "default". - - See PEP 552 "Deterministic pycs" for more details. */ - wchar_t *check_hash_pycs_mode; - - /* --- Path configuration inputs ------------ */ - - /* If greater than 0, suppress _PyPathConfig_Calculate() warnings on Unix. - The parameter has no effect on Windows. - - If set to -1 (default), inherit !Py_FrozenFlag value. */ - int pathconfig_warnings; - - wchar_t *pythonpath_env; /* PYTHONPATH environment variable */ - wchar_t *home; /* PYTHONHOME environment variable, - see also Py_SetPythonHome(). */ - - /* --- Path configuration outputs ----------- */ - - int module_search_paths_set; /* If non-zero, use module_search_paths */ - PyWideStringList module_search_paths; /* sys.path paths. Computed if - module_search_paths_set is equal - to zero. */ - - wchar_t *executable; /* sys.executable */ - wchar_t *base_executable; /* sys._base_executable */ - wchar_t *prefix; /* sys.prefix */ - wchar_t *base_prefix; /* sys.base_prefix */ - wchar_t *exec_prefix; /* sys.exec_prefix */ - wchar_t *base_exec_prefix; /* sys.base_exec_prefix */ - wchar_t *platlibdir; /* sys.platlibdir */ - - /* --- Parameter only used by Py_Main() ---------- */ - - /* Skip the first line of the source ('run_filename' parameter), allowing use of non-Unix forms of - "#!cmd". This is intended for a DOS specific hack only. - - Set by the -x command line option. */ - int skip_source_first_line; - - wchar_t *run_command; /* -c command line argument */ - wchar_t *run_module; /* -m command line argument */ - wchar_t *run_filename; /* Trailing command line argument without -c or -m */ - - /* --- Private fields ---------------------------- */ - - /* Install importlib? If set to 0, importlib is not initialized at all. - Needed by freeze_importlib. */ - int _install_importlib; - - /* If equal to 0, stop Python initialization before the "main" phase */ - int _init_main; - - /* If non-zero, disallow threads, subprocesses, and fork. - Default: 0. */ - int _isolated_interpreter; - - /* Original command line arguments. If _orig_argv is empty and _argv is - not equal to [''], PyConfig_Read() copies the configuration 'argv' list - into '_orig_argv' list before modifying 'argv' list (if parse_argv - is non-zero). - - _PyConfig_Write() initializes Py_GetArgcArgv() to this list. */ - PyWideStringList _orig_argv; -} PyConfig; - -PyAPI_FUNC(void) PyConfig_InitPythonConfig(PyConfig *config); -PyAPI_FUNC(void) PyConfig_InitIsolatedConfig(PyConfig *config); -PyAPI_FUNC(void) PyConfig_Clear(PyConfig *); -PyAPI_FUNC(PyStatus) PyConfig_SetString( - PyConfig *config, - wchar_t **config_str, - const wchar_t *str); -PyAPI_FUNC(PyStatus) PyConfig_SetBytesString( - PyConfig *config, - wchar_t **config_str, - const char *str); -PyAPI_FUNC(PyStatus) PyConfig_Read(PyConfig *config); -PyAPI_FUNC(PyStatus) PyConfig_SetBytesArgv( - PyConfig *config, - Py_ssize_t argc, - char * const *argv); -PyAPI_FUNC(PyStatus) PyConfig_SetArgv(PyConfig *config, - Py_ssize_t argc, - wchar_t * const *argv); -PyAPI_FUNC(PyStatus) PyConfig_SetWideStringList(PyConfig *config, - PyWideStringList *list, - Py_ssize_t length, wchar_t **items); - - -/* --- Helper functions --------------------------------------- */ - -/* Get the original command line arguments, before Python modified them. - - See also PyConfig._orig_argv. */ -PyAPI_FUNC(void) Py_GetArgcArgv(int *argc, wchar_t ***argv); - -#ifdef __cplusplus -} -#endif -#endif /* !Py_LIMITED_API */ -#endif /* !Py_PYCORECONFIG_H */ diff --git a/scripts/build-windows/py39-libs/include/cpython/interpreteridobject.h b/scripts/build-windows/py39-libs/include/cpython/interpreteridobject.h deleted file mode 100644 index 67ec58735..000000000 --- a/scripts/build-windows/py39-libs/include/cpython/interpreteridobject.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef Py_CPYTHON_INTERPRETERIDOBJECT_H -# error "this header file must not be included directly" -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -/* Interpreter ID Object */ - -PyAPI_DATA(PyTypeObject) _PyInterpreterID_Type; - -PyAPI_FUNC(PyObject *) _PyInterpreterID_New(int64_t); -PyAPI_FUNC(PyObject *) _PyInterpreterState_GetIDObject(PyInterpreterState *); -PyAPI_FUNC(PyInterpreterState *) _PyInterpreterID_LookUp(PyObject *); - -#ifdef __cplusplus -} -#endif diff --git a/scripts/build-windows/py39-libs/include/cpython/listobject.h b/scripts/build-windows/py39-libs/include/cpython/listobject.h deleted file mode 100644 index 74fe3301a..000000000 --- a/scripts/build-windows/py39-libs/include/cpython/listobject.h +++ /dev/null @@ -1,43 +0,0 @@ -#ifndef Py_CPYTHON_LISTOBJECT_H -# error "this header file must not be included directly" -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct { - PyObject_VAR_HEAD - /* Vector of pointers to list elements. list[0] is ob_item[0], etc. */ - PyObject **ob_item; - - /* ob_item contains space for 'allocated' elements. The number - * currently in use is ob_size. - * Invariants: - * 0 <= ob_size <= allocated - * len(list) == ob_size - * ob_item == NULL implies ob_size == allocated == 0 - * list.sort() temporarily sets allocated to -1 to detect mutations. - * - * Items must normally not be NULL, except during construction when - * the list is not yet visible outside the function that builds it. - */ - Py_ssize_t allocated; -} PyListObject; - -PyAPI_FUNC(PyObject *) _PyList_Extend(PyListObject *, PyObject *); -PyAPI_FUNC(void) _PyList_DebugMallocStats(FILE *out); - -/* Macro, trading safety for speed */ - -/* Cast argument to PyTupleObject* type. */ -#define _PyList_CAST(op) (assert(PyList_Check(op)), (PyListObject *)(op)) - -#define PyList_GET_ITEM(op, i) (_PyList_CAST(op)->ob_item[i]) -#define PyList_SET_ITEM(op, i, v) (_PyList_CAST(op)->ob_item[i] = (v)) -#define PyList_GET_SIZE(op) Py_SIZE(_PyList_CAST(op)) -#define _PyList_ITEMS(op) (_PyList_CAST(op)->ob_item) - -#ifdef __cplusplus -} -#endif diff --git a/scripts/build-windows/py39-libs/include/cpython/methodobject.h b/scripts/build-windows/py39-libs/include/cpython/methodobject.h deleted file mode 100644 index 7ecbfe3b5..000000000 --- a/scripts/build-windows/py39-libs/include/cpython/methodobject.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef Py_CPYTHON_METHODOBJECT_H -# error "this header file must not be included directly" -#endif - -PyAPI_DATA(PyTypeObject) PyCMethod_Type; - -#define PyCMethod_CheckExact(op) Py_IS_TYPE(op, &PyCMethod_Type) -#define PyCMethod_Check(op) PyObject_TypeCheck(op, &PyCMethod_Type) - -/* Macros for direct access to these values. Type checks are *not* - done, so use with care. */ -#define PyCFunction_GET_FUNCTION(func) \ - (((PyCFunctionObject *)func) -> m_ml -> ml_meth) -#define PyCFunction_GET_SELF(func) \ - (((PyCFunctionObject *)func) -> m_ml -> ml_flags & METH_STATIC ? \ - NULL : ((PyCFunctionObject *)func) -> m_self) -#define PyCFunction_GET_FLAGS(func) \ - (((PyCFunctionObject *)func) -> m_ml -> ml_flags) -#define PyCFunction_GET_CLASS(func) \ - (((PyCFunctionObject *)func) -> m_ml -> ml_flags & METH_METHOD ? \ - ((PyCMethodObject *)func) -> mm_class : NULL) - -typedef struct { - PyObject_HEAD - PyMethodDef *m_ml; /* Description of the C function to call */ - PyObject *m_self; /* Passed as 'self' arg to the C func, can be NULL */ - PyObject *m_module; /* The __module__ attribute, can be anything */ - PyObject *m_weakreflist; /* List of weak references */ - vectorcallfunc vectorcall; -} PyCFunctionObject; - -typedef struct { - PyCFunctionObject func; - PyTypeObject *mm_class; /* Class that defines this method */ -} PyCMethodObject; diff --git a/scripts/build-windows/py39-libs/include/cpython/object.h b/scripts/build-windows/py39-libs/include/cpython/object.h deleted file mode 100644 index 444f832f5..000000000 --- a/scripts/build-windows/py39-libs/include/cpython/object.h +++ /dev/null @@ -1,554 +0,0 @@ -#ifndef Py_CPYTHON_OBJECT_H -# error "this header file must not be included directly" -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -PyAPI_FUNC(void) _Py_NewReference(PyObject *op); - -#ifdef Py_TRACE_REFS -/* Py_TRACE_REFS is such major surgery that we call external routines. */ -PyAPI_FUNC(void) _Py_ForgetReference(PyObject *); -#endif - -/* Update the Python traceback of an object. This function must be called - when a memory block is reused from a free list. */ -PyAPI_FUNC(int) _PyTraceMalloc_NewReference(PyObject *op); - -#ifdef Py_REF_DEBUG -PyAPI_FUNC(Py_ssize_t) _Py_GetRefTotal(void); -#endif - - -/********************* String Literals ****************************************/ -/* This structure helps managing static strings. The basic usage goes like this: - Instead of doing - - r = PyObject_CallMethod(o, "foo", "args", ...); - - do - - _Py_IDENTIFIER(foo); - ... - r = _PyObject_CallMethodId(o, &PyId_foo, "args", ...); - - PyId_foo is a static variable, either on block level or file level. On first - usage, the string "foo" is interned, and the structures are linked. On interpreter - shutdown, all strings are released. - - Alternatively, _Py_static_string allows choosing the variable name. - _PyUnicode_FromId returns a borrowed reference to the interned string. - _PyObject_{Get,Set,Has}AttrId are __getattr__ versions using _Py_Identifier*. -*/ -typedef struct _Py_Identifier { - struct _Py_Identifier *next; - const char* string; - PyObject *object; -} _Py_Identifier; - -#define _Py_static_string_init(value) { .next = NULL, .string = value, .object = NULL } -#define _Py_static_string(varname, value) static _Py_Identifier varname = _Py_static_string_init(value) -#define _Py_IDENTIFIER(varname) _Py_static_string(PyId_##varname, #varname) - -/* buffer interface */ -typedef struct bufferinfo { - void *buf; - PyObject *obj; /* owned reference */ - Py_ssize_t len; - Py_ssize_t itemsize; /* This is Py_ssize_t so it can be - pointed to by strides in simple case.*/ - int readonly; - int ndim; - char *format; - Py_ssize_t *shape; - Py_ssize_t *strides; - Py_ssize_t *suboffsets; - void *internal; -} Py_buffer; - -typedef int (*getbufferproc)(PyObject *, Py_buffer *, int); -typedef void (*releasebufferproc)(PyObject *, Py_buffer *); - -typedef PyObject *(*vectorcallfunc)(PyObject *callable, PyObject *const *args, - size_t nargsf, PyObject *kwnames); - -/* Maximum number of dimensions */ -#define PyBUF_MAX_NDIM 64 - -/* Flags for getting buffers */ -#define PyBUF_SIMPLE 0 -#define PyBUF_WRITABLE 0x0001 -/* we used to include an E, backwards compatible alias */ -#define PyBUF_WRITEABLE PyBUF_WRITABLE -#define PyBUF_FORMAT 0x0004 -#define PyBUF_ND 0x0008 -#define PyBUF_STRIDES (0x0010 | PyBUF_ND) -#define PyBUF_C_CONTIGUOUS (0x0020 | PyBUF_STRIDES) -#define PyBUF_F_CONTIGUOUS (0x0040 | PyBUF_STRIDES) -#define PyBUF_ANY_CONTIGUOUS (0x0080 | PyBUF_STRIDES) -#define PyBUF_INDIRECT (0x0100 | PyBUF_STRIDES) - -#define PyBUF_CONTIG (PyBUF_ND | PyBUF_WRITABLE) -#define PyBUF_CONTIG_RO (PyBUF_ND) - -#define PyBUF_STRIDED (PyBUF_STRIDES | PyBUF_WRITABLE) -#define PyBUF_STRIDED_RO (PyBUF_STRIDES) - -#define PyBUF_RECORDS (PyBUF_STRIDES | PyBUF_WRITABLE | PyBUF_FORMAT) -#define PyBUF_RECORDS_RO (PyBUF_STRIDES | PyBUF_FORMAT) - -#define PyBUF_FULL (PyBUF_INDIRECT | PyBUF_WRITABLE | PyBUF_FORMAT) -#define PyBUF_FULL_RO (PyBUF_INDIRECT | PyBUF_FORMAT) - - -#define PyBUF_READ 0x100 -#define PyBUF_WRITE 0x200 -/* End buffer interface */ - - -typedef struct { - /* Number implementations must check *both* - arguments for proper type and implement the necessary conversions - in the slot functions themselves. */ - - binaryfunc nb_add; - binaryfunc nb_subtract; - binaryfunc nb_multiply; - binaryfunc nb_remainder; - binaryfunc nb_divmod; - ternaryfunc nb_power; - unaryfunc nb_negative; - unaryfunc nb_positive; - unaryfunc nb_absolute; - inquiry nb_bool; - unaryfunc nb_invert; - binaryfunc nb_lshift; - binaryfunc nb_rshift; - binaryfunc nb_and; - binaryfunc nb_xor; - binaryfunc nb_or; - unaryfunc nb_int; - void *nb_reserved; /* the slot formerly known as nb_long */ - unaryfunc nb_float; - - binaryfunc nb_inplace_add; - binaryfunc nb_inplace_subtract; - binaryfunc nb_inplace_multiply; - binaryfunc nb_inplace_remainder; - ternaryfunc nb_inplace_power; - binaryfunc nb_inplace_lshift; - binaryfunc nb_inplace_rshift; - binaryfunc nb_inplace_and; - binaryfunc nb_inplace_xor; - binaryfunc nb_inplace_or; - - binaryfunc nb_floor_divide; - binaryfunc nb_true_divide; - binaryfunc nb_inplace_floor_divide; - binaryfunc nb_inplace_true_divide; - - unaryfunc nb_index; - - binaryfunc nb_matrix_multiply; - binaryfunc nb_inplace_matrix_multiply; -} PyNumberMethods; - -typedef struct { - lenfunc sq_length; - binaryfunc sq_concat; - ssizeargfunc sq_repeat; - ssizeargfunc sq_item; - void *was_sq_slice; - ssizeobjargproc sq_ass_item; - void *was_sq_ass_slice; - objobjproc sq_contains; - - binaryfunc sq_inplace_concat; - ssizeargfunc sq_inplace_repeat; -} PySequenceMethods; - -typedef struct { - lenfunc mp_length; - binaryfunc mp_subscript; - objobjargproc mp_ass_subscript; -} PyMappingMethods; - -typedef struct { - unaryfunc am_await; - unaryfunc am_aiter; - unaryfunc am_anext; -} PyAsyncMethods; - -typedef struct { - getbufferproc bf_getbuffer; - releasebufferproc bf_releasebuffer; -} PyBufferProcs; - -/* Allow printfunc in the tp_vectorcall_offset slot for - * backwards-compatibility */ -typedef Py_ssize_t printfunc; - -struct _typeobject { - PyObject_VAR_HEAD - const char *tp_name; /* For printing, in format "." */ - Py_ssize_t tp_basicsize, tp_itemsize; /* For allocation */ - - /* Methods to implement standard operations */ - - destructor tp_dealloc; - Py_ssize_t tp_vectorcall_offset; - getattrfunc tp_getattr; - setattrfunc tp_setattr; - PyAsyncMethods *tp_as_async; /* formerly known as tp_compare (Python 2) - or tp_reserved (Python 3) */ - reprfunc tp_repr; - - /* Method suites for standard classes */ - - PyNumberMethods *tp_as_number; - PySequenceMethods *tp_as_sequence; - PyMappingMethods *tp_as_mapping; - - /* More standard operations (here for binary compatibility) */ - - hashfunc tp_hash; - ternaryfunc tp_call; - reprfunc tp_str; - getattrofunc tp_getattro; - setattrofunc tp_setattro; - - /* Functions to access object as input/output buffer */ - PyBufferProcs *tp_as_buffer; - - /* Flags to define presence of optional/expanded features */ - unsigned long tp_flags; - - const char *tp_doc; /* Documentation string */ - - /* Assigned meaning in release 2.0 */ - /* call function for all accessible objects */ - traverseproc tp_traverse; - - /* delete references to contained objects */ - inquiry tp_clear; - - /* Assigned meaning in release 2.1 */ - /* rich comparisons */ - richcmpfunc tp_richcompare; - - /* weak reference enabler */ - Py_ssize_t tp_weaklistoffset; - - /* Iterators */ - getiterfunc tp_iter; - iternextfunc tp_iternext; - - /* Attribute descriptor and subclassing stuff */ - struct PyMethodDef *tp_methods; - struct PyMemberDef *tp_members; - struct PyGetSetDef *tp_getset; - struct _typeobject *tp_base; - PyObject *tp_dict; - descrgetfunc tp_descr_get; - descrsetfunc tp_descr_set; - Py_ssize_t tp_dictoffset; - initproc tp_init; - allocfunc tp_alloc; - newfunc tp_new; - freefunc tp_free; /* Low-level free-memory routine */ - inquiry tp_is_gc; /* For PyObject_IS_GC */ - PyObject *tp_bases; - PyObject *tp_mro; /* method resolution order */ - PyObject *tp_cache; - PyObject *tp_subclasses; - PyObject *tp_weaklist; - destructor tp_del; - - /* Type attribute cache version tag. Added in version 2.6 */ - unsigned int tp_version_tag; - - destructor tp_finalize; - vectorcallfunc tp_vectorcall; -}; - -/* The *real* layout of a type object when allocated on the heap */ -typedef struct _heaptypeobject { - /* Note: there's a dependency on the order of these members - in slotptr() in typeobject.c . */ - PyTypeObject ht_type; - PyAsyncMethods as_async; - PyNumberMethods as_number; - PyMappingMethods as_mapping; - PySequenceMethods as_sequence; /* as_sequence comes after as_mapping, - so that the mapping wins when both - the mapping and the sequence define - a given operator (e.g. __getitem__). - see add_operators() in typeobject.c . */ - PyBufferProcs as_buffer; - PyObject *ht_name, *ht_slots, *ht_qualname; - struct _dictkeysobject *ht_cached_keys; - PyObject *ht_module; - /* here are optional user slots, followed by the members. */ -} PyHeapTypeObject; - -/* access macro to the members which are floating "behind" the object */ -#define PyHeapType_GET_MEMBERS(etype) \ - ((PyMemberDef *)(((char *)etype) + Py_TYPE(etype)->tp_basicsize)) - -PyAPI_FUNC(const char *) _PyType_Name(PyTypeObject *); -PyAPI_FUNC(PyObject *) _PyType_Lookup(PyTypeObject *, PyObject *); -PyAPI_FUNC(PyObject *) _PyType_LookupId(PyTypeObject *, _Py_Identifier *); -PyAPI_FUNC(PyObject *) _PyObject_LookupSpecial(PyObject *, _Py_Identifier *); -PyAPI_FUNC(PyTypeObject *) _PyType_CalculateMetaclass(PyTypeObject *, PyObject *); -PyAPI_FUNC(PyObject *) _PyType_GetDocFromInternalDoc(const char *, const char *); -PyAPI_FUNC(PyObject *) _PyType_GetTextSignatureFromInternalDoc(const char *, const char *); - -struct _Py_Identifier; -PyAPI_FUNC(int) PyObject_Print(PyObject *, FILE *, int); -PyAPI_FUNC(void) _Py_BreakPoint(void); -PyAPI_FUNC(void) _PyObject_Dump(PyObject *); -PyAPI_FUNC(int) _PyObject_IsFreed(PyObject *); - -PyAPI_FUNC(int) _PyObject_IsAbstract(PyObject *); -PyAPI_FUNC(PyObject *) _PyObject_GetAttrId(PyObject *, struct _Py_Identifier *); -PyAPI_FUNC(int) _PyObject_SetAttrId(PyObject *, struct _Py_Identifier *, PyObject *); -PyAPI_FUNC(int) _PyObject_HasAttrId(PyObject *, struct _Py_Identifier *); -/* Replacements of PyObject_GetAttr() and _PyObject_GetAttrId() which - don't raise AttributeError. - - Return 1 and set *result != NULL if an attribute is found. - Return 0 and set *result == NULL if an attribute is not found; - an AttributeError is silenced. - Return -1 and set *result == NULL if an error other than AttributeError - is raised. -*/ -PyAPI_FUNC(int) _PyObject_LookupAttr(PyObject *, PyObject *, PyObject **); -PyAPI_FUNC(int) _PyObject_LookupAttrId(PyObject *, struct _Py_Identifier *, PyObject **); - -PyAPI_FUNC(int) _PyObject_GetMethod(PyObject *obj, PyObject *name, PyObject **method); - -PyAPI_FUNC(PyObject **) _PyObject_GetDictPtr(PyObject *); -PyAPI_FUNC(PyObject *) _PyObject_NextNotImplemented(PyObject *); -PyAPI_FUNC(void) PyObject_CallFinalizer(PyObject *); -PyAPI_FUNC(int) PyObject_CallFinalizerFromDealloc(PyObject *); - -/* Same as PyObject_Generic{Get,Set}Attr, but passing the attributes - dict as the last parameter. */ -PyAPI_FUNC(PyObject *) -_PyObject_GenericGetAttrWithDict(PyObject *, PyObject *, PyObject *, int); -PyAPI_FUNC(int) -_PyObject_GenericSetAttrWithDict(PyObject *, PyObject *, - PyObject *, PyObject *); - -PyAPI_FUNC(PyObject *) _PyObject_FunctionStr(PyObject *); - -/* Safely decref `op` and set `op` to `op2`. - * - * As in case of Py_CLEAR "the obvious" code can be deadly: - * - * Py_DECREF(op); - * op = op2; - * - * The safe way is: - * - * Py_SETREF(op, op2); - * - * That arranges to set `op` to `op2` _before_ decref'ing, so that any code - * triggered as a side-effect of `op` getting torn down no longer believes - * `op` points to a valid object. - * - * Py_XSETREF is a variant of Py_SETREF that uses Py_XDECREF instead of - * Py_DECREF. - */ - -#define Py_SETREF(op, op2) \ - do { \ - PyObject *_py_tmp = _PyObject_CAST(op); \ - (op) = (op2); \ - Py_DECREF(_py_tmp); \ - } while (0) - -#define Py_XSETREF(op, op2) \ - do { \ - PyObject *_py_tmp = _PyObject_CAST(op); \ - (op) = (op2); \ - Py_XDECREF(_py_tmp); \ - } while (0) - - -PyAPI_DATA(PyTypeObject) _PyNone_Type; -PyAPI_DATA(PyTypeObject) _PyNotImplemented_Type; - -/* Maps Py_LT to Py_GT, ..., Py_GE to Py_LE. - * Defined in object.c. - */ -PyAPI_DATA(int) _Py_SwappedOp[]; - -PyAPI_FUNC(void) -_PyDebugAllocatorStats(FILE *out, const char *block_name, int num_blocks, - size_t sizeof_block); -PyAPI_FUNC(void) -_PyObject_DebugTypeStats(FILE *out); - -/* Define a pair of assertion macros: - _PyObject_ASSERT_FROM(), _PyObject_ASSERT_WITH_MSG() and _PyObject_ASSERT(). - - These work like the regular C assert(), in that they will abort the - process with a message on stderr if the given condition fails to hold, - but compile away to nothing if NDEBUG is defined. - - However, before aborting, Python will also try to call _PyObject_Dump() on - the given object. This may be of use when investigating bugs in which a - particular object is corrupt (e.g. buggy a tp_visit method in an extension - module breaking the garbage collector), to help locate the broken objects. - - The WITH_MSG variant allows you to supply an additional message that Python - will attempt to print to stderr, after the object dump. */ -#ifdef NDEBUG - /* No debugging: compile away the assertions: */ -# define _PyObject_ASSERT_FROM(obj, expr, msg, filename, lineno, func) \ - ((void)0) -#else - /* With debugging: generate checks: */ -# define _PyObject_ASSERT_FROM(obj, expr, msg, filename, lineno, func) \ - ((expr) \ - ? (void)(0) \ - : _PyObject_AssertFailed((obj), Py_STRINGIFY(expr), \ - (msg), (filename), (lineno), (func))) -#endif - -#define _PyObject_ASSERT_WITH_MSG(obj, expr, msg) \ - _PyObject_ASSERT_FROM(obj, expr, msg, __FILE__, __LINE__, __func__) -#define _PyObject_ASSERT(obj, expr) \ - _PyObject_ASSERT_WITH_MSG(obj, expr, NULL) - -#define _PyObject_ASSERT_FAILED_MSG(obj, msg) \ - _PyObject_AssertFailed((obj), NULL, (msg), __FILE__, __LINE__, __func__) - -/* Declare and define _PyObject_AssertFailed() even when NDEBUG is defined, - to avoid causing compiler/linker errors when building extensions without - NDEBUG against a Python built with NDEBUG defined. - - msg, expr and function can be NULL. */ -PyAPI_FUNC(void) _Py_NO_RETURN _PyObject_AssertFailed( - PyObject *obj, - const char *expr, - const char *msg, - const char *file, - int line, - const char *function); - -/* Check if an object is consistent. For example, ensure that the reference - counter is greater than or equal to 1, and ensure that ob_type is not NULL. - - Call _PyObject_AssertFailed() if the object is inconsistent. - - If check_content is zero, only check header fields: reduce the overhead. - - The function always return 1. The return value is just here to be able to - write: - - assert(_PyObject_CheckConsistency(obj, 1)); */ -PyAPI_FUNC(int) _PyObject_CheckConsistency( - PyObject *op, - int check_content); - - -/* Trashcan mechanism, thanks to Christian Tismer. - -When deallocating a container object, it's possible to trigger an unbounded -chain of deallocations, as each Py_DECREF in turn drops the refcount on "the -next" object in the chain to 0. This can easily lead to stack overflows, -especially in threads (which typically have less stack space to work with). - -A container object can avoid this by bracketing the body of its tp_dealloc -function with a pair of macros: - -static void -mytype_dealloc(mytype *p) -{ - ... declarations go here ... - - PyObject_GC_UnTrack(p); // must untrack first - Py_TRASHCAN_BEGIN(p, mytype_dealloc) - ... The body of the deallocator goes here, including all calls ... - ... to Py_DECREF on contained objects. ... - Py_TRASHCAN_END // there should be no code after this -} - -CAUTION: Never return from the middle of the body! If the body needs to -"get out early", put a label immediately before the Py_TRASHCAN_END -call, and goto it. Else the call-depth counter (see below) will stay -above 0 forever, and the trashcan will never get emptied. - -How it works: The BEGIN macro increments a call-depth counter. So long -as this counter is small, the body of the deallocator is run directly without -further ado. But if the counter gets large, it instead adds p to a list of -objects to be deallocated later, skips the body of the deallocator, and -resumes execution after the END macro. The tp_dealloc routine then returns -without deallocating anything (and so unbounded call-stack depth is avoided). - -When the call stack finishes unwinding again, code generated by the END macro -notices this, and calls another routine to deallocate all the objects that -may have been added to the list of deferred deallocations. In effect, a -chain of N deallocations is broken into (N-1)/(PyTrash_UNWIND_LEVEL-1) pieces, -with the call stack never exceeding a depth of PyTrash_UNWIND_LEVEL. - -Since the tp_dealloc of a subclass typically calls the tp_dealloc of the base -class, we need to ensure that the trashcan is only triggered on the tp_dealloc -of the actual class being deallocated. Otherwise we might end up with a -partially-deallocated object. To check this, the tp_dealloc function must be -passed as second argument to Py_TRASHCAN_BEGIN(). -*/ - -/* This is the old private API, invoked by the macros before 3.2.4. - Kept for binary compatibility of extensions using the stable ABI. */ -PyAPI_FUNC(void) _PyTrash_deposit_object(PyObject*); -PyAPI_FUNC(void) _PyTrash_destroy_chain(void); - -/* This is the old private API, invoked by the macros before 3.9. - Kept for binary compatibility of extensions using the stable ABI. */ -PyAPI_FUNC(void) _PyTrash_thread_deposit_object(PyObject*); -PyAPI_FUNC(void) _PyTrash_thread_destroy_chain(void); - -/* Forward declarations for PyThreadState */ -struct _ts; - -/* Python 3.9 private API, invoked by the macros below. */ -PyAPI_FUNC(int) _PyTrash_begin(struct _ts *tstate, PyObject *op); -PyAPI_FUNC(void) _PyTrash_end(struct _ts *tstate); - -#define PyTrash_UNWIND_LEVEL 50 - -#define Py_TRASHCAN_BEGIN_CONDITION(op, cond) \ - do { \ - PyThreadState *_tstate = NULL; \ - /* If "cond" is false, then _tstate remains NULL and the deallocator \ - * is run normally without involving the trashcan */ \ - if (cond) { \ - _tstate = PyThreadState_GET(); \ - if (_PyTrash_begin(_tstate, _PyObject_CAST(op))) { \ - break; \ - } \ - } - /* The body of the deallocator is here. */ -#define Py_TRASHCAN_END \ - if (_tstate) { \ - _PyTrash_end(_tstate); \ - } \ - } while (0); - -#define Py_TRASHCAN_BEGIN(op, dealloc) \ - Py_TRASHCAN_BEGIN_CONDITION(op, \ - Py_TYPE(op)->tp_dealloc == (destructor)(dealloc)) - -/* For backwards compatibility, these macros enable the trashcan - * unconditionally */ -#define Py_TRASHCAN_SAFE_BEGIN(op) Py_TRASHCAN_BEGIN_CONDITION(op, 1) -#define Py_TRASHCAN_SAFE_END(op) Py_TRASHCAN_END - -#ifdef __cplusplus -} -#endif diff --git a/scripts/build-windows/py39-libs/include/cpython/objimpl.h b/scripts/build-windows/py39-libs/include/cpython/objimpl.h deleted file mode 100644 index b835936db..000000000 --- a/scripts/build-windows/py39-libs/include/cpython/objimpl.h +++ /dev/null @@ -1,145 +0,0 @@ -#ifndef Py_CPYTHON_OBJIMPL_H -# error "this header file must not be included directly" -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -#define _PyObject_SIZE(typeobj) ( (typeobj)->tp_basicsize ) - -/* _PyObject_VAR_SIZE returns the number of bytes (as size_t) allocated for a - vrbl-size object with nitems items, exclusive of gc overhead (if any). The - value is rounded up to the closest multiple of sizeof(void *), in order to - ensure that pointer fields at the end of the object are correctly aligned - for the platform (this is of special importance for subclasses of, e.g., - str or int, so that pointers can be stored after the embedded data). - - Note that there's no memory wastage in doing this, as malloc has to - return (at worst) pointer-aligned memory anyway. -*/ -#if ((SIZEOF_VOID_P - 1) & SIZEOF_VOID_P) != 0 -# error "_PyObject_VAR_SIZE requires SIZEOF_VOID_P be a power of 2" -#endif - -#define _PyObject_VAR_SIZE(typeobj, nitems) \ - _Py_SIZE_ROUND_UP((typeobj)->tp_basicsize + \ - (nitems)*(typeobj)->tp_itemsize, \ - SIZEOF_VOID_P) - - -/* This example code implements an object constructor with a custom - allocator, where PyObject_New is inlined, and shows the important - distinction between two steps (at least): - 1) the actual allocation of the object storage; - 2) the initialization of the Python specific fields - in this storage with PyObject_{Init, InitVar}. - - PyObject * - YourObject_New(...) - { - PyObject *op; - - op = (PyObject *) Your_Allocator(_PyObject_SIZE(YourTypeStruct)); - if (op == NULL) - return PyErr_NoMemory(); - - PyObject_Init(op, &YourTypeStruct); - - op->ob_field = value; - ... - return op; - } - - Note that in C++, the use of the new operator usually implies that - the 1st step is performed automatically for you, so in a C++ class - constructor you would start directly with PyObject_Init/InitVar. */ - - -/* Inline functions trading binary compatibility for speed: - PyObject_INIT() is the fast version of PyObject_Init(), and - PyObject_INIT_VAR() is the fast version of PyObject_InitVar(). - - These inline functions must not be called with op=NULL. */ -static inline PyObject* -_PyObject_INIT(PyObject *op, PyTypeObject *typeobj) -{ - assert(op != NULL); - Py_SET_TYPE(op, typeobj); - if (PyType_GetFlags(typeobj) & Py_TPFLAGS_HEAPTYPE) { - Py_INCREF(typeobj); - } - _Py_NewReference(op); - return op; -} - -#define PyObject_INIT(op, typeobj) \ - _PyObject_INIT(_PyObject_CAST(op), (typeobj)) - -static inline PyVarObject* -_PyObject_INIT_VAR(PyVarObject *op, PyTypeObject *typeobj, Py_ssize_t size) -{ - assert(op != NULL); - Py_SET_SIZE(op, size); - PyObject_INIT((PyObject *)op, typeobj); - return op; -} - -#define PyObject_INIT_VAR(op, typeobj, size) \ - _PyObject_INIT_VAR(_PyVarObject_CAST(op), (typeobj), (size)) - - -/* This function returns the number of allocated memory blocks, regardless of size */ -PyAPI_FUNC(Py_ssize_t) _Py_GetAllocatedBlocks(void); - -/* Macros */ -#ifdef WITH_PYMALLOC -PyAPI_FUNC(int) _PyObject_DebugMallocStats(FILE *out); -#endif - - -typedef struct { - /* user context passed as the first argument to the 2 functions */ - void *ctx; - - /* allocate an arena of size bytes */ - void* (*alloc) (void *ctx, size_t size); - - /* free an arena */ - void (*free) (void *ctx, void *ptr, size_t size); -} PyObjectArenaAllocator; - -/* Get the arena allocator. */ -PyAPI_FUNC(void) PyObject_GetArenaAllocator(PyObjectArenaAllocator *allocator); - -/* Set the arena allocator. */ -PyAPI_FUNC(void) PyObject_SetArenaAllocator(PyObjectArenaAllocator *allocator); - - -PyAPI_FUNC(Py_ssize_t) _PyGC_CollectNoFail(void); -PyAPI_FUNC(Py_ssize_t) _PyGC_CollectIfEnabled(void); - - -/* Test if an object implements the garbage collector protocol */ -PyAPI_FUNC(int) PyObject_IS_GC(PyObject *obj); - - -/* Code built with Py_BUILD_CORE must include pycore_gc.h instead which - defines a different _PyGC_FINALIZED() macro. */ -#ifndef Py_BUILD_CORE - // Kept for backward compatibility with Python 3.8 -# define _PyGC_FINALIZED(o) PyObject_GC_IsFinalized(o) -#endif - -PyAPI_FUNC(PyObject *) _PyObject_GC_Malloc(size_t size); -PyAPI_FUNC(PyObject *) _PyObject_GC_Calloc(size_t size); - - -/* Test if a type supports weak references */ -#define PyType_SUPPORTS_WEAKREFS(t) ((t)->tp_weaklistoffset > 0) - -PyAPI_FUNC(PyObject **) PyObject_GET_WEAKREFS_LISTPTR(PyObject *op); - -#ifdef __cplusplus -} -#endif diff --git a/scripts/build-windows/py39-libs/include/cpython/pyerrors.h b/scripts/build-windows/py39-libs/include/cpython/pyerrors.h deleted file mode 100644 index 9c87b5397..000000000 --- a/scripts/build-windows/py39-libs/include/cpython/pyerrors.h +++ /dev/null @@ -1,200 +0,0 @@ -#ifndef Py_CPYTHON_ERRORS_H -# error "this header file must not be included directly" -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -/* Error objects */ - -/* PyException_HEAD defines the initial segment of every exception class. */ -#define PyException_HEAD PyObject_HEAD PyObject *dict;\ - PyObject *args; PyObject *traceback;\ - PyObject *context; PyObject *cause;\ - char suppress_context; - -typedef struct { - PyException_HEAD -} PyBaseExceptionObject; - -typedef struct { - PyException_HEAD - PyObject *msg; - PyObject *filename; - PyObject *lineno; - PyObject *offset; - PyObject *text; - PyObject *print_file_and_line; -} PySyntaxErrorObject; - -typedef struct { - PyException_HEAD - PyObject *msg; - PyObject *name; - PyObject *path; -} PyImportErrorObject; - -typedef struct { - PyException_HEAD - PyObject *encoding; - PyObject *object; - Py_ssize_t start; - Py_ssize_t end; - PyObject *reason; -} PyUnicodeErrorObject; - -typedef struct { - PyException_HEAD - PyObject *code; -} PySystemExitObject; - -typedef struct { - PyException_HEAD - PyObject *myerrno; - PyObject *strerror; - PyObject *filename; - PyObject *filename2; -#ifdef MS_WINDOWS - PyObject *winerror; -#endif - Py_ssize_t written; /* only for BlockingIOError, -1 otherwise */ -} PyOSErrorObject; - -typedef struct { - PyException_HEAD - PyObject *value; -} PyStopIterationObject; - -/* Compatibility typedefs */ -typedef PyOSErrorObject PyEnvironmentErrorObject; -#ifdef MS_WINDOWS -typedef PyOSErrorObject PyWindowsErrorObject; -#endif - -/* Error handling definitions */ - -PyAPI_FUNC(void) _PyErr_SetKeyError(PyObject *); -PyAPI_FUNC(_PyErr_StackItem*) _PyErr_GetTopmostException(PyThreadState *tstate); -PyAPI_FUNC(void) _PyErr_GetExcInfo(PyThreadState *, PyObject **, PyObject **, PyObject **); - -/* Context manipulation (PEP 3134) */ - -PyAPI_FUNC(void) _PyErr_ChainExceptions(PyObject *, PyObject *, PyObject *); - -/* */ - -#define PyExceptionClass_Name(x) (((PyTypeObject*)(x))->tp_name) - -/* Convenience functions */ - -#ifdef MS_WINDOWS -Py_DEPRECATED(3.3) -PyAPI_FUNC(PyObject *) PyErr_SetFromErrnoWithUnicodeFilename( - PyObject *, const Py_UNICODE *); -#endif /* MS_WINDOWS */ - -/* Like PyErr_Format(), but saves current exception as __context__ and - __cause__. - */ -PyAPI_FUNC(PyObject *) _PyErr_FormatFromCause( - PyObject *exception, - const char *format, /* ASCII-encoded string */ - ... - ); - -#ifdef MS_WINDOWS -/* XXX redeclare to use WSTRING */ -Py_DEPRECATED(3.3) -PyAPI_FUNC(PyObject *) PyErr_SetFromWindowsErrWithUnicodeFilename( - int, const Py_UNICODE *); -Py_DEPRECATED(3.3) -PyAPI_FUNC(PyObject *) PyErr_SetExcFromWindowsErrWithUnicodeFilename( - PyObject *,int, const Py_UNICODE *); -#endif - -/* In exceptions.c */ - -/* Helper that attempts to replace the current exception with one of the - * same type but with a prefix added to the exception text. The resulting - * exception description looks like: - * - * prefix (exc_type: original_exc_str) - * - * Only some exceptions can be safely replaced. If the function determines - * it isn't safe to perform the replacement, it will leave the original - * unmodified exception in place. - * - * Returns a borrowed reference to the new exception (if any), NULL if the - * existing exception was left in place. - */ -PyAPI_FUNC(PyObject *) _PyErr_TrySetFromCause( - const char *prefix_format, /* ASCII-encoded string */ - ... - ); - -/* In signalmodule.c */ - -int PySignal_SetWakeupFd(int fd); -PyAPI_FUNC(int) _PyErr_CheckSignals(void); - -/* Support for adding program text to SyntaxErrors */ - -PyAPI_FUNC(void) PyErr_SyntaxLocationObject( - PyObject *filename, - int lineno, - int col_offset); - -PyAPI_FUNC(PyObject *) PyErr_ProgramTextObject( - PyObject *filename, - int lineno); - -/* Create a UnicodeEncodeError object. - * - * TODO: This API will be removed in Python 3.11. - */ -Py_DEPRECATED(3.3) PyAPI_FUNC(PyObject *) PyUnicodeEncodeError_Create( - const char *encoding, /* UTF-8 encoded string */ - const Py_UNICODE *object, - Py_ssize_t length, - Py_ssize_t start, - Py_ssize_t end, - const char *reason /* UTF-8 encoded string */ - ); - -/* Create a UnicodeTranslateError object. - * - * TODO: This API will be removed in Python 3.11. - */ -Py_DEPRECATED(3.3) PyAPI_FUNC(PyObject *) PyUnicodeTranslateError_Create( - const Py_UNICODE *object, - Py_ssize_t length, - Py_ssize_t start, - Py_ssize_t end, - const char *reason /* UTF-8 encoded string */ - ); -PyAPI_FUNC(PyObject *) _PyUnicodeTranslateError_Create( - PyObject *object, - Py_ssize_t start, - Py_ssize_t end, - const char *reason /* UTF-8 encoded string */ - ); - -PyAPI_FUNC(void) _PyErr_WriteUnraisableMsg( - const char *err_msg, - PyObject *obj); - -PyAPI_FUNC(void) _Py_NO_RETURN _Py_FatalErrorFunc( - const char *func, - const char *message); - -PyAPI_FUNC(void) _Py_NO_RETURN _Py_FatalErrorFormat( - const char *func, - const char *format, - ...); - -#define Py_FatalError(message) _Py_FatalErrorFunc(__func__, message) - -#ifdef __cplusplus -} -#endif diff --git a/scripts/build-windows/py39-libs/include/cpython/pylifecycle.h b/scripts/build-windows/py39-libs/include/cpython/pylifecycle.h deleted file mode 100644 index eb523b82e..000000000 --- a/scripts/build-windows/py39-libs/include/cpython/pylifecycle.h +++ /dev/null @@ -1,72 +0,0 @@ -#ifndef Py_CPYTHON_PYLIFECYCLE_H -# error "this header file must not be included directly" -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -/* Only used by applications that embed the interpreter and need to - * override the standard encoding determination mechanism - */ -PyAPI_FUNC(int) Py_SetStandardStreamEncoding(const char *encoding, - const char *errors); - -/* PEP 432 Multi-phase initialization API (Private while provisional!) */ - -PyAPI_FUNC(PyStatus) Py_PreInitialize( - const PyPreConfig *src_config); -PyAPI_FUNC(PyStatus) Py_PreInitializeFromBytesArgs( - const PyPreConfig *src_config, - Py_ssize_t argc, - char **argv); -PyAPI_FUNC(PyStatus) Py_PreInitializeFromArgs( - const PyPreConfig *src_config, - Py_ssize_t argc, - wchar_t **argv); - -PyAPI_FUNC(int) _Py_IsCoreInitialized(void); - - -/* Initialization and finalization */ - -PyAPI_FUNC(PyStatus) Py_InitializeFromConfig( - const PyConfig *config); -PyAPI_FUNC(PyStatus) _Py_InitializeMain(void); - -PyAPI_FUNC(int) Py_RunMain(void); - - -PyAPI_FUNC(void) _Py_NO_RETURN Py_ExitStatusException(PyStatus err); - -/* Py_PyAtExit is for the atexit module, Py_AtExit is for low-level - * exit functions. - */ -PyAPI_FUNC(void) _Py_PyAtExit(void (*func)(PyObject *), PyObject *); - -/* Restore signals that the interpreter has called SIG_IGN on to SIG_DFL. */ -PyAPI_FUNC(void) _Py_RestoreSignals(void); - -PyAPI_FUNC(int) Py_FdIsInteractive(FILE *, const char *); - -PyAPI_FUNC(void) _Py_SetProgramFullPath(const wchar_t *); - -PyAPI_FUNC(const char *) _Py_gitidentifier(void); -PyAPI_FUNC(const char *) _Py_gitversion(void); - -PyAPI_FUNC(int) _Py_IsFinalizing(void); - -/* Random */ -PyAPI_FUNC(int) _PyOS_URandom(void *buffer, Py_ssize_t size); -PyAPI_FUNC(int) _PyOS_URandomNonblock(void *buffer, Py_ssize_t size); - -/* Legacy locale support */ -PyAPI_FUNC(int) _Py_CoerceLegacyLocale(int warn); -PyAPI_FUNC(int) _Py_LegacyLocaleDetected(int warn); -PyAPI_FUNC(char *) _Py_SetLocaleFromEnv(int category); - -PyAPI_FUNC(PyThreadState *) _Py_NewInterpreter(int isolated_subinterpreter); - -#ifdef __cplusplus -} -#endif diff --git a/scripts/build-windows/py39-libs/include/cpython/pymem.h b/scripts/build-windows/py39-libs/include/cpython/pymem.h deleted file mode 100644 index 79f063b12..000000000 --- a/scripts/build-windows/py39-libs/include/cpython/pymem.h +++ /dev/null @@ -1,108 +0,0 @@ -#ifndef Py_CPYTHON_PYMEM_H -# error "this header file must not be included directly" -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -PyAPI_FUNC(void *) PyMem_RawMalloc(size_t size); -PyAPI_FUNC(void *) PyMem_RawCalloc(size_t nelem, size_t elsize); -PyAPI_FUNC(void *) PyMem_RawRealloc(void *ptr, size_t new_size); -PyAPI_FUNC(void) PyMem_RawFree(void *ptr); - -/* Try to get the allocators name set by _PyMem_SetupAllocators(). */ -PyAPI_FUNC(const char*) _PyMem_GetCurrentAllocatorName(void); - -PyAPI_FUNC(void *) PyMem_Calloc(size_t nelem, size_t elsize); - -/* strdup() using PyMem_RawMalloc() */ -PyAPI_FUNC(char *) _PyMem_RawStrdup(const char *str); - -/* strdup() using PyMem_Malloc() */ -PyAPI_FUNC(char *) _PyMem_Strdup(const char *str); - -/* wcsdup() using PyMem_RawMalloc() */ -PyAPI_FUNC(wchar_t*) _PyMem_RawWcsdup(const wchar_t *str); - - -typedef enum { - /* PyMem_RawMalloc(), PyMem_RawRealloc() and PyMem_RawFree() */ - PYMEM_DOMAIN_RAW, - - /* PyMem_Malloc(), PyMem_Realloc() and PyMem_Free() */ - PYMEM_DOMAIN_MEM, - - /* PyObject_Malloc(), PyObject_Realloc() and PyObject_Free() */ - PYMEM_DOMAIN_OBJ -} PyMemAllocatorDomain; - -typedef enum { - PYMEM_ALLOCATOR_NOT_SET = 0, - PYMEM_ALLOCATOR_DEFAULT = 1, - PYMEM_ALLOCATOR_DEBUG = 2, - PYMEM_ALLOCATOR_MALLOC = 3, - PYMEM_ALLOCATOR_MALLOC_DEBUG = 4, -#ifdef WITH_PYMALLOC - PYMEM_ALLOCATOR_PYMALLOC = 5, - PYMEM_ALLOCATOR_PYMALLOC_DEBUG = 6, -#endif -} PyMemAllocatorName; - - -typedef struct { - /* user context passed as the first argument to the 4 functions */ - void *ctx; - - /* allocate a memory block */ - void* (*malloc) (void *ctx, size_t size); - - /* allocate a memory block initialized by zeros */ - void* (*calloc) (void *ctx, size_t nelem, size_t elsize); - - /* allocate or resize a memory block */ - void* (*realloc) (void *ctx, void *ptr, size_t new_size); - - /* release a memory block */ - void (*free) (void *ctx, void *ptr); -} PyMemAllocatorEx; - -/* Get the memory block allocator of the specified domain. */ -PyAPI_FUNC(void) PyMem_GetAllocator(PyMemAllocatorDomain domain, - PyMemAllocatorEx *allocator); - -/* Set the memory block allocator of the specified domain. - - The new allocator must return a distinct non-NULL pointer when requesting - zero bytes. - - For the PYMEM_DOMAIN_RAW domain, the allocator must be thread-safe: the GIL - is not held when the allocator is called. - - If the new allocator is not a hook (don't call the previous allocator), the - PyMem_SetupDebugHooks() function must be called to reinstall the debug hooks - on top on the new allocator. */ -PyAPI_FUNC(void) PyMem_SetAllocator(PyMemAllocatorDomain domain, - PyMemAllocatorEx *allocator); - -/* Setup hooks to detect bugs in the following Python memory allocator - functions: - - - PyMem_RawMalloc(), PyMem_RawRealloc(), PyMem_RawFree() - - PyMem_Malloc(), PyMem_Realloc(), PyMem_Free() - - PyObject_Malloc(), PyObject_Realloc() and PyObject_Free() - - Newly allocated memory is filled with the byte 0xCB, freed memory is filled - with the byte 0xDB. Additional checks: - - - detect API violations, ex: PyObject_Free() called on a buffer allocated - by PyMem_Malloc() - - detect write before the start of the buffer (buffer underflow) - - detect write after the end of the buffer (buffer overflow) - - The function does nothing if Python is not compiled is debug mode. */ -PyAPI_FUNC(void) PyMem_SetupDebugHooks(void); - -#ifdef __cplusplus -} -#endif diff --git a/scripts/build-windows/py39-libs/include/cpython/pystate.h b/scripts/build-windows/py39-libs/include/cpython/pystate.h deleted file mode 100644 index f292da1d3..000000000 --- a/scripts/build-windows/py39-libs/include/cpython/pystate.h +++ /dev/null @@ -1,263 +0,0 @@ -#ifndef Py_CPYTHON_PYSTATE_H -# error "this header file must not be included directly" -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -#include "cpython/initconfig.h" - -PyAPI_FUNC(int) _PyInterpreterState_RequiresIDRef(PyInterpreterState *); -PyAPI_FUNC(void) _PyInterpreterState_RequireIDRef(PyInterpreterState *, int); - -PyAPI_FUNC(PyObject *) _PyInterpreterState_GetMainModule(PyInterpreterState *); - -/* State unique per thread */ - -/* Py_tracefunc return -1 when raising an exception, or 0 for success. */ -typedef int (*Py_tracefunc)(PyObject *, PyFrameObject *, int, PyObject *); - -/* The following values are used for 'what' for tracefunc functions - * - * To add a new kind of trace event, also update "trace_init" in - * Python/sysmodule.c to define the Python level event name - */ -#define PyTrace_CALL 0 -#define PyTrace_EXCEPTION 1 -#define PyTrace_LINE 2 -#define PyTrace_RETURN 3 -#define PyTrace_C_CALL 4 -#define PyTrace_C_EXCEPTION 5 -#define PyTrace_C_RETURN 6 -#define PyTrace_OPCODE 7 - - -typedef struct _err_stackitem { - /* This struct represents an entry on the exception stack, which is a - * per-coroutine state. (Coroutine in the computer science sense, - * including the thread and generators). - * This ensures that the exception state is not impacted by "yields" - * from an except handler. - */ - PyObject *exc_type, *exc_value, *exc_traceback; - - struct _err_stackitem *previous_item; - -} _PyErr_StackItem; - - -// The PyThreadState typedef is in Include/pystate.h. -struct _ts { - /* See Python/ceval.c for comments explaining most fields */ - - struct _ts *prev; - struct _ts *next; - PyInterpreterState *interp; - - /* Borrowed reference to the current frame (it can be NULL) */ - PyFrameObject *frame; - int recursion_depth; - char overflowed; /* The stack has overflowed. Allow 50 more calls - to handle the runtime error. */ - char recursion_critical; /* The current calls must not cause - a stack overflow. */ - int stackcheck_counter; - - /* 'tracing' keeps track of the execution depth when tracing/profiling. - This is to prevent the actual trace/profile code from being recorded in - the trace/profile. */ - int tracing; - int use_tracing; - - Py_tracefunc c_profilefunc; - Py_tracefunc c_tracefunc; - PyObject *c_profileobj; - PyObject *c_traceobj; - - /* The exception currently being raised */ - PyObject *curexc_type; - PyObject *curexc_value; - PyObject *curexc_traceback; - - /* The exception currently being handled, if no coroutines/generators - * are present. Always last element on the stack referred to be exc_info. - */ - _PyErr_StackItem exc_state; - - /* Pointer to the top of the stack of the exceptions currently - * being handled */ - _PyErr_StackItem *exc_info; - - PyObject *dict; /* Stores per-thread state */ - - int gilstate_counter; - - PyObject *async_exc; /* Asynchronous exception to raise */ - unsigned long thread_id; /* Thread id where this tstate was created */ - - int trash_delete_nesting; - PyObject *trash_delete_later; - - /* Called when a thread state is deleted normally, but not when it - * is destroyed after fork(). - * Pain: to prevent rare but fatal shutdown errors (issue 18808), - * Thread.join() must wait for the join'ed thread's tstate to be unlinked - * from the tstate chain. That happens at the end of a thread's life, - * in pystate.c. - * The obvious way doesn't quite work: create a lock which the tstate - * unlinking code releases, and have Thread.join() wait to acquire that - * lock. The problem is that we _are_ at the end of the thread's life: - * if the thread holds the last reference to the lock, decref'ing the - * lock will delete the lock, and that may trigger arbitrary Python code - * if there's a weakref, with a callback, to the lock. But by this time - * _PyRuntime.gilstate.tstate_current is already NULL, so only the simplest - * of C code can be allowed to run (in particular it must not be possible to - * release the GIL). - * So instead of holding the lock directly, the tstate holds a weakref to - * the lock: that's the value of on_delete_data below. Decref'ing a - * weakref is harmless. - * on_delete points to _threadmodule.c's static release_sentinel() function. - * After the tstate is unlinked, release_sentinel is called with the - * weakref-to-lock (on_delete_data) argument, and release_sentinel releases - * the indirectly held lock. - */ - void (*on_delete)(void *); - void *on_delete_data; - - int coroutine_origin_tracking_depth; - - PyObject *async_gen_firstiter; - PyObject *async_gen_finalizer; - - PyObject *context; - uint64_t context_ver; - - /* Unique thread state id. */ - uint64_t id; - - /* XXX signal handlers should also be here */ - -}; - -// Alias for backward compatibility with Python 3.8 -#define _PyInterpreterState_Get PyInterpreterState_Get - -PyAPI_FUNC(PyThreadState *) _PyThreadState_Prealloc(PyInterpreterState *); - -/* Similar to PyThreadState_Get(), but don't issue a fatal error - * if it is NULL. */ -PyAPI_FUNC(PyThreadState *) _PyThreadState_UncheckedGet(void); - -PyAPI_FUNC(PyObject *) _PyThreadState_GetDict(PyThreadState *tstate); - -/* PyGILState */ - -/* Helper/diagnostic function - return 1 if the current thread - currently holds the GIL, 0 otherwise. - - The function returns 1 if _PyGILState_check_enabled is non-zero. */ -PyAPI_FUNC(int) PyGILState_Check(void); - -/* Get the single PyInterpreterState used by this process' GILState - implementation. - - This function doesn't check for error. Return NULL before _PyGILState_Init() - is called and after _PyGILState_Fini() is called. - - See also _PyInterpreterState_Get() and _PyInterpreterState_GET(). */ -PyAPI_FUNC(PyInterpreterState *) _PyGILState_GetInterpreterStateUnsafe(void); - -/* The implementation of sys._current_frames() Returns a dict mapping - thread id to that thread's current frame. -*/ -PyAPI_FUNC(PyObject *) _PyThread_CurrentFrames(void); - -/* Routines for advanced debuggers, requested by David Beazley. - Don't use unless you know what you are doing! */ -PyAPI_FUNC(PyInterpreterState *) PyInterpreterState_Main(void); -PyAPI_FUNC(PyInterpreterState *) PyInterpreterState_Head(void); -PyAPI_FUNC(PyInterpreterState *) PyInterpreterState_Next(PyInterpreterState *); -PyAPI_FUNC(PyThreadState *) PyInterpreterState_ThreadHead(PyInterpreterState *); -PyAPI_FUNC(PyThreadState *) PyThreadState_Next(PyThreadState *); -PyAPI_FUNC(void) PyThreadState_DeleteCurrent(void); - -/* Frame evaluation API */ - -typedef PyObject* (*_PyFrameEvalFunction)(PyThreadState *tstate, PyFrameObject *, int); - -PyAPI_FUNC(_PyFrameEvalFunction) _PyInterpreterState_GetEvalFrameFunc( - PyInterpreterState *interp); -PyAPI_FUNC(void) _PyInterpreterState_SetEvalFrameFunc( - PyInterpreterState *interp, - _PyFrameEvalFunction eval_frame); - -PyAPI_FUNC(const PyConfig*) _PyInterpreterState_GetConfig(PyInterpreterState *interp); - -// Get the configuration of the currrent interpreter. -// The caller must hold the GIL. -PyAPI_FUNC(const PyConfig*) _Py_GetConfig(void); - - -/* cross-interpreter data */ - -struct _xid; - -// _PyCrossInterpreterData is similar to Py_buffer as an effectively -// opaque struct that holds data outside the object machinery. This -// is necessary to pass safely between interpreters in the same process. -typedef struct _xid { - // data is the cross-interpreter-safe derivation of a Python object - // (see _PyObject_GetCrossInterpreterData). It will be NULL if the - // new_object func (below) encodes the data. - void *data; - // obj is the Python object from which the data was derived. This - // is non-NULL only if the data remains bound to the object in some - // way, such that the object must be "released" (via a decref) when - // the data is released. In that case the code that sets the field, - // likely a registered "crossinterpdatafunc", is responsible for - // ensuring it owns the reference (i.e. incref). - PyObject *obj; - // interp is the ID of the owning interpreter of the original - // object. It corresponds to the active interpreter when - // _PyObject_GetCrossInterpreterData() was called. This should only - // be set by the cross-interpreter machinery. - // - // We use the ID rather than the PyInterpreterState to avoid issues - // with deleted interpreters. Note that IDs are never re-used, so - // each one will always correspond to a specific interpreter - // (whether still alive or not). - int64_t interp; - // new_object is a function that returns a new object in the current - // interpreter given the data. The resulting object (a new - // reference) will be equivalent to the original object. This field - // is required. - PyObject *(*new_object)(struct _xid *); - // free is called when the data is released. If it is NULL then - // nothing will be done to free the data. For some types this is - // okay (e.g. bytes) and for those types this field should be set - // to NULL. However, for most the data was allocated just for - // cross-interpreter use, so it must be freed when - // _PyCrossInterpreterData_Release is called or the memory will - // leak. In that case, at the very least this field should be set - // to PyMem_RawFree (the default if not explicitly set to NULL). - // The call will happen with the original interpreter activated. - void (*free)(void *); -} _PyCrossInterpreterData; - -PyAPI_FUNC(int) _PyObject_GetCrossInterpreterData(PyObject *, _PyCrossInterpreterData *); -PyAPI_FUNC(PyObject *) _PyCrossInterpreterData_NewObject(_PyCrossInterpreterData *); -PyAPI_FUNC(void) _PyCrossInterpreterData_Release(_PyCrossInterpreterData *); - -PyAPI_FUNC(int) _PyObject_CheckCrossInterpreterData(PyObject *); - -/* cross-interpreter data registry */ - -typedef int (*crossinterpdatafunc)(PyObject *, struct _xid *); - -PyAPI_FUNC(int) _PyCrossInterpreterData_RegisterClass(PyTypeObject *, crossinterpdatafunc); -PyAPI_FUNC(crossinterpdatafunc) _PyCrossInterpreterData_Lookup(PyObject *); - -#ifdef __cplusplus -} -#endif diff --git a/scripts/build-windows/py39-libs/include/cpython/sysmodule.h b/scripts/build-windows/py39-libs/include/cpython/sysmodule.h deleted file mode 100644 index 1802b5b30..000000000 --- a/scripts/build-windows/py39-libs/include/cpython/sysmodule.h +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef Py_CPYTHON_SYSMODULE_H -# error "this header file must not be included directly" -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -PyAPI_FUNC(PyObject *) _PySys_GetObjectId(_Py_Identifier *key); -PyAPI_FUNC(int) _PySys_SetObjectId(_Py_Identifier *key, PyObject *); - -PyAPI_FUNC(size_t) _PySys_GetSizeOf(PyObject *); - -typedef int(*Py_AuditHookFunction)(const char *, PyObject *, void *); - -PyAPI_FUNC(int) PySys_Audit( - const char *event, - const char *argFormat, - ...); -PyAPI_FUNC(int) PySys_AddAuditHook(Py_AuditHookFunction, void*); - -#ifdef __cplusplus -} -#endif diff --git a/scripts/build-windows/py39-libs/include/cpython/traceback.h b/scripts/build-windows/py39-libs/include/cpython/traceback.h deleted file mode 100644 index 837470c3b..000000000 --- a/scripts/build-windows/py39-libs/include/cpython/traceback.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef Py_CPYTHON_TRACEBACK_H -# error "this header file must not be included directly" -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct _traceback { - PyObject_HEAD - struct _traceback *tb_next; - PyFrameObject *tb_frame; - int tb_lasti; - int tb_lineno; -} PyTracebackObject; - -PyAPI_FUNC(int) _Py_DisplaySourceLine(PyObject *, PyObject *, int, int); -PyAPI_FUNC(void) _PyTraceback_Add(const char *, const char *, int); - -#ifdef __cplusplus -} -#endif diff --git a/scripts/build-windows/py39-libs/include/cpython/tupleobject.h b/scripts/build-windows/py39-libs/include/cpython/tupleobject.h deleted file mode 100644 index 1565f2a5c..000000000 --- a/scripts/build-windows/py39-libs/include/cpython/tupleobject.h +++ /dev/null @@ -1,36 +0,0 @@ -#ifndef Py_CPYTHON_TUPLEOBJECT_H -# error "this header file must not be included directly" -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct { - PyObject_VAR_HEAD - /* ob_item contains space for 'ob_size' elements. - Items must normally not be NULL, except during construction when - the tuple is not yet visible outside the function that builds it. */ - PyObject *ob_item[1]; -} PyTupleObject; - -PyAPI_FUNC(int) _PyTuple_Resize(PyObject **, Py_ssize_t); -PyAPI_FUNC(void) _PyTuple_MaybeUntrack(PyObject *); - -/* Macros trading safety for speed */ - -/* Cast argument to PyTupleObject* type. */ -#define _PyTuple_CAST(op) (assert(PyTuple_Check(op)), (PyTupleObject *)(op)) - -#define PyTuple_GET_SIZE(op) Py_SIZE(_PyTuple_CAST(op)) - -#define PyTuple_GET_ITEM(op, i) (_PyTuple_CAST(op)->ob_item[i]) - -/* Macro, *only* to be used to fill in brand new tuples */ -#define PyTuple_SET_ITEM(op, i, v) (_PyTuple_CAST(op)->ob_item[i] = v) - -PyAPI_FUNC(void) _PyTuple_DebugMallocStats(FILE *out); - -#ifdef __cplusplus -} -#endif diff --git a/scripts/build-windows/py39-libs/include/cpython/unicodeobject.h b/scripts/build-windows/py39-libs/include/cpython/unicodeobject.h deleted file mode 100644 index 17db79cff..000000000 --- a/scripts/build-windows/py39-libs/include/cpython/unicodeobject.h +++ /dev/null @@ -1,1221 +0,0 @@ -#ifndef Py_CPYTHON_UNICODEOBJECT_H -# error "this header file must not be included directly" -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -/* Py_UNICODE was the native Unicode storage format (code unit) used by - Python and represents a single Unicode element in the Unicode type. - With PEP 393, Py_UNICODE is deprecated and replaced with a - typedef to wchar_t. */ -#define PY_UNICODE_TYPE wchar_t -/* Py_DEPRECATED(3.3) */ typedef wchar_t Py_UNICODE; - -/* --- Internal Unicode Operations ---------------------------------------- */ - -/* Since splitting on whitespace is an important use case, and - whitespace in most situations is solely ASCII whitespace, we - optimize for the common case by using a quick look-up table - _Py_ascii_whitespace (see below) with an inlined check. - - */ -#define Py_UNICODE_ISSPACE(ch) \ - ((Py_UCS4)(ch) < 128U ? _Py_ascii_whitespace[(ch)] : _PyUnicode_IsWhitespace(ch)) - -#define Py_UNICODE_ISLOWER(ch) _PyUnicode_IsLowercase(ch) -#define Py_UNICODE_ISUPPER(ch) _PyUnicode_IsUppercase(ch) -#define Py_UNICODE_ISTITLE(ch) _PyUnicode_IsTitlecase(ch) -#define Py_UNICODE_ISLINEBREAK(ch) _PyUnicode_IsLinebreak(ch) - -#define Py_UNICODE_TOLOWER(ch) _PyUnicode_ToLowercase(ch) -#define Py_UNICODE_TOUPPER(ch) _PyUnicode_ToUppercase(ch) -#define Py_UNICODE_TOTITLE(ch) _PyUnicode_ToTitlecase(ch) - -#define Py_UNICODE_ISDECIMAL(ch) _PyUnicode_IsDecimalDigit(ch) -#define Py_UNICODE_ISDIGIT(ch) _PyUnicode_IsDigit(ch) -#define Py_UNICODE_ISNUMERIC(ch) _PyUnicode_IsNumeric(ch) -#define Py_UNICODE_ISPRINTABLE(ch) _PyUnicode_IsPrintable(ch) - -#define Py_UNICODE_TODECIMAL(ch) _PyUnicode_ToDecimalDigit(ch) -#define Py_UNICODE_TODIGIT(ch) _PyUnicode_ToDigit(ch) -#define Py_UNICODE_TONUMERIC(ch) _PyUnicode_ToNumeric(ch) - -#define Py_UNICODE_ISALPHA(ch) _PyUnicode_IsAlpha(ch) - -#define Py_UNICODE_ISALNUM(ch) \ - (Py_UNICODE_ISALPHA(ch) || \ - Py_UNICODE_ISDECIMAL(ch) || \ - Py_UNICODE_ISDIGIT(ch) || \ - Py_UNICODE_ISNUMERIC(ch)) - -Py_DEPRECATED(3.3) static inline void -Py_UNICODE_COPY(Py_UNICODE *target, const Py_UNICODE *source, Py_ssize_t length) { - memcpy(target, source, (size_t)(length) * sizeof(Py_UNICODE)); -} - -Py_DEPRECATED(3.3) static inline void -Py_UNICODE_FILL(Py_UNICODE *target, Py_UNICODE value, Py_ssize_t length) { - Py_ssize_t i; - for (i = 0; i < length; i++) { - target[i] = value; - } -} - -/* macros to work with surrogates */ -#define Py_UNICODE_IS_SURROGATE(ch) (0xD800 <= (ch) && (ch) <= 0xDFFF) -#define Py_UNICODE_IS_HIGH_SURROGATE(ch) (0xD800 <= (ch) && (ch) <= 0xDBFF) -#define Py_UNICODE_IS_LOW_SURROGATE(ch) (0xDC00 <= (ch) && (ch) <= 0xDFFF) -/* Join two surrogate characters and return a single Py_UCS4 value. */ -#define Py_UNICODE_JOIN_SURROGATES(high, low) \ - (((((Py_UCS4)(high) & 0x03FF) << 10) | \ - ((Py_UCS4)(low) & 0x03FF)) + 0x10000) -/* high surrogate = top 10 bits added to D800 */ -#define Py_UNICODE_HIGH_SURROGATE(ch) (0xD800 - (0x10000 >> 10) + ((ch) >> 10)) -/* low surrogate = bottom 10 bits added to DC00 */ -#define Py_UNICODE_LOW_SURROGATE(ch) (0xDC00 + ((ch) & 0x3FF)) - -/* --- Unicode Type ------------------------------------------------------- */ - -/* ASCII-only strings created through PyUnicode_New use the PyASCIIObject - structure. state.ascii and state.compact are set, and the data - immediately follow the structure. utf8_length and wstr_length can be found - in the length field; the utf8 pointer is equal to the data pointer. */ -typedef struct { - /* There are 4 forms of Unicode strings: - - - compact ascii: - - * structure = PyASCIIObject - * test: PyUnicode_IS_COMPACT_ASCII(op) - * kind = PyUnicode_1BYTE_KIND - * compact = 1 - * ascii = 1 - * ready = 1 - * (length is the length of the utf8 and wstr strings) - * (data starts just after the structure) - * (since ASCII is decoded from UTF-8, the utf8 string are the data) - - - compact: - - * structure = PyCompactUnicodeObject - * test: PyUnicode_IS_COMPACT(op) && !PyUnicode_IS_ASCII(op) - * kind = PyUnicode_1BYTE_KIND, PyUnicode_2BYTE_KIND or - PyUnicode_4BYTE_KIND - * compact = 1 - * ready = 1 - * ascii = 0 - * utf8 is not shared with data - * utf8_length = 0 if utf8 is NULL - * wstr is shared with data and wstr_length=length - if kind=PyUnicode_2BYTE_KIND and sizeof(wchar_t)=2 - or if kind=PyUnicode_4BYTE_KIND and sizeof(wchar_t)=4 - * wstr_length = 0 if wstr is NULL - * (data starts just after the structure) - - - legacy string, not ready: - - * structure = PyUnicodeObject - * test: kind == PyUnicode_WCHAR_KIND - * length = 0 (use wstr_length) - * hash = -1 - * kind = PyUnicode_WCHAR_KIND - * compact = 0 - * ascii = 0 - * ready = 0 - * interned = SSTATE_NOT_INTERNED - * wstr is not NULL - * data.any is NULL - * utf8 is NULL - * utf8_length = 0 - - - legacy string, ready: - - * structure = PyUnicodeObject structure - * test: !PyUnicode_IS_COMPACT(op) && kind != PyUnicode_WCHAR_KIND - * kind = PyUnicode_1BYTE_KIND, PyUnicode_2BYTE_KIND or - PyUnicode_4BYTE_KIND - * compact = 0 - * ready = 1 - * data.any is not NULL - * utf8 is shared and utf8_length = length with data.any if ascii = 1 - * utf8_length = 0 if utf8 is NULL - * wstr is shared with data.any and wstr_length = length - if kind=PyUnicode_2BYTE_KIND and sizeof(wchar_t)=2 - or if kind=PyUnicode_4BYTE_KIND and sizeof(wchar_4)=4 - * wstr_length = 0 if wstr is NULL - - Compact strings use only one memory block (structure + characters), - whereas legacy strings use one block for the structure and one block - for characters. - - Legacy strings are created by PyUnicode_FromUnicode() and - PyUnicode_FromStringAndSize(NULL, size) functions. They become ready - when PyUnicode_READY() is called. - - See also _PyUnicode_CheckConsistency(). - */ - PyObject_HEAD - Py_ssize_t length; /* Number of code points in the string */ - Py_hash_t hash; /* Hash value; -1 if not set */ - struct { - /* - SSTATE_NOT_INTERNED (0) - SSTATE_INTERNED_MORTAL (1) - SSTATE_INTERNED_IMMORTAL (2) - - If interned != SSTATE_NOT_INTERNED, the two references from the - dictionary to this object are *not* counted in ob_refcnt. - */ - unsigned int interned:2; - /* Character size: - - - PyUnicode_WCHAR_KIND (0): - - * character type = wchar_t (16 or 32 bits, depending on the - platform) - - - PyUnicode_1BYTE_KIND (1): - - * character type = Py_UCS1 (8 bits, unsigned) - * all characters are in the range U+0000-U+00FF (latin1) - * if ascii is set, all characters are in the range U+0000-U+007F - (ASCII), otherwise at least one character is in the range - U+0080-U+00FF - - - PyUnicode_2BYTE_KIND (2): - - * character type = Py_UCS2 (16 bits, unsigned) - * all characters are in the range U+0000-U+FFFF (BMP) - * at least one character is in the range U+0100-U+FFFF - - - PyUnicode_4BYTE_KIND (4): - - * character type = Py_UCS4 (32 bits, unsigned) - * all characters are in the range U+0000-U+10FFFF - * at least one character is in the range U+10000-U+10FFFF - */ - unsigned int kind:3; - /* Compact is with respect to the allocation scheme. Compact unicode - objects only require one memory block while non-compact objects use - one block for the PyUnicodeObject struct and another for its data - buffer. */ - unsigned int compact:1; - /* The string only contains characters in the range U+0000-U+007F (ASCII) - and the kind is PyUnicode_1BYTE_KIND. If ascii is set and compact is - set, use the PyASCIIObject structure. */ - unsigned int ascii:1; - /* The ready flag indicates whether the object layout is initialized - completely. This means that this is either a compact object, or - the data pointer is filled out. The bit is redundant, and helps - to minimize the test in PyUnicode_IS_READY(). */ - unsigned int ready:1; - /* Padding to ensure that PyUnicode_DATA() is always aligned to - 4 bytes (see issue #19537 on m68k). */ - unsigned int :24; - } state; - wchar_t *wstr; /* wchar_t representation (null-terminated) */ -} PyASCIIObject; - -/* Non-ASCII strings allocated through PyUnicode_New use the - PyCompactUnicodeObject structure. state.compact is set, and the data - immediately follow the structure. */ -typedef struct { - PyASCIIObject _base; - Py_ssize_t utf8_length; /* Number of bytes in utf8, excluding the - * terminating \0. */ - char *utf8; /* UTF-8 representation (null-terminated) */ - Py_ssize_t wstr_length; /* Number of code points in wstr, possible - * surrogates count as two code points. */ -} PyCompactUnicodeObject; - -/* Strings allocated through PyUnicode_FromUnicode(NULL, len) use the - PyUnicodeObject structure. The actual string data is initially in the wstr - block, and copied into the data block using _PyUnicode_Ready. */ -typedef struct { - PyCompactUnicodeObject _base; - union { - void *any; - Py_UCS1 *latin1; - Py_UCS2 *ucs2; - Py_UCS4 *ucs4; - } data; /* Canonical, smallest-form Unicode buffer */ -} PyUnicodeObject; - -PyAPI_FUNC(int) _PyUnicode_CheckConsistency( - PyObject *op, - int check_content); - -/* Fast access macros */ - -/* Returns the deprecated Py_UNICODE representation's size in code units - (this includes surrogate pairs as 2 units). - If the Py_UNICODE representation is not available, it will be computed - on request. Use PyUnicode_GET_LENGTH() for the length in code points. */ - -/* Py_DEPRECATED(3.3) */ -#define PyUnicode_GET_SIZE(op) \ - (assert(PyUnicode_Check(op)), \ - (((PyASCIIObject *)(op))->wstr) ? \ - PyUnicode_WSTR_LENGTH(op) : \ - ((void)PyUnicode_AsUnicode(_PyObject_CAST(op)),\ - assert(((PyASCIIObject *)(op))->wstr), \ - PyUnicode_WSTR_LENGTH(op))) - -/* Py_DEPRECATED(3.3) */ -#define PyUnicode_GET_DATA_SIZE(op) \ - (PyUnicode_GET_SIZE(op) * Py_UNICODE_SIZE) - -/* Alias for PyUnicode_AsUnicode(). This will create a wchar_t/Py_UNICODE - representation on demand. Using this macro is very inefficient now, - try to port your code to use the new PyUnicode_*BYTE_DATA() macros or - use PyUnicode_WRITE() and PyUnicode_READ(). */ - -/* Py_DEPRECATED(3.3) */ -#define PyUnicode_AS_UNICODE(op) \ - (assert(PyUnicode_Check(op)), \ - (((PyASCIIObject *)(op))->wstr) ? (((PyASCIIObject *)(op))->wstr) : \ - PyUnicode_AsUnicode(_PyObject_CAST(op))) - -/* Py_DEPRECATED(3.3) */ -#define PyUnicode_AS_DATA(op) \ - ((const char *)(PyUnicode_AS_UNICODE(op))) - - -/* --- Flexible String Representation Helper Macros (PEP 393) -------------- */ - -/* Values for PyASCIIObject.state: */ - -/* Interning state. */ -#define SSTATE_NOT_INTERNED 0 -#define SSTATE_INTERNED_MORTAL 1 -#define SSTATE_INTERNED_IMMORTAL 2 - -/* Return true if the string contains only ASCII characters, or 0 if not. The - string may be compact (PyUnicode_IS_COMPACT_ASCII) or not, but must be - ready. */ -#define PyUnicode_IS_ASCII(op) \ - (assert(PyUnicode_Check(op)), \ - assert(PyUnicode_IS_READY(op)), \ - ((PyASCIIObject*)op)->state.ascii) - -/* Return true if the string is compact or 0 if not. - No type checks or Ready calls are performed. */ -#define PyUnicode_IS_COMPACT(op) \ - (((PyASCIIObject*)(op))->state.compact) - -/* Return true if the string is a compact ASCII string (use PyASCIIObject - structure), or 0 if not. No type checks or Ready calls are performed. */ -#define PyUnicode_IS_COMPACT_ASCII(op) \ - (((PyASCIIObject*)op)->state.ascii && PyUnicode_IS_COMPACT(op)) - -enum PyUnicode_Kind { -/* String contains only wstr byte characters. This is only possible - when the string was created with a legacy API and _PyUnicode_Ready() - has not been called yet. */ - PyUnicode_WCHAR_KIND = 0, -/* Return values of the PyUnicode_KIND() macro: */ - PyUnicode_1BYTE_KIND = 1, - PyUnicode_2BYTE_KIND = 2, - PyUnicode_4BYTE_KIND = 4 -}; - -/* Return pointers to the canonical representation cast to unsigned char, - Py_UCS2, or Py_UCS4 for direct character access. - No checks are performed, use PyUnicode_KIND() before to ensure - these will work correctly. */ - -#define PyUnicode_1BYTE_DATA(op) ((Py_UCS1*)PyUnicode_DATA(op)) -#define PyUnicode_2BYTE_DATA(op) ((Py_UCS2*)PyUnicode_DATA(op)) -#define PyUnicode_4BYTE_DATA(op) ((Py_UCS4*)PyUnicode_DATA(op)) - -/* Return one of the PyUnicode_*_KIND values defined above. */ -#define PyUnicode_KIND(op) \ - (assert(PyUnicode_Check(op)), \ - assert(PyUnicode_IS_READY(op)), \ - ((PyASCIIObject *)(op))->state.kind) - -/* Return a void pointer to the raw unicode buffer. */ -#define _PyUnicode_COMPACT_DATA(op) \ - (PyUnicode_IS_ASCII(op) ? \ - ((void*)((PyASCIIObject*)(op) + 1)) : \ - ((void*)((PyCompactUnicodeObject*)(op) + 1))) - -#define _PyUnicode_NONCOMPACT_DATA(op) \ - (assert(((PyUnicodeObject*)(op))->data.any), \ - ((((PyUnicodeObject *)(op))->data.any))) - -#define PyUnicode_DATA(op) \ - (assert(PyUnicode_Check(op)), \ - PyUnicode_IS_COMPACT(op) ? _PyUnicode_COMPACT_DATA(op) : \ - _PyUnicode_NONCOMPACT_DATA(op)) - -/* In the access macros below, "kind" may be evaluated more than once. - All other macro parameters are evaluated exactly once, so it is safe - to put side effects into them (such as increasing the index). */ - -/* Write into the canonical representation, this macro does not do any sanity - checks and is intended for usage in loops. The caller should cache the - kind and data pointers obtained from other macro calls. - index is the index in the string (starts at 0) and value is the new - code point value which should be written to that location. */ -#define PyUnicode_WRITE(kind, data, index, value) \ - do { \ - switch ((kind)) { \ - case PyUnicode_1BYTE_KIND: { \ - ((Py_UCS1 *)(data))[(index)] = (Py_UCS1)(value); \ - break; \ - } \ - case PyUnicode_2BYTE_KIND: { \ - ((Py_UCS2 *)(data))[(index)] = (Py_UCS2)(value); \ - break; \ - } \ - default: { \ - assert((kind) == PyUnicode_4BYTE_KIND); \ - ((Py_UCS4 *)(data))[(index)] = (Py_UCS4)(value); \ - } \ - } \ - } while (0) - -/* Read a code point from the string's canonical representation. No checks - or ready calls are performed. */ -#define PyUnicode_READ(kind, data, index) \ - ((Py_UCS4) \ - ((kind) == PyUnicode_1BYTE_KIND ? \ - ((const Py_UCS1 *)(data))[(index)] : \ - ((kind) == PyUnicode_2BYTE_KIND ? \ - ((const Py_UCS2 *)(data))[(index)] : \ - ((const Py_UCS4 *)(data))[(index)] \ - ) \ - )) - -/* PyUnicode_READ_CHAR() is less efficient than PyUnicode_READ() because it - calls PyUnicode_KIND() and might call it twice. For single reads, use - PyUnicode_READ_CHAR, for multiple consecutive reads callers should - cache kind and use PyUnicode_READ instead. */ -#define PyUnicode_READ_CHAR(unicode, index) \ - (assert(PyUnicode_Check(unicode)), \ - assert(PyUnicode_IS_READY(unicode)), \ - (Py_UCS4) \ - (PyUnicode_KIND((unicode)) == PyUnicode_1BYTE_KIND ? \ - ((const Py_UCS1 *)(PyUnicode_DATA((unicode))))[(index)] : \ - (PyUnicode_KIND((unicode)) == PyUnicode_2BYTE_KIND ? \ - ((const Py_UCS2 *)(PyUnicode_DATA((unicode))))[(index)] : \ - ((const Py_UCS4 *)(PyUnicode_DATA((unicode))))[(index)] \ - ) \ - )) - -/* Returns the length of the unicode string. The caller has to make sure that - the string has it's canonical representation set before calling - this macro. Call PyUnicode_(FAST_)Ready to ensure that. */ -#define PyUnicode_GET_LENGTH(op) \ - (assert(PyUnicode_Check(op)), \ - assert(PyUnicode_IS_READY(op)), \ - ((PyASCIIObject *)(op))->length) - - -/* Fast check to determine whether an object is ready. Equivalent to - PyUnicode_IS_COMPACT(op) || ((PyUnicodeObject*)(op))->data.any) */ - -#define PyUnicode_IS_READY(op) (((PyASCIIObject*)op)->state.ready) - -/* PyUnicode_READY() does less work than _PyUnicode_Ready() in the best - case. If the canonical representation is not yet set, it will still call - _PyUnicode_Ready(). - Returns 0 on success and -1 on errors. */ -#define PyUnicode_READY(op) \ - (assert(PyUnicode_Check(op)), \ - (PyUnicode_IS_READY(op) ? \ - 0 : _PyUnicode_Ready(_PyObject_CAST(op)))) - -/* Return a maximum character value which is suitable for creating another - string based on op. This is always an approximation but more efficient - than iterating over the string. */ -#define PyUnicode_MAX_CHAR_VALUE(op) \ - (assert(PyUnicode_IS_READY(op)), \ - (PyUnicode_IS_ASCII(op) ? \ - (0x7f) : \ - (PyUnicode_KIND(op) == PyUnicode_1BYTE_KIND ? \ - (0xffU) : \ - (PyUnicode_KIND(op) == PyUnicode_2BYTE_KIND ? \ - (0xffffU) : \ - (0x10ffffU))))) - -Py_DEPRECATED(3.3) -static inline Py_ssize_t _PyUnicode_get_wstr_length(PyObject *op) { - return PyUnicode_IS_COMPACT_ASCII(op) ? - ((PyASCIIObject*)op)->length : - ((PyCompactUnicodeObject*)op)->wstr_length; -} -#define PyUnicode_WSTR_LENGTH(op) _PyUnicode_get_wstr_length((PyObject*)op) - -/* === Public API ========================================================= */ - -/* --- Plain Py_UNICODE --------------------------------------------------- */ - -/* With PEP 393, this is the recommended way to allocate a new unicode object. - This function will allocate the object and its buffer in a single memory - block. Objects created using this function are not resizable. */ -PyAPI_FUNC(PyObject*) PyUnicode_New( - Py_ssize_t size, /* Number of code points in the new string */ - Py_UCS4 maxchar /* maximum code point value in the string */ - ); - -/* Initializes the canonical string representation from the deprecated - wstr/Py_UNICODE representation. This function is used to convert Unicode - objects which were created using the old API to the new flexible format - introduced with PEP 393. - - Don't call this function directly, use the public PyUnicode_READY() macro - instead. */ -PyAPI_FUNC(int) _PyUnicode_Ready( - PyObject *unicode /* Unicode object */ - ); - -/* Get a copy of a Unicode string. */ -PyAPI_FUNC(PyObject*) _PyUnicode_Copy( - PyObject *unicode - ); - -/* Copy character from one unicode object into another, this function performs - character conversion when necessary and falls back to memcpy() if possible. - - Fail if to is too small (smaller than *how_many* or smaller than - len(from)-from_start), or if kind(from[from_start:from_start+how_many]) > - kind(to), or if *to* has more than 1 reference. - - Return the number of written character, or return -1 and raise an exception - on error. - - Pseudo-code: - - how_many = min(how_many, len(from) - from_start) - to[to_start:to_start+how_many] = from[from_start:from_start+how_many] - return how_many - - Note: The function doesn't write a terminating null character. - */ -PyAPI_FUNC(Py_ssize_t) PyUnicode_CopyCharacters( - PyObject *to, - Py_ssize_t to_start, - PyObject *from, - Py_ssize_t from_start, - Py_ssize_t how_many - ); - -/* Unsafe version of PyUnicode_CopyCharacters(): don't check arguments and so - may crash if parameters are invalid (e.g. if the output string - is too short). */ -PyAPI_FUNC(void) _PyUnicode_FastCopyCharacters( - PyObject *to, - Py_ssize_t to_start, - PyObject *from, - Py_ssize_t from_start, - Py_ssize_t how_many - ); - -/* Fill a string with a character: write fill_char into - unicode[start:start+length]. - - Fail if fill_char is bigger than the string maximum character, or if the - string has more than 1 reference. - - Return the number of written character, or return -1 and raise an exception - on error. */ -PyAPI_FUNC(Py_ssize_t) PyUnicode_Fill( - PyObject *unicode, - Py_ssize_t start, - Py_ssize_t length, - Py_UCS4 fill_char - ); - -/* Unsafe version of PyUnicode_Fill(): don't check arguments and so may crash - if parameters are invalid (e.g. if length is longer than the string). */ -PyAPI_FUNC(void) _PyUnicode_FastFill( - PyObject *unicode, - Py_ssize_t start, - Py_ssize_t length, - Py_UCS4 fill_char - ); - -/* Create a Unicode Object from the Py_UNICODE buffer u of the given - size. - - u may be NULL which causes the contents to be undefined. It is the - user's responsibility to fill in the needed data afterwards. Note - that modifying the Unicode object contents after construction is - only allowed if u was set to NULL. - - The buffer is copied into the new object. */ -Py_DEPRECATED(3.3) PyAPI_FUNC(PyObject*) PyUnicode_FromUnicode( - const Py_UNICODE *u, /* Unicode buffer */ - Py_ssize_t size /* size of buffer */ - ); - -/* Create a new string from a buffer of Py_UCS1, Py_UCS2 or Py_UCS4 characters. - Scan the string to find the maximum character. */ -PyAPI_FUNC(PyObject*) PyUnicode_FromKindAndData( - int kind, - const void *buffer, - Py_ssize_t size); - -/* Create a new string from a buffer of ASCII characters. - WARNING: Don't check if the string contains any non-ASCII character. */ -PyAPI_FUNC(PyObject*) _PyUnicode_FromASCII( - const char *buffer, - Py_ssize_t size); - -/* Compute the maximum character of the substring unicode[start:end]. - Return 127 for an empty string. */ -PyAPI_FUNC(Py_UCS4) _PyUnicode_FindMaxChar ( - PyObject *unicode, - Py_ssize_t start, - Py_ssize_t end); - -/* Return a read-only pointer to the Unicode object's internal - Py_UNICODE buffer. - If the wchar_t/Py_UNICODE representation is not yet available, this - function will calculate it. */ -Py_DEPRECATED(3.3) PyAPI_FUNC(Py_UNICODE *) PyUnicode_AsUnicode( - PyObject *unicode /* Unicode object */ - ); - -/* Similar to PyUnicode_AsUnicode(), but raises a ValueError if the string - contains null characters. */ -Py_DEPRECATED(3.3) PyAPI_FUNC(const Py_UNICODE *) _PyUnicode_AsUnicode( - PyObject *unicode /* Unicode object */ - ); - -/* Return a read-only pointer to the Unicode object's internal - Py_UNICODE buffer and save the length at size. - If the wchar_t/Py_UNICODE representation is not yet available, this - function will calculate it. */ - -Py_DEPRECATED(3.3) PyAPI_FUNC(Py_UNICODE *) PyUnicode_AsUnicodeAndSize( - PyObject *unicode, /* Unicode object */ - Py_ssize_t *size /* location where to save the length */ - ); - -/* Get the maximum ordinal for a Unicode character. */ -Py_DEPRECATED(3.3) PyAPI_FUNC(Py_UNICODE) PyUnicode_GetMax(void); - - -/* --- _PyUnicodeWriter API ----------------------------------------------- */ - -typedef struct { - PyObject *buffer; - void *data; - enum PyUnicode_Kind kind; - Py_UCS4 maxchar; - Py_ssize_t size; - Py_ssize_t pos; - - /* minimum number of allocated characters (default: 0) */ - Py_ssize_t min_length; - - /* minimum character (default: 127, ASCII) */ - Py_UCS4 min_char; - - /* If non-zero, overallocate the buffer (default: 0). */ - unsigned char overallocate; - - /* If readonly is 1, buffer is a shared string (cannot be modified) - and size is set to 0. */ - unsigned char readonly; -} _PyUnicodeWriter ; - -/* Initialize a Unicode writer. - * - * By default, the minimum buffer size is 0 character and overallocation is - * disabled. Set min_length, min_char and overallocate attributes to control - * the allocation of the buffer. */ -PyAPI_FUNC(void) -_PyUnicodeWriter_Init(_PyUnicodeWriter *writer); - -/* Prepare the buffer to write 'length' characters - with the specified maximum character. - - Return 0 on success, raise an exception and return -1 on error. */ -#define _PyUnicodeWriter_Prepare(WRITER, LENGTH, MAXCHAR) \ - (((MAXCHAR) <= (WRITER)->maxchar \ - && (LENGTH) <= (WRITER)->size - (WRITER)->pos) \ - ? 0 \ - : (((LENGTH) == 0) \ - ? 0 \ - : _PyUnicodeWriter_PrepareInternal((WRITER), (LENGTH), (MAXCHAR)))) - -/* Don't call this function directly, use the _PyUnicodeWriter_Prepare() macro - instead. */ -PyAPI_FUNC(int) -_PyUnicodeWriter_PrepareInternal(_PyUnicodeWriter *writer, - Py_ssize_t length, Py_UCS4 maxchar); - -/* Prepare the buffer to have at least the kind KIND. - For example, kind=PyUnicode_2BYTE_KIND ensures that the writer will - support characters in range U+000-U+FFFF. - - Return 0 on success, raise an exception and return -1 on error. */ -#define _PyUnicodeWriter_PrepareKind(WRITER, KIND) \ - (assert((KIND) != PyUnicode_WCHAR_KIND), \ - (KIND) <= (WRITER)->kind \ - ? 0 \ - : _PyUnicodeWriter_PrepareKindInternal((WRITER), (KIND))) - -/* Don't call this function directly, use the _PyUnicodeWriter_PrepareKind() - macro instead. */ -PyAPI_FUNC(int) -_PyUnicodeWriter_PrepareKindInternal(_PyUnicodeWriter *writer, - enum PyUnicode_Kind kind); - -/* Append a Unicode character. - Return 0 on success, raise an exception and return -1 on error. */ -PyAPI_FUNC(int) -_PyUnicodeWriter_WriteChar(_PyUnicodeWriter *writer, - Py_UCS4 ch - ); - -/* Append a Unicode string. - Return 0 on success, raise an exception and return -1 on error. */ -PyAPI_FUNC(int) -_PyUnicodeWriter_WriteStr(_PyUnicodeWriter *writer, - PyObject *str /* Unicode string */ - ); - -/* Append a substring of a Unicode string. - Return 0 on success, raise an exception and return -1 on error. */ -PyAPI_FUNC(int) -_PyUnicodeWriter_WriteSubstring(_PyUnicodeWriter *writer, - PyObject *str, /* Unicode string */ - Py_ssize_t start, - Py_ssize_t end - ); - -/* Append an ASCII-encoded byte string. - Return 0 on success, raise an exception and return -1 on error. */ -PyAPI_FUNC(int) -_PyUnicodeWriter_WriteASCIIString(_PyUnicodeWriter *writer, - const char *str, /* ASCII-encoded byte string */ - Py_ssize_t len /* number of bytes, or -1 if unknown */ - ); - -/* Append a latin1-encoded byte string. - Return 0 on success, raise an exception and return -1 on error. */ -PyAPI_FUNC(int) -_PyUnicodeWriter_WriteLatin1String(_PyUnicodeWriter *writer, - const char *str, /* latin1-encoded byte string */ - Py_ssize_t len /* length in bytes */ - ); - -/* Get the value of the writer as a Unicode string. Clear the - buffer of the writer. Raise an exception and return NULL - on error. */ -PyAPI_FUNC(PyObject *) -_PyUnicodeWriter_Finish(_PyUnicodeWriter *writer); - -/* Deallocate memory of a writer (clear its internal buffer). */ -PyAPI_FUNC(void) -_PyUnicodeWriter_Dealloc(_PyUnicodeWriter *writer); - - -/* Format the object based on the format_spec, as defined in PEP 3101 - (Advanced String Formatting). */ -PyAPI_FUNC(int) _PyUnicode_FormatAdvancedWriter( - _PyUnicodeWriter *writer, - PyObject *obj, - PyObject *format_spec, - Py_ssize_t start, - Py_ssize_t end); - -/* --- Manage the default encoding ---------------------------------------- */ - -/* Returns a pointer to the default encoding (UTF-8) of the - Unicode object unicode and the size of the encoded representation - in bytes stored in *size. - - In case of an error, no *size is set. - - This function caches the UTF-8 encoded string in the unicodeobject - and subsequent calls will return the same string. The memory is released - when the unicodeobject is deallocated. - - _PyUnicode_AsStringAndSize is a #define for PyUnicode_AsUTF8AndSize to - support the previous internal function with the same behaviour. -*/ - -PyAPI_FUNC(const char *) PyUnicode_AsUTF8AndSize( - PyObject *unicode, - Py_ssize_t *size); - -#define _PyUnicode_AsStringAndSize PyUnicode_AsUTF8AndSize - -/* Returns a pointer to the default encoding (UTF-8) of the - Unicode object unicode. - - Like PyUnicode_AsUTF8AndSize(), this also caches the UTF-8 representation - in the unicodeobject. - - _PyUnicode_AsString is a #define for PyUnicode_AsUTF8 to - support the previous internal function with the same behaviour. - - Use of this API is DEPRECATED since no size information can be - extracted from the returned data. -*/ - -PyAPI_FUNC(const char *) PyUnicode_AsUTF8(PyObject *unicode); - -#define _PyUnicode_AsString PyUnicode_AsUTF8 - -/* --- Generic Codecs ----------------------------------------------------- */ - -/* Encodes a Py_UNICODE buffer of the given size and returns a - Python string object. */ -Py_DEPRECATED(3.3) PyAPI_FUNC(PyObject*) PyUnicode_Encode( - const Py_UNICODE *s, /* Unicode char buffer */ - Py_ssize_t size, /* number of Py_UNICODE chars to encode */ - const char *encoding, /* encoding */ - const char *errors /* error handling */ - ); - -/* --- UTF-7 Codecs ------------------------------------------------------- */ - -Py_DEPRECATED(3.3) PyAPI_FUNC(PyObject*) PyUnicode_EncodeUTF7( - const Py_UNICODE *data, /* Unicode char buffer */ - Py_ssize_t length, /* number of Py_UNICODE chars to encode */ - int base64SetO, /* Encode RFC2152 Set O characters in base64 */ - int base64WhiteSpace, /* Encode whitespace (sp, ht, nl, cr) in base64 */ - const char *errors /* error handling */ - ); - -PyAPI_FUNC(PyObject*) _PyUnicode_EncodeUTF7( - PyObject *unicode, /* Unicode object */ - int base64SetO, /* Encode RFC2152 Set O characters in base64 */ - int base64WhiteSpace, /* Encode whitespace (sp, ht, nl, cr) in base64 */ - const char *errors /* error handling */ - ); - -/* --- UTF-8 Codecs ------------------------------------------------------- */ - -PyAPI_FUNC(PyObject*) _PyUnicode_AsUTF8String( - PyObject *unicode, - const char *errors); - -Py_DEPRECATED(3.3) PyAPI_FUNC(PyObject*) PyUnicode_EncodeUTF8( - const Py_UNICODE *data, /* Unicode char buffer */ - Py_ssize_t length, /* number of Py_UNICODE chars to encode */ - const char *errors /* error handling */ - ); - -/* --- UTF-32 Codecs ------------------------------------------------------ */ - -Py_DEPRECATED(3.3) PyAPI_FUNC(PyObject*) PyUnicode_EncodeUTF32( - const Py_UNICODE *data, /* Unicode char buffer */ - Py_ssize_t length, /* number of Py_UNICODE chars to encode */ - const char *errors, /* error handling */ - int byteorder /* byteorder to use 0=BOM+native;-1=LE,1=BE */ - ); - -PyAPI_FUNC(PyObject*) _PyUnicode_EncodeUTF32( - PyObject *object, /* Unicode object */ - const char *errors, /* error handling */ - int byteorder /* byteorder to use 0=BOM+native;-1=LE,1=BE */ - ); - -/* --- UTF-16 Codecs ------------------------------------------------------ */ - -/* Returns a Python string object holding the UTF-16 encoded value of - the Unicode data. - - If byteorder is not 0, output is written according to the following - byte order: - - byteorder == -1: little endian - byteorder == 0: native byte order (writes a BOM mark) - byteorder == 1: big endian - - If byteorder is 0, the output string will always start with the - Unicode BOM mark (U+FEFF). In the other two modes, no BOM mark is - prepended. - - Note that Py_UNICODE data is being interpreted as UTF-16 reduced to - UCS-2. This trick makes it possible to add full UTF-16 capabilities - at a later point without compromising the APIs. - -*/ -Py_DEPRECATED(3.3) PyAPI_FUNC(PyObject*) PyUnicode_EncodeUTF16( - const Py_UNICODE *data, /* Unicode char buffer */ - Py_ssize_t length, /* number of Py_UNICODE chars to encode */ - const char *errors, /* error handling */ - int byteorder /* byteorder to use 0=BOM+native;-1=LE,1=BE */ - ); - -PyAPI_FUNC(PyObject*) _PyUnicode_EncodeUTF16( - PyObject* unicode, /* Unicode object */ - const char *errors, /* error handling */ - int byteorder /* byteorder to use 0=BOM+native;-1=LE,1=BE */ - ); - -/* --- Unicode-Escape Codecs ---------------------------------------------- */ - -/* Helper for PyUnicode_DecodeUnicodeEscape that detects invalid escape - chars. */ -PyAPI_FUNC(PyObject*) _PyUnicode_DecodeUnicodeEscape( - const char *string, /* Unicode-Escape encoded string */ - Py_ssize_t length, /* size of string */ - const char *errors, /* error handling */ - const char **first_invalid_escape /* on return, points to first - invalid escaped char in - string. */ -); - -Py_DEPRECATED(3.3) PyAPI_FUNC(PyObject*) PyUnicode_EncodeUnicodeEscape( - const Py_UNICODE *data, /* Unicode char buffer */ - Py_ssize_t length /* Number of Py_UNICODE chars to encode */ - ); - -/* --- Raw-Unicode-Escape Codecs ------------------------------------------ */ - -Py_DEPRECATED(3.3) PyAPI_FUNC(PyObject*) PyUnicode_EncodeRawUnicodeEscape( - const Py_UNICODE *data, /* Unicode char buffer */ - Py_ssize_t length /* Number of Py_UNICODE chars to encode */ - ); - -/* --- Latin-1 Codecs ----------------------------------------------------- */ - -PyAPI_FUNC(PyObject*) _PyUnicode_AsLatin1String( - PyObject* unicode, - const char* errors); - -Py_DEPRECATED(3.3) PyAPI_FUNC(PyObject*) PyUnicode_EncodeLatin1( - const Py_UNICODE *data, /* Unicode char buffer */ - Py_ssize_t length, /* Number of Py_UNICODE chars to encode */ - const char *errors /* error handling */ - ); - -/* --- ASCII Codecs ------------------------------------------------------- */ - -PyAPI_FUNC(PyObject*) _PyUnicode_AsASCIIString( - PyObject* unicode, - const char* errors); - -Py_DEPRECATED(3.3) PyAPI_FUNC(PyObject*) PyUnicode_EncodeASCII( - const Py_UNICODE *data, /* Unicode char buffer */ - Py_ssize_t length, /* Number of Py_UNICODE chars to encode */ - const char *errors /* error handling */ - ); - -/* --- Character Map Codecs ----------------------------------------------- */ - -Py_DEPRECATED(3.3) PyAPI_FUNC(PyObject*) PyUnicode_EncodeCharmap( - const Py_UNICODE *data, /* Unicode char buffer */ - Py_ssize_t length, /* Number of Py_UNICODE chars to encode */ - PyObject *mapping, /* encoding mapping */ - const char *errors /* error handling */ - ); - -PyAPI_FUNC(PyObject*) _PyUnicode_EncodeCharmap( - PyObject *unicode, /* Unicode object */ - PyObject *mapping, /* encoding mapping */ - const char *errors /* error handling */ - ); - -/* Translate a Py_UNICODE buffer of the given length by applying a - character mapping table to it and return the resulting Unicode - object. - - The mapping table must map Unicode ordinal integers to Unicode strings, - Unicode ordinal integers or None (causing deletion of the character). - - Mapping tables may be dictionaries or sequences. Unmapped character - ordinals (ones which cause a LookupError) are left untouched and - are copied as-is. - -*/ -Py_DEPRECATED(3.3) PyAPI_FUNC(PyObject *) PyUnicode_TranslateCharmap( - const Py_UNICODE *data, /* Unicode char buffer */ - Py_ssize_t length, /* Number of Py_UNICODE chars to encode */ - PyObject *table, /* Translate table */ - const char *errors /* error handling */ - ); - -/* --- MBCS codecs for Windows -------------------------------------------- */ - -#ifdef MS_WINDOWS -Py_DEPRECATED(3.3) PyAPI_FUNC(PyObject*) PyUnicode_EncodeMBCS( - const Py_UNICODE *data, /* Unicode char buffer */ - Py_ssize_t length, /* number of Py_UNICODE chars to encode */ - const char *errors /* error handling */ - ); -#endif - -/* --- Decimal Encoder ---------------------------------------------------- */ - -/* Takes a Unicode string holding a decimal value and writes it into - an output buffer using standard ASCII digit codes. - - The output buffer has to provide at least length+1 bytes of storage - area. The output string is 0-terminated. - - The encoder converts whitespace to ' ', decimal characters to their - corresponding ASCII digit and all other Latin-1 characters except - \0 as-is. Characters outside this range (Unicode ordinals 1-256) - are treated as errors. This includes embedded NULL bytes. - - Error handling is defined by the errors argument: - - NULL or "strict": raise a ValueError - "ignore": ignore the wrong characters (these are not copied to the - output buffer) - "replace": replaces illegal characters with '?' - - Returns 0 on success, -1 on failure. - -*/ - -Py_DEPRECATED(3.3) PyAPI_FUNC(int) PyUnicode_EncodeDecimal( - Py_UNICODE *s, /* Unicode buffer */ - Py_ssize_t length, /* Number of Py_UNICODE chars to encode */ - char *output, /* Output buffer; must have size >= length */ - const char *errors /* error handling */ - ); - -/* Transforms code points that have decimal digit property to the - corresponding ASCII digit code points. - - Returns a new Unicode string on success, NULL on failure. -*/ - -Py_DEPRECATED(3.3) -PyAPI_FUNC(PyObject*) PyUnicode_TransformDecimalToASCII( - Py_UNICODE *s, /* Unicode buffer */ - Py_ssize_t length /* Number of Py_UNICODE chars to transform */ - ); - -/* Coverts a Unicode object holding a decimal value to an ASCII string - for using in int, float and complex parsers. - Transforms code points that have decimal digit property to the - corresponding ASCII digit code points. Transforms spaces to ASCII. - Transforms code points starting from the first non-ASCII code point that - is neither a decimal digit nor a space to the end into '?'. */ - -PyAPI_FUNC(PyObject*) _PyUnicode_TransformDecimalAndSpaceToASCII( - PyObject *unicode /* Unicode object */ - ); - -/* --- Methods & Slots ---------------------------------------------------- */ - -PyAPI_FUNC(PyObject *) _PyUnicode_JoinArray( - PyObject *separator, - PyObject *const *items, - Py_ssize_t seqlen - ); - -/* Test whether a unicode is equal to ASCII identifier. Return 1 if true, - 0 otherwise. The right argument must be ASCII identifier. - Any error occurs inside will be cleared before return. */ -PyAPI_FUNC(int) _PyUnicode_EqualToASCIIId( - PyObject *left, /* Left string */ - _Py_Identifier *right /* Right identifier */ - ); - -/* Test whether a unicode is equal to ASCII string. Return 1 if true, - 0 otherwise. The right argument must be ASCII-encoded string. - Any error occurs inside will be cleared before return. */ -PyAPI_FUNC(int) _PyUnicode_EqualToASCIIString( - PyObject *left, - const char *right /* ASCII-encoded string */ - ); - -/* Externally visible for str.strip(unicode) */ -PyAPI_FUNC(PyObject *) _PyUnicode_XStrip( - PyObject *self, - int striptype, - PyObject *sepobj - ); - -/* Using explicit passed-in values, insert the thousands grouping - into the string pointed to by buffer. For the argument descriptions, - see Objects/stringlib/localeutil.h */ -PyAPI_FUNC(Py_ssize_t) _PyUnicode_InsertThousandsGrouping( - _PyUnicodeWriter *writer, - Py_ssize_t n_buffer, - PyObject *digits, - Py_ssize_t d_pos, - Py_ssize_t n_digits, - Py_ssize_t min_width, - const char *grouping, - PyObject *thousands_sep, - Py_UCS4 *maxchar); - -/* === Characters Type APIs =============================================== */ - -/* Helper array used by Py_UNICODE_ISSPACE(). */ - -PyAPI_DATA(const unsigned char) _Py_ascii_whitespace[]; - -/* These should not be used directly. Use the Py_UNICODE_IS* and - Py_UNICODE_TO* macros instead. - - These APIs are implemented in Objects/unicodectype.c. - -*/ - -PyAPI_FUNC(int) _PyUnicode_IsLowercase( - Py_UCS4 ch /* Unicode character */ - ); - -PyAPI_FUNC(int) _PyUnicode_IsUppercase( - Py_UCS4 ch /* Unicode character */ - ); - -PyAPI_FUNC(int) _PyUnicode_IsTitlecase( - Py_UCS4 ch /* Unicode character */ - ); - -PyAPI_FUNC(int) _PyUnicode_IsXidStart( - Py_UCS4 ch /* Unicode character */ - ); - -PyAPI_FUNC(int) _PyUnicode_IsXidContinue( - Py_UCS4 ch /* Unicode character */ - ); - -PyAPI_FUNC(int) _PyUnicode_IsWhitespace( - const Py_UCS4 ch /* Unicode character */ - ); - -PyAPI_FUNC(int) _PyUnicode_IsLinebreak( - const Py_UCS4 ch /* Unicode character */ - ); - -/* Py_DEPRECATED(3.3) */ PyAPI_FUNC(Py_UCS4) _PyUnicode_ToLowercase( - Py_UCS4 ch /* Unicode character */ - ); - -/* Py_DEPRECATED(3.3) */ PyAPI_FUNC(Py_UCS4) _PyUnicode_ToUppercase( - Py_UCS4 ch /* Unicode character */ - ); - -Py_DEPRECATED(3.3) PyAPI_FUNC(Py_UCS4) _PyUnicode_ToTitlecase( - Py_UCS4 ch /* Unicode character */ - ); - -PyAPI_FUNC(int) _PyUnicode_ToLowerFull( - Py_UCS4 ch, /* Unicode character */ - Py_UCS4 *res - ); - -PyAPI_FUNC(int) _PyUnicode_ToTitleFull( - Py_UCS4 ch, /* Unicode character */ - Py_UCS4 *res - ); - -PyAPI_FUNC(int) _PyUnicode_ToUpperFull( - Py_UCS4 ch, /* Unicode character */ - Py_UCS4 *res - ); - -PyAPI_FUNC(int) _PyUnicode_ToFoldedFull( - Py_UCS4 ch, /* Unicode character */ - Py_UCS4 *res - ); - -PyAPI_FUNC(int) _PyUnicode_IsCaseIgnorable( - Py_UCS4 ch /* Unicode character */ - ); - -PyAPI_FUNC(int) _PyUnicode_IsCased( - Py_UCS4 ch /* Unicode character */ - ); - -PyAPI_FUNC(int) _PyUnicode_ToDecimalDigit( - Py_UCS4 ch /* Unicode character */ - ); - -PyAPI_FUNC(int) _PyUnicode_ToDigit( - Py_UCS4 ch /* Unicode character */ - ); - -PyAPI_FUNC(double) _PyUnicode_ToNumeric( - Py_UCS4 ch /* Unicode character */ - ); - -PyAPI_FUNC(int) _PyUnicode_IsDecimalDigit( - Py_UCS4 ch /* Unicode character */ - ); - -PyAPI_FUNC(int) _PyUnicode_IsDigit( - Py_UCS4 ch /* Unicode character */ - ); - -PyAPI_FUNC(int) _PyUnicode_IsNumeric( - Py_UCS4 ch /* Unicode character */ - ); - -PyAPI_FUNC(int) _PyUnicode_IsPrintable( - Py_UCS4 ch /* Unicode character */ - ); - -PyAPI_FUNC(int) _PyUnicode_IsAlpha( - Py_UCS4 ch /* Unicode character */ - ); - -Py_DEPRECATED(3.3) PyAPI_FUNC(size_t) Py_UNICODE_strlen( - const Py_UNICODE *u - ); - -Py_DEPRECATED(3.3) PyAPI_FUNC(Py_UNICODE*) Py_UNICODE_strcpy( - Py_UNICODE *s1, - const Py_UNICODE *s2); - -Py_DEPRECATED(3.3) PyAPI_FUNC(Py_UNICODE*) Py_UNICODE_strcat( - Py_UNICODE *s1, const Py_UNICODE *s2); - -Py_DEPRECATED(3.3) PyAPI_FUNC(Py_UNICODE*) Py_UNICODE_strncpy( - Py_UNICODE *s1, - const Py_UNICODE *s2, - size_t n); - -Py_DEPRECATED(3.3) PyAPI_FUNC(int) Py_UNICODE_strcmp( - const Py_UNICODE *s1, - const Py_UNICODE *s2 - ); - -Py_DEPRECATED(3.3) PyAPI_FUNC(int) Py_UNICODE_strncmp( - const Py_UNICODE *s1, - const Py_UNICODE *s2, - size_t n - ); - -Py_DEPRECATED(3.3) PyAPI_FUNC(Py_UNICODE*) Py_UNICODE_strchr( - const Py_UNICODE *s, - Py_UNICODE c - ); - -Py_DEPRECATED(3.3) PyAPI_FUNC(Py_UNICODE*) Py_UNICODE_strrchr( - const Py_UNICODE *s, - Py_UNICODE c - ); - -PyAPI_FUNC(PyObject*) _PyUnicode_FormatLong(PyObject *, int, int, int); - -/* Create a copy of a unicode string ending with a nul character. Return NULL - and raise a MemoryError exception on memory allocation failure, otherwise - return a new allocated buffer (use PyMem_Free() to free the buffer). */ - -Py_DEPRECATED(3.3) PyAPI_FUNC(Py_UNICODE*) PyUnicode_AsUnicodeCopy( - PyObject *unicode - ); - -/* Return an interned Unicode object for an Identifier; may fail if there is no memory.*/ -PyAPI_FUNC(PyObject*) _PyUnicode_FromId(_Py_Identifier*); - -/* Fast equality check when the inputs are known to be exact unicode types - and where the hash values are equal (i.e. a very probable match) */ -PyAPI_FUNC(int) _PyUnicode_EQ(PyObject *, PyObject *); - -PyAPI_FUNC(Py_ssize_t) _PyUnicode_ScanIdentifier(PyObject *); - -#ifdef __cplusplus -} -#endif diff --git a/scripts/build-windows/py39-libs/include/datetime.h b/scripts/build-windows/py39-libs/include/datetime.h deleted file mode 100644 index 5d9f2558f..000000000 --- a/scripts/build-windows/py39-libs/include/datetime.h +++ /dev/null @@ -1,259 +0,0 @@ -/* datetime.h - */ -#ifndef Py_LIMITED_API -#ifndef DATETIME_H -#define DATETIME_H -#ifdef __cplusplus -extern "C" { -#endif - -/* Fields are packed into successive bytes, each viewed as unsigned and - * big-endian, unless otherwise noted: - * - * byte offset - * 0 year 2 bytes, 1-9999 - * 2 month 1 byte, 1-12 - * 3 day 1 byte, 1-31 - * 4 hour 1 byte, 0-23 - * 5 minute 1 byte, 0-59 - * 6 second 1 byte, 0-59 - * 7 usecond 3 bytes, 0-999999 - * 10 - */ - -/* # of bytes for year, month, and day. */ -#define _PyDateTime_DATE_DATASIZE 4 - -/* # of bytes for hour, minute, second, and usecond. */ -#define _PyDateTime_TIME_DATASIZE 6 - -/* # of bytes for year, month, day, hour, minute, second, and usecond. */ -#define _PyDateTime_DATETIME_DATASIZE 10 - - -typedef struct -{ - PyObject_HEAD - Py_hash_t hashcode; /* -1 when unknown */ - int days; /* -MAX_DELTA_DAYS <= days <= MAX_DELTA_DAYS */ - int seconds; /* 0 <= seconds < 24*3600 is invariant */ - int microseconds; /* 0 <= microseconds < 1000000 is invariant */ -} PyDateTime_Delta; - -typedef struct -{ - PyObject_HEAD /* a pure abstract base class */ -} PyDateTime_TZInfo; - - -/* The datetime and time types have hashcodes, and an optional tzinfo member, - * present if and only if hastzinfo is true. - */ -#define _PyTZINFO_HEAD \ - PyObject_HEAD \ - Py_hash_t hashcode; \ - char hastzinfo; /* boolean flag */ - -/* No _PyDateTime_BaseTZInfo is allocated; it's just to have something - * convenient to cast to, when getting at the hastzinfo member of objects - * starting with _PyTZINFO_HEAD. - */ -typedef struct -{ - _PyTZINFO_HEAD -} _PyDateTime_BaseTZInfo; - -/* All time objects are of PyDateTime_TimeType, but that can be allocated - * in two ways, with or without a tzinfo member. Without is the same as - * tzinfo == None, but consumes less memory. _PyDateTime_BaseTime is an - * internal struct used to allocate the right amount of space for the - * "without" case. - */ -#define _PyDateTime_TIMEHEAD \ - _PyTZINFO_HEAD \ - unsigned char data[_PyDateTime_TIME_DATASIZE]; - -typedef struct -{ - _PyDateTime_TIMEHEAD -} _PyDateTime_BaseTime; /* hastzinfo false */ - -typedef struct -{ - _PyDateTime_TIMEHEAD - unsigned char fold; - PyObject *tzinfo; -} PyDateTime_Time; /* hastzinfo true */ - - -/* All datetime objects are of PyDateTime_DateTimeType, but that can be - * allocated in two ways too, just like for time objects above. In addition, - * the plain date type is a base class for datetime, so it must also have - * a hastzinfo member (although it's unused there). - */ -typedef struct -{ - _PyTZINFO_HEAD - unsigned char data[_PyDateTime_DATE_DATASIZE]; -} PyDateTime_Date; - -#define _PyDateTime_DATETIMEHEAD \ - _PyTZINFO_HEAD \ - unsigned char data[_PyDateTime_DATETIME_DATASIZE]; - -typedef struct -{ - _PyDateTime_DATETIMEHEAD -} _PyDateTime_BaseDateTime; /* hastzinfo false */ - -typedef struct -{ - _PyDateTime_DATETIMEHEAD - unsigned char fold; - PyObject *tzinfo; -} PyDateTime_DateTime; /* hastzinfo true */ - - -/* Apply for date and datetime instances. */ -#define PyDateTime_GET_YEAR(o) ((((PyDateTime_Date*)o)->data[0] << 8) | \ - ((PyDateTime_Date*)o)->data[1]) -#define PyDateTime_GET_MONTH(o) (((PyDateTime_Date*)o)->data[2]) -#define PyDateTime_GET_DAY(o) (((PyDateTime_Date*)o)->data[3]) - -#define PyDateTime_DATE_GET_HOUR(o) (((PyDateTime_DateTime*)o)->data[4]) -#define PyDateTime_DATE_GET_MINUTE(o) (((PyDateTime_DateTime*)o)->data[5]) -#define PyDateTime_DATE_GET_SECOND(o) (((PyDateTime_DateTime*)o)->data[6]) -#define PyDateTime_DATE_GET_MICROSECOND(o) \ - ((((PyDateTime_DateTime*)o)->data[7] << 16) | \ - (((PyDateTime_DateTime*)o)->data[8] << 8) | \ - ((PyDateTime_DateTime*)o)->data[9]) -#define PyDateTime_DATE_GET_FOLD(o) (((PyDateTime_DateTime*)o)->fold) - -/* Apply for time instances. */ -#define PyDateTime_TIME_GET_HOUR(o) (((PyDateTime_Time*)o)->data[0]) -#define PyDateTime_TIME_GET_MINUTE(o) (((PyDateTime_Time*)o)->data[1]) -#define PyDateTime_TIME_GET_SECOND(o) (((PyDateTime_Time*)o)->data[2]) -#define PyDateTime_TIME_GET_MICROSECOND(o) \ - ((((PyDateTime_Time*)o)->data[3] << 16) | \ - (((PyDateTime_Time*)o)->data[4] << 8) | \ - ((PyDateTime_Time*)o)->data[5]) -#define PyDateTime_TIME_GET_FOLD(o) (((PyDateTime_Time*)o)->fold) - -/* Apply for time delta instances */ -#define PyDateTime_DELTA_GET_DAYS(o) (((PyDateTime_Delta*)o)->days) -#define PyDateTime_DELTA_GET_SECONDS(o) (((PyDateTime_Delta*)o)->seconds) -#define PyDateTime_DELTA_GET_MICROSECONDS(o) \ - (((PyDateTime_Delta*)o)->microseconds) - - -/* Define structure for C API. */ -typedef struct { - /* type objects */ - PyTypeObject *DateType; - PyTypeObject *DateTimeType; - PyTypeObject *TimeType; - PyTypeObject *DeltaType; - PyTypeObject *TZInfoType; - - /* singletons */ - PyObject *TimeZone_UTC; - - /* constructors */ - PyObject *(*Date_FromDate)(int, int, int, PyTypeObject*); - PyObject *(*DateTime_FromDateAndTime)(int, int, int, int, int, int, int, - PyObject*, PyTypeObject*); - PyObject *(*Time_FromTime)(int, int, int, int, PyObject*, PyTypeObject*); - PyObject *(*Delta_FromDelta)(int, int, int, int, PyTypeObject*); - PyObject *(*TimeZone_FromTimeZone)(PyObject *offset, PyObject *name); - - /* constructors for the DB API */ - PyObject *(*DateTime_FromTimestamp)(PyObject*, PyObject*, PyObject*); - PyObject *(*Date_FromTimestamp)(PyObject*, PyObject*); - - /* PEP 495 constructors */ - PyObject *(*DateTime_FromDateAndTimeAndFold)(int, int, int, int, int, int, int, - PyObject*, int, PyTypeObject*); - PyObject *(*Time_FromTimeAndFold)(int, int, int, int, PyObject*, int, PyTypeObject*); - -} PyDateTime_CAPI; - -#define PyDateTime_CAPSULE_NAME "datetime.datetime_CAPI" - - -/* This block is only used as part of the public API and should not be - * included in _datetimemodule.c, which does not use the C API capsule. - * See bpo-35081 for more details. - * */ -#ifndef _PY_DATETIME_IMPL -/* Define global variable for the C API and a macro for setting it. */ -static PyDateTime_CAPI *PyDateTimeAPI = NULL; - -#define PyDateTime_IMPORT \ - PyDateTimeAPI = (PyDateTime_CAPI *)PyCapsule_Import(PyDateTime_CAPSULE_NAME, 0) - -/* Macro for access to the UTC singleton */ -#define PyDateTime_TimeZone_UTC PyDateTimeAPI->TimeZone_UTC - -/* Macros for type checking when not building the Python core. */ -#define PyDate_Check(op) PyObject_TypeCheck(op, PyDateTimeAPI->DateType) -#define PyDate_CheckExact(op) Py_IS_TYPE(op, PyDateTimeAPI->DateType) - -#define PyDateTime_Check(op) PyObject_TypeCheck(op, PyDateTimeAPI->DateTimeType) -#define PyDateTime_CheckExact(op) Py_IS_TYPE(op, PyDateTimeAPI->DateTimeType) - -#define PyTime_Check(op) PyObject_TypeCheck(op, PyDateTimeAPI->TimeType) -#define PyTime_CheckExact(op) Py_IS_TYPE(op, PyDateTimeAPI->TimeType) - -#define PyDelta_Check(op) PyObject_TypeCheck(op, PyDateTimeAPI->DeltaType) -#define PyDelta_CheckExact(op) Py_IS_TYPE(op, PyDateTimeAPI->DeltaType) - -#define PyTZInfo_Check(op) PyObject_TypeCheck(op, PyDateTimeAPI->TZInfoType) -#define PyTZInfo_CheckExact(op) Py_IS_TYPE(op, PyDateTimeAPI->TZInfoType) - - -/* Macros for accessing constructors in a simplified fashion. */ -#define PyDate_FromDate(year, month, day) \ - PyDateTimeAPI->Date_FromDate(year, month, day, PyDateTimeAPI->DateType) - -#define PyDateTime_FromDateAndTime(year, month, day, hour, min, sec, usec) \ - PyDateTimeAPI->DateTime_FromDateAndTime(year, month, day, hour, \ - min, sec, usec, Py_None, PyDateTimeAPI->DateTimeType) - -#define PyDateTime_FromDateAndTimeAndFold(year, month, day, hour, min, sec, usec, fold) \ - PyDateTimeAPI->DateTime_FromDateAndTimeAndFold(year, month, day, hour, \ - min, sec, usec, Py_None, fold, PyDateTimeAPI->DateTimeType) - -#define PyTime_FromTime(hour, minute, second, usecond) \ - PyDateTimeAPI->Time_FromTime(hour, minute, second, usecond, \ - Py_None, PyDateTimeAPI->TimeType) - -#define PyTime_FromTimeAndFold(hour, minute, second, usecond, fold) \ - PyDateTimeAPI->Time_FromTimeAndFold(hour, minute, second, usecond, \ - Py_None, fold, PyDateTimeAPI->TimeType) - -#define PyDelta_FromDSU(days, seconds, useconds) \ - PyDateTimeAPI->Delta_FromDelta(days, seconds, useconds, 1, \ - PyDateTimeAPI->DeltaType) - -#define PyTimeZone_FromOffset(offset) \ - PyDateTimeAPI->TimeZone_FromTimeZone(offset, NULL) - -#define PyTimeZone_FromOffsetAndName(offset, name) \ - PyDateTimeAPI->TimeZone_FromTimeZone(offset, name) - -/* Macros supporting the DB API. */ -#define PyDateTime_FromTimestamp(args) \ - PyDateTimeAPI->DateTime_FromTimestamp( \ - (PyObject*) (PyDateTimeAPI->DateTimeType), args, NULL) - -#define PyDate_FromTimestamp(args) \ - PyDateTimeAPI->Date_FromTimestamp( \ - (PyObject*) (PyDateTimeAPI->DateType), args) - -#endif /* !defined(_PY_DATETIME_IMPL) */ - -#ifdef __cplusplus -} -#endif -#endif -#endif /* !Py_LIMITED_API */ diff --git a/scripts/build-windows/py39-libs/include/descrobject.h b/scripts/build-windows/py39-libs/include/descrobject.h deleted file mode 100644 index ead269d1d..000000000 --- a/scripts/build-windows/py39-libs/include/descrobject.h +++ /dev/null @@ -1,108 +0,0 @@ -/* Descriptors */ -#ifndef Py_DESCROBJECT_H -#define Py_DESCROBJECT_H -#ifdef __cplusplus -extern "C" { -#endif - -typedef PyObject *(*getter)(PyObject *, void *); -typedef int (*setter)(PyObject *, PyObject *, void *); - -typedef struct PyGetSetDef { - const char *name; - getter get; - setter set; - const char *doc; - void *closure; -} PyGetSetDef; - -#ifndef Py_LIMITED_API -typedef PyObject *(*wrapperfunc)(PyObject *self, PyObject *args, - void *wrapped); - -typedef PyObject *(*wrapperfunc_kwds)(PyObject *self, PyObject *args, - void *wrapped, PyObject *kwds); - -struct wrapperbase { - const char *name; - int offset; - void *function; - wrapperfunc wrapper; - const char *doc; - int flags; - PyObject *name_strobj; -}; - -/* Flags for above struct */ -#define PyWrapperFlag_KEYWORDS 1 /* wrapper function takes keyword args */ - -/* Various kinds of descriptor objects */ - -typedef struct { - PyObject_HEAD - PyTypeObject *d_type; - PyObject *d_name; - PyObject *d_qualname; -} PyDescrObject; - -#define PyDescr_COMMON PyDescrObject d_common - -#define PyDescr_TYPE(x) (((PyDescrObject *)(x))->d_type) -#define PyDescr_NAME(x) (((PyDescrObject *)(x))->d_name) - -typedef struct { - PyDescr_COMMON; - PyMethodDef *d_method; - vectorcallfunc vectorcall; -} PyMethodDescrObject; - -typedef struct { - PyDescr_COMMON; - struct PyMemberDef *d_member; -} PyMemberDescrObject; - -typedef struct { - PyDescr_COMMON; - PyGetSetDef *d_getset; -} PyGetSetDescrObject; - -typedef struct { - PyDescr_COMMON; - struct wrapperbase *d_base; - void *d_wrapped; /* This can be any function pointer */ -} PyWrapperDescrObject; -#endif /* Py_LIMITED_API */ - -PyAPI_DATA(PyTypeObject) PyClassMethodDescr_Type; -PyAPI_DATA(PyTypeObject) PyGetSetDescr_Type; -PyAPI_DATA(PyTypeObject) PyMemberDescr_Type; -PyAPI_DATA(PyTypeObject) PyMethodDescr_Type; -PyAPI_DATA(PyTypeObject) PyWrapperDescr_Type; -PyAPI_DATA(PyTypeObject) PyDictProxy_Type; -#ifndef Py_LIMITED_API -PyAPI_DATA(PyTypeObject) _PyMethodWrapper_Type; -#endif /* Py_LIMITED_API */ - -PyAPI_FUNC(PyObject *) PyDescr_NewMethod(PyTypeObject *, PyMethodDef *); -PyAPI_FUNC(PyObject *) PyDescr_NewClassMethod(PyTypeObject *, PyMethodDef *); -struct PyMemberDef; /* forward declaration for following prototype */ -PyAPI_FUNC(PyObject *) PyDescr_NewMember(PyTypeObject *, - struct PyMemberDef *); -PyAPI_FUNC(PyObject *) PyDescr_NewGetSet(PyTypeObject *, - struct PyGetSetDef *); -#ifndef Py_LIMITED_API -PyAPI_FUNC(PyObject *) PyDescr_NewWrapper(PyTypeObject *, - struct wrapperbase *, void *); -#define PyDescr_IsData(d) (Py_TYPE(d)->tp_descr_set != NULL) -#endif - -PyAPI_FUNC(PyObject *) PyDictProxy_New(PyObject *); -PyAPI_FUNC(PyObject *) PyWrapper_New(PyObject *, PyObject *); - - -PyAPI_DATA(PyTypeObject) PyProperty_Type; -#ifdef __cplusplus -} -#endif -#endif /* !Py_DESCROBJECT_H */ - diff --git a/scripts/build-windows/py39-libs/include/dictobject.h b/scripts/build-windows/py39-libs/include/dictobject.h deleted file mode 100644 index c88b0aa0a..000000000 --- a/scripts/build-windows/py39-libs/include/dictobject.h +++ /dev/null @@ -1,94 +0,0 @@ -#ifndef Py_DICTOBJECT_H -#define Py_DICTOBJECT_H -#ifdef __cplusplus -extern "C" { -#endif - -/* Dictionary object type -- mapping from hashable object to object */ - -/* The distribution includes a separate file, Objects/dictnotes.txt, - describing explorations into dictionary design and optimization. - It covers typical dictionary use patterns, the parameters for - tuning dictionaries, and several ideas for possible optimizations. -*/ - -PyAPI_DATA(PyTypeObject) PyDict_Type; - -#define PyDict_Check(op) \ - PyType_FastSubclass(Py_TYPE(op), Py_TPFLAGS_DICT_SUBCLASS) -#define PyDict_CheckExact(op) Py_IS_TYPE(op, &PyDict_Type) - -PyAPI_FUNC(PyObject *) PyDict_New(void); -PyAPI_FUNC(PyObject *) PyDict_GetItem(PyObject *mp, PyObject *key); -PyAPI_FUNC(PyObject *) PyDict_GetItemWithError(PyObject *mp, PyObject *key); -PyAPI_FUNC(int) PyDict_SetItem(PyObject *mp, PyObject *key, PyObject *item); -PyAPI_FUNC(int) PyDict_DelItem(PyObject *mp, PyObject *key); -PyAPI_FUNC(void) PyDict_Clear(PyObject *mp); -PyAPI_FUNC(int) PyDict_Next( - PyObject *mp, Py_ssize_t *pos, PyObject **key, PyObject **value); -PyAPI_FUNC(PyObject *) PyDict_Keys(PyObject *mp); -PyAPI_FUNC(PyObject *) PyDict_Values(PyObject *mp); -PyAPI_FUNC(PyObject *) PyDict_Items(PyObject *mp); -PyAPI_FUNC(Py_ssize_t) PyDict_Size(PyObject *mp); -PyAPI_FUNC(PyObject *) PyDict_Copy(PyObject *mp); -PyAPI_FUNC(int) PyDict_Contains(PyObject *mp, PyObject *key); - -/* PyDict_Update(mp, other) is equivalent to PyDict_Merge(mp, other, 1). */ -PyAPI_FUNC(int) PyDict_Update(PyObject *mp, PyObject *other); - -/* PyDict_Merge updates/merges from a mapping object (an object that - supports PyMapping_Keys() and PyObject_GetItem()). If override is true, - the last occurrence of a key wins, else the first. The Python - dict.update(other) is equivalent to PyDict_Merge(dict, other, 1). -*/ -PyAPI_FUNC(int) PyDict_Merge(PyObject *mp, - PyObject *other, - int override); - -/* PyDict_MergeFromSeq2 updates/merges from an iterable object producing - iterable objects of length 2. If override is true, the last occurrence - of a key wins, else the first. The Python dict constructor dict(seq2) - is equivalent to dict={}; PyDict_MergeFromSeq(dict, seq2, 1). -*/ -PyAPI_FUNC(int) PyDict_MergeFromSeq2(PyObject *d, - PyObject *seq2, - int override); - -PyAPI_FUNC(PyObject *) PyDict_GetItemString(PyObject *dp, const char *key); -PyAPI_FUNC(int) PyDict_SetItemString(PyObject *dp, const char *key, PyObject *item); -PyAPI_FUNC(int) PyDict_DelItemString(PyObject *dp, const char *key); - -/* Dictionary (keys, values, items) views */ - -PyAPI_DATA(PyTypeObject) PyDictKeys_Type; -PyAPI_DATA(PyTypeObject) PyDictValues_Type; -PyAPI_DATA(PyTypeObject) PyDictItems_Type; - -#define PyDictKeys_Check(op) PyObject_TypeCheck(op, &PyDictKeys_Type) -#define PyDictValues_Check(op) PyObject_TypeCheck(op, &PyDictValues_Type) -#define PyDictItems_Check(op) PyObject_TypeCheck(op, &PyDictItems_Type) -/* This excludes Values, since they are not sets. */ -# define PyDictViewSet_Check(op) \ - (PyDictKeys_Check(op) || PyDictItems_Check(op)) - -/* Dictionary (key, value, items) iterators */ - -PyAPI_DATA(PyTypeObject) PyDictIterKey_Type; -PyAPI_DATA(PyTypeObject) PyDictIterValue_Type; -PyAPI_DATA(PyTypeObject) PyDictIterItem_Type; - -PyAPI_DATA(PyTypeObject) PyDictRevIterKey_Type; -PyAPI_DATA(PyTypeObject) PyDictRevIterItem_Type; -PyAPI_DATA(PyTypeObject) PyDictRevIterValue_Type; - - -#ifndef Py_LIMITED_API -# define Py_CPYTHON_DICTOBJECT_H -# include "cpython/dictobject.h" -# undef Py_CPYTHON_DICTOBJECT_H -#endif - -#ifdef __cplusplus -} -#endif -#endif /* !Py_DICTOBJECT_H */ diff --git a/scripts/build-windows/py39-libs/include/dynamic_annotations.h b/scripts/build-windows/py39-libs/include/dynamic_annotations.h deleted file mode 100644 index 0bd1a833c..000000000 --- a/scripts/build-windows/py39-libs/include/dynamic_annotations.h +++ /dev/null @@ -1,499 +0,0 @@ -/* Copyright (c) 2008-2009, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * --- - * Author: Kostya Serebryany - * Copied to CPython by Jeffrey Yasskin, with all macros renamed to - * start with _Py_ to avoid colliding with users embedding Python, and - * with deprecated macros removed. - */ - -/* This file defines dynamic annotations for use with dynamic analysis - tool such as valgrind, PIN, etc. - - Dynamic annotation is a source code annotation that affects - the generated code (that is, the annotation is not a comment). - Each such annotation is attached to a particular - instruction and/or to a particular object (address) in the program. - - The annotations that should be used by users are macros in all upper-case - (e.g., _Py_ANNOTATE_NEW_MEMORY). - - Actual implementation of these macros may differ depending on the - dynamic analysis tool being used. - - See http://code.google.com/p/data-race-test/ for more information. - - This file supports the following dynamic analysis tools: - - None (DYNAMIC_ANNOTATIONS_ENABLED is not defined or zero). - Macros are defined empty. - - ThreadSanitizer, Helgrind, DRD (DYNAMIC_ANNOTATIONS_ENABLED is 1). - Macros are defined as calls to non-inlinable empty functions - that are intercepted by Valgrind. */ - -#ifndef __DYNAMIC_ANNOTATIONS_H__ -#define __DYNAMIC_ANNOTATIONS_H__ - -#ifndef DYNAMIC_ANNOTATIONS_ENABLED -# define DYNAMIC_ANNOTATIONS_ENABLED 0 -#endif - -#if DYNAMIC_ANNOTATIONS_ENABLED != 0 - - /* ------------------------------------------------------------- - Annotations useful when implementing condition variables such as CondVar, - using conditional critical sections (Await/LockWhen) and when constructing - user-defined synchronization mechanisms. - - The annotations _Py_ANNOTATE_HAPPENS_BEFORE() and - _Py_ANNOTATE_HAPPENS_AFTER() can be used to define happens-before arcs in - user-defined synchronization mechanisms: the race detector will infer an - arc from the former to the latter when they share the same argument - pointer. - - Example 1 (reference counting): - - void Unref() { - _Py_ANNOTATE_HAPPENS_BEFORE(&refcount_); - if (AtomicDecrementByOne(&refcount_) == 0) { - _Py_ANNOTATE_HAPPENS_AFTER(&refcount_); - delete this; - } - } - - Example 2 (message queue): - - void MyQueue::Put(Type *e) { - MutexLock lock(&mu_); - _Py_ANNOTATE_HAPPENS_BEFORE(e); - PutElementIntoMyQueue(e); - } - - Type *MyQueue::Get() { - MutexLock lock(&mu_); - Type *e = GetElementFromMyQueue(); - _Py_ANNOTATE_HAPPENS_AFTER(e); - return e; - } - - Note: when possible, please use the existing reference counting and message - queue implementations instead of inventing new ones. */ - - /* Report that wait on the condition variable at address "cv" has succeeded - and the lock at address "lock" is held. */ -#define _Py_ANNOTATE_CONDVAR_LOCK_WAIT(cv, lock) \ - AnnotateCondVarWait(__FILE__, __LINE__, cv, lock) - - /* Report that wait on the condition variable at "cv" has succeeded. Variant - w/o lock. */ -#define _Py_ANNOTATE_CONDVAR_WAIT(cv) \ - AnnotateCondVarWait(__FILE__, __LINE__, cv, NULL) - - /* Report that we are about to signal on the condition variable at address - "cv". */ -#define _Py_ANNOTATE_CONDVAR_SIGNAL(cv) \ - AnnotateCondVarSignal(__FILE__, __LINE__, cv) - - /* Report that we are about to signal_all on the condition variable at "cv". */ -#define _Py_ANNOTATE_CONDVAR_SIGNAL_ALL(cv) \ - AnnotateCondVarSignalAll(__FILE__, __LINE__, cv) - - /* Annotations for user-defined synchronization mechanisms. */ -#define _Py_ANNOTATE_HAPPENS_BEFORE(obj) _Py_ANNOTATE_CONDVAR_SIGNAL(obj) -#define _Py_ANNOTATE_HAPPENS_AFTER(obj) _Py_ANNOTATE_CONDVAR_WAIT(obj) - - /* Report that the bytes in the range [pointer, pointer+size) are about - to be published safely. The race checker will create a happens-before - arc from the call _Py_ANNOTATE_PUBLISH_MEMORY_RANGE(pointer, size) to - subsequent accesses to this memory. - Note: this annotation may not work properly if the race detector uses - sampling, i.e. does not observe all memory accesses. - */ -#define _Py_ANNOTATE_PUBLISH_MEMORY_RANGE(pointer, size) \ - AnnotatePublishMemoryRange(__FILE__, __LINE__, pointer, size) - - /* Instruct the tool to create a happens-before arc between mu->Unlock() and - mu->Lock(). This annotation may slow down the race detector and hide real - races. Normally it is used only when it would be difficult to annotate each - of the mutex's critical sections individually using the annotations above. - This annotation makes sense only for hybrid race detectors. For pure - happens-before detectors this is a no-op. For more details see - http://code.google.com/p/data-race-test/wiki/PureHappensBeforeVsHybrid . */ -#define _Py_ANNOTATE_PURE_HAPPENS_BEFORE_MUTEX(mu) \ - AnnotateMutexIsUsedAsCondVar(__FILE__, __LINE__, mu) - - /* ------------------------------------------------------------- - Annotations useful when defining memory allocators, or when memory that - was protected in one way starts to be protected in another. */ - - /* Report that a new memory at "address" of size "size" has been allocated. - This might be used when the memory has been retrieved from a free list and - is about to be reused, or when the locking discipline for a variable - changes. */ -#define _Py_ANNOTATE_NEW_MEMORY(address, size) \ - AnnotateNewMemory(__FILE__, __LINE__, address, size) - - /* ------------------------------------------------------------- - Annotations useful when defining FIFO queues that transfer data between - threads. */ - - /* Report that the producer-consumer queue (such as ProducerConsumerQueue) at - address "pcq" has been created. The _Py_ANNOTATE_PCQ_* annotations should - be used only for FIFO queues. For non-FIFO queues use - _Py_ANNOTATE_HAPPENS_BEFORE (for put) and _Py_ANNOTATE_HAPPENS_AFTER (for - get). */ -#define _Py_ANNOTATE_PCQ_CREATE(pcq) \ - AnnotatePCQCreate(__FILE__, __LINE__, pcq) - - /* Report that the queue at address "pcq" is about to be destroyed. */ -#define _Py_ANNOTATE_PCQ_DESTROY(pcq) \ - AnnotatePCQDestroy(__FILE__, __LINE__, pcq) - - /* Report that we are about to put an element into a FIFO queue at address - "pcq". */ -#define _Py_ANNOTATE_PCQ_PUT(pcq) \ - AnnotatePCQPut(__FILE__, __LINE__, pcq) - - /* Report that we've just got an element from a FIFO queue at address "pcq". */ -#define _Py_ANNOTATE_PCQ_GET(pcq) \ - AnnotatePCQGet(__FILE__, __LINE__, pcq) - - /* ------------------------------------------------------------- - Annotations that suppress errors. It is usually better to express the - program's synchronization using the other annotations, but these can - be used when all else fails. */ - - /* Report that we may have a benign race at "pointer", with size - "sizeof(*(pointer))". "pointer" must be a non-void* pointer. Insert at the - point where "pointer" has been allocated, preferably close to the point - where the race happens. See also _Py_ANNOTATE_BENIGN_RACE_STATIC. */ -#define _Py_ANNOTATE_BENIGN_RACE(pointer, description) \ - AnnotateBenignRaceSized(__FILE__, __LINE__, pointer, \ - sizeof(*(pointer)), description) - - /* Same as _Py_ANNOTATE_BENIGN_RACE(address, description), but applies to - the memory range [address, address+size). */ -#define _Py_ANNOTATE_BENIGN_RACE_SIZED(address, size, description) \ - AnnotateBenignRaceSized(__FILE__, __LINE__, address, size, description) - - /* Request the analysis tool to ignore all reads in the current thread - until _Py_ANNOTATE_IGNORE_READS_END is called. - Useful to ignore intentional racey reads, while still checking - other reads and all writes. - See also _Py_ANNOTATE_UNPROTECTED_READ. */ -#define _Py_ANNOTATE_IGNORE_READS_BEGIN() \ - AnnotateIgnoreReadsBegin(__FILE__, __LINE__) - - /* Stop ignoring reads. */ -#define _Py_ANNOTATE_IGNORE_READS_END() \ - AnnotateIgnoreReadsEnd(__FILE__, __LINE__) - - /* Similar to _Py_ANNOTATE_IGNORE_READS_BEGIN, but ignore writes. */ -#define _Py_ANNOTATE_IGNORE_WRITES_BEGIN() \ - AnnotateIgnoreWritesBegin(__FILE__, __LINE__) - - /* Stop ignoring writes. */ -#define _Py_ANNOTATE_IGNORE_WRITES_END() \ - AnnotateIgnoreWritesEnd(__FILE__, __LINE__) - - /* Start ignoring all memory accesses (reads and writes). */ -#define _Py_ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN() \ - do {\ - _Py_ANNOTATE_IGNORE_READS_BEGIN();\ - _Py_ANNOTATE_IGNORE_WRITES_BEGIN();\ - }while(0)\ - - /* Stop ignoring all memory accesses. */ -#define _Py_ANNOTATE_IGNORE_READS_AND_WRITES_END() \ - do {\ - _Py_ANNOTATE_IGNORE_WRITES_END();\ - _Py_ANNOTATE_IGNORE_READS_END();\ - }while(0)\ - - /* Similar to _Py_ANNOTATE_IGNORE_READS_BEGIN, but ignore synchronization events: - RWLOCK* and CONDVAR*. */ -#define _Py_ANNOTATE_IGNORE_SYNC_BEGIN() \ - AnnotateIgnoreSyncBegin(__FILE__, __LINE__) - - /* Stop ignoring sync events. */ -#define _Py_ANNOTATE_IGNORE_SYNC_END() \ - AnnotateIgnoreSyncEnd(__FILE__, __LINE__) - - - /* Enable (enable!=0) or disable (enable==0) race detection for all threads. - This annotation could be useful if you want to skip expensive race analysis - during some period of program execution, e.g. during initialization. */ -#define _Py_ANNOTATE_ENABLE_RACE_DETECTION(enable) \ - AnnotateEnableRaceDetection(__FILE__, __LINE__, enable) - - /* ------------------------------------------------------------- - Annotations useful for debugging. */ - - /* Request to trace every access to "address". */ -#define _Py_ANNOTATE_TRACE_MEMORY(address) \ - AnnotateTraceMemory(__FILE__, __LINE__, address) - - /* Report the current thread name to a race detector. */ -#define _Py_ANNOTATE_THREAD_NAME(name) \ - AnnotateThreadName(__FILE__, __LINE__, name) - - /* ------------------------------------------------------------- - Annotations useful when implementing locks. They are not - normally needed by modules that merely use locks. - The "lock" argument is a pointer to the lock object. */ - - /* Report that a lock has been created at address "lock". */ -#define _Py_ANNOTATE_RWLOCK_CREATE(lock) \ - AnnotateRWLockCreate(__FILE__, __LINE__, lock) - - /* Report that the lock at address "lock" is about to be destroyed. */ -#define _Py_ANNOTATE_RWLOCK_DESTROY(lock) \ - AnnotateRWLockDestroy(__FILE__, __LINE__, lock) - - /* Report that the lock at address "lock" has been acquired. - is_w=1 for writer lock, is_w=0 for reader lock. */ -#define _Py_ANNOTATE_RWLOCK_ACQUIRED(lock, is_w) \ - AnnotateRWLockAcquired(__FILE__, __LINE__, lock, is_w) - - /* Report that the lock at address "lock" is about to be released. */ -#define _Py_ANNOTATE_RWLOCK_RELEASED(lock, is_w) \ - AnnotateRWLockReleased(__FILE__, __LINE__, lock, is_w) - - /* ------------------------------------------------------------- - Annotations useful when implementing barriers. They are not - normally needed by modules that merely use barriers. - The "barrier" argument is a pointer to the barrier object. */ - - /* Report that the "barrier" has been initialized with initial "count". - If 'reinitialization_allowed' is true, initialization is allowed to happen - multiple times w/o calling barrier_destroy() */ -#define _Py_ANNOTATE_BARRIER_INIT(barrier, count, reinitialization_allowed) \ - AnnotateBarrierInit(__FILE__, __LINE__, barrier, count, \ - reinitialization_allowed) - - /* Report that we are about to enter barrier_wait("barrier"). */ -#define _Py_ANNOTATE_BARRIER_WAIT_BEFORE(barrier) \ - AnnotateBarrierWaitBefore(__FILE__, __LINE__, barrier) - - /* Report that we just exited barrier_wait("barrier"). */ -#define _Py_ANNOTATE_BARRIER_WAIT_AFTER(barrier) \ - AnnotateBarrierWaitAfter(__FILE__, __LINE__, barrier) - - /* Report that the "barrier" has been destroyed. */ -#define _Py_ANNOTATE_BARRIER_DESTROY(barrier) \ - AnnotateBarrierDestroy(__FILE__, __LINE__, barrier) - - /* ------------------------------------------------------------- - Annotations useful for testing race detectors. */ - - /* Report that we expect a race on the variable at "address". - Use only in unit tests for a race detector. */ -#define _Py_ANNOTATE_EXPECT_RACE(address, description) \ - AnnotateExpectRace(__FILE__, __LINE__, address, description) - - /* A no-op. Insert where you like to test the interceptors. */ -#define _Py_ANNOTATE_NO_OP(arg) \ - AnnotateNoOp(__FILE__, __LINE__, arg) - - /* Force the race detector to flush its state. The actual effect depends on - * the implementation of the detector. */ -#define _Py_ANNOTATE_FLUSH_STATE() \ - AnnotateFlushState(__FILE__, __LINE__) - - -#else /* DYNAMIC_ANNOTATIONS_ENABLED == 0 */ - -#define _Py_ANNOTATE_RWLOCK_CREATE(lock) /* empty */ -#define _Py_ANNOTATE_RWLOCK_DESTROY(lock) /* empty */ -#define _Py_ANNOTATE_RWLOCK_ACQUIRED(lock, is_w) /* empty */ -#define _Py_ANNOTATE_RWLOCK_RELEASED(lock, is_w) /* empty */ -#define _Py_ANNOTATE_BARRIER_INIT(barrier, count, reinitialization_allowed) /* */ -#define _Py_ANNOTATE_BARRIER_WAIT_BEFORE(barrier) /* empty */ -#define _Py_ANNOTATE_BARRIER_WAIT_AFTER(barrier) /* empty */ -#define _Py_ANNOTATE_BARRIER_DESTROY(barrier) /* empty */ -#define _Py_ANNOTATE_CONDVAR_LOCK_WAIT(cv, lock) /* empty */ -#define _Py_ANNOTATE_CONDVAR_WAIT(cv) /* empty */ -#define _Py_ANNOTATE_CONDVAR_SIGNAL(cv) /* empty */ -#define _Py_ANNOTATE_CONDVAR_SIGNAL_ALL(cv) /* empty */ -#define _Py_ANNOTATE_HAPPENS_BEFORE(obj) /* empty */ -#define _Py_ANNOTATE_HAPPENS_AFTER(obj) /* empty */ -#define _Py_ANNOTATE_PUBLISH_MEMORY_RANGE(address, size) /* empty */ -#define _Py_ANNOTATE_UNPUBLISH_MEMORY_RANGE(address, size) /* empty */ -#define _Py_ANNOTATE_SWAP_MEMORY_RANGE(address, size) /* empty */ -#define _Py_ANNOTATE_PCQ_CREATE(pcq) /* empty */ -#define _Py_ANNOTATE_PCQ_DESTROY(pcq) /* empty */ -#define _Py_ANNOTATE_PCQ_PUT(pcq) /* empty */ -#define _Py_ANNOTATE_PCQ_GET(pcq) /* empty */ -#define _Py_ANNOTATE_NEW_MEMORY(address, size) /* empty */ -#define _Py_ANNOTATE_EXPECT_RACE(address, description) /* empty */ -#define _Py_ANNOTATE_BENIGN_RACE(address, description) /* empty */ -#define _Py_ANNOTATE_BENIGN_RACE_SIZED(address, size, description) /* empty */ -#define _Py_ANNOTATE_PURE_HAPPENS_BEFORE_MUTEX(mu) /* empty */ -#define _Py_ANNOTATE_MUTEX_IS_USED_AS_CONDVAR(mu) /* empty */ -#define _Py_ANNOTATE_TRACE_MEMORY(arg) /* empty */ -#define _Py_ANNOTATE_THREAD_NAME(name) /* empty */ -#define _Py_ANNOTATE_IGNORE_READS_BEGIN() /* empty */ -#define _Py_ANNOTATE_IGNORE_READS_END() /* empty */ -#define _Py_ANNOTATE_IGNORE_WRITES_BEGIN() /* empty */ -#define _Py_ANNOTATE_IGNORE_WRITES_END() /* empty */ -#define _Py_ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN() /* empty */ -#define _Py_ANNOTATE_IGNORE_READS_AND_WRITES_END() /* empty */ -#define _Py_ANNOTATE_IGNORE_SYNC_BEGIN() /* empty */ -#define _Py_ANNOTATE_IGNORE_SYNC_END() /* empty */ -#define _Py_ANNOTATE_ENABLE_RACE_DETECTION(enable) /* empty */ -#define _Py_ANNOTATE_NO_OP(arg) /* empty */ -#define _Py_ANNOTATE_FLUSH_STATE() /* empty */ - -#endif /* DYNAMIC_ANNOTATIONS_ENABLED */ - -/* Use the macros above rather than using these functions directly. */ -#ifdef __cplusplus -extern "C" { -#endif -void AnnotateRWLockCreate(const char *file, int line, - const volatile void *lock); -void AnnotateRWLockDestroy(const char *file, int line, - const volatile void *lock); -void AnnotateRWLockAcquired(const char *file, int line, - const volatile void *lock, long is_w); -void AnnotateRWLockReleased(const char *file, int line, - const volatile void *lock, long is_w); -void AnnotateBarrierInit(const char *file, int line, - const volatile void *barrier, long count, - long reinitialization_allowed); -void AnnotateBarrierWaitBefore(const char *file, int line, - const volatile void *barrier); -void AnnotateBarrierWaitAfter(const char *file, int line, - const volatile void *barrier); -void AnnotateBarrierDestroy(const char *file, int line, - const volatile void *barrier); -void AnnotateCondVarWait(const char *file, int line, - const volatile void *cv, - const volatile void *lock); -void AnnotateCondVarSignal(const char *file, int line, - const volatile void *cv); -void AnnotateCondVarSignalAll(const char *file, int line, - const volatile void *cv); -void AnnotatePublishMemoryRange(const char *file, int line, - const volatile void *address, - long size); -void AnnotateUnpublishMemoryRange(const char *file, int line, - const volatile void *address, - long size); -void AnnotatePCQCreate(const char *file, int line, - const volatile void *pcq); -void AnnotatePCQDestroy(const char *file, int line, - const volatile void *pcq); -void AnnotatePCQPut(const char *file, int line, - const volatile void *pcq); -void AnnotatePCQGet(const char *file, int line, - const volatile void *pcq); -void AnnotateNewMemory(const char *file, int line, - const volatile void *address, - long size); -void AnnotateExpectRace(const char *file, int line, - const volatile void *address, - const char *description); -void AnnotateBenignRace(const char *file, int line, - const volatile void *address, - const char *description); -void AnnotateBenignRaceSized(const char *file, int line, - const volatile void *address, - long size, - const char *description); -void AnnotateMutexIsUsedAsCondVar(const char *file, int line, - const volatile void *mu); -void AnnotateTraceMemory(const char *file, int line, - const volatile void *arg); -void AnnotateThreadName(const char *file, int line, - const char *name); -void AnnotateIgnoreReadsBegin(const char *file, int line); -void AnnotateIgnoreReadsEnd(const char *file, int line); -void AnnotateIgnoreWritesBegin(const char *file, int line); -void AnnotateIgnoreWritesEnd(const char *file, int line); -void AnnotateEnableRaceDetection(const char *file, int line, int enable); -void AnnotateNoOp(const char *file, int line, - const volatile void *arg); -void AnnotateFlushState(const char *file, int line); - -/* Return non-zero value if running under valgrind. - - If "valgrind.h" is included into dynamic_annotations.c, - the regular valgrind mechanism will be used. - See http://valgrind.org/docs/manual/manual-core-adv.html about - RUNNING_ON_VALGRIND and other valgrind "client requests". - The file "valgrind.h" may be obtained by doing - svn co svn://svn.valgrind.org/valgrind/trunk/include - - If for some reason you can't use "valgrind.h" or want to fake valgrind, - there are two ways to make this function return non-zero: - - Use environment variable: export RUNNING_ON_VALGRIND=1 - - Make your tool intercept the function RunningOnValgrind() and - change its return value. - */ -int RunningOnValgrind(void); - -#ifdef __cplusplus -} -#endif - -#if DYNAMIC_ANNOTATIONS_ENABLED != 0 && defined(__cplusplus) - - /* _Py_ANNOTATE_UNPROTECTED_READ is the preferred way to annotate racey reads. - - Instead of doing - _Py_ANNOTATE_IGNORE_READS_BEGIN(); - ... = x; - _Py_ANNOTATE_IGNORE_READS_END(); - one can use - ... = _Py_ANNOTATE_UNPROTECTED_READ(x); */ - template - inline T _Py_ANNOTATE_UNPROTECTED_READ(const volatile T &x) { - _Py_ANNOTATE_IGNORE_READS_BEGIN(); - T res = x; - _Py_ANNOTATE_IGNORE_READS_END(); - return res; - } - /* Apply _Py_ANNOTATE_BENIGN_RACE_SIZED to a static variable. */ -#define _Py_ANNOTATE_BENIGN_RACE_STATIC(static_var, description) \ - namespace { \ - class static_var ## _annotator { \ - public: \ - static_var ## _annotator() { \ - _Py_ANNOTATE_BENIGN_RACE_SIZED(&static_var, \ - sizeof(static_var), \ - # static_var ": " description); \ - } \ - }; \ - static static_var ## _annotator the ## static_var ## _annotator;\ - } -#else /* DYNAMIC_ANNOTATIONS_ENABLED == 0 */ - -#define _Py_ANNOTATE_UNPROTECTED_READ(x) (x) -#define _Py_ANNOTATE_BENIGN_RACE_STATIC(static_var, description) /* empty */ - -#endif /* DYNAMIC_ANNOTATIONS_ENABLED */ - -#endif /* __DYNAMIC_ANNOTATIONS_H__ */ diff --git a/scripts/build-windows/py39-libs/include/enumobject.h b/scripts/build-windows/py39-libs/include/enumobject.h deleted file mode 100644 index c14dbfc8c..000000000 --- a/scripts/build-windows/py39-libs/include/enumobject.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef Py_ENUMOBJECT_H -#define Py_ENUMOBJECT_H - -/* Enumerate Object */ - -#ifdef __cplusplus -extern "C" { -#endif - -PyAPI_DATA(PyTypeObject) PyEnum_Type; -PyAPI_DATA(PyTypeObject) PyReversed_Type; - -#ifdef __cplusplus -} -#endif - -#endif /* !Py_ENUMOBJECT_H */ diff --git a/scripts/build-windows/py39-libs/include/errcode.h b/scripts/build-windows/py39-libs/include/errcode.h deleted file mode 100644 index 790518b8b..000000000 --- a/scripts/build-windows/py39-libs/include/errcode.h +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef Py_ERRCODE_H -#define Py_ERRCODE_H -#ifdef __cplusplus -extern "C" { -#endif - - -/* Error codes passed around between file input, tokenizer, parser and - interpreter. This is necessary so we can turn them into Python - exceptions at a higher level. Note that some errors have a - slightly different meaning when passed from the tokenizer to the - parser than when passed from the parser to the interpreter; e.g. - the parser only returns E_EOF when it hits EOF immediately, and it - never returns E_OK. */ - -#define E_OK 10 /* No error */ -#define E_EOF 11 /* End Of File */ -#define E_INTR 12 /* Interrupted */ -#define E_TOKEN 13 /* Bad token */ -#define E_SYNTAX 14 /* Syntax error */ -#define E_NOMEM 15 /* Ran out of memory */ -#define E_DONE 16 /* Parsing complete */ -#define E_ERROR 17 /* Execution error */ -#define E_TABSPACE 18 /* Inconsistent mixing of tabs and spaces */ -#define E_OVERFLOW 19 /* Node had too many children */ -#define E_TOODEEP 20 /* Too many indentation levels */ -#define E_DEDENT 21 /* No matching outer block for dedent */ -#define E_DECODE 22 /* Error in decoding into Unicode */ -#define E_EOFS 23 /* EOF in triple-quoted string */ -#define E_EOLS 24 /* EOL in single-quoted string */ -#define E_LINECONT 25 /* Unexpected characters after a line continuation */ -#define E_BADSINGLE 27 /* Ill-formed single statement input */ - -#ifdef __cplusplus -} -#endif -#endif /* !Py_ERRCODE_H */ diff --git a/scripts/build-windows/py39-libs/include/eval.h b/scripts/build-windows/py39-libs/include/eval.h deleted file mode 100644 index 2c1c2d054..000000000 --- a/scripts/build-windows/py39-libs/include/eval.h +++ /dev/null @@ -1,37 +0,0 @@ - -/* Interface to execute compiled code */ - -#ifndef Py_EVAL_H -#define Py_EVAL_H -#ifdef __cplusplus -extern "C" { -#endif - -PyAPI_FUNC(PyObject *) PyEval_EvalCode(PyObject *, PyObject *, PyObject *); - -PyAPI_FUNC(PyObject *) PyEval_EvalCodeEx(PyObject *co, - PyObject *globals, - PyObject *locals, - PyObject *const *args, int argc, - PyObject *const *kwds, int kwdc, - PyObject *const *defs, int defc, - PyObject *kwdefs, PyObject *closure); - -#ifndef Py_LIMITED_API -PyAPI_FUNC(PyObject *) _PyEval_EvalCodeWithName( - PyObject *co, - PyObject *globals, PyObject *locals, - PyObject *const *args, Py_ssize_t argcount, - PyObject *const *kwnames, PyObject *const *kwargs, - Py_ssize_t kwcount, int kwstep, - PyObject *const *defs, Py_ssize_t defcount, - PyObject *kwdefs, PyObject *closure, - PyObject *name, PyObject *qualname); - -PyAPI_FUNC(PyObject *) _PyEval_CallTracing(PyObject *func, PyObject *args); -#endif - -#ifdef __cplusplus -} -#endif -#endif /* !Py_EVAL_H */ diff --git a/scripts/build-windows/py39-libs/include/exports.h b/scripts/build-windows/py39-libs/include/exports.h deleted file mode 100644 index fc1a5c5ea..000000000 --- a/scripts/build-windows/py39-libs/include/exports.h +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef Py_EXPORTS_H -#define Py_EXPORTS_H - -#if defined(_WIN32) || defined(__CYGWIN__) - #define Py_IMPORTED_SYMBOL __declspec(dllimport) - #define Py_EXPORTED_SYMBOL __declspec(dllexport) - #define Py_LOCAL_SYMBOL -#else -/* - * If we only ever used gcc >= 5, we could use __has_attribute(visibility) - * as a cross-platform way to determine if visibility is supported. However, - * we may still need to support gcc >= 4, as some Ubuntu LTS and Centos versions - * have 4 < gcc < 5. - */ - #ifndef __has_attribute - #define __has_attribute(x) 0 // Compatibility with non-clang compilers. - #endif - #if (defined(__GNUC__) && (__GNUC__ >= 4)) ||\ - (defined(__clang__) && __has_attribute(visibility)) - #define Py_IMPORTED_SYMBOL __attribute__ ((visibility ("default"))) - #define Py_EXPORTED_SYMBOL __attribute__ ((visibility ("default"))) - #define Py_LOCAL_SYMBOL __attribute__ ((visibility ("hidden"))) - #else - #define Py_IMPORTED_SYMBOL - #define Py_EXPORTED_SYMBOL - #define Py_LOCAL_SYMBOL - #endif -#endif - -#endif /* Py_EXPORTS_H */ diff --git a/scripts/build-windows/py39-libs/include/fileobject.h b/scripts/build-windows/py39-libs/include/fileobject.h deleted file mode 100644 index 6ec2994aa..000000000 --- a/scripts/build-windows/py39-libs/include/fileobject.h +++ /dev/null @@ -1,49 +0,0 @@ -/* File object interface (what's left of it -- see io.py) */ - -#ifndef Py_FILEOBJECT_H -#define Py_FILEOBJECT_H -#ifdef __cplusplus -extern "C" { -#endif - -#define PY_STDIOTEXTMODE "b" - -PyAPI_FUNC(PyObject *) PyFile_FromFd(int, const char *, const char *, int, - const char *, const char *, - const char *, int); -PyAPI_FUNC(PyObject *) PyFile_GetLine(PyObject *, int); -PyAPI_FUNC(int) PyFile_WriteObject(PyObject *, PyObject *, int); -PyAPI_FUNC(int) PyFile_WriteString(const char *, PyObject *); -PyAPI_FUNC(int) PyObject_AsFileDescriptor(PyObject *); - -/* The default encoding used by the platform file system APIs - If non-NULL, this is different than the default encoding for strings -*/ -PyAPI_DATA(const char *) Py_FileSystemDefaultEncoding; -#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03060000 -PyAPI_DATA(const char *) Py_FileSystemDefaultEncodeErrors; -#endif -PyAPI_DATA(int) Py_HasFileSystemDefaultEncoding; - -#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03070000 -PyAPI_DATA(int) Py_UTF8Mode; -#endif - -/* A routine to check if a file descriptor can be select()-ed. */ -#ifdef _MSC_VER - /* On Windows, any socket fd can be select()-ed, no matter how high */ - #define _PyIsSelectable_fd(FD) (1) -#else - #define _PyIsSelectable_fd(FD) ((unsigned int)(FD) < (unsigned int)FD_SETSIZE) -#endif - -#ifndef Py_LIMITED_API -# define Py_CPYTHON_FILEOBJECT_H -# include "cpython/fileobject.h" -# undef Py_CPYTHON_FILEOBJECT_H -#endif - -#ifdef __cplusplus -} -#endif -#endif /* !Py_FILEOBJECT_H */ diff --git a/scripts/build-windows/py39-libs/include/fileutils.h b/scripts/build-windows/py39-libs/include/fileutils.h deleted file mode 100644 index 12bd071c4..000000000 --- a/scripts/build-windows/py39-libs/include/fileutils.h +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef Py_FILEUTILS_H -#define Py_FILEUTILS_H -#ifdef __cplusplus -extern "C" { -#endif - -#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03050000 -PyAPI_FUNC(wchar_t *) Py_DecodeLocale( - const char *arg, - size_t *size); - -PyAPI_FUNC(char*) Py_EncodeLocale( - const wchar_t *text, - size_t *error_pos); - -PyAPI_FUNC(char*) _Py_EncodeLocaleRaw( - const wchar_t *text, - size_t *error_pos); -#endif - -#ifndef Py_LIMITED_API -# define Py_CPYTHON_FILEUTILS_H -# include "cpython/fileutils.h" -# undef Py_CPYTHON_FILEUTILS_H -#endif - -#ifdef __cplusplus -} -#endif -#endif /* !Py_FILEUTILS_H */ diff --git a/scripts/build-windows/py39-libs/include/floatobject.h b/scripts/build-windows/py39-libs/include/floatobject.h deleted file mode 100644 index e994aa8f2..000000000 --- a/scripts/build-windows/py39-libs/include/floatobject.h +++ /dev/null @@ -1,118 +0,0 @@ - -/* Float object interface */ - -/* -PyFloatObject represents a (double precision) floating point number. -*/ - -#ifndef Py_FLOATOBJECT_H -#define Py_FLOATOBJECT_H -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef Py_LIMITED_API -typedef struct { - PyObject_HEAD - double ob_fval; -} PyFloatObject; -#endif - -PyAPI_DATA(PyTypeObject) PyFloat_Type; - -#define PyFloat_Check(op) PyObject_TypeCheck(op, &PyFloat_Type) -#define PyFloat_CheckExact(op) Py_IS_TYPE(op, &PyFloat_Type) - -#ifdef Py_NAN -#define Py_RETURN_NAN return PyFloat_FromDouble(Py_NAN) -#endif - -#define Py_RETURN_INF(sign) do \ - if (copysign(1., sign) == 1.) { \ - return PyFloat_FromDouble(Py_HUGE_VAL); \ - } else { \ - return PyFloat_FromDouble(-Py_HUGE_VAL); \ - } while(0) - -PyAPI_FUNC(double) PyFloat_GetMax(void); -PyAPI_FUNC(double) PyFloat_GetMin(void); -PyAPI_FUNC(PyObject *) PyFloat_GetInfo(void); - -/* Return Python float from string PyObject. */ -PyAPI_FUNC(PyObject *) PyFloat_FromString(PyObject*); - -/* Return Python float from C double. */ -PyAPI_FUNC(PyObject *) PyFloat_FromDouble(double); - -/* Extract C double from Python float. The macro version trades safety for - speed. */ -PyAPI_FUNC(double) PyFloat_AsDouble(PyObject *); -#ifndef Py_LIMITED_API -#define PyFloat_AS_DOUBLE(op) (((PyFloatObject *)(op))->ob_fval) -#endif - -#ifndef Py_LIMITED_API -/* _PyFloat_{Pack,Unpack}{4,8} - * - * The struct and pickle (at least) modules need an efficient platform- - * independent way to store floating-point values as byte strings. - * The Pack routines produce a string from a C double, and the Unpack - * routines produce a C double from such a string. The suffix (4 or 8) - * specifies the number of bytes in the string. - * - * On platforms that appear to use (see _PyFloat_Init()) IEEE-754 formats - * these functions work by copying bits. On other platforms, the formats the - * 4- byte format is identical to the IEEE-754 single precision format, and - * the 8-byte format to the IEEE-754 double precision format, although the - * packing of INFs and NaNs (if such things exist on the platform) isn't - * handled correctly, and attempting to unpack a string containing an IEEE - * INF or NaN will raise an exception. - * - * On non-IEEE platforms with more precision, or larger dynamic range, than - * 754 supports, not all values can be packed; on non-IEEE platforms with less - * precision, or smaller dynamic range, not all values can be unpacked. What - * happens in such cases is partly accidental (alas). - */ - -/* The pack routines write 2, 4 or 8 bytes, starting at p. le is a bool - * argument, true if you want the string in little-endian format (exponent - * last, at p+1, p+3 or p+7), false if you want big-endian format (exponent - * first, at p). - * Return value: 0 if all is OK, -1 if error (and an exception is - * set, most likely OverflowError). - * There are two problems on non-IEEE platforms: - * 1): What this does is undefined if x is a NaN or infinity. - * 2): -0.0 and +0.0 produce the same string. - */ -PyAPI_FUNC(int) _PyFloat_Pack2(double x, unsigned char *p, int le); -PyAPI_FUNC(int) _PyFloat_Pack4(double x, unsigned char *p, int le); -PyAPI_FUNC(int) _PyFloat_Pack8(double x, unsigned char *p, int le); - -/* The unpack routines read 2, 4 or 8 bytes, starting at p. le is a bool - * argument, true if the string is in little-endian format (exponent - * last, at p+1, p+3 or p+7), false if big-endian (exponent first, at p). - * Return value: The unpacked double. On error, this is -1.0 and - * PyErr_Occurred() is true (and an exception is set, most likely - * OverflowError). Note that on a non-IEEE platform this will refuse - * to unpack a string that represents a NaN or infinity. - */ -PyAPI_FUNC(double) _PyFloat_Unpack2(const unsigned char *p, int le); -PyAPI_FUNC(double) _PyFloat_Unpack4(const unsigned char *p, int le); -PyAPI_FUNC(double) _PyFloat_Unpack8(const unsigned char *p, int le); - -PyAPI_FUNC(void) _PyFloat_DebugMallocStats(FILE* out); - -/* Format the object based on the format_spec, as defined in PEP 3101 - (Advanced String Formatting). */ -PyAPI_FUNC(int) _PyFloat_FormatAdvancedWriter( - _PyUnicodeWriter *writer, - PyObject *obj, - PyObject *format_spec, - Py_ssize_t start, - Py_ssize_t end); -#endif /* Py_LIMITED_API */ - -#ifdef __cplusplus -} -#endif -#endif /* !Py_FLOATOBJECT_H */ diff --git a/scripts/build-windows/py39-libs/include/frameobject.h b/scripts/build-windows/py39-libs/include/frameobject.h deleted file mode 100644 index c118af120..000000000 --- a/scripts/build-windows/py39-libs/include/frameobject.h +++ /dev/null @@ -1,20 +0,0 @@ -/* Frame object interface */ - -#ifndef Py_FRAMEOBJECT_H -#define Py_FRAMEOBJECT_H -#ifdef __cplusplus -extern "C" { -#endif - -#include "pyframe.h" - -#ifndef Py_LIMITED_API -# define Py_CPYTHON_FRAMEOBJECT_H -# include "cpython/frameobject.h" -# undef Py_CPYTHON_FRAMEOBJECT_H -#endif - -#ifdef __cplusplus -} -#endif -#endif /* !Py_FRAMEOBJECT_H */ diff --git a/scripts/build-windows/py39-libs/include/funcobject.h b/scripts/build-windows/py39-libs/include/funcobject.h deleted file mode 100644 index c5cc9d261..000000000 --- a/scripts/build-windows/py39-libs/include/funcobject.h +++ /dev/null @@ -1,98 +0,0 @@ - -/* Function object interface */ -#ifndef Py_LIMITED_API -#ifndef Py_FUNCOBJECT_H -#define Py_FUNCOBJECT_H -#ifdef __cplusplus -extern "C" { -#endif - -/* Function objects and code objects should not be confused with each other: - * - * Function objects are created by the execution of the 'def' statement. - * They reference a code object in their __code__ attribute, which is a - * purely syntactic object, i.e. nothing more than a compiled version of some - * source code lines. There is one code object per source code "fragment", - * but each code object can be referenced by zero or many function objects - * depending only on how many times the 'def' statement in the source was - * executed so far. - */ - -typedef struct { - PyObject_HEAD - PyObject *func_code; /* A code object, the __code__ attribute */ - PyObject *func_globals; /* A dictionary (other mappings won't do) */ - PyObject *func_defaults; /* NULL or a tuple */ - PyObject *func_kwdefaults; /* NULL or a dict */ - PyObject *func_closure; /* NULL or a tuple of cell objects */ - PyObject *func_doc; /* The __doc__ attribute, can be anything */ - PyObject *func_name; /* The __name__ attribute, a string object */ - PyObject *func_dict; /* The __dict__ attribute, a dict or NULL */ - PyObject *func_weakreflist; /* List of weak references */ - PyObject *func_module; /* The __module__ attribute, can be anything */ - PyObject *func_annotations; /* Annotations, a dict or NULL */ - PyObject *func_qualname; /* The qualified name */ - vectorcallfunc vectorcall; - - /* Invariant: - * func_closure contains the bindings for func_code->co_freevars, so - * PyTuple_Size(func_closure) == PyCode_GetNumFree(func_code) - * (func_closure may be NULL if PyCode_GetNumFree(func_code) == 0). - */ -} PyFunctionObject; - -PyAPI_DATA(PyTypeObject) PyFunction_Type; - -#define PyFunction_Check(op) Py_IS_TYPE(op, &PyFunction_Type) - -PyAPI_FUNC(PyObject *) PyFunction_New(PyObject *, PyObject *); -PyAPI_FUNC(PyObject *) PyFunction_NewWithQualName(PyObject *, PyObject *, PyObject *); -PyAPI_FUNC(PyObject *) PyFunction_GetCode(PyObject *); -PyAPI_FUNC(PyObject *) PyFunction_GetGlobals(PyObject *); -PyAPI_FUNC(PyObject *) PyFunction_GetModule(PyObject *); -PyAPI_FUNC(PyObject *) PyFunction_GetDefaults(PyObject *); -PyAPI_FUNC(int) PyFunction_SetDefaults(PyObject *, PyObject *); -PyAPI_FUNC(PyObject *) PyFunction_GetKwDefaults(PyObject *); -PyAPI_FUNC(int) PyFunction_SetKwDefaults(PyObject *, PyObject *); -PyAPI_FUNC(PyObject *) PyFunction_GetClosure(PyObject *); -PyAPI_FUNC(int) PyFunction_SetClosure(PyObject *, PyObject *); -PyAPI_FUNC(PyObject *) PyFunction_GetAnnotations(PyObject *); -PyAPI_FUNC(int) PyFunction_SetAnnotations(PyObject *, PyObject *); - -#ifndef Py_LIMITED_API -PyAPI_FUNC(PyObject *) _PyFunction_Vectorcall( - PyObject *func, - PyObject *const *stack, - size_t nargsf, - PyObject *kwnames); -#endif - -/* Macros for direct access to these values. Type checks are *not* - done, so use with care. */ -#define PyFunction_GET_CODE(func) \ - (((PyFunctionObject *)func) -> func_code) -#define PyFunction_GET_GLOBALS(func) \ - (((PyFunctionObject *)func) -> func_globals) -#define PyFunction_GET_MODULE(func) \ - (((PyFunctionObject *)func) -> func_module) -#define PyFunction_GET_DEFAULTS(func) \ - (((PyFunctionObject *)func) -> func_defaults) -#define PyFunction_GET_KW_DEFAULTS(func) \ - (((PyFunctionObject *)func) -> func_kwdefaults) -#define PyFunction_GET_CLOSURE(func) \ - (((PyFunctionObject *)func) -> func_closure) -#define PyFunction_GET_ANNOTATIONS(func) \ - (((PyFunctionObject *)func) -> func_annotations) - -/* The classmethod and staticmethod types lives here, too */ -PyAPI_DATA(PyTypeObject) PyClassMethod_Type; -PyAPI_DATA(PyTypeObject) PyStaticMethod_Type; - -PyAPI_FUNC(PyObject *) PyClassMethod_New(PyObject *); -PyAPI_FUNC(PyObject *) PyStaticMethod_New(PyObject *); - -#ifdef __cplusplus -} -#endif -#endif /* !Py_FUNCOBJECT_H */ -#endif /* Py_LIMITED_API */ diff --git a/scripts/build-windows/py39-libs/include/genericaliasobject.h b/scripts/build-windows/py39-libs/include/genericaliasobject.h deleted file mode 100644 index cf002976b..000000000 --- a/scripts/build-windows/py39-libs/include/genericaliasobject.h +++ /dev/null @@ -1,14 +0,0 @@ -// Implementation of PEP 585: support list[int] etc. -#ifndef Py_GENERICALIASOBJECT_H -#define Py_GENERICALIASOBJECT_H -#ifdef __cplusplus -extern "C" { -#endif - -PyAPI_FUNC(PyObject *) Py_GenericAlias(PyObject *, PyObject *); -PyAPI_DATA(PyTypeObject) Py_GenericAliasType; - -#ifdef __cplusplus -} -#endif -#endif /* !Py_GENERICALIASOBJECT_H */ diff --git a/scripts/build-windows/py39-libs/include/genobject.h b/scripts/build-windows/py39-libs/include/genobject.h deleted file mode 100644 index 8ffd15646..000000000 --- a/scripts/build-windows/py39-libs/include/genobject.h +++ /dev/null @@ -1,102 +0,0 @@ - -/* Generator object interface */ - -#ifndef Py_LIMITED_API -#ifndef Py_GENOBJECT_H -#define Py_GENOBJECT_H -#ifdef __cplusplus -extern "C" { -#endif - -#include "pystate.h" /* _PyErr_StackItem */ - -/* _PyGenObject_HEAD defines the initial segment of generator - and coroutine objects. */ -#define _PyGenObject_HEAD(prefix) \ - PyObject_HEAD \ - /* Note: gi_frame can be NULL if the generator is "finished" */ \ - PyFrameObject *prefix##_frame; \ - /* True if generator is being executed. */ \ - char prefix##_running; \ - /* The code object backing the generator */ \ - PyObject *prefix##_code; \ - /* List of weak reference. */ \ - PyObject *prefix##_weakreflist; \ - /* Name of the generator. */ \ - PyObject *prefix##_name; \ - /* Qualified name of the generator. */ \ - PyObject *prefix##_qualname; \ - _PyErr_StackItem prefix##_exc_state; - -typedef struct { - /* The gi_ prefix is intended to remind of generator-iterator. */ - _PyGenObject_HEAD(gi) -} PyGenObject; - -PyAPI_DATA(PyTypeObject) PyGen_Type; - -#define PyGen_Check(op) PyObject_TypeCheck(op, &PyGen_Type) -#define PyGen_CheckExact(op) Py_IS_TYPE(op, &PyGen_Type) - -PyAPI_FUNC(PyObject *) PyGen_New(PyFrameObject *); -PyAPI_FUNC(PyObject *) PyGen_NewWithQualName(PyFrameObject *, - PyObject *name, PyObject *qualname); -PyAPI_FUNC(int) _PyGen_SetStopIterationValue(PyObject *); -PyAPI_FUNC(int) _PyGen_FetchStopIterationValue(PyObject **); -PyAPI_FUNC(PyObject *) _PyGen_Send(PyGenObject *, PyObject *); -PyObject *_PyGen_yf(PyGenObject *); -PyAPI_FUNC(void) _PyGen_Finalize(PyObject *self); - -#ifndef Py_LIMITED_API -typedef struct { - _PyGenObject_HEAD(cr) - PyObject *cr_origin; -} PyCoroObject; - -PyAPI_DATA(PyTypeObject) PyCoro_Type; -PyAPI_DATA(PyTypeObject) _PyCoroWrapper_Type; - -#define PyCoro_CheckExact(op) Py_IS_TYPE(op, &PyCoro_Type) -PyObject *_PyCoro_GetAwaitableIter(PyObject *o); -PyAPI_FUNC(PyObject *) PyCoro_New(PyFrameObject *, - PyObject *name, PyObject *qualname); - -/* Asynchronous Generators */ - -typedef struct { - _PyGenObject_HEAD(ag) - PyObject *ag_finalizer; - - /* Flag is set to 1 when hooks set up by sys.set_asyncgen_hooks - were called on the generator, to avoid calling them more - than once. */ - int ag_hooks_inited; - - /* Flag is set to 1 when aclose() is called for the first time, or - when a StopAsyncIteration exception is raised. */ - int ag_closed; - - int ag_running_async; -} PyAsyncGenObject; - -PyAPI_DATA(PyTypeObject) PyAsyncGen_Type; -PyAPI_DATA(PyTypeObject) _PyAsyncGenASend_Type; -PyAPI_DATA(PyTypeObject) _PyAsyncGenWrappedValue_Type; -PyAPI_DATA(PyTypeObject) _PyAsyncGenAThrow_Type; - -PyAPI_FUNC(PyObject *) PyAsyncGen_New(PyFrameObject *, - PyObject *name, PyObject *qualname); - -#define PyAsyncGen_CheckExact(op) Py_IS_TYPE(op, &PyAsyncGen_Type) - -PyObject *_PyAsyncGenValueWrapperNew(PyObject *); - -#endif - -#undef _PyGenObject_HEAD - -#ifdef __cplusplus -} -#endif -#endif /* !Py_GENOBJECT_H */ -#endif /* Py_LIMITED_API */ diff --git a/scripts/build-windows/py39-libs/include/graminit.h b/scripts/build-windows/py39-libs/include/graminit.h deleted file mode 100644 index d1027b7a7..000000000 --- a/scripts/build-windows/py39-libs/include/graminit.h +++ /dev/null @@ -1,94 +0,0 @@ -/* Generated by Parser/pgen */ - -#define single_input 256 -#define file_input 257 -#define eval_input 258 -#define decorator 259 -#define decorators 260 -#define decorated 261 -#define async_funcdef 262 -#define funcdef 263 -#define parameters 264 -#define typedargslist 265 -#define tfpdef 266 -#define varargslist 267 -#define vfpdef 268 -#define stmt 269 -#define simple_stmt 270 -#define small_stmt 271 -#define expr_stmt 272 -#define annassign 273 -#define testlist_star_expr 274 -#define augassign 275 -#define del_stmt 276 -#define pass_stmt 277 -#define flow_stmt 278 -#define break_stmt 279 -#define continue_stmt 280 -#define return_stmt 281 -#define yield_stmt 282 -#define raise_stmt 283 -#define import_stmt 284 -#define import_name 285 -#define import_from 286 -#define import_as_name 287 -#define dotted_as_name 288 -#define import_as_names 289 -#define dotted_as_names 290 -#define dotted_name 291 -#define global_stmt 292 -#define nonlocal_stmt 293 -#define assert_stmt 294 -#define compound_stmt 295 -#define async_stmt 296 -#define if_stmt 297 -#define while_stmt 298 -#define for_stmt 299 -#define try_stmt 300 -#define with_stmt 301 -#define with_item 302 -#define except_clause 303 -#define suite 304 -#define namedexpr_test 305 -#define test 306 -#define test_nocond 307 -#define lambdef 308 -#define lambdef_nocond 309 -#define or_test 310 -#define and_test 311 -#define not_test 312 -#define comparison 313 -#define comp_op 314 -#define star_expr 315 -#define expr 316 -#define xor_expr 317 -#define and_expr 318 -#define shift_expr 319 -#define arith_expr 320 -#define term 321 -#define factor 322 -#define power 323 -#define atom_expr 324 -#define atom 325 -#define testlist_comp 326 -#define trailer 327 -#define subscriptlist 328 -#define subscript 329 -#define sliceop 330 -#define exprlist 331 -#define testlist 332 -#define dictorsetmaker 333 -#define classdef 334 -#define arglist 335 -#define argument 336 -#define comp_iter 337 -#define sync_comp_for 338 -#define comp_for 339 -#define comp_if 340 -#define encoding_decl 341 -#define yield_expr 342 -#define yield_arg 343 -#define func_body_suite 344 -#define func_type_input 345 -#define func_type 346 -#define typelist 347 diff --git a/scripts/build-windows/py39-libs/include/grammar.h b/scripts/build-windows/py39-libs/include/grammar.h deleted file mode 100644 index 4b66b1e9b..000000000 --- a/scripts/build-windows/py39-libs/include/grammar.h +++ /dev/null @@ -1,77 +0,0 @@ - -/* Grammar interface */ - -#ifndef Py_GRAMMAR_H -#define Py_GRAMMAR_H -#ifdef __cplusplus -extern "C" { -#endif - -#include "bitset.h" /* Sigh... */ - -/* A label of an arc */ - -typedef struct { - int lb_type; - const char *lb_str; -} label; - -#define EMPTY 0 /* Label number 0 is by definition the empty label */ - -/* A list of labels */ - -typedef struct { - int ll_nlabels; - const label *ll_label; -} labellist; - -/* An arc from one state to another */ - -typedef struct { - short a_lbl; /* Label of this arc */ - short a_arrow; /* State where this arc goes to */ -} arc; - -/* A state in a DFA */ - -typedef struct { - int s_narcs; - const arc *s_arc; /* Array of arcs */ - - /* Optional accelerators */ - int s_lower; /* Lowest label index */ - int s_upper; /* Highest label index */ - int *s_accel; /* Accelerator */ - int s_accept; /* Nonzero for accepting state */ -} state; - -/* A DFA */ - -typedef struct { - int d_type; /* Non-terminal this represents */ - char *d_name; /* For printing */ - int d_nstates; - state *d_state; /* Array of states */ - bitset d_first; -} dfa; - -/* A grammar */ - -typedef struct { - int g_ndfas; - const dfa *g_dfa; /* Array of DFAs */ - const labellist g_ll; - int g_start; /* Start symbol of the grammar */ - int g_accel; /* Set if accelerators present */ -} grammar; - -/* FUNCTIONS */ -const dfa *PyGrammar_FindDFA(grammar *g, int type); -const char *PyGrammar_LabelRepr(label *lb); -void PyGrammar_AddAccelerators(grammar *g); -void PyGrammar_RemoveAccelerators(grammar *); - -#ifdef __cplusplus -} -#endif -#endif /* !Py_GRAMMAR_H */ diff --git a/scripts/build-windows/py39-libs/include/import.h b/scripts/build-windows/py39-libs/include/import.h deleted file mode 100644 index aeef3efd0..000000000 --- a/scripts/build-windows/py39-libs/include/import.h +++ /dev/null @@ -1,98 +0,0 @@ -/* Module definition and import interface */ - -#ifndef Py_IMPORT_H -#define Py_IMPORT_H -#ifdef __cplusplus -extern "C" { -#endif - -PyAPI_FUNC(long) PyImport_GetMagicNumber(void); -PyAPI_FUNC(const char *) PyImport_GetMagicTag(void); -PyAPI_FUNC(PyObject *) PyImport_ExecCodeModule( - const char *name, /* UTF-8 encoded string */ - PyObject *co - ); -PyAPI_FUNC(PyObject *) PyImport_ExecCodeModuleEx( - const char *name, /* UTF-8 encoded string */ - PyObject *co, - const char *pathname /* decoded from the filesystem encoding */ - ); -PyAPI_FUNC(PyObject *) PyImport_ExecCodeModuleWithPathnames( - const char *name, /* UTF-8 encoded string */ - PyObject *co, - const char *pathname, /* decoded from the filesystem encoding */ - const char *cpathname /* decoded from the filesystem encoding */ - ); -#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03030000 -PyAPI_FUNC(PyObject *) PyImport_ExecCodeModuleObject( - PyObject *name, - PyObject *co, - PyObject *pathname, - PyObject *cpathname - ); -#endif -PyAPI_FUNC(PyObject *) PyImport_GetModuleDict(void); -#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03070000 -PyAPI_FUNC(PyObject *) PyImport_GetModule(PyObject *name); -#endif -#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03030000 -PyAPI_FUNC(PyObject *) PyImport_AddModuleObject( - PyObject *name - ); -#endif -PyAPI_FUNC(PyObject *) PyImport_AddModule( - const char *name /* UTF-8 encoded string */ - ); -PyAPI_FUNC(PyObject *) PyImport_ImportModule( - const char *name /* UTF-8 encoded string */ - ); -PyAPI_FUNC(PyObject *) PyImport_ImportModuleNoBlock( - const char *name /* UTF-8 encoded string */ - ); -PyAPI_FUNC(PyObject *) PyImport_ImportModuleLevel( - const char *name, /* UTF-8 encoded string */ - PyObject *globals, - PyObject *locals, - PyObject *fromlist, - int level - ); -#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03050000 -PyAPI_FUNC(PyObject *) PyImport_ImportModuleLevelObject( - PyObject *name, - PyObject *globals, - PyObject *locals, - PyObject *fromlist, - int level - ); -#endif - -#define PyImport_ImportModuleEx(n, g, l, f) \ - PyImport_ImportModuleLevel(n, g, l, f, 0) - -PyAPI_FUNC(PyObject *) PyImport_GetImporter(PyObject *path); -PyAPI_FUNC(PyObject *) PyImport_Import(PyObject *name); -PyAPI_FUNC(PyObject *) PyImport_ReloadModule(PyObject *m); -#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03030000 -PyAPI_FUNC(int) PyImport_ImportFrozenModuleObject( - PyObject *name - ); -#endif -PyAPI_FUNC(int) PyImport_ImportFrozenModule( - const char *name /* UTF-8 encoded string */ - ); - -PyAPI_FUNC(int) PyImport_AppendInittab( - const char *name, /* ASCII encoded string */ - PyObject* (*initfunc)(void) - ); - -#ifndef Py_LIMITED_API -# define Py_CPYTHON_IMPORT_H -# include "cpython/import.h" -# undef Py_CPYTHON_IMPORT_H -#endif - -#ifdef __cplusplus -} -#endif -#endif /* !Py_IMPORT_H */ diff --git a/scripts/build-windows/py39-libs/include/internal/pegen_interface.h b/scripts/build-windows/py39-libs/include/internal/pegen_interface.h deleted file mode 100644 index ee4c77ec0..000000000 --- a/scripts/build-windows/py39-libs/include/internal/pegen_interface.h +++ /dev/null @@ -1,46 +0,0 @@ -#ifndef Py_PEGENINTERFACE -#define Py_PEGENINTERFACE -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef Py_BUILD_CORE -# error "this header requires Py_BUILD_CORE define" -#endif - -#include "Python.h" -#include "Python-ast.h" - -PyAPI_FUNC(mod_ty) PyPegen_ASTFromString( - const char *str, - const char *filename, - int mode, - PyCompilerFlags *flags, - PyArena *arena); -PyAPI_FUNC(mod_ty) PyPegen_ASTFromStringObject( - const char *str, - PyObject* filename, - int mode, - PyCompilerFlags *flags, - PyArena *arena); -PyAPI_FUNC(mod_ty) PyPegen_ASTFromFileObject( - FILE *fp, - PyObject *filename_ob, - int mode, - const char *enc, - const char *ps1, - const char *ps2, - PyCompilerFlags *flags, - int *errcode, - PyArena *arena); -PyAPI_FUNC(mod_ty) PyPegen_ASTFromFilename( - const char *filename, - int mode, - PyCompilerFlags *flags, - PyArena *arena); - - -#ifdef __cplusplus -} -#endif -#endif /* !Py_PEGENINTERFACE*/ diff --git a/scripts/build-windows/py39-libs/include/internal/pycore_abstract.h b/scripts/build-windows/py39-libs/include/internal/pycore_abstract.h deleted file mode 100644 index b791bf243..000000000 --- a/scripts/build-windows/py39-libs/include/internal/pycore_abstract.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef Py_INTERNAL_ABSTRACT_H -#define Py_INTERNAL_ABSTRACT_H -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef Py_BUILD_CORE -# error "this header requires Py_BUILD_CORE define" -#endif - -// Fast inlined version of PyIndex_Check() -static inline int -_PyIndex_Check(PyObject *obj) -{ - PyNumberMethods *tp_as_number = Py_TYPE(obj)->tp_as_number; - return (tp_as_number != NULL && tp_as_number->nb_index != NULL); -} - -#ifdef __cplusplus -} -#endif -#endif /* !Py_INTERNAL_ABSTRACT_H */ diff --git a/scripts/build-windows/py39-libs/include/internal/pycore_accu.h b/scripts/build-windows/py39-libs/include/internal/pycore_accu.h deleted file mode 100644 index d346222e4..000000000 --- a/scripts/build-windows/py39-libs/include/internal/pycore_accu.h +++ /dev/null @@ -1,39 +0,0 @@ -#ifndef Py_LIMITED_API -#ifndef Py_INTERNAL_ACCU_H -#define Py_INTERNAL_ACCU_H -#ifdef __cplusplus -extern "C" { -#endif - -/*** This is a private API for use by the interpreter and the stdlib. - *** Its definition may be changed or removed at any moment. - ***/ - -#ifndef Py_BUILD_CORE -# error "this header requires Py_BUILD_CORE define" -#endif - -/* - * A two-level accumulator of unicode objects that avoids both the overhead - * of keeping a huge number of small separate objects, and the quadratic - * behaviour of using a naive repeated concatenation scheme. - */ - -#undef small /* defined by some Windows headers */ - -typedef struct { - PyObject *large; /* A list of previously accumulated large strings */ - PyObject *small; /* Pending small strings */ -} _PyAccu; - -PyAPI_FUNC(int) _PyAccu_Init(_PyAccu *acc); -PyAPI_FUNC(int) _PyAccu_Accumulate(_PyAccu *acc, PyObject *unicode); -PyAPI_FUNC(PyObject *) _PyAccu_FinishAsList(_PyAccu *acc); -PyAPI_FUNC(PyObject *) _PyAccu_Finish(_PyAccu *acc); -PyAPI_FUNC(void) _PyAccu_Destroy(_PyAccu *acc); - -#ifdef __cplusplus -} -#endif -#endif /* !Py_INTERNAL_ACCU_H */ -#endif /* !Py_LIMITED_API */ diff --git a/scripts/build-windows/py39-libs/include/internal/pycore_atomic.h b/scripts/build-windows/py39-libs/include/internal/pycore_atomic.h deleted file mode 100644 index 1d5c56216..000000000 --- a/scripts/build-windows/py39-libs/include/internal/pycore_atomic.h +++ /dev/null @@ -1,557 +0,0 @@ -#ifndef Py_ATOMIC_H -#define Py_ATOMIC_H -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef Py_BUILD_CORE -# error "this header requires Py_BUILD_CORE define" -#endif - -#include "dynamic_annotations.h" /* _Py_ANNOTATE_MEMORY_ORDER */ -#include "pyconfig.h" - -#if defined(HAVE_STD_ATOMIC) -#include -#endif - - -#if defined(_MSC_VER) -#include -#if defined(_M_IX86) || defined(_M_X64) -# include -#endif -#endif - -/* This is modeled after the atomics interface from C1x, according to - * the draft at - * http://www.open-std.org/JTC1/SC22/wg14/www/docs/n1425.pdf. - * Operations and types are named the same except with a _Py_ prefix - * and have the same semantics. - * - * Beware, the implementations here are deep magic. - */ - -#if defined(HAVE_STD_ATOMIC) - -typedef enum _Py_memory_order { - _Py_memory_order_relaxed = memory_order_relaxed, - _Py_memory_order_acquire = memory_order_acquire, - _Py_memory_order_release = memory_order_release, - _Py_memory_order_acq_rel = memory_order_acq_rel, - _Py_memory_order_seq_cst = memory_order_seq_cst -} _Py_memory_order; - -typedef struct _Py_atomic_address { - atomic_uintptr_t _value; -} _Py_atomic_address; - -typedef struct _Py_atomic_int { - atomic_int _value; -} _Py_atomic_int; - -#define _Py_atomic_signal_fence(/*memory_order*/ ORDER) \ - atomic_signal_fence(ORDER) - -#define _Py_atomic_thread_fence(/*memory_order*/ ORDER) \ - atomic_thread_fence(ORDER) - -#define _Py_atomic_store_explicit(ATOMIC_VAL, NEW_VAL, ORDER) \ - atomic_store_explicit(&((ATOMIC_VAL)->_value), NEW_VAL, ORDER) - -#define _Py_atomic_load_explicit(ATOMIC_VAL, ORDER) \ - atomic_load_explicit(&((ATOMIC_VAL)->_value), ORDER) - -/* Use builtin atomic operations in GCC >= 4.7 */ -#elif defined(HAVE_BUILTIN_ATOMIC) - -typedef enum _Py_memory_order { - _Py_memory_order_relaxed = __ATOMIC_RELAXED, - _Py_memory_order_acquire = __ATOMIC_ACQUIRE, - _Py_memory_order_release = __ATOMIC_RELEASE, - _Py_memory_order_acq_rel = __ATOMIC_ACQ_REL, - _Py_memory_order_seq_cst = __ATOMIC_SEQ_CST -} _Py_memory_order; - -typedef struct _Py_atomic_address { - uintptr_t _value; -} _Py_atomic_address; - -typedef struct _Py_atomic_int { - int _value; -} _Py_atomic_int; - -#define _Py_atomic_signal_fence(/*memory_order*/ ORDER) \ - __atomic_signal_fence(ORDER) - -#define _Py_atomic_thread_fence(/*memory_order*/ ORDER) \ - __atomic_thread_fence(ORDER) - -#define _Py_atomic_store_explicit(ATOMIC_VAL, NEW_VAL, ORDER) \ - (assert((ORDER) == __ATOMIC_RELAXED \ - || (ORDER) == __ATOMIC_SEQ_CST \ - || (ORDER) == __ATOMIC_RELEASE), \ - __atomic_store_n(&((ATOMIC_VAL)->_value), NEW_VAL, ORDER)) - -#define _Py_atomic_load_explicit(ATOMIC_VAL, ORDER) \ - (assert((ORDER) == __ATOMIC_RELAXED \ - || (ORDER) == __ATOMIC_SEQ_CST \ - || (ORDER) == __ATOMIC_ACQUIRE \ - || (ORDER) == __ATOMIC_CONSUME), \ - __atomic_load_n(&((ATOMIC_VAL)->_value), ORDER)) - -/* Only support GCC (for expression statements) and x86 (for simple - * atomic semantics) and MSVC x86/x64/ARM */ -#elif defined(__GNUC__) && (defined(__i386__) || defined(__amd64)) -typedef enum _Py_memory_order { - _Py_memory_order_relaxed, - _Py_memory_order_acquire, - _Py_memory_order_release, - _Py_memory_order_acq_rel, - _Py_memory_order_seq_cst -} _Py_memory_order; - -typedef struct _Py_atomic_address { - uintptr_t _value; -} _Py_atomic_address; - -typedef struct _Py_atomic_int { - int _value; -} _Py_atomic_int; - - -static __inline__ void -_Py_atomic_signal_fence(_Py_memory_order order) -{ - if (order != _Py_memory_order_relaxed) - __asm__ volatile("":::"memory"); -} - -static __inline__ void -_Py_atomic_thread_fence(_Py_memory_order order) -{ - if (order != _Py_memory_order_relaxed) - __asm__ volatile("mfence":::"memory"); -} - -/* Tell the race checker about this operation's effects. */ -static __inline__ void -_Py_ANNOTATE_MEMORY_ORDER(const volatile void *address, _Py_memory_order order) -{ - (void)address; /* shut up -Wunused-parameter */ - switch(order) { - case _Py_memory_order_release: - case _Py_memory_order_acq_rel: - case _Py_memory_order_seq_cst: - _Py_ANNOTATE_HAPPENS_BEFORE(address); - break; - case _Py_memory_order_relaxed: - case _Py_memory_order_acquire: - break; - } - switch(order) { - case _Py_memory_order_acquire: - case _Py_memory_order_acq_rel: - case _Py_memory_order_seq_cst: - _Py_ANNOTATE_HAPPENS_AFTER(address); - break; - case _Py_memory_order_relaxed: - case _Py_memory_order_release: - break; - } -} - -#define _Py_atomic_store_explicit(ATOMIC_VAL, NEW_VAL, ORDER) \ - __extension__ ({ \ - __typeof__(ATOMIC_VAL) atomic_val = ATOMIC_VAL; \ - __typeof__(atomic_val->_value) new_val = NEW_VAL;\ - volatile __typeof__(new_val) *volatile_data = &atomic_val->_value; \ - _Py_memory_order order = ORDER; \ - _Py_ANNOTATE_MEMORY_ORDER(atomic_val, order); \ - \ - /* Perform the operation. */ \ - _Py_ANNOTATE_IGNORE_WRITES_BEGIN(); \ - switch(order) { \ - case _Py_memory_order_release: \ - _Py_atomic_signal_fence(_Py_memory_order_release); \ - /* fallthrough */ \ - case _Py_memory_order_relaxed: \ - *volatile_data = new_val; \ - break; \ - \ - case _Py_memory_order_acquire: \ - case _Py_memory_order_acq_rel: \ - case _Py_memory_order_seq_cst: \ - __asm__ volatile("xchg %0, %1" \ - : "+r"(new_val) \ - : "m"(atomic_val->_value) \ - : "memory"); \ - break; \ - } \ - _Py_ANNOTATE_IGNORE_WRITES_END(); \ - }) - -#define _Py_atomic_load_explicit(ATOMIC_VAL, ORDER) \ - __extension__ ({ \ - __typeof__(ATOMIC_VAL) atomic_val = ATOMIC_VAL; \ - __typeof__(atomic_val->_value) result; \ - volatile __typeof__(result) *volatile_data = &atomic_val->_value; \ - _Py_memory_order order = ORDER; \ - _Py_ANNOTATE_MEMORY_ORDER(atomic_val, order); \ - \ - /* Perform the operation. */ \ - _Py_ANNOTATE_IGNORE_READS_BEGIN(); \ - switch(order) { \ - case _Py_memory_order_release: \ - case _Py_memory_order_acq_rel: \ - case _Py_memory_order_seq_cst: \ - /* Loads on x86 are not releases by default, so need a */ \ - /* thread fence. */ \ - _Py_atomic_thread_fence(_Py_memory_order_release); \ - break; \ - default: \ - /* No fence */ \ - break; \ - } \ - result = *volatile_data; \ - switch(order) { \ - case _Py_memory_order_acquire: \ - case _Py_memory_order_acq_rel: \ - case _Py_memory_order_seq_cst: \ - /* Loads on x86 are automatically acquire operations so */ \ - /* can get by with just a compiler fence. */ \ - _Py_atomic_signal_fence(_Py_memory_order_acquire); \ - break; \ - default: \ - /* No fence */ \ - break; \ - } \ - _Py_ANNOTATE_IGNORE_READS_END(); \ - result; \ - }) - -#elif defined(_MSC_VER) -/* _Interlocked* functions provide a full memory barrier and are therefore - enough for acq_rel and seq_cst. If the HLE variants aren't available - in hardware they will fall back to a full memory barrier as well. - - This might affect performance but likely only in some very specific and - hard to meassure scenario. -*/ -#if defined(_M_IX86) || defined(_M_X64) -typedef enum _Py_memory_order { - _Py_memory_order_relaxed, - _Py_memory_order_acquire, - _Py_memory_order_release, - _Py_memory_order_acq_rel, - _Py_memory_order_seq_cst -} _Py_memory_order; - -typedef struct _Py_atomic_address { - volatile uintptr_t _value; -} _Py_atomic_address; - -typedef struct _Py_atomic_int { - volatile int _value; -} _Py_atomic_int; - - -#if defined(_M_X64) -#define _Py_atomic_store_64bit(ATOMIC_VAL, NEW_VAL, ORDER) \ - switch (ORDER) { \ - case _Py_memory_order_acquire: \ - _InterlockedExchange64_HLEAcquire((__int64 volatile*)&((ATOMIC_VAL)->_value), (__int64)(NEW_VAL)); \ - break; \ - case _Py_memory_order_release: \ - _InterlockedExchange64_HLERelease((__int64 volatile*)&((ATOMIC_VAL)->_value), (__int64)(NEW_VAL)); \ - break; \ - default: \ - _InterlockedExchange64((__int64 volatile*)&((ATOMIC_VAL)->_value), (__int64)(NEW_VAL)); \ - break; \ - } -#else -#define _Py_atomic_store_64bit(ATOMIC_VAL, NEW_VAL, ORDER) ((void)0); -#endif - -#define _Py_atomic_store_32bit(ATOMIC_VAL, NEW_VAL, ORDER) \ - switch (ORDER) { \ - case _Py_memory_order_acquire: \ - _InterlockedExchange_HLEAcquire((volatile long*)&((ATOMIC_VAL)->_value), (int)(NEW_VAL)); \ - break; \ - case _Py_memory_order_release: \ - _InterlockedExchange_HLERelease((volatile long*)&((ATOMIC_VAL)->_value), (int)(NEW_VAL)); \ - break; \ - default: \ - _InterlockedExchange((volatile long*)&((ATOMIC_VAL)->_value), (int)(NEW_VAL)); \ - break; \ - } - -#if defined(_M_X64) -/* This has to be an intptr_t for now. - gil_created() uses -1 as a sentinel value, if this returns - a uintptr_t it will do an unsigned compare and crash -*/ -inline intptr_t _Py_atomic_load_64bit_impl(volatile uintptr_t* value, int order) { - __int64 old; - switch (order) { - case _Py_memory_order_acquire: - { - do { - old = *value; - } while(_InterlockedCompareExchange64_HLEAcquire((volatile __int64*)value, old, old) != old); - break; - } - case _Py_memory_order_release: - { - do { - old = *value; - } while(_InterlockedCompareExchange64_HLERelease((volatile __int64*)value, old, old) != old); - break; - } - case _Py_memory_order_relaxed: - old = *value; - break; - default: - { - do { - old = *value; - } while(_InterlockedCompareExchange64((volatile __int64*)value, old, old) != old); - break; - } - } - return old; -} - -#define _Py_atomic_load_64bit(ATOMIC_VAL, ORDER) \ - _Py_atomic_load_64bit_impl((volatile uintptr_t*)&((ATOMIC_VAL)->_value), (ORDER)) - -#else -#define _Py_atomic_load_64bit(ATOMIC_VAL, ORDER) ((ATOMIC_VAL)->_value) -#endif - -inline int _Py_atomic_load_32bit_impl(volatile int* value, int order) { - long old; - switch (order) { - case _Py_memory_order_acquire: - { - do { - old = *value; - } while(_InterlockedCompareExchange_HLEAcquire((volatile long*)value, old, old) != old); - break; - } - case _Py_memory_order_release: - { - do { - old = *value; - } while(_InterlockedCompareExchange_HLERelease((volatile long*)value, old, old) != old); - break; - } - case _Py_memory_order_relaxed: - old = *value; - break; - default: - { - do { - old = *value; - } while(_InterlockedCompareExchange((volatile long*)value, old, old) != old); - break; - } - } - return old; -} - -#define _Py_atomic_load_32bit(ATOMIC_VAL, ORDER) \ - _Py_atomic_load_32bit_impl((volatile int*)&((ATOMIC_VAL)->_value), (ORDER)) - -#define _Py_atomic_store_explicit(ATOMIC_VAL, NEW_VAL, ORDER) \ - if (sizeof((ATOMIC_VAL)->_value) == 8) { \ - _Py_atomic_store_64bit((ATOMIC_VAL), NEW_VAL, ORDER) } else { \ - _Py_atomic_store_32bit((ATOMIC_VAL), NEW_VAL, ORDER) } - -#define _Py_atomic_load_explicit(ATOMIC_VAL, ORDER) \ - ( \ - sizeof((ATOMIC_VAL)->_value) == 8 ? \ - _Py_atomic_load_64bit((ATOMIC_VAL), ORDER) : \ - _Py_atomic_load_32bit((ATOMIC_VAL), ORDER) \ - ) -#elif defined(_M_ARM) || defined(_M_ARM64) -typedef enum _Py_memory_order { - _Py_memory_order_relaxed, - _Py_memory_order_acquire, - _Py_memory_order_release, - _Py_memory_order_acq_rel, - _Py_memory_order_seq_cst -} _Py_memory_order; - -typedef struct _Py_atomic_address { - volatile uintptr_t _value; -} _Py_atomic_address; - -typedef struct _Py_atomic_int { - volatile int _value; -} _Py_atomic_int; - - -#if defined(_M_ARM64) -#define _Py_atomic_store_64bit(ATOMIC_VAL, NEW_VAL, ORDER) \ - switch (ORDER) { \ - case _Py_memory_order_acquire: \ - _InterlockedExchange64_acq((__int64 volatile*)&((ATOMIC_VAL)->_value), (__int64)NEW_VAL); \ - break; \ - case _Py_memory_order_release: \ - _InterlockedExchange64_rel((__int64 volatile*)&((ATOMIC_VAL)->_value), (__int64)NEW_VAL); \ - break; \ - default: \ - _InterlockedExchange64((__int64 volatile*)&((ATOMIC_VAL)->_value), (__int64)NEW_VAL); \ - break; \ - } -#else -#define _Py_atomic_store_64bit(ATOMIC_VAL, NEW_VAL, ORDER) ((void)0); -#endif - -#define _Py_atomic_store_32bit(ATOMIC_VAL, NEW_VAL, ORDER) \ - switch (ORDER) { \ - case _Py_memory_order_acquire: \ - _InterlockedExchange_acq((volatile long*)&((ATOMIC_VAL)->_value), (int)NEW_VAL); \ - break; \ - case _Py_memory_order_release: \ - _InterlockedExchange_rel((volatile long*)&((ATOMIC_VAL)->_value), (int)NEW_VAL); \ - break; \ - default: \ - _InterlockedExchange((volatile long*)&((ATOMIC_VAL)->_value), (int)NEW_VAL); \ - break; \ - } - -#if defined(_M_ARM64) -/* This has to be an intptr_t for now. - gil_created() uses -1 as a sentinel value, if this returns - a uintptr_t it will do an unsigned compare and crash -*/ -inline intptr_t _Py_atomic_load_64bit_impl(volatile uintptr_t* value, int order) { - uintptr_t old; - switch (order) { - case _Py_memory_order_acquire: - { - do { - old = *value; - } while(_InterlockedCompareExchange64_acq(value, old, old) != old); - break; - } - case _Py_memory_order_release: - { - do { - old = *value; - } while(_InterlockedCompareExchange64_rel(value, old, old) != old); - break; - } - case _Py_memory_order_relaxed: - old = *value; - break; - default: - { - do { - old = *value; - } while(_InterlockedCompareExchange64(value, old, old) != old); - break; - } - } - return old; -} - -#define _Py_atomic_load_64bit(ATOMIC_VAL, ORDER) \ - _Py_atomic_load_64bit_impl((volatile uintptr_t*)&((ATOMIC_VAL)->_value), (ORDER)) - -#else -#define _Py_atomic_load_64bit(ATOMIC_VAL, ORDER) ((ATOMIC_VAL)->_value) -#endif - -inline int _Py_atomic_load_32bit_impl(volatile int* value, int order) { - int old; - switch (order) { - case _Py_memory_order_acquire: - { - do { - old = *value; - } while(_InterlockedCompareExchange_acq(value, old, old) != old); - break; - } - case _Py_memory_order_release: - { - do { - old = *value; - } while(_InterlockedCompareExchange_rel(value, old, old) != old); - break; - } - case _Py_memory_order_relaxed: - old = *value; - break; - default: - { - do { - old = *value; - } while(_InterlockedCompareExchange(value, old, old) != old); - break; - } - } - return old; -} - -#define _Py_atomic_load_32bit(ATOMIC_VAL, ORDER) \ - _Py_atomic_load_32bit_impl((volatile int*)&((ATOMIC_VAL)->_value), (ORDER)) - -#define _Py_atomic_store_explicit(ATOMIC_VAL, NEW_VAL, ORDER) \ - if (sizeof((ATOMIC_VAL)->_value) == 8) { \ - _Py_atomic_store_64bit((ATOMIC_VAL), (NEW_VAL), (ORDER)) } else { \ - _Py_atomic_store_32bit((ATOMIC_VAL), (NEW_VAL), (ORDER)) } - -#define _Py_atomic_load_explicit(ATOMIC_VAL, ORDER) \ - ( \ - sizeof((ATOMIC_VAL)->_value) == 8 ? \ - _Py_atomic_load_64bit((ATOMIC_VAL), (ORDER)) : \ - _Py_atomic_load_32bit((ATOMIC_VAL), (ORDER)) \ - ) -#endif -#else /* !gcc x86 !_msc_ver */ -typedef enum _Py_memory_order { - _Py_memory_order_relaxed, - _Py_memory_order_acquire, - _Py_memory_order_release, - _Py_memory_order_acq_rel, - _Py_memory_order_seq_cst -} _Py_memory_order; - -typedef struct _Py_atomic_address { - uintptr_t _value; -} _Py_atomic_address; - -typedef struct _Py_atomic_int { - int _value; -} _Py_atomic_int; -/* Fall back to other compilers and processors by assuming that simple - volatile accesses are atomic. This is false, so people should port - this. */ -#define _Py_atomic_signal_fence(/*memory_order*/ ORDER) ((void)0) -#define _Py_atomic_thread_fence(/*memory_order*/ ORDER) ((void)0) -#define _Py_atomic_store_explicit(ATOMIC_VAL, NEW_VAL, ORDER) \ - ((ATOMIC_VAL)->_value = NEW_VAL) -#define _Py_atomic_load_explicit(ATOMIC_VAL, ORDER) \ - ((ATOMIC_VAL)->_value) -#endif - -/* Standardized shortcuts. */ -#define _Py_atomic_store(ATOMIC_VAL, NEW_VAL) \ - _Py_atomic_store_explicit((ATOMIC_VAL), (NEW_VAL), _Py_memory_order_seq_cst) -#define _Py_atomic_load(ATOMIC_VAL) \ - _Py_atomic_load_explicit((ATOMIC_VAL), _Py_memory_order_seq_cst) - -/* Python-local extensions */ - -#define _Py_atomic_store_relaxed(ATOMIC_VAL, NEW_VAL) \ - _Py_atomic_store_explicit((ATOMIC_VAL), (NEW_VAL), _Py_memory_order_relaxed) -#define _Py_atomic_load_relaxed(ATOMIC_VAL) \ - _Py_atomic_load_explicit((ATOMIC_VAL), _Py_memory_order_relaxed) - -#ifdef __cplusplus -} -#endif -#endif /* Py_ATOMIC_H */ diff --git a/scripts/build-windows/py39-libs/include/internal/pycore_bytes_methods.h b/scripts/build-windows/py39-libs/include/internal/pycore_bytes_methods.h deleted file mode 100644 index 11e8ab20e..000000000 --- a/scripts/build-windows/py39-libs/include/internal/pycore_bytes_methods.h +++ /dev/null @@ -1,73 +0,0 @@ -#ifndef Py_LIMITED_API -#ifndef Py_BYTES_CTYPE_H -#define Py_BYTES_CTYPE_H - -#ifndef Py_BUILD_CORE -# error "this header requires Py_BUILD_CORE define" -#endif - -/* - * The internal implementation behind PyBytes (bytes) and PyByteArray (bytearray) - * methods of the given names, they operate on ASCII byte strings. - */ -extern PyObject* _Py_bytes_isspace(const char *cptr, Py_ssize_t len); -extern PyObject* _Py_bytes_isalpha(const char *cptr, Py_ssize_t len); -extern PyObject* _Py_bytes_isalnum(const char *cptr, Py_ssize_t len); -extern PyObject* _Py_bytes_isascii(const char *cptr, Py_ssize_t len); -extern PyObject* _Py_bytes_isdigit(const char *cptr, Py_ssize_t len); -extern PyObject* _Py_bytes_islower(const char *cptr, Py_ssize_t len); -extern PyObject* _Py_bytes_isupper(const char *cptr, Py_ssize_t len); -extern PyObject* _Py_bytes_istitle(const char *cptr, Py_ssize_t len); - -/* These store their len sized answer in the given preallocated *result arg. */ -extern void _Py_bytes_lower(char *result, const char *cptr, Py_ssize_t len); -extern void _Py_bytes_upper(char *result, const char *cptr, Py_ssize_t len); -extern void _Py_bytes_title(char *result, const char *s, Py_ssize_t len); -extern void _Py_bytes_capitalize(char *result, const char *s, Py_ssize_t len); -extern void _Py_bytes_swapcase(char *result, const char *s, Py_ssize_t len); - -extern PyObject *_Py_bytes_find(const char *str, Py_ssize_t len, PyObject *args); -extern PyObject *_Py_bytes_index(const char *str, Py_ssize_t len, PyObject *args); -extern PyObject *_Py_bytes_rfind(const char *str, Py_ssize_t len, PyObject *args); -extern PyObject *_Py_bytes_rindex(const char *str, Py_ssize_t len, PyObject *args); -extern PyObject *_Py_bytes_count(const char *str, Py_ssize_t len, PyObject *args); -extern int _Py_bytes_contains(const char *str, Py_ssize_t len, PyObject *arg); -extern PyObject *_Py_bytes_startswith(const char *str, Py_ssize_t len, PyObject *args); -extern PyObject *_Py_bytes_endswith(const char *str, Py_ssize_t len, PyObject *args); - -/* The maketrans() static method. */ -extern PyObject* _Py_bytes_maketrans(Py_buffer *frm, Py_buffer *to); - -/* Shared __doc__ strings. */ -extern const char _Py_isspace__doc__[]; -extern const char _Py_isalpha__doc__[]; -extern const char _Py_isalnum__doc__[]; -extern const char _Py_isascii__doc__[]; -extern const char _Py_isdigit__doc__[]; -extern const char _Py_islower__doc__[]; -extern const char _Py_isupper__doc__[]; -extern const char _Py_istitle__doc__[]; -extern const char _Py_lower__doc__[]; -extern const char _Py_upper__doc__[]; -extern const char _Py_title__doc__[]; -extern const char _Py_capitalize__doc__[]; -extern const char _Py_swapcase__doc__[]; -extern const char _Py_count__doc__[]; -extern const char _Py_find__doc__[]; -extern const char _Py_index__doc__[]; -extern const char _Py_rfind__doc__[]; -extern const char _Py_rindex__doc__[]; -extern const char _Py_startswith__doc__[]; -extern const char _Py_endswith__doc__[]; -extern const char _Py_maketrans__doc__[]; -extern const char _Py_expandtabs__doc__[]; -extern const char _Py_ljust__doc__[]; -extern const char _Py_rjust__doc__[]; -extern const char _Py_center__doc__[]; -extern const char _Py_zfill__doc__[]; - -/* this is needed because some docs are shared from the .o, not static */ -#define PyDoc_STRVAR_shared(name,str) const char name[] = PyDoc_STR(str) - -#endif /* !Py_BYTES_CTYPE_H */ -#endif /* !Py_LIMITED_API */ diff --git a/scripts/build-windows/py39-libs/include/internal/pycore_byteswap.h b/scripts/build-windows/py39-libs/include/internal/pycore_byteswap.h deleted file mode 100644 index 2b20fc6c7..000000000 --- a/scripts/build-windows/py39-libs/include/internal/pycore_byteswap.h +++ /dev/null @@ -1,88 +0,0 @@ -/* Bytes swap functions, reverse order of bytes: - - - _Py_bswap16(uint16_t) - - _Py_bswap32(uint32_t) - - _Py_bswap64(uint64_t) -*/ - -#ifndef Py_INTERNAL_BSWAP_H -#define Py_INTERNAL_BSWAP_H -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef Py_BUILD_CORE -# error "this header requires Py_BUILD_CORE define" -#endif - -#if defined(__GNUC__) \ - && ((__GNUC__ >= 5) || (__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) - /* __builtin_bswap16() is available since GCC 4.8, - __builtin_bswap32() is available since GCC 4.3, - __builtin_bswap64() is available since GCC 4.3. */ -# define _PY_HAVE_BUILTIN_BSWAP -#endif - -#ifdef _MSC_VER - /* Get _byteswap_ushort(), _byteswap_ulong(), _byteswap_uint64() */ -# include -#endif - -static inline uint16_t -_Py_bswap16(uint16_t word) -{ -#if defined(_PY_HAVE_BUILTIN_BSWAP) || _Py__has_builtin(__builtin_bswap16) - return __builtin_bswap16(word); -#elif defined(_MSC_VER) - Py_BUILD_ASSERT(sizeof(word) == sizeof(unsigned short)); - return _byteswap_ushort(word); -#else - // Portable implementation which doesn't rely on circular bit shift - return ( ((word & UINT16_C(0x00FF)) << 8) - | ((word & UINT16_C(0xFF00)) >> 8)); -#endif -} - -static inline uint32_t -_Py_bswap32(uint32_t word) -{ -#if defined(_PY_HAVE_BUILTIN_BSWAP) || _Py__has_builtin(__builtin_bswap32) - return __builtin_bswap32(word); -#elif defined(_MSC_VER) - Py_BUILD_ASSERT(sizeof(word) == sizeof(unsigned long)); - return _byteswap_ulong(word); -#else - // Portable implementation which doesn't rely on circular bit shift - return ( ((word & UINT32_C(0x000000FF)) << 24) - | ((word & UINT32_C(0x0000FF00)) << 8) - | ((word & UINT32_C(0x00FF0000)) >> 8) - | ((word & UINT32_C(0xFF000000)) >> 24)); -#endif -} - -static inline uint64_t -_Py_bswap64(uint64_t word) -{ -#if defined(_PY_HAVE_BUILTIN_BSWAP) || _Py__has_builtin(__builtin_bswap64) - return __builtin_bswap64(word); -#elif defined(_MSC_VER) - return _byteswap_uint64(word); -#else - // Portable implementation which doesn't rely on circular bit shift - return ( ((word & UINT64_C(0x00000000000000FF)) << 56) - | ((word & UINT64_C(0x000000000000FF00)) << 40) - | ((word & UINT64_C(0x0000000000FF0000)) << 24) - | ((word & UINT64_C(0x00000000FF000000)) << 8) - | ((word & UINT64_C(0x000000FF00000000)) >> 8) - | ((word & UINT64_C(0x0000FF0000000000)) >> 24) - | ((word & UINT64_C(0x00FF000000000000)) >> 40) - | ((word & UINT64_C(0xFF00000000000000)) >> 56)); -#endif -} - - -#ifdef __cplusplus -} -#endif -#endif /* !Py_INTERNAL_BSWAP_H */ - diff --git a/scripts/build-windows/py39-libs/include/internal/pycore_call.h b/scripts/build-windows/py39-libs/include/internal/pycore_call.h deleted file mode 100644 index 6b301264a..000000000 --- a/scripts/build-windows/py39-libs/include/internal/pycore_call.h +++ /dev/null @@ -1,39 +0,0 @@ -#ifndef Py_INTERNAL_CALL_H -#define Py_INTERNAL_CALL_H -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef Py_BUILD_CORE -# error "this header requires Py_BUILD_CORE define" -#endif - -PyAPI_FUNC(PyObject *) _PyObject_Call_Prepend( - PyThreadState *tstate, - PyObject *callable, - PyObject *obj, - PyObject *args, - PyObject *kwargs); - -PyAPI_FUNC(PyObject *) _PyObject_FastCallDictTstate( - PyThreadState *tstate, - PyObject *callable, - PyObject *const *args, - size_t nargsf, - PyObject *kwargs); - -PyAPI_FUNC(PyObject *) _PyObject_Call( - PyThreadState *tstate, - PyObject *callable, - PyObject *args, - PyObject *kwargs); - -static inline PyObject * -_PyObject_CallNoArgTstate(PyThreadState *tstate, PyObject *func) { - return _PyObject_VectorcallTstate(tstate, func, NULL, 0, NULL); -} - -#ifdef __cplusplus -} -#endif -#endif /* !Py_INTERNAL_CALL_H */ diff --git a/scripts/build-windows/py39-libs/include/internal/pycore_ceval.h b/scripts/build-windows/py39-libs/include/internal/pycore_ceval.h deleted file mode 100644 index 2affbf742..000000000 --- a/scripts/build-windows/py39-libs/include/internal/pycore_ceval.h +++ /dev/null @@ -1,124 +0,0 @@ -#ifndef Py_INTERNAL_CEVAL_H -#define Py_INTERNAL_CEVAL_H -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef Py_BUILD_CORE -# error "this header requires Py_BUILD_CORE define" -#endif - -/* Forward declarations */ -struct pyruntimestate; -struct _ceval_runtime_state; - -#include "pycore_interp.h" /* PyInterpreterState.eval_frame */ - -extern void _Py_FinishPendingCalls(PyThreadState *tstate); -extern void _PyEval_InitRuntimeState(struct _ceval_runtime_state *); -extern int _PyEval_InitState(struct _ceval_state *ceval); -extern void _PyEval_FiniState(struct _ceval_state *ceval); -PyAPI_FUNC(void) _PyEval_SignalReceived(PyInterpreterState *interp); -PyAPI_FUNC(int) _PyEval_AddPendingCall( - PyInterpreterState *interp, - int (*func)(void *), - void *arg); -PyAPI_FUNC(void) _PyEval_SignalAsyncExc(PyThreadState *tstate); -#ifdef HAVE_FORK -extern void _PyEval_ReInitThreads(struct pyruntimestate *runtime); -#endif -PyAPI_FUNC(void) _PyEval_SetCoroutineOriginTrackingDepth( - PyThreadState *tstate, - int new_depth); - -/* Private function */ -void _PyEval_Fini(void); - -static inline PyObject* -_PyEval_EvalFrame(PyThreadState *tstate, PyFrameObject *f, int throwflag) -{ - return tstate->interp->eval_frame(tstate, f, throwflag); -} - -extern PyObject *_PyEval_EvalCode( - PyThreadState *tstate, - PyObject *_co, PyObject *globals, PyObject *locals, - PyObject *const *args, Py_ssize_t argcount, - PyObject *const *kwnames, PyObject *const *kwargs, - Py_ssize_t kwcount, int kwstep, - PyObject *const *defs, Py_ssize_t defcount, - PyObject *kwdefs, PyObject *closure, - PyObject *name, PyObject *qualname); - -extern int _PyEval_ThreadsInitialized(struct pyruntimestate *runtime); -extern PyStatus _PyEval_InitGIL(PyThreadState *tstate); -extern void _PyEval_FiniGIL(PyThreadState *tstate); - -extern void _PyEval_ReleaseLock(PyThreadState *tstate); - - -/* --- _Py_EnterRecursiveCall() ----------------------------------------- */ - -PyAPI_DATA(int) _Py_CheckRecursionLimit; - -#ifdef USE_STACKCHECK -/* With USE_STACKCHECK macro defined, trigger stack checks in - _Py_CheckRecursiveCall() on every 64th call to Py_EnterRecursiveCall. */ -static inline int _Py_MakeRecCheck(PyThreadState *tstate) { - return (++tstate->recursion_depth > tstate->interp->ceval.recursion_limit - || ++tstate->stackcheck_counter > 64); -} -#else -static inline int _Py_MakeRecCheck(PyThreadState *tstate) { - return (++tstate->recursion_depth > tstate->interp->ceval.recursion_limit); -} -#endif - -PyAPI_FUNC(int) _Py_CheckRecursiveCall( - PyThreadState *tstate, - const char *where); - -static inline int _Py_EnterRecursiveCall(PyThreadState *tstate, - const char *where) { - return (_Py_MakeRecCheck(tstate) && _Py_CheckRecursiveCall(tstate, where)); -} - -static inline int _Py_EnterRecursiveCall_inline(const char *where) { - PyThreadState *tstate = PyThreadState_GET(); - return _Py_EnterRecursiveCall(tstate, where); -} - -#define Py_EnterRecursiveCall(where) _Py_EnterRecursiveCall_inline(where) - -/* Compute the "lower-water mark" for a recursion limit. When - * Py_LeaveRecursiveCall() is called with a recursion depth below this mark, - * the overflowed flag is reset to 0. */ -static inline int _Py_RecursionLimitLowerWaterMark(int limit) { - if (limit > 200) { - return (limit - 50); - } - else { - return (3 * (limit >> 2)); - } -} - -static inline void _Py_LeaveRecursiveCall(PyThreadState *tstate) { - tstate->recursion_depth--; - int limit = tstate->interp->ceval.recursion_limit; - if (tstate->recursion_depth < _Py_RecursionLimitLowerWaterMark(limit)) { - tstate->overflowed = 0; - } -} - -static inline void _Py_LeaveRecursiveCall_inline(void) { - PyThreadState *tstate = PyThreadState_GET(); - _Py_LeaveRecursiveCall(tstate); -} - -#define Py_LeaveRecursiveCall() _Py_LeaveRecursiveCall_inline() - - -#ifdef __cplusplus -} -#endif -#endif /* !Py_INTERNAL_CEVAL_H */ diff --git a/scripts/build-windows/py39-libs/include/internal/pycore_code.h b/scripts/build-windows/py39-libs/include/internal/pycore_code.h deleted file mode 100644 index 8aee7ac25..000000000 --- a/scripts/build-windows/py39-libs/include/internal/pycore_code.h +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef Py_INTERNAL_CODE_H -#define Py_INTERNAL_CODE_H -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct { - PyObject *ptr; /* Cached pointer (borrowed reference) */ - uint64_t globals_ver; /* ma_version of global dict */ - uint64_t builtins_ver; /* ma_version of builtin dict */ -} _PyOpcache_LoadGlobal; - -struct _PyOpcache { - union { - _PyOpcache_LoadGlobal lg; - } u; - char optimized; -}; - -/* Private API */ -int _PyCode_InitOpcache(PyCodeObject *co); - - -#ifdef __cplusplus -} -#endif -#endif /* !Py_INTERNAL_CODE_H */ diff --git a/scripts/build-windows/py39-libs/include/internal/pycore_condvar.h b/scripts/build-windows/py39-libs/include/internal/pycore_condvar.h deleted file mode 100644 index 6e98673d0..000000000 --- a/scripts/build-windows/py39-libs/include/internal/pycore_condvar.h +++ /dev/null @@ -1,95 +0,0 @@ -#ifndef Py_INTERNAL_CONDVAR_H -#define Py_INTERNAL_CONDVAR_H - -#ifndef Py_BUILD_CORE -# error "this header requires Py_BUILD_CORE define" -#endif - -#ifndef _POSIX_THREADS -/* This means pthreads are not implemented in libc headers, hence the macro - not present in unistd.h. But they still can be implemented as an external - library (e.g. gnu pth in pthread emulation) */ -# ifdef HAVE_PTHREAD_H -# include /* _POSIX_THREADS */ -# endif -#endif - -#ifdef _POSIX_THREADS -/* - * POSIX support - */ -#define Py_HAVE_CONDVAR - -#include - -#define PyMUTEX_T pthread_mutex_t -#define PyCOND_T pthread_cond_t - -#elif defined(NT_THREADS) -/* - * Windows (XP, 2003 server and later, as well as (hopefully) CE) support - * - * Emulated condition variables ones that work with XP and later, plus - * example native support on VISTA and onwards. - */ -#define Py_HAVE_CONDVAR - -/* include windows if it hasn't been done before */ -#define WIN32_LEAN_AND_MEAN -#include - -/* options */ -/* non-emulated condition variables are provided for those that want - * to target Windows Vista. Modify this macro to enable them. - */ -#ifndef _PY_EMULATED_WIN_CV -#define _PY_EMULATED_WIN_CV 1 /* use emulated condition variables */ -#endif - -/* fall back to emulation if not targeting Vista */ -#if !defined NTDDI_VISTA || NTDDI_VERSION < NTDDI_VISTA -#undef _PY_EMULATED_WIN_CV -#define _PY_EMULATED_WIN_CV 1 -#endif - -#if _PY_EMULATED_WIN_CV - -typedef CRITICAL_SECTION PyMUTEX_T; - -/* The ConditionVariable object. From XP onwards it is easily emulated - with a Semaphore. - Semaphores are available on Windows XP (2003 server) and later. - We use a Semaphore rather than an auto-reset event, because although - an auto-resent event might appear to solve the lost-wakeup bug (race - condition between releasing the outer lock and waiting) because it - maintains state even though a wait hasn't happened, there is still - a lost wakeup problem if more than one thread are interrupted in the - critical place. A semaphore solves that, because its state is - counted, not Boolean. - Because it is ok to signal a condition variable with no one - waiting, we need to keep track of the number of - waiting threads. Otherwise, the semaphore's state could rise - without bound. This also helps reduce the number of "spurious wakeups" - that would otherwise happen. - */ - -typedef struct _PyCOND_T -{ - HANDLE sem; - int waiting; /* to allow PyCOND_SIGNAL to be a no-op */ -} PyCOND_T; - -#else /* !_PY_EMULATED_WIN_CV */ - -/* Use native Win7 primitives if build target is Win7 or higher */ - -/* SRWLOCK is faster and better than CriticalSection */ -typedef SRWLOCK PyMUTEX_T; - -typedef CONDITION_VARIABLE PyCOND_T; - -#endif /* _PY_EMULATED_WIN_CV */ - -#endif /* _POSIX_THREADS, NT_THREADS */ - -#endif /* Py_INTERNAL_CONDVAR_H */ diff --git a/scripts/build-windows/py39-libs/include/internal/pycore_context.h b/scripts/build-windows/py39-libs/include/internal/pycore_context.h deleted file mode 100644 index 884baa9cb..000000000 --- a/scripts/build-windows/py39-libs/include/internal/pycore_context.h +++ /dev/null @@ -1,42 +0,0 @@ -#ifndef Py_INTERNAL_CONTEXT_H -#define Py_INTERNAL_CONTEXT_H - -#ifndef Py_BUILD_CORE -# error "this header requires Py_BUILD_CORE define" -#endif - -#include "pycore_hamt.h" /* PyHamtObject */ - -struct _pycontextobject { - PyObject_HEAD - PyContext *ctx_prev; - PyHamtObject *ctx_vars; - PyObject *ctx_weakreflist; - int ctx_entered; -}; - - -struct _pycontextvarobject { - PyObject_HEAD - PyObject *var_name; - PyObject *var_default; - PyObject *var_cached; - uint64_t var_cached_tsid; - uint64_t var_cached_tsver; - Py_hash_t var_hash; -}; - - -struct _pycontexttokenobject { - PyObject_HEAD - PyContext *tok_ctx; - PyContextVar *tok_var; - PyObject *tok_oldval; - int tok_used; -}; - - -int _PyContext_Init(void); -void _PyContext_Fini(void); - -#endif /* !Py_INTERNAL_CONTEXT_H */ diff --git a/scripts/build-windows/py39-libs/include/internal/pycore_dtoa.h b/scripts/build-windows/py39-libs/include/internal/pycore_dtoa.h deleted file mode 100644 index 4cf08f61a..000000000 --- a/scripts/build-windows/py39-libs/include/internal/pycore_dtoa.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef PY_NO_SHORT_FLOAT_REPR -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef Py_BUILD_CORE -# error "this header requires Py_BUILD_CORE define" -#endif - -/* These functions are used by modules compiled as C extension like math: - they must be exported. */ - -PyAPI_FUNC(double) _Py_dg_strtod(const char *str, char **ptr); -PyAPI_FUNC(char *) _Py_dg_dtoa(double d, int mode, int ndigits, - int *decpt, int *sign, char **rve); -PyAPI_FUNC(void) _Py_dg_freedtoa(char *s); -PyAPI_FUNC(double) _Py_dg_stdnan(int sign); -PyAPI_FUNC(double) _Py_dg_infinity(int sign); - -#ifdef __cplusplus -} -#endif -#endif /* !PY_NO_SHORT_FLOAT_REPR */ diff --git a/scripts/build-windows/py39-libs/include/internal/pycore_fileutils.h b/scripts/build-windows/py39-libs/include/internal/pycore_fileutils.h deleted file mode 100644 index 9636f2521..000000000 --- a/scripts/build-windows/py39-libs/include/internal/pycore_fileutils.h +++ /dev/null @@ -1,66 +0,0 @@ -#ifndef Py_INTERNAL_FILEUTILS_H -#define Py_INTERNAL_FILEUTILS_H -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef Py_BUILD_CORE -# error "Py_BUILD_CORE must be defined to include this header" -#endif - -#include /* struct lconv */ - -PyAPI_DATA(int) _Py_HasFileSystemDefaultEncodeErrors; - -PyAPI_FUNC(int) _Py_DecodeUTF8Ex( - const char *arg, - Py_ssize_t arglen, - wchar_t **wstr, - size_t *wlen, - const char **reason, - _Py_error_handler errors); - -PyAPI_FUNC(int) _Py_EncodeUTF8Ex( - const wchar_t *text, - char **str, - size_t *error_pos, - const char **reason, - int raw_malloc, - _Py_error_handler errors); - -PyAPI_FUNC(wchar_t*) _Py_DecodeUTF8_surrogateescape( - const char *arg, - Py_ssize_t arglen, - size_t *wlen); - -PyAPI_FUNC(int) _Py_GetForceASCII(void); - -/* Reset "force ASCII" mode (if it was initialized). - - This function should be called when Python changes the LC_CTYPE locale, - so the "force ASCII" mode can be detected again on the new locale - encoding. */ -PyAPI_FUNC(void) _Py_ResetForceASCII(void); - - -PyAPI_FUNC(int) _Py_GetLocaleconvNumeric( - struct lconv *lc, - PyObject **decimal_point, - PyObject **thousands_sep); - -#ifdef HAVE_NON_UNICODE_WCHAR_T_REPRESENTATION -extern int _Py_LocaleUsesNonUnicodeWchar(void); - -extern wchar_t* _Py_DecodeNonUnicodeWchar( - const wchar_t* native, - Py_ssize_t size); - -extern int _Py_EncodeNonUnicodeWchar_InPlace( - wchar_t* unicode, - Py_ssize_t size); -#endif - -#ifdef __cplusplus -} -#endif -#endif /* !Py_INTERNAL_FILEUTILS_H */ diff --git a/scripts/build-windows/py39-libs/include/internal/pycore_gc.h b/scripts/build-windows/py39-libs/include/internal/pycore_gc.h deleted file mode 100644 index 012407a56..000000000 --- a/scripts/build-windows/py39-libs/include/internal/pycore_gc.h +++ /dev/null @@ -1,179 +0,0 @@ -#ifndef Py_INTERNAL_GC_H -#define Py_INTERNAL_GC_H -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef Py_BUILD_CORE -# error "this header requires Py_BUILD_CORE define" -#endif - -/* GC information is stored BEFORE the object structure. */ -typedef struct { - // Pointer to next object in the list. - // 0 means the object is not tracked - uintptr_t _gc_next; - - // Pointer to previous object in the list. - // Lowest two bits are used for flags documented later. - uintptr_t _gc_prev; -} PyGC_Head; - -#define _Py_AS_GC(o) ((PyGC_Head *)(o)-1) - -/* True if the object is currently tracked by the GC. */ -#define _PyObject_GC_IS_TRACKED(o) (_Py_AS_GC(o)->_gc_next != 0) - -/* True if the object may be tracked by the GC in the future, or already is. - This can be useful to implement some optimizations. */ -#define _PyObject_GC_MAY_BE_TRACKED(obj) \ - (PyObject_IS_GC(obj) && \ - (!PyTuple_CheckExact(obj) || _PyObject_GC_IS_TRACKED(obj))) - - -/* Bit flags for _gc_prev */ -/* Bit 0 is set when tp_finalize is called */ -#define _PyGC_PREV_MASK_FINALIZED (1) -/* Bit 1 is set when the object is in generation which is GCed currently. */ -#define _PyGC_PREV_MASK_COLLECTING (2) -/* The (N-2) most significant bits contain the real address. */ -#define _PyGC_PREV_SHIFT (2) -#define _PyGC_PREV_MASK (((uintptr_t) -1) << _PyGC_PREV_SHIFT) - -// Lowest bit of _gc_next is used for flags only in GC. -// But it is always 0 for normal code. -#define _PyGCHead_NEXT(g) ((PyGC_Head*)(g)->_gc_next) -#define _PyGCHead_SET_NEXT(g, p) ((g)->_gc_next = (uintptr_t)(p)) - -// Lowest two bits of _gc_prev is used for _PyGC_PREV_MASK_* flags. -#define _PyGCHead_PREV(g) ((PyGC_Head*)((g)->_gc_prev & _PyGC_PREV_MASK)) -#define _PyGCHead_SET_PREV(g, p) do { \ - assert(((uintptr_t)p & ~_PyGC_PREV_MASK) == 0); \ - (g)->_gc_prev = ((g)->_gc_prev & ~_PyGC_PREV_MASK) \ - | ((uintptr_t)(p)); \ - } while (0) - -#define _PyGCHead_FINALIZED(g) \ - (((g)->_gc_prev & _PyGC_PREV_MASK_FINALIZED) != 0) -#define _PyGCHead_SET_FINALIZED(g) \ - ((g)->_gc_prev |= _PyGC_PREV_MASK_FINALIZED) - -#define _PyGC_FINALIZED(o) \ - _PyGCHead_FINALIZED(_Py_AS_GC(o)) -#define _PyGC_SET_FINALIZED(o) \ - _PyGCHead_SET_FINALIZED(_Py_AS_GC(o)) - - -/* GC runtime state */ - -/* If we change this, we need to change the default value in the - signature of gc.collect. */ -#define NUM_GENERATIONS 3 -/* - NOTE: about untracking of mutable objects. - - Certain types of container cannot participate in a reference cycle, and - so do not need to be tracked by the garbage collector. Untracking these - objects reduces the cost of garbage collections. However, determining - which objects may be untracked is not free, and the costs must be - weighed against the benefits for garbage collection. - - There are two possible strategies for when to untrack a container: - - i) When the container is created. - ii) When the container is examined by the garbage collector. - - Tuples containing only immutable objects (integers, strings etc, and - recursively, tuples of immutable objects) do not need to be tracked. - The interpreter creates a large number of tuples, many of which will - not survive until garbage collection. It is therefore not worthwhile - to untrack eligible tuples at creation time. - - Instead, all tuples except the empty tuple are tracked when created. - During garbage collection it is determined whether any surviving tuples - can be untracked. A tuple can be untracked if all of its contents are - already not tracked. Tuples are examined for untracking in all garbage - collection cycles. It may take more than one cycle to untrack a tuple. - - Dictionaries containing only immutable objects also do not need to be - tracked. Dictionaries are untracked when created. If a tracked item is - inserted into a dictionary (either as a key or value), the dictionary - becomes tracked. During a full garbage collection (all generations), - the collector will untrack any dictionaries whose contents are not - tracked. - - The module provides the python function is_tracked(obj), which returns - the CURRENT tracking status of the object. Subsequent garbage - collections may change the tracking status of the object. - - Untracking of certain containers was introduced in issue #4688, and - the algorithm was refined in response to issue #14775. -*/ - -struct gc_generation { - PyGC_Head head; - int threshold; /* collection threshold */ - int count; /* count of allocations or collections of younger - generations */ -}; - -/* Running stats per generation */ -struct gc_generation_stats { - /* total number of collections */ - Py_ssize_t collections; - /* total number of collected objects */ - Py_ssize_t collected; - /* total number of uncollectable objects (put into gc.garbage) */ - Py_ssize_t uncollectable; -}; - -struct _gc_runtime_state { - /* List of objects that still need to be cleaned up, singly linked - * via their gc headers' gc_prev pointers. */ - PyObject *trash_delete_later; - /* Current call-stack depth of tp_dealloc calls. */ - int trash_delete_nesting; - - int enabled; - int debug; - /* linked lists of container objects */ - struct gc_generation generations[NUM_GENERATIONS]; - PyGC_Head *generation0; - /* a permanent generation which won't be collected */ - struct gc_generation permanent_generation; - struct gc_generation_stats generation_stats[NUM_GENERATIONS]; - /* true if we are currently running the collector */ - int collecting; - /* list of uncollectable objects */ - PyObject *garbage; - /* a list of callbacks to be invoked when collection is performed */ - PyObject *callbacks; - /* This is the number of objects that survived the last full - collection. It approximates the number of long lived objects - tracked by the GC. - - (by "full collection", we mean a collection of the oldest - generation). */ - Py_ssize_t long_lived_total; - /* This is the number of objects that survived all "non-full" - collections, and are awaiting to undergo a full collection for - the first time. */ - Py_ssize_t long_lived_pending; -}; - -PyAPI_FUNC(void) _PyGC_InitState(struct _gc_runtime_state *); - - -// Functions to clear types free lists -extern void _PyFrame_ClearFreeList(void); -extern void _PyTuple_ClearFreeList(void); -extern void _PyFloat_ClearFreeList(void); -extern void _PyList_ClearFreeList(void); -extern void _PyDict_ClearFreeList(void); -extern void _PyAsyncGen_ClearFreeLists(void); -extern void _PyContext_ClearFreeList(void); - -#ifdef __cplusplus -} -#endif -#endif /* !Py_INTERNAL_GC_H */ diff --git a/scripts/build-windows/py39-libs/include/internal/pycore_getopt.h b/scripts/build-windows/py39-libs/include/internal/pycore_getopt.h deleted file mode 100644 index d045469c9..000000000 --- a/scripts/build-windows/py39-libs/include/internal/pycore_getopt.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef Py_INTERNAL_PYGETOPT_H -#define Py_INTERNAL_PYGETOPT_H - -#ifndef Py_BUILD_CORE -# error "this header requires Py_BUILD_CORE define" -#endif - -extern int _PyOS_opterr; -extern Py_ssize_t _PyOS_optind; -extern const wchar_t *_PyOS_optarg; - -extern void _PyOS_ResetGetOpt(void); - -typedef struct { - const wchar_t *name; - int has_arg; - int val; -} _PyOS_LongOption; - -extern int _PyOS_GetOpt(Py_ssize_t argc, wchar_t * const *argv, int *longindex); - -#endif /* !Py_INTERNAL_PYGETOPT_H */ diff --git a/scripts/build-windows/py39-libs/include/internal/pycore_gil.h b/scripts/build-windows/py39-libs/include/internal/pycore_gil.h deleted file mode 100644 index e1c8923c9..000000000 --- a/scripts/build-windows/py39-libs/include/internal/pycore_gil.h +++ /dev/null @@ -1,50 +0,0 @@ -#ifndef Py_INTERNAL_GIL_H -#define Py_INTERNAL_GIL_H -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef Py_BUILD_CORE -# error "this header requires Py_BUILD_CORE define" -#endif - -#include "pycore_atomic.h" /* _Py_atomic_address */ -#include "pycore_condvar.h" /* PyCOND_T */ - -#ifndef Py_HAVE_CONDVAR -# error You need either a POSIX-compatible or a Windows system! -#endif - -/* Enable if you want to force the switching of threads at least - every `interval`. */ -#undef FORCE_SWITCHING -#define FORCE_SWITCHING - -struct _gil_runtime_state { - /* microseconds (the Python API uses seconds, though) */ - unsigned long interval; - /* Last PyThreadState holding / having held the GIL. This helps us - know whether anyone else was scheduled after we dropped the GIL. */ - _Py_atomic_address last_holder; - /* Whether the GIL is already taken (-1 if uninitialized). This is - atomic because it can be read without any lock taken in ceval.c. */ - _Py_atomic_int locked; - /* Number of GIL switches since the beginning. */ - unsigned long switch_number; - /* This condition variable allows one or several threads to wait - until the GIL is released. In addition, the mutex also protects - the above variables. */ - PyCOND_T cond; - PyMUTEX_T mutex; -#ifdef FORCE_SWITCHING - /* This condition variable helps the GIL-releasing thread wait for - a GIL-awaiting thread to be scheduled and take the GIL. */ - PyCOND_T switch_cond; - PyMUTEX_T switch_mutex; -#endif -}; - -#ifdef __cplusplus -} -#endif -#endif /* !Py_INTERNAL_GIL_H */ diff --git a/scripts/build-windows/py39-libs/include/internal/pycore_hamt.h b/scripts/build-windows/py39-libs/include/internal/pycore_hamt.h deleted file mode 100644 index f6abb1139..000000000 --- a/scripts/build-windows/py39-libs/include/internal/pycore_hamt.h +++ /dev/null @@ -1,116 +0,0 @@ -#ifndef Py_INTERNAL_HAMT_H -#define Py_INTERNAL_HAMT_H - -#ifndef Py_BUILD_CORE -# error "this header requires Py_BUILD_CORE define" -#endif - -#define _Py_HAMT_MAX_TREE_DEPTH 7 - - -#define PyHamt_Check(o) Py_IS_TYPE(o, &_PyHamt_Type) - - -/* Abstract tree node. */ -typedef struct { - PyObject_HEAD -} PyHamtNode; - - -/* An HAMT immutable mapping collection. */ -typedef struct { - PyObject_HEAD - PyHamtNode *h_root; - PyObject *h_weakreflist; - Py_ssize_t h_count; -} PyHamtObject; - - -/* A struct to hold the state of depth-first traverse of the tree. - - HAMT is an immutable collection. Iterators will hold a strong reference - to it, and every node in the HAMT has strong references to its children. - - So for iterators, we can implement zero allocations and zero reference - inc/dec depth-first iteration. - - - i_nodes: an array of seven pointers to tree nodes - - i_level: the current node in i_nodes - - i_pos: an array of positions within nodes in i_nodes. -*/ -typedef struct { - PyHamtNode *i_nodes[_Py_HAMT_MAX_TREE_DEPTH]; - Py_ssize_t i_pos[_Py_HAMT_MAX_TREE_DEPTH]; - int8_t i_level; -} PyHamtIteratorState; - - -/* Base iterator object. - - Contains the iteration state, a pointer to the HAMT tree, - and a pointer to the 'yield function'. The latter is a simple - function that returns a key/value tuple for the 'Items' iterator, - just a key for the 'Keys' iterator, and a value for the 'Values' - iterator. -*/ -typedef struct { - PyObject_HEAD - PyHamtObject *hi_obj; - PyHamtIteratorState hi_iter; - binaryfunc hi_yield; -} PyHamtIterator; - - -PyAPI_DATA(PyTypeObject) _PyHamt_Type; -PyAPI_DATA(PyTypeObject) _PyHamt_ArrayNode_Type; -PyAPI_DATA(PyTypeObject) _PyHamt_BitmapNode_Type; -PyAPI_DATA(PyTypeObject) _PyHamt_CollisionNode_Type; -PyAPI_DATA(PyTypeObject) _PyHamtKeys_Type; -PyAPI_DATA(PyTypeObject) _PyHamtValues_Type; -PyAPI_DATA(PyTypeObject) _PyHamtItems_Type; - - -/* Create a new HAMT immutable mapping. */ -PyHamtObject * _PyHamt_New(void); - -/* Return a new collection based on "o", but with an additional - key/val pair. */ -PyHamtObject * _PyHamt_Assoc(PyHamtObject *o, PyObject *key, PyObject *val); - -/* Return a new collection based on "o", but without "key". */ -PyHamtObject * _PyHamt_Without(PyHamtObject *o, PyObject *key); - -/* Find "key" in the "o" collection. - - Return: - - -1: An error occurred. - - 0: "key" wasn't found in "o". - - 1: "key" is in "o"; "*val" is set to its value (a borrowed ref). -*/ -int _PyHamt_Find(PyHamtObject *o, PyObject *key, PyObject **val); - -/* Check if "v" is equal to "w". - - Return: - - 0: v != w - - 1: v == w - - -1: An error occurred. -*/ -int _PyHamt_Eq(PyHamtObject *v, PyHamtObject *w); - -/* Return the size of "o"; equivalent of "len(o)". */ -Py_ssize_t _PyHamt_Len(PyHamtObject *o); - -/* Return a Keys iterator over "o". */ -PyObject * _PyHamt_NewIterKeys(PyHamtObject *o); - -/* Return a Values iterator over "o". */ -PyObject * _PyHamt_NewIterValues(PyHamtObject *o); - -/* Return a Items iterator over "o". */ -PyObject * _PyHamt_NewIterItems(PyHamtObject *o); - -int _PyHamt_Init(void); -void _PyHamt_Fini(void); - -#endif /* !Py_INTERNAL_HAMT_H */ diff --git a/scripts/build-windows/py39-libs/include/internal/pycore_hashtable.h b/scripts/build-windows/py39-libs/include/internal/pycore_hashtable.h deleted file mode 100644 index 8fa411a15..000000000 --- a/scripts/build-windows/py39-libs/include/internal/pycore_hashtable.h +++ /dev/null @@ -1,148 +0,0 @@ -#ifndef Py_INTERNAL_HASHTABLE_H -#define Py_INTERNAL_HASHTABLE_H -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef Py_BUILD_CORE -# error "this header requires Py_BUILD_CORE define" -#endif - -/* Single linked list */ - -typedef struct _Py_slist_item_s { - struct _Py_slist_item_s *next; -} _Py_slist_item_t; - -typedef struct { - _Py_slist_item_t *head; -} _Py_slist_t; - -#define _Py_SLIST_ITEM_NEXT(ITEM) (((_Py_slist_item_t *)ITEM)->next) - -#define _Py_SLIST_HEAD(SLIST) (((_Py_slist_t *)SLIST)->head) - - -/* _Py_hashtable: table entry */ - -typedef struct { - /* used by _Py_hashtable_t.buckets to link entries */ - _Py_slist_item_t _Py_slist_item; - - Py_uhash_t key_hash; - void *key; - void *value; -} _Py_hashtable_entry_t; - - -/* _Py_hashtable: prototypes */ - -/* Forward declaration */ -struct _Py_hashtable_t; -typedef struct _Py_hashtable_t _Py_hashtable_t; - -typedef Py_uhash_t (*_Py_hashtable_hash_func) (const void *key); -typedef int (*_Py_hashtable_compare_func) (const void *key1, const void *key2); -typedef void (*_Py_hashtable_destroy_func) (void *key); -typedef _Py_hashtable_entry_t* (*_Py_hashtable_get_entry_func)(_Py_hashtable_t *ht, - const void *key); - -typedef struct { - // Allocate a memory block - void* (*malloc) (size_t size); - - // Release a memory block - void (*free) (void *ptr); -} _Py_hashtable_allocator_t; - - -/* _Py_hashtable: table */ -struct _Py_hashtable_t { - size_t nentries; // Total number of entries in the table - size_t nbuckets; - _Py_slist_t *buckets; - - _Py_hashtable_get_entry_func get_entry_func; - _Py_hashtable_hash_func hash_func; - _Py_hashtable_compare_func compare_func; - _Py_hashtable_destroy_func key_destroy_func; - _Py_hashtable_destroy_func value_destroy_func; - _Py_hashtable_allocator_t alloc; -}; - -/* Hash a pointer (void*) */ -PyAPI_FUNC(Py_uhash_t) _Py_hashtable_hash_ptr(const void *key); - -/* Comparison using memcmp() */ -PyAPI_FUNC(int) _Py_hashtable_compare_direct( - const void *key1, - const void *key2); - -PyAPI_FUNC(_Py_hashtable_t *) _Py_hashtable_new( - _Py_hashtable_hash_func hash_func, - _Py_hashtable_compare_func compare_func); - -PyAPI_FUNC(_Py_hashtable_t *) _Py_hashtable_new_full( - _Py_hashtable_hash_func hash_func, - _Py_hashtable_compare_func compare_func, - _Py_hashtable_destroy_func key_destroy_func, - _Py_hashtable_destroy_func value_destroy_func, - _Py_hashtable_allocator_t *allocator); - -PyAPI_FUNC(void) _Py_hashtable_destroy(_Py_hashtable_t *ht); - -PyAPI_FUNC(void) _Py_hashtable_clear(_Py_hashtable_t *ht); - -typedef int (*_Py_hashtable_foreach_func) (_Py_hashtable_t *ht, - const void *key, const void *value, - void *user_data); - -/* Call func() on each entry of the hashtable. - Iteration stops if func() result is non-zero, in this case it's the result - of the call. Otherwise, the function returns 0. */ -PyAPI_FUNC(int) _Py_hashtable_foreach( - _Py_hashtable_t *ht, - _Py_hashtable_foreach_func func, - void *user_data); - -PyAPI_FUNC(size_t) _Py_hashtable_size(const _Py_hashtable_t *ht); - -/* Add a new entry to the hash. The key must not be present in the hash table. - Return 0 on success, -1 on memory error. */ -PyAPI_FUNC(int) _Py_hashtable_set( - _Py_hashtable_t *ht, - const void *key, - void *value); - - -/* Get an entry. - Return NULL if the key does not exist. */ -static inline _Py_hashtable_entry_t * -_Py_hashtable_get_entry(_Py_hashtable_t *ht, const void *key) -{ - return ht->get_entry_func(ht, key); -} - - -/* Get value from an entry. - Return NULL if the entry is not found. - - Use _Py_hashtable_get_entry() to distinguish entry value equal to NULL - and entry not found. */ -PyAPI_FUNC(void*) _Py_hashtable_get(_Py_hashtable_t *ht, const void *key); - - -/* Remove a key and its associated value without calling key and value destroy - functions. - - Return the removed value if the key was found. - Return NULL if the key was not found. */ -PyAPI_FUNC(void*) _Py_hashtable_steal( - _Py_hashtable_t *ht, - const void *key); - - -#ifdef __cplusplus -} -#endif -#endif /* !Py_INTERNAL_HASHTABLE_H */ diff --git a/scripts/build-windows/py39-libs/include/internal/pycore_import.h b/scripts/build-windows/py39-libs/include/internal/pycore_import.h deleted file mode 100644 index 4c5e0e5ef..000000000 --- a/scripts/build-windows/py39-libs/include/internal/pycore_import.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef Py_LIMITED_API -#ifndef Py_INTERNAL_IMPORT_H -#define Py_INTERNAL_IMPORT_H -#ifdef __cplusplus -extern "C" { -#endif - -PyAPI_FUNC(PyObject *) _PyImport_FindBuiltin( - PyThreadState *tstate, - const char *name /* UTF-8 encoded string */ - ); - -#ifdef HAVE_FORK -extern void _PyImport_ReInitLock(void); -#endif -extern void _PyImport_Cleanup(PyThreadState *tstate); - -#ifdef __cplusplus -} -#endif -#endif /* !Py_INTERNAL_IMPORT_H */ -#endif /* !Py_LIMITED_API */ diff --git a/scripts/build-windows/py39-libs/include/internal/pycore_initconfig.h b/scripts/build-windows/py39-libs/include/internal/pycore_initconfig.h deleted file mode 100644 index 855fb5505..000000000 --- a/scripts/build-windows/py39-libs/include/internal/pycore_initconfig.h +++ /dev/null @@ -1,167 +0,0 @@ -#ifndef Py_INTERNAL_CORECONFIG_H -#define Py_INTERNAL_CORECONFIG_H -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef Py_BUILD_CORE -# error "this header requires Py_BUILD_CORE define" -#endif - -/* Forward declaration */ -struct pyruntimestate; - -/* --- PyStatus ----------------------------------------------- */ - -/* Almost all errors causing Python initialization to fail */ -#ifdef _MSC_VER - /* Visual Studio 2015 doesn't implement C99 __func__ in C */ -# define _PyStatus_GET_FUNC() __FUNCTION__ -#else -# define _PyStatus_GET_FUNC() __func__ -#endif - -#define _PyStatus_OK() \ - (PyStatus){._type = _PyStatus_TYPE_OK,} - /* other fields are set to 0 */ -#define _PyStatus_ERR(ERR_MSG) \ - (PyStatus){ \ - ._type = _PyStatus_TYPE_ERROR, \ - .func = _PyStatus_GET_FUNC(), \ - .err_msg = (ERR_MSG)} - /* other fields are set to 0 */ -#define _PyStatus_NO_MEMORY() _PyStatus_ERR("memory allocation failed") -#define _PyStatus_EXIT(EXITCODE) \ - (PyStatus){ \ - ._type = _PyStatus_TYPE_EXIT, \ - .exitcode = (EXITCODE)} -#define _PyStatus_IS_ERROR(err) \ - (err._type == _PyStatus_TYPE_ERROR) -#define _PyStatus_IS_EXIT(err) \ - (err._type == _PyStatus_TYPE_EXIT) -#define _PyStatus_EXCEPTION(err) \ - (err._type != _PyStatus_TYPE_OK) -#define _PyStatus_UPDATE_FUNC(err) \ - do { err.func = _PyStatus_GET_FUNC(); } while (0) - -/* --- PyWideStringList ------------------------------------------------ */ - -#define _PyWideStringList_INIT (PyWideStringList){.length = 0, .items = NULL} - -#ifndef NDEBUG -PyAPI_FUNC(int) _PyWideStringList_CheckConsistency(const PyWideStringList *list); -#endif -PyAPI_FUNC(void) _PyWideStringList_Clear(PyWideStringList *list); -PyAPI_FUNC(int) _PyWideStringList_Copy(PyWideStringList *list, - const PyWideStringList *list2); -PyAPI_FUNC(PyStatus) _PyWideStringList_Extend(PyWideStringList *list, - const PyWideStringList *list2); -PyAPI_FUNC(PyObject*) _PyWideStringList_AsList(const PyWideStringList *list); - - -/* --- _PyArgv ---------------------------------------------------- */ - -typedef struct _PyArgv { - Py_ssize_t argc; - int use_bytes_argv; - char * const *bytes_argv; - wchar_t * const *wchar_argv; -} _PyArgv; - -PyAPI_FUNC(PyStatus) _PyArgv_AsWstrList(const _PyArgv *args, - PyWideStringList *list); - - -/* --- Helper functions ------------------------------------------- */ - -PyAPI_FUNC(int) _Py_str_to_int( - const char *str, - int *result); -PyAPI_FUNC(const wchar_t*) _Py_get_xoption( - const PyWideStringList *xoptions, - const wchar_t *name); -PyAPI_FUNC(const char*) _Py_GetEnv( - int use_environment, - const char *name); -PyAPI_FUNC(void) _Py_get_env_flag( - int use_environment, - int *flag, - const char *name); - -/* Py_GetArgcArgv() helper */ -PyAPI_FUNC(void) _Py_ClearArgcArgv(void); - - -/* --- _PyPreCmdline ------------------------------------------------- */ - -typedef struct { - PyWideStringList argv; - PyWideStringList xoptions; /* "-X value" option */ - int isolated; /* -I option */ - int use_environment; /* -E option */ - int dev_mode; /* -X dev and PYTHONDEVMODE */ -} _PyPreCmdline; - -#define _PyPreCmdline_INIT \ - (_PyPreCmdline){ \ - .use_environment = -1, \ - .isolated = -1, \ - .dev_mode = -1} -/* Note: _PyPreCmdline_INIT sets other fields to 0/NULL */ - -extern void _PyPreCmdline_Clear(_PyPreCmdline *cmdline); -extern PyStatus _PyPreCmdline_SetArgv(_PyPreCmdline *cmdline, - const _PyArgv *args); -extern PyStatus _PyPreCmdline_SetConfig( - const _PyPreCmdline *cmdline, - PyConfig *config); -extern PyStatus _PyPreCmdline_Read(_PyPreCmdline *cmdline, - const PyPreConfig *preconfig); - - -/* --- PyPreConfig ----------------------------------------------- */ - -PyAPI_FUNC(void) _PyPreConfig_InitCompatConfig(PyPreConfig *preconfig); -extern void _PyPreConfig_InitFromConfig( - PyPreConfig *preconfig, - const PyConfig *config); -extern PyStatus _PyPreConfig_InitFromPreConfig( - PyPreConfig *preconfig, - const PyPreConfig *config2); -extern PyObject* _PyPreConfig_AsDict(const PyPreConfig *preconfig); -extern void _PyPreConfig_GetConfig(PyPreConfig *preconfig, - const PyConfig *config); -extern PyStatus _PyPreConfig_Read(PyPreConfig *preconfig, - const _PyArgv *args); -extern PyStatus _PyPreConfig_Write(const PyPreConfig *preconfig); - - -/* --- PyConfig ---------------------------------------------- */ - -typedef enum { - /* Py_Initialize() API: backward compatibility with Python 3.6 and 3.7 */ - _PyConfig_INIT_COMPAT = 1, - _PyConfig_INIT_PYTHON = 2, - _PyConfig_INIT_ISOLATED = 3 -} _PyConfigInitEnum; - -PyAPI_FUNC(void) _PyConfig_InitCompatConfig(PyConfig *config); -extern PyStatus _PyConfig_Copy( - PyConfig *config, - const PyConfig *config2); -extern PyStatus _PyConfig_InitPathConfig(PyConfig *config); -extern PyStatus _PyConfig_Write(const PyConfig *config, - struct pyruntimestate *runtime); -extern PyStatus _PyConfig_SetPyArgv( - PyConfig *config, - const _PyArgv *args); - - -/* --- Function used for testing ---------------------------------- */ - -PyAPI_FUNC(PyObject*) _Py_GetConfigsAsDict(void); - -#ifdef __cplusplus -} -#endif -#endif /* !Py_INTERNAL_CORECONFIG_H */ diff --git a/scripts/build-windows/py39-libs/include/internal/pycore_interp.h b/scripts/build-windows/py39-libs/include/internal/pycore_interp.h deleted file mode 100644 index 1023483a3..000000000 --- a/scripts/build-windows/py39-libs/include/internal/pycore_interp.h +++ /dev/null @@ -1,192 +0,0 @@ -#ifndef Py_INTERNAL_INTERP_H -#define Py_INTERNAL_INTERP_H -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef Py_BUILD_CORE -# error "this header requires Py_BUILD_CORE define" -#endif - -#include "pycore_atomic.h" /* _Py_atomic_address */ -#include "pycore_gil.h" /* struct _gil_runtime_state */ -#include "pycore_gc.h" /* struct _gc_runtime_state */ -#include "pycore_warnings.h" /* struct _warnings_runtime_state */ - -/* ceval state */ - -struct _pending_calls { - PyThread_type_lock lock; - /* Request for running pending calls. */ - _Py_atomic_int calls_to_do; - /* Request for looking at the `async_exc` field of the current - thread state. - Guarded by the GIL. */ - int async_exc; -#define NPENDINGCALLS 32 - struct { - int (*func)(void *); - void *arg; - } calls[NPENDINGCALLS]; - int first; - int last; -}; - -struct _ceval_state { - int recursion_limit; - /* Records whether tracing is on for any thread. Counts the number - of threads for which tstate->c_tracefunc is non-NULL, so if the - value is 0, we know we don't have to check this thread's - c_tracefunc. This speeds up the if statement in - _PyEval_EvalFrameDefault() after fast_next_opcode. */ - int tracing_possible; - /* This single variable consolidates all requests to break out of - the fast path in the eval loop. */ - _Py_atomic_int eval_breaker; - /* Request for dropping the GIL */ - _Py_atomic_int gil_drop_request; - struct _pending_calls pending; -}; - -/* fs_codec.encoding is initialized to NULL. - Later, it is set to a non-NULL string by _PyUnicode_InitEncodings(). */ -struct _Py_unicode_fs_codec { - char *encoding; // Filesystem encoding (encoded to UTF-8) - int utf8; // encoding=="utf-8"? - char *errors; // Filesystem errors (encoded to UTF-8) - _Py_error_handler error_handler; -}; - -struct _Py_unicode_state { - struct _Py_unicode_fs_codec fs_codec; -}; - - -/* interpreter state */ - -#define _PY_NSMALLPOSINTS 257 -#define _PY_NSMALLNEGINTS 5 - -// The PyInterpreterState typedef is in Include/pystate.h. -struct _is { - - struct _is *next; - struct _ts *tstate_head; - - /* Reference to the _PyRuntime global variable. This field exists - to not have to pass runtime in addition to tstate to a function. - Get runtime from tstate: tstate->interp->runtime. */ - struct pyruntimestate *runtime; - - int64_t id; - int64_t id_refcount; - int requires_idref; - PyThread_type_lock id_mutex; - - int finalizing; - - struct _ceval_state ceval; - struct _gc_runtime_state gc; - - PyObject *modules; - PyObject *modules_by_index; - PyObject *sysdict; - PyObject *builtins; - PyObject *importlib; - - /* Used in Modules/_threadmodule.c. */ - long num_threads; - /* Support for runtime thread stack size tuning. - A value of 0 means using the platform's default stack size - or the size specified by the THREAD_STACK_SIZE macro. */ - /* Used in Python/thread.c. */ - size_t pythread_stacksize; - - PyObject *codec_search_path; - PyObject *codec_search_cache; - PyObject *codec_error_registry; - int codecs_initialized; - - struct _Py_unicode_state unicode; - - PyConfig config; -#ifdef HAVE_DLOPEN - int dlopenflags; -#endif - - PyObject *dict; /* Stores per-interpreter state */ - - PyObject *builtins_copy; - PyObject *import_func; - /* Initialized to PyEval_EvalFrameDefault(). */ - _PyFrameEvalFunction eval_frame; - - Py_ssize_t co_extra_user_count; - freefunc co_extra_freefuncs[MAX_CO_EXTRA_USERS]; - -#ifdef HAVE_FORK - PyObject *before_forkers; - PyObject *after_forkers_parent; - PyObject *after_forkers_child; -#endif - /* AtExit module */ - void (*pyexitfunc)(PyObject *); - PyObject *pyexitmodule; - - uint64_t tstate_next_unique_id; - - struct _warnings_runtime_state warnings; - - PyObject *audit_hooks; - - struct { - struct { - int level; - int atbol; - } listnode; - } parser; - -#if _PY_NSMALLNEGINTS + _PY_NSMALLPOSINTS > 0 - /* Small integers are preallocated in this array so that they - can be shared. - The integers that are preallocated are those in the range - -_PY_NSMALLNEGINTS (inclusive) to _PY_NSMALLPOSINTS (not inclusive). - */ - PyLongObject* small_ints[_PY_NSMALLNEGINTS + _PY_NSMALLPOSINTS]; -#endif -}; - -/* Used by _PyImport_Cleanup() */ -extern void _PyInterpreterState_ClearModules(PyInterpreterState *interp); - -extern PyStatus _PyInterpreterState_SetConfig( - PyInterpreterState *interp, - const PyConfig *config); - - - -/* cross-interpreter data registry */ - -/* For now we use a global registry of shareable classes. An - alternative would be to add a tp_* slot for a class's - crossinterpdatafunc. It would be simpler and more efficient. */ - -struct _xidregitem; - -struct _xidregitem { - PyTypeObject *cls; - crossinterpdatafunc getdata; - struct _xidregitem *next; -}; - -PyAPI_FUNC(struct _is*) _PyInterpreterState_LookUpID(int64_t); - -PyAPI_FUNC(int) _PyInterpreterState_IDInitref(struct _is *); -PyAPI_FUNC(void) _PyInterpreterState_IDIncref(struct _is *); -PyAPI_FUNC(void) _PyInterpreterState_IDDecref(struct _is *); - -#ifdef __cplusplus -} -#endif -#endif /* !Py_INTERNAL_INTERP_H */ - diff --git a/scripts/build-windows/py39-libs/include/internal/pycore_object.h b/scripts/build-windows/py39-libs/include/internal/pycore_object.h deleted file mode 100644 index 15497007f..000000000 --- a/scripts/build-windows/py39-libs/include/internal/pycore_object.h +++ /dev/null @@ -1,120 +0,0 @@ -#ifndef Py_INTERNAL_OBJECT_H -#define Py_INTERNAL_OBJECT_H -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef Py_BUILD_CORE -# error "this header requires Py_BUILD_CORE define" -#endif - -#include "pycore_gc.h" // _PyObject_GC_IS_TRACKED() -#include "pycore_interp.h" // PyInterpreterState.gc -#include "pycore_pystate.h" // _PyThreadState_GET() - -PyAPI_FUNC(int) _PyType_CheckConsistency(PyTypeObject *type); -PyAPI_FUNC(int) _PyDict_CheckConsistency(PyObject *mp, int check_content); - -/* Tell the GC to track this object. - * - * NB: While the object is tracked by the collector, it must be safe to call the - * ob_traverse method. - * - * Internal note: interp->gc.generation0->_gc_prev doesn't have any bit flags - * because it's not object header. So we don't use _PyGCHead_PREV() and - * _PyGCHead_SET_PREV() for it to avoid unnecessary bitwise operations. - * - * The PyObject_GC_Track() function is the public version of this macro. - */ -static inline void _PyObject_GC_TRACK_impl(const char *filename, int lineno, - PyObject *op) -{ - _PyObject_ASSERT_FROM(op, !_PyObject_GC_IS_TRACKED(op), - "object already tracked by the garbage collector", - filename, lineno, "_PyObject_GC_TRACK"); - - PyGC_Head *gc = _Py_AS_GC(op); - _PyObject_ASSERT_FROM(op, - (gc->_gc_prev & _PyGC_PREV_MASK_COLLECTING) == 0, - "object is in generation which is garbage collected", - filename, lineno, "_PyObject_GC_TRACK"); - - PyThreadState *tstate = _PyThreadState_GET(); - PyGC_Head *generation0 = tstate->interp->gc.generation0; - PyGC_Head *last = (PyGC_Head*)(generation0->_gc_prev); - _PyGCHead_SET_NEXT(last, gc); - _PyGCHead_SET_PREV(gc, last); - _PyGCHead_SET_NEXT(gc, generation0); - generation0->_gc_prev = (uintptr_t)gc; -} - -#define _PyObject_GC_TRACK(op) \ - _PyObject_GC_TRACK_impl(__FILE__, __LINE__, _PyObject_CAST(op)) - -/* Tell the GC to stop tracking this object. - * - * Internal note: This may be called while GC. So _PyGC_PREV_MASK_COLLECTING - * must be cleared. But _PyGC_PREV_MASK_FINALIZED bit is kept. - * - * The object must be tracked by the GC. - * - * The PyObject_GC_UnTrack() function is the public version of this macro. - */ -static inline void _PyObject_GC_UNTRACK_impl(const char *filename, int lineno, - PyObject *op) -{ - _PyObject_ASSERT_FROM(op, _PyObject_GC_IS_TRACKED(op), - "object not tracked by the garbage collector", - filename, lineno, "_PyObject_GC_UNTRACK"); - - PyGC_Head *gc = _Py_AS_GC(op); - PyGC_Head *prev = _PyGCHead_PREV(gc); - PyGC_Head *next = _PyGCHead_NEXT(gc); - _PyGCHead_SET_NEXT(prev, next); - _PyGCHead_SET_PREV(next, prev); - gc->_gc_next = 0; - gc->_gc_prev &= _PyGC_PREV_MASK_FINALIZED; -} - -#define _PyObject_GC_UNTRACK(op) \ - _PyObject_GC_UNTRACK_impl(__FILE__, __LINE__, _PyObject_CAST(op)) - -#ifdef Py_REF_DEBUG -extern void _PyDebug_PrintTotalRefs(void); -#endif - -#ifdef Py_TRACE_REFS -extern void _Py_AddToAllObjects(PyObject *op, int force); -extern void _Py_PrintReferences(FILE *); -extern void _Py_PrintReferenceAddresses(FILE *); -#endif - -static inline PyObject ** -_PyObject_GET_WEAKREFS_LISTPTR(PyObject *op) -{ - Py_ssize_t offset = Py_TYPE(op)->tp_weaklistoffset; - return (PyObject **)((char *)op + offset); -} - -// Fast inlined version of PyType_HasFeature() -static inline int -_PyType_HasFeature(PyTypeObject *type, unsigned long feature) { - return ((type->tp_flags & feature) != 0); -} - -// Fast inlined version of PyObject_IS_GC() -static inline int -_PyObject_IS_GC(PyObject *obj) -{ - return (PyType_IS_GC(Py_TYPE(obj)) - && (Py_TYPE(obj)->tp_is_gc == NULL - || Py_TYPE(obj)->tp_is_gc(obj))); -} - -// Fast inlined version of PyType_IS_GC() -#define _PyType_IS_GC(t) _PyType_HasFeature((t), Py_TPFLAGS_HAVE_GC) - -#ifdef __cplusplus -} -#endif -#endif /* !Py_INTERNAL_OBJECT_H */ diff --git a/scripts/build-windows/py39-libs/include/internal/pycore_pathconfig.h b/scripts/build-windows/py39-libs/include/internal/pycore_pathconfig.h deleted file mode 100644 index 8f706fe69..000000000 --- a/scripts/build-windows/py39-libs/include/internal/pycore_pathconfig.h +++ /dev/null @@ -1,72 +0,0 @@ -#ifndef Py_INTERNAL_PATHCONFIG_H -#define Py_INTERNAL_PATHCONFIG_H -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef Py_BUILD_CORE -# error "this header requires Py_BUILD_CORE define" -#endif - -typedef struct _PyPathConfig { - /* Full path to the Python program */ - wchar_t *program_full_path; - wchar_t *prefix; - wchar_t *exec_prefix; - /* Set by Py_SetPath(), or computed by _PyConfig_InitPathConfig() */ - wchar_t *module_search_path; - /* Python program name */ - wchar_t *program_name; - /* Set by Py_SetPythonHome() or PYTHONHOME environment variable */ - wchar_t *home; -#ifdef MS_WINDOWS - /* isolated and site_import are used to set Py_IsolatedFlag and - Py_NoSiteFlag flags on Windows in read_pth_file(). These fields - are ignored when their value are equal to -1 (unset). */ - int isolated; - int site_import; - /* Set when a venv is detected */ - wchar_t *base_executable; -#endif -} _PyPathConfig; - -#ifdef MS_WINDOWS -# define _PyPathConfig_INIT \ - {.module_search_path = NULL, \ - .isolated = -1, \ - .site_import = -1} -#else -# define _PyPathConfig_INIT \ - {.module_search_path = NULL} -#endif -/* Note: _PyPathConfig_INIT sets other fields to 0/NULL */ - -PyAPI_DATA(_PyPathConfig) _Py_path_config; -#ifdef MS_WINDOWS -PyAPI_DATA(wchar_t*) _Py_dll_path; -#endif - -extern void _PyPathConfig_ClearGlobal(void); - -extern PyStatus _PyPathConfig_Calculate( - _PyPathConfig *pathconfig, - const PyConfig *config); -extern int _PyPathConfig_ComputeSysPath0( - const PyWideStringList *argv, - PyObject **path0); -extern PyStatus _Py_FindEnvConfigValue( - FILE *env_file, - const wchar_t *key, - wchar_t **value_p); - -#ifdef MS_WINDOWS -extern wchar_t* _Py_GetDLLPath(void); -#endif - -extern PyStatus _PyConfig_WritePathConfig(const PyConfig *config); -extern void _Py_DumpPathConfig(PyThreadState *tstate); - -#ifdef __cplusplus -} -#endif -#endif /* !Py_INTERNAL_PATHCONFIG_H */ diff --git a/scripts/build-windows/py39-libs/include/internal/pycore_pyerrors.h b/scripts/build-windows/py39-libs/include/internal/pycore_pyerrors.h deleted file mode 100644 index 6140cf375..000000000 --- a/scripts/build-windows/py39-libs/include/internal/pycore_pyerrors.h +++ /dev/null @@ -1,90 +0,0 @@ -#ifndef Py_INTERNAL_PYERRORS_H -#define Py_INTERNAL_PYERRORS_H -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef Py_BUILD_CORE -# error "this header requires Py_BUILD_CORE define" -#endif - -static inline PyObject* _PyErr_Occurred(PyThreadState *tstate) -{ - assert(tstate != NULL); - return tstate->curexc_type; -} - -static inline void _PyErr_ClearExcState(_PyErr_StackItem *exc_state) -{ - PyObject *t, *v, *tb; - t = exc_state->exc_type; - v = exc_state->exc_value; - tb = exc_state->exc_traceback; - exc_state->exc_type = NULL; - exc_state->exc_value = NULL; - exc_state->exc_traceback = NULL; - Py_XDECREF(t); - Py_XDECREF(v); - Py_XDECREF(tb); -} - - -PyAPI_FUNC(void) _PyErr_Fetch( - PyThreadState *tstate, - PyObject **type, - PyObject **value, - PyObject **traceback); - -PyAPI_FUNC(int) _PyErr_ExceptionMatches( - PyThreadState *tstate, - PyObject *exc); - -PyAPI_FUNC(void) _PyErr_Restore( - PyThreadState *tstate, - PyObject *type, - PyObject *value, - PyObject *traceback); - -PyAPI_FUNC(void) _PyErr_SetObject( - PyThreadState *tstate, - PyObject *type, - PyObject *value); - -PyAPI_FUNC(void) _PyErr_ChainStackItem( - _PyErr_StackItem *exc_info); - -PyAPI_FUNC(void) _PyErr_Clear(PyThreadState *tstate); - -PyAPI_FUNC(void) _PyErr_SetNone(PyThreadState *tstate, PyObject *exception); - -PyAPI_FUNC(PyObject *) _PyErr_NoMemory(PyThreadState *tstate); - -PyAPI_FUNC(void) _PyErr_SetString( - PyThreadState *tstate, - PyObject *exception, - const char *string); - -PyAPI_FUNC(PyObject *) _PyErr_Format( - PyThreadState *tstate, - PyObject *exception, - const char *format, - ...); - -PyAPI_FUNC(void) _PyErr_NormalizeException( - PyThreadState *tstate, - PyObject **exc, - PyObject **val, - PyObject **tb); - -PyAPI_FUNC(PyObject *) _PyErr_FormatFromCauseTstate( - PyThreadState *tstate, - PyObject *exception, - const char *format, - ...); - -PyAPI_FUNC(int) _PyErr_CheckSignalsTstate(PyThreadState *tstate); - -#ifdef __cplusplus -} -#endif -#endif /* !Py_INTERNAL_PYERRORS_H */ diff --git a/scripts/build-windows/py39-libs/include/internal/pycore_pyhash.h b/scripts/build-windows/py39-libs/include/internal/pycore_pyhash.h deleted file mode 100644 index 53d44d90c..000000000 --- a/scripts/build-windows/py39-libs/include/internal/pycore_pyhash.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef Py_INTERNAL_HASH_H -#define Py_INTERNAL_HASH_H - -#ifndef Py_BUILD_CORE -# error "this header requires Py_BUILD_CORE define" -#endif - -uint64_t _Py_KeyedHash(uint64_t, const char *, Py_ssize_t); - -#endif diff --git a/scripts/build-windows/py39-libs/include/internal/pycore_pylifecycle.h b/scripts/build-windows/py39-libs/include/internal/pycore_pylifecycle.h deleted file mode 100644 index 89f99a417..000000000 --- a/scripts/build-windows/py39-libs/include/internal/pycore_pylifecycle.h +++ /dev/null @@ -1,114 +0,0 @@ -#ifndef Py_INTERNAL_LIFECYCLE_H -#define Py_INTERNAL_LIFECYCLE_H -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef Py_BUILD_CORE -# error "this header requires Py_BUILD_CORE define" -#endif - -/* Forward declarations */ -struct _PyArgv; -struct pyruntimestate; - -/* True if the main interpreter thread exited due to an unhandled - * KeyboardInterrupt exception, suggesting the user pressed ^C. */ -PyAPI_DATA(int) _Py_UnhandledKeyboardInterrupt; - -extern int _Py_SetFileSystemEncoding( - const char *encoding, - const char *errors); -extern void _Py_ClearFileSystemEncoding(void); -extern PyStatus _PyUnicode_InitEncodings(PyThreadState *tstate); -#ifdef MS_WINDOWS -extern int _PyUnicode_EnableLegacyWindowsFSEncoding(void); -#endif - -PyAPI_FUNC(void) _Py_ClearStandardStreamEncoding(void); - -PyAPI_FUNC(int) _Py_IsLocaleCoercionTarget(const char *ctype_loc); - -/* Various one-time initializers */ - -extern PyStatus _PyUnicode_Init(void); -extern int _PyStructSequence_Init(void); -extern int _PyLong_Init(PyThreadState *tstate); -extern PyStatus _PyFaulthandler_Init(int enable); -extern int _PyTraceMalloc_Init(int enable); -extern PyObject * _PyBuiltin_Init(PyThreadState *tstate); -extern PyStatus _PySys_Create( - PyThreadState *tstate, - PyObject **sysmod_p); -extern PyStatus _PySys_ReadPreinitWarnOptions(PyWideStringList *options); -extern PyStatus _PySys_ReadPreinitXOptions(PyConfig *config); -extern int _PySys_InitMain(PyThreadState *tstate); -extern PyStatus _PyExc_Init(void); -extern PyStatus _PyErr_Init(void); -extern PyStatus _PyBuiltins_AddExceptions(PyObject * bltinmod); -extern PyStatus _PyImportHooks_Init(PyThreadState *tstate); -extern int _PyFloat_Init(void); -extern PyStatus _Py_HashRandomization_Init(const PyConfig *); - -extern PyStatus _PyTypes_Init(void); -extern PyStatus _PyTypes_InitSlotDefs(void); -extern PyStatus _PyImportZip_Init(PyThreadState *tstate); -extern PyStatus _PyGC_Init(PyThreadState *tstate); - - -/* Various internal finalizers */ - -extern void _PyFrame_Fini(void); -extern void _PyDict_Fini(void); -extern void _PyTuple_Fini(void); -extern void _PyList_Fini(void); -extern void _PySet_Fini(void); -extern void _PyBytes_Fini(void); -extern void _PyFloat_Fini(void); -extern void _PySlice_Fini(void); -extern void _PyAsyncGen_Fini(void); - -extern int _PySignal_Init(int install_signal_handlers); -extern void PyOS_FiniInterrupts(void); - -extern void _PyExc_Fini(void); -extern void _PyImport_Fini(void); -extern void _PyImport_Fini2(void); -extern void _PyGC_Fini(PyThreadState *tstate); -extern void _PyType_Fini(void); -extern void _Py_HashRandomization_Fini(void); -extern void _PyUnicode_Fini(PyThreadState *tstate); -extern void _PyLong_Fini(PyThreadState *tstate); -extern void _PyFaulthandler_Fini(void); -extern void _PyHash_Fini(void); -extern void _PyTraceMalloc_Fini(void); -extern void _PyWarnings_Fini(PyInterpreterState *interp); -extern void _PyAST_Fini(void); - -extern PyStatus _PyGILState_Init(PyThreadState *tstate); -extern void _PyGILState_Fini(PyThreadState *tstate); - -PyAPI_FUNC(void) _PyGC_DumpShutdownStats(PyThreadState *tstate); - -PyAPI_FUNC(PyStatus) _Py_PreInitializeFromPyArgv( - const PyPreConfig *src_config, - const struct _PyArgv *args); -PyAPI_FUNC(PyStatus) _Py_PreInitializeFromConfig( - const PyConfig *config, - const struct _PyArgv *args); - - -PyAPI_FUNC(int) _Py_HandleSystemExit(int *exitcode_p); - -PyAPI_FUNC(PyObject*) _PyErr_WriteUnraisableDefaultHook(PyObject *unraisable); - -PyAPI_FUNC(void) _PyErr_Print(PyThreadState *tstate); -PyAPI_FUNC(void) _PyErr_Display(PyObject *file, PyObject *exception, - PyObject *value, PyObject *tb); - -PyAPI_FUNC(void) _PyThreadState_DeleteCurrent(PyThreadState *tstate); - -#ifdef __cplusplus -} -#endif -#endif /* !Py_INTERNAL_LIFECYCLE_H */ diff --git a/scripts/build-windows/py39-libs/include/internal/pycore_pymem.h b/scripts/build-windows/py39-libs/include/internal/pycore_pymem.h deleted file mode 100644 index ba580bbe4..000000000 --- a/scripts/build-windows/py39-libs/include/internal/pycore_pymem.h +++ /dev/null @@ -1,104 +0,0 @@ -#ifndef Py_INTERNAL_PYMEM_H -#define Py_INTERNAL_PYMEM_H -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef Py_BUILD_CORE -# error "this header requires Py_BUILD_CORE define" -#endif - -#include "pymem.h" // PyMemAllocatorName - - -/* Set the memory allocator of the specified domain to the default. - Save the old allocator into *old_alloc if it's non-NULL. - Return on success, or return -1 if the domain is unknown. */ -PyAPI_FUNC(int) _PyMem_SetDefaultAllocator( - PyMemAllocatorDomain domain, - PyMemAllocatorEx *old_alloc); - -/* Special bytes broadcast into debug memory blocks at appropriate times. - Strings of these are unlikely to be valid addresses, floats, ints or - 7-bit ASCII. - - - PYMEM_CLEANBYTE: clean (newly allocated) memory - - PYMEM_DEADBYTE dead (newly freed) memory - - PYMEM_FORBIDDENBYTE: untouchable bytes at each end of a block - - Byte patterns 0xCB, 0xDB and 0xFB have been replaced with 0xCD, 0xDD and - 0xFD to use the same values than Windows CRT debug malloc() and free(). - If modified, _PyMem_IsPtrFreed() should be updated as well. */ -#define PYMEM_CLEANBYTE 0xCD -#define PYMEM_DEADBYTE 0xDD -#define PYMEM_FORBIDDENBYTE 0xFD - -/* Heuristic checking if a pointer value is newly allocated - (uninitialized), newly freed or NULL (is equal to zero). - - The pointer is not dereferenced, only the pointer value is checked. - - The heuristic relies on the debug hooks on Python memory allocators which - fills newly allocated memory with CLEANBYTE (0xCD) and newly freed memory - with DEADBYTE (0xDD). Detect also "untouchable bytes" marked - with FORBIDDENBYTE (0xFD). */ -static inline int _PyMem_IsPtrFreed(void *ptr) -{ - uintptr_t value = (uintptr_t)ptr; -#if SIZEOF_VOID_P == 8 - return (value == 0 - || value == (uintptr_t)0xCDCDCDCDCDCDCDCD - || value == (uintptr_t)0xDDDDDDDDDDDDDDDD - || value == (uintptr_t)0xFDFDFDFDFDFDFDFD); -#elif SIZEOF_VOID_P == 4 - return (value == 0 - || value == (uintptr_t)0xCDCDCDCD - || value == (uintptr_t)0xDDDDDDDD - || value == (uintptr_t)0xFDFDFDFD); -#else -# error "unknown pointer size" -#endif -} - -PyAPI_FUNC(int) _PyMem_GetAllocatorName( - const char *name, - PyMemAllocatorName *allocator); - -/* Configure the Python memory allocators. - Pass PYMEM_ALLOCATOR_DEFAULT to use default allocators. - PYMEM_ALLOCATOR_NOT_SET does nothing. */ -PyAPI_FUNC(int) _PyMem_SetupAllocators(PyMemAllocatorName allocator); - -/* bpo-35053: Expose _Py_tracemalloc_config for _Py_NewReference() - which access directly _Py_tracemalloc_config.tracing for best - performances. */ -struct _PyTraceMalloc_Config { - /* Module initialized? - Variable protected by the GIL */ - enum { - TRACEMALLOC_NOT_INITIALIZED, - TRACEMALLOC_INITIALIZED, - TRACEMALLOC_FINALIZED - } initialized; - - /* Is tracemalloc tracing memory allocations? - Variable protected by the GIL */ - int tracing; - - /* limit of the number of frames in a traceback, 1 by default. - Variable protected by the GIL. */ - int max_nframe; -}; - -#define _PyTraceMalloc_Config_INIT \ - {.initialized = TRACEMALLOC_NOT_INITIALIZED, \ - .tracing = 0, \ - .max_nframe = 1} - -PyAPI_DATA(struct _PyTraceMalloc_Config) _Py_tracemalloc_config; - - -#ifdef __cplusplus -} -#endif -#endif /* !Py_INTERNAL_PYMEM_H */ diff --git a/scripts/build-windows/py39-libs/include/internal/pycore_pystate.h b/scripts/build-windows/py39-libs/include/internal/pycore_pystate.h deleted file mode 100644 index 2088d5111..000000000 --- a/scripts/build-windows/py39-libs/include/internal/pycore_pystate.h +++ /dev/null @@ -1,138 +0,0 @@ -#ifndef Py_INTERNAL_PYSTATE_H -#define Py_INTERNAL_PYSTATE_H -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef Py_BUILD_CORE -# error "this header requires Py_BUILD_CORE define" -#endif - -#include "pycore_runtime.h" /* PyRuntimeState */ - - -/* Check if the current thread is the main thread. - Use _Py_IsMainInterpreter() to check if it's the main interpreter. */ -static inline int -_Py_IsMainThread(void) -{ - unsigned long thread = PyThread_get_thread_ident(); - return (thread == _PyRuntime.main_thread); -} - - -static inline int -_Py_IsMainInterpreter(PyThreadState* tstate) -{ - /* Use directly _PyRuntime rather than tstate->interp->runtime, since - this function is used in performance critical code path (ceval) */ - return (tstate->interp == _PyRuntime.interpreters.main); -} - - -/* Only handle signals on the main thread of the main interpreter. */ -static inline int -_Py_ThreadCanHandleSignals(PyInterpreterState *interp) -{ - return (_Py_IsMainThread() && interp == _PyRuntime.interpreters.main); -} - - -/* Only execute pending calls on the main thread. */ -static inline int -_Py_ThreadCanHandlePendingCalls(void) -{ - return _Py_IsMainThread(); -} - - -/* Variable and macro for in-line access to current thread - and interpreter state */ - -static inline PyThreadState* -_PyRuntimeState_GetThreadState(_PyRuntimeState *runtime) -{ - return (PyThreadState*)_Py_atomic_load_relaxed(&runtime->gilstate.tstate_current); -} - -/* Get the current Python thread state. - - Efficient macro reading directly the 'gilstate.tstate_current' atomic - variable. The macro is unsafe: it does not check for error and it can - return NULL. - - The caller must hold the GIL. - - See also PyThreadState_Get() and PyThreadState_GET(). */ -static inline PyThreadState* -_PyThreadState_GET(void) -{ - return _PyRuntimeState_GetThreadState(&_PyRuntime); -} - -/* Redefine PyThreadState_GET() as an alias to _PyThreadState_GET() */ -#undef PyThreadState_GET -#define PyThreadState_GET() _PyThreadState_GET() - -PyAPI_FUNC(void) _Py_NO_RETURN _Py_FatalError_TstateNULL(const char *func); - -static inline void -_Py_EnsureFuncTstateNotNULL(const char *func, PyThreadState *tstate) -{ - if (tstate == NULL) { - _Py_FatalError_TstateNULL(func); - } -} - -// Call Py_FatalError() if tstate is NULL -#define _Py_EnsureTstateNotNULL(tstate) \ - _Py_EnsureFuncTstateNotNULL(__func__, tstate) - - -/* Get the current interpreter state. - - The macro is unsafe: it does not check for error and it can return NULL. - - The caller must hold the GIL. - - See also _PyInterpreterState_Get() - and _PyGILState_GetInterpreterStateUnsafe(). */ -static inline PyInterpreterState* _PyInterpreterState_GET(void) { - PyThreadState *tstate = _PyThreadState_GET(); -#ifdef Py_DEBUG - _Py_EnsureTstateNotNULL(tstate); -#endif - return tstate->interp; -} - - -/* Other */ - -PyAPI_FUNC(void) _PyThreadState_Init( - PyThreadState *tstate); -PyAPI_FUNC(void) _PyThreadState_DeleteExcept( - _PyRuntimeState *runtime, - PyThreadState *tstate); - -PyAPI_FUNC(PyThreadState *) _PyThreadState_Swap( - struct _gilstate_runtime_state *gilstate, - PyThreadState *newts); - -PyAPI_FUNC(PyStatus) _PyInterpreterState_Enable(_PyRuntimeState *runtime); -PyAPI_FUNC(void) _PyInterpreterState_DeleteExceptMain(_PyRuntimeState *runtime); - -PyAPI_FUNC(void) _PyGILState_Reinit(_PyRuntimeState *runtime); - - -PyAPI_FUNC(int) _PyState_AddModule( - PyThreadState *tstate, - PyObject* module, - struct PyModuleDef* def); - - -PyAPI_FUNC(int) _PyOS_InterruptOccurred(PyThreadState *tstate); - -#ifdef __cplusplus -} -#endif -#endif /* !Py_INTERNAL_PYSTATE_H */ diff --git a/scripts/build-windows/py39-libs/include/internal/pycore_runtime.h b/scripts/build-windows/py39-libs/include/internal/pycore_runtime.h deleted file mode 100644 index f0dff829f..000000000 --- a/scripts/build-windows/py39-libs/include/internal/pycore_runtime.h +++ /dev/null @@ -1,144 +0,0 @@ -#ifndef Py_INTERNAL_RUNTIME_H -#define Py_INTERNAL_RUNTIME_H -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef Py_BUILD_CORE -# error "this header requires Py_BUILD_CORE define" -#endif - -#include "pycore_atomic.h" /* _Py_atomic_address */ -#include "pycore_gil.h" // struct _gil_runtime_state - -/* ceval state */ - -struct _ceval_runtime_state { - /* Request for checking signals. It is shared by all interpreters (see - bpo-40513). Any thread of any interpreter can receive a signal, but only - the main thread of the main interpreter can handle signals: see - _Py_ThreadCanHandleSignals(). */ - _Py_atomic_int signals_pending; - struct _gil_runtime_state gil; -}; - -/* GIL state */ - -struct _gilstate_runtime_state { - /* bpo-26558: Flag to disable PyGILState_Check(). - If set to non-zero, PyGILState_Check() always return 1. */ - int check_enabled; - /* Assuming the current thread holds the GIL, this is the - PyThreadState for the current thread. */ - _Py_atomic_address tstate_current; - /* The single PyInterpreterState used by this process' - GILState implementation - */ - /* TODO: Given interp_main, it may be possible to kill this ref */ - PyInterpreterState *autoInterpreterState; - Py_tss_t autoTSSkey; -}; - -/* Runtime audit hook state */ - -typedef struct _Py_AuditHookEntry { - struct _Py_AuditHookEntry *next; - Py_AuditHookFunction hookCFunction; - void *userData; -} _Py_AuditHookEntry; - -/* Full Python runtime state */ - -typedef struct pyruntimestate { - /* Is running Py_PreInitialize()? */ - int preinitializing; - - /* Is Python preinitialized? Set to 1 by Py_PreInitialize() */ - int preinitialized; - - /* Is Python core initialized? Set to 1 by _Py_InitializeCore() */ - int core_initialized; - - /* Is Python fully initialized? Set to 1 by Py_Initialize() */ - int initialized; - - /* Set by Py_FinalizeEx(). Only reset to NULL if Py_Initialize() - is called again. - - Use _PyRuntimeState_GetFinalizing() and _PyRuntimeState_SetFinalizing() - to access it, don't access it directly. */ - _Py_atomic_address _finalizing; - - struct pyinterpreters { - PyThread_type_lock mutex; - PyInterpreterState *head; - PyInterpreterState *main; - /* _next_interp_id is an auto-numbered sequence of small - integers. It gets initialized in _PyInterpreterState_Init(), - which is called in Py_Initialize(), and used in - PyInterpreterState_New(). A negative interpreter ID - indicates an error occurred. The main interpreter will - always have an ID of 0. Overflow results in a RuntimeError. - If that becomes a problem later then we can adjust, e.g. by - using a Python int. */ - int64_t next_id; - } interpreters; - // XXX Remove this field once we have a tp_* slot. - struct _xidregistry { - PyThread_type_lock mutex; - struct _xidregitem *head; - } xidregistry; - - unsigned long main_thread; - -#define NEXITFUNCS 32 - void (*exitfuncs[NEXITFUNCS])(void); - int nexitfuncs; - - struct _ceval_runtime_state ceval; - struct _gilstate_runtime_state gilstate; - - PyPreConfig preconfig; - - Py_OpenCodeHookFunction open_code_hook; - void *open_code_userdata; - _Py_AuditHookEntry *audit_hook_head; - - // XXX Consolidate globals found via the check-c-globals script. -} _PyRuntimeState; - -#define _PyRuntimeState_INIT \ - {.preinitialized = 0, .core_initialized = 0, .initialized = 0} -/* Note: _PyRuntimeState_INIT sets other fields to 0/NULL */ - - -PyAPI_DATA(_PyRuntimeState) _PyRuntime; - -PyAPI_FUNC(PyStatus) _PyRuntimeState_Init(_PyRuntimeState *runtime); -PyAPI_FUNC(void) _PyRuntimeState_Fini(_PyRuntimeState *runtime); - -#ifdef HAVE_FORK -PyAPI_FUNC(void) _PyRuntimeState_ReInitThreads(_PyRuntimeState *runtime); -#endif - -/* Initialize _PyRuntimeState. - Return NULL on success, or return an error message on failure. */ -PyAPI_FUNC(PyStatus) _PyRuntime_Initialize(void); - -PyAPI_FUNC(void) _PyRuntime_Finalize(void); - - -static inline PyThreadState* -_PyRuntimeState_GetFinalizing(_PyRuntimeState *runtime) { - return (PyThreadState*)_Py_atomic_load_relaxed(&runtime->_finalizing); -} - -static inline void -_PyRuntimeState_SetFinalizing(_PyRuntimeState *runtime, PyThreadState *tstate) { - _Py_atomic_store_relaxed(&runtime->_finalizing, (uintptr_t)tstate); -} - -#ifdef __cplusplus -} -#endif -#endif /* !Py_INTERNAL_RUNTIME_H */ diff --git a/scripts/build-windows/py39-libs/include/internal/pycore_sysmodule.h b/scripts/build-windows/py39-libs/include/internal/pycore_sysmodule.h deleted file mode 100644 index 363eb873b..000000000 --- a/scripts/build-windows/py39-libs/include/internal/pycore_sysmodule.h +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef Py_INTERNAL_SYSMODULE_H -#define Py_INTERNAL_SYSMODULE_H -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef Py_BUILD_CORE -# error "this header requires Py_BUILD_CORE define" -#endif - -PyAPI_FUNC(int) _PySys_Audit( - PyThreadState *tstate, - const char *event, - const char *argFormat, - ...); - -/* We want minimal exposure of this function, so use extern rather than - PyAPI_FUNC() to not export the symbol. */ -extern void _PySys_ClearAuditHooks(PyThreadState *tstate); - -#ifdef __cplusplus -} -#endif -#endif /* !Py_INTERNAL_SYSMODULE_H */ diff --git a/scripts/build-windows/py39-libs/include/internal/pycore_traceback.h b/scripts/build-windows/py39-libs/include/internal/pycore_traceback.h deleted file mode 100644 index 274e2d0de..000000000 --- a/scripts/build-windows/py39-libs/include/internal/pycore_traceback.h +++ /dev/null @@ -1,97 +0,0 @@ -#ifndef Py_INTERNAL_TRACEBACK_H -#define Py_INTERNAL_TRACEBACK_H -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef Py_BUILD_CORE -# error "this header requires Py_BUILD_CORE define" -#endif - -/* Forward declaration */ -struct _is; - -/* Write the Python traceback into the file 'fd'. For example: - - Traceback (most recent call first): - File "xxx", line xxx in - File "xxx", line xxx in - ... - File "xxx", line xxx in - - This function is written for debug purpose only, to dump the traceback in - the worst case: after a segmentation fault, at fatal error, etc. That's why, - it is very limited. Strings are truncated to 100 characters and encoded to - ASCII with backslashreplace. It doesn't write the source code, only the - function name, filename and line number of each frame. Write only the first - 100 frames: if the traceback is truncated, write the line " ...". - - This function is signal safe. */ - -PyAPI_FUNC(void) _Py_DumpTraceback( - int fd, - PyThreadState *tstate); - -/* Write the traceback of all threads into the file 'fd'. current_thread can be - NULL. - - Return NULL on success, or an error message on error. - - This function is written for debug purpose only. It calls - _Py_DumpTraceback() for each thread, and so has the same limitations. It - only write the traceback of the first 100 threads: write "..." if there are - more threads. - - If current_tstate is NULL, the function tries to get the Python thread state - of the current thread. It is not an error if the function is unable to get - the current Python thread state. - - If interp is NULL, the function tries to get the interpreter state from - the current Python thread state, or from - _PyGILState_GetInterpreterStateUnsafe() in last resort. - - It is better to pass NULL to interp and current_tstate, the function tries - different options to retrieve these informations. - - This function is signal safe. */ - -PyAPI_FUNC(const char*) _Py_DumpTracebackThreads( - int fd, - struct _is *interp, - PyThreadState *current_tstate); - -/* Write a Unicode object into the file descriptor fd. Encode the string to - ASCII using the backslashreplace error handler. - - Do nothing if text is not a Unicode object. The function accepts Unicode - string which is not ready (PyUnicode_WCHAR_KIND). - - This function is signal safe. */ -PyAPI_FUNC(void) _Py_DumpASCII(int fd, PyObject *text); - -/* Format an integer as decimal into the file descriptor fd. - - This function is signal safe. */ -PyAPI_FUNC(void) _Py_DumpDecimal( - int fd, - unsigned long value); - -/* Format an integer as hexadecimal into the file descriptor fd with at least - width digits. - - The maximum width is sizeof(unsigned long)*2 digits. - - This function is signal safe. */ -PyAPI_FUNC(void) _Py_DumpHexadecimal( - int fd, - unsigned long value, - Py_ssize_t width); - -PyAPI_FUNC(PyObject*) _PyTraceBack_FromFrame( - PyObject *tb_next, - PyFrameObject *frame); - -#ifdef __cplusplus -} -#endif -#endif /* !Py_INTERNAL_TRACEBACK_H */ diff --git a/scripts/build-windows/py39-libs/include/internal/pycore_tupleobject.h b/scripts/build-windows/py39-libs/include/internal/pycore_tupleobject.h deleted file mode 100644 index 10772fe38..000000000 --- a/scripts/build-windows/py39-libs/include/internal/pycore_tupleobject.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef Py_INTERNAL_TUPLEOBJECT_H -#define Py_INTERNAL_TUPLEOBJECT_H -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef Py_BUILD_CORE -# error "this header requires Py_BUILD_CORE define" -#endif - -#include "tupleobject.h" /* _PyTuple_CAST() */ - -#define _PyTuple_ITEMS(op) (_PyTuple_CAST(op)->ob_item) -PyAPI_FUNC(PyObject *) _PyTuple_FromArray(PyObject *const *, Py_ssize_t); - -#ifdef __cplusplus -} -#endif -#endif /* !Py_INTERNAL_TUPLEOBJECT_H */ diff --git a/scripts/build-windows/py39-libs/include/internal/pycore_warnings.h b/scripts/build-windows/py39-libs/include/internal/pycore_warnings.h deleted file mode 100644 index 23c50d66c..000000000 --- a/scripts/build-windows/py39-libs/include/internal/pycore_warnings.h +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef Py_INTERNAL_WARNINGS_H -#define Py_INTERNAL_WARNINGS_H -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef Py_BUILD_CORE -# error "this header requires Py_BUILD_CORE define" -#endif - -struct _warnings_runtime_state { - /* Both 'filters' and 'onceregistry' can be set in warnings.py; - get_warnings_attr() will reset these variables accordingly. */ - PyObject *filters; /* List */ - PyObject *once_registry; /* Dict */ - PyObject *default_action; /* String */ - long filters_version; -}; - -extern PyStatus _PyWarnings_InitState(PyThreadState *tstate); - -#ifdef __cplusplus -} -#endif -#endif /* !Py_INTERNAL_WARNINGS_H */ diff --git a/scripts/build-windows/py39-libs/include/interpreteridobject.h b/scripts/build-windows/py39-libs/include/interpreteridobject.h deleted file mode 100644 index c8b5f9536..000000000 --- a/scripts/build-windows/py39-libs/include/interpreteridobject.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef Py_INTERPRETERIDOBJECT_H -#define Py_INTERPRETERIDOBJECT_H - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef Py_LIMITED_API -# define Py_CPYTHON_INTERPRETERIDOBJECT_H -# include "cpython/interpreteridobject.h" -# undef Py_CPYTHON_INTERPRETERIDOBJECT_H -#endif - -#ifdef __cplusplus -} -#endif -#endif /* !Py_INTERPRETERIDOBJECT_H */ diff --git a/scripts/build-windows/py39-libs/include/intrcheck.h b/scripts/build-windows/py39-libs/include/intrcheck.h deleted file mode 100644 index a65bbb11d..000000000 --- a/scripts/build-windows/py39-libs/include/intrcheck.h +++ /dev/null @@ -1,33 +0,0 @@ - -#ifndef Py_INTRCHECK_H -#define Py_INTRCHECK_H -#ifdef __cplusplus -extern "C" { -#endif - -PyAPI_FUNC(int) PyOS_InterruptOccurred(void); -PyAPI_FUNC(void) PyOS_InitInterrupts(void); -#ifdef HAVE_FORK -#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03070000 -PyAPI_FUNC(void) PyOS_BeforeFork(void); -PyAPI_FUNC(void) PyOS_AfterFork_Parent(void); -PyAPI_FUNC(void) PyOS_AfterFork_Child(void); -#endif -#endif -/* Deprecated, please use PyOS_AfterFork_Child() instead */ -Py_DEPRECATED(3.7) PyAPI_FUNC(void) PyOS_AfterFork(void); - -#ifndef Py_LIMITED_API -PyAPI_FUNC(int) _PyOS_IsMainThread(void); -PyAPI_FUNC(void) _PySignal_AfterFork(void); - -#ifdef MS_WINDOWS -/* windows.h is not included by Python.h so use void* instead of HANDLE */ -PyAPI_FUNC(void*) _PyOS_SigintEvent(void); -#endif -#endif /* !Py_LIMITED_API */ - -#ifdef __cplusplus -} -#endif -#endif /* !Py_INTRCHECK_H */ diff --git a/scripts/build-windows/py39-libs/include/iterobject.h b/scripts/build-windows/py39-libs/include/iterobject.h deleted file mode 100644 index 8022a6ea9..000000000 --- a/scripts/build-windows/py39-libs/include/iterobject.h +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef Py_ITEROBJECT_H -#define Py_ITEROBJECT_H -/* Iterators (the basic kind, over a sequence) */ -#ifdef __cplusplus -extern "C" { -#endif - -PyAPI_DATA(PyTypeObject) PySeqIter_Type; -PyAPI_DATA(PyTypeObject) PyCallIter_Type; - -#define PySeqIter_Check(op) Py_IS_TYPE(op, &PySeqIter_Type) - -PyAPI_FUNC(PyObject *) PySeqIter_New(PyObject *); - - -#define PyCallIter_Check(op) Py_IS_TYPE(op, &PyCallIter_Type) - -PyAPI_FUNC(PyObject *) PyCallIter_New(PyObject *, PyObject *); - -#ifdef __cplusplus -} -#endif -#endif /* !Py_ITEROBJECT_H */ - diff --git a/scripts/build-windows/py39-libs/include/listobject.h b/scripts/build-windows/py39-libs/include/listobject.h deleted file mode 100644 index 28273493e..000000000 --- a/scripts/build-windows/py39-libs/include/listobject.h +++ /dev/null @@ -1,52 +0,0 @@ -/* List object interface - - Another generally useful object type is a list of object pointers. - This is a mutable type: the list items can be changed, and items can be - added or removed. Out-of-range indices or non-list objects are ignored. - - WARNING: PyList_SetItem does not increment the new item's reference count, - but does decrement the reference count of the item it replaces, if not nil. - It does *decrement* the reference count if it is *not* inserted in the list. - Similarly, PyList_GetItem does not increment the returned item's reference - count. -*/ - -#ifndef Py_LISTOBJECT_H -#define Py_LISTOBJECT_H -#ifdef __cplusplus -extern "C" { -#endif - -PyAPI_DATA(PyTypeObject) PyList_Type; -PyAPI_DATA(PyTypeObject) PyListIter_Type; -PyAPI_DATA(PyTypeObject) PyListRevIter_Type; - -#define PyList_Check(op) \ - PyType_FastSubclass(Py_TYPE(op), Py_TPFLAGS_LIST_SUBCLASS) -#define PyList_CheckExact(op) Py_IS_TYPE(op, &PyList_Type) - -PyAPI_FUNC(PyObject *) PyList_New(Py_ssize_t size); -PyAPI_FUNC(Py_ssize_t) PyList_Size(PyObject *); - -PyAPI_FUNC(PyObject *) PyList_GetItem(PyObject *, Py_ssize_t); -PyAPI_FUNC(int) PyList_SetItem(PyObject *, Py_ssize_t, PyObject *); -PyAPI_FUNC(int) PyList_Insert(PyObject *, Py_ssize_t, PyObject *); -PyAPI_FUNC(int) PyList_Append(PyObject *, PyObject *); - -PyAPI_FUNC(PyObject *) PyList_GetSlice(PyObject *, Py_ssize_t, Py_ssize_t); -PyAPI_FUNC(int) PyList_SetSlice(PyObject *, Py_ssize_t, Py_ssize_t, PyObject *); - -PyAPI_FUNC(int) PyList_Sort(PyObject *); -PyAPI_FUNC(int) PyList_Reverse(PyObject *); -PyAPI_FUNC(PyObject *) PyList_AsTuple(PyObject *); - -#ifndef Py_LIMITED_API -# define Py_CPYTHON_LISTOBJECT_H -# include "cpython/listobject.h" -# undef Py_CPYTHON_LISTOBJECT_H -#endif - -#ifdef __cplusplus -} -#endif -#endif /* !Py_LISTOBJECT_H */ diff --git a/scripts/build-windows/py39-libs/include/longintrepr.h b/scripts/build-windows/py39-libs/include/longintrepr.h deleted file mode 100644 index cc02f2b33..000000000 --- a/scripts/build-windows/py39-libs/include/longintrepr.h +++ /dev/null @@ -1,99 +0,0 @@ -#ifndef Py_LIMITED_API -#ifndef Py_LONGINTREPR_H -#define Py_LONGINTREPR_H -#ifdef __cplusplus -extern "C" { -#endif - - -/* This is published for the benefit of "friends" marshal.c and _decimal.c. */ - -/* Parameters of the integer representation. There are two different - sets of parameters: one set for 30-bit digits, stored in an unsigned 32-bit - integer type, and one set for 15-bit digits with each digit stored in an - unsigned short. The value of PYLONG_BITS_IN_DIGIT, defined either at - configure time or in pyport.h, is used to decide which digit size to use. - - Type 'digit' should be able to hold 2*PyLong_BASE-1, and type 'twodigits' - should be an unsigned integer type able to hold all integers up to - PyLong_BASE*PyLong_BASE-1. x_sub assumes that 'digit' is an unsigned type, - and that overflow is handled by taking the result modulo 2**N for some N > - PyLong_SHIFT. The majority of the code doesn't care about the precise - value of PyLong_SHIFT, but there are some notable exceptions: - - - long_pow() requires that PyLong_SHIFT be divisible by 5 - - - PyLong_{As,From}ByteArray require that PyLong_SHIFT be at least 8 - - - long_hash() requires that PyLong_SHIFT is *strictly* less than the number - of bits in an unsigned long, as do the PyLong <-> long (or unsigned long) - conversion functions - - - the Python int <-> size_t/Py_ssize_t conversion functions expect that - PyLong_SHIFT is strictly less than the number of bits in a size_t - - - the marshal code currently expects that PyLong_SHIFT is a multiple of 15 - - - NSMALLNEGINTS and NSMALLPOSINTS should be small enough to fit in a single - digit; with the current values this forces PyLong_SHIFT >= 9 - - The values 15 and 30 should fit all of the above requirements, on any - platform. -*/ - -#if PYLONG_BITS_IN_DIGIT == 30 -typedef uint32_t digit; -typedef int32_t sdigit; /* signed variant of digit */ -typedef uint64_t twodigits; -typedef int64_t stwodigits; /* signed variant of twodigits */ -#define PyLong_SHIFT 30 -#define _PyLong_DECIMAL_SHIFT 9 /* max(e such that 10**e fits in a digit) */ -#define _PyLong_DECIMAL_BASE ((digit)1000000000) /* 10 ** DECIMAL_SHIFT */ -#elif PYLONG_BITS_IN_DIGIT == 15 -typedef unsigned short digit; -typedef short sdigit; /* signed variant of digit */ -typedef unsigned long twodigits; -typedef long stwodigits; /* signed variant of twodigits */ -#define PyLong_SHIFT 15 -#define _PyLong_DECIMAL_SHIFT 4 /* max(e such that 10**e fits in a digit) */ -#define _PyLong_DECIMAL_BASE ((digit)10000) /* 10 ** DECIMAL_SHIFT */ -#else -#error "PYLONG_BITS_IN_DIGIT should be 15 or 30" -#endif -#define PyLong_BASE ((digit)1 << PyLong_SHIFT) -#define PyLong_MASK ((digit)(PyLong_BASE - 1)) - -#if PyLong_SHIFT % 5 != 0 -#error "longobject.c requires that PyLong_SHIFT be divisible by 5" -#endif - -/* Long integer representation. - The absolute value of a number is equal to - SUM(for i=0 through abs(ob_size)-1) ob_digit[i] * 2**(SHIFT*i) - Negative numbers are represented with ob_size < 0; - zero is represented by ob_size == 0. - In a normalized number, ob_digit[abs(ob_size)-1] (the most significant - digit) is never zero. Also, in all cases, for all valid i, - 0 <= ob_digit[i] <= MASK. - The allocation function takes care of allocating extra memory - so that ob_digit[0] ... ob_digit[abs(ob_size)-1] are actually available. - - CAUTION: Generic code manipulating subtypes of PyVarObject has to - aware that ints abuse ob_size's sign bit. -*/ - -struct _longobject { - PyObject_VAR_HEAD - digit ob_digit[1]; -}; - -PyAPI_FUNC(PyLongObject *) _PyLong_New(Py_ssize_t); - -/* Return a copy of src. */ -PyAPI_FUNC(PyObject *) _PyLong_Copy(PyLongObject *src); - -#ifdef __cplusplus -} -#endif -#endif /* !Py_LONGINTREPR_H */ -#endif /* Py_LIMITED_API */ diff --git a/scripts/build-windows/py39-libs/include/longobject.h b/scripts/build-windows/py39-libs/include/longobject.h deleted file mode 100644 index 3ff911a19..000000000 --- a/scripts/build-windows/py39-libs/include/longobject.h +++ /dev/null @@ -1,242 +0,0 @@ -#ifndef Py_LONGOBJECT_H -#define Py_LONGOBJECT_H -#ifdef __cplusplus -extern "C" { -#endif - - -/* Long (arbitrary precision) integer object interface */ - -typedef struct _longobject PyLongObject; /* Revealed in longintrepr.h */ - -PyAPI_DATA(PyTypeObject) PyLong_Type; - -#define PyLong_Check(op) \ - PyType_FastSubclass(Py_TYPE(op), Py_TPFLAGS_LONG_SUBCLASS) -#define PyLong_CheckExact(op) Py_IS_TYPE(op, &PyLong_Type) - -PyAPI_FUNC(PyObject *) PyLong_FromLong(long); -PyAPI_FUNC(PyObject *) PyLong_FromUnsignedLong(unsigned long); -PyAPI_FUNC(PyObject *) PyLong_FromSize_t(size_t); -PyAPI_FUNC(PyObject *) PyLong_FromSsize_t(Py_ssize_t); -PyAPI_FUNC(PyObject *) PyLong_FromDouble(double); -PyAPI_FUNC(long) PyLong_AsLong(PyObject *); -PyAPI_FUNC(long) PyLong_AsLongAndOverflow(PyObject *, int *); -PyAPI_FUNC(Py_ssize_t) PyLong_AsSsize_t(PyObject *); -PyAPI_FUNC(size_t) PyLong_AsSize_t(PyObject *); -PyAPI_FUNC(unsigned long) PyLong_AsUnsignedLong(PyObject *); -PyAPI_FUNC(unsigned long) PyLong_AsUnsignedLongMask(PyObject *); -#ifndef Py_LIMITED_API -PyAPI_FUNC(int) _PyLong_AsInt(PyObject *); -#endif -PyAPI_FUNC(PyObject *) PyLong_GetInfo(void); - -/* It may be useful in the future. I've added it in the PyInt -> PyLong - cleanup to keep the extra information. [CH] */ -#define PyLong_AS_LONG(op) PyLong_AsLong(op) - -/* Issue #1983: pid_t can be longer than a C long on some systems */ -#if !defined(SIZEOF_PID_T) || SIZEOF_PID_T == SIZEOF_INT -#define _Py_PARSE_PID "i" -#define PyLong_FromPid PyLong_FromLong -#define PyLong_AsPid PyLong_AsLong -#elif SIZEOF_PID_T == SIZEOF_LONG -#define _Py_PARSE_PID "l" -#define PyLong_FromPid PyLong_FromLong -#define PyLong_AsPid PyLong_AsLong -#elif defined(SIZEOF_LONG_LONG) && SIZEOF_PID_T == SIZEOF_LONG_LONG -#define _Py_PARSE_PID "L" -#define PyLong_FromPid PyLong_FromLongLong -#define PyLong_AsPid PyLong_AsLongLong -#else -#error "sizeof(pid_t) is neither sizeof(int), sizeof(long) or sizeof(long long)" -#endif /* SIZEOF_PID_T */ - -#if SIZEOF_VOID_P == SIZEOF_INT -# define _Py_PARSE_INTPTR "i" -# define _Py_PARSE_UINTPTR "I" -#elif SIZEOF_VOID_P == SIZEOF_LONG -# define _Py_PARSE_INTPTR "l" -# define _Py_PARSE_UINTPTR "k" -#elif defined(SIZEOF_LONG_LONG) && SIZEOF_VOID_P == SIZEOF_LONG_LONG -# define _Py_PARSE_INTPTR "L" -# define _Py_PARSE_UINTPTR "K" -#else -# error "void* different in size from int, long and long long" -#endif /* SIZEOF_VOID_P */ - -#ifndef Py_LIMITED_API -PyAPI_FUNC(int) _PyLong_UnsignedShort_Converter(PyObject *, void *); -PyAPI_FUNC(int) _PyLong_UnsignedInt_Converter(PyObject *, void *); -PyAPI_FUNC(int) _PyLong_UnsignedLong_Converter(PyObject *, void *); -PyAPI_FUNC(int) _PyLong_UnsignedLongLong_Converter(PyObject *, void *); -PyAPI_FUNC(int) _PyLong_Size_t_Converter(PyObject *, void *); -#endif - -/* Used by Python/mystrtoul.c, _PyBytes_FromHex(), - _PyBytes_DecodeEscape(), etc. */ -#ifndef Py_LIMITED_API -PyAPI_DATA(unsigned char) _PyLong_DigitValue[256]; -#endif - -/* _PyLong_Frexp returns a double x and an exponent e such that the - true value is approximately equal to x * 2**e. e is >= 0. x is - 0.0 if and only if the input is 0 (in which case, e and x are both - zeroes); otherwise, 0.5 <= abs(x) < 1.0. On overflow, which is - possible if the number of bits doesn't fit into a Py_ssize_t, sets - OverflowError and returns -1.0 for x, 0 for e. */ -#ifndef Py_LIMITED_API -PyAPI_FUNC(double) _PyLong_Frexp(PyLongObject *a, Py_ssize_t *e); -#endif - -PyAPI_FUNC(double) PyLong_AsDouble(PyObject *); -PyAPI_FUNC(PyObject *) PyLong_FromVoidPtr(void *); -PyAPI_FUNC(void *) PyLong_AsVoidPtr(PyObject *); - -PyAPI_FUNC(PyObject *) PyLong_FromLongLong(long long); -PyAPI_FUNC(PyObject *) PyLong_FromUnsignedLongLong(unsigned long long); -PyAPI_FUNC(long long) PyLong_AsLongLong(PyObject *); -PyAPI_FUNC(unsigned long long) PyLong_AsUnsignedLongLong(PyObject *); -PyAPI_FUNC(unsigned long long) PyLong_AsUnsignedLongLongMask(PyObject *); -PyAPI_FUNC(long long) PyLong_AsLongLongAndOverflow(PyObject *, int *); - -PyAPI_FUNC(PyObject *) PyLong_FromString(const char *, char **, int); -#ifndef Py_LIMITED_API -Py_DEPRECATED(3.3) -PyAPI_FUNC(PyObject *) PyLong_FromUnicode(Py_UNICODE*, Py_ssize_t, int); -PyAPI_FUNC(PyObject *) PyLong_FromUnicodeObject(PyObject *u, int base); -PyAPI_FUNC(PyObject *) _PyLong_FromBytes(const char *, Py_ssize_t, int); -#endif - -#ifndef Py_LIMITED_API -/* _PyLong_Sign. Return 0 if v is 0, -1 if v < 0, +1 if v > 0. - v must not be NULL, and must be a normalized long. - There are no error cases. -*/ -PyAPI_FUNC(int) _PyLong_Sign(PyObject *v); - - -/* _PyLong_NumBits. Return the number of bits needed to represent the - absolute value of a long. For example, this returns 1 for 1 and -1, 2 - for 2 and -2, and 2 for 3 and -3. It returns 0 for 0. - v must not be NULL, and must be a normalized long. - (size_t)-1 is returned and OverflowError set if the true result doesn't - fit in a size_t. -*/ -PyAPI_FUNC(size_t) _PyLong_NumBits(PyObject *v); - -/* _PyLong_DivmodNear. Given integers a and b, compute the nearest - integer q to the exact quotient a / b, rounding to the nearest even integer - in the case of a tie. Return (q, r), where r = a - q*b. The remainder r - will satisfy abs(r) <= abs(b)/2, with equality possible only if q is - even. -*/ -PyAPI_FUNC(PyObject *) _PyLong_DivmodNear(PyObject *, PyObject *); - -/* _PyLong_FromByteArray: View the n unsigned bytes as a binary integer in - base 256, and return a Python int with the same numeric value. - If n is 0, the integer is 0. Else: - If little_endian is 1/true, bytes[n-1] is the MSB and bytes[0] the LSB; - else (little_endian is 0/false) bytes[0] is the MSB and bytes[n-1] the - LSB. - If is_signed is 0/false, view the bytes as a non-negative integer. - If is_signed is 1/true, view the bytes as a 2's-complement integer, - non-negative if bit 0x80 of the MSB is clear, negative if set. - Error returns: - + Return NULL with the appropriate exception set if there's not - enough memory to create the Python int. -*/ -PyAPI_FUNC(PyObject *) _PyLong_FromByteArray( - const unsigned char* bytes, size_t n, - int little_endian, int is_signed); - -/* _PyLong_AsByteArray: Convert the least-significant 8*n bits of long - v to a base-256 integer, stored in array bytes. Normally return 0, - return -1 on error. - If little_endian is 1/true, store the MSB at bytes[n-1] and the LSB at - bytes[0]; else (little_endian is 0/false) store the MSB at bytes[0] and - the LSB at bytes[n-1]. - If is_signed is 0/false, it's an error if v < 0; else (v >= 0) n bytes - are filled and there's nothing special about bit 0x80 of the MSB. - If is_signed is 1/true, bytes is filled with the 2's-complement - representation of v's value. Bit 0x80 of the MSB is the sign bit. - Error returns (-1): - + is_signed is 0 and v < 0. TypeError is set in this case, and bytes - isn't altered. - + n isn't big enough to hold the full mathematical value of v. For - example, if is_signed is 0 and there are more digits in the v than - fit in n; or if is_signed is 1, v < 0, and n is just 1 bit shy of - being large enough to hold a sign bit. OverflowError is set in this - case, but bytes holds the least-significant n bytes of the true value. -*/ -PyAPI_FUNC(int) _PyLong_AsByteArray(PyLongObject* v, - unsigned char* bytes, size_t n, - int little_endian, int is_signed); - -/* _PyLong_FromNbInt: Convert the given object to a PyLongObject - using the nb_int slot, if available. Raise TypeError if either the - nb_int slot is not available or the result of the call to nb_int - returns something not of type int. -*/ -PyAPI_FUNC(PyObject *) _PyLong_FromNbInt(PyObject *); - -/* Convert the given object to a PyLongObject using the nb_index or - nb_int slots, if available (the latter is deprecated). - Raise TypeError if either nb_index and nb_int slots are not - available or the result of the call to nb_index or nb_int - returns something not of type int. - Should be replaced with PyNumber_Index after the end of the - deprecation period. -*/ -PyAPI_FUNC(PyObject *) _PyLong_FromNbIndexOrNbInt(PyObject *); - -/* _PyLong_Format: Convert the long to a string object with given base, - appending a base prefix of 0[box] if base is 2, 8 or 16. */ -PyAPI_FUNC(PyObject *) _PyLong_Format(PyObject *obj, int base); - -PyAPI_FUNC(int) _PyLong_FormatWriter( - _PyUnicodeWriter *writer, - PyObject *obj, - int base, - int alternate); - -PyAPI_FUNC(char*) _PyLong_FormatBytesWriter( - _PyBytesWriter *writer, - char *str, - PyObject *obj, - int base, - int alternate); - -/* Format the object based on the format_spec, as defined in PEP 3101 - (Advanced String Formatting). */ -PyAPI_FUNC(int) _PyLong_FormatAdvancedWriter( - _PyUnicodeWriter *writer, - PyObject *obj, - PyObject *format_spec, - Py_ssize_t start, - Py_ssize_t end); -#endif /* Py_LIMITED_API */ - -/* These aren't really part of the int object, but they're handy. The - functions are in Python/mystrtoul.c. - */ -PyAPI_FUNC(unsigned long) PyOS_strtoul(const char *, char **, int); -PyAPI_FUNC(long) PyOS_strtol(const char *, char **, int); - -#ifndef Py_LIMITED_API -/* For use by the gcd function in mathmodule.c */ -PyAPI_FUNC(PyObject *) _PyLong_GCD(PyObject *, PyObject *); -#endif /* !Py_LIMITED_API */ - -#ifndef Py_LIMITED_API -PyAPI_DATA(PyObject *) _PyLong_Zero; -PyAPI_DATA(PyObject *) _PyLong_One; - -PyAPI_FUNC(PyObject *) _PyLong_Rshift(PyObject *, size_t); -PyAPI_FUNC(PyObject *) _PyLong_Lshift(PyObject *, size_t); -#endif - -#ifdef __cplusplus -} -#endif -#endif /* !Py_LONGOBJECT_H */ diff --git a/scripts/build-windows/py39-libs/include/marshal.h b/scripts/build-windows/py39-libs/include/marshal.h deleted file mode 100644 index de9dfbbf2..000000000 --- a/scripts/build-windows/py39-libs/include/marshal.h +++ /dev/null @@ -1,28 +0,0 @@ - -/* Interface for marshal.c */ - -#ifndef Py_MARSHAL_H -#define Py_MARSHAL_H -#ifdef __cplusplus -extern "C" { -#endif - -#define Py_MARSHAL_VERSION 4 - -PyAPI_FUNC(void) PyMarshal_WriteLongToFile(long, FILE *, int); -PyAPI_FUNC(void) PyMarshal_WriteObjectToFile(PyObject *, FILE *, int); -PyAPI_FUNC(PyObject *) PyMarshal_WriteObjectToString(PyObject *, int); - -#ifndef Py_LIMITED_API -PyAPI_FUNC(long) PyMarshal_ReadLongFromFile(FILE *); -PyAPI_FUNC(int) PyMarshal_ReadShortFromFile(FILE *); -PyAPI_FUNC(PyObject *) PyMarshal_ReadObjectFromFile(FILE *); -PyAPI_FUNC(PyObject *) PyMarshal_ReadLastObjectFromFile(FILE *); -#endif -PyAPI_FUNC(PyObject *) PyMarshal_ReadObjectFromString(const char *, - Py_ssize_t); - -#ifdef __cplusplus -} -#endif -#endif /* !Py_MARSHAL_H */ diff --git a/scripts/build-windows/py39-libs/include/memoryobject.h b/scripts/build-windows/py39-libs/include/memoryobject.h deleted file mode 100644 index 3a7f2c209..000000000 --- a/scripts/build-windows/py39-libs/include/memoryobject.h +++ /dev/null @@ -1,72 +0,0 @@ -/* Memory view object. In Python this is available as "memoryview". */ - -#ifndef Py_MEMORYOBJECT_H -#define Py_MEMORYOBJECT_H -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef Py_LIMITED_API -PyAPI_DATA(PyTypeObject) _PyManagedBuffer_Type; -#endif -PyAPI_DATA(PyTypeObject) PyMemoryView_Type; - -#define PyMemoryView_Check(op) Py_IS_TYPE(op, &PyMemoryView_Type) - -#ifndef Py_LIMITED_API -/* Get a pointer to the memoryview's private copy of the exporter's buffer. */ -#define PyMemoryView_GET_BUFFER(op) (&((PyMemoryViewObject *)(op))->view) -/* Get a pointer to the exporting object (this may be NULL!). */ -#define PyMemoryView_GET_BASE(op) (((PyMemoryViewObject *)(op))->view.obj) -#endif - -PyAPI_FUNC(PyObject *) PyMemoryView_FromObject(PyObject *base); -#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03030000 -PyAPI_FUNC(PyObject *) PyMemoryView_FromMemory(char *mem, Py_ssize_t size, - int flags); -#endif -#ifndef Py_LIMITED_API -PyAPI_FUNC(PyObject *) PyMemoryView_FromBuffer(Py_buffer *info); -#endif -PyAPI_FUNC(PyObject *) PyMemoryView_GetContiguous(PyObject *base, - int buffertype, - char order); - - -/* The structs are declared here so that macros can work, but they shouldn't - be considered public. Don't access their fields directly, use the macros - and functions instead! */ -#ifndef Py_LIMITED_API -#define _Py_MANAGED_BUFFER_RELEASED 0x001 /* access to exporter blocked */ -#define _Py_MANAGED_BUFFER_FREE_FORMAT 0x002 /* free format */ -typedef struct { - PyObject_HEAD - int flags; /* state flags */ - Py_ssize_t exports; /* number of direct memoryview exports */ - Py_buffer master; /* snapshot buffer obtained from the original exporter */ -} _PyManagedBufferObject; - - -/* memoryview state flags */ -#define _Py_MEMORYVIEW_RELEASED 0x001 /* access to master buffer blocked */ -#define _Py_MEMORYVIEW_C 0x002 /* C-contiguous layout */ -#define _Py_MEMORYVIEW_FORTRAN 0x004 /* Fortran contiguous layout */ -#define _Py_MEMORYVIEW_SCALAR 0x008 /* scalar: ndim = 0 */ -#define _Py_MEMORYVIEW_PIL 0x010 /* PIL-style layout */ - -typedef struct { - PyObject_VAR_HEAD - _PyManagedBufferObject *mbuf; /* managed buffer */ - Py_hash_t hash; /* hash value for read-only views */ - int flags; /* state flags */ - Py_ssize_t exports; /* number of buffer re-exports */ - Py_buffer view; /* private copy of the exporter's view */ - PyObject *weakreflist; - Py_ssize_t ob_array[1]; /* shape, strides, suboffsets */ -} PyMemoryViewObject; -#endif - -#ifdef __cplusplus -} -#endif -#endif /* !Py_MEMORYOBJECT_H */ diff --git a/scripts/build-windows/py39-libs/include/methodobject.h b/scripts/build-windows/py39-libs/include/methodobject.h deleted file mode 100644 index a90a2b5f4..000000000 --- a/scripts/build-windows/py39-libs/include/methodobject.h +++ /dev/null @@ -1,110 +0,0 @@ - -/* Method object interface */ - -#ifndef Py_METHODOBJECT_H -#define Py_METHODOBJECT_H -#ifdef __cplusplus -extern "C" { -#endif - -/* This is about the type 'builtin_function_or_method', - not Python methods in user-defined classes. See classobject.h - for the latter. */ - -PyAPI_DATA(PyTypeObject) PyCFunction_Type; - -#define PyCFunction_CheckExact(op) Py_IS_TYPE(op, &PyCFunction_Type) -#define PyCFunction_Check(op) PyObject_TypeCheck(op, &PyCFunction_Type) - -typedef PyObject *(*PyCFunction)(PyObject *, PyObject *); -typedef PyObject *(*_PyCFunctionFast) (PyObject *, PyObject *const *, Py_ssize_t); -typedef PyObject *(*PyCFunctionWithKeywords)(PyObject *, PyObject *, - PyObject *); -typedef PyObject *(*_PyCFunctionFastWithKeywords) (PyObject *, - PyObject *const *, Py_ssize_t, - PyObject *); -typedef PyObject *(*PyCMethod)(PyObject *, PyTypeObject *, PyObject *const *, - size_t, PyObject *); - -PyAPI_FUNC(PyCFunction) PyCFunction_GetFunction(PyObject *); -PyAPI_FUNC(PyObject *) PyCFunction_GetSelf(PyObject *); -PyAPI_FUNC(int) PyCFunction_GetFlags(PyObject *); - -Py_DEPRECATED(3.9) PyAPI_FUNC(PyObject *) PyCFunction_Call(PyObject *, PyObject *, PyObject *); - -struct PyMethodDef { - const char *ml_name; /* The name of the built-in function/method */ - PyCFunction ml_meth; /* The C function that implements it */ - int ml_flags; /* Combination of METH_xxx flags, which mostly - describe the args expected by the C func */ - const char *ml_doc; /* The __doc__ attribute, or NULL */ -}; -typedef struct PyMethodDef PyMethodDef; - -#define PyCFunction_New(ML, SELF) PyCFunction_NewEx((ML), (SELF), NULL) -PyAPI_FUNC(PyObject *) PyCFunction_NewEx(PyMethodDef *, PyObject *, - PyObject *); - -#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03090000 -#define PyCFunction_NewEx(ML, SELF, MOD) PyCMethod_New((ML), (SELF), (MOD), NULL) -PyAPI_FUNC(PyObject *) PyCMethod_New(PyMethodDef *, PyObject *, - PyObject *, PyTypeObject *); -#endif - - -/* Flag passed to newmethodobject */ -/* #define METH_OLDARGS 0x0000 -- unsupported now */ -#define METH_VARARGS 0x0001 -#define METH_KEYWORDS 0x0002 -/* METH_NOARGS and METH_O must not be combined with the flags above. */ -#define METH_NOARGS 0x0004 -#define METH_O 0x0008 - -/* METH_CLASS and METH_STATIC are a little different; these control - the construction of methods for a class. These cannot be used for - functions in modules. */ -#define METH_CLASS 0x0010 -#define METH_STATIC 0x0020 - -/* METH_COEXIST allows a method to be entered even though a slot has - already filled the entry. When defined, the flag allows a separate - method, "__contains__" for example, to coexist with a defined - slot like sq_contains. */ - -#define METH_COEXIST 0x0040 - -#ifndef Py_LIMITED_API -#define METH_FASTCALL 0x0080 -#endif - -/* This bit is preserved for Stackless Python */ -#ifdef STACKLESS -#define METH_STACKLESS 0x0100 -#else -#define METH_STACKLESS 0x0000 -#endif - -/* METH_METHOD means the function stores an - * additional reference to the class that defines it; - * both self and class are passed to it. - * It uses PyCMethodObject instead of PyCFunctionObject. - * May not be combined with METH_NOARGS, METH_O, METH_CLASS or METH_STATIC. - */ - -#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03090000 -#define METH_METHOD 0x0200 -#endif - - -#ifndef Py_LIMITED_API - -#define Py_CPYTHON_METHODOBJECT_H -#include "cpython/methodobject.h" -#undef Py_CPYTHON_METHODOBJECT_H - -#endif - -#ifdef __cplusplus -} -#endif -#endif /* !Py_METHODOBJECT_H */ diff --git a/scripts/build-windows/py39-libs/include/modsupport.h b/scripts/build-windows/py39-libs/include/modsupport.h deleted file mode 100644 index 799116267..000000000 --- a/scripts/build-windows/py39-libs/include/modsupport.h +++ /dev/null @@ -1,255 +0,0 @@ - -#ifndef Py_MODSUPPORT_H -#define Py_MODSUPPORT_H -#ifdef __cplusplus -extern "C" { -#endif - -/* Module support interface */ - -#include - -/* If PY_SSIZE_T_CLEAN is defined, each functions treats #-specifier - to mean Py_ssize_t */ -#ifdef PY_SSIZE_T_CLEAN -#define PyArg_Parse _PyArg_Parse_SizeT -#define PyArg_ParseTuple _PyArg_ParseTuple_SizeT -#define PyArg_ParseTupleAndKeywords _PyArg_ParseTupleAndKeywords_SizeT -#define PyArg_VaParse _PyArg_VaParse_SizeT -#define PyArg_VaParseTupleAndKeywords _PyArg_VaParseTupleAndKeywords_SizeT -#define Py_BuildValue _Py_BuildValue_SizeT -#define Py_VaBuildValue _Py_VaBuildValue_SizeT -#ifndef Py_LIMITED_API -#define _Py_VaBuildStack _Py_VaBuildStack_SizeT -#endif -#else -#ifndef Py_LIMITED_API -PyAPI_FUNC(PyObject *) _Py_VaBuildValue_SizeT(const char *, va_list); -PyAPI_FUNC(PyObject **) _Py_VaBuildStack_SizeT( - PyObject **small_stack, - Py_ssize_t small_stack_len, - const char *format, - va_list va, - Py_ssize_t *p_nargs); -#endif /* !Py_LIMITED_API */ -#endif - -/* Due to a glitch in 3.2, the _SizeT versions weren't exported from the DLL. */ -#if !defined(PY_SSIZE_T_CLEAN) || !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03030000 -PyAPI_FUNC(int) PyArg_Parse(PyObject *, const char *, ...); -PyAPI_FUNC(int) PyArg_ParseTuple(PyObject *, const char *, ...); -PyAPI_FUNC(int) PyArg_ParseTupleAndKeywords(PyObject *, PyObject *, - const char *, char **, ...); -PyAPI_FUNC(int) PyArg_VaParse(PyObject *, const char *, va_list); -PyAPI_FUNC(int) PyArg_VaParseTupleAndKeywords(PyObject *, PyObject *, - const char *, char **, va_list); -#endif -PyAPI_FUNC(int) PyArg_ValidateKeywordArguments(PyObject *); -PyAPI_FUNC(int) PyArg_UnpackTuple(PyObject *, const char *, Py_ssize_t, Py_ssize_t, ...); -PyAPI_FUNC(PyObject *) Py_BuildValue(const char *, ...); -PyAPI_FUNC(PyObject *) _Py_BuildValue_SizeT(const char *, ...); - - -#ifndef Py_LIMITED_API -PyAPI_FUNC(int) _PyArg_UnpackStack( - PyObject *const *args, - Py_ssize_t nargs, - const char *name, - Py_ssize_t min, - Py_ssize_t max, - ...); - -PyAPI_FUNC(int) _PyArg_NoKeywords(const char *funcname, PyObject *kwargs); -PyAPI_FUNC(int) _PyArg_NoKwnames(const char *funcname, PyObject *kwnames); -PyAPI_FUNC(int) _PyArg_NoPositional(const char *funcname, PyObject *args); -#define _PyArg_NoKeywords(funcname, kwargs) \ - ((kwargs) == NULL || _PyArg_NoKeywords((funcname), (kwargs))) -#define _PyArg_NoKwnames(funcname, kwnames) \ - ((kwnames) == NULL || _PyArg_NoKwnames((funcname), (kwnames))) -#define _PyArg_NoPositional(funcname, args) \ - ((args) == NULL || _PyArg_NoPositional((funcname), (args))) - -PyAPI_FUNC(void) _PyArg_BadArgument(const char *, const char *, const char *, PyObject *); -PyAPI_FUNC(int) _PyArg_CheckPositional(const char *, Py_ssize_t, - Py_ssize_t, Py_ssize_t); -#define _PyArg_CheckPositional(funcname, nargs, min, max) \ - (((min) <= (nargs) && (nargs) <= (max)) \ - || _PyArg_CheckPositional((funcname), (nargs), (min), (max))) - -#endif - -PyAPI_FUNC(PyObject *) Py_VaBuildValue(const char *, va_list); -#ifndef Py_LIMITED_API -PyAPI_FUNC(PyObject **) _Py_VaBuildStack( - PyObject **small_stack, - Py_ssize_t small_stack_len, - const char *format, - va_list va, - Py_ssize_t *p_nargs); -#endif - -#ifndef Py_LIMITED_API -typedef struct _PyArg_Parser { - const char *format; - const char * const *keywords; - const char *fname; - const char *custom_msg; - int pos; /* number of positional-only arguments */ - int min; /* minimal number of arguments */ - int max; /* maximal number of positional arguments */ - PyObject *kwtuple; /* tuple of keyword parameter names */ - struct _PyArg_Parser *next; -} _PyArg_Parser; -#ifdef PY_SSIZE_T_CLEAN -#define _PyArg_ParseTupleAndKeywordsFast _PyArg_ParseTupleAndKeywordsFast_SizeT -#define _PyArg_ParseStack _PyArg_ParseStack_SizeT -#define _PyArg_ParseStackAndKeywords _PyArg_ParseStackAndKeywords_SizeT -#define _PyArg_VaParseTupleAndKeywordsFast _PyArg_VaParseTupleAndKeywordsFast_SizeT -#endif -PyAPI_FUNC(int) _PyArg_ParseTupleAndKeywordsFast(PyObject *, PyObject *, - struct _PyArg_Parser *, ...); -PyAPI_FUNC(int) _PyArg_ParseStack( - PyObject *const *args, - Py_ssize_t nargs, - const char *format, - ...); -PyAPI_FUNC(int) _PyArg_ParseStackAndKeywords( - PyObject *const *args, - Py_ssize_t nargs, - PyObject *kwnames, - struct _PyArg_Parser *, - ...); -PyAPI_FUNC(int) _PyArg_VaParseTupleAndKeywordsFast(PyObject *, PyObject *, - struct _PyArg_Parser *, va_list); -PyAPI_FUNC(PyObject * const *) _PyArg_UnpackKeywords( - PyObject *const *args, Py_ssize_t nargs, - PyObject *kwargs, PyObject *kwnames, - struct _PyArg_Parser *parser, - int minpos, int maxpos, int minkw, - PyObject **buf); -#define _PyArg_UnpackKeywords(args, nargs, kwargs, kwnames, parser, minpos, maxpos, minkw, buf) \ - (((minkw) == 0 && (kwargs) == NULL && (kwnames) == NULL && \ - (minpos) <= (nargs) && (nargs) <= (maxpos) && args != NULL) ? (args) : \ - _PyArg_UnpackKeywords((args), (nargs), (kwargs), (kwnames), (parser), \ - (minpos), (maxpos), (minkw), (buf))) - -void _PyArg_Fini(void); -#endif /* Py_LIMITED_API */ - -PyAPI_FUNC(int) PyModule_AddObject(PyObject *, const char *, PyObject *); -PyAPI_FUNC(int) PyModule_AddIntConstant(PyObject *, const char *, long); -PyAPI_FUNC(int) PyModule_AddStringConstant(PyObject *, const char *, const char *); -#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03090000 -/* New in 3.9 */ -PyAPI_FUNC(int) PyModule_AddType(PyObject *module, PyTypeObject *type); -#endif /* Py_LIMITED_API */ -#define PyModule_AddIntMacro(m, c) PyModule_AddIntConstant(m, #c, c) -#define PyModule_AddStringMacro(m, c) PyModule_AddStringConstant(m, #c, c) - -#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03050000 -/* New in 3.5 */ -PyAPI_FUNC(int) PyModule_SetDocString(PyObject *, const char *); -PyAPI_FUNC(int) PyModule_AddFunctions(PyObject *, PyMethodDef *); -PyAPI_FUNC(int) PyModule_ExecDef(PyObject *module, PyModuleDef *def); -#endif - -#define Py_CLEANUP_SUPPORTED 0x20000 - -#define PYTHON_API_VERSION 1013 -#define PYTHON_API_STRING "1013" -/* The API version is maintained (independently from the Python version) - so we can detect mismatches between the interpreter and dynamically - loaded modules. These are diagnosed by an error message but - the module is still loaded (because the mismatch can only be tested - after loading the module). The error message is intended to - explain the core dump a few seconds later. - - The symbol PYTHON_API_STRING defines the same value as a string - literal. *** PLEASE MAKE SURE THE DEFINITIONS MATCH. *** - - Please add a line or two to the top of this log for each API - version change: - - 22-Feb-2006 MvL 1013 PEP 353 - long indices for sequence lengths - - 19-Aug-2002 GvR 1012 Changes to string object struct for - interning changes, saving 3 bytes. - - 17-Jul-2001 GvR 1011 Descr-branch, just to be on the safe side - - 25-Jan-2001 FLD 1010 Parameters added to PyCode_New() and - PyFrame_New(); Python 2.1a2 - - 14-Mar-2000 GvR 1009 Unicode API added - - 3-Jan-1999 GvR 1007 Decided to change back! (Don't reuse 1008!) - - 3-Dec-1998 GvR 1008 Python 1.5.2b1 - - 18-Jan-1997 GvR 1007 string interning and other speedups - - 11-Oct-1996 GvR renamed Py_Ellipses to Py_Ellipsis :-( - - 30-Jul-1996 GvR Slice and ellipses syntax added - - 23-Jul-1996 GvR For 1.4 -- better safe than sorry this time :-) - - 7-Nov-1995 GvR Keyword arguments (should've been done at 1.3 :-( ) - - 10-Jan-1995 GvR Renamed globals to new naming scheme - - 9-Jan-1995 GvR Initial version (incompatible with older API) -*/ - -/* The PYTHON_ABI_VERSION is introduced in PEP 384. For the lifetime of - Python 3, it will stay at the value of 3; changes to the limited API - must be performed in a strictly backwards-compatible manner. */ -#define PYTHON_ABI_VERSION 3 -#define PYTHON_ABI_STRING "3" - -#ifdef Py_TRACE_REFS - /* When we are tracing reference counts, rename module creation functions so - modules compiled with incompatible settings will generate a - link-time error. */ - #define PyModule_Create2 PyModule_Create2TraceRefs - #define PyModule_FromDefAndSpec2 PyModule_FromDefAndSpec2TraceRefs -#endif - -PyAPI_FUNC(PyObject *) PyModule_Create2(struct PyModuleDef*, - int apiver); -#ifndef Py_LIMITED_API -PyAPI_FUNC(PyObject *) _PyModule_CreateInitialized(struct PyModuleDef*, - int apiver); -#endif - -#ifdef Py_LIMITED_API -#define PyModule_Create(module) \ - PyModule_Create2(module, PYTHON_ABI_VERSION) -#else -#define PyModule_Create(module) \ - PyModule_Create2(module, PYTHON_API_VERSION) -#endif - -#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03050000 -/* New in 3.5 */ -PyAPI_FUNC(PyObject *) PyModule_FromDefAndSpec2(PyModuleDef *def, - PyObject *spec, - int module_api_version); - -#ifdef Py_LIMITED_API -#define PyModule_FromDefAndSpec(module, spec) \ - PyModule_FromDefAndSpec2(module, spec, PYTHON_ABI_VERSION) -#else -#define PyModule_FromDefAndSpec(module, spec) \ - PyModule_FromDefAndSpec2(module, spec, PYTHON_API_VERSION) -#endif /* Py_LIMITED_API */ -#endif /* New in 3.5 */ - -#ifndef Py_LIMITED_API -PyAPI_DATA(const char *) _Py_PackageContext; -#endif - -#ifdef __cplusplus -} -#endif -#endif /* !Py_MODSUPPORT_H */ diff --git a/scripts/build-windows/py39-libs/include/moduleobject.h b/scripts/build-windows/py39-libs/include/moduleobject.h deleted file mode 100644 index f02e32bb5..000000000 --- a/scripts/build-windows/py39-libs/include/moduleobject.h +++ /dev/null @@ -1,90 +0,0 @@ - -/* Module object interface */ - -#ifndef Py_MODULEOBJECT_H -#define Py_MODULEOBJECT_H -#ifdef __cplusplus -extern "C" { -#endif - -PyAPI_DATA(PyTypeObject) PyModule_Type; - -#define PyModule_Check(op) PyObject_TypeCheck(op, &PyModule_Type) -#define PyModule_CheckExact(op) Py_IS_TYPE(op, &PyModule_Type) - -#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03030000 -PyAPI_FUNC(PyObject *) PyModule_NewObject( - PyObject *name - ); -#endif -PyAPI_FUNC(PyObject *) PyModule_New( - const char *name /* UTF-8 encoded string */ - ); -PyAPI_FUNC(PyObject *) PyModule_GetDict(PyObject *); -#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03030000 -PyAPI_FUNC(PyObject *) PyModule_GetNameObject(PyObject *); -#endif -PyAPI_FUNC(const char *) PyModule_GetName(PyObject *); -Py_DEPRECATED(3.2) PyAPI_FUNC(const char *) PyModule_GetFilename(PyObject *); -PyAPI_FUNC(PyObject *) PyModule_GetFilenameObject(PyObject *); -#ifndef Py_LIMITED_API -PyAPI_FUNC(void) _PyModule_Clear(PyObject *); -PyAPI_FUNC(void) _PyModule_ClearDict(PyObject *); -PyAPI_FUNC(int) _PyModuleSpec_IsInitializing(PyObject *); -#endif -PyAPI_FUNC(struct PyModuleDef*) PyModule_GetDef(PyObject*); -PyAPI_FUNC(void*) PyModule_GetState(PyObject*); - -#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03050000 -/* New in 3.5 */ -PyAPI_FUNC(PyObject *) PyModuleDef_Init(struct PyModuleDef*); -PyAPI_DATA(PyTypeObject) PyModuleDef_Type; -#endif - -typedef struct PyModuleDef_Base { - PyObject_HEAD - PyObject* (*m_init)(void); - Py_ssize_t m_index; - PyObject* m_copy; -} PyModuleDef_Base; - -#define PyModuleDef_HEAD_INIT { \ - PyObject_HEAD_INIT(NULL) \ - NULL, /* m_init */ \ - 0, /* m_index */ \ - NULL, /* m_copy */ \ - } - -struct PyModuleDef_Slot; -#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03050000 -/* New in 3.5 */ -typedef struct PyModuleDef_Slot{ - int slot; - void *value; -} PyModuleDef_Slot; - -#define Py_mod_create 1 -#define Py_mod_exec 2 - -#ifndef Py_LIMITED_API -#define _Py_mod_LAST_SLOT 2 -#endif - -#endif /* New in 3.5 */ - -typedef struct PyModuleDef{ - PyModuleDef_Base m_base; - const char* m_name; - const char* m_doc; - Py_ssize_t m_size; - PyMethodDef *m_methods; - struct PyModuleDef_Slot* m_slots; - traverseproc m_traverse; - inquiry m_clear; - freefunc m_free; -} PyModuleDef; - -#ifdef __cplusplus -} -#endif -#endif /* !Py_MODULEOBJECT_H */ diff --git a/scripts/build-windows/py39-libs/include/namespaceobject.h b/scripts/build-windows/py39-libs/include/namespaceobject.h deleted file mode 100644 index 35146e5c9..000000000 --- a/scripts/build-windows/py39-libs/include/namespaceobject.h +++ /dev/null @@ -1,19 +0,0 @@ - -/* simple namespace object interface */ - -#ifndef NAMESPACEOBJECT_H -#define NAMESPACEOBJECT_H -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef Py_LIMITED_API -PyAPI_DATA(PyTypeObject) _PyNamespace_Type; - -PyAPI_FUNC(PyObject *) _PyNamespace_New(PyObject *kwds); -#endif /* !Py_LIMITED_API */ - -#ifdef __cplusplus -} -#endif -#endif /* !NAMESPACEOBJECT_H */ diff --git a/scripts/build-windows/py39-libs/include/node.h b/scripts/build-windows/py39-libs/include/node.h deleted file mode 100644 index 8db6298df..000000000 --- a/scripts/build-windows/py39-libs/include/node.h +++ /dev/null @@ -1,47 +0,0 @@ - -/* Parse tree node interface */ - -#ifndef Py_NODE_H -#define Py_NODE_H -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct _node { - short n_type; - char *n_str; - int n_lineno; - int n_col_offset; - int n_nchildren; - struct _node *n_child; - int n_end_lineno; - int n_end_col_offset; -} node; - -PyAPI_FUNC(node *) PyNode_New(int type); -PyAPI_FUNC(int) PyNode_AddChild(node *n, int type, - char *str, int lineno, int col_offset, - int end_lineno, int end_col_offset); -PyAPI_FUNC(void) PyNode_Free(node *n); -#ifndef Py_LIMITED_API -PyAPI_FUNC(Py_ssize_t) _PyNode_SizeOf(node *n); -#endif - -/* Node access functions */ -#define NCH(n) ((n)->n_nchildren) - -#define CHILD(n, i) (&(n)->n_child[i]) -#define TYPE(n) ((n)->n_type) -#define STR(n) ((n)->n_str) -#define LINENO(n) ((n)->n_lineno) - -/* Assert that the type of a node is what we expect */ -#define REQ(n, type) assert(TYPE(n) == (type)) - -PyAPI_FUNC(void) PyNode_ListTree(node *); -void _PyNode_FinalizeEndPos(node *n); // helper also used in parsetok.c - -#ifdef __cplusplus -} -#endif -#endif /* !Py_NODE_H */ diff --git a/scripts/build-windows/py39-libs/include/object.h b/scripts/build-windows/py39-libs/include/object.h deleted file mode 100644 index b07337f6d..000000000 --- a/scripts/build-windows/py39-libs/include/object.h +++ /dev/null @@ -1,648 +0,0 @@ -#ifndef Py_OBJECT_H -#define Py_OBJECT_H - -#ifdef __cplusplus -extern "C" { -#endif - - -/* Object and type object interface */ - -/* -Objects are structures allocated on the heap. Special rules apply to -the use of objects to ensure they are properly garbage-collected. -Objects are never allocated statically or on the stack; they must be -accessed through special macros and functions only. (Type objects are -exceptions to the first rule; the standard types are represented by -statically initialized type objects, although work on type/class unification -for Python 2.2 made it possible to have heap-allocated type objects too). - -An object has a 'reference count' that is increased or decreased when a -pointer to the object is copied or deleted; when the reference count -reaches zero there are no references to the object left and it can be -removed from the heap. - -An object has a 'type' that determines what it represents and what kind -of data it contains. An object's type is fixed when it is created. -Types themselves are represented as objects; an object contains a -pointer to the corresponding type object. The type itself has a type -pointer pointing to the object representing the type 'type', which -contains a pointer to itself!. - -Objects do not float around in memory; once allocated an object keeps -the same size and address. Objects that must hold variable-size data -can contain pointers to variable-size parts of the object. Not all -objects of the same type have the same size; but the size cannot change -after allocation. (These restrictions are made so a reference to an -object can be simply a pointer -- moving an object would require -updating all the pointers, and changing an object's size would require -moving it if there was another object right next to it.) - -Objects are always accessed through pointers of the type 'PyObject *'. -The type 'PyObject' is a structure that only contains the reference count -and the type pointer. The actual memory allocated for an object -contains other data that can only be accessed after casting the pointer -to a pointer to a longer structure type. This longer type must start -with the reference count and type fields; the macro PyObject_HEAD should be -used for this (to accommodate for future changes). The implementation -of a particular object type can cast the object pointer to the proper -type and back. - -A standard interface exists for objects that contain an array of items -whose size is determined when the object is allocated. -*/ - -/* Py_DEBUG implies Py_REF_DEBUG. */ -#if defined(Py_DEBUG) && !defined(Py_REF_DEBUG) -#define Py_REF_DEBUG -#endif - -#if defined(Py_LIMITED_API) && defined(Py_REF_DEBUG) -#error Py_LIMITED_API is incompatible with Py_DEBUG, Py_TRACE_REFS, and Py_REF_DEBUG -#endif - -/* PyTypeObject structure is defined in cpython/object.h. - In Py_LIMITED_API, PyTypeObject is an opaque structure. */ -typedef struct _typeobject PyTypeObject; - -#ifdef Py_TRACE_REFS -/* Define pointers to support a doubly-linked list of all live heap objects. */ -#define _PyObject_HEAD_EXTRA \ - struct _object *_ob_next; \ - struct _object *_ob_prev; - -#define _PyObject_EXTRA_INIT 0, 0, - -#else -#define _PyObject_HEAD_EXTRA -#define _PyObject_EXTRA_INIT -#endif - -/* PyObject_HEAD defines the initial segment of every PyObject. */ -#define PyObject_HEAD PyObject ob_base; - -#define PyObject_HEAD_INIT(type) \ - { _PyObject_EXTRA_INIT \ - 1, type }, - -#define PyVarObject_HEAD_INIT(type, size) \ - { PyObject_HEAD_INIT(type) size }, - -/* PyObject_VAR_HEAD defines the initial segment of all variable-size - * container objects. These end with a declaration of an array with 1 - * element, but enough space is malloc'ed so that the array actually - * has room for ob_size elements. Note that ob_size is an element count, - * not necessarily a byte count. - */ -#define PyObject_VAR_HEAD PyVarObject ob_base; -#define Py_INVALID_SIZE (Py_ssize_t)-1 - -/* Nothing is actually declared to be a PyObject, but every pointer to - * a Python object can be cast to a PyObject*. This is inheritance built - * by hand. Similarly every pointer to a variable-size Python object can, - * in addition, be cast to PyVarObject*. - */ -typedef struct _object { - _PyObject_HEAD_EXTRA - Py_ssize_t ob_refcnt; - PyTypeObject *ob_type; -} PyObject; - -/* Cast argument to PyObject* type. */ -#define _PyObject_CAST(op) ((PyObject*)(op)) -#define _PyObject_CAST_CONST(op) ((const PyObject*)(op)) - -typedef struct { - PyObject ob_base; - Py_ssize_t ob_size; /* Number of items in variable part */ -} PyVarObject; - -/* Cast argument to PyVarObject* type. */ -#define _PyVarObject_CAST(op) ((PyVarObject*)(op)) - -#define Py_REFCNT(ob) (_PyObject_CAST(ob)->ob_refcnt) -#define Py_TYPE(ob) (_PyObject_CAST(ob)->ob_type) -#define Py_SIZE(ob) (_PyVarObject_CAST(ob)->ob_size) - -static inline int _Py_IS_TYPE(const PyObject *ob, const PyTypeObject *type) { - return ob->ob_type == type; -} -#define Py_IS_TYPE(ob, type) _Py_IS_TYPE(_PyObject_CAST_CONST(ob), type) - -static inline void _Py_SET_REFCNT(PyObject *ob, Py_ssize_t refcnt) { - ob->ob_refcnt = refcnt; -} -#define Py_SET_REFCNT(ob, refcnt) _Py_SET_REFCNT(_PyObject_CAST(ob), refcnt) - -static inline void _Py_SET_TYPE(PyObject *ob, PyTypeObject *type) { - ob->ob_type = type; -} -#define Py_SET_TYPE(ob, type) _Py_SET_TYPE(_PyObject_CAST(ob), type) - -static inline void _Py_SET_SIZE(PyVarObject *ob, Py_ssize_t size) { - ob->ob_size = size; -} -#define Py_SET_SIZE(ob, size) _Py_SET_SIZE(_PyVarObject_CAST(ob), size) - - -/* -Type objects contain a string containing the type name (to help somewhat -in debugging), the allocation parameters (see PyObject_New() and -PyObject_NewVar()), -and methods for accessing objects of the type. Methods are optional, a -nil pointer meaning that particular kind of access is not available for -this type. The Py_DECREF() macro uses the tp_dealloc method without -checking for a nil pointer; it should always be implemented except if -the implementation can guarantee that the reference count will never -reach zero (e.g., for statically allocated type objects). - -NB: the methods for certain type groups are now contained in separate -method blocks. -*/ - -typedef PyObject * (*unaryfunc)(PyObject *); -typedef PyObject * (*binaryfunc)(PyObject *, PyObject *); -typedef PyObject * (*ternaryfunc)(PyObject *, PyObject *, PyObject *); -typedef int (*inquiry)(PyObject *); -typedef Py_ssize_t (*lenfunc)(PyObject *); -typedef PyObject *(*ssizeargfunc)(PyObject *, Py_ssize_t); -typedef PyObject *(*ssizessizeargfunc)(PyObject *, Py_ssize_t, Py_ssize_t); -typedef int(*ssizeobjargproc)(PyObject *, Py_ssize_t, PyObject *); -typedef int(*ssizessizeobjargproc)(PyObject *, Py_ssize_t, Py_ssize_t, PyObject *); -typedef int(*objobjargproc)(PyObject *, PyObject *, PyObject *); - -typedef int (*objobjproc)(PyObject *, PyObject *); -typedef int (*visitproc)(PyObject *, void *); -typedef int (*traverseproc)(PyObject *, visitproc, void *); - - -typedef void (*freefunc)(void *); -typedef void (*destructor)(PyObject *); -typedef PyObject *(*getattrfunc)(PyObject *, char *); -typedef PyObject *(*getattrofunc)(PyObject *, PyObject *); -typedef int (*setattrfunc)(PyObject *, char *, PyObject *); -typedef int (*setattrofunc)(PyObject *, PyObject *, PyObject *); -typedef PyObject *(*reprfunc)(PyObject *); -typedef Py_hash_t (*hashfunc)(PyObject *); -typedef PyObject *(*richcmpfunc) (PyObject *, PyObject *, int); -typedef PyObject *(*getiterfunc) (PyObject *); -typedef PyObject *(*iternextfunc) (PyObject *); -typedef PyObject *(*descrgetfunc) (PyObject *, PyObject *, PyObject *); -typedef int (*descrsetfunc) (PyObject *, PyObject *, PyObject *); -typedef int (*initproc)(PyObject *, PyObject *, PyObject *); -typedef PyObject *(*newfunc)(PyTypeObject *, PyObject *, PyObject *); -typedef PyObject *(*allocfunc)(PyTypeObject *, Py_ssize_t); - -typedef struct{ - int slot; /* slot id, see below */ - void *pfunc; /* function pointer */ -} PyType_Slot; - -typedef struct{ - const char* name; - int basicsize; - int itemsize; - unsigned int flags; - PyType_Slot *slots; /* terminated by slot==0. */ -} PyType_Spec; - -PyAPI_FUNC(PyObject*) PyType_FromSpec(PyType_Spec*); -#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03030000 -PyAPI_FUNC(PyObject*) PyType_FromSpecWithBases(PyType_Spec*, PyObject*); -#endif -#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03040000 -PyAPI_FUNC(void*) PyType_GetSlot(PyTypeObject*, int); -#endif -#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03090000 -PyAPI_FUNC(PyObject*) PyType_FromModuleAndSpec(PyObject *, PyType_Spec *, PyObject *); -PyAPI_FUNC(PyObject *) PyType_GetModule(struct _typeobject *); -PyAPI_FUNC(void *) PyType_GetModuleState(struct _typeobject *); -#endif - -/* Generic type check */ -PyAPI_FUNC(int) PyType_IsSubtype(PyTypeObject *, PyTypeObject *); -#define PyObject_TypeCheck(ob, tp) \ - (Py_IS_TYPE(ob, tp) || PyType_IsSubtype(Py_TYPE(ob), (tp))) - -PyAPI_DATA(PyTypeObject) PyType_Type; /* built-in 'type' */ -PyAPI_DATA(PyTypeObject) PyBaseObject_Type; /* built-in 'object' */ -PyAPI_DATA(PyTypeObject) PySuper_Type; /* built-in 'super' */ - -PyAPI_FUNC(unsigned long) PyType_GetFlags(PyTypeObject*); - -PyAPI_FUNC(int) PyType_Ready(PyTypeObject *); -PyAPI_FUNC(PyObject *) PyType_GenericAlloc(PyTypeObject *, Py_ssize_t); -PyAPI_FUNC(PyObject *) PyType_GenericNew(PyTypeObject *, - PyObject *, PyObject *); -PyAPI_FUNC(unsigned int) PyType_ClearCache(void); -PyAPI_FUNC(void) PyType_Modified(PyTypeObject *); - -/* Generic operations on objects */ -PyAPI_FUNC(PyObject *) PyObject_Repr(PyObject *); -PyAPI_FUNC(PyObject *) PyObject_Str(PyObject *); -PyAPI_FUNC(PyObject *) PyObject_ASCII(PyObject *); -PyAPI_FUNC(PyObject *) PyObject_Bytes(PyObject *); -PyAPI_FUNC(PyObject *) PyObject_RichCompare(PyObject *, PyObject *, int); -PyAPI_FUNC(int) PyObject_RichCompareBool(PyObject *, PyObject *, int); -PyAPI_FUNC(PyObject *) PyObject_GetAttrString(PyObject *, const char *); -PyAPI_FUNC(int) PyObject_SetAttrString(PyObject *, const char *, PyObject *); -PyAPI_FUNC(int) PyObject_HasAttrString(PyObject *, const char *); -PyAPI_FUNC(PyObject *) PyObject_GetAttr(PyObject *, PyObject *); -PyAPI_FUNC(int) PyObject_SetAttr(PyObject *, PyObject *, PyObject *); -PyAPI_FUNC(int) PyObject_HasAttr(PyObject *, PyObject *); -PyAPI_FUNC(PyObject *) PyObject_SelfIter(PyObject *); -PyAPI_FUNC(PyObject *) PyObject_GenericGetAttr(PyObject *, PyObject *); -PyAPI_FUNC(int) PyObject_GenericSetAttr(PyObject *, PyObject *, PyObject *); -#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03030000 -PyAPI_FUNC(int) PyObject_GenericSetDict(PyObject *, PyObject *, void *); -#endif -PyAPI_FUNC(Py_hash_t) PyObject_Hash(PyObject *); -PyAPI_FUNC(Py_hash_t) PyObject_HashNotImplemented(PyObject *); -PyAPI_FUNC(int) PyObject_IsTrue(PyObject *); -PyAPI_FUNC(int) PyObject_Not(PyObject *); -PyAPI_FUNC(int) PyCallable_Check(PyObject *); -PyAPI_FUNC(void) PyObject_ClearWeakRefs(PyObject *); - -/* PyObject_Dir(obj) acts like Python builtins.dir(obj), returning a - list of strings. PyObject_Dir(NULL) is like builtins.dir(), - returning the names of the current locals. In this case, if there are - no current locals, NULL is returned, and PyErr_Occurred() is false. -*/ -PyAPI_FUNC(PyObject *) PyObject_Dir(PyObject *); - - -/* Helpers for printing recursive container types */ -PyAPI_FUNC(int) Py_ReprEnter(PyObject *); -PyAPI_FUNC(void) Py_ReprLeave(PyObject *); - -/* Flag bits for printing: */ -#define Py_PRINT_RAW 1 /* No string quotes etc. */ - -/* -Type flags (tp_flags) - -These flags are used to change expected features and behavior for a -particular type. - -Arbitration of the flag bit positions will need to be coordinated among -all extension writers who publicly release their extensions (this will -be fewer than you might expect!). - -Most flags were removed as of Python 3.0 to make room for new flags. (Some -flags are not for backwards compatibility but to indicate the presence of an -optional feature; these flags remain of course.) - -Type definitions should use Py_TPFLAGS_DEFAULT for their tp_flags value. - -Code can use PyType_HasFeature(type_ob, flag_value) to test whether the -given type object has a specified feature. -*/ - -/* Set if the type object is dynamically allocated */ -#define Py_TPFLAGS_HEAPTYPE (1UL << 9) - -/* Set if the type allows subclassing */ -#define Py_TPFLAGS_BASETYPE (1UL << 10) - -/* Set if the type implements the vectorcall protocol (PEP 590) */ -#ifndef Py_LIMITED_API -#define Py_TPFLAGS_HAVE_VECTORCALL (1UL << 11) -// Backwards compatibility alias for API that was provisional in Python 3.8 -#define _Py_TPFLAGS_HAVE_VECTORCALL Py_TPFLAGS_HAVE_VECTORCALL -#endif - -/* Set if the type is 'ready' -- fully initialized */ -#define Py_TPFLAGS_READY (1UL << 12) - -/* Set while the type is being 'readied', to prevent recursive ready calls */ -#define Py_TPFLAGS_READYING (1UL << 13) - -/* Objects support garbage collection (see objimpl.h) */ -#define Py_TPFLAGS_HAVE_GC (1UL << 14) - -/* These two bits are preserved for Stackless Python, next after this is 17 */ -#ifdef STACKLESS -#define Py_TPFLAGS_HAVE_STACKLESS_EXTENSION (3UL << 15) -#else -#define Py_TPFLAGS_HAVE_STACKLESS_EXTENSION 0 -#endif - -/* Objects behave like an unbound method */ -#define Py_TPFLAGS_METHOD_DESCRIPTOR (1UL << 17) - -/* Objects support type attribute cache */ -#define Py_TPFLAGS_HAVE_VERSION_TAG (1UL << 18) -#define Py_TPFLAGS_VALID_VERSION_TAG (1UL << 19) - -/* Type is abstract and cannot be instantiated */ -#define Py_TPFLAGS_IS_ABSTRACT (1UL << 20) - -/* These flags are used to determine if a type is a subclass. */ -#define Py_TPFLAGS_LONG_SUBCLASS (1UL << 24) -#define Py_TPFLAGS_LIST_SUBCLASS (1UL << 25) -#define Py_TPFLAGS_TUPLE_SUBCLASS (1UL << 26) -#define Py_TPFLAGS_BYTES_SUBCLASS (1UL << 27) -#define Py_TPFLAGS_UNICODE_SUBCLASS (1UL << 28) -#define Py_TPFLAGS_DICT_SUBCLASS (1UL << 29) -#define Py_TPFLAGS_BASE_EXC_SUBCLASS (1UL << 30) -#define Py_TPFLAGS_TYPE_SUBCLASS (1UL << 31) - -#define Py_TPFLAGS_DEFAULT ( \ - Py_TPFLAGS_HAVE_STACKLESS_EXTENSION | \ - Py_TPFLAGS_HAVE_VERSION_TAG | \ - 0) - -/* NOTE: The following flags reuse lower bits (removed as part of the - * Python 3.0 transition). */ - -/* The following flag is kept for compatibility. Starting with 3.8, - * binary compatibility of C extensions across feature releases of - * Python is not supported anymore, except when using the stable ABI. - */ - -/* Type structure has tp_finalize member (3.4) */ -#define Py_TPFLAGS_HAVE_FINALIZE (1UL << 0) - - -/* -The macros Py_INCREF(op) and Py_DECREF(op) are used to increment or decrement -reference counts. Py_DECREF calls the object's deallocator function when -the refcount falls to 0; for -objects that don't contain references to other objects or heap memory -this can be the standard function free(). Both macros can be used -wherever a void expression is allowed. The argument must not be a -NULL pointer. If it may be NULL, use Py_XINCREF/Py_XDECREF instead. -The macro _Py_NewReference(op) initialize reference counts to 1, and -in special builds (Py_REF_DEBUG, Py_TRACE_REFS) performs additional -bookkeeping appropriate to the special build. - -We assume that the reference count field can never overflow; this can -be proven when the size of the field is the same as the pointer size, so -we ignore the possibility. Provided a C int is at least 32 bits (which -is implicitly assumed in many parts of this code), that's enough for -about 2**31 references to an object. - -XXX The following became out of date in Python 2.2, but I'm not sure -XXX what the full truth is now. Certainly, heap-allocated type objects -XXX can and should be deallocated. -Type objects should never be deallocated; the type pointer in an object -is not considered to be a reference to the type object, to save -complications in the deallocation function. (This is actually a -decision that's up to the implementer of each new type so if you want, -you can count such references to the type object.) -*/ - -#ifdef Py_REF_DEBUG -PyAPI_DATA(Py_ssize_t) _Py_RefTotal; -PyAPI_FUNC(void) _Py_NegativeRefcount(const char *filename, int lineno, - PyObject *op); -#endif /* Py_REF_DEBUG */ - -PyAPI_FUNC(void) _Py_Dealloc(PyObject *); - -static inline void _Py_INCREF(PyObject *op) -{ -#ifdef Py_REF_DEBUG - _Py_RefTotal++; -#endif - op->ob_refcnt++; -} - -#define Py_INCREF(op) _Py_INCREF(_PyObject_CAST(op)) - -static inline void _Py_DECREF( -#ifdef Py_REF_DEBUG - const char *filename, int lineno, -#endif - PyObject *op) -{ -#ifdef Py_REF_DEBUG - _Py_RefTotal--; -#endif - if (--op->ob_refcnt != 0) { -#ifdef Py_REF_DEBUG - if (op->ob_refcnt < 0) { - _Py_NegativeRefcount(filename, lineno, op); - } -#endif - } - else { - _Py_Dealloc(op); - } -} - -#ifdef Py_REF_DEBUG -# define Py_DECREF(op) _Py_DECREF(__FILE__, __LINE__, _PyObject_CAST(op)) -#else -# define Py_DECREF(op) _Py_DECREF(_PyObject_CAST(op)) -#endif - - -/* Safely decref `op` and set `op` to NULL, especially useful in tp_clear - * and tp_dealloc implementations. - * - * Note that "the obvious" code can be deadly: - * - * Py_XDECREF(op); - * op = NULL; - * - * Typically, `op` is something like self->containee, and `self` is done - * using its `containee` member. In the code sequence above, suppose - * `containee` is non-NULL with a refcount of 1. Its refcount falls to - * 0 on the first line, which can trigger an arbitrary amount of code, - * possibly including finalizers (like __del__ methods or weakref callbacks) - * coded in Python, which in turn can release the GIL and allow other threads - * to run, etc. Such code may even invoke methods of `self` again, or cause - * cyclic gc to trigger, but-- oops! --self->containee still points to the - * object being torn down, and it may be in an insane state while being torn - * down. This has in fact been a rich historic source of miserable (rare & - * hard-to-diagnose) segfaulting (and other) bugs. - * - * The safe way is: - * - * Py_CLEAR(op); - * - * That arranges to set `op` to NULL _before_ decref'ing, so that any code - * triggered as a side-effect of `op` getting torn down no longer believes - * `op` points to a valid object. - * - * There are cases where it's safe to use the naive code, but they're brittle. - * For example, if `op` points to a Python integer, you know that destroying - * one of those can't cause problems -- but in part that relies on that - * Python integers aren't currently weakly referencable. Best practice is - * to use Py_CLEAR() even if you can't think of a reason for why you need to. - */ -#define Py_CLEAR(op) \ - do { \ - PyObject *_py_tmp = _PyObject_CAST(op); \ - if (_py_tmp != NULL) { \ - (op) = NULL; \ - Py_DECREF(_py_tmp); \ - } \ - } while (0) - -/* Function to use in case the object pointer can be NULL: */ -static inline void _Py_XINCREF(PyObject *op) -{ - if (op != NULL) { - Py_INCREF(op); - } -} - -#define Py_XINCREF(op) _Py_XINCREF(_PyObject_CAST(op)) - -static inline void _Py_XDECREF(PyObject *op) -{ - if (op != NULL) { - Py_DECREF(op); - } -} - -#define Py_XDECREF(op) _Py_XDECREF(_PyObject_CAST(op)) - -/* -These are provided as conveniences to Python runtime embedders, so that -they can have object code that is not dependent on Python compilation flags. -*/ -PyAPI_FUNC(void) Py_IncRef(PyObject *); -PyAPI_FUNC(void) Py_DecRef(PyObject *); - -/* -_Py_NoneStruct is an object of undefined type which can be used in contexts -where NULL (nil) is not suitable (since NULL often means 'error'). - -Don't forget to apply Py_INCREF() when returning this value!!! -*/ -PyAPI_DATA(PyObject) _Py_NoneStruct; /* Don't use this directly */ -#define Py_None (&_Py_NoneStruct) - -/* Macro for returning Py_None from a function */ -#define Py_RETURN_NONE return Py_INCREF(Py_None), Py_None - -/* -Py_NotImplemented is a singleton used to signal that an operation is -not implemented for a given type combination. -*/ -PyAPI_DATA(PyObject) _Py_NotImplementedStruct; /* Don't use this directly */ -#define Py_NotImplemented (&_Py_NotImplementedStruct) - -/* Macro for returning Py_NotImplemented from a function */ -#define Py_RETURN_NOTIMPLEMENTED \ - return Py_INCREF(Py_NotImplemented), Py_NotImplemented - -/* Rich comparison opcodes */ -#define Py_LT 0 -#define Py_LE 1 -#define Py_EQ 2 -#define Py_NE 3 -#define Py_GT 4 -#define Py_GE 5 - -/* - * Macro for implementing rich comparisons - * - * Needs to be a macro because any C-comparable type can be used. - */ -#define Py_RETURN_RICHCOMPARE(val1, val2, op) \ - do { \ - switch (op) { \ - case Py_EQ: if ((val1) == (val2)) Py_RETURN_TRUE; Py_RETURN_FALSE; \ - case Py_NE: if ((val1) != (val2)) Py_RETURN_TRUE; Py_RETURN_FALSE; \ - case Py_LT: if ((val1) < (val2)) Py_RETURN_TRUE; Py_RETURN_FALSE; \ - case Py_GT: if ((val1) > (val2)) Py_RETURN_TRUE; Py_RETURN_FALSE; \ - case Py_LE: if ((val1) <= (val2)) Py_RETURN_TRUE; Py_RETURN_FALSE; \ - case Py_GE: if ((val1) >= (val2)) Py_RETURN_TRUE; Py_RETURN_FALSE; \ - default: \ - Py_UNREACHABLE(); \ - } \ - } while (0) - - -/* -More conventions -================ - -Argument Checking ------------------ - -Functions that take objects as arguments normally don't check for nil -arguments, but they do check the type of the argument, and return an -error if the function doesn't apply to the type. - -Failure Modes -------------- - -Functions may fail for a variety of reasons, including running out of -memory. This is communicated to the caller in two ways: an error string -is set (see errors.h), and the function result differs: functions that -normally return a pointer return NULL for failure, functions returning -an integer return -1 (which could be a legal return value too!), and -other functions return 0 for success and -1 for failure. -Callers should always check for errors before using the result. If -an error was set, the caller must either explicitly clear it, or pass -the error on to its caller. - -Reference Counts ----------------- - -It takes a while to get used to the proper usage of reference counts. - -Functions that create an object set the reference count to 1; such new -objects must be stored somewhere or destroyed again with Py_DECREF(). -Some functions that 'store' objects, such as PyTuple_SetItem() and -PyList_SetItem(), -don't increment the reference count of the object, since the most -frequent use is to store a fresh object. Functions that 'retrieve' -objects, such as PyTuple_GetItem() and PyDict_GetItemString(), also -don't increment -the reference count, since most frequently the object is only looked at -quickly. Thus, to retrieve an object and store it again, the caller -must call Py_INCREF() explicitly. - -NOTE: functions that 'consume' a reference count, like -PyList_SetItem(), consume the reference even if the object wasn't -successfully stored, to simplify error handling. - -It seems attractive to make other functions that take an object as -argument consume a reference count; however, this may quickly get -confusing (even the current practice is already confusing). Consider -it carefully, it may save lots of calls to Py_INCREF() and Py_DECREF() at -times. -*/ - -#ifndef Py_LIMITED_API -# define Py_CPYTHON_OBJECT_H -# include "cpython/object.h" -# undef Py_CPYTHON_OBJECT_H -#endif - - -static inline int -PyType_HasFeature(PyTypeObject *type, unsigned long feature) -{ - unsigned long flags; -#ifdef Py_LIMITED_API - // PyTypeObject is opaque in the limited C API - flags = PyType_GetFlags(type); -#else - flags = type->tp_flags; -#endif - return ((flags & feature) != 0); -} - -#define PyType_FastSubclass(type, flag) PyType_HasFeature(type, flag) - -static inline int _PyType_Check(PyObject *op) { - return PyType_FastSubclass(Py_TYPE(op), Py_TPFLAGS_TYPE_SUBCLASS); -} -#define PyType_Check(op) _PyType_Check(_PyObject_CAST(op)) - -static inline int _PyType_CheckExact(PyObject *op) { - return Py_IS_TYPE(op, &PyType_Type); -} -#define PyType_CheckExact(op) _PyType_CheckExact(_PyObject_CAST(op)) - -#ifdef __cplusplus -} -#endif -#endif /* !Py_OBJECT_H */ diff --git a/scripts/build-windows/py39-libs/include/objimpl.h b/scripts/build-windows/py39-libs/include/objimpl.h deleted file mode 100644 index 3045213e5..000000000 --- a/scripts/build-windows/py39-libs/include/objimpl.h +++ /dev/null @@ -1,215 +0,0 @@ -/* The PyObject_ memory family: high-level object memory interfaces. - See pymem.h for the low-level PyMem_ family. -*/ - -#ifndef Py_OBJIMPL_H -#define Py_OBJIMPL_H - -#include "pymem.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/* BEWARE: - - Each interface exports both functions and macros. Extension modules should - use the functions, to ensure binary compatibility across Python versions. - Because the Python implementation is free to change internal details, and - the macros may (or may not) expose details for speed, if you do use the - macros you must recompile your extensions with each Python release. - - Never mix calls to PyObject_ memory functions with calls to the platform - malloc/realloc/ calloc/free, or with calls to PyMem_. -*/ - -/* -Functions and macros for modules that implement new object types. - - - PyObject_New(type, typeobj) allocates memory for a new object of the given - type, and initializes part of it. 'type' must be the C structure type used - to represent the object, and 'typeobj' the address of the corresponding - type object. Reference count and type pointer are filled in; the rest of - the bytes of the object are *undefined*! The resulting expression type is - 'type *'. The size of the object is determined by the tp_basicsize field - of the type object. - - - PyObject_NewVar(type, typeobj, n) is similar but allocates a variable-size - object with room for n items. In addition to the refcount and type pointer - fields, this also fills in the ob_size field. - - - PyObject_Del(op) releases the memory allocated for an object. It does not - run a destructor -- it only frees the memory. PyObject_Free is identical. - - - PyObject_Init(op, typeobj) and PyObject_InitVar(op, typeobj, n) don't - allocate memory. Instead of a 'type' parameter, they take a pointer to a - new object (allocated by an arbitrary allocator), and initialize its object - header fields. - -Note that objects created with PyObject_{New, NewVar} are allocated using the -specialized Python allocator (implemented in obmalloc.c), if WITH_PYMALLOC is -enabled. In addition, a special debugging allocator is used if PYMALLOC_DEBUG -is also #defined. - -In case a specific form of memory management is needed (for example, if you -must use the platform malloc heap(s), or shared memory, or C++ local storage or -operator new), you must first allocate the object with your custom allocator, -then pass its pointer to PyObject_{Init, InitVar} for filling in its Python- -specific fields: reference count, type pointer, possibly others. You should -be aware that Python has no control over these objects because they don't -cooperate with the Python memory manager. Such objects may not be eligible -for automatic garbage collection and you have to make sure that they are -released accordingly whenever their destructor gets called (cf. the specific -form of memory management you're using). - -Unless you have specific memory management requirements, use -PyObject_{New, NewVar, Del}. -*/ - -/* - * Raw object memory interface - * =========================== - */ - -/* Functions to call the same malloc/realloc/free as used by Python's - object allocator. If WITH_PYMALLOC is enabled, these may differ from - the platform malloc/realloc/free. The Python object allocator is - designed for fast, cache-conscious allocation of many "small" objects, - and with low hidden memory overhead. - - PyObject_Malloc(0) returns a unique non-NULL pointer if possible. - - PyObject_Realloc(NULL, n) acts like PyObject_Malloc(n). - PyObject_Realloc(p != NULL, 0) does not return NULL, or free the memory - at p. - - Returned pointers must be checked for NULL explicitly; no action is - performed on failure other than to return NULL (no warning it printed, no - exception is set, etc). - - For allocating objects, use PyObject_{New, NewVar} instead whenever - possible. The PyObject_{Malloc, Realloc, Free} family is exposed - so that you can exploit Python's small-block allocator for non-object - uses. If you must use these routines to allocate object memory, make sure - the object gets initialized via PyObject_{Init, InitVar} after obtaining - the raw memory. -*/ -PyAPI_FUNC(void *) PyObject_Malloc(size_t size); -#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03050000 -PyAPI_FUNC(void *) PyObject_Calloc(size_t nelem, size_t elsize); -#endif -PyAPI_FUNC(void *) PyObject_Realloc(void *ptr, size_t new_size); -PyAPI_FUNC(void) PyObject_Free(void *ptr); - - -/* Macros */ -#define PyObject_MALLOC PyObject_Malloc -#define PyObject_REALLOC PyObject_Realloc -#define PyObject_FREE PyObject_Free -#define PyObject_Del PyObject_Free -#define PyObject_DEL PyObject_Free - - -/* - * Generic object allocator interface - * ================================== - */ - -/* Functions */ -PyAPI_FUNC(PyObject *) PyObject_Init(PyObject *, PyTypeObject *); -PyAPI_FUNC(PyVarObject *) PyObject_InitVar(PyVarObject *, - PyTypeObject *, Py_ssize_t); -PyAPI_FUNC(PyObject *) _PyObject_New(PyTypeObject *); -PyAPI_FUNC(PyVarObject *) _PyObject_NewVar(PyTypeObject *, Py_ssize_t); - -#define PyObject_New(type, typeobj) ((type *)_PyObject_New(typeobj)) - -// Alias to PyObject_New(). In Python 3.8, PyObject_NEW() called directly -// PyObject_MALLOC() with _PyObject_SIZE(). -#define PyObject_NEW(type, typeobj) PyObject_New(type, typeobj) - -#define PyObject_NewVar(type, typeobj, n) \ - ( (type *) _PyObject_NewVar((typeobj), (n)) ) - -// Alias to PyObject_New(). In Python 3.8, PyObject_NEW() called directly -// PyObject_MALLOC() with _PyObject_VAR_SIZE(). -#define PyObject_NEW_VAR(type, typeobj, n) PyObject_NewVar(type, typeobj, n) - - -#ifdef Py_LIMITED_API -/* Define PyObject_INIT() and PyObject_INIT_VAR() as aliases to PyObject_Init() - and PyObject_InitVar() in the limited C API for compatibility with the - CPython C API. */ -# define PyObject_INIT(op, typeobj) \ - PyObject_Init(_PyObject_CAST(op), (typeobj)) -# define PyObject_INIT_VAR(op, typeobj, size) \ - PyObject_InitVar(_PyVarObject_CAST(op), (typeobj), (size)) -#else -/* PyObject_INIT() and PyObject_INIT_VAR() are defined in cpython/objimpl.h */ -#endif - - -/* - * Garbage Collection Support - * ========================== - */ - -/* C equivalent of gc.collect() which ignores the state of gc.enabled. */ -PyAPI_FUNC(Py_ssize_t) PyGC_Collect(void); - -/* Test if a type has a GC head */ -#define PyType_IS_GC(t) PyType_HasFeature((t), Py_TPFLAGS_HAVE_GC) - -PyAPI_FUNC(PyVarObject *) _PyObject_GC_Resize(PyVarObject *, Py_ssize_t); -#define PyObject_GC_Resize(type, op, n) \ - ( (type *) _PyObject_GC_Resize(_PyVarObject_CAST(op), (n)) ) - - - -PyAPI_FUNC(PyObject *) _PyObject_GC_New(PyTypeObject *); -PyAPI_FUNC(PyVarObject *) _PyObject_GC_NewVar(PyTypeObject *, Py_ssize_t); - -/* Tell the GC to track this object. - * - * See also private _PyObject_GC_TRACK() macro. */ -PyAPI_FUNC(void) PyObject_GC_Track(void *); - -/* Tell the GC to stop tracking this object. - * - * See also private _PyObject_GC_UNTRACK() macro. */ -PyAPI_FUNC(void) PyObject_GC_UnTrack(void *); - -PyAPI_FUNC(void) PyObject_GC_Del(void *); - -#define PyObject_GC_New(type, typeobj) \ - ( (type *) _PyObject_GC_New(typeobj) ) -#define PyObject_GC_NewVar(type, typeobj, n) \ - ( (type *) _PyObject_GC_NewVar((typeobj), (n)) ) - -PyAPI_FUNC(int) PyObject_GC_IsTracked(PyObject *); -PyAPI_FUNC(int) PyObject_GC_IsFinalized(PyObject *); - -/* Utility macro to help write tp_traverse functions. - * To use this macro, the tp_traverse function must name its arguments - * "visit" and "arg". This is intended to keep tp_traverse functions - * looking as much alike as possible. - */ -#define Py_VISIT(op) \ - do { \ - if (op) { \ - int vret = visit(_PyObject_CAST(op), arg); \ - if (vret) \ - return vret; \ - } \ - } while (0) - -#ifndef Py_LIMITED_API -# define Py_CPYTHON_OBJIMPL_H -# include "cpython/objimpl.h" -# undef Py_CPYTHON_OBJIMPL_H -#endif - -#ifdef __cplusplus -} -#endif -#endif /* !Py_OBJIMPL_H */ diff --git a/scripts/build-windows/py39-libs/include/odictobject.h b/scripts/build-windows/py39-libs/include/odictobject.h deleted file mode 100644 index 881e7ebcb..000000000 --- a/scripts/build-windows/py39-libs/include/odictobject.h +++ /dev/null @@ -1,43 +0,0 @@ -#ifndef Py_ODICTOBJECT_H -#define Py_ODICTOBJECT_H -#ifdef __cplusplus -extern "C" { -#endif - - -/* OrderedDict */ -/* This API is optional and mostly redundant. */ - -#ifndef Py_LIMITED_API - -typedef struct _odictobject PyODictObject; - -PyAPI_DATA(PyTypeObject) PyODict_Type; -PyAPI_DATA(PyTypeObject) PyODictIter_Type; -PyAPI_DATA(PyTypeObject) PyODictKeys_Type; -PyAPI_DATA(PyTypeObject) PyODictItems_Type; -PyAPI_DATA(PyTypeObject) PyODictValues_Type; - -#define PyODict_Check(op) PyObject_TypeCheck(op, &PyODict_Type) -#define PyODict_CheckExact(op) Py_IS_TYPE(op, &PyODict_Type) -#define PyODict_SIZE(op) PyDict_GET_SIZE((op)) - -PyAPI_FUNC(PyObject *) PyODict_New(void); -PyAPI_FUNC(int) PyODict_SetItem(PyObject *od, PyObject *key, PyObject *item); -PyAPI_FUNC(int) PyODict_DelItem(PyObject *od, PyObject *key); - -/* wrappers around PyDict* functions */ -#define PyODict_GetItem(od, key) PyDict_GetItem(_PyObject_CAST(od), key) -#define PyODict_GetItemWithError(od, key) \ - PyDict_GetItemWithError(_PyObject_CAST(od), key) -#define PyODict_Contains(od, key) PyDict_Contains(_PyObject_CAST(od), key) -#define PyODict_Size(od) PyDict_Size(_PyObject_CAST(od)) -#define PyODict_GetItemString(od, key) \ - PyDict_GetItemString(_PyObject_CAST(od), key) - -#endif - -#ifdef __cplusplus -} -#endif -#endif /* !Py_ODICTOBJECT_H */ diff --git a/scripts/build-windows/py39-libs/include/opcode.h b/scripts/build-windows/py39-libs/include/opcode.h deleted file mode 100644 index f86c2f938..000000000 --- a/scripts/build-windows/py39-libs/include/opcode.h +++ /dev/null @@ -1,142 +0,0 @@ -/* Auto-generated by Tools/scripts/generate_opcode_h.py from Lib/opcode.py */ -#ifndef Py_OPCODE_H -#define Py_OPCODE_H -#ifdef __cplusplus -extern "C" { -#endif - - - /* Instruction opcodes for compiled code */ -#define POP_TOP 1 -#define ROT_TWO 2 -#define ROT_THREE 3 -#define DUP_TOP 4 -#define DUP_TOP_TWO 5 -#define ROT_FOUR 6 -#define NOP 9 -#define UNARY_POSITIVE 10 -#define UNARY_NEGATIVE 11 -#define UNARY_NOT 12 -#define UNARY_INVERT 15 -#define BINARY_MATRIX_MULTIPLY 16 -#define INPLACE_MATRIX_MULTIPLY 17 -#define BINARY_POWER 19 -#define BINARY_MULTIPLY 20 -#define BINARY_MODULO 22 -#define BINARY_ADD 23 -#define BINARY_SUBTRACT 24 -#define BINARY_SUBSCR 25 -#define BINARY_FLOOR_DIVIDE 26 -#define BINARY_TRUE_DIVIDE 27 -#define INPLACE_FLOOR_DIVIDE 28 -#define INPLACE_TRUE_DIVIDE 29 -#define RERAISE 48 -#define WITH_EXCEPT_START 49 -#define GET_AITER 50 -#define GET_ANEXT 51 -#define BEFORE_ASYNC_WITH 52 -#define END_ASYNC_FOR 54 -#define INPLACE_ADD 55 -#define INPLACE_SUBTRACT 56 -#define INPLACE_MULTIPLY 57 -#define INPLACE_MODULO 59 -#define STORE_SUBSCR 60 -#define DELETE_SUBSCR 61 -#define BINARY_LSHIFT 62 -#define BINARY_RSHIFT 63 -#define BINARY_AND 64 -#define BINARY_XOR 65 -#define BINARY_OR 66 -#define INPLACE_POWER 67 -#define GET_ITER 68 -#define GET_YIELD_FROM_ITER 69 -#define PRINT_EXPR 70 -#define LOAD_BUILD_CLASS 71 -#define YIELD_FROM 72 -#define GET_AWAITABLE 73 -#define LOAD_ASSERTION_ERROR 74 -#define INPLACE_LSHIFT 75 -#define INPLACE_RSHIFT 76 -#define INPLACE_AND 77 -#define INPLACE_XOR 78 -#define INPLACE_OR 79 -#define LIST_TO_TUPLE 82 -#define RETURN_VALUE 83 -#define IMPORT_STAR 84 -#define SETUP_ANNOTATIONS 85 -#define YIELD_VALUE 86 -#define POP_BLOCK 87 -#define POP_EXCEPT 89 -#define HAVE_ARGUMENT 90 -#define STORE_NAME 90 -#define DELETE_NAME 91 -#define UNPACK_SEQUENCE 92 -#define FOR_ITER 93 -#define UNPACK_EX 94 -#define STORE_ATTR 95 -#define DELETE_ATTR 96 -#define STORE_GLOBAL 97 -#define DELETE_GLOBAL 98 -#define LOAD_CONST 100 -#define LOAD_NAME 101 -#define BUILD_TUPLE 102 -#define BUILD_LIST 103 -#define BUILD_SET 104 -#define BUILD_MAP 105 -#define LOAD_ATTR 106 -#define COMPARE_OP 107 -#define IMPORT_NAME 108 -#define IMPORT_FROM 109 -#define JUMP_FORWARD 110 -#define JUMP_IF_FALSE_OR_POP 111 -#define JUMP_IF_TRUE_OR_POP 112 -#define JUMP_ABSOLUTE 113 -#define POP_JUMP_IF_FALSE 114 -#define POP_JUMP_IF_TRUE 115 -#define LOAD_GLOBAL 116 -#define IS_OP 117 -#define CONTAINS_OP 118 -#define JUMP_IF_NOT_EXC_MATCH 121 -#define SETUP_FINALLY 122 -#define LOAD_FAST 124 -#define STORE_FAST 125 -#define DELETE_FAST 126 -#define RAISE_VARARGS 130 -#define CALL_FUNCTION 131 -#define MAKE_FUNCTION 132 -#define BUILD_SLICE 133 -#define LOAD_CLOSURE 135 -#define LOAD_DEREF 136 -#define STORE_DEREF 137 -#define DELETE_DEREF 138 -#define CALL_FUNCTION_KW 141 -#define CALL_FUNCTION_EX 142 -#define SETUP_WITH 143 -#define EXTENDED_ARG 144 -#define LIST_APPEND 145 -#define SET_ADD 146 -#define MAP_ADD 147 -#define LOAD_CLASSDEREF 148 -#define SETUP_ASYNC_WITH 154 -#define FORMAT_VALUE 155 -#define BUILD_CONST_KEY_MAP 156 -#define BUILD_STRING 157 -#define LOAD_METHOD 160 -#define CALL_METHOD 161 -#define LIST_EXTEND 162 -#define SET_UPDATE 163 -#define DICT_MERGE 164 -#define DICT_UPDATE 165 - -/* EXCEPT_HANDLER is a special, implicit block type which is created when - entering an except handler. It is not an opcode but we define it here - as we want it to be available to both frameobject.c and ceval.c, while - remaining private.*/ -#define EXCEPT_HANDLER 257 - -#define HAS_ARG(op) ((op) >= HAVE_ARGUMENT) - -#ifdef __cplusplus -} -#endif -#endif /* !Py_OPCODE_H */ diff --git a/scripts/build-windows/py39-libs/include/osdefs.h b/scripts/build-windows/py39-libs/include/osdefs.h deleted file mode 100644 index 4ff50cbb2..000000000 --- a/scripts/build-windows/py39-libs/include/osdefs.h +++ /dev/null @@ -1,51 +0,0 @@ -#ifndef Py_OSDEFS_H -#define Py_OSDEFS_H -#ifdef __cplusplus -extern "C" { -#endif - - -/* Operating system dependencies */ - -#ifdef MS_WINDOWS -#define SEP L'\\' -#define ALTSEP L'/' -#define MAXPATHLEN 256 -#define DELIM L';' -#endif - -#ifdef __VXWORKS__ -#define DELIM L';' -#endif - -/* Filename separator */ -#ifndef SEP -#define SEP L'/' -#endif - -/* Max pathname length */ -#ifdef __hpux -#include -#include -#ifndef PATH_MAX -#define PATH_MAX MAXPATHLEN -#endif -#endif - -#ifndef MAXPATHLEN -#if defined(PATH_MAX) && PATH_MAX > 1024 -#define MAXPATHLEN PATH_MAX -#else -#define MAXPATHLEN 1024 -#endif -#endif - -/* Search path entry delimiter */ -#ifndef DELIM -#define DELIM L':' -#endif - -#ifdef __cplusplus -} -#endif -#endif /* !Py_OSDEFS_H */ diff --git a/scripts/build-windows/py39-libs/include/osmodule.h b/scripts/build-windows/py39-libs/include/osmodule.h deleted file mode 100644 index af5085029..000000000 --- a/scripts/build-windows/py39-libs/include/osmodule.h +++ /dev/null @@ -1,17 +0,0 @@ - -/* os module interface */ - -#ifndef Py_OSMODULE_H -#define Py_OSMODULE_H -#ifdef __cplusplus -extern "C" { -#endif - -#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03060000 -PyAPI_FUNC(PyObject *) PyOS_FSPath(PyObject *path); -#endif - -#ifdef __cplusplus -} -#endif -#endif /* !Py_OSMODULE_H */ diff --git a/scripts/build-windows/py39-libs/include/parsetok.h b/scripts/build-windows/py39-libs/include/parsetok.h deleted file mode 100644 index d7778bf39..000000000 --- a/scripts/build-windows/py39-libs/include/parsetok.h +++ /dev/null @@ -1,110 +0,0 @@ -/* Parser-tokenizer link interface */ - -#ifndef Py_LIMITED_API -#ifndef Py_PARSETOK_H -#define Py_PARSETOK_H -#ifdef __cplusplus -extern "C" { -#endif - -#include "grammar.h" /* grammar */ -#include "node.h" /* node */ - -typedef struct { - int error; - PyObject *filename; - int lineno; - int offset; - char *text; /* UTF-8-encoded string */ - int token; - int expected; -} perrdetail; - -#if 0 -#define PyPARSE_YIELD_IS_KEYWORD 0x0001 -#endif - -#define PyPARSE_DONT_IMPLY_DEDENT 0x0002 - -#if 0 -#define PyPARSE_WITH_IS_KEYWORD 0x0003 -#define PyPARSE_PRINT_IS_FUNCTION 0x0004 -#define PyPARSE_UNICODE_LITERALS 0x0008 -#endif - -#define PyPARSE_IGNORE_COOKIE 0x0010 -#define PyPARSE_BARRY_AS_BDFL 0x0020 -#define PyPARSE_TYPE_COMMENTS 0x0040 -#define PyPARSE_ASYNC_HACKS 0x0080 - -PyAPI_FUNC(node *) PyParser_ParseString(const char *, grammar *, int, - perrdetail *); -PyAPI_FUNC(node *) PyParser_ParseFile (FILE *, const char *, grammar *, int, - const char *, const char *, - perrdetail *); - -PyAPI_FUNC(node *) PyParser_ParseStringFlags(const char *, grammar *, int, - perrdetail *, int); -PyAPI_FUNC(node *) PyParser_ParseFileFlags( - FILE *fp, - const char *filename, /* decoded from the filesystem encoding */ - const char *enc, - grammar *g, - int start, - const char *ps1, - const char *ps2, - perrdetail *err_ret, - int flags); -PyAPI_FUNC(node *) PyParser_ParseFileFlagsEx( - FILE *fp, - const char *filename, /* decoded from the filesystem encoding */ - const char *enc, - grammar *g, - int start, - const char *ps1, - const char *ps2, - perrdetail *err_ret, - int *flags); -PyAPI_FUNC(node *) PyParser_ParseFileObject( - FILE *fp, - PyObject *filename, - const char *enc, - grammar *g, - int start, - const char *ps1, - const char *ps2, - perrdetail *err_ret, - int *flags); - -PyAPI_FUNC(node *) PyParser_ParseStringFlagsFilename( - const char *s, - const char *filename, /* decoded from the filesystem encoding */ - grammar *g, - int start, - perrdetail *err_ret, - int flags); -PyAPI_FUNC(node *) PyParser_ParseStringFlagsFilenameEx( - const char *s, - const char *filename, /* decoded from the filesystem encoding */ - grammar *g, - int start, - perrdetail *err_ret, - int *flags); -PyAPI_FUNC(node *) PyParser_ParseStringObject( - const char *s, - PyObject *filename, - grammar *g, - int start, - perrdetail *err_ret, - int *flags); - -/* Note that the following functions are defined in pythonrun.c, - not in parsetok.c */ -PyAPI_FUNC(void) PyParser_SetError(perrdetail *); -PyAPI_FUNC(void) PyParser_ClearError(perrdetail *); - -#ifdef __cplusplus -} -#endif -#endif /* !Py_PARSETOK_H */ -#endif /* !Py_LIMITED_API */ diff --git a/scripts/build-windows/py39-libs/include/patchlevel.h b/scripts/build-windows/py39-libs/include/patchlevel.h deleted file mode 100644 index 7e0b99db1..000000000 --- a/scripts/build-windows/py39-libs/include/patchlevel.h +++ /dev/null @@ -1,35 +0,0 @@ - -/* Python version identification scheme. - - When the major or minor version changes, the VERSION variable in - configure.ac must also be changed. - - There is also (independent) API version information in modsupport.h. -*/ - -/* Values for PY_RELEASE_LEVEL */ -#define PY_RELEASE_LEVEL_ALPHA 0xA -#define PY_RELEASE_LEVEL_BETA 0xB -#define PY_RELEASE_LEVEL_GAMMA 0xC /* For release candidates */ -#define PY_RELEASE_LEVEL_FINAL 0xF /* Serial should be 0 here */ - /* Higher for patch releases */ - -/* Version parsed out into numeric values */ -/*--start constants--*/ -#define PY_MAJOR_VERSION 3 -#define PY_MINOR_VERSION 9 -#define PY_MICRO_VERSION 6 -#define PY_RELEASE_LEVEL PY_RELEASE_LEVEL_FINAL -#define PY_RELEASE_SERIAL 0 - -/* Version as a string */ -#define PY_VERSION "3.9.6" -/*--end constants--*/ - -/* Version as a single 4-byte hex number, e.g. 0x010502B2 == 1.5.2b2. - Use this for numeric comparisons, e.g. #if PY_VERSION_HEX >= ... */ -#define PY_VERSION_HEX ((PY_MAJOR_VERSION << 24) | \ - (PY_MINOR_VERSION << 16) | \ - (PY_MICRO_VERSION << 8) | \ - (PY_RELEASE_LEVEL << 4) | \ - (PY_RELEASE_SERIAL << 0)) diff --git a/scripts/build-windows/py39-libs/include/picklebufobject.h b/scripts/build-windows/py39-libs/include/picklebufobject.h deleted file mode 100644 index 5d0b0cfaa..000000000 --- a/scripts/build-windows/py39-libs/include/picklebufobject.h +++ /dev/null @@ -1,31 +0,0 @@ -/* PickleBuffer object. This is built-in for ease of use from third-party - * C extensions. - */ - -#ifndef Py_PICKLEBUFOBJECT_H -#define Py_PICKLEBUFOBJECT_H -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef Py_LIMITED_API - -PyAPI_DATA(PyTypeObject) PyPickleBuffer_Type; - -#define PyPickleBuffer_Check(op) Py_IS_TYPE(op, &PyPickleBuffer_Type) - -/* Create a PickleBuffer redirecting to the given buffer-enabled object */ -PyAPI_FUNC(PyObject *) PyPickleBuffer_FromObject(PyObject *); -/* Get the PickleBuffer's underlying view to the original object - * (NULL if released) - */ -PyAPI_FUNC(const Py_buffer *) PyPickleBuffer_GetBuffer(PyObject *); -/* Release the PickleBuffer. Returns 0 on success, -1 on error. */ -PyAPI_FUNC(int) PyPickleBuffer_Release(PyObject *); - -#endif /* !Py_LIMITED_API */ - -#ifdef __cplusplus -} -#endif -#endif /* !Py_PICKLEBUFOBJECT_H */ diff --git a/scripts/build-windows/py39-libs/include/py_curses.h b/scripts/build-windows/py39-libs/include/py_curses.h deleted file mode 100644 index b65aaa7b8..000000000 --- a/scripts/build-windows/py39-libs/include/py_curses.h +++ /dev/null @@ -1,99 +0,0 @@ - -#ifndef Py_CURSES_H -#define Py_CURSES_H - -#ifdef __APPLE__ -/* -** On Mac OS X 10.2 [n]curses.h and stdlib.h use different guards -** against multiple definition of wchar_t. -*/ -#ifdef _BSD_WCHAR_T_DEFINED_ -#define _WCHAR_T -#endif -#endif /* __APPLE__ */ - -/* On FreeBSD, [n]curses.h and stdlib.h/wchar.h use different guards - against multiple definition of wchar_t and wint_t. */ -#if defined(__FreeBSD__) && defined(_XOPEN_SOURCE_EXTENDED) -# ifndef __wchar_t -# define __wchar_t -# endif -# ifndef __wint_t -# define __wint_t -# endif -#endif - -#if !defined(HAVE_CURSES_IS_PAD) && defined(WINDOW_HAS_FLAGS) -/* The following definition is necessary for ncurses 5.7; without it, - some of [n]curses.h set NCURSES_OPAQUE to 1, and then Python - can't get at the WINDOW flags field. */ -#define NCURSES_OPAQUE 0 -#endif - -#ifdef HAVE_NCURSES_H -#include -#else -#include -#endif - -#ifdef HAVE_NCURSES_H -/* configure was checking , but we will - use , which has some or all these features. */ -#if !defined(WINDOW_HAS_FLAGS) && !(NCURSES_OPAQUE+0) -#define WINDOW_HAS_FLAGS 1 -#endif -#if !defined(HAVE_CURSES_IS_PAD) && NCURSES_VERSION_PATCH+0 >= 20090906 -#define HAVE_CURSES_IS_PAD 1 -#endif -#ifndef MVWDELCH_IS_EXPRESSION -#define MVWDELCH_IS_EXPRESSION 1 -#endif -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -#define PyCurses_API_pointers 4 - -/* Type declarations */ - -typedef struct { - PyObject_HEAD - WINDOW *win; - char *encoding; -} PyCursesWindowObject; - -#define PyCursesWindow_Check(v) Py_IS_TYPE(v, &PyCursesWindow_Type) - -#define PyCurses_CAPSULE_NAME "_curses._C_API" - - -#ifdef CURSES_MODULE -/* This section is used when compiling _cursesmodule.c */ - -#else -/* This section is used in modules that use the _cursesmodule API */ - -static void **PyCurses_API; - -#define PyCursesWindow_Type (*(PyTypeObject *) PyCurses_API[0]) -#define PyCursesSetupTermCalled {if (! ((int (*)(void))PyCurses_API[1]) () ) return NULL;} -#define PyCursesInitialised {if (! ((int (*)(void))PyCurses_API[2]) () ) return NULL;} -#define PyCursesInitialisedColor {if (! ((int (*)(void))PyCurses_API[3]) () ) return NULL;} - -#define import_curses() \ - PyCurses_API = (void **)PyCapsule_Import(PyCurses_CAPSULE_NAME, 1); - -#endif - -/* general error messages */ -static const char catchall_ERR[] = "curses function returned ERR"; -static const char catchall_NULL[] = "curses function returned NULL"; - -#ifdef __cplusplus -} -#endif - -#endif /* !defined(Py_CURSES_H) */ - diff --git a/scripts/build-windows/py39-libs/include/pyarena.h b/scripts/build-windows/py39-libs/include/pyarena.h deleted file mode 100644 index 97791bec8..000000000 --- a/scripts/build-windows/py39-libs/include/pyarena.h +++ /dev/null @@ -1,64 +0,0 @@ -/* An arena-like memory interface for the compiler. - */ - -#ifndef Py_LIMITED_API -#ifndef Py_PYARENA_H -#define Py_PYARENA_H - -#ifdef __cplusplus -extern "C" { -#endif - - typedef struct _arena PyArena; - - /* PyArena_New() and PyArena_Free() create a new arena and free it, - respectively. Once an arena has been created, it can be used - to allocate memory via PyArena_Malloc(). Pointers to PyObject can - also be registered with the arena via PyArena_AddPyObject(), and the - arena will ensure that the PyObjects stay alive at least until - PyArena_Free() is called. When an arena is freed, all the memory it - allocated is freed, the arena releases internal references to registered - PyObject*, and none of its pointers are valid. - XXX (tim) What does "none of its pointers are valid" mean? Does it - XXX mean that pointers previously obtained via PyArena_Malloc() are - XXX no longer valid? (That's clearly true, but not sure that's what - XXX the text is trying to say.) - - PyArena_New() returns an arena pointer. On error, it - returns a negative number and sets an exception. - XXX (tim): Not true. On error, PyArena_New() actually returns NULL, - XXX and looks like it may or may not set an exception (e.g., if the - XXX internal PyList_New(0) returns NULL, PyArena_New() passes that on - XXX and an exception is set; OTOH, if the internal - XXX block_new(DEFAULT_BLOCK_SIZE) returns NULL, that's passed on but - XXX an exception is not set in that case). - */ - PyAPI_FUNC(PyArena *) PyArena_New(void); - PyAPI_FUNC(void) PyArena_Free(PyArena *); - - /* Mostly like malloc(), return the address of a block of memory spanning - * `size` bytes, or return NULL (without setting an exception) if enough - * new memory can't be obtained. Unlike malloc(0), PyArena_Malloc() with - * size=0 does not guarantee to return a unique pointer (the pointer - * returned may equal one or more other pointers obtained from - * PyArena_Malloc()). - * Note that pointers obtained via PyArena_Malloc() must never be passed to - * the system free() or realloc(), or to any of Python's similar memory- - * management functions. PyArena_Malloc()-obtained pointers remain valid - * until PyArena_Free(ar) is called, at which point all pointers obtained - * from the arena `ar` become invalid simultaneously. - */ - PyAPI_FUNC(void *) PyArena_Malloc(PyArena *, size_t size); - - /* This routine isn't a proper arena allocation routine. It takes - * a PyObject* and records it so that it can be DECREFed when the - * arena is freed. - */ - PyAPI_FUNC(int) PyArena_AddPyObject(PyArena *, PyObject *); - -#ifdef __cplusplus -} -#endif - -#endif /* !Py_PYARENA_H */ -#endif /* Py_LIMITED_API */ diff --git a/scripts/build-windows/py39-libs/include/pycapsule.h b/scripts/build-windows/py39-libs/include/pycapsule.h deleted file mode 100644 index 9387a1c76..000000000 --- a/scripts/build-windows/py39-libs/include/pycapsule.h +++ /dev/null @@ -1,59 +0,0 @@ - -/* Capsule objects let you wrap a C "void *" pointer in a Python - object. They're a way of passing data through the Python interpreter - without creating your own custom type. - - Capsules are used for communication between extension modules. - They provide a way for an extension module to export a C interface - to other extension modules, so that extension modules can use the - Python import mechanism to link to one another. - - For more information, please see "c-api/capsule.html" in the - documentation. -*/ - -#ifndef Py_CAPSULE_H -#define Py_CAPSULE_H -#ifdef __cplusplus -extern "C" { -#endif - -PyAPI_DATA(PyTypeObject) PyCapsule_Type; - -typedef void (*PyCapsule_Destructor)(PyObject *); - -#define PyCapsule_CheckExact(op) Py_IS_TYPE(op, &PyCapsule_Type) - - -PyAPI_FUNC(PyObject *) PyCapsule_New( - void *pointer, - const char *name, - PyCapsule_Destructor destructor); - -PyAPI_FUNC(void *) PyCapsule_GetPointer(PyObject *capsule, const char *name); - -PyAPI_FUNC(PyCapsule_Destructor) PyCapsule_GetDestructor(PyObject *capsule); - -PyAPI_FUNC(const char *) PyCapsule_GetName(PyObject *capsule); - -PyAPI_FUNC(void *) PyCapsule_GetContext(PyObject *capsule); - -PyAPI_FUNC(int) PyCapsule_IsValid(PyObject *capsule, const char *name); - -PyAPI_FUNC(int) PyCapsule_SetPointer(PyObject *capsule, void *pointer); - -PyAPI_FUNC(int) PyCapsule_SetDestructor(PyObject *capsule, PyCapsule_Destructor destructor); - -PyAPI_FUNC(int) PyCapsule_SetName(PyObject *capsule, const char *name); - -PyAPI_FUNC(int) PyCapsule_SetContext(PyObject *capsule, void *context); - -PyAPI_FUNC(void *) PyCapsule_Import( - const char *name, /* UTF-8 encoded string */ - int no_block); - - -#ifdef __cplusplus -} -#endif -#endif /* !Py_CAPSULE_H */ diff --git a/scripts/build-windows/py39-libs/include/pyconfig.h b/scripts/build-windows/py39-libs/include/pyconfig.h deleted file mode 100644 index 0d5ac77fc..000000000 --- a/scripts/build-windows/py39-libs/include/pyconfig.h +++ /dev/null @@ -1,687 +0,0 @@ -#ifndef Py_CONFIG_H -#define Py_CONFIG_H - -/* pyconfig.h. NOT Generated automatically by configure. - -This is a manually maintained version used for the Watcom, -Borland and Microsoft Visual C++ compilers. It is a -standard part of the Python distribution. - -WINDOWS DEFINES: -The code specific to Windows should be wrapped around one of -the following #defines - -MS_WIN64 - Code specific to the MS Win64 API -MS_WIN32 - Code specific to the MS Win32 (and Win64) API (obsolete, this covers all supported APIs) -MS_WINDOWS - Code specific to Windows, but all versions. -Py_ENABLE_SHARED - Code if the Python core is built as a DLL. - -Also note that neither "_M_IX86" or "_MSC_VER" should be used for -any purpose other than "Windows Intel x86 specific" and "Microsoft -compiler specific". Therefore, these should be very rare. - - -NOTE: The following symbols are deprecated: -NT, USE_DL_EXPORT, USE_DL_IMPORT, DL_EXPORT, DL_IMPORT -MS_CORE_DLL. - -WIN32 is still required for the locale module. - -*/ - -/* Deprecated USE_DL_EXPORT macro - please use Py_BUILD_CORE */ -#ifdef USE_DL_EXPORT -# define Py_BUILD_CORE -#endif /* USE_DL_EXPORT */ - -/* Visual Studio 2005 introduces deprecation warnings for - "insecure" and POSIX functions. The insecure functions should - be replaced by *_s versions (according to Microsoft); the - POSIX functions by _* versions (which, according to Microsoft, - would be ISO C conforming). Neither renaming is feasible, so - we just silence the warnings. */ - -#ifndef _CRT_SECURE_NO_DEPRECATE -#define _CRT_SECURE_NO_DEPRECATE 1 -#endif -#ifndef _CRT_NONSTDC_NO_DEPRECATE -#define _CRT_NONSTDC_NO_DEPRECATE 1 -#endif - -#define HAVE_IO_H -#define HAVE_SYS_UTIME_H -#define HAVE_TEMPNAM -#define HAVE_TMPFILE -#define HAVE_TMPNAM -#define HAVE_CLOCK -#define HAVE_STRERROR - -#include - -#define HAVE_HYPOT -#define HAVE_STRFTIME -#define DONT_HAVE_SIG_ALARM -#define DONT_HAVE_SIG_PAUSE -#define LONG_BIT 32 -#define WORD_BIT 32 - -#define MS_WIN32 /* only support win32 and greater. */ -#define MS_WINDOWS -#ifndef PYTHONPATH -# define PYTHONPATH L".\\DLLs;.\\lib" -#endif -#define NT_THREADS -#define WITH_THREAD -#ifndef NETSCAPE_PI -#define USE_SOCKET -#endif - - -/* Compiler specific defines */ - -/* ------------------------------------------------------------------------*/ -/* Microsoft C defines _MSC_VER */ -#ifdef _MSC_VER - -/* We want COMPILER to expand to a string containing _MSC_VER's *value*. - * This is horridly tricky, because the stringization operator only works - * on macro arguments, and doesn't evaluate macros passed *as* arguments. - * Attempts simpler than the following appear doomed to produce "_MSC_VER" - * literally in the string. - */ -#define _Py_PASTE_VERSION(SUFFIX) \ - ("[MSC v." _Py_STRINGIZE(_MSC_VER) " " SUFFIX "]") -/* e.g., this produces, after compile-time string catenation, - * ("[MSC v.1200 32 bit (Intel)]") - * - * _Py_STRINGIZE(_MSC_VER) expands to - * _Py_STRINGIZE1((_MSC_VER)) expands to - * _Py_STRINGIZE2(_MSC_VER) but as this call is the result of token-pasting - * it's scanned again for macros and so further expands to (under MSVC 6) - * _Py_STRINGIZE2(1200) which then expands to - * "1200" - */ -#define _Py_STRINGIZE(X) _Py_STRINGIZE1((X)) -#define _Py_STRINGIZE1(X) _Py_STRINGIZE2 ## X -#define _Py_STRINGIZE2(X) #X - -/* MSVC defines _WINxx to differentiate the windows platform types - - Note that for compatibility reasons _WIN32 is defined on Win32 - *and* on Win64. For the same reasons, in Python, MS_WIN32 is - defined on Win32 *and* Win64. Win32 only code must therefore be - guarded as follows: - #if defined(MS_WIN32) && !defined(MS_WIN64) -*/ -#ifdef _WIN64 -#define MS_WIN64 -#endif - -/* set the COMPILER */ -#ifdef MS_WIN64 -#if defined(_M_X64) || defined(_M_AMD64) -#if defined(__INTEL_COMPILER) -#define COMPILER ("[ICC v." _Py_STRINGIZE(__INTEL_COMPILER) " 64 bit (amd64) with MSC v." _Py_STRINGIZE(_MSC_VER) " CRT]") -#else -#define COMPILER _Py_PASTE_VERSION("64 bit (AMD64)") -#endif /* __INTEL_COMPILER */ -#define PYD_PLATFORM_TAG "win_amd64" -#elif defined(_M_ARM64) -#define COMPILER _Py_PASTE_VERSION("64 bit (ARM64)") -#define PYD_PLATFORM_TAG "win_arm64" -#else -#define COMPILER _Py_PASTE_VERSION("64 bit (Unknown)") -#endif -#endif /* MS_WIN64 */ - -/* set the version macros for the windows headers */ -/* Python 3.9+ requires Windows 8 or greater */ -#define Py_WINVER 0x0602 /* _WIN32_WINNT_WIN8 */ -#define Py_NTDDI NTDDI_WIN8 - -/* We only set these values when building Python - we don't want to force - these values on extensions, as that will affect the prototypes and - structures exposed in the Windows headers. Even when building Python, we - allow a single source file to override this - they may need access to - structures etc so it can optionally use new Windows features if it - determines at runtime they are available. -*/ -#if defined(Py_BUILD_CORE) || defined(Py_BUILD_CORE_BUILTIN) || defined(Py_BUILD_CORE_MODULE) -#ifndef NTDDI_VERSION -#define NTDDI_VERSION Py_NTDDI -#endif -#ifndef WINVER -#define WINVER Py_WINVER -#endif -#ifndef _WIN32_WINNT -#define _WIN32_WINNT Py_WINVER -#endif -#endif - -/* _W64 is not defined for VC6 or eVC4 */ -#ifndef _W64 -#define _W64 -#endif - -/* Define like size_t, omitting the "unsigned" */ -#ifdef MS_WIN64 -typedef __int64 ssize_t; -#else -typedef _W64 int ssize_t; -#endif -#define HAVE_SSIZE_T 1 - -#if defined(MS_WIN32) && !defined(MS_WIN64) -#if defined(_M_IX86) -#if defined(__INTEL_COMPILER) -#define COMPILER ("[ICC v." _Py_STRINGIZE(__INTEL_COMPILER) " 32 bit (Intel) with MSC v." _Py_STRINGIZE(_MSC_VER) " CRT]") -#else -#define COMPILER _Py_PASTE_VERSION("32 bit (Intel)") -#endif /* __INTEL_COMPILER */ -#define PYD_PLATFORM_TAG "win32" -#elif defined(_M_ARM) -#define COMPILER _Py_PASTE_VERSION("32 bit (ARM)") -#define PYD_PLATFORM_TAG "win_arm32" -#else -#define COMPILER _Py_PASTE_VERSION("32 bit (Unknown)") -#endif -#endif /* MS_WIN32 && !MS_WIN64 */ - -typedef int pid_t; - -#include -#define Py_IS_NAN _isnan -#define Py_IS_INFINITY(X) (!_finite(X) && !_isnan(X)) -#define Py_IS_FINITE(X) _finite(X) - -/* define some ANSI types that are not defined in earlier Win headers */ -#if _MSC_VER >= 1200 -/* This file only exists in VC 6.0 or higher */ -#include -#endif - -#endif /* _MSC_VER */ - -/* ------------------------------------------------------------------------*/ -/* egcs/gnu-win32 defines __GNUC__ and _WIN32 */ -#if defined(__GNUC__) && defined(_WIN32) -/* XXX These defines are likely incomplete, but should be easy to fix. - They should be complete enough to build extension modules. */ -/* Suggested by Rene Liebscher to avoid a GCC 2.91.* - bug that requires structure imports. More recent versions of the - compiler don't exhibit this bug. -*/ -#if (__GNUC__==2) && (__GNUC_MINOR__<=91) -#warning "Please use an up-to-date version of gcc! (>2.91 recommended)" -#endif - -#define COMPILER "[gcc]" -#define PY_LONG_LONG long long -#define PY_LLONG_MIN LLONG_MIN -#define PY_LLONG_MAX LLONG_MAX -#define PY_ULLONG_MAX ULLONG_MAX -#endif /* GNUC */ - -/* ------------------------------------------------------------------------*/ -/* lcc-win32 defines __LCC__ */ -#if defined(__LCC__) -/* XXX These defines are likely incomplete, but should be easy to fix. - They should be complete enough to build extension modules. */ - -#define COMPILER "[lcc-win32]" -typedef int pid_t; -/* __declspec() is supported here too - do nothing to get the defaults */ - -#endif /* LCC */ - -/* ------------------------------------------------------------------------*/ -/* End of compilers - finish up */ - -#ifndef NO_STDIO_H -# include -#endif - -/* 64 bit ints are usually spelt __int64 unless compiler has overridden */ -#ifndef PY_LONG_LONG -# define PY_LONG_LONG __int64 -# define PY_LLONG_MAX _I64_MAX -# define PY_LLONG_MIN _I64_MIN -# define PY_ULLONG_MAX _UI64_MAX -#endif - -/* For Windows the Python core is in a DLL by default. Test -Py_NO_ENABLE_SHARED to find out. Also support MS_NO_COREDLL for b/w compat */ -#if !defined(MS_NO_COREDLL) && !defined(Py_NO_ENABLE_SHARED) -# define Py_ENABLE_SHARED 1 /* standard symbol for shared library */ -# define MS_COREDLL /* deprecated old symbol */ -#endif /* !MS_NO_COREDLL && ... */ - -/* All windows compilers that use this header support __declspec */ -#define HAVE_DECLSPEC_DLL - -/* For an MSVC DLL, we can nominate the .lib files used by extensions */ -#ifdef MS_COREDLL -# if !defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_BUILTIN) - /* not building the core - must be an ext */ -# if defined(_MSC_VER) - /* So MSVC users need not specify the .lib - file in their Makefile (other compilers are - generally taken care of by distutils.) */ -# if defined(_DEBUG) -# pragma comment(lib,"python39_d.lib") -# elif defined(Py_LIMITED_API) -# pragma comment(lib,"python3.lib") -# else -# pragma comment(lib,"python39.lib") -# endif /* _DEBUG */ -# endif /* _MSC_VER */ -# endif /* Py_BUILD_CORE */ -#endif /* MS_COREDLL */ - -#if defined(MS_WIN64) -/* maintain "win32" sys.platform for backward compatibility of Python code, - the Win64 API should be close enough to the Win32 API to make this - preferable */ -# define PLATFORM "win32" -# define SIZEOF_VOID_P 8 -# define SIZEOF_TIME_T 8 -# define SIZEOF_OFF_T 4 -# define SIZEOF_FPOS_T 8 -# define SIZEOF_HKEY 8 -# define SIZEOF_SIZE_T 8 -/* configure.ac defines HAVE_LARGEFILE_SUPPORT iff - sizeof(off_t) > sizeof(long), and sizeof(long long) >= sizeof(off_t). - On Win64 the second condition is not true, but if fpos_t replaces off_t - then this is true. The uses of HAVE_LARGEFILE_SUPPORT imply that Win64 - should define this. */ -# define HAVE_LARGEFILE_SUPPORT -#elif defined(MS_WIN32) -# define PLATFORM "win32" -# define HAVE_LARGEFILE_SUPPORT -# define SIZEOF_VOID_P 4 -# define SIZEOF_OFF_T 4 -# define SIZEOF_FPOS_T 8 -# define SIZEOF_HKEY 4 -# define SIZEOF_SIZE_T 4 - /* MS VS2005 changes time_t to a 64-bit type on all platforms */ -# if defined(_MSC_VER) && _MSC_VER >= 1400 -# define SIZEOF_TIME_T 8 -# else -# define SIZEOF_TIME_T 4 -# endif -#endif - -#ifdef _DEBUG -# define Py_DEBUG -#endif - - -#ifdef MS_WIN32 - -#define SIZEOF_SHORT 2 -#define SIZEOF_INT 4 -#define SIZEOF_LONG 4 -#define SIZEOF_LONG_LONG 8 -#define SIZEOF_DOUBLE 8 -#define SIZEOF_FLOAT 4 - -/* VC 7.1 has them and VC 6.0 does not. VC 6.0 has a version number of 1200. - Microsoft eMbedded Visual C++ 4.0 has a version number of 1201 and doesn't - define these. - If some compiler does not provide them, modify the #if appropriately. */ -#if defined(_MSC_VER) -#if _MSC_VER > 1300 -#define HAVE_UINTPTR_T 1 -#define HAVE_INTPTR_T 1 -#else -/* VC6, VS 2002 and eVC4 don't support the C99 LL suffix for 64-bit integer literals */ -#define Py_LL(x) x##I64 -#endif /* _MSC_VER > 1300 */ -#endif /* _MSC_VER */ - -#endif - -/* define signed and unsigned exact-width 32-bit and 64-bit types, used in the - implementation of Python integers. */ -#define PY_UINT32_T uint32_t -#define PY_UINT64_T uint64_t -#define PY_INT32_T int32_t -#define PY_INT64_T int64_t - -/* Fairly standard from here! */ - -/* Define to 1 if you have the `copysign' function. */ -#define HAVE_COPYSIGN 1 - -/* Define to 1 if you have the `round' function. */ -#if _MSC_VER >= 1800 -#define HAVE_ROUND 1 -#endif - -/* Define to 1 if you have the `isinf' macro. */ -#define HAVE_DECL_ISINF 1 - -/* Define to 1 if you have the `isnan' function. */ -#define HAVE_DECL_ISNAN 1 - -/* Define if on AIX 3. - System headers sometimes define this. - We just want to avoid a redefinition error message. */ -#ifndef _ALL_SOURCE -/* #undef _ALL_SOURCE */ -#endif - -/* Define to empty if the keyword does not work. */ -/* #define const */ - -/* Define to 1 if you have the header file. */ -#define HAVE_CONIO_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_DIRECT_H 1 - -/* Define to 1 if you have the declaration of `tzname', and to 0 if you don't. - */ -#define HAVE_DECL_TZNAME 1 - -/* Define if you have dirent.h. */ -/* #define DIRENT 1 */ - -/* Define to the type of elements in the array set by `getgroups'. - Usually this is either `int' or `gid_t'. */ -/* #undef GETGROUPS_T */ - -/* Define to `int' if doesn't define. */ -/* #undef gid_t */ - -/* Define if your struct tm has tm_zone. */ -/* #undef HAVE_TM_ZONE */ - -/* Define if you don't have tm_zone but do have the external array - tzname. */ -#define HAVE_TZNAME - -/* Define to `int' if doesn't define. */ -/* #undef mode_t */ - -/* Define if you don't have dirent.h, but have ndir.h. */ -/* #undef NDIR */ - -/* Define to `long' if doesn't define. */ -/* #undef off_t */ - -/* Define to `int' if doesn't define. */ -/* #undef pid_t */ - -/* Define if the system does not provide POSIX.1 features except - with this defined. */ -/* #undef _POSIX_1_SOURCE */ - -/* Define if you need to in order for stat and other things to work. */ -/* #undef _POSIX_SOURCE */ - -/* Define as the return type of signal handlers (int or void). */ -#define RETSIGTYPE void - -/* Define to `unsigned' if doesn't define. */ -/* #undef size_t */ - -/* Define if you have the ANSI C header files. */ -#define STDC_HEADERS 1 - -/* Define if you don't have dirent.h, but have sys/dir.h. */ -/* #undef SYSDIR */ - -/* Define if you don't have dirent.h, but have sys/ndir.h. */ -/* #undef SYSNDIR */ - -/* Define if you can safely include both and . */ -/* #undef TIME_WITH_SYS_TIME */ - -/* Define if your declares struct tm. */ -/* #define TM_IN_SYS_TIME 1 */ - -/* Define to `int' if doesn't define. */ -/* #undef uid_t */ - -/* Define if the closedir function returns void instead of int. */ -/* #undef VOID_CLOSEDIR */ - -/* Define if getpgrp() must be called as getpgrp(0) - and (consequently) setpgrp() as setpgrp(0, 0). */ -/* #undef GETPGRP_HAVE_ARGS */ - -/* Define this if your time.h defines altzone */ -/* #define HAVE_ALTZONE */ - -/* Define if you have the putenv function. */ -#define HAVE_PUTENV - -/* Define if your compiler supports function prototypes */ -#define HAVE_PROTOTYPES - -/* Define if you can safely include both and - (which you can't on SCO ODT 3.0). */ -/* #undef SYS_SELECT_WITH_SYS_TIME */ - -/* Define if you want build the _decimal module using a coroutine-local rather - than a thread-local context */ -#define WITH_DECIMAL_CONTEXTVAR 1 - -/* Define if you want documentation strings in extension modules */ -#define WITH_DOC_STRINGS 1 - -/* Define if you want to compile in rudimentary thread support */ -/* #undef WITH_THREAD */ - -/* Define if you want to use the GNU readline library */ -/* #define WITH_READLINE 1 */ - -/* Use Python's own small-block memory-allocator. */ -#define WITH_PYMALLOC 1 - -/* Define if you have clock. */ -/* #define HAVE_CLOCK */ - -/* Define when any dynamic module loading is enabled */ -#define HAVE_DYNAMIC_LOADING - -/* Define if you have ftime. */ -#define HAVE_FTIME - -/* Define if you have getpeername. */ -#define HAVE_GETPEERNAME - -/* Define if you have getpgrp. */ -/* #undef HAVE_GETPGRP */ - -/* Define if you have getpid. */ -#define HAVE_GETPID - -/* Define if you have gettimeofday. */ -/* #undef HAVE_GETTIMEOFDAY */ - -/* Define if you have getwd. */ -/* #undef HAVE_GETWD */ - -/* Define if you have lstat. */ -/* #undef HAVE_LSTAT */ - -/* Define if you have the mktime function. */ -#define HAVE_MKTIME - -/* Define if you have nice. */ -/* #undef HAVE_NICE */ - -/* Define if you have readlink. */ -/* #undef HAVE_READLINK */ - -/* Define if you have setpgid. */ -/* #undef HAVE_SETPGID */ - -/* Define if you have setpgrp. */ -/* #undef HAVE_SETPGRP */ - -/* Define if you have setsid. */ -/* #undef HAVE_SETSID */ - -/* Define if you have setvbuf. */ -#define HAVE_SETVBUF - -/* Define if you have siginterrupt. */ -/* #undef HAVE_SIGINTERRUPT */ - -/* Define if you have symlink. */ -/* #undef HAVE_SYMLINK */ - -/* Define if you have tcgetpgrp. */ -/* #undef HAVE_TCGETPGRP */ - -/* Define if you have tcsetpgrp. */ -/* #undef HAVE_TCSETPGRP */ - -/* Define if you have times. */ -/* #undef HAVE_TIMES */ - -/* Define if you have uname. */ -/* #undef HAVE_UNAME */ - -/* Define if you have waitpid. */ -/* #undef HAVE_WAITPID */ - -/* Define to 1 if you have the `wcsftime' function. */ -#if defined(_MSC_VER) && _MSC_VER >= 1310 -#define HAVE_WCSFTIME 1 -#endif - -/* Define to 1 if you have the `wcscoll' function. */ -#define HAVE_WCSCOLL 1 - -/* Define to 1 if you have the `wcsxfrm' function. */ -#define HAVE_WCSXFRM 1 - -/* Define if the zlib library has inflateCopy */ -#define HAVE_ZLIB_COPY 1 - -/* Define if you have the header file. */ -/* #undef HAVE_DLFCN_H */ - -/* Define to 1 if you have the header file. */ -#define HAVE_ERRNO_H 1 - -/* Define if you have the header file. */ -#define HAVE_FCNTL_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_PROCESS_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SIGNAL_H 1 - -/* Define if you have the prototypes. */ -#define HAVE_STDARG_PROTOTYPES - -/* Define if you have the header file. */ -#define HAVE_STDDEF_H 1 - -/* Define if you have the header file. */ -/* #undef HAVE_SYS_AUDIOIO_H */ - -/* Define if you have the header file. */ -/* #define HAVE_SYS_PARAM_H 1 */ - -/* Define if you have the header file. */ -/* #define HAVE_SYS_SELECT_H 1 */ - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_STAT_H 1 - -/* Define if you have the header file. */ -/* #define HAVE_SYS_TIME_H 1 */ - -/* Define if you have the header file. */ -/* #define HAVE_SYS_TIMES_H 1 */ - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_TYPES_H 1 - -/* Define if you have the header file. */ -/* #define HAVE_SYS_UN_H 1 */ - -/* Define if you have the header file. */ -/* #define HAVE_SYS_UTIME_H 1 */ - -/* Define if you have the header file. */ -/* #define HAVE_SYS_UTSNAME_H 1 */ - -/* Define if you have the header file. */ -/* #define HAVE_UNISTD_H 1 */ - -/* Define if you have the header file. */ -/* #define HAVE_UTIME_H 1 */ - -/* Define if the compiler provides a wchar.h header file. */ -#define HAVE_WCHAR_H 1 - -/* The size of `wchar_t', as computed by sizeof. */ -#define SIZEOF_WCHAR_T 2 - -/* The size of `_Bool', as computed by sizeof. */ -#define SIZEOF__BOOL 1 - -/* The size of `pid_t', as computed by sizeof. */ -#define SIZEOF_PID_T SIZEOF_INT - -/* Define if you have the dl library (-ldl). */ -/* #undef HAVE_LIBDL */ - -/* Define if you have the mpc library (-lmpc). */ -/* #undef HAVE_LIBMPC */ - -/* Define if you have the nsl library (-lnsl). */ -#define HAVE_LIBNSL 1 - -/* Define if you have the seq library (-lseq). */ -/* #undef HAVE_LIBSEQ */ - -/* Define if you have the socket library (-lsocket). */ -#define HAVE_LIBSOCKET 1 - -/* Define if you have the sun library (-lsun). */ -/* #undef HAVE_LIBSUN */ - -/* Define if you have the termcap library (-ltermcap). */ -/* #undef HAVE_LIBTERMCAP */ - -/* Define if you have the termlib library (-ltermlib). */ -/* #undef HAVE_LIBTERMLIB */ - -/* Define if you have the thread library (-lthread). */ -/* #undef HAVE_LIBTHREAD */ - -/* WinSock does not use a bitmask in select, and uses - socket handles greater than FD_SETSIZE */ -#define Py_SOCKET_FD_CAN_BE_GE_FD_SETSIZE - -/* Define if C doubles are 64-bit IEEE 754 binary format, stored with the - least significant byte first */ -#define DOUBLE_IS_LITTLE_ENDIAN_IEEE754 1 - -/* Define to 1 if you have the `erf' function. */ -#define HAVE_ERF 1 - -/* Define to 1 if you have the `erfc' function. */ -#define HAVE_ERFC 1 - -/* Define if you have the 'inet_pton' function. */ -#define HAVE_INET_PTON 1 - -/* framework name */ -#define _PYTHONFRAMEWORK "" - -/* Define if libssl has X509_VERIFY_PARAM_set1_host and related function */ -#define HAVE_X509_VERIFY_PARAM_SET1_HOST 1 - -#define PLATLIBDIR "lib" - -#endif /* !Py_CONFIG_H */ diff --git a/scripts/build-windows/py39-libs/include/pyctype.h b/scripts/build-windows/py39-libs/include/pyctype.h deleted file mode 100644 index 8f4bd79c3..000000000 --- a/scripts/build-windows/py39-libs/include/pyctype.h +++ /dev/null @@ -1,39 +0,0 @@ -#ifndef Py_LIMITED_API -#ifndef PYCTYPE_H -#define PYCTYPE_H -#ifdef __cplusplus -extern "C" { -#endif - -#define PY_CTF_LOWER 0x01 -#define PY_CTF_UPPER 0x02 -#define PY_CTF_ALPHA (PY_CTF_LOWER|PY_CTF_UPPER) -#define PY_CTF_DIGIT 0x04 -#define PY_CTF_ALNUM (PY_CTF_ALPHA|PY_CTF_DIGIT) -#define PY_CTF_SPACE 0x08 -#define PY_CTF_XDIGIT 0x10 - -PyAPI_DATA(const unsigned int) _Py_ctype_table[256]; - -/* Unlike their C counterparts, the following macros are not meant to - * handle an int with any of the values [EOF, 0-UCHAR_MAX]. The argument - * must be a signed/unsigned char. */ -#define Py_ISLOWER(c) (_Py_ctype_table[Py_CHARMASK(c)] & PY_CTF_LOWER) -#define Py_ISUPPER(c) (_Py_ctype_table[Py_CHARMASK(c)] & PY_CTF_UPPER) -#define Py_ISALPHA(c) (_Py_ctype_table[Py_CHARMASK(c)] & PY_CTF_ALPHA) -#define Py_ISDIGIT(c) (_Py_ctype_table[Py_CHARMASK(c)] & PY_CTF_DIGIT) -#define Py_ISXDIGIT(c) (_Py_ctype_table[Py_CHARMASK(c)] & PY_CTF_XDIGIT) -#define Py_ISALNUM(c) (_Py_ctype_table[Py_CHARMASK(c)] & PY_CTF_ALNUM) -#define Py_ISSPACE(c) (_Py_ctype_table[Py_CHARMASK(c)] & PY_CTF_SPACE) - -PyAPI_DATA(const unsigned char) _Py_ctype_tolower[256]; -PyAPI_DATA(const unsigned char) _Py_ctype_toupper[256]; - -#define Py_TOLOWER(c) (_Py_ctype_tolower[Py_CHARMASK(c)]) -#define Py_TOUPPER(c) (_Py_ctype_toupper[Py_CHARMASK(c)]) - -#ifdef __cplusplus -} -#endif -#endif /* !PYCTYPE_H */ -#endif /* !Py_LIMITED_API */ diff --git a/scripts/build-windows/py39-libs/include/pydebug.h b/scripts/build-windows/py39-libs/include/pydebug.h deleted file mode 100644 index e34cf9078..000000000 --- a/scripts/build-windows/py39-libs/include/pydebug.h +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef Py_LIMITED_API -#ifndef Py_PYDEBUG_H -#define Py_PYDEBUG_H -#ifdef __cplusplus -extern "C" { -#endif - -PyAPI_DATA(int) Py_DebugFlag; -PyAPI_DATA(int) Py_VerboseFlag; -PyAPI_DATA(int) Py_QuietFlag; -PyAPI_DATA(int) Py_InteractiveFlag; -PyAPI_DATA(int) Py_InspectFlag; -PyAPI_DATA(int) Py_OptimizeFlag; -PyAPI_DATA(int) Py_NoSiteFlag; -PyAPI_DATA(int) Py_BytesWarningFlag; -PyAPI_DATA(int) Py_FrozenFlag; -PyAPI_DATA(int) Py_IgnoreEnvironmentFlag; -PyAPI_DATA(int) Py_DontWriteBytecodeFlag; -PyAPI_DATA(int) Py_NoUserSiteDirectory; -PyAPI_DATA(int) Py_UnbufferedStdioFlag; -PyAPI_DATA(int) Py_HashRandomizationFlag; -PyAPI_DATA(int) Py_IsolatedFlag; - -#ifdef MS_WINDOWS -PyAPI_DATA(int) Py_LegacyWindowsFSEncodingFlag; -PyAPI_DATA(int) Py_LegacyWindowsStdioFlag; -#endif - -/* this is a wrapper around getenv() that pays attention to - Py_IgnoreEnvironmentFlag. It should be used for getting variables like - PYTHONPATH and PYTHONHOME from the environment */ -#define Py_GETENV(s) (Py_IgnoreEnvironmentFlag ? NULL : getenv(s)) - -#ifdef __cplusplus -} -#endif -#endif /* !Py_PYDEBUG_H */ -#endif /* Py_LIMITED_API */ diff --git a/scripts/build-windows/py39-libs/include/pydtrace.h b/scripts/build-windows/py39-libs/include/pydtrace.h deleted file mode 100644 index 8fac20043..000000000 --- a/scripts/build-windows/py39-libs/include/pydtrace.h +++ /dev/null @@ -1,59 +0,0 @@ -/* Static DTrace probes interface */ - -#ifndef Py_DTRACE_H -#define Py_DTRACE_H -#ifdef __cplusplus -extern "C" { -#endif - -#ifdef WITH_DTRACE - -#include "pydtrace_probes.h" - -/* pydtrace_probes.h, on systems with DTrace, is auto-generated to include - `PyDTrace_{PROBE}` and `PyDTrace_{PROBE}_ENABLED()` macros for every probe - defined in pydtrace_provider.d. - - Calling these functions must be guarded by a `PyDTrace_{PROBE}_ENABLED()` - check to minimize performance impact when probing is off. For example: - - if (PyDTrace_FUNCTION_ENTRY_ENABLED()) - PyDTrace_FUNCTION_ENTRY(f); -*/ - -#else - -/* Without DTrace, compile to nothing. */ - -static inline void PyDTrace_LINE(const char *arg0, const char *arg1, int arg2) {} -static inline void PyDTrace_FUNCTION_ENTRY(const char *arg0, const char *arg1, int arg2) {} -static inline void PyDTrace_FUNCTION_RETURN(const char *arg0, const char *arg1, int arg2) {} -static inline void PyDTrace_GC_START(int arg0) {} -static inline void PyDTrace_GC_DONE(Py_ssize_t arg0) {} -static inline void PyDTrace_INSTANCE_NEW_START(int arg0) {} -static inline void PyDTrace_INSTANCE_NEW_DONE(int arg0) {} -static inline void PyDTrace_INSTANCE_DELETE_START(int arg0) {} -static inline void PyDTrace_INSTANCE_DELETE_DONE(int arg0) {} -static inline void PyDTrace_IMPORT_FIND_LOAD_START(const char *arg0) {} -static inline void PyDTrace_IMPORT_FIND_LOAD_DONE(const char *arg0, int arg1) {} -static inline void PyDTrace_AUDIT(const char *arg0, void *arg1) {} - -static inline int PyDTrace_LINE_ENABLED(void) { return 0; } -static inline int PyDTrace_FUNCTION_ENTRY_ENABLED(void) { return 0; } -static inline int PyDTrace_FUNCTION_RETURN_ENABLED(void) { return 0; } -static inline int PyDTrace_GC_START_ENABLED(void) { return 0; } -static inline int PyDTrace_GC_DONE_ENABLED(void) { return 0; } -static inline int PyDTrace_INSTANCE_NEW_START_ENABLED(void) { return 0; } -static inline int PyDTrace_INSTANCE_NEW_DONE_ENABLED(void) { return 0; } -static inline int PyDTrace_INSTANCE_DELETE_START_ENABLED(void) { return 0; } -static inline int PyDTrace_INSTANCE_DELETE_DONE_ENABLED(void) { return 0; } -static inline int PyDTrace_IMPORT_FIND_LOAD_START_ENABLED(void) { return 0; } -static inline int PyDTrace_IMPORT_FIND_LOAD_DONE_ENABLED(void) { return 0; } -static inline int PyDTrace_AUDIT_ENABLED(void) { return 0; } - -#endif /* !WITH_DTRACE */ - -#ifdef __cplusplus -} -#endif -#endif /* !Py_DTRACE_H */ diff --git a/scripts/build-windows/py39-libs/include/pyerrors.h b/scripts/build-windows/py39-libs/include/pyerrors.h deleted file mode 100644 index bd634e710..000000000 --- a/scripts/build-windows/py39-libs/include/pyerrors.h +++ /dev/null @@ -1,326 +0,0 @@ -#ifndef Py_ERRORS_H -#define Py_ERRORS_H -#ifdef __cplusplus -extern "C" { -#endif - -#include // va_list - -/* Error handling definitions */ - -PyAPI_FUNC(void) PyErr_SetNone(PyObject *); -PyAPI_FUNC(void) PyErr_SetObject(PyObject *, PyObject *); -PyAPI_FUNC(void) PyErr_SetString( - PyObject *exception, - const char *string /* decoded from utf-8 */ - ); -PyAPI_FUNC(PyObject *) PyErr_Occurred(void); -PyAPI_FUNC(void) PyErr_Clear(void); -PyAPI_FUNC(void) PyErr_Fetch(PyObject **, PyObject **, PyObject **); -PyAPI_FUNC(void) PyErr_Restore(PyObject *, PyObject *, PyObject *); -#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03030000 -PyAPI_FUNC(void) PyErr_GetExcInfo(PyObject **, PyObject **, PyObject **); -PyAPI_FUNC(void) PyErr_SetExcInfo(PyObject *, PyObject *, PyObject *); -#endif - -/* Defined in Python/pylifecycle.c - - The Py_FatalError() function is replaced with a macro which logs - automatically the name of the current function, unless the Py_LIMITED_API - macro is defined. */ -PyAPI_FUNC(void) _Py_NO_RETURN Py_FatalError(const char *message); - -#if defined(Py_DEBUG) || defined(Py_LIMITED_API) -#define _PyErr_OCCURRED() PyErr_Occurred() -#else -#define _PyErr_OCCURRED() (PyThreadState_GET()->curexc_type) -#endif - -/* Error testing and normalization */ -PyAPI_FUNC(int) PyErr_GivenExceptionMatches(PyObject *, PyObject *); -PyAPI_FUNC(int) PyErr_ExceptionMatches(PyObject *); -PyAPI_FUNC(void) PyErr_NormalizeException(PyObject**, PyObject**, PyObject**); - -/* Traceback manipulation (PEP 3134) */ -PyAPI_FUNC(int) PyException_SetTraceback(PyObject *, PyObject *); -PyAPI_FUNC(PyObject *) PyException_GetTraceback(PyObject *); - -/* Cause manipulation (PEP 3134) */ -PyAPI_FUNC(PyObject *) PyException_GetCause(PyObject *); -PyAPI_FUNC(void) PyException_SetCause(PyObject *, PyObject *); - -/* Context manipulation (PEP 3134) */ -PyAPI_FUNC(PyObject *) PyException_GetContext(PyObject *); -PyAPI_FUNC(void) PyException_SetContext(PyObject *, PyObject *); - -/* */ - -#define PyExceptionClass_Check(x) \ - (PyType_Check((x)) && \ - PyType_FastSubclass((PyTypeObject*)(x), Py_TPFLAGS_BASE_EXC_SUBCLASS)) - -#define PyExceptionInstance_Check(x) \ - PyType_FastSubclass(Py_TYPE(x), Py_TPFLAGS_BASE_EXC_SUBCLASS) - -PyAPI_FUNC(const char *) PyExceptionClass_Name(PyObject *); - -#define PyExceptionInstance_Class(x) ((PyObject*)Py_TYPE(x)) - - -/* Predefined exceptions */ - -PyAPI_DATA(PyObject *) PyExc_BaseException; -PyAPI_DATA(PyObject *) PyExc_Exception; -#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03050000 -PyAPI_DATA(PyObject *) PyExc_StopAsyncIteration; -#endif -PyAPI_DATA(PyObject *) PyExc_StopIteration; -PyAPI_DATA(PyObject *) PyExc_GeneratorExit; -PyAPI_DATA(PyObject *) PyExc_ArithmeticError; -PyAPI_DATA(PyObject *) PyExc_LookupError; - -PyAPI_DATA(PyObject *) PyExc_AssertionError; -PyAPI_DATA(PyObject *) PyExc_AttributeError; -PyAPI_DATA(PyObject *) PyExc_BufferError; -PyAPI_DATA(PyObject *) PyExc_EOFError; -PyAPI_DATA(PyObject *) PyExc_FloatingPointError; -PyAPI_DATA(PyObject *) PyExc_OSError; -PyAPI_DATA(PyObject *) PyExc_ImportError; -#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03060000 -PyAPI_DATA(PyObject *) PyExc_ModuleNotFoundError; -#endif -PyAPI_DATA(PyObject *) PyExc_IndexError; -PyAPI_DATA(PyObject *) PyExc_KeyError; -PyAPI_DATA(PyObject *) PyExc_KeyboardInterrupt; -PyAPI_DATA(PyObject *) PyExc_MemoryError; -PyAPI_DATA(PyObject *) PyExc_NameError; -PyAPI_DATA(PyObject *) PyExc_OverflowError; -PyAPI_DATA(PyObject *) PyExc_RuntimeError; -#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03050000 -PyAPI_DATA(PyObject *) PyExc_RecursionError; -#endif -PyAPI_DATA(PyObject *) PyExc_NotImplementedError; -PyAPI_DATA(PyObject *) PyExc_SyntaxError; -PyAPI_DATA(PyObject *) PyExc_IndentationError; -PyAPI_DATA(PyObject *) PyExc_TabError; -PyAPI_DATA(PyObject *) PyExc_ReferenceError; -PyAPI_DATA(PyObject *) PyExc_SystemError; -PyAPI_DATA(PyObject *) PyExc_SystemExit; -PyAPI_DATA(PyObject *) PyExc_TypeError; -PyAPI_DATA(PyObject *) PyExc_UnboundLocalError; -PyAPI_DATA(PyObject *) PyExc_UnicodeError; -PyAPI_DATA(PyObject *) PyExc_UnicodeEncodeError; -PyAPI_DATA(PyObject *) PyExc_UnicodeDecodeError; -PyAPI_DATA(PyObject *) PyExc_UnicodeTranslateError; -PyAPI_DATA(PyObject *) PyExc_ValueError; -PyAPI_DATA(PyObject *) PyExc_ZeroDivisionError; - -#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03030000 -PyAPI_DATA(PyObject *) PyExc_BlockingIOError; -PyAPI_DATA(PyObject *) PyExc_BrokenPipeError; -PyAPI_DATA(PyObject *) PyExc_ChildProcessError; -PyAPI_DATA(PyObject *) PyExc_ConnectionError; -PyAPI_DATA(PyObject *) PyExc_ConnectionAbortedError; -PyAPI_DATA(PyObject *) PyExc_ConnectionRefusedError; -PyAPI_DATA(PyObject *) PyExc_ConnectionResetError; -PyAPI_DATA(PyObject *) PyExc_FileExistsError; -PyAPI_DATA(PyObject *) PyExc_FileNotFoundError; -PyAPI_DATA(PyObject *) PyExc_InterruptedError; -PyAPI_DATA(PyObject *) PyExc_IsADirectoryError; -PyAPI_DATA(PyObject *) PyExc_NotADirectoryError; -PyAPI_DATA(PyObject *) PyExc_PermissionError; -PyAPI_DATA(PyObject *) PyExc_ProcessLookupError; -PyAPI_DATA(PyObject *) PyExc_TimeoutError; -#endif - - -/* Compatibility aliases */ -PyAPI_DATA(PyObject *) PyExc_EnvironmentError; -PyAPI_DATA(PyObject *) PyExc_IOError; -#ifdef MS_WINDOWS -PyAPI_DATA(PyObject *) PyExc_WindowsError; -#endif - -/* Predefined warning categories */ -PyAPI_DATA(PyObject *) PyExc_Warning; -PyAPI_DATA(PyObject *) PyExc_UserWarning; -PyAPI_DATA(PyObject *) PyExc_DeprecationWarning; -PyAPI_DATA(PyObject *) PyExc_PendingDeprecationWarning; -PyAPI_DATA(PyObject *) PyExc_SyntaxWarning; -PyAPI_DATA(PyObject *) PyExc_RuntimeWarning; -PyAPI_DATA(PyObject *) PyExc_FutureWarning; -PyAPI_DATA(PyObject *) PyExc_ImportWarning; -PyAPI_DATA(PyObject *) PyExc_UnicodeWarning; -PyAPI_DATA(PyObject *) PyExc_BytesWarning; -PyAPI_DATA(PyObject *) PyExc_ResourceWarning; - - -/* Convenience functions */ - -PyAPI_FUNC(int) PyErr_BadArgument(void); -PyAPI_FUNC(PyObject *) PyErr_NoMemory(void); -PyAPI_FUNC(PyObject *) PyErr_SetFromErrno(PyObject *); -PyAPI_FUNC(PyObject *) PyErr_SetFromErrnoWithFilenameObject( - PyObject *, PyObject *); -#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03040000 -PyAPI_FUNC(PyObject *) PyErr_SetFromErrnoWithFilenameObjects( - PyObject *, PyObject *, PyObject *); -#endif -PyAPI_FUNC(PyObject *) PyErr_SetFromErrnoWithFilename( - PyObject *exc, - const char *filename /* decoded from the filesystem encoding */ - ); - -PyAPI_FUNC(PyObject *) PyErr_Format( - PyObject *exception, - const char *format, /* ASCII-encoded string */ - ... - ); -#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03050000 -PyAPI_FUNC(PyObject *) PyErr_FormatV( - PyObject *exception, - const char *format, - va_list vargs); -#endif - -#ifdef MS_WINDOWS -PyAPI_FUNC(PyObject *) PyErr_SetFromWindowsErrWithFilename( - int ierr, - const char *filename /* decoded from the filesystem encoding */ - ); -PyAPI_FUNC(PyObject *) PyErr_SetFromWindowsErr(int); -PyAPI_FUNC(PyObject *) PyErr_SetExcFromWindowsErrWithFilenameObject( - PyObject *,int, PyObject *); -#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03040000 -PyAPI_FUNC(PyObject *) PyErr_SetExcFromWindowsErrWithFilenameObjects( - PyObject *,int, PyObject *, PyObject *); -#endif -PyAPI_FUNC(PyObject *) PyErr_SetExcFromWindowsErrWithFilename( - PyObject *exc, - int ierr, - const char *filename /* decoded from the filesystem encoding */ - ); -PyAPI_FUNC(PyObject *) PyErr_SetExcFromWindowsErr(PyObject *, int); -#endif /* MS_WINDOWS */ - -#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03060000 -PyAPI_FUNC(PyObject *) PyErr_SetImportErrorSubclass(PyObject *, PyObject *, - PyObject *, PyObject *); -#endif -#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03030000 -PyAPI_FUNC(PyObject *) PyErr_SetImportError(PyObject *, PyObject *, - PyObject *); -#endif - -/* Export the old function so that the existing API remains available: */ -PyAPI_FUNC(void) PyErr_BadInternalCall(void); -PyAPI_FUNC(void) _PyErr_BadInternalCall(const char *filename, int lineno); -/* Mask the old API with a call to the new API for code compiled under - Python 2.0: */ -#define PyErr_BadInternalCall() _PyErr_BadInternalCall(__FILE__, __LINE__) - -/* Function to create a new exception */ -PyAPI_FUNC(PyObject *) PyErr_NewException( - const char *name, PyObject *base, PyObject *dict); -PyAPI_FUNC(PyObject *) PyErr_NewExceptionWithDoc( - const char *name, const char *doc, PyObject *base, PyObject *dict); -PyAPI_FUNC(void) PyErr_WriteUnraisable(PyObject *); - - -/* In signalmodule.c */ -PyAPI_FUNC(int) PyErr_CheckSignals(void); -PyAPI_FUNC(void) PyErr_SetInterrupt(void); - -/* Support for adding program text to SyntaxErrors */ -PyAPI_FUNC(void) PyErr_SyntaxLocation( - const char *filename, /* decoded from the filesystem encoding */ - int lineno); -PyAPI_FUNC(void) PyErr_SyntaxLocationEx( - const char *filename, /* decoded from the filesystem encoding */ - int lineno, - int col_offset); -PyAPI_FUNC(PyObject *) PyErr_ProgramText( - const char *filename, /* decoded from the filesystem encoding */ - int lineno); - -/* The following functions are used to create and modify unicode - exceptions from C */ - -/* create a UnicodeDecodeError object */ -PyAPI_FUNC(PyObject *) PyUnicodeDecodeError_Create( - const char *encoding, /* UTF-8 encoded string */ - const char *object, - Py_ssize_t length, - Py_ssize_t start, - Py_ssize_t end, - const char *reason /* UTF-8 encoded string */ - ); - -/* get the encoding attribute */ -PyAPI_FUNC(PyObject *) PyUnicodeEncodeError_GetEncoding(PyObject *); -PyAPI_FUNC(PyObject *) PyUnicodeDecodeError_GetEncoding(PyObject *); - -/* get the object attribute */ -PyAPI_FUNC(PyObject *) PyUnicodeEncodeError_GetObject(PyObject *); -PyAPI_FUNC(PyObject *) PyUnicodeDecodeError_GetObject(PyObject *); -PyAPI_FUNC(PyObject *) PyUnicodeTranslateError_GetObject(PyObject *); - -/* get the value of the start attribute (the int * may not be NULL) - return 0 on success, -1 on failure */ -PyAPI_FUNC(int) PyUnicodeEncodeError_GetStart(PyObject *, Py_ssize_t *); -PyAPI_FUNC(int) PyUnicodeDecodeError_GetStart(PyObject *, Py_ssize_t *); -PyAPI_FUNC(int) PyUnicodeTranslateError_GetStart(PyObject *, Py_ssize_t *); - -/* assign a new value to the start attribute - return 0 on success, -1 on failure */ -PyAPI_FUNC(int) PyUnicodeEncodeError_SetStart(PyObject *, Py_ssize_t); -PyAPI_FUNC(int) PyUnicodeDecodeError_SetStart(PyObject *, Py_ssize_t); -PyAPI_FUNC(int) PyUnicodeTranslateError_SetStart(PyObject *, Py_ssize_t); - -/* get the value of the end attribute (the int *may not be NULL) - return 0 on success, -1 on failure */ -PyAPI_FUNC(int) PyUnicodeEncodeError_GetEnd(PyObject *, Py_ssize_t *); -PyAPI_FUNC(int) PyUnicodeDecodeError_GetEnd(PyObject *, Py_ssize_t *); -PyAPI_FUNC(int) PyUnicodeTranslateError_GetEnd(PyObject *, Py_ssize_t *); - -/* assign a new value to the end attribute - return 0 on success, -1 on failure */ -PyAPI_FUNC(int) PyUnicodeEncodeError_SetEnd(PyObject *, Py_ssize_t); -PyAPI_FUNC(int) PyUnicodeDecodeError_SetEnd(PyObject *, Py_ssize_t); -PyAPI_FUNC(int) PyUnicodeTranslateError_SetEnd(PyObject *, Py_ssize_t); - -/* get the value of the reason attribute */ -PyAPI_FUNC(PyObject *) PyUnicodeEncodeError_GetReason(PyObject *); -PyAPI_FUNC(PyObject *) PyUnicodeDecodeError_GetReason(PyObject *); -PyAPI_FUNC(PyObject *) PyUnicodeTranslateError_GetReason(PyObject *); - -/* assign a new value to the reason attribute - return 0 on success, -1 on failure */ -PyAPI_FUNC(int) PyUnicodeEncodeError_SetReason( - PyObject *exc, - const char *reason /* UTF-8 encoded string */ - ); -PyAPI_FUNC(int) PyUnicodeDecodeError_SetReason( - PyObject *exc, - const char *reason /* UTF-8 encoded string */ - ); -PyAPI_FUNC(int) PyUnicodeTranslateError_SetReason( - PyObject *exc, - const char *reason /* UTF-8 encoded string */ - ); - -PyAPI_FUNC(int) PyOS_snprintf(char *str, size_t size, const char *format, ...) - Py_GCC_ATTRIBUTE((format(printf, 3, 4))); -PyAPI_FUNC(int) PyOS_vsnprintf(char *str, size_t size, const char *format, va_list va) - Py_GCC_ATTRIBUTE((format(printf, 3, 0))); - -#ifndef Py_LIMITED_API -# define Py_CPYTHON_ERRORS_H -# include "cpython/pyerrors.h" -# undef Py_CPYTHON_ERRORS_H -#endif - -#ifdef __cplusplus -} -#endif -#endif /* !Py_ERRORS_H */ diff --git a/scripts/build-windows/py39-libs/include/pyexpat.h b/scripts/build-windows/py39-libs/include/pyexpat.h deleted file mode 100644 index 5f5d381aa..000000000 --- a/scripts/build-windows/py39-libs/include/pyexpat.h +++ /dev/null @@ -1,55 +0,0 @@ -/* Stuff to export relevant 'expat' entry points from pyexpat to other - * parser modules, such as cElementTree. */ - -/* note: you must import expat.h before importing this module! */ - -#define PyExpat_CAPI_MAGIC "pyexpat.expat_CAPI 1.1" -#define PyExpat_CAPSULE_NAME "pyexpat.expat_CAPI" - -struct PyExpat_CAPI -{ - char* magic; /* set to PyExpat_CAPI_MAGIC */ - int size; /* set to sizeof(struct PyExpat_CAPI) */ - int MAJOR_VERSION; - int MINOR_VERSION; - int MICRO_VERSION; - /* pointers to selected expat functions. add new functions at - the end, if needed */ - const XML_LChar * (*ErrorString)(enum XML_Error code); - enum XML_Error (*GetErrorCode)(XML_Parser parser); - XML_Size (*GetErrorColumnNumber)(XML_Parser parser); - XML_Size (*GetErrorLineNumber)(XML_Parser parser); - enum XML_Status (*Parse)( - XML_Parser parser, const char *s, int len, int isFinal); - XML_Parser (*ParserCreate_MM)( - const XML_Char *encoding, const XML_Memory_Handling_Suite *memsuite, - const XML_Char *namespaceSeparator); - void (*ParserFree)(XML_Parser parser); - void (*SetCharacterDataHandler)( - XML_Parser parser, XML_CharacterDataHandler handler); - void (*SetCommentHandler)( - XML_Parser parser, XML_CommentHandler handler); - void (*SetDefaultHandlerExpand)( - XML_Parser parser, XML_DefaultHandler handler); - void (*SetElementHandler)( - XML_Parser parser, XML_StartElementHandler start, - XML_EndElementHandler end); - void (*SetNamespaceDeclHandler)( - XML_Parser parser, XML_StartNamespaceDeclHandler start, - XML_EndNamespaceDeclHandler end); - void (*SetProcessingInstructionHandler)( - XML_Parser parser, XML_ProcessingInstructionHandler handler); - void (*SetUnknownEncodingHandler)( - XML_Parser parser, XML_UnknownEncodingHandler handler, - void *encodingHandlerData); - void (*SetUserData)(XML_Parser parser, void *userData); - void (*SetStartDoctypeDeclHandler)(XML_Parser parser, - XML_StartDoctypeDeclHandler start); - enum XML_Status (*SetEncoding)(XML_Parser parser, const XML_Char *encoding); - int (*DefaultUnknownEncodingHandler)( - void *encodingHandlerData, const XML_Char *name, XML_Encoding *info); - /* might be none for expat < 2.1.0 */ - int (*SetHashSalt)(XML_Parser parser, unsigned long hash_salt); - /* always add new stuff to the end! */ -}; - diff --git a/scripts/build-windows/py39-libs/include/pyfpe.h b/scripts/build-windows/py39-libs/include/pyfpe.h deleted file mode 100644 index d5a52617b..000000000 --- a/scripts/build-windows/py39-libs/include/pyfpe.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef Py_PYFPE_H -#define Py_PYFPE_H -/* Header excluded from the stable API */ -#ifndef Py_LIMITED_API - -/* These macros used to do something when Python was built with --with-fpectl, - * but support for that was dropped in 3.7. We continue to define them though, - * to avoid breaking API users. - */ - -#define PyFPE_START_PROTECT(err_string, leave_stmt) -#define PyFPE_END_PROTECT(v) - -#endif /* !defined(Py_LIMITED_API) */ -#endif /* !Py_PYFPE_H */ diff --git a/scripts/build-windows/py39-libs/include/pyframe.h b/scripts/build-windows/py39-libs/include/pyframe.h deleted file mode 100644 index a25769022..000000000 --- a/scripts/build-windows/py39-libs/include/pyframe.h +++ /dev/null @@ -1,22 +0,0 @@ -/* Limited C API of PyFrame API - * - * Include "frameobject.h" to get the PyFrameObject structure. - */ - -#ifndef Py_PYFRAME_H -#define Py_PYFRAME_H -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct _frame PyFrameObject; - -/* Return the line of code the frame is currently executing. */ -PyAPI_FUNC(int) PyFrame_GetLineNumber(PyFrameObject *); - -PyAPI_FUNC(PyCodeObject *) PyFrame_GetCode(PyFrameObject *frame); - -#ifdef __cplusplus -} -#endif -#endif /* !Py_PYFRAME_H */ diff --git a/scripts/build-windows/py39-libs/include/pyhash.h b/scripts/build-windows/py39-libs/include/pyhash.h deleted file mode 100644 index fe42fa8c3..000000000 --- a/scripts/build-windows/py39-libs/include/pyhash.h +++ /dev/null @@ -1,147 +0,0 @@ -#ifndef Py_HASH_H - -#define Py_HASH_H -#ifdef __cplusplus -extern "C" { -#endif - -/* Helpers for hash functions */ -#ifndef Py_LIMITED_API -PyAPI_FUNC(Py_hash_t) _Py_HashDouble(double); -PyAPI_FUNC(Py_hash_t) _Py_HashPointer(const void*); -// Similar to _Py_HashPointer(), but don't replace -1 with -2 -PyAPI_FUNC(Py_hash_t) _Py_HashPointerRaw(const void*); -PyAPI_FUNC(Py_hash_t) _Py_HashBytes(const void*, Py_ssize_t); -#endif - -/* Prime multiplier used in string and various other hashes. */ -#define _PyHASH_MULTIPLIER 1000003UL /* 0xf4243 */ - -/* Parameters used for the numeric hash implementation. See notes for - _Py_HashDouble in Python/pyhash.c. Numeric hashes are based on - reduction modulo the prime 2**_PyHASH_BITS - 1. */ - -#if SIZEOF_VOID_P >= 8 -# define _PyHASH_BITS 61 -#else -# define _PyHASH_BITS 31 -#endif - -#define _PyHASH_MODULUS (((size_t)1 << _PyHASH_BITS) - 1) -#define _PyHASH_INF 314159 -#define _PyHASH_NAN 0 -#define _PyHASH_IMAG _PyHASH_MULTIPLIER - - -/* hash secret - * - * memory layout on 64 bit systems - * cccccccc cccccccc cccccccc uc -- unsigned char[24] - * pppppppp ssssssss ........ fnv -- two Py_hash_t - * k0k0k0k0 k1k1k1k1 ........ siphash -- two uint64_t - * ........ ........ ssssssss djbx33a -- 16 bytes padding + one Py_hash_t - * ........ ........ eeeeeeee pyexpat XML hash salt - * - * memory layout on 32 bit systems - * cccccccc cccccccc cccccccc uc - * ppppssss ........ ........ fnv -- two Py_hash_t - * k0k0k0k0 k1k1k1k1 ........ siphash -- two uint64_t (*) - * ........ ........ ssss.... djbx33a -- 16 bytes padding + one Py_hash_t - * ........ ........ eeee.... pyexpat XML hash salt - * - * (*) The siphash member may not be available on 32 bit platforms without - * an unsigned int64 data type. - */ -#ifndef Py_LIMITED_API -typedef union { - /* ensure 24 bytes */ - unsigned char uc[24]; - /* two Py_hash_t for FNV */ - struct { - Py_hash_t prefix; - Py_hash_t suffix; - } fnv; - /* two uint64 for SipHash24 */ - struct { - uint64_t k0; - uint64_t k1; - } siphash; - /* a different (!) Py_hash_t for small string optimization */ - struct { - unsigned char padding[16]; - Py_hash_t suffix; - } djbx33a; - struct { - unsigned char padding[16]; - Py_hash_t hashsalt; - } expat; -} _Py_HashSecret_t; -PyAPI_DATA(_Py_HashSecret_t) _Py_HashSecret; -#endif - -#ifdef Py_DEBUG -PyAPI_DATA(int) _Py_HashSecret_Initialized; -#endif - - -/* hash function definition */ -#ifndef Py_LIMITED_API -typedef struct { - Py_hash_t (*const hash)(const void *, Py_ssize_t); - const char *name; - const int hash_bits; - const int seed_bits; -} PyHash_FuncDef; - -PyAPI_FUNC(PyHash_FuncDef*) PyHash_GetFuncDef(void); -#endif - - -/* cutoff for small string DJBX33A optimization in range [1, cutoff). - * - * About 50% of the strings in a typical Python application are smaller than - * 6 to 7 chars. However DJBX33A is vulnerable to hash collision attacks. - * NEVER use DJBX33A for long strings! - * - * A Py_HASH_CUTOFF of 0 disables small string optimization. 32 bit platforms - * should use a smaller cutoff because it is easier to create colliding - * strings. A cutoff of 7 on 64bit platforms and 5 on 32bit platforms should - * provide a decent safety margin. - */ -#ifndef Py_HASH_CUTOFF -# define Py_HASH_CUTOFF 0 -#elif (Py_HASH_CUTOFF > 7 || Py_HASH_CUTOFF < 0) -# error Py_HASH_CUTOFF must in range 0...7. -#endif /* Py_HASH_CUTOFF */ - - -/* hash algorithm selection - * - * The values for Py_HASH_SIPHASH24 and Py_HASH_FNV are hard-coded in the - * configure script. - * - * - FNV is available on all platforms and architectures. - * - SIPHASH24 only works on platforms that don't require aligned memory for integers. - * - With EXTERNAL embedders can provide an alternative implementation with:: - * - * PyHash_FuncDef PyHash_Func = {...}; - * - * XXX: Figure out __declspec() for extern PyHash_FuncDef. - */ -#define Py_HASH_EXTERNAL 0 -#define Py_HASH_SIPHASH24 1 -#define Py_HASH_FNV 2 - -#ifndef Py_HASH_ALGORITHM -# ifndef HAVE_ALIGNED_REQUIRED -# define Py_HASH_ALGORITHM Py_HASH_SIPHASH24 -# else -# define Py_HASH_ALGORITHM Py_HASH_FNV -# endif /* uint64_t && uint32_t && aligned */ -#endif /* Py_HASH_ALGORITHM */ - -#ifdef __cplusplus -} -#endif - -#endif /* !Py_HASH_H */ diff --git a/scripts/build-windows/py39-libs/include/pylifecycle.h b/scripts/build-windows/py39-libs/include/pylifecycle.h deleted file mode 100644 index 2084b26b7..000000000 --- a/scripts/build-windows/py39-libs/include/pylifecycle.h +++ /dev/null @@ -1,77 +0,0 @@ - -/* Interfaces to configure, query, create & destroy the Python runtime */ - -#ifndef Py_PYLIFECYCLE_H -#define Py_PYLIFECYCLE_H -#ifdef __cplusplus -extern "C" { -#endif - - -/* Initialization and finalization */ -PyAPI_FUNC(void) Py_Initialize(void); -PyAPI_FUNC(void) Py_InitializeEx(int); -PyAPI_FUNC(void) Py_Finalize(void); -#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03060000 -PyAPI_FUNC(int) Py_FinalizeEx(void); -#endif -PyAPI_FUNC(int) Py_IsInitialized(void); - -/* Subinterpreter support */ -PyAPI_FUNC(PyThreadState *) Py_NewInterpreter(void); -PyAPI_FUNC(void) Py_EndInterpreter(PyThreadState *); - - -/* Py_PyAtExit is for the atexit module, Py_AtExit is for low-level - * exit functions. - */ -PyAPI_FUNC(int) Py_AtExit(void (*func)(void)); - -PyAPI_FUNC(void) _Py_NO_RETURN Py_Exit(int); - -/* Bootstrap __main__ (defined in Modules/main.c) */ -PyAPI_FUNC(int) Py_Main(int argc, wchar_t **argv); - -PyAPI_FUNC(int) Py_FrozenMain(int argc, char **argv); - -PyAPI_FUNC(int) Py_BytesMain(int argc, char **argv); - -/* In pathconfig.c */ -PyAPI_FUNC(void) Py_SetProgramName(const wchar_t *); -PyAPI_FUNC(wchar_t *) Py_GetProgramName(void); - -PyAPI_FUNC(void) Py_SetPythonHome(const wchar_t *); -PyAPI_FUNC(wchar_t *) Py_GetPythonHome(void); - -PyAPI_FUNC(wchar_t *) Py_GetProgramFullPath(void); - -PyAPI_FUNC(wchar_t *) Py_GetPrefix(void); -PyAPI_FUNC(wchar_t *) Py_GetExecPrefix(void); -PyAPI_FUNC(wchar_t *) Py_GetPath(void); -PyAPI_FUNC(void) Py_SetPath(const wchar_t *); -#ifdef MS_WINDOWS -int _Py_CheckPython3(void); -#endif - -/* In their own files */ -PyAPI_FUNC(const char *) Py_GetVersion(void); -PyAPI_FUNC(const char *) Py_GetPlatform(void); -PyAPI_FUNC(const char *) Py_GetCopyright(void); -PyAPI_FUNC(const char *) Py_GetCompiler(void); -PyAPI_FUNC(const char *) Py_GetBuildInfo(void); - -/* Signals */ -typedef void (*PyOS_sighandler_t)(int); -PyAPI_FUNC(PyOS_sighandler_t) PyOS_getsig(int); -PyAPI_FUNC(PyOS_sighandler_t) PyOS_setsig(int, PyOS_sighandler_t); - -#ifndef Py_LIMITED_API -# define Py_CPYTHON_PYLIFECYCLE_H -# include "cpython/pylifecycle.h" -# undef Py_CPYTHON_PYLIFECYCLE_H -#endif - -#ifdef __cplusplus -} -#endif -#endif /* !Py_PYLIFECYCLE_H */ diff --git a/scripts/build-windows/py39-libs/include/pymacconfig.h b/scripts/build-windows/py39-libs/include/pymacconfig.h deleted file mode 100644 index a1eccea4a..000000000 --- a/scripts/build-windows/py39-libs/include/pymacconfig.h +++ /dev/null @@ -1,102 +0,0 @@ -#ifndef PYMACCONFIG_H -#define PYMACCONFIG_H - /* - * This file moves some of the autoconf magic to compile-time - * when building on MacOSX. This is needed for building 4-way - * universal binaries and for 64-bit universal binaries because - * the values redefined below aren't configure-time constant but - * only compile-time constant in these scenarios. - */ - -#if defined(__APPLE__) - -# undef SIZEOF_LONG -# undef SIZEOF_PTHREAD_T -# undef SIZEOF_SIZE_T -# undef SIZEOF_TIME_T -# undef SIZEOF_VOID_P -# undef SIZEOF__BOOL -# undef SIZEOF_UINTPTR_T -# undef SIZEOF_PTHREAD_T -# undef WORDS_BIGENDIAN -# undef DOUBLE_IS_ARM_MIXED_ENDIAN_IEEE754 -# undef DOUBLE_IS_BIG_ENDIAN_IEEE754 -# undef DOUBLE_IS_LITTLE_ENDIAN_IEEE754 -# undef HAVE_GCC_ASM_FOR_X87 - -# undef VA_LIST_IS_ARRAY -# if defined(__LP64__) && defined(__x86_64__) -# define VA_LIST_IS_ARRAY 1 -# endif - -# undef HAVE_LARGEFILE_SUPPORT -# ifndef __LP64__ -# define HAVE_LARGEFILE_SUPPORT 1 -# endif - -# undef SIZEOF_LONG -# ifdef __LP64__ -# define SIZEOF__BOOL 1 -# define SIZEOF__BOOL 1 -# define SIZEOF_LONG 8 -# define SIZEOF_PTHREAD_T 8 -# define SIZEOF_SIZE_T 8 -# define SIZEOF_TIME_T 8 -# define SIZEOF_VOID_P 8 -# define SIZEOF_UINTPTR_T 8 -# define SIZEOF_PTHREAD_T 8 -# else -# ifdef __ppc__ -# define SIZEOF__BOOL 4 -# else -# define SIZEOF__BOOL 1 -# endif -# define SIZEOF_LONG 4 -# define SIZEOF_PTHREAD_T 4 -# define SIZEOF_SIZE_T 4 -# define SIZEOF_TIME_T 4 -# define SIZEOF_VOID_P 4 -# define SIZEOF_UINTPTR_T 4 -# define SIZEOF_PTHREAD_T 4 -# endif - -# if defined(__LP64__) - /* MacOSX 10.4 (the first release to support 64-bit code - * at all) only supports 64-bit in the UNIX layer. - * Therefore suppress the toolbox-glue in 64-bit mode. - */ - - /* In 64-bit mode setpgrp always has no arguments, in 32-bit - * mode that depends on the compilation environment - */ -# undef SETPGRP_HAVE_ARG - -# endif - -#ifdef __BIG_ENDIAN__ -#define WORDS_BIGENDIAN 1 -#define DOUBLE_IS_BIG_ENDIAN_IEEE754 -#else -#define DOUBLE_IS_LITTLE_ENDIAN_IEEE754 -#endif /* __BIG_ENDIAN */ - -#ifdef __i386__ -# define HAVE_GCC_ASM_FOR_X87 -#endif - - /* - * The definition in pyconfig.h is only valid on the OS release - * where configure ran on and not necessarily for all systems where - * the executable can be used on. - * - * Specifically: OSX 10.4 has limited supported for '%zd', while - * 10.5 has full support for '%zd'. A binary built on 10.5 won't - * work properly on 10.4 unless we suppress the definition - * of PY_FORMAT_SIZE_T - */ -#undef PY_FORMAT_SIZE_T - - -#endif /* defined(_APPLE__) */ - -#endif /* PYMACCONFIG_H */ diff --git a/scripts/build-windows/py39-libs/include/pymacro.h b/scripts/build-windows/py39-libs/include/pymacro.h deleted file mode 100644 index 7bfee70e1..000000000 --- a/scripts/build-windows/py39-libs/include/pymacro.h +++ /dev/null @@ -1,132 +0,0 @@ -#ifndef Py_PYMACRO_H -#define Py_PYMACRO_H - -/* Minimum value between x and y */ -#define Py_MIN(x, y) (((x) > (y)) ? (y) : (x)) - -/* Maximum value between x and y */ -#define Py_MAX(x, y) (((x) > (y)) ? (x) : (y)) - -/* Absolute value of the number x */ -#define Py_ABS(x) ((x) < 0 ? -(x) : (x)) - -#define _Py_XSTRINGIFY(x) #x - -/* Convert the argument to a string. For example, Py_STRINGIFY(123) is replaced - with "123" by the preprocessor. Defines are also replaced by their value. - For example Py_STRINGIFY(__LINE__) is replaced by the line number, not - by "__LINE__". */ -#define Py_STRINGIFY(x) _Py_XSTRINGIFY(x) - -/* Get the size of a structure member in bytes */ -#define Py_MEMBER_SIZE(type, member) sizeof(((type *)0)->member) - -/* Argument must be a char or an int in [-128, 127] or [0, 255]. */ -#define Py_CHARMASK(c) ((unsigned char)((c) & 0xff)) - -/* Assert a build-time dependency, as an expression. - - Your compile will fail if the condition isn't true, or can't be evaluated - by the compiler. This can be used in an expression: its value is 0. - - Example: - - #define foo_to_char(foo) \ - ((char *)(foo) \ - + Py_BUILD_ASSERT_EXPR(offsetof(struct foo, string) == 0)) - - Written by Rusty Russell, public domain, http://ccodearchive.net/ */ -#define Py_BUILD_ASSERT_EXPR(cond) \ - (sizeof(char [1 - 2*!(cond)]) - 1) - -#define Py_BUILD_ASSERT(cond) do { \ - (void)Py_BUILD_ASSERT_EXPR(cond); \ - } while(0) - -/* Get the number of elements in a visible array - - This does not work on pointers, or arrays declared as [], or function - parameters. With correct compiler support, such usage will cause a build - error (see Py_BUILD_ASSERT_EXPR). - - Written by Rusty Russell, public domain, http://ccodearchive.net/ - - Requires at GCC 3.1+ */ -#if (defined(__GNUC__) && !defined(__STRICT_ANSI__) && \ - (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 1)) || (__GNUC__ >= 4))) -/* Two gcc extensions. - &a[0] degrades to a pointer: a different type from an array */ -#define Py_ARRAY_LENGTH(array) \ - (sizeof(array) / sizeof((array)[0]) \ - + Py_BUILD_ASSERT_EXPR(!__builtin_types_compatible_p(typeof(array), \ - typeof(&(array)[0])))) -#else -#define Py_ARRAY_LENGTH(array) \ - (sizeof(array) / sizeof((array)[0])) -#endif - - -/* Define macros for inline documentation. */ -#define PyDoc_VAR(name) static const char name[] -#define PyDoc_STRVAR(name,str) PyDoc_VAR(name) = PyDoc_STR(str) -#ifdef WITH_DOC_STRINGS -#define PyDoc_STR(str) str -#else -#define PyDoc_STR(str) "" -#endif - -/* Below "a" is a power of 2. */ -/* Round down size "n" to be a multiple of "a". */ -#define _Py_SIZE_ROUND_DOWN(n, a) ((size_t)(n) & ~(size_t)((a) - 1)) -/* Round up size "n" to be a multiple of "a". */ -#define _Py_SIZE_ROUND_UP(n, a) (((size_t)(n) + \ - (size_t)((a) - 1)) & ~(size_t)((a) - 1)) -/* Round pointer "p" down to the closest "a"-aligned address <= "p". */ -#define _Py_ALIGN_DOWN(p, a) ((void *)((uintptr_t)(p) & ~(uintptr_t)((a) - 1))) -/* Round pointer "p" up to the closest "a"-aligned address >= "p". */ -#define _Py_ALIGN_UP(p, a) ((void *)(((uintptr_t)(p) + \ - (uintptr_t)((a) - 1)) & ~(uintptr_t)((a) - 1))) -/* Check if pointer "p" is aligned to "a"-bytes boundary. */ -#define _Py_IS_ALIGNED(p, a) (!((uintptr_t)(p) & (uintptr_t)((a) - 1))) - -/* Use this for unused arguments in a function definition to silence compiler - * warnings. Example: - * - * int func(int a, int Py_UNUSED(b)) { return a; } - */ -#if defined(__GNUC__) || defined(__clang__) -# define Py_UNUSED(name) _unused_ ## name __attribute__((unused)) -#else -# define Py_UNUSED(name) _unused_ ## name -#endif - -#if defined(RANDALL_WAS_HERE) -# define Py_UNREACHABLE() \ - Py_FatalError( \ - "If you're seeing this, the code is in what I thought was\n" \ - "an unreachable state.\n\n" \ - "I could give you advice for what to do, but honestly, why\n" \ - "should you trust me? I clearly screwed this up. I'm writing\n" \ - "a message that should never appear, yet I know it will\n" \ - "probably appear someday.\n\n" \ - "On a deep level, I know I'm not up to this task.\n" \ - "I'm so sorry.\n" \ - "https://xkcd.com/2200") -#elif defined(Py_DEBUG) -# define Py_UNREACHABLE() \ - Py_FatalError( \ - "We've reached an unreachable state. Anything is possible.\n" \ - "The limits were in our heads all along. Follow your dreams.\n" \ - "https://xkcd.com/2200") -#elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)) -# define Py_UNREACHABLE() __builtin_unreachable() -#elif defined(__clang__) || defined(__INTEL_COMPILER) -# define Py_UNREACHABLE() __builtin_unreachable() -#elif defined(_MSC_VER) -# define Py_UNREACHABLE() __assume(0) -#else -# define Py_UNREACHABLE() \ - Py_FatalError("Unreachable C code path reached") -#endif - -#endif /* Py_PYMACRO_H */ diff --git a/scripts/build-windows/py39-libs/include/pymath.h b/scripts/build-windows/py39-libs/include/pymath.h deleted file mode 100644 index 4d305990e..000000000 --- a/scripts/build-windows/py39-libs/include/pymath.h +++ /dev/null @@ -1,238 +0,0 @@ -#ifndef Py_PYMATH_H -#define Py_PYMATH_H - -#include "pyconfig.h" /* include for defines */ - -/************************************************************************** -Symbols and macros to supply platform-independent interfaces to mathematical -functions and constants -**************************************************************************/ - -/* Python provides implementations for copysign, round and hypot in - * Python/pymath.c just in case your math library doesn't provide the - * functions. - * - *Note: PC/pyconfig.h defines copysign as _copysign - */ -#ifndef HAVE_COPYSIGN -extern double copysign(double, double); -#endif - -#ifndef HAVE_ROUND -extern double round(double); -#endif - -#ifndef HAVE_HYPOT -extern double hypot(double, double); -#endif - -/* extra declarations */ -#ifndef _MSC_VER -#ifndef __STDC__ -extern double fmod (double, double); -extern double frexp (double, int *); -extern double ldexp (double, int); -extern double modf (double, double *); -extern double pow(double, double); -#endif /* __STDC__ */ -#endif /* _MSC_VER */ - -/* High precision definition of pi and e (Euler) - * The values are taken from libc6's math.h. - */ -#ifndef Py_MATH_PIl -#define Py_MATH_PIl 3.1415926535897932384626433832795029L -#endif -#ifndef Py_MATH_PI -#define Py_MATH_PI 3.14159265358979323846 -#endif - -#ifndef Py_MATH_El -#define Py_MATH_El 2.7182818284590452353602874713526625L -#endif - -#ifndef Py_MATH_E -#define Py_MATH_E 2.7182818284590452354 -#endif - -/* Tau (2pi) to 40 digits, taken from tauday.com/tau-digits. */ -#ifndef Py_MATH_TAU -#define Py_MATH_TAU 6.2831853071795864769252867665590057683943L -#endif - - -/* On x86, Py_FORCE_DOUBLE forces a floating-point number out of an x87 FPU - register and into a 64-bit memory location, rounding from extended - precision to double precision in the process. On other platforms it does - nothing. */ - -/* we take double rounding as evidence of x87 usage */ -#ifndef Py_LIMITED_API -#ifndef Py_FORCE_DOUBLE -# ifdef X87_DOUBLE_ROUNDING -PyAPI_FUNC(double) _Py_force_double(double); -# define Py_FORCE_DOUBLE(X) (_Py_force_double(X)) -# else -# define Py_FORCE_DOUBLE(X) (X) -# endif -#endif -#endif - -#ifndef Py_LIMITED_API -#ifdef HAVE_GCC_ASM_FOR_X87 -PyAPI_FUNC(unsigned short) _Py_get_387controlword(void); -PyAPI_FUNC(void) _Py_set_387controlword(unsigned short); -#endif -#endif - -/* Py_IS_NAN(X) - * Return 1 if float or double arg is a NaN, else 0. - * Caution: - * X is evaluated more than once. - * This may not work on all platforms. Each platform has *some* - * way to spell this, though -- override in pyconfig.h if you have - * a platform where it doesn't work. - * Note: PC/pyconfig.h defines Py_IS_NAN as _isnan - */ -#ifndef Py_IS_NAN -#if defined HAVE_DECL_ISNAN && HAVE_DECL_ISNAN == 1 -#define Py_IS_NAN(X) isnan(X) -#else -#define Py_IS_NAN(X) ((X) != (X)) -#endif -#endif - -/* Py_IS_INFINITY(X) - * Return 1 if float or double arg is an infinity, else 0. - * Caution: - * X is evaluated more than once. - * This implementation may set the underflow flag if |X| is very small; - * it really can't be implemented correctly (& easily) before C99. - * Override in pyconfig.h if you have a better spelling on your platform. - * Py_FORCE_DOUBLE is used to avoid getting false negatives from a - * non-infinite value v sitting in an 80-bit x87 register such that - * v becomes infinite when spilled from the register to 64-bit memory. - * Note: PC/pyconfig.h defines Py_IS_INFINITY as _isinf - */ -#ifndef Py_IS_INFINITY -# if defined HAVE_DECL_ISINF && HAVE_DECL_ISINF == 1 -# define Py_IS_INFINITY(X) isinf(X) -# else -# define Py_IS_INFINITY(X) ((X) && \ - (Py_FORCE_DOUBLE(X)*0.5 == Py_FORCE_DOUBLE(X))) -# endif -#endif - -/* Py_IS_FINITE(X) - * Return 1 if float or double arg is neither infinite nor NAN, else 0. - * Some compilers (e.g. VisualStudio) have intrinsics for this, so a special - * macro for this particular test is useful - * Note: PC/pyconfig.h defines Py_IS_FINITE as _finite - */ -#ifndef Py_IS_FINITE -#if defined HAVE_DECL_ISFINITE && HAVE_DECL_ISFINITE == 1 -#define Py_IS_FINITE(X) isfinite(X) -#elif defined HAVE_FINITE -#define Py_IS_FINITE(X) finite(X) -#else -#define Py_IS_FINITE(X) (!Py_IS_INFINITY(X) && !Py_IS_NAN(X)) -#endif -#endif - -/* HUGE_VAL is supposed to expand to a positive double infinity. Python - * uses Py_HUGE_VAL instead because some platforms are broken in this - * respect. We used to embed code in pyport.h to try to worm around that, - * but different platforms are broken in conflicting ways. If you're on - * a platform where HUGE_VAL is defined incorrectly, fiddle your Python - * config to #define Py_HUGE_VAL to something that works on your platform. - */ -#ifndef Py_HUGE_VAL -#define Py_HUGE_VAL HUGE_VAL -#endif - -/* Py_NAN - * A value that evaluates to a NaN. On IEEE 754 platforms INF*0 or - * INF/INF works. Define Py_NO_NAN in pyconfig.h if your platform - * doesn't support NaNs. - */ -#if !defined(Py_NAN) && !defined(Py_NO_NAN) -#if !defined(__INTEL_COMPILER) - #define Py_NAN (Py_HUGE_VAL * 0.) -#else /* __INTEL_COMPILER */ - #if defined(ICC_NAN_STRICT) - #pragma float_control(push) - #pragma float_control(precise, on) - #pragma float_control(except, on) - #if defined(_MSC_VER) - __declspec(noinline) - #else /* Linux */ - __attribute__((noinline)) - #endif /* _MSC_VER */ - static double __icc_nan() - { - return sqrt(-1.0); - } - #pragma float_control (pop) - #define Py_NAN __icc_nan() - #else /* ICC_NAN_RELAXED as default for Intel Compiler */ - static const union { unsigned char buf[8]; double __icc_nan; } __nan_store = {0,0,0,0,0,0,0xf8,0x7f}; - #define Py_NAN (__nan_store.__icc_nan) - #endif /* ICC_NAN_STRICT */ -#endif /* __INTEL_COMPILER */ -#endif - -/* Py_OVERFLOWED(X) - * Return 1 iff a libm function overflowed. Set errno to 0 before calling - * a libm function, and invoke this macro after, passing the function - * result. - * Caution: - * This isn't reliable. C99 no longer requires libm to set errno under - * any exceptional condition, but does require +- HUGE_VAL return - * values on overflow. A 754 box *probably* maps HUGE_VAL to a - * double infinity, and we're cool if that's so, unless the input - * was an infinity and an infinity is the expected result. A C89 - * system sets errno to ERANGE, so we check for that too. We're - * out of luck if a C99 754 box doesn't map HUGE_VAL to +Inf, or - * if the returned result is a NaN, or if a C89 box returns HUGE_VAL - * in non-overflow cases. - * X is evaluated more than once. - * Some platforms have better way to spell this, so expect some #ifdef'ery. - * - * OpenBSD uses 'isinf()' because a compiler bug on that platform causes - * the longer macro version to be mis-compiled. This isn't optimal, and - * should be removed once a newer compiler is available on that platform. - * The system that had the failure was running OpenBSD 3.2 on Intel, with - * gcc 2.95.3. - * - * According to Tim's checkin, the FreeBSD systems use isinf() to work - * around a FPE bug on that platform. - */ -#if defined(__FreeBSD__) || defined(__OpenBSD__) -#define Py_OVERFLOWED(X) isinf(X) -#else -#define Py_OVERFLOWED(X) ((X) != 0.0 && (errno == ERANGE || \ - (X) == Py_HUGE_VAL || \ - (X) == -Py_HUGE_VAL)) -#endif - -/* Return whether integral type *type* is signed or not. */ -#define _Py_IntegralTypeSigned(type) ((type)(-1) < 0) -/* Return the maximum value of integral type *type*. */ -#define _Py_IntegralTypeMax(type) ((_Py_IntegralTypeSigned(type)) ? (((((type)1 << (sizeof(type)*CHAR_BIT - 2)) - 1) << 1) + 1) : ~(type)0) -/* Return the minimum value of integral type *type*. */ -#define _Py_IntegralTypeMin(type) ((_Py_IntegralTypeSigned(type)) ? -_Py_IntegralTypeMax(type) - 1 : 0) -/* Check whether *v* is in the range of integral type *type*. This is most - * useful if *v* is floating-point, since demoting a floating-point *v* to an - * integral type that cannot represent *v*'s integral part is undefined - * behavior. */ -#define _Py_InIntegralTypeRange(type, v) (_Py_IntegralTypeMin(type) <= v && v <= _Py_IntegralTypeMax(type)) - -/* Return the smallest integer k such that n < 2**k, or 0 if n == 0. - * Equivalent to floor(log2(x))+1. Also equivalent to: bitwidth_of_type - - * count_leading_zero_bits(x) - */ -#ifndef Py_LIMITED_API -PyAPI_FUNC(unsigned int) _Py_bit_length(unsigned long d); -#endif - -#endif /* Py_PYMATH_H */ diff --git a/scripts/build-windows/py39-libs/include/pymem.h b/scripts/build-windows/py39-libs/include/pymem.h deleted file mode 100644 index a2c8c2557..000000000 --- a/scripts/build-windows/py39-libs/include/pymem.h +++ /dev/null @@ -1,115 +0,0 @@ -/* The PyMem_ family: low-level memory allocation interfaces. - See objimpl.h for the PyObject_ memory family. -*/ - -#ifndef Py_PYMEM_H -#define Py_PYMEM_H - -#include "pyport.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/* BEWARE: - - Each interface exports both functions and macros. Extension modules should - use the functions, to ensure binary compatibility across Python versions. - Because the Python implementation is free to change internal details, and - the macros may (or may not) expose details for speed, if you do use the - macros you must recompile your extensions with each Python release. - - Never mix calls to PyMem_ with calls to the platform malloc/realloc/ - calloc/free. For example, on Windows different DLLs may end up using - different heaps, and if you use PyMem_Malloc you'll get the memory from the - heap used by the Python DLL; it could be a disaster if you free()'ed that - directly in your own extension. Using PyMem_Free instead ensures Python - can return the memory to the proper heap. As another example, in - PYMALLOC_DEBUG mode, Python wraps all calls to all PyMem_ and PyObject_ - memory functions in special debugging wrappers that add additional - debugging info to dynamic memory blocks. The system routines have no idea - what to do with that stuff, and the Python wrappers have no idea what to do - with raw blocks obtained directly by the system routines then. - - The GIL must be held when using these APIs. -*/ - -/* - * Raw memory interface - * ==================== - */ - -/* Functions - - Functions supplying platform-independent semantics for malloc/realloc/ - free. These functions make sure that allocating 0 bytes returns a distinct - non-NULL pointer (whenever possible -- if we're flat out of memory, NULL - may be returned), even if the platform malloc and realloc don't. - Returned pointers must be checked for NULL explicitly. No action is - performed on failure (no exception is set, no warning is printed, etc). -*/ - -PyAPI_FUNC(void *) PyMem_Malloc(size_t size); -PyAPI_FUNC(void *) PyMem_Realloc(void *ptr, size_t new_size); -PyAPI_FUNC(void) PyMem_Free(void *ptr); - -/* Macros. */ - -/* PyMem_MALLOC(0) means malloc(1). Some systems would return NULL - for malloc(0), which would be treated as an error. Some platforms - would return a pointer with no memory behind it, which would break - pymalloc. To solve these problems, allocate an extra byte. */ -/* Returns NULL to indicate error if a negative size or size larger than - Py_ssize_t can represent is supplied. Helps prevents security holes. */ -#define PyMem_MALLOC(n) PyMem_Malloc(n) -#define PyMem_REALLOC(p, n) PyMem_Realloc(p, n) -#define PyMem_FREE(p) PyMem_Free(p) - -/* - * Type-oriented memory interface - * ============================== - * - * Allocate memory for n objects of the given type. Returns a new pointer - * or NULL if the request was too large or memory allocation failed. Use - * these macros rather than doing the multiplication yourself so that proper - * overflow checking is always done. - */ - -#define PyMem_New(type, n) \ - ( ((size_t)(n) > PY_SSIZE_T_MAX / sizeof(type)) ? NULL : \ - ( (type *) PyMem_Malloc((n) * sizeof(type)) ) ) -#define PyMem_NEW(type, n) \ - ( ((size_t)(n) > PY_SSIZE_T_MAX / sizeof(type)) ? NULL : \ - ( (type *) PyMem_MALLOC((n) * sizeof(type)) ) ) - -/* - * The value of (p) is always clobbered by this macro regardless of success. - * The caller MUST check if (p) is NULL afterwards and deal with the memory - * error if so. This means the original value of (p) MUST be saved for the - * caller's memory error handler to not lose track of it. - */ -#define PyMem_Resize(p, type, n) \ - ( (p) = ((size_t)(n) > PY_SSIZE_T_MAX / sizeof(type)) ? NULL : \ - (type *) PyMem_Realloc((p), (n) * sizeof(type)) ) -#define PyMem_RESIZE(p, type, n) \ - ( (p) = ((size_t)(n) > PY_SSIZE_T_MAX / sizeof(type)) ? NULL : \ - (type *) PyMem_REALLOC((p), (n) * sizeof(type)) ) - -/* PyMem{Del,DEL} are left over from ancient days, and shouldn't be used - * anymore. They're just confusing aliases for PyMem_{Free,FREE} now. - */ -#define PyMem_Del PyMem_Free -#define PyMem_DEL PyMem_FREE - - -#ifndef Py_LIMITED_API -# define Py_CPYTHON_PYMEM_H -# include "cpython/pymem.h" -# undef Py_CPYTHON_PYMEM_H -#endif - -#ifdef __cplusplus -} -#endif - -#endif /* !Py_PYMEM_H */ diff --git a/scripts/build-windows/py39-libs/include/pyport.h b/scripts/build-windows/py39-libs/include/pyport.h deleted file mode 100644 index 49a67d900..000000000 --- a/scripts/build-windows/py39-libs/include/pyport.h +++ /dev/null @@ -1,878 +0,0 @@ -#ifndef Py_PYPORT_H -#define Py_PYPORT_H - -#include "pyconfig.h" /* include for defines */ - -#include - - -/* Defines to build Python and its standard library: - * - * - Py_BUILD_CORE: Build Python core. Give access to Python internals, but - * should not be used by third-party modules. - * - Py_BUILD_CORE_BUILTIN: Build a Python stdlib module as a built-in module. - * - Py_BUILD_CORE_MODULE: Build a Python stdlib module as a dynamic library. - * - * Py_BUILD_CORE_BUILTIN and Py_BUILD_CORE_MODULE imply Py_BUILD_CORE. - * - * On Windows, Py_BUILD_CORE_MODULE exports "PyInit_xxx" symbol, whereas - * Py_BUILD_CORE_BUILTIN does not. - */ -#if defined(Py_BUILD_CORE_BUILTIN) && !defined(Py_BUILD_CORE) -# define Py_BUILD_CORE -#endif -#if defined(Py_BUILD_CORE_MODULE) && !defined(Py_BUILD_CORE) -# define Py_BUILD_CORE -#endif - - -/************************************************************************** -Symbols and macros to supply platform-independent interfaces to basic -C language & library operations whose spellings vary across platforms. - -Please try to make documentation here as clear as possible: by definition, -the stuff here is trying to illuminate C's darkest corners. - -Config #defines referenced here: - -SIGNED_RIGHT_SHIFT_ZERO_FILLS -Meaning: To be defined iff i>>j does not extend the sign bit when i is a - signed integral type and i < 0. -Used in: Py_ARITHMETIC_RIGHT_SHIFT - -Py_DEBUG -Meaning: Extra checks compiled in for debug mode. -Used in: Py_SAFE_DOWNCAST - -**************************************************************************/ - -/* typedefs for some C9X-defined synonyms for integral types. - * - * The names in Python are exactly the same as the C9X names, except with a - * Py_ prefix. Until C9X is universally implemented, this is the only way - * to ensure that Python gets reliable names that don't conflict with names - * in non-Python code that are playing their own tricks to define the C9X - * names. - * - * NOTE: don't go nuts here! Python has no use for *most* of the C9X - * integral synonyms. Only define the ones we actually need. - */ - -/* long long is required. Ensure HAVE_LONG_LONG is defined for compatibility. */ -#ifndef HAVE_LONG_LONG -#define HAVE_LONG_LONG 1 -#endif -#ifndef PY_LONG_LONG -#define PY_LONG_LONG long long -/* If LLONG_MAX is defined in limits.h, use that. */ -#define PY_LLONG_MIN LLONG_MIN -#define PY_LLONG_MAX LLONG_MAX -#define PY_ULLONG_MAX ULLONG_MAX -#endif - -#define PY_UINT32_T uint32_t -#define PY_UINT64_T uint64_t - -/* Signed variants of the above */ -#define PY_INT32_T int32_t -#define PY_INT64_T int64_t - -/* If PYLONG_BITS_IN_DIGIT is not defined then we'll use 30-bit digits if all - the necessary integer types are available, and we're on a 64-bit platform - (as determined by SIZEOF_VOID_P); otherwise we use 15-bit digits. */ - -#ifndef PYLONG_BITS_IN_DIGIT -#if SIZEOF_VOID_P >= 8 -#define PYLONG_BITS_IN_DIGIT 30 -#else -#define PYLONG_BITS_IN_DIGIT 15 -#endif -#endif - -/* uintptr_t is the C9X name for an unsigned integral type such that a - * legitimate void* can be cast to uintptr_t and then back to void* again - * without loss of information. Similarly for intptr_t, wrt a signed - * integral type. - */ -typedef uintptr_t Py_uintptr_t; -typedef intptr_t Py_intptr_t; - -/* Py_ssize_t is a signed integral type such that sizeof(Py_ssize_t) == - * sizeof(size_t). C99 doesn't define such a thing directly (size_t is an - * unsigned integral type). See PEP 353 for details. - */ -#ifdef HAVE_SSIZE_T -typedef ssize_t Py_ssize_t; -#elif SIZEOF_VOID_P == SIZEOF_SIZE_T -typedef Py_intptr_t Py_ssize_t; -#else -# error "Python needs a typedef for Py_ssize_t in pyport.h." -#endif - -/* Py_hash_t is the same size as a pointer. */ -#define SIZEOF_PY_HASH_T SIZEOF_SIZE_T -typedef Py_ssize_t Py_hash_t; -/* Py_uhash_t is the unsigned equivalent needed to calculate numeric hash. */ -#define SIZEOF_PY_UHASH_T SIZEOF_SIZE_T -typedef size_t Py_uhash_t; - -/* Only used for compatibility with code that may not be PY_SSIZE_T_CLEAN. */ -#ifdef PY_SSIZE_T_CLEAN -typedef Py_ssize_t Py_ssize_clean_t; -#else -typedef int Py_ssize_clean_t; -#endif - -/* Largest possible value of size_t. */ -#define PY_SIZE_MAX SIZE_MAX - -/* Largest positive value of type Py_ssize_t. */ -#define PY_SSIZE_T_MAX ((Py_ssize_t)(((size_t)-1)>>1)) -/* Smallest negative value of type Py_ssize_t. */ -#define PY_SSIZE_T_MIN (-PY_SSIZE_T_MAX-1) - -/* PY_FORMAT_SIZE_T is a platform-specific modifier for use in a printf - * format to convert an argument with the width of a size_t or Py_ssize_t. - * C99 introduced "z" for this purpose, but old MSVCs had not supported it. - * Since MSVC supports "z" since (at least) 2015, we can just use "z" - * for new code. - * - * These "high level" Python format functions interpret "z" correctly on - * all platforms (Python interprets the format string itself, and does whatever - * the platform C requires to convert a size_t/Py_ssize_t argument): - * - * PyBytes_FromFormat - * PyErr_Format - * PyBytes_FromFormatV - * PyUnicode_FromFormatV - * - * Lower-level uses require that you interpolate the correct format modifier - * yourself (e.g., calling printf, fprintf, sprintf, PyOS_snprintf); for - * example, - * - * Py_ssize_t index; - * fprintf(stderr, "index %" PY_FORMAT_SIZE_T "d sucks\n", index); - * - * That will expand to %zd or to something else correct for a Py_ssize_t on - * the platform. - */ -#ifndef PY_FORMAT_SIZE_T -# define PY_FORMAT_SIZE_T "z" -#endif - -/* Py_LOCAL can be used instead of static to get the fastest possible calling - * convention for functions that are local to a given module. - * - * Py_LOCAL_INLINE does the same thing, and also explicitly requests inlining, - * for platforms that support that. - * - * If PY_LOCAL_AGGRESSIVE is defined before python.h is included, more - * "aggressive" inlining/optimization is enabled for the entire module. This - * may lead to code bloat, and may slow things down for those reasons. It may - * also lead to errors, if the code relies on pointer aliasing. Use with - * care. - * - * NOTE: You can only use this for functions that are entirely local to a - * module; functions that are exported via method tables, callbacks, etc, - * should keep using static. - */ - -#if defined(_MSC_VER) -# if defined(PY_LOCAL_AGGRESSIVE) - /* enable more aggressive optimization for visual studio */ -# pragma optimize("agtw", on) -#endif - /* ignore warnings if the compiler decides not to inline a function */ -# pragma warning(disable: 4710) - /* fastest possible local call under MSVC */ -# define Py_LOCAL(type) static type __fastcall -# define Py_LOCAL_INLINE(type) static __inline type __fastcall -#else -# define Py_LOCAL(type) static type -# define Py_LOCAL_INLINE(type) static inline type -#endif - -/* Py_MEMCPY is kept for backwards compatibility, - * see https://bugs.python.org/issue28126 */ -#define Py_MEMCPY memcpy - -#include - -#ifdef HAVE_IEEEFP_H -#include /* needed for 'finite' declaration on some platforms */ -#endif - -#include /* Moved here from the math section, before extern "C" */ - -/******************************************** - * WRAPPER FOR and/or * - ********************************************/ - -#ifdef TIME_WITH_SYS_TIME -#include -#include -#else /* !TIME_WITH_SYS_TIME */ -#ifdef HAVE_SYS_TIME_H -#include -#else /* !HAVE_SYS_TIME_H */ -#include -#endif /* !HAVE_SYS_TIME_H */ -#endif /* !TIME_WITH_SYS_TIME */ - - -/****************************** - * WRAPPER FOR * - ******************************/ - -/* NB caller must include */ - -#ifdef HAVE_SYS_SELECT_H -#include -#endif /* !HAVE_SYS_SELECT_H */ - -/******************************* - * stat() and fstat() fiddling * - *******************************/ - -#ifdef HAVE_SYS_STAT_H -#include -#elif defined(HAVE_STAT_H) -#include -#endif - -#ifndef S_IFMT -/* VisualAge C/C++ Failed to Define MountType Field in sys/stat.h */ -#define S_IFMT 0170000 -#endif - -#ifndef S_IFLNK -/* Windows doesn't define S_IFLNK but posixmodule.c maps - * IO_REPARSE_TAG_SYMLINK to S_IFLNK */ -# define S_IFLNK 0120000 -#endif - -#ifndef S_ISREG -#define S_ISREG(x) (((x) & S_IFMT) == S_IFREG) -#endif - -#ifndef S_ISDIR -#define S_ISDIR(x) (((x) & S_IFMT) == S_IFDIR) -#endif - -#ifndef S_ISCHR -#define S_ISCHR(x) (((x) & S_IFMT) == S_IFCHR) -#endif - -#ifdef __cplusplus -/* Move this down here since some C++ #include's don't like to be included - inside an extern "C" */ -extern "C" { -#endif - - -/* Py_ARITHMETIC_RIGHT_SHIFT - * C doesn't define whether a right-shift of a signed integer sign-extends - * or zero-fills. Here a macro to force sign extension: - * Py_ARITHMETIC_RIGHT_SHIFT(TYPE, I, J) - * Return I >> J, forcing sign extension. Arithmetically, return the - * floor of I/2**J. - * Requirements: - * I should have signed integer type. In the terminology of C99, this can - * be either one of the five standard signed integer types (signed char, - * short, int, long, long long) or an extended signed integer type. - * J is an integer >= 0 and strictly less than the number of bits in the - * type of I (because C doesn't define what happens for J outside that - * range either). - * TYPE used to specify the type of I, but is now ignored. It's been left - * in for backwards compatibility with versions <= 2.6 or 3.0. - * Caution: - * I may be evaluated more than once. - */ -#ifdef SIGNED_RIGHT_SHIFT_ZERO_FILLS -#define Py_ARITHMETIC_RIGHT_SHIFT(TYPE, I, J) \ - ((I) < 0 ? -1-((-1-(I)) >> (J)) : (I) >> (J)) -#else -#define Py_ARITHMETIC_RIGHT_SHIFT(TYPE, I, J) ((I) >> (J)) -#endif - -/* Py_FORCE_EXPANSION(X) - * "Simply" returns its argument. However, macro expansions within the - * argument are evaluated. This unfortunate trickery is needed to get - * token-pasting to work as desired in some cases. - */ -#define Py_FORCE_EXPANSION(X) X - -/* Py_SAFE_DOWNCAST(VALUE, WIDE, NARROW) - * Cast VALUE to type NARROW from type WIDE. In Py_DEBUG mode, this - * assert-fails if any information is lost. - * Caution: - * VALUE may be evaluated more than once. - */ -#ifdef Py_DEBUG -#define Py_SAFE_DOWNCAST(VALUE, WIDE, NARROW) \ - (assert((WIDE)(NARROW)(VALUE) == (VALUE)), (NARROW)(VALUE)) -#else -#define Py_SAFE_DOWNCAST(VALUE, WIDE, NARROW) (NARROW)(VALUE) -#endif - -/* Py_SET_ERRNO_ON_MATH_ERROR(x) - * If a libm function did not set errno, but it looks like the result - * overflowed or not-a-number, set errno to ERANGE or EDOM. Set errno - * to 0 before calling a libm function, and invoke this macro after, - * passing the function result. - * Caution: - * This isn't reliable. See Py_OVERFLOWED comments. - * X is evaluated more than once. - */ -#if defined(__FreeBSD__) || defined(__OpenBSD__) || (defined(__hpux) && defined(__ia64)) -#define _Py_SET_EDOM_FOR_NAN(X) if (isnan(X)) errno = EDOM; -#else -#define _Py_SET_EDOM_FOR_NAN(X) ; -#endif -#define Py_SET_ERRNO_ON_MATH_ERROR(X) \ - do { \ - if (errno == 0) { \ - if ((X) == Py_HUGE_VAL || (X) == -Py_HUGE_VAL) \ - errno = ERANGE; \ - else _Py_SET_EDOM_FOR_NAN(X) \ - } \ - } while(0) - -/* Py_SET_ERANGE_IF_OVERFLOW(x) - * An alias of Py_SET_ERRNO_ON_MATH_ERROR for backward-compatibility. - */ -#define Py_SET_ERANGE_IF_OVERFLOW(X) Py_SET_ERRNO_ON_MATH_ERROR(X) - -/* Py_ADJUST_ERANGE1(x) - * Py_ADJUST_ERANGE2(x, y) - * Set errno to 0 before calling a libm function, and invoke one of these - * macros after, passing the function result(s) (Py_ADJUST_ERANGE2 is useful - * for functions returning complex results). This makes two kinds of - * adjustments to errno: (A) If it looks like the platform libm set - * errno=ERANGE due to underflow, clear errno. (B) If it looks like the - * platform libm overflowed but didn't set errno, force errno to ERANGE. In - * effect, we're trying to force a useful implementation of C89 errno - * behavior. - * Caution: - * This isn't reliable. See Py_OVERFLOWED comments. - * X and Y may be evaluated more than once. - */ -#define Py_ADJUST_ERANGE1(X) \ - do { \ - if (errno == 0) { \ - if ((X) == Py_HUGE_VAL || (X) == -Py_HUGE_VAL) \ - errno = ERANGE; \ - } \ - else if (errno == ERANGE && (X) == 0.0) \ - errno = 0; \ - } while(0) - -#define Py_ADJUST_ERANGE2(X, Y) \ - do { \ - if ((X) == Py_HUGE_VAL || (X) == -Py_HUGE_VAL || \ - (Y) == Py_HUGE_VAL || (Y) == -Py_HUGE_VAL) { \ - if (errno == 0) \ - errno = ERANGE; \ - } \ - else if (errno == ERANGE) \ - errno = 0; \ - } while(0) - -/* The functions _Py_dg_strtod and _Py_dg_dtoa in Python/dtoa.c (which are - * required to support the short float repr introduced in Python 3.1) require - * that the floating-point unit that's being used for arithmetic operations - * on C doubles is set to use 53-bit precision. It also requires that the - * FPU rounding mode is round-half-to-even, but that's less often an issue. - * - * If your FPU isn't already set to 53-bit precision/round-half-to-even, and - * you want to make use of _Py_dg_strtod and _Py_dg_dtoa, then you should - * - * #define HAVE_PY_SET_53BIT_PRECISION 1 - * - * and also give appropriate definitions for the following three macros: - * - * _PY_SET_53BIT_PRECISION_START : store original FPU settings, and - * set FPU to 53-bit precision/round-half-to-even - * _PY_SET_53BIT_PRECISION_END : restore original FPU settings - * _PY_SET_53BIT_PRECISION_HEADER : any variable declarations needed to - * use the two macros above. - * - * The macros are designed to be used within a single C function: see - * Python/pystrtod.c for an example of their use. - */ - -/* get and set x87 control word for gcc/x86 */ -#ifdef HAVE_GCC_ASM_FOR_X87 -#define HAVE_PY_SET_53BIT_PRECISION 1 -/* _Py_get/set_387controlword functions are defined in Python/pymath.c */ -#define _Py_SET_53BIT_PRECISION_HEADER \ - unsigned short old_387controlword, new_387controlword -#define _Py_SET_53BIT_PRECISION_START \ - do { \ - old_387controlword = _Py_get_387controlword(); \ - new_387controlword = (old_387controlword & ~0x0f00) | 0x0200; \ - if (new_387controlword != old_387controlword) \ - _Py_set_387controlword(new_387controlword); \ - } while (0) -#define _Py_SET_53BIT_PRECISION_END \ - if (new_387controlword != old_387controlword) \ - _Py_set_387controlword(old_387controlword) -#endif - -/* get and set x87 control word for VisualStudio/x86 */ -#if defined(_MSC_VER) && !defined(_WIN64) && !defined(_M_ARM) /* x87 not supported in 64-bit or ARM */ -#define HAVE_PY_SET_53BIT_PRECISION 1 -#define _Py_SET_53BIT_PRECISION_HEADER \ - unsigned int old_387controlword, new_387controlword, out_387controlword -/* We use the __control87_2 function to set only the x87 control word. - The SSE control word is unaffected. */ -#define _Py_SET_53BIT_PRECISION_START \ - do { \ - __control87_2(0, 0, &old_387controlword, NULL); \ - new_387controlword = \ - (old_387controlword & ~(_MCW_PC | _MCW_RC)) | (_PC_53 | _RC_NEAR); \ - if (new_387controlword != old_387controlword) \ - __control87_2(new_387controlword, _MCW_PC | _MCW_RC, \ - &out_387controlword, NULL); \ - } while (0) -#define _Py_SET_53BIT_PRECISION_END \ - do { \ - if (new_387controlword != old_387controlword) \ - __control87_2(old_387controlword, _MCW_PC | _MCW_RC, \ - &out_387controlword, NULL); \ - } while (0) -#endif - -#ifdef HAVE_GCC_ASM_FOR_MC68881 -#define HAVE_PY_SET_53BIT_PRECISION 1 -#define _Py_SET_53BIT_PRECISION_HEADER \ - unsigned int old_fpcr, new_fpcr -#define _Py_SET_53BIT_PRECISION_START \ - do { \ - __asm__ ("fmove.l %%fpcr,%0" : "=g" (old_fpcr)); \ - /* Set double precision / round to nearest. */ \ - new_fpcr = (old_fpcr & ~0xf0) | 0x80; \ - if (new_fpcr != old_fpcr) \ - __asm__ volatile ("fmove.l %0,%%fpcr" : : "g" (new_fpcr)); \ - } while (0) -#define _Py_SET_53BIT_PRECISION_END \ - do { \ - if (new_fpcr != old_fpcr) \ - __asm__ volatile ("fmove.l %0,%%fpcr" : : "g" (old_fpcr)); \ - } while (0) -#endif - -/* default definitions are empty */ -#ifndef HAVE_PY_SET_53BIT_PRECISION -#define _Py_SET_53BIT_PRECISION_HEADER -#define _Py_SET_53BIT_PRECISION_START -#define _Py_SET_53BIT_PRECISION_END -#endif - -/* If we can't guarantee 53-bit precision, don't use the code - in Python/dtoa.c, but fall back to standard code. This - means that repr of a float will be long (17 sig digits). - - Realistically, there are two things that could go wrong: - - (1) doubles aren't IEEE 754 doubles, or - (2) we're on x86 with the rounding precision set to 64-bits - (extended precision), and we don't know how to change - the rounding precision. - */ - -#if !defined(DOUBLE_IS_LITTLE_ENDIAN_IEEE754) && \ - !defined(DOUBLE_IS_BIG_ENDIAN_IEEE754) && \ - !defined(DOUBLE_IS_ARM_MIXED_ENDIAN_IEEE754) -#define PY_NO_SHORT_FLOAT_REPR -#endif - -/* double rounding is symptomatic of use of extended precision on x86. If - we're seeing double rounding, and we don't have any mechanism available for - changing the FPU rounding precision, then don't use Python/dtoa.c. */ -#if defined(X87_DOUBLE_ROUNDING) && !defined(HAVE_PY_SET_53BIT_PRECISION) -#define PY_NO_SHORT_FLOAT_REPR -#endif - - -/* Py_DEPRECATED(version) - * Declare a variable, type, or function deprecated. - * The macro must be placed before the declaration. - * Usage: - * Py_DEPRECATED(3.3) extern int old_var; - * Py_DEPRECATED(3.4) typedef int T1; - * Py_DEPRECATED(3.8) PyAPI_FUNC(int) Py_OldFunction(void); - */ -#if defined(__GNUC__) \ - && ((__GNUC__ >= 4) || (__GNUC__ == 3) && (__GNUC_MINOR__ >= 1)) -#define Py_DEPRECATED(VERSION_UNUSED) __attribute__((__deprecated__)) -#elif defined(_MSC_VER) -#define Py_DEPRECATED(VERSION) __declspec(deprecated( \ - "deprecated in " #VERSION)) -#else -#define Py_DEPRECATED(VERSION_UNUSED) -#endif - -#if defined(__clang__) -#define _Py_COMP_DIAG_PUSH _Pragma("clang diagnostic push") -#define _Py_COMP_DIAG_IGNORE_DEPR_DECLS \ - _Pragma("clang diagnostic ignored \"-Wdeprecated-declarations\"") -#define _Py_COMP_DIAG_POP _Pragma("clang diagnostic pop") -#elif defined(__GNUC__) \ - && ((__GNUC__ >= 5) || (__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) -#define _Py_COMP_DIAG_PUSH _Pragma("GCC diagnostic push") -#define _Py_COMP_DIAG_IGNORE_DEPR_DECLS \ - _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") -#define _Py_COMP_DIAG_POP _Pragma("GCC diagnostic pop") -#elif defined(_MSC_VER) -#define _Py_COMP_DIAG_PUSH __pragma(warning(push)) -#define _Py_COMP_DIAG_IGNORE_DEPR_DECLS __pragma(warning(disable: 4996)) -#define _Py_COMP_DIAG_POP __pragma(warning(pop)) -#else -#define _Py_COMP_DIAG_PUSH -#define _Py_COMP_DIAG_IGNORE_DEPR_DECLS -#define _Py_COMP_DIAG_POP -#endif - -/* _Py_HOT_FUNCTION - * The hot attribute on a function is used to inform the compiler that the - * function is a hot spot of the compiled program. The function is optimized - * more aggressively and on many target it is placed into special subsection of - * the text section so all hot functions appears close together improving - * locality. - * - * Usage: - * int _Py_HOT_FUNCTION x(void) { return 3; } - * - * Issue #28618: This attribute must not be abused, otherwise it can have a - * negative effect on performance. Only the functions were Python spend most of - * its time must use it. Use a profiler when running performance benchmark - * suite to find these functions. - */ -#if defined(__GNUC__) \ - && ((__GNUC__ >= 5) || (__GNUC__ == 4) && (__GNUC_MINOR__ >= 3)) -#define _Py_HOT_FUNCTION __attribute__((hot)) -#else -#define _Py_HOT_FUNCTION -#endif - -/* _Py_NO_INLINE - * Disable inlining on a function. For example, it helps to reduce the C stack - * consumption. - * - * Usage: - * int _Py_NO_INLINE x(void) { return 3; } - */ -#if defined(_MSC_VER) -# define _Py_NO_INLINE __declspec(noinline) -#elif defined(__GNUC__) || defined(__clang__) -# define _Py_NO_INLINE __attribute__ ((noinline)) -#else -# define _Py_NO_INLINE -#endif - -/************************************************************************** -Prototypes that are missing from the standard include files on some systems -(and possibly only some versions of such systems.) - -Please be conservative with adding new ones, document them and enclose them -in platform-specific #ifdefs. -**************************************************************************/ - -#ifdef SOLARIS -/* Unchecked */ -extern int gethostname(char *, int); -#endif - -#ifdef HAVE__GETPTY -#include /* we need to import mode_t */ -extern char * _getpty(int *, int, mode_t, int); -#endif - -/* On QNX 6, struct termio must be declared by including sys/termio.h - if TCGETA, TCSETA, TCSETAW, or TCSETAF are used. sys/termio.h must - be included before termios.h or it will generate an error. */ -#if defined(HAVE_SYS_TERMIO_H) && !defined(__hpux) -#include -#endif - - -/* On 4.4BSD-descendants, ctype functions serves the whole range of - * wchar_t character set rather than single byte code points only. - * This characteristic can break some operations of string object - * including str.upper() and str.split() on UTF-8 locales. This - * workaround was provided by Tim Robbins of FreeBSD project. - */ - -#if defined(__APPLE__) -# define _PY_PORT_CTYPE_UTF8_ISSUE -#endif - -#ifdef _PY_PORT_CTYPE_UTF8_ISSUE -#ifndef __cplusplus - /* The workaround below is unsafe in C++ because - * the defines these symbols as real functions, - * with a slightly different signature. - * See issue #10910 - */ -#include -#include -#undef isalnum -#define isalnum(c) iswalnum(btowc(c)) -#undef isalpha -#define isalpha(c) iswalpha(btowc(c)) -#undef islower -#define islower(c) iswlower(btowc(c)) -#undef isspace -#define isspace(c) iswspace(btowc(c)) -#undef isupper -#define isupper(c) iswupper(btowc(c)) -#undef tolower -#define tolower(c) towlower(btowc(c)) -#undef toupper -#define toupper(c) towupper(btowc(c)) -#endif -#endif - - -/* Declarations for symbol visibility. - - PyAPI_FUNC(type): Declares a public Python API function and return type - PyAPI_DATA(type): Declares public Python data and its type - PyMODINIT_FUNC: A Python module init function. If these functions are - inside the Python core, they are private to the core. - If in an extension module, it may be declared with - external linkage depending on the platform. - - As a number of platforms support/require "__declspec(dllimport/dllexport)", - we support a HAVE_DECLSPEC_DLL macro to save duplication. -*/ - -/* - All windows ports, except cygwin, are handled in PC/pyconfig.h. - - Cygwin is the only other autoconf platform requiring special - linkage handling and it uses __declspec(). -*/ -#if defined(__CYGWIN__) -# define HAVE_DECLSPEC_DLL -#endif - -#include "exports.h" - -/* only get special linkage if built as shared or platform is Cygwin */ -#if defined(Py_ENABLE_SHARED) || defined(__CYGWIN__) -# if defined(HAVE_DECLSPEC_DLL) -# if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -# define PyAPI_FUNC(RTYPE) Py_EXPORTED_SYMBOL RTYPE -# define PyAPI_DATA(RTYPE) extern Py_EXPORTED_SYMBOL RTYPE - /* module init functions inside the core need no external linkage */ - /* except for Cygwin to handle embedding */ -# if defined(__CYGWIN__) -# define PyMODINIT_FUNC Py_EXPORTED_SYMBOL PyObject* -# else /* __CYGWIN__ */ -# define PyMODINIT_FUNC PyObject* -# endif /* __CYGWIN__ */ -# else /* Py_BUILD_CORE */ - /* Building an extension module, or an embedded situation */ - /* public Python functions and data are imported */ - /* Under Cygwin, auto-import functions to prevent compilation */ - /* failures similar to those described at the bottom of 4.1: */ - /* http://docs.python.org/extending/windows.html#a-cookbook-approach */ -# if !defined(__CYGWIN__) -# define PyAPI_FUNC(RTYPE) Py_IMPORTED_SYMBOL RTYPE -# endif /* !__CYGWIN__ */ -# define PyAPI_DATA(RTYPE) extern Py_IMPORTED_SYMBOL RTYPE - /* module init functions outside the core must be exported */ -# if defined(__cplusplus) -# define PyMODINIT_FUNC extern "C" Py_EXPORTED_SYMBOL PyObject* -# else /* __cplusplus */ -# define PyMODINIT_FUNC Py_EXPORTED_SYMBOL PyObject* -# endif /* __cplusplus */ -# endif /* Py_BUILD_CORE */ -# endif /* HAVE_DECLSPEC_DLL */ -#endif /* Py_ENABLE_SHARED */ - -/* If no external linkage macros defined by now, create defaults */ -#ifndef PyAPI_FUNC -# define PyAPI_FUNC(RTYPE) Py_EXPORTED_SYMBOL RTYPE -#endif -#ifndef PyAPI_DATA -# define PyAPI_DATA(RTYPE) extern Py_EXPORTED_SYMBOL RTYPE -#endif -#ifndef PyMODINIT_FUNC -# if defined(__cplusplus) -# define PyMODINIT_FUNC extern "C" Py_EXPORTED_SYMBOL PyObject* -# else /* __cplusplus */ -# define PyMODINIT_FUNC Py_EXPORTED_SYMBOL PyObject* -# endif /* __cplusplus */ -#endif - -/* limits.h constants that may be missing */ - -#ifndef INT_MAX -#define INT_MAX 2147483647 -#endif - -#ifndef LONG_MAX -#if SIZEOF_LONG == 4 -#define LONG_MAX 0X7FFFFFFFL -#elif SIZEOF_LONG == 8 -#define LONG_MAX 0X7FFFFFFFFFFFFFFFL -#else -#error "could not set LONG_MAX in pyport.h" -#endif -#endif - -#ifndef LONG_MIN -#define LONG_MIN (-LONG_MAX-1) -#endif - -#ifndef LONG_BIT -#define LONG_BIT (8 * SIZEOF_LONG) -#endif - -#if LONG_BIT != 8 * SIZEOF_LONG -/* 04-Oct-2000 LONG_BIT is apparently (mis)defined as 64 on some recent - * 32-bit platforms using gcc. We try to catch that here at compile-time - * rather than waiting for integer multiplication to trigger bogus - * overflows. - */ -#error "LONG_BIT definition appears wrong for platform (bad gcc/glibc config?)." -#endif - -#ifdef __cplusplus -} -#endif - -/* - * Hide GCC attributes from compilers that don't support them. - */ -#if (!defined(__GNUC__) || __GNUC__ < 2 || \ - (__GNUC__ == 2 && __GNUC_MINOR__ < 7) ) -#define Py_GCC_ATTRIBUTE(x) -#else -#define Py_GCC_ATTRIBUTE(x) __attribute__(x) -#endif - -/* - * Specify alignment on compilers that support it. - */ -#if defined(__GNUC__) && __GNUC__ >= 3 -#define Py_ALIGNED(x) __attribute__((aligned(x))) -#else -#define Py_ALIGNED(x) -#endif - -/* Eliminate end-of-loop code not reached warnings from SunPro C - * when using do{...}while(0) macros - */ -#ifdef __SUNPRO_C -#pragma error_messages (off,E_END_OF_LOOP_CODE_NOT_REACHED) -#endif - -#ifndef Py_LL -#define Py_LL(x) x##LL -#endif - -#ifndef Py_ULL -#define Py_ULL(x) Py_LL(x##U) -#endif - -#define Py_VA_COPY va_copy - -/* - * Convenient macros to deal with endianness of the platform. WORDS_BIGENDIAN is - * detected by configure and defined in pyconfig.h. The code in pyconfig.h - * also takes care of Apple's universal builds. - */ - -#ifdef WORDS_BIGENDIAN -# define PY_BIG_ENDIAN 1 -# define PY_LITTLE_ENDIAN 0 -#else -# define PY_BIG_ENDIAN 0 -# define PY_LITTLE_ENDIAN 1 -#endif - -#ifdef Py_BUILD_CORE -/* - * Macros to protect CRT calls against instant termination when passed an - * invalid parameter (issue23524). - */ -#if defined _MSC_VER && _MSC_VER >= 1900 - -extern _invalid_parameter_handler _Py_silent_invalid_parameter_handler; -#define _Py_BEGIN_SUPPRESS_IPH { _invalid_parameter_handler _Py_old_handler = \ - _set_thread_local_invalid_parameter_handler(_Py_silent_invalid_parameter_handler); -#define _Py_END_SUPPRESS_IPH _set_thread_local_invalid_parameter_handler(_Py_old_handler); } - -#else - -#define _Py_BEGIN_SUPPRESS_IPH -#define _Py_END_SUPPRESS_IPH - -#endif /* _MSC_VER >= 1900 */ -#endif /* Py_BUILD_CORE */ - -#ifdef __ANDROID__ - /* The Android langinfo.h header is not used. */ -# undef HAVE_LANGINFO_H -# undef CODESET -#endif - -/* Maximum value of the Windows DWORD type */ -#define PY_DWORD_MAX 4294967295U - -/* This macro used to tell whether Python was built with multithreading - * enabled. Now multithreading is always enabled, but keep the macro - * for compatibility. - */ -#ifndef WITH_THREAD -# define WITH_THREAD -#endif - -/* Check that ALT_SOABI is consistent with Py_TRACE_REFS: - ./configure --with-trace-refs should must be used to define Py_TRACE_REFS */ -#if defined(ALT_SOABI) && defined(Py_TRACE_REFS) -# error "Py_TRACE_REFS ABI is not compatible with release and debug ABI" -#endif - -#if defined(__ANDROID__) || defined(__VXWORKS__) - /* Ignore the locale encoding: force UTF-8 */ -# define _Py_FORCE_UTF8_LOCALE -#endif - -#if defined(_Py_FORCE_UTF8_LOCALE) || defined(__APPLE__) - /* Use UTF-8 as filesystem encoding */ -# define _Py_FORCE_UTF8_FS_ENCODING -#endif - -/* Mark a function which cannot return. Example: - PyAPI_FUNC(void) _Py_NO_RETURN PyThread_exit_thread(void); - - XLC support is intentionally omitted due to bpo-40244 */ -#if defined(__clang__) || \ - (defined(__GNUC__) && \ - ((__GNUC__ >= 3) || \ - (__GNUC__ == 2) && (__GNUC_MINOR__ >= 5))) -# define _Py_NO_RETURN __attribute__((__noreturn__)) -#elif defined(_MSC_VER) -# define _Py_NO_RETURN __declspec(noreturn) -#else -# define _Py_NO_RETURN -#endif - - -// Preprocessor check for a builtin preprocessor function. Always return 0 -// if __has_builtin() macro is not defined. -// -// __has_builtin() is available on clang and GCC 10. -#ifdef __has_builtin -# define _Py__has_builtin(x) __has_builtin(x) -#else -# define _Py__has_builtin(x) 0 -#endif - - -#endif /* Py_PYPORT_H */ diff --git a/scripts/build-windows/py39-libs/include/pystate.h b/scripts/build-windows/py39-libs/include/pystate.h deleted file mode 100644 index d9f31e365..000000000 --- a/scripts/build-windows/py39-libs/include/pystate.h +++ /dev/null @@ -1,150 +0,0 @@ -/* Thread and interpreter state structures and their interfaces */ - - -#ifndef Py_PYSTATE_H -#define Py_PYSTATE_H -#ifdef __cplusplus -extern "C" { -#endif - -/* This limitation is for performance and simplicity. If needed it can be -removed (with effort). */ -#define MAX_CO_EXTRA_USERS 255 - -/* Forward declarations for PyFrameObject, PyThreadState - and PyInterpreterState */ -struct _ts; -struct _is; - -/* struct _ts is defined in cpython/pystate.h */ -typedef struct _ts PyThreadState; -/* struct _is is defined in internal/pycore_interp.h */ -typedef struct _is PyInterpreterState; - -PyAPI_FUNC(PyInterpreterState *) PyInterpreterState_New(void); -PyAPI_FUNC(void) PyInterpreterState_Clear(PyInterpreterState *); -PyAPI_FUNC(void) PyInterpreterState_Delete(PyInterpreterState *); - -#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03090000 -/* New in 3.9 */ -/* Get the current interpreter state. - - Issue a fatal error if there no current Python thread state or no current - interpreter. It cannot return NULL. - - The caller must hold the GIL. */ -PyAPI_FUNC(PyInterpreterState *) PyInterpreterState_Get(void); -#endif - -#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03080000 -/* New in 3.8 */ -PyAPI_FUNC(PyObject *) PyInterpreterState_GetDict(PyInterpreterState *); -#endif - -#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03070000 -/* New in 3.7 */ -PyAPI_FUNC(int64_t) PyInterpreterState_GetID(PyInterpreterState *); -#endif -#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03030000 - -/* State unique per thread */ - -/* New in 3.3 */ -PyAPI_FUNC(int) PyState_AddModule(PyObject*, struct PyModuleDef*); -PyAPI_FUNC(int) PyState_RemoveModule(struct PyModuleDef*); -#endif -PyAPI_FUNC(PyObject*) PyState_FindModule(struct PyModuleDef*); - -PyAPI_FUNC(PyThreadState *) PyThreadState_New(PyInterpreterState *); -PyAPI_FUNC(void) PyThreadState_Clear(PyThreadState *); -PyAPI_FUNC(void) PyThreadState_Delete(PyThreadState *); - -/* Get the current thread state. - - When the current thread state is NULL, this issues a fatal error (so that - the caller needn't check for NULL). - - The caller must hold the GIL. - - See also PyThreadState_GET() and _PyThreadState_GET(). */ -PyAPI_FUNC(PyThreadState *) PyThreadState_Get(void); - -/* Get the current Python thread state. - - Macro using PyThreadState_Get() or _PyThreadState_GET() depending if - pycore_pystate.h is included or not (this header redefines the macro). - - If PyThreadState_Get() is used, issue a fatal error if the current thread - state is NULL. - - See also PyThreadState_Get() and _PyThreadState_GET(). */ -#define PyThreadState_GET() PyThreadState_Get() - -PyAPI_FUNC(PyThreadState *) PyThreadState_Swap(PyThreadState *); -PyAPI_FUNC(PyObject *) PyThreadState_GetDict(void); -PyAPI_FUNC(int) PyThreadState_SetAsyncExc(unsigned long, PyObject *); - -#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03090000 -/* New in 3.9 */ -PyAPI_FUNC(PyInterpreterState*) PyThreadState_GetInterpreter(PyThreadState *tstate); -PyAPI_FUNC(PyFrameObject*) PyThreadState_GetFrame(PyThreadState *tstate); -PyAPI_FUNC(uint64_t) PyThreadState_GetID(PyThreadState *tstate); -#endif - -typedef - enum {PyGILState_LOCKED, PyGILState_UNLOCKED} - PyGILState_STATE; - - -/* Ensure that the current thread is ready to call the Python - C API, regardless of the current state of Python, or of its - thread lock. This may be called as many times as desired - by a thread so long as each call is matched with a call to - PyGILState_Release(). In general, other thread-state APIs may - be used between _Ensure() and _Release() calls, so long as the - thread-state is restored to its previous state before the Release(). - For example, normal use of the Py_BEGIN_ALLOW_THREADS/ - Py_END_ALLOW_THREADS macros are acceptable. - - The return value is an opaque "handle" to the thread state when - PyGILState_Ensure() was called, and must be passed to - PyGILState_Release() to ensure Python is left in the same state. Even - though recursive calls are allowed, these handles can *not* be shared - - each unique call to PyGILState_Ensure must save the handle for its - call to PyGILState_Release. - - When the function returns, the current thread will hold the GIL. - - Failure is a fatal error. -*/ -PyAPI_FUNC(PyGILState_STATE) PyGILState_Ensure(void); - -/* Release any resources previously acquired. After this call, Python's - state will be the same as it was prior to the corresponding - PyGILState_Ensure() call (but generally this state will be unknown to - the caller, hence the use of the GILState API.) - - Every call to PyGILState_Ensure must be matched by a call to - PyGILState_Release on the same thread. -*/ -PyAPI_FUNC(void) PyGILState_Release(PyGILState_STATE); - -/* Helper/diagnostic function - get the current thread state for - this thread. May return NULL if no GILState API has been used - on the current thread. Note that the main thread always has such a - thread-state, even if no auto-thread-state call has been made - on the main thread. -*/ -PyAPI_FUNC(PyThreadState *) PyGILState_GetThisThreadState(void); - - -#ifndef Py_LIMITED_API -# define Py_CPYTHON_PYSTATE_H -# include "cpython/pystate.h" -# undef Py_CPYTHON_PYSTATE_H -#endif - -#ifdef __cplusplus -} -#endif -#endif /* !Py_PYSTATE_H */ diff --git a/scripts/build-windows/py39-libs/include/pystrcmp.h b/scripts/build-windows/py39-libs/include/pystrcmp.h deleted file mode 100644 index eccabdce0..000000000 --- a/scripts/build-windows/py39-libs/include/pystrcmp.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef Py_STRCMP_H -#define Py_STRCMP_H - -#ifdef __cplusplus -extern "C" { -#endif - -PyAPI_FUNC(int) PyOS_mystrnicmp(const char *, const char *, Py_ssize_t); -PyAPI_FUNC(int) PyOS_mystricmp(const char *, const char *); - -#ifdef MS_WINDOWS -#define PyOS_strnicmp strnicmp -#define PyOS_stricmp stricmp -#else -#define PyOS_strnicmp PyOS_mystrnicmp -#define PyOS_stricmp PyOS_mystricmp -#endif - -#ifdef __cplusplus -} -#endif - -#endif /* !Py_STRCMP_H */ diff --git a/scripts/build-windows/py39-libs/include/pystrhex.h b/scripts/build-windows/py39-libs/include/pystrhex.h deleted file mode 100644 index bccae77ac..000000000 --- a/scripts/build-windows/py39-libs/include/pystrhex.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef Py_STRHEX_H -#define Py_STRHEX_H - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef Py_LIMITED_API -/* Returns a str() containing the hex representation of argbuf. */ -PyAPI_FUNC(PyObject*) _Py_strhex(const char* argbuf, const Py_ssize_t arglen); -/* Returns a bytes() containing the ASCII hex representation of argbuf. */ -PyAPI_FUNC(PyObject*) _Py_strhex_bytes(const char* argbuf, const Py_ssize_t arglen); -/* These variants include support for a separator between every N bytes: */ -PyAPI_FUNC(PyObject*) _Py_strhex_with_sep(const char* argbuf, const Py_ssize_t arglen, const PyObject* sep, const int bytes_per_group); -PyAPI_FUNC(PyObject*) _Py_strhex_bytes_with_sep(const char* argbuf, const Py_ssize_t arglen, const PyObject* sep, const int bytes_per_group); -#endif /* !Py_LIMITED_API */ - -#ifdef __cplusplus -} -#endif - -#endif /* !Py_STRHEX_H */ diff --git a/scripts/build-windows/py39-libs/include/pystrtod.h b/scripts/build-windows/py39-libs/include/pystrtod.h deleted file mode 100644 index ba2e8d00f..000000000 --- a/scripts/build-windows/py39-libs/include/pystrtod.h +++ /dev/null @@ -1,45 +0,0 @@ -#ifndef Py_STRTOD_H -#define Py_STRTOD_H - -#ifdef __cplusplus -extern "C" { -#endif - - -PyAPI_FUNC(double) PyOS_string_to_double(const char *str, - char **endptr, - PyObject *overflow_exception); - -/* The caller is responsible for calling PyMem_Free to free the buffer - that's is returned. */ -PyAPI_FUNC(char *) PyOS_double_to_string(double val, - char format_code, - int precision, - int flags, - int *type); - -#ifndef Py_LIMITED_API -PyAPI_FUNC(PyObject *) _Py_string_to_number_with_underscores( - const char *str, Py_ssize_t len, const char *what, PyObject *obj, void *arg, - PyObject *(*innerfunc)(const char *, Py_ssize_t, void *)); - -PyAPI_FUNC(double) _Py_parse_inf_or_nan(const char *p, char **endptr); -#endif - - -/* PyOS_double_to_string's "flags" parameter can be set to 0 or more of: */ -#define Py_DTSF_SIGN 0x01 /* always add the sign */ -#define Py_DTSF_ADD_DOT_0 0x02 /* if the result is an integer add ".0" */ -#define Py_DTSF_ALT 0x04 /* "alternate" formatting. it's format_code - specific */ - -/* PyOS_double_to_string's "type", if non-NULL, will be set to one of: */ -#define Py_DTST_FINITE 0 -#define Py_DTST_INFINITE 1 -#define Py_DTST_NAN 2 - -#ifdef __cplusplus -} -#endif - -#endif /* !Py_STRTOD_H */ diff --git a/scripts/build-windows/py39-libs/include/pythonrun.h b/scripts/build-windows/py39-libs/include/pythonrun.h deleted file mode 100644 index ecd35c601..000000000 --- a/scripts/build-windows/py39-libs/include/pythonrun.h +++ /dev/null @@ -1,217 +0,0 @@ - -/* Interfaces to parse and execute pieces of python code */ - -#ifndef Py_PYTHONRUN_H -#define Py_PYTHONRUN_H -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef Py_LIMITED_API -PyAPI_FUNC(int) PyRun_SimpleStringFlags(const char *, PyCompilerFlags *); -PyAPI_FUNC(int) PyRun_AnyFileExFlags( - FILE *fp, - const char *filename, /* decoded from the filesystem encoding */ - int closeit, - PyCompilerFlags *flags); -PyAPI_FUNC(int) PyRun_SimpleFileExFlags( - FILE *fp, - const char *filename, /* decoded from the filesystem encoding */ - int closeit, - PyCompilerFlags *flags); -PyAPI_FUNC(int) PyRun_InteractiveOneFlags( - FILE *fp, - const char *filename, /* decoded from the filesystem encoding */ - PyCompilerFlags *flags); -PyAPI_FUNC(int) PyRun_InteractiveOneObject( - FILE *fp, - PyObject *filename, - PyCompilerFlags *flags); -PyAPI_FUNC(int) PyRun_InteractiveLoopFlags( - FILE *fp, - const char *filename, /* decoded from the filesystem encoding */ - PyCompilerFlags *flags); - -PyAPI_FUNC(struct _mod *) PyParser_ASTFromString( - const char *s, - const char *filename, /* decoded from the filesystem encoding */ - int start, - PyCompilerFlags *flags, - PyArena *arena); -PyAPI_FUNC(struct _mod *) PyParser_ASTFromStringObject( - const char *s, - PyObject *filename, - int start, - PyCompilerFlags *flags, - PyArena *arena); -PyAPI_FUNC(struct _mod *) PyParser_ASTFromFile( - FILE *fp, - const char *filename, /* decoded from the filesystem encoding */ - const char* enc, - int start, - const char *ps1, - const char *ps2, - PyCompilerFlags *flags, - int *errcode, - PyArena *arena); -PyAPI_FUNC(struct _mod *) PyParser_ASTFromFileObject( - FILE *fp, - PyObject *filename, - const char* enc, - int start, - const char *ps1, - const char *ps2, - PyCompilerFlags *flags, - int *errcode, - PyArena *arena); -#endif - -#ifndef PyParser_SimpleParseString -#define PyParser_SimpleParseString(S, B) \ - PyParser_SimpleParseStringFlags(S, B, 0) -#define PyParser_SimpleParseFile(FP, S, B) \ - PyParser_SimpleParseFileFlags(FP, S, B, 0) -#endif - -#ifndef Py_BUILD_CORE -Py_DEPRECATED(3.9) -#endif -PyAPI_FUNC(struct _node *) PyParser_SimpleParseStringFlags(const char *, int, int); -#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03030000 -#ifndef Py_BUILD_CORE -Py_DEPRECATED(3.9) -#endif -PyAPI_FUNC(struct _node *) PyParser_SimpleParseStringFlagsFilename(const char *, - const char *, - int, int); -#endif -#ifndef Py_BUILD_CORE -Py_DEPRECATED(3.9) -#endif -PyAPI_FUNC(struct _node *) PyParser_SimpleParseFileFlags(FILE *, const char *, int, int); -#ifndef Py_LIMITED_API -PyAPI_FUNC(PyObject *) PyRun_StringFlags(const char *, int, PyObject *, - PyObject *, PyCompilerFlags *); - -PyAPI_FUNC(PyObject *) PyRun_FileExFlags( - FILE *fp, - const char *filename, /* decoded from the filesystem encoding */ - int start, - PyObject *globals, - PyObject *locals, - int closeit, - PyCompilerFlags *flags); -#endif - -#ifdef Py_LIMITED_API -PyAPI_FUNC(PyObject *) Py_CompileString(const char *, const char *, int); -#else -#define Py_CompileString(str, p, s) Py_CompileStringExFlags(str, p, s, NULL, -1) -#define Py_CompileStringFlags(str, p, s, f) Py_CompileStringExFlags(str, p, s, f, -1) -PyAPI_FUNC(PyObject *) Py_CompileStringExFlags( - const char *str, - const char *filename, /* decoded from the filesystem encoding */ - int start, - PyCompilerFlags *flags, - int optimize); -PyAPI_FUNC(PyObject *) Py_CompileStringObject( - const char *str, - PyObject *filename, int start, - PyCompilerFlags *flags, - int optimize); -#endif -PyAPI_FUNC(struct symtable *) Py_SymtableString( - const char *str, - const char *filename, /* decoded from the filesystem encoding */ - int start); -#ifndef Py_LIMITED_API -PyAPI_FUNC(const char *) _Py_SourceAsString( - PyObject *cmd, - const char *funcname, - const char *what, - PyCompilerFlags *cf, - PyObject **cmd_copy); - -PyAPI_FUNC(struct symtable *) Py_SymtableStringObject( - const char *str, - PyObject *filename, - int start); - -PyAPI_FUNC(struct symtable *) _Py_SymtableStringObjectFlags( - const char *str, - PyObject *filename, - int start, - PyCompilerFlags *flags); -#endif - -PyAPI_FUNC(void) PyErr_Print(void); -PyAPI_FUNC(void) PyErr_PrintEx(int); -PyAPI_FUNC(void) PyErr_Display(PyObject *, PyObject *, PyObject *); - -#ifndef Py_LIMITED_API -/* A function flavor is also exported by libpython. It is required when - libpython is accessed directly rather than using header files which defines - macros below. On Windows, for example, PyAPI_FUNC() uses dllexport to - export functions in pythonXX.dll. */ -PyAPI_FUNC(PyObject *) PyRun_String(const char *str, int s, PyObject *g, PyObject *l); -PyAPI_FUNC(int) PyRun_AnyFile(FILE *fp, const char *name); -PyAPI_FUNC(int) PyRun_AnyFileEx(FILE *fp, const char *name, int closeit); -PyAPI_FUNC(int) PyRun_AnyFileFlags(FILE *, const char *, PyCompilerFlags *); -PyAPI_FUNC(int) PyRun_SimpleString(const char *s); -PyAPI_FUNC(int) PyRun_SimpleFile(FILE *f, const char *p); -PyAPI_FUNC(int) PyRun_SimpleFileEx(FILE *f, const char *p, int c); -PyAPI_FUNC(int) PyRun_InteractiveOne(FILE *f, const char *p); -PyAPI_FUNC(int) PyRun_InteractiveLoop(FILE *f, const char *p); -PyAPI_FUNC(PyObject *) PyRun_File(FILE *fp, const char *p, int s, PyObject *g, PyObject *l); -PyAPI_FUNC(PyObject *) PyRun_FileEx(FILE *fp, const char *p, int s, PyObject *g, PyObject *l, int c); -PyAPI_FUNC(PyObject *) PyRun_FileFlags(FILE *fp, const char *p, int s, PyObject *g, PyObject *l, PyCompilerFlags *flags); - -/* Use macros for a bunch of old variants */ -#define PyRun_String(str, s, g, l) PyRun_StringFlags(str, s, g, l, NULL) -#define PyRun_AnyFile(fp, name) PyRun_AnyFileExFlags(fp, name, 0, NULL) -#define PyRun_AnyFileEx(fp, name, closeit) \ - PyRun_AnyFileExFlags(fp, name, closeit, NULL) -#define PyRun_AnyFileFlags(fp, name, flags) \ - PyRun_AnyFileExFlags(fp, name, 0, flags) -#define PyRun_SimpleString(s) PyRun_SimpleStringFlags(s, NULL) -#define PyRun_SimpleFile(f, p) PyRun_SimpleFileExFlags(f, p, 0, NULL) -#define PyRun_SimpleFileEx(f, p, c) PyRun_SimpleFileExFlags(f, p, c, NULL) -#define PyRun_InteractiveOne(f, p) PyRun_InteractiveOneFlags(f, p, NULL) -#define PyRun_InteractiveLoop(f, p) PyRun_InteractiveLoopFlags(f, p, NULL) -#define PyRun_File(fp, p, s, g, l) \ - PyRun_FileExFlags(fp, p, s, g, l, 0, NULL) -#define PyRun_FileEx(fp, p, s, g, l, c) \ - PyRun_FileExFlags(fp, p, s, g, l, c, NULL) -#define PyRun_FileFlags(fp, p, s, g, l, flags) \ - PyRun_FileExFlags(fp, p, s, g, l, 0, flags) -#endif - -/* Stuff with no proper home (yet) */ -#ifndef Py_LIMITED_API -PyAPI_FUNC(char *) PyOS_Readline(FILE *, FILE *, const char *); -#endif -PyAPI_DATA(int) (*PyOS_InputHook)(void); -PyAPI_DATA(char) *(*PyOS_ReadlineFunctionPointer)(FILE *, FILE *, const char *); -#ifndef Py_LIMITED_API -PyAPI_DATA(PyThreadState*) _PyOS_ReadlineTState; -#endif - -/* Stack size, in "pointers" (so we get extra safety margins - on 64-bit platforms). On a 32-bit platform, this translates - to an 8k margin. */ -#define PYOS_STACK_MARGIN 2048 - -#if defined(WIN32) && !defined(MS_WIN64) && !defined(_M_ARM) && defined(_MSC_VER) && _MSC_VER >= 1300 -/* Enable stack checking under Microsoft C */ -#define USE_STACKCHECK -#endif - -#ifdef USE_STACKCHECK -/* Check that we aren't overflowing our stack */ -PyAPI_FUNC(int) PyOS_CheckStack(void); -#endif - -#ifdef __cplusplus -} -#endif -#endif /* !Py_PYTHONRUN_H */ diff --git a/scripts/build-windows/py39-libs/include/pythread.h b/scripts/build-windows/py39-libs/include/pythread.h deleted file mode 100644 index 739594a82..000000000 --- a/scripts/build-windows/py39-libs/include/pythread.h +++ /dev/null @@ -1,169 +0,0 @@ - -#ifndef Py_PYTHREAD_H -#define Py_PYTHREAD_H - -typedef void *PyThread_type_lock; - -#ifdef __cplusplus -extern "C" { -#endif - -/* Return status codes for Python lock acquisition. Chosen for maximum - * backwards compatibility, ie failure -> 0, success -> 1. */ -typedef enum PyLockStatus { - PY_LOCK_FAILURE = 0, - PY_LOCK_ACQUIRED = 1, - PY_LOCK_INTR -} PyLockStatus; - -#ifndef Py_LIMITED_API -#define PYTHREAD_INVALID_THREAD_ID ((unsigned long)-1) -#endif - -PyAPI_FUNC(void) PyThread_init_thread(void); -PyAPI_FUNC(unsigned long) PyThread_start_new_thread(void (*)(void *), void *); -PyAPI_FUNC(void) _Py_NO_RETURN PyThread_exit_thread(void); -PyAPI_FUNC(unsigned long) PyThread_get_thread_ident(void); - -#if defined(__APPLE__) || defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(_WIN32) || defined(_AIX) -#define PY_HAVE_THREAD_NATIVE_ID -PyAPI_FUNC(unsigned long) PyThread_get_thread_native_id(void); -#endif - -PyAPI_FUNC(PyThread_type_lock) PyThread_allocate_lock(void); -PyAPI_FUNC(void) PyThread_free_lock(PyThread_type_lock); -PyAPI_FUNC(int) PyThread_acquire_lock(PyThread_type_lock, int); -#define WAIT_LOCK 1 -#define NOWAIT_LOCK 0 - -#ifndef Py_LIMITED_API -#ifdef HAVE_FORK -/* Private function to reinitialize a lock at fork in the child process. - Reset the lock to the unlocked state. - Return 0 on success, return -1 on error. */ -PyAPI_FUNC(int) _PyThread_at_fork_reinit(PyThread_type_lock *lock); -#endif /* HAVE_FORK */ -#endif /* !Py_LIMITED_API */ - -/* PY_TIMEOUT_T is the integral type used to specify timeouts when waiting - on a lock (see PyThread_acquire_lock_timed() below). - PY_TIMEOUT_MAX is the highest usable value (in microseconds) of that - type, and depends on the system threading API. - - NOTE: this isn't the same value as `_thread.TIMEOUT_MAX`. The _thread - module exposes a higher-level API, with timeouts expressed in seconds - and floating-point numbers allowed. -*/ -#define PY_TIMEOUT_T long long - -#if defined(_POSIX_THREADS) - /* PyThread_acquire_lock_timed() uses _PyTime_FromNanoseconds(us * 1000), - convert microseconds to nanoseconds. */ -# define PY_TIMEOUT_MAX (LLONG_MAX / 1000) -#elif defined (NT_THREADS) - /* In the NT API, the timeout is a DWORD and is expressed in milliseconds */ -# if 0xFFFFFFFFLL * 1000 < LLONG_MAX -# define PY_TIMEOUT_MAX (0xFFFFFFFFLL * 1000) -# else -# define PY_TIMEOUT_MAX LLONG_MAX -# endif -#else -# define PY_TIMEOUT_MAX LLONG_MAX -#endif - - -/* If microseconds == 0, the call is non-blocking: it returns immediately - even when the lock can't be acquired. - If microseconds > 0, the call waits up to the specified duration. - If microseconds < 0, the call waits until success (or abnormal failure) - - microseconds must be less than PY_TIMEOUT_MAX. Behaviour otherwise is - undefined. - - If intr_flag is true and the acquire is interrupted by a signal, then the - call will return PY_LOCK_INTR. The caller may reattempt to acquire the - lock. -*/ -PyAPI_FUNC(PyLockStatus) PyThread_acquire_lock_timed(PyThread_type_lock, - PY_TIMEOUT_T microseconds, - int intr_flag); - -PyAPI_FUNC(void) PyThread_release_lock(PyThread_type_lock); - -PyAPI_FUNC(size_t) PyThread_get_stacksize(void); -PyAPI_FUNC(int) PyThread_set_stacksize(size_t); - -#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03030000 -PyAPI_FUNC(PyObject*) PyThread_GetInfo(void); -#endif - - -/* Thread Local Storage (TLS) API - TLS API is DEPRECATED. Use Thread Specific Storage (TSS) API. - - The existing TLS API has used int to represent TLS keys across all - platforms, but it is not POSIX-compliant. Therefore, the new TSS API uses - opaque data type to represent TSS keys to be compatible (see PEP 539). -*/ -Py_DEPRECATED(3.7) PyAPI_FUNC(int) PyThread_create_key(void); -Py_DEPRECATED(3.7) PyAPI_FUNC(void) PyThread_delete_key(int key); -Py_DEPRECATED(3.7) PyAPI_FUNC(int) PyThread_set_key_value(int key, - void *value); -Py_DEPRECATED(3.7) PyAPI_FUNC(void *) PyThread_get_key_value(int key); -Py_DEPRECATED(3.7) PyAPI_FUNC(void) PyThread_delete_key_value(int key); - -/* Cleanup after a fork */ -Py_DEPRECATED(3.7) PyAPI_FUNC(void) PyThread_ReInitTLS(void); - - -#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03070000 -/* New in 3.7 */ -/* Thread Specific Storage (TSS) API */ - -typedef struct _Py_tss_t Py_tss_t; /* opaque */ - -#ifndef Py_LIMITED_API -#if defined(_POSIX_THREADS) - /* Darwin needs pthread.h to know type name the pthread_key_t. */ -# include -# define NATIVE_TSS_KEY_T pthread_key_t -#elif defined(NT_THREADS) - /* In Windows, native TSS key type is DWORD, - but hardcode the unsigned long to avoid errors for include directive. - */ -# define NATIVE_TSS_KEY_T unsigned long -#else -# error "Require native threads. See https://bugs.python.org/issue31370" -#endif - -/* When Py_LIMITED_API is not defined, the type layout of Py_tss_t is - exposed to allow static allocation in the API clients. Even in this case, - you must handle TSS keys through API functions due to compatibility. -*/ -struct _Py_tss_t { - int _is_initialized; - NATIVE_TSS_KEY_T _key; -}; - -#undef NATIVE_TSS_KEY_T - -/* When static allocation, you must initialize with Py_tss_NEEDS_INIT. */ -#define Py_tss_NEEDS_INIT {0} -#endif /* !Py_LIMITED_API */ - -PyAPI_FUNC(Py_tss_t *) PyThread_tss_alloc(void); -PyAPI_FUNC(void) PyThread_tss_free(Py_tss_t *key); - -/* The parameter key must not be NULL. */ -PyAPI_FUNC(int) PyThread_tss_is_created(Py_tss_t *key); -PyAPI_FUNC(int) PyThread_tss_create(Py_tss_t *key); -PyAPI_FUNC(void) PyThread_tss_delete(Py_tss_t *key); -PyAPI_FUNC(int) PyThread_tss_set(Py_tss_t *key, void *value); -PyAPI_FUNC(void *) PyThread_tss_get(Py_tss_t *key); -#endif /* New in 3.7 */ - -#ifdef __cplusplus -} -#endif - -#endif /* !Py_PYTHREAD_H */ diff --git a/scripts/build-windows/py39-libs/include/pytime.h b/scripts/build-windows/py39-libs/include/pytime.h deleted file mode 100644 index dde92ee0b..000000000 --- a/scripts/build-windows/py39-libs/include/pytime.h +++ /dev/null @@ -1,246 +0,0 @@ -#ifndef Py_LIMITED_API -#ifndef Py_PYTIME_H -#define Py_PYTIME_H - -#include "pyconfig.h" /* include for defines */ -#include "object.h" - -/************************************************************************** -Symbols and macros to supply platform-independent interfaces to time related -functions and constants -**************************************************************************/ -#ifdef __cplusplus -extern "C" { -#endif - -/* _PyTime_t: Python timestamp with subsecond precision. It can be used to - store a duration, and so indirectly a date (related to another date, like - UNIX epoch). */ -typedef int64_t _PyTime_t; -#define _PyTime_MIN INT64_MIN -#define _PyTime_MAX INT64_MAX - -typedef enum { - /* Round towards minus infinity (-inf). - For example, used to read a clock. */ - _PyTime_ROUND_FLOOR=0, - /* Round towards infinity (+inf). - For example, used for timeout to wait "at least" N seconds. */ - _PyTime_ROUND_CEILING=1, - /* Round to nearest with ties going to nearest even integer. - For example, used to round from a Python float. */ - _PyTime_ROUND_HALF_EVEN=2, - /* Round away from zero - For example, used for timeout. _PyTime_ROUND_CEILING rounds - -1e-9 to 0 milliseconds which causes bpo-31786 issue. - _PyTime_ROUND_UP rounds -1e-9 to -1 millisecond which keeps - the timeout sign as expected. select.poll(timeout) must block - for negative values." */ - _PyTime_ROUND_UP=3, - /* _PyTime_ROUND_TIMEOUT (an alias for _PyTime_ROUND_UP) should be - used for timeouts. */ - _PyTime_ROUND_TIMEOUT = _PyTime_ROUND_UP -} _PyTime_round_t; - - -/* Convert a time_t to a PyLong. */ -PyAPI_FUNC(PyObject *) _PyLong_FromTime_t( - time_t sec); - -/* Convert a PyLong to a time_t. */ -PyAPI_FUNC(time_t) _PyLong_AsTime_t( - PyObject *obj); - -/* Convert a number of seconds, int or float, to time_t. */ -PyAPI_FUNC(int) _PyTime_ObjectToTime_t( - PyObject *obj, - time_t *sec, - _PyTime_round_t); - -/* Convert a number of seconds, int or float, to a timeval structure. - usec is in the range [0; 999999] and rounded towards zero. - For example, -1.2 is converted to (-2, 800000). */ -PyAPI_FUNC(int) _PyTime_ObjectToTimeval( - PyObject *obj, - time_t *sec, - long *usec, - _PyTime_round_t); - -/* Convert a number of seconds, int or float, to a timespec structure. - nsec is in the range [0; 999999999] and rounded towards zero. - For example, -1.2 is converted to (-2, 800000000). */ -PyAPI_FUNC(int) _PyTime_ObjectToTimespec( - PyObject *obj, - time_t *sec, - long *nsec, - _PyTime_round_t); - - -/* Create a timestamp from a number of seconds. */ -PyAPI_FUNC(_PyTime_t) _PyTime_FromSeconds(int seconds); - -/* Macro to create a timestamp from a number of seconds, no integer overflow. - Only use the macro for small values, prefer _PyTime_FromSeconds(). */ -#define _PYTIME_FROMSECONDS(seconds) \ - ((_PyTime_t)(seconds) * (1000 * 1000 * 1000)) - -/* Create a timestamp from a number of nanoseconds. */ -PyAPI_FUNC(_PyTime_t) _PyTime_FromNanoseconds(_PyTime_t ns); - -/* Create a timestamp from nanoseconds (Python int). */ -PyAPI_FUNC(int) _PyTime_FromNanosecondsObject(_PyTime_t *t, - PyObject *obj); - -/* Convert a number of seconds (Python float or int) to a timetamp. - Raise an exception and return -1 on error, return 0 on success. */ -PyAPI_FUNC(int) _PyTime_FromSecondsObject(_PyTime_t *t, - PyObject *obj, - _PyTime_round_t round); - -/* Convert a number of milliseconds (Python float or int, 10^-3) to a timetamp. - Raise an exception and return -1 on error, return 0 on success. */ -PyAPI_FUNC(int) _PyTime_FromMillisecondsObject(_PyTime_t *t, - PyObject *obj, - _PyTime_round_t round); - -/* Convert a timestamp to a number of seconds as a C double. */ -PyAPI_FUNC(double) _PyTime_AsSecondsDouble(_PyTime_t t); - -/* Convert timestamp to a number of milliseconds (10^-3 seconds). */ -PyAPI_FUNC(_PyTime_t) _PyTime_AsMilliseconds(_PyTime_t t, - _PyTime_round_t round); - -/* Convert timestamp to a number of microseconds (10^-6 seconds). */ -PyAPI_FUNC(_PyTime_t) _PyTime_AsMicroseconds(_PyTime_t t, - _PyTime_round_t round); - -/* Convert timestamp to a number of nanoseconds (10^-9 seconds) as a Python int - object. */ -PyAPI_FUNC(PyObject *) _PyTime_AsNanosecondsObject(_PyTime_t t); - -/* Create a timestamp from a timeval structure. - Raise an exception and return -1 on overflow, return 0 on success. */ -PyAPI_FUNC(int) _PyTime_FromTimeval(_PyTime_t *tp, struct timeval *tv); - -/* Convert a timestamp to a timeval structure (microsecond resolution). - tv_usec is always positive. - Raise an exception and return -1 if the conversion overflowed, - return 0 on success. */ -PyAPI_FUNC(int) _PyTime_AsTimeval(_PyTime_t t, - struct timeval *tv, - _PyTime_round_t round); - -/* Similar to _PyTime_AsTimeval(), but don't raise an exception on error. */ -PyAPI_FUNC(int) _PyTime_AsTimeval_noraise(_PyTime_t t, - struct timeval *tv, - _PyTime_round_t round); - -/* Convert a timestamp to a number of seconds (secs) and microseconds (us). - us is always positive. This function is similar to _PyTime_AsTimeval() - except that secs is always a time_t type, whereas the timeval structure - uses a C long for tv_sec on Windows. - Raise an exception and return -1 if the conversion overflowed, - return 0 on success. */ -PyAPI_FUNC(int) _PyTime_AsTimevalTime_t( - _PyTime_t t, - time_t *secs, - int *us, - _PyTime_round_t round); - -#if defined(HAVE_CLOCK_GETTIME) || defined(HAVE_KQUEUE) -/* Create a timestamp from a timespec structure. - Raise an exception and return -1 on overflow, return 0 on success. */ -PyAPI_FUNC(int) _PyTime_FromTimespec(_PyTime_t *tp, struct timespec *ts); - -/* Convert a timestamp to a timespec structure (nanosecond resolution). - tv_nsec is always positive. - Raise an exception and return -1 on error, return 0 on success. */ -PyAPI_FUNC(int) _PyTime_AsTimespec(_PyTime_t t, struct timespec *ts); -#endif - -/* Compute ticks * mul / div. - The caller must ensure that ((div - 1) * mul) cannot overflow. */ -PyAPI_FUNC(_PyTime_t) _PyTime_MulDiv(_PyTime_t ticks, - _PyTime_t mul, - _PyTime_t div); - -/* Get the current time from the system clock. - - The function cannot fail. _PyTime_Init() ensures that the system clock - works. */ -PyAPI_FUNC(_PyTime_t) _PyTime_GetSystemClock(void); - -/* Get the time of a monotonic clock, i.e. a clock that cannot go backwards. - The clock is not affected by system clock updates. The reference point of - the returned value is undefined, so that only the difference between the - results of consecutive calls is valid. - - The function cannot fail. _PyTime_Init() ensures that a monotonic clock - is available and works. */ -PyAPI_FUNC(_PyTime_t) _PyTime_GetMonotonicClock(void); - - -/* Structure used by time.get_clock_info() */ -typedef struct { - const char *implementation; - int monotonic; - int adjustable; - double resolution; -} _Py_clock_info_t; - -/* Get the current time from the system clock. - * Fill clock information if info is not NULL. - * Raise an exception and return -1 on error, return 0 on success. - */ -PyAPI_FUNC(int) _PyTime_GetSystemClockWithInfo( - _PyTime_t *t, - _Py_clock_info_t *info); - -/* Get the time of a monotonic clock, i.e. a clock that cannot go backwards. - The clock is not affected by system clock updates. The reference point of - the returned value is undefined, so that only the difference between the - results of consecutive calls is valid. - - Fill info (if set) with information of the function used to get the time. - - Return 0 on success, raise an exception and return -1 on error. */ -PyAPI_FUNC(int) _PyTime_GetMonotonicClockWithInfo( - _PyTime_t *t, - _Py_clock_info_t *info); - - -/* Initialize time. - Return 0 on success, raise an exception and return -1 on error. */ -PyAPI_FUNC(int) _PyTime_Init(void); - -/* Converts a timestamp to the Gregorian time, using the local time zone. - Return 0 on success, raise an exception and return -1 on error. */ -PyAPI_FUNC(int) _PyTime_localtime(time_t t, struct tm *tm); - -/* Converts a timestamp to the Gregorian time, assuming UTC. - Return 0 on success, raise an exception and return -1 on error. */ -PyAPI_FUNC(int) _PyTime_gmtime(time_t t, struct tm *tm); - -/* Get the performance counter: clock with the highest available resolution to - measure a short duration. - - The function cannot fail. _PyTime_Init() ensures that the system clock - works. */ -PyAPI_FUNC(_PyTime_t) _PyTime_GetPerfCounter(void); - -/* Get the performance counter: clock with the highest available resolution to - measure a short duration. - - Fill info (if set) with information of the function used to get the time. - - Return 0 on success, raise an exception and return -1 on error. */ -PyAPI_FUNC(int) _PyTime_GetPerfCounterWithInfo( - _PyTime_t *t, - _Py_clock_info_t *info); - -#ifdef __cplusplus -} -#endif - -#endif /* Py_PYTIME_H */ -#endif /* Py_LIMITED_API */ diff --git a/scripts/build-windows/py39-libs/include/rangeobject.h b/scripts/build-windows/py39-libs/include/rangeobject.h deleted file mode 100644 index d2105d026..000000000 --- a/scripts/build-windows/py39-libs/include/rangeobject.h +++ /dev/null @@ -1,27 +0,0 @@ - -/* Range object interface */ - -#ifndef Py_RANGEOBJECT_H -#define Py_RANGEOBJECT_H -#ifdef __cplusplus -extern "C" { -#endif - -/* -A range object represents an integer range. This is an immutable object; -a range cannot change its value after creation. - -Range objects behave like the corresponding tuple objects except that -they are represented by a start, stop, and step datamembers. -*/ - -PyAPI_DATA(PyTypeObject) PyRange_Type; -PyAPI_DATA(PyTypeObject) PyRangeIter_Type; -PyAPI_DATA(PyTypeObject) PyLongRangeIter_Type; - -#define PyRange_Check(op) Py_IS_TYPE(op, &PyRange_Type) - -#ifdef __cplusplus -} -#endif -#endif /* !Py_RANGEOBJECT_H */ diff --git a/scripts/build-windows/py39-libs/include/setobject.h b/scripts/build-windows/py39-libs/include/setobject.h deleted file mode 100644 index 24ae8f4d6..000000000 --- a/scripts/build-windows/py39-libs/include/setobject.h +++ /dev/null @@ -1,107 +0,0 @@ -/* Set object interface */ - -#ifndef Py_SETOBJECT_H -#define Py_SETOBJECT_H -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef Py_LIMITED_API - -/* There are three kinds of entries in the table: - -1. Unused: key == NULL and hash == 0 -2. Dummy: key == dummy and hash == -1 -3. Active: key != NULL and key != dummy and hash != -1 - -The hash field of Unused slots is always zero. - -The hash field of Dummy slots are set to -1 -meaning that dummy entries can be detected by -either entry->key==dummy or by entry->hash==-1. -*/ - -#define PySet_MINSIZE 8 - -typedef struct { - PyObject *key; - Py_hash_t hash; /* Cached hash code of the key */ -} setentry; - -/* The SetObject data structure is shared by set and frozenset objects. - -Invariant for sets: - - hash is -1 - -Invariants for frozensets: - - data is immutable. - - hash is the hash of the frozenset or -1 if not computed yet. - -*/ - -typedef struct { - PyObject_HEAD - - Py_ssize_t fill; /* Number active and dummy entries*/ - Py_ssize_t used; /* Number active entries */ - - /* The table contains mask + 1 slots, and that's a power of 2. - * We store the mask instead of the size because the mask is more - * frequently needed. - */ - Py_ssize_t mask; - - /* The table points to a fixed-size smalltable for small tables - * or to additional malloc'ed memory for bigger tables. - * The table pointer is never NULL which saves us from repeated - * runtime null-tests. - */ - setentry *table; - Py_hash_t hash; /* Only used by frozenset objects */ - Py_ssize_t finger; /* Search finger for pop() */ - - setentry smalltable[PySet_MINSIZE]; - PyObject *weakreflist; /* List of weak references */ -} PySetObject; - -#define PySet_GET_SIZE(so) (assert(PyAnySet_Check(so)),(((PySetObject *)(so))->used)) - -PyAPI_DATA(PyObject *) _PySet_Dummy; - -PyAPI_FUNC(int) _PySet_NextEntry(PyObject *set, Py_ssize_t *pos, PyObject **key, Py_hash_t *hash); -PyAPI_FUNC(int) _PySet_Update(PyObject *set, PyObject *iterable); - -#endif /* Section excluded by Py_LIMITED_API */ - -PyAPI_DATA(PyTypeObject) PySet_Type; -PyAPI_DATA(PyTypeObject) PyFrozenSet_Type; -PyAPI_DATA(PyTypeObject) PySetIter_Type; - -PyAPI_FUNC(PyObject *) PySet_New(PyObject *); -PyAPI_FUNC(PyObject *) PyFrozenSet_New(PyObject *); - -PyAPI_FUNC(int) PySet_Add(PyObject *set, PyObject *key); -PyAPI_FUNC(int) PySet_Clear(PyObject *set); -PyAPI_FUNC(int) PySet_Contains(PyObject *anyset, PyObject *key); -PyAPI_FUNC(int) PySet_Discard(PyObject *set, PyObject *key); -PyAPI_FUNC(PyObject *) PySet_Pop(PyObject *set); -PyAPI_FUNC(Py_ssize_t) PySet_Size(PyObject *anyset); - -#define PyFrozenSet_CheckExact(ob) Py_IS_TYPE(ob, &PyFrozenSet_Type) -#define PyAnySet_CheckExact(ob) \ - (Py_IS_TYPE(ob, &PySet_Type) || Py_IS_TYPE(ob, &PyFrozenSet_Type)) -#define PyAnySet_Check(ob) \ - (Py_IS_TYPE(ob, &PySet_Type) || Py_IS_TYPE(ob, &PyFrozenSet_Type) || \ - PyType_IsSubtype(Py_TYPE(ob), &PySet_Type) || \ - PyType_IsSubtype(Py_TYPE(ob), &PyFrozenSet_Type)) -#define PySet_Check(ob) \ - (Py_IS_TYPE(ob, &PySet_Type) || \ - PyType_IsSubtype(Py_TYPE(ob), &PySet_Type)) -#define PyFrozenSet_Check(ob) \ - (Py_IS_TYPE(ob, &PyFrozenSet_Type) || \ - PyType_IsSubtype(Py_TYPE(ob), &PyFrozenSet_Type)) - -#ifdef __cplusplus -} -#endif -#endif /* !Py_SETOBJECT_H */ diff --git a/scripts/build-windows/py39-libs/include/sliceobject.h b/scripts/build-windows/py39-libs/include/sliceobject.h deleted file mode 100644 index c41506046..000000000 --- a/scripts/build-windows/py39-libs/include/sliceobject.h +++ /dev/null @@ -1,65 +0,0 @@ -#ifndef Py_SLICEOBJECT_H -#define Py_SLICEOBJECT_H -#ifdef __cplusplus -extern "C" { -#endif - -/* The unique ellipsis object "..." */ - -PyAPI_DATA(PyObject) _Py_EllipsisObject; /* Don't use this directly */ - -#define Py_Ellipsis (&_Py_EllipsisObject) - -/* Slice object interface */ - -/* - -A slice object containing start, stop, and step data members (the -names are from range). After much talk with Guido, it was decided to -let these be any arbitrary python type. Py_None stands for omitted values. -*/ -#ifndef Py_LIMITED_API -typedef struct { - PyObject_HEAD - PyObject *start, *stop, *step; /* not NULL */ -} PySliceObject; -#endif - -PyAPI_DATA(PyTypeObject) PySlice_Type; -PyAPI_DATA(PyTypeObject) PyEllipsis_Type; - -#define PySlice_Check(op) Py_IS_TYPE(op, &PySlice_Type) - -PyAPI_FUNC(PyObject *) PySlice_New(PyObject* start, PyObject* stop, - PyObject* step); -#ifndef Py_LIMITED_API -PyAPI_FUNC(PyObject *) _PySlice_FromIndices(Py_ssize_t start, Py_ssize_t stop); -PyAPI_FUNC(int) _PySlice_GetLongIndices(PySliceObject *self, PyObject *length, - PyObject **start_ptr, PyObject **stop_ptr, - PyObject **step_ptr); -#endif -PyAPI_FUNC(int) PySlice_GetIndices(PyObject *r, Py_ssize_t length, - Py_ssize_t *start, Py_ssize_t *stop, Py_ssize_t *step); -Py_DEPRECATED(3.7) -PyAPI_FUNC(int) PySlice_GetIndicesEx(PyObject *r, Py_ssize_t length, - Py_ssize_t *start, Py_ssize_t *stop, - Py_ssize_t *step, - Py_ssize_t *slicelength); - -#if !defined(Py_LIMITED_API) || (Py_LIMITED_API+0 >= 0x03050400 && Py_LIMITED_API+0 < 0x03060000) || Py_LIMITED_API+0 >= 0x03060100 -#define PySlice_GetIndicesEx(slice, length, start, stop, step, slicelen) ( \ - PySlice_Unpack((slice), (start), (stop), (step)) < 0 ? \ - ((*(slicelen) = 0), -1) : \ - ((*(slicelen) = PySlice_AdjustIndices((length), (start), (stop), *(step))), \ - 0)) -PyAPI_FUNC(int) PySlice_Unpack(PyObject *slice, - Py_ssize_t *start, Py_ssize_t *stop, Py_ssize_t *step); -PyAPI_FUNC(Py_ssize_t) PySlice_AdjustIndices(Py_ssize_t length, - Py_ssize_t *start, Py_ssize_t *stop, - Py_ssize_t step); -#endif - -#ifdef __cplusplus -} -#endif -#endif /* !Py_SLICEOBJECT_H */ diff --git a/scripts/build-windows/py39-libs/include/structmember.h b/scripts/build-windows/py39-libs/include/structmember.h deleted file mode 100644 index af01afe72..000000000 --- a/scripts/build-windows/py39-libs/include/structmember.h +++ /dev/null @@ -1,74 +0,0 @@ -#ifndef Py_STRUCTMEMBER_H -#define Py_STRUCTMEMBER_H -#ifdef __cplusplus -extern "C" { -#endif - - -/* Interface to map C struct members to Python object attributes */ - -#include /* For offsetof */ - -/* An array of PyMemberDef structures defines the name, type and offset - of selected members of a C structure. These can be read by - PyMember_GetOne() and set by PyMember_SetOne() (except if their READONLY - flag is set). The array must be terminated with an entry whose name - pointer is NULL. */ - -typedef struct PyMemberDef { - const char *name; - int type; - Py_ssize_t offset; - int flags; - const char *doc; -} PyMemberDef; - -/* Types */ -#define T_SHORT 0 -#define T_INT 1 -#define T_LONG 2 -#define T_FLOAT 3 -#define T_DOUBLE 4 -#define T_STRING 5 -#define T_OBJECT 6 -/* XXX the ordering here is weird for binary compatibility */ -#define T_CHAR 7 /* 1-character string */ -#define T_BYTE 8 /* 8-bit signed int */ -/* unsigned variants: */ -#define T_UBYTE 9 -#define T_USHORT 10 -#define T_UINT 11 -#define T_ULONG 12 - -/* Added by Jack: strings contained in the structure */ -#define T_STRING_INPLACE 13 - -/* Added by Lillo: bools contained in the structure (assumed char) */ -#define T_BOOL 14 - -#define T_OBJECT_EX 16 /* Like T_OBJECT, but raises AttributeError - when the value is NULL, instead of - converting to None. */ -#define T_LONGLONG 17 -#define T_ULONGLONG 18 - -#define T_PYSSIZET 19 /* Py_ssize_t */ -#define T_NONE 20 /* Value is always None */ - - -/* Flags */ -#define READONLY 1 -#define READ_RESTRICTED 2 -#define PY_WRITE_RESTRICTED 4 -#define RESTRICTED (READ_RESTRICTED | PY_WRITE_RESTRICTED) - - -/* Current API, use this */ -PyAPI_FUNC(PyObject *) PyMember_GetOne(const char *, struct PyMemberDef *); -PyAPI_FUNC(int) PyMember_SetOne(char *, struct PyMemberDef *, PyObject *); - - -#ifdef __cplusplus -} -#endif -#endif /* !Py_STRUCTMEMBER_H */ diff --git a/scripts/build-windows/py39-libs/include/structseq.h b/scripts/build-windows/py39-libs/include/structseq.h deleted file mode 100644 index e67bfda7e..000000000 --- a/scripts/build-windows/py39-libs/include/structseq.h +++ /dev/null @@ -1,49 +0,0 @@ - -/* Named tuple object interface */ - -#ifndef Py_STRUCTSEQ_H -#define Py_STRUCTSEQ_H -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct PyStructSequence_Field { - const char *name; - const char *doc; -} PyStructSequence_Field; - -typedef struct PyStructSequence_Desc { - const char *name; - const char *doc; - struct PyStructSequence_Field *fields; - int n_in_sequence; -} PyStructSequence_Desc; - -extern const char * const PyStructSequence_UnnamedField; - -#ifndef Py_LIMITED_API -PyAPI_FUNC(void) PyStructSequence_InitType(PyTypeObject *type, - PyStructSequence_Desc *desc); -PyAPI_FUNC(int) PyStructSequence_InitType2(PyTypeObject *type, - PyStructSequence_Desc *desc); -#endif -PyAPI_FUNC(PyTypeObject*) PyStructSequence_NewType(PyStructSequence_Desc *desc); - -PyAPI_FUNC(PyObject *) PyStructSequence_New(PyTypeObject* type); - -#ifndef Py_LIMITED_API -typedef PyTupleObject PyStructSequence; - -/* Macro, *only* to be used to fill in brand new objects */ -#define PyStructSequence_SET_ITEM(op, i, v) PyTuple_SET_ITEM(op, i, v) - -#define PyStructSequence_GET_ITEM(op, i) PyTuple_GET_ITEM(op, i) -#endif - -PyAPI_FUNC(void) PyStructSequence_SetItem(PyObject*, Py_ssize_t, PyObject*); -PyAPI_FUNC(PyObject*) PyStructSequence_GetItem(PyObject*, Py_ssize_t); - -#ifdef __cplusplus -} -#endif -#endif /* !Py_STRUCTSEQ_H */ diff --git a/scripts/build-windows/py39-libs/include/symtable.h b/scripts/build-windows/py39-libs/include/symtable.h deleted file mode 100644 index 5f490df2c..000000000 --- a/scripts/build-windows/py39-libs/include/symtable.h +++ /dev/null @@ -1,123 +0,0 @@ -#ifndef Py_LIMITED_API -#ifndef Py_SYMTABLE_H -#define Py_SYMTABLE_H -#ifdef __cplusplus -extern "C" { -#endif - -#include "Python-ast.h" /* mod_ty */ - -/* XXX(ncoghlan): This is a weird mix of public names and interpreter internal - * names. - */ - -typedef enum _block_type { FunctionBlock, ClassBlock, ModuleBlock } - _Py_block_ty; - -struct _symtable_entry; - -struct symtable { - PyObject *st_filename; /* name of file being compiled, - decoded from the filesystem encoding */ - struct _symtable_entry *st_cur; /* current symbol table entry */ - struct _symtable_entry *st_top; /* symbol table entry for module */ - PyObject *st_blocks; /* dict: map AST node addresses - * to symbol table entries */ - PyObject *st_stack; /* list: stack of namespace info */ - PyObject *st_global; /* borrowed ref to st_top->ste_symbols */ - int st_nblocks; /* number of blocks used. kept for - consistency with the corresponding - compiler structure */ - PyObject *st_private; /* name of current class or NULL */ - PyFutureFeatures *st_future; /* module's future features that affect - the symbol table */ - int recursion_depth; /* current recursion depth */ - int recursion_limit; /* recursion limit */ -}; - -typedef struct _symtable_entry { - PyObject_HEAD - PyObject *ste_id; /* int: key in ste_table->st_blocks */ - PyObject *ste_symbols; /* dict: variable names to flags */ - PyObject *ste_name; /* string: name of current block */ - PyObject *ste_varnames; /* list of function parameters */ - PyObject *ste_children; /* list of child blocks */ - PyObject *ste_directives;/* locations of global and nonlocal statements */ - _Py_block_ty ste_type; /* module, class, or function */ - int ste_nested; /* true if block is nested */ - unsigned ste_free : 1; /* true if block has free variables */ - unsigned ste_child_free : 1; /* true if a child block has free vars, - including free refs to globals */ - unsigned ste_generator : 1; /* true if namespace is a generator */ - unsigned ste_coroutine : 1; /* true if namespace is a coroutine */ - unsigned ste_comprehension : 1; /* true if namespace is a list comprehension */ - unsigned ste_varargs : 1; /* true if block has varargs */ - unsigned ste_varkeywords : 1; /* true if block has varkeywords */ - unsigned ste_returns_value : 1; /* true if namespace uses return with - an argument */ - unsigned ste_needs_class_closure : 1; /* for class scopes, true if a - closure over __class__ - should be created */ - unsigned ste_comp_iter_target : 1; /* true if visiting comprehension target */ - int ste_comp_iter_expr; /* non-zero if visiting a comprehension range expression */ - int ste_lineno; /* first line of block */ - int ste_col_offset; /* offset of first line of block */ - int ste_opt_lineno; /* lineno of last exec or import * */ - int ste_opt_col_offset; /* offset of last exec or import * */ - struct symtable *ste_table; -} PySTEntryObject; - -PyAPI_DATA(PyTypeObject) PySTEntry_Type; - -#define PySTEntry_Check(op) Py_IS_TYPE(op, &PySTEntry_Type) - -PyAPI_FUNC(int) PyST_GetScope(PySTEntryObject *, PyObject *); - -PyAPI_FUNC(struct symtable *) PySymtable_Build( - mod_ty mod, - const char *filename, /* decoded from the filesystem encoding */ - PyFutureFeatures *future); -PyAPI_FUNC(struct symtable *) PySymtable_BuildObject( - mod_ty mod, - PyObject *filename, - PyFutureFeatures *future); -PyAPI_FUNC(PySTEntryObject *) PySymtable_Lookup(struct symtable *, void *); - -PyAPI_FUNC(void) PySymtable_Free(struct symtable *); - -/* Flags for def-use information */ - -#define DEF_GLOBAL 1 /* global stmt */ -#define DEF_LOCAL 2 /* assignment in code block */ -#define DEF_PARAM 2<<1 /* formal parameter */ -#define DEF_NONLOCAL 2<<2 /* nonlocal stmt */ -#define USE 2<<3 /* name is used */ -#define DEF_FREE 2<<4 /* name used but not defined in nested block */ -#define DEF_FREE_CLASS 2<<5 /* free variable from class's method */ -#define DEF_IMPORT 2<<6 /* assignment occurred via import */ -#define DEF_ANNOT 2<<7 /* this name is annotated */ -#define DEF_COMP_ITER 2<<8 /* this name is a comprehension iteration variable */ - -#define DEF_BOUND (DEF_LOCAL | DEF_PARAM | DEF_IMPORT) - -/* GLOBAL_EXPLICIT and GLOBAL_IMPLICIT are used internally by the symbol - table. GLOBAL is returned from PyST_GetScope() for either of them. - It is stored in ste_symbols at bits 12-15. -*/ -#define SCOPE_OFFSET 11 -#define SCOPE_MASK (DEF_GLOBAL | DEF_LOCAL | DEF_PARAM | DEF_NONLOCAL) - -#define LOCAL 1 -#define GLOBAL_EXPLICIT 2 -#define GLOBAL_IMPLICIT 3 -#define FREE 4 -#define CELL 5 - -#define GENERATOR 1 -#define GENERATOR_EXPRESSION 2 - -#ifdef __cplusplus -} -#endif -#endif /* !Py_SYMTABLE_H */ -#endif /* !Py_LIMITED_API */ diff --git a/scripts/build-windows/py39-libs/include/sysmodule.h b/scripts/build-windows/py39-libs/include/sysmodule.h deleted file mode 100644 index 388744258..000000000 --- a/scripts/build-windows/py39-libs/include/sysmodule.h +++ /dev/null @@ -1,41 +0,0 @@ - -/* System module interface */ - -#ifndef Py_SYSMODULE_H -#define Py_SYSMODULE_H -#ifdef __cplusplus -extern "C" { -#endif - -PyAPI_FUNC(PyObject *) PySys_GetObject(const char *); -PyAPI_FUNC(int) PySys_SetObject(const char *, PyObject *); - -PyAPI_FUNC(void) PySys_SetArgv(int, wchar_t **); -PyAPI_FUNC(void) PySys_SetArgvEx(int, wchar_t **, int); -PyAPI_FUNC(void) PySys_SetPath(const wchar_t *); - -PyAPI_FUNC(void) PySys_WriteStdout(const char *format, ...) - Py_GCC_ATTRIBUTE((format(printf, 1, 2))); -PyAPI_FUNC(void) PySys_WriteStderr(const char *format, ...) - Py_GCC_ATTRIBUTE((format(printf, 1, 2))); -PyAPI_FUNC(void) PySys_FormatStdout(const char *format, ...); -PyAPI_FUNC(void) PySys_FormatStderr(const char *format, ...); - -PyAPI_FUNC(void) PySys_ResetWarnOptions(void); -PyAPI_FUNC(void) PySys_AddWarnOption(const wchar_t *); -PyAPI_FUNC(void) PySys_AddWarnOptionUnicode(PyObject *); -PyAPI_FUNC(int) PySys_HasWarnOptions(void); - -PyAPI_FUNC(void) PySys_AddXOption(const wchar_t *); -PyAPI_FUNC(PyObject *) PySys_GetXOptions(void); - -#ifndef Py_LIMITED_API -# define Py_CPYTHON_SYSMODULE_H -# include "cpython/sysmodule.h" -# undef Py_CPYTHON_SYSMODULE_H -#endif - -#ifdef __cplusplus -} -#endif -#endif /* !Py_SYSMODULE_H */ diff --git a/scripts/build-windows/py39-libs/include/token.h b/scripts/build-windows/py39-libs/include/token.h deleted file mode 100644 index 80c3e2517..000000000 --- a/scripts/build-windows/py39-libs/include/token.h +++ /dev/null @@ -1,96 +0,0 @@ -/* Auto-generated by Tools/scripts/generate_token.py */ - -/* Token types */ -#ifndef Py_LIMITED_API -#ifndef Py_TOKEN_H -#define Py_TOKEN_H -#ifdef __cplusplus -extern "C" { -#endif - -#undef TILDE /* Prevent clash of our definition with system macro. Ex AIX, ioctl.h */ - -#define ENDMARKER 0 -#define NAME 1 -#define NUMBER 2 -#define STRING 3 -#define NEWLINE 4 -#define INDENT 5 -#define DEDENT 6 -#define LPAR 7 -#define RPAR 8 -#define LSQB 9 -#define RSQB 10 -#define COLON 11 -#define COMMA 12 -#define SEMI 13 -#define PLUS 14 -#define MINUS 15 -#define STAR 16 -#define SLASH 17 -#define VBAR 18 -#define AMPER 19 -#define LESS 20 -#define GREATER 21 -#define EQUAL 22 -#define DOT 23 -#define PERCENT 24 -#define LBRACE 25 -#define RBRACE 26 -#define EQEQUAL 27 -#define NOTEQUAL 28 -#define LESSEQUAL 29 -#define GREATEREQUAL 30 -#define TILDE 31 -#define CIRCUMFLEX 32 -#define LEFTSHIFT 33 -#define RIGHTSHIFT 34 -#define DOUBLESTAR 35 -#define PLUSEQUAL 36 -#define MINEQUAL 37 -#define STAREQUAL 38 -#define SLASHEQUAL 39 -#define PERCENTEQUAL 40 -#define AMPEREQUAL 41 -#define VBAREQUAL 42 -#define CIRCUMFLEXEQUAL 43 -#define LEFTSHIFTEQUAL 44 -#define RIGHTSHIFTEQUAL 45 -#define DOUBLESTAREQUAL 46 -#define DOUBLESLASH 47 -#define DOUBLESLASHEQUAL 48 -#define AT 49 -#define ATEQUAL 50 -#define RARROW 51 -#define ELLIPSIS 52 -#define COLONEQUAL 53 -#define OP 54 -#define AWAIT 55 -#define ASYNC 56 -#define TYPE_IGNORE 57 -#define TYPE_COMMENT 58 -#define ERRORTOKEN 59 -#define N_TOKENS 63 -#define NT_OFFSET 256 - -/* Special definitions for cooperation with parser */ - -#define ISTERMINAL(x) ((x) < NT_OFFSET) -#define ISNONTERMINAL(x) ((x) >= NT_OFFSET) -#define ISEOF(x) ((x) == ENDMARKER) -#define ISWHITESPACE(x) ((x) == ENDMARKER || \ - (x) == NEWLINE || \ - (x) == INDENT || \ - (x) == DEDENT) - - -PyAPI_DATA(const char * const) _PyParser_TokenNames[]; /* Token names */ -PyAPI_FUNC(int) PyToken_OneChar(int); -PyAPI_FUNC(int) PyToken_TwoChars(int, int); -PyAPI_FUNC(int) PyToken_ThreeChars(int, int, int); - -#ifdef __cplusplus -} -#endif -#endif /* !Py_TOKEN_H */ -#endif /* Py_LIMITED_API */ diff --git a/scripts/build-windows/py39-libs/include/traceback.h b/scripts/build-windows/py39-libs/include/traceback.h deleted file mode 100644 index b4466f517..000000000 --- a/scripts/build-windows/py39-libs/include/traceback.h +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef Py_TRACEBACK_H -#define Py_TRACEBACK_H -#ifdef __cplusplus -extern "C" { -#endif - -/* Traceback interface */ - -PyAPI_FUNC(int) PyTraceBack_Here(PyFrameObject *); -PyAPI_FUNC(int) PyTraceBack_Print(PyObject *, PyObject *); - -/* Reveal traceback type so we can typecheck traceback objects */ -PyAPI_DATA(PyTypeObject) PyTraceBack_Type; -#define PyTraceBack_Check(v) Py_IS_TYPE(v, &PyTraceBack_Type) - - -#ifndef Py_LIMITED_API -# define Py_CPYTHON_TRACEBACK_H -# include "cpython/traceback.h" -# undef Py_CPYTHON_TRACEBACK_H -#endif - -#ifdef __cplusplus -} -#endif -#endif /* !Py_TRACEBACK_H */ diff --git a/scripts/build-windows/py39-libs/include/tracemalloc.h b/scripts/build-windows/py39-libs/include/tracemalloc.h deleted file mode 100644 index 05b4cc16f..000000000 --- a/scripts/build-windows/py39-libs/include/tracemalloc.h +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef Py_TRACEMALLOC_H -#define Py_TRACEMALLOC_H - -#ifndef Py_LIMITED_API -/* Track an allocated memory block in the tracemalloc module. - Return 0 on success, return -1 on error (failed to allocate memory to store - the trace). - - Return -2 if tracemalloc is disabled. - - If memory block is already tracked, update the existing trace. */ -PyAPI_FUNC(int) PyTraceMalloc_Track( - unsigned int domain, - uintptr_t ptr, - size_t size); - -/* Untrack an allocated memory block in the tracemalloc module. - Do nothing if the block was not tracked. - - Return -2 if tracemalloc is disabled, otherwise return 0. */ -PyAPI_FUNC(int) PyTraceMalloc_Untrack( - unsigned int domain, - uintptr_t ptr); - -/* Get the traceback where a memory block was allocated. - - Return a tuple of (filename: str, lineno: int) tuples. - - Return None if the tracemalloc module is disabled or if the memory block - is not tracked by tracemalloc. - - Raise an exception and return NULL on error. */ -PyAPI_FUNC(PyObject*) _PyTraceMalloc_GetTraceback( - unsigned int domain, - uintptr_t ptr); -#endif - -#endif /* !Py_TRACEMALLOC_H */ diff --git a/scripts/build-windows/py39-libs/include/tupleobject.h b/scripts/build-windows/py39-libs/include/tupleobject.h deleted file mode 100644 index 19f9997e7..000000000 --- a/scripts/build-windows/py39-libs/include/tupleobject.h +++ /dev/null @@ -1,46 +0,0 @@ -/* Tuple object interface */ - -#ifndef Py_TUPLEOBJECT_H -#define Py_TUPLEOBJECT_H -#ifdef __cplusplus -extern "C" { -#endif - -/* -Another generally useful object type is a tuple of object pointers. -For Python, this is an immutable type. C code can change the tuple items -(but not their number), and even use tuples as general-purpose arrays of -object references, but in general only brand new tuples should be mutated, -not ones that might already have been exposed to Python code. - -*** WARNING *** PyTuple_SetItem does not increment the new item's reference -count, but does decrement the reference count of the item it replaces, -if not nil. It does *decrement* the reference count if it is *not* -inserted in the tuple. Similarly, PyTuple_GetItem does not increment the -returned item's reference count. -*/ - -PyAPI_DATA(PyTypeObject) PyTuple_Type; -PyAPI_DATA(PyTypeObject) PyTupleIter_Type; - -#define PyTuple_Check(op) \ - PyType_FastSubclass(Py_TYPE(op), Py_TPFLAGS_TUPLE_SUBCLASS) -#define PyTuple_CheckExact(op) Py_IS_TYPE(op, &PyTuple_Type) - -PyAPI_FUNC(PyObject *) PyTuple_New(Py_ssize_t size); -PyAPI_FUNC(Py_ssize_t) PyTuple_Size(PyObject *); -PyAPI_FUNC(PyObject *) PyTuple_GetItem(PyObject *, Py_ssize_t); -PyAPI_FUNC(int) PyTuple_SetItem(PyObject *, Py_ssize_t, PyObject *); -PyAPI_FUNC(PyObject *) PyTuple_GetSlice(PyObject *, Py_ssize_t, Py_ssize_t); -PyAPI_FUNC(PyObject *) PyTuple_Pack(Py_ssize_t, ...); - -#ifndef Py_LIMITED_API -# define Py_CPYTHON_TUPLEOBJECT_H -# include "cpython/tupleobject.h" -# undef Py_CPYTHON_TUPLEOBJECT_H -#endif - -#ifdef __cplusplus -} -#endif -#endif /* !Py_TUPLEOBJECT_H */ diff --git a/scripts/build-windows/py39-libs/include/typeslots.h b/scripts/build-windows/py39-libs/include/typeslots.h deleted file mode 100644 index 29111f94d..000000000 --- a/scripts/build-windows/py39-libs/include/typeslots.h +++ /dev/null @@ -1,90 +0,0 @@ -/* Do not renumber the file; these numbers are part of the stable ABI. */ -#if defined(Py_LIMITED_API) -/* Disabled, see #10181 */ -#undef Py_bf_getbuffer -#undef Py_bf_releasebuffer -#else -#define Py_bf_getbuffer 1 -#define Py_bf_releasebuffer 2 -#endif -#define Py_mp_ass_subscript 3 -#define Py_mp_length 4 -#define Py_mp_subscript 5 -#define Py_nb_absolute 6 -#define Py_nb_add 7 -#define Py_nb_and 8 -#define Py_nb_bool 9 -#define Py_nb_divmod 10 -#define Py_nb_float 11 -#define Py_nb_floor_divide 12 -#define Py_nb_index 13 -#define Py_nb_inplace_add 14 -#define Py_nb_inplace_and 15 -#define Py_nb_inplace_floor_divide 16 -#define Py_nb_inplace_lshift 17 -#define Py_nb_inplace_multiply 18 -#define Py_nb_inplace_or 19 -#define Py_nb_inplace_power 20 -#define Py_nb_inplace_remainder 21 -#define Py_nb_inplace_rshift 22 -#define Py_nb_inplace_subtract 23 -#define Py_nb_inplace_true_divide 24 -#define Py_nb_inplace_xor 25 -#define Py_nb_int 26 -#define Py_nb_invert 27 -#define Py_nb_lshift 28 -#define Py_nb_multiply 29 -#define Py_nb_negative 30 -#define Py_nb_or 31 -#define Py_nb_positive 32 -#define Py_nb_power 33 -#define Py_nb_remainder 34 -#define Py_nb_rshift 35 -#define Py_nb_subtract 36 -#define Py_nb_true_divide 37 -#define Py_nb_xor 38 -#define Py_sq_ass_item 39 -#define Py_sq_concat 40 -#define Py_sq_contains 41 -#define Py_sq_inplace_concat 42 -#define Py_sq_inplace_repeat 43 -#define Py_sq_item 44 -#define Py_sq_length 45 -#define Py_sq_repeat 46 -#define Py_tp_alloc 47 -#define Py_tp_base 48 -#define Py_tp_bases 49 -#define Py_tp_call 50 -#define Py_tp_clear 51 -#define Py_tp_dealloc 52 -#define Py_tp_del 53 -#define Py_tp_descr_get 54 -#define Py_tp_descr_set 55 -#define Py_tp_doc 56 -#define Py_tp_getattr 57 -#define Py_tp_getattro 58 -#define Py_tp_hash 59 -#define Py_tp_init 60 -#define Py_tp_is_gc 61 -#define Py_tp_iter 62 -#define Py_tp_iternext 63 -#define Py_tp_methods 64 -#define Py_tp_new 65 -#define Py_tp_repr 66 -#define Py_tp_richcompare 67 -#define Py_tp_setattr 68 -#define Py_tp_setattro 69 -#define Py_tp_str 70 -#define Py_tp_traverse 71 -#define Py_tp_members 72 -#define Py_tp_getset 73 -#define Py_tp_free 74 -#define Py_nb_matrix_multiply 75 -#define Py_nb_inplace_matrix_multiply 76 -#define Py_am_await 77 -#define Py_am_aiter 78 -#define Py_am_anext 79 -#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03050000 -/* New in 3.5 */ -#define Py_tp_finalize 80 -#endif diff --git a/scripts/build-windows/py39-libs/include/ucnhash.h b/scripts/build-windows/py39-libs/include/ucnhash.h deleted file mode 100644 index 6d1a29fbe..000000000 --- a/scripts/build-windows/py39-libs/include/ucnhash.h +++ /dev/null @@ -1,36 +0,0 @@ -/* Unicode name database interface */ -#ifndef Py_LIMITED_API -#ifndef Py_UCNHASH_H -#define Py_UCNHASH_H -#ifdef __cplusplus -extern "C" { -#endif - -/* revised ucnhash CAPI interface (exported through a "wrapper") */ - -#define PyUnicodeData_CAPSULE_NAME "unicodedata.ucnhash_CAPI" - -typedef struct { - - /* Size of this struct */ - int size; - - /* Get name for a given character code. Returns non-zero if - success, zero if not. Does not set Python exceptions. - If self is NULL, data come from the default version of the database. - If it is not NULL, it should be a unicodedata.ucd_X_Y_Z object */ - int (*getname)(PyObject *self, Py_UCS4 code, char* buffer, int buflen, - int with_alias_and_seq); - - /* Get character code for a given name. Same error handling - as for getname. */ - int (*getcode)(PyObject *self, const char* name, int namelen, Py_UCS4* code, - int with_named_seq); - -} _PyUnicode_Name_CAPI; - -#ifdef __cplusplus -} -#endif -#endif /* !Py_UCNHASH_H */ -#endif /* !Py_LIMITED_API */ diff --git a/scripts/build-windows/py39-libs/include/unicodeobject.h b/scripts/build-windows/py39-libs/include/unicodeobject.h deleted file mode 100644 index 4213945b2..000000000 --- a/scripts/build-windows/py39-libs/include/unicodeobject.h +++ /dev/null @@ -1,1033 +0,0 @@ -#ifndef Py_UNICODEOBJECT_H -#define Py_UNICODEOBJECT_H - -#include - -/* - -Unicode implementation based on original code by Fredrik Lundh, -modified by Marc-Andre Lemburg (mal@lemburg.com) according to the -Unicode Integration Proposal. (See -http://www.egenix.com/files/python/unicode-proposal.txt). - -Copyright (c) Corporation for National Research Initiatives. - - - Original header: - -------------------------------------------------------------------- - - * Yet another Unicode string type for Python. This type supports the - * 16-bit Basic Multilingual Plane (BMP) only. - * - * Written by Fredrik Lundh, January 1999. - * - * Copyright (c) 1999 by Secret Labs AB. - * Copyright (c) 1999 by Fredrik Lundh. - * - * fredrik@pythonware.com - * http://www.pythonware.com - * - * -------------------------------------------------------------------- - * This Unicode String Type is - * - * Copyright (c) 1999 by Secret Labs AB - * Copyright (c) 1999 by Fredrik Lundh - * - * By obtaining, using, and/or copying this software and/or its - * associated documentation, you agree that you have read, understood, - * and will comply with the following terms and conditions: - * - * Permission to use, copy, modify, and distribute this software and its - * associated documentation for any purpose and without fee is hereby - * granted, provided that the above copyright notice appears in all - * copies, and that both that copyright notice and this permission notice - * appear in supporting documentation, and that the name of Secret Labs - * AB or the author not be used in advertising or publicity pertaining to - * distribution of the software without specific, written prior - * permission. - * - * SECRET LABS AB AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO - * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS. IN NO EVENT SHALL SECRET LABS AB OR THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT - * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * -------------------------------------------------------------------- */ - -#include - -/* === Internal API ======================================================= */ - -/* --- Internal Unicode Format -------------------------------------------- */ - -/* Python 3.x requires unicode */ -#define Py_USING_UNICODE - -#ifndef SIZEOF_WCHAR_T -#error Must define SIZEOF_WCHAR_T -#endif - -#define Py_UNICODE_SIZE SIZEOF_WCHAR_T - -/* If wchar_t can be used for UCS-4 storage, set Py_UNICODE_WIDE. - Otherwise, Unicode strings are stored as UCS-2 (with limited support - for UTF-16) */ - -#if Py_UNICODE_SIZE >= 4 -#define Py_UNICODE_WIDE -#endif - -/* Set these flags if the platform has "wchar.h" and the - wchar_t type is a 16-bit unsigned type */ -/* #define HAVE_WCHAR_H */ -/* #define HAVE_USABLE_WCHAR_T */ - -/* If the compiler provides a wchar_t type we try to support it - through the interface functions PyUnicode_FromWideChar(), - PyUnicode_AsWideChar() and PyUnicode_AsWideCharString(). */ - -#ifdef HAVE_USABLE_WCHAR_T -# ifndef HAVE_WCHAR_H -# define HAVE_WCHAR_H -# endif -#endif - -#ifdef HAVE_WCHAR_H -# include -#endif - -/* Py_UCS4 and Py_UCS2 are typedefs for the respective - unicode representations. */ -typedef uint32_t Py_UCS4; -typedef uint16_t Py_UCS2; -typedef uint8_t Py_UCS1; - -#ifdef __cplusplus -extern "C" { -#endif - - -PyAPI_DATA(PyTypeObject) PyUnicode_Type; -PyAPI_DATA(PyTypeObject) PyUnicodeIter_Type; - -#define PyUnicode_Check(op) \ - PyType_FastSubclass(Py_TYPE(op), Py_TPFLAGS_UNICODE_SUBCLASS) -#define PyUnicode_CheckExact(op) Py_IS_TYPE(op, &PyUnicode_Type) - -/* --- Constants ---------------------------------------------------------- */ - -/* This Unicode character will be used as replacement character during - decoding if the errors argument is set to "replace". Note: the - Unicode character U+FFFD is the official REPLACEMENT CHARACTER in - Unicode 3.0. */ - -#define Py_UNICODE_REPLACEMENT_CHARACTER ((Py_UCS4) 0xFFFD) - -/* === Public API ========================================================= */ - -/* Similar to PyUnicode_FromUnicode(), but u points to UTF-8 encoded bytes */ -PyAPI_FUNC(PyObject*) PyUnicode_FromStringAndSize( - const char *u, /* UTF-8 encoded string */ - Py_ssize_t size /* size of buffer */ - ); - -/* Similar to PyUnicode_FromUnicode(), but u points to null-terminated - UTF-8 encoded bytes. The size is determined with strlen(). */ -PyAPI_FUNC(PyObject*) PyUnicode_FromString( - const char *u /* UTF-8 encoded string */ - ); - -#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03030000 -PyAPI_FUNC(PyObject*) PyUnicode_Substring( - PyObject *str, - Py_ssize_t start, - Py_ssize_t end); -#endif - -#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03030000 -/* Copy the string into a UCS4 buffer including the null character if copy_null - is set. Return NULL and raise an exception on error. Raise a SystemError if - the buffer is smaller than the string. Return buffer on success. - - buflen is the length of the buffer in (Py_UCS4) characters. */ -PyAPI_FUNC(Py_UCS4*) PyUnicode_AsUCS4( - PyObject *unicode, - Py_UCS4* buffer, - Py_ssize_t buflen, - int copy_null); - -/* Copy the string into a UCS4 buffer. A new buffer is allocated using - * PyMem_Malloc; if this fails, NULL is returned with a memory error - exception set. */ -PyAPI_FUNC(Py_UCS4*) PyUnicode_AsUCS4Copy(PyObject *unicode); -#endif - -#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03030000 -/* Get the length of the Unicode object. */ - -PyAPI_FUNC(Py_ssize_t) PyUnicode_GetLength( - PyObject *unicode -); -#endif - -/* Get the number of Py_UNICODE units in the - string representation. */ - -Py_DEPRECATED(3.3) PyAPI_FUNC(Py_ssize_t) PyUnicode_GetSize( - PyObject *unicode /* Unicode object */ - ); - -#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03030000 -/* Read a character from the string. */ - -PyAPI_FUNC(Py_UCS4) PyUnicode_ReadChar( - PyObject *unicode, - Py_ssize_t index - ); - -/* Write a character to the string. The string must have been created through - PyUnicode_New, must not be shared, and must not have been hashed yet. - - Return 0 on success, -1 on error. */ - -PyAPI_FUNC(int) PyUnicode_WriteChar( - PyObject *unicode, - Py_ssize_t index, - Py_UCS4 character - ); -#endif - -/* Resize a Unicode object. The length is the number of characters, except - if the kind of the string is PyUnicode_WCHAR_KIND: in this case, the length - is the number of Py_UNICODE characters. - - *unicode is modified to point to the new (resized) object and 0 - returned on success. - - Try to resize the string in place (which is usually faster than allocating - a new string and copy characters), or create a new string. - - Error handling is implemented as follows: an exception is set, -1 - is returned and *unicode left untouched. - - WARNING: The function doesn't check string content, the result may not be a - string in canonical representation. */ - -PyAPI_FUNC(int) PyUnicode_Resize( - PyObject **unicode, /* Pointer to the Unicode object */ - Py_ssize_t length /* New length */ - ); - -/* Decode obj to a Unicode object. - - bytes, bytearray and other bytes-like objects are decoded according to the - given encoding and error handler. The encoding and error handler can be - NULL to have the interface use UTF-8 and "strict". - - All other objects (including Unicode objects) raise an exception. - - The API returns NULL in case of an error. The caller is responsible - for decref'ing the returned objects. - -*/ - -PyAPI_FUNC(PyObject*) PyUnicode_FromEncodedObject( - PyObject *obj, /* Object */ - const char *encoding, /* encoding */ - const char *errors /* error handling */ - ); - -/* Copy an instance of a Unicode subtype to a new true Unicode object if - necessary. If obj is already a true Unicode object (not a subtype), return - the reference with *incremented* refcount. - - The API returns NULL in case of an error. The caller is responsible - for decref'ing the returned objects. - -*/ - -PyAPI_FUNC(PyObject*) PyUnicode_FromObject( - PyObject *obj /* Object */ - ); - -PyAPI_FUNC(PyObject *) PyUnicode_FromFormatV( - const char *format, /* ASCII-encoded string */ - va_list vargs - ); -PyAPI_FUNC(PyObject *) PyUnicode_FromFormat( - const char *format, /* ASCII-encoded string */ - ... - ); - -PyAPI_FUNC(void) PyUnicode_InternInPlace(PyObject **); -PyAPI_FUNC(void) PyUnicode_InternImmortal(PyObject **); -PyAPI_FUNC(PyObject *) PyUnicode_InternFromString( - const char *u /* UTF-8 encoded string */ - ); - -/* Use only if you know it's a string */ -#define PyUnicode_CHECK_INTERNED(op) \ - (((PyASCIIObject *)(op))->state.interned) - -/* --- wchar_t support for platforms which support it --------------------- */ - -#ifdef HAVE_WCHAR_H - -/* Create a Unicode Object from the wchar_t buffer w of the given - size. - - The buffer is copied into the new object. */ - -PyAPI_FUNC(PyObject*) PyUnicode_FromWideChar( - const wchar_t *w, /* wchar_t buffer */ - Py_ssize_t size /* size of buffer */ - ); - -/* Copies the Unicode Object contents into the wchar_t buffer w. At - most size wchar_t characters are copied. - - Note that the resulting wchar_t string may or may not be - 0-terminated. It is the responsibility of the caller to make sure - that the wchar_t string is 0-terminated in case this is required by - the application. - - Returns the number of wchar_t characters copied (excluding a - possibly trailing 0-termination character) or -1 in case of an - error. */ - -PyAPI_FUNC(Py_ssize_t) PyUnicode_AsWideChar( - PyObject *unicode, /* Unicode object */ - wchar_t *w, /* wchar_t buffer */ - Py_ssize_t size /* size of buffer */ - ); - -/* Convert the Unicode object to a wide character string. The output string - always ends with a nul character. If size is not NULL, write the number of - wide characters (excluding the null character) into *size. - - Returns a buffer allocated by PyMem_Malloc() (use PyMem_Free() to free it) - on success. On error, returns NULL, *size is undefined and raises a - MemoryError. */ - -PyAPI_FUNC(wchar_t*) PyUnicode_AsWideCharString( - PyObject *unicode, /* Unicode object */ - Py_ssize_t *size /* number of characters of the result */ - ); - -#endif - -/* --- Unicode ordinals --------------------------------------------------- */ - -/* Create a Unicode Object from the given Unicode code point ordinal. - - The ordinal must be in range(0x110000). A ValueError is - raised in case it is not. - -*/ - -PyAPI_FUNC(PyObject*) PyUnicode_FromOrdinal(int ordinal); - -/* === Builtin Codecs ===================================================== - - Many of these APIs take two arguments encoding and errors. These - parameters encoding and errors have the same semantics as the ones - of the builtin str() API. - - Setting encoding to NULL causes the default encoding (UTF-8) to be used. - - Error handling is set by errors which may also be set to NULL - meaning to use the default handling defined for the codec. Default - error handling for all builtin codecs is "strict" (ValueErrors are - raised). - - The codecs all use a similar interface. Only deviation from the - generic ones are documented. - -*/ - -/* --- Manage the default encoding ---------------------------------------- */ - -/* Returns "utf-8". */ -PyAPI_FUNC(const char*) PyUnicode_GetDefaultEncoding(void); - -/* --- Generic Codecs ----------------------------------------------------- */ - -/* Create a Unicode object by decoding the encoded string s of the - given size. */ - -PyAPI_FUNC(PyObject*) PyUnicode_Decode( - const char *s, /* encoded string */ - Py_ssize_t size, /* size of buffer */ - const char *encoding, /* encoding */ - const char *errors /* error handling */ - ); - -/* Decode a Unicode object unicode and return the result as Python - object. - - This API is DEPRECATED. The only supported standard encoding is rot13. - Use PyCodec_Decode() to decode with rot13 and non-standard codecs - that decode from str. */ - -Py_DEPRECATED(3.6) PyAPI_FUNC(PyObject*) PyUnicode_AsDecodedObject( - PyObject *unicode, /* Unicode object */ - const char *encoding, /* encoding */ - const char *errors /* error handling */ - ); - -/* Decode a Unicode object unicode and return the result as Unicode - object. - - This API is DEPRECATED. The only supported standard encoding is rot13. - Use PyCodec_Decode() to decode with rot13 and non-standard codecs - that decode from str to str. */ - -Py_DEPRECATED(3.6) PyAPI_FUNC(PyObject*) PyUnicode_AsDecodedUnicode( - PyObject *unicode, /* Unicode object */ - const char *encoding, /* encoding */ - const char *errors /* error handling */ - ); - -/* Encodes a Unicode object and returns the result as Python - object. - - This API is DEPRECATED. It is superseded by PyUnicode_AsEncodedString() - since all standard encodings (except rot13) encode str to bytes. - Use PyCodec_Encode() for encoding with rot13 and non-standard codecs - that encode form str to non-bytes. */ - -Py_DEPRECATED(3.6) PyAPI_FUNC(PyObject*) PyUnicode_AsEncodedObject( - PyObject *unicode, /* Unicode object */ - const char *encoding, /* encoding */ - const char *errors /* error handling */ - ); - -/* Encodes a Unicode object and returns the result as Python string - object. */ - -PyAPI_FUNC(PyObject*) PyUnicode_AsEncodedString( - PyObject *unicode, /* Unicode object */ - const char *encoding, /* encoding */ - const char *errors /* error handling */ - ); - -/* Encodes a Unicode object and returns the result as Unicode - object. - - This API is DEPRECATED. The only supported standard encodings is rot13. - Use PyCodec_Encode() to encode with rot13 and non-standard codecs - that encode from str to str. */ - -Py_DEPRECATED(3.6) PyAPI_FUNC(PyObject*) PyUnicode_AsEncodedUnicode( - PyObject *unicode, /* Unicode object */ - const char *encoding, /* encoding */ - const char *errors /* error handling */ - ); - -/* Build an encoding map. */ - -PyAPI_FUNC(PyObject*) PyUnicode_BuildEncodingMap( - PyObject* string /* 256 character map */ - ); - -/* --- UTF-7 Codecs ------------------------------------------------------- */ - -PyAPI_FUNC(PyObject*) PyUnicode_DecodeUTF7( - const char *string, /* UTF-7 encoded string */ - Py_ssize_t length, /* size of string */ - const char *errors /* error handling */ - ); - -PyAPI_FUNC(PyObject*) PyUnicode_DecodeUTF7Stateful( - const char *string, /* UTF-7 encoded string */ - Py_ssize_t length, /* size of string */ - const char *errors, /* error handling */ - Py_ssize_t *consumed /* bytes consumed */ - ); - -/* --- UTF-8 Codecs ------------------------------------------------------- */ - -PyAPI_FUNC(PyObject*) PyUnicode_DecodeUTF8( - const char *string, /* UTF-8 encoded string */ - Py_ssize_t length, /* size of string */ - const char *errors /* error handling */ - ); - -PyAPI_FUNC(PyObject*) PyUnicode_DecodeUTF8Stateful( - const char *string, /* UTF-8 encoded string */ - Py_ssize_t length, /* size of string */ - const char *errors, /* error handling */ - Py_ssize_t *consumed /* bytes consumed */ - ); - -PyAPI_FUNC(PyObject*) PyUnicode_AsUTF8String( - PyObject *unicode /* Unicode object */ - ); - -/* --- UTF-32 Codecs ------------------------------------------------------ */ - -/* Decodes length bytes from a UTF-32 encoded buffer string and returns - the corresponding Unicode object. - - errors (if non-NULL) defines the error handling. It defaults - to "strict". - - If byteorder is non-NULL, the decoder starts decoding using the - given byte order: - - *byteorder == -1: little endian - *byteorder == 0: native order - *byteorder == 1: big endian - - In native mode, the first four bytes of the stream are checked for a - BOM mark. If found, the BOM mark is analysed, the byte order - adjusted and the BOM skipped. In the other modes, no BOM mark - interpretation is done. After completion, *byteorder is set to the - current byte order at the end of input data. - - If byteorder is NULL, the codec starts in native order mode. - -*/ - -PyAPI_FUNC(PyObject*) PyUnicode_DecodeUTF32( - const char *string, /* UTF-32 encoded string */ - Py_ssize_t length, /* size of string */ - const char *errors, /* error handling */ - int *byteorder /* pointer to byteorder to use - 0=native;-1=LE,1=BE; updated on - exit */ - ); - -PyAPI_FUNC(PyObject*) PyUnicode_DecodeUTF32Stateful( - const char *string, /* UTF-32 encoded string */ - Py_ssize_t length, /* size of string */ - const char *errors, /* error handling */ - int *byteorder, /* pointer to byteorder to use - 0=native;-1=LE,1=BE; updated on - exit */ - Py_ssize_t *consumed /* bytes consumed */ - ); - -/* Returns a Python string using the UTF-32 encoding in native byte - order. The string always starts with a BOM mark. */ - -PyAPI_FUNC(PyObject*) PyUnicode_AsUTF32String( - PyObject *unicode /* Unicode object */ - ); - -/* Returns a Python string object holding the UTF-32 encoded value of - the Unicode data. - - If byteorder is not 0, output is written according to the following - byte order: - - byteorder == -1: little endian - byteorder == 0: native byte order (writes a BOM mark) - byteorder == 1: big endian - - If byteorder is 0, the output string will always start with the - Unicode BOM mark (U+FEFF). In the other two modes, no BOM mark is - prepended. - -*/ - -/* --- UTF-16 Codecs ------------------------------------------------------ */ - -/* Decodes length bytes from a UTF-16 encoded buffer string and returns - the corresponding Unicode object. - - errors (if non-NULL) defines the error handling. It defaults - to "strict". - - If byteorder is non-NULL, the decoder starts decoding using the - given byte order: - - *byteorder == -1: little endian - *byteorder == 0: native order - *byteorder == 1: big endian - - In native mode, the first two bytes of the stream are checked for a - BOM mark. If found, the BOM mark is analysed, the byte order - adjusted and the BOM skipped. In the other modes, no BOM mark - interpretation is done. After completion, *byteorder is set to the - current byte order at the end of input data. - - If byteorder is NULL, the codec starts in native order mode. - -*/ - -PyAPI_FUNC(PyObject*) PyUnicode_DecodeUTF16( - const char *string, /* UTF-16 encoded string */ - Py_ssize_t length, /* size of string */ - const char *errors, /* error handling */ - int *byteorder /* pointer to byteorder to use - 0=native;-1=LE,1=BE; updated on - exit */ - ); - -PyAPI_FUNC(PyObject*) PyUnicode_DecodeUTF16Stateful( - const char *string, /* UTF-16 encoded string */ - Py_ssize_t length, /* size of string */ - const char *errors, /* error handling */ - int *byteorder, /* pointer to byteorder to use - 0=native;-1=LE,1=BE; updated on - exit */ - Py_ssize_t *consumed /* bytes consumed */ - ); - -/* Returns a Python string using the UTF-16 encoding in native byte - order. The string always starts with a BOM mark. */ - -PyAPI_FUNC(PyObject*) PyUnicode_AsUTF16String( - PyObject *unicode /* Unicode object */ - ); - -/* --- Unicode-Escape Codecs ---------------------------------------------- */ - -PyAPI_FUNC(PyObject*) PyUnicode_DecodeUnicodeEscape( - const char *string, /* Unicode-Escape encoded string */ - Py_ssize_t length, /* size of string */ - const char *errors /* error handling */ - ); - -PyAPI_FUNC(PyObject*) PyUnicode_AsUnicodeEscapeString( - PyObject *unicode /* Unicode object */ - ); - -/* --- Raw-Unicode-Escape Codecs ------------------------------------------ */ - -PyAPI_FUNC(PyObject*) PyUnicode_DecodeRawUnicodeEscape( - const char *string, /* Raw-Unicode-Escape encoded string */ - Py_ssize_t length, /* size of string */ - const char *errors /* error handling */ - ); - -PyAPI_FUNC(PyObject*) PyUnicode_AsRawUnicodeEscapeString( - PyObject *unicode /* Unicode object */ - ); - -/* --- Latin-1 Codecs ----------------------------------------------------- - - Note: Latin-1 corresponds to the first 256 Unicode ordinals. */ - -PyAPI_FUNC(PyObject*) PyUnicode_DecodeLatin1( - const char *string, /* Latin-1 encoded string */ - Py_ssize_t length, /* size of string */ - const char *errors /* error handling */ - ); - -PyAPI_FUNC(PyObject*) PyUnicode_AsLatin1String( - PyObject *unicode /* Unicode object */ - ); - -/* --- ASCII Codecs ------------------------------------------------------- - - Only 7-bit ASCII data is excepted. All other codes generate errors. - -*/ - -PyAPI_FUNC(PyObject*) PyUnicode_DecodeASCII( - const char *string, /* ASCII encoded string */ - Py_ssize_t length, /* size of string */ - const char *errors /* error handling */ - ); - -PyAPI_FUNC(PyObject*) PyUnicode_AsASCIIString( - PyObject *unicode /* Unicode object */ - ); - -/* --- Character Map Codecs ----------------------------------------------- - - This codec uses mappings to encode and decode characters. - - Decoding mappings must map byte ordinals (integers in the range from 0 to - 255) to Unicode strings, integers (which are then interpreted as Unicode - ordinals) or None. Unmapped data bytes (ones which cause a LookupError) - as well as mapped to None, 0xFFFE or '\ufffe' are treated as "undefined - mapping" and cause an error. - - Encoding mappings must map Unicode ordinal integers to bytes objects, - integers in the range from 0 to 255 or None. Unmapped character - ordinals (ones which cause a LookupError) as well as mapped to - None are treated as "undefined mapping" and cause an error. - -*/ - -PyAPI_FUNC(PyObject*) PyUnicode_DecodeCharmap( - const char *string, /* Encoded string */ - Py_ssize_t length, /* size of string */ - PyObject *mapping, /* decoding mapping */ - const char *errors /* error handling */ - ); - -PyAPI_FUNC(PyObject*) PyUnicode_AsCharmapString( - PyObject *unicode, /* Unicode object */ - PyObject *mapping /* encoding mapping */ - ); - -/* --- MBCS codecs for Windows -------------------------------------------- */ - -#ifdef MS_WINDOWS -PyAPI_FUNC(PyObject*) PyUnicode_DecodeMBCS( - const char *string, /* MBCS encoded string */ - Py_ssize_t length, /* size of string */ - const char *errors /* error handling */ - ); - -PyAPI_FUNC(PyObject*) PyUnicode_DecodeMBCSStateful( - const char *string, /* MBCS encoded string */ - Py_ssize_t length, /* size of string */ - const char *errors, /* error handling */ - Py_ssize_t *consumed /* bytes consumed */ - ); - -#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03030000 -PyAPI_FUNC(PyObject*) PyUnicode_DecodeCodePageStateful( - int code_page, /* code page number */ - const char *string, /* encoded string */ - Py_ssize_t length, /* size of string */ - const char *errors, /* error handling */ - Py_ssize_t *consumed /* bytes consumed */ - ); -#endif - -PyAPI_FUNC(PyObject*) PyUnicode_AsMBCSString( - PyObject *unicode /* Unicode object */ - ); - -#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03030000 -PyAPI_FUNC(PyObject*) PyUnicode_EncodeCodePage( - int code_page, /* code page number */ - PyObject *unicode, /* Unicode object */ - const char *errors /* error handling */ - ); -#endif - -#endif /* MS_WINDOWS */ - -/* --- Locale encoding --------------------------------------------------- */ - -#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03030000 -/* Decode a string from the current locale encoding. The decoder is strict if - *surrogateescape* is equal to zero, otherwise it uses the 'surrogateescape' - error handler (PEP 383) to escape undecodable bytes. If a byte sequence can - be decoded as a surrogate character and *surrogateescape* is not equal to - zero, the byte sequence is escaped using the 'surrogateescape' error handler - instead of being decoded. *str* must end with a null character but cannot - contain embedded null characters. */ - -PyAPI_FUNC(PyObject*) PyUnicode_DecodeLocaleAndSize( - const char *str, - Py_ssize_t len, - const char *errors); - -/* Similar to PyUnicode_DecodeLocaleAndSize(), but compute the string - length using strlen(). */ - -PyAPI_FUNC(PyObject*) PyUnicode_DecodeLocale( - const char *str, - const char *errors); - -/* Encode a Unicode object to the current locale encoding. The encoder is - strict is *surrogateescape* is equal to zero, otherwise the - "surrogateescape" error handler is used. Return a bytes object. The string - cannot contain embedded null characters. */ - -PyAPI_FUNC(PyObject*) PyUnicode_EncodeLocale( - PyObject *unicode, - const char *errors - ); -#endif - -/* --- File system encoding ---------------------------------------------- */ - -/* ParseTuple converter: encode str objects to bytes using - PyUnicode_EncodeFSDefault(); bytes objects are output as-is. */ - -PyAPI_FUNC(int) PyUnicode_FSConverter(PyObject*, void*); - -/* ParseTuple converter: decode bytes objects to unicode using - PyUnicode_DecodeFSDefaultAndSize(); str objects are output as-is. */ - -PyAPI_FUNC(int) PyUnicode_FSDecoder(PyObject*, void*); - -/* Decode a null-terminated string using Py_FileSystemDefaultEncoding - and the "surrogateescape" error handler. - - If Py_FileSystemDefaultEncoding is not set, fall back to the locale - encoding. - - Use PyUnicode_DecodeFSDefaultAndSize() if the string length is known. -*/ - -PyAPI_FUNC(PyObject*) PyUnicode_DecodeFSDefault( - const char *s /* encoded string */ - ); - -/* Decode a string using Py_FileSystemDefaultEncoding - and the "surrogateescape" error handler. - - If Py_FileSystemDefaultEncoding is not set, fall back to the locale - encoding. -*/ - -PyAPI_FUNC(PyObject*) PyUnicode_DecodeFSDefaultAndSize( - const char *s, /* encoded string */ - Py_ssize_t size /* size */ - ); - -/* Encode a Unicode object to Py_FileSystemDefaultEncoding with the - "surrogateescape" error handler, and return bytes. - - If Py_FileSystemDefaultEncoding is not set, fall back to the locale - encoding. -*/ - -PyAPI_FUNC(PyObject*) PyUnicode_EncodeFSDefault( - PyObject *unicode - ); - -/* --- Methods & Slots ---------------------------------------------------- - - These are capable of handling Unicode objects and strings on input - (we refer to them as strings in the descriptions) and return - Unicode objects or integers as appropriate. */ - -/* Concat two strings giving a new Unicode string. */ - -PyAPI_FUNC(PyObject*) PyUnicode_Concat( - PyObject *left, /* Left string */ - PyObject *right /* Right string */ - ); - -/* Concat two strings and put the result in *pleft - (sets *pleft to NULL on error) */ - -PyAPI_FUNC(void) PyUnicode_Append( - PyObject **pleft, /* Pointer to left string */ - PyObject *right /* Right string */ - ); - -/* Concat two strings, put the result in *pleft and drop the right object - (sets *pleft to NULL on error) */ - -PyAPI_FUNC(void) PyUnicode_AppendAndDel( - PyObject **pleft, /* Pointer to left string */ - PyObject *right /* Right string */ - ); - -/* Split a string giving a list of Unicode strings. - - If sep is NULL, splitting will be done at all whitespace - substrings. Otherwise, splits occur at the given separator. - - At most maxsplit splits will be done. If negative, no limit is set. - - Separators are not included in the resulting list. - -*/ - -PyAPI_FUNC(PyObject*) PyUnicode_Split( - PyObject *s, /* String to split */ - PyObject *sep, /* String separator */ - Py_ssize_t maxsplit /* Maxsplit count */ - ); - -/* Dito, but split at line breaks. - - CRLF is considered to be one line break. Line breaks are not - included in the resulting list. */ - -PyAPI_FUNC(PyObject*) PyUnicode_Splitlines( - PyObject *s, /* String to split */ - int keepends /* If true, line end markers are included */ - ); - -/* Partition a string using a given separator. */ - -PyAPI_FUNC(PyObject*) PyUnicode_Partition( - PyObject *s, /* String to partition */ - PyObject *sep /* String separator */ - ); - -/* Partition a string using a given separator, searching from the end of the - string. */ - -PyAPI_FUNC(PyObject*) PyUnicode_RPartition( - PyObject *s, /* String to partition */ - PyObject *sep /* String separator */ - ); - -/* Split a string giving a list of Unicode strings. - - If sep is NULL, splitting will be done at all whitespace - substrings. Otherwise, splits occur at the given separator. - - At most maxsplit splits will be done. But unlike PyUnicode_Split - PyUnicode_RSplit splits from the end of the string. If negative, - no limit is set. - - Separators are not included in the resulting list. - -*/ - -PyAPI_FUNC(PyObject*) PyUnicode_RSplit( - PyObject *s, /* String to split */ - PyObject *sep, /* String separator */ - Py_ssize_t maxsplit /* Maxsplit count */ - ); - -/* Translate a string by applying a character mapping table to it and - return the resulting Unicode object. - - The mapping table must map Unicode ordinal integers to Unicode strings, - Unicode ordinal integers or None (causing deletion of the character). - - Mapping tables may be dictionaries or sequences. Unmapped character - ordinals (ones which cause a LookupError) are left untouched and - are copied as-is. - -*/ - -PyAPI_FUNC(PyObject *) PyUnicode_Translate( - PyObject *str, /* String */ - PyObject *table, /* Translate table */ - const char *errors /* error handling */ - ); - -/* Join a sequence of strings using the given separator and return - the resulting Unicode string. */ - -PyAPI_FUNC(PyObject*) PyUnicode_Join( - PyObject *separator, /* Separator string */ - PyObject *seq /* Sequence object */ - ); - -/* Return 1 if substr matches str[start:end] at the given tail end, 0 - otherwise. */ - -PyAPI_FUNC(Py_ssize_t) PyUnicode_Tailmatch( - PyObject *str, /* String */ - PyObject *substr, /* Prefix or Suffix string */ - Py_ssize_t start, /* Start index */ - Py_ssize_t end, /* Stop index */ - int direction /* Tail end: -1 prefix, +1 suffix */ - ); - -/* Return the first position of substr in str[start:end] using the - given search direction or -1 if not found. -2 is returned in case - an error occurred and an exception is set. */ - -PyAPI_FUNC(Py_ssize_t) PyUnicode_Find( - PyObject *str, /* String */ - PyObject *substr, /* Substring to find */ - Py_ssize_t start, /* Start index */ - Py_ssize_t end, /* Stop index */ - int direction /* Find direction: +1 forward, -1 backward */ - ); - -#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03030000 -/* Like PyUnicode_Find, but search for single character only. */ -PyAPI_FUNC(Py_ssize_t) PyUnicode_FindChar( - PyObject *str, - Py_UCS4 ch, - Py_ssize_t start, - Py_ssize_t end, - int direction - ); -#endif - -/* Count the number of occurrences of substr in str[start:end]. */ - -PyAPI_FUNC(Py_ssize_t) PyUnicode_Count( - PyObject *str, /* String */ - PyObject *substr, /* Substring to count */ - Py_ssize_t start, /* Start index */ - Py_ssize_t end /* Stop index */ - ); - -/* Replace at most maxcount occurrences of substr in str with replstr - and return the resulting Unicode object. */ - -PyAPI_FUNC(PyObject *) PyUnicode_Replace( - PyObject *str, /* String */ - PyObject *substr, /* Substring to find */ - PyObject *replstr, /* Substring to replace */ - Py_ssize_t maxcount /* Max. number of replacements to apply; - -1 = all */ - ); - -/* Compare two strings and return -1, 0, 1 for less than, equal, - greater than resp. - Raise an exception and return -1 on error. */ - -PyAPI_FUNC(int) PyUnicode_Compare( - PyObject *left, /* Left string */ - PyObject *right /* Right string */ - ); - -/* Compare a Unicode object with C string and return -1, 0, 1 for less than, - equal, and greater than, respectively. It is best to pass only - ASCII-encoded strings, but the function interprets the input string as - ISO-8859-1 if it contains non-ASCII characters. - This function does not raise exceptions. */ - -PyAPI_FUNC(int) PyUnicode_CompareWithASCIIString( - PyObject *left, - const char *right /* ASCII-encoded string */ - ); - -/* Rich compare two strings and return one of the following: - - - NULL in case an exception was raised - - Py_True or Py_False for successful comparisons - - Py_NotImplemented in case the type combination is unknown - - Possible values for op: - - Py_GT, Py_GE, Py_EQ, Py_NE, Py_LT, Py_LE - -*/ - -PyAPI_FUNC(PyObject *) PyUnicode_RichCompare( - PyObject *left, /* Left string */ - PyObject *right, /* Right string */ - int op /* Operation: Py_EQ, Py_NE, Py_GT, etc. */ - ); - -/* Apply an argument tuple or dictionary to a format string and return - the resulting Unicode string. */ - -PyAPI_FUNC(PyObject *) PyUnicode_Format( - PyObject *format, /* Format string */ - PyObject *args /* Argument tuple or dictionary */ - ); - -/* Checks whether element is contained in container and return 1/0 - accordingly. - - element has to coerce to a one element Unicode string. -1 is - returned in case of an error. */ - -PyAPI_FUNC(int) PyUnicode_Contains( - PyObject *container, /* Container string */ - PyObject *element /* Element string */ - ); - -/* Checks whether argument is a valid identifier. */ - -PyAPI_FUNC(int) PyUnicode_IsIdentifier(PyObject *s); - -/* === Characters Type APIs =============================================== */ - -#ifndef Py_LIMITED_API -# define Py_CPYTHON_UNICODEOBJECT_H -# include "cpython/unicodeobject.h" -# undef Py_CPYTHON_UNICODEOBJECT_H -#endif - -#ifdef __cplusplus -} -#endif -#endif /* !Py_UNICODEOBJECT_H */ diff --git a/scripts/build-windows/py39-libs/include/warnings.h b/scripts/build-windows/py39-libs/include/warnings.h deleted file mode 100644 index a1ec42525..000000000 --- a/scripts/build-windows/py39-libs/include/warnings.h +++ /dev/null @@ -1,67 +0,0 @@ -#ifndef Py_WARNINGS_H -#define Py_WARNINGS_H -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef Py_LIMITED_API -PyAPI_FUNC(PyObject*) _PyWarnings_Init(void); -#endif - -PyAPI_FUNC(int) PyErr_WarnEx( - PyObject *category, - const char *message, /* UTF-8 encoded string */ - Py_ssize_t stack_level); -PyAPI_FUNC(int) PyErr_WarnFormat( - PyObject *category, - Py_ssize_t stack_level, - const char *format, /* ASCII-encoded string */ - ...); - -#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03060000 -/* Emit a ResourceWarning warning */ -PyAPI_FUNC(int) PyErr_ResourceWarning( - PyObject *source, - Py_ssize_t stack_level, - const char *format, /* ASCII-encoded string */ - ...); -#endif -#ifndef Py_LIMITED_API -PyAPI_FUNC(int) PyErr_WarnExplicitObject( - PyObject *category, - PyObject *message, - PyObject *filename, - int lineno, - PyObject *module, - PyObject *registry); -#endif -PyAPI_FUNC(int) PyErr_WarnExplicit( - PyObject *category, - const char *message, /* UTF-8 encoded string */ - const char *filename, /* decoded from the filesystem encoding */ - int lineno, - const char *module, /* UTF-8 encoded string */ - PyObject *registry); - -#ifndef Py_LIMITED_API -PyAPI_FUNC(int) -PyErr_WarnExplicitFormat(PyObject *category, - const char *filename, int lineno, - const char *module, PyObject *registry, - const char *format, ...); -#endif - -/* DEPRECATED: Use PyErr_WarnEx() instead. */ -#ifndef Py_LIMITED_API -#define PyErr_Warn(category, msg) PyErr_WarnEx(category, msg, 1) -#endif - -#ifndef Py_LIMITED_API -void _PyErr_WarnUnawaitedCoroutine(PyObject *coro); -#endif - -#ifdef __cplusplus -} -#endif -#endif /* !Py_WARNINGS_H */ - diff --git a/scripts/build-windows/py39-libs/include/weakrefobject.h b/scripts/build-windows/py39-libs/include/weakrefobject.h deleted file mode 100644 index 368908204..000000000 --- a/scripts/build-windows/py39-libs/include/weakrefobject.h +++ /dev/null @@ -1,86 +0,0 @@ -/* Weak references objects for Python. */ - -#ifndef Py_WEAKREFOBJECT_H -#define Py_WEAKREFOBJECT_H -#ifdef __cplusplus -extern "C" { -#endif - - -typedef struct _PyWeakReference PyWeakReference; - -/* PyWeakReference is the base struct for the Python ReferenceType, ProxyType, - * and CallableProxyType. - */ -#ifndef Py_LIMITED_API -struct _PyWeakReference { - PyObject_HEAD - - /* The object to which this is a weak reference, or Py_None if none. - * Note that this is a stealth reference: wr_object's refcount is - * not incremented to reflect this pointer. - */ - PyObject *wr_object; - - /* A callable to invoke when wr_object dies, or NULL if none. */ - PyObject *wr_callback; - - /* A cache for wr_object's hash code. As usual for hashes, this is -1 - * if the hash code isn't known yet. - */ - Py_hash_t hash; - - /* If wr_object is weakly referenced, wr_object has a doubly-linked NULL- - * terminated list of weak references to it. These are the list pointers. - * If wr_object goes away, wr_object is set to Py_None, and these pointers - * have no meaning then. - */ - PyWeakReference *wr_prev; - PyWeakReference *wr_next; -}; -#endif - -PyAPI_DATA(PyTypeObject) _PyWeakref_RefType; -PyAPI_DATA(PyTypeObject) _PyWeakref_ProxyType; -PyAPI_DATA(PyTypeObject) _PyWeakref_CallableProxyType; - -#define PyWeakref_CheckRef(op) PyObject_TypeCheck(op, &_PyWeakref_RefType) -#define PyWeakref_CheckRefExact(op) \ - Py_IS_TYPE(op, &_PyWeakref_RefType) -#define PyWeakref_CheckProxy(op) \ - (Py_IS_TYPE(op, &_PyWeakref_ProxyType) || \ - Py_IS_TYPE(op, &_PyWeakref_CallableProxyType)) - -#define PyWeakref_Check(op) \ - (PyWeakref_CheckRef(op) || PyWeakref_CheckProxy(op)) - - -PyAPI_FUNC(PyObject *) PyWeakref_NewRef(PyObject *ob, - PyObject *callback); -PyAPI_FUNC(PyObject *) PyWeakref_NewProxy(PyObject *ob, - PyObject *callback); -PyAPI_FUNC(PyObject *) PyWeakref_GetObject(PyObject *ref); - -#ifndef Py_LIMITED_API -PyAPI_FUNC(Py_ssize_t) _PyWeakref_GetWeakrefCount(PyWeakReference *head); - -PyAPI_FUNC(void) _PyWeakref_ClearRef(PyWeakReference *self); -#endif - -/* Explanation for the Py_REFCNT() check: when a weakref's target is part - of a long chain of deallocations which triggers the trashcan mechanism, - clearing the weakrefs can be delayed long after the target's refcount - has dropped to zero. In the meantime, code accessing the weakref will - be able to "see" the target object even though it is supposed to be - unreachable. See issue #16602. */ - -#define PyWeakref_GET_OBJECT(ref) \ - (Py_REFCNT(((PyWeakReference *)(ref))->wr_object) > 0 \ - ? ((PyWeakReference *)(ref))->wr_object \ - : Py_None) - - -#ifdef __cplusplus -} -#endif -#endif /* !Py_WEAKREFOBJECT_H */ diff --git a/scripts/build-windows/py39-libs/libs/_tkinter.lib b/scripts/build-windows/py39-libs/libs/_tkinter.lib deleted file mode 100644 index 6bebff9a2..000000000 Binary files a/scripts/build-windows/py39-libs/libs/_tkinter.lib and /dev/null differ diff --git a/scripts/build-windows/py39-libs/libs/python3.lib b/scripts/build-windows/py39-libs/libs/python3.lib deleted file mode 100644 index 800a9c62b..000000000 Binary files a/scripts/build-windows/py39-libs/libs/python3.lib and /dev/null differ diff --git a/scripts/build-windows/py39-libs/libs/python39.lib b/scripts/build-windows/py39-libs/libs/python39.lib deleted file mode 100644 index e57eac455..000000000 Binary files a/scripts/build-windows/py39-libs/libs/python39.lib and /dev/null differ diff --git a/scripts/build-windows/readme.md b/scripts/build-windows/readme.md deleted file mode 100644 index b9a5fe515..000000000 --- a/scripts/build-windows/readme.md +++ /dev/null @@ -1,15 +0,0 @@ -# Build windows/amd64 - -1. install Git -1. install Rust and cargo -1. install Go1.16+ -1. install VC2019 -1. install TDM-GCC-x64 - - https://jmeubank.github.io/tdm-gcc/download/ -1. install LLVM-12.0.1-win64 - - https://github.com/KusionStack/llvm-package-windows/releases/tag/v12.0.1 - - set `LLVM_SYS_120_PREFIX` to root path -1. Open Git Bash - - `cd ./scripts/build-windows` and run `mingw32-make` - - output: `scripts/build-windows/_output/kclvm-windows` - diff --git a/scripts/build-windows/rename.go b/scripts/build-windows/rename.go deleted file mode 100644 index a8505e28d..000000000 --- a/scripts/build-windows/rename.go +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright 2021 The KCL Authors. All rights reserved. - -//go:build ingore -// +build ingore - -package main - -import ( - "flag" - "log" - "os" -) - -var ( - flagOldFile = flag.String("old", "", "set old file") - flagNewFile = flag.String("new", "", "set new file") -) - -func main() { - flag.Parse() - if *flagOldFile == "" || *flagNewFile == "" { - flag.Usage() - os.Exit(1) - } - err := os.Rename(*flagOldFile, *flagNewFile) - if err != nil { - log.Fatal(err) - } -} diff --git a/scripts/build-windows/requirements.release.txt b/scripts/build-windows/requirements.release.txt deleted file mode 100644 index beedcf713..000000000 --- a/scripts/build-windows/requirements.release.txt +++ /dev/null @@ -1,24 +0,0 @@ -wheel==0.34.2 -twine==3.2.0 -pyyaml==5.4 -pytest-xdist==2.2.1 -lark-parser==0.11.3 -filelock==3.6.0 -yapf==0.29.0 -pytest==6.2.2 -pypeg2==2.15.2 -protobuf==3.19.4 -grequests -schema -coverage -ruamel.yaml -toml -numpydoc -pygls==0.10.3 -fastapi -uvicorn -gunicorn==20.1.0 -parsy==1.3.0 -wasmer==1.0.0 -wasmer_compiler_cranelift==1.0.0 -pyopenssl diff --git a/scripts/build-windows/unzip.go b/scripts/build-windows/unzip.go deleted file mode 100644 index 4ac8e41f3..000000000 --- a/scripts/build-windows/unzip.go +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright 2021 The KCL Authors. All rights reserved. - -//go:build ingore -// +build ingore - -package main - -import ( - "archive/zip" - "flag" - "fmt" - "io" - "os" - "path/filepath" - "strings" -) - -var ( - flagZipFile = flag.String("zip", "python-3.9.6-embed-amd64.zip", "set zip file") - flagOutput = flag.String("output", "_output/kclvm-windows", "set output dir") -) - -func main() { - flag.Parse() - - dst := *flagOutput - archive, err := zip.OpenReader(*flagZipFile) - if err != nil { - panic(err) - } - defer archive.Close() - - for _, f := range archive.File { - filePath := filepath.Join(dst, f.Name) - fmt.Println("unzip ", filePath) - - if !strings.HasPrefix(filePath, filepath.Clean(dst)+string(os.PathSeparator)) { - fmt.Println("invalid file path") - return - } - if f.FileInfo().IsDir() { - fmt.Println("creating directory...") - os.MkdirAll(filePath, os.ModePerm) - continue - } - - if err := os.MkdirAll(filepath.Dir(filePath), os.ModePerm); err != nil { - panic(err) - } - - dstFile, err := os.OpenFile(filePath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode()) - if err != nil { - panic(err) - } - - fileInArchive, err := f.Open() - if err != nil { - panic(err) - } - - if _, err := io.Copy(dstFile, fileInArchive); err != nil { - panic(err) - } - - dstFile.Close() - fileInArchive.Close() - } -} diff --git a/scripts/build.sh b/scripts/build.sh new file mode 100755 index 000000000..c9a2dfb88 --- /dev/null +++ b/scripts/build.sh @@ -0,0 +1,80 @@ +#!/usr/bin/env bash + +# Stop on error. +set -e + +# Environment + +getSystemInfo() { + arch=$(uname -m) + case $arch in + armv7*) arch="arm";; + aarch64) arch="arm64";; + x86_64) arch="amd64";; + esac + + os=$(echo `uname`|tr '[:upper:]' '[:lower:]') +} + +getSystemInfo + +prepare_dirs () { + install_dir="$topdir/_build/dist/$os/kclvm" + mkdir -p "$install_dir/bin" +} + +prepare_dirs + +# 1. Build kcl native library + +cd $topdir/kclvm +export PATH=$PATH:/root/.cargo/bin:/usr/lib/llvm-12/bin +# Enable the llvm feature +# cargo build --release --features llvm +# Disable the llvm feature +cargo build --release + +## Switch dll file extension according to os. +dll_extension="so" +case $os in + "Linux" | "linux" | "Default" | "default" | "centos" | "ubuntu" | "debian" | "Ubuntu" | "Debian" | "Static-Debian" | "Cood1-Debian" | "Cood1Shared-Debian") + dll_extension="so" + ;; + "Darwin" | "darwin" | "ios" | "macos") + dll_extension="dylib" + ;; + *) dll_extension="dll" + ;; +esac + +## Copy libkclvm_cli lib to the build folder + +if [ -e $topdir/kclvm/target/release/libkclvm_cli_cdylib.$dll_extension ]; then + touch $install_dir/bin/libkclvm_cli_cdylib.$dll_extension + rm $install_dir/bin/libkclvm_cli_cdylib.$dll_extension + cp $topdir/kclvm/target/release/libkclvm_cli_cdylib.$dll_extension $install_dir/bin/libkclvm_cli_cdylib.$dll_extension +fi + +## 2. Build KCL language server binary + +cd $topdir/kclvm/tools/src/LSP +cargo build --release + +touch $install_dir/bin/kcl-language-server +rm $install_dir/bin/kcl-language-server +cp $topdir/kclvm/target/release/kcl-language-server $install_dir/bin/kcl-language-server + +## 3. Build CLI + +cd $topdir/cli +cargo build --release + +touch $install_dir/bin/kclvm_cli +rm $install_dir/bin/kclvm_cli +cp ./target/release/kclvm_cli $install_dir/bin/kclvm_cli + +cd $topdir + +# Print the summary. +echo "================ Summary ================" +echo " KCL is updated into $install_dir" diff --git a/scripts/docker/kcl-builder-alpine/Dockerfile b/scripts/docker/kcl-builder-alpine/Dockerfile new file mode 100644 index 000000000..5bc9f3f80 --- /dev/null +++ b/scripts/docker/kcl-builder-alpine/Dockerfile @@ -0,0 +1,50 @@ +# Copyright The KCL Authors. All rights reserved. + +FROM alpine:latest + +# set timezone +RUN apk add --no-cache tzdata \ + && cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \ + && echo 'Asia/Shanghai' >/etc/timezone + +# update repositories and install required packages +RUN apk add --no-cache \ + make \ + wget \ + git \ + ca-certificates \ + clang \ + llvm \ + libffi-dev \ + go \ + python3 \ + python3-dev \ + py3-pip + +# set environment variables +ENV GOPATH=/go \ + GOLANG_VERSION=1.20.5 \ + PATH="/root/.cargo/bin:${PATH}" \ + CARGO_NET_GIT_FETCH_WITH_CLI=true + +# install rust and cargo +RUN wget -qO- https://sh.rustup.rs | sh -s -- -y \ + && echo 'source $HOME/.cargo/env' >> $HOME/.ashrc \ + && . $HOME/.cargo/env \ + && cargo version \ + && rustc --version + +# install go tools +RUN go install golang.org/x/lint/golint@latest \ + && go install golang.org/x/tools/cmd/goimports@latest \ + && go install github.com/t-yuki/gocover-cobertura@latest \ + && go install github.com/jstemmer/go-junit-report@latest + +RUN rm -rf /root/.cache/go-build \ + && rm -rf /go/pkg/mod \ + && rm -rf /go/pkg/sumdb \ + && rm -rf /var/cache/apk/* + +WORKDIR /root + +CMD ["ash"] diff --git a/scripts/docker/kcl-builder-alpine/Makefile b/scripts/docker/kcl-builder-alpine/Makefile new file mode 100644 index 000000000..3a633c80c --- /dev/null +++ b/scripts/docker/kcl-builder-alpine/Makefile @@ -0,0 +1,30 @@ +# Copyright The KCL Authors. All rights reserved. + +PWD:=$(shell pwd) + +BUILDER_IMAGE:=kcllang/kcl-builder-alpine + +# export DOCKER_DEFAULT_PLATFORM=linux/amd64 +# or +# --platform linux/amd64 + +RUN_IN_DOCKER:=docker run -it --rm --platform linux/amd64 +RUN_IN_DOCKER+=-v ~/.ssh:/root/.ssh +RUN_IN_DOCKER+=-v ~/.gitconfig:/root/.gitconfig +RUN_IN_DOCKER+=-v ~/go/pkg/mod:/go/pkg/mod + +kcl-builder: + docker build --platform linux/amd64 -t ${BUILDER_IMAGE} . + @echo "ok" + +publish-builder: + # docker login --username= + + # make kcl-builder + docker push ${BUILDER_IMAGE} + @echo "push ${BUILDER_IMAGE} ok" + +sh-in-builder: + ${RUN_IN_DOCKER} -v ${PWD}/../../..:/root/kclvm -w /root ${BUILDER_IMAGE} sh + +clean: diff --git a/scripts/docker/kcl-builder-arm64/Dockerfile b/scripts/docker/kcl-builder-arm64/Dockerfile new file mode 100644 index 000000000..d9a0ed963 --- /dev/null +++ b/scripts/docker/kcl-builder-arm64/Dockerfile @@ -0,0 +1,28 @@ +# Copyright The KCL Authors. All rights reserved. +# Builder for kcllang/kcl-builder-arm64 image + +FROM arm64v8/ubuntu:20.04 + +#RUN uname -a +#RUN cat /etc/os-release + +RUN apt-get update + +RUN apt-get install -y curl make gcc git zlib1g-dev +RUN apt install -y pkg-config libssl-dev + +# rust +RUN curl https://sh.rustup.rs -sSf | bash -s -- -y +ENV CARGO_NET_GIT_FETCH_WITH_CLI=true + +RUN cargo version +RUN rustc --version + +# clang12 +RUN apt-get install -y clang-12 lld-12 +RUN ln -sf /usr/bin/clang-12 /usr/bin/clang +RUN ln -sf /usr/bin/wasm-ld-12 /usr/bin/wasm-ld + +WORKDIR /root + +CMD ["bash"] diff --git a/scripts/docker/kcl-builder-centos7/Dockerfile b/scripts/docker/kcl-builder-centos7/Dockerfile new file mode 100644 index 000000000..b860b965f --- /dev/null +++ b/scripts/docker/kcl-builder-centos7/Dockerfile @@ -0,0 +1,94 @@ +# Copyright The KCL Authors. All rights reserved. + +FROM centos:centos7 + +# macOS M1 --platform linux/amd64 +# try fix "Problem with the SSL CA cert (path? access rights?)" +# https://issueexplorer.com/issue/docker/for-mac/5912 +# https://access.redhat.com/articles/2050743 +RUN touch /etc/sysconfig/64bit_strstr_via_64bit_strstr_sse2_unaligned + +# --------------------------------------------------------------------------------- +# Please note: The following steps are to install the dependency packages +# needed to compile CPython for centos7, see the +# [Python official website](https://devguide.python.org/setup/#install-dependencies) +# for details. When the version of CPython used becomes higher, +# please pay attention to update the installation dependencies. +# --------------------------------------------------------------------------------- + +# Some language environments and plug-ins related to development and compilation, +# such as git, CPython compilation, etc. +RUN yum groupinstall -y "Development Tools" +# Compiler and tool chain required to compile CPython such as gcc, make, sqlite3, ctype, struct, etc. +RUN yum install -y gcc patch libffi-devel python-devel zlib-devel bzip2-devel ncurses-devel sqlite-devel +RUN yum install -y libpcap-devel xz-devel readline-devel tk-devel gdbm-devel db4-deve +# Install the system libraries required by python3 for UNIX based systems +RUN yum -y install yum-utils +RUN yum-builddep -y python3 +# The python zlib module dependency package is required when compiling the python source code, +# in order to use the modules that require zlib, such as setuptools, etc. +RUN yum install -y zlib* +# The python ssl module dependency package is required when compiling the python source code, +# in order to use the modules that require ssl, such as pip3, twine, etc. +RUN yum install -y openssl-devel + +# Install which +RUN yum install -y which + +# Install wget +RUN yum install -y wget + +# Install git-2.x +# RUN yum -y install https://packages.endpoint.com/rhel/7/os/x86_64/endpoint-repo-1.7-1.x86_64.rpm +# RUN yum -y install git + +# rust +# https://www.rust-lang.org/tools/install +RUN curl https://sh.rustup.rs -sSf | bash -s -- -y +ENV PATH="/root/.cargo/bin:${PATH}" +ENV CARGO_NET_GIT_FETCH_WITH_CLI=true + +RUN cargo version +RUN rustc --version + +# wasm +RUN rustup target add wasm32-unknown-unknown + +# Install clang7 and llvm7 +# https://www.softwarecollections.org/en/scls/rhscl/llvm-toolset-7.0/ +# +# 1. Install a package with repository for your system: +# On CentOS, install package centos-release-scl available in CentOS repository: +# $ sudo yum install centos-release-scl +# +# On RHEL, enable RHSCL repository for you system: +# $ sudo yum-config-manager --enable rhel-server-rhscl-7-rpms +# +# 2. Install the collection: +# $ sudo yum install llvm-toolset-7.0 +# +# 3. Start using software collections: +# $ scl enable llvm-toolset-7.0 bash + +RUN yum -y install centos-release-scl +RUN yum-config-manager --enable rhel-server-rhscl-7-rpms +RUN yum -y install llvm-toolset-7.0 +RUN yum -y install llvm-toolset-7.0\* +RUN scl enable llvm-toolset-7.0 bash + +# Install gcc7 +RUN yum -y install devtoolset-7* +RUN scl enable devtoolset-7 bash +RUN gcc -v + +# rpm -ql llvm-toolset-7.0-clang.x86_64 +# /opt/rh/llvm-toolset-7.0/root/usr/lib64/libLLVM-7.so +ENV LD_LIBRARY_PATH="/opt/rh/llvm-toolset-7.0/root/usr/lib64:${LD_LIBRARY_PATH}" +ENV PATH="/opt/rh/llvm-toolset-7.0/root/usr/bin:${PATH}" + +RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime +RUN echo 'Asia/Shanghai' >/etc/timezone + +WORKDIR /root + +CMD ["bash"] diff --git a/scripts/docker/kcl-builder-centos7/Makefile b/scripts/docker/kcl-builder-centos7/Makefile new file mode 100644 index 000000000..264e80492 --- /dev/null +++ b/scripts/docker/kcl-builder-centos7/Makefile @@ -0,0 +1,31 @@ +# Copyright The KCL Authors. All rights reserved. + +PWD:=$(shell pwd) + +BUILDER_IMAGE:=kcllang/kcl-builder:centos7 + +# export DOCKER_DEFAULT_PLATFORM=linux/amd64 +# or +# --platform linux/amd64 + +RUN_IN_DOCKER:=docker run -it --rm --platform linux/amd64 +RUN_IN_DOCKER+=-v ~/.ssh:/root/.ssh +RUN_IN_DOCKER+=-v ~/.gitconfig:/root/.gitconfig +RUN_IN_DOCKER+=-v ~/go/pkg/mod:/go/pkg/mod + +kcl-builder: + docker build --platform linux/amd64 -t ${BUILDER_IMAGE} . + @echo "ok" + +publish-builder: + # https://docker.inc.com/ + # docker login --username= + + # make kcl-builder + docker push ${BUILDER_IMAGE} + @echo "push ${BUILDER_IMAGE} ok" + +sh: + ${RUN_IN_DOCKER} -v ${PWD}/../../..:/root/kclvm -w /root ${BUILDER_IMAGE} bash + +clean: diff --git a/scripts/docker/kcl-builder-centos8/Dockerfile b/scripts/docker/kcl-builder-centos8/Dockerfile new file mode 100644 index 000000000..92edb3d11 --- /dev/null +++ b/scripts/docker/kcl-builder-centos8/Dockerfile @@ -0,0 +1,76 @@ +# Copyright The KCL Authors. All rights reserved. + +FROM centos:centos8 + +# macOS M1 --platform linux/amd64 +# try fix "Problem with the SSL CA cert (path? access rights?)" +# https://issueexplorer.com/issue/docker/for-mac/5912 +# https://access.redhat.com/articles/2050743 +RUN touch /etc/sysconfig/64bit_strstr_via_64bit_strstr_sse2_unaligned + +# https://forketyfork.medium.com/centos-8-no-urls-in-mirrorlist-error-3f87c3466faa +RUN sed -i -e "s|mirrorlist=|#mirrorlist=|g" /etc/yum.repos.d/CentOS-* +RUN sed -i -e "s|#baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org|g" /etc/yum.repos.d/CentOS-* + +RUN yum -y install make +RUN yum -y install which +RUN yum -y install wget +RUN yum -y install git + +# ca-certificates +RUN yum -y install ca-certificates + +# rust-1.54.0 +# cargo 1.54.0 +# RUN yum -y install rust cargo rustfmt +RUN curl https://sh.rustup.rs -sSf | bash -s -- -y +RUN echo 'source $HOME/.cargo/env' >> $HOME/.bashrc + +ENV PATH="/root/.cargo/bin:${PATH}" +ENV CARGO_NET_GIT_FETCH_WITH_CLI=true + +RUN cargo version +RUN rustc --version + +# clang-12 +RUN yum -y install clang +RUN clang --version + +# llvm-12 +RUN yum -y install llvm-devel +RUN yum -y install libffi-devel +RUN ln -s /usr/lib64/libtinfo.so.6 /usr/lib64/libtinfo.so + +# golang 1.19+ +RUN mkdir -p /root/download && cd /root/download \ + && wget https://dl.google.com/go/go1.20.5.linux-amd64.tar.gz \ + && tar -zxvf go1.20.5.linux-amd64.tar.gz \ + && mv ./go /usr/local/go1.20.5 +RUN ln -sf /usr/local/go1.20.5/bin/go /usr/bin/go +RUN rm -rf /root/download + +ENV GOPATH=/go +ENV GOLANG_VERSION=1.20.5 + +RUN go install golang.org/x/lint/golint@latest +RUN go install golang.org/x/tools/cmd/goimports@latest +# RUN go install honnef.co/go/tools/cmd/...@latest + +RUN go install github.com/t-yuki/gocover-cobertura@latest +RUN go install github.com/jstemmer/go-junit-report@latest + +RUN rm -rf /go/pkg/mod +RUN rm -rf /go/pkg/sumdb + +# /usr/lib64/python3.9 +RUN yum -y install python39-devel +RUN python3 -m pip install pytest + +RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime +RUN echo 'Asia/Shanghai' >/etc/timezone + +RUN mkdir -p /root/.cargo && touch /root/.cargo/env + +WORKDIR /root + +CMD ["bash"] diff --git a/scripts/docker/kcl-builder-centos8/Makefile b/scripts/docker/kcl-builder-centos8/Makefile new file mode 100644 index 000000000..b5ed668aa --- /dev/null +++ b/scripts/docker/kcl-builder-centos8/Makefile @@ -0,0 +1,31 @@ +# Copyright The KCL Authors. All rights reserved. + +PWD:=$(shell pwd) + +BUILDER_IMAGE:=kcllang/kcl-builder:centos8 + +# export DOCKER_DEFAULT_PLATFORM=linux/amd64 +# or +# --platform linux/amd64 + +RUN_IN_DOCKER:=docker run -it --rm --platform linux/amd64 +RUN_IN_DOCKER+=-v ~/.ssh:/root/.ssh +RUN_IN_DOCKER+=-v ~/.gitconfig:/root/.gitconfig +RUN_IN_DOCKER+=-v ~/go/pkg/mod:/go/pkg/mod + +kcl-builder: + docker build --platform linux/amd64 -t ${BUILDER_IMAGE} . + @echo "ok" + +publish-builder: + # https://docker.inc.com/ + # docker login --username= + + # make kcl-builder + docker push ${BUILDER_IMAGE} + @echo "push ${BUILDER_IMAGE} ok" + +sh-in-builder: + ${RUN_IN_DOCKER} -v ${PWD}/../../..:/root/kclvm -w /root ${BUILDER_IMAGE} bash + +clean: diff --git a/scripts/docker/kcl-builder-fedora39/Dockerfile b/scripts/docker/kcl-builder-fedora39/Dockerfile new file mode 100644 index 000000000..1d0245437 --- /dev/null +++ b/scripts/docker/kcl-builder-fedora39/Dockerfile @@ -0,0 +1,46 @@ +# Copyright The KCL Authors. All rights reserved. + +FROM fedora:39 + +# Fix SSL CA cert issue +RUN touch /etc/sysconfig/64bit_strstr_via_64bit_strstr_sse2_unaligned + +# Fix mirrorlist issue +RUN sed -i -e "s|metalink=|#metalink=|g" /etc/yum.repos.d/fedora*.repo +RUN sed -i -e "s|#baseurl=http://download.example/pub/fedora/linux|baseurl=https://dl.fedoraproject.org/pub/fedora/linux|g" /etc/yum.repos.d/fedora*.repo + +# install necessary packages +RUN dnf -y install make which wget git ca-certificates clang llvm-devel libffi-devel python3-devel + +# rust +RUN curl https://sh.rustup.rs -sSf | bash -s -- -y && \ + echo 'source $HOME/.cargo/env' >> $HOME/.bashrc +ENV PATH="/root/.cargo/bin:${PATH}" +ENV CARGO_NET_GIT_FETCH_WITH_CLI=true + +# go +RUN mkdir -p /root/download && cd /root/download \ + && wget https://dl.google.com/go/go1.20.5.linux-amd64.tar.gz \ + && tar -zxvf go1.20.5.linux-amd64.tar.gz \ + && mv ./go /usr/local/go1.20.5 +RUN ln -sf /usr/local/go1.20.5/bin/go /usr/bin/go +RUN rm -rf /root/download +ENV GOPATH=/go +ENV GOLANG_VERSION=1.20.5 + +# go tools +RUN go install golang.org/x/lint/golint@latest \ + && go install golang.org/x/tools/cmd/goimports@latest \ + && go install github.com/t-yuki/gocover-cobertura@latest \ + && go install github.com/jstemmer/go-junit-report@latest + +RUN python3 -m pip install pytest + +RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime +RUN echo 'Asia/Shanghai' >/etc/timezone + +RUN mkdir -p /root/.cargo && touch /root/.cargo/env + +WORKDIR /root + +CMD ["bash"] diff --git a/scripts/docker/kcl-builder-fedora39/Makefile b/scripts/docker/kcl-builder-fedora39/Makefile new file mode 100644 index 000000000..fadde5364 --- /dev/null +++ b/scripts/docker/kcl-builder-fedora39/Makefile @@ -0,0 +1,25 @@ +PWD := $(shell pwd) + +BUILDER_IMAGE := kcllang/kcl-builder-fedora39 + +RUN_IN_DOCKER:=docker run -it --rm --platform linux/amd64 +RUN_IN_DOCKER+=-v ~/.ssh:/root/.ssh +RUN_IN_DOCKER+=-v ~/.gitconfig:/root/.gitconfig +RUN_IN_DOCKER+=-v ~/go/pkg/mod:/go/pkg/mod + +kcl-builder: + docker build --platform linux/amd64 -t ${BUILDER_IMAGE} . + @echo "ok" + +publish-builder: + # https://docker.inc.com/ + # docker login --username= + + # make kcl-builder + docker push ${BUILDER_IMAGE} + @echo "push ${BUILDER_IMAGE} ok" + +sh-in-builder: + ${RUN_IN_DOCKER} -v ${PWD}/../../..:/root/kclvm -w /root ${BUILDER_IMAGE} bash + +clean: \ No newline at end of file diff --git a/scripts/docker/kcl-builder/Dockerfile b/scripts/docker/kcl-builder/Dockerfile new file mode 100644 index 000000000..b79efa091 --- /dev/null +++ b/scripts/docker/kcl-builder/Dockerfile @@ -0,0 +1,72 @@ +# Copyright The KCL Authors. All rights reserved. + +FROM ubuntu:22.04 + +#RUN uname -a +#RUN cat /etc/os-release + +RUN apt-get update + +RUN apt-get install -y git wget curl +RUN apt-get install -y make gcc patch g++ swig +RUN apt-get install -y python3-dev libffi-dev +# SSL module deps sed by python3 +RUN apt-get install -y zlib1g-dev ncurses-dev build-essential libncurses5-dev libgdbm-dev libnss3-dev libssl-dev libreadline-dev libffi-dev + +# python-3.9 +RUN mkdir -p /root/download && cd /root/download \ + && wget https://www.python.org/ftp/python/3.9.10/Python-3.9.10.tgz \ + && tar -xzf Python-3.9.10.tgz \ + && cd Python-3.9.10 \ + && LANG=C.UTF-8 ./configure \ + --prefix=/usr/local/python3.9 \ + --enable-optimizations \ + --with-ssl \ + && make install +RUN ln -sf /usr/local/python3.9/bin/python3.9 /usr/bin/python3 +RUN ln -sf /usr/local/python3.9/bin/python3.9 /usr/bin/python3.9 + +# rust +# https://www.rust-lang.org/tools/install +RUN curl https://sh.rustup.rs -sSf | bash -s -- -y +ENV PATH="/root/.cargo/bin:${PATH}" +ENV CARGO_NET_GIT_FETCH_WITH_CLI=true + +RUN cargo version +RUN rustc --version + +# wasm +RUN rustup target add wasm32-unknown-unknown + +# clang12 +RUN apt-get install -y clang-12 lld-12 +RUN ln -sf /usr/bin/clang-12 /usr/bin/clang +RUN ln -sf /usr/bin/wasm-ld-12 /usr/bin/wasm-ld + +# golang 1.20+ +RUN mkdir -p /root/download && cd /root/download \ + && wget https://dl.google.com/go/go1.20.5.linux-amd64.tar.gz \ + && tar -zxvf go1.20.5.linux-amd64.tar.gz \ + && mv ./go /usr/local/go1.20.5 +RUN ln -sf /usr/local/go1.20.5/bin/go /usr/bin/go +RUN rm -rf /root/download + +ENV GOPATH=/go +ENV GOLANG_VERSION=1.20.5 + +RUN go install golang.org/x/lint/golint@latest +RUN go install golang.org/x/tools/cmd/goimports@latest +RUN go install honnef.co/go/tools/cmd/...@latest + +RUN go install github.com/t-yuki/gocover-cobertura@latest +RUN go install github.com/jstemmer/go-junit-report@latest + +RUN rm -rf /go/pkg/mod +RUN rm -rf /go/pkg/sumdb + +RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime +RUN echo 'Asia/Shanghai' >/etc/timezone + +WORKDIR /root + +CMD ["bash"] diff --git a/scripts/docker/kcl-builder/Makefile b/scripts/docker/kcl-builder/Makefile new file mode 100644 index 000000000..4e3f78a68 --- /dev/null +++ b/scripts/docker/kcl-builder/Makefile @@ -0,0 +1,31 @@ +# Copyright The KCL Authors. All rights reserved. + +PWD:=$(shell pwd) + +BUILDER_IMAGE:=kcllang/kcl-builder + +# export DOCKER_DEFAULT_PLATFORM=linux/amd64 +# or +# --platform linux/amd64 + +RUN_IN_DOCKER:=docker run -it --rm --platform linux/amd64 +RUN_IN_DOCKER+=-v ~/.ssh:/root/.ssh +RUN_IN_DOCKER+=-v ~/.gitconfig:/root/.gitconfig +RUN_IN_DOCKER+=-v ~/go/pkg/mod:/go/pkg/mod + +kcl-builder: + docker build --platform linux/amd64 -t ${BUILDER_IMAGE} . + @echo "ok" + +publish-builder: + # https://docker.inc.com/ + # docker login --username= + + # make kcl-builder + docker push ${BUILDER_IMAGE} + @echo "push ${BUILDER_IMAGE} ok" + +sh: + ${RUN_IN_DOCKER} -v ${PWD}/../../..:/root/kclvm -w /root ${BUILDER_IMAGE} bash + +clean: diff --git a/scripts/docker/kclvm-builder-centos7/Dockerfile b/scripts/docker/kclvm-builder-centos7/Dockerfile deleted file mode 100644 index eb46286fe..000000000 --- a/scripts/docker/kclvm-builder-centos7/Dockerfile +++ /dev/null @@ -1,89 +0,0 @@ -# Copyright 2021 The KCL Authors. All rights reserved. - -FROM centos:centos7 - -# macOS M1 --platform linux/amd64 -# try fix "Problem with the SSL CA cert (path? access rights?)" -# https://issueexplorer.com/issue/docker/for-mac/5912 -# https://access.redhat.com/articles/2050743 -RUN touch /etc/sysconfig/64bit_strstr_via_64bit_strstr_sse2_unaligned - -# --------------------------------------------------------------------------------- -# Please note: The following steps are to install the dependency packages -# needed to compile CPython for centos7, see the -# [Python official website](https://devguide.python.org/setup/#install-dependencies) -# for details. When the version of CPython used becomes higher, -# please pay attention to update the installation dependencies. -# --------------------------------------------------------------------------------- - -# Some language environments and plug-ins related to development and compilation, -# such as git, CPython compilation, etc. -RUN yum groupinstall -y "Development Tools" -# Compiler and tool chain required to compile CPython such as gcc, make, sqlite3, ctype, struct, etc. -RUN yum install -y gcc patch libffi-devel python-devel zlib-devel bzip2-devel ncurses-devel sqlite-devel -RUN yum install -y libpcap-devel xz-devel readline-devel tk-devel gdbm-devel db4-deve -# Install the system libraries required by python3 for UNIX based systems -RUN yum -y install yum-utils -RUN yum-builddep -y python3 -# The python zlib module dependency package is required when compiling the python source code, -# in order to use the modules that require zlib, such as setuptools, etc. -RUN yum install -y zlib* -# The python ssl module dependency package is required when compiling the python source code, -# in order to use the modules that require ssl, such as pip3, twine, etc. -RUN yum install -y openssl-devel - -# install which -RUN yum install -y which - -# install wget -RUN yum install -y wget - -# install git-2.x -# RUN yum -y install https://packages.endpoint.com/rhel/7/os/x86_64/endpoint-repo-1.7-1.x86_64.rpm -# RUN yum -y install git - -# rust -# https://www.rust-lang.org/tools/install -RUN curl https://sh.rustup.rs -sSf | bash -s -- -y -ENV PATH="/root/.cargo/bin:${PATH}" -ENV CARGO_NET_GIT_FETCH_WITH_CLI=true - -RUN cargo version -RUN rustc --version - -# wasm -RUN rustup target add wasm32-unknown-unknown - -# clang7 -# https://www.softwarecollections.org/en/scls/rhscl/llvm-toolset-7.0/ -# -# 1. Install a package with repository for your system: -# On CentOS, install package centos-release-scl available in CentOS repository: -# $ sudo yum install centos-release-scl -# -# On RHEL, enable RHSCL repository for you system: -# $ sudo yum-config-manager --enable rhel-server-rhscl-7-rpms -# -# 2. Install the collection: -# $ sudo yum install llvm-toolset-7.0 -# -# 3. Start using software collections: -# $ scl enable llvm-toolset-7.0 bash - -RUN yum -y install centos-release-scl -RUN yum-config-manager --enable rhel-server-rhscl-7-rpms -RUN yum -y install llvm-toolset-7.0 -RUN yum -y install llvm-toolset-7.0\* -RUN scl enable llvm-toolset-7.0 bash - -# rpm -ql llvm-toolset-7.0-clang.x86_64 -# /opt/rh/llvm-toolset-7.0/root/usr/lib64/libLLVM-7.so -ENV LD_LIBRARY_PATH="/opt/rh/llvm-toolset-7.0/root/usr/lib64:${LD_LIBRARY_PATH}" -ENV PATH="/opt/rh/llvm-toolset-7.0/root/usr/bin:${PATH}" - -RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime -RUN echo 'Asia/Shanghai' >/etc/timezone - -WORKDIR /root - -CMD ["bash"] diff --git a/scripts/docker/kclvm-builder-centos7/Makefile b/scripts/docker/kclvm-builder-centos7/Makefile deleted file mode 100644 index 9868ff39d..000000000 --- a/scripts/docker/kclvm-builder-centos7/Makefile +++ /dev/null @@ -1,32 +0,0 @@ -# Copyright 2021 The KCL Authors. All rights reserved. - -PWD:=$(shell pwd) -TIMESTAMP:=$(shell go run timestamp.go) - -BUILDER_IMAGE:=kusionstack/kclvm-builder:centos7 - -# export DOCKER_DEFAULT_PLATFORM=linux/amd64 -# or -# --platform linux/amd64 - -RUN_IN_DOCKER:=docker run -it --rm --platform linux/amd64 -RUN_IN_DOCKER+=-v ~/.ssh:/root/.ssh -RUN_IN_DOCKER+=-v ~/.gitconfig:/root/.gitconfig -RUN_IN_DOCKER+=-v ~/go/pkg/mod:/go/pkg/mod - -kclvm-builder: - docker build --platform linux/amd64 -t ${BUILDER_IMAGE} . - @echo "ok" - -publish-builder: - # https://docker.inc.com/ - # docker login --username= - - # make kclvm-builder - docker push ${BUILDER_IMAGE} - @echo "push ${BUILDER_IMAGE} ok" - -sh: - ${RUN_IN_DOCKER} -v ${PWD}/../../..:/root/kclvm -w /root ${BUILDER_IMAGE} bash - -clean: diff --git a/scripts/docker/kclvm-builder-centos7/timestamp.go b/scripts/docker/kclvm-builder-centos7/timestamp.go deleted file mode 100644 index 96d8a87dc..000000000 --- a/scripts/docker/kclvm-builder-centos7/timestamp.go +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright 2021 The KCL Authors. All rights reserved. - -//go:build ignore -// +build ignore - -package main - -import ( - "fmt" - "time" -) - -func main() { - t := time.Now() - fmt.Printf( - "%04d%02d%02d-%02d%02d%02d", - t.Year(), t.Month(), t.Day(), - t.Hour(), t.Minute(), t.Second(), - ) -} diff --git a/scripts/docker/kclvm-builder-centos8/Dockerfile b/scripts/docker/kclvm-builder-centos8/Dockerfile deleted file mode 100644 index ff30e1451..000000000 --- a/scripts/docker/kclvm-builder-centos8/Dockerfile +++ /dev/null @@ -1,74 +0,0 @@ -# Copyright 2021 The KCL Authors. All rights reserved. - -FROM centos:centos8 - -# macOS M1 --platform linux/amd64 -# try fix "Problem with the SSL CA cert (path? access rights?)" -# https://issueexplorer.com/issue/docker/for-mac/5912 -# https://access.redhat.com/articles/2050743 -RUN touch /etc/sysconfig/64bit_strstr_via_64bit_strstr_sse2_unaligned - -RUN yum -y install make -RUN yum -y install which -RUN yum -y install wget -RUN yum -y install git - -# ca-certificates -RUN yum -y install ca-certificates - -# rust-1.54.0 -# cargo 1.54.0 -RUN yum -y install rust cargo rustfmt -# RUN curl https://sh.rustup.rs -sSf | bash -s -- -y -RUN echo 'source $HOME/.cargo/env' >> $HOME/.bashrc - -ENV PATH="/root/.cargo/bin:${PATH}" -ENV CARGO_NET_GIT_FETCH_WITH_CLI=true - -RUN cargo version -RUN rustc --version - -# clang-12 -RUN yum -y install clang -RUN clang --version - -# llvm-12 -RUN yum -y install llvm-devel -RUN yum -y install libffi-devel -RUN ln -s /usr/lib64/libtinfo.so.6 /usr/lib64/libtinfo.so - -# Go 1.6 -RUN yum -y install golang -RUN go version - -# /usr/lib64/python3.9 -RUN yum -y install python39-devel -RUN python3 -m pip install pytest - -# golang apps -RUN go get golang.org/x/lint/golint -RUN go get golang.org/x/tools/cmd/goimports -#RUN go get honnef.co/go/tools/cmd/... - -RUN go get github.com/t-yuki/gocover-cobertura -RUN go get github.com/jstemmer/go-junit-report - -RUN rm -rf /go/pkg/mod -RUN rm -rf /go/pkg/sumdb - -RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime -RUN echo 'Asia/Shanghai' >/etc/timezone - -#COPY ./vendor-kclvm /root/vendor-kclvm -#COPY ./vendor-kclvm-runtime /root/vendor-kclvm-runtime - -COPY ./crates.io-index /root/crates.io-index - -RUN mkdir -p /root/.cargo -COPY ./_cargo_config-kclvm.toml /root/.cargo/config - -RUN touch /root/.cargo/env - -WORKDIR /root - -CMD ["bash"] diff --git a/scripts/docker/kclvm-builder-centos8/Makefile b/scripts/docker/kclvm-builder-centos8/Makefile deleted file mode 100644 index ae29d16bd..000000000 --- a/scripts/docker/kclvm-builder-centos8/Makefile +++ /dev/null @@ -1,57 +0,0 @@ -# Copyright 2021 The KCL Authors. All rights reserved. - -PWD:=$(shell pwd) -TIMESTAMP:=$(shell go run timestamp.go) - -BUILDER_IMAGE:=reg.docker.inc.com/kusionstack/kclvm-builder-centos8 - -# export DOCKER_DEFAULT_PLATFORM=linux/amd64 -# or -# --platform linux/amd64 - -RUN_IN_DOCKER:=docker run -it --rm --platform linux/amd64 -RUN_IN_DOCKER+=-v ~/.ssh:/root/.ssh -RUN_IN_DOCKER+=-v ~/.gitconfig:/root/.gitconfig -RUN_IN_DOCKER+=-v ~/go/pkg/mod:/go/pkg/mod - -kclvm-builder: crates.io-index - docker build --platform linux/amd64 -t ${BUILDER_IMAGE} . - @echo "ok" - -crates.io-index: - git clone --mirror git@github.com:rust-lang/crates.io-index.git crates.io-index - -vendor-kclvm: - -rm -rf ${PWD}/../../kclvm/vendor - - ${RUN_IN_DOCKER} -v ${PWD}/../..:/root/kclvm -w /root/kclvm/kclvm rust:1.54 cargo vendor --versioned-dirs - mv ${PWD}/../../kclvm/vendor ./vendor-kclvm - - -vendor-kclvm-runtime: - -rm -rf ${PWD}/../../kclvm/runtime/vendor - - ${RUN_IN_DOCKER} -v ${PWD}/../..:/root/kclvm -w /root/kclvm/kclvm/runtime rust:1.54 cargo vendor --versioned-dirs - mv ${PWD}/../../kclvm/runtime/vendor ./vendor-kclvm-runtime - -publish-builder: - # https://docker.inc.com/ - # docker login --username= reg.docker.inc.com - - # make kclvm-builder - docker push ${BUILDER_IMAGE} - @echo "push ${BUILDER_IMAGE} ok" - -publish-builder-tagged: - # https://docker.inc.com/ - # docker login --username= reg.docker.inc.com - - # make kclvm-builder - docker tag ${BUILDER_IMAGE} ${BUILDER_IMAGE}:${TIMESTAMP} - docker push ${BUILDER_IMAGE}:${TIMESTAMP} - @echo "push ${BUILDER_IMAGE}:${TIMESTAMP} ok" - -sh-in-builder: - ${RUN_IN_DOCKER} -v ${PWD}/../..:/root/kclvm -w /root ${BUILDER_IMAGE} bash - -clean: diff --git a/scripts/docker/kclvm-builder-centos8/_cargo_config-kclvmx.toml b/scripts/docker/kclvm-builder-centos8/_cargo_config-kclvmx.toml deleted file mode 100644 index e268e03a6..000000000 --- a/scripts/docker/kclvm-builder-centos8/_cargo_config-kclvmx.toml +++ /dev/null @@ -1,10 +0,0 @@ -# https://stackoverflow.com/questions/31029095/disable-registry-update-in-cargo -# https://doc.rust-lang.org/cargo/reference/config.html - -# /root/.cargo/config - -[source.crates-io] -replace-with = 'local' - -[source.local] -registry = "file:///root/crates.io-index" diff --git a/scripts/docker/kclvm-builder-centos8/timestamp.go b/scripts/docker/kclvm-builder-centos8/timestamp.go deleted file mode 100644 index 96d8a87dc..000000000 --- a/scripts/docker/kclvm-builder-centos8/timestamp.go +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright 2021 The KCL Authors. All rights reserved. - -//go:build ignore -// +build ignore - -package main - -import ( - "fmt" - "time" -) - -func main() { - t := time.Now() - fmt.Printf( - "%04d%02d%02d-%02d%02d%02d", - t.Year(), t.Month(), t.Day(), - t.Hour(), t.Minute(), t.Second(), - ) -} diff --git a/scripts/docker/kclvm-builder/Dockerfile b/scripts/docker/kclvm-builder/Dockerfile deleted file mode 100644 index 7c9482c8c..000000000 --- a/scripts/docker/kclvm-builder/Dockerfile +++ /dev/null @@ -1,72 +0,0 @@ -# Copyright 2021 The KCL Authors. All rights reserved. - -FROM ubuntu:20.04 - -#RUN uname -a -#RUN cat /etc/os-release - -RUN apt-get update - -RUN apt-get install -y git wget curl -RUN apt-get install -y make gcc patch g++ swig -RUN apt-get install -y python-dev libffi-dev -# SSL module deps sed by python3 -RUN apt-get install -y zlib1g-dev ncurses-dev build-essential libncurses5-dev libgdbm-dev libnss3-dev libssl-dev libreadline-dev libffi-dev - -# python-3.9 -RUN mkdir -p /root/download && cd /root/download \ - && wget http://npm.taobao.org/mirrors/python/3.9.10/Python-3.9.10.tgz \ - && tar -xzf Python-3.9.10.tgz \ - && cd Python-3.9.10 \ - && LANG=C.UTF-8 ./configure \ - --prefix=/usr/local/python3.9 \ - --enable-optimizations \ - --with-ssl \ - && make install -RUN ln -sf /usr/local/python3.9/bin/python3.9 /usr/bin/python3 -RUN ln -sf /usr/local/python3.9/bin/python3.9 /usr/bin/python3.9 - -# rust -# https://www.rust-lang.org/tools/install -RUN curl https://sh.rustup.rs -sSf | bash -s -- -y -ENV PATH="/root/.cargo/bin:${PATH}" -ENV CARGO_NET_GIT_FETCH_WITH_CLI=true - -RUN cargo version -RUN rustc --version - -# wasm -RUN rustup target add wasm32-unknown-unknown - -# clang12 -RUN apt-get install -y clang-12 lld-12 -RUN ln -sf /usr/bin/clang-12 /usr/bin/clang -RUN ln -sf /usr/bin/wasm-ld-12 /usr/bin/wasm-ld - -# golang 1.17+ -RUN mkdir -p /root/download && cd /root/download \ - && wget https://dl.google.com/go/go1.17.3.linux-amd64.tar.gz \ - && tar -zxvf go1.17.3.linux-amd64.tar.gz \ - && mv ./go /usr/local/go1.17.3 -RUN ln -sf /usr/local/go1.17.3/bin/go /usr/bin/go -RUN rm -rf /root/download - -ENV GOPATH=/go -ENV GOLANG_VERSION=1.17.3 - -RUN go get golang.org/x/lint/golint -RUN go get golang.org/x/tools/cmd/goimports -RUN go get honnef.co/go/tools/cmd/... - -RUN go get github.com/t-yuki/gocover-cobertura -RUN go get github.com/jstemmer/go-junit-report - -RUN rm -rf /go/pkg/mod -RUN rm -rf /go/pkg/sumdb - -RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime -RUN echo 'Asia/Shanghai' >/etc/timezone - -WORKDIR /root - -CMD ["bash"] diff --git a/scripts/docker/kclvm-builder/Makefile b/scripts/docker/kclvm-builder/Makefile deleted file mode 100644 index 5fbabadd3..000000000 --- a/scripts/docker/kclvm-builder/Makefile +++ /dev/null @@ -1,31 +0,0 @@ -# Copyright 2021 The KCL Authors. All rights reserved. - -PWD:=$(shell pwd) - -BUILDER_IMAGE:=kusionstack/kclvm-builder - -# export DOCKER_DEFAULT_PLATFORM=linux/amd64 -# or -# --platform linux/amd64 - -RUN_IN_DOCKER:=docker run -it --rm --platform linux/amd64 -RUN_IN_DOCKER+=-v ~/.ssh:/root/.ssh -RUN_IN_DOCKER+=-v ~/.gitconfig:/root/.gitconfig -RUN_IN_DOCKER+=-v ~/go/pkg/mod:/go/pkg/mod - -kclvm-builder: - docker build --platform linux/amd64 -t ${BUILDER_IMAGE} . - @echo "ok" - -publish-builder: - # https://docker.inc.com/ - # docker login --username= - - # make kclvm-builder - docker push ${BUILDER_IMAGE} - @echo "push ${BUILDER_IMAGE} ok" - -sh: - ${RUN_IN_DOCKER} -v ${PWD}/../../..:/root/kclvm -w /root ${BUILDER_IMAGE} bash - -clean: diff --git a/scripts/release.sh b/scripts/release.sh new file mode 100755 index 000000000..ad660bd1e --- /dev/null +++ b/scripts/release.sh @@ -0,0 +1,38 @@ +#!/usr/bin/env bash + +getSystemInfo() { + arch=$(uname -m) + case $arch in + armv7*) arch="arm";; + aarch64) arch="arm64";; + x86_64) arch="amd64";; + esac + + os=$(echo `uname`|tr '[:upper:]' '[:lower:]') +} + +if [ -z "$version" ]; then + version=$1 +fi +if [ -z "$version" ]; then + version='latest' +fi + +getSystemInfo + +echo "[info] os: $os" +echo "[info] arch: $arch" +echo "[info] version: $version" +release_file="kclvm-$version-$os-$arch.tar.gz" +release_path="$topdir/_build" +package_dir="$topdir/_build/dist/$os" +install_dir="kclvm" + +cd $package_dir +tar -czvf $release_file $install_dir + +mv $package_dir/$release_file $release_path/$release_file + +# Print the summary. +echo "================ Summary ================" +echo " $release_path/$release_file has been created" diff --git a/scripts/tag.sh b/scripts/tag.sh new file mode 100755 index 000000000..b9286c58e --- /dev/null +++ b/scripts/tag.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env sh +set -e +if [ "$1" == "" ]; then + echo usage: "$0 VERSION" +fi +git tag $1 +git push origin $1 +gh release create $1 --draft --generate-notes --title "$1 Release" diff --git a/test/grammar/assert/invalid/fail_0/stderr.golden b/test/grammar/assert/invalid/fail_0/stderr.golden new file mode 100644 index 000000000..2047a8f1b --- /dev/null +++ b/test/grammar/assert/invalid/fail_0/stderr.golden @@ -0,0 +1,6 @@ +error[E3M38]: EvaluationError + --> ${CWD}/main.k:1:1 + | +1 | assert False + | + | \ No newline at end of file diff --git a/test/grammar/assert/invalid/fail_0/stderr.golden.py b/test/grammar/assert/invalid/fail_0/stderr.golden.py deleted file mode 100644 index e559a04cc..000000000 --- a/test/grammar/assert/invalid/fail_0/stderr.golden.py +++ /dev/null @@ -1,15 +0,0 @@ -import sys -import os - -import kclvm.kcl.error as kcl_error - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message(kcl_error.get_exception(err_type=kcl_error.ErrType.AssertionError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=1 - )] - ), - file=sys.stdout) diff --git a/test/grammar/assert/invalid/fail_1/stderr.golden b/test/grammar/assert/invalid/fail_1/stderr.golden new file mode 100644 index 000000000..e8797487b --- /dev/null +++ b/test/grammar/assert/invalid/fail_1/stderr.golden @@ -0,0 +1,6 @@ +error[E3M38]: EvaluationError + --> ${CWD}/main.k:1:1 + | +1 | assert 1 == 2, '1 is not equal to 2' + | 1 is not equal to 2 + | \ No newline at end of file diff --git a/test/grammar/assert/invalid/fail_1/stderr.golden.py b/test/grammar/assert/invalid/fail_1/stderr.golden.py deleted file mode 100644 index 1ae5f6c7b..000000000 --- a/test/grammar/assert/invalid/fail_1/stderr.golden.py +++ /dev/null @@ -1,22 +0,0 @@ - -import sys -import os - -import kclvm.kcl.error as kcl_error - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.AssertionError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=1 - ) - ], - arg_msg="1 is not equal to 2" - ) - , file=sys.stdout -) - diff --git a/test/grammar/assert/invalid/fail_2/stderr.golden b/test/grammar/assert/invalid/fail_2/stderr.golden new file mode 100644 index 000000000..93ee8da44 --- /dev/null +++ b/test/grammar/assert/invalid/fail_2/stderr.golden @@ -0,0 +1,6 @@ +error[E3M38]: EvaluationError + --> ${CWD}/main.k:2:1 + | +2 | assert _x == "bad case", "x should be 'good case'" + | x should be 'good case' + | \ No newline at end of file diff --git a/test/grammar/assert/invalid/fail_2/stderr.golden.py b/test/grammar/assert/invalid/fail_2/stderr.golden.py deleted file mode 100644 index b09935282..000000000 --- a/test/grammar/assert/invalid/fail_2/stderr.golden.py +++ /dev/null @@ -1,22 +0,0 @@ - -import sys -import os - -import kclvm.kcl.error as kcl_error - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.AssertionError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=2 - ) - ], - arg_msg="x should be 'good case'" - ) - , file=sys.stdout -) - diff --git a/test/grammar/assert/invalid/fail_3/stderr.golden b/test/grammar/assert/invalid/fail_3/stderr.golden new file mode 100644 index 000000000..72a3b312a --- /dev/null +++ b/test/grammar/assert/invalid/fail_3/stderr.golden @@ -0,0 +1,6 @@ +error[E3M38]: EvaluationError + --> ${CWD}/main.k:3:1 + | +3 | assert _x == "bad case" if _x, "x should be 'good case'" + | x should be 'good case' + | \ No newline at end of file diff --git a/test/grammar/assert/invalid/fail_3/stderr.golden.py b/test/grammar/assert/invalid/fail_3/stderr.golden.py deleted file mode 100644 index ced74dad3..000000000 --- a/test/grammar/assert/invalid/fail_3/stderr.golden.py +++ /dev/null @@ -1,22 +0,0 @@ - -import sys -import os - -import kclvm.kcl.error as kcl_error - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.AssertionError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=3 - ) - ], - arg_msg="x should be 'good case'" - ) - , file=sys.stdout -) - diff --git a/test/grammar/assign/assign_0/main.k b/test/grammar/assign/assign_0/main.k new file mode 100644 index 000000000..860c26289 --- /dev/null +++ b/test/grammar/assign/assign_0/main.k @@ -0,0 +1,4 @@ +_a = [0, 1] * 2 +_a[0] = 2 +_a[1] += 2 +a = _a diff --git a/test/grammar/assign/assign_0/stdout.golden b/test/grammar/assign/assign_0/stdout.golden new file mode 100644 index 000000000..98515f468 --- /dev/null +++ b/test/grammar/assign/assign_0/stdout.golden @@ -0,0 +1,5 @@ +a: +- 2 +- 3 +- 0 +- 1 diff --git a/test/grammar/assign/assign_1/main.k b/test/grammar/assign/assign_1/main.k new file mode 100644 index 000000000..7e564c730 --- /dev/null +++ b/test/grammar/assign/assign_1/main.k @@ -0,0 +1,4 @@ +_a = [{key1.key2 = [0] * 2}, {key3.key4 = [0] * 2}] +_a[0].key1.key2[0] = 1 +_a[1].key3.key4[1] += 1 +a = _a diff --git a/test/grammar/assign/assign_1/stdout.golden b/test/grammar/assign/assign_1/stdout.golden new file mode 100644 index 000000000..9d37d64a7 --- /dev/null +++ b/test/grammar/assign/assign_1/stdout.golden @@ -0,0 +1,9 @@ +a: +- key1: + key2: + - 1 + - 0 +- key3: + key4: + - 0 + - 1 diff --git a/test/grammar/assign/assign_fail_0/main.k b/test/grammar/assign/assign_fail_0/main.k new file mode 100644 index 000000000..2b0f4bcb0 --- /dev/null +++ b/test/grammar/assign/assign_fail_0/main.k @@ -0,0 +1,3 @@ +_a = [0, 1] * 2 +_a[10] = 2 +a = _a diff --git a/test/grammar/assign/assign_fail_0/stderr.golden b/test/grammar/assign/assign_fail_0/stderr.golden new file mode 100644 index 000000000..707a6d2dc --- /dev/null +++ b/test/grammar/assign/assign_fail_0/stderr.golden @@ -0,0 +1 @@ +index out of bounds: the len is 4 but the index is 10 \ No newline at end of file diff --git a/test/grammar/assign/assign_fail_1/main.k b/test/grammar/assign/assign_fail_1/main.k new file mode 100644 index 000000000..54001b50a --- /dev/null +++ b/test/grammar/assign/assign_fail_1/main.k @@ -0,0 +1,3 @@ +_a = [{key1.key2 = [0] * 2}, {key3.key4 = [0] * 2}] +_a[1].key1.key2[1] += 1 +a = _a diff --git a/test/grammar/assign/assign_fail_1/stderr.golden b/test/grammar/assign/assign_fail_1/stderr.golden new file mode 100644 index 000000000..ee35051cd --- /dev/null +++ b/test/grammar/assign/assign_fail_1/stderr.golden @@ -0,0 +1 @@ +invalid value 'UndefinedType' to load attribute 'key2' \ No newline at end of file diff --git a/test/grammar/assign/assign_fail_2/main.k b/test/grammar/assign/assign_fail_2/main.k new file mode 100644 index 000000000..1ef8a0c15 --- /dev/null +++ b/test/grammar/assign/assign_fail_2/main.k @@ -0,0 +1,2 @@ +_a = [1, 2, 3] +_a[1:2] = [2, 3] \ No newline at end of file diff --git a/test/grammar/assign/assign_fail_2/stderr.golden b/test/grammar/assign/assign_fail_2/stderr.golden new file mode 100644 index 000000000..e282bf990 --- /dev/null +++ b/test/grammar/assign/assign_fail_2/stderr.golden @@ -0,0 +1 @@ +'SubscriptExpression' is an illegal expression for assignment, because the left-hand side of an assignment expression may not be a slice access \ No newline at end of file diff --git a/test/grammar/assign/assign_fail_3/main.k b/test/grammar/assign/assign_fail_3/main.k new file mode 100644 index 000000000..af839bf50 --- /dev/null +++ b/test/grammar/assign/assign_fail_3/main.k @@ -0,0 +1,2 @@ +_a = {} +_a?.b = "value" \ No newline at end of file diff --git a/test/grammar/assign/assign_fail_3/stderr.golden b/test/grammar/assign/assign_fail_3/stderr.golden new file mode 100644 index 000000000..f485aa623 --- /dev/null +++ b/test/grammar/assign/assign_fail_3/stderr.golden @@ -0,0 +1 @@ +'SelectorExpression' is an illegal expression for assignment, because the left-hand side of an assignment expression may not be an optional attribute access. diff --git a/test/grammar/assign/assign_fail_4/main.k b/test/grammar/assign/assign_fail_4/main.k new file mode 100644 index 000000000..f1097573a --- /dev/null +++ b/test/grammar/assign/assign_fail_4/main.k @@ -0,0 +1 @@ +_a + 1 = 2 \ No newline at end of file diff --git a/test/grammar/assign/assign_fail_4/stderr.golden b/test/grammar/assign/assign_fail_4/stderr.golden new file mode 100644 index 000000000..af7a9f804 --- /dev/null +++ b/test/grammar/assign/assign_fail_4/stderr.golden @@ -0,0 +1 @@ +'BinaryExpression' is an illegal expression for assignment \ No newline at end of file diff --git a/test/grammar/assign/assign_fail_5/main.k b/test/grammar/assign/assign_fail_5/main.k new file mode 100644 index 000000000..ad7d54061 --- /dev/null +++ b/test/grammar/assign/assign_fail_5/main.k @@ -0,0 +1 @@ +[1] = 2 \ No newline at end of file diff --git a/test/grammar/assign/assign_fail_5/stderr.golden b/test/grammar/assign/assign_fail_5/stderr.golden new file mode 100644 index 000000000..9b88d5258 --- /dev/null +++ b/test/grammar/assign/assign_fail_5/stderr.golden @@ -0,0 +1 @@ +'ListExpression' is an illegal expression for assignment \ No newline at end of file diff --git a/test/grammar/assign/assign_fail_6/main.k b/test/grammar/assign/assign_fail_6/main.k new file mode 100644 index 000000000..41c9a8a35 --- /dev/null +++ b/test/grammar/assign/assign_fail_6/main.k @@ -0,0 +1 @@ +_f() = 2 \ No newline at end of file diff --git a/test/grammar/assign/assign_fail_6/stderr.golden b/test/grammar/assign/assign_fail_6/stderr.golden new file mode 100644 index 000000000..fc14ede0d --- /dev/null +++ b/test/grammar/assign/assign_fail_6/stderr.golden @@ -0,0 +1 @@ +'CallExpression' is an illegal expression for assignment \ No newline at end of file diff --git a/test/grammar/attr_operator/config_inside/insert/dict_2/main.k b/test/grammar/attr_operator/config_inside/insert/dict_2/main.k new file mode 100644 index 000000000..4e7150f36 --- /dev/null +++ b/test/grammar/attr_operator/config_inside/insert/dict_2/main.k @@ -0,0 +1,12 @@ +config = { + main: { + env: [ + {name: "ENV_1", value: "1"} + ] + } + main: { + env += [ + {name: "ENV_2", value: "2"} + ] + } +} diff --git a/test/grammar/attr_operator/config_inside/insert/dict_2/stdout.golden b/test/grammar/attr_operator/config_inside/insert/dict_2/stdout.golden new file mode 100644 index 000000000..853930d54 --- /dev/null +++ b/test/grammar/attr_operator/config_inside/insert/dict_2/stdout.golden @@ -0,0 +1,7 @@ +config: + main: + env: + - name: ENV_1 + value: '1' + - name: ENV_2 + value: '2' diff --git a/test/grammar/attr_operator/config_inside/insert/dict_3/main.k b/test/grammar/attr_operator/config_inside/insert/dict_3/main.k new file mode 100644 index 000000000..c5e4cd98b --- /dev/null +++ b/test/grammar/attr_operator/config_inside/insert/dict_3/main.k @@ -0,0 +1,12 @@ +config = { + main: { + env: [ + {name: "ENV_1", value: "1"} + ] + } + main: { + env += [ + {name: "ENV_2", value: "2"} + ] + } +} diff --git a/test/grammar/attr_operator/config_inside/insert/dict_3/stdout.golden b/test/grammar/attr_operator/config_inside/insert/dict_3/stdout.golden new file mode 100644 index 000000000..853930d54 --- /dev/null +++ b/test/grammar/attr_operator/config_inside/insert/dict_3/stdout.golden @@ -0,0 +1,7 @@ +config: + main: + env: + - name: ENV_1 + value: '1' + - name: ENV_2 + value: '2' diff --git a/test/grammar/attr_operator/config_inside/insert/dict_4/main.k b/test/grammar/attr_operator/config_inside/insert/dict_4/main.k new file mode 100644 index 000000000..2e4e44524 --- /dev/null +++ b/test/grammar/attr_operator/config_inside/insert/dict_4/main.k @@ -0,0 +1,7 @@ +config = { + main: {env: [{name: "ENV_1", value: "1"}] + } + main: {env += [ + {name: "ENV_2", value: "2"}] + } +} diff --git a/test/grammar/attr_operator/config_inside/insert/dict_4/stdout.golden b/test/grammar/attr_operator/config_inside/insert/dict_4/stdout.golden new file mode 100644 index 000000000..853930d54 --- /dev/null +++ b/test/grammar/attr_operator/config_inside/insert/dict_4/stdout.golden @@ -0,0 +1,7 @@ +config: + main: + env: + - name: ENV_1 + value: '1' + - name: ENV_2 + value: '2' diff --git a/test/grammar/attr_operator/config_inside/insert/dict_5/main.k b/test/grammar/attr_operator/config_inside/insert/dict_5/main.k new file mode 100644 index 000000000..3779732a7 --- /dev/null +++ b/test/grammar/attr_operator/config_inside/insert/dict_5/main.k @@ -0,0 +1,17 @@ +config = { +main: { +env: [ +{ +name: "ENV_1", +value: "1" +} +] +} +main: {env += [ +{ +name: "ENV_2", +value: "2" +} +] +} +} diff --git a/test/grammar/attr_operator/config_inside/insert/dict_5/stdout.golden b/test/grammar/attr_operator/config_inside/insert/dict_5/stdout.golden new file mode 100644 index 000000000..853930d54 --- /dev/null +++ b/test/grammar/attr_operator/config_inside/insert/dict_5/stdout.golden @@ -0,0 +1,7 @@ +config: + main: + env: + - name: ENV_1 + value: '1' + - name: ENV_2 + value: '2' diff --git a/test/grammar/attr_operator/config_inside/insert/dict_6/main.k b/test/grammar/attr_operator/config_inside/insert/dict_6/main.k new file mode 100644 index 000000000..9befa820a --- /dev/null +++ b/test/grammar/attr_operator/config_inside/insert/dict_6/main.k @@ -0,0 +1,5 @@ +config: {str:[int]} = { + a += [0, 1, 2] + a[0] += [4, 5, 6] + a[-1] += [7, 8, 9] +} diff --git a/test/grammar/attr_operator/config_inside/insert/dict_6/stdout.golden b/test/grammar/attr_operator/config_inside/insert/dict_6/stdout.golden new file mode 100644 index 000000000..2e0992740 --- /dev/null +++ b/test/grammar/attr_operator/config_inside/insert/dict_6/stdout.golden @@ -0,0 +1,11 @@ +config: + a: + - 4 + - 5 + - 6 + - 0 + - 1 + - 7 + - 8 + - 9 + - 2 diff --git a/test/grammar/attr_operator/config_inside/insert/dict_fail_0/main.k b/test/grammar/attr_operator/config_inside/insert/dict_fail_0/main.k new file mode 100644 index 000000000..a2c7912f5 --- /dev/null +++ b/test/grammar/attr_operator/config_inside/insert/dict_fail_0/main.k @@ -0,0 +1,4 @@ + +config: {str:[int]} = { + a[b] += [1, 2, 3] +} diff --git a/test/grammar/attr_operator/config_inside/insert/dict_fail_0/stderr.golden b/test/grammar/attr_operator/config_inside/insert/dict_fail_0/stderr.golden new file mode 100644 index 000000000..cf420e1ea --- /dev/null +++ b/test/grammar/attr_operator/config_inside/insert/dict_fail_0/stderr.golden @@ -0,0 +1,6 @@ +error[E2L23]: CompileError + --> ${CWD}/main.k:3:5 + | +3 | a[b] += [1, 2, 3] + | ^ name 'a' is not defined + | \ No newline at end of file diff --git a/test/grammar/attr_operator/config_inside/insert/schema_3/main.k b/test/grammar/attr_operator/config_inside/insert/schema_3/main.k new file mode 100644 index 000000000..4e23781f1 --- /dev/null +++ b/test/grammar/attr_operator/config_inside/insert/schema_3/main.k @@ -0,0 +1,26 @@ +schema Env: + name: str + value: str + +schema Main: + env: [Env] + +schema Config: + main: Main + +_main = Main {env: [ +{name: "ENV_1", value: "1"} + ] +} + +main1 = Main {env: [{name: "ENV_1", value: "1"} + ] +} + +config = Config { + main: _main + main: Main { + env += [ + {name: "ENV_2", value: "2"} + ]} +} \ No newline at end of file diff --git a/test/grammar/attr_operator/config_inside/insert/schema_3/stdout.golden b/test/grammar/attr_operator/config_inside/insert/schema_3/stdout.golden new file mode 100644 index 000000000..439d02e5a --- /dev/null +++ b/test/grammar/attr_operator/config_inside/insert/schema_3/stdout.golden @@ -0,0 +1,11 @@ +main1: + env: + - name: ENV_1 + value: '1' +config: + main: + env: + - name: ENV_1 + value: '1' + - name: ENV_2 + value: '2' \ No newline at end of file diff --git a/test/grammar/attr_operator/if_entry/insert/dict_3/main.k b/test/grammar/attr_operator/if_entry/insert/dict_3/main.k new file mode 100644 index 000000000..4eb44875a --- /dev/null +++ b/test/grammar/attr_operator/if_entry/insert/dict_3/main.k @@ -0,0 +1,17 @@ +schema Main: + env: [{str:str}] + +schema Config: + main: Main + +config = Config { + main: { + env: [ + {name: "ENV_1", value: "1"} + ] + } + main: { + if True: + env += [{name: "ENV_2", value: "2"}] + } +} diff --git a/test/grammar/attr_operator/if_entry/insert/dict_3/stdout.golden b/test/grammar/attr_operator/if_entry/insert/dict_3/stdout.golden new file mode 100644 index 000000000..853930d54 --- /dev/null +++ b/test/grammar/attr_operator/if_entry/insert/dict_3/stdout.golden @@ -0,0 +1,7 @@ +config: + main: + env: + - name: ENV_1 + value: '1' + - name: ENV_2 + value: '2' diff --git a/test/grammar/attr_operator/list_index/insert/insert_0/main.k b/test/grammar/attr_operator/list_index/insert/insert_0/main.k new file mode 100644 index 000000000..4286eb98b --- /dev/null +++ b/test/grammar/attr_operator/list_index/insert/insert_0/main.k @@ -0,0 +1,4 @@ +a = { + arr = [1, 1, 1] + arr[1] += [2] +} diff --git a/test/grammar/attr_operator/list_index/insert/insert_0/stdout.golden b/test/grammar/attr_operator/list_index/insert/insert_0/stdout.golden new file mode 100644 index 000000000..0d261b25f --- /dev/null +++ b/test/grammar/attr_operator/list_index/insert/insert_0/stdout.golden @@ -0,0 +1,6 @@ +a: + arr: + - 1 + - 2 + - 1 + - 1 diff --git a/test/grammar/attr_operator/list_index/insert/insert_1/main.k b/test/grammar/attr_operator/list_index/insert/insert_1/main.k new file mode 100644 index 000000000..8170e44a7 --- /dev/null +++ b/test/grammar/attr_operator/list_index/insert/insert_1/main.k @@ -0,0 +1,4 @@ +a = { + arr = [1, 1, 1] + arr[1] += [2] + [2] +} diff --git a/test/grammar/attr_operator/list_index/insert/insert_1/stdout.golden b/test/grammar/attr_operator/list_index/insert/insert_1/stdout.golden new file mode 100644 index 000000000..19de7b5fe --- /dev/null +++ b/test/grammar/attr_operator/list_index/insert/insert_1/stdout.golden @@ -0,0 +1,7 @@ +a: + arr: + - 1 + - 2 + - 2 + - 1 + - 1 diff --git a/test/grammar/attr_operator/list_index/insert/insert_2/main.k b/test/grammar/attr_operator/list_index/insert/insert_2/main.k new file mode 100644 index 000000000..5edd79cfb --- /dev/null +++ b/test/grammar/attr_operator/list_index/insert/insert_2/main.k @@ -0,0 +1,4 @@ +a = { + arr = [1, 1, 1] + arr[-2] += [0] +} diff --git a/test/grammar/attr_operator/list_index/insert/insert_2/stdout.golden b/test/grammar/attr_operator/list_index/insert/insert_2/stdout.golden new file mode 100644 index 000000000..e20ce8096 --- /dev/null +++ b/test/grammar/attr_operator/list_index/insert/insert_2/stdout.golden @@ -0,0 +1,6 @@ +a: + arr: + - 1 + - 0 + - 1 + - 1 diff --git a/test/grammar/attr_operator/list_index/insert/insert_3/main.k b/test/grammar/attr_operator/list_index/insert/insert_3/main.k new file mode 100644 index 000000000..a87474510 --- /dev/null +++ b/test/grammar/attr_operator/list_index/insert/insert_3/main.k @@ -0,0 +1,3 @@ +a = { + arr[0] += [0] +} diff --git a/test/grammar/attr_operator/list_index/insert/insert_3/stdout.golden b/test/grammar/attr_operator/list_index/insert/insert_3/stdout.golden new file mode 100644 index 000000000..44c7927ba --- /dev/null +++ b/test/grammar/attr_operator/list_index/insert/insert_3/stdout.golden @@ -0,0 +1,3 @@ +a: + arr: + - 0 diff --git a/test/grammar/attr_operator/list_index/insert/insert_fail_0/main.k b/test/grammar/attr_operator/list_index/insert/insert_fail_0/main.k new file mode 100644 index 000000000..3275bbe24 --- /dev/null +++ b/test/grammar/attr_operator/list_index/insert/insert_fail_0/main.k @@ -0,0 +1,4 @@ +a = { + arr = [1, 1, 1] + arr[5] += [2] + [2] +} diff --git a/test/grammar/attr_operator/list_index/insert/insert_fail_0/stderr.golden b/test/grammar/attr_operator/list_index/insert/insert_fail_0/stderr.golden new file mode 100644 index 000000000..30ebe13b4 --- /dev/null +++ b/test/grammar/attr_operator/list_index/insert/insert_fail_0/stderr.golden @@ -0,0 +1 @@ +insertion index (is 5) should be <= len (is 3) \ No newline at end of file diff --git a/test/grammar/attr_operator/list_index/insert/insert_fail_1/main.k b/test/grammar/attr_operator/list_index/insert/insert_fail_1/main.k new file mode 100644 index 000000000..cbaa8af12 --- /dev/null +++ b/test/grammar/attr_operator/list_index/insert/insert_fail_1/main.k @@ -0,0 +1,3 @@ +a = { + arr[1] += [0] +} diff --git a/test/grammar/attr_operator/list_index/insert/insert_fail_1/stderr.golden b/test/grammar/attr_operator/list_index/insert/insert_fail_1/stderr.golden new file mode 100644 index 000000000..4f41fc469 --- /dev/null +++ b/test/grammar/attr_operator/list_index/insert/insert_fail_1/stderr.golden @@ -0,0 +1 @@ +insertion index (is 1) should be <= len (is 0) \ No newline at end of file diff --git a/test/grammar/attr_operator/list_index/insert/insert_fail_2/main.k b/test/grammar/attr_operator/list_index/insert/insert_fail_2/main.k new file mode 100644 index 000000000..1bf5d7420 --- /dev/null +++ b/test/grammar/attr_operator/list_index/insert/insert_fail_2/main.k @@ -0,0 +1,3 @@ +a = { + arr[-1] += [0] +} diff --git a/test/grammar/attr_operator/list_index/insert/insert_fail_2/stderr.golden b/test/grammar/attr_operator/list_index/insert/insert_fail_2/stderr.golden new file mode 100644 index 000000000..07a23d066 --- /dev/null +++ b/test/grammar/attr_operator/list_index/insert/insert_fail_2/stderr.golden @@ -0,0 +1 @@ +index out of bounds \ No newline at end of file diff --git a/test/grammar/attr_operator/list_index/override/override_0/main.k b/test/grammar/attr_operator/list_index/override/override_0/main.k new file mode 100644 index 000000000..5c95b50de --- /dev/null +++ b/test/grammar/attr_operator/list_index/override/override_0/main.k @@ -0,0 +1,4 @@ +a = { + arr = [1, 1, 1] + arr[1] = 2 +} diff --git a/test/grammar/attr_operator/list_index/override/override_0/stdout.golden b/test/grammar/attr_operator/list_index/override/override_0/stdout.golden new file mode 100644 index 000000000..1193c129f --- /dev/null +++ b/test/grammar/attr_operator/list_index/override/override_0/stdout.golden @@ -0,0 +1,5 @@ +a: + arr: + - 1 + - 2 + - 1 diff --git a/test/grammar/attr_operator/list_index/override/override_1/main.k b/test/grammar/attr_operator/list_index/override/override_1/main.k new file mode 100644 index 000000000..ba27ae6c9 --- /dev/null +++ b/test/grammar/attr_operator/list_index/override/override_1/main.k @@ -0,0 +1,4 @@ +a = { + arr = [1, 1, 1] + arr[-2] = 2 +} diff --git a/test/grammar/attr_operator/list_index/override/override_1/stdout.golden b/test/grammar/attr_operator/list_index/override/override_1/stdout.golden new file mode 100644 index 000000000..1193c129f --- /dev/null +++ b/test/grammar/attr_operator/list_index/override/override_1/stdout.golden @@ -0,0 +1,5 @@ +a: + arr: + - 1 + - 2 + - 1 diff --git a/test/grammar/attr_operator/list_index/override/override_fail_0/main.k b/test/grammar/attr_operator/list_index/override/override_fail_0/main.k new file mode 100644 index 000000000..27630d690 --- /dev/null +++ b/test/grammar/attr_operator/list_index/override/override_fail_0/main.k @@ -0,0 +1,4 @@ +a = { + arr = [1, 1, 1] + arr[5] = 2 +} diff --git a/test/grammar/attr_operator/list_index/override/override_fail_0/stderr.golden b/test/grammar/attr_operator/list_index/override/override_fail_0/stderr.golden new file mode 100644 index 000000000..068284a93 --- /dev/null +++ b/test/grammar/attr_operator/list_index/override/override_fail_0/stderr.golden @@ -0,0 +1 @@ +index out of bounds: the len is 3 but the index is 5 \ No newline at end of file diff --git a/test/grammar/attr_operator/list_index/override/override_fail_1/main.k b/test/grammar/attr_operator/list_index/override/override_fail_1/main.k new file mode 100644 index 000000000..c81bf0cea --- /dev/null +++ b/test/grammar/attr_operator/list_index/override/override_fail_1/main.k @@ -0,0 +1,3 @@ +a = { + arr[1] = [0] +} diff --git a/test/grammar/attr_operator/list_index/override/override_fail_1/stderr.golden b/test/grammar/attr_operator/list_index/override/override_fail_1/stderr.golden new file mode 100644 index 000000000..441481ac9 --- /dev/null +++ b/test/grammar/attr_operator/list_index/override/override_fail_1/stderr.golden @@ -0,0 +1 @@ +only list attribute can be override value with the index 1 \ No newline at end of file diff --git a/test/grammar/attr_operator/list_index/override/override_fail_2/main.k b/test/grammar/attr_operator/list_index/override/override_fail_2/main.k new file mode 100644 index 000000000..c1bf38eea --- /dev/null +++ b/test/grammar/attr_operator/list_index/override/override_fail_2/main.k @@ -0,0 +1,4 @@ +b = { + arr = [{name = "One"}, {name="asdad"}] + arr[5] = {name = "Two"} +} \ No newline at end of file diff --git a/test/grammar/attr_operator/list_index/override/override_fail_2/stderr.golden b/test/grammar/attr_operator/list_index/override/override_fail_2/stderr.golden new file mode 100644 index 000000000..bbd37dd15 --- /dev/null +++ b/test/grammar/attr_operator/list_index/override/override_fail_2/stderr.golden @@ -0,0 +1 @@ +index out of bounds: the len is 2 but the index is 5 \ No newline at end of file diff --git a/test/grammar/attr_operator/list_index/unification/unification_0/main.k b/test/grammar/attr_operator/list_index/unification/unification_0/main.k new file mode 100644 index 000000000..806bc153b --- /dev/null +++ b/test/grammar/attr_operator/list_index/unification/unification_0/main.k @@ -0,0 +1,4 @@ +a = { + config = [{name = "One"}, {name = "asdad"}] + config[0]: {name = "Two"} +} \ No newline at end of file diff --git a/test/grammar/attr_operator/list_index/unification/unification_0/stdout.golden b/test/grammar/attr_operator/list_index/unification/unification_0/stdout.golden new file mode 100644 index 000000000..6851678eb --- /dev/null +++ b/test/grammar/attr_operator/list_index/unification/unification_0/stdout.golden @@ -0,0 +1,4 @@ +a: + config: + - name: Two + - name: asdad diff --git a/test/grammar/attr_operator/list_index/unification/unification_1/main.k b/test/grammar/attr_operator/list_index/unification/unification_1/main.k new file mode 100644 index 000000000..73a01b8a9 --- /dev/null +++ b/test/grammar/attr_operator/list_index/unification/unification_1/main.k @@ -0,0 +1,4 @@ +a = { + config = [{name = "One"}, {name = "asdad"}] + config[0]: {key = "value"} +} \ No newline at end of file diff --git a/test/grammar/attr_operator/list_index/unification/unification_1/stdout.golden b/test/grammar/attr_operator/list_index/unification/unification_1/stdout.golden new file mode 100644 index 000000000..5438366e4 --- /dev/null +++ b/test/grammar/attr_operator/list_index/unification/unification_1/stdout.golden @@ -0,0 +1,5 @@ +a: + config: + - name: One + key: value + - name: asdad diff --git a/test/grammar/attr_operator/list_index/unification/unification_fail_0/main.k b/test/grammar/attr_operator/list_index/unification/unification_fail_0/main.k new file mode 100644 index 000000000..5eb61d039 --- /dev/null +++ b/test/grammar/attr_operator/list_index/unification/unification_fail_0/main.k @@ -0,0 +1,4 @@ +a = { + config = [{name = "One"}, {name = "asdad"}] + config[0]: {name: "value"} +} \ No newline at end of file diff --git a/test/grammar/attr_operator/list_index/unification/unification_fail_0/stderr.golden b/test/grammar/attr_operator/list_index/unification/unification_fail_0/stderr.golden new file mode 100644 index 000000000..06f9922dc --- /dev/null +++ b/test/grammar/attr_operator/list_index/unification/unification_fail_0/stderr.golden @@ -0,0 +1 @@ +conflicting values on the attribute 'name' \ No newline at end of file diff --git a/test/grammar/attr_operator/schema_inside/unification/test_4/main.k b/test/grammar/attr_operator/schema_inside/unification/test_4/main.k index c43b42c8a..43705b5cd 100644 --- a/test/grammar/attr_operator/schema_inside/unification/test_4/main.k +++ b/test/grammar/attr_operator/schema_inside/unification/test_4/main.k @@ -2,7 +2,7 @@ schema Config: [str]: str _c = Config {} -_c |= { +_c: Config { key = "value" } c = _c diff --git a/test/grammar/builtins/crypto/blake/blake3/main.k b/test/grammar/builtins/crypto/blake/blake3/main.k new file mode 100644 index 000000000..e8397fe26 --- /dev/null +++ b/test/grammar/builtins/crypto/blake/blake3/main.k @@ -0,0 +1,3 @@ +import crypto + +blake3 = crypto.blake3("ABCDEF") diff --git a/test/grammar/builtins/crypto/blake/blake3/stdout.golden b/test/grammar/builtins/crypto/blake/blake3/stdout.golden new file mode 100644 index 000000000..59ce547c5 --- /dev/null +++ b/test/grammar/builtins/crypto/blake/blake3/stdout.golden @@ -0,0 +1 @@ +blake3: 61c8c05f3e588c663cd9fbb1d7ad93604ed08cf335497095a020222cc9976cf1 \ No newline at end of file diff --git a/test/grammar/builtins/crypto/sha/filesha256/main.k b/test/grammar/builtins/crypto/sha/filesha256/main.k new file mode 100644 index 000000000..f290fda22 --- /dev/null +++ b/test/grammar/builtins/crypto/sha/filesha256/main.k @@ -0,0 +1,3 @@ +import crypto + +sha = crypto.filesha256("test.txt") diff --git a/test/grammar/builtins/crypto/sha/filesha256/stdout.golden b/test/grammar/builtins/crypto/sha/filesha256/stdout.golden new file mode 100644 index 000000000..98bd79450 --- /dev/null +++ b/test/grammar/builtins/crypto/sha/filesha256/stdout.golden @@ -0,0 +1 @@ +sha: e9c0f8b575cbfcb42ab3b78ecc87efa3b011d9a5d10b09fa4e96f240bf6a82f5 \ No newline at end of file diff --git a/test/grammar/builtins/crypto/sha/filesha256/test.txt b/test/grammar/builtins/crypto/sha/filesha256/test.txt new file mode 100644 index 000000000..1c5f8ba2d --- /dev/null +++ b/test/grammar/builtins/crypto/sha/filesha256/test.txt @@ -0,0 +1 @@ +ABCDEF \ No newline at end of file diff --git a/test/grammar/builtins/datetime/date/main.k b/test/grammar/builtins/datetime/date/main.k new file mode 100644 index 000000000..633b523f6 --- /dev/null +++ b/test/grammar/builtins/datetime/date/main.k @@ -0,0 +1,3 @@ +import datetime + +result: bool = datetime.validate(datetime.date(), "%Y-%m-%d %H:%M:%S") diff --git a/test/grammar/builtins/datetime/date/stdout.golden b/test/grammar/builtins/datetime/date/stdout.golden new file mode 100644 index 000000000..fce304b9d --- /dev/null +++ b/test/grammar/builtins/datetime/date/stdout.golden @@ -0,0 +1 @@ +result: true diff --git a/test/grammar/builtins/datetime/now/main.k b/test/grammar/builtins/datetime/now/main.k new file mode 100644 index 000000000..765d90e70 --- /dev/null +++ b/test/grammar/builtins/datetime/now/main.k @@ -0,0 +1,5 @@ +import datetime + +format = "%H:%M:%S" +result1: bool = datetime.validate(datetime.now(), "%a %b %d %H:%M:%S %Y") +result2: bool = datetime.validate(datetime.now(format), format) diff --git a/test/grammar/builtins/datetime/now/stdout.golden b/test/grammar/builtins/datetime/now/stdout.golden new file mode 100644 index 000000000..c7ae02587 --- /dev/null +++ b/test/grammar/builtins/datetime/now/stdout.golden @@ -0,0 +1,3 @@ +format: '%H:%M:%S' +result1: true +result2: true diff --git a/test/grammar/builtins/datetime/ticks/main.k b/test/grammar/builtins/datetime/ticks/main.k new file mode 100644 index 000000000..31b4c7aa9 --- /dev/null +++ b/test/grammar/builtins/datetime/ticks/main.k @@ -0,0 +1,3 @@ +import datetime + +result = str(datetime.ticks()).startswith("1") diff --git a/test/grammar/builtins/datetime/ticks/stdout.golden b/test/grammar/builtins/datetime/ticks/stdout.golden new file mode 100644 index 000000000..fce304b9d --- /dev/null +++ b/test/grammar/builtins/datetime/ticks/stdout.golden @@ -0,0 +1 @@ +result: true diff --git a/test/grammar/builtins/datetime/today/main.k b/test/grammar/builtins/datetime/today/main.k new file mode 100644 index 000000000..b7e769751 --- /dev/null +++ b/test/grammar/builtins/datetime/today/main.k @@ -0,0 +1,5 @@ +import datetime + +_t = datetime.today().split(".") +assert len(_t) == 2 +result: bool = datetime.validate(_t[0], "%Y-%m-%d %H:%M:%S") diff --git a/test/grammar/builtins/datetime/today/stdout.golden b/test/grammar/builtins/datetime/today/stdout.golden new file mode 100644 index 000000000..fce304b9d --- /dev/null +++ b/test/grammar/builtins/datetime/today/stdout.golden @@ -0,0 +1 @@ +result: true diff --git a/test/grammar/builtins/datetime/validate/main.k b/test/grammar/builtins/datetime/validate/main.k new file mode 100644 index 000000000..6d4ec12d7 --- /dev/null +++ b/test/grammar/builtins/datetime/validate/main.k @@ -0,0 +1,19 @@ +import datetime + +assert datetime.validate("2024-08-26", "%Y-%m-%d") # Valid date +assert datetime.validate("1998-06-06", "%Y-%m-%d") # Valid date +assert datetime.validate("2023-12-31", "%Y-%m-%d") # Valid date +assert datetime.validate("2000-01-01", "%Y-%m-%d") # Valid date + +assert not datetime.validate("2024-13-26", "%Y-%m-%d") # Invalid month +assert not datetime.validate("2024-06-32", "%Y-%m-%d") # Invalid day +assert not datetime.validate("2024-08-26abc", "%Y-%m-%d") # Additional characters +assert not datetime.validate("not-a-date", "%Y-%m-%d") # Non-date string +assert not datetime.validate("2024-08", "%Y-%m-%d") # Missing day +assert not datetime.validate("08-26", "%Y-%m-%d") # Missing year +assert not datetime.validate("2024-08-26 10:00", "%Y-%m-%d") # Extra components +assert datetime.validate("2024-01-01", "%Y-%m-%d") # Starting year of the new year +assert datetime.validate("2024-02-29", "%Y-%m-%d") # Valid leap year date +assert not datetime.validate("2023-02-29", "%Y-%m-%d") # Invalid leap year date + +result: bool = datetime.validate("2000-01-01", "%Y-%m-%d") # Valid date diff --git a/test/grammar/builtins/datetime/validate/stdout.golden b/test/grammar/builtins/datetime/validate/stdout.golden new file mode 100644 index 000000000..fce304b9d --- /dev/null +++ b/test/grammar/builtins/datetime/validate/stdout.golden @@ -0,0 +1 @@ +result: true diff --git a/test/grammar/builtins/default/bin/stdout.golden b/test/grammar/builtins/default/bin/stdout.golden index b76ff25c8..d95ec88af 100644 --- a/test/grammar/builtins/default/bin/stdout.golden +++ b/test/grammar/builtins/default/bin/stdout.golden @@ -1,2 +1,2 @@ a: '0b1010' -b: '0b10100' \ No newline at end of file +b: '0b10100' diff --git a/test/grammar/builtins/default/isnullable/main.k b/test/grammar/builtins/default/isnullable/main.k new file mode 100644 index 000000000..c003b692d --- /dev/null +++ b/test/grammar/builtins/default/isnullable/main.k @@ -0,0 +1,14 @@ +a = [100, 10, 100] +b = [100, 10] +c = ["Hello", "world", "world"] +d = ["Hello", "world"] +e = None +f = Undefined +g = [None] +A = isnullish(a) +B = isnullish(b) +C = isnullish(c) +D = isnullish(d) +E = isnullish(e) +F = isnullish(f) +G = isnullish(g) diff --git a/test/grammar/builtins/default/isnullable/stdout.golden b/test/grammar/builtins/default/isnullable/stdout.golden new file mode 100644 index 000000000..65f0b1fc8 --- /dev/null +++ b/test/grammar/builtins/default/isnullable/stdout.golden @@ -0,0 +1,24 @@ +a: +- 100 +- 10 +- 100 +b: +- 100 +- 10 +c: +- Hello +- world +- world +d: +- Hello +- world +e: null +g: +- null +A: false +B: false +C: false +D: false +E: true +F: true +G: false diff --git a/test/grammar/builtins/file/cp/main.k b/test/grammar/builtins/file/cp/main.k new file mode 100644 index 000000000..acdacd16f --- /dev/null +++ b/test/grammar/builtins/file/cp/main.k @@ -0,0 +1,3 @@ +import file + +file.cp("source.txt", "destination.txt") diff --git a/test/grammar/builtins/file/cp/stderr.golden b/test/grammar/builtins/file/cp/stderr.golden new file mode 100644 index 000000000..01fc01b20 --- /dev/null +++ b/test/grammar/builtins/file/cp/stderr.golden @@ -0,0 +1,6 @@ +error[E3M38]: EvaluationError + --> ${CWD}/main.k:3:1 + | +3 | file.cp("source.txt", "destination.txt") + | Failed to copy from 'source.txt' to 'destination.txt': No such file or directory (os error 2) + | \ No newline at end of file diff --git a/test/grammar/builtins/file/current/main.k b/test/grammar/builtins/file/current/main.k new file mode 100644 index 000000000..cf804e61c --- /dev/null +++ b/test/grammar/builtins/file/current/main.k @@ -0,0 +1,3 @@ +import file + +a = file.current().endswith("main.k") diff --git a/test/grammar/builtins/file/current/stdout.golden b/test/grammar/builtins/file/current/stdout.golden new file mode 100644 index 000000000..b4563830e --- /dev/null +++ b/test/grammar/builtins/file/current/stdout.golden @@ -0,0 +1 @@ +a: true \ No newline at end of file diff --git a/test/grammar/builtins/file/delete/main.k b/test/grammar/builtins/file/delete/main.k new file mode 100644 index 000000000..92a78886b --- /dev/null +++ b/test/grammar/builtins/file/delete/main.k @@ -0,0 +1,6 @@ +import file + +file.delete("test_dir") + + + diff --git a/test/grammar/builtins/file/delete/stderr.golden b/test/grammar/builtins/file/delete/stderr.golden new file mode 100644 index 000000000..4e4f3d86b --- /dev/null +++ b/test/grammar/builtins/file/delete/stderr.golden @@ -0,0 +1,6 @@ +error[E3M38]: EvaluationError + --> ${CWD}/main.k:3:1 + | +3 | file.delete("test_dir") + | failed to delete 'test_dir': No such file or directory (os error 2) + | \ No newline at end of file diff --git a/test/grammar/builtins/file/exists/a.k b/test/grammar/builtins/file/exists/a.k new file mode 100644 index 000000000..d25d49e0f --- /dev/null +++ b/test/grammar/builtins/file/exists/a.k @@ -0,0 +1 @@ +a = 1 \ No newline at end of file diff --git a/test/grammar/builtins/file/exists/main.k b/test/grammar/builtins/file/exists/main.k new file mode 100644 index 000000000..a2d4fa8a0 --- /dev/null +++ b/test/grammar/builtins/file/exists/main.k @@ -0,0 +1,4 @@ +import file + +exists_result_0 = file.exists("a.k") +exists_result_1 = file.exists("b.k") diff --git a/test/grammar/builtins/file/exists/stdout.golden b/test/grammar/builtins/file/exists/stdout.golden new file mode 100644 index 000000000..5ae29c02a --- /dev/null +++ b/test/grammar/builtins/file/exists/stdout.golden @@ -0,0 +1,2 @@ +exists_result_0: true +exists_result_1: false diff --git a/test/grammar/builtins/file/glob/main.k b/test/grammar/builtins/file/glob/main.k new file mode 100644 index 000000000..b1605476c --- /dev/null +++ b/test/grammar/builtins/file/glob/main.k @@ -0,0 +1,3 @@ +import file + +contents = [ file.read(_x) for _x in file.glob("./*.json")] diff --git a/test/grammar/builtins/file/glob/stdout.golden b/test/grammar/builtins/file/glob/stdout.golden new file mode 100644 index 000000000..693ad5008 --- /dev/null +++ b/test/grammar/builtins/file/glob/stdout.golden @@ -0,0 +1,19 @@ +contents: +- |- + { + "key1": "value1", + "key2": "value2", + "data": [1, 2, 3] + } +- |- + { + "key1": "value3", + "key2": "value4", + "data": [4, 5, 6] + } +- |- + { + "key1": "value5", + "key2": "value6", + "data": [7, 8, 9] + } \ No newline at end of file diff --git a/test/grammar/builtins/file/glob/test1.json b/test/grammar/builtins/file/glob/test1.json new file mode 100644 index 000000000..e8772183f --- /dev/null +++ b/test/grammar/builtins/file/glob/test1.json @@ -0,0 +1,5 @@ +{ + "key1": "value1", + "key2": "value2", + "data": [1, 2, 3] +} \ No newline at end of file diff --git a/test/grammar/builtins/file/glob/test2.json b/test/grammar/builtins/file/glob/test2.json new file mode 100644 index 000000000..fc96ddad8 --- /dev/null +++ b/test/grammar/builtins/file/glob/test2.json @@ -0,0 +1,5 @@ +{ + "key1": "value3", + "key2": "value4", + "data": [4, 5, 6] +} \ No newline at end of file diff --git a/test/grammar/builtins/file/glob/test3.json b/test/grammar/builtins/file/glob/test3.json new file mode 100644 index 000000000..e2d404d66 --- /dev/null +++ b/test/grammar/builtins/file/glob/test3.json @@ -0,0 +1,5 @@ +{ + "key1": "value5", + "key2": "value6", + "data": [7, 8, 9] +} \ No newline at end of file diff --git a/test/grammar/builtins/file/load_file_invalid/main.k b/test/grammar/builtins/file/load_file_invalid/main.k new file mode 100644 index 000000000..a9238ff6d --- /dev/null +++ b/test/grammar/builtins/file/load_file_invalid/main.k @@ -0,0 +1,3 @@ +import file + +a = file.read("not_exist.txt") \ No newline at end of file diff --git a/test/grammar/builtins/file/load_file_invalid/stderr.golden b/test/grammar/builtins/file/load_file_invalid/stderr.golden new file mode 100644 index 000000000..f761cd111 --- /dev/null +++ b/test/grammar/builtins/file/load_file_invalid/stderr.golden @@ -0,0 +1 @@ +failed to access the file 'not_exist.txt': No such file or directory \ No newline at end of file diff --git a/test/grammar/builtins/file/load_json/main.k b/test/grammar/builtins/file/load_json/main.k new file mode 100644 index 000000000..1bda19025 --- /dev/null +++ b/test/grammar/builtins/file/load_json/main.k @@ -0,0 +1,8 @@ +import json +import file + +data_string = json.decode(file.read("test.json")) + +key1 = data_string.key1 +key2 = data_string.key2 +data = data_string.data \ No newline at end of file diff --git a/test/grammar/builtins/file/load_json/stdout.golden b/test/grammar/builtins/file/load_json/stdout.golden new file mode 100644 index 000000000..3c268cc99 --- /dev/null +++ b/test/grammar/builtins/file/load_json/stdout.golden @@ -0,0 +1,13 @@ +data_string: + key1: value1 + key2: value2 + data: + - 1 + - 2 + - 3 +key1: value1 +key2: value2 +data: +- 1 +- 2 +- 3 diff --git a/test/grammar/builtins/file/load_json/test.json b/test/grammar/builtins/file/load_json/test.json new file mode 100644 index 000000000..e8772183f --- /dev/null +++ b/test/grammar/builtins/file/load_json/test.json @@ -0,0 +1,5 @@ +{ + "key1": "value1", + "key2": "value2", + "data": [1, 2, 3] +} \ No newline at end of file diff --git a/test/grammar/builtins/file/load_txt/main.k b/test/grammar/builtins/file/load_txt/main.k new file mode 100644 index 000000000..741febc4f --- /dev/null +++ b/test/grammar/builtins/file/load_txt/main.k @@ -0,0 +1,3 @@ +import file + +a = file.read("test.txt") \ No newline at end of file diff --git a/test/grammar/builtins/file/load_txt/stdout.golden b/test/grammar/builtins/file/load_txt/stdout.golden new file mode 100644 index 000000000..623ab06c1 --- /dev/null +++ b/test/grammar/builtins/file/load_txt/stdout.golden @@ -0,0 +1 @@ +a: Helloworld \ No newline at end of file diff --git a/test/grammar/builtins/file/load_txt/test.txt b/test/grammar/builtins/file/load_txt/test.txt new file mode 100644 index 000000000..0cf453276 --- /dev/null +++ b/test/grammar/builtins/file/load_txt/test.txt @@ -0,0 +1 @@ +Helloworld \ No newline at end of file diff --git a/test/grammar/builtins/file/load_yaml/main.k b/test/grammar/builtins/file/load_yaml/main.k new file mode 100644 index 000000000..01a780149 --- /dev/null +++ b/test/grammar/builtins/file/load_yaml/main.k @@ -0,0 +1,8 @@ +import yaml +import file + +data_string = yaml.decode(file.read("test.yaml")) + +key1 = data_string.key1 +key2 = data_string.key2 +data = data_string.data \ No newline at end of file diff --git a/test/grammar/builtins/file/load_yaml/stdout.golden b/test/grammar/builtins/file/load_yaml/stdout.golden new file mode 100644 index 000000000..3c268cc99 --- /dev/null +++ b/test/grammar/builtins/file/load_yaml/stdout.golden @@ -0,0 +1,13 @@ +data_string: + key1: value1 + key2: value2 + data: + - 1 + - 2 + - 3 +key1: value1 +key2: value2 +data: +- 1 +- 2 +- 3 diff --git a/test/grammar/builtins/file/load_yaml/test.yaml b/test/grammar/builtins/file/load_yaml/test.yaml new file mode 100644 index 000000000..0ffe95c1b --- /dev/null +++ b/test/grammar/builtins/file/load_yaml/test.yaml @@ -0,0 +1,3 @@ +key1: "value1" +key2: "value2" +data: [1, 2, 3] diff --git a/test/grammar/builtins/file/mkdir/main.k b/test/grammar/builtins/file/mkdir/main.k new file mode 100644 index 000000000..bd3697910 --- /dev/null +++ b/test/grammar/builtins/file/mkdir/main.k @@ -0,0 +1,4 @@ +import file + +file.mkdir("test_dir") +a = 1 \ No newline at end of file diff --git a/test/grammar/builtins/file/mkdir/stdout.golden b/test/grammar/builtins/file/mkdir/stdout.golden new file mode 100644 index 000000000..a016ac454 --- /dev/null +++ b/test/grammar/builtins/file/mkdir/stdout.golden @@ -0,0 +1 @@ +a: 1 \ No newline at end of file diff --git a/test/grammar/builtins/file/mod_root/main.k b/test/grammar/builtins/file/mod_root/main.k new file mode 100644 index 000000000..3fde22987 --- /dev/null +++ b/test/grammar/builtins/file/mod_root/main.k @@ -0,0 +1,8 @@ +import file +import json + +data_string = json.decode(file.read(file.modpath()+"/test.json")) + +key1 = data_string.key1 +key2 = data_string.key2 +data = data_string.data \ No newline at end of file diff --git a/test/grammar/builtins/file/mod_root/stdout.golden b/test/grammar/builtins/file/mod_root/stdout.golden new file mode 100644 index 000000000..3c268cc99 --- /dev/null +++ b/test/grammar/builtins/file/mod_root/stdout.golden @@ -0,0 +1,13 @@ +data_string: + key1: value1 + key2: value2 + data: + - 1 + - 2 + - 3 +key1: value1 +key2: value2 +data: +- 1 +- 2 +- 3 diff --git a/test/grammar/builtins/file/mod_root/test.json b/test/grammar/builtins/file/mod_root/test.json new file mode 100644 index 000000000..e8772183f --- /dev/null +++ b/test/grammar/builtins/file/mod_root/test.json @@ -0,0 +1,5 @@ +{ + "key1": "value1", + "key2": "value2", + "data": [1, 2, 3] +} \ No newline at end of file diff --git a/test/grammar/builtins/file/mod_root_sub/kcl.mod b/test/grammar/builtins/file/mod_root_sub/kcl.mod new file mode 100644 index 000000000..e70c1ec74 --- /dev/null +++ b/test/grammar/builtins/file/mod_root_sub/kcl.mod @@ -0,0 +1,5 @@ +[package] +name = "workdir_sub" +edition = "0.0.1" +version = "0.0.1" + diff --git a/test/grammar/builtins/file/mod_root_sub/stdout.golden b/test/grammar/builtins/file/mod_root_sub/stdout.golden new file mode 100644 index 000000000..3c268cc99 --- /dev/null +++ b/test/grammar/builtins/file/mod_root_sub/stdout.golden @@ -0,0 +1,13 @@ +data_string: + key1: value1 + key2: value2 + data: + - 1 + - 2 + - 3 +key1: value1 +key2: value2 +data: +- 1 +- 2 +- 3 diff --git a/test/grammar/builtins/file/mod_root_sub/sub/main.k b/test/grammar/builtins/file/mod_root_sub/sub/main.k new file mode 100644 index 000000000..3fde22987 --- /dev/null +++ b/test/grammar/builtins/file/mod_root_sub/sub/main.k @@ -0,0 +1,8 @@ +import file +import json + +data_string = json.decode(file.read(file.modpath()+"/test.json")) + +key1 = data_string.key1 +key2 = data_string.key2 +data = data_string.data \ No newline at end of file diff --git a/test/grammar/builtins/file/mod_root_sub/test.json b/test/grammar/builtins/file/mod_root_sub/test.json new file mode 100644 index 000000000..e8772183f --- /dev/null +++ b/test/grammar/builtins/file/mod_root_sub/test.json @@ -0,0 +1,5 @@ +{ + "key1": "value1", + "key2": "value2", + "data": [1, 2, 3] +} \ No newline at end of file diff --git a/test/grammar/builtins/file/mv/main.k b/test/grammar/builtins/file/mv/main.k new file mode 100644 index 000000000..dd8bdb36d --- /dev/null +++ b/test/grammar/builtins/file/mv/main.k @@ -0,0 +1,3 @@ +import file + +file.mv("source.txt", "destination.txt") diff --git a/test/grammar/builtins/file/mv/stderr.golden b/test/grammar/builtins/file/mv/stderr.golden new file mode 100644 index 000000000..e0e8ca746 --- /dev/null +++ b/test/grammar/builtins/file/mv/stderr.golden @@ -0,0 +1,6 @@ +error[E3M38]: EvaluationError + --> ${CWD}/main.k:3:1 + | +3 | file.mv("source.txt", "destination.txt") + | Failed to move 'source.txt' to 'destination.txt': No such file or directory (os error 2) + | \ No newline at end of file diff --git a/test/grammar/builtins/file/size/main.k b/test/grammar/builtins/file/size/main.k new file mode 100644 index 000000000..92d2adb15 --- /dev/null +++ b/test/grammar/builtins/file/size/main.k @@ -0,0 +1,4 @@ +import file + +file.size("source_file.txt") +file.size("test_file.txt") diff --git a/test/grammar/builtins/file/size/stderr.golden b/test/grammar/builtins/file/size/stderr.golden new file mode 100644 index 000000000..9017b13a6 --- /dev/null +++ b/test/grammar/builtins/file/size/stderr.golden @@ -0,0 +1,6 @@ +error[E3M38]: EvaluationError + --> ${CWD}/main.k:3:1 + | +3 | file.size("source_file.txt") + | failed to get size of 'source_file.txt': No such file or directory (os error 2) + | \ No newline at end of file diff --git a/test/grammar/builtins/file/size/test_file.txt b/test/grammar/builtins/file/size/test_file.txt new file mode 100644 index 000000000..05303ef85 --- /dev/null +++ b/test/grammar/builtins/file/size/test_file.txt @@ -0,0 +1 @@ +This is a sample file. diff --git a/test/grammar/builtins/file/workdir/main.k b/test/grammar/builtins/file/workdir/main.k new file mode 100644 index 000000000..cec24de81 --- /dev/null +++ b/test/grammar/builtins/file/workdir/main.k @@ -0,0 +1,3 @@ +import file + +workdir = file.workdir() diff --git a/test/grammar/builtins/file/workdir/stdout.golden b/test/grammar/builtins/file/workdir/stdout.golden new file mode 100644 index 000000000..a6ec37904 --- /dev/null +++ b/test/grammar/builtins/file/workdir/stdout.golden @@ -0,0 +1 @@ +workdir: '' diff --git a/test/grammar/builtins/file/workdir_sub/kcl.mod b/test/grammar/builtins/file/workdir_sub/kcl.mod new file mode 100644 index 000000000..e70c1ec74 --- /dev/null +++ b/test/grammar/builtins/file/workdir_sub/kcl.mod @@ -0,0 +1,5 @@ +[package] +name = "workdir_sub" +edition = "0.0.1" +version = "0.0.1" + diff --git a/test/grammar/builtins/file/workdir_sub/stdout.golden b/test/grammar/builtins/file/workdir_sub/stdout.golden new file mode 100644 index 000000000..a0a5fd960 --- /dev/null +++ b/test/grammar/builtins/file/workdir_sub/stdout.golden @@ -0,0 +1,14 @@ +data_string: + key1: value1 + key2: value2 + data: + - 1 + - 2 + - 3 +key1: value1 +key2: value2 +data: +- 1 +- 2 +- 3 +workdir: '' diff --git a/test/grammar/builtins/file/workdir_sub/sub/main.k b/test/grammar/builtins/file/workdir_sub/sub/main.k new file mode 100644 index 000000000..b4042e915 --- /dev/null +++ b/test/grammar/builtins/file/workdir_sub/sub/main.k @@ -0,0 +1,10 @@ +import file +import json + +data_string = json.decode(file.read(file.modpath()+"/test.json")) + +key1 = data_string.key1 +key2 = data_string.key2 +data = data_string.data + +workdir = file.workdir() \ No newline at end of file diff --git a/test/grammar/builtins/file/workdir_sub/test.json b/test/grammar/builtins/file/workdir_sub/test.json new file mode 100644 index 000000000..e8772183f --- /dev/null +++ b/test/grammar/builtins/file/workdir_sub/test.json @@ -0,0 +1,5 @@ +{ + "key1": "value1", + "key2": "value2", + "data": [1, 2, 3] +} \ No newline at end of file diff --git a/test/grammar/builtins/file/write/main.k b/test/grammar/builtins/file/write/main.k new file mode 100644 index 000000000..c33358214 --- /dev/null +++ b/test/grammar/builtins/file/write/main.k @@ -0,0 +1,4 @@ +import file + +file.write("test_file.txt", "Hello, world!") +a = 1 \ No newline at end of file diff --git a/test/grammar/builtins/file/write/stdout.golden b/test/grammar/builtins/file/write/stdout.golden new file mode 100644 index 000000000..a016ac454 --- /dev/null +++ b/test/grammar/builtins/file/write/stdout.golden @@ -0,0 +1 @@ +a: 1 \ No newline at end of file diff --git a/test/grammar/builtins/file/write/test_file.txt b/test/grammar/builtins/file/write/test_file.txt new file mode 100644 index 000000000..5dd01c177 --- /dev/null +++ b/test/grammar/builtins/file/write/test_file.txt @@ -0,0 +1 @@ +Hello, world! \ No newline at end of file diff --git a/test/grammar/builtins/json/dump_to_file_0/0.json b/test/grammar/builtins/json/dump_to_file_0/0.json new file mode 100644 index 000000000..6743ea768 --- /dev/null +++ b/test/grammar/builtins/json/dump_to_file_0/0.json @@ -0,0 +1 @@ +"key: value" \ No newline at end of file diff --git a/test/grammar/builtins/json/dump_to_file_0/1.json b/test/grammar/builtins/json/dump_to_file_0/1.json new file mode 100644 index 000000000..8350d35db --- /dev/null +++ b/test/grammar/builtins/json/dump_to_file_0/1.json @@ -0,0 +1 @@ +"- 1\n- 2\n- 3" \ No newline at end of file diff --git a/test/grammar/builtins/json/dump_to_file_0/2.json b/test/grammar/builtins/json/dump_to_file_0/2.json new file mode 100644 index 000000000..2d81c1ae7 --- /dev/null +++ b/test/grammar/builtins/json/dump_to_file_0/2.json @@ -0,0 +1 @@ +"1" \ No newline at end of file diff --git a/test/grammar/builtins/json/dump_to_file_0/3.json b/test/grammar/builtins/json/dump_to_file_0/3.json new file mode 100644 index 000000000..f47281b17 --- /dev/null +++ b/test/grammar/builtins/json/dump_to_file_0/3.json @@ -0,0 +1 @@ +"1.1" \ No newline at end of file diff --git a/test/grammar/builtins/json/dump_to_file_0/4.json b/test/grammar/builtins/json/dump_to_file_0/4.json new file mode 100644 index 000000000..80541ce68 --- /dev/null +++ b/test/grammar/builtins/json/dump_to_file_0/4.json @@ -0,0 +1 @@ +"null" \ No newline at end of file diff --git a/test/grammar/builtins/json/dump_to_file_0/5.json b/test/grammar/builtins/json/dump_to_file_0/5.json new file mode 100644 index 000000000..e942432aa --- /dev/null +++ b/test/grammar/builtins/json/dump_to_file_0/5.json @@ -0,0 +1 @@ +"true" \ No newline at end of file diff --git a/test/grammar/builtins/json/dump_to_file_0/main.k b/test/grammar/builtins/json/dump_to_file_0/main.k new file mode 100644 index 000000000..d7f9dfd1d --- /dev/null +++ b/test/grammar/builtins/json/dump_to_file_0/main.k @@ -0,0 +1,11 @@ +import json + +jsonStrList = [ + 'key: value', + '- 1\n- 2\n- 3', + '1', + '1.1', + 'null', + 'true', +] +_ = [json.dump_to_file(s, "${i}.json") for i, s in jsonStrList] diff --git a/test/grammar/builtins/json/dump_to_file_0/stdout.golden b/test/grammar/builtins/json/dump_to_file_0/stdout.golden new file mode 100644 index 000000000..ea6509147 --- /dev/null +++ b/test/grammar/builtins/json/dump_to_file_0/stdout.golden @@ -0,0 +1,10 @@ +jsonStrList: +- 'key: value' +- |- + - 1 + - 2 + - 3 +- '1' +- '1.1' +- 'null' +- 'true' diff --git a/test/grammar/builtins/json/dump_to_file_1/0.yaml b/test/grammar/builtins/json/dump_to_file_1/0.yaml new file mode 100644 index 000000000..8593e686f --- /dev/null +++ b/test/grammar/builtins/json/dump_to_file_1/0.yaml @@ -0,0 +1 @@ +'key: value' diff --git a/test/grammar/builtins/json/dump_to_file_1/1.yaml b/test/grammar/builtins/json/dump_to_file_1/1.yaml new file mode 100644 index 000000000..726ba9b9d --- /dev/null +++ b/test/grammar/builtins/json/dump_to_file_1/1.yaml @@ -0,0 +1,4 @@ +|- + - 1 + - 2 + - 3 diff --git a/test/grammar/builtins/json/dump_to_file_1/2.yaml b/test/grammar/builtins/json/dump_to_file_1/2.yaml new file mode 100644 index 000000000..cb382054c --- /dev/null +++ b/test/grammar/builtins/json/dump_to_file_1/2.yaml @@ -0,0 +1 @@ +'1' diff --git a/test/grammar/builtins/json/dump_to_file_1/3.yaml b/test/grammar/builtins/json/dump_to_file_1/3.yaml new file mode 100644 index 000000000..95c82787d --- /dev/null +++ b/test/grammar/builtins/json/dump_to_file_1/3.yaml @@ -0,0 +1 @@ +'1.1' diff --git a/test/grammar/builtins/json/dump_to_file_1/4.yaml b/test/grammar/builtins/json/dump_to_file_1/4.yaml new file mode 100644 index 000000000..c99e6404c --- /dev/null +++ b/test/grammar/builtins/json/dump_to_file_1/4.yaml @@ -0,0 +1 @@ +'null' diff --git a/test/grammar/builtins/json/dump_to_file_1/5.yaml b/test/grammar/builtins/json/dump_to_file_1/5.yaml new file mode 100644 index 000000000..fda5ad905 --- /dev/null +++ b/test/grammar/builtins/json/dump_to_file_1/5.yaml @@ -0,0 +1 @@ +'true' diff --git a/test/grammar/builtins/json/dump_to_file_1/main.k b/test/grammar/builtins/json/dump_to_file_1/main.k new file mode 100644 index 000000000..aa6738c03 --- /dev/null +++ b/test/grammar/builtins/json/dump_to_file_1/main.k @@ -0,0 +1,11 @@ +import yaml + +yamlStrList = [ + 'key: value', + '- 1\n- 2\n- 3', + '1', + '1.1', + 'null', + 'true', +] +_ = [yaml.dump_to_file(s, filename="${i}.yaml") for i, s in yamlStrList] diff --git a/test/grammar/builtins/json/dump_to_file_1/stdout.golden b/test/grammar/builtins/json/dump_to_file_1/stdout.golden new file mode 100644 index 000000000..d013fc8fb --- /dev/null +++ b/test/grammar/builtins/json/dump_to_file_1/stdout.golden @@ -0,0 +1,10 @@ +yamlStrList: +- 'key: value' +- |- + - 1 + - 2 + - 3 +- '1' +- '1.1' +- 'null' +- 'true' diff --git a/test/grammar/builtins/json/output_0/main.k b/test/grammar/builtins/json/output_0/main.k index 5be6161d0..ca63c5961 100644 --- a/test/grammar/builtins/json/output_0/main.k +++ b/test/grammar/builtins/json/output_0/main.k @@ -2,7 +2,6 @@ import json schema Person: - __settings__: {str:str} = {"output_type": "STANDALONE"} name?: str age?: int school?: str diff --git a/test/grammar/builtins/json/output_1/main.k b/test/grammar/builtins/json/output_1/main.k index 6e22b6137..e9c3cc5ec 100644 --- a/test/grammar/builtins/json/output_1/main.k +++ b/test/grammar/builtins/json/output_1/main.k @@ -2,16 +2,14 @@ import json schema Person: - __settings__: {str:str} = {"output_type": "STANDALONE"} name?: str age?: int school?: str data?: [int] = [1, 2, None] -_person = Person { +person = Person { name: "Alice" age: 18 } -_filename = "out.json" -print("JSON output is in {}".format(_filename)) -json.dump_to_file(_person, _filename, indent=4, ignore_private=True, ignore_none=True) +filename = "out.json" +json.dump_to_file(person, filename, indent=4, ignore_private=True, ignore_none=True) diff --git a/test/grammar/builtins/json/output_1/stdout.golden b/test/grammar/builtins/json/output_1/stdout.golden index 27297403a..24ff32c56 100644 --- a/test/grammar/builtins/json/output_1/stdout.golden +++ b/test/grammar/builtins/json/output_1/stdout.golden @@ -1 +1,8 @@ -JSON output is in out.json +person: + name: Alice + age: 18 + data: + - 1 + - 2 + - null +filename: out.json diff --git a/test/grammar/builtins/json/output_2/main.k b/test/grammar/builtins/json/output_2/main.k index 68d66e5d4..2e9c5d46e 100644 --- a/test/grammar/builtins/json/output_2/main.k +++ b/test/grammar/builtins/json/output_2/main.k @@ -12,8 +12,7 @@ _person = { "key3": None } } -print("[", end="") -print(json.encode(_person, indent=4), end=",\n") -print(json.encode(_person, indent=4, ignore_private=True), end=",\n") -print(json.encode(_person, indent=4, ignore_none=True), end=",\n") -print(json.encode(_person, indent=4, ignore_private=True, ignore_none=True), end="]\n") +person0 = json.encode(_person, indent=4) +person1 = json.encode(_person, indent=4, ignore_private=True) +person2 = json.encode(_person, indent=4, ignore_none=True) +person3 = json.encode(_person, indent=4, ignore_private=True, ignore_none=True) diff --git a/test/grammar/builtins/json/output_2/stdout.golden b/test/grammar/builtins/json/output_2/stdout.golden index 31b4bfe1e..36c42cd35 100644 --- a/test/grammar/builtins/json/output_2/stdout.golden +++ b/test/grammar/builtins/json/output_2/stdout.golden @@ -1,52 +1,56 @@ -[{ - "_key": "value", - "name": "Alice", - "age": 18, - "data": [ - 1, - 2, - null - ], - "labels": { - "key1": "value1", - "_key2": "value2", - "key3": null - } -}, -{ - "name": "Alice", - "age": 18, - "data": [ - 1, - 2, - null - ], - "labels": { - "key1": "value1", - "key3": null - } -}, -{ - "_key": "value", - "name": "Alice", - "age": 18, - "data": [ - 1, - 2 - ], - "labels": { - "key1": "value1", - "_key2": "value2" - } -}, -{ - "name": "Alice", - "age": 18, - "data": [ - 1, - 2 - ], - "labels": { - "key1": "value1" - } -}] +person0: |- + { + "_key": "value", + "name": "Alice", + "age": 18, + "data": [ + 1, + 2, + null + ], + "labels": { + "key1": "value1", + "_key2": "value2", + "key3": null + } + } +person1: |- + { + "name": "Alice", + "age": 18, + "data": [ + 1, + 2, + null + ], + "labels": { + "key1": "value1", + "key3": null + } + } +person2: |- + { + "_key": "value", + "name": "Alice", + "age": 18, + "data": [ + 1, + 2 + ], + "labels": { + "key1": "value1", + "_key2": "value2" + } + } +person3: |- + { + "name": "Alice", + "age": 18, + "data": [ + 1, + 2 + ], + "labels": { + "key1": "value1" + } + } diff --git a/test/grammar/builtins/json/validate/main.k b/test/grammar/builtins/json/validate/main.k new file mode 100644 index 000000000..7acff6bd3 --- /dev/null +++ b/test/grammar/builtins/json/validate/main.k @@ -0,0 +1,19 @@ +import json + +# Right cases + +resultRight1: bool = json.validate("1") +resultRight2: bool = json.validate("true") +resultRight3: bool = json.validate("1.20") +resultRight4: bool = json.validate("null") +resultRight5: bool = json.validate("[0, 1, 2]") +resultRight6: bool = json.validate('{"key": "value"}') + +# Wrong cases + +resultWrong1: bool = json.validate("1@") +resultWrong2: bool = json.validate("True") +resultWrong3: bool = json.validate("1.20.23+1") +resultWrong4: bool = json.validate("None") +resultWrong5: bool = json.validate("[0, 1, 2,]") +resultWrong6: bool = json.validate(r'''{"key": 'value'}''') diff --git a/test/grammar/builtins/json/validate/stdout.golden b/test/grammar/builtins/json/validate/stdout.golden new file mode 100644 index 000000000..60321cd70 --- /dev/null +++ b/test/grammar/builtins/json/validate/stdout.golden @@ -0,0 +1,12 @@ +resultRight1: true +resultRight2: true +resultRight3: true +resultRight4: true +resultRight5: true +resultRight6: true +resultWrong1: false +resultWrong2: false +resultWrong3: false +resultWrong4: false +resultWrong5: false +resultWrong6: false diff --git a/test/grammar/builtins/manifests/yaml_stream/config/main.k b/test/grammar/builtins/manifests/yaml_stream/config/main.k new file mode 100644 index 000000000..95d777dd7 --- /dev/null +++ b/test/grammar/builtins/manifests/yaml_stream/config/main.k @@ -0,0 +1,11 @@ +import manifests + +schema Person: + name: str = "kcl" + age: int = 1 + +x0 = Person {} +x1 = Person { + age = 101 +} +manifests.yaml_stream([x0, x1]) diff --git a/test/grammar/builtins/manifests/yaml_stream/config/stdout.golden b/test/grammar/builtins/manifests/yaml_stream/config/stdout.golden new file mode 100644 index 000000000..c3eb922d7 --- /dev/null +++ b/test/grammar/builtins/manifests/yaml_stream/config/stdout.golden @@ -0,0 +1,5 @@ +name: kcl +age: 1 +--- +name: kcl +age: 101 diff --git a/test/grammar/builtins/manifests/yaml_stream/config_ignore_none/main.k b/test/grammar/builtins/manifests/yaml_stream/config_ignore_none/main.k new file mode 100644 index 000000000..bb632ddf2 --- /dev/null +++ b/test/grammar/builtins/manifests/yaml_stream/config_ignore_none/main.k @@ -0,0 +1,11 @@ +import manifests + +schema Person: + name: str = "kcl" + age?: int = 1 + +x0 = Person {} +x1 = Person { + age = None +} +manifests.yaml_stream([x0, x1], opts = {ignore_none = True}) diff --git a/test/grammar/builtins/manifests/yaml_stream/config_ignore_none/stdout.golden b/test/grammar/builtins/manifests/yaml_stream/config_ignore_none/stdout.golden new file mode 100644 index 000000000..30fcca92f --- /dev/null +++ b/test/grammar/builtins/manifests/yaml_stream/config_ignore_none/stdout.golden @@ -0,0 +1,4 @@ +name: kcl +age: 1 +--- +name: kcl diff --git a/test/grammar/builtins/manifests/yaml_stream/config_ignore_private_false/main.k b/test/grammar/builtins/manifests/yaml_stream/config_ignore_private_false/main.k new file mode 100644 index 000000000..4631e61aa --- /dev/null +++ b/test/grammar/builtins/manifests/yaml_stream/config_ignore_private_false/main.k @@ -0,0 +1,17 @@ +import manifests + +schema XYZ: + [str]: str + +xyz = { + "_foo": "bar" + "foo": "bar" + xyz: XYZ { + _bla: "bla" + } + a = None +} + +manifests.yaml_stream([xyz], opts={ + ignore_private = False +}) diff --git a/test/grammar/builtins/manifests/yaml_stream/config_ignore_private_false/stdout.golden b/test/grammar/builtins/manifests/yaml_stream/config_ignore_private_false/stdout.golden new file mode 100644 index 000000000..906441f7e --- /dev/null +++ b/test/grammar/builtins/manifests/yaml_stream/config_ignore_private_false/stdout.golden @@ -0,0 +1,5 @@ +_foo: bar +foo: bar +xyz: + _bla: bla +a: null diff --git a/test/grammar/builtins/manifests/yaml_stream/config_ignore_private_true/main.k b/test/grammar/builtins/manifests/yaml_stream/config_ignore_private_true/main.k new file mode 100644 index 000000000..f71b40089 --- /dev/null +++ b/test/grammar/builtins/manifests/yaml_stream/config_ignore_private_true/main.k @@ -0,0 +1,17 @@ +import manifests + +schema XYZ: + [str]: str + +xyz = { + "_foo": "bar" + "foo": "bar" + xyz: XYZ { + _bla: "bla" + } + a = None +} + +manifests.yaml_stream([xyz], opts={ + ignore_private = True +}) diff --git a/test/grammar/builtins/manifests/yaml_stream/config_ignore_private_true/stdout.golden b/test/grammar/builtins/manifests/yaml_stream/config_ignore_private_true/stdout.golden new file mode 100644 index 000000000..32462c35c --- /dev/null +++ b/test/grammar/builtins/manifests/yaml_stream/config_ignore_private_true/stdout.golden @@ -0,0 +1,3 @@ +foo: bar +xyz: {} +a: null diff --git a/test/grammar/builtins/manifests/yaml_stream/config_sep/main.k b/test/grammar/builtins/manifests/yaml_stream/config_sep/main.k new file mode 100644 index 000000000..88c9a90cb --- /dev/null +++ b/test/grammar/builtins/manifests/yaml_stream/config_sep/main.k @@ -0,0 +1,13 @@ +import manifests + +schema Person: + name: str = "kcl" + age: int = 1 + +x0 = Person {} +x1 = Person { + age = 101 +} +manifests.yaml_stream([x0, x1], { + sep = "\n---\n" +}) diff --git a/test/grammar/builtins/manifests/yaml_stream/config_sep/stdout.golden b/test/grammar/builtins/manifests/yaml_stream/config_sep/stdout.golden new file mode 100644 index 000000000..df0171f77 --- /dev/null +++ b/test/grammar/builtins/manifests/yaml_stream/config_sep/stdout.golden @@ -0,0 +1,7 @@ +name: kcl +age: 1 + +--- + +name: kcl +age: 101 \ No newline at end of file diff --git a/test/grammar/builtins/manifests/yaml_stream/config_sort_keys/main.k b/test/grammar/builtins/manifests/yaml_stream/config_sort_keys/main.k new file mode 100644 index 000000000..1421735c6 --- /dev/null +++ b/test/grammar/builtins/manifests/yaml_stream/config_sort_keys/main.k @@ -0,0 +1,11 @@ +import manifests + +schema Person: + name: str = "kcl" + age: int = 1 + +x0 = Person {} +x1 = Person { + age = 101 +} +manifests.yaml_stream([x0, x1], opts = {sort_keys = True}) diff --git a/test/grammar/builtins/manifests/yaml_stream/config_sort_keys/stdout.golden b/test/grammar/builtins/manifests/yaml_stream/config_sort_keys/stdout.golden new file mode 100644 index 000000000..e80c18631 --- /dev/null +++ b/test/grammar/builtins/manifests/yaml_stream/config_sort_keys/stdout.golden @@ -0,0 +1,5 @@ +age: 1 +name: kcl +--- +age: 101 +name: kcl diff --git a/test/grammar/builtins/manifests/yaml_stream/list/main.k b/test/grammar/builtins/manifests/yaml_stream/list/main.k new file mode 100644 index 000000000..f23e06233 --- /dev/null +++ b/test/grammar/builtins/manifests/yaml_stream/list/main.k @@ -0,0 +1,3 @@ +import manifests + +manifests.yaml_stream([{k1 = [1, 2], k2 = [3, 4]}, {k3 = [5, 6], k4 = [7, 8]}, {k5 = [9, 10]}]) diff --git a/test/grammar/builtins/manifests/yaml_stream/list/stdout.golden b/test/grammar/builtins/manifests/yaml_stream/list/stdout.golden new file mode 100644 index 000000000..cf081cf3d --- /dev/null +++ b/test/grammar/builtins/manifests/yaml_stream/list/stdout.golden @@ -0,0 +1,17 @@ +k1: +- 1 +- 2 +k2: +- 3 +- 4 +--- +k3: +- 5 +- 6 +k4: +- 7 +- 8 +--- +k5: +- 9 +- 10 diff --git a/test/grammar/builtins/manifests/yaml_stream/multiple_literal_0/main.k b/test/grammar/builtins/manifests/yaml_stream/multiple_literal_0/main.k new file mode 100644 index 000000000..aad0badc5 --- /dev/null +++ b/test/grammar/builtins/manifests/yaml_stream/multiple_literal_0/main.k @@ -0,0 +1,3 @@ +import manifests + +manifests.yaml_stream([1, 2, 3]) diff --git a/test/grammar/builtins/manifests/yaml_stream/multiple_literal_0/stdout.golden b/test/grammar/builtins/manifests/yaml_stream/multiple_literal_0/stdout.golden new file mode 100644 index 000000000..5fd5cb2ad --- /dev/null +++ b/test/grammar/builtins/manifests/yaml_stream/multiple_literal_0/stdout.golden @@ -0,0 +1,5 @@ +1 +--- +2 +--- +3 diff --git a/test/grammar/builtins/manifests/yaml_stream/multiple_literal_1/main.k b/test/grammar/builtins/manifests/yaml_stream/multiple_literal_1/main.k new file mode 100644 index 000000000..f9e0ace0d --- /dev/null +++ b/test/grammar/builtins/manifests/yaml_stream/multiple_literal_1/main.k @@ -0,0 +1,3 @@ +import manifests + +manifests.yaml_stream([1, Undefined, 2Mi, 3.0, "literal", True, False, None]) diff --git a/test/grammar/builtins/manifests/yaml_stream/multiple_literal_1/stdout.golden b/test/grammar/builtins/manifests/yaml_stream/multiple_literal_1/stdout.golden new file mode 100644 index 000000000..9897c5c14 --- /dev/null +++ b/test/grammar/builtins/manifests/yaml_stream/multiple_literal_1/stdout.golden @@ -0,0 +1,15 @@ +1 +--- +null +--- +2097152.0 +--- +3.0 +--- +literal +--- +true +--- +false +--- +null diff --git a/test/grammar/builtins/manifests/yaml_stream/single_literal_0/main.k b/test/grammar/builtins/manifests/yaml_stream/single_literal_0/main.k new file mode 100644 index 000000000..1d77a8722 --- /dev/null +++ b/test/grammar/builtins/manifests/yaml_stream/single_literal_0/main.k @@ -0,0 +1,3 @@ +import manifests + +manifests.yaml_stream([1]) diff --git a/test/grammar/builtins/manifests/yaml_stream/single_literal_0/stdout.golden b/test/grammar/builtins/manifests/yaml_stream/single_literal_0/stdout.golden new file mode 100644 index 000000000..d00491fd7 --- /dev/null +++ b/test/grammar/builtins/manifests/yaml_stream/single_literal_0/stdout.golden @@ -0,0 +1 @@ +1 diff --git a/test/grammar/builtins/manifests/yaml_stream/single_literal_1/main.k b/test/grammar/builtins/manifests/yaml_stream/single_literal_1/main.k new file mode 100644 index 000000000..89df72131 --- /dev/null +++ b/test/grammar/builtins/manifests/yaml_stream/single_literal_1/main.k @@ -0,0 +1,3 @@ +import manifests + +manifests.yaml_stream([None]) diff --git a/test/grammar/builtins/manifests/yaml_stream/single_literal_1/stdout.golden b/test/grammar/builtins/manifests/yaml_stream/single_literal_1/stdout.golden new file mode 100644 index 000000000..19765bd50 --- /dev/null +++ b/test/grammar/builtins/manifests/yaml_stream/single_literal_1/stdout.golden @@ -0,0 +1 @@ +null diff --git a/test/grammar/builtins/math/expm1/stdout.golden b/test/grammar/builtins/math/expm1/stdout.golden index 819d6db65..3360b4a25 100644 --- a/test/grammar/builtins/math/expm1/stdout.golden +++ b/test/grammar/builtins/math/expm1/stdout.golden @@ -1,2 +1,2 @@ a: 78962960182679.69 -b: -0.9999813562576685 \ No newline at end of file +b: -0.9999813562576684 diff --git a/test/grammar/builtins/math/modf/stdout.golden b/test/grammar/builtins/math/modf/stdout.golden index 86587c451..41259dc5a 100644 --- a/test/grammar/builtins/math/modf/stdout.golden +++ b/test/grammar/builtins/math/modf/stdout.golden @@ -1,5 +1,5 @@ a: -- 0.12000000000000455 +- 0.12000000000000456 - 100.0 b: - 0.7199999999999989 diff --git a/test/grammar/builtins/net/is_ip_2/stdout.golden b/test/grammar/builtins/net/is_ip_2/stdout.golden index 03265e7b7..f36847e50 100644 --- a/test/grammar/builtins/net/is_ip_2/stdout.golden +++ b/test/grammar/builtins/net/is_ip_2/stdout.golden @@ -1,6 +1,6 @@ isip0: true isip1: true -isip2: false +isip2: true isip3: true isip4: true isip5: true \ No newline at end of file diff --git a/test/grammar/builtins/operator/operator_fail_0/stderr.golden b/test/grammar/builtins/operator/operator_fail_0/stderr.golden new file mode 100644 index 000000000..f031b9ff4 --- /dev/null +++ b/test/grammar/builtins/operator/operator_fail_0/stderr.golden @@ -0,0 +1,6 @@ +error[E2G22]: TypeError + --> ${CWD}/main.k:2:5 + | +2 | b = 1 + None + | ^ unsupported operand type(s) for +: 'int(1)' and 'NoneType' + | \ No newline at end of file diff --git a/test/grammar/builtins/operator/operator_fail_0/stderr.golden.py b/test/grammar/builtins/operator/operator_fail_0/stderr.golden.py deleted file mode 100644 index 3da23c34b..000000000 --- a/test/grammar/builtins/operator/operator_fail_0/stderr.golden.py +++ /dev/null @@ -1,21 +0,0 @@ - -import sys -import os - -import kclvm.kcl.error as kcl_error - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.CompileError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=2 - ) - ], - arg_msg="unsupported operand type(s) for +: 'int(1)' and 'NoneType'" - ), - file=sys.stdout -) diff --git a/test/grammar/builtins/operator/operator_fail_1/stderr.golden b/test/grammar/builtins/operator/operator_fail_1/stderr.golden new file mode 100644 index 000000000..e29e672cc --- /dev/null +++ b/test/grammar/builtins/operator/operator_fail_1/stderr.golden @@ -0,0 +1,6 @@ +error[E2G22]: TypeError + --> ${CWD}/main.k:2:5 + | +2 | b = None + 1 + | ^ unsupported operand type(s) for +: 'NoneType' and 'int(1)' + | \ No newline at end of file diff --git a/test/grammar/builtins/operator/operator_fail_1/stderr.golden.py b/test/grammar/builtins/operator/operator_fail_1/stderr.golden.py deleted file mode 100644 index 21347a90e..000000000 --- a/test/grammar/builtins/operator/operator_fail_1/stderr.golden.py +++ /dev/null @@ -1,22 +0,0 @@ - -import sys -import os - -import kclvm.kcl.error as kcl_error - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.CompileError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=2 - ) - ], - arg_msg="unsupported operand type(s) for +: 'NoneType' and 'int(1)'" - ), - file=sys.stdout -) - diff --git a/test/grammar/builtins/operator/operator_fail_2/stderr.golden b/test/grammar/builtins/operator/operator_fail_2/stderr.golden new file mode 100644 index 000000000..b2ab2e1f6 --- /dev/null +++ b/test/grammar/builtins/operator/operator_fail_2/stderr.golden @@ -0,0 +1,6 @@ +error[E2G22]: TypeError + --> ${CWD}/main.k:2:5 + | +2 | b = 1 + a + | ^ unsupported operand type(s) for +: 'int(1)' and '[int | {str:str}]' + | \ No newline at end of file diff --git a/test/grammar/builtins/operator/operator_fail_2/stderr.golden.py b/test/grammar/builtins/operator/operator_fail_2/stderr.golden.py deleted file mode 100644 index 72e10e9f9..000000000 --- a/test/grammar/builtins/operator/operator_fail_2/stderr.golden.py +++ /dev/null @@ -1,22 +0,0 @@ - -import sys -import os - -import kclvm.kcl.error as kcl_error - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.CompileError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=2 - ) - ], - arg_msg="unsupported operand type(s) for +: 'int(1)' and '[int|{str:str}]'" - ), - file=sys.stdout -) - diff --git a/test/grammar/builtins/runtime/catch_0/main.k b/test/grammar/builtins/runtime/catch_0/main.k new file mode 100644 index 000000000..6b524b78a --- /dev/null +++ b/test/grammar/builtins/runtime/catch_0/main.k @@ -0,0 +1,6 @@ +import runtime + +# Get the panic message here +msg = runtime.catch(lambda { + [][0] # panic here +}) diff --git a/test/grammar/builtins/runtime/catch_0/stdout.golden b/test/grammar/builtins/runtime/catch_0/stdout.golden new file mode 100644 index 000000000..cc3892f87 --- /dev/null +++ b/test/grammar/builtins/runtime/catch_0/stdout.golden @@ -0,0 +1 @@ +msg: 'list index out of range: 0' diff --git a/test/grammar/builtins/runtime/catch_1/main.k b/test/grammar/builtins/runtime/catch_1/main.k new file mode 100644 index 000000000..7e77faf72 --- /dev/null +++ b/test/grammar/builtins/runtime/catch_1/main.k @@ -0,0 +1,5 @@ +import runtime + +msg = runtime.catch(lambda { + assert False, "error msg" +}) diff --git a/test/grammar/builtins/runtime/catch_1/stdout.golden b/test/grammar/builtins/runtime/catch_1/stdout.golden new file mode 100644 index 000000000..15d2ac98e --- /dev/null +++ b/test/grammar/builtins/runtime/catch_1/stdout.golden @@ -0,0 +1 @@ +msg: error msg diff --git a/test/grammar/builtins/runtime/catch_2/main.k b/test/grammar/builtins/runtime/catch_2/main.k new file mode 100644 index 000000000..a6ac0e27a --- /dev/null +++ b/test/grammar/builtins/runtime/catch_2/main.k @@ -0,0 +1,15 @@ +import runtime + +schema Person: + age: int + name?: str + + check: + 0 < age < 10, "age must be in the range (0, 10)" + +msg = runtime.catch(lambda { + person = Person { + age: 1000 + } + person.name +}) diff --git a/test/grammar/builtins/runtime/catch_2/stdout.golden b/test/grammar/builtins/runtime/catch_2/stdout.golden new file mode 100644 index 000000000..3d40dad99 --- /dev/null +++ b/test/grammar/builtins/runtime/catch_2/stdout.golden @@ -0,0 +1 @@ +msg: age must be in the range (0, 10) diff --git a/test/grammar/builtins/str/chars/main.k b/test/grammar/builtins/str/chars/main.k new file mode 100644 index 000000000..aa63e6ddf --- /dev/null +++ b/test/grammar/builtins/str/chars/main.k @@ -0,0 +1,2 @@ +a = "Hello, World!".chars() +b = "你好, 世界!".chars() \ No newline at end of file diff --git a/test/grammar/builtins/str/chars/stdout.golden b/test/grammar/builtins/str/chars/stdout.golden new file mode 100644 index 000000000..43e67496a --- /dev/null +++ b/test/grammar/builtins/str/chars/stdout.golden @@ -0,0 +1,22 @@ +a: +- H +- e +- l +- l +- o +- ',' +- ' ' +- W +- o +- r +- l +- d +- '!' +b: +- 你 +- 好 +- , +- ' ' +- 世 +- 界 +- ! \ No newline at end of file diff --git a/test/grammar/builtins/str/index/stderr.golden b/test/grammar/builtins/str/index/stderr.golden new file mode 100644 index 000000000..b655c6ac5 --- /dev/null +++ b/test/grammar/builtins/str/index/stderr.golden @@ -0,0 +1,6 @@ +error[E3M38]: EvaluationError + --> ${CWD}/main.k:2:1 + | +2 | b = "Hello World".index("Wrold") + | substring not found + | \ No newline at end of file diff --git a/test/grammar/builtins/str/index/stderr.golden.py b/test/grammar/builtins/str/index/stderr.golden.py deleted file mode 100644 index d81ddf910..000000000 --- a/test/grammar/builtins/str/index/stderr.golden.py +++ /dev/null @@ -1,21 +0,0 @@ -import sys -import os - -import kclvm.kcl.error as kcl_error - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.EvaluationError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=2 - ) - ], - arg_msg="substring not found" - ) - , file=sys.stdout -) - diff --git a/test/grammar/builtins/str/rindex/stderr.golden b/test/grammar/builtins/str/rindex/stderr.golden new file mode 100644 index 000000000..e76aa4c34 --- /dev/null +++ b/test/grammar/builtins/str/rindex/stderr.golden @@ -0,0 +1,6 @@ +error[E3M38]: EvaluationError + --> ${CWD}/main.k:3:1 + | +3 | c = "Hello World, Hello World".rindex("Hee") + | substring not found + | \ No newline at end of file diff --git a/test/grammar/builtins/str/rindex/stderr.golden.py b/test/grammar/builtins/str/rindex/stderr.golden.py deleted file mode 100644 index ea85be9ec..000000000 --- a/test/grammar/builtins/str/rindex/stderr.golden.py +++ /dev/null @@ -1,21 +0,0 @@ - -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.EvaluationError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=3 - ) - ], - arg_msg="substring not found" - ) - , file=sys.stdout -) - diff --git a/test/grammar/builtins/template/execute_0/main.k b/test/grammar/builtins/template/execute_0/main.k new file mode 100644 index 000000000..89300020f --- /dev/null +++ b/test/grammar/builtins/template/execute_0/main.k @@ -0,0 +1,3 @@ +import template + +content = template.execute("hello {{world}}", {world = "世界"}) diff --git a/test/grammar/builtins/template/execute_0/stdout.golden b/test/grammar/builtins/template/execute_0/stdout.golden new file mode 100644 index 000000000..1f6b45c75 --- /dev/null +++ b/test/grammar/builtins/template/execute_0/stdout.golden @@ -0,0 +1 @@ +content: hello 世界 diff --git a/test/grammar/builtins/template/execute_1/main.k b/test/grammar/builtins/template/execute_1/main.k new file mode 100644 index 000000000..fd22aeb72 --- /dev/null +++ b/test/grammar/builtins/template/execute_1/main.k @@ -0,0 +1,13 @@ +import template + +content = template.execute("""\ +

    +{{#if author}} +

    {{firstName}} {{lastName}}

    +{{/if}} +
    +""", { + author: True, + firstName: "Yehuda", + lastName: "Katz", +}) diff --git a/test/grammar/builtins/template/execute_1/stdout.golden b/test/grammar/builtins/template/execute_1/stdout.golden new file mode 100644 index 000000000..08bfb1944 --- /dev/null +++ b/test/grammar/builtins/template/execute_1/stdout.golden @@ -0,0 +1,4 @@ +content: | +
    +

    Yehuda Katz

    +
    diff --git a/test/grammar/builtins/template/execute_2/main.k b/test/grammar/builtins/template/execute_2/main.k new file mode 100644 index 000000000..7423db2b7 --- /dev/null +++ b/test/grammar/builtins/template/execute_2/main.k @@ -0,0 +1,32 @@ +import template + +_data = { + name = "handlebars", + v = [ { a = 1}, { a = 2}], + c = { d = 5}, + g = { b = [{ aa = { bb = 55}}, { aa = { bb = 66} } ] }, + people = [ "Yehuda Katz", "Alan Johnson", "Charles Jolley" ] +} + +content = template.execute("""\ +Hello world from {{name}} + +{{#each v}} +{{this.a}} +{{/each}} +{{ c.d }} +{{#each people}} +{{ this }} +{{/each}} +{{#each g.b}} +{{this.aa.bb}} +{{/each}} +""", _data) + +content_raw = template.execute("""\ +{{this.name}} +{{this.v}} +{{this.c}} +{{this.g}} +{{this.people}} +""", _data) \ No newline at end of file diff --git a/test/grammar/builtins/template/execute_2/stdout.golden b/test/grammar/builtins/template/execute_2/stdout.golden new file mode 100644 index 000000000..ca2d9e188 --- /dev/null +++ b/test/grammar/builtins/template/execute_2/stdout.golden @@ -0,0 +1,17 @@ +content: | + Hello world from handlebars + + 1 + 2 + 5 + Yehuda Katz + Alan Johnson + Charles Jolley + 55 + 66 +content_raw: | + handlebars + [[object], [object]] + [object] + [object] + [Yehuda Katz, Alan Johnson, Charles Jolley] diff --git a/test/grammar/builtins/template/html_escape_0/main.k b/test/grammar/builtins/template/html_escape_0/main.k new file mode 100644 index 000000000..1e3290535 --- /dev/null +++ b/test/grammar/builtins/template/html_escape_0/main.k @@ -0,0 +1,9 @@ +import template + +content = template.html_escape("""\ +
    +{{#if author}} +

    {{firstName}} {{lastName}}

    +{{/if}} +
    +""") diff --git a/test/grammar/builtins/template/html_escape_0/stdout.golden b/test/grammar/builtins/template/html_escape_0/stdout.golden new file mode 100644 index 000000000..ef0ab2e45 --- /dev/null +++ b/test/grammar/builtins/template/html_escape_0/stdout.golden @@ -0,0 +1,6 @@ +content: | + <div class="entry"> + {{#if author}} + <h1>{{firstName}} {{lastName}}</h1> + {{/if}} + </div> diff --git a/test/grammar/builtins/yaml/decode_all_0/main.k b/test/grammar/builtins/yaml/decode_all_0/main.k new file mode 100644 index 000000000..af7f4da6d --- /dev/null +++ b/test/grammar/builtins/yaml/decode_all_0/main.k @@ -0,0 +1,11 @@ +import yaml + +yamlStrList = [ + 'key: value', + '- 1\n- 2\n- 3', + '1', + '1.1', + 'null', + 'true', +] +data = [yaml.decode_all(s) for s in yamlStrList] diff --git a/test/grammar/builtins/yaml/decode_all_0/stdout.golden b/test/grammar/builtins/yaml/decode_all_0/stdout.golden new file mode 100644 index 000000000..d68520ac0 --- /dev/null +++ b/test/grammar/builtins/yaml/decode_all_0/stdout.golden @@ -0,0 +1,19 @@ +yamlStrList: +- 'key: value' +- |- + - 1 + - 2 + - 3 +- '1' +- '1.1' +- 'null' +- 'true' +data: +- - key: value +- - - 1 + - 2 + - 3 +- - 1 +- - 1.1 +- - null +- - true diff --git a/test/grammar/builtins/yaml/decode_all_1/main.k b/test/grammar/builtins/yaml/decode_all_1/main.k new file mode 100644 index 000000000..e67562cfa --- /dev/null +++ b/test/grammar/builtins/yaml/decode_all_1/main.k @@ -0,0 +1,9 @@ +import yaml + +yamlStrList = [ + 'key1: value2\n---\nkey2: [1, 2, 3]', + '- 1\n- 2\n- 3\n---\nkey: value', + '1\n---\n2', + '1.1\n---\nnull\n---\ntrue\n---\nfalse', +] +data = [yaml.decode_all(s) for s in yamlStrList] diff --git a/test/grammar/builtins/yaml/decode_all_1/stdout.golden b/test/grammar/builtins/yaml/decode_all_1/stdout.golden new file mode 100644 index 000000000..2c4dac91d --- /dev/null +++ b/test/grammar/builtins/yaml/decode_all_1/stdout.golden @@ -0,0 +1,39 @@ +yamlStrList: +- |- + key1: value2 + --- + key2: [1, 2, 3] +- |- + - 1 + - 2 + - 3 + --- + key: value +- |- + 1 + --- + 2 +- |- + 1.1 + --- + null + --- + true + --- + false +data: +- - key1: value2 + - key2: + - 1 + - 2 + - 3 +- - - 1 + - 2 + - 3 + - key: value +- - 1 + - 2 +- - 1.1 + - null + - true + - false diff --git a/test/grammar/builtins/yaml/decode_all_2/main.k b/test/grammar/builtins/yaml/decode_all_2/main.k new file mode 100644 index 000000000..cc4ed0fac --- /dev/null +++ b/test/grammar/builtins/yaml/decode_all_2/main.k @@ -0,0 +1,7 @@ +import yaml + +yamlStr = """\ +key: value +""" +data = yaml.decode(yamlStr) +dataList = yaml.decode_all(yamlStr) diff --git a/test/grammar/builtins/yaml/decode_all_2/stdout.golden b/test/grammar/builtins/yaml/decode_all_2/stdout.golden new file mode 100644 index 000000000..c017f4306 --- /dev/null +++ b/test/grammar/builtins/yaml/decode_all_2/stdout.golden @@ -0,0 +1,6 @@ +yamlStr: | + key: value +data: + key: value +dataList: +- key: value diff --git a/test/grammar/builtins/yaml/dump_all_to_file_0/0.yaml b/test/grammar/builtins/yaml/dump_all_to_file_0/0.yaml new file mode 100644 index 000000000..ad428a629 --- /dev/null +++ b/test/grammar/builtins/yaml/dump_all_to_file_0/0.yaml @@ -0,0 +1,19 @@ +'key: value' + +--- +|- + - 1 + - 2 + - 3 + +--- +'1' + +--- +'1.1' + +--- +'null' + +--- +'true' diff --git a/test/grammar/builtins/yaml/dump_all_to_file_0/main.k b/test/grammar/builtins/yaml/dump_all_to_file_0/main.k new file mode 100644 index 000000000..af1607990 --- /dev/null +++ b/test/grammar/builtins/yaml/dump_all_to_file_0/main.k @@ -0,0 +1,11 @@ +import yaml + +yamlStrList = [ + 'key: value', + '- 1\n- 2\n- 3', + '1', + '1.1', + 'null', + 'true', +] +yaml.dump_all_to_file(yamlStrList, "0.yaml") diff --git a/test/grammar/builtins/yaml/dump_all_to_file_0/stdout.golden b/test/grammar/builtins/yaml/dump_all_to_file_0/stdout.golden new file mode 100644 index 000000000..d013fc8fb --- /dev/null +++ b/test/grammar/builtins/yaml/dump_all_to_file_0/stdout.golden @@ -0,0 +1,10 @@ +yamlStrList: +- 'key: value' +- |- + - 1 + - 2 + - 3 +- '1' +- '1.1' +- 'null' +- 'true' diff --git a/test/grammar/builtins/yaml/dump_to_file_0/0.yaml b/test/grammar/builtins/yaml/dump_to_file_0/0.yaml new file mode 100644 index 000000000..8593e686f --- /dev/null +++ b/test/grammar/builtins/yaml/dump_to_file_0/0.yaml @@ -0,0 +1 @@ +'key: value' diff --git a/test/grammar/builtins/yaml/dump_to_file_0/1.yaml b/test/grammar/builtins/yaml/dump_to_file_0/1.yaml new file mode 100644 index 000000000..726ba9b9d --- /dev/null +++ b/test/grammar/builtins/yaml/dump_to_file_0/1.yaml @@ -0,0 +1,4 @@ +|- + - 1 + - 2 + - 3 diff --git a/test/grammar/builtins/yaml/dump_to_file_0/2.yaml b/test/grammar/builtins/yaml/dump_to_file_0/2.yaml new file mode 100644 index 000000000..cb382054c --- /dev/null +++ b/test/grammar/builtins/yaml/dump_to_file_0/2.yaml @@ -0,0 +1 @@ +'1' diff --git a/test/grammar/builtins/yaml/dump_to_file_0/3.yaml b/test/grammar/builtins/yaml/dump_to_file_0/3.yaml new file mode 100644 index 000000000..95c82787d --- /dev/null +++ b/test/grammar/builtins/yaml/dump_to_file_0/3.yaml @@ -0,0 +1 @@ +'1.1' diff --git a/test/grammar/builtins/yaml/dump_to_file_0/4.yaml b/test/grammar/builtins/yaml/dump_to_file_0/4.yaml new file mode 100644 index 000000000..c99e6404c --- /dev/null +++ b/test/grammar/builtins/yaml/dump_to_file_0/4.yaml @@ -0,0 +1 @@ +'null' diff --git a/test/grammar/builtins/yaml/dump_to_file_0/5.yaml b/test/grammar/builtins/yaml/dump_to_file_0/5.yaml new file mode 100644 index 000000000..fda5ad905 --- /dev/null +++ b/test/grammar/builtins/yaml/dump_to_file_0/5.yaml @@ -0,0 +1 @@ +'true' diff --git a/test/grammar/builtins/yaml/dump_to_file_0/main.k b/test/grammar/builtins/yaml/dump_to_file_0/main.k new file mode 100644 index 000000000..117f93bf9 --- /dev/null +++ b/test/grammar/builtins/yaml/dump_to_file_0/main.k @@ -0,0 +1,11 @@ +import yaml + +yamlStrList = [ + 'key: value', + '- 1\n- 2\n- 3', + '1', + '1.1', + 'null', + 'true', +] +_ = [yaml.dump_to_file(s, "${i}.yaml") for i, s in yamlStrList] diff --git a/test/grammar/builtins/yaml/dump_to_file_0/stdout.golden b/test/grammar/builtins/yaml/dump_to_file_0/stdout.golden new file mode 100644 index 000000000..d013fc8fb --- /dev/null +++ b/test/grammar/builtins/yaml/dump_to_file_0/stdout.golden @@ -0,0 +1,10 @@ +yamlStrList: +- 'key: value' +- |- + - 1 + - 2 + - 3 +- '1' +- '1.1' +- 'null' +- 'true' diff --git a/test/grammar/builtins/yaml/dump_to_file_1/0.yaml b/test/grammar/builtins/yaml/dump_to_file_1/0.yaml new file mode 100644 index 000000000..8593e686f --- /dev/null +++ b/test/grammar/builtins/yaml/dump_to_file_1/0.yaml @@ -0,0 +1 @@ +'key: value' diff --git a/test/grammar/builtins/yaml/dump_to_file_1/1.yaml b/test/grammar/builtins/yaml/dump_to_file_1/1.yaml new file mode 100644 index 000000000..726ba9b9d --- /dev/null +++ b/test/grammar/builtins/yaml/dump_to_file_1/1.yaml @@ -0,0 +1,4 @@ +|- + - 1 + - 2 + - 3 diff --git a/test/grammar/builtins/yaml/dump_to_file_1/2.yaml b/test/grammar/builtins/yaml/dump_to_file_1/2.yaml new file mode 100644 index 000000000..cb382054c --- /dev/null +++ b/test/grammar/builtins/yaml/dump_to_file_1/2.yaml @@ -0,0 +1 @@ +'1' diff --git a/test/grammar/builtins/yaml/dump_to_file_1/3.yaml b/test/grammar/builtins/yaml/dump_to_file_1/3.yaml new file mode 100644 index 000000000..95c82787d --- /dev/null +++ b/test/grammar/builtins/yaml/dump_to_file_1/3.yaml @@ -0,0 +1 @@ +'1.1' diff --git a/test/grammar/builtins/yaml/dump_to_file_1/4.yaml b/test/grammar/builtins/yaml/dump_to_file_1/4.yaml new file mode 100644 index 000000000..c99e6404c --- /dev/null +++ b/test/grammar/builtins/yaml/dump_to_file_1/4.yaml @@ -0,0 +1 @@ +'null' diff --git a/test/grammar/builtins/yaml/dump_to_file_1/5.yaml b/test/grammar/builtins/yaml/dump_to_file_1/5.yaml new file mode 100644 index 000000000..fda5ad905 --- /dev/null +++ b/test/grammar/builtins/yaml/dump_to_file_1/5.yaml @@ -0,0 +1 @@ +'true' diff --git a/test/grammar/builtins/yaml/dump_to_file_1/main.k b/test/grammar/builtins/yaml/dump_to_file_1/main.k new file mode 100644 index 000000000..aa6738c03 --- /dev/null +++ b/test/grammar/builtins/yaml/dump_to_file_1/main.k @@ -0,0 +1,11 @@ +import yaml + +yamlStrList = [ + 'key: value', + '- 1\n- 2\n- 3', + '1', + '1.1', + 'null', + 'true', +] +_ = [yaml.dump_to_file(s, filename="${i}.yaml") for i, s in yamlStrList] diff --git a/test/grammar/builtins/yaml/dump_to_file_1/stdout.golden b/test/grammar/builtins/yaml/dump_to_file_1/stdout.golden new file mode 100644 index 000000000..d013fc8fb --- /dev/null +++ b/test/grammar/builtins/yaml/dump_to_file_1/stdout.golden @@ -0,0 +1,10 @@ +yamlStrList: +- 'key: value' +- |- + - 1 + - 2 + - 3 +- '1' +- '1.1' +- 'null' +- 'true' diff --git a/test/grammar/builtins/yaml/encode_0/_main.k b/test/grammar/builtins/yaml/encode_0/_main.k deleted file mode 100644 index da9c24ede..000000000 --- a/test/grammar/builtins/yaml/encode_0/_main.k +++ /dev/null @@ -1,11 +0,0 @@ -import yaml - -dataDict = {"key": "value"} -dataList = [1, 2, 3] -#dataInt = 1 -#dataFloat = 1.1 -#dataNone = None -#dataBool = True - -#yamlStr = [yaml.encode(data) for data in [dataDict, dataList, dataInt, dataFloat, dataNone, dataBool]] -yamlStr = [yaml.encode(data) for data in [dataDict, dataList]] diff --git a/test/grammar/builtins/yaml/encode_0/main.k b/test/grammar/builtins/yaml/encode_0/main.k new file mode 100644 index 000000000..51e77fba3 --- /dev/null +++ b/test/grammar/builtins/yaml/encode_0/main.k @@ -0,0 +1,6 @@ +import yaml + +dataDict = {"key": "value"} +dataList = [1, 2, 3] + +yamlStr = [yaml.encode(data) for data in [dataDict, dataList]] diff --git a/test/grammar/builtins/yaml/encode_1/_main.k b/test/grammar/builtins/yaml/encode_1/main.k similarity index 100% rename from test/grammar/builtins/yaml/encode_1/_main.k rename to test/grammar/builtins/yaml/encode_1/main.k diff --git a/test/grammar/builtins/yaml/encode_all_0/main.k b/test/grammar/builtins/yaml/encode_all_0/main.k new file mode 100644 index 000000000..f99c6b70a --- /dev/null +++ b/test/grammar/builtins/yaml/encode_all_0/main.k @@ -0,0 +1,6 @@ +import yaml + +dataDict = {"key": "value"} +dataList = [1, 2, 3] + +yamlStr = yaml.encode_all([dataDict, dataList]) diff --git a/test/grammar/builtins/yaml/encode_all_0/stdout.golden b/test/grammar/builtins/yaml/encode_all_0/stdout.golden new file mode 100644 index 000000000..7f546203d --- /dev/null +++ b/test/grammar/builtins/yaml/encode_all_0/stdout.golden @@ -0,0 +1,13 @@ +dataDict: + key: value +dataList: +- 1 +- 2 +- 3 +yamlStr: | + key: value + + --- + - 1 + - 2 + - 3 diff --git a/test/grammar/builtins/yaml/encode_all_1/main.k b/test/grammar/builtins/yaml/encode_all_1/main.k new file mode 100644 index 000000000..be26367f6 --- /dev/null +++ b/test/grammar/builtins/yaml/encode_all_1/main.k @@ -0,0 +1,3 @@ +import yaml + +yamlStr = yaml.encode_all([{"key": [1, 2, 3]}, [1, 2, 3]]) diff --git a/test/grammar/builtins/yaml/encode_all_1/stdout.golden b/test/grammar/builtins/yaml/encode_all_1/stdout.golden new file mode 100644 index 000000000..7484e6014 --- /dev/null +++ b/test/grammar/builtins/yaml/encode_all_1/stdout.golden @@ -0,0 +1,10 @@ +yamlStr: | + key: + - 1 + - 2 + - 3 + + --- + - 1 + - 2 + - 3 diff --git a/test/grammar/builtins/yaml/encode_all_2/main.k b/test/grammar/builtins/yaml/encode_all_2/main.k new file mode 100644 index 000000000..39c7e53db --- /dev/null +++ b/test/grammar/builtins/yaml/encode_all_2/main.k @@ -0,0 +1,3 @@ +import yaml + +yamlStr = yaml.encode_all([1, 2, 3]) diff --git a/test/grammar/builtins/yaml/encode_all_2/stdout.golden b/test/grammar/builtins/yaml/encode_all_2/stdout.golden new file mode 100644 index 000000000..f5df77f8d --- /dev/null +++ b/test/grammar/builtins/yaml/encode_all_2/stdout.golden @@ -0,0 +1,8 @@ +yamlStr: | + 1 + + --- + 2 + + --- + 3 diff --git a/test/grammar/builtins/yaml/output_0/_main.k b/test/grammar/builtins/yaml/output_0/_main.k deleted file mode 100644 index d0c0fd63f..000000000 --- a/test/grammar/builtins/yaml/output_0/_main.k +++ /dev/null @@ -1,24 +0,0 @@ - -import yaml - -schema Person: - __settings__: {str:str} = {"output_type": "STANDALONE"} - name?: str - age?: int - school?: str - data?: [int] = [1, 2, None] - -_person = Person { - name: "Alice" - age: 18 -} -# print(yaml.encode(_person), end="") -# print("---") -# print(yaml.encode(_person, ignore_private=True), end="") -# print("---") -# print(yaml.encode(_person, ignore_none=True), end="") -# print("---") -# print(yaml.encode(_person, ignore_private=True, ignore_none=True), end="") - -a1 = yaml.encode(_person, ignore_private=True) -a2 = yaml.encode(_person, ignore_private=True, ignore_none=True) diff --git a/test/grammar/builtins/yaml/output_0/main.k b/test/grammar/builtins/yaml/output_0/main.k new file mode 100644 index 000000000..cb728ede7 --- /dev/null +++ b/test/grammar/builtins/yaml/output_0/main.k @@ -0,0 +1,15 @@ + +import yaml + +schema Person: + name?: str + age?: int + school?: str + data?: [int] = [1, 2, None] + +_person = Person { + name: "Alice" + age: 18 +} +a1 = yaml.encode(_person, ignore_private=True) +a2 = yaml.encode(_person, ignore_private=True, ignore_none=True) diff --git a/test/grammar/builtins/yaml/output_1/main.k b/test/grammar/builtins/yaml/output_1/main.k index 01c2b23a4..4e1830afb 100644 --- a/test/grammar/builtins/yaml/output_1/main.k +++ b/test/grammar/builtins/yaml/output_1/main.k @@ -2,16 +2,14 @@ import yaml schema Person: - __settings__: {str:str} = {"output_type": "STANDALONE"} name?: str age?: int school?: str data?: [int] = [1, 2, None] -_person = Person { +person = Person { name: "Alice" age: 18 } -_filename = "out.yaml" -print("YAML output is in {}".format(_filename)) -yaml.dump_to_file(_person, _filename, ignore_private=True, ignore_none=True) +filename = "out.yaml" +yaml.dump_to_file(person, filename, ignore_private=True, ignore_none=True) diff --git a/test/grammar/builtins/yaml/output_1/stdout.golden b/test/grammar/builtins/yaml/output_1/stdout.golden index e244fa844..4d4e735e2 100644 --- a/test/grammar/builtins/yaml/output_1/stdout.golden +++ b/test/grammar/builtins/yaml/output_1/stdout.golden @@ -1 +1,8 @@ -YAML output is in out.yaml +person: + name: Alice + age: 18 + data: + - 1 + - 2 + - null +filename: out.yaml diff --git a/test/grammar/builtins/yaml/output_2/main.k b/test/grammar/builtins/yaml/output_2/main.k index 4563c67e3..40224ee89 100644 --- a/test/grammar/builtins/yaml/output_2/main.k +++ b/test/grammar/builtins/yaml/output_2/main.k @@ -19,3 +19,5 @@ print("---") print(yaml.encode(_person, ignore_none=True), end="") print("---") print(yaml.encode(_person, ignore_private=True, ignore_none=True), end="") +print("---") +person = _person diff --git a/test/grammar/builtins/yaml/output_2/stdout.golden b/test/grammar/builtins/yaml/output_2/stdout.golden index 3f96f71d4..5e2f92026 100644 --- a/test/grammar/builtins/yaml/output_2/stdout.golden +++ b/test/grammar/builtins/yaml/output_2/stdout.golden @@ -37,3 +37,14 @@ data: - 2 labels: key1: value1 +--- +person: + name: Alice + age: 18 + data: + - 1 + - 2 + - null + labels: + key1: value1 + key3: null diff --git a/test/grammar/builtins/yaml/validate/main.k b/test/grammar/builtins/yaml/validate/main.k new file mode 100644 index 000000000..46a22fa05 --- /dev/null +++ b/test/grammar/builtins/yaml/validate/main.k @@ -0,0 +1,21 @@ +import yaml + +# Right cases + +resultRight1: bool = yaml.validate("1") +resultRight2: bool = yaml.validate("true") +resultRight3: bool = yaml.validate("1.20") +resultRight4: bool = yaml.validate("null") +resultRight5: bool = yaml.validate("[0, 1, 2]") +resultRight6: bool = yaml.validate('{"key": "value"}') +resultRight7: bool = yaml.validate('a:1\n---\nb:2') + +# Wrong cases + +resultWrong1: bool = yaml.validate("a:\n1") +resultWrong2: bool = yaml.validate("a:\n1\n - 2") +resultWrong3: bool = yaml.validate("a:\n-1") +resultWrong4: bool = yaml.validate("1a : \n1") +resultWrong5: bool = yaml.validate("a:\n- 1\n-----\na:\n- 1") +resultWrong6: bool = yaml.validate(r'''{"key" + 'value'}''') +resultWrong7: bool = yaml.validate("a:1\n-----\nb:\n-2") diff --git a/test/grammar/builtins/yaml/validate/stdout.golden b/test/grammar/builtins/yaml/validate/stdout.golden new file mode 100644 index 000000000..f8d846f47 --- /dev/null +++ b/test/grammar/builtins/yaml/validate/stdout.golden @@ -0,0 +1,14 @@ +resultRight1: true +resultRight2: true +resultRight3: true +resultRight4: true +resultRight5: true +resultRight6: true +resultRight7: true +resultWrong1: false +resultWrong2: false +resultWrong3: false +resultWrong4: false +resultWrong5: false +resultWrong6: false +resultWrong7: false diff --git a/test/grammar/cli_config/cli_config_3/kcl.yaml b/test/grammar/cli_config/cli_config_3/kcl.yaml new file mode 100644 index 000000000..9332e3d14 --- /dev/null +++ b/test/grammar/cli_config/cli_config_3/kcl.yaml @@ -0,0 +1,19 @@ +kcl_options: +- key: env-type + value: TEST +- key: deploy-topology + value: + - cluster: my-cluster + id: '000123' + idc: my-idc + is_dev: true + replicas: 2 + value: null + workspace: my-workspace + zone: my-zone +- key: labels + value: + app: app + env: env +- key: ports + value: [80, 8080] diff --git a/test/grammar/cli_config/cli_config_3/main.k b/test/grammar/cli_config/cli_config_3/main.k new file mode 100644 index 000000000..15c70d78f --- /dev/null +++ b/test/grammar/cli_config/cli_config_3/main.k @@ -0,0 +1,4 @@ +envType = option("env-type") +deployTopology = option("deploy-topology") +labels = option("labels") +ports = option("ports") diff --git a/test/grammar/cli_config/cli_config_3/settings.yaml b/test/grammar/cli_config/cli_config_3/settings.yaml new file mode 100644 index 000000000..69b753958 --- /dev/null +++ b/test/grammar/cli_config/cli_config_3/settings.yaml @@ -0,0 +1 @@ +kcl_options: -Y kcl.yaml diff --git a/test/grammar/cli_config/cli_config_3/stdout.golden b/test/grammar/cli_config/cli_config_3/stdout.golden new file mode 100644 index 000000000..c21abddba --- /dev/null +++ b/test/grammar/cli_config/cli_config_3/stdout.golden @@ -0,0 +1,16 @@ +envType: TEST +deployTopology: + - cluster: my-cluster + id: "000123" + idc: my-idc + is_dev: true + replicas: 2 + value: null + workspace: my-workspace + zone: my-zone +labels: + env: env + app: app +ports: + - 80 + - 8080 diff --git a/test/test_units/test_kclvm/test_types/kcl.mod b/test/grammar/cli_config/cli_config_with_kcl_mod_0/kcl.mod similarity index 100% rename from test/test_units/test_kclvm/test_types/kcl.mod rename to test/grammar/cli_config/cli_config_with_kcl_mod_0/kcl.mod diff --git a/test/grammar/cli_config/cli_config_with_kcl_mod_0/main.k b/test/grammar/cli_config/cli_config_with_kcl_mod_0/main.k new file mode 100644 index 000000000..a67860308 --- /dev/null +++ b/test/grammar/cli_config/cli_config_with_kcl_mod_0/main.k @@ -0,0 +1 @@ +b = 2 diff --git a/test/test_units/test_kclvm/test_compiler/test_vfs/test_data_bytecode_cache/main.k b/test/grammar/cli_config/cli_config_with_kcl_mod_0/pkg/pkg.k similarity index 100% rename from test/test_units/test_kclvm/test_compiler/test_vfs/test_data_bytecode_cache/main.k rename to test/grammar/cli_config/cli_config_with_kcl_mod_0/pkg/pkg.k diff --git a/test/grammar/cli_config/cli_config_with_kcl_mod_0/settings.yaml b/test/grammar/cli_config/cli_config_with_kcl_mod_0/settings.yaml new file mode 100644 index 000000000..964a7fd6a --- /dev/null +++ b/test/grammar/cli_config/cli_config_with_kcl_mod_0/settings.yaml @@ -0,0 +1 @@ +kcl_options: ${KCL_MOD}/pkg/pkg.k diff --git a/test/grammar/cli_config/cli_config_with_kcl_mod_0/stdout.golden b/test/grammar/cli_config/cli_config_with_kcl_mod_0/stdout.golden new file mode 100644 index 000000000..bcb5f26cd --- /dev/null +++ b/test/grammar/cli_config/cli_config_with_kcl_mod_0/stdout.golden @@ -0,0 +1,2 @@ +b: 2 +a: 1 diff --git a/test/grammar/cli_config/empty_cli_config/config.yaml b/test/grammar/cli_config/empty_cli_config/config.yaml index e69de29bb..425cea94f 100644 --- a/test/grammar/cli_config/empty_cli_config/config.yaml +++ b/test/grammar/cli_config/empty_cli_config/config.yaml @@ -0,0 +1 @@ +kcl_cli_configs: \ No newline at end of file diff --git a/test/grammar/comprehension/dict/invalid_loop_var_fail_0/stderr.golden b/test/grammar/comprehension/dict/invalid_loop_var_fail_0/stderr.golden new file mode 100644 index 000000000..4fa9db858 --- /dev/null +++ b/test/grammar/comprehension/dict/invalid_loop_var_fail_0/stderr.golden @@ -0,0 +1,6 @@ +error[E2L23]: CompileError + --> ${CWD}/main.k:2:23 + | +2 | dataLoop = [i for i, j, k in data] # error + | ^ the number of loop variables is 3, which can only be 1 or 2 + | \ No newline at end of file diff --git a/test/grammar/comprehension/dict/invalid_loop_var_fail_0/stderr.golden.py b/test/grammar/comprehension/dict/invalid_loop_var_fail_0/stderr.golden.py deleted file mode 100644 index 7b68df657..000000000 --- a/test/grammar/comprehension/dict/invalid_loop_var_fail_0/stderr.golden.py +++ /dev/null @@ -1,23 +0,0 @@ -import os -import sys - -import kclvm.kcl.error as kcl_error - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.CompileError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=2, - col_no=19, - end_col_no=26 - ) - ], - arg_msg="the number of loop variables is 3, which can only be 1 or 2" - ), - file=sys.stdout -) - diff --git a/test/grammar/comprehension/dict/invalid_loop_var_fail_1/stderr.golden b/test/grammar/comprehension/dict/invalid_loop_var_fail_1/stderr.golden new file mode 100644 index 000000000..782a440ae --- /dev/null +++ b/test/grammar/comprehension/dict/invalid_loop_var_fail_1/stderr.golden @@ -0,0 +1,36 @@ +error[E1001]: InvalidSyntax + --> ${CWD}/main.k:2:20 + | +2 | dataLoop = [i for i() in data] # error + | ^ expected one of ["in"] got ( + | +error[E1001]: InvalidSyntax + --> ${CWD}/main.k:2:21 + | +2 | dataLoop = [i for i() in data] # error + | ^ expected one of ["identifier", "literal", "(", "[", "{"] got ) + | +error[E1001]: InvalidSyntax + --> ${CWD}/main.k:2:21 + | +2 | dataLoop = [i for i() in data] # error + | ^ expected one of ["]"] got ) + | +error[E1001]: InvalidSyntax + --> ${CWD}/main.k:2:21 + | +2 | dataLoop = [i for i() in data] # error + | ^ unexpected token ')' + | +error[E1001]: InvalidSyntax + --> ${CWD}/main.k:2:30 + | +2 | dataLoop = [i for i() in data] # error + | ^ unexpected token ']' + | +error[E2L23]: CompileError + --> ${CWD}/main.k:2:23 + | +2 | dataLoop = [i for i() in data] # error + | ^ name 'in' is not defined, did you mean '["int"]'? + | \ No newline at end of file diff --git a/test/grammar/comprehension/dict/invalid_loop_var_fail_1/stderr.golden.py b/test/grammar/comprehension/dict/invalid_loop_var_fail_1/stderr.golden.py deleted file mode 100644 index 5beb56e27..000000000 --- a/test/grammar/comprehension/dict/invalid_loop_var_fail_1/stderr.golden.py +++ /dev/null @@ -1,22 +0,0 @@ -import os -import sys - -import kclvm.kcl.error as kcl_error - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.CompileError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=2, - col_no=19, - end_col_no=22 - ) - ], - arg_msg="loop variables can only be ordinary identifiers" - ), - file=sys.stdout -) diff --git a/test/grammar/comprehension/dict/invalid_loop_var_fail_2/stderr.golden b/test/grammar/comprehension/dict/invalid_loop_var_fail_2/stderr.golden new file mode 100644 index 000000000..c5ffa7e43 --- /dev/null +++ b/test/grammar/comprehension/dict/invalid_loop_var_fail_2/stderr.golden @@ -0,0 +1,6 @@ +error[E2L23]: CompileError + --> ${CWD}/main.k:2:19 + | +2 | dataLoop = [i for i.j.k in data] # error + | ^ loop variables can only be ordinary identifiers + | \ No newline at end of file diff --git a/test/grammar/comprehension/dict/invalid_loop_var_fail_2/stderr.golden.py b/test/grammar/comprehension/dict/invalid_loop_var_fail_2/stderr.golden.py deleted file mode 100644 index a28d6dd59..000000000 --- a/test/grammar/comprehension/dict/invalid_loop_var_fail_2/stderr.golden.py +++ /dev/null @@ -1,23 +0,0 @@ -import os -import sys - -import kclvm.kcl.error as kcl_error - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.CompileError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=2, - col_no=19, - end_col_no=24 - ) - ], - arg_msg="loop variables can only be ordinary identifiers" - ), - file=sys.stdout -) - diff --git a/test/grammar/comprehension/dict/local_var_as_key/main.k b/test/grammar/comprehension/dict/local_var_as_key/main.k new file mode 100644 index 000000000..1acf2c7a5 --- /dev/null +++ b/test/grammar/comprehension/dict/local_var_as_key/main.k @@ -0,0 +1,10 @@ +_data = { + "a": 'foo' + "b": 'bar' +} + +r0 = [{v = k} for k, v in _data] +r1 = [{k = v} for k, v in _data] +r2 = [{k.foo = v} for k, v in _data] +r3 = [[k] for k, v in _data] +r4 = [[k, v] for k, v in _data] diff --git a/test/grammar/comprehension/dict/local_var_as_key/stdout.golden b/test/grammar/comprehension/dict/local_var_as_key/stdout.golden new file mode 100644 index 000000000..0c16d7b0f --- /dev/null +++ b/test/grammar/comprehension/dict/local_var_as_key/stdout.golden @@ -0,0 +1,19 @@ +r0: +- foo: a +- bar: b +r1: +- a: foo +- b: bar +r2: +- a: + foo: foo +- b: + foo: bar +r3: +- - a +- - b +r4: +- - a + - foo +- - b + - bar diff --git a/test/grammar/comprehension/list/invalid_loop_var_fail_0/stderr.golden b/test/grammar/comprehension/list/invalid_loop_var_fail_0/stderr.golden new file mode 100644 index 000000000..4fa9db858 --- /dev/null +++ b/test/grammar/comprehension/list/invalid_loop_var_fail_0/stderr.golden @@ -0,0 +1,6 @@ +error[E2L23]: CompileError + --> ${CWD}/main.k:2:23 + | +2 | dataLoop = [i for i, j, k in data] # error + | ^ the number of loop variables is 3, which can only be 1 or 2 + | \ No newline at end of file diff --git a/test/grammar/comprehension/list/invalid_loop_var_fail_0/stderr.golden.py b/test/grammar/comprehension/list/invalid_loop_var_fail_0/stderr.golden.py deleted file mode 100644 index 1d99c291b..000000000 --- a/test/grammar/comprehension/list/invalid_loop_var_fail_0/stderr.golden.py +++ /dev/null @@ -1,22 +0,0 @@ -import os -import sys - -import kclvm.kcl.error as kcl_error - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.CompileError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=2, - col_no=19, - end_col_no=26 - ) - ], - arg_msg="the number of loop variables is 3, which can only be 1 or 2" - ), - file=sys.stdout -) diff --git a/test/grammar/comprehension/list/invalid_loop_var_fail_1/stderr.golden b/test/grammar/comprehension/list/invalid_loop_var_fail_1/stderr.golden new file mode 100644 index 000000000..c5ffa7e43 --- /dev/null +++ b/test/grammar/comprehension/list/invalid_loop_var_fail_1/stderr.golden @@ -0,0 +1,6 @@ +error[E2L23]: CompileError + --> ${CWD}/main.k:2:19 + | +2 | dataLoop = [i for i.j.k in data] # error + | ^ loop variables can only be ordinary identifiers + | \ No newline at end of file diff --git a/test/grammar/comprehension/list/invalid_loop_var_fail_1/stderr.golden.py b/test/grammar/comprehension/list/invalid_loop_var_fail_1/stderr.golden.py deleted file mode 100644 index a28d6dd59..000000000 --- a/test/grammar/comprehension/list/invalid_loop_var_fail_1/stderr.golden.py +++ /dev/null @@ -1,23 +0,0 @@ -import os -import sys - -import kclvm.kcl.error as kcl_error - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.CompileError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=2, - col_no=19, - end_col_no=24 - ) - ], - arg_msg="loop variables can only be ordinary identifiers" - ), - file=sys.stdout -) - diff --git a/test/grammar/comprehension/list/invalid_loop_var_fail_2/stderr.golden b/test/grammar/comprehension/list/invalid_loop_var_fail_2/stderr.golden new file mode 100644 index 000000000..782a440ae --- /dev/null +++ b/test/grammar/comprehension/list/invalid_loop_var_fail_2/stderr.golden @@ -0,0 +1,36 @@ +error[E1001]: InvalidSyntax + --> ${CWD}/main.k:2:20 + | +2 | dataLoop = [i for i() in data] # error + | ^ expected one of ["in"] got ( + | +error[E1001]: InvalidSyntax + --> ${CWD}/main.k:2:21 + | +2 | dataLoop = [i for i() in data] # error + | ^ expected one of ["identifier", "literal", "(", "[", "{"] got ) + | +error[E1001]: InvalidSyntax + --> ${CWD}/main.k:2:21 + | +2 | dataLoop = [i for i() in data] # error + | ^ expected one of ["]"] got ) + | +error[E1001]: InvalidSyntax + --> ${CWD}/main.k:2:21 + | +2 | dataLoop = [i for i() in data] # error + | ^ unexpected token ')' + | +error[E1001]: InvalidSyntax + --> ${CWD}/main.k:2:30 + | +2 | dataLoop = [i for i() in data] # error + | ^ unexpected token ']' + | +error[E2L23]: CompileError + --> ${CWD}/main.k:2:23 + | +2 | dataLoop = [i for i() in data] # error + | ^ name 'in' is not defined, did you mean '["int"]'? + | \ No newline at end of file diff --git a/test/grammar/comprehension/list/invalid_loop_var_fail_2/stderr.golden.py b/test/grammar/comprehension/list/invalid_loop_var_fail_2/stderr.golden.py deleted file mode 100644 index c18dc4559..000000000 --- a/test/grammar/comprehension/list/invalid_loop_var_fail_2/stderr.golden.py +++ /dev/null @@ -1,23 +0,0 @@ -import os -import sys - -import kclvm.kcl.error as kcl_error - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.CompileError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=2, - col_no=19, - end_col_no=22 - ) - ], - arg_msg="loop variables can only be ordinary identifiers" - ), - file=sys.stdout -) - diff --git a/test/grammar/comprehension/str/invalid_loop_var_fail_0/stderr.golden b/test/grammar/comprehension/str/invalid_loop_var_fail_0/stderr.golden new file mode 100644 index 000000000..72dadd0a2 --- /dev/null +++ b/test/grammar/comprehension/str/invalid_loop_var_fail_0/stderr.golden @@ -0,0 +1,6 @@ +error[E2L23]: CompileError + --> ${CWD}/main.k:2:23 + | +2 | dataLoop = [i for i, j, k in dataString] # error + | ^ the number of loop variables is 3, which can only be 1 or 2 + | \ No newline at end of file diff --git a/test/grammar/comprehension/str/invalid_loop_var_fail_0/stderr.golden.py b/test/grammar/comprehension/str/invalid_loop_var_fail_0/stderr.golden.py deleted file mode 100644 index 7b68df657..000000000 --- a/test/grammar/comprehension/str/invalid_loop_var_fail_0/stderr.golden.py +++ /dev/null @@ -1,23 +0,0 @@ -import os -import sys - -import kclvm.kcl.error as kcl_error - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.CompileError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=2, - col_no=19, - end_col_no=26 - ) - ], - arg_msg="the number of loop variables is 3, which can only be 1 or 2" - ), - file=sys.stdout -) - diff --git a/test/grammar/comprehension/str/invalid_loop_var_fail_1/stderr.golden b/test/grammar/comprehension/str/invalid_loop_var_fail_1/stderr.golden new file mode 100644 index 000000000..c5ffa7e43 --- /dev/null +++ b/test/grammar/comprehension/str/invalid_loop_var_fail_1/stderr.golden @@ -0,0 +1,6 @@ +error[E2L23]: CompileError + --> ${CWD}/main.k:2:19 + | +2 | dataLoop = [i for i.j.k in data] # error + | ^ loop variables can only be ordinary identifiers + | \ No newline at end of file diff --git a/test/grammar/comprehension/str/invalid_loop_var_fail_1/stderr.golden.py b/test/grammar/comprehension/str/invalid_loop_var_fail_1/stderr.golden.py deleted file mode 100644 index a28d6dd59..000000000 --- a/test/grammar/comprehension/str/invalid_loop_var_fail_1/stderr.golden.py +++ /dev/null @@ -1,23 +0,0 @@ -import os -import sys - -import kclvm.kcl.error as kcl_error - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.CompileError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=2, - col_no=19, - end_col_no=24 - ) - ], - arg_msg="loop variables can only be ordinary identifiers" - ), - file=sys.stdout -) - diff --git a/test/grammar/comprehension/str/invalid_loop_var_fail_2/stderr.golden b/test/grammar/comprehension/str/invalid_loop_var_fail_2/stderr.golden new file mode 100644 index 000000000..782a440ae --- /dev/null +++ b/test/grammar/comprehension/str/invalid_loop_var_fail_2/stderr.golden @@ -0,0 +1,36 @@ +error[E1001]: InvalidSyntax + --> ${CWD}/main.k:2:20 + | +2 | dataLoop = [i for i() in data] # error + | ^ expected one of ["in"] got ( + | +error[E1001]: InvalidSyntax + --> ${CWD}/main.k:2:21 + | +2 | dataLoop = [i for i() in data] # error + | ^ expected one of ["identifier", "literal", "(", "[", "{"] got ) + | +error[E1001]: InvalidSyntax + --> ${CWD}/main.k:2:21 + | +2 | dataLoop = [i for i() in data] # error + | ^ expected one of ["]"] got ) + | +error[E1001]: InvalidSyntax + --> ${CWD}/main.k:2:21 + | +2 | dataLoop = [i for i() in data] # error + | ^ unexpected token ')' + | +error[E1001]: InvalidSyntax + --> ${CWD}/main.k:2:30 + | +2 | dataLoop = [i for i() in data] # error + | ^ unexpected token ']' + | +error[E2L23]: CompileError + --> ${CWD}/main.k:2:23 + | +2 | dataLoop = [i for i() in data] # error + | ^ name 'in' is not defined, did you mean '["int"]'? + | \ No newline at end of file diff --git a/test/grammar/comprehension/str/invalid_loop_var_fail_2/stderr.golden.py b/test/grammar/comprehension/str/invalid_loop_var_fail_2/stderr.golden.py deleted file mode 100644 index 5beb56e27..000000000 --- a/test/grammar/comprehension/str/invalid_loop_var_fail_2/stderr.golden.py +++ /dev/null @@ -1,22 +0,0 @@ -import os -import sys - -import kclvm.kcl.error as kcl_error - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.CompileError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=2, - col_no=19, - end_col_no=22 - ) - ], - arg_msg="loop variables can only be ordinary identifiers" - ), - file=sys.stdout -) diff --git a/test/grammar/datatype/dict/if_item_10/main.k b/test/grammar/datatype/dict/if_item_10/main.k new file mode 100644 index 000000000..3d7073424 --- /dev/null +++ b/test/grammar/datatype/dict/if_item_10/main.k @@ -0,0 +1,6 @@ +a = 123 +b = 456 +data = { + **{key = "value1"} + if a == 123: if b == 456: key = "value2" +} diff --git a/test/grammar/datatype/dict/if_item_10/stdout.golden b/test/grammar/datatype/dict/if_item_10/stdout.golden new file mode 100644 index 000000000..41ace265d --- /dev/null +++ b/test/grammar/datatype/dict/if_item_10/stdout.golden @@ -0,0 +1,4 @@ +a: 123 +b: 456 +data: + key: value2 diff --git a/test/grammar/datatype/dict/if_item_11/main.k b/test/grammar/datatype/dict/if_item_11/main.k new file mode 100644 index 000000000..80c691b79 --- /dev/null +++ b/test/grammar/datatype/dict/if_item_11/main.k @@ -0,0 +1 @@ +data = {if True: key = "val"} diff --git a/test/grammar/datatype/dict/if_item_11/stdout.golden b/test/grammar/datatype/dict/if_item_11/stdout.golden new file mode 100644 index 000000000..77e8e7950 --- /dev/null +++ b/test/grammar/datatype/dict/if_item_11/stdout.golden @@ -0,0 +1,2 @@ +data: + key: val diff --git a/test/grammar/datatype/dict/indexing_in_comprehension_fail_0/stderr.golden b/test/grammar/datatype/dict/indexing_in_comprehension_fail_0/stderr.golden new file mode 100644 index 000000000..80c286409 --- /dev/null +++ b/test/grammar/datatype/dict/indexing_in_comprehension_fail_0/stderr.golden @@ -0,0 +1,6 @@ +error[E2A31]: IllegalAttributeError + --> ${CWD}/main.k:16:13 + | +16 | service: service["name"], + | ^ A attribute must be string type, got '{str:str}' + | \ No newline at end of file diff --git a/test/grammar/datatype/dict/indexing_in_comprehension_fail_0/stderr.golden.py b/test/grammar/datatype/dict/indexing_in_comprehension_fail_0/stderr.golden.py deleted file mode 100644 index f3131eb01..000000000 --- a/test/grammar/datatype/dict/indexing_in_comprehension_fail_0/stderr.golden.py +++ /dev/null @@ -1,20 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.IllegalAttributeError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=16, - col_no=13 - ) - ], - arg_msg="type '{str:str}'" - ) - , file=sys.stdout -) diff --git a/test/grammar/datatype/dict/merge_in_comprehension_0/main.k b/test/grammar/datatype/dict/merge_in_comprehension_0/main.k new file mode 100644 index 000000000..b530b1a12 --- /dev/null +++ b/test/grammar/datatype/dict/merge_in_comprehension_0/main.k @@ -0,0 +1,9 @@ +x = { + a = 1 + b = True +} +y = { + c = 3 + d = "4" +} +z = {"foo": i for i in [x, y]}.foo diff --git a/test/grammar/datatype/dict/merge_in_comprehension_0/stdout.golden b/test/grammar/datatype/dict/merge_in_comprehension_0/stdout.golden new file mode 100644 index 000000000..1dbbd0215 --- /dev/null +++ b/test/grammar/datatype/dict/merge_in_comprehension_0/stdout.golden @@ -0,0 +1,11 @@ +x: + a: 1 + b: true +y: + c: 3 + d: '4' +z: + a: 1 + b: true + c: 3 + d: '4' diff --git a/test/grammar/datatype/dict/merge_in_comprehension_1/main.k b/test/grammar/datatype/dict/merge_in_comprehension_1/main.k new file mode 100644 index 000000000..7e7906e93 --- /dev/null +++ b/test/grammar/datatype/dict/merge_in_comprehension_1/main.k @@ -0,0 +1,10 @@ +x = { + a = 1 + b = True +} +y = { + c = 3 + d = "4" +} +z1 = {**x, **y} +z2 = {"foo": {**i, a = 2, e = "five"} for i in [x, y]}.foo diff --git a/test/grammar/datatype/dict/merge_in_comprehension_1/stdout.golden b/test/grammar/datatype/dict/merge_in_comprehension_1/stdout.golden new file mode 100644 index 000000000..a5e406c8b --- /dev/null +++ b/test/grammar/datatype/dict/merge_in_comprehension_1/stdout.golden @@ -0,0 +1,17 @@ +x: + a: 1 + b: true +y: + c: 3 + d: '4' +z1: + a: 1 + b: true + c: 3 + d: '4' +z2: + a: 2 + b: true + e: five + c: 3 + d: '4' diff --git a/test/grammar/datatype/dict/mutual_ref_0/main.k b/test/grammar/datatype/dict/mutual_ref_0/main.k new file mode 100644 index 000000000..3af68c754 --- /dev/null +++ b/test/grammar/datatype/dict/mutual_ref_0/main.k @@ -0,0 +1,4 @@ +data = { + name = "release" + metadata.name = name +} diff --git a/test/grammar/datatype/dict/mutual_ref_0/stdout.golden b/test/grammar/datatype/dict/mutual_ref_0/stdout.golden new file mode 100644 index 000000000..f506238c8 --- /dev/null +++ b/test/grammar/datatype/dict/mutual_ref_0/stdout.golden @@ -0,0 +1,4 @@ +data: + name: release + metadata: + name: release diff --git a/test/grammar/datatype/dict/mutual_ref_1/main.k b/test/grammar/datatype/dict/mutual_ref_1/main.k new file mode 100644 index 000000000..bb8820f0b --- /dev/null +++ b/test/grammar/datatype/dict/mutual_ref_1/main.k @@ -0,0 +1,4 @@ +data = { + "name" = "release" + metadata.name = name +} diff --git a/test/grammar/datatype/dict/mutual_ref_1/stdout.golden b/test/grammar/datatype/dict/mutual_ref_1/stdout.golden new file mode 100644 index 000000000..f506238c8 --- /dev/null +++ b/test/grammar/datatype/dict/mutual_ref_1/stdout.golden @@ -0,0 +1,4 @@ +data: + name: release + metadata: + name: release diff --git a/test/grammar/datatype/dict/mutual_ref_10/main.k b/test/grammar/datatype/dict/mutual_ref_10/main.k new file mode 100644 index 000000000..67493a9fa --- /dev/null +++ b/test/grammar/datatype/dict/mutual_ref_10/main.k @@ -0,0 +1,6 @@ +_temp = 1 +data = { + _temp = 2 + temp = _temp +} +temp = _temp diff --git a/test/grammar/datatype/dict/mutual_ref_10/stdout.golden b/test/grammar/datatype/dict/mutual_ref_10/stdout.golden new file mode 100644 index 000000000..d70c4f058 --- /dev/null +++ b/test/grammar/datatype/dict/mutual_ref_10/stdout.golden @@ -0,0 +1,3 @@ +data: + temp: 2 +temp: 1 diff --git a/test/grammar/datatype/dict/mutual_ref_11/main.k b/test/grammar/datatype/dict/mutual_ref_11/main.k new file mode 100644 index 000000000..108c04d52 --- /dev/null +++ b/test/grammar/datatype/dict/mutual_ref_11/main.k @@ -0,0 +1,8 @@ +_temp = 1 +data = { + _temp = 2 + if True: + _temp = 3 + temp = _temp +} +temp = _temp diff --git a/test/grammar/datatype/dict/mutual_ref_11/stdout.golden b/test/grammar/datatype/dict/mutual_ref_11/stdout.golden new file mode 100644 index 000000000..3fe0dc8d9 --- /dev/null +++ b/test/grammar/datatype/dict/mutual_ref_11/stdout.golden @@ -0,0 +1,3 @@ +data: + temp: 3 +temp: 1 diff --git a/test/grammar/datatype/dict/mutual_ref_12/main.k b/test/grammar/datatype/dict/mutual_ref_12/main.k new file mode 100644 index 000000000..31392163d --- /dev/null +++ b/test/grammar/datatype/dict/mutual_ref_12/main.k @@ -0,0 +1,7 @@ +c = [ + container | { + volumeMounts = [ + {name = mount.name} for mount in [{"container" = "main", name = container + "Container"}] if mount.container == container.name + ] + } for container in [{"name" = "main"}] +] diff --git a/test/grammar/datatype/dict/mutual_ref_12/stdout.golden b/test/grammar/datatype/dict/mutual_ref_12/stdout.golden new file mode 100644 index 000000000..ad3e88b40 --- /dev/null +++ b/test/grammar/datatype/dict/mutual_ref_12/stdout.golden @@ -0,0 +1,4 @@ +c: +- name: main + volumeMounts: + - name: mainContainer diff --git a/test/grammar/datatype/dict/mutual_ref_13/main.k b/test/grammar/datatype/dict/mutual_ref_13/main.k new file mode 100644 index 000000000..78443307a --- /dev/null +++ b/test/grammar/datatype/dict/mutual_ref_13/main.k @@ -0,0 +1,17 @@ +schema Data: + id: int = 1 + +schema Config[data: Data]: + spec: {str:} = { + internal.data = data.id + id = data.id + } + +Func = lambda data: Data { + { + internal.data = data.id + id = data.id + } +} +spec = Func(Data()) +config = Config(Data()) diff --git a/test/grammar/datatype/dict/mutual_ref_13/stdout.golden b/test/grammar/datatype/dict/mutual_ref_13/stdout.golden new file mode 100644 index 000000000..b86aa87a8 --- /dev/null +++ b/test/grammar/datatype/dict/mutual_ref_13/stdout.golden @@ -0,0 +1,9 @@ +spec: + internal: + data: 1 + id: 1 +config: + spec: + internal: + data: 1 + id: 1 diff --git a/test/grammar/datatype/dict/mutual_ref_14/main.k b/test/grammar/datatype/dict/mutual_ref_14/main.k new file mode 100644 index 000000000..4b94a8d26 --- /dev/null +++ b/test/grammar/datatype/dict/mutual_ref_14/main.k @@ -0,0 +1,6 @@ +deployment = { + metadata.labels.k1 = "v1" + metadata.namespace = "default" + spec.selector.matchLabels = metadata.labels | {k2 = "v2"} +} +labels: {str:str} = deployment.metadata.labels diff --git a/test/grammar/datatype/dict/mutual_ref_14/stdout.golden b/test/grammar/datatype/dict/mutual_ref_14/stdout.golden new file mode 100644 index 000000000..30497ce0c --- /dev/null +++ b/test/grammar/datatype/dict/mutual_ref_14/stdout.golden @@ -0,0 +1,12 @@ +deployment: + metadata: + labels: + k1: v1 + namespace: default + spec: + selector: + matchLabels: + k1: v1 + k2: v2 +labels: + k1: v1 diff --git a/test/grammar/datatype/dict/mutual_ref_15/main.k b/test/grammar/datatype/dict/mutual_ref_15/main.k new file mode 100644 index 000000000..88cbe423e --- /dev/null +++ b/test/grammar/datatype/dict/mutual_ref_15/main.k @@ -0,0 +1,24 @@ +render = lambda { + a = { + foo: "bar" + } + b = { + foo2: "bar2" + a: { + b: "c" + } + } + c = [a, b] +} + +out = render() +a = { + foo: "bar" +} +b = { + foo2: "bar2" + a: { + b: "c" + } +} +c = [a, b] diff --git a/test/grammar/datatype/dict/mutual_ref_15/stdout.golden b/test/grammar/datatype/dict/mutual_ref_15/stdout.golden new file mode 100644 index 000000000..565be56aa --- /dev/null +++ b/test/grammar/datatype/dict/mutual_ref_15/stdout.golden @@ -0,0 +1,16 @@ +out: +- foo: bar +- foo2: bar2 + a: + b: c +a: + foo: bar +b: + foo2: bar2 + a: + b: c +c: +- foo: bar +- foo2: bar2 + a: + b: c diff --git a/test/grammar/datatype/dict/mutual_ref_16/main.k b/test/grammar/datatype/dict/mutual_ref_16/main.k new file mode 100644 index 000000000..39766bd7d --- /dev/null +++ b/test/grammar/datatype/dict/mutual_ref_16/main.k @@ -0,0 +1,9 @@ +level0 = { + name = "apple" + level1_a = { + name = "orange" + } + level1_b = { + name = "pine" + name + } +} diff --git a/test/grammar/datatype/dict/mutual_ref_16/stdout.golden b/test/grammar/datatype/dict/mutual_ref_16/stdout.golden new file mode 100644 index 000000000..25dbfa79d --- /dev/null +++ b/test/grammar/datatype/dict/mutual_ref_16/stdout.golden @@ -0,0 +1,6 @@ +level0: + name: apple + level1_a: + name: orange + level1_b: + name: pineapple diff --git a/test/grammar/datatype/dict/mutual_ref_2/main.k b/test/grammar/datatype/dict/mutual_ref_2/main.k new file mode 100644 index 000000000..d020f81ed --- /dev/null +++ b/test/grammar/datatype/dict/mutual_ref_2/main.k @@ -0,0 +1,5 @@ +data = { + name = "release" + metadata.name = name + spec.template.metadata.name = name +} diff --git a/test/grammar/datatype/dict/mutual_ref_2/stdout.golden b/test/grammar/datatype/dict/mutual_ref_2/stdout.golden new file mode 100644 index 000000000..d052e1641 --- /dev/null +++ b/test/grammar/datatype/dict/mutual_ref_2/stdout.golden @@ -0,0 +1,8 @@ +data: + name: release + metadata: + name: release + spec: + template: + metadata: + name: release diff --git a/test/grammar/datatype/dict/mutual_ref_3/main.k b/test/grammar/datatype/dict/mutual_ref_3/main.k new file mode 100644 index 000000000..8cf30cf92 --- /dev/null +++ b/test/grammar/datatype/dict/mutual_ref_3/main.k @@ -0,0 +1,13 @@ +name = "global-release-name" +data = { + name = "data-release" + metadata.name = name + spec.template.metadata.name = metadata.name +} +metadata = { + name = "metadata-release-name" + labels = { + "app.kubernetes.io/name" = name + "app.kubernetes.io/instance" = name + } +} diff --git a/test/grammar/datatype/dict/mutual_ref_3/stdout.golden b/test/grammar/datatype/dict/mutual_ref_3/stdout.golden new file mode 100644 index 000000000..41d6da07f --- /dev/null +++ b/test/grammar/datatype/dict/mutual_ref_3/stdout.golden @@ -0,0 +1,14 @@ +name: global-release-name +data: + name: data-release + metadata: + name: data-release + spec: + template: + metadata: + name: data-release +metadata: + name: metadata-release-name + labels: + app.kubernetes.io/name: metadata-release-name + app.kubernetes.io/instance: metadata-release-name diff --git a/test/grammar/datatype/dict/mutual_ref_4/main.k b/test/grammar/datatype/dict/mutual_ref_4/main.k new file mode 100644 index 000000000..eede79cc3 --- /dev/null +++ b/test/grammar/datatype/dict/mutual_ref_4/main.k @@ -0,0 +1,10 @@ +schema Data: + name: str + metadata: {str:} + spec: {str:} + +data = Data { + name = "release" + metadata.name = name + spec.template.metadata.name = metadata.name +} diff --git a/test/grammar/datatype/dict/mutual_ref_4/stdout.golden b/test/grammar/datatype/dict/mutual_ref_4/stdout.golden new file mode 100644 index 000000000..d052e1641 --- /dev/null +++ b/test/grammar/datatype/dict/mutual_ref_4/stdout.golden @@ -0,0 +1,8 @@ +data: + name: release + metadata: + name: release + spec: + template: + metadata: + name: release diff --git a/test/grammar/datatype/dict/mutual_ref_5/main.k b/test/grammar/datatype/dict/mutual_ref_5/main.k new file mode 100644 index 000000000..58ade347e --- /dev/null +++ b/test/grammar/datatype/dict/mutual_ref_5/main.k @@ -0,0 +1,7 @@ +isProdEnv = True +data = { + env = "dev" + if isProdEnv: + env = "prod" + metadata.env = env +} diff --git a/test/grammar/datatype/dict/mutual_ref_5/stdout.golden b/test/grammar/datatype/dict/mutual_ref_5/stdout.golden new file mode 100644 index 000000000..03f4b3c76 --- /dev/null +++ b/test/grammar/datatype/dict/mutual_ref_5/stdout.golden @@ -0,0 +1,5 @@ +isProdEnv: true +data: + env: prod + metadata: + env: prod diff --git a/test/grammar/datatype/dict/mutual_ref_6/main.k b/test/grammar/datatype/dict/mutual_ref_6/main.k new file mode 100644 index 000000000..7cb596d67 --- /dev/null +++ b/test/grammar/datatype/dict/mutual_ref_6/main.k @@ -0,0 +1,9 @@ +isProdEnv = False +data = { + env = "dev" + if isProdEnv: + env = "prod" + else: + env = "staging" + metadata.env = env +} diff --git a/test/grammar/datatype/dict/mutual_ref_6/stdout.golden b/test/grammar/datatype/dict/mutual_ref_6/stdout.golden new file mode 100644 index 000000000..dd56a09fb --- /dev/null +++ b/test/grammar/datatype/dict/mutual_ref_6/stdout.golden @@ -0,0 +1,5 @@ +isProdEnv: false +data: + env: staging + metadata: + env: staging diff --git a/test/grammar/datatype/dict/mutual_ref_7/main.k b/test/grammar/datatype/dict/mutual_ref_7/main.k new file mode 100644 index 000000000..36e619f7f --- /dev/null +++ b/test/grammar/datatype/dict/mutual_ref_7/main.k @@ -0,0 +1,11 @@ +isProdEnv = True +data = { + env = "dev" + if False: + env = "test" + elif isProdEnv: + env = "prod" + else: + env = "staging" + metadata.env = env +} diff --git a/test/grammar/datatype/dict/mutual_ref_7/stdout.golden b/test/grammar/datatype/dict/mutual_ref_7/stdout.golden new file mode 100644 index 000000000..03f4b3c76 --- /dev/null +++ b/test/grammar/datatype/dict/mutual_ref_7/stdout.golden @@ -0,0 +1,5 @@ +isProdEnv: true +data: + env: prod + metadata: + env: prod diff --git a/test/grammar/datatype/dict/mutual_ref_8/main.k b/test/grammar/datatype/dict/mutual_ref_8/main.k new file mode 100644 index 000000000..a306bd29e --- /dev/null +++ b/test/grammar/datatype/dict/mutual_ref_8/main.k @@ -0,0 +1,8 @@ +isProdEnv = True +data = { + env = "dev" + if isProdEnv: + if isProdEnv: + env = "prod" + metadata.env = env +} diff --git a/test/grammar/datatype/dict/mutual_ref_8/stdout.golden b/test/grammar/datatype/dict/mutual_ref_8/stdout.golden new file mode 100644 index 000000000..03f4b3c76 --- /dev/null +++ b/test/grammar/datatype/dict/mutual_ref_8/stdout.golden @@ -0,0 +1,5 @@ +isProdEnv: true +data: + env: prod + metadata: + env: prod diff --git a/test/grammar/datatype/dict/mutual_ref_9/main.k b/test/grammar/datatype/dict/mutual_ref_9/main.k new file mode 100644 index 000000000..a94c5c300 --- /dev/null +++ b/test/grammar/datatype/dict/mutual_ref_9/main.k @@ -0,0 +1,11 @@ +isProdEnv = False +data = { + env = "dev" + if isProdEnv: + if isProdEnv: + env = "prod" + else: + env = "staging" + staging = True + metadata.env = env +} diff --git a/test/grammar/datatype/dict/mutual_ref_9/stdout.golden b/test/grammar/datatype/dict/mutual_ref_9/stdout.golden new file mode 100644 index 000000000..45db2f2c5 --- /dev/null +++ b/test/grammar/datatype/dict/mutual_ref_9/stdout.golden @@ -0,0 +1,6 @@ +isProdEnv: false +data: + env: staging + staging: true + metadata: + env: staging diff --git a/test/grammar/datatype/list/add_None_fail/stderr.golden b/test/grammar/datatype/list/add_None_fail/stderr.golden new file mode 100644 index 000000000..6d8905799 --- /dev/null +++ b/test/grammar/datatype/list/add_None_fail/stderr.golden @@ -0,0 +1,6 @@ +error[E3M38]: EvaluationError + --> ${CWD}/main.k:4:1 + | +4 | result2 = _list1 + _list2 + | can only concatenate list (not "NoneType") to list + | \ No newline at end of file diff --git a/test/grammar/datatype/list/add_None_fail/stderr.golden.py b/test/grammar/datatype/list/add_None_fail/stderr.golden.py deleted file mode 100644 index 7a0bbd6e7..000000000 --- a/test/grammar/datatype/list/add_None_fail/stderr.golden.py +++ /dev/null @@ -1,20 +0,0 @@ -import os -import sys - -import kclvm.kcl.error as kcl_error - -cwd = os.path.dirname(os.path.realpath(__file__)) -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.EvaluationError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=4 - ) - ], - arg_msg="can only concatenate list (not \"NoneType\") to list" - ) - , file=sys.stdout -) - diff --git a/test/grammar/datatype/list/if_item_8/main.k b/test/grammar/datatype/list/if_item_8/main.k new file mode 100644 index 000000000..c246b3fb6 --- /dev/null +++ b/test/grammar/datatype/list/if_item_8/main.k @@ -0,0 +1,24 @@ +data0: [int] = [ + if False: + *[0] + else: + 1 + 2 +] +data1: [int] = [ + if False: + *[0] + elif False: + *[1] + else: + *[2] +] +data2: [int] = [ + if False: + *[0] + else: + if False: + *[1] + else: + *[2] +] diff --git a/test/grammar/datatype/list/if_item_8/stdout.golden b/test/grammar/datatype/list/if_item_8/stdout.golden new file mode 100644 index 000000000..a19dc0a68 --- /dev/null +++ b/test/grammar/datatype/list/if_item_8/stdout.golden @@ -0,0 +1,7 @@ +data0: +- 1 +- 2 +data1: +- 2 +data2: +- 2 diff --git a/test/grammar/datatype/range_check_float/normal/stdout.golden b/test/grammar/datatype/range_check_float/normal/stdout.golden index b837978ec..f7e047949 100644 --- a/test/grammar/datatype/range_check_float/normal/stdout.golden +++ b/test/grammar/datatype/range_check_float/normal/stdout.golden @@ -2,4 +2,4 @@ downlimit: 1.175494351e-10 uplimit: 34028234660.0 epsilon: 0.2220446049250313 a: 27845329477.222748 -b: 1.436506529759401e-10 +b: 1.4365065297594008e-10 diff --git a/test/grammar/datatype/range_check_float/overflow/inf/stderr.golden b/test/grammar/datatype/range_check_float/overflow/inf/stderr.golden new file mode 100644 index 000000000..2e5cb5f60 --- /dev/null +++ b/test/grammar/datatype/range_check_float/overflow/inf/stderr.golden @@ -0,0 +1 @@ +inf: A 64-bit floating point number overflow \ No newline at end of file diff --git a/test/grammar/datatype/range_check_float/overflow/inf/stderr.golden.py b/test/grammar/datatype/range_check_float/overflow/inf/stderr.golden.py deleted file mode 100644 index 1234c318c..000000000 --- a/test/grammar/datatype/range_check_float/overflow/inf/stderr.golden.py +++ /dev/null @@ -1,20 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.FloatOverflow_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=6 - ) - ], - arg_msg=kcl_error.FLOAT_OVER_FLOW_MSG.format("inf", 64) - ) - , file=sys.stdout -) - diff --git a/test/grammar/datatype/range_check_float/overflow/number_0/stderr.golden b/test/grammar/datatype/range_check_float/overflow/number_0/stderr.golden new file mode 100644 index 000000000..4e89012b0 --- /dev/null +++ b/test/grammar/datatype/range_check_float/overflow/number_0/stderr.golden @@ -0,0 +1,9 @@ +error[E3M38]: EvaluationError + --> ${CWD}/main.k:8:1 + | +8 | a = uplimit * (100 + epsilon) + | 3.4e+40: A 32-bit floating point number overflow + | +note: backtrace: + 0: kclvm_main + at ${CWD}/main.k:8 \ No newline at end of file diff --git a/test/grammar/datatype/range_check_float/overflow/number_0/stderr.golden.py b/test/grammar/datatype/range_check_float/overflow/number_0/stderr.golden.py deleted file mode 100644 index ebb3e5553..000000000 --- a/test/grammar/datatype/range_check_float/overflow/number_0/stderr.golden.py +++ /dev/null @@ -1,20 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.FloatOverflow_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=8 - ) - ], - arg_msg=kcl_error.FLOAT_OVER_FLOW_MSG.format(3.4e+40, 32) - ) - , file=sys.stdout -) - diff --git a/test/grammar/datatype/range_check_float/overflow/number_1/stdout.golden b/test/grammar/datatype/range_check_float/overflow/number_1/stdout.golden index 03bf70e7b..6e31cb9ad 100644 --- a/test/grammar/datatype/range_check_float/overflow/number_1/stdout.golden +++ b/test/grammar/datatype/range_check_float/overflow/number_1/stdout.golden @@ -1,5 +1,5 @@ downlimit: 1.175494351e-38 -uplimit: 3.4e+38 +uplimit: 3.4e38 epsilon: 2.22e-16 -a: 3.4e+40 -b: 1.175494351e-36 +a: 3.4e40 +b: 1.1754943510000001e-36 diff --git a/test/grammar/datatype/range_check_float/underflow/number_0/stderr.golden b/test/grammar/datatype/range_check_float/underflow/number_0/stderr.golden new file mode 100644 index 000000000..d3d895dbe --- /dev/null +++ b/test/grammar/datatype/range_check_float/underflow/number_0/stderr.golden @@ -0,0 +1 @@ +1.1754943509999997e-38: A 32-bit floating point number underflow diff --git a/test/grammar/datatype/range_check_float/underflow/number_0/stderr.golden.py b/test/grammar/datatype/range_check_float/underflow/number_0/stderr.golden.py deleted file mode 100644 index 0b31d3b1d..000000000 --- a/test/grammar/datatype/range_check_float/underflow/number_0/stderr.golden.py +++ /dev/null @@ -1,19 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_warning_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.FloatUnderflow_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=7 - ) - ], - arg_msg=kcl_error.FLOAT_UNDER_FLOW_MSG.format(1.1754943509999997e-38, 32) - ) - , file=sys.stdout -) diff --git a/test/grammar/datatype/range_check_int/augment_assign_fail_0/stderr.golden b/test/grammar/datatype/range_check_int/augment_assign_fail_0/stderr.golden new file mode 100644 index 000000000..597779eb5 --- /dev/null +++ b/test/grammar/datatype/range_check_int/augment_assign_fail_0/stderr.golden @@ -0,0 +1,9 @@ +error[E3M38]: EvaluationError + --> ${CWD}/main.k:2:1 + | +2 | _a += 1 + | 2147483648: A 32 bit integer overflow + | +note: backtrace: + 0: kclvm_main + at ${CWD}/main.k:2 \ No newline at end of file diff --git a/test/grammar/datatype/range_check_int/augment_assign_fail_0/stderr.golden.py b/test/grammar/datatype/range_check_int/augment_assign_fail_0/stderr.golden.py deleted file mode 100644 index 225e2ee6b..000000000 --- a/test/grammar/datatype/range_check_int/augment_assign_fail_0/stderr.golden.py +++ /dev/null @@ -1,19 +0,0 @@ - -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception(err_type=kcl_error.ErrType.IntOverflow_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=2 - ), - ], - arg_msg=kcl_error.INT_OVER_FLOW_MSG.format(2147483648, 32)) - , file=sys.stdout -) - diff --git a/test/grammar/datatype/range_check_int/augment_assign_fail_1/stderr.golden b/test/grammar/datatype/range_check_int/augment_assign_fail_1/stderr.golden new file mode 100644 index 000000000..3af756538 --- /dev/null +++ b/test/grammar/datatype/range_check_int/augment_assign_fail_1/stderr.golden @@ -0,0 +1,9 @@ +error[E3M38]: EvaluationError + --> ${CWD}/main.k:2:1 + | +2 | _a += 1 + | 9223372036854775808: A 64 bit integer overflow + | +note: backtrace: + 0: kclvm_main + at ${CWD}/main.k:2 \ No newline at end of file diff --git a/test/grammar/datatype/range_check_int/augment_assign_fail_1/stderr.golden.py b/test/grammar/datatype/range_check_int/augment_assign_fail_1/stderr.golden.py deleted file mode 100644 index bafe89e16..000000000 --- a/test/grammar/datatype/range_check_int/augment_assign_fail_1/stderr.golden.py +++ /dev/null @@ -1,21 +0,0 @@ - -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.IntOverflow_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=2 - ) - ], - arg_msg=kcl_error.INT_OVER_FLOW_MSG.format(9223372036854775808, 64) - ) - , file=sys.stdout -) - diff --git a/test/grammar/datatype/range_check_int/augment_assign_fail_2/stderr.golden b/test/grammar/datatype/range_check_int/augment_assign_fail_2/stderr.golden new file mode 100644 index 000000000..3af756538 --- /dev/null +++ b/test/grammar/datatype/range_check_int/augment_assign_fail_2/stderr.golden @@ -0,0 +1,9 @@ +error[E3M38]: EvaluationError + --> ${CWD}/main.k:2:1 + | +2 | _a += 1 + | 9223372036854775808: A 64 bit integer overflow + | +note: backtrace: + 0: kclvm_main + at ${CWD}/main.k:2 \ No newline at end of file diff --git a/test/grammar/datatype/range_check_int/augment_assign_fail_2/stderr.golden.py b/test/grammar/datatype/range_check_int/augment_assign_fail_2/stderr.golden.py deleted file mode 100644 index bafe89e16..000000000 --- a/test/grammar/datatype/range_check_int/augment_assign_fail_2/stderr.golden.py +++ /dev/null @@ -1,21 +0,0 @@ - -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.IntOverflow_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=2 - ) - ], - arg_msg=kcl_error.INT_OVER_FLOW_MSG.format(9223372036854775808, 64) - ) - , file=sys.stdout -) - diff --git a/test/grammar/datatype/range_check_int/augment_assign_fail_3/stderr.golden b/test/grammar/datatype/range_check_int/augment_assign_fail_3/stderr.golden new file mode 100644 index 000000000..597779eb5 --- /dev/null +++ b/test/grammar/datatype/range_check_int/augment_assign_fail_3/stderr.golden @@ -0,0 +1,9 @@ +error[E3M38]: EvaluationError + --> ${CWD}/main.k:2:1 + | +2 | _a += 1 + | 2147483648: A 32 bit integer overflow + | +note: backtrace: + 0: kclvm_main + at ${CWD}/main.k:2 \ No newline at end of file diff --git a/test/grammar/datatype/range_check_int/augment_assign_fail_3/stderr.golden.py b/test/grammar/datatype/range_check_int/augment_assign_fail_3/stderr.golden.py deleted file mode 100644 index 15e8b3254..000000000 --- a/test/grammar/datatype/range_check_int/augment_assign_fail_3/stderr.golden.py +++ /dev/null @@ -1,21 +0,0 @@ - -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.IntOverflow_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=2 - ) - ], - arg_msg=kcl_error.INT_OVER_FLOW_MSG.format(2147483648, 32) - ) - , file=sys.stdout -) - diff --git a/test/grammar/datatype/range_check_int/augment_assign_fail_4/stderr.golden b/test/grammar/datatype/range_check_int/augment_assign_fail_4/stderr.golden new file mode 100644 index 000000000..b8f210907 --- /dev/null +++ b/test/grammar/datatype/range_check_int/augment_assign_fail_4/stderr.golden @@ -0,0 +1,12 @@ +error[E1001]: ImmutableError + --> ${CWD}/main.k:2:1 + | +2 | a += 1 + | ^ Immutable variable 'a' is modified during compiling + | + --> ${CWD}/main.k:1:1 + | +1 | a = 2147483646 + | ^ The variable 'a' is declared here firstly + | +note: change the variable name to '_a' to make it mutable \ No newline at end of file diff --git a/test/grammar/datatype/range_check_int/augment_assign_fail_4/stderr.golden.py b/test/grammar/datatype/range_check_int/augment_assign_fail_4/stderr.golden.py deleted file mode 100644 index f291e2f54..000000000 --- a/test/grammar/datatype/range_check_int/augment_assign_fail_4/stderr.golden.py +++ /dev/null @@ -1,20 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.ImmutableCompileError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=2, - col_no=1 - ) - ], - ) - , file=sys.stdout -) - diff --git a/test/grammar/datatype/range_check_int/dict_fail_0/main.k b/test/grammar/datatype/range_check_int/dict_fail_0/main.k deleted file mode 100644 index cd5bbd2a3..000000000 --- a/test/grammar/datatype/range_check_int/dict_fail_0/main.k +++ /dev/null @@ -1 +0,0 @@ -a = {"key": 2147483648} diff --git a/test/grammar/datatype/range_check_int/dict_fail_0/settings.yaml b/test/grammar/datatype/range_check_int/dict_fail_0/settings.yaml deleted file mode 100644 index 5fae1f7de..000000000 --- a/test/grammar/datatype/range_check_int/dict_fail_0/settings.yaml +++ /dev/null @@ -1 +0,0 @@ -kcl_options: -r -d diff --git a/test/grammar/datatype/range_check_int/dict_fail_0/stderr.golden.py b/test/grammar/datatype/range_check_int/dict_fail_0/stderr.golden.py deleted file mode 100644 index 8643f7a62..000000000 --- a/test/grammar/datatype/range_check_int/dict_fail_0/stderr.golden.py +++ /dev/null @@ -1,20 +0,0 @@ - -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.IntOverflow_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=1 - ) - ], - arg_msg=kcl_error.INT_OVER_FLOW_MSG.format(2147483648, 32) - ) - , file=sys.stdout -) diff --git a/test/grammar/datatype/range_check_int/dict_fail_1/main.k b/test/grammar/datatype/range_check_int/dict_fail_1/main.k deleted file mode 100644 index c216d620d..000000000 --- a/test/grammar/datatype/range_check_int/dict_fail_1/main.k +++ /dev/null @@ -1 +0,0 @@ -a = {"key": 9223372036854775808} diff --git a/test/grammar/datatype/range_check_int/dict_fail_1/settings.yaml b/test/grammar/datatype/range_check_int/dict_fail_1/settings.yaml deleted file mode 100644 index 542d01cf5..000000000 --- a/test/grammar/datatype/range_check_int/dict_fail_1/settings.yaml +++ /dev/null @@ -1 +0,0 @@ -kcl_options: -d diff --git a/test/grammar/datatype/range_check_int/dict_fail_1/stderr.golden.py b/test/grammar/datatype/range_check_int/dict_fail_1/stderr.golden.py deleted file mode 100644 index 877df4f8a..000000000 --- a/test/grammar/datatype/range_check_int/dict_fail_1/stderr.golden.py +++ /dev/null @@ -1,19 +0,0 @@ - -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception(err_type=kcl_error.ErrType.IntOverflow_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=1 - ), - ], - arg_msg=kcl_error.INT_OVER_FLOW_MSG.format(9223372036854775808, 64)) - , file=sys.stdout -) - diff --git a/test/grammar/datatype/range_check_int/list_fail_0/main.k b/test/grammar/datatype/range_check_int/list_fail_0/main.k deleted file mode 100644 index d2f87881d..000000000 --- a/test/grammar/datatype/range_check_int/list_fail_0/main.k +++ /dev/null @@ -1 +0,0 @@ -myList = [1, 2, 3, 2147483648] diff --git a/test/grammar/datatype/range_check_int/list_fail_0/settings.yaml b/test/grammar/datatype/range_check_int/list_fail_0/settings.yaml deleted file mode 100644 index 5fae1f7de..000000000 --- a/test/grammar/datatype/range_check_int/list_fail_0/settings.yaml +++ /dev/null @@ -1 +0,0 @@ -kcl_options: -r -d diff --git a/test/grammar/datatype/range_check_int/list_fail_0/stderr.golden.py b/test/grammar/datatype/range_check_int/list_fail_0/stderr.golden.py deleted file mode 100644 index 602e555a9..000000000 --- a/test/grammar/datatype/range_check_int/list_fail_0/stderr.golden.py +++ /dev/null @@ -1,18 +0,0 @@ - -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception(err_type=kcl_error.ErrType.IntOverflow_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=1 - ), - ], - arg_msg=kcl_error.INT_OVER_FLOW_MSG.format(2147483648, 32)) - , file=sys.stdout -) diff --git a/test/grammar/datatype/range_check_int/list_fail_1/main.k b/test/grammar/datatype/range_check_int/list_fail_1/main.k deleted file mode 100644 index 116e4937c..000000000 --- a/test/grammar/datatype/range_check_int/list_fail_1/main.k +++ /dev/null @@ -1 +0,0 @@ -myList = [1, 2, 3, 9223372036854775808] diff --git a/test/grammar/datatype/range_check_int/list_fail_1/settings.yaml b/test/grammar/datatype/range_check_int/list_fail_1/settings.yaml deleted file mode 100644 index 542d01cf5..000000000 --- a/test/grammar/datatype/range_check_int/list_fail_1/settings.yaml +++ /dev/null @@ -1 +0,0 @@ -kcl_options: -d diff --git a/test/grammar/datatype/range_check_int/list_fail_1/stderr.golden.py b/test/grammar/datatype/range_check_int/list_fail_1/stderr.golden.py deleted file mode 100644 index 877df4f8a..000000000 --- a/test/grammar/datatype/range_check_int/list_fail_1/stderr.golden.py +++ /dev/null @@ -1,19 +0,0 @@ - -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception(err_type=kcl_error.ErrType.IntOverflow_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=1 - ), - ], - arg_msg=kcl_error.INT_OVER_FLOW_MSG.format(9223372036854775808, 64)) - , file=sys.stdout -) - diff --git a/test/grammar/datatype/range_check_int/normal_assign_fail_0/main.k b/test/grammar/datatype/range_check_int/normal_assign_fail_0/main.k index 0dc548955..34126bed6 100644 --- a/test/grammar/datatype/range_check_int/normal_assign_fail_0/main.k +++ b/test/grammar/datatype/range_check_int/normal_assign_fail_0/main.k @@ -1 +1 @@ -a = 2147483648 +a = 2147483648 + 1 diff --git a/test/grammar/datatype/range_check_int/normal_assign_fail_0/stderr.golden b/test/grammar/datatype/range_check_int/normal_assign_fail_0/stderr.golden new file mode 100644 index 000000000..92f92a94a --- /dev/null +++ b/test/grammar/datatype/range_check_int/normal_assign_fail_0/stderr.golden @@ -0,0 +1 @@ +2147483649: A 32 bit integer overflow \ No newline at end of file diff --git a/test/grammar/datatype/range_check_int/normal_assign_fail_0/stderr.golden.py b/test/grammar/datatype/range_check_int/normal_assign_fail_0/stderr.golden.py deleted file mode 100644 index b52d322b3..000000000 --- a/test/grammar/datatype/range_check_int/normal_assign_fail_0/stderr.golden.py +++ /dev/null @@ -1,19 +0,0 @@ - -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception(err_type=kcl_error.ErrType.IntOverflow_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=1 - ), - ], - arg_msg=kcl_error.INT_OVER_FLOW_MSG.format(2147483648, 32)) - , file=sys.stdout -) - diff --git a/test/grammar/datatype/range_check_int/normal_assign_fail_1/main.k b/test/grammar/datatype/range_check_int/normal_assign_fail_1/main.k deleted file mode 100644 index d12c93eb4..000000000 --- a/test/grammar/datatype/range_check_int/normal_assign_fail_1/main.k +++ /dev/null @@ -1 +0,0 @@ -a = 9223372036854775808 diff --git a/test/grammar/datatype/range_check_int/normal_assign_fail_1/settings.yaml b/test/grammar/datatype/range_check_int/normal_assign_fail_1/settings.yaml deleted file mode 100644 index 542d01cf5..000000000 --- a/test/grammar/datatype/range_check_int/normal_assign_fail_1/settings.yaml +++ /dev/null @@ -1 +0,0 @@ -kcl_options: -d diff --git a/test/grammar/datatype/range_check_int/normal_assign_fail_1/stderr.golden.py b/test/grammar/datatype/range_check_int/normal_assign_fail_1/stderr.golden.py deleted file mode 100644 index 877df4f8a..000000000 --- a/test/grammar/datatype/range_check_int/normal_assign_fail_1/stderr.golden.py +++ /dev/null @@ -1,19 +0,0 @@ - -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception(err_type=kcl_error.ErrType.IntOverflow_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=1 - ), - ], - arg_msg=kcl_error.INT_OVER_FLOW_MSG.format(9223372036854775808, 64)) - , file=sys.stdout -) - diff --git a/test/grammar/datatype/range_check_int/oneliner_fail_0/main.k b/test/grammar/datatype/range_check_int/oneliner_fail_0/main.k deleted file mode 100644 index ef1b82d52..000000000 --- a/test/grammar/datatype/range_check_int/oneliner_fail_0/main.k +++ /dev/null @@ -1,2 +0,0 @@ -a = 1 -c = +2147483648 diff --git a/test/grammar/datatype/range_check_int/oneliner_fail_0/settings.yaml b/test/grammar/datatype/range_check_int/oneliner_fail_0/settings.yaml deleted file mode 100644 index d4fd18f4b..000000000 --- a/test/grammar/datatype/range_check_int/oneliner_fail_0/settings.yaml +++ /dev/null @@ -1 +0,0 @@ -kcl_options: -r -d diff --git a/test/grammar/datatype/range_check_int/oneliner_fail_0/stderr.golden.py b/test/grammar/datatype/range_check_int/oneliner_fail_0/stderr.golden.py deleted file mode 100644 index 225e2ee6b..000000000 --- a/test/grammar/datatype/range_check_int/oneliner_fail_0/stderr.golden.py +++ /dev/null @@ -1,19 +0,0 @@ - -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception(err_type=kcl_error.ErrType.IntOverflow_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=2 - ), - ], - arg_msg=kcl_error.INT_OVER_FLOW_MSG.format(2147483648, 32)) - , file=sys.stdout -) - diff --git a/test/grammar/datatype/range_check_int/oneliner_fail_1/main.k b/test/grammar/datatype/range_check_int/oneliner_fail_1/main.k deleted file mode 100644 index 5a13773fd..000000000 --- a/test/grammar/datatype/range_check_int/oneliner_fail_1/main.k +++ /dev/null @@ -1,2 +0,0 @@ -a = 1 -c = +9223372036854775808 diff --git a/test/grammar/datatype/range_check_int/oneliner_fail_1/settings.yaml b/test/grammar/datatype/range_check_int/oneliner_fail_1/settings.yaml deleted file mode 100644 index 542d01cf5..000000000 --- a/test/grammar/datatype/range_check_int/oneliner_fail_1/settings.yaml +++ /dev/null @@ -1 +0,0 @@ -kcl_options: -d diff --git a/test/grammar/datatype/range_check_int/oneliner_fail_1/stderr.golden.py b/test/grammar/datatype/range_check_int/oneliner_fail_1/stderr.golden.py deleted file mode 100644 index f8cdeca0e..000000000 --- a/test/grammar/datatype/range_check_int/oneliner_fail_1/stderr.golden.py +++ /dev/null @@ -1,19 +0,0 @@ - -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception(err_type=kcl_error.ErrType.IntOverflow_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=2 - ), - ], - arg_msg=kcl_error.INT_OVER_FLOW_MSG.format(9223372036854775808, 64)) - , file=sys.stdout -) - diff --git a/test/grammar/datatype/str/long_str_0/main.k b/test/grammar/datatype/str/long_str_0/main.k new file mode 100644 index 000000000..f366815a2 --- /dev/null +++ b/test/grammar/datatype/str/long_str_0/main.k @@ -0,0 +1,15 @@ +x0 = """ +a: 1 +--- +b: 2 +""" +x1 = """\ +a: 1 +--- +b: 2 +""" +x2 = """a: 1\n---\nb: 2\n""" +x3 = """a: 1 +--- +b: 2 +""" diff --git a/test/grammar/datatype/str/long_str_0/stdout.golden b/test/grammar/datatype/str/long_str_0/stdout.golden new file mode 100644 index 000000000..e31ba9e72 --- /dev/null +++ b/test/grammar/datatype/str/long_str_0/stdout.golden @@ -0,0 +1,17 @@ +x0: |2 + + a: 1 + --- + b: 2 +x1: | + a: 1 + --- + b: 2 +x2: | + a: 1 + --- + b: 2 +x3: | + a: 1 + --- + b: 2 diff --git a/test/grammar/datatype/str_interpolation/dollar_escape_0/main.k b/test/grammar/datatype/str_interpolation/dollar_escape_0/main.k new file mode 100644 index 000000000..f520662a5 --- /dev/null +++ b/test/grammar/datatype/str_interpolation/dollar_escape_0/main.k @@ -0,0 +1,3 @@ +a = 1 +b = 1 +data = "$\${a * 1}$$ ${b / 1} $$$$$" + " $$ " diff --git a/test/grammar/datatype/str_interpolation/dollar_escape_0/stdout.golden b/test/grammar/datatype/str_interpolation/dollar_escape_0/stdout.golden new file mode 100644 index 000000000..18d567464 --- /dev/null +++ b/test/grammar/datatype/str_interpolation/dollar_escape_0/stdout.golden @@ -0,0 +1,3 @@ +a: 1 +b: 1 +data: '$${a * 1}$$ 1.0 $$$$$ $$ ' diff --git a/test/grammar/datatype/str_interpolation/invalid_format_spec_fail_0/stderr.golden b/test/grammar/datatype/str_interpolation/invalid_format_spec_fail_0/stderr.golden new file mode 100644 index 000000000..9c0eceefa --- /dev/null +++ b/test/grammar/datatype/str_interpolation/invalid_format_spec_fail_0/stderr.golden @@ -0,0 +1,6 @@ +error[E2L23]: CompileError + --> ${CWD}/main.k:3:11 + | +3 | data = "${a: #js}" + " $$ " + | ^ #js is a invalid format spec + | \ No newline at end of file diff --git a/test/grammar/datatype/str_interpolation/invalid_format_spec_fail_0/stderr.golden.py b/test/grammar/datatype/str_interpolation/invalid_format_spec_fail_0/stderr.golden.py deleted file mode 100644 index 389a3a524..000000000 --- a/test/grammar/datatype/str_interpolation/invalid_format_spec_fail_0/stderr.golden.py +++ /dev/null @@ -1,21 +0,0 @@ -import os -import sys - -import kclvm.kcl.error as kcl_error - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.CompileError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=3, - col_no=11, - ) - ], - arg_msg="#js is a invalid format spec" - ) - , file=sys.stdout -) diff --git a/test/grammar/datatype/str_interpolation/invalid_format_spec_fail_1/stderr.golden b/test/grammar/datatype/str_interpolation/invalid_format_spec_fail_1/stderr.golden new file mode 100644 index 000000000..ce83ca1e0 --- /dev/null +++ b/test/grammar/datatype/str_interpolation/invalid_format_spec_fail_1/stderr.golden @@ -0,0 +1,6 @@ +error[E2L23]: CompileError + --> ${CWD}/main.k:3:11 + | +3 | data = "${a: #yamll}" + " $$ " + | ^ #yamll is a invalid format spec + | \ No newline at end of file diff --git a/test/grammar/datatype/str_interpolation/invalid_format_spec_fail_1/stderr.golden.py b/test/grammar/datatype/str_interpolation/invalid_format_spec_fail_1/stderr.golden.py deleted file mode 100644 index eced44cbe..000000000 --- a/test/grammar/datatype/str_interpolation/invalid_format_spec_fail_1/stderr.golden.py +++ /dev/null @@ -1,21 +0,0 @@ -import os -import sys - -import kclvm.kcl.error as kcl_error - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.CompileError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=3, - col_no=11, - ) - ], - arg_msg="#yamll is a invalid format spec" - ) - , file=sys.stdout -) diff --git a/test/grammar/datatype/str_interpolation/invalid_format_value_fail_0/stderr.golden b/test/grammar/datatype/str_interpolation/invalid_format_value_fail_0/stderr.golden new file mode 100644 index 000000000..becdb22a8 --- /dev/null +++ b/test/grammar/datatype/str_interpolation/invalid_format_value_fail_0/stderr.golden @@ -0,0 +1,6 @@ +error[E1001]: InvalidSyntax + --> ${CWD}/main.k:2:8 + | +2 | b = "${b = a + 1}" + | ^ invalid string interpolation expression: 'b = a + 1' + | \ No newline at end of file diff --git a/test/grammar/datatype/str_interpolation/invalid_format_value_fail_0/stderr.golden.py b/test/grammar/datatype/str_interpolation/invalid_format_value_fail_0/stderr.golden.py deleted file mode 100644 index 475f5969e..000000000 --- a/test/grammar/datatype/str_interpolation/invalid_format_value_fail_0/stderr.golden.py +++ /dev/null @@ -1,23 +0,0 @@ -import os -import sys - -import kclvm.kcl.error as kcl_error - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.InvalidFormatSpec_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=2, - col_no=5, - end_col_no=19 - ) - ], - arg_msg="invalid string interpolation expression 'b = a + 1'" - ), - file=sys.stdout -) - diff --git a/test/grammar/datatype/str_interpolation/invalid_format_value_fail_1/main.k b/test/grammar/datatype/str_interpolation/invalid_format_value_fail_1/main.k deleted file mode 100644 index 7f61501a7..000000000 --- a/test/grammar/datatype/str_interpolation/invalid_format_value_fail_1/main.k +++ /dev/null @@ -1,3 +0,0 @@ -a = 1 -b = 1 -data = "$$${a * 1}$$ ${b / 1} $$$$$" + " $$ " diff --git a/test/grammar/datatype/str_interpolation/invalid_format_value_fail_1/stderr.golden.py b/test/grammar/datatype/str_interpolation/invalid_format_value_fail_1/stderr.golden.py deleted file mode 100644 index 3b79bbd30..000000000 --- a/test/grammar/datatype/str_interpolation/invalid_format_value_fail_1/stderr.golden.py +++ /dev/null @@ -1,23 +0,0 @@ -import os -import sys - -import kclvm.kcl.error as kcl_error - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.InvalidFormatSpec_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=3, - col_no=8, - end_col_no=37 - ) - ], - arg_msg="invalid single '$', expecting '$' or '{'" - ), - file=sys.stdout -) - diff --git a/test/grammar/datatype/str_interpolation/simple_2/stdout.golden b/test/grammar/datatype/str_interpolation/simple_2/stdout.golden index 7f87c2cca..5355d583f 100644 --- a/test/grammar/datatype/str_interpolation/simple_2/stdout.golden +++ b/test/grammar/datatype/str_interpolation/simple_2/stdout.golden @@ -1,3 +1,3 @@ a: 1 b: 1 -data: '$1$ 1.0 $$ $$ ' +data: '$$1$$ 1.0 $$$$ $$ ' diff --git a/test/grammar/datatype/str_interpolation/var_not_define_fail_1/main.k b/test/grammar/datatype/str_interpolation/var_after_string_interpolation/main.k similarity index 100% rename from test/grammar/datatype/str_interpolation/var_not_define_fail_1/main.k rename to test/grammar/datatype/str_interpolation/var_after_string_interpolation/main.k diff --git a/test/grammar/datatype/str_interpolation/var_after_string_interpolation/stdout.golden b/test/grammar/datatype/str_interpolation/var_after_string_interpolation/stdout.golden new file mode 100644 index 000000000..95683b27a --- /dev/null +++ b/test/grammar/datatype/str_interpolation/var_after_string_interpolation/stdout.golden @@ -0,0 +1,3 @@ +a: 1 +b: '3' +c: 2 \ No newline at end of file diff --git a/test/grammar/datatype/str_interpolation/var_not_define_fail_0/stderr.golden b/test/grammar/datatype/str_interpolation/var_not_define_fail_0/stderr.golden new file mode 100644 index 000000000..d2d62332c --- /dev/null +++ b/test/grammar/datatype/str_interpolation/var_not_define_fail_0/stderr.golden @@ -0,0 +1,6 @@ +error[E2L23]: CompileError + --> ${CWD}/main.k:2:8 + | +2 | b = "${c + 1}" + | ^ name 'c' is not defined + | \ No newline at end of file diff --git a/test/grammar/datatype/str_interpolation/var_not_define_fail_0/stderr.golden.py b/test/grammar/datatype/str_interpolation/var_not_define_fail_0/stderr.golden.py deleted file mode 100644 index b311d3ab7..000000000 --- a/test/grammar/datatype/str_interpolation/var_not_define_fail_0/stderr.golden.py +++ /dev/null @@ -1,22 +0,0 @@ -import os -import sys - -import kclvm.kcl.error as kcl_error - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.CompileError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=2, - col_no=8 - ) - ], - arg_msg="name 'c' is not defined" - ), - file=sys.stdout -) - diff --git a/test/grammar/datatype/str_interpolation/var_not_define_fail_1/stderr.golden.py b/test/grammar/datatype/str_interpolation/var_not_define_fail_1/stderr.golden.py deleted file mode 100644 index b311d3ab7..000000000 --- a/test/grammar/datatype/str_interpolation/var_not_define_fail_1/stderr.golden.py +++ /dev/null @@ -1,22 +0,0 @@ -import os -import sys - -import kclvm.kcl.error as kcl_error - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.CompileError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=2, - col_no=8 - ) - ], - arg_msg="name 'c' is not defined" - ), - file=sys.stdout -) - diff --git a/test/grammar/datatype/undefined/fail_0/stderr.golden b/test/grammar/datatype/undefined/fail_0/stderr.golden new file mode 100644 index 000000000..e6d5506b0 --- /dev/null +++ b/test/grammar/datatype/undefined/fail_0/stderr.golden @@ -0,0 +1,6 @@ +error[E3M38]: EvaluationError + --> ${CWD}/main.k:3:1 + | +3 | data = a + b + | unsupported operand type(s) for +: 'int' and 'UndefinedType' + | \ No newline at end of file diff --git a/test/grammar/datatype/undefined/fail_0/stderr.golden.py b/test/grammar/datatype/undefined/fail_0/stderr.golden.py deleted file mode 100644 index f522c2ad5..000000000 --- a/test/grammar/datatype/undefined/fail_0/stderr.golden.py +++ /dev/null @@ -1,21 +0,0 @@ -import os -import sys - -import kclvm.kcl.error as kcl_error - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.EvaluationError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=3 - ) - ], - arg_msg="unsupported operand type(s) for +: 'int' and 'UndefinedType'" - ) - , file=sys.stdout -) - diff --git a/test/grammar/datatype/undefined/fail_1/_main.k b/test/grammar/datatype/undefined/fail_1/_main.k new file mode 100644 index 000000000..b2f848142 --- /dev/null +++ b/test/grammar/datatype/undefined/fail_1/_main.k @@ -0,0 +1,2 @@ +# Fixme: Diffrent error message with diffrent python3 versions. +result = int(Undefined) diff --git a/test/grammar/datatype/undefined/fail_1/main.k b/test/grammar/datatype/undefined/fail_1/main.k deleted file mode 100644 index 39fa4075e..000000000 --- a/test/grammar/datatype/undefined/fail_1/main.k +++ /dev/null @@ -1 +0,0 @@ -result = int(Undefined) diff --git a/test/grammar/datatype/undefined/fail_1/stderr.golden b/test/grammar/datatype/undefined/fail_1/stderr.golden new file mode 100644 index 000000000..24ff9b479 --- /dev/null +++ b/test/grammar/datatype/undefined/fail_1/stderr.golden @@ -0,0 +1 @@ +int() argument must be a string or a number, not 'UndefinedType' diff --git a/test/grammar/datatype/undefined/fail_1/stderr.golden.py b/test/grammar/datatype/undefined/fail_1/stderr.golden.py deleted file mode 100644 index 08affb444..000000000 --- a/test/grammar/datatype/undefined/fail_1/stderr.golden.py +++ /dev/null @@ -1,21 +0,0 @@ -import os -import sys - -import kclvm.kcl.error as kcl_error - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.EvaluationError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=1 - ) - ], - arg_msg="int() argument must be a string, a bytes-like object or a number, not 'UndefinedType'" - ) - , file=sys.stdout -) - diff --git a/test/grammar/datatype/units/invalid_units_fail_0/stderr.golden b/test/grammar/datatype/units/invalid_units_fail_0/stderr.golden new file mode 100644 index 000000000..964ca4849 --- /dev/null +++ b/test/grammar/datatype/units/invalid_units_fail_0/stderr.golden @@ -0,0 +1,6 @@ +error[E1001]: InvalidSyntax + --> ${CWD}/main.k:1:6 + | +1 | mi = 1mi + | ^ invalid int binary suffix + | \ No newline at end of file diff --git a/test/grammar/datatype/units/invalid_units_fail_0/stderr.golden.py b/test/grammar/datatype/units/invalid_units_fail_0/stderr.golden.py deleted file mode 100644 index dddc2c730..000000000 --- a/test/grammar/datatype/units/invalid_units_fail_0/stderr.golden.py +++ /dev/null @@ -1,16 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message(kcl_error.get_exception(err_type=kcl_error.ErrType.InvalidSyntax_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=1, - col_no=7, - arg_msg="Expected one of ['newline']" - )], - ), - file=sys.stdout) diff --git a/test/grammar/datatype/units/invalid_units_fail_1/stderr.golden b/test/grammar/datatype/units/invalid_units_fail_1/stderr.golden new file mode 100644 index 000000000..997fa7aa3 --- /dev/null +++ b/test/grammar/datatype/units/invalid_units_fail_1/stderr.golden @@ -0,0 +1,6 @@ +error[E1001]: InvalidSyntax + --> ${CWD}/main.k:1:6 + | +1 | ni = 1ni + | ^ invalid int binary suffix + | \ No newline at end of file diff --git a/test/grammar/datatype/units/invalid_units_fail_1/stderr.golden.py b/test/grammar/datatype/units/invalid_units_fail_1/stderr.golden.py deleted file mode 100644 index dddc2c730..000000000 --- a/test/grammar/datatype/units/invalid_units_fail_1/stderr.golden.py +++ /dev/null @@ -1,16 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message(kcl_error.get_exception(err_type=kcl_error.ErrType.InvalidSyntax_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=1, - col_no=7, - arg_msg="Expected one of ['newline']" - )], - ), - file=sys.stdout) diff --git a/test/grammar/datatype/units/invalid_units_fail_2/stderr.golden b/test/grammar/datatype/units/invalid_units_fail_2/stderr.golden new file mode 100644 index 000000000..7993a2500 --- /dev/null +++ b/test/grammar/datatype/units/invalid_units_fail_2/stderr.golden @@ -0,0 +1,6 @@ +error[E1001]: InvalidSyntax + --> ${CWD}/main.k:1:6 + | +1 | ui = 1ui + | ^ invalid int binary suffix + | \ No newline at end of file diff --git a/test/grammar/datatype/units/invalid_units_fail_2/stderr.golden.py b/test/grammar/datatype/units/invalid_units_fail_2/stderr.golden.py deleted file mode 100644 index dddc2c730..000000000 --- a/test/grammar/datatype/units/invalid_units_fail_2/stderr.golden.py +++ /dev/null @@ -1,16 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message(kcl_error.get_exception(err_type=kcl_error.ErrType.InvalidSyntax_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=1, - col_no=7, - arg_msg="Expected one of ['newline']" - )], - ), - file=sys.stdout) diff --git a/test/grammar/datatype/units/range_check_fail_0/stderr.golden b/test/grammar/datatype/units/range_check_fail_0/stderr.golden new file mode 100644 index 000000000..5cc8c801e --- /dev/null +++ b/test/grammar/datatype/units/range_check_fail_0/stderr.golden @@ -0,0 +1 @@ +1329227995784915872903807060280344576: A 64 bit integer overflow \ No newline at end of file diff --git a/test/grammar/datatype/units/range_check_fail_0/stderr.golden.py b/test/grammar/datatype/units/range_check_fail_0/stderr.golden.py deleted file mode 100644 index 8685f546b..000000000 --- a/test/grammar/datatype/units/range_check_fail_0/stderr.golden.py +++ /dev/null @@ -1,19 +0,0 @@ - -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception(err_type=kcl_error.ErrType.IntOverflow_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=1 - ), - ], - arg_msg=kcl_error.INT_OVER_FLOW_MSG.format(1329227995784915872903807060280344576, 64)) - , file=sys.stdout -) - diff --git a/test/grammar/datatype/units/range_check_fail_1/stderr.golden b/test/grammar/datatype/units/range_check_fail_1/stderr.golden new file mode 100644 index 000000000..19826f2ab --- /dev/null +++ b/test/grammar/datatype/units/range_check_fail_1/stderr.golden @@ -0,0 +1 @@ +1073849208920891981824: A 64 bit integer overflow \ No newline at end of file diff --git a/test/grammar/datatype/units/range_check_fail_1/stderr.golden.py b/test/grammar/datatype/units/range_check_fail_1/stderr.golden.py deleted file mode 100644 index 5b3cac3db..000000000 --- a/test/grammar/datatype/units/range_check_fail_1/stderr.golden.py +++ /dev/null @@ -1,21 +0,0 @@ - -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.IntOverflow_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=1 - ) - ], - arg_msg=kcl_error.INT_OVER_FLOW_MSG.format(1073849208920891981824, 64) - ) - , file=sys.stdout -) - diff --git a/test/grammar/datatype/units/simple_4/stdout.golden b/test/grammar/datatype/units/simple_4/stdout.golden index 10b6fed8c..7c3083df8 100644 --- a/test/grammar/datatype/units/simple_4/stdout.golden +++ b/test/grammar/datatype/units/simple_4/stdout.golden @@ -1,11 +1,11 @@ -x0: 1000000 -x1: 1000000 +x0: 1000000.0 +x1: 1000000.0 x2: 1000000 x3: 1000000.0 -x4: 1000000 -x5: 1000000 -x6: 1024 -x7: 1024 +x4: 1000000.0 +x5: 1000000.0 +x6: 1024.0 +x7: 1024.0 x0str: 1M x1str: 1M x2str: '1000000' @@ -13,4 +13,4 @@ x3str: '1000000.0' x4str: 1M x5str: 1M x6str: 1Ki -x7str: '{"k": "1Ki"}' +x7str: '{"k": 1024.0}' diff --git a/test/grammar/expr/identifier_prefix/fail_0/stderr.golden b/test/grammar/expr/identifier_prefix/fail_0/stderr.golden new file mode 100644 index 000000000..3a8c137db --- /dev/null +++ b/test/grammar/expr/identifier_prefix/fail_0/stderr.golden @@ -0,0 +1,12 @@ +error[E1001]: ImmutableError + --> ${CWD}/main.k:2:1 + | +2 | $a = 2 + | ^ Can not change the value of 'a', because it was declared immutable + | + --> ${CWD}/main.k:1:1 + | +1 | a = 1 + | ^ The variable 'a' is declared here + | +note: change the variable name to '_a' to make it mutable \ No newline at end of file diff --git a/test/grammar/expr/identifier_prefix/fail_0/stderr.golden.py b/test/grammar/expr/identifier_prefix/fail_0/stderr.golden.py deleted file mode 100644 index 3f4ae726b..000000000 --- a/test/grammar/expr/identifier_prefix/fail_0/stderr.golden.py +++ /dev/null @@ -1,22 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.ImmutableCompileError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=2, - col_no=1, - end_col_no=3 - - ) - ], - ), - file=sys.stdout -) - diff --git a/test/grammar/expr/identifier_prefix/fail_1/stderr.golden b/test/grammar/expr/identifier_prefix/fail_1/stderr.golden new file mode 100644 index 000000000..da065c2e2 --- /dev/null +++ b/test/grammar/expr/identifier_prefix/fail_1/stderr.golden @@ -0,0 +1,12 @@ +error[E1001]: ImmutableError + --> ${CWD}/main.k:2:1 + | +2 | a = 2 + | ^ Can not change the value of 'a', because it was declared immutable + | + --> ${CWD}/main.k:1:1 + | +1 | $a = 1 + | ^ The variable 'a' is declared here + | +note: change the variable name to '_a' to make it mutable \ No newline at end of file diff --git a/test/grammar/expr/identifier_prefix/fail_1/stderr.golden.py b/test/grammar/expr/identifier_prefix/fail_1/stderr.golden.py deleted file mode 100644 index c8b15b5a3..000000000 --- a/test/grammar/expr/identifier_prefix/fail_1/stderr.golden.py +++ /dev/null @@ -1,20 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.ImmutableCompileError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=2, - col_no=1 - ) - ], - ), - file=sys.stdout -) - diff --git a/test/grammar/expr/select_expr/in_for_0/stdout.golden b/test/grammar/expr/select_expr/in_for_0/stdout.golden index a13ffd4bb..7f05c6719 100644 --- a/test/grammar/expr/select_expr/in_for_0/stdout.golden +++ b/test/grammar/expr/select_expr/in_for_0/stdout.golden @@ -1,2 +1,3 @@ c: - name: main + volumeMounts: [] diff --git a/test/grammar/if/if_stmt/test_4/main.k b/test/grammar/if/if_stmt/test_4/main.k new file mode 100644 index 000000000..c2a5cb784 --- /dev/null +++ b/test/grammar/if/if_stmt/test_4/main.k @@ -0,0 +1,4 @@ +if False: + a = 1 +if a: + b = a diff --git a/test/test_units/test_kclvm/test_types/normal_test_data/kcl.mod b/test/grammar/if/if_stmt/test_4/stdout.golden similarity index 100% rename from test/test_units/test_kclvm/test_types/normal_test_data/kcl.mod rename to test/grammar/if/if_stmt/test_4/stdout.golden diff --git a/test/grammar/if/if_stmt/test_5/main.k b/test/grammar/if/if_stmt/test_5/main.k new file mode 100644 index 000000000..b502b908c --- /dev/null +++ b/test/grammar/if/if_stmt/test_5/main.k @@ -0,0 +1,8 @@ +_nodes=[] + +if True: + print("Condition: True") +elif False: + _nodes+=[] + +nodes=_nodes diff --git a/test/grammar/if/if_stmt/test_5/stdout.golden b/test/grammar/if/if_stmt/test_5/stdout.golden new file mode 100644 index 000000000..6f7d259d2 --- /dev/null +++ b/test/grammar/if/if_stmt/test_5/stdout.golden @@ -0,0 +1,2 @@ +Condition: True +nodes: [] diff --git a/test/grammar/import/empty_import_fail/main.k b/test/grammar/import/empty_import_fail/main.k deleted file mode 100644 index e26158c59..000000000 --- a/test/grammar/import/empty_import_fail/main.k +++ /dev/null @@ -1,6 +0,0 @@ -import pkg_empty - -a = 1 -b = 1.2 -c = [1.3] -d = {"1.4": 1.5} diff --git a/test/grammar/import/empty_import_fail/pkg_empty/1.txt b/test/grammar/import/empty_import_fail/pkg_empty/1.txt deleted file mode 100644 index fd7271a52..000000000 --- a/test/grammar/import/empty_import_fail/pkg_empty/1.txt +++ /dev/null @@ -1 +0,0 @@ -kcl \ No newline at end of file diff --git a/test/grammar/import/empty_import_fail/stderr.golden.py b/test/grammar/import/empty_import_fail/stderr.golden.py deleted file mode 100644 index 4bfd2c927..000000000 --- a/test/grammar/import/empty_import_fail/stderr.golden.py +++ /dev/null @@ -1,25 +0,0 @@ - -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) -modulename = 'pkg_empty' - -location = os.path.join(cwd, modulename) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.CannotFindModule_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=1, - col_no=1, - end_col_no=17 - ) - ], - arg_msg=kcl_error.CANNOT_FIND_MODULE_MSG.format(modulename, '{}'.format(location)) - ), - file=sys.stdout -) diff --git a/test/grammar/import/import_abs_fail_0/app-main/stderr.golden b/test/grammar/import/import_abs_fail_0/app-main/stderr.golden new file mode 100644 index 000000000..0c8a0a6e7 --- /dev/null +++ b/test/grammar/import/import_abs_fail_0/app-main/stderr.golden @@ -0,0 +1,14 @@ +error[E2F04]: CannotFindModule + --> ${CWD}/main.k:1:1 + | +1 | import .some0.pkg1 as some00 # some0 not found in app-main package + | ^ Cannot find the module .some0.pkg1 from ${CWD}/some0/pkg1 + | +suggestion: try 'kcl mod add app-main' to download the missing package +suggestion: browse more packages at 'https://artifacthub.io' +error[E2G22]: TypeError + --> ${CWD}/main.k:3:9 + | +3 | Name1 = some00.Name # some0.pkg1.name + | ^ attribute 'Name' not found in 'module 'app-main.some0.pkg1'' + | \ No newline at end of file diff --git a/test/grammar/import/import_abs_fail_0/app-main/stderr.golden.py b/test/grammar/import/import_abs_fail_0/app-main/stderr.golden.py deleted file mode 100644 index 0c3f64f19..000000000 --- a/test/grammar/import/import_abs_fail_0/app-main/stderr.golden.py +++ /dev/null @@ -1,25 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) -modulename = './some0/pkg1' - -packagename = os.path.abspath(os.path.join(cwd, modulename)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.CannotFindModule_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=1, - col_no=1, - end_col_no=29 - ) - ], - arg_msg=kcl_error.CANNOT_FIND_MODULE_MSG.format(".some0.pkg1", packagename) - ), - file=sys.stdout -) - diff --git a/test/grammar/import/import_abs_fail_1/app-main/stderr.golden b/test/grammar/import/import_abs_fail_1/app-main/stderr.golden new file mode 100644 index 000000000..19b1d956d --- /dev/null +++ b/test/grammar/import/import_abs_fail_1/app-main/stderr.golden @@ -0,0 +1 @@ +No KCL files found in the specified folder \ No newline at end of file diff --git a/test/grammar/import/import_abs_fail_1/app-main/stderr.golden.py b/test/grammar/import/import_abs_fail_1/app-main/stderr.golden.py deleted file mode 100644 index 53cc7ac1a..000000000 --- a/test/grammar/import/import_abs_fail_1/app-main/stderr.golden.py +++ /dev/null @@ -1,25 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) -modulename = './../' - -packagename = os.path.abspath(os.path.join(cwd, modulename)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.CannotFindModule_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=1, - col_no=1, - end_col_no=31 - ) - ], - arg_msg=kcl_error.CANNOT_FIND_MODULE_MSG.format("...some0.pkg1", packagename) - ), - file=sys.stdout -) - diff --git a/test/grammar/import/import_main_file_fail_0/stderr.golden b/test/grammar/import/import_main_file_fail_0/stderr.golden new file mode 100644 index 000000000..b38b24fd6 --- /dev/null +++ b/test/grammar/import/import_main_file_fail_0/stderr.golden @@ -0,0 +1,13 @@ +error[E2L23]: CompileError + --> ${CWD}/module.k:2:1 + | +2 | import main + | ^ There is a circular reference between modules module, main + | + +error[E2L23]: CompileError + --> ${CWD}/main.k:1:1 + | +1 | import module + | ^ There is a circular reference between modules module, main + | \ No newline at end of file diff --git a/test/grammar/import/import_main_file_fail_0/stderr.golden.py b/test/grammar/import/import_main_file_fail_0/stderr.golden.py deleted file mode 100644 index 2de4f133d..000000000 --- a/test/grammar/import/import_main_file_fail_0/stderr.golden.py +++ /dev/null @@ -1,23 +0,0 @@ - -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -main_file = os.path.join(cwd, 'main.k') -module_file = os.path.join(cwd, 'module.k') - -kcl_error.print_kcl_error_message( - kcl_error.get_exception(err_type=kcl_error.ErrType.CompileError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=module_file, - line_no=2, - col_no=1, - ), - ], - arg_msg=f"Cannot import {main_file} in the main package") - , file=sys.stdout -) - diff --git a/test/grammar/import/import_main_file_fail_1/stderr.golden b/test/grammar/import/import_main_file_fail_1/stderr.golden new file mode 100644 index 000000000..15a485285 --- /dev/null +++ b/test/grammar/import/import_main_file_fail_1/stderr.golden @@ -0,0 +1,3 @@ +error[E3M38]: error[E1001]: RecursiveLoad +Could not compiles due to cyclic import statements +- ${CWD}/main.k \ No newline at end of file diff --git a/test/grammar/import/import_main_file_fail_1/stderr.golden.py b/test/grammar/import/import_main_file_fail_1/stderr.golden.py deleted file mode 100644 index 6304f8236..000000000 --- a/test/grammar/import/import_main_file_fail_1/stderr.golden.py +++ /dev/null @@ -1,22 +0,0 @@ - -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -file = os.path.join(cwd, 'main.k') - -kcl_error.print_kcl_error_message( - kcl_error.get_exception(err_type=kcl_error.ErrType.CompileError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=file, - line_no=1, - col_no=1, - ), - ], - arg_msg=f"Cannot import {file} in the main package") - , file=sys.stdout -) - diff --git a/test/grammar/import/import_name_same_with_schema_attr/main.k b/test/grammar/import/import_name_same_with_schema_attr/main.k new file mode 100644 index 000000000..597a5615f --- /dev/null +++ b/test/grammar/import/import_name_same_with_schema_attr/main.k @@ -0,0 +1,9 @@ +import file as libfile + +schema FilesSchema: + file: str + + check: + libfile.exists(file) if file, "file not found ${file}" + +v = FilesSchema {file = ""} diff --git a/test/grammar/import/import_name_same_with_schema_attr/stdout.golden b/test/grammar/import/import_name_same_with_schema_attr/stdout.golden new file mode 100644 index 000000000..1a81f8f99 --- /dev/null +++ b/test/grammar/import/import_name_same_with_schema_attr/stdout.golden @@ -0,0 +1,2 @@ +v: + file: '' diff --git a/test/test_units/test_kclvm/test_vm/test_data/kcl.mod b/test/grammar/import/import_package_module_2/kcl.mod similarity index 100% rename from test/test_units/test_kclvm/test_vm/test_data/kcl.mod rename to test/grammar/import/import_package_module_2/kcl.mod diff --git a/test/grammar/import/import_package_module_2/main.k b/test/grammar/import/import_package_module_2/main.k new file mode 100644 index 000000000..4efecd742 --- /dev/null +++ b/test/grammar/import/import_package_module_2/main.k @@ -0,0 +1,3 @@ +import pkg + +data = pkg.Data() diff --git a/test/grammar/import/import_package_module_2/pkg/pkg1.k b/test/grammar/import/import_package_module_2/pkg/pkg1.k new file mode 100644 index 000000000..8f3ce1520 --- /dev/null +++ b/test/grammar/import/import_package_module_2/pkg/pkg1.k @@ -0,0 +1,2 @@ +schema Data: + id: int = global diff --git a/test/grammar/import/import_package_module_2/pkg/pkg2.k b/test/grammar/import/import_package_module_2/pkg/pkg2.k new file mode 100644 index 000000000..cfb5a1623 --- /dev/null +++ b/test/grammar/import/import_package_module_2/pkg/pkg2.k @@ -0,0 +1 @@ +global = 1 diff --git a/test/grammar/import/import_package_module_2/stdout.golden b/test/grammar/import/import_package_module_2/stdout.golden new file mode 100644 index 000000000..ac24fdc22 --- /dev/null +++ b/test/grammar/import/import_package_module_2/stdout.golden @@ -0,0 +1,2 @@ +data: + id: 1 \ No newline at end of file diff --git a/test/test_units/test_kclvm/test_tools/test_list_attr/schema_testdata/empty.k b/test/grammar/import/import_relative_path_with_multi_input_files/base/main.k similarity index 100% rename from test/test_units/test_kclvm/test_tools/test_list_attr/schema_testdata/empty.k rename to test/grammar/import/import_relative_path_with_multi_input_files/base/main.k diff --git a/test/grammar/import/import_relative_path_with_multi_input_files/base/settings.yaml b/test/grammar/import/import_relative_path_with_multi_input_files/base/settings.yaml new file mode 100644 index 000000000..99db600cf --- /dev/null +++ b/test/grammar/import/import_relative_path_with_multi_input_files/base/settings.yaml @@ -0,0 +1 @@ +kcl_options: ../prod/prod.k diff --git a/test/grammar/import/import_relative_path_with_multi_input_files/base/stdout.golden b/test/grammar/import/import_relative_path_with_multi_input_files/base/stdout.golden new file mode 100644 index 000000000..083c5aec5 --- /dev/null +++ b/test/grammar/import/import_relative_path_with_multi_input_files/base/stdout.golden @@ -0,0 +1,2 @@ +a: 1 +b: 2 diff --git a/test/test_units/test_langserver/test_data/go_to_def/kcl.mod b/test/grammar/import/import_relative_path_with_multi_input_files/kcl.mod similarity index 100% rename from test/test_units/test_langserver/test_data/go_to_def/kcl.mod rename to test/grammar/import/import_relative_path_with_multi_input_files/kcl.mod diff --git a/test/grammar/import/import_relative_path_with_multi_input_files/prod/pkg/pkg.k b/test/grammar/import/import_relative_path_with_multi_input_files/prod/pkg/pkg.k new file mode 100644 index 000000000..a67860308 --- /dev/null +++ b/test/grammar/import/import_relative_path_with_multi_input_files/prod/pkg/pkg.k @@ -0,0 +1 @@ +b = 2 diff --git a/test/grammar/import/import_relative_path_with_multi_input_files/prod/prod.k b/test/grammar/import/import_relative_path_with_multi_input_files/prod/prod.k new file mode 100644 index 000000000..c6775dd11 --- /dev/null +++ b/test/grammar/import/import_relative_path_with_multi_input_files/prod/prod.k @@ -0,0 +1,3 @@ +import .pkg + +b = pkg.b diff --git a/test/grammar/import/import_same_as_name_0/pkg/temp.k b/test/grammar/import/import_same_as_name_0/pkg/temp.k index f334ab821..2181504e5 100644 --- a/test/grammar/import/import_same_as_name_0/pkg/temp.k +++ b/test/grammar/import/import_same_as_name_0/pkg/temp.k @@ -1,6 +1,6 @@ -import pkg.core.v1 as v1 +import pkg.core.v1 as corev1 schema CafeDeploy: - data: v1.Deploy = v1.Deploy { + data: corev1.Deploy = corev1.Deploy { name: "deploy" } diff --git a/test/grammar/import/import_syntax_error_0/app-main/stderr.golden b/test/grammar/import/import_syntax_error_0/app-main/stderr.golden new file mode 100644 index 000000000..800cd4673 --- /dev/null +++ b/test/grammar/import/import_syntax_error_0/app-main/stderr.golden @@ -0,0 +1,20 @@ +error[E1001]: InvalidSyntax + --> ${CWD}/main.k:1:15 + | +1 | import .some0..pkg1 as some00 # some0 not found in app-main package + | ^ expected one of ["identifier"] got . + | +error[E2F04]: CannotFindModule + --> ${CWD}/main.k:1:1 + | +1 | import .some0..pkg1 as some00 # some0 not found in app-main package + | ^ Cannot find the module .some0..pkg1 from ${CWD}/some0//pkg1 + | +suggestion: try 'kcl mod add app-main' to download the missing package +suggestion: browse more packages at 'https://artifacthub.io' +error[E2G22]: TypeError + --> ${CWD}/main.k:3:9 + | +3 | Name1 = some00.Name # some0.pkg1.name + | ^ attribute 'Name' not found in 'module 'app-main.some0..pkg1'' + | \ No newline at end of file diff --git a/test/grammar/import/import_syntax_error_0/app-main/stderr.golden.py b/test/grammar/import/import_syntax_error_0/app-main/stderr.golden.py deleted file mode 100644 index 9e3e9c4bd..000000000 --- a/test/grammar/import/import_syntax_error_0/app-main/stderr.golden.py +++ /dev/null @@ -1,16 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message(kcl_error.get_exception(err_type=kcl_error.ErrType.InvalidSyntax_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=1, - col_no=15, - arg_msg="Expected one of ['name']" - )], - ), - file=sys.stdout) diff --git a/test/grammar/import/import_with_complex_types_0/kcl.mod b/test/grammar/import/import_with_complex_types_0/kcl.mod new file mode 100644 index 000000000..e69de29bb diff --git a/test/grammar/import/import_with_complex_types_0/main.k b/test/grammar/import/import_with_complex_types_0/main.k new file mode 100644 index 000000000..f9a886111 --- /dev/null +++ b/test/grammar/import/import_with_complex_types_0/main.k @@ -0,0 +1,11 @@ +import types + +hosts0: {str:types.Host} = { + foo: {host: "foo.example.net"} + bar: {host: "bar.example.net"} +} + +hosts1: {str:types.HostPort} = { + foo: {host: "foo.example.net", port: 80} + bar: {host: "bar.example.net", port: 80} +} diff --git a/test/grammar/import/import_with_complex_types_0/types/host.k b/test/grammar/import/import_with_complex_types_0/types/host.k new file mode 100644 index 000000000..67182e876 --- /dev/null +++ b/test/grammar/import/import_with_complex_types_0/types/host.k @@ -0,0 +1,5 @@ +schema Host: + host: str + +schema HostPort(Host): + port: int diff --git a/test/grammar/import/import_with_complex_types_1/kcl.mod b/test/grammar/import/import_with_complex_types_1/kcl.mod new file mode 100644 index 000000000..e69de29bb diff --git a/test/grammar/import/import_with_complex_types_1/main.k b/test/grammar/import/import_with_complex_types_1/main.k new file mode 100644 index 000000000..cd4bbee3d --- /dev/null +++ b/test/grammar/import/import_with_complex_types_1/main.k @@ -0,0 +1,11 @@ +import types + +hosts0: [types.Host] = [ + {host: "foo.example.net"} + {host: "bar.example.net"} +] + +hosts1: [types.HostPort] = [ + {host: "foo.example.net", port: 80} + {host: "bar.example.net", port: 80} +] diff --git a/test/grammar/import/import_with_complex_types_1/types/host.k b/test/grammar/import/import_with_complex_types_1/types/host.k new file mode 100644 index 000000000..67182e876 --- /dev/null +++ b/test/grammar/import/import_with_complex_types_1/types/host.k @@ -0,0 +1,5 @@ +schema Host: + host: str + +schema HostPort(Host): + port: int diff --git a/test/grammar/import/module/no_module_attr_fail_0/stderr.golden b/test/grammar/import/module/no_module_attr_fail_0/stderr.golden new file mode 100644 index 000000000..29c2fbc6b --- /dev/null +++ b/test/grammar/import/module/no_module_attr_fail_0/stderr.golden @@ -0,0 +1,6 @@ +error[E2G22]: TypeError + --> ${CWD}/main.k:3:5 + | +3 | a = p.D + 1 + | ^ attribute 'D' not found in 'module 'pkg'' + | \ No newline at end of file diff --git a/test/grammar/import/module/no_module_attr_fail_0/stderr.golden.py b/test/grammar/import/module/no_module_attr_fail_0/stderr.golden.py deleted file mode 100644 index a002a3a27..000000000 --- a/test/grammar/import/module/no_module_attr_fail_0/stderr.golden.py +++ /dev/null @@ -1,22 +0,0 @@ - -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.AttributeError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=3, - col_no=5 - ) - ], - arg_msg="module 'pkg' has no attribute 'D'" - ), - file=sys.stdout -) - diff --git a/test/grammar/import/module/no_module_attr_fail_1/stderr.golden b/test/grammar/import/module/no_module_attr_fail_1/stderr.golden new file mode 100644 index 000000000..f740e3fc1 --- /dev/null +++ b/test/grammar/import/module/no_module_attr_fail_1/stderr.golden @@ -0,0 +1,12 @@ +error[E2G22]: TypeError + --> ${CWD}/main.k:3:10 + | +3 | schema A(p.D): + | ^ attribute 'D' not found in 'module 'pkg'' + | +error[E2D34]: IllegalInheritError + --> ${CWD}/main.k:3:10 + | +3 | schema A(p.D): + | ^ invalid schema inherit object type, expect schema, got 'any' + | \ No newline at end of file diff --git a/test/grammar/import/module/no_module_attr_fail_1/stderr.golden.py b/test/grammar/import/module/no_module_attr_fail_1/stderr.golden.py deleted file mode 100644 index bb7333979..000000000 --- a/test/grammar/import/module/no_module_attr_fail_1/stderr.golden.py +++ /dev/null @@ -1,22 +0,0 @@ - -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.AttributeError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=3, - col_no=10 - ) - ], - arg_msg="module 'pkg' has no attribute 'D'" - ), - file=sys.stdout -) - diff --git a/test/grammar/import/module/no_module_attr_fail_2/stderr.golden b/test/grammar/import/module/no_module_attr_fail_2/stderr.golden new file mode 100644 index 000000000..bedb8c0e6 --- /dev/null +++ b/test/grammar/import/module/no_module_attr_fail_2/stderr.golden @@ -0,0 +1,6 @@ +error[E2G22]: TypeError + --> ${CWD}/main.k:3:5 + | +3 | a = math.err_func(1) + | ^ attribute 'err_func' not found in 'module 'math'' + | \ No newline at end of file diff --git a/test/grammar/import/module/no_module_attr_fail_2/stderr.golden.py b/test/grammar/import/module/no_module_attr_fail_2/stderr.golden.py deleted file mode 100644 index 3cb9d21df..000000000 --- a/test/grammar/import/module/no_module_attr_fail_2/stderr.golden.py +++ /dev/null @@ -1,22 +0,0 @@ - -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.AttributeError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=3, - col_no=5 - ) - ], - arg_msg="module 'math' has no attribute 'err_func'" - ), - file=sys.stdout -) - diff --git a/test/grammar/import/module/no_module_attr_fail_3/stderr.golden b/test/grammar/import/module/no_module_attr_fail_3/stderr.golden new file mode 100644 index 000000000..82fbd5bb6 --- /dev/null +++ b/test/grammar/import/module/no_module_attr_fail_3/stderr.golden @@ -0,0 +1,6 @@ +error[E2G22]: TypeError + --> ${CWD}/main.k:3:5 + | +3 | a = mymath.err_func(1) + | ^ attribute 'err_func' not found in 'module 'math'' + | \ No newline at end of file diff --git a/test/grammar/import/module/no_module_attr_fail_3/stderr.golden.py b/test/grammar/import/module/no_module_attr_fail_3/stderr.golden.py deleted file mode 100644 index 3cb9d21df..000000000 --- a/test/grammar/import/module/no_module_attr_fail_3/stderr.golden.py +++ /dev/null @@ -1,22 +0,0 @@ - -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.AttributeError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=3, - col_no=5 - ) - ], - arg_msg="module 'math' has no attribute 'err_func'" - ), - file=sys.stdout -) - diff --git a/test/grammar/import/pkg_inplace_modify_fail_0/stderr.golden b/test/grammar/import/pkg_inplace_modify_fail_0/stderr.golden new file mode 100644 index 000000000..ac1491f52 --- /dev/null +++ b/test/grammar/import/pkg_inplace_modify_fail_0/stderr.golden @@ -0,0 +1,12 @@ +error[E1001]: ImmutableError + --> ${CWD}/main.k:3:1 + | +3 | pkg.a = 1 + | ^ Can not change the value of 'pkg', because it was declared immutable + | + --> ${CWD}/main.k:1:1 + | +1 | import pkg + | ^ The variable 'pkg' is declared here + | +note: change the variable name to '_pkg' to make it mutable \ No newline at end of file diff --git a/test/grammar/import/pkg_inplace_modify_fail_0/stderr.golden.py b/test/grammar/import/pkg_inplace_modify_fail_0/stderr.golden.py deleted file mode 100644 index 26a35d289..000000000 --- a/test/grammar/import/pkg_inplace_modify_fail_0/stderr.golden.py +++ /dev/null @@ -1,19 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception(err_type=kcl_error.ErrType.ImmutableCompileError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=3, - col_no=1, - ), - ], - arg_msg="Immutable variable is modified during compiling") - , file=sys.stdout -) - diff --git a/test/grammar/import/pkg_inplace_modify_fail_1/stderr.golden b/test/grammar/import/pkg_inplace_modify_fail_1/stderr.golden new file mode 100644 index 000000000..94e2c83d8 --- /dev/null +++ b/test/grammar/import/pkg_inplace_modify_fail_1/stderr.golden @@ -0,0 +1 @@ +pkg.a |= 2 \ No newline at end of file diff --git a/test/grammar/import/pkg_inplace_modify_fail_1/stderr.golden.py b/test/grammar/import/pkg_inplace_modify_fail_1/stderr.golden.py deleted file mode 100644 index 88ee9a09b..000000000 --- a/test/grammar/import/pkg_inplace_modify_fail_1/stderr.golden.py +++ /dev/null @@ -1,21 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.CompileError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=3, - col_no=1, - ) - ], - arg_msg="only schema and dict object can be updated attribute" - ), - file=sys.stdout -) - diff --git a/test/grammar/import/pkg_inplace_modify_fail_2/stderr.golden b/test/grammar/import/pkg_inplace_modify_fail_2/stderr.golden new file mode 100644 index 000000000..f3af0be03 --- /dev/null +++ b/test/grammar/import/pkg_inplace_modify_fail_2/stderr.golden @@ -0,0 +1,6 @@ +error[E3M38]: EvaluationError + --> ${CWD}/main.k:4:1 + | +4 | pkg.a = 2 + | failed to update the dict. An iterable of key-value pairs was expected, but got UndefinedType. Check if the syntax for updating the dictionary with the attribute 'a' is correct + | \ No newline at end of file diff --git a/test/grammar/import/pkg_inplace_modify_fail_2/stderr.golden.py b/test/grammar/import/pkg_inplace_modify_fail_2/stderr.golden.py deleted file mode 100644 index e430951f1..000000000 --- a/test/grammar/import/pkg_inplace_modify_fail_2/stderr.golden.py +++ /dev/null @@ -1,19 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception(err_type=kcl_error.ErrType.CompileError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=4, - col_no=5, - ), - ], - arg_msg="only schema and dict object can be updated attribute") - , file=sys.stdout -) - diff --git a/test/grammar/lambda/arg_type/main.k b/test/grammar/lambda/arg_type/main.k new file mode 100644 index 000000000..3cf3c8756 --- /dev/null +++ b/test/grammar/lambda/arg_type/main.k @@ -0,0 +1,9 @@ +import sub as s + +identity = lambda res: s.Test { + res { + name = "world" + } +} + +c = identity(s.Test{name="hello"}) diff --git a/test/grammar/lambda/arg_type/stdout.golden b/test/grammar/lambda/arg_type/stdout.golden new file mode 100644 index 000000000..81be50f43 --- /dev/null +++ b/test/grammar/lambda/arg_type/stdout.golden @@ -0,0 +1,2 @@ +c: + name: world \ No newline at end of file diff --git a/test/grammar/lambda/arg_type/sub.k b/test/grammar/lambda/arg_type/sub.k new file mode 100644 index 000000000..df60bab68 --- /dev/null +++ b/test/grammar/lambda/arg_type/sub.k @@ -0,0 +1,2 @@ +schema Test: + name: str \ No newline at end of file diff --git a/test/grammar/lambda/arg_type_annotation/main.k b/test/grammar/lambda/arg_type_annotation/main.k new file mode 100644 index 000000000..3306437e7 --- /dev/null +++ b/test/grammar/lambda/arg_type_annotation/main.k @@ -0,0 +1,9 @@ +import sub as s + +identity: (s.Test) -> s.Test = lambda res: s.Test { + res { + name = "world" + } +} + +c = identity(s.Test{name="hello"}) diff --git a/test/grammar/lambda/arg_type_annotation/stdout.golden b/test/grammar/lambda/arg_type_annotation/stdout.golden new file mode 100644 index 000000000..81be50f43 --- /dev/null +++ b/test/grammar/lambda/arg_type_annotation/stdout.golden @@ -0,0 +1,2 @@ +c: + name: world \ No newline at end of file diff --git a/test/grammar/lambda/arg_type_annotation/sub.k b/test/grammar/lambda/arg_type_annotation/sub.k new file mode 100644 index 000000000..df60bab68 --- /dev/null +++ b/test/grammar/lambda/arg_type_annotation/sub.k @@ -0,0 +1,2 @@ +schema Test: + name: str \ No newline at end of file diff --git a/test/grammar/lambda/closure_0/main.k b/test/grammar/lambda/closure_0/main.k new file mode 100644 index 000000000..c25411358 --- /dev/null +++ b/test/grammar/lambda/closure_0/main.k @@ -0,0 +1,6 @@ +x = lambda { + a = 1 + lambda { + a + 1 + }() +}() diff --git a/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/plugin.yaml b/test/grammar/lambda/closure_0/stdout.golden similarity index 100% rename from test/test_units/test_kclvm/test_compiler/test_eval/eval_data/plugin.yaml rename to test/grammar/lambda/closure_0/stdout.golden diff --git a/test/grammar/lambda/closure_0_annotation/main.k b/test/grammar/lambda/closure_0_annotation/main.k new file mode 100644 index 000000000..52e2d4053 --- /dev/null +++ b/test/grammar/lambda/closure_0_annotation/main.k @@ -0,0 +1,6 @@ +x : int = lambda { + a = 1 + lambda { + a + 1 + }() +}() diff --git a/test/grammar/lambda/closure_0_annotation/stdout.golden b/test/grammar/lambda/closure_0_annotation/stdout.golden new file mode 100644 index 000000000..ad932ccf5 --- /dev/null +++ b/test/grammar/lambda/closure_0_annotation/stdout.golden @@ -0,0 +1 @@ +x: 2 diff --git a/test/grammar/lambda/closure_1/main.k b/test/grammar/lambda/closure_1/main.k new file mode 100644 index 000000000..0ff1faa6a --- /dev/null +++ b/test/grammar/lambda/closure_1/main.k @@ -0,0 +1,7 @@ +x = lambda { + a = 1 + b = 2 + lambda x { + a + b + x + }(3) +}() diff --git a/test/grammar/lambda/closure_1/stdout.golden b/test/grammar/lambda/closure_1/stdout.golden new file mode 100644 index 000000000..a1ad2d1c9 --- /dev/null +++ b/test/grammar/lambda/closure_1/stdout.golden @@ -0,0 +1 @@ +x: 6 diff --git a/test/grammar/lambda/closure_10/main.k b/test/grammar/lambda/closure_10/main.k new file mode 100644 index 000000000..d0fa36e81 --- /dev/null +++ b/test/grammar/lambda/closure_10/main.k @@ -0,0 +1,14 @@ +func = lambda config: {str:} { + x = 1 + lambda { + y = 1 + lambda { + z = 1 + [lambda q { + {value = x + y + z + config.key + q + i} + }(1) for i in range(1, 2)][0] + }() + }() +} + +x = func({key = 1}) diff --git a/test/grammar/lambda/closure_10/stdout.golden b/test/grammar/lambda/closure_10/stdout.golden new file mode 100644 index 000000000..8094c6f61 --- /dev/null +++ b/test/grammar/lambda/closure_10/stdout.golden @@ -0,0 +1,2 @@ +x: + value: 6 diff --git a/test/grammar/lambda/closure_11/main.k b/test/grammar/lambda/closure_11/main.k new file mode 100644 index 000000000..5c7e6ff4c --- /dev/null +++ b/test/grammar/lambda/closure_11/main.k @@ -0,0 +1,5 @@ +b = 1 +# Use (i) to prevent the schema expr parse conflict +data = [lambda x, y=(i), z=(b) { + x + y + i +}(i) for i in [1, 2, 3]] diff --git a/test/grammar/lambda/closure_11/stdout.golden b/test/grammar/lambda/closure_11/stdout.golden new file mode 100644 index 000000000..901401250 --- /dev/null +++ b/test/grammar/lambda/closure_11/stdout.golden @@ -0,0 +1,5 @@ +b: 1 +data: +- 3 +- 6 +- 9 diff --git a/test/grammar/lambda/closure_1_annotation/main.k b/test/grammar/lambda/closure_1_annotation/main.k new file mode 100644 index 000000000..2311aa8e5 --- /dev/null +++ b/test/grammar/lambda/closure_1_annotation/main.k @@ -0,0 +1,7 @@ +x: int = lambda { + a = 1 + b = 2 + lambda x { + a + b + x + }(3) +}() diff --git a/test/grammar/lambda/closure_1_annotation/stdout.golden b/test/grammar/lambda/closure_1_annotation/stdout.golden new file mode 100644 index 000000000..a1ad2d1c9 --- /dev/null +++ b/test/grammar/lambda/closure_1_annotation/stdout.golden @@ -0,0 +1 @@ +x: 6 diff --git a/test/grammar/lambda/closure_2/main.k b/test/grammar/lambda/closure_2/main.k new file mode 100644 index 000000000..9713226ba --- /dev/null +++ b/test/grammar/lambda/closure_2/main.k @@ -0,0 +1,10 @@ +x = lambda { + a = 1 + lambda { + b = 2 + c = 3 + lambda a { + a + b + c + }(a) + }() +}() diff --git a/test/grammar/lambda/closure_2/stdout.golden b/test/grammar/lambda/closure_2/stdout.golden new file mode 100644 index 000000000..a1ad2d1c9 --- /dev/null +++ b/test/grammar/lambda/closure_2/stdout.golden @@ -0,0 +1 @@ +x: 6 diff --git a/test/grammar/lambda/closure_2_annotation/main.k b/test/grammar/lambda/closure_2_annotation/main.k new file mode 100644 index 000000000..c52ea6265 --- /dev/null +++ b/test/grammar/lambda/closure_2_annotation/main.k @@ -0,0 +1,10 @@ +x: int = lambda { + a = 1 + lambda { + b = 2 + c = 3 + lambda a { + a + b + c + }(a) + }() +}() diff --git a/test/grammar/lambda/closure_2_annotation/stdout.golden b/test/grammar/lambda/closure_2_annotation/stdout.golden new file mode 100644 index 000000000..a1ad2d1c9 --- /dev/null +++ b/test/grammar/lambda/closure_2_annotation/stdout.golden @@ -0,0 +1 @@ +x: 6 diff --git a/test/grammar/lambda/closure_3/main.k b/test/grammar/lambda/closure_3/main.k new file mode 100644 index 000000000..d9d3c6e8f --- /dev/null +++ b/test/grammar/lambda/closure_3/main.k @@ -0,0 +1,9 @@ +x = lambda { + a = 1 + lambda { + b = 2 + lambda a { + b + a + }(a) + }() +}() diff --git a/test/grammar/lambda/closure_3/stdout.golden b/test/grammar/lambda/closure_3/stdout.golden new file mode 100644 index 000000000..e5cfddc4f --- /dev/null +++ b/test/grammar/lambda/closure_3/stdout.golden @@ -0,0 +1 @@ +x: 3 diff --git a/test/grammar/lambda/closure_4/main.k b/test/grammar/lambda/closure_4/main.k new file mode 100644 index 000000000..d536211a2 --- /dev/null +++ b/test/grammar/lambda/closure_4/main.k @@ -0,0 +1,9 @@ +x = lambda { + a = 1 + lambda { + b = a + 1 + lambda { + c = b + 1 + }() + }() +}() diff --git a/test/grammar/lambda/closure_4/stdout.golden b/test/grammar/lambda/closure_4/stdout.golden new file mode 100644 index 000000000..e5cfddc4f --- /dev/null +++ b/test/grammar/lambda/closure_4/stdout.golden @@ -0,0 +1 @@ +x: 3 diff --git a/test/grammar/lambda/closure_4_annotation/main.k b/test/grammar/lambda/closure_4_annotation/main.k new file mode 100644 index 000000000..c19e4845a --- /dev/null +++ b/test/grammar/lambda/closure_4_annotation/main.k @@ -0,0 +1,9 @@ +x: int = lambda { + a = 1 + lambda { + b = a + 1 + lambda { + c = b + 1 + }() + }() +}() diff --git a/test/grammar/lambda/closure_4_annotation/stdout.golden b/test/grammar/lambda/closure_4_annotation/stdout.golden new file mode 100644 index 000000000..e5cfddc4f --- /dev/null +++ b/test/grammar/lambda/closure_4_annotation/stdout.golden @@ -0,0 +1 @@ +x: 3 diff --git a/test/grammar/lambda/closure_5/main.k b/test/grammar/lambda/closure_5/main.k new file mode 100644 index 000000000..d15138434 --- /dev/null +++ b/test/grammar/lambda/closure_5/main.k @@ -0,0 +1,12 @@ +x = lambda { + a = 1 + lambda { + b = a + 1 + lambda { + c = b + 1 + lambda { + d = c + 1 + }() + }() + }() +}() diff --git a/test/grammar/lambda/closure_5/stdout.golden b/test/grammar/lambda/closure_5/stdout.golden new file mode 100644 index 000000000..456a2f814 --- /dev/null +++ b/test/grammar/lambda/closure_5/stdout.golden @@ -0,0 +1 @@ +x: 4 diff --git a/test/grammar/lambda/closure_5_annotation/main.k b/test/grammar/lambda/closure_5_annotation/main.k new file mode 100644 index 000000000..24781567a --- /dev/null +++ b/test/grammar/lambda/closure_5_annotation/main.k @@ -0,0 +1,12 @@ +x: int = lambda { + a = 1 + lambda { + b = a + 1 + lambda { + c = b + 1 + lambda { + d = c + 1 + }() + }() + }() +}() diff --git a/test/grammar/lambda/closure_5_annotation/stdout.golden b/test/grammar/lambda/closure_5_annotation/stdout.golden new file mode 100644 index 000000000..456a2f814 --- /dev/null +++ b/test/grammar/lambda/closure_5_annotation/stdout.golden @@ -0,0 +1 @@ +x: 4 diff --git a/test/grammar/lambda/closure_6/main.k b/test/grammar/lambda/closure_6/main.k new file mode 100644 index 000000000..f1c0869a1 --- /dev/null +++ b/test/grammar/lambda/closure_6/main.k @@ -0,0 +1,14 @@ +func = lambda config: {str:} { + x = 1 + lambda { + y = 1 + lambda { + z = 1 + lambda { + x + y + z + config.key + }() + }() + }() +} + +x = func({key = 1}) diff --git a/test/grammar/lambda/closure_6/stdout.golden b/test/grammar/lambda/closure_6/stdout.golden new file mode 100644 index 000000000..456a2f814 --- /dev/null +++ b/test/grammar/lambda/closure_6/stdout.golden @@ -0,0 +1 @@ +x: 4 diff --git a/test/grammar/lambda/closure_7/main.k b/test/grammar/lambda/closure_7/main.k new file mode 100644 index 000000000..059a15ae7 --- /dev/null +++ b/test/grammar/lambda/closure_7/main.k @@ -0,0 +1,14 @@ +func = lambda config: {str:} { + x = 1 + lambda { + y = 1 + lambda { + z = 1 + lambda { + {value = x + y + z + config.key} + }() + }() + }() +} + +x = func({key = 1}) diff --git a/test/grammar/lambda/closure_7/stdout.golden b/test/grammar/lambda/closure_7/stdout.golden new file mode 100644 index 000000000..711dd9f7c --- /dev/null +++ b/test/grammar/lambda/closure_7/stdout.golden @@ -0,0 +1,2 @@ +x: + value: 4 diff --git a/test/grammar/lambda/closure_8/main.k b/test/grammar/lambda/closure_8/main.k new file mode 100644 index 000000000..a126e994f --- /dev/null +++ b/test/grammar/lambda/closure_8/main.k @@ -0,0 +1,8 @@ +items = [1, 2, 3] +func = lambda config: {str:} { + [lambda { + config.key + i + }() for i in items] +} + +x = func({key = 1}) diff --git a/test/grammar/lambda/closure_8/stdout.golden b/test/grammar/lambda/closure_8/stdout.golden new file mode 100644 index 000000000..30c4fe9ae --- /dev/null +++ b/test/grammar/lambda/closure_8/stdout.golden @@ -0,0 +1,8 @@ +items: +- 1 +- 2 +- 3 +x: +- 2 +- 3 +- 4 diff --git a/test/grammar/lambda/closure_9/main.k b/test/grammar/lambda/closure_9/main.k new file mode 100644 index 000000000..8a1084c5f --- /dev/null +++ b/test/grammar/lambda/closure_9/main.k @@ -0,0 +1,14 @@ +func = lambda config: {str:} { + x = 1 + lambda { + y = 1 + lambda { + z = 1 + lambda q { + {value = x + y + z + config.key + q} + }(1) + }() + }() +} + +x = func({key = 1}) diff --git a/test/grammar/lambda/closure_9/stdout.golden b/test/grammar/lambda/closure_9/stdout.golden new file mode 100644 index 000000000..963929266 --- /dev/null +++ b/test/grammar/lambda/closure_9/stdout.golden @@ -0,0 +1,2 @@ +x: + value: 5 diff --git a/test/grammar/lambda/in_diff_pkg/kcl.mod b/test/grammar/lambda/in_diff_pkg/kcl.mod new file mode 100644 index 000000000..c51d42cae --- /dev/null +++ b/test/grammar/lambda/in_diff_pkg/kcl.mod @@ -0,0 +1,2 @@ +[package] + diff --git a/test/grammar/lambda/in_diff_pkg/main.k b/test/grammar/lambda/in_diff_pkg/main.k new file mode 100644 index 000000000..bf3c78f93 --- /dev/null +++ b/test/grammar/lambda/in_diff_pkg/main.k @@ -0,0 +1,11 @@ +import .pkg + +f = lambda x, y { + pkg.f(x, y) +} +x0 = [ + (lambda x, y { + x + y + })(x, y) for x in [1, 2, 3] for y in [1, 2, 3] +] +x1 = [f(x, y) for x in [1, 2, 3] for y in [1, 2, 3]] diff --git a/test/grammar/lambda/in_diff_pkg/pkg/pkg.k b/test/grammar/lambda/in_diff_pkg/pkg/pkg.k new file mode 100644 index 000000000..e66060051 --- /dev/null +++ b/test/grammar/lambda/in_diff_pkg/pkg/pkg.k @@ -0,0 +1,3 @@ +f = lambda x, y { + x * y +} \ No newline at end of file diff --git a/test/grammar/lambda/in_diff_pkg/stdout.golden b/test/grammar/lambda/in_diff_pkg/stdout.golden new file mode 100644 index 000000000..fe09dbb02 --- /dev/null +++ b/test/grammar/lambda/in_diff_pkg/stdout.golden @@ -0,0 +1,20 @@ +x0: +- 2 +- 3 +- 4 +- 3 +- 4 +- 5 +- 4 +- 5 +- 6 +x1: +- 1 +- 2 +- 3 +- 2 +- 4 +- 6 +- 3 +- 6 +- 9 diff --git a/test/grammar/lambda/in_diff_pkg_annotation/kcl.mod b/test/grammar/lambda/in_diff_pkg_annotation/kcl.mod new file mode 100644 index 000000000..c51d42cae --- /dev/null +++ b/test/grammar/lambda/in_diff_pkg_annotation/kcl.mod @@ -0,0 +1,2 @@ +[package] + diff --git a/test/grammar/lambda/in_diff_pkg_annotation/main.k b/test/grammar/lambda/in_diff_pkg_annotation/main.k new file mode 100644 index 000000000..d05facd61 --- /dev/null +++ b/test/grammar/lambda/in_diff_pkg_annotation/main.k @@ -0,0 +1,11 @@ +import .pkg + +f: ( int , int ) -> int = lambda x, y { + pkg.f(x, y) +} +x0 = [ + (lambda x, y { + x + y + })(x, y) for x in [1, 2, 3] for y in [1, 2, 3] +] +x1 = [f(x, y) for x in [1, 2, 3] for y in [1, 2, 3]] diff --git a/test/grammar/lambda/in_diff_pkg_annotation/pkg/pkg.k b/test/grammar/lambda/in_diff_pkg_annotation/pkg/pkg.k new file mode 100644 index 000000000..8277643c6 --- /dev/null +++ b/test/grammar/lambda/in_diff_pkg_annotation/pkg/pkg.k @@ -0,0 +1,3 @@ +f: ( int , int ) -> int = lambda x, y { + x * y +} \ No newline at end of file diff --git a/test/grammar/lambda/in_diff_pkg_annotation/stdout.golden b/test/grammar/lambda/in_diff_pkg_annotation/stdout.golden new file mode 100644 index 000000000..fe09dbb02 --- /dev/null +++ b/test/grammar/lambda/in_diff_pkg_annotation/stdout.golden @@ -0,0 +1,20 @@ +x0: +- 2 +- 3 +- 4 +- 3 +- 4 +- 5 +- 4 +- 5 +- 6 +x1: +- 1 +- 2 +- 3 +- 2 +- 4 +- 6 +- 3 +- 6 +- 9 diff --git a/test/grammar/lambda/in_for_0_annotation/main.k b/test/grammar/lambda/in_for_0_annotation/main.k new file mode 100644 index 000000000..b270feba1 --- /dev/null +++ b/test/grammar/lambda/in_for_0_annotation/main.k @@ -0,0 +1,9 @@ +f: (int, int) -> int = lambda x, y { + x * y +} +x0 = [ + (lambda x, y { + x + y + })(x, y) for x in [1, 2, 3] for y in [1, 2, 3] +] +x1 = [f(x, y) for x in [1, 2, 3] for y in [1, 2, 3]] diff --git a/test/grammar/lambda/in_for_0_annotation/stdout.golden b/test/grammar/lambda/in_for_0_annotation/stdout.golden new file mode 100644 index 000000000..fe09dbb02 --- /dev/null +++ b/test/grammar/lambda/in_for_0_annotation/stdout.golden @@ -0,0 +1,20 @@ +x0: +- 2 +- 3 +- 4 +- 3 +- 4 +- 5 +- 4 +- 5 +- 6 +x1: +- 1 +- 2 +- 3 +- 2 +- 4 +- 6 +- 3 +- 6 +- 9 diff --git a/test/grammar/lambda/in_for_1_annotation/main.k b/test/grammar/lambda/in_for_1_annotation/main.k new file mode 100644 index 000000000..1fd25e3ed --- /dev/null +++ b/test/grammar/lambda/in_for_1_annotation/main.k @@ -0,0 +1,15 @@ +f: (int , int , int) -> int = lambda x, y, z { + x * y + z +} +schema Data: + val: int = 0 + x0 = [ + (lambda x, y, z { + x + y + })(x, y, val) for x in [1, 2] for y in [1, 2] + ] + x1 = [f(x, y, val) for x in [1, 2] for y in [1, 2]] + +data = Data { + val = 1 +} diff --git a/test/grammar/lambda/in_for_1_annotation/stdout.golden b/test/grammar/lambda/in_for_1_annotation/stdout.golden new file mode 100644 index 000000000..a647b35d4 --- /dev/null +++ b/test/grammar/lambda/in_for_1_annotation/stdout.golden @@ -0,0 +1,12 @@ +data: + val: 1 + x0: + - 2 + - 3 + - 3 + - 4 + x1: + - 2 + - 3 + - 3 + - 5 diff --git a/test/grammar/lambda/in_for_2_annotation/main.k b/test/grammar/lambda/in_for_2_annotation/main.k new file mode 100644 index 000000000..1aebec3ba --- /dev/null +++ b/test/grammar/lambda/in_for_2_annotation/main.k @@ -0,0 +1,12 @@ +data0: int = (lambda x, y { + z = x * 2 + z + y +})(1, 1) + +schema Data: + data = [(lambda x, y { + _z = 2 * x + _z = _z + y + })(x, y) for x in [1, 2] for y in [1, 2]] + +data = Data() diff --git a/test/grammar/lambda/in_for_2_annotation/stdout.golden b/test/grammar/lambda/in_for_2_annotation/stdout.golden new file mode 100644 index 000000000..144005631 --- /dev/null +++ b/test/grammar/lambda/in_for_2_annotation/stdout.golden @@ -0,0 +1,7 @@ +data0: 3 +data: + data: + - 3 + - 4 + - 5 + - 6 diff --git a/test/grammar/lambda/in_for_3/main.k b/test/grammar/lambda/in_for_3/main.k new file mode 100644 index 000000000..465edf194 --- /dev/null +++ b/test/grammar/lambda/in_for_3/main.k @@ -0,0 +1,15 @@ +ll0 = [lambda { + i + 1 +}() for i in range(2)] +ll1 = [lambda { + lambda { + i + 1 + }() +}() for i in range(2)] +ll3 = [lambda { + lambda { + lambda { + i + 1 + }() + }() +}() for i in range(2)] diff --git a/test/grammar/lambda/in_for_3/stdout.golden b/test/grammar/lambda/in_for_3/stdout.golden new file mode 100644 index 000000000..7eea1f63f --- /dev/null +++ b/test/grammar/lambda/in_for_3/stdout.golden @@ -0,0 +1,9 @@ +ll0: +- 1 +- 2 +ll1: +- 1 +- 2 +ll3: +- 1 +- 2 diff --git a/test/grammar/lambda/in_pkg_0_annotation/kcl.mod b/test/grammar/lambda/in_pkg_0_annotation/kcl.mod new file mode 100644 index 000000000..e69de29bb diff --git a/test/grammar/lambda/in_pkg_0_annotation/main.k b/test/grammar/lambda/in_pkg_0_annotation/main.k new file mode 100644 index 000000000..1e1157f63 --- /dev/null +++ b/test/grammar/lambda/in_pkg_0_annotation/main.k @@ -0,0 +1,7 @@ +import pkg + +func = pkg.func +a = pkg.a +b = pkg.b +c = func(1, 1) +d = func("1", "1") diff --git a/test/grammar/lambda/in_pkg_0_annotation/pkg/pkg.k b/test/grammar/lambda/in_pkg_0_annotation/pkg/pkg.k new file mode 100644 index 000000000..1743cf95a --- /dev/null +++ b/test/grammar/lambda/in_pkg_0_annotation/pkg/pkg.k @@ -0,0 +1,5 @@ +func:(int|str, int|str) -> int = lambda x: int | str, y: int | str { + int(x) + int(y) +} +a = func(1, 1) +b = func("1", "1") diff --git a/test/grammar/lambda/in_pkg_0_annotation/stdout.golden b/test/grammar/lambda/in_pkg_0_annotation/stdout.golden new file mode 100644 index 000000000..b9996f995 --- /dev/null +++ b/test/grammar/lambda/in_pkg_0_annotation/stdout.golden @@ -0,0 +1,4 @@ +a: 2 +b: 2 +c: 2 +d: 2 diff --git a/test/grammar/lambda/in_pkg_1_annotation/kcl.mod b/test/grammar/lambda/in_pkg_1_annotation/kcl.mod new file mode 100644 index 000000000..e69de29bb diff --git a/test/grammar/lambda/in_pkg_1_annotation/main.k b/test/grammar/lambda/in_pkg_1_annotation/main.k new file mode 100644 index 000000000..1e1157f63 --- /dev/null +++ b/test/grammar/lambda/in_pkg_1_annotation/main.k @@ -0,0 +1,7 @@ +import pkg + +func = pkg.func +a = pkg.a +b = pkg.b +c = func(1, 1) +d = func("1", "1") diff --git a/test/grammar/lambda/in_pkg_1_annotation/pkg/pkg.k b/test/grammar/lambda/in_pkg_1_annotation/pkg/pkg.k new file mode 100644 index 000000000..99305feb2 --- /dev/null +++ b/test/grammar/lambda/in_pkg_1_annotation/pkg/pkg.k @@ -0,0 +1,8 @@ +global = 1 +func: ( int|str, int|str ) -> int = lambda x: int | str, y: int | str { + (lambda x, y { + int(x) + int(y) + global + })(x, y) +} +a = func(1, 1) +b = func("1", "1") diff --git a/test/grammar/lambda/in_pkg_1_annotation/stdout.golden b/test/grammar/lambda/in_pkg_1_annotation/stdout.golden new file mode 100644 index 000000000..b899d7959 --- /dev/null +++ b/test/grammar/lambda/in_pkg_1_annotation/stdout.golden @@ -0,0 +1,4 @@ +a: 3 +b: 3 +c: 3 +d: 3 diff --git a/test/grammar/lambda/in_schema_0_annotation/main.k b/test/grammar/lambda/in_schema_0_annotation/main.k new file mode 100644 index 000000000..1084b9556 --- /dev/null +++ b/test/grammar/lambda/in_schema_0_annotation/main.k @@ -0,0 +1,12 @@ +schema Data: + var: int = 1 + _func: (int|str, int|str) -> int = lambda x: int | str, y: int | str { + (lambda x, y { + int(x) + int(y) + var + })(x, y) + } + + a = _func(1, 1) + b = _func("123", "456") + +data = Data() diff --git a/test/grammar/lambda/in_schema_0_annotation/stdout.golden b/test/grammar/lambda/in_schema_0_annotation/stdout.golden new file mode 100644 index 000000000..32df9eb86 --- /dev/null +++ b/test/grammar/lambda/in_schema_0_annotation/stdout.golden @@ -0,0 +1,4 @@ +data: + var: 1 + a: 3 + b: 580 diff --git a/test/grammar/lambda/in_schema_10/main.k b/test/grammar/lambda/in_schema_10/main.k new file mode 100644 index 000000000..6d25576be --- /dev/null +++ b/test/grammar/lambda/in_schema_10/main.k @@ -0,0 +1,22 @@ +schema Job: + name: str + + createResource: () -> CronJob = lambda { + lambda { + CronJob { + name = name + } + }() + } + getName: () -> str = lambda { + lambda {name}() + } + +schema CronJob: + name?: str + +myJob = Job { + name = "myJob" +} +myCronJob = myJob.createResource() +name = myJob.getName() diff --git a/test/grammar/lambda/in_schema_10/stdout.golden b/test/grammar/lambda/in_schema_10/stdout.golden new file mode 100644 index 000000000..1d82bd8f2 --- /dev/null +++ b/test/grammar/lambda/in_schema_10/stdout.golden @@ -0,0 +1,5 @@ +myJob: + name: myJob +myCronJob: + name: myJob +name: myJob diff --git a/test/grammar/lambda/in_schema_11/main.k b/test/grammar/lambda/in_schema_11/main.k new file mode 100644 index 000000000..17dd6d27e --- /dev/null +++ b/test/grammar/lambda/in_schema_11/main.k @@ -0,0 +1,20 @@ +protocol StringProtocol: + s: str + +mixin StringMixin for StringProtocol: + add = lambda pref: str { + pref + s + } + +schema String: + mixin [StringMixin] + s: str + add: (str) -> str + +s1 = String { s: "hello" } +s2 = String { s: "world" } + +output = { + s1_add: s1.add("foo ") + s2_add: s2.add("bar ") +} diff --git a/test/grammar/lambda/in_schema_11/stdout.golden b/test/grammar/lambda/in_schema_11/stdout.golden new file mode 100644 index 000000000..805dc3246 --- /dev/null +++ b/test/grammar/lambda/in_schema_11/stdout.golden @@ -0,0 +1,7 @@ +s1: + s: hello +s2: + s: world +output: + s1_add: foo hello + s2_add: bar world diff --git a/test/grammar/lambda/in_schema_1_annotation/main.k b/test/grammar/lambda/in_schema_1_annotation/main.k new file mode 100644 index 000000000..e5d0061b9 --- /dev/null +++ b/test/grammar/lambda/in_schema_1_annotation/main.k @@ -0,0 +1,14 @@ +global: int = 10 + +schema Data: + var: int = 1 + _func = lambda x: int | str, y: int | str { + (lambda x, y { + int(x) + int(y) + var + global + })(x, y) + } + + a = _func(1, 1) + b = _func("123", "456") + +data = Data() diff --git a/test/grammar/lambda/in_schema_1_annotation/stdout.golden b/test/grammar/lambda/in_schema_1_annotation/stdout.golden new file mode 100644 index 000000000..50ae2ab28 --- /dev/null +++ b/test/grammar/lambda/in_schema_1_annotation/stdout.golden @@ -0,0 +1,5 @@ +global: 10 +data: + var: 1 + a: 13 + b: 590 diff --git a/test/grammar/lambda/in_schema_2_annotation/main.k b/test/grammar/lambda/in_schema_2_annotation/main.k new file mode 100644 index 000000000..3fa3a3975 --- /dev/null +++ b/test/grammar/lambda/in_schema_2_annotation/main.k @@ -0,0 +1,15 @@ +global: int = 10 + +schema Data: + var: int = 1 + _func: (int|str, int|str) -> int = lambda x: int | str, y: int | str { + (lambda x, y { + _val = int(x) + int(y) + _val = _val + var + global + })(x, y) + } + + a = _func(1, 1) + b = _func("123", "456") + +data = Data() diff --git a/test/grammar/lambda/in_schema_2_annotation/stdout.golden b/test/grammar/lambda/in_schema_2_annotation/stdout.golden new file mode 100644 index 000000000..50ae2ab28 --- /dev/null +++ b/test/grammar/lambda/in_schema_2_annotation/stdout.golden @@ -0,0 +1,5 @@ +global: 10 +data: + var: 1 + a: 13 + b: 590 diff --git a/test/grammar/lambda/in_schema_5/main.k b/test/grammar/lambda/in_schema_5/main.k new file mode 100644 index 000000000..e0dec3f90 --- /dev/null +++ b/test/grammar/lambda/in_schema_5/main.k @@ -0,0 +1,16 @@ +# Issue 1078 +# Errors caused by deep copy of circular references within schema and schema lambda +schema A: + a: int = 1 + f = lambda { + a + } + +schema B[a: A]: + +C = lambda a: A { +} +a = A {} + +C(a) +B(a) diff --git a/test/grammar/lambda/in_schema_5/stdout.golden b/test/grammar/lambda/in_schema_5/stdout.golden new file mode 100644 index 000000000..f410a92b7 --- /dev/null +++ b/test/grammar/lambda/in_schema_5/stdout.golden @@ -0,0 +1,2 @@ +a: + a: 1 diff --git a/test/grammar/lambda/in_schema_6/main.k b/test/grammar/lambda/in_schema_6/main.k new file mode 100644 index 000000000..33259269a --- /dev/null +++ b/test/grammar/lambda/in_schema_6/main.k @@ -0,0 +1,9 @@ +schema Name: + y: int = 2 + z: int = lambda x { + y = 1 + z = y + 1 # y is 1 instead of 2 + }(1) + + +n = Name {} diff --git a/test/grammar/lambda/in_schema_6/stdout.golden b/test/grammar/lambda/in_schema_6/stdout.golden new file mode 100644 index 000000000..e338aaaa7 --- /dev/null +++ b/test/grammar/lambda/in_schema_6/stdout.golden @@ -0,0 +1,3 @@ +n: + y: 2 + z: 2 diff --git a/test/grammar/lambda/in_schema_7/main.k b/test/grammar/lambda/in_schema_7/main.k new file mode 100644 index 000000000..9c000f117 --- /dev/null +++ b/test/grammar/lambda/in_schema_7/main.k @@ -0,0 +1,10 @@ +schema Name: + y: {str:str} = {} + z: {str:str} = lambda x { + y: {str:str} = {} + y.key = x + y + }("value") + + +n = Name {} diff --git a/test/grammar/lambda/in_schema_7/stdout.golden b/test/grammar/lambda/in_schema_7/stdout.golden new file mode 100644 index 000000000..af6136c94 --- /dev/null +++ b/test/grammar/lambda/in_schema_7/stdout.golden @@ -0,0 +1,4 @@ +n: + y: {} + z: + key: value diff --git a/test/grammar/lambda/in_schema_8/main.k b/test/grammar/lambda/in_schema_8/main.k new file mode 100644 index 000000000..0aff96ec2 --- /dev/null +++ b/test/grammar/lambda/in_schema_8/main.k @@ -0,0 +1,8 @@ +x: int = 1 +schema Name: + x: int = 2 + z: int = lambda a { + a + x # x is the schema x instead of global x + }(2) + +n = Name {} diff --git a/test/grammar/lambda/in_schema_8/stdout.golden b/test/grammar/lambda/in_schema_8/stdout.golden new file mode 100644 index 000000000..3a1d53e25 --- /dev/null +++ b/test/grammar/lambda/in_schema_8/stdout.golden @@ -0,0 +1,4 @@ +x: 1 +n: + x: 2 + z: 4 diff --git a/test/grammar/lambda/in_schema_9/main.k b/test/grammar/lambda/in_schema_9/main.k new file mode 100644 index 000000000..fd2120c62 --- /dev/null +++ b/test/grammar/lambda/in_schema_9/main.k @@ -0,0 +1,20 @@ +schema Job: + name: str + + createResource: () -> CronJob = lambda { + CronJob { + name = name + } + } + getName: () -> str = lambda { + name + } + +schema CronJob: + name?: str + +myJob = Job { + name = "myJob" +} +myCronJob = myJob.createResource() +name = myJob.getName() diff --git a/test/grammar/lambda/in_schema_9/stdout.golden b/test/grammar/lambda/in_schema_9/stdout.golden new file mode 100644 index 000000000..1d82bd8f2 --- /dev/null +++ b/test/grammar/lambda/in_schema_9/stdout.golden @@ -0,0 +1,5 @@ +myJob: + name: myJob +myCronJob: + name: myJob +name: myJob diff --git a/test/grammar/lambda/top_level_0_annotation/main.k b/test/grammar/lambda/top_level_0_annotation/main.k new file mode 100644 index 000000000..9b9aa1bc4 --- /dev/null +++ b/test/grammar/lambda/top_level_0_annotation/main.k @@ -0,0 +1,5 @@ +func:(int|str, int|str) -> int = lambda x: int | str, y: int | str { + int(x) + int(y) +} +a = func(1, 1) +b = func("123", "456") diff --git a/test/grammar/lambda/top_level_0_annotation/stdout.golden b/test/grammar/lambda/top_level_0_annotation/stdout.golden new file mode 100644 index 000000000..73f656a99 --- /dev/null +++ b/test/grammar/lambda/top_level_0_annotation/stdout.golden @@ -0,0 +1,2 @@ +a: 2 +b: 579 diff --git a/test/grammar/lambda/top_level_10/main.k b/test/grammar/lambda/top_level_10/main.k new file mode 100644 index 000000000..e19683dd1 --- /dev/null +++ b/test/grammar/lambda/top_level_10/main.k @@ -0,0 +1,11 @@ +f = lambda { + x = 1 + lambda { + y = 2 + lambda { + x + y + } + } +} +ff = f()() +x = ff() diff --git a/test/grammar/lambda/top_level_10/stdout.golden b/test/grammar/lambda/top_level_10/stdout.golden new file mode 100644 index 000000000..e5cfddc4f --- /dev/null +++ b/test/grammar/lambda/top_level_10/stdout.golden @@ -0,0 +1 @@ +x: 3 diff --git a/test/grammar/lambda/top_level_11/main.k b/test/grammar/lambda/top_level_11/main.k new file mode 100644 index 000000000..dd121f7d2 --- /dev/null +++ b/test/grammar/lambda/top_level_11/main.k @@ -0,0 +1,16 @@ +global: int = 10 + +schema Data: + var: int = 1 + _func = lambda x: int | str, y: int | str { + (lambda x, y { + int(x) + int(y) + var + global + })(x, y) + } + + a = _func(1, 1) + b = _func("123", "456") + func: (int | str, int | str) = _func + +data = Data() +value = data.func(1, 1) diff --git a/test/grammar/lambda/top_level_11/stdout.golden b/test/grammar/lambda/top_level_11/stdout.golden new file mode 100644 index 000000000..b5a9071d5 --- /dev/null +++ b/test/grammar/lambda/top_level_11/stdout.golden @@ -0,0 +1,6 @@ +global: 10 +data: + var: 1 + a: 13 + b: 590 +value: 13 diff --git a/test/grammar/lambda/top_level_1_annotation/main.k b/test/grammar/lambda/top_level_1_annotation/main.k new file mode 100644 index 000000000..b46bd254f --- /dev/null +++ b/test/grammar/lambda/top_level_1_annotation/main.k @@ -0,0 +1,7 @@ +func: (int|str, int|str) -> int = lambda x: int | str, y: int | str { + (lambda x, y { + int(x) + int(y) + })(x, y) +} +a = func(1, 1) +b = func("123", "456") diff --git a/test/grammar/lambda/top_level_1_annotation/stdout.golden b/test/grammar/lambda/top_level_1_annotation/stdout.golden new file mode 100644 index 000000000..73f656a99 --- /dev/null +++ b/test/grammar/lambda/top_level_1_annotation/stdout.golden @@ -0,0 +1,2 @@ +a: 2 +b: 579 diff --git a/test/grammar/lambda/top_level_2_annotation/main.k b/test/grammar/lambda/top_level_2_annotation/main.k new file mode 100644 index 000000000..c6e6f5718 --- /dev/null +++ b/test/grammar/lambda/top_level_2_annotation/main.k @@ -0,0 +1,8 @@ +func: (int|str, int|str) -> int = lambda x: int | str, y: int | str { + (lambda x, y { + int(x) + int(y) + })(x, y) +} +afunc = func +a = afunc(1, 1) +b = afunc("123", "456") diff --git a/test/grammar/lambda/top_level_2_annotation/stdout.golden b/test/grammar/lambda/top_level_2_annotation/stdout.golden new file mode 100644 index 000000000..73f656a99 --- /dev/null +++ b/test/grammar/lambda/top_level_2_annotation/stdout.golden @@ -0,0 +1,2 @@ +a: 2 +b: 579 diff --git a/test/grammar/lambda/top_level_4_annotation/main.k b/test/grammar/lambda/top_level_4_annotation/main.k new file mode 100644 index 000000000..39f35d46a --- /dev/null +++ b/test/grammar/lambda/top_level_4_annotation/main.k @@ -0,0 +1,9 @@ +f:({str:}) -> {str:} = lambda x: {str:} -> {str:} { + 1 + _x = 1 + { + x = _x + } +} + +x = f({data = [1]}) diff --git a/test/grammar/lambda/top_level_4_annotation/stdout.golden b/test/grammar/lambda/top_level_4_annotation/stdout.golden new file mode 100644 index 000000000..6f947823f --- /dev/null +++ b/test/grammar/lambda/top_level_4_annotation/stdout.golden @@ -0,0 +1,2 @@ +x: + x: 1 diff --git a/test/grammar/lambda/top_level_5_annotation/main.k b/test/grammar/lambda/top_level_5_annotation/main.k new file mode 100644 index 000000000..d3725aa2f --- /dev/null +++ b/test/grammar/lambda/top_level_5_annotation/main.k @@ -0,0 +1,4 @@ +f: () -> int = lambda -> int { + 1 +} +x = f() diff --git a/test/grammar/lambda/top_level_5_annotation/stdout.golden b/test/grammar/lambda/top_level_5_annotation/stdout.golden new file mode 100644 index 000000000..d508cf756 --- /dev/null +++ b/test/grammar/lambda/top_level_5_annotation/stdout.golden @@ -0,0 +1 @@ +x: 1 diff --git a/test/grammar/lambda/top_level_7/main.k b/test/grammar/lambda/top_level_7/main.k new file mode 100644 index 000000000..c7dfef9a6 --- /dev/null +++ b/test/grammar/lambda/top_level_7/main.k @@ -0,0 +1,21 @@ +_looper_n = lambda elements: [any], n: int, func: (any, any) -> any, initial: any-> any { + assert n >= 0 + result = initial + if n < len(elements): + result = _looper_n(elements, n + 1, func, func(result, elements[n])) + result +} + +looper = lambda initial: any, elements: [any], func: (any, any) -> any -> any { + _looper_n(elements, 0, func, initial) +} + +for_each = lambda elements: [any], func: (any) -> any { + _looper_n(elements, 0, lambda v, e { + func(e) + }, Undefined) +} + +x = looper(0, [1, 2, 3], lambda i, x { + i + x +}) diff --git a/test/grammar/lambda/top_level_7/stdout.golden b/test/grammar/lambda/top_level_7/stdout.golden new file mode 100644 index 000000000..a1ad2d1c9 --- /dev/null +++ b/test/grammar/lambda/top_level_7/stdout.golden @@ -0,0 +1 @@ +x: 6 diff --git a/test/grammar/lambda/top_level_8/main.k b/test/grammar/lambda/top_level_8/main.k new file mode 100644 index 000000000..d16290899 --- /dev/null +++ b/test/grammar/lambda/top_level_8/main.k @@ -0,0 +1,10 @@ + +func1 = lambda x { + x +} + +func2 = lambda e, func: (any) -> any { + func(e) +} + +x = func2(1, func1) diff --git a/test/grammar/lambda/top_level_8/stdout.golden b/test/grammar/lambda/top_level_8/stdout.golden new file mode 100644 index 000000000..d508cf756 --- /dev/null +++ b/test/grammar/lambda/top_level_8/stdout.golden @@ -0,0 +1 @@ +x: 1 diff --git a/test/grammar/lambda/top_level_9/main.k b/test/grammar/lambda/top_level_9/main.k new file mode 100644 index 000000000..c8e638752 --- /dev/null +++ b/test/grammar/lambda/top_level_9/main.k @@ -0,0 +1,20 @@ +_looper_n = lambda elements: [any], n: int, func: (any, any) -> any, initial: any -> any { + assert n >= 0 + result = initial + if n < len(elements): + result = _looper_n(elements, n + 1, func, func(result, elements[n])) + result +} + +looper = lambda initial: any, elements: [any], func: (any, any) -> any -> any { + _looper_n(elements, 0, func, initial) +} + +for_each = lambda elements: [any], func: (any) -> any { + _looper_n(elements, 0, lambda v, e { func(e) }, Undefined) +} + +x = for_each([1, 2, 3], lambda x { + # Do something + x +}) diff --git a/test/grammar/lambda/top_level_9/stdout.golden b/test/grammar/lambda/top_level_9/stdout.golden new file mode 100644 index 000000000..e5cfddc4f --- /dev/null +++ b/test/grammar/lambda/top_level_9/stdout.golden @@ -0,0 +1 @@ +x: 3 diff --git a/test/grammar/lambda/type_annotation/schema/invalid_0/main.k b/test/grammar/lambda/type_annotation/schema/invalid_0/main.k new file mode 100644 index 000000000..e1d07ec55 --- /dev/null +++ b/test/grammar/lambda/type_annotation/schema/invalid_0/main.k @@ -0,0 +1,16 @@ +schema ProviderFamily: + version: str + marketplace: bool = True + +providerFamily = lambda family: ProviderFamily -> ProviderFamily { + { + **family + version: 1 + hello: "world" + } +} + +v = providerFamily({ + version: 1 + hello: "world" +}) diff --git a/test/grammar/lambda/type_annotation/schema/invalid_0/stderr.golden b/test/grammar/lambda/type_annotation/schema/invalid_0/stderr.golden new file mode 100644 index 000000000..9224a44f0 --- /dev/null +++ b/test/grammar/lambda/type_annotation/schema/invalid_0/stderr.golden @@ -0,0 +1,39 @@ +error[E2G22]: TypeError + --> ${CWD}/main.k:8:9 + | +8 | version: 1 + | ^ expected str, got int(1) + | + + --> ${CWD}/main.k:2:5 + | +2 | version: str + | ^ variable is defined here, its type is str, but got int(1) + | + +error[E2L23]: CompileError + --> ${CWD}/main.k:9:9 + | +9 | hello: "world" + | ^ Cannot add member 'hello' to schema 'ProviderFamily' + | + +error[E2G22]: TypeError + --> ${CWD}/main.k:14:5 + | +14 | version: 1 + | ^ expected str, got int(1) + | + + --> ${CWD}/main.k:2:5 + | +2 | version: str + | ^ variable is defined here, its type is str, but got int(1) + | + +error[E2L23]: CompileError + --> ${CWD}/main.k:15:5 + | +15 | hello: "world" + | ^ Cannot add member 'hello' to schema 'ProviderFamily' + | \ No newline at end of file diff --git a/test/grammar/lambda/type_annotation/schema/invalid_1/main.k b/test/grammar/lambda/type_annotation/schema/invalid_1/main.k new file mode 100644 index 000000000..b7463726d --- /dev/null +++ b/test/grammar/lambda/type_annotation/schema/invalid_1/main.k @@ -0,0 +1,17 @@ +schema ProviderFamily: + [...str]: int + version: str + marketplace: bool = True + +providerFamily = lambda family: ProviderFamily -> ProviderFamily { + { + **family + version: 1 + hello: "world" + } +} + +v = providerFamily({ + version: 1 + hello: "world" +}) diff --git a/test/grammar/lambda/type_annotation/schema/invalid_1/stderr.golden b/test/grammar/lambda/type_annotation/schema/invalid_1/stderr.golden new file mode 100644 index 000000000..f3b53e884 --- /dev/null +++ b/test/grammar/lambda/type_annotation/schema/invalid_1/stderr.golden @@ -0,0 +1,19 @@ +error[E2G22]: TypeError + --> ${CWD}/main.k:9:9 + | +9 | version: 1 + | ^ expected str, got int(1) + | + + --> ${CWD}/main.k:3:5 + | +3 | version: str + | ^ variable is defined here, its type is str, but got int(1) + | + +error[E2G22]: TypeError + --> ${CWD}/main.k:10:9 + | +10 | hello: "world" + | ^ expected int, got str(world) + | diff --git a/test/grammar/misc/empty_file/stdout.golden b/test/grammar/misc/empty_file/stdout.golden index e69de29bb..9e26dfeeb 100644 --- a/test/grammar/misc/empty_file/stdout.golden +++ b/test/grammar/misc/empty_file/stdout.golden @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/test/grammar/misc/empty_plan/main.k b/test/grammar/misc/empty_plan/main.k new file mode 100644 index 000000000..1a3e4dbcc --- /dev/null +++ b/test/grammar/misc/empty_plan/main.k @@ -0,0 +1,2 @@ +# _a is a hidden attribute. +_a = 1 diff --git a/test/grammar/misc/empty_plan/stdout.golden b/test/grammar/misc/empty_plan/stdout.golden new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/test/grammar/misc/empty_plan/stdout.golden @@ -0,0 +1 @@ +{} diff --git a/test/grammar/multi_file_compilation/invalid/invalid_0/stderr.golden b/test/grammar/multi_file_compilation/invalid/invalid_0/stderr.golden new file mode 100644 index 000000000..7050e975b --- /dev/null +++ b/test/grammar/multi_file_compilation/invalid/invalid_0/stderr.golden @@ -0,0 +1,18 @@ +error[E1001]: ImmutableError + --> ${CWD}/pkg.k:1:1 + | +1 | list_data = 1 + | ^ Can not change the value of 'list_data', because it was declared immutable + | + --> ${CWD}/main.k:1:1 + | +1 | list_data = [1, 2, 3] + | ^ The variable 'list_data' is declared here + | +note: change the variable name to '_list_data' to make it mutable +error[E2G22]: TypeError + --> ${CWD}/pkg.k:1:1 + | +1 | list_data = 1 + | ^ expected [int], got int(1) + | \ No newline at end of file diff --git a/test/grammar/multi_file_compilation/invalid/invalid_0/stderr.golden.py b/test/grammar/multi_file_compilation/invalid/invalid_0/stderr.golden.py deleted file mode 100644 index 412c13ee0..000000000 --- a/test/grammar/multi_file_compilation/invalid/invalid_0/stderr.golden.py +++ /dev/null @@ -1,20 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.ImmutableCompileError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/pkg.k", - line_no=1, - col_no=1 - ) - ], - ), - file=sys.stdout -) - diff --git a/test/grammar/multi_file_compilation/invalid/invalid_1/stderr.golden b/test/grammar/multi_file_compilation/invalid/invalid_1/stderr.golden new file mode 100644 index 000000000..bd4399fea --- /dev/null +++ b/test/grammar/multi_file_compilation/invalid/invalid_1/stderr.golden @@ -0,0 +1,11 @@ +error[E2G22]: TypeError + --> ${CWD}/pkg.k:3:5 + | +3 | age: "18" + | ^ expected int, got str(18) + | + --> ${CWD}/main.k:3:5 + | +3 | age: int + | ^ variable is defined here, its type is int, but got str(18) + | \ No newline at end of file diff --git a/test/grammar/multi_file_compilation/invalid/invalid_1/stderr.golden.py b/test/grammar/multi_file_compilation/invalid/invalid_1/stderr.golden.py deleted file mode 100644 index f88f1fe78..000000000 --- a/test/grammar/multi_file_compilation/invalid/invalid_1/stderr.golden.py +++ /dev/null @@ -1,30 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.TypeError_Compile_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=3, - col_no=5, - indent_count=1, - arg_msg="expect int", - err_level=kcl_error.ErrLevel.ORDINARY - ), - kcl_error.ErrFileMsg( - filename=cwd + "/pkg.k", - line_no=3, - col_no=5, - arg_msg="got str(18)" - ) - ], - arg_msg="expect int, got str(18)" - ), - file=sys.stdout -) - diff --git a/test/grammar/multi_file_compilation/invalid/invalid_2/stderr.golden b/test/grammar/multi_file_compilation/invalid/invalid_2/stderr.golden new file mode 100644 index 000000000..d15cde6f7 --- /dev/null +++ b/test/grammar/multi_file_compilation/invalid/invalid_2/stderr.golden @@ -0,0 +1,12 @@ +error[E1001]: ImmutableError + --> ${CWD}/pkg2.k:1:1 + | +1 | a = 3 + | ^ Can not change the value of 'a', because it was declared immutable + | + --> ${CWD}/pkg1.k:1:1 + | +1 | a = _a + | ^ The variable 'a' is declared here + | +note: change the variable name to '_a' to make it mutable \ No newline at end of file diff --git a/test/grammar/multi_file_compilation/invalid/invalid_2/stderr.golden.py b/test/grammar/multi_file_compilation/invalid/invalid_2/stderr.golden.py deleted file mode 100644 index afe307785..000000000 --- a/test/grammar/multi_file_compilation/invalid/invalid_2/stderr.golden.py +++ /dev/null @@ -1,20 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.ImmutableCompileError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/pkg2.k", - line_no=1, - col_no=1 - ) - ], - ), - file=sys.stdout -) - diff --git a/test/grammar/multi_file_compilation/simple/simple_2/pkg.k b/test/grammar/multi_file_compilation/simple/simple_2/pkg.k index 1efb4fa00..59a2c882c 100644 --- a/test/grammar/multi_file_compilation/simple/simple_2/pkg.k +++ b/test/grammar/multi_file_compilation/simple/simple_2/pkg.k @@ -1,4 +1,4 @@ -_list_data |= [1] -_dict_data |= {"key2": "value2"} +_list_data = [1] +_dict_data = {"key2": "value2"} list_data = _list_data dict_data = _dict_data diff --git a/test/grammar/multi_file_compilation/simple/simple_2/stdout.golden b/test/grammar/multi_file_compilation/simple/simple_2/stdout.golden index 1b09e3109..88bd44ec7 100644 --- a/test/grammar/multi_file_compilation/simple/simple_2/stdout.golden +++ b/test/grammar/multi_file_compilation/simple/simple_2/stdout.golden @@ -2,5 +2,4 @@ var: 1 list_data: - 1 dict_data: - key1: value1 key2: value2 diff --git a/test/grammar/nest_var/nest_var_fail_0/stderr.golden b/test/grammar/nest_var/nest_var_fail_0/stderr.golden new file mode 100644 index 000000000..481bbec6d --- /dev/null +++ b/test/grammar/nest_var/nest_var_fail_0/stderr.golden @@ -0,0 +1,11 @@ +error[E2G22]: TypeError + --> ${CWD}/main.k:5:5 + | +5 | name.name: "Alice" + | ^ expected str, got {str(name):str(Alice)} + | + --> ${CWD}/main.k:2:5 + | +2 | name: str + | ^ variable is defined here, its type is str, but got {str(name):str(Alice)} + | \ No newline at end of file diff --git a/test/grammar/nest_var/nest_var_fail_0/stderr.golden.py b/test/grammar/nest_var/nest_var_fail_0/stderr.golden.py deleted file mode 100644 index 375e24f9b..000000000 --- a/test/grammar/nest_var/nest_var_fail_0/stderr.golden.py +++ /dev/null @@ -1,30 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.TypeError_Compile_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=2, - col_no=5, - indent_count=1, - arg_msg="expect str", - err_level=kcl_error.ErrLevel.ORDINARY - ), - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=5, - col_no=5, - arg_msg="got {str(name):str(Alice)}" - ) - ], - arg_msg="expect str, got {str(name):str(Alice)}" - ), - file=sys.stdout -) - diff --git a/test/grammar/nest_var/nest_var_fail_1/stderr.golden b/test/grammar/nest_var/nest_var_fail_1/stderr.golden new file mode 100644 index 000000000..82f3510f2 --- /dev/null +++ b/test/grammar/nest_var/nest_var_fail_1/stderr.golden @@ -0,0 +1,6 @@ +error[E2L23]: CompileError + --> ${CWD}/main.k:8:10 + | +8 | name.err_name: "Alice" + | ^ Cannot add member 'err_name' to schema 'Name' + | \ No newline at end of file diff --git a/test/grammar/nest_var/nest_var_fail_1/stderr.golden.py b/test/grammar/nest_var/nest_var_fail_1/stderr.golden.py deleted file mode 100644 index c541677e3..000000000 --- a/test/grammar/nest_var/nest_var_fail_1/stderr.golden.py +++ /dev/null @@ -1,20 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception(err_type=kcl_error.ErrType.CannotAddMembers_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=8, - col_no=5, - arg_msg="'err_name' is not defined in schema 'Name'" - ), - ], - arg_msg="Cannot add member 'err_name' to schema 'Name'") - , file=sys.stdout -) - diff --git a/test/grammar/option/complex_type_option/settings.yaml b/test/grammar/option/complex_type_option/settings.yaml index 87b5c02f2..03cd766f1 100644 --- a/test/grammar/option/complex_type_option/settings.yaml +++ b/test/grammar/option/complex_type_option/settings.yaml @@ -1 +1 @@ -kcl_options: -D key1=val -D key2=2 -D key3=4.4 -D key4=[1,2,3] -D key5={'key':'value'} -S :app.value +kcl_options: -D key1=val -D key2=2 -D key3=4.4 -D key4=[1,2,3] -D key5={"key":"value"} diff --git a/test/grammar/option/file_options/main.k b/test/grammar/option/file_options/_main.k similarity index 100% rename from test/grammar/option/file_options/main.k rename to test/grammar/option/file_options/_main.k diff --git a/test/grammar/option/file_options_fail_0/stderr.golden b/test/grammar/option/file_options_fail_0/stderr.golden new file mode 100644 index 000000000..6f0cee190 --- /dev/null +++ b/test/grammar/option/file_options_fail_0/stderr.golden @@ -0,0 +1,2 @@ +EvaluationError +Failed to load 'temp.yaml', invalid setting file format \ No newline at end of file diff --git a/test/grammar/option/file_options_fail_0/stderr.golden.py b/test/grammar/option/file_options_fail_0/stderr.golden.py deleted file mode 100644 index 5dac81fe3..000000000 --- a/test/grammar/option/file_options_fail_0/stderr.golden.py +++ /dev/null @@ -1,19 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error - -file = 'temp.yaml' - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.IllegalArgumentError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=file, - ) - ], - arg_msg="Invalid configuration in setting file:\nsetting file content should be a mapping, got: 1" - ), - file=sys.stdout -) - - diff --git a/test/grammar/option/file_options_fail_1/stderr.golden b/test/grammar/option/file_options_fail_1/stderr.golden new file mode 100644 index 000000000..6f0cee190 --- /dev/null +++ b/test/grammar/option/file_options_fail_1/stderr.golden @@ -0,0 +1,2 @@ +EvaluationError +Failed to load 'temp.yaml', invalid setting file format \ No newline at end of file diff --git a/test/grammar/option/file_options_fail_1/stderr.golden.py b/test/grammar/option/file_options_fail_1/stderr.golden.py deleted file mode 100644 index e77a4cf22..000000000 --- a/test/grammar/option/file_options_fail_1/stderr.golden.py +++ /dev/null @@ -1,27 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error - -file = 'temp.yaml' - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.IllegalArgumentError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=file, - ) - ], - arg_msg="""Invalid configuration in setting file: -invalid kcl_options value, should be list of key/value mapping. -=== A good example will be:=== -kcl_options: - - key: myArg # the option key must be a string value - value: myArgValue -=== got: === -kcl_options: - key: key - value: value -""" - ), - file=sys.stdout -) diff --git a/test/grammar/option/file_options_fail_2/stderr.golden b/test/grammar/option/file_options_fail_2/stderr.golden new file mode 100644 index 000000000..6f0cee190 --- /dev/null +++ b/test/grammar/option/file_options_fail_2/stderr.golden @@ -0,0 +1,2 @@ +EvaluationError +Failed to load 'temp.yaml', invalid setting file format \ No newline at end of file diff --git a/test/grammar/option/file_options_fail_2/stderr.golden.py b/test/grammar/option/file_options_fail_2/stderr.golden.py deleted file mode 100644 index bd2c44876..000000000 --- a/test/grammar/option/file_options_fail_2/stderr.golden.py +++ /dev/null @@ -1,26 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error - -file = 'temp.yaml' - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.IllegalArgumentError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=file, - ) - ], - arg_msg="""Invalid configuration in setting file: -invalid kcl_options value, should be list of key/value mapping. -=== A good example will be:=== -kcl_options: - - key: myArg # the option key must be a string value - value: myArgValue -=== got: === -kcl_options: -- key -""" - ), - file=sys.stdout -) diff --git a/test/grammar/option/file_options_fail_3/stderr.golden b/test/grammar/option/file_options_fail_3/stderr.golden new file mode 100644 index 000000000..6f0cee190 --- /dev/null +++ b/test/grammar/option/file_options_fail_3/stderr.golden @@ -0,0 +1,2 @@ +EvaluationError +Failed to load 'temp.yaml', invalid setting file format \ No newline at end of file diff --git a/test/grammar/option/file_options_fail_3/stderr.golden.py b/test/grammar/option/file_options_fail_3/stderr.golden.py deleted file mode 100644 index 30e113c52..000000000 --- a/test/grammar/option/file_options_fail_3/stderr.golden.py +++ /dev/null @@ -1,25 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error - -file = 'temp.yaml' - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.IllegalArgumentError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=file, - ) - ], - arg_msg="""Invalid yaml content of setting file: -while scanning a quoted scalar - in "", line 1, column 1: - " - ^ (line: 1) -found unexpected end of stream - in "", line 1, column 2: - " - ^ (line: 1)""" - ), - file=sys.stdout -) diff --git a/test/grammar/option/file_options_fail_4/stderr.golden b/test/grammar/option/file_options_fail_4/stderr.golden new file mode 100644 index 000000000..6f0cee190 --- /dev/null +++ b/test/grammar/option/file_options_fail_4/stderr.golden @@ -0,0 +1,2 @@ +EvaluationError +Failed to load 'temp.yaml', invalid setting file format \ No newline at end of file diff --git a/test/grammar/option/file_options_fail_4/stderr.golden.py b/test/grammar/option/file_options_fail_4/stderr.golden.py deleted file mode 100644 index 21055f494..000000000 --- a/test/grammar/option/file_options_fail_4/stderr.golden.py +++ /dev/null @@ -1,18 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error - -file = 'temp.yaml' - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.IllegalArgumentError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=file, - ) - ], - arg_msg="""Invalid configuration in setting file: -setting file content should be a mapping, got: :2""" - ), - file=sys.stdout -) diff --git a/test/grammar/option/invalid_option_fail_0/stderr.golden b/test/grammar/option/invalid_option_fail_0/stderr.golden new file mode 100644 index 000000000..a5983f911 --- /dev/null +++ b/test/grammar/option/invalid_option_fail_0/stderr.golden @@ -0,0 +1,2 @@ +EvaluationError +Invalid value for top level arguments \ No newline at end of file diff --git a/test/grammar/option/invalid_option_fail_0/stderr.golden.py b/test/grammar/option/invalid_option_fail_0/stderr.golden.py deleted file mode 100644 index 3ee0b6cf3..000000000 --- a/test/grammar/option/invalid_option_fail_0/stderr.golden.py +++ /dev/null @@ -1,15 +0,0 @@ - -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.IllegalArgumentError_TYPE, - arg_msg="Invalid value for option \"--argument(-D)\": should be in = pattern, got: key=value=" - ), - file=sys.stdout -) - diff --git a/test/grammar/option/invalid_option_fail_1/stderr.golden b/test/grammar/option/invalid_option_fail_1/stderr.golden new file mode 100644 index 000000000..a5983f911 --- /dev/null +++ b/test/grammar/option/invalid_option_fail_1/stderr.golden @@ -0,0 +1,2 @@ +EvaluationError +Invalid value for top level arguments \ No newline at end of file diff --git a/test/grammar/option/invalid_option_fail_1/stderr.golden.py b/test/grammar/option/invalid_option_fail_1/stderr.golden.py deleted file mode 100644 index a77745145..000000000 --- a/test/grammar/option/invalid_option_fail_1/stderr.golden.py +++ /dev/null @@ -1,15 +0,0 @@ - -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.IllegalArgumentError_TYPE, - arg_msg="Invalid value for option \"--argument(-D)\": should be in = pattern, got: key=" - ), - file=sys.stdout -) - diff --git a/test/grammar/option/invalid_option_fail_2/stderr.golden b/test/grammar/option/invalid_option_fail_2/stderr.golden new file mode 100644 index 000000000..a5983f911 --- /dev/null +++ b/test/grammar/option/invalid_option_fail_2/stderr.golden @@ -0,0 +1,2 @@ +EvaluationError +Invalid value for top level arguments \ No newline at end of file diff --git a/test/grammar/option/invalid_option_fail_2/stderr.golden.py b/test/grammar/option/invalid_option_fail_2/stderr.golden.py deleted file mode 100644 index 2b9f41c64..000000000 --- a/test/grammar/option/invalid_option_fail_2/stderr.golden.py +++ /dev/null @@ -1,11 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.IllegalArgumentError_TYPE, - arg_msg="Invalid value for option \"--argument(-D)\": Invalid option name: ''. should be a non-empty string" - ), - file=sys.stdout -) - diff --git a/test/grammar/option/option_help_0/main.k b/test/grammar/option/option_help_0/main.k deleted file mode 100644 index bb8d12465..000000000 --- a/test/grammar/option/option_help_0/main.k +++ /dev/null @@ -1,9 +0,0 @@ -name = option("name", required=True, help="set name value") -a = option("a", default=42, help="set a value") -b = option("b", help="set b value") - -# -D obj="{'a':1,'b':1}" -obj = option("obj") - -# -D obj="[1,2,3]" -obj2 = option("obj2") diff --git a/test/grammar/option/option_help_0/settings.yaml b/test/grammar/option/option_help_0/settings.yaml deleted file mode 100644 index 403895928..000000000 --- a/test/grammar/option/option_help_0/settings.yaml +++ /dev/null @@ -1 +0,0 @@ -kcl_options: -l diff --git a/test/grammar/option/option_help_0/stdout.golden b/test/grammar/option/option_help_0/stdout.golden deleted file mode 100644 index 0da235e23..000000000 --- a/test/grammar/option/option_help_0/stdout.golden +++ /dev/null @@ -1,6 +0,0 @@ -option list: - -D name=? (required) set name value - -D a=42 set a value - -D b=? set b value - -D obj=? - -D obj2=? diff --git a/test/grammar/option/option_help_fail_0/stderr.golden b/test/grammar/option/option_help_fail_0/stderr.golden new file mode 100644 index 000000000..bc9d901e8 --- /dev/null +++ b/test/grammar/option/option_help_fail_0/stderr.golden @@ -0,0 +1,6 @@ +error[E3M38]: EvaluationError + --> ${CWD}/main.k:1:1 + | +1 | name = option("name", required=True, help="set name value") + | option('name') must be initialized, try '-D name=?' argument + | \ No newline at end of file diff --git a/test/grammar/option/option_help_fail_0/stderr.golden.py b/test/grammar/option/option_help_fail_0/stderr.golden.py deleted file mode 100644 index d70de9542..000000000 --- a/test/grammar/option/option_help_fail_0/stderr.golden.py +++ /dev/null @@ -1,22 +0,0 @@ - -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) -file = os.path.join(cwd, 'main.k') - -name = 'name' - -kcl_error.print_kcl_error_message( - kcl_error.get_exception(err_type=kcl_error.ErrType.EvaluationError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=file, - line_no=1, - ), - ], - arg_msg=f"option('{name}') must be initialized, try '-D {name}=?' argument") - , file=sys.stdout -) - diff --git a/test/grammar/option/option_help_type_fail_0/stderr.golden b/test/grammar/option/option_help_type_fail_0/stderr.golden new file mode 100644 index 000000000..a8a56f953 --- /dev/null +++ b/test/grammar/option/option_help_type_fail_0/stderr.golden @@ -0,0 +1,6 @@ +error[E3M38]: EvaluationError + --> ${CWD}/main.k:1:1 + | +1 | name = option("name", type='str', required=True, help="set name value") + | option('name') must be initialized, try '-D name=?' argument + | \ No newline at end of file diff --git a/test/grammar/option/option_help_type_fail_0/stderr.golden.py b/test/grammar/option/option_help_type_fail_0/stderr.golden.py deleted file mode 100644 index f54aea77c..000000000 --- a/test/grammar/option/option_help_type_fail_0/stderr.golden.py +++ /dev/null @@ -1,20 +0,0 @@ - -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) -file = os.path.join(cwd, 'main.k') - -kcl_error.print_kcl_error_message( - kcl_error.get_exception(err_type=kcl_error.ErrType.EvaluationError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=file, - line_no=1, - ), - ], - arg_msg=f"option('name') must be initialized, try '-D name=?' argument") - , file=sys.stdout -) - diff --git a/test/grammar/option/simple_1/main.k b/test/grammar/option/simple_1/main.k index 4dfc8efa8..4b19c7e13 100644 --- a/test/grammar/option/simple_1/main.k +++ b/test/grammar/option/simple_1/main.k @@ -1,4 +1,3 @@ a = option("key1") b = option("key2") c = option("key3") -d = option("key4") diff --git a/test/grammar/option/simple_1/settings.yaml b/test/grammar/option/simple_1/settings.yaml index 4542f110c..99bde177b 100644 --- a/test/grammar/option/simple_1/settings.yaml +++ b/test/grammar/option/simple_1/settings.yaml @@ -1 +1 @@ -kcl_options: -D key1=0 -D key2=False -D key3=0.0 -D key4=.0 +kcl_options: -D key1=0 -D key2=False -D key3=0.0 diff --git a/test/grammar/option/simple_1/stdout.golden b/test/grammar/option/simple_1/stdout.golden index 0cfe38fa6..1847589d4 100644 --- a/test/grammar/option/simple_1/stdout.golden +++ b/test/grammar/option/simple_1/stdout.golden @@ -1,4 +1,3 @@ a: 0 b: false c: 0.0 -d: 0.0 diff --git a/test/grammar/option/simple_2/settings.yaml b/test/grammar/option/simple_2/settings.yaml index 0e8dd7f2c..2da24641e 100644 --- a/test/grammar/option/simple_2/settings.yaml +++ b/test/grammar/option/simple_2/settings.yaml @@ -1 +1 @@ -kcl_options: -D id='000000123456' +kcl_options: -D id="000000123456" diff --git a/test/grammar/option/type_convert_0/main.k b/test/grammar/option/type_convert_0/main.k index af1a22ebb..aa41f0b4f 100644 --- a/test/grammar/option/type_convert_0/main.k +++ b/test/grammar/option/type_convert_0/main.k @@ -1,4 +1,3 @@ a = option("key1", type="bool") b = option("key2", type="bool") c = option("key3", type="int") -d = option("key4", type="int") diff --git a/test/grammar/option/type_convert_0/settings.yaml b/test/grammar/option/type_convert_0/settings.yaml index 4542f110c..99bde177b 100644 --- a/test/grammar/option/type_convert_0/settings.yaml +++ b/test/grammar/option/type_convert_0/settings.yaml @@ -1 +1 @@ -kcl_options: -D key1=0 -D key2=False -D key3=0.0 -D key4=.0 +kcl_options: -D key1=0 -D key2=False -D key3=0.0 diff --git a/test/grammar/option/type_convert_0/stdout.golden b/test/grammar/option/type_convert_0/stdout.golden index ff13dd9f8..42ad19cfe 100644 --- a/test/grammar/option/type_convert_0/stdout.golden +++ b/test/grammar/option/type_convert_0/stdout.golden @@ -1,4 +1,3 @@ a: false b: false c: 0 -d: 0 diff --git a/test/grammar/option/type_convert_fail_0/stderr.golden b/test/grammar/option/type_convert_fail_0/stderr.golden new file mode 100644 index 000000000..d180e127b --- /dev/null +++ b/test/grammar/option/type_convert_fail_0/stderr.golden @@ -0,0 +1,6 @@ +error[E3M38]: EvaluationError + --> ${CWD}/main.k:3:1 + | +3 | c = option("key3", type="dict") + | cannot use '0.0' as type 'dict' + | \ No newline at end of file diff --git a/test/grammar/option/type_convert_fail_0/stderr.golden.py b/test/grammar/option/type_convert_fail_0/stderr.golden.py deleted file mode 100644 index b57d90909..000000000 --- a/test/grammar/option/type_convert_fail_0/stderr.golden.py +++ /dev/null @@ -1,20 +0,0 @@ - -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) -file = os.path.join(cwd, 'main.k') - -kcl_error.print_kcl_error_message( - kcl_error.get_exception(err_type=kcl_error.ErrType.EvaluationError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=file, - line_no=3, - ), - ], - arg_msg=f"cannot use '0.0' as type 'dict'") - , file=sys.stdout -) - diff --git a/test/grammar/option/type_convert_fail_1/stderr.golden b/test/grammar/option/type_convert_fail_1/stderr.golden new file mode 100644 index 000000000..e21ddeb34 --- /dev/null +++ b/test/grammar/option/type_convert_fail_1/stderr.golden @@ -0,0 +1,6 @@ +error[E3M38]: EvaluationError + --> ${CWD}/main.k:1:1 + | +1 | a = option("key1", type="list", default={"key": "value"}) + | cannot use '{'key': 'value'}' as type 'list' + | \ No newline at end of file diff --git a/test/grammar/option/type_convert_fail_1/stderr.golden.py b/test/grammar/option/type_convert_fail_1/stderr.golden.py deleted file mode 100644 index 04e105ffd..000000000 --- a/test/grammar/option/type_convert_fail_1/stderr.golden.py +++ /dev/null @@ -1,20 +0,0 @@ - -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) -file = os.path.join(cwd, 'main.k') - -kcl_error.print_kcl_error_message( - kcl_error.get_exception(err_type=kcl_error.ErrType.EvaluationError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=file, - line_no=1, - ), - ], - arg_msg=f"cannot use '{{'key': 'value'}}' as type 'list'") - , file=sys.stdout -) - diff --git a/test/grammar/option/type_convert_fail_2/stderr.golden b/test/grammar/option/type_convert_fail_2/stderr.golden new file mode 100644 index 000000000..5188ca9f4 --- /dev/null +++ b/test/grammar/option/type_convert_fail_2/stderr.golden @@ -0,0 +1,6 @@ +error[E1001]: InvalidSyntax + --> ${CWD}/main.k:1:51 + | +1 | a = option(type="list", default={"key": "value"}, "key1") + | ^ positional argument follows keyword argument + | \ No newline at end of file diff --git a/test/grammar/option/type_convert_fail_2/stderr.golden.py b/test/grammar/option/type_convert_fail_2/stderr.golden.py deleted file mode 100644 index 7b2d64745..000000000 --- a/test/grammar/option/type_convert_fail_2/stderr.golden.py +++ /dev/null @@ -1,20 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) -file = os.path.join(cwd, 'main.k') - -kcl_error.print_kcl_error_message( - kcl_error.get_exception(err_type=kcl_error.ErrType.IllegalArgumentError_Syntax_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=1, - col_no=51, - end_col_no=57 - ) - ], - arg_msg="positional argument follows keyword argument"), - file=sys.stdout -) diff --git a/test/grammar/override/fail/type_fail/stderr.golden b/test/grammar/override/fail/type_fail/stderr.golden new file mode 100644 index 000000000..62e2840ac --- /dev/null +++ b/test/grammar/override/fail/type_fail/stderr.golden @@ -0,0 +1 @@ +expect int, got str(A) diff --git a/test/grammar/override/fail/type_fail/stderr.golden.py b/test/grammar/override/fail/type_fail/stderr.golden.py deleted file mode 100644 index 5b4c31676..000000000 --- a/test/grammar/override/fail/type_fail/stderr.golden.py +++ /dev/null @@ -1,23 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.TypeError_Compile_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=4, - col_no=5, - arg_msg="expect int", - err_level=kcl_error.ErrLevel.ORDINARY - ), - ], - arg_msg="expect int, got str(A)" - ), - file=sys.stdout -) - diff --git a/test/grammar/path_selector/all_elements/main.k b/test/grammar/path_selector/all_elements/_main.k similarity index 100% rename from test/grammar/path_selector/all_elements/main.k rename to test/grammar/path_selector/all_elements/_main.k diff --git a/test/grammar/path_selector/combination/settings.yaml b/test/grammar/path_selector/combination/settings.yaml index 7f415f82a..7add00e45 100644 --- a/test/grammar/path_selector/combination/settings.yaml +++ b/test/grammar/path_selector/combination/settings.yaml @@ -1 +1 @@ -kcl_options: -S combination:alice.name.firstName -S combination:alice.name.lastName \ No newline at end of file +kcl_options: -S alice.name \ No newline at end of file diff --git a/test/grammar/path_selector/combination/stdout.golden b/test/grammar/path_selector/combination/stdout.golden index 88ef30116..a5f706201 100644 --- a/test/grammar/path_selector/combination/stdout.golden +++ b/test/grammar/path_selector/combination/stdout.golden @@ -1,4 +1,2 @@ -alice: - name: - firstName: Alice - lastName: Terry \ No newline at end of file +firstName: Alice +lastName: Terry diff --git a/test/grammar/path_selector/dict/settings.yaml b/test/grammar/path_selector/dict/settings.yaml index 3cf5354b1..c1ed4fb16 100644 --- a/test/grammar/path_selector/dict/settings.yaml +++ b/test/grammar/path_selector/dict/settings.yaml @@ -1 +1 @@ -kcl_options: -S dict:alice.labels.skin \ No newline at end of file +kcl_options: -S alice.labels.skin \ No newline at end of file diff --git a/test/grammar/path_selector/dict/stdout.golden b/test/grammar/path_selector/dict/stdout.golden index 37aaa884e..d1ed081df 100644 --- a/test/grammar/path_selector/dict/stdout.golden +++ b/test/grammar/path_selector/dict/stdout.golden @@ -1,3 +1 @@ -alice: - labels: - skin: yellow \ No newline at end of file +yellow diff --git a/test/grammar/path_selector/import_package/stdout.golden b/test/grammar/path_selector/import_package/stdout.golden index 8163ffb9b..190a18037 100644 --- a/test/grammar/path_selector/import_package/stdout.golden +++ b/test/grammar/path_selector/import_package/stdout.golden @@ -1 +1 @@ -result1: 123 +123 diff --git a/test/grammar/path_selector/index/main.k b/test/grammar/path_selector/index/_main.k similarity index 100% rename from test/grammar/path_selector/index/main.k rename to test/grammar/path_selector/index/_main.k diff --git a/test/grammar/path_selector/inherit/settings.yaml b/test/grammar/path_selector/inherit/settings.yaml index ea74437c2..785f97e3d 100644 --- a/test/grammar/path_selector/inherit/settings.yaml +++ b/test/grammar/path_selector/inherit/settings.yaml @@ -1 +1 @@ -kcl_options: -S inherit:JohnDoe.firstName -S inherit:JohnDoe.lastName \ No newline at end of file +kcl_options: -S JohnDoe \ No newline at end of file diff --git a/test/grammar/path_selector/inherit/stdout.golden b/test/grammar/path_selector/inherit/stdout.golden index 6ee1692a6..46d02fecd 100644 --- a/test/grammar/path_selector/inherit/stdout.golden +++ b/test/grammar/path_selector/inherit/stdout.golden @@ -1,3 +1,3 @@ -JohnDoe: - firstName: John - lastName: Doe \ No newline at end of file +firstName: John +lastName: Doe +subject: CS diff --git a/test/grammar/path_selector/invalid/invalid_0/stderr.golden b/test/grammar/path_selector/invalid/invalid_0/stderr.golden new file mode 100644 index 000000000..c5dd438ce --- /dev/null +++ b/test/grammar/path_selector/invalid/invalid_0/stderr.golden @@ -0,0 +1,6 @@ +error[E3M38]: EvaluationError + --> ${CWD}/main.k:2:1 + | +2 | dict_data = {"key1": "value1", "key2": "value2"} + | invalid path select operand :list_data.[0,1], value not found + | \ No newline at end of file diff --git a/test/grammar/path_selector/invalid/invalid_0/stderr.golden.py b/test/grammar/path_selector/invalid/invalid_0/stderr.golden.py deleted file mode 100644 index 8cdd91d5e..000000000 --- a/test/grammar/path_selector/invalid/invalid_0/stderr.golden.py +++ /dev/null @@ -1,14 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.CompileError_TYPE, - arg_msg="invalid path selector value [0,1]" - ), - file=sys.stdout -) - diff --git a/test/grammar/path_selector/invalid/invalid_1/stderr.golden b/test/grammar/path_selector/invalid/invalid_1/stderr.golden new file mode 100644 index 000000000..7d3195d98 --- /dev/null +++ b/test/grammar/path_selector/invalid/invalid_1/stderr.golden @@ -0,0 +1 @@ +list variable can't be used with dict selector expression diff --git a/test/grammar/path_selector/invalid/invalid_1/stderr.golden.py b/test/grammar/path_selector/invalid/invalid_1/stderr.golden.py deleted file mode 100644 index 311862206..000000000 --- a/test/grammar/path_selector/invalid/invalid_1/stderr.golden.py +++ /dev/null @@ -1,13 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.SelectorError_TYPE, - arg_msg="list variable can't be used with dict selector expression" - ), - file=sys.stdout -) diff --git a/test/grammar/path_selector/invalid/invalid_2/stderr.golden b/test/grammar/path_selector/invalid/invalid_2/stderr.golden new file mode 100644 index 000000000..8d937c411 --- /dev/null +++ b/test/grammar/path_selector/invalid/invalid_2/stderr.golden @@ -0,0 +1 @@ +dict variable can't be used with list selector expression diff --git a/test/grammar/path_selector/invalid/invalid_2/stderr.golden.py b/test/grammar/path_selector/invalid/invalid_2/stderr.golden.py deleted file mode 100644 index ed87bbf16..000000000 --- a/test/grammar/path_selector/invalid/invalid_2/stderr.golden.py +++ /dev/null @@ -1,14 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.SelectorError_TYPE, - arg_msg="dict variable can't be used with list selector expression" - ), - file=sys.stdout -) - diff --git a/test/grammar/path_selector/list_content/settings.yaml b/test/grammar/path_selector/list_content/settings.yaml index 5de8059c3..857c8d398 100644 --- a/test/grammar/path_selector/list_content/settings.yaml +++ b/test/grammar/path_selector/list_content/settings.yaml @@ -1 +1 @@ -kcl_options: -S :persons.* -S :persons2 \ No newline at end of file +kcl_options: -S persons \ No newline at end of file diff --git a/test/grammar/path_selector/list_content/stdout.golden b/test/grammar/path_selector/list_content/stdout.golden index 10afb74d5..a28cf8287 100644 --- a/test/grammar/path_selector/list_content/stdout.golden +++ b/test/grammar/path_selector/list_content/stdout.golden @@ -1,10 +1,5 @@ -persons: -- name: Alice - age: 18 -- name: Bob - age: 10 -persons2: -- name: Alice - age: 18 -- name: Bob - age: 10 +name: Alice +age: 18 +--- +name: Bob +age: 10 diff --git a/test/grammar/path_selector/mod_root/settings.yaml b/test/grammar/path_selector/mod_root/settings.yaml deleted file mode 100644 index 0764771ad..000000000 --- a/test/grammar/path_selector/mod_root/settings.yaml +++ /dev/null @@ -1 +0,0 @@ -kcl_options: -S :JohnDoe.firstName -S :JohnDoe.lastName \ No newline at end of file diff --git a/test/grammar/path_selector/mod_root/stdout.golden b/test/grammar/path_selector/mod_root/stdout.golden deleted file mode 100644 index 6ee1692a6..000000000 --- a/test/grammar/path_selector/mod_root/stdout.golden +++ /dev/null @@ -1,3 +0,0 @@ -JohnDoe: - firstName: John - lastName: Doe \ No newline at end of file diff --git a/test/grammar/path_selector/mod_root/main.k b/test/grammar/path_selector/mutiple_keys/_main.k similarity index 100% rename from test/grammar/path_selector/mod_root/main.k rename to test/grammar/path_selector/mutiple_keys/_main.k diff --git a/test/grammar/path_selector/mutiple_keys/main.k b/test/grammar/path_selector/mutiple_keys/main.k deleted file mode 100644 index 686d4023c..000000000 --- a/test/grammar/path_selector/mutiple_keys/main.k +++ /dev/null @@ -1,8 +0,0 @@ -schema Person: - firstName: str - lastName: str - -JohnDoe = Person { - firstName: "John" - lastName: "Doe" -} diff --git a/test/grammar/path_selector/nested0/nested1/simple/main.k b/test/grammar/path_selector/nested0/nested1/simple/main.k deleted file mode 100644 index 686d4023c..000000000 --- a/test/grammar/path_selector/nested0/nested1/simple/main.k +++ /dev/null @@ -1,8 +0,0 @@ -schema Person: - firstName: str - lastName: str - -JohnDoe = Person { - firstName: "John" - lastName: "Doe" -} diff --git a/test/grammar/path_selector/nested0/nested1/simple/settings.yaml b/test/grammar/path_selector/nested0/nested1/simple/settings.yaml deleted file mode 100644 index 19e08148d..000000000 --- a/test/grammar/path_selector/nested0/nested1/simple/settings.yaml +++ /dev/null @@ -1 +0,0 @@ -kcl_options: -S nested0.nested1.simple:JohnDoe.firstName -S nested0.nested1.simple:JohnDoe.lastName \ No newline at end of file diff --git a/test/grammar/path_selector/nested0/nested1/simple/stdout.golden b/test/grammar/path_selector/nested0/nested1/simple/stdout.golden deleted file mode 100644 index 6ee1692a6..000000000 --- a/test/grammar/path_selector/nested0/nested1/simple/stdout.golden +++ /dev/null @@ -1,3 +0,0 @@ -JohnDoe: - firstName: John - lastName: Doe \ No newline at end of file diff --git a/test/grammar/path_selector/simple/settings.yaml b/test/grammar/path_selector/simple/settings.yaml index b45b9fc60..ee0c3830c 100644 --- a/test/grammar/path_selector/simple/settings.yaml +++ b/test/grammar/path_selector/simple/settings.yaml @@ -1 +1 @@ -kcl_options: -S simple:JohnDoe.firstName -S simple:JohnDoe.lastName \ No newline at end of file +kcl_options: -S JohnDoe.firstName \ No newline at end of file diff --git a/test/grammar/path_selector/simple/stdout.golden b/test/grammar/path_selector/simple/stdout.golden index 6ee1692a6..076466759 100644 --- a/test/grammar/path_selector/simple/stdout.golden +++ b/test/grammar/path_selector/simple/stdout.golden @@ -1,3 +1 @@ -JohnDoe: - firstName: John - lastName: Doe \ No newline at end of file +John diff --git a/test/grammar/path_selector/type_dict/settings.yaml b/test/grammar/path_selector/type_dict/settings.yaml index 70aa862ef..68886f669 100644 --- a/test/grammar/path_selector/type_dict/settings.yaml +++ b/test/grammar/path_selector/type_dict/settings.yaml @@ -1 +1 @@ -kcl_options: -S type_dict:group.persons.me.age \ No newline at end of file +kcl_options: -S group.persons.me.age \ No newline at end of file diff --git a/test/grammar/path_selector/type_dict/stdout.golden b/test/grammar/path_selector/type_dict/stdout.golden index a9896146f..48082f72f 100644 --- a/test/grammar/path_selector/type_dict/stdout.golden +++ b/test/grammar/path_selector/type_dict/stdout.golden @@ -1,4 +1 @@ -group: - persons: - me: - age: 12 \ No newline at end of file +12 diff --git a/test/grammar/plugin/fail_0/stderr.golden b/test/grammar/plugin/fail_0/stderr.golden new file mode 100644 index 000000000..0af7b50a1 --- /dev/null +++ b/test/grammar/plugin/fail_0/stderr.golden @@ -0,0 +1 @@ +the plugin package `kcl_plugin.hello` is not found, please confirm if plugin mode is enabled \ No newline at end of file diff --git a/test/grammar/plugin/fail_0/stderr.golden.py b/test/grammar/plugin/fail_0/stderr.golden.py deleted file mode 100644 index f7f3d55c1..000000000 --- a/test/grammar/plugin/fail_0/stderr.golden.py +++ /dev/null @@ -1,17 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception(err_type=kcl_error.ErrType.EvaluationError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=3, - ) - ], - arg_msg="unsupported operand type(s) for +: 'NoneType' and 'NoneType'", - ) -) diff --git a/test/grammar/plugin/fail_1/stderr.golden b/test/grammar/plugin/fail_1/stderr.golden new file mode 100644 index 000000000..0af7b50a1 --- /dev/null +++ b/test/grammar/plugin/fail_1/stderr.golden @@ -0,0 +1 @@ +the plugin package `kcl_plugin.hello` is not found, please confirm if plugin mode is enabled \ No newline at end of file diff --git a/test/grammar/plugin/fail_1/stderr.golden.py b/test/grammar/plugin/fail_1/stderr.golden.py deleted file mode 100644 index b554fcbca..000000000 --- a/test/grammar/plugin/fail_1/stderr.golden.py +++ /dev/null @@ -1,17 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception(err_type=kcl_error.ErrType.EvaluationError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=4, - ) - ], - arg_msg="unsupported operand type(s) for +: 'int' and 'str'", - ) -) diff --git a/test/grammar/quant/all/multi_cons_invalid_0/stderr.golden b/test/grammar/quant/all/multi_cons_invalid_0/stderr.golden new file mode 100644 index 000000000..d0c9daa20 --- /dev/null +++ b/test/grammar/quant/all/multi_cons_invalid_0/stderr.golden @@ -0,0 +1,11 @@ +error[E3M38]: EvaluationError + --> ${CWD}/main.k:10:8 + | +10 | main = app_conf { + | ^ Instance check failed + | + --> ${CWD}/main.k:7:1 + | +7 | }, "invalid port" + | Check failed on the condition: invalid port + | \ No newline at end of file diff --git a/test/grammar/quant/all/multi_cons_invalid_0/stderr.golden.py b/test/grammar/quant/all/multi_cons_invalid_0/stderr.golden.py deleted file mode 100644 index e5943ab87..000000000 --- a/test/grammar/quant/all/multi_cons_invalid_0/stderr.golden.py +++ /dev/null @@ -1,25 +0,0 @@ - -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception(err_type=kcl_error.ErrType.SchemaCheckFailure_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=7, - arg_msg=kcl_error.SCHEMA_CHECK_FILE_MSG_COND - ), - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=10, - col_no=8, - arg_msg=kcl_error.SCHEMA_CHECK_FILE_MSG_ERR - ), - ], - arg_msg="invalid port") - , file=sys.stdout -) diff --git a/test/grammar/quant/all/multi_cons_invalid_1/stderr.golden b/test/grammar/quant/all/multi_cons_invalid_1/stderr.golden new file mode 100644 index 000000000..d0c9daa20 --- /dev/null +++ b/test/grammar/quant/all/multi_cons_invalid_1/stderr.golden @@ -0,0 +1,11 @@ +error[E3M38]: EvaluationError + --> ${CWD}/main.k:10:8 + | +10 | main = app_conf { + | ^ Instance check failed + | + --> ${CWD}/main.k:7:1 + | +7 | }, "invalid port" + | Check failed on the condition: invalid port + | \ No newline at end of file diff --git a/test/grammar/quant/all/multi_cons_invalid_1/stderr.golden.py b/test/grammar/quant/all/multi_cons_invalid_1/stderr.golden.py deleted file mode 100644 index 5c35815bf..000000000 --- a/test/grammar/quant/all/multi_cons_invalid_1/stderr.golden.py +++ /dev/null @@ -1,25 +0,0 @@ - -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception(err_type=kcl_error.ErrType.SchemaCheckFailure_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=7, - arg_msg=kcl_error.SCHEMA_CHECK_FILE_MSG_COND - ), - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=10, - col_no=8, - arg_msg=kcl_error.SCHEMA_CHECK_FILE_MSG_ERR - ), - ], - arg_msg="invalid port") - , file=sys.stdout -) \ No newline at end of file diff --git a/test/grammar/quant/all/multi_cons_invalid_2/stderr.golden b/test/grammar/quant/all/multi_cons_invalid_2/stderr.golden new file mode 100644 index 000000000..d0c9daa20 --- /dev/null +++ b/test/grammar/quant/all/multi_cons_invalid_2/stderr.golden @@ -0,0 +1,11 @@ +error[E3M38]: EvaluationError + --> ${CWD}/main.k:10:8 + | +10 | main = app_conf { + | ^ Instance check failed + | + --> ${CWD}/main.k:7:1 + | +7 | }, "invalid port" + | Check failed on the condition: invalid port + | \ No newline at end of file diff --git a/test/grammar/quant/all/multi_cons_invalid_2/stderr.golden.py b/test/grammar/quant/all/multi_cons_invalid_2/stderr.golden.py deleted file mode 100644 index e5943ab87..000000000 --- a/test/grammar/quant/all/multi_cons_invalid_2/stderr.golden.py +++ /dev/null @@ -1,25 +0,0 @@ - -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception(err_type=kcl_error.ErrType.SchemaCheckFailure_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=7, - arg_msg=kcl_error.SCHEMA_CHECK_FILE_MSG_COND - ), - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=10, - col_no=8, - arg_msg=kcl_error.SCHEMA_CHECK_FILE_MSG_ERR - ), - ], - arg_msg="invalid port") - , file=sys.stdout -) diff --git a/test/grammar/quant/all/multi_cons_invalid_3/stderr.golden b/test/grammar/quant/all/multi_cons_invalid_3/stderr.golden new file mode 100644 index 000000000..d0c9daa20 --- /dev/null +++ b/test/grammar/quant/all/multi_cons_invalid_3/stderr.golden @@ -0,0 +1,11 @@ +error[E3M38]: EvaluationError + --> ${CWD}/main.k:10:8 + | +10 | main = app_conf { + | ^ Instance check failed + | + --> ${CWD}/main.k:7:1 + | +7 | }, "invalid port" + | Check failed on the condition: invalid port + | \ No newline at end of file diff --git a/test/grammar/quant/all/multi_cons_invalid_3/stderr.golden.py b/test/grammar/quant/all/multi_cons_invalid_3/stderr.golden.py deleted file mode 100644 index e5943ab87..000000000 --- a/test/grammar/quant/all/multi_cons_invalid_3/stderr.golden.py +++ /dev/null @@ -1,25 +0,0 @@ - -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception(err_type=kcl_error.ErrType.SchemaCheckFailure_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=7, - arg_msg=kcl_error.SCHEMA_CHECK_FILE_MSG_COND - ), - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=10, - col_no=8, - arg_msg=kcl_error.SCHEMA_CHECK_FILE_MSG_ERR - ), - ], - arg_msg="invalid port") - , file=sys.stdout -) diff --git a/test/grammar/quant/all/multi_cons_invalid_4/stderr.golden b/test/grammar/quant/all/multi_cons_invalid_4/stderr.golden new file mode 100644 index 000000000..d0c9daa20 --- /dev/null +++ b/test/grammar/quant/all/multi_cons_invalid_4/stderr.golden @@ -0,0 +1,11 @@ +error[E3M38]: EvaluationError + --> ${CWD}/main.k:10:8 + | +10 | main = app_conf { + | ^ Instance check failed + | + --> ${CWD}/main.k:7:1 + | +7 | }, "invalid port" + | Check failed on the condition: invalid port + | \ No newline at end of file diff --git a/test/grammar/quant/all/multi_cons_invalid_4/stderr.golden.py b/test/grammar/quant/all/multi_cons_invalid_4/stderr.golden.py deleted file mode 100644 index e5943ab87..000000000 --- a/test/grammar/quant/all/multi_cons_invalid_4/stderr.golden.py +++ /dev/null @@ -1,25 +0,0 @@ - -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception(err_type=kcl_error.ErrType.SchemaCheckFailure_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=7, - arg_msg=kcl_error.SCHEMA_CHECK_FILE_MSG_COND - ), - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=10, - col_no=8, - arg_msg=kcl_error.SCHEMA_CHECK_FILE_MSG_ERR - ), - ], - arg_msg="invalid port") - , file=sys.stdout -) diff --git a/test/grammar/quant/all/multi_cons_valid_0/main.k b/test/grammar/quant/all/multi_cons_valid_0/main.k index 801687bd7..8acecdfaf 100644 --- a/test/grammar/quant/all/multi_cons_valid_0/main.k +++ b/test/grammar/quant/all/multi_cons_valid_0/main.k @@ -4,7 +4,7 @@ schema app_conf: check: all port in ports { int(port) >= 1024 and int(port) <= 65535 - }, "invalid port" + }, "invalid ports {}".format(ports) main = app_conf { diff --git a/test/grammar/quant/all/simple_invalid_0/stderr.golden b/test/grammar/quant/all/simple_invalid_0/stderr.golden new file mode 100644 index 000000000..5ec907e63 --- /dev/null +++ b/test/grammar/quant/all/simple_invalid_0/stderr.golden @@ -0,0 +1,11 @@ +error[E3M38]: EvaluationError + --> ${CWD}/main.k:10:8 + | +10 | main = app_conf { + | ^ Instance check failed + | + --> ${CWD}/main.k:7:1 + | +7 | }, "invalid cluster ip" + | Check failed on the condition: invalid cluster ip + | \ No newline at end of file diff --git a/test/grammar/quant/all/simple_invalid_0/stderr.golden.py b/test/grammar/quant/all/simple_invalid_0/stderr.golden.py deleted file mode 100644 index fa6173c1e..000000000 --- a/test/grammar/quant/all/simple_invalid_0/stderr.golden.py +++ /dev/null @@ -1,25 +0,0 @@ - -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception(err_type=kcl_error.ErrType.SchemaCheckFailure_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=7, - arg_msg=kcl_error.SCHEMA_CHECK_FILE_MSG_COND - ), - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=10, - col_no=8, - arg_msg=kcl_error.SCHEMA_CHECK_FILE_MSG_ERR - ), - ], - arg_msg="invalid cluster ip") - , file=sys.stdout -) diff --git a/test/grammar/quant/all/simple_valid_4/main.k b/test/grammar/quant/all/simple_valid_4/main.k new file mode 100644 index 000000000..4573bf308 --- /dev/null +++ b/test/grammar/quant/all/simple_valid_4/main.k @@ -0,0 +1,12 @@ +import regex +data = { + k1 = "1" +} +annotations = { + k1 = "1" + k2 = "2" + k3 = "3" +} +result = all k, v in annotations { + regex.match(v, data[k]) if data[k] +} diff --git a/test/grammar/quant/all/simple_valid_4/stdout.golden b/test/grammar/quant/all/simple_valid_4/stdout.golden new file mode 100644 index 000000000..25efd9c19 --- /dev/null +++ b/test/grammar/quant/all/simple_valid_4/stdout.golden @@ -0,0 +1,7 @@ +data: + k1: '1' +annotations: + k1: '1' + k2: '2' + k3: '3' +result: true diff --git a/test/grammar/quant/any/multi_cons_invalid_0/stderr.golden b/test/grammar/quant/any/multi_cons_invalid_0/stderr.golden new file mode 100644 index 000000000..d0c9daa20 --- /dev/null +++ b/test/grammar/quant/any/multi_cons_invalid_0/stderr.golden @@ -0,0 +1,11 @@ +error[E3M38]: EvaluationError + --> ${CWD}/main.k:10:8 + | +10 | main = app_conf { + | ^ Instance check failed + | + --> ${CWD}/main.k:7:1 + | +7 | }, "invalid port" + | Check failed on the condition: invalid port + | \ No newline at end of file diff --git a/test/grammar/quant/any/multi_cons_invalid_0/stderr.golden.py b/test/grammar/quant/any/multi_cons_invalid_0/stderr.golden.py deleted file mode 100644 index e5943ab87..000000000 --- a/test/grammar/quant/any/multi_cons_invalid_0/stderr.golden.py +++ /dev/null @@ -1,25 +0,0 @@ - -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception(err_type=kcl_error.ErrType.SchemaCheckFailure_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=7, - arg_msg=kcl_error.SCHEMA_CHECK_FILE_MSG_COND - ), - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=10, - col_no=8, - arg_msg=kcl_error.SCHEMA_CHECK_FILE_MSG_ERR - ), - ], - arg_msg="invalid port") - , file=sys.stdout -) diff --git a/test/grammar/quant/any/multi_cons_invalid_1/stderr.golden b/test/grammar/quant/any/multi_cons_invalid_1/stderr.golden new file mode 100644 index 000000000..d0c9daa20 --- /dev/null +++ b/test/grammar/quant/any/multi_cons_invalid_1/stderr.golden @@ -0,0 +1,11 @@ +error[E3M38]: EvaluationError + --> ${CWD}/main.k:10:8 + | +10 | main = app_conf { + | ^ Instance check failed + | + --> ${CWD}/main.k:7:1 + | +7 | }, "invalid port" + | Check failed on the condition: invalid port + | \ No newline at end of file diff --git a/test/grammar/quant/any/multi_cons_invalid_1/stderr.golden.py b/test/grammar/quant/any/multi_cons_invalid_1/stderr.golden.py deleted file mode 100644 index e5943ab87..000000000 --- a/test/grammar/quant/any/multi_cons_invalid_1/stderr.golden.py +++ /dev/null @@ -1,25 +0,0 @@ - -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception(err_type=kcl_error.ErrType.SchemaCheckFailure_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=7, - arg_msg=kcl_error.SCHEMA_CHECK_FILE_MSG_COND - ), - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=10, - col_no=8, - arg_msg=kcl_error.SCHEMA_CHECK_FILE_MSG_ERR - ), - ], - arg_msg="invalid port") - , file=sys.stdout -) diff --git a/test/grammar/quant/any/multi_cons_invalid_2/stderr.golden b/test/grammar/quant/any/multi_cons_invalid_2/stderr.golden new file mode 100644 index 000000000..d0c9daa20 --- /dev/null +++ b/test/grammar/quant/any/multi_cons_invalid_2/stderr.golden @@ -0,0 +1,11 @@ +error[E3M38]: EvaluationError + --> ${CWD}/main.k:10:8 + | +10 | main = app_conf { + | ^ Instance check failed + | + --> ${CWD}/main.k:7:1 + | +7 | }, "invalid port" + | Check failed on the condition: invalid port + | \ No newline at end of file diff --git a/test/grammar/quant/any/multi_cons_invalid_2/stderr.golden.py b/test/grammar/quant/any/multi_cons_invalid_2/stderr.golden.py deleted file mode 100644 index 7322e4809..000000000 --- a/test/grammar/quant/any/multi_cons_invalid_2/stderr.golden.py +++ /dev/null @@ -1,26 +0,0 @@ - -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception(err_type=kcl_error.ErrType.SchemaCheckFailure_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=7, - arg_msg=kcl_error.SCHEMA_CHECK_FILE_MSG_COND - ), - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=10, - col_no=8, - arg_msg=kcl_error.SCHEMA_CHECK_FILE_MSG_ERR - ), - ], - arg_msg="invalid port") - , file=sys.stdout -) - diff --git a/test/grammar/quant/any/multi_cons_invalid_3/stderr.golden b/test/grammar/quant/any/multi_cons_invalid_3/stderr.golden new file mode 100644 index 000000000..d0c9daa20 --- /dev/null +++ b/test/grammar/quant/any/multi_cons_invalid_3/stderr.golden @@ -0,0 +1,11 @@ +error[E3M38]: EvaluationError + --> ${CWD}/main.k:10:8 + | +10 | main = app_conf { + | ^ Instance check failed + | + --> ${CWD}/main.k:7:1 + | +7 | }, "invalid port" + | Check failed on the condition: invalid port + | \ No newline at end of file diff --git a/test/grammar/quant/any/multi_cons_invalid_3/stderr.golden.py b/test/grammar/quant/any/multi_cons_invalid_3/stderr.golden.py deleted file mode 100644 index 903348ae9..000000000 --- a/test/grammar/quant/any/multi_cons_invalid_3/stderr.golden.py +++ /dev/null @@ -1,25 +0,0 @@ - -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) -kcl_error.print_kcl_error_message( - kcl_error.get_exception(err_type=kcl_error.ErrType.SchemaCheckFailure_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=7, - arg_msg=kcl_error.SCHEMA_CHECK_FILE_MSG_COND - ), - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=10, - col_no=8, - arg_msg=kcl_error.SCHEMA_CHECK_FILE_MSG_ERR - ), - ], - arg_msg="invalid port") - , file=sys.stdout -) - diff --git a/test/grammar/quant/any/multi_cons_invalid_4/stderr.golden b/test/grammar/quant/any/multi_cons_invalid_4/stderr.golden new file mode 100644 index 000000000..d0c9daa20 --- /dev/null +++ b/test/grammar/quant/any/multi_cons_invalid_4/stderr.golden @@ -0,0 +1,11 @@ +error[E3M38]: EvaluationError + --> ${CWD}/main.k:10:8 + | +10 | main = app_conf { + | ^ Instance check failed + | + --> ${CWD}/main.k:7:1 + | +7 | }, "invalid port" + | Check failed on the condition: invalid port + | \ No newline at end of file diff --git a/test/grammar/quant/any/multi_cons_invalid_4/stderr.golden.py b/test/grammar/quant/any/multi_cons_invalid_4/stderr.golden.py deleted file mode 100644 index 7322e4809..000000000 --- a/test/grammar/quant/any/multi_cons_invalid_4/stderr.golden.py +++ /dev/null @@ -1,26 +0,0 @@ - -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception(err_type=kcl_error.ErrType.SchemaCheckFailure_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=7, - arg_msg=kcl_error.SCHEMA_CHECK_FILE_MSG_COND - ), - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=10, - col_no=8, - arg_msg=kcl_error.SCHEMA_CHECK_FILE_MSG_ERR - ), - ], - arg_msg="invalid port") - , file=sys.stdout -) - diff --git a/test/grammar/quant/any/simple_invalid_0/stderr.golden b/test/grammar/quant/any/simple_invalid_0/stderr.golden new file mode 100644 index 000000000..20c58be9a --- /dev/null +++ b/test/grammar/quant/any/simple_invalid_0/stderr.golden @@ -0,0 +1,11 @@ +error[E3M38]: EvaluationError + --> ${CWD}/main.k:10:8 + | +10 | main = app_conf { + | ^ Instance check failed + | + --> ${CWD}/main.k:7:1 + | +7 | }, "no server defined" + | Check failed on the condition: no server defined + | \ No newline at end of file diff --git a/test/grammar/quant/any/simple_invalid_0/stderr.golden.py b/test/grammar/quant/any/simple_invalid_0/stderr.golden.py deleted file mode 100644 index 45187ecc5..000000000 --- a/test/grammar/quant/any/simple_invalid_0/stderr.golden.py +++ /dev/null @@ -1,26 +0,0 @@ - -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception(err_type=kcl_error.ErrType.SchemaCheckFailure_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=7, - arg_msg=kcl_error.SCHEMA_CHECK_FILE_MSG_COND - ), - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=10, - col_no=8, - arg_msg=kcl_error.SCHEMA_CHECK_FILE_MSG_ERR - ), - ], - arg_msg="no server defined") - , file=sys.stdout -) - diff --git a/test/grammar/quant/filter/simple_list_2/main.k b/test/grammar/quant/filter/simple_list_2/main.k new file mode 100644 index 000000000..7efb425ef --- /dev/null +++ b/test/grammar/quant/filter/simple_list_2/main.k @@ -0,0 +1,25 @@ +schema Student: + name: str + id: int + grade: int + + check: + id >= 0 + 0 <= grade <= 100 + +students: [Student] = [ + {name = "Alice", id = 1, grade = 85} + {name = "Bob", id = 2, grade = 70} + {name = "Charlie", id = 3, grade = 90} + {name = "David", id = 4, grade = 80} + {name = "Eve", id = 5, grade = 95} +] + +query_student_where_name = lambda students: [Student], name: str -> Student { + (filter s in students { + s.name == name + })?[0] +} + +alice: Student = query_student_where_name(students, name="Alice") +bob: Student = query_student_where_name(students, name="Bob") diff --git a/test/grammar/quant/filter/simple_list_2/stdout.golden b/test/grammar/quant/filter/simple_list_2/stdout.golden new file mode 100644 index 000000000..aa5cc61a3 --- /dev/null +++ b/test/grammar/quant/filter/simple_list_2/stdout.golden @@ -0,0 +1,24 @@ +students: +- name: Alice + id: 1 + grade: 85 +- name: Bob + id: 2 + grade: 70 +- name: Charlie + id: 3 + grade: 90 +- name: David + id: 4 + grade: 80 +- name: Eve + id: 5 + grade: 95 +alice: + name: Alice + id: 1 + grade: 85 +bob: + name: Bob + id: 2 + grade: 70 diff --git a/test/grammar/scalar/config/multi_config_inst_0/main.k b/test/grammar/scalar/config/multi_config_inst_0/main.k new file mode 100644 index 000000000..046b62edc --- /dev/null +++ b/test/grammar/scalar/config/multi_config_inst_0/main.k @@ -0,0 +1,14 @@ +{ + http.server = { + listen = 80 + } +} +{ + http.server = { + listen = 8080 + location = { + root = "/var/www/html" + index = "index.html" + } + } +} diff --git a/test/grammar/scalar/config/multi_config_inst_0/stdout.golden b/test/grammar/scalar/config/multi_config_inst_0/stdout.golden new file mode 100644 index 000000000..a9ce69f21 --- /dev/null +++ b/test/grammar/scalar/config/multi_config_inst_0/stdout.golden @@ -0,0 +1,6 @@ +http: + server: + listen: 8080 + location: + root: /var/www/html + index: index.html diff --git a/test/grammar/scalar/config/single_config_inst_0/main.k b/test/grammar/scalar/config/single_config_inst_0/main.k new file mode 100644 index 000000000..00fc3d5f4 --- /dev/null +++ b/test/grammar/scalar/config/single_config_inst_0/main.k @@ -0,0 +1,9 @@ +{ + http.server = { + listen = 80 + location = { + root = "/var/www/html" + index = "index.html" + } + } +} diff --git a/test/grammar/scalar/config/single_config_inst_0/stdout.golden b/test/grammar/scalar/config/single_config_inst_0/stdout.golden new file mode 100644 index 000000000..c0fdba7c4 --- /dev/null +++ b/test/grammar/scalar/config/single_config_inst_0/stdout.golden @@ -0,0 +1,6 @@ +http: + server: + listen: 80 + location: + root: /var/www/html + index: index.html diff --git a/test/grammar/scalar/hidden_var/main.k b/test/grammar/scalar/hidden_var/main.k new file mode 100644 index 000000000..99bde5b91 --- /dev/null +++ b/test/grammar/scalar/hidden_var/main.k @@ -0,0 +1,5 @@ +_a = 1 + +[ + 1 +] \ No newline at end of file diff --git a/test/grammar/scalar/hidden_var/stdout.golden b/test/grammar/scalar/hidden_var/stdout.golden new file mode 100644 index 000000000..56a6051ca --- /dev/null +++ b/test/grammar/scalar/hidden_var/stdout.golden @@ -0,0 +1 @@ +1 \ No newline at end of file diff --git a/test/grammar/scalar/invalid/conflict_0/main.k b/test/grammar/scalar/invalid/conflict_0/main.k new file mode 100644 index 000000000..1191247b6 --- /dev/null +++ b/test/grammar/scalar/invalid/conflict_0/main.k @@ -0,0 +1,2 @@ +1 +2 diff --git a/test/grammar/scalar/invalid/conflict_0/stderr.golden b/test/grammar/scalar/invalid/conflict_0/stderr.golden new file mode 100644 index 000000000..f9830b6c9 --- /dev/null +++ b/test/grammar/scalar/invalid/conflict_0/stderr.golden @@ -0,0 +1,6 @@ +error[E3M38]: EvaluationError + --> ${CWD}/main.k:2:1 + | +2 | 2 + | conflicting values between 2 and 1 + | \ No newline at end of file diff --git a/test/grammar/scalar/invalid/conflict_1/main.k b/test/grammar/scalar/invalid/conflict_1/main.k new file mode 100644 index 000000000..71e5f7832 --- /dev/null +++ b/test/grammar/scalar/invalid/conflict_1/main.k @@ -0,0 +1,2 @@ +a = 1 +1 diff --git a/test/grammar/scalar/invalid/conflict_1/stderr.golden b/test/grammar/scalar/invalid/conflict_1/stderr.golden new file mode 100644 index 000000000..72100f1f3 --- /dev/null +++ b/test/grammar/scalar/invalid/conflict_1/stderr.golden @@ -0,0 +1,6 @@ +error[E3M38]: EvaluationError + --> ${CWD}/main.k:2:1 + | +2 | 1 + | conflicting values between {...} and 1 + | \ No newline at end of file diff --git a/test/grammar/scalar/number/number_0/main.k b/test/grammar/scalar/number/number_0/main.k new file mode 100644 index 000000000..56a6051ca --- /dev/null +++ b/test/grammar/scalar/number/number_0/main.k @@ -0,0 +1 @@ +1 \ No newline at end of file diff --git a/test/grammar/scalar/number/number_0/stdout.golden b/test/grammar/scalar/number/number_0/stdout.golden new file mode 100644 index 000000000..56a6051ca --- /dev/null +++ b/test/grammar/scalar/number/number_0/stdout.golden @@ -0,0 +1 @@ +1 \ No newline at end of file diff --git a/test/grammar/scalar/schema/multi_schema_inst_0/main.k b/test/grammar/scalar/schema/multi_schema_inst_0/main.k new file mode 100644 index 000000000..faa5e27fd --- /dev/null +++ b/test/grammar/scalar/schema/multi_schema_inst_0/main.k @@ -0,0 +1,29 @@ +schema Nginx: + """Schema for Nginx configuration files""" + http: Http + +schema Http: + server: Server + +schema Server: + listen: int | str # The attribute `listen` can be int type or a string type. + location?: Location # Optional, but must be non-empty when specified + +schema Location: + root: str + index: str + +Nginx { + http.server = { + listen = 80 + } +} +Nginx { + http.server = { + listen = 8080 + location = { + root = "/var/www/html" + index = "index.html" + } + } +} diff --git a/test/grammar/scalar/schema/multi_schema_inst_0/stdout.golden b/test/grammar/scalar/schema/multi_schema_inst_0/stdout.golden new file mode 100644 index 000000000..a9ce69f21 --- /dev/null +++ b/test/grammar/scalar/schema/multi_schema_inst_0/stdout.golden @@ -0,0 +1,6 @@ +http: + server: + listen: 8080 + location: + root: /var/www/html + index: index.html diff --git a/test/grammar/scalar/schema/single_schema_inst_0/main.k b/test/grammar/scalar/schema/single_schema_inst_0/main.k new file mode 100644 index 000000000..8a1facd69 --- /dev/null +++ b/test/grammar/scalar/schema/single_schema_inst_0/main.k @@ -0,0 +1,24 @@ +schema Nginx: + """Schema for Nginx configuration files""" + http: Http + +schema Http: + server: Server + +schema Server: + listen: int | str # The attribute `listen` can be int type or a string type. + location?: Location # Optional, but must be non-empty when specified + +schema Location: + root: str + index: str + +Nginx { + http.server = { + listen = 80 + location = { + root = "/var/www/html" + index = "index.html" + } + } +} diff --git a/test/grammar/scalar/schema/single_schema_inst_0/stdout.golden b/test/grammar/scalar/schema/single_schema_inst_0/stdout.golden new file mode 100644 index 000000000..c0fdba7c4 --- /dev/null +++ b/test/grammar/scalar/schema/single_schema_inst_0/stdout.golden @@ -0,0 +1,6 @@ +http: + server: + listen: 80 + location: + root: /var/www/html + index: index.html diff --git a/test/grammar/scalar/string/string_0/main.k b/test/grammar/scalar/string/string_0/main.k new file mode 100644 index 000000000..075c842d1 --- /dev/null +++ b/test/grammar/scalar/string/string_0/main.k @@ -0,0 +1 @@ +"a" \ No newline at end of file diff --git a/test/grammar/scalar/string/string_0/stdout.golden b/test/grammar/scalar/string/string_0/stdout.golden new file mode 100644 index 000000000..789819226 --- /dev/null +++ b/test/grammar/scalar/string/string_0/stdout.golden @@ -0,0 +1 @@ +a diff --git a/test/grammar/schema/assign_stmt/assign_stmt_0/main.k b/test/grammar/schema/assign_stmt/assign_stmt_0/main.k new file mode 100644 index 000000000..1066a82a3 --- /dev/null +++ b/test/grammar/schema/assign_stmt/assign_stmt_0/main.k @@ -0,0 +1,14 @@ +schema Metadata: + environment?: str = "qa" + region?: str + name?: str + +schema MySchema1: + metadata?: Metadata = {} + + metadata.environment = "dev" + metadata.region = "us-east-1" + +output = MySchema1 { + metadata.name = "config" +} diff --git a/test/grammar/schema/assign_stmt/assign_stmt_0/stdout.golden b/test/grammar/schema/assign_stmt/assign_stmt_0/stdout.golden new file mode 100644 index 000000000..e2a1effb3 --- /dev/null +++ b/test/grammar/schema/assign_stmt/assign_stmt_0/stdout.golden @@ -0,0 +1,5 @@ +output: + metadata: + environment: dev + region: us-east-1 + name: config diff --git a/test/grammar/schema/assign_stmt/assign_stmt_1/main.k b/test/grammar/schema/assign_stmt/assign_stmt_1/main.k new file mode 100644 index 000000000..9992d221e --- /dev/null +++ b/test/grammar/schema/assign_stmt/assign_stmt_1/main.k @@ -0,0 +1,14 @@ +schema Metadata: + environment?: str = "qa" + region?: str + name?: str + +schema MySchema1: + metadata?: Metadata = {} + + metadata.environment = "dev" + + +output = MySchema1 { + metadata.name = "config" +} diff --git a/test/grammar/schema/assign_stmt/assign_stmt_1/stdout.golden b/test/grammar/schema/assign_stmt/assign_stmt_1/stdout.golden new file mode 100644 index 000000000..23403df35 --- /dev/null +++ b/test/grammar/schema/assign_stmt/assign_stmt_1/stdout.golden @@ -0,0 +1,4 @@ +output: + metadata: + environment: dev + name: config diff --git a/test/grammar/schema/assign_stmt/assign_stmt_2/main.k b/test/grammar/schema/assign_stmt/assign_stmt_2/main.k new file mode 100644 index 000000000..8be0f05ba --- /dev/null +++ b/test/grammar/schema/assign_stmt/assign_stmt_2/main.k @@ -0,0 +1,13 @@ +schema Metadata: + environment?: str = "qa" + region?: str + name?: str + +schema MySchema1: + metadata?: Metadata = { + name = "config" + } + metadata.environment = "dev" + metadata.region = "us-east-1" + +output = MySchema1 {} diff --git a/test/grammar/schema/assign_stmt/assign_stmt_2/stdout.golden b/test/grammar/schema/assign_stmt/assign_stmt_2/stdout.golden new file mode 100644 index 000000000..e2a1effb3 --- /dev/null +++ b/test/grammar/schema/assign_stmt/assign_stmt_2/stdout.golden @@ -0,0 +1,5 @@ +output: + metadata: + environment: dev + region: us-east-1 + name: config diff --git a/test/grammar/schema/assign_stmt/assign_stmt_3/main.k b/test/grammar/schema/assign_stmt/assign_stmt_3/main.k new file mode 100644 index 000000000..f1568a0f2 --- /dev/null +++ b/test/grammar/schema/assign_stmt/assign_stmt_3/main.k @@ -0,0 +1,16 @@ +schema Metadata: + environment: str + region: str + name: str + +schema MySchema1: + metadata: Metadata + +schema MySchema2(MySchema1): + metadata.environment = "dev" + +schema MySchema3(MySchema2): + metadata.region = "us-east-1" + +output = MySchema3 {metadata.name = "hello"} + diff --git a/test/grammar/schema/assign_stmt/assign_stmt_3/stdout.golden b/test/grammar/schema/assign_stmt/assign_stmt_3/stdout.golden new file mode 100644 index 000000000..5f647f0ee --- /dev/null +++ b/test/grammar/schema/assign_stmt/assign_stmt_3/stdout.golden @@ -0,0 +1,5 @@ +output: + metadata: + environment: dev + region: us-east-1 + name: hello diff --git a/test/grammar/schema/assign_stmt/assign_stmt_4/main.k b/test/grammar/schema/assign_stmt/assign_stmt_4/main.k new file mode 100644 index 000000000..ab61e786e --- /dev/null +++ b/test/grammar/schema/assign_stmt/assign_stmt_4/main.k @@ -0,0 +1,18 @@ +schema Metadata: + environment: str + region: str + name: str + +schema MySchema1: + metadata: Metadata + +schema MySchema2(MySchema1): + metadata.environment = "dev" + +schema MySchema3(MySchema2): + metadata.region = "us-east-1" + +output = MySchema3 { + metadata.name = "hello" + metadata.environment = "qa" +} diff --git a/test/grammar/schema/assign_stmt/assign_stmt_4/stdout.golden b/test/grammar/schema/assign_stmt/assign_stmt_4/stdout.golden new file mode 100644 index 000000000..c55b51309 --- /dev/null +++ b/test/grammar/schema/assign_stmt/assign_stmt_4/stdout.golden @@ -0,0 +1,5 @@ +output: + metadata: + environment: qa + region: us-east-1 + name: hello diff --git a/test/grammar/schema/assign_stmt/assign_stmt_5/main.k b/test/grammar/schema/assign_stmt/assign_stmt_5/main.k new file mode 100644 index 000000000..a08d60fb8 --- /dev/null +++ b/test/grammar/schema/assign_stmt/assign_stmt_5/main.k @@ -0,0 +1,9 @@ +schema MySchema: + metadata: {str:} = {} + + metadata.environment = "dev" + + +output = MySchema { + metadata.name = "config" +} diff --git a/test/grammar/schema/assign_stmt/assign_stmt_5/stdout.golden b/test/grammar/schema/assign_stmt/assign_stmt_5/stdout.golden new file mode 100644 index 000000000..37a73361b --- /dev/null +++ b/test/grammar/schema/assign_stmt/assign_stmt_5/stdout.golden @@ -0,0 +1,4 @@ +output: + metadata: + name: config + environment: dev diff --git a/test/grammar/schema/assign_stmt/assign_stmt_6/main.k b/test/grammar/schema/assign_stmt/assign_stmt_6/main.k new file mode 100644 index 000000000..5279413be --- /dev/null +++ b/test/grammar/schema/assign_stmt/assign_stmt_6/main.k @@ -0,0 +1,10 @@ +schema MySchema: + metadata: {str:} = {} + + metadata.environment = "dev" + + +output = MySchema { + metadata.environment = "qa" + metadata.name = "config" +} diff --git a/test/grammar/schema/assign_stmt/assign_stmt_6/stdout.golden b/test/grammar/schema/assign_stmt/assign_stmt_6/stdout.golden new file mode 100644 index 000000000..0ce8e1b8c --- /dev/null +++ b/test/grammar/schema/assign_stmt/assign_stmt_6/stdout.golden @@ -0,0 +1,4 @@ +output: + metadata: + environment: qa + name: config diff --git a/test/grammar/schema/assign_stmt/fail_0/main.k b/test/grammar/schema/assign_stmt/fail_0/main.k new file mode 100644 index 000000000..240e2d106 --- /dev/null +++ b/test/grammar/schema/assign_stmt/fail_0/main.k @@ -0,0 +1,4 @@ +schema Schema: + a.b = 1 + +s = Schema {} diff --git a/test/grammar/schema/assign_stmt/fail_0/stderr.golden b/test/grammar/schema/assign_stmt/fail_0/stderr.golden new file mode 100644 index 000000000..310899b9d --- /dev/null +++ b/test/grammar/schema/assign_stmt/fail_0/stderr.golden @@ -0,0 +1,6 @@ +error[E3M38]: EvaluationError + --> ${CWD}/main.k:2:1 + | +2 | a.b = 1 + | failed to update the dict. An iterable of key-value pairs was expected, but got UndefinedType. Check if the syntax for updating the dictionary with the attribute 'b' is correct + | \ No newline at end of file diff --git a/test/grammar/schema/back_ref/back_ref_0/main.k b/test/grammar/schema/back_ref/back_ref_0/main.k new file mode 100644 index 000000000..61f90b8ba --- /dev/null +++ b/test/grammar/schema/back_ref/back_ref_0/main.k @@ -0,0 +1,5 @@ +x0 = Person {} + +schema Person: + name: str = "kcl" + age: int = 1 diff --git a/test/grammar/schema/back_ref/back_ref_0/stdout.golden b/test/grammar/schema/back_ref/back_ref_0/stdout.golden new file mode 100644 index 000000000..2338d037d --- /dev/null +++ b/test/grammar/schema/back_ref/back_ref_0/stdout.golden @@ -0,0 +1,3 @@ +x0: + name: kcl + age: 1 diff --git a/test/grammar/schema/back_ref/back_ref_1/main.k b/test/grammar/schema/back_ref/back_ref_1/main.k new file mode 100644 index 000000000..9e4ea9bb9 --- /dev/null +++ b/test/grammar/schema/back_ref/back_ref_1/main.k @@ -0,0 +1,18 @@ +x0 = Person { + name.firstName = "Bob" + name.lastName = "John" +} + +schema Person: + name: Name + age: int = 1 + +x1 = Person { + name.firstName = "Alice" + name.lastName = "John" + age = 10 +} + +schema Name: + firstName: str + lastName: str diff --git a/test/grammar/schema/back_ref/back_ref_1/stdout.golden b/test/grammar/schema/back_ref/back_ref_1/stdout.golden new file mode 100644 index 000000000..a2ef53a39 --- /dev/null +++ b/test/grammar/schema/back_ref/back_ref_1/stdout.golden @@ -0,0 +1,10 @@ +x0: + name: + firstName: Bob + lastName: John + age: 1 +x1: + name: + firstName: Alice + lastName: John + age: 10 diff --git a/test/grammar/schema/check_block/check_block_fail_0/stderr.golden b/test/grammar/schema/check_block/check_block_fail_0/stderr.golden new file mode 100644 index 000000000..65a581be4 --- /dev/null +++ b/test/grammar/schema/check_block/check_block_fail_0/stderr.golden @@ -0,0 +1,24 @@ +error[E1001]: InvalidSyntax + --> ${CWD}/main.k:12:19 + | +12 | (lastName not None) + | ^ expected one of [")"] got identifier + | +error[E1001]: InvalidSyntax + --> ${CWD}/main.k:12:27 + | +12 | (lastName not None) + | ^ expected one of ["identifier", "literal", "(", "[", "{"] got ) + | +error[E1001]: InvalidSyntax + --> ${CWD}/main.k:12:27 + | +12 | (lastName not None) + | ^ expected expression, got ) + | +error[E1001]: InvalidSyntax + --> ${CWD}/main.k:12:27 + | +12 | (lastName not None) + | ^ expected one of ["identifier", "literal", "(", "[", "{"] got newline + | \ No newline at end of file diff --git a/test/grammar/schema/check_block/check_block_fail_0/stderr.golden.py b/test/grammar/schema/check_block/check_block_fail_0/stderr.golden.py deleted file mode 100644 index c58bf295a..000000000 --- a/test/grammar/schema/check_block/check_block_fail_0/stderr.golden.py +++ /dev/null @@ -1,25 +0,0 @@ - -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception(err_type=kcl_error.ErrType.SchemaCheckFailure_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=10, - arg_msg=kcl_error.SCHEMA_CHECK_FILE_MSG_COND - ), - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=19, - col_no=11, - arg_msg=kcl_error.SCHEMA_CHECK_FILE_MSG_ERR - ), - ]) - , file=sys.stdout -) - diff --git a/test/grammar/schema/check_block/check_block_fail_1/stderr.golden b/test/grammar/schema/check_block/check_block_fail_1/stderr.golden new file mode 100644 index 000000000..592dca22d --- /dev/null +++ b/test/grammar/schema/check_block/check_block_fail_1/stderr.golden @@ -0,0 +1,11 @@ +error[E3M38]: EvaluationError + --> ${CWD}/main.k:9:11 + | +9 | JohnDoe = Person { + | ^ Instance check failed + | + --> ${CWD}/main.k:7:1 + | +7 | age < 140, "age is too large" + | Check failed on the condition: age is too large + | \ No newline at end of file diff --git a/test/grammar/schema/check_block/check_block_fail_1/stderr.golden.py b/test/grammar/schema/check_block/check_block_fail_1/stderr.golden.py deleted file mode 100644 index 478860683..000000000 --- a/test/grammar/schema/check_block/check_block_fail_1/stderr.golden.py +++ /dev/null @@ -1,26 +0,0 @@ - -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception(err_type=kcl_error.ErrType.SchemaCheckFailure_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=7, - arg_msg=kcl_error.SCHEMA_CHECK_FILE_MSG_COND, - ), - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=9, - col_no=11, - arg_msg=kcl_error.SCHEMA_CHECK_FILE_MSG_ERR, - ), - ], - arg_msg="age is too large") - , file=sys.stdout -) - diff --git a/test/grammar/schema/check_block/check_block_fail_10/stderr.golden b/test/grammar/schema/check_block/check_block_fail_10/stderr.golden new file mode 100644 index 000000000..41b5ff4aa --- /dev/null +++ b/test/grammar/schema/check_block/check_block_fail_10/stderr.golden @@ -0,0 +1,11 @@ +error[E3M38]: EvaluationError + --> ${CWD}/main.k:8:9 + | +8 | count = Count { + | ^ Instance check failed + | + --> ${CWD}/main.k:6:1 + | +6 | secondCount < 100 + | Check failed on the condition + | \ No newline at end of file diff --git a/test/grammar/schema/check_block/check_block_fail_10/stderr.golden.py b/test/grammar/schema/check_block/check_block_fail_10/stderr.golden.py deleted file mode 100644 index 55d498f65..000000000 --- a/test/grammar/schema/check_block/check_block_fail_10/stderr.golden.py +++ /dev/null @@ -1,25 +0,0 @@ - -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception(err_type=kcl_error.ErrType.SchemaCheckFailure_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=6, - arg_msg=kcl_error.SCHEMA_CHECK_FILE_MSG_COND - ), - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=8, - col_no=9, - arg_msg=kcl_error.SCHEMA_CHECK_FILE_MSG_ERR - ), - ]) - , file=sys.stdout -) - diff --git a/test/grammar/schema/check_block/check_block_fail_11/stderr.golden b/test/grammar/schema/check_block/check_block_fail_11/stderr.golden new file mode 100644 index 000000000..5e149cee5 --- /dev/null +++ b/test/grammar/schema/check_block/check_block_fail_11/stderr.golden @@ -0,0 +1,11 @@ +error[E3M38]: EvaluationError + --> ${CWD}/main.k:3:9 + | +3 | alice = pkg.Person {} + | ^ Instance check failed + | + --> ${CWD}/pkg/person.k:5:1 + | +5 | name, "name should be defined" + | Check failed on the condition: name should be defined + | \ No newline at end of file diff --git a/test/grammar/schema/check_block/check_block_fail_11/stderr.golden.py b/test/grammar/schema/check_block/check_block_fail_11/stderr.golden.py deleted file mode 100644 index 80933a12c..000000000 --- a/test/grammar/schema/check_block/check_block_fail_11/stderr.golden.py +++ /dev/null @@ -1,26 +0,0 @@ - -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception(err_type=kcl_error.ErrType.SchemaCheckFailure_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/pkg/person.k", - line_no=5, - arg_msg=kcl_error.SCHEMA_CHECK_FILE_MSG_COND - ), - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=3, - col_no=9, - arg_msg=kcl_error.SCHEMA_CHECK_FILE_MSG_ERR - ), - ], - arg_msg="name should be defined") - , file=sys.stdout -) - diff --git a/test/grammar/schema/check_block/check_block_fail_2/stderr.golden b/test/grammar/schema/check_block/check_block_fail_2/stderr.golden new file mode 100644 index 000000000..ff2140ab5 --- /dev/null +++ b/test/grammar/schema/check_block/check_block_fail_2/stderr.golden @@ -0,0 +1,11 @@ +error[E3M38]: EvaluationError + --> ${CWD}/main.k:13:11 + | +13 | JohnDoe = Student { + | ^ Instance check failed + | + --> ${CWD}/main.k:11:1 + | +11 | 12 <= age <= 18 + | Check failed on the condition + | \ No newline at end of file diff --git a/test/grammar/schema/check_block/check_block_fail_2/stderr.golden.py b/test/grammar/schema/check_block/check_block_fail_2/stderr.golden.py deleted file mode 100644 index 899f3ee56..000000000 --- a/test/grammar/schema/check_block/check_block_fail_2/stderr.golden.py +++ /dev/null @@ -1,25 +0,0 @@ - -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception(err_type=kcl_error.ErrType.SchemaCheckFailure_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=11, - arg_msg=kcl_error.SCHEMA_CHECK_FILE_MSG_COND - ), - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=13, - col_no=11, - arg_msg=kcl_error.SCHEMA_CHECK_FILE_MSG_ERR - ), - ]) - , file=sys.stdout -) - diff --git a/test/grammar/schema/check_block/check_block_fail_3/stderr.golden b/test/grammar/schema/check_block/check_block_fail_3/stderr.golden new file mode 100644 index 000000000..2b73867e1 --- /dev/null +++ b/test/grammar/schema/check_block/check_block_fail_3/stderr.golden @@ -0,0 +1,11 @@ +error[E3M38]: EvaluationError + --> ${CWD}/main.k:13:11 + | +13 | JohnDoe = Student { + | ^ Instance check failed + | + --> ${CWD}/main.k:6:1 + | +6 | len(lastName) < 10 + | Check failed on the condition + | \ No newline at end of file diff --git a/test/grammar/schema/check_block/check_block_fail_3/stderr.golden.py b/test/grammar/schema/check_block/check_block_fail_3/stderr.golden.py deleted file mode 100644 index 51ccccd68..000000000 --- a/test/grammar/schema/check_block/check_block_fail_3/stderr.golden.py +++ /dev/null @@ -1,25 +0,0 @@ - -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception(err_type=kcl_error.ErrType.SchemaCheckFailure_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=6, - arg_msg=kcl_error.SCHEMA_CHECK_FILE_MSG_COND - ), - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=13, - col_no=11, - arg_msg=kcl_error.SCHEMA_CHECK_FILE_MSG_ERR - ), - ]) - , file=sys.stdout -) - diff --git a/test/grammar/schema/check_block/check_block_fail_4/stderr.golden b/test/grammar/schema/check_block/check_block_fail_4/stderr.golden new file mode 100644 index 000000000..6026cdd15 --- /dev/null +++ b/test/grammar/schema/check_block/check_block_fail_4/stderr.golden @@ -0,0 +1,11 @@ +error[E3M38]: EvaluationError + --> ${CWD}/main.k:8:14 + | +8 | SameenShaw = Person { + | ^ Instance check failed + | + --> ${CWD}/main.k:6:1 + | +6 | "father" not in family if family + | Check failed on the condition + | \ No newline at end of file diff --git a/test/grammar/schema/check_block/check_block_fail_4/stderr.golden.py b/test/grammar/schema/check_block/check_block_fail_4/stderr.golden.py deleted file mode 100644 index cebae8ba3..000000000 --- a/test/grammar/schema/check_block/check_block_fail_4/stderr.golden.py +++ /dev/null @@ -1,25 +0,0 @@ - -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception(err_type=kcl_error.ErrType.SchemaCheckFailure_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=6, - arg_msg=kcl_error.SCHEMA_CHECK_FILE_MSG_COND - ), - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=8, - col_no=14, - arg_msg=kcl_error.SCHEMA_CHECK_FILE_MSG_ERR - ), - ]) - , file=sys.stdout -) - diff --git a/test/grammar/schema/check_block/check_block_fail_5/stderr.golden b/test/grammar/schema/check_block/check_block_fail_5/stderr.golden new file mode 100644 index 000000000..fe3996074 --- /dev/null +++ b/test/grammar/schema/check_block/check_block_fail_5/stderr.golden @@ -0,0 +1,11 @@ +error[E3M38]: EvaluationError + --> ${CWD}/main.k:9:11 + | +9 | JohnDoe = Person { + | ^ Instance check failed + | + --> ${CWD}/main.k:6:1 + | +6 | name, "name should be defined and not empty" + | Check failed on the condition: name should be defined and not empty + | \ No newline at end of file diff --git a/test/grammar/schema/check_block/check_block_fail_5/stderr.golden.py b/test/grammar/schema/check_block/check_block_fail_5/stderr.golden.py deleted file mode 100644 index f93873685..000000000 --- a/test/grammar/schema/check_block/check_block_fail_5/stderr.golden.py +++ /dev/null @@ -1,24 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception(err_type=kcl_error.ErrType.SchemaCheckFailure_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=6, - arg_msg=kcl_error.SCHEMA_CHECK_FILE_MSG_COND - ), - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=9, - col_no=11, - arg_msg=kcl_error.SCHEMA_CHECK_FILE_MSG_ERR - ), - ], - arg_msg="name should be defined and not empty") - , file=sys.stdout -) diff --git a/test/grammar/schema/check_block/check_block_fail_6/stderr.golden b/test/grammar/schema/check_block/check_block_fail_6/stderr.golden new file mode 100644 index 000000000..945357cc1 --- /dev/null +++ b/test/grammar/schema/check_block/check_block_fail_6/stderr.golden @@ -0,0 +1,11 @@ +error[E3M38]: EvaluationError + --> ${CWD}/main.k:9:11 + | +9 | JohnDoe = Person { + | ^ Instance check failed + | + --> ${CWD}/main.k:7:1 + | +7 | labels, "labels should be defined and not empty" + | Check failed on the condition: labels should be defined and not empty + | \ No newline at end of file diff --git a/test/grammar/schema/check_block/check_block_fail_6/stderr.golden.py b/test/grammar/schema/check_block/check_block_fail_6/stderr.golden.py deleted file mode 100644 index bd9a20b70..000000000 --- a/test/grammar/schema/check_block/check_block_fail_6/stderr.golden.py +++ /dev/null @@ -1,25 +0,0 @@ - -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception(err_type=kcl_error.ErrType.SchemaCheckFailure_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=7, - arg_msg=kcl_error.SCHEMA_CHECK_FILE_MSG_COND - ), - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=9, - col_no=11, - arg_msg=kcl_error.SCHEMA_CHECK_FILE_MSG_ERR - ), - ], - arg_msg="labels should be defined and not empty") - , file=sys.stdout -) diff --git a/test/grammar/schema/check_block/check_block_fail_7/stderr.golden b/test/grammar/schema/check_block/check_block_fail_7/stderr.golden new file mode 100644 index 000000000..945357cc1 --- /dev/null +++ b/test/grammar/schema/check_block/check_block_fail_7/stderr.golden @@ -0,0 +1,11 @@ +error[E3M38]: EvaluationError + --> ${CWD}/main.k:9:11 + | +9 | JohnDoe = Person { + | ^ Instance check failed + | + --> ${CWD}/main.k:7:1 + | +7 | labels, "labels should be defined and not empty" + | Check failed on the condition: labels should be defined and not empty + | \ No newline at end of file diff --git a/test/grammar/schema/check_block/check_block_fail_7/stderr.golden.py b/test/grammar/schema/check_block/check_block_fail_7/stderr.golden.py deleted file mode 100644 index bd9a20b70..000000000 --- a/test/grammar/schema/check_block/check_block_fail_7/stderr.golden.py +++ /dev/null @@ -1,25 +0,0 @@ - -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception(err_type=kcl_error.ErrType.SchemaCheckFailure_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=7, - arg_msg=kcl_error.SCHEMA_CHECK_FILE_MSG_COND - ), - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=9, - col_no=11, - arg_msg=kcl_error.SCHEMA_CHECK_FILE_MSG_ERR - ), - ], - arg_msg="labels should be defined and not empty") - , file=sys.stdout -) diff --git a/test/grammar/schema/check_block/check_block_fail_8/stderr.golden b/test/grammar/schema/check_block/check_block_fail_8/stderr.golden new file mode 100644 index 000000000..945357cc1 --- /dev/null +++ b/test/grammar/schema/check_block/check_block_fail_8/stderr.golden @@ -0,0 +1,11 @@ +error[E3M38]: EvaluationError + --> ${CWD}/main.k:9:11 + | +9 | JohnDoe = Person { + | ^ Instance check failed + | + --> ${CWD}/main.k:7:1 + | +7 | labels, "labels should be defined and not empty" + | Check failed on the condition: labels should be defined and not empty + | \ No newline at end of file diff --git a/test/grammar/schema/check_block/check_block_fail_8/stderr.golden.py b/test/grammar/schema/check_block/check_block_fail_8/stderr.golden.py deleted file mode 100644 index bd9a20b70..000000000 --- a/test/grammar/schema/check_block/check_block_fail_8/stderr.golden.py +++ /dev/null @@ -1,25 +0,0 @@ - -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception(err_type=kcl_error.ErrType.SchemaCheckFailure_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=7, - arg_msg=kcl_error.SCHEMA_CHECK_FILE_MSG_COND - ), - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=9, - col_no=11, - arg_msg=kcl_error.SCHEMA_CHECK_FILE_MSG_ERR - ), - ], - arg_msg="labels should be defined and not empty") - , file=sys.stdout -) diff --git a/test/grammar/schema/check_block/check_block_fail_9/stderr.golden b/test/grammar/schema/check_block/check_block_fail_9/stderr.golden new file mode 100644 index 000000000..9ca6f0f2c --- /dev/null +++ b/test/grammar/schema/check_block/check_block_fail_9/stderr.golden @@ -0,0 +1,11 @@ +error[E3M38]: EvaluationError + --> ${CWD}/main.k:10:13 + | +10 | "name": Name {} + | ^ Instance check failed + | + --> ${CWD}/main.k:4:1 + | +4 | firstName, "firstName should be defined and not empty" + | Check failed on the condition: firstName should be defined and not empty + | \ No newline at end of file diff --git a/test/grammar/schema/check_block/check_block_fail_9/stderr.golden.py b/test/grammar/schema/check_block/check_block_fail_9/stderr.golden.py deleted file mode 100644 index 64402d7a5..000000000 --- a/test/grammar/schema/check_block/check_block_fail_9/stderr.golden.py +++ /dev/null @@ -1,26 +0,0 @@ - -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception(err_type=kcl_error.ErrType.SchemaCheckFailure_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=4, - arg_msg=kcl_error.SCHEMA_CHECK_FILE_MSG_COND - ), - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=10, - col_no=13, - arg_msg=kcl_error.SCHEMA_CHECK_FILE_MSG_ERR - ), - ], - arg_msg="firstName should be defined and not empty") - , file=sys.stdout -) - diff --git a/test/grammar/schema/config_op/delete/delete_0/main.k b/test/grammar/schema/config_op/delete/delete_0/main.k index 77b9de075..44ab3e558 100644 --- a/test/grammar/schema/config_op/delete/delete_0/main.k +++ b/test/grammar/schema/config_op/delete/delete_0/main.k @@ -4,5 +4,8 @@ schema Person: person = Person { info = {"key2": "value2"} - hc[0] = None +} +personDeleteHc0 = { + **person + hc[0] = Undefined } diff --git a/test/grammar/schema/config_op/delete/delete_0/stdout.golden b/test/grammar/schema/config_op/delete/delete_0/stdout.golden index 5d7086c6e..2e9e2cafa 100644 --- a/test/grammar/schema/config_op/delete/delete_0/stdout.golden +++ b/test/grammar/schema/config_op/delete/delete_0/stdout.golden @@ -1,4 +1,11 @@ person: + info: + key2: value2 + hc: + - 1 + - 2 + - 3 +personDeleteHc0: info: key2: value2 hc: diff --git a/test/grammar/schema/config_op/insert/insert_5/main.k b/test/grammar/schema/config_op/insert/insert_5/main.k new file mode 100644 index 000000000..3d63d1800 --- /dev/null +++ b/test/grammar/schema/config_op/insert/insert_5/main.k @@ -0,0 +1,9 @@ +schema x: + m: [str] = ["hello"] + +s = x { +} + +t = s | { + m += ["world"] +} diff --git a/test/grammar/schema/config_op/insert/insert_5/stdout.golden b/test/grammar/schema/config_op/insert/insert_5/stdout.golden new file mode 100644 index 000000000..e1a8ce78b --- /dev/null +++ b/test/grammar/schema/config_op/insert/insert_5/stdout.golden @@ -0,0 +1,7 @@ +s: + m: + - hello +t: + m: + - hello + - world diff --git a/test/grammar/schema/config_op/insert/insert_6/main.k b/test/grammar/schema/config_op/insert/insert_6/main.k new file mode 100644 index 000000000..9a713ba8f --- /dev/null +++ b/test/grammar/schema/config_op/insert/insert_6/main.k @@ -0,0 +1,14 @@ +schema x: + m: [str] = ["hello"] + nn = m + +s = x { +} + +t = s | { + m += ["world"] +} | { + m = ["world"] +} | { + m += ["hello"] +} \ No newline at end of file diff --git a/test/grammar/schema/config_op/insert/insert_6/stdout.golden b/test/grammar/schema/config_op/insert/insert_6/stdout.golden new file mode 100644 index 000000000..deb2dde05 --- /dev/null +++ b/test/grammar/schema/config_op/insert/insert_6/stdout.golden @@ -0,0 +1,12 @@ +s: + m: + - hello + nn: + - hello +t: + m: + - world + - hello + nn: + - world + - hello diff --git a/test/grammar/schema/config_op/override/override_3/main.k b/test/grammar/schema/config_op/override/override_3/main.k new file mode 100644 index 000000000..a37f015f8 --- /dev/null +++ b/test/grammar/schema/config_op/override/override_3/main.k @@ -0,0 +1,10 @@ +schema MySubSchema: + a: int + b: str + c: {str:str} + d: str = c[b] + +schema MyTestSchema: + field1?: [MySubSchema] = [{a = 1, b = "key", c = {key = "value"}}] + +instance = MyTestSchema {field1: None} diff --git a/test/grammar/schema/config_op/override/override_3/stdout.golden b/test/grammar/schema/config_op/override/override_3/stdout.golden new file mode 100644 index 000000000..ad5c75267 --- /dev/null +++ b/test/grammar/schema/config_op/override/override_3/stdout.golden @@ -0,0 +1,7 @@ +instance: + field1: + - a: 1 + b: key + c: + key: value + d: value diff --git a/test/grammar/schema/config_op/override/override_4/main.k b/test/grammar/schema/config_op/override/override_4/main.k new file mode 100644 index 000000000..6ebce8331 --- /dev/null +++ b/test/grammar/schema/config_op/override/override_4/main.k @@ -0,0 +1,10 @@ +schema MySubSchema: + a: int + b: str + c: {str:str} + d: str = c[b] + +schema MyTestSchema: + field1?: [MySubSchema] = [{a: 1}] + +instance = MyTestSchema {field1 = None} diff --git a/test/grammar/schema/config_op/override/override_4/stdout.golden b/test/grammar/schema/config_op/override/override_4/stdout.golden new file mode 100644 index 000000000..044cef528 --- /dev/null +++ b/test/grammar/schema/config_op/override/override_4/stdout.golden @@ -0,0 +1,2 @@ +instance: + field1: null diff --git a/test/grammar/schema/config_op/union/union_3/main.k b/test/grammar/schema/config_op/union/union_3/main.k new file mode 100644 index 000000000..5fd791c44 --- /dev/null +++ b/test/grammar/schema/config_op/union/union_3/main.k @@ -0,0 +1,62 @@ +schema ResourceMapping: + [str]: any + +schema BaseFrontend: + name: str + +protocol MixinProtocol: + count: int + resources: ResourceMapping + +mixin Mixin1Mixin for MixinProtocol: + resources: ResourceMapping { + resource1 += [{ + a = "a" + }] + } + count += 1 + +mixin Mixin2Mixin for MixinProtocol: + resources: ResourceMapping { + resource2 += [{ + b = "b" + }] + } + count += 1 + +mixin Mixin3Mixin for MixinProtocol: + resources: ResourceMapping { + resource3 += [{ + c = "c" + }] + } + count += 1 + +schema BaseBackend[a: BaseFrontend]: + mixin [ + Mixin1Mixin, + Mixin2Mixin, + Mixin3Mixin, + Mixin3Mixin, + ] + resources: ResourceMapping + count: int = 0 + +render = lambda a: BaseFrontend { + impl = BaseBackend(a) + impl +} +frontEnd = BaseFrontend {name = "app"} +res1 = [render(a) for a in BaseFrontend.instances()] +res2 = [BaseBackend(a) for a in BaseFrontend.instances()] +resources: ResourceMapping {} +resources: ResourceMapping { + resource1 += [{ + a = "a" + }] +} +resources: ResourceMapping { + resource2 += [{ + b = "b" + }] +} diff --git a/test/grammar/schema/config_op/union/union_3/stdout.golden b/test/grammar/schema/config_op/union/union_3/stdout.golden new file mode 100644 index 000000000..9b19f672b --- /dev/null +++ b/test/grammar/schema/config_op/union/union_3/stdout.golden @@ -0,0 +1,27 @@ +frontEnd: + name: app +res1: +- resources: + resource1: + - a: a + resource2: + - b: b + resource3: + - c: c + - c: c + count: 4 +res2: +- resources: + resource1: + - a: a + resource2: + - b: b + resource3: + - c: c + - c: c + count: 4 +resources: + resource1: + - a: a + resource2: + - b: b diff --git a/test/grammar/schema/default_value/default_value_3/main.k b/test/grammar/schema/default_value/default_value_3/main.k new file mode 100644 index 000000000..25e960154 --- /dev/null +++ b/test/grammar/schema/default_value/default_value_3/main.k @@ -0,0 +1,9 @@ +schema Config: + val0: "val" + val1: 1 + val2: 1Ki + val3: 2.0 + val4: True + val5: False + +c = Config {} diff --git a/test/grammar/schema/default_value/default_value_3/stdout.golden b/test/grammar/schema/default_value/default_value_3/stdout.golden new file mode 100644 index 000000000..d555630f2 --- /dev/null +++ b/test/grammar/schema/default_value/default_value_3/stdout.golden @@ -0,0 +1,7 @@ +c: + val0: val + val1: 1 + val2: 1024.0 + val3: 2.0 + val4: true + val5: false diff --git a/test/grammar/schema/deprecated/illegal_arg_fail_0/stderr.golden b/test/grammar/schema/deprecated/illegal_arg_fail_0/stderr.golden new file mode 100644 index 000000000..2af97fe72 --- /dev/null +++ b/test/grammar/schema/deprecated/illegal_arg_fail_0/stderr.golden @@ -0,0 +1,6 @@ +error[E1001]: InvalidSyntax + --> ${CWD}/main.k:3:31 + | +3 | @deprecated(strict=False, "1.16") + | ^ positional argument follows keyword argument + | \ No newline at end of file diff --git a/test/grammar/schema/deprecated/illegal_arg_fail_0/stderr.golden.py b/test/grammar/schema/deprecated/illegal_arg_fail_0/stderr.golden.py deleted file mode 100644 index 701db9bc1..000000000 --- a/test/grammar/schema/deprecated/illegal_arg_fail_0/stderr.golden.py +++ /dev/null @@ -1,19 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception(err_type=kcl_error.ErrType.IllegalArgumentError_Syntax_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=3, - col_no=31, - end_col_no=37 - ) - ], - arg_msg="positional argument follows keyword argument"), - file=sys.stdout -) diff --git a/test/grammar/schema/deprecated/member_simple_0/stderr.golden b/test/grammar/schema/deprecated/member_simple_0/stderr.golden new file mode 100644 index 000000000..1e98b0933 --- /dev/null +++ b/test/grammar/schema/deprecated/member_simple_0/stderr.golden @@ -0,0 +1,6 @@ +error[E3M38]: EvaluationError + --> ${CWD}/main.k:7:1 + | +7 | JohnDoe = Person { + | name was deprecated + | \ No newline at end of file diff --git a/test/grammar/schema/deprecated/member_simple_0/stderr.golden.py b/test/grammar/schema/deprecated/member_simple_0/stderr.golden.py deleted file mode 100644 index b42f84d01..000000000 --- a/test/grammar/schema/deprecated/member_simple_0/stderr.golden.py +++ /dev/null @@ -1,19 +0,0 @@ - -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception(err_type=kcl_error.ErrType.Deprecated_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=7, - ), - ], - arg_msg=kcl_error.DEPRECATED_WARNING_MSG.format("name","")) - , file=sys.stdout -) - diff --git a/test/grammar/schema/deprecated/member_simple_1/stderr.golden b/test/grammar/schema/deprecated/member_simple_1/stderr.golden new file mode 100644 index 000000000..965618a7a --- /dev/null +++ b/test/grammar/schema/deprecated/member_simple_1/stderr.golden @@ -0,0 +1,6 @@ +error[E3M38]: EvaluationError + --> ${CWD}/main.k:8:1 + | +8 | JohnDoe = Person { + | name was deprecated + | \ No newline at end of file diff --git a/test/grammar/schema/deprecated/member_simple_1/stderr.golden.py b/test/grammar/schema/deprecated/member_simple_1/stderr.golden.py deleted file mode 100644 index 670370979..000000000 --- a/test/grammar/schema/deprecated/member_simple_1/stderr.golden.py +++ /dev/null @@ -1,19 +0,0 @@ - -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception(err_type=kcl_error.ErrType.Deprecated_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=8, - ), - ], - arg_msg=kcl_error.DEPRECATED_WARNING_MSG.format("name", "")) - , file=sys.stdout -) - diff --git a/test/grammar/schema/deprecated/member_simple_3/stderr.golden b/test/grammar/schema/deprecated/member_simple_3/stderr.golden new file mode 100644 index 000000000..a135f6e78 --- /dev/null +++ b/test/grammar/schema/deprecated/member_simple_3/stderr.golden @@ -0,0 +1,6 @@ +error[E3M38]: EvaluationError + --> ${CWD}/main.k:7:1 + | +7 | attrs: ObsoleteSchema = ObsoleteSchema {} + | ObsoleteSchema was deprecated + | \ No newline at end of file diff --git a/test/grammar/schema/deprecated/member_simple_3/stderr.golden.py b/test/grammar/schema/deprecated/member_simple_3/stderr.golden.py deleted file mode 100644 index 0e44f2624..000000000 --- a/test/grammar/schema/deprecated/member_simple_3/stderr.golden.py +++ /dev/null @@ -1,19 +0,0 @@ - -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception(err_type=kcl_error.ErrType.Deprecated_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=7, - ), - ], - arg_msg=kcl_error.DEPRECATED_WARNING_MSG.format("ObsoleteSchema", "")) - , file=sys.stdout -) - diff --git a/test/grammar/schema/deprecated/member_standard_0/stderr.golden b/test/grammar/schema/deprecated/member_standard_0/stderr.golden new file mode 100644 index 000000000..579160ff2 --- /dev/null +++ b/test/grammar/schema/deprecated/member_standard_0/stderr.golden @@ -0,0 +1,6 @@ +error[E3M38]: EvaluationError + --> ${CWD}/main.k:7:1 + | +7 | JohnDoe = Person { + | name was deprecated since version 1.16, use firstName and lastName instead + | \ No newline at end of file diff --git a/test/grammar/schema/deprecated/member_standard_0/stderr.golden.py b/test/grammar/schema/deprecated/member_standard_0/stderr.golden.py deleted file mode 100644 index a0e057c99..000000000 --- a/test/grammar/schema/deprecated/member_standard_0/stderr.golden.py +++ /dev/null @@ -1,19 +0,0 @@ - -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception(err_type=kcl_error.ErrType.Deprecated_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=7, - ), - ], - arg_msg=kcl_error.DEPRECATED_WARNING_MSG.format("name", "since version 1.16, use firstName and lastName instead")) - , file=sys.stdout -) - diff --git a/test/grammar/schema/deprecated/member_standard_1/stderr.golden b/test/grammar/schema/deprecated/member_standard_1/stderr.golden new file mode 100644 index 000000000..579160ff2 --- /dev/null +++ b/test/grammar/schema/deprecated/member_standard_1/stderr.golden @@ -0,0 +1,6 @@ +error[E3M38]: EvaluationError + --> ${CWD}/main.k:7:1 + | +7 | JohnDoe = Person { + | name was deprecated since version 1.16, use firstName and lastName instead + | \ No newline at end of file diff --git a/test/grammar/schema/deprecated/member_standard_1/stderr.golden.py b/test/grammar/schema/deprecated/member_standard_1/stderr.golden.py deleted file mode 100644 index a0e057c99..000000000 --- a/test/grammar/schema/deprecated/member_standard_1/stderr.golden.py +++ /dev/null @@ -1,19 +0,0 @@ - -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception(err_type=kcl_error.ErrType.Deprecated_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=7, - ), - ], - arg_msg=kcl_error.DEPRECATED_WARNING_MSG.format("name", "since version 1.16, use firstName and lastName instead")) - , file=sys.stdout -) - diff --git a/test/grammar/schema/deprecated/member_standard_2/stderr.golden b/test/grammar/schema/deprecated/member_standard_2/stderr.golden new file mode 100644 index 000000000..579160ff2 --- /dev/null +++ b/test/grammar/schema/deprecated/member_standard_2/stderr.golden @@ -0,0 +1,6 @@ +error[E3M38]: EvaluationError + --> ${CWD}/main.k:7:1 + | +7 | JohnDoe = Person { + | name was deprecated since version 1.16, use firstName and lastName instead + | \ No newline at end of file diff --git a/test/grammar/schema/deprecated/member_standard_2/stderr.golden.py b/test/grammar/schema/deprecated/member_standard_2/stderr.golden.py deleted file mode 100644 index a0e057c99..000000000 --- a/test/grammar/schema/deprecated/member_standard_2/stderr.golden.py +++ /dev/null @@ -1,19 +0,0 @@ - -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception(err_type=kcl_error.ErrType.Deprecated_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=7, - ), - ], - arg_msg=kcl_error.DEPRECATED_WARNING_MSG.format("name", "since version 1.16, use firstName and lastName instead")) - , file=sys.stdout -) - diff --git a/test/grammar/schema/deprecated/member_standard_3/stderr.golden b/test/grammar/schema/deprecated/member_standard_3/stderr.golden new file mode 100644 index 000000000..5df74dd16 --- /dev/null +++ b/test/grammar/schema/deprecated/member_standard_3/stderr.golden @@ -0,0 +1,6 @@ +error[E3M38]: EvaluationError + --> ${CWD}/main.k:9:1 + | +9 | JohnDoe = Person { + | name was deprecated since version 1.16, use firstName and lastName instead + | \ No newline at end of file diff --git a/test/grammar/schema/deprecated/member_standard_3/stderr.golden.py b/test/grammar/schema/deprecated/member_standard_3/stderr.golden.py deleted file mode 100644 index c5f919d4a..000000000 --- a/test/grammar/schema/deprecated/member_standard_3/stderr.golden.py +++ /dev/null @@ -1,19 +0,0 @@ - -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception(err_type=kcl_error.ErrType.Deprecated_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=9, - ), - ], - arg_msg=kcl_error.DEPRECATED_WARNING_MSG.format("name", "since version 1.16, use firstName and lastName instead")) - , file=sys.stdout -) - diff --git a/test/grammar/schema/deprecated/member_standard_4/stderr.golden b/test/grammar/schema/deprecated/member_standard_4/stderr.golden new file mode 100644 index 000000000..4adabed9a --- /dev/null +++ b/test/grammar/schema/deprecated/member_standard_4/stderr.golden @@ -0,0 +1,6 @@ +error[E3M38]: EvaluationError + --> ${CWD}/main.k:10:1 + | +10 | JohnDoe = Son { + | name was deprecated since version 1.16, use firstName and lastName instead + | \ No newline at end of file diff --git a/test/grammar/schema/deprecated/member_standard_4/stderr.golden.py b/test/grammar/schema/deprecated/member_standard_4/stderr.golden.py deleted file mode 100644 index d1112365b..000000000 --- a/test/grammar/schema/deprecated/member_standard_4/stderr.golden.py +++ /dev/null @@ -1,19 +0,0 @@ - -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception(err_type=kcl_error.ErrType.Deprecated_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=10, - ), - ], - arg_msg=kcl_error.DEPRECATED_WARNING_MSG.format("name", "since version 1.16, use firstName and lastName instead")) - , file=sys.stdout -) - diff --git a/test/grammar/schema/deprecated/member_warning_0/main.k b/test/grammar/schema/deprecated/member_warning_0/main.k index 914fc1e9d..831a5a043 100644 --- a/test/grammar/schema/deprecated/member_warning_0/main.k +++ b/test/grammar/schema/deprecated/member_warning_0/main.k @@ -1,7 +1,7 @@ schema Person: firstName?: str = "John" lastName?: str - @deprecated(version="1.16", reason="use firstName and lastName instead", strict=False) + @deprecated(version="1.16", reason="use firstName and lastName instead", strict=True) name?: str JohnDoe = Person { diff --git a/test/grammar/schema/deprecated/member_warning_0/stderr.golden b/test/grammar/schema/deprecated/member_warning_0/stderr.golden new file mode 100644 index 000000000..579160ff2 --- /dev/null +++ b/test/grammar/schema/deprecated/member_warning_0/stderr.golden @@ -0,0 +1,6 @@ +error[E3M38]: EvaluationError + --> ${CWD}/main.k:7:1 + | +7 | JohnDoe = Person { + | name was deprecated since version 1.16, use firstName and lastName instead + | \ No newline at end of file diff --git a/test/grammar/schema/deprecated/member_warning_0/stderr.golden.py b/test/grammar/schema/deprecated/member_warning_0/stderr.golden.py deleted file mode 100644 index 4aee93cfa..000000000 --- a/test/grammar/schema/deprecated/member_warning_0/stderr.golden.py +++ /dev/null @@ -1,14 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_warning_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.Deprecated_Warning_TYPE, - arg_msg=kcl_error.DEPRECATED_WARNING_MSG.format("name", "since version 1.16, use firstName and lastName instead") - ) - , file=sys.stdout -) - diff --git a/test/grammar/schema/deprecated/member_warning_1/main.k b/test/grammar/schema/deprecated/member_warning_1/main.k index bcd3d64b6..035e40e0f 100644 --- a/test/grammar/schema/deprecated/member_warning_1/main.k +++ b/test/grammar/schema/deprecated/member_warning_1/main.k @@ -1,7 +1,7 @@ schema Person: firstName?: str = "John" lastName?: str - @deprecated(strict=False) + @deprecated(strict=True) name?: str JohnDoe = Person { diff --git a/test/grammar/schema/deprecated/member_warning_1/stderr.golden b/test/grammar/schema/deprecated/member_warning_1/stderr.golden new file mode 100644 index 000000000..1e98b0933 --- /dev/null +++ b/test/grammar/schema/deprecated/member_warning_1/stderr.golden @@ -0,0 +1,6 @@ +error[E3M38]: EvaluationError + --> ${CWD}/main.k:7:1 + | +7 | JohnDoe = Person { + | name was deprecated + | \ No newline at end of file diff --git a/test/grammar/schema/deprecated/member_warning_1/stderr.golden.py b/test/grammar/schema/deprecated/member_warning_1/stderr.golden.py deleted file mode 100644 index 6ca2b9b2a..000000000 --- a/test/grammar/schema/deprecated/member_warning_1/stderr.golden.py +++ /dev/null @@ -1,14 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_warning_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.Deprecated_Warning_TYPE, - arg_msg=kcl_error.DEPRECATED_WARNING_MSG.format("name", "") - ) - , file=sys.stdout -) - diff --git a/test/grammar/schema/deprecated/schema_simple_0/stderr.golden b/test/grammar/schema/deprecated/schema_simple_0/stderr.golden new file mode 100644 index 000000000..d1253826f --- /dev/null +++ b/test/grammar/schema/deprecated/schema_simple_0/stderr.golden @@ -0,0 +1,6 @@ +error[E3M38]: EvaluationError + --> ${CWD}/main.k:7:1 + | +7 | JohnDoe = Person { + | Person was deprecated + | \ No newline at end of file diff --git a/test/grammar/schema/deprecated/schema_simple_0/stderr.golden.py b/test/grammar/schema/deprecated/schema_simple_0/stderr.golden.py deleted file mode 100644 index ac5835190..000000000 --- a/test/grammar/schema/deprecated/schema_simple_0/stderr.golden.py +++ /dev/null @@ -1,19 +0,0 @@ - -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception(err_type=kcl_error.ErrType.Deprecated_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=7, - ), - ], - arg_msg=kcl_error.DEPRECATED_WARNING_MSG.format("Person", "")) - , file=sys.stdout -) - diff --git a/test/grammar/schema/deprecated/schema_simple_1/stderr.golden b/test/grammar/schema/deprecated/schema_simple_1/stderr.golden new file mode 100644 index 000000000..97118031b --- /dev/null +++ b/test/grammar/schema/deprecated/schema_simple_1/stderr.golden @@ -0,0 +1,6 @@ +error[E3M38]: EvaluationError + --> ${CWD}/main.k:10:1 + | +10 | JohnDoe = Son {} + | Person was deprecated + | \ No newline at end of file diff --git a/test/grammar/schema/deprecated/schema_simple_1/stderr.golden.py b/test/grammar/schema/deprecated/schema_simple_1/stderr.golden.py deleted file mode 100644 index 8d8688d3d..000000000 --- a/test/grammar/schema/deprecated/schema_simple_1/stderr.golden.py +++ /dev/null @@ -1,19 +0,0 @@ - -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception(err_type=kcl_error.ErrType.Deprecated_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=10, - ), - ], - arg_msg=kcl_error.DEPRECATED_WARNING_MSG.format("Person", "")) - , file=sys.stdout -) - diff --git a/test/grammar/schema/deprecated/schema_standard_0/stderr.golden b/test/grammar/schema/deprecated/schema_standard_0/stderr.golden new file mode 100644 index 000000000..d36647851 --- /dev/null +++ b/test/grammar/schema/deprecated/schema_standard_0/stderr.golden @@ -0,0 +1,6 @@ +error[E3M38]: EvaluationError + --> ${CWD}/main.k:7:1 + | +7 | JohnDoe = Person { + | Person was deprecated since version 1.16, use SuperPerson instead + | \ No newline at end of file diff --git a/test/grammar/schema/deprecated/schema_standard_0/stderr.golden.py b/test/grammar/schema/deprecated/schema_standard_0/stderr.golden.py deleted file mode 100644 index 39bcfffb9..000000000 --- a/test/grammar/schema/deprecated/schema_standard_0/stderr.golden.py +++ /dev/null @@ -1,19 +0,0 @@ - -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception(err_type=kcl_error.ErrType.Deprecated_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=7, - ), - ], - arg_msg=kcl_error.DEPRECATED_WARNING_MSG.format("Person", "since version 1.16, use SuperPerson instead")) - , file=sys.stdout -) - diff --git a/test/grammar/schema/deprecated/schema_standard_1/stderr.golden b/test/grammar/schema/deprecated/schema_standard_1/stderr.golden new file mode 100644 index 000000000..dd7fbf46c --- /dev/null +++ b/test/grammar/schema/deprecated/schema_standard_1/stderr.golden @@ -0,0 +1,6 @@ +error[E3M38]: EvaluationError + --> ${CWD}/main.k:10:1 + | +10 | JohnDoe = Son {} + | Person was deprecated since version 1.16, use SuperPerson instead + | \ No newline at end of file diff --git a/test/grammar/schema/deprecated/schema_standard_1/stderr.golden.py b/test/grammar/schema/deprecated/schema_standard_1/stderr.golden.py deleted file mode 100644 index 70b808315..000000000 --- a/test/grammar/schema/deprecated/schema_standard_1/stderr.golden.py +++ /dev/null @@ -1,19 +0,0 @@ - -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception(err_type=kcl_error.ErrType.Deprecated_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=10 - ), - ], - arg_msg=kcl_error.DEPRECATED_WARNING_MSG.format("Person", "since version 1.16, use SuperPerson instead")) - , file=sys.stdout -) - diff --git a/test/grammar/schema/deprecated/schema_warning_0/main.k b/test/grammar/schema/deprecated/schema_warning_0/main.k index 15f204313..424b1ac31 100644 --- a/test/grammar/schema/deprecated/schema_warning_0/main.k +++ b/test/grammar/schema/deprecated/schema_warning_0/main.k @@ -1,4 +1,4 @@ -@deprecated(strict=False) +@deprecated(strict=True) schema Person: firstName?: str = "John" lastName?: str diff --git a/test/grammar/schema/deprecated/schema_warning_0/stderr.golden b/test/grammar/schema/deprecated/schema_warning_0/stderr.golden new file mode 100644 index 000000000..d1253826f --- /dev/null +++ b/test/grammar/schema/deprecated/schema_warning_0/stderr.golden @@ -0,0 +1,6 @@ +error[E3M38]: EvaluationError + --> ${CWD}/main.k:7:1 + | +7 | JohnDoe = Person { + | Person was deprecated + | \ No newline at end of file diff --git a/test/grammar/schema/deprecated/schema_warning_0/stderr.golden.py b/test/grammar/schema/deprecated/schema_warning_0/stderr.golden.py deleted file mode 100644 index a66cea3b4..000000000 --- a/test/grammar/schema/deprecated/schema_warning_0/stderr.golden.py +++ /dev/null @@ -1,14 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_warning_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.Deprecated_Warning_TYPE, - arg_msg=kcl_error.DEPRECATED_WARNING_MSG.format("Person", "") - ) - , file=sys.stdout -) - diff --git a/test/grammar/schema/deprecated/schema_warning_1/main.k b/test/grammar/schema/deprecated/schema_warning_1/main.k index b592c29ed..524daf366 100644 --- a/test/grammar/schema/deprecated/schema_warning_1/main.k +++ b/test/grammar/schema/deprecated/schema_warning_1/main.k @@ -1,4 +1,4 @@ -@deprecated(strict=False, version="1.16", reason="use SuperPerson instead") +@deprecated(strict=True, version="1.16", reason="use SuperPerson instead") schema Person: firstName?: str = "John" lastName?: str diff --git a/test/grammar/schema/deprecated/schema_warning_1/stderr.golden b/test/grammar/schema/deprecated/schema_warning_1/stderr.golden new file mode 100644 index 000000000..d36647851 --- /dev/null +++ b/test/grammar/schema/deprecated/schema_warning_1/stderr.golden @@ -0,0 +1,6 @@ +error[E3M38]: EvaluationError + --> ${CWD}/main.k:7:1 + | +7 | JohnDoe = Person { + | Person was deprecated since version 1.16, use SuperPerson instead + | \ No newline at end of file diff --git a/test/grammar/schema/deprecated/schema_warning_1/stderr.golden.py b/test/grammar/schema/deprecated/schema_warning_1/stderr.golden.py deleted file mode 100644 index c9fc44588..000000000 --- a/test/grammar/schema/deprecated/schema_warning_1/stderr.golden.py +++ /dev/null @@ -1,14 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_warning_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.Deprecated_Warning_TYPE, - arg_msg=kcl_error.DEPRECATED_WARNING_MSG.format("Person", "since version 1.16, use SuperPerson instead") - ) - , file=sys.stdout -) - diff --git a/test/grammar/schema/deprecated/unknown_fail_0/stderr.golden b/test/grammar/schema/deprecated/unknown_fail_0/stderr.golden new file mode 100644 index 000000000..66a975203 --- /dev/null +++ b/test/grammar/schema/deprecated/unknown_fail_0/stderr.golden @@ -0,0 +1,6 @@ +error[E2L23]: CompileError + --> ${CWD}/main.k:4:6 + | +4 | @err_deprecated(version="1.16", reason="use firstName and lastName instead", strict=False) + | ^ UnKnown decorator err_deprecated + | \ No newline at end of file diff --git a/test/grammar/schema/deprecated/unknown_fail_0/stderr.golden.py b/test/grammar/schema/deprecated/unknown_fail_0/stderr.golden.py deleted file mode 100644 index ffe47b71b..000000000 --- a/test/grammar/schema/deprecated/unknown_fail_0/stderr.golden.py +++ /dev/null @@ -1,21 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.UnKnownDecorator_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=4, - col_no=6 - ) - ], - arg_msg=kcl_error.UNKNOWN_DECORATOR_MSG.format("err_deprecated") - ), - file=sys.stdout -) - diff --git a/test/grammar/schema/deprecated/unknown_fail_1/stderr.golden b/test/grammar/schema/deprecated/unknown_fail_1/stderr.golden new file mode 100644 index 000000000..0007275e5 --- /dev/null +++ b/test/grammar/schema/deprecated/unknown_fail_1/stderr.golden @@ -0,0 +1,6 @@ +error[E2L23]: CompileError + --> ${CWD}/main.k:1:2 + | +1 | @err_deprecated + | ^ UnKnown decorator err_deprecated + | \ No newline at end of file diff --git a/test/grammar/schema/deprecated/unknown_fail_1/stderr.golden.py b/test/grammar/schema/deprecated/unknown_fail_1/stderr.golden.py deleted file mode 100644 index f6477ad73..000000000 --- a/test/grammar/schema/deprecated/unknown_fail_1/stderr.golden.py +++ /dev/null @@ -1,21 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.UnKnownDecorator_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=1, - col_no=2 - ) - ], - arg_msg=kcl_error.UNKNOWN_DECORATOR_MSG.format("err_deprecated") - ), - file=sys.stdout -) - diff --git a/test/grammar/schema/duplicated_key/duplicated_key1/main.k b/test/grammar/schema/duplicated_key/duplicated_key1/main.k new file mode 100644 index 000000000..21297884d --- /dev/null +++ b/test/grammar/schema/duplicated_key/duplicated_key1/main.k @@ -0,0 +1,12 @@ +schema Config: + cpu?: int + +schema A: + k?: Config + +schema C(A): + k?: Config + +a = C { + k: Config {} +} diff --git a/test/grammar/schema/duplicated_key/duplicated_key1/stdout.golden b/test/grammar/schema/duplicated_key/duplicated_key1/stdout.golden new file mode 100644 index 000000000..85c9aa5d6 --- /dev/null +++ b/test/grammar/schema/duplicated_key/duplicated_key1/stdout.golden @@ -0,0 +1,2 @@ +a: + k: {} \ No newline at end of file diff --git a/test/grammar/schema/duplicated_key/duplicated_key2/main.k b/test/grammar/schema/duplicated_key/duplicated_key2/main.k new file mode 100644 index 000000000..7e2160d8f --- /dev/null +++ b/test/grammar/schema/duplicated_key/duplicated_key2/main.k @@ -0,0 +1,12 @@ +schema Config: + cpu?: int + +schema A: + k?: Config + +schema C(A): + k: Config + +a = C { + k: Config {cpu: 1} +} \ No newline at end of file diff --git a/test/grammar/schema/duplicated_key/duplicated_key2/stdout.golden b/test/grammar/schema/duplicated_key/duplicated_key2/stdout.golden new file mode 100644 index 000000000..5c51d173b --- /dev/null +++ b/test/grammar/schema/duplicated_key/duplicated_key2/stdout.golden @@ -0,0 +1,3 @@ +a: + k: + cpu: 1 \ No newline at end of file diff --git a/test/grammar/schema/duplicated_key/duplicated_key3/main.k b/test/grammar/schema/duplicated_key/duplicated_key3/main.k new file mode 100644 index 000000000..320461cd3 --- /dev/null +++ b/test/grammar/schema/duplicated_key/duplicated_key3/main.k @@ -0,0 +1,12 @@ +schema Container: + cpu?: int + +schema App: + container: Container + +container = Container {cpu: 1} + +app = App { + container: container + container: container +} \ No newline at end of file diff --git a/test/grammar/schema/duplicated_key/duplicated_key3/stdout.golden b/test/grammar/schema/duplicated_key/duplicated_key3/stdout.golden new file mode 100644 index 000000000..3a43c7137 --- /dev/null +++ b/test/grammar/schema/duplicated_key/duplicated_key3/stdout.golden @@ -0,0 +1,5 @@ +container: + cpu: 1 +app: + container: + cpu: 1 \ No newline at end of file diff --git a/test/grammar/schema/factory/test_0/main.k b/test/grammar/schema/factory/test_0/main.k new file mode 100644 index 000000000..a7469c78b --- /dev/null +++ b/test/grammar/schema/factory/test_0/main.k @@ -0,0 +1,19 @@ +schema DataA: + id?: int = 1 + value?: str = "value" + +schema DataB: + name?: str = "DataB" + +_dataFactory: {str:} = { + A = DataA + B = DataB +} +TypeA = _dataFactory["A"] +TypeB = _dataFactory["B"] +data0 = TypeA() +data1 = TypeB() +data2 = TypeA() {} +data3 = TypeB {} +data4 = TypeA {} +data5 = TypeB {} diff --git a/test/grammar/schema/factory/test_0/stdout.golden b/test/grammar/schema/factory/test_0/stdout.golden new file mode 100644 index 000000000..8d3b11720 --- /dev/null +++ b/test/grammar/schema/factory/test_0/stdout.golden @@ -0,0 +1,15 @@ +data0: + id: 1 + value: value +data1: + name: DataB +data2: + id: 1 + value: value +data3: + name: DataB +data4: + id: 1 + value: value +data5: + name: DataB diff --git a/test/grammar/schema/factory/test_1/main.k b/test/grammar/schema/factory/test_1/main.k new file mode 100644 index 000000000..420d34b19 --- /dev/null +++ b/test/grammar/schema/factory/test_1/main.k @@ -0,0 +1,19 @@ +schema Foo: + foo: str = "foo" + +schema Bar: + bar: str = "bar" + +factory = lambda type: any, attrs: {:} = {} -> Foo | Bar { + assert typeof(type) == "type" + func = $type + instance = func() {**attrs} +} + +_foo = factory(Foo) +_bar = factory(Bar) +if typeof(_foo) == "Foo": + foo = _foo as Foo + +if typeof(_bar) == "Bar": + bar = _bar as Bar diff --git a/test/grammar/schema/factory/test_1/stdout.golden b/test/grammar/schema/factory/test_1/stdout.golden new file mode 100644 index 000000000..be88aeb52 --- /dev/null +++ b/test/grammar/schema/factory/test_1/stdout.golden @@ -0,0 +1,4 @@ +foo: + foo: foo +bar: + bar: bar diff --git a/test/grammar/schema/factory/test_2/main.k b/test/grammar/schema/factory/test_2/main.k new file mode 100644 index 000000000..6dd6274b7 --- /dev/null +++ b/test/grammar/schema/factory/test_2/main.k @@ -0,0 +1,19 @@ +schema Foo: + foo: str + +schema Bar: + bar: str + +factory = lambda type: any, attrs: {:} = {} -> Foo | Bar { + assert typeof(type) == "type" + func = $type + instance = func() {**attrs} +} + +_foo = factory(Foo, {foo = "foo"}) # Note we set attributes here. +_bar = factory(Bar, {bar = "bar"}) # Note we set attributes here. +if typeof(_foo) == "Foo": + foo = _foo as Foo + +if typeof(_bar) == "Bar": + bar = _bar as Bar diff --git a/test/grammar/schema/factory/test_2/stdout.golden b/test/grammar/schema/factory/test_2/stdout.golden new file mode 100644 index 000000000..be88aeb52 --- /dev/null +++ b/test/grammar/schema/factory/test_2/stdout.golden @@ -0,0 +1,4 @@ +foo: + foo: foo +bar: + bar: bar diff --git a/test/grammar/schema/if_item/if_item_fail_0/stderr.golden b/test/grammar/schema/if_item/if_item_fail_0/stderr.golden new file mode 100644 index 000000000..df0cba355 --- /dev/null +++ b/test/grammar/schema/if_item/if_item_fail_0/stderr.golden @@ -0,0 +1,6 @@ +error[E2L23]: CompileError + --> ${CWD}/main.k:13:35 + | +13 | if data2["key3"] == "value3": "key4": "value4" + | ^ Cannot add member 'key4' to schema 'Data', did you mean '["key1", "key2", "key3"]'? + | \ No newline at end of file diff --git a/test/grammar/schema/if_item/if_item_fail_0/stderr.golden.py b/test/grammar/schema/if_item/if_item_fail_0/stderr.golden.py deleted file mode 100644 index 38ab3417d..000000000 --- a/test/grammar/schema/if_item/if_item_fail_0/stderr.golden.py +++ /dev/null @@ -1,21 +0,0 @@ -import sys -import os - -import kclvm.kcl.error as kcl_error - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception(err_type=kcl_error.ErrType.CannotAddMembers_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=13, - col_no=35, - arg_msg="'key4' is not defined in schema 'Data'" - ), - ], - arg_msg="Cannot add member 'key4' to schema 'Data'") - , file=sys.stdout -) - diff --git a/test/grammar/schema/index_signature/fail_0/stderr.golden b/test/grammar/schema/index_signature/fail_0/stderr.golden new file mode 100644 index 000000000..519b2b135 --- /dev/null +++ b/test/grammar/schema/index_signature/fail_0/stderr.golden @@ -0,0 +1,6 @@ +error[E1001]: IndexSignatureError + --> ${CWD}/main.k:3:5 + | +3 | label: int + | ^ the type 'int' of schema attribute 'label' does not meet the index signature definition [str]: str + | \ No newline at end of file diff --git a/test/grammar/schema/index_signature/fail_0/stderr.golden.py b/test/grammar/schema/index_signature/fail_0/stderr.golden.py deleted file mode 100644 index cb9d9e2bb..000000000 --- a/test/grammar/schema/index_signature/fail_0/stderr.golden.py +++ /dev/null @@ -1,22 +0,0 @@ - -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.IndexSignatureError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=3, - col_no=5 - ) - ], - arg_msg="the type 'int' of schema attribute 'label' does not meet the index signature definition [str]: str" - ), - file=sys.stdout -) - diff --git a/test/grammar/schema/index_signature/fail_1/stderr.golden b/test/grammar/schema/index_signature/fail_1/stderr.golden new file mode 100644 index 000000000..5616cf817 --- /dev/null +++ b/test/grammar/schema/index_signature/fail_1/stderr.golden @@ -0,0 +1,12 @@ +error[E1001]: InvalidSyntax + --> ${CWD}/main.k:3:5 + | +3 | [str]: int + | ^ duplicate schema index signature definitions, only one is allowed in the schema + | +error[E2G22]: TypeError + --> ${CWD}/main.k:6:5 + | +6 | name: "test" + | ^ expected int, got str(test) + | diff --git a/test/grammar/schema/index_signature/fail_1/stderr.golden.py b/test/grammar/schema/index_signature/fail_1/stderr.golden.py deleted file mode 100644 index 30a2a11f9..000000000 --- a/test/grammar/schema/index_signature/fail_1/stderr.golden.py +++ /dev/null @@ -1,22 +0,0 @@ - -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.IndexSignatureError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=3, - col_no=5, - end_col_no=15 - ) - ], - arg_msg="only one index signature is allowed in the schema" - ), - file=sys.stdout -) diff --git a/test/grammar/schema/index_signature/fail_10/main.k b/test/grammar/schema/index_signature/fail_10/main.k new file mode 100644 index 000000000..9913722f7 --- /dev/null +++ b/test/grammar/schema/index_signature/fail_10/main.k @@ -0,0 +1,10 @@ +schema WithComponent: + name: str + $type: str + +schema WithComponents: + [name: str]: WithComponent = WithComponent {name: name} + +components: WithComponents { + ws: {} +} diff --git a/test/grammar/schema/index_signature/fail_10/stderr.golden b/test/grammar/schema/index_signature/fail_10/stderr.golden new file mode 100644 index 000000000..ed6e3939a --- /dev/null +++ b/test/grammar/schema/index_signature/fail_10/stderr.golden @@ -0,0 +1,6 @@ +error[E3M38]: EvaluationError + --> ${CWD}/main.k:6:1 + | +6 | [name: str]: WithComponent = WithComponent {name: name} + | attribute 'type' of WithComponent is required and can't be None or Undefined + | \ No newline at end of file diff --git a/test/grammar/schema/index_signature/fail_11/main.k b/test/grammar/schema/index_signature/fail_11/main.k new file mode 100644 index 000000000..d3dd5088b --- /dev/null +++ b/test/grammar/schema/index_signature/fail_11/main.k @@ -0,0 +1,10 @@ +schema WithComponent: + name: str + $type: str + +schema WithComponents: + [name: str]: WithComponent = WithComponent {name: name} + +components: WithComponents { + ws = {} +} diff --git a/test/grammar/schema/index_signature/fail_11/stderr.golden b/test/grammar/schema/index_signature/fail_11/stderr.golden new file mode 100644 index 000000000..e84cabf05 --- /dev/null +++ b/test/grammar/schema/index_signature/fail_11/stderr.golden @@ -0,0 +1 @@ +attribute 'name' of WithComponent is required and can't be None or Undefined \ No newline at end of file diff --git a/test/grammar/schema/index_signature/fail_12/main.k b/test/grammar/schema/index_signature/fail_12/main.k new file mode 100644 index 000000000..a2d4617c0 --- /dev/null +++ b/test/grammar/schema/index_signature/fail_12/main.k @@ -0,0 +1,10 @@ +type _foo = "foo" | "bar" + +schema IndexSignature: + [_foo]: str + +IndexSignature { + foo = "foo" + # this should throw an error + baz: "baz" +} diff --git a/test/grammar/schema/index_signature/fail_12/stderr.golden b/test/grammar/schema/index_signature/fail_12/stderr.golden new file mode 100644 index 000000000..6350c32ec --- /dev/null +++ b/test/grammar/schema/index_signature/fail_12/stderr.golden @@ -0,0 +1 @@ +Cannot add member 'baz' to schema 'IndexSignature', did you mean '["bar"]'? \ No newline at end of file diff --git a/test/grammar/schema/index_signature/fail_2/stderr.golden b/test/grammar/schema/index_signature/fail_2/stderr.golden new file mode 100644 index 000000000..adcbd6cb6 --- /dev/null +++ b/test/grammar/schema/index_signature/fail_2/stderr.golden @@ -0,0 +1,6 @@ +error[E1001]: IndexSignatureError + --> ${CWD}/main.k:3:5 + | +3 | [name: str]: str + | ^ index signature attribute name 'name' cannot have the same name as schema attributes + | \ No newline at end of file diff --git a/test/grammar/schema/index_signature/fail_2/stderr.golden.py b/test/grammar/schema/index_signature/fail_2/stderr.golden.py deleted file mode 100644 index f7ae1afd3..000000000 --- a/test/grammar/schema/index_signature/fail_2/stderr.golden.py +++ /dev/null @@ -1,21 +0,0 @@ - -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.IndexSignatureError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=3, - col_no=5 - ) - ], - arg_msg="index signature attribute name 'name' cannot have the same name as schema attributes" - ), - file=sys.stdout -) diff --git a/test/grammar/schema/index_signature/fail_3/stderr.golden b/test/grammar/schema/index_signature/fail_3/stderr.golden new file mode 100644 index 000000000..62193a25c --- /dev/null +++ b/test/grammar/schema/index_signature/fail_3/stderr.golden @@ -0,0 +1,6 @@ +error[E2G22]: TypeError + --> ${CWD}/main.k:5:5 + | +5 | name: "test" + | ^ expected int, got str(test) + | diff --git a/test/grammar/schema/index_signature/fail_3/stderr.golden.py b/test/grammar/schema/index_signature/fail_3/stderr.golden.py deleted file mode 100644 index 1bcb1104f..000000000 --- a/test/grammar/schema/index_signature/fail_3/stderr.golden.py +++ /dev/null @@ -1,30 +0,0 @@ - -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.TypeError_Compile_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=2, - col_no=5, - arg_msg="expect int", - err_level=kcl_error.ErrLevel.ORDINARY - ), - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=5, - col_no=5, - arg_msg="got str(test)" - ) - ], - arg_msg="expect int, got str(test)" - ), - file=sys.stdout -) - diff --git a/test/grammar/schema/index_signature/fail_4/stderr.golden b/test/grammar/schema/index_signature/fail_4/stderr.golden new file mode 100644 index 000000000..333c2ad4f --- /dev/null +++ b/test/grammar/schema/index_signature/fail_4/stderr.golden @@ -0,0 +1,6 @@ +error[E1001]: IndexSignatureError + --> ${CWD}/main.k:2:5 + | +2 | count: int + | ^ the type 'int' of schema attribute 'count' does not meet the index signature definition [str]: str + | \ No newline at end of file diff --git a/test/grammar/schema/index_signature/fail_4/stderr.golden.py b/test/grammar/schema/index_signature/fail_4/stderr.golden.py deleted file mode 100644 index 62be229e4..000000000 --- a/test/grammar/schema/index_signature/fail_4/stderr.golden.py +++ /dev/null @@ -1,22 +0,0 @@ - -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.IndexSignatureError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=2, - col_no=5 - ) - ], - arg_msg="the type 'int' of schema attribute 'count' does not meet the index signature definition [str]: str" - ), - file=sys.stdout -) - diff --git a/test/grammar/schema/index_signature/fail_5/stderr.golden b/test/grammar/schema/index_signature/fail_5/stderr.golden new file mode 100644 index 000000000..30326640c --- /dev/null +++ b/test/grammar/schema/index_signature/fail_5/stderr.golden @@ -0,0 +1,11 @@ +error[E3M38]: EvaluationError + --> ${CWD}/main.k:6:8 + | +6 | data = Data { + | ^ Instance check failed + | + --> ${CWD}/main.k:4:1 + | +4 | name in ["Alice", "Bob", "John"] + | Check failed on the condition + | \ No newline at end of file diff --git a/test/grammar/schema/index_signature/fail_5/stderr.golden.py b/test/grammar/schema/index_signature/fail_5/stderr.golden.py deleted file mode 100644 index 2785c515d..000000000 --- a/test/grammar/schema/index_signature/fail_5/stderr.golden.py +++ /dev/null @@ -1,25 +0,0 @@ - -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception(err_type=kcl_error.ErrType.SchemaCheckFailure_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=4, - arg_msg=kcl_error.SCHEMA_CHECK_FILE_MSG_COND - ), - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=6, - col_no=8, - arg_msg=kcl_error.SCHEMA_CHECK_FILE_MSG_ERR - ), - ]) - , file=sys.stdout -) - diff --git a/test/grammar/schema/index_signature/fail_6/stderr.golden b/test/grammar/schema/index_signature/fail_6/stderr.golden new file mode 100644 index 000000000..97422f7db --- /dev/null +++ b/test/grammar/schema/index_signature/fail_6/stderr.golden @@ -0,0 +1,11 @@ +error[E3M38]: EvaluationError + --> ${CWD}/main.k:8:8 + | +8 | data = Data { + | ^ Instance check failed + | + --> ${CWD}/main.k:6:1 + | +6 | regex.match(attr, r'^[-._a-zA-Z0-9]+$') + | Check failed on the condition + | \ No newline at end of file diff --git a/test/grammar/schema/index_signature/fail_6/stderr.golden.py b/test/grammar/schema/index_signature/fail_6/stderr.golden.py deleted file mode 100644 index fa5180808..000000000 --- a/test/grammar/schema/index_signature/fail_6/stderr.golden.py +++ /dev/null @@ -1,24 +0,0 @@ - -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception(err_type=kcl_error.ErrType.SchemaCheckFailure_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=6, - arg_msg=kcl_error.SCHEMA_CHECK_FILE_MSG_COND - ), - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=8, - col_no=8, - arg_msg=kcl_error.SCHEMA_CHECK_FILE_MSG_ERR - ), - ]) - , file=sys.stdout -) diff --git a/test/grammar/schema/index_signature/fail_7/main.k b/test/grammar/schema/index_signature/fail_7/main.k new file mode 100644 index 000000000..0080b8347 --- /dev/null +++ b/test/grammar/schema/index_signature/fail_7/main.k @@ -0,0 +1,10 @@ +schema WithComponent: + name: str + $type: str + +schema WithComponents: + [name: str]: WithComponent = {name: name} + +components: WithComponents { + ws: {} +} diff --git a/test/grammar/schema/index_signature/fail_7/stderr.golden b/test/grammar/schema/index_signature/fail_7/stderr.golden new file mode 100644 index 000000000..f88cfff5e --- /dev/null +++ b/test/grammar/schema/index_signature/fail_7/stderr.golden @@ -0,0 +1 @@ +attribute 'type' of WithComponent is required and can't be None or Undefined \ No newline at end of file diff --git a/test/grammar/schema/index_signature/fail_8/main.k b/test/grammar/schema/index_signature/fail_8/main.k new file mode 100644 index 000000000..2d87773f9 --- /dev/null +++ b/test/grammar/schema/index_signature/fail_8/main.k @@ -0,0 +1,10 @@ +schema WithComponent: + name: str + $type: str + +schema WithComponents: + [name: str]: WithComponent = {name: name} + +components: WithComponents { + ws: WithComponent {} +} diff --git a/test/grammar/schema/index_signature/fail_8/stderr.golden b/test/grammar/schema/index_signature/fail_8/stderr.golden new file mode 100644 index 000000000..a04b6e23d --- /dev/null +++ b/test/grammar/schema/index_signature/fail_8/stderr.golden @@ -0,0 +1,6 @@ +error[E3M38]: EvaluationError + --> ${CWD}/main.k:9:1 + | +9 | ws: WithComponent {} + | attribute 'type' of WithComponent is required and can't be None or Undefined + | \ No newline at end of file diff --git a/test/grammar/schema/index_signature/fail_9/main.k b/test/grammar/schema/index_signature/fail_9/main.k new file mode 100644 index 000000000..6ccc50367 --- /dev/null +++ b/test/grammar/schema/index_signature/fail_9/main.k @@ -0,0 +1,10 @@ +schema WithComponent: + name: str + $type: str + +schema WithComponents: + [name: str]: WithComponent = WithComponent {name: name} + +components: WithComponents { + ws: WithComponent {} +} diff --git a/test/grammar/schema/index_signature/fail_9/stderr.golden b/test/grammar/schema/index_signature/fail_9/stderr.golden new file mode 100644 index 000000000..ed6e3939a --- /dev/null +++ b/test/grammar/schema/index_signature/fail_9/stderr.golden @@ -0,0 +1,6 @@ +error[E3M38]: EvaluationError + --> ${CWD}/main.k:6:1 + | +6 | [name: str]: WithComponent = WithComponent {name: name} + | attribute 'type' of WithComponent is required and can't be None or Undefined + | \ No newline at end of file diff --git a/test/grammar/schema/index_signature/key_alias_0/main.k b/test/grammar/schema/index_signature/key_alias_0/main.k new file mode 100644 index 000000000..4c3eecacc --- /dev/null +++ b/test/grammar/schema/index_signature/key_alias_0/main.k @@ -0,0 +1,12 @@ +schema TeamSpec[id: str]: + fullName: str + name = id + shortName: str = name + +schema TeamMap: + [n: str]: TeamSpec = TeamSpec(n) + +teamMap = TeamMap { + a.fullName = "alpha" + b.fullName = "bravo" +} diff --git a/test/grammar/schema/index_signature/key_alias_0/stdout.golden b/test/grammar/schema/index_signature/key_alias_0/stdout.golden new file mode 100644 index 000000000..054c598c6 --- /dev/null +++ b/test/grammar/schema/index_signature/key_alias_0/stdout.golden @@ -0,0 +1,9 @@ +teamMap: + b: + fullName: bravo + name: b + shortName: b + a: + fullName: alpha + name: a + shortName: a diff --git a/test/grammar/schema/index_signature/key_alias_1/main.k b/test/grammar/schema/index_signature/key_alias_1/main.k new file mode 100644 index 000000000..af69f88c2 --- /dev/null +++ b/test/grammar/schema/index_signature/key_alias_1/main.k @@ -0,0 +1,14 @@ +schema TeamSpec: + fullName: str + name: str + shortName: str = name + +schema TeamMap: + [n: str]: TeamSpec = TeamSpec { + name = n + } + +teamMap = TeamMap { + a.fullName = "alpha" + b.fullName = "bravo" +} diff --git a/test/grammar/schema/index_signature/key_alias_1/stdout.golden b/test/grammar/schema/index_signature/key_alias_1/stdout.golden new file mode 100644 index 000000000..054c598c6 --- /dev/null +++ b/test/grammar/schema/index_signature/key_alias_1/stdout.golden @@ -0,0 +1,9 @@ +teamMap: + b: + fullName: bravo + name: b + shortName: b + a: + fullName: alpha + name: a + shortName: a diff --git a/test/grammar/schema/index_signature/normal_10/main.k b/test/grammar/schema/index_signature/normal_10/main.k new file mode 100644 index 000000000..8e2ed2500 --- /dev/null +++ b/test/grammar/schema/index_signature/normal_10/main.k @@ -0,0 +1,10 @@ +schema WithComponent: + name?: str + $type?: str + +schema WithComponents: + [name: str]: WithComponent = WithComponent {name: name} + +components: WithComponents { + ws = {} +} diff --git a/test/grammar/schema/index_signature/normal_10/stdout.golden b/test/grammar/schema/index_signature/normal_10/stdout.golden new file mode 100644 index 000000000..16cff31f0 --- /dev/null +++ b/test/grammar/schema/index_signature/normal_10/stdout.golden @@ -0,0 +1,2 @@ +components: + ws: {} diff --git a/test/grammar/schema/index_signature/normal_11/main.k b/test/grammar/schema/index_signature/normal_11/main.k new file mode 100644 index 000000000..1966d0b5e --- /dev/null +++ b/test/grammar/schema/index_signature/normal_11/main.k @@ -0,0 +1,25 @@ +schema User: + id: str + +schema Users: + [str]: User + +schema DB: + users: Users = {} + + check: + all user in users { + user == users[user].id + } + +schema DBs: + [str]: DB + +dbs_user: DBs = { + user = DB { + users: { + app = User {id = "app"} + } + } +} +db_user = dbs_user.user diff --git a/test/grammar/schema/index_signature/normal_11/stdout.golden b/test/grammar/schema/index_signature/normal_11/stdout.golden new file mode 100644 index 000000000..19548ed0d --- /dev/null +++ b/test/grammar/schema/index_signature/normal_11/stdout.golden @@ -0,0 +1,9 @@ +dbs_user: + user: + users: + app: + id: app +db_user: + users: + app: + id: app diff --git a/test/grammar/schema/index_signature/normal_4/main.k b/test/grammar/schema/index_signature/normal_4/main.k index 7c08180a1..1c7ff0c1f 100644 --- a/test/grammar/schema/index_signature/normal_4/main.k +++ b/test/grammar/schema/index_signature/normal_4/main.k @@ -4,7 +4,7 @@ schema S: _s: S { a += [1] } -_s |= { +_s: S { b += [1] } s = _s diff --git a/test/grammar/schema/index_signature/normal_5/main.k b/test/grammar/schema/index_signature/normal_5/main.k new file mode 100644 index 000000000..544b6ac25 --- /dev/null +++ b/test/grammar/schema/index_signature/normal_5/main.k @@ -0,0 +1,15 @@ +schema LabelMap: + [str]: str | int + +schema NamedMap: + [str]: {str:str} = {"default_key": "default_value"} + +labelMap = LabelMap { + key1 = "value1" + key2 = 2 +} + +namedMap = NamedMap { + key1 = {key1 = "value1"} + key2 = {key2 = "value2"} +} diff --git a/test/grammar/schema/index_signature/normal_5/stdout.golden b/test/grammar/schema/index_signature/normal_5/stdout.golden new file mode 100644 index 000000000..28478bb4a --- /dev/null +++ b/test/grammar/schema/index_signature/normal_5/stdout.golden @@ -0,0 +1,8 @@ +labelMap: + key1: value1 + key2: 2 +namedMap: + key1: + key1: value1 + key2: + key2: value2 diff --git a/test/grammar/schema/index_signature/normal_6/main.k b/test/grammar/schema/index_signature/normal_6/main.k new file mode 100644 index 000000000..7e128c187 --- /dev/null +++ b/test/grammar/schema/index_signature/normal_6/main.k @@ -0,0 +1,10 @@ +schema WithComponent: + name: str + $type?: str + +schema WithComponents: + [name: str]: WithComponent = {name: name} + +components: WithComponents { + ws: {} +} diff --git a/test/grammar/schema/index_signature/normal_6/stdout.golden b/test/grammar/schema/index_signature/normal_6/stdout.golden new file mode 100644 index 000000000..7ef2dbb12 --- /dev/null +++ b/test/grammar/schema/index_signature/normal_6/stdout.golden @@ -0,0 +1,3 @@ +components: + ws: + name: ws diff --git a/test/grammar/schema/index_signature/normal_7/main.k b/test/grammar/schema/index_signature/normal_7/main.k new file mode 100644 index 000000000..c40963bcb --- /dev/null +++ b/test/grammar/schema/index_signature/normal_7/main.k @@ -0,0 +1,10 @@ +schema WithComponent: + name: str + $type?: str + +schema WithComponents: + [name: str]: WithComponent = {name: name} + +components: WithComponents { + ws: WithComponent {} +} diff --git a/test/grammar/schema/index_signature/normal_7/stdout.golden b/test/grammar/schema/index_signature/normal_7/stdout.golden new file mode 100644 index 000000000..7ef2dbb12 --- /dev/null +++ b/test/grammar/schema/index_signature/normal_7/stdout.golden @@ -0,0 +1,3 @@ +components: + ws: + name: ws diff --git a/test/grammar/schema/index_signature/normal_8/main.k b/test/grammar/schema/index_signature/normal_8/main.k new file mode 100644 index 000000000..5d6577cab --- /dev/null +++ b/test/grammar/schema/index_signature/normal_8/main.k @@ -0,0 +1,10 @@ +schema WithComponent: + name: str + $type?: str + +schema WithComponents: + [name: str]: WithComponent = WithComponent {name: name} + +components: WithComponents { + ws: WithComponent {} +} diff --git a/test/grammar/schema/index_signature/normal_8/stdout.golden b/test/grammar/schema/index_signature/normal_8/stdout.golden new file mode 100644 index 000000000..7ef2dbb12 --- /dev/null +++ b/test/grammar/schema/index_signature/normal_8/stdout.golden @@ -0,0 +1,3 @@ +components: + ws: + name: ws diff --git a/test/grammar/schema/index_signature/normal_9/main.k b/test/grammar/schema/index_signature/normal_9/main.k new file mode 100644 index 000000000..81c9494f3 --- /dev/null +++ b/test/grammar/schema/index_signature/normal_9/main.k @@ -0,0 +1,10 @@ +schema WithComponent: + name: str + $type?: str + +schema WithComponents: + [name: str]: WithComponent = WithComponent {name: name} + +components: WithComponents { + ws: {} +} diff --git a/test/grammar/schema/index_signature/normal_9/stdout.golden b/test/grammar/schema/index_signature/normal_9/stdout.golden new file mode 100644 index 000000000..7ef2dbb12 --- /dev/null +++ b/test/grammar/schema/index_signature/normal_9/stdout.golden @@ -0,0 +1,3 @@ +components: + ws: + name: ws diff --git a/test/grammar/schema/inherit/cycle_inherit_fail_0/stderr.golden b/test/grammar/schema/inherit/cycle_inherit_fail_0/stderr.golden new file mode 100644 index 000000000..274c37510 --- /dev/null +++ b/test/grammar/schema/inherit/cycle_inherit_fail_0/stderr.golden @@ -0,0 +1,13 @@ +error[E2L23]: CompileError + --> ${CWD}/main.k:1:8 + | +1 | schema Parent(Son): + | ^ There is a circular reference between schemas Parent, Son + | + +error[E2L23]: CompileError + --> ${CWD}/main.k:4:8 + | +4 | schema Son(Parent): + | ^ There is a circular reference between schemas Parent, Son + | \ No newline at end of file diff --git a/test/grammar/schema/inherit/cycle_inherit_fail_0/stderr.golden.py b/test/grammar/schema/inherit/cycle_inherit_fail_0/stderr.golden.py deleted file mode 100644 index a8fce6ca4..000000000 --- a/test/grammar/schema/inherit/cycle_inherit_fail_0/stderr.golden.py +++ /dev/null @@ -1,20 +0,0 @@ - -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception(err_type=kcl_error.ErrType.CycleInheritError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=4, - col_no=1 - ), - ], - arg_msg="Son and Parent") - , file=sys.stdout -) - diff --git a/test/grammar/schema/inherit/cycle_inherit_fail_1/stderr.golden b/test/grammar/schema/inherit/cycle_inherit_fail_1/stderr.golden new file mode 100644 index 000000000..0823bf493 --- /dev/null +++ b/test/grammar/schema/inherit/cycle_inherit_fail_1/stderr.golden @@ -0,0 +1,20 @@ +error[E2L23]: CompileError + --> ${CWD}/main.k:1:8 + | +1 | schema Parent(Son): + | ^ There is a circular reference between schemas Parent, Son, GrandSon + | + +error[E2L23]: CompileError + --> ${CWD}/main.k:4:8 + | +4 | schema Son(GrandSon): + | ^ There is a circular reference between schemas Parent, Son, GrandSon + | + +error[E2L23]: CompileError + --> ${CWD}/main.k:7:8 + | +7 | schema GrandSon(Parent): + | ^ There is a circular reference between schemas Parent, Son, GrandSon + | \ No newline at end of file diff --git a/test/grammar/schema/inherit/cycle_inherit_fail_1/stderr.golden.py b/test/grammar/schema/inherit/cycle_inherit_fail_1/stderr.golden.py deleted file mode 100644 index 7987bfaf7..000000000 --- a/test/grammar/schema/inherit/cycle_inherit_fail_1/stderr.golden.py +++ /dev/null @@ -1,20 +0,0 @@ - -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception(err_type=kcl_error.ErrType.CycleInheritError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=7, - col_no=1 - ), - ], - arg_msg="GrandSon and Parent") - , file=sys.stdout -) - diff --git a/test/grammar/schema/inherit/cycle_inherit_fail_2/stderr.golden b/test/grammar/schema/inherit/cycle_inherit_fail_2/stderr.golden new file mode 100644 index 000000000..597758a22 --- /dev/null +++ b/test/grammar/schema/inherit/cycle_inherit_fail_2/stderr.golden @@ -0,0 +1,20 @@ +error[E2L23]: CompileError + --> ${CWD}/pkg/b.k:2:8 + | +2 | schema B(C): + | ^ There is a circular reference between schemas pkg.B, pkg.C + | + +error[E2L23]: CompileError + --> ${CWD}/pkg/c.k:2:8 + | +2 | schema C(B): + | ^ There is a circular reference between schemas pkg.B, pkg.C + | + +error[E2L23]: CompileError + --> ${CWD}/main.k:9:5 + | +9 | fields: "asa", + | ^ Cannot add member 'fields' to schema 'Son', did you mean '["field"]'? + | \ No newline at end of file diff --git a/test/grammar/schema/inherit/cycle_inherit_fail_2/stderr.golden.py b/test/grammar/schema/inherit/cycle_inherit_fail_2/stderr.golden.py deleted file mode 100644 index eab09126b..000000000 --- a/test/grammar/schema/inherit/cycle_inherit_fail_2/stderr.golden.py +++ /dev/null @@ -1,20 +0,0 @@ - -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception(err_type=kcl_error.ErrType.CycleInheritError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/pkg/c.k", - line_no=2, - col_no=1 - ), - ], - arg_msg="C and B") - , file=sys.stdout -) - diff --git a/test/grammar/schema/inherit/cycle_inherit_fail_3/stderr.golden b/test/grammar/schema/inherit/cycle_inherit_fail_3/stderr.golden new file mode 100644 index 000000000..1b8603950 --- /dev/null +++ b/test/grammar/schema/inherit/cycle_inherit_fail_3/stderr.golden @@ -0,0 +1,20 @@ +error[E2L23]: CompileError + --> ${CWD}/pkg/b.k:1:8 + | +1 | schema B(C): + | ^ There is a circular reference between schemas pkg.B, pkg.C + | + +error[E2L23]: CompileError + --> ${CWD}/pkg/c.k:1:8 + | +1 | schema C(B): + | ^ There is a circular reference between schemas pkg.B, pkg.C + | + +error[E2L23]: CompileError + --> ${CWD}/main.k:9:5 + | +9 | fields: "asa", + | ^ Cannot add member 'fields' to schema 'Son', did you mean '["field"]'? + | \ No newline at end of file diff --git a/test/grammar/schema/inherit/cycle_inherit_fail_3/stderr.golden.py b/test/grammar/schema/inherit/cycle_inherit_fail_3/stderr.golden.py deleted file mode 100644 index adffa131f..000000000 --- a/test/grammar/schema/inherit/cycle_inherit_fail_3/stderr.golden.py +++ /dev/null @@ -1,20 +0,0 @@ - -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception(err_type=kcl_error.ErrType.CycleInheritError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/pkg/c.k", - line_no=1, - col_no=1 - ), - ], - arg_msg="C and B") - , file=sys.stdout -) - diff --git a/test/grammar/schema/inherit/cycle_inherit_fail_4/stderr.golden b/test/grammar/schema/inherit/cycle_inherit_fail_4/stderr.golden new file mode 100644 index 000000000..1b8603950 --- /dev/null +++ b/test/grammar/schema/inherit/cycle_inherit_fail_4/stderr.golden @@ -0,0 +1,20 @@ +error[E2L23]: CompileError + --> ${CWD}/pkg/b.k:1:8 + | +1 | schema B(C): + | ^ There is a circular reference between schemas pkg.B, pkg.C + | + +error[E2L23]: CompileError + --> ${CWD}/pkg/c.k:1:8 + | +1 | schema C(B): + | ^ There is a circular reference between schemas pkg.B, pkg.C + | + +error[E2L23]: CompileError + --> ${CWD}/main.k:9:5 + | +9 | fields: "asa", + | ^ Cannot add member 'fields' to schema 'Son', did you mean '["field"]'? + | \ No newline at end of file diff --git a/test/grammar/schema/inherit/cycle_inherit_fail_4/stderr.golden.py b/test/grammar/schema/inherit/cycle_inherit_fail_4/stderr.golden.py deleted file mode 100644 index adffa131f..000000000 --- a/test/grammar/schema/inherit/cycle_inherit_fail_4/stderr.golden.py +++ /dev/null @@ -1,20 +0,0 @@ - -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception(err_type=kcl_error.ErrType.CycleInheritError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/pkg/c.k", - line_no=1, - col_no=1 - ), - ], - arg_msg="C and B") - , file=sys.stdout -) - diff --git a/test/grammar/schema/inherit/illegal_inheritance_fail_0/stderr.golden b/test/grammar/schema/inherit/illegal_inheritance_fail_0/stderr.golden new file mode 100644 index 000000000..312827458 --- /dev/null +++ b/test/grammar/schema/inherit/illegal_inheritance_fail_0/stderr.golden @@ -0,0 +1,12 @@ +error[E2D34]: IllegalInheritError + --> ${CWD}/main.k:3:12 + | +3 | schema Son(a): + | ^ invalid schema inherit object type, expect schema, got 'int' + | +error[E2L23]: CompileError + --> ${CWD}/main.k:7:5 + | +7 | fields: "asa" + | ^ Cannot add member 'fields' to schema 'Son', did you mean '["field"]'? + | \ No newline at end of file diff --git a/test/grammar/schema/inherit/illegal_inheritance_fail_0/stderr.golden.py b/test/grammar/schema/inherit/illegal_inheritance_fail_0/stderr.golden.py deleted file mode 100644 index bbac2d6a5..000000000 --- a/test/grammar/schema/inherit/illegal_inheritance_fail_0/stderr.golden.py +++ /dev/null @@ -1,22 +0,0 @@ - -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.IllegalInheritError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=3, - col_no=1 - ) - ], - arg_msg="illegal schema inherit object type 'int'" - ), - file=sys.stdout -) - diff --git a/test/grammar/schema/inherit/inherit_change_field_type_0/stderr.golden b/test/grammar/schema/inherit/inherit_change_field_type_0/stderr.golden new file mode 100644 index 000000000..20f87b3ca --- /dev/null +++ b/test/grammar/schema/inherit/inherit_change_field_type_0/stderr.golden @@ -0,0 +1,17 @@ +error[E2G22]: TypeError + --> ${CWD}/main.k:6:5 + | +6 | firstName: int + | ^ can't change schema field type of 'firstName' from int to int + | +error[E2G22]: TypeError + --> ${CWD}/main.k:16:5 + | +16 | "firstName": "John", + | ^ expected int, got str(John) + | + --> ${CWD}/main.k:6:5 + | +6 | firstName: int + | ^ variable is defined here, its type is int, but got str(John) + | \ No newline at end of file diff --git a/test/grammar/schema/inherit/inherit_change_field_type_0/stderr.golden.py b/test/grammar/schema/inherit/inherit_change_field_type_0/stderr.golden.py deleted file mode 100644 index 7e3673ca7..000000000 --- a/test/grammar/schema/inherit/inherit_change_field_type_0/stderr.golden.py +++ /dev/null @@ -1,22 +0,0 @@ - -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.TypeError_Compile_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=6, - col_no=5 - ) - ], - arg_msg="can't change schema field type of 'firstName'" - ), - file=sys.stdout -) - diff --git a/test/grammar/schema/inherit/inherit_change_field_type_2/stderr.golden b/test/grammar/schema/inherit/inherit_change_field_type_2/stderr.golden new file mode 100644 index 000000000..526d31700 --- /dev/null +++ b/test/grammar/schema/inherit/inherit_change_field_type_2/stderr.golden @@ -0,0 +1,6 @@ +error[E2G22]: TypeError + --> ${CWD}/main.k:7:5 + | +7 | name: pkg.Name0 + | ^ can't change schema field type of 'name' from Name0 to Name0 + | \ No newline at end of file diff --git a/test/grammar/schema/inherit/inherit_change_field_type_2/stderr.golden.py b/test/grammar/schema/inherit/inherit_change_field_type_2/stderr.golden.py deleted file mode 100644 index 6db11703e..000000000 --- a/test/grammar/schema/inherit/inherit_change_field_type_2/stderr.golden.py +++ /dev/null @@ -1,22 +0,0 @@ - -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.TypeError_Compile_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=7, - col_no=5 - ) - ], - arg_msg="can't change schema field type of 'name'" - ), - file=sys.stdout -) - diff --git a/test/grammar/schema/inherit/inherit_change_field_type_3/stderr.golden b/test/grammar/schema/inherit/inherit_change_field_type_3/stderr.golden new file mode 100644 index 000000000..f270419fe --- /dev/null +++ b/test/grammar/schema/inherit/inherit_change_field_type_3/stderr.golden @@ -0,0 +1,6 @@ +error[E2G22]: TypeError + --> ${CWD}/main.k:4:5 + | +4 | name: pkg.Name0 + | ^ can't change schema field type of 'name' from Name0 to Name0 + | \ No newline at end of file diff --git a/test/grammar/schema/inherit/inherit_change_field_type_3/stderr.golden.py b/test/grammar/schema/inherit/inherit_change_field_type_3/stderr.golden.py deleted file mode 100644 index 5e50f2e73..000000000 --- a/test/grammar/schema/inherit/inherit_change_field_type_3/stderr.golden.py +++ /dev/null @@ -1,22 +0,0 @@ - -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.TypeError_Compile_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=4, - col_no=5 - ) - ], - arg_msg="can't change schema field type of 'name'" - ), - file=sys.stdout -) - diff --git a/test/grammar/schema/inherit/inherit_mixin_fail/stderr.golden b/test/grammar/schema/inherit/inherit_mixin_fail/stderr.golden new file mode 100644 index 000000000..94b79ef50 --- /dev/null +++ b/test/grammar/schema/inherit/inherit_mixin_fail/stderr.golden @@ -0,0 +1,18 @@ +error[E2D34]: IllegalInheritError + --> ${CWD}/main.k:8:16 + | +8 | schema Scholar(FullnameMixin): + | ^ invalid schema inherit object type, expect schema, got 'FullnameMixin' + | +error[E2L23]: CompileError + --> ${CWD}/main.k:12:5 + | +12 | "firstName": "Jon", + | ^ Cannot add member 'firstName' to schema 'Scholar' + | +error[E2L23]: CompileError + --> ${CWD}/main.k:13:5 + | +13 | "lastName": "Doe" + | ^ Cannot add member 'lastName' to schema 'Scholar' + | \ No newline at end of file diff --git a/test/grammar/schema/inherit/inherit_mixin_fail/stderr.golden.py b/test/grammar/schema/inherit/inherit_mixin_fail/stderr.golden.py deleted file mode 100644 index 165aec4a6..000000000 --- a/test/grammar/schema/inherit/inherit_mixin_fail/stderr.golden.py +++ /dev/null @@ -1,21 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.IllegalInheritError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=8, - col_no=1 - ) - ], - arg_msg="mixin inheritance FullnameMixin is prohibited" - ), - file=sys.stdout -) - diff --git a/test/grammar/schema/inherit/multi_inherit_fail_0/stderr.golden b/test/grammar/schema/inherit/multi_inherit_fail_0/stderr.golden new file mode 100644 index 000000000..e7797695e --- /dev/null +++ b/test/grammar/schema/inherit/multi_inherit_fail_0/stderr.golden @@ -0,0 +1,54 @@ +error[E1001]: InvalidSyntax + --> ${CWD}/main.k:9:22 + | +9 | schema Scholar(Person, Knowledge): + | ^ expected one of [")"] got , + | +error[E1001]: InvalidSyntax + --> ${CWD}/main.k:9:24 + | +9 | schema Scholar(Person, Knowledge): + | ^ expected one of [":"] got identifier + | +error[E1001]: InvalidSyntax + --> ${CWD}/main.k:9:33 + | +9 | schema Scholar(Person, Knowledge): + | ^ unexpected token ')' + | +error[E1001]: InvalidSyntax + --> ${CWD}/main.k:9:34 + | +9 | schema Scholar(Person, Knowledge): + | ^ unexpected token ':' + | +error[E1001]: InvalidSyntax + --> ${CWD}/main.k:10:5 + | +10 | school: str + | ^ unexpected token 'indent' + | +error[E1001]: InvalidSyntax + --> ${CWD}/main.k:12:1 + | +12 | JonSnow = Person { + | expected one of ["="] got dedent + | +error[E1001]: InvalidSyntax + --> ${CWD}/main.k:12:1 + | +12 | JonSnow = Person { + | unexpected token 'dedent' + | +error[E2L23]: CompileError + --> ${CWD}/main.k:20:5 + | +20 | "subject": "CS", + | ^ Cannot add member 'subject' to schema 'Scholar' + | +error[E2L23]: CompileError + --> ${CWD}/main.k:21:5 + | +21 | "school": "PKU" + | ^ Cannot add member 'school' to schema 'Scholar' + | \ No newline at end of file diff --git a/test/grammar/schema/inherit/multi_inherit_fail_0/stderr.golden.py b/test/grammar/schema/inherit/multi_inherit_fail_0/stderr.golden.py deleted file mode 100644 index 5c8f2cc43..000000000 --- a/test/grammar/schema/inherit/multi_inherit_fail_0/stderr.golden.py +++ /dev/null @@ -1,23 +0,0 @@ - -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.MultiInheritError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=9, - col_no=16, - end_col_no=33, - ) - ], - arg_msg=kcl_error.MULTI_INHERIT_MSG.format("Scholar") - ), - file=sys.stdout -) - diff --git a/test/grammar/schema/inherit/multi_inherit_fail_1/stderr.golden b/test/grammar/schema/inherit/multi_inherit_fail_1/stderr.golden new file mode 100644 index 000000000..f0f361c42 --- /dev/null +++ b/test/grammar/schema/inherit/multi_inherit_fail_1/stderr.golden @@ -0,0 +1,72 @@ +error[E1001]: InvalidSyntax + --> ${CWD}/main.k:9:30 + | +9 | schema Scholar(KnowledgeMixin, Person): + | ^ expected one of [")"] got , + | +error[E1001]: InvalidSyntax + --> ${CWD}/main.k:9:32 + | +9 | schema Scholar(KnowledgeMixin, Person): + | ^ expected one of [":"] got identifier + | +error[E1001]: InvalidSyntax + --> ${CWD}/main.k:9:38 + | +9 | schema Scholar(KnowledgeMixin, Person): + | ^ unexpected token ')' + | +error[E1001]: InvalidSyntax + --> ${CWD}/main.k:9:39 + | +9 | schema Scholar(KnowledgeMixin, Person): + | ^ unexpected token ':' + | +error[E1001]: InvalidSyntax + --> ${CWD}/main.k:10:5 + | +10 | school: str + | ^ unexpected token 'indent' + | +error[E1001]: InvalidSyntax + --> ${CWD}/main.k:12:1 + | +12 | JonSnow = Person { + | expected one of ["="] got dedent + | +error[E1001]: InvalidSyntax + --> ${CWD}/main.k:12:1 + | +12 | JonSnow = Person { + | unexpected token 'dedent' + | +error[E2D34]: IllegalInheritError + --> ${CWD}/main.k:9:16 + | +9 | schema Scholar(KnowledgeMixin, Person): + | ^ invalid schema inherit object type, expect schema, got 'KnowledgeMixin' + | +error[E2L23]: CompileError + --> ${CWD}/main.k:18:5 + | +18 | "firstName": "John", + | ^ Cannot add member 'firstName' to schema 'Scholar' + | +error[E2L23]: CompileError + --> ${CWD}/main.k:19:5 + | +19 | "lastName": "Doe", + | ^ Cannot add member 'lastName' to schema 'Scholar' + | +error[E2L23]: CompileError + --> ${CWD}/main.k:20:5 + | +20 | "subject": "CS", + | ^ Cannot add member 'subject' to schema 'Scholar' + | +error[E2L23]: CompileError + --> ${CWD}/main.k:21:5 + | +21 | "school": "PKU" + | ^ Cannot add member 'school' to schema 'Scholar' + | \ No newline at end of file diff --git a/test/grammar/schema/inherit/multi_inherit_fail_1/stderr.golden.py b/test/grammar/schema/inherit/multi_inherit_fail_1/stderr.golden.py deleted file mode 100644 index b00dd4090..000000000 --- a/test/grammar/schema/inherit/multi_inherit_fail_1/stderr.golden.py +++ /dev/null @@ -1,22 +0,0 @@ - -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.MultiInheritError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=9, - col_no=16, - end_col_no=38 - ) - ], - arg_msg=kcl_error.MULTI_INHERIT_MSG.format("Scholar") - ), - file=sys.stdout -) diff --git a/test/grammar/schema/init/init_add_member_fail_0/stderr.golden b/test/grammar/schema/init/init_add_member_fail_0/stderr.golden new file mode 100644 index 000000000..f4375381d --- /dev/null +++ b/test/grammar/schema/init/init_add_member_fail_0/stderr.golden @@ -0,0 +1,6 @@ +error[E2L23]: CompileError + --> ${CWD}/main.k:8:5 + | +8 | fullName = "full name" + | ^ Cannot add member 'fullName' to schema 'Person' + | \ No newline at end of file diff --git a/test/grammar/schema/init/init_add_member_fail_0/stderr.golden.py b/test/grammar/schema/init/init_add_member_fail_0/stderr.golden.py deleted file mode 100644 index a4c8d2879..000000000 --- a/test/grammar/schema/init/init_add_member_fail_0/stderr.golden.py +++ /dev/null @@ -1,20 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception(err_type=kcl_error.ErrType.CannotAddMembers_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=8, - col_no=5, - arg_msg="'fullName' is not defined in schema 'Person'" - ), - ], - arg_msg="Cannot add member 'fullName' to schema 'Person'") - , file=sys.stdout -) - diff --git a/test/grammar/schema/init/init_add_member_fail_1/stderr.golden b/test/grammar/schema/init/init_add_member_fail_1/stderr.golden new file mode 100644 index 000000000..de04fb307 --- /dev/null +++ b/test/grammar/schema/init/init_add_member_fail_1/stderr.golden @@ -0,0 +1,6 @@ +error[E2L23]: CompileError + --> ${CWD}/main.k:8:9 + | +8 | "fullName": "full name" + | ^ Cannot add member 'fullName' to schema 'Name' + | \ No newline at end of file diff --git a/test/grammar/schema/init/init_add_member_fail_1/stderr.golden.py b/test/grammar/schema/init/init_add_member_fail_1/stderr.golden.py deleted file mode 100644 index eaf744eb6..000000000 --- a/test/grammar/schema/init/init_add_member_fail_1/stderr.golden.py +++ /dev/null @@ -1,19 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception(err_type=kcl_error.ErrType.CannotAddMembers_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=8, - col_no=9, - arg_msg="'fullName' is not defined in schema 'Name'" - ), - ], - arg_msg="Cannot add member 'fullName' to schema 'Name'") - , file=sys.stdout -) diff --git a/test/grammar/schema/init/init_add_member_fail_2/stderr.golden b/test/grammar/schema/init/init_add_member_fail_2/stderr.golden new file mode 100644 index 000000000..844ca6341 --- /dev/null +++ b/test/grammar/schema/init/init_add_member_fail_2/stderr.golden @@ -0,0 +1,6 @@ +error[E2L23]: CompileError + --> ${CWD}/main.k:15:5 + | +15 | error = "CannotAddMembers" + | ^ Cannot add member 'error' to schema 'Person' + | \ No newline at end of file diff --git a/test/grammar/schema/init/init_add_member_fail_2/stderr.golden.py b/test/grammar/schema/init/init_add_member_fail_2/stderr.golden.py deleted file mode 100644 index 689aab545..000000000 --- a/test/grammar/schema/init/init_add_member_fail_2/stderr.golden.py +++ /dev/null @@ -1,20 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception(err_type=kcl_error.ErrType.CannotAddMembers_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=15, - col_no=5, - arg_msg="'error' is not defined in schema 'Person'" - ), - ], - arg_msg="Cannot add member 'error' to schema 'Person'") - , file=sys.stdout -) - diff --git a/test/grammar/schema/init/init_cycle_fail_0/stderr.golden b/test/grammar/schema/init/init_cycle_fail_0/stderr.golden new file mode 100644 index 000000000..efc799290 --- /dev/null +++ b/test/grammar/schema/init/init_cycle_fail_0/stderr.golden @@ -0,0 +1 @@ +maximum recursion depth exceeded in __instancecheck__ diff --git a/test/grammar/schema/init/init_cycle_fail_0/stderr.golden.py b/test/grammar/schema/init/init_cycle_fail_0/stderr.golden.py deleted file mode 100644 index 5e3d4ee7e..000000000 --- a/test/grammar/schema/init/init_cycle_fail_0/stderr.golden.py +++ /dev/null @@ -1,18 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception(err_type=kcl_error.ErrType.RecursionError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=10, - ), - ], - arg_msg="maximum recursion depth exceeded in __instancecheck__") - , file=sys.stdout -) - diff --git a/test/grammar/schema/init/init_cycle_fail_1/stderr.golden b/test/grammar/schema/init/init_cycle_fail_1/stderr.golden new file mode 100644 index 000000000..efc799290 --- /dev/null +++ b/test/grammar/schema/init/init_cycle_fail_1/stderr.golden @@ -0,0 +1 @@ +maximum recursion depth exceeded in __instancecheck__ diff --git a/test/grammar/schema/init/init_cycle_fail_1/stderr.golden.py b/test/grammar/schema/init/init_cycle_fail_1/stderr.golden.py deleted file mode 100644 index 5e3d4ee7e..000000000 --- a/test/grammar/schema/init/init_cycle_fail_1/stderr.golden.py +++ /dev/null @@ -1,18 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception(err_type=kcl_error.ErrType.RecursionError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=10, - ), - ], - arg_msg="maximum recursion depth exceeded in __instancecheck__") - , file=sys.stdout -) - diff --git a/test/grammar/schema/init/init_cycle_fail_2/stderr.golden b/test/grammar/schema/init/init_cycle_fail_2/stderr.golden new file mode 100644 index 000000000..f8a3ae951 --- /dev/null +++ b/test/grammar/schema/init/init_cycle_fail_2/stderr.golden @@ -0,0 +1 @@ +maximum recursion depth exceeded in comparison diff --git a/test/grammar/schema/init/init_cycle_fail_2/stderr.golden.py b/test/grammar/schema/init/init_cycle_fail_2/stderr.golden.py deleted file mode 100644 index 38dbb6236..000000000 --- a/test/grammar/schema/init/init_cycle_fail_2/stderr.golden.py +++ /dev/null @@ -1,18 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception(err_type=kcl_error.ErrType.RecursionError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=2, - ), - ], - arg_msg="maximum recursion depth exceeded in comparison") - , file=sys.stdout -) - diff --git a/test/grammar/schema/init/init_dict_fail_0/stderr.golden b/test/grammar/schema/init/init_dict_fail_0/stderr.golden new file mode 100644 index 000000000..a8aa62b0f --- /dev/null +++ b/test/grammar/schema/init/init_dict_fail_0/stderr.golden @@ -0,0 +1,6 @@ +error[E2L23]: CompileError + --> ${CWD}/main.k:7:9 + | +7 | "gender": "female" + | ^ Cannot add member 'gender' to schema 'Name' + | \ No newline at end of file diff --git a/test/grammar/schema/init/init_dict_fail_0/stderr.golden.py b/test/grammar/schema/init/init_dict_fail_0/stderr.golden.py deleted file mode 100644 index 1fd1d45ff..000000000 --- a/test/grammar/schema/init/init_dict_fail_0/stderr.golden.py +++ /dev/null @@ -1,19 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception(err_type=kcl_error.ErrType.CannotAddMembers_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=7, - col_no=9, - arg_msg="'gender' is not defined in schema 'Name'" - ), - ], - arg_msg="Cannot add member 'gender' to schema 'Name'") - , file=sys.stdout -) diff --git a/test/grammar/schema/init/init_err_key_fail_0/stderr.golden b/test/grammar/schema/init/init_err_key_fail_0/stderr.golden new file mode 100644 index 000000000..5e14b3201 --- /dev/null +++ b/test/grammar/schema/init/init_err_key_fail_0/stderr.golden @@ -0,0 +1,6 @@ +error[E2G22]: TypeError + --> ${CWD}/main.k:13:21 + | +13 | "name": data.name_err_key, + | ^ attribute 'name_err_key' not found in 'Frontend' + | \ No newline at end of file diff --git a/test/grammar/schema/init/init_err_key_fail_0/stderr.golden.py b/test/grammar/schema/init/init_err_key_fail_0/stderr.golden.py deleted file mode 100644 index 47089180b..000000000 --- a/test/grammar/schema/init/init_err_key_fail_0/stderr.golden.py +++ /dev/null @@ -1,21 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.AttributeError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=13, - col_no=21 - ) - ], - arg_msg="schema 'Frontend' attribute 'name_err_key' not found" - ), - file=sys.stdout -) - diff --git a/test/grammar/schema/init/init_if_expr_1/main.k b/test/grammar/schema/init/init_if_expr_1/main.k index 3be793fbd..6c8e0b314 100644 --- a/test/grammar/schema/init/init_if_expr_1/main.k +++ b/test/grammar/schema/init/init_if_expr_1/main.k @@ -5,7 +5,7 @@ schema Person: info?: {str: int|str} schema InfoMixin: - info |= {"age": age} if age else {} + info = {"age": age} if age else {} alice = Person { "name": "alice", diff --git a/test/grammar/schema/init/init_if_expr_1/stdout.golden b/test/grammar/schema/init/init_if_expr_1/stdout.golden index a851f27fd..696b9be89 100644 --- a/test/grammar/schema/init/init_if_expr_1/stdout.golden +++ b/test/grammar/schema/init/init_if_expr_1/stdout.golden @@ -2,8 +2,8 @@ alice: name: alice age: 10 info: - gender: girl age: 10 + gender: girl John: name: john age: null diff --git a/test/grammar/schema/init/init_if_expr_2/main.k b/test/grammar/schema/init/init_if_expr_2/main.k deleted file mode 100644 index c3f3ac908..000000000 --- a/test/grammar/schema/init/init_if_expr_2/main.k +++ /dev/null @@ -1,33 +0,0 @@ -schema Person: - mixin [InfoMixin] - name?: str - age?: int - info: Info - - __settings__: {str:str} = { - "output_type": "IGNORE" - } - -schema Info: - gender?: str - meta?: {str:} - __settings__: {str:str} = { - "output_type": "STANDALONE" - } - -schema InfoMixin: - info |= { - "meta": { - "name": name if name else "feak", - "age": age if age else -1 - } - } - -persons = [Person { - "name": "alice", - "age": 10, - "info": {"gender": "girl"} -}, Person { - "name": "john", - "info": {"gender": "boy"} -}] diff --git a/test/grammar/schema/init/init_if_expr_2/stdout.golden b/test/grammar/schema/init/init_if_expr_2/stdout.golden deleted file mode 100644 index 274bf55c3..000000000 --- a/test/grammar/schema/init/init_if_expr_2/stdout.golden +++ /dev/null @@ -1,9 +0,0 @@ -gender: girl -meta: - name: alice - age: 10 ---- -gender: boy -meta: - name: john - age: -1 diff --git a/test/grammar/schema/init/init_if_expr_3/main.k b/test/grammar/schema/init/init_if_expr_3/main.k deleted file mode 100644 index 902a5501e..000000000 --- a/test/grammar/schema/init/init_if_expr_3/main.k +++ /dev/null @@ -1,36 +0,0 @@ -schema Person: - mixin [InfoMixin] - name?: str - age?: int - info?: Info - - __settings__: {str:str} = { - "output_type": "IGNORE" - } - -schema Info: - gender?: str - meta?: {str:} - - __settings__: {str:str} = { - "output_type": "STANDALONE" - } - -schema InfoMixin: - info |= { - "meta": { - "name": name if name else "feak", - "age": age if age else -1 - } - } - -person = "john" - -alice = Person { - "name": "alice", - "age": 10, - "info": {"gender": "girl"} -} if person == "alice" else Person { - "name": "john", - "info": {"gender": "boy"} -} diff --git a/test/grammar/schema/init/init_if_expr_3/stdout.golden b/test/grammar/schema/init/init_if_expr_3/stdout.golden deleted file mode 100644 index b9795af58..000000000 --- a/test/grammar/schema/init/init_if_expr_3/stdout.golden +++ /dev/null @@ -1,6 +0,0 @@ -person: john ---- -gender: boy -meta: - name: john - age: -1 diff --git a/test/grammar/schema/init/init_if_expr_4/main.k b/test/grammar/schema/init/init_if_expr_4/main.k deleted file mode 100644 index fb459367e..000000000 --- a/test/grammar/schema/init/init_if_expr_4/main.k +++ /dev/null @@ -1,36 +0,0 @@ -schema Person: - mixin [InfoMixin] - name?: str - age?: int - info?: Info - - __settings__: {str:str} = { - output_type = "IGNORE" - } - -schema Info: - gender?: str - meta?: {str:} - - __settings__: {str:str} = { - output_type = "STANDALONE" - } - -schema InfoMixin: - info |= Info { - meta = { - name = name if name else "feak", - age = age if age else -1 - } - } - -person = "john" - -alice = Person { - name = "alice", - age = 10, - info: Info {gender = "girl"} -} if person == "alice" else Person { - name = "john", - info: Info {gender = "boy"} -} diff --git a/test/grammar/schema/init/init_if_expr_4/stdout.golden b/test/grammar/schema/init/init_if_expr_4/stdout.golden deleted file mode 100644 index b9795af58..000000000 --- a/test/grammar/schema/init/init_if_expr_4/stdout.golden +++ /dev/null @@ -1,6 +0,0 @@ -person: john ---- -gender: boy -meta: - name: john - age: -1 diff --git a/test/grammar/schema/init/init_kwargs_fail_0/stderr.golden b/test/grammar/schema/init/init_kwargs_fail_0/stderr.golden new file mode 100644 index 000000000..6d7426043 --- /dev/null +++ b/test/grammar/schema/init/init_kwargs_fail_0/stderr.golden @@ -0,0 +1,13 @@ +error[E2L23]: CompileError + --> ${CWD}/main.k:4:17 + | +4 | person = Person(_naem="Alice") {} + | ^ "Person" got an unexpected keyword argument '_naem', did you mean '_name'? + | + +error[E2L23]: CompileError + --> ${CWD}/main.k:4:10 + | +4 | person = Person(_naem="Alice") {} + | ^ expected 1 positional argument, found 0 + | diff --git a/test/grammar/schema/init/init_kwargs_fail_0/stderr.golden.py b/test/grammar/schema/init/init_kwargs_fail_0/stderr.golden.py deleted file mode 100644 index 58755b842..000000000 --- a/test/grammar/schema/init/init_kwargs_fail_0/stderr.golden.py +++ /dev/null @@ -1,22 +0,0 @@ - -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.CompileError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=4, - col_no=17 - ) - ], - arg_msg="arguments got an unexpected keyword argument '_naem'" - ), - file=sys.stdout -) - diff --git a/test/grammar/schema/init/init_kwargs_fail_1/stderr.golden b/test/grammar/schema/init/init_kwargs_fail_1/stderr.golden new file mode 100644 index 000000000..0da6a032f --- /dev/null +++ b/test/grammar/schema/init/init_kwargs_fail_1/stderr.golden @@ -0,0 +1,6 @@ +error[E1001]: InvalidSyntax + --> ${CWD}/main.k:5:32 + | +5 | person = Person(_name="Alice", 12) {} + | ^ positional argument follows keyword argument + | \ No newline at end of file diff --git a/test/grammar/schema/init/init_kwargs_fail_1/stderr.golden.py b/test/grammar/schema/init/init_kwargs_fail_1/stderr.golden.py deleted file mode 100644 index 8dc531b3a..000000000 --- a/test/grammar/schema/init/init_kwargs_fail_1/stderr.golden.py +++ /dev/null @@ -1,20 +0,0 @@ - -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception(err_type=kcl_error.ErrType.IllegalArgumentError_Syntax_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=5, - col_no=32, - end_col_no=34 - ) - ], - arg_msg="positional argument follows keyword argument"), - file=sys.stdout -) diff --git a/test/grammar/schema/init/init_nested_schema_1/stdout.golden b/test/grammar/schema/init/init_nested_schema_1/stdout.golden index 788dbbed5..71e6cb93a 100644 --- a/test/grammar/schema/init/init_nested_schema_1/stdout.golden +++ b/test/grammar/schema/init/init_nested_schema_1/stdout.golden @@ -1,5 +1,5 @@ alice: name: name: - name: rename - gender: female \ No newline at end of file + name: alice + gender: female diff --git a/test/grammar/schema/init/init_outside_var_1/main.k b/test/grammar/schema/init/init_outside_var_1/main.k deleted file mode 100644 index 187fc305a..000000000 --- a/test/grammar/schema/init/init_outside_var_1/main.k +++ /dev/null @@ -1,12 +0,0 @@ -patchlist = [1, 2] -data = 1 - -schema Person: - name: str - list: [int] = [4, 5, 6] - val: int = 2 - val = data - list |= patchlist - name = "Alice" - -person_alice = Person {} diff --git a/test/grammar/schema/init/init_outside_var_1/stdout.golden b/test/grammar/schema/init/init_outside_var_1/stdout.golden deleted file mode 100644 index 7b7b0ae70..000000000 --- a/test/grammar/schema/init/init_outside_var_1/stdout.golden +++ /dev/null @@ -1,11 +0,0 @@ -patchlist: -- 1 -- 2 -data: 1 -person_alice: - name: Alice - list: - - 1 - - 2 - - 6 - val: 1 diff --git a/test/grammar/schema/init/init_patch_0/main.k b/test/grammar/schema/init/init_patch_0/main.k deleted file mode 100644 index 5922f9a81..000000000 --- a/test/grammar/schema/init/init_patch_0/main.k +++ /dev/null @@ -1,17 +0,0 @@ -schema Name: - firstName?: str - lastName?: str - -schema Person: - name: Name - name: Name |= { - "lastName": "Dow" - } - gender: str = "default gender" - -alice = Person { - "name": { - "firstName": "John" - }, - "gender" = "female" -} diff --git a/test/grammar/schema/init/init_patch_0/stdout.golden b/test/grammar/schema/init/init_patch_0/stdout.golden deleted file mode 100644 index 9b57c1073..000000000 --- a/test/grammar/schema/init/init_patch_0/stdout.golden +++ /dev/null @@ -1,5 +0,0 @@ -alice: - name: - firstName: John - lastName: Dow - gender: female \ No newline at end of file diff --git a/test/grammar/schema/init/init_schema_6/main.k b/test/grammar/schema/init/init_schema_6/main.k new file mode 100644 index 000000000..55dda4b66 --- /dev/null +++ b/test/grammar/schema/init/init_schema_6/main.k @@ -0,0 +1,11 @@ +schema Config: + name?: str + +makeCopy = lambda p: Config -> Config { + Config {name = p.name + "-copy"} +} +configs = { + "foo": Config {name = "foo"} + "bar": Config {name = "bar"} +} +copies = {"${name}-copy": makeCopy(config) for name, config in configs} diff --git a/test/grammar/schema/init/init_schema_6/stdout.golden b/test/grammar/schema/init/init_schema_6/stdout.golden new file mode 100644 index 000000000..a14973ede --- /dev/null +++ b/test/grammar/schema/init/init_schema_6/stdout.golden @@ -0,0 +1,10 @@ +configs: + foo: + name: foo + bar: + name: bar +copies: + foo-copy: + name: foo-copy + bar-copy: + name: bar-copy diff --git a/test/grammar/schema/init/init_schema_fail_0/stderr.golden b/test/grammar/schema/init/init_schema_fail_0/stderr.golden new file mode 100644 index 000000000..09339d402 --- /dev/null +++ b/test/grammar/schema/init/init_schema_fail_0/stderr.golden @@ -0,0 +1,6 @@ +error[E2G22]: TypeError + --> ${CWD}/main.k:8:5 + | +8 | name: Name = Name0 { + | ^ expected Name, got Name0 + | \ No newline at end of file diff --git a/test/grammar/schema/init/init_schema_fail_0/stderr.golden.py b/test/grammar/schema/init/init_schema_fail_0/stderr.golden.py deleted file mode 100644 index 2e6182da6..000000000 --- a/test/grammar/schema/init/init_schema_fail_0/stderr.golden.py +++ /dev/null @@ -1,22 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.TypeError_Compile_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=8, - col_no=5, - arg_msg="got Name0" - ) - ], - arg_msg="expect Name, got Name0" - ), - file=sys.stdout -) - diff --git a/test/grammar/schema/instances/complex/complex_2/backend.k b/test/grammar/schema/instances/complex/complex_2/backend.k index 24e902f04..5fe279a43 100644 --- a/test/grammar/schema/instances/complex/complex_2/backend.k +++ b/test/grammar/schema/instances/complex/complex_2/backend.k @@ -1,5 +1,4 @@ schema Backend: - __settings__: {str:str} = {"output_type": "STANDALONE"} """ existence of this attribute indicates that the model will be treated standalone by KCLVM. """ diff --git a/test/grammar/schema/instances/complex/complex_2/stdout.golden b/test/grammar/schema/instances/complex/complex_2/stdout.golden index e8f43377d..09d75a312 100644 --- a/test/grammar/schema/instances/complex/complex_2/stdout.golden +++ b/test/grammar/schema/instances/complex/complex_2/stdout.golden @@ -1,34 +1,34 @@ -apiVersion: v1 -kind: Deployment -metadata: - name: model1 - labels: - key1: value1 - key2: value2 - annotations: - key: value -spec: - minReadySeconds: 0 - paused: false - progressDeadlineSeconds: 600 - replicas: 2 - revisionHistoryLimit: 10 - selector: - matchLabels: +backends: +- apiVersion: v1 + kind: Deployment + metadata: + name: model1 + labels: key1: value1 key2: value2 ---- -apiVersion: v1 -kind: Deployment -metadata: - name: model2 - labels: null - annotations: null -spec: - minReadySeconds: 0 - paused: false - progressDeadlineSeconds: 600 - replicas: 3 - revisionHistoryLimit: 10 - selector: - matchLabels: null + annotations: + key: value + spec: + minReadySeconds: 0 + paused: false + progressDeadlineSeconds: 600 + replicas: 2 + revisionHistoryLimit: 10 + selector: + matchLabels: + key1: value1 + key2: value2 +- apiVersion: v1 + kind: Deployment + metadata: + name: model2 + labels: null + annotations: null + spec: + minReadySeconds: 0 + paused: false + progressDeadlineSeconds: 600 + replicas: 3 + revisionHistoryLimit: 10 + selector: + matchLabels: null diff --git a/test/grammar/schema/instances/complex/complex_5/main.k b/test/grammar/schema/instances/complex/complex_5/main.k new file mode 100644 index 000000000..c7ae89a01 --- /dev/null +++ b/test/grammar/schema/instances/complex/complex_5/main.k @@ -0,0 +1,5 @@ +import pkg + +x0 = pkg.Person {} +all_main_persons = pkg.Person.instances() +all_persons = pkg.Person.instances(True) diff --git a/test/grammar/schema/instances/complex/complex_5/pkg/pkg.k b/test/grammar/schema/instances/complex/complex_5/pkg/pkg.k new file mode 100644 index 000000000..51ea3f748 --- /dev/null +++ b/test/grammar/schema/instances/complex/complex_5/pkg/pkg.k @@ -0,0 +1,12 @@ +schema Data: + id: int = 1 + +schema Person: + name: str = "kcl" + age: int = 1 + data: Data = Data {} + +x0 = Person {} +x1 = Person { + age = 101 +} diff --git a/test/grammar/schema/instances/complex/complex_5/stdout.golden b/test/grammar/schema/instances/complex/complex_5/stdout.golden new file mode 100644 index 000000000..d358727ca --- /dev/null +++ b/test/grammar/schema/instances/complex/complex_5/stdout.golden @@ -0,0 +1,23 @@ +x0: + name: kcl + age: 1 + data: + id: 1 +all_main_persons: +- name: kcl + age: 1 + data: + id: 1 +all_persons: +- name: kcl + age: 1 + data: + id: 1 +- name: kcl + age: 101 + data: + id: 1 +- name: kcl + age: 1 + data: + id: 1 diff --git a/test/grammar/schema/instances/invalid/invalid_0/stderr.golden b/test/grammar/schema/instances/invalid/invalid_0/stderr.golden new file mode 100644 index 000000000..457ecfc65 --- /dev/null +++ b/test/grammar/schema/instances/invalid/invalid_0/stderr.golden @@ -0,0 +1,6 @@ +error[E2L23]: CompileError + --> ${CWD}/main.k:6:9 + | +6 | count = PersonErr.instances() + | ^ name 'PersonErr' is not defined, did you mean '["Person"]'? + | \ No newline at end of file diff --git a/test/grammar/schema/instances/invalid/invalid_0/stderr.golden.py b/test/grammar/schema/instances/invalid/invalid_0/stderr.golden.py deleted file mode 100644 index 35766480c..000000000 --- a/test/grammar/schema/instances/invalid/invalid_0/stderr.golden.py +++ /dev/null @@ -1,21 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.CompileError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=6, - col_no=9 - ) - ], - arg_msg="name 'PersonErr' is not defined" - ), - file=sys.stdout -) - diff --git a/test/grammar/schema/instances/invalid/invalid_1/stderr.golden b/test/grammar/schema/instances/invalid/invalid_1/stderr.golden new file mode 100644 index 000000000..8cb223cdd --- /dev/null +++ b/test/grammar/schema/instances/invalid/invalid_1/stderr.golden @@ -0,0 +1,6 @@ +error[E2G22]: TypeError + --> ${CWD}/main.k:6:9 + | +6 | count = Person.err_instances() + | ^ attribute 'err_instances' not found in 'Person', did you mean '["instances"]'? + | \ No newline at end of file diff --git a/test/grammar/schema/instances/invalid/invalid_1/stderr.golden.py b/test/grammar/schema/instances/invalid/invalid_1/stderr.golden.py deleted file mode 100644 index a4d4d336b..000000000 --- a/test/grammar/schema/instances/invalid/invalid_1/stderr.golden.py +++ /dev/null @@ -1,21 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.AttributeError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=6, - col_no=9 - ) - ], - arg_msg="schema 'Person' attribute 'err_instances' not found" - ), - file=sys.stdout -) - diff --git a/test/grammar/schema/invalid/add_attribute/stderr.golden b/test/grammar/schema/invalid/add_attribute/stderr.golden new file mode 100644 index 000000000..6e0e588b6 --- /dev/null +++ b/test/grammar/schema/invalid/add_attribute/stderr.golden @@ -0,0 +1,18 @@ +error[E2L23]: CompileError + --> ${CWD}/main.k:10:5 + | +10 | "first": "alice", + | ^ Cannot add member 'first' to schema 'Girl' + | +error[E2L23]: CompileError + --> ${CWD}/main.k:11:5 + | +11 | "last": " Green", + | ^ Cannot add member 'last' to schema 'Girl' + | +error[E2L23]: CompileError + --> ${CWD}/main.k:12:5 + | +12 | "age": 10 + | ^ Cannot add member 'age' to schema 'Girl' + | \ No newline at end of file diff --git a/test/grammar/schema/invalid/add_attribute/stderr.golden.py b/test/grammar/schema/invalid/add_attribute/stderr.golden.py deleted file mode 100644 index 5dcf7fe3d..000000000 --- a/test/grammar/schema/invalid/add_attribute/stderr.golden.py +++ /dev/null @@ -1,22 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.CannotAddMembers_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=10, - col_no=5, - arg_msg="'first' is not defined in schema 'Girl'" - ) - ], - arg_msg="Cannot add member 'first' to schema 'Girl'" - ), - file=sys.stdout -) - diff --git a/test/grammar/schema/invalid/add_attribute_double_star_expr/main.k b/test/grammar/schema/invalid/add_attribute_double_star_expr/main.k new file mode 100644 index 000000000..a1f03b588 --- /dev/null +++ b/test/grammar/schema/invalid/add_attribute_double_star_expr/main.k @@ -0,0 +1,21 @@ +innerConfig = { + nam = "" + config = { + nam = "" + } +} + +config = { + **innerConfig +} + +schema Config: + name: str + config: ConfigInner + +schema ConfigInner: + name: str + +c = Config { + **config +} diff --git a/test/grammar/schema/invalid/add_attribute_double_star_expr/stderr.golden b/test/grammar/schema/invalid/add_attribute_double_star_expr/stderr.golden new file mode 100644 index 000000000..29b1e5a2f --- /dev/null +++ b/test/grammar/schema/invalid/add_attribute_double_star_expr/stderr.golden @@ -0,0 +1,22 @@ +error[E2L23]: CompileError + --> ${CWD}/main.k:20:7 + | +20 | **config + | ^ Cannot add member 'nam' to schema 'Config', did you mean '["name"]'? + | + --> ${CWD}/main.k:2:5 + | +2 | nam = "" + | ^ config attribute is defined here + | +error[E2L23]: CompileError + --> ${CWD}/main.k:20:7 + | +20 | **config + | ^ Cannot add member 'nam' to schema 'ConfigInner', did you mean '["name"]'? + | + --> ${CWD}/main.k:4:9 + | +4 | nam = "" + | ^ config attribute is defined here + | diff --git a/test/grammar/schema/invalid/change_field/stderr.golden b/test/grammar/schema/invalid/change_field/stderr.golden new file mode 100644 index 000000000..2634d5d9b --- /dev/null +++ b/test/grammar/schema/invalid/change_field/stderr.golden @@ -0,0 +1,12 @@ +error[E1001]: ImmutableError + --> ${CWD}/main.k:9:1 + | +9 | JohnDoe.lastName = "John0" + | ^ Can not change the value of 'JohnDoe', because it was declared immutable + | + --> ${CWD}/main.k:5:1 + | +5 | JohnDoe = Person { + | ^ The variable 'JohnDoe' is declared here + | +note: change the variable name to '_JohnDoe' to make it mutable \ No newline at end of file diff --git a/test/grammar/schema/invalid/change_field/stderr.golden.py b/test/grammar/schema/invalid/change_field/stderr.golden.py deleted file mode 100644 index 59e12ea97..000000000 --- a/test/grammar/schema/invalid/change_field/stderr.golden.py +++ /dev/null @@ -1,21 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.ImmutableCompileError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=9, - col_no=1, - end_col_no=17 - ) - ], - ), - file=sys.stdout -) - diff --git a/test/grammar/schema/invalid/no_schema/stderr.golden b/test/grammar/schema/invalid/no_schema/stderr.golden new file mode 100644 index 000000000..e77a69162 --- /dev/null +++ b/test/grammar/schema/invalid/no_schema/stderr.golden @@ -0,0 +1,6 @@ +error[E2L23]: CompileError + --> ${CWD}/main.k:1:11 + | +1 | JohnDoe = Person { + | ^ name 'Person' is not defined + | \ No newline at end of file diff --git a/test/grammar/schema/invalid/no_schema/stderr.golden.py b/test/grammar/schema/invalid/no_schema/stderr.golden.py deleted file mode 100644 index 5b2fddce2..000000000 --- a/test/grammar/schema/invalid/no_schema/stderr.golden.py +++ /dev/null @@ -1,22 +0,0 @@ - -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.CompileError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=1, - col_no=11 - ) - ], - arg_msg="name 'Person' is not defined" - ), - file=sys.stdout -) - diff --git a/test/grammar/schema/irrelevant_order/complex_2/main.k b/test/grammar/schema/irrelevant_order/complex_2/main.k index e317c61ff..094169b14 100644 --- a/test/grammar/schema/irrelevant_order/complex_2/main.k +++ b/test/grammar/schema/irrelevant_order/complex_2/main.k @@ -1,5 +1,4 @@ schema KubeNamespace: - __settings__: {str:str} = {"output_type": "STANDALONE"} apiVersion: str = "v1" kind: str = "Namespace" metadata: {str:} @@ -34,10 +33,6 @@ schema Namespace(Metadata): name: str = "prod-frontend" finalizers: [str] - __settings__: {str:} = { - "output_type": "IGNORE" - } - node = Namespace { finalizers: ["test"] } diff --git a/test/grammar/schema/irrelevant_order/complex_2/stdout.golden b/test/grammar/schema/irrelevant_order/complex_2/stdout.golden index 588b0e586..1964ad8c6 100644 --- a/test/grammar/schema/irrelevant_order/complex_2/stdout.golden +++ b/test/grammar/schema/irrelevant_order/complex_2/stdout.golden @@ -1,7 +1,14 @@ -apiVersion: v1 -kind: Namespace -metadata: +node: name: prod-frontend -spec: + metadata: + name: prod-frontend finalizers: - test + kubeNamespace: + apiVersion: v1 + kind: Namespace + metadata: + name: prod-frontend + spec: + finalizers: + - test diff --git a/test/grammar/schema/irrelevant_order/complex_4/main.k b/test/grammar/schema/irrelevant_order/complex_4/main.k deleted file mode 100644 index 51cfb601c..000000000 --- a/test/grammar/schema/irrelevant_order/complex_4/main.k +++ /dev/null @@ -1,44 +0,0 @@ -schema KubeAction: - __settings__: {str:str} = {"output_type": "STANDALONE"} - apiVersion: str = "kusion/v1" - kind: str = "Action" - metadata: {str:} - spec: {str:} - -schema Action: - __settings__: {str:str} = {"output_type": "IGNORE"} - name: str - pod: str - namespace: str - cluster: str - type: str - - kubeAction: KubeAction = KubeAction { - metadata.name: name - spec: { - pod: pod, - namespace: namespace, - cluster: cluster, - type: type - } - } - - -schema KeyValueUpdateAction(Action): - keyValues: {str:} - query: {str:} - # kubeAction: KubeAction - pod = "podname" - namespace = "namespace" - cluster: str = "cluster" - type: str = "pods" - name: str = "pod_key_value_update" - - kubeAction.spec |= { - "keyValues": keyValues - } - -act = KeyValueUpdateAction() { - query.hostnames: ["foo.bar"] - keyValues.key: "val" -} diff --git a/test/grammar/schema/irrelevant_order/complex_4/stdout.golden b/test/grammar/schema/irrelevant_order/complex_4/stdout.golden deleted file mode 100644 index d10ccc39a..000000000 --- a/test/grammar/schema/irrelevant_order/complex_4/stdout.golden +++ /dev/null @@ -1,11 +0,0 @@ -apiVersion: kusion/v1 -kind: Action -metadata: - name: pod_key_value_update -spec: - pod: podname - namespace: namespace - cluster: cluster - type: pods - keyValues: - key: val diff --git a/test/grammar/schema/irrelevant_order/for_2/main.k b/test/grammar/schema/irrelevant_order/for_2/main.k index 563148c5b..40b623d75 100644 --- a/test/grammar/schema/irrelevant_order/for_2/main.k +++ b/test/grammar/schema/irrelevant_order/for_2/main.k @@ -3,7 +3,7 @@ schema Data: data: {str:str} = { "key1": "value1" } - data |= { + data = { "key2": "value2" } dataOther = {**data} diff --git a/test/grammar/schema/irrelevant_order/for_2/stdout.golden b/test/grammar/schema/irrelevant_order/for_2/stdout.golden index 33363f055..3ea1572c7 100644 --- a/test/grammar/schema/irrelevant_order/for_2/stdout.golden +++ b/test/grammar/schema/irrelevant_order/for_2/stdout.golden @@ -1,10 +1,7 @@ data: keys: - - key1 - key2 data: - key1: value1 key2: value2 dataOther: - key1: value1 key2: value2 diff --git a/test/grammar/schema/irrelevant_order/if_stmt_0/main.k b/test/grammar/schema/irrelevant_order/if_stmt_0/main.k index 47577f15a..5297600d3 100644 --- a/test/grammar/schema/irrelevant_order/if_stmt_0/main.k +++ b/test/grammar/schema/irrelevant_order/if_stmt_0/main.k @@ -11,3 +11,12 @@ schema Person: person = Person { name = "Overwrite" } + +name: str = _name +age: int = _age +if True: + _name = "Alice" +if False: + _age = 10 +else: + _age = 18 diff --git a/test/grammar/schema/irrelevant_order/if_stmt_0/stdout.golden b/test/grammar/schema/irrelevant_order/if_stmt_0/stdout.golden index 7e7205956..9178de890 100644 --- a/test/grammar/schema/irrelevant_order/if_stmt_0/stdout.golden +++ b/test/grammar/schema/irrelevant_order/if_stmt_0/stdout.golden @@ -1,3 +1,5 @@ person: name: Overwrite age: 18 +name: Alice +age: 18 diff --git a/test/grammar/schema/irrelevant_order/if_stmt_10/main.k b/test/grammar/schema/irrelevant_order/if_stmt_10/main.k new file mode 100644 index 000000000..eb9bacc5a --- /dev/null +++ b/test/grammar/schema/irrelevant_order/if_stmt_10/main.k @@ -0,0 +1,13 @@ +schema Name: + _a = 1 + _b = 1 + if True: + _a += 1 + _b += 1 + elif False: + _a += 1 + _b += 1 + a = _a + b = _b + +name = Name{} diff --git a/test/grammar/schema/irrelevant_order/if_stmt_10/stdout.golden b/test/grammar/schema/irrelevant_order/if_stmt_10/stdout.golden new file mode 100644 index 000000000..5da033819 --- /dev/null +++ b/test/grammar/schema/irrelevant_order/if_stmt_10/stdout.golden @@ -0,0 +1,3 @@ +name: + a: 2 + b: 2 diff --git a/test/grammar/schema/irrelevant_order/if_stmt_7/main.k b/test/grammar/schema/irrelevant_order/if_stmt_7/main.k new file mode 100644 index 000000000..a4ca0aecd --- /dev/null +++ b/test/grammar/schema/irrelevant_order/if_stmt_7/main.k @@ -0,0 +1,6 @@ +_a = 1 +if True: + _a += 1 +elif False: + _a += 1 +a = _a diff --git a/test/grammar/schema/irrelevant_order/if_stmt_7/stdout.golden b/test/grammar/schema/irrelevant_order/if_stmt_7/stdout.golden new file mode 100644 index 000000000..9dfc208df --- /dev/null +++ b/test/grammar/schema/irrelevant_order/if_stmt_7/stdout.golden @@ -0,0 +1 @@ +a: 2 diff --git a/test/grammar/schema/irrelevant_order/if_stmt_8/main.k b/test/grammar/schema/irrelevant_order/if_stmt_8/main.k new file mode 100644 index 000000000..77a9ba1fe --- /dev/null +++ b/test/grammar/schema/irrelevant_order/if_stmt_8/main.k @@ -0,0 +1,9 @@ +schema Name: + _a = 1 + if True: + _a += 1 + elif False: + _a += 1 + a = _a + +name = Name{} diff --git a/test/grammar/schema/irrelevant_order/if_stmt_8/stdout.golden b/test/grammar/schema/irrelevant_order/if_stmt_8/stdout.golden new file mode 100644 index 000000000..e727a4e4f --- /dev/null +++ b/test/grammar/schema/irrelevant_order/if_stmt_8/stdout.golden @@ -0,0 +1,2 @@ +name: + a: 2 diff --git a/test/grammar/schema/irrelevant_order/if_stmt_9/main.k b/test/grammar/schema/irrelevant_order/if_stmt_9/main.k new file mode 100644 index 000000000..17f237ff9 --- /dev/null +++ b/test/grammar/schema/irrelevant_order/if_stmt_9/main.k @@ -0,0 +1,5 @@ +_a = 1 +if True: + print() + _a += 1 +a = _a diff --git a/test/grammar/schema/irrelevant_order/if_stmt_9/stdout.golden b/test/grammar/schema/irrelevant_order/if_stmt_9/stdout.golden new file mode 100644 index 000000000..f393f6aec --- /dev/null +++ b/test/grammar/schema/irrelevant_order/if_stmt_9/stdout.golden @@ -0,0 +1,2 @@ + +a: 2 \ No newline at end of file diff --git a/test/grammar/schema/irrelevant_order/inherit_1/main.k b/test/grammar/schema/irrelevant_order/inherit_1/main.k index 766908ca8..c8364678f 100644 --- a/test/grammar/schema/irrelevant_order/inherit_1/main.k +++ b/test/grammar/schema/irrelevant_order/inherit_1/main.k @@ -1,4 +1,6 @@ schema BasePerson: + firstName: str + lastName: str fullName = firstName + ' ' + lastName schema Person(BasePerson): diff --git a/test/grammar/schema/irrelevant_order/inherit_1/stdout.golden b/test/grammar/schema/irrelevant_order/inherit_1/stdout.golden index c7bb08aef..7caad7724 100644 --- a/test/grammar/schema/irrelevant_order/inherit_1/stdout.golden +++ b/test/grammar/schema/irrelevant_order/inherit_1/stdout.golden @@ -1,4 +1,4 @@ JohnDoe: - fullName: John Doe firstName: John lastName: Doe + fullName: John Doe diff --git a/test/grammar/schema/irrelevant_order/inherit_4/main.k b/test/grammar/schema/irrelevant_order/inherit_4/main.k index b0964f987..0a0ebcb7a 100644 --- a/test/grammar/schema/irrelevant_order/inherit_4/main.k +++ b/test/grammar/schema/irrelevant_order/inherit_4/main.k @@ -10,7 +10,7 @@ schema AppConfig(Config): name: str = "app" if overQuota: - labels |= { + labels = { "key1": "value1" "key2": "value2" } diff --git a/test/grammar/schema/irrelevant_order/inherit_5/main.k b/test/grammar/schema/irrelevant_order/inherit_5/main.k index 81c95f006..afe1cf07f 100644 --- a/test/grammar/schema/irrelevant_order/inherit_5/main.k +++ b/test/grammar/schema/irrelevant_order/inherit_5/main.k @@ -10,11 +10,11 @@ schema AppConfig(Config): name: str = "app" if overQuota: - labels |= { + labels = { "key1": "value1" } if overQuota: - labels |= { + labels = { "key2": "value2" } diff --git a/test/grammar/schema/irrelevant_order/inherit_5/stdout.golden b/test/grammar/schema/irrelevant_order/inherit_5/stdout.golden index 0ef8fe5ac..05ef69e6a 100644 --- a/test/grammar/schema/irrelevant_order/inherit_5/stdout.golden +++ b/test/grammar/schema/irrelevant_order/inherit_5/stdout.golden @@ -8,10 +8,8 @@ appConfig: name: app help: app labels: - key1: value1 key2: value2 metaLabels: - key1: value1 key2: value2 overQuota: true appName: myApp diff --git a/test/grammar/schema/irrelevant_order/inherit_6/main.k b/test/grammar/schema/irrelevant_order/inherit_6/main.k index b48c7089d..0302a0b16 100644 --- a/test/grammar/schema/irrelevant_order/inherit_6/main.k +++ b/test/grammar/schema/irrelevant_order/inherit_6/main.k @@ -3,11 +3,11 @@ schema Parent: key: str = "key" + " " + name name2: str = "Alice" key2: str = "key2" + " " + name2 - _tempA = "tempA" + _tempA: str = "tempA" schema Son1(Parent): name: str = "Son1" - _tempB = "tempB" + _tempB: str = "tempB" schema Son2(Son1): name: str = "Son2" + _tempA diff --git a/test/grammar/schema/irrelevant_order/mixin_2/main.k b/test/grammar/schema/irrelevant_order/mixin_2/main.k index cba2b333c..716e50065 100644 --- a/test/grammar/schema/irrelevant_order/mixin_2/main.k +++ b/test/grammar/schema/irrelevant_order/mixin_2/main.k @@ -4,7 +4,7 @@ schema Data: metaLabels: {str:} = labels schema DataMixin: - labels |= { + labels = { "key": "value" } diff --git a/test/grammar/schema/irrelevant_order/mixin_3/main.k b/test/grammar/schema/irrelevant_order/mixin_3/main.k index 1528261b7..959446009 100644 --- a/test/grammar/schema/irrelevant_order/mixin_3/main.k +++ b/test/grammar/schema/irrelevant_order/mixin_3/main.k @@ -1,6 +1,6 @@ schema ConfigMixin: output: str = option("output") or "default_output" - data |= {"output": output} + data = {"output": output} schema Config: mixin [ConfigMixin] diff --git a/test/grammar/schema/irrelevant_order/simple_10/main.k b/test/grammar/schema/irrelevant_order/simple_10/main.k new file mode 100644 index 000000000..0e59f687f --- /dev/null +++ b/test/grammar/schema/irrelevant_order/simple_10/main.k @@ -0,0 +1,15 @@ +schema Data: + name: str + version?: str + +data1 = Data { + name = data2.name +} + +data2 = Data { + name = "1" + version = version +} + +# Global version +version = "v0.1.0" diff --git a/test/grammar/schema/irrelevant_order/simple_10/stdout.golden b/test/grammar/schema/irrelevant_order/simple_10/stdout.golden new file mode 100644 index 000000000..70d941e06 --- /dev/null +++ b/test/grammar/schema/irrelevant_order/simple_10/stdout.golden @@ -0,0 +1,6 @@ +data1: + name: '1' +data2: + name: '1' + version: v0.1.0 +version: v0.1.0 diff --git a/test/grammar/schema/irrelevant_order/simple_11/main.k b/test/grammar/schema/irrelevant_order/simple_11/main.k new file mode 100644 index 000000000..58306e7f0 --- /dev/null +++ b/test/grammar/schema/irrelevant_order/simple_11/main.k @@ -0,0 +1,9 @@ +v = f1() + +f0 = lambda { + "value" +} + +f1 = lambda { + {f0 = f0()} +} diff --git a/test/grammar/schema/irrelevant_order/simple_11/stdout.golden b/test/grammar/schema/irrelevant_order/simple_11/stdout.golden new file mode 100644 index 000000000..78a499fb1 --- /dev/null +++ b/test/grammar/schema/irrelevant_order/simple_11/stdout.golden @@ -0,0 +1,2 @@ +v: + f0: value diff --git a/test/grammar/schema/irrelevant_order/simple_12/main.k b/test/grammar/schema/irrelevant_order/simple_12/main.k new file mode 100644 index 000000000..148a00c5c --- /dev/null +++ b/test/grammar/schema/irrelevant_order/simple_12/main.k @@ -0,0 +1,12 @@ +schema Derived1(Base): + name: str = "1" + +schema Base: + name: str + name2 = name + +schema Derived2(Base): + name: str = "2" + +d1 = Derived1 {} +d2 = Derived2 {} diff --git a/test/grammar/schema/irrelevant_order/simple_12/stdout.golden b/test/grammar/schema/irrelevant_order/simple_12/stdout.golden new file mode 100644 index 000000000..52980c233 --- /dev/null +++ b/test/grammar/schema/irrelevant_order/simple_12/stdout.golden @@ -0,0 +1,6 @@ +d1: + name: '1' + name2: '1' +d2: + name: '2' + name2: '2' diff --git a/test/grammar/schema/irrelevant_order/simple_4/main.k b/test/grammar/schema/irrelevant_order/simple_4/main.k index c3f76c4b2..fec74eae6 100644 --- a/test/grammar/schema/irrelevant_order/simple_4/main.k +++ b/test/grammar/schema/irrelevant_order/simple_4/main.k @@ -1,8 +1,7 @@ schema Config: a: int = b - b: int + b: int = 1 if True: - b = 1 b += 1 x0 = Config {} diff --git a/test/grammar/schema/irrelevant_order/simple_6/main.k b/test/grammar/schema/irrelevant_order/simple_6/main.k new file mode 100644 index 000000000..5fab5aa77 --- /dev/null +++ b/test/grammar/schema/irrelevant_order/simple_6/main.k @@ -0,0 +1,11 @@ +schema Config: + a: int = b + b: int = 2 + if True: + b = 1 + b += 3 + +x0 = Config {} +x1 = Config { + a = 10 +} diff --git a/test/grammar/schema/irrelevant_order/simple_6/stdout.golden b/test/grammar/schema/irrelevant_order/simple_6/stdout.golden new file mode 100644 index 000000000..cfb622fa3 --- /dev/null +++ b/test/grammar/schema/irrelevant_order/simple_6/stdout.golden @@ -0,0 +1,6 @@ +x0: + a: 4 + b: 4 +x1: + a: 10 + b: 4 diff --git a/test/grammar/schema/irrelevant_order/simple_7/main.k b/test/grammar/schema/irrelevant_order/simple_7/main.k new file mode 100644 index 000000000..c090b2995 --- /dev/null +++ b/test/grammar/schema/irrelevant_order/simple_7/main.k @@ -0,0 +1,2 @@ +b = a +a = 1 diff --git a/test/grammar/schema/irrelevant_order/simple_7/stdout.golden b/test/grammar/schema/irrelevant_order/simple_7/stdout.golden new file mode 100644 index 000000000..1bcc2448b --- /dev/null +++ b/test/grammar/schema/irrelevant_order/simple_7/stdout.golden @@ -0,0 +1,2 @@ +b: 1 +a: 1 diff --git a/test/grammar/schema/irrelevant_order/simple_8/main.k b/test/grammar/schema/irrelevant_order/simple_8/main.k new file mode 100644 index 000000000..e7dc4200f --- /dev/null +++ b/test/grammar/schema/irrelevant_order/simple_8/main.k @@ -0,0 +1,3 @@ +b = a + c +a = 1 +c = a + 1 diff --git a/test/grammar/schema/irrelevant_order/simple_8/stdout.golden b/test/grammar/schema/irrelevant_order/simple_8/stdout.golden new file mode 100644 index 000000000..2befd0fca --- /dev/null +++ b/test/grammar/schema/irrelevant_order/simple_8/stdout.golden @@ -0,0 +1,3 @@ +b: 3 +a: 1 +c: 2 diff --git a/test/grammar/schema/irrelevant_order/simple_9/kcl.mod b/test/grammar/schema/irrelevant_order/simple_9/kcl.mod new file mode 100644 index 000000000..e69de29bb diff --git a/test/grammar/schema/irrelevant_order/simple_9/main.k b/test/grammar/schema/irrelevant_order/simple_9/main.k new file mode 100644 index 000000000..af2d1b5a0 --- /dev/null +++ b/test/grammar/schema/irrelevant_order/simple_9/main.k @@ -0,0 +1,3 @@ +import pkg + +output = pkg.output diff --git a/test/grammar/schema/irrelevant_order/simple_9/pkg/base.k b/test/grammar/schema/irrelevant_order/simple_9/pkg/base.k new file mode 100644 index 000000000..17f5d750f --- /dev/null +++ b/test/grammar/schema/irrelevant_order/simple_9/pkg/base.k @@ -0,0 +1,4 @@ +schema MyApp: + name: str + versions: {str:str} + version = versions[name] diff --git a/test/grammar/schema/irrelevant_order/simple_9/pkg/input.k b/test/grammar/schema/irrelevant_order/simple_9/pkg/input.k new file mode 100644 index 000000000..d5b3ec80d --- /dev/null +++ b/test/grammar/schema/irrelevant_order/simple_9/pkg/input.k @@ -0,0 +1,5 @@ +output = MyApp{ + name = name + versions = my_versions +} +name = "my_app" diff --git a/test/grammar/schema/irrelevant_order/simple_9/pkg/versions.k b/test/grammar/schema/irrelevant_order/simple_9/pkg/versions.k new file mode 100644 index 000000000..f65fa4fdf --- /dev/null +++ b/test/grammar/schema/irrelevant_order/simple_9/pkg/versions.k @@ -0,0 +1,3 @@ +my_versions = { + "my-app": "1.0.0" +} \ No newline at end of file diff --git a/test/grammar/schema/irrelevant_order/simple_9/stdout.golden b/test/grammar/schema/irrelevant_order/simple_9/stdout.golden new file mode 100644 index 000000000..56277907c --- /dev/null +++ b/test/grammar/schema/irrelevant_order/simple_9/stdout.golden @@ -0,0 +1,4 @@ +output: + name: my_app + versions: + my-app: 1.0.0 diff --git a/test/grammar/schema/mixin/add_member_fail/stderr.golden b/test/grammar/schema/mixin/add_member_fail/stderr.golden new file mode 100644 index 000000000..8dbb17612 --- /dev/null +++ b/test/grammar/schema/mixin/add_member_fail/stderr.golden @@ -0,0 +1,6 @@ +error[E2L23]: CompileError + --> ${CWD}/main.k:16:9 + | +16 | "frist": first + | ^ Cannot add member 'frist' to schema 'Person', did you mean '["first"]'? + | \ No newline at end of file diff --git a/test/grammar/schema/mixin/add_member_fail/stderr.golden.py b/test/grammar/schema/mixin/add_member_fail/stderr.golden.py deleted file mode 100644 index b7a19ac26..000000000 --- a/test/grammar/schema/mixin/add_member_fail/stderr.golden.py +++ /dev/null @@ -1,21 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.CannotAddMembers_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=16, - col_no=9, - arg_msg="'frist' is not defined in schema 'Person'" - ) - ], - arg_msg="Cannot add member 'frist' to schema 'Person'" - ), - file=sys.stdout -) diff --git a/test/grammar/schema/mixin/dict_2_schema_0/main.k b/test/grammar/schema/mixin/dict_2_schema_0/main.k index 3ea5962e2..510feaf0c 100644 --- a/test/grammar/schema/mixin/dict_2_schema_0/main.k +++ b/test/grammar/schema/mixin/dict_2_schema_0/main.k @@ -10,9 +10,6 @@ schema Rule: kind: str = "Rule" access: [str] entity: Person - __settings__: {str:} = { - "output_type": "STANDALONE" - } schema RuleMixin: if rule: diff --git a/test/grammar/schema/mixin/dict_2_schema_0/stdout.golden b/test/grammar/schema/mixin/dict_2_schema_0/stdout.golden index 8a6f91af1..1cbedfe0a 100644 --- a/test/grammar/schema/mixin/dict_2_schema_0/stdout.golden +++ b/test/grammar/schema/mixin/dict_2_schema_0/stdout.golden @@ -7,13 +7,13 @@ alice: access: - read - write ---- -kind: Rule -access: -- read -- write -entity: - name: alice - relatives: - - relation: father - name: Reese \ No newline at end of file + ruleModel: + kind: Rule + access: + - read + - write + entity: + name: alice + relatives: + - relation: father + name: Reese diff --git a/test/grammar/schema/mixin/dict_2_schema_1/main.k b/test/grammar/schema/mixin/dict_2_schema_1/main.k index 8321e6cf4..757c7e22b 100644 --- a/test/grammar/schema/mixin/dict_2_schema_1/main.k +++ b/test/grammar/schema/mixin/dict_2_schema_1/main.k @@ -10,9 +10,6 @@ schema Rule: kind: str = "Rule" access: [str] entity: Person - __settings__: {str:} = { - "output_type": "STANDALONE" - } schema RuleMixin: if rule: diff --git a/test/grammar/schema/mixin/dict_2_schema_1/stdout.golden b/test/grammar/schema/mixin/dict_2_schema_1/stdout.golden index e92a589ac..3df72e7e6 100644 --- a/test/grammar/schema/mixin/dict_2_schema_1/stdout.golden +++ b/test/grammar/schema/mixin/dict_2_schema_1/stdout.golden @@ -7,13 +7,13 @@ alice: access: - read - write ---- -kind: Rule -access: -- read -- write -entity: - name: alice - relatives: - - relation: father - name: Reese + ruleModels: + - kind: Rule + access: + - read + - write + entity: + name: alice + relatives: + - relation: father + name: Reese diff --git a/test/grammar/schema/mixin/dict_2_schema_2/main.k b/test/grammar/schema/mixin/dict_2_schema_2/main.k index 2029b2adb..f27bc719e 100644 --- a/test/grammar/schema/mixin/dict_2_schema_2/main.k +++ b/test/grammar/schema/mixin/dict_2_schema_2/main.k @@ -10,9 +10,6 @@ schema Rule: kind: str = "Rule" access: [str] entity: Person - __settings__: {str:} = { - output_type = "STANDALONE" - } schema RuleMixin: if rule: diff --git a/test/grammar/schema/mixin/dict_2_schema_2/stdout.golden b/test/grammar/schema/mixin/dict_2_schema_2/stdout.golden index e92a589ac..3df72e7e6 100644 --- a/test/grammar/schema/mixin/dict_2_schema_2/stdout.golden +++ b/test/grammar/schema/mixin/dict_2_schema_2/stdout.golden @@ -7,13 +7,13 @@ alice: access: - read - write ---- -kind: Rule -access: -- read -- write -entity: - name: alice - relatives: - - relation: father - name: Reese + ruleModels: + - kind: Rule + access: + - read + - write + entity: + name: alice + relatives: + - relation: father + name: Reese diff --git a/test/grammar/schema/mixin/invalid_name_failure/stderr.golden b/test/grammar/schema/mixin/invalid_name_failure/stderr.golden new file mode 100644 index 000000000..d6e083637 --- /dev/null +++ b/test/grammar/schema/mixin/invalid_name_failure/stderr.golden @@ -0,0 +1,24 @@ +error[E1001]: NameError + --> ${CWD}/main.k:10:12 + | +10 | mixin [Fullname] + | ^ a valid mixin name should end with 'Mixin', got 'Fullname' + | +error[E2D34]: IllegalInheritError + --> ${CWD}/main.k:10:12 + | +10 | mixin [Fullname] + | ^ illegal schema mixin object type, expected mixin, got 'Fullname' + | +error[E2L23]: CompileError + --> ${CWD}/main.k:7:31 + | +7 | fullName = "{} {}".format(firstName, lastName) + | ^ name 'firstName' is not defined + | +error[E2L23]: CompileError + --> ${CWD}/main.k:7:42 + | +7 | fullName = "{} {}".format(firstName, lastName) + | ^ name 'lastName' is not defined + | \ No newline at end of file diff --git a/test/grammar/schema/mixin/invalid_name_failure/stderr.golden.py b/test/grammar/schema/mixin/invalid_name_failure/stderr.golden.py deleted file mode 100644 index 7a718bc8f..000000000 --- a/test/grammar/schema/mixin/invalid_name_failure/stderr.golden.py +++ /dev/null @@ -1,21 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.MixinNamingError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=10, - col_no=12 - ) - ], - arg_msg="a valid mixin name should end with 'Mixin', got 'Fullname'" - ), - file=sys.stdout -) - diff --git a/test/grammar/schema/mixin/schema_field_change_dict/main.k b/test/grammar/schema/mixin/schema_field_change_dict/main.k deleted file mode 100644 index b2da3f64a..000000000 --- a/test/grammar/schema/mixin/schema_field_change_dict/main.k +++ /dev/null @@ -1,21 +0,0 @@ -schema Person: - firstName: str - lastName: str - fullName: str - info: {str:str} - -schema InfoMixin: - info |= {"phone": "321"} - -schema Scholar(Person): - mixin [InfoMixin] - school?: str = None - -JohnDoe = Scholar { - "firstName": "John", - "lastName": "Doe", - "fullName": "Doe Jon", - "info": { - "id": "123" - } -} diff --git a/test/grammar/schema/mixin/schema_field_change_dict/stdout.golden b/test/grammar/schema/mixin/schema_field_change_dict/stdout.golden deleted file mode 100644 index 064bd2f75..000000000 --- a/test/grammar/schema/mixin/schema_field_change_dict/stdout.golden +++ /dev/null @@ -1,8 +0,0 @@ -JohnDoe: - firstName: John - lastName: Doe - fullName: Doe Jon - info: - id: '123' - phone: '321' - school: null diff --git a/test/grammar/schema/mixin/schema_field_union_list/main.k b/test/grammar/schema/mixin/schema_field_union_list/main.k deleted file mode 100644 index 8c49257d2..000000000 --- a/test/grammar/schema/mixin/schema_field_union_list/main.k +++ /dev/null @@ -1,18 +0,0 @@ -schema Person: - firstName: str - lastName: str - fullName: str - tags: [str] = ["123"] - -schema InfoMixin: - tags |= ["234"] - -schema Scholar(Person): - mixin [InfoMixin] - school?: str = None - -JohnDoe = Scholar { - "firstName": "John", - "lastName": "Doe", - "fullName": "Doe Jon", -} diff --git a/test/grammar/schema/mixin/schema_field_union_list/stdout.golden b/test/grammar/schema/mixin/schema_field_union_list/stdout.golden deleted file mode 100644 index 638f5f70c..000000000 --- a/test/grammar/schema/mixin/schema_field_union_list/stdout.golden +++ /dev/null @@ -1,7 +0,0 @@ -JohnDoe: - firstName: John - lastName: Doe - fullName: Doe Jon - tags: - - '234' - school: null diff --git a/test/grammar/schema/optional_attr/fail_0/stderr.golden b/test/grammar/schema/optional_attr/fail_0/stderr.golden new file mode 100644 index 000000000..dc2bcdf2f --- /dev/null +++ b/test/grammar/schema/optional_attr/fail_0/stderr.golden @@ -0,0 +1,6 @@ +error[E3M38]: EvaluationError + --> ${CWD}/main.k:5:1 + | +5 | person = Person {} + | attribute 'name' of Person is required and can't be None or Undefined + | \ No newline at end of file diff --git a/test/grammar/schema/optional_attr/fail_0/stderr.golden.py b/test/grammar/schema/optional_attr/fail_0/stderr.golden.py deleted file mode 100644 index 25adb3b6c..000000000 --- a/test/grammar/schema/optional_attr/fail_0/stderr.golden.py +++ /dev/null @@ -1,19 +0,0 @@ -import sys -import os - -import kclvm.kcl.error as kcl_error - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception(err_type=kcl_error.ErrType.EvaluationError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=5, - ), - ], - arg_msg="attribute 'name' of Person is required and can't be None or Undefined") - , file=sys.stdout -) - diff --git a/test/grammar/schema/optional_attr/fail_1/stderr.golden b/test/grammar/schema/optional_attr/fail_1/stderr.golden new file mode 100644 index 000000000..53d14cb7f --- /dev/null +++ b/test/grammar/schema/optional_attr/fail_1/stderr.golden @@ -0,0 +1,6 @@ +error[E3M38]: EvaluationError + --> ${CWD}/main.k:8:1 + | +8 | person = Person { + | attribute 'info' of Person is required and can't be None or Undefined + | \ No newline at end of file diff --git a/test/grammar/schema/optional_attr/fail_1/stderr.golden.py b/test/grammar/schema/optional_attr/fail_1/stderr.golden.py deleted file mode 100644 index d8d89cc67..000000000 --- a/test/grammar/schema/optional_attr/fail_1/stderr.golden.py +++ /dev/null @@ -1,19 +0,0 @@ -import sys -import os - -import kclvm.kcl.error as kcl_error - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception(err_type=kcl_error.ErrType.EvaluationError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=8, - ), - ], - arg_msg="attribute 'info' of Person is required and can't be None or Undefined") - , file=sys.stdout -) - diff --git a/test/grammar/schema/optional_attr/fail_10/main.k b/test/grammar/schema/optional_attr/fail_10/main.k new file mode 100644 index 000000000..0d2583749 --- /dev/null +++ b/test/grammar/schema/optional_attr/fail_10/main.k @@ -0,0 +1,16 @@ +schema TeamSpec[id: str]: + fullName: str + name: str = id + shortName: str = name + +schema Team: + [id: str]: TeamSpec = TeamSpec(id) + +Teams = Team { + a.fullName = "alpha" + b.fullName = "bravo" + c = { + fullName = "charlie" + shortName = "cc" + } +} diff --git a/test/grammar/schema/optional_attr/fail_10/stderr.golden b/test/grammar/schema/optional_attr/fail_10/stderr.golden new file mode 100644 index 000000000..f7d60d17c --- /dev/null +++ b/test/grammar/schema/optional_attr/fail_10/stderr.golden @@ -0,0 +1 @@ +attribute 'name' of TeamSpec is required and can't be None or Undefined \ No newline at end of file diff --git a/test/grammar/schema/optional_attr/fail_11/main.k b/test/grammar/schema/optional_attr/fail_11/main.k new file mode 100644 index 000000000..02acee9f3 --- /dev/null +++ b/test/grammar/schema/optional_attr/fail_11/main.k @@ -0,0 +1,14 @@ +schema TeamSpec[id: str]: + fullName: str + name: str = id + shortName: str = name + +schema Team: + d: TeamSpec = TeamSpec("d") + +Teams = Team { + d = { + fullName = "charlie" + shortName = "dd" + } +} diff --git a/test/grammar/schema/optional_attr/fail_11/stderr.golden b/test/grammar/schema/optional_attr/fail_11/stderr.golden new file mode 100644 index 000000000..f7d60d17c --- /dev/null +++ b/test/grammar/schema/optional_attr/fail_11/stderr.golden @@ -0,0 +1 @@ +attribute 'name' of TeamSpec is required and can't be None or Undefined \ No newline at end of file diff --git a/test/grammar/schema/optional_attr/fail_12/main.k b/test/grammar/schema/optional_attr/fail_12/main.k new file mode 100644 index 000000000..acb07b863 --- /dev/null +++ b/test/grammar/schema/optional_attr/fail_12/main.k @@ -0,0 +1,14 @@ +schema TeamSpec[id: str]: + fullName: str + name: str = id + shortName: str = name + +schema Team: + d: TeamSpec + +Teams = Team { + d = { + fullName = "charlie" + shortName = "dd" + } +} diff --git a/test/grammar/schema/optional_attr/fail_12/stderr.golden b/test/grammar/schema/optional_attr/fail_12/stderr.golden new file mode 100644 index 000000000..f7d60d17c --- /dev/null +++ b/test/grammar/schema/optional_attr/fail_12/stderr.golden @@ -0,0 +1 @@ +attribute 'name' of TeamSpec is required and can't be None or Undefined \ No newline at end of file diff --git a/test/grammar/schema/optional_attr/fail_13/main.k b/test/grammar/schema/optional_attr/fail_13/main.k new file mode 100644 index 000000000..b7e2564af --- /dev/null +++ b/test/grammar/schema/optional_attr/fail_13/main.k @@ -0,0 +1,11 @@ +schema S: + a: int + b: str + +schema L: + ss?: [S] + sss?: {str:S} + +L { + ss = [S {b = "b"}] +} diff --git a/test/grammar/schema/optional_attr/fail_13/stderr.golden b/test/grammar/schema/optional_attr/fail_13/stderr.golden new file mode 100644 index 000000000..e2f20875a --- /dev/null +++ b/test/grammar/schema/optional_attr/fail_13/stderr.golden @@ -0,0 +1,6 @@ +error[E3M38]: EvaluationError + --> ${CWD}/main.k:10:1 + | +10 | ss = [S {b = "b"}] + | attribute 'a' of S is required and can't be None or Undefined + | \ No newline at end of file diff --git a/test/grammar/schema/optional_attr/fail_14/main.k b/test/grammar/schema/optional_attr/fail_14/main.k new file mode 100644 index 000000000..96fd0f211 --- /dev/null +++ b/test/grammar/schema/optional_attr/fail_14/main.k @@ -0,0 +1,11 @@ +schema S: + a: int + b: str + +schema L: + ss?: [S] + sss?: {str:S} + +L { + sss.aa: S {b = "2"} +} diff --git a/test/grammar/schema/optional_attr/fail_14/stderr.golden b/test/grammar/schema/optional_attr/fail_14/stderr.golden new file mode 100644 index 000000000..e933623d6 --- /dev/null +++ b/test/grammar/schema/optional_attr/fail_14/stderr.golden @@ -0,0 +1,6 @@ +error[E3M38]: EvaluationError + --> ${CWD}/main.k:10:1 + | +10 | sss.aa: S {b = "2"} + | attribute 'a' of S is required and can't be None or Undefined + | \ No newline at end of file diff --git a/test/grammar/schema/optional_attr/fail_15/main.k b/test/grammar/schema/optional_attr/fail_15/main.k new file mode 100644 index 000000000..7d3adbc34 --- /dev/null +++ b/test/grammar/schema/optional_attr/fail_15/main.k @@ -0,0 +1,9 @@ +schema Data: + name: str + type: str + +data = { + name = "data" +} + +datas: [Data] = [data] diff --git a/test/grammar/schema/optional_attr/fail_15/stderr.golden b/test/grammar/schema/optional_attr/fail_15/stderr.golden new file mode 100644 index 000000000..b9dcb1dea --- /dev/null +++ b/test/grammar/schema/optional_attr/fail_15/stderr.golden @@ -0,0 +1,6 @@ +error[E3M38]: EvaluationError + --> ${CWD}/main.k:9:1 + | +9 | datas: [Data] = [data] + | attribute 'type' of Data is required and can't be None or Undefined + | \ No newline at end of file diff --git a/test/grammar/schema/optional_attr/fail_16/main.k b/test/grammar/schema/optional_attr/fail_16/main.k new file mode 100644 index 000000000..eb8bc3dd6 --- /dev/null +++ b/test/grammar/schema/optional_attr/fail_16/main.k @@ -0,0 +1,9 @@ +schema Data: + name: str + type: str + +data = { + name = "data" +} + +datas: [[Data]] = [[data]] diff --git a/test/grammar/schema/optional_attr/fail_16/stderr.golden b/test/grammar/schema/optional_attr/fail_16/stderr.golden new file mode 100644 index 000000000..ab276a6ee --- /dev/null +++ b/test/grammar/schema/optional_attr/fail_16/stderr.golden @@ -0,0 +1,6 @@ +error[E3M38]: EvaluationError + --> ${CWD}/main.k:9:1 + | +9 | datas: [[Data]] = [[data]] + | attribute 'type' of Data is required and can't be None or Undefined + | \ No newline at end of file diff --git a/test/grammar/schema/optional_attr/fail_17/main.k b/test/grammar/schema/optional_attr/fail_17/main.k new file mode 100644 index 000000000..0ed33fb6c --- /dev/null +++ b/test/grammar/schema/optional_attr/fail_17/main.k @@ -0,0 +1,11 @@ +schema Data: + name: str + type: str + +data = { + name = "data" +} + +datas: {str:Data} = { + data = data +} diff --git a/test/grammar/schema/optional_attr/fail_17/stderr.golden b/test/grammar/schema/optional_attr/fail_17/stderr.golden new file mode 100644 index 000000000..1c512e6cb --- /dev/null +++ b/test/grammar/schema/optional_attr/fail_17/stderr.golden @@ -0,0 +1,6 @@ +error[E3M38]: EvaluationError + --> ${CWD}/main.k:10:1 + | +10 | data = data + | attribute 'type' of Data is required and can't be None or Undefined + | \ No newline at end of file diff --git a/test/grammar/schema/optional_attr/fail_18/main.k b/test/grammar/schema/optional_attr/fail_18/main.k new file mode 100644 index 000000000..e8700b21d --- /dev/null +++ b/test/grammar/schema/optional_attr/fail_18/main.k @@ -0,0 +1,11 @@ +schema Data: + name: str + type: str + +data = { + name = "data" +} + +datas: {str:{str:Data}} = { + data.data = data +} diff --git a/test/grammar/schema/optional_attr/fail_18/stderr.golden b/test/grammar/schema/optional_attr/fail_18/stderr.golden new file mode 100644 index 000000000..ceb035af4 --- /dev/null +++ b/test/grammar/schema/optional_attr/fail_18/stderr.golden @@ -0,0 +1,6 @@ +error[E3M38]: EvaluationError + --> ${CWD}/main.k:10:1 + | +10 | data.data = data + | attribute 'type' of Data is required and can't be None or Undefined + | \ No newline at end of file diff --git a/test/grammar/schema/optional_attr/fail_19/main.k b/test/grammar/schema/optional_attr/fail_19/main.k new file mode 100644 index 000000000..dc378c832 --- /dev/null +++ b/test/grammar/schema/optional_attr/fail_19/main.k @@ -0,0 +1,11 @@ +schema Data: + name: str + type: str + +data = { + name = "data" +} + +datas: {str:[Data]} = { + data = [data] +} diff --git a/test/grammar/schema/optional_attr/fail_19/stderr.golden b/test/grammar/schema/optional_attr/fail_19/stderr.golden new file mode 100644 index 000000000..e11b8c82e --- /dev/null +++ b/test/grammar/schema/optional_attr/fail_19/stderr.golden @@ -0,0 +1,6 @@ +error[E3M38]: EvaluationError + --> ${CWD}/main.k:10:1 + | +10 | data = [data] + | attribute 'type' of Data is required and can't be None or Undefined + | \ No newline at end of file diff --git a/test/grammar/schema/optional_attr/fail_2/stderr.golden b/test/grammar/schema/optional_attr/fail_2/stderr.golden new file mode 100644 index 000000000..984319b3a --- /dev/null +++ b/test/grammar/schema/optional_attr/fail_2/stderr.golden @@ -0,0 +1,6 @@ +error[E2G22]: TypeError + --> ${CWD}/main.k:5:5 + | +5 | name?: str + | ^ can't change the required schema attribute of 'name' to optional + | \ No newline at end of file diff --git a/test/grammar/schema/optional_attr/fail_2/stderr.golden.py b/test/grammar/schema/optional_attr/fail_2/stderr.golden.py deleted file mode 100644 index e7a974a57..000000000 --- a/test/grammar/schema/optional_attr/fail_2/stderr.golden.py +++ /dev/null @@ -1,20 +0,0 @@ -import sys -import os - -import kclvm.kcl.error as kcl_error - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception(err_type=kcl_error.ErrType.CompileError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=5, - col_no=5, - ), - ], - arg_msg="can't change the required schema attribute of 'name' to optional") - , file=sys.stdout -) - diff --git a/test/grammar/schema/optional_attr/fail_20/main.k b/test/grammar/schema/optional_attr/fail_20/main.k new file mode 100644 index 000000000..de01e7434 --- /dev/null +++ b/test/grammar/schema/optional_attr/fail_20/main.k @@ -0,0 +1,11 @@ +schema Data: + name: str + type: str + +data = { + name = "data" +} + +datas: [{str:[Data]}] = [{ + data = [data] +}] diff --git a/test/grammar/schema/optional_attr/fail_20/stderr.golden b/test/grammar/schema/optional_attr/fail_20/stderr.golden new file mode 100644 index 000000000..e11b8c82e --- /dev/null +++ b/test/grammar/schema/optional_attr/fail_20/stderr.golden @@ -0,0 +1,6 @@ +error[E3M38]: EvaluationError + --> ${CWD}/main.k:10:1 + | +10 | data = [data] + | attribute 'type' of Data is required and can't be None or Undefined + | \ No newline at end of file diff --git a/test/grammar/schema/optional_attr/fail_21/_main.k b/test/grammar/schema/optional_attr/fail_21/_main.k new file mode 100644 index 000000000..45787d999 --- /dev/null +++ b/test/grammar/schema/optional_attr/fail_21/_main.k @@ -0,0 +1,10 @@ +import regex +pattern = 'xxxx' + +schema Name: + name: str + + check: + regex.match(name, pattern) + +n = Name {} diff --git a/test/grammar/schema/optional_attr/fail_21/stderr.golden b/test/grammar/schema/optional_attr/fail_21/stderr.golden new file mode 100644 index 000000000..ff1928d0f --- /dev/null +++ b/test/grammar/schema/optional_attr/fail_21/stderr.golden @@ -0,0 +1,6 @@ +error[E3M38]: EvaluationError + --> ${CWD}/main.k:10:1 + | +10 | n = Name {} + | attribute 'name' of Name is required and can't be None or Undefined + | \ No newline at end of file diff --git a/test/grammar/schema/optional_attr/fail_3/main.k b/test/grammar/schema/optional_attr/fail_3/main.k new file mode 100644 index 000000000..6a47b4463 --- /dev/null +++ b/test/grammar/schema/optional_attr/fail_3/main.k @@ -0,0 +1,10 @@ +schema App: + data?: [int] + version: Version + +schema Version: + versions: [str] + +app = App { + version = Version {} +} diff --git a/test/grammar/schema/optional_attr/fail_3/stderr.golden b/test/grammar/schema/optional_attr/fail_3/stderr.golden new file mode 100644 index 000000000..9d5b729d4 --- /dev/null +++ b/test/grammar/schema/optional_attr/fail_3/stderr.golden @@ -0,0 +1,6 @@ +error[E3M38]: EvaluationError + --> ${CWD}/main.k:9:1 + | +9 | version = Version {} + | attribute 'versions' of Version is required and can't be None or Undefined + | \ No newline at end of file diff --git a/test/grammar/schema/optional_attr/fail_4/main.k b/test/grammar/schema/optional_attr/fail_4/main.k new file mode 100644 index 000000000..2b6f48cee --- /dev/null +++ b/test/grammar/schema/optional_attr/fail_4/main.k @@ -0,0 +1,4 @@ +schema Values: + a: int + +values: Values = {} diff --git a/test/grammar/schema/optional_attr/fail_4/stderr.golden b/test/grammar/schema/optional_attr/fail_4/stderr.golden new file mode 100644 index 000000000..058aeac8d --- /dev/null +++ b/test/grammar/schema/optional_attr/fail_4/stderr.golden @@ -0,0 +1,6 @@ +error[E3M38]: EvaluationError + --> ${CWD}/main.k:4:1 + | +4 | values: Values = {} + | attribute 'a' of Values is required and can't be None or Undefined + | \ No newline at end of file diff --git a/test/grammar/schema/optional_attr/fail_5/main.k b/test/grammar/schema/optional_attr/fail_5/main.k new file mode 100644 index 000000000..4df53ee8c --- /dev/null +++ b/test/grammar/schema/optional_attr/fail_5/main.k @@ -0,0 +1,4 @@ +schema Values: + a: int + +values: Values = Values {a = 1} | {a = Undefined} diff --git a/test/grammar/schema/optional_attr/fail_5/stderr.golden b/test/grammar/schema/optional_attr/fail_5/stderr.golden new file mode 100644 index 000000000..13d28a5d9 --- /dev/null +++ b/test/grammar/schema/optional_attr/fail_5/stderr.golden @@ -0,0 +1,6 @@ +error[E3M38]: EvaluationError + --> ${CWD}/main.k:4:1 + | +4 | values: Values = Values {a = 1} | {a = Undefined} + | attribute 'a' of Values is required and can't be None or Undefined + | \ No newline at end of file diff --git a/test/grammar/schema/optional_attr/fail_6/main.k b/test/grammar/schema/optional_attr/fail_6/main.k new file mode 100644 index 000000000..c75115b68 --- /dev/null +++ b/test/grammar/schema/optional_attr/fail_6/main.k @@ -0,0 +1,4 @@ +schema Values: + a: int + +values: Values = Values {a = 1} | {a = 2} | {a = None} diff --git a/test/grammar/schema/optional_attr/fail_6/stderr.golden b/test/grammar/schema/optional_attr/fail_6/stderr.golden new file mode 100644 index 000000000..ff292179d --- /dev/null +++ b/test/grammar/schema/optional_attr/fail_6/stderr.golden @@ -0,0 +1,6 @@ +error[E3M38]: EvaluationError + --> ${CWD}/main.k:4:1 + | +4 | values: Values = Values {a = 1} | {a = 2} | {a = None} + | attribute 'a' of Values is required and can't be None or Undefined + | \ No newline at end of file diff --git a/test/grammar/schema/optional_attr/fail_7/main.k b/test/grammar/schema/optional_attr/fail_7/main.k new file mode 100644 index 000000000..19d30e069 --- /dev/null +++ b/test/grammar/schema/optional_attr/fail_7/main.k @@ -0,0 +1,7 @@ +schema Values: + a: int + +schema Data: + values = Values {} + +d = Data {} diff --git a/test/grammar/schema/optional_attr/fail_7/stderr.golden b/test/grammar/schema/optional_attr/fail_7/stderr.golden new file mode 100644 index 000000000..ef55f2e28 --- /dev/null +++ b/test/grammar/schema/optional_attr/fail_7/stderr.golden @@ -0,0 +1,6 @@ +error[E3M38]: EvaluationError + --> ${CWD}/main.k:5:1 + | +5 | values = Values {} + | attribute 'a' of Values is required and can't be None or Undefined + | \ No newline at end of file diff --git a/test/grammar/schema/optional_attr/fail_8/main.k b/test/grammar/schema/optional_attr/fail_8/main.k new file mode 100644 index 000000000..a777e9b2c --- /dev/null +++ b/test/grammar/schema/optional_attr/fail_8/main.k @@ -0,0 +1,16 @@ +schema TeamSpec[id: str]: + fullName: str + name: str = id + shortName: str = name + +schema Team: + [id: str]: TeamSpec = TeamSpec(id) + +Teams = Team { + a.fullName = "alpha" + b.fullName = "bravo" + c = TeamSpec { + fullName = "charlie" + shortName = "cc" + } +} diff --git a/test/grammar/schema/optional_attr/fail_8/stderr.golden b/test/grammar/schema/optional_attr/fail_8/stderr.golden new file mode 100644 index 000000000..fa4f8ad5c --- /dev/null +++ b/test/grammar/schema/optional_attr/fail_8/stderr.golden @@ -0,0 +1,6 @@ +error[E2L23]: CompileError + --> ${CWD}/main.k:12:9 + | +12 | c = TeamSpec { + | ^ expected 1 positional argument, found 0 + | \ No newline at end of file diff --git a/test/grammar/schema/optional_attr/fail_9/main.k b/test/grammar/schema/optional_attr/fail_9/main.k new file mode 100644 index 000000000..3c2639604 --- /dev/null +++ b/test/grammar/schema/optional_attr/fail_9/main.k @@ -0,0 +1,13 @@ +schema TeamSpec[id: str]: + fullName: str + name: str = id + shortName: str = name + +schema Team: + [id: str]: TeamSpec = TeamSpec(id) + +Teams = Team { + a.fullName = "alpha" + b.fullName = "bravo" + c.shortName = "cc" +} diff --git a/test/grammar/schema/optional_attr/fail_9/stderr.golden b/test/grammar/schema/optional_attr/fail_9/stderr.golden new file mode 100644 index 000000000..d87bedd16 --- /dev/null +++ b/test/grammar/schema/optional_attr/fail_9/stderr.golden @@ -0,0 +1 @@ +attribute 'fullName' of TeamSpec is required and can't be None or Undefined \ No newline at end of file diff --git a/test/grammar/schema/optional_attr/inherit_2/main.k b/test/grammar/schema/optional_attr/inherit_2/main.k new file mode 100644 index 000000000..bdfd4c299 --- /dev/null +++ b/test/grammar/schema/optional_attr/inherit_2/main.k @@ -0,0 +1,16 @@ +schema Metadata: + environment: str + region: str + name: str + +schema MySchema1: + metadata: Metadata + +schema MySchema2(MySchema1): + metadata: Metadata {environment = "dev"} + +schema MySchema3(MySchema2): + metadata: Metadata {region = "us-east-1"} + +output = MySchema3 {metadata.name = "hello"} + diff --git a/test/grammar/schema/optional_attr/inherit_2/stdout.golden b/test/grammar/schema/optional_attr/inherit_2/stdout.golden new file mode 100644 index 000000000..5f647f0ee --- /dev/null +++ b/test/grammar/schema/optional_attr/inherit_2/stdout.golden @@ -0,0 +1,5 @@ +output: + metadata: + environment: dev + region: us-east-1 + name: hello diff --git a/test/grammar/schema/optional_attr/inherit_3/main.k b/test/grammar/schema/optional_attr/inherit_3/main.k new file mode 100644 index 000000000..8edc480a2 --- /dev/null +++ b/test/grammar/schema/optional_attr/inherit_3/main.k @@ -0,0 +1,18 @@ +schema Metadata: + environment: str + region: str + name: str + +schema MySchema1: + metadata: Metadata + +schema MySchema2(MySchema1): + metadata: Metadata {environment = "dev"} + +schema MySchema3(MySchema2): + metadata: Metadata {region = "us-east-1"} + +output = MySchema3 { + metadata.name = "hello" + metadata.environment = "qa" +} diff --git a/test/grammar/schema/optional_attr/inherit_3/stdout.golden b/test/grammar/schema/optional_attr/inherit_3/stdout.golden new file mode 100644 index 000000000..c55b51309 --- /dev/null +++ b/test/grammar/schema/optional_attr/inherit_3/stdout.golden @@ -0,0 +1,5 @@ +output: + metadata: + environment: qa + region: us-east-1 + name: hello diff --git a/test/grammar/schema/optional_attr/inherit_4/main.k b/test/grammar/schema/optional_attr/inherit_4/main.k new file mode 100644 index 000000000..04ac1fef2 --- /dev/null +++ b/test/grammar/schema/optional_attr/inherit_4/main.k @@ -0,0 +1,13 @@ +schema Name: + n1: str = "aa" + n2: str + +schema Sub[a: str](Name): + n2 = a + +schema Phase: + a: Sub + +a = lambda { + [[Phase{a = Sub("a")}.a]][0][0] | {} +}() diff --git a/test/grammar/schema/optional_attr/inherit_4/stdout.golden b/test/grammar/schema/optional_attr/inherit_4/stdout.golden new file mode 100644 index 000000000..654f98b45 --- /dev/null +++ b/test/grammar/schema/optional_attr/inherit_4/stdout.golden @@ -0,0 +1,3 @@ +a: + n1: aa + n2: a diff --git a/test/grammar/schema/optional_attr/inherit_5/main.k b/test/grammar/schema/optional_attr/inherit_5/main.k new file mode 100644 index 000000000..e2fcc474e --- /dev/null +++ b/test/grammar/schema/optional_attr/inherit_5/main.k @@ -0,0 +1,16 @@ +schema Name: + n1: str = "aa" + n2: str + +schema Sub[a: str](Name): + n2 = a + +schema Phase: + a: Sub + +schema Schema: + f = lambda { + [[Phase{a = Sub("a")}.a]][0][0] | {} + }() + +a = Schema{} \ No newline at end of file diff --git a/test/grammar/schema/optional_attr/inherit_5/stdout.golden b/test/grammar/schema/optional_attr/inherit_5/stdout.golden new file mode 100644 index 000000000..d90f9ab82 --- /dev/null +++ b/test/grammar/schema/optional_attr/inherit_5/stdout.golden @@ -0,0 +1,4 @@ +a: + f: + n1: aa + n2: a diff --git a/test/grammar/schema/optional_attr/inherit_6/main.k b/test/grammar/schema/optional_attr/inherit_6/main.k new file mode 100644 index 000000000..9f27d96cc --- /dev/null +++ b/test/grammar/schema/optional_attr/inherit_6/main.k @@ -0,0 +1,31 @@ +schema Name: + n1: str = "aa" + n2: str + +schema Sub[a: str](Name): + n2 = a + +schema Phase: + a: Sub + +schema Schema: + f0: () = lambda { + [[Phase{a = Sub("a")}.a]][0][0] + } + f1: () = lambda { + [[Phase{a = Sub("a")}.a]][0][0] | {} + } + f2: () = lambda { + s = [[Phase{a = Sub("a")}.a]][0][0] + s | {} + } + ff: () -> () = lambda { + lambda { + [[Phase{a = Sub("a")}.a]][0] | [{}] + } + } + +a = Schema().f0() +b = Schema().f1() +c = Schema().f2() +d = Schema().ff()() diff --git a/test/grammar/schema/optional_attr/inherit_6/stdout.golden b/test/grammar/schema/optional_attr/inherit_6/stdout.golden new file mode 100644 index 000000000..eaba9f398 --- /dev/null +++ b/test/grammar/schema/optional_attr/inherit_6/stdout.golden @@ -0,0 +1,12 @@ +a: + n1: aa + n2: a +b: + n1: aa + n2: a +c: + n1: aa + n2: a +d: +- n1: aa + n2: a diff --git a/test/grammar/schema/optional_attr/inherit_7/main.k b/test/grammar/schema/optional_attr/inherit_7/main.k new file mode 100644 index 000000000..0c53d54a8 --- /dev/null +++ b/test/grammar/schema/optional_attr/inherit_7/main.k @@ -0,0 +1,31 @@ +schema Name: + n1: str = "aa" + n2: str + +schema Sub[a: str](Name): + n2: str = a + +schema Phase: + a: Sub + +schema Schema: + f0: () = lambda { + [[Phase{a = Sub("a")}.a]][0][0] + } + f1: () = lambda { + [[Phase{a = Sub("a")}.a]][0][0] | {} + } + f2: () = lambda { + s = [[Phase{a = Sub("a")}.a]][0][0] + s | {} + } + ff: () -> () = lambda { + lambda { + [[Phase{a = Sub("a")}.a]][0] | [{}] + } + } + +a = Schema().f0() +b = Schema().f1() +c = Schema().f2() +d = Schema().ff()() diff --git a/test/grammar/schema/optional_attr/inherit_7/stdout.golden b/test/grammar/schema/optional_attr/inherit_7/stdout.golden new file mode 100644 index 000000000..eaba9f398 --- /dev/null +++ b/test/grammar/schema/optional_attr/inherit_7/stdout.golden @@ -0,0 +1,12 @@ +a: + n1: aa + n2: a +b: + n1: aa + n2: a +c: + n1: aa + n2: a +d: +- n1: aa + n2: a diff --git a/test/grammar/schema/partial_eval/partial_eval_0/main.k b/test/grammar/schema/partial_eval/partial_eval_0/main.k new file mode 100644 index 000000000..dbcff243c --- /dev/null +++ b/test/grammar/schema/partial_eval/partial_eval_0/main.k @@ -0,0 +1,13 @@ +schema Spec: + id: int + value: str + +schema Config: + name?: str + spec: Spec = Spec { + id = 1 + } + +config = Config { + spec.value = "value" +} diff --git a/test/grammar/schema/partial_eval/partial_eval_0/stdout.golden b/test/grammar/schema/partial_eval/partial_eval_0/stdout.golden new file mode 100644 index 000000000..b825438cd --- /dev/null +++ b/test/grammar/schema/partial_eval/partial_eval_0/stdout.golden @@ -0,0 +1,4 @@ +config: + spec: + id: 1 + value: value diff --git a/test/grammar/schema/partial_eval/partial_eval_1/main.k b/test/grammar/schema/partial_eval/partial_eval_1/main.k new file mode 100644 index 000000000..beda8c306 --- /dev/null +++ b/test/grammar/schema/partial_eval/partial_eval_1/main.k @@ -0,0 +1,13 @@ +schema Spec: + id: int + value: str + +schema Config: + name?: str + spec: Spec { + id = 1 + } + +config = Config { + spec.value = "value" +} diff --git a/test/grammar/schema/partial_eval/partial_eval_1/stdout.golden b/test/grammar/schema/partial_eval/partial_eval_1/stdout.golden new file mode 100644 index 000000000..b825438cd --- /dev/null +++ b/test/grammar/schema/partial_eval/partial_eval_1/stdout.golden @@ -0,0 +1,4 @@ +config: + spec: + id: 1 + value: value diff --git a/test/grammar/schema/partial_eval/partial_eval_2/main.k b/test/grammar/schema/partial_eval/partial_eval_2/main.k new file mode 100644 index 000000000..85fdaecd0 --- /dev/null +++ b/test/grammar/schema/partial_eval/partial_eval_2/main.k @@ -0,0 +1,15 @@ +schema Spec: + id: int + value: str + +schema Config: + spec: Spec = Spec { + id = 1 + } + +schema App: + config: Config + +app = App { + config.spec.value = "value" +} diff --git a/test/grammar/schema/partial_eval/partial_eval_2/stdout.golden b/test/grammar/schema/partial_eval/partial_eval_2/stdout.golden new file mode 100644 index 000000000..29a9be61d --- /dev/null +++ b/test/grammar/schema/partial_eval/partial_eval_2/stdout.golden @@ -0,0 +1,5 @@ +app: + config: + spec: + id: 1 + value: value diff --git a/test/grammar/schema/partial_eval/partial_eval_3/main.k b/test/grammar/schema/partial_eval/partial_eval_3/main.k new file mode 100644 index 000000000..9ae054c98 --- /dev/null +++ b/test/grammar/schema/partial_eval/partial_eval_3/main.k @@ -0,0 +1,17 @@ +schema Spec: + data: int + id: int + +mixin AMixin: + spec: Spec { + id = 1 + } + +schema A: + mixin [AMixin] + + spec: Spec { + data = 1 + } + +a = A() diff --git a/test/grammar/schema/partial_eval/partial_eval_3/stdout.golden b/test/grammar/schema/partial_eval/partial_eval_3/stdout.golden new file mode 100644 index 000000000..488f97530 --- /dev/null +++ b/test/grammar/schema/partial_eval/partial_eval_3/stdout.golden @@ -0,0 +1,4 @@ +a: + spec: + data: 1 + id: 1 diff --git a/test/grammar/schema/partial_eval/partial_eval_4/main.k b/test/grammar/schema/partial_eval/partial_eval_4/main.k new file mode 100644 index 000000000..62200a719 --- /dev/null +++ b/test/grammar/schema/partial_eval/partial_eval_4/main.k @@ -0,0 +1,19 @@ +schema EmptyDir: + medium: "" | "Memory" + sizeLimit?: str + +schema Config: + config: {str:} = { + volumes = [ + { + name = "kubeconfig" + volumeSource = EmptyDir {medium = ""} + } + { + name = "log-storage" + volumeSource = EmptyDir {medium = "Memory"} + } + ] + } + +config = Config {} diff --git a/test/grammar/schema/partial_eval/partial_eval_4/stdout.golden b/test/grammar/schema/partial_eval/partial_eval_4/stdout.golden new file mode 100644 index 000000000..163c415cf --- /dev/null +++ b/test/grammar/schema/partial_eval/partial_eval_4/stdout.golden @@ -0,0 +1,9 @@ +config: + config: + volumes: + - name: kubeconfig + volumeSource: + medium: '' + - name: log-storage + volumeSource: + medium: Memory diff --git a/test/grammar/schema/partial_eval/partial_eval_5/_main.k b/test/grammar/schema/partial_eval/partial_eval_5/_main.k new file mode 100644 index 000000000..a8bf7f3b8 --- /dev/null +++ b/test/grammar/schema/partial_eval/partial_eval_5/_main.k @@ -0,0 +1,35 @@ +schema EmptyDir: + medium: "" | "Memory" + sizeLimit?: str + +schema Config: + config: {str:} = { + volumes = [ + { + name = "kubeconfig" + volumeSource = EmptyDir {medium = ""} + } + { + name = "log-storage" + volumeSource = EmptyDir {medium = "Memory"} + } + ] + } + + workload: {str:} = { + spec = { + template = { + spec = { + if config.volumes: volumes = [ + (lambda volume { + { + name = volume.name + } + })(v) for v in config.volumes if v.volumeSource + ] + } + } + } + } + +config = Config {} diff --git a/test/grammar/schema/partial_eval/partial_eval_5/stdout.golden b/test/grammar/schema/partial_eval/partial_eval_5/stdout.golden new file mode 100644 index 000000000..be90b284f --- /dev/null +++ b/test/grammar/schema/partial_eval/partial_eval_5/stdout.golden @@ -0,0 +1,16 @@ +config: + config: + volumes: + - name: kubeconfig + volumeSource: + medium: '' + - name: log-storage + volumeSource: + medium: Memory + workload: + spec: + template: + spec: + volumes: + - name: kubeconfig + - name: log-storage diff --git a/test/grammar/schema/partial_eval/partial_eval_6/main.k b/test/grammar/schema/partial_eval/partial_eval_6/main.k new file mode 100644 index 000000000..7a859df6f --- /dev/null +++ b/test/grammar/schema/partial_eval/partial_eval_6/main.k @@ -0,0 +1,13 @@ +schema TeamSpec: + fullName?: str + name?: str + shortName?: str = name + +schema TeamMap: + a: TeamSpec = TeamSpec { + name = "a" + } + +teamMap = TeamMap { + a.fullName = "alpha" +} diff --git a/test/grammar/schema/partial_eval/partial_eval_6/stdout.golden b/test/grammar/schema/partial_eval/partial_eval_6/stdout.golden new file mode 100644 index 000000000..7901d5282 --- /dev/null +++ b/test/grammar/schema/partial_eval/partial_eval_6/stdout.golden @@ -0,0 +1,5 @@ +teamMap: + a: + fullName: alpha + name: a + shortName: a diff --git a/test/grammar/schema/partial_eval/partial_eval_7/main.k b/test/grammar/schema/partial_eval/partial_eval_7/main.k new file mode 100644 index 000000000..f0d5db07c --- /dev/null +++ b/test/grammar/schema/partial_eval/partial_eval_7/main.k @@ -0,0 +1,13 @@ +schema TeamSpec: + fullName?: str + name?: str = Undefined + shortName?: str = name + +schema TeamMap: + a: TeamSpec = TeamSpec { + name = "a" + } + +teamMap = TeamMap { + a.fullName = "alpha" +} diff --git a/test/grammar/schema/partial_eval/partial_eval_7/stdout.golden b/test/grammar/schema/partial_eval/partial_eval_7/stdout.golden new file mode 100644 index 000000000..7901d5282 --- /dev/null +++ b/test/grammar/schema/partial_eval/partial_eval_7/stdout.golden @@ -0,0 +1,5 @@ +teamMap: + a: + fullName: alpha + name: a + shortName: a diff --git a/test/grammar/schema/partial_eval/partial_eval_8/main.k b/test/grammar/schema/partial_eval/partial_eval_8/main.k new file mode 100644 index 000000000..4ec7b3f57 --- /dev/null +++ b/test/grammar/schema/partial_eval/partial_eval_8/main.k @@ -0,0 +1,13 @@ +schema TeamSpec: + fullName?: str + name?: str = None + shortName?: str = name + +schema TeamMap: + a: TeamSpec = TeamSpec { + name = "a" + } + +teamMap = TeamMap { + a.fullName = "alpha" +} diff --git a/test/grammar/schema/partial_eval/partial_eval_8/stdout.golden b/test/grammar/schema/partial_eval/partial_eval_8/stdout.golden new file mode 100644 index 000000000..7901d5282 --- /dev/null +++ b/test/grammar/schema/partial_eval/partial_eval_8/stdout.golden @@ -0,0 +1,5 @@ +teamMap: + a: + fullName: alpha + name: a + shortName: a diff --git a/test/grammar/schema/partial_eval/partial_eval_fail_0/main.k b/test/grammar/schema/partial_eval/partial_eval_fail_0/main.k new file mode 100644 index 000000000..980c55077 --- /dev/null +++ b/test/grammar/schema/partial_eval/partial_eval_fail_0/main.k @@ -0,0 +1,13 @@ +schema Spec: + id: int + value: str + +schema Config: + name: str + spec: Spec = Spec { + id = 1 + } + +config = Config { + spec.value = "value" +} diff --git a/test/grammar/schema/partial_eval/partial_eval_fail_0/stderr.golden b/test/grammar/schema/partial_eval/partial_eval_fail_0/stderr.golden new file mode 100644 index 000000000..6c30bcdaf --- /dev/null +++ b/test/grammar/schema/partial_eval/partial_eval_fail_0/stderr.golden @@ -0,0 +1,6 @@ +error[E3M38]: EvaluationError + --> ${CWD}/main.k:11:1 + | +11 | config = Config { + | attribute 'name' of Config is required and can't be None or Undefined + | \ No newline at end of file diff --git a/test/grammar/schema/partial_eval/partial_eval_fail_1/main.k b/test/grammar/schema/partial_eval/partial_eval_fail_1/main.k new file mode 100644 index 000000000..5a1f6dff2 --- /dev/null +++ b/test/grammar/schema/partial_eval/partial_eval_fail_1/main.k @@ -0,0 +1,11 @@ +schema Spec: + id: int + value: str + +schema Config: + name?: str + spec: Spec = Spec { + id = 1 + } + +config = Config {} diff --git a/test/grammar/schema/partial_eval/partial_eval_fail_1/stderr.golden b/test/grammar/schema/partial_eval/partial_eval_fail_1/stderr.golden new file mode 100644 index 000000000..ef4af60ca --- /dev/null +++ b/test/grammar/schema/partial_eval/partial_eval_fail_1/stderr.golden @@ -0,0 +1,6 @@ +error[E3M38]: EvaluationError + --> ${CWD}/main.k:7:1 + | +7 | spec: Spec = Spec { + | attribute 'value' of Spec is required and can't be None or Undefined + | \ No newline at end of file diff --git a/test/grammar/schema/partial_eval/partial_eval_fail_2/main.k b/test/grammar/schema/partial_eval/partial_eval_fail_2/main.k new file mode 100644 index 000000000..24a3f426f --- /dev/null +++ b/test/grammar/schema/partial_eval/partial_eval_fail_2/main.k @@ -0,0 +1,17 @@ +schema Spec: + data: int + id: int + +mixin AMixin: + spec: Spec = { + id = 1 + } + +schema A: + mixin [AMixin] + + spec: Spec = { + data = 1 + } + +a = A() diff --git a/test/grammar/schema/partial_eval/partial_eval_fail_2/stderr.golden b/test/grammar/schema/partial_eval/partial_eval_fail_2/stderr.golden new file mode 100644 index 000000000..91ac98670 --- /dev/null +++ b/test/grammar/schema/partial_eval/partial_eval_fail_2/stderr.golden @@ -0,0 +1,6 @@ +error[E3M38]: EvaluationError + --> ${CWD}/main.k:7:1 + | +7 | id = 1 + | attribute 'data' of Spec is required and can't be None or Undefined + | \ No newline at end of file diff --git a/test/grammar/schema/relaxed/fail_0/_main.k b/test/grammar/schema/relaxed/fail_0/_main.k new file mode 100644 index 000000000..fa23ed300 --- /dev/null +++ b/test/grammar/schema/relaxed/fail_0/_main.k @@ -0,0 +1,17 @@ +values = { + res.cpu = 2 + res.no_such_attr = 2 +} + +schema Config: + res: Res + +schema Res: + cpu: int + +c: Config { + res: values.res + res: Res { + cpu = 1 + } +} diff --git a/test/grammar/schema/relaxed/fail_0/stderr.golden b/test/grammar/schema/relaxed/fail_0/stderr.golden new file mode 100644 index 000000000..e69de29bb diff --git a/test/grammar/schema/relaxed/fail_1/_main.k b/test/grammar/schema/relaxed/fail_1/_main.k new file mode 100644 index 000000000..9a29e0492 --- /dev/null +++ b/test/grammar/schema/relaxed/fail_1/_main.k @@ -0,0 +1,17 @@ +values = { + res.cpu = 2 + res.no_such_attr = 2 +} + +schema Config: + res: Res + +schema Res: + cpu: int + +c: Config { + res: Res { + cpu = 1 + } + res: values.res +} diff --git a/test/grammar/schema/relaxed/fail_1/stderr.golden b/test/grammar/schema/relaxed/fail_1/stderr.golden new file mode 100644 index 000000000..e69de29bb diff --git a/test/grammar/schema/rule/fail/main.k b/test/grammar/schema/rule/fail/main.k new file mode 100644 index 000000000..b5d6a4601 --- /dev/null +++ b/test/grammar/schema/rule/fail/main.k @@ -0,0 +1,18 @@ +protocol KubeResourceProtocol: + svc: Service + + +schema Service: + name: str + +rule ServiceCheckRule for KubeResourceProtocol: + svc.name != "123" + + +svc = Service { + name: "123" +} + +ServiceCheckRule { + svc: svc +} \ No newline at end of file diff --git a/test/grammar/schema/rule/fail/stderr.golden b/test/grammar/schema/rule/fail/stderr.golden new file mode 100644 index 000000000..105801d35 --- /dev/null +++ b/test/grammar/schema/rule/fail/stderr.golden @@ -0,0 +1,11 @@ +error[E3M38]: EvaluationError + --> ${CWD}/main.k:16:1 + | +16 | ServiceCheckRule { + | ^ Instance check failed + | + --> ${CWD}/main.k:9:1 + | +9 | svc.name != "123" + | Check failed on the condition + | \ No newline at end of file diff --git a/test/grammar/schema/rule/rule_with_index_signature/main.k b/test/grammar/schema/rule/rule_with_index_signature/main.k new file mode 100644 index 000000000..3b7031802 --- /dev/null +++ b/test/grammar/schema/rule/rule_with_index_signature/main.k @@ -0,0 +1,17 @@ +protocol XProtocol: + [...str]: str + alice: str + +rule XRule for XProtocol: + alice == "Alice", "expected Alice, got ${alice}" + bob == "Bob", "expected Bob, got ${bob}" + +p = XProtocol { + alice = "Alice" + bob = "Bob" +} + +x = XRule { + alice = "Alice" + bob = "Bob" +} diff --git a/test/grammar/schema/rule/rule_with_index_signature/stdout.golden b/test/grammar/schema/rule/rule_with_index_signature/stdout.golden new file mode 100644 index 000000000..7ea472fb1 --- /dev/null +++ b/test/grammar/schema/rule/rule_with_index_signature/stdout.golden @@ -0,0 +1,6 @@ +p: + alice: Alice + bob: Bob +x: + alice: Alice + bob: Bob diff --git a/test/grammar/schema/rule/simple/main.k b/test/grammar/schema/rule/simple/main.k new file mode 100644 index 000000000..4c1530d92 --- /dev/null +++ b/test/grammar/schema/rule/simple/main.k @@ -0,0 +1,18 @@ +protocol KubeResourceProtocol: + svc: Service + + +schema Service: + name: str + +rule ServiceCheckRule for KubeResourceProtocol: + svc.name == "123" + + +svc = Service { + name: "123" +} + +ServiceCheckRule { + svc: svc +} \ No newline at end of file diff --git a/test/grammar/schema/rule/simple/stdout.golden b/test/grammar/schema/rule/simple/stdout.golden new file mode 100644 index 000000000..a617f2d37 --- /dev/null +++ b/test/grammar/schema/rule/simple/stdout.golden @@ -0,0 +1,2 @@ +svc: + name: '123' \ No newline at end of file diff --git a/test/grammar/schema/same_name_fail/stderr.golden b/test/grammar/schema/same_name_fail/stderr.golden new file mode 100644 index 000000000..72770a817 --- /dev/null +++ b/test/grammar/schema/same_name_fail/stderr.golden @@ -0,0 +1,23 @@ +error[E2L28]: UniqueKeyError + --> ${CWD}/main.k:5:1 + | +5 | schema Person: + | ^ Unique key error name 'Person' + | +error[E2L28]: UniqueKeyError + --> ${CWD}/main.k:5:8 + | +5 | schema Person: + | ^ Unique key error name 'Person' + | + --> ${CWD}/main.k:1:8 + | +1 | schema Person: + | ^ The variable 'Person' is declared here + | +error[E2L23]: CompileError + --> ${CWD}/main.k:9:13 + | +9 | x1 = Person{age:101} + | ^ Cannot add member 'age' to schema 'Person' + | \ No newline at end of file diff --git a/test/grammar/schema/same_name_fail/stderr.golden.py b/test/grammar/schema/same_name_fail/stderr.golden.py deleted file mode 100644 index ece44c526..000000000 --- a/test/grammar/schema/same_name_fail/stderr.golden.py +++ /dev/null @@ -1,21 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.UniqueKeyError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=5, - col_no=1 - ) - ], - arg_msg=kcl_error.UNIQUE_KEY_MSG.format("Person") - ), - file=sys.stdout -) - diff --git a/test/grammar/schema/stmt_block/stmt_block_0/main.k b/test/grammar/schema/stmt_block/stmt_block_0/main.k index 5ebd90ef7..884f13d98 100644 --- a/test/grammar/schema/stmt_block/stmt_block_0/main.k +++ b/test/grammar/schema/stmt_block/stmt_block_0/main.k @@ -1,13 +1,14 @@ schema Person: firstName: str = "John" lastName: str - name: str = _name if len(lastName) > 0: _name = firstName + " " + lastName else: _name = firstName + name: str = _name + JohnDoe = Person { "lastName": "Doe" } diff --git a/test/grammar/schema/stmt_block/stmt_block_32/main.k b/test/grammar/schema/stmt_block/stmt_block_32/main.k index ebf2ea3c5..a0636b3d3 100644 --- a/test/grammar/schema/stmt_block/stmt_block_32/main.k +++ b/test/grammar/schema/stmt_block/stmt_block_32/main.k @@ -5,13 +5,12 @@ _alice = A { } } -_alice.name |= {last: "value"} _alice.name.age = _alice.name.age + 1 _alice.name.age += 1 alice = _alice schema Name: - first: str + first?: str last?: str age?: int diff --git a/test/grammar/schema/stmt_block/stmt_block_32/stdout.golden b/test/grammar/schema/stmt_block/stmt_block_32/stdout.golden index f7684a0e7..bd9dd3d65 100644 --- a/test/grammar/schema/stmt_block/stmt_block_32/stdout.golden +++ b/test/grammar/schema/stmt_block/stmt_block_32/stdout.golden @@ -1,5 +1,4 @@ alice: name: first: aa - last: value age: 3 diff --git a/test/grammar/schema/stmt_block/stmt_block_33/main.k b/test/grammar/schema/stmt_block/stmt_block_33/main.k index f753a9d88..06c7f05eb 100644 --- a/test/grammar/schema/stmt_block/stmt_block_33/main.k +++ b/test/grammar/schema/stmt_block/stmt_block_33/main.k @@ -14,7 +14,6 @@ schema Data: } } - _alice.name |= {last: "value"} _alice.name.age += 1 alice = _alice diff --git a/test/grammar/schema/stmt_block/stmt_block_33/stdout.golden b/test/grammar/schema/stmt_block/stmt_block_33/stdout.golden index ebf4c39f8..45605e19f 100644 --- a/test/grammar/schema/stmt_block/stmt_block_33/stdout.golden +++ b/test/grammar/schema/stmt_block/stmt_block_33/stdout.golden @@ -2,5 +2,4 @@ data: alice: name: first: aa - last: value age: 2 diff --git a/test/grammar/schema/stmt_block/stmt_block_7/main.k b/test/grammar/schema/stmt_block/stmt_block_7/main.k index 17865e476..afde0909b 100644 --- a/test/grammar/schema/stmt_block/stmt_block_7/main.k +++ b/test/grammar/schema/stmt_block/stmt_block_7/main.k @@ -1,15 +1,15 @@ schema Person: firstName: str = "John" lastName: str = "Doe" - headcount: [int] + headcount: [int] = [] keyValue: {str:} - headcount |= [1, 2, 3] + headcount += [1, 2, 3] headcount += [4, 5, 6] - keyValue |= {"key1": "value1"} _keyValue = {"key2": "value2"} keyValue = { + **{"key1": "value1"} **keyValue, **_keyValue } diff --git a/test/grammar/schema/stmt_block/stmt_block_7/stdout.golden b/test/grammar/schema/stmt_block/stmt_block_7/stdout.golden index 88b27a675..76519ff44 100644 --- a/test/grammar/schema/stmt_block/stmt_block_7/stdout.golden +++ b/test/grammar/schema/stmt_block/stmt_block_7/stdout.golden @@ -10,4 +10,4 @@ JohnDoe: - 6 keyValue: key1: value1 - key2: value2 \ No newline at end of file + key2: value2 diff --git a/test/grammar/schema/stmt_block/stmt_block_cycle_fail_0/stderr.golden b/test/grammar/schema/stmt_block/stmt_block_cycle_fail_0/stderr.golden new file mode 100644 index 000000000..f8a3ae951 --- /dev/null +++ b/test/grammar/schema/stmt_block/stmt_block_cycle_fail_0/stderr.golden @@ -0,0 +1 @@ +maximum recursion depth exceeded in comparison diff --git a/test/grammar/schema/stmt_block/stmt_block_cycle_fail_0/stderr.golden.py b/test/grammar/schema/stmt_block/stmt_block_cycle_fail_0/stderr.golden.py deleted file mode 100644 index 5ee369e26..000000000 --- a/test/grammar/schema/stmt_block/stmt_block_cycle_fail_0/stderr.golden.py +++ /dev/null @@ -1,19 +0,0 @@ - -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception(err_type=kcl_error.ErrType.RecursionError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=6, - ), - ], - arg_msg="maximum recursion depth exceeded in comparison") - , file=sys.stdout -) - diff --git a/test/grammar/schema/stmt_block/stmt_block_cycle_fail_1/stderr.golden b/test/grammar/schema/stmt_block/stmt_block_cycle_fail_1/stderr.golden new file mode 100644 index 000000000..f8a3ae951 --- /dev/null +++ b/test/grammar/schema/stmt_block/stmt_block_cycle_fail_1/stderr.golden @@ -0,0 +1 @@ +maximum recursion depth exceeded in comparison diff --git a/test/grammar/schema/stmt_block/stmt_block_cycle_fail_1/stderr.golden.py b/test/grammar/schema/stmt_block/stmt_block_cycle_fail_1/stderr.golden.py deleted file mode 100644 index a28a83371..000000000 --- a/test/grammar/schema/stmt_block/stmt_block_cycle_fail_1/stderr.golden.py +++ /dev/null @@ -1,19 +0,0 @@ - -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception(err_type=kcl_error.ErrType.RecursionError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=2, - ), - ], - arg_msg="maximum recursion depth exceeded in comparison") - , file=sys.stdout -) - diff --git a/test/grammar/schema/stmt_block/stmt_block_fail_0/stderr.golden b/test/grammar/schema/stmt_block/stmt_block_fail_0/stderr.golden new file mode 100644 index 000000000..714b24834 --- /dev/null +++ b/test/grammar/schema/stmt_block/stmt_block_fail_0/stderr.golden @@ -0,0 +1,6 @@ +error[E2G22]: TypeError + --> ${CWD}/main.k:7:5 + | +7 | name = _name + | ^ expected str, got int + | \ No newline at end of file diff --git a/test/grammar/schema/stmt_block/stmt_block_fail_0/stderr.golden.py b/test/grammar/schema/stmt_block/stmt_block_fail_0/stderr.golden.py deleted file mode 100644 index 92cc27027..000000000 --- a/test/grammar/schema/stmt_block/stmt_block_fail_0/stderr.golden.py +++ /dev/null @@ -1,21 +0,0 @@ - -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception(err_type=kcl_error.ErrType.TypeError_Compile_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=7, - col_no=5, - arg_msg="got int" - ), - ], - arg_msg='expect str, got int') - , file=sys.stdout -) - diff --git a/test/grammar/schema/stmt_block/stmt_block_fail_1/stderr.golden b/test/grammar/schema/stmt_block/stmt_block_fail_1/stderr.golden new file mode 100644 index 000000000..6d4e80b56 --- /dev/null +++ b/test/grammar/schema/stmt_block/stmt_block_fail_1/stderr.golden @@ -0,0 +1,6 @@ +error[E3M38]: EvaluationError + --> ${CWD}/main.k:6:1 + | +6 | JohnDoe = Person { + | attribute 'name' of Person is required and can't be None or Undefined + | \ No newline at end of file diff --git a/test/grammar/schema/stmt_block/stmt_block_fail_1/stderr.golden.py b/test/grammar/schema/stmt_block/stmt_block_fail_1/stderr.golden.py deleted file mode 100644 index 347394ed5..000000000 --- a/test/grammar/schema/stmt_block/stmt_block_fail_1/stderr.golden.py +++ /dev/null @@ -1,19 +0,0 @@ - -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception(err_type=kcl_error.ErrType.EvaluationError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=6, - ), - ], - arg_msg="attribute 'name' of Person is required and can't be None or Undefined") - , file=sys.stdout -) - diff --git a/test/grammar/schema/stmt_block/stmt_block_fail_2/stderr.golden b/test/grammar/schema/stmt_block/stmt_block_fail_2/stderr.golden new file mode 100644 index 000000000..f4c08ee31 --- /dev/null +++ b/test/grammar/schema/stmt_block/stmt_block_fail_2/stderr.golden @@ -0,0 +1,6 @@ +error[E3M38]: EvaluationError + --> ${CWD}/main.k:7:1 + | +7 | if sonName + "123" == "123": + | unsupported operand type(s) for +: 'NoneType' and 'str' + | \ No newline at end of file diff --git a/test/grammar/schema/stmt_block/stmt_block_fail_2/stderr.golden.py b/test/grammar/schema/stmt_block/stmt_block_fail_2/stderr.golden.py deleted file mode 100644 index 68f167c86..000000000 --- a/test/grammar/schema/stmt_block/stmt_block_fail_2/stderr.golden.py +++ /dev/null @@ -1,18 +0,0 @@ - -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception(err_type=kcl_error.ErrType.EvaluationError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=7, - ), - ], - arg_msg='unsupported operand type(s) for +: \'NoneType\' and \'str\'') - , file=sys.stdout -) diff --git a/test/grammar/schema/stmt_block/stmt_block_fail_3/stderr.golden b/test/grammar/schema/stmt_block/stmt_block_fail_3/stderr.golden new file mode 100644 index 000000000..7cb916b40 --- /dev/null +++ b/test/grammar/schema/stmt_block/stmt_block_fail_3/stderr.golden @@ -0,0 +1,6 @@ +error[E3M38]: EvaluationError + --> ${CWD}/main.k:7:1 + | +7 | assert False, "assert in schema" + | assert in schema + | \ No newline at end of file diff --git a/test/grammar/schema/stmt_block/stmt_block_fail_3/stderr.golden.py b/test/grammar/schema/stmt_block/stmt_block_fail_3/stderr.golden.py deleted file mode 100644 index c9202e8f0..000000000 --- a/test/grammar/schema/stmt_block/stmt_block_fail_3/stderr.golden.py +++ /dev/null @@ -1,19 +0,0 @@ - -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception(err_type=kcl_error.ErrType.AssertionError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=7, - ), - ], - arg_msg='assert in schema') - , file=sys.stdout -) - diff --git a/test/grammar/schema/str_attr/str_attr_0/main.k b/test/grammar/schema/str_attr/str_attr_0/main.k new file mode 100644 index 000000000..a14982d6b --- /dev/null +++ b/test/grammar/schema/str_attr/str_attr_0/main.k @@ -0,0 +1,23 @@ +schema Data: + "spec": Spec + +schema Spec: + "config": Config + +schema Config: + "template": Template + +schema Template: + [...str]: int + "name": str + +data = Data { + spec: { + config: { + template: { + name: "template" + id: 1 + } + } + } +} diff --git a/test/grammar/schema/str_attr/str_attr_0/stdout.golden b/test/grammar/schema/str_attr/str_attr_0/stdout.golden new file mode 100644 index 000000000..373d3582f --- /dev/null +++ b/test/grammar/schema/str_attr/str_attr_0/stdout.golden @@ -0,0 +1,6 @@ +data: + spec: + config: + template: + name: template + id: 1 diff --git a/test/grammar/schema/str_attr/str_attr_1/main.k b/test/grammar/schema/str_attr/str_attr_1/main.k new file mode 100644 index 000000000..14aa70d8f --- /dev/null +++ b/test/grammar/schema/str_attr/str_attr_1/main.k @@ -0,0 +1,22 @@ +schema Data: + "spec": Spec + +schema Spec: + "config": Config + +schema Config: + "template": Template + +schema Template: + "name": str + +data = Data { + spec: { + config: { + template: { + name: "template" + } + } + } +} +name = data["spec"]["config"]["template"].name diff --git a/test/grammar/schema/str_attr/str_attr_1/stdout.golden b/test/grammar/schema/str_attr/str_attr_1/stdout.golden new file mode 100644 index 000000000..d4216f94e --- /dev/null +++ b/test/grammar/schema/str_attr/str_attr_1/stdout.golden @@ -0,0 +1,6 @@ +data: + spec: + config: + template: + name: template +name: template diff --git a/test/grammar/schema/string_attr/simple_0/main.k b/test/grammar/schema/string_attr/simple_0/main.k new file mode 100644 index 000000000..52e65b4cc --- /dev/null +++ b/test/grammar/schema/string_attr/simple_0/main.k @@ -0,0 +1,6 @@ +schema Data: + "$attr": str + +Data { + "$attr": "value" +} diff --git a/test/grammar/schema/string_attr/simple_0/stdout.golden b/test/grammar/schema/string_attr/simple_0/stdout.golden new file mode 100644 index 000000000..aed4eddb3 --- /dev/null +++ b/test/grammar/schema/string_attr/simple_0/stdout.golden @@ -0,0 +1 @@ +$attr: value diff --git a/test/grammar/schema/string_attr/simple_1/main.k b/test/grammar/schema/string_attr/simple_1/main.k new file mode 100644 index 000000000..167e9d458 --- /dev/null +++ b/test/grammar/schema/string_attr/simple_1/main.k @@ -0,0 +1,6 @@ +schema Data: + "a.b": str + +Data { + "a.b": "value" +} diff --git a/test/grammar/schema/string_attr/simple_1/stdout.golden b/test/grammar/schema/string_attr/simple_1/stdout.golden new file mode 100644 index 000000000..d9d01da4d --- /dev/null +++ b/test/grammar/schema/string_attr/simple_1/stdout.golden @@ -0,0 +1 @@ +a.b: value diff --git a/test/grammar/schema/type/combination_4/main.k b/test/grammar/schema/type/combination_4/main.k index a0ac2de69..506d86054 100644 --- a/test/grammar/schema/type/combination_4/main.k +++ b/test/grammar/schema/type/combination_4/main.k @@ -20,9 +20,6 @@ schema Rule: kind: str = "Rule" access: [str] entity: Person - __settings__: {str:} = { - "output_type": "STANDALONE" - } schema Model: mixin [RuleMixin] diff --git a/test/grammar/schema/type/combination_4/stdout.golden b/test/grammar/schema/type/combination_4/stdout.golden index 8a6f91af1..1cbedfe0a 100644 --- a/test/grammar/schema/type/combination_4/stdout.golden +++ b/test/grammar/schema/type/combination_4/stdout.golden @@ -7,13 +7,13 @@ alice: access: - read - write ---- -kind: Rule -access: -- read -- write -entity: - name: alice - relatives: - - relation: father - name: Reese \ No newline at end of file + ruleModel: + kind: Rule + access: + - read + - write + entity: + name: alice + relatives: + - relation: father + name: Reese diff --git a/test/grammar/schema/type/combination_5_type_fail/stderr.golden b/test/grammar/schema/type/combination_5_type_fail/stderr.golden new file mode 100644 index 000000000..e711352ab --- /dev/null +++ b/test/grammar/schema/type/combination_5_type_fail/stderr.golden @@ -0,0 +1,11 @@ +error[E2G22]: TypeError + --> ${CWD}/main.k:26:17 + | +26 | "firstName": "Alice", + | ^ expected int, got str(Alice) + | + --> ${CWD}/main.k:2:5 + | +2 | firstName: int + | ^ variable is defined here, its type is int, but got str(Alice) + | \ No newline at end of file diff --git a/test/grammar/schema/type/combination_5_type_fail/stderr.golden.py b/test/grammar/schema/type/combination_5_type_fail/stderr.golden.py deleted file mode 100644 index 83eb88b56..000000000 --- a/test/grammar/schema/type/combination_5_type_fail/stderr.golden.py +++ /dev/null @@ -1,30 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.TypeError_Compile_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=2, - col_no=5, - indent_count=1, - arg_msg="expect int", - err_level=kcl_error.ErrLevel.ORDINARY - ), - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=26, - col_no=17, - arg_msg="got str(Alice)" - ) - ], - arg_msg="expect int, got str(Alice)" - ), - file=sys.stdout -) - diff --git a/test/grammar/schema/type/config_expr_index_signature_fail/stderr.golden b/test/grammar/schema/type/config_expr_index_signature_fail/stderr.golden new file mode 100644 index 000000000..5fa973e24 --- /dev/null +++ b/test/grammar/schema/type/config_expr_index_signature_fail/stderr.golden @@ -0,0 +1,11 @@ +error[E2G22]: TypeError + --> ${CWD}/main.k:10:9 + | +10 | "classID" = "aa" + | ^ expected int, got str(aa) + | + --> ${CWD}/main.k:6:5 + | +6 | name: Name + | ^ variable is defined here, its type is int, but got str(aa) + | diff --git a/test/grammar/schema/type/config_expr_index_signature_fail/stderr.golden.py b/test/grammar/schema/type/config_expr_index_signature_fail/stderr.golden.py deleted file mode 100644 index e27b6925a..000000000 --- a/test/grammar/schema/type/config_expr_index_signature_fail/stderr.golden.py +++ /dev/null @@ -1,29 +0,0 @@ - -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.TypeError_Compile_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=3, - col_no=5, - arg_msg="expect int", - err_level=kcl_error.ErrLevel.ORDINARY - ), - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=10, - col_no=9, - arg_msg="got str(aa)" - ) - ], - arg_msg="expect int, got str(aa)" - ), - file=sys.stdout -) diff --git a/test/grammar/schema/type/config_expr_type_fail_0/stderr.golden b/test/grammar/schema/type/config_expr_type_fail_0/stderr.golden new file mode 100644 index 000000000..cd558378d --- /dev/null +++ b/test/grammar/schema/type/config_expr_type_fail_0/stderr.golden @@ -0,0 +1,11 @@ +error[E2G22]: TypeError + --> ${CWD}/main.k:42:44 + | +42 | elif False: ID = "123" + | ^ expected int, got str(123) + | + --> ${CWD}/main.k:4:5 + | +4 | ID: int = 1 + | ^ variable is defined here, its type is int, but got str(123) + | \ No newline at end of file diff --git a/test/grammar/schema/type/config_expr_type_fail_0/stderr.golden.py b/test/grammar/schema/type/config_expr_type_fail_0/stderr.golden.py deleted file mode 100644 index 29d577e3b..000000000 --- a/test/grammar/schema/type/config_expr_type_fail_0/stderr.golden.py +++ /dev/null @@ -1,28 +0,0 @@ - -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception(err_type=kcl_error.ErrType.TypeError_Compile_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=4, - col_no=5, - arg_msg="expect int", - err_level=kcl_error.ErrLevel.ORDINARY - ), - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=42, - col_no=44, - arg_msg="got str(123)" - ), - ], - arg_msg="expect int, got str(123)") - , file=sys.stdout -) - diff --git a/test/grammar/schema/type/config_expr_type_fail_1/stderr.golden b/test/grammar/schema/type/config_expr_type_fail_1/stderr.golden new file mode 100644 index 000000000..3315d2496 --- /dev/null +++ b/test/grammar/schema/type/config_expr_type_fail_1/stderr.golden @@ -0,0 +1,11 @@ +error[E2G22]: TypeError + --> ${CWD}/main.k:12:16 + | +12 | name.name0.name = 123 + | ^ expected str, got int(123) + | + --> ${CWD}/main.k:2:5 + | +2 | name: str = "Kiki" + | ^ variable is defined here, its type is str, but got int(123) + | \ No newline at end of file diff --git a/test/grammar/schema/type/config_expr_type_fail_1/stderr.golden.py b/test/grammar/schema/type/config_expr_type_fail_1/stderr.golden.py deleted file mode 100644 index a43657872..000000000 --- a/test/grammar/schema/type/config_expr_type_fail_1/stderr.golden.py +++ /dev/null @@ -1,31 +0,0 @@ - -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.TypeError_Compile_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=2, - col_no=5, - indent_count=1, - arg_msg="expect str", - err_level=kcl_error.ErrLevel.ORDINARY - ), - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=12, - col_no=5, - arg_msg="got int(123)" - ), - ], - arg_msg="expect str, got int(123)" - ), - file=sys.stdout -) - diff --git a/test/grammar/schema/type/config_expr_type_fail_2/stderr.golden b/test/grammar/schema/type/config_expr_type_fail_2/stderr.golden new file mode 100644 index 000000000..5fa2c6061 --- /dev/null +++ b/test/grammar/schema/type/config_expr_type_fail_2/stderr.golden @@ -0,0 +1,11 @@ +error[E2G22]: TypeError + --> ${CWD}/main.k:38:21 + | +38 | "name2": 1 + | ^ expected Name1, got int(1) + | + --> ${CWD}/main.k:13:5 + | +13 | name2: Name1 + | ^ variable is defined here, its type is Name1, but got int(1) + | \ No newline at end of file diff --git a/test/grammar/schema/type/config_expr_type_fail_2/stderr.golden.py b/test/grammar/schema/type/config_expr_type_fail_2/stderr.golden.py deleted file mode 100644 index 4910e263a..000000000 --- a/test/grammar/schema/type/config_expr_type_fail_2/stderr.golden.py +++ /dev/null @@ -1,28 +0,0 @@ - -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception(err_type=kcl_error.ErrType.TypeError_Compile_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=13, - col_no=5, - arg_msg="expect Name1", - err_level=kcl_error.ErrLevel.ORDINARY - ), - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=38, - col_no=21, - arg_msg="got int(1)" - ), - ], - arg_msg="expect Name1, got int(1)") - , file=sys.stdout -) - diff --git a/test/grammar/schema/type/config_expr_type_fail_3/stderr.golden b/test/grammar/schema/type/config_expr_type_fail_3/stderr.golden new file mode 100644 index 000000000..9ef49d3cb --- /dev/null +++ b/test/grammar/schema/type/config_expr_type_fail_3/stderr.golden @@ -0,0 +1,11 @@ +error[E2G22]: TypeError + --> ${CWD}/main.k:39:25 + | +39 | age = "123" + | ^ expected int, got str(123) + | + --> ${CWD}/main.k:3:5 + | +3 | age: int = 10 + | ^ variable is defined here, its type is int, but got str(123) + | \ No newline at end of file diff --git a/test/grammar/schema/type/config_expr_type_fail_3/stderr.golden.py b/test/grammar/schema/type/config_expr_type_fail_3/stderr.golden.py deleted file mode 100644 index dd5bf12bb..000000000 --- a/test/grammar/schema/type/config_expr_type_fail_3/stderr.golden.py +++ /dev/null @@ -1,28 +0,0 @@ - -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception(err_type=kcl_error.ErrType.TypeError_Compile_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=3, - col_no=5, - arg_msg="expect int", - err_level=kcl_error.ErrLevel.ORDINARY - ), - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=39, - col_no=25, - arg_msg="got str(123)" - ), - ], - arg_msg="expect int, got str(123)") - , file=sys.stdout -) - diff --git a/test/grammar/schema/type/dict_fail_0/stderr.golden b/test/grammar/schema/type/dict_fail_0/stderr.golden new file mode 100644 index 000000000..0e88531df --- /dev/null +++ b/test/grammar/schema/type/dict_fail_0/stderr.golden @@ -0,0 +1,6 @@ +error[E2A31]: IllegalAttributeError + --> ${CWD}/main.k:5:16 + | +5 | "labels": {None: None} + | ^ A attribute must be string type, got 'NoneType' + | \ No newline at end of file diff --git a/test/grammar/schema/type/dict_fail_0/stderr.golden.py b/test/grammar/schema/type/dict_fail_0/stderr.golden.py deleted file mode 100644 index 19959e21b..000000000 --- a/test/grammar/schema/type/dict_fail_0/stderr.golden.py +++ /dev/null @@ -1,21 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.IllegalAttributeError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=5, - col_no=16 - ) - ], - arg_msg="type 'NoneType'" - ), - file=sys.stdout -) - diff --git a/test/grammar/schema/type/dict_nested_fail_0/stderr.golden b/test/grammar/schema/type/dict_nested_fail_0/stderr.golden new file mode 100644 index 000000000..006d30a27 --- /dev/null +++ b/test/grammar/schema/type/dict_nested_fail_0/stderr.golden @@ -0,0 +1,44 @@ +error[E2G22]: TypeError + --> ${CWD}/main.k:15:17 + | +15 | "name3":123 + | ^ expected str, got int(123) + | + --> ${CWD}/main.k:3:5 + | +3 | ids: {str:{str:{str:str}}} + | ^ variable is defined here, its type is str, but got int(123) + | +error[E2G22]: TypeError + --> ${CWD}/main.k:14:13 + | +14 | "name2":{ + | ^ expected {str:str}, got {str(name3):int(123)} + | + --> ${CWD}/main.k:3:5 + | +3 | ids: {str:{str:{str:str}}} + | ^ variable is defined here, its type is {str:str}, but got {str(name3):int(123)} + | +error[E2G22]: TypeError + --> ${CWD}/main.k:13:9 + | +13 | "name1":{ + | ^ expected {str:{str:str}}, got {str(name2):{str(name3):int(123)}} + | + --> ${CWD}/main.k:3:5 + | +3 | ids: {str:{str:{str:str}}} + | ^ variable is defined here, its type is {str:{str:str}}, but got {str(name2):{str(name3):int(123)}} + | +error[E2G22]: TypeError + --> ${CWD}/main.k:12:5 + | +12 | ids: { + | ^ expected {str:{str:{str:str}}}, got {str(name1):{str(name2):{str(name3):int(123)}}} + | + --> ${CWD}/main.k:3:5 + | +3 | ids: {str:{str:{str:str}}} + | ^ variable is defined here, its type is {str:{str:{str:str}}}, but got {str(name1):{str(name2):{str(name3):int(123)}}} + | \ No newline at end of file diff --git a/test/grammar/schema/type/dict_nested_fail_0/stderr.golden.py b/test/grammar/schema/type/dict_nested_fail_0/stderr.golden.py deleted file mode 100644 index 626b1d7ff..000000000 --- a/test/grammar/schema/type/dict_nested_fail_0/stderr.golden.py +++ /dev/null @@ -1,27 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception(err_type=kcl_error.ErrType.TypeError_Compile_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=3, - col_no=5, - arg_msg="expect str", - err_level=kcl_error.ErrLevel.ORDINARY - ), - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=15, - col_no=17, - arg_msg="got int(123)" - ), - ], - arg_msg='expect str, got int(123)') - , file=sys.stdout -) - diff --git a/test/grammar/schema/type/multi_types_1/stderr.golden b/test/grammar/schema/type/multi_types_1/stderr.golden new file mode 100644 index 000000000..a8d11a4c0 --- /dev/null +++ b/test/grammar/schema/type/multi_types_1/stderr.golden @@ -0,0 +1,11 @@ +error[E2G22]: TypeError + --> ${CWD}/main.k:5:5 + | +5 | "port": float(80) + | ^ expected int | str, got float + | + --> ${CWD}/main.k:2:5 + | +2 | port: int | str + | ^ variable is defined here, its type is int | str, but got float + | \ No newline at end of file diff --git a/test/grammar/schema/type/multi_types_1/stderr.golden.py b/test/grammar/schema/type/multi_types_1/stderr.golden.py deleted file mode 100644 index 47a35ac0d..000000000 --- a/test/grammar/schema/type/multi_types_1/stderr.golden.py +++ /dev/null @@ -1,30 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.TypeError_Compile_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=2, - col_no=5, - indent_count=1, - arg_msg="expect int|str", - err_level=kcl_error.ErrLevel.ORDINARY - ), - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=5, - col_no=5, - arg_msg="got float" - ) - ], - arg_msg="expect int|str, got float" - ), - file=sys.stdout -) - diff --git a/test/grammar/schema/type/type_dict_fail_0/stderr.golden b/test/grammar/schema/type/type_dict_fail_0/stderr.golden new file mode 100644 index 000000000..6f01791cc --- /dev/null +++ b/test/grammar/schema/type/type_dict_fail_0/stderr.golden @@ -0,0 +1,11 @@ +error[E2G22]: TypeError + --> ${CWD}/main.k:17:11 + | +17 | "lastName": "Terry" + | ^ expected int, got str(Terry) + | + --> ${CWD}/main.k:3:3 + | +3 | lastName: int + | ^ variable is defined here, its type is int, but got str(Terry) + | \ No newline at end of file diff --git a/test/grammar/schema/type/type_dict_fail_0/stderr.golden.py b/test/grammar/schema/type/type_dict_fail_0/stderr.golden.py deleted file mode 100644 index 33e73efff..000000000 --- a/test/grammar/schema/type/type_dict_fail_0/stderr.golden.py +++ /dev/null @@ -1,27 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception(err_type=kcl_error.ErrType.TypeError_Compile_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=3, - col_no=3, - arg_msg="expect int", - err_level=kcl_error.ErrLevel.ORDINARY - ), - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=17, - col_no=11, - arg_msg="got str(Terry)" - ), - ], - arg_msg='expect int, got str(Terry)') - , file=sys.stdout -) - diff --git a/test/grammar/schema/type/type_fail_0/stderr.golden b/test/grammar/schema/type/type_fail_0/stderr.golden new file mode 100644 index 000000000..579dcf59c --- /dev/null +++ b/test/grammar/schema/type/type_fail_0/stderr.golden @@ -0,0 +1,11 @@ +error[E2G22]: TypeError + --> ${CWD}/main.k:7:5 + | +7 | "lastName": "Doe" + | ^ expected int, got str(Doe) + | + --> ${CWD}/main.k:3:5 + | +3 | lastName: int + | ^ variable is defined here, its type is int, but got str(Doe) + | \ No newline at end of file diff --git a/test/grammar/schema/type/type_fail_0/stderr.golden.py b/test/grammar/schema/type/type_fail_0/stderr.golden.py deleted file mode 100644 index 829c37abe..000000000 --- a/test/grammar/schema/type/type_fail_0/stderr.golden.py +++ /dev/null @@ -1,31 +0,0 @@ - -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.TypeError_Compile_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=3, - col_no=5, - indent_count=1, - arg_msg="expect int", - err_level=kcl_error.ErrLevel.ORDINARY - ), - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=7, - col_no=5, - arg_msg="got str(Doe)" - ), - ], - arg_msg="expect int, got str(Doe)" - ), - file=sys.stdout -) - diff --git a/test/grammar/schema/type/type_fail_1/stderr.golden b/test/grammar/schema/type/type_fail_1/stderr.golden new file mode 100644 index 000000000..78d4a2753 --- /dev/null +++ b/test/grammar/schema/type/type_fail_1/stderr.golden @@ -0,0 +1,11 @@ +error[E2G22]: TypeError + --> ${CWD}/main.k:7:5 + | +7 | lastName: 12 + | ^ expected str, got int(12) + | + --> ${CWD}/main.k:3:5 + | +3 | lastName: str + | ^ variable is defined here, its type is str, but got int(12) + | \ No newline at end of file diff --git a/test/grammar/schema/type/type_fail_1/stderr.golden.py b/test/grammar/schema/type/type_fail_1/stderr.golden.py deleted file mode 100644 index e6130025b..000000000 --- a/test/grammar/schema/type/type_fail_1/stderr.golden.py +++ /dev/null @@ -1,31 +0,0 @@ - -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.TypeError_Compile_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=3, - col_no=5, - indent_count=1, - arg_msg="expect str", - err_level=kcl_error.ErrLevel.ORDINARY - ), - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=7, - col_no=5, - arg_msg="got int(12)" - ) - ], - arg_msg="expect str, got int(12)" - ), - file=sys.stdout -) - diff --git a/test/grammar/schema/type/type_fail_10/stderr.golden b/test/grammar/schema/type/type_fail_10/stderr.golden new file mode 100644 index 000000000..379723757 --- /dev/null +++ b/test/grammar/schema/type/type_fail_10/stderr.golden @@ -0,0 +1,11 @@ +error[E2G22]: TypeError + --> ${CWD}/main.k:7:5 + | +7 | "cards": [1, "2"] + | ^ expected [int], got [int(1) | str(2)] + | + --> ${CWD}/main.k:3:5 + | +3 | cards: [int] + | ^ variable is defined here, its type is [int], but got [int(1) | str(2)] + | \ No newline at end of file diff --git a/test/grammar/schema/type/type_fail_10/stderr.golden.py b/test/grammar/schema/type/type_fail_10/stderr.golden.py deleted file mode 100644 index f139cfbb4..000000000 --- a/test/grammar/schema/type/type_fail_10/stderr.golden.py +++ /dev/null @@ -1,30 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.TypeError_Compile_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=3, - col_no=5, - indent_count=1, - arg_msg="expect [int]", - err_level=kcl_error.ErrLevel.ORDINARY - ), - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=7, - col_no=5, - arg_msg="got [int(1)|str(2)]" - ) - ], - arg_msg="expect [int], got [int(1)|str(2)]" - ), - file=sys.stdout -) - diff --git a/test/grammar/schema/type/type_fail_11/stderr.golden b/test/grammar/schema/type/type_fail_11/stderr.golden new file mode 100644 index 000000000..5e06be275 --- /dev/null +++ b/test/grammar/schema/type/type_fail_11/stderr.golden @@ -0,0 +1,11 @@ +error[E2G22]: TypeError + --> ${CWD}/main.k:7:5 + | +7 | "cards": [1] + | ^ expected [{int:any}], got [int(1)] + | + --> ${CWD}/main.k:3:5 + | +3 | cards: [{int:}] + | ^ variable is defined here, its type is [{int:any}], but got [int(1)] + | \ No newline at end of file diff --git a/test/grammar/schema/type/type_fail_11/stderr.golden.py b/test/grammar/schema/type/type_fail_11/stderr.golden.py deleted file mode 100644 index f3114005a..000000000 --- a/test/grammar/schema/type/type_fail_11/stderr.golden.py +++ /dev/null @@ -1,30 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.TypeError_Compile_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=3, - col_no=5, - indent_count=1, - arg_msg="expect [{int:any}]", - err_level=kcl_error.ErrLevel.ORDINARY - ), - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=7, - col_no=5, - arg_msg="got [int(1)]" - ) - ], - arg_msg="expect [{int:any}], got [int(1)]" - ), - file=sys.stdout -) - diff --git a/test/grammar/schema/type/type_fail_12/stderr.golden b/test/grammar/schema/type/type_fail_12/stderr.golden new file mode 100644 index 000000000..574933c0a --- /dev/null +++ b/test/grammar/schema/type/type_fail_12/stderr.golden @@ -0,0 +1,11 @@ +error[E2G22]: TypeError + --> ${CWD}/main.k:7:5 + | +7 | "cards": [{"error": "error"}] + | ^ expected [{int:any}], got [{str(error):str(error)}] + | + --> ${CWD}/main.k:3:5 + | +3 | cards: [{int:}] + | ^ variable is defined here, its type is [{int:any}], but got [{str(error):str(error)}] + | \ No newline at end of file diff --git a/test/grammar/schema/type/type_fail_12/stderr.golden.py b/test/grammar/schema/type/type_fail_12/stderr.golden.py deleted file mode 100644 index 22a7de3e9..000000000 --- a/test/grammar/schema/type/type_fail_12/stderr.golden.py +++ /dev/null @@ -1,30 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.TypeError_Compile_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=3, - col_no=5, - indent_count=1, - arg_msg="expect [{int:any}]", - err_level=kcl_error.ErrLevel.ORDINARY - ), - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=7, - col_no=5, - arg_msg="got [{str(error):str(error)}]" - ) - ], - arg_msg="expect [{int:any}], got [{str(error):str(error)}]" - ), - file=sys.stdout -) - diff --git a/test/grammar/schema/type/type_fail_13/stderr.golden b/test/grammar/schema/type/type_fail_13/stderr.golden new file mode 100644 index 000000000..fc53fd578 --- /dev/null +++ b/test/grammar/schema/type/type_fail_13/stderr.golden @@ -0,0 +1,11 @@ +error[E2G22]: TypeError + --> ${CWD}/main.k:7:5 + | +7 | "cards": ["error"] + | ^ expected [{str:any}], got [str(error)] + | + --> ${CWD}/main.k:3:5 + | +3 | cards: [{str:}] + | ^ variable is defined here, its type is [{str:any}], but got [str(error)] + | \ No newline at end of file diff --git a/test/grammar/schema/type/type_fail_13/stderr.golden.py b/test/grammar/schema/type/type_fail_13/stderr.golden.py deleted file mode 100644 index fd471eb18..000000000 --- a/test/grammar/schema/type/type_fail_13/stderr.golden.py +++ /dev/null @@ -1,30 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.TypeError_Compile_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=3, - col_no=5, - indent_count=1, - arg_msg="expect [{str:any}]", - err_level=kcl_error.ErrLevel.ORDINARY - ), - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=7, - col_no=5, - arg_msg="got [str(error)]" - ) - ], - arg_msg="expect [{str:any}], got [str(error)]" - ), - file=sys.stdout -) - diff --git a/test/grammar/schema/type/type_fail_14/stderr.golden b/test/grammar/schema/type/type_fail_14/stderr.golden new file mode 100644 index 000000000..ca12eab17 --- /dev/null +++ b/test/grammar/schema/type/type_fail_14/stderr.golden @@ -0,0 +1,11 @@ +error[E2G22]: TypeError + --> ${CWD}/main.k:7:5 + | +7 | "cards": ["error"] + | ^ expected [{str:str}], got [str(error)] + | + --> ${CWD}/main.k:3:5 + | +3 | cards: [{str:str}] + | ^ variable is defined here, its type is [{str:str}], but got [str(error)] + | \ No newline at end of file diff --git a/test/grammar/schema/type/type_fail_14/stderr.golden.py b/test/grammar/schema/type/type_fail_14/stderr.golden.py deleted file mode 100644 index 1c418fa4e..000000000 --- a/test/grammar/schema/type/type_fail_14/stderr.golden.py +++ /dev/null @@ -1,30 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.TypeError_Compile_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=3, - col_no=5, - indent_count=1, - arg_msg="expect [{str:str}]", - err_level=kcl_error.ErrLevel.ORDINARY - ), - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=7, - col_no=5, - arg_msg="got [str(error)]" - ) - ], - arg_msg="expect [{str:str}], got [str(error)]" - ), - file=sys.stdout -) - diff --git a/test/grammar/schema/type/type_fail_15/stderr.golden b/test/grammar/schema/type/type_fail_15/stderr.golden new file mode 100644 index 000000000..7744552ce --- /dev/null +++ b/test/grammar/schema/type/type_fail_15/stderr.golden @@ -0,0 +1,11 @@ +error[E2G22]: TypeError + --> ${CWD}/main.k:7:5 + | +7 | "cards": [{"error": "error"}] + | ^ expected [str], got [{str(error):str(error)}] + | + --> ${CWD}/main.k:3:5 + | +3 | cards: [str] + | ^ variable is defined here, its type is [str], but got [{str(error):str(error)}] + | \ No newline at end of file diff --git a/test/grammar/schema/type/type_fail_15/stderr.golden.py b/test/grammar/schema/type/type_fail_15/stderr.golden.py deleted file mode 100644 index 8bbfb554b..000000000 --- a/test/grammar/schema/type/type_fail_15/stderr.golden.py +++ /dev/null @@ -1,30 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.TypeError_Compile_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=3, - col_no=5, - indent_count=1, - arg_msg="expect [str]", - err_level=kcl_error.ErrLevel.ORDINARY - ), - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=7, - col_no=5, - arg_msg="got [{str(error):str(error)}]" - ) - ], - arg_msg="expect [str], got [{str(error):str(error)}]" - ), - file=sys.stdout -) - diff --git a/test/grammar/schema/type/type_fail_16/stderr.golden b/test/grammar/schema/type/type_fail_16/stderr.golden new file mode 100644 index 000000000..cb5b295c6 --- /dev/null +++ b/test/grammar/schema/type/type_fail_16/stderr.golden @@ -0,0 +1,11 @@ +error[E2G22]: TypeError + --> ${CWD}/main.k:7:5 + | +7 | "cards": {"error":"error"} + | ^ expected [str], got {str(error):str(error)} + | + --> ${CWD}/main.k:3:5 + | +3 | cards : [str] + | ^ variable is defined here, its type is [str], but got {str(error):str(error)} + | \ No newline at end of file diff --git a/test/grammar/schema/type/type_fail_16/stderr.golden.py b/test/grammar/schema/type/type_fail_16/stderr.golden.py deleted file mode 100644 index 5a23dc2d4..000000000 --- a/test/grammar/schema/type/type_fail_16/stderr.golden.py +++ /dev/null @@ -1,30 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.TypeError_Compile_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=3, - col_no=5, - indent_count=1, - arg_msg="expect [str]", - err_level=kcl_error.ErrLevel.ORDINARY - ), - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=7, - col_no=5, - arg_msg="got {str(error):str(error)}" - ) - ], - arg_msg="expect [str], got {str(error):str(error)}" - ), - file=sys.stdout -) - diff --git a/test/grammar/schema/type/type_fail_17/stderr.golden b/test/grammar/schema/type/type_fail_17/stderr.golden new file mode 100644 index 000000000..6edecc121 --- /dev/null +++ b/test/grammar/schema/type/type_fail_17/stderr.golden @@ -0,0 +1,11 @@ +error[E2G22]: TypeError + --> ${CWD}/main.k:7:5 + | +7 | "cards": {"error": "error"} + | ^ expected str, got {str(error):str(error)} + | + --> ${CWD}/main.k:3:5 + | +3 | cards: str + | ^ variable is defined here, its type is str, but got {str(error):str(error)} + | \ No newline at end of file diff --git a/test/grammar/schema/type/type_fail_17/stderr.golden.py b/test/grammar/schema/type/type_fail_17/stderr.golden.py deleted file mode 100644 index 89f6b69c9..000000000 --- a/test/grammar/schema/type/type_fail_17/stderr.golden.py +++ /dev/null @@ -1,30 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.TypeError_Compile_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=3, - col_no=5, - indent_count=1, - arg_msg="expect str", - err_level=kcl_error.ErrLevel.ORDINARY - ), - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=7, - col_no=5, - arg_msg="got {str(error):str(error)}" - ) - ], - arg_msg="expect str, got {str(error):str(error)}" - ), - file=sys.stdout -) - diff --git a/test/grammar/schema/type/type_fail_18/stderr.golden b/test/grammar/schema/type/type_fail_18/stderr.golden new file mode 100644 index 000000000..f023af23a --- /dev/null +++ b/test/grammar/schema/type/type_fail_18/stderr.golden @@ -0,0 +1,22 @@ +error[E2G22]: TypeError + --> ${CWD}/main.k:33:21 + | +33 | "cards": [card {"num":123}] + | ^ expected str, got int(123) + | + --> ${CWD}/main.k:2:5 + | +2 | num: str + | ^ variable is defined here, its type is str, but got int(123) + | +error[E2G22]: TypeError + --> ${CWD}/main.k:33:5 + | +33 | "cards": [card {"num":123}] + | ^ expected [{str:any}], got [card] + | + --> ${CWD}/main.k:18:5 + | +18 | cards: [{str:}] + | ^ variable is defined here, its type is [{str:any}], but got [card] + | \ No newline at end of file diff --git a/test/grammar/schema/type/type_fail_18/stderr.golden.py b/test/grammar/schema/type/type_fail_18/stderr.golden.py deleted file mode 100644 index 90c064c0c..000000000 --- a/test/grammar/schema/type/type_fail_18/stderr.golden.py +++ /dev/null @@ -1,30 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.TypeError_Compile_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=2, - col_no=5, - indent_count=1, - arg_msg="expect str", - err_level=kcl_error.ErrLevel.ORDINARY - ), - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=33, - col_no=21, - arg_msg="got int(123)" - ) - ], - arg_msg="expect str, got int(123)" - ), - file=sys.stdout -) - diff --git a/test/grammar/schema/type/type_fail_19/stderr.golden b/test/grammar/schema/type/type_fail_19/stderr.golden new file mode 100644 index 000000000..358e230e8 --- /dev/null +++ b/test/grammar/schema/type/type_fail_19/stderr.golden @@ -0,0 +1,22 @@ +error[E2G22]: TypeError + --> ${CWD}/main.k:19:25 + | +19 | "cards": [info.card{"num": 123}] + | ^ expected str, got int(123) + | + --> ${CWD}/pkg/info.k:2:5 + | +2 | num: str + | ^ variable is defined here, its type is str, but got int(123) + | +error[E2G22]: TypeError + --> ${CWD}/main.k:19:5 + | +19 | "cards": [info.card{"num": 123}] + | ^ expected [{str:any}], got [card] + | + --> ${CWD}/main.k:5:5 + | +5 | cards: [{str:}] + | ^ variable is defined here, its type is [{str:any}], but got [card] + | \ No newline at end of file diff --git a/test/grammar/schema/type/type_fail_19/stderr.golden.py b/test/grammar/schema/type/type_fail_19/stderr.golden.py deleted file mode 100644 index 41a00aafc..000000000 --- a/test/grammar/schema/type/type_fail_19/stderr.golden.py +++ /dev/null @@ -1,30 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.TypeError_Compile_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/pkg/info.k", - line_no=2, - col_no=5, - indent_count=1, - arg_msg="expect str", - err_level=kcl_error.ErrLevel.ORDINARY - ), - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=19, - col_no=25, - arg_msg="got int(123)" - ) - ], - arg_msg="expect str, got int(123)" - ), - file=sys.stdout -) - diff --git a/test/grammar/schema/type/type_fail_2/stderr.golden b/test/grammar/schema/type/type_fail_2/stderr.golden new file mode 100644 index 000000000..7886dee4c --- /dev/null +++ b/test/grammar/schema/type/type_fail_2/stderr.golden @@ -0,0 +1,11 @@ +error[E2G22]: TypeError + --> ${CWD}/main.k:14:5 + | +14 | "name": Name1 { + | ^ expected Name0, got Name1 + | + --> ${CWD}/main.k:10:5 + | +10 | name: Name0 + | ^ variable is defined here, its type is Name0, but got Name1 + | \ No newline at end of file diff --git a/test/grammar/schema/type/type_fail_2/stderr.golden.py b/test/grammar/schema/type/type_fail_2/stderr.golden.py deleted file mode 100644 index 09dd10936..000000000 --- a/test/grammar/schema/type/type_fail_2/stderr.golden.py +++ /dev/null @@ -1,30 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.TypeError_Compile_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=10, - col_no=5, - indent_count=1, - arg_msg="expect Name0", - err_level=kcl_error.ErrLevel.ORDINARY - ), - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=14, - col_no=5, - arg_msg="got Name1" - ) - ], - arg_msg="expect Name0, got Name1" - ), - file=sys.stdout -) - diff --git a/test/grammar/schema/type/type_fail_20/stderr.golden b/test/grammar/schema/type/type_fail_20/stderr.golden new file mode 100644 index 000000000..8077e6021 --- /dev/null +++ b/test/grammar/schema/type/type_fail_20/stderr.golden @@ -0,0 +1,6 @@ +error[E2G22]: TypeError + --> ${CWD}/main.k:6:12 + | +6 | info0: info.inf + | ^ attribute 'inf' not found in 'module 'pkg.info'' + | \ No newline at end of file diff --git a/test/grammar/schema/type/type_fail_20/stderr.golden.py b/test/grammar/schema/type/type_fail_20/stderr.golden.py deleted file mode 100644 index a7776263b..000000000 --- a/test/grammar/schema/type/type_fail_20/stderr.golden.py +++ /dev/null @@ -1,20 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.AttributeError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=6, - ) - ], - arg_msg="module 'pkg.info' has no attribute 'inf'" - ), - file=sys.stdout -) - diff --git a/test/grammar/schema/type/type_fail_21/stderr.golden b/test/grammar/schema/type/type_fail_21/stderr.golden new file mode 100644 index 000000000..8e4c42303 --- /dev/null +++ b/test/grammar/schema/type/type_fail_21/stderr.golden @@ -0,0 +1,11 @@ +error[E2G22]: TypeError + --> ${CWD}/main.k:6:25 + | +6 | "firstName": "张张张", "lastName": "Doe" + | ^ expected int, got str(Doe) + | + --> ${CWD}/main.k:3:5 + | +3 | lastName: int + | ^ variable is defined here, its type is int, but got str(Doe) + | \ No newline at end of file diff --git a/test/grammar/schema/type/type_fail_21/stderr.golden.py b/test/grammar/schema/type/type_fail_21/stderr.golden.py deleted file mode 100644 index c39365003..000000000 --- a/test/grammar/schema/type/type_fail_21/stderr.golden.py +++ /dev/null @@ -1,30 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.TypeError_Compile_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=3, - col_no=5, - indent_count=1, - arg_msg="expect int", - err_level=kcl_error.ErrLevel.ORDINARY - ), - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=6, - col_no=25, - arg_msg="got str(Doe)" - ) - ], - arg_msg="expect int, got str(Doe)" - ), - file=sys.stdout -) - diff --git a/test/grammar/schema/type/type_fail_22/stderr.golden b/test/grammar/schema/type/type_fail_22/stderr.golden new file mode 100644 index 000000000..ff109589c --- /dev/null +++ b/test/grammar/schema/type/type_fail_22/stderr.golden @@ -0,0 +1,11 @@ +error[E2G22]: TypeError + --> ${CWD}/main.k:9:5 + | +9 | "firstName": 2, + | ^ expected str | Name, got int(2) + | + --> ${CWD}/main.k:5:5 + | +5 | firstName: str | Name + | ^ variable is defined here, its type is str | Name, but got int(2) + | \ No newline at end of file diff --git a/test/grammar/schema/type/type_fail_22/stderr.golden.py b/test/grammar/schema/type/type_fail_22/stderr.golden.py deleted file mode 100644 index 9ee902514..000000000 --- a/test/grammar/schema/type/type_fail_22/stderr.golden.py +++ /dev/null @@ -1,30 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.TypeError_Compile_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=5, - col_no=5, - indent_count=1, - arg_msg="expect str|Name", - err_level=kcl_error.ErrLevel.ORDINARY - ), - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=9, - col_no=5, - arg_msg="got int(2)" - ) - ], - arg_msg="expect str|Name, got int(2)" - ), - file=sys.stdout -) - diff --git a/test/grammar/schema/type/type_fail_24/stderr.golden b/test/grammar/schema/type/type_fail_24/stderr.golden new file mode 100644 index 000000000..5e8afcec9 --- /dev/null +++ b/test/grammar/schema/type/type_fail_24/stderr.golden @@ -0,0 +1,44 @@ +error[E2G22]: TypeError + --> ${CWD}/main.k:6:13 + | +6 | "image": "image", + | ^ expected Container, got str(image) + | + --> ${CWD}/pkg/person.k:3:5 + | +3 | spec: [Container] + | ^ variable is defined here, its type is Container, but got str(image) + | +error[E2G22]: TypeError + --> ${CWD}/main.k:7:13 + | +7 | "name": "name" + | ^ expected Container, got str(name) + | + --> ${CWD}/pkg/person.k:3:5 + | +3 | spec: [Container] + | ^ variable is defined here, its type is Container, but got str(name) + | +error[E2G22]: TypeError + --> ${CWD}/main.k:5:9 + | +5 | spec: { + | ^ expected [Container], got {str(image) | str(name):str(image) | str(name)} + | + --> ${CWD}/pkg/person.k:3:5 + | +3 | spec: [Container] + | ^ variable is defined here, its type is [Container], but got {str(image) | str(name):str(image) | str(name)} + | +error[E2G22]: TypeError + --> ${CWD}/main.k:4:5 + | +4 | name: { + | ^ expected [Container], got {str:str} + | + --> ${CWD}/pkg/person.k:3:5 + | +3 | spec: [Container] + | ^ variable is defined here, its type is [Container], but got {str:str} + | \ No newline at end of file diff --git a/test/grammar/schema/type/type_fail_24/stderr.golden.py b/test/grammar/schema/type/type_fail_24/stderr.golden.py deleted file mode 100644 index 734a41fa4..000000000 --- a/test/grammar/schema/type/type_fail_24/stderr.golden.py +++ /dev/null @@ -1,27 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception(err_type=kcl_error.ErrType.TypeError_Compile_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/pkg/person.k", - line_no=3, - col_no=5, - arg_msg="expect [pkg.Container]", - err_level=kcl_error.ErrLevel.ORDINARY - ), - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=5, - col_no=9, - arg_msg="got {str(image)|str(name):str(image)|str(name)}" - ), - ], - arg_msg="expect [pkg.Container], got {str(image)|str(name):str(image)|str(name)}") - , file=sys.stdout -) - diff --git a/test/grammar/schema/type/type_fail_25/stderr.golden b/test/grammar/schema/type/type_fail_25/stderr.golden new file mode 100644 index 000000000..e52000ea5 --- /dev/null +++ b/test/grammar/schema/type/type_fail_25/stderr.golden @@ -0,0 +1,6 @@ +error[E2L23]: CompileError + --> ${CWD}/main.k:5:11 + | +5 | name: ErrOther + | ^ name 'ErrOther' is not defined, did you mean '["Other"]'? + | \ No newline at end of file diff --git a/test/grammar/schema/type/type_fail_25/stderr.golden.py b/test/grammar/schema/type/type_fail_25/stderr.golden.py deleted file mode 100644 index 591bedfb0..000000000 --- a/test/grammar/schema/type/type_fail_25/stderr.golden.py +++ /dev/null @@ -1,20 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.CompileError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=5, - ) - ], - arg_msg="name 'ErrOther' is not defined" - ), - file=sys.stdout -) - diff --git a/test/grammar/schema/type/type_fail_26/stderr.golden b/test/grammar/schema/type/type_fail_26/stderr.golden new file mode 100644 index 000000000..0ac2719d1 --- /dev/null +++ b/test/grammar/schema/type/type_fail_26/stderr.golden @@ -0,0 +1,6 @@ +error[E2G22]: TypeError + --> ${CWD}/main.k:4:5 + | +4 | affinity: {str:str} = { + | ^ expected {str:str}, got {str(podAntiAffinity):{str(preferredDuringSchedulingIgnoredDuringExecution):[{str(weight) | str(podAffinityTerm):int(100) | {str(labelSelector) | str(topologyKey):{str(matchExpressions):[{str(key) | str(operator) | str(values):str(cluster.k8s/app-name) | str(In) | [str]}]} | str(kubernetes.io/hostname)}}]}} + | \ No newline at end of file diff --git a/test/grammar/schema/type/type_fail_26/stderr.golden.py b/test/grammar/schema/type/type_fail_26/stderr.golden.py deleted file mode 100644 index 8ca6006b8..000000000 --- a/test/grammar/schema/type/type_fail_26/stderr.golden.py +++ /dev/null @@ -1,22 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.TypeError_Compile_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=4, - col_no=5, - arg_msg="got {str(podAntiAffinity):{str(preferredDuringSchedulingIgnoredDuringExecution):[{str(weight)|str(podAffinityTerm):int(100)|{str(labelSelector)|str(topologyKey):str(kubernetes.io/hostname)|{str(matchExpressions):[{str(key)|str(operator)|str(values):str(cluster.k8s/app-name)|str(In)|[str]}]}}}]}}" - ) - ], - arg_msg="expect {str:str}, got {str(podAntiAffinity):{str(preferredDuringSchedulingIgnoredDuringExecution):[{str(weight)|str(podAffinityTerm):int(100)|{str(labelSelector)|str(topologyKey):str(kubernetes.io/hostname)|{str(matchExpressions):[{str(key)|str(operator)|str(values):str(cluster.k8s/app-name)|str(In)|[str]}]}}}]}}" - ), - file=sys.stdout -) - diff --git a/test/grammar/schema/type/type_fail_27/_main.k b/test/grammar/schema/type/type_fail_27/main.k similarity index 100% rename from test/grammar/schema/type/type_fail_27/_main.k rename to test/grammar/schema/type/type_fail_27/main.k diff --git a/test/grammar/schema/type/type_fail_27/stderr.golden b/test/grammar/schema/type/type_fail_27/stderr.golden new file mode 100644 index 000000000..1538d41fa --- /dev/null +++ b/test/grammar/schema/type/type_fail_27/stderr.golden @@ -0,0 +1,6 @@ +error[E3M38]: EvaluationError + --> ${CWD}/main.k:4:1 + | +4 | config?: [str] + | expect [str], got Person + | \ No newline at end of file diff --git a/test/grammar/schema/type/type_fail_27/stderr.golden.py b/test/grammar/schema/type/type_fail_27/stderr.golden.py deleted file mode 100644 index 503a986d5..000000000 --- a/test/grammar/schema/type/type_fail_27/stderr.golden.py +++ /dev/null @@ -1,21 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.EvaluationError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=10, - col_no=5, - ) - ], - arg_msg="expect [str], got Person" - ), - file=sys.stdout -) - diff --git a/test/grammar/schema/type/type_fail_3/stderr.golden b/test/grammar/schema/type/type_fail_3/stderr.golden new file mode 100644 index 000000000..a2ab26486 --- /dev/null +++ b/test/grammar/schema/type/type_fail_3/stderr.golden @@ -0,0 +1,6 @@ +error[E2L23]: CompileError + --> ${CWD}/main.k:18:13 + | +18 | "fullName": "Alice Terry" + | ^ Cannot add member 'fullName' to schema 'Name' + | \ No newline at end of file diff --git a/test/grammar/schema/type/type_fail_3/stderr.golden.py b/test/grammar/schema/type/type_fail_3/stderr.golden.py deleted file mode 100644 index 1571ede66..000000000 --- a/test/grammar/schema/type/type_fail_3/stderr.golden.py +++ /dev/null @@ -1,20 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception(err_type=kcl_error.ErrType.CannotAddMembers_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=18, - col_no=13, - arg_msg="'fullName' is not defined in schema 'Name'" - ), - ], - arg_msg="Cannot add member 'fullName' to schema 'Name'") - , file=sys.stdout -) - diff --git a/test/grammar/schema/type/type_fail_4/stderr.golden b/test/grammar/schema/type/type_fail_4/stderr.golden new file mode 100644 index 000000000..a72ea1d5d --- /dev/null +++ b/test/grammar/schema/type/type_fail_4/stderr.golden @@ -0,0 +1,6 @@ +error[E2L23]: CompileError + --> ${CWD}/main.k:8:5 + | +8 | "fullName": "John Doe" # undefined field + | ^ Cannot add member 'fullName' to schema 'Person' + | \ No newline at end of file diff --git a/test/grammar/schema/type/type_fail_4/stderr.golden.py b/test/grammar/schema/type/type_fail_4/stderr.golden.py deleted file mode 100644 index f0b203020..000000000 --- a/test/grammar/schema/type/type_fail_4/stderr.golden.py +++ /dev/null @@ -1,21 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.CannotAddMembers_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=8, - col_no=5, - arg_msg="'fullName' is not defined in schema 'Person'" - ) - ], - arg_msg="Cannot add member 'fullName' to schema 'Person'" - ), - file=sys.stdout -) diff --git a/test/grammar/schema/type/type_fail_5/stderr.golden b/test/grammar/schema/type/type_fail_5/stderr.golden new file mode 100644 index 000000000..dce612a99 --- /dev/null +++ b/test/grammar/schema/type/type_fail_5/stderr.golden @@ -0,0 +1,11 @@ +error[E2G22]: TypeError + --> ${CWD}/main.k:11:9 + | +11 | "firstName": {"key": "Alice"}, + | ^ expected str, got {str(key):str(Alice)} + | + --> ${CWD}/main.k:2:5 + | +2 | firstName: str + | ^ variable is defined here, its type is str, but got {str(key):str(Alice)} + | \ No newline at end of file diff --git a/test/grammar/schema/type/type_fail_5/stderr.golden.py b/test/grammar/schema/type/type_fail_5/stderr.golden.py deleted file mode 100644 index 461d3aee1..000000000 --- a/test/grammar/schema/type/type_fail_5/stderr.golden.py +++ /dev/null @@ -1,29 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.TypeError_Compile_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=2, - col_no=5, - indent_count=1, - arg_msg="expect str", - err_level=kcl_error.ErrLevel.ORDINARY - ), - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=11, - col_no=9, - arg_msg="got {str(key):str(Alice)}" - ) - ], - arg_msg="expect str, got {str(key):str(Alice)}" - ), - file=sys.stdout -) diff --git a/test/grammar/schema/type/type_fail_6/stderr.golden b/test/grammar/schema/type/type_fail_6/stderr.golden new file mode 100644 index 000000000..20329ba23 --- /dev/null +++ b/test/grammar/schema/type/type_fail_6/stderr.golden @@ -0,0 +1,22 @@ +error[E2G22]: TypeError + --> ${CWD}/main.k:7:15 + | +7 | "cards": {"error": "error"} + | ^ expected int, got str(error) + | + --> ${CWD}/main.k:3:5 + | +3 | cards: {str:int} + | ^ variable is defined here, its type is int, but got str(error) + | +error[E2G22]: TypeError + --> ${CWD}/main.k:7:5 + | +7 | "cards": {"error": "error"} + | ^ expected {str:int}, got {str(error):str(error)} + | + --> ${CWD}/main.k:3:5 + | +3 | cards: {str:int} + | ^ variable is defined here, its type is {str:int}, but got {str(error):str(error)} + | \ No newline at end of file diff --git a/test/grammar/schema/type/type_fail_6/stderr.golden.py b/test/grammar/schema/type/type_fail_6/stderr.golden.py deleted file mode 100644 index 7e8c12318..000000000 --- a/test/grammar/schema/type/type_fail_6/stderr.golden.py +++ /dev/null @@ -1,30 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.TypeError_Compile_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=3, - col_no=5, - indent_count=1, - arg_msg="expect int", - err_level=kcl_error.ErrLevel.ORDINARY - ), - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=7, - col_no=15, - arg_msg="got str(error)" - ) - ], - arg_msg="expect int, got str(error)" - ), - file=sys.stdout -) - diff --git a/test/grammar/schema/type/type_fail_7/stderr.golden b/test/grammar/schema/type/type_fail_7/stderr.golden new file mode 100644 index 000000000..8f0526378 --- /dev/null +++ b/test/grammar/schema/type/type_fail_7/stderr.golden @@ -0,0 +1,17 @@ +error[E2A31]: IllegalAttributeError + --> ${CWD}/main.k:7:15 + | +7 | "cards": {1: 1} + | ^ A attribute must be string type, got 'int(1)' + | +error[E2G22]: TypeError + --> ${CWD}/main.k:7:5 + | +7 | "cards": {1: 1} + | ^ expected {int:{int:any}}, got {int(1):int(1)} + | + --> ${CWD}/main.k:3:5 + | +3 | cards: {int:{int:}} + | ^ variable is defined here, its type is {int:{int:any}}, but got {int(1):int(1)} + | \ No newline at end of file diff --git a/test/grammar/schema/type/type_fail_7/stderr.golden.py b/test/grammar/schema/type/type_fail_7/stderr.golden.py deleted file mode 100644 index a03ed6d1f..000000000 --- a/test/grammar/schema/type/type_fail_7/stderr.golden.py +++ /dev/null @@ -1,30 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.TypeError_Compile_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=3, - col_no=5, - indent_count=1, - arg_msg="expect {int:any}", - err_level=kcl_error.ErrLevel.ORDINARY - ), - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=7, - col_no=15, - arg_msg="got int(1)" - ) - ], - arg_msg="expect {int:any}, got int(1)" - ), - file=sys.stdout -) - diff --git a/test/grammar/schema/type/type_fail_8/stderr.golden b/test/grammar/schema/type/type_fail_8/stderr.golden new file mode 100644 index 000000000..a706f5ab5 --- /dev/null +++ b/test/grammar/schema/type/type_fail_8/stderr.golden @@ -0,0 +1,28 @@ +error[E2G22]: TypeError + --> ${CWD}/main.k:7:18 + | +7 | "cards": {1:{"error":"error"}} + | ^ expected {int:any}, got str(error) + | + --> ${CWD}/main.k:3:5 + | +3 | cards : {int:{int:}} + | ^ variable is defined here, its type is {int:any}, but got str(error) + | +error[E2A31]: IllegalAttributeError + --> ${CWD}/main.k:7:15 + | +7 | "cards": {1:{"error":"error"}} + | ^ A attribute must be string type, got 'int(1)' + | +error[E2G22]: TypeError + --> ${CWD}/main.k:7:5 + | +7 | "cards": {1:{"error":"error"}} + | ^ expected {int:{int:any}}, got {int(1):{str(error):str(error)}} + | + --> ${CWD}/main.k:3:5 + | +3 | cards : {int:{int:}} + | ^ variable is defined here, its type is {int:{int:any}}, but got {int(1):{str(error):str(error)}} + | \ No newline at end of file diff --git a/test/grammar/schema/type/type_fail_8/stderr.golden.py b/test/grammar/schema/type/type_fail_8/stderr.golden.py deleted file mode 100644 index 2a9e33d00..000000000 --- a/test/grammar/schema/type/type_fail_8/stderr.golden.py +++ /dev/null @@ -1,29 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.TypeError_Compile_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=3, - col_no=5, - indent_count=1, - arg_msg="expect {int:any}", - err_level=kcl_error.ErrLevel.ORDINARY - ), - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=7, - col_no=15, - arg_msg="got {str(error):str(error)}" - ) - ], - arg_msg="expect {int:any}, got {str(error):str(error)}" - ), - file=sys.stdout -) diff --git a/test/grammar/schema/type/type_fail_9/stderr.golden b/test/grammar/schema/type/type_fail_9/stderr.golden new file mode 100644 index 000000000..2c483268b --- /dev/null +++ b/test/grammar/schema/type/type_fail_9/stderr.golden @@ -0,0 +1,11 @@ +error[E2G22]: TypeError + --> ${CWD}/main.k:7:5 + | +7 | "cards": 1 + | ^ expected [int], got int(1) + | + --> ${CWD}/main.k:3:5 + | +3 | cards: [int] + | ^ variable is defined here, its type is [int], but got int(1) + | \ No newline at end of file diff --git a/test/grammar/schema/type/type_fail_9/stderr.golden.py b/test/grammar/schema/type/type_fail_9/stderr.golden.py deleted file mode 100644 index 936db7c2b..000000000 --- a/test/grammar/schema/type/type_fail_9/stderr.golden.py +++ /dev/null @@ -1,29 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.TypeError_Compile_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=3, - col_no=5, - indent_count=1, - arg_msg="expect [int]", - err_level=kcl_error.ErrLevel.ORDINARY - ), - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=7, - col_no=5, - arg_msg="got int(1)" - ) - ], - arg_msg="expect [int], got int(1)" - ), - file=sys.stdout -) diff --git a/test/grammar/schema/type/type_fail_default_value_0/stderr.golden b/test/grammar/schema/type/type_fail_default_value_0/stderr.golden new file mode 100644 index 000000000..8fa1bd6ca --- /dev/null +++ b/test/grammar/schema/type/type_fail_default_value_0/stderr.golden @@ -0,0 +1,6 @@ +error[E2G22]: TypeError + --> ${CWD}/main.k:3:5 + | +3 | firstName: int = "John" + | ^ expected int, got str(John) + | \ No newline at end of file diff --git a/test/grammar/schema/type/type_fail_default_value_0/stderr.golden.py b/test/grammar/schema/type/type_fail_default_value_0/stderr.golden.py deleted file mode 100644 index 19121f6fc..000000000 --- a/test/grammar/schema/type/type_fail_default_value_0/stderr.golden.py +++ /dev/null @@ -1,22 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.TypeError_Compile_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=3, - col_no=5, - arg_msg="got str(John)" - ) - ], - arg_msg="expect int, got str(John)" - ), - file=sys.stdout -) - diff --git a/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid/stderr.golden b/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid/stderr.golden new file mode 100644 index 000000000..fb9f78508 --- /dev/null +++ b/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid/stderr.golden @@ -0,0 +1,7 @@ +error[E1001]: IllegalParameterError + --> ${CWD}/main.k:1:15 + | +1 | schema A[a1 = 100, a2, a3]: + | ^ non-default argument follows default argument + | +note: A default argument \ No newline at end of file diff --git a/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid/stderr.golden.py b/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid/stderr.golden.py deleted file mode 100644 index 2716275fd..000000000 --- a/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid/stderr.golden.py +++ /dev/null @@ -1,19 +0,0 @@ -import sys -import os - -import kclvm.kcl.error as kcl_error - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message(kcl_error.get_exception(err_type=kcl_error.ErrType.IllegalArgumentError_Syntax_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=1, - col_no=10, - end_col_no=18, - arg_msg="A default argument" - )], - arg_msg="non-default argument follows default argument" - ), - file=sys.stdout) diff --git a/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_0/stderr.golden b/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_0/stderr.golden new file mode 100644 index 000000000..b93c1aa0c --- /dev/null +++ b/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_0/stderr.golden @@ -0,0 +1,14 @@ +error[E1001]: IllegalParameterError + --> ${CWD}/main.k:1:25 + | +1 | schema A[a1 = 100, a2 = 200, a3]: + | ^ non-default argument follows default argument + | +note: A default argument +error[E1001]: IllegalParameterError + --> ${CWD}/main.k:1:15 + | +1 | schema A[a1 = 100, a2 = 200, a3]: + | ^ non-default argument follows default argument + | +note: A default argument \ No newline at end of file diff --git a/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_0/stderr.golden.py b/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_0/stderr.golden.py deleted file mode 100644 index 3685cf7c4..000000000 --- a/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_0/stderr.golden.py +++ /dev/null @@ -1,19 +0,0 @@ -import sys -import os - -import kclvm.kcl.error as kcl_error - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message(kcl_error.get_exception(err_type=kcl_error.ErrType.IllegalArgumentError_Syntax_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=1, - col_no=20, - end_col_no=28, - arg_msg="A default argument" - )], - arg_msg="non-default argument follows default argument" - ), - file=sys.stdout) diff --git a/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_1/stderr.golden b/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_1/stderr.golden new file mode 100644 index 000000000..74fcb8227 --- /dev/null +++ b/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_1/stderr.golden @@ -0,0 +1,7 @@ +error[E1001]: IllegalParameterError + --> ${CWD}/main.k:1:15 + | +1 | schema A[a1 = 100, a2, a3 = "300"]: + | ^ non-default argument follows default argument + | +note: A default argument \ No newline at end of file diff --git a/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_1/stderr.golden.py b/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_1/stderr.golden.py deleted file mode 100644 index 2716275fd..000000000 --- a/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_1/stderr.golden.py +++ /dev/null @@ -1,19 +0,0 @@ -import sys -import os - -import kclvm.kcl.error as kcl_error - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message(kcl_error.get_exception(err_type=kcl_error.ErrType.IllegalArgumentError_Syntax_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=1, - col_no=10, - end_col_no=18, - arg_msg="A default argument" - )], - arg_msg="non-default argument follows default argument" - ), - file=sys.stdout) diff --git a/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_10/stderr.golden b/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_10/stderr.golden new file mode 100644 index 000000000..90c431891 --- /dev/null +++ b/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_10/stderr.golden @@ -0,0 +1,7 @@ +error[E1001]: IllegalParameterError + --> ${CWD}/main.k:1:19 + | +1 | schema A[a1, a2 = 200, a3]: + | ^ non-default argument follows default argument + | +note: A default argument \ No newline at end of file diff --git a/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_10/stderr.golden.py b/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_10/stderr.golden.py deleted file mode 100644 index e846328c0..000000000 --- a/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_10/stderr.golden.py +++ /dev/null @@ -1,19 +0,0 @@ -import sys -import os - -import kclvm.kcl.error as kcl_error - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message(kcl_error.get_exception(err_type=kcl_error.ErrType.IllegalArgumentError_Syntax_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=1, - col_no=14, - end_col_no=22, - arg_msg="A default argument" - )], - arg_msg="non-default argument follows default argument" - ), - file=sys.stdout) diff --git a/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_11/stderr.golden b/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_11/stderr.golden new file mode 100644 index 000000000..a587fc8bd --- /dev/null +++ b/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_11/stderr.golden @@ -0,0 +1,13 @@ +error[E1001]: IllegalParameterError + --> ${CWD}/main.k:1:15 + | +1 | schema A[a1 = 100, a2, a3]: + | ^ non-default argument follows default argument + | +note: A default argument +error[E2L23]: CompileError + --> ${CWD}/main.k:7:5 + | +7 | a = A(a1=1,a2=2) + | ^ expected 2 positional arguments, found 1 + | \ No newline at end of file diff --git a/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_11/stderr.golden.py b/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_11/stderr.golden.py deleted file mode 100644 index 2716275fd..000000000 --- a/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_11/stderr.golden.py +++ /dev/null @@ -1,19 +0,0 @@ -import sys -import os - -import kclvm.kcl.error as kcl_error - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message(kcl_error.get_exception(err_type=kcl_error.ErrType.IllegalArgumentError_Syntax_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=1, - col_no=10, - end_col_no=18, - arg_msg="A default argument" - )], - arg_msg="non-default argument follows default argument" - ), - file=sys.stdout) diff --git a/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_12/stderr.golden b/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_12/stderr.golden new file mode 100644 index 000000000..31bb4907e --- /dev/null +++ b/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_12/stderr.golden @@ -0,0 +1,20 @@ +error[E1001]: IllegalParameterError + --> ${CWD}/main.k:1:25 + | +1 | schema A[a1 = 100, a2 = 200, a3]: + | ^ non-default argument follows default argument + | +note: A default argument +error[E1001]: IllegalParameterError + --> ${CWD}/main.k:1:15 + | +1 | schema A[a1 = 100, a2 = 200, a3]: + | ^ non-default argument follows default argument + | +note: A default argument +error[E2L23]: CompileError + --> ${CWD}/main.k:7:5 + | +7 | a = A(a1=1,a2=2) + | ^ expected 1 positional argument, found 0 + | \ No newline at end of file diff --git a/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_12/stderr.golden.py b/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_12/stderr.golden.py deleted file mode 100644 index 3685cf7c4..000000000 --- a/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_12/stderr.golden.py +++ /dev/null @@ -1,19 +0,0 @@ -import sys -import os - -import kclvm.kcl.error as kcl_error - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message(kcl_error.get_exception(err_type=kcl_error.ErrType.IllegalArgumentError_Syntax_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=1, - col_no=20, - end_col_no=28, - arg_msg="A default argument" - )], - arg_msg="non-default argument follows default argument" - ), - file=sys.stdout) diff --git a/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_13/stderr.golden b/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_13/stderr.golden new file mode 100644 index 000000000..74fcb8227 --- /dev/null +++ b/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_13/stderr.golden @@ -0,0 +1,7 @@ +error[E1001]: IllegalParameterError + --> ${CWD}/main.k:1:15 + | +1 | schema A[a1 = 100, a2, a3 = "300"]: + | ^ non-default argument follows default argument + | +note: A default argument \ No newline at end of file diff --git a/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_13/stderr.golden.py b/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_13/stderr.golden.py deleted file mode 100644 index 2716275fd..000000000 --- a/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_13/stderr.golden.py +++ /dev/null @@ -1,19 +0,0 @@ -import sys -import os - -import kclvm.kcl.error as kcl_error - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message(kcl_error.get_exception(err_type=kcl_error.ErrType.IllegalArgumentError_Syntax_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=1, - col_no=10, - end_col_no=18, - arg_msg="A default argument" - )], - arg_msg="non-default argument follows default argument" - ), - file=sys.stdout) diff --git a/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_14/stderr.golden b/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_14/stderr.golden new file mode 100644 index 000000000..c5ea5a514 --- /dev/null +++ b/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_14/stderr.golden @@ -0,0 +1,13 @@ +error[E1001]: IllegalParameterError + --> ${CWD}/main.k:1:19 + | +1 | schema A[a1, a2 = 200, a3]: + | ^ non-default argument follows default argument + | +note: A default argument +error[E2L23]: CompileError + --> ${CWD}/main.k:7:5 + | +7 | a = A(a1=1,a2=2) + | ^ expected 2 positional arguments, found 1 + | \ No newline at end of file diff --git a/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_14/stderr.golden.py b/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_14/stderr.golden.py deleted file mode 100644 index e846328c0..000000000 --- a/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_14/stderr.golden.py +++ /dev/null @@ -1,19 +0,0 @@ -import sys -import os - -import kclvm.kcl.error as kcl_error - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message(kcl_error.get_exception(err_type=kcl_error.ErrType.IllegalArgumentError_Syntax_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=1, - col_no=14, - end_col_no=22, - arg_msg="A default argument" - )], - arg_msg="non-default argument follows default argument" - ), - file=sys.stdout) diff --git a/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_15/stderr.golden b/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_15/stderr.golden new file mode 100644 index 000000000..750d3387c --- /dev/null +++ b/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_15/stderr.golden @@ -0,0 +1,13 @@ +error[E1001]: IllegalParameterError + --> ${CWD}/main.k:1:15 + | +1 | schema A[a1 = 100, a2, a3]: + | ^ non-default argument follows default argument + | +note: A default argument +error[E2L23]: CompileError + --> ${CWD}/main.k:7:5 + | +7 | a = A(a1=1) + | ^ expected 2 positional arguments, found 0 + | \ No newline at end of file diff --git a/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_15/stderr.golden.py b/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_15/stderr.golden.py deleted file mode 100644 index 2716275fd..000000000 --- a/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_15/stderr.golden.py +++ /dev/null @@ -1,19 +0,0 @@ -import sys -import os - -import kclvm.kcl.error as kcl_error - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message(kcl_error.get_exception(err_type=kcl_error.ErrType.IllegalArgumentError_Syntax_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=1, - col_no=10, - end_col_no=18, - arg_msg="A default argument" - )], - arg_msg="non-default argument follows default argument" - ), - file=sys.stdout) diff --git a/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_16/stderr.golden b/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_16/stderr.golden new file mode 100644 index 000000000..b16ef52f6 --- /dev/null +++ b/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_16/stderr.golden @@ -0,0 +1,20 @@ +error[E1001]: IllegalParameterError + --> ${CWD}/main.k:1:25 + | +1 | schema A[a1 = 100, a2 = 200, a3]: + | ^ non-default argument follows default argument + | +note: A default argument +error[E1001]: IllegalParameterError + --> ${CWD}/main.k:1:15 + | +1 | schema A[a1 = 100, a2 = 200, a3]: + | ^ non-default argument follows default argument + | +note: A default argument +error[E2L23]: CompileError + --> ${CWD}/main.k:7:5 + | +7 | a = A(a1=1) + | ^ expected 1 positional argument, found 0 + | \ No newline at end of file diff --git a/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_16/stderr.golden.py b/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_16/stderr.golden.py deleted file mode 100644 index 3685cf7c4..000000000 --- a/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_16/stderr.golden.py +++ /dev/null @@ -1,19 +0,0 @@ -import sys -import os - -import kclvm.kcl.error as kcl_error - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message(kcl_error.get_exception(err_type=kcl_error.ErrType.IllegalArgumentError_Syntax_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=1, - col_no=20, - end_col_no=28, - arg_msg="A default argument" - )], - arg_msg="non-default argument follows default argument" - ), - file=sys.stdout) diff --git a/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_17/stderr.golden b/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_17/stderr.golden new file mode 100644 index 000000000..fe66650d0 --- /dev/null +++ b/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_17/stderr.golden @@ -0,0 +1,13 @@ +error[E1001]: IllegalParameterError + --> ${CWD}/main.k:1:15 + | +1 | schema A[a1 = 100, a2, a3 = "300"]: + | ^ non-default argument follows default argument + | +note: A default argument +error[E2L23]: CompileError + --> ${CWD}/main.k:7:5 + | +7 | a = A(a1=1) + | ^ expected 1 positional argument, found 0 + | \ No newline at end of file diff --git a/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_17/stderr.golden.py b/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_17/stderr.golden.py deleted file mode 100644 index 2716275fd..000000000 --- a/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_17/stderr.golden.py +++ /dev/null @@ -1,19 +0,0 @@ -import sys -import os - -import kclvm.kcl.error as kcl_error - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message(kcl_error.get_exception(err_type=kcl_error.ErrType.IllegalArgumentError_Syntax_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=1, - col_no=10, - end_col_no=18, - arg_msg="A default argument" - )], - arg_msg="non-default argument follows default argument" - ), - file=sys.stdout) diff --git a/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_18/stderr.golden b/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_18/stderr.golden new file mode 100644 index 000000000..1f582032e --- /dev/null +++ b/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_18/stderr.golden @@ -0,0 +1,13 @@ +error[E1001]: IllegalParameterError + --> ${CWD}/main.k:1:19 + | +1 | schema A[a1, a2 = 200, a3]: + | ^ non-default argument follows default argument + | +note: A default argument +error[E2L23]: CompileError + --> ${CWD}/main.k:7:5 + | +7 | a = A(a1=1) + | ^ expected 2 positional arguments, found 1 + | \ No newline at end of file diff --git a/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_18/stderr.golden.py b/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_18/stderr.golden.py deleted file mode 100644 index e846328c0..000000000 --- a/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_18/stderr.golden.py +++ /dev/null @@ -1,19 +0,0 @@ -import sys -import os - -import kclvm.kcl.error as kcl_error - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message(kcl_error.get_exception(err_type=kcl_error.ErrType.IllegalArgumentError_Syntax_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=1, - col_no=14, - end_col_no=22, - arg_msg="A default argument" - )], - arg_msg="non-default argument follows default argument" - ), - file=sys.stdout) diff --git a/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_19/stderr.golden b/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_19/stderr.golden new file mode 100644 index 000000000..f1db9a405 --- /dev/null +++ b/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_19/stderr.golden @@ -0,0 +1,13 @@ +error[E1001]: IllegalParameterError + --> ${CWD}/main.k:1:15 + | +1 | schema A[a1 = 100, a2, a3]: + | ^ non-default argument follows default argument + | +note: A default argument +error[E2L23]: CompileError + --> ${CWD}/main.k:7:5 + | +7 | a = A(a2=2) + | ^ expected 2 positional arguments, found 1 + | \ No newline at end of file diff --git a/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_19/stderr.golden.py b/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_19/stderr.golden.py deleted file mode 100644 index 2716275fd..000000000 --- a/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_19/stderr.golden.py +++ /dev/null @@ -1,19 +0,0 @@ -import sys -import os - -import kclvm.kcl.error as kcl_error - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message(kcl_error.get_exception(err_type=kcl_error.ErrType.IllegalArgumentError_Syntax_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=1, - col_no=10, - end_col_no=18, - arg_msg="A default argument" - )], - arg_msg="non-default argument follows default argument" - ), - file=sys.stdout) diff --git a/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_2/stderr.golden b/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_2/stderr.golden new file mode 100644 index 000000000..90c431891 --- /dev/null +++ b/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_2/stderr.golden @@ -0,0 +1,7 @@ +error[E1001]: IllegalParameterError + --> ${CWD}/main.k:1:19 + | +1 | schema A[a1, a2 = 200, a3]: + | ^ non-default argument follows default argument + | +note: A default argument \ No newline at end of file diff --git a/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_2/stderr.golden.py b/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_2/stderr.golden.py deleted file mode 100644 index e846328c0..000000000 --- a/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_2/stderr.golden.py +++ /dev/null @@ -1,19 +0,0 @@ -import sys -import os - -import kclvm.kcl.error as kcl_error - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message(kcl_error.get_exception(err_type=kcl_error.ErrType.IllegalArgumentError_Syntax_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=1, - col_no=14, - end_col_no=22, - arg_msg="A default argument" - )], - arg_msg="non-default argument follows default argument" - ), - file=sys.stdout) diff --git a/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_20/stderr.golden b/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_20/stderr.golden new file mode 100644 index 000000000..8101790b0 --- /dev/null +++ b/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_20/stderr.golden @@ -0,0 +1,20 @@ +error[E1001]: IllegalParameterError + --> ${CWD}/main.k:1:25 + | +1 | schema A[a1 = 100, a2 = 200, a3]: + | ^ non-default argument follows default argument + | +note: A default argument +error[E1001]: IllegalParameterError + --> ${CWD}/main.k:1:15 + | +1 | schema A[a1 = 100, a2 = 200, a3]: + | ^ non-default argument follows default argument + | +note: A default argument +error[E2L23]: CompileError + --> ${CWD}/main.k:7:5 + | +7 | a = A(a2=2) + | ^ expected 1 positional argument, found 0 + | \ No newline at end of file diff --git a/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_20/stderr.golden.py b/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_20/stderr.golden.py deleted file mode 100644 index 3685cf7c4..000000000 --- a/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_20/stderr.golden.py +++ /dev/null @@ -1,19 +0,0 @@ -import sys -import os - -import kclvm.kcl.error as kcl_error - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message(kcl_error.get_exception(err_type=kcl_error.ErrType.IllegalArgumentError_Syntax_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=1, - col_no=20, - end_col_no=28, - arg_msg="A default argument" - )], - arg_msg="non-default argument follows default argument" - ), - file=sys.stdout) diff --git a/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_21/stderr.golden b/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_21/stderr.golden new file mode 100644 index 000000000..74fcb8227 --- /dev/null +++ b/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_21/stderr.golden @@ -0,0 +1,7 @@ +error[E1001]: IllegalParameterError + --> ${CWD}/main.k:1:15 + | +1 | schema A[a1 = 100, a2, a3 = "300"]: + | ^ non-default argument follows default argument + | +note: A default argument \ No newline at end of file diff --git a/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_21/stderr.golden.py b/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_21/stderr.golden.py deleted file mode 100644 index 2716275fd..000000000 --- a/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_21/stderr.golden.py +++ /dev/null @@ -1,19 +0,0 @@ -import sys -import os - -import kclvm.kcl.error as kcl_error - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message(kcl_error.get_exception(err_type=kcl_error.ErrType.IllegalArgumentError_Syntax_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=1, - col_no=10, - end_col_no=18, - arg_msg="A default argument" - )], - arg_msg="non-default argument follows default argument" - ), - file=sys.stdout) diff --git a/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_22/stderr.golden b/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_22/stderr.golden new file mode 100644 index 000000000..4917a8498 --- /dev/null +++ b/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_22/stderr.golden @@ -0,0 +1,13 @@ +error[E1001]: IllegalParameterError + --> ${CWD}/main.k:1:19 + | +1 | schema A[a1, a2 = 200, a3]: + | ^ non-default argument follows default argument + | +note: A default argument +error[E2L23]: CompileError + --> ${CWD}/main.k:7:5 + | +7 | a = A(a2=2) + | ^ expected 2 positional arguments, found 0 + | \ No newline at end of file diff --git a/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_22/stderr.golden.py b/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_22/stderr.golden.py deleted file mode 100644 index e846328c0..000000000 --- a/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_22/stderr.golden.py +++ /dev/null @@ -1,19 +0,0 @@ -import sys -import os - -import kclvm.kcl.error as kcl_error - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message(kcl_error.get_exception(err_type=kcl_error.ErrType.IllegalArgumentError_Syntax_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=1, - col_no=14, - end_col_no=22, - arg_msg="A default argument" - )], - arg_msg="non-default argument follows default argument" - ), - file=sys.stdout) diff --git a/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_23/stderr.golden b/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_23/stderr.golden new file mode 100644 index 000000000..a7f2d1fcb --- /dev/null +++ b/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_23/stderr.golden @@ -0,0 +1,13 @@ +error[E1001]: IllegalParameterError + --> ${CWD}/main.k:1:15 + | +1 | schema A[a1 = 100, a2, a3]: + | ^ non-default argument follows default argument + | +note: A default argument +error[E2L23]: CompileError + --> ${CWD}/main.k:7:5 + | +7 | a = A(a3="3") + | ^ expected 2 positional arguments, found 1 + | \ No newline at end of file diff --git a/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_23/stderr.golden.py b/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_23/stderr.golden.py deleted file mode 100644 index 2716275fd..000000000 --- a/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_23/stderr.golden.py +++ /dev/null @@ -1,19 +0,0 @@ -import sys -import os - -import kclvm.kcl.error as kcl_error - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message(kcl_error.get_exception(err_type=kcl_error.ErrType.IllegalArgumentError_Syntax_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=1, - col_no=10, - end_col_no=18, - arg_msg="A default argument" - )], - arg_msg="non-default argument follows default argument" - ), - file=sys.stdout) diff --git a/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_24/stderr.golden b/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_24/stderr.golden new file mode 100644 index 000000000..b93c1aa0c --- /dev/null +++ b/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_24/stderr.golden @@ -0,0 +1,14 @@ +error[E1001]: IllegalParameterError + --> ${CWD}/main.k:1:25 + | +1 | schema A[a1 = 100, a2 = 200, a3]: + | ^ non-default argument follows default argument + | +note: A default argument +error[E1001]: IllegalParameterError + --> ${CWD}/main.k:1:15 + | +1 | schema A[a1 = 100, a2 = 200, a3]: + | ^ non-default argument follows default argument + | +note: A default argument \ No newline at end of file diff --git a/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_24/stderr.golden.py b/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_24/stderr.golden.py deleted file mode 100644 index 3685cf7c4..000000000 --- a/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_24/stderr.golden.py +++ /dev/null @@ -1,19 +0,0 @@ -import sys -import os - -import kclvm.kcl.error as kcl_error - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message(kcl_error.get_exception(err_type=kcl_error.ErrType.IllegalArgumentError_Syntax_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=1, - col_no=20, - end_col_no=28, - arg_msg="A default argument" - )], - arg_msg="non-default argument follows default argument" - ), - file=sys.stdout) diff --git a/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_25/stderr.golden b/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_25/stderr.golden new file mode 100644 index 000000000..31b0b94ff --- /dev/null +++ b/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_25/stderr.golden @@ -0,0 +1,13 @@ +error[E1001]: IllegalParameterError + --> ${CWD}/main.k:1:15 + | +1 | schema A[a1 = 100, a2, a3 = "300"]: + | ^ non-default argument follows default argument + | +note: A default argument +error[E2L23]: CompileError + --> ${CWD}/main.k:7:5 + | +7 | a = A(a3="3") + | ^ expected 1 positional argument, found 0 + | \ No newline at end of file diff --git a/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_25/stderr.golden.py b/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_25/stderr.golden.py deleted file mode 100644 index 2716275fd..000000000 --- a/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_25/stderr.golden.py +++ /dev/null @@ -1,19 +0,0 @@ -import sys -import os - -import kclvm.kcl.error as kcl_error - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message(kcl_error.get_exception(err_type=kcl_error.ErrType.IllegalArgumentError_Syntax_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=1, - col_no=10, - end_col_no=18, - arg_msg="A default argument" - )], - arg_msg="non-default argument follows default argument" - ), - file=sys.stdout) diff --git a/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_26/stderr.golden b/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_26/stderr.golden new file mode 100644 index 000000000..d1abce386 --- /dev/null +++ b/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_26/stderr.golden @@ -0,0 +1,13 @@ +error[E1001]: IllegalParameterError + --> ${CWD}/main.k:1:19 + | +1 | schema A[a1, a2 = 200, a3]: + | ^ non-default argument follows default argument + | +note: A default argument +error[E2L23]: CompileError + --> ${CWD}/main.k:7:5 + | +7 | a = A(a3="3") + | ^ expected 2 positional arguments, found 1 + | \ No newline at end of file diff --git a/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_26/stderr.golden.py b/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_26/stderr.golden.py deleted file mode 100644 index e846328c0..000000000 --- a/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_26/stderr.golden.py +++ /dev/null @@ -1,19 +0,0 @@ -import sys -import os - -import kclvm.kcl.error as kcl_error - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message(kcl_error.get_exception(err_type=kcl_error.ErrType.IllegalArgumentError_Syntax_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=1, - col_no=14, - end_col_no=22, - arg_msg="A default argument" - )], - arg_msg="non-default argument follows default argument" - ), - file=sys.stdout) diff --git a/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_27/stderr.golden b/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_27/stderr.golden new file mode 100644 index 000000000..4a099e2c5 --- /dev/null +++ b/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_27/stderr.golden @@ -0,0 +1,13 @@ +error[E1001]: IllegalParameterError + --> ${CWD}/main.k:1:15 + | +1 | schema A[a1 = 100, a2, a3]: + | ^ non-default argument follows default argument + | +note: A default argument +error[E2L23]: CompileError + --> ${CWD}/main.k:7:5 + | +7 | a = A() + | ^ expected 2 positional arguments, found 0 + | \ No newline at end of file diff --git a/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_27/stderr.golden.py b/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_27/stderr.golden.py deleted file mode 100644 index 2716275fd..000000000 --- a/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_27/stderr.golden.py +++ /dev/null @@ -1,19 +0,0 @@ -import sys -import os - -import kclvm.kcl.error as kcl_error - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message(kcl_error.get_exception(err_type=kcl_error.ErrType.IllegalArgumentError_Syntax_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=1, - col_no=10, - end_col_no=18, - arg_msg="A default argument" - )], - arg_msg="non-default argument follows default argument" - ), - file=sys.stdout) diff --git a/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_28/stderr.golden b/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_28/stderr.golden new file mode 100644 index 000000000..5dcd3d463 --- /dev/null +++ b/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_28/stderr.golden @@ -0,0 +1,20 @@ +error[E1001]: IllegalParameterError + --> ${CWD}/main.k:1:25 + | +1 | schema A[a1 = 100, a2 = 200, a3]: + | ^ non-default argument follows default argument + | +note: A default argument +error[E1001]: IllegalParameterError + --> ${CWD}/main.k:1:15 + | +1 | schema A[a1 = 100, a2 = 200, a3]: + | ^ non-default argument follows default argument + | +note: A default argument +error[E2L23]: CompileError + --> ${CWD}/main.k:7:5 + | +7 | a = A() + | ^ expected 1 positional argument, found 0 + | \ No newline at end of file diff --git a/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_28/stderr.golden.py b/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_28/stderr.golden.py deleted file mode 100644 index 3685cf7c4..000000000 --- a/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_28/stderr.golden.py +++ /dev/null @@ -1,19 +0,0 @@ -import sys -import os - -import kclvm.kcl.error as kcl_error - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message(kcl_error.get_exception(err_type=kcl_error.ErrType.IllegalArgumentError_Syntax_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=1, - col_no=20, - end_col_no=28, - arg_msg="A default argument" - )], - arg_msg="non-default argument follows default argument" - ), - file=sys.stdout) diff --git a/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_29/stderr.golden b/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_29/stderr.golden new file mode 100644 index 000000000..bf0bb05f5 --- /dev/null +++ b/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_29/stderr.golden @@ -0,0 +1,13 @@ +error[E1001]: IllegalParameterError + --> ${CWD}/main.k:1:15 + | +1 | schema A[a1 = 100, a2, a3 = "300"]: + | ^ non-default argument follows default argument + | +note: A default argument +error[E2L23]: CompileError + --> ${CWD}/main.k:7:5 + | +7 | a = A() + | ^ expected 1 positional argument, found 0 + | \ No newline at end of file diff --git a/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_29/stderr.golden.py b/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_29/stderr.golden.py deleted file mode 100644 index 2716275fd..000000000 --- a/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_29/stderr.golden.py +++ /dev/null @@ -1,19 +0,0 @@ -import sys -import os - -import kclvm.kcl.error as kcl_error - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message(kcl_error.get_exception(err_type=kcl_error.ErrType.IllegalArgumentError_Syntax_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=1, - col_no=10, - end_col_no=18, - arg_msg="A default argument" - )], - arg_msg="non-default argument follows default argument" - ), - file=sys.stdout) diff --git a/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_3/stderr.golden b/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_3/stderr.golden new file mode 100644 index 000000000..fb9f78508 --- /dev/null +++ b/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_3/stderr.golden @@ -0,0 +1,7 @@ +error[E1001]: IllegalParameterError + --> ${CWD}/main.k:1:15 + | +1 | schema A[a1 = 100, a2, a3]: + | ^ non-default argument follows default argument + | +note: A default argument \ No newline at end of file diff --git a/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_3/stderr.golden.py b/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_3/stderr.golden.py deleted file mode 100644 index 2716275fd..000000000 --- a/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_3/stderr.golden.py +++ /dev/null @@ -1,19 +0,0 @@ -import sys -import os - -import kclvm.kcl.error as kcl_error - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message(kcl_error.get_exception(err_type=kcl_error.ErrType.IllegalArgumentError_Syntax_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=1, - col_no=10, - end_col_no=18, - arg_msg="A default argument" - )], - arg_msg="non-default argument follows default argument" - ), - file=sys.stdout) diff --git a/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_30/stderr.golden b/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_30/stderr.golden new file mode 100644 index 000000000..0d73d4b0c --- /dev/null +++ b/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_30/stderr.golden @@ -0,0 +1,13 @@ +error[E1001]: IllegalParameterError + --> ${CWD}/main.k:1:19 + | +1 | schema A[a1, a2 = 200, a3]: + | ^ non-default argument follows default argument + | +note: A default argument +error[E2L23]: CompileError + --> ${CWD}/main.k:7:5 + | +7 | a = A() + | ^ expected 2 positional arguments, found 0 + | \ No newline at end of file diff --git a/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_30/stderr.golden.py b/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_30/stderr.golden.py deleted file mode 100644 index e846328c0..000000000 --- a/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_30/stderr.golden.py +++ /dev/null @@ -1,19 +0,0 @@ -import sys -import os - -import kclvm.kcl.error as kcl_error - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message(kcl_error.get_exception(err_type=kcl_error.ErrType.IllegalArgumentError_Syntax_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=1, - col_no=14, - end_col_no=22, - arg_msg="A default argument" - )], - arg_msg="non-default argument follows default argument" - ), - file=sys.stdout) diff --git a/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_4/stderr.golden b/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_4/stderr.golden new file mode 100644 index 000000000..b93c1aa0c --- /dev/null +++ b/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_4/stderr.golden @@ -0,0 +1,14 @@ +error[E1001]: IllegalParameterError + --> ${CWD}/main.k:1:25 + | +1 | schema A[a1 = 100, a2 = 200, a3]: + | ^ non-default argument follows default argument + | +note: A default argument +error[E1001]: IllegalParameterError + --> ${CWD}/main.k:1:15 + | +1 | schema A[a1 = 100, a2 = 200, a3]: + | ^ non-default argument follows default argument + | +note: A default argument \ No newline at end of file diff --git a/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_4/stderr.golden.py b/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_4/stderr.golden.py deleted file mode 100644 index 3685cf7c4..000000000 --- a/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_4/stderr.golden.py +++ /dev/null @@ -1,19 +0,0 @@ -import sys -import os - -import kclvm.kcl.error as kcl_error - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message(kcl_error.get_exception(err_type=kcl_error.ErrType.IllegalArgumentError_Syntax_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=1, - col_no=20, - end_col_no=28, - arg_msg="A default argument" - )], - arg_msg="non-default argument follows default argument" - ), - file=sys.stdout) diff --git a/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_5/stderr.golden b/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_5/stderr.golden new file mode 100644 index 000000000..74fcb8227 --- /dev/null +++ b/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_5/stderr.golden @@ -0,0 +1,7 @@ +error[E1001]: IllegalParameterError + --> ${CWD}/main.k:1:15 + | +1 | schema A[a1 = 100, a2, a3 = "300"]: + | ^ non-default argument follows default argument + | +note: A default argument \ No newline at end of file diff --git a/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_5/stderr.golden.py b/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_5/stderr.golden.py deleted file mode 100644 index 2716275fd..000000000 --- a/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_5/stderr.golden.py +++ /dev/null @@ -1,19 +0,0 @@ -import sys -import os - -import kclvm.kcl.error as kcl_error - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message(kcl_error.get_exception(err_type=kcl_error.ErrType.IllegalArgumentError_Syntax_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=1, - col_no=10, - end_col_no=18, - arg_msg="A default argument" - )], - arg_msg="non-default argument follows default argument" - ), - file=sys.stdout) diff --git a/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_6/stderr.golden b/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_6/stderr.golden new file mode 100644 index 000000000..4aecd975f --- /dev/null +++ b/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_6/stderr.golden @@ -0,0 +1,13 @@ +error[E1001]: IllegalParameterError + --> ${CWD}/main.k:1:19 + | +1 | schema A[a1, a2 = 200, a3]: + | ^ non-default argument follows default argument + | +note: A default argument +error[E2L23]: CompileError + --> ${CWD}/main.k:7:5 + | +7 | a = A(a2=2,a3="3") + | ^ expected 2 positional arguments, found 1 + | \ No newline at end of file diff --git a/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_6/stderr.golden.py b/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_6/stderr.golden.py deleted file mode 100644 index e846328c0..000000000 --- a/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_6/stderr.golden.py +++ /dev/null @@ -1,19 +0,0 @@ -import sys -import os - -import kclvm.kcl.error as kcl_error - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message(kcl_error.get_exception(err_type=kcl_error.ErrType.IllegalArgumentError_Syntax_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=1, - col_no=14, - end_col_no=22, - arg_msg="A default argument" - )], - arg_msg="non-default argument follows default argument" - ), - file=sys.stdout) diff --git a/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_7/stderr.golden b/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_7/stderr.golden new file mode 100644 index 000000000..de9d0b08f --- /dev/null +++ b/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_7/stderr.golden @@ -0,0 +1,13 @@ +error[E1001]: IllegalParameterError + --> ${CWD}/main.k:1:15 + | +1 | schema A[a1 = 100, a2, a3]: + | ^ non-default argument follows default argument + | +note: A default argument +error[E2L23]: CompileError + --> ${CWD}/main.k:7:5 + | +7 | a = A(a1=1,a3="3") + | ^ expected 2 positional arguments, found 1 + | \ No newline at end of file diff --git a/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_7/stderr.golden.py b/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_7/stderr.golden.py deleted file mode 100644 index 2716275fd..000000000 --- a/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_7/stderr.golden.py +++ /dev/null @@ -1,19 +0,0 @@ -import sys -import os - -import kclvm.kcl.error as kcl_error - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message(kcl_error.get_exception(err_type=kcl_error.ErrType.IllegalArgumentError_Syntax_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=1, - col_no=10, - end_col_no=18, - arg_msg="A default argument" - )], - arg_msg="non-default argument follows default argument" - ), - file=sys.stdout) diff --git a/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_8/stderr.golden b/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_8/stderr.golden new file mode 100644 index 000000000..b93c1aa0c --- /dev/null +++ b/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_8/stderr.golden @@ -0,0 +1,14 @@ +error[E1001]: IllegalParameterError + --> ${CWD}/main.k:1:25 + | +1 | schema A[a1 = 100, a2 = 200, a3]: + | ^ non-default argument follows default argument + | +note: A default argument +error[E1001]: IllegalParameterError + --> ${CWD}/main.k:1:15 + | +1 | schema A[a1 = 100, a2 = 200, a3]: + | ^ non-default argument follows default argument + | +note: A default argument \ No newline at end of file diff --git a/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_8/stderr.golden.py b/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_8/stderr.golden.py deleted file mode 100644 index 3685cf7c4..000000000 --- a/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_8/stderr.golden.py +++ /dev/null @@ -1,19 +0,0 @@ -import sys -import os - -import kclvm.kcl.error as kcl_error - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message(kcl_error.get_exception(err_type=kcl_error.ErrType.IllegalArgumentError_Syntax_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=1, - col_no=20, - end_col_no=28, - arg_msg="A default argument" - )], - arg_msg="non-default argument follows default argument" - ), - file=sys.stdout) diff --git a/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_9/stderr.golden b/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_9/stderr.golden new file mode 100644 index 000000000..ee6c8f250 --- /dev/null +++ b/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_9/stderr.golden @@ -0,0 +1,13 @@ +error[E1001]: IllegalParameterError + --> ${CWD}/main.k:1:15 + | +1 | schema A[a1 = 100, a2, a3 = "300"]: + | ^ non-default argument follows default argument + | +note: A default argument +error[E2L23]: CompileError + --> ${CWD}/main.k:7:5 + | +7 | a = A(a1=1,a3="3") + | ^ expected 1 positional argument, found 0 + | \ No newline at end of file diff --git a/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_9/stderr.golden.py b/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_9/stderr.golden.py deleted file mode 100644 index 2716275fd..000000000 --- a/test/grammar/schema/type_annotation/defaults/default_values_not_full_invalid_9/stderr.golden.py +++ /dev/null @@ -1,19 +0,0 @@ -import sys -import os - -import kclvm.kcl.error as kcl_error - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message(kcl_error.get_exception(err_type=kcl_error.ErrType.IllegalArgumentError_Syntax_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=1, - col_no=10, - end_col_no=18, - arg_msg="A default argument" - )], - arg_msg="non-default argument follows default argument" - ), - file=sys.stdout) diff --git a/test/grammar/schema/type_annotation/type_annotation_inconsistent/stderr.golden b/test/grammar/schema/type_annotation/type_annotation_inconsistent/stderr.golden new file mode 100644 index 000000000..9b9b231d8 --- /dev/null +++ b/test/grammar/schema/type_annotation/type_annotation_inconsistent/stderr.golden @@ -0,0 +1,19 @@ +error[E2G22]: TypeError + --> ${CWD}/main.k:4:5 + | +4 | c: str = a3 + | ^ expected str, got int + | + +error[E2G22]: TypeError + --> ${CWD}/main.k:7:20 + | +7 | a = A(a1=1,a2=2,a3="3") + | ^ expected int, got str(3) + | + + --> ${CWD}/main.k:1:23 + | +1 | schema A[a1, a2: int, a3: int]: + | ^ variable is defined here, its type is int, but got str(3) + | diff --git a/test/grammar/schema/type_annotation/type_annotation_inconsistent/stderr.golden.py b/test/grammar/schema/type_annotation/type_annotation_inconsistent/stderr.golden.py deleted file mode 100644 index c1f9947a9..000000000 --- a/test/grammar/schema/type_annotation/type_annotation_inconsistent/stderr.golden.py +++ /dev/null @@ -1,18 +0,0 @@ -import sys -import os - -import kclvm.kcl.error as kcl_error - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message(kcl_error.get_exception(err_type=kcl_error.ErrType.TypeError_Compile_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - arg_msg="got int", - filename=cwd + "/main.k", - line_no=4, - col_no=5, - )], - arg_msg="expect str, got int" - ), - file=sys.stdout) diff --git a/test/grammar/schema/type_annotation/type_annotation_schema_2/main.k b/test/grammar/schema/type_annotation/type_annotation_schema_2/main.k new file mode 100644 index 000000000..8a577f18a --- /dev/null +++ b/test/grammar/schema/type_annotation/type_annotation_schema_2/main.k @@ -0,0 +1,11 @@ +schema ProviderFamily: + version: str + marketplace: bool = True + +providerFamily = lambda family: ProviderFamily -> ProviderFamily { + family +} + +v = providerFamily({ + version: "1.6.0" +}) diff --git a/test/grammar/schema/type_annotation/type_annotation_schema_2/stdout.golden b/test/grammar/schema/type_annotation/type_annotation_schema_2/stdout.golden new file mode 100644 index 000000000..67d7078bb --- /dev/null +++ b/test/grammar/schema/type_annotation/type_annotation_schema_2/stdout.golden @@ -0,0 +1,3 @@ +v: + version: '1.6.0' + marketplace: true diff --git a/test/grammar/schema/type_annotation/type_annotation_schema_3/main.k b/test/grammar/schema/type_annotation/type_annotation_schema_3/main.k new file mode 100644 index 000000000..544f1cb23 --- /dev/null +++ b/test/grammar/schema/type_annotation/type_annotation_schema_3/main.k @@ -0,0 +1,11 @@ +schema ProviderFamily: + version: str + marketplace: bool = True + +providerFamily = lambda -> ProviderFamily { + { + version: "1.6.0" + } +} + +v = providerFamily() diff --git a/test/grammar/schema/type_annotation/type_annotation_schema_3/stdout.golden b/test/grammar/schema/type_annotation/type_annotation_schema_3/stdout.golden new file mode 100644 index 000000000..67d7078bb --- /dev/null +++ b/test/grammar/schema/type_annotation/type_annotation_schema_3/stdout.golden @@ -0,0 +1,3 @@ +v: + version: '1.6.0' + marketplace: true diff --git a/test/grammar/schema/union/arguments/keyword_argument_0/main.k b/test/grammar/schema/union/arguments/keyword_argument_0/main.k new file mode 100644 index 000000000..2bc3701dd --- /dev/null +++ b/test/grammar/schema/union/arguments/keyword_argument_0/main.k @@ -0,0 +1,10 @@ +schema Person[separator]: + firstName: str = "John" + lastName: str + fullName: str = firstName + separator + lastName + +x = Person(separator=" ") {lastName = "Doe"} + +y = Person("-") {lastName = "Doe1"} + +z = x | y diff --git a/test/grammar/schema/union/arguments/keyword_argument_0/stdout.golden b/test/grammar/schema/union/arguments/keyword_argument_0/stdout.golden new file mode 100644 index 000000000..3ee6d5c90 --- /dev/null +++ b/test/grammar/schema/union/arguments/keyword_argument_0/stdout.golden @@ -0,0 +1,12 @@ +x: + firstName: John + lastName: Doe + fullName: John Doe +y: + firstName: John + lastName: Doe1 + fullName: John-Doe1 +z: + firstName: John + lastName: Doe1 + fullName: John-Doe1 diff --git a/test/grammar/schema/union/arguments/keyword_argument_1/main.k b/test/grammar/schema/union/arguments/keyword_argument_1/main.k new file mode 100644 index 000000000..601a9cd2c --- /dev/null +++ b/test/grammar/schema/union/arguments/keyword_argument_1/main.k @@ -0,0 +1,10 @@ +schema Person[separator]: + firstName: str = "John" + lastName: str + fullName: str = firstName + separator + lastName + +x = Person(" ") {lastName = "Doe"} + +y = Person(separator="-") {lastName = "Doe1"} + +z = x | y diff --git a/test/grammar/schema/union/arguments/keyword_argument_1/stdout.golden b/test/grammar/schema/union/arguments/keyword_argument_1/stdout.golden new file mode 100644 index 000000000..3ee6d5c90 --- /dev/null +++ b/test/grammar/schema/union/arguments/keyword_argument_1/stdout.golden @@ -0,0 +1,12 @@ +x: + firstName: John + lastName: Doe + fullName: John Doe +y: + firstName: John + lastName: Doe1 + fullName: John-Doe1 +z: + firstName: John + lastName: Doe1 + fullName: John-Doe1 diff --git a/test/grammar/schema/union/arguments/single_argument_0/main.k b/test/grammar/schema/union/arguments/single_argument_0/main.k new file mode 100644 index 000000000..422efd147 --- /dev/null +++ b/test/grammar/schema/union/arguments/single_argument_0/main.k @@ -0,0 +1,10 @@ +schema Person[separator]: + firstName: str = "John" + lastName: str + fullName: str = firstName + separator + lastName + +x = Person(" ") {lastName = "Doe"} + +y = Person("-") {lastName = "Doe1"} + +z = x | y diff --git a/test/grammar/schema/union/arguments/single_argument_0/stdout.golden b/test/grammar/schema/union/arguments/single_argument_0/stdout.golden new file mode 100644 index 000000000..3ee6d5c90 --- /dev/null +++ b/test/grammar/schema/union/arguments/single_argument_0/stdout.golden @@ -0,0 +1,12 @@ +x: + firstName: John + lastName: Doe + fullName: John Doe +y: + firstName: John + lastName: Doe1 + fullName: John-Doe1 +z: + firstName: John + lastName: Doe1 + fullName: John-Doe1 diff --git a/test/grammar/schema/union/arguments/single_argument_1/main.k b/test/grammar/schema/union/arguments/single_argument_1/main.k new file mode 100644 index 000000000..83a0f95d6 --- /dev/null +++ b/test/grammar/schema/union/arguments/single_argument_1/main.k @@ -0,0 +1,10 @@ +schema Person[separator]: + firstName: str = "John" + lastName: str + fullName: str = firstName + separator + lastName + +x = Person(" ") {lastName = "Doe"} + +y = {lastName = "Doe1"} + +z = x | y diff --git a/test/grammar/schema/union/arguments/single_argument_1/stdout.golden b/test/grammar/schema/union/arguments/single_argument_1/stdout.golden new file mode 100644 index 000000000..b981466f5 --- /dev/null +++ b/test/grammar/schema/union/arguments/single_argument_1/stdout.golden @@ -0,0 +1,10 @@ +x: + firstName: John + lastName: Doe + fullName: John Doe +y: + lastName: Doe1 +z: + firstName: John + lastName: Doe1 + fullName: John Doe1 diff --git a/test/grammar/schema/union/arguments/single_argument_2/main.k b/test/grammar/schema/union/arguments/single_argument_2/main.k new file mode 100644 index 000000000..b81ebc06c --- /dev/null +++ b/test/grammar/schema/union/arguments/single_argument_2/main.k @@ -0,0 +1,13 @@ +schema Person[separator]: + firstName: str = "John" + lastName: str + fullName: str = firstName + separator + lastName + +x = Person(" ") {lastName = "Doe"} + +y = Person("-") {lastName = "Doe1"} + +z = Person("*") { + **x + **y +} diff --git a/test/grammar/schema/union/arguments/single_argument_2/stdout.golden b/test/grammar/schema/union/arguments/single_argument_2/stdout.golden new file mode 100644 index 000000000..3ee6d5c90 --- /dev/null +++ b/test/grammar/schema/union/arguments/single_argument_2/stdout.golden @@ -0,0 +1,12 @@ +x: + firstName: John + lastName: Doe + fullName: John Doe +y: + firstName: John + lastName: Doe1 + fullName: John-Doe1 +z: + firstName: John + lastName: Doe1 + fullName: John-Doe1 diff --git a/test/grammar/schema/union/binary_union/bin_union_fail_0/stderr.golden b/test/grammar/schema/union/binary_union/bin_union_fail_0/stderr.golden new file mode 100644 index 000000000..05d1e423f --- /dev/null +++ b/test/grammar/schema/union/binary_union/bin_union_fail_0/stderr.golden @@ -0,0 +1,6 @@ +error[E2G22]: TypeError + --> ${CWD}/main.k:3:9 + | +3 | temp3 = temp1 | temp2 + | ^ unsupported operand type(s) for |: '[int]' and '{str:str}' + | \ No newline at end of file diff --git a/test/grammar/schema/union/binary_union/bin_union_fail_0/stderr.golden.py b/test/grammar/schema/union/binary_union/bin_union_fail_0/stderr.golden.py deleted file mode 100644 index 41071e1b2..000000000 --- a/test/grammar/schema/union/binary_union/bin_union_fail_0/stderr.golden.py +++ /dev/null @@ -1,19 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.CompileError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=3, - ) - ], - arg_msg="unsupported operand type(s) for |: '[int]' and '{str:str}'" - ), - file=sys.stdout -) \ No newline at end of file diff --git a/test/grammar/schema/union/binary_union/bin_union_fail_1/stderr.golden b/test/grammar/schema/union/binary_union/bin_union_fail_1/stderr.golden new file mode 100644 index 000000000..34b40ffe8 --- /dev/null +++ b/test/grammar/schema/union/binary_union/bin_union_fail_1/stderr.golden @@ -0,0 +1,6 @@ +error[E2G22]: TypeError + --> ${CWD}/main.k:3:9 + | +3 | temp3 = temp1 | temp2 + | ^ unsupported operand type(s) for |: '{str:str}' and '[int]' + | \ No newline at end of file diff --git a/test/grammar/schema/union/binary_union/bin_union_fail_1/stderr.golden.py b/test/grammar/schema/union/binary_union/bin_union_fail_1/stderr.golden.py deleted file mode 100644 index d9a8e1386..000000000 --- a/test/grammar/schema/union/binary_union/bin_union_fail_1/stderr.golden.py +++ /dev/null @@ -1,20 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.CompileError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=3, - ) - ], - arg_msg="unsupported operand type(s) for |: '{str:str}' and '[int]'" - ), - file=sys.stdout -) - diff --git a/test/grammar/schema/union/binary_union/bin_union_fail_2/stderr.golden b/test/grammar/schema/union/binary_union/bin_union_fail_2/stderr.golden new file mode 100644 index 000000000..fb22774f2 --- /dev/null +++ b/test/grammar/schema/union/binary_union/bin_union_fail_2/stderr.golden @@ -0,0 +1,6 @@ +error[E2G22]: TypeError + --> ${CWD}/main.k:10:7 + | +10 | val = {"key": "value"} | person + | ^ unsupported operand type(s) for |: '{str(key):str(value)}' and 'Person' + | \ No newline at end of file diff --git a/test/grammar/schema/union/binary_union/bin_union_fail_2/stderr.golden.py b/test/grammar/schema/union/binary_union/bin_union_fail_2/stderr.golden.py deleted file mode 100644 index f8ea7d50c..000000000 --- a/test/grammar/schema/union/binary_union/bin_union_fail_2/stderr.golden.py +++ /dev/null @@ -1,20 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.CompileError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=10, - ) - ], - arg_msg="unsupported operand type(s) for |: '{str(key):str(value)}' and 'Person'" - ), - file=sys.stdout -) - diff --git a/test/grammar/schema/union/binary_union/bin_union_fail_3/stderr.golden b/test/grammar/schema/union/binary_union/bin_union_fail_3/stderr.golden new file mode 100644 index 000000000..36a7f0ff9 --- /dev/null +++ b/test/grammar/schema/union/binary_union/bin_union_fail_3/stderr.golden @@ -0,0 +1,6 @@ +error[E2G22]: TypeError + --> ${CWD}/main.k:5:7 + | +5 | val = [1, 2, 3] | Person { + | ^ unsupported operand type(s) for |: '[int(1) | int(2) | int(3)]' and 'Person' + | \ No newline at end of file diff --git a/test/grammar/schema/union/binary_union/bin_union_fail_3/stderr.golden.py b/test/grammar/schema/union/binary_union/bin_union_fail_3/stderr.golden.py deleted file mode 100644 index 5ce4c6a12..000000000 --- a/test/grammar/schema/union/binary_union/bin_union_fail_3/stderr.golden.py +++ /dev/null @@ -1,20 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.CompileError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=5, - ) - ], - arg_msg="unsupported operand type(s) for |: '[int(1)|int(2)|int(3)]' and 'Person'" - ), - file=sys.stdout -) - diff --git a/test/grammar/schema/union/binary_union/bin_union_fail_4/stderr.golden b/test/grammar/schema/union/binary_union/bin_union_fail_4/stderr.golden new file mode 100644 index 000000000..ca882f3fb --- /dev/null +++ b/test/grammar/schema/union/binary_union/bin_union_fail_4/stderr.golden @@ -0,0 +1,6 @@ +error[E2L23]: CompileError + --> ${CWD}/main.k:10:5 + | +10 | err: "123" + | ^ Cannot add member 'err' to schema 'Person' + | \ No newline at end of file diff --git a/test/grammar/schema/union/binary_union/bin_union_fail_4/stderr.golden.py b/test/grammar/schema/union/binary_union/bin_union_fail_4/stderr.golden.py deleted file mode 100644 index 2f09924ce..000000000 --- a/test/grammar/schema/union/binary_union/bin_union_fail_4/stderr.golden.py +++ /dev/null @@ -1,19 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception(err_type=kcl_error.ErrType.CannotAddMembers_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=10, - col_no=5, - arg_msg="'err' is not defined in schema 'Person'" - ), - ], - arg_msg="Cannot add member 'err' to schema 'Person'") - , file=sys.stdout -) diff --git a/test/grammar/schema/union/fail/fail_0/stderr.golden b/test/grammar/schema/union/fail/fail_0/stderr.golden new file mode 100644 index 000000000..46ab2f860 --- /dev/null +++ b/test/grammar/schema/union/fail/fail_0/stderr.golden @@ -0,0 +1,6 @@ +error[E2G22]: TypeError + --> ${CWD}/main.k:2:1 + | +2 | _data |= {"key": "value"} + | ^ unsupported operand type(s) for |: '[int]' and '{str(key):str(value)}' + | \ No newline at end of file diff --git a/test/grammar/schema/union/fail/fail_0/stderr.golden.py b/test/grammar/schema/union/fail/fail_0/stderr.golden.py deleted file mode 100644 index 916ba80a6..000000000 --- a/test/grammar/schema/union/fail/fail_0/stderr.golden.py +++ /dev/null @@ -1,19 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.CompileError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=2 - ) - ], - arg_msg="unsupported operand type(s) for |=: '[int]' and '{str(key):str(value)}'" - ), - file=sys.stdout -) diff --git a/test/grammar/schema/union/fail/fail_1/stderr.golden b/test/grammar/schema/union/fail/fail_1/stderr.golden new file mode 100644 index 000000000..8776698df --- /dev/null +++ b/test/grammar/schema/union/fail/fail_1/stderr.golden @@ -0,0 +1,6 @@ +error[E2G22]: TypeError + --> ${CWD}/main.k:2:1 + | +2 | _data |= "value" + | ^ unsupported operand type(s) for |: '[int]' and 'str(value)' + | \ No newline at end of file diff --git a/test/grammar/schema/union/fail/fail_1/stderr.golden.py b/test/grammar/schema/union/fail/fail_1/stderr.golden.py deleted file mode 100644 index cec5cc65d..000000000 --- a/test/grammar/schema/union/fail/fail_1/stderr.golden.py +++ /dev/null @@ -1,19 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.CompileError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=2, - ) - ], - arg_msg="unsupported operand type(s) for |=: '[int]' and 'str(value)'" - ), - file=sys.stdout -) diff --git a/test/grammar/schema/union/fail/fail_2/stderr.golden b/test/grammar/schema/union/fail/fail_2/stderr.golden new file mode 100644 index 000000000..8169dd1b5 --- /dev/null +++ b/test/grammar/schema/union/fail/fail_2/stderr.golden @@ -0,0 +1 @@ +Cannot add member 'key' to schema 'Person' \ No newline at end of file diff --git a/test/grammar/schema/union/fail/fail_2/stderr.golden.py b/test/grammar/schema/union/fail/fail_2/stderr.golden.py deleted file mode 100644 index bea26c76d..000000000 --- a/test/grammar/schema/union/fail/fail_2/stderr.golden.py +++ /dev/null @@ -1,19 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception(err_type=kcl_error.ErrType.CannotAddMembers_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=5, - col_no=22, - arg_msg="'key' is not defined in schema 'Person'", - ), - ], - arg_msg="Cannot add member 'key' to schema 'Person'" - ) -) diff --git a/test/grammar/schema/union/fail/fail_3/stderr.golden b/test/grammar/schema/union/fail/fail_3/stderr.golden new file mode 100644 index 000000000..f0ad77c11 --- /dev/null +++ b/test/grammar/schema/union/fail/fail_3/stderr.golden @@ -0,0 +1,11 @@ +error[E2G22]: TypeError + --> ${CWD}/main.k:5:30 + | +5 | personB: Person = personA | {"name" = 123} + | ^ expected str, got int(123) + | + --> ${CWD}/main.k:2:5 + | +2 | name: str = "Alice" + | ^ variable is defined here, its type is str, but got int(123) + | \ No newline at end of file diff --git a/test/grammar/schema/union/fail/fail_3/stderr.golden.py b/test/grammar/schema/union/fail/fail_3/stderr.golden.py deleted file mode 100644 index be169371d..000000000 --- a/test/grammar/schema/union/fail/fail_3/stderr.golden.py +++ /dev/null @@ -1,30 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.TypeError_Compile_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=2, - col_no=5, - indent_count=1, - arg_msg="expect str", - err_level=kcl_error.ErrLevel.ORDINARY - ), - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=5, - col_no=30, - arg_msg="got int(123)" - ) - ], - arg_msg="expect str, got int(123)" - ), - file=sys.stdout -) - diff --git a/test/grammar/schema/union/fail/fail_4/stderr.golden b/test/grammar/schema/union/fail/fail_4/stderr.golden new file mode 100644 index 000000000..fc8c8a63f --- /dev/null +++ b/test/grammar/schema/union/fail/fail_4/stderr.golden @@ -0,0 +1,11 @@ +error[E2G22]: TypeError + --> ${CWD}/main.k:5:24 + | +5 | _personA = _personA | {"name" = 123.0} + | ^ expected str, got float(123) + | + --> ${CWD}/main.k:2:5 + | +2 | name: str = "Alice" + | ^ variable is defined here, its type is str, but got float(123) + | \ No newline at end of file diff --git a/test/grammar/schema/union/fail/fail_4/stderr.golden.py b/test/grammar/schema/union/fail/fail_4/stderr.golden.py deleted file mode 100644 index dd7a55d69..000000000 --- a/test/grammar/schema/union/fail/fail_4/stderr.golden.py +++ /dev/null @@ -1,30 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.TypeError_Compile_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=2, - col_no=5, - indent_count=1, - arg_msg="expect str", - err_level=kcl_error.ErrLevel.ORDINARY - ), - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=5, - col_no=24, - arg_msg="got float(123.0)" - ) - ], - arg_msg="expect str, got float(123.0)" - ), - file=sys.stdout -) - diff --git a/test/grammar/schema/union/list/init_0/main.k b/test/grammar/schema/union/list/init_0/main.k deleted file mode 100644 index 5df236323..000000000 --- a/test/grammar/schema/union/list/init_0/main.k +++ /dev/null @@ -1,31 +0,0 @@ -schema Group: - mixin [AGroupMixin] - nums: [{str:}] = [ - { - "id": "000", - "num": 0 - }, - { - "id": "001", - "num": 1 - } - ] - -schema AGroupMixin: - nums |= [ - { - "title": "A" - }, - { - "title": "B" - } - ] - -group = Group { - "nums": [ - {}, - { - "description": "A_000" - } - ] -} diff --git a/test/grammar/schema/union/list/init_0/stdout.golden b/test/grammar/schema/union/list/init_0/stdout.golden deleted file mode 100644 index 16d108930..000000000 --- a/test/grammar/schema/union/list/init_0/stdout.golden +++ /dev/null @@ -1,9 +0,0 @@ -group: - nums: - - id: '000' - num: 0 - title: A - - id: '001' - num: 1 - description: A_000 - title: B diff --git a/test/grammar/schema/union/list/schema_2/kcl.mod b/test/grammar/schema/union/list/schema_2/kcl.mod new file mode 100644 index 000000000..e69de29bb diff --git a/test/grammar/schema/union/list/schema_2/main.k b/test/grammar/schema/union/list/schema_2/main.k new file mode 100644 index 000000000..a7fe98f48 --- /dev/null +++ b/test/grammar/schema/union/list/schema_2/main.k @@ -0,0 +1,7 @@ +import temp + +schema FinalSchema: + _values: [temp.MySchema] = [{id: "hello"},{ id: "world" },{}] + finalValues: [temp.MySchema] = [v {someField = i} for i, v in _values] + +f = FinalSchema{} diff --git a/test/grammar/schema/union/list/schema_2/stdout.golden b/test/grammar/schema/union/list/schema_2/stdout.golden new file mode 100644 index 000000000..f37a90499 --- /dev/null +++ b/test/grammar/schema/union/list/schema_2/stdout.golden @@ -0,0 +1,8 @@ +f: + finalValues: + - id: hello + someField: 0 + - id: world + someField: 1 + - id: id + someField: 2 diff --git a/test/grammar/schema/union/list/schema_2/temp/temp.k b/test/grammar/schema/union/list/schema_2/temp/temp.k new file mode 100644 index 000000000..fa8c94cd4 --- /dev/null +++ b/test/grammar/schema/union/list/schema_2/temp/temp.k @@ -0,0 +1,3 @@ +schema MySchema: + id: str = "id" + someField?: int diff --git a/test/grammar/schema/union/list/variable_fail_0/stderr.golden b/test/grammar/schema/union/list/variable_fail_0/stderr.golden new file mode 100644 index 000000000..012724e0d --- /dev/null +++ b/test/grammar/schema/union/list/variable_fail_0/stderr.golden @@ -0,0 +1,12 @@ +error[E1001]: ImmutableError + --> ${CWD}/main.k:3:1 + | +3 | lists |= ["val", "value2"] + | ^ Immutable variable 'lists' is modified during compiling + | + --> ${CWD}/main.k:1:1 + | +1 | lists = ["va", "d"] + | ^ The variable 'lists' is declared here firstly + | +note: change the variable name to '_lists' to make it mutable \ No newline at end of file diff --git a/test/grammar/schema/union/list/variable_fail_0/stderr.golden.py b/test/grammar/schema/union/list/variable_fail_0/stderr.golden.py deleted file mode 100644 index 674b2e2aa..000000000 --- a/test/grammar/schema/union/list/variable_fail_0/stderr.golden.py +++ /dev/null @@ -1,17 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception(err_type=kcl_error.ErrType.ImmutableCompileError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=3, - col_no=1, - ), - ],) - , file=sys.stdout -) diff --git a/test/grammar/schema/union/schema/instance_0/main.k b/test/grammar/schema/union/schema/instance_0/main.k deleted file mode 100644 index 3f9344ece..000000000 --- a/test/grammar/schema/union/schema/instance_0/main.k +++ /dev/null @@ -1,28 +0,0 @@ -schema Name: - firstName?: str - lastName?: str - -schema Person: - name: Name = { - "firstName": "firstName", - "lastName": "lastName" - } - age: int = 0 - info: {str:str} = { - "card": "123" - } - -schema Boy(Person): - name: Name |= { - "firstName" = "John" - } - age: int = 18 - info: {str:str} |= { - "phoneNum": "123" - } - -JohnDoe = Boy { - "name": { - "lastName" = "Dow" - } -} diff --git a/test/grammar/schema/union/schema/instance_0/stdout.golden b/test/grammar/schema/union/schema/instance_0/stdout.golden deleted file mode 100644 index 8b47ea464..000000000 --- a/test/grammar/schema/union/schema/instance_0/stdout.golden +++ /dev/null @@ -1,8 +0,0 @@ -JohnDoe: - name: - firstName: John - lastName: Dow - age: 18 - info: - card: '123' - phoneNum: '123' \ No newline at end of file diff --git a/test/grammar/schema/union/schema/schema_0/main.k b/test/grammar/schema/union/schema/schema_0/main.k deleted file mode 100644 index 15b29cf0b..000000000 --- a/test/grammar/schema/union/schema/schema_0/main.k +++ /dev/null @@ -1,24 +0,0 @@ -schema Name: - firstName: str - lastName: str - -schema Person: - name: Name = { - "firstName": "firstName", - "lastName": "lastName" - } - age: int = 0 - info: {str:str} = { - "card": "123" - } - -schema Boy(Person): - name: Name |= { - "firstName" = "John" - } - age: int = 18 - info: {str:str} |= { - "phoneNum": "123" - } - -JohnDoe = Boy {} diff --git a/test/grammar/schema/union/schema/schema_0/stdout.golden b/test/grammar/schema/union/schema/schema_0/stdout.golden deleted file mode 100644 index fc9605f91..000000000 --- a/test/grammar/schema/union/schema/schema_0/stdout.golden +++ /dev/null @@ -1,8 +0,0 @@ -JohnDoe: - name: - firstName: John - lastName: lastName - age: 18 - info: - card: '123' - phoneNum: '123' \ No newline at end of file diff --git a/test/grammar/schema/union/variable_fail/int/stderr.golden b/test/grammar/schema/union/variable_fail/int/stderr.golden new file mode 100644 index 000000000..22349a031 --- /dev/null +++ b/test/grammar/schema/union/variable_fail/int/stderr.golden @@ -0,0 +1,12 @@ +error[E1001]: ImmutableError + --> ${CWD}/main.k:4:1 + | +4 | a |= 20 + | ^ Immutable variable 'a' is modified during compiling + | + --> ${CWD}/main.k:3:1 + | +3 | a = 5 + | ^ The variable 'a' is declared here firstly + | +note: change the variable name to '_a' to make it mutable \ No newline at end of file diff --git a/test/grammar/schema/union/variable_fail/int/stderr.golden.py b/test/grammar/schema/union/variable_fail/int/stderr.golden.py deleted file mode 100644 index 3eda7e065..000000000 --- a/test/grammar/schema/union/variable_fail/int/stderr.golden.py +++ /dev/null @@ -1,17 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception(err_type=kcl_error.ErrType.ImmutableCompileError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=4, - col_no=1 - ), - ]) - , file=sys.stdout -) diff --git a/test/grammar/schema/union/variable_fail/list/stderr.golden b/test/grammar/schema/union/variable_fail/list/stderr.golden new file mode 100644 index 000000000..6518a9982 --- /dev/null +++ b/test/grammar/schema/union/variable_fail/list/stderr.golden @@ -0,0 +1,12 @@ +error[E1001]: ImmutableError + --> ${CWD}/main.k:2:1 + | +2 | lists1 |= [5] + | ^ Immutable variable 'lists1' is modified during compiling + | + --> ${CWD}/main.k:1:1 + | +1 | lists1 = [1,2,3] + | ^ The variable 'lists1' is declared here firstly + | +note: change the variable name to '_lists1' to make it mutable \ No newline at end of file diff --git a/test/grammar/schema/union/variable_fail/list/stderr.golden.py b/test/grammar/schema/union/variable_fail/list/stderr.golden.py deleted file mode 100644 index f861b1242..000000000 --- a/test/grammar/schema/union/variable_fail/list/stderr.golden.py +++ /dev/null @@ -1,17 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception(err_type=kcl_error.ErrType.ImmutableCompileError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=2, - col_no=1, - ), - ],) - , file=sys.stdout -) diff --git a/test/grammar/schema/var_not_define_fail/var_not_define_fail_0/main.k b/test/grammar/schema/var_not_define_fail/var_not_define_fail_0/main.k new file mode 100644 index 000000000..b426e207e --- /dev/null +++ b/test/grammar/schema/var_not_define_fail/var_not_define_fail_0/main.k @@ -0,0 +1,11 @@ +import regex + +schema Base: + cc: int = 1 + +schema Person(Base): + image: str + + check: + regex.match(image, "^[a-zA-Z]+:\d+\.\d+\.\d+$"), "image name should be like 'nginx:1.14.2'" + ccc > 2 diff --git a/test/grammar/schema/var_not_define_fail/var_not_define_fail_0/stderr.golden b/test/grammar/schema/var_not_define_fail/var_not_define_fail_0/stderr.golden new file mode 100644 index 000000000..a7506676f --- /dev/null +++ b/test/grammar/schema/var_not_define_fail/var_not_define_fail_0/stderr.golden @@ -0,0 +1,6 @@ +error[E2L23]: CompileError + --> ${CWD}/main.k:11:9 + | +11 | ccc > 2 + | ^ name 'ccc' is not defined + | \ No newline at end of file diff --git a/test/grammar/schema/var_not_define_fail/var_not_define_fail_1/main.k b/test/grammar/schema/var_not_define_fail/var_not_define_fail_1/main.k new file mode 100644 index 000000000..aa4e34e3f --- /dev/null +++ b/test/grammar/schema/var_not_define_fail/var_not_define_fail_1/main.k @@ -0,0 +1,8 @@ +schema Base: + cc: int = 1 + +schema Person(Base): + image: str + + check: + regex.match(image, "^[a-zA-Z]+:\d+\.\d+\.\d+$"), "image name should be like 'nginx:1.14.2'" diff --git a/test/grammar/schema/var_not_define_fail/var_not_define_fail_1/stderr.golden b/test/grammar/schema/var_not_define_fail/var_not_define_fail_1/stderr.golden new file mode 100644 index 000000000..72fa58bc0 --- /dev/null +++ b/test/grammar/schema/var_not_define_fail/var_not_define_fail_1/stderr.golden @@ -0,0 +1,6 @@ +error[E2L23]: CompileError + --> ${CWD}/main.k:8:9 + | +8 | regex.match(image, "^[a-zA-Z]+:\d+\.\d+\.\d+$"), "image name should be like 'nginx:1.14.2'" + | ^ name 'regex' is not defined + | \ No newline at end of file diff --git a/test/grammar/show_hidden/config/main.k b/test/grammar/show_hidden/config/main.k new file mode 100644 index 000000000..3437290d8 --- /dev/null +++ b/test/grammar/show_hidden/config/main.k @@ -0,0 +1 @@ +a = {_b = 1} diff --git a/test/grammar/show_hidden/config/settings.yaml b/test/grammar/show_hidden/config/settings.yaml new file mode 100644 index 000000000..7c23f622a --- /dev/null +++ b/test/grammar/show_hidden/config/settings.yaml @@ -0,0 +1 @@ +kcl_options: --show_hidden diff --git a/test/grammar/show_hidden/config/stdout.golden b/test/grammar/show_hidden/config/stdout.golden new file mode 100644 index 000000000..d167dd546 --- /dev/null +++ b/test/grammar/show_hidden/config/stdout.golden @@ -0,0 +1,2 @@ +a: + _b: 1 diff --git a/test/grammar/show_hidden/schema/main.k b/test/grammar/show_hidden/schema/main.k new file mode 100644 index 000000000..be064edb3 --- /dev/null +++ b/test/grammar/show_hidden/schema/main.k @@ -0,0 +1,4 @@ +schema Data: + [...str]: int + +a = Data {_b = 1} diff --git a/test/grammar/show_hidden/schema/settings.yaml b/test/grammar/show_hidden/schema/settings.yaml new file mode 100644 index 000000000..7c23f622a --- /dev/null +++ b/test/grammar/show_hidden/schema/settings.yaml @@ -0,0 +1 @@ +kcl_options: --show_hidden diff --git a/test/grammar/show_hidden/schema/stdout.golden b/test/grammar/show_hidden/schema/stdout.golden new file mode 100644 index 000000000..d167dd546 --- /dev/null +++ b/test/grammar/show_hidden/schema/stdout.golden @@ -0,0 +1,2 @@ +a: + _b: 1 diff --git a/test/grammar/show_hidden/simple/main.k b/test/grammar/show_hidden/simple/main.k new file mode 100644 index 000000000..ea1b2cfee --- /dev/null +++ b/test/grammar/show_hidden/simple/main.k @@ -0,0 +1,2 @@ +_b = 1 +a = 2 diff --git a/test/grammar/show_hidden/simple/settings.yaml b/test/grammar/show_hidden/simple/settings.yaml new file mode 100644 index 000000000..7c23f622a --- /dev/null +++ b/test/grammar/show_hidden/simple/settings.yaml @@ -0,0 +1 @@ +kcl_options: --show_hidden diff --git a/test/grammar/show_hidden/simple/stdout.golden b/test/grammar/show_hidden/simple/stdout.golden new file mode 100644 index 000000000..b4180cd89 --- /dev/null +++ b/test/grammar/show_hidden/simple/stdout.golden @@ -0,0 +1,2 @@ +_b: 1 +a: 2 diff --git a/test/grammar/sort_keys/config/main.k b/test/grammar/sort_keys/config/main.k new file mode 100644 index 000000000..4d1b2cda2 --- /dev/null +++ b/test/grammar/sort_keys/config/main.k @@ -0,0 +1,4 @@ +c = { + b = 1 + a = 2 +} diff --git a/test/grammar/sort_keys/config/settings.yaml b/test/grammar/sort_keys/config/settings.yaml new file mode 100644 index 000000000..c35040c35 --- /dev/null +++ b/test/grammar/sort_keys/config/settings.yaml @@ -0,0 +1 @@ +kcl_options: -d --sort_keys diff --git a/test/grammar/sort_keys/config/stdout.golden b/test/grammar/sort_keys/config/stdout.golden new file mode 100644 index 000000000..88df2d698 --- /dev/null +++ b/test/grammar/sort_keys/config/stdout.golden @@ -0,0 +1,3 @@ +c: + a: 2 + b: 1 diff --git a/test/grammar/sort_keys/hello/settings.yaml b/test/grammar/sort_keys/hello/settings.yaml index a27cb7724..c35040c35 100644 --- a/test/grammar/sort_keys/hello/settings.yaml +++ b/test/grammar/sort_keys/hello/settings.yaml @@ -1 +1 @@ -kcl_options: -d --sort +kcl_options: -d --sort_keys diff --git a/test/grammar/sort_keys/schema/main.k b/test/grammar/sort_keys/schema/main.k new file mode 100644 index 000000000..a09337391 --- /dev/null +++ b/test/grammar/sort_keys/schema/main.k @@ -0,0 +1,8 @@ +schema X: + b: int + a: int + +c = X { + b = 1 + a = 2 +} diff --git a/test/grammar/sort_keys/schema/settings.yaml b/test/grammar/sort_keys/schema/settings.yaml new file mode 100644 index 000000000..c35040c35 --- /dev/null +++ b/test/grammar/sort_keys/schema/settings.yaml @@ -0,0 +1 @@ +kcl_options: -d --sort_keys diff --git a/test/grammar/sort_keys/schema/stdout.golden b/test/grammar/sort_keys/schema/stdout.golden new file mode 100644 index 000000000..88df2d698 --- /dev/null +++ b/test/grammar/sort_keys/schema/stdout.golden @@ -0,0 +1,3 @@ +c: + a: 2 + b: 1 diff --git a/test/grammar/syntax/else_if_token/main.k b/test/grammar/syntax/else_if_token/main.k new file mode 100644 index 000000000..ca259cb9f --- /dev/null +++ b/test/grammar/syntax/else_if_token/main.k @@ -0,0 +1,4 @@ +if True: + a = 1 +else if False: + b = 1 diff --git a/test/grammar/syntax/else_if_token/stderr.golden b/test/grammar/syntax/else_if_token/stderr.golden new file mode 100644 index 000000000..be7deb06e --- /dev/null +++ b/test/grammar/syntax/else_if_token/stderr.golden @@ -0,0 +1,6 @@ +error[E1001]: InvalidSyntax + --> ${CWD}/main.k:3:1 + | +3 | else if False: + | 'else if' here is invalid in KCL, consider using the 'elif' keyword + | diff --git a/test/grammar/syntax/general/multiple_assign/case0/stderr.golden b/test/grammar/syntax/general/multiple_assign/case0/stderr.golden new file mode 100644 index 000000000..073dab06e --- /dev/null +++ b/test/grammar/syntax/general/multiple_assign/case0/stderr.golden @@ -0,0 +1,6 @@ +error[E1001]: InvalidSyntax + --> ${CWD}/main.k:1:6 + | +1 | a = 1, 2 + | ^ unexpected token ',' + | \ No newline at end of file diff --git a/test/grammar/syntax/general/multiple_assign/case0/stderr.golden.py b/test/grammar/syntax/general/multiple_assign/case0/stderr.golden.py deleted file mode 100644 index 2a94b0170..000000000 --- a/test/grammar/syntax/general/multiple_assign/case0/stderr.golden.py +++ /dev/null @@ -1,16 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message(kcl_error.get_exception(err_type=kcl_error.ErrType.InvalidSyntax_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=1, - col_no=6, - arg_msg="Expected one of ['newline']" - )], - ), - file=sys.stdout) diff --git a/test/grammar/syntax/general/multiple_assign/case1/stderr.golden b/test/grammar/syntax/general/multiple_assign/case1/stderr.golden new file mode 100644 index 000000000..e12fe8a42 --- /dev/null +++ b/test/grammar/syntax/general/multiple_assign/case1/stderr.golden @@ -0,0 +1,18 @@ +error[E1001]: InvalidSyntax + --> ${CWD}/main.k:1:2 + | +1 | a, b = 1, 2 + | ^ unexpected token ',' + | +error[E1001]: InvalidSyntax + --> ${CWD}/main.k:1:9 + | +1 | a, b = 1, 2 + | ^ unexpected token ',' + | +error[E2L23]: CompileError + --> ${CWD}/main.k:1:1 + | +1 | a, b = 1, 2 + | ^ name 'a' is not defined + | \ No newline at end of file diff --git a/test/grammar/syntax/general/multiple_assign/case1/stderr.golden.py b/test/grammar/syntax/general/multiple_assign/case1/stderr.golden.py deleted file mode 100644 index c6623a871..000000000 --- a/test/grammar/syntax/general/multiple_assign/case1/stderr.golden.py +++ /dev/null @@ -1,16 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message(kcl_error.get_exception(err_type=kcl_error.ErrType.InvalidSyntax_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=1, - col_no=6, - arg_msg="Expected one of [',', 'newline']" - )], - ), - file=sys.stdout) diff --git a/test/grammar/syntax/general/unnamed/case0/stderr.golden b/test/grammar/syntax/general/unnamed/case0/stderr.golden new file mode 100644 index 000000000..44200c46b --- /dev/null +++ b/test/grammar/syntax/general/unnamed/case0/stderr.golden @@ -0,0 +1,12 @@ +error[E1001]: InvalidSyntax + --> ${CWD}/main.k:1:3 + | +1 | a== + | ^ expected one of ["identifier", "literal", "(", "[", "{"] got newline + | +error[E2L23]: CompileError + --> ${CWD}/main.k:1:1 + | +1 | a== + | ^ name 'a' is not defined + | \ No newline at end of file diff --git a/test/grammar/syntax/general/unnamed/case0/stderr.golden.py b/test/grammar/syntax/general/unnamed/case0/stderr.golden.py deleted file mode 100644 index 1e99db1a1..000000000 --- a/test/grammar/syntax/general/unnamed/case0/stderr.golden.py +++ /dev/null @@ -1,21 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message(kcl_error.get_exception(err_type=kcl_error.ErrType.InvalidSyntax_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=1, - col_no=4, - arg_msg="Expected one of ['all', 'any', " - "'bin_number', 'dec_number', 'False', " - "'filter', 'float_number', 'hex_number', 'lambda', " - "'{', '[', '(', 'long_string', 'not', 'map', " - "'-', 'name', 'None', '~', 'oct_number', '+" - "', 'string', 'True', 'Undefined']", - )], - ), - file=sys.stdout) diff --git a/test/grammar/syntax/indent/indent_error_0/stderr.golden b/test/grammar/syntax/indent/indent_error_0/stderr.golden new file mode 100644 index 000000000..327bd0a7e --- /dev/null +++ b/test/grammar/syntax/indent/indent_error_0/stderr.golden @@ -0,0 +1,12 @@ +error[E1001]: InvalidSyntax + --> ${CWD}/main.k:3:4 + | +3 | age: int + | ^ invalid indentation with 3 spaces, try to align indents by adding or removing spaces + | +error[E1001]: InvalidSyntax + --> ${CWD}/main.k:4:3 + | +4 | info: str + | ^ invalid indentation with 2 spaces, try to align indents by adding or removing spaces + | \ No newline at end of file diff --git a/test/grammar/syntax/indent/indent_error_0/stderr.golden.py b/test/grammar/syntax/indent/indent_error_0/stderr.golden.py deleted file mode 100644 index 5a9a8bf1f..000000000 --- a/test/grammar/syntax/indent/indent_error_0/stderr.golden.py +++ /dev/null @@ -1,18 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception(err_type=kcl_error.ErrType.IndentationError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=3, - col_no=4, - ) - ], - arg_msg=kcl_error.INDENTATION_ERROR_MSG.format("3")), - file=sys.stdout -) diff --git a/test/grammar/syntax/indent/indent_error_1/stderr.golden b/test/grammar/syntax/indent/indent_error_1/stderr.golden new file mode 100644 index 000000000..ad007b1cd --- /dev/null +++ b/test/grammar/syntax/indent/indent_error_1/stderr.golden @@ -0,0 +1,6 @@ +error[E1001]: InvalidSyntax + --> ${CWD}/main.k:4:3 + | +4 | c = 3 + | ^ invalid indentation with 2 spaces, try to align indents by adding or removing spaces + | \ No newline at end of file diff --git a/test/grammar/syntax/indent/indent_error_1/stderr.golden.py b/test/grammar/syntax/indent/indent_error_1/stderr.golden.py deleted file mode 100644 index d59809ba1..000000000 --- a/test/grammar/syntax/indent/indent_error_1/stderr.golden.py +++ /dev/null @@ -1,18 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception(err_type=kcl_error.ErrType.IndentationError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=4, - col_no=3, - ) - ], - arg_msg=kcl_error.INDENTATION_ERROR_MSG.format("2")), - file=sys.stdout -) \ No newline at end of file diff --git a/test/grammar/syntax/tab/tab_error_0/stderr.golden b/test/grammar/syntax/tab/tab_error_0/stderr.golden new file mode 100644 index 000000000..f57157101 --- /dev/null +++ b/test/grammar/syntax/tab/tab_error_0/stderr.golden @@ -0,0 +1,6 @@ +error[E1001]: InvalidSyntax + --> ${CWD}/main.k:3:2 + | +3 | age: int + | ^ inconsistent use of tabs and spaces in indentation + | \ No newline at end of file diff --git a/test/grammar/syntax/tab/tab_error_0/stderr.golden.py b/test/grammar/syntax/tab/tab_error_0/stderr.golden.py deleted file mode 100644 index 69ef274f5..000000000 --- a/test/grammar/syntax/tab/tab_error_0/stderr.golden.py +++ /dev/null @@ -1,17 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception(err_type=kcl_error.ErrType.TabError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=3, - col_no=2, - ) - ]), - file=sys.stdout -) diff --git a/test/grammar/syntax/tab/tab_error_1/stderr.golden b/test/grammar/syntax/tab/tab_error_1/stderr.golden new file mode 100644 index 000000000..6c717017e --- /dev/null +++ b/test/grammar/syntax/tab/tab_error_1/stderr.golden @@ -0,0 +1,6 @@ +error[E1001]: InvalidSyntax + --> ${CWD}/main.k:4:2 + | +4 | c = 3 + | ^ inconsistent use of tabs and spaces in indentation + | \ No newline at end of file diff --git a/test/grammar/syntax/tab/tab_error_1/stderr.golden.py b/test/grammar/syntax/tab/tab_error_1/stderr.golden.py deleted file mode 100644 index 1c17a5c34..000000000 --- a/test/grammar/syntax/tab/tab_error_1/stderr.golden.py +++ /dev/null @@ -1,15 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message(kcl_error.get_exception(err_type=kcl_error.ErrType.TabError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=4, - col_no=2 - )], - ) - , file=sys.stdout) diff --git a/test/grammar/syntax/underline/main.k b/test/grammar/syntax/underline/main.k new file mode 100644 index 000000000..839a15078 --- /dev/null +++ b/test/grammar/syntax/underline/main.k @@ -0,0 +1 @@ +a = __b \ No newline at end of file diff --git a/test/grammar/syntax/underline/stderr.golden b/test/grammar/syntax/underline/stderr.golden new file mode 100644 index 000000000..69f95e09a --- /dev/null +++ b/test/grammar/syntax/underline/stderr.golden @@ -0,0 +1 @@ +name '__b' is not defined \ No newline at end of file diff --git a/test/grammar/test_grammar.py b/test/grammar/test_grammar.py deleted file mode 100644 index a6fbec652..000000000 --- a/test/grammar/test_grammar.py +++ /dev/null @@ -1,138 +0,0 @@ -"""This is a scripts to run KCL grammar test cases""" -import pytest -import os -import subprocess -import re -import yaml -import pathlib - -TEST_FILE = "main.k" -STDOUT_GOLDEN = "stdout.golden" -STDERR_GOLDEN = "stderr.golden" -STDOUT_GOLDEN_PY = "stdout.golden.py" -STDERR_GOLDEN_PY = "stderr.golden.py" -SETTINGS_FILE = "settings.yaml" - - -def find_test_dirs(path, category): - result = [] - for root, dirs, files in os.walk(path + category): - for name in files: - if name == "main.k": - result.append(root) - return result - - -def compare_strings(result_strings, golden_strings): - assert result_strings == golden_strings - - -def compare_results(result, golden_result): - """Convert bytestring (result) and list of strings (golden_lines) both to - list of strings with line ending stripped, then compare. - """ - - result_strings = result.decode().split("\n") - golden_strings = golden_result.decode().split("\n") - compare_strings(result_strings, golden_strings) - - -def compare_results_with_lines(result, golden_lines): - """Convert bytestring (result) and list of strings (golden_lines) both to - list of strings with line ending stripped, then compare. - """ - - result_strings = result.decode().split("\n") - golden_strings = [] - for line in golden_lines: - clean_line = re.sub("\n$", "", line) - golden_strings.append(clean_line) - # List generated by split() has an ending empty string, when the '\n' is - # the last character - assert result_strings[-1] == "", "The result string does not end with a NEWLINE" - golden_strings.append("") - compare_strings(result_strings, golden_strings) - - -def generate_golden_file(py_file_name): - if os.path.isfile(py_file_name): - try: - process = subprocess.Popen( - ["kclvm", py_file_name], - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - env=dict(os.environ), - ) - stdout, stderr = process.communicate() - assert ( - process.returncode == 0 - ), "Error executing file {}, exit code = {}".format( - py_file_name, process.returncode - ) - except Exception: - raise - return stdout - return None - - -def read_settings_file(settings_file_name): - if os.path.isfile(settings_file_name): - try: - with open(settings_file_name, "r") as stream: - settings = yaml.safe_load(stream) - except Exception: - raise - return settings - return None - - -print("##### K Language Grammar Test Suite #####") -test_dirs = find_test_dirs(str(pathlib.Path(__file__).parent), "") - - -@pytest.mark.parametrize("test_dir", test_dirs) -def test_grammar(test_dir): - print("Testing {}".format(test_dir)) - test_settings = read_settings_file(os.path.join(test_dir, SETTINGS_FILE)) - kcl_command = ["kcl", TEST_FILE] - if test_settings and test_settings["kcl_options"]: - kcl_command.extend(test_settings["kcl_options"].split()) - process = subprocess.Popen( - kcl_command, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - cwd=os.path.abspath(test_dir), - env=dict(os.environ), - ) - stdout, stderr = process.communicate() - print("STDOUT:\n{}".format(stdout.decode())) - print("STDERR:\n{}".format(stderr.decode())) - RETURN_CODE = 0 - KCLVM_OUTPUT = 1 - GOLDEN_FILE = 2 - GOLDEN_FILE_SCRIPT = 3 - settings = { - "stdout": (None, stdout, STDOUT_GOLDEN, STDOUT_GOLDEN_PY), - "stderr": (1, stderr, STDERR_GOLDEN, STDERR_GOLDEN_PY), - } - for _, setting in settings.items(): - # Attempt to generate a golden stdout. - golden_file_result = generate_golden_file( - os.path.join(test_dir, setting[GOLDEN_FILE_SCRIPT]) - ) - if golden_file_result: - compare_results(setting[KCLVM_OUTPUT], golden_file_result) - else: - # Attempt to use existing golden stdout. - try: - with open( - os.path.join(test_dir, setting[GOLDEN_FILE]), "r" - ) as golden_file: - compare_results_with_lines(setting[KCLVM_OUTPUT], golden_file) - if setting[RETURN_CODE] is not None: - assert process.returncode == setting[RETURN_CODE] - except OSError: - # Ignore when a golden file does not exist. - pass - except Exception: - raise diff --git a/test/grammar/types/args/call_expr_err_too_few_args_0/main.k b/test/grammar/types/args/call_expr_err_too_few_args_0/main.k new file mode 100644 index 000000000..4cd8dcec2 --- /dev/null +++ b/test/grammar/types/args/call_expr_err_too_few_args_0/main.k @@ -0,0 +1 @@ +a = "".startswith() diff --git a/test/grammar/types/args/call_expr_err_too_few_args_0/stderr.golden b/test/grammar/types/args/call_expr_err_too_few_args_0/stderr.golden new file mode 100644 index 000000000..5062bfc57 --- /dev/null +++ b/test/grammar/types/args/call_expr_err_too_few_args_0/stderr.golden @@ -0,0 +1,6 @@ +error[E2L23]: CompileError + --> ${CWD}/main.k:1:5 + | +1 | a = "".startswith() + | ^ expected 1 positional argument, found 0 + | \ No newline at end of file diff --git a/test/grammar/types/args/call_expr_err_too_few_args_1/main.k b/test/grammar/types/args/call_expr_err_too_few_args_1/main.k new file mode 100644 index 000000000..0bfc01a41 --- /dev/null +++ b/test/grammar/types/args/call_expr_err_too_few_args_1/main.k @@ -0,0 +1 @@ +a = "".replace("old") diff --git a/test/grammar/types/args/call_expr_err_too_few_args_1/stderr.golden b/test/grammar/types/args/call_expr_err_too_few_args_1/stderr.golden new file mode 100644 index 000000000..49a7bade6 --- /dev/null +++ b/test/grammar/types/args/call_expr_err_too_few_args_1/stderr.golden @@ -0,0 +1,6 @@ +error[E2L23]: CompileError + --> ${CWD}/main.k:1:5 + | +1 | a = "".replace("old") + | ^ expected 2 positional arguments, found 1 + | \ No newline at end of file diff --git a/test/grammar/types/args/lambda_types_03/main.k b/test/grammar/types/args/lambda_types_03/main.k new file mode 100644 index 000000000..1fa97edaa --- /dev/null +++ b/test/grammar/types/args/lambda_types_03/main.k @@ -0,0 +1,11 @@ +schema Cluster: + name: str + extra: int + +a: Cluster = { name = "abc", extra = 6 } + +enrich = lambda value { + [a] +} + +result_typesafe: [Cluster] = enrich({name = "abc", extra = 6 }) diff --git a/test/grammar/types/args/lambda_types_03/stdout.golden b/test/grammar/types/args/lambda_types_03/stdout.golden new file mode 100644 index 000000000..379287eeb --- /dev/null +++ b/test/grammar/types/args/lambda_types_03/stdout.golden @@ -0,0 +1,6 @@ +a: + name: abc + extra: 6 +result_typesafe: +- name: abc + extra: 6 diff --git a/test/grammar/types/args/lambda_types_err_01/stderr.golden b/test/grammar/types/args/lambda_types_err_01/stderr.golden new file mode 100644 index 000000000..aebc67a12 --- /dev/null +++ b/test/grammar/types/args/lambda_types_err_01/stderr.golden @@ -0,0 +1,6 @@ +error[E2G22]: TypeError + --> ${CWD}/main.k:6:18 + | +6 | x1 = typeFunc(1, "Golang") + | ^ expected str(KCL) | str(CUE), got str(Golang) + | \ No newline at end of file diff --git a/test/grammar/types/args/lambda_types_err_01/stderr.golden.py b/test/grammar/types/args/lambda_types_err_01/stderr.golden.py deleted file mode 100644 index 113d483f2..000000000 --- a/test/grammar/types/args/lambda_types_err_01/stderr.golden.py +++ /dev/null @@ -1,22 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.TypeError_Compile_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=6, - col_no=18, - arg_msg="got str(Golang)" - ) - ], - arg_msg="expect str(KCL)|str(CUE), got str(Golang)" - ), - file=sys.stdout -) - diff --git a/test/grammar/types/args/lambda_types_err_02/stderr.golden b/test/grammar/types/args/lambda_types_err_02/stderr.golden new file mode 100644 index 000000000..c0ac0d234 --- /dev/null +++ b/test/grammar/types/args/lambda_types_err_02/stderr.golden @@ -0,0 +1,25 @@ +error[E2G22]: TypeError + --> ${CWD}/main.k:6:15 + | +6 | x1 = typeFunc("1", "Golang") + | ^ expected int, got str(1) + | + + --> ${CWD}/main.k:1:19 + | +1 | typeFunc = lambda age_: int, name_: "KCL"|"CUE" { + | ^ variable is defined here, its type is int, but got str(1) + | + +error[E2G22]: TypeError + --> ${CWD}/main.k:6:20 + | +6 | x1 = typeFunc("1", "Golang") + | ^ expected str(KCL) | str(CUE), got str(Golang) + | + + --> ${CWD}/main.k:1:30 + | +1 | typeFunc = lambda age_: int, name_: "KCL"|"CUE" { + | ^ variable is defined here, its type is str(KCL) | str(CUE), but got str(Golang) + | diff --git a/test/grammar/types/args/lambda_types_err_02/stderr.golden.py b/test/grammar/types/args/lambda_types_err_02/stderr.golden.py deleted file mode 100644 index d90e9898f..000000000 --- a/test/grammar/types/args/lambda_types_err_02/stderr.golden.py +++ /dev/null @@ -1,22 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.TypeError_Compile_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=6, - col_no=15, - arg_msg="got str(1)" - ) - ], - arg_msg="expect int, got str(1)" - ), - file=sys.stdout -) - diff --git a/test/grammar/types/args/schema_types_err_01/stderr.golden b/test/grammar/types/args/schema_types_err_01/stderr.golden new file mode 100644 index 000000000..a80dc54c3 --- /dev/null +++ b/test/grammar/types/args/schema_types_err_01/stderr.golden @@ -0,0 +1,6 @@ +error[E2G22]: TypeError + --> ${CWD}/main.k:5:22 + | +5 | x1 = CheckArgType(1, "Golang") {} + | ^ expected str(KCL) | str(CUE), got str(Golang) + | \ No newline at end of file diff --git a/test/grammar/types/args/schema_types_err_01/stderr.golden.py b/test/grammar/types/args/schema_types_err_01/stderr.golden.py deleted file mode 100644 index 9442f883c..000000000 --- a/test/grammar/types/args/schema_types_err_01/stderr.golden.py +++ /dev/null @@ -1,22 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.TypeError_Compile_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=5, - col_no=22, - arg_msg="got str(Golang)" - ) - ], - arg_msg="expect str(KCL)|str(CUE), got str(Golang)" - ), - file=sys.stdout -) - diff --git a/test/grammar/types/args/schema_types_err_02_schema/stderr.golden b/test/grammar/types/args/schema_types_err_02_schema/stderr.golden new file mode 100644 index 000000000..bbdfc41e0 --- /dev/null +++ b/test/grammar/types/args/schema_types_err_02_schema/stderr.golden @@ -0,0 +1,6 @@ +error[E2G22]: TypeError + --> ${CWD}/main.k:13:19 + | +13 | x1 = CheckArgType(_x) {} + | ^ expected Person, got Person + | \ No newline at end of file diff --git a/test/grammar/types/args/schema_types_err_02_schema/stderr.golden.py b/test/grammar/types/args/schema_types_err_02_schema/stderr.golden.py deleted file mode 100644 index 52849e382..000000000 --- a/test/grammar/types/args/schema_types_err_02_schema/stderr.golden.py +++ /dev/null @@ -1,22 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.TypeError_Compile_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=13, - col_no=19, - arg_msg="got Person" - ) - ], - arg_msg='expect sub.Person, got Person' - ), - file=sys.stdout -) - diff --git a/test/grammar/types/args/schema_types_err_03_list/stderr.golden b/test/grammar/types/args/schema_types_err_03_list/stderr.golden new file mode 100644 index 000000000..19ffb962d --- /dev/null +++ b/test/grammar/types/args/schema_types_err_03_list/stderr.golden @@ -0,0 +1,6 @@ +error[E2G22]: TypeError + --> ${CWD}/main.k:6:46 + | +6 | x1 = CheckArgType([123, True], ["abc", 456], ["aa", True]) {} + | ^ expected [str], got [str(aa) | bool(True)] + | \ No newline at end of file diff --git a/test/grammar/types/args/schema_types_err_03_list/stderr.golden.py b/test/grammar/types/args/schema_types_err_03_list/stderr.golden.py deleted file mode 100644 index a361f5f3a..000000000 --- a/test/grammar/types/args/schema_types_err_03_list/stderr.golden.py +++ /dev/null @@ -1,21 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.TypeError_Compile_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=6, - col_no=46, - arg_msg="got [bool(True)|str(aa)]" - ) - ], - arg_msg='expect [str], got [bool(True)|str(aa)]' - ), - file=sys.stdout -) - diff --git a/test/grammar/types/args/schema_types_err_04_without_config/stderr.golden b/test/grammar/types/args/schema_types_err_04_without_config/stderr.golden new file mode 100644 index 000000000..fac1bffaf --- /dev/null +++ b/test/grammar/types/args/schema_types_err_04_without_config/stderr.golden @@ -0,0 +1,6 @@ +error[E2G22]: TypeError + --> ${CWD}/main.k:6:46 + | +6 | x1 = CheckArgType([123, True], ["abc", 456], ["aa", True]) + | ^ expected [str], got [str(aa) | bool(True)] + | \ No newline at end of file diff --git a/test/grammar/types/args/schema_types_err_04_without_config/stderr.golden.py b/test/grammar/types/args/schema_types_err_04_without_config/stderr.golden.py deleted file mode 100644 index 42785b85c..000000000 --- a/test/grammar/types/args/schema_types_err_04_without_config/stderr.golden.py +++ /dev/null @@ -1,21 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.TypeError_Compile_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=6, - col_no=46, - arg_msg='got [bool(True)|str(aa)]' - ) - ], - arg_msg='expect [str], got [bool(True)|str(aa)]' - ), - file=sys.stdout -) diff --git a/test/grammar/types/args/schema_types_err_05_kwargs/stderr.golden b/test/grammar/types/args/schema_types_err_05_kwargs/stderr.golden new file mode 100644 index 000000000..5c383980f --- /dev/null +++ b/test/grammar/types/args/schema_types_err_05_kwargs/stderr.golden @@ -0,0 +1,12 @@ +error[E2G22]: TypeError + --> ${CWD}/main.k:5:33 + | +5 | person = Person(data="Alice", n="1") + | ^ expected int, got str(1) + | + + --> ${CWD}/main.k:1:26 + | +1 | schema Person[data: str, n: int]: + | ^ variable is defined here, its type is int, but got str(1) + | diff --git a/test/grammar/types/args/schema_types_err_05_kwargs/stderr.golden.py b/test/grammar/types/args/schema_types_err_05_kwargs/stderr.golden.py deleted file mode 100644 index 338fc8cb6..000000000 --- a/test/grammar/types/args/schema_types_err_05_kwargs/stderr.golden.py +++ /dev/null @@ -1,22 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.TypeError_Compile_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=5, - col_no=31, - arg_msg="got str(1)" - ) - ], - arg_msg='expect int, got str(1)' - ), - file=sys.stdout -) - diff --git a/test/grammar/types/args/schema_types_err_too_many_args_0/main.k b/test/grammar/types/args/schema_types_err_too_many_args_0/main.k new file mode 100644 index 000000000..b805bcf68 --- /dev/null +++ b/test/grammar/types/args/schema_types_err_too_many_args_0/main.k @@ -0,0 +1,4 @@ +schema SchemaInMainK: + msg?: str + +schema_in_main_k = SchemaInMainK(msg='I am the instance of SchemaInMainK') diff --git a/test/grammar/types/args/schema_types_err_too_many_args_0/stderr.golden b/test/grammar/types/args/schema_types_err_too_many_args_0/stderr.golden new file mode 100644 index 000000000..8d3ca4ea2 --- /dev/null +++ b/test/grammar/types/args/schema_types_err_too_many_args_0/stderr.golden @@ -0,0 +1,6 @@ +error[E2L23]: CompileError + --> ${CWD}/main.k:4:34 + | +4 | schema_in_main_k = SchemaInMainK(msg='I am the instance of SchemaInMainK') + | ^ "SchemaInMainK" got an unexpected keyword argument 'msg' + | \ No newline at end of file diff --git a/test/grammar/types/args/schema_types_err_too_many_args_1/main.k b/test/grammar/types/args/schema_types_err_too_many_args_1/main.k new file mode 100644 index 000000000..6cdd9cb7a --- /dev/null +++ b/test/grammar/types/args/schema_types_err_too_many_args_1/main.k @@ -0,0 +1,4 @@ +schema SchemaInMainK: + msg?: str + +schema_in_main_k = SchemaInMainK('I am the instance of SchemaInMainK') diff --git a/test/grammar/types/args/schema_types_err_too_many_args_1/stderr.golden b/test/grammar/types/args/schema_types_err_too_many_args_1/stderr.golden new file mode 100644 index 000000000..703e17daa --- /dev/null +++ b/test/grammar/types/args/schema_types_err_too_many_args_1/stderr.golden @@ -0,0 +1,6 @@ +error[E2L23]: CompileError + --> ${CWD}/main.k:4:34 + | +4 | schema_in_main_k = SchemaInMainK('I am the instance of SchemaInMainK') + | ^ "SchemaInMainK" takes 0 positional argument but 1 were given + | \ No newline at end of file diff --git a/test/grammar/types/args/schema_types_err_too_many_args_2/main.k b/test/grammar/types/args/schema_types_err_too_many_args_2/main.k new file mode 100644 index 000000000..de45e7a45 --- /dev/null +++ b/test/grammar/types/args/schema_types_err_too_many_args_2/main.k @@ -0,0 +1,4 @@ +schema SchemaInMainK[m: str]: + msg?: str + +schema_in_main_k = SchemaInMainK('param1', "param2") diff --git a/test/grammar/types/args/schema_types_err_too_many_args_2/stderr.golden b/test/grammar/types/args/schema_types_err_too_many_args_2/stderr.golden new file mode 100644 index 000000000..1713de883 --- /dev/null +++ b/test/grammar/types/args/schema_types_err_too_many_args_2/stderr.golden @@ -0,0 +1,6 @@ +error[E2L23]: CompileError + --> ${CWD}/main.k:4:44 + | +4 | schema_in_main_k = SchemaInMainK('param1', "param2") + | ^ "SchemaInMainK" takes 1 positional argument but 2 were given + | \ No newline at end of file diff --git a/test/grammar/types/binary_expr/binary_expr_0/main.k b/test/grammar/types/binary_expr/binary_expr_0/main.k new file mode 100644 index 000000000..834e8d859 --- /dev/null +++ b/test/grammar/types/binary_expr/binary_expr_0/main.k @@ -0,0 +1,2 @@ +a: float = 1 + 1.0 +b: int = 1 + 1 diff --git a/test/grammar/types/binary_expr/binary_expr_0/stdout.golden b/test/grammar/types/binary_expr/binary_expr_0/stdout.golden new file mode 100644 index 000000000..d1485572b --- /dev/null +++ b/test/grammar/types/binary_expr/binary_expr_0/stdout.golden @@ -0,0 +1,2 @@ +a: 2.0 +b: 2 diff --git a/test/grammar/types/binary_expr/binary_expr_1/main.k b/test/grammar/types/binary_expr/binary_expr_1/main.k new file mode 100644 index 000000000..6b1b0c0a3 --- /dev/null +++ b/test/grammar/types/binary_expr/binary_expr_1/main.k @@ -0,0 +1,2 @@ +a: bool = 1 < 1.0 +b: bool = 1 < 1 diff --git a/test/grammar/types/binary_expr/binary_expr_1/stdout.golden b/test/grammar/types/binary_expr/binary_expr_1/stdout.golden new file mode 100644 index 000000000..25cb5b430 --- /dev/null +++ b/test/grammar/types/binary_expr/binary_expr_1/stdout.golden @@ -0,0 +1,2 @@ +a: false +b: false diff --git a/test/grammar/types/binary_expr/binary_expr_2/main.k b/test/grammar/types/binary_expr/binary_expr_2/main.k new file mode 100644 index 000000000..e28e3c344 --- /dev/null +++ b/test/grammar/types/binary_expr/binary_expr_2/main.k @@ -0,0 +1,4 @@ +a: bool = [0] == [0] +b: bool = [0] == [1] +c: bool = {} == {} +d: bool = {} == {k = "v"} diff --git a/test/grammar/types/binary_expr/binary_expr_2/stdout.golden b/test/grammar/types/binary_expr/binary_expr_2/stdout.golden new file mode 100644 index 000000000..08cc7f908 --- /dev/null +++ b/test/grammar/types/binary_expr/binary_expr_2/stdout.golden @@ -0,0 +1,4 @@ +a: true +b: false +c: true +d: false diff --git a/test/grammar/types/binary_expr/binary_expr_3/main.k b/test/grammar/types/binary_expr/binary_expr_3/main.k new file mode 100644 index 000000000..4ef95f716 --- /dev/null +++ b/test/grammar/types/binary_expr/binary_expr_3/main.k @@ -0,0 +1,4 @@ +a: bool = True +b: bool = a is True +c: bool = a is not True +d: bool = a is not False diff --git a/test/grammar/types/binary_expr/binary_expr_3/stdout.golden b/test/grammar/types/binary_expr/binary_expr_3/stdout.golden new file mode 100644 index 000000000..1cfd03fda --- /dev/null +++ b/test/grammar/types/binary_expr/binary_expr_3/stdout.golden @@ -0,0 +1,4 @@ +a: true +b: true +c: false +d: true diff --git a/test/grammar/types/binary_expr/binary_expr_4/main.k b/test/grammar/types/binary_expr/binary_expr_4/main.k new file mode 100644 index 000000000..9877069bd --- /dev/null +++ b/test/grammar/types/binary_expr/binary_expr_4/main.k @@ -0,0 +1,2 @@ +a = 1 > False +b = 2 < True diff --git a/test/grammar/types/binary_expr/binary_expr_4/stdout.golden b/test/grammar/types/binary_expr/binary_expr_4/stdout.golden new file mode 100644 index 000000000..97890b200 --- /dev/null +++ b/test/grammar/types/binary_expr/binary_expr_4/stdout.golden @@ -0,0 +1,2 @@ +a: true +b: false diff --git a/test/grammar/types/binary_expr/binary_expr_fail_0/main.k b/test/grammar/types/binary_expr/binary_expr_fail_0/main.k new file mode 100644 index 000000000..ec729d19e --- /dev/null +++ b/test/grammar/types/binary_expr/binary_expr_fail_0/main.k @@ -0,0 +1 @@ +a: int = 1 + True \ No newline at end of file diff --git a/test/grammar/types/binary_expr/binary_expr_fail_0/stderr.golden b/test/grammar/types/binary_expr/binary_expr_fail_0/stderr.golden new file mode 100644 index 000000000..1646e4cfd --- /dev/null +++ b/test/grammar/types/binary_expr/binary_expr_fail_0/stderr.golden @@ -0,0 +1,6 @@ +error[E2G22]: TypeError + --> ${CWD}/main.k:1:10 + | +1 | a: int = 1 + True + | ^ unsupported operand type(s) for +: 'int(1)' and 'bool(True)' + | \ No newline at end of file diff --git a/test/grammar/types/binary_expr/binary_expr_fail_1/main.k b/test/grammar/types/binary_expr/binary_expr_fail_1/main.k new file mode 100644 index 000000000..e3bb03d90 --- /dev/null +++ b/test/grammar/types/binary_expr/binary_expr_fail_1/main.k @@ -0,0 +1 @@ +a = [0] < [1] \ No newline at end of file diff --git a/test/grammar/types/binary_expr/binary_expr_fail_1/stderr.golden b/test/grammar/types/binary_expr/binary_expr_fail_1/stderr.golden new file mode 100644 index 000000000..99e980bc5 --- /dev/null +++ b/test/grammar/types/binary_expr/binary_expr_fail_1/stderr.golden @@ -0,0 +1,6 @@ +error[E2G22]: TypeError + --> ${CWD}/main.k:1:5 + | +1 | a = [0] < [1] + | ^ unsupported operand type(s) for <: '[int(0)]' and '[int(1)]' + | \ No newline at end of file diff --git a/test/grammar/types/binary_expr/binary_expr_fail_2/main.k b/test/grammar/types/binary_expr/binary_expr_fail_2/main.k new file mode 100644 index 000000000..902b69d03 --- /dev/null +++ b/test/grammar/types/binary_expr/binary_expr_fail_2/main.k @@ -0,0 +1 @@ +a = {} < {} \ No newline at end of file diff --git a/test/grammar/types/binary_expr/binary_expr_fail_2/stderr.golden b/test/grammar/types/binary_expr/binary_expr_fail_2/stderr.golden new file mode 100644 index 000000000..31742c510 --- /dev/null +++ b/test/grammar/types/binary_expr/binary_expr_fail_2/stderr.golden @@ -0,0 +1,6 @@ +error[E2G22]: TypeError + --> ${CWD}/main.k:1:5 + | +1 | a = {} < {} + | ^ unsupported operand type(s) for <: '{any:any}' and '{any:any}' + | \ No newline at end of file diff --git a/test/grammar/types/config/config_ty_0/main.k b/test/grammar/types/config/config_ty_0/main.k new file mode 100644 index 000000000..377e25e8d --- /dev/null +++ b/test/grammar/types/config/config_ty_0/main.k @@ -0,0 +1,14 @@ +config: {str:} = { + "key" = [ + { + key = "value" + } + ] + "values": [ + "foo" + "bar" + ] +} + +if "foo" in config.values: + a = 1 diff --git a/test/grammar/types/config/config_ty_0/stdout.golden b/test/grammar/types/config/config_ty_0/stdout.golden new file mode 100644 index 000000000..5868ff014 --- /dev/null +++ b/test/grammar/types/config/config_ty_0/stdout.golden @@ -0,0 +1,7 @@ +config: + key: + - key: value + values: + - foo + - bar +a: 1 diff --git a/test/grammar/types/config/config_ty_1/main.k b/test/grammar/types/config/config_ty_1/main.k new file mode 100644 index 000000000..ea3920300 --- /dev/null +++ b/test/grammar/types/config/config_ty_1/main.k @@ -0,0 +1,14 @@ +config: {str:} = { + key = [ + { + key = "value" + } + ] + values: [ + "foo" + "bar" + ] +} + +if "foo" in config.values: + a = 1 diff --git a/test/grammar/types/config/config_ty_1/stdout.golden b/test/grammar/types/config/config_ty_1/stdout.golden new file mode 100644 index 000000000..5868ff014 --- /dev/null +++ b/test/grammar/types/config/config_ty_1/stdout.golden @@ -0,0 +1,7 @@ +config: + key: + - key: value + values: + - foo + - bar +a: 1 diff --git a/test/grammar/types/config/config_ty_2/main.k b/test/grammar/types/config/config_ty_2/main.k new file mode 100644 index 000000000..f93e476a1 --- /dev/null +++ b/test/grammar/types/config/config_ty_2/main.k @@ -0,0 +1,12 @@ +config: {str:} = { + "key" = [ + { + key = "value" + } + ] + "values" = [ + "foo" + "bar" + ] +} +values: [str] = config.values diff --git a/test/grammar/types/config/config_ty_2/stdout.golden b/test/grammar/types/config/config_ty_2/stdout.golden new file mode 100644 index 000000000..e5349a781 --- /dev/null +++ b/test/grammar/types/config/config_ty_2/stdout.golden @@ -0,0 +1,9 @@ +config: + key: + - key: value + values: + - foo + - bar +values: +- foo +- bar diff --git a/test/grammar/types/config/config_ty_3/main.k b/test/grammar/types/config/config_ty_3/main.k new file mode 100644 index 000000000..7e1a11194 --- /dev/null +++ b/test/grammar/types/config/config_ty_3/main.k @@ -0,0 +1,12 @@ +config: {str:} = { + "map" = [ + { + key = "value" + } + ] + "values" = [ + "foo" + "bar" + ] +} +$map: [{str:str}] = config.map diff --git a/test/grammar/types/config/config_ty_3/stdout.golden b/test/grammar/types/config/config_ty_3/stdout.golden new file mode 100644 index 000000000..cf7c1c5e8 --- /dev/null +++ b/test/grammar/types/config/config_ty_3/stdout.golden @@ -0,0 +1,8 @@ +config: + map: + - key: value + values: + - foo + - bar +map: +- key: value diff --git a/test/grammar/types/interpolation/interpolation_0/main.k b/test/grammar/types/interpolation/interpolation_0/main.k new file mode 100644 index 000000000..dd728f189 --- /dev/null +++ b/test/grammar/types/interpolation/interpolation_0/main.k @@ -0,0 +1,13 @@ +schema App: + name: str + containers?: {str: Container} + +schema Container: + image: str + +app: App { + name = "ngnix" + containers = { + "${name}" = {image = name} + } +} diff --git a/test/grammar/types/interpolation/interpolation_0/stdout.golden b/test/grammar/types/interpolation/interpolation_0/stdout.golden new file mode 100644 index 000000000..22a98073a --- /dev/null +++ b/test/grammar/types/interpolation/interpolation_0/stdout.golden @@ -0,0 +1,5 @@ +app: + name: ngnix + containers: + ngnix: + image: ngnix diff --git a/test/grammar/types/interpolation/interpolation_1/main.k b/test/grammar/types/interpolation/interpolation_1/main.k new file mode 100644 index 000000000..993aae1ac --- /dev/null +++ b/test/grammar/types/interpolation/interpolation_1/main.k @@ -0,0 +1,23 @@ +schema App: + name: str + containers?: {str: Container} + +schema Container: + image: str + envs: {str:Env} + +schema Env: + value?: str + valueFrom?: str + +app: App { + name = "ngnix" + containers = { + "${name}" = { + image = name + envs = { + "${name}" = {value = "value"} + } + } + } +} diff --git a/test/grammar/types/interpolation/interpolation_1/stdout.golden b/test/grammar/types/interpolation/interpolation_1/stdout.golden new file mode 100644 index 000000000..069459495 --- /dev/null +++ b/test/grammar/types/interpolation/interpolation_1/stdout.golden @@ -0,0 +1,8 @@ +app: + name: ngnix + containers: + ngnix: + image: ngnix + envs: + ngnix: + value: value diff --git a/test/grammar/types/literal/lit_06_entry_id_key/main.k b/test/grammar/types/literal/lit_06_entry_id_key/main.k new file mode 100644 index 000000000..37e43b9ba --- /dev/null +++ b/test/grammar/types/literal/lit_06_entry_id_key/main.k @@ -0,0 +1,12 @@ +schema Id: + id?: int + +schema Config: + data?: {"A"|"B":Id} + +c = Config { + data = { + A = Id() + B = Id() + } +} diff --git a/test/grammar/types/literal/lit_06_entry_id_key/stdout.golden b/test/grammar/types/literal/lit_06_entry_id_key/stdout.golden new file mode 100644 index 000000000..16f12c11c --- /dev/null +++ b/test/grammar/types/literal/lit_06_entry_id_key/stdout.golden @@ -0,0 +1,4 @@ +c: + data: + A: {} + B: {} diff --git a/test/grammar/types/literal/lit_07_uf8_str_union/main.k b/test/grammar/types/literal/lit_07_uf8_str_union/main.k new file mode 100644 index 000000000..4cbfbf2fc --- /dev/null +++ b/test/grammar/types/literal/lit_07_uf8_str_union/main.k @@ -0,0 +1 @@ +msg: "无需容灾" | "标准型" | "流水型" = "流水型" diff --git a/test/grammar/types/literal/lit_07_uf8_str_union/stdout.golden b/test/grammar/types/literal/lit_07_uf8_str_union/stdout.golden new file mode 100644 index 000000000..34f5a0819 --- /dev/null +++ b/test/grammar/types/literal/lit_07_uf8_str_union/stdout.golden @@ -0,0 +1 @@ +msg: 流水型 diff --git a/test/grammar/types/literal/lit_err_01_bool_01/stderr.golden b/test/grammar/types/literal/lit_err_01_bool_01/stderr.golden new file mode 100644 index 000000000..cc277e9e4 --- /dev/null +++ b/test/grammar/types/literal/lit_err_01_bool_01/stderr.golden @@ -0,0 +1,11 @@ +error[E2G22]: TypeError + --> ${CWD}/main.k:5:5 + | +5 | bool_01 = False + | ^ expected bool(True), got bool(False) + | + --> ${CWD}/main.k:2:5 + | +2 | bool_01: True + | ^ variable is defined here, its type is bool(True), but got bool(False) + | \ No newline at end of file diff --git a/test/grammar/types/literal/lit_err_01_bool_01/stderr.golden.py b/test/grammar/types/literal/lit_err_01_bool_01/stderr.golden.py deleted file mode 100644 index ec79eee44..000000000 --- a/test/grammar/types/literal/lit_err_01_bool_01/stderr.golden.py +++ /dev/null @@ -1,30 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.TypeError_Compile_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=2, - col_no=5, - indent_count=1, - arg_msg="expect bool(True)", - err_level=kcl_error.ErrLevel.ORDINARY - ), - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=5, - col_no=5, - arg_msg="got bool(False)" - ) - ], - arg_msg="expect bool(True), got bool(False)" - ), - file=sys.stdout -) - diff --git a/test/grammar/types/literal/lit_err_01_bool_02/stderr.golden b/test/grammar/types/literal/lit_err_01_bool_02/stderr.golden new file mode 100644 index 000000000..302209019 --- /dev/null +++ b/test/grammar/types/literal/lit_err_01_bool_02/stderr.golden @@ -0,0 +1,11 @@ +error[E2G22]: TypeError + --> ${CWD}/main.k:5:5 + | +5 | bool_01 = 123 + | ^ expected bool(True), got int(123) + | + --> ${CWD}/main.k:2:5 + | +2 | bool_01: True + | ^ variable is defined here, its type is bool(True), but got int(123) + | \ No newline at end of file diff --git a/test/grammar/types/literal/lit_err_01_bool_02/stderr.golden.py b/test/grammar/types/literal/lit_err_01_bool_02/stderr.golden.py deleted file mode 100644 index a557519e8..000000000 --- a/test/grammar/types/literal/lit_err_01_bool_02/stderr.golden.py +++ /dev/null @@ -1,29 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.TypeError_Compile_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=2, - col_no=5, - indent_count=1, - arg_msg="expect bool(True)", - err_level=kcl_error.ErrLevel.ORDINARY - ), - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=5, - col_no=5, - arg_msg="got int(123)" - ) - ], - arg_msg="expect bool(True), got int(123)" - ), - file=sys.stdout -) diff --git a/test/grammar/types/literal/lit_err_02_int_01/stderr.golden b/test/grammar/types/literal/lit_err_02_int_01/stderr.golden new file mode 100644 index 000000000..40f94a359 --- /dev/null +++ b/test/grammar/types/literal/lit_err_02_int_01/stderr.golden @@ -0,0 +1,11 @@ +error[E2G22]: TypeError + --> ${CWD}/main.k:7:5 + | +7 | int_02: 789 + | ^ expected int(123) | int(456), got int(789) + | + --> ${CWD}/main.k:3:5 + | +3 | int_02: 123 | 456 + | ^ variable is defined here, its type is int(123) | int(456), but got int(789) + | \ No newline at end of file diff --git a/test/grammar/types/literal/lit_err_02_int_01/stderr.golden.py b/test/grammar/types/literal/lit_err_02_int_01/stderr.golden.py deleted file mode 100644 index cd5eab6c2..000000000 --- a/test/grammar/types/literal/lit_err_02_int_01/stderr.golden.py +++ /dev/null @@ -1,30 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.TypeError_Compile_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=3, - col_no=5, - indent_count=1, - arg_msg="expect int(123)|int(456)", - err_level=kcl_error.ErrLevel.ORDINARY - ), - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=7, - col_no=5, - arg_msg="got int(789)" - ) - ], - arg_msg="expect int(123)|int(456), got int(789)" - ), - file=sys.stdout -) - diff --git a/test/grammar/types/literal/lit_err_02_int_02/stderr.golden b/test/grammar/types/literal/lit_err_02_int_02/stderr.golden new file mode 100644 index 000000000..bcc4f3c9c --- /dev/null +++ b/test/grammar/types/literal/lit_err_02_int_02/stderr.golden @@ -0,0 +1,11 @@ +error[E2G22]: TypeError + --> ${CWD}/main.k:5:5 + | +5 | int_0: 0.0 + | ^ expected int(0), got float(0) + | + --> ${CWD}/main.k:2:5 + | +2 | int_0: 0 + | ^ variable is defined here, its type is int(0), but got float(0) + | \ No newline at end of file diff --git a/test/grammar/types/literal/lit_err_02_int_02/stderr.golden.py b/test/grammar/types/literal/lit_err_02_int_02/stderr.golden.py deleted file mode 100644 index 75906d989..000000000 --- a/test/grammar/types/literal/lit_err_02_int_02/stderr.golden.py +++ /dev/null @@ -1,30 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.TypeError_Compile_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=2, - col_no=5, - indent_count=1, - arg_msg="expect int(0)", - err_level=kcl_error.ErrLevel.ORDINARY - ), - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=5, - col_no=5, - arg_msg="got float(0.0)" - ) - ], - arg_msg="expect int(0), got float(0.0)" - ), - file=sys.stdout -) - diff --git a/test/grammar/types/literal/lit_err_03_float_01/stderr.golden b/test/grammar/types/literal/lit_err_03_float_01/stderr.golden new file mode 100644 index 000000000..bcc7b9de7 --- /dev/null +++ b/test/grammar/types/literal/lit_err_03_float_01/stderr.golden @@ -0,0 +1,6 @@ +error[E3M38]: EvaluationError + --> ${CWD}/main.k:2:1 + | +2 | float_01: 0.0 + | expect 0.0, got int + | \ No newline at end of file diff --git a/test/grammar/types/literal/lit_err_03_float_01/stderr.golden.py b/test/grammar/types/literal/lit_err_03_float_01/stderr.golden.py deleted file mode 100644 index ca5d449bd..000000000 --- a/test/grammar/types/literal/lit_err_03_float_01/stderr.golden.py +++ /dev/null @@ -1,30 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.TypeError_Compile_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=2, - col_no=5, - indent_count=1, - arg_msg="expect float(0.0)", - err_level=kcl_error.ErrLevel.ORDINARY - ), - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=5, - col_no=5, - arg_msg="got int(0)" - ) - ], - arg_msg="expect float(0.0), got int(0)" - ), - file=sys.stdout -) - diff --git a/test/grammar/types/literal/lit_err_03_float_02/stderr.golden b/test/grammar/types/literal/lit_err_03_float_02/stderr.golden new file mode 100644 index 000000000..d1559f1dd --- /dev/null +++ b/test/grammar/types/literal/lit_err_03_float_02/stderr.golden @@ -0,0 +1,6 @@ +error[E3M38]: EvaluationError + --> ${CWD}/main.k:2:1 + | +2 | x_01: 0.0 | 3.14 | 9527 + | expect 0.0 | 3.14 | 9527, got int + | \ No newline at end of file diff --git a/test/grammar/types/literal/lit_err_03_float_02/stderr.golden.py b/test/grammar/types/literal/lit_err_03_float_02/stderr.golden.py deleted file mode 100644 index f54ca85cc..000000000 --- a/test/grammar/types/literal/lit_err_03_float_02/stderr.golden.py +++ /dev/null @@ -1,30 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.TypeError_Compile_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=2, - col_no=5, - indent_count=1, - arg_msg="expect int(9527)|float(0.0)|float(3.14)", - err_level=kcl_error.ErrLevel.ORDINARY - ), - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=5, - col_no=5, - arg_msg="got int(0)" - ) - ], - arg_msg="expect int(9527)|float(0.0)|float(3.14), got int(0)" - ), - file=sys.stdout -) - diff --git a/test/grammar/types/literal/lit_err_04_str_01/stderr.golden b/test/grammar/types/literal/lit_err_04_str_01/stderr.golden new file mode 100644 index 000000000..1b6ee6c05 --- /dev/null +++ b/test/grammar/types/literal/lit_err_04_str_01/stderr.golden @@ -0,0 +1,11 @@ +error[E2G22]: TypeError + --> ${CWD}/main.k:5:5 + | +5 | x_01: "HTTP" + | ^ expected str(TCP) | str(UDP), got str(HTTP) + | + --> ${CWD}/main.k:2:5 + | +2 | x_01: "TCP" | 'UDP' + | ^ variable is defined here, its type is str(TCP) | str(UDP), but got str(HTTP) + | \ No newline at end of file diff --git a/test/grammar/types/literal/lit_err_04_str_01/stderr.golden.py b/test/grammar/types/literal/lit_err_04_str_01/stderr.golden.py deleted file mode 100644 index 3f899a78a..000000000 --- a/test/grammar/types/literal/lit_err_04_str_01/stderr.golden.py +++ /dev/null @@ -1,30 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.TypeError_Compile_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=2, - col_no=5, - indent_count=1, - arg_msg="expect str(TCP)|str(UDP)", - err_level=kcl_error.ErrLevel.ORDINARY - ), - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=5, - col_no=5, - arg_msg="got str(HTTP)" - ) - ], - arg_msg='expect str(TCP)|str(UDP), got str(HTTP)' - ), - file=sys.stdout -) - diff --git a/test/grammar/types/literal/lit_err_04_str_02/stderr.golden b/test/grammar/types/literal/lit_err_04_str_02/stderr.golden new file mode 100644 index 000000000..c53fa8905 --- /dev/null +++ b/test/grammar/types/literal/lit_err_04_str_02/stderr.golden @@ -0,0 +1,11 @@ +error[E2G22]: TypeError + --> ${CWD}/main.k:5:5 + | +5 | x_01: 443 + | ^ expected str(TCP) | str(UDP), got int(443) + | + --> ${CWD}/main.k:2:5 + | +2 | x_01: "TCP" | 'UDP' + | ^ variable is defined here, its type is str(TCP) | str(UDP), but got int(443) + | \ No newline at end of file diff --git a/test/grammar/types/literal/lit_err_04_str_02/stderr.golden.py b/test/grammar/types/literal/lit_err_04_str_02/stderr.golden.py deleted file mode 100644 index 284fee05e..000000000 --- a/test/grammar/types/literal/lit_err_04_str_02/stderr.golden.py +++ /dev/null @@ -1,29 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.TypeError_Compile_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=2, - col_no=5, - indent_count=1, - arg_msg="expect str(TCP)|str(UDP)", - err_level=kcl_error.ErrLevel.ORDINARY - ), - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=5, - col_no=5, - arg_msg="got int(443)" - ) - ], - arg_msg='expect str(TCP)|str(UDP), got int(443)' - ), - file=sys.stdout -) diff --git a/test/grammar/types/literal/lit_err_05_union_01/stderr.golden b/test/grammar/types/literal/lit_err_05_union_01/stderr.golden new file mode 100644 index 000000000..ca2da25a6 --- /dev/null +++ b/test/grammar/types/literal/lit_err_05_union_01/stderr.golden @@ -0,0 +1,6 @@ +error[E3M38]: EvaluationError + --> ${CWD}/main.k:2:1 + | +2 | x_1?: True|123|3.14|"abc"|[]|{str:} + | expect True | 123 | 3.14 | "abc" | [] | {str:}, got int + | \ No newline at end of file diff --git a/test/grammar/types/literal/lit_err_05_union_01/stderr.golden.py b/test/grammar/types/literal/lit_err_05_union_01/stderr.golden.py deleted file mode 100644 index ba16a2272..000000000 --- a/test/grammar/types/literal/lit_err_05_union_01/stderr.golden.py +++ /dev/null @@ -1,29 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.TypeError_Compile_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=2, - col_no=5, - indent_count=1, - arg_msg="expect bool(True)|int(123)|float(3.14)|str(abc)|[any]|{str:any}", - err_level=kcl_error.ErrLevel.ORDINARY - ), - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=5, - col_no=5, - arg_msg="got int(443)" - ) - ], - arg_msg='expect bool(True)|int(123)|float(3.14)|str(abc)|[any]|{str:any}, got int(443)' - ), - file=sys.stdout -) diff --git a/test/grammar/types/literal/lit_err_06_unit/stderr.golden b/test/grammar/types/literal/lit_err_06_unit/stderr.golden new file mode 100644 index 000000000..4f108971a --- /dev/null +++ b/test/grammar/types/literal/lit_err_06_unit/stderr.golden @@ -0,0 +1,11 @@ +error[E2G22]: TypeError + --> ${CWD}/main.k:6:5 + | +6 | int_01 = 123 + | ^ expected number_multiplier(123K) | int(456), got int(123) + | + --> ${CWD}/main.k:2:5 + | +2 | int_01: 123K | 456 + | ^ variable is defined here, its type is number_multiplier(123K) | int(456), but got int(123) + | \ No newline at end of file diff --git a/test/grammar/types/literal/lit_err_06_unit/stderr.golden.py b/test/grammar/types/literal/lit_err_06_unit/stderr.golden.py deleted file mode 100644 index 5ca3f54e8..000000000 --- a/test/grammar/types/literal/lit_err_06_unit/stderr.golden.py +++ /dev/null @@ -1,29 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.TypeError_Compile_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=2, - col_no=5, - indent_count=1, - arg_msg="expect int(456)|number_multiplier(123K)", - err_level=kcl_error.ErrLevel.ORDINARY - ), - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=6, - col_no=5, - arg_msg="got int(123)" - ) - ], - arg_msg='expect int(456)|number_multiplier(123K), got int(123)' - ), - file=sys.stdout -) diff --git a/test/grammar/types/loop/loop_0/main.k b/test/grammar/types/loop/loop_0/main.k new file mode 100644 index 000000000..8a2f48e78 --- /dev/null +++ b/test/grammar/types/loop/loop_0/main.k @@ -0,0 +1,12 @@ +name = "volume" +configMapVolumes1: {str:{str:}} = { + name = { + name = name + } for _ in range(1) +} + +configMapVolumes2: [{str:}] = [ + { + name = name + } for _ in range(1) +] diff --git a/test/grammar/types/loop/loop_0/stdout.golden b/test/grammar/types/loop/loop_0/stdout.golden new file mode 100644 index 000000000..1e94842a9 --- /dev/null +++ b/test/grammar/types/loop/loop_0/stdout.golden @@ -0,0 +1,6 @@ +name: volume +configMapVolumes1: + volume: + name: volume +configMapVolumes2: +- name: volume diff --git a/test/grammar/types/loop/loop_1/main.k b/test/grammar/types/loop/loop_1/main.k new file mode 100644 index 000000000..6fb5cbe39 --- /dev/null +++ b/test/grammar/types/loop/loop_1/main.k @@ -0,0 +1,12 @@ +name = "volume" +configMapVolumes1: [{str:{str:}}] = [{ + name = { + name = name + } for _ in range(1) +}] + +configMapVolumes2: {str:[{str:}]} = {name = [ + { + name = name + } for _ in range(1) +]} diff --git a/test/grammar/types/loop/loop_1/stdout.golden b/test/grammar/types/loop/loop_1/stdout.golden new file mode 100644 index 000000000..f3239790e --- /dev/null +++ b/test/grammar/types/loop/loop_1/stdout.golden @@ -0,0 +1,7 @@ +name: volume +configMapVolumes1: +- volume: + name: volume +configMapVolumes2: + name: + - name: volume \ No newline at end of file diff --git a/test/grammar/types/runtime_ty/runtime_ty_0/main.k b/test/grammar/types/runtime_ty/runtime_ty_0/main.k new file mode 100644 index 000000000..488d93a82 --- /dev/null +++ b/test/grammar/types/runtime_ty/runtime_ty_0/main.k @@ -0,0 +1,7 @@ +import json + +schema Person: + name: str + age: int + +person: Person = json.decode('{"name": "Alice", "age": 18}') diff --git a/test/grammar/types/runtime_ty/runtime_ty_0/stdout.golden b/test/grammar/types/runtime_ty/runtime_ty_0/stdout.golden new file mode 100644 index 000000000..1a9d164c4 --- /dev/null +++ b/test/grammar/types/runtime_ty/runtime_ty_0/stdout.golden @@ -0,0 +1,3 @@ +person: + name: Alice + age: 18 diff --git a/test/grammar/types/runtime_ty/runtime_ty_1/main.k b/test/grammar/types/runtime_ty/runtime_ty_1/main.k new file mode 100644 index 000000000..5fbf2a145 --- /dev/null +++ b/test/grammar/types/runtime_ty/runtime_ty_1/main.k @@ -0,0 +1,7 @@ +import json + +schema Person: + name: str + age: int + +persons: [Person] = json.decode('[{"name": "Alice", "age": 18}, {"name": "Bob", "age": 10}]') diff --git a/test/grammar/types/runtime_ty/runtime_ty_1/stdout.golden b/test/grammar/types/runtime_ty/runtime_ty_1/stdout.golden new file mode 100644 index 000000000..4fd85888c --- /dev/null +++ b/test/grammar/types/runtime_ty/runtime_ty_1/stdout.golden @@ -0,0 +1,5 @@ +persons: + - name: Alice + age: 18 + - name: Bob + age: 10 diff --git a/test/grammar/types/runtime_ty/runtime_ty_err_0/main.k b/test/grammar/types/runtime_ty/runtime_ty_err_0/main.k new file mode 100644 index 000000000..77e5734a2 --- /dev/null +++ b/test/grammar/types/runtime_ty/runtime_ty_err_0/main.k @@ -0,0 +1,7 @@ +import json + +schema Person: + name: str + age: int + +person: Person = json.decode('{"err_name": "Alice", "age": 18}') diff --git a/test/grammar/types/runtime_ty/runtime_ty_err_0/stderr.golden b/test/grammar/types/runtime_ty/runtime_ty_err_0/stderr.golden new file mode 100644 index 000000000..95f352159 --- /dev/null +++ b/test/grammar/types/runtime_ty/runtime_ty_err_0/stderr.golden @@ -0,0 +1,6 @@ +error[E3M38]: EvaluationError + --> ${CWD}/main.k:7:1 + | +7 | person: Person = json.decode('{"err_name": "Alice", "age": 18}') + | expect Person, got dict + | \ No newline at end of file diff --git a/test/grammar/types/runtime_ty/runtime_ty_err_1/main.k b/test/grammar/types/runtime_ty/runtime_ty_err_1/main.k new file mode 100644 index 000000000..d80cdbecb --- /dev/null +++ b/test/grammar/types/runtime_ty/runtime_ty_err_1/main.k @@ -0,0 +1,7 @@ +import json + +schema Person: + name: str + age: int + +persons: [Person] = json.decode('[{"name": "Alice", "age": 18}, {"err_name": "Bob", "age": 10}]') diff --git a/test/grammar/types/runtime_ty/runtime_ty_err_1/stderr.golden b/test/grammar/types/runtime_ty/runtime_ty_err_1/stderr.golden new file mode 100644 index 000000000..ffd3fb239 --- /dev/null +++ b/test/grammar/types/runtime_ty/runtime_ty_err_1/stderr.golden @@ -0,0 +1 @@ +expect [Person], got list diff --git a/test/grammar/types/type_alias/type_alias_err_0/stderr.golden b/test/grammar/types/type_alias/type_alias_err_0/stderr.golden new file mode 100644 index 000000000..5cd856b3a --- /dev/null +++ b/test/grammar/types/type_alias/type_alias_err_0/stderr.golden @@ -0,0 +1,6 @@ +error[E2G22]: TypeError + --> ${CWD}/main.k:7:22 + | +7 | x1 = CheckArgType(1, "Golang") {} + | ^ expected str(KCL) | str(CUE), got str(Golang) + | \ No newline at end of file diff --git a/test/grammar/types/type_alias/type_alias_err_0/stderr.golden.py b/test/grammar/types/type_alias/type_alias_err_0/stderr.golden.py deleted file mode 100644 index 417f01bd8..000000000 --- a/test/grammar/types/type_alias/type_alias_err_0/stderr.golden.py +++ /dev/null @@ -1,22 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.TypeError_Compile_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=7, - col_no=22, - arg_msg="got str(Golang)" - ) - ], - arg_msg="expect str(KCL)|str(CUE), got str(Golang)" - ), - file=sys.stdout -) - diff --git a/test/grammar/types/type_alias/type_alias_err_1/stderr.golden b/test/grammar/types/type_alias/type_alias_err_1/stderr.golden new file mode 100644 index 000000000..ffe260563 --- /dev/null +++ b/test/grammar/types/type_alias/type_alias_err_1/stderr.golden @@ -0,0 +1,6 @@ +error[E2G22]: TypeError + --> ${CWD}/main.k:3:1 + | +3 | _name: Int = "Green" + | ^ expected int, got str(Green) + | \ No newline at end of file diff --git a/test/grammar/types/type_alias/type_alias_err_1/stderr.golden.py b/test/grammar/types/type_alias/type_alias_err_1/stderr.golden.py deleted file mode 100644 index 2808775f5..000000000 --- a/test/grammar/types/type_alias/type_alias_err_1/stderr.golden.py +++ /dev/null @@ -1,23 +0,0 @@ - -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.TypeError_Compile_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=3, - col_no=1, - arg_msg="got str(Green)" - ) - ], - arg_msg="expect int, got str(Green)" - ), - file=sys.stdout -) - diff --git a/test/grammar/types/type_alias/type_alias_err_2/stderr.golden b/test/grammar/types/type_alias/type_alias_err_2/stderr.golden new file mode 100644 index 000000000..e99ae0985 --- /dev/null +++ b/test/grammar/types/type_alias/type_alias_err_2/stderr.golden @@ -0,0 +1,6 @@ +error[E2G22]: TypeError + --> ${CWD}/main.k:4:1 + | +4 | _name: String = 1 + | ^ expected str, got int(1) + | \ No newline at end of file diff --git a/test/grammar/types/type_alias/type_alias_err_2/stderr.golden.py b/test/grammar/types/type_alias/type_alias_err_2/stderr.golden.py deleted file mode 100644 index 13bdcd2d1..000000000 --- a/test/grammar/types/type_alias/type_alias_err_2/stderr.golden.py +++ /dev/null @@ -1,22 +0,0 @@ - -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.TypeError_Compile_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=4, - col_no=1, - arg_msg="got int(1)" - ) - ], - arg_msg="expect str, got int(1)" - ), - file=sys.stdout -) diff --git a/test/grammar/types/type_alias/type_alias_err_3/stderr.golden b/test/grammar/types/type_alias/type_alias_err_3/stderr.golden new file mode 100644 index 000000000..e79a06a56 --- /dev/null +++ b/test/grammar/types/type_alias/type_alias_err_3/stderr.golden @@ -0,0 +1,6 @@ +error[E2G22]: TypeError + --> ${CWD}/main.k:4:1 + | +4 | _name: List = [1.1] + | ^ expected [str | int], got [float(1.1)] + | \ No newline at end of file diff --git a/test/grammar/types/type_alias/type_alias_err_3/stderr.golden.py b/test/grammar/types/type_alias/type_alias_err_3/stderr.golden.py deleted file mode 100644 index caefb2b20..000000000 --- a/test/grammar/types/type_alias/type_alias_err_3/stderr.golden.py +++ /dev/null @@ -1,22 +0,0 @@ - -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.TypeError_Compile_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=4, - col_no=1, - arg_msg="got [float(1.1)]" - ) - ], - arg_msg="expect [int|str], got [float(1.1)]" - ), - file=sys.stdout -) diff --git a/test/grammar/types/type_as/type_as_5/kcl.mod b/test/grammar/types/type_as/type_as_5/kcl.mod new file mode 100644 index 000000000..e69de29bb diff --git a/test/grammar/types/type_as/type_as_5/main.k b/test/grammar/types/type_as/type_as_5/main.k new file mode 100644 index 000000000..748279ee9 --- /dev/null +++ b/test/grammar/types/type_as/type_as_5/main.k @@ -0,0 +1,3 @@ +import pkg +foo: pkg.Foo | pkg.Bar = pkg.Foo{} +bar = foo as pkg.Foo diff --git a/test/grammar/types/type_as/type_as_5/pkg/pkg.k b/test/grammar/types/type_as/type_as_5/pkg/pkg.k new file mode 100644 index 000000000..d6f2188c8 --- /dev/null +++ b/test/grammar/types/type_as/type_as_5/pkg/pkg.k @@ -0,0 +1,8 @@ +schema Foo: + foo: int = 1 + +schema Bar: + bar: int = 1 + +foo: Foo | Bar = Foo{} +bar = foo as Foo diff --git a/test/grammar/types/type_as/type_as_5/stdout.golden b/test/grammar/types/type_as/type_as_5/stdout.golden new file mode 100644 index 000000000..1ded5182a --- /dev/null +++ b/test/grammar/types/type_as/type_as_5/stdout.golden @@ -0,0 +1,4 @@ +foo: + foo: 1 +bar: + foo: 1 diff --git a/test/grammar/types/type_as/type_as_6/main.k b/test/grammar/types/type_as/type_as_6/main.k new file mode 100644 index 000000000..d6f2188c8 --- /dev/null +++ b/test/grammar/types/type_as/type_as_6/main.k @@ -0,0 +1,8 @@ +schema Foo: + foo: int = 1 + +schema Bar: + bar: int = 1 + +foo: Foo | Bar = Foo{} +bar = foo as Foo diff --git a/test/grammar/types/type_as/type_as_6/stdout.golden b/test/grammar/types/type_as/type_as_6/stdout.golden new file mode 100644 index 000000000..1ded5182a --- /dev/null +++ b/test/grammar/types/type_as/type_as_6/stdout.golden @@ -0,0 +1,4 @@ +foo: + foo: 1 +bar: + foo: 1 diff --git a/test/grammar/types/type_as/type_as_err_0/stderr.golden b/test/grammar/types/type_as/type_as_err_0/stderr.golden new file mode 100644 index 000000000..3c386b3df --- /dev/null +++ b/test/grammar/types/type_as/type_as_err_0/stderr.golden @@ -0,0 +1,6 @@ +error[E2G22]: TypeError + --> ${CWD}/main.k:1:5 + | +1 | a = 1 as str + | ^ Conversion of type 'int(1)' to type 'str' may be a mistake because neither type sufficiently overlaps with the other + | \ No newline at end of file diff --git a/test/grammar/types/type_as/type_as_err_0/stderr.golden.py b/test/grammar/types/type_as/type_as_err_0/stderr.golden.py deleted file mode 100644 index 795286494..000000000 --- a/test/grammar/types/type_as/type_as_err_0/stderr.golden.py +++ /dev/null @@ -1,19 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.CompileError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=1, - ) - ], - arg_msg="Conversion of type 'int(1)' to type 'str' may be a mistake because neither type sufficiently overlaps with the other" - ), - file=sys.stdout -) diff --git a/test/grammar/types/type_as/type_as_err_1/stderr.golden b/test/grammar/types/type_as/type_as_err_1/stderr.golden new file mode 100644 index 000000000..8e12e3119 --- /dev/null +++ b/test/grammar/types/type_as/type_as_err_1/stderr.golden @@ -0,0 +1,6 @@ +error[E2G22]: TypeError + --> ${CWD}/main.k:2:12 + | +2 | b: float = a as float + | ^ Conversion of type 'int | str' to type 'float' may be a mistake because neither type sufficiently overlaps with the other + | \ No newline at end of file diff --git a/test/grammar/types/type_as/type_as_err_1/stderr.golden.py b/test/grammar/types/type_as/type_as_err_1/stderr.golden.py deleted file mode 100644 index 2e3ee4c80..000000000 --- a/test/grammar/types/type_as/type_as_err_1/stderr.golden.py +++ /dev/null @@ -1,19 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.CompileError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=2, - ) - ], - arg_msg="Conversion of type 'int|str' to type 'float' may be a mistake because neither type sufficiently overlaps with the other" - ), - file=sys.stdout -) diff --git a/test/grammar/types/type_as/type_as_err_2/main.k b/test/grammar/types/type_as/type_as_err_2/main.k new file mode 100644 index 000000000..391dd040e --- /dev/null +++ b/test/grammar/types/type_as/type_as_err_2/main.k @@ -0,0 +1,8 @@ +schema Foo: + foo: int = 1 + +schema Bar: + bar: int = 1 + +foo: Foo | Bar = Foo{} +bar = foo as Bar diff --git a/test/grammar/types/type_as/type_as_err_2/stderr.golden b/test/grammar/types/type_as/type_as_err_2/stderr.golden new file mode 100644 index 000000000..9d5e5183e --- /dev/null +++ b/test/grammar/types/type_as/type_as_err_2/stderr.golden @@ -0,0 +1,6 @@ +error[E3M38]: EvaluationError + --> ${CWD}/main.k:8:1 + | +8 | bar = foo as Bar + | expect Bar, got Foo + | diff --git a/test/grammar/types/type_as/type_as_err_3/base/base.k b/test/grammar/types/type_as/type_as_err_3/base/base.k new file mode 100644 index 000000000..ed80aae04 --- /dev/null +++ b/test/grammar/types/type_as/type_as_err_3/base/base.k @@ -0,0 +1,10 @@ +schema Base: + name: str + +schema A(Base): + bar: str + +a = A { + name: "base.A" + bar: "xxx" +} diff --git a/test/grammar/types/type_as/type_as_err_3/child/child.k b/test/grammar/types/type_as/type_as_err_3/child/child.k new file mode 100644 index 000000000..c3faf942b --- /dev/null +++ b/test/grammar/types/type_as/type_as_err_3/child/child.k @@ -0,0 +1,17 @@ +import base + +schema A(base.Base): + foo: str + +a = A { + name: "child.A" + foo: "test" +} + +# Cast to used for skip compile-time type check +_base_a: base.Base = base.a + +# Must fail at runtime: typeof(_base_a) == 'base.A' +base_a: A = _base_a as A +base_a_type = typeof(base_a, True) +child_a_type = typeof(a, True) diff --git a/test/grammar/types/type_as/type_as_err_3/kcl.mod b/test/grammar/types/type_as/type_as_err_3/kcl.mod new file mode 100644 index 000000000..d29a2e503 --- /dev/null +++ b/test/grammar/types/type_as/type_as_err_3/kcl.mod @@ -0,0 +1,4 @@ +[package] +name = "__main__" +edition = "0.0.1" +version = "0.0.1" diff --git a/test/grammar/types/type_as/type_as_err_3/main.k b/test/grammar/types/type_as/type_as_err_3/main.k new file mode 100644 index 000000000..1b2085fe8 --- /dev/null +++ b/test/grammar/types/type_as/type_as_err_3/main.k @@ -0,0 +1,19 @@ +import base +import child + +schema A(base.Base): + name: str + main: str + +a = A { + name: "main.A" + main: "123" +} + +type AA = child.A + +# Cast to / used for skip compile-time type check +_child_a: base.Base = child.a +# Must fail at runtime: typeof(_child_a) == 'child.A' +child_a = _child_a as A +child_a_type = typeof(_child_a,True) diff --git a/test/grammar/types/type_as/type_as_err_3/stderr.golden b/test/grammar/types/type_as/type_as_err_3/stderr.golden new file mode 100644 index 000000000..8dc529e3c --- /dev/null +++ b/test/grammar/types/type_as/type_as_err_3/stderr.golden @@ -0,0 +1,6 @@ +error[E3M38]: EvaluationError + --> ${CWD}/child/child.k:15:1 + | +15 | base_a: A = _base_a as A + | expect A, got base.A + | diff --git a/test/grammar/types/type_as/type_as_err_4/base/base.k b/test/grammar/types/type_as/type_as_err_4/base/base.k new file mode 100644 index 000000000..ed80aae04 --- /dev/null +++ b/test/grammar/types/type_as/type_as_err_4/base/base.k @@ -0,0 +1,10 @@ +schema Base: + name: str + +schema A(Base): + bar: str + +a = A { + name: "base.A" + bar: "xxx" +} diff --git a/test/grammar/types/type_as/type_as_err_4/child/child.k b/test/grammar/types/type_as/type_as_err_4/child/child.k new file mode 100644 index 000000000..13d27abf5 --- /dev/null +++ b/test/grammar/types/type_as/type_as_err_4/child/child.k @@ -0,0 +1,9 @@ +import base + +schema A(base.Base): + foo: str + +a = A { + name: "child.A" + foo: "test" +} diff --git a/test/grammar/types/type_as/type_as_err_4/kcl.mod b/test/grammar/types/type_as/type_as_err_4/kcl.mod new file mode 100644 index 000000000..d29a2e503 --- /dev/null +++ b/test/grammar/types/type_as/type_as_err_4/kcl.mod @@ -0,0 +1,4 @@ +[package] +name = "__main__" +edition = "0.0.1" +version = "0.0.1" diff --git a/test/grammar/types/type_as/type_as_err_4/main.k b/test/grammar/types/type_as/type_as_err_4/main.k new file mode 100644 index 000000000..1b2085fe8 --- /dev/null +++ b/test/grammar/types/type_as/type_as_err_4/main.k @@ -0,0 +1,19 @@ +import base +import child + +schema A(base.Base): + name: str + main: str + +a = A { + name: "main.A" + main: "123" +} + +type AA = child.A + +# Cast to / used for skip compile-time type check +_child_a: base.Base = child.a +# Must fail at runtime: typeof(_child_a) == 'child.A' +child_a = _child_a as A +child_a_type = typeof(_child_a,True) diff --git a/test/grammar/types/type_as/type_as_err_4/stderr.golden b/test/grammar/types/type_as/type_as_err_4/stderr.golden new file mode 100644 index 000000000..857ba7d21 --- /dev/null +++ b/test/grammar/types/type_as/type_as_err_4/stderr.golden @@ -0,0 +1,6 @@ +error[E3M38]: EvaluationError + --> ${CWD}/main.k:18:1 + | +18 | child_a = _child_a as A + | expect A, got child.A + | diff --git a/test/grammar/types/union_expr/union_expr_0/main.k b/test/grammar/types/union_expr/union_expr_0/main.k new file mode 100644 index 000000000..02b6375c7 --- /dev/null +++ b/test/grammar/types/union_expr/union_expr_0/main.k @@ -0,0 +1,14 @@ +schema Container: + name: str + image: str + volumeMounts: [{str:}] + +config = { + image = "test/test-container:test-cluster" + volumeMounts = [{ + name = "config" + mountPath = "/app/config" + }] +} + +expected: Container = config | {name = "test-repo/test-image:test-tag"} diff --git a/test/grammar/types/union_expr/union_expr_0/stdout.golden b/test/grammar/types/union_expr/union_expr_0/stdout.golden new file mode 100644 index 000000000..d06053bb0 --- /dev/null +++ b/test/grammar/types/union_expr/union_expr_0/stdout.golden @@ -0,0 +1,11 @@ +config: + image: test/test-container:test-cluster + volumeMounts: + - name: config + mountPath: /app/config +expected: + name: test-repo/test-image:test-tag + image: test/test-container:test-cluster + volumeMounts: + - name: config + mountPath: /app/config diff --git a/test/grammar/types/union_expr/union_expr_1/main.k b/test/grammar/types/union_expr/union_expr_1/main.k new file mode 100644 index 000000000..e4d638054 --- /dev/null +++ b/test/grammar/types/union_expr/union_expr_1/main.k @@ -0,0 +1,16 @@ +schema Container: + name: str + image: str + volumeMounts: [{str:}] + +schema Config: + _config = { + image = "test/test-container:test-cluster" + volumeMounts = [{ + name = "config" + mountPath = "/app/config" + }] + } + expected: Container = _config | {name = "test-repo/test-image:test-tag"} + +config = Config {} diff --git a/test/grammar/types/union_expr/union_expr_1/stdout.golden b/test/grammar/types/union_expr/union_expr_1/stdout.golden new file mode 100644 index 000000000..6918159dd --- /dev/null +++ b/test/grammar/types/union_expr/union_expr_1/stdout.golden @@ -0,0 +1,7 @@ +config: + expected: + name: test-repo/test-image:test-tag + image: test/test-container:test-cluster + volumeMounts: + - name: config + mountPath: /app/config diff --git a/test/grammar/types/union_expr/union_expr_fail_0/main.k b/test/grammar/types/union_expr/union_expr_fail_0/main.k new file mode 100644 index 000000000..5366ff5ea --- /dev/null +++ b/test/grammar/types/union_expr/union_expr_fail_0/main.k @@ -0,0 +1,14 @@ +schema Container: + name: str + image: str + volumeMounts: [{str:}] + +config = { + image = "test/test-container:test-cluster" + volumeMounts = [{ + name = "config" + mountPath = "/app/config" + }] +} + +expected: Container = config | {name = 1} diff --git a/test/grammar/types/union_expr/union_expr_fail_0/stderr.golden b/test/grammar/types/union_expr/union_expr_fail_0/stderr.golden new file mode 100644 index 000000000..343df5335 --- /dev/null +++ b/test/grammar/types/union_expr/union_expr_fail_0/stderr.golden @@ -0,0 +1,6 @@ +error[E2G22]: TypeError + --> ${CWD}/main.k:14:33 + | +14 | expected: Container = config | {name = 1} + | ^ expected str, got int(1) + | diff --git a/test/grammar/types/union_expr/union_expr_fail_1/main.k b/test/grammar/types/union_expr/union_expr_fail_1/main.k new file mode 100644 index 000000000..a99710fe2 --- /dev/null +++ b/test/grammar/types/union_expr/union_expr_fail_1/main.k @@ -0,0 +1,16 @@ +schema Container: + name: str + image: str + volumeMounts: [{str:}] + +schema Config: + _config = { + image = "test/test-container:test-cluster" + volumeMounts = [{ + name = "config" + mountPath = "/app/config" + }] + } + expected: Container = _config | {name = 1} + +config = Config {} diff --git a/test/grammar/types/union_expr/union_expr_fail_1/stderr.golden b/test/grammar/types/union_expr/union_expr_fail_1/stderr.golden new file mode 100644 index 000000000..b945f754e --- /dev/null +++ b/test/grammar/types/union_expr/union_expr_fail_1/stderr.golden @@ -0,0 +1,6 @@ +error[E2G22]: TypeError + --> ${CWD}/main.k:14:38 + | +14 | expected: Container = _config | {name = 1} + | ^ expected str, got int(1) + | diff --git a/test/grammar/types/union_expr/union_expr_fail_2/main.k b/test/grammar/types/union_expr/union_expr_fail_2/main.k new file mode 100644 index 000000000..ee5d194d4 --- /dev/null +++ b/test/grammar/types/union_expr/union_expr_fail_2/main.k @@ -0,0 +1,17 @@ +schema Container: + name: str + image: str + volumeMounts: [{str:}] + +schema Config: + _config = { + name = 1 + image = "test/test-container:test-cluster" + volumeMounts = [{ + name = "config" + mountPath = "/app/config" + }] + } + expected: Container = _config | {} + +config = Config {} diff --git a/test/grammar/types/union_expr/union_expr_fail_2/stderr.golden b/test/grammar/types/union_expr/union_expr_fail_2/stderr.golden new file mode 100644 index 000000000..5ef591674 --- /dev/null +++ b/test/grammar/types/union_expr/union_expr_fail_2/stderr.golden @@ -0,0 +1,6 @@ +error[E3M38]: EvaluationError + --> ${CWD}/main.k:2:1 + | +2 | name: str + | expect str, got int + | diff --git a/test/grammar/types/union_ty/union_ty_0/main.k b/test/grammar/types/union_ty/union_ty_0/main.k new file mode 100644 index 000000000..4067fdc5f --- /dev/null +++ b/test/grammar/types/union_ty/union_ty_0/main.k @@ -0,0 +1,12 @@ +schema A: + a: int + +schema B: + b: int + +schema X: + x: A | B + +x = X { + x.a = 1 +} diff --git a/test/grammar/types/union_ty/union_ty_0/stdout.golden b/test/grammar/types/union_ty/union_ty_0/stdout.golden new file mode 100644 index 000000000..09785193a --- /dev/null +++ b/test/grammar/types/union_ty/union_ty_0/stdout.golden @@ -0,0 +1,3 @@ +x: + x: + a: 1 diff --git a/test/grammar/types/union_ty/union_ty_1/main.k b/test/grammar/types/union_ty/union_ty_1/main.k new file mode 100644 index 000000000..9ce97d381 --- /dev/null +++ b/test/grammar/types/union_ty/union_ty_1/main.k @@ -0,0 +1,12 @@ +schema A: + a: int + +schema B: + b: int + +schema X: + x: A | B + +x = X { + x.b = 1 +} diff --git a/test/grammar/types/union_ty/union_ty_1/stdout.golden b/test/grammar/types/union_ty/union_ty_1/stdout.golden new file mode 100644 index 000000000..5e7e776a0 --- /dev/null +++ b/test/grammar/types/union_ty/union_ty_1/stdout.golden @@ -0,0 +1,3 @@ +x: + x: + b: 1 diff --git a/test/grammar/types/union_ty/union_ty_10/main.k b/test/grammar/types/union_ty/union_ty_10/main.k new file mode 100644 index 000000000..d9305905c --- /dev/null +++ b/test/grammar/types/union_ty/union_ty_10/main.k @@ -0,0 +1,13 @@ +schema A: + a: int + +schema B(A): + b: int = a + +schema X: + x: A | B + +x = X { + x.a = 1 + x.b = 2 +} diff --git a/test/grammar/types/union_ty/union_ty_10/stdout.golden b/test/grammar/types/union_ty/union_ty_10/stdout.golden new file mode 100644 index 000000000..eaa1a7893 --- /dev/null +++ b/test/grammar/types/union_ty/union_ty_10/stdout.golden @@ -0,0 +1,4 @@ +x: + x: + a: 1 + b: 2 diff --git a/test/grammar/types/union_ty/union_ty_11/main.k b/test/grammar/types/union_ty/union_ty_11/main.k new file mode 100644 index 000000000..0ecbbb635 --- /dev/null +++ b/test/grammar/types/union_ty/union_ty_11/main.k @@ -0,0 +1,6 @@ +metadata = { + name = "app" + labels.app = "app" +} +labels: {str:str} = metadata.labels + diff --git a/test/grammar/types/union_ty/union_ty_11/stdout.golden b/test/grammar/types/union_ty/union_ty_11/stdout.golden new file mode 100644 index 000000000..b230162b2 --- /dev/null +++ b/test/grammar/types/union_ty/union_ty_11/stdout.golden @@ -0,0 +1,6 @@ +metadata: + name: app + labels: + app: app +labels: + app: app diff --git a/test/grammar/types/union_ty/union_ty_12/main.k b/test/grammar/types/union_ty/union_ty_12/main.k new file mode 100644 index 000000000..44a97d4e9 --- /dev/null +++ b/test/grammar/types/union_ty/union_ty_12/main.k @@ -0,0 +1,6 @@ +metadata = { + name = "app" + labels.app = "app" +} +labels: {str:str} = {**metadata.labels} + diff --git a/test/grammar/types/union_ty/union_ty_12/stdout.golden b/test/grammar/types/union_ty/union_ty_12/stdout.golden new file mode 100644 index 000000000..b230162b2 --- /dev/null +++ b/test/grammar/types/union_ty/union_ty_12/stdout.golden @@ -0,0 +1,6 @@ +metadata: + name: app + labels: + app: app +labels: + app: app diff --git a/test/grammar/types/union_ty/union_ty_2/main.k b/test/grammar/types/union_ty/union_ty_2/main.k new file mode 100644 index 000000000..487889c33 --- /dev/null +++ b/test/grammar/types/union_ty/union_ty_2/main.k @@ -0,0 +1,15 @@ +schema A: + a: int + +schema B: + b: int + +schema C(B): + c: int + +schema X: + x: A | B + +x = X { + x.b = 1 +} diff --git a/test/grammar/types/union_ty/union_ty_2/stdout.golden b/test/grammar/types/union_ty/union_ty_2/stdout.golden new file mode 100644 index 000000000..5e7e776a0 --- /dev/null +++ b/test/grammar/types/union_ty/union_ty_2/stdout.golden @@ -0,0 +1,3 @@ +x: + x: + b: 1 diff --git a/test/grammar/types/union_ty/union_ty_3/main.k b/test/grammar/types/union_ty/union_ty_3/main.k new file mode 100644 index 000000000..c46394792 --- /dev/null +++ b/test/grammar/types/union_ty/union_ty_3/main.k @@ -0,0 +1,12 @@ +schema A: + a: int + +schema B: + b: int + +schema X: + x: [A | B] + +x = X { + x = [{a = 1}, {b = 2}] +} diff --git a/test/grammar/types/union_ty/union_ty_3/stdout.golden b/test/grammar/types/union_ty/union_ty_3/stdout.golden new file mode 100644 index 000000000..1ea03027e --- /dev/null +++ b/test/grammar/types/union_ty/union_ty_3/stdout.golden @@ -0,0 +1,4 @@ +x: + x: + - a: 1 + - b: 2 diff --git a/test/grammar/types/union_ty/union_ty_4/main.k b/test/grammar/types/union_ty/union_ty_4/main.k new file mode 100644 index 000000000..a4d8b4f78 --- /dev/null +++ b/test/grammar/types/union_ty/union_ty_4/main.k @@ -0,0 +1,9 @@ +schema A: + a: int + +schema X: + x: A | "1" + +x = X { + x.a = 1 +} diff --git a/test/grammar/types/union_ty/union_ty_4/stdout.golden b/test/grammar/types/union_ty/union_ty_4/stdout.golden new file mode 100644 index 000000000..09785193a --- /dev/null +++ b/test/grammar/types/union_ty/union_ty_4/stdout.golden @@ -0,0 +1,3 @@ +x: + x: + a: 1 diff --git a/test/grammar/types/union_ty/union_ty_5/main.k b/test/grammar/types/union_ty/union_ty_5/main.k new file mode 100644 index 000000000..a6d17ea0a --- /dev/null +++ b/test/grammar/types/union_ty/union_ty_5/main.k @@ -0,0 +1,11 @@ +schema A: + a: int + +schema X: + x: [A | "1"] + y: ["2" | A] + +x = X { + x: [{a = 1}] + y: [{a = 2}] +} diff --git a/test/grammar/types/union_ty/union_ty_5/stdout.golden b/test/grammar/types/union_ty/union_ty_5/stdout.golden new file mode 100644 index 000000000..52ed8310b --- /dev/null +++ b/test/grammar/types/union_ty/union_ty_5/stdout.golden @@ -0,0 +1,5 @@ +x: + x: + - a: 1 + y: + - a: 2 diff --git a/test/grammar/types/union_ty/union_ty_6/main.k b/test/grammar/types/union_ty/union_ty_6/main.k new file mode 100644 index 000000000..f893ca3c6 --- /dev/null +++ b/test/grammar/types/union_ty/union_ty_6/main.k @@ -0,0 +1,14 @@ +schema A: + a: int + +schema B: + b: int + +schema X: + x: A | "1" + y: "2" | B + +x = X { + x.a = 1 + y.b = 2 +} diff --git a/test/grammar/types/union_ty/union_ty_6/stdout.golden b/test/grammar/types/union_ty/union_ty_6/stdout.golden new file mode 100644 index 000000000..5b52e9920 --- /dev/null +++ b/test/grammar/types/union_ty/union_ty_6/stdout.golden @@ -0,0 +1,5 @@ +x: + x: + a: 1 + y: + b: 2 diff --git a/test/grammar/types/union_ty/union_ty_7/main.k b/test/grammar/types/union_ty/union_ty_7/main.k new file mode 100644 index 000000000..55e2e105c --- /dev/null +++ b/test/grammar/types/union_ty/union_ty_7/main.k @@ -0,0 +1,13 @@ +schema A: + a: int + +schema B: + b: int + +schema X: + x: {str: A | B} + +x = X { + x.a.a = 1 + x.b.b = 2 +} diff --git a/test/grammar/types/union_ty/union_ty_7/stdout.golden b/test/grammar/types/union_ty/union_ty_7/stdout.golden new file mode 100644 index 000000000..2006676c6 --- /dev/null +++ b/test/grammar/types/union_ty/union_ty_7/stdout.golden @@ -0,0 +1,6 @@ +x: + x: + a: + a: 1 + b: + b: 2 diff --git a/test/grammar/types/union_ty/union_ty_8/main.k b/test/grammar/types/union_ty/union_ty_8/main.k new file mode 100644 index 000000000..a4b3044c1 --- /dev/null +++ b/test/grammar/types/union_ty/union_ty_8/main.k @@ -0,0 +1,14 @@ +schema A: + a: int + +schema B: + b: int + c: int = b + 1 + +schema X: + x: {str: A | B} + +x = X { + x.a.a = 1 + x.b.b = 2 +} diff --git a/test/grammar/types/union_ty/union_ty_8/stdout.golden b/test/grammar/types/union_ty/union_ty_8/stdout.golden new file mode 100644 index 000000000..690d4b806 --- /dev/null +++ b/test/grammar/types/union_ty/union_ty_8/stdout.golden @@ -0,0 +1,7 @@ +x: + x: + a: + a: 1 + b: + b: 2 + c: 3 diff --git a/test/grammar/types/union_ty/union_ty_9/main.k b/test/grammar/types/union_ty/union_ty_9/main.k new file mode 100644 index 000000000..0f95a06c6 --- /dev/null +++ b/test/grammar/types/union_ty/union_ty_9/main.k @@ -0,0 +1,12 @@ +schema A: + a: int + +schema B(A): + b: int = a + +schema X: + x: B + +x = X { + x.a = 1 +} diff --git a/test/grammar/types/union_ty/union_ty_9/stdout.golden b/test/grammar/types/union_ty/union_ty_9/stdout.golden new file mode 100644 index 000000000..8103e3962 --- /dev/null +++ b/test/grammar/types/union_ty/union_ty_9/stdout.golden @@ -0,0 +1,4 @@ +x: + x: + a: 1 + b: 1 diff --git a/test/grammar/types/union_ty/union_ty_err_0/main.k b/test/grammar/types/union_ty/union_ty_err_0/main.k new file mode 100644 index 000000000..f561dfb38 --- /dev/null +++ b/test/grammar/types/union_ty/union_ty_err_0/main.k @@ -0,0 +1,12 @@ +schema A: + a: int + +schema B: + b: int + +schema X: + x: A | B + +x = X { + x.c = 1 +} diff --git a/test/grammar/types/union_ty/union_ty_err_0/stderr.golden b/test/grammar/types/union_ty/union_ty_err_0/stderr.golden new file mode 100644 index 000000000..1c5283530 --- /dev/null +++ b/test/grammar/types/union_ty/union_ty_err_0/stderr.golden @@ -0,0 +1,6 @@ +error[E2L23]: CompileError + --> ${CWD}/main.k:11:7 + | +11 | x.c = 1 + | ^ Cannot add member 'c' to 'schemas ["A", "B"]' + | \ No newline at end of file diff --git a/test/grammar/types/union_ty/union_ty_err_1/main.k b/test/grammar/types/union_ty/union_ty_err_1/main.k new file mode 100644 index 000000000..5a59573a0 --- /dev/null +++ b/test/grammar/types/union_ty/union_ty_err_1/main.k @@ -0,0 +1,15 @@ +schema A: + a: int + +schema B: + b: int + +schema C(B): + c: int + +schema X: + x: A | B | C + +x = X { + x.d = 1 +} diff --git a/test/grammar/types/union_ty/union_ty_err_1/stderr.golden b/test/grammar/types/union_ty/union_ty_err_1/stderr.golden new file mode 100644 index 000000000..17e9a0ce7 --- /dev/null +++ b/test/grammar/types/union_ty/union_ty_err_1/stderr.golden @@ -0,0 +1,6 @@ +error[E2L23]: CompileError + --> ${CWD}/main.k:14:7 + | +14 | x.d = 1 + | ^ Cannot add member 'd' to 'schemas ["A", "B", "C"]' + | \ No newline at end of file diff --git a/test/grammar/types/var_type_annotation/type_fail_0/stderr.golden b/test/grammar/types/var_type_annotation/type_fail_0/stderr.golden new file mode 100644 index 000000000..f1d3258f2 --- /dev/null +++ b/test/grammar/types/var_type_annotation/type_fail_0/stderr.golden @@ -0,0 +1,6 @@ +error[E2G22]: TypeError + --> ${CWD}/main.k:1:1 + | +1 | _name: int = "Green" + | ^ expected int, got str(Green) + | \ No newline at end of file diff --git a/test/grammar/types/var_type_annotation/type_fail_0/stderr.golden.py b/test/grammar/types/var_type_annotation/type_fail_0/stderr.golden.py deleted file mode 100644 index 668619141..000000000 --- a/test/grammar/types/var_type_annotation/type_fail_0/stderr.golden.py +++ /dev/null @@ -1,23 +0,0 @@ - -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.TypeError_Compile_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=1, - col_no=1, - arg_msg="got str(Green)" - ) - ], - arg_msg="expect int, got str(Green)" - ), - file=sys.stdout -) - diff --git a/test/grammar/types/var_type_annotation/type_fail_1/stderr.golden b/test/grammar/types/var_type_annotation/type_fail_1/stderr.golden new file mode 100644 index 000000000..4128e3ce6 --- /dev/null +++ b/test/grammar/types/var_type_annotation/type_fail_1/stderr.golden @@ -0,0 +1,6 @@ +error[E2G22]: TypeError + --> ${CWD}/main.k:1:1 + | +1 | _name: str = 1 + | ^ expected str, got int(1) + | \ No newline at end of file diff --git a/test/grammar/types/var_type_annotation/type_fail_1/stderr.golden.py b/test/grammar/types/var_type_annotation/type_fail_1/stderr.golden.py deleted file mode 100644 index 6442aca70..000000000 --- a/test/grammar/types/var_type_annotation/type_fail_1/stderr.golden.py +++ /dev/null @@ -1,23 +0,0 @@ - -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.TypeError_Compile_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=1, - col_no=1, - arg_msg="got int(1)" - ) - ], - arg_msg="expect str, got int(1)" - ), - file=sys.stdout -) - diff --git a/test/grammar/types/var_type_annotation/type_fail_10/main.k b/test/grammar/types/var_type_annotation/type_fail_10/main.k new file mode 100644 index 000000000..13bd190a9 --- /dev/null +++ b/test/grammar/types/var_type_annotation/type_fail_10/main.k @@ -0,0 +1,9 @@ +schema Foo: + foo: int + +schema Bar: + bar: int + +foo: Foo = Bar { + bar: 1 +} diff --git a/test/grammar/types/var_type_annotation/type_fail_10/stderr.golden b/test/grammar/types/var_type_annotation/type_fail_10/stderr.golden new file mode 100644 index 000000000..05a596bbb --- /dev/null +++ b/test/grammar/types/var_type_annotation/type_fail_10/stderr.golden @@ -0,0 +1,6 @@ +error[E2G22]: TypeError + --> ${CWD}/main.k:7:1 + | +7 | foo: Foo = Bar { + | ^ expected Foo, got Bar + | \ No newline at end of file diff --git a/test/grammar/types/var_type_annotation/type_fail_11/main.k b/test/grammar/types/var_type_annotation/type_fail_11/main.k new file mode 100644 index 000000000..605bd8e93 --- /dev/null +++ b/test/grammar/types/var_type_annotation/type_fail_11/main.k @@ -0,0 +1,7 @@ +schema Foo: + foo: int + +schema Bar: + bar: int + +foo: Foo = 1 diff --git a/test/grammar/types/var_type_annotation/type_fail_11/stderr.golden b/test/grammar/types/var_type_annotation/type_fail_11/stderr.golden new file mode 100644 index 000000000..e47dbc781 --- /dev/null +++ b/test/grammar/types/var_type_annotation/type_fail_11/stderr.golden @@ -0,0 +1,6 @@ +error[E2G22]: TypeError + --> ${CWD}/main.k:7:1 + | +7 | foo: Foo = 1 + | ^ expected Foo, got int(1) + | \ No newline at end of file diff --git a/test/grammar/types/var_type_annotation/type_fail_12/main.k b/test/grammar/types/var_type_annotation/type_fail_12/main.k new file mode 100644 index 000000000..3206d9486 --- /dev/null +++ b/test/grammar/types/var_type_annotation/type_fail_12/main.k @@ -0,0 +1,9 @@ +schema Foo: + foo: int + +schema Bar: + bar: int + +foo: int = Foo { + foo = 1 +} diff --git a/test/grammar/types/var_type_annotation/type_fail_12/stderr.golden b/test/grammar/types/var_type_annotation/type_fail_12/stderr.golden new file mode 100644 index 000000000..0bdabe257 --- /dev/null +++ b/test/grammar/types/var_type_annotation/type_fail_12/stderr.golden @@ -0,0 +1,6 @@ +error[E2G22]: TypeError + --> ${CWD}/main.k:7:1 + | +7 | foo: int = Foo { + | ^ expected int, got Foo + | \ No newline at end of file diff --git a/test/grammar/types/var_type_annotation/type_fail_13/main.k b/test/grammar/types/var_type_annotation/type_fail_13/main.k new file mode 100644 index 000000000..8f52ec65b --- /dev/null +++ b/test/grammar/types/var_type_annotation/type_fail_13/main.k @@ -0,0 +1,4 @@ +config: {"A"|"B": int} = { + if True: + A = "2" +} diff --git a/test/grammar/types/var_type_annotation/type_fail_13/stderr.golden b/test/grammar/types/var_type_annotation/type_fail_13/stderr.golden new file mode 100644 index 000000000..ba781a519 --- /dev/null +++ b/test/grammar/types/var_type_annotation/type_fail_13/stderr.golden @@ -0,0 +1,38 @@ +error[E2G22]: TypeError + --> ${CWD}/main.k:3:9 + | +3 | A = "2" + | ^ expected int, got str(2) + | + + --> ${CWD}/main.k:1:1 + | +1 | config: {"A"|"B": int} = { + | ^ variable is defined here, its type is int, but got str(2) + | + +error[E2G22]: TypeError + --> ${CWD}/main.k:2:5 + | +2 | if True: + | ^ expected int, got str + | + + --> ${CWD}/main.k:1:1 + | +1 | config: {"A"|"B": int} = { + | ^ variable is defined here, its type is int, but got str + | + + --> ${CWD}/main.k:3:9 + | +3 | A = "2" + | ^ config attribute is defined here + | + +error[E2G22]: TypeError + --> ${CWD}/main.k:1:1 + | +1 | config: {"A"|"B": int} = { + | ^ expected {str(A) | str(B):int}, got {str(A):str(2)} + | \ No newline at end of file diff --git a/test/grammar/types/var_type_annotation/type_fail_14/main.k b/test/grammar/types/var_type_annotation/type_fail_14/main.k new file mode 100644 index 000000000..c2cb07dc4 --- /dev/null +++ b/test/grammar/types/var_type_annotation/type_fail_14/main.k @@ -0,0 +1,4 @@ +config: {"A"|"B": int} = { + if True: + C = 1 +} diff --git a/test/grammar/types/var_type_annotation/type_fail_14/stderr.golden b/test/grammar/types/var_type_annotation/type_fail_14/stderr.golden new file mode 100644 index 000000000..aeb321f0a --- /dev/null +++ b/test/grammar/types/var_type_annotation/type_fail_14/stderr.golden @@ -0,0 +1,6 @@ +error[E2G22]: TypeError + --> ${CWD}/main.k:1:1 + | +1 | config: {"A"|"B": int} = { + | ^ expected {str(A) | str(B):int}, got {str(C):int(1)} + | \ No newline at end of file diff --git a/test/grammar/types/var_type_annotation/type_fail_15/main.k b/test/grammar/types/var_type_annotation/type_fail_15/main.k new file mode 100644 index 000000000..2f3fc1304 --- /dev/null +++ b/test/grammar/types/var_type_annotation/type_fail_15/main.k @@ -0,0 +1,21 @@ +innerConfig = { + name = 1 + config = { + name = 1 + } +} + +config = { + **innerConfig +} + +schema Config: + name: str + config: ConfigInner + +schema ConfigInner: + name: str + +c = Config { + **config +} diff --git a/test/grammar/types/var_type_annotation/type_fail_15/stderr.golden b/test/grammar/types/var_type_annotation/type_fail_15/stderr.golden new file mode 100644 index 000000000..8cb55b06f --- /dev/null +++ b/test/grammar/types/var_type_annotation/type_fail_15/stderr.golden @@ -0,0 +1,37 @@ +error[E2G22]: TypeError + --> ${CWD}/main.k:20:7 + | +20 | **config + | ^ expected str, got int + | + + --> ${CWD}/main.k:13:5 + | +13 | name: str + | ^ variable is defined here, its type is str, but got int + | + + --> ${CWD}/main.k:2:5 + | +2 | name = 1 + | ^ config attribute is defined here + | + +error[E2G22]: TypeError + --> ${CWD}/main.k:20:7 + | +20 | **config + | ^ expected str, got int + | + + --> ${CWD}/main.k:17:5 + | +17 | name: str + | ^ variable is defined here, its type is str, but got int + | + + --> ${CWD}/main.k:4:9 + | +4 | name = 1 + | ^ config attribute is defined here + | \ No newline at end of file diff --git a/test/grammar/types/var_type_annotation/type_fail_2/stderr.golden b/test/grammar/types/var_type_annotation/type_fail_2/stderr.golden new file mode 100644 index 000000000..d95421823 --- /dev/null +++ b/test/grammar/types/var_type_annotation/type_fail_2/stderr.golden @@ -0,0 +1,6 @@ +error[E2G22]: TypeError + --> ${CWD}/main.k:2:1 + | +2 | _name = "s" + | ^ expected int, got str(s) + | \ No newline at end of file diff --git a/test/grammar/types/var_type_annotation/type_fail_2/stderr.golden.py b/test/grammar/types/var_type_annotation/type_fail_2/stderr.golden.py deleted file mode 100644 index e2dfd60c7..000000000 --- a/test/grammar/types/var_type_annotation/type_fail_2/stderr.golden.py +++ /dev/null @@ -1,22 +0,0 @@ - -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.TypeError_Compile_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=2, - col_no=1, - arg_msg="got str(s)" - ) - ], - arg_msg="expect int, got str(s)" - ), - file=sys.stdout -) diff --git a/test/grammar/types/var_type_annotation/type_fail_3/stderr.golden b/test/grammar/types/var_type_annotation/type_fail_3/stderr.golden new file mode 100644 index 000000000..b3d1f3f57 --- /dev/null +++ b/test/grammar/types/var_type_annotation/type_fail_3/stderr.golden @@ -0,0 +1,6 @@ +error[E2G22]: TypeError + --> ${CWD}/main.k:2:1 + | +2 | _name = 1 + | ^ expected str, got int(1) + | \ No newline at end of file diff --git a/test/grammar/types/var_type_annotation/type_fail_3/stderr.golden.py b/test/grammar/types/var_type_annotation/type_fail_3/stderr.golden.py deleted file mode 100644 index 7d9b6c6b1..000000000 --- a/test/grammar/types/var_type_annotation/type_fail_3/stderr.golden.py +++ /dev/null @@ -1,22 +0,0 @@ - -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.TypeError_Compile_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=2, - col_no=1, - arg_msg="got int(1)" - ) - ], - arg_msg="expect str, got int(1)" - ), - file=sys.stdout -) diff --git a/test/grammar/types/var_type_annotation/type_fail_4/stderr.golden b/test/grammar/types/var_type_annotation/type_fail_4/stderr.golden new file mode 100644 index 000000000..18319fcf8 --- /dev/null +++ b/test/grammar/types/var_type_annotation/type_fail_4/stderr.golden @@ -0,0 +1,6 @@ +error[E2G22]: TypeError + --> ${CWD}/main.k:2:1 + | +2 | _name = [1] + | ^ expected [str], got [int(1)] + | \ No newline at end of file diff --git a/test/grammar/types/var_type_annotation/type_fail_4/stderr.golden.py b/test/grammar/types/var_type_annotation/type_fail_4/stderr.golden.py deleted file mode 100644 index 489f83b52..000000000 --- a/test/grammar/types/var_type_annotation/type_fail_4/stderr.golden.py +++ /dev/null @@ -1,23 +0,0 @@ - -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.TypeError_Compile_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=2, - col_no=1, - arg_msg="got [int(1)]" - ) - ], - arg_msg="expect [str], got [int(1)]" - ), - file=sys.stdout -) - diff --git a/test/grammar/types/var_type_annotation/type_fail_5/stderr.golden b/test/grammar/types/var_type_annotation/type_fail_5/stderr.golden new file mode 100644 index 000000000..9f6415eb1 --- /dev/null +++ b/test/grammar/types/var_type_annotation/type_fail_5/stderr.golden @@ -0,0 +1,6 @@ +error[E2G22]: TypeError + --> ${CWD}/main.k:2:1 + | +2 | _name = [1.1] + | ^ expected [str | int], got [float(1.1)] + | \ No newline at end of file diff --git a/test/grammar/types/var_type_annotation/type_fail_5/stderr.golden.py b/test/grammar/types/var_type_annotation/type_fail_5/stderr.golden.py deleted file mode 100644 index f0387221d..000000000 --- a/test/grammar/types/var_type_annotation/type_fail_5/stderr.golden.py +++ /dev/null @@ -1,22 +0,0 @@ - -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.TypeError_Compile_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=2, - col_no=1, - arg_msg="got [float(1.1)]" - ) - ], - arg_msg="expect [int|str], got [float(1.1)]" - ), - file=sys.stdout -) diff --git a/test/grammar/types/var_type_annotation/type_fail_6/stderr.golden b/test/grammar/types/var_type_annotation/type_fail_6/stderr.golden new file mode 100644 index 000000000..955c1d961 --- /dev/null +++ b/test/grammar/types/var_type_annotation/type_fail_6/stderr.golden @@ -0,0 +1,6 @@ +error[E2G22]: TypeError + --> ${CWD}/main.k:1:1 + | +1 | name: "aa\"ab|" = "aa\"ab" + | ^ expected str(aa"ab|), got str(aa"ab) + | \ No newline at end of file diff --git a/test/grammar/types/var_type_annotation/type_fail_6/stderr.golden.py b/test/grammar/types/var_type_annotation/type_fail_6/stderr.golden.py deleted file mode 100644 index 86b1bd64c..000000000 --- a/test/grammar/types/var_type_annotation/type_fail_6/stderr.golden.py +++ /dev/null @@ -1,23 +0,0 @@ - -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.TypeError_Compile_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=1, - col_no=1, - arg_msg='got str(aa"ab)' - ) - ], - arg_msg='expect str(aa"ab|), got str(aa"ab)' - ), - file=sys.stdout -) - diff --git a/test/grammar/types/var_type_annotation/type_fail_7/stderr.golden b/test/grammar/types/var_type_annotation/type_fail_7/stderr.golden new file mode 100644 index 000000000..da4c9e69a --- /dev/null +++ b/test/grammar/types/var_type_annotation/type_fail_7/stderr.golden @@ -0,0 +1,6 @@ +error[E2G22]: TypeError + --> ${CWD}/main.k:1:1 + | +1 | name: "aa\"ab|" | "abc" = "aa\"ab" + | ^ expected str(aa"ab|) | str(abc), got str(aa"ab) + | \ No newline at end of file diff --git a/test/grammar/types/var_type_annotation/type_fail_7/stderr.golden.py b/test/grammar/types/var_type_annotation/type_fail_7/stderr.golden.py deleted file mode 100644 index 30d594587..000000000 --- a/test/grammar/types/var_type_annotation/type_fail_7/stderr.golden.py +++ /dev/null @@ -1,23 +0,0 @@ - -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.TypeError_Compile_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=1, - col_no=1, - arg_msg='got str(aa"ab)' - ) - ], - arg_msg='expect str(aa"ab|)|str(abc), got str(aa"ab)' - ), - file=sys.stdout -) - diff --git a/test/grammar/types/var_type_annotation/type_fail_8/stderr.golden b/test/grammar/types/var_type_annotation/type_fail_8/stderr.golden new file mode 100644 index 000000000..7dd67ed81 --- /dev/null +++ b/test/grammar/types/var_type_annotation/type_fail_8/stderr.golden @@ -0,0 +1,6 @@ +error[E2G22]: TypeError + --> ${CWD}/main.k:1:1 + | +1 | name: ["aa\"ab|"] = ["aa\"ab"] + | ^ expected [str(aa"ab|)], got [str(aa"ab)] + | \ No newline at end of file diff --git a/test/grammar/types/var_type_annotation/type_fail_8/stderr.golden.py b/test/grammar/types/var_type_annotation/type_fail_8/stderr.golden.py deleted file mode 100644 index 9cb15209b..000000000 --- a/test/grammar/types/var_type_annotation/type_fail_8/stderr.golden.py +++ /dev/null @@ -1,23 +0,0 @@ - -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.TypeError_Compile_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=1, - col_no=1, - arg_msg='got [str(aa"ab)]' - ) - ], - arg_msg='expect [str(aa"ab|)], got [str(aa"ab)]' - ), - file=sys.stdout -) - diff --git a/test/grammar/types/var_type_annotation/type_fail_9/stderr.golden b/test/grammar/types/var_type_annotation/type_fail_9/stderr.golden new file mode 100644 index 000000000..2372faaad --- /dev/null +++ b/test/grammar/types/var_type_annotation/type_fail_9/stderr.golden @@ -0,0 +1,50 @@ +error[E2G22]: TypeError + --> ${CWD}/main.k:2:1 + | +2 | _a: {str:int} = {"key2": 1} + | ^ can not change the type of '_a' to {str:str} + | + --> ${CWD}/main.k:1:1 + | +1 | _a: {str:str} = {"key": "value"} + | ^ expected {str:str} + | +error[E2G22]: TypeError + --> ${CWD}/main.k:1:1 + | +1 | _a: {str:str} = {"key": "value"} + | ^ can not change the type of '_a' to {str:int} + | + --> ${CWD}/main.k:2:1 + | +2 | _a: {str:int} = {"key2": 1} + | ^ expected {str:int} + | +error[E2G22]: TypeError + --> ${CWD}/main.k:1:18 + | +1 | _a: {str:str} = {"key": "value"} + | ^ expected int, got str(value) + | + --> ${CWD}/main.k:1:1 + | +1 | _a: {str:str} = {"key": "value"} + | ^ variable is defined here, its type is int, but got str(value) + | +error[E2G22]: TypeError + --> ${CWD}/main.k:1:1 + | +1 | _a: {str:str} = {"key": "value"} + | ^ can not change the type of '_a' to {str:str} + | + --> ${CWD}/main.k:2:1 + | +2 | _a: {str:int} = {"key2": 1} + | ^ expected {str:int} + | +error[E2G22]: TypeError + --> ${CWD}/main.k:1:1 + | +1 | _a: {str:str} = {"key": "value"} + | ^ expected {str:int}, got {str(key):str(value)} + | \ No newline at end of file diff --git a/test/grammar/types/var_type_annotation/type_fail_9/stderr.golden.py b/test/grammar/types/var_type_annotation/type_fail_9/stderr.golden.py deleted file mode 100644 index e749a64ef..000000000 --- a/test/grammar/types/var_type_annotation/type_fail_9/stderr.golden.py +++ /dev/null @@ -1,28 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.TypeError_Compile_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=1, - col_no=1, - arg_msg='expect {str:str}', - err_level=kcl_error.ErrLevel.ORDINARY, - ), - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=2, - col_no=1, - arg_msg='got {str:int}', - ), - ], - arg_msg='can not change type of _a', - ), - file=sys.stdout, -) diff --git a/test/grammar/unification/append_0/main.k b/test/grammar/unification/append_0/main.k index cd6ee4e96..08b4adce3 100644 --- a/test/grammar/unification/append_0/main.k +++ b/test/grammar/unification/append_0/main.k @@ -4,13 +4,13 @@ schema Main: schema Config: main: Main -config = Config { +config: Config { main: Main { env: ["s1"] } } -config = Config { +config: Config { main: Main { env += ["s2"] } diff --git a/test/grammar/unification/append_1/main.k b/test/grammar/unification/append_1/main.k index 4be4b226d..8b23e8dc0 100644 --- a/test/grammar/unification/append_1/main.k +++ b/test/grammar/unification/append_1/main.k @@ -1,10 +1,10 @@ schema Main: env: [str] -main = Main { +main: Main { env: ["s1"] } -main = Main { +main: Main { env += ["s2"] } diff --git a/test/grammar/unification/collection_if_0/main.k b/test/grammar/unification/collection_if_0/main.k index a95e599c0..470bba069 100644 --- a/test/grammar/unification/collection_if_0/main.k +++ b/test/grammar/unification/collection_if_0/main.k @@ -2,12 +2,12 @@ schema Person: name: str age: int -alice = Person { +alice: Person { if True: name: "Alice" } -alice = Person { +alice: Person { if True: age = 18 } diff --git a/test/grammar/unification/collection_if_1/main.k b/test/grammar/unification/collection_if_1/main.k index c0f6980da..7add1ea4d 100644 --- a/test/grammar/unification/collection_if_1/main.k +++ b/test/grammar/unification/collection_if_1/main.k @@ -2,17 +2,17 @@ schema Person: name: str age: int -alice = Person { +alice: Person { if True: name: "Alice" } -alice = Person { +alice: Person { if True: age = 18 } -alice = Person { +alice: Person { age = 10 } diff --git a/test/grammar/unification/empty_0/main.k b/test/grammar/unification/empty_0/main.k index b09bc9bf6..d279fcfc2 100644 --- a/test/grammar/unification/empty_0/main.k +++ b/test/grammar/unification/empty_0/main.k @@ -2,8 +2,8 @@ schema Person: name?: str = None age?: int = None -alice = Person {} -alice = Person {} +alice: Person {} +alice: Person {} name = alice.name or "Alice" age = alice.age or 18 diff --git a/test/grammar/unification/empty_1/main.k b/test/grammar/unification/empty_1/main.k index e9c28d6df..c6e9540e1 100644 --- a/test/grammar/unification/empty_1/main.k +++ b/test/grammar/unification/empty_1/main.k @@ -2,9 +2,9 @@ schema Person: name?: str = None age?: int = None -alice = Person {} +alice: Person {} -alice = Person {} +alice: Person {} name = alice.name or "Alice" age = alice.age or 18 diff --git a/test/grammar/unification/fail_0/stderr.golden b/test/grammar/unification/fail_0/stderr.golden new file mode 100644 index 000000000..63f6c2bf2 --- /dev/null +++ b/test/grammar/unification/fail_0/stderr.golden @@ -0,0 +1,12 @@ +error[E1001]: ImmutableError + --> ${CWD}/main.k:9:1 + | +9 | alice.age = 18 + | ^ Can not change the value of 'alice', because it was declared immutable + | + --> ${CWD}/main.k:5:1 + | +5 | alice = Person { + | ^ The variable 'alice' is declared here + | +note: change the variable name to '_alice' to make it mutable \ No newline at end of file diff --git a/test/grammar/unification/fail_0/stderr.golden.py b/test/grammar/unification/fail_0/stderr.golden.py deleted file mode 100644 index 3d8d30018..000000000 --- a/test/grammar/unification/fail_0/stderr.golden.py +++ /dev/null @@ -1,22 +0,0 @@ -import sys -import os - -import kclvm.kcl.error as kcl_error - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.ImmutableCompileError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=9, - col_no=1, - end_col_no=10 - ) - ], - ), - file=sys.stdout -) - diff --git a/test/grammar/unification/fail_1/stderr.golden b/test/grammar/unification/fail_1/stderr.golden new file mode 100644 index 000000000..a7ea45460 --- /dev/null +++ b/test/grammar/unification/fail_1/stderr.golden @@ -0,0 +1,12 @@ +error[E1001]: ImmutableError + --> ${CWD}/main.k:10:1 + | +10 | config = Config { + | ^ Can not change the value of 'config', because it was declared immutable + | + --> ${CWD}/main.k:6:1 + | +6 | config = Config { + | ^ The variable 'config' is declared here + | +note: change the variable name to '_config' to make it mutable \ No newline at end of file diff --git a/test/grammar/unification/fail_1/stderr.golden.py b/test/grammar/unification/fail_1/stderr.golden.py deleted file mode 100644 index 8c6abaff1..000000000 --- a/test/grammar/unification/fail_1/stderr.golden.py +++ /dev/null @@ -1,18 +0,0 @@ -import sys -import os - -import kclvm.kcl.error as kcl_error - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception(err_type=kcl_error.ErrType.EvaluationError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=10 - ), - ], - arg_msg="attribute 'hc' of Config is required and can't be None or Undefined") - , file=sys.stdout -) diff --git a/test/grammar/unification/fail_2/stderr.golden b/test/grammar/unification/fail_2/stderr.golden new file mode 100644 index 000000000..fb020aa7c --- /dev/null +++ b/test/grammar/unification/fail_2/stderr.golden @@ -0,0 +1,11 @@ +error[E3M38]: EvaluationError + --> ${CWD}/main.k:11:1 + | +11 | _config.age = -1 + | ^ Instance check failed + | + --> ${CWD}/main.k:5:1 + | +5 | age > 0 if age + | Check failed on the condition + | \ No newline at end of file diff --git a/test/grammar/unification/fail_2/stderr.golden.py b/test/grammar/unification/fail_2/stderr.golden.py deleted file mode 100644 index 7d1d3e7d4..000000000 --- a/test/grammar/unification/fail_2/stderr.golden.py +++ /dev/null @@ -1,23 +0,0 @@ - -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception(err_type=kcl_error.ErrType.SchemaCheckFailure_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=5, - arg_msg=kcl_error.SCHEMA_CHECK_FILE_MSG_COND - ), - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=11, - arg_msg=kcl_error.SCHEMA_CHECK_FILE_MSG_ERR - ), - ]) - , file=sys.stdout -) diff --git a/test/grammar/unification/fail_3/stderr.golden b/test/grammar/unification/fail_3/stderr.golden new file mode 100644 index 000000000..ff38aa176 --- /dev/null +++ b/test/grammar/unification/fail_3/stderr.golden @@ -0,0 +1,11 @@ +error[E3M38]: EvaluationError + --> ${CWD}/main.k:11:1 + | +11 | _config |= {age = -1} + | ^ Instance check failed + | + --> ${CWD}/main.k:5:1 + | +5 | age > 0 if age + | Check failed on the condition + | \ No newline at end of file diff --git a/test/grammar/unification/fail_3/stderr.golden.py b/test/grammar/unification/fail_3/stderr.golden.py deleted file mode 100644 index 7d1d3e7d4..000000000 --- a/test/grammar/unification/fail_3/stderr.golden.py +++ /dev/null @@ -1,23 +0,0 @@ - -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception(err_type=kcl_error.ErrType.SchemaCheckFailure_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=5, - arg_msg=kcl_error.SCHEMA_CHECK_FILE_MSG_COND - ), - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=11, - arg_msg=kcl_error.SCHEMA_CHECK_FILE_MSG_ERR - ), - ]) - , file=sys.stdout -) diff --git a/test/grammar/unification/multi_file_compile_0/main.k b/test/grammar/unification/multi_file_compile_0/main.k index 2974347a6..d917345da 100644 --- a/test/grammar/unification/multi_file_compile_0/main.k +++ b/test/grammar/unification/multi_file_compile_0/main.k @@ -3,7 +3,7 @@ schema Config: args: [str] labels: {str:} -config = Config { +config: Config { name: "config1" args: ["kcl", "main.k"] labels.key1: "value1" diff --git a/test/grammar/unification/multi_file_compile_0/stack.k b/test/grammar/unification/multi_file_compile_0/stack.k index c5bc5dd1d..bbd76df47 100644 --- a/test/grammar/unification/multi_file_compile_0/stack.k +++ b/test/grammar/unification/multi_file_compile_0/stack.k @@ -1,3 +1,3 @@ -config = Config { +config: Config { name = "config2" } diff --git a/test/grammar/unification/multi_file_compile_1/main.k b/test/grammar/unification/multi_file_compile_1/main.k index 2974347a6..d917345da 100644 --- a/test/grammar/unification/multi_file_compile_1/main.k +++ b/test/grammar/unification/multi_file_compile_1/main.k @@ -3,7 +3,7 @@ schema Config: args: [str] labels: {str:} -config = Config { +config: Config { name: "config1" args: ["kcl", "main.k"] labels.key1: "value1" diff --git a/test/grammar/unification/multi_file_compile_1/stack.k b/test/grammar/unification/multi_file_compile_1/stack.k index d59c1c7c5..45dbcba0e 100644 --- a/test/grammar/unification/multi_file_compile_1/stack.k +++ b/test/grammar/unification/multi_file_compile_1/stack.k @@ -1,4 +1,4 @@ _NAME = "config2" -config = Config { +config: Config { name = _NAME } diff --git a/test/grammar/unification/nest_var_0/main.k b/test/grammar/unification/nest_var_0/main.k index 7b945cc6e..717e291a6 100644 --- a/test/grammar/unification/nest_var_0/main.k +++ b/test/grammar/unification/nest_var_0/main.k @@ -2,18 +2,18 @@ schema Config: args: [str] labels: {str:} -config = Config { +config: Config { args: ["kcl", "main.k"] labels.key1: "value1" } -config = Config { +config: Config { labels: { key2: "value2" } } -config = Config { +config: Config { "labels": { "key3": "value3" } diff --git a/test/grammar/unification/nest_var_1/main.k b/test/grammar/unification/nest_var_1/main.k index acbcbbec5..cfc72eff2 100644 --- a/test/grammar/unification/nest_var_1/main.k +++ b/test/grammar/unification/nest_var_1/main.k @@ -10,13 +10,13 @@ schema Config: labels: {str:} name: Name -config = Config { +config: Config { args: ["kcl", "main.k"] labels.key1: "value1" name.name.name: "name" } -config = Config { +config: Config { labels: { key2: "value2" } diff --git a/test/grammar/unification/override_0/main.k b/test/grammar/unification/override_0/main.k index 4a6c96944..e40e5665d 100644 --- a/test/grammar/unification/override_0/main.k +++ b/test/grammar/unification/override_0/main.k @@ -3,12 +3,12 @@ schema Person: age: int hc: [int] -alice = Person { +alice: Person { name: "Alice" hc: [1, 2] } -alice = Person { +alice: Person { age: 18 hc = [2] } diff --git a/test/grammar/unification/override_1/main.k b/test/grammar/unification/override_1/main.k index c530ef80b..3b7f03939 100644 --- a/test/grammar/unification/override_1/main.k +++ b/test/grammar/unification/override_1/main.k @@ -3,7 +3,7 @@ schema Person: age: int env: [{str:}] -alice = Person { +alice: Person { name: "Alice" env: [{ name: "key1" @@ -14,7 +14,7 @@ alice = Person { }] } -alice = Person { +alice: Person { age: 18 env = [{ name: "key2" diff --git a/test/grammar/unification/pkg_schema_0/kcl.mod b/test/grammar/unification/pkg_schema_0/kcl.mod new file mode 100644 index 000000000..e69de29bb diff --git a/test/grammar/unification/pkg_schema_0/main.k b/test/grammar/unification/pkg_schema_0/main.k new file mode 100644 index 000000000..744f618d7 --- /dev/null +++ b/test/grammar/unification/pkg_schema_0/main.k @@ -0,0 +1,6 @@ +import pkg + +schema App: + server: pkg.Server {} + +app = App {} diff --git a/test/grammar/unification/pkg_schema_0/pkg/pkg.k b/test/grammar/unification/pkg_schema_0/pkg/pkg.k new file mode 100644 index 000000000..ab106878a --- /dev/null +++ b/test/grammar/unification/pkg_schema_0/pkg/pkg.k @@ -0,0 +1,2 @@ +schema Server: + name?: str diff --git a/test/grammar/unification/pkg_schema_0/stdout.golden b/test/grammar/unification/pkg_schema_0/stdout.golden new file mode 100644 index 000000000..2d1caa717 --- /dev/null +++ b/test/grammar/unification/pkg_schema_0/stdout.golden @@ -0,0 +1,2 @@ +app: + server: {} diff --git a/test/grammar/unification/pkg_schema_1/kcl.mod b/test/grammar/unification/pkg_schema_1/kcl.mod new file mode 100644 index 000000000..e69de29bb diff --git a/test/grammar/unification/pkg_schema_1/main.k b/test/grammar/unification/pkg_schema_1/main.k new file mode 100644 index 000000000..66419894e --- /dev/null +++ b/test/grammar/unification/pkg_schema_1/main.k @@ -0,0 +1,3 @@ +import pkg + +app = pkg.App {} diff --git a/test/grammar/unification/pkg_schema_1/pkg/pkg.k b/test/grammar/unification/pkg_schema_1/pkg/pkg.k new file mode 100644 index 000000000..dee42382f --- /dev/null +++ b/test/grammar/unification/pkg_schema_1/pkg/pkg.k @@ -0,0 +1,4 @@ +import pkg.pkg as a + +schema App: + server: a.Server {} diff --git a/test/grammar/unification/pkg_schema_1/pkg/pkg/pkg.k b/test/grammar/unification/pkg_schema_1/pkg/pkg/pkg.k new file mode 100644 index 000000000..ab106878a --- /dev/null +++ b/test/grammar/unification/pkg_schema_1/pkg/pkg/pkg.k @@ -0,0 +1,2 @@ +schema Server: + name?: str diff --git a/test/grammar/unification/pkg_schema_1/stdout.golden b/test/grammar/unification/pkg_schema_1/stdout.golden new file mode 100644 index 000000000..2d1caa717 --- /dev/null +++ b/test/grammar/unification/pkg_schema_1/stdout.golden @@ -0,0 +1,2 @@ +app: + server: {} diff --git a/test/grammar/unification/schema_simple_0/main.k b/test/grammar/unification/schema_simple_0/main.k index a2024fd99..859391bdf 100644 --- a/test/grammar/unification/schema_simple_0/main.k +++ b/test/grammar/unification/schema_simple_0/main.k @@ -2,10 +2,10 @@ schema Person: name: str age: int -alice = Person { +alice: Person { name: "Alice" } -alice = Person { +alice: Person { age: 18 } diff --git a/test/grammar/unification/schema_simple_1/main.k b/test/grammar/unification/schema_simple_1/main.k index d0e0b97d6..3a16b2854 100644 --- a/test/grammar/unification/schema_simple_1/main.k +++ b/test/grammar/unification/schema_simple_1/main.k @@ -3,15 +3,15 @@ schema Config: age?: int hc: [int] -config = Config { +config: Config { name: "Alice" } -config = Config { +config: Config { age: 18 } -config = Config { +config: Config { hc: [1] } diff --git a/test/grammar/unification/schema_simple_10/main.k b/test/grammar/unification/schema_simple_10/main.k new file mode 100644 index 000000000..f32867461 --- /dev/null +++ b/test/grammar/unification/schema_simple_10/main.k @@ -0,0 +1,22 @@ +schema Resource: + cpu: int + memory: str + +schema Config: + resource: Resource + +r = Resource { + cpu = 4 + memory = "8Gi" +} + +config: Config { + resource: {**r} +} + +config: Config { + resource: Resource { + cpu = 2 + memory = "4Gi" + } +} diff --git a/test/grammar/unification/schema_simple_10/stdout.golden b/test/grammar/unification/schema_simple_10/stdout.golden new file mode 100644 index 000000000..8382946b2 --- /dev/null +++ b/test/grammar/unification/schema_simple_10/stdout.golden @@ -0,0 +1,7 @@ +r: + cpu: 4 + memory: 8Gi +config: + resource: + cpu: 2 + memory: 4Gi diff --git a/test/grammar/unification/schema_simple_11/main.k b/test/grammar/unification/schema_simple_11/main.k new file mode 100644 index 000000000..11336ffa4 --- /dev/null +++ b/test/grammar/unification/schema_simple_11/main.k @@ -0,0 +1,25 @@ +schema Resource: + cpu: int + memory: str + +schema Config: + resource: Resource + +r = Resource { + cpu = 4 + memory = "8Gi" +} + +config: Config { + resource: Resource { + cpu = 2 + memory = "4Gi" + } +} + +config: Config { + resource: r | { + cpu = 8 + memory = "16Gi" + } +} diff --git a/test/grammar/unification/schema_simple_11/stdout.golden b/test/grammar/unification/schema_simple_11/stdout.golden new file mode 100644 index 000000000..473fadc36 --- /dev/null +++ b/test/grammar/unification/schema_simple_11/stdout.golden @@ -0,0 +1,7 @@ +r: + cpu: 4 + memory: 8Gi +config: + resource: + cpu: 8 + memory: 16Gi diff --git a/test/grammar/unification/schema_simple_2/main.k b/test/grammar/unification/schema_simple_2/main.k index bfed69eb2..9d5b10cea 100644 --- a/test/grammar/unification/schema_simple_2/main.k +++ b/test/grammar/unification/schema_simple_2/main.k @@ -3,14 +3,14 @@ schema Config: age?: int hc: [int] -config = Config { +config: Config { name: "Alice" } age = 18 -config = Config { +config: Config { age: age } -config = Config { +config: Config { hc: [1] } diff --git a/test/grammar/unification/schema_simple_3/main.k b/test/grammar/unification/schema_simple_3/main.k index 249adf7b6..b040c34dd 100644 --- a/test/grammar/unification/schema_simple_3/main.k +++ b/test/grammar/unification/schema_simple_3/main.k @@ -13,12 +13,12 @@ _main = Main { args: ["1"] } -config = Config { +config: Config { name: "Alice" main: _main } -config = Config { +config: Config { age: 18 main: Main { env = ["789", "456"] diff --git a/test/grammar/unification/schema_simple_9/main.k b/test/grammar/unification/schema_simple_9/main.k new file mode 100644 index 000000000..7aa708f79 --- /dev/null +++ b/test/grammar/unification/schema_simple_9/main.k @@ -0,0 +1,22 @@ +schema Resource: + cpu: int + memory: str + +schema Config: + resource: Resource + +r = Resource { + cpu = 4 + memory = "8Gi" +} + +config: Config { + resource: Resource { + cpu = 2 + memory = "4Gi" + } +} + +config: Config { + resource: r +} diff --git a/test/grammar/unification/schema_simple_9/stdout.golden b/test/grammar/unification/schema_simple_9/stdout.golden new file mode 100644 index 000000000..98d258ab2 --- /dev/null +++ b/test/grammar/unification/schema_simple_9/stdout.golden @@ -0,0 +1,7 @@ +r: + cpu: 4 + memory: 8Gi +config: + resource: + cpu: 4 + memory: 8Gi diff --git a/test/grammar/unification/schema_with_args_0/main.k b/test/grammar/unification/schema_with_args_0/main.k new file mode 100644 index 000000000..cd79f6da7 --- /dev/null +++ b/test/grammar/unification/schema_with_args_0/main.k @@ -0,0 +1,5 @@ +schema Server[r: int]: + replica: int = r + +server: Server(1) {} +server: Server(2) {} diff --git a/test/grammar/unification/schema_with_args_0/stdout.golden b/test/grammar/unification/schema_with_args_0/stdout.golden new file mode 100644 index 000000000..1867e86c2 --- /dev/null +++ b/test/grammar/unification/schema_with_args_0/stdout.golden @@ -0,0 +1,2 @@ +server: + replica: 2 diff --git a/test/grammar/unification/str_interpolation/main.k b/test/grammar/unification/str_interpolation/main.k index a1ce3777a..b6b35084b 100644 --- a/test/grammar/unification/str_interpolation/main.k +++ b/test/grammar/unification/str_interpolation/main.k @@ -3,8 +3,8 @@ schema Person: age: int key = "age" -_alice = Person { +_alice: Person { name: "Alice" } -_alice = Person {"${key}": 18} +_alice: Person {"${key}": 18} alice = _alice diff --git a/test/grammar/unification/subscript_0/main.k b/test/grammar/unification/subscript_0/main.k index f0758f7e4..c98caabaa 100644 --- a/test/grammar/unification/subscript_0/main.k +++ b/test/grammar/unification/subscript_0/main.k @@ -2,11 +2,11 @@ schema Person: name: str age: int -alice = Person { +alice: Person { name: "Alice" } -alice = Person { +alice: Person { age: 18 } diff --git a/test/grammar/unification/subscript_1/main.k b/test/grammar/unification/subscript_1/main.k index f16cab36a..0be3da37d 100644 --- a/test/grammar/unification/subscript_1/main.k +++ b/test/grammar/unification/subscript_1/main.k @@ -2,12 +2,12 @@ schema Person: name: str age: int -alice = Person { +alice: Person { name: "Alice" age: 18 } -alice = Person {} +alice: Person {} name = alice.name age = alice.age diff --git a/test/grammar/unification/unpack_0/main.k b/test/grammar/unification/unpack_0/main.k index 8a6b73661..427df8559 100644 --- a/test/grammar/unification/unpack_0/main.k +++ b/test/grammar/unification/unpack_0/main.k @@ -7,11 +7,11 @@ _base = { age = 18 } -alice = Person { +alice: Person { **_base } -alice = Person { +alice: Person { name = "Alice" age = 18 } diff --git a/test/grammar/unification/unpack_1/main.k b/test/grammar/unification/unpack_1/main.k index 672db3a1d..97de95184 100644 --- a/test/grammar/unification/unpack_1/main.k +++ b/test/grammar/unification/unpack_1/main.k @@ -7,11 +7,11 @@ _base = { age = 10 } -alice = Person { +alice: Person { age: 18 } -alice = Person { +alice: Person { **_base } diff --git a/test/grammar/variable/export/default/main.k b/test/grammar/variable/export/default/main.k index ecb418c3c..d64702166 100644 --- a/test/grammar/variable/export/default/main.k +++ b/test/grammar/variable/export/default/main.k @@ -1,3 +1,3 @@ _a = 1 -_a << 1 +_a <<= 1 b = 2 \ No newline at end of file diff --git a/test/grammar/variable/export/immutable_0/stderr.golden b/test/grammar/variable/export/immutable_0/stderr.golden new file mode 100644 index 000000000..0f1342fbf --- /dev/null +++ b/test/grammar/variable/export/immutable_0/stderr.golden @@ -0,0 +1,12 @@ +error[E1001]: ImmutableError + --> ${CWD}/main.k:2:1 + | +2 | a = 2 + | ^ Can not change the value of 'a', because it was declared immutable + | + --> ${CWD}/main.k:1:1 + | +1 | a = 1 + | ^ The variable 'a' is declared here + | +note: change the variable name to '_a' to make it mutable \ No newline at end of file diff --git a/test/grammar/variable/export/immutable_0/stderr.golden.py b/test/grammar/variable/export/immutable_0/stderr.golden.py deleted file mode 100644 index 7b85a3b1d..000000000 --- a/test/grammar/variable/export/immutable_0/stderr.golden.py +++ /dev/null @@ -1,19 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.ImmutableCompileError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=2, - col_no=1 - ) - ], - ), - file=sys.stdout -) diff --git a/test/grammar/variable/export/immutable_1/stderr.golden b/test/grammar/variable/export/immutable_1/stderr.golden new file mode 100644 index 000000000..5927edeef --- /dev/null +++ b/test/grammar/variable/export/immutable_1/stderr.golden @@ -0,0 +1,12 @@ +error[E1001]: ImmutableError + --> ${CWD}/main.k:2:1 + | +2 | a = b = 2 + | ^ Can not change the value of 'a', because it was declared immutable + | + --> ${CWD}/main.k:1:1 + | +1 | a = 1 + | ^ The variable 'a' is declared here + | +note: change the variable name to '_a' to make it mutable \ No newline at end of file diff --git a/test/grammar/variable/export/immutable_1/stderr.golden.py b/test/grammar/variable/export/immutable_1/stderr.golden.py deleted file mode 100644 index c8b15b5a3..000000000 --- a/test/grammar/variable/export/immutable_1/stderr.golden.py +++ /dev/null @@ -1,20 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.ImmutableCompileError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=2, - col_no=1 - ) - ], - ), - file=sys.stdout -) - diff --git a/test/grammar/variable/export/immutable_2/stderr.golden b/test/grammar/variable/export/immutable_2/stderr.golden new file mode 100644 index 000000000..84bf87e87 --- /dev/null +++ b/test/grammar/variable/export/immutable_2/stderr.golden @@ -0,0 +1,12 @@ +error[E1001]: ImmutableError + --> ${CWD}/main.k:2:5 + | +2 | b = a = 2 + | ^ Can not change the value of 'a', because it was declared immutable + | + --> ${CWD}/main.k:1:1 + | +1 | a = 1 + | ^ The variable 'a' is declared here + | +note: change the variable name to '_a' to make it mutable \ No newline at end of file diff --git a/test/grammar/variable/export/immutable_2/stderr.golden.py b/test/grammar/variable/export/immutable_2/stderr.golden.py deleted file mode 100644 index 665417538..000000000 --- a/test/grammar/variable/export/immutable_2/stderr.golden.py +++ /dev/null @@ -1,20 +0,0 @@ -import sys -import kclvm.kcl.error as kcl_error -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) - -kcl_error.print_kcl_error_message( - kcl_error.get_exception( - err_type=kcl_error.ErrType.ImmutableCompileError_TYPE, - file_msgs=[ - kcl_error.ErrFileMsg( - filename=cwd + "/main.k", - line_no=2, - col_no=5 - ) - ], - ), - file=sys.stdout -) - diff --git a/test/integration/konfig b/test/integration/konfig new file mode 160000 index 000000000..9f8ec32b7 --- /dev/null +++ b/test/integration/konfig @@ -0,0 +1 @@ +Subproject commit 9f8ec32b7785b00da4979f95072eceda4b7afdab diff --git a/test/integration/test_konfig.bat b/test/integration/test_konfig.bat new file mode 100644 index 000000000..7dc24bc9d --- /dev/null +++ b/test/integration/test_konfig.bat @@ -0,0 +1,5 @@ +cd %~dp0 + +python3 -m pip install --upgrade pip +python3 -m pip install kclvm pytest pytest-xdist +python3 -m pytest -vv -n 10 diff --git a/test/integration/test_konfig_kcl.py b/test/integration/test_konfig_kcl.py new file mode 100644 index 000000000..ed99a55a3 --- /dev/null +++ b/test/integration/test_konfig_kcl.py @@ -0,0 +1,123 @@ +""" +this testing framework is developed based on pytest. +see quick start of pytest: https://docs.pytest.org/en/latest/example/simple.html + +""" +import os +import subprocess +from pathlib import Path + +import pytest +from ruamel.yaml import YAML +from collections.abc import Mapping, Sequence + +TEST_FILE = "kcl.yaml" +CI_TEST_DIR = "ci-test" +STDOUT_GOLDEN = "stdout.golden.yaml" +SETTINGS_FILE = "settings.yaml" + +ROOT_STR = "konfig" +ROOT = str(Path(__file__).parent.joinpath(ROOT_STR)) + +yaml = YAML(typ="unsafe", pure=True) + + +def find_test_dirs(): + result = [] + root_dirs = [ROOT] + for root_dir in root_dirs: + for root, _, files in os.walk(root_dir): + for name in files: + if name == TEST_FILE: + result.append(root) + return result + + +def compare_results(result, golden_result): + """Convert result and golden_result string to string lines with line ending stripped, then compare.""" + result = [ + r + for r in list(yaml.load_all(result)) + if r and r.get("kind") != "SecretProviderClass" + ] + # Convert kusion compile spec to kcl result + expected = [ + r + for r in list(yaml.load_all(golden_result))[0] + if r["attributes"] + # Remove CRDs + and not r["id"].startswith("apiextensions.k8s.io/v1:CustomResourceDefinition") + ] + print(len(result), len(expected)) + assert compare_unordered_yaml_objects(result, expected) + + +def compare_unordered_yaml_objects(result, golden_result): + """Comparing the contents of two YAML objects for equality in an unordered manner""" + if isinstance(result, Mapping) and isinstance(golden_result, Mapping): + if result.keys() != golden_result.keys(): + return False + for key in result.keys(): + if not compare_unordered_yaml_objects(result[key], golden_result[key]): + return False + + return True + elif isinstance(result, Sequence) and isinstance(golden_result, Sequence): + if len(result) != len(golden_result): + return False + for item in result: + if item not in golden_result: + return False + for item in golden_result: + if item not in result: + return False + return True + else: + return result == golden_result + + +def has_settings_file(directory): + settings_file = directory / SETTINGS_FILE + return settings_file.is_file() + + +print("##### K Language Grammar Test Suite #####") +test_dirs = find_test_dirs() +pwd = str(Path(__file__).parent.parent.parent) +os.environ["PYTHONPATH"] = pwd + + +@pytest.mark.parametrize("test_dir", test_dirs) +def test_konfigs(test_dir): + print(f"Testing {test_dir}") + test_dir = Path(test_dir) + kcl_file_name = test_dir / TEST_FILE + ci_test_dir = test_dir / CI_TEST_DIR + if not ci_test_dir.is_dir(): + # Skip invalid test cases + return + golden_file = ci_test_dir / STDOUT_GOLDEN + if not golden_file.is_file(): + # Skip invalid test cases + return + kcl_command = ["kcl"] + if has_settings_file(ci_test_dir): + kcl_command.append("-Y") + kcl_command.append(f"{CI_TEST_DIR}/{SETTINGS_FILE}") + kcl_command.append(f"kcl.yaml") + else: + kcl_command.append(f"{TEST_FILE}") + process = subprocess.run( + kcl_command, capture_output=True, cwd=test_dir, env=dict(os.environ) + ) + stdout, stderr = process.stdout, process.stderr + print(f"STDOUT:\n{stdout.decode()}") + assert ( + process.returncode == 0 and len(stderr) == 0 + ), f"Error executing file {kcl_file_name}.\nexit code = {process.returncode}\nstderr = {stderr}" + if process.returncode == 0 and len(stderr) == 0: + try: + with open(golden_file, "r") as golden: + compare_results(stdout.decode(), golden) + except FileNotFoundError: + raise Exception(f"Error reading expected result from file {golden_file}") diff --git a/test/test_units/test_kclvm/__init__.py b/test/test_units/test_kclvm/__init__.py deleted file mode 100644 index 378661dd8..000000000 --- a/test/test_units/test_kclvm/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/env python -# -*- coding: UTF-8 -*- - diff --git a/test/test_units/test_kclvm/_test_plugin/test_data/VERSION b/test/test_units/test_kclvm/_test_plugin/test_data/VERSION deleted file mode 100644 index da9921cdc..000000000 --- a/test/test_units/test_kclvm/_test_plugin/test_data/VERSION +++ /dev/null @@ -1 +0,0 @@ -test_plugin_version \ No newline at end of file diff --git a/test/test_units/test_kclvm/_test_plugin/test_plugin.py b/test/test_units/test_kclvm/_test_plugin/test_plugin.py deleted file mode 100644 index 13bb5cdf7..000000000 --- a/test/test_units/test_kclvm/_test_plugin/test_plugin.py +++ /dev/null @@ -1,54 +0,0 @@ -# Copyright 2020 The KCL Authors. All rights reserved. - -import kclvm.compiler.extension.plugin as plugin - -hello_plugin = plugin.get_plugin("kcl_plugin.hello") - - -def test_reset_plugin(): - plugin.reset_plugin(plugin.get_plugin_root()) - - -def test_plugin(): - assert "hello" in plugin.get_plugin_names() - - -def test_plugin_info(): - info = plugin.get_info("hello") - assert info["name"] == "hello" - - -def test_plugin_hello_add(): - assert hello_plugin.add(1, 2) == 3 - - -def test_plugin_hello_tolower(): - assert hello_plugin.tolower("KCL") == "kcl" - - -def test_plugin_hello_update_dict(): - assert hello_plugin.update_dict({"name": 123}, "name", "kcl")["name"] == "kcl" - - -def test_plugin_hello_list_append(): - data = hello_plugin.list_append(["abc"], "name", 123) - assert len(data) == 3 - assert data[0] == "abc" - assert data[1] == "name" - assert data[2] == 123 - - -def test_plugin_hello_foo(): - v = hello_plugin.foo("aaa", "bbb", x=123, y=234, abcd=1234) - assert len(v) == 5 - assert v["a"] == "aaa" - assert v["b"] == "bbb" - assert v["x"] == 123 - assert v["y"] == 234 - assert v["abcd"] == 1234 - - v = hello_plugin.foo("aaa", "bbb", x=123) - assert len(v) == 3 - assert v["a"] == "aaa" - assert v["b"] == "bbb" - assert v["x"] == 123 diff --git a/test/test_units/test_kclvm/_test_plugin/test_plugin_root.py b/test/test_units/test_kclvm/_test_plugin/test_plugin_root.py deleted file mode 100644 index 7a9d099bf..000000000 --- a/test/test_units/test_kclvm/_test_plugin/test_plugin_root.py +++ /dev/null @@ -1,55 +0,0 @@ -# Copyright 2020 The KCL Authors. All rights reserved. - -import os -import pathlib -import sys - -import kclvm.compiler.extension.plugin.plugin as plugin - - -def test_find_plugin_root(): - os.environ["KCL_PLUGINS_ROOT"] = "" - - root1 = plugin.find_plugin_root() - sys.stdout.write(f"root1:{root1}\n") - if root1 is None: - return - - - root1_hello_plugin_py = "" - if os.path.exists(f"{root1}/hello/plugin.py"): - root1_hello_plugin_py = f"{root1}/hello/plugin.py" - os.rename(root1_hello_plugin_py, root1_hello_plugin_py+"_test_tmp") - - root2 = plugin.find_plugin_root() - sys.stdout.write(f"root2:{root2}\n") - if root2 is None: - if root1_hello_plugin_py: - os.rename(root1_hello_plugin_py+"_test_tmp", root1_hello_plugin_py) - return - - root2_hello_plugin_py = "" - if os.path.exists(f"{root2}/hello/plugin.py"): - root2_hello_plugin_py = f"{root2}/hello/plugin.py" - os.rename(root2_hello_plugin_py, root2_hello_plugin_py+"_test_tmp") - - plugin.find_plugin_root() # skip $HOME/.kusion/kclvm/plugins - root3 = plugin.find_plugin_root() - assert root3 is None - - if root1_hello_plugin_py: - os.rename(root1_hello_plugin_py+"_test_tmp", root1_hello_plugin_py) - if root2_hello_plugin_py: - os.rename(root2_hello_plugin_py+"_test_tmp", root2_hello_plugin_py) - - root4 = plugin.find_plugin_root() - assert root4 == root1 - - -def test_plugin_version(): - plugin.init_.plugins_root = None - assert plugin.get_plugin_version() == plugin.UNKNOWN_VERSION - plugin.init_.plugins_root = str(pathlib.Path(__file__).parent) - assert plugin.get_plugin_version() == plugin.UNKNOWN_VERSION - plugin.init_.plugins_root = str(pathlib.Path(__file__).parent.joinpath("test_data")) - assert plugin.get_plugin_version() == "test_plugin_version" diff --git a/test/test_units/test_kclvm/_test_plugin/test_template.py b/test/test_units/test_kclvm/_test_plugin/test_template.py deleted file mode 100644 index 733f8afcc..000000000 --- a/test/test_units/test_kclvm/_test_plugin/test_template.py +++ /dev/null @@ -1,11 +0,0 @@ -# Copyright 2020 The KCL Authors. All rights reserved. - -import kclvm.compiler.extension.plugin.template as template - - -hello_plugin_name = "kcl_plugin.hello" - - -def test_reset_plugin(): - template.get_plugin_template_code(hello_plugin_name) - template.get_plugin_test_template_code(hello_plugin_name) diff --git a/test/test_units/test_kclvm/test_api/test_internal/test_common_functions.py b/test/test_units/test_kclvm/test_api/test_internal/test_common_functions.py deleted file mode 100644 index d3dda347b..000000000 --- a/test/test_units/test_kclvm/test_api/test_internal/test_common_functions.py +++ /dev/null @@ -1,232 +0,0 @@ -# Copyright 2020 The KCL Authors. All rights reserved. - -import unittest - -import kclvm.api.object.internal.common as common - - -class TestCommonInternal(unittest.TestCase): - def test_is_builtin_type(self): - cases = [ - # True cases - {"type": "int", "expected": True}, - {"type": "float", "expected": True}, - {"type": "str", "expected": True}, - {"type": "bool", "expected": True}, - # False cases - {"type": "", "expected": False}, - {"type": "int8", "expected": False}, - {"type": "string", "expected": False}, - {"type": "{:}", "expected": False}, - {"type": "[]", "expected": False}, - {"type": "pkg.Schema", "expected": False}, - ] - for case in cases: - tpe_str, expected = case["type"], case["expected"] - value = common.is_builtin_type(tpe_str) - self.assertEqual(value, expected) - - def test_is_dict_type(self): - cases = [ - # True cases - {"type": "{}", "expected": True}, - {"type": "{:}", "expected": True}, - {"type": "{str:}", "expected": True}, - {"type": "{str:str}", "expected": True}, - {"type": "{str: str}", "expected": True}, - {"type": "{str:int}", "expected": True}, - {"type": "{str: int}", "expected": True}, - {"type": "{str:{str:}}", "expected": True}, - {"type": "{str:{str:str}}", "expected": True}, - {"type": "{str:str|int}", "expected": True}, - {"type": "{str:pkg.Schema}", "expected": True}, - # False cases - {"type": "int", "expected": False}, - {"type": "float", "expected": False}, - {"type": "str", "expected": False}, - {"type": "bool", "expected": False}, - {"type": "", "expected": False}, - {"type": "int8", "expected": False}, - {"type": "string", "expected": False}, - {"type": "{", "expected": False}, - {"type": "}", "expected": False}, - ] - for case in cases: - tpe_str, expected = case["type"], case["expected"] - value = common.isdicttype(tpe_str) - self.assertEqual(value, expected) - - def test_is_list_type(self): - cases = [ - # True cases - {"type": "[]", "expected": True}, - {"type": "[int]", "expected": True}, - {"type": "[str]", "expected": True}, - {"type": "[[str]]", "expected": True}, - {"type": "[str|int]", "expected": True}, - {"type": "[pkg.Schema]", "expected": True}, - # False cases - {"type": "int", "expected": False}, - {"type": "float", "expected": False}, - {"type": "str", "expected": False}, - {"type": "bool", "expected": False}, - {"type": "", "expected": False}, - {"type": "int8", "expected": False}, - {"type": "string", "expected": False}, - {"type": "[", "expected": False}, - {"type": "]", "expected": False}, - ] - for case in cases: - tpe_str, expected = case["type"], case["expected"] - value = common.islisttype(tpe_str) - self.assertEqual(value, expected) - - def test_separate_kv(self): - cases = [ - {"type": "{}", "expected": ("", "")}, - {"type": "{:}", "expected": ("", "")}, - {"type": "{str:}", "expected": ("str", "")}, - {"type": "{str:str}", "expected": ("str", "str")}, - {"type": "{str:int}", "expected": ("str", "int")}, - {"type": "{str:{str:}}", "expected": ("str", "{str:}")}, - {"type": "{str:{str:str}}", "expected": ("str", "{str:str}")}, - {"type": "{str:str|int}", "expected": ("str", "str|int")}, - {"type": "{str:pkg.Schema}", "expected": ("str", "pkg.Schema")}, - ] - for case in cases: - tpe_str, expected = case["type"], case["expected"] - value = common.separate_kv(common.dereferencetype(tpe_str)) - self.assertEqual(value, expected, msg=case["type"]) - - def test_union_native(self): - cases = [ - # Left None - {"value1": None, "value2": 1, "expected": 1}, - {"value1": None, "value2": 1.1, "expected": 1.1}, - {"value1": None, "value2": [], "expected": []}, - {"value1": None, "value2": {}, "expected": {}}, - {"value1": None, "value2": "s", "expected": "s"}, - {"value1": None, "value2": True, "expected": True}, - {"value1": None, "value2": False, "expected": False}, - {"value1": None, "value2": None, "expected": None}, - # Right None - {"value1": 1, "value2": None, "expected": 1}, - {"value1": 1.1, "value2": None, "expected": 1.1}, - {"value1": [], "value2": None, "expected": []}, - {"value1": {}, "value2": None, "expected": {}}, - {"value1": "s", "value2": None, "expected": "s"}, - {"value1": True, "value2": None, "expected": True}, - {"value1": False, "value2": None, "expected": False}, - {"value1": None, "value2": None, "expected": None}, - # Int - {"value1": 1, "value2": 1, "expected": 1}, - {"value1": 1, "value2": 2, "expected": 2}, - {"value1": 1, "value2": 3, "expected": 3}, - # Float - {"value1": 1.0, "value2": 1.0, "expected": 1.0}, - {"value1": 1.0, "value2": 1.5, "expected": 1.5}, - # String - {"value1": "s", "value2": "", "expected": ""}, - {"value1": "s", "value2": "s", "expected": "s"}, - {"value1": "s", "value2": "ss", "expected": "ss"}, - # Boolean True - {"value1": True, "value2": True, "expected": True}, - {"value1": True, "value2": False, "expected": False}, - # Boolean False - {"value1": False, "value2": False, "expected": False}, - {"value1": False, "value2": True, "expected": True}, - # List - {"value1": [], "value2": [], "expected": []}, - {"value1": [], "value2": [1], "expected": [1]}, - {"value1": [], "value2": [1, 2], "expected": [1, 2]}, - {"value1": [1], "value2": [1], "expected": [1]}, - {"value1": [1], "value2": [2], "expected": [2]}, - {"value1": [1], "value2": [2, 2], "expected": [2, 2]}, - {"value1": [1, 2], "value2": [3, 4], "expected": [3, 4]}, - {"value1": [1, 2, 3], "value2": [3, 4], "expected": [3, 4, 3]}, - { - "value1": [{"key1": "value1"}], - "value2": [{"key1": "value1"}], - "expected": [{"key1": "value1"}], - }, - { - "value1": [{"key1": "value1"}], - "value2": [{"key1": "value2"}], - "expected": [{"key1": "value2"}], - }, - { - "value1": [{"key1": "value1"}], - "value2": [{"key2": "value2"}], - "expected": [{"key1": "value1", "key2": "value2"}], - }, - { - "value1": [{"key1": "value1"}], - "value2": [{"key1": "value1", "key2": "value2"}], - "expected": [{"key1": "value1", "key2": "value2"}], - }, - { - "value1": [{"key1": "value1"}], - "value2": [{"key2": "value2", "key1": "value1"}], - "expected": [{"key1": "value1", "key2": "value2"}], - }, - { - "value1": [{"key1": "value1", "key2": "value2"}], - "value2": [{"key1": "value1"}], - "expected": [{"key1": "value1", "key2": "value2"}], - }, - # Dict - {"value1": {}, "value2": {}, "expected": {}}, - { - "value1": {}, - "value2": {"key1": "value1"}, - "expected": {"key1": "value1"}, - }, - { - "value1": {"key1": "value1"}, - "value2": {}, - "expected": {"key1": "value1"}, - }, - { - "value1": {"key1": "value1"}, - "value2": {"key1": "value1"}, - "expected": {"key1": "value1"}, - }, - { - "value1": {"key1": "value1"}, - "value2": {"key1": "value1", "key2": "value2"}, - "expected": {"key1": "value1", "key2": "value2"}, - }, - { - "value1": {"key1": "value1", "key2": "value2"}, - "value2": {"key1": "value1"}, - "expected": {"key1": "value1", "key2": "value2"}, - }, - { - "value1": {"s": {"key1": "value1"}}, - "value2": {"s": {"key1": "value1", "key2": "value2"}}, - "expected": {"s": {"key1": "value1", "key2": "value2"}}, - }, - { - "value1": {"s": {"key1": "value1", "key2": "value2"}}, - "value2": {"s": {"key1": "value1"}}, - "expected": {"s": {"key1": "value1", "key2": "value2"}}, - }, - { - "value1": {"key2": "value2", "key1": "value1"}, - "value2": {"key1": "value1", "key2": "value2"}, - "expected": {"key1": "value1", "key2": "value2"}, - }, - { - "value1": {"key2": "value2", "key1": "value1"}, - "value2": {"key1": "value1", "key2": "value2"}, - "expected": {"key1": "value1", "key2": "value2"}, - }, - ] - for case in cases: - value1, value2, expected = case["value1"], case["value2"], case["expected"] - union_value = common.union(value1, value2) - self.assertEqual(union_value, expected) - - -if __name__ == "__main__": - unittest.main(verbosity=2) diff --git a/test/test_units/test_kclvm/test_api/test_internal/test_decorator.py b/test/test_units/test_kclvm/test_api/test_internal/test_decorator.py deleted file mode 100644 index 165001426..000000000 --- a/test/test_units/test_kclvm/test_api/test_internal/test_decorator.py +++ /dev/null @@ -1,109 +0,0 @@ -# Copyright 2020 The KCL Authors. All rights reserved. - -import sys -import typing -import unittest - -import kclvm.kcl.error as kcl_error -import kclvm.api.object.internal.decorators as decorators - - -targets = [ - decorators.DecoratorTargetType.SCHEMA_TYPE, - decorators.DecoratorTargetType.ATTRIBUTE, -] - - -class TestDecoratorFactory(unittest.TestCase): - def test_decorator_factory_normal(self): - for target in targets: - decorators.decorator_factory.get(decorators.Deprecated.NAME, target) - - def test_decorator_factory_invalid(self): - for target in targets: - with self.assertRaises(kcl_error.UnKnownDecoratorError) as err: - decorators.decorator_factory.get(None, target) - self.assertEqual(err.exception.ewcode, kcl_error.ErrEwcode.UnKnownDecorator_Ew) - self.assertEqual(err.exception.arg_msg, "UnKnown decorator ") - - -class TestDecoratorDeprecated(unittest.TestCase): - def test_deprecated_schema(self): - decorator = decorators.Deprecated( - decorators.Deprecated.NAME, decorators.DecoratorTargetType.SCHEMA_TYPE - ) - with self.assertRaises(kcl_error.DeprecatedError) as err: - decorator.run(key="key", value="value") - self.assertEqual(err.exception.ewcode, kcl_error.ErrEwcode.Deprecated_Ew) - self.assertEqual(str(err.exception.arg_msg), "key was deprecated ") - - def test_deprecated_attr(self): - decorator = decorators.Deprecated( - decorators.Deprecated.NAME, decorators.DecoratorTargetType.ATTRIBUTE - ) - with self.assertRaises(kcl_error.DeprecatedError) as err: - decorator.run(key="key", value="value") - self.assertEqual(err.exception.ewcode, kcl_error.ErrEwcode.Deprecated_Ew) - self.assertEqual(str(err.exception.arg_msg), "key was deprecated ") - - def test_deprecated_attr_without_value(self): - decorator = decorators.Deprecated( - decorators.Deprecated.NAME, decorators.DecoratorTargetType.ATTRIBUTE - ) - decorator.run(key="key", value=None) - - def test_deprecated_invalid_target(self): - with self.assertRaises(kcl_error.InvalidDecoratorTargetError) as err: - decorators.Deprecated(decorators.Deprecated.NAME, None) - self.assertEqual(err.exception.ewcode, kcl_error.ErrEwcode.InvalidDecoratorTarget_Ew) - self.assertEqual(str(err.exception.arg_msg), "Invalid decorator target ") - - def test_deprecated_invalid_key(self): - for target in targets: - with self.assertRaises(kcl_error.KCLNameError) as err: - decorators.Deprecated(decorators.Deprecated.NAME, target).run("", "") - self.assertEqual(err.exception.ewcode, kcl_error.ErrEwcode.KCLNameError_Ew) - self.assertEqual(err.exception.arg_msg, "Name error : Decorator target name cannot be empty") - - def test_deprecated_version_parameter(self): - for target in targets: - decorator = decorators.Deprecated( - decorators.Deprecated.NAME, - target, - version="v1.16", - ) - with self.assertRaises(kcl_error.DeprecatedError) as err: - decorator.run(key="key", value="value") - self.assertEqual(err.exception.ewcode, kcl_error.ErrEwcode.Deprecated_Ew) - self.assertEqual( - str(err.exception.arg_msg), "key was deprecated since version v1.16" - ) - - def test_deprecated_version_reason_parameter(self): - for target in targets: - decorator = decorators.Deprecated( - decorators.Deprecated.NAME, - target, - reason="key is not supported", - version="v1.16", - ) - with self.assertRaises(kcl_error.DeprecatedError) as err: - decorator.run(key="key", value="value") - self.assertEqual(err.exception.ewcode, kcl_error.ErrEwcode.Deprecated_Ew) - self.assertEqual( - str(err.exception.arg_msg), - "key was deprecated since version v1.16, key is not supported", - ) - - def test_deprecated_version_strict_parameter(self): - for target in targets: - decorator = decorators.Deprecated( - decorators.Deprecated.NAME, - target, - strict=False, - ) - decorator.run(key="key", value="value") - - -if __name__ == "__main__": - unittest.main(verbosity=2) diff --git a/test/test_units/test_kclvm/test_api/test_internal/test_option.py b/test/test_units/test_kclvm/test_api/test_internal/test_option.py deleted file mode 100644 index c1993892e..000000000 --- a/test/test_units/test_kclvm/test_api/test_internal/test_option.py +++ /dev/null @@ -1,77 +0,0 @@ -# Copyright 2020 The KCL Authors. All rights reserved. - -import unittest - -import kclvm.config -import kclvm.api.object.internal.option as option - - -class TestOption(unittest.TestCase): - def setUp(self): - kclvm.config.arguments = [ - ("key1", "value1"), - ("key1", "value2"), - ("key2", "s"), - ("key3", 1), - ("key4", 1.0), - ("key5", True), - ("key6", False), - ("key7", "1"), - ("key8", "1.0"), - ] - option.kcl_option_init_all() - return super().setUp() - - def tearDown(self): - kclvm.config.arguments = [] - option.kcl_option_reset() - return super().tearDown() - - def test_kcl_option_elem(self): - elem = option.KclOptionElem("key") - self.assertEqual(str(elem), "key=?") - elem.default = "value" - self.assertEqual(str(elem), "key=value") - elem.value_type = "str" - self.assertEqual(str(elem), "key=value (str)") - elem.required = True - self.assertEqual(str(elem), "key=value (str,required)") - elem.value_type = "" - self.assertEqual(str(elem), "key=value (required)") - elem.file = "main.k" - elem.line = 1 - self.assertEqual(elem.get_help(verbose_mode=2), "key=value (required) (main.k:1)") - - def test_kcl_option_dict(self): - elem_key1 = option.KclOptionElem("key1") - elem_key2 = option.KclOptionElem("key2") - option_dict = option._KclOptionDict() - self.assertEqual(option_dict.help(), "") - option_dict.m["key1"] = elem_key1 - option_dict.m["key2"] = elem_key2 - self.assertEqual(option_dict.len(), 2) - self.assertEqual(option_dict.get_dict(), option_dict.m) - self.assertEqual(option_dict.keys(), ["key1", "key2"]) - self.assertEqual(option_dict.has_key("key1"), True) - self.assertEqual(option_dict.has_key("key_err"), False) - self.assertEqual(option_dict.help(), "option list:\nkey1=?\nkey2=?") - - def test_option_not_exist(self): - self.assertEqual(option.kcl_option("not_exist_key"), None) - self.assertEqual(option.kcl_option("not_exist_key", default=1), 1) - self.assertEqual(option.kcl_option("not_exist_key", default=1.0), 1.0) - self.assertEqual(option.kcl_option("not_exist_key", default=True), True) - - def test_option(self): - self.assertEqual(option.kcl_option("key1"), "value2") - self.assertEqual(option.kcl_option("key2"), "s") - self.assertEqual(option.kcl_option("key3"), 1) - self.assertEqual(option.kcl_option("key4"), 1.0) - self.assertEqual(option.kcl_option("key5"), True) - self.assertEqual(option.kcl_option("key6"), False) - self.assertEqual(option.kcl_option("key7", type="int"), 1) - self.assertEqual(option.kcl_option("key8", type="float"), 1.0) - - -if __name__ == "__main__": - unittest.main(verbosity=2) diff --git a/test/test_units/test_kclvm/test_api/test_internal/test_path_selector.py b/test/test_units/test_kclvm/test_api/test_internal/test_path_selector.py deleted file mode 100644 index fb8b6e315..000000000 --- a/test/test_units/test_kclvm/test_api/test_internal/test_path_selector.py +++ /dev/null @@ -1,46 +0,0 @@ -# Copyright 2020 The KCL Authors. All rights reserved. - -import unittest - -import kclvm.api.object.internal.path_selector as ps - - -class TestPathSelector(unittest.TestCase): - def test_select_instance_attributes(self): - cases = [ - {"inst": {"key1": "value1"}, "attrs": None, "expected": {"key1": "value1"}}, - {"inst": {"key1": "value1"}, "attrs": {}, "expected": {"key1": "value1"}}, - { - "inst": {"key1": "value1"}, - "attrs": {"key1": {}}, - "expected": {"key1": "value1"}, - }, - { - "inst": {"key1": "value1"}, - "attrs": {"err_key": {}}, - "expected": None, - }, - { - "inst": {"key1": {"internal_key": "value1"}}, - "attrs": {"key1": {}}, - "expected": {"key1": {"internal_key": "value1"}}, - }, - { - "inst": {"key1": {"internal_key": "value1"}}, - "attrs": {"key1": {"internal_key": {}}}, - "expected": {"key1": {"internal_key": "value1"}}, - }, - { - "inst": {"key1": "value1", "key2": "value2"}, - "attrs": {"key1": {}}, - "expected": {"key1": "value1"}, - }, - ] - for case in cases: - inst, attrs, expected = case["inst"], case["attrs"], case["expected"] - value = ps.select_instance_attributes(inst, attrs) - self.assertEqual(value, expected) - - -if __name__ == "__main__": - unittest.main(verbosity=2) diff --git a/test/test_units/test_kclvm/test_api/test_object/path_selector_test_data/main.k b/test/test_units/test_kclvm/test_api/test_object/path_selector_test_data/main.k deleted file mode 100644 index e122d4c05..000000000 --- a/test/test_units/test_kclvm/test_api/test_object/path_selector_test_data/main.k +++ /dev/null @@ -1,6 +0,0 @@ -schema Data: - id?: int - -data0 = Data { id = 0 } -data1 = Data { id = 1 } -data2 = Data { id = 2 } diff --git a/test/test_units/test_kclvm/test_api/test_object/test_bytecode.py b/test/test_units/test_kclvm/test_api/test_object/test_bytecode.py deleted file mode 100644 index 85dd97fa4..000000000 --- a/test/test_units/test_kclvm/test_api/test_object/test_bytecode.py +++ /dev/null @@ -1,38 +0,0 @@ -# Copyright 2020 The KCL Authors. All rights reserved. - -import pathlib -import unittest - -import kclvm.kcl.error as kcl_error -import kclvm.config as kcfg -import kclvm.api.object as objpkg -import kclvm.api.object.internal.path_selector as path_selector - - -class TestBytecodeObject(unittest.TestCase): - def setUp(self): - kcfg.path_selector = [["", "data0"]] - return super().setUp() - - def tearDown(self): - kcfg.path_selector = [] - return super().tearDown() - - def test_kcl_result(self): - filename = str( - pathlib.Path(__file__) - .parent.joinpath("path_selector_test_data") - .joinpath("main.k") - ) - data = {"data0": {"id": 0}, "data1": {"id": 1}, "data2": {"id": 2}} - dict_obj = objpkg.to_kcl_obj(data).value - result = objpkg.KCLResult(dict_obj, filename) - self.assertEqual(str(result), str(dict_obj)) - self.assertEqual( - result.filter_by_path_selector(), - objpkg.to_kcl_obj({"data0": {"id": 0}}).value, - ) - - -if __name__ == "__main__": - unittest.main(verbosity=2) diff --git a/test/test_units/test_kclvm/test_api/test_object/test_decorator.py b/test/test_units/test_kclvm/test_api/test_object/test_decorator.py deleted file mode 100644 index b0a1552da..000000000 --- a/test/test_units/test_kclvm/test_api/test_object/test_decorator.py +++ /dev/null @@ -1,31 +0,0 @@ -# Copyright 2020 The KCL Authors. All rights reserved. - -import unittest - -import kclvm.kcl.error as kcl_error -import kclvm.api.object as objpkg - -from kclvm.api.object.internal import Decorator - - -class TestDecoratorObject(unittest.TestCase): - def test_decorator_deprecated(self): - schema_name = "Person" - deprecated_decorator_obj = objpkg.KCLDecoratorObject( - target=objpkg.DecoratorTargetType.SCHEMA_TYPE, - name="deprecated", - key=schema_name, - ) - deprecated_decorator_obj.resolve([], []) - self.assertEqual( - deprecated_decorator_obj.type(), objpkg.KCLObjectType.DECORATOR - ) - self.assertEqual(deprecated_decorator_obj.type_str(), "decorator") - self.assertIsInstance(deprecated_decorator_obj.decorator, Decorator) - with self.assertRaises(kcl_error.DeprecatedError) as err: - deprecated_decorator_obj.call([], [], key=schema_name) - self.assertIn(f"{schema_name} was deprecated", str(err.exception)) - - -if __name__ == "__main__": - unittest.main(verbosity=2) diff --git a/test/test_units/test_kclvm/test_api/test_object/test_function.py b/test/test_units/test_kclvm/test_api/test_object/test_function.py deleted file mode 100644 index 5b8d2cab3..000000000 --- a/test/test_units/test_kclvm/test_api/test_object/test_function.py +++ /dev/null @@ -1,45 +0,0 @@ -# Copyright 2020 The KCL Authors. All rights reserved. - -import pathlib -import unittest - -import kclvm.kcl.error as kcl_error -import kclvm.api.object as objpkg - - -class TestFunctionObject(unittest.TestCase): - def test_function_object(self): - empty_func_obj = objpkg.KCLFunctionObject(name="fake") - self.assertEqual(empty_func_obj.type(), objpkg.KCLObjectType.FUNCTION) - self.assertEqual(empty_func_obj.type_str(), "function") - self.assertEqual(empty_func_obj.call([], []), None) - - def test_closure_object(self): - empty_func_obj = objpkg.KCLClosureObject(name="fake") - self.assertEqual(empty_func_obj.type(), objpkg.KCLObjectType.CLOSURE) - self.assertEqual(empty_func_obj.type_str(), "closure") - - def test_builtin_function_object(self): - print_builtin_func_obj = objpkg.KCLBuiltinFunctionObject( - name="print", - function=print, - ) - self.assertEqual(print_builtin_func_obj.call([], []), objpkg.NONE_INSTANCE) - sum_builtin_func_obj = objpkg.KCLBuiltinFunctionObject( - name="sum", - function=sum, - ) - self.assertEqual( - sum_builtin_func_obj.call([objpkg.to_kcl_obj([1, 2, 3])], []), - objpkg.to_kcl_obj(6), - ) - invalid_builtin_func_obj = objpkg.KCLBuiltinFunctionObject( - name="sum", - function=None, - ) - with self.assertRaises(Exception): - invalid_builtin_func_obj.call([], []) - - -if __name__ == "__main__": - unittest.main(verbosity=2) diff --git a/test/test_units/test_kclvm/test_api/test_object/test_object.py b/test/test_units/test_kclvm/test_api/test_object/test_object.py deleted file mode 100644 index 14304199e..000000000 --- a/test/test_units/test_kclvm/test_api/test_object/test_object.py +++ /dev/null @@ -1,360 +0,0 @@ -# Copyright 2020 The KCL Authors. All rights reserved. - -import unittest -from typing import cast - -import kclvm.kcl.ast as ast -import kclvm.kcl.error as kcl_error -from kclvm.api.object import ( - KCLIntObject, - KCLNumberMultiplierObject, - KCLDictObject, - KCLSchemaConfigObject, - KCLSchemaObject, - Undefined, - to_kcl_obj, - to_python_obj, -) - - -def to_kcl_dict_obj(data: dict) -> KCLDictObject: - return cast(KCLDictObject, to_kcl_obj(data)) - - -class TestNumberMultiplierObject(unittest.TestCase): - def test_number_multiplier_member_function(self): - obj = KCLNumberMultiplierObject( - value=1024, - raw_value=1, - binary_suffix="Mi", - ) - self.assertEqual(obj.type_str(), "number_multiplier(1Mi)") - self.assertEqual(str(obj), "1Mi") - self.assertEqual(repr(obj), "1Mi") - self.assertEqual(int(obj), 1024) - self.assertEqual(float(obj), 1024.0) - self.assertEqual(bool(obj), True) - - -class TestDictObject(unittest.TestCase): - def test_dict_object_append_unpack(self): - cases = [ - { - "data": {"key1": 1}, - "item": {"key2": 2}, - "expected": {"key1": 1, "key2": 2}, - }, - {"data": {"key1": 1}, "item": None, "expected": {"key1": 1}}, - {"data": {"key1": 1}, "item": Undefined, "expected": {"key1": 1}}, - { - "data": {"key1": 1}, - "item": KCLSchemaConfigObject( - value={"key1": KCLIntObject(2)}, - operation_map={"key1": ast.ConfigEntryOperation.OVERRIDE}, - ), - "expected": {"key1": 2}, - }, - { - "data": {"key1": 1}, - "item": KCLSchemaObject( - attrs={"key1": KCLIntObject(2)}, - operation_map={"key1": ast.ConfigEntryOperation.OVERRIDE}, - ), - "expected": {"key1": 2}, - }, - ] - for case in cases: - data, item, expected = ( - to_kcl_obj(case["data"]), - to_kcl_obj(case["item"]), - to_kcl_obj(case["expected"]), - ) - data.append_unpack(item) - self.assertEqual(to_python_obj(data), to_python_obj(expected)) - - def test_dict_object_insert_with_key(self): - cases = [ - { - "data": {"key": []}, - "key": "key", - "value": [1], - "index": None, - "expected": {"key": [1]}, - }, - { - "data": {"key": []}, - "key": "key", - "value": [1], - "index": -1, - "expected": {"key": [1]}, - }, - { - "data": {"key": [0]}, - "key": "key", - "value": [1], - "index": -1, - "expected": {"key": [0, 1]}, - }, - { - "data": {"key": [0]}, - "key": "key", - "value": [1], - "index": 0, - "expected": {"key": [1, 0]}, - }, - { - "data": {"key": None}, - "key": "key", - "value": [1], - "index": -1, - "expected": {"key": [1]}, - }, - ] - invalid_cases = [ - { - "data": {"key": 1}, - "key": "key", - "value": [1], - "index": -1, - "expected": {"key": [1]}, - }, - ] - for case in cases: - data, key, value, index, expected = ( - to_kcl_dict_obj(case["data"]), - case["key"], - to_kcl_obj(case["value"]), - case["index"], - case["expected"], - ) - data.insert_with_key(key, value, index) - self.assertEqual(to_python_obj(data), expected) - for case in invalid_cases: - data, key, value, index, expected = ( - to_kcl_dict_obj(case["data"]), - case["key"], - to_kcl_obj(case["value"]), - case["index"], - case["expected"], - ) - with self.assertRaises(kcl_error.KCLException): - data.insert_with_key(key, value, index) - - def test_dict_object_list_key_override(self): - cases = [ - { - "data": {"key": [0]}, - "attr": "key", - "value": 1, - "index": 0, - "expected": {"key": [1]}, - }, - { - "data": {"key": [0, 0]}, - "attr": "key", - "value": 1, - "index": 1, - "expected": {"key": [0, 1]}, - }, - { - "data": {"key": [0]}, - "attr": "key", - "value": Undefined, - "index": 0, - "expected": {"key": []}, - }, - ] - invalid_cases = [ - { - "data": {"key": 1}, - "attr": "key", - "value": [1], - "index": None, - "expected": {}, - }, - ] - for case in cases: - data, attr, value, index, expected = ( - to_kcl_dict_obj(case["data"]), - case["attr"], - to_kcl_obj(case["value"]), - case["index"], - case["expected"], - ) - data.list_key_override(attr, value, index) - self.assertEqual(to_python_obj(data), expected) - for case in invalid_cases: - data, attr, value, index, expected = ( - to_kcl_dict_obj(case["data"]), - case["attr"], - to_kcl_obj(case["value"]), - case["index"], - case["expected"], - ) - with self.assertRaises(kcl_error.KCLException): - data.list_key_override(attr, value, index) - - def test_dict_object_insert_with(self): - cases = [ - {"data": {}, "insert_data": {}, "index": None, "expected": {}}, - {"data": {}, "insert_data": None, "index": None, "expected": {}}, - { - "data": {"key": []}, - "insert_data": {"key": [0]}, - "index": None, - "expected": {"key": [0]}, - }, - { - "data": {"key": [0]}, - "insert_data": {"key": [1]}, - "index": None, - "expected": {"key": [0, 1]}, - }, - { - "data": {"key": [0], "key_val": "val"}, - "insert_data": {"key": [1]}, - "index": None, - "expected": {"key": [0, 1], "key_val": "val"}, - }, - { - "data": {"key": [0]}, - "insert_data": {"key": [1]}, - "index": -1, - "expected": {"key": [0, 1]}, - }, - { - "data": {"key": [0]}, - "insert_data": {"key": [1]}, - "index": 1, - "expected": {"key": [0, 1]}, - }, - { - "data": {"key": [0]}, - "insert_data": {"key": [1]}, - "index": 0, - "expected": {"key": [1, 0]}, - }, - ] - for case in cases: - data, insert_data, index, expected = ( - to_kcl_dict_obj(case["data"]), - to_kcl_dict_obj(case["insert_data"]), - case["index"], - case["expected"], - ) - data.insert_with(insert_data, index) - self.assertEqual(to_python_obj(data), expected) - - def test_dict_object_has_key(self): - cases = [ - {"data": {}, "key": None, "expected": False}, - {"data": {}, "key": "1", "expected": False}, - {"data": {}, "key": 1, "expected": False}, - {"data": {"key": "value"}, "key": "key_err", "expected": False}, - {"data": {"key": "value"}, "key": "key", "expected": True}, - {"data": {"key": {"key": "value"}}, "key": "key", "expected": True}, - ] - for case in cases: - data, key, expected = ( - to_kcl_dict_obj(case["data"]), - case["key"], - case["expected"], - ) - self.assertEqual(data.has_key(key), expected) - self.assertEqual(key in data, expected) - - def test_dict_object_get_key(self): - cases = [ - {"data": {}, "key": None, "expected": Undefined}, - {"data": {}, "key": "1", "expected": Undefined}, - {"data": {}, "key": 1, "expected": Undefined}, - {"data": {"key": "value"}, "key": "key_err", "expected": Undefined}, - {"data": {"key": None}, "key": "key", "expected": None}, - {"data": {"key": "value"}, "key": "key", "expected": "value"}, - { - "data": {"key": {"key": "value"}}, - "key": "key", - "expected": {"key": "value"}, - }, - ] - for case in cases: - data, key, expected = ( - to_kcl_dict_obj(case["data"]), - case["key"], - case["expected"], - ) - self.assertEqual(to_python_obj(data.get(key)), expected) - - def test_dict_object_update(self): - cases = [ - {"data": {}, "update": {"key": "value"}, "expected": {"key": "value"}}, - {"data": {}, "update": {"key": 1}, "expected": {"key": 1}}, - { - "data": {"key": "value"}, - "update": {"key": "override"}, - "expected": {"key": "override"}, - }, - { - "data": {"key1": "value1"}, - "update": {"key2": "value2"}, - "expected": {"key1": "value1", "key2": "value2"}, - }, - ] - for case in cases: - data, update, expected = ( - to_kcl_dict_obj(case["data"]), - case["update"], - case["expected"], - ) - data.update(update) - self.assertEqual(to_python_obj(data), expected) - - for case in cases: - data, update, expected = ( - to_kcl_dict_obj(case["data"]), - to_kcl_obj(case["update"]), - case["expected"], - ) - data.update(update) - self.assertEqual(to_python_obj(data), expected) - - def test_dict_unique_merge(self): - cases = [ - {"data": {}, "update": {"key": "value"}, "expected": {"key": "value"}}, - {"data": {}, "update": {"key": 1}, "expected": {"key": 1}}, - { - "data": {"key1": "value1"}, - "update": {"key2": "value2"}, - "expected": {"key1": "value1", "key2": "value2"}, - }, - ] - for case in cases: - data, update, expected = ( - to_kcl_dict_obj(case["data"]), - to_kcl_obj(case["update"]), - case["expected"], - ) - data.unique_merge_with(update) - self.assertEqual(to_python_obj(data), expected) - - def test_dict_delete(self): - cases = [ - {"data": {"key": "value"}, "key": "key", "expected": {}}, - { - "data": {"key1": "value1", "key2": "value2"}, - "key": "key1", - "expected": {"key2": "value2"}, - }, - ] - for case in cases: - data, key, expected = ( - to_kcl_dict_obj(case["data"]), - case["key"], - case["expected"], - ) - data.delete(key) - self.assertEqual(to_python_obj(data), expected) - - -if __name__ == "__main__": - unittest.main(verbosity=2) diff --git a/test/test_units/test_kclvm/test_api/test_object/test_range_check.py b/test/test_units/test_kclvm/test_api/test_object/test_range_check.py deleted file mode 100644 index 0984788ac..000000000 --- a/test/test_units/test_kclvm/test_api/test_object/test_range_check.py +++ /dev/null @@ -1,49 +0,0 @@ -# Copyright 2020 The KCL Authors. All rights reserved. - -import unittest - -import kclvm.config -import kclvm.kcl.info as kcl_info -import kclvm.kcl.error as kcl_error -import kclvm.api.object as objpkg - -from kclvm.compiler.check.check_type import check - - -class TestRangeCheck(unittest.TestCase): - def test_object_range_check_normal(self): - kclvm.config.debug = True - cases = [ - 1, - 2.0, - kcl_info.INT32_MAX + 1, - kcl_info.INT64_MAX, - kcl_info.FLOAT32_MAX, - ] - for case in cases: - check(objpkg.to_kcl_obj(case)) - kclvm.config.debug = False - - def test_object_range_check_invalid(self): - kclvm.config.debug = True - kclvm.config.strict_range_check = True - cases = [ - kcl_info.INT32_MAX + 1, - kcl_info.FLOAT32_MAX * 2, - ] - for case in cases: - with self.assertRaises(kcl_error.KCLException): - check(objpkg.to_kcl_obj(case)) - kclvm.config.strict_range_check = False - cases = [ - kcl_info.INT64_MAX + 1, - kcl_info.FLOAT64_MAX * 2, - ] - for case in cases: - with self.assertRaises(kcl_error.KCLException): - check(objpkg.to_kcl_obj(case)) - kclvm.config.debug = False - - -if __name__ == "__main__": - unittest.main(verbosity=2) diff --git a/test/test_units/test_kclvm/test_api/test_object/test_schema.py b/test/test_units/test_kclvm/test_api/test_object/test_schema.py deleted file mode 100644 index d44c2b0fc..000000000 --- a/test/test_units/test_kclvm/test_api/test_object/test_schema.py +++ /dev/null @@ -1,246 +0,0 @@ -# Copyright 2020 The KCL Authors. All rights reserved. -import unittest - -import kclvm.kcl.error as kcl_error -import kclvm.api.object.internal.decorators as decorators -from kclvm.api.object.object import ( - to_kcl_obj, - to_python_obj, - Undefined, - KCLIntObject, - KCLSchemaObject, - KCLSchemaConfigObject, - KCLStringLitTypeObject, -) -from kclvm.api.object.function import KCLCompiledFunctionObject, Parameter, KWArg -from kclvm.api.object.schema import KCLSchemaTypeObject -from kclvm.api.object.decorator import KCLDecoratorObject -from kclvm.kcl import ast - - -def build_test_schema_type_obj() -> KCLSchemaTypeObject: - schema_type_obj = KCLSchemaTypeObject.new( - "Person", None, "test.k", pkgpath="__main__", attr_list=["name", "age"] - ) - schema_type_obj.set_func( - KCLCompiledFunctionObject( - name="Person", - params=[ - Parameter( - name="name", value=to_kcl_obj("Alice"), type_annotation="str" - ), - Parameter(name="age", value=to_kcl_obj(18), type_annotation="int"), - Parameter( - name="sex", - value=to_kcl_obj("Male"), - type_annotation='"Male"|"Female"', - ), - ], - ) - ) - return schema_type_obj - - -def to_kcl_schema_obj(data: dict) -> KCLSchemaObject: - return KCLSchemaObject(name="Person", attrs=to_kcl_obj(data).value) - - -class TestSchemaObject(unittest.TestCase): - def test_dict_object_append_unpack(self): - cases = [ - { - "data": KCLSchemaObject(attrs={"key1": KCLIntObject(1)}), - "item": {"key2": 2}, - "expected": {"key1": 1, "key2": 2}, - }, - {"data": KCLSchemaObject(attrs={"key1": KCLIntObject(1)}), "item": None, "expected": {"key1": 1}}, - {"data": KCLSchemaObject(attrs={"key1": KCLIntObject(1)}), "item": Undefined, "expected": {"key1": 1}}, - { - "data": KCLSchemaObject(attrs={"key1": KCLIntObject(1)}), - "item": KCLSchemaConfigObject( - value={"key1": KCLIntObject(2)}, - operation_map={"key1": ast.ConfigEntryOperation.OVERRIDE}, - ), - "expected": {"key1": 2}, - }, - { - "data": KCLSchemaObject(attrs={"key1": KCLIntObject(1)}), - "item": KCLSchemaObject( - attrs={"key1": KCLIntObject(2)}, - operation_map={"key1": ast.ConfigEntryOperation.OVERRIDE}, - ), - "expected": {"key1": 2}, - }, - ] - for case in cases: - data, item, expected = ( - to_kcl_obj(case["data"]), - to_kcl_obj(case["item"]), - to_kcl_obj(case["expected"]), - ) - data.append_unpack(item) - self.assertEqual(to_python_obj(data), to_python_obj(expected)) - - def test_schema_object_update(self): - cases = [ - {"data": {}, "update": {"key": "value"}, "expected": {"key": "value"}}, - {"data": {}, "update": {"key": 1}, "expected": {"key": 1}}, - { - "data": {"key": "value"}, - "update": {"key": "override"}, - "expected": {"key": "override"}, - }, - { - "data": {"key1": "value1"}, - "update": {"key2": "value2"}, - "expected": {"key1": "value1", "key2": "value2"}, - }, - ] - for case in cases: - data, update, expected = ( - to_kcl_schema_obj(case["data"]), - case["update"], - case["expected"], - ) - data.update(update) - self.assertEqual(to_python_obj(data), expected) - - for case in cases: - data, update, expected = ( - to_kcl_schema_obj(case["data"]), - case["update"], - case["expected"], - ) - for k, v in update.items(): - data.update_key_value(k, v) - self.assertEqual(to_python_obj(data), expected) - - def test_schema_delete(self): - cases = [ - {"data": {"key": "value"}, "key": "key", "expected": {}}, - { - "data": {"key1": "value1", "key2": "value2"}, - "key": "key1", - "expected": {"key2": "value2"}, - }, - ] - for case in cases: - data, key, expected = ( - to_kcl_schema_obj(case["data"]), - case["key"], - case["expected"], - ) - data.delete(key) - self.assertEqual(to_python_obj(data), expected) - - def test_schema_set_node_of_attr(self): - schema_type_obj = build_test_schema_type_obj() - node = ast.AST() - schema_type_obj.set_node_of_attr("test_name", node) - self.assertEqual(schema_type_obj.attr_obj_map["test_name"].attr_node, node) - - node_1 = ast.AST() - schema_type_obj.set_node_of_attr("test_name", node_1) - self.assertNotEqual(schema_type_obj.attr_obj_map["test_name"].attr_node, node) - self.assertEqual(schema_type_obj.attr_obj_map["test_name"].attr_node, node_1) - - def test_schema_set_type_of_attr(self): - schema_type_obj = build_test_schema_type_obj() - tpe = KCLStringLitTypeObject() - schema_type_obj.set_type_of_attr("test_name", tpe) - self.assertEqual(schema_type_obj.attr_obj_map["test_name"].attr_type, tpe) - - tpe_1 = KCLStringLitTypeObject(value="test_tpe") - schema_type_obj.set_type_of_attr("test_name", tpe_1) - self.assertNotEqual(schema_type_obj.attr_obj_map["test_name"].attr_type, tpe) - self.assertEqual(schema_type_obj.attr_obj_map["test_name"].attr_type, tpe_1) - - def test_schema_decorator(self): - schema_obj = to_kcl_schema_obj({"key": "value"}) - schema_obj.add_decorator("key", KCLDecoratorObject( - name="Deprecated", - target=decorators.DecoratorTargetType.ATTRIBUTE, - key="key", - value="value", - decorator=decorators.Deprecated, - )) - # Deprecated decorator will raise an error - with self.assertRaises(Exception): - schema_obj.run_all_decorators() - - -class TestSchemaArgsTypeCheck(unittest.TestCase): - def test_schema_object_do_args_type_check_normal_only_args(self): - schema_type_obj = build_test_schema_type_obj() - cases = [ - [to_kcl_obj("Alice"), to_kcl_obj(18)], - [to_kcl_obj("Bob"), to_kcl_obj(10)], - [to_kcl_obj("John"), to_kcl_obj(10), to_kcl_obj("Female")], - ] - for case in cases: - schema_type_obj.do_args_type_check(case, None, {}) - - def test_schema_object_do_args_type_check_normal_only_kwargs(self): - schema_type_obj = build_test_schema_type_obj() - cases = [ - [ - KWArg(name=to_kcl_obj("name"), value=to_kcl_obj("Alice")), - KWArg(name=to_kcl_obj("age"), value=to_kcl_obj(18)), - ], - [ - KWArg(name=to_kcl_obj("name"), value=to_kcl_obj("Bob")), - KWArg(name=to_kcl_obj("age"), value=to_kcl_obj(10)), - ], - [ - KWArg(name=to_kcl_obj("sex"), value=to_kcl_obj("Male")), - KWArg(name=to_kcl_obj("name"), value=to_kcl_obj("Bob")), - KWArg(name=to_kcl_obj("age"), value=to_kcl_obj(10)), - ], - ] - for case in cases: - schema_type_obj.do_args_type_check(None, case, {}) - - def test_schema_object_unexpected_keyword_argument(self): - schema_type_obj = build_test_schema_type_obj() - cases = [ - [ - KWArg(name=to_kcl_obj("err_name"), value=to_kcl_obj("Alice")), - KWArg(name=to_kcl_obj("age"), value=to_kcl_obj(18)), - ], - [ - KWArg(name=to_kcl_obj("name"), value=to_kcl_obj("Bob")), - KWArg(name=to_kcl_obj("err_age"), value=to_kcl_obj(10)), - ], - [ - KWArg(name=to_kcl_obj("err_sex"), value=to_kcl_obj("Male")), - KWArg(name=to_kcl_obj("name"), value=to_kcl_obj("Bob")), - KWArg(name=to_kcl_obj("age"), value=to_kcl_obj(10)), - ], - ] - for case in cases: - with self.assertRaises(kcl_error.EvaluationError) as err: - schema_type_obj.do_args_type_check(None, case, {}) - self.assertEqual( - err.exception.ewcode, kcl_error.ErrEwcode.EvaluationError_Ew - ) - self.assertIn( - "schema arguments got an unexpected keyword argument", - str(err.exception), - ) - - -class TestSchemaTypeInstancesFunction(unittest.TestCase): - def test_schema_type_instances(self): - schema_type_obj = build_test_schema_type_obj() - schema_type_obj.__refs__.append( - KCLSchemaObject(name="Person", instance_pkgpath="__main__") - ) - schema_type_obj.__refs__.append( - KCLSchemaObject(name="Person", instance_pkgpath="pkg.to.path") - ) - self.assertEqual(len(schema_type_obj.instances()), 1) - self.assertEqual(len(schema_type_obj.instances(main_pkg=False)), 2) - - -if __name__ == "__main__": - unittest.main(verbosity=2) diff --git a/test/test_units/test_kclvm/test_api/test_object/test_undefined.py b/test/test_units/test_kclvm/test_api/test_object/test_undefined.py deleted file mode 100644 index cd181eb72..000000000 --- a/test/test_units/test_kclvm/test_api/test_object/test_undefined.py +++ /dev/null @@ -1,19 +0,0 @@ -# Copyright 2020 The KCL Authors. All rights reserved. - -import unittest - -from kclvm.api.object.internal import Undefined - - -class TestUndefinedObject(unittest.TestCase): - def test_undefined_object(self): - self.assertEqual(str(Undefined), "Undefined") - self.assertEqual(repr(Undefined), "Undefined") - self.assertEqual(Undefined.type_str(), "UndefinedType") - self.assertEqual(bool(Undefined), False) - self.assertEqual(not Undefined, True) - self.assertEqual(Undefined.value, None) - - -if __name__ == "__main__": - unittest.main(verbosity=2) diff --git a/test/test_units/test_kclvm/test_ast/test_ast/test_ast.py b/test/test_units/test_kclvm/test_ast/test_ast/test_ast.py deleted file mode 100644 index cd5866d0f..000000000 --- a/test/test_units/test_kclvm/test_ast/test_ast/test_ast.py +++ /dev/null @@ -1,227 +0,0 @@ -# Copyright 2020 The KCL Authors. All rights reserved. - -import typing -import pathlib -import hashlib -import unittest - -import kclvm.kcl.ast as ast -import kclvm.compiler.parser as parser - - -class TestAst(unittest.TestCase): - INIT_LINE = 0 - INIT_COLUMN = 0 - INIT_END_LINE = 0 - INIT_END_COLUMN = 0 - ast_node = ast.AST(INIT_LINE, INIT_COLUMN, INIT_END_LINE, INIT_END_COLUMN) - - set_methods = [ - "set_line", - "set_column", - "set_end_line", - "set_end_column", - ] - - get_methods = [ - "get_line", - "get_column", - "get_end_line", - "get_end_column", - ] - - offset_method = [ - "offset_line", - "offset_column", - "offset_end_line", - "offset_end_column", - ] - - # line, column, end_line, end_column - test_params = [0, 10, 22, 23] - offset_parmas = [-1, 10, 0] - - def test_ast_offset(self): - for i, method in enumerate(self.offset_method): - test_method = getattr(self.ast_node, method) - for offset_value in self.offset_parmas: - get_method = getattr(self.ast_node, self.get_methods[i]) - before = get_method() - test_method(offset_value) - assert get_method() == before + offset_value - - def test_ast_set_get_line_column(self): - for i, method in enumerate(self.set_methods): - test_method = getattr(self.ast_node, method) - test_method(self.test_params[i]) - - for i, method in enumerate(self.get_methods): - test_method = getattr(self.ast_node, method) - assert test_method() == self.test_params[i] - - def test_set_invalid(self): - for method in self.set_methods: - test_method = getattr(self.ast_node, method) - with self.assertRaises(AssertionError): - test_method("-1") - with self.assertRaises(AssertionError): - self.ast_node.set_line(-1) - - def test_offset_line_invalid(self): - for method in self.offset_method: - test_method = getattr(self.ast_node, method) - with self.assertRaises(AssertionError): - test_method("-1") - - def test_position_less_than(self): - _ONE = "one" - _OTHER = "other" - _RESULT = "result" - test_cases = [ - { - # position invalid - _ONE: ast.Position(filename="one.k", line=0, column=1), - _OTHER: ast.Position(filename="one.k", line=0, column=1), - _RESULT: False, - }, - { - # different filename - _ONE: ast.Position(filename="one.k", line=1, column=1), - _OTHER: ast.Position(filename="other.k", line=1, column=1), - _RESULT: False, - }, - { - # line number less than - _ONE: ast.Position(filename="one.k", line=1, column=1), - _OTHER: ast.Position(filename="one.k", line=2, column=1), - _RESULT: True, - }, - { - # line number larger than - _ONE: ast.Position(filename="one.k", line=2, column=1), - _OTHER: ast.Position(filename="one.k", line=1, column=1), - _RESULT: False, - }, - { - # line number equal, column number less than - _ONE: ast.Position(filename="one.k", line=1, column=0), - _OTHER: ast.Position(filename="one.k", line=1, column=1), - _RESULT: True, - }, - ] - for t in test_cases: - expect = t[_RESULT] - got = t[_ONE].less(t[_OTHER]) - assert ( - expect == got - ), f"position less than check between {t[_ONE]} and {t[_OTHER]}, expect: {expect}, got: {got}" - - def test_position_valid(self): - _POS = "pos" - _RESULT = "result" - test_cases = [ - { - # empty filename - _POS: ast.Position(line=1, column=0), - _RESULT: False, - }, - { - # line number < 1 - _POS: ast.Position(filename="pos.k", line=0, column=0), - _RESULT: False, - }, - ] - for t in test_cases: - expect = t[_RESULT] - got = t[_POS].is_valid() - assert ( - expect == got - ), f"position valid on {t[_POS]}, expect: {expect}, got: {got}" - - def test_position_less_equal(self): - _ONE = "one" - _OTHER = "other" - _RESULT = "result" - test_cases = [ - { - # position invalid - _ONE: ast.Position(filename="one.k", line=0, column=1), - _OTHER: ast.Position(filename="one.k", line=0, column=1), - _RESULT: False, - }, - { - # different filename - _ONE: ast.Position(filename="one.k", line=1, column=1), - _OTHER: ast.Position(filename="other.k", line=1, column=1), - _RESULT: False, - }, - { - # position less than - _ONE: ast.Position(filename="one.k", line=1, column=1), - _OTHER: ast.Position(filename="one.k", line=2, column=1), - _RESULT: True, - }, - { - # position equal - _ONE: ast.Position(filename="one.k", line=1, column=1), - _OTHER: ast.Position(filename="one.k", line=1, column=1), - _RESULT: True, - }, - ] - - for t in test_cases: - expect = t[_RESULT] - got = t[_ONE].less_equal(t[_OTHER]) - assert ( - expect == got - ), f"position less equal check between {t[_ONE]} and {t[_OTHER]}, expect: {expect}, got: {got}" - - def test_position_equal(self): - _ONE = "one" - _OTHER = "other" - _RESULT = "result" - test_cases = [ - { - # position equal - _ONE: ast.Position(filename="one.k", line=0, column=1), - _OTHER: ast.Position(filename="one.k", line=0, column=1), - _RESULT: True, - }, - { - # position not equal - _ONE: ast.Position(filename="one.k", line=0, column=1), - _OTHER: ast.Position(filename="one.k", line=0, column=2), - _RESULT: False, - }, - ] - for t in test_cases: - expect = t[_RESULT] - got = t[_ONE] == (t[_OTHER]) - assert ( - expect == got - ), f"position equal check between {t[_ONE]} and {t[_OTHER]}, expect: {expect}, got: {got}" - - def test_get_check_sum(self): - filename = str(pathlib.Path(__file__).parent.joinpath("test_data/check_sum.k")) - prog = parser.LoadProgram(filename) - with open(filename, "rb") as f: - check_sum_expected = hashlib.md5() - check_sum_expected.update(filename.encode("utf-8")) - check_sum_expected.update(f.read()) - self.assertEqual(prog.get_check_sum(), check_sum_expected.hexdigest()) - - def test_GetArgDefault_invalid(self): - arg = ast.Arguments() - self.assertEqual(arg.GetArgDefault(10), None) - - def test_find_nearest_parent_by_type(self): - prog = parser.LoadProgram("mock.k", k_code_list=["a=1"], set_ast_parent=True) - target_identifier = prog.pkgs[prog.MAIN_PKGPATH][0].body[0].targets[0] - self.assertIsNotNone(target_identifier) - self.assertIsNotNone(target_identifier.parent) - nearest_schema_expr = target_identifier.find_nearest_parent_by_type(tpe=ast.SchemaExpr) - self.assertIsNone(nearest_schema_expr) - - -if __name__ == "__main__": - unittest.main(verbosity=2) diff --git a/test/test_units/test_kclvm/test_ast/test_filter/test_filter.py b/test/test_units/test_kclvm/test_ast/test_filter/test_filter.py deleted file mode 100644 index db4720a3c..000000000 --- a/test/test_units/test_kclvm/test_ast/test_filter/test_filter.py +++ /dev/null @@ -1,51 +0,0 @@ -#! /usr/bin/env python3 - -import unittest - -from kclvm.compiler.astutil import filter_declarations -from kclvm.compiler.parser import ParseFile - -import kclvm.kcl.ast as ast -import kclvm.kcl.error as kcl_error - -code = """ -schema Person: - name: str - age: int - -schema Config: - data?: [int] - -a = 1 -b = 2 -person = Person { - name: "Alice" - age: 18 -} -config = Config {} -""" - - -class KCLASTFilterTest(unittest.TestCase): - """ - KCL AST filter test - """ - - def test_filter(self): - module = ParseFile("test.k", code) - global_declarations = filter_declarations(module) - schema_declarations = filter_declarations(module, ast.SchemaExpr) - binary_declarations = filter_declarations(module, ast.BinaryExpr) - self.assertEqual(len(global_declarations), 4) - self.assertEqual(len(schema_declarations), 2) - self.assertEqual(len(binary_declarations), 0) - self.assertEqual(global_declarations[0].name, "a") - self.assertEqual(global_declarations[1].name, "b") - self.assertEqual(global_declarations[2].name, "person") - self.assertEqual(global_declarations[3].name, "config") - self.assertEqual(schema_declarations[0].name, "person") - self.assertEqual(schema_declarations[1].name, "config") - - -if __name__ == "__main__": - unittest.main(verbosity=2) diff --git a/test/test_units/test_kclvm/test_ast/test_precedence/test_precedence.py b/test/test_units/test_kclvm/test_ast/test_precedence/test_precedence.py deleted file mode 100644 index b7a319155..000000000 --- a/test/test_units/test_kclvm/test_ast/test_precedence/test_precedence.py +++ /dev/null @@ -1,60 +0,0 @@ -#! /usr/bin/env python3 - -import unittest - -import kclvm.kcl.ast as ast - -import kclvm.kcl.ast.lark_token as lark_token - - -class KCLPrecedenceTest(unittest.TestCase): - """KCL AST operator precedence test""" - - def test_precedence(self): - self.assertEqual(ast.precedence(None), 0) - self.assertEqual(ast.precedence(ast.lark_token.LarkToken.L_simple_expr), 0) - self.assertEqual(ast.precedence(ast.AugOp.Add), 0) - self.assertEqual(ast.precedence(ast.AugOp.Sub), 0) - self.assertEqual(ast.precedence(ast.AugOp.Mul), 0) - self.assertEqual(ast.precedence(ast.AugOp.Div), 0) - self.assertEqual(ast.precedence(ast.AugOp.Mod), 0) - self.assertEqual(ast.precedence(ast.AugOp.Pow), 0) - self.assertEqual(ast.precedence(ast.AugOp.LShift), 0) - self.assertEqual(ast.precedence(ast.AugOp.RShift), 0) - self.assertEqual(ast.precedence(ast.AugOp.BitOr), 0) - self.assertEqual(ast.precedence(ast.AugOp.BitXor), 0) - self.assertEqual(ast.precedence(ast.AugOp.BitAnd), 0) - self.assertEqual(ast.precedence(ast.AugOp.FloorDiv), 0) - self.assertEqual(ast.precedence(ast.BinOp.Add), 9) - self.assertEqual(ast.precedence(ast.BinOp.Sub), 9) - self.assertEqual(ast.precedence(ast.BinOp.Mul), 10) - self.assertEqual(ast.precedence(ast.BinOp.Div), 10) - self.assertEqual(ast.precedence(ast.BinOp.Mod), 10) - self.assertEqual(ast.precedence(ast.BinOp.Pow), 12) - self.assertEqual(ast.precedence(ast.BinOp.LShift), 8) - self.assertEqual(ast.precedence(ast.BinOp.RShift), 8) - self.assertEqual(ast.precedence(ast.BinOp.BitOr), 6) - self.assertEqual(ast.precedence(ast.BinOp.BitXor), 5) - self.assertEqual(ast.precedence(ast.BinOp.BitAnd), 7) - self.assertEqual(ast.precedence(ast.BinOp.FloorDiv), 10) - self.assertEqual(ast.precedence(ast.BinOp.And), 2) - self.assertEqual(ast.precedence(ast.BinOp.Or), 1) - self.assertEqual(ast.precedence(ast.CmpOp.Eq), 4) - self.assertEqual(ast.precedence(ast.CmpOp.NotEq), 4) - self.assertEqual(ast.precedence(ast.CmpOp.Lt), 4) - self.assertEqual(ast.precedence(ast.CmpOp.LtE), 4) - self.assertEqual(ast.precedence(ast.CmpOp.Gt), 4) - self.assertEqual(ast.precedence(ast.CmpOp.GtE), 4) - self.assertEqual(ast.precedence(ast.CmpOp.Is), 4) - self.assertEqual(ast.precedence(ast.CmpOp.In), 4) - self.assertEqual(ast.precedence(ast.CmpOp.Not), 4) - self.assertEqual(ast.precedence(ast.CmpOp.IsNot), 4) - self.assertEqual(ast.precedence(ast.CmpOp.NotIn), 4) - self.assertEqual(ast.precedence(ast.UnaryOp.UAdd), 11) - self.assertEqual(ast.precedence(ast.UnaryOp.USub), 11) - self.assertEqual(ast.precedence(ast.UnaryOp.Invert), 11) - self.assertEqual(ast.precedence(ast.UnaryOp.Not), 3) - - -if __name__ == "__main__": - unittest.main(verbosity=2) diff --git a/test/test_units/test_kclvm/test_ast/test_transfomer/test_data/assign.input b/test/test_units/test_kclvm/test_ast/test_transfomer/test_data/assign.input deleted file mode 100644 index a5ebf7ab2..000000000 --- a/test/test_units/test_kclvm/test_ast/test_transfomer/test_data/assign.input +++ /dev/null @@ -1,4 +0,0 @@ -a = 1 -b = 2 -if True: - c = 3 diff --git a/test/test_units/test_kclvm/test_ast/test_transfomer/test_data/assign.output b/test/test_units/test_kclvm/test_ast/test_transfomer/test_data/assign.output deleted file mode 100644 index d63f7aa3f..000000000 --- a/test/test_units/test_kclvm/test_ast/test_transfomer/test_data/assign.output +++ /dev/null @@ -1,5 +0,0 @@ -a = aa = 1 -b = bb = 2 -if True: - c = cc = 3 - diff --git a/test/test_units/test_kclvm/test_ast/test_transfomer/test_data/assign_split.input b/test/test_units/test_kclvm/test_ast/test_transfomer/test_data/assign_split.input deleted file mode 100644 index a4f1d33e2..000000000 --- a/test/test_units/test_kclvm/test_ast/test_transfomer/test_data/assign_split.input +++ /dev/null @@ -1,6 +0,0 @@ -schema Config: - data?: int - -config1 = config2 = Config { - data: 1 -} diff --git a/test/test_units/test_kclvm/test_ast/test_transfomer/test_data/assign_split.output b/test/test_units/test_kclvm/test_ast/test_transfomer/test_data/assign_split.output deleted file mode 100644 index ec6c12e13..000000000 --- a/test/test_units/test_kclvm/test_ast/test_transfomer/test_data/assign_split.output +++ /dev/null @@ -1,11 +0,0 @@ -schema Config: - data?: int - -config1 = Config { - data: 1 -} - -config2 = Config { - data: 1 -} - diff --git a/test/test_units/test_kclvm/test_ast/test_transfomer/test_transformer.py b/test/test_units/test_kclvm/test_ast/test_transfomer/test_transformer.py deleted file mode 100644 index ff5f3c7e7..000000000 --- a/test/test_units/test_kclvm/test_ast/test_transfomer/test_transformer.py +++ /dev/null @@ -1,81 +0,0 @@ -#! /usr/bin/env python3 - -import io -import unittest -import pathlib -from copy import deepcopy -from typing import List - -from kclvm.compiler.parser import ParseFile -from kclvm.tools.printer import PrintAST -import kclvm.kcl.ast as ast - - -_FILE_INPUT_SUFFIX = ".input" -_FILE_OUTPUT_SUFFIX = ".output" -_PATH_NAME = "test_data" -_DIR_PATH = pathlib.Path(__file__).parent.joinpath(_PATH_NAME) - - -class TestTransformer(ast.TreeTransformer): - def walk_AssignStmt(self, t: ast.AssignStmt): - name = t.targets[0].get_name() - t.targets.append( - ast.Identifier( - line=t.line, - column=t.column, - names=[name * 2], - ctx=ast.ExprContext.STORE, - ) - ) - return t - - -class AssignSplitTransformer(ast.TreeTransformer): - def walk_AssignStmt(self, t: ast.AssignStmt): - if len(t.targets) > 1: - assign_stmt_list: List[ast.AssertStmt] = [] - for target in t.targets: - t_copy = deepcopy(t) - t_copy.targets = [target] - assign_stmt_list.append(t_copy) - return assign_stmt_list - return t - - -class KCLBaseTreeTransformerTest(unittest.TestCase): - """KCL AST transfomer test""" - - def setUp(self): - inputs = list(sorted(pathlib.Path(_DIR_PATH).glob("*" + _FILE_INPUT_SUFFIX))) - case_inputs = [input.read_text() for input in inputs] - outputs = list(sorted(pathlib.Path(_DIR_PATH).glob("*" + _FILE_OUTPUT_SUFFIX))) - case_outputs = [output.read_text() for output in outputs] - names = [str(output.with_suffix("").name) for output in outputs] - self.TEST_CASES = zip(names, case_inputs, case_outputs) - return super().setUp() - - def transform_code(self, code: str, transformer: ast.TreeTransformer) -> str: - module = ParseFile("", code) - transformer().walk(module) - with io.StringIO() as buf: - PrintAST(module, buf) - return buf.getvalue() - - -class KCLTreeTransformerTest(KCLBaseTreeTransformerTest): - """KCL AST transfomer test""" - - transformer_mapping = { - "assign": TestTransformer, - "assign_split": AssignSplitTransformer, - } - - def test_transform(self): - for name, case_input, case_output in self.TEST_CASES: - transformer = self.transformer_mapping.get(name, TestTransformer) - self.assertEqual(self.transform_code(case_input, transformer), case_output) - - -if __name__ == "__main__": - unittest.main(verbosity=2) diff --git a/test/test_units/test_kclvm/test_compiler/test_astutil/test_builder.py b/test/test_units/test_kclvm/test_compiler/test_astutil/test_builder.py deleted file mode 100644 index f94abd2c8..000000000 --- a/test/test_units/test_kclvm/test_compiler/test_astutil/test_builder.py +++ /dev/null @@ -1,65 +0,0 @@ -# Copyright 2020 The KCL Authors. All rights reserved. - -import os -import pathlib -import unittest - -import kclvm.api.object.internal as internal -import kclvm.kcl.ast as ast -import kclvm.compiler.astutil.builder as ast_builder - - -class TestASTUtil(unittest.TestCase): - def get_fake_schema_expr(self, name: str) -> ast.SchemaExpr: - schema_expr = ast.SchemaExpr(line=1, column=1) - schema_name = ast.Identifier(line=1, column=1) - schema_name.names = [name] - schema_expr.name = schema_name - schema_expr.config = ast.ConfigExpr(line=1, column=1 + 1 +len(name)) - return schema_expr - - def test_build_lit_node_from_string(self): - cases = [ - {"value": "a", "expected": ast.StringLit(value="a", line=1, column=1)}, - {"value": "'a'", "expected": ast.StringLit(value="a", line=1, column=1)}, - {"value": '"a"', "expected": ast.StringLit(value="a", line=1, column=1)}, - {"value": "kclvm:v1", "expected": ast.StringLit(value="kclvm:v1", line=1, column=1)}, - {"value": "1", "expected": ast.NumberLit(value=1, line=1, column=1)}, - {"value": "1.1", "expected": ast.NumberLit(value=1.1, line=1, column=1)}, - {"value": "1.0e1", "expected": ast.NumberLit(value=10.0, line=1, column=1)}, - {"value": "True", "expected": ast.NameConstantLit(value=True, line=1, column=1)}, - {"value": "False", "expected": ast.NameConstantLit(value=False, line=1, column=1)}, - {"value": "None", "expected": ast.NameConstantLit(value=None, line=1, column=1)}, - {"value": "Undefined", "expected": ast.NameConstantLit(value=internal.Undefined, line=1, column=1)}, - {"value": "[]", "expected": ast.ListExpr(line=1, column=1)}, - {"value": "{}", "expected": ast.ConfigExpr(line=1, column=1)}, - {"value": "Data {}", "expected": self.get_fake_schema_expr("Data")}, - {"value": "pkg.Data {}", "expected": self.get_fake_schema_expr("pkg.Data")}, - ] - for case in cases: - value, expected = case["value"], case["expected"] - ast_node = ast_builder.BuildNodeFromString(value, 1, 1) - self.assertEqual(str(ast_node), str(expected)) - - def test_build_lit_node_from_value(self): - cases = [ - {"value": "a", "expected": ast.StringLit(value="a", line=1, column=1)}, - {"value": "'a'", "expected": ast.StringLit(value="'a'", line=1, column=1)}, - {"value": '"a"', "expected": ast.StringLit(value="\"a\"", line=1, column=1)}, - {"value": "kclvm:v1", "expected": ast.StringLit(value="kclvm:v1", line=1, column=1)}, - {"value": 1, "expected": ast.NumberLit(value=1, line=1, column=1)}, - {"value": 1.1, "expected": ast.NumberLit(value=1.1, line=1, column=1)}, - {"value": 1.0e1, "expected": ast.NumberLit(value=10.0, line=1, column=1)}, - {"value": True, "expected": ast.NameConstantLit(value=True, line=1, column=1)}, - {"value": False, "expected": ast.NameConstantLit(value=False, line=1, column=1)}, - {"value": None, "expected": ast.NameConstantLit(value=None, line=1, column=1)}, - {"value": internal.Undefined, "expected": ast.NameConstantLit(value=internal.Undefined, line=1, column=1)}, - ] - for case in cases: - value, expected = case["value"], case["expected"] - ast_node = ast_builder.BuildLitNodeFromValue(value, 1, 1) - self.assertEqual(str(ast_node), str(expected)) - - -if __name__ == "__main__": - unittest.main(verbosity=2) diff --git a/test/test_units/test_kclvm/test_compiler/test_astutil/test_filter.py b/test/test_units/test_kclvm/test_compiler/test_astutil/test_filter.py deleted file mode 100644 index c18f8b1bc..000000000 --- a/test/test_units/test_kclvm/test_compiler/test_astutil/test_filter.py +++ /dev/null @@ -1,37 +0,0 @@ -# Copyright 2020 The KCL Authors. All rights reserved. - -import os -import pathlib -import unittest - -import kclvm.kcl.ast as ast -import kclvm.compiler.parser as parser -import kclvm.compiler.astutil.filter as filter - -filter_simple_case = """ -schema Config: - id: int - -config1 = Config {id = 1} -config2: Config {id = 2} -config3 = {id = 3} -""" - - -class TestASTFilter(unittest.TestCase): - def test_filter_declarations(self): - module = parser.ParseFile( - "__main__.k", code=filter_simple_case - ) - declarations = filter.filter_declarations(module) - self.assertEqual(len(declarations), 3) - declarations = filter.filter_declarations(module, ast_type=ast.SchemaExpr) - self.assertEqual(len(declarations), 2) - declarations = filter.filter_declarations(module, ast_type="SchemaExpr") - self.assertEqual(len(declarations), 2) - declarations = filter.filter_declarations(module, ast_type=(ast.SchemaExpr, ast.ConfigExpr)) - self.assertEqual(len(declarations), 3) - - -if __name__ == "__main__": - unittest.main(verbosity=2) diff --git a/test/test_units/test_kclvm/test_compiler/test_astutil/test_fix.py b/test/test_units/test_kclvm/test_compiler/test_astutil/test_fix.py deleted file mode 100644 index 23d5f02d6..000000000 --- a/test/test_units/test_kclvm/test_compiler/test_astutil/test_fix.py +++ /dev/null @@ -1,118 +0,0 @@ -# Copyright 2020 The KCL Authors. All rights reserved. - -import os -import pathlib -import unittest -import typing - -import kclvm.kcl.ast as ast -import kclvm.compiler.parser as parser -import kclvm.compiler.astutil.fix as fix - -MAIN_FILE = "main.k" -MAIN_PKG = "__main__" -ROOT_PATH = str(pathlib.Path(__file__).parent) - -fix_test_schema_relaxed_case = """ -import path.to.pkg as pkgname - -x = pkgname.Name - -schema Person: - name: str - age: int - -schema TestPerson: - name = "Alice" - age = 18 - person: Person = Person { - name: name - age: age - } - assert person.name == name - assert person.age == age -""" -fix_module_import_list_case = """ -import path.to.pkg as pkgname -import another.path.to.pkg as another_pkgname - -x = pkgname.Name - -schema Person[dataVar: pkgname.Data | another_pkgname.Version]: - name: str - age: int - data?: pkgname.Data | another_pkgname.Version = dataVar - -rule PersonCheck[data: pkgname.Data]: - data.id > 0 - -func = lambda x: pkgname.Data, y -> pkgname.Data { - x + y -} - -person = Person(pkgname.Data {id = 1}) { - name = "Alice" - age = 18 -} -var: pkgname.Data = pkgname.Data {} -type Data = pkgname.Data -""" - - -class TestFixQualifiedIdentifier(unittest.TestCase): - def test_fix_qualified_identifier(self): - module = parser.ParseFile( - MAIN_FILE, code=fix_test_schema_relaxed_case, pkg=MAIN_PKG - ) - fix.fix_qualified_identifier(module) - - -class TestFixAndGetModuleImportList(unittest.TestCase): - def test_fix_and_get_module_import_list(self): - module = parser.ParseFile( - MAIN_FILE, code=fix_module_import_list_case, pkg=MAIN_PKG - ) - self.assertIsInstance(module.body[0], ast.ImportStmt) - self.assertIsInstance(module.body[1], ast.ImportStmt) - self.assertIsInstance(module.body[2], ast.AssignStmt) - self.assertIsInstance(module.body[3], ast.SchemaStmt) - self.assertIsInstance(module.body[4], ast.RuleStmt) - self.assertIsInstance(module.body[5].value, ast.LambdaExpr) - self.assertIsInstance(module.body[6], ast.AssignStmt) - self.assertIsInstance(module.body[7], ast.AssignStmt) - self.assertIsInstance(module.body[8], ast.TypeAliasStmt) - schema_args = typing.cast(ast.SchemaStmt, module.body[3]).args - self.assertEqual(schema_args.GetArgType(0), "pkgname.Data|another_pkgname.Version") - import_list = fix.fix_and_get_module_import_list(ROOT_PATH, module) - self.assertEqual(len(import_list), 2) - self.assertEqual(import_list[0].path, "path.to.pkg") - self.assertEqual(import_list[0].asname, "pkgname") - self.assertEqual(schema_args.GetArgType(0), "@path.to.pkg.Data|@another.path.to.pkg.Version") - fix.fix_and_get_module_import_list(ROOT_PATH, module, reversed=True) - self.assertEqual(schema_args.GetArgType(0), "pkgname.Data|another_pkgname.Version") - - -class TestFixSchemaAutoRelaxed(unittest.TestCase): - def test_fix_test_schema_auto_relaxed_invalid(self): - module = parser.ParseFile("invalid_name.k", code=fix_test_schema_relaxed_case) - # Before fix - self.assertEqual(len(module.body), 4) - self.assertIsInstance(module.body[3], ast.SchemaStmt) - # After fix - fix.fix_test_schema_auto_relaxed(module) - self.assertEqual(len(module.body), 4) - self.assertIsInstance(module.body[3], ast.SchemaStmt) - - def test_fix_test_schema_auto_relaxed_normal(self): - module = parser.ParseFile("person_test.k", code=fix_test_schema_relaxed_case) - # Before fix - self.assertEqual(len(module.body), 4) - self.assertIsInstance(module.body[3], ast.SchemaStmt) - # After fix - fix.fix_test_schema_auto_relaxed(module) - self.assertEqual(len(module.body), 4) - self.assertIsInstance(module.body[3], ast.SchemaStmt) - - -if __name__ == "__main__": - unittest.main(verbosity=2) diff --git a/test/test_units/test_kclvm/test_compiler/test_build/cache_expired_testdata/kcl.mod b/test/test_units/test_kclvm/test_compiler/test_build/cache_expired_testdata/kcl.mod deleted file mode 100644 index f4e7091a3..000000000 --- a/test/test_units/test_kclvm/test_compiler/test_build/cache_expired_testdata/kcl.mod +++ /dev/null @@ -1,3 +0,0 @@ -[build] -enable_pkg_cache=true -cached_pkg_prefix="pkg." diff --git a/test/test_units/test_kclvm/test_compiler/test_build/cache_expired_testdata/main.k b/test/test_units/test_kclvm/test_compiler/test_build/cache_expired_testdata/main.k deleted file mode 100644 index d6c10fcfb..000000000 --- a/test/test_units/test_kclvm/test_compiler/test_build/cache_expired_testdata/main.k +++ /dev/null @@ -1,3 +0,0 @@ -import pkg - -a = pkg.a diff --git a/test/test_units/test_kclvm/test_compiler/test_build/cache_expired_testdata/pkg/pkg.k b/test/test_units/test_kclvm/test_compiler/test_build/cache_expired_testdata/pkg/pkg.k deleted file mode 100644 index 7650d717f..000000000 --- a/test/test_units/test_kclvm/test_compiler/test_build/cache_expired_testdata/pkg/pkg.k +++ /dev/null @@ -1,3 +0,0 @@ -import pkg.pkg1 - -a = pkg1.a diff --git a/test/test_units/test_kclvm/test_compiler/test_build/cache_expired_testdata/pkg/pkg1/pkg.k b/test/test_units/test_kclvm/test_compiler/test_build/cache_expired_testdata/pkg/pkg1/pkg.k deleted file mode 100644 index 1f2c735b1..000000000 --- a/test/test_units/test_kclvm/test_compiler/test_build/cache_expired_testdata/pkg/pkg1/pkg.k +++ /dev/null @@ -1,3 +0,0 @@ -import pkg.pkg1.pkg2 - -a = pkg2.a diff --git a/test/test_units/test_kclvm/test_compiler/test_build/cache_testdata/kcl.mod b/test/test_units/test_kclvm/test_compiler/test_build/cache_testdata/kcl.mod deleted file mode 100644 index f4e7091a3..000000000 --- a/test/test_units/test_kclvm/test_compiler/test_build/cache_testdata/kcl.mod +++ /dev/null @@ -1,3 +0,0 @@ -[build] -enable_pkg_cache=true -cached_pkg_prefix="pkg." diff --git a/test/test_units/test_kclvm/test_compiler/test_build/cache_testdata/main.k b/test/test_units/test_kclvm/test_compiler/test_build/cache_testdata/main.k deleted file mode 100644 index d6c10fcfb..000000000 --- a/test/test_units/test_kclvm/test_compiler/test_build/cache_testdata/main.k +++ /dev/null @@ -1,3 +0,0 @@ -import pkg - -a = pkg.a diff --git a/test/test_units/test_kclvm/test_compiler/test_build/cache_testdata/pkg/pkg.k b/test/test_units/test_kclvm/test_compiler/test_build/cache_testdata/pkg/pkg.k deleted file mode 100644 index 7650d717f..000000000 --- a/test/test_units/test_kclvm/test_compiler/test_build/cache_testdata/pkg/pkg.k +++ /dev/null @@ -1,3 +0,0 @@ -import pkg.pkg1 - -a = pkg1.a diff --git a/test/test_units/test_kclvm/test_compiler/test_build/cache_testdata/pkg/pkg1/pkg.k b/test/test_units/test_kclvm/test_compiler/test_build/cache_testdata/pkg/pkg1/pkg.k deleted file mode 100644 index 1f2c735b1..000000000 --- a/test/test_units/test_kclvm/test_compiler/test_build/cache_testdata/pkg/pkg1/pkg.k +++ /dev/null @@ -1,3 +0,0 @@ -import pkg.pkg1.pkg2 - -a = pkg2.a diff --git a/test/test_units/test_kclvm/test_compiler/test_build/invalid_testdata/defaults_not_full_invalid/main.k b/test/test_units/test_kclvm/test_compiler/test_build/invalid_testdata/defaults_not_full_invalid/main.k deleted file mode 100644 index f7b78cc7e..000000000 --- a/test/test_units/test_kclvm/test_compiler/test_build/invalid_testdata/defaults_not_full_invalid/main.k +++ /dev/null @@ -1,7 +0,0 @@ -schema A[a1 = 100, a2, a3]: - a: int = a1 - b: int = a2 - c: str = a3 - - -a = A(a1=1,a3="3") \ No newline at end of file diff --git a/test/test_units/test_kclvm/test_compiler/test_build/invalid_testdata/name_not_defined/main.k b/test/test_units/test_kclvm/test_compiler/test_build/invalid_testdata/name_not_defined/main.k deleted file mode 100644 index 453a53ca1..000000000 --- a/test/test_units/test_kclvm/test_compiler/test_build/invalid_testdata/name_not_defined/main.k +++ /dev/null @@ -1,2 +0,0 @@ -a = b -b = 1 diff --git a/test/test_units/test_kclvm/test_compiler/test_build/invalid_testdata/nest_import/main.k b/test/test_units/test_kclvm/test_compiler/test_build/invalid_testdata/nest_import/main.k deleted file mode 100644 index fd2b83aef..000000000 --- a/test/test_units/test_kclvm/test_compiler/test_build/invalid_testdata/nest_import/main.k +++ /dev/null @@ -1,5 +0,0 @@ -import module1 - -result0 = module1.module.data.num - -result1 = 100 diff --git a/test/test_units/test_kclvm/test_compiler/test_build/invalid_testdata/nest_import/module1.k b/test/test_units/test_kclvm/test_compiler/test_build/invalid_testdata/nest_import/module1.k deleted file mode 100644 index 92211e140..000000000 --- a/test/test_units/test_kclvm/test_compiler/test_build/invalid_testdata/nest_import/module1.k +++ /dev/null @@ -1 +0,0 @@ -import module diff --git a/test/test_units/test_kclvm/test_compiler/test_build/invalid_testdata/nest_import/module2.k b/test/test_units/test_kclvm/test_compiler/test_build/invalid_testdata/nest_import/module2.k deleted file mode 100644 index 92211e140..000000000 --- a/test/test_units/test_kclvm/test_compiler/test_build/invalid_testdata/nest_import/module2.k +++ /dev/null @@ -1 +0,0 @@ -import module diff --git a/test/test_units/test_kclvm/test_compiler/test_build/invalid_testdata/package_1.k b/test/test_units/test_kclvm/test_compiler/test_build/invalid_testdata/package_1.k deleted file mode 100644 index 3b2f8e656..000000000 --- a/test/test_units/test_kclvm/test_compiler/test_build/invalid_testdata/package_1.k +++ /dev/null @@ -1,3 +0,0 @@ -import pkg - -pkg.a |= 1 diff --git a/test/test_units/test_kclvm/test_compiler/test_build/invalid_testdata/package_2.k b/test/test_units/test_kclvm/test_compiler/test_build/invalid_testdata/package_2.k deleted file mode 100644 index 4fb05f3c3..000000000 --- a/test/test_units/test_kclvm/test_compiler/test_build/invalid_testdata/package_2.k +++ /dev/null @@ -1,3 +0,0 @@ -import pkg - -pkg.a = 1 diff --git a/test/test_units/test_kclvm/test_compiler/test_build/scope_testdata/main.k b/test/test_units/test_kclvm/test_compiler/test_build/scope_testdata/main.k deleted file mode 100644 index f381b4608..000000000 --- a/test/test_units/test_kclvm/test_compiler/test_build/scope_testdata/main.k +++ /dev/null @@ -1,7 +0,0 @@ -import pkg - -schema Sub(pkg.Base): - data?: int = 2 - -base: pkg.Base = pkg.Base {} as pkg.Base -sub: Sub = Sub {} as Sub diff --git a/test/test_units/test_kclvm/test_compiler/test_build/scope_testdata/pkg/pkg.k b/test/test_units/test_kclvm/test_compiler/test_build/scope_testdata/pkg/pkg.k deleted file mode 100644 index cb44e19e9..000000000 --- a/test/test_units/test_kclvm/test_compiler/test_build/scope_testdata/pkg/pkg.k +++ /dev/null @@ -1,2 +0,0 @@ -schema Base: - id?: int = 1 diff --git a/test/test_units/test_kclvm/test_compiler/test_build/scope_testdata/stdout.golden b/test/test_units/test_kclvm/test_compiler/test_build/scope_testdata/stdout.golden deleted file mode 100644 index ff2709378..000000000 --- a/test/test_units/test_kclvm/test_compiler/test_build/scope_testdata/stdout.golden +++ /dev/null @@ -1,5 +0,0 @@ -base: - id: 1 -sub: - id: 1 - data: 2 diff --git a/test/test_units/test_kclvm/test_compiler/test_build/test_build.py b/test/test_units/test_kclvm/test_compiler/test_build/test_build.py deleted file mode 100644 index 056b204dc..000000000 --- a/test/test_units/test_kclvm/test_compiler/test_build/test_build.py +++ /dev/null @@ -1,349 +0,0 @@ -# Copyright 2021 The KCL Authors. All rights reserved. - -import os -import shutil -import unittest -import pathlib - -import kclvm.api.object as objpkg -import kclvm.api.object.internal as obj_internal -import kclvm.kcl.ast as ast -import kclvm.kcl.types as types -import kclvm.compiler.vfs as vfs -from kclvm.kcl.error import KCLCompileException -from kclvm.kcl.error.kcl_error import IllegalArgumentSyntaxError -from kclvm.kcl.types import ProgramScope, Scope -from kclvm.compiler.parser import LoadProgram -from kclvm.compiler.build.compiler import RuntimeCode, CompileProgram, Compiler, SymbolScope -from kclvm.compiler.extension.builtin import get_builtin_func_objects -from kclvm.vm.code import Opcode, Label - -code_empty_list = ["""""", """"""] -code_simple_list = [ - """ -schema Person: - name: str - -a = 1 -""", - """ -b = a -person = Person { - name: "Alice" -} -""", -] -path = str(pathlib.Path(__file__).parent) - - -class KCLCompilerBuildTest(unittest.TestCase): - def test_runtime_code(self): - runtime_code = RuntimeCode( - names=[], - constants=[], - codes=[], - ) - self.assertEqual(runtime_code.type(), objpkg.KCLObjectType.RUNTIME_CODE) - self.assertEqual(runtime_code.type_str(), "runtime_code") - - def test_compile_program_empty(self): - compiled_program = CompileProgram(LoadProgram(path, k_code_list=code_empty_list)) - self.assertEqual(compiled_program.main, "__main__") - self.assertEqual(len(compiled_program.pkgs[compiled_program.main].names), 0) - self.assertEqual( - len(compiled_program.pkgs[compiled_program.main].constants), - len(get_builtin_func_objects()), - ) - - def test_compile_program_simple(self): - compiled_program = CompileProgram( - LoadProgram(path, k_code_list=code_simple_list) - ) - self.assertEqual(compiled_program.main, "__main__") - self.assertEqual(len(compiled_program.pkgs[compiled_program.main].names), 9) - - def test_compile_program_invalid(self): - testdata_path = pathlib.Path(__file__).parent.joinpath("invalid_testdata") - cases = testdata_path.glob("*.k") - for case in cases: - with self.assertRaises(KCLCompileException): - CompileProgram(LoadProgram(case, work_dir=str(testdata_path))) - - - def test_compile_program_invalid_nest_import(self): - testdata_path = pathlib.Path(__file__).parent.joinpath("invalid_testdata").joinpath("nest_import") - cases = testdata_path.glob("main.k") - for case in cases: - with self.assertRaises(KCLCompileException): - CompileProgram(LoadProgram(case, work_dir=str(testdata_path))) - - -class KCLCompilerWalkerFunctionTest(unittest.TestCase): - def setUp(self): - scope = ProgramScope(scope_map={"__main__": Scope()}) - self.fake_compiler = Compiler(scope) - self.fake_compiler.pkgpath = "__main__" - self.fake_compiler.pkg_scope = program_scope = types.ResolveProgram( - LoadProgram(path, k_code_list=code_simple_list) - ).main_scope - self.err_compiler = Compiler(scope) - self.err_compiler.scopes = None - super().setUp() - - def test_generic_compiler_functions(self): - # Expr - numberlit = ast.NumberLit(value=1) - # Stmt - exprstmt = ast.ExprStmt() - exprstmt.exprs = [numberlit] - # Module - module = ast.Module() - module.body = [exprstmt] - self.fake_compiler.generic_walk(module) - self.fake_compiler.generic_walk(exprstmt) - self.fake_compiler.generic_walk(numberlit) - self.fake_compiler.expr(None) - self.fake_compiler.stmt(None) - - def test_generic_compiler_functions_invalid(self): - with self.assertRaises(KCLCompileException): - self.fake_compiler.generic_walk(None) - with self.assertRaises(KCLCompileException): - self.fake_compiler.raise_err("Raise an error") - with self.assertRaises(KCLCompileException): - self.fake_compiler.change_operand(0, 100, 0) - with self.assertRaises(KCLCompileException): - self.err_compiler.leave_scope() - with self.assertRaises(KCLCompileException): - self.err_compiler.add_instruction([0]) - with self.assertRaises(Exception): - self.fake_compiler.make_func_with_content(None, None) - with self.assertRaises(AttributeError): - self.err_compiler.enter_scope() - - def test_emit_call_invalid(self): - keyword = ast.Keyword() - keyword.arg = ast.Identifier(names=["x"]) - keyword.value = ast.NumberLit(value=1) - keywords = [keyword, keyword] - with self.assertRaises(KCLCompileException): - self.fake_compiler.emit_call([], keywords) - - def test_set_jmp_invalid(self): - op, label = Opcode.NOP, Label() - with self.assertRaises(KCLCompileException): - self.fake_compiler.set_jmp(op, label) - - def test_op_decorator(self): - keyword = ast.Keyword() - keyword.arg = ast.Identifier(names=["x"]) - keyword.value = ast.NumberLit(value=1) - args = ast.CallExpr() - args.args = [] - args.keywords = [keyword] - cases = [ - { - "name": "Deprecated", - "key": "Person", - "args": None, - "target": obj_internal.DecoratorTargetType.SCHEMA_TYPE, - }, - { - "name": "Deprecated", - "key": "Person", - "args": args, - "target": obj_internal.DecoratorTargetType.SCHEMA_TYPE, - }, - ] - for case in cases: - name, key, args, target = case["name"], case["key"], case["args"], case["target"] - self.fake_compiler.op_decorator(name, key, args, target) - - def test_op_decorator_invalid(self): - keyword = ast.Keyword() - keyword.arg = ast.Identifier(names=["x"]) - keyword.value = ast.NumberLit(value=1) - args = ast.CallExpr() - args.args = [] - args.keywords = [keyword, keyword] - cases = [ - { - "name": "Deprecated", - "key": "Person", - "args": args, - "target": obj_internal.DecoratorTargetType.SCHEMA_TYPE, - }, - { - "name": None, - "key": "Person", - "args": args, - "target": obj_internal.DecoratorTargetType.SCHEMA_TYPE, - }, - ] - for case in cases: - name, key, args, target = case["name"], case["key"], case["args"], case["target"] - with self.assertRaises(KCLCompileException): - self.fake_compiler.op_decorator(name, key, args, target) - - def test_store_symbol(self): - self.fake_compiler.store_symbol("key") - with self.assertRaises(KCLCompileException): - self.fake_compiler.store_symbol("key") - self.fake_compiler.store_symbol("_key", scope=SymbolScope.INTERNAL) - self.fake_compiler.store_symbol("_key", scope=SymbolScope.INTERNAL) - - def test_load_symbol(self): - with self.assertRaises(KCLCompileException): - self.fake_compiler.load_symbol(None) - with self.assertRaises(KCLCompileException): - self.fake_compiler.load_symbol("_err_test_key") - - def test_walk_module(self): - module = ast.Module() - self.fake_compiler.walk_Module(module) - - def test_walk_expr_stmt(self): - expr_stmt = ast.ExprStmt() - expr_stmt.exprs = [ast.NumberLit(value=1)] - self.fake_compiler.walk_ExprStmt(expr_stmt) - self.fake_compiler._is_in_schema_stmt.append(True) - self.fake_compiler.walk_ExprStmt(expr_stmt) - self.fake_compiler._is_in_schema_stmt.pop() - - def test_walk_schema_stmt_invalid(self): - schema_stmt = ast.SchemaStmt() - schema_stmt.pkgpath = "__main__" - schema_stmt.name = "Person" - schema_stmt.decorators = [ast.Decorator()] - with self.assertRaises(AttributeError): - self.fake_compiler.walk_SchemaStmt(schema_stmt) - # Invalid schema mixin name - name = ast.Identifier(names=["pkg", "MixinError"]) - name.pkgpath = "@pkg" - schema_stmt.mixins = [name] - with self.assertRaises(KCLCompileException): - self.fake_compiler.walk_SchemaStmt(schema_stmt) - # Invalid schema parent name - schema_stmt.parent_name = ast.Identifier(names=["PersonMixin"]) - with self.assertRaises(KCLCompileException): - self.fake_compiler.walk_SchemaStmt(schema_stmt) - - def test_walk_schema_attr_invalid(self): - schema_attr = ast.SchemaAttr() - schema_attr.decorators = [ast.Decorator()] - with self.assertRaises(AttributeError): - self.fake_compiler.walk_SchemaAttr(schema_attr) - - def test_make_func_with_content_invalid_by_defaults(self): - file_path = str(pathlib.Path(__file__).parent.joinpath("invalid_testdata/defaults_not_full_invalid/main.k")) - try: - CompileProgram(LoadProgram(file_path)) - except IllegalArgumentSyntaxError as err: - self.assertEqual(err.arg_msg, "non-default argument follows default argument") - - def test_walk_index_signature_invalid(self): - with self.assertRaises(KCLCompileException): - t = ast.SchemaIndexSignature() - t.key_type = "err_str" - self.fake_compiler.walk_SchemaIndexSignature(t) - - def test_walk_unary_expr_invalid(self): - unary_expr = ast.UnaryExpr() - with self.assertRaises(KCLCompileException): - self.fake_compiler.walk_UnaryExpr(unary_expr) - - def test_walk_binary_expr(self): - bin_expr = ast.BinaryExpr() - bin_expr.left = ast.NumberLit(value=1) - bin_expr.right = ast.NumberLit(value=1) - bin_expr.op = ast.BinOp.Add - self.fake_compiler.walk_BinaryExpr(bin_expr) - bin_expr.op = ast.CmpOp.Eq - self.fake_compiler.walk_BinaryExpr(bin_expr) - bin_expr.op = ast.UnaryOp.Invert - with self.assertRaises(KCLCompileException): - self.fake_compiler.walk_BinaryExpr(bin_expr) - - def test_walk_selector_expr(self): - selector_expr = ast.SelectorExpr() - key = ast.Identifier(names=["selector_key"]) - key.ctx = ast.ExprContext.STORE - self.fake_compiler.walk_Identifier(key) - key.ctx = ast.ExprContext.LOAD - selector_expr.value = key - selector_expr.attr = ast.Identifier(names=["key"]) - selector_expr.ctx = ast.ExprContext.LOAD - self.fake_compiler.walk_SelectorExpr(selector_expr) - selector_expr.has_question = True - self.fake_compiler.walk_SelectorExpr(selector_expr) - selector_expr.ctx = ast.ExprContext.AUGLOAD - self.fake_compiler.walk_SelectorExpr(selector_expr) - selector_expr.ctx = ast.ExprContext.AUGSTORE - self.fake_compiler.walk_SelectorExpr(selector_expr) - - def test_walk_subscript(self): - subscript = ast.Subscript() - subscript.value = ast.StringLit(value="123") - subscript.index = ast.NumberLit(value=0) - subscript.has_question = True - self.fake_compiler.walk_Subscript(subscript) - - -class KCLCompilerProgramScopeTest(unittest.TestCase): - def test_get_type_from_identifier(self): - file_path = str(pathlib.Path(__file__).parent.joinpath("scope_testdata/main.k")) - scope = types.ResolveProgram( - LoadProgram(file_path) - ) - compiler = Compiler(scope) - self.assertIsInstance(compiler.get_type_from_identifier(None), objpkg.KCLAnyTypeObject) - identifier = ast.Identifier(names=["Sub"]) - self.assertIsInstance(compiler.get_type_from_identifier(identifier), objpkg.KCLSchemaDefTypeObject) - del compiler.pkg_scope.elems["Sub"] - self.assertIsInstance(compiler.get_type_from_identifier(identifier), objpkg.KCLAnyTypeObject) - identifier = ast.Identifier(names=["pkg", "Base"]) - self.assertIsInstance(compiler.get_type_from_identifier(identifier), objpkg.KCLAnyTypeObject) - identifier.pkgpath = "@pkg" - self.assertIsInstance(compiler.get_type_from_identifier(identifier), objpkg.KCLSchemaDefTypeObject) - compiler.pkg_scope.elems["@pkg"].type = None - self.assertIsInstance(compiler.get_type_from_identifier(identifier), objpkg.KCLAnyTypeObject) - with self.assertRaises(KCLCompileException): - compiler.get_type_from_identifier(ast.Identifier(names=["pkg", "to", "type"])) - - -class KCLCompilerBuildCacheTest(unittest.TestCase): - def test_compile_cache(self): - cache_path = str(pathlib.Path(__file__).parent.joinpath("cache_testdata/.kclvm/")) - file_path = str(pathlib.Path(__file__).parent.joinpath("cache_testdata/main.k")) - compiled_program = CompileProgram(LoadProgram(file_path)) - compiled_program = CompileProgram(LoadProgram(file_path)) - if os.path.exists(cache_path): - shutil.rmtree(cache_path) - - def test_compile_expired_cache(self): - test_data_path_name = "cache_expired_testdata" - rename_test_data_path = "rename_cache_expired_testdata" - root = str(pathlib.Path(__file__).parent.joinpath(test_data_path_name)) - cache_path = str(pathlib.Path(__file__).parent.joinpath(f"{test_data_path_name}/.kclvm/")) - file_path = str(pathlib.Path(__file__).parent.joinpath(f"{test_data_path_name}/main.k")) - rename_test_data_path = str(pathlib.Path(__file__).parent.joinpath(rename_test_data_path)) - ast_program = LoadProgram(file_path) - compiled_program = CompileProgram(ast_program) - cached_ast = vfs.LoadPkgCache(root, "pkg.pkg1") - cached_bytecode = vfs.LoadBytecodeCache(root, ast_program) - self.assertIsNotNone(cached_ast) - self.assertIsNotNone(cached_bytecode) - # Rename root to test cache expired - os.rename(root, rename_test_data_path) - cached_ast = vfs.LoadPkgCache(rename_test_data_path, "pkg.pkg1") - cached_bytecode = vfs.LoadBytecodeCache(rename_test_data_path, ast_program) - self.assertIsNotNone(cached_ast) - self.assertIsNotNone(cached_bytecode) - # Clear temp file - os.rename(rename_test_data_path, root) - if os.path.exists(cache_path): - shutil.rmtree(cache_path) - - -if __name__ == "__main__": - unittest.main(verbosity=2) diff --git a/test/test_units/test_kclvm/test_compiler/test_build/test_utils/test_units.py b/test/test_units/test_kclvm/test_compiler/test_build/test_utils/test_units.py deleted file mode 100644 index 7eb1497ae..000000000 --- a/test/test_units/test_kclvm/test_compiler/test_build/test_utils/test_units.py +++ /dev/null @@ -1,141 +0,0 @@ -import unittest -from kclvm.compiler.build.utils import units - - -class UnitsTest(unittest.TestCase): - - def test_cal_num_si(self) -> None: - """ - Test cal_num function with SI suffix - """ - cases = [ - {"value": 1, "suffix": "n", "expected": 1e-09}, - {"value": 1, "suffix": "u", "expected": 1e-06}, - {"value": 1, "suffix": "m", "expected": 0.001}, - {"value": 1, "suffix": "", "expected": 1}, - {"value": 1, "suffix": "k", "expected": 1_000}, - {"value": 1, "suffix": "K", "expected": 1_000}, - {"value": 1, "suffix": "M", "expected": 1_000_000}, - {"value": 1, "suffix": "G", "expected": 1_000_000_000}, - {"value": 1, "suffix": "T", "expected": 1_000_000_000_000}, - {"value": 1, "suffix": "P", "expected": 1_000_000_000_000_000}, - ] - - for case in cases: - real = units.cal_num(case["value"], case["suffix"]) - self.assertEqual(real, case["expected"]) - - def test_cal_num_iec(self) -> None: - """ - Test cal_num function with IEC suffix - """ - cases = [ - {"value": 1, "suffix": "Ki", "expected": 1024}, - {"value": 1, "suffix": "Mi", "expected": 1024 ** 2}, - {"value": 1, "suffix": "Gi", "expected": 1024 ** 3}, - {"value": 1, "suffix": "Ti", "expected": 1024 ** 4}, - {"value": 1, "suffix": "Pi", "expected": 1024 ** 5}, - ] - - for case in cases: - real = units.cal_num(case["value"], case["suffix"]) - self.assertEqual(real, case["expected"]) - - def test_cal_num_invalid_suffix(self) -> None: - """ - Test cal_num function with invalid suffix - """ - cases = [ - {"value": 1, "suffix": "x"}, - {"value": 1, "suffix": "ki"}, - {"value": 1, "suffix": "mi"}, - {"value": 1, "suffix": "ui"}, - {"value": 1, "suffix": "ni"}, - ] - - for case in cases: - exception = None - - try: - units.cal_num(case["value"], case["suffix"]) - except ValueError as e: - exception = e - self.assertEqual(str(e), f"Invalid suffix { case['suffix'] }") - - if not exception: - self.assertFalse(True, f"ValueError should be thrown, case: {case['suffix']}") - - def test_to_quantity_si(self) -> None: - """ - Test to_quantity function with SI suffix - """ - cases = [ - {"quantity": "1n", "expected": 1e-09}, - {"quantity": "1u", "expected": 1e-06}, - {"quantity": "1m", "expected": 0.001}, - {"quantity": "1", "expected": 1}, - {"quantity": "1k", "expected": 1_000}, - {"quantity": "1K", "expected": 1_000}, - {"quantity": "1M", "expected": 1_000_000}, - {"quantity": "1G", "expected": 1_000_000_000}, - {"quantity": "1T", "expected": 1_000_000_000_000}, - {"quantity": "1P", "expected": 1_000_000_000_000_000}, - ] - - for case in cases: - real = units.to_quantity(case["quantity"]) - self.assertEqual(real, case["expected"]) - - def test_to_quantity_iec(self) -> None: - """ - Test to_quantity function with SI suffix - """ - cases = [ - {"quantity": "1Ki", "expected": 1024}, - {"quantity": "1Mi", "expected": 1024 ** 2}, - {"quantity": "1Gi", "expected": 1024 ** 3}, - {"quantity": "1Ti", "expected": 1024 ** 4}, - {"quantity": "1Pi", "expected": 1024 ** 5}, - ] - - for case in cases: - real = units.to_quantity(case["quantity"]) - self.assertEqual(real, case["expected"]) - - def test_to_quantity_invalid_suffix(self) -> None: - """ - Test to_quantity function with invalid quantity - """ - cases = [ - {"quantity": "1x"}, - {"quantity": "1ki"}, - {"quantity": "1mi"}, - {"quantity": "1ui"}, - {"quantity": "1ni"}, - {"quantity": "1Kii"}, - {"quantity": "x"}, - ] - - for case in cases: - try: - units.to_quantity(case["quantity"]) - except ValueError as e: - self.assertEqual(str(e), "invalid literal for int() with base 10: '{}'".format(case["quantity"])) - - cases = [ - {"quantity": ""}, - {"quantity": "ki"}, - {"quantity": "mi"}, - {"quantity": "ui"}, - {"quantity": "ni"}, - ] - - for case in cases: - try: - units.to_quantity(case["quantity"]) - except ValueError as e: - self.assertEqual(str(e), "Number can't be empty") - - -if __name__ == "__main__": - unittest.main(verbosity=2) diff --git a/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/assert.yaml b/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/assert.yaml deleted file mode 100644 index 20ca90b92..000000000 --- a/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/assert.yaml +++ /dev/null @@ -1 +0,0 @@ -x: good case diff --git a/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/aug_assign.k b/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/aug_assign.k deleted file mode 100644 index 4120f37a1..000000000 --- a/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/aug_assign.k +++ /dev/null @@ -1,31 +0,0 @@ -schema Name: - first: str - last?: str - age?: int - -schema A: - name: Name - -schema Data: - _alice = A { - name: { - first: "aa" - age: 1 - } - } - - _alice.name |= {last: "value"} - _alice.name.age += 1 - alice = _alice - -data = Data {} -_alice = A { - name: { - first: "aa" - age: 1 - } -} - -_alice.name |= {last: "value"} -_alice.name.age += 1 -alice = _alice diff --git a/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/aug_assign.yaml b/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/aug_assign.yaml deleted file mode 100644 index 1c52b662c..000000000 --- a/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/aug_assign.yaml +++ /dev/null @@ -1,11 +0,0 @@ -data: - alice: - name: - first: aa - last: value - age: 2 -alice: - name: - first: aa - last: value - age: 2 diff --git a/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/calculation.yaml b/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/calculation.yaml deleted file mode 100644 index c1b56e73b..000000000 --- a/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/calculation.yaml +++ /dev/null @@ -1,25 +0,0 @@ -a: 2 -b: 0 -c: 1 -d: 1.0 -e: 1 -f: 0 -g: 0 -h: 2 -i: 1 -j: 1 -k: 1 -l: 1 -m: 1 -n: 0 -o: 0 -p: true -q: false -r: false -s: true -t: false -u: true -v: true -w: false -x: true -y: false diff --git a/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/collection_if.yaml b/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/collection_if.yaml deleted file mode 100644 index 3780384df..000000000 --- a/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/collection_if.yaml +++ /dev/null @@ -1,19 +0,0 @@ -env: env -data1: - name: env - env: env -data2: - name: name - env: name -data3: - key1: value1 -data4: -- value1 -data5: -- value1 -data6: - key: value1 -data7: -- 1 -data8: - k3: v3 diff --git a/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/compare.yaml b/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/compare.yaml deleted file mode 100644 index d43c311a2..000000000 --- a/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/compare.yaml +++ /dev/null @@ -1,2 +0,0 @@ -x0: true -x1: false diff --git a/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/complex.k b/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/complex.k deleted file mode 100644 index 7e2e32b06..000000000 --- a/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/complex.k +++ /dev/null @@ -1,42 +0,0 @@ -import math - -name = "Alice" -schema Base: - hc: int = 3 - key: str = name - -schema Person(Base): - name: str = "Alice" - age: int = 18 - labels: {str:str} = {"key": "value", "ageLabel": "ageVal " + str(age)} - info: [int|str] = [name, age] - -person1 = Person { - "name" = "Bob" - "age" = 16 -} -ceil_val = math.ceil(1.1) -a = 1.1 + 1.1 + 6.6 + 3.2 + abs(-1.2) -b = {"key1": "value1", "key2": "value2"} -attr = b.key1 + person1.name -c = 3 - 2 * 3 / 4 -d = a + 2 -e = a + 2 -f = "ABC" + "234{}" -p = "ABC"[::-1] -ff = f.format("123") -fff = ff.lower() -q = "1" * 12 -g = True -l = [1, 2, 3, attr + "value1"] -ll = [*l, 1] -_e = 1 + 1 -aug1 = aug2 = 4 + 3 -data = [1, 2, 3, 4] -lcomp = [_d * 2 for _d in data for _d in data] -dcomp = {dd: dd * 2 for dd in data} -data0 = data[0] -data12 = data[::-1] -pk = "ABC"[::-1] -qk = [1, 2, 3][::-1] -dict_data = {**person1, **{"key" = "value"}, "key2": "value2"} diff --git a/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/complex.yaml b/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/complex.yaml deleted file mode 100644 index d4f74014a..000000000 --- a/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/complex.yaml +++ /dev/null @@ -1,90 +0,0 @@ -name: Alice -person1: - hc: 3 - key: Bob - name: Bob - age: 16 - labels: - key: value - ageLabel: ageVal 16 - info: - - Bob - - 16 -ceil_val: 2 -a: 13.2 -b: - key1: value1 - key2: value2 -attr: value1Bob -c: 1.5 -d: 15.2 -e: 15.2 -f: ABC234{} -p: CBA -ff: ABC234123 -fff: abc234123 -q: '111111111111' -g: true -l: -- 1 -- 2 -- 3 -- value1Bobvalue1 -ll: -- 1 -- 2 -- 3 -- value1Bobvalue1 -- 1 -aug1: 7 -aug2: 7 -data: -- 1 -- 2 -- 3 -- 4 -lcomp: -- 2 -- 4 -- 6 -- 8 -- 2 -- 4 -- 6 -- 8 -- 2 -- 4 -- 6 -- 8 -- 2 -- 4 -- 6 -- 8 -dcomp: - 1: 2 - 2: 4 - 3: 6 - 4: 8 -data0: 1 -data12: -- 4 -- 3 -- 2 -- 1 -pk: CBA -qk: -- 3 -- 2 -- 1 -dict_data: - hc: 3 - key: value - name: Bob - age: 16 - labels: - key: value - ageLabel: ageVal 16 - info: - - Bob - - 16 - key2: value2 diff --git a/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/config.k b/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/config.k deleted file mode 100644 index 4cc6d7dc8..000000000 --- a/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/config.k +++ /dev/null @@ -1,18 +0,0 @@ -data = { - key1: [0] - key1 += [1] - key2: [0] - key2 = [1] - key3 = [0] - key3 = [1] -} - -schema Config: - data: [int] - env: [{str:}] = [{key1: 1}, {key2: 2}] - -config = Config { - data = [1] - data += [2] - env[0]: {key2: 2} -} diff --git a/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/config.yaml b/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/config.yaml deleted file mode 100644 index d3f9a6470..000000000 --- a/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/config.yaml +++ /dev/null @@ -1,16 +0,0 @@ -data: - key1: - - 0 - - 1 - key2: - - 1 - key3: - - 1 -config: - data: - - 1 - - 2 - env: - - key1: 1 - key2: 2 - - key2: 2 diff --git a/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/convert_collection_value.yaml b/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/convert_collection_value.yaml deleted file mode 100644 index a94581b2f..000000000 --- a/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/convert_collection_value.yaml +++ /dev/null @@ -1,6 +0,0 @@ -config: - nodes: - - name: node1 - - name: node2 - advancedConfig: - id: 1 diff --git a/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/emit_expr.k b/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/emit_expr.k deleted file mode 100644 index f1ad59941..000000000 --- a/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/emit_expr.k +++ /dev/null @@ -1,15 +0,0 @@ -schema Config: - __settings__: {str:str} = { - "output_type": "STANDALONE" - } - id?: int - value?: str - -Config { - id: 1 - value: "value1" -} -Config { - id: 2 - value: "value2" -} diff --git a/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/emit_expr.yaml b/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/emit_expr.yaml deleted file mode 100644 index 762bd5387..000000000 --- a/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/emit_expr.yaml +++ /dev/null @@ -1,5 +0,0 @@ -id: 1 -value: value1 ---- -id: 2 -value: value2 diff --git a/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/expr.k b/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/expr.k deleted file mode 100644 index c91f75ccb..000000000 --- a/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/expr.k +++ /dev/null @@ -1,14 +0,0 @@ -a = 1 -b = 2.2 -c = True -d = "ABC" -e = 'cba' -f = [1, 2, 3] -1 -2.2e3 -False -None -Undefined -"""123""" -myDict = {"key": "value"} -myDictNew = {**myDict, "key" = Undefined} diff --git a/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/expr.yaml b/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/expr.yaml deleted file mode 100644 index d2f330827..000000000 --- a/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/expr.yaml +++ /dev/null @@ -1,12 +0,0 @@ -a: 1 -b: 2.2 -c: true -d: ABC -e: cba -f: -- 1 -- 2 -- 3 -myDict: - key: value -myDictNew: {} diff --git a/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/for.yaml b/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/for.yaml deleted file mode 100644 index a733b7306..000000000 --- a/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/for.yaml +++ /dev/null @@ -1,19 +0,0 @@ -x0: -- 2 -- 3 -x1: -- 2 -- 2 -- 3 -x2: -- 1 -- 3 -- 5 -x3: - key1: key1 - key2: key2 -x4: - key1: key1 -x5: - key1: value1 - key2: value2 diff --git a/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/if.yaml b/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/if.yaml deleted file mode 100644 index e750014d1..000000000 --- a/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/if.yaml +++ /dev/null @@ -1,4 +0,0 @@ -a: 1 -b: 3 -c: 4 -ok: 2 diff --git a/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/index_signature.yaml b/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/index_signature.yaml deleted file mode 100644 index 72dc0ed60..000000000 --- a/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/index_signature.yaml +++ /dev/null @@ -1,3 +0,0 @@ -data: - key1: '1' - key2: '2' diff --git a/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/lambda.k b/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/lambda.k deleted file mode 100644 index 640b945c2..000000000 --- a/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/lambda.k +++ /dev/null @@ -1,36 +0,0 @@ -sumFunc1 = lambda x, y { - x + y -} -sumFunc2 = lambda x, y = 1 { - x + y -} -sumFunc3 = lambda x = 1, y: int = 1 { - x + y -} -sumFunc4 = lambda x: int = 1, y: int = 1 -> int { - x + y -} -x0 = sumFunc1(1, 2) -x1 = sumFunc1(2, 3) -x2 = sumFunc1(3, 4) -x3 = sumFunc1(4, 5) - -schema Data: - var: int = 1 - _func = lambda x: int | str, y: int | str { - (lambda x, y { - int(x) + int(y) + var - })(x, y) - } - - a = _func(1, 1) - b = _func("123", "456") - -data = Data() - -result = (lambda x: int, y: int -> int { - a = 1 - (lambda { - x + y + a + 1 - })() -})(1, 1) diff --git a/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/lambda.yaml b/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/lambda.yaml deleted file mode 100644 index 036eadb05..000000000 --- a/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/lambda.yaml +++ /dev/null @@ -1,9 +0,0 @@ -x0: 3 -x1: 5 -x2: 7 -x3: 9 -data: - var: 1 - a: 3 - b: 580 -result: 4 diff --git a/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/line_continue.k b/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/line_continue.k deleted file mode 100644 index b7d5379f9..000000000 --- a/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/line_continue.k +++ /dev/null @@ -1 +0,0 @@ -\ \ No newline at end of file diff --git a/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/list.k b/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/list.k deleted file mode 100644 index 07b0eeb1a..000000000 --- a/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/list.k +++ /dev/null @@ -1,12 +0,0 @@ -schema Data: - __settings__: {str:} = { - "output_type": "STANDALONE" - } - id?: int - name: str - -x0 = [[{a: 1, b: Undefined}]] -x1 = [[[{a: 1, b: Undefined}]]] -x2 = [[{a: 1, b: None}]] -x3 = [[[{a: 1, b: None}]]] -x4 = [[[1, Data { name = "data" }]]] diff --git a/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/list.yaml b/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/list.yaml deleted file mode 100644 index 067a879c4..000000000 --- a/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/list.yaml +++ /dev/null @@ -1,14 +0,0 @@ -x0: -- - a: 1 -x1: -- - - a: 1 -x2: -- - a: 1 - b: null -x3: -- - - a: 1 - b: null -x4: -- - - 1 ---- -name: data diff --git a/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/member_ship.yaml b/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/member_ship.yaml deleted file mode 100644 index b2407e839..000000000 --- a/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/member_ship.yaml +++ /dev/null @@ -1,4 +0,0 @@ -result1: true -result2: false -result3: false -result4: true diff --git a/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/nest_var.yaml b/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/nest_var.yaml deleted file mode 100644 index d6b3d6e45..000000000 --- a/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/nest_var.yaml +++ /dev/null @@ -1,14 +0,0 @@ -a: - k1: - k2: - k3: 1 -b: - k1: - k2: - k3: - k4: 2 -c: - k1: - k2: - k3: - k4: 3 diff --git a/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/plugin.k b/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/plugin.k deleted file mode 100644 index 3257efaaa..000000000 --- a/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/plugin.k +++ /dev/null @@ -1,3 +0,0 @@ -import kcl_plugin.hello - -x = hello.add(1, 1) diff --git a/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/plus.yaml b/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/plus.yaml deleted file mode 100644 index 51667d2c2..000000000 --- a/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/plus.yaml +++ /dev/null @@ -1,8 +0,0 @@ -persons: -- name: Alice - count: 18 -- name: Alice - count: 18 -- name: Alice - count: 18 -data: '123456789' diff --git a/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/quant_expr.yaml b/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/quant_expr.yaml deleted file mode 100644 index ed01ebb33..000000000 --- a/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/quant_expr.yaml +++ /dev/null @@ -1,17 +0,0 @@ -x0: -- 3 -- 4 -x1: -- 1 -x2: false -x3: true -x4: -- name: '2' - value: 2 -x5: -- name: '1' - value: 1 -x6: - a: foo -x7: - a: foo diff --git a/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/regex.yaml b/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/regex.yaml deleted file mode 100644 index 854c9927a..000000000 --- a/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/regex.yaml +++ /dev/null @@ -1,2 +0,0 @@ -data: - name: name diff --git a/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/rule.k b/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/rule.k deleted file mode 100644 index 2822d2e80..000000000 --- a/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/rule.k +++ /dev/null @@ -1,15 +0,0 @@ -age = 1 - -@deprecated -rule DeprecatedRule: - age == 0 - -schema RuleProtocol: - age: int - -rule Base: - age > 0 - -rule Main(Base) for RuleProtocol: - -Main {} diff --git a/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/rule.yaml b/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/rule.yaml deleted file mode 100644 index 059b61de3..000000000 --- a/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/rule.yaml +++ /dev/null @@ -1 +0,0 @@ -age: 1 diff --git a/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/schema.yaml b/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/schema.yaml deleted file mode 100644 index c7fd865cd..000000000 --- a/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/schema.yaml +++ /dev/null @@ -1,40 +0,0 @@ -name: Alice -person1: - hc: 3 - key: Bob - name: Bob - age: 16 - labels: - key: value - ageLabel: ageVal 16 - info: - - Bob - - 16 -person2: - hc: 3 - key: Alice - name: Alice - age: 18 - labels: - key: value - ageLabel: ageVal 18 - info: - - Alice - - 18 -person3: - hc: 3 - key: Alice - name: Alice - age: 18 - labels: - key: value - ageLabel: ageVal 18 - info: - - Alice - - 18 -info: - name: alice - age: 10 - info: - gender: girl - age: 10 diff --git a/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/schema_args.yaml b/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/schema_args.yaml deleted file mode 100644 index da5ff0d10..000000000 --- a/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/schema_args.yaml +++ /dev/null @@ -1,15 +0,0 @@ -data0: - id1: 1 - id2: 2 -data1: - id1: 1 - id2: 2 -data2: - id1: 1 - id2: 2 -data3: - id1: 1 - id2: 2 -data4: - id1: 1 - id2: 2 diff --git a/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/str.yaml b/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/str.yaml deleted file mode 100644 index 880991697..000000000 --- a/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/str.yaml +++ /dev/null @@ -1,4 +0,0 @@ -hello: Hello -world: World -hello_world: Hello World -hello_world_2: Hello World Hello World diff --git a/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/type_alias.yaml b/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/type_alias.yaml deleted file mode 100644 index 360f83507..000000000 --- a/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/type_alias.yaml +++ /dev/null @@ -1,9 +0,0 @@ -colorRed: Red -colorYellow: Yellow -colorBlue: Blue -dataColorRed: - color: Red -dataColorYellow: - color: Yellow -dataColorBlue: - color: Blue diff --git a/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/type_as.yaml b/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/type_as.yaml deleted file mode 100644 index d4ce11259..000000000 --- a/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/type_as.yaml +++ /dev/null @@ -1,10 +0,0 @@ -a: 1 -b: 2.0 -c: true -d: s -e: -- 1 -f: - key: value -g: - id: 1 diff --git a/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/types.yaml b/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/types.yaml deleted file mode 100644 index 4658fc41d..000000000 --- a/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/types.yaml +++ /dev/null @@ -1,6 +0,0 @@ -person: - name: Alice - count: 1 -personOther: - name: Alice - count: 1 diff --git a/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/unary.yaml b/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/unary.yaml deleted file mode 100644 index 6bd4f4ab0..000000000 --- a/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/unary.yaml +++ /dev/null @@ -1,4 +0,0 @@ -a: -1 -b: 1 -c: true -d: -2 diff --git a/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/unification.yaml b/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/unification.yaml deleted file mode 100644 index 4518f66ce..000000000 --- a/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/unification.yaml +++ /dev/null @@ -1,5 +0,0 @@ -config: - data: 2 -data: - config: - data: 1 diff --git a/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/unification_with_mixin.yaml b/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/unification_with_mixin.yaml deleted file mode 100644 index af11fa75a..000000000 --- a/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/unification_with_mixin.yaml +++ /dev/null @@ -1,8 +0,0 @@ -data: - person: - name: Alice - age: 1 - info: - key1: value1 - key2: value2 - key3: value3 diff --git a/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/units.yaml b/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/units.yaml deleted file mode 100644 index 0bacc4908..000000000 --- a/test/test_units/test_kclvm/test_compiler/test_eval/eval_data/units.yaml +++ /dev/null @@ -1,22 +0,0 @@ -x0: 1000000 -x1: 1000000 -x2: 1000000 -x3: 1000000.0 -x4: 1000000 -x5: 1000000 -x6: 1024 -x7: 1024 -x8: 1000000 -x0str: 1M -x1str: 1M -x2str: '1000000' -x3str: '1000000.0' -x4str: 1M -x5str: 1M -x6str: 1Ki -x7str: '{"k": "1Ki"}' -data: - x0: 1048576 - x1: 1024 - x2: 1024 - x3: 1024 diff --git a/test/test_units/test_kclvm/test_compiler/test_eval/invalid_eval_data/list_schema_match.k b/test/test_units/test_kclvm/test_compiler/test_eval/invalid_eval_data/list_schema_match.k deleted file mode 100644 index 87554aa93..000000000 --- a/test/test_units/test_kclvm/test_compiler/test_eval/invalid_eval_data/list_schema_match.k +++ /dev/null @@ -1,17 +0,0 @@ -schema Data: - field: Field - -schema Field: - id?: int - -schema Config: - data0: Data = { - field: { - id: 1 - } - } - data1: Data = { - field: [] - } - -x0 = Config {} diff --git a/test/test_units/test_kclvm/test_compiler/test_eval/invalid_eval_data/mixin_not_defined.k b/test/test_units/test_kclvm/test_compiler/test_eval/invalid_eval_data/mixin_not_defined.k deleted file mode 100644 index 8ce933d74..000000000 --- a/test/test_units/test_kclvm/test_compiler/test_eval/invalid_eval_data/mixin_not_defined.k +++ /dev/null @@ -1,4 +0,0 @@ -schema Person: - mixin [PersonMixin] - -person = Person {} diff --git a/test/test_units/test_kclvm/test_compiler/test_eval/invalid_eval_data/name_not_defined.k b/test/test_units/test_kclvm/test_compiler/test_eval/invalid_eval_data/name_not_defined.k deleted file mode 100644 index 86e9f1b69..000000000 --- a/test/test_units/test_kclvm/test_compiler/test_eval/invalid_eval_data/name_not_defined.k +++ /dev/null @@ -1,8 +0,0 @@ -schema GetData: - result: str = name - -schema Person: - name: str = "kcl" - result: GetData = GetData {} - -x0 = Person {} diff --git a/test/test_units/test_kclvm/test_compiler/test_eval/test_eval.py b/test/test_units/test_kclvm/test_compiler/test_eval/test_eval.py deleted file mode 100644 index d21eff3d8..000000000 --- a/test/test_units/test_kclvm/test_compiler/test_eval/test_eval.py +++ /dev/null @@ -1,98 +0,0 @@ -# Copyright 2021 The KCL Authors. All rights reserved. - -import unittest -import pathlib -from typing import Tuple - -import kclvm.api.object as kcl_object -import kclvm.kcl.error as kcl_error -from kclvm.program.eval import EvalCode -from kclvm.vm.code import Opcode -from kclvm.vm.runtime.evaluator.eval import Evaluator - -_FILE_INPUT_SUFFIX = ".k" -_FILE_OUTPUT_SUFFIX = ".yaml" -_PATH_NAME = "eval_data" -_DIR_PATH = pathlib.Path(__file__).parent.joinpath(_PATH_NAME) -_TEST_CASES = [ - "assert", - "aug_assign", - "calculation", - "collection_if", - "compare", - "convert_collection_value", - "config", - "emit_expr", - "empty", - "expr", - "quant_expr", - "regex", - "rule", - "schema_args", - "schema", - "type_alias", - "type_as", - "str", - "types", - "complex", - "for", - "if", - "index_signature", - "lambda", - "member_ship", - "nest_var", - "plugin", - "plus", - "line_continue", - "list", - "unary", - "unification_with_mixin", - "unification", - "units", -] - - -class KCLBaseEvaluatorTest(unittest.TestCase): - """ - KCL base Evaluator test - """ - - def read_data(self, data_name: str) -> Tuple[str, str]: - """ - Read format data according to data name - """ - input_filename = data_name + _FILE_INPUT_SUFFIX - output_filename = data_name + _FILE_OUTPUT_SUFFIX - data_input = (_DIR_PATH / input_filename).read_text() - data_output = (_DIR_PATH / output_filename).read_text() - return data_input, data_output - - -class KCLEvaluatorTest(KCLBaseEvaluatorTest): - def test_Evaluator_eval_binary_op(self): - kcl_eval = Evaluator() - self.assertEqual(kcl_object.KCLIntObject(value=11), - kcl_eval.eval_binary_op(left=kcl_object.KCLIntObject(value=10), - right=kcl_object.KCLIntObject(value=11), - code=Opcode.BINARY_OR)) - - def test_eval_data(self) -> None: - """ - Test format data for the comparison of input and golden files - """ - self.maxDiff = None - for case in _TEST_CASES: - try: - input_code, output = self.read_data(case) - self.assertEqual(EvalCode(filename=case+".k", code=input_code), output, msg=f"the case is {case}") - except Exception as err: - print(f"case {case} raise an error: {err}") - - def test_invalid_eval_data(self): - for p in pathlib.Path(__file__).parent.joinpath("invalid_eval_data").glob("*.k"): - with self.assertRaises(kcl_error.KCLException): - EvalCode(filename=str(p)) - - -if __name__ == "__main__": - unittest.main(verbosity=2) diff --git a/test/test_units/test_kclvm/test_compiler/test_extension/test_builtin/test_builtin.py b/test/test_units/test_kclvm/test_compiler/test_extension/test_builtin/test_builtin.py deleted file mode 100644 index e742bd9d6..000000000 --- a/test/test_units/test_kclvm/test_compiler/test_extension/test_builtin/test_builtin.py +++ /dev/null @@ -1,16 +0,0 @@ -# Copyright 2020 The KCL Authors. All rights reserved. - -import unittest - -import kclvm.compiler.extension.builtin.builtin as builtin - - -class TestBuiltinFcuntion(unittest.TestCase): - def test_list(self): - self.assertEqual(builtin.KMANGLED_list(), []) - self.assertEqual(builtin.KMANGLED_list([0]), [0]) - self.assertEqual(builtin.KMANGLED_list({"k": "v"}), ["k"]) - - -if __name__ == "__main__": - unittest.main(verbosity=2) diff --git a/test/test_units/test_kclvm/test_compiler/test_extension/test_builtin/test_net.py b/test/test_units/test_kclvm/test_compiler/test_extension/test_builtin/test_net.py deleted file mode 100644 index 629368331..000000000 --- a/test/test_units/test_kclvm/test_compiler/test_extension/test_builtin/test_net.py +++ /dev/null @@ -1,100 +0,0 @@ -# Copyright 2020 The KCL Authors. All rights reserved. - -import unittest - -import kclvm.compiler.extension.builtin.system_module.net as net - - -class TestNetSystemModule(unittest.TestCase): - def test_host_port(self): - - self.assertEqual( - net.KMANGLED_split_host_port("B-K0NZJGH6-0048.local:80"), - ["B-K0NZJGH6-0048.local", "80"], - ) - self.assertEqual( - net.KMANGLED_join_host_port("B-K0NZJGH6-0048.local", 80), - "B-K0NZJGH6-0048.local:80", - ) - - def test_is_ip(self): - cases = [ - # False cases - {"value": "192.168.0,1", "expected": False}, - {"value": "192.168.0.", "expected": False}, - {"value": "192.168.", "expected": False}, - {"value": "192.", "expected": False}, - {"value": "", "expected": False}, - {"value": "256.168.0,1", "expected": False}, - {"value": "255.255.0.-1", "expected": False}, - {"value": "192.0022.1.1", "expected": False}, - {"value": "492.10.123.12313", "expected": False}, - {"value": "0xFF.0xFF.0xFF.0xFF", "expected": False}, - {"value": "2001:0db8:3c4d:0015+0000:0000:1a2f:1a2b", "expected": False}, - # True cases - {"value": "255.255.0.1", "expected": True}, - {"value": "1.0.0.0", "expected": True}, - {"value": "192.190.0.1", "expected": True}, - {"value": "128.0.0.0", "expected": True}, - {"value": "172.16.0.0", "expected": True}, - {"value": "172.31.255.255", "expected": True}, - {"value": "169.254.0.1", "expected": True}, - {"value": "191.255.255.255", "expected": True}, - {"value": "223.255.255.0", "expected": True}, - {"value": "2001:0db8:3c4d:0015:0000:0000:1a2f:1a2b", "expected": True}, - ] - for case in cases: - value, expected = case["value"], case["expected"] - self.assertEqual(net.KMANGLED_is_IP(value), expected) - - def test_is_multicast_IP(self): - cases = [ - {"value": "239.255.255.255", "expected": True}, - ] - for case in cases: - value, expected = case["value"], case["expected"] - self.assertEqual(net.KMANGLED_is_multicast_IP(value), expected) - - def test_is_loopback_IP(self): - cases = [ - {"value": "127.0.0.1", "expected": True}, - ] - for case in cases: - value, expected = case["value"], case["expected"] - self.assertEqual(net.KMANGLED_is_loopback_IP(value), expected) - - def test_is_link_local_multicast_IP(self): - cases = [ - {"value": "224.0.0.0", "expected": False}, - ] - for case in cases: - value, expected = case["value"], case["expected"] - self.assertEqual(net.KMANGLED_is_link_local_multicast_IP(value), expected) - - def test_is_link_local_unicast_IP(self): - cases = [ - {"value": "fe80::2012:1", "expected": True}, - ] - for case in cases: - value, expected = case["value"], case["expected"] - self.assertEqual(net.KMANGLED_is_link_local_unicast_IP(value), expected) - - def test_is_global_unicast_IP(self): - cases = [ - {"value": "220.181.108.89", "expected": True}, - ] - for case in cases: - value, expected = case["value"], case["expected"] - self.assertEqual(net.KMANGLED_is_global_unicast_IP(value), expected) - - def test_is_unspecified_IP(self): - cases = [ - {"value": "0.0.0.0", "expected": True}, - ] - for case in cases: - value, expected = case["value"], case["expected"] - self.assertEqual(net.KMANGLED_is_unspecified_IP(value), expected) - - -if __name__ == "__main__": - unittest.main(verbosity=2) diff --git a/test/test_units/test_kclvm/test_compiler/test_extension/test_builtin/test_units.py b/test/test_units/test_kclvm/test_compiler/test_extension/test_builtin/test_units.py deleted file mode 100644 index acbfc4ab3..000000000 --- a/test/test_units/test_kclvm/test_compiler/test_extension/test_builtin/test_units.py +++ /dev/null @@ -1,21 +0,0 @@ -# Copyright 2020 The KCL Authors. All rights reserved. - -import unittest - -import kclvm.compiler.extension.builtin.system_module.units as units - - -class TestUnitsSystemModule(unittest.TestCase): - def test_to_unit(self): - cases = [ - {"num": 1e9, "suffix": "G", "expected": "1G"}, - {"num": 1e10, "suffix": "G", "expected": "10G"}, - {"num": 1e9, "suffix": "M", "expected": "1000M"}, - ] - for case in cases: - num, suffix, expected = case["num"], case["suffix"], case["expected"] - self.assertEqual(units.to_unit(num, suffix), expected) - - -if __name__ == "__main__": - unittest.main(verbosity=2) diff --git a/test/test_units/test_kclvm/test_compiler/test_extension/test_builtin/test_yaml.py b/test/test_units/test_kclvm/test_compiler/test_extension/test_builtin/test_yaml.py deleted file mode 100644 index 59c31e539..000000000 --- a/test/test_units/test_kclvm/test_compiler/test_extension/test_builtin/test_yaml.py +++ /dev/null @@ -1,242 +0,0 @@ -# Copyright 2020 The KCL Authors. All rights reserved. - -import unittest - -import kclvm.compiler.extension.builtin.system_module.yaml as yaml - - -class TestYAMLSystemModule(unittest.TestCase): - def test_decode(self): - yamlStrList = [ - "key: value", - "- 1\n- 2\n- 3", - "1", - "1.1", - "null", - "true", - ] - expected = [ - {"key": "value"}, - [1, 2, 3], - 1, - 1.1, - None, - True, - ] - data = [yaml.KMANGLED_decode(s) for s in yamlStrList] - self.assertListEqual(data, expected) - - def test_encode_literal(self): - dataDict = {"key": "value"} - dataList = [1, 2, 3] - dataInt = 1 - dataFloat = 1.1 - dataNone = None - dataBool = True - expected = [ - "key: value\n", - "- 1\n- 2\n- 3\n", - "1\n...\n", - "1.1\n...\n", - "null\n...\n", - "true\n...\n", - ] - yamlStr = [ - yaml.KMANGLED_encode(data) - for data in [dataDict, dataList, dataInt, dataFloat, dataNone, dataBool] - ] - self.assertEqual(yamlStr, expected) - - def test_encode_dict(self): - cases = [ - { - "value": { - "key1": "value1", - "key2": "value2", - "data": [1, 2, 3], - }, - "expected": """\ -key1: value1 -key2: value2 -data: -- 1 -- 2 -- 3 -""", - }, - { - "value": { - "key1": {"key1": "value1", "key2": "value2"}, - "key2": "value2", - "data": [1, 2, 3], - }, - "expected": """\ -key1: - key1: value1 - key2: value2 -key2: value2 -data: -- 1 -- 2 -- 3 -""", - }, - ] - for case in cases: - value, expected = case["value"], case["expected"] - self.assertEqual(yaml.KMANGLED_encode(value), expected) - - def test_encode_dict(self): - cases = [ - { - "value": { - "key1": "value1", - "key2": "value2", - "data": [1, 2, 3], - }, - "expected": """\ -key1: value1 -key2: value2 -data: -- 1 -- 2 -- 3 -""", - }, - { - "value": { - "key1": {"key1": "value1", "key2": "value2"}, - "key2": "value2", - "data": [1, 2, 3], - }, - "expected": """\ -key1: - key1: value1 - key2: value2 -key2: value2 -data: -- 1 -- 2 -- 3 -""", - }, - ] - for case in cases: - value, expected = case["value"], case["expected"] - self.assertEqual(yaml.KMANGLED_encode(value), expected) - - def test_encode_with_ignore_none(self): - cases = [ - { - "value": { - "key1": None, - "key2": "value2", - "data": [1, 2, 3], - }, - "expected": """\ -key2: value2 -data: -- 1 -- 2 -- 3 -""", - }, - { - "value": { - "key1": {"key1": "value1", "key2": "value2"}, - "key2": None, - "data": [1, 2, 3], - }, - "expected": """\ -key1: - key1: value1 - key2: value2 -data: -- 1 -- 2 -- 3 -""", - }, - ] - for case in cases: - value, expected = case["value"], case["expected"] - self.assertEqual(yaml.KMANGLED_encode(value, ignore_none=True), expected) - - def test_encode_with_ignore_private(self): - cases = [ - { - "value": { - "_key1": "value1", - "key2": "value2", - "data": [1, 2, 3], - }, - "expected": """\ -key2: value2 -data: -- 1 -- 2 -- 3 -""", - }, - { - "value": { - "key1": {"key1": "value1", "key2": "value2"}, - "_key2": "value2", - "data": [1, 2, 3], - }, - "expected": """\ -key1: - key1: value1 - key2: value2 -data: -- 1 -- 2 -- 3 -""", - }, - ] - for case in cases: - value, expected = case["value"], case["expected"] - self.assertEqual(yaml.KMANGLED_encode(value, ignore_private=True), expected) - - def test_encode_with_sort_keys(self): - cases = [ - { - "value": { - "key1": "value1", - "key2": "value2", - "data": [1, 2, 3], - }, - "expected": """\ -data: -- 1 -- 2 -- 3 -key1: value1 -key2: value2 -""", - }, - { - "value": { - "key1": {"key1": "value1", "key2": "value2"}, - "key2": "value2", - "data": [1, 2, 3], - }, - "expected": """\ -data: -- 1 -- 2 -- 3 -key1: - key1: value1 - key2: value2 -key2: value2 -""", - }, - ] - for case in cases: - value, expected = case["value"], case["expected"] - self.assertEqual(yaml.KMANGLED_encode(value, sort_keys=True), expected) - -if __name__ == "__main__": - unittest.main(verbosity=2) diff --git a/test/test_units/test_kclvm/test_compiler/test_preprocess/test_preprocess.py b/test/test_units/test_kclvm/test_compiler/test_preprocess/test_preprocess.py deleted file mode 100644 index 9b181c788..000000000 --- a/test/test_units/test_kclvm/test_compiler/test_preprocess/test_preprocess.py +++ /dev/null @@ -1,85 +0,0 @@ -# Copyright 2021 The KCL Authors. All rights reserved. - -import unittest -from typing import cast - -import kclvm.kcl.ast as ast -from kclvm.compiler.parser import ParseFile -from kclvm.compiler.build.preprocess import fix_identifier_prefix - - -simple_case = """ -schema $all: - data?: int - -schema $filter($all): - $name: str - -$map = $filter { - name: "Data" -} -""" - -if_case = """ -schema Data: - if False: - $name = "1" - elif True: - $name = "2" - else: - $name = "3" -""" - -import_case = """ -import $import.$all as $all -""" - - -class CompilerPreprocessTest(unittest.TestCase): - def test_fix_identifier_prefix_invalid_case(self): - self.assertEqual(fix_identifier_prefix(None), None) - - def test_fix_identifier_prefix_simple_case(self): - module = ParseFile("", code=simple_case) - module = cast(ast.Module, fix_identifier_prefix(module)) - self.assertEqual(len(module.body), 3) - schema_stmt_all: ast.SchemaStmt = cast(ast.SchemaStmt, module.body[0]) - schema_stmt_filter: ast.SchemaStmt = cast(ast.SchemaStmt, module.body[1]) - assign_stmt: ast.AssignStmt = cast(ast.AssignStmt, module.body[2]) - self.assertEqual(schema_stmt_all.name, "all") - self.assertEqual(schema_stmt_filter.name, "filter") - self.assertEqual(schema_stmt_filter.parent_name.get_name(), "all") - self.assertEqual(schema_stmt_filter.body[0].name, "name") - self.assertEqual(assign_stmt.value.name.get_name(), "filter") - - def test_fix_identifier_prefix_if_case(self): - module = ParseFile("", code=if_case) - module = cast(ast.Module, fix_identifier_prefix(module)) - self.assertEqual(len(module.body), 1) - schema_stmt: ast.SchemaStmt = cast(ast.SchemaStmt, module.body[0]) - self.assertEqual(len(schema_stmt.body), 1) - if_stmt: ast.IfStmt = cast(ast.IfStmt, schema_stmt.body[0]) - self.assertEqual(if_stmt.body[0].targets[0].get_name(), "name") - self.assertEqual(if_stmt.body[0].value.value, "1") - self.assertEqual(if_stmt.elif_body[0][0].targets[0].get_name(), "name") - self.assertEqual(if_stmt.elif_body[0][0].value.value, "2") - self.assertEqual(if_stmt.else_body[0].targets[0].get_name(), "name") - self.assertEqual(if_stmt.else_body[0].value.value, "3") - - def test_fix_identifier_prefix_import_case(self): - module = ParseFile("", code=import_case) - module = cast(ast.Module, fix_identifier_prefix(module)) - self.assertEqual(len(module.body), 1) - import_stmt: ast.ImportStmt = cast(ast.ImportStmt, module.body[0]) - self.assertEqual(import_stmt.asname, "all") - self.assertEqual(import_stmt.name, "all") - self.assertEqual(import_stmt.pkg_name, "all") - self.assertEqual(import_stmt.path, "import.all") - self.assertEqual(len(import_stmt.path_nodes), 2) - self.assertEqual(import_stmt.path_nodes[0].value, "import") - self.assertEqual(import_stmt.path_nodes[1].value, "all") - - - -if __name__ == "__main__": - unittest.main(verbosity=2) diff --git a/test/test_units/test_kclvm/test_compiler/test_vfs/kcl.mod b/test/test_units/test_kclvm/test_compiler/test_vfs/kcl.mod deleted file mode 100644 index b8356d10c..000000000 --- a/test/test_units/test_kclvm/test_compiler/test_vfs/kcl.mod +++ /dev/null @@ -1,2 +0,0 @@ -[build] -enable_pkg_cache=true diff --git a/test/test_units/test_kclvm/test_compiler/test_vfs/test_data_bytecode_cache/kcl.mod b/test/test_units/test_kclvm/test_compiler/test_vfs/test_data_bytecode_cache/kcl.mod deleted file mode 100644 index f4e7091a3..000000000 --- a/test/test_units/test_kclvm/test_compiler/test_vfs/test_data_bytecode_cache/kcl.mod +++ /dev/null @@ -1,3 +0,0 @@ -[build] -enable_pkg_cache=true -cached_pkg_prefix="pkg." diff --git a/test/test_units/test_kclvm/test_compiler/test_vfs/test_vfs.py b/test/test_units/test_kclvm/test_compiler/test_vfs/test_vfs.py deleted file mode 100644 index bec902f16..000000000 --- a/test/test_units/test_kclvm/test_compiler/test_vfs/test_vfs.py +++ /dev/null @@ -1,303 +0,0 @@ -# Copyright 2020 The KCL Authors. All rights reserved. - -import os -import pathlib -import unittest -import shutil - -import kclvm.api.object as obj -import kclvm.kcl.ast as ast -import kclvm.compiler.vfs.vfs as vfs -import kclvm.compiler.parser as parser -import kclvm.compiler.build.compiler as compiler - - -class TestVfsLoadPkgCache(unittest.TestCase): - def test_invalid_parameters(self): - self.assertEqual(vfs.LoadPkgCache(None, None), None) - self.assertEqual(vfs.LoadPkgCache(None, ""), None) - self.assertEqual(vfs.LoadPkgCache("", None), None) - self.assertEqual(vfs.LoadPkgCache("", ""), None) - - def test_missing_cache(self): - self.assertEqual( - vfs.LoadPkgCache(os.path.dirname(__file__), "pkgpath.missing"), None - ) - - -class TestVfsSavePkgCache(unittest.TestCase): - def test_invalid_parameters(self): - self.assertEqual(vfs.SavePkgCache(None, None, None), None) - self.assertEqual(vfs.SavePkgCache(None, "", ""), None) - self.assertEqual(vfs.SavePkgCache("", None, ""), None) - self.assertEqual(vfs.SavePkgCache("", "", None), None) - self.assertEqual(vfs.SavePkgCache(None, None, ""), None) - self.assertEqual(vfs.SavePkgCache("", None, None), None) - self.assertEqual(vfs.SavePkgCache(None, "", None), None) - - def test_save(self): - vfs.SavePkgCache( - os.path.dirname(__file__), "pkgpath.test_save", {"key": "value"} - ) - - def tearDown(self): - cache_root = f"{os.path.dirname(__file__)}/.kclvm" - if os.path.exists(cache_root): - shutil.rmtree(cache_root) - - -class TestVfsIsAbsPkgPath(unittest.TestCase): - def test_is_abs_pkg_path_with_true_case(self): - tests = ["a", "a.b.c"] - for i in range(len(tests)): - self.assertTrue(vfs.IsAbsPkgPath(tests[i]), msg=f"{tests[i]}") - - def test_is_abs_pkg_path_with_false_case(self): - tests = ["", ".", ".a", "a..b", "a b", None, 1] - for i in range(len(tests)): - self.assertFalse(vfs.IsAbsPkgPath(tests[i]), msg=f"{tests[i]}") - - -class TestVfsIsRelPkgPath(unittest.TestCase): - def test_is_abs_pkg_path_with_true_case(self): - tests = [".", ".a", ".a.b.c", "..a.b", " .a.b.c"] - for i in range(len(tests)): - self.assertTrue(vfs.IsRelPkgPath(tests[i]), msg=f"{tests[i]}") - - def test_is_abs_pkg_path_with_false_case(self): - tests = ["", "a", "a.b.c", "a b", None, 1] - for i in range(len(tests)): - self.assertFalse(vfs.IsRelPkgPath(tests[i]), msg=f"{tests[i]}") - - -class TestFixImportPath(unittest.TestCase): - def test_fix_import_path_invalid_case(self): - cases = [ - {"root": None, "filepath": None, "import_path": None}, - {"root": "", "filepath": "", "import_path": ""}, - ] - for case in cases: - root, filepath, import_path = ( - case["root"], - case["filepath"], - case["import_path"], - ) - with self.assertRaises(AssertionError): - vfs.FixImportPath(root, filepath, import_path) - - def test_fix_import_path_normal_case(self): - cases = [ - { - "root": ".", - "filepath": "path/to/app/file.k", - "import_path": ".sub", - "expected": "path.to.app.sub", - }, - { - "root": ".", - "filepath": "path/to/app/file.k", - "import_path": "..sub", - "expected": "path.to.sub", - }, - { - "root": ".", - "filepath": "path/to/app/file.k", - "import_path": "...sub", - "expected": "path.sub", - }, - { - "root": ".", - "filepath": "path/to/app/file.k", - "import_path": "....sub", - "expected": "sub", - }, - { - "root": ".", - "filepath": "path/to/app/file.k", - "import_path": ".....sub", - "expected": "", - }, - { - "root": ".", - "filepath": "path/to/app/file.k", - "import_path": "path.to.sub", - "expected": "path.to.sub", - }, - { - "root": "path/to/app/", - "filepath": "path/to/app/file.k", - "import_path": ".sub", - "expected": "sub", - }, - { - "root": "path/to/app/", - "filepath": "path/to/app/file.k", - "import_path": "..sub", - "expected": "", - }, - { - "root": "path/to/", - "filepath": "path/to/app/file.k", - "import_path": ".sub", - "expected": "app.sub", - }, - { - "root": "path/to/", - "filepath": "path/to/app/file.k", - "import_path": "..sub", - "expected": "sub", - }, - { - "root": "path/", - "filepath": "path/to/app/file.k", - "import_path": "..sub", - "expected": "to.sub", - }, - { - "root": "path/", - "filepath": "path/to/app/file.k", - "import_path": ".sub", - "expected": "to.app.sub", - }, - ] - for case in cases: - root, filepath, import_path, expected = ( - case["root"], - case["filepath"], - case["import_path"], - case["expected"], - ) - self.assertEqual( - vfs.FixImportPath(root, filepath, import_path), - expected, - f"Case test failed: root: {root}, filepath: {filepath}, import_path: {import_path}", - ) - - -class TestVfsSaveAndLoadASTPkgCache(unittest.TestCase): - def test_ast_save_and_load(self): - codes = ["a = 1", "b = 1"] - pkgs = ["pkg", "pkg.pkg"] - for code, pkg in zip(codes, pkgs): - module = parser.ParseFile("test.k", code) - module_load = vfs.LoadPkgCache(os.path.dirname(__file__), pkg) - self.assertEqual(module_load, None) - vfs.SavePkgCache(os.path.dirname(__file__), pkg, module) - module_load = vfs.LoadPkgCache(os.path.dirname(__file__), pkg) - self.assertIsInstance(module_load, ast.Module) - - def test_cache_loaded_expired(self): - code = "a = 1" - pkg = "pkg" - module = parser.ParseFile("test.k", code) - vfs.SavePkgCache(os.path.dirname(__file__), pkg, module) - module_load = vfs.LoadPkgCache(os.path.dirname(__file__), pkg) - self.assertIsInstance(module_load, ast.Module) - pathlib.Path(__file__).parent.joinpath("pkg/pkg.k").write_text(code) - module_load = vfs.LoadPkgCache(os.path.dirname(__file__), pkg) - self.assertIsNone(module_load) - pathlib.Path(__file__).parent.joinpath("pkg/pkg.k").write_text("") - - -class TestVfsSaveAndLoadASTMainPkgCache(unittest.TestCase): - def test_ast_main_save_and_load(self): - codes = ["a = 1", "b = 1"] - filenames = ["main_test1.k", "main_test2.k"] - for code, filename in zip(codes, filenames): - module = parser.ParseFile(filename, code) - module_load = vfs.LoadMainPkgCache(os.path.dirname(__file__), filename) - self.assertEqual(module_load, None) - vfs.SaveMainPkgCache(os.path.dirname(__file__), filename, module) - module_load = vfs.LoadMainPkgCache(os.path.dirname(__file__), filename) - self.assertIsInstance(module_load, ast.Module) - - def test_main_cache_loaded_expired(self): - code = "a = 1" - pkg = "pkg" - module = parser.ParseFile("test.k", code) - k_filepath = pathlib.Path(__file__).parent.joinpath("pkg/pkg.k") - vfs.SaveMainPkgCache(os.path.dirname(__file__), str(k_filepath), module) - module_load = vfs.LoadMainPkgCache(os.path.dirname(__file__), str(k_filepath)) - self.assertIsInstance(module_load, ast.Module) - k_filepath.write_text(code) - module_load = vfs.LoadMainPkgCache(os.path.dirname(__file__), str(k_filepath)) - self.assertIsNone(module_load) - k_filepath.write_text("") - - def test_kcl_mod_with_main_pkg_save(self): - work_dir = pathlib.Path(__file__).parent - main_file = str(work_dir / "main.k") - # Save main package cache - parser.LoadProgram(main_file, work_dir=str(work_dir)) - # Load main package cache - parser.LoadProgram(main_file, work_dir=str(work_dir)) - - -class TestCacheInfo(unittest.TestCase): - def test_cache_info(self): - root = str(pathlib.Path(__file__).parent) - filepath = str(pathlib.Path(__file__).parent / "pkg") - vfs.write_info_cache({}, root, filepath) - # Read info cache - vfs.read_info_cache(root) - - def test_cache_info_invalid_root(self): - root = str(pathlib.Path(__file__).parent / "err_pkg") - self.assertEqual(vfs.read_info_cache(root), {}) - - def test_cache_info_file(self): - cases = [ - {"filepath": str(pathlib.Path(__file__).parent / "pkg"), "expected": "d41d8cd98f00b204e9800998ecf8427e"}, - {"filepath": str(pathlib.Path(__file__).parent / "pkg/pkg.k"), "expected": "d41d8cd98f00b204e9800998ecf8427e"}, - {"filepath": str(pathlib.Path(__file__).parent / "main.k"), "expected": "fd352b68bf83391284e044021cab0339"}, - ] - for case in cases: - filepath, expected = case["filepath"], case["expected"] - self.assertEqual(vfs.get_cache_info(filepath), expected) - - -class TestVfsSaveAndLoadBytecodeCache(unittest.TestCase): - def setUp(self): - self.test_data_path_name = "test_data_bytecode_cache" - self.root = str(pathlib.Path(__file__).parent.joinpath(self.test_data_path_name)) - self.main_file = str(pathlib.Path(__file__).parent.joinpath(f"{self.test_data_path_name}/main.k")) - self.cache_path = str(pathlib.Path(__file__).parent.joinpath(f"{self.test_data_path_name}/.kclvm")) - return super().setUp() - - def test_save_bytecode_cache(self): - ast_program = parser.LoadProgram(self.main_file) - kcl_program = compiler.CompileProgram(ast_program) - self.assertEqual(kcl_program.root, self.root) - vfs.SaveBytecodeCache(ast_program.root, ast_program, kcl_program) - program_loaded = vfs.LoadBytecodeCache(self.root, ast_program) - self.assertIsNotNone(program_loaded) - if os.path.exists(self.cache_path): - shutil.rmtree(self.cache_path) - - def test_load_bytecode_cache(self): - pass - - def test_save_bytecode_cache_invalid_parameters(self): - cases = [ - {"root": "", "ast_program": None, "program": None}, - {"root": self.root, "ast_program": None, "program": None}, - {"root": self.root, "ast_program": ast.Program(), "program": None}, - {"root": self.root, "ast_program": ast.Program(), "program": obj.KCLProgram()}, - ] - for case in cases: - root, ast_program, program = case["root"], case["ast_program"], case["program"] - vfs.SaveBytecodeCache(root, ast_program, program) - - def test_load_bytecode_cache_invalid_parameters(self): - cases = [ - {"root": "", "ast_program": None}, - {"root": self.root, "ast_program": None}, - {"root": self.root, "ast_program": ast.Program()}, - ] - for case in cases: - root, ast_program = case["root"], case["ast_program"] - vfs.LoadBytecodeCache(root, ast_program) - - -if __name__ == "__main__": - unittest.main(verbosity=2) diff --git a/test/test_units/test_kclvm/test_compiler/test_vfs/test_vfs_get_root.py b/test/test_units/test_kclvm/test_compiler/test_vfs/test_vfs_get_root.py deleted file mode 100644 index 89741acf2..000000000 --- a/test/test_units/test_kclvm/test_compiler/test_vfs/test_vfs_get_root.py +++ /dev/null @@ -1,45 +0,0 @@ -# Copyright 2020 The KCL Authors. All rights reserved. - -import unittest -import pathlib - -import kclvm.kcl.error as kcl_error -import kclvm.compiler.vfs as vfs - -CURRENT_PATH = str(pathlib.Path(__file__).parent) - - -class TestVfsGetRoot(unittest.TestCase): - def test_get_pkg_root(self): - cases = [ - {"path": "../..", "expected": None}, - {"path": f"{CURRENT_PATH}/pkg", "expected": str(CURRENT_PATH)}, - {"path": f"{CURRENT_PATH}/test_get_pkg_root", "expected": f"{CURRENT_PATH}/test_get_pkg_root"}, - ] - for case in cases: - path, expected = case["path"], case["expected"] - result = vfs.GetPkgRoot(path) - self.assertEqual(result, expected) - - def test_must_get_pkg_root(self): - cases = [ - {"paths": ["../..", "."], "expected": None}, - {"paths": [f"{CURRENT_PATH}/pkg", "."], "expected": str(CURRENT_PATH)}, - ] - for case in cases: - paths, expected = case["paths"], case["expected"] - result = vfs.MustGetPkgRoot(paths) - self.assertEqual(result, expected) - - def test_must_get_pkg_root_invalid(self): - cases = [ - {"paths": [f"{CURRENT_PATH}/test_get_pkg_root", str(CURRENT_PATH)]}, - ] - for case in cases: - paths = case["paths"] - with self.assertRaises(kcl_error.CompileError): - result = vfs.MustGetPkgRoot(paths) - - -if __name__ == "__main__": - unittest.main(verbosity=2) diff --git a/test/test_units/test_kclvm/test_config/test_config.py b/test/test_units/test_kclvm/test_config/test_config.py deleted file mode 100644 index 643b9aabf..000000000 --- a/test/test_units/test_kclvm/test_config/test_config.py +++ /dev/null @@ -1,19 +0,0 @@ -# Copyright 2020 The KCL Authors. All rights reserved. - -import unittest -import pathlib - -import kclvm.config as config - - -class TestConfigSettingFile(unittest.TestCase): - def test_cli_setting_action(self): - settings_file = str(pathlib.Path(__file__).parent.joinpath("test_data/settings.yaml")) - action = config.KCLCLISettingAction() - keys, values = [], [] - action.deal_setting_file(settings_file, keys, values) - self.assertListEqual(keys, ["app", "env-type"]) - self.assertListEqual(values, ["kclvm", "dev"]) - -if __name__ == "__main__": - unittest.main(verbosity=2) diff --git a/test/test_units/test_kclvm/test_config/test_data/settings.yaml b/test/test_units/test_kclvm/test_config/test_data/settings.yaml deleted file mode 100644 index 328ccb6b2..000000000 --- a/test/test_units/test_kclvm/test_config/test_data/settings.yaml +++ /dev/null @@ -1,10 +0,0 @@ -# This is a comment -kcl_options: - - key: app - value: kclvm - - key: env-type - value: dev -kcl_cli_configs: - files: - - ./base.k - - ${KCL_MOD}/main.k diff --git a/test/test_units/test_kclvm/test_config/test_settings.py b/test/test_units/test_kclvm/test_config/test_settings.py deleted file mode 100644 index 4a168a3eb..000000000 --- a/test/test_units/test_kclvm/test_config/test_settings.py +++ /dev/null @@ -1,28 +0,0 @@ -# Copyright 2020 The KCL Authors. All rights reserved. - -import unittest -import pathlib - -import kclvm.config as config - - -class TestSettingsFile(unittest.TestCase): - def test_load_settings_files(self): - files = [ - str(pathlib.Path(__file__).parent.joinpath("test_data/settings.yaml")), - ] - work_dir = str(pathlib.Path(__file__).parent.joinpath("test_data")) - cli_config = config.load_settings_files(work_dir, files) - expected_files = [ - str(pathlib.Path(__file__).parent.joinpath("test_data/base.k")), - str(pathlib.Path(__file__).parent.joinpath("test_data/main.k")), - ] - self.assertEqual(cli_config.kcl_cli_configs.files, expected_files) - keys = [opt.key for opt in cli_config.kcl_options] - values = [opt.value for opt in cli_config.kcl_options] - self.assertListEqual(keys, ["app", "env-type"]) - self.assertListEqual(values, ["kclvm", "dev"]) - - -if __name__ == "__main__": - unittest.main(verbosity=2) diff --git a/test/test_units/test_kclvm/test_encoding/test_protobuf/test_parser.py b/test/test_units/test_kclvm/test_encoding/test_protobuf/test_parser.py deleted file mode 100644 index 0e6b0e439..000000000 --- a/test/test_units/test_kclvm/test_encoding/test_protobuf/test_parser.py +++ /dev/null @@ -1,48 +0,0 @@ -# Copyright 2020 The KCL Authors. All rights reserved. - -import unittest -import pathlib - -import kclvm.encoding.protobuf as protobuf - - -simple_test_case = """\ -syntax = "proto3"; -import public "other.proto"; -option java_package = "com.example.foo"; - -enum EnumAllowingAlias { - option allow_alias = true; - UNKNOWN = 0; - STARTED = 1; - RUNNING = 2 [(custom_option) = "hello world"]; -} - -message outer { - option (my_option).a = true; - option (my_option).b = -1; - option (my_option).c = "\\xAA"; - - message inner { - int64 ival = 1; - } - repeated inner inner_message = 2; - EnumAllowingAlias enum_field = 3; - map my_map = 4; -} -""" - - -class TestProtobufParseCode(unittest.TestCase): - def test_simple_case(self): - proto = protobuf.parse_code(simple_test_case) - self.assertEqual(len(proto.statements), 4) - self.assertEqual(proto.syntax, "proto3") - self.assertIsInstance(proto.statements[0], protobuf.Import) - self.assertIsInstance(proto.statements[1], protobuf.Option) - self.assertIsInstance(proto.statements[2], protobuf.Enum) - self.assertIsInstance(proto.statements[3], protobuf.Message) - - -if __name__ == "__main__": - unittest.main(verbosity=2) diff --git a/test/test_units/test_kclvm/test_encoding/test_protobuf/test_printer.py b/test/test_units/test_kclvm/test_encoding/test_protobuf/test_printer.py deleted file mode 100644 index 33fc89896..000000000 --- a/test/test_units/test_kclvm/test_encoding/test_protobuf/test_printer.py +++ /dev/null @@ -1,119 +0,0 @@ -# Copyright 2020 The KCL Authors. All rights reserved. - -import io -import unittest -import pathlib - -import kclvm.encoding.protobuf.parser as parser -import kclvm.encoding.protobuf.printer as printer - - -simple_test_case = """\ -syntax = "proto3"; -package kclvm.runtime.api; -import public "other.proto"; -option java_package = "com.example.foo"; - -enum EnumAllowingAlias { - option allow_alias = true; - UNKNOWN = 0; - STARTED = 1; - RUNNING = 2 [(custom_option) = "hello world"]; -} - -message outer { - option my_option.a = true; - option my_option.b = false; - - message inner { - int64 ival = 1; - } - repeated inner inner_message = 2; - EnumAllowingAlias enum_field = 3; - map my_map = 4; - oneof x { - int32 id = 1; - string name = 2; - } -} - -message Foo { - reserved 2, 15, 9 to 11; - reserved "foo", "bar"; -} - -message Args { - bool result = 1; -} - -service Service { - rpc Method(Args) returns (Args); -} -""" -simple_test_case_expected = """\ -syntax = "proto3"; -package kclvm.runtime.api; -import public "other.proto"; -option java_package = "com.example.foo"; - -enum EnumAllowingAlias { - option allow_alias = true; - UNKNOWN = 0; - STARTED = 1; - RUNNING = 2 [(custom_option) = "hello world"]; -} - -message outer { - option my_option.a = true; - option my_option.b = false; - - message inner { - int64 ival = 1; - } - repeated inner inner_message = 2; - EnumAllowingAlias enum_field = 3; - map my_map = 4; - oneof x { - int32 id = 1; - string name = 2; - } -} - -message Foo { - reserved 2, 15, 9 to 11; - reserved "foo", "bar"; -} - -message Args { - bool result = 1; -} - -service Service { - rpc Method(Args) returns (Args); -} -""" - - -class TestProtobufPrinter(unittest.TestCase): - def setUp(self): - super().setUp() - self.maxDiff = None - - def test_protobuf_printer(self): - proto = parser.parse_code(simple_test_case) - proto_text = printer.print_node_to_string(proto) - self.assertEqual(proto_text, simple_test_case_expected) - - def test_interleave(self): - out = io.StringIO() - printer.BasePrinter.interleave( - lambda: out.write(", "), lambda n: out.write(str(n)), [] - ) - printer.BasePrinter.interleave( - lambda: out.write(", "), lambda n: out.write(str(n)), [1, 2, 3] - ) - self.assertEqual(out.getvalue(), "1, 2, 3") - - -if __name__ == "__main__": - unittest.main(verbosity=2) diff --git a/test/test_units/test_kclvm/test_encoding/test_protobuf/test_protobuf.py b/test/test_units/test_kclvm/test_encoding/test_protobuf/test_protobuf.py deleted file mode 100644 index 5fe085170..000000000 --- a/test/test_units/test_kclvm/test_encoding/test_protobuf/test_protobuf.py +++ /dev/null @@ -1,101 +0,0 @@ -# Copyright 2020 The KCL Authors. All rights reserved. - -import unittest -import pathlib - -import kclvm.encoding.protobuf.protobuf as protobuf - - -simple_to_kcl_test_case = """\ -syntax = "proto3"; -import public "other.proto"; -option java_package = "com.example.foo"; - -enum EnumAllowingAlias { - option allow_alias = true; - UNKNOWN = 0; - STARTED = 1; - RUNNING = 2 [(custom_option) = "hello world"]; -} - -message outer { - option (my_option).a = true; - message inner { - int64 ival = 1; - } - repeated inner inner_message = 2; - EnumAllowingAlias enum_field = 3; - map my_map = 4; - oneof x { - int32 id = 1; - string name = 2; - } -} -""" -simple_to_kcl_test_case_expected = """\ -type EnumAllowingAlias = 0 | 1 | 2 -schema outer: - inner_message: [inner] - enum_field: EnumAllowingAlias - my_map: {int:str} - x: int | str - -schema inner: - ival: int - -""" -simple_to_pb_test_case = """\ -schema Inner: - ival: int - -schema Outer: - inner: Inner - inner_message: [Inner] - my_map: {str:str} - x: int | str -""" -simple_to_pb_test_case_expected = """\ -syntax = "proto3"; - -message Inner { - int64 ival = 1; -} - -message Outer { - Inner inner = 1; - repeated Inner inner_message = 2; - map my_map = 3; - oneof x { - int x1 = 1; - str x2 = 2; - } -} -""" - - -class TestProtobufToKCLCode(unittest.TestCase): - def test_to_kcl_simple_case(self): - kcl_code = protobuf.protobuf_to_kcl(simple_to_kcl_test_case) - self.assertEqual(kcl_code, simple_to_kcl_test_case_expected) - - def test_invalid_function_arguments(self): - with self.assertRaises(ValueError): - protobuf.convert_enum_to_type_alias(None) - with self.assertRaises(ValueError): - protobuf.convert_message_to_schema_list(None) - with self.assertRaises(ValueError): - protobuf.convert_schema_to_message(None) - with self.assertRaises(ValueError): - protobuf.convert_schema_attr_to_message_body(None) - with self.assertRaises(ValueError): - protobuf.convert_kcl_type_to_proto_type("") - - -class TestKCLToProtobufCode(unittest.TestCase): - def test_to_pb_simple_case(self): - kcl_code = protobuf.kcl_to_protobuf(simple_to_pb_test_case) - self.assertEqual(kcl_code, simple_to_pb_test_case_expected) - - -if __name__ == "__main__": - unittest.main(verbosity=2) diff --git a/test/test_units/test_kclvm/test_info/test_naming.py b/test/test_units/test_kclvm/test_info/test_naming.py deleted file mode 100644 index bfca31544..000000000 --- a/test/test_units/test_kclvm/test_info/test_naming.py +++ /dev/null @@ -1,56 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: UTF-8 -*- - -import os -import unittest - -import kclvm.kcl.info as kcl_info - - -class TestKCLInfoNaming(unittest.TestCase): - def test_mangle(self): - cases = [ - {"name": "", "expected": "KMANGLED_"}, - {"name": "a", "expected": "KMANGLED_a"}, - {"name": "a.b", "expected": "KMANGLED_a.KMANGLED_b"}, - ] - for case in cases: - name, expected = case["name"], case["expected"] - self.assertEqual(kcl_info.mangle(name), expected) - - def test_demangle(self): - cases = [ - {"name": "", "expected": ""}, - {"name": "KMANGLED_a", "expected": "a"}, - {"name": "KMANGLED_a.KMANGLED_b", "expected": "a.b"}, - ] - for case in cases: - name, expected = case["name"], case["expected"] - self.assertEqual(kcl_info.demangle(name), expected) - - - def test_tagging(self): - cases = [ - {"name": "", "tag": "", "expected": "KTAG__"}, - {"name": "", "tag": "attr", "expected": "KTAG_attr_"}, - {"name": "a", "tag": "attr", "expected": "KTAG_attr_a"}, - {"name": "a.b", "tag": "attr", "expected": "KTAG_attr_a.b"}, - ] - for case in cases: - name, tag, expected = case["name"], case["tag"], case["expected"] - self.assertEqual(kcl_info.tagging(tag, name), expected) - - def test_detagging(self): - cases = [ - {"name": "", "tag": "", "expected": ""}, - {"name": "KTAG_attr_", "tag": "attr", "expected": ""}, - {"name": "KTAG_attr_a", "tag": "attr", "expected": "a"}, - {"name": "KTAG_attr_a.b", "tag": "attr", "expected": "a.b"}, - ] - for case in cases: - name, tag, expected = case["name"], case["tag"], case["expected"] - self.assertEqual(kcl_info.detagging(tag, name), expected) - - -if __name__ == "__main__": - unittest.main(verbosity=2) diff --git a/test/test_units/test_kclvm/test_program/test_exec/test_runner.py b/test/test_units/test_kclvm/test_program/test_exec/test_runner.py deleted file mode 100644 index 5112d7646..000000000 --- a/test/test_units/test_kclvm/test_program/test_exec/test_runner.py +++ /dev/null @@ -1,24 +0,0 @@ -# Copyright 2021 The KCL Authors. All rights reserved. - -import unittest -import pathlib - -import kclvm.program.exec.runner as runner - - -class KCLCompilerBuildCacheTest(unittest.TestCase): - def test_schema_infer(self): - test_path = pathlib.Path(__file__).parent.joinpath("testdata/schema_infer") - test_main = test_path.joinpath("main.k") - result = runner.Run([str(test_main)], work_dir=str(test_path)) - self.assertEqual(list(result.filter_by_path_selector().keys()), ['Person', 'x0', 'x1', 'x2', '@pkg']) - - def _test_schema_infer_native(self): - test_path = pathlib.Path(__file__).parent.joinpath("testdata/schema_infer") - test_main = test_path.joinpath("main.k") - result = runner.Run([str(test_main)], work_dir=str(test_path), target="native") - self.assertEqual(list(result.filter_by_path_selector().keys()), ['Person', 'x0', 'x1', 'x2', '@pkg']) - - -if __name__ == "__main__": - unittest.main(verbosity=2) diff --git a/test/test_units/test_kclvm/test_program/test_exec/testdata/schema_infer/main.k b/test/test_units/test_kclvm/test_program/test_exec/testdata/schema_infer/main.k deleted file mode 100644 index 309c70eae..000000000 --- a/test/test_units/test_kclvm/test_program/test_exec/testdata/schema_infer/main.k +++ /dev/null @@ -1,14 +0,0 @@ -import pkg - -schema Person: - name: str = "kcl" - age: int = 1 - -x0: pkg.Person = { - age = 101 -} - -x1: Person = { - age = 101 -} -x2: Person = Person() diff --git a/test/test_units/test_kclvm/test_program/test_exec/testdata/schema_infer/pkg/pkg.k b/test/test_units/test_kclvm/test_program/test_exec/testdata/schema_infer/pkg/pkg.k deleted file mode 100644 index a49235a51..000000000 --- a/test/test_units/test_kclvm/test_program/test_exec/testdata/schema_infer/pkg/pkg.k +++ /dev/null @@ -1,3 +0,0 @@ -schema Person: - name: str = "kcl" - age: int = 1 diff --git a/test/test_units/test_kclvm/test_rpc_server/invalid_testdata/eval-code.json b/test/test_units/test_kclvm/test_rpc_server/invalid_testdata/eval-code.json deleted file mode 100644 index b1609343c..000000000 --- a/test/test_units/test_kclvm/test_rpc_server/invalid_testdata/eval-code.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "code": "schema Data:\n foo: int = 1\n bar: str = 'ss'\n\ndata = ata {}" -} \ No newline at end of file diff --git a/test/test_units/test_kclvm/test_rpc_server/invalid_testdata/exec-program.json b/test/test_units/test_kclvm/test_rpc_server/invalid_testdata/exec-program.json deleted file mode 100644 index 699059a78..000000000 --- a/test/test_units/test_kclvm/test_rpc_server/invalid_testdata/exec-program.json +++ /dev/null @@ -1,9 +0,0 @@ - -{ - "k_filename_list":[ - "hello.k" - ], - "k_code_list":[ - "a=b" - ] -} diff --git a/test/test_units/test_kclvm/test_rpc_server/invalid_testdata/get-schema.json b/test/test_units/test_kclvm/test_rpc_server/invalid_testdata/get-schema.json deleted file mode 100644 index df3c78203..000000000 --- a/test/test_units/test_kclvm/test_rpc_server/invalid_testdata/get-schema.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "code": "\nschema Person:\n key: str\n val:Str\n check:\n \"value\" in key # 'key' is required and 'key' must contain \"value\"\n" -} diff --git a/test/test_units/test_kclvm/test_rpc_server/invalid_testdata/resolve-code.json b/test/test_units/test_kclvm/test_rpc_server/invalid_testdata/resolve-code.json deleted file mode 100644 index bd996995d..000000000 --- a/test/test_units/test_kclvm/test_rpc_server/invalid_testdata/resolve-code.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "code": "schema Data:\n foo: int = 1\n bar: str = 1\n\ndata = Data {}" -} \ No newline at end of file diff --git a/test/test_units/test_kclvm/test_rpc_server/invalid_testdata/splice-code.json b/test/test_units/test_kclvm/test_rpc_server/invalid_testdata/splice-code.json deleted file mode 100644 index 3df2d69be..000000000 --- a/test/test_units/test_kclvm/test_rpc_server/invalid_testdata/splice-code.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "codeSnippets": [ - { - "schema": "schema Person:1\n age: int\n", - "rule": "age > 0" - } - ] -} diff --git a/test/test_units/test_kclvm/test_rpc_server/invalid_testdata/vet-simple.json b/test/test_units/test_kclvm/test_rpc_server/invalid_testdata/vet-simple.json deleted file mode 100644 index cfa09e5cf..000000000 --- a/test/test_units/test_kclvm/test_rpc_server/invalid_testdata/vet-simple.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "code": "import regex\n\nschema Sample:\n foo: str # Required, 不能为None, 且类型必须为str\n bar: int # Required, 不能为None, 且类型必须为int\n fooList: [str] # Required, 不能为None, 且类型必须为str列表\n color: \"Red\" | \"Yellow\" | \"Blue\" # Required, 字面值联合类型,且必须为\"Red\", \"Yellow\", \"Blue\"中的一个,枚举作用\n id?: int # Optional,可以留空,类型必须为int\n \n check:\n bar >= 0 # bar必须大于等于0\n bar < 100 # bar必须小于100\n len(fooList) > 0 # fooList不能为None,并且长度必须大于0\n len(fooList) < 100 # fooList不能为None,并且长度必须小于100\n regex.match(foo, \"^The.*Foo$\") # regex 正则表达式匹配\n bar in range(100) # range, bar范围只能为1到99\n bar in [2, 4, 6, 8] # enum, bar只能取2, 4, 6, 8\n bar % 2 == 0 # bar必须为2的倍数\n abs(id) > 10 if id is not None # check if 表达式,当 id 不为空时,id的绝对值必须大于10\n", - "data": "{\"attr_name\":{\n \"foo\": \"ThehFoo\",\n \"bar\": 3,\n \"fooList\": [\n \"a\",\n \"b\"\n ],\n \"color\": \"Red\",\n \"id\": 100\n}}" -} diff --git a/test/test_units/test_kclvm/test_rpc_server/test_rpc_server.py b/test/test_units/test_kclvm/test_rpc_server/test_rpc_server.py deleted file mode 100644 index 43c5be39b..000000000 --- a/test/test_units/test_kclvm/test_rpc_server/test_rpc_server.py +++ /dev/null @@ -1,140 +0,0 @@ -# Copyright 2020 The KCL Authors. All rights reserved. - -import time -import json -import pathlib -import unittest -import subprocess -import requests -import os - -import kclvm.internal.util as util - - -SERVER_CMD = "kclvm -m kclvm.program.rpc-server -http=127.0.0.1:2021" -HEADERS = { - "content-type": "accept/json", -} - - -class TestRpcServer(unittest.TestCase): - def setUp(self): - self.p = subprocess.Popen(SERVER_CMD.split()) - # Sleep enough time to establish connection - time.sleep(10) - super().setUp() - - def tearDown(self): - self.p.kill() - super().tearDown() - - def test_rpc_server_normal(self): - apis = [ - "EvalCode", - "ExecProgram", - "GetSchemaType", - "ResolveCode", - "SpliceCode", - "ValidateCode", - "ValidateCode", - "ValidateCode", - ] - data_files = [ - "eval-code", - "exec-program", - "get-schema", - "resolve-code", - "splice-code", - "vet-hello", - "vet-simple", - "vet-single", - ] - test_path = "testdata" - for api, data_file in zip(apis, data_files): - try: - json_file = pathlib.Path(__file__).parent.joinpath( - f"{test_path}/{data_file}.json" - ) - json_data = json_file.read_text(encoding="utf-8") - res = requests.post( - f"http://127.0.0.1:2021/api:protorpc/KclvmService.{api}", - data=json_data.encode("utf-8"), - headers=HEADERS, - ) - res_data = res.json() - self.assertEqual( - res_data["error"], "", msg=f"api: {api}, data_file: {data_file}" - ) - except Exception as err: - self.assertTrue(False, msg=f"api: {api}, data_file: {data_file}, reason: {err}") - continue - - def test_rpc_server_invalid(self): - apis = [ - "EvalCode", - "ExecProgram", - "GetSchemaType", - "ResolveCode", - "SpliceCode", - "ValidateCode", - ] - data_files = [ - "eval-code", - "exec-program", - "get-schema", - "resolve-code", - "splice-code", - "vet-simple", - ] - test_path = "invalid_testdata" - for api, data_file in zip(apis, data_files): - try: - json_file = pathlib.Path(__file__).parent.joinpath( - f"{test_path}/{data_file}.json" - ) - json_data = json_file.read_text(encoding="utf-8") - res = requests.post( - f"http://127.0.0.1:2021/api:protorpc/KclvmService.{api}", - data=json_data.encode("utf-8"), - headers=HEADERS, - ) - res_data = res.json() - self.assertTrue( - bool(res_data["error"]), msg=f"api: {api}, data_file: {data_file}" - ) - except: - self.assertTrue(False, msg=f"api: {api}, data_file: {data_file}") - continue - - # TODO: enable this test after the kcl-go upgraded - def _test_rpc_server_ListDepFiles(self): - appWorkDir = pathlib.Path(__file__).parent.joinpath(f"testdata/kcl-module/app0") - - api = "ListDepFiles" - json_data = f"{{\"work_dir\": \"{appWorkDir}\"}}" - res = requests.post( - f"http://127.0.0.1:2021/api:protorpc/KclvmService.{api}", - data=json_data.encode("utf-8"), - headers=HEADERS, - ) - - res_data = res.json() - self.assertEqual(res_data["error"], "", msg=f"api: {api}, res_data: {res_data}, appWorkDir: {appWorkDir}") - self.assertTrue(res_data["result"], msg=f"api: {api}, res_data: {res_data}, appWorkDir: {appWorkDir}") - - expect = [ - "main.k", - "app0/before/base.k", - "app0/main.k", - "app0/sub/sub.k", - ] - - self.assertEqual( - sorted(res_data["result"]["files"]), - sorted(expect), - msg=f"api: {api}, res_data: {res_data}, expect: {expect}, appWorkDir: {appWorkDir}" - ) - - -if __name__ == "__main__": - unittest.main(verbosity=2) diff --git a/test/test_units/test_kclvm/test_rpc_server/testdata/eval-code.json b/test/test_units/test_kclvm/test_rpc_server/testdata/eval-code.json deleted file mode 100644 index ac6306d99..000000000 --- a/test/test_units/test_kclvm/test_rpc_server/testdata/eval-code.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "code": "schema Data:\n foo: int = 1\n bar: str = 'ss'\n\ndata = Data {}" -} \ No newline at end of file diff --git a/test/test_units/test_kclvm/test_rpc_server/testdata/eval-code.response.json b/test/test_units/test_kclvm/test_rpc_server/testdata/eval-code.response.json deleted file mode 100644 index f0f22018f..000000000 --- a/test/test_units/test_kclvm/test_rpc_server/testdata/eval-code.response.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "result": { - "json_result": "{\n \"data\": {\n \"foo\": 1,\n \"bar\": \"ss\"\n }\n}" - }, - "error": "" -} \ No newline at end of file diff --git a/test/test_units/test_kclvm/test_rpc_server/testdata/exec-program.json b/test/test_units/test_kclvm/test_rpc_server/testdata/exec-program.json deleted file mode 100644 index 864eab235..000000000 --- a/test/test_units/test_kclvm/test_rpc_server/testdata/exec-program.json +++ /dev/null @@ -1,9 +0,0 @@ - -{ - "k_filename_list":[ - "hello.k" - ], - "k_code_list":[ - "a=1" - ] -} diff --git a/test/test_units/test_kclvm/test_rpc_server/testdata/exec-program.response.json b/test/test_units/test_kclvm/test_rpc_server/testdata/exec-program.response.json deleted file mode 100644 index 39e04cab6..000000000 --- a/test/test_units/test_kclvm/test_rpc_server/testdata/exec-program.response.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "result": { - "json_result": "[\n {\n \"a\": 1\n }\n]", - "yaml_result": "a: 1\n", - "escaped_time": "0.002061128616333008" - }, - "error": "" -} \ No newline at end of file diff --git a/test/test_units/test_kclvm/test_rpc_server/testdata/get-schema.json b/test/test_units/test_kclvm/test_rpc_server/testdata/get-schema.json deleted file mode 100644 index 5f374d679..000000000 --- a/test/test_units/test_kclvm/test_rpc_server/testdata/get-schema.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "code": "\nschema Person:\n key: str\n\n check:\n \"value\" in key # 'key' is required and 'key' must contain \"value\"\n" -} diff --git a/test/test_units/test_kclvm/test_rpc_server/testdata/get-schema.response.json b/test/test_units/test_kclvm/test_rpc_server/testdata/get-schema.response.json deleted file mode 100644 index 639ed96ac..000000000 --- a/test/test_units/test_kclvm/test_rpc_server/testdata/get-schema.response.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "result": { - "schema_type_list": [ - { - "type": "schema", - "schema_name": "Person", - "properties": { - "key": { - "type": "str", - "line": 1, - "union_types": [], - "default": "", - "schema_name": "", - "schema_doc": "", - "properties": {}, - "required": [] - } - }, - "union_types": [], - "default": "", - "schema_doc": "", - "required": [], - "line": 0 - } - ] - }, - "error": "" -} \ No newline at end of file diff --git a/test/test_units/test_kclvm/test_rpc_server/testdata/kcl-module/app0/before/base.k b/test/test_units/test_kclvm/test_rpc_server/testdata/kcl-module/app0/before/base.k deleted file mode 100644 index 62b769890..000000000 --- a/test/test_units/test_kclvm/test_rpc_server/testdata/kcl-module/app0/before/base.k +++ /dev/null @@ -1 +0,0 @@ -base1 = 1 diff --git a/test/test_units/test_kclvm/test_rpc_server/testdata/kcl-module/app0/kcl.yaml b/test/test_units/test_kclvm/test_rpc_server/testdata/kcl-module/app0/kcl.yaml deleted file mode 100644 index 7bb840a6e..000000000 --- a/test/test_units/test_kclvm/test_rpc_server/testdata/kcl-module/app0/kcl.yaml +++ /dev/null @@ -1,10 +0,0 @@ -kcl_cli_configs: - file: - - ../main.k - - ./before/base.k - - main.k - - ${KCL_MOD}/app0/sub/sub.k - - disable_none: false - strict_range_check: false - debug: false diff --git a/test/test_units/test_kclvm/test_rpc_server/testdata/kcl-module/app0/main.k b/test/test_units/test_kclvm/test_rpc_server/testdata/kcl-module/app0/main.k deleted file mode 100644 index d8b72a0eb..000000000 --- a/test/test_units/test_kclvm/test_rpc_server/testdata/kcl-module/app0/main.k +++ /dev/null @@ -1,9 +0,0 @@ -import .sub as sub - -main1=3 - -app_name = option("app-name") -image = option("image") -deploy_topology = option("deploy-topology") - -x = deploy_topology[1] diff --git a/test/test_units/test_kclvm/test_rpc_server/testdata/kcl-module/app0/sub/sub.k b/test/test_units/test_kclvm/test_rpc_server/testdata/kcl-module/app0/sub/sub.k deleted file mode 100644 index 64d5c3823..000000000 --- a/test/test_units/test_kclvm/test_rpc_server/testdata/kcl-module/app0/sub/sub.k +++ /dev/null @@ -1 +0,0 @@ -sub1 = 2 diff --git a/test/test_units/test_kclvm/test_rpc_server/testdata/nginx.conf b/test/test_units/test_kclvm/test_rpc_server/testdata/nginx.conf deleted file mode 100644 index 349a973a2..000000000 --- a/test/test_units/test_kclvm/test_rpc_server/testdata/nginx.conf +++ /dev/null @@ -1,20 +0,0 @@ -# nginx -c ./nginx.conf - -events {} - -http { - upstream kclvm_service { - server 127.0.0.1:3021 weight=1; - server 127.0.0.1:3022 weight=1; - server 127.0.0.1:3023 weight=1; - server 127.0.0.1:3024 weight=1; - } - - server { - listen 2021; - server_name localhost; - location / { - proxy_pass http://kclvm_service; - } - } -} diff --git a/test/test_units/test_kclvm/test_rpc_server/testdata/resolve-code.json b/test/test_units/test_kclvm/test_rpc_server/testdata/resolve-code.json deleted file mode 100644 index ac6306d99..000000000 --- a/test/test_units/test_kclvm/test_rpc_server/testdata/resolve-code.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "code": "schema Data:\n foo: int = 1\n bar: str = 'ss'\n\ndata = Data {}" -} \ No newline at end of file diff --git a/test/test_units/test_kclvm/test_rpc_server/testdata/resolve-code.response.json b/test/test_units/test_kclvm/test_rpc_server/testdata/resolve-code.response.json deleted file mode 100644 index 877e5b33c..000000000 --- a/test/test_units/test_kclvm/test_rpc_server/testdata/resolve-code.response.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "result": { - "success": true - }, - "error": "" -} \ No newline at end of file diff --git a/test/test_units/test_kclvm/test_rpc_server/testdata/splice-code.json b/test/test_units/test_kclvm/test_rpc_server/testdata/splice-code.json deleted file mode 100644 index 2b796b552..000000000 --- a/test/test_units/test_kclvm/test_rpc_server/testdata/splice-code.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "codeSnippets": [ - { - "schema": "schema Person:\n age: int\n", - "rule": "age > 0" - } - ] -} diff --git a/test/test_units/test_kclvm/test_rpc_server/testdata/splice-code.response.json b/test/test_units/test_kclvm/test_rpc_server/testdata/splice-code.response.json deleted file mode 100644 index efd1f6633..000000000 --- a/test/test_units/test_kclvm/test_rpc_server/testdata/splice-code.response.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "result": { - "spliceCode": "schema Person:\n age: int\n\n check:\n age > 0\n" - }, - "error": "" -} \ No newline at end of file diff --git a/test/test_units/test_kclvm/test_rpc_server/testdata/vet-hello.json b/test/test_units/test_kclvm/test_rpc_server/testdata/vet-hello.json deleted file mode 100644 index 4997d0458..000000000 --- a/test/test_units/test_kclvm/test_rpc_server/testdata/vet-hello.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "code": "\nschema Person:\n key: str\n\n check:\n \"value\" in key # 'key' is required and 'key' must contain \"value\"\n", - "data": "{\"attr_name\": {\"key\": \"value\"}}" -} diff --git a/test/test_units/test_kclvm/test_rpc_server/testdata/vet-hello.response.json b/test/test_units/test_kclvm/test_rpc_server/testdata/vet-hello.response.json deleted file mode 100644 index e32421862..000000000 --- a/test/test_units/test_kclvm/test_rpc_server/testdata/vet-hello.response.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "result": { - "success": true, - "err_message": "" - }, - "error": "" -} \ No newline at end of file diff --git a/test/test_units/test_kclvm/test_rpc_server/testdata/vet-simple.json b/test/test_units/test_kclvm/test_rpc_server/testdata/vet-simple.json deleted file mode 100644 index 13a004f73..000000000 --- a/test/test_units/test_kclvm/test_rpc_server/testdata/vet-simple.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "code": "import regex\n\nschema Sample:\n foo: str # Required, 不能为None, 且类型必须为str\n bar: int # Required, 不能为None, 且类型必须为int\n fooList: [str] # Required, 不能为None, 且类型必须为str列表\n color: \"Red\" | \"Yellow\" | \"Blue\" # Required, 字面值联合类型,且必须为\"Red\", \"Yellow\", \"Blue\"中的一个,枚举作用\n id?: int # Optional,可以留空,类型必须为int\n \n check:\n bar >= 0 # bar必须大于等于0\n bar < 100 # bar必须小于100\n len(fooList) > 0 # fooList不能为None,并且长度必须大于0\n len(fooList) < 100 # fooList不能为None,并且长度必须小于100\n regex.match(foo, \"^The.*Foo$\") # regex 正则表达式匹配\n bar in range(100) # range, bar范围只能为1到99\n bar in [2, 4, 6, 8] # enum, bar只能取2, 4, 6, 8\n bar % 2 == 0 # bar必须为2的倍数\n abs(id) > 10 if id is not None # check if 表达式,当 id 不为空时,id的绝对值必须大于10\n", - "data": "{\"attr_name\":{\n \"foo\": \"ThehFoo\",\n \"bar\": 2,\n \"fooList\": [\n \"a\",\n \"b\"\n ],\n \"color\": \"Red\",\n \"id\": 100\n}}" -} diff --git a/test/test_units/test_kclvm/test_rpc_server/testdata/vet-simple.response.json b/test/test_units/test_kclvm/test_rpc_server/testdata/vet-simple.response.json deleted file mode 100644 index e32421862..000000000 --- a/test/test_units/test_kclvm/test_rpc_server/testdata/vet-simple.response.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "result": { - "success": true, - "err_message": "" - }, - "error": "" -} \ No newline at end of file diff --git a/test/test_units/test_kclvm/test_rpc_server/testdata/vet-single.json b/test/test_units/test_kclvm/test_rpc_server/testdata/vet-single.json deleted file mode 100644 index 2fc93142c..000000000 --- a/test/test_units/test_kclvm/test_rpc_server/testdata/vet-single.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "code": "assert mname==\"100\"", - "data": "{\"mname\": \"100\"}" -} \ No newline at end of file diff --git a/test/test_units/test_kclvm/test_rpc_server/testdata/vet-single.response.json b/test/test_units/test_kclvm/test_rpc_server/testdata/vet-single.response.json deleted file mode 100644 index e32421862..000000000 --- a/test/test_units/test_kclvm/test_rpc_server/testdata/vet-single.response.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "result": { - "success": true, - "err_message": "" - }, - "error": "" -} \ No newline at end of file diff --git a/test/test_units/test_kclvm/test_rpc_server/testdata/vet/hello.k b/test/test_units/test_kclvm/test_rpc_server/testdata/vet/hello.k deleted file mode 100644 index ecf5fd5b3..000000000 --- a/test/test_units/test_kclvm/test_rpc_server/testdata/vet/hello.k +++ /dev/null @@ -1,6 +0,0 @@ - -schema Person: - key: str - - check: - "value" in key # 'key' is required and 'key' must contain "value" diff --git a/test/test_units/test_kclvm/test_rpc_server/testdata/vet/hello.k.json b/test/test_units/test_kclvm/test_rpc_server/testdata/vet/hello.k.json deleted file mode 100644 index 9082d25ef..000000000 --- a/test/test_units/test_kclvm/test_rpc_server/testdata/vet/hello.k.json +++ /dev/null @@ -1 +0,0 @@ -{"key": "value"} \ No newline at end of file diff --git a/test/test_units/test_kclvm/test_rpc_server/testdata/vet/simple.k b/test/test_units/test_kclvm/test_rpc_server/testdata/vet/simple.k deleted file mode 100644 index 1ed734eea..000000000 --- a/test/test_units/test_kclvm/test_rpc_server/testdata/vet/simple.k +++ /dev/null @@ -1,23 +0,0 @@ -import regex -schema Sample: - foo: str # Required, 不能为None, 且类型必须为str - bar: int # Required, 不能为None, 且类型必须为int - fooList: [int] # Required, 不能为None, 且类型必须为str列表 - color: "Red" | "Yellow" | "Blue" # Required, 字面值联合类型,且必须为"Red", "Yellow", "Blue"中的一个,枚举作用 - id?: int # Optional,可以留空,类型必须为int - check: - bar >= 0 # bar必须大于等于0 - bar < 100 # bar必须小于100 - len(fooList) > 0 # fooList不能为None,并且长度必须大于0 - len(fooList) < 100 # fooList不能为None,并且长度必须小于100 - regex.match(foo, "^The.*Foo$") # regex 正则表达式匹配 - bar in range(100) # range, bar范围只能为1到99 - bar in [2, 4, 6, 8] # enum, bar只能取2, 4, 6, 8 - bar % 2 == 0 # bar必须为2的倍数 - all foo in fooList { - foo > 1 - } # fooList中的所有元素必须大于1 - any foo in fooList { - foo > 10 - } # fooList中至少有一个元素必须大于10 - abs(id) > 10 if id is not None # check if 表达式,当 id 不为空时,id的绝对值必须大于10 diff --git a/test/test_units/test_kclvm/test_rpc_server/testdata/vet/simple.k.json b/test/test_units/test_kclvm/test_rpc_server/testdata/vet/simple.k.json deleted file mode 100644 index d6d403b90..000000000 --- a/test/test_units/test_kclvm/test_rpc_server/testdata/vet/simple.k.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "foo": "good boy", - "bar": 100, - "fooList": [ - "a", - "b" - ], - "color": "Red", - "id": 100 -} \ No newline at end of file diff --git a/test/test_units/test_kclvm/test_runtime/test_lazy_eval.py b/test/test_units/test_kclvm/test_runtime/test_lazy_eval.py deleted file mode 100644 index 27ebb8a57..000000000 --- a/test/test_units/test_kclvm/test_runtime/test_lazy_eval.py +++ /dev/null @@ -1,68 +0,0 @@ -# Copyright 2021 The KCL Authors. All rights reserved. - -import unittest - -import kclvm.api.object as obj -import kclvm.vm as vm - -from kclvm.vm.runtime.evaluator import ValueCache, Backtracking - -KEY_FIELD = "key" -VALUE_FIELD = "value" - - -class KCLSchemaLazyEvalTest(unittest.TestCase): - def test_cache(self): - """Runtime cache test""" - values = [ - 1, - 1.1, - "s", - True, - False, - None, - [], - {}, - [1, 2, 3], - {"key": "value"}, - ] - cases = [ - {KEY_FIELD: KEY_FIELD + str(i), VALUE_FIELD: obj.to_kcl_obj(v)} - for i, v in enumerate(values) - ] - cache = ValueCache() - for case in cases: - cache.set(case[KEY_FIELD], case[VALUE_FIELD]) - self.assertEqual(cache.get(case[KEY_FIELD]), case[VALUE_FIELD]) - - def test_back_track(self): - name = "key" - err_name = "err" - backtracking = Backtracking() - self.assertEqual(backtracking.is_backtracking(name), False) - with backtracking.catch(name): - level = backtracking.tracking_level(name) - self.assertEqual(level, 1) - self.assertEqual(backtracking.is_backtracking(name), True) - self.assertEqual(backtracking.is_backtracking(err_name), False) - with backtracking.catch(name): - level = backtracking.tracking_level(name) - self.assertEqual(level, 2) - self.assertEqual(backtracking.is_backtracking(name), True) - with backtracking.catch(name): - level = backtracking.tracking_level(name) - self.assertEqual(level, 3) - self.assertEqual(backtracking.is_backtracking(name), True) - with backtracking.catch(name): - level = backtracking.tracking_level(name) - self.assertEqual(level, 2) - self.assertEqual(backtracking.is_backtracking(name), True) - level = backtracking.tracking_level(name) - self.assertEqual(level, 1) - self.assertEqual(backtracking.is_backtracking(name), True) - self.assertEqual(backtracking.is_backtracking(err_name), False) - self.assertEqual(backtracking.is_backtracking(name), False) - - -if __name__ == "__main__": - unittest.main(verbosity=2) diff --git a/test/test_units/test_kclvm/test_runtime/test_union.py b/test/test_units/test_kclvm/test_runtime/test_union.py deleted file mode 100644 index 205f239db..000000000 --- a/test/test_units/test_kclvm/test_runtime/test_union.py +++ /dev/null @@ -1,294 +0,0 @@ -# Copyright 2020 The KCL Authors. All rights reserved. - -import unittest - -import kclvm.kcl.ast as ast -import kclvm.kcl.error as kcl_error -import kclvm.api.object as obj -import kclvm.vm as vm -from kclvm.vm.runtime.evaluator.union import union, resolve_schema_obj - -VALUE1_KEY = "value1" -VALUE2_KEY = "value2" -EXPECTED_KEY = "expected" - - -class TestUnion(unittest.TestCase): - def get_vm(self): - app = obj.KCLProgram() - app.pkgs = {"testpkg": obj.KCLBytecode()} - app.main = "testpkg" - test_vm = vm.VirtualMachine(app=app) - test_f = vm.Frame() - test_f.locals = {} - test_f.globals = {} - test_vm.ctx = test_f - return test_vm - - def test_union(self): - cases = [ - # Left None - {VALUE1_KEY: None, VALUE2_KEY: 1, EXPECTED_KEY: 1}, - {VALUE1_KEY: None, VALUE2_KEY: 1.1, EXPECTED_KEY: 1.1}, - {VALUE1_KEY: None, VALUE2_KEY: [], EXPECTED_KEY: []}, - {VALUE1_KEY: None, VALUE2_KEY: {}, EXPECTED_KEY: {}}, - {VALUE1_KEY: None, VALUE2_KEY: "s", EXPECTED_KEY: "s"}, - {VALUE1_KEY: None, VALUE2_KEY: True, EXPECTED_KEY: True}, - {VALUE1_KEY: None, VALUE2_KEY: False, EXPECTED_KEY: False}, - {VALUE1_KEY: None, VALUE2_KEY: None, EXPECTED_KEY: None}, - # Right None - {VALUE1_KEY: 1, VALUE2_KEY: None, EXPECTED_KEY: 1}, - {VALUE1_KEY: 1.1, VALUE2_KEY: None, EXPECTED_KEY: 1.1}, - {VALUE1_KEY: [], VALUE2_KEY: None, EXPECTED_KEY: []}, - {VALUE1_KEY: {}, VALUE2_KEY: None, EXPECTED_KEY: {}}, - {VALUE1_KEY: "s", VALUE2_KEY: None, EXPECTED_KEY: "s"}, - {VALUE1_KEY: True, VALUE2_KEY: None, EXPECTED_KEY: True}, - {VALUE1_KEY: False, VALUE2_KEY: None, EXPECTED_KEY: False}, - {VALUE1_KEY: None, VALUE2_KEY: None, EXPECTED_KEY: None}, - # Int - {VALUE1_KEY: 1, VALUE2_KEY: 1, EXPECTED_KEY: 1}, - {VALUE1_KEY: 1, VALUE2_KEY: 2, EXPECTED_KEY: 2}, - {VALUE1_KEY: 1, VALUE2_KEY: 3, EXPECTED_KEY: 3}, - # Float - {VALUE1_KEY: 1.0, VALUE2_KEY: 1.0, EXPECTED_KEY: 1.0}, - {VALUE1_KEY: 1.0, VALUE2_KEY: 1.5, EXPECTED_KEY: 1.5}, - # String - {VALUE1_KEY: "s", VALUE2_KEY: "", EXPECTED_KEY: ""}, - {VALUE1_KEY: "s", VALUE2_KEY: "s", EXPECTED_KEY: "s"}, - {VALUE1_KEY: "s", VALUE2_KEY: "ss", EXPECTED_KEY: "ss"}, - # Boolean True - {VALUE1_KEY: True, VALUE2_KEY: True, EXPECTED_KEY: True}, - {VALUE1_KEY: True, VALUE2_KEY: False, EXPECTED_KEY: False}, - # Boolean False - {VALUE1_KEY: False, VALUE2_KEY: False, EXPECTED_KEY: False}, - {VALUE1_KEY: False, VALUE2_KEY: True, EXPECTED_KEY: True}, - # List - {VALUE1_KEY: [], VALUE2_KEY: [], EXPECTED_KEY: []}, - {VALUE1_KEY: [], VALUE2_KEY: [1], EXPECTED_KEY: [1]}, - {VALUE1_KEY: [], VALUE2_KEY: [1, 2], EXPECTED_KEY: [1, 2]}, - {VALUE1_KEY: [1], VALUE2_KEY: [1], EXPECTED_KEY: [1]}, - {VALUE1_KEY: [1], VALUE2_KEY: [2], EXPECTED_KEY: [2]}, - {VALUE1_KEY: [1], VALUE2_KEY: [2, 2], EXPECTED_KEY: [2, 2]}, - {VALUE1_KEY: [1, 2], VALUE2_KEY: [3, 4], EXPECTED_KEY: [3, 4]}, - {VALUE1_KEY: [1, 2, 3], VALUE2_KEY: [3, 4], EXPECTED_KEY: [3, 4, 3]}, - { - VALUE1_KEY: [{"key1": "value1"}], - VALUE2_KEY: [{"key1": "value1"}], - EXPECTED_KEY: [{"key1": "value1"}], - }, - { - VALUE1_KEY: [{"key1": "value1"}], - VALUE2_KEY: [{"key1": "value2"}], - EXPECTED_KEY: [{"key1": "value2"}], - }, - { - VALUE1_KEY: [{"key1": "value1"}], - VALUE2_KEY: [{"key2": "value2"}], - EXPECTED_KEY: [{"key1": "value1", "key2": "value2"}], - }, - { - VALUE1_KEY: [{"key1": "value1"}], - VALUE2_KEY: [{"key1": "value1", "key2": "value2"}], - EXPECTED_KEY: [{"key1": "value1", "key2": "value2"}], - }, - { - VALUE1_KEY: [{"key1": "value1"}], - VALUE2_KEY: [{"key2": "value2", "key1": "value1"}], - EXPECTED_KEY: [{"key1": "value1", "key2": "value2"}], - }, - { - VALUE1_KEY: [{"key1": "value1", "key2": "value2"}], - VALUE2_KEY: [{"key1": "value1"}], - EXPECTED_KEY: [{"key1": "value1", "key2": "value2"}], - }, - # Dict - {VALUE1_KEY: {}, VALUE2_KEY: {}, EXPECTED_KEY: {}}, - { - VALUE1_KEY: {}, - VALUE2_KEY: {"key1": "value1"}, - EXPECTED_KEY: {"key1": "value1"}, - }, - { - VALUE1_KEY: {"key1": "value1"}, - VALUE2_KEY: {}, - EXPECTED_KEY: {"key1": "value1"}, - }, - { - VALUE1_KEY: {"key1": "value1"}, - VALUE2_KEY: {"key1": "value1"}, - EXPECTED_KEY: {"key1": "value1"}, - }, - { - VALUE1_KEY: {"key1": "value1"}, - VALUE2_KEY: {"key1": "value1", "key2": "value2"}, - EXPECTED_KEY: {"key1": "value1", "key2": "value2"}, - }, - { - VALUE1_KEY: {"key1": "value1", "key2": "value2"}, - VALUE2_KEY: {"key1": "value1"}, - EXPECTED_KEY: {"key1": "value1", "key2": "value2"}, - }, - { - VALUE1_KEY: {"s": {"key1": "value1"}}, - VALUE2_KEY: {"s": {"key1": "value1", "key2": "value2"}}, - EXPECTED_KEY: {"s": {"key1": "value1", "key2": "value2"}}, - }, - { - VALUE1_KEY: {"s": {"key1": "value1", "key2": "value2"}}, - VALUE2_KEY: {"s": {"key1": "value1"}}, - EXPECTED_KEY: {"s": {"key1": "value1", "key2": "value2"}}, - }, - { - VALUE1_KEY: {"key2": "value2", "key1": "value1"}, - VALUE2_KEY: {"key1": "value1", "key2": "value2"}, - EXPECTED_KEY: {"key1": "value1", "key2": "value2"}, - }, - { - VALUE1_KEY: {"key2": "value2", "key1": "value1"}, - VALUE2_KEY: {"key1": "value1", "key2": "value2"}, - EXPECTED_KEY: {"key1": "value1", "key2": "value2"}, - }, - ] - for case in cases: - try: - value1 = obj.to_kcl_obj(case[VALUE1_KEY]) - value2 = obj.to_kcl_obj(case[VALUE2_KEY]) - union_value = obj.to_python_obj(union(value1, value2)) - expected = obj.to_python_obj(case[EXPECTED_KEY]) - self.assertEqual(union_value, expected) - except AssertionError as err: - print( - f"Assert fail between the value1 {value1} and the value2 {value2}" - ) - raise err - - def test_union_with_idempotent_check(self): - cases = [ - { - VALUE1_KEY: obj.KCLSchemaConfigObject( - value=obj.to_kcl_obj({"key": [0]}).value, - ), - VALUE2_KEY: obj.KCLSchemaConfigObject( - value=obj.to_kcl_obj({"key": [1]}).value, - operation_map={"key": ast.ConfigEntryOperation.INSERT}, - insert_index_map={"key": -1}, - ), - EXPECTED_KEY: {"key": [0, 1]}, - }, - { - VALUE1_KEY: obj.KCLSchemaConfigObject( - value=obj.to_kcl_obj({"key": [0]}).value, - ), - VALUE2_KEY: obj.KCLSchemaConfigObject( - value=obj.to_kcl_obj({"key": 1}).value, - operation_map={"key": ast.ConfigEntryOperation.INSERT}, - insert_index_map={"key": 0}, - ), - EXPECTED_KEY: {"key": [1, 0]}, - }, - { - VALUE1_KEY: obj.KCLSchemaObject( - attrs=obj.to_kcl_obj({"key": [0]}).value, - ), - VALUE2_KEY: obj.KCLSchemaObject( - attrs=obj.to_kcl_obj({"key": 1}).value, - operation_map={"key": ast.ConfigEntryOperation.INSERT}, - insert_index_map={"key": 0}, - ), - EXPECTED_KEY: {"key": [1, 0]}, - }, - { - VALUE1_KEY: obj.KCLSchemaObject( - attrs=obj.to_kcl_obj({"key": [0]}).value, - ), - VALUE2_KEY: obj.KCLSchemaObject( - attrs=obj.to_kcl_obj({"key": [1]}).value, - operation_map={"key": ast.ConfigEntryOperation.OVERRIDE}, - ), - EXPECTED_KEY: {"key": [1]}, - }, - { - VALUE1_KEY: obj.KCLSchemaObject( - attrs=obj.to_kcl_obj({"key": [0, 1]}).value, - operation_map={"key": ast.ConfigEntryOperation.OVERRIDE}, - ), - VALUE2_KEY: obj.KCLSchemaObject( - attrs=obj.to_kcl_obj({"key": obj.Undefined}).value, - operation_map={"key": ast.ConfigEntryOperation.OVERRIDE}, - insert_index_map={"key": 0}, - ), - EXPECTED_KEY: {"key": [1]}, - }, - ] - invalid_cases = [ - { - VALUE1_KEY: {"key": 1}, - VALUE2_KEY: {"key": 2}, - }, - { - VALUE1_KEY: {"key": 1.0}, - VALUE2_KEY: {"key": 2.0}, - }, - { - VALUE1_KEY: {"key": True}, - VALUE2_KEY: {"key": False}, - }, - { - VALUE1_KEY: obj.KCLSchemaConfigObject( - value=obj.to_kcl_obj({"key": [0]}).value, - ), - VALUE2_KEY: obj.KCLSchemaConfigObject( - value=obj.to_kcl_obj({"key": [1]}).value, - ), - }, - { - VALUE1_KEY: obj.KCLSchemaObject( - attrs=obj.to_kcl_obj({"key": [0]}).value, - ), - VALUE2_KEY: obj.KCLSchemaObject( - attrs=obj.to_kcl_obj({"key": [1]}).value, - ), - }, - ] - for case in cases: - try: - value1 = obj.to_kcl_obj(case[VALUE1_KEY]) - value2 = obj.to_kcl_obj(case[VALUE2_KEY]) - union_value = obj.to_python_obj( - union(value1, value2, should_idempotent_check=True) - ) - expected = obj.to_python_obj(case[EXPECTED_KEY]) - self.assertEqual(union_value, expected) - except AssertionError as err: - print( - f"Assert fail between the value1 {value1} and the value2 {value2}" - ) - raise err - for case in invalid_cases: - value1 = obj.to_kcl_obj(case[VALUE1_KEY]) - value2 = obj.to_kcl_obj(case[VALUE2_KEY]) - with self.assertRaises(kcl_error.KCLException): - union(value1, value2, should_idempotent_check=True) - - def test_resolve_schema_obj(self): - cases = [ - {"schema_obj": None, "keys": None, "vm": None, "expected": None}, - { - "schema_obj": obj.KCLSchemaObject(name="Person"), - "keys": set(), - "vm": self.get_vm(), - "expected": obj.KCLSchemaObject(name="Person"), - }, - ] - for case in cases: - schema_obj, keys, vm, expected = ( - case["schema_obj"], - case["keys"], - case["vm"], - case["expected"], - ) - self.assertEqual(resolve_schema_obj(schema_obj, keys, vm), expected) - - -if __name__ == "__main__": - unittest.main(verbosity=2) diff --git a/test/test_units/test_kclvm/test_tools/test_doc/doc_data/docs/docs_markdown_base_schema_pkg_en/base_schema_pkg/base/doc_person_en.md b/test/test_units/test_kclvm/test_tools/test_doc/doc_data/docs/docs_markdown_base_schema_pkg_en/base_schema_pkg/base/doc_person_en.md deleted file mode 100644 index 4bf12d7db..000000000 --- a/test/test_units/test_kclvm/test_tools/test_doc/doc_data/docs/docs_markdown_base_schema_pkg_en/base_schema_pkg/base/doc_person_en.md +++ /dev/null @@ -1,13 +0,0 @@ -# person - -Source: [base_schema_pkg/base/person.k](https://url/to/source_code/base_schema_pkg/base/person.k) - -## Schema Person - -### Attributes - -|Name and Description|Type|Default Value|Required| -|--------------------|----|-------------|--------| -|**name**|str|Undefined|**required**| -|**age**|int|Undefined|**required**| - diff --git a/test/test_units/test_kclvm/test_tools/test_doc/doc_data/docs/docs_markdown_base_schema_pkg_en/base_schema_pkg/sub/doc_student_en.md b/test/test_units/test_kclvm/test_tools/test_doc/doc_data/docs/docs_markdown_base_schema_pkg_en/base_schema_pkg/sub/doc_student_en.md deleted file mode 100644 index eb757e9b8..000000000 --- a/test/test_units/test_kclvm/test_tools/test_doc/doc_data/docs/docs_markdown_base_schema_pkg_en/base_schema_pkg/sub/doc_student_en.md +++ /dev/null @@ -1,17 +0,0 @@ -# student - -Source: [base_schema_pkg/sub/student.k](https://url/to/source_code/base_schema_pkg/sub/student.k) - -## Schema Student - -Student is the person with a grade - -### Base Schema -[@base_schema_pkg.base.Person](../base/doc_person_en#schema-person) - -### Attributes - -|Name and Description|Type|Default Value|Required| -|--------------------|----|-------------|--------| -|**grade**
    the current grade that the student is in.|int|Undefined|**required**| - diff --git a/test/test_units/test_kclvm/test_tools/test_doc/doc_data/docs/docs_markdown_config_map_en/config_map/core/doc_metadata_en.md b/test/test_units/test_kclvm/test_tools/test_doc/doc_data/docs/docs_markdown_config_map_en/config_map/core/doc_metadata_en.md deleted file mode 100644 index 126f9794e..000000000 --- a/test/test_units/test_kclvm/test_tools/test_doc/doc_data/docs/docs_markdown_config_map_en/config_map/core/doc_metadata_en.md +++ /dev/null @@ -1,17 +0,0 @@ -# metadata - -Source: [config_map/core/metadata.k](https://url/to/source_code/config_map/core/metadata.k) - -## Schema Metadata - -Metadata is the base schema of all models, which contains data
    that helps uniquely identify the object. - -### Attributes - -|Name and Description|Type|Default Value|Required| -|--------------------|----|-------------|--------| -|**name**
    The name of the resource.
    Name must be unique within a namespace. It's required when creating
    resources, although some resources may allow a client to request the
    generation of an appropriate name automatically.
    Name is primarily intended for creation idempotence and configuration
    definition. Cannot be updated. More info:
    http://kubernetes.io/docs/user-guide/identifiers\#names|str|Undefined|**required**| -|**labels**
    Labels is a map of string keys and values that can be used to
    organize and categorize (scope and select) objects.
    May match selectors of replication controllers and services.
    More info: http://kubernetes.io/docs/user-guide/labels|{str: str}|Undefined|optional| -|**annotations**
    Annotations is an unstructured key value map stored with a
    resource that may be set by external tools to store and retrieve
    arbitrary metadata. They are not queryable and should be preserved
    when modifying objects.
    More info: http://kubernetes.io/docs/user-guide/annotations|{str: str}|Undefined|optional| -|**namespace**
    Namespaces are intended for use in environments with many users spread
    across multiple teams, or projects.
    For clusters with a few to tens of users, you should not need to create
    or think about namespaces at all. Start using namespaces when you need the features they provide.
    More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/|str|Undefined|optional| - diff --git a/test/test_units/test_kclvm/test_tools/test_doc/doc_data/docs/docs_markdown_config_map_en/config_map/core/v1/doc_config_map_en.md b/test/test_units/test_kclvm/test_tools/test_doc/doc_data/docs/docs_markdown_config_map_en/config_map/core/v1/doc_config_map_en.md deleted file mode 100644 index b0d46f892..000000000 --- a/test/test_units/test_kclvm/test_tools/test_doc/doc_data/docs/docs_markdown_config_map_en/config_map/core/v1/doc_config_map_en.md +++ /dev/null @@ -1,16 +0,0 @@ -# config_map - -Source: [config_map/core/v1/config_map.k](https://url/to/source_code/config_map/core/v1/config_map.k) - -## Schema ConfigMap - -### Base Schema -[@config_map.core.metadata.Metadata](../doc_metadata_en#schema-metadata) - -### Attributes - -|Name and Description|Type|Default Value|Required| -|--------------------|----|-------------|--------| -|**data**|{str: str}|Undefined|optional| -|**binaryData**|{str: str}|Undefined|optional| - diff --git a/test/test_units/test_kclvm/test_tools/test_doc/doc_data/docs/docs_markdown_frontend_zh_cn/frontend/doc_container_zh_cn.md b/test/test_units/test_kclvm/test_tools/test_doc/doc_data/docs/docs_markdown_frontend_zh_cn/frontend/doc_container_zh_cn.md deleted file mode 100644 index 907995b18..000000000 --- a/test/test_units/test_kclvm/test_tools/test_doc/doc_data/docs/docs_markdown_frontend_zh_cn/frontend/doc_container_zh_cn.md +++ /dev/null @@ -1,23 +0,0 @@ -# container - -## Schema Container - -在 pod 中运行的单应用容器 - -### Attributes - -|Name and Description|Type|Default Value|Required| -|--------------------|----|-------------|--------| -|**image**
    Docker 镜像名称|str|Undefined|**required**| -|**ports**
    容器对外暴露的端口列表|[frontend.ContainerPort]|Undefined|optional| -## Schema ContainerPort - -ContainerPort 表示单个容器中的一个网络端口 - -### Attributes - -|Name and Description|Type|Default Value|Required| -|--------------------|----|-------------|--------| -|**port**
    在 pod IP 地址上暴露的端口号。必须是合法的端口号:介于 0 和 65536 之间(不包含)|int|Undefined|**required**| -|**protocol**
    端口协议,合法取值有:"UDP","TCP","SCTP"|"TCP" | "UDP" | "SCTP"|"TCP"|**required**| - diff --git a/test/test_units/test_kclvm/test_tools/test_doc/doc_data/docs/docs_markdown_frontend_zh_cn/frontend/doc_server_zh_cn.md b/test/test_units/test_kclvm/test_tools/test_doc/doc_data/docs/docs_markdown_frontend_zh_cn/frontend/doc_server_zh_cn.md deleted file mode 100644 index e2f572e6b..000000000 --- a/test/test_units/test_kclvm/test_tools/test_doc/doc_data/docs/docs_markdown_frontend_zh_cn/frontend/doc_server_zh_cn.md +++ /dev/null @@ -1,15 +0,0 @@ -# server - -## Schema Server - -Server 定义了经典的长连接服务 - -### Attributes - -|Name and Description|Type|Default Value|Required| -|--------------------|----|-------------|--------| -|**name**
    server 的名称|str|Undefined|**required**| -|**workloadType**
    工作负载的类型|"Deployment" | "StatefulSet" | "DaemonSet"|"Deployment"|**required**| -|**replica**
    目标副本数|int|1|**required**| -|**mainContainer**
    主容器|Container|Undefined|**required**| - diff --git a/test/test_units/test_kclvm/test_tools/test_doc/doc_data/docs/docs_markdown_import_pkg_en/import_pkg/apis/doc_label_selector_en.md b/test/test_units/test_kclvm/test_tools/test_doc/doc_data/docs/docs_markdown_import_pkg_en/import_pkg/apis/doc_label_selector_en.md deleted file mode 100644 index 3fec3ab69..000000000 --- a/test/test_units/test_kclvm/test_tools/test_doc/doc_data/docs/docs_markdown_import_pkg_en/import_pkg/apis/doc_label_selector_en.md +++ /dev/null @@ -1,16 +0,0 @@ -# label_selector - -Source: [import_pkg/apis/label_selector.k](https://url/to/source_code/import_pkg/apis/label_selector.k) - -This is the label\_selector module in kusion\_kubernetes.apimachinery.apis package.
    This file was generated by the KCL auto-gen tool. DO NOT EDIT.
    Editing this file might prove futile when you re-run the KCL auto-gen generate command. - -## Schema LabelSelector - -A label selector is a label query over a set of resources. The result of matchLabels and matchExpressions are ANDed. An empty label selector matches all objects. A null label selector matches no objects. - -### Attributes - -|Name and Description|Type|Default Value|Required| -|--------------------|----|-------------|--------| -|**matchLabels**
    matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed.|{str: str}|Undefined|optional| - diff --git a/test/test_units/test_kclvm/test_tools/test_doc/doc_data/docs/docs_markdown_import_pkg_en/import_pkg/apis/doc_object_meta_en.md b/test/test_units/test_kclvm/test_tools/test_doc/doc_data/docs/docs_markdown_import_pkg_en/import_pkg/apis/doc_object_meta_en.md deleted file mode 100644 index 0ba6ae800..000000000 --- a/test/test_units/test_kclvm/test_tools/test_doc/doc_data/docs/docs_markdown_import_pkg_en/import_pkg/apis/doc_object_meta_en.md +++ /dev/null @@ -1,29 +0,0 @@ -# object_meta - -Source: [import_pkg/apis/object_meta.k](https://url/to/source_code/import_pkg/apis/object_meta.k) - -This is the object\_meta module in kusion\_kubernetes.apimachinery.apis package.
    This file was generated by the KCL auto-gen tool. DO NOT EDIT.
    Editing this file might prove futile when you re-run the KCL auto-gen generate command. - -## Schema ObjectMeta - -ObjectMeta is metadata that all persisted resources must have, which includes all objects users must create. - -### Attributes - -|Name and Description|Type|Default Value|Required| -|--------------------|----|-------------|--------| -|**annotations**
    Annotations is an unstructured key value map stored with a resource that may be set by external tools to store and retrieve arbitrary metadata. They are not queryable and should be preserved when modifying objects. More info: http://kubernetes.io/docs/user-guide/annotations|{str: str}|Undefined|optional| -|**clusterName**
    The name of the cluster which the object belongs to. This is used to distinguish resources with same name and namespace in different clusters. This field is not set anywhere right now and apiserver is going to ignore it if set in create or update request.|str|Undefined|optional| -|**creationTimestamp**
    CreationTimestamp is a timestamp representing the server time when this object was created. It is not guaranteed to be set in happens-before order across separate operations. Clients may not set this value. It is represented in RFC3339 form and is in UTC. Populated by the system. Read-only. Null for lists. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md\#metadata|str|Undefined|optional| -|**deletionGracePeriodSeconds**
    Number of seconds allowed for this object to gracefully terminate before it will be removed from the system. Only set when deletionTimestamp is also set. May only be shortened. Read-only.|int|Undefined|optional| -|**deletionTimestamp**
    DeletionTimestamp is RFC 3339 date and time at which this resource will be deleted. This field is set by the server when a graceful deletion is requested by the user, and is not directly settable by a client. The resource is expected to be deleted (no longer visible from resource lists, and not reachable by name) after the time in this field, once the finalizers list is empty. As long as the finalizers list contains items, deletion is blocked. Once the deletionTimestamp is set, this value may not be unset or be set further into the future, although it may be shortened or the resource may be deleted prior to this time. For example, a user may request that a pod is deleted in 30 seconds. The Kubelet will react by sending a graceful termination signal to the containers in the pod. After that 30 seconds, the Kubelet will send a hard termination signal (SIGKILL) to the container and after cleanup, remove the pod from the API. In the presence of network partitions, this object may still exist after this timestamp, until an administrator or automated process can determine the resource is fully terminated. If not set, graceful deletion of the object has not been requested. Populated by the system when a graceful deletion is requested. Read-only. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md\#metadata|str|Undefined|optional| -|**finalizers**
    Must be empty before the object is deleted from the registry. Each entry is an identifier for the responsible component that will remove the entry from the list. If the deletionTimestamp of the object is non-nil, entries in this list can only be removed. Finalizers may be processed and removed in any order. Order is NOT enforced because it introduces significant risk of stuck finalizers. finalizers is a shared field, any actor with permission can reorder it. If the finalizer list is processed in order, then this can lead to a situation in which the component responsible for the first finalizer in the list is waiting for a signal (field value, external system, or other) produced by a component responsible for a finalizer later in the list, resulting in a deadlock. Without enforced ordering finalizers are free to order amongst themselves and are not vulnerable to ordering changes in the list.|[str]|Undefined|optional| -|**generateName**
    GenerateName is an optional prefix, used by the server, to generate a unique name ONLY IF the Name field has not been provided. If this field is used, the name returned to the client will be different than the name passed. This value will also be combined with a unique suffix. The provided value has the same validation rules as the Name field, and may be truncated by the length of the suffix required to make the value unique on the server. If this field is specified and the generated name exists, the server will NOT return a 409 - instead, it will either return 201 Created or 500 with Reason ServerTimeout indicating a unique name could not be found in the time allotted, and the client should retry (optionally after the time indicated in the Retry-After header). Applied only if Name is not specified. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md\#idempotency|str|Undefined|optional| -|**generation**
    A sequence number representing a specific generation of the desired state. Populated by the system. Read-only.|int|Undefined|optional| -|**labels**
    Map of string keys and values that can be used to organize and categorize (scope and select) objects. May match selectors of replication controllers and services. More info: http://kubernetes.io/docs/user-guide/labels|{str: str}|Undefined|optional| -|**name**
    Name must be unique within a namespace. Is required when creating resources, although some resources may allow a client to request the generation of an appropriate name automatically. Name is primarily intended for creation idempotence and configuration definition. Cannot be updated. More info: http://kubernetes.io/docs/user-guide/identifiers\#names|str|Undefined|optional| -|**namespace**
    Namespace defines the space within which each name must be unique. An empty namespace is equivalent to the "default" namespace, but "default" is the canonical representation. Not all objects are required to be scoped to a namespace - the value of this field for those objects will be empty. Must be a DNS\_LABEL. Cannot be updated. More info: http://kubernetes.io/docs/user-guide/namespaces|str|Undefined|optional| -|**resourceVersion**
    An opaque value that represents the internal version of this object that can be used by clients to determine when objects have changed. May be used for optimistic concurrency, change detection, and the watch operation on a resource or set of resources. Clients must treat these values as opaque and passed unmodified back to the server. They may only be valid for a particular resource or set of resources. Populated by the system. Read-only. Value must be treated as opaque by clients and . More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md\#concurrency-control-and-consistency|str|Undefined|optional| -|**selfLink**
    SelfLink is a URL representing this object. Populated by the system. Read-only. DEPRECATED Kubernetes will stop propagating this field in 1.20 release and the field is planned to be removed in 1.21 release.|str|Undefined|optional| -|**uid**
    UID is the unique in time and space value for this object. It is typically generated by the server on successful creation of a resource and is not allowed to change on PUT operations. Populated by the system. Read-only. More info: http://kubernetes.io/docs/user-guide/identifiers\#uids|str|Undefined|optional| - diff --git a/test/test_units/test_kclvm/test_tools/test_doc/doc_data/docs/docs_markdown_import_pkg_en/import_pkg/apps/doc_deployment_en.md b/test/test_units/test_kclvm/test_tools/test_doc/doc_data/docs/docs_markdown_import_pkg_en/import_pkg/apps/doc_deployment_en.md deleted file mode 100644 index cc6779352..000000000 --- a/test/test_units/test_kclvm/test_tools/test_doc/doc_data/docs/docs_markdown_import_pkg_en/import_pkg/apps/doc_deployment_en.md +++ /dev/null @@ -1,19 +0,0 @@ -# deployment - -Source: [import_pkg/apps/deployment.k](https://url/to/source_code/import_pkg/apps/deployment.k) - -This is the deployment module in kusion\_kubernetes.api.apps.v1 package.
    This file was generated by the KCL auto-gen tool. DO NOT EDIT.
    Editing this file might prove futile when you re-run the KCL auto-gen generate command. - -## Schema Deployment - -Deployment enables declarative updates for Pods and ReplicaSets. - -### Attributes - -|Name and Description|Type|Default Value|Required| -|--------------------|----|-------------|--------| -|**apiVersion**
    APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md\#resources|"apps/v1"|"apps/v1"|**required**| -|**kind**
    Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md\#types-kinds|"Deployment"|"Deployment"|**required**| -|**metadata**
    Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md\#metadata|[apis.ObjectMeta](../apis/doc_object_meta_en#schema-objectmeta)|Undefined|optional| -|**spec**
    Specification of the desired behavior of the Deployment.|[DeploymentSpec](doc_deployment_spec_en#schema-deploymentspec)|Undefined|optional| - diff --git a/test/test_units/test_kclvm/test_tools/test_doc/doc_data/docs/docs_markdown_import_pkg_en/import_pkg/apps/doc_deployment_spec_en.md b/test/test_units/test_kclvm/test_tools/test_doc/doc_data/docs/docs_markdown_import_pkg_en/import_pkg/apps/doc_deployment_spec_en.md deleted file mode 100644 index af0fd770b..000000000 --- a/test/test_units/test_kclvm/test_tools/test_doc/doc_data/docs/docs_markdown_import_pkg_en/import_pkg/apps/doc_deployment_spec_en.md +++ /dev/null @@ -1,23 +0,0 @@ -# deployment_spec - -Source: [import_pkg/apps/deployment_spec.k](https://url/to/source_code/import_pkg/apps/deployment_spec.k) - -This is the deployment\_spec module in kusion\_kubernetes.api.apps.v1 package.
    This file was generated by the KCL auto-gen tool. DO NOT EDIT.
    Editing this file might prove futile when you re-run the KCL auto-gen generate command. - -## Schema DeploymentSpec - -DeploymentSpec is the specification of the desired behavior of the Deployment. - -### Attributes - -|Name and Description|Type|Default Value|Required| -|--------------------|----|-------------|--------| -|**minReadySeconds**
    Minimum number of seconds for which a newly created pod should be ready without any of its container crashing, for it to be considered available. Defaults to 0 (pod will be considered available as soon as it is ready)|int|Undefined|optional| -|**paused**
    Indicates that the deployment is paused.|bool|Undefined|optional| -|**progressDeadlineSeconds**
    The maximum time in seconds for a deployment to make progress before it is considered to be failed. The deployment controller will continue to process failed deployments and a condition with a ProgressDeadlineExceeded reason will be surfaced in the deployment status. Note that progress will not be estimated during the time a deployment is paused. Defaults to 600s.|int|Undefined|optional| -|**replicas**
    Number of desired pods. This is a pointer to distinguish between explicit zero and not specified. Defaults to 1.|int|Undefined|optional| -|**revisionHistoryLimit**
    The number of old ReplicaSets to retain to allow rollback. This is a pointer to distinguish between explicit zero and not specified. Defaults to 10.|int|Undefined|optional| -|**selector**
    Label selector for pods. Existing ReplicaSets whose pods are selected by this will be the ones affected by this deployment. It must match the pod template's labels.|[apis.LabelSelector](../apis/doc_label_selector_en#schema-labelselector)|Undefined|**required**| -|**strategy**
    The deployment strategy to use to replace existing pods with new ones.|[DeploymentStrategy](doc_deployment_strategy_en#schema-deploymentstrategy)|Undefined|optional| -|**template**
    Template describes the pods that will be created.|[core.PodTemplateSpec](../core/doc_pod_template_spec_en#schema-podtemplatespec)|Undefined|**required**| - diff --git a/test/test_units/test_kclvm/test_tools/test_doc/doc_data/docs/docs_markdown_import_pkg_en/import_pkg/apps/doc_deployment_strategy_en.md b/test/test_units/test_kclvm/test_tools/test_doc/doc_data/docs/docs_markdown_import_pkg_en/import_pkg/apps/doc_deployment_strategy_en.md deleted file mode 100644 index 74d7ede7a..000000000 --- a/test/test_units/test_kclvm/test_tools/test_doc/doc_data/docs/docs_markdown_import_pkg_en/import_pkg/apps/doc_deployment_strategy_en.md +++ /dev/null @@ -1,17 +0,0 @@ -# deployment_strategy - -Source: [import_pkg/apps/deployment_strategy.k](https://url/to/source_code/import_pkg/apps/deployment_strategy.k) - -This is the deployment\_strategy module in kusion\_kubernetes.api.apps.v1 package.
    This file was generated by the KCL auto-gen tool. DO NOT EDIT.
    Editing this file might prove futile when you re-run the KCL auto-gen generate command. - -## Schema DeploymentStrategy - -DeploymentStrategy describes how to replace existing pods with new ones. - -### Attributes - -|Name and Description|Type|Default Value|Required| -|--------------------|----|-------------|--------| -|**type**
    Type of deployment. Can be "Recreate" or "RollingUpdate". Default is RollingUpdate.|str|Undefined|optional| -|**rollingUpdate**
    Rolling update config params. Present only if DeploymentStrategyType = RollingUpdate.|[RollingUpdateDeployment](doc_rolling_update_deployment_en#schema-rollingupdatedeployment)|Undefined|optional| - diff --git a/test/test_units/test_kclvm/test_tools/test_doc/doc_data/docs/docs_markdown_import_pkg_en/import_pkg/apps/doc_rolling_update_deployment_en.md b/test/test_units/test_kclvm/test_tools/test_doc/doc_data/docs/docs_markdown_import_pkg_en/import_pkg/apps/doc_rolling_update_deployment_en.md deleted file mode 100644 index 0c88f53bd..000000000 --- a/test/test_units/test_kclvm/test_tools/test_doc/doc_data/docs/docs_markdown_import_pkg_en/import_pkg/apps/doc_rolling_update_deployment_en.md +++ /dev/null @@ -1,17 +0,0 @@ -# rolling_update_deployment - -Source: [import_pkg/apps/rolling_update_deployment.k](https://url/to/source_code/import_pkg/apps/rolling_update_deployment.k) - -This is the rolling\_update\_deployment module in kusion\_kubernetes.api.apps.v1 package.
    This file was generated by the KCL auto-gen tool. DO NOT EDIT.
    Editing this file might prove futile when you re-run the KCL auto-gen generate command. - -## Schema RollingUpdateDeployment - -Spec to control the desired behavior of rolling update. - -### Attributes - -|Name and Description|Type|Default Value|Required| -|--------------------|----|-------------|--------| -|**maxSurge**
    The maximum number of pods that can be scheduled above the desired number of pods. Value can be an absolute number (ex: 5) or a percentage of desired pods (ex: 10%). This can not be 0 if MaxUnavailable is 0. Absolute number is calculated from percentage by rounding up. Defaults to 25%. Example: when this is set to 30%, the new ReplicaSet can be scaled up immediately when the rolling update starts, such that the total number of old and new pods do not exceed 130% of desired pods. Once old pods have been killed, new ReplicaSet can be scaled up further, ensuring that total number of pods running at any time during the update is at most 130% of desired pods.|int \| str|Undefined|optional| -|**maxUnavailable**
    The maximum number of pods that can be unavailable during the update. Value can be an absolute number (ex: 5) or a percentage of desired pods (ex: 10%). Absolute number is calculated from percentage by rounding down. This can not be 0 if MaxSurge is 0. Defaults to 25%. Example: when this is set to 30%, the old ReplicaSet can be scaled down to 70% of desired pods immediately when the rolling update starts. Once new pods are ready, old ReplicaSet can be scaled down further, followed by scaling up the new ReplicaSet, ensuring that the total number of pods available at all times during the update is at least 70% of desired pods.|int \| str|Undefined|optional| - diff --git a/test/test_units/test_kclvm/test_tools/test_doc/doc_data/docs/docs_markdown_import_pkg_en/import_pkg/core/doc_pod_spec_en.md b/test/test_units/test_kclvm/test_tools/test_doc/doc_data/docs/docs_markdown_import_pkg_en/import_pkg/core/doc_pod_spec_en.md deleted file mode 100644 index 12f43bb4c..000000000 --- a/test/test_units/test_kclvm/test_tools/test_doc/doc_data/docs/docs_markdown_import_pkg_en/import_pkg/core/doc_pod_spec_en.md +++ /dev/null @@ -1,38 +0,0 @@ -# pod_spec - -Source: [import_pkg/core/pod_spec.k](https://url/to/source_code/import_pkg/core/pod_spec.k) - -This is the pod\_spec module in kusion\_kubernetes.api.core.v1 package.
    This file was generated by the KCL auto-gen tool. DO NOT EDIT.
    Editing this file might prove futile when you re-run the KCL auto-gen generate command. - -## Schema PodSpec - -PodSpec is a description of a pod. - -### Attributes - -|Name and Description|Type|Default Value|Required| -|--------------------|----|-------------|--------| -|**activeDeadlineSeconds**
    Optional duration in seconds the pod may be active on the node relative to StartTime before the system will actively try to mark it failed and kill associated containers. Value must be a positive integer.|int|Undefined|optional| -|**automountServiceAccountToken**
    AutomountServiceAccountToken indicates whether a service account token should be automatically mounted.|bool|Undefined|optional| -|**dnsPolicy**
    Set DNS policy for the pod. Defaults to "ClusterFirst". Valid values are 'ClusterFirstWithHostNet', 'ClusterFirst', 'Default' or 'None'. DNS parameters given in DNSConfig will be merged with the policy selected with DNSPolicy. To have DNS options set along with hostNetwork, you have to specify DNS policy explicitly to 'ClusterFirstWithHostNet'.|str|Undefined|optional| -|**enableServiceLinks**
    EnableServiceLinks indicates whether information about services should be injected into pod's environment variables, matching the syntax of Docker links. Optional: Defaults to true.|bool|Undefined|optional| -|**hostIPC**
    Use the host's ipc namespace. Optional: Default to false.|bool|Undefined|optional| -|**hostNetwork**
    Host networking requested for this pod. Use the host's network namespace. If this option is set, the ports that will be used must be specified. Default to false.|bool|Undefined|optional| -|**hostPID**
    Use the host's pid namespace. Optional: Default to false.|bool|Undefined|optional| -|**hostname**
    Specifies the hostname of the Pod If not specified, the pod's hostname will be set to a system-defined value.|str|Undefined|optional| -|**nodeName**
    NodeName is a request to schedule this pod onto a specific node. If it is non-empty, the scheduler simply schedules this pod onto that node, assuming that it fits resource requirements.|str|Undefined|optional| -|**nodeSelector**
    NodeSelector is a selector which must be true for the pod to fit on a node. Selector which must match a node's labels for the pod to be scheduled on that node. More info: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/|{str: str}|Undefined|optional| -|**overhead**
    Overhead represents the resource overhead associated with running a pod for a given RuntimeClass. This field will be autopopulated at admission time by the RuntimeClass admission controller. If the RuntimeClass admission controller is enabled, overhead must not be set in Pod create requests. The RuntimeClass admission controller will reject Pod create requests which have the overhead already set. If RuntimeClass is configured and selected in the PodSpec, Overhead will be set to the value defined in the corresponding RuntimeClass, otherwise it will remain unset and treated as zero. More info: https://git.k8s.io/enhancements/keps/sig-node/688-pod-overhead/README.md This field is beta-level as of Kubernetes v1.18, and is only honored by servers that enable the PodOverhead feature.|{str: str}|Undefined|optional| -|**preemptionPolicy**
    PreemptionPolicy is the Policy for preempting pods with lower priority. One of Never, PreemptLowerPriority. Defaults to PreemptLowerPriority if unset. This field is beta-level, gated by the NonPreemptingPriority feature-gate.|str|Undefined|optional| -|**priority**
    The priority value. Various system components use this field to find the priority of the pod. When Priority Admission Controller is enabled, it prevents users from setting this field. The admission controller populates this field from PriorityClassName. The higher the value, the higher the priority.|int|Undefined|optional| -|**priorityClassName**
    If specified, indicates the pod's priority. "system-node-critical" and "system-cluster-critical" are two special keywords which indicate the highest priorities with the former being the highest priority. Any other name must be defined by creating a PriorityClass object with that name. If not specified, the pod priority will be default or zero if there is no default.|str|Undefined|optional| -|**restartPolicy**
    Restart policy for all containers within the pod. One of Always, OnFailure, Never. Default to Always. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/\#restart-policy|str|Undefined|optional| -|**runtimeClassName**
    RuntimeClassName refers to a RuntimeClass object in the node.k8s.io group, which should be used to run this pod. If no RuntimeClass resource matches the named class, the pod will not be run. If unset or empty, the "legacy" RuntimeClass will be used, which is an implicit class with an empty definition that uses the default runtime handler. More info: https://git.k8s.io/enhancements/keps/sig-node/585-runtime-class This is a beta feature as of Kubernetes v1.14.|str|Undefined|optional| -|**schedulerName**
    If specified, the pod will be dispatched by specified scheduler. If not specified, the pod will be dispatched by default scheduler.|str|Undefined|optional| -|**serviceAccount**
    DeprecatedServiceAccount is a depreciated alias for ServiceAccountName. Deprecated: Use serviceAccountName instead.|str|Undefined|optional| -|**serviceAccountName**
    ServiceAccountName is the name of the ServiceAccount to use to run this pod. More info: https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/|str|Undefined|optional| -|**setHostnameAsFQDN**
    If true the pod's hostname will be configured as the pod's FQDN, rather than the leaf name (the default). In Linux containers, this means setting the FQDN in the hostname field of the kernel (the nodename field of struct utsname). In Windows containers, this means setting the registry value of hostname for the registry key HKEY\_LOCAL\_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters to FQDN. If a pod does not have FQDN, this has no effect. Default to false.|bool|Undefined|optional| -|**shareProcessNamespace**
    Share a single process namespace between all of the containers in a pod. When this is set containers will be able to view and signal processes from other containers in the same pod, and the first process in each container will not be assigned PID 1. HostPID and ShareProcessNamespace cannot both be set. Optional: Default to false.|bool|Undefined|optional| -|**subdomain**
    If specified, the fully qualified Pod hostname will be "\.\.\.svc.\". If not specified, the pod will not have a domainname at all.|str|Undefined|optional| -|**terminationGracePeriodSeconds**
    Optional duration in seconds the pod needs to terminate gracefully. May be decreased in delete request. Value must be non-negative integer. The value zero indicates stop immediately via the kill signal (no opportunity to shut down). If this value is nil, the default grace period will be used instead. The grace period is the duration in seconds after the processes running in the pod are sent a termination signal and the time when the processes are forcibly halted with a kill signal. Set this value longer than the expected cleanup time for your process. Defaults to 30 seconds.|int|Undefined|optional| - diff --git a/test/test_units/test_kclvm/test_tools/test_doc/doc_data/docs/docs_markdown_import_pkg_en/import_pkg/core/doc_pod_template_spec_en.md b/test/test_units/test_kclvm/test_tools/test_doc/doc_data/docs/docs_markdown_import_pkg_en/import_pkg/core/doc_pod_template_spec_en.md deleted file mode 100644 index 06a577abd..000000000 --- a/test/test_units/test_kclvm/test_tools/test_doc/doc_data/docs/docs_markdown_import_pkg_en/import_pkg/core/doc_pod_template_spec_en.md +++ /dev/null @@ -1,17 +0,0 @@ -# pod_template_spec - -Source: [import_pkg/core/pod_template_spec.k](https://url/to/source_code/import_pkg/core/pod_template_spec.k) - -This is the pod\_template\_spec module in kusion\_kubernetes.api.core.v1 package.
    This file was generated by the KCL auto-gen tool. DO NOT EDIT.
    Editing this file might prove futile when you re-run the KCL auto-gen generate command. - -## Schema PodTemplateSpec - -PodTemplateSpec describes the data a pod should have when created from a template - -### Attributes - -|Name and Description|Type|Default Value|Required| -|--------------------|----|-------------|--------| -|**metadata**
    Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md\#metadata|[apis.ObjectMeta](../apis/doc_object_meta_en#schema-objectmeta)|Undefined|optional| -|**spec**
    Specification of the desired behavior of the pod. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md\#spec-and-status|[PodSpec](doc_pod_spec_en#schema-podspec)|Undefined|optional| - diff --git a/test/test_units/test_kclvm/test_tools/test_doc/doc_data/docs/docs_markdown_simple_zh_cn/doc_simple_zh_cn.md b/test/test_units/test_kclvm/test_tools/test_doc/doc_data/docs/docs_markdown_simple_zh_cn/doc_simple_zh_cn.md deleted file mode 100644 index b245eb546..000000000 --- a/test/test_units/test_kclvm/test_tools/test_doc/doc_data/docs/docs_markdown_simple_zh_cn/doc_simple_zh_cn.md +++ /dev/null @@ -1,25 +0,0 @@ -# simple - -Source: [simple.k](https://url/to/source_code/simple.k) - -模块文档,当前模块中定义了一个名为 "Person" 的模型 - -## Schema Person - -Person 是一个简单的模型示例 - -### Attributes - -|Name and Description|Type|Default Value|Required| -|--------------------|----|-------------|--------| -|**name**
    普通属性,名为 "name",表示人的名称|str|"Default"|**required**| -|**age**
    普通属性,名为 "age",表示人的年龄|int|18|optional| -### Examples -```python -person = Person { - name: "Alice" - age: 18 -} -``` - - diff --git a/test/test_units/test_kclvm/test_tools/test_doc/doc_data/docs/i18n_docs_YAML_compact_type_zh_cn/i18n_compact_type_zh_cn.yaml b/test/test_units/test_kclvm/test_tools/test_doc/doc_data/docs/i18n_docs_YAML_compact_type_zh_cn/i18n_compact_type_zh_cn.yaml deleted file mode 100644 index 6f55165c2..000000000 --- a/test/test_units/test_kclvm/test_tools/test_doc/doc_data/docs/i18n_docs_YAML_compact_type_zh_cn/i18n_compact_type_zh_cn.yaml +++ /dev/null @@ -1,138 +0,0 @@ -name: compact_type -relative_path: ./compact_type.k -schemas: -- name: Metadata - doc: | - Metadata is the base schema of all models, which contains data - that helps uniquely identify the object. - attributes: - - name: name - doc: | - The name of the resource. - Name must be unique within a namespace. It's required when creating - resources, although some resources may allow a client to request the - generation of an appropriate name automatically. - Name is primarily intended for creation idempotence and configuration - definition. Cannot be updated. More info: - http://kubernetes.io/docs/user-guide/identifiers#names - type: - type_str: str - type_category: BUILTIN - builtin_type: STRING - is_optional: false - default_value: '' - - name: labels - doc: | - Labels is a map of string keys and values that can be used to - organize and categorize (scope and select) objects. - May match selectors of replication controllers and services. - More info: http://kubernetes.io/docs/user-guide/labels - type: - type_str: '{str: str}' - type_category: DICT - dict_type: - key_type: - type_str: str - type_category: BUILTIN - builtin_type: STRING - value_type: - type_str: str - type_category: BUILTIN - builtin_type: STRING - is_optional: true - default_value: '' - - name: annotations - doc: | - Annotations is an unstructured key value map stored with a - resource that may be set by external tools to store and retrieve - arbitrary metadata. They are not queryable and should be preserved - when modifying objects. - More info: http://kubernetes.io/docs/user-guide/annotations - type: - type_str: '{str: str}' - type_category: DICT - dict_type: - key_type: - type_str: str - type_category: BUILTIN - builtin_type: STRING - value_type: - type_str: str - type_category: BUILTIN - builtin_type: STRING - is_optional: true - default_value: '' - - name: namespace - doc: | - Namespaces are intended for use in environments with many users spread - across multiple teams, or projects. - For clusters with a few to tens of users, you should not need to create - or think about namespaces at all. Start using namespaces when you need the features they provide. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/ - type: - type_str: str - type_category: BUILTIN - builtin_type: STRING - is_optional: true - default_value: default - examples: '' -- name: AppConfiguration - doc: | - AppConfiguration is the common user interface for long-running - services adopting the best practice of Kubernetes. - attributes: - - name: workloadType - doc: | - Use this attribute to specify which kind of long-running service you want. - Valid values: Deployment, CafeDeployment. - Default to Deployment. - See also: kusion_models/core/v1/workload_metadata.k - type: - type_str: str - type_category: BUILTIN - builtin_type: STRING - default_value: Deployment - is_optional: false - - name: name - doc: | - Required. - A Server-level attribute. - The name of the long-running service. - See also: kusion_models/core/v1/metadata.k - type: - type_str: str - type_category: BUILTIN - builtin_type: STRING - is_optional: false - default_value: '' - - name: namespace - doc: | - Required. - A Server-level attribute. - The namespace of the long-running service. - See also: kusion_models/core/v1/metadata.k - type: - type_str: str - type_category: BUILTIN - builtin_type: STRING - default_value: default - is_optional: false - - name: app - doc: | - A Server-level attribute. - The name of the application. - If specified, it will be used as the value of the default label "app". - If not specified, the value of the attribute name will be used. - See also: kusion_models/core/v1/workload_metadata.k - type: - type_str: str - type_category: BUILTIN - builtin_type: STRING - is_optional: false - default_value: '' - examples: | - myCustomApp = AppConfiguration { - name: "componentName" - } -doc: '' -source_code_url: '' diff --git a/test/test_units/test_kclvm/test_tools/test_doc/doc_data/docs/i18n_docs_YAML_frontend_zh_cn/i18n_container_zh_cn.yaml b/test/test_units/test_kclvm/test_tools/test_doc/doc_data/docs/i18n_docs_YAML_frontend_zh_cn/i18n_container_zh_cn.yaml deleted file mode 100644 index 44e03447d..000000000 --- a/test/test_units/test_kclvm/test_tools/test_doc/doc_data/docs/i18n_docs_YAML_frontend_zh_cn/i18n_container_zh_cn.yaml +++ /dev/null @@ -1,70 +0,0 @@ -name: container -relative_path: ./frontend/container.k -schemas: -- name: Container - doc: | - A single application container that you want to run within a pod - attributes: - - name: image - doc: | - Docker image name. - type: - type_str: str - type_category: BUILTIN - builtin_type: STRING - default_value: Undefined - is_optional: false - - name: ports - doc: | - List of ports to expose from the container. - type: - type_str: '[frontend.ContainerPort]' - type_category: LIST - list_type: - item_type: - type_str: frontend.ContainerPort - type_category: SCHEMA - schema_type: - name: ContainerPort - relative_path: ./frontend/container.k - is_optional: true - default_value: Undefined - examples: '' -- name: ContainerPort - doc: | - ContainerPort represents a network port in a single container. - attributes: - - name: port - doc: | - Number of port to expose on the pod's IP address. This must be a valid port number, 0 < x < 65536. - type: - type_str: int - type_category: BUILTIN - builtin_type: INT - default_value: Undefined - is_optional: false - - name: protocol - doc: | - Protocol for port. Must be UDP, TCP, or SCTP. - type: - type_str: '"TCP" | "UDP" | "SCTP"' - union_type: - types: - - type_str: '"TCP"' - type_category: LIT - lit_type: - string_lit: TCP - - type_str: '"UDP"' - type_category: LIT - lit_type: - string_lit: UDP - - type_str: '"SCTP"' - type_category: LIT - lit_type: - string_lit: SCTP - type_category: UNION - default_value: '"TCP"' - is_optional: false - examples: '' -doc: '' -source_code_url: '' diff --git a/test/test_units/test_kclvm/test_tools/test_doc/doc_data/docs/i18n_docs_YAML_frontend_zh_cn/i18n_server_zh_cn.yaml b/test/test_units/test_kclvm/test_tools/test_doc/doc_data/docs/i18n_docs_YAML_frontend_zh_cn/i18n_server_zh_cn.yaml deleted file mode 100644 index a0e684900..000000000 --- a/test/test_units/test_kclvm/test_tools/test_doc/doc_data/docs/i18n_docs_YAML_frontend_zh_cn/i18n_server_zh_cn.yaml +++ /dev/null @@ -1,61 +0,0 @@ -name: server -relative_path: ./frontend/server.k -schemas: -- name: Server - doc: | - Server defined the classical Long-running Service. - attributes: - - name: name - doc: | - The name of the server. - type: - type_str: str - type_category: BUILTIN - builtin_type: STRING - default_value: Undefined - is_optional: false - - name: workloadType - doc: | - The type of the workload. - type: - type_str: '"Deployment" | "StatefulSet" | "DaemonSet"' - union_type: - types: - - type_str: '"Deployment"' - type_category: LIT - lit_type: - string_lit: Deployment - - type_str: '"StatefulSet"' - type_category: LIT - lit_type: - string_lit: StatefulSet - - type_str: '"DaemonSet"' - type_category: LIT - lit_type: - string_lit: DaemonSet - type_category: UNION - default_value: '"Deployment"' - is_optional: false - - name: replica - doc: | - The desired replica count - type: - type_str: int - type_category: BUILTIN - builtin_type: INT - default_value: '1' - is_optional: false - - name: mainContainer - doc: | - The main container. - type: - type_str: Container - type_category: SCHEMA - schema_type: - name: Container - relative_path: ./frontend/container.k - default_value: Undefined - is_optional: false - examples: '' -doc: '' -source_code_url: '' diff --git a/test/test_units/test_kclvm/test_tools/test_doc/doc_data/docs/i18n_docs_YAML_simple_zh_cn/i18n_simple_zh_cn.yaml b/test/test_units/test_kclvm/test_tools/test_doc/doc_data/docs/i18n_docs_YAML_simple_zh_cn/i18n_simple_zh_cn.yaml deleted file mode 100644 index 096bff10b..000000000 --- a/test/test_units/test_kclvm/test_tools/test_doc/doc_data/docs/i18n_docs_YAML_simple_zh_cn/i18n_simple_zh_cn.yaml +++ /dev/null @@ -1,32 +0,0 @@ -name: simple -relative_path: ./simple.k -schemas: -- name: Person - doc: | - Person is a simple schema - attributes: - - name: name - doc: | - A Normal attribute named 'name' - type: - type_str: str - type_category: BUILTIN - builtin_type: STRING - default_value: '"Default"' - is_optional: false - - name: age - doc: | - A Normal attribute named 'age' - type: - type_str: int - type_category: BUILTIN - builtin_type: INT - is_optional: true - default_value: '18' - examples: | - person = Person { - name: "Alice" - age: 18 - } -doc: '' -source_code_url: '' diff --git a/test/test_units/test_kclvm/test_tools/test_doc/doc_data/i18n_inputs/frontend/i18n_container_zh_cn.yaml b/test/test_units/test_kclvm/test_tools/test_doc/doc_data/i18n_inputs/frontend/i18n_container_zh_cn.yaml deleted file mode 100644 index 0ae2aeeb8..000000000 --- a/test/test_units/test_kclvm/test_tools/test_doc/doc_data/i18n_inputs/frontend/i18n_container_zh_cn.yaml +++ /dev/null @@ -1,70 +0,0 @@ -name: container -relative_path: ./frontend/container.k -schemas: -- name: Container - doc: | - 在 pod 中运行的单应用容器 - attributes: - - name: image - doc: | - Docker 镜像名称 - type: - type_str: str - type_category: BUILTIN - builtin_type: STRING - default_value: Undefined - is_optional: false - - name: ports - doc: | - 容器对外暴露的端口列表 - type: - type_str: '[frontend.ContainerPort]' - type_category: LIST - list_type: - item_type: - type_str: frontend.ContainerPort - type_category: SCHEMA - schema_type: - name: ContainerPort - relative_path: ./frontend/container.k - is_optional: true - default_value: Undefined - examples: '' -- name: ContainerPort - doc: | - ContainerPort 表示单个容器中的一个网络端口 - attributes: - - name: port - doc: | - 在 pod IP 地址上暴露的端口号。必须是合法的端口号:介于 0 和 65536 之间(不包含) - type: - type_str: int - type_category: BUILTIN - builtin_type: INT - default_value: Undefined - is_optional: false - - name: protocol - doc: | - 端口协议,合法取值有:"UDP","TCP","SCTP" - type: - type_str: '"TCP" | "UDP" | "SCTP"' - union_type: - types: - - type_str: '"TCP"' - type_category: LIT - lit_type: - string_lit: TCP - - type_str: '"UDP"' - type_category: LIT - lit_type: - string_lit: UDP - - type_str: '"SCTP"' - type_category: LIT - lit_type: - string_lit: SCTP - type_category: UNION - default_value: '"TCP"' - is_optional: false - examples: '' -doc: '' -source_code_url: '' diff --git a/test/test_units/test_kclvm/test_tools/test_doc/doc_data/i18n_inputs/frontend/i18n_server_zh_cn.yaml b/test/test_units/test_kclvm/test_tools/test_doc/doc_data/i18n_inputs/frontend/i18n_server_zh_cn.yaml deleted file mode 100644 index c620ff808..000000000 --- a/test/test_units/test_kclvm/test_tools/test_doc/doc_data/i18n_inputs/frontend/i18n_server_zh_cn.yaml +++ /dev/null @@ -1,61 +0,0 @@ -name: server -relative_path: ./frontend/server.k -schemas: -- name: Server - doc: | - Server 定义了经典的长连接服务 - attributes: - - name: name - doc: | - server 的名称 - type: - type_str: str - type_category: BUILTIN - builtin_type: STRING - default_value: Undefined - is_optional: false - - name: workloadType - doc: | - 工作负载的类型 - type: - type_str: '"Deployment" | "StatefulSet" | "DaemonSet"' - union_type: - types: - - type_str: '"Deployment"' - type_category: LIT - lit_type: - string_lit: Deployment - - type_str: '"StatefulSet"' - type_category: LIT - lit_type: - string_lit: StatefulSet - - type_str: '"DaemonSet"' - type_category: LIT - lit_type: - string_lit: DaemonSet - type_category: UNION - default_value: '"Deployment"' - is_optional: false - - name: replica - doc: | - 目标副本数 - type: - type_str: int - type_category: BUILTIN - builtin_type: INT - default_value: '1' - is_optional: false - - name: mainContainer - doc: | - 主容器 - type: - type_str: Container - type_category: SCHEMA - schema_type: - name: Container - relative_path: ./frontend/container.k - default_value: Undefined - is_optional: false - examples: '' -doc: '' -source_code_url: '' diff --git a/test/test_units/test_kclvm/test_tools/test_doc/doc_data/i18n_inputs/i18n_simple_zh_cn.yaml b/test/test_units/test_kclvm/test_tools/test_doc/doc_data/i18n_inputs/i18n_simple_zh_cn.yaml deleted file mode 100644 index 74c251ac1..000000000 --- a/test/test_units/test_kclvm/test_tools/test_doc/doc_data/i18n_inputs/i18n_simple_zh_cn.yaml +++ /dev/null @@ -1,32 +0,0 @@ -name: simple -relative_path: ./simple.k -schemas: -- name: Person - doc: | - Person 是一个简单的模型示例 - attributes: - - name: name - doc: | - 普通属性,名为 "name",表示人的名称 - type: - type_str: str - type_category: BUILTIN - builtin_type: STRING - default_value: '"Default"' - is_optional: false - - name: age - doc: | - 普通属性,名为 "age",表示人的年龄 - type: - type_str: int - type_category: BUILTIN - builtin_type: INT - is_optional: true - default_value: '18' - examples: | - person = Person { - name: "Alice" - age: 18 - } -doc: '模块文档,当前模块中定义了一个名为 "Person" 的模型' -source_code_url: 'https://url/to/source_code' diff --git a/test/test_units/test_kclvm/test_tools/test_doc/doc_data/source_files/base_schema.k b/test/test_units/test_kclvm/test_tools/test_doc/doc_data/source_files/base_schema.k deleted file mode 100644 index 175b4d741..000000000 --- a/test/test_units/test_kclvm/test_tools/test_doc/doc_data/source_files/base_schema.k +++ /dev/null @@ -1,14 +0,0 @@ -schema Person: - name: str - age: int - -schema Student(Person): - """Student is the person with a grade - - Attributes - ---------- - grade : int, default is Undefined, required - the current grade that the student is in. - - """ - grade: int diff --git a/test/test_units/test_kclvm/test_tools/test_doc/doc_data/source_files/base_schema_pkg/sub/student.k b/test/test_units/test_kclvm/test_tools/test_doc/doc_data/source_files/base_schema_pkg/sub/student.k deleted file mode 100644 index 9b49e8373..000000000 --- a/test/test_units/test_kclvm/test_tools/test_doc/doc_data/source_files/base_schema_pkg/sub/student.k +++ /dev/null @@ -1,12 +0,0 @@ -import base_schema_pkg.base - -schema Student(base.Person): - """Student is the person with a grade - - Attributes - ---------- - grade : int, default is Undefined, required - the current grade that the student is in. - - """ - grade: int diff --git a/test/test_units/test_kclvm/test_tools/test_doc/doc_data/source_files/compact_type.k b/test/test_units/test_kclvm/test_tools/test_doc/doc_data/source_files/compact_type.k deleted file mode 100644 index 842b747d3..000000000 --- a/test/test_units/test_kclvm/test_tools/test_doc/doc_data/source_files/compact_type.k +++ /dev/null @@ -1,75 +0,0 @@ -schema Metadata: - '''Metadata is the base schema of all models, which contains data - that helps uniquely identify the object. - - Attributes - ---------- - name: str - The name of the resource. - Name must be unique within a namespace. It's required when creating - resources, although some resources may allow a client to request the - generation of an appropriate name automatically. - Name is primarily intended for creation idempotence and configuration - definition. Cannot be updated. More info: - http://kubernetes.io/docs/user-guide/identifiers#names - labels: {str:str}, optional - Labels is a map of string keys and values that can be used to - organize and categorize (scope and select) objects. - May match selectors of replication controllers and services. - More info: http://kubernetes.io/docs/user-guide/labels - annotations: {str:str}, optional - Annotations is an unstructured key value map stored with a - resource that may be set by external tools to store and retrieve - arbitrary metadata. They are not queryable and should be preserved - when modifying objects. - More info: http://kubernetes.io/docs/user-guide/annotations - namespace: str, default is default, optional - Namespaces are intended for use in environments with many users spread - across multiple teams, or projects. - For clusters with a few to tens of users, you should not need to create - or think about namespaces at all. Start using namespaces when you need the features they provide. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/ - ''' - name: str - labels?: {str: str} - annotations?: {str: str} - namespace?: str - -schema AppConfiguration: - ''' AppConfiguration is the common user interface for long-running - services adopting the best practice of Kubernetes. - - Attributes - ---------- - workloadType: str, default is Deployment - Use this attribute to specify which kind of long-running service you want. - Valid values: Deployment, CafeDeployment. - Default to Deployment. - See also: kusion_models/core/v1/workload_metadata.k - name: str - Required. - A Server-level attribute. - The name of the long-running service. - See also: kusion_models/core/v1/metadata.k - namespace: str, default = default - Required. - A Server-level attribute. - The namespace of the long-running service. - See also: kusion_models/core/v1/metadata.k - app: str - A Server-level attribute. - The name of the application. - If specified, it will be used as the value of the default label "app". - If not specified, the value of the attribute name will be used. - See also: kusion_models/core/v1/workload_metadata.k - - Examples - -------- - myCustomApp = AppConfiguration { - name: "componentName" - } - ''' - workloadType: str = "Deployment" - name: str - namespace: str = "default" - app: str \ No newline at end of file diff --git a/test/test_units/test_kclvm/test_tools/test_doc/doc_data/source_files/config_map/core/metadata.k b/test/test_units/test_kclvm/test_tools/test_doc/doc_data/source_files/config_map/core/metadata.k deleted file mode 100644 index 1f7d6fd2c..000000000 --- a/test/test_units/test_kclvm/test_tools/test_doc/doc_data/source_files/config_map/core/metadata.k +++ /dev/null @@ -1,37 +0,0 @@ -schema Metadata: - """Metadata is the base schema of all models, which contains data - that helps uniquely identify the object. - - Attributes - ---------- - name: str, default is Undefined, required. - The name of the resource. - Name must be unique within a namespace. It's required when creating - resources, although some resources may allow a client to request the - generation of an appropriate name automatically. - Name is primarily intended for creation idempotence and configuration - definition. Cannot be updated. More info: - http://kubernetes.io/docs/user-guide/identifiers#names - labels: {str:str}, default is Undefined, optional. - Labels is a map of string keys and values that can be used to - organize and categorize (scope and select) objects. - May match selectors of replication controllers and services. - More info: http://kubernetes.io/docs/user-guide/labels - annotations: {str:str}, default is Undefined, optional. - Annotations is an unstructured key value map stored with a - resource that may be set by external tools to store and retrieve - arbitrary metadata. They are not queryable and should be preserved - when modifying objects. - More info: http://kubernetes.io/docs/user-guide/annotations - namespace: str, default is Undefined, optional. - Namespaces are intended for use in environments with many users spread - across multiple teams, or projects. - For clusters with a few to tens of users, you should not need to create - or think about namespaces at all. Start using namespaces when you need the features they provide. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/ - """ - - name: str - labels?: {str:str} - annotations?: {str:str} - namespace?: str diff --git a/test/test_units/test_kclvm/test_tools/test_doc/doc_data/source_files/config_map/core/v1/config_map.k b/test/test_units/test_kclvm/test_tools/test_doc/doc_data/source_files/config_map/core/v1/config_map.k deleted file mode 100644 index 5c961c61a..000000000 --- a/test/test_units/test_kclvm/test_tools/test_doc/doc_data/source_files/config_map/core/v1/config_map.k +++ /dev/null @@ -1,7 +0,0 @@ -import config_map.core.metadata - -schema ConfigMap(metadata.Metadata): - # 目的是根据入参生成 Kubernetes 资源 - # 入参列表 - data?: {str:str} - binaryData?: {str:str} diff --git a/test/test_units/test_kclvm/test_tools/test_doc/doc_data/source_files/frontend/container.k b/test/test_units/test_kclvm/test_tools/test_doc/doc_data/source_files/frontend/container.k deleted file mode 100644 index 4bda9fae2..000000000 --- a/test/test_units/test_kclvm/test_tools/test_doc/doc_data/source_files/frontend/container.k +++ /dev/null @@ -1,31 +0,0 @@ -schema Container: - """A single application container that you want to run within a pod - - Attributes - ---------- - image : str, Default is Undefined, required - Docker image name. - ports: [ContainerPort], Default is Undefined, optional - List of ports to expose from the container. - """ - image: str - ports?: [ContainerPort] - - -schema ContainerPort: - """ContainerPort represents a network port in a single container. - - Attributes - ---------- - port : int, Default is Undefined, required - Number of port to expose on the pod's IP address. This must be a valid port number, 0 < x < 65536. - protocol : "TCP" | "UDP" | "SCTP", Default is "TCP", required - Protocol for port. Must be UDP, TCP, or SCTP. - """ - port: int - protocol: "TCP" | "UDP" | "SCTP" = "TCP" - - check: - 0 < port < 65536 - - diff --git a/test/test_units/test_kclvm/test_tools/test_doc/doc_data/source_files/frontend/server.k b/test/test_units/test_kclvm/test_tools/test_doc/doc_data/source_files/frontend/server.k deleted file mode 100644 index 6a421b234..000000000 --- a/test/test_units/test_kclvm/test_tools/test_doc/doc_data/source_files/frontend/server.k +++ /dev/null @@ -1,18 +0,0 @@ -schema Server: - """Server defined the classical Long-running Service. - - Attributes - ---------- - name : str, Default is Undefined, required - The name of the server. - workloadType : "Deployment" | "StatefulSet" | "DaemonSet", Default is "Deployment", required - The type of the workload. - replica : int, Default is 1, required - The desired replica count - mainContainer : Container, Default is Undefined, required - The main container. - """ - name: str - workloadType: "Deployment" | "StatefulSet" | "DaemonSet" = "Deployment" - replica: int = 1 - mainContainer: Container diff --git a/test/test_units/test_kclvm/test_tools/test_doc/doc_data/source_files/good.k b/test/test_units/test_kclvm/test_tools/test_doc/doc_data/source_files/good.k deleted file mode 100644 index 551d8ef53..000000000 --- a/test/test_units/test_kclvm/test_tools/test_doc/doc_data/source_files/good.k +++ /dev/null @@ -1,29 +0,0 @@ -schema Server: - """Server is the common user interface for long-running - services adopting the best practice of Kubernetes. - - Attributes - ---------- - workloadType : str, default is Deployment - Use this attribute to specify which kind of long-running service you want. - Valid values: Deployment, CafeDeployment. - See also: kusion_models/core/v1/workload_metadata.k. - name : str - A Server-level attribute. - The name of the long-running service. - See also: kusion_models/core/v1/metadata.k. - labels : {str:str}, optional - A Server-level attribute. - The labels of the long-running service. - See also: kusion_models/core/v1/metadata.k. - - Examples - ---------------------- - myCustomApp = AppConfiguration { - name: "componentName" - } - """ - workloadType: str = "Deployment" - name: str - labels?: {str:str} - diff --git a/test/test_units/test_kclvm/test_tools/test_doc/doc_data/source_files/import_pkg/apis/label_selector.k b/test/test_units/test_kclvm/test_tools/test_doc/doc_data/source_files/import_pkg/apis/label_selector.k deleted file mode 100644 index e4a76ef9d..000000000 --- a/test/test_units/test_kclvm/test_tools/test_doc/doc_data/source_files/import_pkg/apis/label_selector.k +++ /dev/null @@ -1,20 +0,0 @@ -""" -This is the label_selector module in kusion_kubernetes.apimachinery.apis package. -This file was generated by the KCL auto-gen tool. DO NOT EDIT. -Editing this file might prove futile when you re-run the KCL auto-gen generate command. -""" - - -schema LabelSelector: - """ A label selector is a label query over a set of resources. The result of matchLabels and matchExpressions are ANDed. An empty label selector matches all objects. A null label selector matches no objects. - - Attributes - ---------- - matchLabels : {str:str}, default is Undefined, optional - matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. - """ - - - matchLabels?: {str:str} - - diff --git a/test/test_units/test_kclvm/test_tools/test_doc/doc_data/source_files/import_pkg/apis/object_meta.k b/test/test_units/test_kclvm/test_tools/test_doc/doc_data/source_files/import_pkg/apis/object_meta.k deleted file mode 100644 index 73b3690ed..000000000 --- a/test/test_units/test_kclvm/test_tools/test_doc/doc_data/source_files/import_pkg/apis/object_meta.k +++ /dev/null @@ -1,72 +0,0 @@ -""" -This is the object_meta module in kusion_kubernetes.apimachinery.apis package. -This file was generated by the KCL auto-gen tool. DO NOT EDIT. -Editing this file might prove futile when you re-run the KCL auto-gen generate command. -""" - - -schema ObjectMeta: - """ ObjectMeta is metadata that all persisted resources must have, which includes all objects users must create. - - Attributes - ---------- - annotations : {str:str}, default is Undefined, optional - Annotations is an unstructured key value map stored with a resource that may be set by external tools to store and retrieve arbitrary metadata. They are not queryable and should be preserved when modifying objects. More info: http://kubernetes.io/docs/user-guide/annotations - clusterName : str, default is Undefined, optional - The name of the cluster which the object belongs to. This is used to distinguish resources with same name and namespace in different clusters. This field is not set anywhere right now and apiserver is going to ignore it if set in create or update request. - creationTimestamp : str, default is Undefined, optional - CreationTimestamp is a timestamp representing the server time when this object was created. It is not guaranteed to be set in happens-before order across separate operations. Clients may not set this value. It is represented in RFC3339 form and is in UTC. Populated by the system. Read-only. Null for lists. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - deletionGracePeriodSeconds : int, default is Undefined, optional - Number of seconds allowed for this object to gracefully terminate before it will be removed from the system. Only set when deletionTimestamp is also set. May only be shortened. Read-only. - deletionTimestamp : str, default is Undefined, optional - DeletionTimestamp is RFC 3339 date and time at which this resource will be deleted. This field is set by the server when a graceful deletion is requested by the user, and is not directly settable by a client. The resource is expected to be deleted (no longer visible from resource lists, and not reachable by name) after the time in this field, once the finalizers list is empty. As long as the finalizers list contains items, deletion is blocked. Once the deletionTimestamp is set, this value may not be unset or be set further into the future, although it may be shortened or the resource may be deleted prior to this time. For example, a user may request that a pod is deleted in 30 seconds. The Kubelet will react by sending a graceful termination signal to the containers in the pod. After that 30 seconds, the Kubelet will send a hard termination signal (SIGKILL) to the container and after cleanup, remove the pod from the API. In the presence of network partitions, this object may still exist after this timestamp, until an administrator or automated process can determine the resource is fully terminated. If not set, graceful deletion of the object has not been requested. Populated by the system when a graceful deletion is requested. Read-only. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - finalizers : [str], default is Undefined, optional - Must be empty before the object is deleted from the registry. Each entry is an identifier for the responsible component that will remove the entry from the list. If the deletionTimestamp of the object is non-nil, entries in this list can only be removed. Finalizers may be processed and removed in any order. Order is NOT enforced because it introduces significant risk of stuck finalizers. finalizers is a shared field, any actor with permission can reorder it. If the finalizer list is processed in order, then this can lead to a situation in which the component responsible for the first finalizer in the list is waiting for a signal (field value, external system, or other) produced by a component responsible for a finalizer later in the list, resulting in a deadlock. Without enforced ordering finalizers are free to order amongst themselves and are not vulnerable to ordering changes in the list. - generateName : str, default is Undefined, optional - GenerateName is an optional prefix, used by the server, to generate a unique name ONLY IF the Name field has not been provided. If this field is used, the name returned to the client will be different than the name passed. This value will also be combined with a unique suffix. The provided value has the same validation rules as the Name field, and may be truncated by the length of the suffix required to make the value unique on the server. If this field is specified and the generated name exists, the server will NOT return a 409 - instead, it will either return 201 Created or 500 with Reason ServerTimeout indicating a unique name could not be found in the time allotted, and the client should retry (optionally after the time indicated in the Retry-After header). Applied only if Name is not specified. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#idempotency - generation : int, default is Undefined, optional - A sequence number representing a specific generation of the desired state. Populated by the system. Read-only. - labels : {str:str}, default is Undefined, optional - Map of string keys and values that can be used to organize and categorize (scope and select) objects. May match selectors of replication controllers and services. More info: http://kubernetes.io/docs/user-guide/labels - name : str, default is Undefined, optional - Name must be unique within a namespace. Is required when creating resources, although some resources may allow a client to request the generation of an appropriate name automatically. Name is primarily intended for creation idempotence and configuration definition. Cannot be updated. More info: http://kubernetes.io/docs/user-guide/identifiers#names - namespace : str, default is Undefined, optional - Namespace defines the space within which each name must be unique. An empty namespace is equivalent to the "default" namespace, but "default" is the canonical representation. Not all objects are required to be scoped to a namespace - the value of this field for those objects will be empty. Must be a DNS_LABEL. Cannot be updated. More info: http://kubernetes.io/docs/user-guide/namespaces - resourceVersion : str, default is Undefined, optional - An opaque value that represents the internal version of this object that can be used by clients to determine when objects have changed. May be used for optimistic concurrency, change detection, and the watch operation on a resource or set of resources. Clients must treat these values as opaque and passed unmodified back to the server. They may only be valid for a particular resource or set of resources. Populated by the system. Read-only. Value must be treated as opaque by clients and . More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency - selfLink : str, default is Undefined, optional - SelfLink is a URL representing this object. Populated by the system. Read-only. DEPRECATED Kubernetes will stop propagating this field in 1.20 release and the field is planned to be removed in 1.21 release. - uid : str, default is Undefined, optional - UID is the unique in time and space value for this object. It is typically generated by the server on successful creation of a resource and is not allowed to change on PUT operations. Populated by the system. Read-only. More info: http://kubernetes.io/docs/user-guide/identifiers#uids - """ - - - annotations?: {str:str} - - clusterName?: str - - creationTimestamp?: str - - deletionGracePeriodSeconds?: int - - deletionTimestamp?: str - - finalizers?: [str] - - generateName?: str - - generation?: int - - labels?: {str:str} - - name?: str - - namespace?: str - - resourceVersion?: str - - selfLink?: str - - uid?: str - - diff --git a/test/test_units/test_kclvm/test_tools/test_doc/doc_data/source_files/import_pkg/apps/deployment.k b/test/test_units/test_kclvm/test_tools/test_doc/doc_data/source_files/import_pkg/apps/deployment.k deleted file mode 100644 index 308874421..000000000 --- a/test/test_units/test_kclvm/test_tools/test_doc/doc_data/source_files/import_pkg/apps/deployment.k +++ /dev/null @@ -1,33 +0,0 @@ -""" -This is the deployment module in kusion_kubernetes.api.apps.v1 package. -This file was generated by the KCL auto-gen tool. DO NOT EDIT. -Editing this file might prove futile when you re-run the KCL auto-gen generate command. -""" -import import_pkg.apis - - -schema Deployment: - """ Deployment enables declarative updates for Pods and ReplicaSets. - - Attributes - ---------- - apiVersion : "apps/v1", default is "apps/v1", required - APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources - kind : "Deployment", default is "Deployment", required - Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - metadata : apis.ObjectMeta, default is Undefined, optional - Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - spec : DeploymentSpec, default is Undefined, optional - Specification of the desired behavior of the Deployment. - """ - - - apiVersion: "apps/v1" = "apps/v1" - - kind: "Deployment" = "Deployment" - - metadata?: apis.ObjectMeta - - spec?: DeploymentSpec - - diff --git a/test/test_units/test_kclvm/test_tools/test_doc/doc_data/source_files/import_pkg/apps/deployment_spec.k b/test/test_units/test_kclvm/test_tools/test_doc/doc_data/source_files/import_pkg/apps/deployment_spec.k deleted file mode 100644 index 082a965cf..000000000 --- a/test/test_units/test_kclvm/test_tools/test_doc/doc_data/source_files/import_pkg/apps/deployment_spec.k +++ /dev/null @@ -1,50 +0,0 @@ -""" -This is the deployment_spec module in kusion_kubernetes.api.apps.v1 package. -This file was generated by the KCL auto-gen tool. DO NOT EDIT. -Editing this file might prove futile when you re-run the KCL auto-gen generate command. -""" -import import_pkg.apis -import import_pkg.core - - -schema DeploymentSpec: - """ DeploymentSpec is the specification of the desired behavior of the Deployment. - - Attributes - ---------- - minReadySeconds : int, default is Undefined, optional - Minimum number of seconds for which a newly created pod should be ready without any of its container crashing, for it to be considered available. Defaults to 0 (pod will be considered available as soon as it is ready) - paused : bool, default is Undefined, optional - Indicates that the deployment is paused. - progressDeadlineSeconds : int, default is Undefined, optional - The maximum time in seconds for a deployment to make progress before it is considered to be failed. The deployment controller will continue to process failed deployments and a condition with a ProgressDeadlineExceeded reason will be surfaced in the deployment status. Note that progress will not be estimated during the time a deployment is paused. Defaults to 600s. - replicas : int, default is Undefined, optional - Number of desired pods. This is a pointer to distinguish between explicit zero and not specified. Defaults to 1. - revisionHistoryLimit : int, default is Undefined, optional - The number of old ReplicaSets to retain to allow rollback. This is a pointer to distinguish between explicit zero and not specified. Defaults to 10. - selector : apis.LabelSelector, default is Undefined, required - Label selector for pods. Existing ReplicaSets whose pods are selected by this will be the ones affected by this deployment. It must match the pod template's labels. - strategy : DeploymentStrategy, default is Undefined, optional - The deployment strategy to use to replace existing pods with new ones. - template : core.PodTemplateSpec, default is Undefined, required - Template describes the pods that will be created. - """ - - - minReadySeconds?: int - - paused?: bool - - progressDeadlineSeconds?: int - - replicas?: int - - revisionHistoryLimit?: int - - selector: apis.LabelSelector - - strategy?: DeploymentStrategy - - template: core.PodTemplateSpec - - diff --git a/test/test_units/test_kclvm/test_tools/test_doc/doc_data/source_files/import_pkg/apps/deployment_strategy.k b/test/test_units/test_kclvm/test_tools/test_doc/doc_data/source_files/import_pkg/apps/deployment_strategy.k deleted file mode 100644 index b5b655160..000000000 --- a/test/test_units/test_kclvm/test_tools/test_doc/doc_data/source_files/import_pkg/apps/deployment_strategy.k +++ /dev/null @@ -1,24 +0,0 @@ -""" -This is the deployment_strategy module in kusion_kubernetes.api.apps.v1 package. -This file was generated by the KCL auto-gen tool. DO NOT EDIT. -Editing this file might prove futile when you re-run the KCL auto-gen generate command. -""" - - -schema DeploymentStrategy: - """ DeploymentStrategy describes how to replace existing pods with new ones. - - Attributes - ---------- - $type : str, default is Undefined, optional - Type of deployment. Can be "Recreate" or "RollingUpdate". Default is RollingUpdate. - rollingUpdate : RollingUpdateDeployment, default is Undefined, optional - Rolling update config params. Present only if DeploymentStrategyType = RollingUpdate. - """ - - - $type?: str - - rollingUpdate?: RollingUpdateDeployment - - diff --git a/test/test_units/test_kclvm/test_tools/test_doc/doc_data/source_files/import_pkg/apps/rolling_update_deployment.k b/test/test_units/test_kclvm/test_tools/test_doc/doc_data/source_files/import_pkg/apps/rolling_update_deployment.k deleted file mode 100644 index f63d3e178..000000000 --- a/test/test_units/test_kclvm/test_tools/test_doc/doc_data/source_files/import_pkg/apps/rolling_update_deployment.k +++ /dev/null @@ -1,24 +0,0 @@ -""" -This is the rolling_update_deployment module in kusion_kubernetes.api.apps.v1 package. -This file was generated by the KCL auto-gen tool. DO NOT EDIT. -Editing this file might prove futile when you re-run the KCL auto-gen generate command. -""" - - -schema RollingUpdateDeployment: - """ Spec to control the desired behavior of rolling update. - - Attributes - ---------- - maxSurge : int | str, default is Undefined, optional - The maximum number of pods that can be scheduled above the desired number of pods. Value can be an absolute number (ex: 5) or a percentage of desired pods (ex: 10%). This can not be 0 if MaxUnavailable is 0. Absolute number is calculated from percentage by rounding up. Defaults to 25%. Example: when this is set to 30%, the new ReplicaSet can be scaled up immediately when the rolling update starts, such that the total number of old and new pods do not exceed 130% of desired pods. Once old pods have been killed, new ReplicaSet can be scaled up further, ensuring that total number of pods running at any time during the update is at most 130% of desired pods. - maxUnavailable : int | str, default is Undefined, optional - The maximum number of pods that can be unavailable during the update. Value can be an absolute number (ex: 5) or a percentage of desired pods (ex: 10%). Absolute number is calculated from percentage by rounding down. This can not be 0 if MaxSurge is 0. Defaults to 25%. Example: when this is set to 30%, the old ReplicaSet can be scaled down to 70% of desired pods immediately when the rolling update starts. Once new pods are ready, old ReplicaSet can be scaled down further, followed by scaling up the new ReplicaSet, ensuring that the total number of pods available at all times during the update is at least 70% of desired pods. - """ - - - maxSurge?: int | str - - maxUnavailable?: int | str - - diff --git a/test/test_units/test_kclvm/test_tools/test_doc/doc_data/source_files/import_pkg/core/pod_spec.k b/test/test_units/test_kclvm/test_tools/test_doc/doc_data/source_files/import_pkg/core/pod_spec.k deleted file mode 100644 index b8014641e..000000000 --- a/test/test_units/test_kclvm/test_tools/test_doc/doc_data/source_files/import_pkg/core/pod_spec.k +++ /dev/null @@ -1,108 +0,0 @@ -""" -This is the pod_spec module in kusion_kubernetes.api.core.v1 package. -This file was generated by the KCL auto-gen tool. DO NOT EDIT. -Editing this file might prove futile when you re-run the KCL auto-gen generate command. -""" - - -schema PodSpec: - """ PodSpec is a description of a pod. - - Attributes - ---------- - activeDeadlineSeconds : int, default is Undefined, optional - Optional duration in seconds the pod may be active on the node relative to StartTime before the system will actively try to mark it failed and kill associated containers. Value must be a positive integer. - automountServiceAccountToken : bool, default is Undefined, optional - AutomountServiceAccountToken indicates whether a service account token should be automatically mounted. - dnsPolicy : str, default is Undefined, optional - Set DNS policy for the pod. Defaults to "ClusterFirst". Valid values are 'ClusterFirstWithHostNet', 'ClusterFirst', 'Default' or 'None'. DNS parameters given in DNSConfig will be merged with the policy selected with DNSPolicy. To have DNS options set along with hostNetwork, you have to specify DNS policy explicitly to 'ClusterFirstWithHostNet'. - enableServiceLinks : bool, default is Undefined, optional - EnableServiceLinks indicates whether information about services should be injected into pod's environment variables, matching the syntax of Docker links. Optional: Defaults to true. - hostIPC : bool, default is Undefined, optional - Use the host's ipc namespace. Optional: Default to false. - hostNetwork : bool, default is Undefined, optional - Host networking requested for this pod. Use the host's network namespace. If this option is set, the ports that will be used must be specified. Default to false. - hostPID : bool, default is Undefined, optional - Use the host's pid namespace. Optional: Default to false. - hostname : str, default is Undefined, optional - Specifies the hostname of the Pod If not specified, the pod's hostname will be set to a system-defined value. - nodeName : str, default is Undefined, optional - NodeName is a request to schedule this pod onto a specific node. If it is non-empty, the scheduler simply schedules this pod onto that node, assuming that it fits resource requirements. - nodeSelector : {str:str}, default is Undefined, optional - NodeSelector is a selector which must be true for the pod to fit on a node. Selector which must match a node's labels for the pod to be scheduled on that node. More info: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/ - overhead : {str:str}, default is Undefined, optional - Overhead represents the resource overhead associated with running a pod for a given RuntimeClass. This field will be autopopulated at admission time by the RuntimeClass admission controller. If the RuntimeClass admission controller is enabled, overhead must not be set in Pod create requests. The RuntimeClass admission controller will reject Pod create requests which have the overhead already set. If RuntimeClass is configured and selected in the PodSpec, Overhead will be set to the value defined in the corresponding RuntimeClass, otherwise it will remain unset and treated as zero. More info: https://git.k8s.io/enhancements/keps/sig-node/688-pod-overhead/README.md This field is beta-level as of Kubernetes v1.18, and is only honored by servers that enable the PodOverhead feature. - preemptionPolicy : str, default is Undefined, optional - PreemptionPolicy is the Policy for preempting pods with lower priority. One of Never, PreemptLowerPriority. Defaults to PreemptLowerPriority if unset. This field is beta-level, gated by the NonPreemptingPriority feature-gate. - priority : int, default is Undefined, optional - The priority value. Various system components use this field to find the priority of the pod. When Priority Admission Controller is enabled, it prevents users from setting this field. The admission controller populates this field from PriorityClassName. The higher the value, the higher the priority. - priorityClassName : str, default is Undefined, optional - If specified, indicates the pod's priority. "system-node-critical" and "system-cluster-critical" are two special keywords which indicate the highest priorities with the former being the highest priority. Any other name must be defined by creating a PriorityClass object with that name. If not specified, the pod priority will be default or zero if there is no default. - restartPolicy : str, default is Undefined, optional - Restart policy for all containers within the pod. One of Always, OnFailure, Never. Default to Always. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#restart-policy - runtimeClassName : str, default is Undefined, optional - RuntimeClassName refers to a RuntimeClass object in the node.k8s.io group, which should be used to run this pod. If no RuntimeClass resource matches the named class, the pod will not be run. If unset or empty, the "legacy" RuntimeClass will be used, which is an implicit class with an empty definition that uses the default runtime handler. More info: https://git.k8s.io/enhancements/keps/sig-node/585-runtime-class This is a beta feature as of Kubernetes v1.14. - schedulerName : str, default is Undefined, optional - If specified, the pod will be dispatched by specified scheduler. If not specified, the pod will be dispatched by default scheduler. - serviceAccount : str, default is Undefined, optional - DeprecatedServiceAccount is a depreciated alias for ServiceAccountName. Deprecated: Use serviceAccountName instead. - serviceAccountName : str, default is Undefined, optional - ServiceAccountName is the name of the ServiceAccount to use to run this pod. More info: https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/ - setHostnameAsFQDN : bool, default is Undefined, optional - If true the pod's hostname will be configured as the pod's FQDN, rather than the leaf name (the default). In Linux containers, this means setting the FQDN in the hostname field of the kernel (the nodename field of struct utsname). In Windows containers, this means setting the registry value of hostname for the registry key HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters to FQDN. If a pod does not have FQDN, this has no effect. Default to false. - shareProcessNamespace : bool, default is Undefined, optional - Share a single process namespace between all of the containers in a pod. When this is set containers will be able to view and signal processes from other containers in the same pod, and the first process in each container will not be assigned PID 1. HostPID and ShareProcessNamespace cannot both be set. Optional: Default to false. - subdomain : str, default is Undefined, optional - If specified, the fully qualified Pod hostname will be "...svc.". If not specified, the pod will not have a domainname at all. - terminationGracePeriodSeconds : int, default is Undefined, optional - Optional duration in seconds the pod needs to terminate gracefully. May be decreased in delete request. Value must be non-negative integer. The value zero indicates stop immediately via the kill signal (no opportunity to shut down). If this value is nil, the default grace period will be used instead. The grace period is the duration in seconds after the processes running in the pod are sent a termination signal and the time when the processes are forcibly halted with a kill signal. Set this value longer than the expected cleanup time for your process. Defaults to 30 seconds. - """ - - - activeDeadlineSeconds?: int - - automountServiceAccountToken?: bool - - dnsPolicy?: str - - enableServiceLinks?: bool - - hostIPC?: bool - - hostNetwork?: bool - - hostPID?: bool - - hostname?: str - - nodeName?: str - - nodeSelector?: {str:str} - - overhead?: {str:str} - - preemptionPolicy?: str - - priority?: int - - priorityClassName?: str - - restartPolicy?: str - - runtimeClassName?: str - - schedulerName?: str - - serviceAccount?: str - - serviceAccountName?: str - - setHostnameAsFQDN?: bool - - shareProcessNamespace?: bool - - subdomain?: str - - terminationGracePeriodSeconds?: int - - diff --git a/test/test_units/test_kclvm/test_tools/test_doc/doc_data/source_files/import_pkg/core/pod_template_spec.k b/test/test_units/test_kclvm/test_tools/test_doc/doc_data/source_files/import_pkg/core/pod_template_spec.k deleted file mode 100644 index 9a068268b..000000000 --- a/test/test_units/test_kclvm/test_tools/test_doc/doc_data/source_files/import_pkg/core/pod_template_spec.k +++ /dev/null @@ -1,25 +0,0 @@ -""" -This is the pod_template_spec module in kusion_kubernetes.api.core.v1 package. -This file was generated by the KCL auto-gen tool. DO NOT EDIT. -Editing this file might prove futile when you re-run the KCL auto-gen generate command. -""" -import import_pkg.apis - - -schema PodTemplateSpec: - """ PodTemplateSpec describes the data a pod should have when created from a template - - Attributes - ---------- - metadata : apis.ObjectMeta, default is Undefined, optional - Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - spec : PodSpec, default is Undefined, optional - Specification of the desired behavior of the pod. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status - """ - - - metadata?: apis.ObjectMeta - - spec?: PodSpec - - diff --git a/test/test_units/test_kclvm/test_tools/test_doc/doc_data/source_files/no_type.k b/test/test_units/test_kclvm/test_tools/test_doc/doc_data/source_files/no_type.k deleted file mode 100644 index 2f0e36f21..000000000 --- a/test/test_units/test_kclvm/test_tools/test_doc/doc_data/source_files/no_type.k +++ /dev/null @@ -1,31 +0,0 @@ -schema Server: - """Server is the common user interface for long-running - services adopting the best practice of Kubernetes. - - Attributes - ---------- - workloadType : default is Deployment - Use this attribute to specify which kind of long-running service you want. - Valid values: Deployment, CafeDeployment. - See also: kusion_models/core/v1/workload_metadata.k. - name - A Server-level attribute. - The name of the long-running service. - See also: kusion_models/core/v1/metadata.k. - labels : optional - A Server-level attribute. - The labels of the long-running service. - See also: kusion_models/core/v1/metadata.k. - replica : default is 1, optional - Replica of the server. - - Examples - ---------------------- - myCustomApp = AppConfiguration { - name: "componentName" - } - """ - workloadType: str = "Deployment" - name: str - labels?: {str: str} - replica?: int = 1 diff --git a/test/test_units/test_kclvm/test_tools/test_doc/doc_data/source_files/simple.k b/test/test_units/test_kclvm/test_tools/test_doc/doc_data/source_files/simple.k deleted file mode 100644 index 5feb31e32..000000000 --- a/test/test_units/test_kclvm/test_tools/test_doc/doc_data/source_files/simple.k +++ /dev/null @@ -1,21 +0,0 @@ -schema Person: - '''Person is a simple schema - - Attributes - ---------- - name: str, default is "Default" - A Normal attribute named 'name' - age: int, default = 18, optional - A Normal attribute named 'age' - - Examples - -------- - person = Person { - name: "Alice" - age: 18 - } - ''' - name: str - age?: int - -person = Person {} diff --git a/test/test_units/test_kclvm/test_tools/test_doc/test_checker.py b/test/test_units/test_kclvm/test_tools/test_doc/test_checker.py deleted file mode 100644 index 7602f6c2c..000000000 --- a/test/test_units/test_kclvm/test_tools/test_doc/test_checker.py +++ /dev/null @@ -1,57 +0,0 @@ -import unittest -import pathlib -import typing - -import kclvm.compiler.parser.parser as parser -import kclvm.tools.docs.doc_parser as doc_parser -import kclvm.kcl.types.checker as type_checker -import kclvm.api.object as obj_pkg -import kclvm.tools.docs.model_pb2 as model - - -_DIR_PATH = pathlib.Path(__file__).parent.joinpath("doc_data") / "source_files" - - -def resolve(kcl_file: str) -> typing.List[model.SchemaDoc]: - prog = parser.LoadProgram(kcl_file) - type_checker.ResolveProgramImport(prog) - checker = type_checker.TypeChecker(prog, type_checker.CheckConfig()) - checker.check_import(prog.MAIN_PKGPATH) - checker.init_global_types() - schemas = prog.pkgs[prog.MAIN_PKGPATH][0].GetSchemaList() - - schema_docs: typing.List[model.SchemaDoc] = [] - for schema in schemas: - schema_obj_type = checker.scope_map[prog.MAIN_PKGPATH].elems[schema.name].type - assert isinstance(schema_obj_type, obj_pkg.KCLSchemaDefTypeObject) - schema_docs.append( - doc_parser.SchemaDocParser( - schema=schema, - schema_type=schema_obj_type.schema_type, - root=prog.root, - ).doc - ) - return schema_docs - - -class KCLDocCheckerTest(unittest.TestCase): - def test_simple_case(self) -> None: - docs = resolve(_DIR_PATH / "simple.k") - assert len(docs) == 1 - doc = docs[0] - assert doc.doc.startswith("Person is a simple schema") - assert doc.attributes[0].name == "name" - assert doc.attributes[0].type.type_str == "str" - assert doc.attributes[0].is_optional is False - assert doc.attributes[0].default_value == '"Default"' - assert doc.attributes[0].doc.startswith("A Normal attribute named 'name'") - assert doc.attributes[1].name == "age" - assert doc.attributes[1].type.type_str == "int" - assert doc.attributes[1].is_optional is True - assert doc.attributes[1].default_value == "18" - assert doc.attributes[1].doc.startswith("A Normal attribute named 'age'") - assert doc.examples.startswith("person = Person {") - - -if __name__ == "__main__": - unittest.main(verbosity=2) diff --git a/test/test_units/test_kclvm/test_tools/test_doc/test_doc_gen.py b/test/test_units/test_kclvm/test_tools/test_doc/test_doc_gen.py deleted file mode 100644 index faa500315..000000000 --- a/test/test_units/test_kclvm/test_tools/test_doc/test_doc_gen.py +++ /dev/null @@ -1,160 +0,0 @@ -import unittest -import pathlib -import shutil -import filecmp - -from kclvm.tools.docs.doc import kcl_doc_generate -import kclvm.tools.docs.formats as doc_formats - -_DIR_PATH = pathlib.Path(__file__).parent.joinpath("doc_data") -_SOURCE_PATH = _DIR_PATH / "source_files" -_DOCS_PATH = _DIR_PATH / "docs" -_I18N_PATH = _DIR_PATH / "i18n_inputs" - - -class KCLDocGenTestData: - def __init__( - self, - filename: str, - recursive: bool, - format: str, - locale: str = "en", - i18n_path: str = None, - ): - self.filename: str = filename - self.recursive: bool = recursive - self.format: str = format - self.locale: str = locale - self.i18n_path: str = i18n_path - - -def read_file_content(path) -> str: - with open(path, "r") as f: - return f.read() - - -class KCLDocGenerateTest(unittest.TestCase): - test_cases = [ - KCLDocGenTestData( - filename="import_pkg", - recursive=True, - format="markdown", - ), - KCLDocGenTestData( - filename="base_schema_pkg", - recursive=True, - format="markdown", - ), - KCLDocGenTestData( - filename="config_map", - recursive=True, - format="markdown", - ), - ] - - def test_doc_gen(self) -> None: - # make tmp output dir - tmp_output = _DIR_PATH / "tmp" - for t_case in self.test_cases: - tmp_output_current = ( - tmp_output - / f"docs_{t_case.format}_{t_case.filename.rsplit('.k', 1)[0]}_{t_case.locale}" - ) - expect_output_current = ( - _DOCS_PATH - / f"docs_{t_case.format}_{t_case.filename.rsplit('.k', 1)[0]}_{t_case.locale}" - ) - # generate docs to tmp output dir - kcl_doc_generate( - kcl_files=[str(_SOURCE_PATH / t_case.filename)], - recursively=t_case.recursive, - output=str(tmp_output_current), - # output=str(expect_output_current), # for expect docs generate - format=t_case.format, - repo_url="https://url/to/source_code", - with_locale_suffix=True, - ) - # compare docs between expect and got - match, mismatch, errors = filecmp.cmpfiles( - expect_output_current, - tmp_output_current, - common=[ - str(f.relative_to(tmp_output_current)) - for f in list( - tmp_output_current.rglob( - f"*{doc_formats.KCLDocSuffix.TO_SUFFIX[t_case.format.upper()]}" - ) - ) - ], - ) - assert len(mismatch) == 0, f"mismatch exists: {mismatch}. {t_case.filename}" - assert len(errors) == 0, f"errors exists: {errors}. {t_case.filename}" - - # clear tmp files - shutil.rmtree(tmp_output) - - -class KCLDocI18nGenTest(unittest.TestCase): - test_cases = [ - KCLDocGenTestData( - filename="simple.k", - format="markdown", - recursive=True, - locale="zh_cn", - i18n_path="i18n_simple_zh_cn.yaml", - ), - KCLDocGenTestData( - filename="frontend", - format="markdown", - recursive=True, - locale="zh_cn", - i18n_path="frontend", - ), - ] - - def test_doc_gen_by_i18n(self) -> None: - # make tmp output dir - tmp_output = _DIR_PATH / "tmp" - for t_case in self.test_cases: - tmp_output_current = ( - tmp_output - / f"docs_{t_case.format}_{t_case.filename.rsplit('.k', 1)[0]}_{t_case.locale}" - ) - expect_output_current = ( - _DOCS_PATH - / f"docs_{t_case.format}_{t_case.filename.rsplit('.k', 1)[0]}_{t_case.locale}" - ) - # generate docs to tmp output dir - kcl_doc_generate( - kcl_files=[str(_SOURCE_PATH / t_case.filename)], - recursively=t_case.recursive, - output=str(tmp_output_current), - # output=str(expect_output_current), # for expect docs generate - format=t_case.format, - repo_url="https://url/to/source_code", - locale=t_case.locale, - i18n_path=str(_I18N_PATH / t_case.i18n_path), - with_locale_suffix=True, - ) - # compare docs between expect and got - match, mismatch, errors = filecmp.cmpfiles( - expect_output_current, - tmp_output_current, - common=[ - str(f.relative_to(tmp_output_current)) - for f in list( - tmp_output_current.rglob( - f"*{doc_formats.KCLDocSuffix.TO_SUFFIX[t_case.format.upper()]}" - ) - ) - ], - ) - assert len(mismatch) == 0, f"mismatch exists: {mismatch}. {t_case.filename}" - assert len(errors) == 0, f"errors exists: {errors}. {t_case.filename}" - - # clear tmp files - shutil.rmtree(tmp_output) - - -if __name__ == "__main__": - unittest.main(verbosity=2) diff --git a/test/test_units/test_kclvm/test_tools/test_doc/test_doc_parser.py b/test/test_units/test_kclvm/test_tools/test_doc/test_doc_parser.py deleted file mode 100644 index 2bf62dba2..000000000 --- a/test/test_units/test_kclvm/test_tools/test_doc/test_doc_parser.py +++ /dev/null @@ -1,194 +0,0 @@ -import unittest -import pathlib -import typing - -import kclvm.compiler.parser.parser as parser -import kclvm.tools.docs.doc_parser as doc_parser -import kclvm.kcl.types.checker as type_checker -import kclvm.api.object as obj_pkg -import kclvm.tools.docs.model_pb2 as model - - -_DIR_PATH = pathlib.Path(__file__).parent.joinpath("doc_data") / "source_files" - - -def resolve(kcl_file: str) -> typing.List[model.SchemaDoc]: - prog = parser.LoadProgram(kcl_file) - type_checker.ResolveProgramImport(prog) - checker = type_checker.TypeChecker(prog, type_checker.CheckConfig()) - checker.check_import(prog.MAIN_PKGPATH) - checker.init_global_types() - schemas = prog.pkgs[prog.MAIN_PKGPATH][0].GetSchemaList() - - schema_docs: typing.List[model.SchemaDoc] = [] - for schema in schemas: - schema_obj_type = checker.scope_map[prog.MAIN_PKGPATH].elems[schema.name].type - assert isinstance(schema_obj_type, obj_pkg.KCLSchemaDefTypeObject) - schema_docs.append( - doc_parser.SchemaDocParser( - schema=schema, - schema_type=schema_obj_type.schema_type, - root=prog.root, - ).doc - ) - return schema_docs - - -class KCLDocGenTest(unittest.TestCase): - def test_simple_case(self) -> None: - docs = resolve(_DIR_PATH / "simple.k") - assert len(docs) == 1 - doc = docs[0] - assert doc.doc.startswith("Person is a simple schema") - assert doc.attributes[0].name == "name" - assert doc.attributes[0].type.type_str == "str" - assert doc.attributes[0].is_optional is False - assert doc.attributes[0].default_value == '"Default"' - assert doc.attributes[0].doc.startswith("A Normal attribute named 'name'") - assert doc.attributes[1].name == "age" - assert doc.attributes[1].type.type_str == "int" - assert doc.attributes[1].is_optional is True - assert doc.attributes[1].default_value == "18" - assert doc.attributes[1].doc.startswith("A Normal attribute named 'age'") - assert doc.examples.startswith("person = Person {") - - def test_good_case(self) -> None: - docs = resolve(_DIR_PATH / "good.k") - assert len(docs) == 1 - doc = docs[0] - assert doc.doc.startswith( - "Server is the common user interface for long-running" - ) - assert doc.attributes[0].name == "workloadType" - assert doc.attributes[0].type.type_str == "str" - assert doc.attributes[0].is_optional is False - assert doc.attributes[0].default_value == "Deployment" - assert doc.attributes[0].doc.startswith( - "Use this attribute to specify which kind of long-running service you want" - ) - assert doc.attributes[1].name == "name" - assert doc.attributes[1].type.type_str == "str" - assert doc.attributes[1].is_optional is False - assert doc.attributes[1].default_value == "" - assert doc.attributes[1].doc.startswith("A Server-level attribute") - assert doc.attributes[2].name == "labels" - assert doc.attributes[2].type.type_str == "{str: str}" - assert doc.attributes[2].is_optional is True - assert doc.attributes[2].default_value == "" - assert doc.attributes[2].doc.startswith("A Server-level attribute") - assert doc.examples.startswith("myCustomApp = AppConfiguration") - - def test_no_type_case(self) -> None: - docs = resolve(_DIR_PATH / "no_type.k") - assert len(docs) == 1 - doc = docs[0] - assert doc.doc.startswith( - "Server is the common user interface for long-running" - ) - assert doc.attributes[0].name == "workloadType" - assert doc.attributes[0].type.type_str == "str" - assert doc.attributes[0].is_optional is False - assert doc.attributes[0].default_value == "Deployment" - assert doc.attributes[0].doc.startswith( - "Use this attribute to specify which kind of long-running service you want" - ) - assert doc.attributes[1].name == "name" - assert doc.attributes[1].type.type_str == "str" - assert doc.attributes[1].is_optional is False - assert doc.attributes[1].default_value == "" - assert doc.attributes[1].doc.startswith("A Server-level attribute") - assert doc.attributes[2].name == "labels" - assert doc.attributes[2].type.type_str == "{str: str}" - assert doc.attributes[2].is_optional is True - assert doc.attributes[2].default_value == "" - assert doc.attributes[2].doc.startswith("A Server-level attribute") - assert doc.attributes[3].name == "replica" - assert doc.attributes[3].type.type_str == "int" - assert doc.attributes[3].is_optional is True - assert doc.attributes[3].default_value == "1" - assert doc.attributes[3].doc.startswith("Replica of the server") - assert doc.examples.startswith("myCustomApp = AppConfiguration") - - def test_compact_type_case(self) -> None: - docs = resolve(_DIR_PATH / "compact_type.k") - assert len(docs) == 2 - doc = docs[0] - assert doc.doc.startswith("Metadata is the base schema of all models") - assert doc.attributes[0].name == "name" - assert doc.attributes[0].type.type_str == "str" - assert doc.attributes[0].is_optional is False - assert doc.attributes[0].default_value == "" - assert doc.attributes[0].doc.startswith("The name of the resource.") - assert doc.attributes[1].name == "labels" - assert doc.attributes[1].type.type_str == "{str: str}" - assert doc.attributes[1].is_optional is True - assert doc.attributes[1].default_value == "" - assert doc.attributes[1].doc.startswith( - "Labels is a map of string keys and values" - ) - assert doc.attributes[2].name == "annotations" - assert doc.attributes[2].type.type_str == "{str: str}" - assert doc.attributes[2].is_optional is True - assert doc.attributes[2].default_value == "" - assert doc.attributes[2].doc.startswith( - "Annotations is an unstructured key value map" - ) - assert doc.attributes[3].name == "namespace" - assert doc.attributes[3].type.type_str == "str" - assert doc.attributes[3].is_optional is True - assert doc.attributes[3].default_value == "default" - assert doc.attributes[3].doc.startswith( - "Namespaces are intended for use in environments" - ) - assert doc.examples == "" - - doc = docs[1] - assert doc.doc.startswith("AppConfiguration is the common user interface") - assert doc.attributes[0].name == "workloadType" - assert doc.attributes[0].type.type_str == "str" - assert doc.attributes[0].is_optional is False - assert doc.attributes[0].default_value == "Deployment" - assert doc.attributes[0].doc.startswith("Use this attribute to specify") - assert doc.attributes[1].name == "name" - assert doc.attributes[1].type.type_str == "str" - assert doc.attributes[1].is_optional is False - assert doc.attributes[1].default_value == "" - assert doc.attributes[1].doc.startswith("Required.\nA Server-level attribute.") - assert doc.attributes[2].name == "namespace" - assert doc.attributes[2].type.type_str == "str" - assert doc.attributes[2].is_optional is False - assert doc.attributes[2].default_value == "default" - assert doc.attributes[2].doc.startswith("Required.\nA Server-level attribute.") - assert doc.attributes[3].name == "app" - assert doc.attributes[3].type.type_str == "str" - assert doc.attributes[3].is_optional is False - assert doc.attributes[3].default_value == "" - assert doc.attributes[3].doc.startswith("A Server-level attribute.") - assert doc.examples.startswith("myCustomApp = AppConfiguration {") - - def test_base_schema_case(self) -> None: - docs = resolve(_DIR_PATH / "base_schema.k") - assert len(docs) == 2 - doc = docs[0] - assert doc.attributes[0].name == "name" - assert doc.attributes[0].type.type_str == "str" - assert doc.attributes[0].is_optional is False - assert doc.attributes[0].default_value == "" - assert doc.attributes[1].name == "age" - assert doc.attributes[1].type.type_str == "int" - assert doc.attributes[1].is_optional is False - assert doc.attributes[1].default_value == "" - - doc = docs[1] - assert doc.doc.startswith("Student is the person with a grade") - assert doc.attributes[0].name == "grade" - assert doc.attributes[0].type.type_str == "int" - assert doc.attributes[0].is_optional is False - assert doc.attributes[0].default_value == "Undefined" - assert doc.attributes[0].doc.startswith( - "the current grade that the student is in." - ) - - -if __name__ == "__main__": - unittest.main(verbosity=2) diff --git a/test/test_units/test_kclvm/test_tools/test_doc/test_i18n.py b/test/test_units/test_kclvm/test_tools/test_doc/test_i18n.py deleted file mode 100644 index 1783416b0..000000000 --- a/test/test_units/test_kclvm/test_tools/test_doc/test_i18n.py +++ /dev/null @@ -1,83 +0,0 @@ -import filecmp -import pathlib -import shutil -import unittest - -import kclvm.tools.docs.formats as doc_formats -from kclvm.tools.docs.doc import kcl_i18n_init - -_DIR_PATH = pathlib.Path(__file__).parent.joinpath("doc_data") -_SOURCE_PATH = _DIR_PATH / "source_files" -_DOCS_PATH = _DIR_PATH / "docs" - - -class KCLDocI18nTestData: - def __init__(self, filename: str, format: str, recursive: bool, locale: str): - self.filename: str = filename - self.format: str = format - self.recursive: bool = recursive - self.locale: str = locale - - -class KCLDocI18nInitTest(unittest.TestCase): - test_cases = [ - KCLDocI18nTestData( - filename="frontend", - format=doc_formats.KCLI18NFormat.YAML, - recursive=True, - locale="zh_cn", - ), - KCLDocI18nTestData( - filename="simple.k", - format=doc_formats.KCLI18NFormat.YAML, - recursive=True, - locale="zh_cn", - ), - KCLDocI18nTestData( - filename="compact_type.k", - format=doc_formats.KCLI18NFormat.YAML, - recursive=True, - locale="zh_cn", - ), - ] - - def test_doc_i18n_init(self) -> None: - # make tmp output dir - tmp_output = _DIR_PATH / "tmp" - for t_case in self.test_cases: - tmp_output_current = ( - tmp_output - / f"i18n_docs_{t_case.format}_{t_case.filename.rsplit('.k', 1)[0]}_{t_case.locale}" - ) - expect_output_current = ( - _DOCS_PATH - / f"i18n_docs_{t_case.format}_{t_case.filename.rsplit('.k', 1)[0]}_{t_case.locale}" - ) - # generate docs to tmp output dir - kcl_i18n_init( - kcl_files=[str(_SOURCE_PATH / t_case.filename)], - recursively=t_case.recursive, - output=str(tmp_output_current), - # output=str(expect_output_current), # for expect docs generate - format=t_case.format, - locale=t_case.locale, - with_locale_suffix=True, - ) - - match, mismatch, errors = filecmp.cmpfiles( - expect_output_current, - tmp_output_current, - common=[ - str(f.relative_to(tmp_output_current)) - for f in list( - tmp_output_current.rglob( - f"*{doc_formats.KCLDocSuffix.TO_SUFFIX[t_case.format.upper()]}" - ) - ) - ], - ) - assert len(mismatch) == 0, f"mismatch exists: {mismatch}. {t_case.filename}" - assert len(errors) == 0, f"errors exists: {errors}. {t_case.filename}" - - # clear tmp files - shutil.rmtree(tmp_output) diff --git a/test/test_units/test_kclvm/test_tools/test_format/format_data/assert.golden b/test/test_units/test_kclvm/test_tools/test_format/format_data/assert.golden deleted file mode 100644 index 6bf676029..000000000 --- a/test/test_units/test_kclvm/test_tools/test_format/format_data/assert.golden +++ /dev/null @@ -1,3 +0,0 @@ -assert True if True, "message" -assert False if data, "message" # Comment -assert 1 diff --git a/test/test_units/test_kclvm/test_tools/test_format/format_data/codelayout.input b/test/test_units/test_kclvm/test_tools/test_format/format_data/codelayout.input deleted file mode 100644 index a64e4feed..000000000 --- a/test/test_units/test_kclvm/test_tools/test_format/format_data/codelayout.input +++ /dev/null @@ -1,74 +0,0 @@ - - - -import math as alias_math -schema Person: - name:str# inline comment - age:int -person = Person{ - name:"Alice" - age:18 -} -if True: - a = 1 -elif True: - b = 2 -else: - c = 3 -d = 1 + 2 -e = ( 1 + 2 ) -f=[ 1, 2, 3 ] -g = { "key" : "value" } -# block comment -print (1) -dct={"key": "value"} -lst=[1,2,3] -h = dct [ 'key' ] -i = lst [ 1 ] -x = 1 -y = 2 -long_variable = 3 -i = i+1 -submitted+=1 -x = x*2 - 1 -hypot2 = x*x + y*y -_c = (a+b) * (a-b) -_b=2 -_c= 3 -_d =4 - -_value = (1 + 2 * 3) -_value = (1+2*3) -_value =1+ - 2 * ~ 3 -_list = [1, 2, 3] -_list = [*_list, [4, 5 ,6]] -_list = [* _list, [4, 5 ,6]] - -_dict = {** {"k": "v"}, ** {"k": "v"}} -a = [1,2,3] -b = [ - 1,2,3, - 4,5,6, -] -_dict={ - "k1":"v1" - "k2" :"v2" - "k3": "v3" - "k4" : "v4" - "k5" : "v5" -} -foo=1 -if foo is not None: - _a = 1 - _dict|={} - hello = "world{}" . format( 1 )[2 : 4] . lower( ) - range_int = [ i for i in range( 10 ) if i > 1 ] -op = 1+2 - - 3 + (3 - 1) // 3 -op += 1 -op -= 12 + 23 -print( " " , end= '') -log = math. log(12) -aa = 1 -assert aa == 1,"message" -aaaa = (1 + 2 / 2) if _a == 2 + + 134.3 else ("a"*3) -bbbb = "{}". format(a) \ No newline at end of file diff --git a/test/test_units/test_kclvm/test_tools/test_format/format_data/comment.golden b/test/test_units/test_kclvm/test_tools/test_format/format_data/comment.golden deleted file mode 100644 index a82bf0a81..000000000 --- a/test/test_units/test_kclvm/test_tools/test_format/format_data/comment.golden +++ /dev/null @@ -1,10 +0,0 @@ -# Block comment -a = 1 # Inline comment - -schema Person: - """ - Schema doc string - """ - name: str = "Alice" # Inline comment in schema - # Block comment in schema - age: int = 18 diff --git a/test/test_units/test_kclvm/test_tools/test_format/format_data/comment.input b/test/test_units/test_kclvm/test_tools/test_format/format_data/comment.input deleted file mode 100644 index 2134faeb9..000000000 --- a/test/test_units/test_kclvm/test_tools/test_format/format_data/comment.input +++ /dev/null @@ -1,9 +0,0 @@ -# Block comment -a = 1# Inline comment -schema Person: - """ - Schema doc string - """ - name:str="Alice"# Inline comment in schema - # Block comment in schema - age:int=18 \ No newline at end of file diff --git a/test/test_units/test_kclvm/test_tools/test_format/format_data/comp_for.golden b/test/test_units/test_kclvm/test_tools/test_format/format_data/comp_for.golden deleted file mode 100644 index e20b45832..000000000 --- a/test/test_units/test_kclvm/test_tools/test_format/format_data/comp_for.golden +++ /dev/null @@ -1,7 +0,0 @@ -data0 = [ - i + 1 for i in range(10) if i > 1 -] -data1 = [ - i + 1 for i in range(10) - if i > 1 -] diff --git a/test/test_units/test_kclvm/test_tools/test_format/format_data/comp_for.input b/test/test_units/test_kclvm/test_tools/test_format/format_data/comp_for.input deleted file mode 100644 index a4bb9ab42..000000000 --- a/test/test_units/test_kclvm/test_tools/test_format/format_data/comp_for.input +++ /dev/null @@ -1,7 +0,0 @@ -data0 = [ - i + 1 for i in range(10) if i > 1 -] -data1 = [ - i + 1 for i in range(10) - if i > 1 -] diff --git a/test/test_units/test_kclvm/test_tools/test_format/format_data/import.input b/test/test_units/test_kclvm/test_tools/test_format/format_data/import.input deleted file mode 100644 index 977a13711..000000000 --- a/test/test_units/test_kclvm/test_tools/test_format/format_data/import.input +++ /dev/null @@ -1,10 +0,0 @@ -import a - -import b - -import c -import d - -import e as e - -a = 1 diff --git a/test/test_units/test_kclvm/test_tools/test_format/format_data/lambda.golden b/test/test_units/test_kclvm/test_tools/test_format/format_data/lambda.golden deleted file mode 100644 index 08d1b9b63..000000000 --- a/test/test_units/test_kclvm/test_tools/test_format/format_data/lambda.golden +++ /dev/null @@ -1,6 +0,0 @@ -f0 = lambda { - 1 + 1 -} -f1 = lambda x: int, y: int -> int { - x + y -} diff --git a/test/test_units/test_kclvm/test_tools/test_format/format_data/lambda.input b/test/test_units/test_kclvm/test_tools/test_format/format_data/lambda.input deleted file mode 100644 index 55039b367..000000000 --- a/test/test_units/test_kclvm/test_tools/test_format/format_data/lambda.input +++ /dev/null @@ -1,6 +0,0 @@ -f0 = lambda { - 1 + 1 -} -f1 = lambda x : int , y : int ->int{ - x + y -} diff --git a/test/test_units/test_kclvm/test_tools/test_format/format_data/quant.input b/test/test_units/test_kclvm/test_tools/test_format/format_data/quant.input deleted file mode 100644 index a6a65a3c2..000000000 --- a/test/test_units/test_kclvm/test_tools/test_format/format_data/quant.input +++ /dev/null @@ -1,8 +0,0 @@ -a = all x in [-1, 0, 1, 2, 3] { - x >= 1 if x > 0 -} -b = any x in {k1 = "v1", k2 = "v2"} {x in ["k1", "v2"]} -c = map x in {k1 = "v1", k2 = "v2"} {x} -d = filter x in [1, 2, 3] { - x > 1 -} diff --git a/test/test_units/test_kclvm/test_tools/test_format/format_data/schema.golden b/test/test_units/test_kclvm/test_tools/test_format/format_data/schema.golden deleted file mode 100644 index 04f126520..000000000 --- a/test/test_units/test_kclvm/test_tools/test_format/format_data/schema.golden +++ /dev/null @@ -1,21 +0,0 @@ -import math - -schema XXMixin: - nameVar: str - -schema Base: - """ - Base schema doc string - """ - mixin [XXMixin, XXMixin] - name: str = "Alice" - labels: {str:str} = None - -schema Person[para1:str = "value", para2="value"](Base): - age: int = 18 - name = para - check: - True - bool(math.log(10)) - -person = Person(para1="12") {} diff --git a/test/test_units/test_kclvm/test_tools/test_format/format_path_data/output.golden b/test/test_units/test_kclvm/test_tools/test_format/format_path_data/output.golden deleted file mode 100644 index 874e8f629..000000000 --- a/test/test_units/test_kclvm/test_tools/test_format/format_path_data/output.golden +++ /dev/null @@ -1,14 +0,0 @@ -if True: - a = 1 -elif True: - b = 2 - if True: - c = 3 - else: - d = 4 -else: - e = 8 - -schema Person: - name: str - age: int diff --git a/test/test_units/test_kclvm/test_tools/test_format/test_format.py b/test/test_units/test_kclvm/test_tools/test_format/test_format.py deleted file mode 100644 index eff9ff89f..000000000 --- a/test/test_units/test_kclvm/test_tools/test_format/test_format.py +++ /dev/null @@ -1,232 +0,0 @@ -#! /usr/bin/env python3 - -import io -import sys -import unittest -import pathlib -from typing import Tuple - -from kclvm.tools.format import kcl_fmt_source, kcl_fmt, TextAdapterWalker, Formatter - - -_FILE_INPUT_SUFFIX = ".input" -_FILE_OUTPUT_SUFFIX = ".golden" -_PATH_NAME = "format_data" -_DIR_PATH = pathlib.Path(__file__).parent.joinpath(_PATH_NAME) -_TEST_CASES = [ - "assert", - "check", - "blankline", - "breakline", - "codelayout", - "collection_if", - "comment", - "comp_for", - "empty", - "import", - "indent", - "inline_comment", - "lambda", - "quant", - "schema", - "string", - "type_alias", - "unary", -] -TEST_FMT_PATH = pathlib.Path(__file__).parent.joinpath("format_path_data") -FMT_PATH_EXPECTED_OUTPUT = pathlib.Path(__file__).parent.joinpath("format_path_data/output.golden").read_text() - - -class KCLBaseFormatterTest(unittest.TestCase): - """ - KCL base formatter test - """ - - def read_data(self, data_name: str) -> Tuple[str, str]: - """ - Read format data according to data name - """ - input_filename = data_name + _FILE_INPUT_SUFFIX - output_filename = data_name + _FILE_OUTPUT_SUFFIX - data_input = (_DIR_PATH / input_filename).read_text() - data_output = (_DIR_PATH / output_filename).read_text() - return data_input, data_output - - def assert_format_equal(self, data_name: str) -> None: - """ - Read format test data according to data name and assert equal. - """ - data_input, data_output = self.read_data(data_name) - formatted, _ = kcl_fmt_source(data_input) - self.assertMultiLineEqual(formatted, data_output) - - def assert_printer_equal(self, string: str, walker: TextAdapterWalker) -> bool: - """ - Read walker printer buffer string and assert it is equal to 'string' - """ - walker.printer.seek(0) - self.assertEqual(string, walker.printer.read()) - - -class KCLFormatterTest(KCLBaseFormatterTest): - def test_format_data(self) -> None: - """ - Test format data for the comparison of input and golden files - """ - self.maxDiff = None - for case in _TEST_CASES: - print(case+"-begin") - self.assert_format_equal(case) - print(case+"-end") - - def test_text_adapter_walker_write(self) -> None: - """ - Test TextAdapterWalker class write function in kclvm format.py - """ - inputs = ["test", "123", "456", "\n"] - outputs = ["test", "test123", "test123456", "test123456\n"] - walker = TextAdapterWalker() - for input, output in zip(inputs, outputs): - walker.write(input) - self.assert_printer_equal(output, walker) - - def test_text_adapter_walker_blankline(self) -> None: - """ - Test TextAdapterWalker class blankline function in kclvm format.py - """ - inputs = [ - "\n", - "\n\n", - "\n\n\n", - "\n \n \n", - "\n # comment \n \n", - "\n # comment \n # comment \n", - ] - outputs = [0, 1, 2, 2, 1, 0] - walker = TextAdapterWalker() - for input, output in zip(inputs, outputs): - self.assertEqual(walker.count_blank_line(input), output) - - def test_text_adapter_walker_indent(self) -> None: - """ - Test TextAdapterWalker class indent function in kclvm format.py - """ - inputs = ["", " ", "\n ", " \n ", "\n ", "\n\n ", "\n ", "\n"] - outputs = [0, 0, 2, 2, 4, 4, 2, 0] - levels = [0, 0, 1, 1, 2, 2, 1, 0] - walker = TextAdapterWalker() - for input, output, level in zip(inputs, outputs, levels): - self.assertEqual(walker.count_indent(input), output) - self.assertEqual(walker.indent_level, level) - - def test_formatter_split_newline(self) -> None: - """ - Test Formatter class split_newline function in kclvm format.py - """ - inputs = [ - "\n# comment\n", - "\n # comment \n", - "\n # comment \n ", - "\n # comment # \n", - "\n\n # comment \\n # \n", - "\n\n # comment \\n # \n#comment\n", - "\n \n # comment \n # comment \n\n # comment \n", - "\n\n # comment \\n # # \n # \n # \n \n# comment\n\n# comment \n", - ] - outputs = [ - ["\n", "# comment", "\n"], - ["\n ", "# comment ", "\n"], - ["\n ", "# comment ", "\n "], - ["\n ", "# comment # ", "\n"], - ["\n\n ", "# comment \\n # ", "\n"], - ["\n\n ", "# comment \\n # ", "\n", "#comment", "\n"], - ["\n \n ", "# comment ", "\n ", "# comment ", "\n\n ", "# comment ", "\n"], - [ - "\n\n ", - "# comment \\n # # ", - "\n ", - "# ", - "\n ", - "# ", - "\n \n", - "# comment", - "\n\n", - "# comment ", - "\n", - ], - ] - formatter = Formatter() - for input, output in zip(inputs, outputs): - self.assertListEqual(formatter.split_newline_value(input), output) - - def test_formatter_write_newline(self) -> None: - """ - Test Formatter class write newline function in kclvm format.py - """ - inputs = ["\n", "\n\n", "\n\n\n", "\n\n\n\n"] - outputs = ["\n", "\n\n", "\n\n", "\n\n"] - for input, output in zip(inputs, outputs): - formatter = Formatter() - formatter.write_newline(input) - self.assert_printer_equal(output, formatter) - - def test_formatter_write_string(self) -> None: - """ - Test Formatter class write newline function in kclvm format.py - """ - inputs = ["'test'", '"test"', "R'test'", 'B"test"'] - outputs = ["'test'", '"test"', "r'test'", 'b"test"'] - for input, output in zip(inputs, outputs): - formatter = Formatter() - formatter.write_string(input) - self.assert_printer_equal(output, formatter) - - def test_kcl_fmt_recursively(self): - with io.StringIO() as buf: - origin_io = sys.stdout - sys.stdout = buf - kcl_fmt(TEST_FMT_PATH, is_stdout=True, recursively=True) - # Format two files recursively - self.assertEqual(buf.getvalue().count(FMT_PATH_EXPECTED_OUTPUT), 2) - sys.stdout = origin_io - - def test_kcl_fmt_non_recursively(self): - # Format one file non-recursively - with io.StringIO() as buf: - origin_io = sys.stdout - sys.stdout = buf - kcl_fmt(TEST_FMT_PATH, is_stdout=True, recursively=False) - # only one file formatted - self.assertEqual(buf.getvalue().count(FMT_PATH_EXPECTED_OUTPUT), 1) - sys.stdout = origin_io - - def test_kcl_fmt_single_file(self): - # Format single file - for case in _TEST_CASES: - with io.StringIO() as buf: - origin_io = sys.stdout - sys.stdout = buf - input_filename = str(_DIR_PATH / (case + _FILE_INPUT_SUFFIX)) - output_filename = case + _FILE_OUTPUT_SUFFIX - expect_output = (_DIR_PATH / output_filename).read_text() - - kcl_fmt(input_filename, is_stdout=True) - self.assertEqual(expect_output, buf.getvalue()) - sys.stdout = origin_io - - - def test_kcl_fmt_not_stdout(self): - for case in _TEST_CASES: - input_filepath = _DIR_PATH / (case + _FILE_INPUT_SUFFIX) - output_filepath = _DIR_PATH / (case + _FILE_OUTPUT_SUFFIX) - ori_content_backup = input_filepath.read_text() - expect_output = output_filepath.read_text() - - kcl_fmt(input_filepath, is_stdout=False) - formatted_content = input_filepath.read_text() - self.assertEqual(expect_output, formatted_content) - input_filepath.write_text(ori_content_backup) - - -if __name__ == "__main__": - unittest.main(verbosity=2) diff --git a/test/test_units/test_kclvm/test_tools/test_lint/test_checker/test_checker.py b/test/test_units/test_kclvm/test_tools/test_lint/test_checker/test_checker.py deleted file mode 100644 index 41ba1a904..000000000 --- a/test/test_units/test_kclvm/test_tools/test_lint/test_checker/test_checker.py +++ /dev/null @@ -1,177 +0,0 @@ -import unittest -import pathlib -import kclvm.tools.lint.lint.KCLLint as KCLLint -from kclvm.tools.lint.message.message import Message -import kclvm.compiler.parser.parser as parser - -_FILE_INPUT_SUFFIX = ".k" -_FILE_OUTPUT_SUFFIX = ".golden" -_PATH_NAME = "test_data" -_DIR_PATH = pathlib.Path(__file__).parent.joinpath(_PATH_NAME) -_TEST_CASE_NAMES = [ - "import", - "misc", - "basic", -] -_TEST_CASE_OUTPUT = { - "import": [ - Message("E0401", - str(_DIR_PATH.joinpath("import.k")), - "Unable to import abc.", - "import abc # unable to import", - (1, 1), - ["abc"]), - Message("W0404", - str(_DIR_PATH.joinpath("import.k")), - "a is reimported multiple times.", - "import a # reimport", - (3, 1), - ["a"]), - Message("E0413", - str(_DIR_PATH.joinpath("import.k")), - "Import b should be placed at the top of the module.", - "import b # import position", - (18, 1), - ["b"]), - Message("W0411", - str(_DIR_PATH.joinpath("import.k")), - "math imported but unused.", - "import math", - (5, 1), - ["math"]), - Message("W0411", - str(_DIR_PATH.joinpath("import.k")), - "b imported but unused.", - "import b # import position", - (18, 1), - ["b"]), - - ], - "misc": [ - Message("E0501", - str(_DIR_PATH.joinpath("misc.k")), - "line too long (121 > 120 characters).", - "# line too long, line too long, line too long, line too long, line too long, line too long, line too long, line too long,", - (1, 1), - [121, 120]) - ], - "basic": [ - Message("C0103", - str(_DIR_PATH.joinpath("basic.k")), - "Variable name \"I\" doesn't conform to ^[^\W\dA-Z][^\W_]+$.", - "I = 1", - (2, 1), - ['Variable', 'I', '^[^\\W\\dA-Z][^\\W_]+$']), - - Message("C0104", - str(_DIR_PATH.joinpath("basic.k")), - "Disallowed name \"I\".", - "I = 1", - (2, 1), - ['I']), - Message("C0103", - str(_DIR_PATH.joinpath("basic.k")), - "Schema name \"person\" doesn't conform to PascalCase naming style.", - "schema person:", - (5, 8), - ['Schema', 'person', 'PascalCase naming style']), - Message("C0103", - str(_DIR_PATH.joinpath("basic.k")), - "Mixin name \"personMixin\" doesn't conform to PascalCase naming style.", - "mixin personMixin:", - (9, 7), - ['Mixin', 'personMixin', 'PascalCase naming style']), - Message("C0103", - str(_DIR_PATH.joinpath("basic.k")), - "Argument name \"PaP\" doesn't conform to camelCase naming style.", - "schema Person[PaP]:", - (13, 15), - ['Argument', 'PaP', 'camelCase naming style']), - Message("C0103", - str(_DIR_PATH.joinpath("basic.k")), - "Schema attribute name \"Age\" doesn't conform to camelCase naming style.", - " Age : int = 1", - (15, 5), - ['Schema attribute', 'Age', 'camelCase naming style']), - Message("C0103", - str(_DIR_PATH.joinpath("basic.k")), - "Variable name \"pers_on\" doesn't conform to ^[^\W\dA-Z][^\W_]+$.", - "pers_on = Person {", - (19, 1), - ['Variable', 'pers_on', '^[^\\W\\dA-Z][^\\W_]+$']), - Message("C0103", - str(_DIR_PATH.joinpath("basic.k")), - "Protocol name \"personProtocol\" doesn't conform to PascalCase naming style.", - "protocol personProtocol:", - (24, 10), - ['Protocol', 'personProtocol', 'PascalCase naming style']), - Message("C0103", - str(_DIR_PATH.joinpath("basic.k")), - "Schema name \"someRule\" doesn't conform to PascalCase naming style.", - "rule someRule:", - (39, 6), - ['Schema', 'someRule', 'PascalCase naming style']), - ], -} -CHECKER_CONFIG = { - "check_list": ["import", "misc", "basic"], - "ignore": [], - "max_line_length": 120, - "output": ["stdout"], - "output_path": None, - "module_naming_style": "ANY", - "package_naming_style": "ANY", - "schema_naming_style": "PascalCase", - "mixin_naming_style": "PascalCase", - "argument_naming_style": "camelCase", - "schema_attribute_naming_style": "camelCase", - "variable_rgx": r"^[^\W\dA-Z][^\W_]+$", - "bad_names": ["foo", "bar", "baz", "toto", "tata", "tutu", "I", "l", "O"], -} - - -class KCLCheckerBaseTest(unittest.TestCase): - def setUp(self): - self.maxDiff = None - - def read_data(self, data_name: str): - """Read test data""" - input_filename = data_name + _FILE_INPUT_SUFFIX - input_file = _DIR_PATH / input_filename - with open(input_file) as f: - code = f.read() - - return input_file, code - - def assert_checker_msgs_equal( - self, case: str, input_file: str, code: str - ): - checker = KCLLint.CheckerFactory.get_checker(case) - checker.options = KCLLint.LinterConfig() - checker.options.update(CHECKER_CONFIG) - prog = parser.LoadProgram(input_file) - checker.check(prog, code) - for i, m in enumerate(checker.msgs): - expect = _TEST_CASE_OUTPUT[case][i] - self.assertEqual(expect, m, f"Expected:\n{expect}\narguments:{expect.arguments}\nActual:\n{m}\narguments:{m.arguments}") - - -class KCLCheckerTest(KCLCheckerBaseTest): - def test_checker_msgs(self) -> None: - for case in _TEST_CASE_NAMES: - input_file, code = self.read_data(case) - self.assert_checker_msgs_equal(case, input_file, code) - - def test_dot_path(self) -> None: - # When the path is `.`, the filename in ast is "a/./b". This may affect import path check, e.g: a/./b == a/b - input_file = _DIR_PATH / ("./import" + _FILE_INPUT_SUFFIX) - with open(input_file) as f: - code = f.read() - checker = KCLLint.CheckerFactory.get_checker("import") - checker.options = CHECKER_CONFIG - prog = parser.LoadProgram(input_file) - checker.check(prog, code) - - -if __name__ == "__main__": - unittest.main(verbosity=2) diff --git a/test/test_units/test_kclvm/test_tools/test_lint/test_checker/test_data/a.k b/test/test_units/test_kclvm/test_tools/test_lint/test_checker/test_data/a.k deleted file mode 100644 index 12a18c3c3..000000000 --- a/test/test_units/test_kclvm/test_tools/test_lint/test_checker/test_data/a.k +++ /dev/null @@ -1,4 +0,0 @@ -_a = 1 -schema Person: - name: str - age: int \ No newline at end of file diff --git a/test/test_units/test_kclvm/test_tools/test_lint/test_checker/test_data/basic.k b/test/test_units/test_kclvm/test_tools/test_lint/test_checker/test_data/basic.k deleted file mode 100644 index 618d8e703..000000000 --- a/test/test_units/test_kclvm/test_tools/test_lint/test_checker/test_data/basic.k +++ /dev/null @@ -1,40 +0,0 @@ -# disallowed name -I = 1 - -#schema name -schema person: - name : str = "kcl" - -# mixin -mixin personMixin: - name : str = "kcl" - -# schema argument, camelCase -schema Person[PaP]: - # schema attr, camelCase - Age : int = 1 - name : str = "1" - -# variable, rgx: ^[^\W\dA-Z][^\W_]+$ -pers_on = Person { - age = 1 -} - -# protocol -protocol personProtocol: - name : str = "kcl" - -# TODO: just for test coverage, remove when fix generic_walk for IfStmt.elif_body: List[List[Stmt]] -if Ture: - _c = 1 -elif True: - _c = 2 -else: - _c = 3 - -# rule name -rule SomeRule: - i > 1 - -rule someRule: - i > 1 diff --git a/test/test_units/test_kclvm/test_tools/test_lint/test_checker/test_data/d.k b/test/test_units/test_kclvm/test_tools/test_lint/test_checker/test_data/d.k deleted file mode 100644 index 5f833b16d..000000000 --- a/test/test_units/test_kclvm/test_tools/test_lint/test_checker/test_data/d.k +++ /dev/null @@ -1,2 +0,0 @@ -schema Parent: - age1?: int \ No newline at end of file diff --git a/test/test_units/test_kclvm/test_tools/test_lint/test_checker/test_data/e.k b/test/test_units/test_kclvm/test_tools/test_lint/test_checker/test_data/e.k deleted file mode 100644 index 30670d303..000000000 --- a/test/test_units/test_kclvm/test_tools/test_lint/test_checker/test_data/e.k +++ /dev/null @@ -1,2 +0,0 @@ -schema UnionType: - a?: int \ No newline at end of file diff --git a/test/test_units/test_kclvm/test_tools/test_lint/test_checker/test_data/f.k b/test/test_units/test_kclvm/test_tools/test_lint/test_checker/test_data/f.k deleted file mode 100644 index ad344532c..000000000 --- a/test/test_units/test_kclvm/test_tools/test_lint/test_checker/test_data/f.k +++ /dev/null @@ -1,2 +0,0 @@ -schema UnionType: - b?: int \ No newline at end of file diff --git a/test/test_units/test_kclvm/test_tools/test_lint/test_checker/test_data/import.k b/test/test_units/test_kclvm/test_tools/test_lint/test_checker/test_data/import.k deleted file mode 100644 index 5a0cdf332..000000000 --- a/test/test_units/test_kclvm/test_tools/test_lint/test_checker/test_data/import.k +++ /dev/null @@ -1,32 +0,0 @@ -import abc # unable to import -import a -import a # reimport - -import math -import c # test unused import for mixin name -import d # test unused import for parent name -import e # test unused import for union type -import f # test unused import for union type - -schema Main(d.Parent): - mixin [c.TestOfMixin] - age?: int = 18 - person?: a.Person - list_union_type: [e.UnionType|int] - dict_union_type: {f.UnionType|int:float} - -import b # import position - -if a._a > 1: - _c = 1 -elif a._a == 1: - _c = 2 -else: - _c = 3 - -p = Main{ - age = a._a -} - - - diff --git a/test/test_units/test_kclvm/test_tools/test_lint/test_checker/test_data/misc.k b/test/test_units/test_kclvm/test_tools/test_lint/test_checker/test_data/misc.k deleted file mode 100644 index da988199a..000000000 --- a/test/test_units/test_kclvm/test_tools/test_lint/test_checker/test_data/misc.k +++ /dev/null @@ -1 +0,0 @@ -# line too long, line too long, line too long, line too long, line too long, line too long, line too long, line too long, \ No newline at end of file diff --git a/test/test_units/test_kclvm/test_tools/test_lint/test_exception/test_exceptions.py b/test/test_units/test_kclvm/test_tools/test_lint/test_exception/test_exceptions.py deleted file mode 100644 index 49a5fc262..000000000 --- a/test/test_units/test_kclvm/test_tools/test_lint/test_exception/test_exceptions.py +++ /dev/null @@ -1,109 +0,0 @@ -import pathlib -import unittest - -import kclvm.tools.lint.lint.KCLLint as KCLLint -import kclvm.tools.lint.lint.exceptions as exceptions - - -LINT_CONFIG_SUFFIX = ".kcllint" -_PATH_NAME = "test_data" -_FILE_NAME = "main.k" -_DIR_PATH = pathlib.Path(__file__).parent.joinpath(_PATH_NAME) -_TEST_FILE = _DIR_PATH.joinpath(_FILE_NAME) -_WRONG_FILE_NAME = "mian.k" -_WRONG_TEST_FILE = _DIR_PATH.joinpath(_WRONG_FILE_NAME) - - -TEST_CASE = { - "invalid_checker": { - "code": "", - "path": _TEST_FILE, - "config": { - "check_list": ["invalid_checker"], - "ignore": [], - "max_line_length": 200, - "output": ["stdout"], - } - }, - "invalid_reporter": { - "code": "", - "path": _TEST_FILE, - "config": { - "check_list": ["import"], - "ignore": [], - "max_line_length": 200, - "output": ["invalid_reporter"], - } - }, - "empty_reporter": { - "code": "", - "path": _TEST_FILE, - "config": { - "output": [], - } - }, - "without_output_path": { - "code": "", - "path": _TEST_FILE, - "config": { - "output": ["file"], - } - }, - "wrong_path": { - "path": _WRONG_TEST_FILE, - } -} - - -class KCLLintExceptionTest(unittest.TestCase): - def test_invalid_checker(self): - code = TEST_CASE["invalid_checker"]["code"] - config = TEST_CASE["invalid_checker"]["config"] - path = TEST_CASE["invalid_checker"]["path"] - try: - KCLLint.kcl_lint_code(path, k_code_list=[code], config=config) - assert False - except Exception as err: - assert isinstance(err, exceptions.InvalidCheckerError) - - def test_invalid_reporter(self): - code = TEST_CASE["invalid_reporter"]["code"] - config = TEST_CASE["invalid_reporter"]["config"] - path = TEST_CASE["invalid_reporter"]["path"] - try: - KCLLint.kcl_lint_code(path, k_code_list=[code], config=config) - assert False - except Exception as err: - assert isinstance(err, exceptions.InvalidReporterError) - - def test_empty_reporter(self): - code = TEST_CASE["empty_reporter"]["code"] - config = TEST_CASE["empty_reporter"]["config"] - path = TEST_CASE["empty_reporter"]["path"] - try: - KCLLint.kcl_lint_code(path, k_code_list=[code], config=config) - assert False - except Exception as err: - assert isinstance(err, exceptions.EmptyReporterError) - - def test_without_output_path(self): - code = TEST_CASE["without_output_path"]["code"] - config = TEST_CASE["without_output_path"]["config"] - path = TEST_CASE["without_output_path"]["path"] - try: - KCLLint.kcl_lint_code(path, k_code_list=[code], config=config) - assert False - except Exception as err: - assert isinstance(err, AssertionError) - self.assertEqual(err.args, ("Without ouput file path",)) - - def test_wrong_path(self): - path = TEST_CASE["wrong_path"]["path"] - try: - KCLLint.kcl_lint(path) - assert False - except Exception as err: - assert isinstance(err, FileNotFoundError) - -if __name__ == "__main__": - unittest.main(verbosity=2) diff --git a/test/test_units/test_kclvm/test_tools/test_lint/test_lint_integration/test_data/.kcllint b/test/test_units/test_kclvm/test_tools/test_lint/test_lint_integration/test_data/.kcllint deleted file mode 100644 index 003edc9a8..000000000 --- a/test/test_units/test_kclvm/test_tools/test_lint/test_lint_integration/test_data/.kcllint +++ /dev/null @@ -1 +0,0 @@ -max_line_length: 120 diff --git a/test/test_units/test_kclvm/test_tools/test_lint/test_lint_integration/test_data/failed.k b/test/test_units/test_kclvm/test_tools/test_lint/test_lint_integration/test_data/failed.k deleted file mode 100644 index a62a04da4..000000000 --- a/test/test_units/test_kclvm/test_tools/test_lint/test_lint_integration/test_data/failed.k +++ /dev/null @@ -1 +0,0 @@ -a ==== 1 # Parse failed \ No newline at end of file diff --git a/test/test_units/test_kclvm/test_tools/test_lint/test_lint_integration/test_data/main.k b/test/test_units/test_kclvm/test_tools/test_lint/test_lint_integration/test_data/main.k deleted file mode 100644 index 6df733dce..000000000 --- a/test/test_units/test_kclvm/test_tools/test_lint/test_lint_integration/test_data/main.k +++ /dev/null @@ -1,2 +0,0 @@ -import empty_file -$for = 1 \ No newline at end of file diff --git a/test/test_units/test_kclvm/test_tools/test_lint/test_lint_integration/test_lint_integration.py b/test/test_units/test_kclvm/test_tools/test_lint/test_lint_integration/test_lint_integration.py deleted file mode 100644 index 4d403f50a..000000000 --- a/test/test_units/test_kclvm/test_tools/test_lint/test_lint_integration/test_lint_integration.py +++ /dev/null @@ -1,126 +0,0 @@ -import pathlib -import unittest - -import kclvm.tools.lint.lint.KCLLint as KCLLint -from kclvm.tools.lint.checkers.imports import ImportsChecker -from kclvm.tools.lint.checkers.misc import MiscChecker -from kclvm.tools.lint.checkers.basic import BasicChecker -from kclvm.tools.lint.reporters.stdout_reporter import STDOUTReporter -from kclvm.tools.lint.message.message import Message - -LINT_CONFIG_SUFFIX = ".kcllint" -_FILE_INPUT_SUFFIX = ".k" -_PATH_NAME = "test_data" -_DIR_PATH = pathlib.Path(__file__).parent.joinpath(_PATH_NAME) - - -class KCLLintIntegrationTest(unittest.TestCase): - msgs = [ - Message( - "E0999", - str(_DIR_PATH.joinpath("failed.k")), - "Parse failed:InvalidSyntax.", - "a ==== 1 # Parse failed", - (1, 5), - ["InvalidSyntax"] - ), - Message( - "W0411", - str(_DIR_PATH.joinpath("main.k")), - "empty_file imported but unused.", - "import empty_file", - (1, 1), - ["empty_file"] - ), - ] - lint_code_test_case = [ - { - "code": """a ==== 1 # Parse failed -""", - "file": str(_DIR_PATH.joinpath("failed.k")), - "msgs": [ - Message( - "E0999", - str(_DIR_PATH.joinpath("failed.k")), - "Parse failed:InvalidSyntax.", - "a ==== 1 # Parse failed", - (1, 5), - ["InvalidSyntax"] - ) - ], - }, - { - "code": """import empty_file -""", - "file": str(_DIR_PATH.joinpath("main.k")), - "msgs": [ - Message( - "W0411", - str(_DIR_PATH.joinpath("main.k")), - "empty_file imported but unused.", - "import empty_file", - (1, 1), - ["empty_file"] - ) - ], - }, - ] - - def setUp(self) -> None: - self.linter = KCLLint.KCLLinter(_DIR_PATH) - self.linter.run() - - def test_load_config(self): - config = { - "check_list": ["import", "misc", "basic"], - "ignore": [], - "max_line_length": 120, # default 200, overwrite in .kcllint - "output": ["stdout"], - "output_path":None, - "module_naming_style": "ANY", - "package_naming_style": "ANY", - "schema_naming_style": "PascalCase", - "mixin_naming_style": "PascalCase", - "argument_naming_style": "camelCase", - "variable_naming_style": "ANY", - "schema_attribute_naming_style": "ANY", - "module_rgx": None, - "package_rgx": None, - "schema_rgx": None, - "mixin_rgx": None, - "argument_rgx": None, - "variable_rgx": None, - "schema_attribute_rgx": None, - "bad_names": ["foo", "bar", "baz", "toto", "tata", "tutu", "I", "l", "O"], - } - for k, v in config.items(): - self.assertEqual(getattr(self.linter.config, k), v) - - def test_register_checkers(self): - checker_list = [ImportsChecker(self.linter), MiscChecker(self.linter), BasicChecker(self.linter)] - self.assertListEqual(self.linter.checkers, checker_list) - - def test_register_reporter(self): - reporter_list = [STDOUTReporter(self.linter)] - self.assertListEqual(self.linter.reporters, reporter_list) - - def test_ignore_msg(self): - self.linter.config.ignore = ["E0999", "W0411"] - self.linter.run() - self.assertEqual(len(self.linter.msgs), 0) - - def test_kcl_lint_fun(self): - msgs = KCLLint.kcl_lint(_DIR_PATH) - self.assertListEqual(msgs, self.msgs) - - def test_kcl_lint_code_fun(self): - for case in self.lint_code_test_case: - code = case["code"] - msgs = KCLLint.kcl_lint_code(case["file"], k_code_list=[code]) - for i, m in enumerate(msgs): - expect = case["msgs"][i] - self.assertEqual(expect, m, f"Expected:\n{expect}\narguments:{expect.arguments}\nActual:\n{m}\narguments:{m.arguments}") - - -if __name__ == "__main__": - unittest.main(verbosity=2) diff --git a/test/test_units/test_kclvm/test_tools/test_lint/test_reporter/test_data/file_reporter.golden b/test/test_units/test_kclvm/test_tools/test_lint/test_reporter/test_data/file_reporter.golden deleted file mode 100644 index eb52f3124..000000000 --- a/test/test_units/test_kclvm/test_tools/test_lint/test_reporter/test_data/file_reporter.golden +++ /dev/null @@ -1,7 +0,0 @@ -:1:1: E0401 Unable to import abc. -import abc as abc -^ - -Check total 1 files: -1 E0401: Unable to import -KCL Lint: 1 problems diff --git a/test/test_units/test_kclvm/test_tools/test_lint/test_reporter/test_data/reporter.k b/test/test_units/test_kclvm/test_tools/test_lint/test_reporter/test_data/reporter.k deleted file mode 100644 index 479f37a3a..000000000 --- a/test/test_units/test_kclvm/test_tools/test_lint/test_reporter/test_data/reporter.k +++ /dev/null @@ -1,3 +0,0 @@ -import abc as abc # This file is only used to create linter - - diff --git a/test/test_units/test_kclvm/test_tools/test_lint/test_reporter/test_data/sarif_reporter.golden b/test/test_units/test_kclvm/test_tools/test_lint/test_reporter/test_data/sarif_reporter.golden deleted file mode 100644 index c51270eb7..000000000 --- a/test/test_units/test_kclvm/test_tools/test_lint/test_reporter/test_data/sarif_reporter.golden +++ /dev/null @@ -1,52 +0,0 @@ -{ - "runs": [ - { - "results": [ - { - "level": "error", - "locations": [ - { - "physicalLocation": { - "artifactLocation": { - "uri": "kclvm/test/test_units/test_kclvm/test_tools/test_lint/test_reporter/test_data/reporter.k" - }, - "region": { - "startColumn": 1, - "startLine": 1 - } - } - } - ], - "message": { - "arguments": [ - "abc" - ], - "id": "default" - }, - "ruleId": "E0401" - } - ], - "tool": { - "driver": { - "informationUri": "https://kusion-docs.com/docs/reference/cli/kcl/lint", - "name": "kcl-lint", - "rules": [ - { - "id": "E0401", - "messageStrings": { - "default": { - "text": "Unable to import '{0}'." - }, - "shortStrings": { - "text": "Unable to import" - } - } - } - ], - "version": "0.0.1" - } - } - } - ], - "version": "2.1.0" -} diff --git a/test/test_units/test_kclvm/test_tools/test_lint/test_reporter/test_reporter.py b/test/test_units/test_kclvm/test_tools/test_lint/test_reporter/test_reporter.py deleted file mode 100644 index c409e59b3..000000000 --- a/test/test_units/test_kclvm/test_tools/test_lint/test_reporter/test_reporter.py +++ /dev/null @@ -1,179 +0,0 @@ -import unittest -import pathlib -import sys -import os - -import kclvm.tools.lint.lint.KCLLint as KCLLint -from kclvm.tools.lint.reporters.stdout_reporter import color -from kclvm.tools.lint.message.message import Message - -_FILE_INPUT_SUFFIX = ".k" -_FILE_OUTPUT_SUFFIX = ".golden" -_FILE_TEST_OUTPUT_SUFFIX = ".test" -_PATH_NAME = "test_data" -_DIR_PATH = pathlib.Path(__file__).parent.joinpath(_PATH_NAME) - -_TEST_CASE_NAMES = [ - "stdout", - "file" -] - -_TEST_CASE = { - "stdout": { - "msg": [ - Message("E0401", - str(_DIR_PATH.joinpath("reporter.k")), - "Unable to import abc.", - "import abc as abc", - (1, 1), - ["abc"]), - ], - "msgs_map": {"E0401": 1}, - "expected": { - "msg_with_color": color(str(_DIR_PATH.joinpath("reporter.k")), "FILE_NAME") - + f''':{color("1", "LINE_COLUMN")}:{color("1", "LINE_COLUMN")}: {color("E0401", "ID")} Unable to import abc. -import abc as abc -{color("^", "MARK")} - -Check total {color("1", "NUMBER")} files: -{color("1", "NUMBER")} {color("E0401", "ID")}: Unable to import -KCL Lint: {color("1", "NUMBER")} problems -''', - "msg_without_color": str(_DIR_PATH.joinpath("reporter.k")) - + f''':1:1: E0401 Unable to import abc. -import abc as abc -^ - -Check total 1 files: -1 E0401: Unable to import -KCL Lint: 1 problems -'''}}, - "file": - {"msg": [ - Message("E0401", - str(_DIR_PATH.joinpath("reporter.k")), - "Unable to import abc.", - "import abc as abc", - (1, 1), - ["abc"]), - ], - "msgs_map": {"E0401": 1}, - "expected": "" - }, - "sarif": - {"msg": [ - Message("E0401", - str(_DIR_PATH.joinpath("reporter.k")), - "Unable to import abc.", - "import abc as abc", - (1, 1), - ["abc"]), - ], - "msgs_map": {"E0401": 1}, - "expected": "" - }, -} -DEFAULT_CONFIG = { - "check_list": ["import", "misc"], - "ignore": [], - "max_line_length": 200, - "output": ["stdout"], - "output_path": None -} -MSGS = { - "E0401": ( - "Unable to import %s.", - "Unable to import", - "Unable to import '{0}'." - ) -} - - -class KCLReporterBaseTest(unittest.TestCase): - def setUp(self): - self.maxDiff = None - - def read_data(self, data_name: str): - """Read test data""" - input_filename = data_name + _FILE_INPUT_SUFFIX - input_file = _DIR_PATH / input_filename - return input_file - - def build_reporter(self, case): - input_file = self.read_data("reporter") - linter = KCLLint.KCLLinter(input_file, config=DEFAULT_CONFIG) - linter.msgs = _TEST_CASE[case]["msg"] - linter.msgs_map = _TEST_CASE[case]["msgs_map"] - if case == "file" or case == "sarif": - linter.config.output_path = str(_DIR_PATH.joinpath(case + "_reporter" + _FILE_TEST_OUTPUT_SUFFIX)) - reporter = KCLLint.ReporterFactory.get_reporter(case, linter) - linter.MSGS = MSGS - return reporter - - -class KCLReporterTest(KCLReporterBaseTest): - def test_stdout_reporter(self) -> None: - class _redirect: - content = "" - is_atty = False - - def write(self, in_str): - self.content += in_str - - def flush(self): - self.content = "" - - def isatty(self): - return self.is_atty - - def getvalue(self): - return self.content - - r = _redirect() - sys.stdout = r - reporter = self.build_reporter("stdout") - reporter.print_msg(reporter.linter.msgs, r) - self.assertEqual(r.content, _TEST_CASE["stdout"]["expected"]["msg_without_color"]) - - """ - Print msg with color, remove it temporarily. - r.is_atty = True - r.content = "" - reporter.print_msg(reporter.linter.msgs, r) - self.assertEqual(r.content, _TEST_CASE["stdout"]["expected"]["msg_with_color"]) - """ - - def test_file_reporter(self) -> None: - reporter = self.build_reporter("file") - reporter.display() - test_output = str(_DIR_PATH.joinpath("file_reporter" + _FILE_TEST_OUTPUT_SUFFIX)) - golden_output = str(_DIR_PATH.joinpath("file_reporter" + _FILE_OUTPUT_SUFFIX)) - with open(golden_output) as f: - golden_output_list = f.readlines() - golden_output_list[0] = str(_DIR_PATH.joinpath("reporter" + _FILE_INPUT_SUFFIX)) + golden_output_list[0] - with open(test_output) as f: - test_output_list = f.readlines() - test_output_list[0] = str( - _DIR_PATH.joinpath("reporter" + _FILE_INPUT_SUFFIX)) + ":1:1: E0401 Unable to import abc.\n" - self.assertListEqual(test_output_list, golden_output_list) - os.remove(test_output) - - def test_sarif_reporter(self) -> None: - reporter = self.build_reporter("sarif") - reporter.display() - test_output = str(_DIR_PATH.joinpath("sarif_reporter" + _FILE_TEST_OUTPUT_SUFFIX)) - golden_output = str(_DIR_PATH.joinpath("sarif_reporter" + _FILE_OUTPUT_SUFFIX)) - with open(golden_output) as f: - golden_output_list = f.readlines() - golden_output_list[10] = " \"uri\": \"" + str( - _DIR_PATH.joinpath("reporter" + _FILE_INPUT_SUFFIX)) + "\"" - with open(test_output) as f: - test_output_list = f.readlines() - test_output_list[10] = " \"uri\": \"" + str( - _DIR_PATH.joinpath("reporter" + _FILE_INPUT_SUFFIX)) + "\"" - self.assertListEqual(test_output_list, golden_output_list) - os.remove(test_output) - - -if __name__ == "__main__": - unittest.main(verbosity=2) diff --git a/test/test_units/test_kclvm/test_tools/test_list_attr/schema_testdata/complex.k b/test/test_units/test_kclvm/test_tools/test_list_attr/schema_testdata/complex.k deleted file mode 100644 index c720d1c8b..000000000 --- a/test/test_units/test_kclvm/test_tools/test_list_attr/schema_testdata/complex.k +++ /dev/null @@ -1,19 +0,0 @@ -@info(version="v1") -schema User: - @info(message="name") - name: str = "default_name" - age: int = 1 - homeTown?: HomeTown - -schema HomeTown: - province: str - city: Custom - -schema Custom: - left: int - right: int - -schema Color: - color: "Yellow" | "Blue" | "Green" - listAttr: [int] - dictAttr: {str:} diff --git a/test/test_units/test_kclvm/test_tools/test_list_attr/schema_testdata/complex.k.json b/test/test_units/test_kclvm/test_tools/test_list_attr/schema_testdata/complex.k.json deleted file mode 100644 index 5463416fa..000000000 --- a/test/test_units/test_kclvm/test_tools/test_list_attr/schema_testdata/complex.k.json +++ /dev/null @@ -1,166 +0,0 @@ -[ - { - "type": "schema", - "schemaName": "User", - "properties": { - "name": { - "type": "str", - "default": "default_name", - "line": 1, - "decorators": [ - { - "name": "info", - "keywords": { - "message": "name" - } - } - ] - }, - "homeTown": { - "type": "schema", - "schemaName": "HomeTown", - "properties": { - "province": { - "type": "str", - "line": 1 - }, - "city": { - "type": "schema", - "schemaName": "Custom", - "properties": { - "left": { - "type": "int", - "line": 1 - }, - "right": { - "type": "int", - "line": 2 - } - }, - "required": [ - "left", - "right" - ], - "line": 2 - } - }, - "required": [ - "city", - "province" - ], - "line": 3 - }, - "age": { - "type": "int", - "default": "1", - "line": 2 - } - }, - "required": [ - "age", - "name" - ], - "decorators": [ - { - "name": "info", - "keywords": { - "version": "v1" - } - } - ] - }, - { - "type": "schema", - "schemaName": "HomeTown", - "properties": { - "province": { - "type": "str", - "line": 1 - }, - "city": { - "type": "schema", - "schemaName": "Custom", - "properties": { - "right": { - "type": "int", - "line": 2 - }, - "left": { - "type": "int", - "line": 1 - } - }, - "required": [ - "left", - "right" - ], - "line": 2 - } - }, - "required": [ - "city", - "province" - ] - }, - { - "type": "schema", - "schemaName": "Custom", - "properties": { - "left": { - "type": "int", - "line": 1 - }, - "right": { - "type": "int", - "line": 2 - } - }, - "required": [ - "left", - "right" - ] - }, - { - "type": "schema", - "schemaName": "Color", - "properties": { - "dictAttr": { - "type": "dict", - "key": { - "type": "str" - }, - "item": { - "type": "any" - }, - "line": 3 - }, - "listAttr": { - "type": "list", - "item": { - "type": "int" - }, - "line": 2 - }, - "color": { - "type": "union", - "unionTypes": [ - { - "type": "str(Yellow)" - }, - { - "type": "str(Blue)" - }, - { - "type": "str(Green)" - } - ], - "line": 1 - } - }, - "required": [ - "color", - "dictAttr", - "listAttr" - ] - } -] diff --git a/test/test_units/test_kclvm/test_tools/test_list_attr/schema_testdata/empty.k.json b/test/test_units/test_kclvm/test_tools/test_list_attr/schema_testdata/empty.k.json deleted file mode 100644 index 0637a088a..000000000 --- a/test/test_units/test_kclvm/test_tools/test_list_attr/schema_testdata/empty.k.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/test/test_units/test_kclvm/test_tools/test_list_attr/schema_testdata/simple.k b/test/test_units/test_kclvm/test_tools/test_list_attr/schema_testdata/simple.k deleted file mode 100644 index e90c53e93..000000000 --- a/test/test_units/test_kclvm/test_tools/test_list_attr/schema_testdata/simple.k +++ /dev/null @@ -1,6 +0,0 @@ -import units - -schema Data: - id?: int - name: str - cpu: units.NumberMultiplier diff --git a/test/test_units/test_kclvm/test_tools/test_list_attr/schema_testdata/simple.k.json b/test/test_units/test_kclvm/test_tools/test_list_attr/schema_testdata/simple.k.json deleted file mode 100644 index 50fb43ddb..000000000 --- a/test/test_units/test_kclvm/test_tools/test_list_attr/schema_testdata/simple.k.json +++ /dev/null @@ -1,24 +0,0 @@ -[ - { - "type": "schema", - "schemaName": "Data", - "properties": { - "name": { - "type": "str", - "line": 2 - }, - "id": { - "type": "int", - "line": 1 - }, - "cpu": { - "line": 3, - "type": "number_multiplier" - } - }, - "required": [ - "cpu", - "name" - ] - } -] \ No newline at end of file diff --git a/test/test_units/test_kclvm/test_tools/test_list_attr/test_data/import_file.k b/test/test_units/test_kclvm/test_tools/test_list_attr/test_data/import_file.k deleted file mode 100644 index 6a5ad3a1f..000000000 --- a/test/test_units/test_kclvm/test_tools/test_list_attr/test_data/import_file.k +++ /dev/null @@ -1,4 +0,0 @@ -import importfile -schema Person(Persona): - name: str - age: int diff --git a/test/test_units/test_kclvm/test_tools/test_list_attr/test_data/importfile/nested_import_file.k b/test/test_units/test_kclvm/test_tools/test_list_attr/test_data/importfile/nested_import_file.k deleted file mode 100644 index f887109a4..000000000 --- a/test/test_units/test_kclvm/test_tools/test_list_attr/test_data/importfile/nested_import_file.k +++ /dev/null @@ -1,3 +0,0 @@ -schema Persona: - name: str - age: int \ No newline at end of file diff --git a/test/test_units/test_kclvm/test_tools/test_list_attr/test_data/list_attr.full_schema b/test/test_units/test_kclvm/test_tools/test_list_attr/test_data/list_attr.full_schema deleted file mode 100644 index 569fe8c34..000000000 --- a/test/test_units/test_kclvm/test_tools/test_list_attr/test_data/list_attr.full_schema +++ /dev/null @@ -1,3 +0,0 @@ -FullName, attr:[firstName, lastName], -Person1, attr:[name, card, _mybkLabels, commands], parent:Person, attr:[name, age], parent:Persona, attr:[name, age], -Person2, attr:[card], parent:Person1, attr:[name, card, _mybkLabels, commands], parent:Person, attr:[name, age], parent:Persona, attr:[name, age], \ No newline at end of file diff --git a/test/test_units/test_kclvm/test_tools/test_list_attr/test_data/list_attr.golden b/test/test_units/test_kclvm/test_tools/test_list_attr/test_data/list_attr.golden deleted file mode 100644 index d0dda0509..000000000 --- a/test/test_units/test_kclvm/test_tools/test_list_attr/test_data/list_attr.golden +++ /dev/null @@ -1,44 +0,0 @@ ------------- schema list ------------ -Here are schemas defined in list_attr.k: -- FullName -- Person1 -- Person2 -Here are schemas imported to list_attr.k: -imported from import_file.k -- Person -imported from nested_import_file.k -- Persona ------------- schema structures ------------ -schema FullName: -name type default is_final is_optional -firstName str Required -lastName str Required - -schema Person1: -name type default is_final is_optional -name FullName FullName{...} Required -card str "abc" Required -_mybkLabels {str:str} ... -commands [str] ... Required -attrs inherited from Person -name str Required -age int Required -attrs inherited from Persona -name str Required -age int Required - -schema Person2: -name type default is_final is_optional -card str Required -attrs inherited from Person1 -name FullName FullName{...} Required -card str "abc" Required -_mybkLabels {str:str} ... -commands [str] ... Required -attrs inherited from Person -name str Required -age int Required -attrs inherited from Persona -name str Required -age int Required - diff --git a/test/test_units/test_kclvm/test_tools/test_list_attr/test_data/list_attr.k b/test/test_units/test_kclvm/test_tools/test_list_attr/test_data/list_attr.k deleted file mode 100644 index d93954389..000000000 --- a/test/test_units/test_kclvm/test_tools/test_list_attr/test_data/list_attr.k +++ /dev/null @@ -1,25 +0,0 @@ -import import_file -# test for builtin -import math -# test for plugin -import kcl_plugin.app_context as ctx - -schema FullName: - firstName: str - lastName: str - -schema Person1(Person): - name: FullName = FullName{ - firstName = "hello" - lastName = "world" - } - card: str = "abc" - _mybkLabels?: {str:str} = { - if _workspace: "app.stack.io/workspace": _workspace.lower() - "app.kubernetes.io/name": _appName - "app.kubernetes.io/instance": _appName - } if _globalTenantName == "CLOUDCORE" else Undefined - commands: [str] = ["a", if True : "b"] - -schema Person2(Person1): - card: str diff --git a/test/test_units/test_kclvm/test_tools/test_list_attr/test_listattr.py b/test/test_units/test_kclvm/test_tools/test_list_attr/test_listattr.py deleted file mode 100644 index 8b6785c24..000000000 --- a/test/test_units/test_kclvm/test_tools/test_list_attr/test_listattr.py +++ /dev/null @@ -1,85 +0,0 @@ -import os -import sys -import unittest -import pathlib -import subprocess -from typing import Tuple -import kclvm.kcl.ast as ast -from kclvm.compiler.parser import ParseFile -from kclvm.tools.list_attribute.utils import ListAttributePrinter - -_FILE_INPUT_SUFFIX = ".k" -_FILE_OUTPUT_SUFFIX = ".golden" -_FILE_FULLSCHEMA_SUFFIX = ".full_schema" -_PATH_NAME = "test_data" -_DIR_PATH = pathlib.Path(__file__).parent.joinpath(_PATH_NAME) -_TEST_CASE_NAMES = [ - "list_attr" -] - - -class KCLListAttrBaseTest(unittest.TestCase): - def setUp(self): - self.maxDiff = None - - def read_data(self, data_name: str): - """Read test data""" - input_filename = data_name + _FILE_INPUT_SUFFIX - output_filename = data_name + _FILE_OUTPUT_SUFFIX - full_schema_filename = data_name + _FILE_FULLSCHEMA_SUFFIX - input_file = _DIR_PATH / input_filename - data_input = (_DIR_PATH / input_filename).read_text() - data_output = (_DIR_PATH / output_filename).read_text() - data_full_schema = (_DIR_PATH / full_schema_filename).read_text() - return input_file, data_input, data_output, data_full_schema - - def assert_full_schema_equal( - self, - data_name: str - ): - input_file, input_str, output_str, full_schema_str = self.read_data(data_name) - printer = ListAttributePrinter(str(input_file)) - printer.build_full_schema_list() - if not printer.full_schema_list: - return - full_schema_list = printer.full_schema_list - full_schema = "" - for s in full_schema_list: - full_schema += str(s) + "\n" - full_schema = full_schema[:-1] - self.assertEqual(full_schema, full_schema_str) - - def assert_list_attr_equal( - self, - data_name: str - ): - input_file, input_str, output_str, full_schema_str = self.read_data(data_name) - buffer = Redirect() - current = sys.stdout - sys.stdout = buffer - ListAttributePrinter(str(input_file)).print() - sys.stdout = current - self.assertEqual(buffer.content, output_str) - - -# rewrite sys.stdout.write() to get content of print() -class Redirect: - def __init__(self): - self.content = "" - - def write(self, str): - self.content += str - - -class KCLListAttrTest(KCLListAttrBaseTest): - def test_full_schema(self) -> None: - for case in _TEST_CASE_NAMES: - self.assert_full_schema_equal(case) - - def test_list_attr_schema(self) -> None: - for case in _TEST_CASE_NAMES: - self.assert_list_attr_equal(case) - - -if __name__ == "__main__": - unittest.main(verbosity=2) diff --git a/test/test_units/test_kclvm/test_tools/test_list_attr/test_schema.py b/test/test_units/test_kclvm/test_tools/test_list_attr/test_schema.py deleted file mode 100644 index a94889c1a..000000000 --- a/test/test_units/test_kclvm/test_tools/test_list_attr/test_schema.py +++ /dev/null @@ -1,48 +0,0 @@ -import json -import unittest -import pathlib - -import kclvm.kcl.ast as ast -import kclvm.api.object as objpkg -import kclvm.tools.list_attribute.schema as schema -import kclvm.internal.gpyrpc.gpyrpc_pb2 as pb2 - - -import google.protobuf.json_format as json_format - - -class KCLListAttrSchemaTest(unittest.TestCase): - def test_get_schema_type_from_code(self): - self.maxDiff = None - testdata_path = pathlib.Path(__file__).parent.joinpath("schema_testdata") - k_files = list(sorted(testdata_path.glob("*.k"))) - json_files = list(sorted(testdata_path.glob("*.k.json"))) - for k_file, json_file in zip(k_files, json_files): - k_code = k_file.read_text() - type_list = schema.get_schema_type_from_code("", code=k_code) - type_list = [json_format.MessageToDict(t) for t in type_list] - json_str = json_file.read_text() - expected_data = json.loads(json_str) - self.assertEqual(type_list, expected_data) - - def test_get_schema_type_from_code_with_schema_name_para(self): - testdata_path = pathlib.Path(__file__).parent.joinpath("schema_testdata").joinpath("complex.k") - k_code = testdata_path.read_text() - schema_names = ["User", "HomeTown", "Custom", "Color"] - for name in schema_names: - type_list = schema.get_schema_type_from_code("", code=k_code, schema_name=name) - self.assertEqual(len(type_list), 1) - err_name = "ErrSchema" - type_list = schema.get_schema_type_from_code("", code=k_code, schema_name=err_name) - self.assertEqual(len(type_list), 0) - - def test_get_schema_type_from_code_invalid(self): - with self.assertRaises(Exception): - schema.get_schema_type_from_code(None, None) - - def test_kcl_type_obj_to_pb_kcl_type(self): - self.assertEqual(schema.kcl_type_obj_to_pb_kcl_type(None), None) - - -if __name__ == "__main__": - unittest.main(verbosity=2) diff --git a/test/test_units/test_kclvm/test_tools/test_overrides/file_test_data/pkg/internal_pkg/data.k b/test/test_units/test_kclvm/test_tools/test_overrides/file_test_data/pkg/internal_pkg/data.k deleted file mode 100644 index 7a530baa9..000000000 --- a/test/test_units/test_kclvm/test_tools/test_overrides/file_test_data/pkg/internal_pkg/data.k +++ /dev/null @@ -1,2 +0,0 @@ -schema Data: - id?: int diff --git a/test/test_units/test_kclvm/test_tools/test_overrides/file_test_data/pkg/person.k b/test/test_units/test_kclvm/test_tools/test_overrides/file_test_data/pkg/person.k deleted file mode 100644 index 8e2889433..000000000 --- a/test/test_units/test_kclvm/test_tools/test_overrides/file_test_data/pkg/person.k +++ /dev/null @@ -1,6 +0,0 @@ -import pkg.internal_pkg - -schema Person: - name: str = "kcl" - age: int = 1 - data?: internal_pkg.Data diff --git a/test/test_units/test_kclvm/test_tools/test_overrides/file_test_data/test.k b/test/test_units/test_kclvm/test_tools/test_overrides/file_test_data/test.k deleted file mode 100644 index 57613032a..000000000 --- a/test/test_units/test_kclvm/test_tools/test_overrides/file_test_data/test.k +++ /dev/null @@ -1,20 +0,0 @@ -schema Data: - id?: int = 0 - value?: str = "value" - -schema Config: - image: str - data?: Data - -if True: - configOther = Config { - image = "image/other:v1" - } - -config = Config { - image = "image/image:v1" - data = { - id = 1 - value = "override_value" - } -} diff --git a/test/test_units/test_kclvm/test_tools/test_overrides/file_test_data/test_auto_fix.k b/test/test_units/test_kclvm/test_tools/test_overrides/file_test_data/test_auto_fix.k deleted file mode 100644 index 9459f9ac8..000000000 --- a/test/test_units/test_kclvm/test_tools/test_overrides/file_test_data/test_auto_fix.k +++ /dev/null @@ -1,20 +0,0 @@ -schema Data: - id?: int = 0 - value?: str = "value" - -schema Config: - image: str - data?: Data - -if True: - configOther = Config { - image = "image/other:v1" - } - -config = Config { - image = "image/image:v1" - data = { - id = 1 - value = str(1) - } -} diff --git a/test/test_units/test_kclvm/test_tools/test_overrides/file_test_data/test_auto_import_schema.k b/test/test_units/test_kclvm/test_tools/test_overrides/file_test_data/test_auto_import_schema.k deleted file mode 100644 index 4da128f62..000000000 --- a/test/test_units/test_kclvm/test_tools/test_overrides/file_test_data/test_auto_import_schema.k +++ /dev/null @@ -1,6 +0,0 @@ -import pkg.internal_pkg -import pkg - -x0 = pkg.Person { - data = internal_pkg.Data {id = 1} -} diff --git a/test/test_units/test_kclvm/test_tools/test_overrides/file_test_data/test_import_paths.k b/test/test_units/test_kclvm/test_tools/test_overrides/file_test_data/test_import_paths.k deleted file mode 100644 index f2eb06591..000000000 --- a/test/test_units/test_kclvm/test_tools/test_overrides/file_test_data/test_import_paths.k +++ /dev/null @@ -1,10 +0,0 @@ -import pkg.pkg -import pkg - -schema Data: - id?: int = 0 - value?: str = "value" - -data = Data { - value = "override_value" -} diff --git a/test/test_units/test_kclvm/test_tools/test_overrides/test_data/config.input b/test/test_units/test_kclvm/test_tools/test_overrides/test_data/config.input deleted file mode 100644 index fcaa8ba77..000000000 --- a/test/test_units/test_kclvm/test_tools/test_overrides/test_data/config.input +++ /dev/null @@ -1,59 +0,0 @@ -schema Main: - name?: str - env?: [{str:}] - -schema Probe: - initialDelaySeconds?: int - timeoutSeconds?: int - periodSeconds?: int = 10 - successThreshold?: int - failureThreshold?: int - -schema AppConfiguration: - appName: str - image: str - overQuota: bool = False - resource: {str:} - mainContainer?: Main - labels: {str:} - probe: Probe - -appConfiguration = AppConfiguration { - appName: "kusion" - image: "kusion/kusion:v0.3.0" - resource: { - cpu: "4" - disk: "50Gi" - memory: "12Gi" - } - labels: { - key: { - key: "value" - } - } - mainContainer: Main { - name: "kusion" - } - overQuota = True - overQuota = True - probe: Probe {} -} - -appConfigurationUnification: AppConfiguration { - appName: "kusion" - image: "kusion/kusion:v0.3.0" - resource: { - cpu: "4" - disk: "50Gi" - memory: "12Gi" - } - labels: { - key: { - key: "value" - } - } - mainContainer: Main { - name: "kusion" - } - overQuota: True -} diff --git a/test/test_units/test_kclvm/test_tools/test_overrides/test_data/config.output b/test/test_units/test_kclvm/test_tools/test_overrides/test_data/config.output deleted file mode 100644 index 562aca887..000000000 --- a/test/test_units/test_kclvm/test_tools/test_overrides/test_data/config.output +++ /dev/null @@ -1,57 +0,0 @@ -schema Main: - name?: str - env?: [{str:}] - -schema Probe: - initialDelaySeconds?: int - timeoutSeconds?: int - periodSeconds?: int = 10 - successThreshold?: int - failureThreshold?: int - -schema AppConfiguration: - appName: str - image: str - overQuota: bool = False - resource: {str:} - mainContainer?: Main - labels: {str:} - probe: Probe - -appConfiguration = AppConfiguration { - appName: "kusion" - image: "kusion/kusion:v0.3.1" - resource: { - cpu: "4" - disk: "50Gi" - memory: "12Gi" - } - labels: { - key: { - key: "override_value" - } - } - mainContainer: Main { - name: "kusion_override" - } - overQuota = False - overQuota = False - probe: { - periodSeconds = 20 - } -} - -appConfigurationUnification: AppConfiguration { - appName: "kusion" - image: "kusion/kusion:v0.3.1" - labels: { - key: { - key: "override_value" - } - } - mainContainer: Main { - name: "kusion_override" - } - overQuota: False -} - diff --git a/test/test_units/test_kclvm/test_tools/test_overrides/test_overrides.py b/test/test_units/test_kclvm/test_tools/test_overrides/test_overrides.py deleted file mode 100644 index f599a3ad1..000000000 --- a/test/test_units/test_kclvm/test_tools/test_overrides/test_overrides.py +++ /dev/null @@ -1,161 +0,0 @@ -#! /usr/bin/env python3 - -import io -import os -import unittest -import pathlib - -from typing import Tuple, List, Union - -import kclvm.kcl.ast as ast -import kclvm.kcl.error as kcl_error -from kclvm.compiler.parser import ParseFile, LoadProgram - - -FILE_INPUT_SUFFIX = ".input" -FILE_OUTPUT_SUFFIX = ".output" -PATH_NAME = "test_data" -TEST_DIR_PATH = pathlib.Path(__file__).parent.joinpath(PATH_NAME) -CMD_OVERRIDES = [ - ast.CmdOverrideSpec( - field_path="appConfiguration.image", - field_value="kusion/kusion:v0.3.1", - ), - ast.CmdOverrideSpec( - field_path="appConfiguration.mainContainer.name", - field_value="kusion_override", - ), - ast.CmdOverrideSpec( - field_path="appConfiguration.labels.key.key", - field_value="override_value", - ), - ast.CmdOverrideSpec( - field_path="appConfiguration.overQuota", - field_value="False", - ), - ast.CmdOverrideSpec( - field_path="appConfiguration.probe", - field_value="{periodSeconds=20}", - ), - ast.CmdOverrideSpec( - field_path="appConfigurationUnification.image", - field_value="kusion/kusion:v0.3.1", - ), - ast.CmdOverrideSpec( - field_path="appConfigurationUnification.mainContainer.name", - field_value="kusion_override", - ), - ast.CmdOverrideSpec( - field_path="appConfigurationUnification.labels.key.key", - field_value="override_value", - ), - ast.CmdOverrideSpec( - field_path="appConfigurationUnification.overQuota", - field_value="False", - ), - ast.CmdOverrideSpec( - field_path="appConfigurationUnification.resource", - action=ast.OverrideAction.DELETE, - ), -] - - -def _read_override_test_cases_from_dir( - dir: Union[pathlib.Path, str] -) -> List[Tuple[str, str, str]]: - if not dir: - return [] - inputs = list(sorted(pathlib.Path(dir).glob("*" + FILE_INPUT_SUFFIX))) - case_inputs = [input.read_text() for input in inputs] - outputs = list(sorted(pathlib.Path(dir).glob("*" + FILE_OUTPUT_SUFFIX))) - case_outputs = [output.read_text() for output in outputs] - filenames = [str(input) for input in inputs] - return zip(filenames, case_inputs, case_outputs) - - -class KCLBaseOverrideTest(unittest.TestCase): - """KCL Override test""" - - def setUp(self): - self.test_cases = _read_override_test_cases_from_dir(dir=TEST_DIR_PATH) - self.maxDiff = None - return super().setUp() - - def assertOverrideEqual(self, filename: str, case_input: str, case_output: str): - from kclvm.tools.query import ApplyOverrides - from kclvm.tools.printer import PrintAST - - if not filename or not case_input or not case_output: - return - prog = LoadProgram(filename) - ApplyOverrides(prog, CMD_OVERRIDES) - with io.StringIO() as out: - PrintAST(prog.pkgs[prog.main][0], out) - out.write("\n") - self.assertEqual(out.getvalue(), case_output) - - def print_overrides_ast(self): - from kclvm.tools.query import PrintOverridesAST, OverrideInfo - - for i in range(len(OverrideInfo.MODIFIED)): - OverrideInfo.MODIFIED[i].filename = OverrideInfo.MODIFIED[i].filename.replace( - FILE_INPUT_SUFFIX, - FILE_OUTPUT_SUFFIX, - ) - PrintOverridesAST() - OverrideInfo.MODIFIED = [] - - -class KCLOverridesTest(KCLBaseOverrideTest): - """KCL Override test""" - - def test_overrides(self): - for filename, case_input, case_output in self.test_cases: - self.assertOverrideEqual(filename, case_input, case_output) - - def test_override_file(self): - from kclvm.tools.query.override import override_file - - file = str(pathlib.Path(__file__).parent.joinpath("file_test_data").joinpath("test.k")) - specs = ["config.image=\"image/image\"", ":config.image=\"image/image:v1\"", ":config.data={id=1,value=\"override_value\"}"] - self.assertEqual(override_file(file, specs), True) - - def test_override_file_auto_fix(self): - from kclvm.tools.query.override import override_file - from kclvm.tools.query.override import KCL_FEATURE_GATE_OVERRIDE_AUTO_FIX_ENV - - os.environ[KCL_FEATURE_GATE_OVERRIDE_AUTO_FIX_ENV] = "1" - file = str(pathlib.Path(__file__).parent.joinpath("file_test_data").joinpath("test_auto_fix.k")) - specs = ["config.image=\"image/image\"", ":config.image=\"image/image:v1\"", ":config.data={id=1,value=1}"] - self.assertEqual(override_file(file, specs), True) - del os.environ[KCL_FEATURE_GATE_OVERRIDE_AUTO_FIX_ENV] - - def test_override_file_auto_schema_import(self): - from kclvm.tools.query.override import override_file - from kclvm.tools.query.override import KCL_FEATURE_GATE_OVERRIDE_AUTO_FIX_ENV - - os.environ[KCL_FEATURE_GATE_OVERRIDE_AUTO_FIX_ENV] = "1" - file = str(pathlib.Path(__file__).parent.joinpath("file_test_data").joinpath("test_auto_import_schema.k")) - specs = ["x0.data=Data{id=1}"] - self.assertEqual(override_file(file, specs), True) - del os.environ[KCL_FEATURE_GATE_OVERRIDE_AUTO_FIX_ENV] - - def test_override_file_with_import_paths(self): - from kclvm.tools.query.override import override_file - - file = str(pathlib.Path(__file__).parent.joinpath("file_test_data").joinpath("test_import_paths.k")) - specs = ["data.value=\"override_value\""] - import_paths = ["pkg", "pkg.pkg"] - self.assertEqual(override_file(file, specs, import_paths), True) - - def test_override_file_invalid(self): - from kclvm.tools.query.override import override_file - - specs = [":a:", "a=1", ":a", "a-1"] - for spec in specs: - with self.assertRaises(kcl_error.KCLException): - override_file("main.k", [spec]) - - -if __name__ == "__main__": - unittest.main(verbosity=2) diff --git a/test/test_units/test_kclvm/test_tools/test_printer/test_data/arguments.input b/test/test_units/test_kclvm/test_tools/test_printer/test_data/arguments.input deleted file mode 100644 index d356f83fb..000000000 --- a/test/test_units/test_kclvm/test_tools/test_printer/test_data/arguments.input +++ /dev/null @@ -1,6 +0,0 @@ -schema Config[nameVar, textVar: str, idVar: int = 1]: - name: str = nameVar - text: str = textVar - id?: int = idVar - -config = Config("test", "text") diff --git a/test/test_units/test_kclvm/test_tools/test_printer/test_data/arguments.output b/test/test_units/test_kclvm/test_tools/test_printer/test_data/arguments.output deleted file mode 100644 index d356f83fb..000000000 --- a/test/test_units/test_kclvm/test_tools/test_printer/test_data/arguments.output +++ /dev/null @@ -1,6 +0,0 @@ -schema Config[nameVar, textVar: str, idVar: int = 1]: - name: str = nameVar - text: str = textVar - id?: int = idVar - -config = Config("test", "text") diff --git a/test/test_units/test_kclvm/test_tools/test_printer/test_data/codelayout.input b/test/test_units/test_kclvm/test_tools/test_printer/test_data/codelayout.input deleted file mode 100644 index 5f44a591a..000000000 --- a/test/test_units/test_kclvm/test_tools/test_printer/test_data/codelayout.input +++ /dev/null @@ -1,77 +0,0 @@ - - - -import math as alias_math -schema Person ( Base): - name:str# inline comment - age:int - check : - age>0 if age , "age must > 0" -person = Person{ - name:"Alice" - age:18 -} -if True: - a = 1 -elif True: - b = 2 -else: - c = 3 -d = 1 + 2 -e = ( 1 + 2 ) -f=[ 1, 2, 3 ] -g = { "key" : "value" } -# block comment -print (1) -dct={"key": "value"} -lst=[1,2,3] -h = dct [ 'key' ] -i = lst [ 1 ] -x = 1 -y = 2 -long_variable = 3 -i = i+1 -submitted+=1 -x = x*2 - 1 -hypot2 = x*x + y*y -_c = (a+b) * (a-b) -_b=2 -_c= 3 -_d =4 - -_value = (1 + 2 * 3) -_value = (1+2*3) -_value =1+ - 2 * ~ 3 -_list = [1, 2, 3] -_list = [*_list, [4, 5 ,6]] -_list = [* _list, [4, 5 ,6]] - -_dict = {** {"k": "v"}, ** {"k": "v"}} -a = [1,2,3] -b = [ - 1,2,3, - 4,5,6, -] -_dict={ - "k1":"v1" - "k2" :"v2" - "k3": "v3" - "k4" : "v4" - "k5" : "v5" -} -foo=1 -if foo is not None: - _a = 1 - _dict|={} - hello = "world{}" . format( 1 )[2 : 4] . lower( ) - range_int = [ i for i in range( 10 ) ] -op = 1+2 - - 3 + (3 - 1) // 3 -op += 1 -op -= 12 + 23 -print( " " , end= '') -log = math. log(12) -aa = 1 -assert aa == 1,"message" -assert aa == 1 if aa,"message" -aaaa = (1 + 2 / 2) if _a == 2 + + 134.3 else ("a"*3) -bbbb = "{}". format(a) \ No newline at end of file diff --git a/test/test_units/test_kclvm/test_tools/test_printer/test_data/codelayout.output b/test/test_units/test_kclvm/test_tools/test_printer/test_data/codelayout.output deleted file mode 100644 index 568ecf7a5..000000000 --- a/test/test_units/test_kclvm/test_tools/test_printer/test_data/codelayout.output +++ /dev/null @@ -1,82 +0,0 @@ -import math as alias_math -schema Person(Base): - # inline comment - name: str - age: int - - check: - age > 0 if age, "age must > 0" - -person = Person { - name: "Alice" - age: 18 -} - -if True: - a = 1 -elif True: - b = 2 -else: - c = 3 - -d = 1 + 2 -e = (1 + 2) -f = [1, 2, 3] -g = {"key": "value"} -# block comment -print(1) -dct = {"key": "value"} -lst = [1, 2, 3] -h = dct['key'] -i = lst[1] -x = 1 -y = 2 -long_variable = 3 -i = i + 1 -submitted += 1 -x = x * 2 - 1 -hypot2 = x * x + y * y -_c = (a + b) * (a - b) -_b = 2 -_c = 3 -_d = 4 -_value = (1 + 2 * 3) -_value = (1 + 2 * 3) -_value = 1 + -2 * ~3 -_list = [1, 2, 3] -_list = [*_list, [4, 5, 6]] -_list = [*_list, [4, 5, 6]] -_dict = {**{"k": "v"}, **{"k": "v"}} -a = [1, 2, 3] -b = [ - 1 - 2 - 3 - 4 - 5 - 6 -] -_dict = { - "k1": "v1" - "k2": "v2" - "k3": "v3" - "k4": "v4" - "k5": "v5" -} -foo = 1 -if foo is not None: - _a = 1 - _dict |= {} - hello = "world{}".format(1)[2:4:].lower() - range_int = [i for i in range(10)] - -op = 1 + 2 - -3 + (3 - 1) // 3 -op += 1 -op -= 12 + 23 -print(" ", end='') -log = math.log(12) -aa = 1 -assert aa == 1, "message" -assert aa == 1 if aa, "message" -aaaa = (1 + 2 / 2) if _a == 2 + +134.3 else ("a" * 3) -bbbb = "{}".format(a) diff --git a/test/test_units/test_kclvm/test_tools/test_printer/test_data/collection_if.input b/test/test_units/test_kclvm/test_tools/test_printer/test_data/collection_if.input deleted file mode 100644 index 080538c1c..000000000 --- a/test/test_units/test_kclvm/test_tools/test_printer/test_data/collection_if.input +++ /dev/null @@ -1,51 +0,0 @@ -schema Config: - name: str - env: str - data: [int] -env = "env" -data1 = Config { - if env == "env": - name: env - env: env - data += [0] - else: - name = "name" - env = "name" - data += [1] -} -data1 = Config { - if env == "env": - name: env - env: env - else: - name: "name" - env: "name" -} -data2 = Config { - if env != "env": - name: env - env: env - else: - name: "name" - env: "name" -} -data3 = { - if True: - key1: "value1" - elif True: - key2: "value2" - elif True: - key3: "value3" - else: - key4: "value4" -} -data4 = [ - if True: - "value1" - elif True: - "value2" - elif True: - "value3" - else: - "value4" -] diff --git a/test/test_units/test_kclvm/test_tools/test_printer/test_data/collection_if.output b/test/test_units/test_kclvm/test_tools/test_printer/test_data/collection_if.output deleted file mode 100644 index 009f8947a..000000000 --- a/test/test_units/test_kclvm/test_tools/test_printer/test_data/collection_if.output +++ /dev/null @@ -1,55 +0,0 @@ -schema Config: - name: str - env: str - data: [int] - -env = "env" -data1 = Config { - if env == "env": - name: env - env: env - data += [0] - else: - name = "name" - env = "name" - data += [1] -} - -data1 = Config { - if env == "env": - name: env - env: env - else: - name: "name" - env: "name" -} - -data2 = Config { - if env != "env": - name: env - env: env - else: - name: "name" - env: "name" -} - -data3 = { - if True: - key1: "value1" - elif True: - key2: "value2" - elif True: - key3: "value3" - else: - key4: "value4" -} -data4 = [ - if True: - "value1" - elif True: - "value2" - elif True: - "value3" - else: - "value4" -] diff --git a/test/test_units/test_kclvm/test_tools/test_printer/test_data/comment.input b/test/test_units/test_kclvm/test_tools/test_printer/test_data/comment.input deleted file mode 100644 index 681a69c31..000000000 --- a/test/test_units/test_kclvm/test_tools/test_printer/test_data/comment.input +++ /dev/null @@ -1,38 +0,0 @@ -# Comment One -schema Main: - name?: str - env?: [{str:}] - -# Comment Two -schema AppConfiguration: - appName: str - image: str - overQuota: bool = False - resource: {str:} - mainContainer?: Main - labels: {str:} - -# Comment Three -appConfiguration = AppConfiguration { - # Comment Four - appName: "kusion" - image: "test-image:v1" # Comment Five - resource: { - cpu: "4" - disk: "50Gi" - memory: "12Gi" - } - labels: { - key: { - key: 12 - } - } - # Comment Six - mainContainer: Main { - name: "kusion_override" - }# Comment Seven - - # Comment Eight - overQuota: True -} -# Comment Nine diff --git a/test/test_units/test_kclvm/test_tools/test_printer/test_data/comment.output b/test/test_units/test_kclvm/test_tools/test_printer/test_data/comment.output deleted file mode 100644 index 4689cf1af..000000000 --- a/test/test_units/test_kclvm/test_tools/test_printer/test_data/comment.output +++ /dev/null @@ -1,40 +0,0 @@ -# Comment One -schema Main: - name?: str - env?: [{str:}] - -# Comment Two -schema AppConfiguration: - appName: str - image: str - overQuota: bool = False - resource: {str:} - mainContainer?: Main - labels: {str:} - -# Comment Three -appConfiguration = AppConfiguration { - # Comment Four - appName: "kusion" - # Comment Five - image: "test-image:v1" - resource: { - cpu: "4" - disk: "50Gi" - memory: "12Gi" - } - labels: { - key: { - key: 12 - } - } - # Comment Six - mainContainer: Main { - name: "kusion_override" - } - # Comment Seven - # Comment Eight - overQuota: True -} - -# Comment Nine diff --git a/test/test_units/test_kclvm/test_tools/test_printer/test_data/empty.input b/test/test_units/test_kclvm/test_tools/test_printer/test_data/empty.input deleted file mode 100644 index fd40910d9..000000000 --- a/test/test_units/test_kclvm/test_tools/test_printer/test_data/empty.input +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/test/test_units/test_kclvm/test_tools/test_printer/test_data/index_sign.input b/test/test_units/test_kclvm/test_tools/test_printer/test_data/index_sign.input deleted file mode 100644 index 54d611873..000000000 --- a/test/test_units/test_kclvm/test_tools/test_printer/test_data/index_sign.input +++ /dev/null @@ -1,12 +0,0 @@ -schema Data: - [str]: any - -schema DataOther: - [...str]: str - id?: int - -schema DataMap: - [name: str]: str - check: - name in ["A", "B", "C"] - \ No newline at end of file diff --git a/test/test_units/test_kclvm/test_tools/test_printer/test_data/index_sign.output b/test/test_units/test_kclvm/test_tools/test_printer/test_data/index_sign.output deleted file mode 100644 index 7da6687ac..000000000 --- a/test/test_units/test_kclvm/test_tools/test_printer/test_data/index_sign.output +++ /dev/null @@ -1,13 +0,0 @@ -schema Data: - [str]: any - -schema DataOther: - [...str]: str - id?: int - -schema DataMap: - [name: str]: str - - check: - name in ["A", "B", "C"] - diff --git a/test/test_units/test_kclvm/test_tools/test_printer/test_data/joined_str.input b/test/test_units/test_kclvm/test_tools/test_printer/test_data/joined_str.input deleted file mode 100644 index 8af336d4a..000000000 --- a/test/test_units/test_kclvm/test_tools/test_printer/test_data/joined_str.input +++ /dev/null @@ -1,3 +0,0 @@ -a = 1 -b = "${a}" -c = "a.${1}" diff --git a/test/test_units/test_kclvm/test_tools/test_printer/test_data/joined_str.output b/test/test_units/test_kclvm/test_tools/test_printer/test_data/joined_str.output deleted file mode 100644 index 8af336d4a..000000000 --- a/test/test_units/test_kclvm/test_tools/test_printer/test_data/joined_str.output +++ /dev/null @@ -1,3 +0,0 @@ -a = 1 -b = "${a}" -c = "a.${1}" diff --git a/test/test_units/test_kclvm/test_tools/test_printer/test_data/lambda.input b/test/test_units/test_kclvm/test_tools/test_printer/test_data/lambda.input deleted file mode 100644 index 32142fc2e..000000000 --- a/test/test_units/test_kclvm/test_tools/test_printer/test_data/lambda.input +++ /dev/null @@ -1,21 +0,0 @@ -sumFunc1 = lambda x, y { - z = x + y - z + x - -} -sumFunc2 = lambda x, y = 1 { - x + y - -} -sumFunc3 = lambda x = 1, y = 1 { - x + y - -} -sumFunc4 = lambda x: int = 1, y: int = 1 -> int { - x + y - -} -x0 = sumFunc1(1, 2) -x1 = sumFunc1(2, 3) -x2 = sumFunc1(3, 4) -x3 = sumFunc1(4, 5) diff --git a/test/test_units/test_kclvm/test_tools/test_printer/test_data/lambda.output b/test/test_units/test_kclvm/test_tools/test_printer/test_data/lambda.output deleted file mode 100644 index 169ae8a1c..000000000 --- a/test/test_units/test_kclvm/test_tools/test_printer/test_data/lambda.output +++ /dev/null @@ -1,21 +0,0 @@ -sumFunc1 = lambda x, y { - z = x + y - z + x - -} -sumFunc2 = lambda x, y = 1 { - x + y - -} -sumFunc3 = lambda x = 1, y = 1 { - x + y - -} -sumFunc4 = lambda x: int = 1, y: int = 1 -> int { - x + y - -} -x0 = sumFunc1(1, 2) -x1 = sumFunc1(2, 3) -x2 = sumFunc1(3, 4) -x3 = sumFunc1(4, 5) diff --git a/test/test_units/test_kclvm/test_tools/test_printer/test_data/quant.input b/test/test_units/test_kclvm/test_tools/test_printer/test_data/quant.input deleted file mode 100644 index 23022c694..000000000 --- a/test/test_units/test_kclvm/test_tools/test_printer/test_data/quant.input +++ /dev/null @@ -1,8 +0,0 @@ -a = all x in [-1, 0, 1, 2, 3] { - x >= 1 if x > 0 -} -b = any x in {k1 = "v1", k2 = "v2"} {x in ["k1", "v2"]} -c = map x in {k1 = "v1", k2 = "v2"} {x} -d = filter x in [1, 2, 3] { - x > 1 -} \ No newline at end of file diff --git a/test/test_units/test_kclvm/test_tools/test_printer/test_data/rule.input b/test/test_units/test_kclvm/test_tools/test_printer/test_data/rule.input deleted file mode 100644 index 662e8eec3..000000000 --- a/test/test_units/test_kclvm/test_tools/test_printer/test_data/rule.input +++ /dev/null @@ -1,19 +0,0 @@ -age = 1 - -schema MainProtocol: - """Protocol doc""" - var: int - -schema MainMixin for MainProtocol: - var: int - -@deprecated -rule Base: - """Rule doc""" - age > 0 - age < 10 - -rule Main[var](Base) for MainProtocol: - var - -Main(1) diff --git a/test/test_units/test_kclvm/test_tools/test_printer/test_data/rule.output b/test/test_units/test_kclvm/test_tools/test_printer/test_data/rule.output deleted file mode 100644 index f45bfac37..000000000 --- a/test/test_units/test_kclvm/test_tools/test_printer/test_data/rule.output +++ /dev/null @@ -1,16 +0,0 @@ -age = 1 -protocol MainProtocol: - """Protocol doc""" - var: int - -mixin MainMixin for MainProtocol: - var: int - -@deprecated -rule Base: - """Rule doc""" - age > 0 - age < 10 -rule Main[var](Base) for MainProtocol: - var -Main(1) diff --git a/test/test_units/test_kclvm/test_tools/test_printer/test_data/type_alias.output b/test/test_units/test_kclvm/test_tools/test_printer/test_data/type_alias.output deleted file mode 100644 index ecb38accb..000000000 --- a/test/test_units/test_kclvm/test_tools/test_printer/test_data/type_alias.output +++ /dev/null @@ -1,19 +0,0 @@ -type Color = "Red"|"Yellow"|"Blue" -colorRed: Color = "Red" -colorYellow: Color = "Yellow" -colorBlue: Color = "Blue" -schema Data: - color: Color - -dataColorRed = Data { - color = "Red" -} - -dataColorYellow = Data { - color = "Yellow" -} - -dataColorBlue = Data { - color = "Blue" -} - diff --git a/test/test_units/test_kclvm/test_tools/test_printer/test_data/unification.input b/test/test_units/test_kclvm/test_tools/test_printer/test_data/unification.input deleted file mode 100644 index 22d05d0bb..000000000 --- a/test/test_units/test_kclvm/test_tools/test_printer/test_data/unification.input +++ /dev/null @@ -1,5 +0,0 @@ -schema Config: - name: str -config: Config { - name = "name" -} \ No newline at end of file diff --git a/test/test_units/test_kclvm/test_tools/test_printer/test_printer.py b/test/test_units/test_kclvm/test_tools/test_printer/test_printer.py deleted file mode 100644 index e8b720195..000000000 --- a/test/test_units/test_kclvm/test_tools/test_printer/test_printer.py +++ /dev/null @@ -1,71 +0,0 @@ -#! /usr/bin/env python3 - -import os -import io -import unittest -import pathlib -from typing import Tuple - -from kclvm.compiler.parser import ParseFile, ParseMode - - -_FILE_INPUT_SUFFIX = ".input" -_FILE_OUTPUT_SUFFIX = ".output" -_PATH_NAME = "test_data" -_DIR_PATH = pathlib.Path(__file__).parent.joinpath(_PATH_NAME) -_TEST_CASES = [ - "arguments", - "empty", - "codelayout", - "collection_if", - "comment", - "index_sign", - "joined_str", - "lambda", - "quant", - "rule", - "type_alias", - "unification", -] - - -class KCLBasePrinterTest(unittest.TestCase): - """ - KCL base Printer test - """ - - def read_data(self, data_name: str) -> Tuple[str, str]: - """ - Read printer data according to data name - """ - input_filename = data_name + _FILE_INPUT_SUFFIX - output_filename = data_name + _FILE_OUTPUT_SUFFIX - data_input = (_DIR_PATH / input_filename).read_text() - data_output = (_DIR_PATH / output_filename).read_text() - return data_input, data_output - - def assert_printer_equal(self, data_name: str) -> None: - """ - Read printer test data according to data name and assert equal. - """ - from kclvm.tools.printer import PrintAST - - data_input, data_output = self.read_data(data_name) - module = ParseFile("", data_input, mode=ParseMode.ParseComments) - with io.StringIO() as str_io: - PrintAST(module, str_io) - self.assertEqual(str_io.getvalue(), data_output) - - -class KCLPrinterTest(KCLBasePrinterTest): - def test_printer_data(self) -> None: - """ - Test printer data for the comparison of input and golden files - """ - self.maxDiff = None - for case in _TEST_CASES: - self.assert_printer_equal(case) - - -if __name__ == "__main__": - unittest.main(verbosity=2) diff --git a/test/test_units/test_kclvm/test_tools/test_printer/test_splice.py b/test/test_units/test_kclvm/test_tools/test_printer/test_splice.py deleted file mode 100644 index f552b4f91..000000000 --- a/test/test_units/test_kclvm/test_tools/test_printer/test_splice.py +++ /dev/null @@ -1,194 +0,0 @@ -#! /usr/bin/env python3 - -import os -import io -import unittest -import pathlib -from typing import Tuple - -from kclvm.tools.printer import SchemaRuleCodeSnippet, splice_schema_with_rule -from kclvm.tools.printer.splice import ( - build_rule_check_block_str, - add_indent_to_code_string, -) - - -class TestSplice(unittest.TestCase): - def test_splice_schema_with_rule(self): - cases = [ - { - "snippet_list": [ - SchemaRuleCodeSnippet( - schema="""\ -schema Person: - name: str -""", - rule="""\ -"a" in name -""", - ) - ], - "expected": """\ -schema Person: - name: str - - check: - "a" in name -""", - }, - { - "snippet_list": [ - SchemaRuleCodeSnippet( - schema="""\ -# Schema Person definition -schema Person: - name: str -""", - rule="""\ -# Schema Person Rule definition -"a" in name -""", - ) - ], - "expected": """\ -# Schema Person definition -schema Person: - name: str - - check: - # Schema Person Rule definition - "a" in name -""", - }, - { - "snippet_list": [ - SchemaRuleCodeSnippet( - schema="""\ -schema Person: - name: str -""", - rule="""""", - ) - ], - "expected": """\ -schema Person: - name: str -""", - }, - { - "snippet_list": [ - SchemaRuleCodeSnippet( - schema="""""", - rule="""\ -"a" in name -""", - ) - ], - "expected": """ -""", - }, - { - "snippet_list": [ - SchemaRuleCodeSnippet( - schema="""\ -schema Person: - name: str - data: Data -""", - rule="""\ -"a" in name -""", - ), - SchemaRuleCodeSnippet( - schema="""\ -schema Data: - id: int -""", - rule="""\ -id > 0 -""", - ), - ], - "expected": """\ -schema Person: - name: str - data: Data - - check: - "a" in name - -schema Data: - id: int - - check: - id > 0 -""", - }, - ] - for case in cases: - snippet_list, expected = case["snippet_list"], case["expected"] - self.assertEqual( - splice_schema_with_rule(snippet_list), expected, msg=f"{snippet_list}" - ) - - def test_splice_schema_with_rule_value_error(self): - cases = [ - {"snippet_list": None}, - {"snippet_list": 1}, - {"snippet_list": [1]}, - ] - for case in cases: - snippet_list = case["snippet_list"] - with self.assertRaises(ValueError): - splice_schema_with_rule(snippet_list) - - def test_build_rule_check_block_str(self): - cases = [ - {"schema": "Mock", "code": "", "expected": ""}, - {"schema": "", "code": "a > 1", "expected": ""}, - { - "schema": "Mock", - "code": "a > 1", - "expected": """\ -schema Mock: - check: - a > 1\ -""", - }, - { - "schema": "Mock", - "code": "a > 1\nb < 1", - "expected": """\ -schema Mock: - check: - a > 1 - b < 1\ -""", - }, - ] - for case in cases: - schema, code, expected = case["schema"], case["code"], case["expected"] - self.assertEqual( - build_rule_check_block_str(schema, code), - expected, - msg=f"schema: {schema}, code: {code}", - ) - - def test_add_indent_to_code_string(self): - cases = [ - {"code": None, "indent": 2, "expected": ""}, - {"code": "", "indent": 2, "expected": ""}, - {"code": "a = 1", "indent": 2, "expected": " a = 1"}, - {"code": "a = 1", "indent": 4, "expected": " a = 1"}, - {"code": "a = 1", "indent": 8, "expected": " a = 1"}, - {"code": "a = 1\nb = 1", "indent": 4, "expected": " a = 1\n b = 1"}, - ] - for case in cases: - code, indent, expected = case["code"], case["indent"], case["expected"] - self.assertEqual( - add_indent_to_code_string(code, indent), expected, msg=f"{code}" - ) - - -if __name__ == "__main__": - unittest.main(verbosity=2) diff --git a/test/test_units/test_kclvm/test_tools/test_validation/json_invalid_test_data/schema.k.json b/test/test_units/test_kclvm/test_tools/test_validation/json_invalid_test_data/schema.k.json deleted file mode 100644 index 3afbbf902..000000000 --- a/test/test_units/test_kclvm/test_tools/test_validation/json_invalid_test_data/schema.k.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "name": "Alice", - "age": "err_age", - "message": "This is Alice" -} diff --git a/test/test_units/test_kclvm/test_tools/test_validation/json_invalid_test_data/schema_with_check.k b/test/test_units/test_kclvm/test_tools/test_validation/json_invalid_test_data/schema_with_check.k deleted file mode 100644 index 523f04288..000000000 --- a/test/test_units/test_kclvm/test_tools/test_validation/json_invalid_test_data/schema_with_check.k +++ /dev/null @@ -1,7 +0,0 @@ -schema User: - name: str - age: int - message?: str - - check: - age > 10 diff --git a/test/test_units/test_kclvm/test_tools/test_validation/json_invalid_test_data/schema_with_check.k.json b/test/test_units/test_kclvm/test_tools/test_validation/json_invalid_test_data/schema_with_check.k.json deleted file mode 100644 index d01557075..000000000 --- a/test/test_units/test_kclvm/test_tools/test_validation/json_invalid_test_data/schema_with_check.k.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "name": "Alice", - "age": "8", - "message": "This is Alice" -} diff --git a/test/test_units/test_kclvm/test_tools/test_validation/json_invalid_test_data/simple.k b/test/test_units/test_kclvm/test_tools/test_validation/json_invalid_test_data/simple.k deleted file mode 100644 index 849c8e9b0..000000000 --- a/test/test_units/test_kclvm/test_tools/test_validation/json_invalid_test_data/simple.k +++ /dev/null @@ -1 +0,0 @@ -assert typeof(value) == "int" diff --git a/test/test_units/test_kclvm/test_tools/test_validation/json_invalid_test_data/simple.k.json b/test/test_units/test_kclvm/test_tools/test_validation/json_invalid_test_data/simple.k.json deleted file mode 100644 index 9459d4ba2..000000000 --- a/test/test_units/test_kclvm/test_tools/test_validation/json_invalid_test_data/simple.k.json +++ /dev/null @@ -1 +0,0 @@ -1.1 diff --git a/test/test_units/test_kclvm/test_tools/test_validation/test_validation.py b/test/test_units/test_kclvm/test_tools/test_validation/test_validation.py deleted file mode 100644 index 0e3b0ffd2..000000000 --- a/test/test_units/test_kclvm/test_tools/test_validation/test_validation.py +++ /dev/null @@ -1,94 +0,0 @@ -#! /usr/bin/env python3 - -import json -import unittest -import pathlib - -from kclvm.kcl.error import KCLException -from kclvm.tools.validation import validate_code, validate_code_with_attr_data - - -class KCLValidationTest(unittest.TestCase): - def test_validate_code_normal_json_data(self): - case_path = pathlib.Path(__file__).parent.joinpath("json_test_data") - json_data_list = sorted(case_path.glob("*.k.json")) - code_string_list = sorted(case_path.glob("*.k")) - for json_data_file, code_string_file in zip(json_data_list, code_string_list): - json_data = pathlib.Path(json_data_file).read_text() - code_string = pathlib.Path(code_string_file).read_text() - self.assertTrue(validate_code(json_data, code_string)) - - def test_validate_code_invalid_json_data(self): - case_path = pathlib.Path(__file__).parent.joinpath("json_invalid_test_data") - json_data_list = sorted(case_path.glob("*.k.json")) - code_string_list = sorted(case_path.glob("*.k")) - for json_data_file, code_string_file in zip(json_data_list, code_string_list): - json_data = pathlib.Path(json_data_file).read_text() - code_string = pathlib.Path(code_string_file).read_text() - with self.assertRaises(KCLException): - validate_code(json_data, code_string) - - def test_validate_code_invalid_argument(self): - invalid_argument_cases = [ - {"data": None, "code": None, "format": "json", "attribute_name": "value"}, - {"data": "1", "code": None, "format": "json", "attribute_name": "value"}, - { - "data": None, - "code": "a = 1", - "format": "json", - "attribute_name": "value", - }, - { - "data": "1", - "code": "assert value >= 1", - "format": None, - "attribute_name": "value", - }, - { - "data": "1", - "code": "assert value >= 1", - "format": "err_format", - "attribute_name": "value", - }, - { - "data": "1", - "code": "assert value >= 1", - "format": "json", - "attribute_name": None, - }, - ] - for case in invalid_argument_cases: - with self.assertRaises(ValueError, msg=f"{case}"): - data, code, format, attribute_name = ( - case["data"], - case["code"], - case["format"], - case["attribute_name"], - ) - validate_code(data, code, format=format, attribute_name=attribute_name) - - def test_validate_code_with_attr_data_normal_json_data(self): - case_path = pathlib.Path(__file__).parent.joinpath("json_test_data") - json_data_list = sorted(case_path.glob("*.k.json")) - code_string_list = sorted(case_path.glob("*.k")) - attr_name = "value" - for json_data_file, code_string_file in zip(json_data_list, code_string_list): - json_data = pathlib.Path(json_data_file).read_text() - json_data = json.dumps({attr_name: json.loads(json_data)}) - code_string = pathlib.Path(code_string_file).read_text() - self.assertTrue(validate_code_with_attr_data(json_data, code_string)) - - def test_validate_code_with_attr_data_invalid_json_data(self): - case_path = pathlib.Path(__file__).parent.joinpath("json_test_data") - json_data_list = sorted(case_path.glob("*.k.json")) - code_string_list = sorted(case_path.glob("*.k")) - attr_name = "value" - for json_data_file, code_string_file in zip(json_data_list, code_string_list): - json_data = pathlib.Path(json_data_file).read_text() - json_data = json.dumps({attr_name: json.loads(json_data), "err_key": {}}) - with self.assertRaises(ValueError): - validate_code_with_attr_data(json_data, "") - - -if __name__ == "__main__": - unittest.main(verbosity=2) diff --git a/test/test_units/test_kclvm/test_types/err_collect_test_data/call.k b/test/test_units/test_kclvm/test_types/err_collect_test_data/call.k deleted file mode 100644 index d713716d5..000000000 --- a/test/test_units/test_kclvm/test_types/err_collect_test_data/call.k +++ /dev/null @@ -1,3 +0,0 @@ -a = 1 -b = a() -c = "".err_lower() diff --git a/test/test_units/test_kclvm/test_types/err_collect_test_data/config.k b/test/test_units/test_kclvm/test_types/err_collect_test_data/config.k deleted file mode 100644 index f21dae226..000000000 --- a/test/test_units/test_kclvm/test_types/err_collect_test_data/config.k +++ /dev/null @@ -1,4 +0,0 @@ -a = 1 -b = a { - key: "value" -} diff --git a/test/test_units/test_kclvm/test_types/err_collect_test_data/index_sign.k b/test/test_units/test_kclvm/test_types/err_collect_test_data/index_sign.k deleted file mode 100644 index e86cbfdd8..000000000 --- a/test/test_units/test_kclvm/test_types/err_collect_test_data/index_sign.k +++ /dev/null @@ -1,7 +0,0 @@ -schema Data: - [str]: int - name: str - -data = Data { - name: "name" -} diff --git a/test/test_units/test_kclvm/test_types/err_collect_test_data/iter.k b/test/test_units/test_kclvm/test_types/err_collect_test_data/iter.k deleted file mode 100644 index 8fb7e9d89..000000000 --- a/test/test_units/test_kclvm/test_types/err_collect_test_data/iter.k +++ /dev/null @@ -1,12 +0,0 @@ -# `int` type object not iterable error -a = 1 -b = [i for i in a] -c = all i in a { - i > 0 -} -# `any` type object return any -d = None -e = [i for i in d] -f = all i in d { - i > 0 -} diff --git a/test/test_units/test_kclvm/test_types/err_collect_test_data/load_attr.k b/test/test_units/test_kclvm/test_types/err_collect_test_data/load_attr.k deleted file mode 100644 index de02e69b9..000000000 --- a/test/test_units/test_kclvm/test_types/err_collect_test_data/load_attr.k +++ /dev/null @@ -1,2 +0,0 @@ -a = 1 -b = a.b diff --git a/test/test_units/test_kclvm/test_types/err_collect_test_data/membership_as.k b/test/test_units/test_kclvm/test_types/err_collect_test_data/membership_as.k deleted file mode 100644 index bfba97320..000000000 --- a/test/test_units/test_kclvm/test_types/err_collect_test_data/membership_as.k +++ /dev/null @@ -1,2 +0,0 @@ -a: str = "s" -b = "1" as a[0] diff --git a/test/test_units/test_kclvm/test_types/err_collect_test_data/module_not_found.k b/test/test_units/test_kclvm/test_types/err_collect_test_data/module_not_found.k deleted file mode 100644 index dc9183c26..000000000 --- a/test/test_units/test_kclvm/test_types/err_collect_test_data/module_not_found.k +++ /dev/null @@ -1,3 +0,0 @@ -import pkg_test - -variable = pkg_test.variable diff --git a/test/test_units/test_kclvm/test_types/err_collect_test_data/pkg/pkg.k b/test/test_units/test_kclvm/test_types/err_collect_test_data/pkg/pkg.k deleted file mode 100644 index 6679bc790..000000000 --- a/test/test_units/test_kclvm/test_types/err_collect_test_data/pkg/pkg.k +++ /dev/null @@ -1,4 +0,0 @@ -schema SomeProtocol: - data: int - -variable = 1 diff --git a/test/test_units/test_kclvm/test_types/err_collect_test_data/pkg_test.k b/test/test_units/test_kclvm/test_types/err_collect_test_data/pkg_test.k deleted file mode 100644 index 13dec83eb..000000000 --- a/test/test_units/test_kclvm/test_types/err_collect_test_data/pkg_test.k +++ /dev/null @@ -1,5 +0,0 @@ -import pkg - -a = pkg.a -b = err_pkg.b -pkg = 1 diff --git a/test/test_units/test_kclvm/test_types/err_collect_test_data/pkg_test/pkg1.k b/test/test_units/test_kclvm/test_types/err_collect_test_data/pkg_test/pkg1.k deleted file mode 100644 index 3c572b1f6..000000000 --- a/test/test_units/test_kclvm/test_types/err_collect_test_data/pkg_test/pkg1.k +++ /dev/null @@ -1,2 +0,0 @@ -import pkg - diff --git a/test/test_units/test_kclvm/test_types/err_collect_test_data/pkg_test/pkg2.k b/test/test_units/test_kclvm/test_types/err_collect_test_data/pkg_test/pkg2.k deleted file mode 100644 index f3d89bcf1..000000000 --- a/test/test_units/test_kclvm/test_types/err_collect_test_data/pkg_test/pkg2.k +++ /dev/null @@ -1 +0,0 @@ -variable = pkg.variable diff --git a/test/test_units/test_kclvm/test_types/err_collect_test_data/protocol.k b/test/test_units/test_kclvm/test_types/err_collect_test_data/protocol.k deleted file mode 100644 index 250aa4b55..000000000 --- a/test/test_units/test_kclvm/test_types/err_collect_test_data/protocol.k +++ /dev/null @@ -1,18 +0,0 @@ -import pkg - -a = 1 - -schema DataProtocol: - data: str - -schema DataMixin for pkg.pkg.DataProtocol: - x: str = data - -schema AMixin for a: - x: str = data - -schema Data(pkg.pkg.Base) for DataProtocol: - x: str = data - -schema A(a) for a: - x: str = data diff --git a/test/test_units/test_kclvm/test_types/err_collect_test_data/relaxed.k b/test/test_units/test_kclvm/test_types/err_collect_test_data/relaxed.k deleted file mode 100644 index 09cdc6abc..000000000 --- a/test/test_units/test_kclvm/test_types/err_collect_test_data/relaxed.k +++ /dev/null @@ -1,7 +0,0 @@ -schema Data: - name: str - -data: Data = Data { - name: "name" - id: 1 -} diff --git a/test/test_units/test_kclvm/test_types/err_collect_test_data/rule.k b/test/test_units/test_kclvm/test_types/err_collect_test_data/rule.k deleted file mode 100644 index b586f63f1..000000000 --- a/test/test_units/test_kclvm/test_types/err_collect_test_data/rule.k +++ /dev/null @@ -1,16 +0,0 @@ -import pkg - -rule SomeRule1 for pkg.SomeProtocol: - some > 0 - -# Invalid protocol type error -rule SomeRule2 for pkg.pkg.SomeProtocol: - some > 0 - -# Package attribute not found type error -rule SomeRule3 for pkg.NotFoundProtocol: - some > 0 - -# Invalid rule protocol object type -rule SomeRule4 for pkg.variable: - some > 0 diff --git a/test/test_units/test_kclvm/test_types/err_collect_test_data/schema.k b/test/test_units/test_kclvm/test_types/err_collect_test_data/schema.k deleted file mode 100644 index 4c76487c5..000000000 --- a/test/test_units/test_kclvm/test_types/err_collect_test_data/schema.k +++ /dev/null @@ -1,36 +0,0 @@ -import pkg - -schema DataProtocol: - data: str - -schema DataMixin: - name: str = "data" - -# Invalid schmea inherit from protocol type error -schema Data for DataProtocol: - mixin [DataMixin] - # Type check errors - a: int = "s" - b: str = 1 - c: bool = "s" - d: [int] = {} - e: {:} = [] - f: "Yellow" | "Green" = "Red" - g: int = 1 if True else "s" - i: int | str = 1.0 - - -# Invalid protocol type error -schema SomeMixin1 for pkg.pkg.SomeProtocol: - some: int - -# Pacakge attribute not found type error -schema SomeMixin2 for pkg.NotFoundProtocol: - some: int - -# Unique key error -schema _Data: - name: str - -schema _Data: - id: int diff --git a/test/test_units/test_kclvm/test_types/err_collect_test_data/select.k b/test/test_units/test_kclvm/test_types/err_collect_test_data/select.k deleted file mode 100644 index d8537f13a..000000000 --- a/test/test_units/test_kclvm/test_types/err_collect_test_data/select.k +++ /dev/null @@ -1,2 +0,0 @@ -a = 1 -b = a.key diff --git a/test/test_units/test_kclvm/test_types/err_collect_test_data/simple.k b/test/test_units/test_kclvm/test_types/err_collect_test_data/simple.k deleted file mode 100644 index 9119606f4..000000000 --- a/test/test_units/test_kclvm/test_types/err_collect_test_data/simple.k +++ /dev/null @@ -1,8 +0,0 @@ -a: int = "s" -b: str = 1 -c: bool = "s" -d: [int] = {} -e: {:} = [] -f: "Yellow" | "Green" = "Red" -g: int = 1 if True else "s" -i: int | str = 1.0 diff --git a/test/test_units/test_kclvm/test_types/err_collect_test_data/str.k b/test/test_units/test_kclvm/test_types/err_collect_test_data/str.k deleted file mode 100644 index 405ff16bd..000000000 --- a/test/test_units/test_kclvm/test_types/err_collect_test_data/str.k +++ /dev/null @@ -1,2 +0,0 @@ -data = "s" -dataUpper = data.upper() diff --git a/test/test_units/test_kclvm/test_types/err_collect_test_data/subscript.k b/test/test_units/test_kclvm/test_types/err_collect_test_data/subscript.k deleted file mode 100644 index a5b4ca790..000000000 --- a/test/test_units/test_kclvm/test_types/err_collect_test_data/subscript.k +++ /dev/null @@ -1,10 +0,0 @@ -a = 1 -b = a[0] -c = 1[0] -d = {} -e = None -f = e[0] - -data = {key: "value"} -dataKey = data[::-1] -dataValue = data[d] diff --git a/test/test_units/test_kclvm/test_types/err_collect_test_data/type.k b/test/test_units/test_kclvm/test_types/err_collect_test_data/type.k deleted file mode 100644 index a8af59a71..000000000 --- a/test/test_units/test_kclvm/test_types/err_collect_test_data/type.k +++ /dev/null @@ -1,2 +0,0 @@ -_a: str = "s" -_a: int = 1 diff --git a/test/test_units/test_kclvm/test_types/err_collect_test_data/unpack.k b/test/test_units/test_kclvm/test_types/err_collect_test_data/unpack.k deleted file mode 100644 index 28e8c81bc..000000000 --- a/test/test_units/test_kclvm/test_types/err_collect_test_data/unpack.k +++ /dev/null @@ -1,4 +0,0 @@ -# only list, dict, schema object can be used * and ** unpacked -a = 1 -b = [*a] -c = {**a} diff --git a/test/test_units/test_kclvm/test_types/err_collect_test_data/var_not_defined.k b/test/test_units/test_kclvm/test_types/err_collect_test_data/var_not_defined.k deleted file mode 100644 index ff9b48395..000000000 --- a/test/test_units/test_kclvm/test_types/err_collect_test_data/var_not_defined.k +++ /dev/null @@ -1,3 +0,0 @@ -_a = b -_a = c -_d = a diff --git a/test/test_units/test_kclvm/test_types/invalid_test_data/assert/assert_0.k b/test/test_units/test_kclvm/test_types/invalid_test_data/assert/assert_0.k deleted file mode 100644 index 88775be26..000000000 --- a/test/test_units/test_kclvm/test_types/invalid_test_data/assert/assert_0.k +++ /dev/null @@ -1 +0,0 @@ -assert False, 1 diff --git a/test/test_units/test_kclvm/test_types/invalid_test_data/assert/assert_1.k b/test/test_units/test_kclvm/test_types/invalid_test_data/assert/assert_1.k deleted file mode 100644 index b3745fe1c..000000000 --- a/test/test_units/test_kclvm/test_types/invalid_test_data/assert/assert_1.k +++ /dev/null @@ -1,2 +0,0 @@ -a = 1 -assert False, a diff --git a/test/test_units/test_kclvm/test_types/invalid_test_data/attr_op/attr_op_0.k b/test/test_units/test_kclvm/test_types/invalid_test_data/attr_op/attr_op_0.k deleted file mode 100644 index 5300d6d4e..000000000 --- a/test/test_units/test_kclvm/test_types/invalid_test_data/attr_op/attr_op_0.k +++ /dev/null @@ -1,5 +0,0 @@ -a = { - key1 = [0] # [0] - key1 += [1] # [0, 1] - key1 += None # Error: only list type can in inserted -} diff --git a/test/test_units/test_kclvm/test_types/invalid_test_data/attr_op/attr_op_1.k b/test/test_units/test_kclvm/test_types/invalid_test_data/attr_op/attr_op_1.k deleted file mode 100644 index 51ff50dd2..000000000 --- a/test/test_units/test_kclvm/test_types/invalid_test_data/attr_op/attr_op_1.k +++ /dev/null @@ -1,8 +0,0 @@ -schema Data: - key1: [int] - -a = Data { - key1 = [0] # [0] - key1 += [1] # [0, 1] - key1 += Undefined # Error: only list type can in inserted -} diff --git a/test/test_units/test_kclvm/test_types/invalid_test_data/calculation/calculation_0.k b/test/test_units/test_kclvm/test_types/invalid_test_data/calculation/calculation_0.k deleted file mode 100644 index d0155490a..000000000 --- a/test/test_units/test_kclvm/test_types/invalid_test_data/calculation/calculation_0.k +++ /dev/null @@ -1 +0,0 @@ -a = 1 + "s" diff --git a/test/test_units/test_kclvm/test_types/invalid_test_data/calculation/calculation_1.k b/test/test_units/test_kclvm/test_types/invalid_test_data/calculation/calculation_1.k deleted file mode 100644 index 259f280da..000000000 --- a/test/test_units/test_kclvm/test_types/invalid_test_data/calculation/calculation_1.k +++ /dev/null @@ -1 +0,0 @@ -a = -"s" diff --git a/test/test_units/test_kclvm/test_types/invalid_test_data/calculation/calculation_2.k b/test/test_units/test_kclvm/test_types/invalid_test_data/calculation/calculation_2.k deleted file mode 100644 index b7f65d99e..000000000 --- a/test/test_units/test_kclvm/test_types/invalid_test_data/calculation/calculation_2.k +++ /dev/null @@ -1 +0,0 @@ -a = "s" < 1 diff --git a/test/test_units/test_kclvm/test_types/invalid_test_data/calculation/calculation_3.k b/test/test_units/test_kclvm/test_types/invalid_test_data/calculation/calculation_3.k deleted file mode 100644 index 13a7312e8..000000000 --- a/test/test_units/test_kclvm/test_types/invalid_test_data/calculation/calculation_3.k +++ /dev/null @@ -1 +0,0 @@ -a = 1 / 0 diff --git a/test/test_units/test_kclvm/test_types/invalid_test_data/calculation/calculation_4.k b/test/test_units/test_kclvm/test_types/invalid_test_data/calculation/calculation_4.k deleted file mode 100644 index 7b9544e84..000000000 --- a/test/test_units/test_kclvm/test_types/invalid_test_data/calculation/calculation_4.k +++ /dev/null @@ -1 +0,0 @@ -a = 1 * None diff --git a/test/test_units/test_kclvm/test_types/invalid_test_data/calculation/calculation_5.k b/test/test_units/test_kclvm/test_types/invalid_test_data/calculation/calculation_5.k deleted file mode 100644 index d4ef9cb9f..000000000 --- a/test/test_units/test_kclvm/test_types/invalid_test_data/calculation/calculation_5.k +++ /dev/null @@ -1 +0,0 @@ -a = [] | {} diff --git a/test/test_units/test_kclvm/test_types/invalid_test_data/calculation/calculation_6.k b/test/test_units/test_kclvm/test_types/invalid_test_data/calculation/calculation_6.k deleted file mode 100644 index b0f77def3..000000000 --- a/test/test_units/test_kclvm/test_types/invalid_test_data/calculation/calculation_6.k +++ /dev/null @@ -1 +0,0 @@ -a = 1 // 0 diff --git a/test/test_units/test_kclvm/test_types/invalid_test_data/calculation/calculation_7.k b/test/test_units/test_kclvm/test_types/invalid_test_data/calculation/calculation_7.k deleted file mode 100644 index 257b158d8..000000000 --- a/test/test_units/test_kclvm/test_types/invalid_test_data/calculation/calculation_7.k +++ /dev/null @@ -1 +0,0 @@ -a = 1 % 0 diff --git a/test/test_units/test_kclvm/test_types/invalid_test_data/for_comp/for_comp_0.k b/test/test_units/test_kclvm/test_types/invalid_test_data/for_comp/for_comp_0.k deleted file mode 100644 index 1470b4b9d..000000000 --- a/test/test_units/test_kclvm/test_types/invalid_test_data/for_comp/for_comp_0.k +++ /dev/null @@ -1,4 +0,0 @@ -data1 = {"k1": "v1", "k2": "v2"} -data2 = {"k3": "v3", "k4": "v4"} -# Error: dict unpacking cannot be used in dict comprehension -dataNew = {**{"${k1}": v1, "${k1}": v2, "${k2}": v1, "${k2}": v2} for k1, v1 in data1 for k2, v2 in data2} diff --git a/test/test_units/test_kclvm/test_types/invalid_test_data/for_comp/for_comp_1.k b/test/test_units/test_kclvm/test_types/invalid_test_data/for_comp/for_comp_1.k deleted file mode 100644 index d0099b7c6..000000000 --- a/test/test_units/test_kclvm/test_types/invalid_test_data/for_comp/for_comp_1.k +++ /dev/null @@ -1,3 +0,0 @@ -data = [[1, 2], [3, 4]] -# Error: list unpacking cannot be used in list comprehension -dataNew = [*i for i in data] diff --git a/test/test_units/test_kclvm/test_types/invalid_test_data/func_call/func_call_0.k b/test/test_units/test_kclvm/test_types/invalid_test_data/func_call/func_call_0.k deleted file mode 100644 index 9d75fa5d8..000000000 --- a/test/test_units/test_kclvm/test_types/invalid_test_data/func_call/func_call_0.k +++ /dev/null @@ -1 +0,0 @@ -a = 1() diff --git a/test/test_units/test_kclvm/test_types/invalid_test_data/func_call/func_call_1.k b/test/test_units/test_kclvm/test_types/invalid_test_data/func_call/func_call_1.k deleted file mode 100644 index 97d6f8b8d..000000000 --- a/test/test_units/test_kclvm/test_types/invalid_test_data/func_call/func_call_1.k +++ /dev/null @@ -1 +0,0 @@ -a = ""() diff --git a/test/test_units/test_kclvm/test_types/invalid_test_data/func_call/func_call_2.k b/test/test_units/test_kclvm/test_types/invalid_test_data/func_call/func_call_2.k deleted file mode 100644 index 79531565b..000000000 --- a/test/test_units/test_kclvm/test_types/invalid_test_data/func_call/func_call_2.k +++ /dev/null @@ -1 +0,0 @@ -a = func() diff --git a/test/test_units/test_kclvm/test_types/invalid_test_data/func_call/func_call_3.k b/test/test_units/test_kclvm/test_types/invalid_test_data/func_call/func_call_3.k deleted file mode 100644 index 02e620417..000000000 --- a/test/test_units/test_kclvm/test_types/invalid_test_data/func_call/func_call_3.k +++ /dev/null @@ -1,7 +0,0 @@ -schema Person: - name: str - -func: any = lambda x: Person { - x.name -} -name = func(Person {name = 1}) diff --git a/test/test_units/test_kclvm/test_types/invalid_test_data/if/if_0.k b/test/test_units/test_kclvm/test_types/invalid_test_data/if/if_0.k deleted file mode 100644 index 57be988ea..000000000 --- a/test/test_units/test_kclvm/test_types/invalid_test_data/if/if_0.k +++ /dev/null @@ -1 +0,0 @@ -a: int = 1 if True else "2" diff --git a/test/test_units/test_kclvm/test_types/invalid_test_data/if/if_1.k b/test/test_units/test_kclvm/test_types/invalid_test_data/if/if_1.k deleted file mode 100644 index 5e86489b5..000000000 --- a/test/test_units/test_kclvm/test_types/invalid_test_data/if/if_1.k +++ /dev/null @@ -1,3 +0,0 @@ -_a: int = 1 -if True: - _a = "2" diff --git a/test/test_units/test_kclvm/test_types/invalid_test_data/import/import_1.k b/test/test_units/test_kclvm/test_types/invalid_test_data/import/import_1.k deleted file mode 100644 index 05827d95d..000000000 --- a/test/test_units/test_kclvm/test_types/invalid_test_data/import/import_1.k +++ /dev/null @@ -1 +0,0 @@ -import import_2 diff --git a/test/test_units/test_kclvm/test_types/invalid_test_data/import/import_2.k b/test/test_units/test_kclvm/test_types/invalid_test_data/import/import_2.k deleted file mode 100644 index 0b281f285..000000000 --- a/test/test_units/test_kclvm/test_types/invalid_test_data/import/import_2.k +++ /dev/null @@ -1 +0,0 @@ -import import_1 diff --git a/test/test_units/test_kclvm/test_types/invalid_test_data/loop/loop_0.k b/test/test_units/test_kclvm/test_types/invalid_test_data/loop/loop_0.k deleted file mode 100644 index c925349c0..000000000 --- a/test/test_units/test_kclvm/test_types/invalid_test_data/loop/loop_0.k +++ /dev/null @@ -1 +0,0 @@ -a = [i for i in 1] \ No newline at end of file diff --git a/test/test_units/test_kclvm/test_types/invalid_test_data/loop/loop_1.k b/test/test_units/test_kclvm/test_types/invalid_test_data/loop/loop_1.k deleted file mode 100644 index 21c0ce4af..000000000 --- a/test/test_units/test_kclvm/test_types/invalid_test_data/loop/loop_1.k +++ /dev/null @@ -1,4 +0,0 @@ -a = 1 -b = all i in a { - i -} diff --git a/test/test_units/test_kclvm/test_types/invalid_test_data/loop/loop_2.k b/test/test_units/test_kclvm/test_types/invalid_test_data/loop/loop_2.k deleted file mode 100644 index 1a4308681..000000000 --- a/test/test_units/test_kclvm/test_types/invalid_test_data/loop/loop_2.k +++ /dev/null @@ -1 +0,0 @@ -a: {str:} = {i: "value" for i in [{"name": "value"}, {"name": "value"}]} diff --git a/test/test_units/test_kclvm/test_types/invalid_test_data/loop/loop_3.k b/test/test_units/test_kclvm/test_types/invalid_test_data/loop/loop_3.k deleted file mode 100644 index 4abc698f2..000000000 --- a/test/test_units/test_kclvm/test_types/invalid_test_data/loop/loop_3.k +++ /dev/null @@ -1 +0,0 @@ -x: [int] = [i for i in [0] or ["1"]] diff --git a/test/test_units/test_kclvm/test_types/invalid_test_data/loop/loop_4.k b/test/test_units/test_kclvm/test_types/invalid_test_data/loop/loop_4.k deleted file mode 100644 index 7558e5094..000000000 --- a/test/test_units/test_kclvm/test_types/invalid_test_data/loop/loop_4.k +++ /dev/null @@ -1 +0,0 @@ -x: [str] = [i for i in [0] or ["1"]] diff --git a/test/test_units/test_kclvm/test_types/invalid_test_data/loop/loop_5.k b/test/test_units/test_kclvm/test_types/invalid_test_data/loop/loop_5.k deleted file mode 100644 index 5e382772e..000000000 --- a/test/test_units/test_kclvm/test_types/invalid_test_data/loop/loop_5.k +++ /dev/null @@ -1 +0,0 @@ -x = [i + v for i, v in [0] or ["1"]] diff --git a/test/test_units/test_kclvm/test_types/invalid_test_data/module/module_0.k b/test/test_units/test_kclvm/test_types/invalid_test_data/module/module_0.k deleted file mode 100644 index 26ac612aa..000000000 --- a/test/test_units/test_kclvm/test_types/invalid_test_data/module/module_0.k +++ /dev/null @@ -1,3 +0,0 @@ -import pkg - -a = pkg.b diff --git a/test/test_units/test_kclvm/test_types/invalid_test_data/module/module_1.k b/test/test_units/test_kclvm/test_types/invalid_test_data/module/module_1.k deleted file mode 100644 index 4fb05f3c3..000000000 --- a/test/test_units/test_kclvm/test_types/invalid_test_data/module/module_1.k +++ /dev/null @@ -1,3 +0,0 @@ -import pkg - -pkg.a = 1 diff --git a/test/test_units/test_kclvm/test_types/invalid_test_data/module/module_2.k b/test/test_units/test_kclvm/test_types/invalid_test_data/module/module_2.k deleted file mode 100644 index 0ed0addb0..000000000 --- a/test/test_units/test_kclvm/test_types/invalid_test_data/module/module_2.k +++ /dev/null @@ -1,3 +0,0 @@ -import pkg as pkgpkg - -a = pkgpkg.b diff --git a/test/test_units/test_kclvm/test_types/invalid_test_data/module/module_3.k b/test/test_units/test_kclvm/test_types/invalid_test_data/module/module_3.k deleted file mode 100644 index 1492535ff..000000000 --- a/test/test_units/test_kclvm/test_types/invalid_test_data/module/module_3.k +++ /dev/null @@ -1 +0,0 @@ -import math_err diff --git a/test/test_units/test_kclvm/test_types/invalid_test_data/module/module_4.k b/test/test_units/test_kclvm/test_types/invalid_test_data/module/module_4.k deleted file mode 100644 index c656b420a..000000000 --- a/test/test_units/test_kclvm/test_types/invalid_test_data/module/module_4.k +++ /dev/null @@ -1 +0,0 @@ -import kcl_plugin.err_plugin diff --git a/test/test_units/test_kclvm/test_types/invalid_test_data/module/module_5.k b/test/test_units/test_kclvm/test_types/invalid_test_data/module/module_5.k deleted file mode 100644 index 39cb50c91..000000000 --- a/test/test_units/test_kclvm/test_types/invalid_test_data/module/module_5.k +++ /dev/null @@ -1 +0,0 @@ -import pkg1 diff --git a/test/test_units/test_kclvm/test_types/invalid_test_data/module/module_6.k b/test/test_units/test_kclvm/test_types/invalid_test_data/module/module_6.k deleted file mode 100644 index daef190bc..000000000 --- a/test/test_units/test_kclvm/test_types/invalid_test_data/module/module_6.k +++ /dev/null @@ -1,4 +0,0 @@ -import math - -a = math.err_func(1) - diff --git a/test/test_units/test_kclvm/test_types/invalid_test_data/module/pkg1/a.k b/test/test_units/test_kclvm/test_types/invalid_test_data/module/pkg1/a.k deleted file mode 100644 index 288701ba1..000000000 --- a/test/test_units/test_kclvm/test_types/invalid_test_data/module/pkg1/a.k +++ /dev/null @@ -1 +0,0 @@ -import pkg diff --git a/test/test_units/test_kclvm/test_types/invalid_test_data/module/pkg1/b.k b/test/test_units/test_kclvm/test_types/invalid_test_data/module/pkg1/b.k deleted file mode 100644 index bbd114505..000000000 --- a/test/test_units/test_kclvm/test_types/invalid_test_data/module/pkg1/b.k +++ /dev/null @@ -1 +0,0 @@ -b = pkg.a diff --git a/test/test_units/test_kclvm/test_types/invalid_test_data/protocol/pkg/pkg.k b/test/test_units/test_kclvm/test_types/invalid_test_data/protocol/pkg/pkg.k deleted file mode 100644 index 1c30c4acd..000000000 --- a/test/test_units/test_kclvm/test_types/invalid_test_data/protocol/pkg/pkg.k +++ /dev/null @@ -1,2 +0,0 @@ -schema SomeProtocol: - data: int diff --git a/test/test_units/test_kclvm/test_types/invalid_test_data/protocol/protocol_1.k b/test/test_units/test_kclvm/test_types/invalid_test_data/protocol/protocol_1.k deleted file mode 100644 index af6a60c60..000000000 --- a/test/test_units/test_kclvm/test_types/invalid_test_data/protocol/protocol_1.k +++ /dev/null @@ -1,5 +0,0 @@ -schema DataProtocol: - data: str - -schema Data for DataProtocol: - x: int = data diff --git a/test/test_units/test_kclvm/test_types/invalid_test_data/protocol/protocol_2.k b/test/test_units/test_kclvm/test_types/invalid_test_data/protocol/protocol_2.k deleted file mode 100644 index ee9f7d81d..000000000 --- a/test/test_units/test_kclvm/test_types/invalid_test_data/protocol/protocol_2.k +++ /dev/null @@ -1,7 +0,0 @@ -import pkg - -schema DataProtocol: - data: str - -schema DataMixin for pkg.DataProtocol: - x: int = data diff --git a/test/test_units/test_kclvm/test_types/invalid_test_data/protocol/protocol_3.k b/test/test_units/test_kclvm/test_types/invalid_test_data/protocol/protocol_3.k deleted file mode 100644 index 6cd890a1f..000000000 --- a/test/test_units/test_kclvm/test_types/invalid_test_data/protocol/protocol_3.k +++ /dev/null @@ -1,7 +0,0 @@ -import pkg - -schema DataProtocol: - data: str - -schema DataMixin for pkg.pkg.DataProtocol: - x: int = data diff --git a/test/test_units/test_kclvm/test_types/invalid_test_data/protocol/protocol_4.k b/test/test_units/test_kclvm/test_types/invalid_test_data/protocol/protocol_4.k deleted file mode 100644 index a35a69a33..000000000 --- a/test/test_units/test_kclvm/test_types/invalid_test_data/protocol/protocol_4.k +++ /dev/null @@ -1,4 +0,0 @@ -a = None - -schema DataMixin for a: - x: int = data diff --git a/test/test_units/test_kclvm/test_types/invalid_test_data/protocol/protocol_5.k b/test/test_units/test_kclvm/test_types/invalid_test_data/protocol/protocol_5.k deleted file mode 100644 index a9d78448d..000000000 --- a/test/test_units/test_kclvm/test_types/invalid_test_data/protocol/protocol_5.k +++ /dev/null @@ -1,3 +0,0 @@ -protocol DataProtocol: - x: str = "1" - x = "2" diff --git a/test/test_units/test_kclvm/test_types/invalid_test_data/schema/pkg/pkg.k b/test/test_units/test_kclvm/test_types/invalid_test_data/schema/pkg/pkg.k deleted file mode 100644 index 69d89eea9..000000000 --- a/test/test_units/test_kclvm/test_types/invalid_test_data/schema/pkg/pkg.k +++ /dev/null @@ -1,8 +0,0 @@ -schema Person: - name: str = "Alice" - age: int = 18 - -Base = 1 - -schema PersonMixin: - nameUpper: str = name.upper() diff --git a/test/test_units/test_kclvm/test_types/invalid_test_data/schema/schema_0.k b/test/test_units/test_kclvm/test_types/invalid_test_data/schema/schema_0.k deleted file mode 100644 index 7cc8d965c..000000000 --- a/test/test_units/test_kclvm/test_types/invalid_test_data/schema/schema_0.k +++ /dev/null @@ -1,2 +0,0 @@ -schema Data(pkg.Base.Base): - name: str diff --git a/test/test_units/test_kclvm/test_types/invalid_test_data/schema/schema_1.k b/test/test_units/test_kclvm/test_types/invalid_test_data/schema/schema_1.k deleted file mode 100644 index 851f6ba8f..000000000 --- a/test/test_units/test_kclvm/test_types/invalid_test_data/schema/schema_1.k +++ /dev/null @@ -1,2 +0,0 @@ -schema Data(Base): - name: str diff --git a/test/test_units/test_kclvm/test_types/invalid_test_data/schema/schema_10.k b/test/test_units/test_kclvm/test_types/invalid_test_data/schema/schema_10.k deleted file mode 100644 index 725308ede..000000000 --- a/test/test_units/test_kclvm/test_types/invalid_test_data/schema/schema_10.k +++ /dev/null @@ -1,5 +0,0 @@ -schema _Data: - name: str - -schema _Data: - name: str diff --git a/test/test_units/test_kclvm/test_types/invalid_test_data/schema/schema_11.k b/test/test_units/test_kclvm/test_types/invalid_test_data/schema/schema_11.k deleted file mode 100644 index 5e6ffe064..000000000 --- a/test/test_units/test_kclvm/test_types/invalid_test_data/schema/schema_11.k +++ /dev/null @@ -1,6 +0,0 @@ -schema Data: - name: str - -data = Data { - data: 1 -} diff --git a/test/test_units/test_kclvm/test_types/invalid_test_data/schema/schema_12.k b/test/test_units/test_kclvm/test_types/invalid_test_data/schema/schema_12.k deleted file mode 100644 index d7f6d5765..000000000 --- a/test/test_units/test_kclvm/test_types/invalid_test_data/schema/schema_12.k +++ /dev/null @@ -1,12 +0,0 @@ -schema NamedMap: - [str]: str - -data = { - key1: "value1" - key2: "value2" -} - -named_data = NamedMap { - **data - data: 1 -} diff --git a/test/test_units/test_kclvm/test_types/invalid_test_data/schema/schema_13.k b/test/test_units/test_kclvm/test_types/invalid_test_data/schema/schema_13.k deleted file mode 100644 index 924123d57..000000000 --- a/test/test_units/test_kclvm/test_types/invalid_test_data/schema/schema_13.k +++ /dev/null @@ -1,3 +0,0 @@ -schema NamedMap: - [str]: str - data: int diff --git a/test/test_units/test_kclvm/test_types/invalid_test_data/schema/schema_14.k b/test/test_units/test_kclvm/test_types/invalid_test_data/schema/schema_14.k deleted file mode 100644 index 27c9bb4bc..000000000 --- a/test/test_units/test_kclvm/test_types/invalid_test_data/schema/schema_14.k +++ /dev/null @@ -1,4 +0,0 @@ -schema Person[name: str, age: int]: - """""" - -person = Person(name="Alice", name="Bob") {} diff --git a/test/test_units/test_kclvm/test_types/invalid_test_data/schema/schema_15.k b/test/test_units/test_kclvm/test_types/invalid_test_data/schema/schema_15.k deleted file mode 100644 index 9369932fb..000000000 --- a/test/test_units/test_kclvm/test_types/invalid_test_data/schema/schema_15.k +++ /dev/null @@ -1,4 +0,0 @@ -schema Person[name: str, age: int]: - """""" - -person = Person(name="Alice", name="Bob") diff --git a/test/test_units/test_kclvm/test_types/invalid_test_data/schema/schema_16.k b/test/test_units/test_kclvm/test_types/invalid_test_data/schema/schema_16.k deleted file mode 100644 index 003f22796..000000000 --- a/test/test_units/test_kclvm/test_types/invalid_test_data/schema/schema_16.k +++ /dev/null @@ -1,4 +0,0 @@ -schema Person[name: str, age: int]: - """""" - -person = Person(err_name="Alice") diff --git a/test/test_units/test_kclvm/test_types/invalid_test_data/schema/schema_17.k b/test/test_units/test_kclvm/test_types/invalid_test_data/schema/schema_17.k deleted file mode 100644 index 9ff2da45e..000000000 --- a/test/test_units/test_kclvm/test_types/invalid_test_data/schema/schema_17.k +++ /dev/null @@ -1,4 +0,0 @@ -schema Person[name: str, age: int]: - """""" - -person = Person(10, "name") diff --git a/test/test_units/test_kclvm/test_types/invalid_test_data/schema/schema_18.k b/test/test_units/test_kclvm/test_types/invalid_test_data/schema/schema_18.k deleted file mode 100644 index f62e33f2c..000000000 --- a/test/test_units/test_kclvm/test_types/invalid_test_data/schema/schema_18.k +++ /dev/null @@ -1,5 +0,0 @@ -@deprecated(err_version="v1.16") -schema Person[name: str, age: int]: - """""" - -person = Person("name", 10) diff --git a/test/test_units/test_kclvm/test_types/invalid_test_data/schema/schema_19.k b/test/test_units/test_kclvm/test_types/invalid_test_data/schema/schema_19.k deleted file mode 100644 index 707cc4962..000000000 --- a/test/test_units/test_kclvm/test_types/invalid_test_data/schema/schema_19.k +++ /dev/null @@ -1,4 +0,0 @@ -Person = 1 -b = Person { - name: "Alice" -} diff --git a/test/test_units/test_kclvm/test_types/invalid_test_data/schema/schema_2.k b/test/test_units/test_kclvm/test_types/invalid_test_data/schema/schema_2.k deleted file mode 100644 index 82c22b698..000000000 --- a/test/test_units/test_kclvm/test_types/invalid_test_data/schema/schema_2.k +++ /dev/null @@ -1,4 +0,0 @@ -Base = 1 - -schema Data(Base): - name: str diff --git a/test/test_units/test_kclvm/test_types/invalid_test_data/schema/schema_20.k b/test/test_units/test_kclvm/test_types/invalid_test_data/schema/schema_20.k deleted file mode 100644 index 0bf8facc8..000000000 --- a/test/test_units/test_kclvm/test_types/invalid_test_data/schema/schema_20.k +++ /dev/null @@ -1,7 +0,0 @@ -schema Data: - [str]: int - -data = Data { - key1: 1 - key2: "value" -} \ No newline at end of file diff --git a/test/test_units/test_kclvm/test_types/invalid_test_data/schema/schema_21.k b/test/test_units/test_kclvm/test_types/invalid_test_data/schema/schema_21.k deleted file mode 100644 index 3bf2fe880..000000000 --- a/test/test_units/test_kclvm/test_types/invalid_test_data/schema/schema_21.k +++ /dev/null @@ -1,9 +0,0 @@ -base = 1 - -schema Data: - [str]: int - -data = Data { - **base - key1: 1 -} \ No newline at end of file diff --git a/test/test_units/test_kclvm/test_types/invalid_test_data/schema/schema_22.k b/test/test_units/test_kclvm/test_types/invalid_test_data/schema/schema_22.k deleted file mode 100644 index ba9d6358e..000000000 --- a/test/test_units/test_kclvm/test_types/invalid_test_data/schema/schema_22.k +++ /dev/null @@ -1,4 +0,0 @@ -schema Data: - [str]: int - -data_list = Data.err_instances() diff --git a/test/test_units/test_kclvm/test_types/invalid_test_data/schema/schema_23.k b/test/test_units/test_kclvm/test_types/invalid_test_data/schema/schema_23.k deleted file mode 100644 index 6b645cd77..000000000 --- a/test/test_units/test_kclvm/test_types/invalid_test_data/schema/schema_23.k +++ /dev/null @@ -1,9 +0,0 @@ -schema Person: - name: str - temp: str - - _temp = None - temp = _temp - - _name = 123 - name = _name diff --git a/test/test_units/test_kclvm/test_types/invalid_test_data/schema/schema_24.k b/test/test_units/test_kclvm/test_types/invalid_test_data/schema/schema_24.k deleted file mode 100644 index 444ea8d06..000000000 --- a/test/test_units/test_kclvm/test_types/invalid_test_data/schema/schema_24.k +++ /dev/null @@ -1,5 +0,0 @@ -schema Parent(Son): - name: str - -schema Son(Parent): - name: str diff --git a/test/test_units/test_kclvm/test_types/invalid_test_data/schema/schema_25.k b/test/test_units/test_kclvm/test_types/invalid_test_data/schema/schema_25.k deleted file mode 100644 index 25f27ade9..000000000 --- a/test/test_units/test_kclvm/test_types/invalid_test_data/schema/schema_25.k +++ /dev/null @@ -1,2 +0,0 @@ -schema Conifg: - name.attr: str diff --git a/test/test_units/test_kclvm/test_types/invalid_test_data/schema/schema_26.k b/test/test_units/test_kclvm/test_types/invalid_test_data/schema/schema_26.k deleted file mode 100644 index 25f27ade9..000000000 --- a/test/test_units/test_kclvm/test_types/invalid_test_data/schema/schema_26.k +++ /dev/null @@ -1,2 +0,0 @@ -schema Conifg: - name.attr: str diff --git a/test/test_units/test_kclvm/test_types/invalid_test_data/schema/schema_27.k b/test/test_units/test_kclvm/test_types/invalid_test_data/schema/schema_27.k deleted file mode 100644 index 8c8fdadf2..000000000 --- a/test/test_units/test_kclvm/test_types/invalid_test_data/schema/schema_27.k +++ /dev/null @@ -1,2 +0,0 @@ -schema Person[name: str]: - name: str = name diff --git a/test/test_units/test_kclvm/test_types/invalid_test_data/schema/schema_28.k b/test/test_units/test_kclvm/test_types/invalid_test_data/schema/schema_28.k deleted file mode 100644 index e1498e3a4..000000000 --- a/test/test_units/test_kclvm/test_types/invalid_test_data/schema/schema_28.k +++ /dev/null @@ -1,6 +0,0 @@ -# Arguments cannot be used in the schema modification expression -schema Person: - name: str - -personOrigin = Person { name = "Alice" } -personNew = personOrigin("invalid arguments") { name = "Bob" } diff --git a/test/test_units/test_kclvm/test_types/invalid_test_data/schema/schema_29.k b/test/test_units/test_kclvm/test_types/invalid_test_data/schema/schema_29.k deleted file mode 100644 index d4e1249c4..000000000 --- a/test/test_units/test_kclvm/test_types/invalid_test_data/schema/schema_29.k +++ /dev/null @@ -1,2 +0,0 @@ -schema str: - name: str diff --git a/test/test_units/test_kclvm/test_types/invalid_test_data/schema/schema_3.k b/test/test_units/test_kclvm/test_types/invalid_test_data/schema/schema_3.k deleted file mode 100644 index 1f0c17dc3..000000000 --- a/test/test_units/test_kclvm/test_types/invalid_test_data/schema/schema_3.k +++ /dev/null @@ -1,4 +0,0 @@ -import pkg - -schema Data(pkg.ErrorName): - name: str diff --git a/test/test_units/test_kclvm/test_types/invalid_test_data/schema/schema_30.k b/test/test_units/test_kclvm/test_types/invalid_test_data/schema/schema_30.k deleted file mode 100644 index 5ba39ea00..000000000 --- a/test/test_units/test_kclvm/test_types/invalid_test_data/schema/schema_30.k +++ /dev/null @@ -1,4 +0,0 @@ -id = 1 - -rule str: - id > 0 diff --git a/test/test_units/test_kclvm/test_types/invalid_test_data/schema/schema_31.k b/test/test_units/test_kclvm/test_types/invalid_test_data/schema/schema_31.k deleted file mode 100644 index 0b6537a84..000000000 --- a/test/test_units/test_kclvm/test_types/invalid_test_data/schema/schema_31.k +++ /dev/null @@ -1,3 +0,0 @@ -schema Data: - a = 1 - a = "1" diff --git a/test/test_units/test_kclvm/test_types/invalid_test_data/schema/schema_32.k b/test/test_units/test_kclvm/test_types/invalid_test_data/schema/schema_32.k deleted file mode 100644 index ea52735fd..000000000 --- a/test/test_units/test_kclvm/test_types/invalid_test_data/schema/schema_32.k +++ /dev/null @@ -1,8 +0,0 @@ -schema Person: - name: str = "kcl" - age: int = 1 - -schema Data: - x: Person = { - age = "123" - } diff --git a/test/test_units/test_kclvm/test_types/invalid_test_data/schema/schema_33.k b/test/test_units/test_kclvm/test_types/invalid_test_data/schema/schema_33.k deleted file mode 100644 index d7c59ea75..000000000 --- a/test/test_units/test_kclvm/test_types/invalid_test_data/schema/schema_33.k +++ /dev/null @@ -1,7 +0,0 @@ -schema Person: - name: str = "kcl" - age: int = 1 - -x: Person = { - age = "123" -} diff --git a/test/test_units/test_kclvm/test_types/invalid_test_data/schema/schema_34.k b/test/test_units/test_kclvm/test_types/invalid_test_data/schema/schema_34.k deleted file mode 100644 index 62abcac8c..000000000 --- a/test/test_units/test_kclvm/test_types/invalid_test_data/schema/schema_34.k +++ /dev/null @@ -1,11 +0,0 @@ -schema Base: - name: str - -schema Person(Base): - name?: str - age?: int - -person = Person { - name: "Alice" - age: 18 -} diff --git a/test/test_units/test_kclvm/test_types/invalid_test_data/schema/schema_35.k b/test/test_units/test_kclvm/test_types/invalid_test_data/schema/schema_35.k deleted file mode 100644 index db7cfa2dc..000000000 --- a/test/test_units/test_kclvm/test_types/invalid_test_data/schema/schema_35.k +++ /dev/null @@ -1,2 +0,0 @@ -schema Data: - [int]: int diff --git a/test/test_units/test_kclvm/test_types/invalid_test_data/schema/schema_4.k b/test/test_units/test_kclvm/test_types/invalid_test_data/schema/schema_4.k deleted file mode 100644 index 0da6d0d5d..000000000 --- a/test/test_units/test_kclvm/test_types/invalid_test_data/schema/schema_4.k +++ /dev/null @@ -1,4 +0,0 @@ -import pkg - -schema Data(err_pkg.Person): - name: str diff --git a/test/test_units/test_kclvm/test_types/invalid_test_data/schema/schema_5.k b/test/test_units/test_kclvm/test_types/invalid_test_data/schema/schema_5.k deleted file mode 100644 index b842cac00..000000000 --- a/test/test_units/test_kclvm/test_types/invalid_test_data/schema/schema_5.k +++ /dev/null @@ -1,4 +0,0 @@ -import pkg - -schema Data(pkg.Base): - name: str diff --git a/test/test_units/test_kclvm/test_types/invalid_test_data/schema/schema_6.k b/test/test_units/test_kclvm/test_types/invalid_test_data/schema/schema_6.k deleted file mode 100644 index 3d64f8883..000000000 --- a/test/test_units/test_kclvm/test_types/invalid_test_data/schema/schema_6.k +++ /dev/null @@ -1,5 +0,0 @@ -schema DataMixin: - name: str - -schema Data(DataMixin): - name: str diff --git a/test/test_units/test_kclvm/test_types/invalid_test_data/schema/schema_7.k b/test/test_units/test_kclvm/test_types/invalid_test_data/schema/schema_7.k deleted file mode 100644 index a62ce95e2..000000000 --- a/test/test_units/test_kclvm/test_types/invalid_test_data/schema/schema_7.k +++ /dev/null @@ -1,10 +0,0 @@ -import pkg - -schema DataMixin: - name: str - -schema Data: - mixin [ - pkg.PersonMixin, - DataMixinError - ] diff --git a/test/test_units/test_kclvm/test_types/invalid_test_data/schema/schema_8.k b/test/test_units/test_kclvm/test_types/invalid_test_data/schema/schema_8.k deleted file mode 100644 index e57d4f1c5..000000000 --- a/test/test_units/test_kclvm/test_types/invalid_test_data/schema/schema_8.k +++ /dev/null @@ -1,3 +0,0 @@ -schema Data: - name: str - name: int diff --git a/test/test_units/test_kclvm/test_types/invalid_test_data/schema/schema_9.k b/test/test_units/test_kclvm/test_types/invalid_test_data/schema/schema_9.k deleted file mode 100644 index 17451d18d..000000000 --- a/test/test_units/test_kclvm/test_types/invalid_test_data/schema/schema_9.k +++ /dev/null @@ -1,3 +0,0 @@ -schema Data: - [name: str]: int - name: int diff --git a/test/test_units/test_kclvm/test_types/invalid_test_data/select_attr/select_attr_1.k b/test/test_units/test_kclvm/test_types/invalid_test_data/select_attr/select_attr_1.k deleted file mode 100644 index 7b3e58dbb..000000000 --- a/test/test_units/test_kclvm/test_types/invalid_test_data/select_attr/select_attr_1.k +++ /dev/null @@ -1 +0,0 @@ -name = "Alice".err_upper() \ No newline at end of file diff --git a/test/test_units/test_kclvm/test_types/invalid_test_data/select_attr/select_attr_2.k b/test/test_units/test_kclvm/test_types/invalid_test_data/select_attr/select_attr_2.k deleted file mode 100644 index bbf2c74a4..000000000 --- a/test/test_units/test_kclvm/test_types/invalid_test_data/select_attr/select_attr_2.k +++ /dev/null @@ -1,9 +0,0 @@ -schema Person: - name: str - age: int - -person = Person { - name: "Alice" - age: 18 -} -age = person.err_age diff --git a/test/test_units/test_kclvm/test_types/invalid_test_data/subscript/subscript_0.k b/test/test_units/test_kclvm/test_types/invalid_test_data/subscript/subscript_0.k deleted file mode 100644 index 96366b60a..000000000 --- a/test/test_units/test_kclvm/test_types/invalid_test_data/subscript/subscript_0.k +++ /dev/null @@ -1,2 +0,0 @@ -dataList = [1, 2, 3] -dataList0: int = dataList["1"] diff --git a/test/test_units/test_kclvm/test_types/invalid_test_data/subscript/subscript_1.k b/test/test_units/test_kclvm/test_types/invalid_test_data/subscript/subscript_1.k deleted file mode 100644 index 0ca79e770..000000000 --- a/test/test_units/test_kclvm/test_types/invalid_test_data/subscript/subscript_1.k +++ /dev/null @@ -1,3 +0,0 @@ -dataDict = {key: "value"} -keyType = [1] -dataKeyValue: str = dataDict[keyType] diff --git a/test/test_units/test_kclvm/test_types/invalid_test_data/subscript/subscript_2.k b/test/test_units/test_kclvm/test_types/invalid_test_data/subscript/subscript_2.k deleted file mode 100644 index 3fbe05562..000000000 --- a/test/test_units/test_kclvm/test_types/invalid_test_data/subscript/subscript_2.k +++ /dev/null @@ -1 +0,0 @@ -data = 1[0] diff --git a/test/test_units/test_kclvm/test_types/invalid_test_data/type_alias/pkg/pkg1.k b/test/test_units/test_kclvm/test_types/invalid_test_data/type_alias/pkg/pkg1.k deleted file mode 100644 index b4c3153b0..000000000 --- a/test/test_units/test_kclvm/test_types/invalid_test_data/type_alias/pkg/pkg1.k +++ /dev/null @@ -1,3 +0,0 @@ -schema Person: - name: str - age: int diff --git a/test/test_units/test_kclvm/test_types/invalid_test_data/type_alias/pkg/pkg2.k b/test/test_units/test_kclvm/test_types/invalid_test_data/type_alias/pkg/pkg2.k deleted file mode 100644 index 4b875356f..000000000 --- a/test/test_units/test_kclvm/test_types/invalid_test_data/type_alias/pkg/pkg2.k +++ /dev/null @@ -1,9 +0,0 @@ -schema Data: - person: Person - -data = Data { - person: Person { - name = "Alice" - age = 18 - } -} diff --git a/test/test_units/test_kclvm/test_types/invalid_test_data/type_alias/type_alias_0.k b/test/test_units/test_kclvm/test_types/invalid_test_data/type_alias/type_alias_0.k deleted file mode 100644 index 868488628..000000000 --- a/test/test_units/test_kclvm/test_types/invalid_test_data/type_alias/type_alias_0.k +++ /dev/null @@ -1,5 +0,0 @@ -import pkg - -type Person = pkg.Person - -data: int = pkg.data diff --git a/test/test_units/test_kclvm/test_types/invalid_test_data/type_alias/type_alias_1.k b/test/test_units/test_kclvm/test_types/invalid_test_data/type_alias/type_alias_1.k deleted file mode 100644 index f1e3ecb8c..000000000 --- a/test/test_units/test_kclvm/test_types/invalid_test_data/type_alias/type_alias_1.k +++ /dev/null @@ -1 +0,0 @@ -x: Int = 1.0 diff --git a/test/test_units/test_kclvm/test_types/invalid_test_data/type_alias/type_alias_2.k b/test/test_units/test_kclvm/test_types/invalid_test_data/type_alias/type_alias_2.k deleted file mode 100644 index dd9d9cdcb..000000000 --- a/test/test_units/test_kclvm/test_types/invalid_test_data/type_alias/type_alias_2.k +++ /dev/null @@ -1 +0,0 @@ -type int = str diff --git a/test/test_units/test_kclvm/test_types/invalid_test_data/type_annotation/type_annotation_0.k b/test/test_units/test_kclvm/test_types/invalid_test_data/type_annotation/type_annotation_0.k deleted file mode 100644 index 21c6db817..000000000 --- a/test/test_units/test_kclvm/test_types/invalid_test_data/type_annotation/type_annotation_0.k +++ /dev/null @@ -1 +0,0 @@ -a: int = "s" diff --git a/test/test_units/test_kclvm/test_types/invalid_test_data/type_annotation/type_annotation_1.k b/test/test_units/test_kclvm/test_types/invalid_test_data/type_annotation/type_annotation_1.k deleted file mode 100644 index 1cd4be8ad..000000000 --- a/test/test_units/test_kclvm/test_types/invalid_test_data/type_annotation/type_annotation_1.k +++ /dev/null @@ -1 +0,0 @@ -a: str = 1 diff --git a/test/test_units/test_kclvm/test_types/invalid_test_data/type_annotation/type_annotation_2.k b/test/test_units/test_kclvm/test_types/invalid_test_data/type_annotation/type_annotation_2.k deleted file mode 100644 index 7d71b1d77..000000000 --- a/test/test_units/test_kclvm/test_types/invalid_test_data/type_annotation/type_annotation_2.k +++ /dev/null @@ -1,10 +0,0 @@ -schema Data: - id?: int - -schema Person: - data: Data - name: a = 1 - -a: int = 1 - -person = Person {} diff --git a/test/test_units/test_kclvm/test_types/invalid_test_data/type_annotation/type_annotation_3.k b/test/test_units/test_kclvm/test_types/invalid_test_data/type_annotation/type_annotation_3.k deleted file mode 100644 index c4e485afd..000000000 --- a/test/test_units/test_kclvm/test_types/invalid_test_data/type_annotation/type_annotation_3.k +++ /dev/null @@ -1,3 +0,0 @@ -_a: str = 1 -_a = "123" -a = _a diff --git a/test/test_units/test_kclvm/test_types/invalid_test_data/type_annotation/type_annotation_4.k b/test/test_units/test_kclvm/test_types/invalid_test_data/type_annotation/type_annotation_4.k deleted file mode 100644 index 16d29cdfd..000000000 --- a/test/test_units/test_kclvm/test_types/invalid_test_data/type_annotation/type_annotation_4.k +++ /dev/null @@ -1,2 +0,0 @@ -_a: str = 1 -a = _a diff --git a/test/test_units/test_kclvm/test_types/invalid_test_data/type_annotation/type_annotation_5.k b/test/test_units/test_kclvm/test_types/invalid_test_data/type_annotation/type_annotation_5.k deleted file mode 100644 index feafc7489..000000000 --- a/test/test_units/test_kclvm/test_types/invalid_test_data/type_annotation/type_annotation_5.k +++ /dev/null @@ -1,2 +0,0 @@ -_a: str = "1" -_a: int = 1 diff --git a/test/test_units/test_kclvm/test_types/invalid_test_data/type_annotation/type_annotation_6.k b/test/test_units/test_kclvm/test_types/invalid_test_data/type_annotation/type_annotation_6.k deleted file mode 100644 index d6aad8c25..000000000 --- a/test/test_units/test_kclvm/test_types/invalid_test_data/type_annotation/type_annotation_6.k +++ /dev/null @@ -1,2 +0,0 @@ -a: str = "1" -b: int = a as int diff --git a/test/test_units/test_kclvm/test_types/invalid_test_data/type_annotation/type_annotation_7.k b/test/test_units/test_kclvm/test_types/invalid_test_data/type_annotation/type_annotation_7.k deleted file mode 100644 index fd484e0d5..000000000 --- a/test/test_units/test_kclvm/test_types/invalid_test_data/type_annotation/type_annotation_7.k +++ /dev/null @@ -1,2 +0,0 @@ -a: str = "1" -b: int = "1" as a[0] diff --git a/test/test_units/test_kclvm/test_types/invalid_test_data/type_annotation/type_annotation_8.k b/test/test_units/test_kclvm/test_types/invalid_test_data/type_annotation/type_annotation_8.k deleted file mode 100644 index 6336306f0..000000000 --- a/test/test_units/test_kclvm/test_types/invalid_test_data/type_annotation/type_annotation_8.k +++ /dev/null @@ -1,2 +0,0 @@ -a: str = "1" -b: int = "1" as a diff --git a/test/test_units/test_kclvm/test_types/invalid_test_data/type_as/pkg/pkg1.k b/test/test_units/test_kclvm/test_types/invalid_test_data/type_as/pkg/pkg1.k deleted file mode 100644 index b4c3153b0..000000000 --- a/test/test_units/test_kclvm/test_types/invalid_test_data/type_as/pkg/pkg1.k +++ /dev/null @@ -1,3 +0,0 @@ -schema Person: - name: str - age: int diff --git a/test/test_units/test_kclvm/test_types/invalid_test_data/type_as/pkg/pkg2.k b/test/test_units/test_kclvm/test_types/invalid_test_data/type_as/pkg/pkg2.k deleted file mode 100644 index c22670caf..000000000 --- a/test/test_units/test_kclvm/test_types/invalid_test_data/type_as/pkg/pkg2.k +++ /dev/null @@ -1,9 +0,0 @@ -schema Data: - person: Person - -data = Data { - person: Person { - name = "Alice" - age = 18 - } as Person -} diff --git a/test/test_units/test_kclvm/test_types/invalid_test_data/type_as/type_as_0.k b/test/test_units/test_kclvm/test_types/invalid_test_data/type_as/type_as_0.k deleted file mode 100644 index a282f9e38..000000000 --- a/test/test_units/test_kclvm/test_types/invalid_test_data/type_as/type_as_0.k +++ /dev/null @@ -1,3 +0,0 @@ -import pkg - -data: int = pkg.data as float diff --git a/test/test_units/test_kclvm/test_types/invalid_test_data/type_as/type_as_1.k b/test/test_units/test_kclvm/test_types/invalid_test_data/type_as/type_as_1.k deleted file mode 100644 index b15c20e31..000000000 --- a/test/test_units/test_kclvm/test_types/invalid_test_data/type_as/type_as_1.k +++ /dev/null @@ -1 +0,0 @@ -x = 1.0 as Int diff --git a/test/test_units/test_kclvm/test_types/invalid_test_data/unification/unification.k b/test/test_units/test_kclvm/test_types/invalid_test_data/unification/unification.k deleted file mode 100644 index 43a88e7f1..000000000 --- a/test/test_units/test_kclvm/test_types/invalid_test_data/unification/unification.k +++ /dev/null @@ -1,8 +0,0 @@ -schema Config: - name: str - id?: int - -config.name: Config { - name: "config" - id: 1 -} diff --git a/test/test_units/test_kclvm/test_types/invalid_test_data/unique/unique_1.k b/test/test_units/test_kclvm/test_types/invalid_test_data/unique/unique_1.k deleted file mode 100644 index 20e49fa50..000000000 --- a/test/test_units/test_kclvm/test_types/invalid_test_data/unique/unique_1.k +++ /dev/null @@ -1,2 +0,0 @@ -a = 1 -a = 2 \ No newline at end of file diff --git a/test/test_units/test_kclvm/test_types/invalid_test_data/unique/unique_2.k b/test/test_units/test_kclvm/test_types/invalid_test_data/unique/unique_2.k deleted file mode 100644 index 30ba79261..000000000 --- a/test/test_units/test_kclvm/test_types/invalid_test_data/unique/unique_2.k +++ /dev/null @@ -1,4 +0,0 @@ -schema Person: - name: str - -Person = 1 diff --git a/test/test_units/test_kclvm/test_types/invalid_test_data/unique/unique_3.k b/test/test_units/test_kclvm/test_types/invalid_test_data/unique/unique_3.k deleted file mode 100644 index 5e72165dd..000000000 --- a/test/test_units/test_kclvm/test_types/invalid_test_data/unique/unique_3.k +++ /dev/null @@ -1,2 +0,0 @@ -_a: int = 1 -_a: str = "s" diff --git a/test/test_units/test_kclvm/test_types/invalid_test_data/unpack/unpack_0.k b/test/test_units/test_kclvm/test_types/invalid_test_data/unpack/unpack_0.k deleted file mode 100644 index 6e08a93d8..000000000 --- a/test/test_units/test_kclvm/test_types/invalid_test_data/unpack/unpack_0.k +++ /dev/null @@ -1,2 +0,0 @@ -a = 1 -b = [*a] diff --git a/test/test_units/test_kclvm/test_types/invalid_test_data/unpack/unpack_1.k b/test/test_units/test_kclvm/test_types/invalid_test_data/unpack/unpack_1.k deleted file mode 100644 index a95fc530b..000000000 --- a/test/test_units/test_kclvm/test_types/invalid_test_data/unpack/unpack_1.k +++ /dev/null @@ -1 +0,0 @@ -a = [*1] diff --git a/test/test_units/test_kclvm/test_types/invalid_test_data/unpack/unpack_2.k b/test/test_units/test_kclvm/test_types/invalid_test_data/unpack/unpack_2.k deleted file mode 100644 index 97798e94d..000000000 --- a/test/test_units/test_kclvm/test_types/invalid_test_data/unpack/unpack_2.k +++ /dev/null @@ -1,10 +0,0 @@ -schema Person: - name?: str - -data: {str:str} | Person = {name: "Alice"} -a = { - if True: **None - elif False: **data - else: **{} -} -b = {if True: **1} diff --git a/test/test_units/test_kclvm/test_types/normal_test_data/assert.k b/test/test_units/test_kclvm/test_types/normal_test_data/assert.k deleted file mode 100644 index 7b997c1e5..000000000 --- a/test/test_units/test_kclvm/test_types/normal_test_data/assert.k +++ /dev/null @@ -1,2 +0,0 @@ -assert True -assert False, "message" diff --git a/test/test_units/test_kclvm/test_types/normal_test_data/builtin.k b/test/test_units/test_kclvm/test_types/normal_test_data/builtin.k deleted file mode 100644 index 6ec348c55..000000000 --- a/test/test_units/test_kclvm/test_types/normal_test_data/builtin.k +++ /dev/null @@ -1,17 +0,0 @@ -import math -import net - - -schema Person: - name: str - age: int - -a: any = math.log(10) -b: any = 1 + 2 -c: any = net.is_IP("192.168.0.1") -d: str = ".".replace(".", "") -e: bool = "A".isupper() -f: [] = Person.instances() -g: any = 1.1 -h: int = int(1.1) -i: float = float(1.1) diff --git a/test/test_units/test_kclvm/test_types/normal_test_data/calculation.k b/test/test_units/test_kclvm/test_types/normal_test_data/calculation.k deleted file mode 100644 index 96e1465fc..000000000 --- a/test/test_units/test_kclvm/test_types/normal_test_data/calculation.k +++ /dev/null @@ -1,290 +0,0 @@ -schema Data: - [str]: str - name: str - -# 1. Binary Operator -# Add -add_a = 1 + 1 -add_b = 1 + 1.1 -add_c = 1.1 + 1.1 -add_d = 1.1 + 1 -add_e = True + 1 -add_f = 1 + False -add_g = "s" + "s" -add_h = [0] + [1] -add_i = 1 + add_b -add_j = add_c + 1 -add_k = add_e + add_f -add_l = 1 + 1 + 1 -add_m = 1 + 1.1 + 1 -add_n = 1.1 + True + 1 + 1.0 -# Sub -sub_a = 1 - 1 -sub_b = 1 - 1.1 -sub_c = 1.1 - 1.1 -sub_d = 1.1 - 1 -sub_e = True - 1 -sub_f = 1 - False -sub_g = 0 - 0.0 -sub_h = True - False -sub_i = 1 - sub_b -sub_j = sub_c - 1 -sub_k = sub_e - sub_f -sub_l = 1 - 1 - 1 -sub_m = 1 - 1.1 - 1 -sub_n = 1.1 - True - 1 - 1.0 -# Mul -mul_a = 1 * 1 -mul_b = 1 * 1.1 -mul_c = 1.1 * 1.1 -mul_d = 1.1 * 1 -mul_e = True * 1 -mul_f = 1 * False -mul_g = "s" * 2 + 2 * "s" -mul_h = 2 * [0] + [0] * 2 -mul_i = 1 * mul_b -mul_j = mul_c * 1 -mul_k = mul_e * mul_f -mul_l = 1 * 1 * 1 -mul_m = 1 * 1.1 * 1 -mul_n = 1.1 * True * 1 * 1.0 -mul_o = (1 if mul_n else "1") * 2 -# Div -div_a = 1 / 1 -div_b = 1 / 1.1 -div_c = 1.1 / 1.1 -div_d = 1.1 / 1 -div_e = False / 1 -div_f = 1 / True -div_g = False / True / 1.0 -div_h = 1.0 / 1 / True / True -div_i = 1 / div_b -div_j = div_c / 1 -div_k = div_e / div_f -div_l = 1 / 1 / 1 -div_m = 1 / 1.1 / 1 -div_n = 1.1 / True / 1 / 1.0 -# FloorDiv -floor_div_a = 1 // 1 -floor_div_b = 1 // 1.1 -floor_div_c = 1.1 // 1.1 -floor_div_d = 1.1 // 1 -floor_div_e = False // 1 -floor_div_f = 1 // True -floor_div_g = False // True // 1.0 -floor_div_h = 1.0 // 1 // True // True -floor_div_i = 1 // floor_div_b -floor_div_j = floor_div_c // 1 -floor_div_k = floor_div_e // floor_div_f -floor_div_l = 1 // 1 // 1 -floor_div_m = 1 // 1.1 // 1 -floor_div_n = 1.1 // True // 1 // 1.0 -# Mod -mod_a = 1 % 1 -mod_b = 1 % 1.1 -mod_c = 1.1 % 1.1 -mod_d = 1.1 % 1 -mod_e = False % 1 -mod_f = 1 % True -mod_g = False % True % 1.0 -mod_h = 1.0 % 1 % True % True -mod_i = 1 % mod_b -mod_j = mod_c % 1 -mod_k = mod_e % mod_f -mod_l = 1 % 1 % 1 -mod_m = 1 % 1.1 % 1 -mod_n = 1.1 % True % 1 % 1.0 -# Pow -pow_a = 1 ** 1 -pow_b = 1 ** 1.1 -pow_c = 1.1 ** 1.1 -pow_d = 1.1 ** 1 -pow_e = False ** 1 -pow_f = 1 ** True -pow_g = False ** True ** 1.0 -pow_h = 1.0 ** 1 ** True ** True -pow_i = 1 ** pow_b -pow_j = pow_c ** 1 -pow_k = pow_e ** pow_f -pow_l = 1 ** 1 ** 1 -pow_m = 1 ** 1.1 ** 1 -pow_n = 1.1 ** True ** 1 ** 1.0 -# LShift -lshift_a = 1 >> 0 -lshift_b = 0 >> 1 -lshift_c = 2 >> 2 -lshift_d = 2 >> 1 -lshift_e = 1 >> 2 -# RShift -rshift_a = 1 << 0 -rshift_b = 0 << 1 -rshift_c = 2 << 2 -rshift_d = 2 << 1 -rshift_e = 1 << 2 -# BitOr -bitor_a = 1 | 2 -bitor_b = 2 | 3 -bitor_c = 0xAb | 0xbA -bitor_d = [] | [] -bitor_e = {} | {} -bitor_f = [1] | [2] -bitor_g = {key: "value1"} | {key: "value2"} -bitor_h = bitor_e | bitor_g -bitor_i = bitor_e | None -bitor_j = bitor_f | None -bitor_k = None | {key: "value2"} -bitor_l = Data {name: "v"} | {name: "v"} -bitor_m = Data {name: "v"} | Data {name: "v"} -# BitXOr -bitxor_a = 1 ^ 2 -bitxor_b = 2 ^ 3 -bitxor_c = 0xAb ^ 0xbA -bitxor_d = bitxor_a & 0xFF -bitxor_e = 0xFF & bitxor_b -bitxor_f = bitxor_c & bitxor_d -# BitAdd -bitand_a = 1 & 2 -bitand_b = 2 & 3 -bitand_c = 0xAb & 0xbA -bitand_d = bitand_a & 0xFF -bitand_e = 0xFF & bitand_b -bitand_f = bitand_c & bitand_d -# And -logicand_a = 1 and 2 -logicand_b = "" and 2 -logicand_c = None and 2.0 and "" and Undefined -logicand_d = logicand_a == 1 and 2.0 and "" -logicand_e = logicand_b and False and {} and [] -# Or -logicor_a = 1 or 2 -logicor_b = "" or 2 -logicor_c = None or 2.0 or "" or Undefined -logicor_d = logicor_a == 1 or 2.0 or "" -logicor_e = logicor_b or False or {} and [] -# 2. Compare Operator -# Eq -compare_eq_a = 1 == 1 -compare_eq_b = 1 == 1.0 -compare_eq_c = 1.0 == 1 -compare_eq_d = True == False -compare_eq_e = None == False -compare_eq_f = None == Undefined -# NotEq -compare_not_eq_a = 1 == 1 -compare_not_eq_b = 1 == 1.0 -compare_not_eq_c = 1.0 == 1 -compare_not_eq_d = True == False -compare_not_eq_e = None == False -compare_not_eq_f = None == Undefined -compare_not_eq_g = [] == [] -compare_not_eq_h = {} == {} -compare_not_eq_i = "" == "" -compare_not_eq_j = compare_not_eq_h == True -# Lt -compare_lt_a = 1 < 2 -compare_lt_b = 1 < 2.0 -compare_lt_c = 1.0 < 2 -compare_lt_d = 1.0 < 2.0 -compare_lt_e = compare_lt_a < compare_lt_d -compare_lt_f = "s" < "ss" -compare_lt_g = [1] < [2] -# LtE -compare_lte_a = 1 <= 2 -compare_lte_b = 1 <= 2.0 -compare_lte_c = 1.0 <= 2 -compare_lte_d = 1.0 <= 2.0 -compare_lte_e = compare_lte_a <= compare_lte_d -compare_lte_f = "s" <= "ss" -compare_lte_g = [1] <= [2] -# Gt -compare_gt_a = 1 > 2 -compare_gt_b = 1 > 2.0 -compare_gt_c = 1.0 > 2 -compare_gt_d = 1.0 > 2.0 -compare_gt_e = compare_gt_a > compare_gt_d -compare_gt_f = "s" > "ss" -compare_gt_g = [1] > [2] -# GtE -compare_gte_a = 1 >= 2 -compare_gte_b = 1 >= 2.0 -compare_gte_c = 1.0 >= 2 -compare_gte_d = 1.0 >= 2.0 -compare_gte_e = compare_gte_a >= compare_gte_d -compare_gte_f = "s" >= "ss" -compare_gte_g = [1] >= [2] -# Is -compare_is_a = 1 is 2 -compare_is_b = 1 is 2.0 -compare_is_c = 1.0 is 2 -compare_is_d = 1.0 is 2.0 -compare_is_e = compare_is_a is compare_is_d -compare_is_f = "s" is "ss" -compare_is_g = [1] is [2] -compare_is_h = compare_is_g is True -compare_is_i = None is None -compare_is_j = True is False -compare_is_k = compare_is_f is Undefined -# In -compare_in_a = 1 in [2] -compare_in_b = "key" in {} -compare_in_c = "s" in "ss" -compare_in_d = compare_in_a in [True] -compare_in_e = compare_in_d in {} -# Not -compare_not_a = 1 not 2 -compare_not_b = 1 not 2.0 -compare_not_c = 1.0 not 2 -compare_not_d = 1.0 not 2.0 -compare_not_e = compare_not_a not compare_not_d -compare_not_f = "s" not "ss" -compare_not_g = [1] not [2] -compare_not_h = compare_not_g not True -compare_not_i = None not None -compare_not_j = True not False -compare_not_k = compare_not_f not Undefined -# IsNot -compare_is_not_a = 1 is not 2 -compare_is_not_b = 1 is not 2.0 -compare_is_not_c = 1.0 is not 2 -compare_is_not_d = 1.0 is not 2.0 -compare_is_not_e = compare_is_not_a is not compare_is_not_d -compare_is_not_f = "s" is not "ss" -compare_is_not_g = [1] is not [2] -compare_is_not_h = compare_is_not_g is not True -compare_is_not_i = None is not None -compare_is_not_j = True is not False -compare_is_not_k = compare_is_not_f is not Undefined -# NotIn -compare_not_in_a = 1 not in [2] -compare_not_in_b = "key" not in {} -compare_not_in_c = "s" not in "ss" -compare_not_in_d = compare_not_in_a not in [True] -compare_not_in_e = compare_not_in_d not in {} -# 3. Unary Operator -# UAdd -unary_add_a = +1 -unary_add_b = +1.0 -unary_add_c = +True -unart_add_d = None -unart_add_e = +unart_add_d -# USub -unary_sub_a = -1 -unary_sub_b = -1.0 -unary_sub_c = -True -unart_sub_d = None -unart_sub_e = -unart_sub_d -# Invert -unary_invert_a = ~1 -unary_invert_b = ~True -unary_invert_c = ~False -unart_invert_d = None -unart_invert_e = ~unart_invert_d -# Not -unary_not_a = not 1 -unary_not_b = not 1.0 -unary_not_c = not "" -unary_not_d = not False -unary_not_e = not [] -unary_not_f = not {} -unary_not_g = not None -unary_not_h = not Undefined diff --git a/test/test_units/test_kclvm/test_types/normal_test_data/config_op.k b/test/test_units/test_kclvm/test_types/normal_test_data/config_op.k deleted file mode 100644 index 6f619a7af..000000000 --- a/test/test_units/test_kclvm/test_types/normal_test_data/config_op.k +++ /dev/null @@ -1,20 +0,0 @@ -schema Person: - [str]: any - name: str = "Alice" - age: int = 10 - data: [int] = [1, 2, 3] - labels: {str:} - -name = "" -age = 1 -person = Person { - name: name - age: age - "1": 1 - data[0] += 1 - data[1] = 1 - data += [2] - "temp": "temp" - labels.key1: 1 - labels.key2: "1" -} diff --git a/test/test_units/test_kclvm/test_types/normal_test_data/dict.k b/test/test_units/test_kclvm/test_types/normal_test_data/dict.k deleted file mode 100644 index e50864113..000000000 --- a/test/test_units/test_kclvm/test_types/normal_test_data/dict.k +++ /dev/null @@ -1,9 +0,0 @@ -data: {str:str} = { - key1: "value1" - key2: "value2" - if True: key3: "value3" - if True: "key4": "value4" -} -dataNew = data { - key5 = "value5" -} diff --git a/test/test_units/test_kclvm/test_types/normal_test_data/dict_assign_to_schema.k b/test/test_units/test_kclvm/test_types/normal_test_data/dict_assign_to_schema.k deleted file mode 100644 index bf667a575..000000000 --- a/test/test_units/test_kclvm/test_types/normal_test_data/dict_assign_to_schema.k +++ /dev/null @@ -1,34 +0,0 @@ -# Dict to schema test -schema Person: - name: str - age: int - -data0: {str:str} = {name: "Alice"} -data1: {str:int} = {age: 18} -data2: {:} = {} -data3: {any:any} = {} -data4: any = {} - -person0 = Person {**data0} -person1 = Person {**data1} -person2 = Person {**data2} -person3 = Person {**data3} -person4 = Person {**data4} - -schema KeyVal: - labels?: {str:} - -schema Data: - keyVals?: KeyVal - -# Dict to schema in schema test -data = Data { - keyVals: { - labels.key: 456 - } - keyVals.labels.key2: 789 -} - -# Any dict to schema -personData: any = {name: "Alice", age: 18} -person: Person = personData diff --git a/test/test_units/test_kclvm/test_types/normal_test_data/final.k b/test/test_units/test_kclvm/test_types/normal_test_data/final.k deleted file mode 100644 index bd1ab30f9..000000000 --- a/test/test_units/test_kclvm/test_types/normal_test_data/final.k +++ /dev/null @@ -1,51 +0,0 @@ -schema Name: - name: str = "Kiki" - age: int = 10 - -schema Name0: - name0: Name - -schema Name1: - name1: Name0 - -schema Name2: - name2: Name1 - -schema Name3: - name3: Name2 - -schema Name4: - name4: Name3 - -schema Name5: - name5: Name4 - -schema Name6: - name6: Name5 - -schema Name7: - name7: Name6 - -schema Person: - name: Name7 - -John = Person{ - name.name7.name6:{ - name5: Name4{ - name4:{ - name3: Name2{ - if True: name2.name1: { - name0:{ - age = 11 - } - } - elif False: name2.name1: { - name0:{ - age = 12 - } - } - } - } - } - } -} diff --git a/test/test_units/test_kclvm/test_types/normal_test_data/if_expr.k b/test/test_units/test_kclvm/test_types/normal_test_data/if_expr.k deleted file mode 100644 index 0c8a5f597..000000000 --- a/test/test_units/test_kclvm/test_types/normal_test_data/if_expr.k +++ /dev/null @@ -1,6 +0,0 @@ -a = 1 if True else "ss" -b = "1" if a else 1 -c = 1 + 2 if True else 3 -d: int|str = 1 -e: bool = d == "s" -f: [int] = [1, 2] + ([3, 4] + [5, 6] if True else [7, 8]) diff --git a/test/test_units/test_kclvm/test_types/normal_test_data/if_item.k b/test/test_units/test_kclvm/test_types/normal_test_data/if_item.k deleted file mode 100644 index f625f9423..000000000 --- a/test/test_units/test_kclvm/test_types/normal_test_data/if_item.k +++ /dev/null @@ -1,11 +0,0 @@ -data1 = { - if True: name: "Alice" - age: int -} -data2 = [ - if True: {key1: "value1"} - {key2: "value2"} -] -data3 = { - if True: key.key1.key2: "value" -} diff --git a/test/test_units/test_kclvm/test_types/normal_test_data/if_stmt.k b/test/test_units/test_kclvm/test_types/normal_test_data/if_stmt.k deleted file mode 100644 index a2a7f66a8..000000000 --- a/test/test_units/test_kclvm/test_types/normal_test_data/if_stmt.k +++ /dev/null @@ -1,7 +0,0 @@ -a = 1 -if a > 2: - _b = 1 -elif a > 1: - _b = 2 -else: - _b = 3 diff --git a/test/test_units/test_kclvm/test_types/normal_test_data/index_signature.k b/test/test_units/test_kclvm/test_types/normal_test_data/index_signature.k deleted file mode 100644 index 30032f733..000000000 --- a/test/test_units/test_kclvm/test_types/normal_test_data/index_signature.k +++ /dev/null @@ -1,10 +0,0 @@ -schema Data: - [name: str]: str - - check: - name.islower() - -data = Data { - key: "value" -} -value = data.key diff --git a/test/test_units/test_kclvm/test_types/normal_test_data/list.k b/test/test_units/test_kclvm/test_types/normal_test_data/list.k deleted file mode 100644 index 604ab8ba7..000000000 --- a/test/test_units/test_kclvm/test_types/normal_test_data/list.k +++ /dev/null @@ -1,6 +0,0 @@ -data: [str] = [ - "value1" - "value2" - if True: "value3" - if True: "value4" -] diff --git a/test/test_units/test_kclvm/test_types/normal_test_data/loop.k b/test/test_units/test_kclvm/test_types/normal_test_data/loop.k deleted file mode 100644 index 3f8099889..000000000 --- a/test/test_units/test_kclvm/test_types/normal_test_data/loop.k +++ /dev/null @@ -1,17 +0,0 @@ -str0 = [str(i) + ": " + c.upper() for i, c in "apple"] -str1 = [c.upper() for c in "apple"] -str2 = {str(i): c.upper() for i, c in "apple"} -str3 = {c: c.upper() for c in "apple"} - -list0 = [str(i) + ": " + c.upper() for i, c in ["a", "p", "p"]] -list1 = [c.upper() for c in ["a", "p", "p"]] -list2 = {str(i): c.upper() for i, c in ["a", "p", "p"]} -list3 = {c: c.upper() for c in ["a", "p", "p"]} - -dict0 = [str(k) + ": " + v.upper() for k, v in {"a": "A", "p": "P"}] -dict1 = [c.upper() for c in {"a": "A", "p": "P"}] -dict2 = {str(k): v.upper() for k, v in {"a": "A", "p": "P"}} -dict3 = {c: c.upper() for c in {"a": "A", "p": "P"}} - -listUnion0 = [i for i in [0] or ["1"]] -listUnion1 = [i for i in [0, "1"] or ["1", 0]] diff --git a/test/test_units/test_kclvm/test_types/normal_test_data/nest_var.k b/test/test_units/test_kclvm/test_types/normal_test_data/nest_var.k deleted file mode 100644 index 58e8c6e46..000000000 --- a/test/test_units/test_kclvm/test_types/normal_test_data/nest_var.k +++ /dev/null @@ -1,10 +0,0 @@ -schema Person: - name: str = "Alice" - -person = { - "name": "Alice" -} - -data = Person { - person["name"]: person["name"].upper() -} diff --git a/test/test_units/test_kclvm/test_types/normal_test_data/pkg/pkg.k b/test/test_units/test_kclvm/test_types/normal_test_data/pkg/pkg.k deleted file mode 100644 index 93d194a75..000000000 --- a/test/test_units/test_kclvm/test_types/normal_test_data/pkg/pkg.k +++ /dev/null @@ -1,6 +0,0 @@ -schema Person: - name: str - age: int - -rule PkgRule: - age < 10 diff --git a/test/test_units/test_kclvm/test_types/normal_test_data/protocol.k b/test/test_units/test_kclvm/test_types/normal_test_data/protocol.k deleted file mode 100644 index dabf99b66..000000000 --- a/test/test_units/test_kclvm/test_types/normal_test_data/protocol.k +++ /dev/null @@ -1,8 +0,0 @@ -schema DataProtocol: - a: int - -schema DataMixin for DataProtocol: - x: int = a - -schema Data: - mixin [DataMixin] diff --git a/test/test_units/test_kclvm/test_types/normal_test_data/quant.k b/test/test_units/test_kclvm/test_types/normal_test_data/quant.k deleted file mode 100644 index 1958307cd..000000000 --- a/test/test_units/test_kclvm/test_types/normal_test_data/quant.k +++ /dev/null @@ -1,27 +0,0 @@ -schema Person: - name: str = "Alice" - - check: - all c in name { - c.isupper() - } - -data0 = all i, c in "app" { - c.upper() if 1 > 1 -} -data1: bool = all i in [1, 2, 3] { - i if i > 2 -} -data2: bool = any i in [1, 2, 3] { - i if i > 2 -} -data3: [str] = map k, v in {key1: "value1", key2: "value2"} { - k + v -} -data4: [int] = filter i, elem in [1, 2, 3] { - i > 1 and elem > 2 -} -value = [0] or ["0"] -data5: bool = all v in value { - int(v) > 1 -} diff --git a/test/test_units/test_kclvm/test_types/normal_test_data/rule.k b/test/test_units/test_kclvm/test_types/normal_test_data/rule.k deleted file mode 100644 index 363bd85be..000000000 --- a/test/test_units/test_kclvm/test_types/normal_test_data/rule.k +++ /dev/null @@ -1,20 +0,0 @@ -import pkg - -age = 1 - -schema MainProtocol: - var: int - age: int - -schema MainMixin for MainProtocol: - var: int - -rule Base: - age > 0 - -rule Main[var, default=1](Base, pkg.PkgRule) for MainProtocol: - age < 10 - -Main(1) { - age = 1 -} diff --git a/test/test_units/test_kclvm/test_types/normal_test_data/schema.k b/test/test_units/test_kclvm/test_types/normal_test_data/schema.k deleted file mode 100644 index f3e0b2c10..000000000 --- a/test/test_units/test_kclvm/test_types/normal_test_data/schema.k +++ /dev/null @@ -1,18 +0,0 @@ -schema PersonMixin: - nameUpper: str = name.upper() - -schema Person: - mixin [PersonMixin] - _temp = 1 - _temp = 2 - name: str = "Alice" - age: int = 10 - -name = "Bob" -age = 10 -base = {name: "Alice", age: 10} -person = Person { - **base - name: name - age: age -} diff --git a/test/test_units/test_kclvm/test_types/normal_test_data/select_attr.k b/test/test_units/test_kclvm/test_types/normal_test_data/select_attr.k deleted file mode 100644 index fc6134693..000000000 --- a/test/test_units/test_kclvm/test_types/normal_test_data/select_attr.k +++ /dev/null @@ -1,18 +0,0 @@ -schema Person[nameVar: str]: - name: str = nameVar - age: int = 18 - -_person = Person("Alice") -_person.name = "Bob" - -data = { - key1: "value1" - key2: "value2" -} -schemaSelectAttr: int = _person.age -dictSelectAttr: str = data.key1 -strSelectAttr0: any = "abc".upper() -strSelectAttr1: any = strSelectAttr0.upper() - -unionData: {str:} | Person = Person("Bob") -unionDataAttr: int = unionData.age diff --git a/test/test_units/test_kclvm/test_types/normal_test_data/starred_expr.k b/test/test_units/test_kclvm/test_types/normal_test_data/starred_expr.k deleted file mode 100644 index 53af8c775..000000000 --- a/test/test_units/test_kclvm/test_types/normal_test_data/starred_expr.k +++ /dev/null @@ -1,14 +0,0 @@ -schema Person: - name: str - -a = [1, 2, 3] -b: [int] = [*a, 4, 5] -c = {key1: "value1"} -d: {str:str} = {**c, key2: "value2"} -e: [str] = [*d] -f: [any] = [*Undefined] -g: [any] = [*None] -h: {str:} = {**Undefined, key: "value"} -i: {str:} = {**None, key: "value"} -j: {str:} | Person = {name: "name"} -k: {str:} = {**j} diff --git a/test/test_units/test_kclvm/test_types/normal_test_data/subscript.k b/test/test_units/test_kclvm/test_types/normal_test_data/subscript.k deleted file mode 100644 index 635799ee9..000000000 --- a/test/test_units/test_kclvm/test_types/normal_test_data/subscript.k +++ /dev/null @@ -1,15 +0,0 @@ -dataList = [1, 2, 3] -dataList0: int = dataList[0] -dataListSlice: [int] = dataList[0:1:2] -dataDict = {key: "value"} -dataKeyValue: str = dataDict["key"] -dataStr: str = "apple" -dataStrSlice = dataStr[::-1] + "apple"[::-1] -keyAny: any = None -dataDictAny = dataDict[keyAny] - -# Literal subscript -literalSubscript0 = [1][0] -literalSubscript1 = [1, 2][0] -literalSubscript2 = {key: "value"}.key -literalSubscript3 = {key: "value"}.key1 diff --git a/test/test_units/test_kclvm/test_types/normal_test_data/type_alias.k b/test/test_units/test_kclvm/test_types/normal_test_data/type_alias.k deleted file mode 100644 index aed0d442a..000000000 --- a/test/test_units/test_kclvm/test_types/normal_test_data/type_alias.k +++ /dev/null @@ -1,21 +0,0 @@ -import pkg - -type Color = "Red" | "Yellow" | "Blue" -type Person = pkg.Person - -person: Person = Person { - name = "Alice" - age = 18 -} -color: Color = "Red" - -type Int = int -type FloatUnionInt = float | Int -type BoolUnionFloatUnionInt = bool | FloatUnionInt -type StringUnionBoolUnionFloatUnionInt = str | BoolUnionFloatUnionInt - -a: Int = 1 -b: FloatUnionInt = 2.0 -c: BoolUnionFloatUnionInt = True -d: StringUnionBoolUnionFloatUnionInt = "xx" - diff --git a/test/test_units/test_kclvm/test_types/normal_test_data/type_annotation.k b/test/test_units/test_kclvm/test_types/normal_test_data/type_annotation.k deleted file mode 100644 index c44d7e68f..000000000 --- a/test/test_units/test_kclvm/test_types/normal_test_data/type_annotation.k +++ /dev/null @@ -1,69 +0,0 @@ -"""Type annotation test""" - -import pkg -import math -import pkg - -schema PersonMixin: - nameUpper: str = name.upper() - -schema Person(Base): - # Mixin - mixin [PersonMixin] - # Index signature - [str]: int|str|{str:} - # Attributes - name: str = "Alice" - - _age: int = 18 - _age += 10 - labels: {str:} = {key1: "value1"} - lebels: {str:} |= {key2: "value2"} - # Check block - check: - _age > 0 - -@deprecated -schema Base(pkg.Person): - data?: str - -print("Hello type annotation check") - -a: int = 1 -b: float = 1.0 -c: float = 1 -d: bool = True -e: bool = False -f: bool = None -g: bool = Undefined -h: [str] = ["Red", "Yellow", "Blue"] -i: [] = ["Red", "Yellow", "Blue"] -j: ["Red"|"Yellow"|"Blue"] = ["Red", "Yellow", "Blue"] -k: [int|str] = [1, 2, "s", "ss"] -l: [{str:}] = [{key: "value"}, {key.key1.key2: "value"}] -m: {str:str|int} = {"key1": "value1", "key2": 2} -n: "Red"|"Yellow"|"Blue" = "Red" -o: Person = Person { - name: "Bob" - age: 10 -} -p: pkg.Person = pkg.Person { - name: "Alice" - age: 18 -} -q: Person = { - name: "Bob" - age: 18 -} -r: Base = Person { - name: "Bob" - age: 18 -} -s: any = 1 -t: any = "s" -u: any = (r + s) -v: str = p.name -w: int = q?.age -x: int|str = 1 if True else "s" -y: [int] = [i ** 2 for i in [1, 2, 3]] -z: {str:} = {"${k}": int(k) for k in ["1", "2", "3"]} diff --git a/test/test_units/test_kclvm/test_types/normal_test_data/type_as.k b/test/test_units/test_kclvm/test_types/normal_test_data/type_as.k deleted file mode 100644 index 75281b690..000000000 --- a/test/test_units/test_kclvm/test_types/normal_test_data/type_as.k +++ /dev/null @@ -1,7 +0,0 @@ -import pkg - -person: pkg.Person = pkg.Person { - name = "Alice" - age = 18 -} -personOther = person as pkg.Person diff --git a/test/test_units/test_kclvm/test_types/normal_test_data/type_dict.k b/test/test_units/test_kclvm/test_types/normal_test_data/type_dict.k deleted file mode 100644 index 63f97c404..000000000 --- a/test/test_units/test_kclvm/test_types/normal_test_data/type_dict.k +++ /dev/null @@ -1,22 +0,0 @@ -schema Name: - firstName: str - lastName: str - -schema Person: - name: Name - age: int - -schema Group: - persons: {str:Person} - -group = Group { - "persons": { - "1": { - "name": { - "firstName": "Alice", - "lastName": "Terry" - }, - "age": 12 - } - } -} diff --git a/test/test_units/test_kclvm/test_types/normal_test_data/unfication_stmt.k b/test/test_units/test_kclvm/test_types/normal_test_data/unfication_stmt.k deleted file mode 100644 index 3fbedf3d7..000000000 --- a/test/test_units/test_kclvm/test_types/normal_test_data/unfication_stmt.k +++ /dev/null @@ -1,8 +0,0 @@ -schema Config: - name: str - id?: int - -config: Config { - name: "config" - id: 1 -} diff --git a/test/test_units/test_kclvm/test_types/scope_test_data/inherit.k b/test/test_units/test_kclvm/test_types/scope_test_data/inherit.k deleted file mode 100644 index c2f4cc22e..000000000 --- a/test/test_units/test_kclvm/test_types/scope_test_data/inherit.k +++ /dev/null @@ -1,5 +0,0 @@ -schema Parent: - name: str - -schema Son(Parent): - age: int diff --git a/test/test_units/test_kclvm/test_types/scope_test_data/package.k b/test/test_units/test_kclvm/test_types/scope_test_data/package.k deleted file mode 100644 index a07b5340a..000000000 --- a/test/test_units/test_kclvm/test_types/scope_test_data/package.k +++ /dev/null @@ -1,12 +0,0 @@ -import scope_test_data.pkg as pkg1 -import scope_test_data.pkg.pkg as pkg2 - -person1 = pkg1.Person { - name: "Alice" - age: 18 -} - -person2 = pkg2.Person { - name: "Alice" - age: 18 -} diff --git a/test/test_units/test_kclvm/test_types/scope_test_data/pkg/pkg/test.k b/test/test_units/test_kclvm/test_types/scope_test_data/pkg/pkg/test.k deleted file mode 100644 index b4c3153b0..000000000 --- a/test/test_units/test_kclvm/test_types/scope_test_data/pkg/pkg/test.k +++ /dev/null @@ -1,3 +0,0 @@ -schema Person: - name: str - age: int diff --git a/test/test_units/test_kclvm/test_types/scope_test_data/pkg/test.k b/test/test_units/test_kclvm/test_types/scope_test_data/pkg/test.k deleted file mode 100644 index b4c3153b0..000000000 --- a/test/test_units/test_kclvm/test_types/scope_test_data/pkg/test.k +++ /dev/null @@ -1,3 +0,0 @@ -schema Person: - name: str - age: int diff --git a/test/test_units/test_kclvm/test_types/scope_test_data/schema.k b/test/test_units/test_kclvm/test_types/scope_test_data/schema.k deleted file mode 100644 index ed88216af..000000000 --- a/test/test_units/test_kclvm/test_types/scope_test_data/schema.k +++ /dev/null @@ -1,8 +0,0 @@ -schema Person: - name: str - age: int = 10 - -person: Person = Person { - name: "Alice" - age: 18 -} diff --git a/test/test_units/test_kclvm/test_types/scope_test_data/simple.k b/test/test_units/test_kclvm/test_types/scope_test_data/simple.k deleted file mode 100644 index ab88e0917..000000000 --- a/test/test_units/test_kclvm/test_types/scope_test_data/simple.k +++ /dev/null @@ -1,30 +0,0 @@ -schema Base: - id0: str = 'id-base' - id1: str - -schema Person[_name:str, id='id-person'](Base): - name: str = 'kcl' - age: int = 1 - x: 1 | "aaa" | True = 1 - -person = Person(_name="arg-name") { - name: 'Alice' -} - -none0 = Undefined -none1 = None -bool1 = True -bool2 = False -bool3: bool = None -s0 = 'abc' -s1: str = 'abc' -i0 = 123.3 -f0 = 1.5 -x0 = 1 + 1.5 -x1 = x0 + 1 -personOther: Person = Person {} -if person.name == 'Alice': - print("hello KCL") - -rule SomeRule: - x0 > 0 diff --git a/test/test_units/test_kclvm/test_types/test_scope.py b/test/test_units/test_kclvm/test_types/test_scope.py deleted file mode 100644 index 2190b4bcf..000000000 --- a/test/test_units/test_kclvm/test_types/test_scope.py +++ /dev/null @@ -1,43 +0,0 @@ -# Copyright 2021 The KCL Authors. All rights reserved. - -import unittest -import pathlib -import typing - -import kclvm.kcl.ast as ast -import kclvm.compiler.parser as parser -import kclvm.kcl.types as types - - -path = pathlib.Path(__file__).parent -simple_case_file = str(path.joinpath("scope_test_data/simple.k")) - - -class ScopeTest(unittest.TestCase): - def test_scope_inner_most(self): - program = parser.LoadProgram(simple_case_file) - scope = types.ResolveProgram(program).main_scope - while scope.parent is not None: - scope = scope.parent - inner_most = scope.inner_most(pos=ast.Position(filename=simple_case_file, line=6, column=2)) - self.assertIsNotNone(inner_most) - self.assertTrue(isinstance(inner_most.node, ast.SchemaStmt)) - self.assertTrue(typing.cast(ast.SchemaStmt, inner_most.node).name == "Person") - - def test_scope_contains_pos(self): - program = parser.LoadProgram(simple_case_file) - scope = types.ResolveProgram(program).main_scope - self.assertTrue(isinstance(scope, types.PackageScope)) - # Schema Statement - self.assertTrue(scope.contains_pos(pos=ast.Position(filename=simple_case_file, line=3, column=2))) - # Rule Statement - self.assertTrue(scope.contains_pos(pos=ast.Position(filename=simple_case_file, line=30, column=5))) - for child in scope.children: - if isinstance(child.node, ast.SchemaStmt) and child.node.name == "Base": - self.assertTrue(child.contains_pos(pos=ast.Position(filename=simple_case_file, line=3, column=2))) - elif isinstance(child.node, ast.RuleStmt) and child.node.name == "SomeRule": - self.assertTrue(child.contains_pos(pos=ast.Position(filename=simple_case_file, line=30, column=5))) - self.assertFalse(child.contains_pos(pos=ast.Position(filename=simple_case_file, line=28, column=5))) - -if __name__ == "__main__": - unittest.main(verbosity=2) diff --git a/test/test_units/test_kclvm/test_types/test_type.py b/test/test_units/test_kclvm/test_types/test_type.py deleted file mode 100644 index f4dfecf23..000000000 --- a/test/test_units/test_kclvm/test_types/test_type.py +++ /dev/null @@ -1,177 +0,0 @@ -# Copyright 2021 The KCL Authors. All rights reserved. - -import unittest -import pathlib -from typing import Tuple - -import kclvm.api.object as objpkg -import kclvm.kcl.types as types - - -class TypeTest(unittest.TestCase): - def test_sup(self): - cases = [ - {"types": [], "expected": types.ANY_TYPE}, - {"types": [types.ANY_TYPE], "expected": types.ANY_TYPE}, - {"types": [types.STR_TYPE], "expected": types.STR_TYPE}, - { - "types": [types.STR_TYPE, types.INT_TYPE], - "expected": objpkg.KCLUnionTypeObject( - types=[types.INT_TYPE, types.STR_TYPE] - ), - }, - { - "types": [ - types.STR_TYPE, - types.INT_TYPE, - objpkg.KCLUnionTypeObject(types=[types.INT_TYPE, types.STR_TYPE]), - ], - "expected": objpkg.KCLUnionTypeObject( - types=[types.INT_TYPE, types.STR_TYPE] - ), - }, - { - "types": [types.BOOL_TYPE, types.TRUE_LIT_TYPE], - "expected": types.BOOL_TYPE, - }, - { - "types": [ - objpkg.KCLStringLitTypeObject("Blue"), - objpkg.KCLStringLitTypeObject("Yellow"), - objpkg.KCLStringLitTypeObject("Red"), - ], - "expected": objpkg.KCLUnionTypeObject( - types=[ - objpkg.KCLStringLitTypeObject("Blue"), - objpkg.KCLStringLitTypeObject("Yellow"), - objpkg.KCLStringLitTypeObject("Red"), - ] - ), - }, - { - "types": [ - objpkg.KCLListTypeObject( - objpkg.KCLUnionTypeObject( - [ - objpkg.KCLIntLitTypeObject(1), - objpkg.KCLIntLitTypeObject(2), - ] - ) - ), - objpkg.KCLListTypeObject( - objpkg.KCLUnionTypeObject( - [ - objpkg.KCLIntLitTypeObject(3), - objpkg.KCLIntLitTypeObject(4), - ] - ) - ), - ], - "expected": objpkg.KCLUnionTypeObject( - [ - objpkg.KCLListTypeObject( - objpkg.KCLUnionTypeObject( - [ - objpkg.KCLIntLitTypeObject(1), - objpkg.KCLIntLitTypeObject(2), - ] - ) - ), - objpkg.KCLListTypeObject( - objpkg.KCLUnionTypeObject( - [ - objpkg.KCLIntLitTypeObject(3), - objpkg.KCLIntLitTypeObject(4), - ] - ), - ), - ] - ), - }, - { - "types": [ - objpkg.KCLUnionTypeObject( - [ - types.STR_TYPE, - types.DICT_STR_STR_TYPE, - ] - ), - types.DICT_ANY_ANY_TYPE, - ], - "expected": objpkg.KCLUnionTypeObject( - [ - types.STR_TYPE, - types.DICT_ANY_ANY_TYPE, - ] - ), - }, - ] - for case in cases: - type_list, expected = case["types"], case["expected"] - got = types.sup(type_list) - self.assertEqual( - got, - expected, - msg=f"assert error on type list {type_list}, got {got}", - ) - - def test_assignale_to(self): - cases = [ - {"type1": types.NONE_TYPE, "type2": types.ANY_TYPE, "expected": True}, - {"type1": types.ANY_TYPE, "type2": types.ANY_TYPE, "expected": True}, - {"type1": types.ANY_TYPE, "type2": types.INT_TYPE, "expected": True}, - {"type1": types.INT_TYPE, "type2": types.ANY_TYPE, "expected": True}, - {"type1": types.INT_TYPE, "type2": types.FLOAT_TYPE, "expected": True}, - { - "type1": objpkg.KCLStringLitTypeObject("ss"), - "type2": types.STR_TYPE, - "expected": True, - }, - { - "type1": types.INT_TYPE, - "type2": objpkg.KCLUnionTypeObject( - types=[types.INT_TYPE, types.STR_TYPE] - ), - "expected": True, - }, - { - "type1": types.DICT_STR_STR_TYPE, - "type2": types.DICT_STR_ANY_TYPE, - "expected": True, - }, - {"type1": types.VOID_TYPE, "type2": types.ANY_TYPE, "expected": False}, - {"type1": types.FLOAT_TYPE, "type2": types.INT_TYPE, "expected": False}, - { - "type1": objpkg.KCLSchemaTypeObject( - name="Person", - runtime_type="runtime_type_543fa9efacae37b4c698a94214cdf779_Person", - ), - "type2": objpkg.KCLSchemaTypeObject( - name="Person", - runtime_type="runtime_type_543fa9efacae37b4c698a94214cdf779_Person", - ), - "expected": True, - }, - ] - for case in cases: - type1, type2, expected = case["type1"], case["type2"], case["expected"] - self.assertEqual( - types.assignable_to(type1, type2), - expected, - msg=f"assert error on types {type1} and {type2}", - ) - - def test_type_to_kcl_type_annotation_str_invalid(self): - with self.assertRaises(Exception): - types.type_to_kcl_type_annotation_str(None) - - self.assertEqual( - types.type_to_kcl_type_annotation_str( - objpkg.KCLFunctionTypeObject("test", None, None, None) - ), - "", - ) - - -if __name__ == "__main__": - unittest.main(verbosity=2) diff --git a/test/test_units/test_kclvm/test_types/test_type_checker.py b/test/test_units/test_kclvm/test_types/test_type_checker.py deleted file mode 100644 index 4069bf930..000000000 --- a/test/test_units/test_kclvm/test_types/test_type_checker.py +++ /dev/null @@ -1,207 +0,0 @@ -# Copyright 2021 The KCL Authors. All rights reserved. -import ast -import unittest -import pathlib - -import kclvm.compiler.parser as parser -import kclvm.compiler.check.check_type as check_type -import kclvm.compiler.extension.builtin as builtin -import kclvm.api.object as objpkg -import kclvm.kcl.types as types -import kclvm.kcl.error as kcl_error -import kclvm.internal.util.check_utils as check_utils - -path = pathlib.Path(__file__).parent -invalid_case_path_list = [ - "assert", - "attr_op", - "calculation", - "final", - "for_comp", - "func_call", - "if", - "import", - "loop", - "module", - "schema", - "select_attr", - "subscript", - "type_alias", - "type_annotation", - "type_as", - "unificaion", - "unique", - "unpack", -] -simple_case_file = str(path.joinpath("scope_test_data/simple.k")) -schema_case_file = str(path.joinpath("scope_test_data/schema.k")) -package_case_file = str(path.joinpath("scope_test_data/package.k")) -normal_cases = list(path.joinpath("normal_test_data").glob("*.k")) -err_collect_cases = list(path.joinpath("err_collect_test_data").glob("*.k")) -invalid_cases = [file for p in invalid_case_path_list for file in path.joinpath(f"invalid_test_data/{p}").glob("*.k")] - - -class TypeCheckerTest(unittest.TestCase): - - def test_internal_bug(self): - check_utils.CHECK_MODE = True - program = parser.LoadProgram(simple_case_file) - tc = types.checker.TypeChecker(program) - tc.config_expr_context.append("invalid_expr") - with self.assertRaises( - AssertionError, - msg=f"Here is unreachable unless a bug occurs" - ): - tc.find_schema_attr_obj_from_schema_expr_stack("test") - - def test_switch_config_expr_context_by_key(self): - check_utils.CHECK_MODE = True - program = parser.LoadProgram(simple_case_file) - tc = types.checker.TypeChecker(program) - self.assertEqual(0, tc.switch_config_expr_context_by_key(ast.AST())) - - def test_clear_config_expr_context(self): - check_utils.CHECK_MODE = True - program = parser.LoadProgram(simple_case_file) - tc = types.checker.TypeChecker(program) - tc.config_expr_context.append("invalid_expr") - self.assertEqual(1, len(tc.config_expr_context)) - tc.config_expr_context.append("invalid_expr") - tc.config_expr_context.append("invalid_expr") - self.assertEqual(3, len(tc.config_expr_context)) - tc.clear_config_expr_context(clear_all=True) - self.assertEqual(0, len(tc.config_expr_context)) - - def test_type_checker_simple_case(self): - program = parser.LoadProgram(simple_case_file) - prog_scope = types.ResolveProgram(program) - scope = prog_scope.main_scope - pkgpaths = prog_scope.pkgpaths - base_schema_type = scope.elems["Base"].type.schema_type - person_schema_type = scope.elems["Person"].type.schema_type - self.assertListEqual(pkgpaths, ["__main__"]) - self.assertEqual(scope.elems["Base"].type.schema_type.type_str(), "Base") - self.assertEqual(scope.elems["Person"].type.schema_type.type_str(), "Person") - self.assertEqual(scope.parent, types.BUILTIN_SCOPE) - self.assertEqual(len(scope.parent.elems), len(builtin.BUILTIN_FUNCTIONS)) - self.assertIsInstance(base_schema_type, objpkg.KCLSchemaTypeObject) - self.assertIsInstance(person_schema_type, objpkg.KCLSchemaTypeObject) - self.assertEqual(base_schema_type.name, "Base") - self.assertEqual(person_schema_type.name, "Person") - self.assertEqual(base_schema_type.base, None) - self.assertIsInstance(person_schema_type.base, objpkg.KCLSchemaTypeObject) - self.assertEqual(person_schema_type.base.name, "Base") - - def test_type_checker_schema_case(self): - program = parser.LoadProgram(schema_case_file) - scope = types.ResolveProgram(program).main_scope - person_schema_type = scope.elems["Person"].type.schema_type - self.assertIsInstance(person_schema_type, objpkg.KCLSchemaTypeObject) - - def test_type_checker_package_case(self): - program = parser.LoadProgram(package_case_file) - scope = types.ResolveProgram(program).main_scope - person1_obj = scope.elems["person1"].type - person2_obj = scope.elems["person2"].type - self.assertIsInstance(person1_obj, objpkg.KCLSchemaTypeObject) - self.assertIsInstance(person2_obj, objpkg.KCLSchemaTypeObject) - self.assertEqual(package_case_file in scope.file_begin_position_map, True) - self.assertEqual(scope.file_begin_position_map[package_case_file].filename, package_case_file) - self.assertEqual(scope.file_begin_position_map[package_case_file].line, 1) - self.assertEqual(scope.file_begin_position_map[package_case_file].column, 1) - self.assertEqual(package_case_file in scope.file_end_position_map, True) - self.assertEqual(scope.file_end_position_map[package_case_file].filename, package_case_file) - self.assertEqual(scope.file_end_position_map[package_case_file].line, 12) - self.assertEqual(scope.file_end_position_map[package_case_file].column, 2) - self.assertEqual(person1_obj.pkgpath, "scope_test_data.pkg") - self.assertEqual(person2_obj.pkgpath, "scope_test_data.pkg.pkg") - - for person_obj in [person1_obj, person2_obj]: - self.assertTrue("__settings__" in person_obj.attr_obj_map) - self.assertTrue("name" in person_obj.attr_obj_map) - self.assertTrue("age" in person_obj.attr_obj_map) - self.assertEqual(types.DICT_STR_ANY_TYPE, person_obj.attr_obj_map["__settings__"].attr_type) - self.assertEqual(types.STR_TYPE, person_obj.attr_obj_map["name"].attr_type) - self.assertEqual(types.INT_TYPE, person_obj.attr_obj_map["age"].attr_type) - - def test_type_checker_normal_case(self): - for case in normal_cases: - program = parser.LoadProgram(case) - types.ResolveProgram(program) - - def test_type_checker_invalid_case(self): - for case in invalid_cases: - with self.assertRaises( - kcl_error.KCLException, msg=f"case: {case}" - ): - program = parser.LoadProgram(case) - types.ResolveProgram(program) - - def test_type_checker_err_collect_case(self): - for case in err_collect_cases: - program = parser.LoadProgram(case) - types.ResolveProgram(program, config=types.CheckConfig( - raise_err=False, - )) - - def test_check_type(self): - cases = [ - # True cases - {"value": None, "expected_type": "int", "result": True}, - {"value": objpkg.Undefined, "expected_type": "int", "result": True}, - {"value": 1, "expected_type": "float", "result": True}, - {"value": 1, "expected_type": "", "result": True}, - {"value": 1, "expected_type": "int", "result": True}, - {"value": 1.1, "expected_type": "float", "result": True}, - {"value": "s", "expected_type": "str", "result": True}, - {"value": True, "expected_type": "bool", "result": True}, - {"value": [1, 2, 3], "expected_type": "[int]", "result": True}, - {"value": {"key": "value"}, "expected_type": "{str:}", "result": True}, - # False cases - {"value": 1, "expected_type": "str", "result": False}, - {"value": 1.1, "expected_type": "int", "result": False}, - {"value": "s", "expected_type": "int", "result": False}, - {"value": True, "expected_type": "str", "result": False}, - {"value": [1, 2, 3], "expected_type": "[str]", "result": False}, - {"value": {"key": "value"}, "expected_type": "{str:int}", "result": False}, - ] - for case in cases: - value = objpkg.to_kcl_obj(case["value"]) - expected_type = case["expected_type"] - result = case["result"] - self.assertEqual( - check_type.check_type(value, expected_type)[0], - result, - msg=f"value: {value}, expected_type: {expected_type}" - ) - - def test_check_type_builtin(self): - cases = [ - # True cases - {"value": 1, "expected_types": [], "result": True}, - {"value": 1, "expected_types": ["float"], "result": True}, - {"value": 1, "expected_types": ["int"], "result": True}, - {"value": 1, "expected_types": ["str", "int"], "result": True}, - {"value": 1.1, "expected_types": ["float"], "result": True}, - {"value": 1.1, "expected_types": ["float", "int"], "result": True}, - {"value": "s", "expected_types": ["str"], "result": True}, - {"value": True, "expected_types": ["bool"], "result": True}, - # False cases - {"value": 1, "expected_types": ["str"], "result": False}, - {"value": 1.1, "expected_types": ["int"], "result": False}, - {"value": "s", "expected_types": ["int"], "result": False}, - {"value": True, "expected_types": ["str"], "result": False}, - ] - for case in cases: - value = objpkg.to_kcl_obj(case["value"]) - expected_types = case["expected_types"] - result = case["result"] - self.assertEqual( - check_type.check_type_builtin(value, expected_types, should_raise_err=False), - result, - msg=f"value: {value}, expected_types: {expected_types}" - ) - - -if __name__ == "__main__": - unittest.main(verbosity=2) diff --git a/test/test_units/test_kclvm/test_types/test_type_convension.py b/test/test_units/test_kclvm/test_types/test_type_convension.py deleted file mode 100644 index 8dde91532..000000000 --- a/test/test_units/test_kclvm/test_types/test_type_convension.py +++ /dev/null @@ -1,67 +0,0 @@ -# Copyright 2021 The KCL Authors. All rights reserved. - -import unittest -import pathlib - -import kclvm.kcl.error as kcl_error -import kclvm.api.object as objpkg -import kclvm.kcl.types as types - - -class TypeConvensionTest(unittest.TestCase): - def test_type_convert(self): - cases = [ - { - "obj": objpkg.NONE_INSTANCE, - "tpe": objpkg.KCLIntTypeObject(), - "expected": objpkg.NONE_INSTANCE, - }, - { - "obj": objpkg.UNDEFINED_INSTANCE, - "tpe": objpkg.KCLIntTypeObject(), - "expected": objpkg.UNDEFINED_INSTANCE, - }, - { - "obj": objpkg.KCLIntObject(1), - "tpe": types.ANY_TYPE, - "expected": objpkg.KCLIntObject(1), - }, - { - "obj": objpkg.KCLDictObject(value={"key": objpkg.KCLStringObject("s")}), - "tpe": types.DICT_STR_STR_TYPE, - "expected": objpkg.KCLDictObject(value={"key": objpkg.KCLStringObject("s")}), - }, - { - "obj": objpkg.KCLListObject(items=[objpkg.KCLStringObject("s")]), - "tpe": objpkg.KCLListTypeObject(objpkg.KCLStringTypeObject()), - "expected": objpkg.KCLListObject(items=[objpkg.KCLStringObject("s")]), - }, - ] - for case in cases: - obj, tpe, expected = case["obj"], case["tpe"], case["expected"] - self.assertEqual(types.type_convert(obj, tpe), expected) - - def test_type_convert_failed(self): - cases = [ - {"obj": objpkg.KCLIntObject(0), "tpe": objpkg.KCLStringTypeObject()}, - {"obj": objpkg.KCLStringObject("s"), "tpe": objpkg.KCLIntTypeObject()}, - ] - for case in cases: - obj, tpe = case["obj"], case["tpe"] - with self.assertRaises(kcl_error.EvaluationError): - types.type_convert(obj, tpe) - - def test_type_convert_invalid_params(self): - cases = [ - {"obj": None, "tpe": None}, - {"obj": objpkg.KCLIntObject(0), "tpe": None}, - {"obj": None, "tpe": objpkg.KCLIntTypeObject()}, - ] - for case in cases: - obj, tpe = case["obj"], case["tpe"] - with self.assertRaises(ValueError): - types.type_convert(obj, tpe) - - -if __name__ == "__main__": - unittest.main(verbosity=2) diff --git a/test/test_units/test_kclvm/test_types/test_type_parser.py b/test/test_units/test_kclvm/test_types/test_type_parser.py deleted file mode 100644 index 92afae7a8..000000000 --- a/test/test_units/test_kclvm/test_types/test_type_parser.py +++ /dev/null @@ -1,338 +0,0 @@ -# Copyright 2021 The KCL Authors. All rights reserved. - -import unittest -import pathlib -from typing import Tuple - -import kclvm.api.object as objpkg -import kclvm.api.object.internal.common as common -import kclvm.kcl.types as types -import kclvm.kcl.types.type_parser as type_parser - - -class TypeParserTest(unittest.TestCase): - def test_is_lit_type(self): - cases = [ - {"type_str": "1", "expected": True}, - {"type_str": "1.1", "expected": True}, - {"type_str": "1.e+0", "expected": True}, - {"type_str": ".1", "expected": True}, - {"type_str": "True", "expected": True}, - {"type_str": "False", "expected": True}, - {"type_str": "'s'", "expected": True}, - {"type_str": "\"s\"", "expected": True}, - {"type_str": "true", "expected": False}, - {"type_str": "false", "expected": False}, - {"type_str": "\"s", "expected": False}, - {"type_str": "'s", "expected": False}, - {"type_str": "schema", "expected": False}, - {"type_str": "pkg.schema", "expected": False}, - ] - for case in cases: - type_str, expected = case["type_str"], case["expected"] - self.assertEqual( - type_parser.is_lit_type_str(type_str), expected - ) - - def test_is_type_union(self): - cases = [ - {"type_str": "A|B|C", "expected": True}, - {"type_str": "'123'|'456'|'789'", "expected": True}, - {"type_str": "'|'|'||'|'|||'", "expected": True}, - {"type_str": '"aa\\"ab|"|"aa\\"abccc"', "expected": True}, - {"type_str": '["|"]|""', "expected": True}, - {"type_str": '{str:"|"}|"|"', "expected": True}, - {"type_str": '"aa\\"ab|"', "expected": False}, - {"type_str": '"|aa\\"ab|"', "expected": False}, - ] - for case in cases: - type_str, expected = case["type_str"], case["expected"] - self.assertEqual( - common.is_type_union(type_str), expected - ) - - def test_split_type_union(self): - cases = [ - {"type_str": "A|B|C", "expected": ["A", "B", "C"]}, - {"type_str": "'123'|'456'|'789'", "expected": ["'123'", "'456'", "'789'"]}, - {"type_str": "'|'|'||'|'|||'", "expected": ["'|'", "'||'", "'|||'"]}, - {"type_str": '["|"]|""', "expected": ['["|"]', '""']}, - {"type_str": '{str:"|"}|"|"', "expected": ['{str:"|"}', '"|"']}, - ] - for case in cases: - type_str, expected = case["type_str"], case["expected"] - self.assertEqual( - common.split_type_union(type_str), expected - ) - - def test_parse_type_str_normal(self): - cases = [ - # Common built-in types - {"type_str": None, "expected": types.ANY_TYPE}, - {"type_str": "", "expected": types.ANY_TYPE}, - {"type_str": "any", "expected": types.ANY_TYPE}, - {"type_str": "any", "expected": objpkg.KCLAnyTypeObject()}, - {"type_str": "int", "expected": types.INT_TYPE}, - {"type_str": "float", "expected": types.FLOAT_TYPE}, - {"type_str": "str", "expected": types.STR_TYPE}, - {"type_str": "bool", "expected": types.BOOL_TYPE}, - # Dict types - { - "type_str": "{:}", - "expected": objpkg.KCLDictTypeObject( - key_type=types.ANY_TYPE, value_type=types.ANY_TYPE - ), - }, - { - "type_str": "{str:}", - "expected": objpkg.KCLDictTypeObject( - key_type=types.STR_TYPE, value_type=types.ANY_TYPE - ), - }, - { - "type_str": "{str:any}", - "expected": objpkg.KCLDictTypeObject( - key_type=types.STR_TYPE, value_type=types.ANY_TYPE - ), - }, - { - "type_str": "{str:str}", - "expected": objpkg.KCLDictTypeObject( - key_type=types.STR_TYPE, value_type=types.STR_TYPE - ), - }, - { - "type_str": "{str:{str:str}}", - "expected": objpkg.KCLDictTypeObject( - key_type=types.STR_TYPE, - value_type=objpkg.KCLDictTypeObject( - key_type=types.STR_TYPE, - value_type=types.STR_TYPE, - ), - ), - }, - { - "type_str": "{str:[str]}", - "expected": objpkg.KCLDictTypeObject( - key_type=types.STR_TYPE, - value_type=objpkg.KCLListTypeObject(item_type=types.STR_TYPE), - ), - }, - # List types - { - "type_str": "[]", - "expected": objpkg.KCLListTypeObject(item_type=types.ANY_TYPE), - }, - { - "type_str": "[any]", - "expected": objpkg.KCLListTypeObject(item_type=types.ANY_TYPE), - }, - { - "type_str": "[str]", - "expected": objpkg.KCLListTypeObject(item_type=types.STR_TYPE), - }, - { - "type_str": "[{str:}]", - "expected": objpkg.KCLListTypeObject(item_type=types.DICT_STR_ANY_TYPE), - }, - { - "type_str": "[{str:str}]", - "expected": objpkg.KCLListTypeObject(item_type=types.DICT_STR_STR_TYPE), - }, - # Union types - { - "type_str": "str|int", - "expected": objpkg.KCLUnionTypeObject( - types=[ - types.INT_TYPE, - types.STR_TYPE, - ] - ), - }, - { - "type_str": "int|str", - "expected": objpkg.KCLUnionTypeObject( - types=[ - types.INT_TYPE, - types.STR_TYPE, - ] - ), - }, - { - "type_str": "int|str|int", - "expected": objpkg.KCLUnionTypeObject( - types=[ - types.INT_TYPE, - types.STR_TYPE, - ] - ), - }, - { - "type_str": "int|str|int|str", - "expected": objpkg.KCLUnionTypeObject( - types=[ - types.INT_TYPE, - types.STR_TYPE, - ] - ), - }, - { - "type_str": "{str:int|str}", - "expected": objpkg.KCLDictTypeObject( - key_type=types.STR_TYPE, - value_type=objpkg.KCLUnionTypeObject( - types=[ - types.INT_TYPE, - types.STR_TYPE, - ] - ), - ), - }, - { - "type_str": "{str|int:int|str}", - "expected": objpkg.KCLDictTypeObject( - key_type=objpkg.KCLUnionTypeObject( - types=[ - types.INT_TYPE, - types.STR_TYPE, - ] - ), - value_type=objpkg.KCLUnionTypeObject( - types=[ - types.INT_TYPE, - types.STR_TYPE, - ] - ), - ), - }, - { - "type_str": "[int|str]", - "expected": objpkg.KCLListTypeObject( - item_type=objpkg.KCLUnionTypeObject( - types=[ - types.INT_TYPE, - types.STR_TYPE, - ] - ), - ), - }, - # Literal types - {"type_str": "True", "expected": types.TRUE_LIT_TYPE}, - {"type_str": "False", "expected": types.FALSE_LIT_TYPE}, - { - "type_str": "123", - "expected": objpkg.KCLIntLitTypeObject(value=123), - }, - { - "type_str": "123.0", - "expected": objpkg.KCLFloatLitTypeObject(value=123.0), - }, - { - "type_str": "'ss'", - "expected": objpkg.KCLStringLitTypeObject(value="ss"), - }, - { - "type_str": '"ss"', - "expected": objpkg.KCLStringLitTypeObject(value="ss"), - }, - { - "type_str": "'Red'|'Yellow'|'Blue'", - "expected": objpkg.KCLUnionTypeObject( - types=[ - objpkg.KCLStringLitTypeObject(value="Red"), - objpkg.KCLStringLitTypeObject(value="Yellow"), - objpkg.KCLStringLitTypeObject(value="Blue"), - ] - ), - }, - { - "type_str": "1|2|3", - "expected": objpkg.KCLUnionTypeObject( - types=[ - objpkg.KCLIntLitTypeObject(value=1), - objpkg.KCLIntLitTypeObject(value=2), - objpkg.KCLIntLitTypeObject(value=3), - ] - ), - }, - # Partially ordered types - { - "type_str": "str|'ss'|int", - "expected": objpkg.KCLUnionTypeObject( - types=[ - types.INT_TYPE, - types.STR_TYPE, - ] - ), - }, - { - "type_str": "str|'ss'|int|1|bool|True", - "expected": objpkg.KCLUnionTypeObject( - types=[ - types.BOOL_TYPE, - types.INT_TYPE, - types.STR_TYPE, - ] - ), - }, - { - "type_str": "1|1|2", - "expected": objpkg.KCLUnionTypeObject( - types=[ - objpkg.KCLIntLitTypeObject(value=1), - objpkg.KCLIntLitTypeObject(value=2), - ] - ), - }, - { - "type_str": "2|1|1", - "expected": objpkg.KCLUnionTypeObject( - types=[ - objpkg.KCLIntLitTypeObject(value=2), - objpkg.KCLIntLitTypeObject(value=1), - ] - ), - }, - { - "type_str": "{str:}|{str:str}", - "expected": types.DICT_STR_ANY_TYPE, - }, - { - "type_str": "[]|[str]", - "expected": objpkg.KCLListTypeObject(item_type=types.ANY_TYPE), - }, - { - "type_str": '1|"aaa"|True', - "expected": objpkg.KCLUnionTypeObject( - types=[ - types.TRUE_LIT_TYPE, - objpkg.KCLIntLitTypeObject(1), - objpkg.KCLStringLitTypeObject("aaa"), - ] - ), - }, - ] - for case in cases: - type_str, expected = case["type_str"], case["expected"] - self.assertEqual( - types.parse_type_str(type_str), - expected, - msg=f"Assert error type: {type_str}", - ) - - def test_parse_type_str_invalid(self): - cases = [ - {"type_str": True}, - {"type_str": 1}, - {"type_str": []}, - {"type_str": {}}, - {"type_str": ()}, - ] - for case in cases: - type_str = case["type_str"] - with self.assertRaises(ValueError): - types.parse_type_str(type_str) - - -if __name__ == "__main__": - unittest.main(verbosity=2) diff --git a/test/test_units/test_kclvm/test_types/test_type_walker.py b/test/test_units/test_kclvm/test_types/test_type_walker.py deleted file mode 100644 index e9ae8703a..000000000 --- a/test/test_units/test_kclvm/test_types/test_type_walker.py +++ /dev/null @@ -1,86 +0,0 @@ -# Copyright 2021 The KCL Authors. All rights reserved. - -import unittest -import pathlib -from typing import Tuple - -import kclvm.api.object as objpkg -import kclvm.kcl.types as types -import kclvm.kcl.types.walker as type_walker - - -class TypeTest(unittest.TestCase): - def test_type_walker_convert_int_to_str(self): - def walk_fn(t): - if isinstance(t, objpkg.KCLIntTypeObject): - return objpkg.KCLStringTypeObject() - return t - - cases = [ - {"type": types.INT_TYPE, "expected": types.STR_TYPE}, - { - "type": objpkg.KCLListTypeObject(types.ANY_TYPE), - "expected": objpkg.KCLListTypeObject(types.ANY_TYPE), - }, - { - "type": objpkg.KCLListTypeObject(types.STR_TYPE), - "expected": objpkg.KCLListTypeObject(types.STR_TYPE), - }, - { - "type": objpkg.KCLListTypeObject(types.INT_TYPE), - "expected": objpkg.KCLListTypeObject(types.STR_TYPE), - }, - { - "type": objpkg.KCLUnionTypeObject([types.STR_TYPE, types.INT_TYPE]), - "expected": objpkg.KCLUnionTypeObject( - types=[types.STR_TYPE, types.STR_TYPE] - ), - }, - { - "type": objpkg.KCLUnionTypeObject( - [ - types.STR_TYPE, - types.INT_TYPE, - objpkg.KCLUnionTypeObject( - types=[types.INT_TYPE, types.STR_TYPE] - ), - ] - ), - "expected": objpkg.KCLUnionTypeObject( - [ - types.STR_TYPE, - types.STR_TYPE, - objpkg.KCLUnionTypeObject( - types=[types.STR_TYPE, types.STR_TYPE] - ), - ] - ), - }, - { - "type": objpkg.KCLUnionTypeObject( - [types.BOOL_TYPE, types.TRUE_LIT_TYPE] - ), - "expected": objpkg.KCLUnionTypeObject( - [types.BOOL_TYPE, types.TRUE_LIT_TYPE] - ), - }, - { - "type": objpkg.KCLDictTypeObject( - key_type=types.INT_TYPE, value_type=types.INT_TYPE - ), - "expected": objpkg.KCLDictTypeObject( - key_type=types.STR_TYPE, value_type=types.STR_TYPE - ), - }, - ] - for case in cases: - tpe, expected = case["type"], case["expected"] - self.assertEqual( - type_walker.WalkType(tpe, walk_fn), - expected, - msg=f"assert error on type {tpe}, and the expected is {expected}", - ) - - -if __name__ == "__main__": - unittest.main(verbosity=2) diff --git a/test/test_units/test_kclvm/test_unification/test_data/collection_if.code b/test/test_units/test_kclvm/test_unification/test_data/collection_if.code deleted file mode 100644 index d0a8e22df..000000000 --- a/test/test_units/test_kclvm/test_unification/test_data/collection_if.code +++ /dev/null @@ -1,10 +0,0 @@ -schema Person: - name: str - age: int - -alice = Person { - if True: - name: "Alice" - if True: - age = 18 -} diff --git a/test/test_units/test_kclvm/test_unification/test_data/collection_if.input b/test/test_units/test_kclvm/test_unification/test_data/collection_if.input deleted file mode 100644 index 091888d3a..000000000 --- a/test/test_units/test_kclvm/test_unification/test_data/collection_if.input +++ /dev/null @@ -1,13 +0,0 @@ -schema Person: - name: str - age: int - -alice = Person { - if True: - name: "Alice" -} - -alice = Person { - if True: - age = 18 -} diff --git a/test/test_units/test_kclvm/test_unification/test_data/collection_if.vertex b/test/test_units/test_kclvm/test_unification/test_data/collection_if.vertex deleted file mode 100644 index 16a23cb77..000000000 --- a/test/test_units/test_kclvm/test_unification/test_data/collection_if.vertex +++ /dev/null @@ -1,14 +0,0 @@ -name: @root -is_unique: False -adjs: - name: alice - is_unique: False - config_name: Person - adjs: - name: None - is_unique: False - value: - - name: None - is_unique: False - value: diff --git a/test/test_units/test_kclvm/test_unification/test_data/empty.code b/test/test_units/test_kclvm/test_unification/test_data/empty.code deleted file mode 100644 index 75037e666..000000000 --- a/test/test_units/test_kclvm/test_unification/test_data/empty.code +++ /dev/null @@ -1 +0,0 @@ -config = Config {} diff --git a/test/test_units/test_kclvm/test_unification/test_data/empty.input b/test/test_units/test_kclvm/test_unification/test_data/empty.input deleted file mode 100644 index 24e854d0d..000000000 --- a/test/test_units/test_kclvm/test_unification/test_data/empty.input +++ /dev/null @@ -1,10 +0,0 @@ -schema Config: - name?: str - args?: [str] - labels?: {str:} - -config = Config {} - -config = {} - -config = {} diff --git a/test/test_units/test_kclvm/test_unification/test_data/empty.vertex b/test/test_units/test_kclvm/test_unification/test_data/empty.vertex deleted file mode 100644 index 578627739..000000000 --- a/test/test_units/test_kclvm/test_unification/test_data/empty.vertex +++ /dev/null @@ -1,7 +0,0 @@ -name: @root -is_unique: False -adjs: - name: config - is_unique: False - config_name: Config - value: config: > diff --git a/test/test_units/test_kclvm/test_unification/test_data/insert.code b/test/test_units/test_kclvm/test_unification/test_data/insert.code deleted file mode 100644 index 33ba46548..000000000 --- a/test/test_units/test_kclvm/test_unification/test_data/insert.code +++ /dev/null @@ -1,4 +0,0 @@ -person = Person { - info = {"key2": "value2"} - hc[0] += 4 -} diff --git a/test/test_units/test_kclvm/test_unification/test_data/insert.input b/test/test_units/test_kclvm/test_unification/test_data/insert.input deleted file mode 100644 index a6417714b..000000000 --- a/test/test_units/test_kclvm/test_unification/test_data/insert.input +++ /dev/null @@ -1,11 +0,0 @@ -schema Person: - info: {str:} = {"key1": "value1"} - hc: [int] = [1, 2, 3] - -person = Person { - info = {"key2": "value2"} -} - -person = Person { - hc[0] += 4 -} diff --git a/test/test_units/test_kclvm/test_unification/test_data/insert.vertex b/test/test_units/test_kclvm/test_unification/test_data/insert.vertex deleted file mode 100644 index 8351028ca..000000000 --- a/test/test_units/test_kclvm/test_unification/test_data/insert.vertex +++ /dev/null @@ -1,17 +0,0 @@ -name: @root -is_unique: False -adjs: - name: person - is_unique: False - config_name: Person - adjs: - name: info - is_unique: False - adjs: - name: key2 - is_unique: False - value: - - name: - is_unique: False - value: diff --git a/test/test_units/test_kclvm/test_unification/test_data/int_dict.code b/test/test_units/test_kclvm/test_unification/test_data/int_dict.code deleted file mode 100644 index 9560f5f3f..000000000 --- a/test/test_units/test_kclvm/test_unification/test_data/int_dict.code +++ /dev/null @@ -1,11 +0,0 @@ -group = Group { - persons: { - 1: { - name: { - firstName: "Alice" - lastName: "Terry" - } - age: 12 - } - } -} diff --git a/test/test_units/test_kclvm/test_unification/test_data/int_dict.input b/test/test_units/test_kclvm/test_unification/test_data/int_dict.input deleted file mode 100644 index baae380e9..000000000 --- a/test/test_units/test_kclvm/test_unification/test_data/int_dict.input +++ /dev/null @@ -1,30 +0,0 @@ -schema Name: - firstName: str - lastName: str - -schema Person: - name: Name - age: int - -schema Group: - persons: {int:Person} - -group = Group { - "persons": { - 1: { - "name": { - "firstName": "Alice", - }, - "age": 12 - } - } -} -group = Group { - "persons": { - 1: { - "name": { - "lastName": "Terry" - }, - } - } -} \ No newline at end of file diff --git a/test/test_units/test_kclvm/test_unification/test_data/int_dict.vertex b/test/test_units/test_kclvm/test_unification/test_data/int_dict.vertex deleted file mode 100644 index 76a48dcc1..000000000 --- a/test/test_units/test_kclvm/test_unification/test_data/int_dict.vertex +++ /dev/null @@ -1,27 +0,0 @@ -name: @root -is_unique: False -adjs: - name: group - is_unique: False - config_name: Group - adjs: - name: persons - is_unique: False - adjs: - name: 1 - is_unique: False - adjs: - name: name - is_unique: False - adjs: - name: firstName - is_unique: False - value: - - name: lastName - is_unique: False - value: - - name: age - is_unique: False - value: diff --git a/test/test_units/test_kclvm/test_unification/test_data/nest_declaration.code b/test/test_units/test_kclvm/test_unification/test_data/nest_declaration.code deleted file mode 100644 index 8fca0c7b7..000000000 --- a/test/test_units/test_kclvm/test_unification/test_data/nest_declaration.code +++ /dev/null @@ -1,6 +0,0 @@ -config = Config { - args: ["kcl", "main.k"] - labels: { - key1: "value1" - } -} diff --git a/test/test_units/test_kclvm/test_unification/test_data/nest_declaration.input b/test/test_units/test_kclvm/test_unification/test_data/nest_declaration.input deleted file mode 100644 index ec15d23cd..000000000 --- a/test/test_units/test_kclvm/test_unification/test_data/nest_declaration.input +++ /dev/null @@ -1,11 +0,0 @@ -schema Config: - name?: str - args: [str] - labels: {str:} - -config = Config { - args: ["kcl", "main.k"] - labels.key1: "value1" -} - -config.name = "config" diff --git a/test/test_units/test_kclvm/test_unification/test_data/nest_declaration.vertex b/test/test_units/test_kclvm/test_unification/test_data/nest_declaration.vertex deleted file mode 100644 index 3ecf1d6ad..000000000 --- a/test/test_units/test_kclvm/test_unification/test_data/nest_declaration.vertex +++ /dev/null @@ -1,17 +0,0 @@ -name: @root -is_unique: False -adjs: - name: config - is_unique: False - config_name: Config - adjs: - name: args - is_unique: False - value: , ]> - - name: labels - is_unique: False - adjs: - name: key1 - is_unique: False - value: diff --git a/test/test_units/test_kclvm/test_unification/test_data/nest_var_0.code b/test/test_units/test_kclvm/test_unification/test_data/nest_var_0.code deleted file mode 100644 index ce2a49612..000000000 --- a/test/test_units/test_kclvm/test_unification/test_data/nest_var_0.code +++ /dev/null @@ -1,8 +0,0 @@ -config = Config { - args: ["kcl", "main.k"] - labels: { - key1: "value1" - key2: "value2" - key3: "value3" - } -} diff --git a/test/test_units/test_kclvm/test_unification/test_data/nest_var_0.input b/test/test_units/test_kclvm/test_unification/test_data/nest_var_0.input deleted file mode 100644 index 7b945cc6e..000000000 --- a/test/test_units/test_kclvm/test_unification/test_data/nest_var_0.input +++ /dev/null @@ -1,20 +0,0 @@ -schema Config: - args: [str] - labels: {str:} - -config = Config { - args: ["kcl", "main.k"] - labels.key1: "value1" -} - -config = Config { - labels: { - key2: "value2" - } -} - -config = Config { - "labels": { - "key3": "value3" - } -} diff --git a/test/test_units/test_kclvm/test_unification/test_data/nest_var_0.vertex b/test/test_units/test_kclvm/test_unification/test_data/nest_var_0.vertex deleted file mode 100644 index 4cefdeb3e..000000000 --- a/test/test_units/test_kclvm/test_unification/test_data/nest_var_0.vertex +++ /dev/null @@ -1,25 +0,0 @@ -name: @root -is_unique: False -adjs: - name: config - is_unique: False - config_name: Config - adjs: - name: args - is_unique: False - value: , ]> - - name: labels - is_unique: False - adjs: - name: key1 - is_unique: False - value: - - name: key2 - is_unique: False - value: - - name: key3 - is_unique: False - value: diff --git a/test/test_units/test_kclvm/test_unification/test_data/nest_var_1.code b/test/test_units/test_kclvm/test_unification/test_data/nest_var_1.code deleted file mode 100644 index aed22117f..000000000 --- a/test/test_units/test_kclvm/test_unification/test_data/nest_var_1.code +++ /dev/null @@ -1,13 +0,0 @@ -config = Config { - args: ["kcl", "main.k"] - labels: { - key1: "value1" - key2: "value2" - } - name: { - name: { - name: "name" - data: 1 - } - } -} diff --git a/test/test_units/test_kclvm/test_unification/test_data/nest_var_1.input b/test/test_units/test_kclvm/test_unification/test_data/nest_var_1.input deleted file mode 100644 index acbcbbec5..000000000 --- a/test/test_units/test_kclvm/test_unification/test_data/nest_var_1.input +++ /dev/null @@ -1,24 +0,0 @@ -schema Name0: - name?: str - data?: int - -schema Name: - name?: Name0 - -schema Config: - args?: [str] - labels: {str:} - name: Name - -config = Config { - args: ["kcl", "main.k"] - labels.key1: "value1" - name.name.name: "name" -} - -config = Config { - labels: { - key2: "value2" - } - name.name: Name0 {data: 1} -} diff --git a/test/test_units/test_kclvm/test_unification/test_data/nest_var_1.vertex b/test/test_units/test_kclvm/test_unification/test_data/nest_var_1.vertex deleted file mode 100644 index eb042c96f..000000000 --- a/test/test_units/test_kclvm/test_unification/test_data/nest_var_1.vertex +++ /dev/null @@ -1,35 +0,0 @@ -name: @root -is_unique: False -adjs: - name: config - is_unique: False - config_name: Config - adjs: - name: args - is_unique: False - value: , ]> - - name: labels - is_unique: False - adjs: - name: key1 - is_unique: False - value: - - name: key2 - is_unique: False - value: - - name: name - is_unique: False - adjs: - name: name - is_unique: False - adjs: - name: name - is_unique: False - value: - - name: data - is_unique: False - value: diff --git a/test/test_units/test_kclvm/test_unification/test_data/override.code b/test/test_units/test_kclvm/test_unification/test_data/override.code deleted file mode 100644 index 5c6186393..000000000 --- a/test/test_units/test_kclvm/test_unification/test_data/override.code +++ /dev/null @@ -1,10 +0,0 @@ -config = Config { - name: "config1" - name: "config2" - args: ["kcl", "main.k"] - args: ["kcl2"] - labels: { - key1: "value1" - key2: "value2" - } -} diff --git a/test/test_units/test_kclvm/test_unification/test_data/override.input b/test/test_units/test_kclvm/test_unification/test_data/override.input deleted file mode 100644 index 168491818..000000000 --- a/test/test_units/test_kclvm/test_unification/test_data/override.input +++ /dev/null @@ -1,17 +0,0 @@ -schema Config: - """Config Definition""" - name?: str - args: [str] - labels: {str:} - -config = Config { - name: "config1" # Literal Initial - args: ["kcl", "main.k"] # List Initial - labels.key1: "value1" # Dict Initial -} - -config = Config { - name = "config2" # Literal Override - args: ["kcl2"] # List Override - labels: {key2: "value2"} # Dict Unification -} diff --git a/test/test_units/test_kclvm/test_unification/test_data/override.vertex b/test/test_units/test_kclvm/test_unification/test_data/override.vertex deleted file mode 100644 index 4f97906d1..000000000 --- a/test/test_units/test_kclvm/test_unification/test_data/override.vertex +++ /dev/null @@ -1,33 +0,0 @@ -name: @root -is_unique: False -adjs: - name: config - is_unique: False - config_name: Config - adjs: - name: name - is_unique: False - value: - - name: name - is_unique: False - value: - - name: args - is_unique: False - value: , ]> - - name: args - is_unique: False - value: ]> - - name: labels - is_unique: False - adjs: - name: key1 - is_unique: False - value: - - name: key2 - is_unique: False - value: diff --git a/test/test_units/test_kclvm/test_unification/test_data/schema.code b/test/test_units/test_kclvm/test_unification/test_data/schema.code deleted file mode 100644 index 2f2140ef3..000000000 --- a/test/test_units/test_kclvm/test_unification/test_data/schema.code +++ /dev/null @@ -1,5 +0,0 @@ -config = Config { - name: "Alice" - age: 18 - hc: [1] -} diff --git a/test/test_units/test_kclvm/test_unification/test_data/schema.input b/test/test_units/test_kclvm/test_unification/test_data/schema.input deleted file mode 100644 index 13190b0da..000000000 --- a/test/test_units/test_kclvm/test_unification/test_data/schema.input +++ /dev/null @@ -1,16 +0,0 @@ -schema Config: - name?: str - age?: int - hc: [int] - -config = Config { - name: "Alice" -} - -config = Config { - age: 18 -} - -config = Config { - hc: [1] -} diff --git a/test/test_units/test_kclvm/test_unification/test_data/schema.vertex b/test/test_units/test_kclvm/test_unification/test_data/schema.vertex deleted file mode 100644 index 1a7ae9e11..000000000 --- a/test/test_units/test_kclvm/test_unification/test_data/schema.vertex +++ /dev/null @@ -1,18 +0,0 @@ -name: @root -is_unique: False -adjs: - name: config - is_unique: False - config_name: Config - adjs: - name: name - is_unique: False - value: - - name: age - is_unique: False - value: - - name: hc - is_unique: False - value: ]> diff --git a/test/test_units/test_kclvm/test_unification/test_data/schema_and_dict.code b/test/test_units/test_kclvm/test_unification/test_data/schema_and_dict.code deleted file mode 100644 index 2f2140ef3..000000000 --- a/test/test_units/test_kclvm/test_unification/test_data/schema_and_dict.code +++ /dev/null @@ -1,5 +0,0 @@ -config = Config { - name: "Alice" - age: 18 - hc: [1] -} diff --git a/test/test_units/test_kclvm/test_unification/test_data/schema_and_dict.input b/test/test_units/test_kclvm/test_unification/test_data/schema_and_dict.input deleted file mode 100644 index 7dcc10109..000000000 --- a/test/test_units/test_kclvm/test_unification/test_data/schema_and_dict.input +++ /dev/null @@ -1,16 +0,0 @@ -schema Config: - name?: str - age?: int - hc: [int] - -config = Config { - name: "Alice" -} - -config = { - "age": 18 -} - -config = Config { - hc: [1] -} diff --git a/test/test_units/test_kclvm/test_unification/test_data/schema_and_dict.vertex b/test/test_units/test_kclvm/test_unification/test_data/schema_and_dict.vertex deleted file mode 100644 index de31ebc14..000000000 --- a/test/test_units/test_kclvm/test_unification/test_data/schema_and_dict.vertex +++ /dev/null @@ -1,18 +0,0 @@ -name: @root -is_unique: False -adjs: - name: config - is_unique: False - config_name: Config - adjs: - name: name - is_unique: False - value: - - name: age - is_unique: False - value: - - name: hc - is_unique: False - value: ]> diff --git a/test/test_units/test_kclvm/test_unification/test_data/schema_with_list.code b/test/test_units/test_kclvm/test_unification/test_data/schema_with_list.code deleted file mode 100644 index 3423a61b5..000000000 --- a/test/test_units/test_kclvm/test_unification/test_data/schema_with_list.code +++ /dev/null @@ -1,14 +0,0 @@ -_main = Main { - env: ["123", "456"] - args: ["1"] -} - -config = Config { - name: "Alice" - main: _main - main: Main { - env: ["123"] - args: [] - } - age: 18 -} diff --git a/test/test_units/test_kclvm/test_unification/test_data/schema_with_list.input b/test/test_units/test_kclvm/test_unification/test_data/schema_with_list.input deleted file mode 100644 index 6ccc0c230..000000000 --- a/test/test_units/test_kclvm/test_unification/test_data/schema_with_list.input +++ /dev/null @@ -1,27 +0,0 @@ -schema Main: - env: [str] - args: [str] - -schema Config: - name?: str - age?: int - hc?: [int] - main: Main - -_main = Main { - env: ["123", "456"] - args: ["1"] -} - -config = Config { - name: "Alice" - main: _main -} - -config = Config { - age: 18 - main: Main { - env: ["123"] - args: [] - } -} diff --git a/test/test_units/test_kclvm/test_unification/test_data/schema_with_list.vertex b/test/test_units/test_kclvm/test_unification/test_data/schema_with_list.vertex deleted file mode 100644 index 28ebe660c..000000000 --- a/test/test_units/test_kclvm/test_unification/test_data/schema_with_list.vertex +++ /dev/null @@ -1,42 +0,0 @@ -name: @root -is_unique: False -adjs: - name: _main - is_unique: False - config_name: Main - adjs: - name: env - is_unique: False - value: , ]> - - name: args - is_unique: False - value: ]> - - name: config - is_unique: False - config_name: Config - adjs: - name: name - is_unique: False - value: - - name: main - is_unique: False - value: - - name: main - is_unique: False - config_name: Main - adjs: - name: env - is_unique: False - value: ]> - - name: args - is_unique: False - value: - - name: age - is_unique: False - value: diff --git a/test/test_units/test_kclvm/test_unification/test_data/single.code b/test/test_units/test_kclvm/test_unification/test_data/single.code deleted file mode 100644 index 94475c2ff..000000000 --- a/test/test_units/test_kclvm/test_unification/test_data/single.code +++ /dev/null @@ -1,7 +0,0 @@ -config = Config { - labels: { - env1 = "v1" - env2 = "v2" - env3 = "v3" - } -} diff --git a/test/test_units/test_kclvm/test_unification/test_data/single.input b/test/test_units/test_kclvm/test_unification/test_data/single.input deleted file mode 100644 index 2b5a96181..000000000 --- a/test/test_units/test_kclvm/test_unification/test_data/single.input +++ /dev/null @@ -1,12 +0,0 @@ -schema Config: - name?: str - args?: [str] - labels?: {str:} - -config = Config { - labels.env1 = "v1" - labels.env2 = "v2" - labels: { - env3 = "v3" - } -} diff --git a/test/test_units/test_kclvm/test_unification/test_data/single.vertex b/test/test_units/test_kclvm/test_unification/test_data/single.vertex deleted file mode 100644 index 415949e6e..000000000 --- a/test/test_units/test_kclvm/test_unification/test_data/single.vertex +++ /dev/null @@ -1,21 +0,0 @@ -name: @root -is_unique: False -adjs: - name: config - is_unique: False - config_name: Config - adjs: - name: labels - is_unique: False - adjs: - name: env1 - is_unique: False - value: - - name: env2 - is_unique: False - value: - - name: env3 - is_unique: False - value: diff --git a/test/test_units/test_kclvm/test_unification/test_data/str_interpolation.code b/test/test_units/test_kclvm/test_unification/test_data/str_interpolation.code deleted file mode 100644 index a0a68ab3d..000000000 --- a/test/test_units/test_kclvm/test_unification/test_data/str_interpolation.code +++ /dev/null @@ -1,5 +0,0 @@ -key = "age" -alice = Person { - name: "Alice" - "${key}": 18 -} diff --git a/test/test_units/test_kclvm/test_unification/test_data/str_interpolation.input b/test/test_units/test_kclvm/test_unification/test_data/str_interpolation.input deleted file mode 100644 index 19960eeaa..000000000 --- a/test/test_units/test_kclvm/test_unification/test_data/str_interpolation.input +++ /dev/null @@ -1,9 +0,0 @@ -schema Person: - name: str - age: int - -key = "age" -alice = Person { - name: "Alice" -} -alice = {"${key}": 18} diff --git a/test/test_units/test_kclvm/test_unification/test_data/str_interpolation.vertex b/test/test_units/test_kclvm/test_unification/test_data/str_interpolation.vertex deleted file mode 100644 index 3972eb7d2..000000000 --- a/test/test_units/test_kclvm/test_unification/test_data/str_interpolation.vertex +++ /dev/null @@ -1,18 +0,0 @@ -name: @root -is_unique: False -adjs: - name: key - is_unique: False - value: - - name: alice - is_unique: False - config_name: Person - adjs: - name: name - is_unique: False - value: - - name: - is_unique: False - value: diff --git a/test/test_units/test_kclvm/test_unification/test_data/unification.code b/test/test_units/test_kclvm/test_unification/test_data/unification.code deleted file mode 100644 index ed1328819..000000000 --- a/test/test_units/test_kclvm/test_unification/test_data/unification.code +++ /dev/null @@ -1,17 +0,0 @@ -schema Config: - """Config Definition""" - name?: str - args: [str] - labels: {str:} - -config: Config { - name: "config1" # Literal Initial - args: ["kcl", "main.k"] # List Initial - labels.key1: "value1" # Dict Initial -} - -config: Config { - name = "config2" # Literal Override - args: ["kcl2"] # List Override - labels: {key2: "value2"} # Dict Unification -} diff --git a/test/test_units/test_kclvm/test_unification/test_data/unification.input b/test/test_units/test_kclvm/test_unification/test_data/unification.input deleted file mode 100644 index ed1328819..000000000 --- a/test/test_units/test_kclvm/test_unification/test_data/unification.input +++ /dev/null @@ -1,17 +0,0 @@ -schema Config: - """Config Definition""" - name?: str - args: [str] - labels: {str:} - -config: Config { - name: "config1" # Literal Initial - args: ["kcl", "main.k"] # List Initial - labels.key1: "value1" # Dict Initial -} - -config: Config { - name = "config2" # Literal Override - args: ["kcl2"] # List Override - labels: {key2: "value2"} # Dict Unification -} diff --git a/test/test_units/test_kclvm/test_unification/test_data/unification.vertex b/test/test_units/test_kclvm/test_unification/test_data/unification.vertex deleted file mode 100644 index 4f97906d1..000000000 --- a/test/test_units/test_kclvm/test_unification/test_data/unification.vertex +++ /dev/null @@ -1,33 +0,0 @@ -name: @root -is_unique: False -adjs: - name: config - is_unique: False - config_name: Config - adjs: - name: name - is_unique: False - value: - - name: name - is_unique: False - value: - - name: args - is_unique: False - value: , ]> - - name: args - is_unique: False - value: ]> - - name: labels - is_unique: False - adjs: - name: key1 - is_unique: False - value: - - name: key2 - is_unique: False - value: diff --git a/test/test_units/test_kclvm/test_unification/test_data/unpack.code b/test/test_units/test_kclvm/test_unification/test_data/unpack.code deleted file mode 100644 index 77231632d..000000000 --- a/test/test_units/test_kclvm/test_unification/test_data/unpack.code +++ /dev/null @@ -1,14 +0,0 @@ -schema Person: - name: str - age: int - -_base = { - name = "Bob" - age = 18 -} - -alice = Person { - **_base - name = "Alice" - age = 18 -} diff --git a/test/test_units/test_kclvm/test_unification/test_data/unpack.input b/test/test_units/test_kclvm/test_unification/test_data/unpack.input deleted file mode 100644 index 241949694..000000000 --- a/test/test_units/test_kclvm/test_unification/test_data/unpack.input +++ /dev/null @@ -1,17 +0,0 @@ -schema Person: - name: str - age: int - -_base = { - name = "Bob" - age = 18 -} - -alice = Person { - **_base -} - -alice = Person { - name = "Alice" - age = 18 -} diff --git a/test/test_units/test_kclvm/test_unification/test_data/unpack.vertex b/test/test_units/test_kclvm/test_unification/test_data/unpack.vertex deleted file mode 100644 index fef1e9afe..000000000 --- a/test/test_units/test_kclvm/test_unification/test_data/unpack.vertex +++ /dev/null @@ -1,29 +0,0 @@ -name: @root -is_unique: False -adjs: - name: _base - is_unique: False - adjs: - name: name - is_unique: False - value: - - name: age - is_unique: False - value: - - name: alice - is_unique: False - config_name: Person - adjs: - name: None - is_unique: False - value: - - name: name - is_unique: False - value: - - name: age - is_unique: False - value: diff --git a/test/test_units/test_kclvm/test_unification/test_merge.py b/test/test_units/test_kclvm/test_unification/test_merge.py deleted file mode 100644 index f1f47ef09..000000000 --- a/test/test_units/test_kclvm/test_unification/test_merge.py +++ /dev/null @@ -1,101 +0,0 @@ -#! /usr/bin/env python3 - -import unittest - -import kclvm.kcl.ast as ast -import kclvm.kcl.error as kcl_error -from kclvm.compiler.parser import ParseFile -from kclvm.unification import MergeAST, MergeASTList - -codes = [ - """ -schema Person: - name: str - age: int - labels: {str:} - -person = Person { - name: "Alice" -} -person = Person { - labels.key: "value" -} -""", - """ -person = Person { - age: 18 -} -persons = Person.instances() -""", -] -type_merge_not_conflict_case = """\ -schema Id1: - id1?: int - -schema Id2: - id2?: int - -schema Data: - id?: Id1 | Id2 - -data = Data { - id = Id1 {id1 = 1} - id = Id2 {id2 = 2} -} -""" -type_merge_conflict_case = """\ -schema Id1: - id1?: int - -schema Id2: - id2?: int - -schema Data: - id?: Id1 | Id2 - -data = Data { - id: Id1 {id1 = 1} - id: Id2 {id2 = 2} -} -""" - - -class KCLMergeTest(unittest.TestCase): - def setUp(self): - self.maxDiff = None - self.modules = [ParseFile(f"test-{i}.k", code) for i, code in enumerate(codes)] - return super().setUp() - - def test_merge(self): - module = MergeAST(self.modules[0]) - self.assertEqual(len(module.body), 2) - self.assertIsInstance(module.body[0], ast.SchemaStmt) - self.assertIsInstance(module.body[1], ast.AssignStmt) - self.assertEqual(len(module.body[1].value.config.items), 2) - self.assertEqual(module.body[1].value.config.keys[0].get_name(), "name") - self.assertEqual(module.body[1].value.config.keys[1].get_name(), "labels") - - def test_merge_list(self): - modules = MergeASTList(self.modules) - self.assertEqual(len(modules), 2) - # The first module - self.assertEqual(len(modules[0].body), 1) - self.assertIsInstance(modules[0].body[0], ast.SchemaStmt) - # The second module - self.assertIsInstance(modules[1].body[0], ast.AssignStmt) - self.assertEqual(len(modules[1].body[0].value.config.items), 3) - self.assertEqual(modules[1].body[0].value.config.keys[0].get_name(), "name") - self.assertEqual(modules[1].body[0].value.config.keys[1].get_name(), "labels") - self.assertEqual(modules[1].body[0].value.config.keys[2].get_name(), "age") - - def test_merge_type_conflict(self): - module = ParseFile("type_merge_not_conflict_case", type_merge_not_conflict_case) - module = MergeASTList([module]) - module = ParseFile("type_merge_conflict_case", type_merge_conflict_case) - with self.assertRaises(kcl_error.CompileError) as err: - module = MergeASTList([module]) - self.assertIn("conflict unification types between Id2 and Id1", str(err.exception)) - - -if __name__ == "__main__": - unittest.main(verbosity=2) diff --git a/test/test_units/test_kclvm/test_unification/test_subsume.py b/test/test_units/test_kclvm/test_unification/test_subsume.py deleted file mode 100644 index 283b8a57b..000000000 --- a/test/test_units/test_kclvm/test_unification/test_subsume.py +++ /dev/null @@ -1,360 +0,0 @@ -#! /usr/bin/env python3 - -import os -import unittest -import pathlib -from typing import Tuple - -import kclvm.api.object as obj -import kclvm.kcl.types as types -from kclvm.compiler.parser import ParseFile -from kclvm.unification import value_subsume, type_subsume - -VALUE1_KEY = "value1" -VALUE2_KEY = "value2" -EXPECTED_KEY = "expected" - - -class KCLSubsumeTest(unittest.TestCase): - def test_value_subsume(self): - cases = [ - # Left None - {VALUE1_KEY: None, VALUE2_KEY: 1, EXPECTED_KEY: True}, - {VALUE1_KEY: None, VALUE2_KEY: 1.1, EXPECTED_KEY: True}, - {VALUE1_KEY: None, VALUE2_KEY: [], EXPECTED_KEY: True}, - {VALUE1_KEY: None, VALUE2_KEY: {}, EXPECTED_KEY: True}, - {VALUE1_KEY: None, VALUE2_KEY: "s", EXPECTED_KEY: True}, - {VALUE1_KEY: None, VALUE2_KEY: True, EXPECTED_KEY: True}, - {VALUE1_KEY: None, VALUE2_KEY: False, EXPECTED_KEY: True}, - {VALUE1_KEY: None, VALUE2_KEY: None, EXPECTED_KEY: True}, - # Right None - {VALUE1_KEY: 1, VALUE2_KEY: None, EXPECTED_KEY: True}, - {VALUE1_KEY: 1.1, VALUE2_KEY: None, EXPECTED_KEY: True}, - {VALUE1_KEY: [], VALUE2_KEY: None, EXPECTED_KEY: True}, - {VALUE1_KEY: {}, VALUE2_KEY: None, EXPECTED_KEY: True}, - {VALUE1_KEY: "s", VALUE2_KEY: None, EXPECTED_KEY: True}, - {VALUE1_KEY: True, VALUE2_KEY: None, EXPECTED_KEY: True}, - {VALUE1_KEY: False, VALUE2_KEY: None, EXPECTED_KEY: True}, - {VALUE1_KEY: None, VALUE2_KEY: None, EXPECTED_KEY: True}, - # Left Undefined - {VALUE1_KEY: obj.Undefined, VALUE2_KEY: 1, EXPECTED_KEY: True}, - {VALUE1_KEY: obj.Undefined, VALUE2_KEY: 1.1, EXPECTED_KEY: True}, - {VALUE1_KEY: obj.Undefined, VALUE2_KEY: [], EXPECTED_KEY: True}, - {VALUE1_KEY: obj.Undefined, VALUE2_KEY: {}, EXPECTED_KEY: True}, - {VALUE1_KEY: obj.Undefined, VALUE2_KEY: "s", EXPECTED_KEY: True}, - {VALUE1_KEY: obj.Undefined, VALUE2_KEY: True, EXPECTED_KEY: True}, - {VALUE1_KEY: obj.Undefined, VALUE2_KEY: False, EXPECTED_KEY: True}, - {VALUE1_KEY: obj.Undefined, VALUE2_KEY: None, EXPECTED_KEY: True}, - # Right Undefined - {VALUE1_KEY: 1, VALUE2_KEY: obj.Undefined, EXPECTED_KEY: True}, - {VALUE1_KEY: 1.1, VALUE2_KEY: obj.Undefined, EXPECTED_KEY: True}, - {VALUE1_KEY: [], VALUE2_KEY: obj.Undefined, EXPECTED_KEY: True}, - {VALUE1_KEY: {}, VALUE2_KEY: obj.Undefined, EXPECTED_KEY: True}, - {VALUE1_KEY: "s", VALUE2_KEY: obj.Undefined, EXPECTED_KEY: True}, - {VALUE1_KEY: True, VALUE2_KEY: obj.Undefined, EXPECTED_KEY: True}, - {VALUE1_KEY: False, VALUE2_KEY: obj.Undefined, EXPECTED_KEY: True}, - {VALUE1_KEY: None, VALUE2_KEY: obj.Undefined, EXPECTED_KEY: True}, - # Int - {VALUE1_KEY: 1, VALUE2_KEY: 1, EXPECTED_KEY: True}, - {VALUE1_KEY: 1, VALUE2_KEY: 2, EXPECTED_KEY: False}, - {VALUE1_KEY: 1, VALUE2_KEY: 1.0, EXPECTED_KEY: False}, - {VALUE1_KEY: 1, VALUE2_KEY: 1.1, EXPECTED_KEY: False}, - {VALUE1_KEY: 1, VALUE2_KEY: [], EXPECTED_KEY: False}, - {VALUE1_KEY: 1, VALUE2_KEY: {}, EXPECTED_KEY: False}, - {VALUE1_KEY: 1, VALUE2_KEY: "s", EXPECTED_KEY: False}, - {VALUE1_KEY: 1, VALUE2_KEY: True, EXPECTED_KEY: False}, - {VALUE1_KEY: 1, VALUE2_KEY: False, EXPECTED_KEY: False}, - # Float - {VALUE1_KEY: 1.1, VALUE2_KEY: 1, EXPECTED_KEY: False}, - {VALUE1_KEY: 1.1, VALUE2_KEY: 2, EXPECTED_KEY: False}, - {VALUE1_KEY: 1.1, VALUE2_KEY: 1.0, EXPECTED_KEY: False}, - {VALUE1_KEY: 1.1, VALUE2_KEY: 1.1, EXPECTED_KEY: True}, - {VALUE1_KEY: 1.1, VALUE2_KEY: [], EXPECTED_KEY: False}, - {VALUE1_KEY: 1.1, VALUE2_KEY: {}, EXPECTED_KEY: False}, - {VALUE1_KEY: 1.1, VALUE2_KEY: "s", EXPECTED_KEY: False}, - {VALUE1_KEY: 1.1, VALUE2_KEY: True, EXPECTED_KEY: False}, - {VALUE1_KEY: 1.1, VALUE2_KEY: False, EXPECTED_KEY: False}, - # String - {VALUE1_KEY: "s", VALUE2_KEY: 1, EXPECTED_KEY: False}, - {VALUE1_KEY: "s", VALUE2_KEY: 2, EXPECTED_KEY: False}, - {VALUE1_KEY: "s", VALUE2_KEY: 1.0, EXPECTED_KEY: False}, - {VALUE1_KEY: "s", VALUE2_KEY: 1.1, EXPECTED_KEY: False}, - {VALUE1_KEY: "s", VALUE2_KEY: [], EXPECTED_KEY: False}, - {VALUE1_KEY: "s", VALUE2_KEY: {}, EXPECTED_KEY: False}, - {VALUE1_KEY: "s", VALUE2_KEY: "s", EXPECTED_KEY: True}, - {VALUE1_KEY: "s", VALUE2_KEY: "", EXPECTED_KEY: False}, - {VALUE1_KEY: "s", VALUE2_KEY: "ss", EXPECTED_KEY: False}, - {VALUE1_KEY: "s", VALUE2_KEY: True, EXPECTED_KEY: False}, - {VALUE1_KEY: "s", VALUE2_KEY: False, EXPECTED_KEY: False}, - # Boolean True - {VALUE1_KEY: True, VALUE2_KEY: 1, EXPECTED_KEY: False}, - {VALUE1_KEY: True, VALUE2_KEY: 2, EXPECTED_KEY: False}, - {VALUE1_KEY: True, VALUE2_KEY: 1.0, EXPECTED_KEY: False}, - {VALUE1_KEY: True, VALUE2_KEY: 1.1, EXPECTED_KEY: False}, - {VALUE1_KEY: True, VALUE2_KEY: [], EXPECTED_KEY: False}, - {VALUE1_KEY: True, VALUE2_KEY: {}, EXPECTED_KEY: False}, - {VALUE1_KEY: True, VALUE2_KEY: "s", EXPECTED_KEY: False}, - {VALUE1_KEY: True, VALUE2_KEY: "", EXPECTED_KEY: False}, - {VALUE1_KEY: True, VALUE2_KEY: "ss", EXPECTED_KEY: False}, - {VALUE1_KEY: True, VALUE2_KEY: True, EXPECTED_KEY: True}, - {VALUE1_KEY: True, VALUE2_KEY: False, EXPECTED_KEY: False}, - # Boolean False - {VALUE1_KEY: False, VALUE2_KEY: 1, EXPECTED_KEY: False}, - {VALUE1_KEY: False, VALUE2_KEY: 2, EXPECTED_KEY: False}, - {VALUE1_KEY: False, VALUE2_KEY: 1.0, EXPECTED_KEY: False}, - {VALUE1_KEY: False, VALUE2_KEY: 1.1, EXPECTED_KEY: False}, - {VALUE1_KEY: False, VALUE2_KEY: [], EXPECTED_KEY: False}, - {VALUE1_KEY: False, VALUE2_KEY: {}, EXPECTED_KEY: False}, - {VALUE1_KEY: False, VALUE2_KEY: "s", EXPECTED_KEY: False}, - {VALUE1_KEY: False, VALUE2_KEY: "", EXPECTED_KEY: False}, - {VALUE1_KEY: False, VALUE2_KEY: "ss", EXPECTED_KEY: False}, - {VALUE1_KEY: False, VALUE2_KEY: True, EXPECTED_KEY: False}, - {VALUE1_KEY: False, VALUE2_KEY: False, EXPECTED_KEY: True}, - # List - {VALUE1_KEY: [], VALUE2_KEY: 1, EXPECTED_KEY: False}, - {VALUE1_KEY: [], VALUE2_KEY: 2, EXPECTED_KEY: False}, - {VALUE1_KEY: [], VALUE2_KEY: 1.0, EXPECTED_KEY: False}, - {VALUE1_KEY: [], VALUE2_KEY: 1.1, EXPECTED_KEY: False}, - {VALUE1_KEY: [], VALUE2_KEY: [], EXPECTED_KEY: True}, - {VALUE1_KEY: [], VALUE2_KEY: {}, EXPECTED_KEY: False}, - {VALUE1_KEY: [], VALUE2_KEY: "s", EXPECTED_KEY: False}, - {VALUE1_KEY: [], VALUE2_KEY: True, EXPECTED_KEY: False}, - {VALUE1_KEY: [], VALUE2_KEY: False, EXPECTED_KEY: False}, - {VALUE1_KEY: [1], VALUE2_KEY: [1], EXPECTED_KEY: True}, - {VALUE1_KEY: [1], VALUE2_KEY: [2], EXPECTED_KEY: False}, - {VALUE1_KEY: [1], VALUE2_KEY: [1, 1], EXPECTED_KEY: False}, - { - VALUE1_KEY: [{"key1": "value1"}], - VALUE2_KEY: [{"key1": "value1"}], - EXPECTED_KEY: True, - }, - { - VALUE1_KEY: [{"key1": "value1"}], - VALUE2_KEY: [{"key1": "value2"}], - EXPECTED_KEY: False, - }, - { - VALUE1_KEY: [{"key1": "value1"}], - VALUE2_KEY: [{"key2": "value2"}], - EXPECTED_KEY: True, - }, - { - VALUE1_KEY: [{"key1": "value1"}], - VALUE2_KEY: [{"key1": "value1", "key2": "value2"}], - EXPECTED_KEY: True, - }, - { - VALUE1_KEY: [{"key1": "value1"}], - VALUE2_KEY: [{"key2": "value2", "key1": "value1"}], - EXPECTED_KEY: True, - }, - { - VALUE1_KEY: [{"key1": "value1", "key2": "value2"}], - VALUE2_KEY: [{"key1": "value1"}], - EXPECTED_KEY: True, - }, - # Dict - {VALUE1_KEY: {}, VALUE2_KEY: 1, EXPECTED_KEY: False}, - {VALUE1_KEY: {}, VALUE2_KEY: 2, EXPECTED_KEY: False}, - {VALUE1_KEY: {}, VALUE2_KEY: 1.0, EXPECTED_KEY: False}, - {VALUE1_KEY: {}, VALUE2_KEY: 1.1, EXPECTED_KEY: False}, - {VALUE1_KEY: {}, VALUE2_KEY: [], EXPECTED_KEY: False}, - {VALUE1_KEY: {}, VALUE2_KEY: {}, EXPECTED_KEY: True}, - {VALUE1_KEY: {}, VALUE2_KEY: "s", EXPECTED_KEY: False}, - {VALUE1_KEY: {}, VALUE2_KEY: True, EXPECTED_KEY: False}, - {VALUE1_KEY: {}, VALUE2_KEY: False, EXPECTED_KEY: False}, - {VALUE1_KEY: {}, VALUE2_KEY: {"key1": "value1"}, EXPECTED_KEY: True}, - {VALUE1_KEY: {"key1": "value1"}, VALUE2_KEY: {}, EXPECTED_KEY: True}, - { - VALUE1_KEY: {"key1": "value1"}, - VALUE2_KEY: {"key1": "value1"}, - EXPECTED_KEY: True, - }, - { - VALUE1_KEY: {"key1": "value1"}, - VALUE2_KEY: {"key1": "value1", "key2": "value2"}, - EXPECTED_KEY: True, - }, - { - VALUE1_KEY: {"key1": "value1", "key2": "value2"}, - VALUE2_KEY: {"key1": "value1"}, - EXPECTED_KEY: True, - }, - { - VALUE1_KEY: {"s": {"key1": "value1"}}, - VALUE2_KEY: {"s": {"key1": "value1", "key2": "value2"}}, - EXPECTED_KEY: True, - }, - { - VALUE1_KEY: {"s": {"key1": "value1", "key2": "value2"}}, - VALUE2_KEY: {"s": {"key1": "value1"}}, - EXPECTED_KEY: True, - }, - { - VALUE1_KEY: {"key2": "value2", "key1": "value1"}, - VALUE2_KEY: {"key1": "value1", "key2": "value2"}, - EXPECTED_KEY: True, - }, - { - VALUE1_KEY: {"key2": "value2", "key1": "value1"}, - VALUE2_KEY: {"key1": "value1", "key2": "value2"}, - EXPECTED_KEY: True, - }, - # Schema - ] - for case in cases: - try: - value1 = obj.to_kcl_obj(case[VALUE1_KEY]) - value2 = obj.to_kcl_obj(case[VALUE2_KEY]) - expected = case[EXPECTED_KEY] - self.assertEqual(value_subsume(value1, value2), expected) - except AssertionError as err: - print( - f"Assert fail between the value1 {obj.to_python_obj(value1)} and the value2 {obj.to_python_obj(value2)}" - ) - raise err - - def test_type_subsume(self): - cases = [ - # The same types - {VALUE1_KEY: None, VALUE2_KEY: None, EXPECTED_KEY: False}, - {VALUE1_KEY: 1, VALUE2_KEY: 2, EXPECTED_KEY: False}, - { - VALUE1_KEY: obj.NONE_INSTANCE, - VALUE2_KEY: obj.NONE_INSTANCE, - EXPECTED_KEY: True, - }, - { - VALUE1_KEY: types.ANY_TYPE, - VALUE2_KEY: types.ANY_TYPE, - EXPECTED_KEY: True, - }, - { - VALUE1_KEY: types.STR_TYPE, - VALUE2_KEY: types.STR_TYPE, - EXPECTED_KEY: True, - }, - { - VALUE1_KEY: types.INT_TYPE, - VALUE2_KEY: types.INT_TYPE, - EXPECTED_KEY: True, - }, - { - VALUE1_KEY: types.FLOAT_TYPE, - VALUE2_KEY: types.FLOAT_TYPE, - EXPECTED_KEY: True, - }, - { - VALUE1_KEY: types.BOOL_TYPE, - VALUE2_KEY: types.BOOL_TYPE, - EXPECTED_KEY: True, - }, - { - VALUE1_KEY: types.NONE_TYPE, - VALUE2_KEY: types.BOOL_TYPE, - EXPECTED_KEY: True, - }, - { - VALUE1_KEY: types.INT_TYPE, - VALUE2_KEY: types.FLOAT_TYPE, - EXPECTED_KEY: True, - }, - { - VALUE1_KEY: types.DICT_STR_ANY_TYPE, - VALUE2_KEY: types.DICT_STR_ANY_TYPE, - EXPECTED_KEY: True, - }, - { - VALUE1_KEY: types.DICT_STR_STR_TYPE, - VALUE2_KEY: types.DICT_STR_ANY_TYPE, - EXPECTED_KEY: True, - }, - { - VALUE1_KEY: obj.KCLIntLitTypeObject(1), - VALUE2_KEY: types.INT_TYPE, - EXPECTED_KEY: True, - }, - { - VALUE1_KEY: obj.KCLFloatLitTypeObject(1.0), - VALUE2_KEY: types.FLOAT_TYPE, - EXPECTED_KEY: True, - }, - { - VALUE1_KEY: obj.KCLStringLitTypeObject("s"), - VALUE2_KEY: types.STR_TYPE, - EXPECTED_KEY: True, - }, - { - VALUE1_KEY: types.TRUE_LIT_TYPE, - VALUE2_KEY: types.BOOL_TYPE, - EXPECTED_KEY: True, - }, - { - VALUE1_KEY: types.INT_TYPE, - VALUE2_KEY: obj.KCLUnionTypeObject([types.INT_TYPE, types.STR_TYPE]), - EXPECTED_KEY: True, - }, - { - VALUE1_KEY: types.STR_TYPE, - VALUE2_KEY: obj.KCLUnionTypeObject([types.INT_TYPE, types.STR_TYPE]), - EXPECTED_KEY: True, - }, - { - VALUE1_KEY: types.INT_OR_STR_TYPE, - VALUE2_KEY: obj.KCLUnionTypeObject([types.STR_TYPE, types.INT_TYPE]), - EXPECTED_KEY: True, - }, - { - VALUE1_KEY: obj.KCLIntObject(1), - VALUE2_KEY: obj.KCLUnionTypeObject([types.STR_TYPE, types.INT_TYPE]), - EXPECTED_KEY: False, - }, - { - VALUE1_KEY: obj.KCLIntLitTypeObject(1), - VALUE2_KEY: obj.KCLUnionTypeObject( - types=[ - obj.KCLIntLitTypeObject(1), - types.TRUE_LIT_TYPE, - obj.KCLStringLitTypeObject("aaa"), - ] - ), - EXPECTED_KEY: True, - }, - { - VALUE1_KEY: obj.KCLNumberMultiplierTypeObject( - value=1024, - raw_value=1, - binary_suffix="1Mi" - ), - VALUE2_KEY: obj.KCLNumberMultiplierTypeObject( - value=1024, - raw_value=1, - binary_suffix="1Mi" - ), - EXPECTED_KEY: True, - }, - { - VALUE1_KEY: obj.KCLNumberMultiplierTypeObject(), - VALUE2_KEY: obj.KCLNumberMultiplierTypeObject( - value=1024, - raw_value=1, - binary_suffix="1Mi" - ), - EXPECTED_KEY: True, - }, - ] - for case in cases: - type1, type2, expected = ( - case[VALUE1_KEY], - case[VALUE2_KEY], - case[EXPECTED_KEY], - ) - self.assertEqual( - type_subsume(type1, type2), - expected, - msg=f"Assert error between {type1} and {type2}", - ) - - -if __name__ == "__main__": - unittest.main(verbosity=2) diff --git a/test/test_units/test_kclvm/test_unification/test_unifier.py b/test/test_units/test_kclvm/test_unification/test_unifier.py deleted file mode 100644 index 33a9e92d2..000000000 --- a/test/test_units/test_kclvm/test_unification/test_unifier.py +++ /dev/null @@ -1,98 +0,0 @@ -#! /usr/bin/env python3 - -import os -import unittest -import pathlib -from typing import Tuple - -import kclvm.kcl.ast as ast -from kclvm.compiler.parser import ParseFile -from kclvm.compiler.astutil.filter import filter_stmt -from kclvm.unification import MergeASTToVertex, MergeStrategy, Vertex - - -_FILE_INPUT_SUFFIX = ".input" -_FILE_VERTEX_SUFFIX = ".vertex" -_FILE_CODE_SUFFIX = ".code" -_PATH_NAME = "test_data" -_DIR_PATH = pathlib.Path(__file__).parent.joinpath(_PATH_NAME) -_TEST_CASE_NAMES = [ - "collection_if", - "empty", - "insert", - "int_dict", - "nest_declaration", - "nest_var_0", - "nest_var_1", - "override", - "schema_and_dict", - "schema_with_list", - "schema", - "single", - "str_interpolation", - "unification", - "unpack", -] - - -class KCLUnifierBaseTest(unittest.TestCase): - def setUp(self): - self.maxDiff = None - self.test_cases = [self.read_data(case) for case in _TEST_CASE_NAMES] - - def read_data_with_suffix(self, data_name: str, suffix: str): - return (_DIR_PATH / (data_name + suffix)).read_text() - - def read_data(self, data_name: str) -> Tuple[str, str]: - """Read test data""" - data_input = self.read_data_with_suffix(data_name, _FILE_INPUT_SUFFIX) - data_vertex = self.read_data_with_suffix(data_name, _FILE_VERTEX_SUFFIX) - data_code = self.read_data_with_suffix(data_name, _FILE_CODE_SUFFIX) - return data_input, data_vertex, data_code - - def assert_vertex_unify_equal( - self, - input_str: str, - vertex_str: str, - code_str: str, - strategy: MergeStrategy = MergeStrategy.UNION, - msg=None, - ): - origin_module = ParseFile("", input_str) - code_module = ParseFile("", code_str) - origin_vertex, unify_vertex, merge_module = MergeASTToVertex(origin_module) - # TODO: Optimize the function test to smaller granularity test. @lingzhi.xpf - self.assertEqual(unify_vertex.pretty(), vertex_str, msg=msg) - - -class KCLUnifierTest(KCLUnifierBaseTest): - def test_vertex_unification(self) -> None: - for input, vertex, code in self.test_cases: - self.assert_vertex_unify_equal(input, vertex, code, msg=f"the fail code is\n{code}") - - def test_vertex_override_merge(self) -> None: - for input, vertex, code in self.test_cases: - self.assert_vertex_unify_equal(input, vertex, code, MergeStrategy.OVERRIDE) - - -def print_vertex_unification_result(test_file: str): - """Print vertex unification result - - Usage: - print_vertex_unification_result("schema.input") - """ - if not test_file: - return - filename = str(pathlib.Path(__file__).parent.joinpath(_DIR_PATH, test_file)) - module = ParseFile(filename) - vertex, unify_vertex, merged_module = MergeASTToVertex(module) - print("Origin vertex formed by AST as follows:\n") - print(vertex.pretty()) - print("Unify vertex result as follows:\n") - print(unify_vertex.pretty()) - print("Merged AST as follows:\n") - print(merged_module.to_json()) - - -if __name__ == "__main__": - unittest.main(verbosity=2) diff --git a/test/test_units/test_kclvm/test_vm/invalid_test_data/recursive.k b/test/test_units/test_kclvm/test_vm/invalid_test_data/recursive.k deleted file mode 100644 index 778942b3d..000000000 --- a/test/test_units/test_kclvm/test_vm/invalid_test_data/recursive.k +++ /dev/null @@ -1,13 +0,0 @@ -schema Son: - son_field: str - parent: Parent = None - -schema Parent[name](Son): - field: str = name - son: Son = Son { - parent: Parent(name) { - "field": "123" - } - } - -parent = Parent(name = "123") {} diff --git a/test/test_units/test_kclvm/test_vm/invalid_test_data/unification.k b/test/test_units/test_kclvm/test_vm/invalid_test_data/unification.k deleted file mode 100644 index 7926dd595..000000000 --- a/test/test_units/test_kclvm/test_vm/invalid_test_data/unification.k +++ /dev/null @@ -1 +0,0 @@ -data = {id: 1} | {id: 2} \ No newline at end of file diff --git a/test/test_units/test_kclvm/test_vm/test_code.py b/test/test_units/test_kclvm/test_vm/test_code.py deleted file mode 100644 index c0ef13c09..000000000 --- a/test/test_units/test_kclvm/test_vm/test_code.py +++ /dev/null @@ -1,61 +0,0 @@ -# Copyright 2021 The KCL Authors. All rights reserved. - -import pathlib -import unittest - -import kclvm.compiler.parser as parser -import kclvm.compiler.build.compiler as compiler -import kclvm.vm.code.code as code -import kclvm.vm.code.code_factory as code_factory -import kclvm.vm as vm - - -TEST_PKG_PATH = "__main__" -TEST_FILE_META = ("main.k", 1, 1) -TEST_SCHEMA_NAME = "TestPerson" -TEST_CODE = """\ -schema Person: - name: str = "Alice" - age: int = 18 - -person = Person {} -""" - - -class VMCodeTest(unittest.TestCase): - def test_code_factory(self): - codes = [code.Opcode.INVALID, code.Opcode.POP_TOP, TEST_FILE_META] - opcode_factory = code_factory.OpcodeFactory.build_from_codes( - codes, TEST_PKG_PATH - ) - opcode_factory.pretty_print() - opcode_factory.values = [] - opcode_factory.pretty_print() - program = compiler.CompileProgram( - parser.LoadProgram(TEST_FILE_META[0], k_code_list=[TEST_CODE]) - ) - opcode_factory = code_factory.SchemaBodyOpcodeFactory.build_from_codes( - program.pkgs[TEST_PKG_PATH].instructions, TEST_PKG_PATH, TEST_SCHEMA_NAME - ) - opcode_factory.pretty_print() - opcode_factory.values = [] - opcode_factory.pretty_print() - - def test_code_actions(self): - program = compiler.CompileProgram( - parser.LoadProgram(TEST_FILE_META[0], k_code_list=[TEST_CODE]) - ) - for opcode in [ - code.Opcode.DEBUG_GLOBALS, - code.Opcode.DEBUG_LOCALS, - code.Opcode.DEBUG_NAMES, - code.Opcode.DEBUG_STACK, - ]: - program.pkgs[TEST_PKG_PATH].instructions.extend( - [opcode, 0, 0, 0, TEST_FILE_META] - ) - vm.Run(program) - - -if __name__ == "__main__": - unittest.main(verbosity=2) diff --git a/test/test_units/test_kclvm/test_vm/test_data/main.k b/test/test_units/test_kclvm/test_vm/test_data/main.k deleted file mode 100644 index eab736f11..000000000 --- a/test/test_units/test_kclvm/test_vm/test_data/main.k +++ /dev/null @@ -1,6 +0,0 @@ -import pkg - -person = pkg.Person { - name = "Alice" - age = 18 -} diff --git a/test/test_units/test_kclvm/test_vm/test_data/pkg/pkg.k b/test/test_units/test_kclvm/test_vm/test_data/pkg/pkg.k deleted file mode 100644 index b4c3153b0..000000000 --- a/test/test_units/test_kclvm/test_vm/test_data/pkg/pkg.k +++ /dev/null @@ -1,3 +0,0 @@ -schema Person: - name: str - age: int diff --git a/test/test_units/test_kclvm/test_vm/test_evaluator.py b/test/test_units/test_kclvm/test_vm/test_evaluator.py deleted file mode 100644 index 2aa96e47b..000000000 --- a/test/test_units/test_kclvm/test_vm/test_evaluator.py +++ /dev/null @@ -1,175 +0,0 @@ -# Copyright 2021 The KCL Authors. All rights reserved. - -import pathlib -import unittest - -import kclvm.kcl.error as kcl_error -import kclvm.api.object as objpkg -import kclvm.vm.code as vm_code -import kclvm.vm.runtime.evaluator.eval as eval - - -class EvaluatorTest(unittest.TestCase): - def setUp(self): - self._evaluator = eval.Evaluator() - return super().setUp() - - def test_eval_binary_op(self): - cases = [ - { - "left": objpkg.KCLIntObject(1), - "right": objpkg.KCLIntObject(1), - "code": vm_code.Opcode.BINARY_ADD, - "expected": objpkg.KCLIntObject(2), - }, - { - "left": objpkg.KCLIntObject(1), - "right": objpkg.KCLIntObject(1), - "code": vm_code.Opcode.BINARY_SUBTRACT, - "expected": objpkg.KCLIntObject(0), - }, - ] - for case in cases: - left, right, code, expected = ( - case["left"], - case["right"], - case["code"], - case["expected"], - ) - result = self._evaluator.eval_binary_op(left, right, code) - self.assertEqual(result, expected) - - def test_eval_binary_op_invalid(self): - cases = [ - {"left": None, "right": None, "code": vm_code.Opcode.BINARY_ADD}, - { - "left": objpkg.KCLIntObject(1), - "right": objpkg.KCLIntObject(1), - "code": vm_code.Opcode.NOP, - }, - ] - for case in cases: - left, right, code = case["left"], case["right"], case["code"] - with self.assertRaises(Exception): - self._evaluator.eval_binary_op(left, right, code) - - def test_eval_compare_op(self): - cases = [ - { - "left": objpkg.KCLIntObject(1), - "right": objpkg.KCLIntObject(1), - "code": vm_code.Opcode.COMPARE_EQUAL_TO, - "expected": objpkg.TRUE_INSTANCE, - }, - { - "left": objpkg.KCLIntObject(1), - "right": objpkg.KCLIntObject(1), - "code": vm_code.Opcode.COMPARE_GREATER_THAN_OR_EQUAL_TO, - "expected": objpkg.TRUE_INSTANCE, - }, - ] - for case in cases: - left, right, code, expected = ( - case["left"], - case["right"], - case["code"], - case["expected"], - ) - result = self._evaluator.eval_compare_op(left, right, code) - self.assertEqual(result, expected) - - def test_eval_compare_op_invalid(self): - cases = [ - {"left": None, "right": None, "code": vm_code.Opcode.BINARY_ADD}, - { - "left": objpkg.KCLIntObject(1), - "right": objpkg.KCLIntObject(1), - "code": vm_code.Opcode.NOP, - }, - ] - for case in cases: - left, right, code = case["left"], case["right"], case["code"] - with self.assertRaises(Exception): - self._evaluator.eval_compare_op(left, right, code) - - def test_eval_unary_op(self): - cases = [ - { - "operand": objpkg.KCLIntObject(1), - "code": vm_code.Opcode.UNARY_POSITIVE, - "expected": objpkg.KCLIntObject(1), - }, - { - "operand": objpkg.KCLIntObject(1), - "code": vm_code.Opcode.UNARY_NEGATIVE, - "expected": objpkg.KCLIntObject(-1), - }, - ] - for case in cases: - operand, code, expected = ( - case["operand"], - case["code"], - case["expected"], - ) - result = self._evaluator.eval_unary_op(operand, code) - self.assertEqual(result, expected) - - def test_eval_unary_op_invalid(self): - cases = [ - {"operand": None, "code": vm_code.Opcode.BINARY_ADD}, - { - "operand": objpkg.KCLIntObject(1), - "code": vm_code.Opcode.NOP, - }, - ] - for case in cases: - operand, code = case["operand"], case["code"] - with self.assertRaises(Exception): - self._evaluator.eval_unary_op(operand, code) - - def test_set_item(self): - cases = [ - { - "operand": objpkg.to_kcl_obj({"key": "value"}), - "item": objpkg.KCLStringObject("key"), - "value": objpkg.KCLStringObject("override"), - "expected": objpkg.to_kcl_obj({"key": "override"}), - }, - { - "operand": objpkg.to_kcl_obj([0, 0]), - "item": objpkg.KCLIntObject(0), - "value": objpkg.KCLIntObject(1), - "expected": objpkg.to_kcl_obj([1, 0]), - }, - ] - for case in cases: - operand, item, value, expected = case["operand"], case["item"], case["value"], case["expected"] - result = self._evaluator.set_item(operand, item, value) - self.assertEqual(result, expected) - - def test_format_value(self): - cases = [ - { - "operand": objpkg.to_kcl_obj({"key": "value"}), - "format_spec": None, - "expected": objpkg.KCLStringObject(value="{'key': 'value'}"), - }, - { - "operand": objpkg.to_kcl_obj({"key": "value"}), - "format_spec": "#json", - "expected": objpkg.KCLStringObject(value='{"key": "value"}'), - }, - { - "operand": objpkg.to_kcl_obj({"key": "value"}), - "format_spec": "#yaml", - "expected": objpkg.KCLStringObject(value='key: value\n'), - }, - ] - for case in cases: - operand, format_spec, expected = case["operand"], case["format_spec"], case["expected"] - result = self._evaluator.format_value(operand, format_spec) - self.assertEqual(result, expected) - - -if __name__ == "__main__": - unittest.main(verbosity=2) diff --git a/test/test_units/test_kclvm/test_vm/test_planner.py b/test/test_units/test_kclvm/test_vm/test_planner.py deleted file mode 100644 index b1c2f4156..000000000 --- a/test/test_units/test_kclvm/test_vm/test_planner.py +++ /dev/null @@ -1,46 +0,0 @@ -# Copyright 2021 The KCL Authors. All rights reserved. - -import unittest - -import kclvm.api.object as objpkg -import kclvm.vm.planner as planner - - -class PlannerTest(unittest.TestCase): - def test_object_planner(self): - cases = [ - {"obj": {"key": 1}, "expected": {"key": 1}}, - { - "obj": {"key": [1, 2, 3]}, - "expected": {"key": [1, 2, 3]}, - }, - { - "obj": {"key": True}, - "expected": {"key": True}, - }, - { - "obj": {"key": {"key": 1}}, - "expected": {"key": {"key": 1}}, - }, - ] - for case in cases: - obj, expected = case["obj"], case["expected"] - self.assertEqual( - planner.ObjectPlanner().to_python(obj), - expected, - msg=f"{obj}", - ) - self.assertEqual( - planner.ObjectPlanner().to_python(objpkg.to_kcl_obj(obj)), - expected, - msg=f"{obj}", - ) - self.assertEqual( - planner.ObjectPlanner().to_python(objpkg.to_kcl_obj(obj).value), - expected, - msg=f"{obj}", - ) - - -if __name__ == "__main__": - unittest.main(verbosity=2) diff --git a/test/test_units/test_kclvm/test_vm/test_vm.py b/test/test_units/test_kclvm/test_vm/test_vm.py deleted file mode 100644 index 5f7cff5de..000000000 --- a/test/test_units/test_kclvm/test_vm/test_vm.py +++ /dev/null @@ -1,71 +0,0 @@ -# Copyright 2021 The KCL Authors. All rights reserved. - -import pathlib -import unittest - -import kclvm.kcl.error as kcl_error -import kclvm.vm as vm -import kclvm.api.object as kcl_object -import kclvm.compiler.parser as parser -import kclvm.compiler.build.compiler as compiler - -from kclvm.api.object import KCLCompiledFunctionObject, Parameter - - -class VMTest(unittest.TestCase): - def get_vm(self, filepath: str) -> vm.VirtualMachine: - program = compiler.CompileProgram(parser.LoadProgram(filepath)) - return vm.VirtualMachine(program) - - def test_vm_run(self): - filepath = str( - pathlib.Path(__file__).parent.joinpath("test_data").joinpath("main.k") - ) - machine = self.get_vm(filepath) - result = machine.Run() - self.assertEqual(result.filename, filepath) - self.assertEqual(list(result.m.keys()), ["person", "@pkg"]) - self.assertEqual(list(machine.state.modules.keys()), ["pkg"]) - self.assertEqual(list(machine.all_schema_types.keys()), ["pkg.Person"]) - self.assertEqual(machine.last_popped_obj(), kcl_object.NONE_INSTANCE) - - def test_vm_invalid_run(self): - filepaths = [ - str( - pathlib.Path(__file__) - .parent.joinpath("invalid_test_data") - .joinpath("unification.k") - ), - str( - pathlib.Path(__file__) - .parent.joinpath("invalid_test_data") - .joinpath("recursive.k") - ), - ] - for filepath in filepaths: - with self.assertRaises(kcl_error.KCLException): - self.get_vm(filepath).Run() - - def test_default_not_full(self): - app = kcl_object.KCLProgram() - app.pkgs = {"testpkg": kcl_object.KCLBytecode()} - app.main = "testpkg" - test_vm = vm.VirtualMachine(app=app) - - test_f = vm.Frame() - test_f.locals = {} - test_f.globals = {} - test_vm.ctx = test_f - - test_func = KCLCompiledFunctionObject(name="test_function") - test_func.params = [ - Parameter(name="test_name", value=kcl_object.to_kcl_obj(10)) - ] - test_vm.push_frame_using_callable( - pkgpath="test_pkg", func=test_func, args=[], kwargs=[] - ) - self.assertEqual(test_vm.ctx.locals["test_name"], kcl_object.to_kcl_obj(10)) - - -if __name__ == "__main__": - unittest.main(verbosity=2) diff --git a/test/test_units/test_langserver/__init__.py b/test/test_units/test_langserver/__init__.py deleted file mode 100644 index 378661dd8..000000000 --- a/test/test_units/test_langserver/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/env python -# -*- coding: UTF-8 -*- - diff --git a/test/test_units/test_langserver/test_common.py b/test/test_units/test_langserver/test_common.py deleted file mode 100644 index 8f8be141e..000000000 --- a/test/test_units/test_langserver/test_common.py +++ /dev/null @@ -1,182 +0,0 @@ -# Copyright 2021 The KCL Authors. All rights reserved. -import unittest -import pathlib -from typing import Optional - -import kclvm.tools.langserver.common as common -import kclvm.kcl.ast as ast -import kclvm.kcl.types.scope as scope - -_TEST_PATH_NAME = "test_data" -_GO_TO_DEF_PATH_NAME = "go_to_def" -_DIR_PATH = ( - pathlib.Path(__file__) - .parent.joinpath(_TEST_PATH_NAME) - .joinpath(_GO_TO_DEF_PATH_NAME) -) - - -class PosToScopeTest(unittest.TestCase): - def test_pos_to_scope(self): - # check invalid pos - pos = ast.Position(line=0, column=0) - _, got, _ = common.pos_to_scope(pos) - self.assertIsNone( - got, f"find scope from invalid position {pos}, expect: None, got: {got}" - ) - - file_path = "invalid_path" - _, got, _ = common.pos_to_scope( - pos=ast.Position(filename=file_path, line=1, column=1) - ) - self.assertIsNone( - got, - f"find scope from invalid file path {file_path}, expect: None, got: {got}", - ) - - file_path = str(_DIR_PATH / "schema.k") - prog = common.file_to_prog(file_path) - prog.pkgs['__main__'][0].body[0].body[0].type_str = None - - _, got = common.file_or_prog_to_scope(prog, file_path) - self.assertIsInstance( - got, - scope.ProgramScope, - f"find scope from invalid prog {file_path}, expect: None, got: {got}" - ) - - -class PosToNodeTestCase: - def __init__( - self, - filename: str, - line: int, - column: int, - name: Optional[str] = None, - start_pos: Optional[ast.Position] = None, - end_pos: Optional[ast.Position] = None, - ): - self.filename: str = filename - self.line: int = line - self.column: int = column - self.name: Optional[str] = name - self.start_pos: Optional[ast.Position] = start_pos - self.end_pos: Optional[ast.Position] = end_pos - - -class PosToNodeTest(unittest.TestCase): - _cases = [ - PosToNodeTestCase( - filename="member_access.k", - line=6, - column=1, - name="name", - start_pos=ast.Position(line=6, column=1), - end_pos=ast.Position(line=6, column=5), - ), - PosToNodeTestCase( - filename="schema.k", - line=5, - column=9, - name="Person", - start_pos=ast.Position(line=5, column=9), - end_pos=ast.Position(line=5, column=15), - ), - PosToNodeTestCase( - filename="simple.k", - line=2, - column=5, - name="d", - start_pos=ast.Position(line=2, column=5), - end_pos=ast.Position(line=2, column=6), - ), - PosToNodeTestCase( - filename="invalid_grammar.k", - line=1, - column=1, - ), - PosToNodeTestCase( - filename="", - line=0, - column=0, - ), - PosToNodeTestCase( - filename="invalid_path.k", - line=1, - column=1, - ), - PosToNodeTestCase( - filename="simple.k", - line=1, - column=3, - ), - ] - - def test_pos_to_node(self): - for t_case in self._cases: - _, node = common.pos_to_node( - pos=ast.Position( - filename=str(_DIR_PATH / t_case.filename), - line=t_case.line, - column=t_case.column, - ), - ) - if node: - self.assertEqual( - str(_DIR_PATH / t_case.filename), - node.filename, - msg="filename not match", - ) - self.assertEqual( - t_case.start_pos.line, - node.line, - msg=f"start line not match. filename={t_case.filename}", - ) - self.assertEqual( - t_case.start_pos.column, - node.column, - msg=f"start column not match. filename={t_case.filename}", - ) - self.assertEqual( - t_case.end_pos.line, - node.end_line, - msg=f"end line not match. filename={t_case.filename}", - ) - self.assertEqual( - t_case.end_pos.column, - node.end_column, - msg=f"end column not match. filename={t_case.filename}", - ) - if isinstance(node, ast.Name): - self.assertEqual( - t_case.name, - node.value, - msg=f"node value not match. filename={t_case.filename}", - ) - else: - self.assertIsNone( - t_case.name, - msg=f"node value not match, filename: {t_case.filename}", - ) - self.assertIsNone( - t_case.start_pos, - msg=f"node start pos not match, filename: {t_case.filename}", - ) - self.assertIsNone( - t_case.end_pos, - msg=f"node end pos not match, filename: {t_case.filename}", - ) - - -class ScopeObjToLocationTest(unittest.TestCase): - def test_scope_obj_to_location_None_input(self): - self.assertIsNone(common.scope_obj_to_location(None)) - self.assertIsNone(common.scope_obj_to_location(scope.ScopeObject(name="mock",node=None,type=None))) - - def test_file_to_location_invalid_path(self): - self.assertIsNone(common.file_to_location(filepath="")) - self.assertIsNone(common.file_to_location(filepath="mock.txt")) - - -if __name__ == "__main__": - unittest.main(verbosity=2) diff --git a/test/test_units/test_langserver/test_complete.py b/test/test_units/test_langserver/test_complete.py deleted file mode 100644 index bed0bce17..000000000 --- a/test/test_units/test_langserver/test_complete.py +++ /dev/null @@ -1,92 +0,0 @@ -import pathlib -import unittest -import typing - -from pygls.lsp.types.language_features.completion import ( - CompletionList, - CompletionItem, - CompletionItemKind, -) - -import kclvm.kcl.ast as ast -from kclvm.tools.langserver.complete import complete - - -_TEST_PATH_NAME = "test_data" -_COMPLETE_PATH_NAME = "complete" -_DIR_PATH = ( - pathlib.Path(__file__) - .parent.joinpath(_TEST_PATH_NAME) - .joinpath(_COMPLETE_PATH_NAME) -) - - -class CompleteTest(unittest.TestCase): - def test_complete(self): - for t_case in test_cases: - got_completions = complete( - pos=ast.Position( - filename=str(_DIR_PATH / t_case.filename), - line=t_case.line, - column=t_case.column, - ), - name=t_case.name, - ) - - expect_completions = t_case.completions - - self.assertEqual( - expect_completions, - got_completions, - f"expect: {expect_completions}, got: {got_completions}", - ) - - -class CompletionTestCase: - def __init__( - self, - filename: str, - line: int, - column: int, - name: str, - completions: typing.List[CompletionItem], - ): - self.filename: str = filename - self.line: int = line - self.column: int = column - self.name: str = name - self.completions: typing.List[CompletionItem] = completions - - -test_cases = [ - CompletionTestCase( - filename="simple.k", - line=2, - column=6, - name="a", - completions=CompletionList( - is_incomplete=False, - items=[ - CompletionItem(label="aa", kind=CompletionItemKind.Value), - CompletionItem(label="abs", kind=CompletionItemKind.Function), - CompletionItem(label="all_true", kind=CompletionItemKind.Function), - CompletionItem(label="any_true", kind=CompletionItemKind.Function), - ], - ).items, - ), - CompletionTestCase( - filename="schema.k", - line=4, - column=8, - name="Per", - completions=CompletionList( - is_incomplete=False, - items=[ - CompletionItem(label="Person", kind=CompletionItemKind.Struct), - ], - ).items, - ), -] - -if __name__ == "__main__": - unittest.main(verbosity=2) diff --git a/test/test_units/test_langserver/test_data/complete/schema.k b/test/test_units/test_langserver/test_data/complete/schema.k deleted file mode 100644 index 7a38bc357..000000000 --- a/test/test_units/test_langserver/test_data/complete/schema.k +++ /dev/null @@ -1,4 +0,0 @@ -schema Person: - name: str - -p = Per \ No newline at end of file diff --git a/test/test_units/test_langserver/test_data/complete/simple.k b/test/test_units/test_langserver/test_data/complete/simple.k deleted file mode 100644 index a8bdfc1cd..000000000 --- a/test/test_units/test_langserver/test_data/complete/simple.k +++ /dev/null @@ -1,2 +0,0 @@ -aa = 2 -b = a diff --git a/test/test_units/test_langserver/test_data/document_symbol/invalid_grammar.k b/test/test_units/test_langserver/test_data/document_symbol/invalid_grammar.k deleted file mode 100644 index 2199c03be..000000000 --- a/test/test_units/test_langserver/test_data/document_symbol/invalid_grammar.k +++ /dev/null @@ -1,2 +0,0 @@ -a = 1 -b = diff --git a/test/test_units/test_langserver/test_data/document_symbol/invalid_semantic.k b/test/test_units/test_langserver/test_data/document_symbol/invalid_semantic.k deleted file mode 100644 index b7fe1e3f7..000000000 --- a/test/test_units/test_langserver/test_data/document_symbol/invalid_semantic.k +++ /dev/null @@ -1,2 +0,0 @@ -a = b -c = a diff --git a/test/test_units/test_langserver/test_data/document_symbol/symbol.k b/test/test_units/test_langserver/test_data/document_symbol/symbol.k deleted file mode 100644 index 0dc451e75..000000000 --- a/test/test_units/test_langserver/test_data/document_symbol/symbol.k +++ /dev/null @@ -1,12 +0,0 @@ -a = b = 1 - -schema Person: - mixin [ - aMixin - ] - age : int = 1 - name : str = "1" - -person = Person { - age = 1 -} \ No newline at end of file diff --git a/test/test_units/test_langserver/test_data/go_to_def/attr.k b/test/test_units/test_langserver/test_data/go_to_def/attr.k deleted file mode 100644 index 69f759620..000000000 --- a/test/test_units/test_langserver/test_data/go_to_def/attr.k +++ /dev/null @@ -1,17 +0,0 @@ -alice_first_name = "alice" - -schema Name: - first: str - last: str - -schema Person: - name: Name - name.first = "a" - name.last = "b" - -alice = Person { - name: { - first = alice_first_name - last = "Green" - } -} diff --git a/test/test_units/test_langserver/test_data/go_to_def/dict_fix_me.k b/test/test_units/test_langserver/test_data/go_to_def/dict_fix_me.k deleted file mode 100644 index 3331f7207..000000000 --- a/test/test_units/test_langserver/test_data/go_to_def/dict_fix_me.k +++ /dev/null @@ -1,24 +0,0 @@ -schema Person: - name: Name - age: int - additional: {str: Info} - -schema Info: - value: str - -schema Name: - first: str - last: str - -alice: Person = { - name: { - first: "alice" - last: "Green" - } - age: 10 - additional: { - hobby: { - value: "piano" - } - } -} \ No newline at end of file diff --git a/test/test_units/test_langserver/test_data/go_to_def/import_module.k b/test/test_units/test_langserver/test_data/go_to_def/import_module.k deleted file mode 100644 index 786ce6978..000000000 --- a/test/test_units/test_langserver/test_data/go_to_def/import_module.k +++ /dev/null @@ -1,9 +0,0 @@ -import .pkg.parent as p - -alice = p.Parent { - name: "alice" -} - -bob = p.Parent_Typo { - name: "alice" -} \ No newline at end of file diff --git a/test/test_units/test_langserver/test_data/go_to_def/inherit.k b/test/test_units/test_langserver/test_data/go_to_def/inherit.k deleted file mode 100644 index a1bef7126..000000000 --- a/test/test_units/test_langserver/test_data/go_to_def/inherit.k +++ /dev/null @@ -1,10 +0,0 @@ -schema Parent: - name: str - -schema Son(Parent): - age: int - son_name: str = name - -schema GrandSon(Son): - grand_son_name: str = name - a: str = name_not_exist diff --git a/test/test_units/test_langserver/test_data/go_to_def/inherit_pkg.k b/test/test_units/test_langserver/test_data/go_to_def/inherit_pkg.k deleted file mode 100644 index 39cdf9b1d..000000000 --- a/test/test_units/test_langserver/test_data/go_to_def/inherit_pkg.k +++ /dev/null @@ -1,4 +0,0 @@ -import pkg - -schema Son(pkg.Parent): - son_name: str = name diff --git a/test/test_units/test_langserver/test_data/go_to_def/invalid_grammar.k b/test/test_units/test_langserver/test_data/go_to_def/invalid_grammar.k deleted file mode 100644 index 2199c03be..000000000 --- a/test/test_units/test_langserver/test_data/go_to_def/invalid_grammar.k +++ /dev/null @@ -1,2 +0,0 @@ -a = 1 -b = diff --git a/test/test_units/test_langserver/test_data/go_to_def/invalid_semantic.k b/test/test_units/test_langserver/test_data/go_to_def/invalid_semantic.k deleted file mode 100644 index b7fe1e3f7..000000000 --- a/test/test_units/test_langserver/test_data/go_to_def/invalid_semantic.k +++ /dev/null @@ -1,2 +0,0 @@ -a = b -c = a diff --git a/test/test_units/test_langserver/test_data/go_to_def/list_comp.k b/test/test_units/test_langserver/test_data/go_to_def/list_comp.k deleted file mode 100644 index 63a9fdc7c..000000000 --- a/test/test_units/test_langserver/test_data/go_to_def/list_comp.k +++ /dev/null @@ -1,7 +0,0 @@ -a = e = 1 - -schema S: - a: str - b: [str] - c: [str] = [a for a in b] - d: int = e diff --git a/test/test_units/test_langserver/test_data/go_to_def/member_access.k b/test/test_units/test_langserver/test_data/go_to_def/member_access.k deleted file mode 100644 index a1ddd16fd..000000000 --- a/test/test_units/test_langserver/test_data/go_to_def/member_access.k +++ /dev/null @@ -1,6 +0,0 @@ -schema Person: - name: str = "default" - -alice = Person{} - -name = alice.name \ No newline at end of file diff --git a/test/test_units/test_langserver/test_data/go_to_def/parent_attr.k b/test/test_units/test_langserver/test_data/go_to_def/parent_attr.k deleted file mode 100644 index 5e0a6924c..000000000 --- a/test/test_units/test_langserver/test_data/go_to_def/parent_attr.k +++ /dev/null @@ -1,9 +0,0 @@ -import pkg - -schema Son(pkg.Parent): - age: int - -alice = Son { - name: "alice" - age: 10 -} \ No newline at end of file diff --git a/test/test_units/test_langserver/test_data/go_to_def/pkg/import_abs.k b/test/test_units/test_langserver/test_data/go_to_def/pkg/import_abs.k deleted file mode 100644 index ed9885a69..000000000 --- a/test/test_units/test_langserver/test_data/go_to_def/pkg/import_abs.k +++ /dev/null @@ -1,5 +0,0 @@ -import pkg.parent - -alice = parent.Parent { - name: "alice" -} \ No newline at end of file diff --git a/test/test_units/test_langserver/test_data/go_to_def/pkg/parent.k b/test/test_units/test_langserver/test_data/go_to_def/pkg/parent.k deleted file mode 100644 index 10a407aa2..000000000 --- a/test/test_units/test_langserver/test_data/go_to_def/pkg/parent.k +++ /dev/null @@ -1,2 +0,0 @@ -schema Parent: - name: str diff --git a/test/test_units/test_langserver/test_data/go_to_def/schema.k b/test/test_units/test_langserver/test_data/go_to_def/schema.k deleted file mode 100644 index 0a9e7c301..000000000 --- a/test/test_units/test_langserver/test_data/go_to_def/schema.k +++ /dev/null @@ -1,7 +0,0 @@ -schema Person: - name: str - info: str = name - -alice = Person { - name: "alice" -} \ No newline at end of file diff --git a/test/test_units/test_langserver/test_data/go_to_def/schema_index_signature.k b/test/test_units/test_langserver/test_data/go_to_def/schema_index_signature.k deleted file mode 100644 index 30032f733..000000000 --- a/test/test_units/test_langserver/test_data/go_to_def/schema_index_signature.k +++ /dev/null @@ -1,10 +0,0 @@ -schema Data: - [name: str]: str - - check: - name.islower() - -data = Data { - key: "value" -} -value = data.key diff --git a/test/test_units/test_langserver/test_data/go_to_def/simple.k b/test/test_units/test_langserver/test_data/go_to_def/simple.k deleted file mode 100644 index 49f7694af..000000000 --- a/test/test_units/test_langserver/test_data/go_to_def/simple.k +++ /dev/null @@ -1,2 +0,0 @@ -d = 1 -c = d \ No newline at end of file diff --git a/test/test_units/test_langserver/test_data/hover/built_in.k b/test/test_units/test_langserver/test_data/hover/built_in.k deleted file mode 100644 index 596bd3e83..000000000 --- a/test/test_units/test_langserver/test_data/hover/built_in.k +++ /dev/null @@ -1,42 +0,0 @@ -import base64 -import crypto - -# str built in -a = "hello World".capitalize() -b = "hello world".islower() -c = "Hello World".islower() -d = "Hello world, Hello world".count("o") -e = "Hello world, Hello world".count("Hello", 5, 20) -f = "Hello World".endswith("rld") -g = "Hello World".endswith("rld", 0, 9) - - -# base 64 -decode = base64.decode("MC4zLjA=") - - -# crypto -md5 = crypto.md5("ABCDEF") -sha = crypto.sha1("ABCDEF") - - -# regex -regex_result = regex.match("192.168.0.1", "^(1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|[1-9])\\."+"(1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|\\d)\\."+"(1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|\\d)\\."+"(1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|\\d)$") - - -# default -h = max(80, 100, 1000) -i = max(-80, -20, -10) - - -# type of -none1 = typeof(None) - -# option -j = option("a", default=42, help="set a value") - -# deprecated -@deprecated(version="1.2.3", reason="schema-deprecated", strict=False) -schema Person: - @deprecated(version="4.5.6", reason="attr-deprecated", strict=True) - name: str \ No newline at end of file diff --git a/test/test_units/test_langserver/test_data/hover/hello.k b/test/test_units/test_langserver/test_data/hover/hello.k deleted file mode 100644 index b0921f6a2..000000000 --- a/test/test_units/test_langserver/test_data/hover/hello.k +++ /dev/null @@ -1,12 +0,0 @@ -schema Server: - name: str - image: str - replica: int = 1 - -myServer = Server { - name: "demo" - image: "demo image" - replica: 10 -} - -n = myServer.name \ No newline at end of file diff --git a/test/test_units/test_langserver/test_data/hover/import.k b/test/test_units/test_langserver/test_data/hover/import.k deleted file mode 100644 index 6c1c8a97d..000000000 --- a/test/test_units/test_langserver/test_data/hover/import.k +++ /dev/null @@ -1 +0,0 @@ -import .hello \ No newline at end of file diff --git a/test/test_units/test_langserver/test_data/hover/incomplete.k b/test/test_units/test_langserver/test_data/hover/incomplete.k deleted file mode 100644 index 3b7d46a4d..000000000 --- a/test/test_units/test_langserver/test_data/hover/incomplete.k +++ /dev/null @@ -1,7 +0,0 @@ -schema ProviderConfig: - __settings__?: {str:str} = {"output_type": "INLINE"} - -schema AConfig(ProviderConfig): -schema BConfig(ProviderConfig): - access_key?: str = option("ak") - secret_key?: str = option("sk") \ No newline at end of file diff --git a/test/test_units/test_langserver/test_document_symbol.py b/test/test_units/test_langserver/test_document_symbol.py deleted file mode 100644 index e9b873d6a..000000000 --- a/test/test_units/test_langserver/test_document_symbol.py +++ /dev/null @@ -1,174 +0,0 @@ -# Copyright 2021 The KCL Authors. All rights reserved. - -import unittest -import pathlib - -from pygls.lsp.types.basic_structures import Range, Position -from pygls.lsp.types.language_features.document_symbol import DocumentSymbol, SymbolKind - -import kclvm.tools.langserver.document_symbol as symbol - -_DOCUMENT_SYMBOL_DIR = pathlib.Path(__file__).parent.joinpath( - "test_data/document_symbol" -) - - -class DocumentSymbolTest(unittest.TestCase): - def test_file_to_symbol(self): - expect_result = [ - DocumentSymbol( - name="a", - kind=SymbolKind.Variable, - range=Range( - start=Position(line=0, character=0), - end=Position(line=0, character=9), - ), - selection_range=Range( - start=Position(line=0, character=0), - end=Position(line=0, character=1), - ), - ), - DocumentSymbol( - name="b", - kind=SymbolKind.Variable, - range=Range( - start=Position(line=0, character=0), - end=Position(line=0, character=9), - ), - selection_range=Range( - start=Position(line=0, character=4), - end=Position(line=0, character=5), - ), - ), - DocumentSymbol( - name="Person", - kind=SymbolKind.Struct, - range=Range( - start=Position(line=2, character=0), - end=Position(line=7, character=20), - ), - selection_range=Range( - start=Position(line=2, character=7), - end=Position(line=2, character=13), - ), - children=[ - DocumentSymbol( - name="mixin", - kind=SymbolKind.Property, - range=Range( - start=Position(line=3, character=4), - end=Position(line=3, character=9), - ), - selection_range=Range( - start=Position(line=3, character=4), - end=Position(line=3, character=9), - ), - children=[ - DocumentSymbol( - name="aMixin", - kind=SymbolKind.Variable, - range=Range( - start=Position(line=4, character=8), - end=Position(line=4, character=14), - ), - selection_range=Range( - start=Position(line=4, character=8), - end=Position(line=4, character=14), - ), - ) - ], - ), - DocumentSymbol( - name="age", - kind=SymbolKind.Property, - range=Range( - start=Position(line=6, character=4), - end=Position(line=6, character=17), - ), - selection_range=Range( - start=Position(line=6, character=4), - end=Position(line=6, character=7), - ), - ), - DocumentSymbol( - name="name", - kind=SymbolKind.Property, - range=Range( - start=Position(line=7, character=4), - end=Position(line=7, character=20), - ), - selection_range=Range( - start=Position(line=7, character=4), - end=Position(line=7, character=8), - ), - ), - ], - ), - DocumentSymbol( - name="person", - kind=SymbolKind.Variable, - range=Range( - start=Position(line=9, character=0), - end=Position(line=11, character=1), - ), - selection_range=Range( - start=Position(line=9, character=0), - end=Position(line=9, character=6), - ), - ), - ] - symbols = symbol.document_symbol(_DOCUMENT_SYMBOL_DIR.joinpath("symbol.k")) - self.check_result(expect_result, symbols) - - def test_invalid_grammar(self): - symbols = symbol.document_symbol( - _DOCUMENT_SYMBOL_DIR.joinpath("invalid_grammar.k") - ) - assert ( - not symbols - ), "invalid grammar should got empty document symbol result for now" - - def test_invalid_semantic(self): - expect_result = [ - DocumentSymbol( - name="a", - kind=SymbolKind.Variable, - range=Range( - start=Position(line=0, character=0), - end=Position(line=0, character=5), - ), - selection_range=Range( - start=Position(line=0, character=0), - end=Position(line=0, character=1), - ), - ), - DocumentSymbol( - name="c", - kind=SymbolKind.Variable, - range=Range( - start=Position(line=1, character=0), - end=Position(line=1, character=5), - ), - selection_range=Range( - start=Position(line=1, character=0), - end=Position(line=1, character=1), - ), - ), - ] - symbols = symbol.document_symbol( - _DOCUMENT_SYMBOL_DIR.joinpath("invalid_semantic.k") - ) - self.check_result(expect_result, symbols) - - def check_result(self, expect, got): - self.assertEqual( - len(expect), - len(got), - f"inconsistent number of symbols found, expect: {len(expect)}, got: {len(got)}", - ) - for i, s in enumerate(got): - self.assertEqual(expect[i], s, f"expect: {expect[i]}, got: {s}") - - -if __name__ == "__main__": - unittest.main(verbosity=2) diff --git a/test/test_units/test_langserver/test_go_to_def.py b/test/test_units/test_langserver/test_go_to_def.py deleted file mode 100644 index 14e0f65c4..000000000 --- a/test/test_units/test_langserver/test_go_to_def.py +++ /dev/null @@ -1,460 +0,0 @@ -# Copyright 2021 The KCL Authors. All rights reserved. - -import pathlib -import unittest - -from typing import List -from pygls.lsp.types.basic_structures import Location, Range, Position - -import kclvm.kcl.ast as ast -import kclvm.tools.langserver.common as common -import kclvm.tools.langserver.go_to_def as go_to_def - - -_TEST_PATH_NAME = "test_data" -_GO_TO_DEF_PATH_NAME = "go_to_def" -_DIR_PATH = ( - pathlib.Path(__file__) - .parent.joinpath(_TEST_PATH_NAME) - .joinpath(_GO_TO_DEF_PATH_NAME) -) - - -class GoToDefTestCase: - def __init__( - self, - filename: str, - line: int, - column: int, - locations: List[Location], - ): - self.filename: str = filename - self.line: int = line - self.column: int = column - self.locations: List[Location] = locations - - -class GoToDefTest(unittest.TestCase): - test_cases = [ - GoToDefTestCase( - filename="dict_fix_me.k", - line=15, - column=9, - locations=[ - Location( - uri="dict_fix_me.k", - range=Range( - start=Position(line=14, character=8), - end=Position(line=14, character=13), - ), - # range=Range( - # start=Position(line=9, character=4), - # end=Position(line=9, character=9), - # ), - ) - ], - ), - GoToDefTestCase( - filename="dict_fix_me.k", - line=14, - column=6, - locations=[ - Location( - uri="dict_fix_me.k", - range=Range( - start=Position(line=13, character=4), - end=Position(line=13, character=8), - ), - # range=Range( - # start=Position(line=1, character=4), - # end=Position(line=1, character=8), - # ), - ) - ], - ), - GoToDefTestCase( - filename="import_module.k", - line=3, - column=11, - locations=[ - Location( - uri="pkg/parent.k", - range=Range( - start=Position(line=0, character=7), - end=Position(line=0, character=13), - ), - ) - ], - ), - GoToDefTestCase( - filename="pkg/import_abs.k", - line=4, - column=5, - locations=[ - Location( - uri="pkg/parent.k", - range=Range( - start=Position(line=1, character=4), - end=Position(line=1, character=8), - ), - ) - ], - ), - GoToDefTestCase( - filename="pkg/import_abs.k", - line=1, - column=12, - locations=[ - Location( - uri="pkg/parent.k", - range=Range( - start=Position(line=0, character=0), - end=Position(line=0, character=0), - ), - ) - ], - ), - GoToDefTestCase( - filename="simple.k", - line=2, - column=5, - locations=[ - Location( - uri="simple.k", - range=Range( - start=Position(line=0, character=0), - end=Position(line=0, character=1), - ), - ) - ], - ), - GoToDefTestCase( - filename="schema.k", - line=3, - column=17, - locations=[ - Location( - uri="schema.k", - range=Range( - start=Position(line=1, character=4), - end=Position(line=1, character=8), - ), - ) - ], - ), - GoToDefTestCase( - filename="import_module.k", - line=1, - column=13, - locations=[ - Location( - uri="pkg/parent.k", - range=common.emptyRange(), - ) - ], - ), - GoToDefTestCase( - filename="import_module.k", - line=3, - column=11, - locations=[ - Location( - uri="pkg/parent.k", - range=Range( - start=Position(line=0, character=7), - end=Position(line=0, character=13), - ), - ) - ], - ), - GoToDefTestCase( - filename="import_module.k", - line=3, - column=9, - locations=[ - Location( - uri="import_module.k", - range=Range( - start=Position(line=0, character=22), - end=Position(line=0, character=23), - ), - ) - ], - ), - GoToDefTestCase( - filename="import_module.k", - line=1, - column=23, - locations=[ - Location( - uri="import_module.k", - range=Range( - start=Position(line=0, character=22), - end=Position(line=0, character=23), - ), - ) - ], - ), - GoToDefTestCase( - filename="import_module.k", - line=7, - column=9, - locations=[], - ), - GoToDefTestCase( - filename="attr.k", - line=9, - column=10, - locations=[ - Location( - uri="attr.k", - range=Range( - start=Position(line=3, character=4), - end=Position(line=3, character=9), - ), - ) - ], - ), - GoToDefTestCase( - filename="attr.k", - line=14, - column=17, - locations=[ - Location( - uri="attr.k", - range=Range( - start=Position(line=0, character=0), - end=Position(line=0, character=16), - ), - ) - ], - ), - GoToDefTestCase( - filename="inherit.k", - line=1, - column=8, - locations=[ - Location( - uri="inherit.k", - range=Range( - start=Position(line=0, character=7), - end=Position(line=0, character=13), - ), - ) - ], - ), - GoToDefTestCase( - filename="inherit.k", - line=9, - column=27, - locations=[ - Location( - uri="inherit.k", - range=Range( - start=Position(line=1, character=4), - end=Position(line=1, character=8), - ), - ) - ], - ), - GoToDefTestCase( - filename="inherit.k", - line=10, - column=14, - locations=[], - ), - GoToDefTestCase( - filename="schema.k", - line=5, - column=9, - locations=[ - Location( - uri="schema.k", - range=Range( - start=Position(line=0, character=7), - end=Position(line=0, character=13), - ), - ) - ], - ), - GoToDefTestCase( - filename="schema_index_signature.k", - line=5, - column=9, - locations=[ - Location( - uri="schema_index_signature.k", - range=Range( - start=Position(line=1, character=5), - end=Position(line=1, character=9), - ), - ) - ], - ), - GoToDefTestCase( - filename="parent_attr.k", - line=7, - column=5, - locations=[ - Location( - uri="pkg/parent.k", - range=Range( - start=Position(line=1, character=4), - end=Position(line=1, character=8), - ), - ) - ], - ), - GoToDefTestCase( - filename="list_comp.k", - line=6, - column=17, - locations=[ - Location( - uri="list_comp.k", - range=Range( - start=Position(line=5, character=22), - end=Position(line=5, character=23), - ), - ) - ], - ), - GoToDefTestCase( - filename="list_comp.k", - line=7, - column=14, - # name="e", - locations=[ - Location( - uri="list_comp.k", - range=Range( - start=Position(line=0, character=4), - end=Position(line=0, character=5), - ), - ) - ], - ), - GoToDefTestCase( - filename="inherit.k", - line=6, - column=21, - locations=[ - Location( - uri="inherit.k", - range=Range( - start=Position(line=1, character=4), - end=Position(line=1, character=8), - ), - ) - ], - ), - GoToDefTestCase( - filename="inherit_pkg.k", - line=4, - column=21, - locations=[ - Location( - uri=str(pathlib.Path("pkg") / "parent.k"), - range=Range( - start=Position(line=1, character=4), - end=Position(line=1, character=8), - ), - ) - ], - ), - GoToDefTestCase( - filename="inherit_pkg.k", - line=3, - column=12, - locations=[ - Location( - uri=str("inherit_pkg.k"), - range=Range( - start=Position(line=0, character=7), - end=Position(line=0, character=10), - ), - ) - ], - ), - GoToDefTestCase( - filename="inherit_pkg.k", - line=7, - column=1, - locations=[], - ), - GoToDefTestCase( - filename="invalid_semantic.k", - line=2, - column=5, - locations=[ - Location( - uri="invalid_semantic.k", - range=Range( - start=Position(line=0, character=0), - end=Position(line=0, character=1), - ), - ) - ], - ), - GoToDefTestCase( - filename="invalid_grammar.k", - line=1, - column=1, - locations=[], - ), - ] - - def test_go_to_def(self): - for i, t_case in enumerate(self.test_cases): - got_locations = go_to_def.go_to_def( - pos=ast.Position( - filename=str(_DIR_PATH / t_case.filename), - line=t_case.line, - column=t_case.column, - ), - ) - expect_locations = [ - Location(uri=str(_DIR_PATH / loc.uri), range=loc.range) - for loc in t_case.locations - ] - self.assertEqual( - expect_locations, - got_locations, - f"err go to def for case[{i}], from pos:{t_case.filename}:{t_case.line}:{t_case.column}\nexpect: {expect_locations}, got: {got_locations}", - ) - - -class NoneInputTest(unittest.TestCase): - def test_find_declaration_None_input(self): - self.assertIsNone(go_to_def.find_declaration(None, None, None)) - - def test_find_declaration_by_scope_obj_None_input(self): - self.assertIsNone( - go_to_def.find_declaration_by_scope_obj(None, None, None, None) - ) - - def test_find_declaration_obj_by_pos_and_name_None_input(self): - self.assertIsNone( - go_to_def.find_declaration_obj_by_pos_and_name(None, None, None) - ) - - def test_find_inner_name_None_input(self): - self.assertIsNone(go_to_def.find_inner_name(None, None, None)) - - def test_find_attr_by_name_None_input(self): - self.assertIsNone(go_to_def.find_attr_by_name(None, None, None)) - - -def test_find_declaration_obj_by_pos_and_name(): - pos: ast.Position = ast.Position(filename="simple.k", line=2, column=5) - _, prog_scope = common.file_or_prog_to_scope(file_path=_DIR_PATH / "simple.k") - assert ( - go_to_def.find_declaration_obj_by_pos_and_name( - pos=pos, name="d", prog_scope=prog_scope - ) - is None - ) - - -if __name__ == "__main__": - unittest.main(verbosity=2) diff --git a/test/test_units/test_langserver/test_hover.py b/test/test_units/test_langserver/test_hover.py deleted file mode 100644 index 9eac125b9..000000000 --- a/test/test_units/test_langserver/test_hover.py +++ /dev/null @@ -1,161 +0,0 @@ -import pathlib -import unittest -import typing - -from pygls.lsp.types.basic_structures import MarkupContent, MarkupKind, Range, Position -import pygls.lsp.types.language_features.hover as pygls_hover - -import kclvm.kcl.ast as ast -import kclvm.tools.langserver.hover as hover -import kclvm.tools.langserver.go_to_def as go_to_def - - -_TEST_PATH_NAME = "test_data" -_HOVER_PATH_NAME = "hover" -_DIR_PATH = ( - pathlib.Path(__file__).parent.joinpath(_TEST_PATH_NAME).joinpath(_HOVER_PATH_NAME) -) - - -class HoverTestCase: - def __init__( - self, - filename: str, - line: int, - column: int, - msg: str = None, - range: typing.Optional[Range] = None, - no_result: bool = False, - ): - self.filename: str = filename - self.line: int = line - self.column: int = column - self.msg: str = msg - self.range: Range = range - self.no_result: bool = no_result - - -class HoverTest(unittest.TestCase): - test_cases = [ - HoverTestCase( - filename="incomplete.k", - line=4, - column=23, - msg=f"ProviderConfig\ntype: ProviderConfig\ndefined in:{_DIR_PATH}/incomplete.k", - range=Range( - start=Position(line=3, character=15), - end=Position(line=3, character=29), - ), - ), - HoverTestCase( - filename="built_in.k", - line=28, - column=5, - msg="(built-in) max(): any\nWith a single iterable argument, return its biggest item.\n The default keyword-only argument specifies an object to return\n if the provided iterable is empty. With two or more arguments,\n return the largest argument.\n ", - range=Range( - start=Position(line=27, character=4), - end=Position(line=27, character=7), - ), - ), - HoverTestCase( - filename="built_in.k", - line=33, - column=11, - msg="(built-in) typeof(x: any, full_name: bool=False): str\nReturn the type of the kcl object", - range=Range( - start=Position(line=32, character=8), - end=Position(line=32, character=14), - ), - ), - HoverTestCase( - filename="built_in.k", - line=36, - column=5, - msg='(built-in) option(key: str, type: str="", required: bool=False, default: any=None, help: str="", help: str="", file: str="", line: int=0): any\nReturn the top level argument by the key', - range=Range( - start=Position(line=35, character=4), - end=Position(line=35, character=10), - ), - ), - HoverTestCase( - filename="hello.k", - line=8, - column=5, - msg=f"image\ntype: str\ndefined in:{_DIR_PATH}/hello.k", - range=Range( - start=Position(line=7, character=4), - end=Position(line=7, character=9), - ), - ), - HoverTestCase( - filename="hello.k", - line=12, - column=15, - msg=f"name\ntype: str\ndefined in:{_DIR_PATH}/hello.k", - range=Range( - start=Position(line=11, character=13), - end=Position(line=11, character=17), - ), - ), - HoverTestCase( - filename="hello.k", - line=7, - column=11, - no_result=True, - ), - HoverTestCase( - filename="hello.k", - line=5, - column=1, - no_result=True, - ), - HoverTestCase( - filename="import.k", - line=1, - column=10, - msg="hello", - range=Range( - start=Position(line=0, character=8), - end=Position(line=0, character=13), - ), - ), - ] - - def test_hover(self): - for i, t_case in enumerate(self.test_cases): - if i != 0: - return - got = hover.hover( - pos=ast.Position( - filename=str(_DIR_PATH / t_case.filename), - line=t_case.line, - column=t_case.column, - ), - ) - expect = ( - pygls_hover.Hover( - contents=MarkupContent( - kind=MarkupKind.PlainText, - value=t_case.msg, - ), - range=t_case.range, - ) - if not t_case.no_result - else None - ) - self.assertEqual( - expect, - got, - f"err hover for case[{i}], from pos:{t_case.filename}:{t_case.line}:{t_case.column}\nexpect: {expect}, got: {got}", - ) - - -class NoneInputTest(unittest.TestCase): - def test_definition_None_input(self): - node, scope_obj = go_to_def.definition(None, None) - self.assertIsNone(node) - self.assertIsNone(scope_obj) - - def test_scope_obj_desc_None_input(self): - result = hover.scope_obj_desc(None, None) - self.assertIsNone(result) diff --git a/test/test_units/test_langserver/test_wrapper.py b/test/test_units/test_langserver/test_wrapper.py deleted file mode 100644 index 8f588e424..000000000 --- a/test/test_units/test_langserver/test_wrapper.py +++ /dev/null @@ -1,76 +0,0 @@ -# Copyright 2021 The KCL Authors. All rights reserved. - -import pathlib -import unittest -import json -from pathlib import Path -import pygls.lsp.types.basic_structures as pygls_basic -from kclvm.internal.gpyrpc.gpyrpc_pb2 import Position -import kclvm.tools.langserver.grpc_wrapper as wrapper - -_TEST_PATH_NAME = "test_data" -_GO_TO_DEF_PATH_NAME = "go_to_def" -_COMPLETE_PATH_NAME = "complete" -_DOCUMENT_SYMBOL_PATH_NAME = "document_symbol" -_HOVER_PATH_NAME = "hover" -_DIR_PATH = pathlib.Path(__file__).parent.joinpath(_TEST_PATH_NAME) - - -class RequestWrapperTest(unittest.TestCase): - def test_go_to_def_wrapper(self): - filename = str(_DIR_PATH / _GO_TO_DEF_PATH_NAME / "simple.k") - got_result = wrapper.go_to_def_wrapper( - Position(line=1, column=4, filename=filename), - ) - expect_result = ( - '[{"uri": "' - + filename - + '", "range": {"start": {"line": 0, "character": 0}, "end": {"line": 0, "character": 1}}}]' - ) - self.assertEqual( - expect_result, got_result, f"expect: {expect_result}, got: {got_result}" - ) - - def test_complete_wrapper(self): - filename = str(_DIR_PATH / _COMPLETE_PATH_NAME / "simple.k") - got_result = wrapper.complete_wrapper( - pos=Position(line=1, column=5, filename=filename), - name="a", - ) - expect_result = '[{"label": "aa", "kind": 12, "tags": null, "detail": null, "documentation": null, "deprecated": false, "preselect": false, "sort_text": null, "filter_text": null, "insert_text": null, "insert_text_format": null, "text_edit": null, "additional_text_edits": null, "commit_characters": null, "command": null, "data": null}, {"label": "abs", "kind": 3, "tags": null, "detail": null, "documentation": null, "deprecated": false, "preselect": false, "sort_text": null, "filter_text": null, "insert_text": null, "insert_text_format": null, "text_edit": null, "additional_text_edits": null, "commit_characters": null, "command": null, "data": null}, {"label": "all_true", "kind": 3, "tags": null, "detail": null, "documentation": null, "deprecated": false, "preselect": false, "sort_text": null, "filter_text": null, "insert_text": null, "insert_text_format": null, "text_edit": null, "additional_text_edits": null, "commit_characters": null, "command": null, "data": null}, {"label": "any_true", "kind": 3, "tags": null, "detail": null, "documentation": null, "deprecated": false, "preselect": false, "sort_text": null, "filter_text": null, "insert_text": null, "insert_text_format": null, "text_edit": null, "additional_text_edits": null, "commit_characters": null, "command": null, "data": null}]' - self.assertEqual( - expect_result, got_result, f"expect: {expect_result}, got: {got_result}" - ) - - def test_document_symbol_wrapper(self): - filename = str(_DIR_PATH / _DOCUMENT_SYMBOL_PATH_NAME / "symbol.k") - got_result = wrapper.document_symbol_wrapper(filename) - expect_result = '[{"name": "a", "kind": 13, "range": {"start": {"line": 0, "character": 0}, "end": {"line": 0, "character": 9}}, "selectionRange": {"start": {"line": 0, "character": 0}, "end": {"line": 0, "character": 1}}, "detail": null, "children": null, "deprecated": false}, {"name": "b", "kind": 13, "range": {"start": {"line": 0, "character": 0}, "end": {"line": 0, "character": 9}}, "selectionRange": {"start": {"line": 0, "character": 4}, "end": {"line": 0, "character": 5}}, "detail": null, "children": null, "deprecated": false}, {"name": "Person", "kind": 23, "range": {"start": {"line": 2, "character": 0}, "end": {"line": 7, "character": 20}}, "selectionRange": {"start": {"line": 2, "character": 7}, "end": {"line": 2, "character": 13}}, "detail": null, "children": [{"name": "mixin", "kind": 7, "range": {"start": {"line": 3, "character": 4}, "end": {"line": 3, "character": 9}}, "selectionRange": {"start": {"line": 3, "character": 4}, "end": {"line": 3, "character": 9}}, "detail": null, "children": [{"name": "aMixin", "kind": 13, "range": {"start": {"line": 4, "character": 8}, "end": {"line": 4, "character": 14}}, "selectionRange": {"start": {"line": 4, "character": 8}, "end": {"line": 4, "character": 14}}, "detail": null, "children": null, "deprecated": false}], "deprecated": false}, {"name": "age", "kind": 7, "range": {"start": {"line": 6, "character": 4}, "end": {"line": 6, "character": 17}}, "selectionRange": {"start": {"line": 6, "character": 4}, "end": {"line": 6, "character": 7}}, "detail": null, "children": null, "deprecated": false}, {"name": "name", "kind": 7, "range": {"start": {"line": 7, "character": 4}, "end": {"line": 7, "character": 20}}, "selectionRange": {"start": {"line": 7, "character": 4}, "end": {"line": 7, "character": 8}}, "detail": null, "children": null, "deprecated": false}], "deprecated": false}, {"name": "person", "kind": 13, "range": {"start": {"line": 9, "character": 0}, "end": {"line": 11, "character": 1}}, "selectionRange": {"start": {"line": 9, "character": 0}, "end": {"line": 9, "character": 6}}, "detail": null, "children": null, "deprecated": false}]' - self.assertEqual( - expect_result, got_result, f"expect: {expect_result}, got: {got_result}" - ) - - def test_hover_wrapper(self): - filename = str(_DIR_PATH / _HOVER_PATH_NAME / "hello.k") - got_result = wrapper.hover_wrapper( - pos=Position(line=7, column=4, filename=filename), - code=Path(filename).read_text(encoding="utf-8") - ) - expect = { - "contents": { - "kind": "plaintext", - "value": f"image\ntype: str\ndefined in:{filename}" - }, - "range": pygls_basic.Range( - start=pygls_basic.Position(line=7, character=4), - end=pygls_basic.Position(line=7, character=9), - ), - } - expect_result = json.dumps(obj=expect, default=lambda x: x.__dict__) - self.assertEqual( - expect_result, got_result, f"expect: {expect_result}, got: {got_result}" - ) - - -if __name__ == "__main__": - unittest.main(verbosity=2)